aboutsummaryrefslogtreecommitdiff
path: root/gcc
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 /gcc
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 'gcc')
-rw-r--r--gcc/Makefile.in4
-rwxr-xr-xgcc/configure107
-rw-r--r--gcc/configure.ac2
-rw-r--r--gcc/d/Make-lang.in132
-rw-r--r--gcc/d/config-lang.in2
-rw-r--r--gcc/d/d-attribs.cc1
-rw-r--r--gcc/d/d-builtins.cc52
-rw-r--r--gcc/d/d-codegen.cc78
-rw-r--r--gcc/d/d-compiler.cc49
-rw-r--r--gcc/d/d-convert.cc86
-rw-r--r--gcc/d/d-diagnostic.cc75
-rw-r--r--gcc/d/d-frontend.cc119
-rw-r--r--gcc/d/d-frontend.h37
-rw-r--r--gcc/d/d-incpath.cc5
-rw-r--r--gcc/d/d-lang.cc287
-rw-r--r--gcc/d/d-longdouble.cc6
-rw-r--r--gcc/d/d-system.h52
-rw-r--r--gcc/d/d-target.cc112
-rw-r--r--gcc/d/d-tree.h1
-rw-r--r--gcc/d/decl.cc166
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/README.md259
-rw-r--r--gcc/d/dmd/VERSION1
-rw-r--r--gcc/d/dmd/access.c560
-rw-r--r--gcc/d/dmd/access.d410
-rw-r--r--gcc/d/dmd/aggregate.d769
-rw-r--r--gcc/d/dmd/aggregate.h189
-rw-r--r--gcc/d/dmd/aliasthis.c94
-rw-r--r--gcc/d/dmd/aliasthis.d202
-rw-r--r--gcc/d/dmd/aliasthis.h10
-rw-r--r--gcc/d/dmd/apply.c149
-rw-r--r--gcc/d/dmd/apply.d189
-rw-r--r--gcc/d/dmd/arrayop.c634
-rw-r--r--gcc/d/dmd/arrayop.d387
-rw-r--r--gcc/d/dmd/arraytypes.d57
-rw-r--r--gcc/d/dmd/arraytypes.h9
-rw-r--r--gcc/d/dmd/ast_node.d26
-rw-r--r--gcc/d/dmd/astcodegen.d102
-rw-r--r--gcc/d/dmd/astenums.d391
-rw-r--r--gcc/d/dmd/attrib.c1320
-rw-r--r--gcc/d/dmd/attrib.d1518
-rw-r--r--gcc/d/dmd/attrib.h86
-rw-r--r--gcc/d/dmd/blockexit.c506
-rw-r--r--gcc/d/dmd/blockexit.d537
-rw-r--r--gcc/d/dmd/builtin.d33
-rw-r--r--gcc/d/dmd/canthrow.c316
-rw-r--r--gcc/d/dmd/canthrow.d244
-rw-r--r--gcc/d/dmd/chkformat.c985
-rw-r--r--gcc/d/dmd/chkformat.d1364
-rw-r--r--gcc/d/dmd/clone.c1179
-rw-r--r--gcc/d/dmd/clone.d1695
-rw-r--r--gcc/d/dmd/compiler.d57
-rw-r--r--gcc/d/dmd/compiler.h6
-rw-r--r--gcc/d/dmd/complex.d112
-rw-r--r--gcc/d/dmd/complex_t.h4
-rw-r--r--gcc/d/dmd/cond.c738
-rw-r--r--gcc/d/dmd/cond.d1004
-rw-r--r--gcc/d/dmd/cond.h31
-rw-r--r--gcc/d/dmd/constfold.c1922
-rw-r--r--gcc/d/dmd/constfold.d1825
-rw-r--r--gcc/d/dmd/cparse.d4249
-rw-r--r--gcc/d/dmd/cppmangle.c1168
-rw-r--r--gcc/d/dmd/cppmangle.d2540
-rw-r--r--gcc/d/dmd/ctfe.h222
-rw-r--r--gcc/d/dmd/ctfeexpr.c2127
-rw-r--r--gcc/d/dmd/ctfeexpr.d2096
-rw-r--r--gcc/d/dmd/ctorflow.d225
-rw-r--r--gcc/d/dmd/dcast.c3566
-rw-r--r--gcc/d/dmd/dcast.d3741
-rw-r--r--gcc/d/dmd/dclass.c1041
-rw-r--r--gcc/d/dmd/dclass.d1139
-rw-r--r--gcc/d/dmd/declaration.c1575
-rw-r--r--gcc/d/dmd/declaration.d2323
-rw-r--r--gcc/d/dmd/declaration.h582
-rw-r--r--gcc/d/dmd/delegatize.c208
-rw-r--r--gcc/d/dmd/delegatize.d305
-rw-r--r--gcc/d/dmd/denum.c388
-rw-r--r--gcc/d/dmd/denum.d333
-rw-r--r--gcc/d/dmd/dimport.c320
-rw-r--r--gcc/d/dmd/dimport.d358
-rw-r--r--gcc/d/dmd/dinterpret.c7017
-rw-r--r--gcc/d/dmd/dinterpret.d7487
-rw-r--r--gcc/d/dmd/dmacro.c458
-rw-r--r--gcc/d/dmd/dmacro.d435
-rw-r--r--gcc/d/dmd/dmangle.c1122
-rw-r--r--gcc/d/dmd/dmangle.d1297
-rw-r--r--gcc/d/dmd/dmodule.c1276
-rw-r--r--gcc/d/dmd/dmodule.d1608
-rw-r--r--gcc/d/dmd/doc.c2807
-rw-r--r--gcc/d/dmd/doc.d5388
-rw-r--r--gcc/d/dmd/doc.h6
-rw-r--r--gcc/d/dmd/dscope.c646
-rw-r--r--gcc/d/dmd/dscope.d768
-rw-r--r--gcc/d/dmd/dstruct.c1303
-rw-r--r--gcc/d/dmd/dstruct.d610
-rw-r--r--gcc/d/dmd/dsymbol.c1803
-rw-r--r--gcc/d/dmd/dsymbol.d2386
-rw-r--r--gcc/d/dmd/dsymbol.h142
-rw-r--r--gcc/d/dmd/dsymbolsem.c5620
-rw-r--r--gcc/d/dmd/dsymbolsem.d6654
-rw-r--r--gcc/d/dmd/dtemplate.c7581
-rw-r--r--gcc/d/dmd/dtemplate.d8415
-rw-r--r--gcc/d/dmd/dtoh.d3225
-rw-r--r--gcc/d/dmd/dversion.c187
-rw-r--r--gcc/d/dmd/dversion.d215
-rw-r--r--gcc/d/dmd/entity.c2390
-rw-r--r--gcc/d/dmd/entity.d2395
-rw-r--r--gcc/d/dmd/enum.h23
-rw-r--r--gcc/d/dmd/errors.d446
-rw-r--r--gcc/d/dmd/errors.h8
-rw-r--r--gcc/d/dmd/escape.c1234
-rw-r--r--gcc/d/dmd/escape.d2290
-rw-r--r--gcc/d/dmd/expression.c5706
-rw-r--r--gcc/d/dmd/expression.d6985
-rw-r--r--gcc/d/dmd/expression.h579
-rw-r--r--gcc/d/dmd/expressionsem.c10740
-rw-r--r--gcc/d/dmd/expressionsem.d13058
-rw-r--r--gcc/d/dmd/foreachvar.d323
-rw-r--r--gcc/d/dmd/func.c3161
-rw-r--r--gcc/d/dmd/func.d4102
-rw-r--r--gcc/d/dmd/globals.d640
-rw-r--r--gcc/d/dmd/globals.h255
-rw-r--r--gcc/d/dmd/gluelayer.d90
-rw-r--r--gcc/d/dmd/hdrgen.c3591
-rw-r--r--gcc/d/dmd/hdrgen.d3956
-rw-r--r--gcc/d/dmd/hdrgen.h43
-rw-r--r--gcc/d/dmd/iasm.c44
-rw-r--r--gcc/d/dmd/iasm.d59
-rw-r--r--gcc/d/dmd/iasmgcc.c379
-rw-r--r--gcc/d/dmd/iasmgcc.d537
-rw-r--r--gcc/d/dmd/id.d568
-rw-r--r--gcc/d/dmd/id.h16
-rw-r--r--gcc/d/dmd/identifier.c188
-rw-r--r--gcc/d/dmd/identifier.d362
-rw-r--r--gcc/d/dmd/identifier.h32
-rw-r--r--gcc/d/dmd/idgen.c560
-rw-r--r--gcc/d/dmd/impcnvgen.c598
-rw-r--r--gcc/d/dmd/impcnvtab.d379
-rw-r--r--gcc/d/dmd/imphint.c52
-rw-r--r--gcc/d/dmd/imphint.d91
-rw-r--r--gcc/d/dmd/import.h13
-rw-r--r--gcc/d/dmd/init.c282
-rw-r--r--gcc/d/dmd/init.d332
-rw-r--r--gcc/d/dmd/init.h69
-rw-r--r--gcc/d/dmd/initsem.c914
-rw-r--r--gcc/d/dmd/initsem.d1268
-rw-r--r--gcc/d/dmd/inline.d30
-rw-r--r--gcc/d/dmd/intrange.c839
-rw-r--r--gcc/d/dmd/intrange.d919
-rw-r--r--gcc/d/dmd/json.c888
-rw-r--r--gcc/d/dmd/json.d1085
-rw-r--r--gcc/d/dmd/json.h2
-rw-r--r--gcc/d/dmd/lambdacomp.d495
-rw-r--r--gcc/d/dmd/lexer.c2405
-rw-r--r--gcc/d/dmd/lexer.d3273
-rw-r--r--gcc/d/dmd/mangle.h6
-rw-r--r--gcc/d/dmd/module.h59
-rw-r--r--gcc/d/dmd/mtype.c8722
-rw-r--r--gcc/d/dmd/mtype.d7355
-rw-r--r--gcc/d/dmd/mtype.h444
-rw-r--r--gcc/d/dmd/nogc.c241
-rw-r--r--gcc/d/dmd/nogc.d266
-rw-r--r--gcc/d/dmd/nspace.c164
-rw-r--r--gcc/d/dmd/nspace.d170
-rw-r--r--gcc/d/dmd/nspace.h10
-rw-r--r--gcc/d/dmd/ob.d2680
-rw-r--r--gcc/d/dmd/objc.c84
-rw-r--r--gcc/d/dmd/objc.d953
-rw-r--r--gcc/d/dmd/objc.h55
-rw-r--r--gcc/d/dmd/opover.c1960
-rw-r--r--gcc/d/dmd/opover.d1843
-rw-r--r--gcc/d/dmd/optimize.c1230
-rw-r--r--gcc/d/dmd/optimize.d1186
-rw-r--r--gcc/d/dmd/parse.c8492
-rw-r--r--gcc/d/dmd/parse.d9365
-rw-r--r--gcc/d/dmd/parsetimevisitor.d297
-rw-r--r--gcc/d/dmd/permissivevisitor.d28
-rw-r--r--gcc/d/dmd/printast.d173
-rw-r--r--gcc/d/dmd/readme.txt13
-rw-r--r--gcc/d/dmd/res/default_ddoc_theme.ddoc825
-rw-r--r--gcc/d/dmd/root/README.md23
-rw-r--r--gcc/d/dmd/root/aav.c171
-rw-r--r--gcc/d/dmd/root/aav.d339
-rw-r--r--gcc/d/dmd/root/array.d1121
-rw-r--r--gcc/d/dmd/root/array.h52
-rw-r--r--gcc/d/dmd/root/bitarray.d192
-rw-r--r--gcc/d/dmd/root/bitarray.h4
-rw-r--r--gcc/d/dmd/root/checkedint.c238
-rw-r--r--gcc/d/dmd/root/ctfloat.d63
-rw-r--r--gcc/d/dmd/root/ctfloat.h6
-rw-r--r--gcc/d/dmd/root/dcompat.h12
-rw-r--r--gcc/d/dmd/root/file.c258
-rw-r--r--gcc/d/dmd/root/file.d814
-rw-r--r--gcc/d/dmd/root/file.h54
-rw-r--r--gcc/d/dmd/root/filename.c671
-rw-r--r--gcc/d/dmd/root/filename.d1273
-rw-r--r--gcc/d/dmd/root/filename.h15
-rw-r--r--gcc/d/dmd/root/hash.d83
-rw-r--r--gcc/d/dmd/root/longdouble.d140
-rw-r--r--gcc/d/dmd/root/object.h27
-rw-r--r--gcc/d/dmd/root/outbuffer.c417
-rw-r--r--gcc/d/dmd/root/outbuffer.d720
-rw-r--r--gcc/d/dmd/root/outbuffer.h31
-rw-r--r--gcc/d/dmd/root/port.d49
-rw-r--r--gcc/d/dmd/root/port.h11
-rw-r--r--gcc/d/dmd/root/region.d161
-rw-r--r--gcc/d/dmd/root/rmem.c191
-rw-r--r--gcc/d/dmd/root/rmem.d375
-rw-r--r--gcc/d/dmd/root/rmem.h17
-rw-r--r--gcc/d/dmd/root/root.h1
-rw-r--r--gcc/d/dmd/root/rootobject.c48
-rw-r--r--gcc/d/dmd/root/rootobject.d67
-rw-r--r--gcc/d/dmd/root/speller.c231
-rw-r--r--gcc/d/dmd/root/speller.d303
-rw-r--r--gcc/d/dmd/root/string.d293
-rw-r--r--gcc/d/dmd/root/stringtable.c196
-rw-r--r--gcc/d/dmd/root/stringtable.d411
-rw-r--r--gcc/d/dmd/safe.c168
-rw-r--r--gcc/d/dmd/safe.d228
-rw-r--r--gcc/d/dmd/sapply.c155
-rw-r--r--gcc/d/dmd/sapply.d180
-rw-r--r--gcc/d/dmd/scope.h122
-rw-r--r--gcc/d/dmd/semantic2.c430
-rw-r--r--gcc/d/dmd/semantic2.d774
-rw-r--r--gcc/d/dmd/semantic3.c1399
-rw-r--r--gcc/d/dmd/semantic3.d1624
-rw-r--r--gcc/d/dmd/sideeffect.c432
-rw-r--r--gcc/d/dmd/sideeffect.d418
-rw-r--r--gcc/d/dmd/statement.c1793
-rw-r--r--gcc/d/dmd/statement.d2053
-rw-r--r--gcc/d/dmd/statement.h354
-rw-r--r--gcc/d/dmd/statement_rewrite_walker.d194
-rw-r--r--gcc/d/dmd/statementsem.c3875
-rw-r--r--gcc/d/dmd/statementsem.d4995
-rw-r--r--gcc/d/dmd/staticassert.c55
-rw-r--r--gcc/d/dmd/staticassert.d66
-rw-r--r--gcc/d/dmd/staticassert.h6
-rw-r--r--gcc/d/dmd/staticcond.c96
-rw-r--r--gcc/d/dmd/staticcond.d424
-rw-r--r--gcc/d/dmd/stmtstate.d142
-rw-r--r--gcc/d/dmd/target.d438
-rw-r--r--gcc/d/dmd/target.h118
-rw-r--r--gcc/d/dmd/template.h146
-rw-r--r--gcc/d/dmd/templateparamsem.c116
-rw-r--r--gcc/d/dmd/templateparamsem.d190
-rw-r--r--gcc/d/dmd/tokens.c476
-rw-r--r--gcc/d/dmd/tokens.d1022
-rw-r--r--gcc/d/dmd/tokens.h69
-rw-r--r--gcc/d/dmd/traits.c1973
-rw-r--r--gcc/d/dmd/traits.d2202
-rw-r--r--gcc/d/dmd/transitivevisitor.d1207
-rw-r--r--gcc/d/dmd/typesem.c1462
-rw-r--r--gcc/d/dmd/typesem.d4896
-rw-r--r--gcc/d/dmd/typinf.d28
-rw-r--r--gcc/d/dmd/utf.c306
-rw-r--r--gcc/d/dmd/utf.d561
-rw-r--r--gcc/d/dmd/utils.c123
-rw-r--r--gcc/d/dmd/utils.d298
-rw-r--r--gcc/d/dmd/version.h18
-rw-r--r--gcc/d/dmd/visitor.d254
-rw-r--r--gcc/d/dmd/visitor.h481
-rw-r--r--gcc/d/expr.cc267
-rw-r--r--gcc/d/imports.cc8
-rw-r--r--gcc/d/intrinsics.cc10
-rw-r--r--gcc/d/intrinsics.def97
-rw-r--r--gcc/d/lang.opt165
-rw-r--r--gcc/d/modules.cc22
-rw-r--r--gcc/d/runtime.def30
-rw-r--r--gcc/d/toir.cc101
-rw-r--r--gcc/d/typeinfo.cc60
-rw-r--r--gcc/d/types.cc74
-rw-r--r--gcc/d/verstr.h1
-rw-r--r--gcc/po/EXCLUDES43
-rw-r--r--gcc/testsuite/gdc.dg/Wcastresult2.d2
-rw-r--r--gcc/testsuite/gdc.dg/asm1.d18
-rw-r--r--gcc/testsuite/gdc.dg/asm2.d2
-rw-r--r--gcc/testsuite/gdc.dg/asm3.d10
-rw-r--r--gcc/testsuite/gdc.dg/gdc282.d6
-rw-r--r--gcc/testsuite/gdc.dg/imports/gdc170.d8
-rw-r--r--gcc/testsuite/gdc.dg/intrinsics.d36
-rw-r--r--gcc/testsuite/gdc.dg/pr101672.d2
-rw-r--r--gcc/testsuite/gdc.dg/pr90650a.d2
-rw-r--r--gcc/testsuite/gdc.dg/pr90650b.d2
-rw-r--r--gcc/testsuite/gdc.dg/pr94777a.d2
-rw-r--r--gcc/testsuite/gdc.dg/pr94777c.d62
-rw-r--r--gcc/testsuite/gdc.dg/pr95250.d2
-rw-r--r--gcc/testsuite/gdc.dg/pr96156b.d17
-rw-r--r--gcc/testsuite/gdc.dg/pr96157c.d40
-rw-r--r--gcc/testsuite/gdc.dg/pr96869.d26
-rw-r--r--gcc/testsuite/gdc.dg/pr98277.d2
-rw-r--r--gcc/testsuite/gdc.dg/pr98457.d6
-rw-r--r--gcc/testsuite/gdc.dg/simd1.d8
-rw-r--r--gcc/testsuite/gdc.dg/simd2a.d8
-rw-r--r--gcc/testsuite/gdc.dg/simd2b.d8
-rw-r--r--gcc/testsuite/gdc.dg/simd2c.d8
-rw-r--r--gcc/testsuite/gdc.dg/simd2d.d8
-rw-r--r--gcc/testsuite/gdc.dg/simd2e.d8
-rw-r--r--gcc/testsuite/gdc.dg/simd2f.d8
-rw-r--r--gcc/testsuite/gdc.dg/simd2g.d8
-rw-r--r--gcc/testsuite/gdc.dg/simd2h.d8
-rw-r--r--gcc/testsuite/gdc.dg/simd2i.d8
-rw-r--r--gcc/testsuite/gdc.dg/simd2j.d8
-rw-r--r--gcc/testsuite/gdc.dg/simd7951.d1
-rw-r--r--gcc/testsuite/gdc.dg/simd_ctfe.d87
-rw-r--r--gcc/testsuite/gdc.dg/torture/gdc309.d1
-rw-r--r--gcc/testsuite/gdc.dg/torture/pr94424.d16
-rw-r--r--gcc/testsuite/gdc.dg/torture/pr94777b.d135
-rw-r--r--gcc/testsuite/gdc.dg/torture/simd17344.d11
-rw-r--r--gcc/testsuite/gdc.dg/torture/simd20052.d17
-rw-r--r--gcc/testsuite/gdc.dg/torture/simd6.d26
-rw-r--r--gcc/testsuite/gdc.dg/torture/simd7.d18
-rw-r--r--gcc/testsuite/gdc.test/compilable/a3682.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/aliasassign.d41
-rw-r--r--gcc/testsuite/gdc.test/compilable/aliasdecl.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/art4769.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/b1215.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/b12504.d44
-rw-r--r--gcc/testsuite/gdc.test/compilable/b15206.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/b16360.d39
-rw-r--r--gcc/testsuite/gdc.test/compilable/b16697.d27
-rw-r--r--gcc/testsuite/gdc.test/compilable/b16967.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/b17111.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/b17651.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/b18197.d17
-rw-r--r--gcc/testsuite/gdc.test/compilable/b18242.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/b18489.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/b19432.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/b19442.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/b19775.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/b19829.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/b20045.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/b20067.d23
-rw-r--r--gcc/testsuite/gdc.test/compilable/b20758.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/b20780.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/b20833.d20
-rw-r--r--gcc/testsuite/gdc.test/compilable/b20885.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/b20938.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/b21285.d27
-rw-r--r--gcc/testsuite/gdc.test/compilable/b33.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/b6227.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/b6395.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/b6400.d37
-rw-r--r--gcc/testsuite/gdc.test/compilable/betterc.d27
-rw-r--r--gcc/testsuite/gdc.test/compilable/bug21196.d31
-rw-r--r--gcc/testsuite/gdc.test/compilable/callconv.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/ccompile.d36
-rw-r--r--gcc/testsuite/gdc.test/compilable/cdcmp.d148
-rw-r--r--gcc/testsuite/gdc.test/compilable/chkformat.d27
-rw-r--r--gcc/testsuite/gdc.test/compilable/commontype.d486
-rw-r--r--gcc/testsuite/gdc.test/compilable/compile1.d243
-rw-r--r--gcc/testsuite/gdc.test/compilable/cpp_abi_tag_unused.d21
-rw-r--r--gcc/testsuite/gdc.test/compilable/cppmangle.d958
-rw-r--r--gcc/testsuite/gdc.test/compilable/cppmangle2.d21
-rw-r--r--gcc/testsuite/gdc.test/compilable/cppmangle3.d23
-rw-r--r--gcc/testsuite/gdc.test/compilable/cppmangle_abitag.d106
-rw-r--r--gcc/testsuite/gdc.test/compilable/ctfe_math.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc1.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc10.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc10236.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc10236b.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc10325.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc10334.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc10366.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc10367.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc10869.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc10870.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc11.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc11479.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc11511.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc11823.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc12.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc12706.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc12745.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc13.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc13270.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc13645.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc14.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc14383.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc14413.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc14778.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc15475.d27
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc17697.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc18361.d27
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc198.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc19814.d23
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc2.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc2273.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc4.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc4162.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc5.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc5446.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc6.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc648.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc6491.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc7.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc7555.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc7656.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc7715.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc7795.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc8.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc8271.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc8739.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9037.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9155.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9305.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9369.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9475.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9497a.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9497b.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9497c.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9497d.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9676a.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9676b.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9727.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9789.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc9903.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks.d30
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks_verbose.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_code.d46
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_code_verbose.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis.d45
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis_verbose.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_escapes.d27
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings.d40
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings_verbose.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_links.d42
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_links_verbose.d17
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists.d68
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists_verbose.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote.d53
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote_verbose.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables.d42
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_verbose.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddocbackticks.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ddocunittest.d50
-rw-r--r--gcc/testsuite/gdc.test/compilable/debugInference.d55
-rw-r--r--gcc/testsuite/gdc.test/compilable/defa.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/depmsg.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/depsOutput9948.d12
-rw-r--r--gcc/testsuite/gdc.test/compilable/dip22.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/dip22d.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/disable_new.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_21217.d91
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration.d217
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration_98.d56
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d106
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d67
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d347
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d286
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d401
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_UnionDeclaration.d93
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_VarDeclaration.d116
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_cpp98_compat.d142
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_enum.d271
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_enum_cpp98.d244
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_expressions.d127
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_extern_type.d174
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d265
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_functions.d276
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_ignored.d147
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d170
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_names.d260
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_protection.d218
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_required_symbols.d225
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d90
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_unittest_block.d52
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtoh_verbose.d172
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtorfields.d52
-rw-r--r--gcc/testsuite/gdc.test/compilable/dtorfields_deprecation.d49
-rw-r--r--gcc/testsuite/gdc.test/compilable/extra-files/c6395.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/extra-files/depsOutput9948a.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/extra-files/dtoh_imports.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/extra-files/dtoh_imports2.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/extra-files/emptymain.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/extra-files/header1.d78
-rw-r--r--gcc/testsuite/gdc.test/compilable/extra-files/header17125.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/extra-files/header18365.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/extra-files/header2.d65
-rw-r--r--gcc/testsuite/gdc.test/compilable/fail137.d26
-rw-r--r--gcc/testsuite/gdc.test/compilable/fieldwise.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/filefullpath_18911.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/fix13165.d12
-rw-r--r--gcc/testsuite/gdc.test/compilable/fix17145.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/fix20416.d36
-rw-r--r--gcc/testsuite/gdc.test/compilable/fix21647.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/fix21684.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/fix22180.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/forward1.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/future.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/futurexf.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/fwdref21063.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/header18364.d24
-rw-r--r--gcc/testsuite/gdc.test/compilable/header18365.d34
-rw-r--r--gcc/testsuite/gdc.test/compilable/ice11054.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/ice11300.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/ice13403.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/ice13819.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/ice1524.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/ice20044.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/ice20415.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/ice6538.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/ice854.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/implicitconv.d33
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/a12511.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/a18911.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/cstuff3.c6
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/g313.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/imp16088.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/imp21832.d24
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/imp22122.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/impfieldwise.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/pkg11847/mod11847.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/pkg11847/package.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/protectionimp.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test11563std_traits.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test13582.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test16709a.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test16709b.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test16709c.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test16709d.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test17441foo/bar.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test17441foo/package.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test17541_2.d20
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test17541_3.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test18651/algorithm.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test18651/b.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test18651/c.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test18651/datetime.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test18771a.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test18771b.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test18771c.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test18771d.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19187.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19344.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19656a.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19656b.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19656c.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19657b.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19657c.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19657d.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19657e.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19657f.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19657g.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19746a.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19746b.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19746c.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19746d.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19750a.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19750b.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19750c.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test19750d.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test21227/..foo/a.txt1
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test21227/a..b.txt1
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test21227/a.txt1
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test21464a.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/test63a.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/testcontracts.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/testlambda1.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/testlambda2.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/u20958.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/interpret3.d1503
-rw-r--r--gcc/testsuite/gdc.test/compilable/interpret4.d31
-rw-r--r--gcc/testsuite/gdc.test/compilable/isZeroInit.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/isreturnonstack.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue12520.d21
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue15478.d55
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue15795.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue15818.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue18097.d12
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue19925.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue20362.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue20599.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue20704.d29
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue20705.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue20995.d12
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue21328.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue21378.d33
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue21662.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue21726.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue21880.d23
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue21882.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue21905.d24
-rw-r--r--gcc/testsuite/gdc.test/compilable/issue9884.d25
-rw-r--r--gcc/testsuite/gdc.test/compilable/json.d153
-rw-r--r--gcc/testsuite/gdc.test/compilable/json20742.d69
-rw-r--r--gcc/testsuite/gdc.test/compilable/minimal.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/minimal2.d31
-rw-r--r--gcc/testsuite/gdc.test/compilable/mixin.d38
-rw-r--r--gcc/testsuite/gdc.test/compilable/mixinTemplateMangling.d35
-rw-r--r--gcc/testsuite/gdc.test/compilable/mixintempl.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/nestedtempl0.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/nestedtempl1.d25
-rw-r--r--gcc/testsuite/gdc.test/compilable/nogc.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/noreturn1.d49
-rw-r--r--gcc/testsuite/gdc.test/compilable/ob1.d149
-rw-r--r--gcc/testsuite/gdc.test/compilable/pr9374.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/pr9383.d25
-rw-r--r--gcc/testsuite/gdc.test/compilable/previewall.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/previewin.d116
-rw-r--r--gcc/testsuite/gdc.test/compilable/protattr.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/protection.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/quadratic.d42
-rw-r--r--gcc/testsuite/gdc.test/compilable/readmodify_structclass.d30
-rw-r--r--gcc/testsuite/gdc.test/compilable/reinterpretctfe.d34
-rw-r--r--gcc/testsuite/gdc.test/compilable/riia_ctor.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/rvalueref.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/scope.d247
-rw-r--r--gcc/testsuite/gdc.test/compilable/scopeinfer.d30
-rw-r--r--gcc/testsuite/gdc.test/compilable/shared.d125
-rw-r--r--gcc/testsuite/gdc.test/compilable/sharedopt.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/shortened_methods.d33
-rw-r--r--gcc/testsuite/gdc.test/compilable/staticforeach.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/sw_transition_complex.d118
-rw-r--r--gcc/testsuite/gdc.test/compilable/sw_transition_field.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/sw_transition_tls.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/test1.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test10312.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test10375.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test10520.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/test10752.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test10981.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/test10993.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/test11169.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test11225a.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test11237.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/test11259.d25
-rw-r--r--gcc/testsuite/gdc.test/compilable/test11371.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test11563.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test11656.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test1170.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test11847.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/test1238.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test12496.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/test12511.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/test12558.d39
-rw-r--r--gcc/testsuite/gdc.test/compilable/test12567c.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/test12567d.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test12807.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/test13226.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test13242.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test13512.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/test13582a.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/test13582b.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/test13858.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test13953.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/test14114.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/test14275.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test14528.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test14666.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test14740.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/test14831.d60
-rw-r--r--gcc/testsuite/gdc.test/compilable/test14929.d (renamed from gcc/testsuite/gdc.test/fail_compilation/ice14929.d)13
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15019.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15150.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15225.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15292.d (renamed from gcc/testsuite/gdc.test/fail_compilation/fail15292.d)8
-rw-r--r--gcc/testsuite/gdc.test/compilable/test1537.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15389_x.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15389_y.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test1547.d20
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15490.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15519_x.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15519_y.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15780.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15785.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15856.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/test15907.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16002.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16013a.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16013b.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16037.d23
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16085.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16088.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16107.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16183.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16214a.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16273.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16460.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16492.d87
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16570.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16578a.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16578b.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16621.d23
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16635.d56
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16657.d17
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16685.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16709.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/test16798.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17057.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17143.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17146.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17351.d17
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17373.d (renamed from gcc/testsuite/gdc.test/runnable/test17373.d)14
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17419.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17441.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17512.d26
-rw-r--r--gcc/testsuite/gdc.test/compilable/test1754.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17541.d28
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17548.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17752.d12
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17782.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17793.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17807.d17
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17853.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17906.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17942.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/test17970.d28
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18000.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18020.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18030.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18099.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18115.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18199.d87
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18251.d23
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18385b.d29
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18430.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18468.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18474.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18572.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18578.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18584.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18645.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18651a.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18670.d12
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18694.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18737.d32
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18771.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18775.d20
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18821.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18905.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18936.d31
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18951a.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18951b.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/test18976.d32
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19014.d12
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19066.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19081.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19097.d23
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19108.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19187.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19203.d27
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19224.d18
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19227.d29
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19315.d20
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19409.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19464.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19491.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19499.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19519.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19540.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19557.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19609.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19631.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19652.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19656.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19657a.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19713.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19728.d52
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19731.d78
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19746.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19750.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19754.d45
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19804.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19809.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19833.d27
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19840.d21
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19895.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19936.d17
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19954.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19970.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20000.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20021.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20039.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20051.d18
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20065.d12
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20100.d50
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20136.d18
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20138.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20181.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20296.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20318.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20326.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20367.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20388.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20406.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20410.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20417.d12
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20420.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20488.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20596.d31
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20653.d20
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20656.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20661.d17
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20695.d35
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20710.d24
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20744.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20789.d34
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20795.d35
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20821.d17
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20835.d59
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20842.d33
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20868.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20906.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20909.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20923.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20958.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test20990.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21050.d24
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21058.d25
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21227.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21255.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21282.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21299a.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21299b.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21330.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21372.d24
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21398.d31
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21464.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21514.d20
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21543.d116
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21591.d46
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21659.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21661.d24
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21668.d7
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21680.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21743.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21753.d21
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21802.d38
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21806.d24
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21828.d27
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21830.d25
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21831.d20
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21832.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21861.d38
-rw-r--r--gcc/testsuite/gdc.test/compilable/test21876.d17
-rw-r--r--gcc/testsuite/gdc.test/compilable/test22122.d53
-rw-r--r--gcc/testsuite/gdc.test/compilable/test22226.d15
-rw-r--r--gcc/testsuite/gdc.test/compilable/test25.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/test2991.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test3004.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/test313a.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test313c.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test313d.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/test313e.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test313f.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test313g.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/test314.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test3775.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test4003.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/test4375.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/test50.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test5227.d23
-rw-r--r--gcc/testsuite/gdc.test/compilable/test55.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test59.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test5973.d41
-rw-r--r--gcc/testsuite/gdc.test/compilable/test6013.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test602.d8
-rw-r--r--gcc/testsuite/gdc.test/compilable/test61.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test62.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test63.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test6395.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test6541.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/test66.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/test67.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test6777.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/test68.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/test69.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test6999.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test70.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test71.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test7172.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test72.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test7399.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/test7491.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test7524.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test7754.d23
-rw-r--r--gcc/testsuite/gdc.test/compilable/test8509.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/test8543.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test8696.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/test8922a.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test8922b.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test8922c.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test8922d.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test8922e.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test8922f.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9209.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9274.d26
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9276.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9278a.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9278b.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test930.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9434.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9435.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9436.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9613.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9672.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9692.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9701.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9818.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/test9919.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/testAliasLookup.d60
-rw-r--r--gcc/testsuite/gdc.test/compilable/testCpCtor.d21
-rw-r--r--gcc/testsuite/gdc.test/compilable/testDIP37a.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/testInference.d54
-rw-r--r--gcc/testsuite/gdc.test/compilable/testVRP.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/testcontracts.d44
-rw-r--r--gcc/testsuite/gdc.test/compilable/testcstuff3.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/testdip1008.d21
-rw-r--r--gcc/testsuite/gdc.test/compilable/testexpression.d26
-rw-r--r--gcc/testsuite/gdc.test/compilable/testfwdref.d44
-rw-r--r--gcc/testsuite/gdc.test/compilable/testheader1.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/testheader12567a.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/testheader12567b.d16
-rw-r--r--gcc/testsuite/gdc.test/compilable/testheader17125.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/testheader1i.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/testheader2.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/testheader2i.d11
-rw-r--r--gcc/testsuite/gdc.test/compilable/testheader3.d31
-rw-r--r--gcc/testsuite/gdc.test/compilable/testheaderudamodule.d24
-rw-r--r--gcc/testsuite/gdc.test/compilable/testimport12242.d2
-rw-r--r--gcc/testsuite/gdc.test/compilable/testlambdacomp.d216
-rw-r--r--gcc/testsuite/gdc.test/compilable/testparse.d49
-rw-r--r--gcc/testsuite/gdc.test/compilable/testsctreturn.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/testtempl2.d24
-rw-r--r--gcc/testsuite/gdc.test/compilable/traits.d190
-rw-r--r--gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d120
-rw-r--r--gcc/testsuite/gdc.test/compilable/typeid_name.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/uda.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/udamodule1.d3
-rw-r--r--gcc/testsuite/gdc.test/compilable/udamodule2.d1
-rw-r--r--gcc/testsuite/gdc.test/compilable/union_initialization.d43
-rw-r--r--gcc/testsuite/gdc.test/compilable/vcg-ast.d25
-rw-r--r--gcc/testsuite/gdc.test/compilable/version.d23
-rw-r--r--gcc/testsuite/gdc.test/compilable/vgc1.d41
-rw-r--r--gcc/testsuite/gdc.test/compilable/vgc2.d34
-rw-r--r--gcc/testsuite/gdc.test/compilable/vgc3.d6
-rw-r--r--gcc/testsuite/gdc.test/compilable/vtemplates.d28
-rw-r--r--gcc/testsuite/gdc.test/compilable/vtemplates_list.d46
-rw-r--r--gcc/testsuite/gdc.test/compilable/warn3882.d10
-rw-r--r--gcc/testsuite/gdc.test/compilable/zerosize.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/aacmp10381.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/aliasassign.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/aliasassign1.d34
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/already_defined.d76
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b15069.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b15909.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b17918.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b19523.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b19685.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b19691.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b19691e.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b19717a.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b19730.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b20011.d40
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b20780.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b20875.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b3841.d45
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/b6227.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/betterc.d30
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/bug15613.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/bug16165.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/bug18743.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/bug19569.d90
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/bug8891.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/bug9631.d47
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ccast.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/checkimports2.d30
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/checkimports2a.d32
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/checkimports2b.d29
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/checkimports2c.d29
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/circ10280.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/class1.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/class2.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/commaexp.d57
-rwxr-xr-xgcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d45
-rwxr-xr-xgcc/testsuite/gdc.test/fail_compilation/constraints_defs.d56
-rwxr-xr-xgcc/testsuite/gdc.test/fail_compilation/constraints_func1.d93
-rwxr-xr-xgcc/testsuite/gdc.test/fail_compilation/constraints_func2.d108
-rwxr-xr-xgcc/testsuite/gdc.test/fail_compilation/constraints_func3.d60
-rwxr-xr-xgcc/testsuite/gdc.test/fail_compilation/constraints_func4.d97
-rwxr-xr-xgcc/testsuite/gdc.test/fail_compilation/constraints_tmpl.d44
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/cpp_abi_tag.d57
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/cpp_abi_tag2.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/cppeh1.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/cppmangle.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/cppmangle2.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ctfe10989.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ctfe10995.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ctfe11467.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ctfe13612.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ctfe14207.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ctfe14465.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dassert.d43
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ddoc_18083.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/debugCaseDeclaration.d39
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d191
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/depmsg.d40
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/depmsg15814.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/depmsg15815.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/deprecate1553.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/deprecated6760.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/deprecatedImports.d31
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/deprecatedTemplates.d63
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d30
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/deprecations.d66
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10089.d5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10099.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10141.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10169.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10319.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10405.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10415.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10688.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10768.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10783.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10792.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10805.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10862.d68
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10926.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag10984.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag11078.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag11132.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag11425.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag11727.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag11756.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag11769.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag12063.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag12124.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag12280.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag12312.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag12380.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag12480.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag12487.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag12678.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag12777.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag12829.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag13028.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag13215.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag13320.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag13333.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag13528.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag13609b.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag13787.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag13884.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag13942.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag14102.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag14145.d38
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag14163.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag14235.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag14818.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag14875.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag14876.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag15209.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag15411.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag15669.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag15713.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag15974.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag16499.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag16977.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag1730.d57
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag18460.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag18574.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag19022.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag19225.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag20059.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag20518.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag21883.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag2452.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag3013.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag3438.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag3672.d66
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag3672a.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag3869.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag3913.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag4479.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag4528.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag4596.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag5385.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag5450.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag6373.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag6539.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag6677.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag6699.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag6707.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag7050a.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag7050b.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag7050c.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag7420.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag7477.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag7747.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag7998.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8044.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8101.d40
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8101b.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8178.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8318.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8425.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8510.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8559.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8648.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8684.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8697.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8714.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8777.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8787.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8894.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag8928.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9004.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9148.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9191.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9210a.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9247.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9312.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9357.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9358.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9398.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9451.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9620.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9635.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9679.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9831.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9861.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9880.d5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag9961.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag_class_alloc.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag_cstyle.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag_debug_conditional.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag_err1.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag_funclit.d40
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag_template_alias.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diag_template_this.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diagin.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/diaginref.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dip22a.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dip22b.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dip22e.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dip25.d29
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/disable_new.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d190
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d43
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/e15876_1.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/e15876_2.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/e15876_3.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/e15876_4.d23
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/e15876_5.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/e15876_6.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/enum9921.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/extra-files/a14446.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail100.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10082.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail101.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10102.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10115.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10254.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10277.d42
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10299.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail104.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10481.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail105.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10528.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10534.d32
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail106.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10630.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10666.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10806.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail109.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10905.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10947.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10964.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10968.d42
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail10980.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail110.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11038.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail111.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11125.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11151.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11163.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail113.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11355.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11375.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail114.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11445.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11453b.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11503c.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11503d.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11510.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11532.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11542.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11545.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11552.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11562.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11591b.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail116.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail117.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11714.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11717.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11720.d33
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail11748.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail118.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail120.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail122.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12236.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12255.d36
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail123.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12378.d30
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12390.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail124.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12436.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail125.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail126.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12622.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12636.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail127.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12744.d36
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12749.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12764.d26
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12809.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail129.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12901.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12908.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail12932.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13064.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail131.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13116.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13120.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13187.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail132.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13203.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail133.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13336a.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13336b.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail134.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13424.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13435.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13498.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13574.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail136.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13601.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13701.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13756.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail139.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail13902.d70
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14089.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail142.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14249.d28
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail143.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14304.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail144.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14406.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14407.d47
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14416.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14486.d100
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail145.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14554.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14669.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14965.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail14997.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail150.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail15068.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail153.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail154.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail155.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail15535.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail15550.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail156.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail15616a.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail15616b.d32
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail15626.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail15667.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail15691.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail15755.d29
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail158.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail159.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail160.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail16001.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail161.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail162.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail16206a.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail16206b.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail163.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail16600.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail16689.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail169.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail16997.d59
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail170.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail172.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17275.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17354.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17491.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17492.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17502.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17518.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17570.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail176.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17602.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17612.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17625.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17646.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail177.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17722a.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17722b.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17842.d29
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail179.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17927.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17955.d102
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17969.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail17976.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail180.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18057.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18093.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18228.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18236.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18243.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail183.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18417.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail185.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18620.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail187.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18719.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail188.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18892.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18938.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18970.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18979.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18985.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail18994.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail190.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail1900.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19038.d29
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19076.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19098.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19099.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19103.d36
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19107.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19181.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail192.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19202.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19209.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail193.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19319a.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19319b.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail194.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19441.d49
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19447.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail195.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19609.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19687.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19729.d37
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19744.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19757_m32.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19757_m64.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail198.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19871.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19881.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19890a.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19890b.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19897.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19898a.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19898b.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19911b.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19911c.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19912a.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19912b.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19912c.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19912d.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19912e.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19913.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19914.d5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19915.d5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19917.d49
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19919.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19922.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19923.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19931.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail1995.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19955.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19965.d37
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20000.d39
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20033.d54
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20040.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20073.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20084.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20108.d31
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20163.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20164.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20183.d47
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20376.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20448.d23
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20461.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20538.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20547.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20551.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20609.d45
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20637.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20638.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20658.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20691.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail207.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20714.d32
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20730a.d39
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20730b.d46
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20771.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20772.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20775.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20779.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail208.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20800.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail209.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail20965.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21091a.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21091b.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21092.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail212.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21275.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail213.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail215.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21508.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21508_2.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21547.d34
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail216.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail218.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21830.d34
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21831.d29
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21832.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21849.d36
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21868b.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21885.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21928.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail21928b.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail2195.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22035.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22054.d23
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22075.d30
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22084.d23
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail221.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22118.d36
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22121.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22121/imports/test22121/package.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22138.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail22157.d34
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail222.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail223.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail224.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail229.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail23.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail231.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail233.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail235.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail236.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail2361.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail237.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail24.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail240.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail241.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail243.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail244.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail245.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail2450.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail2456.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail246.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail247.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail248.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail249.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail25.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail250.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail251.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail253.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail256.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail259.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail261.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail262.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail263.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail265.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail267.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail270.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail272.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail273.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail275.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail278.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail2789.d109
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail282.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail284.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail288.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail291.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail296.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail2962.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail297.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail299.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail3.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail301.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail302.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail303.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail305.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail309.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail310.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail311.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail312.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail313.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail314.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail3144.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail315.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail317.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail318.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail319.d5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail320.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail324.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail325.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail328.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail329.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail330.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail331.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail332.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail333.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail336.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail337.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail34.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail340.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail341.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail343.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail347.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail349.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail35.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail351.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail354.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail355.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail36.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail3672.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail3703.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail3753.d48
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail37_m32.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail37_m64.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail38.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail3882.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail39.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail3990.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail40.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4082.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail41.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail42.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375a.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375b.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375c.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375d.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375e.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375f.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375g.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375h.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375i.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375j.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375k.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375l.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375m.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375o.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375r.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375s.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375t.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375u.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375v.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375w.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375x.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4375y.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail44.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4421.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4448.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail45.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4517.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4544.d23
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail46.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4611.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail4923.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail50.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail51.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail5153.d28
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail52.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail54.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail59.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail61.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail6107.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail62.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail6242.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail63.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail6334.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail6453.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail66.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail6652.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail6795.d37
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail6889.d30
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail7173.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail73.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail7352.d52
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail74.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail7443.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail75.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail76.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail7848.d43
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail7862.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail79.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail7903.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail8009.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail809.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail8217.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail8262.d33
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail8373.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail86.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail8631.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail8724.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9063.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9081.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail91.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9199.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail92.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9290.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail93.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9346.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9368.d49
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail94.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9413.d42
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9414a.d42
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9414b.d42
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9414c.d42
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9414d.d42
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail95.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9537.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9562.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail96.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9613.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9665a.d77
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9665b.d26
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail97.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9710.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9766.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9773.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9790.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail98.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9891.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9892.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail9936.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/failCopyCtor.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/failCopyCtor2.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_arrayexp.d30
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_arrayop1.d53
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d163
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3a.d28
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3b.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3c.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_casting.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_casting2.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_circular.d64
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_circular2.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_contracts3.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_opover.d28
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_pretty_errors.d36
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail_scope.d32
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/failattr.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/failmemalloc.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/failob1.d34
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/failob2.d67
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/failoffset.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fix17349.d (renamed from gcc/testsuite/gdc.test/compilable/fix17349.d)8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fix17635.d23
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fix17751.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fix18575.d41
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fix19018.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fix19059.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fix19246.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fix5212.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fob1.d63
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fob2.d178
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/gag4269f.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/goto1.d26
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/goto2.d143
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/goto3.d37
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10016.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10076.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10212.d5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10259.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10341.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10419.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10600.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10616.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10624.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10651.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10713.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10727a.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10727b.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10922.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10938.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice10949.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11086.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11404.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice1144.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11472.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11513a.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11513b.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11518.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11552.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11553.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11755.d30
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11790.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11793.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11822.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11849b.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11850.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11856_0.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11919.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11922.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11925.d (renamed from gcc/testsuite/gdc.test/compilable/ice11925.d)7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice11944.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12040.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12158.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12174.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12235.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12350.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12362.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12534.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12539.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12574.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12727.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12827.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12841.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice12902.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13024.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13027.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13081.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13131.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13220.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13221.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13225.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13311.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13356.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13382.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13385.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13459.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13465a.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13465b.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice1358.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13788.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13816.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13835.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13921.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice13987.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14055.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14096.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14116.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14130.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14146.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14177.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14272.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14424.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14446.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14621.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14642.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14844.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14907.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice15092.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice15172.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice15332.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice15441.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice15688.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice15788.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice15816.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice15922.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice16035.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice16657.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice17074.d26
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice17831.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice18469.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice18753.d39
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice18803a.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice18803b.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice19295.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice19755.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice19762.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice19887.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice19950.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice20042.d29
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice20056.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice20057.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice20264.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice20545.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice20709.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice21095.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice2843.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice4094.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice4983.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice6538.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice7645.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice8100.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice8255.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice8309.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice8711.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice8795.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice9273a.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice9273b.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice9284.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice9338.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice9439.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice9494.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice9545.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice9759.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice9806.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice9865.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/impconv.d40
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imphint.d90
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/a14407.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/a17625.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/a18243.d5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/b17625.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/b17918a.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/b19762.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/c19762.d27
-rwxr-xr-xgcc/testsuite/gdc.test/fail_compilation/imports/constraints.d73
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/deprecatedImporta.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/deprecatedImportb.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/diag20518a.d0
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/diag20518a/b.d0
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdcomplex.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/fail20164.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/fail20637b.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/fail20638b.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/fail21275a.d34
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/i20057.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/imp17602.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/imp18554.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/imp18979.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/imp19661.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/imp20709.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/imp21832.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/import21508.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/issue21685.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/test18480a.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/test18480b.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/test18938a/cache.d0
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/test18938a/file.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/test18938b/file.d28
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/test19107a.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/test19107b.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/test20267.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/imports/test21246.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/issue15103.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/issue20422.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/issue20627.d67
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/issue20704.d39
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/issue21203.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/issue21295.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/issue21378.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/issue21685_main.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/issue21936.d32
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/issue3827.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/lexer1.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/lexer2.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/lexer3.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/lexer4.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/lookup.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/mangle1.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/mangle2.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/misc1.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d51
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/mixin.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/mixin_gc.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/nestedtempl0.d35
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/nestedtempl1.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/nestedtempl2.d38
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/nestedtempl3.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d26
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/no_TypeInfo.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/nogc1.d44
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/nogc2.d35
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/nogc3.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/noreturn.d118
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/notype.d31
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/objc_class2.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/objc_class3.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/objc_non_objc_base.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/parse12967a.d32
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/parse12967b.d50
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/parse19277.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/parseStc2.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/parseStc3.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/parseStc4.d23
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/parseStc5.d31
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/pragmainline.d5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/pragmas.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/previewin.d42
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/protattr1.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/protattr2.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/protattr3.d1
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/pull12941.d31
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/reserved_version.d206
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/retref2.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/retscope.d87
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/retscope2.d51
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/retscope3.d130
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/retscope4.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/retscope5.d26
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/retscope6.d233
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/scope_class.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/scope_type.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/shared.d227
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/skip.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/spell9644.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/staticforeach4.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/switches.d35
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test10.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test1021.d171
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test11006.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test11047.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test11176.d5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test12228.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test12385.d30
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test12558.d57
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test12822.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test13152.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test13536.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test13537.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test13667.d101
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test13786.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test13867.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test14064.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test14238.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test143.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test14496.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test14538.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15177.d (renamed from gcc/testsuite/gdc.test/fail_compilation/test15117.d)5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15191.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15306.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15373.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15399.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15544.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15660.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15672.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15703.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15704.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15785.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15785b.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15897.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15925.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test15989.d7
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test16095.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test16116.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test16193.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test16195.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test16228.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test16284.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test16365.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test16381.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test16523.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test16589.d26
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test16694.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17284.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17380spec.d23
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17422.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17423.d29
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17450.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17451.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17586.d14
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17868.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17868b.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17892.d32
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test17959.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test18130.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test18282.d89
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test18385.d31
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test18385b.d47
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test18480.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test18484.d26
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test18554.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test18597.d27
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test18607.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test18644.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test18708.d64
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test18736.d23
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test19097.d56
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test19107.d25
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test19112.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test19176.d26
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test19193.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test19473.d31
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test19646.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test19661.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test19971.d17
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20096.d28
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20149.d34
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20245.d43
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20267.d31
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20324.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20383.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20515.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20549.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20565.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20569.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20610.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20626.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20696.d21
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20719.d32
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21096.d13
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21198.d24
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21204.d23
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21246.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21259.d52
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21319.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21518.d38
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21665.d31
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21807.d54
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21912.d54
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test22048.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test22227.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test314.d2
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test4838.d12
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test4946.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test64.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test8556.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test9150.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test9176.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/testCols.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/testInference.d33
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/testpull1810.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d8
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/traits.d91
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/traits_child.d6
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/typeerrors.d31
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/union_initialization.d88
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/vararg2.d23
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/varargsstc.d11
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/verifyhookexist.d45
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/warn13679.d5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/warn7444.d3
-rw-r--r--gcc/testsuite/gdc.test/runnable/A16.d11
-rw-r--r--gcc/testsuite/gdc.test/runnable/Same.d11
-rw-r--r--gcc/testsuite/gdc.test/runnable/a17.d10
-rw-r--r--gcc/testsuite/gdc.test/runnable/a18.d12
-rw-r--r--gcc/testsuite/gdc.test/runnable/a21.d14
-rw-r--r--gcc/testsuite/gdc.test/runnable/aliasassign.d31
-rw-r--r--gcc/testsuite/gdc.test/runnable/aliasthis.d222
-rw-r--r--gcc/testsuite/gdc.test/runnable/arrayop.d96
-rw-r--r--gcc/testsuite/gdc.test/runnable/auto1.d13
-rw-r--r--gcc/testsuite/gdc.test/runnable/b10562.d93
-rw-r--r--gcc/testsuite/gdc.test/runnable/b16360.d50
-rw-r--r--gcc/testsuite/gdc.test/runnable/b18034.d28
-rw-r--r--gcc/testsuite/gdc.test/runnable/b19584.d13
-rw-r--r--gcc/testsuite/gdc.test/runnable/b20470.d97
-rw-r--r--gcc/testsuite/gdc.test/runnable/b20890.d48
-rw-r--r--gcc/testsuite/gdc.test/runnable/b26.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/b6400.d69
-rw-r--r--gcc/testsuite/gdc.test/runnable/bench1.d14
-rw-r--r--gcc/testsuite/gdc.test/runnable/betterc.d202
-rw-r--r--gcc/testsuite/gdc.test/runnable/bettercUnittest.d38
-rw-r--r--gcc/testsuite/gdc.test/runnable/bitops.d58
-rw-r--r--gcc/testsuite/gdc.test/runnable/bug11155.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/bug19652.d22
-rw-r--r--gcc/testsuite/gdc.test/runnable/bug7068.d3
-rw-r--r--gcc/testsuite/gdc.test/runnable/builtin.d39
-rw-r--r--gcc/testsuite/gdc.test/runnable/cassert.d17
-rw-r--r--gcc/testsuite/gdc.test/runnable/casting.d53
-rw-r--r--gcc/testsuite/gdc.test/runnable/circular.d25
-rw-r--r--gcc/testsuite/gdc.test/runnable/closure.d12
-rw-r--r--gcc/testsuite/gdc.test/runnable/complex.d1180
-rw-r--r--gcc/testsuite/gdc.test/runnable/constfold.d96
-rw-r--r--gcc/testsuite/gdc.test/runnable/cppdtor.d143
-rw-r--r--gcc/testsuite/gdc.test/runnable/ctorpowtests.d72
-rw-r--r--gcc/testsuite/gdc.test/runnable/declaration.d28
-rw-r--r--gcc/testsuite/gdc.test/runnable/delegate.d45
-rw-r--r--gcc/testsuite/gdc.test/runnable/dhry.d931
-rw-r--r--gcc/testsuite/gdc.test/runnable/eh.d188
-rw-r--r--gcc/testsuite/gdc.test/runnable/entity1.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/evalorder.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/extra-files/lib13742a.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/extra-files/lib13742b.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/extra-files/minimal/object.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/extra-files/moreBettercUnittests.d11
-rw-r--r--gcc/testsuite/gdc.test/runnable/extra-files/test13742.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/extra-files/teststdio.txt6
-rw-r--r--gcc/testsuite/gdc.test/runnable/fix20466.d40
-rw-r--r--gcc/testsuite/gdc.test/runnable/fix22115.d70
-rw-r--r--gcc/testsuite/gdc.test/runnable/foreach.d31
-rw-r--r--gcc/testsuite/gdc.test/runnable/foreach2.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/foreach3.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/foreach4.d45
-rw-r--r--gcc/testsuite/gdc.test/runnable/foreach5.d128
-rw-r--r--gcc/testsuite/gdc.test/runnable/funclit.d95
-rw-r--r--gcc/testsuite/gdc.test/runnable/functype.d12
-rw-r--r--gcc/testsuite/gdc.test/runnable/hello.d4
-rw-r--r--gcc/testsuite/gdc.test/runnable/helloUTF8.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/ice15030.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/ice21696.d23
-rw-r--r--gcc/testsuite/gdc.test/runnable/ice21727.d46
-rw-r--r--gcc/testsuite/gdc.test/runnable/ifti.d53
-rw-r--r--gcc/testsuite/gdc.test/runnable/implicit.d35
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/A16a.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/Other.d11
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/a12037.d37
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/a21a.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/another_module_with_tests.d4
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/depsprot_default.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/depsprot_private.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/depsprot_public.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/module_with_tests.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/pubprivtmpla.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/std11file.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/std15017variant.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/template_ovs1.d9
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/template_ovs2.d9
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/template_ovs3.d5
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test11931a.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test11931d.d19
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test13a.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test15777a.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test15777b.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test17181a.d10
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test17181b.d3
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test17181c.d7
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test18868_a.d3
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test18868_fls.d33
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test19655b.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test19655c.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test19655d.d14
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test19655e.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test19655f.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test19655g.d3
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test24a.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test24b.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test24c.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test27a.d13
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test39a.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test40a.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test45a.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test45b.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test49a.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/testmod2a.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/inclusive_incontracts.d80
-rw-r--r--gcc/testsuite/gdc.test/runnable/inline.d71
-rw-r--r--gcc/testsuite/gdc.test/runnable/inner.d20
-rw-r--r--gcc/testsuite/gdc.test/runnable/interface.d9
-rw-r--r--gcc/testsuite/gdc.test/runnable/interface2.d28
-rw-r--r--gcc/testsuite/gdc.test/runnable/interface3.d10
-rw-r--r--gcc/testsuite/gdc.test/runnable/interpret.d151
-rw-r--r--gcc/testsuite/gdc.test/runnable/interpret2.d16
-rw-r--r--gcc/testsuite/gdc.test/runnable/issue16995.d42
-rw-r--r--gcc/testsuite/gdc.test/runnable/issue8671.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/lazy.d22
-rw-r--r--gcc/testsuite/gdc.test/runnable/lexer.d4
-rw-r--r--gcc/testsuite/gdc.test/runnable/link11069a.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/link11127.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/link12037.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/link12144.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/link13043.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/link13350.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/link13415.d14
-rw-r--r--gcc/testsuite/gdc.test/runnable/link14074a.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/link14074b.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/link14541.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/link14992.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/link15017.d7
-rw-r--r--gcc/testsuite/gdc.test/runnable/link6574.d12
-rw-r--r--gcc/testsuite/gdc.test/runnable/link7745.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/literal.d27
-rw-r--r--gcc/testsuite/gdc.test/runnable/loopunroll.d21
-rw-r--r--gcc/testsuite/gdc.test/runnable/m1.d12
-rw-r--r--gcc/testsuite/gdc.test/runnable/manboy.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/mangle.d48
-rw-r--r--gcc/testsuite/gdc.test/runnable/mars1.d1838
-rw-r--r--gcc/testsuite/gdc.test/runnable/minimal.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/minimal2.d46
-rw-r--r--gcc/testsuite/gdc.test/runnable/mixin1.d98
-rw-r--r--gcc/testsuite/gdc.test/runnable/mixin2.d30
-rw-r--r--gcc/testsuite/gdc.test/runnable/mod1.d10
-rw-r--r--gcc/testsuite/gdc.test/runnable/nan.d42
-rw-r--r--gcc/testsuite/gdc.test/runnable/nested.d121
-rw-r--r--gcc/testsuite/gdc.test/runnable/newdel.d70
-rw-r--r--gcc/testsuite/gdc.test/runnable/nogc.d12
-rw-r--r--gcc/testsuite/gdc.test/runnable/nulltype.d12
-rw-r--r--gcc/testsuite/gdc.test/runnable/opdisp.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/opover.d78
-rw-r--r--gcc/testsuite/gdc.test/runnable/opover2.d137
-rw-r--r--gcc/testsuite/gdc.test/runnable/opover3.d4
-rw-r--r--gcc/testsuite/gdc.test/runnable/overload.d101
-rw-r--r--gcc/testsuite/gdc.test/runnable/previewin.d189
-rw-r--r--gcc/testsuite/gdc.test/runnable/printargs.d4
-rw-r--r--gcc/testsuite/gdc.test/runnable/property.d4
-rw-r--r--gcc/testsuite/gdc.test/runnable/property2.d67
-rw-r--r--gcc/testsuite/gdc.test/runnable/pubprivtmpl.d20
-rw-r--r--gcc/testsuite/gdc.test/runnable/s2ir.d19
-rw-r--r--gcc/testsuite/gdc.test/runnable/sctor.d88
-rw-r--r--gcc/testsuite/gdc.test/runnable/sctor2.d20
-rw-r--r--gcc/testsuite/gdc.test/runnable/sdtor.d480
-rw-r--r--gcc/testsuite/gdc.test/runnable/statictor.d23
-rw-r--r--gcc/testsuite/gdc.test/runnable/stress.d194
-rw-r--r--gcc/testsuite/gdc.test/runnable/structlit.d86
-rw-r--r--gcc/testsuite/gdc.test/runnable/template1.d30
-rw-r--r--gcc/testsuite/gdc.test/runnable/template13478.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/template2.d40
-rw-r--r--gcc/testsuite/gdc.test/runnable/template4.d64
-rw-r--r--gcc/testsuite/gdc.test/runnable/template9.d526
-rw-r--r--gcc/testsuite/gdc.test/runnable/test10.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/test10378.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test10619.d38
-rw-r--r--gcc/testsuite/gdc.test/runnable/test10736.d11
-rw-r--r--gcc/testsuite/gdc.test/runnable/test10942.d16
-rw-r--r--gcc/testsuite/gdc.test/runnable/test11.d20
-rw-r--r--gcc/testsuite/gdc.test/runnable/test11447c.d3
-rw-r--r--gcc/testsuite/gdc.test/runnable/test11863.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test11934.d22
-rw-r--r--gcc/testsuite/gdc.test/runnable/test12.d70
-rw-r--r--gcc/testsuite/gdc.test/runnable/test12486.d18
-rw-r--r--gcc/testsuite/gdc.test/runnable/test14874.d76
-rw-r--r--gcc/testsuite/gdc.test/runnable/test15.d134
-rw-r--r--gcc/testsuite/gdc.test/runnable/test15079.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/test15373.d15
-rw-r--r--gcc/testsuite/gdc.test/runnable/test15568.d58
-rw-r--r--gcc/testsuite/gdc.test/runnable/test15624.d51
-rw-r--r--gcc/testsuite/gdc.test/runnable/test16047.d17
-rw-r--r--gcc/testsuite/gdc.test/runnable/test16115.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test16140.d32
-rw-r--r--gcc/testsuite/gdc.test/runnable/test16555.d20
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17072.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17073.d13
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17181.d12
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17181b.d16
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17246.d50
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17258.d33
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17337.d23
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17338.d34
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17559.d84
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17684.d17
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17868.d45
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17868b.d52
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17885.d11
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17940.d46
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17943.d9
-rw-r--r--gcc/testsuite/gdc.test/runnable/test17965.d29
-rw-r--r--gcc/testsuite/gdc.test/runnable/test18296.d24
-rw-r--r--gcc/testsuite/gdc.test/runnable/test18534.d18
-rw-r--r--gcc/testsuite/gdc.test/runnable/test18545.d63
-rw-r--r--gcc/testsuite/gdc.test/runnable/test18746.d16
-rw-r--r--gcc/testsuite/gdc.test/runnable/test18868.d9
-rw-r--r--gcc/testsuite/gdc.test/runnable/test18868_2.d13
-rw-r--r--gcc/testsuite/gdc.test/runnable/test18868_3.d16
-rw-r--r--gcc/testsuite/gdc.test/runnable/test18880.d20
-rw-r--r--gcc/testsuite/gdc.test/runnable/test18916.d22
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19.d18
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19086.d64
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19122.d46
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19185.d22
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19192.d18
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19223.d38
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19251.d20
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19317.d32
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19386.d36
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19393.d37
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19441.d24
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19476.d18
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19639.d22
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19655a.d10
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19672.d21
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19679.d21
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19688.d13
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19729.d61
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19734.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19774.d43
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19782.d23
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19822.d29
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19825.d42
-rw-r--r--gcc/testsuite/gdc.test/runnable/test19891.d13
-rw-r--r--gcc/testsuite/gdc.test/runnable/test20.d109
-rw-r--r--gcc/testsuite/gdc.test/runnable/test20025.d21
-rw-r--r--gcc/testsuite/gdc.test/runnable/test20036.d10
-rw-r--r--gcc/testsuite/gdc.test/runnable/test20130.d44
-rw-r--r--gcc/testsuite/gdc.test/runnable/test20401.d20
-rw-r--r--gcc/testsuite/gdc.test/runnable/test20565.d18
-rw-r--r--gcc/testsuite/gdc.test/runnable/test20649.d15
-rw-r--r--gcc/testsuite/gdc.test/runnable/test20855.d26
-rw-r--r--gcc/testsuite/gdc.test/runnable/test20893.d21
-rw-r--r--gcc/testsuite/gdc.test/runnable/test21040.d61
-rw-r--r--gcc/testsuite/gdc.test/runnable/test21120.d27
-rw-r--r--gcc/testsuite/gdc.test/runnable/test21357.d35
-rw-r--r--gcc/testsuite/gdc.test/runnable/test21403.d72
-rw-r--r--gcc/testsuite/gdc.test/runnable/test21424.d12
-rw-r--r--gcc/testsuite/gdc.test/runnable/test21479.d28
-rw-r--r--gcc/testsuite/gdc.test/runnable/test21515.d81
-rw-r--r--gcc/testsuite/gdc.test/runnable/test21586.d31
-rw-r--r--gcc/testsuite/gdc.test/runnable/test21822.d18
-rw-r--r--gcc/testsuite/gdc.test/runnable/test21833.d30
-rw-r--r--gcc/testsuite/gdc.test/runnable/test22.d357
-rw-r--r--gcc/testsuite/gdc.test/runnable/test22209.d21
-rw-r--r--gcc/testsuite/gdc.test/runnable/test23.d177
-rw-r--r--gcc/testsuite/gdc.test/runnable/test24.d4
-rw-r--r--gcc/testsuite/gdc.test/runnable/test27.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/test28.d159
-rw-r--r--gcc/testsuite/gdc.test/runnable/test29.d13
-rw-r--r--gcc/testsuite/gdc.test/runnable/test3.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test30.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test34.d226
-rw-r--r--gcc/testsuite/gdc.test/runnable/test3449.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/test3574a.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test3574b.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test3574c.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test3574d.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test37.d9
-rw-r--r--gcc/testsuite/gdc.test/runnable/test38.d14
-rw-r--r--gcc/testsuite/gdc.test/runnable/test4.d166
-rw-r--r--gcc/testsuite/gdc.test/runnable/test40.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test42.d352
-rw-r--r--gcc/testsuite/gdc.test/runnable/test42a.d9
-rw-r--r--gcc/testsuite/gdc.test/runnable/test435.d14
-rw-r--r--gcc/testsuite/gdc.test/runnable/test45.d16
-rw-r--r--gcc/testsuite/gdc.test/runnable/test48.d14
-rw-r--r--gcc/testsuite/gdc.test/runnable/test49.d14
-rw-r--r--gcc/testsuite/gdc.test/runnable/test5.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/test52.d45
-rw-r--r--gcc/testsuite/gdc.test/runnable/test5305.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/test60.d23
-rw-r--r--gcc/testsuite/gdc.test/runnable/test61.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test6795.d26
-rw-r--r--gcc/testsuite/gdc.test/runnable/test711.d51
-rw-r--r--gcc/testsuite/gdc.test/runnable/test7452.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/test7511.d18
-rw-r--r--gcc/testsuite/gdc.test/runnable/test7932.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/test8.d115
-rw-r--r--gcc/testsuite/gdc.test/runnable/test809.d13
-rw-r--r--gcc/testsuite/gdc.test/runnable/test8544.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/test9259.d3
-rw-r--r--gcc/testsuite/gdc.test/runnable/test9271.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/testCopyCtor.d159
-rw-r--r--gcc/testsuite/gdc.test/runnable/test_dip1006.d38
-rw-r--r--gcc/testsuite/gdc.test/runnable/test_dip1006b.d35
-rw-r--r--gcc/testsuite/gdc.test/runnable/testaa.d91
-rw-r--r--gcc/testsuite/gdc.test/runnable/testaa2.d32
-rw-r--r--gcc/testsuite/gdc.test/runnable/testaa3.d7
-rw-r--r--gcc/testsuite/gdc.test/runnable/testabi.d926
-rw-r--r--gcc/testsuite/gdc.test/runnable/testaliascast.d63
-rw-r--r--gcc/testsuite/gdc.test/runnable/testappend.d16
-rw-r--r--gcc/testsuite/gdc.test/runnable/testassert.d380
-rw-r--r--gcc/testsuite/gdc.test/runnable/testassert_debug.d26
-rw-r--r--gcc/testsuite/gdc.test/runnable/testassign.d73
-rw-r--r--gcc/testsuite/gdc.test/runnable/testbitarray.d17
-rw-r--r--gcc/testsuite/gdc.test/runnable/testbounds.d123
-rw-r--r--gcc/testsuite/gdc.test/runnable/testbtst.d156
-rw-r--r--gcc/testsuite/gdc.test/runnable/testcgelem.d47
-rw-r--r--gcc/testsuite/gdc.test/runnable/testclass.d54
-rw-r--r--gcc/testsuite/gdc.test/runnable/testconst.d142
-rw-r--r--gcc/testsuite/gdc.test/runnable/testcontracts.d196
-rw-r--r--gcc/testsuite/gdc.test/runnable/testdefault_after_variadic.d98
-rw-r--r--gcc/testsuite/gdc.test/runnable/testdstress.d58
-rw-r--r--gcc/testsuite/gdc.test/runnable/testdt.d18
-rw-r--r--gcc/testsuite/gdc.test/runnable/testenum.d26
-rw-r--r--gcc/testsuite/gdc.test/runnable/testfile.d25
-rw-r--r--gcc/testsuite/gdc.test/runnable/testfloat.d239
-rw-r--r--gcc/testsuite/gdc.test/runnable/testformat.d126
-rw-r--r--gcc/testsuite/gdc.test/runnable/testgc2.d22
-rw-r--r--gcc/testsuite/gdc.test/runnable/testgc3.d11
-rw-r--r--gcc/testsuite/gdc.test/runnable/testinvariant.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/testkeyword.d4
-rw-r--r--gcc/testsuite/gdc.test/runnable/testline.d5
-rw-r--r--gcc/testsuite/gdc.test/runnable/testmain.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable/testminit.d13
-rw-r--r--gcc/testsuite/gdc.test/runnable/testmmfile.d120
-rw-r--r--gcc/testsuite/gdc.test/runnable/testmod2.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/testpic.d19
-rw-r--r--gcc/testsuite/gdc.test/runnable/testptrref.d29
-rw-r--r--gcc/testsuite/gdc.test/runnable/testptrref_gc.d3
-rw-r--r--gcc/testsuite/gdc.test/runnable/testreturn.d14
-rw-r--r--gcc/testsuite/gdc.test/runnable/testrightthis.d16
-rw-r--r--gcc/testsuite/gdc.test/runnable/testsafe.d20
-rw-r--r--gcc/testsuite/gdc.test/runnable/testscope.d55
-rw-r--r--gcc/testsuite/gdc.test/runnable/testscope2.d8
-rw-r--r--gcc/testsuite/gdc.test/runnable/testsignals.d114
-rw-r--r--gcc/testsuite/gdc.test/runnable/testsocket.d51
-rw-r--r--gcc/testsuite/gdc.test/runnable/teststdio.d34
-rw-r--r--gcc/testsuite/gdc.test/runnable/testswitch.d48
-rw-r--r--gcc/testsuite/gdc.test/runnable/testthread.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/testthread2.d39
-rw-r--r--gcc/testsuite/gdc.test/runnable/testtypeid.d102
-rw-r--r--gcc/testsuite/gdc.test/runnable/traits.d254
-rw-r--r--gcc/testsuite/gdc.test/runnable/traits_getPointerBitmap.d7
-rw-r--r--gcc/testsuite/gdc.test/runnable/traits_getUnitTests.d2
-rw-r--r--gcc/testsuite/gdc.test/runnable/tuple_default_parameters.d64
-rw-r--r--gcc/testsuite/gdc.test/runnable/uda.d28
-rw-r--r--gcc/testsuite/gdc.test/runnable/ufcs.d127
-rw-r--r--gcc/testsuite/gdc.test/runnable/uniformctor.d22
-rw-r--r--gcc/testsuite/gdc.test/runnable/unique_typeinfo_names.d93
-rw-r--r--gcc/testsuite/gdc.test/runnable/variadic.d38
-rw-r--r--gcc/testsuite/gdc.test/runnable/version.d12
-rw-r--r--gcc/testsuite/gdc.test/runnable/warning1.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/wc.d4
-rw-r--r--gcc/testsuite/gdc.test/runnable/wc2.d6
-rw-r--r--gcc/testsuite/gdc.test/runnable/whetstone.d231
-rw-r--r--gcc/testsuite/gdc.test/runnable/xdtor.d26
-rw-r--r--gcc/testsuite/gdc.test/runnable/xpostblit.d59
-rw-r--r--gcc/testsuite/gdc.test/runnable/xtest46.d632
-rw-r--r--gcc/testsuite/gdc.test/runnable/xtest46_gc.d37
-rw-r--r--gcc/testsuite/gdc.test/runnable/xtest47.d67
-rw-r--r--gcc/testsuite/gdc.test/runnable/xtest55.d7
-rw-r--r--gcc/testsuite/gdc.test/runnable/xtestenum.d11
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/abi_tags.d139
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/cpp11.d70
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d116
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/cpp_stdlib.d58
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/cppa.d497
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/externmangle.d57
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/externmangle2.d216
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/abi_tags.cpp146
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/c14203.cpp2
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp11.cpp35
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp19179.cpp15
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_abi_tests.cpp103
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_stdlib.cpp47
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.cpp262
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.h83
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/externmangle.cpp59
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/stdint.cpp8
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/test20652.cpp34
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/test21515.cpp18
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/extra-files/test6716.cpp13
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/stdint.d24
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/test14203.d22
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/test19179.d32
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/test20652.d23
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/test21515.d1
-rw-r--r--gcc/testsuite/gdc.test/runnable_cxx/test6716.d20
-rw-r--r--gcc/testsuite/lib/gdc-utils.exp81
2437 files changed, 213443 insertions, 133854 deletions
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 7054201..81ea8a7 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1092,6 +1092,10 @@ SYSLIBS = @GNAT_LIBEXC@
GNATBIND = @GNATBIND@
GNATMAKE = @GNATMAKE@
+# Used from d/Make-lang.in
+GDC = @GDC@
+GDCFLAGS = @GDCFLAGS@
+
# Libs needed (at present) just for jcf-dump.
LDEXP_LIB = @LDEXP_LIB@
diff --git a/gcc/configure b/gcc/configure
index fab7621..a5160da 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -858,6 +858,8 @@ EGREP
GREP
CXXCPP
PICFLAG_FOR_TARGET
+GDCFLAGS
+GDC
GNATMAKE
GNATBIND
ac_ct_CXX
@@ -5257,6 +5259,106 @@ else
fi
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gdc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gdc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_GDC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$GDC"; then
+ ac_cv_prog_GDC="$GDC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_GDC="${ac_tool_prefix}gdc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+GDC=$ac_cv_prog_GDC
+if test -n "$GDC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GDC" >&5
+$as_echo "$GDC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_GDC"; then
+ ac_ct_GDC=$GDC
+ # Extract the first word of "gdc", so it can be a program name with args.
+set dummy gdc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_GDC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_GDC"; then
+ ac_cv_prog_ac_ct_GDC="$ac_ct_GDC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_GDC="gdc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_GDC=$ac_cv_prog_ac_ct_GDC
+if test -n "$ac_ct_GDC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_GDC" >&5
+$as_echo "$ac_ct_GDC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_GDC" = x; then
+ GDC="no"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ GDC=$ac_ct_GDC
+ fi
+else
+ GDC="$ac_cv_prog_GDC"
+fi
+
+if test "x$GDC" != xno; then
+ have_gdc=yes
+else
+ have_gdc=no
+fi
+
+
# Do configure tests with the C++ compiler, since that's what we build with.
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
@@ -5275,6 +5377,7 @@ esac
+
# Determine PICFLAG for target gnatlib.
@@ -19458,7 +19561,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 19461 "configure"
+#line 19564 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -19564,7 +19667,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 19567 "configure"
+#line 19670 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
diff --git a/gcc/configure.ac b/gcc/configure.ac
index aa2f6d8..df4d2d8 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -435,6 +435,7 @@ rm -f a.out a.exe b.out
AC_PROG_CC
AC_PROG_CXX
ACX_PROG_GNAT([-I"$srcdir"/ada/libgnat])
+ACX_PROG_GDC([-I"$srcdir"/d])
# Do configure tests with the C++ compiler, since that's what we build with.
AC_LANG(C++)
@@ -448,6 +449,7 @@ case "$CC" in
esac
AC_SUBST(CFLAGS)
AC_SUBST(CXXFLAGS)
+AC_SUBST(GDCFLAGS)
# Determine PICFLAG for target gnatlib.
GCC_PICFLAG_FOR_TARGET
diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index 1ed8134..4c0a032 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -46,30 +46,61 @@ gdc-cross$(exeext): gdc$(exeext)
-rm -f gdc-cross$(exeext)
cp gdc$(exeext) gdc-cross$(exeext)
-# Filter out pedantic and virtual overload warnings.
-d-warn = $(filter-out -pedantic -Woverloaded-virtual, $(STRICT_WARN))
-
-# Also filter out warnings for missing format attributes in the D Frontend.
-DMD_WARN_CXXFLAGS = $(filter-out -Wmissing-format-attribute, $(WARN_CXXFLAGS))
-DMD_COMPILE = $(subst $(WARN_CXXFLAGS), $(DMD_WARN_CXXFLAGS), $(COMPILE))
+# Use strict warnings.
+d-warn = $(STRICT_WARN)
+
+# D compiler and flags for building the front-end.
+ifeq ($(TREECHECKING),)
+CHECKING_DFLAGS = -frelease
+else
+CHECKING_DFLAGS =
+endif
+WARN_DFLAGS = -Wall -Wdeprecated $(NOCOMMON_FLAG)
+
+ALL_DFLAGS = $(DFLAGS-$@) $(GDCFLAGS) -fversion=IN_GCC $(CHECKING_DFLAGS) \
+ $(PICFLAG) $(ALIASING_FLAGS) $(COVERAGE_FLAGS) $(WARN_DFLAGS)
+
+DCOMPILE.base = $(GDC) $(NO_PIE_CFLAGS) -c $(ALL_DFLAGS) -o $@
+DCOMPILE = $(DCOMPILE.base) -MT $@ -MMD -MP -MF $(@D)/$(DEPDIR)/$(*F).TPo
+DPOSTCOMPILE = @mv $(@D)/$(DEPDIR)/$(*F).TPo $(@D)/$(DEPDIR)/$(*F).Po
+DLINKER = $(GDC) $(NO_PIE_FLAG) -lstdc++
+
+# Like LINKER, but use a mutex for serializing front end links.
+ifeq (@DO_LINK_MUTEX@,true)
+DLLINKER = $(SHELL) $(srcdir)/lock-and-run.sh linkfe.lck $(DLINKER)
+else
+DLLINKER = $(DLINKER)
+endif
# D Frontend object files.
D_FRONTEND_OBJS = \
d/aav.o \
d/access.o \
+ d/aggregate.o \
d/aliasthis.o \
d/apply.o \
+ d/array.o \
d/arrayop.o \
+ d/arraytypes.o \
d/attrib.o \
+ d/ast_node.o \
+ d/astcodegen.o \
+ d/astenums.o \
+ d/bitarray.o \
d/blockexit.o \
+ d/builtin.o \
d/canthrow.o \
- d/checkedint.o \
d/chkformat.o \
d/clone.o \
+ d/compiler.o \
+ d/complex.o \
d/cond.o \
d/constfold.o \
+ d/cparse.o \
d/cppmangle.o \
d/ctfeexpr.o \
+ d/ctfloat.o \
+ d/ctorflow.o \
d/dcast.o \
d/dclass.o \
d/declaration.o \
@@ -86,32 +117,49 @@ D_FRONTEND_OBJS = \
d/dsymbol.o \
d/dsymbolsem.o \
d/dtemplate.o \
+ d/dtoh.o \
d/dversion.o \
d/entity.o \
+ d/errors.o \
d/escape.o \
d/expression.o \
d/expressionsem.o \
d/file.o \
d/filename.o \
+ d/foreachvar.o \
d/func.o \
+ d/globals.o \
+ d/gluelayer.o \
+ d/hash.o \
d/hdrgen.o \
d/iasm.o \
d/iasmgcc.o \
+ d/id.o \
d/identifier.o \
+ d/impcnvtab.o \
d/imphint.o \
d/init.o \
d/initsem.o \
+ d/inline.o \
d/intrange.o \
d/json.o \
+ d/lambdacomp.o \
d/lexer.o \
+ d/longdouble.o \
d/mtype.o \
d/nogc.o \
d/nspace.o \
+ d/ob.o \
d/objc.o \
d/opover.o \
d/optimize.o \
d/outbuffer.o \
d/parse.o \
+ d/parsetimevisitor.o \
+ d/permissivevisitor.o \
+ d/port.o \
+ d/printast.o \
+ d/region.o \
d/rmem.o \
d/rootobject.o \
d/safe.o \
@@ -121,20 +169,23 @@ D_FRONTEND_OBJS = \
d/sideeffect.o \
d/speller.o \
d/statement.o \
+ d/statement_rewrite_walker.o \
d/statementsem.o \
d/staticassert.o \
d/staticcond.o \
+ d/stmtstate.o \
+ d/string.o \
d/stringtable.o \
+ d/target.o \
d/templateparamsem.o \
d/tokens.o \
d/traits.o \
+ d/transitivevisitor.o \
d/typesem.o \
+ d/typinf.o \
d/utf.o \
- d/utils.o
-
-# D Frontend generated files.
-D_GENERATED_SRCS = d/id.c d/id.h d/impcnvtab.c
-D_GENERATED_OBJS = d/id.o d/impcnvtab.o
+ d/utils.o \
+ d/visitor.o
# Language-specific object files for D.
D_OBJS = \
@@ -163,13 +214,13 @@ D_OBJS = \
d/types.o
# All language-specific object files for D.
-D_ALL_OBJS = $(D_FRONTEND_OBJS) $(D_GENERATED_OBJS) $(D_OBJS) $(D_TARGET_OBJS)
+D_ALL_OBJS = $(D_FRONTEND_OBJS) $(D_OBJS) $(D_TARGET_OBJS)
d_OBJS = $(D_ALL_OBJS) d/d-spec.o
d21$(exeext): $(D_ALL_OBJS) attribs.o $(BACKEND) $(LIBDEPS) $(d.prev)
@$(call LINK_PROGRESS,$(INDEX.d),start)
- +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \
+ +$(DLLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -static-libphobos -o $@ \
$(D_ALL_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS)
@$(call LINK_PROGRESS,$(INDEX.d),end)
@@ -221,7 +272,7 @@ d.srcextra:
d.tags: force
cd $(srcdir)/d; \
- $(ETAGS) -o TAGS.sub *.c *.cc *.h dmd/*.c dmd/*.h dmd/root/*.h dmd/root/*.c; \
+ $(ETAGS) -o TAGS.sub *.c *.cc *.h dmd/*.h dmd/root/*.h; \
$(ETAGS) --include TAGS.sub --include ../TAGS.sub
d.man: doc/gdc.1
@@ -313,8 +364,6 @@ d.uninstall:
d.mostlyclean:
-rm -f d/*$(objext)
-rm -f d/*$(coverageexts)
- -rm -f $(D_GENERATED_SRCS)
- -rm -f d/idgen$(build_exeext) d/impcnvgen$(build_exeext)
-rm -f gdc$(exeext) gdc-cross$(exeext) d21$(exeext)
d.clean:
d.distclean:
@@ -337,48 +386,13 @@ d.stagefeedback: stagefeedback-start
-mv d/*$(objext) stagefeedback/d
# Include the dfrontend and build directories for headers.
-D_INCLUDES = -I$(srcdir)/d -I$(srcdir)/d/dmd -Id
-
-CFLAGS-d/id.o += $(D_INCLUDES)
-CFLAGS-d/impcnvtab.o += $(D_INCLUDES)
+D_INCLUDES = -I$(srcdir)/d -J$(srcdir)/d/dmd -J$(srcdir)/d/dmd/res
# Override build rules for D frontend.
-d/%.o: d/dmd/%.c $(D_GENERATED_SRCS)
- $(DMD_COMPILE) $(D_INCLUDES) $<
- $(POSTCOMPILE)
-
-d/%.o: d/dmd/root/%.c $(D_GENERATED_SRCS)
- $(DMD_COMPILE) $(D_INCLUDES) $<
- $(POSTCOMPILE)
-
-# Generated programs.
-d/idgen$(build_exeext): d/idgen.dmdgen.o $(BUILD_LIBDEPS)
- +$(LINKER_FOR_BUILD) $(BUILD_LINKERFLAGS) $(BUILD_LDFLAGS) -o $@ \
- $(filter-out $(BUILD_LIBDEPS), $^) $(BUILD_LIBS)
-
-d/impcnvgen$(build_exeext): d/impcnvgen.dmdgen.o $(BUILD_LIBDEPS)
- +$(LINKER_FOR_BUILD) $(BUILD_LINKERFLAGS) $(BUILD_LDFLAGS) -o $@ \
- $(filter-out $(BUILD_LIBDEPS), $^) $(BUILD_LIBS)
-
-# Generated sources.
-d/id.c: d/idgen$(build_exeext)
- cd d && ./idgen$(build_exeext)
-
-# idgen also generates id.h; just verify it exists.
-d/id.h: d/id.c
-
-d/impcnvtab.c: d/impcnvgen$(build_exeext)
- cd d && ./impcnvgen$(build_exeext)
-
-# Compile the generator programs.
-d/%.dmdgen.o: $(srcdir)/d/dmd/%.c
- $(COMPILER_FOR_BUILD) -c $(BUILD_COMPILERFLAGS) $(D_INCLUDES) \
- $(BUILD_CPPFLAGS) -o $@ $<
-
-# Header dependencies for the generator programs.
-D_SYSTEM_H = d/dmd/root/dsystem.h d/d-system.h
-
-d/idgen.dmdgen.o: d/dmd/idgen.c $(D_SYSTEM_H) $(BCONFIG_H) $(SYSTEM_H)
+d/%.o: d/dmd/%.d
+ $(DCOMPILE) $(D_INCLUDES) $<
+ $(DPOSTCOMPILE)
-d/impcnvgen.dmdgen.o: d/dmd/impcnvgen.c d/dmd/mtype.h $(D_SYSTEM_H) \
- $(BCONFIG_H) $(SYSTEM_H)
+d/%.o: d/dmd/root/%.d
+ $(DCOMPILE) $(D_INCLUDES) $<
+ $(DPOSTCOMPILE)
diff --git a/gcc/d/config-lang.in b/gcc/d/config-lang.in
index 0568b8d..00a71d6 100644
--- a/gcc/d/config-lang.in
+++ b/gcc/d/config-lang.in
@@ -19,10 +19,12 @@
# We define several parameters used by configure:
#
# language - name of language as it would appear in $(LANGUAGES)
+# boot_language - "yes" if we need to build this language in stage1
# compilers - value to add to $(COMPILERS)
language="d"
+boot_language=yes
compilers="d21\$(exeext)"
phobos_target_deps="target-zlib target-libbacktrace"
diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc
index b79cf96..04b9791 100644
--- a/gcc/d/d-attribs.cc
+++ b/gcc/d/d-attribs.cc
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "dmd/attrib.h"
#include "dmd/declaration.h"
+#include "dmd/expression.h"
#include "dmd/module.h"
#include "dmd/mtype.h"
#include "dmd/template.h"
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
index 33347a1..ab3a950 100644
--- a/gcc/d/d-builtins.cc
+++ b/gcc/d/d-builtins.cc
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
#include "stor-layout.h"
#include "d-tree.h"
+#include "d-frontend.h"
#include "d-target.h"
@@ -98,7 +99,7 @@ build_frontend_type (tree type)
if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == char_type_node)
return Type::tchar->addMod (dtype->mod)->pointerTo ()->addMod (mod);
- if (dtype->ty == Tfunction)
+ if (dtype->ty == TY::Tfunction)
return (TypePointer::create (dtype))->addMod (mod);
return dtype->pointerTo ()->addMod (mod);
@@ -130,7 +131,7 @@ build_frontend_type (tree type)
/* For now, skip support for cent/ucent until the frontend
has better support for handling it. */
- for (size_t i = Tint8; i <= Tuns64; i++)
+ for (size_t i = (size_t) TY::Tint8; i <= (size_t) TY::Tuns64; i++)
{
dtype = Type::basic[i];
@@ -148,7 +149,7 @@ build_frontend_type (tree type)
{
unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
- for (size_t i = Tfloat32; i <= Tfloat80; i++)
+ for (size_t i = (size_t) TY::Tfloat32; i <= (size_t) TY::Tfloat80; i++)
{
dtype = Type::basic[i];
@@ -164,7 +165,8 @@ build_frontend_type (tree type)
case COMPLEX_TYPE:
{
unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
- for (size_t i = Tcomplex32; i <= Tcomplex80; i++)
+ for (size_t i = (size_t) TY::Tcomplex32; i <= (size_t) TY::Tcomplex80;
+ i++)
{
dtype = Type::basic[i];
@@ -235,7 +237,7 @@ build_frontend_type (tree type)
sdecl->structsize = int_size_in_bytes (type);
sdecl->alignsize = TYPE_ALIGN_UNIT (type);
sdecl->alignment = STRUCTALIGN_DEFAULT;
- sdecl->sizeok = SIZEOKdone;
+ sdecl->sizeok = Sizeok::done;
sdecl->type = (TypeStruct::create (sdecl))->addMod (mod);
sdecl->type->ctype = type;
sdecl->type->merge2 ();
@@ -243,7 +245,7 @@ build_frontend_type (tree type)
/* Add both named and anonymous fields as members of the struct.
Anonymous fields still need a name in D, so call them "__pad%u". */
unsigned anonfield_id = 0;
- sdecl->members = new Dsymbols;
+ sdecl->members = d_gc_malloc<Dsymbols> ();
for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
{
@@ -253,7 +255,6 @@ build_frontend_type (tree type)
/* Drop any field types that got cached before the conversion
of this record type failed. */
builtin_converted_decls.truncate (saved_builtin_decls_length);
- delete sdecl->members;
return NULL;
}
@@ -292,7 +293,7 @@ build_frontend_type (tree type)
tree parms = TYPE_ARG_TYPES (type);
VarArg varargs_p = VARARGvariadic;
- Parameters *args = new Parameters;
+ Parameters *args = d_gc_malloc<Parameters> ();
args->reserve (list_length (parms));
/* Attempt to convert all parameter types. */
@@ -318,7 +319,6 @@ build_frontend_type (tree type)
/* Drop any parameter types that got cached before the
conversion of this function type failed. */
builtin_converted_decls.truncate (saved_builtin_decls_length);
- delete args;
return NULL;
}
@@ -329,7 +329,7 @@ build_frontend_type (tree type)
have no named parameters, and so can't be represented in D. */
if (args->length != 0 || varargs_p == VARARGnone)
{
- dtype = TypeFunction::create (args, dtype, varargs_p, LINKc);
+ dtype = TypeFunction::create (args, dtype, varargs_p, LINK::c);
return dtype->addMod (mod);
}
}
@@ -386,7 +386,7 @@ d_eval_constant_expression (const Loc &loc, tree cst)
else if (code == VECTOR_CST)
{
dinteger_t nunits = VECTOR_CST_NELTS (cst).to_constant ();
- Expressions *elements = new Expressions;
+ Expressions *elements = d_gc_malloc<Expressions> ();
elements->setDim (nunits);
for (size_t i = 0; i < nunits; i++)
@@ -520,7 +520,7 @@ build_alias_declaration (const char *alias, Type *type)
void
d_build_builtins_module (Module *m)
{
- Dsymbols *members = new Dsymbols;
+ Dsymbols *members = d_gc_malloc<Dsymbols> ();
tree decl;
for (size_t i = 0; vec_safe_iterate (gcc_builtins_functions, i, &decl); ++i)
@@ -543,16 +543,16 @@ d_build_builtins_module (Module *m)
flag_unsafe_math_optimizations.
- Built-ins never use the GC or raise a D exception, and so are always
marked as `nothrow' and `@nogc'. */
- tf->purity = DECL_PURE_P (decl) ? PUREstrong
- : TREE_READONLY (decl) ? PUREconst
- : DECL_IS_NOVOPS (decl) ? PUREweak
- : !DECL_ASSEMBLER_NAME_SET_P (decl) ? PUREweak
- : PUREimpure;
- tf->trust = !DECL_ASSEMBLER_NAME_SET_P (decl) ? TRUSTsafe
- : TREE_NOTHROW (decl) ? TRUSTtrusted
- : TRUSTsystem;
- tf->isnothrow = true;
- tf->isnogc = true;
+ tf->purity = DECL_PURE_P (decl) ? PURE::strong
+ : TREE_READONLY (decl) ? PURE::const_
+ : DECL_IS_NOVOPS (decl) ? PURE::weak
+ : !DECL_ASSEMBLER_NAME_SET_P (decl) ? PURE::weak
+ : PURE::impure;
+ tf->trust = !DECL_ASSEMBLER_NAME_SET_P (decl) ? TRUST::safe
+ : TREE_NOTHROW (decl) ? TRUST::trusted
+ : TRUST::system;
+ tf->isnothrow (true);
+ tf->isnogc (true);
FuncDeclaration *func
= FuncDeclaration::create (Loc (), Loc (),
@@ -560,7 +560,7 @@ d_build_builtins_module (Module *m)
STCextern, tf);
DECL_LANG_SPECIFIC (decl) = build_lang_decl (func);
func->csym = decl;
- func->builtin = BUILTINgcc;
+ func->builtin = BUILTIN::gcc;
members->push (func);
}
@@ -660,7 +660,7 @@ d_build_builtins_module (Module *m)
members->push (build_alias_declaration ("__builtin_unwind_uint", t));
}
- m->members->push (LinkDeclaration::create (LINKc, members));
+ m->members->push (LinkDeclaration::create (Loc (), LINK::c, members));
}
/* Search for any `extern(C)' functions that match any known GCC library builtin
@@ -700,7 +700,7 @@ maybe_set_builtin_1 (Dsymbol *d)
/* Found a match, tell the frontend this is a builtin. */
DECL_LANG_SPECIFIC (t) = build_lang_decl (fd);
fd->csym = t;
- fd->builtin = BUILTINgcc;
+ fd->builtin = BUILTIN::gcc;
return;
}
}
@@ -858,7 +858,7 @@ d_build_d_type_nodes (void)
/* Calling build_ctype() links the front-end Type to the GCC node,
and sets the TYPE_NAME to the D language type. */
- for (unsigned ty = 0; ty < TMAX; ty++)
+ for (unsigned ty = 0; ty < (unsigned) TY::TMAX; ty++)
{
if (Type::basic[ty] != NULL)
build_ctype (Type::basic[ty]);
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index e633650..403e3c7 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -76,7 +76,7 @@ d_decl_context (Dsymbol *dsym)
but only for extern(D) symbols. */
if (parent->isModule ())
{
- if ((decl != NULL && decl->linkage != LINKd)
+ if ((decl != NULL && decl->linkage != LINK::d)
|| (ad != NULL && ad->classKind != ClassKind::d))
return NULL_TREE;
@@ -131,7 +131,7 @@ declaration_reference_p (Declaration *decl)
Type *tb = decl->type->toBasetype ();
/* Declaration is a reference type. */
- if (tb->ty == Treference || decl->storage_class & (STCout | STCref))
+ if (tb->ty == TY::Treference || decl->storage_class & (STCout | STCref))
return true;
return false;
@@ -146,7 +146,7 @@ declaration_type (Declaration *decl)
if (decl->storage_class & STClazy)
{
TypeFunction *tf = TypeFunction::create (NULL, decl->type,
- VARARGnone, LINKd);
+ VARARGnone, LINK::d);
TypeDelegate *t = TypeDelegate::create (tf);
return build_ctype (t->merge2 ());
}
@@ -181,7 +181,7 @@ parameter_reference_p (Parameter *arg)
Type *tb = arg->type->toBasetype ();
/* Parameter is a reference type. */
- if (tb->ty == Treference || arg->storageClass & (STCout | STCref))
+ if (tb->ty == TY::Treference || arg->storageClass & (STCout | STCref))
return true;
return false;
@@ -196,7 +196,7 @@ parameter_type (Parameter *arg)
if (arg->storageClass & STClazy)
{
TypeFunction *tf = TypeFunction::create (NULL, arg->type,
- VARARGnone, LINKd);
+ VARARGnone, LINK::d);
TypeDelegate *t = TypeDelegate::create (tf);
return build_ctype (t->merge2 ());
}
@@ -319,10 +319,10 @@ get_array_length (tree exp, Type *type)
switch (tb->ty)
{
- case Tsarray:
+ case TY::Tsarray:
return size_int (tb->isTypeSArray ()->dim->toUInteger ());
- case Tarray:
+ case TY::Tarray:
return d_array_length (exp);
default:
@@ -411,7 +411,7 @@ build_delegate_cst (tree method, tree object, Type *type)
tree ctype;
Type *tb = type->toBasetype ();
- if (tb->ty == Tdelegate)
+ if (tb->ty == TY::Tdelegate)
ctype = build_ctype (type);
else
{
@@ -464,11 +464,11 @@ build_typeof_null_value (Type *type)
tree value;
/* For dynamic arrays, set length and pointer fields to zero. */
- if (tb->ty == Tarray)
+ if (tb->ty == TY::Tarray)
value = d_array_value (build_ctype (type), size_int (0), null_pointer_node);
/* For associative arrays, set the pointer field to null. */
- else if (tb->ty == Taarray)
+ else if (tb->ty == TY::Taarray)
{
tree ctype = build_ctype (type);
gcc_assert (TYPE_ASSOCIATIVE_ARRAY (ctype));
@@ -478,7 +478,7 @@ build_typeof_null_value (Type *type)
}
/* For delegates, set the frame and function pointer fields to null. */
- else if (tb->ty == Tdelegate)
+ else if (tb->ty == TY::Tdelegate)
value = build_delegate_cst (null_pointer_node, null_pointer_node, type);
/* Simple zero constant for all other types. */
@@ -882,7 +882,9 @@ identity_compare_p (StructDeclaration *sd)
}
/* Check for types that may have padding. */
- if ((tb->ty == Tcomplex80 || tb->ty == Tfloat80 || tb->ty == Timaginary80)
+ if ((tb->ty == TY::Tcomplex80
+ || tb->ty == TY::Tfloat80
+ || tb->ty == TY::Timaginary80)
&& target.realpad != 0)
return false;
@@ -960,12 +962,12 @@ lower_struct_comparison (tree_code code, StructDeclaration *sd,
/* Compare inner data structures. */
tcmp = lower_struct_comparison (code, ts->sym, t1ref, t2ref);
}
- else if (type->ty != Tvector && type->isintegral ())
+ else if (type->ty != TY::Tvector && type->isintegral ())
{
/* Integer comparison, no special handling required. */
tcmp = build_boolop (code, t1ref, t2ref);
}
- else if (type->ty != Tvector && type->isfloating ())
+ else if (type->ty != TY::Tvector && type->isfloating ())
{
/* Floating-point comparison, don't compare padding in type. */
if (!type->iscomplex ())
@@ -1839,7 +1841,7 @@ static tree
build_filename_from_loc (const Loc &loc)
{
const char *filename = loc.filename
- ? loc.filename : d_function_chain->module->srcfile->toChars ();
+ ? loc.filename : d_function_chain->module->srcfile.toChars ();
unsigned length = strlen (filename);
tree str = build_string (length, filename);
@@ -1862,7 +1864,6 @@ build_assert_call (const Loc &loc, libcall_fn libcall, tree msg)
{
case LIBCALL_ASSERT_MSG:
case LIBCALL_UNITTEST_MSG:
- case LIBCALL_SWITCH_ERROR:
/* File location is passed as a D string. */
if (loc.filename)
{
@@ -1912,7 +1913,7 @@ build_array_bounds_call (const Loc &loc)
/* Builds a bounds condition checking that INDEX is between 0 and LENGTH
in the index expression IE. The condition returns the INDEX if true, or
- throws a `RangeError`. */
+ throws a `ArrayIndexError`. */
tree
build_bounds_index_condition (IndexExp *ie, tree index, tree length)
@@ -1927,7 +1928,16 @@ build_bounds_index_condition (IndexExp *ie, tree index, tree length)
No need to check whether INDEX >= 0 as the front-end should
have already taken care of implicit casts to unsigned. */
tree condition = fold_build2 (GE_EXPR, d_bool_type, index, length);
- tree boundserr = build_array_bounds_call (ie->e2->loc);
+ tree boundserr;
+
+ if (checkaction_trap_p ())
+ boundserr = build_call_expr (builtin_decl_explicit (BUILT_IN_TRAP), 0);
+ else
+ {
+ boundserr = build_libcall (LIBCALL_ARRAYBOUNDS_INDEXP, Type::tvoid, 4,
+ build_filename_from_loc (ie->e2->loc),
+ size_int (ie->e2->loc.linnum), index, length);
+ }
return build_condition (TREE_TYPE (index), condition, boundserr, index);
}
@@ -1963,7 +1973,22 @@ build_bounds_slice_condition (SliceExp *se, tree lower, tree upper, tree length)
if (condition != NULL_TREE)
{
- tree boundserr = build_array_bounds_call (se->loc);
+ tree boundserr;
+
+ if (checkaction_trap_p ())
+ {
+ boundserr =
+ build_call_expr (builtin_decl_explicit (BUILT_IN_TRAP), 0);
+ }
+ else
+ {
+ boundserr = build_libcall (LIBCALL_ARRAYBOUNDS_SLICEP,
+ Type::tvoid, 5,
+ build_filename_from_loc (se->loc),
+ size_int (se->loc.linnum),
+ lower, upper, length);
+ }
+
upper = build_condition (TREE_TYPE (upper), condition,
boundserr, upper);
}
@@ -1993,9 +2018,9 @@ array_bounds_check (void)
case CHECKENABLEsafeonly:
/* For D2 safe functions only. */
fd = d_function_chain->function;
- if (fd && fd->type->ty == Tfunction)
+ if (fd && fd->type->ty == TY::Tfunction)
{
- if (fd->type->isTypeFunction ()->trust == TRUSTsafe)
+ if (fd->type->isTypeFunction ()->trust == TRUST::safe)
return true;
}
return false;
@@ -2014,6 +2039,7 @@ checkaction_trap_p (void)
switch (global.params.checkAction)
{
case CHECKACTION_D:
+ case CHECKACTION_context:
return false;
case CHECKACTION_C:
@@ -2032,11 +2058,11 @@ TypeFunction *
get_function_type (Type *t)
{
TypeFunction *tf = NULL;
- if (t->ty == Tpointer)
+ if (t->ty == TY::Tpointer)
t = t->nextOf ()->toBasetype ();
- if (t->ty == Tfunction)
+ if (t->ty == TY::Tfunction)
tf = t->isTypeFunction ();
- else if (t->ty == Tdelegate)
+ else if (t->ty == TY::Tdelegate)
tf = t->isTypeDelegate ()->next->isTypeFunction ();
return tf;
}
@@ -2096,7 +2122,7 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
gcc_assert (FUNC_OR_METHOD_TYPE_P (ctype));
gcc_assert (tf != NULL);
- gcc_assert (tf->ty == Tfunction);
+ gcc_assert (tf->ty == TY::Tfunction);
if (TREE_CODE (ctype) != FUNCTION_TYPE && object == NULL_TREE)
{
@@ -2195,7 +2221,7 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
SET_EXPR_LOCATION (result, input_location);
/* Enforce left to right evaluation. */
- if (tf->linkage == LINKd)
+ if (tf->linkage == LINK::d)
CALL_EXPR_ARGS_ORDERED (result) = 1;
result = maybe_expand_intrinsic (result);
diff --git a/gcc/d/d-compiler.cc b/gcc/d/d-compiler.cc
index 512ef4b..3df40073 100644
--- a/gcc/d/d-compiler.cc
+++ b/gcc/d/d-compiler.cc
@@ -20,7 +20,6 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "dmd/compiler.h"
-#include "dmd/scope.h"
#include "dmd/expression.h"
#include "dmd/identifier.h"
#include "dmd/module.h"
@@ -34,40 +33,6 @@ along with GCC; see the file COPYING3. If not see
/* Implements the Compiler interface used by the frontend. */
-/* Generate C main() in response to seeing D main(). This used to be in
- libdruntime, but contained a reference to _Dmain which didn't work when
- druntime was made into a shared library and was linked to a program, such
- as a C++ program, that didn't have a _Dmain. */
-
-void
-Compiler::genCmain (Scope *sc)
-{
- static bool initialized = false;
-
- if (initialized)
- return;
-
- /* The D code to be generated is provided by __entrypoint.di, try to load it,
- but don't fail if unfound. */
- unsigned errors = global.startGagging ();
- Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__entrypoint"));
-
- if (global.endGagging (errors))
- m = NULL;
-
- if (m != NULL)
- {
- m->importedFrom = m;
- m->importAll (NULL);
- dsymbolSemantic (m, NULL);
- semantic2 (m, NULL);
- semantic3 (m, NULL);
- d_add_entrypoint_module (m, sc->_module);
- }
-
- initialized = true;
-}
-
/* Perform a reinterpret cast of EXPR to type TYPE for use in CTFE.
The front end should have already ensured that EXPR is a constant,
so we just lower the value to GCC and return the converted CST. */
@@ -123,7 +88,7 @@ Compiler::paintAsType (UnionExp *, Expression *expr, Type *type)
/* Encode CST to buffer. */
int len = native_encode_expr (cst, buffer, sizeof (buffer));
- if (tb->ty == Tsarray)
+ if (tb->ty == TY::Tsarray)
{
/* Interpret value as a vector of the same size,
then return the array literal. */
@@ -161,22 +126,22 @@ Compiler::onParseModule (Module *m)
{
ModuleDeclaration *md = m->md;
- if (!md || !md->id || !md->packages)
+ if (!md || !md->id|| md->packages.length == 0)
{
Identifier *id = (md && md->id) ? md->id : m->ident;
if (!strcmp (id->toChars (), "object"))
create_tinfo_types (m);
}
- else if (md->packages->length == 1)
+ else if (md->packages.length == 1)
{
- if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
+ if (!strcmp (md->packages.ptr[0]->toChars (), "gcc")
&& !strcmp (md->id->toChars (), "builtins"))
d_build_builtins_module (m);
}
- else if (md->packages->length == 2)
+ else if (md->packages.length == 2)
{
- if (!strcmp ((*md->packages)[0]->toChars (), "core")
- && !strcmp ((*md->packages)[1]->toChars (), "stdc"))
+ if (!strcmp (md->packages.ptr[0]->toChars (), "core")
+ && !strcmp (md->packages.ptr[1]->toChars (), "stdc"))
d_add_builtin_module (m);
}
}
diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc
index 3b47902..25fd603 100644
--- a/gcc/d/d-convert.cc
+++ b/gcc/d/d-convert.cc
@@ -361,14 +361,14 @@ convert_expr (tree exp, Type *etype, Type *totype)
switch (ebtype->ty)
{
- case Tdelegate:
- if (tbtype->ty == Tdelegate)
+ case TY::Tdelegate:
+ if (tbtype->ty == TY::Tdelegate)
{
exp = d_save_expr (exp);
return build_delegate_cst (delegate_method (exp),
delegate_object (exp), totype);
}
- else if (tbtype->ty == Tpointer)
+ else if (tbtype->ty == TY::Tpointer)
{
/* The front-end converts <delegate>.ptr to cast (void *)<delegate>.
Maybe should only allow void* ? */
@@ -382,8 +382,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
}
break;
- case Tstruct:
- if (tbtype->ty == Tstruct)
+ case TY::Tstruct:
+ if (tbtype->ty == TY::Tstruct)
{
if (totype->size () == etype->size ())
{
@@ -400,8 +400,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
/* else, default conversion, which should produce an error. */
break;
- case Tclass:
- if (tbtype->ty == Tclass)
+ case TY::Tclass:
+ if (tbtype->ty == TY::Tclass)
{
ClassDeclaration *cdfrom = ebtype->isClassHandle ();
ClassDeclaration *cdto = tbtype->isClassHandle ();
@@ -460,12 +460,12 @@ convert_expr (tree exp, Type *etype, Type *totype)
/* else default conversion. */
break;
- case Tsarray:
- if (tbtype->ty == Tpointer)
+ case TY::Tsarray:
+ if (tbtype->ty == TY::Tpointer)
{
result = build_nop (build_ctype (totype), build_address (exp));
}
- else if (tbtype->ty == Tarray)
+ else if (tbtype->ty == TY::Tarray)
{
dinteger_t dim = ebtype->isTypeSArray ()->dim->toInteger ();
dinteger_t esize = ebtype->nextOf ()->size ();
@@ -490,12 +490,12 @@ convert_expr (tree exp, Type *etype, Type *totype)
return d_array_value (build_ctype (totype), size_int (dim),
build_nop (ptrtype, build_address (exp)));
}
- else if (tbtype->ty == Tsarray)
+ else if (tbtype->ty == TY::Tsarray)
{
/* D allows casting a static array to any static array type. */
return build_nop (build_ctype (totype), exp);
}
- else if (tbtype->ty == Tstruct)
+ else if (tbtype->ty == TY::Tstruct)
{
/* And allows casting a static array to any struct type too.
Type sizes should have already been checked by the frontend. */
@@ -510,12 +510,12 @@ convert_expr (tree exp, Type *etype, Type *totype)
}
break;
- case Tarray:
- if (tbtype->ty == Tpointer)
+ case TY::Tarray:
+ if (tbtype->ty == TY::Tpointer)
{
return d_convert (build_ctype (totype), d_array_ptr (exp));
}
- else if (tbtype->ty == Tarray)
+ else if (tbtype->ty == TY::Tarray)
{
/* Assume tvoid->size() == 1. */
d_uns64 fsize = ebtype->nextOf ()->toBasetype ()->size ();
@@ -523,9 +523,18 @@ convert_expr (tree exp, Type *etype, Type *totype)
if (fsize != tsize)
{
- /* Conversion requires a reinterpret cast of array. */
- return build_libcall (LIBCALL_ARRAYCAST, totype, 3,
- size_int (tsize), size_int (fsize), exp);
+ /* Conversion requires a reinterpret cast of array.
+ This case should have been lowered in the semantic pass. */
+ if (tsize != 0 && fsize % tsize == 0)
+ {
+ /* Set array dimension to (length * (fsize / tsize)). */
+ tree newlength = size_mult_expr (d_array_length (exp),
+ size_int (fsize / tsize));
+ return d_array_value (build_ctype (totype), newlength,
+ d_array_ptr (exp));
+ }
+ else
+ gcc_unreachable ();
}
else
{
@@ -534,7 +543,7 @@ convert_expr (tree exp, Type *etype, Type *totype)
return build_vconvert (build_ctype (totype), exp);
}
}
- else if (tbtype->ty == Tsarray)
+ else if (tbtype->ty == TY::Tsarray)
{
/* Strings are treated as dynamic arrays in D2. */
if (ebtype->isString () && tbtype->isString ())
@@ -548,23 +557,23 @@ convert_expr (tree exp, Type *etype, Type *totype)
}
break;
- case Taarray:
- if (tbtype->ty == Taarray)
+ case TY::Taarray:
+ if (tbtype->ty == TY::Taarray)
return build_vconvert (build_ctype (totype), exp);
/* Can convert associative arrays to void pointers. */
- else if (tbtype->ty == Tpointer && tbtype->nextOf ()->ty == Tvoid)
+ else if (tbtype->ty == TY::Tpointer && tbtype->nextOf ()->ty == TY::Tvoid)
return build_vconvert (build_ctype (totype), exp);
/* Else, default conversion, which should product an error. */
break;
- case Tpointer:
+ case TY::Tpointer:
/* Can convert void pointers to associative arrays too. */
- if (tbtype->ty == Taarray && ebtype->nextOf ()->ty == Tvoid)
+ if (tbtype->ty == TY::Taarray && ebtype->nextOf ()->ty == TY::Tvoid)
return build_vconvert (build_ctype (totype), exp);
break;
- case Tnull:
- case Tnoreturn:
+ case TY::Tnull:
+ case TY::Tnoreturn:
/* Casting from `typeof(null)' for `null' expressions, or `typeof(*null)'
for `noreturn' expressions is represented as all zeros. */
result = build_typeof_null_value (totype);
@@ -574,8 +583,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
result = compound_expr (exp, result);
break;
- case Tvector:
- if (tbtype->ty == Tsarray)
+ case TY::Tvector:
+ if (tbtype->ty == TY::Tsarray)
{
if (tbtype->size () == ebtype->size ())
return build_vconvert (build_ctype (totype), exp);
@@ -613,7 +622,7 @@ convert_for_rvalue (tree expr, Type *etype, Type *totype)
Type *ebtype = etype->toBasetype ();
Type *tbtype = totype->toBasetype ();
- if (ebtype->ty == Tbool)
+ if (ebtype->ty == TY::Tbool)
{
/* If casting from bool, the result is either 0 or 1, any other value
violates @safe code, so enforce that it is never invalid. */
@@ -651,7 +660,7 @@ convert_for_assignment (tree expr, Type *etype, Type *totype)
/* Assuming this only has to handle converting a non Tsarray type to
arbitrarily dimensioned Tsarrays. */
- if (tbtype->ty == Tsarray)
+ if (tbtype->ty == TY::Tsarray)
{
Type *telem = tbtype->nextOf ()->baseElemOf ();
@@ -685,7 +694,7 @@ convert_for_assignment (tree expr, Type *etype, Type *totype)
}
/* D Front end uses IntegerExp(0) to mean zero-init an array or structure. */
- if ((tbtype->ty == Tsarray || tbtype->ty == Tstruct)
+ if ((tbtype->ty == TY::Tsarray || tbtype->ty == TY::Tstruct)
&& ebtype->isintegral ())
{
if (!integer_zerop (expr))
@@ -736,12 +745,12 @@ convert_for_condition (tree expr, Type *type)
switch (type->toBasetype ()->ty)
{
- case Taarray:
+ case TY::Taarray:
/* Checks that aa.ptr !is null. */
result = component_ref (expr, TYPE_FIELDS (TREE_TYPE (expr)));
break;
- case Tarray:
+ case TY::Tarray:
{
/* Checks (arr.length || arr.ptr) (i.e arr !is null). */
expr = d_save_expr (expr);
@@ -762,7 +771,7 @@ convert_for_condition (tree expr, Type *type)
break;
}
- case Tdelegate:
+ case TY::Tdelegate:
{
/* Checks (function || object), but what good is it if there is
a null function pointer? */
@@ -783,7 +792,7 @@ convert_for_condition (tree expr, Type *type)
break;
}
- case Tnoreturn:
+ case TY::Tnoreturn:
/* Front-end allows conditionals that never return, represent the
conditional result value as all zeros. */
result = build_zero_cst (d_bool_type);
@@ -810,10 +819,10 @@ d_array_convert (Expression *exp)
{
Type *tb = exp->type->toBasetype ();
- if (tb->ty == Tarray)
+ if (tb->ty == TY::Tarray)
return build_expr (exp);
- if (tb->ty == Tsarray)
+ if (tb->ty == TY::Tsarray)
{
Type *totype = tb->nextOf ()->arrayOf ();
return convert_expr (build_expr (exp), exp->type, totype);
@@ -832,7 +841,8 @@ d_array_convert (Type *etype, Expression *exp)
{
Type *tb = exp->type->toBasetype ();
- if ((tb->ty != Tarray && tb->ty != Tsarray) || same_type_p (tb, etype))
+ if ((tb->ty != TY::Tarray && tb->ty != TY::Tsarray)
+ || same_type_p (tb, etype))
{
/* Convert single element to an array. */
tree expr = build_expr (exp);
diff --git a/gcc/d/d-diagnostic.cc b/gcc/d/d-diagnostic.cc
index 1982bd9..947b6e2 100644
--- a/gcc/d/d-diagnostic.cc
+++ b/gcc/d/d-diagnostic.cc
@@ -222,15 +222,6 @@ d_diagnostic_report_diagnostic (const Loc &loc, int opt, const char *format,
message prefix PREFIX1 and PREFIX2, increasing the global or gagged
error count. */
-void ATTRIBUTE_GCC_DIAG(2,3)
-error (const Loc &loc, const char *format, ...)
-{
- va_list ap;
- va_start (ap, format);
- verror (loc, format, ap);
- va_end (ap);
-}
-
void ATTRIBUTE_GCC_DIAG(2,0)
verror (const Loc &loc, const char *format, va_list ap,
const char *prefix1, const char *prefix2, const char *)
@@ -263,15 +254,6 @@ verror (const Loc &loc, const char *format, va_list ap,
/* Print supplementary message about the last error with explicit location LOC.
This doesn't increase the global error count. */
-void ATTRIBUTE_GCC_DIAG(2,3)
-errorSupplemental (const Loc &loc, const char *format, ...)
-{
- va_list ap;
- va_start (ap, format);
- verrorSupplemental (loc, format, ap);
- va_end (ap);
-}
-
void ATTRIBUTE_GCC_DIAG(2,0)
verrorSupplemental (const Loc &loc, const char *format, va_list ap)
{
@@ -284,15 +266,6 @@ verrorSupplemental (const Loc &loc, const char *format, va_list ap)
/* Print a warning message with explicit location LOC, increasing the
global warning count. */
-void ATTRIBUTE_GCC_DIAG(2,3)
-warning (const Loc &loc, const char *format, ...)
-{
- va_list ap;
- va_start (ap, format);
- vwarning (loc, format, ap);
- va_end (ap);
-}
-
void ATTRIBUTE_GCC_DIAG(2,0)
vwarning (const Loc &loc, const char *format, va_list ap)
{
@@ -311,15 +284,6 @@ vwarning (const Loc &loc, const char *format, va_list ap)
/* Print supplementary message about the last warning with explicit location
LOC. This doesn't increase the global warning count. */
-void ATTRIBUTE_GCC_DIAG(2,3)
-warningSupplemental (const Loc &loc, const char *format, ...)
-{
- va_list ap;
- va_start (ap, format);
- vwarningSupplemental (loc, format, ap);
- va_end (ap);
-}
-
void ATTRIBUTE_GCC_DIAG(2,0)
vwarningSupplemental (const Loc &loc, const char *format, va_list ap)
{
@@ -333,15 +297,6 @@ vwarningSupplemental (const Loc &loc, const char *format, va_list ap)
message prefix PREFIX1 and PREFIX2, increasing the global warning or
error count depending on how deprecations are treated. */
-void ATTRIBUTE_GCC_DIAG(2,3)
-deprecation (const Loc &loc, const char *format, ...)
-{
- va_list ap;
- va_start (ap, format);
- vdeprecation (loc, format, ap);
- va_end (ap);
-}
-
void ATTRIBUTE_GCC_DIAG(2,0)
vdeprecation (const Loc &loc, const char *format, va_list ap,
const char *prefix1, const char *prefix2)
@@ -372,15 +327,6 @@ vdeprecation (const Loc &loc, const char *format, va_list ap,
/* Print supplementary message about the last deprecation with explicit
location LOC. This does not increase the global error count. */
-void ATTRIBUTE_GCC_DIAG(2,3)
-deprecationSupplemental (const Loc &loc, const char *format, ...)
-{
- va_list ap;
- va_start (ap, format);
- vdeprecationSupplemental (loc, format, ap);
- va_end (ap);
-}
-
void ATTRIBUTE_GCC_DIAG(2,0)
vdeprecationSupplemental (const Loc &loc, const char *format, va_list ap)
{
@@ -392,30 +338,19 @@ vdeprecationSupplemental (const Loc &loc, const char *format, va_list ap)
/* Print a verbose message with explicit location LOC. */
-void ATTRIBUTE_GCC_DIAG(2, 3)
-message (const Loc &loc, const char *format, ...)
-{
- va_list ap;
- va_start (ap, format);
- vmessage (loc, format, ap);
- va_end (ap);
-}
-
void ATTRIBUTE_GCC_DIAG(2,0)
vmessage (const Loc &loc, const char *format, va_list ap)
{
d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, true);
}
-/* Same as above, but doesn't take a location argument. */
+/* Print a tip message with prefix and highlighing. */
-void ATTRIBUTE_GCC_DIAG(1, 2)
-message (const char *format, ...)
+void ATTRIBUTE_GCC_DIAG(1,0)
+vtip (const char *format, va_list ap)
{
- va_list ap;
- va_start (ap, format);
- vmessage (Loc (), format, ap);
- va_end (ap);
+ if (!global.gag)
+ d_diagnostic_report_diagnostic (Loc (), 0, format, ap, DK_DEBUG, true);
}
/* Call this after printing out fatal error messages to clean up and
diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc
index 30fc6d43..522095f 100644
--- a/gcc/d/d-frontend.cc
+++ b/gcc/d/d-frontend.cc
@@ -27,116 +27,11 @@ along with GCC; see the file COPYING3. If not see
#include "dmd/scope.h"
#include "tree.h"
-#include "options.h"
#include "fold-const.h"
#include "diagnostic.h"
#include "d-tree.h"
-
-/* Implements the Global interface defined by the frontend.
- Used for managing the state of the current compilation. */
-
-Global global;
-
-void
-Global::_init (void)
-{
- this->mars_ext = "d";
- this->hdr_ext = "di";
- this->doc_ext = "html";
- this->ddoc_ext = "ddoc";
- this->json_ext = "json";
- this->obj_ext = "o";
-
- this->run_noext = true;
- this->version = "v"
-#include "verstr.h"
- ;
-
- this->stdmsg = stderr;
-}
-
-/* Start gagging. Return the current number of gagged errors. */
-
-unsigned
-Global::startGagging (void)
-{
- this->gag++;
- return this->gaggedErrors;
-}
-
-/* End gagging, restoring the old gagged state. Return true if errors
- occured while gagged. */
-
-bool
-Global::endGagging (unsigned oldGagged)
-{
- bool anyErrs = (this->gaggedErrors != oldGagged);
- this->gag--;
-
- /* Restore the original state of gagged errors; set total errors
- to be original errors + new ungagged errors. */
- this->errors -= (this->gaggedErrors - oldGagged);
- this->gaggedErrors = oldGagged;
-
- return anyErrs;
-}
-
-/* Increment the error count to record that an error has occured in the
- current context. An error message may or may not have been printed. */
-
-void
-Global::increaseErrorCount (void)
-{
- if (gag)
- this->gaggedErrors++;
-
- this->errors++;
-}
-
-
-/* Implements the Loc interface defined by the frontend.
- Used for keeping track of current file/line position in code. */
-
-Loc::Loc (const char *filename, unsigned linnum, unsigned charnum)
-{
- this->linnum = linnum;
- this->charnum = charnum;
- this->filename = filename;
-}
-
-const char *
-Loc::toChars (void) const
-{
- OutBuffer buf;
-
- if (this->filename)
- buf.printf ("%s", this->filename);
-
- if (this->linnum)
- {
- buf.printf (":%u", this->linnum);
- if (this->charnum)
- buf.printf (":%u", this->charnum);
- }
-
- return buf.extractChars ();
-}
-
-bool
-Loc::equals (const Loc &loc)
-{
- if (this->linnum != loc.linnum || this->charnum != loc.charnum)
- return false;
-
- if (!FileName::equals (this->filename, loc.filename))
- return false;
-
- return true;
-}
-
-
/* Implements back-end specific interfaces used by the frontend. */
/* Determine if function FD is a builtin one that we can evaluate in CTFE. */
@@ -144,7 +39,7 @@ Loc::equals (const Loc &loc)
BUILTIN
isBuiltin (FuncDeclaration *fd)
{
- if (fd->builtin != BUILTINunknown)
+ if (fd->builtin != BUILTIN::unknown)
return fd->builtin;
maybe_set_intrinsic (fd);
@@ -158,7 +53,7 @@ isBuiltin (FuncDeclaration *fd)
Expression *
eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
{
- if (fd->builtin == BUILTINunimp)
+ if (fd->builtin == BUILTIN::unimp)
return NULL;
tree decl = get_symbol_decl (fd);
@@ -185,16 +80,8 @@ eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
Type *
getTypeInfoType (Loc loc, Type *type, Scope *sc)
{
- gcc_assert (type->ty != Terror);
+ gcc_assert (type->ty != TY::Terror);
check_typeinfo_type (loc, sc);
create_typeinfo (type, sc ? sc->_module->importedFrom : NULL);
return type->vtinfo->type;
}
-
-/* Return an inlined copy of a default argument for a function parameter. */
-
-Expression *
-inlineCopy (Expression *e, Scope *)
-{
- return e->copy ();
-}
diff --git a/gcc/d/d-frontend.h b/gcc/d/d-frontend.h
new file mode 100644
index 0000000..3edf812
--- /dev/null
+++ b/gcc/d/d-frontend.h
@@ -0,0 +1,37 @@
+/* d-frontend.h -- D frontend interface to the gcc back-end.
+ Copyright (C) 2019 Free Software Foundation, Inc.
+
+GCC 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, or (at your option)
+any later version.
+
+GCC 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/>. */
+
+#ifndef GCC_D_FRONTEND_H
+#define GCC_D_FRONTEND_H
+
+/* These functions are defined in D runtime. */
+extern "C" int rt_init (void);
+extern "C" int rt_term (void);
+//extern "C" void gc_disable (void);
+extern "C" void *gc_malloc (size_t sz, unsigned ba = 0, const void *ti = NULL);
+extern "C" void gc_free (void *);
+extern "C" void gc_collect (void);
+
+template<typename T>
+inline T *
+d_gc_malloc (void)
+{
+ void *ptr = gc_malloc (sizeof (T));
+ return new(ptr) T ();
+}
+
+#endif
diff --git a/gcc/d/d-incpath.cc b/gcc/d/d-incpath.cc
index d863929..9a65622 100644
--- a/gcc/d/d-incpath.cc
+++ b/gcc/d/d-incpath.cc
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "dmd/globals.h"
+#include "d-frontend.h"
#include "cppdefault.h"
@@ -71,7 +72,7 @@ add_globalpaths (Strings *paths)
if (paths)
{
if (!global.path)
- global.path = new Strings ();
+ global.path = d_gc_malloc<Strings> ();
for (size_t i = 0; i < paths->length; i++)
{
@@ -98,7 +99,7 @@ add_filepaths (Strings *paths)
if (paths)
{
if (!global.filePath)
- global.filePath = new Strings ();
+ global.filePath = d_gc_malloc<Strings> ();
for (size_t i = 0; i < paths->length; i++)
{
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index be6330f..d20370e 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -26,12 +26,13 @@ along with GCC; see the file COPYING3. If not see
#include "dmd/errors.h"
#include "dmd/expression.h"
#include "dmd/hdrgen.h"
+#include "dmd/id.h"
#include "dmd/identifier.h"
#include "dmd/json.h"
#include "dmd/mangle.h"
-#include "dmd/mars.h"
#include "dmd/module.h"
#include "dmd/mtype.h"
+#include "dmd/root/file.h"
#include "dmd/target.h"
#include "opts.h"
@@ -53,7 +54,7 @@ along with GCC; see the file COPYING3. If not see
#include "input.h"
#include "d-tree.h"
-#include "id.h"
+#include "d-frontend.h"
/* Array of D frontend type/decl nodes. */
@@ -83,10 +84,6 @@ d_option;
/* List of modules being compiled. */
static Modules builtin_modules;
-/* Module where `C main' is defined, compiled in if needed. */
-static Module *entrypoint_module = NULL;
-static Module *entrypoint_root_module = NULL;
-
/* The current and global binding level in effect. */
struct binding_level *current_binding_level;
struct binding_level *global_binding_level;
@@ -202,7 +199,7 @@ deps_write (Module *module, obstack *buffer)
deps_write_string (d_option.deps_target[i], buffer, column);
}
else
- deps_write_string (module->objfile->name->str, buffer, column);
+ deps_write_string (module->objfile.toChars (), buffer, column);
obstack_1grow (buffer, ':');
column++;
@@ -212,7 +209,7 @@ deps_write (Module *module, obstack *buffer)
{
Module *depmod = modlist.pop ();
- const char *modstr = depmod->srcfile->name->str;
+ const char *modstr = depmod->srcfile.toChars ();
/* Skip modules that have already been looked at. */
if (seen_modules.add (modstr))
@@ -238,9 +235,7 @@ deps_write (Module *module, obstack *buffer)
Module *m = depmod->aimports[i];
/* Ignore compiler-generated modules. */
- if ((m->ident == Identifier::idPool ("__entrypoint")
- || m->ident == Identifier::idPool ("__main"))
- && m->parent == NULL)
+ if (m->ident == Identifier::idPool ("__main") && m->parent == NULL)
continue;
/* Don't search system installed modules, this includes
@@ -251,9 +246,9 @@ deps_write (Module *module, obstack *buffer)
&& m->parent == NULL)
continue;
- if (m->md && m->md->packages)
+ if (m->md && m->md->packages.length)
{
- Identifier *package = (*m->md->packages)[0];
+ Identifier *package = m->md->packages.ptr[0];
if (package == Identifier::idPool ("core")
|| package == Identifier::idPool ("std")
@@ -291,27 +286,15 @@ deps_write (Module *module, obstack *buffer)
static void
d_init_options (unsigned int, cl_decoded_option *decoded_options)
{
+ /* Initialize the D runtime. */
+ rt_init ();
+// gc_disable ();
+
/* Set default values. */
global._init ();
global.vendor = lang_hooks.name;
global.params.argv0 = xstrdup (decoded_options[0].arg);
- global.params.link = true;
- global.params.useAssert = CHECKENABLEdefault;
- global.params.useInvariants = CHECKENABLEdefault;
- global.params.useIn = CHECKENABLEdefault;
- global.params.useOut = CHECKENABLEdefault;
- global.params.useArrayBounds = CHECKENABLEdefault;
- global.params.useSwitchError = CHECKENABLEdefault;
- global.params.checkAction = CHECKACTION_D;
- global.params.useModuleInfo = true;
- global.params.useTypeInfo = true;
- global.params.useExceptions = true;
- global.params.useInline = false;
- global.params.obj = true;
- global.params.hdrStripPlainFunctions = true;
- global.params.betterC = false;
- global.params.allInst = false;
global.params.errorLimit = flag_max_errors;
/* Default extern(C++) mangling to C++14. */
@@ -320,9 +303,10 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options)
/* Warnings and deprecations are disabled by default. */
global.params.useDeprecated = DIAGNOSTICinform;
global.params.warnings = DIAGNOSTICoff;
+ global.params.messageStyle = MESSAGESTYLEgnu;
- global.params.imppath = new Strings ();
- global.params.fileImppath = new Strings ();
+ global.params.imppath = d_gc_malloc<Strings> ();
+ global.params.fileImppath = d_gc_malloc<Strings> ();
/* Extra GDC-specific options. */
d_option.fonly = NULL;
@@ -462,6 +446,11 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
: (value == 1) ? CHECKENABLEsafeonly : CHECKENABLEoff;
break;
+ case OPT_fcheckaction_:
+ global.params.checkAction = (value == 0) ? CHECKACTION_D
+ : (value == 1) ? CHECKACTION_halt : CHECKACTION_context;
+ break;
+
case OPT_fdebug:
global.params.debuglevel = value ? 1 : 0;
break;
@@ -480,7 +469,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
{
if (!global.params.debugids)
- global.params.debugids = new Strings ();
+ global.params.debugids = d_gc_malloc<Strings> ();
global.params.debugids->push (arg);
break;
}
@@ -510,6 +499,16 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
global.params.betterC = !value;
break;
+ case OPT_fdump_c___spec_:
+ if (global.params.doCxxHdrGeneration == CxxHeaderMode::none)
+ global.params.doCxxHdrGeneration = CxxHeaderMode::silent;
+ global.params.cxxhdrname = arg;
+ break;
+
+ case OPT_fdump_c___spec_verbose:
+ global.params.doCxxHdrGeneration = CxxHeaderMode::verbose;
+ break;
+
case OPT_fdump_d_original:
global.params.vcg_ast = value;
break;
@@ -518,6 +517,22 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
global.params.useExceptions = value;
break;
+ case OPT_fextern_std_:
+ switch (value)
+ {
+ case CppStdRevisionCpp98:
+ case CppStdRevisionCpp11:
+ case CppStdRevisionCpp14:
+ case CppStdRevisionCpp17:
+ case CppStdRevisionCpp20:
+ global.params.cplusplus = (CppStdRevision) value;
+ break;
+
+ default:
+ error ("bad argument for %<-fextern-std%>: %qs", arg);
+ }
+ break;
+
case OPT_fignore_unknown_pragmas:
global.params.ignoreUnsupportedPragmas = value;
break;
@@ -552,35 +567,115 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
global.params.useIn = value ? CHECKENABLEon : CHECKENABLEoff;
break;
+ case OPT_fpreview_all:
+ global.params.ehnogc = value;
+ global.params.useDIP25 = FeatureState::enabled;
+ global.params.useDIP1000 = FeatureState::enabled;
+ global.params.useDIP1021 = value;
+ global.params.dtorFields = FeatureState::enabled;
+ global.params.fieldwise = value;
+ global.params.fixAliasThis = value;
+ global.params.previewIn = value;
+ global.params.fix16997 = value;
+ global.params.markdown = value;
+ global.params.noSharedAccess = value;
+ global.params.rvalueRefParam = value;
+ global.params.inclusiveInContracts = value;
+ global.params.shortenedMethods = value;
+ break;
+
+ case OPT_fpreview_dip1000:
+ global.params.useDIP1000 = FeatureState::enabled;
+ break;
+
+ case OPT_fpreview_dip1008:
+ global.params.ehnogc = value;
+ break;
+
+ case OPT_fpreview_dip1021:
+ global.params.useDIP1021 = value;
+ break;
+
+ case OPT_fpreview_dip25:
+ global.params.useDIP25 = FeatureState::enabled;
+ break;
+
+ case OPT_fpreview_dtorfields:
+ global.params.dtorFields = FeatureState::enabled;
+ break;
+
+ case OPT_fpreview_fieldwise:
+ global.params.fieldwise = value;
+ break;
+
+ case OPT_fpreview_fixaliasthis:
+ global.params.fixAliasThis = value;
+ break;
+
+ case OPT_fpreview_in:
+ global.params.previewIn = value;
+ break;
+
+ case OPT_fpreview_inclusiveincontracts:
+ global.params.inclusiveInContracts = value;
+ break;
+
+ case OPT_fpreview_intpromote:
+ global.params.fix16997 = value;
+ break;
+
+ case OPT_fpreview_nosharedaccess:
+ global.params.noSharedAccess = value;
+ break;
+
+ case OPT_fpreview_rvaluerefparam:
+ global.params.rvalueRefParam = value;
+ break;
+
+ case OPT_fpreview_shortenedmethods:
+ global.params.shortenedMethods = value;
+ break;
+
case OPT_frelease:
global.params.release = value;
break;
- case OPT_frtti:
- global.params.useTypeInfo = value;
+ case OPT_frevert_all:
+ global.params.useDIP25 = FeatureState::disabled;
+ global.params.markdown = !value;
+ global.params.dtorFields = FeatureState::disabled;
break;
- case OPT_fswitch_errors:
- global.params.useSwitchError = value ? CHECKENABLEon : CHECKENABLEoff;
+ case OPT_frevert_dip25:
+ global.params.useDIP25 = FeatureState::disabled;
break;
- case OPT_ftransition_all:
- global.params.vtls = value;
- global.params.vfield = value;
- global.params.vcomplex = value;
+ case OPT_frevert_dtorfields:
+ global.params.dtorFields = FeatureState::disabled;
+ break;
+
+ case OPT_frevert_markdown:
+ global.params.markdown = !value;
break;
- case OPT_ftransition_complex:
- global.params.vcomplex = value;
+ case OPT_frtti:
+ global.params.useTypeInfo = value;
break;
- case OPT_ftransition_dip1000:
- global.params.vsafe = value;
- global.params.useDIP25 = value;
+ case OPT_fsave_mixins_:
+ global.params.mixinFile = arg;
+ global.params.mixinOut = d_gc_malloc<OutBuffer> ();
break;
- case OPT_ftransition_dip25:
- global.params.useDIP25 = value;
+ case OPT_fswitch_errors:
+ global.params.useSwitchError = value ? CHECKENABLEon : CHECKENABLEoff;
+ break;
+
+ case OPT_ftransition_all:
+ global.params.vfield = value;
+ global.params.vgc = value;
+ global.params.vmarkdown= value;
+ global.params.vtls = value;
break;
case OPT_ftransition_field:
@@ -591,6 +686,14 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
global.params.vgc = value;
break;
+ case OPT_ftransition_vmarkdown:
+ global.params.vmarkdown = value;
+ break;
+
+ case OPT_ftransition_templates:
+ global.params.vtemplates = value;
+ break;
+
case OPT_ftransition_tls:
global.params.vtls = value;
break;
@@ -613,7 +716,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
{
if (!global.params.versionids)
- global.params.versionids = new Strings ();
+ global.params.versionids = d_gc_malloc<Strings> ();
global.params.versionids->push (arg);
break;
}
@@ -804,6 +907,14 @@ d_post_options (const char ** fn)
global.params.checkAction = CHECKACTION_C;
}
+ /* Enabling DIP1021 implies DIP1000. */
+ if (global.params.useDIP1021)
+ global.params.useDIP1000 = FeatureState::enabled;
+
+ /* Enabling DIP1000 implies DIP25. */
+ if (global.params.useDIP1000 == FeatureState::enabled)
+ global.params.useDIP25 = FeatureState::enabled;
+
/* Keep in sync with existing -fbounds-check flag. */
flag_bounds_check = (global.params.useArrayBounds == CHECKENABLEon);
@@ -828,6 +939,7 @@ d_post_options (const char ** fn)
global.params.symdebug = write_symbols != NO_DEBUG;
global.params.useInline = flag_inline_functions;
global.params.showColumns = flag_show_column;
+ global.params.printErrorContext = flag_diagnostics_show_caret;
if (global.params.useInline)
global.params.hdrStripPlainFunctions = false;
@@ -872,17 +984,6 @@ d_add_builtin_module (Module *m)
builtin_modules.push (m);
}
-/* Record the entrypoint module ENTRY which will be compiled in the current
- compilation. ROOT is the module scope where this was requested from. */
-
-void
-d_add_entrypoint_module (Module *entry, Module *root)
-{
- /* We are emitting this straight to object file. */
- entrypoint_module = entry;
- entrypoint_root_module = root;
-}
-
/* Implements the lang_hooks.parse_file routine for language D. */
static void
@@ -891,7 +992,7 @@ d_parse_file (void)
if (global.params.verbose)
{
message ("binary %s", global.params.argv0.ptr);
- message ("version %s", global.version.ptr);
+ message ("version %s", global.versionChars ());
if (global.versionids)
{
@@ -955,16 +1056,16 @@ d_parse_file (void)
/* Handling stdin, generate a unique name for the module. */
Module *m = Module::create (in_fnames[i],
- Identifier::generateId ("__stdin"),
+ Identifier::idPool ("__stdin"),
global.params.doDocComments,
global.params.doHdrGeneration);
modules.push (m);
/* Overwrite the source file for the module, the one created by
Module::create would have a forced a `.d' suffix. */
- m->srcfile = File::create ("<stdin>");
- m->srcfile->len = len;
- m->srcfile->buffer = buffer;
+ m->srcBuffer = FileBuffer::create ();
+ m->srcBuffer->data.length = len;
+ m->srcBuffer->data.ptr = buffer;
}
else
{
@@ -1011,15 +1112,16 @@ d_parse_file (void)
}
/* Load the module containing D main. */
+ Module *main_module = NULL;
if (global.params.addMain)
{
unsigned errors = global.startGagging ();
- Module *m = Module::load (Loc (), NULL, Identifier::idPool ("__main"));
+ main_module = Module::load (Loc (), NULL, Identifier::idPool ("__main"));
if (!global.endGagging (errors))
{
- m->importedFrom = m;
- modules.push (m);
+ main_module->importedFrom = main_module;
+ modules.push (main_module);
}
}
@@ -1038,7 +1140,7 @@ d_parse_file (void)
for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
- if (d_option.fonly && m != Module::rootModule)
+ if (m->isHdrFile || (d_option.fonly && m != Module::rootModule))
continue;
if (global.params.verbose)
@@ -1203,7 +1305,7 @@ d_parse_file (void)
if (name && (name[0] != '-' || name[1] != '\0'))
{
const char *nameext
- = FileName::defaultExt (name, global.json_ext.ptr);
+ = FileName::defaultExt (name, json_ext.ptr);
json_stream = fopen (nameext, "w");
if (!json_stream)
{
@@ -1245,22 +1347,25 @@ d_parse_file (void)
}
}
+ /* Generate C++ header files. */
+ if (global.params.doCxxHdrGeneration != CxxHeaderMode::none)
+ genCppHdrFiles (modules);
+
+ if (global.errors)
+ goto had_errors;
+
for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
- if (d_option.fonly && m != Module::rootModule)
+ if ((m->isHdrFile && m != main_module)
+ || (d_option.fonly && m != Module::rootModule))
continue;
if (global.params.verbose)
message ("code %s", m->toChars ());
if (!flag_syntax_only)
- {
- if ((entrypoint_module != NULL) && (m == entrypoint_root_module))
- build_decl_tree (entrypoint_module);
-
- build_decl_tree (m);
- }
+ build_decl_tree (m);
}
/* And end the main input file, if the debug writer wants it. */
@@ -1272,16 +1377,37 @@ d_parse_file (void)
exit with an error status. */
errorcount += (global.errors + global.warnings);
+ /* We want to write the mixin expansion file also on error. */
+ if (global.params.mixinOut)
+ {
+ FILE *mixin_stream = fopen (global.params.mixinFile, "w");
+
+ if (mixin_stream)
+ {
+ OutBuffer *buf = global.params.mixinOut;
+ fprintf (mixin_stream, "%s", buf->peekChars ());
+
+ if (ferror (mixin_stream) || fclose (mixin_stream))
+ fatal_error (input_location, "closing mixin file %s: %m",
+ global.params.mixinFile);
+ }
+ else
+ {
+ fatal_error (input_location, "opening mixin file %s: %m",
+ global.params.mixinFile);
+ }
+ }
+
/* Remove generated .di files on error. */
if (errorcount && dump_headers)
{
for (size_t i = 0; i < modules.length; i++)
{
Module *m = modules[i];
- if (d_option.fonly && m != Module::rootModule)
+ if (m->isHdrFile || (d_option.fonly && m != Module::rootModule))
continue;
- remove (m->hdrfile->toChars ());
+ remove (m->hdrfile.toChars ());
}
}
@@ -1406,7 +1532,7 @@ d_type_promotes_to (tree type)
/* Promotions are only applied on unnamed function arguments for declarations
with `extern(C)' or `extern(C++)' linkage. */
if (cfun && DECL_LANG_FRONTEND (cfun->decl)
- && DECL_LANG_FRONTEND (cfun->decl)->linkage != LINKd)
+ && DECL_LANG_FRONTEND (cfun->decl)->linkage != LINK::d)
{
/* In [type/integer-promotions], integer promotions are conversions of the
following types:
@@ -1559,7 +1685,8 @@ d_types_compatible_p (tree x, tree y)
return true;
/* Type system allows implicit conversion between. */
- if (tx->implicitConvTo (ty) || ty->implicitConvTo (tx))
+ if (tx->implicitConvTo (ty) != MATCH::nomatch
+ || ty->implicitConvTo (tx) != MATCH::nomatch)
return true;
}
diff --git a/gcc/d/d-longdouble.cc b/gcc/d/d-longdouble.cc
index 471544e..27c8d17 100644
--- a/gcc/d/d-longdouble.cc
+++ b/gcc/d/d-longdouble.cc
@@ -30,12 +30,6 @@ along with GCC; see the file COPYING3. If not see
#include "longdouble.h"
-/* Constant real values 0, 1, -1 and 0.5. */
-real_t CTFloat::zero;
-real_t CTFloat::one;
-real_t CTFloat::minusone;
-real_t CTFloat::half;
-
/* Truncate longdouble to the highest precision supported by target. */
longdouble
diff --git a/gcc/d/d-system.h b/gcc/d/d-system.h
index a6a9fcc..d7a0079 100644
--- a/gcc/d/d-system.h
+++ b/gcc/d/d-system.h
@@ -26,60 +26,8 @@
#endif
#include "system.h"
-/* Used by the dmd front-end to determine if we have POSIX-style IO. */
-#define POSIX (__linux__ || __GLIBC__ || __gnu_hurd__ || __APPLE__ \
- || __FreeBSD__ || __NetBSD__ || __OpenBSD__ || __DragonFly__ \
- || __sun || __unix__)
-
/* Forward assert invariants to gcc_assert. */
#undef assert
#define assert(EXPR) gcc_assert(EXPR)
-/* Use libiberty's lrealpath to avoid portability problems. */
-#undef realpath
-#define realpath(a, b) lrealpath((a))
-
-/* Forward ctype.h macros used by the dmd front-end to safe-ctype.h. */
-#undef isalpha
-#define isalpha(c) ISALPHA(c)
-#undef isalnum
-#define isalnum(c) ISALNUM(c)
-#undef isdigit
-#define isdigit(c) ISDIGIT(c)
-#undef islower
-#define islower(c) ISLOWER(c)
-#undef isprint
-#define isprint(c) ISPRINT(c)
-#undef isspace
-#define isspace(c) ISSPACE(c)
-#undef isupper
-#define isupper(c) ISUPPER(c)
-#undef isxdigit
-#define isxdigit(c) ISXDIGIT(c)
-#undef tolower
-#define tolower(c) TOLOWER(c)
-
-/* Forward _mkdir on MinGW to mkdir in system.h. */
-#ifdef _WIN32
-#undef _mkdir
-#define _mkdir(p) mkdir(p, 0)
-#endif
-
-/* Define any missing _MAX and _MIN macros. */
-#ifndef INT32_MAX
-# define INT32_MAX INTTYPE_MAXIMUM (int32_t)
-#endif
-#ifndef INT32_MIN
-# define INT32_MIN INTTYPE_MINIMUM (int32_t)
-#endif
-#ifndef INT64_MIN
-# define INT64_MIN INTTYPE_MINIMUM (int64_t)
-#endif
-#ifndef UINT32_MAX
-# define UINT32_MAX INTTYPE_MAXIMUM (uint32_t)
-#endif
-#ifndef UINT64_MAX
-# define UINT64_MAX INTTYPE_MAXIMUM (uint64_t)
-#endif
-
#endif /* GCC_D_SYSTEM_H */
diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc
index 1488bce..21417dd 100644
--- a/gcc/d/d-target.cc
+++ b/gcc/d/d-target.cc
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm.h"
#include "tm_p.h"
#include "target.h"
+#include "calls.h"
#include "d-tree.h"
#include "d-target.h"
@@ -42,8 +43,6 @@ along with GCC; see the file COPYING3. If not see
/* Implements the Target interface defined by the front end.
Used for retrieving target-specific information. */
-Target target;
-
/* Internal key handlers for `__traits(getTargetInfo)'. */
static tree d_handle_target_cpp_std (void);
static tree d_handle_target_cpp_runtime_library (void);
@@ -89,9 +88,6 @@ define_float_constants (T &f, tree type)
/* Floating-point NaN. */
real_nan (&f.nan.rv (), "", 1, mode);
- /* Signalling floating-point NaN. */
- real_nan (&f.snan.rv (), "", 0, mode);
-
/* Floating-point +Infinity if the target supports infinities. */
real_inf (&f.infinity.rv ());
@@ -142,19 +138,19 @@ Target::_init (const Param &)
/* Define what type to use for size_t, ptrdiff_t. */
if (this->ptrsize == 8)
{
- global.params.isLP64 = true;
- Type::tsize_t = Type::basic[Tuns64];
- Type::tptrdiff_t = Type::basic[Tint64];
+ this->isLP64 = true;
+ Type::tsize_t = Type::basic[(int)TY::Tuns64];
+ Type::tptrdiff_t = Type::basic[(int)TY::Tint64];
}
else if (this->ptrsize == 4)
{
- Type::tsize_t = Type::basic[Tuns32];
- Type::tptrdiff_t = Type::basic[Tint32];
+ Type::tsize_t = Type::basic[(int)TY::Tuns32];
+ Type::tptrdiff_t = Type::basic[(int)TY::Tint32];
}
else if (this->ptrsize == 2)
{
- Type::tsize_t = Type::basic[Tuns16];
- Type::tptrdiff_t = Type::basic[Tint16];
+ Type::tsize_t = Type::basic[(int)TY::Tuns16];
+ Type::tptrdiff_t = Type::basic[(int)TY::Tint16];
}
else
sorry ("D does not support pointers on this target.");
@@ -164,15 +160,7 @@ Target::_init (const Param &)
/* Set-up target C ABI. */
this->c.longsize = int_size_in_bytes (long_integer_type_node);
this->c.long_doublesize = int_size_in_bytes (long_double_type_node);
-
- /* Define what type to use for wchar_t. We don't want to support wide
- characters less than "short" in D. */
- if (WCHAR_TYPE_SIZE == 32)
- this->c.twchar_t = Type::basic[Tdchar];
- else if (WCHAR_TYPE_SIZE == 16)
- this->c.twchar_t = Type::basic[Twchar];
- else
- sorry ("D does not support wide characters on this target.");
+ this->c.wchar_tsize = (WCHAR_TYPE_SIZE / BITS_PER_UNIT);
/* Set-up target C++ ABI. */
this->cpp.reverseOverloads = false;
@@ -182,6 +170,12 @@ Target::_init (const Param &)
/* Set-up target Objective-C ABI. */
this->objc.supported = false;
+ /* Set-up environmental settings. */
+ this->obj_ext = "o";
+ this->lib_ext = "a";
+ this->dll_ext = "so";
+ this->run_noext = true;
+
/* Initialize all compile-time properties for floating-point types.
Should ensure that our real_t type is able to represent real_value. */
gcc_assert (sizeof (real_t) >= sizeof (real_value));
@@ -273,7 +267,7 @@ Target::isVectorTypeSupported (int sz, Type *type)
type = Type::tuns8;
/* No support for non-trivial types, complex types, or booleans. */
- if (!type->isTypeBasic () || type->iscomplex () || type->ty == Tbool)
+ if (!type->isTypeBasic () || type->iscomplex () || type->ty == TY::Tbool)
return 2;
/* In [simd/vector extensions], which vector types are supported depends on
@@ -293,9 +287,9 @@ Target::isVectorTypeSupported (int sz, Type *type)
Returns true if the operation is supported or type is not a vector. */
bool
-Target::isVectorOpSupported (Type *type, TOK op, Type *)
+Target::isVectorOpSupported (Type *type, unsigned op, Type *)
{
- if (type->ty != Tvector)
+ if (type->ty != TY::Tvector)
return true;
/* Don't support if type is non-scalar, such as __vector(void[]). */
@@ -322,18 +316,10 @@ Target::isVectorOpSupported (Type *type, TOK op, Type *)
/* Logical operators must have a result type of bool. */
return false;
- case TOKue:
- case TOKlg:
- case TOKule:
- case TOKul:
- case TOKuge:
- case TOKug:
case TOKle:
case TOKlt:
case TOKge:
case TOKgt:
- case TOKleg:
- case TOKunord:
case TOKequal:
case TOKnotequal:
case TOKidentity:
@@ -379,7 +365,8 @@ TargetCPP::thunkMangle (FuncDeclaration *fd, int offset)
const char *
TargetCPP::typeMangle (Type *type)
{
- if (type->isTypeBasic () || type->ty == Tvector || type->ty == Tstruct)
+ if (type->isTypeBasic () || type->ty == TY::Tvector
+ || type->ty == TY::Tstruct)
{
tree ctype = build_ctype (type);
return targetm.mangle_type (ctype);
@@ -400,14 +387,14 @@ TargetCPP::parameterType (Parameter *arg)
else if (arg->storageClass & STClazy)
{
/* Mangle as delegate. */
- Type *td = TypeFunction::create (NULL, t, VARARGnone, LINKd);
- td = TypeDelegate::create (td);
- t = t->merge2 ();
+ TypeFunction *tf = TypeFunction::create (NULL, t, VARARGnone, LINK::d);
+ TypeDelegate *td = TypeDelegate::create (tf);
+ t = td->merge2 ();
}
/* Could be a va_list, which we mangle as a pointer. */
Type *tvalist = target.va_listType (Loc (), NULL);
- if (t->ty == Tsarray && tvalist->ty == Tsarray)
+ if (t->ty == TY::Tsarray && tvalist->ty == TY::Tsarray)
{
Type *tb = t->toBasetype ()->mutableOf ();
if (tb == tvalist)
@@ -450,10 +437,10 @@ Target::systemLinkage (void)
/* In [attribute/linkage], `System' is the same as `Windows' on Windows
platforms, and `C' on other platforms. */
if (link_system)
- return LINKwindows;
+ return LINK::windows;
}
- return LINKc;
+ return LINK::c;
}
/* Generate a TypeTuple of the equivalent types used to determine if a
@@ -477,12 +464,12 @@ Target::isReturnOnStack (TypeFunction *tf, bool)
/* Need the back-end type to determine this, but this is called from the
frontend before semantic processing is finished. An accurate value
is not currently needed anyway. */
- if (tf->isref)
+ if (tf->isref ())
return false;
Type *tn = tf->next->toBasetype ();
- return (tn->ty == Tstruct || tn->ty == Tsarray);
+ return (tn->ty == TY::Tstruct || tn->ty == TY::Tsarray);
}
/* Add all target info in HANDLERS to D_TARGET_INFO_TABLE for use by
@@ -575,12 +562,49 @@ Target::getTargetInfo (const char *key, const Loc &loc)
return NULL;
}
-/**
- * Returns true if the implementation for object monitors is always defined
- * in the D runtime library (rt/monitor_.d). */
+/* Returns true if the callee invokes destructors for arguments. */
+
+bool
+Target::isCalleeDestroyingArgs (TypeFunction *tf)
+{
+ return tf->linkage == LINK::d;
+}
+
+/* Returns true if the implementation for object monitors is always defined
+ in the D runtime library (rt/monitor_.d). */
bool
Target::libraryObjectMonitors (FuncDeclaration *, Statement *)
{
return true;
}
+
+/* Decides whether an `in' parameter of the specified POD type PARAM_TYPE is to
+ be passed by reference or by valie. This is used only when compiling with
+ `-fpreview=in' enabled. */
+
+bool
+Target::preferPassByRef (Type *param_type)
+{
+ if (param_type->size () == SIZE_INVALID)
+ return false;
+
+ tree type = build_ctype (param_type);
+
+ /* Prefer a `ref' if the type is an aggregate, and its size is greater than
+ its alignment. */
+ if (AGGREGATE_TYPE_P (type)
+ && (!valid_constant_size_p (TYPE_SIZE_UNIT (type))
+ || compare_tree_int (TYPE_SIZE_UNIT (type), TYPE_ALIGN (type)) > 0))
+ return true;
+
+ /* If the back-end is always going to pass this by invisible reference. */
+ if (pass_by_reference (NULL, function_arg_info (type, true)))
+ return true;
+
+ /* If returning the parameter means the caller will do RVO. */
+ if (targetm.calls.return_in_memory (type, NULL_TREE))
+ return true;
+
+ return false;
+}
diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h
index 9b90ca5..328b6b8 100644
--- a/gcc/d/d-tree.h
+++ b/gcc/d/d-tree.h
@@ -617,7 +617,6 @@ extern void add_import_paths (const char *, const char *, bool);
/* In d-lang.cc. */
extern void d_add_builtin_module (Module *);
-extern void d_add_entrypoint_module (Module *, Module *);
extern d_tree_node_structure_enum d_tree_node_structure (lang_tree_node *);
extern struct lang_type *build_lang_type (Type *);
extern struct lang_decl *build_lang_decl (Declaration *);
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 9c9205f..e28a581 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -106,9 +106,9 @@ gcc_attribute_p (Dsymbol *decl)
{
ModuleDeclaration *md = decl->getModule ()->md;
- if (md && md->packages && md->packages->length == 1)
+ if (md && md->packages.length == 1)
{
- if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
+ if (!strcmp (md->packages.ptr[0]->toChars (), "gcc")
&& !strcmp (md->id->toChars (), "attributes"))
return true;
}
@@ -116,6 +116,59 @@ gcc_attribute_p (Dsymbol *decl)
return false;
}
+/* Subroutine of pragma declaration visitor for marking the function in the
+ defined in SYM as a global constructor or destructor. If ISCTOR is true,
+ then we're applying pragma(crt_constructor). */
+
+static int
+apply_pragma_crt (Dsymbol *sym, bool isctor)
+{
+ AttribDeclaration *ad = sym->isAttribDeclaration ();
+ if (ad != NULL)
+ {
+ int nested = 0;
+
+ /* Walk all declarations of the attribute scope. */
+ Dsymbols *ds = ad->include (NULL);
+ if (ds)
+ {
+ for (size_t i = 0; i < ds->length; i++)
+ nested += apply_pragma_crt ((*ds)[i], isctor);
+ }
+
+ return nested;
+ }
+
+ FuncDeclaration *fd = sym->isFuncDeclaration ();
+ if (fd != NULL)
+ {
+ tree decl = get_decl_tree (fd);
+
+ /* Apply flags to the function. */
+ if (isctor)
+ {
+ DECL_STATIC_CONSTRUCTOR (decl) = 1;
+ decl_init_priority_insert (decl, DEFAULT_INIT_PRIORITY);
+ }
+ else
+ {
+ DECL_STATIC_DESTRUCTOR (decl) = 1;
+ decl_fini_priority_insert (decl, DEFAULT_INIT_PRIORITY);
+ }
+
+ if (fd->linkage != LINK::c)
+ {
+ error_at (make_location_t (fd->loc),
+ "must be %<extern(C)%> for %<pragma(%s)%>",
+ isctor ? "crt_constructor" : "crt_destructor");
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
/* Implements the visitor interface to lower all Declaration AST classes
emitted from the D Front-end to GCC trees.
All visit methods accept one parameter D, which holds the frontend AST
@@ -246,19 +299,31 @@ public:
}
/* Pragmas are a way to pass special information to the compiler and to add
- vendor specific extensions to D. We don't do anything here, yet. */
+ vendor specific extensions to D. */
void visit (PragmaDeclaration *d)
{
- if (!global.params.ignoreUnsupportedPragmas)
+ if (d->ident == Identifier::idPool ("lib")
+ || d->ident == Identifier::idPool ("startaddress"))
{
- if (d->ident == Identifier::idPool ("lib")
- || d->ident == Identifier::idPool ("startaddress"))
+ if (!global.params.ignoreUnsupportedPragmas)
{
warning_at (make_location_t (d->loc), OPT_Wunknown_pragmas,
"pragma(%s) not implemented", d->ident->toChars ());
}
}
+ else if (d->ident == Identifier::idPool ("crt_constructor")
+ || d->ident == Identifier::idPool ("crt_destructor"))
+ {
+ /* Handle pragma(crt_constructor) and pragma(crt_destructor). Apply
+ flag to indicate that the functions enclosed should run automatically
+ at the beginning or end of execution. */
+ bool isctor = (d->ident == Identifier::idPool ("crt_constructor"));
+
+ if (apply_pragma_crt (d, isctor) > 1)
+ error_at (make_location_t (d->loc),
+ "can only apply to a single declaration");
+ }
visit ((AttribDeclaration *) d);
}
@@ -311,14 +376,14 @@ public:
nested members. Only applies to classes or structs. */
Type *tb = fd->type->nextOf ()->baseElemOf ();
- while (tb->ty == Tarray || tb->ty == Tpointer)
+ while (tb->ty == TY::Tarray || tb->ty == TY::Tpointer)
tb = tb->nextOf ()->baseElemOf ();
TemplateInstance *ti = NULL;
- if (tb->ty == Tstruct)
+ if (tb->ty == TY::Tstruct)
ti = tb->isTypeStruct ()->sym->isInstantiated ();
- else if (tb->ty == Tclass)
+ else if (tb->ty == TY::Tclass)
ti = tb->isTypeClass ()->sym->isInstantiated ();
/* Return type is instantiated from this template declaration, walk over
@@ -360,7 +425,7 @@ public:
if (d->semanticRun >= PASSobj)
return;
- if (d->type->ty == Terror)
+ if (d->type->ty == TY::Terror)
{
error_at (make_location_t (d->loc),
"had semantic errors when compiling");
@@ -447,7 +512,8 @@ public:
if (fd2->isFuture ())
continue;
- if (fd->leastAsSpecialized (fd2) || fd2->leastAsSpecialized (fd))
+ if (fd->leastAsSpecialized (fd2) != MATCH::nomatch
+ || fd2->leastAsSpecialized (fd) != MATCH::nomatch)
{
error_at (make_location_t (fd->loc), "use of %qs",
fd->toPrettyChars ());
@@ -474,7 +540,7 @@ public:
if (d->semanticRun >= PASSobj)
return;
- if (d->type->ty == Terror)
+ if (d->type->ty == TY::Terror)
{
error_at (make_location_t (d->loc),
"had semantic errors when compiling");
@@ -495,7 +561,8 @@ public:
/* Generate C symbols. */
d->csym = get_classinfo_decl (d);
- d->vtblsym = get_vtable_decl (d);
+ Dsymbol *vtblsym = d->vtblSymbol ();
+ vtblsym->csym = get_vtable_decl (d);
tree sinit = aggregate_initializer_decl (d);
/* Generate static initializer. */
@@ -527,9 +594,9 @@ public:
}
}
- DECL_INITIAL (d->vtblsym)
- = build_constructor (TREE_TYPE (d->vtblsym), elms);
- d_finish_decl (d->vtblsym);
+ DECL_INITIAL (vtblsym->csym)
+ = build_constructor (TREE_TYPE (vtblsym->csym), elms);
+ d_finish_decl (vtblsym->csym);
/* Add this decl to the current binding level. */
tree ctype = TREE_TYPE (build_ctype (d->type));
@@ -547,7 +614,7 @@ public:
if (d->semanticRun >= PASSobj)
return;
- if (d->type->ty == Terror)
+ if (d->type->ty == TY::Terror)
{
error_at (make_location_t (d->loc),
"had semantic errors when compiling");
@@ -590,7 +657,7 @@ public:
if (d->semanticRun >= PASSobj)
return;
- if (d->errors || d->type->ty == Terror)
+ if (d->errors || d->type->ty == TY::Terror)
{
error_at (make_location_t (d->loc),
"had semantic errors when compiling");
@@ -629,7 +696,7 @@ public:
if (d->semanticRun >= PASSobj)
return;
- if (d->type->ty == Terror)
+ if (d->type->ty == TY::Terror)
{
error_at (make_location_t (d->loc),
"had semantic errors when compiling");
@@ -695,7 +762,7 @@ public:
/* Frontend should have already caught this. */
gcc_assert (!integer_zerop (size)
- || d->type->toBasetype ()->ty == Tsarray);
+ || d->type->toBasetype ()->ty == TY::Tsarray);
d_finish_decl (decl);
@@ -770,7 +837,7 @@ public:
/* Check if any errors occurred when running semantic. */
if (TypeFunction *tf = d->type->isTypeFunction ())
{
- if (tf->next == NULL || tf->next->ty == Terror)
+ if (tf->next == NULL || tf->next->ty == TY::Terror)
return;
}
@@ -1183,6 +1250,17 @@ get_symbol_decl (Declaration *decl)
}
else if (TREE_CODE (decl->csym) == FUNCTION_DECL)
{
+ /* Dual-context functions require the code generation to build an array
+ for the context pointer of the function, making the delicate task of
+ tracking which context to follow when encountering a non-local symbol,
+ and so are a not planned to be supported. */
+ if (fd->needThis () && !fd->isMember2 ())
+ {
+ fatal_error (make_location_t (fd->loc),
+ "function requires a dual-context, which is not yet "
+ "supported by GDC");
+ }
+
/* The real function type may differ from its declaration. */
tree fntype = TREE_TYPE (decl->csym);
tree newfntype = NULL_TREE;
@@ -1238,9 +1316,9 @@ get_symbol_decl (Declaration *decl)
/* In [pragma/inline], functions decorated with `pragma(inline)' affects
whether they are inlined or not. */
- if (fd->inlining == PINLINEalways)
+ if (fd->inlining == PINLINE::always)
DECL_DECLARED_INLINE_P (decl->csym) = 1;
- else if (fd->inlining == PINLINEnever)
+ else if (fd->inlining == PINLINE::never)
DECL_UNINLINABLE (decl->csym) = 1;
/* Function was declared `naked'. */
@@ -1254,13 +1332,6 @@ get_symbol_decl (Declaration *decl)
if (fd->generated)
DECL_ARTIFICIAL (decl->csym) = 1;
- /* Vector array operations are always compiler generated. */
- if (fd->isArrayOp)
- {
- DECL_ARTIFICIAL (decl->csym) = 1;
- DECL_DECLARED_INLINE_P (decl->csym) = 1;
- }
-
/* Ensure and require contracts are lexically nested in the function they
part of, but are always publicly callable. */
if (fd->ident == Identifier::idPool ("ensure")
@@ -1271,7 +1342,7 @@ get_symbol_decl (Declaration *decl)
DECL_FINAL_P (decl->csym) = 1;
/* Function is of type `noreturn' or `typeof(*null)'. */
- if (fd->type->nextOf ()->ty == Tnoreturn)
+ if (fd->type->nextOf ()->ty == TY::Tnoreturn)
TREE_THIS_VOLATILE (decl->csym) = 1;
/* Check whether this function is expanded by the frontend. */
@@ -1298,10 +1369,10 @@ get_symbol_decl (Declaration *decl)
if (decl->storage_class & STCvolatile)
TREE_THIS_VOLATILE (decl->csym) = 1;
- /* Protection attributes are used by the debugger. */
- if (decl->protection.kind == Prot::private_)
+ /* Visibility attributes are used by the debugger. */
+ if (decl->visibility.kind == Visibility::private_)
TREE_PRIVATE (decl->csym) = 1;
- else if (decl->protection.kind == Prot::protected_)
+ else if (decl->visibility.kind == Visibility::protected_)
TREE_PROTECTED (decl->csym) = 1;
/* Likewise, so could the deprecated attribute. */
@@ -1794,7 +1865,7 @@ make_thunk (FuncDeclaration *decl, int offset)
forcing a D local thunk to be emitted. */
const char *ident;
- if (decl->linkage == LINKcpp)
+ if (decl->linkage == LINK::cpp)
ident = target.cpp.thunkMangle (decl, offset);
else
{
@@ -1810,7 +1881,9 @@ make_thunk (FuncDeclaration *decl, int offset)
SET_DECL_ASSEMBLER_NAME (thunk, DECL_NAME (thunk));
d_keep (thunk);
- free (CONST_CAST (char *, ident));
+
+ if (decl->linkage != LINK::cpp)
+ free (CONST_CAST (char *, ident));
if (!DECL_EXTERNAL (function))
finish_thunk (thunk, function);
@@ -1989,26 +2062,27 @@ d_mark_needed (tree decl)
tree
get_vtable_decl (ClassDeclaration *decl)
{
- if (decl->vtblsym)
- return decl->vtblsym;
+ if (decl->vtblsym && decl->vtblsym->csym)
+ return decl->vtblsym->csym;
tree ident = mangle_internal_decl (decl, "__vtbl", "Z");
/* Note: Using a static array type for the VAR_DECL, the DECL_INITIAL value
will have a different type. However the back-end seems to accept this. */
tree type = build_ctype (Type::tvoidptr->sarrayOf (decl->vtbl.length));
- decl->vtblsym = declare_extern_var (ident, type);
- DECL_LANG_SPECIFIC (decl->vtblsym) = build_lang_decl (NULL);
+ Dsymbol *vtblsym = decl->vtblSymbol ();
+ vtblsym->csym = declare_extern_var (ident, type);
+ DECL_LANG_SPECIFIC (vtblsym->csym) = build_lang_decl (NULL);
/* Class is a reference, want the record type. */
- DECL_CONTEXT (decl->vtblsym) = TREE_TYPE (build_ctype (decl->type));
- TREE_READONLY (decl->vtblsym) = 1;
- DECL_VIRTUAL_P (decl->vtblsym) = 1;
+ DECL_CONTEXT (vtblsym->csym) = TREE_TYPE (build_ctype (decl->type));
+ TREE_READONLY (vtblsym->csym) = 1;
+ DECL_VIRTUAL_P (vtblsym->csym) = 1;
- SET_DECL_ALIGN (decl->vtblsym, TARGET_VTABLE_ENTRY_ALIGN);
- DECL_USER_ALIGN (decl->vtblsym) = true;
+ SET_DECL_ALIGN (vtblsym->csym, TARGET_VTABLE_ENTRY_ALIGN);
+ DECL_USER_ALIGN (vtblsym->csym) = true;
- return decl->vtblsym;
+ return vtblsym->csym;
}
/* Helper function of build_class_instance. Find the field inside aggregate
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 2568993..129050b 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-27e388b4c4d292cac25811496aaf79341c05c940
+b8384668f28741ad5884fc055a2bdb9c05fd95ec
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md
new file mode 100644
index 0000000..720d256
--- /dev/null
+++ b/gcc/d/dmd/README.md
@@ -0,0 +1,259 @@
+# DMD Source code
+
+This is the source code to the DMD compiler
+for the D Programming Language defined in the documents at
+http://dlang.org/
+
+These sources are free, they are redistributable and modifiable
+under the terms of the Boost Software License, Version 1.0.
+The terms of this license are in the file boostlicense.txt,
+or see http://www.boost.org/LICENSE_1_0.txt.
+
+If a particular file has a different license in it, that overrides
+this license for that file.
+
+-Walter Bright
+
+## Directory structure
+
+| Folder | Purpose |
+|--------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| [dmd/](https://github.com/dlang/dmd/tree/master/src/dmd) | The dmd driver and front-end |
+| [dmd/backend/](https://github.com/dlang/dmd/tree/master/src/dmd/backend) | Code generation for x86 or x86-64. Shared by the [Digital Mars C compiler](https://github.com/DigitalMars/Compiler/), but not [LDC](https://github.com/ldc-developers/ldc) or [GDC](https://gdcproject.org/). |
+| [dmd/root/](https://github.com/dlang/dmd/tree/master/src/dmd/root) | Meant as a portable utility library, but ["it wasn't very good and the only project left using it is dmd"](https://github.com/dlang/dmd/pull/9844#issuecomment-498479516). |
+
+DMD has a mostly flat directory structure, so this section aims to divide all source files into logical groups for easier navigation.
+The groups are roughly ordered by how late they appear in the compilation process.
+Note that these groups have no strict meaning, the category assignments are a bit subjective.
+
+### Driver
+
+| File | Purpose |
+|-----------------------------------------------------------------------------|-----------------------------------------------------------------------|
+| [mars.d](https://github.com/dlang/dmd/blob/master/src/dmd/mars.d) | The entry point. Contains `main`. |
+| [cli.d](https://github.com/dlang/dmd/blob/master/src/dmd/cli.d) | Define the command line interface |
+| [globals.d](https://github.com/dlang/dmd/blob/master/src/dmd/globals.d) | Define a structure storing command line options |
+| [dinifile.d](https://github.com/dlang/dmd/blob/master/src/dmd/dinifile.d) | Parse settings from .ini file (`sc.ini` / `dmd.conf`) |
+| [vsoptions.d](https://github.com/dlang/dmd/blob/master/src/dmd/vsoptions.d) | Detect the Microsoft Visual Studio toolchain for linking |
+| [frontend.d](https://github.com/dlang/dmd/blob/master/src/dmd/frontend.d) | An interface for using DMD as a library |
+| [errors.d](https://github.com/dlang/dmd/blob/master/src/dmd/errors.d) | Error reporting functionality |
+| [target.d](https://github.com/dlang/dmd/blob/master/src/dmd/target.d) | Manage target-specific parameters for cross-compiling (for LDC/GDC) |
+| [compiler.d](https://github.com/dlang/dmd/blob/master/src/dmd/compiler.d) | Describe a back-end compiler and implements compiler-specific actions |
+
+### Lexing / parsing
+
+| File | Purpose |
+|-----------------------------------------------------------------------|----------------------------------------------------------------------|
+| [lexer.d](https://github.com/dlang/dmd/blob/master/src/dmd/lexer.d) | Convert source code into tokens for the D and ImportC parsers |
+| [entity.d](https://github.com/dlang/dmd/blob/master/src/dmd/entity.d) | Define "\\&Entity;" escape sequence for strings / character literals |
+| [tokens.d](https://github.com/dlang/dmd/blob/master/src/dmd/tokens.d) | Define lexical tokens. |
+| [parse.d](https://github.com/dlang/dmd/blob/master/src/dmd/parse.d) | D parser, converting tokens into an Abstract Syntax Tree (AST) |
+| [cparse.d](https://github.com/dlang/dmd/blob/master/src/dmd/cparse.d) | ImportC parser, converting tokens into an Abstract Syntax Tree (AST) |
+
+### Semantic analysis
+
+**Symbols and declarations**
+
+| File | Purpose |
+|---------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|
+| [dsymbol.d](https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d) | Base class for a D symbol, e.g. a variable, function, module, enum etc. |
+| [identifier.d](https://github.com/dlang/dmd/blob/master/src/dmd/identifier.d) | Represents the name of a `Dsymbol` |
+| [id.d](https://github.com/dlang/dmd/blob/master/src/dmd/id.d) | Define strings for pre-defined identifiers (e.g. `sizeof`, `string`) |
+| [dscope.d](https://github.com/dlang/dmd/blob/master/src/dmd/dscope.d) | Define a 'scope' on which symbol lookup can be performed |
+| [dtemplate.d](https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d) | A template declaration or instance |
+| [dmodule.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmodule.d) | Define a package and module |
+| [mtype.d](https://github.com/dlang/dmd/blob/master/src/dmd/mtype.d) | Define expression types such as `int`, `char[]`, `void function()` |
+| [arraytypes.d](https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.d) | For certain Declaration nodes of type `T`, provides aliases for `Array!T` |
+| [declaration.d](https://github.com/dlang/dmd/blob/master/src/dmd/declaration.d) | Misc. declarations of `alias`, variables, type tuples, `ClassInfo` etc. |
+| [denum.d](https://github.com/dlang/dmd/blob/master/src/dmd/denum.d) | Defines `enum` declarations and enum members |
+| [attrib.d](https://github.com/dlang/dmd/blob/master/src/dmd/nogc.d) | Declarations of 'attributes' such as `private`, `pragma()`, `immutable`, `@UDA`, `align`, `extern(C++)` and more |
+| [func.d](https://github.com/dlang/dmd/blob/master/src/dmd/func.d) | Define a function declaration (includes function literals, `invariant`, `unittest`) |
+| [dversion.d](https://github.com/dlang/dmd/blob/master/src/dmd/dversion.d) | Defines a version symbol, e.g. `version = ident`, `debug = ident` |
+
+**AST nodes**
+
+| File | Purpose |
+|-----------------------------------------------------------------------------------|-------------------------------------------------------------|
+| [ast_node.d](https://github.com/dlang/dmd/blob/master/src/dmd/ast_node.d) | Define an abstract AST node class |
+| [astbase.d](https://github.com/dlang/dmd/blob/master/src/dmd/astbase.d) | Namespace of AST nodes that can be produced by the parser |
+| [astcodegen.d](https://github.com/dlang/dmd/blob/master/src/dmd/astcodegen.d) | Namespace of AST nodes of a AST ready for code generation |
+| [astenums.d](https://github.com/dlang/dmd/blob/master/src/dmd/astenums.d) | Enums common to DMD and AST |
+| [expression.d](https://github.com/dlang/dmd/blob/master/src/dmd/expression.d) | Define expression AST nodes |
+| [statement.d](https://github.com/dlang/dmd/blob/master/src/dmd/statement.d) | Define statement AST nodes |
+| [staticassert.d](https://github.com/dlang/dmd/blob/master/src/dmd/staticassert.d) | Define a `static assert` AST node |
+| [aggregate.d](https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d) | Define an aggregate (`struct`, `union` or `class`) AST node |
+| [dclass.d](https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d) | Define a `class` AST node |
+| [dstruct.d](https://github.com/dlang/dmd/blob/master/src/dmd/dstruct.d) | Define a `struct` or `union` AST node |
+| [init.d](https://github.com/dlang/dmd/blob/master/src/dmd/init.d) | Define variable initializers |
+
+**AST visitors**
+
+| File | Purpose |
+|-----------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
+| [parsetimevisitor.d](https://github.com/dlang/dmd/blob/master/src/dmd/parsetimevisitor.d) | General [visitor](https://en.wikipedia.org/wiki/Visitor_pattern) for AST nodes |
+| [permissivevisitor.d](https://github.com/dlang/dmd/blob/master/src/dmd/permissivevisitor.d) | Subclass of ParseTimeVisitor that does not `assert(0)` on unimplemented nodes |
+| [strictvisitor.d](https://github.com/dlang/dmd/blob/master/src/dmd/strictvisitor.d) | Visitor that forces derived classes to implement `visit` for every possible node |
+| [visitor.d](https://github.com/dlang/dmd/blob/master/src/dmd/visitor.d) | A visitor implementing `visit` for all nodes present in the compiler |
+| [transitivevisitor.d](https://github.com/dlang/dmd/blob/master/src/dmd/transitivevisitor.d) | Provide a mixin template with visit methods for the parse time AST |
+| [apply.d](https://github.com/dlang/dmd/blob/master/src/dmd/apply.d) | Depth-first expression visitor |
+| [sapply.d](https://github.com/dlang/dmd/blob/master/src/dmd/sapply.d) | Depth-first statement visitor |
+| [statement_rewrite_walker.d](https://github.com/dlang/dmd/blob/master/src/dmd/statement_rewrite_walker.d) | Statement visitor that allows replacing the currently visited node |
+
+**Semantic passes**
+
+| File | Purpose |
+|-------------------------------------------------------------------------------------------|-------------------------------------------------------------------|
+| [dsymbolsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d) | Do semantic 1 pass (symbol identifiers/types) |
+| [semantic2.d](https://github.com/dlang/dmd/blob/master/src/dmd/semantic2.d) | Do semantic 2 pass (symbol initializers) |
+| [semantic3.d](https://github.com/dlang/dmd/blob/master/src/dmd/semantic3.d) | Do semantic 3 pass (function bodies) |
+| [inline.d](https://github.com/dlang/dmd/blob/master/src/dmd/inline.d) | Do inline pass (optimization pass that dmd does in the front-end) |
+| [inlinecost.d](https://github.com/dlang/dmd/blob/master/src/dmd/inlinecost.d) | Compute the cost of inlining a function call. |
+| [expressionsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d) | Do semantic analysis for expressions |
+| [statementsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/statementsem.d) | Do semantic analysis for statements |
+| [initsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/initsem.d) | Do semantic analysis for initializers |
+| [templateparamsem.d](https://github.com/dlang/dmd/blob/master/src/dmd/templateparamsem.d) | Do semantic analysis for template parameters |
+| [typesem.d](https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d) | Do semantic analysis for types |
+
+**Semantic helpers**
+
+| File | Purpose |
+|-------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
+| [opover.d](https://github.com/dlang/dmd/blob/master/src/dmd/opover.d) | Operator overloading |
+| [clone.d](https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d) | Generate automatic `opEquals`, `opAssign` and constructors for structs |
+| [blockexit.d](https://github.com/dlang/dmd/blob/master/src/dmd/blockexit.d) | Find out in what ways control flow can exit a block |
+| [ctorflow.d](https://github.com/dlang/dmd/blob/master/src/dmd/ctorflow.d) | Control flow in constructors |
+| [constfold.d](https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d) | Do constant folding of arithmetic expressions |
+| [optimize.d](https://github.com/dlang/dmd/blob/master/src/dmd/optimize.d) | Do constant folding more generally |
+| [dcast.d](https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d) | Implicit or explicit cast(), finding common types e.g. in `x ? a : b`, integral promotions |
+| [impcnvtab.d](https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d) | Define an implicit conversion table for basic types |
+| [sideeffect.d](https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d) | Extract side-effects of expressions for certain lowerings. |
+
+**Compile Time Function Execution (CTFE)**
+
+| File | Purpose |
+|-------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
+| [dinterpret.d](https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d) | CTFE entry point |
+| [ctfeexpr.d](https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d) | CTFE for expressions involving pointers, slices, array concatenation etc. |
+| [builtin.d](https://github.com/dlang/dmd/blob/master/src/dmd/builtin.d) | Allow CTFE of certain external functions (`core.math`, `std.math` and `core.bitop`) |
+
+### Specific language features
+
+**Attribute checks**
+
+| File | Purpose |
+|---------------------------------------------------------------------------|----------------------------------------|
+| [nogc.d](https://github.com/dlang/dmd/blob/master/src/dmd/nogc.d) | `@nogc` checks |
+| [safe.d](https://github.com/dlang/dmd/blob/master/src/dmd/safe.d) | `@safe` checks |
+| [canthrow.d](https://github.com/dlang/dmd/blob/master/src/dmd/canthrow.d) | `nothrow` checks |
+| [escape.d](https://github.com/dlang/dmd/blob/master/src/dmd/escape.d) | `scope` checks |
+| [access.d](https://github.com/dlang/dmd/blob/master/src/dmd/access.d) | `public` / `private` checks |
+| [ob.d](https://github.com/dlang/dmd/blob/master/src/dmd/ob.d) | Ownership / borrowing (`@live`) checks |
+
+**Inline Assembly**
+
+| File | Purpose |
+|-------------------------------------------------------------------------|-------------------------------------------|
+| [iasm.d](https://github.com/dlang/dmd/blob/master/src/dmd/iasm.d) | Inline assembly depending on the compiler |
+| [iasmdmd.d](https://github.com/dlang/dmd/blob/master/src/dmd/iasmdmd.d) | Inline assembly for DMD |
+| [iasmgcc.d](https://github.com/dlang/dmd/blob/master/src/dmd/iasmgcc.d) | Inline assembly for GDC |
+
+**Other**
+
+| File | Purpose |
+|-------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
+| [aliasthis.d](https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d) | Resolve implicit conversions for `alias X this` |
+| [traits.d](https://github.com/dlang/dmd/blob/master/src/dmd/traits.d) | `__traits()` |
+| [lambdacomp.d](https://github.com/dlang/dmd/blob/master/src/dmd/lambdacomp.d) | `__traits(isSame, x => y, z => w)` |
+| [cond.d](https://github.com/dlang/dmd/blob/master/src/dmd/cond.d) | Evaluate `static if`, `version` `debug ` |
+| [staticcond.d](https://github.com/dlang/dmd/blob/master/src/dmd/staticcond.d) | Lazily evaluate static conditions for `static if`, `static assert` and template constraints |
+| [delegatize.d](https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d) | Converts expression to delegates for `lazy` parameters |
+| [eh.d](https://github.com/dlang/dmd/blob/master/src/dmd/eh.d) | Generate tables for exception handling |
+| [nspace.d](https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d) | Namespace for `extern (C++, Module)` |
+| [intrange.d](https://github.com/dlang/dmd/blob/master/src/dmd/intrange.d) | [Value range propagation](https://digitalmars.com/articles/b62.html) |
+| [dimport.d](https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d) | Renamed imports (`import aliasSymbol = pkg1.pkg2.symbol`) |
+| [arrayop.d](https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d) | Array operations (`a[] = b[] + c[]`) |
+| [typinf.d](https://github.com/dlang/dmd/blob/master/src/dmd/typinf.d) | Generate typeinfo for `typeid()` (as well as internals) |
+
+| File | Purpose |
+|-----------------------------------------------------------------------------|------------------------------------------------------------------------------------|
+| [chkformat.d](https://github.com/dlang/dmd/blob/master/src/dmd/chkformat.d) | Validate arguments with format specifiers for `printf` / `scanf` etc. |
+| [imphint.d](https://github.com/dlang/dmd/blob/master/src/dmd/imphint.d) | Give a suggestion to e.g. `import std.stdio` when `writeln` could not be resolved. |
+
+### Library files
+
+| File | Purpose |
+|-------------------------------------------------------------------------------|------------------------------------------------------|
+| [lib.d](https://github.com/dlang/dmd/blob/master/src/dmd/lib.d) | Abstract library class |
+| [libelf.d](https://github.com/dlang/dmd/blob/master/src/dmd/libelf.d) | Library in ELF format (Unix) |
+| [libmach.d](https://github.com/dlang/dmd/blob/master/src/dmd/libmach.d) | Library in Mach-O format (macOS) |
+| [libmscoff.d](https://github.com/dlang/dmd/blob/master/src/dmd/libmscoff.d) | Library in COFF format (32/64-bit Windows) |
+| [libomf.d](https://github.com/dlang/dmd/blob/master/src/dmd/libomf.d) | Library in OMF format (legacy 32-bit Windows) |
+| [scanelf.d](https://github.com/dlang/dmd/blob/master/src/dmd/scanelf.d) | Extract symbol names from a library in ELF format |
+| [scanmach.d](https://github.com/dlang/dmd/blob/master/src/dmd/scanmach.d) | Extract symbol names from a library in Mach-O format |
+| [scanmscoff.d](https://github.com/dlang/dmd/blob/master/src/dmd/scanmscoff.d) | Extract symbol names from a library in COFF format |
+| [scanomf.d](https://github.com/dlang/dmd/blob/master/src/dmd/scanomf.d) | Extract symbol names from a library in OMF format |
+
+### Code generation / back-end interfacing
+
+| File | Purpose |
+|---------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
+| [dmsc.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmsc.d) | Configures and initializes the back-end |
+| [toobj.d](https://github.com/dlang/dmd/blob/master/src/dmd/toobj.d) | Convert an AST that went through all semantic phases into an object file |
+| [toir.d](https://github.com/dlang/dmd/blob/master/src/dmd/toir.d) | Convert Dsymbols intermediate representation |
+| [e2ir.d](https://github.com/dlang/dmd/blob/master/src/dmd/e2ir.d) | Convert Expressions to intermediate representation |
+| [s2ir.d](https://github.com/dlang/dmd/blob/master/src/dmd/s2ir.d) | Convert Statements to intermediate representation |
+| [stmtstate.d](https://github.com/dlang/dmd/blob/master/src/dmd/stmtstate.d) | Used to help transform statement AST into flow graph |
+| [toctype.d](https://github.com/dlang/dmd/blob/master/src/dmd/toctype.d) | Convert a D type to a type the back-end understands |
+| [tocsym.d](https://github.com/dlang/dmd/blob/master/src/dmd/tocsym.d) | Convert a D symbol to a symbol the linker understands (with mangled name) |
+| [argtypes_x86.d](https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_x86.d) | Convert a D type into simple (register) types for the 32-bit x86 ABI |
+| [argtypes_sysv_x64.d](https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_sysv_x64.d) | 'argtypes' for the x86_64 System V ABI |
+| [argtypes_aarch64.d](https://github.com/dlang/dmd/blob/master/src/dmd/argtypes_aarch64.d) | 'argtypes' for the AArch64 ABI |
+| [glue.d](https://github.com/dlang/dmd/blob/master/src/dmd/glue.d) | Generate the object file for function declarations |
+| [gluelayer.d](https://github.com/dlang/dmd/blob/master/src/dmd/gluelayer.d) | Declarations for back-end functions that the front-end invokes |
+| [todt.d](https://github.com/dlang/dmd/blob/master/src/dmd/todt.d) | Convert initializers into structures that the back-end will add to the data segment |
+| [tocvdebug.d](https://github.com/dlang/dmd/blob/master/src/dmd/tovcdebug.d) | Generate debug info in the CV4 debug format. |
+| [objc.d](https://github.com/dlang/dmd/blob/master/src/dmd/objc.d) | Objective-C interfacing |
+| [objc_glue.d](https://github.com/dlang/dmd/blob/master/src/dmd/objc_glue.d) | Glue code for Objective-C interop. |
+
+**Name mangling**
+
+| File | Purpose |
+|-----------------------------------------------------------------------------------|------------------------------------------------------------------|
+| [cppmangle.d](https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d) | C++ name mangling |
+| [cppmanglewin.d](https://github.com/dlang/dmd/blob/master/src/dmd/cppmanglewin.d) | C++ name mangling for Windows |
+| [dmangle.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d) | D [name mangling](https://dlang.org/spec/abi.html#name_mangling) |
+
+### Linking
+
+| File | Purpose |
+|-------------------------------------------------------------------|-----------------------------------------|
+| [link.d](https://github.com/dlang/dmd/blob/master/src/dmd/link.d) | Invoke the linker as a separate process |
+
+### Special output
+
+| File | Purpose |
+|-----------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
+| [doc.d](https://github.com/dlang/dmd/blob/master/src/dmd/doc.d) | [Documentation generation](https://dlang.org/spec/ddoc.html) |
+| [dmacro.d](https://github.com/dlang/dmd/blob/master/src/dmd/dmacro.d) | DDoc macro processing |
+| [hdrgen.d](https://github.com/dlang/dmd/blob/master/src/dmd/hdrgen.d) | Convert an AST into D source code for `.di` header generation, as well as `-vcg-ast` and error messages |
+| [json.d](https://github.com/dlang/dmd/blob/master/src/dmd/json.d) | Describe the module in a `.json` file for the `-X` flag |
+| [dtoh.d](https://github.com/dlang/dmd/blob/master/src/dmd/dtoh.d) | C++ header generation from D source files |
+
+### Utility
+
+Note: many other utilities are in [dmd/root](https://github.com/dlang/dmd/tree/master/src/dmd/root).
+
+| File | Purpose |
+|-----------------------------------------------------------------------------|---------------------------------------------------|
+| [env.d](https://github.com/dlang/dmd/blob/master/src/dmd/env.d) | Modify environment variables |
+| [console.d](https://github.com/dlang/dmd/blob/master/src/dmd/console.d) | Print error messages in color |
+| [utf.d](https://github.com/dlang/dmd/blob/master/src/dmd/utf.d) | Encoding/decoding Unicode text |
+| [filecache.d](https://github.com/dlang/dmd/blob/master/src/dmd/filecache.d) | Keep file contents in memory |
+| [utils.d](https://github.com/dlang/dmd/blob/master/src/dmd/utils.d) | Utility functions related to files and file paths |
+| [complex.d](https://github.com/dlang/dmd/blob/master/src/dmd/complex.d) | A complex number type |
+
+| File | Purpose |
+|---------------------------------------------------------------------------------|---------------------------------------------------------------|
+| [asttypename.d](https://github.com/dlang/dmd/blob/master/src/dmd/asttypename.d) | Print the internal name of an AST node (for debugging only) |
+| [printast.d](https://github.com/dlang/dmd/blob/master/src/dmd/printast.d) | Print the AST data structure |
+| [foreachvar.d](https://github.com/dlang/dmd/blob/master/src/dmd/foreachvar.d) | Used in `ob.d` to iterate over all variables in an expression |
diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION
new file mode 100644
index 0000000..64ce79a
--- /dev/null
+++ b/gcc/d/dmd/VERSION
@@ -0,0 +1 @@
+v2.097.2
diff --git a/gcc/d/dmd/access.c b/gcc/d/dmd/access.c
deleted file mode 100644
index 11b26c5..0000000
--- a/gcc/d/dmd/access.c
+++ /dev/null
@@ -1,560 +0,0 @@
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/access.c
- */
-
-#include "root/dsystem.h"
-#include "root/root.h"
-#include "root/rmem.h"
-
-#include "errors.h"
-#include "enum.h"
-#include "aggregate.h"
-#include "init.h"
-#include "attrib.h"
-#include "scope.h"
-#include "id.h"
-#include "mtype.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "expression.h"
-#include "module.h"
-#include "template.h"
-
-/* Code to do access checks
- */
-
-bool hasPackageAccess(Scope *sc, Dsymbol *s);
-bool hasPackageAccess(Module *mod, Dsymbol *s);
-bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember);
-bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd);
-static Dsymbol *mostVisibleOverload(Dsymbol *s);
-
-/****************************************
- * Return Prot access for Dsymbol smember in this declaration.
- */
-Prot getAccess(AggregateDeclaration *ad, Dsymbol *smember)
-{
- Prot access_ret = Prot(Prot::none);
-
- assert(ad->isStructDeclaration() || ad->isClassDeclaration());
- if (smember->toParent() == ad)
- {
- access_ret = smember->prot();
- }
- else if (smember->isDeclaration()->isStatic())
- {
- access_ret = smember->prot();
- }
- if (ClassDeclaration *cd = ad->isClassDeclaration())
- {
- for (size_t i = 0; i < cd->baseclasses->length; i++)
- {
- BaseClass *b = (*cd->baseclasses)[i];
-
- Prot access = getAccess(b->sym, smember);
- switch (access.kind)
- {
- case Prot::none:
- break;
-
- case Prot::private_:
- access_ret = Prot(Prot::none); // private members of base class not accessible
- break;
-
- case Prot::package_:
- case Prot::protected_:
- case Prot::public_:
- case Prot::export_:
- // If access is to be tightened
- if (Prot::public_ < access.kind)
- access = Prot(Prot::public_);
-
- // Pick path with loosest access
- if (access_ret.isMoreRestrictiveThan(access))
- access_ret = access;
- break;
-
- default:
- assert(0);
- }
- }
- }
-
- return access_ret;
-}
-
-/********************************************************
- * Helper function for checkAccess()
- * Returns:
- * false is not accessible
- * true is accessible
- */
-static bool isAccessible(
- Dsymbol *smember,
- Dsymbol *sfunc,
- AggregateDeclaration *dthis,
- AggregateDeclaration *cdscope)
-{
- assert(dthis);
-
- if (hasPrivateAccess(dthis, sfunc) ||
- isFriendOf(dthis, cdscope))
- {
- if (smember->toParent() == dthis)
- return true;
-
- if (ClassDeclaration *cdthis = dthis->isClassDeclaration())
- {
- for (size_t i = 0; i < cdthis->baseclasses->length; i++)
- {
- BaseClass *b = (*cdthis->baseclasses)[i];
- Prot access = getAccess(b->sym, smember);
- if (access.kind >= Prot::protected_ ||
- isAccessible(smember, sfunc, b->sym, cdscope))
- {
- return true;
- }
- }
- }
- }
- else
- {
- if (smember->toParent() != dthis)
- {
- if (ClassDeclaration *cdthis = dthis->isClassDeclaration())
- {
- for (size_t i = 0; i < cdthis->baseclasses->length; i++)
- {
- BaseClass *b = (*cdthis->baseclasses)[i];
- if (isAccessible(smember, sfunc, b->sym, cdscope))
- return true;
- }
- }
- }
- }
- return false;
-}
-
-/*******************************
- * Do access check for member of this class, this class being the
- * type of the 'this' pointer used to access smember.
- * Returns true if the member is not accessible.
- */
-bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember)
-{
- FuncDeclaration *f = sc->func;
- AggregateDeclaration *cdscope = sc->getStructClassScope();
-
- Dsymbol *smemberparent = smember->toParent();
- if (!smemberparent || !smemberparent->isAggregateDeclaration())
- {
- return false; // then it is accessible
- }
-
- // BUG: should enable this check
- //assert(smember->parent->isBaseOf(this, NULL));
-
- bool result;
- Prot access;
- if (smemberparent == ad)
- {
- access = smember->prot();
- result = access.kind >= Prot::public_ ||
- hasPrivateAccess(ad, f) ||
- isFriendOf(ad, cdscope) ||
- (access.kind == Prot::package_ && hasPackageAccess(sc, smember)) ||
- ad->getAccessModule() == sc->_module;
- }
- else if ((access = getAccess(ad, smember)).kind >= Prot::public_)
- {
- result = true;
- }
- else if (access.kind == Prot::package_ && hasPackageAccess(sc, ad))
- {
- result = true;
- }
- else
- {
- result = isAccessible(smember, f, ad, cdscope);
- }
- if (!result)
- {
- ad->error(loc, "member %s is not accessible", smember->toChars());
- //printf("smember = %s %s, prot = %d, semanticRun = %d\n",
- // smember->kind(), smember->toPrettyChars(), smember->prot(), smember->semanticRun);
- return true;
- }
- return false;
-}
-
-/****************************************
- * Determine if this is the same or friend of cd.
- */
-bool isFriendOf(AggregateDeclaration *ad, AggregateDeclaration *cd)
-{
- if (ad == cd)
- return true;
-
- // Friends if both are in the same module
- //if (toParent() == cd->toParent())
- if (cd && ad->getAccessModule() == cd->getAccessModule())
- {
- return true;
- }
-
- return false;
-}
-
-/****************************************
- * Determine if scope sc has package level access to s.
- */
-bool hasPackageAccess(Scope *sc, Dsymbol *s)
-{
- return hasPackageAccess(sc->_module, s);
-}
-
-bool hasPackageAccess(Module *mod, Dsymbol *s)
-{
- Package *pkg = NULL;
-
- if (s->prot().pkg)
- pkg = s->prot().pkg;
- else
- {
- // no explicit package for protection, inferring most qualified one
- for (; s; s = s->parent)
- {
- if (Module *m = s->isModule())
- {
- DsymbolTable *dst = Package::resolve(m->md ? m->md->packages : NULL, NULL, NULL);
- assert(dst);
- Dsymbol *s2 = dst->lookup(m->ident);
- assert(s2);
- Package *p = s2->isPackage();
- if (p && p->isPackageMod())
- {
- pkg = p;
- break;
- }
- }
- else if ((pkg = s->isPackage()) != NULL)
- break;
- }
- }
-
- if (pkg)
- {
- if (pkg == mod->parent)
- {
- return true;
- }
- if (pkg->isPackageMod() == mod)
- {
- return true;
- }
- Dsymbol* ancestor = mod->parent;
- for (; ancestor; ancestor = ancestor->parent)
- {
- if (ancestor == pkg)
- {
- return true;
- }
- }
- }
-
- return false;
-}
-
-/****************************************
- * Determine if scope sc has protected level access to cd.
- */
-bool hasProtectedAccess(Scope *sc, Dsymbol *s)
-{
- if (ClassDeclaration *cd = s->isClassMember()) // also includes interfaces
- {
- for (Scope *scx = sc; scx; scx = scx->enclosing)
- {
- if (!scx->scopesym)
- continue;
- ClassDeclaration *cd2 = scx->scopesym->isClassDeclaration();
- if (cd2 && cd->isBaseOf(cd2, NULL))
- return true;
- }
- }
- return sc->_module == s->getAccessModule();
-}
-
-/**********************************
- * Determine if smember has access to private members of this declaration.
- */
-bool hasPrivateAccess(AggregateDeclaration *ad, Dsymbol *smember)
-{
- if (smember)
- {
- AggregateDeclaration *cd = NULL;
- Dsymbol *smemberparent = smember->toParent();
- if (smemberparent)
- cd = smemberparent->isAggregateDeclaration();
-
- if (ad == cd) // smember is a member of this class
- {
- return true; // so we get private access
- }
-
- // If both are members of the same module, grant access
- while (1)
- {
- Dsymbol *sp = smember->toParent();
- if (sp->isFuncDeclaration() && smember->isFuncDeclaration())
- smember = sp;
- else
- break;
- }
- if (!cd && ad->toParent() == smember->toParent())
- {
- return true;
- }
- if (!cd && ad->getAccessModule() == smember->getAccessModule())
- {
- return true;
- }
- }
- return false;
-}
-
-/****************************************
- * Check access to d for expression e.d
- * Returns true if the declaration is not accessible.
- */
-bool checkAccess(Loc loc, Scope *sc, Expression *e, Declaration *d)
-{
- if (sc->flags & SCOPEnoaccesscheck)
- return false;
-
- if (d->isUnitTestDeclaration())
- {
- // Unittests are always accessible.
- return false;
- }
- if (!e)
- return false;
-
- if (e->type->ty == Tclass)
- {
- // Do access check
- ClassDeclaration *cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym);
- if (e->op == TOKsuper)
- {
- ClassDeclaration *cd2 = sc->func->toParent()->isClassDeclaration();
- if (cd2)
- cd = cd2;
- }
- return checkAccess(cd, loc, sc, d);
- }
- else if (e->type->ty == Tstruct)
- {
- // Do access check
- StructDeclaration *cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym);
- return checkAccess(cd, loc, sc, d);
- }
- return false;
-}
-
-/****************************************
- * Check access to package/module `p` from scope `sc`.
- *
- * Params:
- * loc = source location for issued error message
- * sc = scope from which to access to a fully qualified package name
- * p = the package/module to check access for
- * Returns: true if the package is not accessible.
- *
- * Because a global symbol table tree is used for imported packages/modules,
- * access to them needs to be checked based on the imports in the scope chain
- * (see Bugzilla 313).
- *
- */
-bool checkAccess(Scope *sc, Package *p)
-{
- if (sc->_module == p)
- return false;
- for (; sc; sc = sc->enclosing)
- {
- if (sc->scopesym && sc->scopesym->isPackageAccessible(p, Prot(Prot::private_)))
- return false;
- }
-
- return true;
-}
-
-/**
- * Check whether symbols `s` is visible in `mod`.
- *
- * Params:
- * mod = lookup origin
- * s = symbol to check for visibility
- * Returns: true if s is visible in mod
- */
-bool symbolIsVisible(Module *mod, Dsymbol *s)
-{
- // should sort overloads by ascending protection instead of iterating here
- s = mostVisibleOverload(s);
-
- switch (s->prot().kind)
- {
- case Prot::undefined:
- return true;
- case Prot::none:
- return false; // no access
- case Prot::private_:
- return s->getAccessModule() == mod;
- case Prot::package_:
- return s->getAccessModule() == mod || hasPackageAccess(mod, s);
- case Prot::protected_:
- return s->getAccessModule() == mod;
- case Prot::public_:
- case Prot::export_:
- return true;
- default:
- assert(0);
- }
- return false;
-}
-
-/**
- * Same as above, but determines the lookup module from symbols `origin`.
- */
-bool symbolIsVisible(Dsymbol *origin, Dsymbol *s)
-{
- return symbolIsVisible(origin->getAccessModule(), s);
-}
-
-/**
- * Same as above but also checks for protected symbols visible from scope `sc`.
- * Used for qualified name lookup.
- *
- * Params:
- * sc = lookup scope
- * s = symbol to check for visibility
- * Returns: true if s is visible by origin
- */
-bool symbolIsVisible(Scope *sc, Dsymbol *s)
-{
- s = mostVisibleOverload(s);
-
- switch (s->prot().kind)
- {
- case Prot::undefined:
- return true;
- case Prot::none:
- return false; // no access
- case Prot::private_:
- return sc->_module == s->getAccessModule();
- case Prot::package_:
- return sc->_module == s->getAccessModule() || hasPackageAccess(sc->_module, s);
- case Prot::protected_:
- return hasProtectedAccess(sc, s);
- case Prot::public_:
- case Prot::export_:
- return true;
- default:
- assert(0);
- }
- return false;
-}
-
-/**
- * Use the most visible overload to check visibility. Later perform an access
- * check on the resolved overload. This function is similar to overloadApply,
- * but doesn't recurse nor resolve aliases because protection/visibility is an
- * attribute of the alias not the aliasee.
- */
-static Dsymbol *mostVisibleOverload(Dsymbol *s)
-{
- if (!s->isOverloadable())
- return s;
-
- Dsymbol *next = NULL;
- Dsymbol *fstart = s;
- Dsymbol *mostVisible = s;
- for (; s; s = next)
- {
- // void func() {}
- // private void func(int) {}
- if (FuncDeclaration *fd = s->isFuncDeclaration())
- next = fd->overnext;
- // template temp(T) {}
- // private template temp(T:int) {}
- else if (TemplateDeclaration *td = s->isTemplateDeclaration())
- next = td->overnext;
- // alias common = mod1.func1;
- // alias common = mod2.func2;
- else if (FuncAliasDeclaration *fa = s->isFuncAliasDeclaration())
- next = fa->overnext;
- // alias common = mod1.templ1;
- // alias common = mod2.templ2;
- else if (OverDeclaration *od = s->isOverDeclaration())
- next = od->overnext;
- // alias name = sym;
- // private void name(int) {}
- else if (AliasDeclaration *ad = s->isAliasDeclaration())
- {
- if (!ad->isOverloadable())
- {
- //printf("Non overloadable Aliasee in overload list\n");
- assert(0);
- }
- // Yet unresolved aliases store overloads in overnext.
- if (ad->semanticRun < PASSsemanticdone)
- next = ad->overnext;
- else
- {
- /* This is a bit messy due to the complicated implementation of
- * alias. Aliases aren't overloadable themselves, but if their
- * Aliasee is overloadable they can be converted to an overloadable
- * alias.
- *
- * This is done by replacing the Aliasee w/ FuncAliasDeclaration
- * (for functions) or OverDeclaration (for templates) which are
- * simply overloadable aliases w/ weird names.
- *
- * Usually aliases should not be resolved for visibility checking
- * b/c public aliases to private symbols are public. But for the
- * overloadable alias situation, the Alias (_ad_) has been moved
- * into it's own Aliasee, leaving a shell that we peel away here.
- */
- Dsymbol *aliasee = ad->toAlias();
- if (aliasee->isFuncAliasDeclaration() || aliasee->isOverDeclaration())
- next = aliasee;
- else
- {
- /* A simple alias can be at the end of a function or template overload chain.
- * It can't have further overloads b/c it would have been
- * converted to an overloadable alias.
- */
- if (ad->overnext)
- {
- //printf("Unresolved overload of alias\n");
- assert(0);
- }
- break;
- }
- }
-
- // handled by overloadApply for unknown reason
- assert(next != ad); // should not alias itself
- assert(next != fstart); // should not alias the overload list itself
- }
- else
- break;
-
- if (next && mostVisible->prot().isMoreRestrictiveThan(next->prot()))
- mostVisible = next;
- }
- return mostVisible;
-}
diff --git a/gcc/d/dmd/access.d b/gcc/d/dmd/access.d
new file mode 100644
index 0000000..944c9d3
--- /dev/null
+++ b/gcc/d/dmd/access.d
@@ -0,0 +1,410 @@
+/**
+ * Enforce visibility contrains such as `public` and `private`.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/attribute.html#visibility_attributes, Visibility Attributes)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/access.d, _access.d)
+ * Documentation: https://dlang.org/phobos/dmd_access.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/access.d
+ */
+
+module dmd.access;
+
+import dmd.aggregate;
+import dmd.astenums;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.errors;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.mtype;
+import dmd.tokens;
+
+private enum LOG = false;
+
+
+/*******************************
+ * Do access check for member of this class, this class being the
+ * type of the 'this' pointer used to access smember.
+ * Returns true if the member is not accessible.
+ */
+bool checkAccess(AggregateDeclaration ad, Loc loc, Scope* sc, Dsymbol smember)
+{
+ static if (LOG)
+ {
+ printf("AggregateDeclaration::checkAccess() for %s.%s in function %s() in scope %s\n", ad.toChars(), smember.toChars(), f ? f.toChars() : null, cdscope ? cdscope.toChars() : null);
+ }
+
+ const p = smember.toParent();
+ if (p && p.isTemplateInstance())
+ {
+ return false; // for backward compatibility
+ }
+
+ if (!symbolIsVisible(sc, smember))
+ {
+ // when in @safe code or with -preview=dip1000
+ if (sc.flags & SCOPE.onlysafeaccess)
+ {
+ // if there is a func. ask for it's opinion of safety, and if it considers the access @safe accept it.
+ if (sc.func && !sc.func.setUnsafe())
+ return false;
+ }
+
+ ad.error(loc, "%s `%s` is not accessible%s", smember.kind(), smember.toChars(), (sc.flags & SCOPE.onlysafeaccess) ? " from `@safe` code".ptr : "".ptr);
+ //printf("smember = %s %s, vis = %d, semanticRun = %d\n",
+ // smember.kind(), smember.toPrettyChars(), smember.visible() smember.semanticRun);
+ return true;
+ }
+ return false;
+}
+
+/****************************************
+ * Determine if scope sc has package level access to s.
+ */
+private bool hasPackageAccess(Scope* sc, Dsymbol s)
+{
+ return hasPackageAccess(sc._module, s);
+}
+
+private bool hasPackageAccess(Module mod, Dsymbol s)
+{
+ static if (LOG)
+ {
+ printf("hasPackageAccess(s = '%s', mod = '%s', s.visibility.pkg = '%s')\n", s.toChars(), mod.toChars(), s.visible().pkg ? s.visible().pkg.toChars() : "NULL");
+ }
+ Package pkg = null;
+ if (s.visible().pkg)
+ pkg = s.visible().pkg;
+ else
+ {
+ // no explicit package for visibility, inferring most qualified one
+ for (; s; s = s.parent)
+ {
+ if (auto m = s.isModule())
+ {
+ DsymbolTable dst = Package.resolve(m.md ? m.md.packages : null, null, null);
+ assert(dst);
+ Dsymbol s2 = dst.lookup(m.ident);
+ assert(s2);
+ Package p = s2.isPackage();
+ if (p && p.isPackageMod())
+ {
+ pkg = p;
+ break;
+ }
+ }
+ else if ((pkg = s.isPackage()) !is null)
+ break;
+ }
+ }
+ static if (LOG)
+ {
+ if (pkg)
+ printf("\tsymbol access binds to package '%s'\n", pkg.toChars());
+ }
+ if (pkg)
+ {
+ if (pkg == mod.parent)
+ {
+ static if (LOG)
+ {
+ printf("\tsc is in permitted package for s\n");
+ }
+ return true;
+ }
+ if (pkg.isPackageMod() == mod)
+ {
+ static if (LOG)
+ {
+ printf("\ts is in same package.d module as sc\n");
+ }
+ return true;
+ }
+ Dsymbol ancestor = mod.parent;
+ for (; ancestor; ancestor = ancestor.parent)
+ {
+ if (ancestor == pkg)
+ {
+ static if (LOG)
+ {
+ printf("\tsc is in permitted ancestor package for s\n");
+ }
+ return true;
+ }
+ }
+ }
+ static if (LOG)
+ {
+ printf("\tno package access\n");
+ }
+ return false;
+}
+
+/****************************************
+ * Determine if scope sc has protected level access to cd.
+ */
+private bool hasProtectedAccess(Scope *sc, Dsymbol s)
+{
+ if (auto cd = s.isClassMember()) // also includes interfaces
+ {
+ for (auto scx = sc; scx; scx = scx.enclosing)
+ {
+ if (!scx.scopesym)
+ continue;
+ auto cd2 = scx.scopesym.isClassDeclaration();
+ if (cd2 && cd.isBaseOf(cd2, null))
+ return true;
+ }
+ }
+ return sc._module == s.getAccessModule();
+}
+
+/****************************************
+ * Check access to d for expression e.d
+ * Returns true if the declaration is not accessible.
+ */
+bool checkAccess(Loc loc, Scope* sc, Expression e, Dsymbol d)
+{
+ if (sc.flags & SCOPE.noaccesscheck)
+ return false;
+ static if (LOG)
+ {
+ if (e)
+ {
+ printf("checkAccess(%s . %s)\n", e.toChars(), d.toChars());
+ printf("\te.type = %s\n", e.type.toChars());
+ }
+ else
+ {
+ printf("checkAccess(%s)\n", d.toPrettyChars());
+ }
+ }
+ if (d.isUnitTestDeclaration())
+ {
+ // Unittests are always accessible.
+ return false;
+ }
+
+ if (!e)
+ return false;
+
+ if (auto tc = e.type.isTypeClass())
+ {
+ // Do access check
+ ClassDeclaration cd = tc.sym;
+ if (e.op == TOK.super_)
+ {
+ if (ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration())
+ cd = cd2;
+ }
+ return checkAccess(cd, loc, sc, d);
+ }
+ else if (auto ts = e.type.isTypeStruct())
+ {
+ // Do access check
+ StructDeclaration cd = ts.sym;
+ return checkAccess(cd, loc, sc, d);
+ }
+ return false;
+}
+
+/****************************************
+ * Check access to package/module `p` from scope `sc`.
+ *
+ * Params:
+ * sc = scope from which to access to a fully qualified package name
+ * p = the package/module to check access for
+ * Returns: true if the package is not accessible.
+ *
+ * Because a global symbol table tree is used for imported packages/modules,
+ * access to them needs to be checked based on the imports in the scope chain
+ * (see https://issues.dlang.org/show_bug.cgi?id=313).
+ *
+ */
+bool checkAccess(Scope* sc, Package p)
+{
+ if (sc._module == p)
+ return false;
+ for (; sc; sc = sc.enclosing)
+ {
+ if (sc.scopesym && sc.scopesym.isPackageAccessible(p, Visibility(Visibility.Kind.private_)))
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Check whether symbols `s` is visible in `mod`.
+ *
+ * Params:
+ * mod = lookup origin
+ * s = symbol to check for visibility
+ * Returns: true if s is visible in mod
+ */
+bool symbolIsVisible(Module mod, Dsymbol s)
+{
+ // should sort overloads by ascending visibility instead of iterating here
+ s = mostVisibleOverload(s);
+ final switch (s.visible().kind)
+ {
+ case Visibility.Kind.undefined: return true;
+ case Visibility.Kind.none: return false; // no access
+ case Visibility.Kind.private_: return s.getAccessModule() == mod;
+ case Visibility.Kind.package_: return s.getAccessModule() == mod || hasPackageAccess(mod, s);
+ case Visibility.Kind.protected_: return s.getAccessModule() == mod;
+ case Visibility.Kind.public_, Visibility.Kind.export_: return true;
+ }
+}
+
+/**
+ * Same as above, but determines the lookup module from symbols `origin`.
+ */
+bool symbolIsVisible(Dsymbol origin, Dsymbol s)
+{
+ return symbolIsVisible(origin.getAccessModule(), s);
+}
+
+/**
+ * Same as above but also checks for protected symbols visible from scope `sc`.
+ * Used for qualified name lookup.
+ *
+ * Params:
+ * sc = lookup scope
+ * s = symbol to check for visibility
+ * Returns: true if s is visible by origin
+ */
+bool symbolIsVisible(Scope *sc, Dsymbol s)
+{
+ s = mostVisibleOverload(s);
+ return checkSymbolAccess(sc, s);
+}
+
+/**
+ * Check if a symbol is visible from a given scope without taking
+ * into account the most visible overload.
+ *
+ * Params:
+ * sc = lookup scope
+ * s = symbol to check for visibility
+ * Returns: true if s is visible by origin
+ */
+bool checkSymbolAccess(Scope *sc, Dsymbol s)
+{
+ final switch (s.visible().kind)
+ {
+ case Visibility.Kind.undefined: return true;
+ case Visibility.Kind.none: return false; // no access
+ case Visibility.Kind.private_: return sc._module == s.getAccessModule();
+ case Visibility.Kind.package_: return sc._module == s.getAccessModule() || hasPackageAccess(sc._module, s);
+ case Visibility.Kind.protected_: return hasProtectedAccess(sc, s);
+ case Visibility.Kind.public_, Visibility.Kind.export_: return true;
+ }
+}
+
+/**
+ * Use the most visible overload to check visibility. Later perform an access
+ * check on the resolved overload. This function is similar to overloadApply,
+ * but doesn't recurse nor resolve aliases because visibility is an
+ * attribute of the alias not the aliasee.
+ */
+public Dsymbol mostVisibleOverload(Dsymbol s, Module mod = null)
+{
+ if (!s.isOverloadable())
+ return s;
+
+ Dsymbol next, fstart = s, mostVisible = s;
+ for (; s; s = next)
+ {
+ // void func() {}
+ // private void func(int) {}
+ if (auto fd = s.isFuncDeclaration())
+ next = fd.overnext;
+ // template temp(T) {}
+ // private template temp(T:int) {}
+ else if (auto td = s.isTemplateDeclaration())
+ next = td.overnext;
+ // alias common = mod1.func1;
+ // alias common = mod2.func2;
+ else if (auto fa = s.isFuncAliasDeclaration())
+ next = fa.overnext;
+ // alias common = mod1.templ1;
+ // alias common = mod2.templ2;
+ else if (auto od = s.isOverDeclaration())
+ next = od.overnext;
+ // alias name = sym;
+ // private void name(int) {}
+ else if (auto ad = s.isAliasDeclaration())
+ {
+ assert(ad.isOverloadable || ad.type && ad.type.ty == Terror,
+ "Non overloadable Aliasee in overload list");
+ // Yet unresolved aliases store overloads in overnext.
+ if (ad.semanticRun < PASS.semanticdone)
+ next = ad.overnext;
+ else
+ {
+ /* This is a bit messy due to the complicated implementation of
+ * alias. Aliases aren't overloadable themselves, but if their
+ * Aliasee is overloadable they can be converted to an overloadable
+ * alias.
+ *
+ * This is done by replacing the Aliasee w/ FuncAliasDeclaration
+ * (for functions) or OverDeclaration (for templates) which are
+ * simply overloadable aliases w/ weird names.
+ *
+ * Usually aliases should not be resolved for visibility checking
+ * b/c public aliases to private symbols are public. But for the
+ * overloadable alias situation, the Alias (_ad_) has been moved
+ * into its own Aliasee, leaving a shell that we peel away here.
+ */
+ auto aliasee = ad.toAlias();
+ if (aliasee.isFuncAliasDeclaration || aliasee.isOverDeclaration)
+ next = aliasee;
+ else
+ {
+ /* A simple alias can be at the end of a function or template overload chain.
+ * It can't have further overloads b/c it would have been
+ * converted to an overloadable alias.
+ */
+ assert(ad.overnext is null, "Unresolved overload of alias");
+ break;
+ }
+ }
+ // handled by dmd.func.overloadApply for unknown reason
+ assert(next !is ad); // should not alias itself
+ assert(next !is fstart); // should not alias the overload list itself
+ }
+ else
+ break;
+
+ /**
+ * Return the "effective" visibility attribute of a symbol when accessed in a module.
+ * The effective visibility attribute is the same as the regular visibility attribute,
+ * except package() is "private" if the module is outside the package;
+ * otherwise, "public".
+ */
+ static Visibility visibilitySeenFromModule(Dsymbol d, Module mod = null)
+ {
+ Visibility vis = d.visible();
+ if (mod && vis.kind == Visibility.Kind.package_)
+ {
+ return hasPackageAccess(mod, d) ? Visibility(Visibility.Kind.public_) : Visibility(Visibility.Kind.private_);
+ }
+ return vis;
+ }
+
+ if (next &&
+ visibilitySeenFromModule(mostVisible, mod) < visibilitySeenFromModule(next, mod))
+ mostVisible = next;
+ }
+ return mostVisible;
+}
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
new file mode 100644
index 0000000..cff4b9f
--- /dev/null
+++ b/gcc/d/dmd/aggregate.d
@@ -0,0 +1,769 @@
+/**
+ * Defines a `Dsymbol` representing an aggregate, which is a `struct`, `union` or `class`.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions),
+ * $(LINK2 https://dlang.org/spec/class.html, Class).
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d, _aggregate.d)
+ * Documentation: https://dlang.org/phobos/dmd_aggregate.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/aggregate.d
+ */
+
+module dmd.aggregate;
+
+import core.stdc.stdio;
+import core.checkedint;
+
+import dmd.aliasthis;
+import dmd.apply;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.tokens;
+import dmd.typesem : defaultInit;
+import dmd.visitor;
+
+/**
+ * The ClassKind enum is used in AggregateDeclaration AST nodes to
+ * specify the linkage type of the struct/class/interface or if it
+ * is an anonymous class. If the class is anonymous it is also
+ * considered to be a D class.
+ */
+enum ClassKind : ubyte
+{
+ /// the aggregate is a d(efault) class
+ d,
+ /// the aggregate is a C++ struct/class/interface
+ cpp,
+ /// the aggregate is an Objective-C class/interface
+ objc,
+ /// the aggregate is a C struct
+ c,
+}
+
+/**
+ * If an aggregate has a pargma(mangle, ...) this holds the information
+ * to mangle.
+ */
+struct MangleOverride
+{
+ Dsymbol agg; // The symbol to copy template parameters from (if any)
+ Identifier id; // the name to override the aggregate's with, defaults to agg.ident
+}
+
+/***********************************************************
+ * Abstract aggregate as a common ancestor for Class- and StructDeclaration.
+ */
+extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
+{
+ Type type; ///
+ StorageClass storage_class; ///
+ uint structsize; /// size of struct
+ uint alignsize; /// size of struct for alignment purposes
+ VarDeclarations fields; /// VarDeclaration fields
+ Dsymbol deferred; /// any deferred semantic2() or semantic3() symbol
+
+ /// specifies whether this is a D, C++, Objective-C or anonymous struct/class/interface
+ ClassKind classKind;
+ /// Specify whether to mangle the aggregate as a `class` or a `struct`
+ /// This information is used by the MSVC mangler
+ /// Only valid for class and struct. TODO: Merge with ClassKind ?
+ CPPMANGLE cppmangle;
+
+ /// overridden symbol with pragma(mangle, "...") if not null
+ MangleOverride* mangleOverride;
+
+ /**
+ * !=null if is nested
+ * pointing to the dsymbol that directly enclosing it.
+ * 1. The function that enclosing it (nested struct and class)
+ * 2. The class that enclosing it (nested class only)
+ * 3. If enclosing aggregate is template, its enclosing dsymbol.
+ *
+ * See AggregateDeclaraton::makeNested for the details.
+ */
+ Dsymbol enclosing;
+
+ VarDeclaration vthis; /// 'this' parameter if this aggregate is nested
+ VarDeclaration vthis2; /// 'this' parameter if this aggregate is a template and is nested
+
+ // Special member functions
+ FuncDeclarations invs; /// Array of invariants
+ FuncDeclaration inv; /// Merged invariant calling all members of invs
+
+ /// CtorDeclaration or TemplateDeclaration
+ Dsymbol ctor;
+
+ /// default constructor - should have no arguments, because
+ /// it would be stored in TypeInfo_Class.defaultConstructor
+ CtorDeclaration defaultCtor;
+
+ AliasThis aliasthis; /// forward unresolved lookups to aliasthis
+
+ DtorDeclarations dtors; /// Array of destructors
+ DtorDeclaration dtor; /// aggregate destructor calling dtors and member constructors
+ DtorDeclaration primaryDtor;/// non-deleting C++ destructor, same as dtor for D
+ DtorDeclaration tidtor; /// aggregate destructor used in TypeInfo (must have extern(D) ABI)
+ FuncDeclaration fieldDtor; /// aggregate destructor for just the fields
+
+ Expression getRTInfo; /// pointer to GC info generated by object.RTInfo(this)
+
+ ///
+ Visibility visibility;
+ bool noDefaultCtor; /// no default construction
+ bool disableNew; /// disallow allocations using `new`
+ Sizeok sizeok = Sizeok.none; /// set when structsize contains valid data
+
+ final extern (D) this(const ref Loc loc, Identifier id)
+ {
+ super(loc, id);
+ visibility = Visibility(Visibility.Kind.public_);
+ }
+
+ /***************************************
+ * Create a new scope from sc.
+ * semantic, semantic2 and semantic3 will use this for aggregate members.
+ */
+ Scope* newScope(Scope* sc)
+ {
+ auto sc2 = sc.push(this);
+ sc2.stc &= STC.flowThruAggregate;
+ sc2.parent = this;
+ sc2.inunion = isUnionDeclaration();
+ sc2.visibility = Visibility(Visibility.Kind.public_);
+ sc2.explicitVisibility = 0;
+ sc2.aligndecl = null;
+ sc2.userAttribDecl = null;
+ sc2.namespace = null;
+ return sc2;
+ }
+
+ override final void setScope(Scope* sc)
+ {
+ // Might need a scope to resolve forward references. The check for
+ // semanticRun prevents unnecessary setting of _scope during deferred
+ // setScope phases for aggregates which already finished semantic().
+ // See https://issues.dlang.org/show_bug.cgi?id=16607
+ if (semanticRun < PASS.semanticdone)
+ ScopeDsymbol.setScope(sc);
+ }
+
+ /***************************************
+ * Returns:
+ * The total number of fields minus the number of hidden fields.
+ */
+ final size_t nonHiddenFields()
+ {
+ return fields.dim - isNested() - (vthis2 !is null);
+ }
+
+ /***************************************
+ * Collect all instance fields, then determine instance size.
+ * Returns:
+ * false if failed to determine the size.
+ */
+ final bool determineSize(Loc loc)
+ {
+ //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
+
+ // The previous instance size finalizing had:
+ if (type.ty == Terror)
+ return false; // failed already
+ if (sizeok == Sizeok.done)
+ return true; // succeeded
+
+ if (!members)
+ {
+ error(loc, "unknown size");
+ return false;
+ }
+
+ if (_scope)
+ dsymbolSemantic(this, null);
+
+ // Determine the instance size of base class first.
+ if (auto cd = isClassDeclaration())
+ {
+ cd = cd.baseClass;
+ if (cd && !cd.determineSize(loc))
+ goto Lfail;
+ }
+
+ // Determine instance fields when sizeok == Sizeok.none
+ if (!this.determineFields())
+ goto Lfail;
+ if (sizeok != Sizeok.done)
+ finalizeSize();
+
+ // this aggregate type has:
+ if (type.ty == Terror)
+ return false; // marked as invalid during the finalizing.
+ if (sizeok == Sizeok.done)
+ return true; // succeeded to calculate instance size.
+
+ Lfail:
+ // There's unresolvable forward reference.
+ if (type != Type.terror)
+ error(loc, "no size because of forward reference");
+ // Don't cache errors from speculative semantic, might be resolvable later.
+ // https://issues.dlang.org/show_bug.cgi?id=16574
+ if (!global.gag)
+ {
+ type = Type.terror;
+ errors = true;
+ }
+ return false;
+ }
+
+ abstract void finalizeSize();
+
+ override final d_uns64 size(const ref Loc loc)
+ {
+ //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
+ bool ok = determineSize(loc);
+ //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
+ return ok ? structsize : SIZE_INVALID;
+ }
+
+ /***************************************
+ * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
+ * field initializers have unique memory space on instance.
+ * Returns:
+ * true if any errors happen.
+ */
+ extern (D) final bool checkOverlappedFields()
+ {
+ //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
+ assert(sizeok == Sizeok.done);
+ size_t nfields = fields.dim;
+ if (isNested())
+ {
+ auto cd = isClassDeclaration();
+ if (!cd || !cd.baseClass || !cd.baseClass.isNested())
+ nfields--;
+ if (vthis2 && !(cd && cd.baseClass && cd.baseClass.vthis2))
+ nfields--;
+ }
+ bool errors = false;
+
+ // Fill in missing any elements with default initializers
+ foreach (i; 0 .. nfields)
+ {
+ auto vd = fields[i];
+ if (vd.errors)
+ {
+ errors = true;
+ continue;
+ }
+
+ const vdIsVoidInit = vd._init && vd._init.isVoidInitializer();
+
+ // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
+ foreach (j; 0 .. nfields)
+ {
+ if (i == j)
+ continue;
+ auto v2 = fields[j];
+ if (v2.errors)
+ {
+ errors = true;
+ continue;
+ }
+ if (!vd.isOverlappedWith(v2))
+ continue;
+
+ // vd and v2 are overlapping.
+ vd.overlapped = true;
+ v2.overlapped = true;
+
+ if (!MODimplicitConv(vd.type.mod, v2.type.mod))
+ v2.overlapUnsafe = true;
+ if (!MODimplicitConv(v2.type.mod, vd.type.mod))
+ vd.overlapUnsafe = true;
+
+ if (i > j)
+ continue;
+
+ if (!v2._init)
+ continue;
+
+ if (v2._init.isVoidInitializer())
+ continue;
+
+ if (vd._init && !vdIsVoidInit && v2._init)
+ {
+ .error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
+ errors = true;
+ }
+ else if (v2._init && i < j)
+ {
+ .error(v2.loc, "union field `%s` with default initialization `%s` must be before field `%s`",
+ v2.toChars(), v2._init.toChars(), vd.toChars());
+ errors = true;
+ }
+ }
+ }
+ return errors;
+ }
+
+ /***************************************
+ * Fill out remainder of elements[] with default initializers for fields[].
+ * Params:
+ * loc = location
+ * elements = explicit arguments which given to construct object.
+ * ctorinit = true if the elements will be used for default initialization.
+ * Returns:
+ * false if any errors occur.
+ * Otherwise, returns true and the missing arguments will be pushed in elements[].
+ */
+ final bool fill(Loc loc, Expressions* elements, bool ctorinit)
+ {
+ //printf("AggregateDeclaration::fill() %s\n", toChars());
+ assert(sizeok == Sizeok.done);
+ assert(elements);
+ const nfields = nonHiddenFields();
+ bool errors = false;
+
+ size_t dim = elements.dim;
+ elements.setDim(nfields);
+ foreach (size_t i; dim .. nfields)
+ (*elements)[i] = null;
+
+ // Fill in missing any elements with default initializers
+ foreach (i; 0 .. nfields)
+ {
+ if ((*elements)[i])
+ continue;
+
+ auto vd = fields[i];
+ auto vx = vd;
+ if (vd._init && vd._init.isVoidInitializer())
+ vx = null;
+
+ // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
+ size_t fieldi = i;
+ foreach (j; 0 .. nfields)
+ {
+ if (i == j)
+ continue;
+ auto v2 = fields[j];
+ if (!vd.isOverlappedWith(v2))
+ continue;
+
+ if ((*elements)[j])
+ {
+ vx = null;
+ break;
+ }
+ if (v2._init && v2._init.isVoidInitializer())
+ continue;
+
+ version (all)
+ {
+ /* Prefer first found non-void-initialized field
+ * union U { int a; int b = 2; }
+ * U u; // Error: overlapping initialization for field a and b
+ */
+ if (!vx)
+ {
+ vx = v2;
+ fieldi = j;
+ }
+ else if (v2._init)
+ {
+ .error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
+ errors = true;
+ }
+ }
+ else
+ {
+ // fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always
+
+ /* Prefer explicitly initialized field
+ * union U { int a; int b = 2; }
+ * U u; // OK (u.b == 2)
+ */
+ if (!vx || !vx._init && v2._init)
+ {
+ vx = v2;
+ fieldi = j;
+ }
+ else if (vx != vd && !vx.isOverlappedWith(v2))
+ {
+ // Both vx and v2 fills vd, but vx and v2 does not overlap
+ }
+ else if (vx._init && v2._init)
+ {
+ .error(loc, "overlapping default initialization for field `%s` and `%s`",
+ v2.toChars(), vd.toChars());
+ errors = true;
+ }
+ else
+ assert(vx._init || !vx._init && !v2._init);
+ }
+ }
+ if (vx)
+ {
+ Expression e;
+ if (vx.type.size() == 0)
+ {
+ e = null;
+ }
+ else if (vx._init)
+ {
+ assert(!vx._init.isVoidInitializer());
+ if (vx.inuse) // https://issues.dlang.org/show_bug.cgi?id=18057
+ {
+ vx.error(loc, "recursive initialization of field");
+ errors = true;
+ }
+ else
+ e = vx.getConstInitializer(false);
+ }
+ else
+ {
+ if ((vx.storage_class & STC.nodefaultctor) && !ctorinit)
+ {
+ .error(loc, "field `%s.%s` must be initialized because it has no default constructor",
+ type.toChars(), vx.toChars());
+ errors = true;
+ }
+ /* https://issues.dlang.org/show_bug.cgi?id=12509
+ * Get the element of static array type.
+ */
+ Type telem = vx.type;
+ if (telem.ty == Tsarray)
+ {
+ /* We cannot use Type::baseElemOf() here.
+ * If the bottom of the Tsarray is an enum type, baseElemOf()
+ * will return the base of the enum, and its default initializer
+ * would be different from the enum's.
+ */
+ TypeSArray tsa;
+ while ((tsa = telem.toBasetype().isTypeSArray()) !is null)
+ telem = tsa.next;
+ if (telem.ty == Tvoid)
+ telem = Type.tuns8.addMod(telem.mod);
+ }
+ if (telem.needsNested() && ctorinit)
+ e = telem.defaultInit(loc);
+ else
+ e = telem.defaultInitLiteral(loc);
+ }
+ (*elements)[fieldi] = e;
+ }
+ }
+ foreach (e; *elements)
+ {
+ if (e && e.op == TOK.error)
+ return false;
+ }
+
+ return !errors;
+ }
+
+ /****************************
+ * Do byte or word alignment as necessary.
+ * Align sizes of 0, as we may not know array sizes yet.
+ * Params:
+ * alignment = struct alignment that is in effect
+ * size = alignment requirement of field
+ * poffset = pointer to offset to be aligned
+ */
+ extern (D) static void alignmember(structalign_t alignment, uint size, uint* poffset) pure nothrow @safe
+ {
+ //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset);
+ switch (alignment)
+ {
+ case cast(structalign_t)1:
+ // No alignment
+ break;
+
+ case cast(structalign_t)STRUCTALIGN_DEFAULT:
+ // Alignment in Target::fieldalignsize must match what the
+ // corresponding C compiler's default alignment behavior is.
+ assert(size > 0 && !(size & (size - 1)));
+ *poffset = (*poffset + size - 1) & ~(size - 1);
+ break;
+
+ default:
+ // Align on alignment boundary, which must be a positive power of 2
+ assert(alignment > 0 && !(alignment & (alignment - 1)));
+ *poffset = (*poffset + alignment - 1) & ~(alignment - 1);
+ break;
+ }
+ }
+
+ /****************************************
+ * Place a member (mem) into an aggregate (agg), which can be a struct, union or class
+ * Returns:
+ * offset to place field at
+ *
+ * nextoffset: next location in aggregate
+ * memsize: size of member
+ * memalignsize: natural alignment of member
+ * alignment: alignment in effect for this member
+ * paggsize: size of aggregate (updated)
+ * paggalignsize: alignment of aggregate (updated)
+ * isunion: the aggregate is a union
+ */
+ extern (D) static uint placeField(uint* nextoffset, uint memsize, uint memalignsize,
+ structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion)
+ {
+ uint ofs = *nextoffset;
+
+ const uint actualAlignment =
+ alignment == STRUCTALIGN_DEFAULT ? memalignsize : alignment;
+
+ // Ensure no overflow
+ bool overflow;
+ const sz = addu(memsize, actualAlignment, overflow);
+ addu(ofs, sz, overflow);
+ if (overflow) assert(0);
+
+ alignmember(alignment, memalignsize, &ofs);
+ uint memoffset = ofs;
+ ofs += memsize;
+ if (ofs > *paggsize)
+ *paggsize = ofs;
+ if (!isunion)
+ *nextoffset = ofs;
+
+ if (*paggalignsize < actualAlignment)
+ *paggalignsize = actualAlignment;
+
+ return memoffset;
+ }
+
+ override final Type getType()
+ {
+ return type;
+ }
+
+ // is aggregate deprecated?
+ override final bool isDeprecated() const
+ {
+ return !!(this.storage_class & STC.deprecated_);
+ }
+
+ /// Flag this aggregate as deprecated
+ final void setDeprecated()
+ {
+ this.storage_class |= STC.deprecated_;
+ }
+
+ /****************************************
+ * Returns true if there's an extra member which is the 'this'
+ * pointer to the enclosing context (enclosing aggregate or function)
+ */
+ final bool isNested() const
+ {
+ return enclosing !is null;
+ }
+
+ /* Append vthis field (this.tupleof[$-1]) to make this aggregate type nested.
+ */
+ extern (D) final void makeNested()
+ {
+ if (enclosing) // if already nested
+ return;
+ if (sizeok == Sizeok.done)
+ return;
+ if (isUnionDeclaration() || isInterfaceDeclaration())
+ return;
+ if (storage_class & STC.static_)
+ return;
+
+ // If nested struct, add in hidden 'this' pointer to outer scope
+ auto s = toParentLocal();
+ if (!s)
+ s = toParent2();
+ if (!s)
+ return;
+ Type t = null;
+ if (auto fd = s.isFuncDeclaration())
+ {
+ enclosing = fd;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=14422
+ * If a nested class parent is a function, its
+ * context pointer (== `outer`) should be void* always.
+ */
+ t = Type.tvoidptr;
+ }
+ else if (auto ad = s.isAggregateDeclaration())
+ {
+ if (isClassDeclaration() && ad.isClassDeclaration())
+ {
+ enclosing = ad;
+ }
+ else if (isStructDeclaration())
+ {
+ if (auto ti = ad.parent.isTemplateInstance())
+ {
+ enclosing = ti.enclosing;
+ }
+ }
+ t = ad.handleType();
+ }
+ if (enclosing)
+ {
+ //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing.toChars());
+ assert(t);
+ if (t.ty == Tstruct)
+ t = Type.tvoidptr; // t should not be a ref type
+
+ assert(!vthis);
+ vthis = new ThisDeclaration(loc, t);
+ //vthis.storage_class |= STC.ref_;
+
+ // Emulate vthis.addMember()
+ members.push(vthis);
+
+ // Emulate vthis.dsymbolSemantic()
+ vthis.storage_class |= STC.field;
+ vthis.parent = this;
+ vthis.visibility = Visibility(Visibility.Kind.public_);
+ vthis.alignment = t.alignment();
+ vthis.semanticRun = PASS.semanticdone;
+
+ if (sizeok == Sizeok.fwd)
+ fields.push(vthis);
+
+ makeNested2();
+ }
+ }
+
+ /* Append vthis2 field (this.tupleof[$-1]) to add a second context pointer.
+ */
+ extern (D) final void makeNested2()
+ {
+ if (vthis2)
+ return;
+ if (!vthis)
+ makeNested(); // can't add second before first
+ if (!vthis)
+ return;
+ if (sizeok == Sizeok.done)
+ return;
+ if (isUnionDeclaration() || isInterfaceDeclaration())
+ return;
+ if (storage_class & STC.static_)
+ return;
+
+ auto s0 = toParentLocal();
+ auto s = toParent2();
+ if (!s || !s0 || s == s0)
+ return;
+ auto cd = s.isClassDeclaration();
+ Type t = cd ? cd.type : Type.tvoidptr;
+
+ vthis2 = new ThisDeclaration(loc, t);
+ //vthis2.storage_class |= STC.ref_;
+
+ // Emulate vthis2.addMember()
+ members.push(vthis2);
+
+ // Emulate vthis2.dsymbolSemantic()
+ vthis2.storage_class |= STC.field;
+ vthis2.parent = this;
+ vthis2.visibility = Visibility(Visibility.Kind.public_);
+ vthis2.alignment = t.alignment();
+ vthis2.semanticRun = PASS.semanticdone;
+
+ if (sizeok == Sizeok.fwd)
+ fields.push(vthis2);
+ }
+
+ override final bool isExport() const
+ {
+ return visibility.kind == Visibility.Kind.export_;
+ }
+
+ /*******************************************
+ * Look for constructor declaration.
+ */
+ final Dsymbol searchCtor()
+ {
+ auto s = search(Loc.initial, Id.ctor);
+ if (s)
+ {
+ if (!(s.isCtorDeclaration() ||
+ s.isTemplateDeclaration() ||
+ s.isOverloadSet()))
+ {
+ s.error("is not a constructor; identifiers starting with `__` are reserved for the implementation");
+ errors = true;
+ s = null;
+ }
+ }
+ if (s && s.toParent() != this)
+ s = null; // search() looks through ancestor classes
+ if (s)
+ {
+ // Finish all constructors semantics to determine this.noDefaultCtor.
+ struct SearchCtor
+ {
+ extern (C++) static int fp(Dsymbol s, void* ctxt)
+ {
+ auto f = s.isCtorDeclaration();
+ if (f && f.semanticRun == PASS.init)
+ f.dsymbolSemantic(null);
+ return 0;
+ }
+ }
+
+ for (size_t i = 0; i < members.dim; i++)
+ {
+ auto sm = (*members)[i];
+ sm.apply(&SearchCtor.fp, null);
+ }
+ }
+ return s;
+ }
+
+ override final Visibility visible() pure nothrow @nogc @safe
+ {
+ return visibility;
+ }
+
+ // 'this' type
+ final Type handleType()
+ {
+ return type;
+ }
+
+ // Does this class have an invariant function?
+ final bool hasInvariant()
+ {
+ return invs.length != 0;
+ }
+
+ // Back end
+ void* sinit; /// initializer symbol
+
+ override final inout(AggregateDeclaration) isAggregateDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index 4935e6a..f8d2f45 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -10,12 +10,10 @@
#pragma once
-#include "root/root.h"
-
#include "dsymbol.h"
-#include "declaration.h"
#include "objc.h"
+class AliasThis;
class Identifier;
class Type;
class TypeFunction;
@@ -23,65 +21,51 @@ class Expression;
class FuncDeclaration;
class CtorDeclaration;
class DtorDeclaration;
-class InvariantDeclaration;
-class NewDeclaration;
-class DeleteDeclaration;
class InterfaceDeclaration;
class TypeInfoClassDeclaration;
class VarDeclaration;
-enum Sizeok
+enum class Sizeok : uint8_t
{
- SIZEOKnone, // size of aggregate is not yet able to compute
- SIZEOKfwd, // size of aggregate is ready to compute
- SIZEOKdone // size of aggregate is set correctly
+ none, // size of aggregate is not yet able to compute
+ fwd, // size of aggregate is ready to compute
+ inProcess, // in the midst of computing the size
+ done // size of aggregate is set correctly
};
-enum Baseok
+enum class Baseok : uint8_t
{
- BASEOKnone, // base classes not computed yet
- BASEOKin, // in process of resolving base classes
- BASEOKdone, // all base classes are resolved
- BASEOKsemanticdone // all base classes semantic done
+ none, // base classes not computed yet
+ in, // in process of resolving base classes
+ done, // all base classes are resolved
+ semanticdone // all base classes semantic done
};
-enum StructPOD
+enum class ThreeState : uint8_t
{
- ISPODno, // struct is not POD
- ISPODyes, // struct is POD
- ISPODfwd // POD not yet computed
+ none, // value not yet computed
+ no, // value is false
+ yes, // value is true
};
-enum Abstract
+FuncDeclaration *search_toString(StructDeclaration *sd);
+
+enum class ClassKind : uint8_t
{
- ABSfwdref = 0, // whether an abstract class is not yet computed
- ABSyes, // is abstract class
- ABSno // is not abstract class
+ /// the aggregate is a d(efault) struct/class/interface
+ d,
+ /// the aggregate is a C++ struct/class/interface
+ cpp,
+ /// the aggregate is an Objective-C class/interface
+ objc,
+ /// the aggregate is a C struct
+ c,
};
-FuncDeclaration *hasIdentityOpAssign(AggregateDeclaration *ad, Scope *sc);
-FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc);
-bool needOpEquals(StructDeclaration *sd);
-FuncDeclaration *buildOpEquals(StructDeclaration *sd, Scope *sc);
-FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc);
-FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc);
-FuncDeclaration *buildXtoHash(StructDeclaration *ad, Scope *sc);
-FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc);
-FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc);
-FuncDeclaration *buildInv(AggregateDeclaration *ad, Scope *sc);
-FuncDeclaration *search_toString(StructDeclaration *sd);
-
-struct ClassKind
+struct MangleOverride
{
- enum Type
- {
- /// the class is a d(efault) class
- d,
- /// the class is a C++ interface
- cpp,
- /// the class is an Objective-C class/interface
- objc,
- };
+ Dsymbol *agg;
+ Identifier *id;
};
class AggregateDeclaration : public ScopeDsymbol
@@ -89,16 +73,16 @@ class AggregateDeclaration : public ScopeDsymbol
public:
Type *type;
StorageClass storage_class;
- Prot protection;
unsigned structsize; // size of struct
unsigned alignsize; // size of struct for alignment purposes
VarDeclarations fields; // VarDeclaration fields
- Sizeok sizeok; // set when structsize contains valid data
Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol
- bool isdeprecated; // true if deprecated
- ClassKind::Type classKind; // specifies the linkage type
+ ClassKind classKind; // specifies the linkage type
+ CPPMANGLE cppmangle;
+ // overridden symbol with pragma(mangle, "...")
+ MangleOverride *mangleOverride;
/* !=NULL if is nested
* pointing to the dsymbol that directly enclosing it.
* 1. The function that enclosing it (nested struct and class)
@@ -108,11 +92,10 @@ public:
*/
Dsymbol *enclosing;
VarDeclaration *vthis; // 'this' parameter if this aggregate is nested
+ VarDeclaration *vthis2; // 'this' parameter if this aggregate is a template and is nested
// Special member functions
FuncDeclarations invs; // Array of invariants
FuncDeclaration *inv; // invariant
- NewDeclaration *aggNew; // allocator
- DeleteDeclaration *aggDelete; // deallocator
Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration
@@ -120,42 +103,44 @@ public:
// it would be stored in TypeInfo_Class.defaultConstructor
CtorDeclaration *defaultCtor;
- Dsymbol *aliasthis; // forward unresolved lookups to aliasthis
- bool noDefaultCtor; // no default construction
+ AliasThis *aliasthis; // forward unresolved lookups to aliasthis
- FuncDeclarations dtors; // Array of destructors
- FuncDeclaration *dtor; // aggregate destructor
+ DtorDeclarations dtors; // Array of destructors
+ DtorDeclaration *dtor; // aggregate destructor
+ DtorDeclaration *primaryDtor; // non-deleting C++ destructor, same as dtor for D
+ DtorDeclaration *tidtor; // aggregate destructor used in TypeInfo (must have extern(D) ABI)
+ FuncDeclaration *fieldDtor; // aggregate destructor for just the fields
Expression *getRTInfo; // pointer to GC info generated by object.RTInfo(this)
- AggregateDeclaration(Loc loc, Identifier *id);
+ Visibility visibility;
+ bool noDefaultCtor; // no default construction
+ bool disableNew; // disallow allocations using `new`
+ Sizeok sizeok; // set when structsize contains valid data
+
virtual Scope *newScope(Scope *sc);
void setScope(Scope *sc);
- bool determineFields();
+ size_t nonHiddenFields();
bool determineSize(Loc loc);
virtual void finalizeSize() = 0;
- d_uns64 size(Loc loc);
- bool checkOverlappedFields();
+ d_uns64 size(const Loc &loc);
bool fill(Loc loc, Expressions *elements, bool ctorinit);
- static void alignmember(structalign_t salign, unsigned size, unsigned *poffset);
- static unsigned placeField(unsigned *nextoffset,
- unsigned memsize, unsigned memalignsize, structalign_t memalign,
- unsigned *paggsize, unsigned *paggalignsize, bool isunion);
Type *getType();
- bool isDeprecated(); // is aggregate deprecated?
- bool isNested();
- void makeNested();
+ bool isDeprecated() const; // is aggregate deprecated?
+ void setDeprecated();
+ bool isNested() const;
bool isExport() const;
Dsymbol *searchCtor();
- Prot prot();
+ Visibility visible();
// 'this' type
Type *handleType() { return type; }
+ bool hasInvariant();
+
// Back end
- Symbol *stag; // tag symbol for debug data
- Symbol *sinit;
+ void *sinit;
AggregateDeclaration *isAggregateDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
@@ -163,8 +148,7 @@ public:
struct StructFlags
{
- typedef unsigned Type;
- enum Enum
+ enum Type
{
none = 0x0,
hasPointers = 0x1 // NB: should use noPointers as in ClassFlags
@@ -174,9 +158,17 @@ struct StructFlags
class StructDeclaration : public AggregateDeclaration
{
public:
- int zeroInit; // !=0 if initialize with 0 fill
+ bool zeroInit; // !=0 if initialize with 0 fill
bool hasIdentityAssign; // true if has identity opAssign
+ bool hasBlitAssign; // true if opAssign is a blit
bool hasIdentityEquals; // true if has identity opEquals
+ bool hasNoFields; // has no fields
+ bool hasCopyCtor; // copy constructor
+ // Even if struct is defined as non-root symbol, some built-in operations
+ // (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
+ // For those, today TypeInfo_Struct is generated in COMDAT.
+ bool requestTypeInfo;
+
FuncDeclarations postblits; // Array of postblit functions
FuncDeclaration *postblit; // aggregate postblit
@@ -187,36 +179,30 @@ public:
static FuncDeclaration *xerrcmp; // object.xopCmp
structalign_t alignment; // alignment applied outside of the struct
- StructPOD ispod; // if struct is POD
+ ThreeState ispod; // if struct is POD
- // For 64 bit Efl function call/return ABI
- Type *arg1type;
- Type *arg2type;
+ // ABI-specific type(s) if the struct can be passed in registers
+ TypeTuple *argTypes;
- // Even if struct is defined as non-root symbol, some built-in operations
- // (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
- // For those, today TypeInfo_Struct is generated in COMDAT.
- bool requestTypeInfo;
-
- StructDeclaration(Loc loc, Identifier *id, bool inObject);
static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
- Dsymbol *syntaxCopy(Dsymbol *s);
- void semanticTypeInfoMembers();
+ StructDeclaration *syntaxCopy(Dsymbol *s);
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
const char *kind() const;
void finalizeSize();
- bool fit(Loc loc, Scope *sc, Expressions *elements, Type *stype);
bool isPOD();
StructDeclaration *isStructDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
+
+ unsigned numArgTypes() const;
+ Type *argType(unsigned index);
+ bool hasRegularCtor(bool checkDisabled = false);
};
class UnionDeclaration : public StructDeclaration
{
public:
- UnionDeclaration(Loc loc, Identifier *id);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ UnionDeclaration *syntaxCopy(Dsymbol *s);
const char *kind() const;
UnionDeclaration *isUnionDeclaration() { return this; }
@@ -236,18 +222,14 @@ struct BaseClass
DArray<BaseClass> baseInterfaces; // if BaseClass is an interface, these
// are a copy of the InterfaceDeclaration::interfaces
- BaseClass();
- BaseClass(Type *type);
-
bool fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance);
- void copyBaseInterfaces(BaseClasses *);
};
struct ClassFlags
{
- typedef unsigned Type;
- enum Enum
+ enum Type
{
+ none = 0x0,
isCOMclass = 0x1,
noPointers = 0x2,
hasOffTi = 0x4,
@@ -286,15 +268,18 @@ public:
TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration
bool com; // true if this is a COM class (meaning it derives from IUnknown)
- bool isscope; // true if this is a scope class
- Abstract isabstract; // 0: fwdref, 1: is abstract class, 2: not abstract
- int inuse; // to prevent recursive attempts
+ bool stack; // true if this is a scope class
+ int cppDtorVtblIndex; // slot reserved for the virtual destructor [extern(C++)]
+ bool inuse; // to prevent recursive attempts
+
+ ThreeState isabstract; // if abstract class
Baseok baseok; // set the progress of base classes resolving
+ ObjcClassDeclaration objc; // Data for a class declaration that is needed for the Objective-C integration
Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr
- ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject = false);
static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ const char *toPrettyChars(bool QualifyTypes = false);
+ ClassDeclaration *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
bool isBaseOf2(ClassDeclaration *cd);
@@ -318,9 +303,11 @@ public:
const char *kind() const;
void addLocalClass(ClassDeclarations *);
+ void addObjcSymbols(ClassDeclarations *classes, ClassDeclarations *categories);
// Back end
- Symbol *vtblsym;
+ Dsymbol *vtblsym;
+ Dsymbol *vtblSymbol();
ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
void accept(Visitor *v) { v->visit(this); }
@@ -329,11 +316,9 @@ public:
class InterfaceDeclaration : public ClassDeclaration
{
public:
- InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ InterfaceDeclaration *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
bool isBaseOf(ClassDeclaration *cd, int *poffset);
- bool isBaseOf(BaseClass *bc, int *poffset);
const char *kind() const;
int vtblOffset() const;
bool isCPPinterface() const;
diff --git a/gcc/d/dmd/aliasthis.c b/gcc/d/dmd/aliasthis.c
deleted file mode 100644
index 458416f..0000000
--- a/gcc/d/dmd/aliasthis.c
+++ /dev/null
@@ -1,94 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 2009-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/aliasthis.c
- */
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "identifier.h"
-#include "aliasthis.h"
-#include "scope.h"
-#include "aggregate.h"
-#include "dsymbol.h"
-#include "mtype.h"
-#include "declaration.h"
-#include "expression.h"
-#include "tokens.h"
-
-Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag)
-{
- AggregateDeclaration *ad = isAggregate(e->type);
-
- if (ad && ad->aliasthis)
- {
- unsigned olderrors = gag ? global.startGagging() : 0;
-
- Loc loc = e->loc;
- Type *tthis = (e->op == TOKtype ? e->type : NULL);
- e = new DotIdExp(loc, e, ad->aliasthis->ident);
- e = expressionSemantic(e, sc);
- if (tthis && ad->aliasthis->needThis())
- {
- if (e->op == TOKvar)
- {
- if (FuncDeclaration *fd = ((VarExp *)e)->var->isFuncDeclaration())
- {
- // Bugzilla 13009: Support better match for the overloaded alias this.
- bool hasOverloads = false;
- if (FuncDeclaration *f = fd->overloadModMatch(loc, tthis, hasOverloads))
- {
- if (!hasOverloads)
- fd = f; // use exact match
- e = new VarExp(loc, fd, hasOverloads);
- e->type = f->type;
- e = new CallExp(loc, e);
- goto L1;
- }
- }
- }
- /* non-@property function is not called inside typeof(),
- * so resolve it ahead.
- */
- {
- int save = sc->intypeof;
- sc->intypeof = 1; // bypass "need this" error check
- e = resolveProperties(sc, e);
- sc->intypeof = save;
- }
-
- L1:
- e = new TypeExp(loc, new TypeTypeof(loc, e));
- e = expressionSemantic(e, sc);
- }
- e = resolveProperties(sc, e);
-
- if (gag && global.endGagging(olderrors))
- e = NULL;
- }
-
- return e;
-}
-
-AliasThis::AliasThis(Loc loc, Identifier *ident)
- : Dsymbol(NULL) // it's anonymous (no identifier)
-{
- this->loc = loc;
- this->ident = ident;
-}
-
-Dsymbol *AliasThis::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- return new AliasThis(loc, ident);
-}
-
-const char *AliasThis::kind() const
-{
- return "alias this";
-}
diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d
new file mode 100644
index 0000000..81e0d7e
--- /dev/null
+++ b/gcc/d/dmd/aliasthis.d
@@ -0,0 +1,202 @@
+/**
+ * Implements the `alias this` symbol.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/class.html#alias-this, Alias This)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.d, _aliasthis.d)
+ * Documentation: https://dlang.org/phobos/dmd_aliasthis.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/aliasthis.d
+ */
+
+module dmd.aliasthis;
+
+import core.stdc.stdio;
+import dmd.aggregate;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.globals;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.opover;
+import dmd.tokens;
+import dmd.visitor;
+
+/***********************************************************
+ * alias ident this;
+ */
+extern (C++) final class AliasThis : Dsymbol
+{
+ Identifier ident;
+ /// The symbol this `alias this` resolves to
+ Dsymbol sym;
+ /// Whether this `alias this` is deprecated or not
+ bool isDeprecated_;
+
+ extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ super(loc, null); // it's anonymous (no identifier)
+ this.ident = ident;
+ }
+
+ override AliasThis syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto at = new AliasThis(loc, ident);
+ at.comment = comment;
+ return at;
+ }
+
+ override const(char)* kind() const
+ {
+ return "alias this";
+ }
+
+ AliasThis isAliasThis()
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ override bool isDeprecated() const
+ {
+ return this.isDeprecated_;
+ }
+}
+
+Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false)
+{
+ for (AggregateDeclaration ad = isAggregate(e.type); ad;)
+ {
+ if (ad.aliasthis)
+ {
+ uint olderrors = gag ? global.startGagging() : 0;
+ Loc loc = e.loc;
+ Type tthis = (e.op == TOK.type ? e.type : null);
+ e = new DotIdExp(loc, e, ad.aliasthis.ident);
+ e = e.expressionSemantic(sc);
+ if (tthis && ad.aliasthis.sym.needThis())
+ {
+ if (e.op == TOK.variable)
+ {
+ if (auto fd = (cast(VarExp)e).var.isFuncDeclaration())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=13009
+ // Support better match for the overloaded alias this.
+ bool hasOverloads;
+ if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads))
+ {
+ if (!hasOverloads)
+ fd = f; // use exact match
+ e = new VarExp(loc, fd, hasOverloads);
+ e.type = f.type;
+ e = new CallExp(loc, e);
+ goto L1;
+ }
+ }
+ }
+ /* non-@property function is not called inside typeof(),
+ * so resolve it ahead.
+ */
+ {
+ int save = sc.intypeof;
+ sc.intypeof = 1; // bypass "need this" error check
+ e = resolveProperties(sc, e);
+ sc.intypeof = save;
+ }
+ L1:
+ e = new TypeExp(loc, new TypeTypeof(loc, e));
+ e = e.expressionSemantic(sc);
+ }
+ e = resolveProperties(sc, e);
+ if (!gag)
+ ad.aliasthis.checkDeprecatedAliasThis(loc, sc);
+ else if (global.endGagging(olderrors))
+ e = null;
+ }
+
+ import dmd.dclass : ClassDeclaration;
+ auto cd = ad.isClassDeclaration();
+ if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
+ {
+ ad = cd.baseClass;
+ continue;
+ }
+ break;
+ }
+ return e;
+}
+
+/**
+ * Check if an `alias this` is deprecated
+ *
+ * Usually one would use `expression.checkDeprecated(scope, aliasthis)` to
+ * check if `expression` uses a deprecated `aliasthis`, but this calls
+ * `toPrettyChars` which lead to the following message:
+ * "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated"
+ *
+ * Params:
+ * at = The `AliasThis` object to check
+ * loc = `Loc` of the expression triggering the access to `at`
+ * sc = `Scope` of the expression
+ * (deprecations do not trigger in deprecated scopes)
+ *
+ * Returns:
+ * Whether the alias this was reported as deprecated.
+ */
+bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc)
+{
+ import dmd.errors : deprecation, Classification;
+ import dmd.dsymbolsem : getMessage;
+
+ if (global.params.useDeprecated != DiagnosticReporting.off
+ && at.isDeprecated() && !sc.isDeprecated())
+ {
+ const(char)* message = null;
+ for (Dsymbol p = at; p; p = p.parent)
+ {
+ message = p.depdecl ? p.depdecl.getMessage() : null;
+ if (message)
+ break;
+ }
+ if (message)
+ deprecation(loc, "`alias %s this` is deprecated - %s",
+ at.sym.toChars(), message);
+ else
+ deprecation(loc, "`alias %s this` is deprecated",
+ at.sym.toChars());
+
+ if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
+ ti.printInstantiationTrace(Classification.deprecation);
+
+ return true;
+ }
+ return false;
+}
+
+/**************************************
+ * Check and set 'att' if 't' is a recursive 'alias this' type
+ * Params:
+ * att = type reference used to detect recursion
+ * t = 'alias this' type
+ *
+ * Returns:
+ * Whether the 'alias this' is recursive or not
+ */
+bool isRecursiveAliasThis(ref Type att, Type t)
+{
+ auto tb = t.toBasetype();
+ if (att && tb.equivalent(att))
+ return true;
+ else if (!att && tb.checkAliasThisRec())
+ att = tb;
+ return false;
+}
diff --git a/gcc/d/dmd/aliasthis.h b/gcc/d/dmd/aliasthis.h
index 15905e4..de93a8e 100644
--- a/gcc/d/dmd/aliasthis.h
+++ b/gcc/d/dmd/aliasthis.h
@@ -5,11 +5,12 @@
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/dlang/dmd/blob/master/src/aliasthis.h
+ * https://github.com/dlang/dmd/blob/master/src/dmd/aliasthis.h
*/
#pragma once
+#include "globals.h"
#include "dsymbol.h"
/**************************************************************/
@@ -19,11 +20,12 @@ class AliasThis : public Dsymbol
public:
// alias Identifier this;
Identifier *ident;
+ Dsymbol *sym;
+ bool isDeprecated_;
- AliasThis(Loc loc, Identifier *ident);
-
- Dsymbol *syntaxCopy(Dsymbol *);
+ AliasThis *syntaxCopy(Dsymbol *);
const char *kind() const;
AliasThis *isAliasThis() { return this; }
void accept(Visitor *v) { v->visit(this); }
+ bool isDeprecated() const { return this->isDeprecated_; }
};
diff --git a/gcc/d/dmd/apply.c b/gcc/d/dmd/apply.c
deleted file mode 100644
index 8a727ae..0000000
--- a/gcc/d/dmd/apply.c
+++ /dev/null
@@ -1,149 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/apply.c
- */
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "expression.h"
-#include "template.h"
-#include "visitor.h"
-
-
-/**************************************
- * An Expression tree walker that will visit each Expression e in the tree,
- * in depth-first evaluation order, and call fp(e,param) on it.
- * fp() signals whether the walking continues with its return value:
- * Returns:
- * 0 continue
- * 1 done
- * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
- * Creating an iterator for this would be much more complex.
- */
-
-class PostorderExpressionVisitor : public StoppableVisitor
-{
-public:
- StoppableVisitor *v;
- PostorderExpressionVisitor(StoppableVisitor *v) : v(v) {}
-
- bool doCond(Expression *e)
- {
- if (!stop && e)
- e->accept(this);
- return stop;
- }
- bool doCond(Expressions *e)
- {
- if (!e)
- return false;
- for (size_t i = 0; i < e->length && !stop; i++)
- doCond((*e)[i]);
- return stop;
- }
- bool applyTo(Expression *e)
- {
- e->accept(v);
- stop = v->stop;
- return true;
- }
-
- void visit(Expression *e)
- {
- applyTo(e);
- }
-
- void visit(NewExp *e)
- {
- //printf("NewExp::apply(): %s\n", toChars());
-
- doCond(e->thisexp) || doCond(e->newargs) || doCond(e->arguments) || applyTo(e);
- }
-
- void visit(NewAnonClassExp *e)
- {
- //printf("NewAnonClassExp::apply(): %s\n", toChars());
-
- doCond(e->thisexp) || doCond(e->newargs) || doCond(e->arguments) || applyTo(e);
- }
-
- void visit(TypeidExp *e)
- {
- doCond(isExpression(e->obj)) || applyTo(e);
- }
-
- void visit(UnaExp *e)
- {
- doCond(e->e1) || applyTo(e);
- }
-
- void visit(BinExp *e)
- {
- doCond(e->e1) || doCond(e->e2) || applyTo(e);
- }
-
- void visit(AssertExp *e)
- {
- //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
- doCond(e->e1) || doCond(e->msg) || applyTo(e);
- }
-
- void visit(CallExp *e)
- {
- //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
- doCond(e->e1) || doCond(e->arguments) || applyTo(e);
- }
-
- void visit(ArrayExp *e)
- {
- //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
- doCond(e->e1) || doCond(e->arguments) || applyTo(e);
- }
-
- void visit(SliceExp *e)
- {
- doCond(e->e1) || doCond(e->lwr) || doCond(e->upr) || applyTo(e);
- }
-
- void visit(ArrayLiteralExp *e)
- {
- doCond(e->basis) || doCond(e->elements) || applyTo(e);
- }
-
- void visit(AssocArrayLiteralExp *e)
- {
- doCond(e->keys) || doCond(e->values) || applyTo(e);
- }
-
- void visit(StructLiteralExp *e)
- {
- if (e->stageflags & stageApply) return;
- int old = e->stageflags;
- e->stageflags |= stageApply;
- doCond(e->elements) || applyTo(e);
- e->stageflags = old;
- }
-
- void visit(TupleExp *e)
- {
- doCond(e->e0) || doCond(e->exps) || applyTo(e);
- }
-
- void visit(CondExp *e)
- {
- doCond(e->econd) || doCond(e->e1) || doCond(e->e2) || applyTo(e);
- }
-};
-
-bool walkPostorder(Expression *e, StoppableVisitor *v)
-{
- PostorderExpressionVisitor pv(v);
- e->accept(&pv);
- return v->stop;
-}
diff --git a/gcc/d/dmd/apply.d b/gcc/d/dmd/apply.d
new file mode 100644
index 0000000..ab427e8
--- /dev/null
+++ b/gcc/d/dmd/apply.d
@@ -0,0 +1,189 @@
+/**
+ * A depth-first visitor for expressions.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/apply.d, _apply.d)
+ * Documentation: https://dlang.org/phobos/dmd_apply.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/apply.d
+ */
+
+module dmd.apply;
+
+import dmd.arraytypes;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.expression;
+import dmd.visitor;
+
+bool walkPostorder(Expression e, StoppableVisitor v)
+{
+ scope PostorderExpressionVisitor pv = new PostorderExpressionVisitor(v);
+ e.accept(pv);
+ return v.stop;
+}
+
+/*********************************
+ * Iterate this dsymbol or members of this scoped dsymbol, then
+ * call `fp` with the found symbol and `params`.
+ * Params:
+ * symbol = the dsymbol or parent of members to call fp on
+ * fp = function pointer to process the iterated symbol.
+ * If it returns nonzero, the iteration will be aborted.
+ * params = any parameters passed to fp.
+ * Returns:
+ * nonzero if the iteration is aborted by the return value of fp,
+ * or 0 if it's completed.
+ */
+int apply(FP, Params...)(Dsymbol symbol, FP fp, Params params)
+{
+ if (auto nd = symbol.isNspace())
+ {
+ return nd.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } );
+ }
+ if (auto ad = symbol.isAttribDeclaration())
+ {
+ return ad.include(ad._scope).foreachDsymbol( (s) { return s && s.apply(fp, params); } );
+ }
+ if (auto tm = symbol.isTemplateMixin())
+ {
+ if (tm._scope) // if fwd reference
+ dsymbolSemantic(tm, null); // try to resolve it
+
+ return tm.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } );
+ }
+
+ return fp(symbol, params);
+}
+
+/**************************************
+ * An Expression tree walker that will visit each Expression e in the tree,
+ * in depth-first evaluation order, and call fp(e,param) on it.
+ * fp() signals whether the walking continues with its return value:
+ * Returns:
+ * 0 continue
+ * 1 done
+ * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
+ * Creating an iterator for this would be much more complex.
+ */
+private extern (C++) final class PostorderExpressionVisitor : StoppableVisitor
+{
+ alias visit = typeof(super).visit;
+public:
+ StoppableVisitor v;
+
+ extern (D) this(StoppableVisitor v)
+ {
+ this.v = v;
+ }
+
+ bool doCond(Expression e)
+ {
+ if (!stop && e)
+ e.accept(this);
+ return stop;
+ }
+
+ bool doCond(Expressions* e)
+ {
+ if (!e)
+ return false;
+ for (size_t i = 0; i < e.dim && !stop; i++)
+ doCond((*e)[i]);
+ return stop;
+ }
+
+ bool applyTo(Expression e)
+ {
+ e.accept(v);
+ stop = v.stop;
+ return true;
+ }
+
+ override void visit(Expression e)
+ {
+ applyTo(e);
+ }
+
+ override void visit(NewExp e)
+ {
+ //printf("NewExp::apply(): %s\n", toChars());
+ doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e);
+ }
+
+ override void visit(NewAnonClassExp e)
+ {
+ //printf("NewAnonClassExp::apply(): %s\n", toChars());
+ doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e);
+ }
+
+ override void visit(TypeidExp e)
+ {
+ doCond(isExpression(e.obj)) || applyTo(e);
+ }
+
+ override void visit(UnaExp e)
+ {
+ doCond(e.e1) || applyTo(e);
+ }
+
+ override void visit(BinExp e)
+ {
+ doCond(e.e1) || doCond(e.e2) || applyTo(e);
+ }
+
+ override void visit(AssertExp e)
+ {
+ //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
+ doCond(e.e1) || doCond(e.msg) || applyTo(e);
+ }
+
+ override void visit(CallExp e)
+ {
+ //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
+ doCond(e.e1) || doCond(e.arguments) || applyTo(e);
+ }
+
+ override void visit(ArrayExp e)
+ {
+ //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars());
+ doCond(e.e1) || doCond(e.arguments) || applyTo(e);
+ }
+
+ override void visit(SliceExp e)
+ {
+ doCond(e.e1) || doCond(e.lwr) || doCond(e.upr) || applyTo(e);
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ doCond(e.basis) || doCond(e.elements) || applyTo(e);
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ doCond(e.keys) || doCond(e.values) || applyTo(e);
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ if (e.stageflags & stageApply)
+ return;
+ int old = e.stageflags;
+ e.stageflags |= stageApply;
+ doCond(e.elements) || applyTo(e);
+ e.stageflags = old;
+ }
+
+ override void visit(TupleExp e)
+ {
+ doCond(e.e0) || doCond(e.exps) || applyTo(e);
+ }
+
+ override void visit(CondExp e)
+ {
+ doCond(e.econd) || doCond(e.e1) || doCond(e.e2) || applyTo(e);
+ }
+}
diff --git a/gcc/d/dmd/arrayop.c b/gcc/d/dmd/arrayop.c
deleted file mode 100644
index 52d596b..0000000
--- a/gcc/d/dmd/arrayop.c
+++ /dev/null
@@ -1,634 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/arrayop.c
- */
-
-#include "root/dsystem.h"
-#include "root/rmem.h"
-#include "root/aav.h"
-
-#include "mars.h"
-#include "expression.h"
-#include "statement.h"
-#include "mtype.h"
-#include "declaration.h"
-#include "scope.h"
-#include "id.h"
-#include "module.h"
-#include "init.h"
-#include "tokens.h"
-
-void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments);
-Expression *buildArrayLoop(Expression *e, Parameters *fparams);
-
-/**************************************
- * Hash table of array op functions already generated or known about.
- */
-
-AA *arrayfuncs;
-
-/**************************************
- * Structure to contain information needed to insert an array op call
- */
-
-FuncDeclaration *buildArrayOp(Identifier *ident, BinExp *exp, Scope *sc)
-{
- Parameters *fparams = new Parameters();
- Expression *loopbody = buildArrayLoop(exp, fparams);
-
- /* Construct the function body:
- * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++)
- * loopbody;
- * return p;
- */
-
- Parameter *p = (*fparams)[0];
- // foreach (i; 0 .. p.length)
- Statement *s1 = new ForeachRangeStatement(Loc(), TOKforeach,
- new Parameter(0, NULL, Id::p, NULL, NULL),
- new IntegerExp(Loc(), 0, Type::tsize_t),
- new ArrayLengthExp(Loc(), new IdentifierExp(Loc(), p->ident)),
- new ExpStatement(Loc(), loopbody),
- Loc());
- //printf("%s\n", s1->toChars());
- Statement *s2 = new ReturnStatement(Loc(), new IdentifierExp(Loc(), p->ident));
- //printf("s2: %s\n", s2->toChars());
- Statement *fbody = new CompoundStatement(Loc(), s1, s2);
-
- // Built-in array ops should be @trusted, pure, nothrow and nogc
- StorageClass stc = STCtrusted | STCpure | STCnothrow | STCnogc;
-
- /* Construct the function
- */
- TypeFunction *ftype = new TypeFunction(ParameterList(fparams), exp->e1->type, LINKc, stc);
- //printf("fd: %s %s\n", ident->toChars(), ftype->toChars());
- FuncDeclaration *fd = new FuncDeclaration(Loc(), Loc(), ident, STCundefined, ftype);
- fd->fbody = fbody;
- fd->protection = Prot(Prot::public_);
- fd->linkage = LINKc;
- fd->isArrayOp = 1;
-
- sc->_module->importedFrom->members->push(fd);
-
- sc = sc->push();
- sc->parent = sc->_module->importedFrom;
- sc->stc = 0;
- sc->linkage = LINKc;
- dsymbolSemantic(fd, sc);
- semantic2(fd, sc);
- unsigned errors = global.startGagging();
- semantic3(fd, sc);
- if (global.endGagging(errors))
- {
- fd->type = Type::terror;
- fd->errors = true;
- fd->fbody = NULL;
- }
- sc->pop();
-
- return fd;
-}
-
-/**********************************************
- * Check that there are no uses of arrays without [].
- */
-bool isArrayOpValid(Expression *e)
-{
- if (e->op == TOKslice)
- return true;
- if (e->op == TOKarrayliteral)
- {
- Type *t = e->type->toBasetype();
- while (t->ty == Tarray || t->ty == Tsarray)
- t = t->nextOf()->toBasetype();
- return (t->ty != Tvoid);
- }
- Type *tb = e->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (isUnaArrayOp(e->op))
- {
- return isArrayOpValid(((UnaExp *)e)->e1);
- }
- if (isBinArrayOp(e->op) ||
- isBinAssignArrayOp(e->op) ||
- e->op == TOKassign)
- {
- BinExp *be = (BinExp *)e;
- return isArrayOpValid(be->e1) && isArrayOpValid(be->e2);
- }
- if (e->op == TOKconstruct)
- {
- BinExp *be = (BinExp *)e;
- return be->e1->op == TOKslice && isArrayOpValid(be->e2);
- }
- if (e->op == TOKcall)
- {
- return false; // TODO: Decide if [] is required after arrayop calls.
- }
- else
- {
- return false;
- }
- }
- return true;
-}
-
-bool isNonAssignmentArrayOp(Expression *e)
-{
- if (e->op == TOKslice)
- return isNonAssignmentArrayOp(((SliceExp *)e)->e1);
-
- Type *tb = e->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- return (isUnaArrayOp(e->op) || isBinArrayOp(e->op));
- }
- return false;
-}
-
-bool checkNonAssignmentArrayOp(Expression *e, bool suggestion)
-{
- if (isNonAssignmentArrayOp(e))
- {
- const char *s = "";
- if (suggestion)
- s = " (possible missing [])";
- e->error("array operation %s without destination memory not allowed%s", e->toChars(), s);
- return true;
- }
- return false;
-}
-
-/***********************************
- * Construct the array operation expression.
- */
-
-Expression *arrayOp(BinExp *e, Scope *sc)
-{
- //printf("BinExp::arrayOp() %s\n", toChars());
-
- Type *tb = e->type->toBasetype();
- assert(tb->ty == Tarray || tb->ty == Tsarray);
- Type *tbn = tb->nextOf()->toBasetype();
- if (tbn->ty == Tvoid)
- {
- e->error("cannot perform array operations on void[] arrays");
- return new ErrorExp();
- }
- if (!isArrayOpValid(e))
- {
- e->error("invalid array operation %s (possible missing [])", e->toChars());
- return new ErrorExp();
- }
-
- Expressions *arguments = new Expressions();
-
- /* The expression to generate an array operation for is mangled
- * into a name to use as the array operation function name.
- * Mangle in the operands and operators in RPN order, and type.
- */
- OutBuffer buf;
- buf.writestring("_array");
- buildArrayIdent(e, &buf, arguments);
- buf.writeByte('_');
-
- /* Append deco of array element type
- */
- buf.writestring(e->type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco);
-
- char *name = buf.peekChars();
- Identifier *ident = Identifier::idPool(name);
-
- FuncDeclaration **pFd = (FuncDeclaration **)dmd_aaGet(&arrayfuncs, (void *)ident);
- FuncDeclaration *fd = *pFd;
-
- if (!fd)
- fd = buildArrayOp(ident, e, sc);
-
- if (fd && fd->errors)
- {
- const char *fmt;
- if (tbn->ty == Tstruct || tbn->ty == Tclass)
- fmt = "invalid array operation '%s' because %s doesn't support necessary arithmetic operations";
- else if (!tbn->isscalar())
- fmt = "invalid array operation '%s' because %s is not a scalar type";
- else
- fmt = "invalid array operation '%s' for element type %s";
-
- e->error(fmt, e->toChars(), tbn->toChars());
- return new ErrorExp();
- }
-
- *pFd = fd;
-
- Expression *ev = new VarExp(e->loc, fd);
- Expression *ec = new CallExp(e->loc, ev, arguments);
-
- return expressionSemantic(ec, sc);
-}
-
-Expression *arrayOp(BinAssignExp *e, Scope *sc)
-{
- //printf("BinAssignExp::arrayOp() %s\n", toChars());
-
- /* Check that the elements of e1 can be assigned to
- */
- Type *tn = e->e1->type->toBasetype()->nextOf();
-
- if (tn && (!tn->isMutable() || !tn->isAssignable()))
- {
- e->error("slice %s is not mutable", e->e1->toChars());
- return new ErrorExp();
- }
- if (e->e1->op == TOKarrayliteral)
- {
- return e->e1->modifiableLvalue(sc, e->e1);
- }
-
- return arrayOp((BinExp *)e, sc);
-}
-
-/******************************************
- * Construct the identifier for the array operation function,
- * and build the argument list to pass to it.
- */
-
-void buildArrayIdent(Expression *e, OutBuffer *buf, Expressions *arguments)
-{
- class BuildArrayIdentVisitor : public Visitor
- {
- OutBuffer *buf;
- Expressions *arguments;
- public:
- BuildArrayIdentVisitor(OutBuffer *buf, Expressions *arguments)
- : buf(buf), arguments(arguments)
- {
- }
-
- void visit(Expression *e)
- {
- buf->writestring("Exp");
- arguments->shift(e);
- }
-
- void visit(CastExp *e)
- {
- Type *tb = e->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- e->e1->accept(this);
- }
- else
- visit((Expression *)e);
- }
-
- void visit(ArrayLiteralExp *e)
- {
- buf->writestring("Slice");
- arguments->shift(e);
- }
-
- void visit(SliceExp *e)
- {
- buf->writestring("Slice");
- arguments->shift(e);
- }
-
- void visit(AssignExp *e)
- {
- /* Evaluate assign expressions right to left
- */
- e->e2->accept(this);
- e->e1->accept(this);
- buf->writestring("Assign");
- }
-
- void visit(BinAssignExp *e)
- {
- /* Evaluate assign expressions right to left
- */
- e->e2->accept(this);
- e->e1->accept(this);
- const char *s;
- switch(e->op)
- {
- case TOKaddass: s = "Addass"; break;
- case TOKminass: s = "Minass"; break;
- case TOKmulass: s = "Mulass"; break;
- case TOKdivass: s = "Divass"; break;
- case TOKmodass: s = "Modass"; break;
- case TOKxorass: s = "Xorass"; break;
- case TOKandass: s = "Andass"; break;
- case TOKorass: s = "Orass"; break;
- case TOKpowass: s = "Powass"; break;
- default: assert(0);
- }
- buf->writestring(s);
- }
-
- void visit(NegExp *e)
- {
- e->e1->accept(this);
- buf->writestring("Neg");
- }
-
- void visit(ComExp *e)
- {
- e->e1->accept(this);
- buf->writestring("Com");
- }
-
- void visit(BinExp *e)
- {
- /* Evaluate assign expressions left to right
- */
- const char *s = NULL;
- switch(e->op)
- {
- case TOKadd: s = "Add"; break;
- case TOKmin: s = "Min"; break;
- case TOKmul: s = "Mul"; break;
- case TOKdiv: s = "Div"; break;
- case TOKmod: s = "Mod"; break;
- case TOKxor: s = "Xor"; break;
- case TOKand: s = "And"; break;
- case TOKor: s = "Or"; break;
- case TOKpow: s = "Pow"; break;
- default: break;
- }
- if (s)
- {
- Type *tb = e->type->toBasetype();
- Type *t1 = e->e1->type->toBasetype();
- Type *t2 = e->e2->type->toBasetype();
- e->e1->accept(this);
- if (t1->ty == Tarray &&
- ((t2->ty == Tarray && !t1->equivalent(tb)) ||
- (t2->ty != Tarray && !t1->nextOf()->equivalent(e->e2->type))))
- {
- // Bugzilla 12780: if A is narrower than B
- // A[] op B[]
- // A[] op B
- buf->writestring("Of");
- buf->writestring(t1->nextOf()->mutableOf()->deco);
- }
- e->e2->accept(this);
- if (t2->ty == Tarray &&
- ((t1->ty == Tarray && !t2->equivalent(tb)) ||
- (t1->ty != Tarray && !t2->nextOf()->equivalent(e->e1->type))))
- {
- // Bugzilla 12780: if B is narrower than A:
- // A[] op B[]
- // A op B[]
- buf->writestring("Of");
- buf->writestring(t2->nextOf()->mutableOf()->deco);
- }
- buf->writestring(s);
- }
- else
- visit((Expression *)e);
- }
- };
-
- BuildArrayIdentVisitor v(buf, arguments);
- e->accept(&v);
-}
-
-/******************************************
- * Construct the inner loop for the array operation function,
- * and build the parameter list.
- */
-
-Expression *buildArrayLoop(Expression *e, Parameters *fparams)
-{
- class BuildArrayLoopVisitor : public Visitor
- {
- Parameters *fparams;
- Expression *result;
-
- public:
- BuildArrayLoopVisitor(Parameters *fparams)
- : fparams(fparams), result(NULL)
- {
- }
-
- void visit(Expression *e)
- {
- Identifier *id = Identifier::generateId("c", fparams->length);
- Parameter *param = new Parameter(0, e->type, id, NULL, NULL);
- fparams->shift(param);
- result = new IdentifierExp(Loc(), id);
- }
-
- void visit(CastExp *e)
- {
- Type *tb = e->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- e->e1->accept(this);
- }
- else
- visit((Expression *)e);
- }
-
- void visit(ArrayLiteralExp *e)
- {
- Identifier *id = Identifier::generateId("p", fparams->length);
- Parameter *param = new Parameter(STCconst, e->type, id, NULL, NULL);
- fparams->shift(param);
- Expression *ie = new IdentifierExp(Loc(), id);
- Expression *index = new IdentifierExp(Loc(), Id::p);
- result = new ArrayExp(Loc(), ie, index);
- }
-
- void visit(SliceExp *e)
- {
- Identifier *id = Identifier::generateId("p", fparams->length);
- Parameter *param = new Parameter(STCconst, e->type, id, NULL, NULL);
- fparams->shift(param);
- Expression *ie = new IdentifierExp(Loc(), id);
- Expression *index = new IdentifierExp(Loc(), Id::p);
- result = new ArrayExp(Loc(), ie, index);
- }
-
- void visit(AssignExp *e)
- {
- /* Evaluate assign expressions right to left
- */
- Expression *ex2 = buildArrayLoop(e->e2);
- /* Need the cast because:
- * b = c + p[i];
- * where b is a byte fails because (c + p[i]) is an int
- * which cannot be implicitly cast to byte.
- */
- ex2 = new CastExp(Loc(), ex2, e->e1->type->nextOf());
- Expression *ex1 = buildArrayLoop(e->e1);
- Parameter *param = (*fparams)[0];
- param->storageClass = 0;
- result = new AssignExp(Loc(), ex1, ex2);
- }
-
- void visit(BinAssignExp *e)
- {
- /* Evaluate assign expressions right to left
- */
- Expression *ex2 = buildArrayLoop(e->e2);
- Expression *ex1 = buildArrayLoop(e->e1);
- Parameter *param = (*fparams)[0];
- param->storageClass = 0;
- switch(e->op)
- {
- case TOKaddass: result = new AddAssignExp(e->loc, ex1, ex2); return;
- case TOKminass: result = new MinAssignExp(e->loc, ex1, ex2); return;
- case TOKmulass: result = new MulAssignExp(e->loc, ex1, ex2); return;
- case TOKdivass: result = new DivAssignExp(e->loc, ex1, ex2); return;
- case TOKmodass: result = new ModAssignExp(e->loc, ex1, ex2); return;
- case TOKxorass: result = new XorAssignExp(e->loc, ex1, ex2); return;
- case TOKandass: result = new AndAssignExp(e->loc, ex1, ex2); return;
- case TOKorass: result = new OrAssignExp(e->loc, ex1, ex2); return;
- case TOKpowass: result = new PowAssignExp(e->loc, ex1, ex2); return;
- default:
- assert(0);
- }
- }
-
- void visit(NegExp *e)
- {
- Expression *ex1 = buildArrayLoop(e->e1);
- result = new NegExp(Loc(), ex1);
- }
-
- void visit(ComExp *e)
- {
- Expression *ex1 = buildArrayLoop(e->e1);
- result = new ComExp(Loc(), ex1);
- }
-
- void visit(BinExp *e)
- {
- if (isBinArrayOp(e->op))
- {
- /* Evaluate assign expressions left to right
- */
- BinExp *be = (BinExp *)e->copy();
- be->e1 = buildArrayLoop(be->e1);
- be->e2 = buildArrayLoop(be->e2);
- be->type = NULL;
- result = be;
- return;
- }
- else
- {
- visit((Expression *)e);
- return;
- }
- }
-
- Expression *buildArrayLoop(Expression *e)
- {
- e->accept(this);
- return result;
- }
- };
-
- BuildArrayLoopVisitor v(fparams);
- return v.buildArrayLoop(e);
-}
-
-/***********************************************
- * Test if expression is a unary array op.
- */
-
-bool isUnaArrayOp(TOK op)
-{
- switch (op)
- {
- case TOKneg:
- case TOKtilde:
- return true;
- default:
- break;
- }
- return false;
-}
-
-/***********************************************
- * Test if expression is a binary array op.
- */
-
-bool isBinArrayOp(TOK op)
-{
- switch (op)
- {
- case TOKadd:
- case TOKmin:
- case TOKmul:
- case TOKdiv:
- case TOKmod:
- case TOKxor:
- case TOKand:
- case TOKor:
- case TOKpow:
- return true;
- default:
- break;
- }
- return false;
-}
-
-/***********************************************
- * Test if expression is a binary assignment array op.
- */
-
-bool isBinAssignArrayOp(TOK op)
-{
- switch (op)
- {
- case TOKaddass:
- case TOKminass:
- case TOKmulass:
- case TOKdivass:
- case TOKmodass:
- case TOKxorass:
- case TOKandass:
- case TOKorass:
- case TOKpowass:
- return true;
- default:
- break;
- }
- return false;
-}
-
-/***********************************************
- * Test if operand is a valid array op operand.
- */
-
-bool isArrayOpOperand(Expression *e)
-{
- //printf("Expression::isArrayOpOperand() %s\n", e->toChars());
- if (e->op == TOKslice)
- return true;
- if (e->op == TOKarrayliteral)
- {
- Type *t = e->type->toBasetype();
- while (t->ty == Tarray || t->ty == Tsarray)
- t = t->nextOf()->toBasetype();
- return (t->ty != Tvoid);
- }
- Type *tb = e->type->toBasetype();
- if (tb->ty == Tarray)
- {
- return (isUnaArrayOp(e->op) ||
- isBinArrayOp(e->op) ||
- isBinAssignArrayOp(e->op) ||
- e->op == TOKassign);
- }
- return false;
-}
diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d
new file mode 100644
index 0000000..66be73e
--- /dev/null
+++ b/gcc/d/dmd/arrayop.d
@@ -0,0 +1,387 @@
+/**
+ * Implement array operations, such as `a[] = b[] + c[]`.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/arrays.html#array-operations, Array Operations)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arrayop.d, _arrayop.d)
+ * Documentation: https://dlang.org/phobos/dmd_arrayop.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/arrayop.d
+ */
+
+module dmd.arrayop;
+
+import core.stdc.stdio;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.root.outbuffer;
+import dmd.statement;
+import dmd.tokens;
+import dmd.visitor;
+
+/**********************************************
+ * Check that there are no uses of arrays without [].
+ */
+bool isArrayOpValid(Expression e)
+{
+ //printf("isArrayOpValid() %s\n", e.toChars());
+ if (e.op == TOK.slice)
+ return true;
+ if (e.op == TOK.arrayLiteral)
+ {
+ Type t = e.type.toBasetype();
+ while (t.ty == Tarray || t.ty == Tsarray)
+ t = t.nextOf().toBasetype();
+ return (t.ty != Tvoid);
+ }
+ Type tb = e.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (isUnaArrayOp(e.op))
+ {
+ return isArrayOpValid((cast(UnaExp)e).e1);
+ }
+ if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == TOK.assign)
+ {
+ BinExp be = cast(BinExp)e;
+ return isArrayOpValid(be.e1) && isArrayOpValid(be.e2);
+ }
+ if (e.op == TOK.construct)
+ {
+ BinExp be = cast(BinExp)e;
+ return be.e1.op == TOK.slice && isArrayOpValid(be.e2);
+ }
+ // if (e.op == TOK.call)
+ // {
+ // TODO: Decide if [] is required after arrayop calls.
+ // }
+ return false;
+ }
+ return true;
+}
+
+bool isNonAssignmentArrayOp(Expression e)
+{
+ if (e.op == TOK.slice)
+ return isNonAssignmentArrayOp((cast(SliceExp)e).e1);
+
+ Type tb = e.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ return (isUnaArrayOp(e.op) || isBinArrayOp(e.op));
+ }
+ return false;
+}
+
+bool checkNonAssignmentArrayOp(Expression e, bool suggestion = false)
+{
+ if (isNonAssignmentArrayOp(e))
+ {
+ const(char)* s = "";
+ if (suggestion)
+ s = " (possible missing [])";
+ e.error("array operation `%s` without destination memory not allowed%s", e.toChars(), s);
+ return true;
+ }
+ return false;
+}
+
+/***********************************
+ * Construct the array operation expression, call object._arrayOp!(tiargs)(args).
+ *
+ * Encode operand types and operations into tiargs using reverse polish notation (RPN) to preserve precedence.
+ * Unary operations are prefixed with "u" (e.g. "u~").
+ * Pass operand values (slices or scalars) as args.
+ *
+ * Scalar expression sub-trees of `e` are evaluated before calling
+ * into druntime to hoist them out of the loop. This is a valid
+ * evaluation order as the actual array operations have no
+ * side-effect.
+ * References:
+ * https://github.com/dlang/druntime/blob/master/src/object.d#L3944
+ * https://github.com/dlang/druntime/blob/master/src/core/internal/array/operations.d
+ */
+Expression arrayOp(BinExp e, Scope* sc)
+{
+ //printf("BinExp.arrayOp() %s\n", e.toChars());
+ Type tb = e.type.toBasetype();
+ assert(tb.ty == Tarray || tb.ty == Tsarray);
+ Type tbn = tb.nextOf().toBasetype();
+ if (tbn.ty == Tvoid)
+ {
+ e.error("cannot perform array operations on `void[]` arrays");
+ return ErrorExp.get();
+ }
+ if (!isArrayOpValid(e))
+ return arrayOpInvalidError(e);
+
+ auto tiargs = new Objects();
+ auto args = new Expressions();
+ buildArrayOp(sc, e, tiargs, args);
+
+ import dmd.dtemplate : TemplateDeclaration;
+ __gshared TemplateDeclaration arrayOp;
+ if (arrayOp is null)
+ {
+ // Create .object._arrayOp
+ Identifier idArrayOp = Identifier.idPool("_arrayOp");
+ Expression id = new IdentifierExp(e.loc, Id.empty);
+ id = new DotIdExp(e.loc, id, Id.object);
+ id = new DotIdExp(e.loc, id, idArrayOp);
+
+ id = id.expressionSemantic(sc);
+ if (auto te = id.isTemplateExp())
+ arrayOp = te.td;
+ else
+ ObjectNotFound(idArrayOp); // fatal error
+ }
+
+ auto fd = resolveFuncCall(e.loc, sc, arrayOp, tiargs, null, args, FuncResolveFlag.standard);
+ if (!fd || fd.errors)
+ return ErrorExp.get();
+ return new CallExp(e.loc, new VarExp(e.loc, fd, false), args).expressionSemantic(sc);
+}
+
+/// ditto
+Expression arrayOp(BinAssignExp e, Scope* sc)
+{
+ //printf("BinAssignExp.arrayOp() %s\n", toChars());
+
+ /* Check that the elements of e1 can be assigned to
+ */
+ Type tn = e.e1.type.toBasetype().nextOf();
+
+ if (tn && (!tn.isMutable() || !tn.isAssignable()))
+ {
+ e.error("slice `%s` is not mutable", e.e1.toChars());
+ if (e.op == TOK.addAssign)
+ checkPossibleAddCatError!(AddAssignExp, CatAssignExp)(e.isAddAssignExp);
+ return ErrorExp.get();
+ }
+ if (e.e1.op == TOK.arrayLiteral)
+ {
+ return e.e1.modifiableLvalue(sc, e.e1);
+ }
+
+ return arrayOp(cast(BinExp)e, sc);
+}
+
+/******************************************
+ * Convert the expression tree e to template and function arguments,
+ * using reverse polish notation (RPN) to encode order of operations.
+ * Encode operations as string arguments, using a "u" prefix for unary operations.
+ */
+private void buildArrayOp(Scope* sc, Expression e, Objects* tiargs, Expressions* args)
+{
+ extern (C++) final class BuildArrayOpVisitor : Visitor
+ {
+ alias visit = Visitor.visit;
+ Scope* sc;
+ Objects* tiargs;
+ Expressions* args;
+
+ public:
+ extern (D) this(Scope* sc, Objects* tiargs, Expressions* args)
+ {
+ this.sc = sc;
+ this.tiargs = tiargs;
+ this.args = args;
+ }
+
+ override void visit(Expression e)
+ {
+ tiargs.push(e.type);
+ args.push(e);
+ }
+
+ override void visit(SliceExp e)
+ {
+ visit(cast(Expression) e);
+ }
+
+ override void visit(CastExp e)
+ {
+ visit(cast(Expression) e);
+ }
+
+ override void visit(UnaExp e)
+ {
+ Type tb = e.type.toBasetype();
+ if (tb.ty != Tarray && tb.ty != Tsarray) // hoist scalar expressions
+ {
+ visit(cast(Expression) e);
+ }
+ else
+ {
+ // RPN, prefix unary ops with u
+ OutBuffer buf;
+ buf.writestring("u");
+ buf.writestring(Token.toString(e.op));
+ e.e1.accept(this);
+ tiargs.push(new StringExp(Loc.initial, buf.extractSlice()).expressionSemantic(sc));
+ }
+ }
+
+ override void visit(BinExp e)
+ {
+ Type tb = e.type.toBasetype();
+ if (tb.ty != Tarray && tb.ty != Tsarray) // hoist scalar expressions
+ {
+ visit(cast(Expression) e);
+ }
+ else
+ {
+ // RPN
+ e.e1.accept(this);
+ e.e2.accept(this);
+ tiargs.push(new StringExp(Loc.initial, Token.toString(e.op)).expressionSemantic(sc));
+ }
+ }
+ }
+
+ scope v = new BuildArrayOpVisitor(sc, tiargs, args);
+ e.accept(v);
+}
+
+/***********************************************
+ * Some implicit casting can be performed by the _arrayOp template.
+ * Params:
+ * tfrom = type converting from
+ * tto = type converting to
+ * Returns:
+ * true if can be performed by _arrayOp
+ */
+bool isArrayOpImplicitCast(TypeDArray tfrom, TypeDArray tto)
+{
+ const tyf = tfrom.nextOf().toBasetype().ty;
+ const tyt = tto .nextOf().toBasetype().ty;
+ return tyf == tyt ||
+ tyf == Tint32 && tyt == Tfloat64;
+}
+
+/***********************************************
+ * Test if expression is a unary array op.
+ */
+bool isUnaArrayOp(TOK op)
+{
+ switch (op)
+ {
+ case TOK.negate:
+ case TOK.tilde:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/***********************************************
+ * Test if expression is a binary array op.
+ */
+bool isBinArrayOp(TOK op)
+{
+ switch (op)
+ {
+ case TOK.add:
+ case TOK.min:
+ case TOK.mul:
+ case TOK.div:
+ case TOK.mod:
+ case TOK.xor:
+ case TOK.and:
+ case TOK.or:
+ case TOK.pow:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/***********************************************
+ * Test if expression is a binary assignment array op.
+ */
+bool isBinAssignArrayOp(TOK op)
+{
+ switch (op)
+ {
+ case TOK.addAssign:
+ case TOK.minAssign:
+ case TOK.mulAssign:
+ case TOK.divAssign:
+ case TOK.modAssign:
+ case TOK.xorAssign:
+ case TOK.andAssign:
+ case TOK.orAssign:
+ case TOK.powAssign:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/***********************************************
+ * Test if operand is a valid array op operand.
+ */
+bool isArrayOpOperand(Expression e)
+{
+ //printf("Expression.isArrayOpOperand() %s\n", e.toChars());
+ if (e.op == TOK.slice)
+ return true;
+ if (e.op == TOK.arrayLiteral)
+ {
+ Type t = e.type.toBasetype();
+ while (t.ty == Tarray || t.ty == Tsarray)
+ t = t.nextOf().toBasetype();
+ return (t.ty != Tvoid);
+ }
+ Type tb = e.type.toBasetype();
+ if (tb.ty == Tarray)
+ {
+ return (isUnaArrayOp(e.op) ||
+ isBinArrayOp(e.op) ||
+ isBinAssignArrayOp(e.op) ||
+ e.op == TOK.assign);
+ }
+ return false;
+}
+
+
+/***************************************************
+ * Print error message about invalid array operation.
+ * Params:
+ * e = expression with the invalid array operation
+ * Returns:
+ * instance of ErrorExp
+ */
+
+ErrorExp arrayOpInvalidError(Expression e)
+{
+ e.error("invalid array operation `%s` (possible missing [])", e.toChars());
+ if (e.op == TOK.add)
+ checkPossibleAddCatError!(AddExp, CatExp)(e.isAddExp());
+ else if (e.op == TOK.addAssign)
+ checkPossibleAddCatError!(AddAssignExp, CatAssignExp)(e.isAddAssignExp());
+ return ErrorExp.get();
+}
+
+private void checkPossibleAddCatError(AddT, CatT)(AddT ae)
+{
+ if (!ae.e2.type || ae.e2.type.ty != Tarray || !ae.e2.type.implicitConvTo(ae.e1.type))
+ return;
+ CatT ce = new CatT(ae.loc, ae.e1, ae.e2);
+ ae.errorSupplemental("did you mean to concatenate (`%s`) instead ?", ce.toChars());
+}
diff --git a/gcc/d/dmd/arraytypes.d b/gcc/d/dmd/arraytypes.d
new file mode 100644
index 0000000..b1f8d86
--- /dev/null
+++ b/gcc/d/dmd/arraytypes.d
@@ -0,0 +1,57 @@
+/**
+ * Provide aliases for arrays of certain declarations or statements.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/arraytypes.d, _arraytypes.d)
+ * Documentation: https://dlang.org/phobos/dmd_arraytypes.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/arraytypes.d
+ */
+
+module dmd.arraytypes;
+
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dmodule;
+import dmd.dsymbol;
+import dmd.dtemplate;
+import dmd.expression;
+import dmd.func;
+import dmd.identifier;
+import dmd.init;
+import dmd.mtype;
+import dmd.root.array;
+import dmd.root.rootobject;
+import dmd.statement;
+
+alias Strings = Array!(const(char)*);
+alias Identifiers = Array!(Identifier);
+alias TemplateParameters = Array!(TemplateParameter);
+alias Expressions = Array!(Expression);
+alias Statements = Array!(Statement);
+alias BaseClasses = Array!(BaseClass*);
+alias ClassDeclarations = Array!(ClassDeclaration);
+alias Dsymbols = Array!(Dsymbol);
+alias Objects = Array!(RootObject);
+alias DtorDeclarations = Array!(DtorDeclaration);
+alias FuncDeclarations = Array!(FuncDeclaration);
+alias Parameters = Array!(Parameter);
+alias Initializers = Array!(Initializer);
+alias VarDeclarations = Array!(VarDeclaration);
+alias Types = Array!(Type);
+alias Catches = Array!(Catch);
+alias StaticDtorDeclarations = Array!(StaticDtorDeclaration);
+alias SharedStaticDtorDeclarations = Array!(SharedStaticDtorDeclaration);
+alias AliasDeclarations = Array!(AliasDeclaration);
+alias Modules = Array!(Module);
+alias CaseStatements = Array!(CaseStatement);
+alias ScopeStatements = Array!(ScopeStatement);
+alias GotoCaseStatements = Array!(GotoCaseStatement);
+alias ReturnStatements = Array!(ReturnStatement);
+alias GotoStatements = Array!(GotoStatement);
+alias TemplateInstances = Array!(TemplateInstance);
+alias Ensures = Array!(Ensure);
+alias Designators = Array!(Designator);
+alias DesigInits = Array!(DesigInit);
+
diff --git a/gcc/d/dmd/arraytypes.h b/gcc/d/dmd/arraytypes.h
index 0ecccf1..602d890 100644
--- a/gcc/d/dmd/arraytypes.h
+++ b/gcc/d/dmd/arraytypes.h
@@ -27,6 +27,8 @@ typedef Array<class Dsymbol *> Dsymbols;
typedef Array<class RootObject *> Objects;
+typedef Array<class DtorDeclaration *> DtorDeclarations;
+
typedef Array<class FuncDeclaration *> FuncDeclarations;
typedef Array<class Parameter *> Parameters;
@@ -48,8 +50,6 @@ typedef Array<class AliasDeclaration *> AliasDeclarations;
typedef Array<class Module *> Modules;
-typedef Array<struct File *> Files;
-
typedef Array<class CaseStatement *> CaseStatements;
typedef Array<class ScopeStatement *> ScopeStatements;
@@ -63,3 +63,8 @@ typedef Array<class GotoStatement *> GotoStatements;
typedef Array<class TemplateInstance *> TemplateInstances;
typedef Array<struct Ensure> Ensures;
+
+typedef Array<struct Designator> Designators;
+
+typedef Array<struct DesigInit> DesigInits;
+
diff --git a/gcc/d/dmd/ast_node.d b/gcc/d/dmd/ast_node.d
new file mode 100644
index 0000000..82d62a0
--- /dev/null
+++ b/gcc/d/dmd/ast_node.d
@@ -0,0 +1,26 @@
+/**
+ * Defines the base class for all nodes which are part of the AST.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ast_node.d, _ast_node.d)
+ * Documentation: https://dlang.org/phobos/dmd_ast_node.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ast_node.d
+ */
+module dmd.ast_node;
+
+import dmd.root.rootobject : RootObject;
+import dmd.visitor : Visitor;
+
+/// The base class of all AST nodes.
+extern (C++) abstract class ASTNode : RootObject
+{
+ /**
+ * Visits this AST node using the given visitor.
+ *
+ * Params:
+ * v = the visitor to use when visiting this node
+ */
+ abstract void accept(Visitor v);
+}
diff --git a/gcc/d/dmd/astcodegen.d b/gcc/d/dmd/astcodegen.d
new file mode 100644
index 0000000..d40f836
--- /dev/null
+++ b/gcc/d/dmd/astcodegen.d
@@ -0,0 +1,102 @@
+/**
+ * Defines AST nodes for the code generation stage.
+ *
+ * Documentation: https://dlang.org/phobos/dmd_astcodegen.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/astcodegen.d
+ */
+module dmd.astcodegen;
+
+
+struct ASTCodegen
+{
+ public import dmd.aggregate;
+ public import dmd.aliasthis;
+ public import dmd.arraytypes;
+ public import dmd.attrib;
+ public import dmd.cond;
+ public import dmd.dclass;
+ public import dmd.declaration;
+ public import dmd.denum;
+ public import dmd.dimport;
+ public import dmd.dmodule;
+ public import dmd.dstruct;
+ public import dmd.dsymbol;
+ public import dmd.dtemplate;
+ public import dmd.dversion;
+ public import dmd.expression;
+ public import dmd.func;
+ public import dmd.hdrgen;
+ public import dmd.init;
+ public import dmd.initsem;
+ public import dmd.mtype;
+ public import dmd.nspace;
+ public import dmd.statement;
+ public import dmd.staticassert;
+ public import dmd.typesem;
+ public import dmd.ctfeexpr;
+ public import dmd.init : Designator;
+
+
+ alias initializerToExpression = dmd.initsem.initializerToExpression;
+ alias typeToExpression = dmd.typesem.typeToExpression;
+ alias UserAttributeDeclaration = dmd.attrib.UserAttributeDeclaration;
+ alias Ensure = dmd.func.Ensure; // workaround for bug in older DMD frontends
+ alias ErrorExp = dmd.expression.ErrorExp;
+
+ alias MODFlags = dmd.mtype.MODFlags;
+ alias Type = dmd.mtype.Type;
+ alias Parameter = dmd.mtype.Parameter;
+ alias Tarray = dmd.mtype.Tarray;
+ alias Taarray = dmd.mtype.Taarray;
+ alias Tbool = dmd.mtype.Tbool;
+ alias Tchar = dmd.mtype.Tchar;
+ alias Tdchar = dmd.mtype.Tdchar;
+ alias Tdelegate = dmd.mtype.Tdelegate;
+ alias Tenum = dmd.mtype.Tenum;
+ alias Terror = dmd.mtype.Terror;
+ alias Tfloat32 = dmd.mtype.Tfloat32;
+ alias Tfloat64 = dmd.mtype.Tfloat64;
+ alias Tfloat80 = dmd.mtype.Tfloat80;
+ alias Tfunction = dmd.mtype.Tfunction;
+ alias Tpointer = dmd.mtype.Tpointer;
+ alias Treference = dmd.mtype.Treference;
+ alias Tident = dmd.mtype.Tident;
+ alias Tint8 = dmd.mtype.Tint8;
+ alias Tint16 = dmd.mtype.Tint16;
+ alias Tint32 = dmd.mtype.Tint32;
+ alias Tint64 = dmd.mtype.Tint64;
+ alias Tsarray = dmd.mtype.Tsarray;
+ alias Tstruct = dmd.mtype.Tstruct;
+ alias Tuns8 = dmd.mtype.Tuns8;
+ alias Tuns16 = dmd.mtype.Tuns16;
+ alias Tuns32 = dmd.mtype.Tuns32;
+ alias Tuns64 = dmd.mtype.Tuns64;
+ alias Tvoid = dmd.mtype.Tvoid;
+ alias Twchar = dmd.mtype.Twchar;
+ alias Tnoreturn = dmd.mtype.Tnoreturn;
+
+ alias Timaginary32 = dmd.mtype.Timaginary32;
+ alias Timaginary64 = dmd.mtype.Timaginary64;
+ alias Timaginary80 = dmd.mtype.Timaginary80;
+ alias Tcomplex32 = dmd.mtype.Tcomplex32;
+ alias Tcomplex64 = dmd.mtype.Tcomplex64;
+ alias Tcomplex80 = dmd.mtype.Tcomplex80;
+
+ alias ParameterList = dmd.mtype.ParameterList;
+ alias VarArg = dmd.mtype.VarArg;
+ alias STC = dmd.declaration.STC;
+ alias Dsymbol = dmd.dsymbol.Dsymbol;
+ alias Dsymbols = dmd.dsymbol.Dsymbols;
+ alias Visibility = dmd.dsymbol.Visibility;
+
+ alias stcToBuffer = dmd.hdrgen.stcToBuffer;
+ alias linkageToChars = dmd.hdrgen.linkageToChars;
+ alias visibilityToChars = dmd.hdrgen.visibilityToChars;
+
+ alias isType = dmd.dtemplate.isType;
+ alias isExpression = dmd.dtemplate.isExpression;
+ alias isTuple = dmd.dtemplate.isTuple;
+
+ alias IgnoreErrors = dmd.dsymbol.IgnoreErrors;
+ alias PASS = dmd.dsymbol.PASS;
+}
diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d
new file mode 100644
index 0000000..df88bb9
--- /dev/null
+++ b/gcc/d/dmd/astenums.d
@@ -0,0 +1,391 @@
+/**
+ * Defines enums common to dmd and dmd as parse library.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/astenums.d, _astenums.d)
+ * Documentation: https://dlang.org/phobos/dmd_astenums.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/astenums.d
+ */
+
+module dmd.astenums;
+
+enum Sizeok : ubyte
+{
+ none, /// size of aggregate is not yet able to compute
+ fwd, /// size of aggregate is ready to compute
+ inProcess, /// in the midst of computing the size
+ done, /// size of aggregate is set correctly
+}
+
+enum Baseok : ubyte
+{
+ none, /// base classes not computed yet
+ start, /// in process of resolving base classes
+ done, /// all base classes are resolved
+ semanticdone, /// all base classes semantic done
+}
+
+enum MODFlags : int
+{
+ const_ = 1, // type is const
+ immutable_ = 4, // type is immutable
+ shared_ = 2, // type is shared
+ wild = 8, // type is wild
+ wildconst = (MODFlags.wild | MODFlags.const_), // type is wild const
+ mutable = 0x10, // type is mutable (only used in wildcard matching)
+}
+
+alias MOD = ubyte;
+
+enum STC : ulong // transfer changes to declaration.h
+{
+ undefined_ = 0,
+
+ static_ = 1, /// `static`
+ extern_ = 2, /// `extern`
+ const_ = 4, /// `const`
+ final_ = 8, /// `final`
+
+ abstract_ = 0x10, /// `abstract`
+ parameter = 0x20, /// is function parameter
+ field = 0x40, /// is field of struct, union or class
+ override_ = 0x80, /// `override`
+
+ auto_ = 0x100, /// `auto`
+ synchronized_ = 0x200, /// `synchronized`
+ deprecated_ = 0x400, /// `deprecated`
+ in_ = 0x800, /// `in` parameter
+
+ out_ = 0x1000, /// `out` parameter
+ lazy_ = 0x2000, /// `lazy` parameter
+ foreach_ = 0x4000, /// variable for foreach loop
+ variadic = 0x8000, /// the `variadic` parameter in: T foo(T a, U b, V variadic...)
+
+ ctorinit = 0x1_0000, /// can only be set inside constructor
+ templateparameter = 0x2_0000, /// template parameter
+ ref_ = 0x4_0000, /// `ref`
+ scope_ = 0x8_0000, /// `scope`
+
+ maybescope = 0x10_0000, /// parameter might be `scope`
+ scopeinferred = 0x20_0000, /// `scope` has been inferred and should not be part of mangling, `scope_` must also be set
+ return_ = 0x40_0000, /// 'return ref' or 'return scope' for function parameters
+ returnScope = 0x80_0000, /// if `ref return scope` then resolve to `ref` and `return scope`
+
+ returninferred = 0x100_0000, /// `return` has been inferred and should not be part of mangling, `return_` must also be set
+ immutable_ = 0x200_0000, /// `immutable`
+ init = 0x400_0000, /// has explicit initializer
+ manifest = 0x800_0000, /// manifest constant
+
+ nodtor = 0x1000_0000, /// do not run destructor
+ nothrow_ = 0x2000_0000, /// `nothrow` meaning never throws exceptions
+ pure_ = 0x4000_0000, /// `pure` function
+ tls = 0x8000_0000, /// thread local
+
+ alias_ = 0x1_0000_0000, /// `alias` parameter
+ shared_ = 0x2_0000_0000, /// accessible from multiple threads
+ gshared = 0x4_0000_0000, /// accessible from multiple threads, but not typed as `shared`
+ wild = 0x8_0000_0000, /// for wild type constructor
+
+ property = 0x10_0000_0000, /// `@property`
+ safe = 0x20_0000_0000, /// `@safe`
+ trusted = 0x40_0000_0000, /// `@trusted`
+ system = 0x80_0000_0000, /// `@system`
+
+ ctfe = 0x100_0000_0000, /// can be used in CTFE, even if it is static
+ disable = 0x200_0000_0000, /// for functions that are not callable
+ result = 0x400_0000_0000, /// for result variables passed to out contracts
+ nodefaultctor = 0x800_0000_0000, /// must be set inside constructor
+
+ temp = 0x1000_0000_0000, /// temporary variable
+ rvalue = 0x2000_0000_0000, /// force rvalue for variables
+ nogc = 0x4000_0000_0000, /// `@nogc`
+ autoref = 0x8000_0000_0000, /// Mark for the already deduced `auto ref` parameter
+
+ inference = 0x1_0000_0000_0000, /// do attribute inference
+ exptemp = 0x2_0000_0000_0000, /// temporary variable that has lifetime restricted to an expression
+ future = 0x4_0000_0000_0000, /// introducing new base class function
+ local = 0x8_0000_0000_0000, /// do not forward (see dmd.dsymbol.ForwardingScopeDsymbol).
+
+ live = 0x10_0000_0000_0000, /// function `@live` attribute
+ register = 0x20_0000_0000_0000, /// `register` storage class (ImportC)
+ volatile_ = 0x40_0000_0000_0000, /// destined for volatile in the back end
+
+ safeGroup = STC.safe | STC.trusted | STC.system,
+ IOR = STC.in_ | STC.ref_ | STC.out_,
+ TYPECTOR = (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild),
+ FUNCATTR = (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.property | STC.live |
+ safeGroup),
+
+ /* These are visible to the user, i.e. are expressed by the user
+ */
+ visibleStorageClasses =
+ (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.const_ | STC.final_ | STC.abstract_ | STC.synchronized_ |
+ STC.deprecated_ | STC.future | STC.override_ | STC.lazy_ | STC.alias_ | STC.out_ | STC.in_ | STC.manifest |
+ STC.immutable_ | STC.shared_ | STC.wild | STC.nothrow_ | STC.nogc | STC.pure_ | STC.ref_ | STC.return_ | STC.tls | STC.gshared |
+ STC.property | STC.safeGroup | STC.disable | STC.local | STC.live),
+
+ /* These storage classes "flow through" to the inner scope of a Dsymbol
+ */
+ flowThruAggregate = STC.safeGroup, /// for an AggregateDeclaration
+ flowThruFunction = ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.abstract_ | STC.deprecated_ | STC.override_ |
+ STC.TYPECTOR | STC.final_ | STC.tls | STC.gshared | STC.ref_ | STC.return_ | STC.property |
+ STC.nothrow_ | STC.pure_ | STC.safe | STC.trusted | STC.system), /// for a FuncDeclaration
+
+}
+
+/********
+ * Determine if it's the ambigous case of where `return` attaches to.
+ * Params:
+ * stc = STC flags
+ * Returns:
+ * true if (`ref` | `out`) and `scope` and `return`
+ */
+@safe pure @nogc nothrow
+bool isRefReturnScope(const ulong stc)
+{
+ return (stc & (STC.scope_ | STC.return_)) == (STC.scope_ | STC.return_) &&
+ stc & (STC.ref_ | STC.out_);
+}
+
+/* This is different from the one in declaration.d, make that fix a separate PR */
+static if (0)
+extern (C++) __gshared const(StorageClass) STCStorageClass =
+ (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.const_ | STC.final_ |
+ STC.abstract_ | STC.synchronized_ | STC.deprecated_ | STC.override_ | STC.lazy_ |
+ STC.alias_ | STC.out_ | STC.in_ | STC.manifest | STC.immutable_ | STC.shared_ |
+ STC.wild | STC.nothrow_ | STC.nogc | STC.pure_ | STC.ref_ | STC.return_ | STC.tls |
+ STC.gshared | STC.property | STC.live |
+ STC.safeGroup | STC.disable);
+
+enum TY : ubyte
+{
+ Tarray, // slice array, aka T[]
+ Tsarray, // static array, aka T[dimension]
+ Taarray, // associative array, aka T[type]
+ Tpointer,
+ Treference,
+ Tfunction,
+ Tident,
+ Tclass,
+ Tstruct,
+ Tenum,
+
+ Tdelegate,
+ Tnone,
+ Tvoid,
+ Tint8,
+ Tuns8,
+ Tint16,
+ Tuns16,
+ Tint32,
+ Tuns32,
+ Tint64,
+
+ Tuns64,
+ Tfloat32,
+ Tfloat64,
+ Tfloat80,
+ Timaginary32,
+ Timaginary64,
+ Timaginary80,
+ Tcomplex32,
+ Tcomplex64,
+ Tcomplex80,
+
+ Tbool,
+ Tchar,
+ Twchar,
+ Tdchar,
+ Terror,
+ Tinstance,
+ Ttypeof,
+ Ttuple,
+ Tslice,
+ Treturn,
+
+ Tnull,
+ Tvector,
+ Tint128,
+ Tuns128,
+ Ttraits,
+ Tmixin,
+ Tnoreturn,
+ Ttag,
+ TMAX
+}
+
+alias Tarray = TY.Tarray;
+alias Tsarray = TY.Tsarray;
+alias Taarray = TY.Taarray;
+alias Tpointer = TY.Tpointer;
+alias Treference = TY.Treference;
+alias Tfunction = TY.Tfunction;
+alias Tident = TY.Tident;
+alias Tclass = TY.Tclass;
+alias Tstruct = TY.Tstruct;
+alias Tenum = TY.Tenum;
+alias Tdelegate = TY.Tdelegate;
+alias Tnone = TY.Tnone;
+alias Tvoid = TY.Tvoid;
+alias Tint8 = TY.Tint8;
+alias Tuns8 = TY.Tuns8;
+alias Tint16 = TY.Tint16;
+alias Tuns16 = TY.Tuns16;
+alias Tint32 = TY.Tint32;
+alias Tuns32 = TY.Tuns32;
+alias Tint64 = TY.Tint64;
+alias Tuns64 = TY.Tuns64;
+alias Tfloat32 = TY.Tfloat32;
+alias Tfloat64 = TY.Tfloat64;
+alias Tfloat80 = TY.Tfloat80;
+alias Timaginary32 = TY.Timaginary32;
+alias Timaginary64 = TY.Timaginary64;
+alias Timaginary80 = TY.Timaginary80;
+alias Tcomplex32 = TY.Tcomplex32;
+alias Tcomplex64 = TY.Tcomplex64;
+alias Tcomplex80 = TY.Tcomplex80;
+alias Tbool = TY.Tbool;
+alias Tchar = TY.Tchar;
+alias Twchar = TY.Twchar;
+alias Tdchar = TY.Tdchar;
+alias Terror = TY.Terror;
+alias Tinstance = TY.Tinstance;
+alias Ttypeof = TY.Ttypeof;
+alias Ttuple = TY.Ttuple;
+alias Tslice = TY.Tslice;
+alias Treturn = TY.Treturn;
+alias Tnull = TY.Tnull;
+alias Tvector = TY.Tvector;
+alias Tint128 = TY.Tint128;
+alias Tuns128 = TY.Tuns128;
+alias Ttraits = TY.Ttraits;
+alias Tmixin = TY.Tmixin;
+alias Tnoreturn = TY.Tnoreturn;
+alias Ttag = TY.Ttag;
+alias TMAX = TY.TMAX;
+
+enum TFlags
+{
+ integral = 1,
+ floating = 2,
+ unsigned = 4,
+ real_ = 8,
+ imaginary = 0x10,
+ complex = 0x20,
+}
+
+enum PKG : int
+{
+ unknown, /// not yet determined whether it's a package.d or not
+ module_, /// already determined that's an actual package.d
+ package_, /// already determined that's an actual package
+}
+
+enum ThreeState : ubyte
+{
+ none, /// state is not yet computed
+ no, /// state is false
+ yes, /// state is true
+}
+
+enum TRUST : ubyte
+{
+ default_ = 0,
+ system = 1, // @system (same as TRUST.default)
+ trusted = 2, // @trusted
+ safe = 3, // @safe
+}
+
+enum PURE : ubyte
+{
+ impure = 0, // not pure at all
+ fwdref = 1, // it's pure, but not known which level yet
+ weak = 2, // no mutable globals are read or written
+ const_ = 3, // parameters are values or const
+ strong = 4, // parameters are values or immutable
+}
+
+// Whether alias this dependency is recursive or not
+enum AliasThisRec : int
+{
+ no = 0, // no alias this recursion
+ yes = 1, // alias this has recursive dependency
+ fwdref = 2, // not yet known
+ typeMask = 3, // mask to read no/yes/fwdref
+ tracing = 0x4, // mark in progress of implicitConvTo/deduceWild
+ tracingDT = 0x8, // mark in progress of deduceType
+}
+
+/***************
+ * Variadic argument lists
+ * https://dlang.org/spec/function.html#variadic
+ */
+enum VarArg : ubyte
+{
+ none = 0, /// fixed number of arguments
+ variadic = 1, /// (T t, ...) can be C-style (core.stdc.stdarg) or D-style (core.vararg)
+ typesafe = 2, /// (T t ...) typesafe https://dlang.org/spec/function.html#typesafe_variadic_functions
+ /// or https://dlang.org/spec/function.html#typesafe_variadic_functions
+}
+
+/*************************
+ * Identify Statement types with this enum rather than
+ * virtual functions
+ */
+enum STMT : ubyte
+{
+ Error,
+ Peel,
+ Exp, DtorExp,
+ Compile,
+ Compound, CompoundDeclaration, CompoundAsm,
+ UnrolledLoop,
+ Scope,
+ Forwarding,
+ While,
+ Do,
+ For,
+ Foreach,
+ ForeachRange,
+ If,
+ Conditional,
+ StaticForeach,
+ Pragma,
+ StaticAssert,
+ Switch,
+ Case,
+ CaseRange,
+ Default,
+ GotoDefault,
+ GotoCase,
+ SwitchError,
+ Return,
+ Break,
+ Continue,
+ Synchronized,
+ With,
+ TryCatch,
+ TryFinally,
+ ScopeGuard,
+ Throw,
+ Debug,
+ Goto,
+ Label,
+ Asm, InlineAsm, GccAsm,
+ Import,
+}
+
+/**********************
+ * Discriminant for which kind of initializer
+ */
+enum InitKind : ubyte
+{
+ void_,
+ error,
+ struct_,
+ array,
+ exp,
+ C_,
+}
+
diff --git a/gcc/d/dmd/attrib.c b/gcc/d/dmd/attrib.c
deleted file mode 100644
index a808b8a..0000000
--- a/gcc/d/dmd/attrib.c
+++ /dev/null
@@ -1,1320 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/attrib.c
- */
-
-#include "root/dsystem.h" // memcmp()
-#include "root/rmem.h"
-
-#include "mars.h"
-#include "init.h"
-#include "declaration.h"
-#include "attrib.h"
-#include "cond.h"
-#include "scope.h"
-#include "id.h"
-#include "expression.h"
-#include "dsymbol.h"
-#include "aggregate.h"
-#include "module.h"
-#include "parse.h"
-#include "target.h"
-#include "template.h"
-#include "utf.h"
-#include "mtype.h"
-
-bool definitelyValueParameter(Expression *e);
-Dsymbols *makeTupleForeachStaticDecl(Scope *sc, ForeachStatement *fs, Dsymbols *dbody, bool needExpansion);
-
-/********************************* AttribDeclaration ****************************/
-
-AttribDeclaration::AttribDeclaration(Dsymbols *decl)
- : Dsymbol()
-{
- this->decl = decl;
-}
-
-Dsymbols *AttribDeclaration::include(Scope *)
-{
- if (errors)
- return NULL;
-
- return decl;
-}
-
-int AttribDeclaration::apply(Dsymbol_apply_ft_t fp, void *param)
-{
- Dsymbols *d = include(_scope);
-
- if (d)
- {
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- if (s)
- {
- if (s->apply(fp, param))
- return 1;
- }
- }
- }
- return 0;
-}
-
-/****************************************
- * Create a new scope if one or more given attributes
- * are different from the sc's.
- * If the returned scope != sc, the caller should pop
- * the scope after it used.
- */
-Scope *AttribDeclaration::createNewScope(Scope *sc,
- StorageClass stc, LINK linkage, CPPMANGLE cppmangle, Prot protection,
- int explicitProtection, AlignDeclaration *aligndecl, PINLINE inlining)
-{
- Scope *sc2 = sc;
- if (stc != sc->stc ||
- linkage != sc->linkage ||
- cppmangle != sc->cppmangle ||
- explicitProtection != sc->explicitProtection ||
- !(protection == sc->protection) ||
- aligndecl != sc->aligndecl ||
- inlining != sc->inlining)
- {
- // create new one for changes
- sc2 = sc->copy();
- sc2->stc = stc;
- sc2->linkage = linkage;
- sc2->cppmangle = cppmangle;
- sc2->protection = protection;
- sc2->explicitProtection = explicitProtection;
- sc2->aligndecl = aligndecl;
- sc2->inlining = inlining;
- }
- return sc2;
-}
-
-/****************************************
- * A hook point to supply scope for members.
- * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
- */
-Scope *AttribDeclaration::newScope(Scope *sc)
-{
- return sc;
-}
-
-void AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
-{
- Dsymbols *d = include(sc);
-
- if (d)
- {
- Scope *sc2 = newScope(sc);
-
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- //printf("\taddMember %s to %s\n", s->toChars(), sds->toChars());
- s->addMember(sc2, sds);
- }
-
- if (sc2 != sc)
- sc2->pop();
- }
-}
-
-void AttribDeclaration::setScope(Scope *sc)
-{
- Dsymbols *d = include(sc);
-
- //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d);
- if (d)
- {
- Scope *sc2 = newScope(sc);
-
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->setScope(sc2);
- }
-
- if (sc2 != sc)
- sc2->pop();
- }
-}
-
-void AttribDeclaration::importAll(Scope *sc)
-{
- Dsymbols *d = include(sc);
-
- //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
- if (d)
- {
- Scope *sc2 = newScope(sc);
-
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->importAll(sc2);
- }
-
- if (sc2 != sc)
- sc2->pop();
- }
-}
-
-void AttribDeclaration::addComment(const utf8_t *comment)
-{
- //printf("AttribDeclaration::addComment %s\n", comment);
- if (comment)
- {
- Dsymbols *d = include(NULL);
-
- if (d)
- {
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- //printf("AttribDeclaration::addComment %s\n", s->toChars());
- s->addComment(comment);
- }
- }
- }
-}
-
-void AttribDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
-{
- Dsymbols *d = include(NULL);
-
- if (d)
- {
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->setFieldOffset(ad, poffset, isunion);
- }
- }
-}
-
-bool AttribDeclaration::hasPointers()
-{
- Dsymbols *d = include(NULL);
-
- if (d)
- {
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- if (s->hasPointers())
- return true;
- }
- }
- return false;
-}
-
-bool AttribDeclaration::hasStaticCtorOrDtor()
-{
- Dsymbols *d = include(NULL);
-
- if (d)
- {
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- if (s->hasStaticCtorOrDtor())
- return true;
- }
- }
- return false;
-}
-
-const char *AttribDeclaration::kind() const
-{
- return "attribute";
-}
-
-bool AttribDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
-{
- Dsymbols *d = include(NULL);
-
- return Dsymbol::oneMembers(d, ps, ident);
-}
-
-void AttribDeclaration::checkCtorConstInit()
-{
- Dsymbols *d = include(NULL);
-
- if (d)
- {
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->checkCtorConstInit();
- }
- }
-}
-
-/****************************************
- */
-
-void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses)
-{
- Dsymbols *d = include(NULL);
-
- if (d)
- {
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->addLocalClass(aclasses);
- }
- }
-}
-
-/************************* StorageClassDeclaration ****************************/
-
-StorageClassDeclaration::StorageClassDeclaration(StorageClass stc, Dsymbols *decl)
- : AttribDeclaration(decl)
-{
- this->stc = stc;
-}
-
-Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- return new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl));
-}
-
-bool StorageClassDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
-{
- bool t = Dsymbol::oneMembers(decl, ps, ident);
- if (t && *ps)
- {
- /* This is to deal with the following case:
- * struct Tick {
- * template to(T) { const T to() { ... } }
- * }
- * For eponymous function templates, the 'const' needs to get attached to 'to'
- * before the semantic analysis of 'to', so that template overloading based on the
- * 'this' pointer can be successful.
- */
-
- FuncDeclaration *fd = (*ps)->isFuncDeclaration();
- if (fd)
- {
- /* Use storage_class2 instead of storage_class otherwise when we do .di generation
- * we'll wind up with 'const const' rather than 'const'.
- */
- /* Don't think we need to worry about mutually exclusive storage classes here
- */
- fd->storage_class2 |= stc;
- }
- }
- return t;
-}
-
-void StorageClassDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
-{
- Dsymbols *d = include(sc);
- if (d)
- {
- Scope *sc2 = newScope(sc);
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- //printf("\taddMember %s to %s\n", s->toChars(), sds->toChars());
- // STClocal needs to be attached before the member is added to the scope (because it influences the parent symbol)
- if (Declaration *decl = s->isDeclaration())
- {
- decl->storage_class |= stc & STClocal;
- if (StorageClassDeclaration *sdecl = s->isStorageClassDeclaration())
- {
- sdecl->stc |= stc & STClocal;
- }
- }
- s->addMember(sc2, sds);
- }
- if (sc2 != sc)
- sc2->pop();
- }
-}
-
-Scope *StorageClassDeclaration::newScope(Scope *sc)
-{
- StorageClass scstc = sc->stc;
-
- /* These sets of storage classes are mutually exclusive,
- * so choose the innermost or most recent one.
- */
- if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest))
- scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest);
- if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared))
- scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared);
- if (stc & (STCconst | STCimmutable | STCmanifest))
- scstc &= ~(STCconst | STCimmutable | STCmanifest);
- if (stc & (STCgshared | STCshared | STCtls))
- scstc &= ~(STCgshared | STCshared | STCtls);
- if (stc & (STCsafe | STCtrusted | STCsystem))
- scstc &= ~(STCsafe | STCtrusted | STCsystem);
- scstc |= stc;
- //printf("scstc = x%llx\n", scstc);
-
- return createNewScope(sc, scstc, sc->linkage, sc->cppmangle,
- sc->protection, sc->explicitProtection, sc->aligndecl,
- sc->inlining);
-}
-
-/********************************* DeprecatedDeclaration ****************************/
-
-DeprecatedDeclaration::DeprecatedDeclaration(Expression *msg, Dsymbols *decl)
- : StorageClassDeclaration(STCdeprecated, decl)
-{
- this->msg = msg;
- this->msgstr = NULL;
-}
-
-Dsymbol *DeprecatedDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- return new DeprecatedDeclaration(msg->syntaxCopy(), Dsymbol::arraySyntaxCopy(decl));
-}
-
-/**
- * Provides a new scope with `STCdeprecated` and `Scope.depdecl` set
- *
- * Calls `StorageClassDeclaration.newScope` (as it must be called or copied
- * in any function overriding `newScope`), then set the `Scope`'s depdecl.
- *
- * Returns:
- * Always a new scope, to use for this `DeprecatedDeclaration`'s members.
- */
-Scope *DeprecatedDeclaration::newScope(Scope *sc)
-{
- Scope *scx = StorageClassDeclaration::newScope(sc);
- // The enclosing scope is deprecated as well
- if (scx == sc)
- scx = sc->push();
- scx->depdecl = this;
- return scx;
-}
-
-void DeprecatedDeclaration::setScope(Scope *sc)
-{
- //printf("DeprecatedDeclaration::setScope() %p\n", this);
- if (decl)
- Dsymbol::setScope(sc); // for forward reference
- return AttribDeclaration::setScope(sc);
-}
-
-const char *DeprecatedDeclaration::getMessage()
-{
- if (Scope *sc = _scope)
- {
- _scope = NULL;
-
- sc = sc->startCTFE();
- msg = expressionSemantic(msg, sc);
- msg = resolveProperties(sc, msg);
- sc = sc->endCTFE();
- msg = msg->ctfeInterpret();
-
- if (StringExp *se = msg->toStringExp())
- msgstr = (char *)se->string;
- else
- msg->error("compile time constant expected, not `%s`", msg->toChars());
- }
- return msgstr;
-}
-
-/********************************* LinkDeclaration ****************************/
-
-LinkDeclaration::LinkDeclaration(LINK p, Dsymbols *decl)
- : AttribDeclaration(decl)
-{
- //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl);
- linkage = (p == LINKsystem) ? target.systemLinkage() : p;
-}
-
-LinkDeclaration *LinkDeclaration::create(LINK p, Dsymbols *decl)
-{
- return new LinkDeclaration(p, decl);
-}
-
-Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- return new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl));
-}
-
-Scope *LinkDeclaration::newScope(Scope *sc)
-{
- return createNewScope(sc, sc->stc, this->linkage, sc->cppmangle,
- sc->protection, sc->explicitProtection, sc->aligndecl,
- sc->inlining);
-}
-
-const char *LinkDeclaration::toChars()
-{
- return "extern ()";
-}
-
-/********************************* CPPMangleDeclaration ****************************/
-
-CPPMangleDeclaration::CPPMangleDeclaration(CPPMANGLE p, Dsymbols *decl)
- : AttribDeclaration(decl)
-{
- //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", p, decl);
- cppmangle = p;
-}
-
-Dsymbol *CPPMangleDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- return new CPPMangleDeclaration(cppmangle, Dsymbol::arraySyntaxCopy(decl));
-}
-
-Scope *CPPMangleDeclaration::newScope(Scope *sc)
-{
- return createNewScope(sc, sc->stc, LINKcpp, this->cppmangle,
- sc->protection, sc->explicitProtection, sc->aligndecl,
- sc->inlining);
-}
-
-const char *CPPMangleDeclaration::toChars()
-{
- return "extern ()";
-}
-
-/********************************* ProtDeclaration ****************************/
-
-/**
- * Params:
- * loc = source location of attribute token
- * p = protection attribute data
- * decl = declarations which are affected by this protection attribute
- */
-ProtDeclaration::ProtDeclaration(Loc loc, Prot p, Dsymbols *decl)
- : AttribDeclaration(decl)
-{
- this->loc = loc;
- this->protection = p;
- this->pkg_identifiers = NULL;
- //printf("decl = %p\n", decl);
-}
-
-/**
- * Params:
- * loc = source location of attribute token
- * pkg_identifiers = list of identifiers for a qualified package name
- * decl = declarations which are affected by this protection attribute
- */
-ProtDeclaration::ProtDeclaration(Loc loc, Identifiers* pkg_identifiers, Dsymbols *decl)
- : AttribDeclaration(decl)
-{
- this->loc = loc;
- this->protection.kind = Prot::package_;
- this->protection.pkg = NULL;
- this->pkg_identifiers = pkg_identifiers;
-}
-
-Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- if (protection.kind == Prot::package_)
- return new ProtDeclaration(this->loc, pkg_identifiers, Dsymbol::arraySyntaxCopy(decl));
- else
- return new ProtDeclaration(this->loc, protection, Dsymbol::arraySyntaxCopy(decl));
-}
-
-Scope *ProtDeclaration::newScope(Scope *sc)
-{
- if (pkg_identifiers)
- dsymbolSemantic(this, sc);
- return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle,
- this->protection, 1, sc->aligndecl,
- sc->inlining);
-}
-
-void ProtDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
-{
- if (pkg_identifiers)
- {
- Dsymbol* tmp;
- Package::resolve(pkg_identifiers, &tmp, NULL);
- protection.pkg = tmp ? tmp->isPackage() : NULL;
- pkg_identifiers = NULL;
- }
-
- if (protection.kind == Prot::package_ && protection.pkg && sc->_module)
- {
- Module *m = sc->_module;
-
- // While isAncestorPackageOf does an equality check, the fix for issue 17441 adds a check to see if
- // each package's .isModule() properites are equal.
- //
- // Properties generated from `package(foo)` i.e. protection.pkg have .isModule() == null.
- // This breaks package declarations of the package in question if they are declared in
- // the same package.d file, which _do_ have a module associated with them, and hence a non-null
- // isModule()
- if (!m->isPackage() || !protection.pkg->ident->equals(m->isPackage()->ident))
- {
- Package* pkg = m->parent ? m->parent->isPackage() : NULL;
- if (!pkg || !protection.pkg->isAncestorPackageOf(pkg))
- error("does not bind to one of ancestor packages of module `%s`",
- m->toPrettyChars(true));
- }
- }
-
- return AttribDeclaration::addMember(sc, sds);
-}
-
-const char *ProtDeclaration::kind() const
-{
- return "protection attribute";
-}
-
-const char *ProtDeclaration::toPrettyChars(bool)
-{
- assert(protection.kind > Prot::undefined);
-
- OutBuffer buf;
- buf.writeByte('\'');
- protectionToBuffer(&buf, protection);
- buf.writeByte('\'');
- return buf.extractChars();
-}
-
-/********************************* AlignDeclaration ****************************/
-
-AlignDeclaration::AlignDeclaration(Loc loc, Expression *ealign, Dsymbols *decl)
- : AttribDeclaration(decl)
-{
- this->loc = loc;
- this->ealign = ealign;
- this->salign = 0;
-}
-
-Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- return new AlignDeclaration(loc,
- ealign ? ealign->syntaxCopy() : NULL,
- Dsymbol::arraySyntaxCopy(decl));
-}
-
-Scope *AlignDeclaration::newScope(Scope *sc)
-{
- return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle,
- sc->protection, sc->explicitProtection, this,
- sc->inlining);
-}
-
-structalign_t AlignDeclaration::getAlignment(Scope *sc)
-{
- if (salign != 0)
- return salign;
-
- if (!ealign)
- return salign = STRUCTALIGN_DEFAULT;
-
- sc = sc->startCTFE();
- ealign = expressionSemantic(ealign, sc);
- ealign = resolveProperties(sc, ealign);
- sc = sc->endCTFE();
- ealign = ealign->ctfeInterpret();
-
- if (ealign->op == TOKerror)
- return salign = STRUCTALIGN_DEFAULT;
-
- Type *tb = ealign->type->toBasetype();
- sinteger_t n = ealign->toInteger();
-
- if (n < 1 || n & (n - 1) || STRUCTALIGN_DEFAULT < n || !tb->isintegral())
- {
- ::error(loc, "alignment must be an integer positive power of 2, not %s", ealign->toChars());
- return salign = STRUCTALIGN_DEFAULT;
- }
-
- return salign = (structalign_t)n;
-}
-
-/********************************* AnonDeclaration ****************************/
-
-AnonDeclaration::AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl)
- : AttribDeclaration(decl)
-{
- this->loc = loc;
- this->isunion = isunion;
- this->sem = 0;
- this->anonoffset = 0;
- this->anonstructsize = 0;
- this->anonalignsize = 0;
-}
-
-Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- return new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl));
-}
-
-void AnonDeclaration::setScope(Scope *sc)
-{
- //printf("AnonDeclaration::setScope() %p\n", this);
- if (decl)
- Dsymbol::setScope(sc);
- AttribDeclaration::setScope(sc);
-}
-
-void AnonDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
-{
- //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
-
- if (decl)
- {
- /* This works by treating an AnonDeclaration as an aggregate 'member',
- * so in order to place that member we need to compute the member's
- * size and alignment.
- */
-
- size_t fieldstart = ad->fields.length;
-
- /* Hackishly hijack ad's structsize and alignsize fields
- * for use in our fake anon aggregate member.
- */
- unsigned savestructsize = ad->structsize;
- unsigned savealignsize = ad->alignsize;
- ad->structsize = 0;
- ad->alignsize = 0;
-
- unsigned offset = 0;
- for (size_t i = 0; i < decl->length; i++)
- {
- Dsymbol *s = (*decl)[i];
- s->setFieldOffset(ad, &offset, this->isunion);
- if (this->isunion)
- offset = 0;
- }
-
- /* Bugzilla 13613: If the fields in this->members had been already
- * added in ad->fields, just update *poffset for the subsequent
- * field offset calculation.
- */
- if (fieldstart == ad->fields.length)
- {
- ad->structsize = savestructsize;
- ad->alignsize = savealignsize;
- *poffset = ad->structsize;
- return;
- }
-
- anonstructsize = ad->structsize;
- anonalignsize = ad->alignsize;
- ad->structsize = savestructsize;
- ad->alignsize = savealignsize;
-
- // 0 sized structs are set to 1 byte
- // TODO: is this corect hebavior?
- if (anonstructsize == 0)
- {
- anonstructsize = 1;
- anonalignsize = 1;
- }
-
- assert(_scope);
- structalign_t alignment = _scope->alignment();
-
- /* Given the anon 'member's size and alignment,
- * go ahead and place it.
- */
- anonoffset = AggregateDeclaration::placeField(
- poffset,
- anonstructsize, anonalignsize, alignment,
- &ad->structsize, &ad->alignsize,
- isunion);
-
- // Add to the anon fields the base offset of this anonymous aggregate
- //printf("anon fields, anonoffset = %d\n", anonoffset);
- for (size_t i = fieldstart; i < ad->fields.length; i++)
- {
- VarDeclaration *v = ad->fields[i];
- //printf("\t[%d] %s %d\n", i, v->toChars(), v->offset);
- v->offset += anonoffset;
- }
- }
-}
-
-const char *AnonDeclaration::kind() const
-{
- return (isunion ? "anonymous union" : "anonymous struct");
-}
-
-/********************************* PragmaDeclaration ****************************/
-
-PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl)
- : AttribDeclaration(decl)
-{
- this->loc = loc;
- this->ident = ident;
- this->args = args;
-}
-
-Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s)
-{
- //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
- assert(!s);
- return new PragmaDeclaration(loc, ident,
- Expression::arraySyntaxCopy(args),
- Dsymbol::arraySyntaxCopy(decl));
-}
-
-Scope *PragmaDeclaration::newScope(Scope *sc)
-{
- if (ident == Id::Pinline)
- {
- PINLINE inlining = PINLINEdefault;
- if (!args || args->length == 0)
- inlining = PINLINEdefault;
- else if (args->length != 1)
- {
- error("one boolean expression expected for pragma(inline), not %d", args->length);
- args->setDim(1);
- (*args)[0] = new ErrorExp();
- }
- else
- {
- Expression *e = (*args)[0];
-
- if (e->op != TOKint64 || !e->type->equals(Type::tbool))
- {
- if (e->op != TOKerror)
- {
- error("pragma(inline, true or false) expected, not %s", e->toChars());
- (*args)[0] = new ErrorExp();
- }
- }
- else if (e->isBool(true))
- inlining = PINLINEalways;
- else if (e->isBool(false))
- inlining = PINLINEnever;
- }
-
- return createNewScope(sc, sc->stc, sc->linkage, sc->cppmangle,
- sc->protection, sc->explicitProtection, sc->aligndecl,
- inlining);
- }
- if (ident == Id::printf || ident == Id::scanf)
- {
- Scope *sc2 = sc->push();
-
- if (ident == Id::printf)
- // Override previous setting, never let both be set
- sc2->flags = (sc2->flags & ~SCOPEscanf) | SCOPEprintf;
- else
- sc2->flags = (sc2->flags & ~SCOPEprintf) | SCOPEscanf;
-
- return sc2;
- }
- return sc;
-}
-
-const char *PragmaDeclaration::kind() const
-{
- return "pragma";
-}
-
-/********************************* ConditionalDeclaration ****************************/
-
-ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl)
- : AttribDeclaration(decl)
-{
- //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
- this->condition = condition;
- this->elsedecl = elsedecl;
-}
-
-Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- return new ConditionalDeclaration(condition->syntaxCopy(),
- Dsymbol::arraySyntaxCopy(decl),
- Dsymbol::arraySyntaxCopy(elsedecl));
-}
-
-bool ConditionalDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
-{
- //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc);
- if (condition->inc)
- {
- Dsymbols *d = condition->include(NULL) ? decl : elsedecl;
- return Dsymbol::oneMembers(d, ps, ident);
- }
- else
- {
- bool res = (Dsymbol::oneMembers( decl, ps, ident) && *ps == NULL &&
- Dsymbol::oneMembers(elsedecl, ps, ident) && *ps == NULL);
- *ps = NULL;
- return res;
- }
-}
-
-// Decide if 'then' or 'else' code should be included
-
-Dsymbols *ConditionalDeclaration::include(Scope *sc)
-{
- //printf("ConditionalDeclaration::include(sc = %p) _scope = %p\n", sc, _scope);
-
- if (errors)
- return NULL;
-
- assert(condition);
- return condition->include(_scope ? _scope : sc) ? decl : elsedecl;
-}
-
-void ConditionalDeclaration::setScope(Scope *sc)
-{
- Dsymbols *d = include(sc);
-
- //printf("\tConditionalDeclaration::setScope '%s', d = %p\n",toChars(), d);
- if (d)
- {
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->setScope(sc);
- }
- }
-}
-
-void ConditionalDeclaration::addComment(const utf8_t *comment)
-{
- /* Because addComment is called by the parser, if we called
- * include() it would define a version before it was used.
- * But it's no problem to drill down to both decl and elsedecl,
- * so that's the workaround.
- */
-
- if (comment)
- {
- Dsymbols *d = decl;
-
- for (int j = 0; j < 2; j++)
- {
- if (d)
- {
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- //printf("ConditionalDeclaration::addComment %s\n", s->toChars());
- s->addComment(comment);
- }
- }
- d = elsedecl;
- }
- }
-}
-
-/***************************** StaticIfDeclaration ****************************/
-
-StaticIfDeclaration::StaticIfDeclaration(Condition *condition,
- Dsymbols *decl, Dsymbols *elsedecl)
- : ConditionalDeclaration(condition, decl, elsedecl)
-{
- //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
- scopesym = NULL;
- addisdone = false;
- onStack = false;
-}
-
-Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- return new StaticIfDeclaration(condition->syntaxCopy(),
- Dsymbol::arraySyntaxCopy(decl),
- Dsymbol::arraySyntaxCopy(elsedecl));
-}
-
-/****************************************
- * Different from other AttribDeclaration subclasses, include() call requires
- * the completion of addMember and setScope phases.
- */
-Dsymbols *StaticIfDeclaration::include(Scope *sc)
-{
- //printf("StaticIfDeclaration::include(sc = %p) _scope = %p\n", sc, _scope);
-
- if (errors || onStack)
- return NULL;
- onStack = true;
- Dsymbols *d;
-
- if (condition->inc == 0)
- {
- assert(scopesym); // addMember is already done
- assert(_scope); // setScope is already done
-
- d = ConditionalDeclaration::include(_scope);
-
- if (d && !addisdone)
- {
- // Add members lazily.
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->addMember(_scope, scopesym);
- }
-
- // Set the member scopes lazily.
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->setScope(_scope);
- }
-
- addisdone = true;
- }
- onStack = false;
- return d;
- }
- else
- {
- d = ConditionalDeclaration::include(sc);
- onStack = false;
- return d;
- }
-}
-
-void StaticIfDeclaration::addMember(Scope *, ScopeDsymbol *sds)
-{
- //printf("StaticIfDeclaration::addMember() '%s'\n", toChars());
- /* This is deferred until the condition evaluated later (by the include() call),
- * so that expressions in the condition can refer to declarations
- * in the same scope, such as:
- *
- * template Foo(int i)
- * {
- * const int j = i + 1;
- * static if (j == 3)
- * const int k;
- * }
- */
- this->scopesym = sds;
-}
-
-void StaticIfDeclaration::importAll(Scope *)
-{
- // do not evaluate condition before semantic pass
-}
-
-void StaticIfDeclaration::setScope(Scope *sc)
-{
- // do not evaluate condition before semantic pass
-
- // But do set the scope, in case we need it for forward referencing
- Dsymbol::setScope(sc);
-}
-
-const char *StaticIfDeclaration::kind() const
-{
- return "static if";
-}
-
-/***************************** StaticForeachDeclaration ***********************/
-
-/* Static foreach at declaration scope, like:
- * static foreach (i; [0, 1, 2]){ }
- */
-
-StaticForeachDeclaration::StaticForeachDeclaration(StaticForeach *sfe, Dsymbols *decl)
- : AttribDeclaration(decl)
-{
- this->sfe = sfe;
- this->scopesym = NULL;
- this->onStack = false;
- this->cached = false;
- this->cache = NULL;
-}
-
-Dsymbol *StaticForeachDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- return new StaticForeachDeclaration(
- sfe->syntaxCopy(),
- Dsymbol::arraySyntaxCopy(decl));
-}
-
-bool StaticForeachDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
-{
- // Required to support IFTI on a template that contains a
- // `static foreach` declaration. `super.oneMember` calls
- // include with a `null` scope. As `static foreach` requires
- // the scope for expansion, `oneMember` can only return a
- // precise result once `static foreach` has been expanded.
- if (cached)
- {
- return AttribDeclaration::oneMember(ps, ident);
- }
- *ps = NULL; // a `static foreach` declaration may in general expand to multiple symbols
- return false;
-}
-
-Dsymbols *StaticForeachDeclaration::include(Scope *)
-{
- if (errors || onStack)
- return NULL;
- if (cached)
- {
- assert(!onStack);
- return cache;
- }
- onStack = true;
-
- if (_scope)
- {
- staticForeachPrepare(sfe, _scope); // lower static foreach aggregate
- }
- if (!staticForeachReady(sfe))
- {
- onStack = false;
- return NULL; // TODO: ok?
- }
-
- // expand static foreach
- Dsymbols *d = makeTupleForeachStaticDecl(_scope, sfe->aggrfe, decl, sfe->needExpansion);
- if (d) // process generated declarations
- {
- // Add members lazily.
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->addMember(_scope, scopesym);
- }
- // Set the member scopes lazily.
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->setScope(_scope);
- }
- }
- onStack = false;
- cached = true;
- cache = d;
- return d;
-}
-
-void StaticForeachDeclaration::addMember(Scope *, ScopeDsymbol *sds)
-{
- // used only for caching the enclosing symbol
- this->scopesym = sds;
-}
-
-void StaticForeachDeclaration::addComment(const utf8_t *)
-{
- // do nothing
- // change this to give semantics to documentation comments on static foreach declarations
-}
-
-void StaticForeachDeclaration::setScope(Scope *sc)
-{
- // do not evaluate condition before semantic pass
- // But do set the scope, in case we need it for forward referencing
- Dsymbol::setScope(sc);
-}
-
-void StaticForeachDeclaration::importAll(Scope *)
-{
- // do not evaluate aggregate before semantic pass
-}
-
-const char *StaticForeachDeclaration::kind() const
-{
- return "static foreach";
-}
-
-/***********************************************************
- * Collection of declarations that stores foreach index variables in a
- * local symbol table. Other symbols declared within are forwarded to
- * another scope, like:
- *
- * static foreach (i; 0 .. 10) // loop variables for different indices do not conflict.
- * { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STClocal
- * mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable
- * }
- *
- * static foreach (i; 0.. 10)
- * {
- * pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope
- * }
- *
- * static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
- *
- * A StaticForeachDeclaration generates one
- * ForwardingAttribDeclaration for each expansion of its body. The
- * AST of the ForwardingAttribDeclaration contains both the `static
- * foreach` variables and the respective copy of the `static foreach`
- * body. The functionality is achieved by using a
- * ForwardingScopeDsymbol as the parent symbol for the generated
- * declarations.
- */
-
-ForwardingAttribDeclaration::ForwardingAttribDeclaration(Dsymbols *decl)
- : AttribDeclaration(decl)
-{
- sym = new ForwardingScopeDsymbol(NULL);
- sym->symtab = new DsymbolTable();
-}
-
-/**************************************
- * Use the ForwardingScopeDsymbol as the parent symbol for members.
- */
-Scope *ForwardingAttribDeclaration::newScope(Scope *sc)
-{
- return sc->push(sym);
-}
-
-/***************************************
- * Lazily initializes the scope to forward to.
- */
-void ForwardingAttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
-{
- parent = sym->parent = sym->forward = sds;
- return AttribDeclaration::addMember(sc, sym);
-}
-
-/***************************** CompileDeclaration *****************************/
-
-// These are mixin declarations, like mixin("int x");
-
-CompileDeclaration::CompileDeclaration(Loc loc, Expressions *exps)
- : AttribDeclaration(NULL)
-{
- //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
- this->loc = loc;
- this->exps = exps;
- this->scopesym = NULL;
- this->compiled = false;
-}
-
-Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *)
-{
- //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
- return new CompileDeclaration(loc, Expression::arraySyntaxCopy(exps));
-}
-
-void CompileDeclaration::addMember(Scope *, ScopeDsymbol *sds)
-{
- //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
- this->scopesym = sds;
-}
-
-void CompileDeclaration::setScope(Scope *sc)
-{
- Dsymbol::setScope(sc);
-}
-
-const char *CompileDeclaration::kind() const
-{
- return "mixin";
-}
-
-/***************************** UserAttributeDeclaration *****************************/
-
-UserAttributeDeclaration::UserAttributeDeclaration(Expressions *atts, Dsymbols *decl)
- : AttribDeclaration(decl)
-{
- //printf("UserAttributeDeclaration()\n");
- this->atts = atts;
-}
-
-Dsymbol *UserAttributeDeclaration::syntaxCopy(Dsymbol *s)
-{
- //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars());
- assert(!s);
- return new UserAttributeDeclaration(
- Expression::arraySyntaxCopy(this->atts),
- Dsymbol::arraySyntaxCopy(decl));
-}
-
-Scope *UserAttributeDeclaration::newScope(Scope *sc)
-{
- Scope *sc2 = sc;
- if (atts && atts->length)
- {
- // create new one for changes
- sc2 = sc->copy();
- sc2->userAttribDecl = this;
- }
- return sc2;
-}
-
-void UserAttributeDeclaration::setScope(Scope *sc)
-{
- //printf("UserAttributeDeclaration::setScope() %p\n", this);
- if (decl)
- Dsymbol::setScope(sc); // for forward reference of UDAs
-
- return AttribDeclaration::setScope(sc);
-}
-
-void udaExpressionEval(Scope *sc, Expressions *exps)
-{
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e = (*exps)[i];
- if (e)
- {
- e = expressionSemantic(e, sc);
- if (definitelyValueParameter(e))
- e = e->ctfeInterpret();
- if (e->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)e;
- udaExpressionEval(sc, te->exps);
- }
- (*exps)[i] = e;
- }
- }
-}
-
-Expressions *UserAttributeDeclaration::concat(Expressions *udas1, Expressions *udas2)
-{
- Expressions *udas;
- if (!udas1 || udas1->length == 0)
- udas = udas2;
- else if (!udas2 || udas2->length == 0)
- udas = udas1;
- else
- {
- /* Create a new tuple that combines them
- * (do not append to left operand, as this is a copy-on-write operation)
- */
- udas = new Expressions();
- udas->push(new TupleExp(Loc(), udas1));
- udas->push(new TupleExp(Loc(), udas2));
- }
- return udas;
-}
-
-Expressions *UserAttributeDeclaration::getAttributes()
-{
- if (Scope *sc = _scope)
- {
- _scope = NULL;
- arrayExpressionSemantic(atts, sc);
- }
-
- Expressions *exps = new Expressions();
- if (userAttribDecl)
- exps->push(new TupleExp(Loc(), userAttribDecl->getAttributes()));
- if (atts && atts->length)
- exps->push(new TupleExp(Loc(), atts));
-
- return exps;
-}
-
-const char *UserAttributeDeclaration::kind() const
-{
- return "UserAttribute";
-}
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
new file mode 100644
index 0000000..ae8f65b
--- /dev/null
+++ b/gcc/d/dmd/attrib.d
@@ -0,0 +1,1518 @@
+/**
+ * Defines declarations of various attributes.
+ *
+ * The term 'attribute' refers to things that can apply to a larger scope than a single declaration.
+ * Among them are:
+ * - Alignment (`align(8)`)
+ * - User defined attributes (`@UDA`)
+ * - Function Attributes (`@safe`)
+ * - Storage classes (`static`, `__gshared`)
+ * - Mixin declarations (`mixin("int x;")`)
+ * - Conditional compilation (`static if`, `static foreach`)
+ * - Linkage (`extern(C)`)
+ * - Anonymous structs / unions
+ * - Protection (`private`, `public`)
+ * - Deprecated declarations (`@deprecated`)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/attrib.d, _attrib.d)
+ * Documentation: https://dlang.org/phobos/dmd_attrib.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/attrib.d
+ */
+
+module dmd.attrib;
+
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.cond;
+import dmd.declaration;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem : dsymbolSemantic;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.hdrgen : visibilityToBuffer;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.objc; // for objc.addSymbols
+import dmd.root.outbuffer;
+import dmd.target; // for target.systemLinkage
+import dmd.tokens;
+import dmd.visitor;
+
+/***********************************************************
+ * Abstract attribute applied to Dsymbol's used as a common
+ * ancestor for storage classes (StorageClassDeclaration),
+ * linkage (LinkageDeclaration) and others.
+ */
+extern (C++) abstract class AttribDeclaration : Dsymbol
+{
+ Dsymbols* decl; /// Dsymbol's affected by this AttribDeclaration
+
+ extern (D) this(Dsymbols* decl)
+ {
+ this.decl = decl;
+ }
+
+ extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl)
+ {
+ super(loc, ident);
+ this.decl = decl;
+ }
+
+ Dsymbols* include(Scope* sc)
+ {
+ if (errors)
+ return null;
+
+ return decl;
+ }
+
+ /****************************************
+ * Create a new scope if one or more given attributes
+ * are different from the sc's.
+ * If the returned scope != sc, the caller should pop
+ * the scope after it used.
+ */
+ extern (D) static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage,
+ CPPMANGLE cppmangle, Visibility visibility, int explicitVisibility,
+ AlignDeclaration aligndecl, PragmaDeclaration inlining)
+ {
+ Scope* sc2 = sc;
+ if (stc != sc.stc ||
+ linkage != sc.linkage ||
+ cppmangle != sc.cppmangle ||
+ explicitVisibility != sc.explicitVisibility ||
+ visibility != sc.visibility ||
+ aligndecl !is sc.aligndecl ||
+ inlining != sc.inlining)
+ {
+ // create new one for changes
+ sc2 = sc.copy();
+ sc2.stc = stc;
+ sc2.linkage = linkage;
+ sc2.cppmangle = cppmangle;
+ sc2.visibility = visibility;
+ sc2.explicitVisibility = explicitVisibility;
+ sc2.aligndecl = aligndecl;
+ sc2.inlining = inlining;
+ }
+ return sc2;
+ }
+
+ /****************************************
+ * A hook point to supply scope for members.
+ * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
+ */
+ Scope* newScope(Scope* sc)
+ {
+ return sc;
+ }
+
+ override void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ Dsymbols* d = include(sc);
+ if (d)
+ {
+ Scope* sc2 = newScope(sc);
+ d.foreachDsymbol( s => s.addMember(sc2, sds) );
+ if (sc2 != sc)
+ sc2.pop();
+ }
+ }
+
+ override void setScope(Scope* sc)
+ {
+ Dsymbols* d = include(sc);
+ //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d);
+ if (d)
+ {
+ Scope* sc2 = newScope(sc);
+ d.foreachDsymbol( s => s.setScope(sc2) );
+ if (sc2 != sc)
+ sc2.pop();
+ }
+ }
+
+ override void importAll(Scope* sc)
+ {
+ Dsymbols* d = include(sc);
+ //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
+ if (d)
+ {
+ Scope* sc2 = newScope(sc);
+ d.foreachDsymbol( s => s.importAll(sc2) );
+ if (sc2 != sc)
+ sc2.pop();
+ }
+ }
+
+ override void addComment(const(char)* comment)
+ {
+ //printf("AttribDeclaration::addComment %s\n", comment);
+ if (comment)
+ {
+ include(null).foreachDsymbol( s => s.addComment(comment) );
+ }
+ }
+
+ override const(char)* kind() const
+ {
+ return "attribute";
+ }
+
+ override bool oneMember(Dsymbol* ps, Identifier ident)
+ {
+ Dsymbols* d = include(null);
+ return Dsymbol.oneMembers(d, ps, ident);
+ }
+
+ override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
+ {
+ include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
+ }
+
+ override final bool hasPointers()
+ {
+ return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
+ }
+
+ override final bool hasStaticCtorOrDtor()
+ {
+ return include(null).foreachDsymbol( (s) { return s.hasStaticCtorOrDtor(); } ) != 0;
+ }
+
+ override final void checkCtorConstInit()
+ {
+ include(null).foreachDsymbol( s => s.checkCtorConstInit() );
+ }
+
+ /****************************************
+ */
+ override final void addLocalClass(ClassDeclarations* aclasses)
+ {
+ include(null).foreachDsymbol( s => s.addLocalClass(aclasses) );
+ }
+
+ override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
+ {
+ objc.addSymbols(this, classes, categories);
+ }
+
+ override final inout(AttribDeclaration) isAttribDeclaration() inout pure @safe
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Storage classes applied to Dsymbols, e.g. `const int i;`
+ *
+ * <stc> <decl...>
+ */
+extern (C++) class StorageClassDeclaration : AttribDeclaration
+{
+ StorageClass stc;
+
+ extern (D) this(StorageClass stc, Dsymbols* decl)
+ {
+ super(decl);
+ this.stc = stc;
+ }
+
+ override StorageClassDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ return new StorageClassDeclaration(stc, Dsymbol.arraySyntaxCopy(decl));
+ }
+
+ override Scope* newScope(Scope* sc)
+ {
+ StorageClass scstc = sc.stc;
+ /* These sets of storage classes are mutually exclusive,
+ * so choose the innermost or most recent one.
+ */
+ if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest))
+ scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest);
+ if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.manifest | STC.gshared))
+ scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.manifest | STC.gshared);
+ if (stc & (STC.const_ | STC.immutable_ | STC.manifest))
+ scstc &= ~(STC.const_ | STC.immutable_ | STC.manifest);
+ if (stc & (STC.gshared | STC.shared_ | STC.tls))
+ scstc &= ~(STC.gshared | STC.shared_ | STC.tls);
+ if (stc & (STC.safe | STC.trusted | STC.system))
+ scstc &= ~(STC.safe | STC.trusted | STC.system);
+ scstc |= stc;
+ //printf("scstc = x%llx\n", scstc);
+ return createNewScope(sc, scstc, sc.linkage, sc.cppmangle,
+ sc.visibility, sc.explicitVisibility, sc.aligndecl, sc.inlining);
+ }
+
+ override final bool oneMember(Dsymbol* ps, Identifier ident)
+ {
+ bool t = Dsymbol.oneMembers(decl, ps, ident);
+ if (t && *ps)
+ {
+ /* This is to deal with the following case:
+ * struct Tick {
+ * template to(T) { const T to() { ... } }
+ * }
+ * For eponymous function templates, the 'const' needs to get attached to 'to'
+ * before the semantic analysis of 'to', so that template overloading based on the
+ * 'this' pointer can be successful.
+ */
+ FuncDeclaration fd = (*ps).isFuncDeclaration();
+ if (fd)
+ {
+ /* Use storage_class2 instead of storage_class otherwise when we do .di generation
+ * we'll wind up with 'const const' rather than 'const'.
+ */
+ /* Don't think we need to worry about mutually exclusive storage classes here
+ */
+ fd.storage_class2 |= stc;
+ }
+ }
+ return t;
+ }
+
+ override void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ Dsymbols* d = include(sc);
+ if (d)
+ {
+ Scope* sc2 = newScope(sc);
+
+ d.foreachDsymbol( (s)
+ {
+ //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars());
+ // STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol)
+ if (auto decl = s.isDeclaration())
+ {
+ decl.storage_class |= stc & STC.local;
+ if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case?
+ {
+ sdecl.stc |= stc & STC.local;
+ }
+ }
+ s.addMember(sc2, sds);
+ });
+
+ if (sc2 != sc)
+ sc2.pop();
+ }
+
+ }
+
+ override inout(StorageClassDeclaration) isStorageClassDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Deprecation with an additional message applied to Dsymbols,
+ * e.g. `deprecated("Superseeded by foo") int bar;`.
+ * (Note that `deprecated int bar;` is currently represented as a
+ * StorageClassDeclaration with STC.deprecated_)
+ *
+ * `deprecated(<msg>) <decl...>`
+ */
+extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration
+{
+ Expression msg; /// deprecation message
+ const(char)* msgstr; /// cached string representation of msg
+
+ extern (D) this(Expression msg, Dsymbols* decl)
+ {
+ super(STC.deprecated_, decl);
+ this.msg = msg;
+ }
+
+ override DeprecatedDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ return new DeprecatedDeclaration(msg.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl));
+ }
+
+ /**
+ * Provides a new scope with `STC.deprecated_` and `Scope.depdecl` set
+ *
+ * Calls `StorageClassDeclaration.newScope` (as it must be called or copied
+ * in any function overriding `newScope`), then set the `Scope`'s depdecl.
+ *
+ * Returns:
+ * Always a new scope, to use for this `DeprecatedDeclaration`'s members.
+ */
+ override Scope* newScope(Scope* sc)
+ {
+ auto scx = super.newScope(sc);
+ // The enclosing scope is deprecated as well
+ if (scx == sc)
+ scx = sc.push();
+ scx.depdecl = this;
+ return scx;
+ }
+
+ override void setScope(Scope* sc)
+ {
+ //printf("DeprecatedDeclaration::setScope() %p\n", this);
+ if (decl)
+ Dsymbol.setScope(sc); // for forward reference
+ return AttribDeclaration.setScope(sc);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Linkage attribute applied to Dsymbols, e.g.
+ * `extern(C) void foo()`.
+ *
+ * `extern(<linkage>) <decl...>`
+ */
+extern (C++) final class LinkDeclaration : AttribDeclaration
+{
+ LINK linkage; /// either explicitly set or `default_`
+
+ extern (D) this(const ref Loc loc, LINK linkage, Dsymbols* decl)
+ {
+ super(loc, null, decl);
+ //printf("LinkDeclaration(linkage = %d, decl = %p)\n", linkage, decl);
+ this.linkage = (linkage == LINK.system) ? target.systemLinkage() : linkage;
+ }
+
+ static LinkDeclaration create(const ref Loc loc, LINK p, Dsymbols* decl)
+ {
+ return new LinkDeclaration(loc, p, decl);
+ }
+
+ override LinkDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ return new LinkDeclaration(loc, linkage, Dsymbol.arraySyntaxCopy(decl));
+ }
+
+ override Scope* newScope(Scope* sc)
+ {
+ return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility,
+ sc.aligndecl, sc.inlining);
+ }
+
+ override const(char)* toChars() const
+ {
+ return toString().ptr;
+ }
+
+ extern(D) override const(char)[] toString() const
+ {
+ return "extern ()";
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Attribute declaring whether an external aggregate should be mangled as
+ * a struct or class in C++, e.g. `extern(C++, struct) class C { ... }`.
+ * This is required for correct name mangling on MSVC targets,
+ * see cppmanglewin.d for details.
+ *
+ * `extern(C++, <cppmangle>) <decl...>`
+ */
+extern (C++) final class CPPMangleDeclaration : AttribDeclaration
+{
+ CPPMANGLE cppmangle;
+
+ extern (D) this(const ref Loc loc, CPPMANGLE cppmangle, Dsymbols* decl)
+ {
+ super(loc, null, decl);
+ //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", cppmangle, decl);
+ this.cppmangle = cppmangle;
+ }
+
+ override CPPMangleDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ return new CPPMangleDeclaration(loc, cppmangle, Dsymbol.arraySyntaxCopy(decl));
+ }
+
+ override Scope* newScope(Scope* sc)
+ {
+ return createNewScope(sc, sc.stc, LINK.cpp, cppmangle, sc.visibility, sc.explicitVisibility,
+ sc.aligndecl, sc.inlining);
+ }
+
+ override void setScope(Scope* sc)
+ {
+ if (decl)
+ Dsymbol.setScope(sc); // for forward reference
+ return AttribDeclaration.setScope(sc);
+ }
+
+ override const(char)* toChars() const
+ {
+ return toString().ptr;
+ }
+
+ extern(D) override const(char)[] toString() const
+ {
+ return "extern ()";
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/**
+ * A node to represent an `extern(C++)` namespace attribute
+ *
+ * There are two ways to declarate a symbol as member of a namespace:
+ * `Nspace` and `CPPNamespaceDeclaration`.
+ * The former creates a scope for the symbol, and inject them in the
+ * parent scope at the same time.
+ * The later, this class, has no semantic implications and is only
+ * used for mangling.
+ * Additionally, this class allows one to use reserved identifiers
+ * (D keywords) in the namespace.
+ *
+ * A `CPPNamespaceDeclaration` can be created from an `Identifier`
+ * (already resolved) or from an `Expression`, which is CTFE-ed
+ * and can be either a `TupleExp`, in which can additional
+ * `CPPNamespaceDeclaration` nodes are created, or a `StringExp`.
+ *
+ * Note that this class, like `Nspace`, matches only one identifier
+ * part of a namespace. For the namespace `"foo::bar"`,
+ * the will be a `CPPNamespaceDeclaration` with its `ident`
+ * set to `"bar"`, and its `namespace` field pointing to another
+ * `CPPNamespaceDeclaration` with its `ident` set to `"foo"`.
+ */
+extern (C++) final class CPPNamespaceDeclaration : AttribDeclaration
+{
+ /// CTFE-able expression, resolving to `TupleExp` or `StringExp`
+ Expression exp;
+
+ extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl)
+ {
+ super(loc, ident, decl);
+ }
+
+ extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl)
+ {
+ super(loc, null, decl);
+ this.exp = exp;
+ }
+
+ extern (D) this(const ref Loc loc, Identifier ident, Expression exp, Dsymbols* decl,
+ CPPNamespaceDeclaration parent)
+ {
+ super(loc, ident, decl);
+ this.exp = exp;
+ this.cppnamespace = parent;
+ }
+
+ override CPPNamespaceDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ return new CPPNamespaceDeclaration(
+ this.loc, this.ident, this.exp, Dsymbol.arraySyntaxCopy(this.decl), this.cppnamespace);
+ }
+
+ /**
+ * Returns:
+ * A copy of the parent scope, with `this` as `namespace` and C++ linkage
+ */
+ override Scope* newScope(Scope* sc)
+ {
+ auto scx = sc.copy();
+ scx.linkage = LINK.cpp;
+ scx.namespace = this;
+ return scx;
+ }
+
+ override const(char)* toChars() const
+ {
+ return toString().ptr;
+ }
+
+ extern(D) override const(char)[] toString() const
+ {
+ return "extern (C++, `namespace`)";
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ override inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return this; }
+}
+
+/***********************************************************
+ * Visibility declaration for Dsymbols, e.g. `public int i;`
+ *
+ * `<visibility> <decl...>` or
+ * `package(<pkg_identifiers>) <decl...>` if `pkg_identifiers !is null`
+ */
+extern (C++) final class VisibilityDeclaration : AttribDeclaration
+{
+ Visibility visibility; /// the visibility
+ Identifier[] pkg_identifiers; /// identifiers for `package(foo.bar)` or null
+
+ /**
+ * Params:
+ * loc = source location of attribute token
+ * visibility = visibility attribute data
+ * decl = declarations which are affected by this visibility attribute
+ */
+ extern (D) this(const ref Loc loc, Visibility visibility, Dsymbols* decl)
+ {
+ super(loc, null, decl);
+ this.visibility = visibility;
+ //printf("decl = %p\n", decl);
+ }
+
+ /**
+ * Params:
+ * loc = source location of attribute token
+ * pkg_identifiers = list of identifiers for a qualified package name
+ * decl = declarations which are affected by this visibility attribute
+ */
+ extern (D) this(const ref Loc loc, Identifier[] pkg_identifiers, Dsymbols* decl)
+ {
+ super(loc, null, decl);
+ this.visibility.kind = Visibility.Kind.package_;
+ this.pkg_identifiers = pkg_identifiers;
+ if (pkg_identifiers.length > 0)
+ {
+ Dsymbol tmp;
+ Package.resolve(pkg_identifiers, &tmp, null);
+ visibility.pkg = tmp ? tmp.isPackage() : null;
+ }
+ }
+
+ override VisibilityDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+
+ if (visibility.kind == Visibility.Kind.package_)
+ return new VisibilityDeclaration(this.loc, pkg_identifiers, Dsymbol.arraySyntaxCopy(decl));
+ else
+ return new VisibilityDeclaration(this.loc, visibility, Dsymbol.arraySyntaxCopy(decl));
+ }
+
+ override Scope* newScope(Scope* sc)
+ {
+ if (pkg_identifiers)
+ dsymbolSemantic(this, sc);
+ return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.visibility, 1, sc.aligndecl, sc.inlining);
+ }
+
+ override void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ if (pkg_identifiers)
+ {
+ Dsymbol tmp;
+ Package.resolve(pkg_identifiers, &tmp, null);
+ visibility.pkg = tmp ? tmp.isPackage() : null;
+ pkg_identifiers = null;
+ }
+ if (visibility.kind == Visibility.Kind.package_ && visibility.pkg && sc._module)
+ {
+ Module m = sc._module;
+
+ // While isAncestorPackageOf does an equality check, the fix for issue 17441 adds a check to see if
+ // each package's .isModule() properites are equal.
+ //
+ // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null.
+ // This breaks package declarations of the package in question if they are declared in
+ // the same package.d file, which _do_ have a module associated with them, and hence a non-null
+ // isModule()
+ if (!m.isPackage() || !visibility.pkg.ident.equals(m.isPackage().ident))
+ {
+ Package pkg = m.parent ? m.parent.isPackage() : null;
+ if (!pkg || !visibility.pkg.isAncestorPackageOf(pkg))
+ error("does not bind to one of ancestor packages of module `%s`", m.toPrettyChars(true));
+ }
+ }
+ return AttribDeclaration.addMember(sc, sds);
+ }
+
+ override const(char)* kind() const
+ {
+ return "visibility attribute";
+ }
+
+ override const(char)* toPrettyChars(bool)
+ {
+ assert(visibility.kind > Visibility.Kind.undefined);
+ OutBuffer buf;
+ visibilityToBuffer(&buf, visibility);
+ return buf.extractChars();
+ }
+
+ override inout(VisibilityDeclaration) isVisibilityDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Alignment attribute for aggregates, members and variables.
+ *
+ * `align(<ealign>) <decl...>` or
+ * `align <decl...>` if `ealign` is null
+ */
+extern (C++) final class AlignDeclaration : AttribDeclaration
+{
+ Expressions* exps; /// Expression(s) yielding the desired alignment,
+ /// the largest value wins
+ enum structalign_t UNKNOWN = 0; /// alignment not yet computed
+ static assert(STRUCTALIGN_DEFAULT != UNKNOWN);
+
+ /// the actual alignment, `UNKNOWN` until it's either set to the value of `ealign`
+ /// or `STRUCTALIGN_DEFAULT` if `ealign` is null ( / an error ocurred)
+ structalign_t salign = UNKNOWN;
+
+
+ extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl)
+ {
+ super(loc, null, decl);
+ if (exp)
+ {
+ if (!exps)
+ exps = new Expressions();
+ exps.push(exp);
+ }
+ }
+
+ extern (D) this(const ref Loc loc, Expressions* exps, Dsymbols* decl)
+ {
+ super(loc, null, decl);
+ this.exps = exps;
+ }
+
+ override AlignDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ return new AlignDeclaration(loc,
+ Expression.arraySyntaxCopy(exps),
+ Dsymbol.arraySyntaxCopy(decl));
+ }
+
+ override Scope* newScope(Scope* sc)
+ {
+ return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, this, sc.inlining);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * An anonymous struct/union (defined by `isunion`).
+ */
+extern (C++) final class AnonDeclaration : AttribDeclaration
+{
+ bool isunion; /// whether it's a union
+ int sem; /// 1 if successful semantic()
+ uint anonoffset; /// offset of anonymous struct
+ uint anonstructsize; /// size of anonymous struct
+ uint anonalignsize; /// size of anonymous struct for alignment purposes
+
+ extern (D) this(const ref Loc loc, bool isunion, Dsymbols* decl)
+ {
+ super(loc, null, decl);
+ this.isunion = isunion;
+ }
+
+ override AnonDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl));
+ }
+
+ override void setScope(Scope* sc)
+ {
+ if (decl)
+ Dsymbol.setScope(sc);
+ return AttribDeclaration.setScope(sc);
+ }
+
+ override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
+ {
+ //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
+ if (decl)
+ {
+ /* This works by treating an AnonDeclaration as an aggregate 'member',
+ * so in order to place that member we need to compute the member's
+ * size and alignment.
+ */
+ size_t fieldstart = ad.fields.dim;
+
+ /* Hackishly hijack ad's structsize and alignsize fields
+ * for use in our fake anon aggregate member.
+ */
+ uint savestructsize = ad.structsize;
+ uint savealignsize = ad.alignsize;
+ ad.structsize = 0;
+ ad.alignsize = 0;
+
+ FieldState fs;
+ decl.foreachDsymbol( (s)
+ {
+ s.setFieldOffset(ad, fs, this.isunion);
+ if (this.isunion)
+ fs.offset = 0;
+ });
+
+ /* https://issues.dlang.org/show_bug.cgi?id=13613
+ * If the fields in this.members had been already
+ * added in ad.fields, just update *poffset for the subsequent
+ * field offset calculation.
+ */
+ if (fieldstart == ad.fields.dim)
+ {
+ ad.structsize = savestructsize;
+ ad.alignsize = savealignsize;
+ fieldState.offset = ad.structsize;
+ return;
+ }
+
+ anonstructsize = ad.structsize;
+ anonalignsize = ad.alignsize;
+ ad.structsize = savestructsize;
+ ad.alignsize = savealignsize;
+
+ // 0 sized structs are set to 1 byte
+ if (anonstructsize == 0)
+ {
+ anonstructsize = 1;
+ anonalignsize = 1;
+ }
+
+ assert(_scope);
+ auto alignment = _scope.alignment();
+
+ /* Given the anon 'member's size and alignment,
+ * go ahead and place it.
+ */
+ anonoffset = AggregateDeclaration.placeField(
+ &fieldState.offset,
+ anonstructsize, anonalignsize, alignment,
+ &ad.structsize, &ad.alignsize,
+ isunion);
+
+ // Add to the anon fields the base offset of this anonymous aggregate
+ //printf("anon fields, anonoffset = %d\n", anonoffset);
+ foreach (const i; fieldstart .. ad.fields.dim)
+ {
+ VarDeclaration v = ad.fields[i];
+ //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
+ v.offset += anonoffset;
+ }
+ }
+ }
+
+ override const(char)* kind() const
+ {
+ return (isunion ? "anonymous union" : "anonymous struct");
+ }
+
+ override inout(AnonDeclaration) isAnonDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Pragma applied to Dsymbols, e.g. `pragma(inline, true) void foo`,
+ * but not PragmaStatement's like `pragma(msg, "hello");`.
+ *
+ * pragma(<ident>, <args>)
+ */
+extern (C++) final class PragmaDeclaration : AttribDeclaration
+{
+ Expressions* args; /// parameters of this pragma
+
+ extern (D) this(const ref Loc loc, Identifier ident, Expressions* args, Dsymbols* decl)
+ {
+ super(loc, ident, decl);
+ this.args = args;
+ }
+
+ override PragmaDeclaration syntaxCopy(Dsymbol s)
+ {
+ //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
+ assert(!s);
+ return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl));
+ }
+
+ override Scope* newScope(Scope* sc)
+ {
+ if (ident == Id.Pinline)
+ {
+ // We keep track of this pragma inside scopes,
+ // then it's evaluated on demand in function semantic
+ return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, this);
+ }
+ if (ident == Id.printf || ident == Id.scanf)
+ {
+ auto sc2 = sc.push();
+
+ if (ident == Id.printf)
+ // Override previous setting, never let both be set
+ sc2.flags = (sc2.flags & ~SCOPE.scanf) | SCOPE.printf;
+ else
+ sc2.flags = (sc2.flags & ~SCOPE.printf) | SCOPE.scanf;
+
+ return sc2;
+ }
+ return sc;
+ }
+
+ PINLINE evalPragmaInline(Scope* sc)
+ {
+ if (!args || args.dim == 0)
+ return PINLINE.default_;
+
+ Expression e = (*args)[0];
+ if (!e.type)
+ {
+
+ sc = sc.startCTFE();
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ sc = sc.endCTFE();
+ e = e.ctfeInterpret();
+ e = e.toBoolean(sc);
+ if (e.isErrorExp())
+ error("pragma(`inline`, `true` or `false`) expected, not `%s`", (*args)[0].toChars());
+ (*args)[0] = e;
+ }
+
+ if (e.isBool(true))
+ return PINLINE.always;
+ else if (e.isBool(false))
+ return PINLINE.never;
+ else
+ return PINLINE.default_;
+ }
+
+ override const(char)* kind() const
+ {
+ return "pragma";
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * A conditional compilation declaration, used for `version`
+ * / `debug` and specialized for `static if`.
+ *
+ * <condition> { <decl...> } else { <elsedecl> }
+ */
+extern (C++) class ConditionalDeclaration : AttribDeclaration
+{
+ Condition condition; /// condition deciding whether decl or elsedecl applies
+ Dsymbols* elsedecl; /// array of Dsymbol's for else block
+
+ extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl)
+ {
+ super(loc, null, decl);
+ //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
+ this.condition = condition;
+ this.elsedecl = elsedecl;
+ }
+
+ override ConditionalDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ return new ConditionalDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
+ }
+
+ override final bool oneMember(Dsymbol* ps, Identifier ident)
+ {
+ //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc);
+ if (condition.inc != Include.notComputed)
+ {
+ Dsymbols* d = condition.include(null) ? decl : elsedecl;
+ return Dsymbol.oneMembers(d, ps, ident);
+ }
+ else
+ {
+ bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null);
+ *ps = null;
+ return res;
+ }
+ }
+
+ // Decide if 'then' or 'else' code should be included
+ override Dsymbols* include(Scope* sc)
+ {
+ //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, scope);
+
+ if (errors)
+ return null;
+
+ assert(condition);
+ return condition.include(_scope ? _scope : sc) ? decl : elsedecl;
+ }
+
+ override final void addComment(const(char)* comment)
+ {
+ /* Because addComment is called by the parser, if we called
+ * include() it would define a version before it was used.
+ * But it's no problem to drill down to both decl and elsedecl,
+ * so that's the workaround.
+ */
+ if (comment)
+ {
+ decl .foreachDsymbol( s => s.addComment(comment) );
+ elsedecl.foreachDsymbol( s => s.addComment(comment) );
+ }
+ }
+
+ override void setScope(Scope* sc)
+ {
+ include(sc).foreachDsymbol( s => s.setScope(sc) );
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * `<scopesym> {
+ * static if (<condition>) { <decl> } else { <elsedecl> }
+ * }`
+ */
+extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
+{
+ ScopeDsymbol scopesym; /// enclosing symbol (e.g. module) where symbols will be inserted
+ private bool addisdone = false; /// true if members have been added to scope
+ private bool onStack = false; /// true if a call to `include` is currently active
+
+ extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl)
+ {
+ super(loc, condition, decl, elsedecl);
+ //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
+ }
+
+ override StaticIfDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ return new StaticIfDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
+ }
+
+ /****************************************
+ * Different from other AttribDeclaration subclasses, include() call requires
+ * the completion of addMember and setScope phases.
+ */
+ override Dsymbols* include(Scope* sc)
+ {
+ //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, scope);
+
+ if (errors || onStack)
+ return null;
+ onStack = true;
+ scope(exit) onStack = false;
+
+ if (sc && condition.inc == Include.notComputed)
+ {
+ assert(scopesym); // addMember is already done
+ assert(_scope); // setScope is already done
+ Dsymbols* d = ConditionalDeclaration.include(_scope);
+ if (d && !addisdone)
+ {
+ // Add members lazily.
+ d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
+
+ // Set the member scopes lazily.
+ d.foreachDsymbol( s => s.setScope(_scope) );
+
+ addisdone = true;
+ }
+ return d;
+ }
+ else
+ {
+ return ConditionalDeclaration.include(sc);
+ }
+ }
+
+ override void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ //printf("StaticIfDeclaration::addMember() '%s'\n", toChars());
+ /* This is deferred until the condition evaluated later (by the include() call),
+ * so that expressions in the condition can refer to declarations
+ * in the same scope, such as:
+ *
+ * template Foo(int i)
+ * {
+ * const int j = i + 1;
+ * static if (j == 3)
+ * const int k;
+ * }
+ */
+ this.scopesym = sds;
+ }
+
+ override void setScope(Scope* sc)
+ {
+ // do not evaluate condition before semantic pass
+ // But do set the scope, in case we need it for forward referencing
+ Dsymbol.setScope(sc);
+ }
+
+ override void importAll(Scope* sc)
+ {
+ // do not evaluate condition before semantic pass
+ }
+
+ override const(char)* kind() const
+ {
+ return "static if";
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Static foreach at declaration scope, like:
+ * static foreach (i; [0, 1, 2]){ }
+ */
+
+extern (C++) final class StaticForeachDeclaration : AttribDeclaration
+{
+ StaticForeach sfe; /// contains `static foreach` expansion logic
+
+ ScopeDsymbol scopesym; /// cached enclosing scope (mimics `static if` declaration)
+
+ /++
+ `include` can be called multiple times, but a `static foreach`
+ should be expanded at most once. Achieved by caching the result
+ of the first call. We need both `cached` and `cache`, because
+ `null` is a valid value for `cache`.
+ +/
+ bool onStack = false;
+ bool cached = false;
+ Dsymbols* cache = null;
+
+ extern (D) this(StaticForeach sfe, Dsymbols* decl)
+ {
+ super(sfe.loc, null, decl);
+ this.sfe = sfe;
+ }
+
+ override StaticForeachDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ return new StaticForeachDeclaration(
+ sfe.syntaxCopy(),
+ Dsymbol.arraySyntaxCopy(decl));
+ }
+
+ override bool oneMember(Dsymbol* ps, Identifier ident)
+ {
+ // Required to support IFTI on a template that contains a
+ // `static foreach` declaration. `super.oneMember` calls
+ // include with a `null` scope. As `static foreach` requires
+ // the scope for expansion, `oneMember` can only return a
+ // precise result once `static foreach` has been expanded.
+ if (cached)
+ {
+ return super.oneMember(ps, ident);
+ }
+ *ps = null; // a `static foreach` declaration may in general expand to multiple symbols
+ return false;
+ }
+
+ override Dsymbols* include(Scope* sc)
+ {
+ if (errors || onStack)
+ return null;
+ if (cached)
+ {
+ assert(!onStack);
+ return cache;
+ }
+ onStack = true;
+ scope(exit) onStack = false;
+
+ if (_scope)
+ {
+ sfe.prepare(_scope); // lower static foreach aggregate
+ }
+ if (!sfe.ready())
+ {
+ return null; // TODO: ok?
+ }
+
+ // expand static foreach
+ import dmd.statementsem: makeTupleForeach;
+ Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion);
+ if (d) // process generated declarations
+ {
+ // Add members lazily.
+ d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
+
+ // Set the member scopes lazily.
+ d.foreachDsymbol( s => s.setScope(_scope) );
+ }
+ cached = true;
+ cache = d;
+ return d;
+ }
+
+ override void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ // used only for caching the enclosing symbol
+ this.scopesym = sds;
+ }
+
+ override void addComment(const(char)* comment)
+ {
+ // do nothing
+ // change this to give semantics to documentation comments on static foreach declarations
+ }
+
+ override void setScope(Scope* sc)
+ {
+ // do not evaluate condition before semantic pass
+ // But do set the scope, in case we need it for forward referencing
+ Dsymbol.setScope(sc);
+ }
+
+ override void importAll(Scope* sc)
+ {
+ // do not evaluate aggregate before semantic pass
+ }
+
+ override const(char)* kind() const
+ {
+ return "static foreach";
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Collection of declarations that stores foreach index variables in a
+ * local symbol table. Other symbols declared within are forwarded to
+ * another scope, like:
+ *
+ * static foreach (i; 0 .. 10) // loop variables for different indices do not conflict.
+ * { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STC.local
+ * mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable
+ * }
+ *
+ * static foreach (i; 0.. 10)
+ * {
+ * pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope
+ * }
+ *
+ * static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
+ *
+ * A StaticForeachDeclaration generates one
+ * ForwardingAttribDeclaration for each expansion of its body. The
+ * AST of the ForwardingAttribDeclaration contains both the `static
+ * foreach` variables and the respective copy of the `static foreach`
+ * body. The functionality is achieved by using a
+ * ForwardingScopeDsymbol as the parent symbol for the generated
+ * declarations.
+ */
+
+extern(C++) final class ForwardingAttribDeclaration: AttribDeclaration
+{
+ ForwardingScopeDsymbol sym = null;
+
+ this(Dsymbols* decl)
+ {
+ super(decl);
+ sym = new ForwardingScopeDsymbol(null);
+ sym.symtab = new DsymbolTable();
+ }
+
+ /**************************************
+ * Use the ForwardingScopeDsymbol as the parent symbol for members.
+ */
+ override Scope* newScope(Scope* sc)
+ {
+ return sc.push(sym);
+ }
+
+ /***************************************
+ * Lazily initializes the scope to forward to.
+ */
+ override void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ parent = sym.parent = sym.forward = sds;
+ return super.addMember(sc, sym);
+ }
+
+ override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+
+/***********************************************************
+ * Mixin declarations, like:
+ * mixin("int x");
+ * https://dlang.org/spec/module.html#mixin-declaration
+ */
+extern (C++) final class CompileDeclaration : AttribDeclaration
+{
+ Expressions* exps;
+ ScopeDsymbol scopesym;
+ bool compiled;
+
+ extern (D) this(const ref Loc loc, Expressions* exps)
+ {
+ super(loc, null, null);
+ //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
+ this.exps = exps;
+ }
+
+ override CompileDeclaration syntaxCopy(Dsymbol s)
+ {
+ //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
+ return new CompileDeclaration(loc, Expression.arraySyntaxCopy(exps));
+ }
+
+ override void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
+ this.scopesym = sds;
+ }
+
+ override void setScope(Scope* sc)
+ {
+ Dsymbol.setScope(sc);
+ }
+
+ override const(char)* kind() const
+ {
+ return "mixin";
+ }
+
+ override inout(CompileDeclaration) isCompileDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * User defined attributes look like:
+ * @foo(args, ...)
+ * @(args, ...)
+ */
+extern (C++) final class UserAttributeDeclaration : AttribDeclaration
+{
+ Expressions* atts;
+
+ extern (D) this(Expressions* atts, Dsymbols* decl)
+ {
+ super(decl);
+ this.atts = atts;
+ }
+
+ override UserAttributeDeclaration syntaxCopy(Dsymbol s)
+ {
+ //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars());
+ assert(!s);
+ return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl));
+ }
+
+ override Scope* newScope(Scope* sc)
+ {
+ Scope* sc2 = sc;
+ if (atts && atts.dim)
+ {
+ // create new one for changes
+ sc2 = sc.copy();
+ sc2.userAttribDecl = this;
+ }
+ return sc2;
+ }
+
+ override void setScope(Scope* sc)
+ {
+ //printf("UserAttributeDeclaration::setScope() %p\n", this);
+ if (decl)
+ Dsymbol.setScope(sc); // for forward reference of UDAs
+ return AttribDeclaration.setScope(sc);
+ }
+
+ extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2)
+ {
+ Expressions* udas;
+ if (!udas1 || udas1.dim == 0)
+ udas = udas2;
+ else if (!udas2 || udas2.dim == 0)
+ udas = udas1;
+ else
+ {
+ /* Create a new tuple that combines them
+ * (do not append to left operand, as this is a copy-on-write operation)
+ */
+ udas = new Expressions(2);
+ (*udas)[0] = new TupleExp(Loc.initial, udas1);
+ (*udas)[1] = new TupleExp(Loc.initial, udas2);
+ }
+ return udas;
+ }
+
+ Expressions* getAttributes()
+ {
+ if (auto sc = _scope)
+ {
+ _scope = null;
+ arrayExpressionSemantic(atts, sc);
+ }
+ auto exps = new Expressions();
+ if (userAttribDecl && userAttribDecl !is this)
+ exps.push(new TupleExp(Loc.initial, userAttribDecl.getAttributes()));
+ if (atts && atts.dim)
+ exps.push(new TupleExp(Loc.initial, atts));
+ return exps;
+ }
+
+ override const(char)* kind() const
+ {
+ return "UserAttribute";
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ /**
+ * Check if the provided expression references `core.attribute.gnuAbiTag`
+ *
+ * This should be called after semantic has been run on the expression.
+ * Semantic on UDA happens in semantic2 (see `dmd.semantic2`).
+ *
+ * Params:
+ * e = Expression to check (usually from `UserAttributeDeclaration.atts`)
+ *
+ * Returns:
+ * `true` if the expression references the compiler-recognized `gnuAbiTag`
+ */
+ static bool isGNUABITag(Expression e)
+ {
+ if (global.params.cplusplus < CppStdRevision.cpp11)
+ return false;
+
+ auto ts = e.type ? e.type.isTypeStruct() : null;
+ if (!ts)
+ return false;
+ if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent)
+ return false;
+ // Can only be defined in druntime
+ Module m = ts.sym.parent.isModule();
+ if (!m || !m.isCoreModule(Id.attribute))
+ return false;
+ return true;
+ }
+
+ /**
+ * Called from a symbol's semantic to check if `gnuAbiTag` UDA
+ * can be applied to them
+ *
+ * Directly emits an error if the UDA doesn't work with this symbol
+ *
+ * Params:
+ * sym = symbol to check for `gnuAbiTag`
+ * linkage = Linkage of the symbol (Declaration.link or sc.link)
+ */
+ static void checkGNUABITag(Dsymbol sym, LINK linkage)
+ {
+ if (global.params.cplusplus < CppStdRevision.cpp11)
+ return;
+
+ // Avoid `if` at the call site
+ if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null)
+ return;
+
+ foreach (exp; *sym.userAttribDecl.atts)
+ {
+ if (isGNUABITag(exp))
+ {
+ if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
+ {
+ exp.error("`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars());
+ sym.errors = true;
+ }
+ else if (linkage != LINK.cpp)
+ {
+ exp.error("`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars());
+ sym.errors = true;
+ }
+ // Only one `@gnuAbiTag` is allowed by semantic2
+ return;
+ }
+ }
+ }
+}
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index 174d3c1..e63c80b 100644
--- a/gcc/d/dmd/attrib.h
+++ b/gcc/d/dmd/attrib.h
@@ -10,13 +10,10 @@
#pragma once
+#include "root/port.h"
#include "dsymbol.h"
class Expression;
-class Statement;
-class LabelDsymbol;
-class Initializer;
-class Module;
class Condition;
class StaticForeach;
@@ -27,12 +24,7 @@ class AttribDeclaration : public Dsymbol
public:
Dsymbols *decl; // array of Dsymbol's
- AttribDeclaration(Dsymbols *decl);
virtual Dsymbols *include(Scope *sc);
- int apply(Dsymbol_apply_ft_t fp, void *param);
- static Scope *createNewScope(Scope *sc,
- StorageClass newstc, LINK linkage, CPPMANGLE cppmangle, Prot protection,
- int explicitProtection, AlignDeclaration *aligndecl, PINLINE inlining);
virtual Scope *newScope(Scope *sc);
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope *sc);
@@ -40,7 +32,7 @@ public:
void addComment(const utf8_t *comment);
const char *kind() const;
bool oneMember(Dsymbol **ps, Identifier *ident);
- void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+ void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
bool hasPointers();
bool hasStaticCtorOrDtor();
void checkCtorConstInit();
@@ -55,8 +47,7 @@ class StorageClassDeclaration : public AttribDeclaration
public:
StorageClass stc;
- StorageClassDeclaration(StorageClass stc, Dsymbols *decl);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ StorageClassDeclaration *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
bool oneMember(Dsymbol **ps, Identifier *ident);
void addMember(Scope *sc, ScopeDsymbol *sds);
@@ -71,11 +62,9 @@ public:
Expression *msg;
const char *msgstr;
- DeprecatedDeclaration(Expression *msg, Dsymbols *decl);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ DeprecatedDeclaration *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
void setScope(Scope *sc);
- const char *getMessage();
void accept(Visitor *v) { v->visit(this); }
};
@@ -84,11 +73,10 @@ class LinkDeclaration : public AttribDeclaration
public:
LINK linkage;
- LinkDeclaration(LINK p, Dsymbols *decl);
- static LinkDeclaration *create(LINK p, Dsymbols *decl);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ static LinkDeclaration *create(const Loc &loc, LINK p, Dsymbols *decl);
+ LinkDeclaration *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
- const char *toChars();
+ const char *toChars() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -97,40 +85,48 @@ class CPPMangleDeclaration : public AttribDeclaration
public:
CPPMANGLE cppmangle;
- CPPMangleDeclaration(CPPMANGLE p, Dsymbols *decl);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ CPPMangleDeclaration *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
- const char *toChars();
+ void setScope(Scope *sc);
+ const char *toChars() const;
void accept(Visitor *v) { v->visit(this); }
};
-class ProtDeclaration : public AttribDeclaration
+class CPPNamespaceDeclaration : public AttribDeclaration
{
public:
- Prot protection;
- Identifiers* pkg_identifiers;
+ Expression *exp;
- ProtDeclaration(Loc loc, Prot p, Dsymbols *decl);
- ProtDeclaration(Loc loc, Identifiers* pkg_identifiers, Dsymbols *decl);
+ CPPNamespaceDeclaration *syntaxCopy(Dsymbol *s);
+ Scope *newScope(Scope *sc);
+ const char *toChars() const;
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class VisibilityDeclaration : public AttribDeclaration
+{
+public:
+ Visibility visibility;
+ DArray<Identifier*> pkg_identifiers;
- Dsymbol *syntaxCopy(Dsymbol *s);
+ VisibilityDeclaration *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
void addMember(Scope *sc, ScopeDsymbol *sds);
const char *kind() const;
const char *toPrettyChars(bool unused);
+ VisibilityDeclaration *isVisibilityDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
class AlignDeclaration : public AttribDeclaration
{
public:
- Expression *ealign;
+ Expressions *alignExps;
structalign_t salign;
- AlignDeclaration(Loc loc, Expression *ealign, Dsymbols *decl);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ AlignDeclaration(const Loc &loc, Expression *ealign, Dsymbols *decl);
+ AlignDeclaration *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
- structalign_t getAlignment(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -143,10 +139,9 @@ public:
unsigned anonstructsize; // size of anonymous struct
unsigned anonalignsize; // size of anonymous struct for alignment purposes
- AnonDeclaration(Loc loc, bool isunion, Dsymbols *decl);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ AnonDeclaration *syntaxCopy(Dsymbol *s);
void setScope(Scope *sc);
- void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+ void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
const char *kind() const;
AnonDeclaration *isAnonDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
@@ -157,9 +152,9 @@ class PragmaDeclaration : public AttribDeclaration
public:
Expressions *args; // array of Expression's
- PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ PragmaDeclaration *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
+ PINLINE evalPragmaInline(Scope* sc);
const char *kind() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -170,8 +165,7 @@ public:
Condition *condition;
Dsymbols *elsedecl; // array of Dsymbol's for else block
- ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ ConditionalDeclaration *syntaxCopy(Dsymbol *s);
bool oneMember(Dsymbol **ps, Identifier *ident);
Dsymbols *include(Scope *sc);
void addComment(const utf8_t *comment);
@@ -186,8 +180,7 @@ public:
bool addisdone;
bool onStack;
- StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ StaticIfDeclaration *syntaxCopy(Dsymbol *s);
Dsymbols *include(Scope *sc);
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope *sc);
@@ -205,8 +198,7 @@ public:
bool cached;
Dsymbols *cache;
- StaticForeachDeclaration(StaticForeach *sfe, Dsymbols *decl);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ StaticForeachDeclaration *syntaxCopy(Dsymbol *s);
bool oneMember(Dsymbol **ps, Identifier *ident);
Dsymbols *include(Scope *sc);
void addMember(Scope *sc, ScopeDsymbol *sds);
@@ -222,7 +214,6 @@ class ForwardingAttribDeclaration : public AttribDeclaration
public:
ForwardingScopeDsymbol *sym;
- ForwardingAttribDeclaration(Dsymbols *decl);
Scope *newScope(Scope *sc);
void addMember(Scope *sc, ScopeDsymbol *sds);
ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return this; }
@@ -239,8 +230,7 @@ public:
ScopeDsymbol *scopesym;
bool compiled;
- CompileDeclaration(Loc loc, Expressions *exps);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ CompileDeclaration *syntaxCopy(Dsymbol *s);
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope *sc);
const char *kind() const;
@@ -256,11 +246,9 @@ class UserAttributeDeclaration : public AttribDeclaration
public:
Expressions *atts;
- UserAttributeDeclaration(Expressions *atts, Dsymbols *decl);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ UserAttributeDeclaration *syntaxCopy(Dsymbol *s);
Scope *newScope(Scope *sc);
void setScope(Scope *sc);
- static Expressions *concat(Expressions *udas1, Expressions *udas2);
Expressions *getAttributes();
const char *kind() const;
void accept(Visitor *v) { v->visit(this); }
diff --git a/gcc/d/dmd/blockexit.c b/gcc/d/dmd/blockexit.c
deleted file mode 100644
index 1895d36..0000000
--- a/gcc/d/dmd/blockexit.c
+++ /dev/null
@@ -1,506 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- */
-
-#include "statement.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "id.h"
-
-/* Only valid after semantic analysis
- * If 'mustNotThrow' is true, generate an error if it throws
- */
-int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow)
-{
- class BlockExit : public Visitor
- {
- public:
- FuncDeclaration *func;
- bool mustNotThrow;
- int result;
-
- BlockExit(FuncDeclaration *func, bool mustNotThrow)
- : func(func), mustNotThrow(mustNotThrow)
- {
- result = BEnone;
- }
-
- void visit(Statement *s)
- {
- printf("Statement::blockExit(%p)\n", s);
- printf("%s\n", s->toChars());
- assert(0);
- result = BEany;
- }
-
- void visit(ErrorStatement *)
- {
- result = BEany;
- }
-
- void visit(ExpStatement *s)
- {
- result = BEfallthru;
- if (s->exp)
- {
- if (s->exp->op == TOKhalt)
- {
- result = BEhalt;
- return;
- }
- if (s->exp->op == TOKassert)
- {
- AssertExp *a = (AssertExp *)s->exp;
- if (a->e1->isBool(false)) // if it's an assert(0)
- {
- result = BEhalt;
- return;
- }
- }
- if (s->exp->type->toBasetype()->isTypeNoreturn())
- result = BEhalt;
- if (canThrow(s->exp, func, mustNotThrow))
- result |= BEthrow;
- }
- }
-
- void visit(CompileStatement *)
- {
- assert(global.errors);
- result = BEfallthru;
- }
-
- void visit(CompoundStatement *cs)
- {
- //printf("CompoundStatement::blockExit(%p) %d result = x%X\n", cs, cs->statements->length, result);
- result = BEfallthru;
- Statement *slast = NULL;
- for (size_t i = 0; i < cs->statements->length; i++)
- {
- Statement *s = (*cs->statements)[i];
- if (s)
- {
- //printf("result = x%x\n", result);
- //printf("s: %s\n", s->toChars());
- if (result & BEfallthru && slast)
- {
- slast = slast->last();
- if (slast && (slast->isCaseStatement() || slast->isDefaultStatement()) &&
- (s->isCaseStatement() || s->isDefaultStatement()))
- {
- // Allow if last case/default was empty
- CaseStatement *sc = slast->isCaseStatement();
- DefaultStatement *sd = slast->isDefaultStatement();
- if (sc && (!sc->statement->hasCode() || sc->statement->isCaseStatement() || sc->statement->isErrorStatement()))
- ;
- else if (sd && (!sd->statement->hasCode() || sd->statement->isCaseStatement() || sd->statement->isErrorStatement()))
- ;
- else
- {
- const char *gototype = s->isCaseStatement() ? "case" : "default";
- s->deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
- }
- }
- }
-
- if (!(result & BEfallthru) && !s->comeFrom())
- {
- if (blockExit(s, func, mustNotThrow) != BEhalt && s->hasCode())
- s->warning("statement is not reachable");
- }
- else
- {
- result &= ~BEfallthru;
- result |= blockExit(s, func, mustNotThrow);
- }
- slast = s;
- }
- }
- }
-
- void visit(UnrolledLoopStatement *uls)
- {
- result = BEfallthru;
- for (size_t i = 0; i < uls->statements->length; i++)
- {
- Statement *s = (*uls->statements)[i];
- if (s)
- {
- int r = blockExit(s, func, mustNotThrow);
- result |= r & ~(BEbreak | BEcontinue | BEfallthru);
- if ((r & (BEfallthru | BEcontinue | BEbreak)) == 0)
- result &= ~BEfallthru;
- }
- }
- }
-
- void visit(ScopeStatement *s)
- {
- //printf("ScopeStatement::blockExit(%p)\n", s->statement);
- result = s->statement ? blockExit(s->statement, func, mustNotThrow) : BEfallthru;
- }
-
- void visit(WhileStatement *)
- {
- assert(global.errors);
- result = BEfallthru;
- }
-
- void visit(DoStatement *s)
- {
- if (s->_body)
- {
- result = blockExit(s->_body, func, mustNotThrow);
- if (result == BEbreak)
- {
- result = BEfallthru;
- return;
- }
- if (result & BEcontinue)
- result |= BEfallthru;
- }
- else
- result = BEfallthru;
- if (result & BEfallthru)
- {
- if (canThrow(s->condition, func, mustNotThrow))
- result |= BEthrow;
- if (!(result & BEbreak) && s->condition->isBool(true))
- result &= ~BEfallthru;
- }
- result &= ~(BEbreak | BEcontinue);
- }
-
- void visit(ForStatement *s)
- {
- result = BEfallthru;
- if (s->_init)
- {
- result = blockExit(s->_init, func, mustNotThrow);
- if (!(result & BEfallthru))
- return;
- }
- if (s->condition)
- {
- if (canThrow(s->condition, func, mustNotThrow))
- result |= BEthrow;
- if (s->condition->isBool(true))
- result &= ~BEfallthru;
- else if (s->condition->isBool(false))
- return;
- }
- else
- result &= ~BEfallthru; // the body must do the exiting
- if (s->_body)
- {
- int r = blockExit(s->_body, func, mustNotThrow);
- if (r & (BEbreak | BEgoto))
- result |= BEfallthru;
- result |= r & ~(BEfallthru | BEbreak | BEcontinue);
- }
- if (s->increment && canThrow(s->increment, func, mustNotThrow))
- result |= BEthrow;
- }
-
- void visit(ForeachStatement *s)
- {
- result = BEfallthru;
- if (canThrow(s->aggr, func, mustNotThrow))
- result |= BEthrow;
- if (s->_body)
- result |= blockExit(s->_body, func, mustNotThrow) & ~(BEbreak | BEcontinue);
- }
-
- void visit(ForeachRangeStatement *)
- {
- assert(global.errors);
- result = BEfallthru;
- }
-
- void visit(IfStatement *s)
- {
- //printf("IfStatement::blockExit(%p)\n", s);
-
- result = BEnone;
- if (canThrow(s->condition, func, mustNotThrow))
- result |= BEthrow;
- if (s->condition->isBool(true))
- {
- if (s->ifbody)
- result |= blockExit(s->ifbody, func, mustNotThrow);
- else
- result |= BEfallthru;
- }
- else if (s->condition->isBool(false))
- {
- if (s->elsebody)
- result |= blockExit(s->elsebody, func, mustNotThrow);
- else
- result |= BEfallthru;
- }
- else
- {
- if (s->ifbody)
- result |= blockExit(s->ifbody, func, mustNotThrow);
- else
- result |= BEfallthru;
- if (s->elsebody)
- result |= blockExit(s->elsebody, func, mustNotThrow);
- else
- result |= BEfallthru;
- }
- //printf("IfStatement::blockExit(%p) = x%x\n", s, result);
- }
-
- void visit(ConditionalStatement *s)
- {
- result = blockExit(s->ifbody, func, mustNotThrow);
- if (s->elsebody)
- result |= blockExit(s->elsebody, func, mustNotThrow);
- }
-
- void visit(PragmaStatement *)
- {
- result = BEfallthru;
- }
-
- void visit(StaticAssertStatement *)
- {
- result = BEfallthru;
- }
-
- void visit(SwitchStatement *s)
- {
- result = BEnone;
- if (canThrow(s->condition, func, mustNotThrow))
- result |= BEthrow;
- if (s->_body)
- {
- result |= blockExit(s->_body, func, mustNotThrow);
- if (result & BEbreak)
- {
- result |= BEfallthru;
- result &= ~BEbreak;
- }
- }
- else
- result |= BEfallthru;
- }
-
- void visit(CaseStatement *s)
- {
- result = blockExit(s->statement, func, mustNotThrow);
- }
-
- void visit(DefaultStatement *s)
- {
- result = blockExit(s->statement, func, mustNotThrow);
- }
-
- void visit(GotoDefaultStatement *)
- {
- result = BEgoto;
- }
-
- void visit(GotoCaseStatement *)
- {
- result = BEgoto;
- }
-
- void visit(SwitchErrorStatement *)
- {
- // Switch errors are non-recoverable
- result = BEhalt;
- }
-
- void visit(ReturnStatement *s)
- {
- result = BEreturn;
- if (s->exp && canThrow(s->exp, func, mustNotThrow))
- result |= BEthrow;
- }
-
- void visit(BreakStatement *s)
- {
- //printf("BreakStatement::blockExit(%p) = x%x\n", s, s->ident ? BEgoto : BEbreak);
- result = s->ident ? BEgoto : BEbreak;
- }
-
- void visit(ContinueStatement *s)
- {
- result = s->ident ? BEgoto : BEcontinue;
- }
-
- void visit(SynchronizedStatement *s)
- {
- result = s->_body ? blockExit(s->_body, func, mustNotThrow) : BEfallthru;
- }
-
- void visit(WithStatement *s)
- {
- result = BEnone;
- if (canThrow(s->exp, func, mustNotThrow))
- result = BEthrow;
- if (s->_body)
- result |= blockExit(s->_body, func, mustNotThrow);
- else
- result |= BEfallthru;
- }
-
- void visit(TryCatchStatement *s)
- {
- assert(s->_body);
- result = blockExit(s->_body, func, false);
-
- int catchresult = 0;
- for (size_t i = 0; i < s->catches->length; i++)
- {
- Catch *c = (*s->catches)[i];
- if (c->type == Type::terror)
- continue;
-
- int cresult;
- if (c->handler)
- cresult = blockExit(c->handler, func, mustNotThrow);
- else
- cresult = BEfallthru;
-
- /* If we're catching Object, then there is no throwing
- */
- Identifier *id = c->type->toBasetype()->isClassHandle()->ident;
- if (c->internalCatch && (cresult & BEfallthru))
- {
- // Bugzilla 11542: leave blockExit flags of the body
- cresult &= ~BEfallthru;
- }
- else if (id == Id::Object || id == Id::Throwable)
- {
- result &= ~(BEthrow | BEerrthrow);
- }
- else if (id == Id::Exception)
- {
- result &= ~BEthrow;
- }
- catchresult |= cresult;
- }
- if (mustNotThrow && (result & BEthrow))
- {
- // now explain why this is nothrow
- blockExit(s->_body, func, mustNotThrow);
- }
- result |= catchresult;
- }
-
- void visit(TryFinallyStatement *s)
- {
- result = BEfallthru;
- if (s->_body)
- result = blockExit(s->_body, func, false);
-
- // check finally body as well, it may throw (bug #4082)
- int finalresult = BEfallthru;
- if (s->finalbody)
- finalresult = blockExit(s->finalbody, func, false);
-
- // If either body or finalbody halts
- if (result == BEhalt)
- finalresult = BEnone;
- if (finalresult == BEhalt)
- result = BEnone;
-
- if (mustNotThrow)
- {
- // now explain why this is nothrow
- if (s->_body && (result & BEthrow))
- blockExit(s->_body, func, mustNotThrow);
- if (s->finalbody && (finalresult & BEthrow))
- blockExit(s->finalbody, func, mustNotThrow);
- }
-
- #if 0
- // Bugzilla 13201: Mask to prevent spurious warnings for
- // destructor call, exit of synchronized statement, etc.
- if (result == BEhalt && finalresult != BEhalt && s->finalbody &&
- s->finalbody->hasCode())
- {
- s->finalbody->warning("statement is not reachable");
- }
- #endif
-
- if (!(finalresult & BEfallthru))
- result &= ~BEfallthru;
- result |= finalresult & ~BEfallthru;
- }
-
- void visit(ScopeGuardStatement *)
- {
- // At this point, this statement is just an empty placeholder
- result = BEfallthru;
- }
-
- void visit(ThrowStatement *s)
- {
- if (s->internalThrow)
- {
- // Bugzilla 8675: Allow throwing 'Throwable' object even if mustNotThrow.
- result = BEfallthru;
- return;
- }
-
- Type *t = s->exp->type->toBasetype();
- ClassDeclaration *cd = t->isClassHandle();
- assert(cd);
-
- if (cd == ClassDeclaration::errorException ||
- ClassDeclaration::errorException->isBaseOf(cd, NULL))
- {
- result = BEerrthrow;
- return;
- }
- if (mustNotThrow)
- s->error("%s is thrown but not caught", s->exp->type->toChars());
-
- result = BEthrow;
- }
-
- void visit(GotoStatement *)
- {
- //printf("GotoStatement::blockExit(%p)\n", s);
- result = BEgoto;
- }
-
- void visit(LabelStatement *s)
- {
- //printf("LabelStatement::blockExit(%p)\n", s);
- result = s->statement ? blockExit(s->statement, func, mustNotThrow) : BEfallthru;
- if (s->breaks)
- result |= BEfallthru;
- }
-
- void visit(CompoundAsmStatement *s)
- {
- if (mustNotThrow && !(s->stc & STCnothrow))
- s->deprecation("asm statement is assumed to throw - mark it with `nothrow` if it does not");
-
- // Assume the worst
- result = BEfallthru | BEreturn | BEgoto | BEhalt;
- if (!(s->stc & STCnothrow)) result |= BEthrow;
- }
-
- void visit(ImportStatement *)
- {
- result = BEfallthru;
- }
- };
-
- if (!s)
- return BEfallthru;
- BlockExit be(func, mustNotThrow);
- s->accept(&be);
- return be.result;
-}
diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d
new file mode 100644
index 0000000..1fd9005
--- /dev/null
+++ b/gcc/d/dmd/blockexit.d
@@ -0,0 +1,537 @@
+/**
+ * Find out in what ways control flow can exit a statement block.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/blockexit.d, _blockexit.d)
+ * Documentation: https://dlang.org/phobos/dmd_blockexit.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/blockexit.d
+ */
+
+module dmd.blockexit;
+
+import core.stdc.stdio;
+
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.canthrow;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.statement;
+import dmd.tokens;
+import dmd.visitor;
+
+/**
+ * BE stands for BlockExit.
+ *
+ * It indicates if a statement does transfer control to another block.
+ * A block is a sequence of statements enclosed in { }
+ */
+enum BE : int
+{
+ none = 0,
+ fallthru = 1,
+ throw_ = 2,
+ return_ = 4,
+ goto_ = 8,
+ halt = 0x10,
+ break_ = 0x20,
+ continue_ = 0x40,
+ errthrow = 0x80,
+ any = (fallthru | throw_ | return_ | goto_ | halt),
+}
+
+
+/*********************************************
+ * Determine mask of ways that a statement can exit.
+ *
+ * Only valid after semantic analysis.
+ * Params:
+ * s = statement to check for block exit status
+ * func = function that statement s is in
+ * mustNotThrow = generate an error if it throws
+ * Returns:
+ * BE.xxxx
+ */
+int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
+{
+ extern (C++) final class BlockExit : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ FuncDeclaration func;
+ bool mustNotThrow;
+ int result;
+
+ extern (D) this(FuncDeclaration func, bool mustNotThrow)
+ {
+ this.func = func;
+ this.mustNotThrow = mustNotThrow;
+ result = BE.none;
+ }
+
+ override void visit(Statement s)
+ {
+ printf("Statement::blockExit(%p)\n", s);
+ printf("%s\n", s.toChars());
+ assert(0);
+ }
+
+ override void visit(ErrorStatement s)
+ {
+ result = BE.none;
+ }
+
+ override void visit(ExpStatement s)
+ {
+ result = BE.fallthru;
+ if (s.exp)
+ {
+ if (s.exp.op == TOK.halt)
+ {
+ result = BE.halt;
+ return;
+ }
+ if (s.exp.op == TOK.assert_)
+ {
+ AssertExp a = cast(AssertExp)s.exp;
+ if (a.e1.isBool(false)) // if it's an assert(0)
+ {
+ result = BE.halt;
+ return;
+ }
+ }
+ if (s.exp.type.toBasetype().isTypeNoreturn())
+ result = BE.halt;
+ if (canThrow(s.exp, func, mustNotThrow))
+ result |= BE.throw_;
+ }
+ }
+
+ override void visit(CompileStatement s)
+ {
+ assert(global.errors);
+ result = BE.fallthru;
+ }
+
+ override void visit(CompoundStatement cs)
+ {
+ //printf("CompoundStatement.blockExit(%p) %d result = x%X\n", cs, cs.statements.dim, result);
+ result = BE.fallthru;
+ Statement slast = null;
+ foreach (s; *cs.statements)
+ {
+ if (s)
+ {
+ //printf("result = x%x\n", result);
+ //printf("s: %s\n", s.toChars());
+ if (result & BE.fallthru && slast)
+ {
+ slast = slast.last();
+ if (slast && (slast.isCaseStatement() || slast.isDefaultStatement()) && (s.isCaseStatement() || s.isDefaultStatement()))
+ {
+ // Allow if last case/default was empty
+ CaseStatement sc = slast.isCaseStatement();
+ DefaultStatement sd = slast.isDefaultStatement();
+ if (sc && (!sc.statement.hasCode() || sc.statement.isCaseStatement() || sc.statement.isErrorStatement()))
+ {
+ }
+ else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement()))
+ {
+ }
+ else
+ {
+ const(char)* gototype = s.isCaseStatement() ? "case" : "default";
+ s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
+ }
+ }
+ }
+
+ if (!(result & BE.fallthru) && !s.comeFrom())
+ {
+ if (blockExit(s, func, mustNotThrow) != BE.halt && s.hasCode() &&
+ s.loc != Loc.initial) // don't emit warning for generated code
+ s.warning("statement is not reachable");
+ }
+ else
+ {
+ result &= ~BE.fallthru;
+ result |= blockExit(s, func, mustNotThrow);
+ }
+ slast = s;
+ }
+ }
+ }
+
+ override void visit(UnrolledLoopStatement uls)
+ {
+ result = BE.fallthru;
+ foreach (s; *uls.statements)
+ {
+ if (s)
+ {
+ int r = blockExit(s, func, mustNotThrow);
+ result |= r & ~(BE.break_ | BE.continue_ | BE.fallthru);
+ if ((r & (BE.fallthru | BE.continue_ | BE.break_)) == 0)
+ result &= ~BE.fallthru;
+ }
+ }
+ }
+
+ override void visit(ScopeStatement s)
+ {
+ //printf("ScopeStatement::blockExit(%p)\n", s.statement);
+ result = blockExit(s.statement, func, mustNotThrow);
+ }
+
+ override void visit(WhileStatement s)
+ {
+ assert(global.errors);
+ result = BE.fallthru;
+ }
+
+ override void visit(DoStatement s)
+ {
+ if (s._body)
+ {
+ result = blockExit(s._body, func, mustNotThrow);
+ if (result == BE.break_)
+ {
+ result = BE.fallthru;
+ return;
+ }
+ if (result & BE.continue_)
+ result |= BE.fallthru;
+ }
+ else
+ result = BE.fallthru;
+ if (result & BE.fallthru)
+ {
+ if (canThrow(s.condition, func, mustNotThrow))
+ result |= BE.throw_;
+ if (!(result & BE.break_) && s.condition.isBool(true))
+ result &= ~BE.fallthru;
+ }
+ result &= ~(BE.break_ | BE.continue_);
+ }
+
+ override void visit(ForStatement s)
+ {
+ result = BE.fallthru;
+ if (s._init)
+ {
+ result = blockExit(s._init, func, mustNotThrow);
+ if (!(result & BE.fallthru))
+ return;
+ }
+ if (s.condition)
+ {
+ if (canThrow(s.condition, func, mustNotThrow))
+ result |= BE.throw_;
+ if (s.condition.isBool(true))
+ result &= ~BE.fallthru;
+ else if (s.condition.isBool(false))
+ return;
+ }
+ else
+ result &= ~BE.fallthru; // the body must do the exiting
+ if (s._body)
+ {
+ int r = blockExit(s._body, func, mustNotThrow);
+ if (r & (BE.break_ | BE.goto_))
+ result |= BE.fallthru;
+ result |= r & ~(BE.fallthru | BE.break_ | BE.continue_);
+ }
+ if (s.increment && canThrow(s.increment, func, mustNotThrow))
+ result |= BE.throw_;
+ }
+
+ override void visit(ForeachStatement s)
+ {
+ result = BE.fallthru;
+ if (canThrow(s.aggr, func, mustNotThrow))
+ result |= BE.throw_;
+ if (s._body)
+ result |= blockExit(s._body, func, mustNotThrow) & ~(BE.break_ | BE.continue_);
+ }
+
+ override void visit(ForeachRangeStatement s)
+ {
+ assert(global.errors);
+ result = BE.fallthru;
+ }
+
+ override void visit(IfStatement s)
+ {
+ //printf("IfStatement::blockExit(%p)\n", s);
+ result = BE.none;
+ if (canThrow(s.condition, func, mustNotThrow))
+ result |= BE.throw_;
+ if (s.condition.isBool(true))
+ {
+ result |= blockExit(s.ifbody, func, mustNotThrow);
+ }
+ else if (s.condition.isBool(false))
+ {
+ result |= blockExit(s.elsebody, func, mustNotThrow);
+ }
+ else
+ {
+ result |= blockExit(s.ifbody, func, mustNotThrow);
+ result |= blockExit(s.elsebody, func, mustNotThrow);
+ }
+ //printf("IfStatement::blockExit(%p) = x%x\n", s, result);
+ }
+
+ override void visit(ConditionalStatement s)
+ {
+ result = blockExit(s.ifbody, func, mustNotThrow);
+ if (s.elsebody)
+ result |= blockExit(s.elsebody, func, mustNotThrow);
+ }
+
+ override void visit(PragmaStatement s)
+ {
+ result = BE.fallthru;
+ }
+
+ override void visit(StaticAssertStatement s)
+ {
+ result = BE.fallthru;
+ }
+
+ override void visit(SwitchStatement s)
+ {
+ result = BE.none;
+ if (canThrow(s.condition, func, mustNotThrow))
+ result |= BE.throw_;
+ if (s._body)
+ {
+ result |= blockExit(s._body, func, mustNotThrow);
+ if (result & BE.break_)
+ {
+ result |= BE.fallthru;
+ result &= ~BE.break_;
+ }
+ }
+ else
+ result |= BE.fallthru;
+ }
+
+ override void visit(CaseStatement s)
+ {
+ result = blockExit(s.statement, func, mustNotThrow);
+ }
+
+ override void visit(DefaultStatement s)
+ {
+ result = blockExit(s.statement, func, mustNotThrow);
+ }
+
+ override void visit(GotoDefaultStatement s)
+ {
+ result = BE.goto_;
+ }
+
+ override void visit(GotoCaseStatement s)
+ {
+ result = BE.goto_;
+ }
+
+ override void visit(SwitchErrorStatement s)
+ {
+ // Switch errors are non-recoverable
+ result = BE.halt;
+ }
+
+ override void visit(ReturnStatement s)
+ {
+ result = BE.return_;
+ if (s.exp && canThrow(s.exp, func, mustNotThrow))
+ result |= BE.throw_;
+ }
+
+ override void visit(BreakStatement s)
+ {
+ //printf("BreakStatement::blockExit(%p) = x%x\n", s, s.ident ? BE.goto_ : BE.break_);
+ result = s.ident ? BE.goto_ : BE.break_;
+ }
+
+ override void visit(ContinueStatement s)
+ {
+ result = s.ident ? BE.continue_ | BE.goto_ : BE.continue_;
+ }
+
+ override void visit(SynchronizedStatement s)
+ {
+ result = blockExit(s._body, func, mustNotThrow);
+ }
+
+ override void visit(WithStatement s)
+ {
+ result = BE.none;
+ if (canThrow(s.exp, func, mustNotThrow))
+ result = BE.throw_;
+ result |= blockExit(s._body, func, mustNotThrow);
+ }
+
+ override void visit(TryCatchStatement s)
+ {
+ assert(s._body);
+ result = blockExit(s._body, func, false);
+
+ int catchresult = 0;
+ foreach (c; *s.catches)
+ {
+ if (c.type == Type.terror)
+ continue;
+
+ int cresult = blockExit(c.handler, func, mustNotThrow);
+
+ /* If we're catching Object, then there is no throwing
+ */
+ Identifier id = c.type.toBasetype().isClassHandle().ident;
+ if (c.internalCatch && (cresult & BE.fallthru))
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=11542
+ // leave blockExit flags of the body
+ cresult &= ~BE.fallthru;
+ }
+ else if (id == Id.Object || id == Id.Throwable)
+ {
+ result &= ~(BE.throw_ | BE.errthrow);
+ }
+ else if (id == Id.Exception)
+ {
+ result &= ~BE.throw_;
+ }
+ catchresult |= cresult;
+ }
+ if (mustNotThrow && (result & BE.throw_))
+ {
+ // now explain why this is nothrow
+ blockExit(s._body, func, mustNotThrow);
+ }
+ result |= catchresult;
+ }
+
+ override void visit(TryFinallyStatement s)
+ {
+ result = BE.fallthru;
+ if (s._body)
+ result = blockExit(s._body, func, false);
+
+ // check finally body as well, it may throw (bug #4082)
+ int finalresult = BE.fallthru;
+ if (s.finalbody)
+ finalresult = blockExit(s.finalbody, func, false);
+
+ // If either body or finalbody halts
+ if (result == BE.halt)
+ finalresult = BE.none;
+ if (finalresult == BE.halt)
+ result = BE.none;
+
+ if (mustNotThrow)
+ {
+ // now explain why this is nothrow
+ if (s._body && (result & BE.throw_))
+ blockExit(s._body, func, mustNotThrow);
+ if (s.finalbody && (finalresult & BE.throw_))
+ blockExit(s.finalbody, func, mustNotThrow);
+ }
+
+ version (none)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=13201
+ // Mask to prevent spurious warnings for
+ // destructor call, exit of synchronized statement, etc.
+ if (result == BE.halt && finalresult != BE.halt && s.finalbody && s.finalbody.hasCode())
+ {
+ s.finalbody.warning("statement is not reachable");
+ }
+ }
+
+ if (!(finalresult & BE.fallthru))
+ result &= ~BE.fallthru;
+ result |= finalresult & ~BE.fallthru;
+ }
+
+ override void visit(ScopeGuardStatement s)
+ {
+ // At this point, this statement is just an empty placeholder
+ result = BE.fallthru;
+ }
+
+ override void visit(ThrowStatement s)
+ {
+ if (s.internalThrow)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=8675
+ // Allow throwing 'Throwable' object even if mustNotThrow.
+ result = BE.fallthru;
+ return;
+ }
+
+ Type t = s.exp.type.toBasetype();
+ ClassDeclaration cd = t.isClassHandle();
+ assert(cd);
+
+ if (cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null))
+ {
+ result = BE.errthrow;
+ return;
+ }
+ if (mustNotThrow)
+ s.error("`%s` is thrown but not caught", s.exp.type.toChars());
+
+ result = BE.throw_;
+ }
+
+ override void visit(GotoStatement s)
+ {
+ //printf("GotoStatement::blockExit(%p)\n", s);
+ result = BE.goto_;
+ }
+
+ override void visit(LabelStatement s)
+ {
+ //printf("LabelStatement::blockExit(%p)\n", s);
+ result = blockExit(s.statement, func, mustNotThrow);
+ if (s.breaks)
+ result |= BE.fallthru;
+ }
+
+ override void visit(CompoundAsmStatement s)
+ {
+ // Assume the worst
+ result = BE.fallthru | BE.return_ | BE.goto_ | BE.halt;
+ if (!(s.stc & STC.nothrow_))
+ {
+ if (mustNotThrow && !(s.stc & STC.nothrow_))
+ s.deprecation("`asm` statement is assumed to throw - mark it with `nothrow` if it does not");
+ else
+ result |= BE.throw_;
+ }
+ }
+
+ override void visit(ImportStatement s)
+ {
+ result = BE.fallthru;
+ }
+ }
+
+ if (!s)
+ return BE.fallthru;
+ scope BlockExit be = new BlockExit(func, mustNotThrow);
+ s.accept(be);
+ return be.result;
+}
+
diff --git a/gcc/d/dmd/builtin.d b/gcc/d/dmd/builtin.d
new file mode 100644
index 0000000..b99f690
--- /dev/null
+++ b/gcc/d/dmd/builtin.d
@@ -0,0 +1,33 @@
+/**
+ * Implement CTFE for intrinsic (builtin) functions.
+ *
+ * Currently includes functions from `std.math`, `core.math` and `core.bitop`.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/builtin.d, _builtin.d)
+ * Documentation: https://dlang.org/phobos/dmd_builtin.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/builtin.d
+ */
+
+module dmd.builtin;
+
+import core.stdc.math;
+import core.stdc.string;
+import dmd.arraytypes;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+
+/**********************************
+ * Determine if function is a builtin one that we can
+ * evaluate at compile time.
+ */
+public extern (C++) BUILTIN isBuiltin(FuncDeclaration fd);
+
+/**************************************
+ * Evaluate builtin function.
+ * Return result; NULL if cannot evaluate it.
+ */
+public extern (C++) Expression eval_builtin(Loc loc, FuncDeclaration fd, Expressions* arguments);
diff --git a/gcc/d/dmd/canthrow.c b/gcc/d/dmd/canthrow.c
deleted file mode 100644
index 5d180f5..0000000
--- a/gcc/d/dmd/canthrow.c
+++ /dev/null
@@ -1,316 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/canthrow.c
- */
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "init.h"
-#include "expression.h"
-#include "template.h"
-#include "statement.h"
-#include "mtype.h"
-#include "utf.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "scope.h"
-#include "attrib.h"
-#include "tokens.h"
-
-bool Dsymbol_canThrow(Dsymbol *s, FuncDeclaration *func, bool mustNotThrow);
-bool walkPostorder(Expression *e, StoppableVisitor *v);
-
-/********************************************
- * Returns true if the expression may throw exceptions.
- * If 'mustNotThrow' is true, generate an error if it throws
- */
-
-bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow)
-{
- //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars());
-
- // stop walking if we determine this expression can throw
- class CanThrow : public StoppableVisitor
- {
- FuncDeclaration *func;
- bool mustNotThrow;
-
- public:
- CanThrow(FuncDeclaration *func, bool mustNotThrow)
- : func(func), mustNotThrow(mustNotThrow)
- {
- }
-
- void visit(Expression *)
- {
- }
-
- void visit(DeclarationExp *de)
- {
- stop = Dsymbol_canThrow(de->declaration, func, mustNotThrow);
- }
-
- void visit(CallExp *ce)
- {
- if (global.errors && !ce->e1->type)
- return; // error recovery
-
- /* If calling a function or delegate that is typed as nothrow,
- * then this expression cannot throw.
- * Note that pure functions can throw.
- */
- Type *t = ce->e1->type->toBasetype();
- if (ce->f && ce->f == func)
- return;
- if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow)
- return;
- if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow)
- return;
-
- if (mustNotThrow)
- {
- if (ce->f)
- {
- ce->error("%s `%s` is not nothrow",
- ce->f->kind(), ce->f->toPrettyChars());
- }
- else
- {
- Expression *e1 = ce->e1;
- if (e1->op == TOKstar) // print 'fp' if e1 is (*fp)
- e1 = ((PtrExp *)e1)->e1;
- ce->error("`%s` is not nothrow", e1->toChars());
- }
- }
- stop = true;
- }
-
- void visit(NewExp *ne)
- {
- if (ne->member)
- {
- if (ne->allocator)
- {
- // Bugzilla 14407
- Type *t = ne->allocator->type->toBasetype();
- if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
- {
- if (mustNotThrow)
- {
- ne->error("%s `%s` is not nothrow",
- ne->allocator->kind(), ne->allocator->toPrettyChars());
- }
- stop = true;
- }
- }
- // See if constructor call can throw
- Type *t = ne->member->type->toBasetype();
- if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
- {
- if (mustNotThrow)
- {
- ne->error("%s `%s` is not nothrow",
- ne->member->kind(), ne->member->toPrettyChars());
- }
- stop = true;
- }
- }
- // regard storage allocation failures as not recoverable
- }
-
- void visit(DeleteExp *de)
- {
- Type *tb = de->e1->type->toBasetype();
- AggregateDeclaration *ad = NULL;
- switch (tb->ty)
- {
- case Tclass:
- ad = ((TypeClass *)tb)->sym;
- break;
-
- case Tpointer:
- tb = ((TypePointer *)tb)->next->toBasetype();
- if (tb->ty == Tstruct)
- ad = ((TypeStruct *)tb)->sym;
- break;
-
- case Tarray:
- {
- Type *tv = tb->nextOf()->baseElemOf();
- if (tv->ty == Tstruct)
- {
- ad = ((TypeStruct *)tv)->sym;
- break;
- }
- }
-
- default:
- break;
- }
- if (!ad)
- return;
-
- if (ad->dtor)
- {
- Type *t = ad->dtor->type->toBasetype();
- if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
- {
- if (mustNotThrow)
- {
- de->error("%s `%s` is not nothrow",
- ad->dtor->kind(), ad->dtor->toPrettyChars());
- }
- stop = true;
- }
- }
- if (ad->aggDelete && tb->ty != Tarray)
- {
- Type *t = ad->aggDelete->type;
- if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
- {
- if (mustNotThrow)
- {
- de->error("%s `%s` is not nothrow",
- ad->aggDelete->kind(), ad->aggDelete->toPrettyChars());
- }
- stop = true;
- }
- }
- }
-
- void visit(AssignExp *ae)
- {
- // blit-init cannot throw
- if (ae->op == TOKblit)
- return;
-
- /* Element-wise assignment could invoke postblits.
- */
- Type *t;
- if (ae->type->toBasetype()->ty == Tsarray)
- {
- if (!ae->e2->isLvalue())
- return;
- t = ae->type;
- }
- else if (ae->e1->op == TOKslice)
- t = ((SliceExp *)ae->e1)->e1->type;
- else
- return;
-
- Type *tv = t->baseElemOf();
- if (tv->ty != Tstruct)
- return;
- StructDeclaration *sd = ((TypeStruct *)tv)->sym;
- if (!sd->postblit || sd->postblit->type->ty != Tfunction)
- return;
-
- if (((TypeFunction *)sd->postblit->type)->isnothrow)
- ;
- else
- {
- if (mustNotThrow)
- {
- ae->error("%s `%s` is not nothrow",
- sd->postblit->kind(), sd->postblit->toPrettyChars());
- }
- stop = true;
- }
- }
-
- void visit(NewAnonClassExp *)
- {
- assert(0); // should have been lowered by semantic()
- }
- };
-
- CanThrow ct(func, mustNotThrow);
- return walkPostorder(e, &ct);
-}
-
-/**************************************
- * Does symbol, when initialized, throw?
- * Mirrors logic in Dsymbol_toElem().
- */
-
-bool Dsymbol_canThrow(Dsymbol *s, FuncDeclaration *func, bool mustNotThrow)
-{
- AttribDeclaration *ad;
- VarDeclaration *vd;
- TemplateMixin *tm;
- TupleDeclaration *td;
-
- //printf("Dsymbol_toElem() %s\n", s->toChars());
- ad = s->isAttribDeclaration();
- if (ad)
- {
- Dsymbols *decl = ad->include(NULL);
- if (decl && decl->length)
- {
- for (size_t i = 0; i < decl->length; i++)
- {
- s = (*decl)[i];
- if (Dsymbol_canThrow(s, func, mustNotThrow))
- return true;
- }
- }
- }
- else if ((vd = s->isVarDeclaration()) != NULL)
- {
- s = s->toAlias();
- if (s != vd)
- return Dsymbol_canThrow(s, func, mustNotThrow);
- if (vd->storage_class & STCmanifest)
- ;
- else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared))
- ;
- else
- {
- if (vd->_init)
- {
- ExpInitializer *ie = vd->_init->isExpInitializer();
- if (ie && canThrow(ie->exp, func, mustNotThrow))
- return true;
- }
- if (vd->needsScopeDtor())
- return canThrow(vd->edtor, func, mustNotThrow);
- }
- }
- else if ((tm = s->isTemplateMixin()) != NULL)
- {
- //printf("%s\n", tm->toChars());
- if (tm->members)
- {
- for (size_t i = 0; i < tm->members->length; i++)
- {
- Dsymbol *sm = (*tm->members)[i];
- if (Dsymbol_canThrow(sm, func, mustNotThrow))
- return true;
- }
- }
- }
- else if ((td = s->isTupleDeclaration()) != NULL)
- {
- for (size_t i = 0; i < td->objects->length; i++)
- {
- RootObject *o = (*td->objects)[i];
- if (o->dyncast() == DYNCAST_EXPRESSION)
- {
- Expression *eo = (Expression *)o;
- if (eo->op == TOKdsymbol)
- {
- DsymbolExp *se = (DsymbolExp *)eo;
- if (Dsymbol_canThrow(se->s, func, mustNotThrow))
- return true;
- }
- }
- }
- }
- return false;
-}
diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d
new file mode 100644
index 0000000..ed05af6
--- /dev/null
+++ b/gcc/d/dmd/canthrow.d
@@ -0,0 +1,244 @@
+/**
+ * Perform checks for `nothrow`.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/function.html#nothrow-functions, Nothrow Functions)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/canthrow.d, _canthrow.d)
+ * Documentation: https://dlang.org/phobos/dmd_canthrow.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/canthrow.d
+ */
+
+module dmd.canthrow;
+
+import dmd.aggregate;
+import dmd.apply;
+import dmd.arraytypes;
+import dmd.attrib;
+import dmd.astenums;
+import dmd.declaration;
+import dmd.dsymbol;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.init;
+import dmd.mtype;
+import dmd.root.rootobject;
+import dmd.tokens;
+import dmd.visitor;
+
+/********************************************
+ * Returns true if the expression may throw exceptions.
+ * If 'mustNotThrow' is true, generate an error if it throws
+ */
+extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow)
+{
+ //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars());
+ // stop walking if we determine this expression can throw
+ extern (C++) final class CanThrow : StoppableVisitor
+ {
+ alias visit = typeof(super).visit;
+ FuncDeclaration func;
+ bool mustNotThrow;
+
+ public:
+ extern (D) this(FuncDeclaration func, bool mustNotThrow)
+ {
+ this.func = func;
+ this.mustNotThrow = mustNotThrow;
+ }
+
+ void checkFuncThrows(Expression e, FuncDeclaration f)
+ {
+ auto tf = f.type.toBasetype().isTypeFunction();
+ if (tf && !tf.isnothrow)
+ {
+ if (mustNotThrow)
+ {
+ e.error("%s `%s` is not `nothrow`",
+ f.kind(), f.toPrettyChars());
+
+ e.checkOverridenDtor(null, f, dd => dd.type.toTypeFunction().isnothrow, "not nothrow");
+ }
+ stop = true; // if any function throws, then the whole expression throws
+ }
+ }
+
+ override void visit(Expression)
+ {
+ }
+
+ override void visit(DeclarationExp de)
+ {
+ stop = Dsymbol_canThrow(de.declaration, func, mustNotThrow);
+ }
+
+ override void visit(CallExp ce)
+ {
+ if (ce.inDebugStatement)
+ return;
+
+ if (global.errors && !ce.e1.type)
+ return; // error recovery
+ /* If calling a function or delegate that is typed as nothrow,
+ * then this expression cannot throw.
+ * Note that pure functions can throw.
+ */
+ if (ce.f && ce.f == func)
+ return;
+ Type t = ce.e1.type.toBasetype();
+ auto tf = t.isTypeFunction();
+ if (tf && tf.isnothrow)
+ return;
+ else
+ {
+ auto td = t.isTypeDelegate();
+ if (td && td.nextOf().isTypeFunction().isnothrow)
+ return;
+ }
+
+ if (ce.f)
+ checkFuncThrows(ce, ce.f);
+ else if (mustNotThrow)
+ {
+ auto e1 = ce.e1;
+ if (auto pe = e1.isPtrExp()) // print 'fp' if e1 is (*fp)
+ e1 = pe.e1;
+ ce.error("`%s` is not `nothrow`", e1.toChars());
+ }
+ stop = true;
+ }
+
+ override void visit(NewExp ne)
+ {
+ if (ne.member)
+ {
+ // See if constructor call can throw
+ checkFuncThrows(ne, ne.member);
+ }
+ // regard storage allocation failures as not recoverable
+ }
+
+ override void visit(DeleteExp de)
+ {
+ Type tb = de.e1.type.toBasetype();
+ AggregateDeclaration ad = null;
+ switch (tb.ty)
+ {
+ case Tclass:
+ ad = tb.isTypeClass().sym;
+ break;
+
+ case Tpointer:
+ case Tarray:
+ auto ts = tb.nextOf().baseElemOf().isTypeStruct();
+ if (!ts)
+ return;
+ ad = ts.sym;
+ break;
+
+ default:
+ assert(0); // error should have been detected by semantic()
+ }
+
+ if (ad.dtor)
+ checkFuncThrows(de, ad.dtor);
+ }
+
+ override void visit(AssignExp ae)
+ {
+ // blit-init cannot throw
+ if (ae.op == TOK.blit)
+ return;
+ /* Element-wise assignment could invoke postblits.
+ */
+ Type t;
+ if (ae.type.toBasetype().ty == Tsarray)
+ {
+ if (!ae.e2.isLvalue())
+ return;
+ t = ae.type;
+ }
+ else if (auto se = ae.e1.isSliceExp())
+ t = se.e1.type;
+ else
+ return;
+
+ if (auto ts = t.baseElemOf().isTypeStruct())
+ if (auto postblit = ts.sym.postblit)
+ checkFuncThrows(ae, postblit);
+ }
+
+ override void visit(NewAnonClassExp)
+ {
+ assert(0); // should have been lowered by semantic()
+ }
+ }
+
+ scope CanThrow ct = new CanThrow(func, mustNotThrow);
+ return walkPostorder(e, ct);
+}
+
+/**************************************
+ * Does symbol, when initialized, throw?
+ * Mirrors logic in Dsymbol_toElem().
+ */
+private bool Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow)
+{
+ int symbolDg(Dsymbol s)
+ {
+ return Dsymbol_canThrow(s, func, mustNotThrow);
+ }
+
+ //printf("Dsymbol_toElem() %s\n", s.toChars());
+ if (auto vd = s.isVarDeclaration())
+ {
+ s = s.toAlias();
+ if (s != vd)
+ return Dsymbol_canThrow(s, func, mustNotThrow);
+ if (vd.storage_class & STC.manifest)
+ {
+ }
+ else if (vd.isStatic() || vd.storage_class & (STC.extern_ | STC.tls | STC.gshared))
+ {
+ }
+ else
+ {
+ if (vd._init)
+ {
+ if (auto ie = vd._init.isExpInitializer())
+ if (canThrow(ie.exp, func, mustNotThrow))
+ return true;
+ }
+ if (vd.needsScopeDtor())
+ return canThrow(vd.edtor, func, mustNotThrow);
+ }
+ }
+ else if (auto ad = s.isAttribDeclaration())
+ {
+ return ad.include(null).foreachDsymbol(&symbolDg) != 0;
+ }
+ else if (auto tm = s.isTemplateMixin())
+ {
+ return tm.members.foreachDsymbol(&symbolDg) != 0;
+ }
+ else if (auto td = s.isTupleDeclaration())
+ {
+ for (size_t i = 0; i < td.objects.dim; i++)
+ {
+ RootObject o = (*td.objects)[i];
+ if (o.dyncast() == DYNCAST.expression)
+ {
+ Expression eo = cast(Expression)o;
+ if (auto se = eo.isDsymbolExp())
+ {
+ if (Dsymbol_canThrow(se.s, func, mustNotThrow))
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
diff --git a/gcc/d/dmd/chkformat.c b/gcc/d/dmd/chkformat.c
deleted file mode 100644
index a4a97c9..0000000
--- a/gcc/d/dmd/chkformat.c
+++ /dev/null
@@ -1,985 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- */
-
-// Check the arguments to `printf` and `scanf` against the `format` string.
-
-#include "root/dsystem.h"
-#include "root/dcompat.h"
-
-#include "arraytypes.h"
-#include "cond.h"
-#include "errors.h"
-#include "expression.h"
-#include "globals.h"
-#include "identifier.h"
-#include "mtype.h"
-#include "target.h"
-
-
-/* Different kinds of formatting specifications, variations we don't
- care about are merged. (Like we don't care about the difference between
- f, e, g, a, etc.)
-
- For `scanf`, every format is a pointer.
- */
-enum Format
-{
- Format_d, // int
- Format_hhd, // signed char
- Format_hd, // short int
- Format_ld, // long int
- Format_lld, // long long int
- Format_jd, // intmax_t
- Format_zd, // size_t
- Format_td, // ptrdiff_t
- Format_u, // unsigned int
- Format_hhu, // unsigned char
- Format_hu, // unsigned short int
- Format_lu, // unsigned long int
- Format_llu, // unsigned long long int
- Format_ju, // uintmax_t
- Format_g, // float (scanf) / double (printf)
- Format_lg, // double (scanf)
- Format_Lg, // long double (both)
- Format_s, // char string (both)
- Format_ls, // wchar_t string (both)
- Format_c, // char (printf)
- Format_lc, // wint_t (printf)
- Format_p, // pointer
- Format_n, // pointer to int
- Format_hhn, // pointer to signed char
- Format_hn, // pointer to short
- Format_ln, // pointer to long int
- Format_lln, // pointer to long long int
- Format_jn, // pointer to intmax_t
- Format_zn, // pointer to size_t
- Format_tn, // pointer to ptrdiff_t
- Format_GNU_a, // GNU ext. : address to a string with no maximum size (scanf)
- Format_GNU_m, // GNU ext. : string corresponding to the error code in errno (printf) / length modifier (scanf)
- Format_percent, // %% (i.e. no argument)
- Format_error, // invalid format specification
-};
-
-/**************************************
- * Parse the *length specifier* and the *specifier* of the following form:
- * `[length]specifier`
- *
- * Params:
- * format = format string
- * idx = index of of start of format specifier,
- * which gets updated to index past the end of it,
- * even if `Format_error` is returned
- * genSpecifier = Generic specifier. For instance, it will be set to `d` if the
- * format is `hdd`.
- * Returns:
- * Format
- */
-static Format parseGenericFormatSpecifier(const char *format,
- size_t &idx, char &genSpecifier, bool useGNUExts =
- findCondition(global.versionids, Identifier::idPool("CRuntime_Glibc")))
-{
- genSpecifier = 0;
-
- const size_t length = strlen(format);
-
- /* Read the `length modifier`
- */
- const char lm = format[idx];
- bool lm1= false; // if jztL
- bool lm2= false; // if `hh` or `ll`
- if (lm == 'j' ||
- lm == 'z' ||
- lm == 't' ||
- lm == 'L')
- {
- ++idx;
- if (idx == length)
- return Format_error;
- lm1 = true;
- }
- else if (lm == 'h' || lm == 'l')
- {
- ++idx;
- if (idx == length)
- return Format_error;
- lm2 = lm == format[idx];
- if (lm2)
- {
- ++idx;
- if (idx == length)
- return Format_error;
- }
- }
-
- /* Read the `specifier`
- */
- Format specifier;
- const char sc = format[idx];
- genSpecifier = sc;
- switch (sc)
- {
- case 'd':
- case 'i':
- if (lm == 'L')
- specifier = Format_error;
- else
- specifier = lm == 'h' && lm2 ? Format_hhd :
- lm == 'h' ? Format_hd :
- lm == 'l' && lm2 ? Format_lld :
- lm == 'l' ? Format_ld :
- lm == 'j' ? Format_jd :
- lm == 'z' ? Format_zd :
- lm == 't' ? Format_td :
- Format_d;
- break;
-
- case 'u':
- case 'o':
- case 'x':
- case 'X':
- if (lm == 'L')
- specifier = Format_error;
- else
- specifier = lm == 'h' && lm2 ? Format_hhu :
- lm == 'h' ? Format_hu :
- lm == 'l' && lm2 ? Format_llu :
- lm == 'l' ? Format_lu :
- lm == 'j' ? Format_ju :
- lm == 'z' ? Format_zd :
- lm == 't' ? Format_td :
- Format_u;
- break;
-
- case 'a':
- if (useGNUExts)
- {
- // https://www.gnu.org/software/libc/manual/html_node/Dynamic-String-Input.html
- specifier = Format_GNU_a;
- break;
- }
- /* fall through */
-
- case 'f':
- case 'F':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- case 'A':
- if (lm == 'L')
- specifier = Format_Lg;
- else if (lm1 || lm2 || lm == 'h')
- specifier = Format_error;
- else
- specifier = lm == 'l' ? Format_lg : Format_g;
- break;
-
- case 'c':
- if (lm1 || lm2 || lm == 'h')
- specifier = Format_error;
- else
- specifier = lm == 'l' ? Format_lc : Format_c;
- break;
-
- case 's':
- if (lm1 || lm2 || lm == 'h')
- specifier = Format_error;
- else
- specifier = lm == 'l' ? Format_ls : Format_s;
- break;
-
- case 'p':
- if (lm1 || lm2 || lm == 'h' || lm == 'l')
- specifier = Format_error;
- else
- specifier = Format_p;
- break;
-
- case 'n':
- if (lm == 'L')
- specifier = Format_error;
- else
- specifier = lm == 'l' && lm2 ? Format_lln :
- lm == 'l' ? Format_ln :
- lm == 'h' && lm2 ? Format_hhn :
- lm == 'h' ? Format_hn :
- lm == 'j' ? Format_jn :
- lm == 'z' ? Format_zn :
- lm == 't' ? Format_tn :
- Format_n;
- break;
-
- case 'm':
- if (useGNUExts)
- {
- // http://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html
- specifier = Format_GNU_m;
- break;
- }
- goto Ldefault;
-
- default:
- Ldefault:
- specifier = Format_error;
- break;
- }
-
- ++idx;
- return specifier; // success
-}
-
-Format formatError(size_t &idx, size_t i)
-{
- idx = i;
- return Format_error;
-}
-
-/**************************************
- * Parse the *format specifier* which is of the form:
- *
- * `%[*][width][length]specifier`
- *
- * Params:
- * format = format string
- * idx = index of `%` of start of format specifier,
- * which gets updated to index past the end of it,
- * even if `Format_error` is returned
- * asterisk = set if there is a `*` sub-specifier
- * Returns:
- * Format
- */
-static Format parseScanfFormatSpecifier(const char *format, size_t &idx,
- bool &asterisk)
-{
- asterisk = false;
-
- size_t i = idx;
- assert(format[i] == '%');
- const size_t length = strlen(format);
-
- ++i;
- if (i == length)
- return formatError(idx, i);
-
- if (format[i] == '%')
- {
- idx = i + 1;
- return Format_percent;
- }
-
- // * sub-specifier
- if (format[i] == '*')
- {
- ++i;
- if (i == length)
- return formatError(idx, i);
- asterisk = true;
- }
-
- // fieldWidth
- while (isdigit(format[i]))
- {
- i++;
- if (i == length)
- return formatError(idx, i);
- }
-
- /* Read the scanset
- * A scanset can be anything, so we just check that it is paired
- */
- if (format[i] == '[')
- {
- while (i < length)
- {
- if (format[i] == ']')
- break;
- ++i;
- }
-
- // no `]` found
- if (i == length)
- return formatError(idx, i);
-
- ++i;
- // no specifier after `]`
- // it could be mixed with the one above, but then idx won't have the right index
- if (i == length)
- return formatError(idx, i);
- }
-
- /* Read the specifier
- */
- char genSpec;
- Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
- if (specifier == Format_error)
- return formatError(idx, i);
-
- idx = i;
- return specifier; // success
-}
-
-/**************************************
- * Parse the *format specifier* which is of the form:
- *
- * `%[flags][field width][.precision][length modifier]specifier`
- *
- * Params:
- * format = format string
- * idx = index of `%` of start of format specifier,
- * which gets updated to index past the end of it,
- * even if `Format_error` is returned
- * widthStar = set if * for width
- * precisionStar = set if * for precision
- * Returns:
- * Format
- */
-static Format parsePrintfFormatSpecifier(const char *format, size_t &idx,
- bool &widthStar, bool &precisionStar)
-{
- widthStar = false;
- precisionStar = false;
-
- size_t i = idx;
- assert(format[i] == '%');
- const size_t format_length = strlen(format);
- const size_t length = format_length;
- bool hash = false;
- bool zero = false;
- bool flags = false;
- bool width = false;
- bool precision = false;
-
- ++i;
- if (i == length)
- return formatError(idx, i);
-
- if (format[i] == '%')
- {
- idx = i + 1;
- return Format_percent;
- }
-
- /* Read the `flags`
- */
- while (1)
- {
- const char c = format[i];
- if (c == '-' ||
- c == '+' ||
- c == ' ')
- {
- flags = true;
- }
- else if (c == '#')
- {
- hash = true;
- }
- else if (c == '0')
- {
- zero = true;
- }
- else
- break;
- ++i;
- if (i == length)
- return formatError(idx, i);
- }
-
- /* Read the `field width`
- */
- {
- const char c = format[i];
- if (c == '*')
- {
- width = true;
- widthStar = true;
- ++i;
- if (i == length)
- return formatError(idx, i);
- }
- else if ('1' <= c && c <= '9')
- {
- width = true;
- ++i;
- if (i == length)
- return formatError(idx, i);
- while ('0' <= format[i] && format[i] <= '9')
- {
- ++i;
- if (i == length)
- return formatError(idx, i);
- }
- }
- }
-
- /* Read the `precision`
- */
- if (format[i] == '.')
- {
- precision = true;
- ++i;
- if (i == length)
- return formatError(idx, i);
- const char c = format[i];
- if (c == '*')
- {
- precisionStar = true;
- ++i;
- if (i == length)
- return formatError(idx, i);
- }
- else if ('0' <= c && c <= '9')
- {
- ++i;
- if (i == length)
- return formatError(idx, i);
- while ('0' <= format[i] && format[i] <= '9')
- {
- ++i;
- if (i == length)
- return formatError(idx, i);
- }
- }
- }
-
- /* Read the specifier
- */
- char genSpec;
- Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
- if (specifier == Format_error)
- return formatError(idx, i);
-
- switch (genSpec)
- {
- case 'c':
- case 's':
- if (hash || zero)
- return formatError(idx, i);
- break;
-
- case 'd':
- case 'i':
- if (hash)
- return formatError(idx, i);
- break;
-
- case 'n':
- if (hash || zero || precision || width || flags)
- return formatError(idx, i);
- break;
-
- default:
- break;
- }
-
- idx = i;
- return specifier; // success
-}
-
-/*******************************************/
-
-static Expression *getNextPrintfArg(const Loc &loc, Expressions &args, size_t &n,
- size_t gnu_m_count, bool &skip)
-{
- if (n == args.length)
- {
- if (args.length < (n + 1) - gnu_m_count)
- deprecation(loc, "more format specifiers than %d arguments", (int)n);
- else
- skip = true;
- return NULL;
- }
- return args[n++];
-}
-
-static void errorPrintfFormat(const char *prefix, DString &slice, Expression *arg,
- const char *texpect, Type *tactual)
-{
- deprecation(arg->loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
- prefix ? prefix : "", arg->toChars(), (int)slice.length, slice.ptr, texpect, tactual->toChars());
-}
-
-/******************************************
- * Check that arguments to a printf format string are compatible
- * with that string. Issue errors for incompatibilities.
- *
- * Follows the C99 specification for printf.
- *
- * Takes a generous, rather than strict, view of compatiblity.
- * For example, an unsigned value can be formatted with a signed specifier.
- *
- * Diagnosed incompatibilities are:
- *
- * 1. incompatible sizes which will cause argument misalignment
- * 2. deferencing arguments that are not pointers
- * 3. insufficient number of arguments
- * 4. struct arguments
- * 5. array and slice arguments
- * 6. non-pointer arguments to `s` specifier
- * 7. non-standard formats
- * 8. undefined behavior per C99
- *
- * Per the C Standard, extra arguments are ignored.
- *
- * No attempt is made to fix the arguments or the format string.
- *
- * Params:
- * loc = location for error messages
- * format = format string
- * args = arguments to match with format string
- * isVa_list = if a "v" function (format check only)
- *
- * Returns:
- * `true` if errors occurred
- * References:
- * C99 7.19.6.1
- * http://www.cplusplus.com/reference/cstdio/printf/
- */
-bool checkPrintfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list)
-{
- //printf("checkPrintFormat('%s')\n", format);
- size_t n = 0; // index in args
- size_t gnu_m_count = 0; // number of Format_GNU_m
- const size_t format_length = strlen(format);
- for (size_t i = 0; i < format_length;)
- {
- if (format[i] != '%')
- {
- ++i;
- continue;
- }
- bool widthStar = false;
- bool precisionStar = false;
- size_t j = i;
- const Format fmt = parsePrintfFormatSpecifier(format, j, widthStar, precisionStar);
- DString slice = DString(j - i, format + i);
- i = j;
-
- if (fmt == Format_percent)
- continue; // "%%", no arguments
-
- if (isVa_list)
- {
- // format check only
- if (fmt == Format_error)
- deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
- continue;
- }
-
- if (fmt == Format_GNU_m)
- ++gnu_m_count;
-
- if (widthStar)
- {
- bool skip = false;
- Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
- if (skip)
- continue;
- if (!e)
- return true;
- Type *t = e->type->toBasetype();
- if (t->ty != Tint32 && t->ty != Tuns32)
- errorPrintfFormat("width ", slice, e, "int", t);
- }
-
- if (precisionStar)
- {
- bool skip = false;
- Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
- if (skip)
- continue;
- if (!e)
- return true;
- Type *t = e->type->toBasetype();
- if (t->ty != Tint32 && t->ty != Tuns32)
- errorPrintfFormat("precision ", slice, e, "int", t);
- }
-
- bool skip = false;
- Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
- if (skip)
- continue;
- if (!e)
- return true;
- Type *t = e->type->toBasetype();
- Type *tnext = t->nextOf();
- const unsigned c_longsize = target.c.longsize;
- const unsigned ptrsize = target.ptrsize;
-
- // Types which are promoted to int are allowed.
- // Spec: C99 6.5.2.2.7
- switch (fmt)
- {
- case Format_u: // unsigned int
- case Format_d: // int
- if (t->ty != Tint32 && t->ty != Tuns32)
- errorPrintfFormat(NULL, slice, e, fmt == Format_u ? "uint" : "int", t);
- break;
-
- case Format_hhu: // unsigned char
- case Format_hhd: // signed char
- if (t->ty != Tint32 && t->ty != Tuns32 && t->ty != Tint8 && t->ty != Tuns8)
- errorPrintfFormat(NULL, slice, e, fmt == Format_hhu ? "ubyte" : "byte", t);
- break;
-
- case Format_hu: // unsigned short int
- case Format_hd: // short int
- if (t->ty != Tint32 && t->ty != Tuns32 && t->ty != Tint16 && t->ty != Tuns16)
- errorPrintfFormat(NULL, slice, e, fmt == Format_hu ? "ushort" : "short", t);
- break;
-
- case Format_lu: // unsigned long int
- case Format_ld: // long int
- if (!(t->isintegral() && t->size() == c_longsize))
- {
- if (fmt == Format_lu)
- errorPrintfFormat(NULL, slice, e, (c_longsize == 4 ? "uint" : "ulong"), t);
- else
- errorPrintfFormat(NULL, slice, e, (c_longsize == 4 ? "int" : "long"), t);
- }
- break;
-
- case Format_llu: // unsigned long long int
- case Format_lld: // long long int
- if (t->ty != Tint64 && t->ty != Tuns64)
- errorPrintfFormat(NULL, slice, e, fmt == Format_llu ? "ulong" : "long", t);
- break;
-
- case Format_ju: // uintmax_t
- case Format_jd: // intmax_t
- if (t->ty != Tint64 && t->ty != Tuns64)
- {
- if (fmt == Format_ju)
- errorPrintfFormat(NULL, slice, e, "core.stdc.stdint.uintmax_t", t);
- else
- errorPrintfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t", t);
- }
- break;
-
- case Format_zd: // size_t
- if (!(t->isintegral() && t->size() == ptrsize))
- errorPrintfFormat(NULL, slice, e, "size_t", t);
- break;
-
- case Format_td: // ptrdiff_t
- if (!(t->isintegral() && t->size() == ptrsize))
- errorPrintfFormat(NULL, slice, e, "ptrdiff_t", t);
- break;
-
- case Format_GNU_a: // Format_GNU_a is only for scanf
- case Format_lg:
- case Format_g: // double
- if (t->ty != Tfloat64 && t->ty != Timaginary64)
- errorPrintfFormat(NULL, slice, e, "double", t);
- break;
-
- case Format_Lg: // long double
- if (t->ty != Tfloat80 && t->ty != Timaginary80)
- errorPrintfFormat(NULL, slice, e, "real", t);
- break;
-
- case Format_p: // pointer
- if (t->ty != Tpointer && t->ty != Tnull && t->ty != Tclass && t->ty != Tdelegate && t->ty != Taarray)
- errorPrintfFormat(NULL, slice, e, "void*", t);
- break;
-
- case Format_n: // pointer to int
- if (!(t->ty == Tpointer && tnext->ty == Tint32))
- errorPrintfFormat(NULL, slice, e, "int*", t);
- break;
-
- case Format_ln: // pointer to long int
- if (!(t->ty == Tpointer && tnext->isintegral() && !tnext->isunsigned() && tnext->size() == c_longsize))
- errorPrintfFormat(NULL, slice, e, (c_longsize == 4 ? "int*" : "long*"), t);
- break;
-
- case Format_lln: // pointer to long long int
- if (!(t->ty == Tpointer && tnext->ty == Tint64))
- errorPrintfFormat(NULL, slice, e, "long*", t);
- break;
-
- case Format_hn: // pointer to short
- if (!(t->ty == Tpointer && tnext->ty == Tint16))
- errorPrintfFormat(NULL, slice, e, "short*", t);
- break;
-
- case Format_hhn: // pointer to signed char
- if (!(t->ty == Tpointer && tnext->ty == Tint16))
- errorPrintfFormat(NULL, slice, e, "byte*", t);
- break;
-
- case Format_jn: // pointer to intmax_t
- if (!(t->ty == Tpointer && tnext->ty == Tint64))
- errorPrintfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t*", t);
- break;
-
- case Format_zn: // pointer to size_t
- if (!(t->ty == Tpointer && tnext->isintegral() && tnext->isunsigned() && tnext->size() == ptrsize))
- errorPrintfFormat(NULL, slice, e, "size_t*", t);
- break;
-
- case Format_tn: // pointer to ptrdiff_t
- if (!(t->ty == Tpointer && tnext->isintegral() && !tnext->isunsigned() && tnext->size() == ptrsize))
- errorPrintfFormat(NULL, slice, e, "ptrdiff_t*", t);
- break;
-
- case Format_c: // char
- if (t->ty != Tint32 && t->ty != Tuns32)
- errorPrintfFormat(NULL, slice, e, "char", t);
- break;
-
- case Format_lc: // wint_t
- if (t->ty != Tint32 && t->ty != Tuns32)
- errorPrintfFormat(NULL, slice, e, "wchar_t", t);
- break;
-
- case Format_s: // pointer to char string
- if (!(t->ty == Tpointer && (tnext->ty == Tchar || tnext->ty == Tint8 || tnext->ty == Tuns8)))
- errorPrintfFormat(NULL, slice, e, "char*", t);
- break;
-
- case Format_ls: // pointer to wchar_t string
- {
- if (!(t->ty == Tpointer && tnext == target.c.twchar_t))
- errorPrintfFormat(NULL, slice, e, "wchar_t*", t);
- break;
- }
- case Format_error:
- deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
- break;
-
- case Format_GNU_m:
- break; // not assert(0) because it may go through it if there are extra arguments
-
- case Format_percent:
- default:
- assert(0);
- }
- }
- return false;
-}
-
-/*******************************************/
-
-static Expression *getNextScanfArg(const Loc &loc, Expressions &args, size_t &n, bool asterisk)
-{
- if (n == args.length)
- {
- if (!asterisk)
- deprecation(loc, "more format specifiers than %d arguments", (int)n);
- return NULL;
- }
- return args[n++];
-}
-
-static void errorScanfFormat(const char *prefix, DString &slice,
- Expression *arg, const char *texpect, Type *tactual)
-{
- deprecation(arg->loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
- prefix ? prefix : "", arg->toChars(), (int)slice.length, slice.ptr, texpect, tactual->toChars());
-}
-
-/******************************************
- * Check that arguments to a scanf format string are compatible
- * with that string. Issue errors for incompatibilities.
- *
- * Follows the C99 specification for scanf.
- *
- * Takes a generous, rather than strict, view of compatiblity.
- * For example, an unsigned value can be formatted with a signed specifier.
- *
- * Diagnosed incompatibilities are:
- *
- * 1. incompatible sizes which will cause argument misalignment
- * 2. deferencing arguments that are not pointers
- * 3. insufficient number of arguments
- * 4. struct arguments
- * 5. array and slice arguments
- * 6. non-standard formats
- * 7. undefined behavior per C99
- *
- * Per the C Standard, extra arguments are ignored.
- *
- * No attempt is made to fix the arguments or the format string.
- *
- * Params:
- * loc = location for error messages
- * format = format string
- * args = arguments to match with format string
- * isVa_list = if a "v" function (format check only)
- *
- * Returns:
- * `true` if errors occurred
- * References:
- * C99 7.19.6.2
- * http://www.cplusplus.com/reference/cstdio/scanf/
- */
-bool checkScanfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list)
-{
- size_t n = 0;
- const size_t format_length = strlen(format);
- for (size_t i = 0; i < format_length;)
- {
- if (format[i] != '%')
- {
- ++i;
- continue;
- }
- bool asterisk = false;
- size_t j = i;
- const Format fmt = parseScanfFormatSpecifier(format, j, asterisk);
- DString slice = DString(j - i, format + i);
- i = j;
-
- if (fmt == Format_percent || asterisk)
- continue; // "%%", "%*": no arguments
-
- if (isVa_list)
- {
- // format check only
- if (fmt == Format_error)
- deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
- continue;
- }
-
- Expression *e = getNextScanfArg(loc, args, n, asterisk);
- if (!e)
- return true;
-
- Type *t = e->type->toBasetype();
- Type *tnext = t->nextOf();
- const unsigned c_longsize = target.c.longsize;
- const unsigned ptrsize = target.ptrsize;
-
- switch (fmt)
- {
- case Format_n:
- case Format_d: // pointer to int
- if (!(t->ty == Tpointer && tnext->ty == Tint32))
- errorScanfFormat(NULL, slice, e, "int*", t);
- break;
-
- case Format_hhn:
- case Format_hhd: // pointer to signed char
- if (!(t->ty == Tpointer && tnext->ty == Tint16))
- errorScanfFormat(NULL, slice, e, "byte*", t);
- break;
-
- case Format_hn:
- case Format_hd: // pointer to short
- if (!(t->ty == Tpointer && tnext->ty == Tint16))
- errorScanfFormat(NULL, slice, e, "short*", t);
- break;
-
- case Format_ln:
- case Format_ld: // pointer to long int
- if (!(t->ty == Tpointer && tnext->isintegral() && tnext->size() == c_longsize))
- errorScanfFormat(NULL, slice, e, (c_longsize == 4 ? "int*" : "long*"), t);
- break;
-
- case Format_lln:
- case Format_lld: // pointer to long long int
- if (!(t->ty == Tpointer && tnext->ty == Tint64))
- errorScanfFormat(NULL, slice, e, "long*", t);
- break;
-
- case Format_jn:
- case Format_jd: // pointer to intmax_t
- if (!(t->ty == Tpointer && tnext->ty == Tint64))
- errorScanfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t*", t);
- break;
-
- case Format_zn:
- case Format_zd: // pointer to size_t
- if (!(t->ty == Tpointer && tnext->isintegral() && tnext->isunsigned() && tnext->size() == ptrsize))
- errorScanfFormat(NULL, slice, e, "size_t*", t);
- break;
-
- case Format_tn:
- case Format_td: // pointer to ptrdiff_t
- if (!(t->ty == Tpointer && tnext->isintegral() && !tnext->isunsigned() && tnext->size() == ptrsize))
- errorScanfFormat(NULL, slice, e, "ptrdiff_t*", t);
- break;
-
- case Format_u: // pointer to unsigned int
- if (!(t->ty == Tpointer && tnext->ty == Tuns32))
- errorScanfFormat(NULL, slice, e, "uint*", t);
- break;
-
- case Format_hhu: // pointer to unsigned char
- if (!(t->ty == Tpointer && tnext->ty == Tuns8))
- errorScanfFormat(NULL, slice, e, "ubyte*", t);
- break;
-
- case Format_hu: // pointer to unsigned short int
- if (!(t->ty == Tpointer && tnext->ty == Tuns16))
- errorScanfFormat(NULL, slice, e, "ushort*", t);
- break;
-
- case Format_lu: // pointer to unsigned long int
- if (!(t->ty == Tpointer && tnext->isintegral() && tnext->isunsigned() && tnext->size() == c_longsize))
- errorScanfFormat(NULL, slice, e, (c_longsize == 4 ? "uint*" : "ulong*"), t);
- break;
-
- case Format_llu: // pointer to unsigned long long int
- if (!(t->ty == Tpointer && tnext->ty == Tuns64))
- errorScanfFormat(NULL, slice, e, "ulong*", t);
- break;
-
- case Format_ju: // pointer to uintmax_t
- if (!(t->ty == Tpointer && tnext->ty == Tuns64))
- errorScanfFormat(NULL, slice, e, "ulong*", t);
- break;
-
- case Format_g: // pointer to float
- if (!(t->ty == Tpointer && tnext->ty == Tfloat32))
- errorScanfFormat(NULL, slice, e, "float*", t);
- break;
-
- case Format_lg: // pointer to double
- if (!(t->ty == Tpointer && tnext->ty == Tfloat64))
- errorScanfFormat(NULL, slice, e, "double*", t);
- break;
-
- case Format_Lg: // pointer to long double
- if (!(t->ty == Tpointer && tnext->ty == Tfloat80))
- errorScanfFormat(NULL, slice, e, "real*", t);
- break;
-
- case Format_GNU_a:
- case Format_GNU_m:
- case Format_c:
- case Format_s: // pointer to char string
- if (!(t->ty == Tpointer && (tnext->ty == Tchar || tnext->ty == Tint8 || tnext->ty == Tuns8)))
- errorScanfFormat(NULL, slice, e, "char*", t);
- break;
-
- case Format_lc:
- case Format_ls: // pointer to wchar_t string
- {
- if (!(t->ty == Tpointer && tnext == target.c.twchar_t))
- errorScanfFormat(NULL, slice, e, "wchar_t*", t);
- break;
- }
- case Format_p: // double pointer
- if (!(t->ty == Tpointer && tnext->ty == Tpointer))
- errorScanfFormat(NULL, slice, e, "void**", t);
- break;
-
- case Format_error:
- deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
- break;
-
- case Format_percent:
- default:
- assert(0);
- }
- }
- return false;
-}
diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d
new file mode 100644
index 0000000..97adc5a
--- /dev/null
+++ b/gcc/d/dmd/chkformat.d
@@ -0,0 +1,1364 @@
+/**
+ * Check the arguments to `printf` and `scanf` against the `format` string.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/chkformat.d, _chkformat.d)
+ * Documentation: https://dlang.org/phobos/dmd_chkformat.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/chkformat.d
+ */
+module dmd.chkformat;
+
+//import core.stdc.stdio : printf, scanf;
+import core.stdc.ctype : isdigit;
+
+import dmd.astenums;
+import dmd.cond;
+import dmd.errors;
+import dmd.expression;
+import dmd.globals;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.target;
+
+
+/******************************************
+ * Check that arguments to a printf format string are compatible
+ * with that string. Issue errors for incompatibilities.
+ *
+ * Follows the C99 specification for printf.
+ *
+ * Takes a generous, rather than strict, view of compatiblity.
+ * For example, an unsigned value can be formatted with a signed specifier.
+ *
+ * Diagnosed incompatibilities are:
+ *
+ * 1. incompatible sizes which will cause argument misalignment
+ * 2. deferencing arguments that are not pointers
+ * 3. insufficient number of arguments
+ * 4. struct arguments
+ * 5. array and slice arguments
+ * 6. non-pointer arguments to `s` specifier
+ * 7. non-standard formats
+ * 8. undefined behavior per C99
+ *
+ * Per the C Standard, extra arguments are ignored.
+ *
+ * No attempt is made to fix the arguments or the format string.
+ *
+ * Params:
+ * loc = location for error messages
+ * format = format string
+ * args = arguments to match with format string
+ * isVa_list = if a "v" function (format check only)
+ *
+ * Returns:
+ * `true` if errors occurred
+ * References:
+ * C99 7.19.6.1
+ * http://www.cplusplus.com/reference/cstdio/printf/
+ */
+bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list)
+{
+ //printf("checkPrintFormat('%.*s')\n", cast(int)format.length, format.ptr);
+ size_t n, gnu_m_count; // index in args / number of Format.GNU_m
+ for (size_t i = 0; i < format.length;)
+ {
+ if (format[i] != '%')
+ {
+ ++i;
+ continue;
+ }
+ bool widthStar;
+ bool precisionStar;
+ size_t j = i;
+ const fmt = parsePrintfFormatSpecifier(format, j, widthStar, precisionStar);
+ const slice = format[i .. j];
+ i = j;
+
+ if (fmt == Format.percent)
+ continue; // "%%", no arguments
+
+ if (isVa_list)
+ {
+ // format check only
+ if (fmt == Format.error)
+ deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr);
+ continue;
+ }
+
+ if (fmt == Format.GNU_m)
+ ++gnu_m_count;
+
+ Expression getNextArg(ref bool skip)
+ {
+ if (n == args.length)
+ {
+ if (args.length < (n + 1) - gnu_m_count)
+ deprecation(loc, "more format specifiers than %d arguments", cast(int)n);
+ else
+ skip = true;
+ return null;
+ }
+ return args[n++];
+ }
+
+ void errorMsg(const char* prefix, Expression arg, const char* texpect, Type tactual)
+ {
+ deprecation(arg.loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
+ prefix ? prefix : "", arg.toChars(), cast(int)slice.length, slice.ptr, texpect, tactual.toChars());
+ }
+
+ if (widthStar)
+ {
+ bool skip;
+ auto e = getNextArg(skip);
+ if (skip)
+ continue;
+ if (!e)
+ return true;
+ auto t = e.type.toBasetype();
+ if (t.ty != Tint32 && t.ty != Tuns32)
+ errorMsg("width ", e, "int", t);
+ }
+
+ if (precisionStar)
+ {
+ bool skip;
+ auto e = getNextArg(skip);
+ if (skip)
+ continue;
+ if (!e)
+ return true;
+ auto t = e.type.toBasetype();
+ if (t.ty != Tint32 && t.ty != Tuns32)
+ errorMsg("precision ", e, "int", t);
+ }
+
+ bool skip;
+ auto e = getNextArg(skip);
+ if (skip)
+ continue;
+ if (!e)
+ return true;
+ auto t = e.type.toBasetype();
+ auto tnext = t.nextOf();
+ const c_longsize = target.c.longsize;
+ const ptrsize = target.ptrsize;
+
+ // Types which are promoted to int are allowed.
+ // Spec: C99 6.5.2.2.7
+ final switch (fmt)
+ {
+ case Format.u: // unsigned int
+ case Format.d: // int
+ if (t.ty != Tint32 && t.ty != Tuns32)
+ errorMsg(null, e, fmt == Format.u ? "uint" : "int", t);
+ break;
+
+ case Format.hhu: // unsigned char
+ case Format.hhd: // signed char
+ if (t.ty != Tint32 && t.ty != Tuns32 && t.ty != Tint8 && t.ty != Tuns8)
+ errorMsg(null, e, fmt == Format.hhu ? "ubyte" : "byte", t);
+ break;
+
+ case Format.hu: // unsigned short int
+ case Format.hd: // short int
+ if (t.ty != Tint32 && t.ty != Tuns32 && t.ty != Tint16 && t.ty != Tuns16)
+ errorMsg(null, e, fmt == Format.hu ? "ushort" : "short", t);
+ break;
+
+ case Format.lu: // unsigned long int
+ case Format.ld: // long int
+ if (!(t.isintegral() && t.size() == c_longsize))
+ {
+ if (fmt == Format.lu)
+ errorMsg(null, e, (c_longsize == 4 ? "uint" : "ulong"), t);
+ else
+ errorMsg(null, e, (c_longsize == 4 ? "int" : "long"), t);
+ }
+ break;
+
+ case Format.llu: // unsigned long long int
+ case Format.lld: // long long int
+ if (t.ty != Tint64 && t.ty != Tuns64)
+ errorMsg(null, e, fmt == Format.llu ? "ulong" : "long", t);
+ break;
+
+ case Format.ju: // uintmax_t
+ case Format.jd: // intmax_t
+ if (t.ty != Tint64 && t.ty != Tuns64)
+ {
+ if (fmt == Format.ju)
+ errorMsg(null, e, "core.stdc.stdint.uintmax_t", t);
+ else
+ errorMsg(null, e, "core.stdc.stdint.intmax_t", t);
+ }
+ break;
+
+ case Format.zd: // size_t
+ if (!(t.isintegral() && t.size() == ptrsize))
+ errorMsg(null, e, "size_t", t);
+ break;
+
+ case Format.td: // ptrdiff_t
+ if (!(t.isintegral() && t.size() == ptrsize))
+ errorMsg(null, e, "ptrdiff_t", t);
+ break;
+
+ case Format.GNU_a: // Format.GNU_a is only for scanf
+ case Format.lg:
+ case Format.g: // double
+ if (t.ty != Tfloat64 && t.ty != Timaginary64)
+ errorMsg(null, e, "double", t);
+ break;
+
+ case Format.Lg: // long double
+ if (t.ty != Tfloat80 && t.ty != Timaginary80)
+ errorMsg(null, e, "real", t);
+ break;
+
+ case Format.p: // pointer
+ if (t.ty != Tpointer && t.ty != Tnull && t.ty != Tclass && t.ty != Tdelegate && t.ty != Taarray)
+ errorMsg(null, e, "void*", t);
+ break;
+
+ case Format.n: // pointer to int
+ if (!(t.ty == Tpointer && tnext.ty == Tint32))
+ errorMsg(null, e, "int*", t);
+ break;
+
+ case Format.ln: // pointer to long int
+ if (!(t.ty == Tpointer && tnext.isintegral() && tnext.size() == c_longsize))
+ errorMsg(null, e, (c_longsize == 4 ? "int*" : "long*"), t);
+ break;
+
+ case Format.lln: // pointer to long long int
+ if (!(t.ty == Tpointer && tnext.ty == Tint64))
+ errorMsg(null, e, "long*", t);
+ break;
+
+ case Format.hn: // pointer to short
+ if (!(t.ty == Tpointer && tnext.ty == Tint16))
+ errorMsg(null, e, "short*", t);
+ break;
+
+ case Format.hhn: // pointer to signed char
+ if (!(t.ty == Tpointer && tnext.ty == Tint16))
+ errorMsg(null, e, "byte*", t);
+ break;
+
+ case Format.jn: // pointer to intmax_t
+ if (!(t.ty == Tpointer && tnext.ty == Tint64))
+ errorMsg(null, e, "core.stdc.stdint.intmax_t*", t);
+ break;
+
+ case Format.zn: // pointer to size_t
+ if (!(t.ty == Tpointer && tnext.isintegral() && tnext.isunsigned() && tnext.size() == ptrsize))
+ errorMsg(null, e, "size_t*", t);
+ break;
+
+ case Format.tn: // pointer to ptrdiff_t
+ if (!(t.ty == Tpointer && tnext.isintegral() && !tnext.isunsigned() && tnext.size() == ptrsize))
+ errorMsg(null, e, "ptrdiff_t*", t);
+ break;
+
+ case Format.c: // char
+ if (t.ty != Tint32 && t.ty != Tuns32)
+ errorMsg(null, e, "char", t);
+ break;
+
+ case Format.lc: // wint_t
+ if (t.ty != Tint32 && t.ty != Tuns32)
+ errorMsg(null, e, "wchar_t", t);
+ break;
+
+ case Format.s: // pointer to char string
+ if (!(t.ty == Tpointer && (tnext.ty == Tchar || tnext.ty == Tint8 || tnext.ty == Tuns8)))
+ errorMsg(null, e, "char*", t);
+ break;
+
+ case Format.ls: // pointer to wchar_t string
+ if (!(t.ty == Tpointer && tnext.ty.isSomeChar && tnext.size() == target.c.wchar_tsize))
+ errorMsg(null, e, "wchar_t*", t);
+ break;
+
+ case Format.error:
+ deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr);
+ break;
+
+ case Format.GNU_m:
+ break; // not assert(0) because it may go through it if there are extra arguments
+
+ case Format.percent:
+ assert(0);
+ }
+ }
+ return false;
+}
+
+/******************************************
+ * Check that arguments to a scanf format string are compatible
+ * with that string. Issue errors for incompatibilities.
+ *
+ * Follows the C99 specification for scanf.
+ *
+ * Takes a generous, rather than strict, view of compatiblity.
+ * For example, an unsigned value can be formatted with a signed specifier.
+ *
+ * Diagnosed incompatibilities are:
+ *
+ * 1. incompatible sizes which will cause argument misalignment
+ * 2. deferencing arguments that are not pointers
+ * 3. insufficient number of arguments
+ * 4. struct arguments
+ * 5. array and slice arguments
+ * 6. non-standard formats
+ * 7. undefined behavior per C99
+ *
+ * Per the C Standard, extra arguments are ignored.
+ *
+ * No attempt is made to fix the arguments or the format string.
+ *
+ * Params:
+ * loc = location for error messages
+ * format = format string
+ * args = arguments to match with format string
+ * isVa_list = if a "v" function (format check only)
+ *
+ * Returns:
+ * `true` if errors occurred
+ * References:
+ * C99 7.19.6.2
+ * http://www.cplusplus.com/reference/cstdio/scanf/
+ */
+bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list)
+{
+ size_t n = 0;
+ for (size_t i = 0; i < format.length;)
+ {
+ if (format[i] != '%')
+ {
+ ++i;
+ continue;
+ }
+ bool asterisk;
+ size_t j = i;
+ const fmt = parseScanfFormatSpecifier(format, j, asterisk);
+ const slice = format[i .. j];
+ i = j;
+
+ if (fmt == Format.percent || asterisk)
+ continue; // "%%", "%*": no arguments
+
+ if (isVa_list)
+ {
+ // format check only
+ if (fmt == Format.error)
+ deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr);
+ continue;
+ }
+
+ Expression getNextArg()
+ {
+ if (n == args.length)
+ {
+ if (!asterisk)
+ deprecation(loc, "more format specifiers than %d arguments", cast(int)n);
+ return null;
+ }
+ return args[n++];
+ }
+
+ void errorMsg(const char* prefix, Expression arg, const char* texpect, Type tactual)
+ {
+ deprecation(arg.loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
+ prefix ? prefix : "", arg.toChars(), cast(int)slice.length, slice.ptr, texpect, tactual.toChars());
+ }
+
+ auto e = getNextArg();
+ if (!e)
+ return true;
+
+ auto t = e.type.toBasetype();
+ auto tnext = t.nextOf();
+ const c_longsize = target.c.longsize;
+ const ptrsize = target.ptrsize;
+
+ final switch (fmt)
+ {
+ case Format.n:
+ case Format.d: // pointer to int
+ if (!(t.ty == Tpointer && tnext.ty == Tint32))
+ errorMsg(null, e, "int*", t);
+ break;
+
+ case Format.hhn:
+ case Format.hhd: // pointer to signed char
+ if (!(t.ty == Tpointer && tnext.ty == Tint16))
+ errorMsg(null, e, "byte*", t);
+ break;
+
+ case Format.hn:
+ case Format.hd: // pointer to short
+ if (!(t.ty == Tpointer && tnext.ty == Tint16))
+ errorMsg(null, e, "short*", t);
+ break;
+
+ case Format.ln:
+ case Format.ld: // pointer to long int
+ if (!(t.ty == Tpointer && tnext.isintegral() && !tnext.isunsigned() && tnext.size() == c_longsize))
+ errorMsg(null, e, (c_longsize == 4 ? "int*" : "long*"), t);
+ break;
+
+ case Format.lln:
+ case Format.lld: // pointer to long long int
+ if (!(t.ty == Tpointer && tnext.ty == Tint64))
+ errorMsg(null, e, "long*", t);
+ break;
+
+ case Format.jn:
+ case Format.jd: // pointer to intmax_t
+ if (!(t.ty == Tpointer && tnext.ty == Tint64))
+ errorMsg(null, e, "core.stdc.stdint.intmax_t*", t);
+ break;
+
+ case Format.zn:
+ case Format.zd: // pointer to size_t
+ if (!(t.ty == Tpointer && tnext.isintegral() && tnext.isunsigned() && tnext.size() == ptrsize))
+ errorMsg(null, e, "size_t*", t);
+ break;
+
+ case Format.tn:
+ case Format.td: // pointer to ptrdiff_t
+ if (!(t.ty == Tpointer && tnext.isintegral() && !tnext.isunsigned() && tnext.size() == ptrsize))
+ errorMsg(null, e, "ptrdiff_t*", t);
+ break;
+
+ case Format.u: // pointer to unsigned int
+ if (!(t.ty == Tpointer && tnext.ty == Tuns32))
+ errorMsg(null, e, "uint*", t);
+ break;
+
+ case Format.hhu: // pointer to unsigned char
+ if (!(t.ty == Tpointer && tnext.ty == Tuns8))
+ errorMsg(null, e, "ubyte*", t);
+ break;
+
+ case Format.hu: // pointer to unsigned short int
+ if (!(t.ty == Tpointer && tnext.ty == Tuns16))
+ errorMsg(null, e, "ushort*", t);
+ break;
+
+ case Format.lu: // pointer to unsigned long int
+ if (!(t.ty == Tpointer && tnext.isintegral() && tnext.isunsigned() && tnext.size() == c_longsize))
+ errorMsg(null, e, (c_longsize == 4 ? "uint*" : "ulong*"), t);
+ break;
+
+ case Format.llu: // pointer to unsigned long long int
+ if (!(t.ty == Tpointer && tnext.ty == Tuns64))
+ errorMsg(null, e, "ulong*", t);
+ break;
+
+ case Format.ju: // pointer to uintmax_t
+ if (!(t.ty == Tpointer && tnext.ty == Tuns64))
+ errorMsg(null, e, "core.stdc.stdint.uintmax_t*", t);
+ break;
+
+ case Format.g: // pointer to float
+ if (!(t.ty == Tpointer && tnext.ty == Tfloat32))
+ errorMsg(null, e, "float*", t);
+ break;
+
+ case Format.lg: // pointer to double
+ if (!(t.ty == Tpointer && tnext.ty == Tfloat64))
+ errorMsg(null, e, "double*", t);
+ break;
+
+ case Format.Lg: // pointer to long double
+ if (!(t.ty == Tpointer && tnext.ty == Tfloat80))
+ errorMsg(null, e, "real*", t);
+ break;
+
+ case Format.GNU_a:
+ case Format.GNU_m:
+ case Format.c:
+ case Format.s: // pointer to char string
+ if (!(t.ty == Tpointer && (tnext.ty == Tchar || tnext.ty == Tint8 || tnext.ty == Tuns8)))
+ errorMsg(null, e, "char*", t);
+ break;
+
+ case Format.lc:
+ case Format.ls: // pointer to wchar_t string
+ if (!(t.ty == Tpointer && tnext.ty.isSomeChar && tnext.size() == target.c.wchar_tsize))
+ errorMsg(null, e, "wchar_t*", t);
+ break;
+
+ case Format.p: // double pointer
+ if (!(t.ty == Tpointer && tnext.ty == Tpointer))
+ errorMsg(null, e, "void**", t);
+ break;
+
+ case Format.error:
+ deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr);
+ break;
+
+ case Format.percent:
+ assert(0);
+ }
+ }
+ return false;
+}
+
+private:
+
+/**************************************
+ * Parse the *format specifier* which is of the form:
+ *
+ * `%[*][width][length]specifier`
+ *
+ * Params:
+ * format = format string
+ * idx = index of `%` of start of format specifier,
+ * which gets updated to index past the end of it,
+ * even if `Format.error` is returned
+ * asterisk = set if there is a `*` sub-specifier
+ * Returns:
+ * Format
+ */
+Format parseScanfFormatSpecifier(scope const char[] format, ref size_t idx,
+ out bool asterisk) nothrow pure @safe
+{
+ auto i = idx;
+ assert(format[i] == '%');
+ const length = format.length;
+
+ Format error()
+ {
+ idx = i;
+ return Format.error;
+ }
+
+ ++i;
+ if (i == length)
+ return error();
+
+ if (format[i] == '%')
+ {
+ idx = i + 1;
+ return Format.percent;
+ }
+
+ // * sub-specifier
+ if (format[i] == '*')
+ {
+ ++i;
+ if (i == length)
+ return error();
+ asterisk = true;
+ }
+
+ // fieldWidth
+ while (isdigit(format[i]))
+ {
+ i++;
+ if (i == length)
+ return error();
+ }
+
+ /* Read the scanset
+ * A scanset can be anything, so we just check that it is paired
+ */
+ if (format[i] == '[')
+ {
+ while (i < length)
+ {
+ if (format[i] == ']')
+ break;
+ ++i;
+ }
+
+ // no `]` found
+ if (i == length)
+ return error();
+
+ ++i;
+ // no specifier after `]`
+ // it could be mixed with the one above, but then idx won't have the right index
+ if (i == length)
+ return error();
+ }
+
+ /* Read the specifier
+ */
+ char genSpec;
+ Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
+ if (specifier == Format.error)
+ return error();
+
+ idx = i;
+ return specifier; // success
+}
+
+/**************************************
+ * Parse the *format specifier* which is of the form:
+ *
+ * `%[flags][field width][.precision][length modifier]specifier`
+ *
+ * Params:
+ * format = format string
+ * idx = index of `%` of start of format specifier,
+ * which gets updated to index past the end of it,
+ * even if `Format.error` is returned
+ * widthStar = set if * for width
+ * precisionStar = set if * for precision
+ * Returns:
+ * Format
+ */
+Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx,
+ out bool widthStar, out bool precisionStar) nothrow pure @safe
+{
+ auto i = idx;
+ assert(format[i] == '%');
+ const length = format.length;
+ bool hash;
+ bool zero;
+ bool flags;
+ bool width;
+ bool precision;
+
+ Format error()
+ {
+ idx = i;
+ return Format.error;
+ }
+
+ ++i;
+ if (i == length)
+ return error();
+
+ if (format[i] == '%')
+ {
+ idx = i + 1;
+ return Format.percent;
+ }
+
+ /* Read the `flags`
+ */
+ while (1)
+ {
+ const c = format[i];
+ if (c == '-' ||
+ c == '+' ||
+ c == ' ')
+ {
+ flags = true;
+ }
+ else if (c == '#')
+ {
+ hash = true;
+ }
+ else if (c == '0')
+ {
+ zero = true;
+ }
+ else
+ break;
+ ++i;
+ if (i == length)
+ return error();
+ }
+
+ /* Read the `field width`
+ */
+ {
+ const c = format[i];
+ if (c == '*')
+ {
+ width = true;
+ widthStar = true;
+ ++i;
+ if (i == length)
+ return error();
+ }
+ else if ('1' <= c && c <= '9')
+ {
+ width = true;
+ ++i;
+ if (i == length)
+ return error();
+ while ('0' <= format[i] && format[i] <= '9')
+ {
+ ++i;
+ if (i == length)
+ return error();
+ }
+ }
+ }
+
+ /* Read the `precision`
+ */
+ if (format[i] == '.')
+ {
+ precision = true;
+ ++i;
+ if (i == length)
+ return error();
+ const c = format[i];
+ if (c == '*')
+ {
+ precisionStar = true;
+ ++i;
+ if (i == length)
+ return error();
+ }
+ else if ('0' <= c && c <= '9')
+ {
+ ++i;
+ if (i == length)
+ return error();
+ while ('0' <= format[i] && format[i] <= '9')
+ {
+ ++i;
+ if (i == length)
+ return error();
+ }
+ }
+ }
+
+ /* Read the specifier
+ */
+ char genSpec;
+ Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
+ if (specifier == Format.error)
+ return error();
+
+ switch (genSpec)
+ {
+ case 'c':
+ case 's':
+ if (hash || zero)
+ return error();
+ break;
+
+ case 'd':
+ case 'i':
+ if (hash)
+ return error();
+ break;
+
+ case 'n':
+ if (hash || zero || precision || width || flags)
+ return error();
+ break;
+
+ default:
+ break;
+ }
+
+ idx = i;
+ return specifier; // success
+}
+
+/* Different kinds of formatting specifications, variations we don't
+ care about are merged. (Like we don't care about the difference between
+ f, e, g, a, etc.)
+
+ For `scanf`, every format is a pointer.
+ */
+enum Format
+{
+ d, // int
+ hhd, // signed char
+ hd, // short int
+ ld, // long int
+ lld, // long long int
+ jd, // intmax_t
+ zd, // size_t
+ td, // ptrdiff_t
+ u, // unsigned int
+ hhu, // unsigned char
+ hu, // unsigned short int
+ lu, // unsigned long int
+ llu, // unsigned long long int
+ ju, // uintmax_t
+ g, // float (scanf) / double (printf)
+ lg, // double (scanf)
+ Lg, // long double (both)
+ s, // char string (both)
+ ls, // wchar_t string (both)
+ c, // char (printf)
+ lc, // wint_t (printf)
+ p, // pointer
+ n, // pointer to int
+ hhn, // pointer to signed char
+ hn, // pointer to short
+ ln, // pointer to long int
+ lln, // pointer to long long int
+ jn, // pointer to intmax_t
+ zn, // pointer to size_t
+ tn, // pointer to ptrdiff_t
+ GNU_a, // GNU ext. : address to a string with no maximum size (scanf)
+ GNU_m, // GNU ext. : string corresponding to the error code in errno (printf) / length modifier (scanf)
+ percent, // %% (i.e. no argument)
+ error, // invalid format specification
+}
+
+/**************************************
+ * Parse the *length specifier* and the *specifier* of the following form:
+ * `[length]specifier`
+ *
+ * Params:
+ * format = format string
+ * idx = index of of start of format specifier,
+ * which gets updated to index past the end of it,
+ * even if `Format.error` is returned
+ * genSpecifier = Generic specifier. For instance, it will be set to `d` if the
+ * format is `hdd`.
+ * Returns:
+ * Format
+ */
+Format parseGenericFormatSpecifier(scope const char[] format,
+ ref size_t idx, out char genSpecifier, bool useGNUExts =
+ findCondition(global.versionids, Identifier.idPool("CRuntime_Glibc"))) nothrow pure @trusted
+{
+ const length = format.length;
+
+ /* Read the `length modifier`
+ */
+ const lm = format[idx];
+ bool lm1; // if jztL
+ bool lm2; // if `hh` or `ll`
+ if (lm == 'j' ||
+ lm == 'z' ||
+ lm == 't' ||
+ lm == 'L')
+ {
+ ++idx;
+ if (idx == length)
+ return Format.error;
+ lm1 = true;
+ }
+ else if (lm == 'h' || lm == 'l')
+ {
+ ++idx;
+ if (idx == length)
+ return Format.error;
+ lm2 = lm == format[idx];
+ if (lm2)
+ {
+ ++idx;
+ if (idx == length)
+ return Format.error;
+ }
+ }
+
+ /* Read the `specifier`
+ */
+ Format specifier;
+ const sc = format[idx];
+ genSpecifier = sc;
+ switch (sc)
+ {
+ case 'd':
+ case 'i':
+ if (lm == 'L')
+ specifier = Format.error;
+ else
+ specifier = lm == 'h' && lm2 ? Format.hhd :
+ lm == 'h' ? Format.hd :
+ lm == 'l' && lm2 ? Format.lld :
+ lm == 'l' ? Format.ld :
+ lm == 'j' ? Format.jd :
+ lm == 'z' ? Format.zd :
+ lm == 't' ? Format.td :
+ Format.d;
+ break;
+
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ if (lm == 'L')
+ specifier = Format.error;
+ else
+ specifier = lm == 'h' && lm2 ? Format.hhu :
+ lm == 'h' ? Format.hu :
+ lm == 'l' && lm2 ? Format.llu :
+ lm == 'l' ? Format.lu :
+ lm == 'j' ? Format.ju :
+ lm == 'z' ? Format.zd :
+ lm == 't' ? Format.td :
+ Format.u;
+ break;
+
+ case 'a':
+ if (useGNUExts)
+ {
+ // https://www.gnu.org/software/libc/manual/html_node/Dynamic-String-Input.html
+ specifier = Format.GNU_a;
+ break;
+ }
+ goto case;
+
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ case 'A':
+ if (lm == 'L')
+ specifier = Format.Lg;
+ else if (lm1 || lm2 || lm == 'h')
+ specifier = Format.error;
+ else
+ specifier = lm == 'l' ? Format.lg : Format.g;
+ break;
+
+ case 'c':
+ if (lm1 || lm2 || lm == 'h')
+ specifier = Format.error;
+ else
+ specifier = lm == 'l' ? Format.lc : Format.c;
+ break;
+
+ case 's':
+ if (lm1 || lm2 || lm == 'h')
+ specifier = Format.error;
+ else
+ specifier = lm == 'l' ? Format.ls : Format.s;
+ break;
+
+ case 'p':
+ if (lm1 || lm2 || lm == 'h' || lm == 'l')
+ specifier = Format.error;
+ else
+ specifier = Format.p;
+ break;
+
+ case 'n':
+ if (lm == 'L')
+ specifier = Format.error;
+ else
+ specifier = lm == 'l' && lm2 ? Format.lln :
+ lm == 'l' ? Format.ln :
+ lm == 'h' && lm2 ? Format.hhn :
+ lm == 'h' ? Format.hn :
+ lm == 'j' ? Format.jn :
+ lm == 'z' ? Format.zn :
+ lm == 't' ? Format.tn :
+ Format.n;
+ break;
+
+ case 'm':
+ if (useGNUExts)
+ {
+ // http://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html
+ specifier = Format.GNU_m;
+ break;
+ }
+ goto default;
+
+ default:
+ specifier = Format.error;
+ break;
+ }
+
+ ++idx;
+ return specifier; // success
+}
+
+unittest
+{
+ /* parseGenericFormatSpecifier
+ */
+
+ char genSpecifier;
+ size_t idx;
+
+ assert(parseGenericFormatSpecifier("hhd", idx, genSpecifier) == Format.hhd);
+ assert(genSpecifier == 'd');
+
+ idx = 0;
+ assert(parseGenericFormatSpecifier("hn", idx, genSpecifier) == Format.hn);
+ assert(genSpecifier == 'n');
+
+ idx = 0;
+ assert(parseGenericFormatSpecifier("ji", idx, genSpecifier) == Format.jd);
+ assert(genSpecifier == 'i');
+
+ idx = 0;
+ assert(parseGenericFormatSpecifier("lu", idx, genSpecifier) == Format.lu);
+ assert(genSpecifier == 'u');
+
+ idx = 0;
+ assert(parseGenericFormatSpecifier("k", idx, genSpecifier) == Format.error);
+
+ /* parsePrintfFormatSpecifier
+ */
+
+ bool widthStar;
+ bool precisionStar;
+
+ // one for each Format
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%d", idx, widthStar, precisionStar) == Format.d);
+ assert(idx == 2);
+ assert(!widthStar && !precisionStar);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%ld", idx, widthStar, precisionStar) == Format.ld);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%lld", idx, widthStar, precisionStar) == Format.lld);
+ assert(idx == 4);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%jd", idx, widthStar, precisionStar) == Format.jd);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%zd", idx, widthStar, precisionStar) == Format.zd);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%td", idx, widthStar, precisionStar) == Format.td);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%g", idx, widthStar, precisionStar) == Format.g);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%Lg", idx, widthStar, precisionStar) == Format.Lg);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%p", idx, widthStar, precisionStar) == Format.p);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%n", idx, widthStar, precisionStar) == Format.n);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%ln", idx, widthStar, precisionStar) == Format.ln);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%lln", idx, widthStar, precisionStar) == Format.lln);
+ assert(idx == 4);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%hn", idx, widthStar, precisionStar) == Format.hn);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%hhn", idx, widthStar, precisionStar) == Format.hhn);
+ assert(idx == 4);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%jn", idx, widthStar, precisionStar) == Format.jn);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%zn", idx, widthStar, precisionStar) == Format.zn);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%tn", idx, widthStar, precisionStar) == Format.tn);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%c", idx, widthStar, precisionStar) == Format.c);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%lc", idx, widthStar, precisionStar) == Format.lc);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%s", idx, widthStar, precisionStar) == Format.s);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%ls", idx, widthStar, precisionStar) == Format.ls);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%%", idx, widthStar, precisionStar) == Format.percent);
+ assert(idx == 2);
+
+ // Synonyms
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%i", idx, widthStar, precisionStar) == Format.d);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%u", idx, widthStar, precisionStar) == Format.u);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%o", idx, widthStar, precisionStar) == Format.u);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%x", idx, widthStar, precisionStar) == Format.u);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%X", idx, widthStar, precisionStar) == Format.u);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%f", idx, widthStar, precisionStar) == Format.g);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%F", idx, widthStar, precisionStar) == Format.g);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%G", idx, widthStar, precisionStar) == Format.g);
+ assert(idx == 2);
+
+ idx = 0;
+ Format g = parsePrintfFormatSpecifier("%a", idx, widthStar, precisionStar);
+ assert(g == Format.g || g == Format.GNU_a);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%A", idx, widthStar, precisionStar) == Format.g);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%lg", idx, widthStar, precisionStar) == Format.lg);
+ assert(idx == 3);
+
+ // width, precision
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%*d", idx, widthStar, precisionStar) == Format.d);
+ assert(idx == 3);
+ assert(widthStar && !precisionStar);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%.*d", idx, widthStar, precisionStar) == Format.d);
+ assert(idx == 4);
+ assert(!widthStar && precisionStar);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%*.*d", idx, widthStar, precisionStar) == Format.d);
+ assert(idx == 5);
+ assert(widthStar && precisionStar);
+
+ // Too short formats
+ {
+ foreach (s; ["%", "%-", "%+", "% ", "%#", "%0", "%*", "%1", "%19", "%.", "%.*", "%.1", "%.12",
+ "%j", "%z", "%t", "%l", "%h", "%ll", "%hh"])
+ {
+ idx = 0;
+ assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar) == Format.error);
+ assert(idx == s.length);
+ }
+ }
+
+ // Undefined format combinations
+ {
+ foreach (s; ["%#d", "%llg", "%jg", "%zg", "%tg", "%hg", "%hhg",
+ "%#c", "%0c", "%jc", "%zc", "%tc", "%Lc", "%hc", "%hhc", "%llc",
+ "%#s", "%0s", "%js", "%zs", "%ts", "%Ls", "%hs", "%hhs", "%lls",
+ "%jp", "%zp", "%tp", "%Lp", "%hp", "%lp", "%hhp", "%llp",
+ "%-n", "%+n", "% n", "%#n", "%0n", "%*n", "%1n", "%19n", "%.n", "%.*n", "%.1n", "%.12n", "%Ln", "%K"])
+ {
+ idx = 0;
+ assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar) == Format.error);
+ assert(idx == s.length);
+ }
+ }
+
+ /* parseScanfFormatSpecifier
+ */
+
+ bool asterisk;
+
+ // one for each Format
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%d", idx, asterisk) == Format.d);
+ assert(idx == 2);
+ assert(!asterisk);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%hhd", idx, asterisk) == Format.hhd);
+ assert(idx == 4);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%hd", idx, asterisk) == Format.hd);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%ld", idx, asterisk) == Format.ld);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%lld", idx, asterisk) == Format.lld);
+ assert(idx == 4);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%jd", idx, asterisk) == Format.jd);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%zd", idx, asterisk) == Format.zd);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%td", idx, asterisk,) == Format.td);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%u", idx, asterisk) == Format.u);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%hhu", idx, asterisk,) == Format.hhu);
+ assert(idx == 4);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%hu", idx, asterisk) == Format.hu);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%lu", idx, asterisk) == Format.lu);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%llu", idx, asterisk) == Format.llu);
+ assert(idx == 4);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%ju", idx, asterisk) == Format.ju);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%g", idx, asterisk) == Format.g);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%lg", idx, asterisk) == Format.lg);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%Lg", idx, asterisk) == Format.Lg);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%p", idx, asterisk) == Format.p);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%s", idx, asterisk) == Format.s);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%ls", idx, asterisk,) == Format.ls);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%%", idx, asterisk) == Format.percent);
+ assert(idx == 2);
+
+ // Synonyms
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%i", idx, asterisk) == Format.d);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%n", idx, asterisk) == Format.n);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%o", idx, asterisk) == Format.u);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%x", idx, asterisk) == Format.u);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%f", idx, asterisk) == Format.g);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%e", idx, asterisk) == Format.g);
+ assert(idx == 2);
+
+ idx = 0;
+ g = parseScanfFormatSpecifier("%a", idx, asterisk);
+ assert(g == Format.g || g == Format.GNU_a);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%c", idx, asterisk) == Format.c);
+ assert(idx == 2);
+
+ // asterisk
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%*d", idx, asterisk) == Format.d);
+ assert(idx == 3);
+ assert(asterisk);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%9ld", idx, asterisk) == Format.ld);
+ assert(idx == 4);
+ assert(!asterisk);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%*25984hhd", idx, asterisk) == Format.hhd);
+ assert(idx == 10);
+ assert(asterisk);
+
+ // scansets
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%[a-zA-Z]s", idx, asterisk) == Format.s);
+ assert(idx == 10);
+ assert(!asterisk);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%*25[a-z]hhd", idx, asterisk) == Format.hhd);
+ assert(idx == 12);
+ assert(asterisk);
+
+ // Too short formats
+ foreach (s; ["%", "% ", "%#", "%0", "%*", "%1", "%19",
+ "%j", "%z", "%t", "%l", "%h", "%ll", "%hh", "%K"])
+ {
+ idx = 0;
+ assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error);
+ assert(idx == s.length);
+ }
+
+
+ // Undefined format combinations
+ foreach (s; ["%Ld", "%llg", "%jg", "%zg", "%tg", "%hg", "%hhg",
+ "%jc", "%zc", "%tc", "%Lc", "%hc", "%hhc", "%llc",
+ "%jp", "%zp", "%tp", "%Lp", "%hp", "%lp", "%hhp", "%llp",
+ "%-", "%+", "%#", "%0", "%.", "%Ln"])
+ {
+ idx = 0;
+ assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error);
+ assert(idx == s.length);
+
+ }
+
+ // Invalid scansets
+ foreach (s; ["%[]", "%[s", "%[0-9lld", "%[", "%[a-z]"])
+ {
+ idx = 0;
+ assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error);
+ assert(idx == s.length);
+ }
+
+}
diff --git a/gcc/d/dmd/clone.c b/gcc/d/dmd/clone.c
deleted file mode 100644
index eb09076..0000000
--- a/gcc/d/dmd/clone.c
+++ /dev/null
@@ -1,1179 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/clone.c
- */
-
-#include "root/dsystem.h"
-#include "root/root.h"
-
-#include "aggregate.h"
-#include "scope.h"
-#include "mtype.h"
-#include "declaration.h"
-#include "module.h"
-#include "id.h"
-#include "expression.h"
-#include "statement.h"
-#include "init.h"
-#include "template.h"
-#include "tokens.h"
-
-/*******************************************
- * Merge function attributes pure, nothrow, @safe, @nogc, and @disable
- */
-StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f)
-{
- if (!f)
- return s1;
-
- StorageClass s2 = (f->storage_class & STCdisable);
- TypeFunction *tf = (TypeFunction *)f->type;
- if (tf->trust == TRUSTsafe)
- s2 |= STCsafe;
- else if (tf->trust == TRUSTsystem)
- s2 |= STCsystem;
- else if (tf->trust == TRUSTtrusted)
- s2 |= STCtrusted;
- if (tf->purity != PUREimpure)
- s2 |= STCpure;
- if (tf->isnothrow)
- s2 |= STCnothrow;
- if (tf->isnogc)
- s2 |= STCnogc;
-
- StorageClass stc = 0;
- StorageClass sa = s1 & s2;
- StorageClass so = s1 | s2;
-
- if (so & STCsystem)
- stc |= STCsystem;
- else if (sa & STCtrusted)
- stc |= STCtrusted;
- else if ((so & (STCtrusted | STCsafe)) == (STCtrusted | STCsafe))
- stc |= STCtrusted;
- else if (sa & STCsafe)
- stc |= STCsafe;
-
- if (sa & STCpure)
- stc |= STCpure;
-
- if (sa & STCnothrow)
- stc |= STCnothrow;
-
- if (sa & STCnogc)
- stc |= STCnogc;
-
- if (so & STCdisable)
- stc |= STCdisable;
-
- return stc;
-}
-
-/*******************************************
- * Check given aggregate actually has an identity opAssign or not.
- * Params:
- * ad = struct or class
- * sc = current scope
- * Returns:
- * if found, returns FuncDeclaration of opAssign, otherwise null
- */
-FuncDeclaration *hasIdentityOpAssign(AggregateDeclaration *ad, Scope *sc)
-{
- Dsymbol *assign = search_function(ad, Id::assign);
- if (assign)
- {
- /* check identity opAssign exists
- */
- UnionExp er; new(&er) NullExp(ad->loc, ad->type); // dummy rvalue
- UnionExp el; new(&el) IdentifierExp(ad->loc, Id::p); // dummy lvalue
- el.exp()->type = ad->type;
- Expressions a;
- a.setDim(1);
-
- unsigned errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
- sc = sc->push();
- sc->tinst = NULL;
- sc->minst = NULL;
-
- a[0] = er.exp();
- FuncDeclaration *f = resolveFuncCall(ad->loc, sc, assign, NULL, ad->type, &a, 1);
- if (!f)
- {
- a[0] = el.exp();
- f = resolveFuncCall(ad->loc, sc, assign, NULL, ad->type, &a, 1);
- }
-
- sc = sc->pop();
- global.endGagging(errors);
-
- if (f)
- {
- if (f->errors)
- return NULL;
- ParameterList fparams = f->getParameterList();
- if (fparams.length())
- {
- Parameter *fparam0 = fparams[0];
- if (fparam0->type->toDsymbol(NULL) != ad)
- f = NULL;
- }
- }
- // BUGS: This detection mechanism cannot find some opAssign-s like follows:
- // struct S { void opAssign(ref immutable S) const; }
- return f;
- }
- return NULL;
-}
-
-/*******************************************
- * We need an opAssign for the struct if
- * it has a destructor or a postblit.
- * We need to generate one if a user-specified one does not exist.
- */
-bool needOpAssign(StructDeclaration *sd)
-{
- //printf("StructDeclaration::needOpAssign() %s\n", sd->toChars());
- if (sd->isUnionDeclaration())
- return false;
-
- if (sd->hasIdentityAssign)
- goto Lneed; // because has identity==elaborate opAssign
-
- if (sd->dtor || sd->postblit)
- goto Lneed;
-
- /* If any of the fields need an opAssign, then we
- * need it too.
- */
- for (size_t i = 0; i < sd->fields.length; i++)
- {
- VarDeclaration *v = sd->fields[i];
- if (v->storage_class & STCref)
- continue;
- if (v->overlapped) // if field of a union
- continue; // user must handle it themselves
- Type *tv = v->type->baseElemOf();
- if (tv->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)tv;
- if (ts->sym->isUnionDeclaration())
- continue;
- if (needOpAssign(ts->sym))
- goto Lneed;
- }
- }
- //printf("\tdontneed\n");
- return false;
-
-Lneed:
- //printf("\tneed\n");
- return true;
-}
-
-/******************************************
- * Build opAssign for struct.
- * ref S opAssign(S s) { ... }
- *
- * Note that s will be constructed onto the stack, and probably
- * copy-constructed in caller site.
- *
- * If S has copy copy construction and/or destructor,
- * the body will make bit-wise object swap:
- * S __swap = this; // bit copy
- * this = s; // bit copy
- * __swap.dtor();
- * Instead of running the destructor on s, run it on tmp instead.
- *
- * Otherwise, the body will make member-wise assignments:
- * Then, the body is:
- * this.field1 = s.field1;
- * this.field2 = s.field2;
- * ...;
- */
-FuncDeclaration *buildOpAssign(StructDeclaration *sd, Scope *sc)
-{
- if (FuncDeclaration *f = hasIdentityOpAssign(sd, sc))
- {
- sd->hasIdentityAssign = true;
- return f;
- }
- // Even if non-identity opAssign is defined, built-in identity opAssign
- // will be defined.
-
- if (!needOpAssign(sd))
- return NULL;
-
- //printf("StructDeclaration::buildOpAssign() %s\n", sd->toChars());
- StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
- Loc declLoc = sd->loc;
- Loc loc = Loc(); // internal code should have no loc to prevent coverage
-
- // One of our sub-field might have `@disable opAssign` so we need to
- // check for it.
- // In this event, it will be reflected by having `stc` (opAssign's
- // storage class) include `STCdisabled`.
- for (size_t i = 0; i < sd->fields.length; i++)
- {
- VarDeclaration *v = sd->fields[i];
- if (v->storage_class & STCref)
- continue;
- if (v->overlapped)
- continue;
- Type *tv = v->type->baseElemOf();
- if (tv->ty != Tstruct)
- continue;
-
- StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
- stc = mergeFuncAttrs(stc, hasIdentityOpAssign(sdv, sc));
- }
-
- if (sd->dtor || sd->postblit)
- {
- if (!sd->type->isAssignable()) // Bugzilla 13044
- return NULL;
- stc = mergeFuncAttrs(stc, sd->dtor);
- if (stc & STCsafe)
- stc = (stc & ~STCsafe) | STCtrusted;
- }
-
- Parameters *fparams = new Parameters;
- fparams->push(new Parameter(STCnodtor, sd->type, Id::p, NULL, NULL));
- TypeFunction *tf = new TypeFunction(ParameterList(fparams), sd->handleType(), LINKd, stc | STCref);
-
- FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), Id::assign, stc, tf);
- fop->storage_class |= STCinference;
- fop->generated = true;
- Expression *e = NULL;
- if (stc & STCdisable)
- {
- }
- else if (sd->dtor || sd->postblit)
- {
- /* Do swap this and rhs.
- * __swap = this; this = s; __swap.dtor();
- */
- //printf("\tswap copy\n");
- Identifier *idtmp = Identifier::generateId("__swap");
- VarDeclaration *tmp = NULL;
- AssignExp *ec = NULL;
- if (sd->dtor)
- {
- tmp = new VarDeclaration(loc, sd->type, idtmp, new VoidInitializer(loc));
- tmp->storage_class |= STCnodtor | STCtemp | STCctfe;
- e = new DeclarationExp(loc, tmp);
- ec = new BlitExp(loc, new VarExp(loc, tmp), new ThisExp(loc));
- e = Expression::combine(e, ec);
- }
- ec = new BlitExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id::p));
- e = Expression::combine(e, ec);
- if (sd->dtor)
- {
- /* Instead of running the destructor on s, run it
- * on tmp. This avoids needing to copy tmp back in to s.
- */
- Expression *ec2 = new DotVarExp(loc, new VarExp(loc, tmp), sd->dtor, false);
- ec2 = new CallExp(loc, ec2);
- e = Expression::combine(e, ec2);
- }
- }
- else
- {
- /* Do memberwise copy.
- *
- * If sd is a nested struct, its vthis field assignment is:
- * 1. If it's nested in a class, it's a rebind of class reference.
- * 2. If it's nested in a function or struct, it's an update of void*.
- * In both cases, it will change the parent context.
- */
- //printf("\tmemberwise copy\n");
- for (size_t i = 0; i < sd->fields.length; i++)
- {
- VarDeclaration *v = sd->fields[i];
- // this.v = s.v;
- AssignExp *ec = new AssignExp(loc,
- new DotVarExp(loc, new ThisExp(loc), v),
- new DotVarExp(loc, new IdentifierExp(loc, Id::p), v));
- e = Expression::combine(e, ec);
- }
- }
- if (e)
- {
- Statement *s1 = new ExpStatement(loc, e);
-
- /* Add:
- * return this;
- */
- e = new ThisExp(loc);
- Statement *s2 = new ReturnStatement(loc, e);
-
- fop->fbody = new CompoundStatement(loc, s1, s2);
- tf->isreturn = true;
- }
-
- sd->members->push(fop);
- fop->addMember(sc, sd);
- sd->hasIdentityAssign = true; // temporary mark identity assignable
-
- unsigned errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
- Scope *sc2 = sc->push();
- sc2->stc = 0;
- sc2->linkage = LINKd;
-
- dsymbolSemantic(fop, sc2);
- semantic2(fop, sc2);
- // Bugzilla 15044: fop->semantic3 isn't run here for lazy forward reference resolution.
-
- sc2->pop();
- if (global.endGagging(errors)) // if errors happened
- {
- // Disable generated opAssign, because some members forbid identity assignment.
- fop->storage_class |= STCdisable;
- fop->fbody = NULL; // remove fbody which contains the error
- }
-
- //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd->toChars(), (fop->storage_class & STCdisable) != 0);
-
- return fop;
-}
-
-/*******************************************
- * We need an opEquals for the struct if
- * any fields has an opEquals.
- * Generate one if a user-specified one does not exist.
- */
-bool needOpEquals(StructDeclaration *sd)
-{
- //printf("StructDeclaration::needOpEquals() %s\n", sd->toChars());
- if (sd->isUnionDeclaration())
- goto Ldontneed;
-
- if (sd->hasIdentityEquals)
- goto Lneed;
-
- /* If any of the fields has an opEquals, then we
- * need it too.
- */
- for (size_t i = 0; i < sd->fields.length; i++)
- {
- VarDeclaration *v = sd->fields[i];
- if (v->storage_class & STCref)
- continue;
- if (v->overlapped)
- continue;
- Type *tv = v->type->toBasetype();
- Type *tvbase = tv->baseElemOf();
- if (tvbase->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)tvbase;
- if (ts->sym->isUnionDeclaration())
- continue;
- if (needOpEquals(ts->sym))
- goto Lneed;
- if (ts->sym->aliasthis) // Bugzilla 14806
- goto Lneed;
- }
- if (tv->isfloating())
- {
- // This is necessray for:
- // 1. comparison of +0.0 and -0.0 should be true.
- // 2. comparison of NANs should be false always.
- goto Lneed;
- }
- if (tv->ty == Tarray)
- goto Lneed;
- if (tv->ty == Taarray)
- goto Lneed;
- if (tv->ty == Tclass)
- goto Lneed;
- }
-Ldontneed:
- //printf("\tdontneed\n");
- return false;
-
-Lneed:
- //printf("\tneed\n");
- return true;
-}
-
-/*******************************************
- * Check given aggregate actually has an identity opEquals or not.
- */
-FuncDeclaration *hasIdentityOpEquals(AggregateDeclaration *ad, Scope *sc)
-{
- Dsymbol *eq = search_function(ad, Id::eq);
- if (eq)
- {
- /* check identity opEquals exists
- */
- UnionExp er; new(&er) NullExp(ad->loc, NULL); // dummy rvalue
- UnionExp el; new(&el) IdentifierExp(ad->loc, Id::p); // dummy lvalue
- Expressions a;
- a.setDim(1);
- for (size_t i = 0; i < 5; i++)
- {
- Type *tthis = NULL; // dead-store to prevent spurious warning
- switch (i)
- {
- case 0: tthis = ad->type; break;
- case 1: tthis = ad->type->constOf(); break;
- case 2: tthis = ad->type->immutableOf(); break;
- case 3: tthis = ad->type->sharedOf(); break;
- case 4: tthis = ad->type->sharedConstOf(); break;
- default: assert(0);
- }
- FuncDeclaration *f = NULL;
-
- unsigned errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
- sc = sc->push();
- sc->tinst = NULL;
- sc->minst = NULL;
-
- for (size_t j = 0; j < 2; j++)
- {
- a[0] = (j == 0 ? er.exp() : el.exp());
- a[0]->type = tthis;
- f = resolveFuncCall(ad->loc, sc, eq, NULL, tthis, &a, 1);
- if (f)
- break;
- }
-
- sc = sc->pop();
- global.endGagging(errors);
-
- if (f)
- {
- if (f->errors)
- return NULL;
- return f;
- }
- }
- }
- return NULL;
-}
-
-/******************************************
- * Build opEquals for struct.
- * const bool opEquals(const S s) { ... }
- *
- * By fixing bugzilla 3789, opEquals is changed to be never implicitly generated.
- * Now, struct objects comparison s1 == s2 is translated to:
- * s1.tupleof == s2.tupleof
- * to calculate structural equality. See EqualExp::op_overload.
- */
-FuncDeclaration *buildOpEquals(StructDeclaration *sd, Scope *sc)
-{
- if (hasIdentityOpEquals(sd, sc))
- {
- sd->hasIdentityEquals = true;
- }
- return NULL;
-}
-
-/******************************************
- * Build __xopEquals for TypeInfo_Struct
- * static bool __xopEquals(ref const S p, ref const S q)
- * {
- * return p == q;
- * }
- *
- * This is called by TypeInfo.equals(p1, p2). If the struct does not support
- * const objects comparison, it will throw "not implemented" Error in runtime.
- */
-FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc)
-{
- if (!needOpEquals(sd))
- return NULL; // bitwise comparison would work
-
- //printf("StructDeclaration::buildXopEquals() %s\n", sd->toChars());
- if (Dsymbol *eq = search_function(sd, Id::eq))
- {
- if (FuncDeclaration *fd = eq->isFuncDeclaration())
- {
- TypeFunction *tfeqptr;
- {
- Scope scx;
-
- /* const bool opEquals(ref const S s);
- */
- Parameters *parameters = new Parameters;
- parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL, NULL));
- tfeqptr = new TypeFunction(ParameterList(parameters), Type::tbool, LINKd);
- tfeqptr->mod = MODconst;
- tfeqptr = (TypeFunction *)typeSemantic(tfeqptr, Loc(), &scx);
- }
- fd = fd->overloadExactMatch(tfeqptr);
- if (fd)
- return fd;
- }
- }
-
- if (!sd->xerreq)
- {
- // object._xopEquals
- Identifier *id = Identifier::idPool("_xopEquals");
- Expression *e = new IdentifierExp(sd->loc, Id::empty);
- e = new DotIdExp(sd->loc, e, Id::object);
- e = new DotIdExp(sd->loc, e, id);
- e = expressionSemantic(e, sc);
- Dsymbol *s = getDsymbol(e);
- assert(s);
- sd->xerreq = s->isFuncDeclaration();
- }
-
- Loc declLoc = Loc(); // loc is unnecessary so __xopEquals is never called directly
- Loc loc = Loc(); // loc is unnecessary so errors are gagged
-
- Parameters *parameters = new Parameters;
- parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL, NULL));
- parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL, NULL));
- TypeFunction *tf = new TypeFunction(ParameterList(parameters), Type::tbool, LINKd);
-
- Identifier *id = Id::xopEquals;
- FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);
- fop->generated = true;
- Expression *e1 = new IdentifierExp(loc, Id::p);
- Expression *e2 = new IdentifierExp(loc, Id::q);
- Expression *e = new EqualExp(TOKequal, loc, e1, e2);
-
- fop->fbody = new ReturnStatement(loc, e);
-
- unsigned errors = global.startGagging(); // Do not report errors
- Scope *sc2 = sc->push();
- sc2->stc = 0;
- sc2->linkage = LINKd;
-
- dsymbolSemantic(fop, sc2);
- semantic2(fop, sc2);
-
- sc2->pop();
- if (global.endGagging(errors)) // if errors happened
- fop = sd->xerreq;
-
- return fop;
-}
-
-/******************************************
- * Build __xopCmp for TypeInfo_Struct
- * static bool __xopCmp(ref const S p, ref const S q)
- * {
- * return p.opCmp(q);
- * }
- *
- * This is called by TypeInfo.compare(p1, p2). If the struct does not support
- * const objects comparison, it will throw "not implemented" Error in runtime.
- */
-FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc)
-{
- //printf("StructDeclaration::buildXopCmp() %s\n", toChars());
- if (Dsymbol *cmp = search_function(sd, Id::cmp))
- {
- if (FuncDeclaration *fd = cmp->isFuncDeclaration())
- {
- TypeFunction *tfcmpptr;
- {
- Scope scx;
-
- /* const int opCmp(ref const S s);
- */
- Parameters *parameters = new Parameters;
- parameters->push(new Parameter(STCref | STCconst, sd->type, NULL, NULL, NULL));
- tfcmpptr = new TypeFunction(ParameterList(parameters), Type::tint32, LINKd);
- tfcmpptr->mod = MODconst;
- tfcmpptr = (TypeFunction *)typeSemantic(tfcmpptr, Loc(), &scx);
- }
- fd = fd->overloadExactMatch(tfcmpptr);
- if (fd)
- return fd;
- }
- }
- else
- {
- // FIXME: doesn't work for recursive alias this
- return NULL;
- }
-
- if (!sd->xerrcmp)
- {
- // object._xopCmp
- Identifier *id = Identifier::idPool("_xopCmp");
- Expression *e = new IdentifierExp(sd->loc, Id::empty);
- e = new DotIdExp(sd->loc, e, Id::object);
- e = new DotIdExp(sd->loc, e, id);
- e = expressionSemantic(e, sc);
- Dsymbol *s = getDsymbol(e);
- assert(s);
- sd->xerrcmp = s->isFuncDeclaration();
- }
-
- Loc declLoc = Loc(); // loc is unnecessary so __xopCmp is never called directly
- Loc loc = Loc(); // loc is unnecessary so errors are gagged
-
- Parameters *parameters = new Parameters;
- parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL, NULL));
- parameters->push(new Parameter(STCref | STCconst, sd->type, Id::q, NULL, NULL));
- TypeFunction *tf = new TypeFunction(ParameterList(parameters), Type::tint32, LINKd);
-
- Identifier *id = Id::xopCmp;
- FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);
- fop->generated = true;
- Expression *e1 = new IdentifierExp(loc, Id::p);
- Expression *e2 = new IdentifierExp(loc, Id::q);
-#ifdef IN_GCC
- Expression *e = new CallExp(loc, new DotIdExp(loc, e1, Id::cmp), e2);
-#else
- Expression *e = new CallExp(loc, new DotIdExp(loc, e2, Id::cmp), e1);
-#endif
-
- fop->fbody = new ReturnStatement(loc, e);
-
- unsigned errors = global.startGagging(); // Do not report errors
- Scope *sc2 = sc->push();
- sc2->stc = 0;
- sc2->linkage = LINKd;
-
- dsymbolSemantic(fop, sc2);
- semantic2(fop, sc2);
-
- sc2->pop();
- if (global.endGagging(errors)) // if errors happened
- fop = sd->xerrcmp;
-
- return fop;
-}
-
-/*******************************************
- * We need a toHash for the struct if
- * any fields has a toHash.
- * Generate one if a user-specified one does not exist.
- */
-bool needToHash(StructDeclaration *sd)
-{
- //printf("StructDeclaration::needToHash() %s\n", sd->toChars());
- if (sd->isUnionDeclaration())
- goto Ldontneed;
-
- if (sd->xhash)
- goto Lneed;
-
- /* If any of the fields has an opEquals, then we
- * need it too.
- */
- for (size_t i = 0; i < sd->fields.length; i++)
- {
- VarDeclaration *v = sd->fields[i];
- if (v->storage_class & STCref)
- continue;
- if (v->overlapped)
- continue;
- Type *tv = v->type->toBasetype();
- Type *tvbase = tv->baseElemOf();
- if (tvbase->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)tvbase;
- if (ts->sym->isUnionDeclaration())
- continue;
- if (needToHash(ts->sym))
- goto Lneed;
- if (ts->sym->aliasthis) // Bugzilla 14948
- goto Lneed;
- }
- if (tv->isfloating())
- {
- // This is necessray for:
- // 1. comparison of +0.0 and -0.0 should be true.
- goto Lneed;
- }
- if (tv->ty == Tarray)
- goto Lneed;
- if (tv->ty == Taarray)
- goto Lneed;
- if (tv->ty == Tclass)
- goto Lneed;
- }
-Ldontneed:
- //printf("\tdontneed\n");
- return false;
-
-Lneed:
- //printf("\tneed\n");
- return true;
-}
-
-/******************************************
- * Build __xtoHash for non-bitwise hashing
- * static hash_t xtoHash(ref const S p) nothrow @trusted;
- */
-FuncDeclaration *buildXtoHash(StructDeclaration *sd, Scope *sc)
-{
- if (Dsymbol *s = search_function(sd, Id::tohash))
- {
- static TypeFunction *tftohash;
- if (!tftohash)
- {
- tftohash = new TypeFunction(ParameterList(), Type::thash_t, LINKd);
- tftohash->mod = MODconst;
- tftohash = (TypeFunction *)tftohash->merge();
- }
-
- if (FuncDeclaration *fd = s->isFuncDeclaration())
- {
- fd = fd->overloadExactMatch(tftohash);
- if (fd)
- return fd;
- }
- }
-
- if (!needToHash(sd))
- return NULL;
-
- //printf("StructDeclaration::buildXtoHash() %s\n", sd->toPrettyChars());
- Loc declLoc = Loc(); // loc is unnecessary so __xtoHash is never called directly
- Loc loc = Loc(); // internal code should have no loc to prevent coverage
-
- Parameters *parameters = new Parameters();
- parameters->push(new Parameter(STCref | STCconst, sd->type, Id::p, NULL, NULL));
- TypeFunction *tf = new TypeFunction(ParameterList(parameters), Type::thash_t,
- LINKd, STCnothrow | STCtrusted);
-
- Identifier *id = Id::xtoHash;
- FuncDeclaration *fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf);
- fop->generated = true;
-
- /* Do memberwise hashing.
- *
- * If sd is a nested struct, and if it's nested in a class, the calculated
- * hash value will also contain the result of parent class's toHash().
- */
- const char *code =
- "size_t h = 0;"
- "foreach (i, T; typeof(p.tupleof))"
- " h += typeid(T).getHash(cast(const void*)&p.tupleof[i]);"
- "return h;";
- fop->fbody = new CompileStatement(loc, new StringExp(loc, const_cast<char *>(code)));
-
- Scope *sc2 = sc->push();
- sc2->stc = 0;
- sc2->linkage = LINKd;
-
- dsymbolSemantic(fop, sc2);
- semantic2(fop, sc2);
-
- sc2->pop();
-
- //printf("%s fop = %s %s\n", sd->toChars(), fop->toChars(), fop->type->toChars());
- return fop;
-}
-
-/*****************************************
- * Create inclusive postblit for struct by aggregating
- * all the postblits in postblits[] with the postblits for
- * all the members.
- * Note the close similarity with AggregateDeclaration::buildDtor(),
- * and the ordering changes (runs forward instead of backwards).
- */
-FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
-{
- //printf("StructDeclaration::buildPostBlit() %s\n", sd->toChars());
- if (sd->isUnionDeclaration())
- return NULL;
-
- StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
- Loc declLoc = sd->postblits.length ? sd->postblits[0]->loc : sd->loc;
- Loc loc = Loc(); // internal code should have no loc to prevent coverage
-
- for (size_t i = 0; i < sd->postblits.length; i++)
- {
- stc |= sd->postblits[i]->storage_class & STCdisable;
- }
-
- Statements *a = new Statements();
- for (size_t i = 0; i < sd->fields.length && !(stc & STCdisable); i++)
- {
- VarDeclaration *v = sd->fields[i];
- if (v->storage_class & STCref)
- continue;
- if (v->overlapped)
- continue;
- Type *tv = v->type->baseElemOf();
- if (tv->ty != Tstruct)
- continue;
- StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
- if (!sdv->postblit)
- continue;
- assert(!sdv->isUnionDeclaration());
- sdv->postblit->functionSemantic();
-
- stc = mergeFuncAttrs(stc, sdv->postblit);
- stc = mergeFuncAttrs(stc, sdv->dtor);
- if (stc & STCdisable)
- {
- a->setDim(0);
- break;
- }
-
- Expression *ex = NULL;
- tv = v->type->toBasetype();
- if (tv->ty == Tstruct)
- {
- // this.v.__xpostblit()
-
- ex = new ThisExp(loc);
- ex = new DotVarExp(loc, ex, v);
-
- // This is a hack so we can call postblits on const/immutable objects.
- ex = new AddrExp(loc, ex);
- ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
- ex = new PtrExp(loc, ex);
- if (stc & STCsafe)
- stc = (stc & ~STCsafe) | STCtrusted;
-
- ex = new DotVarExp(loc, ex, sdv->postblit, false);
- ex = new CallExp(loc, ex);
- }
- else
- {
- // __ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])
-
- uinteger_t n = tv->numberOfElems(loc);
- if (n == 0)
- continue;
-
- ex = new ThisExp(loc);
- ex = new DotVarExp(loc, ex, v);
-
- // This is a hack so we can call postblits on const/immutable objects.
- ex = new DotIdExp(loc, ex, Id::ptr);
- ex = new CastExp(loc, ex, sdv->type->pointerTo());
- if (stc & STCsafe)
- stc = (stc & ~STCsafe) | STCtrusted;
-
- ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
- new IntegerExp(loc, n, Type::tsize_t));
- // Prevent redundant bounds check
- ((SliceExp *)ex)->upperIsInBounds = true;
- ((SliceExp *)ex)->lowerIsLessThanUpper = true;
-
- ex = new CallExp(loc, new IdentifierExp(loc, Id::__ArrayPostblit), ex);
- }
- a->push(new ExpStatement(loc, ex)); // combine in forward order
-
- /* Bugzilla 10972: When the following field postblit calls fail,
- * this field should be destructed for Exception Safety.
- */
- if (!sdv->dtor)
- continue;
- sdv->dtor->functionSemantic();
-
- tv = v->type->toBasetype();
- if (v->type->toBasetype()->ty == Tstruct)
- {
- // this.v.__xdtor()
-
- ex = new ThisExp(loc);
- ex = new DotVarExp(loc, ex, v);
-
- // This is a hack so we can call destructors on const/immutable objects.
- ex = new AddrExp(loc, ex);
- ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
- ex = new PtrExp(loc, ex);
- if (stc & STCsafe)
- stc = (stc & ~STCsafe) | STCtrusted;
-
- ex = new DotVarExp(loc, ex, sdv->dtor, false);
- ex = new CallExp(loc, ex);
- }
- else
- {
- // __ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
-
- uinteger_t n = tv->numberOfElems(loc);
- //if (n == 0)
- // continue;
-
- ex = new ThisExp(loc);
- ex = new DotVarExp(loc, ex, v);
-
- // This is a hack so we can call destructors on const/immutable objects.
- ex = new DotIdExp(loc, ex, Id::ptr);
- ex = new CastExp(loc, ex, sdv->type->pointerTo());
- if (stc & STCsafe)
- stc = (stc & ~STCsafe) | STCtrusted;
-
- ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
- new IntegerExp(loc, n, Type::tsize_t));
- // Prevent redundant bounds check
- ((SliceExp *)ex)->upperIsInBounds = true;
- ((SliceExp *)ex)->lowerIsLessThanUpper = true;
-
- ex = new CallExp(loc, new IdentifierExp(loc, Id::__ArrayDtor), ex);
- }
- a->push(new ScopeGuardStatement(loc, TOKon_scope_failure, new ExpStatement(loc, ex)));
- }
-
- // Build our own "postblit" which executes a, but only if needed.
- if (a->length || (stc & STCdisable))
- {
- //printf("Building __fieldPostBlit()\n");
- PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__fieldPostblit);
- dd->generated = true;
- dd->storage_class |= STCinference;
- dd->fbody = (stc & STCdisable) ? NULL : new CompoundStatement(loc, a);
- sd->postblits.shift(dd);
- sd->members->push(dd);
- dsymbolSemantic(dd, sc);
- }
-
- FuncDeclaration *xpostblit = NULL;
- switch (sd->postblits.length)
- {
- case 0:
- break;
-
- case 1:
- xpostblit = sd->postblits[0];
- break;
-
- default:
- Expression *e = NULL;
- stc = STCsafe | STCnothrow | STCpure | STCnogc;
- for (size_t i = 0; i < sd->postblits.length; i++)
- {
- FuncDeclaration *fd = sd->postblits[i];
- stc = mergeFuncAttrs(stc, fd);
- if (stc & STCdisable)
- {
- e = NULL;
- break;
- }
- Expression *ex = new ThisExp(loc);
- ex = new DotVarExp(loc, ex, fd, false);
- ex = new CallExp(loc, ex);
- e = Expression::combine(e, ex);
- }
- PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__aggrPostblit);
- dd->storage_class |= STCinference;
- dd->fbody = new ExpStatement(loc, e);
- sd->members->push(dd);
- dsymbolSemantic(dd, sc);
- xpostblit = dd;
- break;
- }
- // Add an __xpostblit alias to make the inclusive postblit accessible
- if (xpostblit)
- {
- AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xpostblit, xpostblit);
- dsymbolSemantic(alias, sc);
- sd->members->push(alias);
- alias->addMember(sc, sd); // add to symbol table
- }
- return xpostblit;
-}
-
-/*****************************************
- * Create inclusive destructor for struct/class by aggregating
- * all the destructors in dtors[] with the destructors for
- * all the members.
- * Note the close similarity with StructDeclaration::buildPostBlit(),
- * and the ordering changes (runs backward instead of forwards).
- */
-FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc)
-{
- //printf("AggregateDeclaration::buildDtor() %s\n", ad->toChars());
- if (ad->isUnionDeclaration())
- return NULL;
-
- StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
- Loc declLoc = ad->dtors.length ? ad->dtors[0]->loc : ad->loc;
- Loc loc = Loc(); // internal code should have no loc to prevent coverage
-
- Expression *e = NULL;
- for (size_t i = 0; i < ad->fields.length; i++)
- {
- VarDeclaration *v = ad->fields[i];
- if (v->storage_class & STCref)
- continue;
- if (v->overlapped)
- continue;
- Type *tv = v->type->baseElemOf();
- if (tv->ty != Tstruct)
- continue;
- StructDeclaration *sdv = ((TypeStruct *)tv)->sym;
- if (!sdv->dtor)
- continue;
- sdv->dtor->functionSemantic();
-
- stc = mergeFuncAttrs(stc, sdv->dtor);
- if (stc & STCdisable)
- {
- e = NULL;
- break;
- }
-
- Expression *ex = NULL;
- tv = v->type->toBasetype();
- if (tv->ty == Tstruct)
- {
- // this.v.__xdtor()
-
- ex = new ThisExp(loc);
- ex = new DotVarExp(loc, ex, v);
-
- // This is a hack so we can call destructors on const/immutable objects.
- ex = new AddrExp(loc, ex);
- ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
- ex = new PtrExp(loc, ex);
- if (stc & STCsafe)
- stc = (stc & ~STCsafe) | STCtrusted;
-
- ex = new DotVarExp(loc, ex, sdv->dtor, false);
- ex = new CallExp(loc, ex);
- }
- else
- {
- // __ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
-
- uinteger_t n = tv->numberOfElems(loc);
- if (n == 0)
- continue;
-
- ex = new ThisExp(loc);
- ex = new DotVarExp(loc, ex, v);
-
- // This is a hack so we can call destructors on const/immutable objects.
- ex = new DotIdExp(loc, ex, Id::ptr);
- ex = new CastExp(loc, ex, sdv->type->pointerTo());
- if (stc & STCsafe)
- stc = (stc & ~STCsafe) | STCtrusted;
-
- ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
- new IntegerExp(loc, n, Type::tsize_t));
- // Prevent redundant bounds check
- ((SliceExp *)ex)->upperIsInBounds = true;
- ((SliceExp *)ex)->lowerIsLessThanUpper = true;
-
- ex = new CallExp(loc, new IdentifierExp(loc, Id::__ArrayDtor), ex);
- }
- e = Expression::combine(ex, e); // combine in reverse order
- }
-
- /* Build our own "destructor" which executes e
- */
- if (e || (stc & STCdisable))
- {
- //printf("Building __fieldDtor()\n");
- DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__fieldDtor);
- dd->generated = true;
- dd->storage_class |= STCinference;
- dd->fbody = new ExpStatement(loc, e);
- ad->dtors.shift(dd);
- ad->members->push(dd);
- dsymbolSemantic(dd, sc);
- }
-
- FuncDeclaration *xdtor = NULL;
- switch (ad->dtors.length)
- {
- case 0:
- break;
-
- case 1:
- xdtor = ad->dtors[0];
- break;
-
- default:
- e = NULL;
- stc = STCsafe | STCnothrow | STCpure | STCnogc;
- for (size_t i = 0; i < ad->dtors.length; i++)
- {
- FuncDeclaration *fd = ad->dtors[i];
- stc = mergeFuncAttrs(stc, fd);
- if (stc & STCdisable)
- {
- e = NULL;
- break;
- }
- Expression *ex = new ThisExp(loc);
- ex = new DotVarExp(loc, ex, fd, false);
- ex = new CallExp(loc, ex);
- e = Expression::combine(ex, e);
- }
- DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__aggrDtor);
- dd->generated = true;
- dd->storage_class |= STCinference;
- dd->fbody = new ExpStatement(loc, e);
- ad->members->push(dd);
- dsymbolSemantic(dd, sc);
- xdtor = dd;
- break;
- }
- // Add an __xdtor alias to make the inclusive dtor accessible
- if (xdtor)
- {
- AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xdtor, xdtor);
- dsymbolSemantic(alias, sc);
- ad->members->push(alias);
- alias->addMember(sc, ad); // add to symbol table
- }
- return xdtor;
-}
-
-/******************************************
- * Create inclusive invariant for struct/class by aggregating
- * all the invariants in invs[].
- * void __invariant() const [pure nothrow @trusted]
- * {
- * invs[0](), invs[1](), ...;
- * }
- */
-FuncDeclaration *buildInv(AggregateDeclaration *ad, Scope *sc)
-{
- StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc;
- Loc declLoc = ad->loc;
- Loc loc = Loc(); // internal code should have no loc to prevent coverage
-
- switch (ad->invs.length)
- {
- case 0:
- return NULL;
-
- case 1:
- // Don't return invs[0] so it has uniquely generated name.
- /* fall through */
-
- default:
- Expression *e = NULL;
- StorageClass stcx = 0;
- for (size_t i = 0; i < ad->invs.length; i++)
- {
- stc = mergeFuncAttrs(stc, ad->invs[i]);
- if (stc & STCdisable)
- {
- // What should do?
- }
- StorageClass stcy = (ad->invs[i]->storage_class & STCsynchronized) |
- (ad->invs[i]->type->mod & MODshared ? STCshared : 0);
- if (i == 0)
- stcx = stcy;
- else if (stcx ^ stcy)
- {
- #if 1 // currently rejects
- ad->error(ad->invs[i]->loc, "mixing invariants with shared/synchronized differene is not supported");
- e = NULL;
- break;
- #endif
- }
- e = Expression::combine(e, new CallExp(loc, new VarExp(loc, ad->invs[i], false)));
- }
- InvariantDeclaration *inv;
- inv = new InvariantDeclaration(declLoc, Loc(), stc | stcx, Id::classInvariant);
- inv->fbody = new ExpStatement(loc, e);
- ad->members->push(inv);
- dsymbolSemantic(inv, sc);
- return inv;
- }
-}
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
new file mode 100644
index 0000000..d300617
--- /dev/null
+++ b/gcc/d/dmd/clone.d
@@ -0,0 +1,1695 @@
+/**
+ * Builds struct member functions if needed and not defined by the user.
+ * Includes `opEquals`, `opAssign`, post blit, copy constructor and destructor.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/clone.d, _clone.d)
+ * Documentation: https://dlang.org/phobos/dmd_clone.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/clone.d
+ */
+
+module dmd.clone;
+
+import core.stdc.stdio;
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.mtype;
+import dmd.opover;
+import dmd.semantic2;
+import dmd.semantic3;
+import dmd.statement;
+import dmd.target;
+import dmd.typesem;
+import dmd.tokens;
+
+/*******************************************
+ * Merge function attributes pure, nothrow, @safe, @nogc, and @disable
+ * from f into s1.
+ * Params:
+ * s1 = storage class to merge into
+ * f = function
+ * Returns:
+ * merged storage class
+ */
+StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure
+{
+ if (!f)
+ return s1;
+ StorageClass s2 = (f.storage_class & STC.disable);
+
+ TypeFunction tf = cast(TypeFunction)f.type;
+ if (tf.trust == TRUST.safe)
+ s2 |= STC.safe;
+ else if (tf.trust == TRUST.system)
+ s2 |= STC.system;
+ else if (tf.trust == TRUST.trusted)
+ s2 |= STC.trusted;
+
+ if (tf.purity != PURE.impure)
+ s2 |= STC.pure_;
+ if (tf.isnothrow)
+ s2 |= STC.nothrow_;
+ if (tf.isnogc)
+ s2 |= STC.nogc;
+
+ const sa = s1 & s2;
+ const so = s1 | s2;
+
+ StorageClass stc = (sa & (STC.pure_ | STC.nothrow_ | STC.nogc)) | (so & STC.disable);
+
+ if (so & STC.system)
+ stc |= STC.system;
+ else if (sa & STC.trusted)
+ stc |= STC.trusted;
+ else if ((so & (STC.trusted | STC.safe)) == (STC.trusted | STC.safe))
+ stc |= STC.trusted;
+ else if (sa & STC.safe)
+ stc |= STC.safe;
+
+ return stc;
+}
+
+/*******************************************
+ * Check given aggregate actually has an identity opAssign or not.
+ * Params:
+ * ad = struct or class
+ * sc = current scope
+ * Returns:
+ * if found, returns FuncDeclaration of opAssign, otherwise null
+ */
+FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc)
+{
+ Dsymbol assign = search_function(ad, Id.assign);
+ if (assign)
+ {
+ /* check identity opAssign exists
+ */
+ scope er = new NullExp(ad.loc, ad.type); // dummy rvalue
+ scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue
+ el.type = ad.type;
+ Expressions a;
+ a.setDim(1);
+ const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
+ sc = sc.push();
+ sc.tinst = null;
+ sc.minst = null;
+
+ a[0] = er;
+ auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, &a, FuncResolveFlag.quiet);
+ if (!f)
+ {
+ a[0] = el;
+ f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, &a, FuncResolveFlag.quiet);
+ }
+
+ sc = sc.pop();
+ global.endGagging(errors);
+ if (f)
+ {
+ if (f.errors)
+ return null;
+ auto fparams = f.getParameterList();
+ if (fparams.length)
+ {
+ auto fparam0 = fparams[0];
+ if (fparam0.type.toDsymbol(null) != ad)
+ f = null;
+ }
+ }
+ // BUGS: This detection mechanism cannot find some opAssign-s like follows:
+ // struct S { void opAssign(ref immutable S) const; }
+ return f;
+ }
+ return null;
+}
+
+/*******************************************
+ * We need an opAssign for the struct if
+ * it has a destructor or a postblit.
+ * We need to generate one if a user-specified one does not exist.
+ */
+private bool needOpAssign(StructDeclaration sd)
+{
+ //printf("StructDeclaration::needOpAssign() %s\n", sd.toChars());
+
+ static bool isNeeded()
+ {
+ //printf("\tneed\n");
+ return true;
+ }
+
+ if (sd.isUnionDeclaration())
+ return !isNeeded();
+
+ if (sd.hasIdentityAssign || // because has identity==elaborate opAssign
+ sd.dtor ||
+ sd.postblit)
+ return isNeeded();
+
+ /* If any of the fields need an opAssign, then we
+ * need it too.
+ */
+ foreach (v; sd.fields)
+ {
+ if (v.storage_class & STC.ref_)
+ continue;
+ if (v.overlapped) // if field of a union
+ continue; // user must handle it themselves
+ Type tv = v.type.baseElemOf();
+ if (tv.ty == Tstruct)
+ {
+ TypeStruct ts = cast(TypeStruct)tv;
+ if (ts.sym.isUnionDeclaration())
+ continue;
+ if (needOpAssign(ts.sym))
+ return isNeeded();
+ }
+ }
+ return !isNeeded();
+}
+
+/******************************************
+ * Build opAssign for a `struct`.
+ *
+ * The generated `opAssign` function has the following signature:
+ *---
+ *ref S opAssign(S s) // S is the name of the `struct`
+ *---
+ *
+ * The opAssign function will be built for a struct `S` if the
+ * following constraints are met:
+ *
+ * 1. `S` does not have an identity `opAssign` defined.
+ *
+ * 2. `S` has at least one of the following members: a postblit (user-defined or
+ * generated for fields that have a defined postblit), a destructor
+ * (user-defined or generated for fields that have a defined destructor)
+ * or at least one field that has a defined `opAssign`.
+ *
+ * 3. `S` does not have any non-mutable fields.
+ *
+ * If `S` has a disabled destructor or at least one field that has a disabled
+ * `opAssign`, `S.opAssign` is going to be generated, but marked with `@disable`
+ *
+ * If `S` defines a destructor, the generated code for `opAssign` is:
+ *
+ *---
+ *S __swap = void;
+ *__swap = this; // bit copy
+ *this = s; // bit copy
+ *__swap.dtor();
+ *---
+ *
+ * Otherwise, if `S` defines a postblit, the generated code for `opAssign` is:
+ *
+ *---
+ *this = s;
+ *---
+ *
+ * Note that the parameter to the generated `opAssign` is passed by value, which means
+ * that the postblit is going to be called (if it is defined) in both of the above
+ * situations before entering the body of `opAssign`. The assignments in the above generated
+ * function bodies are blit expressions, so they can be regarded as `memcpy`s
+ * (`opAssign` is not called as this will result in an infinite recursion; the postblit
+ * is not called because it has already been called when the parameter was passed by value).
+ *
+ * If `S` does not have a postblit or a destructor, but contains at least one field that defines
+ * an `opAssign` function (which is not disabled), then the body will make member-wise
+ * assignments:
+ *
+ *---
+ *this.field1 = s.field1;
+ *this.field2 = s.field2;
+ *...;
+ *---
+ *
+ * In this situation, the assignemnts are actual assign expressions (`opAssign` is used
+ * if defined).
+ *
+ * References:
+ * https://dlang.org/spec/struct.html#assign-overload
+ * Params:
+ * sd = struct to generate opAssign for
+ * sc = context
+ * Returns:
+ * generated `opAssign` function
+ */
+FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
+{
+ if (FuncDeclaration f = hasIdentityOpAssign(sd, sc))
+ {
+ sd.hasIdentityAssign = true;
+ return f;
+ }
+ // Even if non-identity opAssign is defined, built-in identity opAssign
+ // will be defined.
+ if (!needOpAssign(sd))
+ return null;
+
+ //printf("StructDeclaration::buildOpAssign() %s\n", sd.toChars());
+ StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
+ Loc declLoc = sd.loc;
+ Loc loc; // internal code should have no loc to prevent coverage
+
+ // One of our sub-field might have `@disable opAssign` so we need to
+ // check for it.
+ // In this event, it will be reflected by having `stc` (opAssign's
+ // storage class) include `STC.disabled`.
+ foreach (v; sd.fields)
+ {
+ if (v.storage_class & STC.ref_)
+ continue;
+ if (v.overlapped)
+ continue;
+ Type tv = v.type.baseElemOf();
+ if (tv.ty != Tstruct)
+ continue;
+ StructDeclaration sdv = (cast(TypeStruct)tv).sym;
+ stc = mergeFuncAttrs(stc, hasIdentityOpAssign(sdv, sc));
+ }
+
+ if (sd.dtor || sd.postblit)
+ {
+ // if the type is not assignable, we cannot generate opAssign
+ if (!sd.type.isAssignable()) // https://issues.dlang.org/show_bug.cgi?id=13044
+ return null;
+ stc = mergeFuncAttrs(stc, sd.dtor);
+ if (stc & STC.safe)
+ stc = (stc & ~STC.safe) | STC.trusted;
+ }
+
+ auto fparams = new Parameters();
+ fparams.push(new Parameter(STC.nodtor, sd.type, Id.p, null, null));
+ auto tf = new TypeFunction(ParameterList(fparams), sd.handleType(), LINK.d, stc | STC.ref_);
+ auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.assign, stc, tf);
+ fop.storage_class |= STC.inference;
+ fop.generated = true;
+ Expression e;
+ if (stc & STC.disable)
+ {
+ e = null;
+ }
+ /* Do swap this and rhs.
+ * __swap = this; this = s; __swap.dtor();
+ */
+ else if (sd.dtor)
+ {
+ //printf("\tswap copy\n");
+ TypeFunction tdtor = cast(TypeFunction)sd.dtor.type;
+ assert(tdtor.ty == Tfunction);
+
+ auto idswap = Identifier.generateId("__swap");
+ auto swap = new VarDeclaration(loc, sd.type, idswap, new VoidInitializer(loc));
+ swap.storage_class |= STC.nodtor | STC.temp | STC.ctfe;
+ if (tdtor.isScopeQual)
+ swap.storage_class |= STC.scope_;
+ auto e1 = new DeclarationExp(loc, swap);
+
+ auto e2 = new BlitExp(loc, new VarExp(loc, swap), new ThisExp(loc));
+ auto e3 = new BlitExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id.p));
+
+ /* Instead of running the destructor on s, run it
+ * on swap. This avoids needing to copy swap back in to s.
+ */
+ auto e4 = new CallExp(loc, new DotVarExp(loc, new VarExp(loc, swap), sd.dtor, false));
+
+ e = Expression.combine(e1, e2, e3, e4);
+ }
+ /* postblit was called when the value was passed to opAssign, we just need to blit the result */
+ else if (sd.postblit)
+ {
+ e = new BlitExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id.p));
+ sd.hasBlitAssign = true;
+ }
+ else
+ {
+ /* Do memberwise copy.
+ *
+ * If sd is a nested struct, its vthis field assignment is:
+ * 1. If it's nested in a class, it's a rebind of class reference.
+ * 2. If it's nested in a function or struct, it's an update of void*.
+ * In both cases, it will change the parent context.
+ */
+ //printf("\tmemberwise copy\n");
+ e = null;
+ foreach (v; sd.fields)
+ {
+ // this.v = s.v;
+ auto ec = new AssignExp(loc,
+ new DotVarExp(loc, new ThisExp(loc), v),
+ new DotVarExp(loc, new IdentifierExp(loc, Id.p), v));
+ e = Expression.combine(e, ec);
+ }
+ }
+ if (e)
+ {
+ Statement s1 = new ExpStatement(loc, e);
+ /* Add:
+ * return this;
+ */
+ auto er = new ThisExp(loc);
+ Statement s2 = new ReturnStatement(loc, er);
+ fop.fbody = new CompoundStatement(loc, s1, s2);
+ tf.isreturn = true;
+ }
+ sd.members.push(fop);
+ fop.addMember(sc, sd);
+ sd.hasIdentityAssign = true; // temporary mark identity assignable
+ const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
+ Scope* sc2 = sc.push();
+ sc2.stc = 0;
+ sc2.linkage = LINK.d;
+ fop.dsymbolSemantic(sc2);
+ fop.semantic2(sc2);
+ // https://issues.dlang.org/show_bug.cgi?id=15044
+ //semantic3(fop, sc2); // isn't run here for lazy forward reference resolution.
+
+ sc2.pop();
+ if (global.endGagging(errors)) // if errors happened
+ {
+ // Disable generated opAssign, because some members forbid identity assignment.
+ fop.storage_class |= STC.disable;
+ fop.fbody = null; // remove fbody which contains the error
+ }
+
+ //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd.toChars(), (fop.storage_class & STC.disable) != 0);
+ //printf("fop.type: %s\n", fop.type.toPrettyChars());
+ return fop;
+}
+
+/*******************************************
+ * We need an opEquals for the struct if
+ * any fields has an opEquals.
+ * Generate one if a user-specified one does not exist.
+ */
+bool needOpEquals(StructDeclaration sd)
+{
+ //printf("StructDeclaration::needOpEquals() %s\n", sd.toChars());
+ if (sd.isUnionDeclaration())
+ goto Ldontneed;
+ if (sd.hasIdentityEquals)
+ goto Lneed;
+ /* If any of the fields has an opEquals, then we
+ * need it too.
+ */
+ foreach (VarDeclaration v; sd.fields)
+ {
+ if (v.storage_class & STC.ref_)
+ continue;
+ if (v.overlapped)
+ continue;
+ Type tv = v.type.toBasetype();
+ auto tvbase = tv.baseElemOf();
+ if (tvbase.ty == Tstruct)
+ {
+ TypeStruct ts = cast(TypeStruct)tvbase;
+ if (ts.sym.isUnionDeclaration())
+ continue;
+ if (needOpEquals(ts.sym))
+ goto Lneed;
+ }
+ if (tvbase.isfloating())
+ {
+ // This is necessray for:
+ // 1. comparison of +0.0 and -0.0 should be true.
+ // 2. comparison of NANs should be false always.
+ goto Lneed;
+ }
+ if (tvbase.ty == Tarray)
+ goto Lneed;
+ if (tvbase.ty == Taarray)
+ goto Lneed;
+ if (tvbase.ty == Tclass)
+ goto Lneed;
+ }
+Ldontneed:
+ //printf("\tdontneed\n");
+ return false;
+Lneed:
+ //printf("\tneed\n");
+ return true;
+}
+
+/*******************************************
+ * Check given aggregate actually has an identity opEquals or not.
+ */
+private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc)
+{
+ FuncDeclaration f;
+ if (Dsymbol eq = search_function(ad, Id.eq))
+ {
+ /* check identity opEquals exists
+ */
+ scope er = new NullExp(ad.loc, null); // dummy rvalue
+ scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue
+ Expressions a;
+ a.setDim(1);
+
+ bool hasIt(Type tthis)
+ {
+ const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it
+ sc = sc.push();
+ sc.tinst = null;
+ sc.minst = null;
+
+ FuncDeclaration rfc(Expression e)
+ {
+ a[0] = e;
+ a[0].type = tthis;
+ return resolveFuncCall(ad.loc, sc, eq, null, tthis, &a, FuncResolveFlag.quiet);
+ }
+
+ f = rfc(er);
+ if (!f)
+ f = rfc(el);
+
+ sc = sc.pop();
+ global.endGagging(errors);
+
+ return f !is null;
+ }
+
+ if (hasIt(ad.type) ||
+ hasIt(ad.type.constOf()) ||
+ hasIt(ad.type.immutableOf()) ||
+ hasIt(ad.type.sharedOf()) ||
+ hasIt(ad.type.sharedConstOf()))
+ {
+ if (f.errors)
+ return null;
+ }
+ }
+ return f;
+}
+
+/******************************************
+ * Build opEquals for struct.
+ * const bool opEquals(const S s) { ... }
+ *
+ * By fixing https://issues.dlang.org/show_bug.cgi?id=3789
+ * opEquals is changed to be never implicitly generated.
+ * Now, struct objects comparison s1 == s2 is translated to:
+ * s1.tupleof == s2.tupleof
+ * to calculate structural equality. See EqualExp.op_overload.
+ */
+FuncDeclaration buildOpEquals(StructDeclaration sd, Scope* sc)
+{
+ if (hasIdentityOpEquals(sd, sc))
+ {
+ sd.hasIdentityEquals = true;
+ }
+ return null;
+}
+
+/******************************************
+ * Build __xopEquals for TypeInfo_Struct
+ * static bool __xopEquals(ref const S p, ref const S q)
+ * {
+ * return p == q;
+ * }
+ *
+ * This is called by TypeInfo.equals(p1, p2). If the struct does not support
+ * const objects comparison, it will throw "not implemented" Error in runtime.
+ */
+FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
+{
+ if (!needOpEquals(sd))
+ return null; // bitwise comparison would work
+
+ //printf("StructDeclaration::buildXopEquals() %s\n", sd.toChars());
+ if (Dsymbol eq = search_function(sd, Id.eq))
+ {
+ if (FuncDeclaration fd = eq.isFuncDeclaration())
+ {
+ TypeFunction tfeqptr;
+ {
+ Scope scx;
+ /* const bool opEquals(ref const S s);
+ */
+ auto parameters = new Parameters();
+ parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, null, null, null));
+ tfeqptr = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d);
+ tfeqptr.mod = MODFlags.const_;
+ tfeqptr = cast(TypeFunction)tfeqptr.typeSemantic(Loc.initial, &scx);
+ }
+ fd = fd.overloadExactMatch(tfeqptr);
+ if (fd)
+ return fd;
+ }
+ }
+ if (!sd.xerreq)
+ {
+ // object._xopEquals
+ Identifier id = Identifier.idPool("_xopEquals");
+ Expression e = new IdentifierExp(sd.loc, Id.empty);
+ e = new DotIdExp(sd.loc, e, Id.object);
+ e = new DotIdExp(sd.loc, e, id);
+ e = e.expressionSemantic(sc);
+ Dsymbol s = getDsymbol(e);
+ assert(s);
+ sd.xerreq = s.isFuncDeclaration();
+ }
+ Loc declLoc; // loc is unnecessary so __xopEquals is never called directly
+ Loc loc; // loc is unnecessary so errors are gagged
+ auto parameters = new Parameters();
+ parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null))
+ .push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null, null));
+ auto tf = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d);
+ Identifier id = Id.xopEquals;
+ auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
+ fop.generated = true;
+ Expression e1 = new IdentifierExp(loc, Id.p);
+ Expression e2 = new IdentifierExp(loc, Id.q);
+ Expression e = new EqualExp(TOK.equal, loc, e1, e2);
+ fop.fbody = new ReturnStatement(loc, e);
+ uint errors = global.startGagging(); // Do not report errors
+ Scope* sc2 = sc.push();
+ sc2.stc = 0;
+ sc2.linkage = LINK.d;
+ fop.dsymbolSemantic(sc2);
+ fop.semantic2(sc2);
+ sc2.pop();
+ if (global.endGagging(errors)) // if errors happened
+ fop = sd.xerreq;
+ return fop;
+}
+
+/******************************************
+ * Build __xopCmp for TypeInfo_Struct
+ * static bool __xopCmp(ref const S p, ref const S q)
+ * {
+ * return p.opCmp(q);
+ * }
+ *
+ * This is called by TypeInfo.compare(p1, p2). If the struct does not support
+ * const objects comparison, it will throw "not implemented" Error in runtime.
+ */
+FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
+{
+ //printf("StructDeclaration::buildXopCmp() %s\n", toChars());
+ if (Dsymbol cmp = search_function(sd, Id.cmp))
+ {
+ if (FuncDeclaration fd = cmp.isFuncDeclaration())
+ {
+ TypeFunction tfcmpptr;
+ {
+ Scope scx;
+ /* const int opCmp(ref const S s);
+ */
+ auto parameters = new Parameters();
+ parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, null, null, null));
+ tfcmpptr = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d);
+ tfcmpptr.mod = MODFlags.const_;
+ tfcmpptr = cast(TypeFunction)tfcmpptr.typeSemantic(Loc.initial, &scx);
+ }
+ fd = fd.overloadExactMatch(tfcmpptr);
+ if (fd)
+ return fd;
+ }
+ }
+ else
+ {
+ version (none) // FIXME: doesn't work for recursive alias this
+ {
+ /* Check opCmp member exists.
+ * Consider 'alias this', but except opDispatch.
+ */
+ Expression e = new DsymbolExp(sd.loc, sd);
+ e = new DotIdExp(sd.loc, e, Id.cmp);
+ Scope* sc2 = sc.push();
+ e = e.trySemantic(sc2);
+ sc2.pop();
+ if (e)
+ {
+ Dsymbol s = null;
+ switch (e.op)
+ {
+ case TOK.overloadSet:
+ s = (cast(OverExp)e).vars;
+ break;
+ case TOK.scope_:
+ s = (cast(ScopeExp)e).sds;
+ break;
+ case TOK.variable:
+ s = (cast(VarExp)e).var;
+ break;
+ default:
+ break;
+ }
+ if (!s || s.ident != Id.cmp)
+ e = null; // there's no valid member 'opCmp'
+ }
+ if (!e)
+ return null; // bitwise comparison would work
+ /* Essentially, a struct which does not define opCmp is not comparable.
+ * At this time, typeid(S).compare might be correct that throwing "not implement" Error.
+ * But implementing it would break existing code, such as:
+ *
+ * struct S { int value; } // no opCmp
+ * int[S] aa; // Currently AA key uses bitwise comparison
+ * // (It's default behavior of TypeInfo_Strust.compare).
+ *
+ * Not sure we should fix this inconsistency, so just keep current behavior.
+ */
+ }
+ else
+ {
+ return null;
+ }
+ }
+ if (!sd.xerrcmp)
+ {
+ // object._xopCmp
+ Identifier id = Identifier.idPool("_xopCmp");
+ Expression e = new IdentifierExp(sd.loc, Id.empty);
+ e = new DotIdExp(sd.loc, e, Id.object);
+ e = new DotIdExp(sd.loc, e, id);
+ e = e.expressionSemantic(sc);
+ Dsymbol s = getDsymbol(e);
+ assert(s);
+ sd.xerrcmp = s.isFuncDeclaration();
+ }
+ Loc declLoc; // loc is unnecessary so __xopCmp is never called directly
+ Loc loc; // loc is unnecessary so errors are gagged
+ auto parameters = new Parameters();
+ parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null));
+ parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null, null));
+ auto tf = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d);
+ Identifier id = Id.xopCmp;
+ auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
+ fop.generated = true;
+ Expression e1 = new IdentifierExp(loc, Id.p);
+ Expression e2 = new IdentifierExp(loc, Id.q);
+ version (IN_GCC)
+ Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.cmp), e2);
+ else
+ Expression e = new CallExp(loc, new DotIdExp(loc, e2, Id.cmp), e1);
+ fop.fbody = new ReturnStatement(loc, e);
+ uint errors = global.startGagging(); // Do not report errors
+ Scope* sc2 = sc.push();
+ sc2.stc = 0;
+ sc2.linkage = LINK.d;
+ fop.dsymbolSemantic(sc2);
+ fop.semantic2(sc2);
+ sc2.pop();
+ if (global.endGagging(errors)) // if errors happened
+ fop = sd.xerrcmp;
+ return fop;
+}
+
+/*******************************************
+ * We need a toHash for the struct if
+ * any fields has a toHash.
+ * Generate one if a user-specified one does not exist.
+ */
+private bool needToHash(StructDeclaration sd)
+{
+ //printf("StructDeclaration::needToHash() %s\n", sd.toChars());
+ if (sd.isUnionDeclaration())
+ goto Ldontneed;
+ if (sd.xhash)
+ goto Lneed;
+
+ /* If any of the fields has an toHash, then we
+ * need it too.
+ */
+ foreach (VarDeclaration v; sd.fields)
+ {
+ if (v.storage_class & STC.ref_)
+ continue;
+ if (v.overlapped)
+ continue;
+ Type tv = v.type.toBasetype();
+ auto tvbase = tv.baseElemOf();
+ if (tvbase.ty == Tstruct)
+ {
+ TypeStruct ts = cast(TypeStruct)tvbase;
+ if (ts.sym.isUnionDeclaration())
+ continue;
+ if (needToHash(ts.sym))
+ goto Lneed;
+ }
+ if (tvbase.isfloating())
+ {
+ /* This is necessary because comparison of +0.0 and -0.0 should be true,
+ * i.e. not a bit compare.
+ */
+ goto Lneed;
+ }
+ if (tvbase.ty == Tarray)
+ goto Lneed;
+ if (tvbase.ty == Taarray)
+ goto Lneed;
+ if (tvbase.ty == Tclass)
+ goto Lneed;
+ }
+Ldontneed:
+ //printf("\tdontneed\n");
+ return false;
+Lneed:
+ //printf("\tneed\n");
+ return true;
+}
+
+/******************************************
+ * Build __xtoHash for non-bitwise hashing
+ * static hash_t xtoHash(ref const S p) nothrow @trusted;
+ */
+FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
+{
+ if (Dsymbol s = search_function(sd, Id.tohash))
+ {
+ __gshared TypeFunction tftohash;
+ if (!tftohash)
+ {
+ tftohash = new TypeFunction(ParameterList(), Type.thash_t, LINK.d);
+ tftohash.mod = MODFlags.const_;
+ tftohash = cast(TypeFunction)tftohash.merge();
+ }
+ if (FuncDeclaration fd = s.isFuncDeclaration())
+ {
+ fd = fd.overloadExactMatch(tftohash);
+ if (fd)
+ return fd;
+ }
+ }
+ if (!needToHash(sd))
+ return null;
+
+ //printf("StructDeclaration::buildXtoHash() %s\n", sd.toPrettyChars());
+ Loc declLoc; // loc is unnecessary so __xtoHash is never called directly
+ Loc loc; // internal code should have no loc to prevent coverage
+ auto parameters = new Parameters();
+ parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null));
+ auto tf = new TypeFunction(ParameterList(parameters), Type.thash_t, LINK.d, STC.nothrow_ | STC.trusted);
+ Identifier id = Id.xtoHash;
+ auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
+ fop.generated = true;
+
+ /* Do memberwise hashing.
+ *
+ * If sd is a nested struct, and if it's nested in a class, the calculated
+ * hash value will also contain the result of parent class's toHash().
+ */
+ const(char)[] code =
+ ".object.size_t h = 0;" ~
+ "foreach (i, T; typeof(p.tupleof))" ~
+ // workaround https://issues.dlang.org/show_bug.cgi?id=17968
+ " static if(is(T* : const(.object.Object)*)) " ~
+ " h = h * 33 + typeid(const(.object.Object)).getHash(cast(const void*)&p.tupleof[i]);" ~
+ " else " ~
+ " h = h * 33 + typeid(T).getHash(cast(const void*)&p.tupleof[i]);" ~
+ "return h;";
+ fop.fbody = new CompileStatement(loc, new StringExp(loc, code));
+ Scope* sc2 = sc.push();
+ sc2.stc = 0;
+ sc2.linkage = LINK.d;
+ fop.dsymbolSemantic(sc2);
+ fop.semantic2(sc2);
+ sc2.pop();
+
+ //printf("%s fop = %s %s\n", sd.toChars(), fop.toChars(), fop.type.toChars());
+ return fop;
+}
+
+/*****************************************
+ * Create inclusive destructor for struct/class by aggregating
+ * all the destructors in dtors[] with the destructors for
+ * all the members.
+ * Params:
+ * ad = struct or class to build destructor for
+ * sc = context
+ * Returns:
+ * generated function, null if none needed
+ * Note:
+ * Close similarity with StructDeclaration::buildPostBlit(),
+ * and the ordering changes (runs backward instead of forwards).
+ */
+DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
+{
+ //printf("AggregateDeclaration::buildDtor() %s\n", ad.toChars());
+ if (ad.isUnionDeclaration())
+ return null; // unions don't have destructors
+
+ StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
+ Loc declLoc = ad.dtors.dim ? ad.dtors[0].loc : ad.loc;
+ Loc loc; // internal code should have no loc to prevent coverage
+ FuncDeclaration xdtor_fwd = null;
+
+ // if the dtor is an extern(C++) prototype, then we expect it performs a full-destruction; we don't need to build a full-dtor
+ const bool dtorIsCppPrototype = ad.dtors.dim == 1 && ad.dtors[0].linkage == LINK.cpp && !ad.dtors[0].fbody;
+ if (!dtorIsCppPrototype)
+ {
+ Expression e = null;
+ for (size_t i = 0; i < ad.fields.dim; i++)
+ {
+ auto v = ad.fields[i];
+ if (v.storage_class & STC.ref_)
+ continue;
+ if (v.overlapped)
+ continue;
+ auto tv = v.type.baseElemOf();
+ if (tv.ty != Tstruct)
+ continue;
+ auto sdv = (cast(TypeStruct)tv).sym;
+ if (!sdv.dtor)
+ continue;
+
+ // fix: https://issues.dlang.org/show_bug.cgi?id=17257
+ // braces for shrink wrapping scope of a
+ {
+ xdtor_fwd = sdv.dtor; // this dtor is temporary it could be anything
+ auto a = new AliasDeclaration(Loc.initial, Id.__xdtor, xdtor_fwd);
+ a.addMember(sc, ad); // temporarily add to symbol table
+ }
+
+ sdv.dtor.functionSemantic();
+
+ stc = mergeFuncAttrs(stc, sdv.dtor);
+ if (stc & STC.disable)
+ {
+ e = null;
+ break;
+ }
+
+ Expression ex;
+ tv = v.type.toBasetype();
+ if (tv.ty == Tstruct)
+ {
+ // this.v.__xdtor()
+
+ ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, v);
+
+ // This is a hack so we can call destructors on const/immutable objects.
+ // Do it as a type 'paint'.
+ ex = new CastExp(loc, ex, v.type.mutableOf());
+ if (stc & STC.safe)
+ stc = (stc & ~STC.safe) | STC.trusted;
+
+ ex = new DotVarExp(loc, ex, sdv.dtor, false);
+ ex = new CallExp(loc, ex);
+ }
+ else
+ {
+ // __ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
+
+ const n = tv.numberOfElems(loc);
+ if (n == 0)
+ continue;
+
+ ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, v);
+
+ // This is a hack so we can call destructors on const/immutable objects.
+ ex = new DotIdExp(loc, ex, Id.ptr);
+ ex = new CastExp(loc, ex, sdv.type.pointerTo());
+ if (stc & STC.safe)
+ stc = (stc & ~STC.safe) | STC.trusted;
+
+ ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
+ new IntegerExp(loc, n, Type.tsize_t));
+ // Prevent redundant bounds check
+ (cast(SliceExp)ex).upperIsInBounds = true;
+ (cast(SliceExp)ex).lowerIsLessThanUpper = true;
+
+ ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), ex);
+ }
+ e = Expression.combine(ex, e); // combine in reverse order
+ }
+
+ /* extern(C++) destructors call into super to destruct the full hierarchy
+ */
+ ClassDeclaration cldec = ad.isClassDeclaration();
+ if (cldec && cldec.classKind == ClassKind.cpp && cldec.baseClass && cldec.baseClass.primaryDtor)
+ {
+ // WAIT BUT: do I need to run `cldec.baseClass.dtor` semantic? would it have been run before?
+ cldec.baseClass.dtor.functionSemantic();
+
+ stc = mergeFuncAttrs(stc, cldec.baseClass.primaryDtor);
+ if (!(stc & STC.disable))
+ {
+ // super.__xdtor()
+
+ Expression ex = new SuperExp(loc);
+
+ // This is a hack so we can call destructors on const/immutable objects.
+ // Do it as a type 'paint'.
+ ex = new CastExp(loc, ex, cldec.baseClass.type.mutableOf());
+ if (stc & STC.safe)
+ stc = (stc & ~STC.safe) | STC.trusted;
+
+ ex = new DotVarExp(loc, ex, cldec.baseClass.primaryDtor, false);
+ ex = new CallExp(loc, ex);
+
+ e = Expression.combine(e, ex); // super dtor last
+ }
+ }
+
+ /* Build our own "destructor" which executes e
+ */
+ if (e || (stc & STC.disable))
+ {
+ //printf("Building __fieldDtor(), %s\n", e.toChars());
+ auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__fieldDtor);
+ dd.generated = true;
+ dd.storage_class |= STC.inference;
+ dd.fbody = new ExpStatement(loc, e);
+ ad.dtors.shift(dd);
+ ad.members.push(dd);
+ dd.dsymbolSemantic(sc);
+ ad.fieldDtor = dd;
+ }
+ }
+
+ DtorDeclaration xdtor = null;
+ switch (ad.dtors.dim)
+ {
+ case 0:
+ break;
+
+ case 1:
+ xdtor = ad.dtors[0];
+ break;
+
+ default:
+ assert(!dtorIsCppPrototype);
+ Expression e = null;
+ e = null;
+ stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
+ foreach (FuncDeclaration fd; ad.dtors)
+ {
+ stc = mergeFuncAttrs(stc, fd);
+ if (stc & STC.disable)
+ {
+ e = null;
+ break;
+ }
+ Expression ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, fd, false);
+ ex = new CallExp(loc, ex);
+ e = Expression.combine(ex, e);
+ }
+ auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__aggrDtor);
+ dd.generated = true;
+ dd.storage_class |= STC.inference;
+ dd.fbody = new ExpStatement(loc, e);
+ ad.members.push(dd);
+ dd.dsymbolSemantic(sc);
+ xdtor = dd;
+ break;
+ }
+
+ ad.primaryDtor = xdtor;
+
+ if (xdtor && xdtor.linkage == LINK.cpp && !target.cpp.twoDtorInVtable)
+ xdtor = buildWindowsCppDtor(ad, xdtor, sc);
+
+ // Add an __xdtor alias to make the inclusive dtor accessible
+ if (xdtor)
+ {
+ auto _alias = new AliasDeclaration(Loc.initial, Id.__xdtor, xdtor);
+ _alias.dsymbolSemantic(sc);
+ ad.members.push(_alias);
+ if (xdtor_fwd)
+ ad.symtab.update(_alias); // update forward dtor to correct one
+ else
+ _alias.addMember(sc, ad); // add to symbol table
+ }
+
+ return xdtor;
+}
+
+/**
+ * build a shim function around the compound dtor that accepts an argument
+ * that is used to implement the deleting C++ destructor
+ *
+ * Params:
+ * ad = the aggregate that contains the destructor to wrap
+ * dtor = the destructor to wrap
+ * sc = the scope in which to analyze the new function
+ *
+ * Returns:
+ * the shim destructor, semantically analyzed and added to the class as a member
+ */
+private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclaration dtor, Scope* sc)
+{
+ auto cldec = ad.isClassDeclaration();
+ if (!cldec || cldec.cppDtorVtblIndex == -1) // scalar deleting dtor not built for non-virtual dtors
+ return dtor;
+
+ // generate deleting C++ destructor corresponding to:
+ // void* C::~C(int del)
+ // {
+ // this->~C();
+ // // TODO: if (del) delete (char*)this;
+ // return (void*) this;
+ // }
+ Parameter delparam = new Parameter(STC.undefined_, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32), null);
+ Parameters* params = new Parameters;
+ params.push(delparam);
+ auto ftype = new TypeFunction(ParameterList(params), Type.tvoidptr, LINK.cpp, dtor.storage_class);
+ auto func = new DtorDeclaration(dtor.loc, dtor.loc, dtor.storage_class, Id.cppdtor);
+ func.type = ftype;
+ if (dtor.fbody)
+ {
+ const loc = dtor.loc;
+ auto stmts = new Statements;
+ auto call = new CallExp(loc, dtor, null);
+ call.directcall = true;
+ stmts.push(new ExpStatement(loc, call));
+ stmts.push(new ReturnStatement(loc, new CastExp(loc, new ThisExp(loc), Type.tvoidptr)));
+ func.fbody = new CompoundStatement(loc, stmts);
+ func.generated = true;
+ }
+
+ auto sc2 = sc.push();
+ sc2.stc &= ~STC.static_; // not a static destructor
+ sc2.linkage = LINK.cpp;
+
+ ad.members.push(func);
+ func.addMember(sc2, ad);
+ func.dsymbolSemantic(sc2);
+
+ sc2.pop();
+ return func;
+}
+
+/**
+ * build a shim function around the compound dtor that translates
+ * a C++ destructor to a destructor with extern(D) calling convention
+ *
+ * Params:
+ * ad = the aggregate that contains the destructor to wrap
+ * sc = the scope in which to analyze the new function
+ *
+ * Returns:
+ * the shim destructor, semantically analyzed and added to the class as a member
+ */
+DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
+{
+ auto dtor = ad.primaryDtor;
+ if (!dtor)
+ return null;
+
+ // Generate shim only when ABI incompatible on target platform
+ if (ad.classKind != ClassKind.cpp || !target.cpp.wrapDtorInExternD)
+ return dtor;
+
+ // generate member function that adjusts calling convention
+ // (EAX used for 'this' instead of ECX on Windows/stack on others):
+ // extern(D) void __ticppdtor()
+ // {
+ // Class.__dtor();
+ // }
+ auto ftype = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, dtor.storage_class);
+ auto func = new DtorDeclaration(dtor.loc, dtor.loc, dtor.storage_class, Id.ticppdtor);
+ func.type = ftype;
+
+ auto call = new CallExp(dtor.loc, dtor, null);
+ call.directcall = true; // non-virtual call Class.__dtor();
+ func.fbody = new ExpStatement(dtor.loc, call);
+ func.generated = true;
+ func.storage_class |= STC.inference;
+
+ auto sc2 = sc.push();
+ sc2.stc &= ~STC.static_; // not a static destructor
+ sc2.linkage = LINK.d;
+
+ ad.members.push(func);
+ func.addMember(sc2, ad);
+ func.dsymbolSemantic(sc2);
+ func.functionSemantic(); // to infer attributes
+
+ sc2.pop();
+ return func;
+}
+
+/******************************************
+ * Create inclusive invariant for struct/class by aggregating
+ * all the invariants in invs[].
+ * ---
+ * void __invariant() const [pure nothrow @trusted]
+ * {
+ * invs[0](), invs[1](), ...;
+ * }
+ * ---
+ */
+FuncDeclaration buildInv(AggregateDeclaration ad, Scope* sc)
+{
+ switch (ad.invs.dim)
+ {
+ case 0:
+ return null;
+
+ case 1:
+ // Don't return invs[0] so it has uniquely generated name.
+ goto default;
+
+ default:
+ Expression e = null;
+ StorageClass stcx = 0;
+ StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
+ foreach (i, inv; ad.invs)
+ {
+ stc = mergeFuncAttrs(stc, inv);
+ if (stc & STC.disable)
+ {
+ // What should do?
+ }
+ const stcy = (inv.storage_class & STC.synchronized_) |
+ (inv.type.mod & MODFlags.shared_ ? STC.shared_ : 0);
+ if (i == 0)
+ stcx = stcy;
+ else if (stcx ^ stcy)
+ {
+ version (all)
+ {
+ // currently rejects
+ ad.error(inv.loc, "mixing invariants with different `shared`/`synchronized` qualifiers is not supported");
+ e = null;
+ break;
+ }
+ }
+ e = Expression.combine(e, new CallExp(Loc.initial, new VarExp(Loc.initial, inv, false)));
+ }
+ auto inv = new InvariantDeclaration(ad.loc, Loc.initial, stc | stcx,
+ Id.classInvariant, new ExpStatement(Loc.initial, e));
+ ad.members.push(inv);
+ inv.dsymbolSemantic(sc);
+ return inv;
+ }
+}
+
+/*****************************************
+ * Create inclusive postblit for struct by aggregating
+ * all the postblits in postblits[] with the postblits for
+ * all the members.
+ * Note the close similarity with AggregateDeclaration::buildDtor(),
+ * and the ordering changes (runs forward instead of backwards).
+ */
+FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
+{
+ //printf("buildPostBlit() %s\n", sd.toChars());
+ if (sd.isUnionDeclaration())
+ return null;
+
+ const hasUserDefinedPosblit = sd.postblits.dim && !sd.postblits[0].isDisabled ? true : false;
+
+ // by default, the storage class of the created postblit
+ StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
+ Loc declLoc = sd.postblits.dim ? sd.postblits[0].loc : sd.loc;
+ Loc loc; // internal code should have no loc to prevent coverage
+
+ // if any of the postblits are disabled, then the generated postblit
+ // will be disabled
+ foreach (postblit; sd.postblits)
+ stc |= postblit.storage_class & STC.disable;
+
+ VarDeclaration[] fieldsToDestroy;
+ auto postblitCalls = new Statements();
+ // iterate through all the struct fields that are not disabled
+ for (size_t i = 0; i < sd.fields.dim && !(stc & STC.disable); i++)
+ {
+ auto structField = sd.fields[i];
+ if (structField.storage_class & STC.ref_)
+ continue;
+ if (structField.overlapped)
+ continue;
+ // if it's a struct declaration or an array of structs
+ Type tv = structField.type.baseElemOf();
+ if (tv.ty != Tstruct)
+ continue;
+ auto sdv = (cast(TypeStruct)tv).sym;
+ // which has a postblit declaration
+ if (!sdv.postblit)
+ continue;
+ assert(!sdv.isUnionDeclaration());
+
+ // if this field's postblit is not `nothrow`, add a `scope(failure)`
+ // block to destroy any prior successfully postblitted fields should
+ // this field's postblit fail
+ if (fieldsToDestroy.length > 0 && !(cast(TypeFunction)sdv.postblit.type).isnothrow)
+ {
+ // create a list of destructors that need to be called
+ Expression[] dtorCalls;
+ foreach(sf; fieldsToDestroy)
+ {
+ Expression ex;
+ tv = sf.type.toBasetype();
+ if (tv.ty == Tstruct)
+ {
+ // this.v.__xdtor()
+
+ ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, sf);
+
+ // This is a hack so we can call destructors on const/immutable objects.
+ ex = new AddrExp(loc, ex);
+ ex = new CastExp(loc, ex, sf.type.mutableOf().pointerTo());
+ ex = new PtrExp(loc, ex);
+ if (stc & STC.safe)
+ stc = (stc & ~STC.safe) | STC.trusted;
+
+ auto sfv = (cast(TypeStruct)sf.type.baseElemOf()).sym;
+
+ ex = new DotVarExp(loc, ex, sfv.dtor, false);
+ ex = new CallExp(loc, ex);
+
+ dtorCalls ~= ex;
+ }
+ else
+ {
+ // _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])
+
+ const length = tv.numberOfElems(loc);
+
+ ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, sf);
+
+ // This is a hack so we can call destructors on const/immutable objects.
+ ex = new DotIdExp(loc, ex, Id.ptr);
+ ex = new CastExp(loc, ex, sdv.type.pointerTo());
+ if (stc & STC.safe)
+ stc = (stc & ~STC.safe) | STC.trusted;
+
+ auto se = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
+ new IntegerExp(loc, length, Type.tsize_t));
+ // Prevent redundant bounds check
+ se.upperIsInBounds = true;
+ se.lowerIsLessThanUpper = true;
+
+ ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se);
+
+ dtorCalls ~= ex;
+ }
+ }
+ fieldsToDestroy = [];
+
+ // aggregate the destructor calls
+ auto dtors = new Statements();
+ foreach_reverse(dc; dtorCalls)
+ {
+ dtors.push(new ExpStatement(loc, dc));
+ }
+
+ // put destructor calls in a `scope(failure)` block
+ postblitCalls.push(new ScopeGuardStatement(loc, TOK.onScopeFailure, new CompoundStatement(loc, dtors)));
+ }
+
+ // perform semantic on the member postblit in order to
+ // be able to aggregate it later on with the rest of the
+ // postblits
+ sdv.postblit.functionSemantic();
+
+ stc = mergeFuncAttrs(stc, sdv.postblit);
+ stc = mergeFuncAttrs(stc, sdv.dtor);
+
+ // if any of the struct member fields has disabled
+ // its postblit, then `sd` is not copyable, so no
+ // postblit is generated
+ if (stc & STC.disable)
+ {
+ postblitCalls.setDim(0);
+ break;
+ }
+
+ Expression ex;
+ tv = structField.type.toBasetype();
+ if (tv.ty == Tstruct)
+ {
+ // this.v.__xpostblit()
+
+ ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, structField);
+
+ // This is a hack so we can call postblits on const/immutable objects.
+ ex = new AddrExp(loc, ex);
+ ex = new CastExp(loc, ex, structField.type.mutableOf().pointerTo());
+ ex = new PtrExp(loc, ex);
+ if (stc & STC.safe)
+ stc = (stc & ~STC.safe) | STC.trusted;
+
+ ex = new DotVarExp(loc, ex, sdv.postblit, false);
+ ex = new CallExp(loc, ex);
+ }
+ else
+ {
+ // _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])
+
+ const length = tv.numberOfElems(loc);
+ if (length == 0)
+ continue;
+
+ ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, structField);
+
+ // This is a hack so we can call postblits on const/immutable objects.
+ ex = new DotIdExp(loc, ex, Id.ptr);
+ ex = new CastExp(loc, ex, sdv.type.pointerTo());
+ if (stc & STC.safe)
+ stc = (stc & ~STC.safe) | STC.trusted;
+
+ auto se = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
+ new IntegerExp(loc, length, Type.tsize_t));
+ // Prevent redundant bounds check
+ se.upperIsInBounds = true;
+ se.lowerIsLessThanUpper = true;
+ ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayPostblit), se);
+ }
+ postblitCalls.push(new ExpStatement(loc, ex)); // combine in forward order
+
+ /* https://issues.dlang.org/show_bug.cgi?id=10972
+ * When subsequent field postblit calls fail,
+ * this field should be destructed for Exception Safety.
+ */
+ if (sdv.dtor)
+ {
+ sdv.dtor.functionSemantic();
+
+ // keep a list of fields that need to be destroyed in case
+ // of a future postblit failure
+ fieldsToDestroy ~= structField;
+ }
+ }
+
+ void checkShared()
+ {
+ if (sd.type.isShared())
+ stc |= STC.shared_;
+ }
+
+ // Build our own "postblit" which executes a, but only if needed.
+ if (postblitCalls.dim || (stc & STC.disable))
+ {
+ //printf("Building __fieldPostBlit()\n");
+ checkShared();
+ auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__fieldPostblit);
+ dd.generated = true;
+ dd.storage_class |= STC.inference | STC.scope_;
+ dd.fbody = (stc & STC.disable) ? null : new CompoundStatement(loc, postblitCalls);
+ sd.postblits.shift(dd);
+ sd.members.push(dd);
+ dd.dsymbolSemantic(sc);
+ }
+
+ // create __xpostblit, which is the generated postblit
+ FuncDeclaration xpostblit = null;
+ switch (sd.postblits.dim)
+ {
+ case 0:
+ break;
+
+ case 1:
+ xpostblit = sd.postblits[0];
+ break;
+
+ default:
+ Expression e = null;
+ stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
+ foreach (fd; sd.postblits)
+ {
+ stc = mergeFuncAttrs(stc, fd);
+ if (stc & STC.disable)
+ {
+ e = null;
+ break;
+ }
+ Expression ex = new ThisExp(loc);
+ ex = new DotVarExp(loc, ex, fd, false);
+ ex = new CallExp(loc, ex);
+ e = Expression.combine(e, ex);
+ }
+
+ checkShared();
+ auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__aggrPostblit);
+ dd.generated = true;
+ dd.storage_class |= STC.inference;
+ dd.fbody = new ExpStatement(loc, e);
+ sd.members.push(dd);
+ dd.dsymbolSemantic(sc);
+ xpostblit = dd;
+ break;
+ }
+
+ // Add an __xpostblit alias to make the inclusive postblit accessible
+ if (xpostblit)
+ {
+ auto _alias = new AliasDeclaration(Loc.initial, Id.__xpostblit, xpostblit);
+ _alias.dsymbolSemantic(sc);
+ sd.members.push(_alias);
+ _alias.addMember(sc, sd); // add to symbol table
+ }
+
+ if (sd.hasCopyCtor)
+ {
+ // we have user defined postblit, so we prioritize it
+ if (hasUserDefinedPosblit)
+ {
+ sd.hasCopyCtor = false;
+ return xpostblit;
+ }
+ // we have fields with postblits, so print deprecations
+ if (xpostblit && !xpostblit.isDisabled())
+ {
+ deprecation(sd.loc, "`struct %s` implicitly-generated postblit hides copy constructor.", sd.toChars);
+ deprecationSupplemental(sd.loc, "The field postblit will have priority over the copy constructor.");
+ deprecationSupplemental(sd.loc, "To change this, the postblit should be disabled for `struct %s`", sd.toChars());
+ sd.hasCopyCtor = false;
+ }
+ else
+ xpostblit = null;
+ }
+
+ return xpostblit;
+}
+
+/**
+ * Generates a copy constructor declaration with the specified storage
+ * class for the parameter and the function.
+ *
+ * Params:
+ * sd = the `struct` that contains the copy constructor
+ * paramStc = the storage class of the copy constructor parameter
+ * funcStc = the storage class for the copy constructor declaration
+ *
+ * Returns:
+ * The copy constructor declaration for struct `sd`.
+ */
+private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const StorageClass paramStc, const StorageClass funcStc)
+{
+ auto fparams = new Parameters();
+ auto structType = sd.type;
+ fparams.push(new Parameter(paramStc | STC.ref_ | STC.return_ | STC.scope_, structType, Id.p, null, null));
+ ParameterList pList = ParameterList(fparams);
+ auto tf = new TypeFunction(pList, structType, LINK.d, STC.ref_);
+ auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf, true);
+ ccd.storage_class |= funcStc;
+ ccd.storage_class |= STC.inference;
+ ccd.generated = true;
+ return ccd;
+}
+
+/**
+ * Generates a trivial copy constructor body that simply does memberwise
+ * initialization:
+ *
+ * this.field1 = rhs.field1;
+ * this.field2 = rhs.field2;
+ * ...
+ *
+ * Params:
+ * sd = the `struct` declaration that contains the copy constructor
+ *
+ * Returns:
+ * A `CompoundStatement` containing the body of the copy constructor.
+ */
+private Statement generateCopyCtorBody(StructDeclaration sd)
+{
+ Loc loc;
+ Expression e;
+ foreach (v; sd.fields)
+ {
+ auto ec = new AssignExp(loc,
+ new DotVarExp(loc, new ThisExp(loc), v),
+ new DotVarExp(loc, new IdentifierExp(loc, Id.p), v));
+ e = Expression.combine(e, ec);
+ //printf("e.toChars = %s\n", e.toChars());
+ }
+ Statement s1 = new ExpStatement(loc, e);
+ return new CompoundStatement(loc, s1);
+}
+
+/**
+ * Determine if a copy constructor is needed for struct sd,
+ * if the following conditions are met:
+ *
+ * 1. sd does not define a copy constructor
+ * 2. at least one field of sd defines a copy constructor
+ *
+ * Params:
+ * sd = the `struct` for which the copy constructor is generated
+ * hasCpCtor = set to true if a copy constructor is already present
+ *
+ * Returns:
+ * `true` if one needs to be generated
+ * `false` otherwise
+ */
+private bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor)
+{
+ if (global.errors)
+ return false;
+
+ auto ctor = sd.search(sd.loc, Id.ctor);
+ if (ctor)
+ {
+ if (ctor.isOverloadSet())
+ return false;
+ if (auto td = ctor.isTemplateDeclaration())
+ ctor = td.funcroot;
+ }
+
+ CtorDeclaration cpCtor;
+ CtorDeclaration rvalueCtor;
+
+ if (!ctor)
+ goto LcheckFields;
+
+ overloadApply(ctor, (Dsymbol s)
+ {
+ if (s.isTemplateDeclaration())
+ return 0;
+ auto ctorDecl = s.isCtorDeclaration();
+ assert(ctorDecl);
+ if (ctorDecl.isCpCtor)
+ {
+ if (!cpCtor)
+ cpCtor = ctorDecl;
+ return 0;
+ }
+
+ auto tf = ctorDecl.type.toTypeFunction();
+ const dim = tf.parameterList.length;
+ if (dim == 1)
+ {
+ auto param = tf.parameterList[0];
+ if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
+ {
+ rvalueCtor = ctorDecl;
+ }
+ }
+ return 0;
+ });
+
+ if (cpCtor)
+ {
+ if (rvalueCtor)
+ {
+ .error(sd.loc, "`struct %s` may not define both a rvalue constructor and a copy constructor", sd.toChars());
+ errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here");
+ errorSupplemental(cpCtor.loc, "copy constructor defined here");
+ }
+ hasCpCtor = true;
+ return false;
+ }
+
+LcheckFields:
+ VarDeclaration fieldWithCpCtor;
+ // see if any struct members define a copy constructor
+ foreach (v; sd.fields)
+ {
+ if (v.storage_class & STC.ref_)
+ continue;
+ if (v.overlapped)
+ continue;
+
+ auto ts = v.type.baseElemOf().isTypeStruct();
+ if (!ts)
+ continue;
+ if (ts.sym.hasCopyCtor)
+ {
+ fieldWithCpCtor = v;
+ break;
+ }
+ }
+
+ if (fieldWithCpCtor && rvalueCtor)
+ {
+ .error(sd.loc, "`struct %s` may not define a rvalue constructor and have fields with copy constructors", sd.toChars());
+ errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here");
+ errorSupplemental(fieldWithCpCtor.loc, "field with copy constructor defined here");
+ return false;
+ }
+ else if (!fieldWithCpCtor)
+ return false;
+ return true;
+}
+
+/**
+ * Generates a copy constructor if needCopyCtor() returns true.
+ * The generated copy constructor will be of the form:
+ * this(ref return scope inout(S) rhs) inout
+ * {
+ * this.field1 = rhs.field1;
+ * this.field2 = rhs.field2;
+ * ...
+ * }
+ *
+ * Params:
+ * sd = the `struct` for which the copy constructor is generated
+ * sc = the scope where the copy constructor is generated
+ *
+ * Returns:
+ * `true` if `struct` sd defines a copy constructor (explicitly or generated),
+ * `false` otherwise.
+ */
+bool buildCopyCtor(StructDeclaration sd, Scope* sc)
+{
+ bool hasCpCtor;
+ if (!needCopyCtor(sd, hasCpCtor))
+ return hasCpCtor;
+
+ //printf("generating copy constructor for %s\n", sd.toChars());
+ const MOD paramMod = MODFlags.wild;
+ const MOD funcMod = MODFlags.wild;
+ auto ccd = generateCopyCtorDeclaration(sd, ModToStc(paramMod), ModToStc(funcMod));
+ auto copyCtorBody = generateCopyCtorBody(sd);
+ ccd.fbody = copyCtorBody;
+ sd.members.push(ccd);
+ ccd.addMember(sc, sd);
+ const errors = global.startGagging();
+ Scope* sc2 = sc.push();
+ sc2.stc = 0;
+ sc2.linkage = LINK.d;
+ ccd.dsymbolSemantic(sc2);
+ ccd.semantic2(sc2);
+ ccd.semantic3(sc2);
+ //printf("ccd semantic: %s\n", ccd.type.toChars());
+ sc2.pop();
+ if (global.endGagging(errors) || sd.isUnionDeclaration())
+ {
+ ccd.storage_class |= STC.disable;
+ ccd.fbody = null;
+ }
+ return true;
+}
+
+
diff --git a/gcc/d/dmd/compiler.d b/gcc/d/dmd/compiler.d
new file mode 100644
index 0000000..28f9ba6
--- /dev/null
+++ b/gcc/d/dmd/compiler.d
@@ -0,0 +1,57 @@
+/**
+ * Describes a back-end compiler and implements compiler-specific actions.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/compiler.d, _compiler.d)
+ * Documentation: https://dlang.org/phobos/dmd_compiler.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/compiler.d
+ */
+
+module dmd.compiler;
+
+import dmd.arraytypes;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.expression;
+import dmd.mtype;
+import dmd.root.array;
+
+extern (C++) __gshared
+{
+ bool includeImports = false;
+ // array of module patterns used to include/exclude imported modules
+ Array!(const(char)*) includeModulePatterns;
+ Modules compiledImports;
+}
+
+
+/**
+ * A data structure that describes a back-end compiler and implements
+ * compiler-specific actions.
+ */
+extern (C++) struct Compiler
+{
+ /******************************
+ * Encode the given expression, which is assumed to be an rvalue literal
+ * as another type for use in CTFE.
+ * This corresponds roughly to the idiom *(Type *)&e.
+ */
+ extern (C++) static Expression paintAsType(UnionExp* pue, Expression e, Type type);
+
+ /******************************
+ * For the given module, perform any post parsing analysis.
+ * Certain compiler backends (ie: GDC) have special placeholder
+ * modules whose source are empty, but code gets injected
+ * immediately after loading.
+ */
+ extern (C++) static void onParseModule(Module m);
+
+ /**
+ * A callback function that is called once an imported module is
+ * parsed. If the callback returns true, then it tells the
+ * frontend that the driver intends on compiling the import.
+ */
+ extern (C++) static bool onImport(Module m);
+}
diff --git a/gcc/d/dmd/compiler.h b/gcc/d/dmd/compiler.h
index e7ef5a4..27e87b6 100644
--- a/gcc/d/dmd/compiler.h
+++ b/gcc/d/dmd/compiler.h
@@ -22,11 +22,6 @@ class Type;
struct Scope;
struct UnionExp;
-// DMD-generated module `__entrypoint` where the C main resides
-extern Module *entrypoint;
-// Module in which the D main is
-extern Module *rootHasMain;
-
extern bool includeImports;
// array of module patterns used to include/exclude imported modules
extern Array<const char*> includeModulePatterns;
@@ -37,7 +32,6 @@ struct Compiler
// CTFE support for cross-compilation.
static Expression *paintAsType(UnionExp *, Expression *, Type *);
// Backend
- static void genCmain(Scope *);
static bool onImport(Module *);
static void onParseModule(Module *);
};
diff --git a/gcc/d/dmd/complex.d b/gcc/d/dmd/complex.d
new file mode 100644
index 0000000..84bf5e97
--- /dev/null
+++ b/gcc/d/dmd/complex.d
@@ -0,0 +1,112 @@
+/**
+ * Implements a complex number type.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/complex.d, _complex.d)
+ * Documentation: https://dlang.org/phobos/dmd_complex.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/complex.d
+ */
+
+module dmd.complex;
+
+import dmd.root.ctfloat;
+
+extern (C++) struct complex_t
+{
+ real_t re;
+ real_t im;
+
+ this() @disable;
+
+ this(real_t re)
+ {
+ this(re, CTFloat.zero);
+ }
+
+ this(real_t re, real_t im)
+ {
+ this.re = re;
+ this.im = im;
+ }
+
+ extern (D) complex_t opBinary(string op)(complex_t y)
+ if (op == "+")
+ {
+ return complex_t(re + y.re, im + y.im);
+ }
+
+ extern (D) complex_t opBinary(string op)(complex_t y)
+ if (op == "-")
+ {
+ return complex_t(re - y.re, im - y.im);
+ }
+
+ extern (D) complex_t opUnary(string op)()
+ if (op == "-")
+ {
+ return complex_t(-re, -im);
+ }
+
+ extern (D) complex_t opBinary(string op)(complex_t y)
+ if (op == "*")
+ {
+ return complex_t(re * y.re - im * y.im, im * y.re + re * y.im);
+ }
+
+ extern (D) complex_t opBinaryRight(string op)(real_t x)
+ if (op == "*")
+ {
+ return complex_t(x) * this;
+ }
+
+ extern (D) complex_t opBinary(string op)(real_t y)
+ if (op == "*")
+ {
+ return this * complex_t(y);
+ }
+
+ extern (D) complex_t opBinary(string op)(real_t y)
+ if (op == "/")
+ {
+ return this / complex_t(y);
+ }
+
+ extern (D) complex_t opBinary(string op)(complex_t y)
+ if (op == "/")
+ {
+ if (CTFloat.fabs(y.re) < CTFloat.fabs(y.im))
+ {
+ const r = y.re / y.im;
+ const den = y.im + r * y.re;
+ return complex_t((re * r + im) / den, (im * r - re) / den);
+ }
+ else
+ {
+ const r = y.im / y.re;
+ const den = y.re + r * y.im;
+ return complex_t((re + r * im) / den, (im - r * re) / den);
+ }
+ }
+
+ extern (D) bool opCast(T : bool)() const
+ {
+ return re || im;
+ }
+
+ int opEquals(complex_t y) const
+ {
+ return re == y.re && im == y.im;
+ }
+}
+
+extern (C++) real_t creall(complex_t x)
+{
+ return x.re;
+}
+
+extern (C++) real_t cimagl(complex_t x)
+{
+ return x.im;
+}
diff --git a/gcc/d/dmd/complex_t.h b/gcc/d/dmd/complex_t.h
index 7f17460..3359171 100644
--- a/gcc/d/dmd/complex_t.h
+++ b/gcc/d/dmd/complex_t.h
@@ -20,7 +20,7 @@ struct complex_t
real_t re;
real_t im;
- complex_t(real_t re) : re(re), im(ldouble(0)) {}
+ complex_t(real_t re) : re(re), im(CTFloat::zero) {}
complex_t(real_t re, real_t im) : re(re), im(im) {}
complex_t operator + (complex_t y) { return complex_t(re + y.re, im + y.im); }
@@ -52,7 +52,7 @@ struct complex_t
int operator != (complex_t y) { return re != y.re || im != y.im; }
private:
- complex_t() : re(ldouble(0)), im(ldouble(0)) {}
+ complex_t() : re(CTFloat::zero), im(CTFloat::zero) {}
};
inline complex_t operator * (real_t x, complex_t y) { return complex_t(x) * y; }
diff --git a/gcc/d/dmd/cond.c b/gcc/d/dmd/cond.c
deleted file mode 100644
index 6c7dc9e..0000000
--- a/gcc/d/dmd/cond.c
+++ /dev/null
@@ -1,738 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/cond.c
- */
-
-#include "root/dsystem.h" // strcmp()
-
-#include "mars.h"
-#include "id.h"
-#include "init.h"
-#include "aggregate.h"
-#include "declaration.h"
-#include "identifier.h"
-#include "expression.h"
-#include "cond.h"
-#include "module.h"
-#include "template.h"
-#include "mtype.h"
-#include "scope.h"
-#include "statement.h"
-#include "arraytypes.h"
-#include "tokens.h"
-
-bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
-
-int findCondition(Identifiers *ids, Identifier *ident)
-{
- if (ids)
- {
- for (size_t i = 0; i < ids->length; i++)
- {
- Identifier *id = (*ids)[i];
-
- if (id == ident)
- return true;
- }
- }
-
- return false;
-}
-
-/* ============================================================ */
-
-Condition::Condition(Loc loc)
-{
- this->loc = loc;
- inc = 0;
-}
-
-/* ============================================================ */
-
-StaticForeach::StaticForeach(Loc loc, ForeachStatement *aggrfe, ForeachRangeStatement *rangefe)
-{
- assert(!!aggrfe ^ !!rangefe);
- this->loc = loc;
- this->aggrfe = aggrfe;
- this->rangefe = rangefe;
- this->needExpansion = false;
-}
-
-StaticForeach *StaticForeach::syntaxCopy()
-{
- return new StaticForeach(
- loc,
- aggrfe ? (ForeachStatement *)aggrfe->syntaxCopy() : NULL,
- rangefe ? (ForeachRangeStatement *)rangefe->syntaxCopy() : NULL
- );
-}
-
-/*****************************************
- * Turn an aggregate which is an array into an expression tuple
- * of its elements. I.e., lower
- * static foreach (x; [1, 2, 3, 4]) { ... }
- * to
- * static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... }
- */
-
-static void lowerArrayAggregate(StaticForeach *sfe, Scope *sc)
-{
- Expression *aggr = sfe->aggrfe->aggr;
- Expression *el = new ArrayLengthExp(aggr->loc, aggr);
- sc = sc->startCTFE();
- el = expressionSemantic(el, sc);
- sc = sc->endCTFE();
- el = el->optimize(WANTvalue);
- el = el->ctfeInterpret();
- if (el->op == TOKint64)
- {
- Expressions *es;
- if (ArrayLiteralExp *ale = aggr->isArrayLiteralExp())
- {
- // Directly use the elements of the array for the TupleExp creation
- es = ale->elements;
- }
- else
- {
- size_t length = (size_t)el->toInteger();
- es = new Expressions();
- es->setDim(length);
- for (size_t i = 0; i < length; i++)
- {
- IntegerExp *index = new IntegerExp(sfe->loc, i, Type::tsize_t);
- Expression *value = new IndexExp(aggr->loc, aggr, index);
- (*es)[i] = value;
- }
- }
- sfe->aggrfe->aggr = new TupleExp(aggr->loc, es);
- sfe->aggrfe->aggr = expressionSemantic(sfe->aggrfe->aggr, sc);
- sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue);
- sfe->aggrfe->aggr = sfe->aggrfe->aggr->ctfeInterpret();
- }
- else
- {
- sfe->aggrfe->aggr = new ErrorExp();
- }
-}
-
-/*****************************************
- * Wrap a statement into a function literal and call it.
- *
- * Params:
- * loc = The source location.
- * s = The statement.
- * Returns:
- * AST of the expression `(){ s; }()` with location loc.
- */
-
-static Expression *wrapAndCall(Loc loc, Statement *s)
-{
- TypeFunction *tf = new TypeFunction(ParameterList(), NULL, LINKdefault, 0);
- FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, loc, tf, TOKreserved, NULL);
- fd->fbody = s;
- FuncExp *fe = new FuncExp(loc, fd);
- Expression *ce = new CallExp(loc, fe, new Expressions());
- return ce;
-}
-
-/*****************************************
- * Create a `foreach` statement from `aggrefe/rangefe` with given
- * `foreach` variables and body `s`.
- *
- * Params:
- * loc = The source location.
- * parameters = The foreach variables.
- * s = The `foreach` body.
- * Returns:
- * `foreach (parameters; aggregate) s;` or
- * `foreach (parameters; lower .. upper) s;`
- * Where aggregate/lower, upper are as for the current StaticForeach.
- */
-
-static Statement *createForeach(StaticForeach *sfe, Loc loc, Parameters *parameters, Statement *s)
-{
- if (sfe->aggrfe)
- {
- return new ForeachStatement(loc, sfe->aggrfe->op, parameters, sfe->aggrfe->aggr->syntaxCopy(), s, loc);
- }
- else
- {
- assert(sfe->rangefe && parameters->length == 1);
- return new ForeachRangeStatement(loc, sfe->rangefe->op, (*parameters)[0],
- sfe->rangefe->lwr->syntaxCopy(),
- sfe->rangefe->upr->syntaxCopy(), s, loc);
- }
-}
-
-/*****************************************
- * For a `static foreach` with multiple loop variables, the
- * aggregate is lowered to an array of tuples. As D does not have
- * built-in tuples, we need a suitable tuple type. This generates
- * a `struct` that serves as the tuple type. This type is only
- * used during CTFE and hence its typeinfo will not go to the
- * object file.
- *
- * Params:
- * loc = The source location.
- * e = The expressions we wish to store in the tuple.
- * sc = The current scope.
- * Returns:
- * A struct type of the form
- * struct Tuple
- * {
- * typeof(AliasSeq!(e)) tuple;
- * }
- */
-
-static TypeStruct *createTupleType(Loc loc, Expressions *e)
-{ // TODO: move to druntime?
- Identifier *sid = Identifier::generateId("Tuple");
- StructDeclaration *sdecl = new StructDeclaration(loc, sid, false);
- sdecl->storage_class |= STCstatic;
- sdecl->members = new Dsymbols();
- Identifier *fid = Identifier::idPool("tuple");
- Type *ty = new TypeTypeof(loc, new TupleExp(loc, e));
- sdecl->members->push(new VarDeclaration(loc, ty, fid, NULL));
- TypeStruct *r = (TypeStruct *)sdecl->type;
- if (global.params.useTypeInfo && Type::dtypeinfo)
- r->vtinfo = TypeInfoStructDeclaration::create(r); // prevent typeinfo from going to object file
- return r;
-}
-
-/*****************************************
- * Create the AST for an instantiation of a suitable tuple type.
- *
- * Params:
- * loc = The source location.
- * type = A Tuple type, created with createTupleType.
- * e = The expressions we wish to store in the tuple.
- * Returns:
- * An AST for the expression `Tuple(e)`.
- */
-
-static Expression *createTuple(Loc loc, TypeStruct *type, Expressions *e)
-{ // TODO: move to druntime?
- return new CallExp(loc, new TypeExp(loc, type), e);
-}
-
-/*****************************************
- * Lower any aggregate that is not an array to an array using a
- * regular foreach loop within CTFE. If there are multiple
- * `static foreach` loop variables, an array of tuples is
- * generated. In thise case, the field `needExpansion` is set to
- * true to indicate that the static foreach loop expansion will
- * need to expand the tuples into multiple variables.
- *
- * For example, `static foreach (x; range) { ... }` is lowered to:
- *
- * static foreach (x; {
- * typeof({
- * foreach (x; range) return x;
- * }())[] __res;
- * foreach (x; range) __res ~= x;
- * return __res;
- * }()) { ... }
- *
- * Finally, call `lowerArrayAggregate` to turn the produced
- * array into an expression tuple.
- *
- * Params:
- * sc = The current scope.
- */
-
-static void lowerNonArrayAggregate(StaticForeach *sfe, Scope *sc)
-{
- size_t nvars = sfe->aggrfe ? sfe->aggrfe->parameters->length : 1;
- Loc aloc = sfe->aggrfe ? sfe->aggrfe->aggr->loc : sfe->rangefe->lwr->loc;
- // We need three sets of foreach loop variables because the
- // lowering contains three foreach loops.
- Parameters *pparams[3] = {new Parameters(), new Parameters(), new Parameters()};
- for (size_t i = 0; i < nvars; i++)
- {
- for (size_t j = 0; j < 3; j++)
- {
- Parameters *params = pparams[j];
- Parameter *p = sfe->aggrfe ? (*sfe->aggrfe->parameters)[i] : sfe->rangefe->prm;
- params->push(new Parameter(p->storageClass, p->type, p->ident, NULL, NULL));
- }
- }
- Expression *res[2];
- TypeStruct *tplty = NULL;
- if (nvars == 1) // only one `static foreach` variable, generate identifiers.
- {
- for (size_t i = 0; i < 2; i++)
- {
- res[i] = new IdentifierExp(aloc, (*pparams[i])[0]->ident);
- }
- }
- else // multiple `static foreach` variables, generate tuples.
- {
- for (size_t i = 0; i < 2; i++)
- {
- Expressions *e = new Expressions();
- for (size_t j = 0; j < pparams[0]->length; j++)
- {
- Parameter *p = (*pparams[i])[j];
- e->push(new IdentifierExp(aloc, p->ident));
- }
- if (!tplty)
- {
- tplty = createTupleType(aloc, e);
- }
- res[i] = createTuple(aloc, tplty, e);
- }
- sfe->needExpansion = true; // need to expand the tuples later
- }
- // generate remaining code for the new aggregate which is an
- // array (see documentation comment).
- if (sfe->rangefe)
- {
- sc = sc->startCTFE();
- sfe->rangefe->lwr = expressionSemantic(sfe->rangefe->lwr, sc);
- sfe->rangefe->lwr = resolveProperties(sc, sfe->rangefe->lwr);
- sfe->rangefe->upr = expressionSemantic(sfe->rangefe->upr, sc);
- sfe->rangefe->upr = resolveProperties(sc, sfe->rangefe->upr);
- sc = sc->endCTFE();
- sfe->rangefe->lwr = sfe->rangefe->lwr->optimize(WANTvalue);
- sfe->rangefe->lwr = sfe->rangefe->lwr->ctfeInterpret();
- sfe->rangefe->upr = sfe->rangefe->upr->optimize(WANTvalue);
- sfe->rangefe->upr = sfe->rangefe->upr->ctfeInterpret();
- }
- Statements *s1 = new Statements();
- Statements *sfebody = new Statements();
- if (tplty) sfebody->push(new ExpStatement(sfe->loc, tplty->sym));
- sfebody->push(new ReturnStatement(aloc, res[0]));
- s1->push(createForeach(sfe, aloc, pparams[0], new CompoundStatement(aloc, sfebody)));
- s1->push(new ExpStatement(aloc, new AssertExp(aloc, new IntegerExp(aloc, 0, Type::tint32))));
- Type *ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
- Type *aty = ety->arrayOf();
- Identifier *idres = Identifier::generateId("__res");
- VarDeclaration *vard = new VarDeclaration(aloc, aty, idres, NULL);
- Statements *s2 = new Statements();
-
- // Run 'typeof' gagged to avoid duplicate errors and if it fails just create
- // an empty foreach to expose them.
- unsigned olderrors = global.startGagging();
- ety = typeSemantic(ety, aloc, sc);
- if (global.endGagging(olderrors))
- s2->push(createForeach(sfe, aloc, pparams[1], NULL));
- else
- {
- s2->push(new ExpStatement(aloc, vard));
- Expression *catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
- s2->push(createForeach(sfe, aloc, pparams[1], new ExpStatement(aloc, catass)));
- s2->push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
- }
-
- Expression *aggr;
- Type *indexty;
-
- if (sfe->rangefe && (indexty = ety)->isintegral())
- {
- sfe->rangefe->lwr->type = indexty;
- sfe->rangefe->upr->type = indexty;
- IntRange lwrRange = getIntRange(sfe->rangefe->lwr);
- IntRange uprRange = getIntRange(sfe->rangefe->upr);
-
- const dinteger_t lwr = sfe->rangefe->lwr->toInteger();
- dinteger_t upr = sfe->rangefe->upr->toInteger();
- size_t length = 0;
-
- if (lwrRange.imin <= uprRange.imax)
- length = (size_t)(upr - lwr);
-
- Expressions *exps = new Expressions();
- exps->setDim(length);
-
- if (sfe->rangefe->op == TOKforeach)
- {
- for (size_t i = 0; i < length; i++)
- (*exps)[i] = new IntegerExp(aloc, lwr + i, indexty);
- }
- else
- {
- --upr;
- for (size_t i = 0; i < length; i++)
- (*exps)[i] = new IntegerExp(aloc, upr - i, indexty);
- }
- aggr = new ArrayLiteralExp(aloc, indexty->arrayOf(), exps);
- }
- else
- {
- aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2));
- sc = sc->startCTFE();
- aggr = expressionSemantic(aggr, sc);
- aggr = resolveProperties(sc, aggr);
- sc = sc->endCTFE();
- aggr = aggr->optimize(WANTvalue);
- aggr = aggr->ctfeInterpret();
- }
-
- assert(!!sfe->aggrfe ^ !!sfe->rangefe);
- sfe->aggrfe = new ForeachStatement(sfe->loc, TOKforeach, pparams[2], aggr,
- sfe->aggrfe ? sfe->aggrfe->_body : sfe->rangefe->_body,
- sfe->aggrfe ? sfe->aggrfe->endloc : sfe->rangefe->endloc);
- sfe->rangefe = NULL;
- lowerArrayAggregate(sfe, sc); // finally, turn generated array into expression tuple
-}
-
-/*****************************************
- * Perform `static foreach` lowerings that are necessary in order
- * to finally expand the `static foreach` using
- * `ddmd.statementsem.makeTupleForeach`.
- */
-
-void staticForeachPrepare(StaticForeach *sfe, Scope *sc)
-{
- assert(sc);
- if (sfe->aggrfe)
- {
- sc = sc->startCTFE();
- sfe->aggrfe->aggr = expressionSemantic(sfe->aggrfe->aggr, sc);
- sc = sc->endCTFE();
- sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue);
- }
-
- if (sfe->aggrfe && sfe->aggrfe->aggr->type->toBasetype()->ty == Terror)
- {
- return;
- }
-
- if (!staticForeachReady(sfe))
- {
- if (sfe->aggrfe && sfe->aggrfe->aggr->type->toBasetype()->ty == Tarray)
- {
- lowerArrayAggregate(sfe, sc);
- }
- else
- {
- lowerNonArrayAggregate(sfe, sc);
- }
- }
-}
-
-/*****************************************
- * Returns:
- * `true` iff ready to call `ddmd.statementsem.makeTupleForeach`.
- */
-
-bool staticForeachReady(StaticForeach *sfe)
-{
- return sfe->aggrfe && sfe->aggrfe->aggr && sfe->aggrfe->aggr->type &&
- sfe->aggrfe->aggr->type->toBasetype()->ty == Ttuple;
-}
-
-/* ============================================================ */
-
-DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
- : Condition(Loc())
-{
- this->mod = mod;
- this->level = level;
- this->ident = ident;
-}
-
-Condition *DVCondition::syntaxCopy()
-{
- return this; // don't need to copy
-}
-
-/* ============================================================ */
-
-void DebugCondition::addGlobalIdent(const char *ident)
-{
- if (!global.debugids)
- global.debugids = new Identifiers();
- global.debugids->push(Identifier::idPool(ident));
-}
-
-
-DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
- : DVCondition(mod, level, ident)
-{
-}
-
-// Helper for printing dependency information
-void printDepsConditional(Scope *sc, DVCondition* condition, const char* depType)
-{
- if (!global.params.moduleDeps || global.params.moduleDepsFile.length)
- return;
- OutBuffer *ob = global.params.moduleDeps;
- Module* imod = sc ? sc->instantiatingModule() : condition->mod;
- if (!imod)
- return;
- ob->writestring(depType);
- ob->writestring(imod->toPrettyChars());
- ob->writestring(" (");
- escapePath(ob, imod->srcfile->toChars());
- ob->writestring(") : ");
- if (condition->ident)
- ob->printf("%s\n", condition->ident->toChars());
- else
- ob->printf("%d\n", condition->level);
-}
-
-
-int DebugCondition::include(Scope *sc)
-{
- //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
- if (inc == 0)
- {
- inc = 2;
- bool definedInModule = false;
- if (ident)
- {
- if (findCondition(mod->debugids, ident))
- {
- inc = 1;
- definedInModule = true;
- }
- else if (findCondition(global.debugids, ident))
- inc = 1;
- else
- { if (!mod->debugidsNot)
- mod->debugidsNot = new Identifiers();
- mod->debugidsNot->push(ident);
- }
- }
- else if (level <= global.params.debuglevel || level <= mod->debuglevel)
- inc = 1;
- if (!definedInModule)
- printDepsConditional(sc, this, "depsDebug ");
- }
- return (inc == 1);
-}
-
-/* ============================================================ */
-
-static bool isReserved(const char *ident)
-{
- static const char* reserved[] =
- {
- "DigitalMars",
- "GNU",
- "LDC",
- "SDC",
- "Windows",
- "Win32",
- "Win64",
- "linux",
- "OSX",
- "FreeBSD",
- "OpenBSD",
- "NetBSD",
- "DragonFlyBSD",
- "BSD",
- "Solaris",
- "Posix",
- "AIX",
- "Haiku",
- "SkyOS",
- "SysV3",
- "SysV4",
- "Hurd",
- "Android",
- "PlayStation",
- "PlayStation4",
- "Cygwin",
- "MinGW",
- "FreeStanding",
- "X86",
- "X86_64",
- "ARM",
- "ARM_Thumb",
- "ARM_SoftFloat",
- "ARM_SoftFP",
- "ARM_HardFloat",
- "AArch64",
- "Epiphany",
- "PPC",
- "PPC_SoftFloat",
- "PPC_HardFloat",
- "PPC64",
- "IA64",
- "MIPS32",
- "MIPS64",
- "MIPS_O32",
- "MIPS_N32",
- "MIPS_O64",
- "MIPS_N64",
- "MIPS_EABI",
- "MIPS_SoftFloat",
- "MIPS_HardFloat",
- "MSP430",
- "NVPTX",
- "NVPTX64",
- "RISCV32",
- "RISCV64",
- "SPARC",
- "SPARC_V8Plus",
- "SPARC_SoftFloat",
- "SPARC_HardFloat",
- "SPARC64",
- "S390",
- "S390X",
- "HPPA",
- "HPPA64",
- "SH",
- "Alpha",
- "Alpha_SoftFloat",
- "Alpha_HardFloat",
- "LittleEndian",
- "BigEndian",
- "ELFv1",
- "ELFv2",
- "CRuntime_Digitalmars",
- "CRuntime_Glibc",
- "CRuntime_Microsoft",
- "CRuntime_Musl",
- "CRuntime_UClibc",
- "CppRuntime_Clang",
- "CppRuntime_DigitalMars",
- "CppRuntime_Gcc",
- "CppRuntime_Microsoft",
- "CppRuntime_Sun",
- "D_Coverage",
- "D_Ddoc",
- "D_InlineAsm_X86",
- "D_InlineAsm_X86_64",
- "D_LP64",
- "D_X32",
- "D_HardFloat",
- "D_SoftFloat",
- "D_PIC",
- "D_SIMD",
- "D_Version2",
- "D_NoBoundsChecks",
- "unittest",
- "assert",
- "all",
- "none",
- NULL
- };
-
- for (unsigned i = 0; reserved[i]; i++)
- {
- if (strcmp(ident, reserved[i]) == 0)
- return true;
- }
-
- if (ident[0] == 'D' && ident[1] == '_')
- return true;
- return false;
-}
-
-void checkReserved(Loc loc, const char *ident)
-{
- if (isReserved(ident))
- error(loc, "version identifier `%s` is reserved and cannot be set", ident);
-}
-
-void VersionCondition::addGlobalIdent(const char *ident)
-{
- checkReserved(Loc(), ident);
- addPredefinedGlobalIdent(ident);
-}
-
-void VersionCondition::addPredefinedGlobalIdent(const char *ident)
-{
- if (!global.versionids)
- global.versionids = new Identifiers();
- global.versionids->push(Identifier::idPool(ident));
-}
-
-
-VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
- : DVCondition(mod, level, ident)
-{
-}
-
-int VersionCondition::include(Scope *sc)
-{
- //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
- //if (ident) printf("\tident = '%s'\n", ident->toChars());
- if (inc == 0)
- {
- inc = 2;
- bool definedInModule=false;
- if (ident)
- {
- if (findCondition(mod->versionids, ident))
- {
- inc = 1;
- definedInModule = true;
- }
- else if (findCondition(global.versionids, ident))
- inc = 1;
- else
- {
- if (!mod->versionidsNot)
- mod->versionidsNot = new Identifiers();
- mod->versionidsNot->push(ident);
- }
- }
- else if (level <= global.params.versionlevel || level <= mod->versionlevel)
- inc = 1;
- if (!definedInModule && (!ident || (!isReserved(ident->toChars()) && ident != Id::_unittest && ident != Id::_assert)))
- printDepsConditional(sc, this, "depsVersion ");
- }
- return (inc == 1);
-}
-
-/**************************** StaticIfCondition *******************************/
-
-StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
- : Condition(loc)
-{
- this->exp = exp;
-}
-
-Condition *StaticIfCondition::syntaxCopy()
-{
- return new StaticIfCondition(loc, exp->syntaxCopy());
-}
-
-int StaticIfCondition::include(Scope *sc)
-{
- if (inc == 0)
- {
- if (!sc)
- {
- error(loc, "static if conditional cannot be at global scope");
- inc = 2;
- return 0;
- }
-
- sc = sc->push(sc->scopesym);
-
- bool errors = false;
-
- if (!exp)
- goto Lerror;
-
- bool result = evalStaticCondition(sc, exp, exp, errors);
- sc->pop();
-
- // Prevent repeated condition evaluation.
- // See: fail_compilation/fail7815.d
- if (inc != 0)
- return (inc == 1);
- if (errors)
- goto Lerror;
- if (result)
- inc = 1;
- else
- inc = 2;
- }
- return (inc == 1);
-
-Lerror:
- if (!global.gag)
- inc = 2; // so we don't see the error message again
- return 0;
-}
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
new file mode 100644
index 0000000..d4a8b13
--- /dev/null
+++ b/gcc/d/dmd/cond.d
@@ -0,0 +1,1004 @@
+/**
+ * Evaluate compile-time conditionals, such as `static if` `version` and `debug`.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/version.html, Conditional Compilation)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cond.d, _cond.d)
+ * Documentation: https://dlang.org/phobos/dmd_cond.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cond.d
+ */
+
+module dmd.cond;
+
+import core.stdc.string;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.ast_node;
+import dmd.dcast;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.globals;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.typesem;
+import dmd.root.outbuffer;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.tokens;
+import dmd.utils;
+import dmd.visitor;
+import dmd.id;
+import dmd.statement;
+import dmd.declaration;
+import dmd.dstruct;
+import dmd.func;
+
+/***********************************************************
+ */
+
+enum Include : ubyte
+{
+ notComputed, /// not computed yet
+ yes, /// include the conditional code
+ no, /// do not include the conditional code
+}
+
+extern (C++) abstract class Condition : ASTNode
+{
+ Loc loc;
+
+ Include inc;
+
+ override final DYNCAST dyncast() const
+ {
+ return DYNCAST.condition;
+ }
+
+ extern (D) this(const ref Loc loc)
+ {
+ this.loc = loc;
+ }
+
+ abstract Condition syntaxCopy();
+
+ abstract int include(Scope* sc);
+
+ inout(DebugCondition) isDebugCondition() inout
+ {
+ return null;
+ }
+
+ inout(VersionCondition) isVersionCondition() inout
+ {
+ return null;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Implements common functionality for StaticForeachDeclaration and
+ * StaticForeachStatement This performs the necessary lowerings before
+ * dmd.statementsem.makeTupleForeach can be used to expand the
+ * corresponding `static foreach` declaration or statement.
+ */
+
+extern (C++) final class StaticForeach : RootObject
+{
+ extern(D) static immutable tupleFieldName = "tuple"; // used in lowering
+
+ Loc loc;
+
+ /***************
+ * Not `null` iff the `static foreach` is over an aggregate. In
+ * this case, it contains the corresponding ForeachStatement. For
+ * StaticForeachDeclaration, the body is `null`.
+ */
+ ForeachStatement aggrfe;
+ /***************
+ * Not `null` iff the `static foreach` is over a range. Exactly
+ * one of the `aggrefe` and `rangefe` fields is not null. See
+ * `aggrfe` field for more details.
+ */
+ ForeachRangeStatement rangefe;
+
+ /***************
+ * true if it is necessary to expand a tuple into multiple
+ * variables (see lowerNonArrayAggregate).
+ */
+ bool needExpansion = false;
+
+ extern (D) this(const ref Loc loc, ForeachStatement aggrfe, ForeachRangeStatement rangefe)
+ {
+ assert(!!aggrfe ^ !!rangefe);
+
+ this.loc = loc;
+ this.aggrfe = aggrfe;
+ this.rangefe = rangefe;
+ }
+
+ StaticForeach syntaxCopy()
+ {
+ return new StaticForeach(
+ loc,
+ aggrfe ? aggrfe.syntaxCopy() : null,
+ rangefe ? rangefe.syntaxCopy() : null
+ );
+ }
+
+ /*****************************************
+ * Turn an aggregate which is an array into an expression tuple
+ * of its elements. I.e., lower
+ * static foreach (x; [1, 2, 3, 4]) { ... }
+ * to
+ * static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... }
+ */
+ private extern(D) void lowerArrayAggregate(Scope* sc)
+ {
+ auto aggr = aggrfe.aggr;
+ Expression el = new ArrayLengthExp(aggr.loc, aggr);
+ sc = sc.startCTFE();
+ el = el.expressionSemantic(sc);
+ sc = sc.endCTFE();
+ el = el.optimize(WANTvalue);
+ el = el.ctfeInterpret();
+ if (el.op == TOK.int64)
+ {
+ Expressions *es = void;
+ if (auto ale = aggr.isArrayLiteralExp())
+ {
+ // Directly use the elements of the array for the TupleExp creation
+ es = ale.elements;
+ }
+ else
+ {
+ const length = cast(size_t)el.toInteger();
+ es = new Expressions(length);
+ foreach (i; 0 .. length)
+ {
+ auto index = new IntegerExp(loc, i, Type.tsize_t);
+ auto value = new IndexExp(aggr.loc, aggr, index);
+ (*es)[i] = value;
+ }
+ }
+ aggrfe.aggr = new TupleExp(aggr.loc, es);
+ aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
+ aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue);
+ aggrfe.aggr = aggrfe.aggr.ctfeInterpret();
+ }
+ else
+ {
+ aggrfe.aggr = ErrorExp.get();
+ }
+ }
+
+ /*****************************************
+ * Wrap a statement into a function literal and call it.
+ *
+ * Params:
+ * loc = The source location.
+ * s = The statement.
+ * Returns:
+ * AST of the expression `(){ s; }()` with location loc.
+ */
+ private extern(D) Expression wrapAndCall(const ref Loc loc, Statement s)
+ {
+ auto tf = new TypeFunction(ParameterList(), null, LINK.default_, 0);
+ auto fd = new FuncLiteralDeclaration(loc, loc, tf, TOK.reserved, null);
+ fd.fbody = s;
+ auto fe = new FuncExp(loc, fd);
+ auto ce = new CallExp(loc, fe, new Expressions());
+ return ce;
+ }
+
+ /*****************************************
+ * Create a `foreach` statement from `aggrefe/rangefe` with given
+ * `foreach` variables and body `s`.
+ *
+ * Params:
+ * loc = The source location.
+ * parameters = The foreach variables.
+ * s = The `foreach` body.
+ * Returns:
+ * `foreach (parameters; aggregate) s;` or
+ * `foreach (parameters; lower .. upper) s;`
+ * Where aggregate/lower, upper are as for the current StaticForeach.
+ */
+ private extern(D) Statement createForeach(const ref Loc loc, Parameters* parameters, Statement s)
+ {
+ if (aggrfe)
+ {
+ return new ForeachStatement(loc, aggrfe.op, parameters, aggrfe.aggr.syntaxCopy(), s, loc);
+ }
+ else
+ {
+ assert(rangefe && parameters.dim == 1);
+ return new ForeachRangeStatement(loc, rangefe.op, (*parameters)[0], rangefe.lwr.syntaxCopy(), rangefe.upr.syntaxCopy(), s, loc);
+ }
+ }
+
+ /*****************************************
+ * For a `static foreach` with multiple loop variables, the
+ * aggregate is lowered to an array of tuples. As D does not have
+ * built-in tuples, we need a suitable tuple type. This generates
+ * a `struct` that serves as the tuple type. This type is only
+ * used during CTFE and hence its typeinfo will not go to the
+ * object file.
+ *
+ * Params:
+ * loc = The source location.
+ * e = The expressions we wish to store in the tuple.
+ * sc = The current scope.
+ * Returns:
+ * A struct type of the form
+ * struct Tuple
+ * {
+ * typeof(AliasSeq!(e)) tuple;
+ * }
+ */
+
+ private extern(D) TypeStruct createTupleType(const ref Loc loc, Expressions* e, Scope* sc)
+ { // TODO: move to druntime?
+ auto sid = Identifier.generateId("Tuple");
+ auto sdecl = new StructDeclaration(loc, sid, false);
+ sdecl.storage_class |= STC.static_;
+ sdecl.members = new Dsymbols();
+ auto fid = Identifier.idPool(tupleFieldName.ptr, tupleFieldName.length);
+ auto ty = new TypeTypeof(loc, new TupleExp(loc, e));
+ sdecl.members.push(new VarDeclaration(loc, ty, fid, null, 0));
+ auto r = cast(TypeStruct)sdecl.type;
+ if (global.params.useTypeInfo && Type.dtypeinfo)
+ r.vtinfo = TypeInfoStructDeclaration.create(r); // prevent typeinfo from going to object file
+ return r;
+ }
+
+ /*****************************************
+ * Create the AST for an instantiation of a suitable tuple type.
+ *
+ * Params:
+ * loc = The source location.
+ * type = A Tuple type, created with createTupleType.
+ * e = The expressions we wish to store in the tuple.
+ * Returns:
+ * An AST for the expression `Tuple(e)`.
+ */
+
+ private extern(D) Expression createTuple(const ref Loc loc, TypeStruct type, Expressions* e)
+ { // TODO: move to druntime?
+ return new CallExp(loc, new TypeExp(loc, type), e);
+ }
+
+
+ /*****************************************
+ * Lower any aggregate that is not an array to an array using a
+ * regular foreach loop within CTFE. If there are multiple
+ * `static foreach` loop variables, an array of tuples is
+ * generated. In thise case, the field `needExpansion` is set to
+ * true to indicate that the static foreach loop expansion will
+ * need to expand the tuples into multiple variables.
+ *
+ * For example, `static foreach (x; range) { ... }` is lowered to:
+ *
+ * static foreach (x; {
+ * typeof({
+ * foreach (x; range) return x;
+ * }())[] __res;
+ * foreach (x; range) __res ~= x;
+ * return __res;
+ * }()) { ... }
+ *
+ * Finally, call `lowerArrayAggregate` to turn the produced
+ * array into an expression tuple.
+ *
+ * Params:
+ * sc = The current scope.
+ */
+
+ private void lowerNonArrayAggregate(Scope* sc)
+ {
+ auto nvars = aggrfe ? aggrfe.parameters.dim : 1;
+ auto aloc = aggrfe ? aggrfe.aggr.loc : rangefe.lwr.loc;
+ // We need three sets of foreach loop variables because the
+ // lowering contains three foreach loops.
+ Parameters*[3] pparams = [new Parameters(), new Parameters(), new Parameters()];
+ foreach (i; 0 .. nvars)
+ {
+ foreach (params; pparams)
+ {
+ auto p = aggrfe ? (*aggrfe.parameters)[i] : rangefe.prm;
+ params.push(new Parameter(p.storageClass, p.type, p.ident, null, null));
+ }
+ }
+ Expression[2] res;
+ TypeStruct tplty = null;
+ if (nvars == 1) // only one `static foreach` variable, generate identifiers.
+ {
+ foreach (i; 0 .. 2)
+ {
+ res[i] = new IdentifierExp(aloc, (*pparams[i])[0].ident);
+ }
+ }
+ else // multiple `static foreach` variables, generate tuples.
+ {
+ foreach (i; 0 .. 2)
+ {
+ auto e = new Expressions(pparams[0].dim);
+ foreach (j, ref elem; *e)
+ {
+ auto p = (*pparams[i])[j];
+ elem = new IdentifierExp(aloc, p.ident);
+ }
+ if (!tplty)
+ {
+ tplty = createTupleType(aloc, e, sc);
+ }
+ res[i] = createTuple(aloc, tplty, e);
+ }
+ needExpansion = true; // need to expand the tuples later
+ }
+ // generate remaining code for the new aggregate which is an
+ // array (see documentation comment).
+ if (rangefe)
+ {
+ sc = sc.startCTFE();
+ rangefe.lwr = rangefe.lwr.expressionSemantic(sc);
+ rangefe.lwr = resolveProperties(sc, rangefe.lwr);
+ rangefe.upr = rangefe.upr.expressionSemantic(sc);
+ rangefe.upr = resolveProperties(sc, rangefe.upr);
+ sc = sc.endCTFE();
+ rangefe.lwr = rangefe.lwr.optimize(WANTvalue);
+ rangefe.lwr = rangefe.lwr.ctfeInterpret();
+ rangefe.upr = rangefe.upr.optimize(WANTvalue);
+ rangefe.upr = rangefe.upr.ctfeInterpret();
+ }
+ auto s1 = new Statements();
+ auto sfe = new Statements();
+ if (tplty) sfe.push(new ExpStatement(loc, tplty.sym));
+ sfe.push(new ReturnStatement(aloc, res[0]));
+ s1.push(createForeach(aloc, pparams[0], new CompoundStatement(aloc, sfe)));
+ s1.push(new ExpStatement(aloc, new AssertExp(aloc, IntegerExp.literal!0)));
+ Type ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
+ auto aty = ety.arrayOf();
+ auto idres = Identifier.generateId("__res");
+ auto vard = new VarDeclaration(aloc, aty, idres, null);
+ auto s2 = new Statements();
+
+ // Run 'typeof' gagged to avoid duplicate errors and if it fails just create
+ // an empty foreach to expose them.
+ uint olderrors = global.startGagging();
+ ety = ety.typeSemantic(aloc, sc);
+ if (global.endGagging(olderrors))
+ s2.push(createForeach(aloc, pparams[1], null));
+ else
+ {
+ s2.push(new ExpStatement(aloc, vard));
+ auto catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
+ s2.push(createForeach(aloc, pparams[1], new ExpStatement(aloc, catass)));
+ s2.push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
+ }
+
+ Expression aggr = void;
+ Type indexty = void;
+
+ if (rangefe && (indexty = ety).isintegral())
+ {
+ rangefe.lwr.type = indexty;
+ rangefe.upr.type = indexty;
+ auto lwrRange = getIntRange(rangefe.lwr);
+ auto uprRange = getIntRange(rangefe.upr);
+
+ const lwr = rangefe.lwr.toInteger();
+ auto upr = rangefe.upr.toInteger();
+ size_t length = 0;
+
+ if (lwrRange.imin <= uprRange.imax)
+ length = cast(size_t) (upr - lwr);
+
+ auto exps = new Expressions(length);
+
+ if (rangefe.op == TOK.foreach_)
+ {
+ foreach (i; 0 .. length)
+ (*exps)[i] = new IntegerExp(aloc, lwr + i, indexty);
+ }
+ else
+ {
+ --upr;
+ foreach (i; 0 .. length)
+ (*exps)[i] = new IntegerExp(aloc, upr - i, indexty);
+ }
+ aggr = new ArrayLiteralExp(aloc, indexty.arrayOf(), exps);
+ }
+ else
+ {
+ aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2));
+ sc = sc.startCTFE();
+ aggr = aggr.expressionSemantic(sc);
+ aggr = resolveProperties(sc, aggr);
+ sc = sc.endCTFE();
+ aggr = aggr.optimize(WANTvalue);
+ aggr = aggr.ctfeInterpret();
+ }
+
+ assert(!!aggrfe ^ !!rangefe);
+ aggrfe = new ForeachStatement(loc, TOK.foreach_, pparams[2], aggr,
+ aggrfe ? aggrfe._body : rangefe._body,
+ aggrfe ? aggrfe.endloc : rangefe.endloc);
+ rangefe = null;
+ lowerArrayAggregate(sc); // finally, turn generated array into expression tuple
+ }
+
+ /*****************************************
+ * Perform `static foreach` lowerings that are necessary in order
+ * to finally expand the `static foreach` using
+ * `dmd.statementsem.makeTupleForeach`.
+ */
+ extern(D) void prepare(Scope* sc)
+ {
+ assert(sc);
+
+ if (aggrfe)
+ {
+ sc = sc.startCTFE();
+ aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
+ sc = sc.endCTFE();
+ aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue);
+ }
+
+ if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Terror)
+ {
+ return;
+ }
+
+ if (!ready())
+ {
+ if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Tarray)
+ {
+ lowerArrayAggregate(sc);
+ }
+ else
+ {
+ lowerNonArrayAggregate(sc);
+ }
+ }
+ }
+
+ /*****************************************
+ * Returns:
+ * `true` iff ready to call `dmd.statementsem.makeTupleForeach`.
+ */
+ extern(D) bool ready()
+ {
+ return aggrfe && aggrfe.aggr && aggrfe.aggr.type && aggrfe.aggr.type.toBasetype().ty == Ttuple;
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) class DVCondition : Condition
+{
+ uint level;
+ Identifier ident;
+ Module mod;
+
+ extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident)
+ {
+ super(loc);
+ this.mod = mod;
+ this.level = level;
+ this.ident = ident;
+ }
+
+ override final DVCondition syntaxCopy()
+ {
+ return this; // don't need to copy
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DebugCondition : DVCondition
+{
+ /**
+ * Add an user-supplied identifier to the list of global debug identifiers
+ *
+ * Can be called from either the driver or a `debug = Ident;` statement.
+ * Unlike version identifier, there isn't any reserved debug identifier
+ * so no validation takes place.
+ *
+ * Params:
+ * ident = identifier to add
+ */
+ deprecated("Kept for C++ compat - Use the string overload instead")
+ static void addGlobalIdent(const(char)* ident)
+ {
+ addGlobalIdent(ident[0 .. ident.strlen]);
+ }
+
+ /// Ditto
+ extern(D) static void addGlobalIdent(string ident)
+ {
+ // Overload necessary for string literals
+ addGlobalIdent(cast(const(char)[])ident);
+ }
+
+
+ /// Ditto
+ extern(D) static void addGlobalIdent(const(char)[] ident)
+ {
+ if (!global.debugids)
+ global.debugids = new Identifiers();
+ global.debugids.push(Identifier.idPool(ident));
+ }
+
+
+ /**
+ * Instantiate a new `DebugCondition`
+ *
+ * Params:
+ * mod = Module this node belongs to
+ * level = Minimum global level this condition needs to pass.
+ * Only used if `ident` is `null`.
+ * ident = Identifier required for this condition to pass.
+ * If `null`, this conditiion will use an integer level.
+ * loc = Location in the source file
+ */
+ extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident)
+ {
+ super(loc, mod, level, ident);
+ }
+
+ override int include(Scope* sc)
+ {
+ //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
+ if (inc == Include.notComputed)
+ {
+ inc = Include.no;
+ bool definedInModule = false;
+ if (ident)
+ {
+ if (findCondition(mod.debugids, ident))
+ {
+ inc = Include.yes;
+ definedInModule = true;
+ }
+ else if (findCondition(global.debugids, ident))
+ inc = Include.yes;
+ else
+ {
+ if (!mod.debugidsNot)
+ mod.debugidsNot = new Identifiers();
+ mod.debugidsNot.push(ident);
+ }
+ }
+ else if (level <= global.params.debuglevel || level <= mod.debuglevel)
+ inc = Include.yes;
+ if (!definedInModule)
+ printDepsConditional(sc, this, "depsDebug ");
+ }
+ return (inc == Include.yes);
+ }
+
+ override inout(DebugCondition) isDebugCondition() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ override const(char)* toChars() const
+ {
+ return ident ? ident.toChars() : "debug".ptr;
+ }
+}
+
+/**
+ * Node to represent a version condition
+ *
+ * A version condition is of the form:
+ * ---
+ * version (Identifier)
+ * ---
+ * In user code.
+ * This class also provides means to add version identifier
+ * to the list of global (cross module) identifiers.
+ */
+extern (C++) final class VersionCondition : DVCondition
+{
+ /**
+ * Check if a given version identifier is reserved.
+ *
+ * Params:
+ * ident = identifier being checked
+ *
+ * Returns:
+ * `true` if it is reserved, `false` otherwise
+ */
+ extern(D) private static bool isReserved(const(char)[] ident)
+ {
+ // This list doesn't include "D_*" versions, see the last return
+ switch (ident)
+ {
+ case "AArch64":
+ case "AIX":
+ case "all":
+ case "Alpha":
+ case "Alpha_HardFloat":
+ case "Alpha_SoftFloat":
+ case "Android":
+ case "ARM":
+ case "ARM_HardFloat":
+ case "ARM_SoftFloat":
+ case "ARM_SoftFP":
+ case "ARM_Thumb":
+ case "AsmJS":
+ case "assert":
+ case "AVR":
+ case "BigEndian":
+ case "BSD":
+ case "CppRuntime_Clang":
+ case "CppRuntime_DigitalMars":
+ case "CppRuntime_Gcc":
+ case "CppRuntime_Microsoft":
+ case "CppRuntime_Sun":
+ case "CRuntime_Bionic":
+ case "CRuntime_DigitalMars":
+ case "CRuntime_Glibc":
+ case "CRuntime_Microsoft":
+ case "CRuntime_Musl":
+ case "CRuntime_Newlib":
+ case "CRuntime_UClibc":
+ case "CRuntime_WASI":
+ case "Cygwin":
+ case "DigitalMars":
+ case "DragonFlyBSD":
+ case "Emscripten":
+ case "ELFv1":
+ case "ELFv2":
+ case "Epiphany":
+ case "FreeBSD":
+ case "FreeStanding":
+ case "GNU":
+ case "Haiku":
+ case "HPPA":
+ case "HPPA64":
+ case "Hurd":
+ case "IA64":
+ case "iOS":
+ case "LDC":
+ case "linux":
+ case "LittleEndian":
+ case "MinGW":
+ case "MIPS32":
+ case "MIPS64":
+ case "MIPS_EABI":
+ case "MIPS_HardFloat":
+ case "MIPS_N32":
+ case "MIPS_N64":
+ case "MIPS_O32":
+ case "MIPS_O64":
+ case "MIPS_SoftFloat":
+ case "MSP430":
+ case "NetBSD":
+ case "none":
+ case "NVPTX":
+ case "NVPTX64":
+ case "OpenBSD":
+ case "OSX":
+ case "PlayStation":
+ case "PlayStation4":
+ case "Posix":
+ case "PPC":
+ case "PPC64":
+ case "PPC_HardFloat":
+ case "PPC_SoftFloat":
+ case "RISCV32":
+ case "RISCV64":
+ case "S390":
+ case "S390X":
+ case "SDC":
+ case "SH":
+ case "SkyOS":
+ case "Solaris":
+ case "SPARC":
+ case "SPARC64":
+ case "SPARC_HardFloat":
+ case "SPARC_SoftFloat":
+ case "SPARC_V8Plus":
+ case "SystemZ":
+ case "SysV3":
+ case "SysV4":
+ case "TVOS":
+ case "unittest":
+ case "WASI":
+ case "WatchOS":
+ case "WebAssembly":
+ case "Win32":
+ case "Win64":
+ case "Windows":
+ case "X86":
+ case "X86_64":
+ return true;
+
+ default:
+ // Anything that starts with "D_" is reserved
+ return (ident.length >= 2 && ident[0 .. 2] == "D_");
+ }
+ }
+
+ /**
+ * Raises an error if a version identifier is reserved.
+ *
+ * Called when setting a version identifier, e.g. `-version=identifier`
+ * parameter to the compiler or `version = Foo` in user code.
+ *
+ * Params:
+ * loc = Where the identifier is set
+ * ident = identifier being checked (ident[$] must be '\0')
+ */
+ extern(D) static void checkReserved(const ref Loc loc, const(char)[] ident)
+ {
+ if (isReserved(ident))
+ error(loc, "version identifier `%s` is reserved and cannot be set",
+ ident.ptr);
+ }
+
+ /**
+ * Add an user-supplied global identifier to the list
+ *
+ * Only called from the driver for `-version=Ident` parameters.
+ * Will raise an error if the identifier is reserved.
+ *
+ * Params:
+ * ident = identifier to add
+ */
+ deprecated("Kept for C++ compat - Use the string overload instead")
+ static void addGlobalIdent(const(char)* ident)
+ {
+ addGlobalIdent(ident[0 .. ident.strlen]);
+ }
+
+ /// Ditto
+ extern(D) static void addGlobalIdent(string ident)
+ {
+ // Overload necessary for string literals
+ addGlobalIdent(cast(const(char)[])ident);
+ }
+
+
+ /// Ditto
+ extern(D) static void addGlobalIdent(const(char)[] ident)
+ {
+ checkReserved(Loc.initial, ident);
+ addPredefinedGlobalIdent(ident);
+ }
+
+ /**
+ * Add any global identifier to the list, without checking
+ * if it's predefined
+ *
+ * Only called from the driver after platform detection,
+ * and internally.
+ *
+ * Params:
+ * ident = identifier to add (ident[$] must be '\0')
+ */
+ deprecated("Kept for C++ compat - Use the string overload instead")
+ static void addPredefinedGlobalIdent(const(char)* ident)
+ {
+ addPredefinedGlobalIdent(ident.toDString());
+ }
+
+ /// Ditto
+ extern(D) static void addPredefinedGlobalIdent(string ident)
+ {
+ // Forward: Overload necessary for string literal
+ addPredefinedGlobalIdent(cast(const(char)[])ident);
+ }
+
+
+ /// Ditto
+ extern(D) static void addPredefinedGlobalIdent(const(char)[] ident)
+ {
+ if (!global.versionids)
+ global.versionids = new Identifiers();
+ global.versionids.push(Identifier.idPool(ident));
+ }
+
+ /**
+ * Instantiate a new `VersionCondition`
+ *
+ * Params:
+ * mod = Module this node belongs to
+ * level = Minimum global level this condition needs to pass.
+ * Only used if `ident` is `null`.
+ * ident = Identifier required for this condition to pass.
+ * If `null`, this conditiion will use an integer level.
+ * loc = Location in the source file
+ */
+ extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident)
+ {
+ super(loc, mod, level, ident);
+ }
+
+ override int include(Scope* sc)
+ {
+ //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
+ //if (ident) printf("\tident = '%s'\n", ident.toChars());
+ if (inc == Include.notComputed)
+ {
+ inc = Include.no;
+ bool definedInModule = false;
+ if (ident)
+ {
+ if (findCondition(mod.versionids, ident))
+ {
+ inc = Include.yes;
+ definedInModule = true;
+ }
+ else if (findCondition(global.versionids, ident))
+ inc = Include.yes;
+ else
+ {
+ if (!mod.versionidsNot)
+ mod.versionidsNot = new Identifiers();
+ mod.versionidsNot.push(ident);
+ }
+ }
+ else if (level <= global.params.versionlevel || level <= mod.versionlevel)
+ inc = Include.yes;
+ if (!definedInModule &&
+ (!ident || (!isReserved(ident.toString()) && ident != Id._unittest && ident != Id._assert)))
+ {
+ printDepsConditional(sc, this, "depsVersion ");
+ }
+ }
+ return (inc == Include.yes);
+ }
+
+ override inout(VersionCondition) isVersionCondition() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ override const(char)* toChars() const
+ {
+ return ident ? ident.toChars() : "version".ptr;
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class StaticIfCondition : Condition
+{
+ Expression exp;
+
+ extern (D) this(const ref Loc loc, Expression exp)
+ {
+ super(loc);
+ this.exp = exp;
+ }
+
+ override StaticIfCondition syntaxCopy()
+ {
+ return new StaticIfCondition(loc, exp.syntaxCopy());
+ }
+
+ override int include(Scope* sc)
+ {
+ // printf("StaticIfCondition::include(sc = %p) this=%p inc = %d\n", sc, this, inc);
+
+ int errorReturn()
+ {
+ if (!global.gag)
+ inc = Include.no; // so we don't see the error message again
+ return 0;
+ }
+
+ if (inc == Include.notComputed)
+ {
+ if (!sc)
+ {
+ error(loc, "`static if` conditional cannot be at global scope");
+ inc = Include.no;
+ return 0;
+ }
+
+ import dmd.staticcond;
+ bool errors;
+
+ if (!exp)
+ return errorReturn();
+
+ bool result = evalStaticCondition(sc, exp, exp, errors);
+
+ // Prevent repeated condition evaluation.
+ // See: fail_compilation/fail7815.d
+ if (inc != Include.notComputed)
+ return (inc == Include.yes);
+ if (errors)
+ return errorReturn();
+ if (result)
+ inc = Include.yes;
+ else
+ inc = Include.no;
+ }
+ return (inc == Include.yes);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ override const(char)* toChars() const
+ {
+ return exp ? exp.toChars() : "static if".ptr;
+ }
+}
+
+
+/****************************************
+ * Find `ident` in an array of identifiers.
+ * Params:
+ * ids = array of identifiers
+ * ident = identifier to search for
+ * Returns:
+ * true if found
+ */
+bool findCondition(Identifiers* ids, Identifier ident) @safe nothrow pure
+{
+ if (ids)
+ {
+ foreach (id; *ids)
+ {
+ if (id == ident)
+ return true;
+ }
+ }
+ return false;
+}
+
+// Helper for printing dependency information
+private void printDepsConditional(Scope* sc, DVCondition condition, const(char)[] depType)
+{
+ if (!global.params.moduleDeps || global.params.moduleDepsFile)
+ return;
+ OutBuffer* ob = global.params.moduleDeps;
+ Module imod = sc ? sc._module : condition.mod;
+ if (!imod)
+ return;
+ ob.writestring(depType);
+ ob.writestring(imod.toPrettyChars());
+ ob.writestring(" (");
+ escapePath(ob, imod.srcfile.toChars());
+ ob.writestring(") : ");
+ if (condition.ident)
+ ob.writestring(condition.ident.toString());
+ else
+ ob.print(condition.level);
+ ob.writeByte('\n');
+}
diff --git a/gcc/d/dmd/cond.h b/gcc/d/dmd/cond.h
index 593a98d..4f26116 100644
--- a/gcc/d/dmd/cond.h
+++ b/gcc/d/dmd/cond.h
@@ -16,26 +16,24 @@
class Expression;
class Identifier;
-struct OutBuffer;
class Module;
struct Scope;
-class ScopeDsymbol;
class DebugCondition;
class ForeachStatement;
class ForeachRangeStatement;
-int findCondition(Identifiers *ids, Identifier *ident);
+enum Include
+{
+ INCLUDEnotComputed, /// not computed yet
+ INCLUDEyes, /// include the conditional code
+ INCLUDEno /// do not include the conditional code
+};
class Condition : public ASTNode
{
public:
Loc loc;
- // 0: not computed yet
- // 1: include
- // 2: do not include
- int inc;
-
- Condition(Loc loc);
+ Include inc;
virtual Condition *syntaxCopy() = 0;
virtual int include(Scope *sc) = 0;
@@ -54,13 +52,9 @@ public:
bool needExpansion;
- StaticForeach(Loc loc, ForeachStatement *aggrfe, ForeachRangeStatement *rangefe);
StaticForeach *syntaxCopy();
};
-void staticForeachPrepare(StaticForeach *sfe, Scope *sc);
-bool staticForeachReady(StaticForeach *sfe);
-
class DVCondition : public Condition
{
public:
@@ -68,9 +62,7 @@ public:
Identifier *ident;
Module *mod;
- DVCondition(Module *mod, unsigned level, Identifier *ident);
-
- Condition *syntaxCopy();
+ DVCondition *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -79,8 +71,6 @@ class DebugCondition : public DVCondition
public:
static void addGlobalIdent(const char *ident);
- DebugCondition(Module *mod, unsigned level, Identifier *ident);
-
int include(Scope *sc);
DebugCondition *isDebugCondition() { return this; }
void accept(Visitor *v) { v->visit(this); }
@@ -92,8 +82,6 @@ public:
static void addGlobalIdent(const char *ident);
static void addPredefinedGlobalIdent(const char *ident);
- VersionCondition(Module *mod, unsigned level, Identifier *ident);
-
int include(Scope *sc);
VersionCondition *isVersionCondition() { return this; }
void accept(Visitor *v) { v->visit(this); }
@@ -104,8 +92,7 @@ class StaticIfCondition : public Condition
public:
Expression *exp;
- StaticIfCondition(Loc loc, Expression *exp);
- Condition *syntaxCopy();
+ StaticIfCondition *syntaxCopy();
int include(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
diff --git a/gcc/d/dmd/constfold.c b/gcc/d/dmd/constfold.c
deleted file mode 100644
index 8cfeac5..0000000
--- a/gcc/d/dmd/constfold.c
+++ /dev/null
@@ -1,1922 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/constfold.c
- */
-
-#include "root/dsystem.h" // mem{cpy|set|cmp}()
-
-#ifndef IN_GCC
-#include <math.h>
-#endif
-
-#include "root/rmem.h"
-#include "root/root.h"
-#include "root/port.h"
-
-#include "errors.h"
-#include "mtype.h"
-#include "expression.h"
-#include "aggregate.h"
-#include "declaration.h"
-#include "utf.h"
-#include "ctfe.h"
-#include "target.h"
-
-int RealEquals(real_t x1, real_t x2);
-
-Expression *expType(Type *type, Expression *e)
-{
- if (type != e->type)
- {
- e = e->copy();
- e->type = type;
- }
- return e;
-}
-
-/* ================================== isConst() ============================== */
-
-int isConst(Expression *e)
-{
- //printf("Expression::isConst(): %s\n", e->toChars());
- switch (e->op)
- {
- case TOKint64:
- case TOKfloat64:
- case TOKcomplex80:
- return 1;
- case TOKnull:
- return 0;
- case TOKsymoff:
- return 2;
- default:
- return 0;
- }
- assert(0);
- return 0;
-}
-
-/* =============================== constFold() ============================== */
-
-/* The constFold() functions were redundant with the optimize() ones,
- * and so have been folded in with them.
- */
-
-/* ========================================================================== */
-
-UnionExp Neg(Type *type, Expression *e1)
-{
- UnionExp ue;
- Loc loc = e1->loc;
-
- if (e1->type->isreal())
- {
- new(&ue) RealExp(loc, -e1->toReal(), type);
- }
- else if (e1->type->isimaginary())
- {
- new(&ue) RealExp(loc, -e1->toImaginary(), type);
- }
- else if (e1->type->iscomplex())
- {
- new(&ue) ComplexExp(loc, -e1->toComplex(), type);
- }
- else
- {
- new(&ue) IntegerExp(loc, -e1->toInteger(), type);
- }
- return ue;
-}
-
-UnionExp Com(Type *type, Expression *e1)
-{
- UnionExp ue;
- Loc loc = e1->loc;
-
- new(&ue) IntegerExp(loc, ~e1->toInteger(), type);
- return ue;
-}
-
-UnionExp Not(Type *type, Expression *e1)
-{
- UnionExp ue;
- Loc loc = e1->loc;
-
- new(&ue) IntegerExp(loc, e1->isBool(false) ? 1 : 0, type);
- return ue;
-}
-
-UnionExp Bool(Type *type, Expression *e1)
-{
- UnionExp ue;
- Loc loc = e1->loc;
-
- new(&ue) IntegerExp(loc, e1->isBool(true) ? 1 : 0, type);
- return ue;
-}
-
-UnionExp Add(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
-
- if (type->isreal())
- {
- new(&ue) RealExp(loc, e1->toReal() + e2->toReal(), type);
- }
- else if (type->isimaginary())
- {
- new(&ue) RealExp(loc, e1->toImaginary() + e2->toImaginary(), type);
- }
- else if (type->iscomplex())
- {
- // This rigamarole is necessary so that -0.0 doesn't get
- // converted to +0.0 by doing an extraneous add with +0.0
- complex_t c1 = complex_t(CTFloat::zero);
- real_t r1 = CTFloat::zero;
- real_t i1 = CTFloat::zero;
-
- complex_t c2 = complex_t(CTFloat::zero);
- real_t r2 = CTFloat::zero;
- real_t i2 = CTFloat::zero;
-
- complex_t v = complex_t(CTFloat::zero);
- int x;
-
- if (e1->type->isreal())
- {
- r1 = e1->toReal();
- x = 0;
- }
- else if (e1->type->isimaginary())
- {
- i1 = e1->toImaginary();
- x = 3;
- }
- else
- {
- c1 = e1->toComplex();
- x = 6;
- }
-
- if (e2->type->isreal())
- {
- r2 = e2->toReal();
- }
- else if (e2->type->isimaginary())
- {
- i2 = e2->toImaginary();
- x += 1;
- }
- else
- {
- c2 = e2->toComplex();
- x += 2;
- }
-
- switch (x)
- {
- case 0 + 0:
- v = complex_t(r1 + r2);
- break;
- case 0 + 1:
- v = complex_t(r1, i2);
- break;
- case 0 + 2:
- v = complex_t(r1 + creall(c2), cimagl(c2));
- break;
- case 3 + 0:
- v = complex_t(r2, i1);
- break;
- case 3 + 1:
- v = complex_t(CTFloat::zero, i1 + i2);
- break;
- case 3 + 2:
- v = complex_t(creall(c2), i1 + cimagl(c2));
- break;
- case 6 + 0:
- v = complex_t(creall(c1) + r2, cimagl(c2));
- break;
- case 6 + 1:
- v = complex_t(creall(c1), cimagl(c1) + i2);
- break;
- case 6 + 2:
- v = c1 + c2;
- break;
- default:
- assert(0);
- }
- new(&ue) ComplexExp(loc, v, type);
- }
- else if (e1->op == TOKsymoff)
- {
- SymOffExp *soe = (SymOffExp *)e1;
- new(&ue) SymOffExp(loc, soe->var, soe->offset + e2->toInteger());
- ue.exp()->type = type;
- }
- else if (e2->op == TOKsymoff)
- {
- SymOffExp *soe = (SymOffExp *)e2;
- new(&ue) SymOffExp(loc, soe->var, soe->offset + e1->toInteger());
- ue.exp()->type = type;
- }
- else
- new(&ue) IntegerExp(loc, e1->toInteger() + e2->toInteger(), type);
- return ue;
-}
-
-
-UnionExp Min(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
-
- if (type->isreal())
- {
- new(&ue) RealExp(loc, e1->toReal() - e2->toReal(), type);
- }
- else if (type->isimaginary())
- {
- new(&ue) RealExp(loc, e1->toImaginary() - e2->toImaginary(), type);
- }
- else if (type->iscomplex())
- {
- // This rigamarole is necessary so that -0.0 doesn't get
- // converted to +0.0 by doing an extraneous add with +0.0
- complex_t c1 = complex_t(CTFloat::zero);
- real_t r1 = CTFloat::zero;
- real_t i1 = CTFloat::zero;
-
- complex_t c2 = complex_t(CTFloat::zero);
- real_t r2 = CTFloat::zero;
- real_t i2 = CTFloat::zero;
-
- complex_t v = complex_t(CTFloat::zero);
- int x;
-
- if (e1->type->isreal())
- {
- r1 = e1->toReal();
- x = 0;
- }
- else if (e1->type->isimaginary())
- {
- i1 = e1->toImaginary();
- x = 3;
- }
- else
- {
- c1 = e1->toComplex();
- x = 6;
- }
-
- if (e2->type->isreal())
- {
- r2 = e2->toReal();
- }
- else if (e2->type->isimaginary())
- {
- i2 = e2->toImaginary();
- x += 1;
- }
- else
- {
- c2 = e2->toComplex();
- x += 2;
- }
-
- switch (x)
- {
- case 0 + 0:
- v = complex_t(r1 - r2);
- break;
- case 0 + 1:
- v = complex_t(r1, -i2);
- break;
- case 0 + 2:
- v = complex_t(r1 - creall(c2), -cimagl(c2));
- break;
- case 3 + 0:
- v = complex_t(-r2, i1);
- break;
- case 3 + 1:
- v = complex_t(CTFloat::zero, i1 - i2);
- break;
- case 3 + 2:
- v = complex_t(-creall(c2), i1 - cimagl(c2));
- break;
- case 6 + 0:
- v = complex_t(creall(c1) - r2, cimagl(c1));
- break;
- case 6 + 1:
- v = complex_t(creall(c1), cimagl(c1) - i2);
- break;
- case 6 + 2:
- v = c1 - c2;
- break;
- default:
- assert(0);
- }
- new(&ue) ComplexExp(loc, v, type);
- }
- else if (e1->op == TOKsymoff)
- {
- SymOffExp *soe = (SymOffExp *)e1;
- new(&ue) SymOffExp(loc, soe->var, soe->offset - e2->toInteger());
- ue.exp()->type = type;
- }
- else
- {
- new(&ue) IntegerExp(loc, e1->toInteger() - e2->toInteger(), type);
- }
- return ue;
-}
-
-UnionExp Mul(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
-
- if (type->isfloating())
- {
- complex_t c = complex_t(CTFloat::zero);
- real_t r;
-
- if (e1->type->isreal())
- {
- r = e1->toReal();
- c = e2->toComplex();
- c = complex_t(r * creall(c), r * cimagl(c));
- }
- else if (e1->type->isimaginary())
- {
- r = e1->toImaginary();
- c = e2->toComplex();
- c = complex_t(-r * cimagl(c), r * creall(c));
- }
- else if (e2->type->isreal())
- {
- r = e2->toReal();
- c = e1->toComplex();
- c = complex_t(r * creall(c), r * cimagl(c));
- }
- else if (e2->type->isimaginary())
- {
- r = e2->toImaginary();
- c = e1->toComplex();
- c = complex_t(-r * cimagl(c), r * creall(c));
- }
- else
- c = e1->toComplex() * e2->toComplex();
-
- if (type->isreal())
- new(&ue) RealExp(loc, creall(c), type);
- else if (type->isimaginary())
- new(&ue) RealExp(loc, cimagl(c), type);
- else if (type->iscomplex())
- new(&ue) ComplexExp(loc, c, type);
- else
- assert(0);
- }
- else
- {
- new(&ue) IntegerExp(loc, e1->toInteger() * e2->toInteger(), type);
- }
- return ue;
-}
-
-UnionExp Div(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
-
- if (type->isfloating())
- {
- complex_t c = complex_t(CTFloat::zero);
- real_t r;
-
- //e1->type->print();
- //e2->type->print();
- if (e2->type->isreal())
- {
- if (e1->type->isreal())
- {
- new(&ue) RealExp(loc, e1->toReal() / e2->toReal(), type);
- return ue;
- }
- r = e2->toReal();
- c = e1->toComplex();
- c = complex_t(creall(c) / r, cimagl(c) / r);
- }
- else if (e2->type->isimaginary())
- {
- r = e2->toImaginary();
- c = e1->toComplex();
- c = complex_t(cimagl(c) / r, -creall(c) / r);
- }
- else
- {
- c = e1->toComplex() / e2->toComplex();
- }
-
- if (type->isreal())
- new(&ue) RealExp(loc, creall(c), type);
- else if (type->isimaginary())
- new(&ue) RealExp(loc, cimagl(c), type);
- else if (type->iscomplex())
- new(&ue) ComplexExp(loc, c, type);
- else
- assert(0);
- }
- else
- {
- sinteger_t n1;
- sinteger_t n2;
- sinteger_t n;
-
- n1 = e1->toInteger();
- n2 = e2->toInteger();
- if (n2 == 0)
- {
- e2->error("divide by 0");
- new(&ue) ErrorExp();
- return ue;
- }
- if (n2 == -1 && !type->isunsigned())
- {
- // Check for int.min / -1
- if ((dinteger_t)n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64)
- {
- e2->error("integer overflow: int.min / -1");
- new(&ue) ErrorExp();
- return ue;
- }
- else if ((dinteger_t)n1 == 0x8000000000000000LL) // long.min / -1
- {
- e2->error("integer overflow: long.min / -1");
- new(&ue) ErrorExp();
- return ue;
- }
- }
- if (e1->type->isunsigned() || e2->type->isunsigned())
- n = ((dinteger_t) n1) / ((dinteger_t) n2);
- else
- n = n1 / n2;
- new(&ue) IntegerExp(loc, n, type);
- }
- return ue;
-}
-
-UnionExp Mod(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
-
- if (type->isfloating())
- {
- complex_t c = complex_t(CTFloat::zero);
-
- if (e2->type->isreal())
- {
- real_t r2 = e2->toReal();
-
-#ifdef IN_GCC
- c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2);
-#else
- c = complex_t(::fmodl(e1->toReal(), r2), ::fmodl(e1->toImaginary(), r2));
-#endif
- }
- else if (e2->type->isimaginary())
- {
- real_t i2 = e2->toImaginary();
-
-#ifdef IN_GCC
- c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2);
-#else
- c = complex_t(::fmodl(e1->toReal(), i2), ::fmodl(e1->toImaginary(), i2));
-#endif
- }
- else
- assert(0);
-
- if (type->isreal())
- new(&ue) RealExp(loc, creall(c), type);
- else if (type->isimaginary())
- new(&ue) RealExp(loc, cimagl(c), type);
- else if (type->iscomplex())
- new(&ue) ComplexExp(loc, c, type);
- else
- assert(0);
- }
- else
- {
- sinteger_t n1;
- sinteger_t n2;
- sinteger_t n;
-
- n1 = e1->toInteger();
- n2 = e2->toInteger();
- if (n2 == 0)
- {
- e2->error("divide by 0");
- new(&ue) ErrorExp();
- return ue;
- }
- if (n2 == -1 && !type->isunsigned())
- {
- // Check for int.min % -1
- if ((dinteger_t)n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64)
- {
- e2->error("integer overflow: int.min %% -1");
- new(&ue) ErrorExp();
- return ue;
- }
- else if ((dinteger_t)n1 == 0x8000000000000000LL) // long.min % -1
- {
- e2->error("integer overflow: long.min %% -1");
- new(&ue) ErrorExp();
- return ue;
- }
- }
- if (e1->type->isunsigned() || e2->type->isunsigned())
- n = ((dinteger_t) n1) % ((dinteger_t) n2);
- else
- n = n1 % n2;
- new(&ue) IntegerExp(loc, n, type);
- }
- return ue;
-}
-
-UnionExp Pow(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
-
- // Handle integer power operations.
- if (e2->type->isintegral())
- {
- dinteger_t n = e2->toInteger();
- bool neg;
-
- if (!e2->type->isunsigned() && (sinteger_t)n < 0)
- {
- if (e1->type->isintegral())
- {
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
- }
-
- // Don't worry about overflow, from now on n is unsigned.
- neg = true;
- n = -n;
- }
- else
- neg = false;
-
- UnionExp ur, uv;
- if (e1->type->iscomplex())
- {
- new(&ur) ComplexExp(loc, e1->toComplex(), e1->type);
- new(&uv) ComplexExp(loc, complex_t(CTFloat::one), e1->type);
- }
- else if (e1->type->isfloating())
- {
- new(&ur) RealExp(loc, e1->toReal(), e1->type);
- new(&uv) RealExp(loc, CTFloat::one, e1->type);
- }
- else
- {
- new(&ur) IntegerExp(loc, e1->toInteger(), e1->type);
- new(&uv) IntegerExp(loc, 1, e1->type);
- }
-
- Expression* r = ur.exp();
- Expression* v = uv.exp();
- while (n != 0)
- {
- if (n & 1)
- {
- // v = v * r;
- uv = Mul(loc, v->type, v, r);
- }
- n >>= 1;
- // r = r * r
- ur = Mul(loc, r->type, r, r);
- }
-
- if (neg)
- {
- // ue = 1.0 / v
- UnionExp one;
- new(&one) RealExp(loc, CTFloat::one, v->type);
- uv = Div(loc, v->type, one.exp(), v);
- }
-
- if (type->iscomplex())
- new(&ue) ComplexExp(loc, v->toComplex(), type);
- else if (type->isintegral())
- new(&ue) IntegerExp(loc, v->toInteger(), type);
- else
- new(&ue) RealExp(loc, v->toReal(), type);
- }
- else if (e2->type->isfloating())
- {
- // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
- if (e1->toReal() < CTFloat::zero)
- {
- new(&ue) RealExp(loc, target.RealProperties.nan, type);
- }
- else
- new(&ue) CTFEExp(TOKcantexp);
- }
- else
- new(&ue) CTFEExp(TOKcantexp);
-
- return ue;
-}
-
-UnionExp Shl(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
- new(&ue) IntegerExp(loc, e1->toInteger() << e2->toInteger(), type);
- return ue;
-}
-
-UnionExp Shr(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
- dinteger_t value = e1->toInteger();
- dinteger_t dcount = e2->toInteger();
- assert(dcount <= 0xFFFFFFFF);
- unsigned count = (unsigned)dcount;
- switch (e1->type->toBasetype()->ty)
- {
- case Tint8:
- value = (d_int8)(value) >> count;
- break;
-
- case Tuns8:
- case Tchar:
- value = (d_uns8)(value) >> count;
- break;
-
- case Tint16:
- value = (d_int16)(value) >> count;
- break;
-
- case Tuns16:
- case Twchar:
- value = (d_uns16)(value) >> count;
- break;
-
- case Tint32:
- value = (d_int32)(value) >> count;
- break;
-
- case Tuns32:
- case Tdchar:
- value = (d_uns32)(value) >> count;
- break;
-
- case Tint64:
- value = (d_int64)(value) >> count;
- break;
-
- case Tuns64:
- value = (d_uns64)(value) >> count;
- break;
-
- case Terror:
- new(&ue) ErrorExp();
- return ue;
-
- default:
- assert(0);
- }
- new(&ue) IntegerExp(loc, value, type);
- return ue;
-}
-
-UnionExp Ushr(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
- dinteger_t value = e1->toInteger();
- dinteger_t dcount = e2->toInteger();
- assert(dcount <= 0xFFFFFFFF);
- unsigned count = (unsigned)dcount;
- switch (e1->type->toBasetype()->ty)
- {
- case Tint8:
- case Tuns8:
- case Tchar:
- // Possible only with >>>=. >>> always gets promoted to int.
- value = (value & 0xFF) >> count;
- break;
-
- case Tint16:
- case Tuns16:
- case Twchar:
- // Possible only with >>>=. >>> always gets promoted to int.
- value = (value & 0xFFFF) >> count;
- break;
-
- case Tint32:
- case Tuns32:
- case Tdchar:
- value = (value & 0xFFFFFFFF) >> count;
- break;
-
- case Tint64:
- case Tuns64:
- value = (d_uns64)(value) >> count;
- break;
-
- case Terror:
- new(&ue) ErrorExp();
- return ue;
-
- default:
- assert(0);
- }
- new(&ue) IntegerExp(loc, value, type);
- return ue;
-}
-
-UnionExp And(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
- new(&ue) IntegerExp(loc, e1->toInteger() & e2->toInteger(), type);
- return ue;
-}
-
-UnionExp Or(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
- new(&ue) IntegerExp(loc, e1->toInteger() | e2->toInteger(), type);
- return ue;
-}
-
-UnionExp Xor(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
- new(&ue) IntegerExp(loc, e1->toInteger() ^ e2->toInteger(), type);
- return ue;
-}
-
-/* Also returns TOKcantexp if cannot be computed.
- */
-UnionExp Equal(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
- int cmp = 0;
- real_t r1;
- real_t r2;
-
- //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
-
- assert(op == TOKequal || op == TOKnotequal);
-
- if (e1->op == TOKnull)
- {
- if (e2->op == TOKnull)
- cmp = 1;
- else if (e2->op == TOKstring)
- {
- StringExp *es2 = (StringExp *)e2;
- cmp = (0 == es2->len);
- }
- else if (e2->op == TOKarrayliteral)
- {
- ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
- cmp = !es2->elements || (0 == es2->elements->length);
- }
- else
- {
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
- }
- }
- else if (e2->op == TOKnull)
- {
- if (e1->op == TOKstring)
- {
- StringExp *es1 = (StringExp *)e1;
- cmp = (0 == es1->len);
- }
- else if (e1->op == TOKarrayliteral)
- {
- ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
- cmp = !es1->elements || (0 == es1->elements->length);
- }
- else
- {
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
- }
- }
- else if (e1->op == TOKstring && e2->op == TOKstring)
- {
- StringExp *es1 = (StringExp *)e1;
- StringExp *es2 = (StringExp *)e2;
-
- if (es1->sz != es2->sz)
- {
- assert(global.errors);
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
- }
- if (es1->len == es2->len &&
- memcmp(es1->string, es2->string, es1->sz * es1->len) == 0)
- cmp = 1;
- else
- cmp = 0;
- }
- else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral)
- {
- ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
- ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
-
- if ((!es1->elements || !es1->elements->length) &&
- (!es2->elements || !es2->elements->length))
- cmp = 1; // both arrays are empty
- else if (!es1->elements || !es2->elements)
- cmp = 0;
- else if (es1->elements->length != es2->elements->length)
- cmp = 0;
- else
- {
- for (size_t i = 0; i < es1->elements->length; i++)
- {
- Expression *ee1 = es1->getElement(i);
- Expression *ee2 = es2->getElement(i);
- ue = Equal(TOKequal, loc, Type::tint32, ee1, ee2);
- if (CTFEExp::isCantExp(ue.exp()))
- return ue;
- cmp = (int)ue.exp()->toInteger();
- if (cmp == 0)
- break;
- }
- }
- }
- else if (e1->op == TOKarrayliteral && e2->op == TOKstring)
- {
- // Swap operands and use common code
- Expression *etmp = e1;
- e1 = e2;
- e2 = etmp;
- goto Lsa;
- }
- else if (e1->op == TOKstring && e2->op == TOKarrayliteral)
- {
- Lsa:
- StringExp *es1 = (StringExp *)e1;
- ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
- size_t dim1 = es1->len;
- size_t dim2 = es2->elements ? es2->elements->length : 0;
- if (dim1 != dim2)
- cmp = 0;
- else
- {
- cmp = 1; // if dim1 winds up being 0
- for (size_t i = 0; i < dim1; i++)
- {
- uinteger_t c = es1->charAt(i);
- Expression *ee2 = es2->getElement(i);
- if (ee2->isConst() != 1)
- {
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
- }
- cmp = (c == ee2->toInteger());
- if (cmp == 0)
- break;
- }
- }
- }
- else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
- {
- StructLiteralExp *es1 = (StructLiteralExp *)e1;
- StructLiteralExp *es2 = (StructLiteralExp *)e2;
-
- if (es1->sd != es2->sd)
- cmp = 0;
- else if ((!es1->elements || !es1->elements->length) &&
- (!es2->elements || !es2->elements->length))
- cmp = 1; // both arrays are empty
- else if (!es1->elements || !es2->elements)
- cmp = 0;
- else if (es1->elements->length != es2->elements->length)
- cmp = 0;
- else
- {
- cmp = 1;
- for (size_t i = 0; i < es1->elements->length; i++)
- {
- Expression *ee1 = (*es1->elements)[i];
- Expression *ee2 = (*es2->elements)[i];
-
- if (ee1 == ee2)
- continue;
- if (!ee1 || !ee2)
- {
- cmp = 0;
- break;
- }
- ue = Equal(TOKequal, loc, Type::tint32, ee1, ee2);
- if (ue.exp()->op == TOKcantexp)
- return ue;
- cmp = (int)ue.exp()->toInteger();
- if (cmp == 0)
- break;
- }
- }
- }
- else if (e1->isConst() != 1 || e2->isConst() != 1)
- {
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
- }
- else if (e1->type->isreal())
- {
- r1 = e1->toReal();
- r2 = e2->toReal();
- goto L1;
- }
- else if (e1->type->isimaginary())
- {
- r1 = e1->toImaginary();
- r2 = e2->toImaginary();
- L1:
- if (CTFloat::isNaN(r1) || CTFloat::isNaN(r2)) // if unordered
- {
- cmp = 0;
- }
- else
- {
- cmp = (r1 == r2);
- }
- }
- else if (e1->type->iscomplex())
- {
- cmp = e1->toComplex() == e2->toComplex();
- }
- else if (e1->type->isintegral() || e1->type->toBasetype()->ty == Tpointer)
- {
- cmp = (e1->toInteger() == e2->toInteger());
- }
- else
- {
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
- }
-
- if (op == TOKnotequal)
- cmp ^= 1;
- new(&ue) IntegerExp(loc, cmp, type);
- return ue;
-}
-
-UnionExp Identity(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
- int cmp;
-
- if (e1->op == TOKnull)
- {
- cmp = (e2->op == TOKnull);
- }
- else if (e2->op == TOKnull)
- {
- cmp = 0;
- }
- else if (e1->op == TOKsymoff && e2->op == TOKsymoff)
- {
- SymOffExp *es1 = (SymOffExp *)e1;
- SymOffExp *es2 = (SymOffExp *)e2;
-
- cmp = (es1->var == es2->var && es1->offset == es2->offset);
- }
- else
- {
- if (e1->type->isreal())
- {
- cmp = RealEquals(e1->toReal(), e2->toReal());
- }
- else if (e1->type->isimaginary())
- {
- cmp = RealEquals(e1->toImaginary(), e2->toImaginary());
- }
- else if (e1->type->iscomplex())
- {
- complex_t v1 = e1->toComplex();
- complex_t v2 = e2->toComplex();
- cmp = RealEquals(creall(v1), creall(v2)) &&
- RealEquals(cimagl(v1), cimagl(v1));
- }
- else
- {
- ue = Equal((op == TOKidentity) ? TOKequal : TOKnotequal, loc, type, e1, e2);
- return ue;
- }
- }
- if (op == TOKnotidentity)
- cmp ^= 1;
- new(&ue) IntegerExp(loc, cmp, type);
- return ue;
-}
-
-
-UnionExp Cmp(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
- dinteger_t n;
- real_t r1;
- real_t r2;
-
- //printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
-
- if (e1->op == TOKstring && e2->op == TOKstring)
- {
- StringExp *es1 = (StringExp *)e1;
- StringExp *es2 = (StringExp *)e2;
- size_t sz = es1->sz;
- assert(sz == es2->sz);
-
- size_t len = es1->len;
- if (es2->len < len)
- len = es2->len;
-
- int rawCmp = memcmp(es1->string, es2->string, sz * len);
- if (rawCmp == 0)
- rawCmp = (int)(es1->len - es2->len);
- n = specificCmp(op, rawCmp);
- }
- else if (e1->isConst() != 1 || e2->isConst() != 1)
- {
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
- }
- else if (e1->type->isreal())
- {
- r1 = e1->toReal();
- r2 = e2->toReal();
- goto L1;
- }
- else if (e1->type->isimaginary())
- {
- r1 = e1->toImaginary();
- r2 = e2->toImaginary();
- L1:
- n = realCmp(op, r1, r2);
- }
- else if (e1->type->iscomplex())
- {
- assert(0);
- }
- else
- {
- sinteger_t n1;
- sinteger_t n2;
-
- n1 = e1->toInteger();
- n2 = e2->toInteger();
- if (e1->type->isunsigned() || e2->type->isunsigned())
- n = intUnsignedCmp(op, n1, n2);
- else
- n = intSignedCmp(op, n1, n2);
- }
- new(&ue) IntegerExp(loc, n, type);
- return ue;
-}
-
-/* Also returns TOKcantexp if cannot be computed.
- * to: type to cast to
- * type: type to paint the result
- */
-
-UnionExp Cast(Loc loc, Type *type, Type *to, Expression *e1)
-{
- UnionExp ue;
- Type *tb = to->toBasetype();
- Type *typeb = type->toBasetype();
-
- //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars());
- //printf("\te1->type = %s\n", e1->type->toChars());
- if (e1->type->equals(type) && type->equals(to))
- {
- new(&ue) UnionExp(e1);
- return ue;
- }
-
- if (e1->op == TOKvector && ((TypeVector *)e1->type)->basetype->equals(type) && type->equals(to))
- {
- Expression *ex = ((VectorExp *)e1)->e1;
- new(&ue) UnionExp(ex);
- return ue;
- }
-
- if (e1->type->implicitConvTo(to) >= MATCHconst ||
- to->implicitConvTo(e1->type) >= MATCHconst)
- {
- goto L1;
- }
-
- // Allow covariant converions of delegates
- // (Perhaps implicit conversion from pure to impure should be a MATCHconst,
- // then we wouldn't need this extra check.)
- if (e1->type->toBasetype()->ty == Tdelegate &&
- e1->type->implicitConvTo(to) == MATCHconvert)
- {
- goto L1;
- }
-
- /* Allow casting from one string type to another
- */
- if (e1->op == TOKstring)
- {
- if (tb->ty == Tarray && typeb->ty == Tarray &&
- tb->nextOf()->size() == typeb->nextOf()->size())
- {
- goto L1;
- }
- }
-
- if (e1->op == TOKarrayliteral && typeb == tb)
- {
-L1:
- Expression *ex = expType(to, e1);
- new(&ue) UnionExp(ex);
- return ue;
- }
-
- if (e1->isConst() != 1)
- {
- new(&ue) CTFEExp(TOKcantexp);
- }
- else if (tb->ty == Tbool)
- {
- new(&ue) IntegerExp(loc, e1->toInteger() != 0, type);
- }
- else if (type->isintegral())
- {
- if (e1->type->isfloating())
- {
- dinteger_t result;
- real_t r = e1->toReal();
-
- switch (typeb->ty)
- {
- case Tint8:
- result = (d_int8)(sinteger_t)r;
- break;
- case Tchar:
- case Tuns8:
- result = (d_uns8)(dinteger_t)r;
- break;
- case Tint16:
- result = (d_int16)(sinteger_t)r;
- break;
- case Twchar:
- case Tuns16:
- result = (d_uns16)(dinteger_t)r;
- break;
- case Tint32:
- result = (d_int32)r;
- break;
- case Tdchar:
- case Tuns32:
- result = (d_uns32)r;
- break;
- case Tint64:
- result = (d_int64)r;
- break;
- case Tuns64:
- result = (d_uns64)r;
- break;
- default:
- assert(0);
- }
-
- new(&ue) IntegerExp(loc, result, type);
- }
- else if (type->isunsigned())
- new(&ue) IntegerExp(loc, e1->toUInteger(), type);
- else
- new(&ue) IntegerExp(loc, e1->toInteger(), type);
- }
- else if (tb->isreal())
- {
- real_t value = e1->toReal();
-
- new(&ue) RealExp(loc, value, type);
- }
- else if (tb->isimaginary())
- {
- real_t value = e1->toImaginary();
-
- new(&ue) RealExp(loc, value, type);
- }
- else if (tb->iscomplex())
- {
- complex_t value = e1->toComplex();
-
- new(&ue) ComplexExp(loc, value, type);
- }
- else if (tb->isscalar())
- {
- new(&ue) IntegerExp(loc, e1->toInteger(), type);
- }
- else if (tb->ty == Tvoid)
- {
- new(&ue) CTFEExp(TOKcantexp);
- }
- else if (tb->ty == Tstruct && e1->op == TOKint64)
- {
- // Struct = 0;
- StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration();
- assert(sd);
- Expressions *elements = new Expressions;
- for (size_t i = 0; i < sd->fields.length; i++)
- {
- VarDeclaration *v = sd->fields[i];
- UnionExp zero;
- new(&zero) IntegerExp(0);
- ue = Cast(loc, v->type, v->type, zero.exp());
- if (ue.exp()->op == TOKcantexp)
- return ue;
- elements->push(ue.exp()->copy());
- }
- new(&ue) StructLiteralExp(loc, sd, elements);
- ue.exp()->type = type;
- }
- else
- {
- if (type != Type::terror)
- {
- // have to change to Internal Compiler Error
- // all invalid casts should be handled already in Expression::castTo().
- error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars());
- }
- new(&ue) ErrorExp();
- }
- return ue;
-}
-
-
-UnionExp ArrayLength(Type *type, Expression *e1)
-{
- UnionExp ue;
- Loc loc = e1->loc;
-
- if (e1->op == TOKstring)
- {
- StringExp *es1 = (StringExp *)e1;
-
- new(&ue) IntegerExp(loc, es1->len, type);
- }
- else if (e1->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
- size_t dim = ale->elements ? ale->elements->length : 0;
-
- new(&ue) IntegerExp(loc, dim, type);
- }
- else if (e1->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1;
- size_t dim = ale->keys->length;
-
- new(&ue) IntegerExp(loc, dim, type);
- }
- else if (e1->type->toBasetype()->ty == Tsarray)
- {
- Expression *e = ((TypeSArray *)e1->type->toBasetype())->dim;
- new(&ue) UnionExp(e);
- }
- else
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
-}
-
-/* Also return TOKcantexp if this fails
- */
-UnionExp Index(Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
- Loc loc = e1->loc;
-
- //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
- assert(e1->type);
- if (e1->op == TOKstring && e2->op == TOKint64)
- {
- StringExp *es1 = (StringExp *)e1;
- uinteger_t i = e2->toInteger();
-
- if (i >= es1->len)
- {
- e1->error("string index %llu is out of bounds [0 .. %llu]", i, (ulonglong)es1->len);
- new(&ue) ErrorExp();
- }
- else
- {
- new(&ue) IntegerExp(loc, es1->charAt(i), type);
- }
- }
- else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64)
- {
- TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype();
- uinteger_t length = tsa->dim->toInteger();
- uinteger_t i = e2->toInteger();
-
- if (i >= length)
- {
- e1->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length);
- new(&ue) ErrorExp();
- }
- else if (e1->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
- Expression *e = ale->getElement((size_t)i);
- e->type = type;
- e->loc = loc;
- if (hasSideEffect(e))
- new(&ue) CTFEExp(TOKcantexp);
- else
- new(&ue) UnionExp(e);
- }
- else
- new(&ue) CTFEExp(TOKcantexp);
- }
- else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64)
- {
- uinteger_t i = e2->toInteger();
-
- if (e1->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
- if (i >= ale->elements->length)
- {
- e1->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->length);
- new(&ue) ErrorExp();
- }
- else
- {
- Expression *e = ale->getElement((size_t)i);
- e->type = type;
- e->loc = loc;
- if (hasSideEffect(e))
- new(&ue) CTFEExp(TOKcantexp);
- else
- new(&ue) UnionExp(e);
- }
- }
- else
- new(&ue) CTFEExp(TOKcantexp);
- }
- else if (e1->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1;
- /* Search the keys backwards, in case there are duplicate keys
- */
- for (size_t i = ae->keys->length; i;)
- {
- i--;
- Expression *ekey = (*ae->keys)[i];
- ue = Equal(TOKequal, loc, Type::tbool, ekey, e2);
- if (CTFEExp::isCantExp(ue.exp()))
- return ue;
- if (ue.exp()->isBool(true))
- {
- Expression *e = (*ae->values)[i];
- e->type = type;
- e->loc = loc;
- if (hasSideEffect(e))
- new(&ue) CTFEExp(TOKcantexp);
- else
- new(&ue) UnionExp(e);
- return ue;
- }
- }
- new(&ue) CTFEExp(TOKcantexp);
- }
- else
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
-}
-
-/* Also return TOKcantexp if this fails
- */
-UnionExp Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr)
-{
- UnionExp ue;
- Loc loc = e1->loc;
-
- if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64)
- {
- StringExp *es1 = (StringExp *)e1;
- uinteger_t ilwr = lwr->toInteger();
- uinteger_t iupr = upr->toInteger();
-
- if (iupr > es1->len || ilwr > iupr)
- {
- e1->error("string slice [%llu .. %llu] is out of bounds", ilwr, iupr);
- new(&ue) ErrorExp();
- }
- else
- {
- size_t len = (size_t)(iupr - ilwr);
- unsigned char sz = es1->sz;
-
- void *s = mem.xmalloc((len + 1) * sz);
- memcpy((char *)s, (char *)es1->string + ilwr * sz, len * sz);
- memset((char *)s + len * sz, 0, sz);
-
- new(&ue) StringExp(loc, s, len, es1->postfix);
- StringExp *es = (StringExp *)ue.exp();
- es->sz = sz;
- es->committed = es1->committed;
- es->type = type;
- }
- }
- else if (e1->op == TOKarrayliteral &&
- lwr->op == TOKint64 && upr->op == TOKint64 &&
- !hasSideEffect(e1))
- {
- ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
- uinteger_t ilwr = lwr->toInteger();
- uinteger_t iupr = upr->toInteger();
-
- if (iupr > es1->elements->length || ilwr > iupr)
- {
- e1->error("array slice [%llu .. %llu] is out of bounds", ilwr, iupr);
- new(&ue) ErrorExp();
- }
- else
- {
- Expressions *elements = new Expressions();
- elements->setDim((size_t)(iupr - ilwr));
- memcpy(elements->tdata(),
- es1->elements->tdata() + ilwr,
- (size_t)(iupr - ilwr) * sizeof((*es1->elements)[0]));
- new(&ue) ArrayLiteralExp(e1->loc, type, elements);
- }
- }
- else
- new(&ue) CTFEExp(TOKcantexp);
- assert(ue.exp()->type);
- return ue;
-}
-
-/* Set a slice of char/integer array literal 'existingAE' from a string 'newval'.
- * existingAE[firstIndex..firstIndex+newval.length] = newval.
- */
-void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, size_t firstIndex)
-{
- size_t newlen = newval->len;
- size_t sz = newval->sz;
- void *s = newval->string;
- Type *elemType = existingAE->type->nextOf();
- for (size_t j = 0; j < newlen; j++)
- {
- dinteger_t val;
- switch (sz)
- {
- case 1: val = (( utf8_t *)s)[j]; break;
- case 2: val = ((utf16_t *)s)[j]; break;
- case 4: val = ((utf32_t *)s)[j]; break;
- default: assert(0); break;
- }
- (*existingAE->elements)[j + firstIndex]
- = new IntegerExp(newval->loc, val, elemType);
- }
-}
-
-/* Set a slice of string 'existingSE' from a char array literal 'newae'.
- * existingSE[firstIndex..firstIndex+newae.length] = newae.
- */
-void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, size_t firstIndex)
-{
- void *s = existingSE->string;
- for (size_t j = 0; j < newae->elements->length; j++)
- {
- unsigned val = (unsigned)newae->getElement(j)->toInteger();
- switch (existingSE->sz)
- {
- case 1: (( utf8_t *)s)[j + firstIndex] = ( utf8_t)val; break;
- case 2: ((utf16_t *)s)[j + firstIndex] = (utf16_t)val; break;
- case 4: ((utf32_t *)s)[j + firstIndex] = (utf32_t)val; break;
- default: assert(0); break;
- }
- }
-}
-
-/* Set a slice of string 'existingSE' from a string 'newstr'.
- * existingSE[firstIndex..firstIndex+newstr.length] = newstr.
- */
-void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, size_t firstIndex)
-{
- void *s = existingSE->string;
- size_t sz = existingSE->sz;
- assert(sz == newstr->sz);
- memcpy((char *)s + firstIndex * sz, newstr->string, sz * newstr->len);
-}
-
-/* Compare a string slice with another string slice.
- * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len])
- */
-int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len)
-{
- void *s1 = se1->string;
- void *s2 = se2->string;
- size_t sz = se1->sz;
- assert(sz == se2->sz);
- return memcmp((char *)s1 + sz * lo1, (char *)s2 + sz * lo2, sz * len);
-}
-
-/* Compare a string slice with an array literal slice
- * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len])
- */
-int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len)
-{
- void *s = se1->string;
- size_t sz = se1->sz;
-
- for (size_t j = 0; j < len; j++)
- {
- unsigned val2 = (unsigned)ae2->getElement(j + lo2)->toInteger();
- unsigned val1;
- switch (sz)
- {
- case 1: val1 = (( utf8_t *)s)[j + lo1]; break;
- case 2: val1 = ((utf16_t *)s)[j + lo1]; break;
- case 4: val1 = ((utf32_t *)s)[j + lo1]; break;
- default: assert(0); break;
- }
- int c = val1 - val2;
- if (c)
- return c;
- }
- return 0;
-}
-
-/* Also return TOKcantexp if this fails
- */
-UnionExp Cat(Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
- Expression *e = CTFEExp::cantexp;
- Loc loc = e1->loc;
- Type *t;
- Type *t1 = e1->type->toBasetype();
- Type *t2 = e2->type->toBasetype();
-
- //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
- //printf("\tt1 = %s, t2 = %s, type = %s\n", t1->toChars(), t2->toChars(), type->toChars());
-
- if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral))
- {
- e = e2;
- t = t1;
- goto L2;
- }
- else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull)
- {
- e = e1;
- t = t2;
- L2:
- Type *tn = e->type->toBasetype();
- if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
- {
- // Create a StringExp
- if (t->nextOf())
- t = t->nextOf()->toBasetype();
- unsigned char sz = (unsigned char)t->size();
-
- dinteger_t v = e->toInteger();
-
- size_t len = (t->ty == tn->ty) ? 1 : utf_codeLength(sz, (dchar_t)v);
- void *s = mem.xmalloc((len + 1) * sz);
- if (t->ty == tn->ty)
- Port::valcpy(s, v, sz);
- else
- utf_encode(sz, s, (dchar_t)v);
-
- // Add terminating 0
- memset((char *)s + len * sz, 0, sz);
-
- new(&ue) StringExp(loc, s, len);
- StringExp *es = (StringExp *)ue.exp();
- es->type = type;
- es->sz = sz;
- es->committed = 1;
- }
- else
- {
- // Create an ArrayLiteralExp
- Expressions *elements = new Expressions();
- elements->push(e);
- new(&ue) ArrayLiteralExp(e->loc, type, elements);
- }
- assert(ue.exp()->type);
- return ue;
- }
- else if (e1->op == TOKnull && e2->op == TOKnull)
- {
- if (type == e1->type)
- {
- // Handle null ~= null
- if (t1->ty == Tarray && t2 == t1->nextOf())
- {
- new(&ue) ArrayLiteralExp(e1->loc, type, e2);
- assert(ue.exp()->type);
- return ue;
- }
- else
- {
- new(&ue) UnionExp(e1);
- assert(ue.exp()->type);
- return ue;
- }
- }
- if (type == e2->type)
- {
- new(&ue) UnionExp(e2);
- assert(ue.exp()->type);
- return ue;
- }
- new(&ue) NullExp(e1->loc, type);
- assert(ue.exp()->type);
- return ue;
- }
- else if (e1->op == TOKstring && e2->op == TOKstring)
- {
- // Concatenate the strings
- StringExp *es1 = (StringExp *)e1;
- StringExp *es2 = (StringExp *)e2;
- size_t len = es1->len + es2->len;
- unsigned char sz = es1->sz;
-
- if (sz != es2->sz)
- {
- /* Can happen with:
- * auto s = "foo"d ~ "bar"c;
- */
- assert(global.errors);
- new(&ue) CTFEExp(TOKcantexp);
- assert(ue.exp()->type);
- return ue;
- }
- void *s = mem.xmalloc((len + 1) * sz);
- memcpy((char *)s, es1->string, es1->len * sz);
- memcpy((char *)s + es1->len * sz, es2->string, es2->len * sz);
-
- // Add terminating 0
- memset((char *)s + len * sz, 0, sz);
-
- new(&ue) StringExp(loc, s, len);
- StringExp *es = (StringExp *)ue.exp();
- es->sz = sz;
- es->committed = es1->committed | es2->committed;
- es->type = type;
- assert(ue.exp()->type);
- return ue;
- }
- else if (e2->op == TOKstring && e1->op == TOKarrayliteral &&
- t1->nextOf()->isintegral())
- {
- // [chars] ~ string --> [chars]
- StringExp *es = (StringExp *)e2;
- ArrayLiteralExp *ea = (ArrayLiteralExp *)e1;
- size_t len = es->len + ea->elements->length;
- Expressions * elems = new Expressions;
- elems->setDim(len);
- for (size_t i= 0; i < ea->elements->length; ++i)
- {
- (*elems)[i] = ea->getElement(i);
- }
- new(&ue) ArrayLiteralExp(e1->loc, type, elems);
- ArrayLiteralExp *dest = (ArrayLiteralExp *)ue.exp();
- sliceAssignArrayLiteralFromString(dest, es, ea->elements->length);
- assert(ue.exp()->type);
- return ue;
- }
- else if (e1->op == TOKstring && e2->op == TOKarrayliteral &&
- t2->nextOf()->isintegral())
- {
- // string ~ [chars] --> [chars]
- StringExp *es = (StringExp *)e1;
- ArrayLiteralExp *ea = (ArrayLiteralExp *)e2;
- size_t len = es->len + ea->elements->length;
- Expressions * elems = new Expressions;
- elems->setDim(len);
- for (size_t i= 0; i < ea->elements->length; ++i)
- {
- (*elems)[es->len + i] = ea->getElement(i);
- }
- new(&ue) ArrayLiteralExp(e1->loc, type, elems);
- ArrayLiteralExp *dest = (ArrayLiteralExp *)ue.exp();
- sliceAssignArrayLiteralFromString(dest, es, 0);
- assert(ue.exp()->type);
- return ue;
- }
- else if (e1->op == TOKstring && e2->op == TOKint64)
- {
- // string ~ char --> string
- StringExp *es1 = (StringExp *)e1;
- StringExp *es;
- unsigned char sz = es1->sz;
- dinteger_t v = e2->toInteger();
-
- // Is it a concatentation of homogenous types?
- // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar)
- bool homoConcat = (sz == t2->size());
- size_t len = es1->len;
- len += homoConcat ? 1 : utf_codeLength(sz, (dchar_t)v);
-
- void *s = mem.xmalloc((len + 1) * sz);
- memcpy(s, es1->string, es1->len * sz);
- if (homoConcat)
- Port::valcpy((char *)s + (sz * es1->len), v, sz);
- else
- utf_encode(sz, (char *)s + (sz * es1->len), (dchar_t)v);
-
- // Add terminating 0
- memset((char *)s + len * sz, 0, sz);
-
- new(&ue) StringExp(loc, s, len);
- es = (StringExp *)ue.exp();
- es->sz = sz;
- es->committed = es1->committed;
- es->type = type;
- assert(ue.exp()->type);
- return ue;
- }
- else if (e1->op == TOKint64 && e2->op == TOKstring)
- {
- // [w|d]?char ~ string --> string
- // We assume that we only ever prepend one char of the same type
- // (wchar,dchar) as the string's characters.
- StringExp *es2 = (StringExp *)e2;
- size_t len = 1 + es2->len;
- unsigned char sz = es2->sz;
- dinteger_t v = e1->toInteger();
-
- void *s = mem.xmalloc((len + 1) * sz);
- Port::valcpy((char *)s, v, sz);
- memcpy((char *)s + sz, es2->string, es2->len * sz);
-
- // Add terminating 0
- memset((char *)s + len * sz, 0, sz);
-
- new(&ue) StringExp(loc, s, len);
- StringExp *es = (StringExp *)ue.exp();
- es->sz = sz;
- es->committed = es2->committed;
- es->type = type;
- assert(ue.exp()->type);
- return ue;
- }
- else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
- t1->nextOf()->equals(t2->nextOf()))
- {
- // Concatenate the arrays
- Expressions *elems = ArrayLiteralExp::copyElements(e1, e2);
-
- new(&ue) ArrayLiteralExp(e1->loc, NULL, elems);
-
- e = ue.exp();
- if (type->toBasetype()->ty == Tsarray)
- {
- e->type = t1->nextOf()->sarrayOf(elems->length);
- }
- else
- e->type = type;
- assert(ue.exp()->type);
- return ue;
- }
- else if (e1->op == TOKarrayliteral && e2->op == TOKnull &&
- t1->nextOf()->equals(t2->nextOf()))
- {
- e = e1;
- goto L3;
- }
- else if (e1->op == TOKnull && e2->op == TOKarrayliteral &&
- t1->nextOf()->equals(t2->nextOf()))
- {
- e = e2;
- L3:
- // Concatenate the array with null
- Expressions *elems = ArrayLiteralExp::copyElements(e);
-
- new(&ue) ArrayLiteralExp(e->loc, NULL, elems);
-
- e = ue.exp();
- if (type->toBasetype()->ty == Tsarray)
- {
- e->type = t1->nextOf()->sarrayOf(elems->length);
- }
- else
- e->type = type;
- assert(ue.exp()->type);
- return ue;
- }
- else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) &&
- e1->type->toBasetype()->nextOf() &&
- e1->type->toBasetype()->nextOf()->equals(e2->type))
- {
- Expressions *elems = (e1->op == TOKarrayliteral)
- ? ArrayLiteralExp::copyElements(e1) : new Expressions();
- elems->push(e2);
-
- new(&ue) ArrayLiteralExp(e1->loc, NULL, elems);
-
- e = ue.exp();
- if (type->toBasetype()->ty == Tsarray)
- {
- e->type = e2->type->sarrayOf(elems->length);
- }
- else
- e->type = type;
- assert(ue.exp()->type);
- return ue;
- }
- else if (e2->op == TOKarrayliteral &&
- e2->type->toBasetype()->nextOf()->equals(e1->type))
- {
- Expressions *elems = ArrayLiteralExp::copyElements(e1, e2);
-
- new(&ue) ArrayLiteralExp(e2->loc, NULL, elems);
-
- e = ue.exp();
- if (type->toBasetype()->ty == Tsarray)
- {
- e->type = e1->type->sarrayOf(elems->length);
- }
- else
- e->type = type;
- assert(ue.exp()->type);
- return ue;
- }
- else if (e1->op == TOKnull && e2->op == TOKstring)
- {
- t = e1->type;
- e = e2;
- goto L1;
- }
- else if (e1->op == TOKstring && e2->op == TOKnull)
- {
- e = e1;
- t = e2->type;
- L1:
- Type *tb = t->toBasetype();
- if (tb->ty == Tarray && tb->nextOf()->equivalent(e->type))
- {
- Expressions *expressions = new Expressions();
- expressions->push(e);
- new(&ue) ArrayLiteralExp(loc, t, expressions);
- e = ue.exp();
- }
- else
- {
- new(&ue) UnionExp(e);
- e = ue.exp();
- }
- if (!e->type->equals(type))
- {
- StringExp *se = (StringExp *)e->copy();
- e = se->castTo(NULL, type);
- new(&ue) UnionExp(e);
- e = ue.exp();
- }
- }
- else
- new(&ue) CTFEExp(TOKcantexp);
- assert(ue.exp()->type);
- return ue;
-}
-
-UnionExp Ptr(Type *type, Expression *e1)
-{
- //printf("Ptr(e1 = %s)\n", e1->toChars());
- UnionExp ue;
- if (e1->op == TOKadd)
- {
- AddExp *ae = (AddExp *)e1;
- if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
- {
- AddrExp *ade = (AddrExp *)ae->e1;
- if (ade->e1->op == TOKstructliteral)
- {
- StructLiteralExp *se = (StructLiteralExp *)ade->e1;
- unsigned offset = (unsigned)ae->e2->toInteger();
- Expression *e = se->getField(type, offset);
- if (e)
- {
- new(&ue) UnionExp(e);
- return ue;
- }
- }
- }
- }
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
-}
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
new file mode 100644
index 0000000..1dada60
--- /dev/null
+++ b/gcc/d/dmd/constfold.d
@@ -0,0 +1,1825 @@
+/**
+ * Perform constant folding of arithmetic expressions.
+ *
+ * The routines in this module are called from `optimize.d`.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/float.html#fp_const_folding, Floating Point Constant Folding)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d, _constfold.d)
+ * Documentation: https://dlang.org/phobos/dmd_constfold.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/constfold.d
+ */
+
+module dmd.constfold;
+
+import core.stdc.string;
+import core.stdc.stdio;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.complex;
+import dmd.ctfeexpr;
+import dmd.declaration;
+import dmd.dstruct;
+import dmd.errors;
+import dmd.expression;
+import dmd.globals;
+import dmd.mtype;
+import dmd.root.ctfloat;
+import dmd.root.port;
+import dmd.root.rmem;
+import dmd.sideeffect;
+import dmd.target;
+import dmd.tokens;
+import dmd.utf;
+
+private enum LOG = false;
+
+private Expression expType(Type type, Expression e)
+{
+ if (type != e.type)
+ {
+ e = e.copy();
+ e.type = type;
+ }
+ return e;
+}
+
+/************************************
+ * Returns:
+ * true if e is a constant
+ */
+int isConst(Expression e)
+{
+ //printf("Expression::isConst(): %s\n", e.toChars());
+ switch (e.op)
+ {
+ case TOK.int64:
+ case TOK.float64:
+ case TOK.complex80:
+ return 1;
+ case TOK.null_:
+ return 0;
+ case TOK.symbolOffset:
+ return 2;
+ default:
+ return 0;
+ }
+ assert(0);
+}
+
+/**********************************
+ * Initialize a TOK.cantExpression Expression.
+ * Params:
+ * ue = where to write it
+ */
+void cantExp(out UnionExp ue)
+{
+ emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+}
+
+/* =============================== constFold() ============================== */
+/* The constFold() functions were redundant with the optimize() ones,
+ * and so have been folded in with them.
+ */
+/* ========================================================================== */
+UnionExp Neg(Type type, Expression e1)
+{
+ UnionExp ue = void;
+ Loc loc = e1.loc;
+ if (e1.type.isreal())
+ {
+ emplaceExp!(RealExp)(&ue, loc, -e1.toReal(), type);
+ }
+ else if (e1.type.isimaginary())
+ {
+ emplaceExp!(RealExp)(&ue, loc, -e1.toImaginary(), type);
+ }
+ else if (e1.type.iscomplex())
+ {
+ emplaceExp!(ComplexExp)(&ue, loc, -e1.toComplex(), type);
+ }
+ else
+ {
+ emplaceExp!(IntegerExp)(&ue, loc, -e1.toInteger(), type);
+ }
+ return ue;
+}
+
+UnionExp Com(Type type, Expression e1)
+{
+ UnionExp ue = void;
+ Loc loc = e1.loc;
+ emplaceExp!(IntegerExp)(&ue, loc, ~e1.toInteger(), type);
+ return ue;
+}
+
+UnionExp Not(Type type, Expression e1)
+{
+ UnionExp ue = void;
+ Loc loc = e1.loc;
+ emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(false) ? 1 : 0, type);
+ return ue;
+}
+
+private UnionExp Bool(Type type, Expression e1)
+{
+ UnionExp ue = void;
+ Loc loc = e1.loc;
+ emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(true) ? 1 : 0, type);
+ return ue;
+}
+
+UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ static if (LOG)
+ {
+ printf("Add(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
+ }
+ if (type.isreal())
+ {
+ emplaceExp!(RealExp)(&ue, loc, e1.toReal() + e2.toReal(), type);
+ }
+ else if (type.isimaginary())
+ {
+ emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() + e2.toImaginary(), type);
+ }
+ else if (type.iscomplex())
+ {
+ // This rigamarole is necessary so that -0.0 doesn't get
+ // converted to +0.0 by doing an extraneous add with +0.0
+ auto c1 = complex_t(CTFloat.zero);
+ real_t r1 = CTFloat.zero;
+ real_t i1 = CTFloat.zero;
+ auto c2 = complex_t(CTFloat.zero);
+ real_t r2 = CTFloat.zero;
+ real_t i2 = CTFloat.zero;
+ auto v = complex_t(CTFloat.zero);
+ int x;
+ if (e1.type.isreal())
+ {
+ r1 = e1.toReal();
+ x = 0;
+ }
+ else if (e1.type.isimaginary())
+ {
+ i1 = e1.toImaginary();
+ x = 3;
+ }
+ else
+ {
+ c1 = e1.toComplex();
+ x = 6;
+ }
+ if (e2.type.isreal())
+ {
+ r2 = e2.toReal();
+ }
+ else if (e2.type.isimaginary())
+ {
+ i2 = e2.toImaginary();
+ x += 1;
+ }
+ else
+ {
+ c2 = e2.toComplex();
+ x += 2;
+ }
+ switch (x)
+ {
+ case 0 + 0:
+ v = complex_t(r1 + r2);
+ break;
+ case 0 + 1:
+ v = complex_t(r1, i2);
+ break;
+ case 0 + 2:
+ v = complex_t(r1 + creall(c2), cimagl(c2));
+ break;
+ case 3 + 0:
+ v = complex_t(r2, i1);
+ break;
+ case 3 + 1:
+ v = complex_t(CTFloat.zero, i1 + i2);
+ break;
+ case 3 + 2:
+ v = complex_t(creall(c2), i1 + cimagl(c2));
+ break;
+ case 6 + 0:
+ v = complex_t(creall(c1) + r2, cimagl(c2));
+ break;
+ case 6 + 1:
+ v = complex_t(creall(c1), cimagl(c1) + i2);
+ break;
+ case 6 + 2:
+ v = c1 + c2;
+ break;
+ default:
+ assert(0);
+ }
+ emplaceExp!(ComplexExp)(&ue, loc, v, type);
+ }
+ else if (e1.op == TOK.symbolOffset)
+ {
+ SymOffExp soe = cast(SymOffExp)e1;
+ emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger());
+ ue.exp().type = type;
+ }
+ else if (e2.op == TOK.symbolOffset)
+ {
+ SymOffExp soe = cast(SymOffExp)e2;
+ emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger());
+ ue.exp().type = type;
+ }
+ else
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() + e2.toInteger(), type);
+ return ue;
+}
+
+UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ if (type.isreal())
+ {
+ emplaceExp!(RealExp)(&ue, loc, e1.toReal() - e2.toReal(), type);
+ }
+ else if (type.isimaginary())
+ {
+ emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() - e2.toImaginary(), type);
+ }
+ else if (type.iscomplex())
+ {
+ // This rigamarole is necessary so that -0.0 doesn't get
+ // converted to +0.0 by doing an extraneous add with +0.0
+ auto c1 = complex_t(CTFloat.zero);
+ real_t r1 = CTFloat.zero;
+ real_t i1 = CTFloat.zero;
+ auto c2 = complex_t(CTFloat.zero);
+ real_t r2 = CTFloat.zero;
+ real_t i2 = CTFloat.zero;
+ auto v = complex_t(CTFloat.zero);
+ int x;
+ if (e1.type.isreal())
+ {
+ r1 = e1.toReal();
+ x = 0;
+ }
+ else if (e1.type.isimaginary())
+ {
+ i1 = e1.toImaginary();
+ x = 3;
+ }
+ else
+ {
+ c1 = e1.toComplex();
+ x = 6;
+ }
+ if (e2.type.isreal())
+ {
+ r2 = e2.toReal();
+ }
+ else if (e2.type.isimaginary())
+ {
+ i2 = e2.toImaginary();
+ x += 1;
+ }
+ else
+ {
+ c2 = e2.toComplex();
+ x += 2;
+ }
+ switch (x)
+ {
+ case 0 + 0:
+ v = complex_t(r1 - r2);
+ break;
+ case 0 + 1:
+ v = complex_t(r1, -i2);
+ break;
+ case 0 + 2:
+ v = complex_t(r1 - creall(c2), -cimagl(c2));
+ break;
+ case 3 + 0:
+ v = complex_t(-r2, i1);
+ break;
+ case 3 + 1:
+ v = complex_t(CTFloat.zero, i1 - i2);
+ break;
+ case 3 + 2:
+ v = complex_t(-creall(c2), i1 - cimagl(c2));
+ break;
+ case 6 + 0:
+ v = complex_t(creall(c1) - r2, cimagl(c1));
+ break;
+ case 6 + 1:
+ v = complex_t(creall(c1), cimagl(c1) - i2);
+ break;
+ case 6 + 2:
+ v = c1 - c2;
+ break;
+ default:
+ assert(0);
+ }
+ emplaceExp!(ComplexExp)(&ue, loc, v, type);
+ }
+ else if (e1.op == TOK.symbolOffset)
+ {
+ SymOffExp soe = cast(SymOffExp)e1;
+ emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger());
+ ue.exp().type = type;
+ }
+ else
+ {
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() - e2.toInteger(), type);
+ }
+ return ue;
+}
+
+UnionExp Mul(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ if (type.isfloating())
+ {
+ auto c = complex_t(CTFloat.zero);
+ real_t r = CTFloat.zero;
+ if (e1.type.isreal())
+ {
+ r = e1.toReal();
+ c = e2.toComplex();
+ c = complex_t(r * creall(c), r * cimagl(c));
+ }
+ else if (e1.type.isimaginary())
+ {
+ r = e1.toImaginary();
+ c = e2.toComplex();
+ c = complex_t(-r * cimagl(c), r * creall(c));
+ }
+ else if (e2.type.isreal())
+ {
+ r = e2.toReal();
+ c = e1.toComplex();
+ c = complex_t(r * creall(c), r * cimagl(c));
+ }
+ else if (e2.type.isimaginary())
+ {
+ r = e2.toImaginary();
+ c = e1.toComplex();
+ c = complex_t(-r * cimagl(c), r * creall(c));
+ }
+ else
+ c = e1.toComplex() * e2.toComplex();
+ if (type.isreal())
+ emplaceExp!(RealExp)(&ue, loc, creall(c), type);
+ else if (type.isimaginary())
+ emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
+ else if (type.iscomplex())
+ emplaceExp!(ComplexExp)(&ue, loc, c, type);
+ else
+ assert(0);
+ }
+ else
+ {
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() * e2.toInteger(), type);
+ }
+ return ue;
+}
+
+UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ if (type.isfloating())
+ {
+ auto c = complex_t(CTFloat.zero);
+ if (e2.type.isreal())
+ {
+ if (e1.type.isreal())
+ {
+ emplaceExp!(RealExp)(&ue, loc, e1.toReal() / e2.toReal(), type);
+ return ue;
+ }
+ const r = e2.toReal();
+ c = e1.toComplex();
+ c = complex_t(creall(c) / r, cimagl(c) / r);
+ }
+ else if (e2.type.isimaginary())
+ {
+ const r = e2.toImaginary();
+ c = e1.toComplex();
+ c = complex_t(cimagl(c) / r, -creall(c) / r);
+ }
+ else
+ {
+ c = e1.toComplex() / e2.toComplex();
+ }
+
+ if (type.isreal())
+ emplaceExp!(RealExp)(&ue, loc, creall(c), type);
+ else if (type.isimaginary())
+ emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
+ else if (type.iscomplex())
+ emplaceExp!(ComplexExp)(&ue, loc, c, type);
+ else
+ assert(0);
+ }
+ else
+ {
+ sinteger_t n1;
+ sinteger_t n2;
+ sinteger_t n;
+ n1 = e1.toInteger();
+ n2 = e2.toInteger();
+ if (n2 == 0)
+ {
+ e2.error("divide by 0");
+ emplaceExp!(ErrorExp)(&ue);
+ return ue;
+ }
+ if (n2 == -1 && !type.isunsigned())
+ {
+ // Check for int.min / -1
+ if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
+ {
+ e2.error("integer overflow: `int.min / -1`");
+ emplaceExp!(ErrorExp)(&ue);
+ return ue;
+ }
+ else if (n1 == 0x8000000000000000L) // long.min / -1
+ {
+ e2.error("integer overflow: `long.min / -1L`");
+ emplaceExp!(ErrorExp)(&ue);
+ return ue;
+ }
+ }
+ if (e1.type.isunsigned() || e2.type.isunsigned())
+ n = (cast(dinteger_t)n1) / (cast(dinteger_t)n2);
+ else
+ n = n1 / n2;
+ emplaceExp!(IntegerExp)(&ue, loc, n, type);
+ }
+ return ue;
+}
+
+UnionExp Mod(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ if (type.isfloating())
+ {
+ auto c = complex_t(CTFloat.zero);
+ if (e2.type.isreal())
+ {
+ const r2 = e2.toReal();
+ c = complex_t(e1.toReal() % r2, e1.toImaginary() % r2);
+ }
+ else if (e2.type.isimaginary())
+ {
+ const i2 = e2.toImaginary();
+ c = complex_t(e1.toReal() % i2, e1.toImaginary() % i2);
+ }
+ else
+ assert(0);
+ if (type.isreal())
+ emplaceExp!(RealExp)(&ue, loc, creall(c), type);
+ else if (type.isimaginary())
+ emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
+ else if (type.iscomplex())
+ emplaceExp!(ComplexExp)(&ue, loc, c, type);
+ else
+ assert(0);
+ }
+ else
+ {
+ sinteger_t n1;
+ sinteger_t n2;
+ sinteger_t n;
+ n1 = e1.toInteger();
+ n2 = e2.toInteger();
+ if (n2 == 0)
+ {
+ e2.error("divide by 0");
+ emplaceExp!(ErrorExp)(&ue);
+ return ue;
+ }
+ if (n2 == -1 && !type.isunsigned())
+ {
+ // Check for int.min % -1
+ if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
+ {
+ e2.error("integer overflow: `int.min %% -1`");
+ emplaceExp!(ErrorExp)(&ue);
+ return ue;
+ }
+ else if (n1 == 0x8000000000000000L) // long.min % -1
+ {
+ e2.error("integer overflow: `long.min %% -1L`");
+ emplaceExp!(ErrorExp)(&ue);
+ return ue;
+ }
+ }
+ if (e1.type.isunsigned() || e2.type.isunsigned())
+ n = (cast(dinteger_t)n1) % (cast(dinteger_t)n2);
+ else
+ n = n1 % n2;
+ emplaceExp!(IntegerExp)(&ue, loc, n, type);
+ }
+ return ue;
+}
+
+UnionExp Pow(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ //printf("Pow()\n");
+ UnionExp ue;
+ // Handle integer power operations.
+ if (e2.type.isintegral())
+ {
+ dinteger_t n = e2.toInteger();
+ bool neg;
+ if (!e2.type.isunsigned() && cast(sinteger_t)n < 0)
+ {
+ if (e1.type.isintegral())
+ {
+ cantExp(ue);
+ return ue;
+ }
+ // Don't worry about overflow, from now on n is unsigned.
+ neg = true;
+ n = -n;
+ }
+ else
+ neg = false;
+ UnionExp ur, uv;
+ if (e1.type.iscomplex())
+ {
+ emplaceExp!(ComplexExp)(&ur, loc, e1.toComplex(), e1.type);
+ emplaceExp!(ComplexExp)(&uv, loc, complex_t(CTFloat.one), e1.type);
+ }
+ else if (e1.type.isfloating())
+ {
+ emplaceExp!(RealExp)(&ur, loc, e1.toReal(), e1.type);
+ emplaceExp!(RealExp)(&uv, loc, CTFloat.one, e1.type);
+ }
+ else
+ {
+ emplaceExp!(IntegerExp)(&ur, loc, e1.toInteger(), e1.type);
+ emplaceExp!(IntegerExp)(&uv, loc, 1, e1.type);
+ }
+ Expression r = ur.exp();
+ Expression v = uv.exp();
+ while (n != 0)
+ {
+ if (n & 1)
+ {
+ // v = v * r;
+ uv = Mul(loc, v.type, v, r);
+ }
+ n >>= 1;
+ // r = r * r
+ ur = Mul(loc, r.type, r, r);
+ }
+ if (neg)
+ {
+ // ue = 1.0 / v
+ UnionExp one;
+ emplaceExp!(RealExp)(&one, loc, CTFloat.one, v.type);
+ uv = Div(loc, v.type, one.exp(), v);
+ }
+ if (type.iscomplex())
+ emplaceExp!(ComplexExp)(&ue, loc, v.toComplex(), type);
+ else if (type.isintegral())
+ emplaceExp!(IntegerExp)(&ue, loc, v.toInteger(), type);
+ else
+ emplaceExp!(RealExp)(&ue, loc, v.toReal(), type);
+ }
+ else if (e2.type.isfloating())
+ {
+ // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
+ if (e1.toReal() < CTFloat.zero)
+ {
+ emplaceExp!(RealExp)(&ue, loc, target.RealProperties.nan, type);
+ }
+ else
+ cantExp(ue);
+ }
+ else
+ cantExp(ue);
+ return ue;
+}
+
+UnionExp Shl(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() << e2.toInteger(), type);
+ return ue;
+}
+
+UnionExp Shr(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ dinteger_t value = e1.toInteger();
+ dinteger_t dcount = e2.toInteger();
+ assert(dcount <= 0xFFFFFFFF);
+ uint count = cast(uint)dcount;
+ switch (e1.type.toBasetype().ty)
+ {
+ case Tint8:
+ value = cast(d_int8)value >> count;
+ break;
+ case Tuns8:
+ case Tchar:
+ value = cast(d_uns8)value >> count;
+ break;
+ case Tint16:
+ value = cast(d_int16)value >> count;
+ break;
+ case Tuns16:
+ case Twchar:
+ value = cast(d_uns16)value >> count;
+ break;
+ case Tint32:
+ value = cast(d_int32)value >> count;
+ break;
+ case Tuns32:
+ case Tdchar:
+ value = cast(d_uns32)value >> count;
+ break;
+ case Tint64:
+ value = cast(d_int64)value >> count;
+ break;
+ case Tuns64:
+ value = cast(d_uns64)value >> count;
+ break;
+ case Terror:
+ emplaceExp!(ErrorExp)(&ue);
+ return ue;
+ default:
+ assert(0);
+ }
+ emplaceExp!(IntegerExp)(&ue, loc, value, type);
+ return ue;
+}
+
+UnionExp Ushr(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ dinteger_t value = e1.toInteger();
+ dinteger_t dcount = e2.toInteger();
+ assert(dcount <= 0xFFFFFFFF);
+ uint count = cast(uint)dcount;
+ switch (e1.type.toBasetype().ty)
+ {
+ case Tint8:
+ case Tuns8:
+ case Tchar:
+ // Possible only with >>>=. >>> always gets promoted to int.
+ value = (value & 0xFF) >>> count;
+ break;
+ case Tint16:
+ case Tuns16:
+ case Twchar:
+ // Possible only with >>>=. >>> always gets promoted to int.
+ value = (value & 0xFFFF) >>> count;
+ break;
+ case Tint32:
+ case Tuns32:
+ case Tdchar:
+ value = (value & 0xFFFFFFFF) >>> count;
+ break;
+ case Tint64:
+ case Tuns64:
+ value = value >>> count;
+ break;
+ case Terror:
+ emplaceExp!(ErrorExp)(&ue);
+ return ue;
+ default:
+ assert(0);
+ }
+ emplaceExp!(IntegerExp)(&ue, loc, value, type);
+ return ue;
+}
+
+UnionExp And(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() & e2.toInteger(), type);
+ return ue;
+}
+
+UnionExp Or(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() | e2.toInteger(), type);
+ return ue;
+}
+
+UnionExp Xor(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ //printf("Xor(linnum = %d, e1 = %s, e2 = %s)\n", loc.linnum, e1.toChars(), e2.toChars());
+ UnionExp ue = void;
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() ^ e2.toInteger(), type);
+ return ue;
+}
+
+/* Also returns TOK.cantExpression if cannot be computed.
+ */
+UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ int cmp = 0;
+ real_t r1 = CTFloat.zero;
+ real_t r2 = CTFloat.zero;
+ //printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
+ assert(op == TOK.equal || op == TOK.notEqual);
+ if (e1.op == TOK.null_)
+ {
+ if (e2.op == TOK.null_)
+ cmp = 1;
+ else if (e2.op == TOK.string_)
+ {
+ StringExp es2 = cast(StringExp)e2;
+ cmp = (0 == es2.len);
+ }
+ else if (e2.op == TOK.arrayLiteral)
+ {
+ ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+ cmp = !es2.elements || (0 == es2.elements.dim);
+ }
+ else
+ {
+ cantExp(ue);
+ return ue;
+ }
+ }
+ else if (e2.op == TOK.null_)
+ {
+ if (e1.op == TOK.string_)
+ {
+ StringExp es1 = cast(StringExp)e1;
+ cmp = (0 == es1.len);
+ }
+ else if (e1.op == TOK.arrayLiteral)
+ {
+ ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
+ cmp = !es1.elements || (0 == es1.elements.dim);
+ }
+ else
+ {
+ cantExp(ue);
+ return ue;
+ }
+ }
+ else if (e1.op == TOK.string_ && e2.op == TOK.string_)
+ {
+ StringExp es1 = cast(StringExp)e1;
+ StringExp es2 = cast(StringExp)e2;
+ if (es1.sz != es2.sz)
+ {
+ assert(global.errors);
+ cantExp(ue);
+ return ue;
+ }
+ const data1 = es1.peekData();
+ const data2 = es2.peekData();
+ if (es1.len == es2.len && memcmp(data1.ptr, data2.ptr, es1.sz * es1.len) == 0)
+ cmp = 1;
+ else
+ cmp = 0;
+ }
+ else if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral)
+ {
+ ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
+ ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+ if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
+ cmp = 1; // both arrays are empty
+ else if (!es1.elements || !es2.elements)
+ cmp = 0;
+ else if (es1.elements.dim != es2.elements.dim)
+ cmp = 0;
+ else
+ {
+ for (size_t i = 0; i < es1.elements.dim; i++)
+ {
+ auto ee1 = es1[i];
+ auto ee2 = es2[i];
+ ue = Equal(TOK.equal, loc, Type.tint32, ee1, ee2);
+ if (CTFEExp.isCantExp(ue.exp()))
+ return ue;
+ cmp = cast(int)ue.exp().toInteger();
+ if (cmp == 0)
+ break;
+ }
+ }
+ }
+ else if (e1.op == TOK.arrayLiteral && e2.op == TOK.string_)
+ {
+ // Swap operands and use common code
+ Expression etmp = e1;
+ e1 = e2;
+ e2 = etmp;
+ goto Lsa;
+ }
+ else if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral)
+ {
+ Lsa:
+ StringExp es1 = cast(StringExp)e1;
+ ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+ size_t dim1 = es1.len;
+ size_t dim2 = es2.elements ? es2.elements.dim : 0;
+ if (dim1 != dim2)
+ cmp = 0;
+ else
+ {
+ cmp = 1; // if dim1 winds up being 0
+ for (size_t i = 0; i < dim1; i++)
+ {
+ uinteger_t c = es1.charAt(i);
+ auto ee2 = es2[i];
+ if (ee2.isConst() != 1)
+ {
+ cantExp(ue);
+ return ue;
+ }
+ cmp = (c == ee2.toInteger());
+ if (cmp == 0)
+ break;
+ }
+ }
+ }
+ else if (e1.op == TOK.structLiteral && e2.op == TOK.structLiteral)
+ {
+ StructLiteralExp es1 = cast(StructLiteralExp)e1;
+ StructLiteralExp es2 = cast(StructLiteralExp)e2;
+ if (es1.sd != es2.sd)
+ cmp = 0;
+ else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
+ cmp = 1; // both arrays are empty
+ else if (!es1.elements || !es2.elements)
+ cmp = 0;
+ else if (es1.elements.dim != es2.elements.dim)
+ cmp = 0;
+ else
+ {
+ cmp = 1;
+ for (size_t i = 0; i < es1.elements.dim; i++)
+ {
+ Expression ee1 = (*es1.elements)[i];
+ Expression ee2 = (*es2.elements)[i];
+ if (ee1 == ee2)
+ continue;
+ if (!ee1 || !ee2)
+ {
+ cmp = 0;
+ break;
+ }
+ ue = Equal(TOK.equal, loc, Type.tint32, ee1, ee2);
+ if (ue.exp().op == TOK.cantExpression)
+ return ue;
+ cmp = cast(int)ue.exp().toInteger();
+ if (cmp == 0)
+ break;
+ }
+ }
+ }
+ else if (e1.isConst() != 1 || e2.isConst() != 1)
+ {
+ cantExp(ue);
+ return ue;
+ }
+ else if (e1.type.isreal())
+ {
+ r1 = e1.toReal();
+ r2 = e2.toReal();
+ goto L1;
+ }
+ else if (e1.type.isimaginary())
+ {
+ r1 = e1.toImaginary();
+ r2 = e2.toImaginary();
+ L1:
+ if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
+ {
+ cmp = 0;
+ }
+ else
+ {
+ cmp = (r1 == r2);
+ }
+ }
+ else if (e1.type.iscomplex())
+ {
+ cmp = e1.toComplex() == e2.toComplex();
+ }
+ else if (e1.type.isintegral() || e1.type.toBasetype().ty == Tpointer)
+ {
+ cmp = (e1.toInteger() == e2.toInteger());
+ }
+ else
+ {
+ cantExp(ue);
+ return ue;
+ }
+ if (op == TOK.notEqual)
+ cmp ^= 1;
+ emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
+ return ue;
+}
+
+UnionExp Identity(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ int cmp;
+ if (e1.op == TOK.null_)
+ {
+ cmp = (e2.op == TOK.null_);
+ }
+ else if (e2.op == TOK.null_)
+ {
+ cmp = 0;
+ }
+ else if (e1.op == TOK.symbolOffset && e2.op == TOK.symbolOffset)
+ {
+ SymOffExp es1 = cast(SymOffExp)e1;
+ SymOffExp es2 = cast(SymOffExp)e2;
+ cmp = (es1.var == es2.var && es1.offset == es2.offset);
+ }
+ else
+ {
+ if (e1.type.isreal())
+ {
+ cmp = RealIdentical(e1.toReal(), e2.toReal());
+ }
+ else if (e1.type.isimaginary())
+ {
+ cmp = RealIdentical(e1.toImaginary(), e2.toImaginary());
+ }
+ else if (e1.type.iscomplex())
+ {
+ complex_t v1 = e1.toComplex();
+ complex_t v2 = e2.toComplex();
+ cmp = RealIdentical(creall(v1), creall(v2)) && RealIdentical(cimagl(v1), cimagl(v1));
+ }
+ else
+ {
+ ue = Equal((op == TOK.identity) ? TOK.equal : TOK.notEqual, loc, type, e1, e2);
+ return ue;
+ }
+ }
+ if (op == TOK.notIdentity)
+ cmp ^= 1;
+ emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
+ return ue;
+}
+
+UnionExp Cmp(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ dinteger_t n;
+ real_t r1 = CTFloat.zero;
+ real_t r2 = CTFloat.zero;
+ //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
+ if (e1.op == TOK.string_ && e2.op == TOK.string_)
+ {
+ StringExp es1 = cast(StringExp)e1;
+ StringExp es2 = cast(StringExp)e2;
+ size_t sz = es1.sz;
+ assert(sz == es2.sz);
+ size_t len = es1.len;
+ if (es2.len < len)
+ len = es2.len;
+ const data1 = es1.peekData();
+ const data2 = es1.peekData();
+ int rawCmp = memcmp(data1.ptr, data2.ptr, sz * len);
+ if (rawCmp == 0)
+ rawCmp = cast(int)(es1.len - es2.len);
+ n = specificCmp(op, rawCmp);
+ }
+ else if (e1.isConst() != 1 || e2.isConst() != 1)
+ {
+ cantExp(ue);
+ return ue;
+ }
+ else if (e1.type.isreal())
+ {
+ r1 = e1.toReal();
+ r2 = e2.toReal();
+ goto L1;
+ }
+ else if (e1.type.isimaginary())
+ {
+ r1 = e1.toImaginary();
+ r2 = e2.toImaginary();
+ L1:
+ n = realCmp(op, r1, r2);
+ }
+ else if (e1.type.iscomplex())
+ {
+ assert(0);
+ }
+ else
+ {
+ sinteger_t n1;
+ sinteger_t n2;
+ n1 = e1.toInteger();
+ n2 = e2.toInteger();
+ if (e1.type.isunsigned() || e2.type.isunsigned())
+ n = intUnsignedCmp(op, n1, n2);
+ else
+ n = intSignedCmp(op, n1, n2);
+ }
+ emplaceExp!(IntegerExp)(&ue, loc, n, type);
+ return ue;
+}
+
+/* Also returns TOK.cantExpression if cannot be computed.
+ * to: type to cast to
+ * type: type to paint the result
+ */
+UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
+{
+ UnionExp ue = void;
+ Type tb = to.toBasetype();
+ Type typeb = type.toBasetype();
+ //printf("Cast(type = %s, to = %s, e1 = %s)\n", type.toChars(), to.toChars(), e1.toChars());
+ //printf("\te1.type = %s\n", e1.type.toChars());
+ if (e1.type.equals(type) && type.equals(to))
+ {
+ emplaceExp!(UnionExp)(&ue, e1);
+ return ue;
+ }
+ if (e1.op == TOK.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
+ {
+ Expression ex = (cast(VectorExp)e1).e1;
+ emplaceExp!(UnionExp)(&ue, ex);
+ return ue;
+ }
+ if (e1.type.implicitConvTo(to) >= MATCH.constant || to.implicitConvTo(e1.type) >= MATCH.constant)
+ {
+ goto L1;
+ }
+ // Allow covariant converions of delegates
+ // (Perhaps implicit conversion from pure to impure should be a MATCH.constant,
+ // then we wouldn't need this extra check.)
+ if (e1.type.toBasetype().ty == Tdelegate && e1.type.implicitConvTo(to) == MATCH.convert)
+ {
+ goto L1;
+ }
+ /* Allow casting from one string type to another
+ */
+ if (e1.op == TOK.string_)
+ {
+ if (tb.ty == Tarray && typeb.ty == Tarray && tb.nextOf().size() == typeb.nextOf().size())
+ {
+ goto L1;
+ }
+ }
+ if (e1.op == TOK.arrayLiteral && typeb == tb)
+ {
+ L1:
+ Expression ex = expType(to, e1);
+ emplaceExp!(UnionExp)(&ue, ex);
+ return ue;
+ }
+ if (e1.isConst() != 1)
+ {
+ cantExp(ue);
+ }
+ else if (tb.ty == Tbool)
+ {
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() != 0, type);
+ }
+ else if (type.isintegral())
+ {
+ if (e1.type.isfloating())
+ {
+ dinteger_t result;
+ real_t r = e1.toReal();
+ switch (typeb.ty)
+ {
+ case Tint8:
+ result = cast(d_int8)cast(sinteger_t)r;
+ break;
+ case Tchar:
+ case Tuns8:
+ result = cast(d_uns8)cast(dinteger_t)r;
+ break;
+ case Tint16:
+ result = cast(d_int16)cast(sinteger_t)r;
+ break;
+ case Twchar:
+ case Tuns16:
+ result = cast(d_uns16)cast(dinteger_t)r;
+ break;
+ case Tint32:
+ result = cast(d_int32)r;
+ break;
+ case Tdchar:
+ case Tuns32:
+ result = cast(d_uns32)r;
+ break;
+ case Tint64:
+ result = cast(d_int64)r;
+ break;
+ case Tuns64:
+ result = cast(d_uns64)r;
+ break;
+ default:
+ assert(0);
+ }
+ emplaceExp!(IntegerExp)(&ue, loc, result, type);
+ }
+ else if (type.isunsigned())
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toUInteger(), type);
+ else
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
+ }
+ else if (tb.isreal())
+ {
+ real_t value = e1.toReal();
+ emplaceExp!(RealExp)(&ue, loc, value, type);
+ }
+ else if (tb.isimaginary())
+ {
+ real_t value = e1.toImaginary();
+ emplaceExp!(RealExp)(&ue, loc, value, type);
+ }
+ else if (tb.iscomplex())
+ {
+ complex_t value = e1.toComplex();
+ emplaceExp!(ComplexExp)(&ue, loc, value, type);
+ }
+ else if (tb.isscalar())
+ {
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
+ }
+ else if (tb.ty == Tvoid)
+ {
+ cantExp(ue);
+ }
+ else if (tb.ty == Tstruct && e1.op == TOK.int64)
+ {
+ // Struct = 0;
+ StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration();
+ assert(sd);
+ auto elements = new Expressions();
+ for (size_t i = 0; i < sd.fields.dim; i++)
+ {
+ VarDeclaration v = sd.fields[i];
+ UnionExp zero;
+ emplaceExp!(IntegerExp)(&zero, 0);
+ ue = Cast(loc, v.type, v.type, zero.exp());
+ if (ue.exp().op == TOK.cantExpression)
+ return ue;
+ elements.push(ue.exp().copy());
+ }
+ emplaceExp!(StructLiteralExp)(&ue, loc, sd, elements);
+ ue.exp().type = type;
+ }
+ else
+ {
+ if (type != Type.terror)
+ {
+ // have to change to Internal Compiler Error
+ // all invalid casts should be handled already in Expression::castTo().
+ error(loc, "cannot cast `%s` to `%s`", e1.type.toChars(), type.toChars());
+ }
+ emplaceExp!(ErrorExp)(&ue);
+ }
+ return ue;
+}
+
+UnionExp ArrayLength(Type type, Expression e1)
+{
+ UnionExp ue = void;
+ Loc loc = e1.loc;
+ if (e1.op == TOK.string_)
+ {
+ StringExp es1 = cast(StringExp)e1;
+ emplaceExp!(IntegerExp)(&ue, loc, es1.len, type);
+ }
+ else if (e1.op == TOK.arrayLiteral)
+ {
+ ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
+ size_t dim = ale.elements ? ale.elements.dim : 0;
+ emplaceExp!(IntegerExp)(&ue, loc, dim, type);
+ }
+ else if (e1.op == TOK.assocArrayLiteral)
+ {
+ AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1;
+ size_t dim = ale.keys.dim;
+ emplaceExp!(IntegerExp)(&ue, loc, dim, type);
+ }
+ else if (e1.type.toBasetype().ty == Tsarray)
+ {
+ Expression e = (cast(TypeSArray)e1.type.toBasetype()).dim;
+ emplaceExp!(UnionExp)(&ue, e);
+ }
+ else
+ cantExp(ue);
+ return ue;
+}
+
+/* Also return TOK.cantExpression if this fails
+ */
+UnionExp Index(Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ Loc loc = e1.loc;
+ //printf("Index(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
+ assert(e1.type);
+ if (e1.op == TOK.string_ && e2.op == TOK.int64)
+ {
+ StringExp es1 = cast(StringExp)e1;
+ uinteger_t i = e2.toInteger();
+ if (i >= es1.len)
+ {
+ e1.error("string index %llu is out of bounds `[0 .. %llu]`", i, cast(ulong)es1.len);
+ emplaceExp!(ErrorExp)(&ue);
+ }
+ else
+ {
+ emplaceExp!(IntegerExp)(&ue, loc, es1.charAt(i), type);
+ }
+ }
+ else if (e1.type.toBasetype().ty == Tsarray && e2.op == TOK.int64)
+ {
+ TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype();
+ uinteger_t length = tsa.dim.toInteger();
+ uinteger_t i = e2.toInteger();
+ if (i >= length)
+ {
+ e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length);
+ emplaceExp!(ErrorExp)(&ue);
+ }
+ else if (e1.op == TOK.arrayLiteral)
+ {
+ ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
+ auto e = ale[cast(size_t)i];
+ e.type = type;
+ e.loc = loc;
+ if (hasSideEffect(e))
+ cantExp(ue);
+ else
+ emplaceExp!(UnionExp)(&ue, e);
+ }
+ else
+ cantExp(ue);
+ }
+ else if (e1.type.toBasetype().ty == Tarray && e2.op == TOK.int64)
+ {
+ uinteger_t i = e2.toInteger();
+ if (e1.op == TOK.arrayLiteral)
+ {
+ ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
+ if (i >= ale.elements.dim)
+ {
+ e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), cast(ulong) ale.elements.dim);
+ emplaceExp!(ErrorExp)(&ue);
+ }
+ else
+ {
+ auto e = ale[cast(size_t)i];
+ e.type = type;
+ e.loc = loc;
+ if (hasSideEffect(e))
+ cantExp(ue);
+ else
+ emplaceExp!(UnionExp)(&ue, e);
+ }
+ }
+ else
+ cantExp(ue);
+ }
+ else if (e1.op == TOK.assocArrayLiteral)
+ {
+ AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1;
+ /* Search the keys backwards, in case there are duplicate keys
+ */
+ for (size_t i = ae.keys.dim; i;)
+ {
+ i--;
+ Expression ekey = (*ae.keys)[i];
+ ue = Equal(TOK.equal, loc, Type.tbool, ekey, e2);
+ if (CTFEExp.isCantExp(ue.exp()))
+ return ue;
+ if (ue.exp().isBool(true))
+ {
+ Expression e = (*ae.values)[i];
+ e.type = type;
+ e.loc = loc;
+ if (hasSideEffect(e))
+ cantExp(ue);
+ else
+ emplaceExp!(UnionExp)(&ue, e);
+ return ue;
+ }
+ }
+ cantExp(ue);
+ }
+ else
+ cantExp(ue);
+ return ue;
+}
+
+/* Also return TOK.cantExpression if this fails
+ */
+UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
+{
+ UnionExp ue = void;
+ Loc loc = e1.loc;
+ static if (LOG)
+ {
+ printf("Slice()\n");
+ if (lwr)
+ {
+ printf("\te1 = %s\n", e1.toChars());
+ printf("\tlwr = %s\n", lwr.toChars());
+ printf("\tupr = %s\n", upr.toChars());
+ }
+ }
+
+ static bool sliceBoundsCheck(uinteger_t lwr, uinteger_t upr, uinteger_t newlwr, uinteger_t newupr) pure
+ {
+ assert(lwr <= upr);
+ return !(newlwr <= newupr &&
+ lwr <= newlwr &&
+ newupr <= upr);
+ }
+
+ if (e1.op == TOK.string_ && lwr.op == TOK.int64 && upr.op == TOK.int64)
+ {
+ StringExp es1 = cast(StringExp)e1;
+ const uinteger_t ilwr = lwr.toInteger();
+ const uinteger_t iupr = upr.toInteger();
+ if (sliceBoundsCheck(0, es1.len, ilwr, iupr))
+ cantExp(ue); // https://issues.dlang.org/show_bug.cgi?id=18115
+ else
+ {
+ const len = cast(size_t)(iupr - ilwr);
+ const sz = es1.sz;
+ void* s = mem.xmalloc(len * sz);
+ const data1 = es1.peekData();
+ memcpy(s, data1.ptr + ilwr * sz, len * sz);
+ emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz, es1.postfix);
+ StringExp es = cast(StringExp)ue.exp();
+ es.committed = es1.committed;
+ es.type = type;
+ }
+ }
+ else if (e1.op == TOK.arrayLiteral && lwr.op == TOK.int64 && upr.op == TOK.int64 && !hasSideEffect(e1))
+ {
+ ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
+ const uinteger_t ilwr = lwr.toInteger();
+ const uinteger_t iupr = upr.toInteger();
+ if (sliceBoundsCheck(0, es1.elements.dim, ilwr, iupr))
+ cantExp(ue);
+ else
+ {
+ auto elements = new Expressions(cast(size_t)(iupr - ilwr));
+ memcpy(elements.tdata(), es1.elements.tdata() + ilwr, cast(size_t)(iupr - ilwr) * ((*es1.elements)[0]).sizeof);
+ emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elements);
+ }
+ }
+ else
+ cantExp(ue);
+ return ue;
+}
+
+/* Set a slice of char/integer array literal 'existingAE' from a string 'newval'.
+ * existingAE[firstIndex..firstIndex+newval.length] = newval.
+ */
+void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringExp newval, size_t firstIndex)
+{
+ const len = newval.len;
+ Type elemType = existingAE.type.nextOf();
+ foreach (j; 0 .. len)
+ {
+ const val = newval.getCodeUnit(j);
+ (*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType);
+ }
+}
+
+/* Set a slice of string 'existingSE' from a char array literal 'newae'.
+ * existingSE[firstIndex..firstIndex+newae.length] = newae.
+ */
+void sliceAssignStringFromArrayLiteral(StringExp existingSE, ArrayLiteralExp newae, size_t firstIndex)
+{
+ assert(existingSE.ownedByCtfe != OwnedBy.code);
+ foreach (j; 0 .. newae.elements.dim)
+ {
+ existingSE.setCodeUnit(firstIndex + j, cast(dchar)newae[j].toInteger());
+ }
+}
+
+/* Set a slice of string 'existingSE' from a string 'newstr'.
+ * existingSE[firstIndex..firstIndex+newstr.length] = newstr.
+ */
+void sliceAssignStringFromString(StringExp existingSE, const StringExp newstr, size_t firstIndex)
+{
+ assert(existingSE.ownedByCtfe != OwnedBy.code);
+ size_t sz = existingSE.sz;
+ assert(sz == newstr.sz);
+ auto data1 = existingSE.borrowData();
+ const data2 = newstr.peekData();
+ memcpy(data1.ptr + firstIndex * sz, data2.ptr, data2.length);
+}
+
+/* Compare a string slice with another string slice.
+ * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len])
+ */
+int sliceCmpStringWithString(const StringExp se1, const StringExp se2, size_t lo1, size_t lo2, size_t len)
+{
+ size_t sz = se1.sz;
+ assert(sz == se2.sz);
+ const data1 = se1.peekData();
+ const data2 = se2.peekData();
+ return memcmp(data1.ptr + sz * lo1, data2.ptr + sz * lo2, sz * len);
+}
+
+/* Compare a string slice with an array literal slice
+ * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len])
+ */
+int sliceCmpStringWithArray(const StringExp se1, ArrayLiteralExp ae2, size_t lo1, size_t lo2, size_t len)
+{
+ foreach (j; 0 .. len)
+ {
+ const val2 = cast(dchar)ae2[j + lo2].toInteger();
+ const val1 = se1.getCodeUnit(j + lo1);
+ const int c = val1 - val2;
+ if (c)
+ return c;
+ }
+ return 0;
+}
+
+/** Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s.
+ * Params:
+ * e1 = If it's ArrayLiteralExp, its `elements` will be copied.
+ * Otherwise, `e1` itself will be pushed into the new `Expressions`.
+ * e2 = If it's not `null`, it will be pushed/appended to the new
+ * `Expressions` by the same way with `e1`.
+ * Returns:
+ * Newly allocated `Expressions`. Note that it points to the original
+ * `Expression` values in e1 and e2.
+ */
+private Expressions* copyElements(Expression e1, Expression e2 = null)
+{
+ auto elems = new Expressions();
+
+ void append(ArrayLiteralExp ale)
+ {
+ if (!ale.elements)
+ return;
+ auto d = elems.dim;
+ elems.append(ale.elements);
+ foreach (ref el; (*elems)[d .. elems.dim])
+ {
+ if (!el)
+ el = ale.basis;
+ }
+ }
+
+ if (e1.op == TOK.arrayLiteral)
+ append(cast(ArrayLiteralExp)e1);
+ else
+ elems.push(e1);
+
+ if (e2)
+ {
+ if (e2.op == TOK.arrayLiteral)
+ append(cast(ArrayLiteralExp)e2);
+ else
+ elems.push(e2);
+ }
+
+ return elems;
+}
+
+/* Also return TOK.cantExpression if this fails
+ */
+UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ Expression e = CTFEExp.cantexp;
+ Type t;
+ Type t1 = e1.type.toBasetype();
+ Type t2 = e2.type.toBasetype();
+ //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
+ //printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars());
+ if (e1.op == TOK.null_ && (e2.op == TOK.int64 || e2.op == TOK.structLiteral))
+ {
+ e = e2;
+ t = t1;
+ goto L2;
+ }
+ else if ((e1.op == TOK.int64 || e1.op == TOK.structLiteral) && e2.op == TOK.null_)
+ {
+ e = e1;
+ t = t2;
+ L2:
+ Type tn = e.type.toBasetype();
+ if (tn.ty.isSomeChar)
+ {
+ // Create a StringExp
+ if (t.nextOf())
+ t = t.nextOf().toBasetype();
+ const sz = cast(ubyte)t.size();
+ dinteger_t v = e.toInteger();
+ const len = (t.ty == tn.ty) ? 1 : utf_codeLength(sz, cast(dchar)v);
+ void* s = mem.xmalloc(len * sz);
+ if (t.ty == tn.ty)
+ Port.valcpy(s, v, sz);
+ else
+ utf_encode(sz, s, cast(dchar)v);
+ emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
+ StringExp es = cast(StringExp)ue.exp();
+ es.type = type;
+ es.committed = 1;
+ }
+ else
+ {
+ // Create an ArrayLiteralExp
+ auto elements = new Expressions();
+ elements.push(e);
+ emplaceExp!(ArrayLiteralExp)(&ue, e.loc, type, elements);
+ }
+ assert(ue.exp().type);
+ return ue;
+ }
+ else if (e1.op == TOK.null_ && e2.op == TOK.null_)
+ {
+ if (type == e1.type)
+ {
+ // Handle null ~= null
+ if (t1.ty == Tarray && t2 == t1.nextOf())
+ {
+ emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, e2);
+ assert(ue.exp().type);
+ return ue;
+ }
+ else
+ {
+ emplaceExp!(UnionExp)(&ue, e1);
+ assert(ue.exp().type);
+ return ue;
+ }
+ }
+ if (type == e2.type)
+ {
+ emplaceExp!(UnionExp)(&ue, e2);
+ assert(ue.exp().type);
+ return ue;
+ }
+ emplaceExp!(NullExp)(&ue, e1.loc, type);
+ assert(ue.exp().type);
+ return ue;
+ }
+ else if (e1.op == TOK.string_ && e2.op == TOK.string_)
+ {
+ // Concatenate the strings
+ StringExp es1 = cast(StringExp)e1;
+ StringExp es2 = cast(StringExp)e2;
+ size_t len = es1.len + es2.len;
+ ubyte sz = es1.sz;
+ if (sz != es2.sz)
+ {
+ /* Can happen with:
+ * auto s = "foo"d ~ "bar"c;
+ */
+ assert(global.errors);
+ cantExp(ue);
+ assert(ue.exp().type);
+ return ue;
+ }
+ void* s = mem.xmalloc(len * sz);
+ const data1 = es1.peekData();
+ const data2 = es2.peekData();
+ memcpy(cast(char*)s, data1.ptr, es1.len * sz);
+ memcpy(cast(char*)s + es1.len * sz, data2.ptr, es2.len * sz);
+ emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
+ StringExp es = cast(StringExp)ue.exp();
+ es.committed = es1.committed | es2.committed;
+ es.type = type;
+ assert(ue.exp().type);
+ return ue;
+ }
+ else if (e2.op == TOK.string_ && e1.op == TOK.arrayLiteral && t1.nextOf().isintegral())
+ {
+ // [chars] ~ string --> [chars]
+ StringExp es = cast(StringExp)e2;
+ ArrayLiteralExp ea = cast(ArrayLiteralExp)e1;
+ size_t len = es.len + ea.elements.dim;
+ auto elems = new Expressions(len);
+ for (size_t i = 0; i < ea.elements.dim; ++i)
+ {
+ (*elems)[i] = ea[i];
+ }
+ emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
+ ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp();
+ sliceAssignArrayLiteralFromString(dest, es, ea.elements.dim);
+ assert(ue.exp().type);
+ return ue;
+ }
+ else if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral && t2.nextOf().isintegral())
+ {
+ // string ~ [chars] --> [chars]
+ StringExp es = cast(StringExp)e1;
+ ArrayLiteralExp ea = cast(ArrayLiteralExp)e2;
+ size_t len = es.len + ea.elements.dim;
+ auto elems = new Expressions(len);
+ for (size_t i = 0; i < ea.elements.dim; ++i)
+ {
+ (*elems)[es.len + i] = ea[i];
+ }
+ emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
+ ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp();
+ sliceAssignArrayLiteralFromString(dest, es, 0);
+ assert(ue.exp().type);
+ return ue;
+ }
+ else if (e1.op == TOK.string_ && e2.op == TOK.int64)
+ {
+ // string ~ char --> string
+ StringExp es1 = cast(StringExp)e1;
+ StringExp es;
+ const sz = es1.sz;
+ dinteger_t v = e2.toInteger();
+ // Is it a concatenation of homogenous types?
+ // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar)
+ bool homoConcat = (sz == t2.size());
+ const len = es1.len + (homoConcat ? 1 : utf_codeLength(sz, cast(dchar)v));
+ void* s = mem.xmalloc(len * sz);
+ const data1 = es1.peekData();
+ memcpy(s, data1.ptr, data1.length);
+ if (homoConcat)
+ Port.valcpy(cast(char*)s + (sz * es1.len), v, sz);
+ else
+ utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v);
+ emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
+ es = cast(StringExp)ue.exp();
+ es.committed = es1.committed;
+ es.type = type;
+ assert(ue.exp().type);
+ return ue;
+ }
+ else if (e1.op == TOK.int64 && e2.op == TOK.string_)
+ {
+ // [w|d]?char ~ string --> string
+ // We assume that we only ever prepend one char of the same type
+ // (wchar,dchar) as the string's characters.
+ StringExp es2 = cast(StringExp)e2;
+ const len = 1 + es2.len;
+ const sz = es2.sz;
+ dinteger_t v = e1.toInteger();
+ void* s = mem.xmalloc(len * sz);
+ Port.valcpy(cast(char*)s, v, sz);
+ const data2 = es2.peekData();
+ memcpy(cast(char*)s + sz, data2.ptr, data2.length);
+ emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
+ StringExp es = cast(StringExp)ue.exp();
+ es.sz = sz;
+ es.committed = es2.committed;
+ es.type = type;
+ assert(ue.exp().type);
+ return ue;
+ }
+ else if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
+ {
+ // Concatenate the arrays
+ auto elems = copyElements(e1, e2);
+
+ emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, cast(Type)null, elems);
+
+ e = ue.exp();
+ if (type.toBasetype().ty == Tsarray)
+ {
+ e.type = t1.nextOf().sarrayOf(elems.dim);
+ }
+ else
+ e.type = type;
+ assert(ue.exp().type);
+ return ue;
+ }
+ else if (e1.op == TOK.arrayLiteral && e2.op == TOK.null_ && t1.nextOf().equals(t2.nextOf()))
+ {
+ e = e1;
+ goto L3;
+ }
+ else if (e1.op == TOK.null_ && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
+ {
+ e = e2;
+ L3:
+ // Concatenate the array with null
+ auto elems = copyElements(e);
+
+ emplaceExp!(ArrayLiteralExp)(&ue, e.loc, cast(Type)null, elems);
+
+ e = ue.exp();
+ if (type.toBasetype().ty == Tsarray)
+ {
+ e.type = t1.nextOf().sarrayOf(elems.dim);
+ }
+ else
+ e.type = type;
+ assert(ue.exp().type);
+ return ue;
+ }
+ else if ((e1.op == TOK.arrayLiteral || e1.op == TOK.null_) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type))
+ {
+ auto elems = (e1.op == TOK.arrayLiteral)
+ ? copyElements(e1) : new Expressions();
+ elems.push(e2);
+
+ emplaceExp!(ArrayLiteralExp)(&ue, loc, cast(Type)null, elems);
+
+ e = ue.exp();
+ if (type.toBasetype().ty == Tsarray)
+ {
+ e.type = e2.type.sarrayOf(elems.dim);
+ }
+ else
+ e.type = type;
+ assert(ue.exp().type);
+ return ue;
+ }
+ else if (e2.op == TOK.arrayLiteral && e2.type.toBasetype().nextOf().equals(e1.type))
+ {
+ auto elems = copyElements(e1, e2);
+
+ emplaceExp!(ArrayLiteralExp)(&ue, loc, cast(Type)null, elems);
+
+ e = ue.exp();
+ if (type.toBasetype().ty == Tsarray)
+ {
+ e.type = e1.type.sarrayOf(elems.dim);
+ }
+ else
+ e.type = type;
+ assert(ue.exp().type);
+ return ue;
+ }
+ else if (e1.op == TOK.null_ && e2.op == TOK.string_)
+ {
+ t = e1.type;
+ e = e2;
+ goto L1;
+ }
+ else if (e1.op == TOK.string_ && e2.op == TOK.null_)
+ {
+ e = e1;
+ t = e2.type;
+ L1:
+ Type tb = t.toBasetype();
+ if (tb.ty == Tarray && tb.nextOf().equivalent(e.type))
+ {
+ auto expressions = new Expressions();
+ expressions.push(e);
+ emplaceExp!(ArrayLiteralExp)(&ue, loc, t, expressions);
+ e = ue.exp();
+ }
+ else
+ {
+ emplaceExp!(UnionExp)(&ue, e);
+ e = ue.exp();
+ }
+ if (!e.type.equals(type))
+ {
+ StringExp se = cast(StringExp)e.copy();
+ e = se.castTo(null, type);
+ emplaceExp!(UnionExp)(&ue, e);
+ e = ue.exp();
+ }
+ }
+ else
+ cantExp(ue);
+ assert(ue.exp().type);
+ return ue;
+}
+
+UnionExp Ptr(Type type, Expression e1)
+{
+ //printf("Ptr(e1 = %s)\n", e1.toChars());
+ UnionExp ue = void;
+ if (e1.op == TOK.add)
+ {
+ AddExp ae = cast(AddExp)e1;
+ if (ae.e1.op == TOK.address && ae.e2.op == TOK.int64)
+ {
+ AddrExp ade = cast(AddrExp)ae.e1;
+ if (ade.e1.op == TOK.structLiteral)
+ {
+ StructLiteralExp se = cast(StructLiteralExp)ade.e1;
+ uint offset = cast(uint)ae.e2.toInteger();
+ Expression e = se.getField(type, offset);
+ if (e)
+ {
+ emplaceExp!(UnionExp)(&ue, e);
+ return ue;
+ }
+ }
+ }
+ }
+ cantExp(ue);
+ return ue;
+}
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
new file mode 100644
index 0000000..bb40649
--- /dev/null
+++ b/gcc/d/dmd/cparse.d
@@ -0,0 +1,4249 @@
+/**
+ * Takes a token stream from the lexer, and parses it into an abstract syntax tree.
+ *
+ * Specification: C11
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cparse.d, _cparse.d)
+ * Documentation: https://dlang.org/phobos/dmd_cparse.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cparse.d
+ */
+
+module dmd.cparse;
+
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.astenums;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.lexer;
+import dmd.parse;
+import dmd.errors;
+import dmd.root.filename;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.tokens;
+
+/***********************************************************
+ */
+final class CParser(AST) : Parser!AST
+{
+ AST.Dsymbols* symbols; // symbols declared in current scope
+
+ bool addFuncName; /// add declaration of __func__ to function symbol table
+
+ extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment,
+ const ref TARGET target)
+ {
+ super(_module, input, doDocComment);
+
+ //printf("CParser.this()\n");
+ mod = _module;
+ linkage = LINK.c;
+ Ccompile = true;
+
+ // Configure sizes for C `long`, `long double`, `wchar_t`
+ this.longsize = target.longsize;
+ this.long_doublesize = target.long_doublesize;
+ this.wchar_tsize = target.wchar_tsize;
+
+ // C `char` is always unsigned in ImportC
+ }
+
+ /********************************************
+ * Parse translation unit.
+ * C11 6.9
+ * translation-unit:
+ * external-declaration
+ * translation-unit external-declaration
+ *
+ * external-declaration:
+ * function-definition
+ * declaration
+ * Returns:
+ * array of Dsymbols that were declared
+ */
+ override AST.Dsymbols* parseModule()
+ {
+ //printf("cparseTranslationUnit()\n");
+ symbols = new AST.Dsymbols();
+ while (1)
+ {
+ if (token.value == TOK.endOfFile)
+ {
+ // wrap the symbols in `extern (C) { symbols }`
+ auto wrap = new AST.Dsymbols();
+ auto ld = new AST.LinkDeclaration(token.loc, LINK.c, symbols);
+ wrap.push(ld);
+
+ return wrap;
+ }
+
+ cparseDeclaration(LVL.global);
+ }
+ }
+
+ /******************************************************************************/
+ /********************************* Statement Parser ***************************/
+ //{
+
+ /**********************
+ * C11 6.8
+ * statement:
+ * labeled-statement
+ * compound-statement
+ * expression-statement
+ * selection-statement
+ * iteration-statement
+ * jump-statement
+ *
+ * Params:
+ * flags = PSxxxx
+ * endPtr = store location of closing brace
+ * pEndloc = if { ... statements ... }, store location of closing brace, otherwise loc of last token of statement
+ * Returns:
+ * parsed statement
+ */
+ AST.Statement cparseStatement(int flags, const(char)** endPtr = null, Loc* pEndloc = null)
+ {
+ AST.Statement s;
+ const loc = token.loc;
+
+ //printf("cparseStatement()\n");
+
+ auto symbolsSave = symbols;
+ if (!(flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope)))
+ symbols = new AST.Dsymbols();
+
+ switch (token.value)
+ {
+ case TOK.identifier:
+ /* A leading identifier can be a declaration, label, or expression.
+ * A quick check of the next token can disambiguate most cases.
+ */
+ switch (peekNext())
+ {
+ case TOK.colon:
+ {
+ // It's a label
+ auto ident = token.ident;
+ nextToken(); // advance to `:`
+ nextToken(); // advance past `:`
+ if (token.value == TOK.rightCurly)
+ s = null;
+ else if (token.value == TOK.leftCurly)
+ s = cparseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_);
+ else
+ s = cparseStatement(ParseStatementFlags.semiOk);
+ s = new AST.LabelStatement(loc, ident, s);
+ break;
+ }
+
+ case TOK.dot:
+ case TOK.arrow:
+ case TOK.plusPlus:
+ case TOK.minusMinus:
+ case TOK.leftBracket:
+ case TOK.question:
+ case TOK.assign:
+ case TOK.addAssign:
+ case TOK.minAssign:
+ case TOK.mulAssign:
+ case TOK.divAssign:
+ case TOK.modAssign:
+ case TOK.andAssign:
+ case TOK.orAssign:
+ case TOK.xorAssign:
+ case TOK.leftShiftAssign:
+ case TOK.rightShiftAssign:
+ goto Lexp;
+
+ case TOK.leftParenthesis:
+ {
+ /* If tokens look like a function call, assume it is one,
+ * As any type-name won't be resolved until semantic, this
+ * could be rewritten later.
+ */
+ auto tk = &token;
+ if (isFunctionCall(tk))
+ goto Lexp;
+ goto default;
+ }
+
+ default:
+ {
+ /* If tokens look like a declaration, assume it is one
+ */
+ auto tk = &token;
+ if (isCDeclaration(tk))
+ goto Ldeclaration;
+ goto Lexp;
+ }
+ }
+ break;
+
+ case TOK.int32Literal:
+ case TOK.uns32Literal:
+ case TOK.int64Literal:
+ case TOK.uns64Literal:
+ case TOK.int128Literal:
+ case TOK.uns128Literal:
+ case TOK.float32Literal:
+ case TOK.float64Literal:
+ case TOK.float80Literal:
+ case TOK.imaginary32Literal:
+ case TOK.imaginary64Literal:
+ case TOK.imaginary80Literal:
+ case TOK.leftParenthesis:
+ case TOK.and:
+ case TOK.mul:
+ case TOK.min:
+ case TOK.add:
+ case TOK.tilde:
+ case TOK.not:
+ case TOK.plusPlus:
+ case TOK.minusMinus:
+ case TOK.sizeof_:
+ Lexp:
+ auto exp = cparseExpression();
+ if (token.value == TOK.identifier && exp.op == TOK.identifier)
+ {
+ error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
+ nextToken();
+ }
+ else
+ check(TOK.semicolon, "statement");
+ s = new AST.ExpStatement(loc, exp);
+ break;
+
+ // type-specifiers
+ case TOK.void_:
+ case TOK.char_:
+ case TOK.int16:
+ case TOK.int32:
+ case TOK.int64:
+ case TOK.float32:
+ case TOK.float64:
+ case TOK.signed:
+ case TOK.unsigned:
+ case TOK._Bool:
+ //case TOK._Imaginary:
+ case TOK._Complex:
+ case TOK.struct_:
+ case TOK.union_:
+ case TOK.enum_:
+
+ // storage-class-specifiers
+ case TOK.typedef_:
+ case TOK.extern_:
+ case TOK.static_:
+ case TOK._Thread_local:
+ case TOK.auto_:
+ case TOK.register:
+
+ // function-specifiers
+ case TOK.inline:
+ case TOK._Noreturn:
+
+ // type-qualifiers
+ case TOK.const_:
+ case TOK.volatile:
+ case TOK.restrict:
+
+ // alignment-specifier
+ case TOK._Alignas:
+
+ // atomic-type-specifier or type_qualifier
+ case TOK._Atomic:
+
+ Ldeclaration:
+ {
+ cparseDeclaration(LVL.local);
+ if (symbols.length > 1)
+ {
+ auto as = new AST.Statements();
+ as.reserve(symbols.length);
+ foreach (d; (*symbols)[])
+ {
+ s = new AST.ExpStatement(loc, d);
+ as.push(s);
+ }
+ s = new AST.CompoundDeclarationStatement(loc, as);
+ symbols.setDim(0);
+ }
+ else if (symbols.length == 1)
+ {
+ auto d = (*symbols)[0];
+ s = new AST.ExpStatement(loc, d);
+ symbols.setDim(0);
+ }
+ else
+ s = new AST.ExpStatement(loc, cast(AST.Expression)null);
+ if (flags & ParseStatementFlags.scope_)
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ break;
+ }
+
+ case TOK._Static_assert: // _Static_assert ( constant-expression, string-literal ) ;
+ s = new AST.StaticAssertStatement(cparseStaticAssert());
+ break;
+
+ case TOK.leftCurly:
+ {
+ /* C11 6.8.2
+ * compound-statement:
+ * { block-item-list (opt) }
+ *
+ * block-item-list:
+ * block-item
+ * block-item-list block-item
+ *
+ * block-item:
+ * declaration
+ * statement
+ */
+ nextToken();
+ auto statements = new AST.Statements();
+ while (token.value != TOK.rightCurly && token.value != TOK.endOfFile)
+ {
+ statements.push(cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
+ }
+ if (endPtr)
+ *endPtr = token.ptr;
+ endloc = token.loc;
+ if (pEndloc)
+ {
+ *pEndloc = token.loc;
+ pEndloc = null; // don't set it again
+ }
+ s = new AST.CompoundStatement(loc, statements);
+ if (flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope))
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ check(TOK.rightCurly, "compound statement");
+ break;
+ }
+
+ case TOK.while_:
+ {
+ nextToken();
+ check(TOK.leftParenthesis);
+ auto condition = cparseExpression();
+ check(TOK.rightParenthesis);
+ Loc endloc;
+ auto _body = cparseStatement(ParseStatementFlags.scope_, null, &endloc);
+ s = new AST.WhileStatement(loc, condition, _body, endloc, null);
+ break;
+ }
+
+ case TOK.semicolon:
+ /* C11 6.8.3 null statement
+ */
+ nextToken();
+ s = new AST.ExpStatement(loc, cast(AST.Expression)null);
+ break;
+
+ case TOK.do_:
+ {
+ nextToken();
+ auto _body = cparseStatement(ParseStatementFlags.scope_);
+ check(TOK.while_);
+ check(TOK.leftParenthesis);
+ auto condition = cparseExpression();
+ check(TOK.rightParenthesis);
+ check(TOK.semicolon, "terminating `;` required after do-while statement");
+ s = new AST.DoStatement(loc, _body, condition, token.loc);
+ break;
+ }
+
+ case TOK.for_:
+ {
+ AST.Statement _init;
+ AST.Expression condition;
+ AST.Expression increment;
+
+ nextToken();
+ check(TOK.leftParenthesis);
+ if (token.value == TOK.semicolon)
+ {
+ _init = null;
+ nextToken();
+ }
+ else
+ {
+ _init = cparseStatement(0);
+ }
+ if (token.value == TOK.semicolon)
+ {
+ condition = null;
+ nextToken();
+ }
+ else
+ {
+ condition = cparseExpression();
+ check(TOK.semicolon, "`for` condition");
+ }
+ if (token.value == TOK.rightParenthesis)
+ {
+ increment = null;
+ nextToken();
+ }
+ else
+ {
+ increment = cparseExpression();
+ check(TOK.rightParenthesis);
+ }
+ Loc endloc;
+ auto _body = cparseStatement(ParseStatementFlags.scope_, null, &endloc);
+ s = new AST.ForStatement(loc, _init, condition, increment, _body, endloc);
+ break;
+ }
+
+ case TOK.if_:
+ {
+ nextToken();
+ check(TOK.leftParenthesis);
+ auto condition = cparseExpression();
+ check(TOK.rightParenthesis);
+ auto ifbody = cparseStatement(ParseStatementFlags.scope_);
+ AST.Statement elsebody;
+ if (token.value == TOK.else_)
+ {
+ nextToken();
+ elsebody = cparseStatement(ParseStatementFlags.scope_);
+ }
+ else
+ elsebody = null;
+ if (condition && ifbody)
+ s = new AST.IfStatement(loc, null, condition, ifbody, elsebody, token.loc);
+ else
+ s = null; // don't propagate parsing errors
+ break;
+ }
+
+ case TOK.else_:
+ error("found `else` without a corresponding `if` statement");
+ goto Lerror;
+
+ case TOK.switch_:
+ {
+ nextToken();
+ check(TOK.leftParenthesis);
+ auto condition = cparseExpression();
+ check(TOK.rightParenthesis);
+ auto _body = cparseStatement(ParseStatementFlags.scope_);
+ s = new AST.SwitchStatement(loc, condition, _body, false);
+ break;
+ }
+
+ case TOK.case_:
+ {
+
+ nextToken();
+ auto exp = cparseAssignExp();
+ check(TOK.colon);
+
+ if (flags & ParseStatementFlags.curlyScope)
+ {
+ auto statements = new AST.Statements();
+ while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
+ {
+ auto cur = cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
+ statements.push(cur);
+
+ // https://issues.dlang.org/show_bug.cgi?id=21739
+ // Stop at the last break s.t. the following non-case statements are
+ // not merged into the current case. This can happen for
+ // case 1: ... break;
+ // debug { case 2: ... }
+ if (cur && cur.isBreakStatement())
+ break;
+ }
+ s = new AST.CompoundStatement(loc, statements);
+ }
+ else
+ {
+ s = cparseStatement(ParseStatementFlags.semi);
+ }
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ s = new AST.CaseStatement(loc, exp, s);
+ break;
+ }
+
+ case TOK.default_:
+ {
+ nextToken();
+ check(TOK.colon);
+
+ if (flags & ParseStatementFlags.curlyScope)
+ {
+ auto statements = new AST.Statements();
+ while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
+ {
+ statements.push(cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
+ }
+ s = new AST.CompoundStatement(loc, statements);
+ }
+ else
+ s = cparseStatement(ParseStatementFlags.semi);
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ s = new AST.DefaultStatement(loc, s);
+ break;
+ }
+
+ case TOK.return_:
+ {
+ /* return ;
+ * return expression ;
+ */
+ nextToken();
+ auto exp = token.value == TOK.semicolon ? null : cparseExpression();
+ check(TOK.semicolon, "`return` statement");
+ s = new AST.ReturnStatement(loc, exp);
+ break;
+ }
+
+ case TOK.break_:
+ nextToken();
+ check(TOK.semicolon, "`break` statement");
+ s = new AST.BreakStatement(loc, null);
+ break;
+
+ case TOK.continue_:
+ nextToken();
+ check(TOK.semicolon, "`continue` statement");
+ s = new AST.ContinueStatement(loc, null);
+ break;
+
+ case TOK.goto_:
+ {
+ Identifier ident;
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `goto`");
+ ident = null;
+ }
+ else
+ {
+ ident = token.ident;
+ nextToken();
+ }
+ s = new AST.GotoStatement(loc, ident);
+ check(TOK.semicolon, "`goto` statement");
+ break;
+ }
+
+ case TOK.asm_:
+ s = parseAsm();
+ break;
+
+ default:
+ error("found `%s` instead of statement", token.toChars());
+ goto Lerror;
+
+ Lerror:
+ panic();
+ if (token.value == TOK.semicolon)
+ nextToken();
+ s = null;
+ break;
+ }
+ if (pEndloc)
+ *pEndloc = prevloc;
+ symbols = symbolsSave;
+ return s;
+ }
+
+ //}
+ /*******************************************************************************/
+ /********************************* Expression Parser ***************************/
+ //{
+
+ /**************
+ * C11 6.5.17
+ * expression:
+ * assignment-expression
+ * expression , assignment-expression
+ */
+ AST.Expression cparseExpression()
+ {
+ auto loc = token.loc;
+
+ //printf("cparseExpression() loc = %d\n", loc.linnum);
+ auto e = cparseAssignExp();
+ while (token.value == TOK.comma)
+ {
+ nextToken();
+ auto e2 = cparseAssignExp();
+ e = new AST.CommaExp(loc, e, e2, false);
+ loc = token.loc;
+ }
+ return e;
+ }
+
+
+ /*********************
+ * C11 6.5.1
+ * primary-expression:
+ * identifier
+ * constant
+ * string-literal
+ * ( expression )
+ * generic-selection
+ */
+ AST.Expression cparsePrimaryExp()
+ {
+ AST.Expression e;
+ const loc = token.loc;
+
+ //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
+ switch (token.value)
+ {
+ case TOK.identifier:
+ if (token.ident is Id.__func__)
+ {
+ addFuncName = true; // implicitly declare __func__
+ }
+ e = new AST.IdentifierExp(loc, token.ident);
+ nextToken();
+ break;
+
+ case TOK.int32Literal:
+ e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint32);
+ nextToken();
+ break;
+
+ case TOK.uns32Literal:
+ e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32);
+ nextToken();
+ break;
+
+ case TOK.int64Literal:
+ e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint64);
+ nextToken();
+ break;
+
+ case TOK.uns64Literal:
+ e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns64);
+ nextToken();
+ break;
+
+ case TOK.float32Literal:
+ e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat32);
+ nextToken();
+ break;
+
+ case TOK.float64Literal:
+ e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat64);
+ nextToken();
+ break;
+
+ case TOK.float80Literal:
+ e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat80);
+ nextToken();
+ break;
+
+ case TOK.imaginary32Literal:
+ e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary32);
+ nextToken();
+ break;
+
+ case TOK.imaginary64Literal:
+ e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary64);
+ nextToken();
+ break;
+
+ case TOK.imaginary80Literal:
+ e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary80);
+ nextToken();
+ break;
+
+ case TOK.string_:
+ {
+ // cat adjacent strings
+ auto s = token.ustring;
+ auto len = token.len;
+ auto postfix = token.postfix;
+ while (1)
+ {
+ nextToken();
+ if (token.value == TOK.string_)
+ {
+ if (token.postfix)
+ {
+ if (token.postfix != postfix)
+ error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
+ postfix = token.postfix;
+ }
+
+ const len1 = len;
+ const len2 = token.len;
+ len = len1 + len2;
+ auto s2 = cast(char*)mem.xmalloc_noscan(len * char.sizeof);
+ memcpy(s2, s, len1 * char.sizeof);
+ memcpy(s2 + len1, token.ustring, len2 * char.sizeof);
+ s = s2;
+ }
+ else
+ break;
+ }
+ e = new AST.StringExp(loc, s[0 .. len], len, 1, postfix);
+ break;
+ }
+
+ case TOK.leftParenthesis:
+ nextToken();
+ e = cparseExpression();
+ check(TOK.rightParenthesis);
+ break;
+
+ case TOK._Generic:
+ e = cparseGenericSelection();
+ break;
+
+ default:
+ error("expression expected, not `%s`", token.toChars());
+ // Anything for e, as long as it's not NULL
+ e = new AST.IntegerExp(loc, 0, AST.Type.tint32);
+ nextToken();
+ break;
+ }
+ return e;
+ }
+
+ /*********************************
+ * C11 6.5.2
+ * postfix-expression:
+ * primary-expression
+ * postfix-expression [ expression ]
+ * postfix-expression ( argument-expression-list (opt) )
+ * postfix-expression . identifier
+ * postfix-expression -> identifier
+ * postfix-expression ++
+ * postfix-expression --
+ * ( type-name ) { initializer-list }
+ * ( type-name ) { initializer-list , }
+ *
+ * argument-expression-list:
+ * assignment-expression
+ * argument-expression-list , assignment-expression
+ */
+ private AST.Expression cparsePostfixExp(AST.Expression e)
+ {
+ e = cparsePrimaryExp();
+ return cparsePostfixOperators(e);
+ }
+
+ /********************************
+ * C11 6.5.2
+ * Parse a series of operators for a postfix expression after already parsing
+ * a primary-expression or compound literal expression.
+ * Params:
+ * e = parsed primary or compound literal expression
+ * Returns:
+ * parsed postfix expression
+ */
+ private AST.Expression cparsePostfixOperators(AST.Expression e)
+ {
+ while (1)
+ {
+ const loc = token.loc;
+ switch (token.value)
+ {
+ case TOK.dot:
+ case TOK.arrow:
+ nextToken();
+ if (token.value == TOK.identifier)
+ {
+ Identifier id = token.ident;
+ e = new AST.DotIdExp(loc, e, id);
+ break;
+ }
+ error("identifier expected following `.`, not `%s`", token.toChars());
+ break;
+
+ case TOK.plusPlus:
+ e = new AST.PostExp(TOK.plusPlus, loc, e);
+ break;
+
+ case TOK.minusMinus:
+ e = new AST.PostExp(TOK.minusMinus, loc, e);
+ break;
+
+ case TOK.leftParenthesis:
+ e = new AST.CallExp(loc, e, cparseArguments());
+ continue;
+
+ case TOK.leftBracket:
+ {
+ // array dereferences:
+ // array[index]
+ AST.Expression index;
+ auto arguments = new AST.Expressions();
+
+ inBrackets++;
+ nextToken();
+ index = cparseAssignExp();
+ arguments.push(index);
+ check(TOK.rightBracket);
+ inBrackets--;
+ e = new AST.ArrayExp(loc, e, arguments);
+ continue;
+ }
+ default:
+ return e;
+ }
+ nextToken();
+ }
+ }
+
+ /************************
+ * C11 6.5.3
+ * unary-expression:
+ * postfix-expression
+ * ++ unary-expression
+ * -- unary-expression
+ * unary-operator cast-expression
+ * sizeof unary-expression
+ * sizeof ( type-name )
+ * _Alignof ( type-name )
+ *
+ * unary-operator:
+ * & * + - ~ !
+ */
+ private AST.Expression cparseUnaryExp()
+ {
+ AST.Expression e;
+ const loc = token.loc;
+
+ switch (token.value)
+ {
+ case TOK.plusPlus:
+ nextToken();
+ // Parse `++` as an unary operator so that cast expressions only give
+ // an error for being non-lvalues.
+ e = cparseCastExp();
+ e = new AST.PreExp(TOK.prePlusPlus, loc, e);
+ break;
+
+ case TOK.minusMinus:
+ nextToken();
+ // Parse `--` as an unary operator, same as prefix increment.
+ e = cparseCastExp();
+ e = new AST.PreExp(TOK.preMinusMinus, loc, e);
+ break;
+
+ case TOK.and:
+ nextToken();
+ e = cparseCastExp();
+ e = new AST.AddrExp(loc, e);
+ break;
+
+ case TOK.mul:
+ nextToken();
+ e = cparseCastExp();
+ e = new AST.PtrExp(loc, e);
+ break;
+
+ case TOK.min:
+ nextToken();
+ e = cparseCastExp();
+ e = new AST.NegExp(loc, e);
+ break;
+
+ case TOK.add:
+ nextToken();
+ e = cparseCastExp();
+ e = new AST.UAddExp(loc, e);
+ break;
+
+ case TOK.not:
+ nextToken();
+ e = cparseCastExp();
+ e = new AST.NotExp(loc, e);
+ break;
+
+ case TOK.tilde:
+ nextToken();
+ e = cparseCastExp();
+ e = new AST.ComExp(loc, e);
+ break;
+
+ case TOK.sizeof_:
+ {
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ {
+ auto tk = peek(&token);
+ if (isTypeName(tk))
+ {
+ /* Expression may be either be requesting the sizeof a type-name
+ * or a compound literal, which requires checking whether
+ * the next token is leftCurly
+ */
+ nextToken();
+ auto t = cparseTypeName();
+ check(TOK.rightParenthesis);
+ if (token.value == TOK.leftCurly)
+ {
+ // ( type-name ) { initializer-list }
+ auto ci = cparseInitializer();
+ e = new AST.CompoundLiteralExp(loc, t, ci);
+ e = cparsePostfixOperators(e);
+ }
+ else
+ {
+ // ( type-name )
+ e = new AST.TypeExp(loc, t);
+ }
+ e = new AST.DotIdExp(loc, e, Id.__sizeof);
+ break;
+ }
+ }
+ e = cparseUnaryExp();
+ e = new AST.DotIdExp(loc, e, Id.__sizeof);
+ break;
+ }
+
+ case TOK._Alignof:
+ {
+ nextToken();
+ check(TOK.leftParenthesis);
+ auto t = cparseTypeName();
+ check(TOK.rightParenthesis);
+ e = new AST.TypeExp(loc, t);
+ e = new AST.DotIdExp(loc, e, Id.__xalignof);
+ break;
+ }
+
+ default:
+ e = cparsePostfixExp(e);
+ break;
+ }
+ assert(e);
+ return e;
+ }
+
+ /**************
+ * C11 6.5.4
+ * cast-expression
+ * unary-expression
+ * ( type-name ) cast-expression
+ */
+ private AST.Expression cparseCastExp()
+ {
+ if (token.value == TOK.leftParenthesis)
+ {
+ // If ( type-name )
+ auto pt = &token;
+ if (isCastExpression(pt))
+ {
+ // Expression may be either a cast or a compound literal, which
+ // requires checking whether the next token is leftCurly
+ const loc = token.loc;
+ nextToken();
+ auto t = cparseTypeName();
+ check(TOK.rightParenthesis);
+
+ if (token.value == TOK.leftCurly)
+ {
+ // C11 6.5.2.5 ( type-name ) { initializer-list }
+ auto ci = cparseInitializer();
+ auto ce = new AST.CompoundLiteralExp(loc, t, ci);
+ return cparsePostfixOperators(ce);
+ }
+ else
+ {
+ // ( type-name ) cast-expression
+ auto ce = cparseCastExp();
+ return new AST.CastExp(loc, ce, t);
+ }
+ }
+ }
+ return cparseUnaryExp();
+ }
+
+ /**************
+ * C11 6.5.5
+ * multiplicative-expression
+ * cast-expression
+ * multiplicative-expression * cast-expression
+ * multiplicative-expression / cast-expression
+ * multiplicative-expression % cast-expression
+ */
+ private AST.Expression cparseMulExp()
+ {
+ const loc = token.loc;
+ auto e = cparseCastExp();
+
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.mul:
+ nextToken();
+ auto e2 = cparseCastExp();
+ e = new AST.MulExp(loc, e, e2);
+ continue;
+
+ case TOK.div:
+ nextToken();
+ auto e2 = cparseCastExp();
+ e = new AST.DivExp(loc, e, e2);
+ continue;
+
+ case TOK.mod:
+ nextToken();
+ auto e2 = cparseCastExp();
+ e = new AST.ModExp(loc, e, e2);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ return e;
+ }
+
+ /**************
+ * C11 6.5.6
+ * additive-expression
+ * multiplicative-expression
+ * additive-expression + multiplicative-expression
+ * additive-expression - multiplicative-expression
+ */
+ private AST.Expression cparseAddExp()
+ {
+ const loc = token.loc;
+ auto e = cparseMulExp();
+
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.add:
+ nextToken();
+ auto e2 = cparseMulExp();
+ e = new AST.AddExp(loc, e, e2);
+ continue;
+
+ case TOK.min:
+ nextToken();
+ auto e2 = cparseMulExp();
+ e = new AST.MinExp(loc, e, e2);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ return e;
+ }
+
+ /**************
+ * C11 6.5.7
+ * shift-expression
+ * additive-expression
+ * shift-expression << additive-expression
+ * shift-expression >> additive-expression
+ */
+ private AST.Expression cparseShiftExp()
+ {
+ const loc = token.loc;
+ auto e = cparseAddExp();
+
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.leftShift:
+ nextToken();
+ auto e2 = cparseAddExp();
+ e = new AST.ShlExp(loc, e, e2);
+ continue;
+
+ case TOK.rightShift:
+ nextToken();
+ auto e2 = cparseAddExp();
+ e = new AST.ShrExp(loc, e, e2);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ return e;
+ }
+
+ /**************
+ * C11 6.5.8
+ * relational-expression
+ * shift-expression
+ * relational-expression < shift-expression
+ * relational-expression > shift-expression
+ * relational-expression <= shift-expression
+ * relational-expression >= shift-expression
+ */
+ private AST.Expression cparseRelationalExp()
+ {
+ const loc = token.loc;
+
+ auto e = cparseShiftExp();
+ TOK op = token.value;
+
+ switch (op)
+ {
+ case TOK.lessThan:
+ case TOK.lessOrEqual:
+ case TOK.greaterThan:
+ case TOK.greaterOrEqual:
+ nextToken();
+ auto e2 = cparseShiftExp();
+ e = new AST.CmpExp(op, loc, e, e2);
+ break;
+
+ default:
+ break;
+ }
+ return e;
+ }
+
+ /**************
+ * C11 6.5.9
+ * equality-expression
+ * relational-expression
+ * equality-expression == relational-expression
+ * equality-expression != relational-expression
+ */
+ private AST.Expression cparseEqualityExp()
+ {
+ const loc = token.loc;
+
+ auto e = cparseRelationalExp();
+ const TOK op = token.value;
+
+ switch (op)
+ {
+ case TOK.equal:
+ case TOK.notEqual:
+ nextToken();
+ auto e2 = cparseRelationalExp();
+ e = new AST.EqualExp(op, loc, e, e2);
+ break;
+
+ default:
+ break;
+ }
+ return e;
+ }
+
+ /**************
+ * C11 6.5.10
+ * AND-expression
+ * equality-expression
+ * AND-expression & equality-expression
+ */
+ private AST.Expression cparseAndExp()
+ {
+ Loc loc = token.loc;
+ auto e = cparseEqualityExp();
+ while (token.value == TOK.and)
+ {
+ nextToken();
+ auto e2 = cparseEqualityExp();
+ e = new AST.AndExp(loc, e, e2);
+ loc = token.loc;
+ }
+ return e;
+ }
+
+ /**************
+ * C11 6.5.11
+ * exclusive-OR-expression
+ * AND-expression
+ * exclusive-OR-expression ^ AND-expression
+ */
+ private AST.Expression cparseXorExp()
+ {
+ const loc = token.loc;
+
+ auto e = cparseAndExp();
+ while (token.value == TOK.xor)
+ {
+ nextToken();
+ auto e2 = cparseAndExp();
+ e = new AST.XorExp(loc, e, e2);
+ }
+ return e;
+ }
+
+ /**************
+ * C11 6.5.12
+ * inclusive-OR-expression
+ * exclusive-OR-expression
+ * inclusive-OR-expression | exclusive-OR-expression
+ */
+ private AST.Expression cparseOrExp()
+ {
+ const loc = token.loc;
+
+ auto e = cparseXorExp();
+ while (token.value == TOK.or)
+ {
+ nextToken();
+ auto e2 = cparseXorExp();
+ e = new AST.OrExp(loc, e, e2);
+ }
+ return e;
+ }
+
+ /**************
+ * C11 6.5.13
+ * logical-AND-expression
+ * inclusive-OR-expression
+ * logical-AND-expression && inclusive-OR-expression
+ */
+ private AST.Expression cparseAndAndExp()
+ {
+ const loc = token.loc;
+
+ auto e = cparseOrExp();
+ while (token.value == TOK.andAnd)
+ {
+ nextToken();
+ auto e2 = cparseOrExp();
+ e = new AST.LogicalExp(loc, TOK.andAnd, e, e2);
+ }
+ return e;
+ }
+
+ /**************
+ * C11 6.5.14
+ * logical-OR-expression
+ * logical-AND-expression
+ * logical-OR-expression || logical-AND-expression
+ */
+ private AST.Expression cparseOrOrExp()
+ {
+ const loc = token.loc;
+
+ auto e = cparseAndAndExp();
+ while (token.value == TOK.orOr)
+ {
+ nextToken();
+ auto e2 = cparseAndAndExp();
+ e = new AST.LogicalExp(loc, TOK.orOr, e, e2);
+ }
+ return e;
+ }
+
+ /**************
+ * C11 6.5.15
+ * conditional-expression:
+ * logical-OR-expression
+ * logical-OR-expression ? expression : conditional-expression
+ */
+ private AST.Expression cparseCondExp()
+ {
+ const loc = token.loc;
+
+ auto e = cparseOrOrExp();
+ if (token.value == TOK.question)
+ {
+ nextToken();
+ auto e1 = cparseExpression();
+ check(TOK.colon);
+ auto e2 = cparseCondExp();
+ e = new AST.CondExp(loc, e, e1, e2);
+ }
+ return e;
+ }
+
+ /**************
+ * C11 6.5.16
+ * assignment-expression:
+ * conditional-expression
+ * unary-expression assignment-operator assignment-expression
+ *
+ * assignment-operator:
+ * = *= /= %= += -= <<= >>= &= ^= |=
+ */
+ AST.Expression cparseAssignExp()
+ {
+ AST.Expression e;
+ e = cparseCondExp(); // constrain it to being unary-expression in semantic pass
+ if (e is null)
+ return e;
+
+ const loc = token.loc;
+ switch (token.value)
+ {
+ case TOK.assign:
+ nextToken();
+ auto e2 = cparseAssignExp();
+ e = new AST.AssignExp(loc, e, e2);
+ break;
+
+ case TOK.addAssign:
+ nextToken();
+ auto e2 = cparseAssignExp();
+ e = new AST.AddAssignExp(loc, e, e2);
+ break;
+
+ case TOK.minAssign:
+ nextToken();
+ auto e2 = cparseAssignExp();
+ e = new AST.MinAssignExp(loc, e, e2);
+ break;
+
+ case TOK.mulAssign:
+ nextToken();
+ auto e2 = cparseAssignExp();
+ e = new AST.MulAssignExp(loc, e, e2);
+ break;
+
+ case TOK.divAssign:
+ nextToken();
+ auto e2 = cparseAssignExp();
+ e = new AST.DivAssignExp(loc, e, e2);
+ break;
+
+ case TOK.modAssign:
+ nextToken();
+ auto e2 = cparseAssignExp();
+ e = new AST.ModAssignExp(loc, e, e2);
+ break;
+
+ case TOK.andAssign:
+ nextToken();
+ auto e2 = cparseAssignExp();
+ e = new AST.AndAssignExp(loc, e, e2);
+ break;
+
+ case TOK.orAssign:
+ nextToken();
+ auto e2 = cparseAssignExp();
+ e = new AST.OrAssignExp(loc, e, e2);
+ break;
+
+ case TOK.xorAssign:
+ nextToken();
+ auto e2 = cparseAssignExp();
+ e = new AST.XorAssignExp(loc, e, e2);
+ break;
+
+ case TOK.leftShiftAssign:
+ nextToken();
+ auto e2 = cparseAssignExp();
+ e = new AST.ShlAssignExp(loc, e, e2);
+ break;
+
+ case TOK.rightShiftAssign:
+ nextToken();
+ auto e2 = cparseAssignExp();
+ e = new AST.ShrAssignExp(loc, e, e2);
+ break;
+
+ default:
+ break;
+ }
+
+ return e;
+ }
+
+ /***********************
+ * C11 6.5.1.1
+ * _Generic ( assignment-expression, generic-assoc-list )
+ *
+ * generic-assoc-list:
+ * generic-association
+ * generic-assoc-list generic-association
+ *
+ * generic-association:
+ * type-name : assignment-expression
+ * default : assignment-expression
+ */
+ private AST.Expression cparseGenericSelection()
+ {
+ const loc = token.loc;
+ nextToken();
+ check(TOK.leftParenthesis);
+ auto cntlExp = cparseAssignExp();
+ check(TOK.comma);
+ auto types = new AST.Types();
+ auto exps = new AST.Expressions();
+ bool sawDefault;
+ while (1)
+ {
+ AST.Type t;
+ if (token.value == TOK.default_)
+ {
+ nextToken();
+ if (sawDefault)
+ error("only one `default` allowed in generic-assoc-list");
+ sawDefault = true;
+ t = null;
+ }
+ else
+ t = cparseTypeName();
+ types.push(t);
+
+ check(TOK.colon);
+ auto e = cparseAssignExp();
+ exps.push(e);
+ if (token.value == TOK.rightParenthesis || token.value == TOK.endOfFile)
+ break;
+ check(TOK.comma);
+ }
+ check(TOK.rightParenthesis);
+ return new AST.GenericExp(loc, cntlExp, types, exps);
+ }
+
+ /***********************
+ * C11 6.6 Constant expressions
+ * constant-expression:
+ * conditional-expression
+ */
+ private AST.Expression cparseConstantExp()
+ {
+ return cparseAssignExp();
+ }
+
+ //}
+ /********************************************************************************/
+ /********************************* Declaration Parser ***************************/
+ //{
+
+ /*************************************
+ * C11 6.7
+ * declaration:
+ * declaration-specifiers init-declarator-list (opt) ;
+ * static_assert-declaration
+ *
+ * init-declarator-list:
+ * init-declarator
+ * init-declarator-list , init-declarator
+ *
+ * init-declarator:
+ * declarator
+ * declarator = initializer
+ *
+ * Params:
+ * level = declaration context
+ */
+ void cparseDeclaration(LVL level)
+ {
+ //printf("cparseDeclaration(level = %d)\n", level);
+ if (token.value == TOK._Static_assert)
+ {
+ auto s = cparseStaticAssert();
+ symbols.push(s);
+ return;
+ }
+
+ auto symbolsSave = symbols;
+ Specifier specifier;
+ auto tspec = cparseDeclarationSpecifiers(level, specifier);
+
+ /* If a declarator does not follow, it is unnamed
+ */
+ if (token.value == TOK.semicolon && tspec)
+ {
+ nextToken();
+ auto tt = tspec.isTypeTag();
+ if (!tt || !tt.id)
+ return; // legal but meaningless empty declaration, ignore it
+
+ /* `struct tag;` and `struct tag { ... };`
+ * always result in a declaration in the current scope
+ */
+ auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) :
+ (tt.tok == TOK.union_) ? new AST.UnionDeclaration(tt.loc, tt.id) :
+ new AST.EnumDeclaration(tt.loc, tt.id, AST.Type.tint32);
+ stag.members = tt.members;
+ if (!symbols)
+ symbols = new AST.Dsymbols();
+ auto stags = applySpecifier(stag, specifier);
+ symbols.push(stags);
+
+ if (tt.tok == TOK.enum_)
+ {
+ if (!tt.members)
+ error(tt.loc, "`enum %s` has no members", stag.toChars());
+ }
+ return;
+ }
+
+ if (tspec && specifier.mod & MOD.xconst)
+ {
+ tspec = toConst(tspec);
+ specifier.mod = MOD.xnone; // 'used' it
+ }
+
+ bool first = true;
+ while (1)
+ {
+ Identifier id;
+ AST.Expression asmname;
+ auto dt = cparseDeclarator(DTR.xdirect, tspec, id);
+ if (!dt)
+ {
+ panic();
+ nextToken();
+ break; // error recovery
+ }
+
+ /* GNU Extensions
+ * init-declarator:
+ * declarator simple-asm-expr (opt) gnu-attributes (opt)
+ * declarator simple-asm-expr (opt) gnu-attributes (opt) = initializer
+ */
+ switch (token.value)
+ {
+ case TOK.assign:
+ case TOK.comma:
+ case TOK.semicolon:
+ case TOK.asm_:
+ case TOK.__attribute__:
+ /* This is a data definition, there cannot now be a
+ * function definition.
+ */
+ first = false;
+ if (token.value == TOK.asm_)
+ asmname = cparseSimpleAsmExpr();
+ if (token.value == TOK.__attribute__)
+ {
+ cparseGnuAttributes(specifier);
+ if (token.value == TOK.leftCurly)
+ {
+ error("attributes should be specified before the function definition");
+ auto t = &token;
+ if (skipBraces(t))
+ {
+ token = *t;
+ return;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (specifier.alignExps && dt.isTypeFunction())
+ error("no alignment-specifier for function declaration"); // C11 6.7.5-2
+ if (specifier.alignExps && specifier.scw == SCW.xregister)
+ error("no alignment-specifier for `register` storage class"); // C11 6.7.5-2
+
+ /* C11 6.9.1 Function Definitions
+ * function-definition:
+ * declaration-specifiers declarator declaration-list (opt) compound-statement
+ *
+ * declaration-list:
+ * declaration
+ * declaration-list declaration
+ */
+ auto t = &token;
+ if (first && // first declarator
+ id &&
+ dt.isTypeFunction() && // function type not inherited from a typedef
+ isDeclarationList(t) && // optional declaration-list
+ level == LVL.global && // function definitions only at global scope
+ t.value == TOK.leftCurly) // start of compound-statement
+ {
+ auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier);
+ symbols = symbolsSave;
+ symbols.push(s);
+ return;
+ }
+ AST.Dsymbol s = null;
+ symbols = symbolsSave;
+ if (!symbols)
+ symbols = new AST.Dsymbols; // lazilly create it
+
+ if (level != LVL.global && !tspec && !specifier.scw && !specifier.mod)
+ error("declaration-specifier-seq required");
+ else if (specifier.scw == SCW.xtypedef)
+ {
+ if (token.value == TOK.assign)
+ error("no initializer for typedef declaration");
+ if (specifier.alignExps)
+ error("no alignment-specifier for typedef declaration"); // C11 6.7.5-2
+
+ bool isalias = true;
+ if (auto ts = dt.isTypeStruct())
+ {
+ if (ts.sym.isAnonymous())
+ {
+ // This is a typedef for an anonymous struct-or-union.
+ // Directly set the ident for the struct-or-union.
+ ts.sym.ident = id;
+ isalias = false;
+ }
+ }
+ else if (auto te = dt.isTypeEnum())
+ {
+ if (te.sym.isAnonymous())
+ {
+ // This is a typedef for an anonymous enum.
+ te.sym.ident = id;
+ isalias = false;
+ }
+ }
+ if (isalias)
+ s = new AST.AliasDeclaration(token.loc, id, dt);
+ }
+ else if (id)
+ {
+ if (level == LVL.prototype)
+ break; // declared later as Parameter, not VarDeclaration
+
+ if (dt.ty == AST.Tvoid)
+ error("`void` has no value");
+
+ AST.Initializer initializer;
+ bool hasInitializer;
+ if (token.value == TOK.assign)
+ {
+ nextToken();
+ hasInitializer = true;
+ initializer = cparseInitializer();
+ }
+ // declare the symbol
+ assert(id);
+ if (dt.isTypeFunction())
+ {
+ if (hasInitializer)
+ error("no initializer for function declaration");
+ if (specifier.scw & SCW.x_Thread_local)
+ error("functions cannot be `_Thread_local`"); // C11 6.7.1-4
+ auto fd = new AST.FuncDeclaration(token.loc, Loc.initial, id, specifiersToSTC(level, specifier), dt, specifier.noreturn);
+ s = fd;
+ }
+ else
+ {
+ // Give non-extern variables an implicit void initializer
+ // if one has not been explicitly set.
+ if (!hasInitializer && !(specifier.scw & SCW.xextern))
+ initializer = new AST.VoidInitializer(token.loc);
+ s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(level, specifier));
+ }
+ }
+ if (s !is null)
+ {
+ s = applySpecifier(s, specifier);
+ if (level == LVL.local)
+ {
+ // Wrap the declaration in `extern (C) { declaration }`
+ // Necessary for function pointers, but harmless to apply to all.
+ auto decls = new AST.Dsymbols(1);
+ (*decls)[0] = s;
+ s = new AST.LinkDeclaration(s.loc, linkage, decls);
+ }
+ // Saw `asm("name")` in the function, type, or variable definition.
+ // This maps directly to `pragma(mangle, "name")`
+ if (asmname)
+ {
+ auto args = new AST.Expressions(1);
+ (*args)[0] = asmname;
+ auto decls = new AST.Dsymbols(1);
+ (*decls)[0] = s;
+ s = new AST.PragmaDeclaration(asmname.loc, Id.mangle, args, decls);
+ }
+ symbols.push(s);
+ }
+ first = false;
+
+ switch (token.value)
+ {
+ case TOK.identifier:
+ error("missing comma");
+ goto default;
+
+ case TOK.semicolon:
+ nextToken();
+ return;
+
+ case TOK.comma:
+ nextToken();
+ break;
+
+ default:
+ error("`=`, `;` or `,` expected");
+ while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
+ nextToken();
+ nextToken();
+ return;
+ }
+ }
+ }
+
+ /***************************************
+ * C11 Function Definitions
+ * function-definition
+ * declaration-specifiers declarator declaration-list (opt) compound-statement
+ *
+ * declaration-list:
+ * declaration
+ * declaration-list declaration
+ *
+ * It's already been parsed up to the declaration-list (opt).
+ * Pick it up from there.
+ * Params:
+ * id = function identifier
+ * ft = function type
+ * specifier = function specifiers
+ * Returns:
+ * Dsymbol for the function
+ */
+ AST.Dsymbol cparseFunctionDefinition(Identifier id, AST.TypeFunction ft, ref Specifier specifier)
+ {
+ if (token.value != TOK.leftCurly) // if not start of a compound-statement
+ {
+ // Do declaration-list
+ do
+ {
+ cparseDeclaration(LVL.parameter);
+ } while (token.value != TOK.leftCurly);
+
+ /* Since there were declarations, the parameter-list must have been
+ * an identifier-list.
+ */
+ auto pl = ft.parameterList;
+ pl.hasIdentifierList = true; // semantic needs to know to adjust parameter types
+ if (pl.varargs != AST.VarArg.none)
+ error("function identifier-list cannot end with `...`");
+ auto plLength = pl.length;
+ if (symbols.length != plLength)
+ error("%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length);
+
+ /* Transfer the types and storage classes from symbols[] to pl[]
+ */
+ foreach (i; 0 .. plLength)
+ {
+ auto p = pl[i]; // yes, quadratic
+
+ // Convert typedef-identifier to identifier
+ if (p.type)
+ {
+ if (auto t = p.type.isTypeIdentifier())
+ {
+ p.ident = t.ident;
+ p.type = null;
+ }
+ }
+
+ if (p.type || !(p.storageClass & STC.parameter))
+ error("storage class and type are not allowed in identifier-list");
+ foreach (s; (*symbols)[]) // yes, quadratic
+ {
+ auto d = s.isDeclaration();
+ if (d && p.ident == d.ident && d.type)
+ {
+ p.type = d.type;
+ p.storageClass = d.storage_class;
+ d.type = null; // don't reuse
+ break;
+ }
+ }
+ if (!p.type)
+ error("no declaration for identifier `%s`", p.ident.toChars());
+ }
+ }
+
+ addFuncName = false; // gets set to true if somebody references __func__ in this function
+ const locFunc = token.loc;
+
+ auto body = cparseStatement(ParseStatementFlags.curly); // don't start a new scope; continue with parameter scope
+ auto fd = new AST.FuncDeclaration(locFunc, prevloc, id, specifiersToSTC(LVL.global, specifier), ft, specifier.noreturn);
+
+ if (addFuncName)
+ {
+ auto s = createFuncName(locFunc, id);
+ body = new AST.CompoundStatement(locFunc, s, body);
+ }
+ fd.fbody = body;
+
+ // TODO add `symbols` to the function's local symbol table `sc2` in FuncDeclaration::semantic3()
+
+ return fd;
+ }
+
+ /***************************************
+ * C11 Initialization
+ * initializer:
+ * assignment-expression
+ * { initializer-list }
+ * { initializer-list , }
+ *
+ * initializer-list:
+ * designation (opt) initializer
+ * initializer-list , designation (opt) initializer
+ *
+ * designation:
+ * designator-list =
+ *
+ * designator-list:
+ * designator
+ * designator-list designator
+ *
+ * designator:
+ * [ constant-expression ]
+ * . identifier
+ * Returns:
+ * initializer
+ */
+ AST.Initializer cparseInitializer()
+ {
+ if (token.value != TOK.leftCurly)
+ {
+ auto ae = cparseAssignExp(); // assignment-expression
+ return new AST.ExpInitializer(token.loc, ae);
+ }
+ nextToken();
+ const loc = token.loc;
+
+ /* Collect one or more `designation (opt) initializer`
+ * into ci.initializerList, but lazily create ci
+ */
+ AST.CInitializer ci;
+ while (1)
+ {
+ /* There can be 0 or more designators preceding an initializer.
+ * Collect them in desigInit
+ */
+ AST.DesigInit desigInit;
+ while (1)
+ {
+ if (token.value == TOK.leftBracket) // [ constant-expression ]
+ {
+ nextToken();
+ auto e = cparseConstantExp();
+ check(TOK.rightBracket);
+ if (!desigInit.designatorList)
+ desigInit.designatorList = new AST.Designators;
+ desigInit.designatorList.push(AST.Designator(e));
+ }
+ else if (token.value == TOK.dot) // . identifier
+ {
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `.` designator");
+ break;
+ }
+ if (!desigInit.designatorList)
+ desigInit.designatorList = new AST.Designators;
+ desigInit.designatorList.push(AST.Designator(token.ident));
+ nextToken();
+ }
+ else
+ {
+ if (desigInit.designatorList)
+ check(TOK.assign);
+ break;
+ }
+ }
+
+ desigInit.initializer = cparseInitializer();
+ if (!ci)
+ ci = new AST.CInitializer(loc);
+ ci.initializerList.push(desigInit);
+ if (token.value == TOK.comma)
+ {
+ nextToken();
+ if (token.value != TOK.rightCurly)
+ continue;
+ }
+ break;
+ }
+ check(TOK.rightCurly);
+ //printf("ci: %s\n", ci.toChars());
+ return ci;
+ }
+
+ /*************************************
+ * C11 6.7
+ * declaration-specifier:
+ * storage-class-specifier declaration-specifiers (opt)
+ * type-specifier declaration-specifiers (opt)
+ * type-qualifier declaration-specifiers (opt)
+ * function-specifier declaration-specifiers (opt)
+ * alignment-specifier declaration-specifiers (opt)
+ * Params:
+ * level = declaration context
+ * specifier = specifiers in and out
+ * Returns:
+ * resulting type, null if not specified
+ */
+ private AST.Type cparseDeclarationSpecifiers(LVL level, ref Specifier specifier)
+ {
+ enum TKW : uint
+ {
+ xnone = 0,
+ xchar = 1,
+ xsigned = 2,
+ xunsigned = 4,
+ xshort = 8,
+ xint = 0x10,
+ xlong = 0x20,
+ xllong = 0x40,
+ xfloat = 0x80,
+ xdouble = 0x100,
+ xldouble = 0x200,
+ xtag = 0x400,
+ xident = 0x800,
+ xvoid = 0x1000,
+ xbool = 0x4000,
+ ximaginary = 0x8000,
+ xcomplex = 0x10000,
+ x_Atomic = 0x20000,
+ }
+
+ AST.Type t;
+ Loc loc;
+ //printf("parseDeclarationSpecifiers()\n");
+
+ TKW tkw;
+ SCW scw = specifier.scw & SCW.xtypedef;
+ MOD mod;
+ Identifier id;
+ Identifier previd;
+
+ Lwhile:
+ while (1)
+ {
+ //printf("token %s\n", token.toChars());
+ TKW tkwx;
+ SCW scwx;
+ MOD modx;
+ switch (token.value)
+ {
+ // Storage class specifiers
+ case TOK.static_: scwx = SCW.xstatic; break;
+ case TOK.extern_: scwx = SCW.xextern; break;
+ case TOK.auto_: scwx = SCW.xauto; break;
+ case TOK.register: scwx = SCW.xregister; break;
+ case TOK.typedef_: scwx = SCW.xtypedef; break;
+ case TOK.inline: scwx = SCW.xinline; break;
+ case TOK._Noreturn: scwx = SCW.x_Noreturn; break;
+ case TOK._Thread_local: scwx = SCW.x_Thread_local; break;
+
+ // Type qualifiers
+ case TOK.const_: modx = MOD.xconst; break;
+ case TOK.volatile: modx = MOD.xvolatile; break;
+ case TOK.restrict: modx = MOD.xrestrict; break;
+
+ // Type specifiers
+ case TOK.char_: tkwx = TKW.xchar; break;
+ case TOK.signed: tkwx = TKW.xsigned; break;
+ case TOK.unsigned: tkwx = TKW.xunsigned; break;
+ case TOK.int16: tkwx = TKW.xshort; break;
+ case TOK.int32: tkwx = TKW.xint; break;
+ case TOK.int64: tkwx = TKW.xlong; break;
+ case TOK.float32: tkwx = TKW.xfloat; break;
+ case TOK.float64: tkwx = TKW.xdouble; break;
+ case TOK.void_: tkwx = TKW.xvoid; break;
+ case TOK._Bool: tkwx = TKW.xbool; break;
+ case TOK._Imaginary: tkwx = TKW.ximaginary; break;
+ case TOK._Complex: tkwx = TKW.xcomplex; break;
+
+ case TOK.identifier:
+ tkwx = TKW.xident;
+ id = token.ident;
+ break;
+
+ case TOK.struct_:
+ case TOK.union_:
+ {
+ const structOrUnion = token.value;
+ const sloc = token.loc;
+ nextToken();
+
+ /* GNU Extensions
+ * struct-or-union-specifier:
+ * struct-or-union gnu-attributes (opt) identifier (opt) { struct-declaration-list } gnu-attributes (opt)
+ * struct-or-union gnu-attribute (opt) identifier
+ */
+ if (token.value == TOK.__attribute__)
+ cparseGnuAttributes(specifier);
+
+ t = cparseStruct(sloc, structOrUnion, symbols);
+ tkwx = TKW.xtag;
+ break;
+ }
+
+ case TOK.enum_:
+ t = cparseEnum(symbols);
+ tkwx = TKW.xtag;
+ break;
+
+ case TOK._Atomic:
+ {
+ // C11 6.7.2.4
+ // type-specifier if followed by `( type-name )`
+ auto tk = peek(&token);
+ if (tk.value == TOK.leftParenthesis)
+ {
+ tk = peek(tk);
+ if (isTypeName(tk) && tk.value == TOK.rightParenthesis)
+ {
+ nextToken();
+ t = cparseTypeName();
+ // TODO - implement the "atomic" part of t
+ tkwx = TKW.x_Atomic;
+ break;
+ }
+ }
+ // C11 6.7.3 type-qualifier if not
+ modx = MOD.x_Atomic;
+ break;
+ }
+
+ case TOK._Alignas:
+ {
+ /* C11 6.7.5
+ * _Alignas ( type-name )
+ * _Alignas ( constant-expression )
+ */
+
+ if (level & (LVL.parameter | LVL.prototype))
+ error("no alignment-specifier for parameters"); // C11 6.7.5-2
+
+ nextToken();
+ check(TOK.leftParenthesis);
+ AST.Expression exp;
+ auto tk = &token;
+ if (isTypeName(tk)) // _Alignas ( type-name )
+ {
+ auto talign = cparseTypeName();
+ /* Convert type to expression: `talign.alignof`
+ */
+ auto e = new AST.TypeExp(loc, talign);
+ exp = new AST.DotIdExp(loc, e, Id.__xalignof);
+ }
+ else // _Alignas ( constant-expression )
+ {
+ exp = cparseConstantExp();
+ }
+
+ if (!specifier.alignExps)
+ specifier.alignExps = new AST.Expressions(0);
+ specifier.alignExps.push(exp);
+
+ check(TOK.rightParenthesis);
+ break;
+ }
+
+ case TOK.__attribute__:
+ {
+ /* GNU Extensions
+ * declaration-specifiers:
+ * gnu-attributes declaration-specifiers (opt)
+ */
+ cparseGnuAttributes(specifier);
+ break;
+ }
+
+ default:
+ break Lwhile;
+ }
+
+ if (tkwx)
+ {
+ if (tkw & TKW.xlong && tkwx & TKW.xlong)
+ {
+ tkw &= ~TKW.xlong;
+ tkwx = TKW.xllong;
+ }
+ if (tkw && tkwx & TKW.xident)
+ {
+ // 2nd identifier can't be a typedef
+ break Lwhile; // leave parser on the identifier for the following declarator
+ }
+ else if (tkwx & TKW.xident)
+ {
+ // 1st identifier, save it for TypeIdentifier
+ previd = id;
+ }
+ if (tkw & TKW.xident && tkwx || // typedef-name followed by type-specifier
+ tkw & tkwx) // duplicate type-specifiers
+ {
+ error("illegal combination of type specifiers");
+ tkwx = TKW.init;
+ }
+ tkw |= tkwx;
+ if (!(tkwx & TKW.xtag)) // if parser already advanced
+ nextToken();
+ continue;
+ }
+
+ if (modx)
+ {
+ mod |= modx;
+ nextToken();
+ continue;
+ }
+
+ if (scwx)
+ {
+ if (scw & scwx)
+ error("duplicate storage class");
+ scw |= scwx;
+ const scw2 = scw & (SCW.xstatic | SCW.xextern | SCW.xauto | SCW.xregister | SCW.xtypedef);
+ if (scw2 & (scw2 - 1) ||
+ scw & (SCW.xauto | SCW.xregister) && scw & (SCW.xinline | SCW.x_Noreturn))
+ {
+ error("conflicting storage class");
+ scw &= ~scwx;
+ }
+ if (level & (LVL.parameter | LVL.prototype) &&
+ scw & ~SCW.xregister)
+ {
+ error("only `register` storage class allowed for function parameters");
+ scw &= ~scwx;
+ }
+ if (level == LVL.global &&
+ scw & (SCW.xauto | SCW.xregister))
+ {
+ error("`auto` and `register` storage class not allowed for global");
+ scw &= ~scwx;
+ }
+ nextToken();
+ continue;
+ }
+ }
+
+ specifier.scw = scw;
+ specifier.mod = mod;
+
+ // Convert TKW bits to type t
+ switch (tkw)
+ {
+ case TKW.xnone: t = null; break;
+
+ case TKW.xchar: t = AST.Type.tchar; break;
+ case TKW.xsigned | TKW.xchar: t = AST.Type.tint8; break;
+ case TKW.xunsigned | TKW.xchar: t = AST.Type.tuns8; break;
+
+ case TKW.xshort:
+ case TKW.xsigned | TKW.xshort:
+ case TKW.xsigned | TKW.xshort | TKW.xint:
+ case TKW.xshort | TKW.xint: t = AST.Type.tint16; break;
+
+ case TKW.xunsigned | TKW.xshort | TKW.xint:
+ case TKW.xunsigned | TKW.xshort: t = AST.Type.tuns16; break;
+
+ case TKW.xint:
+ case TKW.xsigned:
+ case TKW.xsigned | TKW.xint: t = AST.Type.tint32; break;
+
+ case TKW.xunsigned:
+ case TKW.xunsigned | TKW.xint: t = AST.Type.tuns32; break;
+
+ case TKW.xlong:
+ case TKW.xsigned | TKW.xlong:
+ case TKW.xsigned | TKW.xlong | TKW.xint:
+ case TKW.xlong | TKW.xint: t = longsize == 4 ? AST.Type.tint32 : AST.Type.tint64; break;
+
+ case TKW.xunsigned | TKW.xlong | TKW.xint:
+ case TKW.xunsigned | TKW.xlong: t = longsize == 4 ? AST.Type.tuns32 : AST.Type.tuns64; break;
+
+ case TKW.xllong:
+ case TKW.xsigned | TKW.xllong:
+ case TKW.xsigned | TKW.xllong | TKW.xint:
+ case TKW.xllong | TKW.xint: t = AST.Type.tint64; break;
+
+ case TKW.xunsigned | TKW.xllong | TKW.xint:
+ case TKW.xunsigned | TKW.xllong: t = AST.Type.tuns64; break;
+
+ case TKW.xvoid: t = AST.Type.tvoid; break;
+ case TKW.xbool: t = AST.Type.tbool; break;
+
+ case TKW.xfloat: t = AST.Type.tfloat32; break;
+ case TKW.xdouble: t = AST.Type.tfloat64; break;
+ case TKW.xlong | TKW.xdouble: t = realType(RTFlags.realfloat); break;
+
+ case TKW.ximaginary | TKW.xfloat: t = AST.Type.timaginary32; break;
+ case TKW.ximaginary | TKW.xdouble: t = AST.Type.timaginary64; break;
+ case TKW.ximaginary | TKW.xlong | TKW.xdouble: t = realType(RTFlags.imaginary); break;
+
+ case TKW.xcomplex | TKW.xfloat: t = AST.Type.tcomplex32; break;
+ case TKW.xcomplex | TKW.xdouble: t = AST.Type.tcomplex64; break;
+ case TKW.xcomplex | TKW.xlong | TKW.xdouble: t = realType(RTFlags.complex); break;
+
+ case TKW.xident: t = new AST.TypeIdentifier(loc, previd);
+ break;
+
+ case TKW.xtag:
+ break; // t is already set
+
+ default:
+ error("illegal type combination");
+ t = AST.Type.terror;
+ break;
+ }
+
+ return t;
+ }
+
+ /********************************
+ * C11 6.7.6
+ * Parse a declarator (including function definitions).
+ * declarator:
+ * pointer (opt) direct-declarator
+ *
+ * direct-declarator :
+ * identifier
+ * ( declarator )
+ * direct-declarator [ type-qualifier-list (opt) assignment-expression (opt) ]
+ * direct-declarator [ static type-qualifier-list (opt) assignment-expression ]
+ * direct-declarator [ type-qualifier-list static assignment-expression (opt) ]
+ * direct-declarator [ type-qualifier-list (opt) * ]
+ * direct-declarator ( parameter-type-list )
+ * direct-declarator ( identifier-list (opt) )
+ *
+ * pointer :
+ * * type-qualifier-list (opt)
+ * * type-qualifier-list (opt) pointer
+ *
+ * type-qualifier-list :
+ * type-qualifier
+ * type-qualifier-list type-qualifier
+ *
+ * parameter-type-list :
+ * parameter-list
+ * parameter-list , ...
+ *
+ * parameter-list :
+ * parameter-declaration
+ * parameter-list , parameter-declaration
+ *
+ * parameter-declaration :
+ * declaration-specifiers declarator
+ * declaration-specifiers abstract-declarator (opt)
+ *
+ * identifier-list :
+ * identifier
+ * identifier-list , identifier
+ *
+ * Params:
+ * declarator = declarator kind
+ * t = base type to start with
+ * pident = set to Identifier if there is one, null if not
+ * storageClass = any storage classes seen so far that apply to a function
+ * Returns:
+ * type declared. If a TypeFunction is returned, this.symbols is the
+ * symbol table for the parameter-type-list, which will contain any
+ * declared struct, union or enum tags.
+ */
+ private AST.Type cparseDeclarator(DTR declarator, AST.Type t,
+ out Identifier pident, StorageClass storageClass = 0)
+ {
+ //printf("cparseDeclarator(%d)\n", declarator);
+ AST.Types constTypes; // all the Types that will need `const` applied to them
+ constTypes.setDim(0);
+
+ AST.Type parseDecl(AST.Type t)
+ {
+ AST.Type ts;
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.identifier: // identifier
+ //printf("identifier %s\n", token.ident.toChars());
+ if (declarator == DTR.xabstract)
+ error("identifier not allowed in abstract-declarator");
+ pident = token.ident;
+ ts = t;
+ nextToken();
+ break;
+
+ case TOK.leftParenthesis: // ( declarator )
+ /* like: T (*fp)();
+ * T ((*fp))();
+ */
+ nextToken();
+ ts = parseDecl(t);
+ check(TOK.rightParenthesis);
+ break;
+
+ case TOK.mul: // pointer
+ t = new AST.TypePointer(t);
+ nextToken();
+ // add post fixes const/volatile/restrict/_Atomic
+ const mod = cparseTypeQualifierList();
+ if (mod & MOD.xconst)
+ constTypes.push(t);
+ continue;
+
+ default:
+ if (declarator == DTR.xdirect)
+ {
+ error("identifier or `(` expected"); // )
+ panic();
+ }
+ ts = t;
+ break;
+ }
+ break;
+ }
+
+ // parse DeclaratorSuffixes
+ while (1)
+ {
+ /* Insert tx -> t into
+ * ts -> ... -> t
+ * so that
+ * ts -> ... -> tx -> t
+ */
+ static void insertTx(ref AST.Type ts, AST.Type tx, AST.Type t)
+ {
+ AST.Type* pt;
+ for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next)
+ {
+ }
+ *pt = tx;
+ }
+
+ switch (token.value)
+ {
+ case TOK.leftBracket:
+ {
+ // post [] syntax, pick up any leading type qualifiers, `static` and `*`
+ AST.Type ta;
+ nextToken();
+
+ auto mod = cparseTypeQualifierList(); // const/volatile/restrict/_Atomic
+
+ bool isStatic;
+ bool isVLA;
+ if (token.value == TOK.static_)
+ {
+ isStatic = true; // `static`
+ nextToken();
+ if (!mod) // type qualifiers after `static`
+ mod = cparseTypeQualifierList();
+ }
+ else if (token.value == TOK.mul)
+ {
+ if (peekNext() == TOK.rightBracket)
+ {
+ isVLA = true; // `*`
+ nextToken();
+ }
+ }
+
+ if (isStatic || token.value != TOK.rightBracket)
+ {
+ //printf("It's a static array\n");
+ AST.Expression e = cparseAssignExp(); // [ expression ]
+ ta = new AST.TypeSArray(t, e);
+ }
+ else
+ {
+ // An array of unknown size, fake it with a DArray
+ ta = new AST.TypeDArray(t); // []
+ }
+ check(TOK.rightBracket);
+
+ // Issue errors for unsupported types.
+ if (isVLA) // C11 6.7.6.2
+ {
+ error("variable length arrays are not supported");
+ }
+ if (isStatic) // C11 6.7.6.3
+ {
+ error("static array parameters are not supported");
+ }
+ if (declarator != DTR.xparameter)
+ {
+ /* C11 6.7.6.2-4: '*' can only be used with function prototype scope.
+ */
+ if (isVLA)
+ error("variable length array used outside of function prototype");
+ /* C11 6.7.6.2-1: type qualifiers and 'static' shall only appear
+ * in a declaration of a function parameter with an array type.
+ */
+ if (isStatic || mod)
+ error("static or type qualifier used outside of function prototype");
+ }
+ if (ts.isTypeSArray() || ts.isTypeDArray())
+ {
+ /* C11 6.7.6.2-1: type qualifiers and 'static' shall only appear
+ * in the outermost array type derivation.
+ */
+ if (isStatic || mod)
+ error("static or type qualifier used in non-outermost array type derivation");
+ /* C11 6.7.6.2-1: the element type shall not be an incomplete or
+ * function type.
+ */
+ if (ta.isTypeDArray() && !isVLA)
+ error("array type has incomplete element type `%s`", ta.toChars());
+ }
+
+ // Apply type qualifiers to the constructed type.
+ if (mod & MOD.xconst) // ignore the other bits
+ ta = toConst(ta);
+ insertTx(ts, ta, t); // ts -> ... -> ta -> t
+ continue;
+ }
+
+ case TOK.leftParenthesis:
+ {
+ // New symbol table for parameter-list
+ auto symbolsSave = this.symbols;
+ this.symbols = null;
+
+ auto parameterList = cparseParameterList();
+ AST.Type tf = new AST.TypeFunction(parameterList, t, linkage, 0);
+ // tf = tf.addSTC(storageClass); // TODO
+ insertTx(ts, tf, t); // ts -> ... -> tf -> t
+
+ if (ts != tf)
+ this.symbols = symbolsSave;
+ break;
+ }
+
+ default:
+ break;
+ }
+ break;
+ }
+ return ts;
+ }
+
+ t = parseDecl(t);
+
+ /* Because const is transitive, cannot assemble types from
+ * fragments. Instead, types to be annotated with const are put
+ * in constTypes[], and a bottom up scan of t is done to apply
+ * const
+ */
+ if (constTypes.length)
+ {
+ AST.Type constApply(AST.Type t)
+ {
+ if (t.nextOf())
+ {
+ auto tn = cast(AST.TypeNext)t; // t.nextOf() should return a ref instead of this
+ tn.next = constApply(tn.next);
+ }
+ foreach (tc; constTypes[])
+ {
+ if (tc is t)
+ {
+ return toConst(t);
+ }
+ }
+ return t;
+ }
+
+ t = constApply(t);
+ }
+
+ //printf("result: %s\n", t.toChars());
+ return t;
+ }
+
+ /******************************
+ * C11 6.7.3
+ * type-qualifier:
+ * const
+ * restrict
+ * volatile
+ * _Atomic
+ */
+ MOD cparseTypeQualifierList()
+ {
+ MOD mod;
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.const_: mod |= MOD.xconst; break;
+ case TOK.volatile: mod |= MOD.xvolatile; break;
+ case TOK.restrict: mod |= MOD.xrestrict; break;
+ case TOK._Atomic: mod |= MOD.x_Atomic; break;
+
+ default:
+ return mod;
+ }
+ nextToken();
+ }
+ }
+
+ /***********************************
+ * C11 6.7.7
+ */
+ AST.Type cparseTypeName()
+ {
+ Specifier specifier;
+ auto tspec = cparseSpecifierQualifierList(LVL.global, specifier);
+ Identifier id;
+ return cparseDeclarator(DTR.xabstract, tspec, id);
+ }
+
+ /***********************************
+ * C11 6.7.2.1
+ * specifier-qualifier-list:
+ * type-specifier specifier-qualifier-list (opt)
+ * type-qualifier specifier-qualifier-list (opt)
+ * Params:
+ * level = declaration context
+ * specifier = specifiers in and out
+ * Returns:
+ * resulting type, null if not specified
+ */
+ AST.Type cparseSpecifierQualifierList(LVL level, ref Specifier specifier)
+ {
+ auto t = cparseDeclarationSpecifiers(level, specifier);
+ if (specifier.scw)
+ error("storage class not allowed in specifier-qualified-list");
+ return t;
+ }
+
+ /***********************************
+ * C11 6.7.6.3
+ * ( parameter-type-list )
+ * ( identifier-list (opt) )
+ */
+ AST.ParameterList cparseParameterList()
+ {
+ auto parameters = new AST.Parameters();
+ AST.VarArg varargs = AST.VarArg.none;
+ StorageClass varargsStc;
+
+ check(TOK.leftParenthesis);
+ if (token.value == TOK.void_ && peekNext() == TOK.rightParenthesis)
+ {
+ nextToken();
+ nextToken();
+ return AST.ParameterList(parameters, varargs, varargsStc);
+ }
+
+ /* The check for identifier-list comes later,
+ * when doing the trailing declaration-list (opt)
+ */
+ while (1)
+ {
+ if (token.value == TOK.rightParenthesis)
+ break;
+ if (token.value == TOK.dotDotDot)
+ {
+ varargs = AST.VarArg.variadic; // C-style variadics
+ nextToken();
+ check(TOK.rightParenthesis);
+ return AST.ParameterList(parameters, varargs, varargsStc);
+ }
+
+ Specifier specifier;
+ auto tspec = cparseDeclarationSpecifiers(LVL.prototype, specifier);
+
+ Identifier id;
+ auto t = cparseDeclarator(DTR.xparameter, tspec, id);
+ if (specifier.mod & MOD.xconst)
+ t = toConst(t);
+ auto param = new AST.Parameter(STC.parameter, t, id, null, null);
+ parameters.push(param);
+ if (token.value == TOK.rightParenthesis)
+ break;
+ check(TOK.comma);
+ }
+ nextToken();
+ return AST.ParameterList(parameters, varargs, varargsStc);
+ }
+
+ /***********************************
+ * C11 6.7.10
+ * _Static_assert ( constant-expression , string-literal ) ;
+ */
+ private AST.StaticAssert cparseStaticAssert()
+ {
+ const loc = token.loc;
+
+ //printf("cparseStaticAssert()\n");
+ nextToken();
+ check(TOK.leftParenthesis);
+ auto exp = cparseConstantExp();
+ check(TOK.comma);
+ if (token.value != TOK.string_)
+ error("string literal expected");
+ auto msg = cparsePrimaryExp();
+ check(TOK.rightParenthesis);
+ check(TOK.semicolon);
+ return new AST.StaticAssert(loc, exp, msg);
+ }
+
+ /*************************
+ * Collect argument list.
+ * Parser is on opening parenthesis.
+ * Returns:
+ * the arguments
+ */
+ private AST.Expressions* cparseArguments()
+ {
+ nextToken();
+ auto arguments = new AST.Expressions();
+ while (token.value != TOK.rightParenthesis && token.value != TOK.endOfFile)
+ {
+ auto arg = cparseAssignExp();
+ arguments.push(arg);
+ if (token.value != TOK.comma)
+ break;
+
+ nextToken(); // consume comma
+ }
+
+ check(TOK.rightParenthesis);
+
+ return arguments;
+ }
+
+ /*************************
+ * __declspec parser
+ * https://docs.microsoft.com/en-us/cpp/cpp/declspec
+ * decl-specifier:
+ * __declspec ( extended-decl-modifier-seq )
+ *
+ * extended-decl-modifier-seq:
+ * extended-decl-modifier (opt)
+ * extended-decl-modifier extended-decl-modifier-seq
+ *
+ * extended-decl-modifier:
+ * dllimport
+ * dllexport
+ */
+ private void cparseDeclspec()
+ {
+ /* Check for dllexport, dllimport
+ * Ignore the rest
+ */
+ bool dllimport; // TODO implement
+ bool dllexport; // TODO implement
+ nextToken(); // move past __declspec
+ check(TOK.leftParenthesis);
+ while (1)
+ {
+ if (token.value == TOK.rightParenthesis)
+ {
+ nextToken();
+ break;
+ }
+ else if (token.value == TOK.endOfFile)
+ break;
+ else if (token.value == TOK.identifier)
+ {
+ if (token.ident == Id.dllimport)
+ {
+ dllimport = true;
+ nextToken();
+ }
+ else if (token.ident == Id.dllexport)
+ {
+ dllexport = true;
+ nextToken();
+ }
+ else
+ {
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ cparseParens();
+ }
+ }
+ else
+ {
+ error("extended-decl-modifier expected");
+ }
+ break;
+ }
+ }
+
+ /*************************
+ * Simple asm parser
+ * https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html
+ * simple-asm-expr:
+ * asm ( asm-string-literal )
+ *
+ * asm-string-literal:
+ * string-literal
+ */
+ private AST.Expression cparseSimpleAsmExpr()
+ {
+ nextToken(); // move past asm
+ check(TOK.leftParenthesis);
+ if (token.value != TOK.string_)
+ error("string literal expected");
+ auto label = cparsePrimaryExp();
+ check(TOK.rightParenthesis);
+ return label;
+ }
+
+ /*************************
+ * __attribute__ parser
+ * https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
+ * gnu-attributes:
+ * gnu-attributes gnu-attribute-specifier
+ *
+ * gnu-attribute-specifier:
+ * __attribute__ (( gnu-attribute-list ))
+ *
+ * gnu-attribute-list:
+ * gnu-attribute (opt)
+ * gnu-attribute-list , gnu-attribute
+ *
+ * Params:
+ * specifier = filled in with the attribute(s)
+ */
+ private void cparseGnuAttributes(ref Specifier specifier)
+ {
+ while (token.value == TOK.__attribute__)
+ {
+ nextToken(); // move past __attribute__
+ check(TOK.leftParenthesis);
+ check(TOK.leftParenthesis);
+
+ if (token.value != TOK.rightParenthesis)
+ {
+ while (1)
+ {
+ cparseGnuAttribute(specifier);
+ if (token.value != TOK.comma)
+ break;
+ nextToken();
+ }
+ }
+
+ check(TOK.rightParenthesis);
+ check(TOK.rightParenthesis);
+ }
+ }
+
+ /*************************
+ * Parse a single GNU attribute
+ * gnu-attribute:
+ * gnu-attribute-name
+ * gnu-attribute-name ( identifier )
+ * gnu-attribute-name ( identifier , expression-list )
+ * gnu-attribute-name ( expression-list (opt) )
+ *
+ * gnu-attribute-name:
+ * keyword
+ * identifier
+ *
+ * expression-list:
+ * constant-expression
+ * expression-list , constant-expression
+ *
+ * Params:
+ * specifier = filled in with the attribute(s)
+ */
+ private void cparseGnuAttribute(ref Specifier specifier)
+ {
+ /* Check for dllimport, dllexport, vector_size(bytes)
+ * Ignore the rest
+ */
+ bool dllimport; // TODO implement
+ bool dllexport; // TODO implement
+
+ if (!isGnuAttributeName())
+ return;
+
+ if (token.value == TOK.identifier)
+ {
+ if (token.ident == Id.dllimport)
+ {
+ dllimport = true;
+ nextToken();
+ }
+ else if (token.ident == Id.dllexport)
+ {
+ dllexport = true;
+ nextToken();
+ }
+ else if (token.ident == Id.noreturn)
+ {
+ specifier.noreturn = true;
+ nextToken();
+ }
+ else if (token.ident == Id.vector_size)
+ {
+ nextToken();
+ check(TOK.leftParenthesis);
+ cparseConstantExp(); // TODO implement
+ check(TOK.rightParenthesis);
+ }
+ else
+ {
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ cparseParens();
+ }
+ }
+ else
+ {
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ cparseParens();
+ }
+ }
+
+ /*************************
+ * See if match for GNU attribute name, which may be any identifier,
+ * storage-class-specifier, type-specifier, or type-qualifier.
+ * Returns:
+ * true if a valid GNU attribute name
+ */
+ private bool isGnuAttributeName()
+ {
+ switch (token.value)
+ {
+ case TOK.identifier:
+ case TOK.static_:
+ case TOK.unsigned:
+ case TOK.int64:
+ case TOK.const_:
+ case TOK.extern_:
+ case TOK.register:
+ case TOK.typedef_:
+ case TOK.int16:
+ case TOK.inline:
+ case TOK._Noreturn:
+ case TOK.volatile:
+ case TOK.signed:
+ case TOK.auto_:
+ case TOK.restrict:
+ case TOK._Complex:
+ case TOK._Thread_local:
+ case TOK.int32:
+ case TOK.char_:
+ case TOK.float32:
+ case TOK.float64:
+ case TOK.void_:
+ case TOK._Bool:
+ case TOK._Atomic:
+ return true;
+
+ default:
+ return false;
+ }
+ }
+
+ /***************************
+ * Like skipParens(), but consume the tokens.
+ */
+ private void cparseParens()
+ {
+ check(TOK.leftParenthesis);
+ int parens = 1;
+
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.leftParenthesis:
+ ++parens;
+ break;
+
+ case TOK.rightParenthesis:
+ --parens;
+ if (parens < 0)
+ {
+ error("extra right parenthesis");
+ return;
+ }
+ if (parens == 0)
+ {
+ nextToken();
+ return;
+ }
+ break;
+
+ case TOK.endOfFile:
+ error("end of file found before right parenthesis");
+ return;
+
+ default:
+ break;
+ }
+ nextToken();
+ }
+ }
+
+ //}
+ /******************************************************************************/
+ /***************************** Struct & Enum Parser ***************************/
+ //{
+
+ /*************************************
+ * C11 6.7.2.2
+ * enum-specifier:
+ * enum identifier (opt) { enumerator-list }
+ * enum identifier (opt) { enumerator-list , }
+ * enum identifier
+ *
+ * enumerator-list:
+ * enumerator
+ * enumerator-list , enumerator
+ *
+ * enumerator:
+ * enumeration-constant
+ * enumeration-constant = constant-expression
+ *
+ * enumeration-constant:
+ * identifier
+ *
+ * Params:
+ * symbols = symbols to add enum declaration to
+ * Returns:
+ * type of the enum
+ */
+ private AST.Type cparseEnum(ref AST.Dsymbols* symbols)
+ {
+ const loc = token.loc;
+ nextToken();
+
+ /* GNU Extensions
+ * enum-specifier:
+ * enum gnu-attributes (opt) identifier (opt) { enumerator-list } gnu-attributes (opt)
+ * enum gnu-attributes (opt) identifier (opt) { enumerator-list , } gnu-attributes (opt)
+ * enum gnu-attributes (opt) identifier
+ */
+ Specifier specifier;
+ if (token.value == TOK.__attribute__)
+ cparseGnuAttributes(specifier);
+
+ Identifier tag;
+ if (token.value == TOK.identifier)
+ {
+ tag = token.ident;
+ nextToken();
+ }
+
+ AST.Dsymbols* members;
+ if (token.value == TOK.leftCurly)
+ {
+ nextToken();
+ members = new AST.Dsymbols();
+
+ if (token.value == TOK.rightCurly) // C11 6.7.2.2-1
+ {
+ if (tag)
+ error("no members for `enum %s`", tag.toChars());
+ else
+ error("no members for anonymous enum");
+ }
+
+ while (token.value == TOK.identifier)
+ {
+ auto ident = token.ident; // enumeration-constant
+ nextToken();
+ auto mloc = token.loc;
+
+ AST.Expression value;
+ if (token.value == TOK.assign)
+ {
+ nextToken();
+ value = cparseConstantExp();
+ // TODO C11 6.7.2.2-2 value must fit into an int
+ }
+
+ auto em = new AST.EnumMember(mloc, ident, value, null, 0, null, null);
+ members.push(em);
+
+ if (token.value == TOK.comma)
+ {
+ nextToken();
+ continue;
+ }
+ break;
+ }
+ check(TOK.rightCurly);
+
+ /* GNU Extensions
+ * Parse the postfix gnu-attributes (opt)
+ */
+ if (token.value == TOK.__attribute__)
+ cparseGnuAttributes(specifier);
+ }
+ else if (!tag)
+ error("missing `identifier` after `enum`");
+
+ /* Need semantic information to determine if this is a declaration,
+ * redeclaration, or reference to existing declaration.
+ * Defer to the semantic() pass with a TypeTag.
+ */
+ return new AST.TypeTag(loc, TOK.enum_, tag, members);
+ }
+
+ /*************************************
+ * C11 6.7.2.1
+ * Parse struct and union specifiers.
+ * Parser is advanced to the tag identifier or brace.
+ * struct-or-union-specifier:
+ * struct-or-union identifier (opt) { struct-declaration-list }
+ * struct-or-union identifier
+ *
+ * struct-or-union:
+ * struct
+ * union
+ *
+ * struct-declaration-list:
+ * struct-declaration
+ * struct-declaration-list struct-declaration
+ *
+ * Params:
+ * loc = location of `struct` or `union`
+ * structOrUnion = TOK.struct_ or TOK.union_
+ * symbols = symbols to add struct-or-union declaration to
+ * Returns:
+ * type of the struct
+ */
+ private AST.Type cparseStruct(Loc loc, TOK structOrUnion, ref AST.Dsymbols* symbols)
+ {
+ Identifier tag;
+
+ if (token.value == TOK.identifier)
+ {
+ tag = token.ident;
+ nextToken();
+ }
+
+ AST.Dsymbols* members;
+ if (token.value == TOK.leftCurly)
+ {
+ nextToken();
+ auto symbolsSave = symbols;
+ symbols = new AST.Dsymbols();
+ while (token.value != TOK.rightCurly)
+ {
+ cparseStructDeclaration();
+
+ if (token.value == TOK.endOfFile)
+ break;
+ }
+ members = symbols; // `members` will be non-null even with 0 members
+ symbols = symbolsSave;
+ check(TOK.rightCurly);
+
+ if ((*members).length == 0) // C11 6.7.2.1-8
+ /* TODO: not strict enough, should really be contains "no named members",
+ * not just "no members".
+ * I.e. an unnamed bit field, _Static_assert, etc, are not named members,
+ * but will pass this check.
+ * Be careful to detect named members that come anonymous structs.
+ * Correctly doing this will likely mean moving it to typesem.d.
+ */
+ error("empty struct-declaration-list for `%s %s`", Token.toChars(structOrUnion), tag ? tag.toChars() : "Anonymous".ptr);
+ }
+ else if (!tag)
+ error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion));
+
+ /* Need semantic information to determine if this is a declaration,
+ * redeclaration, or reference to existing declaration.
+ * Defer to the semantic() pass with a TypeTag.
+ */
+ return new AST.TypeTag(loc, structOrUnion, tag, members);
+ }
+
+ /*************************************
+ * C11 6.7.2.1
+ * Parse a struct declaration member.
+ * struct-declaration:
+ * specifier-qualifier-list struct-declarator-list (opt) ;
+ * static_assert-declaration
+ *
+ * struct-declarator-list:
+ * struct-declarator
+ * struct-declarator-list , struct-declarator
+ *
+ * struct-declarator:
+ * declarator
+ * declarator (opt) : constant-expression
+ */
+ void cparseStructDeclaration()
+ {
+ //printf("cparseStructDeclaration()\n");
+ if (token.value == TOK._Static_assert)
+ {
+ auto s = cparseStaticAssert();
+ symbols.push(s);
+ return;
+ }
+
+ auto symbolsSave = symbols;
+ Specifier specifier;
+ auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
+
+ /* If a declarator does not follow, it is unnamed
+ */
+ if (token.value == TOK.semicolon && tspec)
+ {
+ nextToken();
+ auto tt = tspec.isTypeTag();
+ if (!tt)
+ return; // legal but meaningless empty declaration
+
+ /* If anonymous struct declaration
+ * struct { ... members ... };
+ * C11 6.7.2.1-13
+ */
+ if (!tt.id && tt.members)
+ {
+ /* members of anonymous struct are considered members of
+ * the containing struct
+ */
+ auto ad = new AST.AnonDeclaration(tt.loc, tt.tok == TOK.union_, tt.members);
+ if (!symbols)
+ symbols = new AST.Dsymbols();
+ auto s = applySpecifier(ad, specifier);
+ symbols.push(s);
+ return;
+ }
+ if (!tt.id && !tt.members)
+ return; // already gave error in cparseStruct()
+
+ /* `struct tag;` and `struct tag { ... };`
+ * always result in a declaration in the current scope
+ */
+ // TODO: merge in specifier
+ auto stag = (tt.tok == TOK.struct_)
+ ? new AST.StructDeclaration(tt.loc, tt.id, false)
+ : new AST.UnionDeclaration(tt.loc, tt.id);
+ stag.members = tt.members;
+ if (!symbols)
+ symbols = new AST.Dsymbols();
+ auto s = applySpecifier(stag, specifier);
+ symbols.push(s);
+ return;
+ }
+
+ while (1)
+ {
+ Identifier id;
+ AST.Type dt;
+ if (token.value == TOK.colon)
+ {
+ // C11 6.7.2.1-12 unnamed bit-field
+ id = Identifier.generateAnonymousId("BitField");
+ dt = tspec;
+ }
+ else
+ dt = cparseDeclarator(DTR.xdirect, tspec, id);
+ if (!dt)
+ {
+ panic();
+ nextToken();
+ break; // error recovery
+ }
+
+ AST.Expression width;
+ if (token.value == TOK.colon)
+ {
+ // C11 6.7.2.1-10 bit-field
+ nextToken();
+ width = cparseConstantExp();
+ }
+
+ if (specifier.mod & MOD.xconst)
+ dt = toConst(dt);
+
+ /* GNU Extensions
+ * struct-declarator:
+ * declarator gnu-attributes (opt)
+ * declarator (opt) : constant-expression gnu-attributes (opt)
+ */
+ if (token.value == TOK.__attribute__)
+ cparseGnuAttributes(specifier);
+
+ AST.Dsymbol s = null;
+ symbols = symbolsSave;
+ if (!symbols)
+ symbols = new AST.Dsymbols; // lazilly create it
+
+ if (!tspec && !specifier.scw && !specifier.mod)
+ error("specifier-qualifier-list required");
+ else if (width)
+ {
+ if (specifier.alignExps)
+ error("no alignment-specifier for bit field declaration"); // C11 6.7.5-2
+ s = new AST.BitFieldDeclaration(width.loc, dt, id, width);
+ }
+ else if (id)
+ {
+ if (dt.ty == AST.Tvoid)
+ error("`void` has no value");
+
+ // declare the symbol
+ // Give member variables an implicit void initializer
+ auto initializer = new AST.VoidInitializer(token.loc);
+ s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(LVL.member, specifier));
+ s = applySpecifier(s, specifier);
+ }
+ if (s !is null)
+ symbols.push(s);
+
+ switch (token.value)
+ {
+ case TOK.identifier:
+ error("missing comma");
+ goto default;
+
+ case TOK.semicolon:
+ nextToken();
+ return;
+
+ case TOK.comma:
+ nextToken();
+ break;
+
+ default:
+ error("`;` or `,` expected");
+ while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
+ nextToken();
+ nextToken();
+ return;
+ }
+ }
+ }
+
+ //}
+ /******************************************************************************/
+ /********************************* Lookahead Parser ***************************/
+ //{
+
+ /************************************
+ * Determine if the scanner is sitting on the start of a declaration.
+ * Params:
+ * t = current token of the scanner
+ * needId = flag with additional requirements for a declaration
+ * endtok = ending token
+ * pt = will be set ending token (if not null)
+ * Returns:
+ * true at start of a declaration
+ */
+ private bool isCDeclaration(ref Token* pt)
+ {
+ //printf("isCDeclaration()\n");
+ auto t = pt;
+ if (!isDeclarationSpecifiers(t))
+ return false;
+
+ while (1)
+ {
+ if (t.value == TOK.semicolon)
+ {
+ t = peek(t);
+ pt = t;
+ return true;
+ }
+ if (!isCDeclarator(t, DTR.xdirect))
+ return false;
+ if (t.value == TOK.asm_)
+ {
+ t = peek(t);
+ if (t.value != TOK.leftParenthesis || !skipParens(t, &t))
+ return false;
+ }
+ if (t.value == TOK.__attribute__)
+ {
+ t = peek(t);
+ if (t.value != TOK.leftParenthesis || !skipParens(t, &t))
+ return false;
+ }
+ if (t.value == TOK.assign)
+ {
+ t = peek(t);
+ if (!isInitializer(t))
+ return false;
+ }
+ switch (t.value)
+ {
+ case TOK.comma:
+ t = peek(t);
+ break;
+
+ case TOK.semicolon:
+ t = peek(t);
+ pt = t;
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ /********************************
+ * See if match for initializer.
+ * Params:
+ * pt = starting token, updated to one past end of initializer if true
+ * Returns:
+ * true if initializer
+ */
+ private bool isInitializer(ref Token* pt)
+ {
+ //printf("isInitializer()\n");
+ auto t = pt;
+
+ if (t.value == TOK.leftCurly)
+ {
+ if (!skipBraces(t))
+ return false;
+ pt = t;
+ return true;
+ }
+
+ // skip over assignment-expression, ending before comma or semiColon or EOF
+ if (!isAssignmentExpression(t))
+ return false;
+ pt = t;
+ return true;
+ }
+
+ /********************************
+ * See if match for:
+ * postfix-expression ( argument-expression-list(opt) )
+ * Params:
+ * pt = starting token, updated to one past end of initializer if true
+ * Returns:
+ * true if function call
+ */
+ private bool isFunctionCall(ref Token* pt)
+ {
+ //printf("isFunctionCall()\n");
+ auto t = pt;
+
+ if (!isPrimaryExpression(t))
+ return false;
+ if (t.value != TOK.leftParenthesis)
+ return false;
+ t = peek(t);
+ while (1)
+ {
+ if (!isAssignmentExpression(t))
+ return false;
+ if (t.value == TOK.comma)
+ {
+ t = peek(t);
+ continue;
+ }
+ if (t.value == TOK.rightParenthesis)
+ {
+ t = peek(t);
+ break;
+ }
+ return false;
+ }
+ if (t.value != TOK.semicolon)
+ return false;
+ pt = t;
+ return true;
+ }
+
+ /********************************
+ * See if match for assignment-expression.
+ * Params:
+ * pt = starting token, updated to one past end of assignment-expression if true
+ * Returns:
+ * true if assignment-expression
+ */
+ private bool isAssignmentExpression(ref Token* pt)
+ {
+ //printf("isAssignmentExpression()\n");
+ auto t = pt;
+
+ /* This doesn't actually check for grammar matching an
+ * assignment-expression. It just matches ( ) [ ] looking for
+ * an ending token that would terminate one.
+ */
+ bool any;
+ while (1)
+ {
+ switch (t.value)
+ {
+ case TOK.comma:
+ case TOK.semicolon:
+ case TOK.rightParenthesis:
+ case TOK.rightBracket:
+ case TOK.endOfFile:
+ if (!any)
+ return false;
+ break;
+
+ case TOK.leftParenthesis:
+ if (!skipParens(t, &t))
+ return false;
+ continue;
+
+ case TOK.leftBracket:
+ if (!skipBrackets(t))
+ return false;
+ continue;
+
+ default:
+ any = true; // assume token was part of an a-e
+ t = peek(t);
+ continue;
+ }
+ pt = t;
+ return true;
+ }
+ }
+
+ /********************************
+ * See if match for constant-expression.
+ * Params:
+ * pt = starting token, updated to one past end of constant-expression if true
+ * Returns:
+ * true if constant-expression
+ */
+ private bool isConstantExpression(ref Token* pt)
+ {
+ return isAssignmentExpression(pt);
+ }
+
+ /********************************
+ * See if match for declaration-specifiers.
+ * No errors are diagnosed.
+ * Params:
+ * pt = starting token, updated to one past end of declaration-specifiers if true
+ * Returns:
+ * true if declaration-specifiers
+ */
+ private bool isDeclarationSpecifiers(ref Token* pt)
+ {
+ //printf("isDeclarationSpecifiers()\n");
+
+ auto t = pt;
+
+ bool any;
+ while (1)
+ {
+ switch (t.value)
+ {
+ // type-specifiers
+ case TOK.void_:
+ case TOK.char_:
+ case TOK.int16:
+ case TOK.int32:
+ case TOK.int64:
+ case TOK.float32:
+ case TOK.float64:
+ case TOK.signed:
+ case TOK.unsigned:
+ case TOK._Bool:
+ //case TOK._Imaginary:
+ case TOK._Complex:
+ case TOK.identifier: // typedef-name
+ t = peek(t);
+ any = true;
+ break;
+
+ case TOK.struct_:
+ case TOK.union_:
+ case TOK.enum_:
+ t = peek(t);
+ if (t.value == TOK.identifier)
+ {
+ t = peek(t);
+ if (t.value == TOK.leftCurly)
+ {
+ if (!skipBraces(t))
+ return false;
+ }
+ }
+ else if (t.value == TOK.leftCurly)
+ {
+ if (!skipBraces(t))
+ return false;
+ }
+ else
+ return false;
+ any = true;
+ continue;
+
+ // storage-class-specifiers
+ case TOK.typedef_:
+ case TOK.extern_:
+ case TOK.static_:
+ case TOK._Thread_local:
+ case TOK.auto_:
+ case TOK.register:
+
+ // function-specifiers
+ case TOK.inline:
+ case TOK._Noreturn:
+
+ // type-qualifiers
+ case TOK.const_:
+ case TOK.volatile:
+ case TOK.restrict:
+ t = peek(t);
+ any = true;
+ continue;
+
+ case TOK._Alignas: // alignment-specifier
+ case TOK.__declspec: // decl-specifier
+ case TOK.__attribute__: // attribute-specifier
+ t = peek(t);
+ if (!skipParens(t, &t))
+ return false;
+ any = true;
+ continue;
+
+ // either atomic-type-specifier or type_qualifier
+ case TOK._Atomic: // TODO _Atomic ( type-name )
+ t = peek(t);
+ if (t.value == TOK.leftParenthesis) // maybe atomic-type-specifier
+ {
+ auto tsave = t;
+ t = peek(t);
+ if (!isTypeName(t) || t.value != TOK.rightParenthesis)
+ { // it's a type-qualifier
+ t = tsave; // back up parser
+ any = true;
+ continue;
+ }
+ t = peek(t); // move past right parenthesis of atomic-type-specifier
+ }
+ any = true;
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (any)
+ {
+ pt = t;
+ return true;
+ }
+ return false;
+ }
+
+ /**************************************
+ * See if declaration-list is present.
+ * Returns:
+ * true if declaration-list is present, even an empty one
+ */
+ bool isDeclarationList(ref Token* pt)
+ {
+ auto t = pt;
+ while (1)
+ {
+ if (t.value == TOK.leftCurly)
+ {
+ pt = t;
+ return true;
+ }
+ if (!isCDeclaration(t))
+ return false;
+ }
+ }
+
+ /*******************************************
+ * Skip braces.
+ * Params:
+ * pt = enters on left brace, set to token past right bracket on true
+ * Returns:
+ * true if successful
+ */
+ private bool skipBraces(ref Token* pt)
+ {
+ auto t = pt;
+ if (t.value != TOK.leftCurly)
+ return false;
+
+ int braces = 0;
+
+ while (1)
+ {
+ switch (t.value)
+ {
+ case TOK.leftCurly:
+ ++braces;
+ t = peek(t);
+ continue;
+
+ case TOK.rightCurly:
+ --braces;
+ if (braces == 0)
+ {
+ pt = peek(t);
+ return true;
+ }
+ if (braces < 0)
+ return false;
+
+ t = peek(t);
+ continue;
+
+ case TOK.endOfFile:
+ return false;
+
+ default:
+ t = peek(t);
+ continue;
+ }
+ }
+ }
+
+ /*******************************************
+ * Skip brackets.
+ * Params:
+ * pt = enters on left bracket, set to token past right bracket on true
+ * Returns:
+ * true if successful
+ */
+ private bool skipBrackets(ref Token* pt)
+ {
+ auto t = pt;
+ if (t.value != TOK.leftBracket)
+ return false;
+
+ int brackets = 0;
+
+ while (1)
+ {
+ switch (t.value)
+ {
+ case TOK.leftBracket:
+ ++brackets;
+ t = peek(t);
+ continue;
+
+ case TOK.rightBracket:
+ --brackets;
+ if (brackets == 0)
+ {
+ pt = peek(t);
+ return true;
+ }
+ if (brackets < 0)
+ return false;
+
+ t = peek(t);
+ continue;
+
+ case TOK.endOfFile:
+ return false;
+
+ default:
+ t = peek(t);
+ continue;
+ }
+ }
+ }
+
+ /*********************************
+ * Check to see if tokens starting with *pt form a declarator.
+ * Params:
+ * pt = pointer to starting token, updated to point past declarator if true is returned
+ * declarator = declarator kind
+ * Returns:
+ * true if it does
+ */
+ private bool isCDeclarator(ref Token* pt, DTR declarator)
+ {
+ auto t = pt;
+ while (1)
+ {
+ if (t.value == TOK.mul) // pointer
+ {
+ t = peek(t);
+ if (!isTypeQualifierList(t))
+ return false;
+ }
+ else
+ break;
+ }
+
+ if (t.value == TOK.identifier)
+ {
+ if (declarator == DTR.xabstract)
+ return false;
+ t = peek(t);
+ }
+ else if (t.value == TOK.leftParenthesis)
+ {
+ t = peek(t);
+ if (!isCDeclarator(t, declarator))
+ return false;
+ if (t.value != TOK.rightParenthesis)
+ return false;
+ t = peek(t);
+ }
+ else if (declarator == DTR.xdirect)
+ {
+ return false;
+ }
+
+ while (1)
+ {
+ if (t.value == TOK.leftBracket)
+ {
+ if (!skipBrackets(t))
+ return false;
+ }
+ else if (t.value == TOK.leftParenthesis)
+ {
+ if (!skipParens(t, &t))
+ return false;
+ }
+ else
+ break;
+ }
+ pt = t;
+ return true;
+ }
+
+ /***************************
+ * Is this the start of a type-qualifier-list?
+ * (Can be empty.)
+ * Params:
+ * pt = first token; updated with past end of type-qualifier-list if true
+ * Returns:
+ * true if start of type-qualifier-list
+ */
+ private bool isTypeQualifierList(ref Token* pt)
+ {
+ auto t = pt;
+ while (1)
+ {
+ switch (t.value)
+ {
+ case TOK.const_:
+ case TOK.restrict:
+ case TOK.volatile:
+ case TOK._Atomic:
+ t = peek(t);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ pt = t;
+ return true;
+ }
+
+ /***************************
+ * Is this the start of a type-name?
+ * Params:
+ * pt = first token; updated with past end of type-name if true
+ * Returns:
+ * true if start of type-name
+ */
+ private bool isTypeName(ref Token* pt)
+ {
+ auto t = pt;
+ //printf("isTypeName() %s\n", t.toChars());
+ if (!isSpecifierQualifierList(t))
+ return false;
+ if (!isCDeclarator(t, DTR.xabstract))
+ return false;
+ if (t.value != TOK.rightParenthesis)
+ return false;
+ pt = t;
+ return true;
+ }
+
+ /***************************
+ * Is this the start of a specifier-qualifier-list?
+ * Params:
+ * pt = first token; updated with past end of specifier-qualifier-list if true
+ * Returns:
+ * true if start of specifier-qualifier-list
+ */
+ private bool isSpecifierQualifierList(ref Token* pt)
+ {
+ auto t = pt;
+ bool result;
+ while (1)
+ {
+ switch (t.value)
+ {
+ // Type Qualifiers
+ case TOK.const_:
+ case TOK.restrict:
+ case TOK.volatile:
+
+ // Type Specifiers
+ case TOK.char_:
+ case TOK.signed:
+ case TOK.unsigned:
+ case TOK.int16:
+ case TOK.int32:
+ case TOK.int64:
+ case TOK.float32:
+ case TOK.float64:
+ case TOK.void_:
+ case TOK._Bool:
+ //case TOK._Imaginary: // ? missing in Spec
+ case TOK._Complex:
+
+ // typedef-name
+ case TOK.identifier: // will not know until semantic if typedef
+ t = peek(t);
+ break;
+
+ // struct-or-union-specifier
+ // enum-specifier
+ case TOK.struct_:
+ case TOK.union_:
+ case TOK.enum_:
+ t = peek(t);
+ if (t.value == TOK.identifier)
+ {
+ t = peek(t);
+ if (t.value == TOK.leftCurly)
+ {
+ if (!skipBraces(t))
+ return false;
+ }
+ }
+ else if (t.value == TOK.leftCurly)
+ {
+ if (!skipBraces(t))
+ return false;
+ }
+ else
+ return false;
+ break;
+
+ // atomic-type-specifier
+ case TOK._Atomic:
+ t = peek(t);
+ if (t.value != TOK.leftParenthesis ||
+ !skipParens(t, &t))
+ return false;
+ break;
+
+ default:
+ if (result)
+ pt = t;
+ return result;
+ }
+ result = true;
+ }
+ }
+
+ /************************************
+ * Looking at the leading left parenthesis, and determine if it is
+ * either of the following:
+ * ( type-name ) cast-expression
+ * ( type-name ) { initializer-list }
+ * as opposed to:
+ * ( expression )
+ * Params:
+ * pt = starting token, updated to one past end of constant-expression if true
+ * afterParenType = true if already seen ( type-name )
+ * Returns:
+ * true if matches ( type-name ) ...
+ */
+ private bool isCastExpression(ref Token* pt, bool afterParenType = false)
+ {
+ auto t = pt;
+ switch (t.value)
+ {
+ case TOK.leftParenthesis:
+ auto tk = peek(t); // move past left parenthesis
+ if (!isTypeName(tk) || tk.value != TOK.rightParenthesis)
+ {
+ if (afterParenType)
+ goto default; // could be ( type-name ) ( unary-expression )
+ return false;
+ }
+ tk = peek(tk); // move past right parenthesis
+
+ if (tk.value == TOK.leftCurly)
+ {
+ // ( type-name ) { initializer-list }
+ if (!isInitializer(tk))
+ return false;
+ t = tk;
+ break;
+ }
+ if (!isCastExpression(tk, true))
+ {
+ if (afterParenType) // could be ( type-name ) ( unary-expression )
+ goto default; // where unary-expression also matched type-name
+ return false;
+ }
+ // ( type-name ) cast-expression
+ t = tk;
+ break;
+
+ default:
+ if (!afterParenType || !isUnaryExpression(t, afterParenType))
+ return false;
+ // if we've already seen ( type-name ), then this is a cast
+ break;
+ }
+ pt = t;
+ return true;
+ }
+
+ /********************************
+ * See if match for unary-expression.
+ * Params:
+ * pt = starting token, updated to one past end of constant-expression if true
+ * afterParenType = true if already seen ( type-name ) of a cast-expression
+ * Returns:
+ * true if unary-expression
+ */
+ private bool isUnaryExpression(ref Token* pt, bool afterParenType = false)
+ {
+ auto t = pt;
+ switch (t.value)
+ {
+ case TOK.plusPlus:
+ case TOK.minusMinus:
+ t = peek(t);
+ if (!isUnaryExpression(t, afterParenType))
+ return false;
+ break;
+
+ case TOK.and:
+ case TOK.mul:
+ case TOK.min:
+ case TOK.add:
+ case TOK.not:
+ case TOK.tilde:
+ t = peek(t);
+ if (!isCastExpression(t, afterParenType))
+ return false;
+ break;
+
+ case TOK.sizeof_:
+ t = peek(t);
+ if (t.value == TOK.leftParenthesis)
+ {
+ auto tk = peek(t);
+ if (isTypeName(tk))
+ {
+ if (tk.value != TOK.rightParenthesis)
+ return false;
+ t = peek(tk);
+ break;
+ }
+ }
+ if (!isUnaryExpression(t, afterParenType))
+ return false;
+ break;
+
+ case TOK._Alignof:
+ t = peek(t);
+ if (t.value != TOK.leftParenthesis)
+ return false;
+ t = peek(t);
+ if (!isTypeName(t) || t.value != TOK.rightParenthesis)
+ return false;
+ break;
+
+ default:
+ // Compound literals are handled by cast and sizeof expressions,
+ // so be content with just seeing a primary expression.
+ if (!isPrimaryExpression(t))
+ return false;
+ break;
+ }
+ pt = t;
+ return true;
+ }
+
+ /********************************
+ * See if match for primary-expression.
+ * Params:
+ * pt = starting token, updated to one past end of constant-expression if true
+ * Returns:
+ * true if primary-expression
+ */
+ private bool isPrimaryExpression(ref Token* pt)
+ {
+ auto t = pt;
+ switch (t.value)
+ {
+ case TOK.identifier:
+ case TOK.int32Literal:
+ case TOK.uns32Literal:
+ case TOK.int64Literal:
+ case TOK.uns64Literal:
+ case TOK.float32Literal:
+ case TOK.float64Literal:
+ case TOK.float80Literal:
+ case TOK.imaginary32Literal:
+ case TOK.imaginary64Literal:
+ case TOK.imaginary80Literal:
+ case TOK.string_:
+ t = peek(t);
+ break;
+
+ case TOK.leftParenthesis:
+ // ( expression )
+ if (!skipParens(t, &t))
+ return false;
+ break;
+
+ case TOK._Generic:
+ t = peek(t);
+ if (!skipParens(t, &t))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+ pt = t;
+ return true;
+ }
+
+ //}
+ /******************************************************************************/
+ /********************************* More ***************************************/
+ //{
+
+ /**************
+ * Declaration context
+ */
+ enum LVL
+ {
+ global = 1, /// global
+ parameter = 2, /// function parameter (declarations for function identifier-list)
+ prototype = 4, /// function prototype
+ local = 8, /// local
+ member = 0x10, /// struct member
+ }
+
+ /// Types of declarator to parse
+ enum DTR
+ {
+ xdirect = 1, /// C11 6.7.6 direct-declarator
+ xabstract = 2, /// C11 6.7.7 abstract-declarator
+ xparameter = 3, /// parameter declarator may be either direct or abstract
+ }
+
+ /// C11 6.7.1 Storage-class specifiers
+ enum SCW : uint
+ {
+ xnone = 0,
+ xtypedef = 1,
+ xextern = 2,
+ xstatic = 4,
+ x_Thread_local = 8,
+ xauto = 0x10,
+ xregister = 0x20,
+ // C11 6.7.4 Function specifiers
+ xinline = 0x40,
+ x_Noreturn = 0x80,
+ }
+
+ /// C11 6.7.3 Type qualifiers
+ enum MOD : uint
+ {
+ xnone = 0,
+ xconst = 1,
+ xvolatile = 2,
+ xrestrict = 4,
+ x_Atomic = 8,
+ }
+
+ /**********************************
+ * Aggregate for all the various specifiers
+ */
+ struct Specifier
+ {
+ bool noreturn; /// noreturn attribute
+ SCW scw; /// storage-class specifiers
+ MOD mod; /// type qualifiers
+ AST.Expressions* alignExps; /// alignment
+ }
+
+ /***********************
+ * Convert from C specifiers to D storage class
+ * Params:
+ * level = declaration context
+ * specifier = specifiers, context, etc.
+ * Returns:
+ * corresponding D storage class
+ */
+ StorageClass specifiersToSTC(LVL level, const ref Specifier specifier)
+ {
+ StorageClass stc;
+ if (specifier.scw & SCW.x_Thread_local)
+ {
+ if (level == LVL.global)
+ {
+ if (specifier.scw & SCW.xextern)
+ stc = AST.STC.extern_;
+ }
+ else if (level == LVL.local)
+ {
+ if (specifier.scw & SCW.xextern)
+ stc = AST.STC.extern_;
+ else if (specifier.scw & SCW.xstatic)
+ stc = AST.STC.static_;
+ }
+ else if (level == LVL.member)
+ {
+ if (specifier.scw & SCW.xextern)
+ stc = AST.STC.extern_;
+ else if (specifier.scw & SCW.xstatic)
+ stc = AST.STC.static_;
+ }
+ }
+ else
+ {
+ if (level == LVL.global)
+ {
+ if (specifier.scw & SCW.xextern)
+ stc = AST.STC.extern_ | AST.STC.gshared;
+ else
+ stc = AST.STC.gshared;
+ }
+ else if (level == LVL.local)
+ {
+ if (specifier.scw & SCW.xextern)
+ stc = AST.STC.extern_ | AST.STC.gshared;
+ else if (specifier.scw & SCW.xstatic)
+ stc = AST.STC.gshared;
+ }
+ else if (level == LVL.member)
+ {
+ if (specifier.scw & SCW.xextern)
+ stc = AST.STC.extern_ | AST.STC.gshared;
+ else if (specifier.scw & SCW.xstatic)
+ stc = AST.STC.gshared;
+ }
+ }
+ return stc;
+ }
+
+ /***********************
+ * Return suitable D float type for C `long double`
+ * Params:
+ * flags = kind of float to return (real, imaginary, complex).
+ * Returns:
+ * corresponding D type
+ */
+ private AST.Type realType(RTFlags flags)
+ {
+ if (long_doublesize == AST.Type.tfloat80.size())
+ {
+ // On GDC and LDC, D `real` types map to C `long double`, so never
+ // return a double type when real.sizeof == double.sizeof.
+ final switch (flags)
+ {
+ case RTFlags.realfloat: return AST.Type.tfloat80;
+ case RTFlags.imaginary: return AST.Type.timaginary80;
+ case RTFlags.complex: return AST.Type.tcomplex80;
+ }
+ }
+ else
+ {
+ final switch (flags)
+ {
+ case RTFlags.realfloat: return long_doublesize == 8 ? AST.Type.tfloat64 : AST.Type.tfloat80;
+ case RTFlags.imaginary: return long_doublesize == 8 ? AST.Type.timaginary64 : AST.Type.timaginary80;
+ case RTFlags.complex: return long_doublesize == 8 ? AST.Type.tcomplex64 : AST.Type.tcomplex80;
+ }
+ }
+ }
+
+ /**************
+ * Flags for realType
+ */
+ private enum RTFlags
+ {
+ realfloat,
+ imaginary,
+ complex,
+ }
+
+ /********************
+ * C11 6.4.2.2 Create declaration to predefine __func__
+ * `static const char __func__[] = " function-name ";`
+ * Params:
+ * loc = location for this declaration
+ * id = identifier of function
+ * Returns:
+ * statement representing the declaration of __func__
+ */
+ private AST.Statement createFuncName(Loc loc, Identifier id)
+ {
+ const fn = id.toString(); // function-name
+ auto efn = new AST.StringExp(loc, fn, fn.length, 1, 'c');
+ auto ifn = new AST.ExpInitializer(loc, efn);
+ auto lenfn = new AST.IntegerExp(loc, fn.length + 1, AST.Type.tuns32); // +1 for terminating 0
+ auto tfn = new AST.TypeSArray(AST.Type.tchar, lenfn);
+ efn.type = tfn.immutableOf();
+ efn.committed = 1;
+ auto sfn = new AST.VarDeclaration(loc, tfn, Id.__func__, ifn, STC.gshared | STC.immutable_);
+ auto e = new AST.DeclarationExp(loc, sfn);
+ return new AST.ExpStatement(loc, e);
+ }
+
+ /************************
+ * After encountering an error, scan forward until a right brace or ; is found
+ * or the end of the file.
+ */
+ void panic()
+ {
+ while (token.value != TOK.rightCurly && token.value != TOK.semicolon && token.value != TOK.endOfFile)
+ nextToken();
+ }
+
+ /**************************
+ * Apply `const` to a type.
+ * Params:
+ * t = type to add const to
+ * Returns:
+ * resulting type
+ */
+ private AST.Type toConst(AST.Type t)
+ {
+ // `const` is always applied to the return type, not the
+ // type function itself.
+ if (auto tf = t.isTypeFunction())
+ tf.next = tf.next.addSTC(STC.const_);
+ else
+ t = t.addSTC(STC.const_);
+ return t;
+ }
+
+ /***************************
+ * Apply specifier to a Dsymbol.
+ * Params:
+ * s = Dsymbol
+ * specifier = specifiers to apply
+ * Returns:
+ * Dsymbol with specifiers applied
+ */
+ private AST.Dsymbol applySpecifier(AST.Dsymbol s, ref Specifier specifier)
+ {
+ if (specifier.alignExps)
+ {
+ // Wrap declaration in an AlignDeclaration
+ auto decls = new AST.Dsymbols(1);
+ (*decls)[0] = s;
+ s = new AST.AlignDeclaration(s.loc, specifier.alignExps, decls);
+ }
+ return s;
+ }
+
+ //}
+}
diff --git a/gcc/d/dmd/cppmangle.c b/gcc/d/dmd/cppmangle.c
deleted file mode 100644
index baf64c5..0000000
--- a/gcc/d/dmd/cppmangle.c
+++ /dev/null
@@ -1,1168 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/cppmangle.c
- */
-
-/**
- * Do mangling for C++ linkage.
- *
- * References:
- * Follows Itanium C++ ABI 1.86 section 5.1
- * http://refspecs.linux-foundation.org/cxxabi-1.86.html#mangling
- * which is where the grammar comments come from.
- *
- * Bugs:
- * https://issues.dlang.org/query.cgi
- * enter `C++, mangling` as the keywords.
- */
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "dsymbol.h"
-#include "mtype.h"
-#include "scope.h"
-#include "init.h"
-#include "expression.h"
-#include "attrib.h"
-#include "declaration.h"
-#include "template.h"
-#include "id.h"
-#include "enum.h"
-#include "import.h"
-#include "aggregate.h"
-#include "target.h"
-
-typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param);
-int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL);
-
-class CppMangleVisitor : public Visitor
-{
- Objects components; // array of components available for substitution
- OutBuffer *buf; // append the mangling to buf[]
- public:
- Loc loc; // location for use in error messages
-
- // Write <seq-id> to buf
- void write_seq_id(size_t i)
- {
- if (i >= 36)
- {
- write_seq_id(i / 36);
- i %= 36;
- }
- i += (i < 10) ? '0' : 'A' - 10;
- buf->writeByte((char)i);
- }
-
- bool substitute(RootObject *p)
- {
- //printf("substitute %s\n", p ? p->toChars() : NULL);
- int i = find(p);
- if (i >= 0)
- {
- //printf("\tmatch\n");
- /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ...
- */
- buf->writeByte('S');
- if (i)
- {
- write_seq_id(i - 1);
- }
- buf->writeByte('_');
- return true;
- }
- return false;
- }
-
- /******
- * See if `p` exists in components[]
- * Returns:
- * index if found, -1 if not
- */
- int find(RootObject *p)
- {
- //printf("find %p %d %s\n", p, p.dyncast(), p ? p.toChars() : NULL);
- for (size_t i = 0; i < components.length; i++)
- {
- if (p == components[i])
- return (int)i;
- }
- return -1;
- }
-
- /*********************
- * Append p to components[]
- */
- void append(RootObject *p)
- {
- //printf("append %p %d %s\n", p, p.dyncast(), p ? p.toChars() : "null");
- components.push(p);
- }
-
- /************************
- * Determine if symbol is indeed the global ::std namespace.
- * Params:
- * s = symbol to check
- * Returns:
- * true if it is ::std
- */
- static bool isStd(Dsymbol *s)
- {
- return (s &&
- s->ident == Id::std && // the right name
- s->isNspace() && // g++ disallows global "std" for other than a namespace
- !getQualifier(s)); // at global level
- }
-
- /************************
- * Determine if type is a C++ fundamental type.
- * Params:
- * t = type to check
- * Returns:
- * true if it is a fundamental type
- */
- static bool isFundamentalType(Type *t)
- {
- // First check the target whether some specific ABI is being followed.
- bool isFundamental;
- if (target.cpp.fundamentalType(t, isFundamental))
- return isFundamental;
- if (t->ty == Tenum)
- {
- // Peel off enum type from special types.
- TypeEnum *te = (TypeEnum *)t;
- if (te->sym->isSpecial())
- t = te->sym->getMemtype(Loc());
- }
-
- // Fundamental arithmetic types:
- // 1. integral types: bool, char, int, ...
- // 2. floating point types: float, double, real
- // 3. void
- // 4. null pointer: std::nullptr_t (since C++11)
- if (t->ty == Tvoid || t->ty == Tbool)
- return true;
- else if (t->ty == Tnull && global.params.cplusplus >= CppStdRevisionCpp11)
- return true;
- else
- return t->isTypeBasic() && (t->isintegral() || t->isreal());
- }
-
- /******************************
- * Write the mangled representation of the template arguments.
- * Params:
- * ti = the template instance
- */
- void template_args(TemplateInstance *ti)
- {
- /* <template-args> ::= I <template-arg>+ E
- */
- if (!ti) // could happen if std::basic_string is not a template
- return;
- buf->writeByte('I');
- for (size_t i = 0; i < ti->tiargs->length; i++)
- {
- RootObject *o = (*ti->tiargs)[i];
- TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration();
- assert(td);
- TemplateParameter *tp = (*td->parameters)[i];
-
- /*
- * <template-arg> ::= <type> # type or template
- * ::= X <expression> E # expression
- * ::= <expr-primary> # simple expressions
- * ::= I <template-arg>* E # argument pack
- */
- if (tp->isTemplateTupleParameter())
- {
- buf->writeByte('I'); // argument pack
-
- // mangle the rest of the arguments as types
- for (size_t j = i; j < ti->tiargs->length; j++)
- {
- Type *t = isType((*ti->tiargs)[j]);
- assert(t);
- t->accept(this);
- }
-
- buf->writeByte('E');
- break;
- }
- if (tp->isTemplateTypeParameter())
- {
- Type *t = isType(o);
- assert(t);
- t->accept(this);
- }
- else if (TemplateValueParameter *tv = tp->isTemplateValueParameter())
- {
- // <expr-primary> ::= L <type> <value number> E # integer literal
- if (tv->valType->isintegral())
- {
- Expression *e = isExpression(o);
- assert(e);
- buf->writeByte('L');
- tv->valType->accept(this);
- uinteger_t val = e->toUInteger();
- if (!tv->valType->isunsigned() && (sinteger_t)val < 0)
- {
- val = -val;
- buf->writeByte('n');
- }
- buf->printf("%llu", val);
- buf->writeByte('E');
- }
- else
- {
- ti->error("Internal Compiler Error: C++ `%s` template value parameter is not supported", tv->valType->toChars());
- fatal();
- }
- }
- else if (tp->isTemplateAliasParameter())
- {
- Dsymbol *d = isDsymbol(o);
- Expression *e = isExpression(o);
- if (d && d->isFuncDeclaration())
- {
- bool is_nested = d->toParent3() &&
- !d->toParent3()->isModule() &&
- ((TypeFunction*)d->isFuncDeclaration()->type)->linkage == LINKcpp;
- if (is_nested)
- buf->writeByte('X');
- buf->writeByte('L');
- mangle_function(d->isFuncDeclaration());
- buf->writeByte('E');
- if (is_nested)
- buf->writeByte('E');
- }
- else if (e && e->op == TOKvar && ((VarExp*)e)->var->isVarDeclaration())
- {
- VarDeclaration *vd = ((VarExp*)e)->var->isVarDeclaration();
- buf->writeByte('L');
- mangle_variable(vd, true);
- buf->writeByte('E');
- }
- else if (d && d->isTemplateDeclaration() && d->isTemplateDeclaration()->onemember)
- {
- if (!substitute(d))
- {
- cpp_mangle_name(d, false);
- }
- }
- else
- {
- ti->error("Internal Compiler Error: `%s` is unsupported parameter for C++ template", o->toChars());
- fatal();
- }
- }
- else if (tp->isTemplateThisParameter())
- {
- ti->error("Internal Compiler Error: C++ `%s` template this parameter is not supported", o->toChars());
- fatal();
- }
- else
- {
- assert(0);
- }
- }
- buf->writeByte('E');
- }
-
- void source_name(Dsymbol *s)
- {
- //printf("source_name(%s)\n", s->toChars());
- if (TemplateInstance *ti = s->isTemplateInstance())
- {
- if (!substitute(ti->tempdecl))
- {
- append(ti->tempdecl);
- const char *name = ti->tempdecl->toAlias()->ident->toChars();
- buf->printf("%d", strlen(name));
- buf->writestring(name);
- }
- template_args(ti);
- }
- else
- {
- const char *name = s->ident->toChars();
- buf->printf("%d", strlen(name));
- buf->writestring(name);
- }
- }
-
- /********
- * See if s is actually an instance of a template
- * Params:
- * s = symbol
- * Returns:
- * if s is instance of a template, return the instance, otherwise return s
- */
- Dsymbol *getInstance(Dsymbol *s)
- {
- Dsymbol *p = s->toParent3();
- if (p)
- {
- if (TemplateInstance *ti = p->isTemplateInstance())
- return ti;
- }
- return s;
- }
-
- /********
- * Get qualifier for `s`, meaning the symbol
- * that s is in the symbol table of.
- * The module does not count as a qualifier, because C++
- * does not have modules.
- * Params:
- * s = symbol that may have a qualifier
- * Returns:
- * qualifier, NULL if none
- */
- static Dsymbol *getQualifier(Dsymbol *s)
- {
- Dsymbol *p = s->toParent3();
- return (p && !p->isModule()) ? p : NULL;
- }
-
- // Detect type char
- static bool isChar(RootObject *o)
- {
- Type *t = isType(o);
- return (t && t->equals(Type::tchar));
- }
-
- // Detect type ::std::char_traits<char>
- static bool isChar_traits_char(RootObject *o)
- {
- return isIdent_char(Id::char_traits, o);
- }
-
- // Detect type ::std::allocator<char>
- static bool isAllocator_char(RootObject *o)
- {
- return isIdent_char(Id::allocator, o);
- }
-
- // Detect type ::std::ident<char>
- static bool isIdent_char(Identifier *ident, RootObject *o)
- {
- Type *t = isType(o);
- if (!t || t->ty != Tstruct)
- return false;
- Dsymbol *s = ((TypeStruct*)t)->toDsymbol(NULL);
- if (s->ident != ident)
- return false;
- Dsymbol *p = s->toParent3();
- if (!p)
- return false;
- TemplateInstance *ti = p->isTemplateInstance();
- if (!ti)
- return false;
- Dsymbol *q = getQualifier(ti);
- return isStd(q) && ti->tiargs->length == 1 && isChar((*ti->tiargs)[0]);
- }
-
- /***
- * Detect template args <char, ::std::char_traits<char>>
- * and write st if found.
- * Returns:
- * true if found
- */
- bool char_std_char_traits_char(TemplateInstance *ti, const char *st)
- {
- if (ti->tiargs->length == 2 &&
- isChar((*ti->tiargs)[0]) &&
- isChar_traits_char((*ti->tiargs)[1]))
- {
- buf->writestring(st);
- return true;
- }
- return false;
- }
-
-
- void prefix_name(Dsymbol *s)
- {
- //printf("prefix_name(%s)\n", s->toChars());
- if (!substitute(s))
- {
- Dsymbol *si = getInstance(s);
- Dsymbol *p = getQualifier(si);
- if (p)
- {
- if (isStd(p))
- {
- TemplateInstance *ti = si->isTemplateInstance();
- if (ti)
- {
- if (s->ident == Id::allocator)
- {
- buf->writestring("Sa");
- template_args(ti);
- append(ti);
- return;
- }
- if (s->ident == Id::basic_string)
- {
- // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>
- if (ti->tiargs->length == 3 &&
- isChar((*ti->tiargs)[0]) &&
- isChar_traits_char((*ti->tiargs)[1]) &&
- isAllocator_char((*ti->tiargs)[2]))
-
- {
- buf->writestring("Ss");
- return;
- }
- buf->writestring("Sb"); // ::std::basic_string
- template_args(ti);
- append(ti);
- return;
- }
-
- // ::std::basic_istream<char, ::std::char_traits<char>>
- if (s->ident == Id::basic_istream &&
- char_std_char_traits_char(ti, "Si"))
- return;
-
- // ::std::basic_ostream<char, ::std::char_traits<char>>
- if (s->ident == Id::basic_ostream &&
- char_std_char_traits_char(ti, "So"))
- return;
-
- // ::std::basic_iostream<char, ::std::char_traits<char>>
- if (s->ident == Id::basic_iostream &&
- char_std_char_traits_char(ti, "Sd"))
- return;
- }
- buf->writestring("St");
- }
- else
- prefix_name(p);
- }
- source_name(si);
- if (!isStd(si))
- {
- /* Do this after the source_name() call to keep components[]
- * in the right order.
- * https://issues.dlang.org/show_bug.cgi?id=17947
- */
- append(si);
- }
- }
- }
-
- void cpp_mangle_name(Dsymbol *s, bool qualified)
- {
- //printf("cpp_mangle_name(%s, %d)\n", s->toChars(), qualified);
- Dsymbol *p = s->toParent3();
- Dsymbol *se = s;
- bool write_prefix = true;
- if (p && p->isTemplateInstance())
- {
- se = p;
- if (find(p->isTemplateInstance()->tempdecl) >= 0)
- write_prefix = false;
- p = p->toParent3();
- }
-
- if (p && !p->isModule())
- {
- /* The N..E is not required if:
- * 1. the parent is 'std'
- * 2. 'std' is the initial qualifier
- * 3. there is no CV-qualifier or a ref-qualifier for a member function
- * ABI 5.1.8
- */
- if (isStd(p) && !qualified)
- {
- TemplateInstance *ti = se->isTemplateInstance();
- if (s->ident == Id::allocator)
- {
- buf->writestring("Sa"); // "Sa" is short for ::std::allocator
- template_args(ti);
- }
- else if (s->ident == Id::basic_string)
- {
- // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>
- if (ti->tiargs->length == 3 &&
- isChar((*ti->tiargs)[0]) &&
- isChar_traits_char((*ti->tiargs)[1]) &&
- isAllocator_char((*ti->tiargs)[2]))
-
- {
- buf->writestring("Ss");
- return;
- }
- buf->writestring("Sb"); // ::std::basic_string
- template_args(ti);
- }
- else
- {
- // ::std::basic_istream<char, ::std::char_traits<char>>
- if (s->ident == Id::basic_istream)
- {
- if (char_std_char_traits_char(ti, "Si"))
- return;
- }
- else if (s->ident == Id::basic_ostream)
- {
- if (char_std_char_traits_char(ti, "So"))
- return;
- }
- else if (s->ident == Id::basic_iostream)
- {
- if (char_std_char_traits_char(ti, "Sd"))
- return;
- }
- buf->writestring("St");
- source_name(se);
- }
- }
- else
- {
- buf->writeByte('N');
- if (write_prefix)
- prefix_name(p);
- source_name(se);
- buf->writeByte('E');
- }
- }
- else
- source_name(se);
- append(s);
- }
-
- void CV_qualifiers(Type *t)
- {
- // CV-qualifiers are 'r': restrict, 'V': volatile, 'K': const
- if (t->isConst())
- buf->writeByte('K');
- }
-
- void mangle_variable(VarDeclaration *d, bool is_temp_arg_ref)
- {
- // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525
- if (!(d->storage_class & (STCextern | STCfield | STCgshared)))
- {
- d->error("Internal Compiler Error: C++ static non-`__gshared` non-`extern` variables not supported");
- fatal();
- }
-
- Dsymbol *p = d->toParent3();
- if (p && !p->isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE"
- {
- buf->writestring("_ZN");
- prefix_name(p);
- source_name(d);
- buf->writeByte('E');
- }
- else //char beta[6] should mangle as "beta"
- {
- if (!is_temp_arg_ref)
- {
- buf->writestring(d->ident->toChars());
- }
- else
- {
- buf->writestring("_Z");
- source_name(d);
- }
- }
- }
-
- void mangle_function(FuncDeclaration *d)
- {
- //printf("mangle_function(%s)\n", d->toChars());
- /*
- * <mangled-name> ::= _Z <encoding>
- */
- buf->writestring("_Z");
- this->mangle_function_encoding(d);
- }
-
- void mangle_function_encoding(FuncDeclaration *d)
- {
- //printf("mangle_function_encoding(%s)\n", d->toChars());
- /*
- * <encoding> ::= <function name> <bare-function-type>
- * ::= <data name>
- * ::= <special-name>
- */
- TypeFunction *tf = (TypeFunction *)d->type;
-
- if (getFuncTemplateDecl(d))
- {
- /* It's an instance of a function template
- */
- TemplateInstance *ti = d->parent->isTemplateInstance();
- assert(ti);
- Dsymbol *p = ti->toParent3();
- if (p && !p->isModule() && tf->linkage == LINKcpp)
- {
- buf->writeByte('N');
- CV_qualifiers(d->type);
- prefix_name(p);
- if (d->isCtorDeclaration())
- buf->writestring("C1");
- else if (d->isDtorDeclaration())
- buf->writestring("D1");
- else
- source_name(ti);
- buf->writeByte('E');
- }
- else
- source_name(ti);
- headOfType(tf->nextOf()); // mangle return type
- }
- else
- {
- Dsymbol *p = d->toParent3();
- if (p && !p->isModule() && tf->linkage == LINKcpp)
- {
- /* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
- * ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
- */
- buf->writeByte('N');
- CV_qualifiers(d->type);
-
- /* <prefix> ::= <prefix> <unqualified-name>
- * ::= <template-prefix> <template-args>
- * ::= <template-param>
- * ::= # empty
- * ::= <substitution>
- * ::= <prefix> <data-member-prefix>
- */
- prefix_name(p);
- //printf("p: %s\n", buf.peekChars());
-
- if (d->isCtorDeclaration())
- {
- buf->writestring("C1");
- }
- else if (d->isDtorDeclaration())
- {
- buf->writestring("D1");
- }
- else
- {
- source_name(d);
- }
- buf->writeByte('E');
- }
- else
- {
- source_name(d);
- }
- }
-
- if (tf->linkage == LINKcpp) //Template args accept extern "C" symbols with special mangling
- {
- assert(tf->ty == Tfunction);
- mangleFunctionParameters(tf->parameterList.parameters,
- tf->parameterList.varargs);
- }
- }
-
- void mangleFunctionParameters(Parameters *parameters, int varargs)
- {
- struct ParamsCppMangle
- {
- int numparams;
- CppMangleVisitor *mangler;
-
- static int dg(void *ctx, size_t, Parameter *fparam)
- {
- ParamsCppMangle *p = (ParamsCppMangle *)ctx;
- CppMangleVisitor *mangler = p->mangler;
- Type *t = target.cpp.parameterType(fparam);
- if (t->ty == Tsarray)
- {
- // Static arrays in D are passed by value; no counterpart in C++
- t->error(mangler->loc, "Internal Compiler Error: unable to pass static array `%s` to extern(C++) function, use pointer instead",
- t->toChars());
- fatal();
- }
- mangler->headOfType(t);
- p->numparams++;
- return 0;
- }
- };
-
- ParamsCppMangle p;
- p.numparams = 0;
- p.mangler = this;
-
- if (parameters)
- Parameter_foreach(parameters, &ParamsCppMangle::dg, (void*)&p);
-
- if (varargs)
- buf->writeByte('z');
- else if (!p.numparams)
- buf->writeByte('v'); // encode (void) parameters
- }
-
-public:
- CppMangleVisitor(OutBuffer *buf, Loc loc)
- : components(), buf(buf), loc(loc)
- {
- }
-
- /*****
- * Entry point. Append mangling to buf[]
- * Params:
- * s = symbol to mangle
- */
- void mangleOf(Dsymbol *s)
- {
- if (VarDeclaration *vd = s->isVarDeclaration())
- {
- mangle_variable(vd, false);
- }
- else if (FuncDeclaration *fd = s->isFuncDeclaration())
- {
- mangle_function(fd);
- }
- else
- {
- assert(0);
- }
- }
-
- /****** The rest is type mangling ************/
-
- void error(Type *t)
- {
- const char *p;
- if (t->isImmutable())
- p = "`immutable` ";
- else if (t->isShared())
- p = "`shared` ";
- else
- p = "";
- t->error(loc, "Internal Compiler Error: %stype `%s` can not be mapped to C++", p, t->toChars());
- fatal(); //Fatal, because this error should be handled in frontend
- }
-
- /****************************
- * Mangle a type,
- * treating it as a Head followed by a Tail.
- * Params:
- * t = Head of a type
- */
- void headOfType(Type *t)
- {
- if (t->ty == Tclass)
- {
- mangleTypeClass((TypeClass*)t, true);
- }
- else
- {
- // For value types, strip const/immutable/shared from the head of the type
- t->mutableOf()->unSharedOf()->accept(this);
- }
- }
-
- void visit(Type *t)
- {
- error(t);
- }
-
- /******
- * Write out 1 or 2 character basic type mangling.
- * Handle const and substitutions.
- * Params:
- * t = type to mangle
- * p = if not 0, then character prefix
- * c = mangling character
- */
- void writeBasicType(Type *t, char p, char c)
- {
- // Only do substitutions for non-fundamental types.
- if (!isFundamentalType(t) || t->isConst())
- {
- if (substitute(t))
- return;
- else
- append(t);
- }
- CV_qualifiers(t);
- if (p)
- buf->writeByte(p);
- buf->writeByte(c);
- }
-
- void visit(TypeNull *t)
- {
- if (t->isImmutable() || t->isShared())
- return error(t);
-
- writeBasicType(t, 'D', 'n');
- }
-
- void visit(TypeNoreturn *t)
- {
- if (t->isImmutable() || t->isShared())
- return error(t);
-
- writeBasicType(t, 0, 'v'); // mangle like `void`
- }
-
- void visit(TypeBasic *t)
- {
- if (t->isImmutable() || t->isShared())
- return error(t);
-
- // Handle any target-specific basic types.
- if (const char *tm = target.cpp.typeMangle(t))
- {
- // Only do substitutions for non-fundamental types.
- if (!isFundamentalType(t) || t->isConst())
- {
- if (substitute(t))
- return;
- else
- append(t);
- }
- CV_qualifiers(t);
- buf->writestring(tm);
- return;
- }
-
- /* <builtin-type>:
- * v void
- * w wchar_t
- * b bool
- * c char
- * a signed char
- * h unsigned char
- * s short
- * t unsigned short
- * i int
- * j unsigned int
- * l long
- * m unsigned long
- * x long long, __int64
- * y unsigned long long, __int64
- * n __int128
- * o unsigned __int128
- * f float
- * d double
- * e long double, __float80
- * g __float128
- * z ellipsis
- * Dd 64 bit IEEE 754r decimal floating point
- * De 128 bit IEEE 754r decimal floating point
- * Df 32 bit IEEE 754r decimal floating point
- * Dh 16 bit IEEE 754r half-precision floating point
- * Di char32_t
- * Ds char16_t
- * u <source-name> # vendor extended type
- */
-
- char c;
- char p = 0;
- switch (t->ty)
- {
- case Tvoid: c = 'v'; break;
- case Tint8: c = 'a'; break;
- case Tuns8: c = 'h'; break;
- case Tint16: c = 's'; break;
- case Tuns16: c = 't'; break;
- case Tint32: c = 'i'; break;
- case Tuns32: c = 'j'; break;
- case Tfloat32: c = 'f'; break;
- case Tint64:
- c = (target.c.longsize == 8 ? 'l' : 'x');
- break;
- case Tuns64:
- c = (target.c.longsize == 8 ? 'm' : 'y');
- break;
- case Tint128: c = 'n'; break;
- case Tuns128: c = 'o'; break;
- case Tfloat64: c = 'd'; break;
- case Tfloat80: c = 'e'; break;
- case Tbool: c = 'b'; break;
- case Tchar: c = 'c'; break;
- case Twchar: c = 't'; break; // unsigned short (perhaps use 'Ds' ?
- case Tdchar: c = 'w'; break; // wchar_t (UTF-32) (perhaps use 'Di' ?
- case Timaginary32: p = 'G'; c = 'f'; break; // 'G' means imaginary
- case Timaginary64: p = 'G'; c = 'd'; break;
- case Timaginary80: p = 'G'; c = 'e'; break;
- case Tcomplex32: p = 'C'; c = 'f'; break; // 'C' means complex
- case Tcomplex64: p = 'C'; c = 'd'; break;
- case Tcomplex80: p = 'C'; c = 'e'; break;
-
- default:
- return error(t);
- }
- writeBasicType(t, p, c);
- }
-
- void visit(TypeVector *t)
- {
- if (t->isImmutable() || t->isShared())
- return error(t);
-
- if (substitute(t))
- return;
- append(t);
- CV_qualifiers(t);
-
- // Handle any target-specific vector types.
- if (const char *tm = target.cpp.typeMangle(t))
- {
- buf->writestring(tm);
- }
- else
- {
- assert(t->basetype && t->basetype->ty == Tsarray);
- assert(((TypeSArray *)t->basetype)->dim);
- buf->writestring("U8__vector"); //-- Gnu ABI v.3
- t->basetype->nextOf()->accept(this);
- }
- }
-
- void visit(TypeSArray *t)
- {
- if (t->isImmutable() || t->isShared())
- return error(t);
-
- if (!substitute(t))
- append(t);
- CV_qualifiers(t);
- buf->writeByte('A');
- buf->printf("%llu", t->dim ? t->dim->toInteger() : 0);
- buf->writeByte('_');
- t->next->accept(this);
- }
-
- void visit(TypePointer *t)
- {
- if (t->isImmutable() || t->isShared())
- return error(t);
-
- if (substitute(t))
- return;
- CV_qualifiers(t);
- buf->writeByte('P');
- t->next->accept(this);
- append(t);
- }
-
- void visit(TypeReference *t)
- {
- //printf("TypeReference %s\n", t->toChars());
- if (substitute(t))
- return;
- buf->writeByte('R');
- t->next->accept(this);
- append(t);
- }
-
- void visit(TypeFunction *t)
- {
- /*
- * <function-type> ::= F [Y] <bare-function-type> E
- * <bare-function-type> ::= <signature type>+
- * # types are possible return type, then parameter types
- */
-
- /* ABI says:
- "The type of a non-static member function is considered to be different,
- for the purposes of substitution, from the type of a namespace-scope or
- static member function whose type appears similar. The types of two
- non-static member functions are considered to be different, for the
- purposes of substitution, if the functions are members of different
- classes. In other words, for the purposes of substitution, the class of
- which the function is a member is considered part of the type of
- function."
-
- BUG: Right now, types of functions are never merged, so our simplistic
- component matcher always finds them to be different.
- We should use Type::equals on these, and use different
- TypeFunctions for non-static member functions, and non-static
- member functions of different classes.
- */
- if (substitute(t))
- return;
- buf->writeByte('F');
- if (t->linkage == LINKc)
- buf->writeByte('Y');
- Type *tn = t->next;
- if (t->isref)
- tn = tn->referenceTo();
- tn->accept(this);
- mangleFunctionParameters(t->parameterList.parameters,
- t->parameterList.varargs);
- buf->writeByte('E');
- append(t);
- }
-
- void visit(TypeStruct *t)
- {
- if (t->isImmutable() || t->isShared())
- return error(t);
-
- //printf("TypeStruct %s\n", t->toChars());
- doSymbol(t);
- }
-
-
- void visit(TypeEnum *t)
- {
- if (t->isImmutable() || t->isShared())
- return error(t);
-
- /* __c_(u)long(long) and others get special mangling
- */
- Identifier *id = t->sym->ident;
- //printf("enum id = '%s'\n", id->toChars());
- if (id == Id::__c_long)
- return writeBasicType(t, 0, 'l');
- else if (id == Id::__c_ulong)
- return writeBasicType(t, 0, 'm');
- else if (id == Id::__c_wchar_t)
- return writeBasicType(t, 0, 'w');
- else if (id == Id::__c_longlong)
- return writeBasicType(t, 0, 'x');
- else if (id == Id::__c_ulonglong)
- return writeBasicType(t, 0, 'y');
- else if (id == Id::__c_complex_float)
- return writeBasicType(t, 'C', 'f');
- else if (id == Id::__c_complex_double)
- return writeBasicType(t, 'C', 'd');
- else if (id == Id::__c_complex_real)
- return writeBasicType(t, 'C', 'e');
-
- doSymbol(t);
- }
-
- /****************
- * Write structs and enums.
- * Params:
- * t = TypeStruct or TypeEnum
- */
- void doSymbol(Type *t)
- {
- if (substitute(t))
- return;
- CV_qualifiers(t);
-
- // Handle any target-specific struct types.
- if (const char *tm = target.cpp.typeMangle(t))
- {
- buf->writestring(tm);
- }
- else
- {
- Dsymbol *s = t->toDsymbol(NULL);
- Dsymbol *p = s->toParent3();
- if (p && p->isTemplateInstance())
- {
- /* https://issues.dlang.org/show_bug.cgi?id=17947
- * Substitute the template instance symbol, not the struct/enum symbol
- */
- if (substitute(p))
- return;
- }
- if (!substitute(s))
- {
- cpp_mangle_name(s, t->isConst());
- }
- }
- if (t->isConst())
- append(t);
- }
-
- void visit(TypeClass *t)
- {
- mangleTypeClass(t, false);
- }
-
- /************************
- * Mangle a class type.
- * If it's the head, treat the initial pointer as a value type.
- * Params:
- * t = class type
- * head = true for head of a type
- */
- void mangleTypeClass(TypeClass *t, bool head)
- {
- if (t->isImmutable() || t->isShared())
- return error(t);
-
- /* Mangle as a <pointer to><struct>
- */
- if (substitute(t))
- return;
- if (!head)
- CV_qualifiers(t);
- buf->writeByte('P');
-
- CV_qualifiers(t);
-
- {
- Dsymbol *s = t->toDsymbol(NULL);
- Dsymbol *p = s->toParent3();
- if (p && p->isTemplateInstance())
- {
- /* https://issues.dlang.org/show_bug.cgi?id=17947
- * Substitute the template instance symbol, not the class symbol
- */
- if (substitute(p))
- return;
- }
- }
-
- if (!substitute(t->sym))
- {
- cpp_mangle_name(t->sym, t->isConst());
- }
- if (t->isConst())
- append(NULL); // C++ would have an extra type here
- append(t);
- }
-
- const char *mangle_typeinfo(Dsymbol *s)
- {
- buf->writestring("_ZTI");
- cpp_mangle_name(s, false);
- return buf->extractChars();
- }
-};
-
-const char *toCppMangleItanium(Dsymbol *s)
-{
- //printf("toCppMangleItanium(%s)\n", s->toChars());
- OutBuffer buf;
- CppMangleVisitor v(&buf, s->loc);
- v.mangleOf(s);
- return buf.extractChars();
-}
-
-const char *cppTypeInfoMangleItanium(Dsymbol *s)
-{
- //printf("cppTypeInfoMangleItanium(%s)\n", s->toChars());
- OutBuffer buf;
- buf.writestring("_ZTI"); // "TI" means typeinfo structure
- CppMangleVisitor v(&buf, s->loc);
- v.cpp_mangle_name(s, false);
- return buf.extractChars();
-}
-
-const char *cppThunkMangleItanium(FuncDeclaration *fd, int offset)
-{
- //printf("cppThunkMangleItanium(%s)\n", fd.toChars());
- OutBuffer buf;
- buf.printf("_ZThn%u_", offset); // "Th" means thunk, "n%u" is the call offset
- CppMangleVisitor v(&buf, fd->loc);
- v.mangle_function_encoding(fd);
- return buf.extractChars();
-}
diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d
new file mode 100644
index 0000000..0381f9a
--- /dev/null
+++ b/gcc/d/dmd/cppmangle.d
@@ -0,0 +1,2540 @@
+/**
+ * Do mangling for C++ linkage.
+ *
+ * This is the POSIX side of the implementation.
+ * It exports two functions to C++, `toCppMangleItanium` and `cppTypeInfoMangleItanium`.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d, _cppmangle.d)
+ * Documentation: https://dlang.org/phobos/dmd_cppmangle.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cppmangle.d
+ *
+ * References:
+ * Follows Itanium C++ ABI 1.86 section 5.1
+ * http://refspecs.linux-foundation.org/cxxabi-1.86.html#mangling
+ * which is where the grammar comments come from.
+ *
+ * Bugs:
+ * https://issues.dlang.org/query.cgi
+ * enter `C++, mangling` as the keywords.
+ */
+
+module dmd.cppmangle;
+
+import core.stdc.string;
+import core.stdc.stdio;
+
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.declaration;
+import dmd.dsymbol;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.nspace;
+import dmd.root.array;
+import dmd.root.outbuffer;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.target;
+import dmd.tokens;
+import dmd.typesem;
+import dmd.visitor;
+
+
+// helper to check if an identifier is a C++ operator
+enum CppOperator { Cast, Assign, Eq, Index, Call, Unary, Binary, OpAssign, Unknown }
+package CppOperator isCppOperator(Identifier id)
+{
+ __gshared const(Identifier)[] operators = null;
+ if (!operators)
+ operators = [Id._cast, Id.assign, Id.eq, Id.index, Id.call, Id.opUnary, Id.opBinary, Id.opOpAssign];
+ foreach (i, op; operators)
+ {
+ if (op == id)
+ return cast(CppOperator)i;
+ }
+ return CppOperator.Unknown;
+}
+
+///
+extern(C++) const(char)* toCppMangleItanium(Dsymbol s)
+{
+ //printf("toCppMangleItanium(%s)\n", s.toChars());
+ OutBuffer buf;
+ scope CppMangleVisitor v = new CppMangleVisitor(&buf, s.loc);
+ v.mangleOf(s);
+ return buf.extractChars();
+}
+
+///
+extern(C++) const(char)* cppTypeInfoMangleItanium(Dsymbol s)
+{
+ //printf("cppTypeInfoMangle(%s)\n", s.toChars());
+ OutBuffer buf;
+ buf.writestring("_ZTI"); // "TI" means typeinfo structure
+ scope CppMangleVisitor v = new CppMangleVisitor(&buf, s.loc);
+ v.cpp_mangle_name(s, false);
+ return buf.extractChars();
+}
+
+///
+extern(C++) const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset)
+{
+ //printf("cppThunkMangleItanium(%s)\n", fd.toChars());
+ OutBuffer buf;
+ buf.printf("_ZThn%u_", offset); // "Th" means thunk, "n%u" is the call offset
+ scope CppMangleVisitor v = new CppMangleVisitor(&buf, fd.loc);
+ v.mangle_function_encoding(fd);
+ return buf.extractChars();
+}
+
+/******************************
+ * Determine if sym is the 'primary' destructor, that is,
+ * the most-aggregate destructor (the one that is defined as __xdtor)
+ * Params:
+ * sym = Dsymbol
+ * Returns:
+ * true if sym is the primary destructor for an aggregate
+ */
+bool isPrimaryDtor(const Dsymbol sym)
+{
+ const dtor = sym.isDtorDeclaration();
+ if (!dtor)
+ return false;
+ const ad = dtor.isMember();
+ assert(ad);
+ return dtor == ad.primaryDtor;
+}
+
+/// Context used when processing pre-semantic AST
+private struct Context
+{
+ /// Template instance of the function being mangled
+ TemplateInstance ti;
+ /// Function declaration we're mangling
+ FuncDeclaration fd;
+ /// Current type / expression being processed (semantically analyzed)
+ RootObject res;
+
+ @disable ref Context opAssign(ref Context other);
+ @disable ref Context opAssign(Context other);
+
+ /**
+ * Helper function to track `res`
+ *
+ * Params:
+ * next = Value to set `this.res` to.
+ * If `this.res` is `null`, the expression is not evalutated.
+ * This allow this code to be used even when no context is needed.
+ *
+ * Returns:
+ * The previous state of this `Context` object
+ */
+ private Context push(lazy RootObject next)
+ {
+ auto r = this.res;
+ if (r !is null)
+ this.res = next;
+ return Context(this.ti, this.fd, r);
+ }
+
+ /**
+ * Reset the context to a previous one, making any adjustment necessary
+ */
+ private void pop(ref Context prev)
+ {
+ this.res = prev.res;
+ }
+}
+
+private final class CppMangleVisitor : Visitor
+{
+ /// Context used when processing pre-semantic AST
+ private Context context;
+
+ ABITagContainer abiTags; /// Container for already-written ABI tags
+ Objects components; /// array of components available for substitution
+ OutBuffer* buf; /// append the mangling to buf[]
+ Loc loc; /// location for use in error messages
+
+ /**
+ * Constructor
+ *
+ * Params:
+ * buf = `OutBuffer` to write the mangling to
+ * loc = `Loc` of the symbol being mangled
+ */
+ this(OutBuffer* buf, Loc loc)
+ {
+ this.buf = buf;
+ this.loc = loc;
+ }
+
+ /*****
+ * Entry point. Append mangling to buf[]
+ * Params:
+ * s = symbol to mangle
+ */
+ void mangleOf(Dsymbol s)
+ {
+ if (VarDeclaration vd = s.isVarDeclaration())
+ {
+ mangle_variable(vd, vd.cppnamespace !is null);
+ }
+ else if (FuncDeclaration fd = s.isFuncDeclaration())
+ {
+ mangle_function(fd);
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+
+ /**
+ * Mangle the return type of a function
+ *
+ * This is called on a templated function type.
+ * Context is set to the `FuncDeclaration`.
+ *
+ * Params:
+ * preSemantic = the `FuncDeclaration`'s `originalType`
+ */
+ void mangleReturnType(TypeFunction preSemantic)
+ {
+ auto tf = cast(TypeFunction)this.context.res.asFuncDecl().type;
+ Type rt = preSemantic.nextOf();
+ if (tf.isref)
+ rt = rt.referenceTo();
+ auto prev = this.context.push(tf.nextOf());
+ scope (exit) this.context.pop(prev);
+ this.headOfType(rt);
+ }
+
+ /**
+ * Write a seq-id from an index number, excluding the terminating '_'
+ *
+ * Params:
+ * idx = the index in a substitution list.
+ * Note that index 0 has no value, and `S0_` would be the
+ * substitution at index 1 in the list.
+ *
+ * See-Also:
+ * https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id
+ */
+ private void writeSequenceFromIndex(size_t idx)
+ {
+ if (idx)
+ {
+ void write_seq_id(size_t i)
+ {
+ if (i >= 36)
+ {
+ write_seq_id(i / 36);
+ i %= 36;
+ }
+ i += (i < 10) ? '0' : 'A' - 10;
+ buf.writeByte(cast(char)i);
+ }
+
+ write_seq_id(idx - 1);
+ }
+ }
+
+ /**
+ * Attempt to perform substitution on `p`
+ *
+ * If `p` already appeared in the mangling, it is stored as
+ * a 'part', and short references in the form of `SX_` can be used.
+ * Note that `p` can be anything: template declaration, struct declaration,
+ * class declaration, namespace...
+ *
+ * Params:
+ * p = The object to attempt to substitute
+ * nested = Whether or not `p` is to be considered nested.
+ * When `true`, `N` will be prepended before the substitution.
+ *
+ * Returns:
+ * Whether `p` already appeared in the mangling,
+ * and substitution has been written to `this.buf`.
+ */
+ bool substitute(RootObject p, bool nested = false)
+ {
+ //printf("substitute %s\n", p ? p.toChars() : null);
+ auto i = find(p);
+ if (i < 0)
+ return false;
+
+ //printf("\tmatch\n");
+ /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ...
+ */
+ if (nested)
+ buf.writeByte('N');
+ buf.writeByte('S');
+ writeSequenceFromIndex(i);
+ buf.writeByte('_');
+ return true;
+ }
+
+ /******
+ * See if `p` exists in components[]
+ *
+ * Note that components can contain `null` entries,
+ * as the index used in mangling is based on the index in the array.
+ *
+ * If called with an object whose dynamic type is `Nspace`,
+ * calls the `find(Nspace)` overload.
+ *
+ * Returns:
+ * index if found, -1 if not
+ */
+ int find(RootObject p)
+ {
+ //printf("find %p %d %s\n", p, p.dyncast(), p ? p.toChars() : null);
+ scope v = new ComponentVisitor(p);
+ foreach (i, component; components)
+ {
+ if (component)
+ component.visitObject(v);
+ if (v.result)
+ return cast(int)i;
+ }
+ return -1;
+ }
+
+ /*********************
+ * Append p to components[]
+ */
+ void append(RootObject p)
+ {
+ //printf("append %p %d %s\n", p, p.dyncast(), p ? p.toChars() : "null");
+ components.push(p);
+ }
+
+ /**
+ * Write an identifier preceded by its length
+ *
+ * Params:
+ * ident = `Identifier` to write to `this.buf`
+ */
+ void writeIdentifier(const ref Identifier ident)
+ {
+ const name = ident.toString();
+ this.buf.print(name.length);
+ this.buf.writestring(name);
+ }
+
+ /**
+ * Insert the leftover ABI tags to the buffer
+ *
+ * This inset ABI tags that hasn't already been written
+ * after the mangled name of the function.
+ * For more details, see the `abiTags` variable.
+ *
+ * Params:
+ * off = Offset to insert at
+ * fd = Type of the function to mangle the return type of
+ */
+ void writeRemainingTags(size_t off, TypeFunction tf)
+ {
+ scope remainingVisitor = new LeftoverVisitor(&this.abiTags.written);
+ tf.next.accept(remainingVisitor);
+ OutBuffer b2;
+ foreach (se; remainingVisitor.toWrite)
+ {
+ auto tag = se.peekString();
+ // We can only insert a slice, and each insert is a memmove,
+ // so use a temporary buffer to keep it efficient.
+ b2.reset();
+ b2.writestring("B");
+ b2.print(tag.length);
+ b2.writestring(tag);
+ this.buf.insert(off, b2[]);
+ off += b2.length;
+ }
+ }
+
+ /************************
+ * Determine if symbol is indeed the global ::std namespace.
+ * Params:
+ * s = symbol to check
+ * Returns:
+ * true if it is ::std
+ */
+ static bool isStd(Dsymbol s)
+ {
+ if (!s)
+ return false;
+
+ if (auto cnd = s.isCPPNamespaceDeclaration())
+ return isStd(cnd);
+
+ return (s.ident == Id.std && // the right name
+ s.isNspace() && // g++ disallows global "std" for other than a namespace
+ !getQualifier(s)); // at global level
+ }
+
+ /// Ditto
+ static bool isStd(CPPNamespaceDeclaration s)
+ {
+ return s && s.cppnamespace is null && s.ident == Id.std;
+ }
+
+ /************************
+ * Determine if type is a C++ fundamental type.
+ * Params:
+ * t = type to check
+ * Returns:
+ * true if it is a fundamental type
+ */
+ static bool isFundamentalType(Type t)
+ {
+ // First check the target whether some specific ABI is being followed.
+ bool isFundamental = void;
+ if (target.cpp.fundamentalType(t, isFundamental))
+ return isFundamental;
+
+ if (auto te = t.isTypeEnum())
+ {
+ // Peel off enum type from special types.
+ if (te.sym.isSpecial())
+ t = te.memType();
+ }
+
+ // Fundamental arithmetic types:
+ // 1. integral types: bool, char, int, ...
+ // 2. floating point types: float, double, real
+ // 3. void
+ // 4. null pointer: std::nullptr_t (since C++11)
+ if (t.ty == Tvoid || t.ty == Tbool)
+ return true;
+ else if (t.ty == Tnull && global.params.cplusplus >= CppStdRevision.cpp11)
+ return true;
+ else
+ return t.isTypeBasic() && (t.isintegral() || t.isreal());
+ }
+
+ /******************************
+ * Write the mangled representation of a template argument.
+ * Params:
+ * ti = the template instance
+ * arg = the template argument index
+ */
+ void template_arg(TemplateInstance ti, size_t arg)
+ {
+ TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
+ assert(td);
+ TemplateParameter tp = (*td.parameters)[arg];
+ RootObject o = (*ti.tiargs)[arg];
+
+ auto prev = this.context.push({
+ TemplateInstance parentti;
+ if (this.context.res.dyncast() == DYNCAST.dsymbol)
+ parentti = this.context.res.asFuncDecl().parent.isTemplateInstance();
+ else
+ parentti = this.context.res.asType().toDsymbol(null).parent.isTemplateInstance();
+ return (*parentti.tiargs)[arg];
+ }());
+ scope (exit) this.context.pop(prev);
+
+ if (tp.isTemplateTypeParameter())
+ {
+ Type t = isType(o);
+ assert(t);
+ t.accept(this);
+ }
+ else if (TemplateValueParameter tv = tp.isTemplateValueParameter())
+ {
+ // <expr-primary> ::= L <type> <value number> E # integer literal
+ if (tv.valType.isintegral())
+ {
+ Expression e = isExpression(o);
+ assert(e);
+ buf.writeByte('L');
+ tv.valType.accept(this);
+ auto val = e.toUInteger();
+ if (!tv.valType.isunsigned() && cast(sinteger_t)val < 0)
+ {
+ val = -val;
+ buf.writeByte('n');
+ }
+ buf.print(val);
+ buf.writeByte('E');
+ }
+ else
+ {
+ ti.error("Internal Compiler Error: C++ `%s` template value parameter is not supported", tv.valType.toChars());
+ fatal();
+ }
+ }
+ else if (tp.isTemplateAliasParameter())
+ {
+ // Passing a function as alias parameter is the same as passing
+ // `&function`
+ Dsymbol d = isDsymbol(o);
+ Expression e = isExpression(o);
+ if (d && d.isFuncDeclaration())
+ {
+ // X .. E => template parameter is an expression
+ // 'ad' => unary operator ('&')
+ // L .. E => is a <expr-primary>
+ buf.writestring("XadL");
+ mangle_function(d.isFuncDeclaration());
+ buf.writestring("EE");
+ }
+ else if (e && e.op == TOK.variable && (cast(VarExp)e).var.isVarDeclaration())
+ {
+ VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration();
+ buf.writeByte('L');
+ mangle_variable(vd, true);
+ buf.writeByte('E');
+ }
+ else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember)
+ {
+ if (!substitute(d))
+ {
+ cpp_mangle_name(d, false);
+ }
+ }
+ else
+ {
+ ti.error("Internal Compiler Error: C++ `%s` template alias parameter is not supported", o.toChars());
+ fatal();
+ }
+ }
+ else if (tp.isTemplateThisParameter())
+ {
+ ti.error("Internal Compiler Error: C++ `%s` template this parameter is not supported", o.toChars());
+ fatal();
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+
+ /******************************
+ * Write the mangled representation of the template arguments.
+ * Params:
+ * ti = the template instance
+ * firstArg = index of the first template argument to mangle
+ * (used for operator overloading)
+ * Returns:
+ * true if any arguments were written
+ */
+ bool template_args(TemplateInstance ti, int firstArg = 0)
+ {
+ /* <template-args> ::= I <template-arg>+ E
+ */
+ if (!ti || ti.tiargs.dim <= firstArg) // could happen if std::basic_string is not a template
+ return false;
+ buf.writeByte('I');
+ foreach (i; firstArg .. ti.tiargs.dim)
+ {
+ TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
+ assert(td);
+ TemplateParameter tp = (*td.parameters)[i];
+
+ /*
+ * <template-arg> ::= <type> # type or template
+ * ::= X <expression> E # expression
+ * ::= <expr-primary> # simple expressions
+ * ::= J <template-arg>* E # argument pack
+ *
+ * Reference: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.template-arg
+ */
+ if (TemplateTupleParameter tt = tp.isTemplateTupleParameter())
+ {
+ buf.writeByte('J'); // argument pack
+
+ // mangle the rest of the arguments as types
+ foreach (j; i .. (*ti.tiargs).dim)
+ {
+ Type t = isType((*ti.tiargs)[j]);
+ assert(t);
+ t.accept(this);
+ }
+
+ buf.writeByte('E');
+ break;
+ }
+
+ template_arg(ti, i);
+ }
+ buf.writeByte('E');
+ return true;
+ }
+
+ /**
+ * Write the symbol `p` if not null, then execute the delegate
+ *
+ * Params:
+ * p = Symbol to write
+ * dg = Delegate to execute
+ */
+ void writeChained(Dsymbol p, scope void delegate() dg)
+ {
+ if (p && !p.isModule())
+ {
+ buf.writestring("N");
+ source_name(p, true);
+ dg();
+ buf.writestring("E");
+ }
+ else
+ dg();
+ }
+
+ /**
+ * Write the name of `s` to the buffer
+ *
+ * Params:
+ * s = Symbol to write the name of
+ * haveNE = Whether `N..E` is already part of the mangling
+ * Because `Nspace` and `CPPNamespaceAttribute` can be
+ * mixed, this is a mandatory hack.
+ */
+ void source_name(Dsymbol s, bool haveNE = false)
+ {
+ version (none)
+ {
+ printf("source_name(%s)\n", s.toChars());
+ auto sl = this.buf.peekSlice();
+ assert(sl.length == 0 || haveNE || s.cppnamespace is null || sl != "_ZN");
+ }
+ auto ti = s.isTemplateInstance();
+
+ if (!ti)
+ {
+ auto ag = s.isAggregateDeclaration();
+ const ident = (ag && ag.mangleOverride) ? ag.mangleOverride.id : s.ident;
+ this.writeNamespace(s.cppnamespace, () {
+ this.writeIdentifier(ident);
+ this.abiTags.writeSymbol(s, this);
+ },
+ haveNE);
+ return;
+ }
+
+ bool needsTa = false;
+
+ // https://issues.dlang.org/show_bug.cgi?id=20413
+ // N..E is not needed when substituting members of the std namespace.
+ // This is observed in the GCC and Clang implementations.
+ // The Itanium specification is not clear enough on this specific case.
+ // References:
+ // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.name
+ // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression
+ Dsymbol q = getQualifier(ti.tempdecl);
+ Dsymbol ns = ti.tempdecl.cppnamespace;
+ const inStd = ns && isStd(ns) || q && isStd(q);
+ const isNested = !inStd && (ns || q);
+
+ if (substitute(ti.tempdecl, !haveNE && isNested))
+ {
+ template_args(ti);
+ if (!haveNE && isNested)
+ buf.writeByte('E');
+ return;
+ }
+ else if (this.writeStdSubstitution(ti, needsTa))
+ {
+ this.abiTags.writeSymbol(ti, this);
+ if (needsTa)
+ template_args(ti);
+ return;
+ }
+
+ auto ag = ti.aliasdecl ? ti.aliasdecl.isAggregateDeclaration() : null;
+ if (ag && ag.mangleOverride)
+ {
+ this.writeNamespace(
+ ti.toAlias().cppnamespace, () {
+ this.writeIdentifier(ag.mangleOverride.id);
+ if (ag.mangleOverride.agg && ag.mangleOverride.agg.isInstantiated())
+ {
+ auto to = ag.mangleOverride.agg.isInstantiated();
+ append(to);
+ this.abiTags.writeSymbol(to.tempdecl, this);
+ template_args(to);
+ }
+ }, haveNE);
+ }
+ else
+ {
+ this.writeNamespace(
+ s.cppnamespace, () {
+ this.writeIdentifier(ti.tempdecl.toAlias().ident);
+ append(ti.tempdecl);
+ this.abiTags.writeSymbol(ti.tempdecl, this);
+ template_args(ti);
+ }, haveNE);
+ }
+ }
+
+ /********
+ * See if s is actually an instance of a template
+ * Params:
+ * s = symbol
+ * Returns:
+ * if s is instance of a template, return the instance, otherwise return s
+ */
+ static Dsymbol getInstance(Dsymbol s)
+ {
+ Dsymbol p = s.toParent();
+ if (p)
+ {
+ if (TemplateInstance ti = p.isTemplateInstance())
+ return ti;
+ }
+ return s;
+ }
+
+ /// Get the namespace of a template instance
+ CPPNamespaceDeclaration getTiNamespace(TemplateInstance ti)
+ {
+ // If we receive a pre-semantic `TemplateInstance`,
+ // `cppnamespace` is always `null`
+ return ti.tempdecl ? ti.cppnamespace
+ : this.context.res.asType().toDsymbol(null).cppnamespace;
+ }
+
+ /********
+ * Get qualifier for `s`, meaning the symbol
+ * that s is in the symbol table of.
+ * The module does not count as a qualifier, because C++
+ * does not have modules.
+ * Params:
+ * s = symbol that may have a qualifier
+ * s is rewritten to be TemplateInstance if s is one
+ * Returns:
+ * qualifier, null if none
+ */
+ static Dsymbol getQualifier(Dsymbol s)
+ {
+ Dsymbol p = s.toParent();
+ return (p && !p.isModule()) ? p : null;
+ }
+
+ // Detect type char
+ static bool isChar(RootObject o)
+ {
+ Type t = isType(o);
+ return (t && t.equals(Type.tchar));
+ }
+
+ // Detect type ::std::char_traits<char>
+ bool isChar_traits_char(RootObject o)
+ {
+ return isIdent_char(Id.char_traits, o);
+ }
+
+ // Detect type ::std::allocator<char>
+ bool isAllocator_char(RootObject o)
+ {
+ return isIdent_char(Id.allocator, o);
+ }
+
+ // Detect type ::std::ident<char>
+ bool isIdent_char(Identifier ident, RootObject o)
+ {
+ Type t = isType(o);
+ if (!t || t.ty != Tstruct)
+ return false;
+ Dsymbol s = (cast(TypeStruct)t).toDsymbol(null);
+ if (s.ident != ident)
+ return false;
+ Dsymbol p = s.toParent();
+ if (!p)
+ return false;
+ TemplateInstance ti = p.isTemplateInstance();
+ if (!ti)
+ return false;
+ Dsymbol q = getQualifier(ti);
+ const bool inStd = isStd(q) || isStd(this.getTiNamespace(ti));
+ return inStd && ti.tiargs.dim == 1 && isChar((*ti.tiargs)[0]);
+ }
+
+ /***
+ * Detect template args <char, ::std::char_traits<char>>
+ * and write st if found.
+ * Returns:
+ * true if found
+ */
+ bool char_std_char_traits_char(TemplateInstance ti, string st)
+ {
+ if (ti.tiargs.dim == 2 &&
+ isChar((*ti.tiargs)[0]) &&
+ isChar_traits_char((*ti.tiargs)[1]))
+ {
+ buf.writestring(st.ptr);
+ return true;
+ }
+ return false;
+ }
+
+
+ void prefix_name(Dsymbol s)
+ {
+ //printf("prefix_name(%s)\n", s.toChars());
+ if (substitute(s))
+ return;
+ if (isStd(s))
+ return buf.writestring("St");
+
+ auto si = getInstance(s);
+ Dsymbol p = getQualifier(si);
+ if (p)
+ {
+ if (isStd(p))
+ {
+ bool needsTa;
+ auto ti = si.isTemplateInstance();
+ if (this.writeStdSubstitution(ti, needsTa))
+ {
+ this.abiTags.writeSymbol(ti, this);
+ if (needsTa)
+ {
+ template_args(ti);
+ append(ti);
+ }
+ return;
+ }
+ buf.writestring("St");
+ }
+ else
+ prefix_name(p);
+ }
+ source_name(si, true);
+ if (!isStd(si))
+ /* Do this after the source_name() call to keep components[]
+ * in the right order.
+ * https://issues.dlang.org/show_bug.cgi?id=17947
+ */
+ append(si);
+ }
+
+ /**
+ * Write common substitution for standard types, such as std::allocator
+ *
+ * This function assumes that the symbol `ti` is in the namespace `std`.
+ *
+ * Params:
+ * ti = Template instance to consider
+ * needsTa = If this function returns `true`, this value indicates
+ * if additional template argument mangling is needed
+ *
+ * Returns:
+ * `true` if a special std symbol was found
+ */
+ bool writeStdSubstitution(TemplateInstance ti, out bool needsTa)
+ {
+ if (!ti)
+ return false;
+ if (!isStd(this.getTiNamespace(ti)) && !isStd(getQualifier(ti)))
+ return false;
+
+ if (ti.name == Id.allocator)
+ {
+ buf.writestring("Sa");
+ needsTa = true;
+ return true;
+ }
+ if (ti.name == Id.basic_string)
+ {
+ // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>
+ if (ti.tiargs.dim == 3 &&
+ isChar((*ti.tiargs)[0]) &&
+ isChar_traits_char((*ti.tiargs)[1]) &&
+ isAllocator_char((*ti.tiargs)[2]))
+
+ {
+ buf.writestring("Ss");
+ return true;
+ }
+ buf.writestring("Sb"); // ::std::basic_string
+ needsTa = true;
+ return true;
+ }
+
+ // ::std::basic_istream<char, ::std::char_traits<char>>
+ if (ti.name == Id.basic_istream &&
+ char_std_char_traits_char(ti, "Si"))
+ return true;
+
+ // ::std::basic_ostream<char, ::std::char_traits<char>>
+ if (ti.name == Id.basic_ostream &&
+ char_std_char_traits_char(ti, "So"))
+ return true;
+
+ // ::std::basic_iostream<char, ::std::char_traits<char>>
+ if (ti.name == Id.basic_iostream &&
+ char_std_char_traits_char(ti, "Sd"))
+ return true;
+
+ return false;
+ }
+
+ void cpp_mangle_name(Dsymbol s, bool qualified)
+ {
+ //printf("cpp_mangle_name(%s, %d)\n", s.toChars(), qualified);
+ Dsymbol p = s.toParent();
+ Dsymbol se = s;
+ bool write_prefix = true;
+ if (p && p.isTemplateInstance())
+ {
+ se = p;
+ if (find(p.isTemplateInstance().tempdecl) >= 0)
+ write_prefix = false;
+ p = p.toParent();
+ }
+ if (!p || p.isModule())
+ {
+ source_name(se, false);
+ append(s);
+ return;
+ }
+
+ if (!isStd(p) || qualified)
+ {
+ buf.writeByte('N');
+ if (write_prefix)
+ {
+ if (isStd(p))
+ buf.writestring("St");
+ else
+ prefix_name(p);
+ }
+ source_name(se, true);
+ buf.writeByte('E');
+ append(s);
+ return;
+ }
+ /* The N..E is not required if:
+ * 1. the parent is 'std'
+ * 2. 'std' is the initial qualifier
+ * 3. there is no CV-qualifier or a ref-qualifier for a member function
+ * ABI 5.1.8
+ */
+ TemplateInstance ti = se.isTemplateInstance();
+ if (s.ident == Id.allocator)
+ {
+ buf.writestring("Sa"); // "Sa" is short for ::std::allocator
+ template_args(ti);
+ }
+ else if (s.ident == Id.basic_string)
+ {
+ // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>
+ if (ti.tiargs.dim == 3 &&
+ isChar((*ti.tiargs)[0]) &&
+ isChar_traits_char((*ti.tiargs)[1]) &&
+ isAllocator_char((*ti.tiargs)[2]))
+ {
+ buf.writestring("Ss");
+ return;
+ }
+ buf.writestring("Sb"); // ::std::basic_string
+ template_args(ti);
+ }
+ else
+ {
+ // ::std::basic_istream<char, ::std::char_traits<char>>
+ if (s.ident == Id.basic_istream)
+ {
+ if (char_std_char_traits_char(ti, "Si"))
+ return;
+ }
+ else if (s.ident == Id.basic_ostream)
+ {
+ if (char_std_char_traits_char(ti, "So"))
+ return;
+ }
+ else if (s.ident == Id.basic_iostream)
+ {
+ if (char_std_char_traits_char(ti, "Sd"))
+ return;
+ }
+ buf.writestring("St");
+ source_name(se, true);
+ }
+ append(s);
+ }
+
+ /**
+ * Write CV-qualifiers to the buffer
+ *
+ * CV-qualifiers are 'r': restrict (unused in D), 'V': volatile, 'K': const
+ *
+ * See_Also:
+ * https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.CV-qualifiers
+ */
+ void CV_qualifiers(const Type t)
+ {
+ if (t.isConst())
+ buf.writeByte('K');
+ }
+
+ /**
+ * Mangles a variable
+ *
+ * Params:
+ * d = Variable declaration to mangle
+ * isNested = Whether this variable is nested, e.g. a template parameter
+ * or within a namespace
+ */
+ void mangle_variable(VarDeclaration d, bool isNested)
+ {
+ // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525
+ if (!(d.storage_class & (STC.extern_ | STC.field | STC.gshared)))
+ {
+ d.error("Internal Compiler Error: C++ static non-`__gshared` non-`extern` variables not supported");
+ fatal();
+ }
+ Dsymbol p = d.toParent();
+ if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE"
+ {
+ buf.writestring("_ZN");
+ prefix_name(p);
+ source_name(d, true);
+ buf.writeByte('E');
+ }
+ else if (isNested)
+ {
+ buf.writestring("_Z");
+ source_name(d, false);
+ }
+ else
+ {
+ if (auto varTags = ABITagContainer.forSymbol(d))
+ {
+ buf.writestring("_Z");
+ source_name(d, false);
+ return;
+ }
+ if (auto typeTags = ABITagContainer.forSymbol(d.type.toDsymbol(null)))
+ {
+ buf.writestring("_Z");
+ source_name(d, false);
+ this.abiTags.write(*this.buf, typeTags);
+ return;
+ }
+ //char beta[6] should mangle as "beta"
+ buf.writestring(d.ident.toString());
+ }
+ }
+
+ void mangle_function(FuncDeclaration d)
+ {
+ //printf("mangle_function(%s)\n", d.toChars());
+ /*
+ * <mangled-name> ::= _Z <encoding>
+ */
+ buf.writestring("_Z");
+ this.mangle_function_encoding(d);
+ }
+
+ void mangle_function_encoding(FuncDeclaration d)
+ {
+ //printf("mangle_function_encoding(%s)\n", d.toChars());
+ /*
+ * <encoding> ::= <function name> <bare-function-type>
+ * ::= <data name>
+ * ::= <special-name>
+ */
+ TypeFunction tf = cast(TypeFunction)d.type;
+
+ if (TemplateDeclaration ftd = getFuncTemplateDecl(d))
+ {
+ /* It's an instance of a function template
+ */
+ TemplateInstance ti = d.parent.isTemplateInstance();
+ assert(ti);
+ this.mangleTemplatedFunction(d, tf, ftd, ti);
+ return;
+ }
+
+ Dsymbol p = d.toParent();
+ if (p && !p.isModule() && tf.linkage == LINK.cpp)
+ {
+ this.mangleNestedFuncPrefix(tf, p);
+
+ if (auto ctor = d.isCtorDeclaration())
+ buf.writestring(ctor.isCpCtor ? "C2" : "C1");
+ else if (d.isPrimaryDtor())
+ buf.writestring("D1");
+ else if (d.ident && d.ident == Id.assign)
+ buf.writestring("aS");
+ else if (d.ident && d.ident == Id.eq)
+ buf.writestring("eq");
+ else if (d.ident && d.ident == Id.index)
+ buf.writestring("ix");
+ else if (d.ident && d.ident == Id.call)
+ buf.writestring("cl");
+ else
+ source_name(d, true);
+ buf.writeByte('E');
+ }
+ else
+ {
+ source_name(d, false);
+ }
+
+ // Save offset for potentially writing tags
+ const size_t off = this.buf.length();
+
+ // Template args accept extern "C" symbols with special mangling
+ if (tf.linkage == LINK.cpp)
+ mangleFunctionParameters(tf.parameterList);
+
+ if (!tf.next.isTypeBasic())
+ this.writeRemainingTags(off, tf);
+ }
+
+ /**
+ * Recursively mangles a non-scoped namespace
+ *
+ * Parameters:
+ * ns = Namespace to mangle
+ * dg = A delegate to write the identifier in this namespace
+ * haveNE = When `false` (the default), surround the namespace / dg
+ * call with nested name qualifier (`N..E`).
+ * Otherwise, they are already present (e.g. `Nspace` was used).
+ */
+ void writeNamespace(CPPNamespaceDeclaration ns, scope void delegate() dg,
+ bool haveNE = false)
+ {
+ void runDg () { if (dg !is null) dg(); }
+
+ if (ns is null || ns.ident is null)
+ return runDg();
+
+ if (isStd(ns))
+ {
+ if (!substitute(ns))
+ buf.writestring("St");
+ runDg();
+ }
+ else if (dg !is null)
+ {
+ if (!haveNE)
+ buf.writestring("N");
+ if (!substitute(ns))
+ {
+ this.writeNamespace(ns.cppnamespace, null);
+ this.writeIdentifier(ns.ident);
+ append(ns);
+ }
+ dg();
+ if (!haveNE)
+ buf.writestring("E");
+ }
+ else if (!substitute(ns))
+ {
+ this.writeNamespace(ns.cppnamespace, null);
+ this.writeIdentifier(ns.ident);
+ append(ns);
+ }
+ }
+
+ /**
+ * Mangles a function template to C++
+ *
+ * Params:
+ * d = Function declaration
+ * tf = Function type (casted d.type)
+ * ftd = Template declaration (ti.templdecl)
+ * ti = Template instance (d.parent)
+ */
+ void mangleTemplatedFunction(FuncDeclaration d, TypeFunction tf,
+ TemplateDeclaration ftd, TemplateInstance ti)
+ {
+ Dsymbol p = ti.toParent();
+ // Check if this function is *not* nested
+ if (!p || p.isModule() || tf.linkage != LINK.cpp)
+ {
+ this.context.ti = ti;
+ this.context.fd = d;
+ this.context.res = d;
+ TypeFunction preSemantic = cast(TypeFunction)d.originalType;
+ auto nspace = ti.toParent();
+ if (nspace && nspace.isNspace())
+ this.writeChained(ti.toParent(), () => source_name(ti, true));
+ else
+ source_name(ti, false);
+ this.mangleReturnType(preSemantic);
+ this.mangleFunctionParameters(ParameterList(preSemantic.parameterList.parameters, tf.parameterList.varargs));
+ return;
+ }
+
+ // It's a nested function (e.g. a member of an aggregate)
+ this.mangleNestedFuncPrefix(tf, p);
+
+ if (d.isCtorDeclaration())
+ {
+ buf.writestring("C1");
+ mangleFunctionParameters(tf.parameterList);
+ return;
+ }
+ else if (d.isPrimaryDtor())
+ {
+ buf.writestring("D1");
+ mangleFunctionParameters(tf.parameterList);
+ return;
+ }
+
+ int firstTemplateArg = 0;
+ bool appendReturnType = true;
+ bool isConvertFunc = false;
+ string symName;
+
+ // test for special symbols
+ CppOperator whichOp = isCppOperator(ti.name);
+ final switch (whichOp)
+ {
+ case CppOperator.Unknown:
+ break;
+ case CppOperator.Cast:
+ symName = "cv";
+ firstTemplateArg = 1;
+ isConvertFunc = true;
+ appendReturnType = false;
+ break;
+ case CppOperator.Assign:
+ symName = "aS";
+ break;
+ case CppOperator.Eq:
+ symName = "eq";
+ break;
+ case CppOperator.Index:
+ symName = "ix";
+ break;
+ case CppOperator.Call:
+ symName = "cl";
+ break;
+ case CppOperator.Unary:
+ case CppOperator.Binary:
+ case CppOperator.OpAssign:
+ TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
+ assert(td);
+ assert(ti.tiargs.dim >= 1);
+ TemplateParameter tp = (*td.parameters)[0];
+ TemplateValueParameter tv = tp.isTemplateValueParameter();
+ if (!tv || !tv.valType.isString())
+ break; // expecting a string argument to operators!
+ Expression exp = (*ti.tiargs)[0].isExpression();
+ StringExp str = exp.toStringExp();
+ switch (whichOp)
+ {
+ case CppOperator.Unary:
+ switch (str.peekString())
+ {
+ case "*": symName = "de"; goto continue_template;
+ case "++": symName = "pp"; goto continue_template;
+ case "--": symName = "mm"; goto continue_template;
+ case "-": symName = "ng"; goto continue_template;
+ case "+": symName = "ps"; goto continue_template;
+ case "~": symName = "co"; goto continue_template;
+ default: break;
+ }
+ break;
+ case CppOperator.Binary:
+ switch (str.peekString())
+ {
+ case ">>": symName = "rs"; goto continue_template;
+ case "<<": symName = "ls"; goto continue_template;
+ case "*": symName = "ml"; goto continue_template;
+ case "-": symName = "mi"; goto continue_template;
+ case "+": symName = "pl"; goto continue_template;
+ case "&": symName = "an"; goto continue_template;
+ case "/": symName = "dv"; goto continue_template;
+ case "%": symName = "rm"; goto continue_template;
+ case "^": symName = "eo"; goto continue_template;
+ case "|": symName = "or"; goto continue_template;
+ default: break;
+ }
+ break;
+ case CppOperator.OpAssign:
+ switch (str.peekString())
+ {
+ case "*": symName = "mL"; goto continue_template;
+ case "+": symName = "pL"; goto continue_template;
+ case "-": symName = "mI"; goto continue_template;
+ case "/": symName = "dV"; goto continue_template;
+ case "%": symName = "rM"; goto continue_template;
+ case ">>": symName = "rS"; goto continue_template;
+ case "<<": symName = "lS"; goto continue_template;
+ case "&": symName = "aN"; goto continue_template;
+ case "|": symName = "oR"; goto continue_template;
+ case "^": symName = "eO"; goto continue_template;
+ default: break;
+ }
+ break;
+ default:
+ assert(0);
+ continue_template:
+ firstTemplateArg = 1;
+ break;
+ }
+ break;
+ }
+ if (symName.length == 0)
+ source_name(ti, true);
+ else
+ {
+ buf.writestring(symName);
+ if (isConvertFunc)
+ template_arg(ti, 0);
+ appendReturnType = template_args(ti, firstTemplateArg) && appendReturnType;
+ }
+ buf.writeByte('E');
+ if (appendReturnType)
+ headOfType(tf.nextOf()); // mangle return type
+ mangleFunctionParameters(tf.parameterList);
+ }
+
+ /**
+ * Mangle the parameters of a function
+ *
+ * For templated functions, `context.res` is set to the `FuncDeclaration`
+ *
+ * Params:
+ * parameters = Array of `Parameter` to mangle
+ * varargs = if != 0, this function has varargs parameters
+ */
+ void mangleFunctionParameters(ParameterList parameterList)
+ {
+ int numparams = 0;
+
+ foreach (n, fparam; parameterList)
+ {
+ Type t = target.cpp.parameterType(fparam);
+ if (t.ty == Tsarray)
+ {
+ // Static arrays in D are passed by value; no counterpart in C++
+ .error(loc, "Internal Compiler Error: unable to pass static array `%s` to extern(C++) function, use pointer instead",
+ t.toChars());
+ fatal();
+ }
+ auto prev = this.context.push({
+ TypeFunction tf;
+ if (isDsymbol(this.context.res))
+ tf = cast(TypeFunction)this.context.res.asFuncDecl().type;
+ else
+ tf = this.context.res.asType().isTypeFunction();
+ assert(tf);
+ return (*tf.parameterList.parameters)[n].type;
+ }());
+ scope (exit) this.context.pop(prev);
+
+ if (this.context.ti && global.params.cplusplus >= CppStdRevision.cpp11)
+ handleParamPack(t, this.context.ti.tempdecl.isTemplateDeclaration().parameters);
+
+ headOfType(t);
+ ++numparams;
+ }
+
+ if (parameterList.varargs == VarArg.variadic)
+ buf.writeByte('z');
+ else if (!numparams)
+ buf.writeByte('v'); // encode (void) parameters
+ }
+
+ /****** The rest is type mangling ************/
+
+ void error(Type t)
+ {
+ const(char)* p;
+ if (t.isImmutable())
+ p = "`immutable` ";
+ else if (t.isShared())
+ p = "`shared` ";
+ else
+ p = "";
+ .error(loc, "Internal Compiler Error: %stype `%s` cannot be mapped to C++\n", p, t.toChars());
+ fatal(); //Fatal, because this error should be handled in frontend
+ }
+
+ /****************************
+ * Mangle a type,
+ * treating it as a Head followed by a Tail.
+ * Params:
+ * t = Head of a type
+ */
+ void headOfType(Type t)
+ {
+ if (t.ty == Tclass)
+ {
+ mangleTypeClass(cast(TypeClass)t, true);
+ }
+ else
+ {
+ // For value types, strip const/immutable/shared from the head of the type
+ auto prev = this.context.push(this.context.res.asType().mutableOf().unSharedOf());
+ scope (exit) this.context.pop(prev);
+ t.mutableOf().unSharedOf().accept(this);
+ }
+ }
+
+ /******
+ * Write out 1 or 2 character basic type mangling.
+ * Handle const and substitutions.
+ * Params:
+ * t = type to mangle
+ * p = if not 0, then character prefix
+ * c = mangling character
+ */
+ void writeBasicType(Type t, char p, char c)
+ {
+ // Only do substitutions for non-fundamental types.
+ if (!isFundamentalType(t) || t.isConst())
+ {
+ if (substitute(t))
+ return;
+ else
+ append(t);
+ }
+ CV_qualifiers(t);
+ if (p)
+ buf.writeByte(p);
+ buf.writeByte(c);
+ }
+
+
+ /****************
+ * Write structs and enums.
+ * Params:
+ * t = TypeStruct or TypeEnum
+ */
+ void doSymbol(Type t)
+ {
+ if (substitute(t))
+ return;
+ CV_qualifiers(t);
+
+ // Handle any target-specific struct types.
+ if (auto tm = target.cpp.typeMangle(t))
+ {
+ buf.writestring(tm);
+ }
+ else
+ {
+ Dsymbol s = t.toDsymbol(null);
+ Dsymbol p = s.toParent();
+ if (p && p.isTemplateInstance())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=17947
+ * Substitute the template instance symbol, not the struct/enum symbol
+ */
+ if (substitute(p))
+ return;
+ }
+ if (!substitute(s))
+ cpp_mangle_name(s, false);
+ }
+ if (t.isConst())
+ append(t);
+ }
+
+
+
+ /************************
+ * Mangle a class type.
+ * If it's the head, treat the initial pointer as a value type.
+ * Params:
+ * t = class type
+ * head = true for head of a type
+ */
+ void mangleTypeClass(TypeClass t, bool head)
+ {
+ if (t.isImmutable() || t.isShared())
+ return error(t);
+
+ /* Mangle as a <pointer to><struct>
+ */
+ if (substitute(t))
+ return;
+ if (!head)
+ CV_qualifiers(t);
+ buf.writeByte('P');
+
+ CV_qualifiers(t);
+
+ {
+ Dsymbol s = t.toDsymbol(null);
+ Dsymbol p = s.toParent();
+ if (p && p.isTemplateInstance())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=17947
+ * Substitute the template instance symbol, not the class symbol
+ */
+ if (substitute(p))
+ return;
+ }
+ }
+
+ if (!substitute(t.sym))
+ {
+ cpp_mangle_name(t.sym, false);
+ }
+ if (t.isConst())
+ append(null); // C++ would have an extra type here
+ append(t);
+ }
+
+ /**
+ * Mangle the prefix of a nested (e.g. member) function
+ *
+ * Params:
+ * tf = Type of the nested function
+ * parent = Parent in which the function is nested
+ */
+ void mangleNestedFuncPrefix(TypeFunction tf, Dsymbol parent)
+ {
+ /* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+ * ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+ */
+ buf.writeByte('N');
+ CV_qualifiers(tf);
+
+ /* <prefix> ::= <prefix> <unqualified-name>
+ * ::= <template-prefix> <template-args>
+ * ::= <template-param>
+ * ::= # empty
+ * ::= <substitution>
+ * ::= <prefix> <data-member-prefix>
+ */
+ prefix_name(parent);
+ }
+
+ /**
+ * Write `Dp` (C++11 function parameter pack prefix) if 't' is a TemplateSequenceParameter (T...).
+ *
+ * Params:
+ * t = Parameter type
+ * params = Template parameters of the function
+ */
+ private void handleParamPack(Type t, TemplateParameters* params)
+ {
+ if (t.isTypeReference())
+ t = t.nextOf();
+ auto ti = t.isTypeIdentifier();
+ if (!ti)
+ return;
+
+ auto idx = templateParamIndex(ti.ident, params);
+ if (idx < params.length && (*params)[idx].isTemplateTupleParameter())
+ buf.writestring("Dp");
+ }
+
+ /**
+ * Helper function to write a `T..._` template index.
+ *
+ * Params:
+ * idx = Index of `param` in the template argument list
+ * param = Template parameter to mangle
+ */
+ private void writeTemplateArgIndex(size_t idx, TemplateParameter param)
+ {
+ // expressions are mangled in <X..E>
+ if (param.isTemplateValueParameter())
+ buf.writeByte('X');
+ buf.writeByte('T');
+ writeSequenceFromIndex(idx);
+ buf.writeByte('_');
+ if (param.isTemplateValueParameter())
+ buf.writeByte('E');
+ }
+
+ /**
+ * Given an array of template parameters and an identifier,
+ * returns the index of the identifier in that array.
+ *
+ * Params:
+ * ident = Identifier for which substitution is attempted
+ * (e.g. `void func(T)(T param)` => `T` from `T param`)
+ * params = `TemplateParameters` of the enclosing symbol
+ * (in the previous example, `func`'s template parameters)
+ *
+ * Returns:
+ * The index of the identifier match in `params`,
+ * or `params.length` if there wasn't any match.
+ */
+ private static size_t templateParamIndex(
+ const ref Identifier ident, TemplateParameters* params)
+ {
+ foreach (idx, param; *params)
+ if (param.ident == ident)
+ return idx;
+ return params.length;
+ }
+
+ /**
+ * Given a template instance `t`, write its qualified name
+ * without the template parameter list
+ *
+ * Params:
+ * t = Post-parsing `TemplateInstance` pointing to the symbol
+ * to mangle (one level deep)
+ * dg = Delegate to execute after writing the qualified symbol
+ *
+ */
+ private void writeQualified(TemplateInstance t, scope void delegate() dg)
+ {
+ auto type = isType(this.context.res);
+ if (!type)
+ {
+ this.writeIdentifier(t.name);
+ return dg();
+ }
+ auto sym1 = type.toDsymbol(null);
+ if (!sym1)
+ {
+ this.writeIdentifier(t.name);
+ return dg();
+ }
+ // Get the template instance
+ auto sym = getQualifier(sym1);
+ auto sym2 = getQualifier(sym);
+ if (sym2 && isStd(sym2)) // Nspace path
+ {
+ bool unused;
+ assert(sym.isTemplateInstance());
+ if (this.writeStdSubstitution(sym.isTemplateInstance(), unused))
+ return dg();
+ // std names don't require `N..E`
+ buf.writestring("St");
+ this.writeIdentifier(t.name);
+ this.append(t);
+ return dg();
+ }
+ else if (sym2)
+ {
+ buf.writestring("N");
+ if (!this.substitute(sym2))
+ sym2.accept(this);
+ }
+ this.writeNamespace(
+ sym1.cppnamespace, () {
+ this.writeIdentifier(t.name);
+ this.append(t);
+ dg();
+ });
+ if (sym2)
+ buf.writestring("E");
+ }
+
+extern(C++):
+
+ alias visit = Visitor.visit;
+
+ override void visit(TypeNull t)
+ {
+ if (t.isImmutable() || t.isShared())
+ return error(t);
+
+ writeBasicType(t, 'D', 'n');
+ }
+
+ override void visit(TypeNoreturn t)
+ {
+ if (t.isImmutable() || t.isShared())
+ return error(t);
+
+ writeBasicType(t, 0, 'v'); // mangle like `void`
+ }
+
+ override void visit(TypeBasic t)
+ {
+ if (t.isImmutable() || t.isShared())
+ return error(t);
+
+ // Handle any target-specific basic types.
+ if (auto tm = target.cpp.typeMangle(t))
+ {
+ // Only do substitutions for non-fundamental types.
+ if (!isFundamentalType(t) || t.isConst())
+ {
+ if (substitute(t))
+ return;
+ else
+ append(t);
+ }
+ CV_qualifiers(t);
+ buf.writestring(tm);
+ return;
+ }
+
+ /* <builtin-type>:
+ * v void
+ * w wchar_t
+ * b bool
+ * c char
+ * a signed char
+ * h unsigned char
+ * s short
+ * t unsigned short
+ * i int
+ * j unsigned int
+ * l long
+ * m unsigned long
+ * x long long, __int64
+ * y unsigned long long, __int64
+ * n __int128
+ * o unsigned __int128
+ * f float
+ * d double
+ * e long double, __float80
+ * g __float128
+ * z ellipsis
+ * Dd 64 bit IEEE 754r decimal floating point
+ * De 128 bit IEEE 754r decimal floating point
+ * Df 32 bit IEEE 754r decimal floating point
+ * Dh 16 bit IEEE 754r half-precision floating point
+ * Di char32_t
+ * Ds char16_t
+ * u <source-name> # vendor extended type
+ */
+ char c;
+ char p = 0;
+ switch (t.ty)
+ {
+ case Tvoid: c = 'v'; break;
+ case Tint8: c = 'a'; break;
+ case Tuns8: c = 'h'; break;
+ case Tint16: c = 's'; break;
+ case Tuns16: c = 't'; break;
+ case Tint32: c = 'i'; break;
+ case Tuns32: c = 'j'; break;
+ case Tfloat32: c = 'f'; break;
+ case Tint64:
+ c = target.c.longsize == 8 ? 'l' : 'x';
+ break;
+ case Tuns64:
+ c = target.c.longsize == 8 ? 'm' : 'y';
+ break;
+ case Tint128: c = 'n'; break;
+ case Tuns128: c = 'o'; break;
+ case Tfloat64: c = 'd'; break;
+ case Tfloat80: c = 'e'; break;
+ case Tbool: c = 'b'; break;
+ case Tchar: c = 'c'; break;
+ case Twchar: p = 'D'; c = 's'; break; // since C++11
+ case Tdchar: p = 'D'; c = 'i'; break; // since C++11
+ case Timaginary32: p = 'G'; c = 'f'; break; // 'G' means imaginary
+ case Timaginary64: p = 'G'; c = 'd'; break;
+ case Timaginary80: p = 'G'; c = 'e'; break;
+ case Tcomplex32: p = 'C'; c = 'f'; break; // 'C' means complex
+ case Tcomplex64: p = 'C'; c = 'd'; break;
+ case Tcomplex80: p = 'C'; c = 'e'; break;
+
+ default:
+ return error(t);
+ }
+ writeBasicType(t, p, c);
+ }
+
+ override void visit(TypeVector t)
+ {
+ if (t.isImmutable() || t.isShared())
+ return error(t);
+
+ if (substitute(t))
+ return;
+ append(t);
+ CV_qualifiers(t);
+
+ // Handle any target-specific vector types.
+ if (auto tm = target.cpp.typeMangle(t))
+ {
+ buf.writestring(tm);
+ }
+ else
+ {
+ assert(t.basetype && t.basetype.ty == Tsarray);
+ auto tsa = t.basetype.isTypeSArray();
+ assert(tsa.dim);
+ buf.writestring("Dv"); // -- Gnu ABI v.4
+ buf.print(tsa.dim.toInteger());
+ buf.writeByte('_');
+ t.basetype.nextOf().accept(this);
+ }
+ }
+
+ override void visit(TypeSArray t)
+ {
+ if (t.isImmutable() || t.isShared())
+ return error(t);
+
+ if (!substitute(t))
+ append(t);
+ CV_qualifiers(t);
+ buf.writeByte('A');
+ buf.print(t.dim ? t.dim.toInteger() : 0);
+ buf.writeByte('_');
+ t.next.accept(this);
+ }
+
+ override void visit(TypePointer t)
+ {
+ if (t.isImmutable() || t.isShared())
+ return error(t);
+
+ // Check for const - Since we cannot represent C++'s `char* const`,
+ // and `const char* const` (a.k.a `const(char*)` in D) is mangled
+ // the same as `const char*` (`const(char)*` in D), we need to add
+ // an extra `K` if `nextOf()` is `const`, before substitution
+ CV_qualifiers(t);
+ if (substitute(t))
+ return;
+ buf.writeByte('P');
+ auto prev = this.context.push(this.context.res.asType().nextOf());
+ scope (exit) this.context.pop(prev);
+ t.next.accept(this);
+ append(t);
+ }
+
+ override void visit(TypeReference t)
+ {
+ if (substitute(t))
+ return;
+ buf.writeByte('R');
+ CV_qualifiers(t.nextOf());
+ headOfType(t.nextOf());
+ if (t.nextOf().isConst())
+ append(t.nextOf());
+ append(t);
+ }
+
+ override void visit(TypeFunction t)
+ {
+ /*
+ * <function-type> ::= F [Y] <bare-function-type> E
+ * <bare-function-type> ::= <signature type>+
+ * # types are possible return type, then parameter types
+ */
+ /* ABI says:
+ "The type of a non-static member function is considered to be different,
+ for the purposes of substitution, from the type of a namespace-scope or
+ static member function whose type appears similar. The types of two
+ non-static member functions are considered to be different, for the
+ purposes of substitution, if the functions are members of different
+ classes. In other words, for the purposes of substitution, the class of
+ which the function is a member is considered part of the type of
+ function."
+
+ BUG: Right now, types of functions are never merged, so our simplistic
+ component matcher always finds them to be different.
+ We should use Type.equals on these, and use different
+ TypeFunctions for non-static member functions, and non-static
+ member functions of different classes.
+ */
+ if (substitute(t))
+ return;
+ buf.writeByte('F');
+ if (t.linkage == LINK.c)
+ buf.writeByte('Y');
+ Type tn = t.next;
+ if (t.isref)
+ tn = tn.referenceTo();
+ tn.accept(this);
+ mangleFunctionParameters(t.parameterList);
+ buf.writeByte('E');
+ append(t);
+ }
+
+ override void visit(TypeStruct t)
+ {
+ if (t.isImmutable() || t.isShared())
+ return error(t);
+ //printf("TypeStruct %s\n", t.toChars());
+ doSymbol(t);
+ }
+
+ override void visit(TypeEnum t)
+ {
+ if (t.isImmutable() || t.isShared())
+ return error(t);
+
+ /* __c_(u)long(long) and others get special mangling
+ */
+ const id = t.sym.ident;
+ //printf("enum id = '%s'\n", id.toChars());
+ if (id == Id.__c_long)
+ return writeBasicType(t, 0, 'l');
+ else if (id == Id.__c_ulong)
+ return writeBasicType(t, 0, 'm');
+ else if (id == Id.__c_wchar_t)
+ return writeBasicType(t, 0, 'w');
+ else if (id == Id.__c_longlong)
+ return writeBasicType(t, 0, 'x');
+ else if (id == Id.__c_ulonglong)
+ return writeBasicType(t, 0, 'y');
+ else if (id == Id.__c_complex_float)
+ return writeBasicType(t, 'C', 'f');
+ else if (id == Id.__c_complex_double)
+ return writeBasicType(t, 'C', 'd');
+ else if (id == Id.__c_complex_real)
+ return writeBasicType(t, 'C', 'e');
+
+ doSymbol(t);
+ }
+
+ override void visit(TypeClass t)
+ {
+ mangleTypeClass(t, false);
+ }
+
+ /**
+ * Performs template parameter substitution
+ *
+ * Mangling is performed on a copy of the post-parsing AST before
+ * any semantic pass is run.
+ * There is no easy way to link a type to the template parameters
+ * once semantic has run, because:
+ * - the `TemplateInstance` installs aliases in its scope to its params
+ * - `AliasDeclaration`s are resolved in many places
+ * - semantic passes are destructive, so the `TypeIdentifier` gets lost
+ *
+ * As a result, the best approach with the current architecture is to:
+ * - Run the visitor on the `originalType` of the function,
+ * looking up any `TypeIdentifier` at the template scope when found.
+ * - Fallback to the post-semantic `TypeFunction` when the identifier is
+ * not a template parameter.
+ */
+ override void visit(TypeIdentifier t)
+ {
+ auto decl = cast(TemplateDeclaration)this.context.ti.tempdecl;
+ assert(decl.parameters !is null);
+ auto idx = templateParamIndex(t.ident, decl.parameters);
+ // If not found, default to the post-semantic type
+ if (idx >= decl.parameters.length)
+ return this.context.res.visitObject(this);
+
+ auto param = (*decl.parameters)[idx];
+ if (auto type = this.context.res.isType())
+ CV_qualifiers(type);
+ // Otherwise, attempt substitution (`S_` takes precedence on `T_`)
+ if (this.substitute(param))
+ return;
+
+ // If substitution failed, write `TX_` where `X` is the index
+ this.writeTemplateArgIndex(idx, param);
+ this.append(param);
+ // Write the ABI tags, if any
+ if (auto sym = this.context.res.isDsymbol())
+ this.abiTags.writeSymbol(sym, this);
+ }
+
+ /// Ditto
+ override void visit(TypeInstance t)
+ {
+ assert(t.tempinst !is null);
+ t.tempinst.accept(this);
+ }
+
+ /**
+ * Mangles a `TemplateInstance`
+ *
+ * A `TemplateInstance` can be found either in the parameter,
+ * or the return value.
+ * Arguments to the template instance needs to be mangled but the template
+ * can be partially substituted, so for example the following:
+ * `Container!(T, Val) func16479_12 (alias Container, T, int Val) ()`
+ * will mangle the return value part to "T_IT0_XT1_EE"
+ */
+ override void visit(TemplateInstance t)
+ {
+ // Template names are substituted, but args still need to be written
+ void writeArgs ()
+ {
+ buf.writeByte('I');
+ // When visiting the arguments, the context will be set to the
+ // resolved type
+ auto analyzed_ti = this.context.res.asType().toDsymbol(null).isInstantiated();
+ auto prev = this.context;
+ scope (exit) this.context.pop(prev);
+ foreach (idx, RootObject o; *t.tiargs)
+ {
+ this.context.res = (*analyzed_ti.tiargs)[idx];
+ o.visitObject(this);
+ }
+ if (analyzed_ti.tiargs.dim > t.tiargs.dim)
+ {
+ // If the resolved AST has more args than the parse one,
+ // we have default arguments
+ auto oparams = (cast(TemplateDeclaration)analyzed_ti.tempdecl).origParameters;
+ foreach (idx, arg; (*oparams)[t.tiargs.dim .. $])
+ {
+ this.context.res = (*analyzed_ti.tiargs)[idx + t.tiargs.dim];
+
+ if (auto ttp = arg.isTemplateTypeParameter())
+ ttp.defaultType.accept(this);
+ else if (auto tvp = arg.isTemplateValueParameter())
+ tvp.defaultValue.accept(this);
+ else if (auto tvp = arg.isTemplateThisParameter())
+ tvp.defaultType.accept(this);
+ else if (auto tvp = arg.isTemplateAliasParameter())
+ tvp.defaultAlias.visitObject(this);
+ else
+ assert(0, arg.toString());
+ }
+ }
+ buf.writeByte('E');
+ }
+
+ // `name` is used, not `ident`
+ assert(t.name !is null);
+ assert(t.tiargs !is null);
+
+ bool needsTa;
+ auto decl = cast(TemplateDeclaration)this.context.ti.tempdecl;
+ // Attempt to substitute the template itself
+ auto idx = templateParamIndex(t.name, decl.parameters);
+ if (idx < decl.parameters.length)
+ {
+ auto param = (*decl.parameters)[idx];
+ if (auto type = t.getType())
+ CV_qualifiers(type);
+ if (this.substitute(param))
+ return;
+ this.writeTemplateArgIndex(idx, param);
+ this.append(param);
+ writeArgs();
+ }
+ else if (this.writeStdSubstitution(t, needsTa))
+ {
+ if (needsTa)
+ writeArgs();
+ }
+ else if (!this.substitute(t))
+ this.writeQualified(t, &writeArgs);
+ }
+
+ /// Ditto
+ override void visit(IntegerExp t)
+ {
+ this.buf.writeByte('L');
+ t.type.accept(this);
+ this.buf.print(t.getInteger());
+ this.buf.writeByte('E');
+ }
+
+ override void visit(Nspace t)
+ {
+ if (auto p = getQualifier(t))
+ p.accept(this);
+
+ if (isStd(t))
+ buf.writestring("St");
+ else
+ {
+ this.writeIdentifier(t.ident);
+ this.append(t);
+ }
+ }
+
+ override void visit(Type t)
+ {
+ error(t);
+ }
+
+ void visit(Tuple t)
+ {
+ assert(0);
+ }
+}
+
+/// Helper code to visit `RootObject`, as it doesn't define `accept`,
+/// only its direct subtypes do.
+private void visitObject(V : Visitor)(RootObject o, V this_)
+{
+ assert(o !is null);
+ if (Type ta = isType(o))
+ ta.accept(this_);
+ else if (Expression ea = isExpression(o))
+ ea.accept(this_);
+ else if (Dsymbol sa = isDsymbol(o))
+ sa.accept(this_);
+ else if (TemplateParameter t = isTemplateParameter(o))
+ t.accept(this_);
+ else if (Tuple t = isTuple(o))
+ // `Tuple` inherits `RootObject` and does not define accept
+ // For this reason, this uses static dispatch on the visitor
+ this_.visit(t);
+ else
+ assert(0, o.toString());
+}
+
+/// Helper function to safely get a type out of a `RootObject`
+private Type asType(RootObject o)
+{
+ Type ta = isType(o);
+ // When called with context.res as argument, it can be `FuncDeclaration`
+ if (!ta && o.asFuncDecl())
+ ta = (cast(FuncDeclaration)o).type;
+ assert(ta !is null, o.toString());
+ return ta;
+}
+
+/// Helper function to safely get a `FuncDeclaration` out of a `RootObject`
+private FuncDeclaration asFuncDecl(RootObject o)
+{
+ Dsymbol d = isDsymbol(o);
+ assert(d !is null);
+ auto fd = d.isFuncDeclaration();
+ assert(fd !is null);
+ return fd;
+}
+
+/// Helper class to compare entries in components
+private extern(C++) final class ComponentVisitor : Visitor
+{
+ /// Only one of the following is not `null`, it's always
+ /// the most specialized type, set from the ctor
+ private Nspace namespace;
+
+ /// Ditto
+ private CPPNamespaceDeclaration namespace2;
+
+ /// Ditto
+ private TypePointer tpointer;
+
+ /// Ditto
+ private TypeReference tref;
+
+ /// Ditto
+ private TypeIdentifier tident;
+
+ /// Least specialized type
+ private RootObject object;
+
+ /// Set to the result of the comparison
+ private bool result;
+
+ public this(RootObject base)
+ {
+ switch (base.dyncast())
+ {
+ case DYNCAST.dsymbol:
+ if (auto ns = (cast(Dsymbol)base).isNspace())
+ this.namespace = ns;
+ else if (auto ns = (cast(Dsymbol)base).isCPPNamespaceDeclaration())
+ this.namespace2 = ns;
+ else
+ goto default;
+ break;
+
+ case DYNCAST.type:
+ auto t = cast(Type)base;
+ if (t.ty == Tpointer)
+ this.tpointer = cast(TypePointer)t;
+ else if (t.ty == Treference)
+ this.tref = cast(TypeReference)t;
+ else if (t.ty == Tident)
+ this.tident = cast(TypeIdentifier)t;
+ else
+ goto default;
+ break;
+
+ // Note: ABI tags are also handled here (they are TupleExp of StringExp)
+ default:
+ this.object = base;
+ }
+ }
+
+ /// Introduce base class overloads
+ alias visit = Visitor.visit;
+
+ /// Least specialized overload of each direct child of `RootObject`
+ public override void visit(Dsymbol o)
+ {
+ this.result = this.object && this.object == o;
+ }
+
+ /// Ditto
+ public override void visit(Expression o)
+ {
+ this.result = this.object && this.object == o;
+ }
+
+ /// Ditto
+ public void visit(Tuple o)
+ {
+ this.result = this.object && this.object == o;
+ }
+
+ /// Ditto
+ public override void visit(Type o)
+ {
+ this.result = this.object && this.object == o;
+ }
+
+ /// Ditto
+ public override void visit(TemplateParameter o)
+ {
+ this.result = this.object && this.object == o;
+ }
+
+ /**
+ * This overload handles composed types including template parameters
+ *
+ * Components for substitutions include "next" type.
+ * For example, if `ref T` is present, `ref T` and `T` will be present
+ * in the substitution array.
+ * But since we don't have the final/merged type, we cannot rely on
+ * object comparison, and need to recurse instead.
+ */
+ public override void visit(TypeReference o)
+ {
+ if (!this.tref)
+ return;
+ if (this.tref == o)
+ this.result = true;
+ else
+ {
+ // It might be a reference to a template parameter that we already
+ // saw, so we need to recurse
+ scope v = new ComponentVisitor(this.tref.next);
+ o.next.visitObject(v);
+ this.result = v.result;
+ }
+ }
+
+ /// Ditto
+ public override void visit(TypePointer o)
+ {
+ if (!this.tpointer)
+ return;
+ if (this.tpointer == o)
+ this.result = true;
+ else
+ {
+ // It might be a pointer to a template parameter that we already
+ // saw, so we need to recurse
+ scope v = new ComponentVisitor(this.tpointer.next);
+ o.next.visitObject(v);
+ this.result = v.result;
+ }
+ }
+
+ /// Ditto
+ public override void visit(TypeIdentifier o)
+ {
+ /// Since we know they are at the same level, scope resolution will
+ /// give us the same symbol, thus we can just compare ident.
+ this.result = (this.tident && (this.tident.ident == o.ident));
+ }
+
+ /**
+ * Overload which accepts a Namespace
+ *
+ * It is very common for large C++ projects to have multiple files sharing
+ * the same `namespace`. If any D project adopts the same approach
+ * (e.g. separating data structures from functions), it will lead to two
+ * `Nspace` objects being instantiated, with different addresses.
+ * At the same time, we cannot compare just any Dsymbol via identifier,
+ * because it messes with templates.
+ *
+ * See_Also:
+ * https://issues.dlang.org/show_bug.cgi?id=18922
+ *
+ * Params:
+ * ns = C++ namespace to do substitution for
+ */
+ public override void visit(Nspace ns)
+ {
+ this.result = isNamespaceEqual(this.namespace, ns)
+ || isNamespaceEqual(this.namespace2, ns);
+ }
+
+ /// Ditto
+ public override void visit(CPPNamespaceDeclaration ns)
+ {
+ this.result = isNamespaceEqual(this.namespace, ns)
+ || isNamespaceEqual(this.namespace2, ns);
+ }
+}
+
+/// Transitional functions for `CPPNamespaceDeclaration` / `Nspace`
+/// Remove when `Nspace` is removed.
+private bool isNamespaceEqual (Nspace a, Nspace b)
+{
+ if (a is null || b is null)
+ return false;
+ return a.equals(b);
+}
+
+/// Ditto
+private bool isNamespaceEqual (Nspace a, CPPNamespaceDeclaration b)
+{
+ return isNamespaceEqual(b, a);
+}
+
+/// Ditto
+private bool isNamespaceEqual (CPPNamespaceDeclaration a, Nspace b, size_t idx = 0)
+{
+ if ((a is null) != (b is null))
+ return false;
+ if (!a.ident.equals(b.ident))
+ return false;
+
+ // We need to see if there's more ident enclosing
+ if (auto pb = b.toParent().isNspace())
+ return isNamespaceEqual(a.cppnamespace, pb);
+ else
+ return a.cppnamespace is null;
+}
+
+/// Returns:
+/// Whether two `CPPNamespaceDeclaration` are equals
+private bool isNamespaceEqual (CPPNamespaceDeclaration a, CPPNamespaceDeclaration b)
+{
+ if (a is null || b is null)
+ return false;
+
+ if ((a.cppnamespace is null) != (b.cppnamespace is null))
+ return false;
+ if (a.ident != b.ident)
+ return false;
+ return a.cppnamespace is null ? true : isNamespaceEqual(a.cppnamespace, b.cppnamespace);
+}
+
+/**
+ * A container for ABI tags
+ *
+ * At its hearth, there is a sorted array of ABI tags having been written
+ * already. ABI tags can be present on parameters, template parameters,
+ * return value, and varaible. ABI tags for a given type needs to be written
+ * sorted. When a function returns a type that has ABI tags, only the tags that
+ * haven't been printed as part of the mangling (e.g. arguments) are written
+ * directly after the function name.
+ *
+ * This means that:
+ * ---
+ * /++ C++ type definitions:
+ * struct [[gnu::abi_tag("tag1")]] Struct1 {};
+ * struct [[gnu::abi_tag("tag2")]] Struct2 {};
+ * // Can also be: "tag2", "tag1", since tags are sorted.
+ * struct [[gnu::abi_tag("tag1", "tag2")]] Struct3 {};
+ * +/
+ * // Functions definitions:
+ * Struct3 func1 (Struct1);
+ * Struct3 func2 (Struct2);
+ * Struct3 func3 (Struct2, Struct1);
+ * ---
+ * Will be respectively pseudo-mangled (part of interest between stars) as:
+ * "_Z4 func1 *B4tag2* ParamsMangling" (ParamsMangling includes tag1),
+ * "_Z4 func2 *B4tag1* ParamsMangling" (ParamsMangling includes tag2),
+ * "_Z4 func2 *B4tag1* ParamsMangling" (ParamsMangling includes both).
+ *
+ * This is why why need to keep a list of tags that were written,
+ * and insert the missing one after parameter mangling has been written.
+ * Since there's a lot of operations that are not easily doable in DMD
+ * (since we can't use Phobos), this special container is implemented.
+ */
+private struct ABITagContainer
+{
+ private Array!StringExp written;
+
+ static ArrayLiteralExp forSymbol (Dsymbol s)
+ {
+ if (!s)
+ return null;
+ // If this is a template instance, we want the declaration,
+ // as that's where the UDAs are
+ if (auto ti = s.isTemplateInstance())
+ s = ti.tempdecl;
+ if (!s.userAttribDecl || !s.userAttribDecl.atts)
+ return null;
+
+ foreach (exp; *s.userAttribDecl.atts)
+ {
+ if (UserAttributeDeclaration.isGNUABITag(exp))
+ return (*exp.isStructLiteralExp().elements)[0]
+ .isArrayLiteralExp();
+ }
+ return null;
+ }
+
+ void writeSymbol(Dsymbol s, CppMangleVisitor self)
+ {
+ auto tale = forSymbol(s);
+ if (!tale) return;
+ if (self.substitute(tale))
+ return;
+ this.write(*self.buf, tale);
+ }
+
+ /**
+ * Write an ArrayLiteralExp (expected to be an ABI tag) to the buffer
+ *
+ * Params:
+ * buf = Buffer to write mangling to
+ * ale = GNU ABI tag array literal expression, semantically analyzed
+ */
+ void write (ref OutBuffer buf, ArrayLiteralExp ale, bool skipKnown = false)
+ {
+ void writeElem (StringExp exp)
+ {
+ const tag = exp.peekString();
+ buf.writestring("B");
+ buf.print(tag.length);
+ buf.writestring(tag);
+ }
+
+ bool match;
+ foreach (exp; *ale.elements)
+ {
+ auto elem = exp.toStringExp();
+ auto idx = closestIndex(this.written[], elem, match);
+ if (!match)
+ {
+ writeElem(elem);
+ this.written.insert(idx, elem);
+ }
+ else if (!skipKnown)
+ writeElem(elem);
+ }
+ }
+}
+
+/**
+ * Returns the closest index to to `exp` in `slice`
+ *
+ * Performs a binary search on `slice` (assumes `slice` is sorted),
+ * and returns either `exp`'s index in `slice` if `exact` is `true`,
+ * or the index at which `exp` can be inserted in `slice` if `exact is `false`.
+ * Inserting `exp` at the return value will keep the array sorted.
+ *
+ * Params:
+ * slice = The sorted slice to search into
+ * exp = The string expression to search for
+ * exact = If `true` on return, `exp` was found in `slice`
+ *
+ * Returns:
+ * Either the index to insert `exp` at (if `exact == false`),
+ * or the index of `exp` in `slice`.
+ */
+private size_t closestIndex (const(StringExp)[] slice, StringExp exp, out bool exact)
+{
+ if (!slice.length) return 0;
+
+ const StringExp* first = slice.ptr;
+ while (true)
+ {
+ int res = dstrcmp(exp.peekString(), slice[$ / 2].peekString());
+ if (res == 0)
+ {
+ exact = true;
+ return (&slice[$/2] - first);
+ }
+
+ if (slice.length == 1)
+ return (slice.ptr - first) + (res > 0);
+ slice = slice[(res > 0 ? $ / 2 : 0) .. (res > 0 ? $ : $ / 2)];
+ }
+}
+
+//
+unittest
+{
+ bool match;
+ auto s1 = new StringExp(Loc.initial, "Amande");
+ auto s2 = new StringExp(Loc.initial, "Baguette");
+ auto s3 = new StringExp(Loc.initial, "Croissant");
+ auto s4 = new StringExp(Loc.initial, "Framboises");
+ auto s5 = new StringExp(Loc.initial, "Proscuitto");
+
+ // Found, odd size
+ assert(closestIndex([s1, s2, s3, s4, s5], s1, match) == 0 && match);
+ assert(closestIndex([s1, s2, s3, s4, s5], s2, match) == 1 && match);
+ assert(closestIndex([s1, s2, s3, s4, s5], s3, match) == 2 && match);
+ assert(closestIndex([s1, s2, s3, s4, s5], s4, match) == 3 && match);
+ assert(closestIndex([s1, s2, s3, s4, s5], s5, match) == 4 && match);
+
+ // Not found, even size
+ assert(closestIndex([s2, s3, s4, s5], s1, match) == 0 && !match);
+ assert(closestIndex([s1, s3, s4, s5], s2, match) == 1 && !match);
+ assert(closestIndex([s1, s2, s4, s5], s3, match) == 2 && !match);
+ assert(closestIndex([s1, s2, s3, s5], s4, match) == 3 && !match);
+ assert(closestIndex([s1, s2, s3, s4], s5, match) == 4 && !match);
+
+ // Found, even size
+ assert(closestIndex([s1, s2, s3, s4], s1, match) == 0 && match);
+ assert(closestIndex([s1, s2, s3, s4], s2, match) == 1 && match);
+ assert(closestIndex([s1, s2, s3, s4], s3, match) == 2 && match);
+ assert(closestIndex([s1, s2, s3, s4], s4, match) == 3 && match);
+ assert(closestIndex([s1, s3, s4, s5], s5, match) == 3 && match);
+
+ // Not found, odd size
+ assert(closestIndex([s2, s4, s5], s1, match) == 0 && !match);
+ assert(closestIndex([s1, s4, s5], s2, match) == 1 && !match);
+ assert(closestIndex([s1, s2, s4], s3, match) == 2 && !match);
+ assert(closestIndex([s1, s3, s5], s4, match) == 2 && !match);
+ assert(closestIndex([s1, s2, s4], s5, match) == 3 && !match);
+}
+
+/**
+ * Visits the return type of a function and writes leftover ABI tags
+ */
+extern(C++) private final class LeftoverVisitor : Visitor
+{
+ /// List of tags to write
+ private Array!StringExp toWrite;
+ /// List of tags to ignore
+ private const(Array!StringExp)* ignore;
+
+ ///
+ public this(const(Array!StringExp)* previous)
+ {
+ this.ignore = previous;
+ }
+
+ /// Reintroduce base class overloads
+ public alias visit = Visitor.visit;
+
+ /// Least specialized overload of each direct child of `RootObject`
+ public override void visit(Dsymbol o)
+ {
+ auto ale = ABITagContainer.forSymbol(o);
+ if (!ale) return;
+
+ bool match;
+ foreach (elem; *ale.elements)
+ {
+ auto se = elem.toStringExp();
+ closestIndex((*this.ignore)[], se, match);
+ if (match) continue;
+ auto idx = closestIndex(this.toWrite[], se, match);
+ if (!match)
+ this.toWrite.insert(idx, se);
+ }
+ }
+
+ /// Ditto
+ public override void visit(Type o)
+ {
+ if (auto sym = o.toDsymbol(null))
+ sym.accept(this);
+ }
+
+ /// Composite type
+ public override void visit(TypePointer o)
+ {
+ o.next.accept(this);
+ }
+
+ public override void visit(TypeReference o)
+ {
+ o.next.accept(this);
+ }
+}
diff --git a/gcc/d/dmd/ctfe.h b/gcc/d/dmd/ctfe.h
index 359739e..242dd55 100644
--- a/gcc/d/dmd/ctfe.h
+++ b/gcc/d/dmd/ctfe.h
@@ -5,31 +5,15 @@
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/dlang/dmd/blob/master/src/ctfe.h
+ * https://github.com/dlang/dmd/blob/master/src/dmd/ctfe.h
*/
#pragma once
-#include "arraytypes.h"
#include "tokens.h"
#include "expression.h"
/**
- Global status of the CTFE engine. Mostly used for performance diagnostics
- */
-struct CtfeStatus
-{
- static int callDepth; // current number of recursive calls
- /* When printing a stack trace,
- * suppress this number of calls
- */
- static int stackTraceCallsToSuppress;
- static int maxCallDepth; // highest number of recursive calls
- static int numArrayAllocs; // Number of allocated arrays
- static int numAssignments; // total number of assignments executed
-};
-
-/**
A reference to a class, or an interface. We need this when we
point to a base class (we must record what the type is).
*/
@@ -37,55 +21,35 @@ class ClassReferenceExp : public Expression
{
public:
StructLiteralExp *value;
- ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type);
ClassDeclaration *originalClass();
/// Return index of the field, or -1 if not found
- int getFieldIndex(Type *fieldtype, unsigned fieldoffset);
- /// Return index of the field, or -1 if not found
/// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
int findFieldIndexByName(VarDeclaration *v);
void accept(Visitor *v) { v->visit(this); }
};
-// The various functions are used only to detect compiler CTFE bugs
-Expression *getValue(VarDeclaration *vd);
-bool hasValue(VarDeclaration *vd);
-void setValueNull(VarDeclaration *vd);
-void setValueWithoutChecking(VarDeclaration *vd, Expression *newval);
-void setValue(VarDeclaration *vd, Expression *newval);
-
-/// Return index of the field, or -1 if not found
-/// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
-int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v);
-
-
-/** An uninitialized value
+/**
+ An uninitialized value
*/
class VoidInitExp : public Expression
{
public:
VarDeclaration *var;
- VoidInitExp(VarDeclaration *var, Type *type);
- const char *toChars();
+ const char *toChars() const;
void accept(Visitor *v) { v->visit(this); }
};
-// Create an appropriate void initializer
-UnionExp voidInitLiteral(Type *t, VarDeclaration *var);
-
-/** Fake class which holds the thrown exception.
- Used for implementing exception handling.
+/**
+ Fake class which holds the thrown exception.
+ Used for implementing exception handling.
*/
class ThrownExceptionExp : public Expression
{
public:
ClassReferenceExp *thrown; // the thing being tossed
- ThrownExceptionExp(Loc loc, ClassReferenceExp *victim);
- const char *toChars();
- /// Generate an error message when this exception is not caught
- void generateUncaughtError();
+ const char *toChars() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -96,173 +60,5 @@ public:
class CTFEExp : public Expression
{
public:
- CTFEExp(TOK tok);
-
- const char *toChars();
-
- // Handy instances to share
- static CTFEExp *cantexp;
- static CTFEExp *voidexp;
- static CTFEExp *breakexp;
- static CTFEExp *continueexp;
- static CTFEExp *gotoexp;
-
- static bool isCantExp(Expression *e) { return e && e->op == TOKcantexp; }
- static bool isGotoExp(Expression *e) { return e && e->op == TOKgoto; }
+ const char *toChars() const;
};
-
-/****************************************************************/
-
-
-/// True if 'e' is TOKcantexp, or an exception
-bool exceptionOrCantInterpret(Expression *e);
-
-// Used for debugging only
-void showCtfeExpr(Expression *e, int level = 0);
-
-/// Return true if this is a valid CTFE expression
-bool isCtfeValueValid(Expression *newval);
-bool isCtfeReferenceValid(Expression *newval);
-
-/// Given expr, which evaluates to an array/AA/string literal,
-/// return true if it needs to be copied
-bool needToCopyLiteral(Expression *expr);
-
-/// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
-/// This value will be used for in-place modification.
-UnionExp copyLiteral(Expression *e);
-
-/// Set this literal to the given type, copying it if necessary
-Expression *paintTypeOntoLiteral(Type *type, Expression *lit);
-Expression *paintTypeOntoLiteral(UnionExp *pue, Type *type, Expression *lit);
-UnionExp paintTypeOntoLiteralCopy(Type *type, Expression *lit);
-
-/// Convert from a CTFE-internal slice, into a normal Expression
-Expression *resolveSlice(Expression *e, UnionExp *pue = NULL);
-
-/// Determine the array length, without interpreting the expression.
-uinteger_t resolveArrayLength(Expression *e);
-
-/// Create an array literal consisting of 'elem' duplicated 'dim' times.
-ArrayLiteralExp *createBlockDuplicatedArrayLiteral(UnionExp *pue, Loc loc, Type *type,
- Expression *elem, size_t dim);
-
-/// Create a string literal consisting of 'value' duplicated 'dim' times.
-StringExp *createBlockDuplicatedStringLiteral(UnionExp *pue, Loc loc, Type *type,
- unsigned value, size_t dim, unsigned char sz);
-
-
-/* Set dest = src, where both dest and src are container value literals
- * (ie, struct literals, or static arrays (can be an array literal or a string)
- * Assignment is recursively in-place.
- * Purpose: any reference to a member of 'dest' will remain valid after the
- * assignment.
- */
-void assignInPlace(Expression *dest, Expression *src);
-
-/// Duplicate the elements array, then set field 'indexToChange' = newelem.
-Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem);
-
-/// Given an AA literal aae, set arr[index] = newval and return the new array.
-Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae,
- Expression *index, Expression *newval);
-
-/// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
-/// oldlen, change its length to newlen. If the newlen is longer than oldlen,
-/// all new elements will be set to the default initializer for the element type.
-UnionExp changeArrayLiteralLength(Loc loc, TypeArray *arrayType,
- Expression *oldval, size_t oldlen, size_t newlen);
-
-
-
-/// Return true if t is a pointer (not a function pointer)
-bool isPointer(Type *t);
-
-// For CTFE only. Returns true if 'e' is TRUE or a non-null pointer.
-bool isTrueBool(Expression *e);
-
-/// Is it safe to convert from srcPointee* to destPointee* ?
-/// srcPointee is the genuine type (never void).
-/// destPointee may be void.
-bool isSafePointerCast(Type *srcPointee, Type *destPointee);
-
-/// Given pointer e, return the memory block expression it points to,
-/// and set ofs to the offset within that memory block.
-Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs);
-
-/// Return true if agg1 and agg2 are pointers to the same memory block
-bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2);
-
-// return e1 - e2 as an integer, or error if not possible
-UnionExp pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2);
-
-/// Return 1 if true, 0 if false
-/// -1 if comparison is illegal because they point to non-comparable memory blocks
-int comparePointers(TOK op, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2);
-
-// Return eptr op e2, where eptr is a pointer, e2 is an integer,
-// and op is TOKadd or TOKmin
-UnionExp pointerArithmetic(Loc loc, TOK op, Type *type,
- Expression *eptr, Expression *e2);
-
-// True if conversion from type 'from' to 'to' involves a reinterpret_cast
-// floating point -> integer or integer -> floating point
-bool isFloatIntPaint(Type *to, Type *from);
-
-// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
-Expression *paintFloatInt(UnionExp *pue, Expression *fromVal, Type *to);
-
-/// Return true if t is an AA
-bool isAssocArray(Type *t);
-
-/// Given a template AA type, extract the corresponding built-in AA type
-TypeAArray *toBuiltinAAType(Type *t);
-
-/* Given an AA literal 'ae', and a key 'e2':
- * Return ae[e2] if present, or NULL if not found.
- * Return TOKcantexp on error.
- */
-Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2);
-
-/// True if type is TypeInfo_Class
-bool isTypeInfo_Class(Type *type);
-
-
-/***********************************************
- COW const-folding operations
-***********************************************/
-
-/// Return true if non-pointer expression e can be compared
-/// with >,is, ==, etc, using ctfeCmp, ctfeEquals, ctfeIdentity
-bool isCtfeComparable(Expression *e);
-
-/// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1
-int ctfeEqual(Loc loc, TOK op, Expression *e1, Expression *e2);
-
-/// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1
-int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2);
-
-/// Returns rawCmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-int specificCmp(TOK op, int rawCmp);
-
-/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-int intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2);
-
-/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2);
-
-/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-int realCmp(TOK op, real_t r1, real_t r2);
-
-/// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
-int ctfeCmp(Loc loc, TOK op, Expression *e1, Expression *e2);
-
-/// Returns e1 ~ e2. Resolves slices before concatenation.
-UnionExp ctfeCat(Loc loc, Type *type, Expression *e1, Expression *e2);
-
-/// Same as for constfold.Index, except that it only works for static arrays,
-/// dynamic arrays, and strings.
-Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx);
-
-/// Cast 'e' of type 'type' to type 'to'.
-Expression *ctfeCast(UnionExp *pue, Loc loc, Type *type, Type *to, Expression *e);
diff --git a/gcc/d/dmd/ctfeexpr.c b/gcc/d/dmd/ctfeexpr.c
deleted file mode 100644
index a8e9783..0000000
--- a/gcc/d/dmd/ctfeexpr.c
+++ /dev/null
@@ -1,2127 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/ctfeexpr.c
- */
-
-#include "root/dsystem.h" // mem{cpy|set}()
-#include "root/rmem.h"
-
-#include "mars.h"
-#include "expression.h"
-#include "declaration.h"
-#include "aggregate.h"
-// for AssocArray
-#include "id.h"
-#include "utf.h"
-#include "template.h"
-#include "ctfe.h"
-
-int RealEquals(real_t x1, real_t x2);
-
-/************** ClassReferenceExp ********************************************/
-
-ClassReferenceExp::ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type)
- : Expression(loc, TOKclassreference, sizeof(ClassReferenceExp))
-{
- assert(lit && lit->sd && lit->sd->isClassDeclaration());
- this->value = lit;
- this->type = type;
-}
-
-ClassDeclaration *ClassReferenceExp::originalClass()
-{
- return value->sd->isClassDeclaration();
-}
-
-// Return index of the field, or -1 if not found
-int ClassReferenceExp::getFieldIndex(Type *fieldtype, unsigned fieldoffset)
-{
- ClassDeclaration *cd = originalClass();
- unsigned fieldsSoFar = 0;
- for (size_t j = 0; j < value->elements->length; j++)
- {
- while (j - fieldsSoFar >= cd->fields.length)
- {
- fieldsSoFar += cd->fields.length;
- cd = cd->baseClass;
- }
- VarDeclaration *v2 = cd->fields[j - fieldsSoFar];
- if (fieldoffset == v2->offset &&
- fieldtype->size() == v2->type->size())
- {
- return (int)(value->elements->length - fieldsSoFar - cd->fields.length + (j-fieldsSoFar));
- }
- }
- return -1;
-}
-
-// Return index of the field, or -1 if not found
-// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
-int ClassReferenceExp::findFieldIndexByName(VarDeclaration *v)
-{
- ClassDeclaration *cd = originalClass();
- size_t fieldsSoFar = 0;
- for (size_t j = 0; j < value->elements->length; j++)
- {
- while (j - fieldsSoFar >= cd->fields.length)
- {
- fieldsSoFar += cd->fields.length;
- cd = cd->baseClass;
- }
- VarDeclaration *v2 = cd->fields[j - fieldsSoFar];
- if (v == v2)
- {
- return (int)(value->elements->length - fieldsSoFar - cd->fields.length + (j-fieldsSoFar));
- }
- }
- return -1;
-}
-
-/************** VoidInitExp ********************************************/
-
-VoidInitExp::VoidInitExp(VarDeclaration *var, Type *)
- : Expression(var->loc, TOKvoid, sizeof(VoidInitExp))
-{
- this->var = var;
- this->type = var->type;
-}
-
-const char *VoidInitExp::toChars()
-{
- return "void";
-}
-
-// Return index of the field, or -1 if not found
-// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
-int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v)
-{
- for (size_t i = 0; i < sd->fields.length; ++i)
- {
- if (sd->fields[i] == v)
- return (int)i;
- }
- return -1;
-}
-
-/************** ThrownExceptionExp ********************************************/
-
-ThrownExceptionExp::ThrownExceptionExp(Loc loc, ClassReferenceExp *victim) : Expression(loc, TOKthrownexception, sizeof(ThrownExceptionExp))
-{
- this->thrown = victim;
- this->type = victim->type;
-}
-
-const char *ThrownExceptionExp::toChars()
-{
- return "CTFE ThrownException";
-}
-
-// Generate an error message when this exception is not caught
-void ThrownExceptionExp::generateUncaughtError()
-{
- UnionExp ue;
- Expression *e = resolveSlice((*thrown->value->elements)[0], &ue);
- StringExp *se = e->toStringExp();
- thrown->error("uncaught CTFE exception %s(%s)", thrown->type->toChars(), se ? se->toChars() : e->toChars());
-
- /* Also give the line where the throw statement was. We won't have it
- * in the case where the ThrowStatement is generated internally
- * (eg, in ScopeStatement)
- */
- if (loc.filename && !loc.equals(thrown->loc))
- errorSupplemental(loc, "thrown from here");
-}
-
-// True if 'e' is CTFEExp::cantexp, or an exception
-bool exceptionOrCantInterpret(Expression *e)
-{
- return e && (e->op == TOKcantexp || e->op == TOKthrownexception);
-}
-
-/********************** CTFEExp ******************************************/
-
-CTFEExp *CTFEExp::cantexp;
-CTFEExp *CTFEExp::voidexp;
-CTFEExp *CTFEExp::breakexp;
-CTFEExp *CTFEExp::continueexp;
-CTFEExp *CTFEExp::gotoexp;
-
-CTFEExp::CTFEExp(TOK tok)
- : Expression(Loc(), tok, sizeof(CTFEExp))
-{
- type = Type::tvoid;
-}
-
-const char *CTFEExp::toChars()
-{
- switch (op)
- {
- case TOKcantexp: return "<cant>";
- case TOKvoidexp: return "cast(void)0";
- case TOKbreak: return "<break>";
- case TOKcontinue: return "<continue>";
- case TOKgoto: return "<goto>";
- default: assert(0); return NULL;
- }
-}
-
-Expression *UnionExp::copy()
-{
- Expression *e = exp();
- //if (e->size > sizeof(u)) printf("%s\n", Token::toChars(e->op));
- assert(e->size <= sizeof(u));
- if (e->op == TOKcantexp) return CTFEExp::cantexp;
- if (e->op == TOKvoidexp) return CTFEExp::voidexp;
- if (e->op == TOKbreak) return CTFEExp::breakexp;
- if (e->op == TOKcontinue) return CTFEExp::continueexp;
- if (e->op == TOKgoto) return CTFEExp::gotoexp;
- return e->copy();
-}
-
-/************** Aggregate literals (AA/string/array/struct) ******************/
-
-// Given expr, which evaluates to an array/AA/string literal,
-// return true if it needs to be copied
-bool needToCopyLiteral(Expression *expr)
-{
- for (;;)
- {
- switch (expr->op)
- {
- case TOKarrayliteral:
- return ((ArrayLiteralExp *)expr)->ownedByCtfe == OWNEDcode;
- case TOKassocarrayliteral:
- return ((AssocArrayLiteralExp *)expr)->ownedByCtfe == OWNEDcode;
- case TOKstructliteral:
- return ((StructLiteralExp *)expr)->ownedByCtfe == OWNEDcode;
- case TOKstring:
- case TOKthis:
- case TOKvar:
- return false;
- case TOKassign:
- return false;
- case TOKindex:
- case TOKdotvar:
- case TOKslice:
- case TOKcast:
- expr = ((UnaExp *)expr)->e1;
- continue;
- case TOKcat:
- return needToCopyLiteral(((BinExp *)expr)->e1) ||
- needToCopyLiteral(((BinExp *)expr)->e2);
- case TOKcatass:
- expr = ((BinExp *)expr)->e2;
- continue;
- default:
- return false;
- }
- }
-}
-
-Expressions *copyLiteralArray(Expressions *oldelems, Expression *basis = NULL)
-{
- if (!oldelems)
- return oldelems;
- CtfeStatus::numArrayAllocs++;
- Expressions *newelems = new Expressions();
- newelems->setDim(oldelems->length);
- for (size_t i = 0; i < oldelems->length; i++)
- {
- Expression *el = (*oldelems)[i];
- if (!el)
- el = basis;
- (*newelems)[i] = copyLiteral(el).copy();
- }
- return newelems;
-}
-
-// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
-// This value will be used for in-place modification.
-UnionExp copyLiteral(Expression *e)
-{
- UnionExp ue;
- if (e->op == TOKstring) // syntaxCopy doesn't make a copy for StringExp!
- {
- StringExp *se = (StringExp *)e;
- utf8_t *s = (utf8_t *)mem.xcalloc(se->len + 1, se->sz);
- memcpy(s, se->string, se->len * se->sz);
- new(&ue) StringExp(se->loc, s, se->len);
- StringExp *se2 = (StringExp *)ue.exp();
- se2->committed = se->committed;
- se2->postfix = se->postfix;
- se2->type = se->type;
- se2->sz = se->sz;
- se2->ownedByCtfe = OWNEDctfe;
- return ue;
- }
- if (e->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
- Expressions *elements = copyLiteralArray(ale->elements, ale->basis);
-
- new(&ue) ArrayLiteralExp(e->loc, e->type, elements);
-
- ArrayLiteralExp *r = (ArrayLiteralExp *)ue.exp();
- r->ownedByCtfe = OWNEDctfe;
- return ue;
- }
- if (e->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
- new(&ue) AssocArrayLiteralExp(e->loc, copyLiteralArray(aae->keys), copyLiteralArray(aae->values));
- AssocArrayLiteralExp *r = (AssocArrayLiteralExp *)ue.exp();
- r->type = e->type;
- r->ownedByCtfe = OWNEDctfe;
- return ue;
- }
- if (e->op == TOKstructliteral)
- {
- /* syntaxCopy doesn't work for struct literals, because of a nasty special
- * case: block assignment is permitted inside struct literals, eg,
- * an int[4] array can be initialized with a single int.
- */
- StructLiteralExp *sle = (StructLiteralExp *)e;
- Expressions *oldelems = sle->elements;
- Expressions * newelems = new Expressions();
- newelems->setDim(oldelems->length);
- for (size_t i = 0; i < newelems->length; i++)
- {
- // We need the struct definition to detect block assignment
- VarDeclaration *v = sle->sd->fields[i];
- Expression *m = (*oldelems)[i];
-
- // If it is a void assignment, use the default initializer
- if (!m)
- m = voidInitLiteral(v->type, v).copy();
-
- if (v->type->ty == Tarray || v->type->ty == Taarray)
- {
- // Don't have to copy array references
- }
- else
- {
- // Buzilla 15681: Copy the source element always.
- m = copyLiteral(m).copy();
-
- // Block assignment from inside struct literals
- if (v->type->ty != m->type->ty && v->type->ty == Tsarray)
- {
- TypeSArray *tsa = (TypeSArray *)v->type;
- size_t len = (size_t)tsa->dim->toInteger();
- UnionExp uex;
- m = createBlockDuplicatedArrayLiteral(&uex, e->loc, v->type, m, len);
- if (m == uex.exp())
- m = uex.copy();
- }
- }
- (*newelems)[i] = m;
- }
- new(&ue) StructLiteralExp(e->loc, sle->sd, newelems, sle->stype);
- StructLiteralExp *r = (StructLiteralExp *)ue.exp();
- r->type = e->type;
- r->ownedByCtfe = OWNEDctfe;
- r->origin = ((StructLiteralExp *)e)->origin;
- return ue;
- }
- if (e->op == TOKfunction || e->op == TOKdelegate ||
- e->op == TOKsymoff || e->op == TOKnull ||
- e->op == TOKvar || e->op == TOKdotvar ||
- e->op == TOKint64 || e->op == TOKfloat64 ||
- e->op == TOKchar || e->op == TOKcomplex80 ||
- e->op == TOKvoid || e->op == TOKvector ||
- e->op == TOKtypeid)
- {
- // Simple value types
- // Keep e1 for DelegateExp and DotVarExp
- new(&ue) UnionExp(e);
- Expression *r = ue.exp();
- r->type = e->type;
- return ue;
- }
- if (e->op == TOKslice)
- {
- SliceExp *se = (SliceExp *)e;
- if (se->type->toBasetype()->ty == Tsarray)
- {
- // same with resolveSlice()
- if (se->e1->op == TOKnull)
- {
- new(&ue) NullExp(se->loc, se->type);
- return ue;
- }
- ue = Slice(se->type, se->e1, se->lwr, se->upr);
- assert(ue.exp()->op == TOKarrayliteral);
- ArrayLiteralExp *r = (ArrayLiteralExp *)ue.exp();
- r->elements = copyLiteralArray(r->elements);
- r->ownedByCtfe = OWNEDctfe;
- return ue;
- }
- else
- {
- // Array slices only do a shallow copy
- new(&ue) SliceExp(e->loc, se->e1, se->lwr, se->upr);
- Expression *r = ue.exp();
- r->type = e->type;
- return ue;
- }
- }
- if (isPointer(e->type))
- {
- // For pointers, we only do a shallow copy.
- if (e->op == TOKaddress)
- new(&ue) AddrExp(e->loc, ((AddrExp *)e)->e1);
- else if (e->op == TOKindex)
- new(&ue) IndexExp(e->loc, ((IndexExp *)e)->e1, ((IndexExp *)e)->e2);
- else if (e->op == TOKdotvar)
- {
- new(&ue) DotVarExp(e->loc, ((DotVarExp *)e)->e1,
- ((DotVarExp *)e)->var, ((DotVarExp *)e)->hasOverloads);
- }
- else
- assert(0);
- Expression *r = ue.exp();
- r->type = e->type;
- return ue;
- }
- if (e->op == TOKclassreference)
- {
- new(&ue) ClassReferenceExp(e->loc, ((ClassReferenceExp *)e)->value, e->type);
- return ue;
- }
- if (e->op == TOKerror)
- {
- new(&ue) UnionExp(e);
- return ue;
- }
- e->error("CTFE internal error: literal %s", e->toChars());
- assert(0);
- return ue;
-}
-
-/* Deal with type painting.
- * Type painting is a major nuisance: we can't just set
- * e->type = type, because that would change the original literal.
- * But, we can't simply copy the literal either, because that would change
- * the values of any pointers.
- */
-Expression *paintTypeOntoLiteral(Type *type, Expression *lit)
-{
- if (lit->type->equals(type))
- return lit;
- return paintTypeOntoLiteralCopy(type, lit).copy();
-}
-
-Expression *paintTypeOntoLiteral(UnionExp *pue, Type *type, Expression *lit)
-{
- if (lit->type->equals(type))
- return lit;
- *pue = paintTypeOntoLiteralCopy(type, lit);
- return pue->exp();
-}
-
-UnionExp paintTypeOntoLiteralCopy(Type *type, Expression *lit)
-{
- UnionExp ue;
-
- if (lit->type->equals(type))
- {
- new(&ue) UnionExp(lit);
- return ue;
- }
-
- // If it is a cast to inout, retain the original type of the referenced part.
- if (type->hasWild() && type->hasPointers())
- {
- new(&ue) UnionExp(lit);
- ue.exp()->type = type;
- return ue;
- }
-
- if (lit->op == TOKslice)
- {
- SliceExp *se = (SliceExp *)lit;
- new(&ue) SliceExp(lit->loc, se->e1, se->lwr, se->upr);
- }
- else if (lit->op == TOKindex)
- {
- IndexExp *ie = (IndexExp *)lit;
- new(&ue) IndexExp(lit->loc, ie->e1, ie->e2);
- }
- else if (lit->op == TOKarrayliteral)
- {
- new(&ue) SliceExp(lit->loc, lit,
- new IntegerExp(Loc(), 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit).copy());
- }
- else if (lit->op == TOKstring)
- {
- // For strings, we need to introduce another level of indirection
- new(&ue) SliceExp(lit->loc, lit,
- new IntegerExp(Loc(), 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit).copy());
- }
- else if (lit->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)lit;
- // TODO: we should be creating a reference to this AAExp, not
- // just a ref to the keys and values.
- OwnedBy wasOwned = aae->ownedByCtfe;
- new(&ue) AssocArrayLiteralExp(lit->loc, aae->keys, aae->values);
- aae = (AssocArrayLiteralExp *)ue.exp();
- aae->ownedByCtfe = wasOwned;
- }
- else
- {
- // Can't type paint from struct to struct*; this needs another
- // level of indirection
- if (lit->op == TOKstructliteral && isPointer(type))
- lit->error("CTFE internal error: painting %s", type->toChars());
- ue = copyLiteral(lit);
- }
- ue.exp()->type = type;
- return ue;
-}
-
-/*************************************
- * If e is a SliceExp, constant fold it.
- * Params:
- * e = expression to resolve
- * pue = if not null, store resulting expression here
- * Returns:
- * resulting expression
- */
-Expression *resolveSlice(Expression *e, UnionExp *pue)
-{
- if (e->op != TOKslice)
- return e;
- SliceExp *se = (SliceExp *)e;
- if (se->e1->op == TOKnull)
- return se->e1;
- if (pue)
- {
- *pue = Slice(e->type, se->e1, se->lwr, se->upr);
- return pue->exp();
- }
- else
- return Slice(e->type, se->e1, se->lwr, se->upr).copy();
-}
-
-/* Determine the array length, without interpreting it.
- * e must be an array literal, or a slice
- * It's very wasteful to resolve the slice when we only
- * need the length.
- */
-uinteger_t resolveArrayLength(Expression *e)
-{
- if (e->op == TOKvector)
- return ((VectorExp *)e)->dim;
-
- if (e->op == TOKnull)
- return 0;
- if (e->op == TOKslice)
- {
- uinteger_t ilo = ((SliceExp *)e)->lwr->toInteger();
- uinteger_t iup = ((SliceExp *)e)->upr->toInteger();
- return iup - ilo;
- }
- if (e->op == TOKstring)
- {
- return ((StringExp *)e)->len;
- }
- if (e->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
- return ale->elements ? ale->elements->length : 0;
- }
- if (e->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e;
- return ale->keys->length;
- }
- assert(0);
- return 0;
-}
-
-/******************************
- * Helper for NewExp
- * Create an array literal consisting of 'elem' duplicated 'dim' times.
- * Params:
- * pue = where to store result
- * loc = source location where the interpretation occurs
- * type = target type of the result
- * elem = the source of array element, it will be owned by the result
- * dim = element number of the result
- * Returns:
- * Constructed ArrayLiteralExp
- */
-ArrayLiteralExp *createBlockDuplicatedArrayLiteral(UnionExp *pue, Loc loc, Type *type,
- Expression *elem, size_t dim)
-{
- if (type->ty == Tsarray && type->nextOf()->ty == Tsarray && elem->type->ty != Tsarray)
- {
- // If it is a multidimensional array literal, do it recursively
- TypeSArray *tsa = (TypeSArray *)type->nextOf();
- size_t len = (size_t)tsa->dim->toInteger();
- UnionExp ue;
- elem = createBlockDuplicatedArrayLiteral(&ue, loc, type->nextOf(), elem, len);
- if (elem == ue.exp())
- elem = ue.copy();
- }
-
- // Buzilla 15681
- Type *tb = elem->type->toBasetype();
- const bool mustCopy = tb->ty == Tstruct || tb->ty == Tsarray;
-
- Expressions *elements = new Expressions();
- elements->setDim(dim);
- for (size_t i = 0; i < dim; i++)
- {
- (*elements)[i] = mustCopy ? copyLiteral(elem).copy() : elem;
- }
- new(pue) ArrayLiteralExp(loc, type, elements);
- ArrayLiteralExp *ale = (ArrayLiteralExp *)pue->exp();
- ale->ownedByCtfe = OWNEDctfe;
- return ale;
-}
-
-/******************************
- * Helper for NewExp
- * Create a string literal consisting of 'value' duplicated 'dim' times.
- */
-StringExp *createBlockDuplicatedStringLiteral(UnionExp *pue, Loc loc, Type *type,
- unsigned value, size_t dim, unsigned char sz)
-{
- utf8_t *s = (utf8_t *)mem.xcalloc(dim + 1, sz);
- for (size_t elemi = 0; elemi < dim; ++elemi)
- {
- switch (sz)
- {
- case 1: s[elemi] = (utf8_t)value; break;
- case 2: ((unsigned short *)s)[elemi] = (unsigned short)value; break;
- case 4: ((unsigned *)s)[elemi] = value; break;
- default: assert(0);
- }
- }
- new(pue) StringExp(loc, s, dim);
- StringExp *se = (StringExp *)pue->exp();
- se->type = type;
- se->sz = sz;
- se->committed = true;
- se->ownedByCtfe = OWNEDctfe;
- return se;
-}
-
-// Return true if t is an AA
-bool isAssocArray(Type *t)
-{
- t = t->toBasetype();
- if (t->ty == Taarray)
- return true;
- return false;
-}
-
-// Given a template AA type, extract the corresponding built-in AA type
-TypeAArray *toBuiltinAAType(Type *t)
-{
- t = t->toBasetype();
- if (t->ty == Taarray)
- return (TypeAArray *)t;
- assert(0);
- return NULL;
-}
-
-/************** TypeInfo operations ************************************/
-
-// Return true if type is TypeInfo_Class
-bool isTypeInfo_Class(Type *type)
-{
- return type->ty == Tclass &&
- (Type::dtypeinfo == ((TypeClass *)type)->sym ||
- Type::dtypeinfo->isBaseOf(((TypeClass *)type)->sym, NULL));
-}
-
-/************** Pointer operations ************************************/
-
-// Return true if t is a pointer (not a function pointer)
-bool isPointer(Type *t)
-{
- Type * tb = t->toBasetype();
- return tb->ty == Tpointer && tb->nextOf()->ty != Tfunction;
-}
-
-// For CTFE only. Returns true if 'e' is true or a non-null pointer.
-bool isTrueBool(Expression *e)
-{
- return e->isBool(true) ||
- ((e->type->ty == Tpointer || e->type->ty == Tclass) && e->op != TOKnull);
-}
-
-/* Is it safe to convert from srcPointee* to destPointee* ?
- * srcPointee is the genuine type (never void).
- * destPointee may be void.
- */
-bool isSafePointerCast(Type *srcPointee, Type *destPointee)
-{
- // It's safe to cast S** to D** if it's OK to cast S* to D*
- while (srcPointee->ty == Tpointer && destPointee->ty == Tpointer)
- {
- srcPointee = srcPointee->nextOf();
- destPointee = destPointee->nextOf();
- }
-
- // It's OK if both are the same (modulo const)
- if (srcPointee->constConv(destPointee))
- return true;
-
- // It's OK if function pointers differ only in safe/pure/nothrow
- if (srcPointee->ty == Tfunction && destPointee->ty == Tfunction)
- return srcPointee->covariant(destPointee) == 1;
-
- // it's OK to cast to void*
- if (destPointee->ty == Tvoid)
- return true;
-
- // It's OK to cast from V[K] to void*
- if (srcPointee->ty == Taarray && destPointee == Type::tvoidptr)
- return true;
-
- // It's OK if they are the same size (static array of) integers, eg:
- // int* --> uint*
- // int[5][] --> uint[5][]
- if (srcPointee->ty == Tsarray && destPointee->ty == Tsarray)
- {
- if (srcPointee->size() != destPointee->size())
- return false;
- srcPointee = srcPointee->baseElemOf();
- destPointee = destPointee->baseElemOf();
- }
- return srcPointee->isintegral() &&
- destPointee->isintegral() &&
- srcPointee->size() == destPointee->size();
-}
-
-Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs)
-{
- *ofs = 0;
- if (e->op == TOKaddress)
- e = ((AddrExp *)e)->e1;
- if (e->op == TOKsymoff)
- *ofs = ((SymOffExp *)e)->offset;
- if (e->op == TOKdotvar)
- {
- Expression *ex = ((DotVarExp *)e)->e1;
- VarDeclaration *v = ((DotVarExp *)e)->var->isVarDeclaration();
- assert(v);
- StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex;
- // We can't use getField, because it makes a copy
- unsigned i;
- if (ex->op == TOKclassreference)
- i = ((ClassReferenceExp *)ex)->getFieldIndex(e->type, v->offset);
- else
- i = se->getFieldIndex(e->type, v->offset);
- e = (*se->elements)[i];
- }
- if (e->op == TOKindex)
- {
- IndexExp *ie = (IndexExp *)e;
- // Note that each AA element is part of its own memory block
- if ((ie->e1->type->ty == Tarray ||
- ie->e1->type->ty == Tsarray ||
- ie->e1->op == TOKstring ||
- ie->e1->op == TOKarrayliteral) &&
- ie->e2->op == TOKint64)
- {
- *ofs = ie->e2->toInteger();
- return ie->e1;
- }
- }
- if (e->op == TOKslice && e->type->toBasetype()->ty == Tsarray)
- {
- SliceExp *se = (SliceExp *)e;
- if ((se->e1->type->ty == Tarray ||
- se->e1->type->ty == Tsarray ||
- se->e1->op == TOKstring ||
- se->e1->op == TOKarrayliteral) &&
- se->lwr->op == TOKint64)
- {
- *ofs = se->lwr->toInteger();
- return se->e1;
- }
- }
- return e;
-}
-
-/** Return true if agg1 and agg2 are pointers to the same memory block
-*/
-bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2)
-{
- if (agg1 == agg2)
- return true;
-
- // For integers cast to pointers, we regard them as non-comparable
- // unless they are identical. (This may be overly strict).
- if (agg1->op == TOKint64 && agg2->op == TOKint64 &&
- agg1->toInteger() == agg2->toInteger())
- {
- return true;
- }
-
- // Note that type painting can occur with VarExp, so we
- // must compare the variables being pointed to.
- if (agg1->op == TOKvar && agg2->op == TOKvar &&
- ((VarExp *)agg1)->var == ((VarExp *)agg2)->var)
- {
- return true;
- }
- if (agg1->op == TOKsymoff && agg2->op == TOKsymoff &&
- ((SymOffExp *)agg1)->var == ((SymOffExp *)agg2)->var)
- {
- return true;
- }
-
- return false;
-}
-
-// return e1 - e2 as an integer, or error if not possible
-UnionExp pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- UnionExp ue;
- dinteger_t ofs1, ofs2;
- Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
- Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
- if (agg1 == agg2)
- {
- Type *pointee = ((TypePointer *)agg1->type)->next;
- dinteger_t sz = pointee->size();
- new(&ue) IntegerExp(loc, (ofs1 - ofs2) * sz, type);
- }
- else if (agg1->op == TOKstring && agg2->op == TOKstring)
- {
- if (((StringExp *)agg1)->string == ((StringExp *)agg2)->string)
- {
- Type *pointee = ((TypePointer *)agg1->type)->next;
- dinteger_t sz = pointee->size();
- new(&ue) IntegerExp(loc, (ofs1 - ofs2) * sz, type);
- }
- }
- else if (agg1->op == TOKsymoff && agg2->op == TOKsymoff &&
- ((SymOffExp *)agg1)->var == ((SymOffExp *)agg2)->var)
- {
- new(&ue) IntegerExp(loc, ofs1 - ofs2, type);
- }
- else
- {
- error(loc, "%s - %s cannot be interpreted at compile time: cannot subtract "
- "pointers to two different memory blocks",
- e1->toChars(), e2->toChars());
- new(&ue) CTFEExp(TOKcantexp);
- }
- return ue;
-}
-
-// Return eptr op e2, where eptr is a pointer, e2 is an integer,
-// and op is TOKadd or TOKmin
-UnionExp pointerArithmetic(Loc loc, TOK op, Type *type,
- Expression *eptr, Expression *e2)
-{
- UnionExp ue;
-
- if (eptr->type->nextOf()->ty == Tvoid)
- {
- error(loc, "cannot perform arithmetic on void* pointers at compile time");
- Lcant:
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
- }
-
- dinteger_t ofs1;
- if (eptr->op == TOKaddress)
- eptr = ((AddrExp *)eptr)->e1;
- Expression *agg1 = getAggregateFromPointer(eptr, &ofs1);
- if (agg1->op == TOKsymoff)
- {
- if (((SymOffExp *)agg1)->var->type->ty != Tsarray)
- {
- error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time");
- goto Lcant;
- }
- }
- else if (agg1->op != TOKstring && agg1->op != TOKarrayliteral)
- {
- error(loc, "cannot perform pointer arithmetic on non-arrays at compile time");
- goto Lcant;
- }
- dinteger_t ofs2 = e2->toInteger();
-
- Type *pointee = ((TypeNext *)agg1->type->toBasetype())->next;
- dinteger_t sz = pointee->size();
-
- sinteger_t indx;
- dinteger_t len;
- if (agg1->op == TOKsymoff)
- {
- indx = ofs1 / sz;
- len = ((TypeSArray *)((SymOffExp *)agg1)->var->type)->dim->toInteger();
- }
- else
- {
- Expression *dollar = ArrayLength(Type::tsize_t, agg1).copy();
- assert(!CTFEExp::isCantExp(dollar));
- indx = ofs1;
- len = dollar->toInteger();
- }
- if (op == TOKadd || op == TOKaddass || op == TOKplusplus)
- indx += ofs2 / sz;
- else if (op == TOKmin || op == TOKminass || op == TOKminusminus)
- indx -= ofs2 / sz;
- else
- {
- error(loc, "CTFE internal error: bad pointer operation");
- goto Lcant;
- }
-
- if (indx < 0 || len < (dinteger_t)indx)
- {
- error(loc, "cannot assign pointer to index %lld inside memory block [0..%lld]", (ulonglong)indx, (ulonglong)len);
- goto Lcant;
- }
-
- if (agg1->op == TOKsymoff)
- {
- new(&ue) SymOffExp(loc, ((SymOffExp *)agg1)->var, indx * sz);
- SymOffExp *se = (SymOffExp *)ue.exp();
- se->type = type;
- return ue;
- }
-
- if (agg1->op != TOKarrayliteral && agg1->op != TOKstring)
- {
- error(loc, "CTFE internal error: pointer arithmetic %s", agg1->toChars());
- goto Lcant;
- }
-
- if (eptr->type->toBasetype()->ty == Tsarray)
- {
- dinteger_t dim = ((TypeSArray *)eptr->type->toBasetype())->dim->toInteger();
-
- // Create a CTFE pointer &agg1[indx .. indx+dim]
- SliceExp *se = new SliceExp(loc, agg1,
- new IntegerExp(loc, indx, Type::tsize_t),
- new IntegerExp(loc, indx + dim, Type::tsize_t));
- se->type = type->toBasetype()->nextOf();
- new(&ue) AddrExp(loc, se);
- ue.exp()->type = type;
- return ue;
- }
-
- // Create a CTFE pointer &agg1[indx]
- IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t);
- Expression *ie = new IndexExp(loc, agg1, ofs);
- ie->type = type->toBasetype()->nextOf(); // Bugzilla 13992
- new(&ue) AddrExp(loc, ie);
- ue.exp()->type = type;
- return ue;
-}
-
-// Return 1 if true, 0 if false
-// -1 if comparison is illegal because they point to non-comparable memory blocks
-int comparePointers(TOK op, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2)
-{
- if (pointToSameMemoryBlock(agg1, agg2))
- {
- int n;
- switch (op)
- {
- case TOKlt: n = (ofs1 < ofs2); break;
- case TOKle: n = (ofs1 <= ofs2); break;
- case TOKgt: n = (ofs1 > ofs2); break;
- case TOKge: n = (ofs1 >= ofs2); break;
- case TOKidentity:
- case TOKequal: n = (ofs1 == ofs2); break;
- case TOKnotidentity:
- case TOKnotequal: n = (ofs1 != ofs2); break;
- default:
- assert(0);
- }
- return n;
- }
- bool null1 = (agg1->op == TOKnull);
- bool null2 = (agg2->op == TOKnull);
-
- int cmp;
- if (null1 || null2)
- {
- switch (op)
- {
- case TOKlt: cmp = null1 && !null2; break;
- case TOKgt: cmp = !null1 && null2; break;
- case TOKle: cmp = null1; break;
- case TOKge: cmp = null2; break;
- case TOKidentity:
- case TOKequal:
- case TOKnotidentity: // 'cmp' gets inverted below
- case TOKnotequal:
- cmp = (null1 == null2);
- break;
- default:
- assert(0);
- }
- }
- else
- {
- switch (op)
- {
- case TOKidentity:
- case TOKequal:
- case TOKnotidentity: // 'cmp' gets inverted below
- case TOKnotequal:
- cmp = 0;
- break;
- default:
- return -1; // memory blocks are different
- }
- }
- if (op == TOKnotidentity || op == TOKnotequal)
- cmp ^= 1;
- return cmp;
-}
-
-// True if conversion from type 'from' to 'to' involves a reinterpret_cast
-// floating point -> integer or integer -> floating point
-bool isFloatIntPaint(Type *to, Type *from)
-{
- return from->size() == to->size() &&
- ((from->isintegral() && to->isfloating()) ||
- (from->isfloating() && to->isintegral()));
-}
-
-// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
-Expression *paintFloatInt(UnionExp *pue, Expression *fromVal, Type *to)
-{
- if (exceptionOrCantInterpret(fromVal))
- return fromVal;
-
- assert(to->size() == 4 || to->size() == 8);
- return Compiler::paintAsType(pue, fromVal, to);
-}
-
-/******** Constant folding, with support for CTFE ***************************/
-
-/// Return true if non-pointer expression e can be compared
-/// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity
-bool isCtfeComparable(Expression *e)
-{
- if (e->op == TOKslice)
- e = ((SliceExp *)e)->e1;
-
- if (e->isConst() != 1)
- {
- if (e->op == TOKnull ||
- e->op == TOKstring ||
- e->op == TOKfunction ||
- e->op == TOKdelegate ||
- e->op == TOKarrayliteral ||
- e->op == TOKstructliteral ||
- e->op == TOKassocarrayliteral ||
- e->op == TOKclassreference)
- {
- return true;
- }
- // Bugzilla 14123: TypeInfo object is comparable in CTFE
- if (e->op == TOKtypeid)
- return true;
-
- return false;
- }
- return true;
-}
-
-/// Map TOK comparison ops
-template <typename N>
-static bool numCmp(TOK op, N n1, N n2)
-{
- switch (op)
- {
- case TOKlt:
- return n1 < n2;
- case TOKle:
- return n1 <= n2;
- case TOKgt:
- return n1 > n2;
- case TOKge:
- return n1 >= n2;
-
- default:
- assert(0);
- }
- return false;
-}
-
-/// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-int specificCmp(TOK op, int rawCmp)
-{
- return numCmp<int>(op, rawCmp, 0);
-}
-
-/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-int intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2)
-{
- return numCmp<dinteger_t>(op, n1, n2);
-}
-
-/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2)
-{
- return numCmp<sinteger_t>(op, n1, n2);
-}
-
-/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-int realCmp(TOK op, real_t r1, real_t r2)
-{
- // Don't rely on compiler, handle NAN arguments separately
- if (CTFloat::isNaN(r1) || CTFloat::isNaN(r2)) // if unordered
- {
- switch (op)
- {
- case TOKlt:
- case TOKle:
- case TOKgt:
- case TOKge:
- break;
-
- default:
- assert(0);
- }
- return 0;
- }
- else
- {
- return numCmp<real_t>(op, r1, r2);
- }
-}
-
-int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2);
-
-/* Conceptually the same as memcmp(e1, e2).
- * e1 and e2 may be strings, arrayliterals, or slices.
- * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
- * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
- */
-int ctfeCmpArrays(Loc loc, Expression *e1, Expression *e2, uinteger_t len)
-{
- // Resolve slices, if necessary
- uinteger_t lo1 = 0;
- uinteger_t lo2 = 0;
-
- Expression *x = e1;
- if (x->op == TOKslice)
- {
- lo1 = ((SliceExp *)x)->lwr->toInteger();
- x = ((SliceExp *)x)->e1;
- }
- StringExp *se1 = (x->op == TOKstring) ? (StringExp *)x : NULL;
- ArrayLiteralExp *ae1 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : NULL;
-
- x = e2;
- if (x->op == TOKslice)
- {
- lo2 = ((SliceExp *)x)->lwr->toInteger();
- x = ((SliceExp *)x)->e1;
- }
- StringExp *se2 = (x->op == TOKstring) ? (StringExp *)x : NULL;
- ArrayLiteralExp *ae2 = (x->op == TOKarrayliteral) ? (ArrayLiteralExp *)x : NULL;
-
- // Now both must be either TOKarrayliteral or TOKstring
- if (se1 && se2)
- return sliceCmpStringWithString(se1, se2, (size_t)lo1, (size_t)lo2, (size_t)len);
- if (se1 && ae2)
- return sliceCmpStringWithArray(se1, ae2, (size_t)lo1, (size_t)lo2, (size_t)len);
- if (se2 && ae1)
- return -sliceCmpStringWithArray(se2, ae1, (size_t)lo2, (size_t)lo1, (size_t)len);
-
- assert (ae1 && ae2);
- // Comparing two array literals. This case is potentially recursive.
- // If they aren't strings, we just need an equality check rather than
- // a full cmp.
- bool needCmp = ae1->type->nextOf()->isintegral();
- for (size_t i = 0; i < (size_t)len; i++)
- {
- Expression *ee1 = (*ae1->elements)[(size_t)(lo1 + i)];
- Expression *ee2 = (*ae2->elements)[(size_t)(lo2 + i)];
- if (needCmp)
- {
- sinteger_t c = ee1->toInteger() - ee2->toInteger();
- if (c > 0)
- return 1;
- if (c < 0)
- return -1;
- }
- else
- {
- if (ctfeRawCmp(loc, ee1, ee2))
- return 1;
- }
- }
- return 0;
-}
-
-/* Given a delegate expression e, return .funcptr.
- * If e is NullExp, return NULL.
- */
-FuncDeclaration *funcptrOf(Expression *e)
-{
- assert(e->type->ty == Tdelegate);
-
- if (e->op == TOKdelegate)
- return ((DelegateExp *)e)->func;
- if (e->op == TOKfunction)
- return ((FuncExp *)e)->fd;
- assert(e->op == TOKnull);
- return NULL;
-}
-
-bool isArray(Expression *e)
-{
- return e->op == TOKarrayliteral || e->op == TOKstring ||
- e->op == TOKslice || e->op == TOKnull;
-}
-
-/* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
- * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
- */
-int ctfeRawCmp(Loc loc, Expression *e1, Expression *e2)
-{
- if (e1->op == TOKclassreference || e2->op == TOKclassreference)
- {
- if (e1->op == TOKclassreference && e2->op == TOKclassreference &&
- ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value)
- return 0;
- return 1;
- }
- if (e1->op == TOKtypeid && e2->op == TOKtypeid)
- {
- // printf("e1: %s\n", e1->toChars());
- // printf("e2: %s\n", e2->toChars());
- Type *t1 = isType(((TypeidExp *)e1)->obj);
- Type *t2 = isType(((TypeidExp *)e2)->obj);
- assert(t1);
- assert(t2);
- return t1 != t2;
- }
-
- // null == null, regardless of type
-
- if (e1->op == TOKnull && e2->op == TOKnull)
- return 0;
-
- if (e1->type->ty == Tpointer && e2->type->ty == Tpointer)
- {
- // Can only be an equality test.
-
- dinteger_t ofs1, ofs2;
- Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
- Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
- if ((agg1 == agg2) || (agg1->op == TOKvar && agg2->op == TOKvar &&
- ((VarExp *)agg1)->var == ((VarExp *)agg2)->var))
- {
- if (ofs1 == ofs2)
- return 0;
- }
- return 1;
- }
- if (e1->type->ty == Tdelegate && e2->type->ty == Tdelegate)
- {
- // If .funcptr isn't the same, they are not equal
-
- if (funcptrOf(e1) != funcptrOf(e2))
- return 1;
-
- // If both are delegate literals, assume they have the
- // same closure pointer. TODO: We don't support closures yet!
- if (e1->op == TOKfunction && e2->op == TOKfunction)
- return 0;
- assert(e1->op == TOKdelegate && e2->op == TOKdelegate);
-
- // Same .funcptr. Do they have the same .ptr?
- Expression * ptr1 = ((DelegateExp *)e1)->e1;
- Expression * ptr2 = ((DelegateExp *)e2)->e1;
-
- dinteger_t ofs1, ofs2;
- Expression *agg1 = getAggregateFromPointer(ptr1, &ofs1);
- Expression *agg2 = getAggregateFromPointer(ptr2, &ofs2);
- // If they are TOKvar, it means they are FuncDeclarations
- if ((agg1 == agg2 && ofs1 == ofs2) ||
- (agg1->op == TOKvar && agg2->op == TOKvar &&
- ((VarExp *)agg1)->var == ((VarExp *)agg2)->var))
- {
- return 0;
- }
- return 1;
- }
- if (isArray(e1) && isArray(e2))
- {
- uinteger_t len1 = resolveArrayLength(e1);
- uinteger_t len2 = resolveArrayLength(e2);
- // workaround for dmc optimizer bug calculating wrong len for
- // uinteger_t len = (len1 < len2 ? len1 : len2);
- // if (len == 0) ...
- if (len1 > 0 && len2 > 0)
- {
- uinteger_t len = (len1 < len2 ? len1 : len2);
- int res = ctfeCmpArrays(loc, e1, e2, len);
- if (res != 0)
- return res;
- }
- return (int)(len1 - len2);
- }
- if (e1->type->isintegral())
- {
- return e1->toInteger() != e2->toInteger();
- }
- real_t r1;
- real_t r2;
- if (e1->type->isreal())
- {
- r1 = e1->toReal();
- r2 = e2->toReal();
- goto L1;
- }
- else if (e1->type->isimaginary())
- {
- r1 = e1->toImaginary();
- r2 = e2->toImaginary();
- L1:
- if (CTFloat::isNaN(r1) || CTFloat::isNaN(r2)) // if unordered
- {
- return 1;
- }
- else
- {
- return (r1 != r2);
- }
- }
- else if (e1->type->iscomplex())
- {
- return e1->toComplex() != e2->toComplex();
- }
-
- if (e1->op == TOKstructliteral && e2->op == TOKstructliteral)
- {
- StructLiteralExp *es1 = (StructLiteralExp *)e1;
- StructLiteralExp *es2 = (StructLiteralExp *)e2;
- // For structs, we only need to return 0 or 1 (< and > aren't legal).
-
- if (es1->sd != es2->sd)
- return 1;
- else if ((!es1->elements || !es1->elements->length) &&
- (!es2->elements || !es2->elements->length))
- return 0; // both arrays are empty
- else if (!es1->elements || !es2->elements)
- return 1;
- else if (es1->elements->length != es2->elements->length)
- return 1;
- else
- {
- for (size_t i = 0; i < es1->elements->length; i++)
- {
- Expression *ee1 = (*es1->elements)[i];
- Expression *ee2 = (*es2->elements)[i];
-
- if (ee1 == ee2)
- continue;
- if (!ee1 || !ee2)
- return 1;
- int cmp = ctfeRawCmp(loc, ee1, ee2);
- if (cmp)
- return 1;
- }
- return 0; // All elements are equal
- }
- }
- if (e1->op == TOKassocarrayliteral && e2->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *es1 = (AssocArrayLiteralExp *)e1;
- AssocArrayLiteralExp *es2 = (AssocArrayLiteralExp *)e2;
-
- size_t dim = es1->keys->length;
- if (es2->keys->length != dim)
- return 1;
-
- bool *used = (bool *)mem.xmalloc(sizeof(bool) * dim);
- memset(used, 0, sizeof(bool) * dim);
-
- for (size_t i = 0; i < dim; ++i)
- {
- Expression *k1 = (*es1->keys)[i];
- Expression *v1 = (*es1->values)[i];
- Expression *v2 = NULL;
- for (size_t j = 0; j < dim; ++j)
- {
- if (used[j])
- continue;
- Expression *k2 = (*es2->keys)[j];
-
- if (ctfeRawCmp(loc, k1, k2))
- continue;
- used[j] = true;
- v2 = (*es2->values)[j];
- break;
- }
- if (!v2 || ctfeRawCmp(loc, v1, v2))
- {
- mem.xfree(used);
- return 1;
- }
- }
- mem.xfree(used);
- return 0;
- }
- error(loc, "CTFE internal error: bad compare of `%s` and `%s`", e1->toChars(), e2->toChars());
- assert(0);
- return 0;
-}
-
-/// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1
-int ctfeEqual(Loc loc, TOK op, Expression *e1, Expression *e2)
-{
- int cmp = !ctfeRawCmp(loc, e1, e2);
- if (op == TOKnotequal)
- cmp ^= 1;
- return cmp;
-}
-
-/// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1
-int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2)
-{
- //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", Token::toChars(op),
- // Token::toChars(e1->op), e1->toChars(), Token::toChars(e2->op), e1->toChars());
- int cmp;
- if (e1->op == TOKnull)
- {
- cmp = (e2->op == TOKnull);
- }
- else if (e2->op == TOKnull)
- {
- cmp = 0;
- }
- else if (e1->op == TOKsymoff && e2->op == TOKsymoff)
- {
- SymOffExp *es1 = (SymOffExp *)e1;
- SymOffExp *es2 = (SymOffExp *)e2;
- cmp = (es1->var == es2->var && es1->offset == es2->offset);
- }
- else if (e1->type->isreal())
- cmp = RealEquals(e1->toReal(), e2->toReal());
- else if (e1->type->isimaginary())
- cmp = RealEquals(e1->toImaginary(), e2->toImaginary());
- else if (e1->type->iscomplex())
- {
- complex_t v1 = e1->toComplex();
- complex_t v2 = e2->toComplex();
- cmp = RealEquals(creall(v1), creall(v2)) &&
- RealEquals(cimagl(v1), cimagl(v1));
- }
- else
- cmp = !ctfeRawCmp(loc, e1, e2);
-
- if (op == TOKnotidentity || op == TOKnotequal)
- cmp ^= 1;
- return cmp;
-}
-
-/// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
-int ctfeCmp(Loc loc, TOK op, Expression *e1, Expression *e2)
-{
- Type *t1 = e1->type->toBasetype();
- Type *t2 = e2->type->toBasetype();
-
- if (t1->isString() && t2->isString())
- return specificCmp(op, ctfeRawCmp(loc, e1, e2));
- else if (t1->isreal())
- return realCmp(op, e1->toReal(), e2->toReal());
- else if (t1->isimaginary())
- return realCmp(op, e1->toImaginary(), e2->toImaginary());
- else if (t1->isunsigned() || t2->isunsigned())
- return intUnsignedCmp(op, e1->toInteger(), e2->toInteger());
- else
- return intSignedCmp(op, e1->toInteger(), e2->toInteger());
-}
-
-UnionExp ctfeCat(Loc loc, Type *type, Expression *e1, Expression *e2)
-{
- Type *t1 = e1->type->toBasetype();
- Type *t2 = e2->type->toBasetype();
- UnionExp ue;
- if (e2->op == TOKstring && e1->op == TOKarrayliteral &&
- t1->nextOf()->isintegral())
- {
- // [chars] ~ string => string (only valid for CTFE)
- StringExp *es1 = (StringExp *)e2;
- ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1;
- size_t len = es1->len + es2->elements->length;
- unsigned char sz = es1->sz;
-
- void *s = mem.xmalloc((len + 1) * sz);
- memcpy((char *)s + sz * es2->elements->length, es1->string, es1->len * sz);
- for (size_t i = 0; i < es2->elements->length; i++)
- {
- Expression *es2e = (*es2->elements)[i];
- if (es2e->op != TOKint64)
- {
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
- }
- dinteger_t v = es2e->toInteger();
- Port::valcpy((utf8_t *)s + i * sz, v, sz);
- }
-
- // Add terminating 0
- memset((utf8_t *)s + len * sz, 0, sz);
-
- new(&ue) StringExp(loc, s, len);
- StringExp *es = (StringExp *)ue.exp();
- es->sz = sz;
- es->committed = 0;
- es->type = type;
- return ue;
- }
- if (e1->op == TOKstring && e2->op == TOKarrayliteral &&
- t2->nextOf()->isintegral())
- {
- // string ~ [chars] => string (only valid for CTFE)
- // Concatenate the strings
- StringExp *es1 = (StringExp *)e1;
- ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
- size_t len = es1->len + es2->elements->length;
- unsigned char sz = es1->sz;
-
- void *s = mem.xmalloc((len + 1) * sz);
- memcpy(s, es1->string, es1->len * sz);
- for (size_t i = 0; i < es2->elements->length; i++)
- {
- Expression *es2e = (*es2->elements)[i];
- if (es2e->op != TOKint64)
- {
- new(&ue) CTFEExp(TOKcantexp);
- return ue;
- }
- dinteger_t v = es2e->toInteger();
- Port::valcpy((utf8_t *)s + (es1->len + i) * sz, v, sz);
- }
-
- // Add terminating 0
- memset((utf8_t *)s + len * sz, 0, sz);
-
- new(&ue) StringExp(loc, s, len);
- StringExp *es = (StringExp *)ue.exp();
- es->sz = sz;
- es->committed = 0; //es1->committed;
- es->type = type;
- return ue;
- }
- if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral &&
- t1->nextOf()->equals(t2->nextOf()))
- {
- // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
- ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1;
- ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2;
-
- new(&ue) ArrayLiteralExp(es1->loc, type, copyLiteralArray(es1->elements));
- es1 = (ArrayLiteralExp *)ue.exp();
- es1->elements->insert(es1->elements->length, copyLiteralArray(es2->elements));
- return ue;
- }
- if (e1->op == TOKarrayliteral && e2->op == TOKnull &&
- t1->nextOf()->equals(t2->nextOf()))
- {
- // [ e1 ] ~ null ----> [ e1 ].dup
- ue = paintTypeOntoLiteralCopy(type, copyLiteral(e1).copy());
- return ue;
- }
- if (e1->op == TOKnull && e2->op == TOKarrayliteral &&
- t1->nextOf()->equals(t2->nextOf()))
- {
- // null ~ [ e2 ] ----> [ e2 ].dup
- ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy());
- return ue;
- }
- ue = Cat(type, e1, e2);
- return ue;
-}
-
-/* Given an AA literal 'ae', and a key 'e2':
- * Return ae[e2] if present, or NULL if not found.
- */
-Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2)
-{
- /* Search the keys backwards, in case there are duplicate keys
- */
- for (size_t i = ae->keys->length; i;)
- {
- i--;
- Expression *ekey = (*ae->keys)[i];
- int eq = ctfeEqual(loc, TOKequal, ekey, e2);
- if (eq)
- {
- return (*ae->values)[i];
- }
- }
- return NULL;
-}
-
-/* Same as for constfold.Index, except that it only works for static arrays,
- * dynamic arrays, and strings. We know that e1 is an
- * interpreted CTFE expression, so it cannot have side-effects.
- */
-Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx)
-{
- //printf("ctfeIndex(e1 = %s)\n", e1->toChars());
- assert(e1->type);
- if (e1->op == TOKstring)
- {
- StringExp *es1 = (StringExp *)e1;
- if (indx >= es1->len)
- {
- error(loc, "string index %llu is out of bounds [0 .. %llu]", (ulonglong)indx, (ulonglong)es1->len);
- return CTFEExp::cantexp;
- }
- return new IntegerExp(loc, es1->charAt(indx), type);
- }
- assert(e1->op == TOKarrayliteral);
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
- if (indx >= ale->elements->length)
- {
- error(loc, "array index %llu is out of bounds %s[0 .. %llu]", (ulonglong)indx, e1->toChars(), (ulonglong)ale->elements->length);
- return CTFEExp::cantexp;
- }
- Expression *e = (*ale->elements)[(size_t)indx];
- return paintTypeOntoLiteral(type, e);
- }
-}
-
-Expression *ctfeCast(UnionExp *pue, Loc loc, Type *type, Type *to, Expression *e)
-{
- if (e->op == TOKnull)
- return paintTypeOntoLiteral(pue, to, e);
-
- if (e->op == TOKclassreference)
- {
- // Disallow reinterpreting class casts. Do this by ensuring that
- // the original class can implicitly convert to the target class
- ClassDeclaration *originalClass = ((ClassReferenceExp *)e)->originalClass();
- if (originalClass->type->implicitConvTo(to->mutableOf()))
- return paintTypeOntoLiteral(pue, to, e);
- else
- {
- new(pue) NullExp(loc, to);
- return pue->exp();
- }
- }
-
- // Allow TypeInfo type painting
- if (isTypeInfo_Class(e->type) && e->type->implicitConvTo(to))
- return paintTypeOntoLiteral(pue, to, e);
-
- // Allow casting away const for struct literals
- if (e->op == TOKstructliteral &&
- e->type->toBasetype()->castMod(0) == to->toBasetype()->castMod(0))
- return paintTypeOntoLiteral(pue, to, e);
-
- Expression *r;
- if (e->type->equals(type) && type->equals(to))
- {
- // necessary not to change e's address for pointer comparisons
- r = e;
- }
- else if (to->toBasetype()->ty == Tarray &&
- type->toBasetype()->ty == Tarray &&
- to->toBasetype()->nextOf()->size() == type->toBasetype()->nextOf()->size())
- {
- // Bugzilla 12495: Array reinterpret casts: eg. string to immutable(ubyte)[]
- return paintTypeOntoLiteral(pue, to, e);
- }
- else
- {
- *pue = Cast(loc, type, to, e);
- r = pue->exp();
- }
-
- if (CTFEExp::isCantExp(r))
- error(loc, "cannot cast %s to %s at compile time", e->toChars(), to->toChars());
-
- if (e->op == TOKarrayliteral)
- ((ArrayLiteralExp *)e)->ownedByCtfe = OWNEDctfe;
-
- if (e->op == TOKstring)
- ((StringExp *)e)->ownedByCtfe = OWNEDctfe;
-
- return r;
-}
-
-/******** Assignment helper functions ***************************/
-
-/* Set dest = src, where both dest and src are container value literals
- * (ie, struct literals, or static arrays (can be an array literal or a string))
- * Assignment is recursively in-place.
- * Purpose: any reference to a member of 'dest' will remain valid after the
- * assignment.
- */
-void assignInPlace(Expression *dest, Expression *src)
-{
- assert(dest->op == TOKstructliteral ||
- dest->op == TOKarrayliteral ||
- dest->op == TOKstring);
- Expressions *oldelems;
- Expressions *newelems;
- if (dest->op == TOKstructliteral)
- {
- assert(dest->op == src->op);
- oldelems = ((StructLiteralExp *)dest)->elements;
- newelems = ((StructLiteralExp *)src)->elements;
- if (((StructLiteralExp *)dest)->sd->isNested() && oldelems->length == newelems->length - 1)
- oldelems->push(NULL);
- }
- else if (dest->op == TOKarrayliteral && src->op==TOKarrayliteral)
- {
- oldelems = ((ArrayLiteralExp *)dest)->elements;
- newelems = ((ArrayLiteralExp *)src)->elements;
- }
- else if (dest->op == TOKstring && src->op == TOKstring)
- {
- sliceAssignStringFromString((StringExp *)dest, (StringExp *)src, 0);
- return;
- }
- else if (dest->op == TOKarrayliteral && src->op == TOKstring)
- {
- sliceAssignArrayLiteralFromString((ArrayLiteralExp *)dest, (StringExp *)src, 0);
- return;
- }
- else if (src->op == TOKarrayliteral && dest->op == TOKstring)
- {
- sliceAssignStringFromArrayLiteral((StringExp *)dest, (ArrayLiteralExp *)src, 0);
- return;
- }
- else
- assert(0);
-
- assert(oldelems->length == newelems->length);
-
- for (size_t i= 0; i < oldelems->length; ++i)
- {
- Expression *e = (*newelems)[i];
- Expression *o = (*oldelems)[i];
- if (e->op == TOKstructliteral)
- {
- assert(o->op == e->op);
- assignInPlace(o, e);
- }
- else if (e->type->ty == Tsarray && e->op != TOKvoid &&
- o->type->ty == Tsarray)
- {
- assignInPlace(o, e);
- }
- else
- {
- (*oldelems)[i] = (*newelems)[i];
- }
- }
-}
-
-// Duplicate the elements array, then set field 'indexToChange' = newelem.
-Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem)
-{
- Expressions *expsx = new Expressions();
- ++CtfeStatus::numArrayAllocs;
- expsx->setDim(oldelems->length);
- for (size_t j = 0; j < expsx->length; j++)
- {
- if (j == indexToChange)
- (*expsx)[j] = newelem;
- else
- (*expsx)[j] = (*oldelems)[j];
- }
- return expsx;
-}
-
-// Given an AA literal aae, set aae[index] = newval and return newval.
-Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae,
- Expression *index, Expression *newval)
-{
- /* Create new associative array literal reflecting updated key/value
- */
- Expressions *keysx = aae->keys;
- Expressions *valuesx = aae->values;
- int updated = 0;
- for (size_t j = valuesx->length; j; )
- {
- j--;
- Expression *ekey = (*aae->keys)[j];
- int eq = ctfeEqual(loc, TOKequal, ekey, index);
- if (eq)
- {
- (*valuesx)[j] = newval;
- updated = 1;
- }
- }
- if (!updated)
- {
- // Append index/newval to keysx[]/valuesx[]
- valuesx->push(newval);
- keysx->push(index);
- }
- return newval;
-}
-
-/// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
-/// oldlen, change its length to newlen. If the newlen is longer than oldlen,
-/// all new elements will be set to the default initializer for the element type.
-UnionExp changeArrayLiteralLength(Loc loc, TypeArray *arrayType,
- Expression *oldval, size_t oldlen, size_t newlen)
-{
- UnionExp ue;
- Type *elemType = arrayType->next;
- assert(elemType);
- Expression *defaultElem = elemType->defaultInitLiteral(loc);
- Expressions *elements = new Expressions();
- elements->setDim(newlen);
-
- // Resolve slices
- size_t indxlo = 0;
- if (oldval->op == TOKslice)
- {
- indxlo = (size_t)((SliceExp *)oldval)->lwr->toInteger();
- oldval = ((SliceExp *)oldval)->e1;
- }
- size_t copylen = oldlen < newlen ? oldlen : newlen;
- if (oldval->op == TOKstring)
- {
- StringExp *oldse = (StringExp *)oldval;
- void *s = mem.xcalloc(newlen + 1, oldse->sz);
- memcpy(s, oldse->string, copylen * oldse->sz);
- unsigned defaultValue = (unsigned)(defaultElem->toInteger());
- for (size_t elemi = copylen; elemi < newlen; ++elemi)
- {
- switch (oldse->sz)
- {
- case 1: (( utf8_t *)s)[(size_t)(indxlo + elemi)] = ( utf8_t)defaultValue; break;
- case 2: ((utf16_t *)s)[(size_t)(indxlo + elemi)] = (utf16_t)defaultValue; break;
- case 4: ((utf32_t *)s)[(size_t)(indxlo + elemi)] = (utf32_t)defaultValue; break;
- default: assert(0);
- }
- }
- new(&ue) StringExp(loc, s, newlen);
- StringExp *se = (StringExp *)ue.exp();
- se->type = arrayType;
- se->sz = oldse->sz;
- se->committed = oldse->committed;
- se->ownedByCtfe = OWNEDctfe;
- }
- else
- {
- if (oldlen != 0)
- {
- assert(oldval->op == TOKarrayliteral);
- ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval;
- for (size_t i = 0; i < copylen; i++)
- (*elements)[i] = (*ae->elements)[indxlo + i];
- }
- if (elemType->ty == Tstruct || elemType->ty == Tsarray)
- {
- /* If it is an aggregate literal representing a value type,
- * we need to create a unique copy for each element
- */
- for (size_t i = copylen; i < newlen; i++)
- (*elements)[i] = copyLiteral(defaultElem).copy();
- }
- else
- {
- for (size_t i = copylen; i < newlen; i++)
- (*elements)[i] = defaultElem;
- }
- new(&ue) ArrayLiteralExp(loc, arrayType, elements);
- ArrayLiteralExp *aae = (ArrayLiteralExp *)ue.exp();
- aae->ownedByCtfe = OWNEDctfe;
- }
- return ue;
-}
-
-/*************************** CTFE Sanity Checks ***************************/
-
-bool isCtfeValueValid(Expression *newval)
-{
- Type *tb = newval->type->toBasetype();
-
- if (newval->op == TOKint64 ||
- newval->op == TOKfloat64 ||
- newval->op == TOKchar ||
- newval->op == TOKcomplex80)
- {
- return tb->isscalar();
- }
- if (newval->op == TOKnull)
- {
- return tb->ty == Tnull ||
- tb->ty == Tpointer ||
- tb->ty == Tarray ||
- tb->ty == Taarray ||
- tb->ty == Tclass ||
- tb->ty == Tdelegate;
- }
-
- if (newval->op == TOKstring)
- return true; // CTFE would directly use the StringExp in AST.
- if (newval->op == TOKarrayliteral)
- return true; //((ArrayLiteralExp *)newval)->ownedByCtfe;
- if (newval->op == TOKassocarrayliteral)
- return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe;
- if (newval->op == TOKstructliteral)
- return true; //((StructLiteralExp *)newval)->ownedByCtfe;
- if (newval->op == TOKclassreference)
- return true;
-
- if (newval->op == TOKvector)
- return true; // vector literal
-
- if (newval->op == TOKfunction)
- return true; // function literal or delegate literal
- if (newval->op == TOKdelegate)
- {
- // &struct.func or &clasinst.func
- // &nestedfunc
- Expression *ethis = ((DelegateExp *)newval)->e1;
- return (ethis->op == TOKstructliteral ||
- ethis->op == TOKclassreference ||
- (ethis->op == TOKvar && ((VarExp *)ethis)->var == ((DelegateExp *)newval)->func));
- }
- if (newval->op == TOKsymoff)
- {
- // function pointer, or pointer to static variable
- Declaration *d = ((SymOffExp *)newval)->var;
- return d->isFuncDeclaration() || d->isDataseg();
- }
- if (newval->op == TOKtypeid)
- {
- // always valid
- return true;
- }
- if (newval->op == TOKaddress)
- {
- // e1 should be a CTFE reference
- Expression *e1 = ((AddrExp *)newval)->e1;
- return tb->ty == Tpointer &&
- (((e1->op == TOKstructliteral || e1->op == TOKarrayliteral) && isCtfeValueValid(e1)) ||
- (e1->op == TOKvar) ||
- (e1->op == TOKdotvar && isCtfeReferenceValid(e1)) ||
- (e1->op == TOKindex && isCtfeReferenceValid(e1)) ||
- (e1->op == TOKslice && e1->type->toBasetype()->ty == Tsarray));
- }
- if (newval->op == TOKslice)
- {
- // e1 should be an array aggregate
- SliceExp *se = (SliceExp *)newval;
- assert(se->lwr && se->lwr->op == TOKint64);
- assert(se->upr && se->upr->op == TOKint64);
- return (tb->ty == Tarray ||
- tb->ty == Tsarray) &&
- (se->e1->op == TOKstring ||
- se->e1->op == TOKarrayliteral);
- }
-
- if (newval->op == TOKvoid)
- return true; // uninitialized value
-
- newval->error("CTFE internal error: illegal CTFE value %s", newval->toChars());
- return false;
-}
-
-bool isCtfeReferenceValid(Expression *newval)
-{
- if (newval->op == TOKthis)
- return true;
- if (newval->op == TOKvar)
- {
- VarDeclaration *v = ((VarExp *)newval)->var->isVarDeclaration();
- assert(v);
- // Must not be a reference to a reference
- return true;
- }
- if (newval->op == TOKindex)
- {
- Expression *eagg = ((IndexExp *)newval)->e1;
- return eagg->op == TOKstring ||
- eagg->op == TOKarrayliteral ||
- eagg->op == TOKassocarrayliteral;
- }
- if (newval->op == TOKdotvar)
- {
- Expression *eagg = ((DotVarExp *)newval)->e1;
- return (eagg->op == TOKstructliteral || eagg->op == TOKclassreference) &&
- isCtfeValueValid(eagg);
- }
-
- // Internally a ref variable may directly point a stack memory.
- // e.g. ref int v = 1;
- return isCtfeValueValid(newval);
-}
-
-// Used for debugging only
-void showCtfeExpr(Expression *e, int level)
-{
- for (int i = level; i > 0; --i) printf(" ");
- Expressions *elements = NULL;
- // We need the struct definition to detect block assignment
- StructDeclaration *sd = NULL;
- ClassDeclaration *cd = NULL;
- if (e->op == TOKstructliteral)
- {
- elements = ((StructLiteralExp *)e)->elements;
- sd = ((StructLiteralExp *)e)->sd;
- printf("STRUCT type = %s %p:\n", e->type->toChars(),
- e);
- }
- else if (e->op == TOKclassreference)
- {
- elements = ((ClassReferenceExp *)e)->value->elements;
- cd = ((ClassReferenceExp *)e)->originalClass();
- printf("CLASS type = %s %p:\n", e->type->toChars(),
- ((ClassReferenceExp *)e)->value);
- }
- else if (e->op == TOKarrayliteral)
- {
- elements = ((ArrayLiteralExp *)e)->elements;
- printf("ARRAY LITERAL type=%s %p:\n", e->type->toChars(),
- e);
- }
- else if (e->op == TOKassocarrayliteral)
- {
- printf("AA LITERAL type=%s %p:\n", e->type->toChars(),
- e);
- }
- else if (e->op == TOKstring)
- {
- printf("STRING %s %p\n", e->toChars(),
- ((StringExp *)e)->string);
- }
- else if (e->op == TOKslice)
- {
- printf("SLICE %p: %s\n", e, e->toChars());
- showCtfeExpr(((SliceExp *)e)->e1, level + 1);
- }
- else if (e->op == TOKvar)
- {
- printf("VAR %p %s\n", e, e->toChars());
- VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
- if (v && getValue(v))
- showCtfeExpr(getValue(v), level + 1);
- }
- else if (e->op == TOKaddress)
- {
- // This is potentially recursive. We mustn't try to print the thing we're pointing to.
- printf("POINTER %p to %p: %s\n", e, ((AddrExp *)e)->e1, e->toChars());
- }
- else
- printf("VALUE %p: %s\n", e, e->toChars());
-
- if (elements)
- {
- size_t fieldsSoFar = 0;
- for (size_t i = 0; i < elements->length; i++)
- {
- Expression *z = NULL;
- VarDeclaration *v = NULL;
- if (i > 15)
- {
- printf("...(total %d elements)\n", (int)elements->length);
- return;
- }
- if (sd)
- {
- v = sd->fields[i];
- z = (*elements)[i];
- }
- else if (cd)
- {
- while (i - fieldsSoFar >= cd->fields.length)
- {
- fieldsSoFar += cd->fields.length;
- cd = cd->baseClass;
- for (int j = level; j > 0; --j) printf(" ");
- printf(" BASE CLASS: %s\n", cd->toChars());
- }
- v = cd->fields[i - fieldsSoFar];
- assert((elements->length + i) >= (fieldsSoFar + cd->fields.length));
- size_t indx = (elements->length - fieldsSoFar)- cd->fields.length + i;
- assert(indx < elements->length);
- z = (*elements)[indx];
- }
- if (!z)
- {
- for (int j = level; j > 0; --j) printf(" ");
- printf(" void\n");
- continue;
- }
-
- if (v)
- {
- // If it is a void assignment, use the default initializer
- if ((v->type->ty != z->type->ty) && v->type->ty == Tsarray)
- {
- for (int j = level; --j; ) printf(" ");
- printf(" field: block initalized static array\n");
- continue;
- }
- }
- showCtfeExpr(z, level + 1);
- }
- }
-}
-
-/*************************** Void initialization ***************************/
-
-UnionExp voidInitLiteral(Type *t, VarDeclaration *var)
-{
- UnionExp ue;
- if (t->ty == Tsarray)
- {
- TypeSArray *tsa = (TypeSArray *)t;
- Expression *elem = voidInitLiteral(tsa->next, var).copy();
-
- // For aggregate value types (structs, static arrays) we must
- // create an a separate copy for each element.
- bool mustCopy = (elem->op == TOKarrayliteral || elem->op == TOKstructliteral);
-
- Expressions *elements = new Expressions();
- size_t d = (size_t)tsa->dim->toInteger();
- elements->setDim(d);
- for (size_t i = 0; i < d; i++)
- {
- if (mustCopy && i > 0)
- elem = copyLiteral(elem).copy();
- (*elements)[i] = elem;
- }
- new(&ue) ArrayLiteralExp(var->loc, tsa, elements);
- ArrayLiteralExp *ae = (ArrayLiteralExp *)ue.exp();
- ae->ownedByCtfe = OWNEDctfe;
- }
- else if (t->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)t;
- Expressions *exps = new Expressions();
- exps->setDim(ts->sym->fields.length);
- for (size_t i = 0; i < ts->sym->fields.length; i++)
- {
- (*exps)[i] = voidInitLiteral(ts->sym->fields[i]->type, ts->sym->fields[i]).copy();
- }
- new(&ue) StructLiteralExp(var->loc, ts->sym, exps);
- StructLiteralExp *se = (StructLiteralExp *)ue.exp();
- se->type = ts;
- se->ownedByCtfe = OWNEDctfe;
- }
- else
- new(&ue) VoidInitExp(var, t);
- return ue;
-}
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
new file mode 100644
index 0000000..22633a8
--- /dev/null
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -0,0 +1,2096 @@
+/**
+ * CTFE for expressions involving pointers, slices, array concatenation etc.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d, _ctfeexpr.d)
+ * Documentation: https://dlang.org/phobos/dmd_ctfeexpr.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ctfeexpr.d
+ */
+
+module dmd.ctfeexpr;
+
+import core.stdc.stdio;
+import core.stdc.stdlib;
+import core.stdc.string;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.complex;
+import dmd.constfold;
+import dmd.compiler;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dinterpret;
+import dmd.dstruct;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.mtype;
+import dmd.root.ctfloat;
+import dmd.root.port;
+import dmd.root.rmem;
+import dmd.tokens;
+import dmd.visitor;
+
+
+/***********************************************************
+ * A reference to a class, or an interface. We need this when we
+ * point to a base class (we must record what the type is).
+ */
+extern (C++) final class ClassReferenceExp : Expression
+{
+ StructLiteralExp value;
+
+ extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type)
+ {
+ super(loc, TOK.classReference, __traits(classInstanceSize, ClassReferenceExp));
+ assert(lit && lit.sd && lit.sd.isClassDeclaration());
+ this.value = lit;
+ this.type = type;
+ }
+
+ ClassDeclaration originalClass()
+ {
+ return value.sd.isClassDeclaration();
+ }
+
+ // Return index of the field, or -1 if not found
+ private int getFieldIndex(Type fieldtype, uint fieldoffset)
+ {
+ ClassDeclaration cd = originalClass();
+ uint fieldsSoFar = 0;
+ for (size_t j = 0; j < value.elements.dim; j++)
+ {
+ while (j - fieldsSoFar >= cd.fields.dim)
+ {
+ fieldsSoFar += cd.fields.dim;
+ cd = cd.baseClass;
+ }
+ VarDeclaration v2 = cd.fields[j - fieldsSoFar];
+ if (fieldoffset == v2.offset && fieldtype.size() == v2.type.size())
+ {
+ return cast(int)(value.elements.dim - fieldsSoFar - cd.fields.dim + (j - fieldsSoFar));
+ }
+ }
+ return -1;
+ }
+
+ // Return index of the field, or -1 if not found
+ // Same as getFieldIndex, but checks for a direct match with the VarDeclaration
+ int findFieldIndexByName(VarDeclaration v)
+ {
+ ClassDeclaration cd = originalClass();
+ size_t fieldsSoFar = 0;
+ for (size_t j = 0; j < value.elements.dim; j++)
+ {
+ while (j - fieldsSoFar >= cd.fields.dim)
+ {
+ fieldsSoFar += cd.fields.dim;
+ cd = cd.baseClass;
+ }
+ VarDeclaration v2 = cd.fields[j - fieldsSoFar];
+ if (v == v2)
+ {
+ return cast(int)(value.elements.dim - fieldsSoFar - cd.fields.dim + (j - fieldsSoFar));
+ }
+ }
+ return -1;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/*************************
+ * Same as getFieldIndex, but checks for a direct match with the VarDeclaration
+ * Returns:
+ * index of the field, or -1 if not found
+ */
+int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure
+{
+ foreach (i, field; sd.fields)
+ {
+ if (field == v)
+ return cast(int)i;
+ }
+ return -1;
+}
+
+/***********************************************************
+ * Fake class which holds the thrown exception.
+ * Used for implementing exception handling.
+ */
+extern (C++) final class ThrownExceptionExp : Expression
+{
+ ClassReferenceExp thrown; // the thing being tossed
+
+ extern (D) this(const ref Loc loc, ClassReferenceExp victim)
+ {
+ super(loc, TOK.thrownException, __traits(classInstanceSize, ThrownExceptionExp));
+ this.thrown = victim;
+ this.type = victim.type;
+ }
+
+ override const(char)* toChars() const
+ {
+ return "CTFE ThrownException";
+ }
+
+ // Generate an error message when this exception is not caught
+ extern (D) void generateUncaughtError()
+ {
+ UnionExp ue = void;
+ Expression e = resolveSlice((*thrown.value.elements)[0], &ue);
+ StringExp se = e.toStringExp();
+ thrown.error("uncaught CTFE exception `%s(%s)`", thrown.type.toChars(), se ? se.toChars() : e.toChars());
+ /* Also give the line where the throw statement was. We won't have it
+ * in the case where the ThrowStatement is generated internally
+ * (eg, in ScopeStatement)
+ */
+ if (loc.isValid() && !loc.equals(thrown.loc))
+ .errorSupplemental(loc, "thrown from here");
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * This type is only used by the interpreter.
+ */
+extern (C++) final class CTFEExp : Expression
+{
+ extern (D) this(TOK tok)
+ {
+ super(Loc.initial, tok, __traits(classInstanceSize, CTFEExp));
+ type = Type.tvoid;
+ }
+
+ override const(char)* toChars() const
+ {
+ switch (op)
+ {
+ case TOK.cantExpression:
+ return "<cant>";
+ case TOK.voidExpression:
+ return "cast(void)0";
+ case TOK.showCtfeContext:
+ return "<error>";
+ case TOK.break_:
+ return "<break>";
+ case TOK.continue_:
+ return "<continue>";
+ case TOK.goto_:
+ return "<goto>";
+ default:
+ assert(0);
+ }
+ }
+
+ extern (D) __gshared CTFEExp cantexp;
+ extern (D) __gshared CTFEExp voidexp;
+ extern (D) __gshared CTFEExp breakexp;
+ extern (D) __gshared CTFEExp continueexp;
+ extern (D) __gshared CTFEExp gotoexp;
+ /* Used when additional information is needed regarding
+ * a ctfe error.
+ */
+ extern (D) __gshared CTFEExp showcontext;
+
+ extern (D) static bool isCantExp(const Expression e)
+ {
+ return e && e.op == TOK.cantExpression;
+ }
+
+ extern (D) static bool isGotoExp(const Expression e)
+ {
+ return e && e.op == TOK.goto_;
+ }
+}
+
+// True if 'e' is CTFEExp::cantexp, or an exception
+bool exceptionOrCantInterpret(const Expression e)
+{
+ return e && (e.op == TOK.cantExpression || e.op == TOK.thrownException || e.op == TOK.showCtfeContext);
+}
+
+/************** Aggregate literals (AA/string/array/struct) ******************/
+// Given expr, which evaluates to an array/AA/string literal,
+// return true if it needs to be copied
+bool needToCopyLiteral(const Expression expr)
+{
+ Expression e = cast()expr;
+ for (;;)
+ {
+ switch (e.op)
+ {
+ case TOK.arrayLiteral:
+ return (cast(ArrayLiteralExp)e).ownedByCtfe == OwnedBy.code;
+ case TOK.assocArrayLiteral:
+ return (cast(AssocArrayLiteralExp)e).ownedByCtfe == OwnedBy.code;
+ case TOK.structLiteral:
+ return (cast(StructLiteralExp)e).ownedByCtfe == OwnedBy.code;
+ case TOK.string_:
+ case TOK.this_:
+ case TOK.variable:
+ return false;
+ case TOK.assign:
+ return false;
+ case TOK.index:
+ case TOK.dotVariable:
+ case TOK.slice:
+ case TOK.cast_:
+ e = (cast(UnaExp)e).e1;
+ continue;
+ case TOK.concatenate:
+ return needToCopyLiteral((cast(BinExp)e).e1) || needToCopyLiteral((cast(BinExp)e).e2);
+ case TOK.concatenateAssign:
+ case TOK.concatenateElemAssign:
+ case TOK.concatenateDcharAssign:
+ e = (cast(BinExp)e).e2;
+ continue;
+ default:
+ return false;
+ }
+ }
+}
+
+private Expressions* copyLiteralArray(Expressions* oldelems, Expression basis = null)
+{
+ if (!oldelems)
+ return oldelems;
+ incArrayAllocs();
+ auto newelems = new Expressions(oldelems.dim);
+ foreach (i, el; *oldelems)
+ {
+ (*newelems)[i] = copyLiteral(el ? el : basis).copy();
+ }
+ return newelems;
+}
+
+// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
+// This value will be used for in-place modification.
+UnionExp copyLiteral(Expression e)
+{
+ UnionExp ue = void;
+ if (auto se = e.isStringExp()) // syntaxCopy doesn't make a copy for StringExp!
+ {
+ char* s = cast(char*)mem.xcalloc(se.len + 1, se.sz);
+ const slice = se.peekData();
+ memcpy(s, slice.ptr, slice.length);
+ emplaceExp!(StringExp)(&ue, se.loc, s[0 .. se.len * se.sz], se.len, se.sz);
+ StringExp se2 = cast(StringExp)ue.exp();
+ se2.committed = se.committed;
+ se2.postfix = se.postfix;
+ se2.type = se.type;
+ se2.ownedByCtfe = OwnedBy.ctfe;
+ return ue;
+ }
+ if (auto ale = e.isArrayLiteralExp())
+ {
+ auto elements = copyLiteralArray(ale.elements, ale.basis);
+
+ emplaceExp!(ArrayLiteralExp)(&ue, e.loc, e.type, elements);
+
+ ArrayLiteralExp r = cast(ArrayLiteralExp)ue.exp();
+ r.ownedByCtfe = OwnedBy.ctfe;
+ return ue;
+ }
+ if (auto aae = e.isAssocArrayLiteralExp())
+ {
+ emplaceExp!(AssocArrayLiteralExp)(&ue, e.loc, copyLiteralArray(aae.keys), copyLiteralArray(aae.values));
+ AssocArrayLiteralExp r = cast(AssocArrayLiteralExp)ue.exp();
+ r.type = e.type;
+ r.ownedByCtfe = OwnedBy.ctfe;
+ return ue;
+ }
+ if (auto sle = e.isStructLiteralExp())
+ {
+ /* syntaxCopy doesn't work for struct literals, because of a nasty special
+ * case: block assignment is permitted inside struct literals, eg,
+ * an int[4] array can be initialized with a single int.
+ */
+ auto oldelems = sle.elements;
+ auto newelems = new Expressions(oldelems.dim);
+ foreach (i, ref el; *newelems)
+ {
+ // We need the struct definition to detect block assignment
+ auto v = sle.sd.fields[i];
+ auto m = (*oldelems)[i];
+
+ // If it is a void assignment, use the default initializer
+ if (!m)
+ m = voidInitLiteral(v.type, v).copy();
+
+ if (v.type.ty == Tarray || v.type.ty == Taarray)
+ {
+ // Don't have to copy array references
+ }
+ else
+ {
+ // Buzilla 15681: Copy the source element always.
+ m = copyLiteral(m).copy();
+
+ // Block assignment from inside struct literals
+ if (v.type.ty != m.type.ty && v.type.ty == Tsarray)
+ {
+ auto tsa = v.type.isTypeSArray();
+ auto len = cast(size_t)tsa.dim.toInteger();
+ UnionExp uex = void;
+ m = createBlockDuplicatedArrayLiteral(&uex, e.loc, v.type, m, len);
+ if (m == uex.exp())
+ m = uex.copy();
+ }
+ }
+ el = m;
+ }
+ emplaceExp!(StructLiteralExp)(&ue, e.loc, sle.sd, newelems, sle.stype);
+ auto r = ue.exp().isStructLiteralExp();
+ r.type = e.type;
+ r.ownedByCtfe = OwnedBy.ctfe;
+ r.origin = sle.origin;
+ return ue;
+ }
+ if (e.op == TOK.function_ || e.op == TOK.delegate_ || e.op == TOK.symbolOffset || e.op == TOK.null_ || e.op == TOK.variable || e.op == TOK.dotVariable || e.op == TOK.int64 || e.op == TOK.float64 || e.op == TOK.char_ || e.op == TOK.complex80 || e.op == TOK.void_ || e.op == TOK.vector || e.op == TOK.typeid_)
+ {
+ // Simple value types
+ // Keep e1 for DelegateExp and DotVarExp
+ emplaceExp!(UnionExp)(&ue, e);
+ Expression r = ue.exp();
+ r.type = e.type;
+ return ue;
+ }
+ if (auto se = e.isSliceExp())
+ {
+ if (se.type.toBasetype().ty == Tsarray)
+ {
+ // same with resolveSlice()
+ if (se.e1.op == TOK.null_)
+ {
+ emplaceExp!(NullExp)(&ue, se.loc, se.type);
+ return ue;
+ }
+ ue = Slice(se.type, se.e1, se.lwr, se.upr);
+ auto r = ue.exp().isArrayLiteralExp();
+ r.elements = copyLiteralArray(r.elements);
+ r.ownedByCtfe = OwnedBy.ctfe;
+ return ue;
+ }
+ else
+ {
+ // Array slices only do a shallow copy
+ emplaceExp!(SliceExp)(&ue, e.loc, se.e1, se.lwr, se.upr);
+ Expression r = ue.exp();
+ r.type = e.type;
+ return ue;
+ }
+ }
+ if (isPointer(e.type))
+ {
+ // For pointers, we only do a shallow copy.
+ if (auto ae = e.isAddrExp())
+ emplaceExp!(AddrExp)(&ue, e.loc, ae.e1);
+ else if (auto ie = e.isIndexExp())
+ emplaceExp!(IndexExp)(&ue, e.loc, ie.e1, ie.e2);
+ else if (auto dve = e.isDotVarExp())
+ {
+ emplaceExp!(DotVarExp)(&ue, e.loc, dve.e1, dve.var, dve.hasOverloads);
+ }
+ else
+ assert(0);
+
+ Expression r = ue.exp();
+ r.type = e.type;
+ return ue;
+ }
+ if (auto cre = e.isClassReferenceExp())
+ {
+ emplaceExp!(ClassReferenceExp)(&ue, e.loc, cre.value, e.type);
+ return ue;
+ }
+ if (e.op == TOK.error)
+ {
+ emplaceExp!(UnionExp)(&ue, e);
+ return ue;
+ }
+ e.error("CTFE internal error: literal `%s`", e.toChars());
+ assert(0);
+}
+
+/* Deal with type painting.
+ * Type painting is a major nuisance: we can't just set
+ * e.type = type, because that would change the original literal.
+ * But, we can't simply copy the literal either, because that would change
+ * the values of any pointers.
+ */
+Expression paintTypeOntoLiteral(Type type, Expression lit)
+{
+ if (lit.type.equals(type))
+ return lit;
+ return paintTypeOntoLiteralCopy(type, lit).copy();
+}
+
+Expression paintTypeOntoLiteral(UnionExp* pue, Type type, Expression lit)
+{
+ if (lit.type.equals(type))
+ return lit;
+ *pue = paintTypeOntoLiteralCopy(type, lit);
+ return pue.exp();
+}
+
+private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit)
+{
+ UnionExp ue;
+ if (lit.type.equals(type))
+ {
+ emplaceExp!(UnionExp)(&ue, lit);
+ return ue;
+ }
+ // If it is a cast to inout, retain the original type of the referenced part.
+ if (type.hasWild())
+ {
+ emplaceExp!(UnionExp)(&ue, lit);
+ ue.exp().type = type;
+ return ue;
+ }
+ if (auto se = lit.isSliceExp())
+ {
+ emplaceExp!(SliceExp)(&ue, lit.loc, se.e1, se.lwr, se.upr);
+ }
+ else if (auto ie = lit.isIndexExp())
+ {
+ emplaceExp!(IndexExp)(&ue, lit.loc, ie.e1, ie.e2);
+ }
+ else if (lit.op == TOK.arrayLiteral)
+ {
+ emplaceExp!(SliceExp)(&ue, lit.loc, lit, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy());
+ }
+ else if (lit.op == TOK.string_)
+ {
+ // For strings, we need to introduce another level of indirection
+ emplaceExp!(SliceExp)(&ue, lit.loc, lit, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy());
+ }
+ else if (auto aae = lit.isAssocArrayLiteralExp())
+ {
+ // TODO: we should be creating a reference to this AAExp, not
+ // just a ref to the keys and values.
+ OwnedBy wasOwned = aae.ownedByCtfe;
+ emplaceExp!(AssocArrayLiteralExp)(&ue, lit.loc, aae.keys, aae.values);
+ aae = cast(AssocArrayLiteralExp)ue.exp();
+ aae.ownedByCtfe = wasOwned;
+ }
+ else
+ {
+ // Can't type paint from struct to struct*; this needs another
+ // level of indirection
+ if (lit.op == TOK.structLiteral && isPointer(type))
+ lit.error("CTFE internal error: painting `%s`", type.toChars());
+ ue = copyLiteral(lit);
+ }
+ ue.exp().type = type;
+ return ue;
+}
+
+/*************************************
+ * If e is a SliceExp, constant fold it.
+ * Params:
+ * e = expression to resolve
+ * pue = if not null, store resulting expression here
+ * Returns:
+ * resulting expression
+ */
+Expression resolveSlice(Expression e, UnionExp* pue = null)
+{
+ SliceExp se = e.isSliceExp();
+ if (!se)
+ return e;
+ if (se.e1.op == TOK.null_)
+ return se.e1;
+ if (pue)
+ {
+ *pue = Slice(e.type, se.e1, se.lwr, se.upr);
+ return pue.exp();
+ }
+ else
+ return Slice(e.type, se.e1, se.lwr, se.upr).copy();
+}
+
+/* Determine the array length, without interpreting it.
+ * e must be an array literal, or a slice
+ * It's very wasteful to resolve the slice when we only
+ * need the length.
+ */
+uinteger_t resolveArrayLength(const Expression e)
+{
+ switch (e.op)
+ {
+ case TOK.vector:
+ return e.isVectorExp().dim;
+
+ case TOK.null_:
+ return 0;
+
+ case TOK.slice:
+ {
+ auto se = cast(SliceExp)e;
+ const ilo = se.lwr.toInteger();
+ const iup = se.upr.toInteger();
+ return iup - ilo;
+ }
+
+ case TOK.string_:
+ return e.isStringExp().len;
+
+ case TOK.arrayLiteral:
+ {
+ const ale = e.isArrayLiteralExp();
+ return ale.elements ? ale.elements.dim : 0;
+ }
+
+ case TOK.assocArrayLiteral:
+ {
+ return e.isAssocArrayLiteralExp().keys.dim;
+ }
+
+ default:
+ assert(0);
+ }
+}
+
+/******************************
+ * Helper for NewExp
+ * Create an array literal consisting of 'elem' duplicated 'dim' times.
+ * Params:
+ * pue = where to store result
+ * loc = source location where the interpretation occurs
+ * type = target type of the result
+ * elem = the source of array element, it will be owned by the result
+ * dim = element number of the result
+ * Returns:
+ * Constructed ArrayLiteralExp
+ */
+ArrayLiteralExp createBlockDuplicatedArrayLiteral(UnionExp* pue, const ref Loc loc, Type type, Expression elem, size_t dim)
+{
+ if (type.ty == Tsarray && type.nextOf().ty == Tsarray && elem.type.ty != Tsarray)
+ {
+ // If it is a multidimensional array literal, do it recursively
+ auto tsa = type.nextOf().isTypeSArray();
+ const len = cast(size_t)tsa.dim.toInteger();
+ UnionExp ue = void;
+ elem = createBlockDuplicatedArrayLiteral(&ue, loc, type.nextOf(), elem, len);
+ if (elem == ue.exp())
+ elem = ue.copy();
+ }
+
+ // Buzilla 15681
+ const tb = elem.type.toBasetype();
+ const mustCopy = tb.ty == Tstruct || tb.ty == Tsarray;
+
+ auto elements = new Expressions(dim);
+ foreach (i, ref el; *elements)
+ {
+ el = mustCopy && i ? copyLiteral(elem).copy() : elem;
+ }
+ emplaceExp!(ArrayLiteralExp)(pue, loc, type, elements);
+ auto ale = pue.exp().isArrayLiteralExp();
+ ale.ownedByCtfe = OwnedBy.ctfe;
+ return ale;
+}
+
+/******************************
+ * Helper for NewExp
+ * Create a string literal consisting of 'value' duplicated 'dim' times.
+ */
+StringExp createBlockDuplicatedStringLiteral(UnionExp* pue, const ref Loc loc, Type type, dchar value, size_t dim, ubyte sz)
+{
+ auto s = cast(char*)mem.xcalloc(dim, sz);
+ foreach (elemi; 0 .. dim)
+ {
+ switch (sz)
+ {
+ case 1:
+ s[elemi] = cast(char)value;
+ break;
+ case 2:
+ (cast(wchar*)s)[elemi] = cast(wchar)value;
+ break;
+ case 4:
+ (cast(dchar*)s)[elemi] = value;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ emplaceExp!(StringExp)(pue, loc, s[0 .. dim * sz], dim, sz);
+ auto se = pue.exp().isStringExp();
+ se.type = type;
+ se.committed = true;
+ se.ownedByCtfe = OwnedBy.ctfe;
+ return se;
+}
+
+// Return true if t is an AA
+bool isAssocArray(Type t)
+{
+ return t.toBasetype().isTypeAArray() !is null;
+}
+
+// Given a template AA type, extract the corresponding built-in AA type
+TypeAArray toBuiltinAAType(Type t)
+{
+ return t.toBasetype().isTypeAArray();
+}
+
+/************** TypeInfo operations ************************************/
+// Return true if type is TypeInfo_Class
+bool isTypeInfo_Class(const Type type)
+{
+ auto tc = cast()type.isTypeClass();
+ return tc && (Type.dtypeinfo == tc.sym || Type.dtypeinfo.isBaseOf(tc.sym, null));
+}
+
+/************** Pointer operations ************************************/
+// Return true if t is a pointer (not a function pointer)
+bool isPointer(Type t)
+{
+ Type tb = t.toBasetype();
+ return tb.ty == Tpointer && tb.nextOf().ty != Tfunction;
+}
+
+// For CTFE only. Returns true if 'e' is true or a non-null pointer.
+bool isTrueBool(Expression e)
+{
+ return e.isBool(true) || ((e.type.ty == Tpointer || e.type.ty == Tclass) && e.op != TOK.null_);
+}
+
+/* Is it safe to convert from srcPointee* to destPointee* ?
+ * srcPointee is the genuine type (never void).
+ * destPointee may be void.
+ */
+bool isSafePointerCast(Type srcPointee, Type destPointee)
+{
+ // It's safe to cast S** to D** if it's OK to cast S* to D*
+ while (srcPointee.ty == Tpointer && destPointee.ty == Tpointer)
+ {
+ srcPointee = srcPointee.nextOf();
+ destPointee = destPointee.nextOf();
+ }
+ // It's OK if both are the same (modulo const)
+ if (srcPointee.constConv(destPointee))
+ return true;
+ // It's OK if function pointers differ only in safe/pure/nothrow
+ if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction)
+ return srcPointee.covariant(destPointee) == Covariant.yes ||
+ destPointee.covariant(srcPointee) == Covariant.yes;
+ // it's OK to cast to void*
+ if (destPointee.ty == Tvoid)
+ return true;
+ // It's OK to cast from V[K] to void*
+ if (srcPointee.ty == Taarray && destPointee == Type.tvoidptr)
+ return true;
+ // It's OK if they are the same size (static array of) integers, eg:
+ // int* --> uint*
+ // int[5][] --> uint[5][]
+ if (srcPointee.ty == Tsarray && destPointee.ty == Tsarray)
+ {
+ if (srcPointee.size() != destPointee.size())
+ return false;
+ srcPointee = srcPointee.baseElemOf();
+ destPointee = destPointee.baseElemOf();
+ }
+ return srcPointee.isintegral() && destPointee.isintegral() && srcPointee.size() == destPointee.size();
+}
+
+Expression getAggregateFromPointer(Expression e, dinteger_t* ofs)
+{
+ *ofs = 0;
+ if (auto ae = e.isAddrExp())
+ e = ae.e1;
+ if (auto soe = e.isSymOffExp())
+ *ofs = soe.offset;
+ if (auto dve = e.isDotVarExp())
+ {
+ const ex = dve.e1;
+ const v = dve.var.isVarDeclaration();
+ assert(v);
+ StructLiteralExp se = (ex.op == TOK.classReference)
+ ? (cast(ClassReferenceExp)ex).value
+ : cast(StructLiteralExp)ex;
+
+ // We can't use getField, because it makes a copy
+ const i = (ex.op == TOK.classReference)
+ ? (cast(ClassReferenceExp)ex).getFieldIndex(e.type, v.offset)
+ : se.getFieldIndex(e.type, v.offset);
+ e = (*se.elements)[i];
+ }
+ if (auto ie = e.isIndexExp())
+ {
+ // Note that each AA element is part of its own memory block
+ if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == TOK.string_ || ie.e1.op == TOK.arrayLiteral) && ie.e2.op == TOK.int64)
+ {
+ *ofs = ie.e2.toInteger();
+ return ie.e1;
+ }
+ }
+ if (auto se = e.isSliceExp())
+ {
+ if (se && e.type.toBasetype().ty == Tsarray &&
+ (se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == TOK.string_ || se.e1.op == TOK.arrayLiteral) && se.lwr.op == TOK.int64)
+ {
+ *ofs = se.lwr.toInteger();
+ return se.e1;
+ }
+ }
+
+ // It can be a `null` disguised as a cast, e.g. `cast(void*)0`.
+ if (auto ie = e.isIntegerExp())
+ if (ie.type.ty == Tpointer && ie.getInteger() == 0)
+ return new NullExp(ie.loc, e.type.nextOf());
+ // Those casts are invalid, but let the rest of the code handle it,
+ // as it could be something like `x !is null`, which doesn't need
+ // to dereference the pointer, even if the pointer is `cast(void*)420`.
+
+ return e;
+}
+
+/** Return true if agg1 and agg2 are pointers to the same memory block
+ */
+bool pointToSameMemoryBlock(Expression agg1, Expression agg2)
+{
+ if (agg1 == agg2)
+ return true;
+ // For integers cast to pointers, we regard them as non-comparable
+ // unless they are identical. (This may be overly strict).
+ if (agg1.op == TOK.int64 && agg2.op == TOK.int64 && agg1.toInteger() == agg2.toInteger())
+ {
+ return true;
+ }
+ // Note that type painting can occur with VarExp, so we
+ // must compare the variables being pointed to.
+ if (agg1.op == TOK.variable && agg2.op == TOK.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)
+ {
+ return true;
+ }
+ if (agg1.op == TOK.symbolOffset && agg2.op == TOK.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
+ {
+ return true;
+ }
+ return false;
+}
+
+// return e1 - e2 as an integer, or error if not possible
+UnionExp pointerDifference(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ UnionExp ue = void;
+ dinteger_t ofs1, ofs2;
+ Expression agg1 = getAggregateFromPointer(e1, &ofs1);
+ Expression agg2 = getAggregateFromPointer(e2, &ofs2);
+ if (agg1 == agg2)
+ {
+ Type pointee = (cast(TypePointer)agg1.type).next;
+ const sz = pointee.size();
+ emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type);
+ }
+ else if (agg1.op == TOK.string_ && agg2.op == TOK.string_ &&
+ (cast(StringExp)agg1).peekString().ptr == (cast(StringExp)agg2).peekString().ptr)
+ {
+ Type pointee = (cast(TypePointer)agg1.type).next;
+ const sz = pointee.size();
+ emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type);
+ }
+ else if (agg1.op == TOK.symbolOffset && agg2.op == TOK.symbolOffset &&
+ (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
+ {
+ emplaceExp!(IntegerExp)(&ue, loc, ofs1 - ofs2, type);
+ }
+ else
+ {
+ error(loc, "`%s - %s` cannot be interpreted at compile time: cannot subtract pointers to two different memory blocks", e1.toChars(), e2.toChars());
+ emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+ }
+ return ue;
+}
+
+// Return eptr op e2, where eptr is a pointer, e2 is an integer,
+// and op is TOK.add or TOK.min
+UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr, Expression e2)
+{
+ UnionExp ue;
+ if (eptr.type.nextOf().ty == Tvoid)
+ {
+ error(loc, "cannot perform arithmetic on `void*` pointers at compile time");
+ Lcant:
+ emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+ return ue;
+ }
+ if (eptr.op == TOK.address)
+ eptr = (cast(AddrExp)eptr).e1;
+ dinteger_t ofs1;
+ Expression agg1 = getAggregateFromPointer(eptr, &ofs1);
+ if (agg1.op == TOK.symbolOffset)
+ {
+ if ((cast(SymOffExp)agg1).var.type.ty != Tsarray)
+ {
+ error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time");
+ goto Lcant;
+ }
+ }
+ else if (agg1.op != TOK.string_ && agg1.op != TOK.arrayLiteral)
+ {
+ error(loc, "cannot perform pointer arithmetic on non-arrays at compile time");
+ goto Lcant;
+ }
+ dinteger_t ofs2 = e2.toInteger();
+ Type pointee = (cast(TypeNext)agg1.type.toBasetype()).next;
+ dinteger_t sz = pointee.size();
+ sinteger_t indx;
+ dinteger_t len;
+ if (agg1.op == TOK.symbolOffset)
+ {
+ indx = ofs1 / sz;
+ len = (cast(TypeSArray)(cast(SymOffExp)agg1).var.type).dim.toInteger();
+ }
+ else
+ {
+ Expression dollar = ArrayLength(Type.tsize_t, agg1).copy();
+ assert(!CTFEExp.isCantExp(dollar));
+ indx = ofs1;
+ len = dollar.toInteger();
+ }
+ if (op == TOK.add || op == TOK.addAssign || op == TOK.plusPlus)
+ indx += ofs2 / sz;
+ else if (op == TOK.min || op == TOK.minAssign || op == TOK.minusMinus)
+ indx -= ofs2 / sz;
+ else
+ {
+ error(loc, "CTFE internal error: bad pointer operation");
+ goto Lcant;
+ }
+ if (indx < 0 || len < indx)
+ {
+ error(loc, "cannot assign pointer to index %lld inside memory block `[0..%lld]`", indx, len);
+ goto Lcant;
+ }
+ if (agg1.op == TOK.symbolOffset)
+ {
+ emplaceExp!(SymOffExp)(&ue, loc, (cast(SymOffExp)agg1).var, indx * sz);
+ SymOffExp se = cast(SymOffExp)ue.exp();
+ se.type = type;
+ return ue;
+ }
+ if (agg1.op != TOK.arrayLiteral && agg1.op != TOK.string_)
+ {
+ error(loc, "CTFE internal error: pointer arithmetic `%s`", agg1.toChars());
+ goto Lcant;
+ }
+ if (eptr.type.toBasetype().ty == Tsarray)
+ {
+ dinteger_t dim = (cast(TypeSArray)eptr.type.toBasetype()).dim.toInteger();
+ // Create a CTFE pointer &agg1[indx .. indx+dim]
+ auto se = ctfeEmplaceExp!SliceExp(loc, agg1,
+ ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t),
+ ctfeEmplaceExp!IntegerExp(loc, indx + dim, Type.tsize_t));
+ se.type = type.toBasetype().nextOf();
+ emplaceExp!(AddrExp)(&ue, loc, se);
+ ue.exp().type = type;
+ return ue;
+ }
+ // Create a CTFE pointer &agg1[indx]
+ auto ofs = ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t);
+ Expression ie = ctfeEmplaceExp!IndexExp(loc, agg1, ofs);
+ ie.type = type.toBasetype().nextOf(); // https://issues.dlang.org/show_bug.cgi?id=13992
+ emplaceExp!(AddrExp)(&ue, loc, ie);
+ ue.exp().type = type;
+ return ue;
+}
+
+// Return 1 if true, 0 if false
+// -1 if comparison is illegal because they point to non-comparable memory blocks
+int comparePointers(TOK op, Expression agg1, dinteger_t ofs1, Expression agg2, dinteger_t ofs2)
+{
+ if (pointToSameMemoryBlock(agg1, agg2))
+ {
+ int n;
+ switch (op)
+ {
+ case TOK.lessThan:
+ n = (ofs1 < ofs2);
+ break;
+ case TOK.lessOrEqual:
+ n = (ofs1 <= ofs2);
+ break;
+ case TOK.greaterThan:
+ n = (ofs1 > ofs2);
+ break;
+ case TOK.greaterOrEqual:
+ n = (ofs1 >= ofs2);
+ break;
+ case TOK.identity:
+ case TOK.equal:
+ n = (ofs1 == ofs2);
+ break;
+ case TOK.notIdentity:
+ case TOK.notEqual:
+ n = (ofs1 != ofs2);
+ break;
+ default:
+ assert(0);
+ }
+ return n;
+ }
+ const null1 = (agg1.op == TOK.null_);
+ const null2 = (agg2.op == TOK.null_);
+ int cmp;
+ if (null1 || null2)
+ {
+ switch (op)
+ {
+ case TOK.lessThan:
+ cmp = null1 && !null2;
+ break;
+ case TOK.greaterThan:
+ cmp = !null1 && null2;
+ break;
+ case TOK.lessOrEqual:
+ cmp = null1;
+ break;
+ case TOK.greaterOrEqual:
+ cmp = null2;
+ break;
+ case TOK.identity:
+ case TOK.equal:
+ case TOK.notIdentity: // 'cmp' gets inverted below
+ case TOK.notEqual:
+ cmp = (null1 == null2);
+ break;
+ default:
+ assert(0);
+ }
+ }
+ else
+ {
+ switch (op)
+ {
+ case TOK.identity:
+ case TOK.equal:
+ case TOK.notIdentity: // 'cmp' gets inverted below
+ case TOK.notEqual:
+ cmp = 0;
+ break;
+ default:
+ return -1; // memory blocks are different
+ }
+ }
+ if (op == TOK.notIdentity || op == TOK.notEqual)
+ cmp ^= 1;
+ return cmp;
+}
+
+// True if conversion from type 'from' to 'to' involves a reinterpret_cast
+// floating point -> integer or integer -> floating point
+bool isFloatIntPaint(Type to, Type from)
+{
+ return from.size() == to.size() && (from.isintegral() && to.isfloating() || from.isfloating() && to.isintegral());
+}
+
+// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
+Expression paintFloatInt(UnionExp* pue, Expression fromVal, Type to)
+{
+ if (exceptionOrCantInterpret(fromVal))
+ return fromVal;
+ assert(to.size() == 4 || to.size() == 8);
+ return Compiler.paintAsType(pue, fromVal, to);
+}
+
+/******** Constant folding, with support for CTFE ***************************/
+/// Return true if non-pointer expression e can be compared
+/// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity
+bool isCtfeComparable(Expression e)
+{
+ if (e.op == TOK.slice)
+ e = (cast(SliceExp)e).e1;
+ if (e.isConst() != 1)
+ {
+ if (e.op == TOK.null_ || e.op == TOK.string_ || e.op == TOK.function_ || e.op == TOK.delegate_ || e.op == TOK.arrayLiteral || e.op == TOK.structLiteral || e.op == TOK.assocArrayLiteral || e.op == TOK.classReference)
+ {
+ return true;
+ }
+ // https://issues.dlang.org/show_bug.cgi?id=14123
+ // TypeInfo object is comparable in CTFE
+ if (e.op == TOK.typeid_)
+ return true;
+ return false;
+ }
+ return true;
+}
+
+/// Map TOK comparison ops
+private bool numCmp(N)(TOK op, N n1, N n2)
+{
+ switch (op)
+ {
+ case TOK.lessThan:
+ return n1 < n2;
+ case TOK.lessOrEqual:
+ return n1 <= n2;
+ case TOK.greaterThan:
+ return n1 > n2;
+ case TOK.greaterOrEqual:
+ return n1 >= n2;
+
+ default:
+ assert(0);
+ }
+}
+
+/// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+bool specificCmp(TOK op, int rawCmp)
+{
+ return numCmp!int(op, rawCmp, 0);
+}
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+bool intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2)
+{
+ return numCmp!dinteger_t(op, n1, n2);
+}
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+bool intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2)
+{
+ return numCmp!sinteger_t(op, n1, n2);
+}
+
+/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
+bool realCmp(TOK op, real_t r1, real_t r2)
+{
+ // Don't rely on compiler, handle NAN arguments separately
+ if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
+ {
+ switch (op)
+ {
+ case TOK.lessThan:
+ case TOK.lessOrEqual:
+ case TOK.greaterThan:
+ case TOK.greaterOrEqual:
+ return false;
+
+ default:
+ assert(0);
+ }
+ }
+ else
+ {
+ return numCmp!real_t(op, r1, r2);
+ }
+}
+
+/* Conceptually the same as memcmp(e1, e2).
+ * e1 and e2 may be strings, arrayliterals, or slices.
+ * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
+ * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
+ * Returns:
+ * -1,0,1
+ */
+private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinteger_t len)
+{
+ // Resolve slices, if necessary
+ uinteger_t lo1 = 0;
+ uinteger_t lo2 = 0;
+
+ Expression x1 = e1;
+ if (auto sle1 = x1.isSliceExp())
+ {
+ lo1 = sle1.lwr.toInteger();
+ x1 = sle1.e1;
+ }
+ auto se1 = x1.isStringExp();
+ auto ae1 = x1.isArrayLiteralExp();
+
+ Expression x2 = e2;
+ if (auto sle2 = x2.isSliceExp())
+ {
+ lo2 = sle2.lwr.toInteger();
+ x2 = sle2.e1;
+ }
+ auto se2 = x2.isStringExp();
+ auto ae2 = x2.isArrayLiteralExp();
+
+ // Now both must be either TOK.arrayLiteral or TOK.string_
+ if (se1 && se2)
+ return sliceCmpStringWithString(se1, se2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len);
+ if (se1 && ae2)
+ return sliceCmpStringWithArray(se1, ae2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len);
+ if (se2 && ae1)
+ return -sliceCmpStringWithArray(se2, ae1, cast(size_t)lo2, cast(size_t)lo1, cast(size_t)len);
+ assert(ae1 && ae2);
+ // Comparing two array literals. This case is potentially recursive.
+ // If they aren't strings, we just need an equality check rather than
+ // a full cmp.
+ const bool needCmp = ae1.type.nextOf().isintegral();
+ foreach (size_t i; 0 .. cast(size_t)len)
+ {
+ Expression ee1 = (*ae1.elements)[cast(size_t)(lo1 + i)];
+ Expression ee2 = (*ae2.elements)[cast(size_t)(lo2 + i)];
+ if (needCmp)
+ {
+ const sinteger_t c = ee1.toInteger() - ee2.toInteger();
+ if (c > 0)
+ return 1;
+ if (c < 0)
+ return -1;
+ }
+ else
+ {
+ if (ctfeRawCmp(loc, ee1, ee2))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Given a delegate expression e, return .funcptr.
+ * If e is NullExp, return NULL.
+ */
+private FuncDeclaration funcptrOf(Expression e)
+{
+ assert(e.type.ty == Tdelegate);
+ if (auto de = e.isDelegateExp())
+ return de.func;
+ if (auto fe = e.isFuncExp())
+ return fe.fd;
+ assert(e.op == TOK.null_);
+ return null;
+}
+
+private bool isArray(const Expression e)
+{
+ return e.op == TOK.arrayLiteral || e.op == TOK.string_ || e.op == TOK.slice || e.op == TOK.null_;
+}
+
+/*****
+ * Params:
+ * loc = source file location
+ * e1 = left operand
+ * e2 = right operand
+ * identity = true for `is` identity comparisons
+ * Returns:
+ * For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
+ * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
+ */
+private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool identity = false)
+{
+ if (e1.op == TOK.classReference || e2.op == TOK.classReference)
+ {
+ if (e1.op == TOK.classReference && e2.op == TOK.classReference &&
+ (cast(ClassReferenceExp)e1).value == (cast(ClassReferenceExp)e2).value)
+ return 0;
+ return 1;
+ }
+ if (e1.op == TOK.typeid_ && e2.op == TOK.typeid_)
+ {
+ // printf("e1: %s\n", e1.toChars());
+ // printf("e2: %s\n", e2.toChars());
+ Type t1 = isType((cast(TypeidExp)e1).obj);
+ Type t2 = isType((cast(TypeidExp)e2).obj);
+ assert(t1);
+ assert(t2);
+ return t1 != t2;
+ }
+ // null == null, regardless of type
+ if (e1.op == TOK.null_ && e2.op == TOK.null_)
+ return 0;
+ if (e1.type.ty == Tpointer && e2.type.ty == Tpointer)
+ {
+ // Can only be an equality test.
+ dinteger_t ofs1, ofs2;
+ Expression agg1 = getAggregateFromPointer(e1, &ofs1);
+ Expression agg2 = getAggregateFromPointer(e2, &ofs2);
+ if ((agg1 == agg2) || (agg1.op == TOK.variable && agg2.op == TOK.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
+ {
+ if (ofs1 == ofs2)
+ return 0;
+ }
+ return 1;
+ }
+ if (e1.type.ty == Tdelegate && e2.type.ty == Tdelegate)
+ {
+ // If .funcptr isn't the same, they are not equal
+ if (funcptrOf(e1) != funcptrOf(e2))
+ return 1;
+ // If both are delegate literals, assume they have the
+ // same closure pointer. TODO: We don't support closures yet!
+ if (e1.op == TOK.function_ && e2.op == TOK.function_)
+ return 0;
+ assert(e1.op == TOK.delegate_ && e2.op == TOK.delegate_);
+ // Same .funcptr. Do they have the same .ptr?
+ Expression ptr1 = (cast(DelegateExp)e1).e1;
+ Expression ptr2 = (cast(DelegateExp)e2).e1;
+ dinteger_t ofs1, ofs2;
+ Expression agg1 = getAggregateFromPointer(ptr1, &ofs1);
+ Expression agg2 = getAggregateFromPointer(ptr2, &ofs2);
+ // If they are TOK.variable, it means they are FuncDeclarations
+ if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == TOK.variable && agg2.op == TOK.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
+ {
+ return 0;
+ }
+ return 1;
+ }
+ if (isArray(e1) && isArray(e2))
+ {
+ const uinteger_t len1 = resolveArrayLength(e1);
+ const uinteger_t len2 = resolveArrayLength(e2);
+ // workaround for dmc optimizer bug calculating wrong len for
+ // uinteger_t len = (len1 < len2 ? len1 : len2);
+ // if (len == 0) ...
+ if (len1 > 0 && len2 > 0)
+ {
+ const uinteger_t len = (len1 < len2 ? len1 : len2);
+ const int res = ctfeCmpArrays(loc, e1, e2, len);
+ if (res != 0)
+ return res;
+ }
+ return cast(int)(len1 - len2);
+ }
+ if (e1.type.isintegral())
+ {
+ return e1.toInteger() != e2.toInteger();
+ }
+ if (e1.type.isreal() || e1.type.isimaginary())
+ {
+ real_t r1 = e1.type.isreal() ? e1.toReal() : e1.toImaginary();
+ real_t r2 = e1.type.isreal() ? e2.toReal() : e2.toImaginary();
+ if (identity)
+ return !RealIdentical(r1, r2);
+ if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
+ {
+ return 1; // they are not equal
+ }
+ else
+ {
+ return (r1 != r2);
+ }
+ }
+ else if (e1.type.iscomplex())
+ {
+ auto c1 = e1.toComplex();
+ auto c2 = e2.toComplex();
+ if (identity)
+ {
+ return !RealIdentical(c1.re, c2.re) && !RealIdentical(c1.im, c2.im);
+ }
+ return c1 != c2;
+ }
+ if (e1.op == TOK.structLiteral && e2.op == TOK.structLiteral)
+ {
+ StructLiteralExp es1 = cast(StructLiteralExp)e1;
+ StructLiteralExp es2 = cast(StructLiteralExp)e2;
+ // For structs, we only need to return 0 or 1 (< and > aren't legal).
+ if (es1.sd != es2.sd)
+ return 1;
+ else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
+ return 0; // both arrays are empty
+ else if (!es1.elements || !es2.elements)
+ return 1;
+ else if (es1.elements.dim != es2.elements.dim)
+ return 1;
+ else
+ {
+ foreach (size_t i; 0 .. es1.elements.dim)
+ {
+ Expression ee1 = (*es1.elements)[i];
+ Expression ee2 = (*es2.elements)[i];
+
+ // https://issues.dlang.org/show_bug.cgi?id=16284
+ if (ee1.op == TOK.void_ && ee2.op == TOK.void_) // if both are VoidInitExp
+ continue;
+
+ if (ee1 == ee2)
+ continue;
+ if (!ee1 || !ee2)
+ return 1;
+ const int cmp = ctfeRawCmp(loc, ee1, ee2, identity);
+ if (cmp)
+ return 1;
+ }
+ return 0; // All elements are equal
+ }
+ }
+ if (e1.op == TOK.assocArrayLiteral && e2.op == TOK.assocArrayLiteral)
+ {
+ AssocArrayLiteralExp es1 = cast(AssocArrayLiteralExp)e1;
+ AssocArrayLiteralExp es2 = cast(AssocArrayLiteralExp)e2;
+ size_t dim = es1.keys.dim;
+ if (es2.keys.dim != dim)
+ return 1;
+ bool* used = cast(bool*)mem.xmalloc(bool.sizeof * dim);
+ memset(used, 0, bool.sizeof * dim);
+ foreach (size_t i; 0 .. dim)
+ {
+ Expression k1 = (*es1.keys)[i];
+ Expression v1 = (*es1.values)[i];
+ Expression v2 = null;
+ foreach (size_t j; 0 .. dim)
+ {
+ if (used[j])
+ continue;
+ Expression k2 = (*es2.keys)[j];
+ if (ctfeRawCmp(loc, k1, k2, identity))
+ continue;
+ used[j] = true;
+ v2 = (*es2.values)[j];
+ break;
+ }
+ if (!v2 || ctfeRawCmp(loc, v1, v2, identity))
+ {
+ mem.xfree(used);
+ return 1;
+ }
+ }
+ mem.xfree(used);
+ return 0;
+ }
+ error(loc, "CTFE internal error: bad compare of `%s` and `%s`", e1.toChars(), e2.toChars());
+ assert(0);
+}
+
+/// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1
+bool ctfeEqual(const ref Loc loc, TOK op, Expression e1, Expression e2)
+{
+ return !ctfeRawCmp(loc, e1, e2) ^ (op == TOK.notEqual);
+}
+
+/// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1
+bool ctfeIdentity(const ref Loc loc, TOK op, Expression e1, Expression e2)
+{
+ //printf("ctfeIdentity %s %s\n", e1.toChars(), e2.toChars());
+ //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", Token::toChars(op),
+ // Token::toChars(e1.op), e1.toChars(), Token::toChars(e2.op), e1.toChars());
+ bool cmp;
+ if (e1.op == TOK.null_)
+ {
+ cmp = (e2.op == TOK.null_);
+ }
+ else if (e2.op == TOK.null_)
+ {
+ cmp = false;
+ }
+ else if (e1.op == TOK.symbolOffset && e2.op == TOK.symbolOffset)
+ {
+ SymOffExp es1 = cast(SymOffExp)e1;
+ SymOffExp es2 = cast(SymOffExp)e2;
+ cmp = (es1.var == es2.var && es1.offset == es2.offset);
+ }
+ else if (e1.type.isreal())
+ cmp = RealIdentical(e1.toReal(), e2.toReal());
+ else if (e1.type.isimaginary())
+ cmp = RealIdentical(e1.toImaginary(), e2.toImaginary());
+ else if (e1.type.iscomplex())
+ {
+ complex_t v1 = e1.toComplex();
+ complex_t v2 = e2.toComplex();
+ cmp = RealIdentical(creall(v1), creall(v2)) && RealIdentical(cimagl(v1), cimagl(v1));
+ }
+ else
+ {
+ cmp = !ctfeRawCmp(loc, e1, e2, true);
+ }
+ if (op == TOK.notIdentity || op == TOK.notEqual)
+ cmp ^= true;
+ return cmp;
+}
+
+/// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
+bool ctfeCmp(const ref Loc loc, TOK op, Expression e1, Expression e2)
+{
+ Type t1 = e1.type.toBasetype();
+ Type t2 = e2.type.toBasetype();
+
+ if (t1.isString() && t2.isString())
+ return specificCmp(op, ctfeRawCmp(loc, e1, e2));
+ else if (t1.isreal())
+ return realCmp(op, e1.toReal(), e2.toReal());
+ else if (t1.isimaginary())
+ return realCmp(op, e1.toImaginary(), e2.toImaginary());
+ else if (t1.isunsigned() || t2.isunsigned())
+ return intUnsignedCmp(op, e1.toInteger(), e2.toInteger());
+ else
+ return intSignedCmp(op, e1.toInteger(), e2.toInteger());
+}
+
+UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
+{
+ Type t1 = e1.type.toBasetype();
+ Type t2 = e2.type.toBasetype();
+ UnionExp ue;
+ if (e2.op == TOK.string_ && e1.op == TOK.arrayLiteral && t1.nextOf().isintegral())
+ {
+ // [chars] ~ string => string (only valid for CTFE)
+ StringExp es1 = cast(StringExp)e2;
+ ArrayLiteralExp es2 = cast(ArrayLiteralExp)e1;
+ const len = es1.len + es2.elements.dim;
+ const sz = es1.sz;
+ void* s = mem.xmalloc((len + 1) * sz);
+ const data1 = es1.peekData();
+ memcpy(cast(char*)s + sz * es2.elements.dim, data1.ptr, data1.length);
+ foreach (size_t i; 0 .. es2.elements.dim)
+ {
+ Expression es2e = (*es2.elements)[i];
+ if (es2e.op != TOK.int64)
+ {
+ emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+ return ue;
+ }
+ dinteger_t v = es2e.toInteger();
+ Port.valcpy(cast(char*)s + i * sz, v, sz);
+ }
+ // Add terminating 0
+ memset(cast(char*)s + len * sz, 0, sz);
+ emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
+ StringExp es = cast(StringExp)ue.exp();
+ es.committed = 0;
+ es.type = type;
+ return ue;
+ }
+ if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral && t2.nextOf().isintegral())
+ {
+ // string ~ [chars] => string (only valid for CTFE)
+ // Concatenate the strings
+ StringExp es1 = cast(StringExp)e1;
+ ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+ const len = es1.len + es2.elements.dim;
+ const sz = es1.sz;
+ void* s = mem.xmalloc((len + 1) * sz);
+ auto slice = es1.peekData();
+ memcpy(s, slice.ptr, slice.length);
+ foreach (size_t i; 0 .. es2.elements.dim)
+ {
+ Expression es2e = (*es2.elements)[i];
+ if (es2e.op != TOK.int64)
+ {
+ emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+ return ue;
+ }
+ const v = es2e.toInteger();
+ Port.valcpy(cast(char*)s + (es1.len + i) * sz, v, sz);
+ }
+ // Add terminating 0
+ memset(cast(char*)s + len * sz, 0, sz);
+ emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
+ StringExp es = cast(StringExp)ue.exp();
+ es.sz = sz;
+ es.committed = 0; //es1.committed;
+ es.type = type;
+ return ue;
+ }
+ if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
+ {
+ // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
+ ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
+ ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+ emplaceExp!(ArrayLiteralExp)(&ue, es1.loc, type, copyLiteralArray(es1.elements));
+ es1 = cast(ArrayLiteralExp)ue.exp();
+ es1.elements.insert(es1.elements.dim, copyLiteralArray(es2.elements));
+ return ue;
+ }
+ if (e1.op == TOK.arrayLiteral && e2.op == TOK.null_ && t1.nextOf().equals(t2.nextOf()))
+ {
+ // [ e1 ] ~ null ----> [ e1 ].dup
+ ue = paintTypeOntoLiteralCopy(type, copyLiteral(e1).copy());
+ return ue;
+ }
+ if (e1.op == TOK.null_ && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
+ {
+ // null ~ [ e2 ] ----> [ e2 ].dup
+ ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy());
+ return ue;
+ }
+ ue = Cat(loc, type, e1, e2);
+ return ue;
+}
+
+/* Given an AA literal 'ae', and a key 'e2':
+ * Return ae[e2] if present, or NULL if not found.
+ */
+Expression findKeyInAA(const ref Loc loc, AssocArrayLiteralExp ae, Expression e2)
+{
+ /* Search the keys backwards, in case there are duplicate keys
+ */
+ for (size_t i = ae.keys.dim; i;)
+ {
+ --i;
+ Expression ekey = (*ae.keys)[i];
+ const int eq = ctfeEqual(loc, TOK.equal, ekey, e2);
+ if (eq)
+ {
+ return (*ae.values)[i];
+ }
+ }
+ return null;
+}
+
+/* Same as for constfold.Index, except that it only works for static arrays,
+ * dynamic arrays, and strings. We know that e1 is an
+ * interpreted CTFE expression, so it cannot have side-effects.
+ */
+Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1, uinteger_t indx)
+{
+ //printf("ctfeIndex(e1 = %s)\n", e1.toChars());
+ assert(e1.type);
+ if (auto es1 = e1.isStringExp())
+ {
+ if (indx >= es1.len)
+ {
+ error(loc, "string index %llu is out of bounds `[0 .. %zu]`", indx, es1.len);
+ return CTFEExp.cantexp;
+ }
+ emplaceExp!IntegerExp(pue, loc, es1.charAt(indx), type);
+ return pue.exp();
+ }
+
+ if (auto ale = e1.isArrayLiteralExp())
+ {
+ if (indx >= ale.elements.dim)
+ {
+ error(loc, "array index %llu is out of bounds `%s[0 .. %zu]`", indx, e1.toChars(), ale.elements.dim);
+ return CTFEExp.cantexp;
+ }
+ Expression e = (*ale.elements)[cast(size_t)indx];
+ return paintTypeOntoLiteral(pue, type, e);
+ }
+
+ assert(0);
+}
+
+Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expression e)
+{
+ Expression paint()
+ {
+ return paintTypeOntoLiteral(pue, to, e);
+ }
+
+ if (e.op == TOK.null_)
+ return paint();
+
+ if (e.op == TOK.classReference)
+ {
+ // Disallow reinterpreting class casts. Do this by ensuring that
+ // the original class can implicitly convert to the target class
+ ClassDeclaration originalClass = (cast(ClassReferenceExp)e).originalClass();
+ if (originalClass.type.implicitConvTo(to.mutableOf()))
+ return paint();
+ else
+ {
+ emplaceExp!(NullExp)(pue, loc, to);
+ return pue.exp();
+ }
+ }
+
+ // Allow TypeInfo type painting
+ if (isTypeInfo_Class(e.type) && e.type.implicitConvTo(to))
+ return paint();
+
+ // Allow casting away const for struct literals
+ if (e.op == TOK.structLiteral && e.type.toBasetype().castMod(0) == to.toBasetype().castMod(0))
+ return paint();
+
+ Expression r;
+ if (e.type.equals(type) && type.equals(to))
+ {
+ // necessary not to change e's address for pointer comparisons
+ r = e;
+ }
+ else if (to.toBasetype().ty == Tarray &&
+ type.toBasetype().ty == Tarray &&
+ to.toBasetype().nextOf().size() == type.toBasetype().nextOf().size())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=12495
+ // Array reinterpret casts: eg. string to immutable(ubyte)[]
+ return paint();
+ }
+ else
+ {
+ *pue = Cast(loc, type, to, e);
+ r = pue.exp();
+ }
+
+ if (CTFEExp.isCantExp(r))
+ error(loc, "cannot cast `%s` to `%s` at compile time", e.toChars(), to.toChars());
+
+ if (auto ae = e.isArrayLiteralExp())
+ ae.ownedByCtfe = OwnedBy.ctfe;
+
+ if (auto se = e.isStringExp())
+ se.ownedByCtfe = OwnedBy.ctfe;
+
+ return r;
+}
+
+/******** Assignment helper functions ***************************/
+/* Set dest = src, where both dest and src are container value literals
+ * (ie, struct literals, or static arrays (can be an array literal or a string))
+ * Assignment is recursively in-place.
+ * Purpose: any reference to a member of 'dest' will remain valid after the
+ * assignment.
+ */
+void assignInPlace(Expression dest, Expression src)
+{
+ if (!(dest.op == TOK.structLiteral || dest.op == TOK.arrayLiteral || dest.op == TOK.string_))
+ {
+ printf("invalid op %d %d\n", src.op, dest.op);
+ assert(0);
+ }
+ Expressions* oldelems;
+ Expressions* newelems;
+ if (dest.op == TOK.structLiteral)
+ {
+ assert(dest.op == src.op);
+ oldelems = (cast(StructLiteralExp)dest).elements;
+ newelems = (cast(StructLiteralExp)src).elements;
+ auto sd = (cast(StructLiteralExp)dest).sd;
+ const nfields = sd.nonHiddenFields();
+ const nvthis = sd.fields.dim - nfields;
+ if (nvthis && oldelems.dim >= nfields && oldelems.dim < newelems.dim)
+ foreach (_; 0 .. newelems.dim - oldelems.dim)
+ oldelems.push(null);
+ }
+ else if (dest.op == TOK.arrayLiteral && src.op == TOK.arrayLiteral)
+ {
+ oldelems = (cast(ArrayLiteralExp)dest).elements;
+ newelems = (cast(ArrayLiteralExp)src).elements;
+ }
+ else if (dest.op == TOK.string_ && src.op == TOK.string_)
+ {
+ sliceAssignStringFromString(cast(StringExp)dest, cast(StringExp)src, 0);
+ return;
+ }
+ else if (dest.op == TOK.arrayLiteral && src.op == TOK.string_)
+ {
+ sliceAssignArrayLiteralFromString(cast(ArrayLiteralExp)dest, cast(StringExp)src, 0);
+ return;
+ }
+ else if (src.op == TOK.arrayLiteral && dest.op == TOK.string_)
+ {
+ sliceAssignStringFromArrayLiteral(cast(StringExp)dest, cast(ArrayLiteralExp)src, 0);
+ return;
+ }
+ else
+ {
+ printf("invalid op %d %d\n", src.op, dest.op);
+ assert(0);
+ }
+ assert(oldelems.dim == newelems.dim);
+ foreach (size_t i; 0 .. oldelems.dim)
+ {
+ Expression e = (*newelems)[i];
+ Expression o = (*oldelems)[i];
+ if (e.op == TOK.structLiteral)
+ {
+ assert(o.op == e.op);
+ assignInPlace(o, e);
+ }
+ else if (e.type.ty == Tsarray && e.op != TOK.void_ && o.type.ty == Tsarray)
+ {
+ assignInPlace(o, e);
+ }
+ else
+ {
+ (*oldelems)[i] = (*newelems)[i];
+ }
+ }
+}
+
+// Given an AA literal aae, set aae[index] = newval and return newval.
+Expression assignAssocArrayElement(const ref Loc loc, AssocArrayLiteralExp aae, Expression index, Expression newval)
+{
+ /* Create new associative array literal reflecting updated key/value
+ */
+ Expressions* keysx = aae.keys;
+ Expressions* valuesx = aae.values;
+ int updated = 0;
+ for (size_t j = valuesx.dim; j;)
+ {
+ j--;
+ Expression ekey = (*aae.keys)[j];
+ int eq = ctfeEqual(loc, TOK.equal, ekey, index);
+ if (eq)
+ {
+ (*valuesx)[j] = newval;
+ updated = 1;
+ }
+ }
+ if (!updated)
+ {
+ // Append index/newval to keysx[]/valuesx[]
+ valuesx.push(newval);
+ keysx.push(index);
+ }
+ return newval;
+}
+
+/// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
+/// oldlen, change its length to newlen. If the newlen is longer than oldlen,
+/// all new elements will be set to the default initializer for the element type.
+UnionExp changeArrayLiteralLength(const ref Loc loc, TypeArray arrayType, Expression oldval, size_t oldlen, size_t newlen)
+{
+ UnionExp ue;
+ Type elemType = arrayType.next;
+ assert(elemType);
+ Expression defaultElem = elemType.defaultInitLiteral(loc);
+ auto elements = new Expressions(newlen);
+ // Resolve slices
+ size_t indxlo = 0;
+ if (oldval.op == TOK.slice)
+ {
+ indxlo = cast(size_t)(cast(SliceExp)oldval).lwr.toInteger();
+ oldval = (cast(SliceExp)oldval).e1;
+ }
+ size_t copylen = oldlen < newlen ? oldlen : newlen;
+ if (oldval.op == TOK.string_)
+ {
+ StringExp oldse = cast(StringExp)oldval;
+ void* s = mem.xcalloc(newlen + 1, oldse.sz);
+ const data = oldse.peekData();
+ memcpy(s, data.ptr, copylen * oldse.sz);
+ const defaultValue = cast(uint)defaultElem.toInteger();
+ foreach (size_t elemi; copylen .. newlen)
+ {
+ switch (oldse.sz)
+ {
+ case 1:
+ (cast(char*)s)[cast(size_t)(indxlo + elemi)] = cast(char)defaultValue;
+ break;
+ case 2:
+ (cast(wchar*)s)[cast(size_t)(indxlo + elemi)] = cast(wchar)defaultValue;
+ break;
+ case 4:
+ (cast(dchar*)s)[cast(size_t)(indxlo + elemi)] = cast(dchar)defaultValue;
+ break;
+ default:
+ assert(0);
+ }
+ }
+ emplaceExp!(StringExp)(&ue, loc, s[0 .. newlen * oldse.sz], newlen, oldse.sz);
+ StringExp se = cast(StringExp)ue.exp();
+ se.type = arrayType;
+ se.sz = oldse.sz;
+ se.committed = oldse.committed;
+ se.ownedByCtfe = OwnedBy.ctfe;
+ }
+ else
+ {
+ if (oldlen != 0)
+ {
+ assert(oldval.op == TOK.arrayLiteral);
+ ArrayLiteralExp ae = cast(ArrayLiteralExp)oldval;
+ foreach (size_t i; 0 .. copylen)
+ (*elements)[i] = (*ae.elements)[indxlo + i];
+ }
+ if (elemType.ty == Tstruct || elemType.ty == Tsarray)
+ {
+ /* If it is an aggregate literal representing a value type,
+ * we need to create a unique copy for each element
+ */
+ foreach (size_t i; copylen .. newlen)
+ (*elements)[i] = copyLiteral(defaultElem).copy();
+ }
+ else
+ {
+ foreach (size_t i; copylen .. newlen)
+ (*elements)[i] = defaultElem;
+ }
+ emplaceExp!(ArrayLiteralExp)(&ue, loc, arrayType, elements);
+ ArrayLiteralExp aae = cast(ArrayLiteralExp)ue.exp();
+ aae.ownedByCtfe = OwnedBy.ctfe;
+ }
+ return ue;
+}
+
+/*************************** CTFE Sanity Checks ***************************/
+
+bool isCtfeValueValid(Expression newval)
+{
+ Type tb = newval.type.toBasetype();
+ switch (newval.op)
+ {
+ case TOK.int64:
+ case TOK.float64:
+ case TOK.char_:
+ case TOK.complex80:
+ return tb.isscalar();
+
+ case TOK.null_:
+ return tb.ty == Tnull ||
+ tb.ty == Tpointer ||
+ tb.ty == Tarray ||
+ tb.ty == Taarray ||
+ tb.ty == Tclass ||
+ tb.ty == Tdelegate;
+
+ case TOK.string_:
+ return true; // CTFE would directly use the StringExp in AST.
+
+ case TOK.arrayLiteral:
+ return true; //((ArrayLiteralExp *)newval)->ownedByCtfe;
+
+ case TOK.assocArrayLiteral:
+ return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe;
+
+ case TOK.structLiteral:
+ return true; //((StructLiteralExp *)newval)->ownedByCtfe;
+
+ case TOK.classReference:
+ return true;
+
+ case TOK.type:
+ return true;
+
+ case TOK.vector:
+ return true; // vector literal
+
+ case TOK.function_:
+ return true; // function literal or delegate literal
+
+ case TOK.delegate_:
+ {
+ // &struct.func or &clasinst.func
+ // &nestedfunc
+ Expression ethis = (cast(DelegateExp)newval).e1;
+ return (ethis.op == TOK.structLiteral || ethis.op == TOK.classReference || ethis.op == TOK.variable && (cast(VarExp)ethis).var == (cast(DelegateExp)newval).func);
+ }
+
+ case TOK.symbolOffset:
+ {
+ // function pointer, or pointer to static variable
+ Declaration d = (cast(SymOffExp)newval).var;
+ return d.isFuncDeclaration() || d.isDataseg();
+ }
+
+ case TOK.typeid_:
+ {
+ // always valid
+ return true;
+ }
+
+ case TOK.address:
+ {
+ // e1 should be a CTFE reference
+ Expression e1 = (cast(AddrExp)newval).e1;
+ return tb.ty == Tpointer &&
+ (
+ (e1.op == TOK.structLiteral || e1.op == TOK.arrayLiteral) && isCtfeValueValid(e1) ||
+ e1.op == TOK.variable ||
+ e1.op == TOK.dotVariable && isCtfeReferenceValid(e1) ||
+ e1.op == TOK.index && isCtfeReferenceValid(e1) ||
+ e1.op == TOK.slice && e1.type.toBasetype().ty == Tsarray
+ );
+ }
+
+ case TOK.slice:
+ {
+ // e1 should be an array aggregate
+ const SliceExp se = cast(SliceExp)newval;
+ assert(se.lwr && se.lwr.op == TOK.int64);
+ assert(se.upr && se.upr.op == TOK.int64);
+ return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == TOK.string_ || se.e1.op == TOK.arrayLiteral);
+ }
+
+ case TOK.void_:
+ return true; // uninitialized value
+
+ default:
+ newval.error("CTFE internal error: illegal CTFE value `%s`", newval.toChars());
+ return false;
+ }
+}
+
+bool isCtfeReferenceValid(Expression newval)
+{
+ switch (newval.op)
+ {
+ case TOK.this_:
+ return true;
+
+ case TOK.variable:
+ {
+ const VarDeclaration v = (cast(VarExp)newval).var.isVarDeclaration();
+ assert(v);
+ // Must not be a reference to a reference
+ return true;
+ }
+
+ case TOK.index:
+ {
+ const Expression eagg = (cast(IndexExp)newval).e1;
+ return eagg.op == TOK.string_ || eagg.op == TOK.arrayLiteral || eagg.op == TOK.assocArrayLiteral;
+ }
+
+ case TOK.dotVariable:
+ {
+ Expression eagg = (cast(DotVarExp)newval).e1;
+ return (eagg.op == TOK.structLiteral || eagg.op == TOK.classReference) && isCtfeValueValid(eagg);
+ }
+
+ default:
+ // Internally a ref variable may directly point a stack memory.
+ // e.g. ref int v = 1;
+ return isCtfeValueValid(newval);
+ }
+}
+
+// Used for debugging only
+void showCtfeExpr(Expression e, int level = 0)
+{
+ for (int i = level; i > 0; --i)
+ printf(" ");
+ Expressions* elements = null;
+ // We need the struct definition to detect block assignment
+ StructDeclaration sd = null;
+ ClassDeclaration cd = null;
+ if (e.op == TOK.structLiteral)
+ {
+ elements = (cast(StructLiteralExp)e).elements;
+ sd = (cast(StructLiteralExp)e).sd;
+ printf("STRUCT type = %s %p:\n", e.type.toChars(), e);
+ }
+ else if (e.op == TOK.classReference)
+ {
+ elements = (cast(ClassReferenceExp)e).value.elements;
+ cd = (cast(ClassReferenceExp)e).originalClass();
+ printf("CLASS type = %s %p:\n", e.type.toChars(), (cast(ClassReferenceExp)e).value);
+ }
+ else if (e.op == TOK.arrayLiteral)
+ {
+ elements = (cast(ArrayLiteralExp)e).elements;
+ printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e);
+ }
+ else if (e.op == TOK.assocArrayLiteral)
+ {
+ printf("AA LITERAL type=%s %p:\n", e.type.toChars(), e);
+ }
+ else if (e.op == TOK.string_)
+ {
+ printf("STRING %s %p\n", e.toChars(), e.isStringExp.peekString.ptr);
+ }
+ else if (e.op == TOK.slice)
+ {
+ printf("SLICE %p: %s\n", e, e.toChars());
+ showCtfeExpr((cast(SliceExp)e).e1, level + 1);
+ }
+ else if (e.op == TOK.variable)
+ {
+ printf("VAR %p %s\n", e, e.toChars());
+ VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
+ if (v && getValue(v))
+ showCtfeExpr(getValue(v), level + 1);
+ }
+ else if (e.op == TOK.address)
+ {
+ // This is potentially recursive. We mustn't try to print the thing we're pointing to.
+ printf("POINTER %p to %p: %s\n", e, (cast(AddrExp)e).e1, e.toChars());
+ }
+ else
+ printf("VALUE %p: %s\n", e, e.toChars());
+ if (elements)
+ {
+ size_t fieldsSoFar = 0;
+ for (size_t i = 0; i < elements.dim; i++)
+ {
+ Expression z = null;
+ VarDeclaration v = null;
+ if (i > 15)
+ {
+ printf("...(total %d elements)\n", cast(int)elements.dim);
+ return;
+ }
+ if (sd)
+ {
+ v = sd.fields[i];
+ z = (*elements)[i];
+ }
+ else if (cd)
+ {
+ while (i - fieldsSoFar >= cd.fields.dim)
+ {
+ fieldsSoFar += cd.fields.dim;
+ cd = cd.baseClass;
+ for (int j = level; j > 0; --j)
+ printf(" ");
+ printf(" BASE CLASS: %s\n", cd.toChars());
+ }
+ v = cd.fields[i - fieldsSoFar];
+ assert((elements.dim + i) >= (fieldsSoFar + cd.fields.dim));
+ size_t indx = (elements.dim - fieldsSoFar) - cd.fields.dim + i;
+ assert(indx < elements.dim);
+ z = (*elements)[indx];
+ }
+ if (!z)
+ {
+ for (int j = level; j > 0; --j)
+ printf(" ");
+ printf(" void\n");
+ continue;
+ }
+ if (v)
+ {
+ // If it is a void assignment, use the default initializer
+ if ((v.type.ty != z.type.ty) && v.type.ty == Tsarray)
+ {
+ for (int j = level; --j;)
+ printf(" ");
+ printf(" field: block initialized static array\n");
+ continue;
+ }
+ }
+ showCtfeExpr(z, level + 1);
+ }
+ }
+}
+
+/*************************** Void initialization ***************************/
+UnionExp voidInitLiteral(Type t, VarDeclaration var)
+{
+ UnionExp ue;
+ if (t.ty == Tsarray)
+ {
+ TypeSArray tsa = cast(TypeSArray)t;
+ Expression elem = voidInitLiteral(tsa.next, var).copy();
+ // For aggregate value types (structs, static arrays) we must
+ // create an a separate copy for each element.
+ const mustCopy = (elem.op == TOK.arrayLiteral || elem.op == TOK.structLiteral);
+ const d = cast(size_t)tsa.dim.toInteger();
+ auto elements = new Expressions(d);
+ foreach (i; 0 .. d)
+ {
+ if (mustCopy && i > 0)
+ elem = copyLiteral(elem).copy();
+ (*elements)[i] = elem;
+ }
+ emplaceExp!(ArrayLiteralExp)(&ue, var.loc, tsa, elements);
+ ArrayLiteralExp ae = cast(ArrayLiteralExp)ue.exp();
+ ae.ownedByCtfe = OwnedBy.ctfe;
+ }
+ else if (t.ty == Tstruct)
+ {
+ TypeStruct ts = cast(TypeStruct)t;
+ auto exps = new Expressions(ts.sym.fields.dim);
+ foreach (size_t i; 0 .. ts.sym.fields.dim)
+ {
+ (*exps)[i] = voidInitLiteral(ts.sym.fields[i].type, ts.sym.fields[i]).copy();
+ }
+ emplaceExp!(StructLiteralExp)(&ue, var.loc, ts.sym, exps);
+ StructLiteralExp se = cast(StructLiteralExp)ue.exp();
+ se.type = ts;
+ se.ownedByCtfe = OwnedBy.ctfe;
+ }
+ else
+ emplaceExp!(VoidInitExp)(&ue, var);
+ return ue;
+}
diff --git a/gcc/d/dmd/ctorflow.d b/gcc/d/dmd/ctorflow.d
new file mode 100644
index 0000000..c8b61be
--- /dev/null
+++ b/gcc/d/dmd/ctorflow.d
@@ -0,0 +1,225 @@
+/**
+ * Manage flow analysis for constructors.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctorflow.d, _ctorflow.d)
+ * Documentation: https://dlang.org/phobos/dmd_ctorflow.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ctorflow.d
+ */
+
+module dmd.ctorflow;
+
+import core.stdc.stdio;
+
+import dmd.root.rmem;
+import dmd.globals : Loc;
+
+enum CSX : ushort
+{
+ none = 0,
+ this_ctor = 0x01, /// called this()
+ super_ctor = 0x02, /// called super()
+ label = 0x04, /// seen a label
+ return_ = 0x08, /// seen a return statement
+ any_ctor = 0x10, /// either this() or super() was called
+ halt = 0x20, /// assert(0)
+}
+
+/// Individual field in the Ctor with information about its callees and location.
+struct FieldInit
+{
+ CSX csx; /// information about the field's callees
+ Loc loc; /// location of the field initialization
+}
+
+/***********
+ * Primitive flow analysis for constructors
+ */
+struct CtorFlow
+{
+ CSX callSuper; /// state of calling other constructors
+
+ FieldInit[] fieldinit; /// state of field initializations
+
+ void allocFieldinit(size_t dim)
+ {
+ fieldinit = (cast(FieldInit*)mem.xcalloc(FieldInit.sizeof, dim))[0 .. dim];
+ }
+
+ void freeFieldinit()
+ {
+ if (fieldinit.ptr)
+ mem.xfree(fieldinit.ptr);
+
+ fieldinit = null;
+ }
+
+ /***********************
+ * Create a deep copy of `this`
+ * Returns:
+ * a copy
+ */
+ CtorFlow clone()
+ {
+ return CtorFlow(callSuper, fieldinit.arraydup);
+ }
+
+ /**********************************
+ * Set CSX bits in flow analysis state
+ * Params:
+ * csx = bits to set
+ */
+ void orCSX(CSX csx) nothrow pure
+ {
+ callSuper |= csx;
+ foreach (ref u; fieldinit)
+ u.csx |= csx;
+ }
+
+ /******************************
+ * OR CSX bits to `this`
+ * Params:
+ * ctorflow = bits to OR in
+ */
+ void OR(const ref CtorFlow ctorflow) pure nothrow
+ {
+ callSuper |= ctorflow.callSuper;
+ if (fieldinit.length && ctorflow.fieldinit.length)
+ {
+ assert(fieldinit.length == ctorflow.fieldinit.length);
+ foreach (i, u; ctorflow.fieldinit)
+ {
+ auto fi = &fieldinit[i];
+ fi.csx |= u.csx;
+ if (fi.loc is Loc.init)
+ fi.loc = u.loc;
+ }
+ }
+ }
+}
+
+
+/****************************************
+ * Merge `b` flow analysis results into `a`.
+ * Params:
+ * a = the path to merge `b` into
+ * b = the other path
+ * Returns:
+ * false means one of the paths skips construction
+ */
+bool mergeCallSuper(ref CSX a, const CSX b) pure nothrow
+{
+ // This does a primitive flow analysis to support the restrictions
+ // regarding when and how constructors can appear.
+ // It merges the results of two paths.
+ // The two paths are `a` and `b`; the result is merged into `a`.
+ if (b == a)
+ return true;
+
+ // Have ALL branches called a constructor?
+ const aAll = (a & (CSX.this_ctor | CSX.super_ctor)) != 0;
+ const bAll = (b & (CSX.this_ctor | CSX.super_ctor)) != 0;
+ // Have ANY branches called a constructor?
+ const aAny = (a & CSX.any_ctor) != 0;
+ const bAny = (b & CSX.any_ctor) != 0;
+ // Have any branches returned?
+ const aRet = (a & CSX.return_) != 0;
+ const bRet = (b & CSX.return_) != 0;
+ // Have any branches halted?
+ const aHalt = (a & CSX.halt) != 0;
+ const bHalt = (b & CSX.halt) != 0;
+ if (aHalt && bHalt)
+ {
+ a = CSX.halt;
+ }
+ else if ((!bHalt && bRet && !bAny && aAny) || (!aHalt && aRet && !aAny && bAny))
+ {
+ // If one has returned without a constructor call, there must not
+ // be ctor calls in the other.
+ return false;
+ }
+ else if (bHalt || bRet && bAll)
+ {
+ // If one branch has called a ctor and then exited, anything the
+ // other branch has done is OK (except returning without a
+ // ctor call, but we already checked that).
+ a |= b & (CSX.any_ctor | CSX.label);
+ }
+ else if (aHalt || aRet && aAll)
+ {
+ a = cast(CSX)(b | (a & (CSX.any_ctor | CSX.label)));
+ }
+ else if (aAll != bAll) // both branches must have called ctors, or both not
+ return false;
+ else
+ {
+ // If one returned without a ctor, remember that
+ if (bRet && !bAny)
+ a |= CSX.return_;
+ a |= b & (CSX.any_ctor | CSX.label);
+ }
+ return true;
+}
+
+
+/****************************************
+ * Merge `b` flow analysis results into `a`.
+ * Params:
+ * a = the path to merge `b` into
+ * b = the other path
+ * Returns:
+ * false means either `a` or `b` skips initialization
+ */
+bool mergeFieldInit(ref CSX a, const CSX b) pure nothrow
+{
+ if (b == a)
+ return true;
+
+ // Have any branches returned?
+ const aRet = (a & CSX.return_) != 0;
+ const bRet = (b & CSX.return_) != 0;
+ // Have any branches halted?
+ const aHalt = (a & CSX.halt) != 0;
+ const bHalt = (b & CSX.halt) != 0;
+
+ if (aHalt && bHalt)
+ {
+ a = CSX.halt;
+ return true;
+ }
+
+ // The logic here is to prefer the branch that neither halts nor returns.
+ bool ok;
+ if (!bHalt && bRet)
+ {
+ // Branch b returns, no merging required.
+ ok = (b & CSX.this_ctor);
+ }
+ else if (!aHalt && aRet)
+ {
+ // Branch a returns, but b doesn't, b takes precedence.
+ ok = (a & CSX.this_ctor);
+ a = b;
+ }
+ else if (bHalt)
+ {
+ // Branch b halts, no merging required.
+ ok = (a & CSX.this_ctor);
+ }
+ else if (aHalt)
+ {
+ // Branch a halts, but b doesn't, b takes precedence.
+ ok = (b & CSX.this_ctor);
+ a = b;
+ }
+ else
+ {
+ // Neither branch returns nor halts, merge flags.
+ ok = !((a ^ b) & CSX.this_ctor);
+ a |= b;
+ }
+ return ok;
+}
+
diff --git a/gcc/d/dmd/dcast.c b/gcc/d/dmd/dcast.c
deleted file mode 100644
index d84ab7f..0000000
--- a/gcc/d/dmd/dcast.c
+++ /dev/null
@@ -1,3566 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/cast.c
- */
-
-#include "root/dsystem.h" // mem{set|cpy}()
-#include "root/rmem.h"
-
-#include "mars.h"
-#include "expression.h"
-#include "mtype.h"
-#include "utf.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "template.h"
-#include "scope.h"
-#include "id.h"
-#include "init.h"
-#include "tokens.h"
-
-FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
-bool isCommutative(TOK op);
-MOD MODmerge(MOD mod1, MOD mod2);
-void toAutoQualChars(const char **result, Type *t1, Type *t2);
-
-/* ==================== implicitCast ====================== */
-
-/**************************************
- * Do an implicit cast.
- * Issue error if it can't be done.
- */
-
-
-Expression *implicitCastTo(Expression *e, Scope *sc, Type *t)
-{
- class ImplicitCastTo : public Visitor
- {
- public:
- Type *t;
- Scope *sc;
- Expression *result;
-
- ImplicitCastTo(Scope *sc, Type *t)
- : t(t), sc(sc)
- {
- result = NULL;
- }
-
- void visit(Expression *e)
- {
- //printf("Expression::implicitCastTo(%s of type %s) => %s\n", e->toChars(), e->type->toChars(), t->toChars());
-
- MATCH match = e->implicitConvTo(t);
- if (match)
- {
- if (match == MATCHconst &&
- (e->type->constConv(t) ||
- (!e->isLvalue() && e->type->equivalent(t))))
- {
- /* Do not emit CastExp for const conversions and
- * unique conversions on rvalue.
- */
- result = e->copy();
- result->type = t;
- return;
- }
- result = e->castTo(sc, t);
- return;
- }
-
- result = e->optimize(WANTvalue);
- if (result != e)
- {
- result->accept(this);
- return;
- }
-
- if (t->ty != Terror && e->type->ty != Terror)
- {
- if (!t->deco)
- {
- e->error("forward reference to type %s", t->toChars());
- }
- else
- {
- //printf("type %p ty %d deco %p\n", type, type->ty, type->deco);
- //type = type->semantic(loc, sc);
- //printf("type %s t %s\n", type->deco, t->deco);
- const char *ts[2];
- toAutoQualChars(ts, e->type, t);
- e->error("cannot implicitly convert expression (%s) of type %s to %s",
- e->toChars(), ts[0], ts[1]);
- }
- }
- result = new ErrorExp();
- }
-
- void visit(StringExp *e)
- {
- //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e->toChars(), e->type->toChars(), t->toChars());
- visit((Expression *)e);
- if (result->op == TOKstring)
- {
- // Retain polysemous nature if it started out that way
- ((StringExp *)result)->committed = e->committed;
- }
- }
-
- void visit(ErrorExp *e)
- {
- result = e;
- }
-
- void visit(FuncExp *e)
- {
- //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e->type, e->type ? e->type->toChars() : NULL, t->toChars());
- FuncExp *fe;
- if (e->matchType(t, sc, &fe) > MATCHnomatch)
- {
- result = fe;
- return;
- }
- visit((Expression *)e);
- }
-
- void visit(ArrayLiteralExp *e)
- {
- visit((Expression *)e);
-
- Type *tb = result->type->toBasetype();
- if (tb->ty == Tarray && global.params.useTypeInfo && Type::dtypeinfo)
- semanticTypeInfo(sc, ((TypeDArray *)tb)->next);
- }
-
- void visit(SliceExp *e)
- {
- visit((Expression *)e);
- if (result->op != TOKslice)
- return;
-
- e = (SliceExp *)result;
- if (e->e1->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e->e1;
- Type *tb = t->toBasetype();
- Type *tx;
- if (tb->ty == Tsarray)
- tx = tb->nextOf()->sarrayOf(ale->elements ? ale->elements->length : 0);
- else
- tx = tb->nextOf()->arrayOf();
- e->e1 = ale->implicitCastTo(sc, tx);
- }
- }
- };
-
- ImplicitCastTo v(sc, t);
- e->accept(&v);
- return v.result;
-}
-
-/*******************************************
- * Return MATCH level of implicitly converting e to type t.
- * Don't do the actual cast; don't change e.
- */
-
-MATCH implicitConvTo(Expression *e, Type *t)
-{
- class ImplicitConvTo : public Visitor
- {
- public:
- Type *t;
- MATCH result;
-
- ImplicitConvTo(Type *t)
- : t(t)
- {
- result = MATCHnomatch;
- }
-
- void visit(Expression *e)
- {
- //static int nest; if (++nest == 10) halt();
- if (t == Type::terror)
- return;
- if (!e->type)
- {
- e->error("%s is not an expression", e->toChars());
- e->type = Type::terror;
- }
- Expression *ex = e->optimize(WANTvalue);
- if (ex->type->equals(t))
- {
- result = MATCHexact;
- return;
- }
- if (ex != e)
- {
- //printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars());
- result = ex->implicitConvTo(t);
- return;
- }
- MATCH match = e->type->implicitConvTo(t);
- if (match != MATCHnomatch)
- {
- result = match;
- return;
- }
-
- /* See if we can do integral narrowing conversions
- */
- if (e->type->isintegral() && t->isintegral() &&
- e->type->isTypeBasic() && t->isTypeBasic())
- {
- IntRange src = getIntRange(e);
- IntRange target = IntRange::fromType(t);
- if (target.contains(src))
- {
- result = MATCHconvert;
- return;
- }
- }
- }
-
- /******
- * Given expression e of type t, see if we can implicitly convert e
- * to type tprime, where tprime is type t with mod bits added.
- * Returns:
- * match level
- */
- static MATCH implicitMod(Expression *e, Type *t, MOD mod)
- {
- Type *tprime;
- if (t->ty == Tpointer)
- tprime = t->nextOf()->castMod(mod)->pointerTo();
- else if (t->ty == Tarray)
- tprime = t->nextOf()->castMod(mod)->arrayOf();
- else if (t->ty == Tsarray)
- tprime = t->nextOf()->castMod(mod)->sarrayOf(t->size() / t->nextOf()->size());
- else
- tprime = t->castMod(mod);
-
- return e->implicitConvTo(tprime);
- }
-
- static MATCH implicitConvToAddMin(BinExp *e, Type *t)
- {
- /* Is this (ptr +- offset)? If so, then ask ptr
- * if the conversion can be done.
- * This is to support doing things like implicitly converting a mutable unique
- * pointer to an immutable pointer.
- */
-
- Type *typeb = e->type->toBasetype();
- Type *tb = t->toBasetype();
- if (typeb->ty != Tpointer || tb->ty != Tpointer)
- return MATCHnomatch;
-
- Type *t1b = e->e1->type->toBasetype();
- Type *t2b = e->e2->type->toBasetype();
- if (t1b->ty == Tpointer && t2b->isintegral() &&
- t1b->equivalent(tb))
- {
- // ptr + offset
- // ptr - offset
- MATCH m = e->e1->implicitConvTo(t);
- return (m > MATCHconst) ? MATCHconst : m;
- }
- if (t2b->ty == Tpointer && t1b->isintegral() &&
- t2b->equivalent(tb))
- {
- // offset + ptr
- MATCH m = e->e2->implicitConvTo(t);
- return (m > MATCHconst) ? MATCHconst : m;
- }
-
- return MATCHnomatch;
- }
-
- void visit(AddExp *e)
- {
- visit((Expression *)e);
- if (result == MATCHnomatch)
- result = implicitConvToAddMin(e, t);
- }
-
- void visit(MinExp *e)
- {
- visit((Expression *)e);
- if (result == MATCHnomatch)
- result = implicitConvToAddMin(e, t);
- }
-
- void visit(IntegerExp *e)
- {
- MATCH m = e->type->implicitConvTo(t);
- if (m >= MATCHconst)
- {
- result = m;
- return;
- }
-
- TY ty = e->type->toBasetype()->ty;
- TY toty = t->toBasetype()->ty;
- TY oldty = ty;
-
- if (m == MATCHnomatch && t->ty == Tenum)
- return;
-
- if (t->ty == Tvector)
- {
- TypeVector *tv = (TypeVector *)t;
- TypeBasic *tb = tv->elementType();
- if (tb->ty == Tvoid)
- return;
- toty = tb->ty;
- }
-
- switch (ty)
- {
- case Tbool:
- case Tint8:
- case Tchar:
- case Tuns8:
- case Tint16:
- case Tuns16:
- case Twchar:
- ty = Tint32;
- break;
-
- case Tdchar:
- ty = Tuns32;
- break;
-
- default:
- break;
- }
-
- // Only allow conversion if no change in value
- dinteger_t value = e->toInteger();
- switch (toty)
- {
- case Tbool:
- if ((value & 1) != value)
- return;
- break;
-
- case Tint8:
- if (ty == Tuns64 && value & ~0x7FUL)
- return;
- else if ((signed char)value != (sinteger_t)value)
- return;
- break;
-
- case Tchar:
- if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F)
- return;
- /* fall through */
- case Tuns8:
- //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value);
- if ((unsigned char)value != value)
- return;
- break;
-
- case Tint16:
- if (ty == Tuns64 && value & ~0x7FFFUL)
- return;
- else if ((short)value != (sinteger_t)value)
- return;
- break;
-
- case Twchar:
- if (oldty == Tdchar && value > 0xD7FF && value < 0xE000)
- return;
- /* fall through */
- case Tuns16:
- if ((unsigned short)value != value)
- return;
- break;
-
- case Tint32:
- if (ty == Tuns32)
- {
- }
- else if (ty == Tuns64 && value & ~0x7FFFFFFFUL)
- return;
- else if ((int)value != (sinteger_t)value)
- return;
- break;
-
- case Tuns32:
- if (ty == Tint32)
- {
- }
- else if ((unsigned)value != value)
- return;
- break;
-
- case Tdchar:
- if (value > 0x10FFFFUL)
- return;
- break;
-
- case Tfloat32:
- {
- volatile float f;
- if (e->type->isunsigned())
- {
- f = (float)value;
- if (f != value)
- return;
- }
- else
- {
- f = (float)(sinteger_t)value;
- if (f != (sinteger_t)value)
- return;
- }
- break;
- }
-
- case Tfloat64:
- {
- volatile double f;
- if (e->type->isunsigned())
- {
- f = (double)value;
- if (f != value)
- return;
- }
- else
- {
- f = (double)(sinteger_t)value;
- if (f != (sinteger_t)value)
- return;
- }
- break;
- }
-
- case Tfloat80:
- {
- volatile_longdouble f;
- if (e->type->isunsigned())
- {
- f = ldouble(value);
- if ((dinteger_t)f != value) // isn't this a noop, because the compiler prefers ld
- return;
- }
- else
- {
- f = ldouble((sinteger_t)value);
- if ((sinteger_t)f != (sinteger_t)value)
- return;
- }
- break;
- }
-
- case Tpointer:
- //printf("type = %s\n", type->toBasetype()->toChars());
- //printf("t = %s\n", t->toBasetype()->toChars());
- if (ty == Tpointer &&
- e->type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty)
- {
- /* Allow things like:
- * const char* P = cast(char *)3;
- * char* q = P;
- */
- break;
- }
- /* fall through */
-
- default:
- visit((Expression *)e);
- return;
- }
-
- //printf("MATCHconvert\n");
- result = MATCHconvert;
- }
-
- void visit(ErrorExp *)
- {
- // no match
- }
-
- void visit(NullExp *e)
- {
- if (e->type->equals(t))
- {
- result = MATCHexact;
- return;
- }
-
- /* Allow implicit conversions from immutable to mutable|const,
- * and mutable to immutable. It works because, after all, a null
- * doesn't actually point to anything.
- */
- if (t->equivalent(e->type))
- {
- result = MATCHconst;
- return;
- }
-
- visit((Expression *)e);
- }
-
- void visit(StructLiteralExp *e)
- {
- visit((Expression *)e);
- if (result != MATCHnomatch)
- return;
- if (e->type->ty == t->ty && e->type->ty == Tstruct &&
- ((TypeStruct *)e->type)->sym == ((TypeStruct *)t)->sym)
- {
- result = MATCHconst;
- for (size_t i = 0; i < e->elements->length; i++)
- {
- Expression *el = (*e->elements)[i];
- if (!el)
- continue;
- Type *te = el->type;
- te = e->sd->fields[i]->type->addMod(t->mod);
- MATCH m2 = el->implicitConvTo(te);
- //printf("\t%s => %s, match = %d\n", el->toChars(), te->toChars(), m2);
- if (m2 < result)
- result = m2;
- }
- }
- }
-
- void visit(StringExp *e)
- {
- if (!e->committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
- return;
-
- if (e->type->ty == Tsarray || e->type->ty == Tarray || e->type->ty == Tpointer)
- {
- TY tyn = e->type->nextOf()->ty;
- if (tyn == Tchar || tyn == Twchar || tyn == Tdchar)
- {
- switch (t->ty)
- {
- case Tsarray:
- if (e->type->ty == Tsarray)
- {
- TY tynto = t->nextOf()->ty;
- if (tynto == tyn)
- {
- if (((TypeSArray *)e->type)->dim->toInteger() ==
- ((TypeSArray *)t)->dim->toInteger())
- {
- result = MATCHexact;
- }
- return;
- }
- if (tynto == Tchar || tynto == Twchar || tynto == Tdchar)
- {
- if (e->committed && tynto != tyn)
- return;
- size_t fromlen = e->numberOfCodeUnits(tynto);
- size_t tolen = (size_t)((TypeSArray *)t)->dim->toInteger();
- if (tolen < fromlen)
- return;
- if (tolen != fromlen)
- {
- // implicit length extending
- result = MATCHconvert;
- return;
- }
- }
- if (!e->committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar))
- {
- result = MATCHexact;
- return;
- }
- }
- else if (e->type->ty == Tarray)
- {
- TY tynto = t->nextOf()->ty;
- if (tynto == Tchar || tynto == Twchar || tynto == Tdchar)
- {
- if (e->committed && tynto != tyn)
- return;
- size_t fromlen = e->numberOfCodeUnits(tynto);
- size_t tolen = (size_t)((TypeSArray *)t)->dim->toInteger();
- if (tolen < fromlen)
- return;
- if (tolen != fromlen)
- {
- // implicit length extending
- result = MATCHconvert;
- return;
- }
- }
- if (tynto == tyn)
- {
- result = MATCHexact;
- return;
- }
- if (!e->committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar))
- {
- result = MATCHexact;
- return;
- }
- }
- /* fall through */
- case Tarray:
- case Tpointer:
- Type *tn = t->nextOf();
- MATCH m = MATCHexact;
- if (e->type->nextOf()->mod != tn->mod)
- {
- if (!tn->isConst())
- return;
- m = MATCHconst;
- }
- if (!e->committed)
- {
- switch (tn->ty)
- {
- case Tchar:
- if (e->postfix == 'w' || e->postfix == 'd')
- m = MATCHconvert;
- result = m;
- return;
- case Twchar:
- if (e->postfix != 'w')
- m = MATCHconvert;
- result = m;
- return;
- case Tdchar:
- if (e->postfix != 'd')
- m = MATCHconvert;
- result = m;
- return;
- }
- }
- break;
- }
- }
- }
-
- visit((Expression *)e);
- }
-
- void visit(ArrayLiteralExp *e)
- {
- Type *typeb = e->type->toBasetype();
- Type *tb = t->toBasetype();
- if ((tb->ty == Tarray || tb->ty == Tsarray) &&
- (typeb->ty == Tarray || typeb->ty == Tsarray))
- {
- result = MATCHexact;
- Type *typen = typeb->nextOf()->toBasetype();
-
- if (tb->ty == Tsarray)
- {
- TypeSArray *tsa = (TypeSArray *)tb;
- if (e->elements->length != tsa->dim->toInteger())
- result = MATCHnomatch;
- }
-
- Type *telement = tb->nextOf();
- if (!e->elements->length)
- {
- if (typen->ty != Tvoid)
- result = typen->implicitConvTo(telement);
- }
- else
- {
- if (e->basis)
- {
- MATCH m = e->basis->implicitConvTo(telement);
- if (m < result)
- result = m;
- }
- for (size_t i = 0; i < e->elements->length; i++)
- {
- Expression *el = (*e->elements)[i];
- if (result == MATCHnomatch)
- break;
- if (!el)
- continue;
- MATCH m = el->implicitConvTo(telement);
- if (m < result)
- result = m; // remember worst match
- }
- }
-
- if (!result)
- result = e->type->implicitConvTo(t);
-
- return;
- }
- else if (tb->ty == Tvector &&
- (typeb->ty == Tarray || typeb->ty == Tsarray))
- {
- result = MATCHexact;
- // Convert array literal to vector type
- TypeVector *tv = (TypeVector *)tb;
- TypeSArray *tbase = (TypeSArray *)tv->basetype;
- assert(tbase->ty == Tsarray);
- const size_t edim = e->elements->length;
- const size_t tbasedim = tbase->dim->toInteger();
- if (edim > tbasedim)
- {
- result = MATCHnomatch;
- return;
- }
-
- Type *telement = tv->elementType();
- if (edim < tbasedim)
- {
- Expression *el = typeb->nextOf()->defaultInitLiteral(e->loc);
- MATCH m = el->implicitConvTo(telement);
- if (m < result)
- result = m; // remember worst match
- }
- for (size_t i = 0; i < edim; i++)
- {
- Expression *el = (*e->elements)[i];
- MATCH m = el->implicitConvTo(telement);
- if (m < result)
- result = m; // remember worst match
- if (result == MATCHnomatch)
- break; // no need to check for worse
- }
- return;
- }
-
- visit((Expression *)e);
- }
-
- void visit(AssocArrayLiteralExp *e)
- {
- Type *typeb = e->type->toBasetype();
- Type *tb = t->toBasetype();
- if (tb->ty == Taarray && typeb->ty == Taarray)
- {
- result = MATCHexact;
- for (size_t i = 0; i < e->keys->length; i++)
- {
- Expression *el = (*e->keys)[i];
- MATCH m = el->implicitConvTo(((TypeAArray *)tb)->index);
- if (m < result)
- result = m; // remember worst match
- if (result == MATCHnomatch)
- break; // no need to check for worse
- el = (*e->values)[i];
- m = el->implicitConvTo(tb->nextOf());
- if (m < result)
- result = m; // remember worst match
- if (result == MATCHnomatch)
- break; // no need to check for worse
- }
- return;
- }
- else
- visit((Expression *)e);
- }
-
- void visit(CallExp *e)
- {
- visit((Expression *)e);
- if (result != MATCHnomatch)
- return;
-
- /* Allow the result of strongly pure functions to
- * convert to immutable
- */
- if (e->f && e->f->isolateReturn())
- {
- result = e->type->immutableOf()->implicitConvTo(t);
- if (result > MATCHconst) // Match level is MATCHconst at best.
- result = MATCHconst;
- return;
- }
-
- /* Conversion is 'const' conversion if:
- * 1. function is pure (weakly pure is ok)
- * 2. implicit conversion only fails because of mod bits
- * 3. each function parameter can be implicitly converted to the mod bits
- */
- Type *tx = e->f ? e->f->type : e->e1->type;
- tx = tx->toBasetype();
- if (tx->ty != Tfunction)
- return;
- TypeFunction *tf = (TypeFunction *)tx;
-
- if (tf->purity == PUREimpure)
- return;
- if (e->f && e->f->isNested())
- return;
-
- /* See if fail only because of mod bits.
- *
- * Bugzilla 14155: All pure functions can access global immutable data.
- * So the returned pointer may refer an immutable global data,
- * and then the returned pointer that points non-mutable object
- * cannot be unique pointer.
- *
- * Example:
- * immutable g;
- * static this() { g = 1; }
- * const(int*) foo() pure { return &g; }
- * void test() {
- * immutable(int*) ip = foo(); // OK
- * int* mp = foo(); // should be disallowed
- * }
- */
- if (e->type->immutableOf()->implicitConvTo(t) < MATCHconst &&
- e->type->addMod(MODshared)->implicitConvTo(t) < MATCHconst &&
- e->type->implicitConvTo(t->addMod(MODshared)) < MATCHconst)
- {
- return;
- }
- // Allow a conversion to immutable type, or
- // conversions of mutable types between thread-local and shared.
-
- /* Get mod bits of what we're converting to
- */
- Type *tb = t->toBasetype();
- MOD mod = tb->mod;
- if (tf->isref)
- ;
- else
- {
- Type *ti = getIndirection(t);
- if (ti)
- mod = ti->mod;
- }
- if (mod & MODwild)
- return; // not sure what to do with this
-
- /* Apply mod bits to each function parameter,
- * and see if we can convert the function argument to the modded type
- */
-
- size_t nparams = tf->parameterList.length();
- size_t j = tf->isDstyleVariadic(); // if TypeInfoArray was prepended
- if (e->e1->op == TOKdotvar)
- {
- /* Treat 'this' as just another function argument
- */
- DotVarExp *dve = (DotVarExp *)e->e1;
- Type *targ = dve->e1->type;
- if (targ->constConv(targ->castMod(mod)) == MATCHnomatch)
- return;
- }
- for (size_t i = j; i < e->arguments->length; ++i)
- {
- Expression *earg = (*e->arguments)[i];
- Type *targ = earg->type->toBasetype();
- if (i - j < nparams)
- {
- Parameter *fparam = tf->parameterList[i - j];
- if (fparam->storageClass & STClazy)
- return; // not sure what to do with this
- Type *tparam = fparam->type;
- if (!tparam)
- continue;
- if (fparam->storageClass & (STCout | STCref))
- {
- if (targ->constConv(tparam->castMod(mod)) == MATCHnomatch)
- return;
- continue;
- }
- }
-
- if (implicitMod(earg, targ, mod) == MATCHnomatch)
- return;
- }
-
- /* Success
- */
- result = MATCHconst;
- }
-
- void visit(AddrExp *e)
- {
- result = e->type->implicitConvTo(t);
- //printf("\tresult = %d\n", result);
-
- if (result != MATCHnomatch)
- return;
-
- // Look for pointers to functions where the functions are overloaded.
-
- t = t->toBasetype();
-
- if (e->e1->op == TOKoverloadset &&
- (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
- {
- OverExp *eo = (OverExp *)e->e1;
- FuncDeclaration *f = NULL;
- for (size_t i = 0; i < eo->vars->a.length; i++)
- {
- Dsymbol *s = eo->vars->a[i];
- FuncDeclaration *f2 = s->isFuncDeclaration();
- assert(f2);
- if (f2->overloadExactMatch(t->nextOf()))
- {
- if (f)
- {
- /* Error if match in more than one overload set,
- * even if one is a 'better' match than the other.
- */
- ScopeDsymbol::multiplyDefined(e->loc, f, f2);
- }
- else
- f = f2;
- result = MATCHexact;
- }
- }
- }
-
- if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tfunction &&
- t->ty == Tpointer && t->nextOf()->ty == Tfunction &&
- e->e1->op == TOKvar)
- {
- /* I don't think this can ever happen -
- * it should have been
- * converted to a SymOffExp.
- */
- assert(0);
- }
-
- //printf("\tresult = %d\n", result);
- }
-
- void visit(SymOffExp *e)
- {
- result = e->type->implicitConvTo(t);
- //printf("\tresult = %d\n", result);
- if (result != MATCHnomatch)
- return;
-
- // Look for pointers to functions where the functions are overloaded.
- t = t->toBasetype();
- if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tfunction &&
- (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
- {
- if (FuncDeclaration *f = e->var->isFuncDeclaration())
- {
- f = f->overloadExactMatch(t->nextOf());
- if (f)
- {
- if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) ||
- (t->ty == Tpointer && !(f->needThis() || f->isNested())))
- {
- result = MATCHexact;
- }
- }
- }
- }
- //printf("\tresult = %d\n", result);
- }
-
- void visit(DelegateExp *e)
- {
- result = e->type->implicitConvTo(t);
- if (result != MATCHnomatch)
- return;
-
- // Look for pointers to functions where the functions are overloaded.
- t = t->toBasetype();
- if (e->type->ty == Tdelegate &&
- t->ty == Tdelegate)
- {
- if (e->func && e->func->overloadExactMatch(t->nextOf()))
- result = MATCHexact;
- }
- }
-
- void visit(FuncExp *e)
- {
- //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e->type, e->type ? e->type->toChars() : NULL, t->toChars());
- MATCH m = e->matchType(t, NULL, NULL, 1);
- if (m > MATCHnomatch)
- {
- result = m;
- return;
- }
- visit((Expression *)e);
- }
-
- void visit(AndExp *e)
- {
- visit((Expression *)e);
- if (result != MATCHnomatch)
- return;
-
- MATCH m1 = e->e1->implicitConvTo(t);
- MATCH m2 = e->e2->implicitConvTo(t);
-
- // Pick the worst match
- result = (m1 < m2) ? m1 : m2;
- }
-
- void visit(OrExp *e)
- {
- visit((Expression *)e);
- if (result != MATCHnomatch)
- return;
-
- MATCH m1 = e->e1->implicitConvTo(t);
- MATCH m2 = e->e2->implicitConvTo(t);
-
- // Pick the worst match
- result = (m1 < m2) ? m1 : m2;
- }
-
- void visit(XorExp *e)
- {
- visit((Expression *)e);
- if (result != MATCHnomatch)
- return;
-
- MATCH m1 = e->e1->implicitConvTo(t);
- MATCH m2 = e->e2->implicitConvTo(t);
-
- // Pick the worst match
- result = (m1 < m2) ? m1 : m2;
- }
-
- void visit(CondExp *e)
- {
- MATCH m1 = e->e1->implicitConvTo(t);
- MATCH m2 = e->e2->implicitConvTo(t);
- //printf("CondExp: m1 %d m2 %d\n", m1, m2);
-
- // Pick the worst match
- result = (m1 < m2) ? m1 : m2;
- }
-
- void visit(CommaExp *e)
- {
- e->e2->accept(this);
- }
-
- void visit(CastExp *e)
- {
- result = e->type->implicitConvTo(t);
- if (result != MATCHnomatch)
- return;
-
- if (t->isintegral() &&
- e->e1->type->isintegral() &&
- e->e1->implicitConvTo(t) != MATCHnomatch)
- result = MATCHconvert;
- else
- visit((Expression *)e);
- }
-
- void visit(NewExp *e)
- {
- visit((Expression *)e);
- if (result != MATCHnomatch)
- return;
-
- /* Calling new() is like calling a pure function. We can implicitly convert the
- * return from new() to t using the same algorithm as in CallExp, with the function
- * 'arguments' being:
- * thisexp
- * newargs
- * arguments
- * .init
- * 'member' and 'allocator' need to be pure.
- */
-
- /* See if fail only because of mod bits
- */
- if (e->type->immutableOf()->implicitConvTo(t->immutableOf()) == MATCHnomatch)
- return;
-
- /* Get mod bits of what we're converting to
- */
- Type *tb = t->toBasetype();
- MOD mod = tb->mod;
- if (Type *ti = getIndirection(t))
- mod = ti->mod;
- if (mod & MODwild)
- return; // not sure what to do with this
-
- /* Apply mod bits to each argument,
- * and see if we can convert the argument to the modded type
- */
-
- if (e->thisexp)
- {
- /* Treat 'this' as just another function argument
- */
- Type *targ = e->thisexp->type;
- if (targ->constConv(targ->castMod(mod)) == MATCHnomatch)
- return;
- }
-
- /* Check call to 'allocator', then 'member'
- */
- FuncDeclaration *fd = e->allocator;
- for (int count = 0; count < 2; ++count, (fd = e->member))
- {
- if (!fd)
- continue;
- if (fd->errors || fd->type->ty != Tfunction)
- return; // error
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (tf->purity == PUREimpure)
- return; // impure
-
- if (fd == e->member)
- {
- if (e->type->immutableOf()->implicitConvTo(t) < MATCHconst &&
- e->type->addMod(MODshared)->implicitConvTo(t) < MATCHconst &&
- e->type->implicitConvTo(t->addMod(MODshared)) < MATCHconst)
- {
- return;
- }
- // Allow a conversion to immutable type, or
- // conversions of mutable types between thread-local and shared.
- }
-
- Expressions *args = (fd == e->allocator) ? e->newargs : e->arguments;
-
- size_t nparams = tf->parameterList.length();
- size_t j = tf->isDstyleVariadic(); // if TypeInfoArray was prepended
- for (size_t i = j; i < e->arguments->length; ++i)
- {
- Expression *earg = (*args)[i];
- Type *targ = earg->type->toBasetype();
- if (i - j < nparams)
- {
- Parameter *fparam = tf->parameterList[i - j];
- if (fparam->storageClass & STClazy)
- return; // not sure what to do with this
- Type *tparam = fparam->type;
- if (!tparam)
- continue;
- if (fparam->storageClass & (STCout | STCref))
- {
- if (targ->constConv(tparam->castMod(mod)) == MATCHnomatch)
- return;
- continue;
- }
- }
-
- if (implicitMod(earg, targ, mod) == MATCHnomatch)
- return;
- }
- }
-
- /* If no 'member', then construction is by simple assignment,
- * and just straight check 'arguments'
- */
- if (!e->member && e->arguments)
- {
- for (size_t i = 0; i < e->arguments->length; ++i)
- {
- Expression *earg = (*e->arguments)[i];
- if (!earg) // Bugzilla 14853: if it's on overlapped field
- continue;
- Type *targ = earg->type->toBasetype();
- if (implicitMod(earg, targ, mod) == MATCHnomatch)
- return;
- }
- }
-
- /* Consider the .init expression as an argument
- */
- Type *ntb = e->newtype->toBasetype();
- if (ntb->ty == Tarray)
- ntb = ntb->nextOf()->toBasetype();
- if (ntb->ty == Tstruct)
- {
- // Don't allow nested structs - uplevel reference may not be convertible
- StructDeclaration *sd = ((TypeStruct *)ntb)->sym;
- sd->size(e->loc); // resolve any forward references
- if (sd->isNested())
- return;
- }
- if (ntb->isZeroInit(e->loc))
- {
- /* Zeros are implicitly convertible, except for special cases.
- */
- if (ntb->ty == Tclass)
- {
- /* With new() must look at the class instance initializer.
- */
- ClassDeclaration *cd = ((TypeClass *)ntb)->sym;
-
- cd->size(e->loc); // resolve any forward references
-
- if (cd->isNested())
- return; // uplevel reference may not be convertible
-
- assert(!cd->isInterfaceDeclaration());
-
- struct ClassCheck
- {
- static bool convertible(Loc loc, ClassDeclaration *cd, MOD mod)
- {
- for (size_t i = 0; i < cd->fields.length; i++)
- {
- VarDeclaration *v = cd->fields[i];
- Initializer *init = v->_init;
- if (init)
- {
- if (init->isVoidInitializer())
- ;
- else if (ExpInitializer *ei = init->isExpInitializer())
- {
- Type *tb = v->type->toBasetype();
- if (implicitMod(ei->exp, tb, mod) == MATCHnomatch)
- return false;
- }
- else
- {
- /* Enhancement: handle StructInitializer and ArrayInitializer
- */
- return false;
- }
- }
- else if (!v->type->isZeroInit(loc))
- return false;
- }
- return cd->baseClass ? convertible(loc, cd->baseClass, mod) : true;
- }
- };
-
- if (!ClassCheck::convertible(e->loc, cd, mod))
- return;
- }
- }
- else
- {
- Expression *earg = e->newtype->defaultInitLiteral(e->loc);
- Type *targ = e->newtype->toBasetype();
-
- if (implicitMod(earg, targ, mod) == MATCHnomatch)
- return;
- }
-
- /* Success
- */
- result = MATCHconst;
- }
-
- void visit(SliceExp *e)
- {
- //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e->toChars(), e->type->toChars());
- visit((Expression *)e);
- if (result != MATCHnomatch)
- return;
-
- Type *tb = t->toBasetype();
- Type *typeb = e->type->toBasetype();
- if (tb->ty == Tsarray && typeb->ty == Tarray)
- {
- typeb = toStaticArrayType(e);
- if (typeb)
- result = typeb->implicitConvTo(t);
- return;
- }
-
- /* If the only reason it won't convert is because of the mod bits,
- * then test for conversion by seeing if e1 can be converted with those
- * same mod bits.
- */
- Type *t1b = e->e1->type->toBasetype();
- if (tb->ty == Tarray && typeb->equivalent(tb))
- {
- Type *tbn = tb->nextOf();
- Type *tx = NULL;
-
- /* If e->e1 is dynamic array or pointer, the uniqueness of e->e1
- * is equivalent with the uniqueness of the referred data. And in here
- * we can have arbitrary typed reference for that.
- */
- if (t1b->ty == Tarray)
- tx = tbn->arrayOf();
- if (t1b->ty == Tpointer)
- tx = tbn->pointerTo();
-
- /* If e->e1 is static array, at least it should be an rvalue.
- * If not, e->e1 is a reference, and its uniqueness does not link
- * to the uniqueness of the referred data.
- */
- if (t1b->ty == Tsarray && !e->e1->isLvalue())
- tx = tbn->sarrayOf(t1b->size() / tbn->size());
-
- if (tx)
- {
- result = e->e1->implicitConvTo(tx);
- if (result > MATCHconst) // Match level is MATCHconst at best.
- result = MATCHconst;
- }
- }
-
- // Enhancement 10724
- if (tb->ty == Tpointer && e->e1->op == TOKstring)
- e->e1->accept(this);
- }
- };
-
- ImplicitConvTo v(t);
- e->accept(&v);
- return v.result;
-}
-
-Type *toStaticArrayType(SliceExp *e)
-{
- if (e->lwr && e->upr)
- {
- // For the following code to work, e should be optimized beforehand.
- // (eg. $ in lwr and upr should be already resolved, if possible)
- Expression *lwr = e->lwr->optimize(WANTvalue);
- Expression *upr = e->upr->optimize(WANTvalue);
- if (lwr->isConst() && upr->isConst())
- {
- size_t len = (size_t)(upr->toUInteger() - lwr->toUInteger());
- return e->type->toBasetype()->nextOf()->sarrayOf(len);
- }
- }
- else
- {
- Type *t1b = e->e1->type->toBasetype();
- if (t1b->ty == Tsarray)
- return t1b;
- }
- return NULL;
-}
-
-/* ==================== castTo ====================== */
-
-/**************************************
- * Do an explicit cast.
- * Assume that the 'this' expression does not have any indirections.
- */
-
-Expression *castTo(Expression *e, Scope *sc, Type *t)
-{
- class CastTo : public Visitor
- {
- public:
- Type *t;
- Scope *sc;
- Expression *result;
-
- CastTo(Scope *sc, Type *t)
- : t(t), sc(sc)
- {
- result = NULL;
- }
-
- void visit(Expression *e)
- {
- //printf("Expression::castTo(this=%s, t=%s)\n", e->toChars(), t->toChars());
- if (e->type->equals(t))
- {
- result = e;
- return;
- }
- if (e->op == TOKvar)
- {
- VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
- if (v && v->storage_class & STCmanifest)
- {
- result = e->ctfeInterpret();
- result = result->castTo(sc, t);
- return;
- }
- }
-
- Type *tob = t->toBasetype();
- Type *t1b = e->type->toBasetype();
- if (tob->equals(t1b))
- {
- result = e->copy(); // because of COW for assignment to e->type
- result->type = t;
- return;
- }
-
- /* Make semantic error against invalid cast between concrete types.
- * Assume that 'e' is never be any placeholder expressions.
- * The result of these checks should be consistent with CastExp::toElem().
- */
-
- // Fat Value types
- const bool tob_isFV = (tob->ty == Tstruct || tob->ty == Tsarray || tob->ty == Tvector);
- const bool t1b_isFV = (t1b->ty == Tstruct || t1b->ty == Tsarray || t1b->ty == Tvector);
-
- // Fat Reference types
- const bool tob_isFR = (tob->ty == Tarray || tob->ty == Tdelegate);
- const bool t1b_isFR = (t1b->ty == Tarray || t1b->ty == Tdelegate);
-
- // Reference types
- const bool tob_isR = (tob_isFR || tob->ty == Tpointer || tob->ty == Taarray || tob->ty == Tclass);
- const bool t1b_isR = (t1b_isFR || t1b->ty == Tpointer || t1b->ty == Taarray || t1b->ty == Tclass);
-
- // Arithmetic types (== valueable basic types)
- const bool tob_isA = ((tob->isintegral() || tob->isfloating()) && tob->ty != Tvector);
- const bool t1b_isA = ((t1b->isintegral() || t1b->isfloating()) && t1b->ty != Tvector);
-
- if (AggregateDeclaration *t1ad = isAggregate(t1b))
- {
- AggregateDeclaration *toad = isAggregate(tob);
- if (t1ad != toad && t1ad->aliasthis)
- {
- if (t1b->ty == Tclass && tob->ty == Tclass)
- {
- ClassDeclaration *t1cd = t1b->isClassHandle();
- ClassDeclaration *tocd = tob->isClassHandle();
- int offset;
- if (tocd->isBaseOf(t1cd, &offset))
- goto Lok;
- }
-
- /* Forward the cast to our alias this member, rewrite to:
- * cast(to)e1.aliasthis
- */
- result = resolveAliasThis(sc, e);
- result = result->castTo(sc, t);
- return;
- }
- }
- else if (tob->ty == Tvector && t1b->ty != Tvector)
- {
- //printf("test1 e = %s, e->type = %s, tob = %s\n", e->toChars(), e->type->toChars(), tob->toChars());
- TypeVector *tv = (TypeVector *)tob;
- result = new CastExp(e->loc, e, tv->elementType());
- result = new VectorExp(e->loc, result, tob);
- result = expressionSemantic(result, sc);
- return;
- }
- else if (tob->ty != Tvector && t1b->ty == Tvector)
- {
- // T[n] <-- __vector(U[m])
- if (tob->ty == Tsarray)
- {
- if (t1b->size(e->loc) == tob->size(e->loc))
- goto Lok;
- }
- goto Lfail;
- }
- else if (t1b->implicitConvTo(tob) == MATCHconst && t->equals(e->type->constOf()))
- {
- result = e->copy();
- result->type = t;
- return;
- }
-
- // arithmetic values vs. other arithmetic values
- // arithmetic values vs. T*
- if ((tob_isA && (t1b_isA || t1b->ty == Tpointer)) ||
- (t1b_isA && (tob_isA || tob->ty == Tpointer)))
- {
- goto Lok;
- }
-
- // arithmetic values vs. references or fat values
- if ((tob_isA && (t1b_isR || t1b_isFV)) ||
- (t1b_isA && (tob_isR || tob_isFV)))
- {
- goto Lfail;
- }
-
- // Bugzlla 3133: A cast between fat values is possible only when the sizes match.
- if (tob_isFV && t1b_isFV)
- {
- if (t1b->size(e->loc) == tob->size(e->loc))
- goto Lok;
- e->error("cannot cast expression %s of type %s to %s because of different sizes",
- e->toChars(), e->type->toChars(), t->toChars());
- result = new ErrorExp();
- return;
- }
-
- // Fat values vs. null or references
- if ((tob_isFV && (t1b->ty == Tnull || t1b_isR)) ||
- (t1b_isFV && (tob->ty == Tnull || tob_isR)))
- {
- if (tob->ty == Tpointer && t1b->ty == Tsarray)
- {
- // T[n] sa;
- // cast(U*)sa; // ==> cast(U*)sa.ptr;
- result = new AddrExp(e->loc, e, t);
- return;
- }
- if (tob->ty == Tarray && t1b->ty == Tsarray)
- {
- // T[n] sa;
- // cast(U[])sa; // ==> cast(U[])sa[];
- d_uns64 fsize = t1b->nextOf()->size();
- d_uns64 tsize = tob->nextOf()->size();
- if (fsize != tsize)
- {
- dinteger_t dim = ((TypeSArray *)t1b)->dim->toInteger();
- if (tsize == 0 || (dim * fsize) % tsize != 0)
- {
- e->error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up",
- e->toChars(), e->type->toChars(), t->toChars());
- result = new ErrorExp();
- return;
- }
- }
- goto Lok;
- }
- goto Lfail;
- }
-
- /* For references, any reinterpret casts are allowed to same 'ty' type.
- * T* to U*
- * R1 function(P1) to R2 function(P2)
- * R1 delegate(P1) to R2 delegate(P2)
- * T[] to U[]
- * V1[K1] to V2[K2]
- * class/interface A to B (will be a dynamic cast if possible)
- */
- if (tob->ty == t1b->ty && tob_isR && t1b_isR)
- goto Lok;
-
- // typeof(null) <-- non-null references or values
- if (tob->ty == Tnull && t1b->ty != Tnull)
- goto Lfail; // Bugzilla 14629
- // typeof(null) --> non-null references or arithmetic values
- if (t1b->ty == Tnull && tob->ty != Tnull)
- goto Lok;
-
- // Check size mismatch of references.
- // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof.
- if ((tob_isFR && t1b_isR) || (t1b_isFR && tob_isR))
- {
- if (tob->ty == Tpointer && t1b->ty == Tarray)
- {
- // T[] da;
- // cast(U*)da; // ==> cast(U*)da.ptr;
- goto Lok;
- }
- if (tob->ty == Tpointer && t1b->ty == Tdelegate)
- {
- // void delegate() dg;
- // cast(U*)dg; // ==> cast(U*)dg.ptr;
- // Note that it happens even when U is a Tfunction!
- e->deprecation("casting from %s to %s is deprecated", e->type->toChars(), t->toChars());
- goto Lok;
- }
- goto Lfail;
- }
-
- if (t1b->ty == Tvoid && tob->ty != Tvoid)
- {
- Lfail:
- e->error("cannot cast expression %s of type %s to %s",
- e->toChars(), e->type->toChars(), t->toChars());
- result = new ErrorExp();
- return;
- }
-
- Lok:
- result = new CastExp(e->loc, e, t);
- result->type = t; // Don't call semantic()
- //printf("Returning: %s\n", result->toChars());
- }
-
- void visit(ErrorExp *e)
- {
- result = e;
- }
-
- void visit(RealExp *e)
- {
- if (!e->type->equals(t))
- {
- if ((e->type->isreal() && t->isreal()) ||
- (e->type->isimaginary() && t->isimaginary())
- )
- {
- result = e->copy();
- result->type = t;
- }
- else
- visit((Expression *)e);
- return;
- }
- result = e;
- }
-
- void visit(ComplexExp *e)
- {
- if (!e->type->equals(t))
- {
- if (e->type->iscomplex() && t->iscomplex())
- {
- result = e->copy();
- result->type = t;
- }
- else
- visit((Expression *)e);
- return;
- }
- result = e;
- }
-
- void visit(NullExp *e)
- {
- //printf("NullExp::castTo(t = %s) %s\n", t->toChars(), toChars());
- visit((Expression *)e);
- if (result->op == TOKnull)
- {
- NullExp *ex = (NullExp *)result;
- ex->committed = 1;
- return;
- }
- }
-
- void visit(StructLiteralExp *e)
- {
- visit((Expression *)e);
- if (result->op == TOKstructliteral)
- ((StructLiteralExp *)result)->stype = t; // commit type
- }
-
- void visit(StringExp *e)
- {
- /* This follows copy-on-write; any changes to 'this'
- * will result in a copy.
- * The this->string member is considered immutable.
- */
- int copied = 0;
-
- //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), e->toChars(), e->committed);
-
- if (!e->committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid)
- {
- e->error("cannot convert string literal to void*");
- result = new ErrorExp();
- return;
- }
-
- StringExp *se = e;
- if (!e->committed)
- {
- se = (StringExp *)e->copy();
- se->committed = 1;
- copied = 1;
- }
-
- if (e->type->equals(t))
- {
- result = se;
- return;
- }
-
- Type *tb = t->toBasetype();
- //printf("\ttype = %s\n", e->type->toChars());
- if (tb->ty == Tdelegate && e->type->toBasetype()->ty != Tdelegate)
- {
- visit((Expression *)e);
- return;
- }
-
- Type *typeb = e->type->toBasetype();
- if (typeb->equals(tb))
- {
- if (!copied)
- {
- se = (StringExp *)e->copy();
- copied = 1;
- }
- se->type = t;
- result = se;
- return;
- }
-
- /* Handle reinterpret casts:
- * cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000]
- * cast(wchar[2])"abcd"c --> [\u6261, \u6463]
- * cast(wchar[1])"abcd"c --> [\u6261]
- */
- if (e->committed && tb->ty == Tsarray && typeb->ty == Tarray)
- {
- se = (StringExp *)e->copy();
- d_uns64 szx = tb->nextOf()->size();
- assert(szx <= 255);
- se->sz = (unsigned char)szx;
- se->len = (size_t)((TypeSArray *)tb)->dim->toInteger();
- se->committed = 1;
- se->type = t;
-
- /* Assure space for terminating 0
- */
- if ((se->len + 1) * se->sz > (e->len + 1) * e->sz)
- {
- void *s = (void *)mem.xmalloc((se->len + 1) * se->sz);
- memcpy(s, se->string, se->len * se->sz);
- memset((char *)s + se->len * se->sz, 0, se->sz);
- se->string = s;
- }
- result = se;
- return;
- }
-
- if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer)
- {
- if (!copied)
- {
- se = (StringExp *)e->copy();
- copied = 1;
- }
- goto Lcast;
- }
- if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer)
- {
- if (!copied)
- {
- se = (StringExp *)e->copy();
- copied = 1;
- }
- goto Lcast;
- }
-
- if (typeb->nextOf()->size() == tb->nextOf()->size())
- {
- if (!copied)
- {
- se = (StringExp *)e->copy();
- copied = 1;
- }
- if (tb->ty == Tsarray)
- goto L2; // handle possible change in static array dimension
- se->type = t;
- result = se;
- return;
- }
-
- if (e->committed)
- goto Lcast;
-
- #define X(tf,tt) ((int)(tf) * 256 + (int)(tt))
- {
- OutBuffer buffer;
- size_t newlen = 0;
- int tfty = typeb->nextOf()->toBasetype()->ty;
- int ttty = tb->nextOf()->toBasetype()->ty;
- switch (X(tfty, ttty))
- {
- case X(Tchar, Tchar):
- case X(Twchar,Twchar):
- case X(Tdchar,Tdchar):
- break;
-
- case X(Tchar, Twchar):
- for (size_t u = 0; u < e->len;)
- {
- unsigned c;
- const char *p = utf_decodeChar((utf8_t *)se->string, e->len, &u, &c);
- if (p)
- e->error("%s", p);
- else
- buffer.writeUTF16(c);
- }
- newlen = buffer.length() / 2;
- buffer.writeUTF16(0);
- goto L1;
-
- case X(Tchar, Tdchar):
- for (size_t u = 0; u < e->len;)
- {
- unsigned c;
- const char *p = utf_decodeChar((utf8_t *)se->string, e->len, &u, &c);
- if (p)
- e->error("%s", p);
- buffer.write4(c);
- newlen++;
- }
- buffer.write4(0);
- goto L1;
-
- case X(Twchar,Tchar):
- for (size_t u = 0; u < e->len;)
- {
- unsigned c;
- const char *p = utf_decodeWchar((unsigned short *)se->string, e->len, &u, &c);
- if (p)
- e->error("%s", p);
- else
- buffer.writeUTF8(c);
- }
- newlen = buffer.length();
- buffer.writeUTF8(0);
- goto L1;
-
- case X(Twchar,Tdchar):
- for (size_t u = 0; u < e->len;)
- {
- unsigned c;
- const char *p = utf_decodeWchar((unsigned short *)se->string, e->len, &u, &c);
- if (p)
- e->error("%s", p);
- buffer.write4(c);
- newlen++;
- }
- buffer.write4(0);
- goto L1;
-
- case X(Tdchar,Tchar):
- for (size_t u = 0; u < e->len; u++)
- {
- unsigned c = ((unsigned *)se->string)[u];
- if (!utf_isValidDchar(c))
- e->error("invalid UCS-32 char \\U%08x", c);
- else
- buffer.writeUTF8(c);
- newlen++;
- }
- newlen = buffer.length();
- buffer.writeUTF8(0);
- goto L1;
-
- case X(Tdchar,Twchar):
- for (size_t u = 0; u < e->len; u++)
- {
- unsigned c = ((unsigned *)se->string)[u];
- if (!utf_isValidDchar(c))
- e->error("invalid UCS-32 char \\U%08x", c);
- else
- buffer.writeUTF16(c);
- newlen++;
- }
- newlen = buffer.length() / 2;
- buffer.writeUTF16(0);
- goto L1;
-
- L1:
- if (!copied)
- {
- se = (StringExp *)e->copy();
- copied = 1;
- }
- se->string = buffer.extractData();
- se->len = newlen;
-
- {
- d_uns64 szx = tb->nextOf()->size();
- assert(szx <= 255);
- se->sz = (unsigned char)szx;
- }
- break;
-
- default:
- assert(typeb->nextOf()->size() != tb->nextOf()->size());
- goto Lcast;
- }
- }
- #undef X
- L2:
- assert(copied);
-
- // See if need to truncate or extend the literal
- if (tb->ty == Tsarray)
- {
- size_t dim2 = (size_t)((TypeSArray *)tb)->dim->toInteger();
-
- //printf("dim from = %d, to = %d\n", (int)se->len, (int)dim2);
-
- // Changing dimensions
- if (dim2 != se->len)
- {
- // Copy when changing the string literal
- size_t newsz = se->sz;
- size_t d = (dim2 < se->len) ? dim2 : se->len;
- void *s = (void *)mem.xmalloc((dim2 + 1) * newsz);
- memcpy(s, se->string, d * newsz);
- // Extend with 0, add terminating 0
- memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz);
- se->string = s;
- se->len = dim2;
- }
- }
- se->type = t;
- result = se;
- return;
-
- Lcast:
- result = new CastExp(e->loc, se, t);
- result->type = t; // so semantic() won't be run on e
- }
-
- void visit(AddrExp *e)
- {
- Type *tb;
-
- result = e;
-
- tb = t->toBasetype();
- e->type = e->type->toBasetype();
- if (!tb->equals(e->type))
- {
- // Look for pointers to functions where the functions are overloaded.
-
- if (e->e1->op == TOKoverloadset &&
- (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction)
- {
- OverExp *eo = (OverExp *)e->e1;
- FuncDeclaration *f = NULL;
- for (size_t i = 0; i < eo->vars->a.length; i++)
- {
- Dsymbol *s = eo->vars->a[i];
- FuncDeclaration *f2 = s->isFuncDeclaration();
- assert(f2);
- if (f2->overloadExactMatch(t->nextOf()))
- {
- if (f)
- {
- /* Error if match in more than one overload set,
- * even if one is a 'better' match than the other.
- */
- ScopeDsymbol::multiplyDefined(e->loc, f, f2);
- }
- else
- f = f2;
- }
- }
- if (f)
- {
- f->tookAddressOf++;
- SymOffExp *se = new SymOffExp(e->loc, f, 0, false);
- expressionSemantic(se, sc);
- // Let SymOffExp::castTo() do the heavy lifting
- visit(se);
- return;
- }
- }
-
- if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tfunction &&
- tb->ty == Tpointer && tb->nextOf()->ty == Tfunction &&
- e->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e->e1;
- FuncDeclaration *f = ve->var->isFuncDeclaration();
- if (f)
- {
- assert(f->isImportedSymbol());
- f = f->overloadExactMatch(tb->nextOf());
- if (f)
- {
- result = new VarExp(e->loc, f, false);
- result->type = f->type;
- result = new AddrExp(e->loc, result, t);
- return;
- }
- }
- }
-
- if (FuncDeclaration *f = isFuncAddress(e))
- {
- if (f->checkForwardRef(e->loc))
- {
- result = new ErrorExp();
- return;
- }
- }
-
- visit((Expression *)e);
- }
- result->type = t;
- }
-
- void visit(TupleExp *e)
- {
- if (e->type->equals(t))
- {
- result = e;
- return;
- }
-
- TupleExp *te = (TupleExp *)e->copy();
- te->e0 = e->e0 ? e->e0->copy() : NULL;
- te->exps = (Expressions *)e->exps->copy();
- for (size_t i = 0; i < te->exps->length; i++)
- {
- Expression *ex = (*te->exps)[i];
- ex = ex->castTo(sc, t);
- (*te->exps)[i] = ex;
- }
- result = te;
-
- /* Questionable behavior: In here, result->type is not set to t.
- * Therefoe:
- * TypeTuple!(int, int) values;
- * auto values2 = cast(long)values;
- * // typeof(values2) == TypeTuple!(int, int) !!
- *
- * Only when the casted tuple is immediately expanded, it would work.
- * auto arr = [cast(long)values];
- * // typeof(arr) == long[]
- */
- }
-
- void visit(ArrayLiteralExp *e)
- {
- if (e->type == t)
- {
- result = e;
- return;
- }
- ArrayLiteralExp *ae = e;
- Type *typeb = e->type->toBasetype();
- Type *tb = t->toBasetype();
- if ((tb->ty == Tarray || tb->ty == Tsarray) &&
- (typeb->ty == Tarray || typeb->ty == Tsarray))
- {
- if (tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)
- {
- // Don't do anything to cast non-void[] to void[]
- }
- else if (typeb->ty == Tsarray && typeb->nextOf()->toBasetype()->ty == Tvoid)
- {
- // Don't do anything for casting void[n] to others
- }
- else
- {
- if (tb->ty == Tsarray)
- {
- TypeSArray *tsa = (TypeSArray *)tb;
- if (e->elements->length != tsa->dim->toInteger())
- goto L1;
- }
-
- ae = (ArrayLiteralExp *)e->copy();
- if (e->basis)
- ae->basis = e->basis->castTo(sc, tb->nextOf());
- ae->elements = e->elements->copy();
- for (size_t i = 0; i < e->elements->length; i++)
- {
- Expression *ex = (*e->elements)[i];
- if (!ex)
- continue;
- ex = ex->castTo(sc, tb->nextOf());
- (*ae->elements)[i] = ex;
- }
- ae->type = t;
- result = ae;
- return;
- }
- }
- else if (tb->ty == Tpointer && typeb->ty == Tsarray)
- {
- Type *tp = typeb->nextOf()->pointerTo();
- if (!tp->equals(ae->type))
- {
- ae = (ArrayLiteralExp *)e->copy();
- ae->type = tp;
- }
- }
- else if (tb->ty == Tvector &&
- (typeb->ty == Tarray || typeb->ty == Tsarray))
- {
- // Convert array literal to vector type
- TypeVector *tv = (TypeVector *)tb;
- TypeSArray *tbase = (TypeSArray *)tv->basetype;
- assert(tbase->ty == Tsarray);
- const size_t edim = e->elements->length;
- const size_t tbasedim = tbase->dim->toInteger();
- if (edim > tbasedim)
- goto L1;
-
- ae = (ArrayLiteralExp *)e->copy();
- ae->type = tbase; // Bugzilla 12642
- ae->elements = e->elements->copy();
- Type *telement = tv->elementType();
- for (size_t i = 0; i < edim; i++)
- {
- Expression *ex = (*e->elements)[i];
- ex = ex->castTo(sc, telement);
- (*ae->elements)[i] = ex;
- }
- // Fill in the rest with the default initializer
- ae->elements->setDim(tbasedim);
- for (size_t i = edim; i < tbasedim; i++)
- {
- Expression *ex = typeb->nextOf()->defaultInitLiteral(e->loc);
- ex = ex->castTo(sc, telement);
- (*ae->elements)[i] = ex;
- }
- Expression *ev = new VectorExp(e->loc, ae, tb);
- ev = expressionSemantic(ev, sc);
- result = ev;
- return;
- }
- L1:
- visit((Expression *)ae);
- }
-
- void visit(AssocArrayLiteralExp *e)
- {
- if (e->type == t)
- {
- result = e;
- return;
- }
- Type *typeb = e->type->toBasetype();
- Type *tb = t->toBasetype();
- if (tb->ty == Taarray && typeb->ty == Taarray &&
- tb->nextOf()->toBasetype()->ty != Tvoid)
- {
- AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e->copy();
- ae->keys = e->keys->copy();
- ae->values = e->values->copy();
- assert(e->keys->length == e->values->length);
- for (size_t i = 0; i < e->keys->length; i++)
- {
- Expression *ex = (*e->values)[i];
- ex = ex->castTo(sc, tb->nextOf());
- (*ae->values)[i] = ex;
-
- ex = (*e->keys)[i];
- ex = ex->castTo(sc, ((TypeAArray *)tb)->index);
- (*ae->keys)[i] = ex;
- }
- ae->type = t;
- result = ae;
- return;
- }
- visit((Expression *)e);
- }
-
- void visit(SymOffExp *e)
- {
- if (e->type == t && !e->hasOverloads)
- {
- result = e;
- return;
- }
- Type *tb = t->toBasetype();
- Type *typeb = e->type->toBasetype();
-
- if (tb->equals(typeb))
- {
- result = e->copy();
- result->type = t;
- ((SymOffExp *)result)->hasOverloads = false;
- return;
- }
-
- // Look for pointers to functions where the functions are overloaded.
- if (e->hasOverloads &&
- typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction &&
- (tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction)
- {
- FuncDeclaration *f = e->var->isFuncDeclaration();
- f = f ? f->overloadExactMatch(tb->nextOf()) : NULL;
- if (f)
- {
- if (tb->ty == Tdelegate)
- {
- if (f->needThis() && hasThis(sc))
- {
- result = new DelegateExp(e->loc, new ThisExp(e->loc), f, false);
- result = expressionSemantic(result, sc);
- }
- else if (f->isNested())
- {
- result = new DelegateExp(e->loc, new IntegerExp(0), f, false);
- result = expressionSemantic(result, sc);
- }
- else if (f->needThis())
- {
- e->error("no `this` to create delegate for %s", f->toChars());
- result = new ErrorExp();
- return;
- }
- else
- {
- e->error("cannot cast from function pointer to delegate");
- result = new ErrorExp();
- return;
- }
- }
- else
- {
- result = new SymOffExp(e->loc, f, 0, false);
- result->type = t;
- }
- f->tookAddressOf++;
- return;
- }
- }
-
- if (FuncDeclaration *f = isFuncAddress(e))
- {
- if (f->checkForwardRef(e->loc))
- {
- result = new ErrorExp();
- return;
- }
- }
-
- visit((Expression *)e);
- }
-
- void visit(DelegateExp *e)
- {
- static const char msg[] = "cannot form delegate due to covariant return type";
-
- Type *tb = t->toBasetype();
- Type *typeb = e->type->toBasetype();
- if (!tb->equals(typeb) || e->hasOverloads)
- {
- // Look for delegates to functions where the functions are overloaded.
- if (typeb->ty == Tdelegate &&
- tb->ty == Tdelegate)
- {
- if (e->func)
- {
- FuncDeclaration *f = e->func->overloadExactMatch(tb->nextOf());
- if (f)
- {
- int offset;
- if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset)
- e->error("%s", msg);
- if (f != e->func) // if address not already marked as taken
- f->tookAddressOf++;
- result = new DelegateExp(e->loc, e->e1, f, false);
- result->type = t;
- return;
- }
- if (e->func->tintro)
- e->error("%s", msg);
- }
- }
-
- if (FuncDeclaration *f = isFuncAddress(e))
- {
- if (f->checkForwardRef(e->loc))
- {
- result = new ErrorExp();
- return;
- }
- }
-
- visit((Expression *)e);
- }
- else
- {
- int offset;
- e->func->tookAddressOf++;
- if (e->func->tintro && e->func->tintro->nextOf()->isBaseOf(e->func->type->nextOf(), &offset) && offset)
- e->error("%s", msg);
- result = e->copy();
- result->type = t;
- }
- }
-
- void visit(FuncExp *e)
- {
- //printf("FuncExp::castTo type = %s, t = %s\n", e->type->toChars(), t->toChars());
- FuncExp *fe;
- if (e->matchType(t, sc, &fe, 1) > MATCHnomatch)
- {
- result = fe;
- return;
- }
- visit((Expression *)e);
- }
-
- void visit(CondExp *e)
- {
- if (!e->type->equals(t))
- {
- result = new CondExp(e->loc, e->econd, e->e1->castTo(sc, t), e->e2->castTo(sc, t));
- result->type = t;
- return;
- }
- result = e;
- }
-
- void visit(CommaExp *e)
- {
- Expression *e2c = e->e2->castTo(sc, t);
-
- if (e2c != e->e2)
- {
- result = new CommaExp(e->loc, e->e1, e2c);
- result->type = e2c->type;
- }
- else
- {
- result = e;
- result->type = e->e2->type;
- }
- }
-
- void visit(SliceExp *e)
- {
- //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e->toChars(), e->type->toChars(), t->toChars());
- Type *typeb = e->type->toBasetype();
- Type *tb = t->toBasetype();
- if (e->type->equals(t) || typeb->ty != Tarray ||
- (tb->ty != Tarray && tb->ty != Tsarray))
- {
- visit((Expression *)e);
- return;
- }
-
- if (tb->ty == Tarray)
- {
- if (typeb->nextOf()->equivalent(tb->nextOf()))
- {
- // T[] to const(T)[]
- result = e->copy();
- result->type = t;
- }
- else
- {
- visit((Expression *)e);
- }
- return;
- }
-
- // Handle the cast from Tarray to Tsarray with CT-known slicing
-
- TypeSArray *tsa = (TypeSArray *)toStaticArrayType(e);
- if (tsa && tsa->size(e->loc) == tb->size(e->loc))
- {
- /* Match if the sarray sizes are equal:
- * T[a .. b] to const(T)[b-a]
- * T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim)
- *
- * If a SliceExp has Tsarray, it will become lvalue.
- * That's handled in SliceExp::isLvalue and toLvalue
- */
- result = e->copy();
- result->type = t;
- return;
- }
- if (tsa && tsa->dim->equals(((TypeSArray *)tb)->dim))
- {
- /* Match if the dimensions are equal
- * with the implicit conversion of e->e1:
- * cast(float[2]) [2.0, 1.0, 0.0][0..2];
- */
- Type *t1b = e->e1->type->toBasetype();
- if (t1b->ty == Tsarray)
- t1b = tb->nextOf()->sarrayOf(((TypeSArray *)t1b)->dim->toInteger());
- else if (t1b->ty == Tarray)
- t1b = tb->nextOf()->arrayOf();
- else if (t1b->ty == Tpointer)
- t1b = tb->nextOf()->pointerTo();
- else
- assert(0);
- if (e->e1->implicitConvTo(t1b) > MATCHnomatch)
- {
- Expression *e1x = e->e1->implicitCastTo(sc, t1b);
- assert(e1x->op != TOKerror);
- e = (SliceExp *)e->copy();
- e->e1 = e1x;
- e->type = t;
- result = e;
- return;
- }
- }
- e->error("cannot cast expression %s of type %s to %s",
- e->toChars(), tsa ? tsa->toChars() : e->type->toChars(),
- t->toChars());
- result = new ErrorExp();
- }
- };
-
- CastTo v(sc, t);
- e->accept(&v);
- return v.result;
-}
-
-/* ==================== inferType ====================== */
-
-/****************************************
- * Set type inference target
- * t Target type
- * flag 1: don't put an error when inference fails
- */
-
-Expression *inferType(Expression *e, Type *t, int flag)
-{
- class InferType : public Visitor
- {
- public:
- Type *t;
- int flag;
- Expression *result;
-
- InferType(Type *t, int flag)
- : t(t), flag(flag)
- {
- result = NULL;
- }
-
-
- void visit(Expression *e)
- {
- result = e;
- }
-
- void visit(ArrayLiteralExp *ale)
- {
- Type *tb = t->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- Type *tn = tb->nextOf();
- if (ale->basis)
- ale->basis = inferType(ale->basis, tn, flag);
- for (size_t i = 0; i < ale->elements->length; i++)
- {
- Expression *e = (*ale->elements)[i];
- if (e)
- {
- e = inferType(e, tn, flag);
- (*ale->elements)[i] = e;
- }
- }
- }
- result = ale;
- }
-
- void visit(AssocArrayLiteralExp *aale)
- {
- Type *tb = t->toBasetype();
- if (tb->ty == Taarray)
- {
- TypeAArray *taa = (TypeAArray *)tb;
- Type *ti = taa->index;
- Type *tv = taa->nextOf();
- for (size_t i = 0; i < aale->keys->length; i++)
- {
- Expression *e = (*aale->keys)[i];
- if (e)
- {
- e = inferType(e, ti, flag);
- (*aale->keys)[i] = e;
- }
- }
- for (size_t i = 0; i < aale->values->length; i++)
- {
- Expression *e = (*aale->values)[i];
- if (e)
- {
- e = inferType(e, tv, flag);
- (*aale->values)[i] = e;
- }
- }
- }
- result = aale;
- }
-
- void visit(FuncExp *fe)
- {
- //printf("FuncExp::inferType('%s'), to=%s\n", fe->type ? fe->type->toChars() : "null", t->toChars());
- if (t->ty == Tdelegate ||
- (t->ty == Tpointer && t->nextOf()->ty == Tfunction))
- {
- fe->fd->treq = t;
- }
- result = fe;
- }
-
- void visit(CondExp *ce)
- {
- Type *tb = t->toBasetype();
- ce->e1 = inferType(ce->e1, tb, flag);
- ce->e2 = inferType(ce->e2, tb, flag);
- result = ce;
- }
- };
-
- if (!t)
- return e;
-
- InferType v(t, flag);
- e->accept(&v);
- return v.result;
-}
-
-/* ==================== ====================== */
-
-/****************************************
- * Scale addition/subtraction to/from pointer.
- */
-
-Expression *scaleFactor(BinExp *be, Scope *sc)
-{
- Type *t1b = be->e1->type->toBasetype();
- Type *t2b = be->e2->type->toBasetype();
- Expression *eoff;
-
- if (t1b->ty == Tpointer && t2b->isintegral())
- {
- // Need to adjust operator by the stride
- // Replace (ptr + int) with (ptr + (int * stride))
- Type *t = Type::tptrdiff_t;
-
- d_uns64 stride = t1b->nextOf()->size(be->loc);
- if (!t->equals(t2b))
- be->e2 = be->e2->castTo(sc, t);
- eoff = be->e2;
- be->e2 = new MulExp(be->loc, be->e2, new IntegerExp(Loc(), stride, t));
- be->e2->type = t;
- be->type = be->e1->type;
- }
- else if (t2b->ty == Tpointer && t1b->isintegral())
- {
- // Need to adjust operator by the stride
- // Replace (int + ptr) with (ptr + (int * stride))
- Type *t = Type::tptrdiff_t;
- Expression *e;
-
- d_uns64 stride = t2b->nextOf()->size(be->loc);
- if (!t->equals(t1b))
- e = be->e1->castTo(sc, t);
- else
- e = be->e1;
- eoff = e;
- e = new MulExp(be->loc, e, new IntegerExp(Loc(), stride, t));
- e->type = t;
- be->type = be->e2->type;
- be->e1 = be->e2;
- be->e2 = e;
- }
- else
- assert(0);
-
- if (sc->func && !sc->intypeof)
- {
- eoff = eoff->optimize(WANTvalue);
- if (eoff->op == TOKint64 && eoff->toInteger() == 0)
- ;
- else if (sc->func->setUnsafe())
- {
- be->error("pointer arithmetic not allowed in @safe functions");
- return new ErrorExp();
- }
- }
-
- return be;
-}
-
-/**************************************
- * Return true if e is an empty array literal with dimensionality
- * equal to or less than type of other array.
- * [], [[]], [[[]]], etc.
- * I.e., make sure that [1,2] is compatible with [],
- * [[1,2]] is compatible with [[]], etc.
- */
-bool isVoidArrayLiteral(Expression *e, Type *other)
-{
- while (e->op == TOKarrayliteral && e->type->ty == Tarray
- && (((ArrayLiteralExp *)e)->elements->length == 1))
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
- e = ale->getElement(0);
- if (other->ty == Tsarray || other->ty == Tarray)
- other = other->nextOf();
- else
- return false;
- }
- if (other->ty != Tsarray && other->ty != Tarray)
- return false;
- Type *t = e->type;
- return (e->op == TOKarrayliteral && t->ty == Tarray &&
- t->nextOf()->ty == Tvoid &&
- ((ArrayLiteralExp *)e)->elements->length == 0);
-}
-
-// used by deduceType()
-Type *rawTypeMerge(Type *t1, Type *t2)
-{
- if (t1->equals(t2))
- return t1;
- if (t1->equivalent(t2))
- return t1->castMod(MODmerge(t1->mod, t2->mod));
-
- Type *t1b = t1->toBasetype();
- Type *t2b = t2->toBasetype();
- if (t1b->equals(t2b))
- return t1b;
- if (t1b->equivalent(t2b))
- return t1b->castMod(MODmerge(t1b->mod, t2b->mod));
-
- TY ty = (TY)impcnvResult[t1b->ty][t2b->ty];
- if (ty != Terror)
- return Type::basic[ty];
-
- return NULL;
-}
-
-/**************************************
- * Combine types.
- * Output:
- * *pt merged type, if *pt is not NULL
- * *pe1 rewritten e1
- * *pe2 rewritten e2
- * Returns:
- * true success
- * false failed
- */
-
-bool typeMerge(Scope *sc, TOK op, Type **pt, Expression **pe1, Expression **pe2)
-{
- //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars());
-
- MATCH m;
- Expression *e1 = *pe1;
- Expression *e2 = *pe2;
- Type *t1b = e1->type->toBasetype();
- Type *t2b = e2->type->toBasetype();
-
- if (op != TOKquestion ||
- (t1b->ty != t2b->ty && (t1b->isTypeBasic() && t2b->isTypeBasic())))
- {
- e1 = integralPromotions(e1, sc);
- e2 = integralPromotions(e2, sc);
- }
-
- Type *t1 = e1->type;
- Type *t2 = e2->type;
- assert(t1);
- Type *t = t1;
-
- /* The start type of alias this type recursion.
- * In following case, we should save A, and stop recursion
- * if it appears again.
- * X -> Y -> [A] -> B -> A -> B -> ...
- */
- Type *att1 = NULL;
- Type *att2 = NULL;
-
- //if (t1) printf("\tt1 = %s\n", t1->toChars());
- //if (t2) printf("\tt2 = %s\n", t2->toChars());
- assert(t2);
-
- if (t1->mod != t2->mod &&
- t1->ty == Tenum && t2->ty == Tenum &&
- ((TypeEnum *)t1)->sym == ((TypeEnum *)t2)->sym)
- {
- unsigned char mod = MODmerge(t1->mod, t2->mod);
- t1 = t1->castMod(mod);
- t2 = t2->castMod(mod);
- }
-
-Lagain:
- t1b = t1->toBasetype();
- t2b = t2->toBasetype();
-
- TY ty = (TY)impcnvResult[t1b->ty][t2b->ty];
- if (ty != Terror)
- {
- TY ty1 = (TY)impcnvType1[t1b->ty][t2b->ty];
- TY ty2 = (TY)impcnvType2[t1b->ty][t2b->ty];
-
- if (t1b->ty == ty1) // if no promotions
- {
- if (t1->equals(t2))
- {
- t = t1;
- goto Lret;
- }
-
- if (t1b->equals(t2b))
- {
- t = t1b;
- goto Lret;
- }
- }
-
- t = Type::basic[ty];
-
- t1 = Type::basic[ty1];
- t2 = Type::basic[ty2];
- e1 = e1->castTo(sc, t1);
- e2 = e2->castTo(sc, t2);
- //printf("after typeCombine():\n");
- //print();
- //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2);
- goto Lret;
- }
-
- t1 = t1b;
- t2 = t2b;
-
- if (t1->ty == Ttuple || t2->ty == Ttuple)
- goto Lincompatible;
-
- if (t1->equals(t2))
- {
- // merging can not result in new enum type
- if (t->ty == Tenum)
- t = t1b;
- }
- else if ((t1->ty == Tpointer && t2->ty == Tpointer) ||
- (t1->ty == Tdelegate && t2->ty == Tdelegate))
- {
- // Bring pointers to compatible type
- Type *t1n = t1->nextOf();
- Type *t2n = t2->nextOf();
-
- if (t1n->equals(t2n))
- ;
- else if (t1n->ty == Tvoid) // pointers to void are always compatible
- t = t2;
- else if (t2n->ty == Tvoid)
- ;
- else if (t1->implicitConvTo(t2))
- {
- goto Lt2;
- }
- else if (t2->implicitConvTo(t1))
- {
- goto Lt1;
- }
- else if (t1n->ty == Tfunction && t2n->ty == Tfunction)
- {
- TypeFunction *tf1 = (TypeFunction *)t1n;
- TypeFunction *tf2 = (TypeFunction *)t2n;
- tf1->purityLevel();
- tf2->purityLevel();
-
- TypeFunction *d = (TypeFunction *)tf1->syntaxCopy();
-
- if (tf1->purity != tf2->purity)
- d->purity = PUREimpure;
- assert(d->purity != PUREfwdref);
-
- d->isnothrow = (tf1->isnothrow && tf2->isnothrow);
- d->isnogc = (tf1->isnogc && tf2->isnogc);
-
- if (tf1->trust == tf2->trust)
- d->trust = tf1->trust;
- else if (tf1->trust <= TRUSTsystem || tf2->trust <= TRUSTsystem)
- d->trust = TRUSTsystem;
- else
- d->trust = TRUSTtrusted;
-
- Type *tx = NULL;
- if (t1->ty == Tdelegate)
- {
- tx = new TypeDelegate(d);
- }
- else
- tx = d->pointerTo();
-
- tx = typeSemantic(tx, e1->loc, sc);
-
- if (t1->implicitConvTo(tx) && t2->implicitConvTo(tx))
- {
- t = tx;
- e1 = e1->castTo(sc, t);
- e2 = e2->castTo(sc, t);
- goto Lret;
- }
- goto Lincompatible;
- }
- else if (t1n->mod != t2n->mod)
- {
- if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared())
- goto Lincompatible;
- unsigned char mod = MODmerge(t1n->mod, t2n->mod);
- t1 = t1n->castMod(mod)->pointerTo();
- t2 = t2n->castMod(mod)->pointerTo();
- t = t1;
- goto Lagain;
- }
- else if (t1n->ty == Tclass && t2n->ty == Tclass)
- {
- ClassDeclaration *cd1 = t1n->isClassHandle();
- ClassDeclaration *cd2 = t2n->isClassHandle();
- int offset;
-
- if (cd1->isBaseOf(cd2, &offset))
- {
- if (offset)
- e2 = e2->castTo(sc, t);
- }
- else if (cd2->isBaseOf(cd1, &offset))
- {
- t = t2;
- if (offset)
- e1 = e1->castTo(sc, t);
- }
- else
- goto Lincompatible;
- }
- else
- {
- t1 = t1n->constOf()->pointerTo();
- t2 = t2n->constOf()->pointerTo();
- if (t1->implicitConvTo(t2))
- {
- goto Lt2;
- }
- else if (t2->implicitConvTo(t1))
- {
- goto Lt1;
- }
- goto Lincompatible;
- }
- }
- else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
- ((e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid) ||
- (e2->op == TOKarrayliteral && t2->ty == Tsarray && t2->nextOf()->ty == Tvoid && ((TypeSArray *)t2)->dim->toInteger() == 0) ||
- (isVoidArrayLiteral(e2, t1)))
- )
- {
- /* (T[n] op void*) => T[]
- * (T[] op void*) => T[]
- * (T[n] op void[0]) => T[]
- * (T[] op void[0]) => T[]
- * (T[n] op void[]) => T[]
- * (T[] op void[]) => T[]
- */
- goto Lx1;
- }
- else if ((t2->ty == Tsarray || t2->ty == Tarray) &&
- ((e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid) ||
- (e1->op == TOKarrayliteral && t1->ty == Tsarray && t1->nextOf()->ty == Tvoid && ((TypeSArray *)t1)->dim->toInteger() == 0) ||
- (isVoidArrayLiteral(e1, t2)))
- )
- {
- /* (void* op T[n]) => T[]
- * (void* op T[]) => T[]
- * (void[0] op T[n]) => T[]
- * (void[0] op T[]) => T[]
- * (void[] op T[n]) => T[]
- * (void[] op T[]) => T[]
- */
- goto Lx2;
- }
- else if ((t1->ty == Tsarray || t1->ty == Tarray) &&
- (m = t1->implicitConvTo(t2)) != MATCHnomatch)
- {
- // Bugzilla 7285: Tsarray op [x, y, ...] should to be Tsarray
- // Bugzilla 14737: Tsarray ~ [x, y, ...] should to be Tarray
- if (t1->ty == Tsarray && e2->op == TOKarrayliteral && op != TOKcat)
- goto Lt1;
- if (m == MATCHconst &&
- (op == TOKaddass || op == TOKminass || op == TOKmulass ||
- op == TOKdivass || op == TOKmodass || op == TOKpowass ||
- op == TOKandass || op == TOKorass || op == TOKxorass)
- )
- {
- // Don't make the lvalue const
- t = t2;
- goto Lret;
- }
- goto Lt2;
- }
- else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1))
- {
- // Bugzilla 7285 & 14737
- if (t2->ty == Tsarray && e1->op == TOKarrayliteral && op != TOKcat)
- goto Lt2;
- goto Lt1;
- }
- else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) &&
- (t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) &&
- t1->nextOf()->mod != t2->nextOf()->mod
- )
- {
- /* If one is mutable and the other invariant, then retry
- * with both of them as const
- */
- Type *t1n = t1->nextOf();
- Type *t2n = t2->nextOf();
- unsigned char mod;
- if (e1->op == TOKnull && e2->op != TOKnull)
- mod = t2n->mod;
- else if (e1->op != TOKnull && e2->op == TOKnull)
- mod = t1n->mod;
- else if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared())
- goto Lincompatible;
- else
- mod = MODmerge(t1n->mod, t2n->mod);
-
- if (t1->ty == Tpointer)
- t1 = t1n->castMod(mod)->pointerTo();
- else
- t1 = t1n->castMod(mod)->arrayOf();
-
- if (t2->ty == Tpointer)
- t2 = t2n->castMod(mod)->pointerTo();
- else
- t2 = t2n->castMod(mod)->arrayOf();
- t = t1;
- goto Lagain;
- }
- else if (t1->ty == Tclass && t2->ty == Tclass)
- {
- if (t1->mod != t2->mod)
- {
- unsigned char mod;
- if (e1->op == TOKnull && e2->op != TOKnull)
- mod = t2->mod;
- else if (e1->op != TOKnull && e2->op == TOKnull)
- mod = t1->mod;
- else if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
- goto Lincompatible;
- else
- mod = MODmerge(t1->mod, t2->mod);
- t1 = t1->castMod(mod);
- t2 = t2->castMod(mod);
- t = t1;
- goto Lagain;
- }
- goto Lcc;
- }
- else if (t1->ty == Tclass || t2->ty == Tclass)
- {
-Lcc:
- while (1)
- {
- MATCH i1 = e2->implicitConvTo(t1);
- MATCH i2 = e1->implicitConvTo(t2);
-
- if (i1 && i2)
- {
- // We have the case of class vs. void*, so pick class
- if (t1->ty == Tpointer)
- i1 = MATCHnomatch;
- else if (t2->ty == Tpointer)
- i2 = MATCHnomatch;
- }
-
- if (i2)
- {
- e2 = e2->castTo(sc, t2);
- goto Lt2;
- }
- else if (i1)
- {
- e1 = e1->castTo(sc, t1);
- goto Lt1;
- }
- else if (t1->ty == Tclass && t2->ty == Tclass)
- {
- TypeClass *tc1 = (TypeClass *)t1;
- TypeClass *tc2 = (TypeClass *)t2;
-
- /* Pick 'tightest' type
- */
- ClassDeclaration *cd1 = tc1->sym->baseClass;
- ClassDeclaration *cd2 = tc2->sym->baseClass;
-
- if (cd1 && cd2)
- {
- t1 = cd1->type->castMod(t1->mod);
- t2 = cd2->type->castMod(t2->mod);
- }
- else if (cd1)
- t1 = cd1->type;
- else if (cd2)
- t2 = cd2->type;
- else
- goto Lincompatible;
- }
- else if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis)
- {
- if (att1 && e1->type == att1)
- goto Lincompatible;
- if (!att1 && e1->type->checkAliasThisRec())
- att1 = e1->type;
- //printf("att tmerge(c || c) e1 = %s\n", e1->type->toChars());
- e1 = resolveAliasThis(sc, e1);
- t1 = e1->type;
- continue;
- }
- else if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis)
- {
- if (att2 && e2->type == att2)
- goto Lincompatible;
- if (!att2 && e2->type->checkAliasThisRec())
- att2 = e2->type;
- //printf("att tmerge(c || c) e2 = %s\n", e2->type->toChars());
- e2 = resolveAliasThis(sc, e2);
- t2 = e2->type;
- continue;
- }
- else
- goto Lincompatible;
- }
- }
- else if (t1->ty == Tstruct && t2->ty == Tstruct)
- {
- if (t1->mod != t2->mod)
- {
- if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
- goto Lincompatible;
- unsigned char mod = MODmerge(t1->mod, t2->mod);
- t1 = t1->castMod(mod);
- t2 = t2->castMod(mod);
- t = t1;
- goto Lagain;
- }
-
- TypeStruct *ts1 = (TypeStruct *)t1;
- TypeStruct *ts2 = (TypeStruct *)t2;
- if (ts1->sym != ts2->sym)
- {
- if (!ts1->sym->aliasthis && !ts2->sym->aliasthis)
- goto Lincompatible;
-
- MATCH i1 = MATCHnomatch;
- MATCH i2 = MATCHnomatch;
-
- Expression *e1b = NULL;
- Expression *e2b = NULL;
- if (ts2->sym->aliasthis)
- {
- if (att2 && e2->type == att2)
- goto Lincompatible;
- if (!att2 && e2->type->checkAliasThisRec())
- att2 = e2->type;
- //printf("att tmerge(s && s) e2 = %s\n", e2->type->toChars());
- e2b = resolveAliasThis(sc, e2);
- i1 = e2b->implicitConvTo(t1);
- }
- if (ts1->sym->aliasthis)
- {
- if (att1 && e1->type == att1)
- goto Lincompatible;
- if (!att1 && e1->type->checkAliasThisRec())
- att1 = e1->type;
- //printf("att tmerge(s && s) e1 = %s\n", e1->type->toChars());
- e1b = resolveAliasThis(sc, e1);
- i2 = e1b->implicitConvTo(t2);
- }
- if (i1 && i2)
- goto Lincompatible;
-
- if (i1)
- goto Lt1;
- else if (i2)
- goto Lt2;
-
- if (e1b)
- {
- e1 = e1b;
- t1 = e1b->type->toBasetype();
- }
- if (e2b)
- {
- e2 = e2b;
- t2 = e2b->type->toBasetype();
- }
- t = t1;
- goto Lagain;
- }
- }
- else if (t1->ty == Tstruct || t2->ty == Tstruct)
- {
- if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis)
- {
- if (att1 && e1->type == att1)
- goto Lincompatible;
- if (!att1 && e1->type->checkAliasThisRec())
- att1 = e1->type;
- //printf("att tmerge(s || s) e1 = %s\n", e1->type->toChars());
- e1 = resolveAliasThis(sc, e1);
- t1 = e1->type;
- t = t1;
- goto Lagain;
- }
- if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis)
- {
- if (att2 && e2->type == att2)
- goto Lincompatible;
- if (!att2 && e2->type->checkAliasThisRec())
- att2 = e2->type;
- //printf("att tmerge(s || s) e2 = %s\n", e2->type->toChars());
- e2 = resolveAliasThis(sc, e2);
- t2 = e2->type;
- t = t2;
- goto Lagain;
- }
- goto Lincompatible;
- }
- else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2))
- {
- goto Lt2;
- }
- else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1))
- {
- goto Lt1;
- }
- else if (t1->ty == Tsarray && t2->ty == Tsarray &&
- e2->implicitConvTo(t1->nextOf()->arrayOf()))
- {
- Lx1:
- t = t1->nextOf()->arrayOf(); // T[]
- e1 = e1->castTo(sc, t);
- e2 = e2->castTo(sc, t);
- }
- else if (t1->ty == Tsarray && t2->ty == Tsarray &&
- e1->implicitConvTo(t2->nextOf()->arrayOf()))
- {
- Lx2:
- t = t2->nextOf()->arrayOf();
- e1 = e1->castTo(sc, t);
- e2 = e2->castTo(sc, t);
- }
- else if (t1->ty == Tvector && t2->ty == Tvector)
- {
- // Bugzilla 13841, all vector types should have no common types between
- // different vectors, even though their sizes are same.
- TypeVector *tv1 = (TypeVector *)t1;
- TypeVector *tv2 = (TypeVector *)t2;
- if (!tv1->basetype->equals(tv2->basetype))
- goto Lincompatible;
-
- goto LmodCompare;
- }
- else if (t1->ty == Tvector && t2->ty != Tvector &&
- e2->implicitConvTo(t1))
- {
- e2 = e2->castTo(sc, t1);
- t2 = t1;
- t = t1;
- goto Lagain;
- }
- else if (t2->ty == Tvector && t1->ty != Tvector &&
- e1->implicitConvTo(t2))
- {
- e1 = e1->castTo(sc, t2);
- t1 = t2;
- t = t1;
- goto Lagain;
- }
- else if (t1->isintegral() && t2->isintegral())
- {
- if (t1->ty != t2->ty)
- {
- if (t1->ty == Tvector || t2->ty == Tvector)
- goto Lincompatible;
- e1 = integralPromotions(e1, sc);
- e2 = integralPromotions(e2, sc);
- t1 = e1->type;
- t2 = e2->type;
- goto Lagain;
- }
- assert(t1->ty == t2->ty);
-LmodCompare:
- if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared())
- goto Lincompatible;
- unsigned char mod = MODmerge(t1->mod, t2->mod);
-
- t1 = t1->castMod(mod);
- t2 = t2->castMod(mod);
- t = t1;
- e1 = e1->castTo(sc, t);
- e2 = e2->castTo(sc, t);
- goto Lagain;
- }
- else if (t1->ty == Tnull && t2->ty == Tnull)
- {
- unsigned char mod = MODmerge(t1->mod, t2->mod);
-
- t = t1->castMod(mod);
- e1 = e1->castTo(sc, t);
- e2 = e2->castTo(sc, t);
- goto Lret;
- }
- else if (t2->ty == Tnull &&
- (t1->ty == Tpointer || t1->ty == Taarray || t1->ty == Tarray))
- {
- goto Lt1;
- }
- else if (t1->ty == Tnull &&
- (t2->ty == Tpointer || t2->ty == Taarray || t2->ty == Tarray))
- {
- goto Lt2;
- }
- else if (t1->ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1))
- {
- if (e2->implicitConvTo(t1->nextOf()))
- {
- // T[] op T
- // T[] op cast(T)U
- e2 = e2->castTo(sc, t1->nextOf());
- t = t1->nextOf()->arrayOf();
- }
- else if (t1->nextOf()->implicitConvTo(e2->type))
- {
- // (cast(T)U)[] op T (Bugzilla 12780)
- // e1 is left as U[], it will be handled in arrayOp() later.
- t = e2->type->arrayOf();
- }
- else if (t2->ty == Tarray && isArrayOpOperand(e2))
- {
- if (t1->nextOf()->implicitConvTo(t2->nextOf()))
- {
- // (cast(T)U)[] op T[] (Bugzilla 12780)
- // e1 is left as U[], it will be handled in arrayOp() later.
- t = t2->nextOf()->arrayOf();
- }
- else if (t2->nextOf()->implicitConvTo(t1->nextOf()))
- {
- // T[] op (cast(T)U)[] (Bugzilla 12780)
- // e2 is left as U[], it will be handled in arrayOp() later.
- t = t1->nextOf()->arrayOf();
- }
- else
- goto Lincompatible;
- }
- else
- goto Lincompatible;
- }
- else if (t2->ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e2))
- {
- if (e1->implicitConvTo(t2->nextOf()))
- {
- // T op T[]
- // cast(T)U op T[]
- e1 = e1->castTo(sc, t2->nextOf());
- t = t2->nextOf()->arrayOf();
- }
- else if (t2->nextOf()->implicitConvTo(e1->type))
- {
- // T op (cast(T)U)[] (Bugzilla 12780)
- // e2 is left as U[], it will be handled in arrayOp() later.
- t = e1->type->arrayOf();
- }
- else
- goto Lincompatible;
-
- //printf("test %s\n", Token::toChars(op));
- e1 = e1->optimize(WANTvalue);
- if (isCommutative(op) && e1->isConst())
- {
- /* Swap operands to minimize number of functions generated
- */
- //printf("swap %s\n", Token::toChars(op));
- Expression *tmp = e1;
- e1 = e2;
- e2 = tmp;
- }
- }
- else
- {
- Lincompatible:
- return false;
- }
-Lret:
- if (!*pt)
- *pt = t;
- *pe1 = e1;
- *pe2 = e2;
- //print();
- return true;
-
-
-Lt1:
- e2 = e2->castTo(sc, t1);
- t = t1;
- goto Lret;
-
-Lt2:
- e1 = e1->castTo(sc, t2);
- t = t2;
- goto Lret;
-}
-
-/************************************
- * Bring leaves to common type.
- * Returns ErrorExp if error occurs. otherwise returns NULL.
- */
-
-Expression *typeCombine(BinExp *be, Scope *sc)
-{
- Type *t1 = be->e1->type->toBasetype();
- Type *t2 = be->e2->type->toBasetype();
-
- if (be->op == TOKmin || be->op == TOKadd)
- {
- // struct+struct, and class+class are errors
- if (t1->ty == Tstruct && t2->ty == Tstruct)
- goto Lerror;
- else if (t1->ty == Tclass && t2->ty == Tclass)
- goto Lerror;
- else if (t1->ty == Taarray && t2->ty == Taarray)
- goto Lerror;
- }
-
- if (!typeMerge(sc, be->op, &be->type, &be->e1, &be->e2))
- goto Lerror;
- // If the types have no value, return an error
- if (be->e1->op == TOKerror)
- return be->e1;
- if (be->e2->op == TOKerror)
- return be->e2;
- return NULL;
-
-Lerror:
- Expression *ex = be->incompatibleTypes();
- if (ex->op == TOKerror)
- return ex;
- return new ErrorExp();
-}
-
-/***********************************
- * Do integral promotions (convertchk).
- * Don't convert <array of> to <pointer to>
- */
-
-Expression *integralPromotions(Expression *e, Scope *sc)
-{
- //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars());
- switch (e->type->toBasetype()->ty)
- {
- case Tvoid:
- e->error("void has no value");
- return new ErrorExp();
-
- case Tint8:
- case Tuns8:
- case Tint16:
- case Tuns16:
- case Tbool:
- case Tchar:
- case Twchar:
- e = e->castTo(sc, Type::tint32);
- break;
-
- case Tdchar:
- e = e->castTo(sc, Type::tuns32);
- break;
- default:
- break;
- }
- return e;
-}
-
-/***********************************
- * See if both types are arrays that can be compared
- * for equality. Return true if so.
- * If they are arrays, but incompatible, issue error.
- * This is to enable comparing things like an immutable
- * array with a mutable one.
- */
-
-bool arrayTypeCompatible(Loc loc, Type *t1, Type *t2)
-{
- t1 = t1->toBasetype()->merge2();
- t2 = t2->toBasetype()->merge2();
-
- if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
- (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer))
- {
- if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst &&
- t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst &&
- (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid))
- {
- error(loc, "array equality comparison type mismatch, %s vs %s", t1->toChars(), t2->toChars());
- }
- return true;
- }
- return false;
-}
-
-/***********************************
- * See if both types are arrays that can be compared
- * for equality without any casting. Return true if so.
- * This is to enable comparing things like an immutable
- * array with a mutable one.
- */
-bool arrayTypeCompatibleWithoutCasting(Type *t1, Type *t2)
-{
- t1 = t1->toBasetype();
- t2 = t2->toBasetype();
-
- if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
- t2->ty == t1->ty)
- {
- if (t1->nextOf()->implicitConvTo(t2->nextOf()) >= MATCHconst ||
- t2->nextOf()->implicitConvTo(t1->nextOf()) >= MATCHconst)
- return true;
- }
- return false;
-}
-
-/******************************************************************/
-
-/* Determine the integral ranges of an expression.
- * This is used to determine if implicit narrowing conversions will
- * be allowed.
- */
-
-IntRange getIntRange(Expression *e)
-{
- class IntRangeVisitor : public Visitor
- {
- public:
- IntRange range;
-
- void visit(Expression *e)
- {
- range = IntRange::fromType(e->type);
- }
-
- void visit(IntegerExp *e)
- {
- range = IntRange(SignExtendedNumber(e->getInteger())).cast(e->type);
- }
-
- void visit(CastExp *e)
- {
- range = getIntRange(e->e1).cast(e->type);
- }
-
- void visit(AddExp *e)
- {
- IntRange ir1 = getIntRange(e->e1);
- IntRange ir2 = getIntRange(e->e2);
- range = (ir1 + ir2).cast(e->type);
- }
-
- void visit(MinExp *e)
- {
- IntRange ir1 = getIntRange(e->e1);
- IntRange ir2 = getIntRange(e->e2);
- range = (ir1 - ir2).cast(e->type);
- }
-
- void visit(DivExp *e)
- {
- IntRange ir1 = getIntRange(e->e1);
- IntRange ir2 = getIntRange(e->e2);
-
- range = (ir1 / ir2).cast(e->type);
- }
-
- void visit(MulExp *e)
- {
- IntRange ir1 = getIntRange(e->e1);
- IntRange ir2 = getIntRange(e->e2);
-
- range = (ir1 * ir2).cast(e->type);
- }
-
- void visit(ModExp *e)
- {
- IntRange ir1 = getIntRange(e->e1);
- IntRange ir2 = getIntRange(e->e2);
-
- // Modding on 0 is invalid anyway.
- if (!ir2.absNeg().imin.negative)
- {
- visit((Expression *)e);
- return;
- }
- range = (ir1 % ir2).cast(e->type);
- }
-
- void visit(AndExp *e)
- {
- IntRange result;
- bool hasResult = false;
- result.unionOrAssign(getIntRange(e->e1) & getIntRange(e->e2), hasResult);
-
- assert(hasResult);
- range = result.cast(e->type);
- }
-
- void visit(OrExp *e)
- {
- IntRange result;
- bool hasResult = false;
- result.unionOrAssign(getIntRange(e->e1) | getIntRange(e->e2), hasResult);
-
- assert(hasResult);
- range = result.cast(e->type);
- }
-
- void visit(XorExp *e)
- {
- IntRange result;
- bool hasResult = false;
- result.unionOrAssign(getIntRange(e->e1) ^ getIntRange(e->e2), hasResult);
-
- assert(hasResult);
- range = result.cast(e->type);
- }
-
- void visit(ShlExp *e)
- {
- IntRange ir1 = getIntRange(e->e1);
- IntRange ir2 = getIntRange(e->e2);
-
- range = (ir1 << ir2).cast(e->type);
- }
-
- void visit(ShrExp *e)
- {
- IntRange ir1 = getIntRange(e->e1);
- IntRange ir2 = getIntRange(e->e2);
-
- range = (ir1 >> ir2).cast(e->type);
- }
-
- void visit(UshrExp *e)
- {
- IntRange ir1 = getIntRange(e->e1).castUnsigned(e->e1->type);
- IntRange ir2 = getIntRange(e->e2);
-
- range = (ir1 >> ir2).cast(e->type);
- }
-
- void visit(AssignExp *e)
- {
- range = getIntRange(e->e2).cast(e->type);
- }
-
- void visit(CondExp *e)
- {
- // No need to check e->econd; assume caller has called optimize()
- IntRange ir1 = getIntRange(e->e1);
- IntRange ir2 = getIntRange(e->e2);
- range = ir1.unionWith(ir2).cast(e->type);
- }
-
- void visit(VarExp *e)
- {
- Expression *ie;
- VarDeclaration* vd = e->var->isVarDeclaration();
- if (vd && vd->range)
- range = vd->range->cast(e->type);
- else if (vd && vd->_init && !vd->type->isMutable() &&
- (ie = vd->getConstInitializer()) != NULL)
- ie->accept(this);
- else
- visit((Expression *)e);
- }
-
- void visit(CommaExp *e)
- {
- e->e2->accept(this);
- }
-
- void visit(ComExp *e)
- {
- IntRange ir = getIntRange(e->e1);
- range = IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative),
- SignExtendedNumber(~ir.imin.value, !ir.imin.negative)).cast(e->type);
- }
-
- void visit(NegExp *e)
- {
- IntRange ir = getIntRange(e->e1);
- range = (-ir).cast(e->type);
- }
- };
-
- IntRangeVisitor v;
- e->accept(&v);
- return v.range;
-}
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
new file mode 100644
index 0000000..4c70565
--- /dev/null
+++ b/gcc/d/dmd/dcast.d
@@ -0,0 +1,3741 @@
+/**
+ * Semantic analysis for cast-expressions.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d, _dcast.d)
+ * Documentation: https://dlang.org/phobos/dmd_dcast.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dcast.d
+ */
+
+module dmd.dcast;
+
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arrayop;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.errors;
+import dmd.escape;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.impcnvtab;
+import dmd.id;
+import dmd.init;
+import dmd.intrange;
+import dmd.mtype;
+import dmd.opover;
+import dmd.root.ctfloat;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+import dmd.tokens;
+import dmd.typesem;
+import dmd.utf;
+import dmd.visitor;
+
+enum LOG = false;
+
+/**
+ * Attempt to implicitly cast the expression into type `t`.
+ *
+ * This routine will change `e`. To check the matching level,
+ * use `implicitConvTo`.
+ *
+ * Params:
+ * e = Expression that is to be casted
+ * sc = Current scope
+ * t = Expected resulting type
+ *
+ * Returns:
+ * The resulting casted expression (mutating `e`), or `ErrorExp`
+ * if such an implicit conversion is not possible.
+ */
+Expression implicitCastTo(Expression e, Scope* sc, Type t)
+{
+ extern (C++) final class ImplicitCastTo : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ Type t;
+ Scope* sc;
+ Expression result;
+
+ extern (D) this(Scope* sc, Type t)
+ {
+ this.sc = sc;
+ this.t = t;
+ }
+
+ override void visit(Expression e)
+ {
+ //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
+
+ if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t))
+ {
+ if (match == MATCH.constant && (e.type.constConv(t) || !e.isLvalue() && e.type.equivalent(t)))
+ {
+ /* Do not emit CastExp for const conversions and
+ * unique conversions on rvalue.
+ */
+ result = e.copy();
+ result.type = t;
+ return;
+ }
+
+ auto ad = isAggregate(e.type);
+ if (ad && ad.aliasthis)
+ {
+ auto ts = ad.type.isTypeStruct();
+ const adMatch = ts
+ ? ts.implicitConvToWithoutAliasThis(t)
+ : ad.type.isTypeClass().implicitConvToWithoutAliasThis(t);
+
+ if (!adMatch)
+ {
+ Type tob = t.toBasetype();
+ Type t1b = e.type.toBasetype();
+ if (ad != isAggregate(tob))
+ {
+ if (t1b.ty == Tclass && tob.ty == Tclass)
+ {
+ ClassDeclaration t1cd = t1b.isClassHandle();
+ ClassDeclaration tocd = tob.isClassHandle();
+ int offset;
+ if (tocd.isBaseOf(t1cd, &offset))
+ {
+ result = new CastExp(e.loc, e, t);
+ result.type = t;
+ return;
+ }
+ }
+
+ /* Forward the cast to our alias this member, rewrite to:
+ * cast(to)e1.aliasthis
+ */
+ result = resolveAliasThis(sc, e);
+ result = result.castTo(sc, t);
+ return;
+ }
+ }
+ }
+
+ result = e.castTo(sc, t);
+ return;
+ }
+
+ result = e.optimize(WANTvalue);
+ if (result != e)
+ {
+ result.accept(this);
+ return;
+ }
+
+ if (t.ty != Terror && e.type.ty != Terror)
+ {
+ if (!t.deco)
+ {
+ e.error("forward reference to type `%s`", t.toChars());
+ }
+ else
+ {
+ //printf("type %p ty %d deco %p\n", type, type.ty, type.deco);
+ //type = type.typeSemantic(loc, sc);
+ //printf("type %s t %s\n", type.deco, t.deco);
+ auto ts = toAutoQualChars(e.type, t);
+ e.error("cannot implicitly convert expression `%s` of type `%s` to `%s`",
+ e.toChars(), ts[0], ts[1]);
+ }
+ }
+ result = ErrorExp.get();
+ }
+
+ override void visit(StringExp e)
+ {
+ //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
+ visit(cast(Expression)e);
+ if (auto se = result.isStringExp())
+ {
+ // Retain polysemous nature if it started out that way
+ se.committed = e.committed;
+ }
+ }
+
+ override void visit(ErrorExp e)
+ {
+ result = e;
+ }
+
+ override void visit(FuncExp e)
+ {
+ //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars());
+ FuncExp fe;
+ if (e.matchType(t, sc, &fe) > MATCH.nomatch)
+ {
+ result = fe;
+ return;
+ }
+ visit(cast(Expression)e);
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ visit(cast(Expression)e);
+
+ Type tb = result.type.toBasetype();
+ if (auto ta = tb.isTypeDArray())
+ if (global.params.useTypeInfo && Type.dtypeinfo)
+ semanticTypeInfo(sc, ta.next);
+ }
+
+ override void visit(SliceExp e)
+ {
+ visit(cast(Expression)e);
+
+ if (auto se = result.isSliceExp())
+ if (auto ale = se.e1.isArrayLiteralExp())
+ {
+ Type tb = t.toBasetype();
+ Type tx = (tb.ty == Tsarray)
+ ? tb.nextOf().sarrayOf(ale.elements ? ale.elements.dim : 0)
+ : tb.nextOf().arrayOf();
+ se.e1 = ale.implicitCastTo(sc, tx);
+ }
+ }
+ }
+
+ scope ImplicitCastTo v = new ImplicitCastTo(sc, t);
+ e.accept(v);
+ return v.result;
+}
+
+/**
+ * Checks whether or not an expression can be implicitly converted
+ * to type `t`.
+ *
+ * Unlike `implicitCastTo`, this routine does not perform the actual cast,
+ * but only checks up to what `MATCH` level the conversion would be possible.
+ *
+ * Params:
+ * e = Expression that is to be casted
+ * t = Expected resulting type
+ *
+ * Returns:
+ * The `MATCH` level between `e.type` and `t`.
+ */
+MATCH implicitConvTo(Expression e, Type t)
+{
+ extern (C++) final class ImplicitConvTo : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ Type t;
+ MATCH result;
+
+ extern (D) this(Type t)
+ {
+ this.t = t;
+ result = MATCH.nomatch;
+ }
+
+ override void visit(Expression e)
+ {
+ version (none)
+ {
+ printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ //static int nest; if (++nest == 10) assert(0);
+ if (t == Type.terror)
+ return;
+ if (!e.type)
+ {
+ e.error("`%s` is not an expression", e.toChars());
+ e.type = Type.terror;
+ }
+
+ Expression ex = e.optimize(WANTvalue);
+ if (ex.type.equals(t))
+ {
+ result = MATCH.exact;
+ return;
+ }
+ if (ex != e)
+ {
+ //printf("\toptimized to %s of type %s\n", e.toChars(), e.type.toChars());
+ result = ex.implicitConvTo(t);
+ return;
+ }
+
+ MATCH match = e.type.implicitConvTo(t);
+ if (match != MATCH.nomatch)
+ {
+ result = match;
+ return;
+ }
+
+ /* See if we can do integral narrowing conversions
+ */
+ if (e.type.isintegral() && t.isintegral() && e.type.isTypeBasic() && t.isTypeBasic())
+ {
+ IntRange src = getIntRange(e);
+ IntRange target = IntRange.fromType(t);
+ if (target.contains(src))
+ {
+ result = MATCH.convert;
+ return;
+ }
+ }
+ }
+
+ /******
+ * Given expression e of type t, see if we can implicitly convert e
+ * to type tprime, where tprime is type t with mod bits added.
+ * Returns:
+ * match level
+ */
+ static MATCH implicitMod(Expression e, Type t, MOD mod)
+ {
+ Type tprime;
+ if (t.ty == Tpointer)
+ tprime = t.nextOf().castMod(mod).pointerTo();
+ else if (t.ty == Tarray)
+ tprime = t.nextOf().castMod(mod).arrayOf();
+ else if (t.ty == Tsarray)
+ tprime = t.nextOf().castMod(mod).sarrayOf(t.size() / t.nextOf().size());
+ else
+ tprime = t.castMod(mod);
+
+ return e.implicitConvTo(tprime);
+ }
+
+ static MATCH implicitConvToAddMin(BinExp e, Type t)
+ {
+ /* Is this (ptr +- offset)? If so, then ask ptr
+ * if the conversion can be done.
+ * This is to support doing things like implicitly converting a mutable unique
+ * pointer to an immutable pointer.
+ */
+
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ if (typeb.ty != Tpointer || tb.ty != Tpointer)
+ return MATCH.nomatch;
+
+ Type t1b = e.e1.type.toBasetype();
+ Type t2b = e.e2.type.toBasetype();
+ if (t1b.ty == Tpointer && t2b.isintegral() && t1b.equivalent(tb))
+ {
+ // ptr + offset
+ // ptr - offset
+ MATCH m = e.e1.implicitConvTo(t);
+ return (m > MATCH.constant) ? MATCH.constant : m;
+ }
+ if (t2b.ty == Tpointer && t1b.isintegral() && t2b.equivalent(tb))
+ {
+ // offset + ptr
+ MATCH m = e.e2.implicitConvTo(t);
+ return (m > MATCH.constant) ? MATCH.constant : m;
+ }
+
+ return MATCH.nomatch;
+ }
+
+ override void visit(AddExp e)
+ {
+ version (none)
+ {
+ printf("AddExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ visit(cast(Expression)e);
+ if (result == MATCH.nomatch)
+ result = implicitConvToAddMin(e, t);
+ }
+
+ override void visit(MinExp e)
+ {
+ version (none)
+ {
+ printf("MinExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ visit(cast(Expression)e);
+ if (result == MATCH.nomatch)
+ result = implicitConvToAddMin(e, t);
+ }
+
+ override void visit(IntegerExp e)
+ {
+ version (none)
+ {
+ printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ MATCH m = e.type.implicitConvTo(t);
+ if (m >= MATCH.constant)
+ {
+ result = m;
+ return;
+ }
+
+ TY ty = e.type.toBasetype().ty;
+ TY toty = t.toBasetype().ty;
+ TY oldty = ty;
+
+ if (m == MATCH.nomatch && t.ty == Tenum)
+ return;
+
+ if (auto tv = t.isTypeVector())
+ {
+ TypeBasic tb = tv.elementType();
+ if (tb.ty == Tvoid)
+ return;
+ toty = tb.ty;
+ }
+
+ switch (ty)
+ {
+ case Tbool:
+ case Tint8:
+ case Tchar:
+ case Tuns8:
+ case Tint16:
+ case Tuns16:
+ case Twchar:
+ ty = Tint32;
+ break;
+
+ case Tdchar:
+ ty = Tuns32;
+ break;
+
+ default:
+ break;
+ }
+
+ // Only allow conversion if no change in value
+ immutable dinteger_t value = e.toInteger();
+
+ bool isLosslesslyConvertibleToFP(T)()
+ {
+ if (e.type.isunsigned())
+ {
+ const f = cast(T) value;
+ return cast(dinteger_t) f == value;
+ }
+
+ const f = cast(T) cast(sinteger_t) value;
+ return cast(sinteger_t) f == cast(sinteger_t) value;
+ }
+
+ switch (toty)
+ {
+ case Tbool:
+ if ((value & 1) != value)
+ return;
+ break;
+
+ case Tint8:
+ if (ty == Tuns64 && value & ~0x7FU)
+ return;
+ else if (cast(byte)value != value)
+ return;
+ break;
+
+ case Tchar:
+ if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F)
+ return;
+ goto case Tuns8;
+ case Tuns8:
+ //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value);
+ if (cast(ubyte)value != value)
+ return;
+ break;
+
+ case Tint16:
+ if (ty == Tuns64 && value & ~0x7FFFU)
+ return;
+ else if (cast(short)value != value)
+ return;
+ break;
+
+ case Twchar:
+ if (oldty == Tdchar && value > 0xD7FF && value < 0xE000)
+ return;
+ goto case Tuns16;
+ case Tuns16:
+ if (cast(ushort)value != value)
+ return;
+ break;
+
+ case Tint32:
+ if (ty == Tuns32)
+ {
+ }
+ else if (ty == Tuns64 && value & ~0x7FFFFFFFU)
+ return;
+ else if (cast(int)value != value)
+ return;
+ break;
+
+ case Tuns32:
+ if (ty == Tint32)
+ {
+ }
+ else if (cast(uint)value != value)
+ return;
+ break;
+
+ case Tdchar:
+ if (value > 0x10FFFFU)
+ return;
+ break;
+
+ case Tfloat32:
+ if (!isLosslesslyConvertibleToFP!float)
+ return;
+ break;
+
+ case Tfloat64:
+ if (!isLosslesslyConvertibleToFP!double)
+ return;
+ break;
+
+ case Tfloat80:
+ if (!isLosslesslyConvertibleToFP!real_t)
+ return;
+ break;
+
+ case Tpointer:
+ //printf("type = %s\n", type.toBasetype()->toChars());
+ //printf("t = %s\n", t.toBasetype()->toChars());
+ if (ty == Tpointer && e.type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty)
+ {
+ /* Allow things like:
+ * const char* P = cast(char *)3;
+ * char* q = P;
+ */
+ break;
+ }
+ goto default;
+
+ default:
+ visit(cast(Expression)e);
+ return;
+ }
+
+ //printf("MATCH.convert\n");
+ result = MATCH.convert;
+ }
+
+ override void visit(ErrorExp e)
+ {
+ // no match
+ }
+
+ override void visit(NullExp e)
+ {
+ version (none)
+ {
+ printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ if (e.type.equals(t))
+ {
+ result = MATCH.exact;
+ return;
+ }
+
+ /* Allow implicit conversions from immutable to mutable|const,
+ * and mutable to immutable. It works because, after all, a null
+ * doesn't actually point to anything.
+ */
+ if (t.equivalent(e.type))
+ {
+ result = MATCH.constant;
+ return;
+ }
+
+ visit(cast(Expression)e);
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ version (none)
+ {
+ printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ visit(cast(Expression)e);
+ if (result != MATCH.nomatch)
+ return;
+ if (e.type.ty == t.ty && e.type.isTypeStruct() && e.type.isTypeStruct().sym == t.isTypeStruct().sym)
+ {
+ result = MATCH.constant;
+ foreach (i, el; (*e.elements)[])
+ {
+ if (!el)
+ continue;
+ Type te = e.sd.fields[i].type.addMod(t.mod);
+ MATCH m2 = el.implicitConvTo(te);
+ //printf("\t%s => %s, match = %d\n", el.toChars(), te.toChars(), m2);
+ if (m2 < result)
+ result = m2;
+ }
+ }
+ }
+
+ override void visit(StringExp e)
+ {
+ version (none)
+ {
+ printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", e.toChars(), e.committed, e.type.toChars(), t.toChars());
+ }
+ if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid)
+ return;
+
+ if (!(e.type.ty == Tsarray || e.type.ty == Tarray || e.type.ty == Tpointer))
+ return visit(cast(Expression)e);
+
+ TY tyn = e.type.nextOf().ty;
+
+ if (!tyn.isSomeChar)
+ return visit(cast(Expression)e);
+
+ switch (t.ty)
+ {
+ case Tsarray:
+ if (e.type.ty == Tsarray)
+ {
+ TY tynto = t.nextOf().ty;
+ if (tynto == tyn)
+ {
+ if (e.type.isTypeSArray().dim.toInteger() == t.isTypeSArray().dim.toInteger())
+ {
+ result = MATCH.exact;
+ }
+ return;
+ }
+ if (tynto.isSomeChar)
+ {
+ if (e.committed && tynto != tyn)
+ return;
+ size_t fromlen = e.numberOfCodeUnits(tynto);
+ size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger();
+ if (tolen < fromlen)
+ return;
+ if (tolen != fromlen)
+ {
+ // implicit length extending
+ result = MATCH.convert;
+ return;
+ }
+ }
+ if (!e.committed && tynto.isSomeChar)
+ {
+ result = MATCH.exact;
+ return;
+ }
+ }
+ else if (e.type.ty == Tarray)
+ {
+ TY tynto = t.nextOf().ty;
+ if (tynto.isSomeChar)
+ {
+ if (e.committed && tynto != tyn)
+ return;
+ size_t fromlen = e.numberOfCodeUnits(tynto);
+ size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger();
+ if (tolen < fromlen)
+ return;
+ if (tolen != fromlen)
+ {
+ // implicit length extending
+ result = MATCH.convert;
+ return;
+ }
+ }
+ if (tynto == tyn)
+ {
+ result = MATCH.exact;
+ return;
+ }
+ if (!e.committed && tynto.isSomeChar)
+ {
+ result = MATCH.exact;
+ return;
+ }
+ }
+ goto case; /+ fall through +/
+ case Tarray:
+ case Tpointer:
+ Type tn = t.nextOf();
+ MATCH m = MATCH.exact;
+ if (e.type.nextOf().mod != tn.mod)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=16183
+ if (!tn.isConst() && !tn.isImmutable())
+ return;
+ m = MATCH.constant;
+ }
+ if (!e.committed)
+ {
+ switch (tn.ty)
+ {
+ case Tchar:
+ if (e.postfix == 'w' || e.postfix == 'd')
+ m = MATCH.convert;
+ result = m;
+ return;
+ case Twchar:
+ if (e.postfix != 'w')
+ m = MATCH.convert;
+ result = m;
+ return;
+ case Tdchar:
+ if (e.postfix != 'd')
+ m = MATCH.convert;
+ result = m;
+ return;
+ case Tenum:
+ if (tn.isTypeEnum().sym.isSpecial())
+ {
+ /* Allow string literal -> const(wchar_t)[]
+ */
+ if (TypeBasic tob = tn.toBasetype().isTypeBasic())
+ result = tn.implicitConvTo(tob);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ visit(cast(Expression)e);
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ version (none)
+ {
+ printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ if ((tb.ty == Tarray || tb.ty == Tsarray) &&
+ (typeb.ty == Tarray || typeb.ty == Tsarray))
+ {
+ result = MATCH.exact;
+ Type typen = typeb.nextOf().toBasetype();
+
+ if (auto tsa = tb.isTypeSArray())
+ {
+ if (e.elements.dim != tsa.dim.toInteger())
+ result = MATCH.nomatch;
+ }
+
+ Type telement = tb.nextOf();
+ if (!e.elements.dim)
+ {
+ if (typen.ty != Tvoid)
+ result = typen.implicitConvTo(telement);
+ }
+ else
+ {
+ if (e.basis)
+ {
+ MATCH m = e.basis.implicitConvTo(telement);
+ if (m < result)
+ result = m;
+ }
+ for (size_t i = 0; i < e.elements.dim; i++)
+ {
+ Expression el = (*e.elements)[i];
+ if (result == MATCH.nomatch)
+ break;
+ if (!el)
+ continue;
+ MATCH m = el.implicitConvTo(telement);
+ if (m < result)
+ result = m; // remember worst match
+ }
+ }
+
+ if (!result)
+ result = e.type.implicitConvTo(t);
+
+ return;
+ }
+ else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray))
+ {
+ result = MATCH.exact;
+ // Convert array literal to vector type
+ TypeVector tv = tb.isTypeVector();
+ TypeSArray tbase = tv.basetype.isTypeSArray();
+ assert(tbase);
+ const edim = e.elements.dim;
+ const tbasedim = tbase.dim.toInteger();
+ if (edim > tbasedim)
+ {
+ result = MATCH.nomatch;
+ return;
+ }
+
+ Type telement = tv.elementType();
+ if (edim < tbasedim)
+ {
+ Expression el = typeb.nextOf.defaultInitLiteral(e.loc);
+ MATCH m = el.implicitConvTo(telement);
+ if (m < result)
+ result = m; // remember worst match
+ }
+ foreach (el; (*e.elements)[])
+ {
+ MATCH m = el.implicitConvTo(telement);
+ if (m < result)
+ result = m; // remember worst match
+ if (result == MATCH.nomatch)
+ break; // no need to check for worse
+ }
+ return;
+ }
+
+ visit(cast(Expression)e);
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ auto taa = t.toBasetype().isTypeAArray();
+ Type typeb = e.type.toBasetype();
+
+ if (!(taa && typeb.ty == Taarray))
+ return visit(cast(Expression)e);
+
+ result = MATCH.exact;
+ foreach (i, el; (*e.keys)[])
+ {
+ MATCH m = el.implicitConvTo(taa.index);
+ if (m < result)
+ result = m; // remember worst match
+ if (result == MATCH.nomatch)
+ break; // no need to check for worse
+ el = (*e.values)[i];
+ m = el.implicitConvTo(taa.nextOf());
+ if (m < result)
+ result = m; // remember worst match
+ if (result == MATCH.nomatch)
+ break; // no need to check for worse
+ }
+ }
+
+ override void visit(CallExp e)
+ {
+ enum LOG = false;
+ static if (LOG)
+ {
+ printf("CallExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+
+ visit(cast(Expression)e);
+ if (result != MATCH.nomatch)
+ return;
+
+ /* Allow the result of strongly pure functions to
+ * convert to immutable
+ */
+ if (e.f &&
+ (global.params.useDIP1000 != FeatureState.enabled || // lots of legacy code breaks with the following purity check
+ e.f.isPure() >= PURE.strong ||
+ // Special case exemption for Object.dup() which we assume is implemented correctly
+ e.f.ident == Id.dup &&
+ e.f.toParent2() == ClassDeclaration.object.toParent()) &&
+ e.f.isReturnIsolated() // check isReturnIsolated last, because it is potentially expensive.
+ )
+ {
+ result = e.type.immutableOf().implicitConvTo(t);
+ if (result > MATCH.constant) // Match level is MATCH.constant at best.
+ result = MATCH.constant;
+ return;
+ }
+
+ /* Conversion is 'const' conversion if:
+ * 1. function is pure (weakly pure is ok)
+ * 2. implicit conversion only fails because of mod bits
+ * 3. each function parameter can be implicitly converted to the mod bits
+ */
+ auto tf = (e.f ? e.f.type : e.e1.type).toBasetype().isTypeFunction();
+ if (!tf)
+ return;
+
+ if (tf.purity == PURE.impure)
+ return;
+ if (e.f && e.f.isNested())
+ return;
+
+ /* See if fail only because of mod bits.
+ *
+ * https://issues.dlang.org/show_bug.cgi?id=14155
+ * All pure functions can access global immutable data.
+ * So the returned pointer may refer an immutable global data,
+ * and then the returned pointer that points non-mutable object
+ * cannot be unique pointer.
+ *
+ * Example:
+ * immutable g;
+ * static this() { g = 1; }
+ * const(int*) foo() pure { return &g; }
+ * void test() {
+ * immutable(int*) ip = foo(); // OK
+ * int* mp = foo(); // should be disallowed
+ * }
+ */
+ if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant)
+ {
+ return;
+ }
+ // Allow a conversion to immutable type, or
+ // conversions of mutable types between thread-local and shared.
+
+ /* Get mod bits of what we're converting to
+ */
+ Type tb = t.toBasetype();
+ MOD mod = tb.mod;
+ if (tf.isref)
+ {
+ }
+ else
+ {
+ if (Type ti = getIndirection(t))
+ mod = ti.mod;
+ }
+ static if (LOG)
+ {
+ printf("mod = x%x\n", mod);
+ }
+ if (mod & MODFlags.wild)
+ return; // not sure what to do with this
+
+ /* Apply mod bits to each function parameter,
+ * and see if we can convert the function argument to the modded type
+ */
+
+ size_t nparams = tf.parameterList.length;
+ size_t j = tf.isDstyleVariadic(); // if TypeInfoArray was prepended
+ if (auto dve = e.e1.isDotVarExp())
+ {
+ /* Treat 'this' as just another function argument
+ */
+ Type targ = dve.e1.type;
+ if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch)
+ return;
+ }
+ foreach (const i; j .. e.arguments.dim)
+ {
+ Expression earg = (*e.arguments)[i];
+ Type targ = earg.type.toBasetype();
+ static if (LOG)
+ {
+ printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
+ }
+ if (i - j < nparams)
+ {
+ Parameter fparam = tf.parameterList[i - j];
+ if (fparam.storageClass & STC.lazy_)
+ return; // not sure what to do with this
+ Type tparam = fparam.type;
+ if (!tparam)
+ continue;
+ if (fparam.isReference())
+ {
+ if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch)
+ return;
+ continue;
+ }
+ }
+ static if (LOG)
+ {
+ printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
+ }
+ if (implicitMod(earg, targ, mod) == MATCH.nomatch)
+ return;
+ }
+
+ /* Success
+ */
+ result = MATCH.constant;
+ }
+
+ override void visit(AddrExp e)
+ {
+ version (none)
+ {
+ printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ result = e.type.implicitConvTo(t);
+ //printf("\tresult = %d\n", result);
+
+ if (result != MATCH.nomatch)
+ return;
+
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ // Look for pointers to functions where the functions are overloaded.
+ if (e.e1.op == TOK.overloadSet &&
+ (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
+ {
+ OverExp eo = e.e1.isOverExp();
+ FuncDeclaration f = null;
+ foreach (s; eo.vars.a[])
+ {
+ FuncDeclaration f2 = s.isFuncDeclaration();
+ assert(f2);
+ if (f2.overloadExactMatch(tb.nextOf()))
+ {
+ if (f)
+ {
+ /* Error if match in more than one overload set,
+ * even if one is a 'better' match than the other.
+ */
+ ScopeDsymbol.multiplyDefined(e.loc, f, f2);
+ }
+ else
+ f = f2;
+ result = MATCH.exact;
+ }
+ }
+ }
+
+ if (e.e1.op == TOK.variable &&
+ typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
+ tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
+ {
+ /* I don't think this can ever happen -
+ * it should have been
+ * converted to a SymOffExp.
+ */
+ assert(0);
+ }
+
+ //printf("\tresult = %d\n", result);
+ }
+
+ override void visit(SymOffExp e)
+ {
+ version (none)
+ {
+ printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ result = e.type.implicitConvTo(t);
+ //printf("\tresult = %d\n", result);
+ if (result != MATCH.nomatch)
+ return;
+
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ // Look for pointers to functions where the functions are overloaded.
+ if (typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
+ (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
+ {
+ if (FuncDeclaration f = e.var.isFuncDeclaration())
+ {
+ f = f.overloadExactMatch(tb.nextOf());
+ if (f)
+ {
+ if ((tb.ty == Tdelegate && (f.needThis() || f.isNested())) ||
+ (tb.ty == Tpointer && !(f.needThis() || f.isNested())))
+ {
+ result = MATCH.exact;
+ }
+ }
+ }
+ }
+ //printf("\tresult = %d\n", result);
+ }
+
+ override void visit(DelegateExp e)
+ {
+ version (none)
+ {
+ printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ result = e.type.implicitConvTo(t);
+ if (result != MATCH.nomatch)
+ return;
+
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ // Look for pointers to functions where the functions are overloaded.
+ if (typeb.ty == Tdelegate && tb.ty == Tdelegate)
+ {
+ if (e.func && e.func.overloadExactMatch(tb.nextOf()))
+ result = MATCH.exact;
+ }
+ }
+
+ override void visit(FuncExp e)
+ {
+ //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars());
+ MATCH m = e.matchType(t, null, null, 1);
+ if (m > MATCH.nomatch)
+ {
+ result = m;
+ return;
+ }
+ visit(cast(Expression)e);
+ }
+
+ override void visit(AndExp e)
+ {
+ visit(cast(Expression)e);
+ if (result != MATCH.nomatch)
+ return;
+
+ MATCH m1 = e.e1.implicitConvTo(t);
+ MATCH m2 = e.e2.implicitConvTo(t);
+
+ // Pick the worst match
+ result = (m1 < m2) ? m1 : m2;
+ }
+
+ override void visit(OrExp e)
+ {
+ visit(cast(Expression)e);
+ if (result != MATCH.nomatch)
+ return;
+
+ MATCH m1 = e.e1.implicitConvTo(t);
+ MATCH m2 = e.e2.implicitConvTo(t);
+
+ // Pick the worst match
+ result = (m1 < m2) ? m1 : m2;
+ }
+
+ override void visit(XorExp e)
+ {
+ visit(cast(Expression)e);
+ if (result != MATCH.nomatch)
+ return;
+
+ MATCH m1 = e.e1.implicitConvTo(t);
+ MATCH m2 = e.e2.implicitConvTo(t);
+
+ // Pick the worst match
+ result = (m1 < m2) ? m1 : m2;
+ }
+
+ override void visit(CondExp e)
+ {
+ MATCH m1 = e.e1.implicitConvTo(t);
+ MATCH m2 = e.e2.implicitConvTo(t);
+ //printf("CondExp: m1 %d m2 %d\n", m1, m2);
+
+ // Pick the worst match
+ result = (m1 < m2) ? m1 : m2;
+ }
+
+ override void visit(CommaExp e)
+ {
+ e.e2.accept(this);
+ }
+
+ override void visit(CastExp e)
+ {
+ version (none)
+ {
+ printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ result = e.type.implicitConvTo(t);
+ if (result != MATCH.nomatch)
+ return;
+
+ if (t.isintegral() && e.e1.type.isintegral() && e.e1.implicitConvTo(t) != MATCH.nomatch)
+ result = MATCH.convert;
+ else
+ visit(cast(Expression)e);
+ }
+
+ override void visit(NewExp e)
+ {
+ version (none)
+ {
+ printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ visit(cast(Expression)e);
+ if (result != MATCH.nomatch)
+ return;
+
+ /* Calling new() is like calling a pure function. We can implicitly convert the
+ * return from new() to t using the same algorithm as in CallExp, with the function
+ * 'arguments' being:
+ * thisexp
+ * newargs
+ * arguments
+ * .init
+ * 'member' need to be pure.
+ */
+
+ /* See if fail only because of mod bits
+ */
+ if (e.type.immutableOf().implicitConvTo(t.immutableOf()) == MATCH.nomatch)
+ return;
+
+ /* Get mod bits of what we're converting to
+ */
+ Type tb = t.toBasetype();
+ MOD mod = tb.mod;
+ if (Type ti = getIndirection(t))
+ mod = ti.mod;
+ static if (LOG)
+ {
+ printf("mod = x%x\n", mod);
+ }
+ if (mod & MODFlags.wild)
+ return; // not sure what to do with this
+
+ /* Apply mod bits to each argument,
+ * and see if we can convert the argument to the modded type
+ */
+
+ if (e.thisexp)
+ {
+ /* Treat 'this' as just another function argument
+ */
+ Type targ = e.thisexp.type;
+ if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch)
+ return;
+ }
+
+ /* Check call to 'member'
+ */
+ if (e.member)
+ {
+ FuncDeclaration fd = e.member;
+ if (fd.errors || fd.type.ty != Tfunction)
+ return; // error
+ TypeFunction tf = fd.type.isTypeFunction();
+ if (tf.purity == PURE.impure)
+ return; // impure
+
+ if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant)
+ {
+ return;
+ }
+ // Allow a conversion to immutable type, or
+ // conversions of mutable types between thread-local and shared.
+
+ Expressions* args = e.arguments;
+
+ size_t nparams = tf.parameterList.length;
+ // if TypeInfoArray was prepended
+ size_t j = tf.isDstyleVariadic();
+ for (size_t i = j; i < e.arguments.dim; ++i)
+ {
+ Expression earg = (*args)[i];
+ Type targ = earg.type.toBasetype();
+ static if (LOG)
+ {
+ printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
+ }
+ if (i - j < nparams)
+ {
+ Parameter fparam = tf.parameterList[i - j];
+ if (fparam.storageClass & STC.lazy_)
+ return; // not sure what to do with this
+ Type tparam = fparam.type;
+ if (!tparam)
+ continue;
+ if (fparam.isReference())
+ {
+ if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch)
+ return;
+ continue;
+ }
+ }
+ static if (LOG)
+ {
+ printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
+ }
+ if (implicitMod(earg, targ, mod) == MATCH.nomatch)
+ return;
+ }
+ }
+
+ /* If no 'member', then construction is by simple assignment,
+ * and just straight check 'arguments'
+ */
+ if (!e.member && e.arguments)
+ {
+ for (size_t i = 0; i < e.arguments.dim; ++i)
+ {
+ Expression earg = (*e.arguments)[i];
+ if (!earg) // https://issues.dlang.org/show_bug.cgi?id=14853
+ // if it's on overlapped field
+ continue;
+ Type targ = earg.type.toBasetype();
+ static if (LOG)
+ {
+ printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
+ printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
+ }
+ if (implicitMod(earg, targ, mod) == MATCH.nomatch)
+ return;
+ }
+ }
+
+ /* Consider the .init expression as an argument
+ */
+ Type ntb = e.newtype.toBasetype();
+ if (ntb.ty == Tarray)
+ ntb = ntb.nextOf().toBasetype();
+ if (auto ts = ntb.isTypeStruct())
+ {
+ // Don't allow nested structs - uplevel reference may not be convertible
+ StructDeclaration sd = ts.sym;
+ sd.size(e.loc); // resolve any forward references
+ if (sd.isNested())
+ return;
+ }
+ if (ntb.isZeroInit(e.loc))
+ {
+ /* Zeros are implicitly convertible, except for special cases.
+ */
+ if (auto tc = ntb.isTypeClass())
+ {
+ /* With new() must look at the class instance initializer.
+ */
+ ClassDeclaration cd = tc.sym;
+
+ cd.size(e.loc); // resolve any forward references
+
+ if (cd.isNested())
+ return; // uplevel reference may not be convertible
+
+ assert(!cd.isInterfaceDeclaration());
+
+ struct ClassCheck
+ {
+ extern (C++) static bool convertible(Expression e, ClassDeclaration cd, MOD mod)
+ {
+ for (size_t i = 0; i < cd.fields.dim; i++)
+ {
+ VarDeclaration v = cd.fields[i];
+ Initializer _init = v._init;
+ if (_init)
+ {
+ if (_init.isVoidInitializer())
+ {
+ }
+ else if (ExpInitializer ei = _init.isExpInitializer())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=21319
+ // This is to prevent re-analyzing the same expression
+ // over and over again.
+ if (ei.exp == e)
+ return false;
+ Type tb = v.type.toBasetype();
+ if (implicitMod(ei.exp, tb, mod) == MATCH.nomatch)
+ return false;
+ }
+ else
+ {
+ /* Enhancement: handle StructInitializer and ArrayInitializer
+ */
+ return false;
+ }
+ }
+ else if (!v.type.isZeroInit(e.loc))
+ return false;
+ }
+ return cd.baseClass ? convertible(e, cd.baseClass, mod) : true;
+ }
+ }
+
+ if (!ClassCheck.convertible(e, cd, mod))
+ return;
+ }
+ }
+ else
+ {
+ Expression earg = e.newtype.defaultInitLiteral(e.loc);
+ Type targ = e.newtype.toBasetype();
+
+ if (implicitMod(earg, targ, mod) == MATCH.nomatch)
+ return;
+ }
+
+ /* Success
+ */
+ result = MATCH.constant;
+ }
+
+ override void visit(SliceExp e)
+ {
+ //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e.toChars(), e.type.toChars());
+ visit(cast(Expression)e);
+ if (result != MATCH.nomatch)
+ return;
+
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ if (tb.ty == Tsarray && typeb.ty == Tarray)
+ {
+ typeb = toStaticArrayType(e);
+ if (typeb)
+ {
+ // Try: T[] -> T[dim]
+ // (Slice with compile-time known boundaries to static array)
+ result = typeb.implicitConvTo(t);
+ if (result > MATCH.convert)
+ result = MATCH.convert; // match with implicit conversion at most
+ }
+ return;
+ }
+
+ /* If the only reason it won't convert is because of the mod bits,
+ * then test for conversion by seeing if e1 can be converted with those
+ * same mod bits.
+ */
+ Type t1b = e.e1.type.toBasetype();
+ if (tb.ty == Tarray && typeb.equivalent(tb))
+ {
+ Type tbn = tb.nextOf();
+ Type tx = null;
+
+ /* If e.e1 is dynamic array or pointer, the uniqueness of e.e1
+ * is equivalent with the uniqueness of the referred data. And in here
+ * we can have arbitrary typed reference for that.
+ */
+ if (t1b.ty == Tarray)
+ tx = tbn.arrayOf();
+ if (t1b.ty == Tpointer)
+ tx = tbn.pointerTo();
+
+ /* If e.e1 is static array, at least it should be an rvalue.
+ * If not, e.e1 is a reference, and its uniqueness does not link
+ * to the uniqueness of the referred data.
+ */
+ if (t1b.ty == Tsarray && !e.e1.isLvalue())
+ tx = tbn.sarrayOf(t1b.size() / tbn.size());
+
+ if (tx)
+ {
+ result = e.e1.implicitConvTo(tx);
+ if (result > MATCH.constant) // Match level is MATCH.constant at best.
+ result = MATCH.constant;
+ }
+ }
+
+ // Enhancement 10724
+ if (tb.ty == Tpointer && e.e1.op == TOK.string_)
+ e.e1.accept(this);
+ }
+ }
+
+ scope ImplicitConvTo v = new ImplicitConvTo(t);
+ e.accept(v);
+ return v.result;
+}
+
+/**
+ * Same as implicitConvTo(); except follow C11 rules, which are quite a bit
+ * more permissive than D.
+ * C11 6.3 and 6.5.16.1
+ * Params:
+ * e = Expression that is to be casted
+ * t = Expected resulting type
+ * Returns:
+ * The `MATCH` level between `e.type` and `t`.
+ */
+MATCH cimplicitConvTo(Expression e, Type t)
+{
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ if (tb.equals(typeb))
+ return MATCH.exact;
+ if ((typeb.isintegral() || typeb.isfloating()) &&
+ (tb.isintegral() || tb.isfloating()))
+ return MATCH.convert;
+ if (tb.ty == Tpointer && typeb.isintegral()) // C11 6.3.2.3-5
+ return MATCH.convert;
+ if (tb.isintegral() && typeb.ty == Tpointer) // C11 6.3.2.3-6
+ return MATCH.convert;
+ if (tb.ty == Tpointer && typeb.ty == Tpointer)
+ {
+ if (tb.isTypePointer().next.ty == Tvoid ||
+ typeb.isTypePointer().next.ty == Tvoid)
+ return MATCH.convert; // convert to/from void* C11 6.3.2.3-1
+ }
+
+ return implicitConvTo(e, t);
+}
+
+/*****************************************
+ */
+Type toStaticArrayType(SliceExp e)
+{
+ if (e.lwr && e.upr)
+ {
+ // For the following code to work, e should be optimized beforehand.
+ // (eg. $ in lwr and upr should be already resolved, if possible)
+ Expression lwr = e.lwr.optimize(WANTvalue);
+ Expression upr = e.upr.optimize(WANTvalue);
+ if (lwr.isConst() && upr.isConst())
+ {
+ size_t len = cast(size_t)(upr.toUInteger() - lwr.toUInteger());
+ return e.type.toBasetype().nextOf().sarrayOf(len);
+ }
+ }
+ else
+ {
+ Type t1b = e.e1.type.toBasetype();
+ if (t1b.ty == Tsarray)
+ return t1b;
+ }
+ return null;
+}
+
+/**************************************
+ * Do an explicit cast.
+ * Assume that the expression `e` does not have any indirections.
+ * (Parameter 'att' is used to stop 'alias this' recursion)
+ */
+Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
+{
+ extern (C++) final class CastTo : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ Type t;
+ Scope* sc;
+ Expression result;
+
+ extern (D) this(Scope* sc, Type t)
+ {
+ this.sc = sc;
+ this.t = t;
+ }
+
+ override void visit(Expression e)
+ {
+ //printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars());
+ version (none)
+ {
+ printf("Expression::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ if (e.type.equals(t))
+ {
+ result = e;
+ return;
+ }
+ if (e.op == TOK.variable)
+ {
+ VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
+ if (v && v.storage_class & STC.manifest)
+ {
+ result = e.ctfeInterpret();
+ /* https://issues.dlang.org/show_bug.cgi?id=18236
+ *
+ * The expression returned by ctfeInterpret points
+ * to the line where the manifest constant was declared
+ * so we need to update the location before trying to cast
+ */
+ result.loc = e.loc;
+ result = result.castTo(sc, t);
+ return;
+ }
+ }
+
+ Type tob = t.toBasetype();
+ Type t1b = e.type.toBasetype();
+ if (tob.equals(t1b))
+ {
+ result = e.copy(); // because of COW for assignment to e.type
+ result.type = t;
+ return;
+ }
+
+ /* Make semantic error against invalid cast between concrete types.
+ * Assume that 'e' is never be any placeholder expressions.
+ * The result of these checks should be consistent with CastExp::toElem().
+ */
+
+ // Fat Value types
+ const(bool) tob_isFV = (tob.ty == Tstruct || tob.ty == Tsarray || tob.ty == Tvector);
+ const(bool) t1b_isFV = (t1b.ty == Tstruct || t1b.ty == Tsarray || t1b.ty == Tvector);
+
+ // Fat Reference types
+ const(bool) tob_isFR = (tob.ty == Tarray || tob.ty == Tdelegate);
+ const(bool) t1b_isFR = (t1b.ty == Tarray || t1b.ty == Tdelegate);
+
+ // Reference types
+ const(bool) tob_isR = (tob_isFR || tob.ty == Tpointer || tob.ty == Taarray || tob.ty == Tclass);
+ const(bool) t1b_isR = (t1b_isFR || t1b.ty == Tpointer || t1b.ty == Taarray || t1b.ty == Tclass);
+
+ // Arithmetic types (== valueable basic types)
+ const(bool) tob_isA = ((tob.isintegral() || tob.isfloating()) && tob.ty != Tvector);
+ const(bool) t1b_isA = ((t1b.isintegral() || t1b.isfloating()) && t1b.ty != Tvector);
+
+ // Try casting the alias this member.
+ // Return the expression if it succeeds, null otherwise.
+ Expression tryAliasThisCast()
+ {
+ if (isRecursiveAliasThis(att, t1b))
+ return null;
+
+ /* Forward the cast to our alias this member, rewrite to:
+ * cast(to)e1.aliasthis
+ */
+ auto exp = resolveAliasThis(sc, e);
+ const errors = global.startGagging();
+ exp = castTo(exp, sc, t, att);
+ return global.endGagging(errors) ? null : exp;
+ }
+
+ bool hasAliasThis;
+ if (AggregateDeclaration t1ad = isAggregate(t1b))
+ {
+ AggregateDeclaration toad = isAggregate(tob);
+ if (t1ad != toad && t1ad.aliasthis)
+ {
+ if (t1b.ty == Tclass && tob.ty == Tclass)
+ {
+ ClassDeclaration t1cd = t1b.isClassHandle();
+ ClassDeclaration tocd = tob.isClassHandle();
+ int offset;
+ if (tocd.isBaseOf(t1cd, &offset))
+ goto Lok;
+ }
+ hasAliasThis = true;
+ }
+ }
+ else if (tob.ty == Tvector && t1b.ty != Tvector)
+ {
+ //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars());
+ TypeVector tv = tob.isTypeVector();
+ result = new CastExp(e.loc, e, tv.elementType());
+ result = new VectorExp(e.loc, result, tob);
+ result = result.expressionSemantic(sc);
+ return;
+ }
+ else if (tob.ty != Tvector && t1b.ty == Tvector)
+ {
+ // T[n] <-- __vector(U[m])
+ if (tob.ty == Tsarray)
+ {
+ if (t1b.size(e.loc) == tob.size(e.loc))
+ goto Lok;
+ }
+ goto Lfail;
+ }
+ else if (t1b.implicitConvTo(tob) == MATCH.constant && t.equals(e.type.constOf()))
+ {
+ result = e.copy();
+ result.type = t;
+ return;
+ }
+
+ // arithmetic values vs. other arithmetic values
+ // arithmetic values vs. T*
+ if (tob_isA && (t1b_isA || t1b.ty == Tpointer) || t1b_isA && (tob_isA || tob.ty == Tpointer))
+ {
+ goto Lok;
+ }
+
+ // arithmetic values vs. references or fat values
+ if (tob_isA && (t1b_isR || t1b_isFV) || t1b_isA && (tob_isR || tob_isFV))
+ {
+ goto Lfail;
+ }
+
+ // Bugzlla 3133: A cast between fat values is possible only when the sizes match.
+ if (tob_isFV && t1b_isFV)
+ {
+ if (hasAliasThis)
+ {
+ result = tryAliasThisCast();
+ if (result)
+ return;
+ }
+
+ if (t1b.size(e.loc) == tob.size(e.loc))
+ goto Lok;
+
+ auto ts = toAutoQualChars(e.type, t);
+ e.error("cannot cast expression `%s` of type `%s` to `%s` because of different sizes",
+ e.toChars(), ts[0], ts[1]);
+ result = ErrorExp.get();
+ return;
+ }
+
+ // Fat values vs. null or references
+ if (tob_isFV && (t1b.ty == Tnull || t1b_isR) || t1b_isFV && (tob.ty == Tnull || tob_isR))
+ {
+ if (tob.ty == Tpointer && t1b.ty == Tsarray)
+ {
+ // T[n] sa;
+ // cast(U*)sa; // ==> cast(U*)sa.ptr;
+ result = new AddrExp(e.loc, e, t);
+ return;
+ }
+ if (tob.ty == Tarray && t1b.ty == Tsarray)
+ {
+ // T[n] sa;
+ // cast(U[])sa; // ==> cast(U[])sa[];
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ {
+ if (auto v = expToVariable(e))
+ {
+ if (e.type.hasPointers() && !checkAddressVar(sc, e, v))
+ goto Lfail;
+ }
+ }
+ const fsize = t1b.nextOf().size();
+ const tsize = tob.nextOf().size();
+ if (fsize != tsize)
+ {
+ const dim = t1b.isTypeSArray().dim.toInteger();
+ if (tsize == 0 || (dim * fsize) % tsize != 0)
+ {
+ e.error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up",
+ e.toChars(), e.type.toChars(), t.toChars());
+ result = ErrorExp.get();
+ return;
+ }
+ }
+ goto Lok;
+ }
+ goto Lfail;
+ }
+
+ /* For references, any reinterpret casts are allowed to same 'ty' type.
+ * T* to U*
+ * R1 function(P1) to R2 function(P2)
+ * R1 delegate(P1) to R2 delegate(P2)
+ * T[] to U[]
+ * V1[K1] to V2[K2]
+ * class/interface A to B (will be a dynamic cast if possible)
+ */
+ if (tob.ty == t1b.ty && tob_isR && t1b_isR)
+ goto Lok;
+
+ // typeof(null) <-- non-null references or values
+ if (tob.ty == Tnull && t1b.ty != Tnull)
+ goto Lfail; // https://issues.dlang.org/show_bug.cgi?id=14629
+ // typeof(null) --> non-null references or arithmetic values
+ if (t1b.ty == Tnull && tob.ty != Tnull)
+ goto Lok;
+
+ // Check size mismatch of references.
+ // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof.
+ if (tob_isFR && t1b_isR || t1b_isFR && tob_isR)
+ {
+ if (tob.ty == Tpointer && t1b.ty == Tarray)
+ {
+ // T[] da;
+ // cast(U*)da; // ==> cast(U*)da.ptr;
+ goto Lok;
+ }
+ if (tob.ty == Tpointer && t1b.ty == Tdelegate)
+ {
+ // void delegate() dg;
+ // cast(U*)dg; // ==> cast(U*)dg.ptr;
+ // Note that it happens even when U is a Tfunction!
+ e.deprecation("casting from %s to %s is deprecated", e.type.toChars(), t.toChars());
+ goto Lok;
+ }
+ goto Lfail;
+ }
+
+ if (t1b.ty == Tvoid && tob.ty != Tvoid)
+ {
+ Lfail:
+ /* if the cast cannot be performed, maybe there is an alias
+ * this that can be used for casting.
+ */
+ if (hasAliasThis)
+ {
+ result = tryAliasThisCast();
+ if (result)
+ return;
+ }
+ e.error("cannot cast expression `%s` of type `%s` to `%s`", e.toChars(), e.type.toChars(), t.toChars());
+ result = ErrorExp.get();
+ return;
+ }
+
+ Lok:
+ result = new CastExp(e.loc, e, t);
+ result.type = t; // Don't call semantic()
+ //printf("Returning: %s\n", result.toChars());
+ }
+
+ override void visit(ErrorExp e)
+ {
+ result = e;
+ }
+
+ override void visit(RealExp e)
+ {
+ if (!e.type.equals(t))
+ {
+ if ((e.type.isreal() && t.isreal()) || (e.type.isimaginary() && t.isimaginary()))
+ {
+ result = e.copy();
+ result.type = t;
+ }
+ else
+ visit(cast(Expression)e);
+ return;
+ }
+ result = e;
+ }
+
+ override void visit(ComplexExp e)
+ {
+ if (!e.type.equals(t))
+ {
+ if (e.type.iscomplex() && t.iscomplex())
+ {
+ result = e.copy();
+ result.type = t;
+ }
+ else
+ visit(cast(Expression)e);
+ return;
+ }
+ result = e;
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ visit(cast(Expression)e);
+ if (result.op == TOK.structLiteral)
+ (cast(StructLiteralExp)result).stype = t; // commit type
+ }
+
+ override void visit(StringExp e)
+ {
+ /* This follows copy-on-write; any changes to 'this'
+ * will result in a copy.
+ * The this.string member is considered immutable.
+ */
+ int copied = 0;
+
+ //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed);
+
+ if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid)
+ {
+ e.error("cannot convert string literal to `void*`");
+ result = ErrorExp.get();
+ return;
+ }
+
+ StringExp se = e;
+ if (!e.committed)
+ {
+ se = cast(StringExp)e.copy();
+ se.committed = 1;
+ copied = 1;
+ }
+
+ if (e.type.equals(t))
+ {
+ result = se;
+ return;
+ }
+
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ //printf("\ttype = %s\n", e.type.toChars());
+ if (tb.ty == Tdelegate && typeb.ty != Tdelegate)
+ {
+ visit(cast(Expression)e);
+ return;
+ }
+
+ if (typeb.equals(tb))
+ {
+ if (!copied)
+ {
+ se = cast(StringExp)e.copy();
+ copied = 1;
+ }
+ se.type = t;
+ result = se;
+ return;
+ }
+
+ /* Handle reinterpret casts:
+ * cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000]
+ * cast(wchar[2])"abcd"c --> [\u6261, \u6463]
+ * cast(wchar[1])"abcd"c --> [\u6261]
+ * cast(char[4])"a" --> ['a', 0, 0, 0]
+ */
+ if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray)
+ {
+ se = cast(StringExp)e.copy();
+ d_uns64 szx = tb.nextOf().size();
+ assert(szx <= 255);
+ se.sz = cast(ubyte)szx;
+ se.len = cast(size_t)tb.isTypeSArray().dim.toInteger();
+ se.committed = 1;
+ se.type = t;
+
+ /* If larger than source, pad with zeros.
+ */
+ const fullSize = (se.len + 1) * se.sz; // incl. terminating 0
+ if (fullSize > (e.len + 1) * e.sz)
+ {
+ void* s = mem.xmalloc(fullSize);
+ const srcSize = e.len * e.sz;
+ const data = se.peekData();
+ memcpy(s, data.ptr, srcSize);
+ memset(s + srcSize, 0, fullSize - srcSize);
+ se.setData(s, se.len, se.sz);
+ }
+ result = se;
+ return;
+ }
+
+ if (tb.ty != Tsarray && tb.ty != Tarray && tb.ty != Tpointer)
+ {
+ if (!copied)
+ {
+ se = cast(StringExp)e.copy();
+ copied = 1;
+ }
+ goto Lcast;
+ }
+ if (typeb.ty != Tsarray && typeb.ty != Tarray && typeb.ty != Tpointer)
+ {
+ if (!copied)
+ {
+ se = cast(StringExp)e.copy();
+ copied = 1;
+ }
+ goto Lcast;
+ }
+
+ if (typeb.nextOf().size() == tb.nextOf().size())
+ {
+ if (!copied)
+ {
+ se = cast(StringExp)e.copy();
+ copied = 1;
+ }
+ if (tb.ty == Tsarray)
+ goto L2; // handle possible change in static array dimension
+ se.type = t;
+ result = se;
+ return;
+ }
+
+ if (e.committed)
+ goto Lcast;
+
+ auto X(T, U)(T tf, U tt)
+ {
+ return (cast(int)tf * 256 + cast(int)tt);
+ }
+
+ {
+ OutBuffer buffer;
+ size_t newlen = 0;
+ int tfty = typeb.nextOf().toBasetype().ty;
+ int ttty = tb.nextOf().toBasetype().ty;
+ switch (X(tfty, ttty))
+ {
+ case X(Tchar, Tchar):
+ case X(Twchar, Twchar):
+ case X(Tdchar, Tdchar):
+ break;
+
+ case X(Tchar, Twchar):
+ for (size_t u = 0; u < e.len;)
+ {
+ dchar c;
+ if (const s = utf_decodeChar(se.peekString(), u, c))
+ e.error("%.*s", cast(int)s.length, s.ptr);
+ else
+ buffer.writeUTF16(c);
+ }
+ newlen = buffer.length / 2;
+ buffer.writeUTF16(0);
+ goto L1;
+
+ case X(Tchar, Tdchar):
+ for (size_t u = 0; u < e.len;)
+ {
+ dchar c;
+ if (const s = utf_decodeChar(se.peekString(), u, c))
+ e.error("%.*s", cast(int)s.length, s.ptr);
+ buffer.write4(c);
+ newlen++;
+ }
+ buffer.write4(0);
+ goto L1;
+
+ case X(Twchar, Tchar):
+ for (size_t u = 0; u < e.len;)
+ {
+ dchar c;
+ if (const s = utf_decodeWchar(se.peekWstring(), u, c))
+ e.error("%.*s", cast(int)s.length, s.ptr);
+ else
+ buffer.writeUTF8(c);
+ }
+ newlen = buffer.length;
+ buffer.writeUTF8(0);
+ goto L1;
+
+ case X(Twchar, Tdchar):
+ for (size_t u = 0; u < e.len;)
+ {
+ dchar c;
+ if (const s = utf_decodeWchar(se.peekWstring(), u, c))
+ e.error("%.*s", cast(int)s.length, s.ptr);
+ buffer.write4(c);
+ newlen++;
+ }
+ buffer.write4(0);
+ goto L1;
+
+ case X(Tdchar, Tchar):
+ for (size_t u = 0; u < e.len; u++)
+ {
+ uint c = se.peekDstring()[u];
+ if (!utf_isValidDchar(c))
+ e.error("invalid UCS-32 char \\U%08x", c);
+ else
+ buffer.writeUTF8(c);
+ newlen++;
+ }
+ newlen = buffer.length;
+ buffer.writeUTF8(0);
+ goto L1;
+
+ case X(Tdchar, Twchar):
+ for (size_t u = 0; u < e.len; u++)
+ {
+ uint c = se.peekDstring()[u];
+ if (!utf_isValidDchar(c))
+ e.error("invalid UCS-32 char \\U%08x", c);
+ else
+ buffer.writeUTF16(c);
+ newlen++;
+ }
+ newlen = buffer.length / 2;
+ buffer.writeUTF16(0);
+ goto L1;
+
+ L1:
+ if (!copied)
+ {
+ se = cast(StringExp)e.copy();
+ copied = 1;
+ }
+
+ {
+ d_uns64 szx = tb.nextOf().size();
+ assert(szx <= 255);
+ se.setData(buffer.extractSlice().ptr, newlen, cast(ubyte)szx);
+ }
+ break;
+
+ default:
+ assert(typeb.nextOf().size() != tb.nextOf().size());
+ goto Lcast;
+ }
+ }
+ L2:
+ assert(copied);
+
+ // See if need to truncate or extend the literal
+ if (auto tsa = tb.isTypeSArray())
+ {
+ size_t dim2 = cast(size_t)tsa.dim.toInteger();
+ //printf("dim from = %d, to = %d\n", (int)se.len, (int)dim2);
+
+ // Changing dimensions
+ if (dim2 != se.len)
+ {
+ // Copy when changing the string literal
+ const newsz = se.sz;
+ const d = (dim2 < se.len) ? dim2 : se.len;
+ void* s = mem.xmalloc((dim2 + 1) * newsz);
+ memcpy(s, se.peekData().ptr, d * newsz);
+ // Extend with 0, add terminating 0
+ memset(s + d * newsz, 0, (dim2 + 1 - d) * newsz);
+ se.setData(s, dim2, newsz);
+ }
+ }
+ se.type = t;
+ result = se;
+ return;
+
+ Lcast:
+ result = new CastExp(e.loc, se, t);
+ result.type = t; // so semantic() won't be run on e
+ }
+
+ override void visit(AddrExp e)
+ {
+ version (none)
+ {
+ printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ result = e;
+
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ if (tb.equals(typeb))
+ {
+ result = e.copy();
+ result.type = t;
+ return;
+ }
+
+ // Look for pointers to functions where the functions are overloaded.
+ if (e.e1.op == TOK.overloadSet &&
+ (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
+ {
+ OverExp eo = cast(OverExp)e.e1;
+ FuncDeclaration f = null;
+ for (size_t i = 0; i < eo.vars.a.dim; i++)
+ {
+ auto s = eo.vars.a[i];
+ auto f2 = s.isFuncDeclaration();
+ assert(f2);
+ if (f2.overloadExactMatch(tb.nextOf()))
+ {
+ if (f)
+ {
+ /* Error if match in more than one overload set,
+ * even if one is a 'better' match than the other.
+ */
+ ScopeDsymbol.multiplyDefined(e.loc, f, f2);
+ }
+ else
+ f = f2;
+ }
+ }
+ if (f)
+ {
+ f.tookAddressOf++;
+ auto se = new SymOffExp(e.loc, f, 0, false);
+ auto se2 = se.expressionSemantic(sc);
+ // Let SymOffExp::castTo() do the heavy lifting
+ visit(se2);
+ return;
+ }
+ }
+
+ if (e.e1.op == TOK.variable &&
+ typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
+ tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
+ {
+ auto ve = cast(VarExp)e.e1;
+ auto f = ve.var.isFuncDeclaration();
+ if (f)
+ {
+ assert(f.isImportedSymbol());
+ f = f.overloadExactMatch(tb.nextOf());
+ if (f)
+ {
+ result = new VarExp(e.loc, f, false);
+ result.type = f.type;
+ result = new AddrExp(e.loc, result, t);
+ return;
+ }
+ }
+ }
+
+ if (auto f = isFuncAddress(e))
+ {
+ if (f.checkForwardRef(e.loc))
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ }
+
+ visit(cast(Expression)e);
+ }
+
+ override void visit(TupleExp e)
+ {
+ if (e.type.equals(t))
+ {
+ result = e;
+ return;
+ }
+
+ TupleExp te = e.copy().isTupleExp();
+ te.e0 = e.e0 ? e.e0.copy() : null;
+ te.exps = e.exps.copy();
+ for (size_t i = 0; i < te.exps.dim; i++)
+ {
+ Expression ex = (*te.exps)[i];
+ ex = ex.castTo(sc, t);
+ (*te.exps)[i] = ex;
+ }
+ result = te;
+
+ /* Questionable behavior: In here, result.type is not set to t.
+ * Therefoe:
+ * TypeTuple!(int, int) values;
+ * auto values2 = cast(long)values;
+ * // typeof(values2) == TypeTuple!(int, int) !!
+ *
+ * Only when the casted tuple is immediately expanded, it would work.
+ * auto arr = [cast(long)values];
+ * // typeof(arr) == long[]
+ */
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ version (none)
+ {
+ printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+
+ ArrayLiteralExp ae = e;
+
+ Type tb = t.toBasetype();
+ if (tb.ty == Tarray && global.params.useDIP1000 == FeatureState.enabled)
+ {
+ if (checkArrayLiteralEscape(sc, ae, false))
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ }
+
+ if (e.type == t)
+ {
+ result = e;
+ return;
+ }
+ Type typeb = e.type.toBasetype();
+
+ if ((tb.ty == Tarray || tb.ty == Tsarray) &&
+ (typeb.ty == Tarray || typeb.ty == Tsarray))
+ {
+ if (tb.nextOf().toBasetype().ty == Tvoid && typeb.nextOf().toBasetype().ty != Tvoid)
+ {
+ // Don't do anything to cast non-void[] to void[]
+ }
+ else if (typeb.ty == Tsarray && typeb.nextOf().toBasetype().ty == Tvoid)
+ {
+ // Don't do anything for casting void[n] to others
+ }
+ else
+ {
+ if (auto tsa = tb.isTypeSArray())
+ {
+ if (e.elements.dim != tsa.dim.toInteger())
+ goto L1;
+ }
+
+ ae = cast(ArrayLiteralExp)e.copy();
+ if (e.basis)
+ ae.basis = e.basis.castTo(sc, tb.nextOf());
+ ae.elements = e.elements.copy();
+ for (size_t i = 0; i < e.elements.dim; i++)
+ {
+ Expression ex = (*e.elements)[i];
+ if (!ex)
+ continue;
+ ex = ex.castTo(sc, tb.nextOf());
+ (*ae.elements)[i] = ex;
+ }
+ ae.type = t;
+ result = ae;
+ return;
+ }
+ }
+ else if (tb.ty == Tpointer && typeb.ty == Tsarray)
+ {
+ Type tp = typeb.nextOf().pointerTo();
+ if (!tp.equals(ae.type))
+ {
+ ae = cast(ArrayLiteralExp)e.copy();
+ ae.type = tp;
+ }
+ }
+ else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray))
+ {
+ // Convert array literal to vector type
+ TypeVector tv = tb.isTypeVector();
+ TypeSArray tbase = tv.basetype.isTypeSArray();
+ assert(tbase.ty == Tsarray);
+ const edim = e.elements.dim;
+ const tbasedim = tbase.dim.toInteger();
+ if (edim > tbasedim)
+ goto L1;
+
+ ae = e.copy().isArrayLiteralExp();
+ ae.type = tbase; // https://issues.dlang.org/show_bug.cgi?id=12642
+ ae.elements = e.elements.copy();
+ Type telement = tv.elementType();
+ foreach (i; 0 .. edim)
+ {
+ Expression ex = (*e.elements)[i];
+ ex = ex.castTo(sc, telement);
+ (*ae.elements)[i] = ex;
+ }
+ // Fill in the rest with the default initializer
+ ae.elements.setDim(cast(size_t)tbasedim);
+ foreach (i; edim .. cast(size_t)tbasedim)
+ {
+ Expression ex = typeb.nextOf.defaultInitLiteral(e.loc);
+ ex = ex.castTo(sc, telement);
+ (*ae.elements)[i] = ex;
+ }
+ Expression ev = new VectorExp(e.loc, ae, tb);
+ ev = ev.expressionSemantic(sc);
+ result = ev;
+ return;
+ }
+ L1:
+ visit(cast(Expression)ae);
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ //printf("AssocArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ if (e.type == t)
+ {
+ result = e;
+ return;
+ }
+
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ if (tb.ty == Taarray && typeb.ty == Taarray &&
+ tb.nextOf().toBasetype().ty != Tvoid)
+ {
+ AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e.copy();
+ ae.keys = e.keys.copy();
+ ae.values = e.values.copy();
+ assert(e.keys.dim == e.values.dim);
+ for (size_t i = 0; i < e.keys.dim; i++)
+ {
+ Expression ex = (*e.values)[i];
+ ex = ex.castTo(sc, tb.nextOf());
+ (*ae.values)[i] = ex;
+
+ ex = (*e.keys)[i];
+ ex = ex.castTo(sc, tb.isTypeAArray().index);
+ (*ae.keys)[i] = ex;
+ }
+ ae.type = t;
+ result = ae;
+ return;
+ }
+ visit(cast(Expression)e);
+ }
+
+ override void visit(SymOffExp e)
+ {
+ version (none)
+ {
+ printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ if (e.type == t && !e.hasOverloads)
+ {
+ result = e;
+ return;
+ }
+
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ if (tb.equals(typeb))
+ {
+ result = e.copy();
+ result.type = t;
+ (cast(SymOffExp)result).hasOverloads = false;
+ return;
+ }
+
+ // Look for pointers to functions where the functions are overloaded.
+ if (e.hasOverloads &&
+ typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
+ (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
+ {
+ FuncDeclaration f = e.var.isFuncDeclaration();
+ f = f ? f.overloadExactMatch(tb.nextOf()) : null;
+ if (f)
+ {
+ if (tb.ty == Tdelegate)
+ {
+ if (f.needThis() && hasThis(sc))
+ {
+ result = new DelegateExp(e.loc, new ThisExp(e.loc), f, false);
+ result = result.expressionSemantic(sc);
+ }
+ else if (f.needThis())
+ {
+ e.error("no `this` to create delegate for `%s`", f.toChars());
+ result = ErrorExp.get();
+ return;
+ }
+ else if (f.isNested())
+ {
+ result = new DelegateExp(e.loc, IntegerExp.literal!0, f, false);
+ result = result.expressionSemantic(sc);
+ }
+ else
+ {
+ e.error("cannot cast from function pointer to delegate");
+ result = ErrorExp.get();
+ return;
+ }
+ }
+ else
+ {
+ result = new SymOffExp(e.loc, f, 0, false);
+ result.type = t;
+ }
+ f.tookAddressOf++;
+ return;
+ }
+ }
+
+ if (auto f = isFuncAddress(e))
+ {
+ if (f.checkForwardRef(e.loc))
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ }
+
+ visit(cast(Expression)e);
+ }
+
+ override void visit(DelegateExp e)
+ {
+ version (none)
+ {
+ printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+ }
+ __gshared const(char)* msg = "cannot form delegate due to covariant return type";
+
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ if (tb.equals(typeb) && !e.hasOverloads)
+ {
+ int offset;
+ e.func.tookAddressOf++;
+ if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset)
+ e.error("%s", msg);
+ result = e.copy();
+ result.type = t;
+ return;
+ }
+
+ // Look for delegates to functions where the functions are overloaded.
+ if (typeb.ty == Tdelegate && tb.ty == Tdelegate)
+ {
+ if (e.func)
+ {
+ auto f = e.func.overloadExactMatch(tb.nextOf());
+ if (f)
+ {
+ int offset;
+ if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset)
+ e.error("%s", msg);
+ if (f != e.func) // if address not already marked as taken
+ f.tookAddressOf++;
+ result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2);
+ result.type = t;
+ return;
+ }
+ if (e.func.tintro)
+ e.error("%s", msg);
+ }
+ }
+
+ if (auto f = isFuncAddress(e))
+ {
+ if (f.checkForwardRef(e.loc))
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ }
+
+ visit(cast(Expression)e);
+ }
+
+ override void visit(FuncExp e)
+ {
+ //printf("FuncExp::castTo type = %s, t = %s\n", e.type.toChars(), t.toChars());
+ FuncExp fe;
+ if (e.matchType(t, sc, &fe, 1) > MATCH.nomatch)
+ {
+ result = fe;
+ return;
+ }
+ visit(cast(Expression)e);
+ }
+
+ override void visit(CondExp e)
+ {
+ if (!e.type.equals(t))
+ {
+ result = new CondExp(e.loc, e.econd, e.e1.castTo(sc, t), e.e2.castTo(sc, t));
+ result.type = t;
+ return;
+ }
+ result = e;
+ }
+
+ override void visit(CommaExp e)
+ {
+ Expression e2c = e.e2.castTo(sc, t);
+
+ if (e2c != e.e2)
+ {
+ result = new CommaExp(e.loc, e.e1, e2c);
+ result.type = e2c.type;
+ }
+ else
+ {
+ result = e;
+ result.type = e.e2.type;
+ }
+ }
+
+ override void visit(SliceExp e)
+ {
+ //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e.toChars(), e.type.toChars(), t.toChars());
+
+ Type tb = t.toBasetype();
+ Type typeb = e.type.toBasetype();
+
+ if (e.type.equals(t) || typeb.ty != Tarray ||
+ (tb.ty != Tarray && tb.ty != Tsarray))
+ {
+ visit(cast(Expression)e);
+ return;
+ }
+
+ if (tb.ty == Tarray)
+ {
+ if (typeb.nextOf().equivalent(tb.nextOf()))
+ {
+ // T[] to const(T)[]
+ result = e.copy();
+ result.type = t;
+ }
+ else
+ {
+ visit(cast(Expression)e);
+ }
+ return;
+ }
+
+ // Handle the cast from Tarray to Tsarray with CT-known slicing
+
+ TypeSArray tsa = toStaticArrayType(e).isTypeSArray();
+ if (tsa && tsa.size(e.loc) == tb.size(e.loc))
+ {
+ /* Match if the sarray sizes are equal:
+ * T[a .. b] to const(T)[b-a]
+ * T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim)
+ *
+ * If a SliceExp has Tsarray, it will become lvalue.
+ * That's handled in SliceExp::isLvalue and toLvalue
+ */
+ result = e.copy();
+ result.type = t;
+ return;
+ }
+ if (tsa && tsa.dim.equals(tb.isTypeSArray().dim))
+ {
+ /* Match if the dimensions are equal
+ * with the implicit conversion of e.e1:
+ * cast(float[2]) [2.0, 1.0, 0.0][0..2];
+ */
+ Type t1b = e.e1.type.toBasetype();
+ if (t1b.ty == Tsarray)
+ t1b = tb.nextOf().sarrayOf(t1b.isTypeSArray().dim.toInteger());
+ else if (t1b.ty == Tarray)
+ t1b = tb.nextOf().arrayOf();
+ else if (t1b.ty == Tpointer)
+ t1b = tb.nextOf().pointerTo();
+ else
+ assert(0);
+ if (e.e1.implicitConvTo(t1b) > MATCH.nomatch)
+ {
+ Expression e1x = e.e1.implicitCastTo(sc, t1b);
+ assert(e1x.op != TOK.error);
+ e = cast(SliceExp)e.copy();
+ e.e1 = e1x;
+ e.type = t;
+ result = e;
+ return;
+ }
+ }
+ auto ts = toAutoQualChars(tsa ? tsa : e.type, t);
+ e.error("cannot cast expression `%s` of type `%s` to `%s`",
+ e.toChars(), ts[0], ts[1]);
+ result = ErrorExp.get();
+ }
+ }
+
+ // Casting to noreturn isn't an actual cast
+ // Rewrite cast(<qual> noreturn) <exp>
+ // as <exp>, assert(false)
+ if (t.isTypeNoreturn())
+ {
+ // Don't generate an unreachable assert(false) if e will abort
+ if (e.type.isTypeNoreturn())
+ {
+ // Paint e to accomodate for different type qualifiers
+ e.type = t;
+ return e;
+ }
+
+ auto ini = t.defaultInitLiteral(e.loc);
+ return Expression.combine(e, ini);
+ }
+
+ scope CastTo v = new CastTo(sc, t);
+ e.accept(v);
+ return v.result;
+}
+
+/****************************************
+ * Set type inference target
+ * t Target type
+ * flag 1: don't put an error when inference fails
+ */
+Expression inferType(Expression e, Type t, int flag = 0)
+{
+ Expression visitAle(ArrayLiteralExp ale)
+ {
+ Type tb = t.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ Type tn = tb.nextOf();
+ if (ale.basis)
+ ale.basis = inferType(ale.basis, tn, flag);
+ for (size_t i = 0; i < ale.elements.dim; i++)
+ {
+ if (Expression e = (*ale.elements)[i])
+ {
+ e = inferType(e, tn, flag);
+ (*ale.elements)[i] = e;
+ }
+ }
+ }
+ return ale;
+ }
+
+ Expression visitAar(AssocArrayLiteralExp aale)
+ {
+ Type tb = t.toBasetype();
+ if (auto taa = tb.isTypeAArray())
+ {
+ Type ti = taa.index;
+ Type tv = taa.nextOf();
+ for (size_t i = 0; i < aale.keys.dim; i++)
+ {
+ if (Expression e = (*aale.keys)[i])
+ {
+ e = inferType(e, ti, flag);
+ (*aale.keys)[i] = e;
+ }
+ }
+ for (size_t i = 0; i < aale.values.dim; i++)
+ {
+ if (Expression e = (*aale.values)[i])
+ {
+ e = inferType(e, tv, flag);
+ (*aale.values)[i] = e;
+ }
+ }
+ }
+ return aale;
+ }
+
+ Expression visitFun(FuncExp fe)
+ {
+ //printf("FuncExp::inferType('%s'), to=%s\n", fe.type ? fe.type.toChars() : "null", t.toChars());
+ if (t.ty == Tdelegate || t.ty == Tpointer && t.nextOf().ty == Tfunction)
+ {
+ fe.fd.treq = t;
+ }
+ return fe;
+ }
+
+ Expression visitTer(CondExp ce)
+ {
+ Type tb = t.toBasetype();
+ ce.e1 = inferType(ce.e1, tb, flag);
+ ce.e2 = inferType(ce.e2, tb, flag);
+ return ce;
+ }
+
+ if (t) switch (e.op)
+ {
+ case TOK.arrayLiteral: return visitAle(cast(ArrayLiteralExp) e);
+ case TOK.assocArrayLiteral: return visitAar(cast(AssocArrayLiteralExp) e);
+ case TOK.function_: return visitFun(cast(FuncExp) e);
+ case TOK.question: return visitTer(cast(CondExp) e);
+ default:
+ }
+ return e;
+}
+
+/****************************************
+ * Scale addition/subtraction to/from pointer.
+ */
+Expression scaleFactor(BinExp be, Scope* sc)
+{
+ Type t1b = be.e1.type.toBasetype();
+ Type t2b = be.e2.type.toBasetype();
+ Expression eoff;
+
+ if (t1b.ty == Tpointer && t2b.isintegral())
+ {
+ // Need to adjust operator by the stride
+ // Replace (ptr + int) with (ptr + (int * stride))
+ Type t = Type.tptrdiff_t;
+
+ d_uns64 stride = t1b.nextOf().size(be.loc);
+ if (!t.equals(t2b))
+ be.e2 = be.e2.castTo(sc, t);
+ eoff = be.e2;
+ be.e2 = new MulExp(be.loc, be.e2, new IntegerExp(Loc.initial, stride, t));
+ be.e2.type = t;
+ be.type = be.e1.type;
+ }
+ else if (t2b.ty == Tpointer && t1b.isintegral())
+ {
+ // Need to adjust operator by the stride
+ // Replace (int + ptr) with (ptr + (int * stride))
+ Type t = Type.tptrdiff_t;
+ Expression e;
+
+ d_uns64 stride = t2b.nextOf().size(be.loc);
+ if (!t.equals(t1b))
+ e = be.e1.castTo(sc, t);
+ else
+ e = be.e1;
+ eoff = e;
+ e = new MulExp(be.loc, e, new IntegerExp(Loc.initial, stride, t));
+ e.type = t;
+ be.type = be.e2.type;
+ be.e1 = be.e2;
+ be.e2 = e;
+ }
+ else
+ assert(0);
+
+ if (sc.func && !sc.intypeof)
+ {
+ eoff = eoff.optimize(WANTvalue);
+ if (eoff.op == TOK.int64 && eoff.toInteger() == 0)
+ {
+ }
+ else if (sc.func.setUnsafe())
+ {
+ be.error("pointer arithmetic not allowed in @safe functions");
+ return ErrorExp.get();
+ }
+ }
+
+ return be;
+}
+
+/**************************************
+ * Return true if e is an empty array literal with dimensionality
+ * equal to or less than type of other array.
+ * [], [[]], [[[]]], etc.
+ * I.e., make sure that [1,2] is compatible with [],
+ * [[1,2]] is compatible with [[]], etc.
+ */
+private bool isVoidArrayLiteral(Expression e, Type other)
+{
+ while (e.op == TOK.arrayLiteral && e.type.ty == Tarray && ((cast(ArrayLiteralExp)e).elements.dim == 1))
+ {
+ auto ale = cast(ArrayLiteralExp)e;
+ e = ale[0];
+ if (other.ty == Tsarray || other.ty == Tarray)
+ other = other.nextOf();
+ else
+ return false;
+ }
+ if (other.ty != Tsarray && other.ty != Tarray)
+ return false;
+ Type t = e.type;
+ return (e.op == TOK.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && (cast(ArrayLiteralExp)e).elements.dim == 0);
+}
+
+/**
+ * Merge types of `e1` and `e2` into a common subset
+ *
+ * Parameters `e1` and `e2` will be rewritten in place as needed.
+ *
+ * Params:
+ * sc = Current scope
+ * op = Operator such as `e1 op e2`. In practice, either TOK.question
+ * or one of the binary operator.
+ * pe1 = The LHS of the operation, will be rewritten
+ * pe2 = The RHS of the operation, will be rewritten
+ *
+ * Returns:
+ * The resulting type in case of success, `null` in case of error
+ */
+Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
+{
+ //printf("typeMerge() %s op %s\n", e1.toChars(), e2.toChars());
+
+ Expression e1 = pe1;
+ Expression e2 = pe2;
+
+ Type Lret(Type result)
+ {
+ pe1 = e1;
+ pe2 = e2;
+
+ version (none)
+ {
+ printf("-typeMerge() %s op %s\n", e1.toChars(), e2.toChars());
+ if (e1.type)
+ printf("\tt1 = %s\n", e1.type.toChars());
+ if (e2.type)
+ printf("\tt2 = %s\n", e2.type.toChars());
+ printf("\ttype = %s\n", result.toChars());
+ }
+ return result;
+ }
+
+ /// Converts one of the expression too the other
+ Type convert(ref Expression from, Type to)
+ {
+ from = from.castTo(sc, to);
+ return Lret(to);
+ }
+
+ /// Converts both expression to a third type
+ Type coerce(Type towards)
+ {
+ e1 = e1.castTo(sc, towards);
+ e2 = e2.castTo(sc, towards);
+ return Lret(towards);
+ }
+
+ Type t1b = e1.type.toBasetype();
+ Type t2b = e2.type.toBasetype();
+
+ if (op != TOK.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic()))
+ {
+ if (op == TOK.question && t1b.ty.isSomeChar() && t2b.ty.isSomeChar())
+ {
+ e1 = e1.castTo(sc, Type.tdchar);
+ e2 = e2.castTo(sc, Type.tdchar);
+ }
+ else
+ {
+ e1 = integralPromotions(e1, sc);
+ e2 = integralPromotions(e2, sc);
+ }
+ }
+
+ MATCH m;
+ Type t1 = e1.type;
+ Type t2 = e2.type;
+ assert(t1);
+ Type t = t1;
+
+ /* The start type of alias this type recursion.
+ * In following case, we should save A, and stop recursion
+ * if it appears again.
+ * X -> Y -> [A] -> B -> A -> B -> ...
+ */
+ Type att1 = null;
+ Type att2 = null;
+
+ if (t1.mod != t2.mod &&
+ t1.ty == Tenum && t2.ty == Tenum &&
+ t1.isTypeEnum().sym == t2.isTypeEnum().sym)
+ {
+ ubyte mod = MODmerge(t1.mod, t2.mod);
+ t1 = t1.castMod(mod);
+ t2 = t2.castMod(mod);
+ }
+
+Lagain:
+ t1b = t1.toBasetype();
+ t2b = t2.toBasetype();
+
+ const ty = implicitConvCommonTy(t1b.ty, t2b.ty);
+ if (ty != Terror)
+ {
+ const ty1 = implicitConvTy1(t1b.ty, t2b.ty);
+ const ty2 = implicitConvTy1(t2b.ty, t1b.ty);
+
+ if (t1b.ty == ty1) // if no promotions
+ {
+ if (t1.equals(t2))
+ return Lret(t1);
+
+ if (t1b.equals(t2b))
+ return Lret(t1b);
+ }
+
+ t1 = Type.basic[ty1];
+ t2 = Type.basic[ty2];
+ e1 = e1.castTo(sc, t1);
+ e2 = e2.castTo(sc, t2);
+ return Lret(Type.basic[ty]);
+ }
+
+ t1 = t1b;
+ t2 = t2b;
+
+ if (t1.ty == Ttuple || t2.ty == Ttuple)
+ return null;
+
+ if (t1.equals(t2))
+ {
+ // merging can not result in new enum type
+ if (t.ty == Tenum)
+ return Lret(t1b);
+ return Lret(t);
+ }
+
+ if ((t1.ty == Tpointer && t2.ty == Tpointer) || (t1.ty == Tdelegate && t2.ty == Tdelegate))
+ {
+ // Bring pointers to compatible type
+ Type t1n = t1.nextOf();
+ Type t2n = t2.nextOf();
+
+ if (t1n.equals(t2n))
+ return Lret(t);
+
+ if (t1n.ty == Tvoid) // pointers to void are always compatible
+ return Lret(t2);
+
+ if (t2n.ty == Tvoid)
+ return Lret(t);
+
+ if (t1.implicitConvTo(t2))
+ return convert(e1, t2);
+
+ if (t2.implicitConvTo(t1))
+ return convert(e2, t1);
+
+ if (t1n.ty == Tfunction && t2n.ty == Tfunction)
+ {
+ TypeFunction tf1 = t1n.isTypeFunction();
+ TypeFunction tf2 = t2n.isTypeFunction();
+ tf1.purityLevel();
+ tf2.purityLevel();
+
+ TypeFunction d = tf1.syntaxCopy();
+
+ if (tf1.purity != tf2.purity)
+ d.purity = PURE.impure;
+ assert(d.purity != PURE.fwdref);
+
+ d.isnothrow = (tf1.isnothrow && tf2.isnothrow);
+ d.isnogc = (tf1.isnogc && tf2.isnogc);
+
+ if (tf1.trust == tf2.trust)
+ d.trust = tf1.trust;
+ else if (tf1.trust <= TRUST.system || tf2.trust <= TRUST.system)
+ d.trust = TRUST.system;
+ else
+ d.trust = TRUST.trusted;
+
+ Type tx = (t1.ty == Tdelegate) ? new TypeDelegate(d) : d.pointerTo();
+ tx = tx.typeSemantic(e1.loc, sc);
+
+ if (t1.implicitConvTo(tx) && t2.implicitConvTo(tx))
+ return coerce(tx);
+ return null;
+ }
+
+ if (t1n.mod != t2n.mod)
+ {
+ if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared())
+ return null;
+ ubyte mod = MODmerge(t1n.mod, t2n.mod);
+ t1 = t1n.castMod(mod).pointerTo();
+ t2 = t2n.castMod(mod).pointerTo();
+ t = t1;
+ goto Lagain;
+ }
+
+ if (t1n.ty == Tclass && t2n.ty == Tclass)
+ {
+ ClassDeclaration cd1 = t1n.isClassHandle();
+ ClassDeclaration cd2 = t2n.isClassHandle();
+ int offset;
+ if (cd1.isBaseOf(cd2, &offset))
+ {
+ if (offset)
+ e2 = e2.castTo(sc, t);
+ return Lret(t);
+ }
+
+ if (cd2.isBaseOf(cd1, &offset))
+ {
+ if (offset)
+ e1 = e1.castTo(sc, t2);
+ return Lret(t2);
+ }
+
+ return null;
+ }
+
+ t1 = t1n.constOf().pointerTo();
+ t2 = t2n.constOf().pointerTo();
+ if (t1.implicitConvTo(t2))
+ return convert(e1, t2);
+ if (t2.implicitConvTo(t1))
+ return convert(e2, t1);
+ return null;
+ }
+
+ if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == TOK.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == TOK.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && t2.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1)))
+ {
+ /* (T[n] op void*) => T[]
+ * (T[] op void*) => T[]
+ * (T[n] op void[0]) => T[]
+ * (T[] op void[0]) => T[]
+ * (T[n] op void[]) => T[]
+ * (T[] op void[]) => T[]
+ */
+ return coerce(t1.nextOf().arrayOf());
+ }
+
+ if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == TOK.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == TOK.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && t1.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2)))
+ {
+ /* (void* op T[n]) => T[]
+ * (void* op T[]) => T[]
+ * (void[0] op T[n]) => T[]
+ * (void[0] op T[]) => T[]
+ * (void[] op T[n]) => T[]
+ * (void[] op T[]) => T[]
+ */
+ return coerce(t2.nextOf().arrayOf());
+ }
+
+ if ((t1.ty == Tsarray || t1.ty == Tarray) && (m = t1.implicitConvTo(t2)) != MATCH.nomatch)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=7285
+ // Tsarray op [x, y, ...] should to be Tsarray
+ // https://issues.dlang.org/show_bug.cgi?id=14737
+ // Tsarray ~ [x, y, ...] should to be Tarray
+ if (t1.ty == Tsarray && e2.op == TOK.arrayLiteral && op != TOK.concatenate)
+ return convert(e2, t1);
+ if (m == MATCH.constant && (op == TOK.addAssign || op == TOK.minAssign || op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign || op == TOK.powAssign || op == TOK.andAssign || op == TOK.orAssign || op == TOK.xorAssign))
+ {
+ // Don't make the lvalue const
+ return Lret(t2);
+ }
+ return convert(e1, t2);
+ }
+
+ if ((t2.ty == Tsarray || t2.ty == Tarray) && t2.implicitConvTo(t1))
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=7285
+ // https://issues.dlang.org/show_bug.cgi?id=14737
+ if (t2.ty == Tsarray && e1.op == TOK.arrayLiteral && op != TOK.concatenate)
+ return convert(e1, t2);
+ return convert(e2, t1);
+ }
+
+ if ((t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Tpointer) && (t2.ty == Tsarray || t2.ty == Tarray || t2.ty == Tpointer) && t1.nextOf().mod != t2.nextOf().mod)
+ {
+ /* If one is mutable and the other immutable, then retry
+ * with both of them as const
+ */
+ Type t1n = t1.nextOf();
+ Type t2n = t2.nextOf();
+ ubyte mod;
+ if (e1.op == TOK.null_ && e2.op != TOK.null_)
+ mod = t2n.mod;
+ else if (e1.op != TOK.null_ && e2.op == TOK.null_)
+ mod = t1n.mod;
+ else if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared())
+ return null;
+ else
+ mod = MODmerge(t1n.mod, t2n.mod);
+
+ if (t1.ty == Tpointer)
+ t1 = t1n.castMod(mod).pointerTo();
+ else
+ t1 = t1n.castMod(mod).arrayOf();
+
+ if (t2.ty == Tpointer)
+ t2 = t2n.castMod(mod).pointerTo();
+ else
+ t2 = t2n.castMod(mod).arrayOf();
+ t = t1;
+ goto Lagain;
+ }
+
+ if (t1.ty == Tclass && t2.ty == Tclass)
+ {
+ if (t1.mod != t2.mod)
+ {
+ ubyte mod;
+ if (e1.op == TOK.null_ && e2.op != TOK.null_)
+ mod = t2.mod;
+ else if (e1.op != TOK.null_ && e2.op == TOK.null_)
+ mod = t1.mod;
+ else if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared())
+ return null;
+ else
+ mod = MODmerge(t1.mod, t2.mod);
+ t1 = t1.castMod(mod);
+ t2 = t2.castMod(mod);
+ t = t1;
+ goto Lagain;
+ }
+ goto Lcc;
+ }
+
+ if (t1.ty == Tclass || t2.ty == Tclass)
+ {
+ Lcc:
+ while (1)
+ {
+ MATCH i1 = e2.implicitConvTo(t1);
+ MATCH i2 = e1.implicitConvTo(t2);
+
+ if (i1 && i2)
+ {
+ // We have the case of class vs. void*, so pick class
+ if (t1.ty == Tpointer)
+ i1 = MATCH.nomatch;
+ else if (t2.ty == Tpointer)
+ i2 = MATCH.nomatch;
+ }
+
+ if (i2)
+ return coerce(t2);
+ if (i1)
+ return coerce(t1);
+
+ if (t1.ty == Tclass && t2.ty == Tclass)
+ {
+ TypeClass tc1 = t1.isTypeClass();
+ TypeClass tc2 = t2.isTypeClass();
+
+ /* Pick 'tightest' type
+ */
+ ClassDeclaration cd1 = tc1.sym.baseClass;
+ ClassDeclaration cd2 = tc2.sym.baseClass;
+ if (cd1 && cd2)
+ {
+ t1 = cd1.type.castMod(t1.mod);
+ t2 = cd2.type.castMod(t2.mod);
+ }
+ else if (cd1)
+ t1 = cd1.type;
+ else if (cd2)
+ t2 = cd2.type;
+ else
+ return null;
+ }
+ else if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis)
+ {
+ if (isRecursiveAliasThis(att1, e1.type))
+ return null;
+ //printf("att tmerge(c || c) e1 = %s\n", e1.type.toChars());
+ e1 = resolveAliasThis(sc, e1);
+ t1 = e1.type;
+ continue;
+ }
+ else if (t2.ty == Tstruct && t2.isTypeStruct().sym.aliasthis)
+ {
+ if (isRecursiveAliasThis(att2, e2.type))
+ return null;
+ //printf("att tmerge(c || c) e2 = %s\n", e2.type.toChars());
+ e2 = resolveAliasThis(sc, e2);
+ t2 = e2.type;
+ continue;
+ }
+ else
+ return null;
+ }
+ }
+
+ if (t1.ty == Tstruct && t2.ty == Tstruct)
+ {
+ if (t1.mod != t2.mod)
+ {
+ if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared())
+ return null;
+ ubyte mod = MODmerge(t1.mod, t2.mod);
+ t1 = t1.castMod(mod);
+ t2 = t2.castMod(mod);
+ t = t1;
+ goto Lagain;
+ }
+
+ TypeStruct ts1 = t1.isTypeStruct();
+ TypeStruct ts2 = t2.isTypeStruct();
+ if (ts1.sym != ts2.sym)
+ {
+ if (!ts1.sym.aliasthis && !ts2.sym.aliasthis)
+ return null;
+
+ MATCH i1 = MATCH.nomatch;
+ MATCH i2 = MATCH.nomatch;
+
+ Expression e1b = null;
+ Expression e2b = null;
+ if (ts2.sym.aliasthis)
+ {
+ if (isRecursiveAliasThis(att2, e2.type))
+ return null;
+ //printf("att tmerge(s && s) e2 = %s\n", e2.type.toChars());
+ e2b = resolveAliasThis(sc, e2);
+ i1 = e2b.implicitConvTo(t1);
+ }
+ if (ts1.sym.aliasthis)
+ {
+ if (isRecursiveAliasThis(att1, e1.type))
+ return null;
+ //printf("att tmerge(s && s) e1 = %s\n", e1.type.toChars());
+ e1b = resolveAliasThis(sc, e1);
+ i2 = e1b.implicitConvTo(t2);
+ }
+ if (i1 && i2)
+ return null;
+
+ if (i1)
+ return convert(e2, t1);
+ if (i2)
+ return convert(e1, t2);
+
+ if (e1b)
+ {
+ e1 = e1b;
+ t1 = e1b.type.toBasetype();
+ }
+ if (e2b)
+ {
+ e2 = e2b;
+ t2 = e2b.type.toBasetype();
+ }
+ t = t1;
+ goto Lagain;
+ }
+ }
+
+ if (t1.ty == Tstruct || t2.ty == Tstruct)
+ {
+ if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis)
+ {
+ if (isRecursiveAliasThis(att1, e1.type))
+ return null;
+ //printf("att tmerge(s || s) e1 = %s\n", e1.type.toChars());
+ e1 = resolveAliasThis(sc, e1);
+ t1 = e1.type;
+ t = t1;
+ goto Lagain;
+ }
+ if (t2.ty == Tstruct && t2.isTypeStruct().sym.aliasthis)
+ {
+ if (isRecursiveAliasThis(att2, e2.type))
+ return null;
+ //printf("att tmerge(s || s) e2 = %s\n", e2.type.toChars());
+ e2 = resolveAliasThis(sc, e2);
+ t2 = e2.type;
+ t = t2;
+ goto Lagain;
+ }
+ return null;
+ }
+
+ if ((e1.op == TOK.string_ || e1.op == TOK.null_) && e1.implicitConvTo(t2))
+ return convert(e1, t2);
+ if ((e2.op == TOK.string_ || e2.op == TOK.null_) && e2.implicitConvTo(t1))
+ return convert(e2, t1);
+ if (t1.ty == Tsarray && t2.ty == Tsarray && e2.implicitConvTo(t1.nextOf().arrayOf()))
+ return coerce(t1.nextOf().arrayOf());
+ if (t1.ty == Tsarray && t2.ty == Tsarray && e1.implicitConvTo(t2.nextOf().arrayOf()))
+ return coerce(t2.nextOf().arrayOf());
+
+ if (t1.ty == Tvector && t2.ty == Tvector)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=13841
+ // all vector types should have no common types between
+ // different vectors, even though their sizes are same.
+ auto tv1 = t1.isTypeVector();
+ auto tv2 = t2.isTypeVector();
+ if (!tv1.basetype.equals(tv2.basetype))
+ return null;
+
+ goto LmodCompare;
+ }
+
+ if (t1.ty == Tvector && t2.ty != Tvector && e2.implicitConvTo(t1))
+ {
+ e2 = e2.castTo(sc, t1);
+ t2 = t1;
+ t = t1;
+ goto Lagain;
+ }
+
+ if (t2.ty == Tvector && t1.ty != Tvector && e1.implicitConvTo(t2))
+ {
+ e1 = e1.castTo(sc, t2);
+ t1 = t2;
+ t = t1;
+ goto Lagain;
+ }
+
+ if (t1.isintegral() && t2.isintegral())
+ {
+ if (t1.ty != t2.ty)
+ {
+ if (t1.ty == Tvector || t2.ty == Tvector)
+ return null;
+ e1 = integralPromotions(e1, sc);
+ e2 = integralPromotions(e2, sc);
+ t1 = e1.type;
+ t2 = e2.type;
+ goto Lagain;
+ }
+ assert(t1.ty == t2.ty);
+LmodCompare:
+ if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared())
+ return null;
+ ubyte mod = MODmerge(t1.mod, t2.mod);
+
+ t1 = t1.castMod(mod);
+ t2 = t2.castMod(mod);
+ t = t1;
+ e1 = e1.castTo(sc, t);
+ e2 = e2.castTo(sc, t);
+ goto Lagain;
+ }
+
+ if (t1.ty == Tnull && t2.ty == Tnull)
+ {
+ ubyte mod = MODmerge(t1.mod, t2.mod);
+ return coerce(t1.castMod(mod));
+ }
+
+ if (t2.ty == Tnull && (t1.ty == Tpointer || t1.ty == Taarray || t1.ty == Tarray))
+ return convert(e2, t1);
+ if (t1.ty == Tnull && (t2.ty == Tpointer || t2.ty == Taarray || t2.ty == Tarray))
+ return convert(e1, t2);
+
+ if (t1.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1))
+ {
+ if (e2.implicitConvTo(t1.nextOf()))
+ {
+ // T[] op T
+ // T[] op cast(T)U
+ e2 = e2.castTo(sc, t1.nextOf());
+ return Lret(t1.nextOf().arrayOf());
+ }
+ if (t1.nextOf().implicitConvTo(e2.type))
+ {
+ // (cast(T)U)[] op T (https://issues.dlang.org/show_bug.cgi?id=12780)
+ // e1 is left as U[], it will be handled in arrayOp() later.
+ return Lret(e2.type.arrayOf());
+ }
+ if (t2.ty == Tarray && isArrayOpOperand(e2))
+ {
+ if (t1.nextOf().implicitConvTo(t2.nextOf()))
+ {
+ // (cast(T)U)[] op T[] (https://issues.dlang.org/show_bug.cgi?id=12780)
+ t = t2.nextOf().arrayOf();
+ // if cast won't be handled in arrayOp() later
+ if (!isArrayOpImplicitCast(t1.isTypeDArray(), t2.isTypeDArray()))
+ e1 = e1.castTo(sc, t);
+ return Lret(t);
+ }
+ if (t2.nextOf().implicitConvTo(t1.nextOf()))
+ {
+ // T[] op (cast(T)U)[] (https://issues.dlang.org/show_bug.cgi?id=12780)
+ // e2 is left as U[], it will be handled in arrayOp() later.
+ t = t1.nextOf().arrayOf();
+ // if cast won't be handled in arrayOp() later
+ if (!isArrayOpImplicitCast(t2.isTypeDArray(), t1.isTypeDArray()))
+ e2 = e2.castTo(sc, t);
+ return Lret(t);
+ }
+ return null;
+ }
+ return null;
+ }
+ else if (t2.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e2))
+ {
+ if (e1.implicitConvTo(t2.nextOf()))
+ {
+ // T op T[]
+ // cast(T)U op T[]
+ e1 = e1.castTo(sc, t2.nextOf());
+ t = t2.nextOf().arrayOf();
+ }
+ else if (t2.nextOf().implicitConvTo(e1.type))
+ {
+ // T op (cast(T)U)[] (https://issues.dlang.org/show_bug.cgi?id=12780)
+ // e2 is left as U[], it will be handled in arrayOp() later.
+ t = e1.type.arrayOf();
+ }
+ else
+ return null;
+
+ //printf("test %s\n", Token::toChars(op));
+ e1 = e1.optimize(WANTvalue);
+ if (isCommutative(op) && e1.isConst())
+ {
+ /* Swap operands to minimize number of functions generated
+ */
+ //printf("swap %s\n", Token::toChars(op));
+ Expression tmp = e1;
+ e1 = e2;
+ e2 = tmp;
+ }
+ return Lret(t);
+ }
+
+ return null;
+}
+
+/************************************
+ * Bring leaves to common type.
+ * Returns:
+ * null on success, ErrorExp if error occurs
+ */
+Expression typeCombine(BinExp be, Scope* sc)
+{
+ Expression errorReturn()
+ {
+ Expression ex = be.incompatibleTypes();
+ if (ex.op == TOK.error)
+ return ex;
+ return ErrorExp.get();
+ }
+
+ Type t1 = be.e1.type.toBasetype();
+ Type t2 = be.e2.type.toBasetype();
+
+ if (be.op == TOK.min || be.op == TOK.add)
+ {
+ // struct+struct, and class+class are errors
+ if (t1.ty == Tstruct && t2.ty == Tstruct)
+ return errorReturn();
+ else if (t1.ty == Tclass && t2.ty == Tclass)
+ return errorReturn();
+ else if (t1.ty == Taarray && t2.ty == Taarray)
+ return errorReturn();
+ }
+
+ if (auto result = typeMerge(sc, be.op, be.e1, be.e2))
+ {
+ if (be.type is null)
+ be.type = result;
+ }
+ else
+ return errorReturn();
+
+ // If the types have no value, return an error
+ if (be.e1.op == TOK.error)
+ return be.e1;
+ if (be.e2.op == TOK.error)
+ return be.e2;
+ return null;
+}
+
+/***********************************
+ * Do integral promotions (convertchk).
+ * Don't convert <array of> to <pointer to>
+ */
+Expression integralPromotions(Expression e, Scope* sc)
+{
+ //printf("integralPromotions %s %s\n", e.toChars(), e.type.toChars());
+ switch (e.type.toBasetype().ty)
+ {
+ case Tvoid:
+ e.error("void has no value");
+ return ErrorExp.get();
+
+ case Tint8:
+ case Tuns8:
+ case Tint16:
+ case Tuns16:
+ case Tbool:
+ case Tchar:
+ case Twchar:
+ e = e.castTo(sc, Type.tint32);
+ break;
+
+ case Tdchar:
+ e = e.castTo(sc, Type.tuns32);
+ break;
+
+ default:
+ break;
+ }
+ return e;
+}
+
+/******************************************************
+ * This provides a transition from the non-promoting behavior
+ * of unary + - ~ to the C-like integral promotion behavior.
+ * Params:
+ * sc = context
+ * ue = NegExp, UAddExp, or ComExp which is revised per rules
+ * References:
+ * https://issues.dlang.org/show_bug.cgi?id=16997
+ */
+
+void fix16997(Scope* sc, UnaExp ue)
+{
+ if (global.params.fix16997 || sc.flags & SCOPE.Cfile)
+ ue.e1 = integralPromotions(ue.e1, sc); // desired C-like behavor
+ else
+ {
+ switch (ue.e1.type.toBasetype.ty)
+ {
+ case Tint8:
+ case Tuns8:
+ case Tint16:
+ case Tuns16:
+ //case Tbool: // these operations aren't allowed on bool anyway
+ case Tchar:
+ case Twchar:
+ case Tdchar:
+ ue.deprecation("integral promotion not done for `%s`, use '-preview=intpromote' switch or `%scast(int)(%s)`",
+ ue.toChars(), Token.toChars(ue.op), ue.e1.toChars());
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/***********************************
+ * See if both types are arrays that can be compared
+ * for equality without any casting. Return true if so.
+ * This is to enable comparing things like an immutable
+ * array with a mutable one.
+ */
+extern (C++) bool arrayTypeCompatibleWithoutCasting(Type t1, Type t2)
+{
+ t1 = t1.toBasetype();
+ t2 = t2.toBasetype();
+
+ if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && t2.ty == t1.ty)
+ {
+ if (t1.nextOf().implicitConvTo(t2.nextOf()) >= MATCH.constant || t2.nextOf().implicitConvTo(t1.nextOf()) >= MATCH.constant)
+ return true;
+ }
+ return false;
+}
+
+/******************************************************************/
+/* Determine the integral ranges of an expression.
+ * This is used to determine if implicit narrowing conversions will
+ * be allowed.
+ */
+IntRange getIntRange(Expression e)
+{
+ extern (C++) final class IntRangeVisitor : Visitor
+ {
+ alias visit = Visitor.visit;
+
+ public:
+ IntRange range;
+
+ override void visit(Expression e)
+ {
+ range = IntRange.fromType(e.type);
+ }
+
+ override void visit(IntegerExp e)
+ {
+ range = IntRange(SignExtendedNumber(e.getInteger()))._cast(e.type);
+ }
+
+ override void visit(CastExp e)
+ {
+ range = getIntRange(e.e1)._cast(e.type);
+ }
+
+ override void visit(AddExp e)
+ {
+ IntRange ir1 = getIntRange(e.e1);
+ IntRange ir2 = getIntRange(e.e2);
+ range = (ir1 + ir2)._cast(e.type);
+ }
+
+ override void visit(MinExp e)
+ {
+ IntRange ir1 = getIntRange(e.e1);
+ IntRange ir2 = getIntRange(e.e2);
+ range = (ir1 - ir2)._cast(e.type);
+ }
+
+ override void visit(DivExp e)
+ {
+ IntRange ir1 = getIntRange(e.e1);
+ IntRange ir2 = getIntRange(e.e2);
+
+ range = (ir1 / ir2)._cast(e.type);
+ }
+
+ override void visit(MulExp e)
+ {
+ IntRange ir1 = getIntRange(e.e1);
+ IntRange ir2 = getIntRange(e.e2);
+
+ range = (ir1 * ir2)._cast(e.type);
+ }
+
+ override void visit(ModExp e)
+ {
+ IntRange ir1 = getIntRange(e.e1);
+ IntRange ir2 = getIntRange(e.e2);
+
+ // Modding on 0 is invalid anyway.
+ if (!ir2.absNeg().imin.negative)
+ {
+ visit(cast(Expression)e);
+ return;
+ }
+ range = (ir1 % ir2)._cast(e.type);
+ }
+
+ override void visit(AndExp e)
+ {
+ IntRange result;
+ bool hasResult = false;
+ result.unionOrAssign(getIntRange(e.e1) & getIntRange(e.e2), hasResult);
+
+ assert(hasResult);
+ range = result._cast(e.type);
+ }
+
+ override void visit(OrExp e)
+ {
+ IntRange result;
+ bool hasResult = false;
+ result.unionOrAssign(getIntRange(e.e1) | getIntRange(e.e2), hasResult);
+
+ assert(hasResult);
+ range = result._cast(e.type);
+ }
+
+ override void visit(XorExp e)
+ {
+ IntRange result;
+ bool hasResult = false;
+ result.unionOrAssign(getIntRange(e.e1) ^ getIntRange(e.e2), hasResult);
+
+ assert(hasResult);
+ range = result._cast(e.type);
+ }
+
+ override void visit(ShlExp e)
+ {
+ IntRange ir1 = getIntRange(e.e1);
+ IntRange ir2 = getIntRange(e.e2);
+
+ range = (ir1 << ir2)._cast(e.type);
+ }
+
+ override void visit(ShrExp e)
+ {
+ IntRange ir1 = getIntRange(e.e1);
+ IntRange ir2 = getIntRange(e.e2);
+
+ range = (ir1 >> ir2)._cast(e.type);
+ }
+
+ override void visit(UshrExp e)
+ {
+ IntRange ir1 = getIntRange(e.e1).castUnsigned(e.e1.type);
+ IntRange ir2 = getIntRange(e.e2);
+
+ range = (ir1 >>> ir2)._cast(e.type);
+ }
+
+ override void visit(AssignExp e)
+ {
+ range = getIntRange(e.e2)._cast(e.type);
+ }
+
+ override void visit(CondExp e)
+ {
+ // No need to check e.econd; assume caller has called optimize()
+ IntRange ir1 = getIntRange(e.e1);
+ IntRange ir2 = getIntRange(e.e2);
+ range = ir1.unionWith(ir2)._cast(e.type);
+ }
+
+ override void visit(VarExp e)
+ {
+ Expression ie;
+ VarDeclaration vd = e.var.isVarDeclaration();
+ if (vd && vd.range)
+ range = vd.range._cast(e.type);
+ else if (vd && vd._init && !vd.type.isMutable() && (ie = vd.getConstInitializer()) !is null)
+ ie.accept(this);
+ else
+ visit(cast(Expression)e);
+ }
+
+ override void visit(CommaExp e)
+ {
+ e.e2.accept(this);
+ }
+
+ override void visit(ComExp e)
+ {
+ IntRange ir = getIntRange(e.e1);
+ range = IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative), SignExtendedNumber(~ir.imin.value, !ir.imin.negative))._cast(e.type);
+ }
+
+ override void visit(NegExp e)
+ {
+ IntRange ir = getIntRange(e.e1);
+ range = (-ir)._cast(e.type);
+ }
+ }
+
+ scope IntRangeVisitor v = new IntRangeVisitor();
+ e.accept(v);
+ return v.range;
+}
diff --git a/gcc/d/dmd/dclass.c b/gcc/d/dmd/dclass.c
deleted file mode 100644
index 3f33014..0000000
--- a/gcc/d/dmd/dclass.c
+++ /dev/null
@@ -1,1041 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/class.c
- */
-
-#include "root/dsystem.h" // mem{cpy|set}()
-#include "root/root.h"
-#include "root/rmem.h"
-
-#include "errors.h"
-#include "enum.h"
-#include "init.h"
-#include "attrib.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "id.h"
-#include "mtype.h"
-#include "scope.h"
-#include "module.h"
-#include "expression.h"
-#include "statement.h"
-#include "template.h"
-#include "target.h"
-#include "objc.h"
-
-bool symbolIsVisible(Dsymbol *origin, Dsymbol *s);
-Objc *objc();
-
-
-/********************************* ClassDeclaration ****************************/
-
-ClassDeclaration *ClassDeclaration::object;
-ClassDeclaration *ClassDeclaration::throwable;
-ClassDeclaration *ClassDeclaration::exception;
-ClassDeclaration *ClassDeclaration::errorException;
-ClassDeclaration *ClassDeclaration::cpp_type_info_ptr; // Object.__cpp_type_info_ptr
-
-ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject)
- : AggregateDeclaration(loc, id ? id : Identifier::generateId("__anonclass"))
-{
- static const char msg[] = "only object.d can define this reserved class name";
-
- if (baseclasses)
- {
- // Actually, this is a transfer
- this->baseclasses = baseclasses;
- }
- else
- this->baseclasses = new BaseClasses();
-
- this->members = members;
-
- baseClass = NULL;
-
- interfaces.length = 0;
- interfaces.ptr = NULL;
-
- vtblInterfaces = NULL;
-
- //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses->length);
-
- // For forward references
- type = new TypeClass(this);
-
- staticCtor = NULL;
- staticDtor = NULL;
-
- vtblsym = NULL;
- vclassinfo = NULL;
-
- if (id)
- {
- // Look for special class names
-
- if (id == Id::__sizeof || id == Id::__xalignof || id == Id::_mangleof)
- error("illegal class name");
-
- // BUG: What if this is the wrong TypeInfo, i.e. it is nested?
- if (id->toChars()[0] == 'T')
- {
- if (id == Id::TypeInfo)
- {
- if (!inObject)
- error("%s", msg);
- Type::dtypeinfo = this;
- }
-
- if (id == Id::TypeInfo_Class)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfoclass = this;
- }
-
- if (id == Id::TypeInfo_Interface)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfointerface = this;
- }
-
- if (id == Id::TypeInfo_Struct)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfostruct = this;
- }
-
- if (id == Id::TypeInfo_Pointer)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfopointer = this;
- }
-
- if (id == Id::TypeInfo_Array)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfoarray = this;
- }
-
- if (id == Id::TypeInfo_StaticArray)
- {
- //if (!inObject)
- // Type::typeinfostaticarray->error("%s", msg);
- Type::typeinfostaticarray = this;
- }
-
- if (id == Id::TypeInfo_AssociativeArray)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfoassociativearray = this;
- }
-
- if (id == Id::TypeInfo_Enum)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfoenum = this;
- }
-
- if (id == Id::TypeInfo_Function)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfofunction = this;
- }
-
- if (id == Id::TypeInfo_Delegate)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfodelegate = this;
- }
-
- if (id == Id::TypeInfo_Tuple)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfotypelist = this;
- }
-
- if (id == Id::TypeInfo_Const)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfoconst = this;
- }
-
- if (id == Id::TypeInfo_Invariant)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfoinvariant = this;
- }
-
- if (id == Id::TypeInfo_Shared)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfoshared = this;
- }
-
- if (id == Id::TypeInfo_Wild)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfowild = this;
- }
-
- if (id == Id::TypeInfo_Vector)
- {
- if (!inObject)
- error("%s", msg);
- Type::typeinfovector = this;
- }
- }
-
- if (id == Id::Object)
- {
- if (!inObject)
- error("%s", msg);
- object = this;
- }
-
- if (id == Id::Throwable)
- {
- if (!inObject)
- error("%s", msg);
- throwable = this;
- }
-
- if (id == Id::Exception)
- {
- if (!inObject)
- error("%s", msg);
- exception = this;
- }
-
- if (id == Id::Error)
- {
- if (!inObject)
- error("%s", msg);
- errorException = this;
- }
-
- if (id == Id::cpp_type_info_ptr)
- {
- if (!inObject)
- error("%s", msg);
- cpp_type_info_ptr = this;
- }
- }
-
- com = false;
- isscope = false;
- isabstract = ABSfwdref;
- inuse = 0;
- baseok = BASEOKnone;
- cpp_type_info_ptr_sym = NULL;
-}
-
-ClassDeclaration *ClassDeclaration::create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject)
-{
- return new ClassDeclaration(loc, id, baseclasses, members, inObject);
-}
-
-Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s)
-{
- //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars());
- ClassDeclaration *cd =
- s ? (ClassDeclaration *)s
- : new ClassDeclaration(loc, ident, NULL, NULL, false);
-
- cd->storage_class |= storage_class;
-
- cd->baseclasses->setDim(this->baseclasses->length);
- for (size_t i = 0; i < cd->baseclasses->length; i++)
- {
- BaseClass *b = (*this->baseclasses)[i];
- BaseClass *b2 = new BaseClass(b->type->syntaxCopy());
- (*cd->baseclasses)[i] = b2;
- }
-
- return ScopeDsymbol::syntaxCopy(cd);
-}
-
-Scope *ClassDeclaration::newScope(Scope *sc)
-{
- Scope *sc2 = AggregateDeclaration::newScope(sc);
- if (isCOMclass())
- {
- /* This enables us to use COM objects under Linux and
- * work with things like XPCOM
- */
- sc2->linkage = target.systemLinkage();
- }
- return sc2;
-}
-
-/*********************************************
- * Determine if 'this' is a base class of cd.
- * This is used to detect circular inheritance only.
- */
-
-bool ClassDeclaration::isBaseOf2(ClassDeclaration *cd)
-{
- if (!cd)
- return false;
- //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
- for (size_t i = 0; i < cd->baseclasses->length; i++)
- {
- BaseClass *b = (*cd->baseclasses)[i];
- if (b->sym == this || isBaseOf2(b->sym))
- return true;
- }
- return false;
-}
-
-/*******************************************
- * Determine if 'this' is a base class of cd.
- */
-
-bool ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
-{
- //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars());
- if (poffset)
- *poffset = 0;
- while (cd)
- {
- /* cd->baseClass might not be set if cd is forward referenced.
- */
- if (!cd->baseClass && cd->semanticRun < PASSsemanticdone && !cd->isInterfaceDeclaration())
- {
- dsymbolSemantic(cd, NULL);
- if (!cd->baseClass && cd->semanticRun < PASSsemanticdone)
- cd->error("base class is forward referenced by %s", toChars());
- }
-
- if (this == cd->baseClass)
- return true;
-
- cd = cd->baseClass;
- }
- return false;
-}
-
-/*********************************************
- * Determine if 'this' has complete base class information.
- * This is used to detect forward references in covariant overloads.
- */
-
-bool ClassDeclaration::isBaseInfoComplete()
-{
- return baseok >= BASEOKdone;
-}
-
-Dsymbol *ClassDeclaration::search(const Loc &loc, Identifier *ident, int flags)
-{
- //printf("%s.ClassDeclaration::search('%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
-
- //if (_scope) printf("%s baseok = %d\n", toChars(), baseok);
- if (_scope && baseok < BASEOKdone)
- {
- if (!inuse)
- {
- // must semantic on base class/interfaces
- ++inuse;
- dsymbolSemantic(this, NULL);
- --inuse;
- }
- }
-
- if (!members || !symtab) // opaque or addMember is not yet done
- {
- error("is forward referenced when looking for `%s`", ident->toChars());
- //*(char*)0=0;
- return NULL;
- }
-
- Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
-
- // don't search imports of base classes
- if (flags & SearchImportsOnly)
- return s;
-
- if (!s)
- {
- // Search bases classes in depth-first, left to right order
-
- for (size_t i = 0; i < baseclasses->length; i++)
- {
- BaseClass *b = (*baseclasses)[i];
-
- if (b->sym)
- {
- if (!b->sym->symtab)
- error("base %s is forward referenced", b->sym->ident->toChars());
- else
- {
- s = b->sym->search(loc, ident, flags);
- if (!s)
- continue;
- else if (s == this) // happens if s is nested in this and derives from this
- s = NULL;
- else if (!(flags & IgnoreSymbolVisibility) && !(s->prot().kind == Prot::protected_) && !symbolIsVisible(this, s))
- s = NULL;
- else
- break;
- }
- }
- }
- }
- return s;
-}
-
-/************************************
- * Search base classes in depth-first, left-to-right order for
- * a class or interface named 'ident'.
- * Stops at first found. Does not look for additional matches.
- * Params:
- * ident = identifier to search for
- * Returns:
- * ClassDeclaration if found, null if not
- */
-ClassDeclaration *ClassDeclaration::searchBase(Identifier *ident)
-{
- for (size_t i = 0; i < baseclasses->length; i++)
- {
- BaseClass *b = (*baseclasses)[i];
- ClassDeclaration *cdb = b->type->isClassHandle();
- if (!cdb) // Bugzilla 10616
- return NULL;
- if (cdb->ident->equals(ident))
- return cdb;
- cdb = cdb->searchBase(ident);
- if (cdb)
- return cdb;
- }
- return NULL;
-}
-
-/****
- * Runs through the inheritance graph to set the BaseClass.offset fields.
- * Recursive in order to account for the size of the interface classes, if they are
- * more than just interfaces.
- * Params:
- * cd = interface to look at
- * baseOffset = offset of where cd will be placed
- * Returns:
- * subset of instantiated size used by cd for interfaces
- */
-static unsigned membersPlace(BaseClasses *vtblInterfaces, size_t &bi, ClassDeclaration *cd, unsigned baseOffset)
-{
- //printf(" membersPlace(%s, %d)\n", cd->toChars(), baseOffset);
- unsigned offset = baseOffset;
-
- for (size_t i = 0; i < cd->interfaces.length; i++)
- {
- BaseClass *b = cd->interfaces.ptr[i];
- if (b->sym->sizeok != SIZEOKdone)
- b->sym->finalizeSize();
- assert(b->sym->sizeok == SIZEOKdone);
-
- if (!b->sym->alignsize)
- b->sym->alignsize = target.ptrsize;
- cd->alignmember(b->sym->alignsize, b->sym->alignsize, &offset);
- assert(bi < vtblInterfaces->length);
- BaseClass *bv = (*vtblInterfaces)[bi];
- if (b->sym->interfaces.length == 0)
- {
- //printf("\tvtblInterfaces[%d] b=%p b->sym = %s, offset = %d\n", bi, bv, bv->sym->toChars(), offset);
- bv->offset = offset;
- ++bi;
- // All the base interfaces down the left side share the same offset
- for (BaseClass *b2 = bv; b2->baseInterfaces.length; )
- {
- b2 = &b2->baseInterfaces.ptr[0];
- b2->offset = offset;
- //printf("\tvtblInterfaces[%d] b=%p sym = %s, offset = %d\n", bi, b2, b2->sym->toChars(), b2->offset);
- }
- }
- membersPlace(vtblInterfaces, bi, b->sym, offset);
- //printf(" %s size = %d\n", b->sym->toChars(), b->sym->structsize);
- offset += b->sym->structsize;
- if (cd->alignsize < b->sym->alignsize)
- cd->alignsize = b->sym->alignsize;
- }
- return offset - baseOffset;
-}
-
-void ClassDeclaration::finalizeSize()
-{
- assert(sizeok != SIZEOKdone);
-
- // Set the offsets of the fields and determine the size of the class
- if (baseClass)
- {
- assert(baseClass->sizeok == SIZEOKdone);
-
- alignsize = baseClass->alignsize;
- if (classKind == ClassKind::cpp)
- structsize = target.cpp.derivedClassOffset(baseClass);
- else
- structsize = baseClass->structsize;
- }
- else if (isInterfaceDeclaration())
- {
- if (interfaces.length == 0)
- {
- alignsize = target.ptrsize;
- structsize = target.ptrsize; // allow room for __vptr
- }
- }
- else
- {
- alignsize = target.ptrsize;
- structsize = target.ptrsize; // allow room for __vptr
- if (hasMonitor())
- structsize += target.ptrsize; // allow room for __monitor
- }
-
- //printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
- size_t bi = 0; // index into vtblInterfaces[]
-
- // Add vptr's for any interfaces implemented by this class
- structsize += membersPlace(vtblInterfaces, bi, this, structsize);
-
- if (isInterfaceDeclaration())
- {
- sizeok = SIZEOKdone;
- return;
- }
-
- // FIXME: Currently setFieldOffset functions need to increase fields
- // to calculate each variable offsets. It can be improved later.
- fields.setDim(0);
-
- unsigned offset = structsize;
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->setFieldOffset(this, &offset, false);
- }
-
- sizeok = SIZEOKdone;
-
- // Calculate fields[i]->overlapped
- checkOverlappedFields();
-}
-
-/**************
- * Returns: true if there's a __monitor field
- */
-bool ClassDeclaration::hasMonitor()
-{
- return classKind == ClassKind::d;
-}
-
-/**********************************************************
- * fd is in the vtbl[] for this class.
- * Return 1 if function is hidden (not findable through search).
- */
-
-int isf(void *param, Dsymbol *s)
-{
- FuncDeclaration *fd = s->isFuncDeclaration();
- if (!fd)
- return 0;
- //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars());
- return (RootObject *)param == fd;
-}
-
-bool ClassDeclaration::isFuncHidden(FuncDeclaration *fd)
-{
- //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toPrettyChars());
- Dsymbol *s = search(Loc(), fd->ident, IgnoreAmbiguous | IgnoreErrors);
- if (!s)
- {
- //printf("not found\n");
- /* Because, due to a hack, if there are multiple definitions
- * of fd->ident, NULL is returned.
- */
- return false;
- }
- s = s->toAlias();
- OverloadSet *os = s->isOverloadSet();
- if (os)
- {
- for (size_t i = 0; i < os->a.length; i++)
- {
- Dsymbol *s2 = os->a[i];
- FuncDeclaration *f2 = s2->isFuncDeclaration();
- if (f2 && overloadApply(f2, (void *)fd, &isf))
- return false;
- }
- return true;
- }
- else
- {
- FuncDeclaration *fdstart = s->isFuncDeclaration();
- //printf("%s fdstart = %p\n", s->kind(), fdstart);
- if (overloadApply(fdstart, (void *)fd, &isf))
- return false;
-
- return !fd->parent->isTemplateMixin();
- }
-}
-
-/****************
- * Find virtual function matching identifier and type.
- * Used to build virtual function tables for interface implementations.
- */
-
-FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf)
-{
- //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars());
- FuncDeclaration *fdmatch = NULL;
- FuncDeclaration *fdambig = NULL;
-
- ClassDeclaration *cd = this;
- Dsymbols *vtbl = &cd->vtbl;
- while (1)
- {
- for (size_t i = 0; i < vtbl->length; i++)
- {
- FuncDeclaration *fd = (*vtbl)[i]->isFuncDeclaration();
- if (!fd)
- continue; // the first entry might be a ClassInfo
-
- //printf("\t[%d] = %s\n", i, fd->toChars());
- if (ident == fd->ident &&
- fd->type->covariant(tf) == 1)
- {
- //printf("fd->parent->isClassDeclaration() = %p\n", fd->parent->isClassDeclaration());
- if (!fdmatch)
- goto Lfd;
- if (fd == fdmatch)
- goto Lfdmatch;
-
- {
- // Function type matcing: exact > covariant
- MATCH m1 = tf->equals(fd ->type) ? MATCHexact : MATCHnomatch;
- MATCH m2 = tf->equals(fdmatch->type) ? MATCHexact : MATCHnomatch;
- if (m1 > m2)
- goto Lfd;
- else if (m1 < m2)
- goto Lfdmatch;
- }
-
- {
- MATCH m1 = (tf->mod == fd ->type->mod) ? MATCHexact : MATCHnomatch;
- MATCH m2 = (tf->mod == fdmatch->type->mod) ? MATCHexact : MATCHnomatch;
- if (m1 > m2)
- goto Lfd;
- else if (m1 < m2)
- goto Lfdmatch;
- }
-
- {
- // The way of definition: non-mixin > mixin
- MATCH m1 = fd ->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch;
- MATCH m2 = fdmatch->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch;
- if (m1 > m2)
- goto Lfd;
- else if (m1 < m2)
- goto Lfdmatch;
- }
-
- fdambig = fd;
- //printf("Lambig fdambig = %s %s [%s]\n", fdambig->toChars(), fdambig->type->toChars(), fdambig->loc.toChars());
- continue;
-
- Lfd:
- fdmatch = fd;
- fdambig = NULL;
- //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch->toChars(), fdmatch->type->toChars(), fdmatch->loc.toChars());
- continue;
-
- Lfdmatch:
- continue;
- }
- //else printf("\t\t%d\n", fd->type->covariant(tf));
- }
- if (!cd)
- break;
- vtbl = &cd->vtblFinal;
- cd = cd->baseClass;
- }
-
- if (fdambig)
- error("ambiguous virtual function %s", fdambig->toChars());
- return fdmatch;
-}
-
-/****************************************
- */
-
-bool ClassDeclaration::isCOMclass() const
-{
- return com;
-}
-
-bool ClassDeclaration::isCOMinterface() const
-{
- return false;
-}
-
-bool ClassDeclaration::isCPPclass() const
-{
- return classKind == ClassKind::cpp;
-}
-
-bool ClassDeclaration::isCPPinterface() const
-{
- return false;
-}
-
-
-/****************************************
- */
-
-bool ClassDeclaration::isAbstract()
-{
- if (isabstract != ABSfwdref)
- return isabstract == ABSyes;
-
- /* Bugzilla 11169: Resolve forward references to all class member functions,
- * and determine whether this class is abstract.
- */
- struct SearchAbstract
- {
- static int fp(Dsymbol *s, void *)
- {
- FuncDeclaration *fd = s->isFuncDeclaration();
- if (!fd)
- return 0;
- if (fd->storage_class & STCstatic)
- return 0;
-
- if (fd->_scope)
- dsymbolSemantic(fd, NULL);
-
- if (fd->isAbstract())
- return 1;
- return 0;
- }
- };
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- if (s->apply(&SearchAbstract::fp, this))
- {
- isabstract = ABSyes;
- return true;
- }
- }
-
- /* Iterate inherited member functions and check their abstract attribute.
- */
- for (size_t i = 1; i < vtbl.length; i++)
- {
- FuncDeclaration *fd = vtbl[i]->isFuncDeclaration();
- //if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd->loc.toChars(), fd->toChars());
- if (!fd || fd->isAbstract())
- {
- isabstract = ABSyes;
- return true;
- }
- }
-
- isabstract = ABSno;
- return false;
-}
-
-
-/****************************************
- * Determine if slot 0 of the vtbl[] is reserved for something else.
- * For class objects, yes, this is where the classinfo ptr goes.
- * For COM interfaces, no.
- * For non-COM interfaces, yes, this is where the Interface ptr goes.
- * Returns:
- * 0 vtbl[0] is first virtual function pointer
- * 1 vtbl[0] is classinfo/interfaceinfo pointer
- */
-
-int ClassDeclaration::vtblOffset() const
-{
- return classKind == ClassKind::cpp ? 0 : 1;
-}
-
-/****************************************
- */
-
-const char *ClassDeclaration::kind() const
-{
- return "class";
-}
-
-/****************************************
- */
-
-void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses)
-{
- aclasses->push(this);
-}
-
-/********************************* InterfaceDeclaration ****************************/
-
-InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses)
- : ClassDeclaration(loc, id, baseclasses, NULL, false)
-{
- if (id == Id::IUnknown) // IUnknown is the root of all COM interfaces
- {
- com = true;
- classKind = ClassKind::cpp; // IUnknown is also a C++ interface
- }
-}
-
-Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s)
-{
- InterfaceDeclaration *id =
- s ? (InterfaceDeclaration *)s
- : new InterfaceDeclaration(loc, ident, NULL);
- return ClassDeclaration::syntaxCopy(id);
-}
-
-Scope *InterfaceDeclaration::newScope(Scope *sc)
-{
- Scope *sc2 = ClassDeclaration::newScope(sc);
- if (com)
- sc2->linkage = LINKwindows;
- else if (classKind == ClassKind::cpp)
- sc2->linkage = LINKcpp;
- else if (classKind == ClassKind::objc)
- sc2->linkage = LINKobjc;
- return sc2;
-}
-
-/*******************************************
- * Determine if 'this' is a base class of cd.
- * (Actually, if it is an interface supported by cd)
- * Output:
- * *poffset offset to start of class
- * OFFSET_RUNTIME must determine offset at runtime
- * Returns:
- * false not a base
- * true is a base
- */
-
-bool InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset)
-{
- //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars());
- assert(!baseClass);
- for (size_t j = 0; j < cd->interfaces.length; j++)
- {
- BaseClass *b = cd->interfaces.ptr[j];
-
- //printf("\tX base %s\n", b->sym->toChars());
- if (this == b->sym)
- {
- //printf("\tfound at offset %d\n", b->offset);
- if (poffset)
- {
- // don't return incorrect offsets https://issues.dlang.org/show_bug.cgi?id=16980
- *poffset = cd->sizeok == SIZEOKdone ? b->offset : OFFSET_FWDREF;
- }
- //printf("\tfound at offset %d\n", b->offset);
- return true;
- }
- if (isBaseOf(b, poffset))
- return true;
- }
-
- if (cd->baseClass && isBaseOf(cd->baseClass, poffset))
- return true;
-
- if (poffset)
- *poffset = 0;
- return false;
-}
-
-bool InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset)
-{
- //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->sym->toChars());
- for (size_t j = 0; j < bc->baseInterfaces.length; j++)
- {
- BaseClass *b = &bc->baseInterfaces.ptr[j];
-
- //printf("\tY base %s\n", b->sym->toChars());
- if (this == b->sym)
- {
- //printf("\tfound at offset %d\n", b->offset);
- if (poffset)
- {
- *poffset = b->offset;
- }
- return true;
- }
- if (isBaseOf(b, poffset))
- {
- return true;
- }
- }
- if (poffset)
- *poffset = 0;
- return false;
-}
-
-/****************************************
- * Determine if slot 0 of the vtbl[] is reserved for something else.
- * For class objects, yes, this is where the ClassInfo ptr goes.
- * For COM interfaces, no.
- * For non-COM interfaces, yes, this is where the Interface ptr goes.
- */
-
-int InterfaceDeclaration::vtblOffset() const
-{
- if (isCOMinterface() || isCPPinterface())
- return 0;
- return 1;
-}
-
-bool InterfaceDeclaration::isCOMinterface() const
-{
- return com;
-}
-
-bool InterfaceDeclaration::isCPPinterface() const
-{
- return classKind == ClassKind::cpp;
-}
-
-/*******************************************
- */
-
-const char *InterfaceDeclaration::kind() const
-{
- return "interface";
-}
-
-
-/******************************** BaseClass *****************************/
-
-BaseClass::BaseClass()
-{
- this->type = NULL;
- this->sym = NULL;
- this->offset = 0;
-
- this->baseInterfaces.length = 0;
- this->baseInterfaces.ptr = NULL;
-}
-
-BaseClass::BaseClass(Type *type)
-{
- //printf("BaseClass(this = %p, '%s')\n", this, type->toChars());
- this->type = type;
- this->sym = NULL;
- this->offset = 0;
-
- this->baseInterfaces.length = 0;
- this->baseInterfaces.ptr = NULL;
-}
-
-/****************************************
- * Fill in vtbl[] for base class based on member functions of class cd.
- * Input:
- * vtbl if !=NULL, fill it in
- * newinstance !=0 means all entries must be filled in by members
- * of cd, not members of any base classes of cd.
- * Returns:
- * true if any entries were filled in by members of cd (not exclusively
- * by base classes)
- */
-
-bool BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance)
-{
- bool result = false;
-
- //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", sym->toChars(), cd->toChars());
- if (vtbl)
- vtbl->setDim(sym->vtbl.length);
-
- // first entry is ClassInfo reference
- for (size_t j = sym->vtblOffset(); j < sym->vtbl.length; j++)
- {
- FuncDeclaration *ifd = sym->vtbl[j]->isFuncDeclaration();
- FuncDeclaration *fd;
- TypeFunction *tf;
-
- //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null");
-
- assert(ifd);
- // Find corresponding function in this class
- tf = ifd->type->toTypeFunction();
- fd = cd->findFunc(ifd->ident, tf);
- if (fd && !fd->isAbstract())
- {
- //printf(" found\n");
- // Check that calling conventions match
- if (fd->linkage != ifd->linkage)
- fd->error("linkage doesn't match interface function");
-
- // Check that it is current
- //printf("newinstance = %d fd->toParent() = %s ifd->toParent() = %s\n",
- //newinstance, fd->toParent()->toChars(), ifd->toParent()->toChars());
- if (newinstance && fd->toParent() != cd && ifd->toParent() == sym)
- cd->error("interface function `%s` is not implemented", ifd->toFullSignature());
-
- if (fd->toParent() == cd)
- result = true;
- }
- else
- {
- //printf(" not found %p\n", fd);
- // BUG: should mark this class as abstract?
- if (!cd->isAbstract())
- cd->error("interface function `%s` is not implemented", ifd->toFullSignature());
-
- fd = NULL;
- }
- if (vtbl)
- (*vtbl)[j] = fd;
- }
-
- return result;
-}
-
-void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces)
-{
- //printf("+copyBaseInterfaces(), %s\n", sym->toChars());
-// if (baseInterfaces.length)
-// return;
-
- baseInterfaces.length = sym->interfaces.length;
- baseInterfaces.ptr = (BaseClass *)mem.xcalloc(baseInterfaces.length, sizeof(BaseClass));
-
- //printf("%s.copyBaseInterfaces()\n", sym->toChars());
- for (size_t i = 0; i < baseInterfaces.length; i++)
- {
- void *pb = &baseInterfaces.ptr[i];
- BaseClass *b2 = sym->interfaces.ptr[i];
-
- assert(b2->vtbl.length == 0); // should not be filled yet
- BaseClass *b = (BaseClass *)memcpy(pb, b2, sizeof(BaseClass));
-
- if (i) // single inheritance is i==0
- vtblInterfaces->push(b); // only need for M.I.
- b->copyBaseInterfaces(vtblInterfaces);
- }
- //printf("-copyBaseInterfaces\n");
-}
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
new file mode 100644
index 0000000..b065251
--- /dev/null
+++ b/gcc/d/dmd/dclass.d
@@ -0,0 +1,1139 @@
+/**
+ * Defines a `class` declaration.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/class.html, Classes)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dclass.d, _dclass.d)
+ * Documentation: https://dlang.org/phobos/dmd_dclass.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dclass.d
+ */
+
+module dmd.dclass;
+
+import core.stdc.stdio;
+import core.stdc.string;
+
+import dmd.aggregate;
+import dmd.apply;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.gluelayer;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.objc;
+import dmd.root.rmem;
+import dmd.target;
+import dmd.visitor;
+
+/***********************************************************
+ */
+extern (C++) struct BaseClass
+{
+ Type type; // (before semantic processing)
+
+ ClassDeclaration sym;
+ uint offset; // 'this' pointer offset
+
+ // for interfaces: Array of FuncDeclaration's making up the vtbl[]
+ FuncDeclarations vtbl;
+
+ // if BaseClass is an interface, these
+ // are a copy of the InterfaceDeclaration.interfaces
+ BaseClass[] baseInterfaces;
+
+ extern (D) this(Type type)
+ {
+ //printf("BaseClass(this = %p, '%s')\n", this, type.toChars());
+ this.type = type;
+ }
+
+ /****************************************
+ * Fill in vtbl[] for base class based on member functions of class cd.
+ * Input:
+ * vtbl if !=NULL, fill it in
+ * newinstance !=0 means all entries must be filled in by members
+ * of cd, not members of any base classes of cd.
+ * Returns:
+ * true if any entries were filled in by members of cd (not exclusively
+ * by base classes)
+ */
+ extern (C++) bool fillVtbl(ClassDeclaration cd, FuncDeclarations* vtbl, int newinstance)
+ {
+ bool result = false;
+
+ //printf("BaseClass.fillVtbl(this='%s', cd='%s')\n", sym.toChars(), cd.toChars());
+ if (vtbl)
+ vtbl.setDim(sym.vtbl.dim);
+
+ // first entry is ClassInfo reference
+ for (size_t j = sym.vtblOffset(); j < sym.vtbl.dim; j++)
+ {
+ FuncDeclaration ifd = sym.vtbl[j].isFuncDeclaration();
+
+ //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd.toChars() : "null");
+ assert(ifd);
+
+ // Find corresponding function in this class
+ auto tf = ifd.type.toTypeFunction();
+ auto fd = cd.findFunc(ifd.ident, tf);
+ if (fd && !fd.isAbstract())
+ {
+ if (fd.toParent() == cd)
+ result = true;
+ }
+ else
+ fd = null;
+ if (vtbl)
+ (*vtbl)[j] = fd;
+ }
+ return result;
+ }
+
+ extern (D) void copyBaseInterfaces(BaseClasses* vtblInterfaces)
+ {
+ //printf("+copyBaseInterfaces(), %s\n", sym.toChars());
+ // if (baseInterfaces.length)
+ // return;
+ auto bc = cast(BaseClass*)mem.xcalloc(sym.interfaces.length, BaseClass.sizeof);
+ baseInterfaces = bc[0 .. sym.interfaces.length];
+ //printf("%s.copyBaseInterfaces()\n", sym.toChars());
+ for (size_t i = 0; i < baseInterfaces.length; i++)
+ {
+ BaseClass* b = &baseInterfaces[i];
+ BaseClass* b2 = sym.interfaces[i];
+
+ assert(b2.vtbl.dim == 0); // should not be filled yet
+ memcpy(b, b2, BaseClass.sizeof);
+
+ if (i) // single inheritance is i==0
+ vtblInterfaces.push(b); // only need for M.I.
+ b.copyBaseInterfaces(vtblInterfaces);
+ }
+ //printf("-copyBaseInterfaces\n");
+ }
+}
+
+enum ClassFlags : uint
+{
+ none = 0x0,
+ isCOMclass = 0x1,
+ noPointers = 0x2,
+ hasOffTi = 0x4,
+ hasCtor = 0x8,
+ hasGetMembers = 0x10,
+ hasTypeInfo = 0x20,
+ isAbstract = 0x40,
+ isCPPclass = 0x80,
+ hasDtor = 0x100,
+}
+
+/***********************************************************
+ */
+extern (C++) class ClassDeclaration : AggregateDeclaration
+{
+ extern (C++) __gshared
+ {
+ // Names found by reading object.d in druntime
+ ClassDeclaration object;
+ ClassDeclaration throwable;
+ ClassDeclaration exception;
+ ClassDeclaration errorException;
+ ClassDeclaration cpp_type_info_ptr; // Object.__cpp_type_info_ptr
+ }
+
+ ClassDeclaration baseClass; // NULL only if this is Object
+ FuncDeclaration staticCtor;
+ FuncDeclaration staticDtor;
+ Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[]
+ Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[]
+
+ // Array of BaseClass's; first is super, rest are Interface's
+ BaseClasses* baseclasses;
+
+ /* Slice of baseclasses[] that does not include baseClass
+ */
+ BaseClass*[] interfaces;
+
+ // array of base interfaces that have their own vtbl[]
+ BaseClasses* vtblInterfaces;
+
+ // the ClassInfo object for this ClassDeclaration
+ TypeInfoClassDeclaration vclassinfo;
+
+ // true if this is a COM class
+ bool com;
+
+ /// true if this is a scope class
+ bool stack;
+
+ /// if this is a C++ class, this is the slot reserved for the virtual destructor
+ int cppDtorVtblIndex = -1;
+
+ /// to prevent recursive attempts
+ private bool inuse;
+
+ ThreeState isabstract;
+
+ /// set the progress of base classes resolving
+ Baseok baseok;
+
+ /**
+ * Data for a class declaration that is needed for the Objective-C
+ * integration.
+ */
+ ObjcClassDeclaration objc;
+
+ Symbol* cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr
+
+ final extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
+ {
+ objc = ObjcClassDeclaration(this);
+
+ if (!id)
+ id = Identifier.generateAnonymousId("class");
+
+ super(loc, id);
+
+ __gshared const(char)* msg = "only object.d can define this reserved class name";
+
+ if (baseclasses)
+ {
+ // Actually, this is a transfer
+ this.baseclasses = baseclasses;
+ }
+ else
+ this.baseclasses = new BaseClasses();
+
+ this.members = members;
+
+ //printf("ClassDeclaration(%s), dim = %d\n", ident.toChars(), this.baseclasses.dim);
+
+ // For forward references
+ type = new TypeClass(this);
+
+ // Look for special class names
+ if (id == Id.__sizeof || id == Id.__xalignof || id == Id._mangleof)
+ error("illegal class name");
+
+ // BUG: What if this is the wrong TypeInfo, i.e. it is nested?
+ if (id.toChars()[0] == 'T')
+ {
+ if (id == Id.TypeInfo)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.dtypeinfo = this;
+ }
+ if (id == Id.TypeInfo_Class)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfoclass = this;
+ }
+ if (id == Id.TypeInfo_Interface)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfointerface = this;
+ }
+ if (id == Id.TypeInfo_Struct)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfostruct = this;
+ }
+ if (id == Id.TypeInfo_Pointer)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfopointer = this;
+ }
+ if (id == Id.TypeInfo_Array)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfoarray = this;
+ }
+ if (id == Id.TypeInfo_StaticArray)
+ {
+ //if (!inObject)
+ // Type.typeinfostaticarray.error("%s", msg);
+ Type.typeinfostaticarray = this;
+ }
+ if (id == Id.TypeInfo_AssociativeArray)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfoassociativearray = this;
+ }
+ if (id == Id.TypeInfo_Enum)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfoenum = this;
+ }
+ if (id == Id.TypeInfo_Function)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfofunction = this;
+ }
+ if (id == Id.TypeInfo_Delegate)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfodelegate = this;
+ }
+ if (id == Id.TypeInfo_Tuple)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfotypelist = this;
+ }
+ if (id == Id.TypeInfo_Const)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfoconst = this;
+ }
+ if (id == Id.TypeInfo_Invariant)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfoinvariant = this;
+ }
+ if (id == Id.TypeInfo_Shared)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfoshared = this;
+ }
+ if (id == Id.TypeInfo_Wild)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfowild = this;
+ }
+ if (id == Id.TypeInfo_Vector)
+ {
+ if (!inObject)
+ error("%s", msg);
+ Type.typeinfovector = this;
+ }
+ }
+
+ if (id == Id.Object)
+ {
+ if (!inObject)
+ error("%s", msg);
+ object = this;
+ }
+
+ if (id == Id.Throwable)
+ {
+ if (!inObject)
+ error("%s", msg);
+ throwable = this;
+ }
+ if (id == Id.Exception)
+ {
+ if (!inObject)
+ error("%s", msg);
+ exception = this;
+ }
+ if (id == Id.Error)
+ {
+ if (!inObject)
+ error("%s", msg);
+ errorException = this;
+ }
+ if (id == Id.cpp_type_info_ptr)
+ {
+ if (!inObject)
+ error("%s", msg);
+ cpp_type_info_ptr = this;
+ }
+
+ baseok = Baseok.none;
+ }
+
+ static ClassDeclaration create(Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
+ {
+ return new ClassDeclaration(loc, id, baseclasses, members, inObject);
+ }
+
+ override const(char)* toPrettyChars(bool qualifyTypes = false)
+ {
+ if (objc.isMeta)
+ return .objc.toPrettyChars(this, qualifyTypes);
+
+ return super.toPrettyChars(qualifyTypes);
+ }
+
+ override ClassDeclaration syntaxCopy(Dsymbol s)
+ {
+ //printf("ClassDeclaration.syntaxCopy('%s')\n", toChars());
+ ClassDeclaration cd =
+ s ? cast(ClassDeclaration)s
+ : new ClassDeclaration(loc, ident, null, null, false);
+
+ cd.storage_class |= storage_class;
+
+ cd.baseclasses.setDim(this.baseclasses.dim);
+ for (size_t i = 0; i < cd.baseclasses.dim; i++)
+ {
+ BaseClass* b = (*this.baseclasses)[i];
+ auto b2 = new BaseClass(b.type.syntaxCopy());
+ (*cd.baseclasses)[i] = b2;
+ }
+
+ ScopeDsymbol.syntaxCopy(cd);
+ return cd;
+ }
+
+ override Scope* newScope(Scope* sc)
+ {
+ auto sc2 = super.newScope(sc);
+ if (isCOMclass())
+ {
+ /* This enables us to use COM objects under Linux and
+ * work with things like XPCOM
+ */
+ sc2.linkage = target.systemLinkage();
+ }
+ return sc2;
+ }
+
+ /*********************************************
+ * Determine if 'this' is a base class of cd.
+ * This is used to detect circular inheritance only.
+ */
+ final bool isBaseOf2(ClassDeclaration cd) pure nothrow @nogc
+ {
+ if (!cd)
+ return false;
+ //printf("ClassDeclaration.isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
+ for (size_t i = 0; i < cd.baseclasses.dim; i++)
+ {
+ BaseClass* b = (*cd.baseclasses)[i];
+ if (b.sym == this || isBaseOf2(b.sym))
+ return true;
+ }
+ return false;
+ }
+
+ enum OFFSET_RUNTIME = 0x76543210;
+ enum OFFSET_FWDREF = 0x76543211;
+
+ /*******************************************
+ * Determine if 'this' is a base class of cd.
+ */
+ bool isBaseOf(ClassDeclaration cd, int* poffset) pure nothrow @nogc
+ {
+ //printf("ClassDeclaration.isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
+ if (poffset)
+ *poffset = 0;
+ while (cd)
+ {
+ if (this == cd.baseClass)
+ return true;
+
+ cd = cd.baseClass;
+ }
+ return false;
+ }
+
+ /*********************************************
+ * Determine if 'this' has complete base class information.
+ * This is used to detect forward references in covariant overloads.
+ */
+ final bool isBaseInfoComplete() const
+ {
+ return baseok >= Baseok.done;
+ }
+
+ override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
+ {
+ //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
+ //if (_scope) printf("%s baseok = %d\n", toChars(), baseok);
+ if (_scope && baseok < Baseok.done)
+ {
+ if (!inuse)
+ {
+ // must semantic on base class/interfaces
+ inuse = true;
+ dsymbolSemantic(this, null);
+ inuse = false;
+ }
+ }
+
+ if (!members || !symtab) // opaque or addMember is not yet done
+ {
+ // .stringof is always defined (but may be hidden by some other symbol)
+ if (ident != Id.stringof && !(flags & IgnoreErrors) && semanticRun < PASS.semanticdone)
+ error("is forward referenced when looking for `%s`", ident.toChars());
+ //*(char*)0=0;
+ return null;
+ }
+
+ auto s = ScopeDsymbol.search(loc, ident, flags);
+
+ // don't search imports of base classes
+ if (flags & SearchImportsOnly)
+ return s;
+
+ if (s)
+ return s;
+
+ // Search bases classes in depth-first, left to right order
+ foreach (b; (*baseclasses)[])
+ {
+ if (!b.sym)
+ continue;
+
+ if (!b.sym.symtab)
+ {
+ error("base `%s` is forward referenced", b.sym.ident.toChars());
+ continue;
+ }
+
+ import dmd.access : symbolIsVisible;
+
+ s = b.sym.search(loc, ident, flags);
+ if (!s)
+ continue;
+ else if (s == this) // happens if s is nested in this and derives from this
+ s = null;
+ else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(this, s))
+ s = null;
+ else
+ break;
+ }
+
+ return s;
+ }
+
+ /************************************
+ * Search base classes in depth-first, left-to-right order for
+ * a class or interface named 'ident'.
+ * Stops at first found. Does not look for additional matches.
+ * Params:
+ * ident = identifier to search for
+ * Returns:
+ * ClassDeclaration if found, null if not
+ */
+ final ClassDeclaration searchBase(Identifier ident)
+ {
+ foreach (b; *baseclasses)
+ {
+ auto cdb = b.type.isClassHandle();
+ if (!cdb) // https://issues.dlang.org/show_bug.cgi?id=10616
+ return null;
+ if (cdb.ident.equals(ident))
+ return cdb;
+ auto result = cdb.searchBase(ident);
+ if (result)
+ return result;
+ }
+ return null;
+ }
+
+ final override void finalizeSize()
+ {
+ assert(sizeok != Sizeok.done);
+
+ // Set the offsets of the fields and determine the size of the class
+ if (baseClass)
+ {
+ assert(baseClass.sizeok == Sizeok.done);
+
+ alignsize = baseClass.alignsize;
+ if (classKind == ClassKind.cpp)
+ structsize = target.cpp.derivedClassOffset(baseClass);
+ else
+ structsize = baseClass.structsize;
+ }
+ else if (classKind == ClassKind.objc)
+ structsize = 0; // no hidden member for an Objective-C class
+ else if (isInterfaceDeclaration())
+ {
+ if (interfaces.length == 0)
+ {
+ alignsize = target.ptrsize;
+ structsize = target.ptrsize; // allow room for __vptr
+ }
+ }
+ else
+ {
+ alignsize = target.ptrsize;
+ structsize = target.ptrsize; // allow room for __vptr
+ if (hasMonitor())
+ structsize += target.ptrsize; // allow room for __monitor
+ }
+
+ //printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
+ size_t bi = 0; // index into vtblInterfaces[]
+
+ /****
+ * Runs through the inheritance graph to set the BaseClass.offset fields.
+ * Recursive in order to account for the size of the interface classes, if they are
+ * more than just interfaces.
+ * Params:
+ * cd = interface to look at
+ * baseOffset = offset of where cd will be placed
+ * Returns:
+ * subset of instantiated size used by cd for interfaces
+ */
+ uint membersPlace(ClassDeclaration cd, uint baseOffset)
+ {
+ //printf(" membersPlace(%s, %d)\n", cd.toChars(), baseOffset);
+ uint offset = baseOffset;
+
+ foreach (BaseClass* b; cd.interfaces)
+ {
+ if (b.sym.sizeok != Sizeok.done)
+ b.sym.finalizeSize();
+ assert(b.sym.sizeok == Sizeok.done);
+
+ if (!b.sym.alignsize)
+ b.sym.alignsize = target.ptrsize;
+ alignmember(b.sym.alignsize, b.sym.alignsize, &offset);
+ assert(bi < vtblInterfaces.dim);
+
+ BaseClass* bv = (*vtblInterfaces)[bi];
+ if (b.sym.interfaces.length == 0)
+ {
+ //printf("\tvtblInterfaces[%d] b=%p b.sym = %s, offset = %d\n", bi, bv, bv.sym.toChars(), offset);
+ bv.offset = offset;
+ ++bi;
+ // All the base interfaces down the left side share the same offset
+ for (BaseClass* b2 = bv; b2.baseInterfaces.length; )
+ {
+ b2 = &b2.baseInterfaces[0];
+ b2.offset = offset;
+ //printf("\tvtblInterfaces[%d] b=%p sym = %s, offset = %d\n", bi, b2, b2.sym.toChars(), b2.offset);
+ }
+ }
+ membersPlace(b.sym, offset);
+ //printf(" %s size = %d\n", b.sym.toChars(), b.sym.structsize);
+ offset += b.sym.structsize;
+ if (alignsize < b.sym.alignsize)
+ alignsize = b.sym.alignsize;
+ }
+ return offset - baseOffset;
+ }
+
+ structsize += membersPlace(this, structsize);
+
+ if (isInterfaceDeclaration())
+ {
+ sizeok = Sizeok.done;
+ return;
+ }
+
+ // FIXME: Currently setFieldOffset functions need to increase fields
+ // to calculate each variable offsets. It can be improved later.
+ fields.setDim(0);
+
+ FieldState fieldState;
+ fieldState.offset = structsize;
+ foreach (s; *members)
+ {
+ s.setFieldOffset(this, fieldState, false);
+ }
+
+ sizeok = Sizeok.done;
+
+ // Calculate fields[i].overlapped
+ checkOverlappedFields();
+ }
+
+ /**************
+ * Returns: true if there's a __monitor field
+ */
+ final bool hasMonitor()
+ {
+ return classKind == ClassKind.d;
+ }
+
+ final bool isFuncHidden(FuncDeclaration fd)
+ {
+ //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars());
+ Dsymbol s = search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors);
+ if (!s)
+ {
+ //printf("not found\n");
+ /* Because, due to a hack, if there are multiple definitions
+ * of fd.ident, NULL is returned.
+ */
+ return false;
+ }
+ s = s.toAlias();
+ if (auto os = s.isOverloadSet())
+ {
+ foreach (sm; os.a)
+ {
+ auto fm = sm.isFuncDeclaration();
+ if (overloadApply(fm, s => fd == s.isFuncDeclaration()))
+ return false;
+ }
+ return true;
+ }
+ else
+ {
+ auto f = s.isFuncDeclaration();
+ //printf("%s fdstart = %p\n", s.kind(), fdstart);
+ if (overloadApply(f, s => fd == s.isFuncDeclaration()))
+ return false;
+ return !fd.parent.isTemplateMixin();
+ }
+ }
+
+ /****************
+ * Find virtual function matching identifier and type.
+ * Used to build virtual function tables for interface implementations.
+ * Params:
+ * ident = function's identifier
+ * tf = function's type
+ * Returns:
+ * function symbol if found, null if not
+ * Errors:
+ * prints error message if more than one match
+ */
+ final FuncDeclaration findFunc(Identifier ident, TypeFunction tf)
+ {
+ //printf("ClassDeclaration.findFunc(%s, %s) %s\n", ident.toChars(), tf.toChars(), toChars());
+ FuncDeclaration fdmatch = null;
+ FuncDeclaration fdambig = null;
+
+ void updateBestMatch(FuncDeclaration fd)
+ {
+ fdmatch = fd;
+ fdambig = null;
+ //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch.toChars(), fdmatch.type.toChars(), fdmatch.loc.toChars());
+ }
+
+ void searchVtbl(ref Dsymbols vtbl)
+ {
+ foreach (s; vtbl)
+ {
+ auto fd = s.isFuncDeclaration();
+ if (!fd)
+ continue;
+
+ // the first entry might be a ClassInfo
+ //printf("\t[%d] = %s\n", i, fd.toChars());
+ if (ident != fd.ident || fd.type.covariant(tf) != Covariant.yes)
+ {
+ //printf("\t\t%d\n", fd.type.covariant(tf));
+ continue;
+ }
+
+ //printf("fd.parent.isClassDeclaration() = %p\n", fd.parent.isClassDeclaration());
+ if (!fdmatch)
+ {
+ updateBestMatch(fd);
+ continue;
+ }
+ if (fd == fdmatch)
+ continue;
+
+ {
+ // Function type matching: exact > covariant
+ MATCH m1 = tf.equals(fd.type) ? MATCH.exact : MATCH.nomatch;
+ MATCH m2 = tf.equals(fdmatch.type) ? MATCH.exact : MATCH.nomatch;
+ if (m1 > m2)
+ {
+ updateBestMatch(fd);
+ continue;
+ }
+ else if (m1 < m2)
+ continue;
+ }
+ {
+ MATCH m1 = (tf.mod == fd.type.mod) ? MATCH.exact : MATCH.nomatch;
+ MATCH m2 = (tf.mod == fdmatch.type.mod) ? MATCH.exact : MATCH.nomatch;
+ if (m1 > m2)
+ {
+ updateBestMatch(fd);
+ continue;
+ }
+ else if (m1 < m2)
+ continue;
+ }
+ {
+ // The way of definition: non-mixin > mixin
+ MATCH m1 = fd.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
+ MATCH m2 = fdmatch.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
+ if (m1 > m2)
+ {
+ updateBestMatch(fd);
+ continue;
+ }
+ else if (m1 < m2)
+ continue;
+ }
+
+ fdambig = fd;
+ //printf("Lambig fdambig = %s %s [%s]\n", fdambig.toChars(), fdambig.type.toChars(), fdambig.loc.toChars());
+ }
+ }
+
+ searchVtbl(vtbl);
+ for (auto cd = this; cd; cd = cd.baseClass)
+ {
+ searchVtbl(cd.vtblFinal);
+ }
+
+ if (fdambig)
+ error("ambiguous virtual function `%s`", fdambig.toChars());
+
+ return fdmatch;
+ }
+
+ /****************************************
+ */
+ final bool isCOMclass() const
+ {
+ return com;
+ }
+
+ bool isCOMinterface() const
+ {
+ return false;
+ }
+
+ final bool isCPPclass() const
+ {
+ return classKind == ClassKind.cpp;
+ }
+
+ bool isCPPinterface() const
+ {
+ return false;
+ }
+
+ /****************************************
+ */
+ final bool isAbstract()
+ {
+ enum log = false;
+ if (isabstract != ThreeState.none)
+ return isabstract == ThreeState.yes;
+
+ if (log) printf("isAbstract(%s)\n", toChars());
+
+ bool no() { if (log) printf("no\n"); isabstract = ThreeState.no; return false; }
+ bool yes() { if (log) printf("yes\n"); isabstract = ThreeState.yes; return true; }
+
+ if (storage_class & STC.abstract_ || _scope && _scope.stc & STC.abstract_)
+ return yes();
+
+ if (errors)
+ return no();
+
+ /* https://issues.dlang.org/show_bug.cgi?id=11169
+ * Resolve forward references to all class member functions,
+ * and determine whether this class is abstract.
+ */
+ static int func(Dsymbol s)
+ {
+ auto fd = s.isFuncDeclaration();
+ if (!fd)
+ return 0;
+ if (fd.storage_class & STC.static_)
+ return 0;
+
+ if (fd.isAbstract())
+ return 1;
+ return 0;
+ }
+
+ for (size_t i = 0; i < members.dim; i++)
+ {
+ auto s = (*members)[i];
+ if (s.apply(&func))
+ {
+ return yes();
+ }
+ }
+
+ /* If the base class is not abstract, then this class cannot
+ * be abstract.
+ */
+ if (!isInterfaceDeclaration() && (!baseClass || !baseClass.isAbstract()))
+ return no();
+
+ /* If any abstract functions are inherited, but not overridden,
+ * then the class is abstract. Do this by checking the vtbl[].
+ * Need to do semantic() on class to fill the vtbl[].
+ */
+ this.dsymbolSemantic(null);
+
+ /* The next line should work, but does not because when ClassDeclaration.dsymbolSemantic()
+ * is called recursively it can set PASS.semanticdone without finishing it.
+ */
+ //if (semanticRun < PASS.semanticdone)
+ {
+ /* Could not complete semantic(). Try running semantic() on
+ * each of the virtual functions,
+ * which will fill in the vtbl[] overrides.
+ */
+ static int virtualSemantic(Dsymbol s)
+ {
+ auto fd = s.isFuncDeclaration();
+ if (fd && !(fd.storage_class & STC.static_) && !fd.isUnitTestDeclaration())
+ fd.dsymbolSemantic(null);
+ return 0;
+ }
+
+ for (size_t i = 0; i < members.dim; i++)
+ {
+ auto s = (*members)[i];
+ s.apply(&virtualSemantic);
+ }
+ }
+
+ /* Finally, check the vtbl[]
+ */
+ foreach (i; 1 .. vtbl.dim)
+ {
+ auto fd = vtbl[i].isFuncDeclaration();
+ //if (fd) printf("\tvtbl[%d] = [%s] %s\n", i, fd.loc.toChars(), fd.toPrettyChars());
+ if (!fd || fd.isAbstract())
+ {
+ return yes();
+ }
+ }
+
+ return no();
+ }
+
+ /****************************************
+ * Determine if slot 0 of the vtbl[] is reserved for something else.
+ * For class objects, yes, this is where the classinfo ptr goes.
+ * For COM interfaces, no.
+ * For non-COM interfaces, yes, this is where the Interface ptr goes.
+ * Returns:
+ * 0 vtbl[0] is first virtual function pointer
+ * 1 vtbl[0] is classinfo/interfaceinfo pointer
+ */
+ int vtblOffset() const
+ {
+ return classKind == ClassKind.cpp ? 0 : 1;
+ }
+
+ /****************************************
+ */
+ override const(char)* kind() const
+ {
+ return "class";
+ }
+
+ /****************************************
+ */
+ override final void addLocalClass(ClassDeclarations* aclasses)
+ {
+ if (classKind != ClassKind.objc)
+ aclasses.push(this);
+ }
+
+ override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
+ {
+ .objc.addSymbols(this, classes, categories);
+ }
+
+ // Back end
+ Dsymbol vtblsym;
+
+ final Dsymbol vtblSymbol()
+ {
+ if (!vtblsym)
+ {
+ auto vtype = Type.tvoidptr.immutableOf().sarrayOf(vtbl.dim);
+ auto var = new VarDeclaration(loc, vtype, Identifier.idPool("__vtbl"), null, STC.immutable_ | STC.static_);
+ var.addMember(null, this);
+ var.isdataseg = 1;
+ var.linkage = LINK.d;
+ var.semanticRun = PASS.semanticdone; // no more semantic wanted
+ vtblsym = var;
+ }
+ return vtblsym;
+ }
+
+ override final inout(ClassDeclaration) isClassDeclaration() inout @nogc nothrow pure @safe
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class InterfaceDeclaration : ClassDeclaration
+{
+ extern (D) this(const ref Loc loc, Identifier id, BaseClasses* baseclasses)
+ {
+ super(loc, id, baseclasses, null, false);
+ if (id == Id.IUnknown) // IUnknown is the root of all COM interfaces
+ {
+ com = true;
+ classKind = ClassKind.cpp; // IUnknown is also a C++ interface
+ }
+ }
+
+ override InterfaceDeclaration syntaxCopy(Dsymbol s)
+ {
+ InterfaceDeclaration id =
+ s ? cast(InterfaceDeclaration)s
+ : new InterfaceDeclaration(loc, ident, null);
+ ClassDeclaration.syntaxCopy(id);
+ return id;
+ }
+
+
+ override Scope* newScope(Scope* sc)
+ {
+ auto sc2 = super.newScope(sc);
+ if (com)
+ sc2.linkage = LINK.windows;
+ else if (classKind == ClassKind.cpp)
+ sc2.linkage = LINK.cpp;
+ else if (classKind == ClassKind.objc)
+ sc2.linkage = LINK.objc;
+ return sc2;
+ }
+
+ /*******************************************
+ * Determine if 'this' is a base class of cd.
+ * (Actually, if it is an interface supported by cd)
+ * Output:
+ * *poffset offset to start of class
+ * OFFSET_RUNTIME must determine offset at runtime
+ * Returns:
+ * false not a base
+ * true is a base
+ */
+ override bool isBaseOf(ClassDeclaration cd, int* poffset) pure nothrow @nogc
+ {
+ //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars());
+ assert(!baseClass);
+ foreach (b; cd.interfaces)
+ {
+ //printf("\tX base %s\n", b.sym.toChars());
+ if (this == b.sym)
+ {
+ //printf("\tfound at offset %d\n", b.offset);
+ if (poffset)
+ {
+ // don't return incorrect offsets
+ // https://issues.dlang.org/show_bug.cgi?id=16980
+ *poffset = cd.sizeok == Sizeok.done ? b.offset : OFFSET_FWDREF;
+ }
+ // printf("\tfound at offset %d\n", b.offset);
+ return true;
+ }
+ if (baseClassImplementsInterface(this, b, poffset))
+ return true;
+ }
+ if (cd.baseClass && isBaseOf(cd.baseClass, poffset))
+ return true;
+
+ if (poffset)
+ *poffset = 0;
+ return false;
+ }
+
+ /*******************************************
+ */
+ override const(char)* kind() const
+ {
+ return "interface";
+ }
+
+ /****************************************
+ * Determine if slot 0 of the vtbl[] is reserved for something else.
+ * For class objects, yes, this is where the ClassInfo ptr goes.
+ * For COM interfaces, no.
+ * For non-COM interfaces, yes, this is where the Interface ptr goes.
+ */
+ override int vtblOffset() const
+ {
+ if (isCOMinterface() || isCPPinterface())
+ return 0;
+ return 1;
+ }
+
+ override bool isCPPinterface() const
+ {
+ return classKind == ClassKind.cpp;
+ }
+
+ override bool isCOMinterface() const
+ {
+ return com;
+ }
+
+ override inout(InterfaceDeclaration) isInterfaceDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/**
+ * Returns whether `bc` implements `id`, including indirectly (`bc` implements an interfaces
+ * that inherits from `id`)
+ *
+ * Params:
+ * id = the interface
+ * bc = the base class
+ * poffset = out parameter, offset of the interface in an object
+ *
+ * Returns:
+ * true if the `bc` implements `id`, false otherwise
+ **/
+private bool baseClassImplementsInterface(InterfaceDeclaration id, BaseClass* bc, int* poffset) pure nothrow @nogc
+{
+ //printf("%s.InterfaceDeclaration.isBaseOf(bc = '%s')\n", id.toChars(), bc.sym.toChars());
+ for (size_t j = 0; j < bc.baseInterfaces.length; j++)
+ {
+ BaseClass* b = &bc.baseInterfaces[j];
+ //printf("\tY base %s\n", b.sym.toChars());
+ if (id == b.sym)
+ {
+ //printf("\tfound at offset %d\n", b.offset);
+ if (poffset)
+ {
+ *poffset = b.offset;
+ }
+ return true;
+ }
+ if (baseClassImplementsInterface(id, b, poffset))
+ {
+ return true;
+ }
+ }
+
+ if (poffset)
+ *poffset = 0;
+ return false;
+}
diff --git a/gcc/d/dmd/declaration.c b/gcc/d/dmd/declaration.c
deleted file mode 100644
index a9394dc..0000000
--- a/gcc/d/dmd/declaration.c
+++ /dev/null
@@ -1,1575 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/declaration.c
- */
-
-#include "root/dsystem.h"
-#include "root/checkedint.h"
-
-#include "errors.h"
-#include "init.h"
-#include "declaration.h"
-#include "attrib.h"
-#include "mtype.h"
-#include "template.h"
-#include "scope.h"
-#include "aggregate.h"
-#include "module.h"
-#include "import.h"
-#include "id.h"
-#include "expression.h"
-#include "statement.h"
-#include "ctfe.h"
-#include "target.h"
-#include "hdrgen.h"
-
-bool checkNestedRef(Dsymbol *s, Dsymbol *p);
-
-/************************************
- * Check to see the aggregate type is nested and its context pointer is
- * accessible from the current scope.
- * Returns true if error occurs.
- */
-bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t iStart = 0)
-{
- Dsymbol *sparent = ad->toParent2();
- Dsymbol *s = sc->func;
- if (ad->isNested() && s)
- {
- //printf("ad = %p %s [%s], parent:%p\n", ad, ad->toChars(), ad->loc.toChars(), ad->parent);
- //printf("sparent = %p %s [%s], parent: %s\n", sparent, sparent->toChars(), sparent->loc.toChars(), sparent->parent->toChars());
- if (checkNestedRef(s, sparent))
- {
- error(loc, "cannot access frame pointer of %s", ad->toPrettyChars());
- return true;
- }
- }
-
- bool result = false;
- for (size_t i = iStart; i < ad->fields.length; i++)
- {
- VarDeclaration *vd = ad->fields[i];
- Type *tb = vd->type->baseElemOf();
- if (tb->ty == Tstruct)
- {
- result |= checkFrameAccess(loc, sc, ((TypeStruct *)tb)->sym);
- }
- }
- return result;
-}
-
-/********************************* Declaration ****************************/
-
-Declaration::Declaration(Identifier *id)
- : Dsymbol(id)
-{
- type = NULL;
- originalType = NULL;
- storage_class = STCundefined;
- protection = Prot(Prot::undefined);
- linkage = LINKdefault;
- inuse = 0;
- mangleOverride = NULL;
-}
-
-const char *Declaration::kind() const
-{
- return "declaration";
-}
-
-d_uns64 Declaration::size(Loc)
-{
- assert(type);
- return type->size();
-}
-
-bool Declaration::isDelete()
-{
- return false;
-}
-
-bool Declaration::isDataseg()
-{
- return false;
-}
-
-bool Declaration::isThreadlocal()
-{
- return false;
-}
-
-bool Declaration::isCodeseg() const
-{
- return false;
-}
-
-Prot Declaration::prot()
-{
- return protection;
-}
-
-/*************************************
- * Check to see if declaration can be modified in this context (sc).
- * Issue error if not.
- */
-
-int Declaration::checkModify(Loc loc, Scope *sc, Type *, Expression *e1, int flag)
-{
- VarDeclaration *v = isVarDeclaration();
- if (v && v->canassign)
- return 2;
-
- if (isParameter() || isResult())
- {
- for (Scope *scx = sc; scx; scx = scx->enclosing)
- {
- if (scx->func == parent && (scx->flags & SCOPEcontract))
- {
- const char *s = isParameter() && parent->ident != Id::ensure ? "parameter" : "result";
- if (!flag) error(loc, "cannot modify %s `%s` in contract", s, toChars());
- return 2; // do not report type related errors
- }
- }
- }
-
- if (e1 && e1->op == TOKthis && isField())
- {
- VarDeclaration *vthis = e1->isThisExp()->var;
- for (Scope *scx = sc; scx; scx = scx->enclosing)
- {
- if (scx->func == vthis->parent && (scx->flags & SCOPEcontract))
- {
- if (!flag)
- error(loc, "cannot modify parameter `this` in contract");
- return 2; // do not report type related errors
- }
- }
- }
-
- if (v && (isCtorinit() || isField()))
- {
- // It's only modifiable if inside the right constructor
- if ((storage_class & (STCforeach | STCref)) == (STCforeach | STCref))
- return 2;
- return modifyFieldVar(loc, sc, v, e1) ? 2 : 1;
- }
- return 1;
-}
-
-/**
- * Issue an error if an attempt to call a disabled method is made
- *
- * If the declaration is disabled but inside a disabled function,
- * returns `true` but do not issue an error message.
- *
- * Params:
- * loc = Location information of the call
- * sc = Scope in which the call occurs
- * isAliasedDeclaration = if `true` searches overload set
- *
- * Returns:
- * `true` if this `Declaration` is `@disable`d, `false` otherwise.
- */
-bool Declaration::checkDisabled(Loc loc, Scope *sc, bool isAliasedDeclaration)
-{
- if (!(storage_class & STCdisable))
- return false;
-
- if (sc->func && (sc->func->storage_class & STCdisable))
- return true;
-
- Dsymbol *p = toParent();
- if (p && isPostBlitDeclaration())
- {
- p->error(loc, "is not copyable because it is annotated with `@disable`");
- return true;
- }
-
- // if the function is @disabled, maybe there
- // is an overload in the overload set that isn't
- if (isAliasedDeclaration)
- {
- FuncDeclaration *fd = isFuncDeclaration();
- if (fd)
- {
- for (FuncDeclaration *ovl = fd; ovl; ovl = (FuncDeclaration *)ovl->overnext)
- if (!(ovl->storage_class & STCdisable))
- return false;
- }
- }
- error(loc, "cannot be used because it is annotated with `@disable`");
- return true;
-}
-
-Dsymbol *Declaration::search(const Loc &loc, Identifier *ident, int flags)
-{
- Dsymbol *s = Dsymbol::search(loc, ident, flags);
- if (!s && type)
- {
- s = type->toDsymbol(_scope);
- if (s)
- s = s->search(loc, ident, flags);
- }
- return s;
-}
-
-
-/********************************* TupleDeclaration ****************************/
-
-TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects)
- : Declaration(id)
-{
- this->loc = loc;
- this->type = NULL;
- this->objects = objects;
- this->isexp = false;
- this->tupletype = NULL;
-}
-
-Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *)
-{
- assert(0);
- return NULL;
-}
-
-const char *TupleDeclaration::kind() const
-{
- return "tuple";
-}
-
-Type *TupleDeclaration::getType()
-{
- /* If this tuple represents a type, return that type
- */
-
- //printf("TupleDeclaration::getType() %s\n", toChars());
- if (isexp)
- return NULL;
- if (!tupletype)
- {
- /* It's only a type tuple if all the Object's are types
- */
- for (size_t i = 0; i < objects->length; i++)
- {
- RootObject *o = (*objects)[i];
- if (o->dyncast() != DYNCAST_TYPE)
- {
- //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast());
- return NULL;
- }
- }
-
- /* We know it's a type tuple, so build the TypeTuple
- */
- Types *types = (Types *)objects;
- Parameters *args = new Parameters();
- args->setDim(objects->length);
- OutBuffer buf;
- int hasdeco = 1;
- for (size_t i = 0; i < types->length; i++)
- {
- Type *t = (*types)[i];
- //printf("type = %s\n", t->toChars());
- Parameter *arg = new Parameter(0, t, NULL, NULL, NULL);
- (*args)[i] = arg;
- if (!t->deco)
- hasdeco = 0;
- }
-
- tupletype = new TypeTuple(args);
- if (hasdeco)
- return typeSemantic(tupletype, Loc(), NULL);
- }
-
- return tupletype;
-}
-
-Dsymbol *TupleDeclaration::toAlias2()
-{
- //printf("TupleDeclaration::toAlias2() '%s' objects = %s\n", toChars(), objects->toChars());
-
- for (size_t i = 0; i < objects->length; i++)
- {
- RootObject *o = (*objects)[i];
- if (Dsymbol *s = isDsymbol(o))
- {
- s = s->toAlias2();
- (*objects)[i] = s;
- }
- }
- return this;
-}
-
-bool TupleDeclaration::needThis()
-{
- //printf("TupleDeclaration::needThis(%s)\n", toChars());
- for (size_t i = 0; i < objects->length; i++)
- {
- RootObject *o = (*objects)[i];
- if (o->dyncast() == DYNCAST_EXPRESSION)
- {
- Expression *e = (Expression *)o;
- if (e->op == TOKdsymbol)
- {
- DsymbolExp *ve = (DsymbolExp *)e;
- Declaration *d = ve->s->isDeclaration();
- if (d && d->needThis())
- {
- return true;
- }
- }
- }
- }
- return false;
-}
-
-/********************************* AliasDeclaration ****************************/
-
-AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type)
- : Declaration(id)
-{
- //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type);
- //printf("type = '%s'\n", type->toChars());
- this->loc = loc;
- this->type = type;
- this->aliassym = NULL;
- this->_import = NULL;
- this->overnext = NULL;
- assert(type);
-}
-
-AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s)
- : Declaration(id)
-{
- //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s);
- assert(s != this);
- this->loc = loc;
- this->type = NULL;
- this->aliassym = s;
- this->_import = NULL;
- this->overnext = NULL;
- assert(s);
-}
-
-AliasDeclaration *AliasDeclaration::create(Loc loc, Identifier *id, Type *type)
-{
- return new AliasDeclaration(loc, id, type);
-}
-
-Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s)
-{
- //printf("AliasDeclaration::syntaxCopy()\n");
- assert(!s);
- AliasDeclaration *sa =
- type ? new AliasDeclaration(loc, ident, type->syntaxCopy())
- : new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL));
- sa->storage_class = storage_class;
- return sa;
-}
-
-bool AliasDeclaration::overloadInsert(Dsymbol *s)
-{
- //printf("[%s] AliasDeclaration::overloadInsert('%s') s = %s %s @ [%s]\n",
- // loc.toChars(), toChars(), s->kind(), s->toChars(), s->loc.toChars());
-
- /** Aliases aren't overloadable themselves, but if their Aliasee is
- * overloadable they are converted to an overloadable Alias (either
- * FuncAliasDeclaration or OverDeclaration).
- *
- * This is done by moving the Aliasee into such an overloadable alias
- * which is then used to replace the existing Aliasee. The original
- * Alias (_this_) remains a useless shell.
- *
- * This is a horrible mess. It was probably done to avoid replacing
- * existing AST nodes and references, but it needs a major
- * simplification b/c it's too complex to maintain.
- *
- * A simpler approach might be to merge any colliding symbols into a
- * simple Overload class (an array) and then later have that resolve
- * all collisions.
- */
- if (semanticRun >= PASSsemanticdone)
- {
- /* Semantic analysis is already finished, and the aliased entity
- * is not overloadable.
- */
- if (type)
- return false;
-
- /* When s is added in member scope by static if, mixin("code") or others,
- * aliassym is determined already. See the case in: test/compilable/test61.d
- */
- Dsymbol *sa = aliassym->toAlias();
- if (FuncDeclaration *fd = sa->isFuncDeclaration())
- {
- FuncAliasDeclaration *fa = new FuncAliasDeclaration(ident, fd);
- fa->protection = protection;
- fa->parent = parent;
- aliassym = fa;
- return aliassym->overloadInsert(s);
- }
- if (TemplateDeclaration *td = sa->isTemplateDeclaration())
- {
- OverDeclaration *od = new OverDeclaration(ident, td);
- od->protection = protection;
- od->parent = parent;
- aliassym = od;
- return aliassym->overloadInsert(s);
- }
- if (OverDeclaration *od = sa->isOverDeclaration())
- {
- if (sa->ident != ident || sa->parent != parent)
- {
- od = new OverDeclaration(ident, od);
- od->protection = protection;
- od->parent = parent;
- aliassym = od;
- }
- return od->overloadInsert(s);
- }
- if (OverloadSet *os = sa->isOverloadSet())
- {
- if (sa->ident != ident || sa->parent != parent)
- {
- os = new OverloadSet(ident, os);
- // TODO: protection is lost here b/c OverloadSets have no protection attribute
- // Might no be a practical issue, b/c the code below fails to resolve the overload anyhow.
- // ----
- // module os1;
- // import a, b;
- // private alias merged = foo; // private alias to overload set of a.foo and b.foo
- // ----
- // module os2;
- // import a, b;
- // public alias merged = bar; // public alias to overload set of a.bar and b.bar
- // ----
- // module bug;
- // import os1, os2;
- // void test() { merged(123); } // should only look at os2.merged
- //
- // os.protection = protection;
- os->parent = parent;
- aliassym = os;
- }
- os->push(s);
- return true;
- }
- return false;
- }
-
- /* Don't know yet what the aliased symbol is, so assume it can
- * be overloaded and check later for correctness.
- */
- if (overnext)
- return overnext->overloadInsert(s);
- if (s == this)
- return true;
- overnext = s;
- return true;
-}
-
-const char *AliasDeclaration::kind() const
-{
- return "alias";
-}
-
-Type *AliasDeclaration::getType()
-{
- if (type)
- return type;
- return toAlias()->getType();
-}
-
-Dsymbol *AliasDeclaration::toAlias()
-{
- //printf("[%s] AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s', inuse = %d)\n",
- // loc.toChars(), toChars(), this, aliassym, aliassym ? aliassym->kind() : "", inuse);
- assert(this != aliassym);
- //static int count; if (++count == 10) *(char*)0=0;
- if (inuse == 1 && type && _scope)
- {
- inuse = 2;
- unsigned olderrors = global.errors;
- Dsymbol *s = type->toDsymbol(_scope);
- //printf("[%s] type = %s, s = %p, this = %p\n", loc.toChars(), type->toChars(), s, this);
- if (global.errors != olderrors)
- goto Lerr;
- if (s)
- {
- s = s->toAlias();
- if (global.errors != olderrors)
- goto Lerr;
- aliassym = s;
- inuse = 0;
- }
- else
- {
- Type *t = typeSemantic(type, loc, _scope);
- if (t->ty == Terror)
- goto Lerr;
- if (global.errors != olderrors)
- goto Lerr;
- //printf("t = %s\n", t->toChars());
- inuse = 0;
- }
- }
- if (inuse)
- {
- error("recursive alias declaration");
-
- Lerr:
- // Avoid breaking "recursive alias" state during errors gagged
- if (global.gag)
- return this;
-
- aliassym = new AliasDeclaration(loc, ident, Type::terror);
- type = Type::terror;
- return aliassym;
- }
-
- if (semanticRun >= PASSsemanticdone)
- {
- // semantic is already done.
-
- // Do not see aliassym !is null, because of lambda aliases.
-
- // Do not see type.deco !is null, even so "alias T = const int;` needs
- // semantic analysis to take the storage class `const` as type qualifier.
- }
- else
- {
- if (_import && _import->_scope)
- {
- /* If this is an internal alias for selective/renamed import,
- * load the module first.
- */
- dsymbolSemantic(_import, NULL);
- }
- if (_scope)
- {
- aliasSemantic(this, _scope);
- }
- }
-
- inuse = 1;
- Dsymbol *s = aliassym ? aliassym->toAlias() : this;
- inuse = 0;
- return s;
-}
-
-Dsymbol *AliasDeclaration::toAlias2()
-{
- if (inuse)
- {
- error("recursive alias declaration");
- return this;
- }
- inuse = 1;
- Dsymbol *s = aliassym ? aliassym->toAlias2() : this;
- inuse = 0;
- return s;
-}
-
-bool AliasDeclaration::isOverloadable()
-{
- // assume overloadable until alias is resolved
- return semanticRun < PASSsemanticdone ||
- (aliassym && aliassym->isOverloadable());
-}
-
-/****************************** OverDeclaration **************************/
-
-OverDeclaration::OverDeclaration(Identifier *ident, Dsymbol *s, bool hasOverloads)
- : Declaration(ident)
-{
- this->overnext = NULL;
- this->aliassym = s;
-
- this->hasOverloads = hasOverloads;
- if (hasOverloads)
- {
- if (OverDeclaration *od = aliassym->isOverDeclaration())
- this->hasOverloads = od->hasOverloads;
- }
- else
- {
- // for internal use
- assert(!aliassym->isOverDeclaration());
- }
-}
-
-const char *OverDeclaration::kind() const
-{
- return "overload alias"; // todo
-}
-
-bool OverDeclaration::equals(RootObject *o)
-{
- if (this == o)
- return true;
-
- Dsymbol *s = isDsymbol(o);
- if (!s)
- return false;
-
- OverDeclaration *od1 = this;
- if (OverDeclaration *od2 = s->isOverDeclaration())
- {
- return od1->aliassym->equals(od2->aliassym) &&
- od1->hasOverloads == od2->hasOverloads;
- }
- if (aliassym == s)
- {
- if (hasOverloads)
- return true;
- if (FuncDeclaration *fd = s->isFuncDeclaration())
- {
- return fd->isUnique() != NULL;
- }
- if (TemplateDeclaration *td = s->isTemplateDeclaration())
- {
- return td->overnext == NULL;
- }
- }
- return false;
-}
-
-bool OverDeclaration::overloadInsert(Dsymbol *s)
-{
- //printf("OverDeclaration::overloadInsert('%s') aliassym = %p, overnext = %p\n", s->toChars(), aliassym, overnext);
- if (overnext)
- return overnext->overloadInsert(s);
- if (s == this)
- return true;
- overnext = s;
- return true;
-}
-
-Dsymbol *OverDeclaration::toAlias()
-{
- return this;
-}
-
-bool OverDeclaration::isOverloadable()
-{
- return true;
-}
-
-Dsymbol *OverDeclaration::isUnique()
-{
- if (!hasOverloads)
- {
- if (aliassym->isFuncDeclaration() ||
- aliassym->isTemplateDeclaration())
- {
- return aliassym;
- }
- }
-
- struct ParamUniqueSym
- {
- static int fp(void *param, Dsymbol *s)
- {
- Dsymbol **ps = (Dsymbol **)param;
- if (*ps)
- {
- *ps = NULL;
- return 1; // ambiguous, done
- }
- else
- {
- *ps = s;
- return 0;
- }
- }
- };
- Dsymbol *result = NULL;
- overloadApply(aliassym, &result, &ParamUniqueSym::fp);
- return result;
-}
-
-/********************************* VarDeclaration ****************************/
-
-VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init)
- : Declaration(id)
-{
- //printf("VarDeclaration('%s')\n", id->toChars());
- assert(id);
- assert(type || init);
- this->type = type;
- this->_init = init;
- this->loc = loc;
- offset = 0;
- isargptr = false;
- alignment = 0;
- ctorinit = 0;
- aliassym = NULL;
- onstack = false;
- mynew = false;
- canassign = 0;
- overlapped = false;
- overlapUnsafe = false;
- doNotInferScope = false;
- isdataseg = 0;
- lastVar = NULL;
- endlinnum = 0;
- ctfeAdrOnStack = -1;
- edtor = NULL;
- range = NULL;
-
- static unsigned nextSequenceNumber = 0;
- this->sequenceNumber = ++nextSequenceNumber;
-}
-
-VarDeclaration *VarDeclaration::create(Loc loc, Type *type, Identifier *id, Initializer *init)
-{
- return new VarDeclaration(loc, type, id, init);
-}
-
-Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s)
-{
- //printf("VarDeclaration::syntaxCopy(%s)\n", toChars());
- assert(!s);
- VarDeclaration *v = new VarDeclaration(loc,
- type ? type->syntaxCopy() : NULL,
- ident,
- _init ? _init->syntaxCopy() : NULL);
- v->storage_class = storage_class;
- return v;
-}
-
-void VarDeclaration::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
-{
- //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad->toChars(), toChars());
-
- if (aliassym)
- {
- // If this variable was really a tuple, set the offsets for the tuple fields
- TupleDeclaration *v2 = aliassym->isTupleDeclaration();
- assert(v2);
- for (size_t i = 0; i < v2->objects->length; i++)
- {
- RootObject *o = (*v2->objects)[i];
- assert(o->dyncast() == DYNCAST_EXPRESSION);
- Expression *e = (Expression *)o;
- assert(e->op == TOKdsymbol);
- DsymbolExp *se = (DsymbolExp *)e;
- se->s->setFieldOffset(ad, poffset, isunion);
- }
- return;
- }
-
- if (!isField())
- return;
- assert(!(storage_class & (STCstatic | STCextern | STCparameter | STCtls)));
-
- //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad->toChars(), toChars());
-
- /* Fields that are tuples appear both as part of TupleDeclarations and
- * as members. That means ignore them if they are already a field.
- */
- if (offset)
- {
- // already a field
- *poffset = ad->structsize; // Bugzilla 13613
- return;
- }
- for (size_t i = 0; i < ad->fields.length; i++)
- {
- if (ad->fields[i] == this)
- {
- // already a field
- *poffset = ad->structsize; // Bugzilla 13613
- return;
- }
- }
-
- // Check for forward referenced types which will fail the size() call
- Type *t = type->toBasetype();
- if (storage_class & STCref)
- {
- // References are the size of a pointer
- t = Type::tvoidptr;
- }
- Type *tv = t->baseElemOf();
- if (tv->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)tv;
- assert(ts->sym != ad); // already checked in ad->determineFields()
- if (!ts->sym->determineSize(loc))
- {
- type = Type::terror;
- errors = true;
- return;
- }
- }
-
- // List in ad->fields. Even if the type is error, it's necessary to avoid
- // pointless error diagnostic "more initializers than fields" on struct literal.
- ad->fields.push(this);
-
- if (t->ty == Terror)
- return;
-
- const d_uns64 sz = t->size(loc);
- assert(sz != SIZE_INVALID && sz < UINT32_MAX);
- unsigned memsize = (unsigned)sz; // size of member
- unsigned memalignsize = target.fieldalign(t); // size of member for alignment purposes
-
- offset = AggregateDeclaration::placeField(poffset, memsize, memalignsize, alignment,
- &ad->structsize, &ad->alignsize, isunion);
-
- //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
-
- //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad->toChars(), offset, memsize);
-}
-
-const char *VarDeclaration::kind() const
-{
- return "variable";
-}
-
-Dsymbol *VarDeclaration::toAlias()
-{
- //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym);
- if ((!type || !type->deco) && _scope)
- dsymbolSemantic(this, _scope);
-
- assert(this != aliassym);
- Dsymbol *s = aliassym ? aliassym->toAlias() : this;
- return s;
-}
-
-AggregateDeclaration *VarDeclaration::isThis()
-{
- AggregateDeclaration *ad = NULL;
-
- if (!(storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter |
- STCtls | STCgshared | STCctfe)))
- {
- for (Dsymbol *s = this; s; s = s->parent)
- {
- ad = s->isMember();
- if (ad)
- break;
- if (!s->parent || !s->parent->isTemplateMixin()) break;
- }
- }
- return ad;
-}
-
-bool VarDeclaration::needThis()
-{
- //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class);
- return isField();
-}
-
-bool VarDeclaration::isExport() const
-{
- return protection.kind == Prot::export_;
-}
-
-bool VarDeclaration::isImportedSymbol() const
-{
- if (protection.kind == Prot::export_ && !_init &&
- (storage_class & STCstatic || parent->isModule()))
- return true;
- return false;
-}
-
-/*******************************************
- * Helper function for the expansion of manifest constant.
- */
-Expression *VarDeclaration::expandInitializer(Loc loc)
-{
- assert((storage_class & STCmanifest) && _init);
-
- Expression *e = getConstInitializer();
- if (!e)
- {
- ::error(loc, "cannot make expression out of initializer for %s", toChars());
- return new ErrorExp();
- }
-
- e = e->copy();
- e->loc = loc; // for better error message
- return e;
-}
-
-void VarDeclaration::checkCtorConstInit()
-{
-#if 0 /* doesn't work if more than one static ctor */
- if (ctorinit == 0 && isCtorinit() && !isField())
- error("missing initializer in static constructor for const variable");
-#endif
-}
-
-bool lambdaCheckForNestedRef(Expression *e, Scope *sc);
-
-/************************************
- * Check to see if this variable is actually in an enclosing function
- * rather than the current one.
- * Returns true if error occurs.
- */
-bool VarDeclaration::checkNestedReference(Scope *sc, Loc loc)
-{
- //printf("VarDeclaration::checkNestedReference() %s\n", toChars());
- if (sc->intypeof == 1 || (sc->flags & SCOPEctfe))
- return false;
- if (!parent || parent == sc->parent)
- return false;
- if (isDataseg() || (storage_class & STCmanifest))
- return false;
-
- // The current function
- FuncDeclaration *fdthis = sc->parent->isFuncDeclaration();
- if (!fdthis)
- return false; // out of function scope
-
- Dsymbol *p = toParent2();
-
- // Function literals from fdthis to p must be delegates
- checkNestedRef(fdthis, p);
-
- // The function that this variable is in
- FuncDeclaration *fdv = p->isFuncDeclaration();
- if (!fdv || fdv == fdthis)
- return false;
-
- // Add fdthis to nestedrefs[] if not already there
- if (!nestedrefs.contains(fdthis))
- nestedrefs.push(fdthis);
-
- /* __require and __ensure will always get called directly,
- * so they never make outer functions closure.
- */
- if (fdthis->ident == Id::require || fdthis->ident == Id::ensure)
- return false;
-
- //printf("\tfdv = %s\n", fdv->toChars());
- //printf("\tfdthis = %s\n", fdthis->toChars());
- if (loc.filename)
- {
- int lv = fdthis->getLevel(loc, sc, fdv);
- if (lv == -2) // error
- return true;
- }
-
- // Add this to fdv->closureVars[] if not already there
- if (!sc->intypeof && !(sc->flags & SCOPEcompile))
- {
- if (!fdv->closureVars.contains(this))
- fdv->closureVars.push(this);
- }
-
- //printf("fdthis is %s\n", fdthis->toChars());
- //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars());
- // __dollar creates problems because it isn't a real variable Bugzilla 3326
- if (ident == Id::dollar)
- {
- ::error(loc, "cannnot use $ inside a function literal");
- return true;
- }
-
- if (ident == Id::withSym) // Bugzilla 1759
- {
- ExpInitializer *ez = _init->isExpInitializer();
- assert(ez);
- Expression *e = ez->exp;
- if (e->op == TOKconstruct || e->op == TOKblit)
- e = ((AssignExp *)e)->e2;
- return lambdaCheckForNestedRef(e, sc);
- }
-
- return false;
-}
-
-/*******************************************
- * If variable has a constant expression initializer, get it.
- * Otherwise, return NULL.
- */
-
-Expression *VarDeclaration::getConstInitializer(bool needFullType)
-{
- assert(type && _init);
-
- // Ungag errors when not speculative
- unsigned oldgag = global.gag;
- if (global.gag)
- {
- Dsymbol *sym = toParent()->isAggregateDeclaration();
- if (sym && !sym->isSpeculative())
- global.gag = 0;
- }
-
- if (_scope)
- {
- inuse++;
- _init = initializerSemantic(_init, _scope, type, INITinterpret);
- _scope = NULL;
- inuse--;
- }
- Expression *e = initializerToExpression(_init, needFullType ? type : NULL);
-
- global.gag = oldgag;
- return e;
-}
-
-/*************************************
- * Return true if we can take the address of this variable.
- */
-
-bool VarDeclaration::canTakeAddressOf()
-{
- return !(storage_class & STCmanifest);
-}
-
-
-/*******************************
- * Does symbol go into data segment?
- * Includes extern variables.
- */
-
-bool VarDeclaration::isDataseg()
-{
- if (isdataseg == 0) // the value is not cached
- {
- isdataseg = 2; // The Variables does not go into the datasegment
-
- if (!canTakeAddressOf())
- {
- return false;
- }
-
- Dsymbol *parent = toParent();
- if (!parent && !(storage_class & STCstatic))
- {
- error("forward referenced");
- type = Type::terror;
- }
- else if (storage_class & (STCstatic | STCextern | STCtls | STCgshared) ||
- parent->isModule() || parent->isTemplateInstance() || parent->isNspace())
- {
- assert(!isParameter() && !isResult());
- isdataseg = 1; // It is in the DataSegment
- }
- }
-
- return (isdataseg == 1);
-}
-
-/************************************
- * Does symbol go into thread local storage?
- */
-
-bool VarDeclaration::isThreadlocal()
-{
- //printf("VarDeclaration::isThreadlocal(%p, '%s')\n", this, toChars());
- /* Data defaults to being thread-local. It is not thread-local
- * if it is immutable, const or shared.
- */
- bool i = isDataseg() &&
- !(storage_class & (STCimmutable | STCconst | STCshared | STCgshared));
- //printf("\treturn %d\n", i);
- return i;
-}
-
-/********************************************
- * Can variable be read and written by CTFE?
- */
-
-bool VarDeclaration::isCTFE()
-{
- return (storage_class & STCctfe) != 0; // || !isDataseg();
-}
-
-bool VarDeclaration::isOverlappedWith(VarDeclaration *v)
-{
- const d_uns64 vsz = v->type->size();
- const d_uns64 tsz = type->size();
- assert(vsz != SIZE_INVALID && tsz != SIZE_INVALID);
- return offset < v->offset + vsz &&
- v->offset < offset + tsz;
-}
-
-bool VarDeclaration::hasPointers()
-{
- //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty);
- return (!isDataseg() && type->hasPointers());
-}
-
-/******************************************
- * Return true if variable needs to call the destructor.
- */
-
-bool VarDeclaration::needsScopeDtor()
-{
- //printf("VarDeclaration::needsScopeDtor() %s\n", toChars());
- return edtor && !(storage_class & STCnodtor);
-}
-
-
-/******************************************
- * If a variable has a scope destructor call, return call for it.
- * Otherwise, return NULL.
- */
-
-Expression *VarDeclaration::callScopeDtor(Scope *)
-{
- //printf("VarDeclaration::callScopeDtor() %s\n", toChars());
-
- // Destruction of STCfield's is handled by buildDtor()
- if (storage_class & (STCnodtor | STCref | STCout | STCfield))
- {
- return NULL;
- }
-
- Expression *e = NULL;
-
- // Destructors for structs and arrays of structs
- Type *tv = type->baseElemOf();
- if (tv->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)tv)->sym;
- if (!sd->dtor || sd->errors)
- return NULL;
-
- const d_uns64 sz = type->size();
- assert(sz != SIZE_INVALID);
- if (!sz)
- return NULL;
-
- if (type->toBasetype()->ty == Tstruct)
- {
- // v.__xdtor()
- e = new VarExp(loc, this);
-
- /* This is a hack so we can call destructors on const/immutable objects.
- * Need to add things like "const ~this()" and "immutable ~this()" to
- * fix properly.
- */
- e->type = e->type->mutableOf();
-
- // Enable calling destructors on shared objects.
- // The destructor is always a single, non-overloaded function,
- // and must serve both shared and non-shared objects.
- e->type = e->type->unSharedOf();
-
- e = new DotVarExp(loc, e, sd->dtor, false);
- e = new CallExp(loc, e);
- }
- else
- {
- // __ArrayDtor(v[0 .. n])
- e = new VarExp(loc, this);
-
- const d_uns64 sdsz = sd->type->size();
- assert(sdsz != SIZE_INVALID && sdsz != 0);
- const d_uns64 n = sz / sdsz;
- e = new SliceExp(loc, e, new IntegerExp(loc, 0, Type::tsize_t),
- new IntegerExp(loc, n, Type::tsize_t));
- // Prevent redundant bounds check
- ((SliceExp *)e)->upperIsInBounds = true;
- ((SliceExp *)e)->lowerIsLessThanUpper = true;
-
- // This is a hack so we can call destructors on const/immutable objects.
- e->type = sd->type->arrayOf();
-
- e = new CallExp(loc, new IdentifierExp(loc, Id::__ArrayDtor), e);
- }
- return e;
- }
-
- // Destructors for classes
- if (storage_class & (STCauto | STCscope) && !(storage_class & STCparameter))
- {
- for (ClassDeclaration *cd = type->isClassHandle();
- cd;
- cd = cd->baseClass)
- {
- /* We can do better if there's a way with onstack
- * classes to determine if there's no way the monitor
- * could be set.
- */
- //if (cd->isInterfaceDeclaration())
- //error("interface %s cannot be scope", cd->toChars());
-
- // Destroying C++ scope classes crashes currently. Since C++ class dtors are not currently supported, simply do not run dtors for them.
- // See https://issues.dlang.org/show_bug.cgi?id=13182
- if (cd->isCPPclass())
- {
- break;
- }
- if (mynew || onstack) // if any destructors
- {
- // delete this;
- Expression *ec;
-
- ec = new VarExp(loc, this);
- e = new DeleteExp(loc, ec, true);
- e->type = Type::tvoid;
- break;
- }
- }
- }
- return e;
-}
-
-/**********************************
- * Determine if `this` has a lifetime that lasts past
- * the destruction of `v`
- * Params:
- * v = variable to test against
- * Returns:
- * true if it does
- */
-bool VarDeclaration::enclosesLifetimeOf(VarDeclaration *v) const
-{
- return sequenceNumber < v->sequenceNumber;
-}
-
-/******************************************
- */
-
-void ObjectNotFound(Identifier *id)
-{
- Type::error(Loc(), "%s not found. object.d may be incorrectly installed or corrupt.", id->toChars());
- fatal();
-}
-
-/******************************** SymbolDeclaration ********************************/
-
-SymbolDeclaration::SymbolDeclaration(Loc loc, StructDeclaration *dsym)
- : Declaration(dsym->ident)
-{
- this->loc = loc;
- this->dsym = dsym;
- storage_class |= STCconst;
-}
-
-/********************************* TypeInfoDeclaration ****************************/
-
-TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo)
- : VarDeclaration(Loc(), Type::dtypeinfo->type, tinfo->getTypeInfoIdent(), NULL)
-{
- this->tinfo = tinfo;
- storage_class = STCstatic | STCgshared;
- protection = Prot(Prot::public_);
- linkage = LINKc;
- alignment = target.ptrsize;
-}
-
-TypeInfoDeclaration *TypeInfoDeclaration::create(Type *tinfo)
-{
- return new TypeInfoDeclaration(tinfo);
-}
-
-Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *)
-{
- assert(0); // should never be produced by syntax
- return NULL;
-}
-
-const char *TypeInfoDeclaration::toChars()
-{
- //printf("TypeInfoDeclaration::toChars() tinfo = %s\n", tinfo->toChars());
- OutBuffer buf;
- buf.writestring("typeid(");
- buf.writestring(tinfo->toChars());
- buf.writeByte(')');
- return buf.extractChars();
-}
-
-/***************************** TypeInfoConstDeclaration **********************/
-
-TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfoconst)
- {
- ObjectNotFound(Id::TypeInfo_Const);
- }
- type = Type::typeinfoconst->type;
-}
-
-TypeInfoConstDeclaration *TypeInfoConstDeclaration::create(Type *tinfo)
-{
- return new TypeInfoConstDeclaration(tinfo);
-}
-
-/***************************** TypeInfoInvariantDeclaration **********************/
-
-TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfoinvariant)
- {
- ObjectNotFound(Id::TypeInfo_Invariant);
- }
- type = Type::typeinfoinvariant->type;
-}
-
-TypeInfoInvariantDeclaration *TypeInfoInvariantDeclaration::create(Type *tinfo)
-{
- return new TypeInfoInvariantDeclaration(tinfo);
-}
-
-/***************************** TypeInfoSharedDeclaration **********************/
-
-TypeInfoSharedDeclaration::TypeInfoSharedDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfoshared)
- {
- ObjectNotFound(Id::TypeInfo_Shared);
- }
- type = Type::typeinfoshared->type;
-}
-
-TypeInfoSharedDeclaration *TypeInfoSharedDeclaration::create(Type *tinfo)
-{
- return new TypeInfoSharedDeclaration(tinfo);
-}
-
-/***************************** TypeInfoWildDeclaration **********************/
-
-TypeInfoWildDeclaration::TypeInfoWildDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfowild)
- {
- ObjectNotFound(Id::TypeInfo_Wild);
- }
- type = Type::typeinfowild->type;
-}
-
-TypeInfoWildDeclaration *TypeInfoWildDeclaration::create(Type *tinfo)
-{
- return new TypeInfoWildDeclaration(tinfo);
-}
-
-/***************************** TypeInfoStructDeclaration **********************/
-
-TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfostruct)
- {
- ObjectNotFound(Id::TypeInfo_Struct);
- }
- type = Type::typeinfostruct->type;
-}
-
-TypeInfoStructDeclaration *TypeInfoStructDeclaration::create(Type *tinfo)
-{
- return new TypeInfoStructDeclaration(tinfo);
-}
-
-/***************************** TypeInfoClassDeclaration ***********************/
-
-TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfoclass)
- {
- ObjectNotFound(Id::TypeInfo_Class);
- }
- type = Type::typeinfoclass->type;
-}
-
-TypeInfoClassDeclaration *TypeInfoClassDeclaration::create(Type *tinfo)
-{
- return new TypeInfoClassDeclaration(tinfo);
-}
-
-/***************************** TypeInfoInterfaceDeclaration *******************/
-
-TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfointerface)
- {
- ObjectNotFound(Id::TypeInfo_Interface);
- }
- type = Type::typeinfointerface->type;
-}
-
-TypeInfoInterfaceDeclaration *TypeInfoInterfaceDeclaration::create(Type *tinfo)
-{
- return new TypeInfoInterfaceDeclaration(tinfo);
-}
-
-/***************************** TypeInfoPointerDeclaration *********************/
-
-TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfopointer)
- {
- ObjectNotFound(Id::TypeInfo_Pointer);
- }
- type = Type::typeinfopointer->type;
-}
-
-TypeInfoPointerDeclaration *TypeInfoPointerDeclaration::create(Type *tinfo)
-{
- return new TypeInfoPointerDeclaration(tinfo);
-}
-
-/***************************** TypeInfoArrayDeclaration ***********************/
-
-TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfoarray)
- {
- ObjectNotFound(Id::TypeInfo_Array);
- }
- type = Type::typeinfoarray->type;
-}
-
-TypeInfoArrayDeclaration *TypeInfoArrayDeclaration::create(Type *tinfo)
-{
- return new TypeInfoArrayDeclaration(tinfo);
-}
-
-/***************************** TypeInfoStaticArrayDeclaration *****************/
-
-TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfostaticarray)
- {
- ObjectNotFound(Id::TypeInfo_StaticArray);
- }
- type = Type::typeinfostaticarray->type;
-}
-
-TypeInfoStaticArrayDeclaration *TypeInfoStaticArrayDeclaration::create(Type *tinfo)
-{
- return new TypeInfoStaticArrayDeclaration(tinfo);
-}
-
-/***************************** TypeInfoAssociativeArrayDeclaration ************/
-
-TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfoassociativearray)
- {
- ObjectNotFound(Id::TypeInfo_AssociativeArray);
- }
- type = Type::typeinfoassociativearray->type;
-}
-
-TypeInfoAssociativeArrayDeclaration *TypeInfoAssociativeArrayDeclaration::create(Type *tinfo)
-{
- return new TypeInfoAssociativeArrayDeclaration(tinfo);
-}
-
-/***************************** TypeInfoVectorDeclaration ***********************/
-
-TypeInfoVectorDeclaration::TypeInfoVectorDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfovector)
- {
- ObjectNotFound(Id::TypeInfo_Vector);
- }
- type = Type::typeinfovector->type;
-}
-
-TypeInfoVectorDeclaration *TypeInfoVectorDeclaration::create(Type *tinfo)
-{
- return new TypeInfoVectorDeclaration(tinfo);
-}
-
-/***************************** TypeInfoEnumDeclaration ***********************/
-
-TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfoenum)
- {
- ObjectNotFound(Id::TypeInfo_Enum);
- }
- type = Type::typeinfoenum->type;
-}
-
-TypeInfoEnumDeclaration *TypeInfoEnumDeclaration::create(Type *tinfo)
-{
- return new TypeInfoEnumDeclaration(tinfo);
-}
-
-/***************************** TypeInfoFunctionDeclaration ********************/
-
-TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfofunction)
- {
- ObjectNotFound(Id::TypeInfo_Function);
- }
- type = Type::typeinfofunction->type;
-}
-
-TypeInfoFunctionDeclaration *TypeInfoFunctionDeclaration::create(Type *tinfo)
-{
- return new TypeInfoFunctionDeclaration(tinfo);
-}
-
-/***************************** TypeInfoDelegateDeclaration ********************/
-
-TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfodelegate)
- {
- ObjectNotFound(Id::TypeInfo_Delegate);
- }
- type = Type::typeinfodelegate->type;
-}
-
-TypeInfoDelegateDeclaration *TypeInfoDelegateDeclaration::create(Type *tinfo)
-{
- return new TypeInfoDelegateDeclaration(tinfo);
-}
-
-/***************************** TypeInfoTupleDeclaration **********************/
-
-TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo)
- : TypeInfoDeclaration(tinfo)
-{
- if (!Type::typeinfotypelist)
- {
- ObjectNotFound(Id::TypeInfo_Tuple);
- }
- type = Type::typeinfotypelist->type;
-}
-
-TypeInfoTupleDeclaration *TypeInfoTupleDeclaration::create(Type *tinfo)
-{
- return new TypeInfoTupleDeclaration(tinfo);
-}
-
-/********************************* ThisDeclaration ****************************/
-
-// For the "this" parameter to member functions
-
-ThisDeclaration::ThisDeclaration(Loc loc, Type *t)
- : VarDeclaration(loc, t, Id::This, NULL)
-{
- storage_class |= STCnodtor;
-}
-
-Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *)
-{
- assert(0); // should never be produced by syntax
- return NULL;
-}
-
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
new file mode 100644
index 0000000..0f40c11
--- /dev/null
+++ b/gcc/d/dmd/declaration.d
@@ -0,0 +1,2323 @@
+/**
+ * Miscellaneous declarations, including typedef, alias, variable declarations including the
+ * implicit this declaration, type tuples, ClassInfo, ModuleInfo and various TypeInfos.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/declaration.d, _declaration.d)
+ * Documentation: https://dlang.org/phobos/dmd_declaration.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/declaration.d
+ */
+
+module dmd.declaration;
+
+import core.stdc.stdio;
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.ctorflow;
+import dmd.dclass;
+import dmd.delegatize;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.initsem;
+import dmd.intrange;
+import dmd.mtype;
+import dmd.root.outbuffer;
+import dmd.root.rootobject;
+import dmd.target;
+import dmd.tokens;
+import dmd.typesem;
+import dmd.visitor;
+
+/************************************
+ * Check to see the aggregate type is nested and its context pointer is
+ * accessible from the current scope.
+ * Returns true if error occurs.
+ */
+bool checkFrameAccess(Loc loc, Scope* sc, AggregateDeclaration ad, size_t iStart = 0)
+{
+ Dsymbol sparent = ad.toParentLocal();
+ Dsymbol sparent2 = ad.toParent2();
+ Dsymbol s = sc.func;
+ if (ad.isNested() && s)
+ {
+ //printf("ad = %p %s [%s], parent:%p\n", ad, ad.toChars(), ad.loc.toChars(), ad.parent);
+ //printf("sparent = %p %s [%s], parent: %s\n", sparent, sparent.toChars(), sparent.loc.toChars(), sparent.parent,toChars());
+ //printf("sparent2 = %p %s [%s], parent: %s\n", sparent2, sparent2.toChars(), sparent2.loc.toChars(), sparent2.parent,toChars());
+ if (!ensureStaticLinkTo(s, sparent) || sparent != sparent2 && !ensureStaticLinkTo(s, sparent2))
+ {
+ error(loc, "cannot access frame pointer of `%s`", ad.toPrettyChars());
+ return true;
+ }
+ }
+
+ bool result = false;
+ for (size_t i = iStart; i < ad.fields.dim; i++)
+ {
+ VarDeclaration vd = ad.fields[i];
+ Type tb = vd.type.baseElemOf();
+ if (tb.ty == Tstruct)
+ {
+ result |= checkFrameAccess(loc, sc, (cast(TypeStruct)tb).sym);
+ }
+ }
+ return result;
+}
+
+/***********************************************
+ * Mark variable v as modified if it is inside a constructor that var
+ * is a field in.
+ */
+bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1)
+{
+ //printf("modifyFieldVar(var = %s)\n", var.toChars());
+ Dsymbol s = sc.func;
+ while (1)
+ {
+ FuncDeclaration fd = null;
+ if (s)
+ fd = s.isFuncDeclaration();
+ if (fd &&
+ ((fd.isCtorDeclaration() && var.isField()) ||
+ (fd.isStaticCtorDeclaration() && !var.isField())) &&
+ fd.toParentDecl() == var.toParent2() &&
+ (!e1 || e1.op == TOK.this_))
+ {
+ bool result = true;
+
+ var.ctorinit = true;
+ //printf("setting ctorinit\n");
+
+ if (var.isField() && sc.ctorflow.fieldinit.length && !sc.intypeof)
+ {
+ assert(e1);
+ auto mustInit = ((var.storage_class & STC.nodefaultctor) != 0 ||
+ var.type.needsNested());
+
+ const dim = sc.ctorflow.fieldinit.length;
+ auto ad = fd.isMemberDecl();
+ assert(ad);
+ size_t i;
+ for (i = 0; i < dim; i++) // same as findFieldIndexByName in ctfeexp.c ?
+ {
+ if (ad.fields[i] == var)
+ break;
+ }
+ assert(i < dim);
+ auto fieldInit = &sc.ctorflow.fieldinit[i];
+ const fi = fieldInit.csx;
+
+ if (fi & CSX.this_ctor)
+ {
+ if (var.type.isMutable() && e1.type.isMutable())
+ result = false;
+ else
+ {
+ const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod);
+ .error(loc, "%s field `%s` initialized multiple times", modStr, var.toChars());
+ .errorSupplemental(fieldInit.loc, "Previous initialization is here.");
+ }
+ }
+ else if (sc.inLoop || (fi & CSX.label))
+ {
+ if (!mustInit && var.type.isMutable() && e1.type.isMutable())
+ result = false;
+ else
+ {
+ const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod);
+ .error(loc, "%s field `%s` initialization is not allowed in loops or after labels", modStr, var.toChars());
+ }
+ }
+
+ fieldInit.csx |= CSX.this_ctor;
+ fieldInit.loc = e1.loc;
+ if (var.overlapped) // https://issues.dlang.org/show_bug.cgi?id=15258
+ {
+ foreach (j, v; ad.fields)
+ {
+ if (v is var || !var.isOverlappedWith(v))
+ continue;
+ v.ctorinit = true;
+ sc.ctorflow.fieldinit[j].csx = CSX.this_ctor;
+ }
+ }
+ }
+ else if (fd != sc.func)
+ {
+ if (var.type.isMutable())
+ result = false;
+ else if (sc.func.fes)
+ {
+ const(char)* p = var.isField() ? "field" : var.kind();
+ .error(loc, "%s %s `%s` initialization is not allowed in foreach loop",
+ MODtoChars(var.type.mod), p, var.toChars());
+ }
+ else
+ {
+ const(char)* p = var.isField() ? "field" : var.kind();
+ .error(loc, "%s %s `%s` initialization is not allowed in nested function `%s`",
+ MODtoChars(var.type.mod), p, var.toChars(), sc.func.toChars());
+ }
+ }
+ else if (fd.isStaticCtorDeclaration() && !fd.isSharedStaticCtorDeclaration() &&
+ var.type.isImmutable())
+ {
+ .error(loc, "%s %s `%s` initialization is not allowed in `static this`",
+ MODtoChars(var.type.mod), var.kind(), var.toChars());
+ errorSupplemental(loc, "Use `shared static this` instead.");
+ }
+ return result;
+ }
+ else
+ {
+ if (s)
+ {
+ s = s.toParentP(var.toParent2());
+ continue;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+/******************************************
+ */
+extern (C++) void ObjectNotFound(Identifier id)
+{
+ error(Loc.initial, "`%s` not found. object.d may be incorrectly installed or corrupt.", id.toChars());
+ fatal();
+}
+
+/* Accumulator for successive matches.
+ */
+struct MatchAccumulator
+{
+ int count; // number of matches found so far
+ MATCH last = MATCH.nomatch; // match level of lastf
+ FuncDeclaration lastf; // last matching function we found
+ FuncDeclaration nextf; // if ambiguous match, this is the "other" function
+}
+
+/***********************************************************
+ */
+extern (C++) abstract class Declaration : Dsymbol
+{
+ Type type;
+ Type originalType; // before semantic analysis
+ StorageClass storage_class = STC.undefined_;
+ Visibility visibility;
+ LINK linkage = LINK.default_;
+ short inuse; // used to detect cycles
+
+ ubyte adFlags; // control re-assignment of AliasDeclaration (put here for packing reasons)
+ enum wasRead = 1; // set if AliasDeclaration was read
+ enum ignoreRead = 2; // ignore any reads of AliasDeclaration
+
+ // overridden symbol with pragma(mangle, "...")
+ const(char)[] mangleOverride;
+
+ final extern (D) this(Identifier ident)
+ {
+ super(ident);
+ visibility = Visibility(Visibility.Kind.undefined);
+ }
+
+ final extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ super(loc, ident);
+ visibility = Visibility(Visibility.Kind.undefined);
+ }
+
+ override const(char)* kind() const
+ {
+ return "declaration";
+ }
+
+ override final d_uns64 size(const ref Loc loc)
+ {
+ assert(type);
+ return type.size();
+ }
+
+ /**
+ * Issue an error if an attempt to call a disabled method is made
+ *
+ * If the declaration is disabled but inside a disabled function,
+ * returns `true` but do not issue an error message.
+ *
+ * Params:
+ * loc = Location information of the call
+ * sc = Scope in which the call occurs
+ * isAliasedDeclaration = if `true` searches overload set
+ *
+ * Returns:
+ * `true` if this `Declaration` is `@disable`d, `false` otherwise.
+ */
+ extern (D) final bool checkDisabled(Loc loc, Scope* sc, bool isAliasedDeclaration = false)
+ {
+ if (!(storage_class & STC.disable))
+ return false;
+
+ if (sc.func && sc.func.storage_class & STC.disable)
+ return true;
+
+ if (auto p = toParent())
+ {
+ if (auto postblit = isPostBlitDeclaration())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=21885
+ *
+ * If the generated postblit is disabled, it
+ * means that one of the fields has a disabled
+ * postblit. Print the first field that has
+ * a disabled postblit.
+ */
+ if (postblit.generated)
+ {
+ auto sd = p.isStructDeclaration();
+ assert(sd);
+ for (size_t i = 0; i < sd.fields.dim; i++)
+ {
+ auto structField = sd.fields[i];
+ if (structField.overlapped)
+ continue;
+ Type tv = structField.type.baseElemOf();
+ if (tv.ty != Tstruct)
+ continue;
+ auto sdv = (cast(TypeStruct)tv).sym;
+ if (!sdv.postblit)
+ continue;
+ if (sdv.postblit.isDisabled())
+ {
+ p.error(loc, "is not copyable because field `%s` is not copyable", structField.toChars());
+ return true;
+ }
+ }
+ }
+ p.error(loc, "is not copyable because it has a disabled postblit");
+ return true;
+ }
+ }
+
+ // if the function is @disabled, maybe there
+ // is an overload in the overload set that isn't
+ if (isAliasedDeclaration)
+ {
+ FuncDeclaration fd = isFuncDeclaration();
+ if (fd)
+ {
+ for (FuncDeclaration ovl = fd; ovl; ovl = cast(FuncDeclaration)ovl.overnext)
+ if (!(ovl.storage_class & STC.disable))
+ return false;
+ }
+ }
+
+ if (auto ctor = isCtorDeclaration())
+ {
+ if (ctor.isCpCtor && ctor.generated)
+ {
+ .error(loc, "Generating an `inout` copy constructor for `struct %s` failed, therefore instances of it are uncopyable", parent.toPrettyChars());
+ return true;
+ }
+ }
+ error(loc, "cannot be used because it is annotated with `@disable`");
+ return true;
+ }
+
+ /*************************************
+ * Check to see if declaration can be modified in this context (sc).
+ * Issue error if not.
+ * Params:
+ * loc = location for error messages
+ * e1 = `null` or `this` expression when this declaration is a field
+ * sc = context
+ * flag = if the first bit is set it means do not issue error message for
+ * invalid modification; if the second bit is set, it means that
+ this declaration is a field and a subfield of it is modified.
+ * Returns:
+ * Modifiable.yes or Modifiable.initialization
+ */
+ extern (D) final Modifiable checkModify(Loc loc, Scope* sc, Expression e1, ModifyFlags flag)
+ {
+ VarDeclaration v = isVarDeclaration();
+ if (v && v.canassign)
+ return Modifiable.initialization;
+
+ if (isParameter() || isResult())
+ {
+ for (Scope* scx = sc; scx; scx = scx.enclosing)
+ {
+ if (scx.func == parent && (scx.flags & SCOPE.contract))
+ {
+ const(char)* s = isParameter() && parent.ident != Id.ensure ? "parameter" : "result";
+ if (!(flag & ModifyFlags.noError))
+ error(loc, "cannot modify %s `%s` in contract", s, toChars());
+ return Modifiable.initialization; // do not report type related errors
+ }
+ }
+ }
+
+ if (e1 && e1.op == TOK.this_ && isField())
+ {
+ VarDeclaration vthis = (cast(ThisExp)e1).var;
+ for (Scope* scx = sc; scx; scx = scx.enclosing)
+ {
+ if (scx.func == vthis.parent && (scx.flags & SCOPE.contract))
+ {
+ if (!(flag & ModifyFlags.noError))
+ error(loc, "cannot modify parameter `this` in contract");
+ return Modifiable.initialization; // do not report type related errors
+ }
+ }
+ }
+
+ if (v && (isCtorinit() || isField()))
+ {
+ // It's only modifiable if inside the right constructor
+ if ((storage_class & (STC.foreach_ | STC.ref_)) == (STC.foreach_ | STC.ref_))
+ return Modifiable.initialization;
+ if (flag & ModifyFlags.fieldAssign)
+ return Modifiable.yes;
+ return modifyFieldVar(loc, sc, v, e1) ? Modifiable.initialization : Modifiable.yes;
+ }
+ return Modifiable.yes;
+ }
+
+ override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
+ {
+ Dsymbol s = Dsymbol.search(loc, ident, flags);
+ if (!s && type)
+ {
+ s = type.toDsymbol(_scope);
+ if (s)
+ s = s.search(loc, ident, flags);
+ }
+ return s;
+ }
+
+ final bool isStatic() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.static_) != 0;
+ }
+
+ bool isDelete()
+ {
+ return false;
+ }
+
+ bool isDataseg()
+ {
+ return false;
+ }
+
+ bool isThreadlocal()
+ {
+ return false;
+ }
+
+ bool isCodeseg() const pure nothrow @nogc @safe
+ {
+ return false;
+ }
+
+ final bool isCtorinit() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.ctorinit) != 0;
+ }
+
+ final bool isFinal() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.final_) != 0;
+ }
+
+ bool isAbstract()
+ {
+ return (storage_class & STC.abstract_) != 0;
+ }
+
+ final bool isConst() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.const_) != 0;
+ }
+
+ final bool isImmutable() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.immutable_) != 0;
+ }
+
+ final bool isWild() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.wild) != 0;
+ }
+
+ final bool isAuto() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.auto_) != 0;
+ }
+
+ final bool isScope() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.scope_) != 0;
+ }
+
+ final bool isSynchronized() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.synchronized_) != 0;
+ }
+
+ final bool isParameter() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.parameter) != 0;
+ }
+
+ override final bool isDeprecated() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.deprecated_) != 0;
+ }
+
+ final bool isDisabled() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.disable) != 0;
+ }
+
+ final bool isOverride() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.override_) != 0;
+ }
+
+ final bool isResult() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.result) != 0;
+ }
+
+ final bool isField() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.field) != 0;
+ }
+
+ final bool isIn() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.in_) != 0;
+ }
+
+ final bool isOut() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.out_) != 0;
+ }
+
+ final bool isRef() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.ref_) != 0;
+ }
+
+ /// Returns: Whether the variable is a reference, annotated with `out` or `ref`
+ final bool isReference() const pure nothrow @nogc @safe
+ {
+ return (storage_class & (STC.ref_ | STC.out_)) != 0;
+ }
+
+ final bool isFuture() const pure nothrow @nogc @safe
+ {
+ return (storage_class & STC.future) != 0;
+ }
+
+ override final Visibility visible() pure nothrow @nogc @safe
+ {
+ return visibility;
+ }
+
+ override final inout(Declaration) isDeclaration() inout pure nothrow @nogc @safe
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TupleDeclaration : Declaration
+{
+ Objects* objects;
+ bool isexp; // true: expression tuple
+ TypeTuple tupletype; // !=null if this is a type tuple
+
+ extern (D) this(const ref Loc loc, Identifier ident, Objects* objects)
+ {
+ super(loc, ident);
+ this.objects = objects;
+ }
+
+ override TupleDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(0);
+ }
+
+ override const(char)* kind() const
+ {
+ return "tuple";
+ }
+
+ override Type getType()
+ {
+ /* If this tuple represents a type, return that type
+ */
+
+ //printf("TupleDeclaration::getType() %s\n", toChars());
+ if (isexp)
+ return null;
+ if (!tupletype)
+ {
+ /* It's only a type tuple if all the Object's are types
+ */
+ for (size_t i = 0; i < objects.dim; i++)
+ {
+ RootObject o = (*objects)[i];
+ if (o.dyncast() != DYNCAST.type)
+ {
+ //printf("\tnot[%d], %p, %d\n", i, o, o.dyncast());
+ return null;
+ }
+ }
+
+ /* We know it's a type tuple, so build the TypeTuple
+ */
+ Types* types = cast(Types*)objects;
+ auto args = new Parameters(objects.dim);
+ OutBuffer buf;
+ int hasdeco = 1;
+ for (size_t i = 0; i < types.dim; i++)
+ {
+ Type t = (*types)[i];
+ //printf("type = %s\n", t.toChars());
+ version (none)
+ {
+ buf.printf("_%s_%d", ident.toChars(), i);
+ const len = buf.offset;
+ const name = buf.extractSlice().ptr;
+ auto id = Identifier.idPool(name, len);
+ auto arg = new Parameter(STC.in_, t, id, null);
+ }
+ else
+ {
+ auto arg = new Parameter(0, t, null, null, null);
+ }
+ (*args)[i] = arg;
+ if (!t.deco)
+ hasdeco = 0;
+ }
+
+ tupletype = new TypeTuple(args);
+ if (hasdeco)
+ return tupletype.typeSemantic(Loc.initial, null);
+ }
+ return tupletype;
+ }
+
+ override Dsymbol toAlias2()
+ {
+ //printf("TupleDeclaration::toAlias2() '%s' objects = %s\n", toChars(), objects.toChars());
+ for (size_t i = 0; i < objects.dim; i++)
+ {
+ RootObject o = (*objects)[i];
+ if (Dsymbol s = isDsymbol(o))
+ {
+ s = s.toAlias2();
+ (*objects)[i] = s;
+ }
+ }
+ return this;
+ }
+
+ override bool needThis()
+ {
+ //printf("TupleDeclaration::needThis(%s)\n", toChars());
+ for (size_t i = 0; i < objects.dim; i++)
+ {
+ RootObject o = (*objects)[i];
+ if (o.dyncast() == DYNCAST.expression)
+ {
+ Expression e = cast(Expression)o;
+ if (e.op == TOK.dSymbol)
+ {
+ DsymbolExp ve = cast(DsymbolExp)e;
+ Declaration d = ve.s.isDeclaration();
+ if (d && d.needThis())
+ {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ override inout(TupleDeclaration) isTupleDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class AliasDeclaration : Declaration
+{
+ Dsymbol aliassym;
+ Dsymbol overnext; // next in overload list
+ Dsymbol _import; // !=null if unresolved internal alias for selective import
+
+ extern (D) this(const ref Loc loc, Identifier ident, Type type)
+ {
+ super(loc, ident);
+ //printf("AliasDeclaration(id = '%s', type = %p)\n", id.toChars(), type);
+ //printf("type = '%s'\n", type.toChars());
+ this.type = type;
+ assert(type);
+ }
+
+ extern (D) this(const ref Loc loc, Identifier ident, Dsymbol s)
+ {
+ super(loc, ident);
+ //printf("AliasDeclaration(id = '%s', s = %p)\n", id.toChars(), s);
+ assert(s != this);
+ this.aliassym = s;
+ assert(s);
+ }
+
+ static AliasDeclaration create(Loc loc, Identifier id, Type type)
+ {
+ return new AliasDeclaration(loc, id, type);
+ }
+
+ override AliasDeclaration syntaxCopy(Dsymbol s)
+ {
+ //printf("AliasDeclaration::syntaxCopy()\n");
+ assert(!s);
+ AliasDeclaration sa = type ? new AliasDeclaration(loc, ident, type.syntaxCopy()) : new AliasDeclaration(loc, ident, aliassym.syntaxCopy(null));
+ sa.comment = comment;
+ sa.storage_class = storage_class;
+ return sa;
+ }
+
+ override bool overloadInsert(Dsymbol s)
+ {
+ //printf("[%s] AliasDeclaration::overloadInsert('%s') s = %s %s @ [%s]\n",
+ // loc.toChars(), toChars(), s.kind(), s.toChars(), s.loc.toChars());
+
+ /** Aliases aren't overloadable themselves, but if their Aliasee is
+ * overloadable they are converted to an overloadable Alias (either
+ * FuncAliasDeclaration or OverDeclaration).
+ *
+ * This is done by moving the Aliasee into such an overloadable alias
+ * which is then used to replace the existing Aliasee. The original
+ * Alias (_this_) remains a useless shell.
+ *
+ * This is a horrible mess. It was probably done to avoid replacing
+ * existing AST nodes and references, but it needs a major
+ * simplification b/c it's too complex to maintain.
+ *
+ * A simpler approach might be to merge any colliding symbols into a
+ * simple Overload class (an array) and then later have that resolve
+ * all collisions.
+ */
+ if (semanticRun >= PASS.semanticdone)
+ {
+ /* Semantic analysis is already finished, and the aliased entity
+ * is not overloadable.
+ */
+ if (type)
+ return false;
+
+ /* When s is added in member scope by static if, mixin("code") or others,
+ * aliassym is determined already. See the case in: test/compilable/test61.d
+ */
+ auto sa = aliassym.toAlias();
+
+ if (auto td = s.toAlias().isTemplateDeclaration())
+ s = td.funcroot ? td.funcroot : td;
+
+ if (auto fd = sa.isFuncDeclaration())
+ {
+ auto fa = new FuncAliasDeclaration(ident, fd);
+ fa.visibility = visibility;
+ fa.parent = parent;
+ aliassym = fa;
+ return aliassym.overloadInsert(s);
+ }
+ if (auto td = sa.isTemplateDeclaration())
+ {
+ auto od = new OverDeclaration(ident, td.funcroot ? td.funcroot : td);
+ od.visibility = visibility;
+ od.parent = parent;
+ aliassym = od;
+ return aliassym.overloadInsert(s);
+ }
+ if (auto od = sa.isOverDeclaration())
+ {
+ if (sa.ident != ident || sa.parent != parent)
+ {
+ od = new OverDeclaration(ident, od);
+ od.visibility = visibility;
+ od.parent = parent;
+ aliassym = od;
+ }
+ return od.overloadInsert(s);
+ }
+ if (auto os = sa.isOverloadSet())
+ {
+ if (sa.ident != ident || sa.parent != parent)
+ {
+ os = new OverloadSet(ident, os);
+ // TODO: visibility is lost here b/c OverloadSets have no visibility attribute
+ // Might no be a practical issue, b/c the code below fails to resolve the overload anyhow.
+ // ----
+ // module os1;
+ // import a, b;
+ // private alias merged = foo; // private alias to overload set of a.foo and b.foo
+ // ----
+ // module os2;
+ // import a, b;
+ // public alias merged = bar; // public alias to overload set of a.bar and b.bar
+ // ----
+ // module bug;
+ // import os1, os2;
+ // void test() { merged(123); } // should only look at os2.merged
+ //
+ // os.visibility = visibility;
+ os.parent = parent;
+ aliassym = os;
+ }
+ os.push(s);
+ return true;
+ }
+ return false;
+ }
+
+ /* Don't know yet what the aliased symbol is, so assume it can
+ * be overloaded and check later for correctness.
+ */
+ if (overnext)
+ return overnext.overloadInsert(s);
+ if (s is this)
+ return true;
+ overnext = s;
+ return true;
+ }
+
+ override const(char)* kind() const
+ {
+ return "alias";
+ }
+
+ override Type getType()
+ {
+ if (type)
+ return type;
+ return toAlias().getType();
+ }
+
+ override Dsymbol toAlias()
+ {
+ //printf("[%s] AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s', inuse = %d)\n",
+ // loc.toChars(), toChars(), this, aliassym, aliassym ? aliassym.kind() : "", inuse);
+ assert(this != aliassym);
+ //static int count; if (++count == 10) *(char*)0=0;
+
+ // Reading the AliasDeclaration
+ if (!(adFlags & ignoreRead))
+ adFlags |= wasRead; // can never assign to this AliasDeclaration again
+
+ if (inuse == 1 && type && _scope)
+ {
+ inuse = 2;
+ uint olderrors = global.errors;
+ Dsymbol s = type.toDsymbol(_scope);
+ //printf("[%s] type = %s, s = %p, this = %p\n", loc.toChars(), type.toChars(), s, this);
+ if (global.errors != olderrors)
+ goto Lerr;
+ if (s)
+ {
+ s = s.toAlias();
+ if (global.errors != olderrors)
+ goto Lerr;
+ aliassym = s;
+ inuse = 0;
+ }
+ else
+ {
+ Type t = type.typeSemantic(loc, _scope);
+ if (t.ty == Terror)
+ goto Lerr;
+ if (global.errors != olderrors)
+ goto Lerr;
+ //printf("t = %s\n", t.toChars());
+ inuse = 0;
+ }
+ }
+ if (inuse)
+ {
+ error("recursive alias declaration");
+
+ Lerr:
+ // Avoid breaking "recursive alias" state during errors gagged
+ if (global.gag)
+ return this;
+ aliassym = new AliasDeclaration(loc, ident, Type.terror);
+ type = Type.terror;
+ return aliassym;
+ }
+
+ if (semanticRun >= PASS.semanticdone)
+ {
+ // semantic is already done.
+
+ // Do not see aliassym !is null, because of lambda aliases.
+
+ // Do not see type.deco !is null, even so "alias T = const int;` needs
+ // semantic analysis to take the storage class `const` as type qualifier.
+ }
+ else
+ {
+ if (_import && _import._scope)
+ {
+ /* If this is an internal alias for selective/renamed import,
+ * load the module first.
+ */
+ _import.dsymbolSemantic(null);
+ }
+ if (_scope)
+ {
+ aliasSemantic(this, _scope);
+ }
+ }
+
+ inuse = 1;
+ Dsymbol s = aliassym ? aliassym.toAlias() : this;
+ inuse = 0;
+ return s;
+ }
+
+ override Dsymbol toAlias2()
+ {
+ if (inuse)
+ {
+ error("recursive alias declaration");
+ return this;
+ }
+ inuse = 1;
+ Dsymbol s = aliassym ? aliassym.toAlias2() : this;
+ inuse = 0;
+ return s;
+ }
+
+ override bool isOverloadable() const
+ {
+ // assume overloadable until alias is resolved
+ return semanticRun < PASS.semanticdone ||
+ aliassym && aliassym.isOverloadable();
+ }
+
+ override inout(AliasDeclaration) isAliasDeclaration() inout
+ {
+ return this;
+ }
+
+ /** Returns: `true` if this instance was created to make a template parameter
+ visible in the scope of a template body, `false` otherwise */
+ extern (D) bool isAliasedTemplateParameter() const
+ {
+ return !!(storage_class & STC.templateparameter);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class OverDeclaration : Declaration
+{
+ Dsymbol overnext; // next in overload list
+ Dsymbol aliassym;
+
+ extern (D) this(Identifier ident, Dsymbol s)
+ {
+ super(ident);
+ this.aliassym = s;
+ }
+
+ override const(char)* kind() const
+ {
+ return "overload alias"; // todo
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+
+ auto s = isDsymbol(o);
+ if (!s)
+ return false;
+
+ if (auto od2 = s.isOverDeclaration())
+ return this.aliassym.equals(od2.aliassym);
+ return this.aliassym == s;
+ }
+
+ override bool overloadInsert(Dsymbol s)
+ {
+ //printf("OverDeclaration::overloadInsert('%s') aliassym = %p, overnext = %p\n", s.toChars(), aliassym, overnext);
+ if (overnext)
+ return overnext.overloadInsert(s);
+ if (s == this)
+ return true;
+ overnext = s;
+ return true;
+ }
+
+ override bool isOverloadable() const
+ {
+ return true;
+ }
+
+ Dsymbol isUnique()
+ {
+ Dsymbol result = null;
+ overloadApply(aliassym, (Dsymbol s)
+ {
+ if (result)
+ {
+ result = null;
+ return 1; // ambiguous, done
+ }
+ else
+ {
+ result = s;
+ return 0;
+ }
+ });
+ return result;
+ }
+
+ override inout(OverDeclaration) isOverDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) class VarDeclaration : Declaration
+{
+ Initializer _init;
+ FuncDeclarations nestedrefs; // referenced by these lexically nested functions
+ Dsymbol aliassym; // if redone as alias to another symbol
+ VarDeclaration lastVar; // Linked list of variables for goto-skips-init detection
+ Expression edtor; // if !=null, does the destruction of the variable
+ IntRange* range; // if !=null, the variable is known to be within the range
+ VarDeclarations* maybes; // STC.maybescope variables that are assigned to this STC.maybescope variable
+
+ uint endlinnum; // line number of end of scope that this var lives in
+ uint offset;
+ uint sequenceNumber; // order the variables are declared
+ __gshared uint nextSequenceNumber; // the counter for sequenceNumber
+ structalign_t alignment;
+
+ // When interpreting, these point to the value (NULL if value not determinable)
+ // The index of this variable on the CTFE stack, AdrOnStackNone if not allocated
+ enum AdrOnStackNone = ~0u;
+ uint ctfeAdrOnStack;
+
+ bool isargptr; // if parameter that _argptr points to
+ bool ctorinit; // it has been initialized in a ctor
+ bool iscatchvar; // this is the exception object variable in catch() clause
+ bool isowner; // this is an Owner, despite it being `scope`
+
+ // Both these mean the var is not rebindable once assigned,
+ // and the destructor gets run when it goes out of scope
+ bool onstack; // it is a class that was allocated on the stack
+ bool mynew; // it is a class new'd with custom operator new
+
+ byte canassign; // it can be assigned to
+ bool overlapped; // if it is a field and has overlapping
+ bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe
+ bool doNotInferScope; // do not infer 'scope' for this variable
+ bool doNotInferReturn; // do not infer 'return' for this variable
+ ubyte isdataseg; // private data for isDataseg 0 unset, 1 true, 2 false
+
+ bool isArgDtorVar; // temporary created to handle scope destruction of a function argument
+
+ final extern (D) this(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_)
+ in
+ {
+ assert(ident);
+ }
+ do
+ {
+ //printf("VarDeclaration('%s')\n", ident.toChars());
+ super(loc, ident);
+ debug
+ {
+ if (!type && !_init)
+ {
+ //printf("VarDeclaration('%s')\n", ident.toChars());
+ //*(char*)0=0;
+ }
+ }
+
+ assert(type || _init);
+ this.type = type;
+ this._init = _init;
+ ctfeAdrOnStack = AdrOnStackNone;
+ this.storage_class = storage_class;
+ sequenceNumber = ++nextSequenceNumber;
+ }
+
+ static VarDeclaration create(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_)
+ {
+ return new VarDeclaration(loc, type, ident, _init, storage_class);
+ }
+
+ override VarDeclaration syntaxCopy(Dsymbol s)
+ {
+ //printf("VarDeclaration::syntaxCopy(%s)\n", toChars());
+ assert(!s);
+ auto v = new VarDeclaration(loc, type ? type.syntaxCopy() : null, ident, _init ? _init.syntaxCopy() : null, storage_class);
+ v.comment = comment;
+ return v;
+ }
+
+ override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
+ {
+ //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
+
+ if (aliassym)
+ {
+ // If this variable was really a tuple, set the offsets for the tuple fields
+ TupleDeclaration v2 = aliassym.isTupleDeclaration();
+ assert(v2);
+ for (size_t i = 0; i < v2.objects.dim; i++)
+ {
+ RootObject o = (*v2.objects)[i];
+ assert(o.dyncast() == DYNCAST.expression);
+ Expression e = cast(Expression)o;
+ assert(e.op == TOK.dSymbol);
+ DsymbolExp se = cast(DsymbolExp)e;
+ se.s.setFieldOffset(ad, fieldState, isunion);
+ }
+ return;
+ }
+
+ if (!isField())
+ return;
+ assert(!(storage_class & (STC.static_ | STC.extern_ | STC.parameter | STC.tls)));
+
+ //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
+
+ /* Fields that are tuples appear both as part of TupleDeclarations and
+ * as members. That means ignore them if they are already a field.
+ */
+ if (offset)
+ {
+ // already a field
+ fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
+ return;
+ }
+ for (size_t i = 0; i < ad.fields.dim; i++)
+ {
+ if (ad.fields[i] == this)
+ {
+ // already a field
+ fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
+ return;
+ }
+ }
+
+ // Check for forward referenced types which will fail the size() call
+ Type t = type.toBasetype();
+ if (storage_class & STC.ref_)
+ {
+ // References are the size of a pointer
+ t = Type.tvoidptr;
+ }
+ Type tv = t.baseElemOf();
+ if (tv.ty == Tstruct)
+ {
+ auto ts = cast(TypeStruct)tv;
+ assert(ts.sym != ad); // already checked in ad.determineFields()
+ if (!ts.sym.determineSize(loc))
+ {
+ type = Type.terror;
+ errors = true;
+ return;
+ }
+ }
+
+ // List in ad.fields. Even if the type is error, it's necessary to avoid
+ // pointless error diagnostic "more initializers than fields" on struct literal.
+ ad.fields.push(this);
+
+ if (t.ty == Terror)
+ return;
+
+ /* If coming after a bit field in progress,
+ * advance past the field
+ */
+ if (fieldState.inFlight)
+ {
+ fieldState.inFlight = false;
+ if (0 && target.os & Target.OS.Posix)
+ fieldState.offset += (fieldState.bitOffset + 7) / 8;
+ else if (0 &&target.os == Target.OS.Windows)
+ fieldState.offset += fieldState.fieldSize;
+ }
+
+ const sz = t.size(loc);
+ assert(sz != SIZE_INVALID && sz < uint.max);
+ uint memsize = cast(uint)sz; // size of member
+ uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
+ offset = AggregateDeclaration.placeField(
+ &fieldState.offset,
+ memsize, memalignsize, alignment,
+ &ad.structsize, &ad.alignsize,
+ isunion);
+
+ //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
+ //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
+ }
+
+ override const(char)* kind() const
+ {
+ return "variable";
+ }
+
+ override final inout(AggregateDeclaration) isThis() inout
+ {
+ if (!(storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.tls | STC.gshared | STC.ctfe)))
+ {
+ /* The casting is necessary because `s = s.parent` is otherwise rejected
+ */
+ for (auto s = cast(Dsymbol)this; s; s = s.parent)
+ {
+ auto ad = (cast(inout)s).isMember();
+ if (ad)
+ return ad;
+ if (!s.parent || !s.parent.isTemplateMixin())
+ break;
+ }
+ }
+ return null;
+ }
+
+ override final bool needThis()
+ {
+ //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class);
+ return isField();
+ }
+
+ override final bool isExport() const
+ {
+ return visibility.kind == Visibility.Kind.export_;
+ }
+
+ override final bool isImportedSymbol() const
+ {
+ if (visibility.kind == Visibility.Kind.export_ && !_init && (storage_class & STC.static_ || parent.isModule()))
+ return true;
+ return false;
+ }
+
+ /*******************************
+ * Does symbol go into data segment?
+ * Includes extern variables.
+ */
+ override final bool isDataseg()
+ {
+ version (none)
+ {
+ printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars());
+ printf("%llx, isModule: %p, isTemplateInstance: %p, isNspace: %p\n",
+ storage_class & (STC.static_ | STC.const_), parent.isModule(), parent.isTemplateInstance(), parent.isNspace());
+ printf("parent = '%s'\n", parent.toChars());
+ }
+
+ if (isdataseg == 0) // the value is not cached
+ {
+ isdataseg = 2; // The Variables does not go into the datasegment
+
+ if (!canTakeAddressOf())
+ {
+ return false;
+ }
+
+ Dsymbol parent = toParent();
+ if (!parent && !(storage_class & STC.static_))
+ {
+ error("forward referenced");
+ type = Type.terror;
+ }
+ else if (storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared) ||
+ parent.isModule() || parent.isTemplateInstance() || parent.isNspace())
+ {
+ assert(!isParameter() && !isResult());
+ isdataseg = 1; // It is in the DataSegment
+ }
+ }
+
+ return (isdataseg == 1);
+ }
+ /************************************
+ * Does symbol go into thread local storage?
+ */
+ override final bool isThreadlocal()
+ {
+ //printf("VarDeclaration::isThreadlocal(%p, '%s')\n", this, toChars());
+ /* Data defaults to being thread-local. It is not thread-local
+ * if it is immutable, const or shared.
+ */
+ bool i = isDataseg() && !(storage_class & (STC.immutable_ | STC.const_ | STC.shared_ | STC.gshared));
+ //printf("\treturn %d\n", i);
+ return i;
+ }
+
+ /********************************************
+ * Can variable be read and written by CTFE?
+ */
+ final bool isCTFE()
+ {
+ return (storage_class & STC.ctfe) != 0; // || !isDataseg();
+ }
+
+ final bool isOverlappedWith(VarDeclaration v)
+ {
+ const vsz = v.type.size();
+ const tsz = type.size();
+ assert(vsz != SIZE_INVALID && tsz != SIZE_INVALID);
+
+ // Overlap is checked by comparing bit offsets
+ auto bitoffset = offset * 8;
+ auto vbitoffset = v.offset * 8;
+
+ // Bitsize of types are overridden by any bit-field widths.
+ ulong tbitsize = void;
+ if (auto bf = isBitFieldDeclaration())
+ {
+ bitoffset += bf.bitOffset;
+ tbitsize = bf.fieldWidth;
+ }
+ else
+ tbitsize = tsz * 8;
+
+ ulong vbitsize = void;
+ if (auto vbf = v.isBitFieldDeclaration())
+ {
+ vbitoffset += vbf.bitOffset;
+ vbitsize = vbf.fieldWidth;
+ }
+ else
+ vbitsize = vsz * 8;
+
+ return bitoffset < vbitoffset + vbitsize &&
+ vbitoffset < bitoffset + tbitsize;
+ }
+
+ override final bool hasPointers()
+ {
+ //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type.ty);
+ return (!isDataseg() && type.hasPointers());
+ }
+
+ /*************************************
+ * Return true if we can take the address of this variable.
+ */
+ final bool canTakeAddressOf()
+ {
+ return !(storage_class & STC.manifest);
+ }
+
+ /******************************************
+ * Return true if variable needs to call the destructor.
+ */
+ final bool needsScopeDtor()
+ {
+ //printf("VarDeclaration::needsScopeDtor() %s\n", toChars());
+ return edtor && !(storage_class & STC.nodtor);
+ }
+
+ /******************************************
+ * If a variable has a scope destructor call, return call for it.
+ * Otherwise, return NULL.
+ */
+ extern (D) final Expression callScopeDtor(Scope* sc)
+ {
+ //printf("VarDeclaration::callScopeDtor() %s\n", toChars());
+
+ // Destruction of STC.field's is handled by buildDtor()
+ if (storage_class & (STC.nodtor | STC.ref_ | STC.out_ | STC.field))
+ {
+ return null;
+ }
+
+ if (iscatchvar)
+ return null; // destructor is built by `void semantic(Catch c, Scope* sc)`, not here
+
+ Expression e = null;
+ // Destructors for structs and arrays of structs
+ Type tv = type.baseElemOf();
+ if (tv.ty == Tstruct)
+ {
+ StructDeclaration sd = (cast(TypeStruct)tv).sym;
+ if (!sd.dtor || sd.errors)
+ return null;
+
+ const sz = type.size();
+ assert(sz != SIZE_INVALID);
+ if (!sz)
+ return null;
+
+ if (type.toBasetype().ty == Tstruct)
+ {
+ // v.__xdtor()
+ e = new VarExp(loc, this);
+
+ /* This is a hack so we can call destructors on const/immutable objects.
+ * Need to add things like "const ~this()" and "immutable ~this()" to
+ * fix properly.
+ */
+ e.type = e.type.mutableOf();
+
+ // Enable calling destructors on shared objects.
+ // The destructor is always a single, non-overloaded function,
+ // and must serve both shared and non-shared objects.
+ e.type = e.type.unSharedOf;
+
+ e = new DotVarExp(loc, e, sd.dtor, false);
+ e = new CallExp(loc, e);
+ }
+ else
+ {
+ // __ArrayDtor(v[0 .. n])
+ e = new VarExp(loc, this);
+
+ const sdsz = sd.type.size();
+ assert(sdsz != SIZE_INVALID && sdsz != 0);
+ const n = sz / sdsz;
+ e = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, n, Type.tsize_t));
+
+ // Prevent redundant bounds check
+ (cast(SliceExp)e).upperIsInBounds = true;
+ (cast(SliceExp)e).lowerIsLessThanUpper = true;
+
+ // This is a hack so we can call destructors on const/immutable objects.
+ e.type = sd.type.arrayOf();
+
+ e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), e);
+ }
+ return e;
+ }
+ // Destructors for classes
+ if (storage_class & (STC.auto_ | STC.scope_) && !(storage_class & STC.parameter))
+ {
+ for (ClassDeclaration cd = type.isClassHandle(); cd; cd = cd.baseClass)
+ {
+ /* We can do better if there's a way with onstack
+ * classes to determine if there's no way the monitor
+ * could be set.
+ */
+ //if (cd.isInterfaceDeclaration())
+ // error("interface `%s` cannot be scope", cd.toChars());
+
+ if (mynew || onstack) // if any destructors
+ {
+ // delete'ing C++ classes crashes (and delete is deprecated anyway)
+ if (cd.classKind == ClassKind.cpp)
+ {
+ // Don't call non-existant dtor
+ if (!cd.dtor)
+ break;
+
+ e = new VarExp(loc, this);
+ e.type = e.type.mutableOf().unSharedOf(); // Hack for mutable ctor on immutable instances
+ e = new DotVarExp(loc, e, cd.dtor, false);
+ e = new CallExp(loc, e);
+ break;
+ }
+
+ // delete this;
+ Expression ec;
+ ec = new VarExp(loc, this);
+ e = new DeleteExp(loc, ec, true);
+ e.type = Type.tvoid;
+ break;
+ }
+ }
+ }
+ return e;
+ }
+
+ /*******************************************
+ * If variable has a constant expression initializer, get it.
+ * Otherwise, return null.
+ */
+ extern (D) final Expression getConstInitializer(bool needFullType = true)
+ {
+ assert(type && _init);
+
+ // Ungag errors when not speculative
+ uint oldgag = global.gag;
+ if (global.gag)
+ {
+ Dsymbol sym = toParent().isAggregateDeclaration();
+ if (sym && !sym.isSpeculative())
+ global.gag = 0;
+ }
+
+ if (_scope)
+ {
+ inuse++;
+ _init = _init.initializerSemantic(_scope, type, INITinterpret);
+ _scope = null;
+ inuse--;
+ }
+
+ Expression e = _init.initializerToExpression(needFullType ? type : null);
+ global.gag = oldgag;
+ return e;
+ }
+
+ /*******************************************
+ * Helper function for the expansion of manifest constant.
+ */
+ extern (D) final Expression expandInitializer(Loc loc)
+ {
+ assert((storage_class & STC.manifest) && _init);
+
+ auto e = getConstInitializer();
+ if (!e)
+ {
+ .error(loc, "cannot make expression out of initializer for `%s`", toChars());
+ return ErrorExp.get();
+ }
+
+ e = e.copy();
+ e.loc = loc; // for better error message
+ return e;
+ }
+
+ override final void checkCtorConstInit()
+ {
+ version (none)
+ {
+ /* doesn't work if more than one static ctor */
+ if (ctorinit == 0 && isCtorinit() && !isField())
+ error("missing initializer in static constructor for const variable");
+ }
+ }
+
+ /************************************
+ * Check to see if this variable is actually in an enclosing function
+ * rather than the current one.
+ * Update nestedrefs[], closureVars[] and outerVars[].
+ * Returns: true if error occurs.
+ */
+ extern (D) final bool checkNestedReference(Scope* sc, Loc loc)
+ {
+ //printf("VarDeclaration::checkNestedReference() %s\n", toChars());
+ if (sc.intypeof == 1 || (sc.flags & SCOPE.ctfe))
+ return false;
+ if (!parent || parent == sc.parent)
+ return false;
+ if (isDataseg() || (storage_class & STC.manifest))
+ return false;
+
+ // The current function
+ FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
+ if (!fdthis)
+ return false; // out of function scope
+
+ Dsymbol p = toParent2();
+
+ // Function literals from fdthis to p must be delegates
+ ensureStaticLinkTo(fdthis, p);
+
+ // The function that this variable is in
+ FuncDeclaration fdv = p.isFuncDeclaration();
+ if (!fdv || fdv == fdthis)
+ return false;
+
+ // Add fdthis to nestedrefs[] if not already there
+ if (!nestedrefs.contains(fdthis))
+ nestedrefs.push(fdthis);
+
+ //printf("\tfdv = %s\n", fdv.toChars());
+ //printf("\tfdthis = %s\n", fdthis.toChars());
+ if (loc.isValid())
+ {
+ if (fdthis.getLevelAndCheck(loc, sc, fdv, this) == fdthis.LevelError)
+ return true;
+ }
+
+ // Add this VarDeclaration to fdv.closureVars[] if not already there
+ if (!sc.intypeof && !(sc.flags & SCOPE.compile) &&
+ // https://issues.dlang.org/show_bug.cgi?id=17605
+ (fdv.flags & FUNCFLAG.compileTimeOnly || !(fdthis.flags & FUNCFLAG.compileTimeOnly))
+ )
+ {
+ if (!fdv.closureVars.contains(this))
+ fdv.closureVars.push(this);
+ }
+
+ if (!fdthis.outerVars.contains(this))
+ fdthis.outerVars.push(this);
+
+ //printf("fdthis is %s\n", fdthis.toChars());
+ //printf("var %s in function %s is nested ref\n", toChars(), fdv.toChars());
+ // __dollar creates problems because it isn't a real variable
+ // https://issues.dlang.org/show_bug.cgi?id=3326
+ if (ident == Id.dollar)
+ {
+ .error(loc, "cannnot use `$` inside a function literal");
+ return true;
+ }
+ if (ident == Id.withSym) // https://issues.dlang.org/show_bug.cgi?id=1759
+ {
+ ExpInitializer ez = _init.isExpInitializer();
+ assert(ez);
+ Expression e = ez.exp;
+ if (e.op == TOK.construct || e.op == TOK.blit)
+ e = (cast(AssignExp)e).e2;
+ return lambdaCheckForNestedRef(e, sc);
+ }
+
+ return false;
+ }
+
+ override final Dsymbol toAlias()
+ {
+ //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym);
+ if ((!type || !type.deco) && _scope)
+ dsymbolSemantic(this, _scope);
+
+ assert(this != aliassym);
+ Dsymbol s = aliassym ? aliassym.toAlias() : this;
+ return s;
+ }
+
+ // Eliminate need for dynamic_cast
+ override final inout(VarDeclaration) isVarDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ /**********************************
+ * Determine if `this` has a lifetime that lasts past
+ * the destruction of `v`
+ * Params:
+ * v = variable to test against
+ * Returns:
+ * true if it does
+ */
+ final bool enclosesLifetimeOf(VarDeclaration v) const pure
+ {
+ // VarDeclaration's with these STC's need special treatment
+ enum special = STC.temp | STC.foreach_;
+
+ // Sequence numbers work when there are no special VarDeclaration's involved
+ if (!((this.storage_class | v.storage_class) & special))
+ {
+ // FIXME: VarDeclaration's for parameters are created in semantic3, so
+ // they will have a greater sequence number than local variables.
+ // Hence reverse the result for mixed comparisons.
+ const exp = this.isParameter() == v.isParameter();
+
+ return (this.sequenceNumber < v.sequenceNumber) == exp;
+ }
+
+ // Assume that semantic produces temporaries according to their lifetime
+ // (It won't create a temporary before the actual content)
+ if ((this.storage_class & special) && (v.storage_class & special))
+ return this.sequenceNumber < v.sequenceNumber;
+
+ // Fall back to lexical order
+ assert(this.loc != Loc.initial);
+ assert(v.loc != Loc.initial);
+
+ if (auto ld = this.loc.linnum - v.loc.linnum)
+ return ld < 0;
+
+ if (auto cd = this.loc.charnum - v.loc.charnum)
+ return cd < 0;
+
+ // Default fallback
+ return this.sequenceNumber < v.sequenceNumber;
+ }
+
+ /***************************************
+ * Add variable to maybes[].
+ * When a maybescope variable `v` is assigned to a maybescope variable `this`,
+ * we cannot determine if `this` is actually scope until the semantic
+ * analysis for the function is completed. Thus, we save the data
+ * until then.
+ * Params:
+ * v = an STC.maybescope variable that was assigned to `this`
+ */
+ final void addMaybe(VarDeclaration v)
+ {
+ //printf("add %s to %s's list of dependencies\n", v.toChars(), toChars());
+ if (!maybes)
+ maybes = new VarDeclarations();
+ maybes.push(v);
+ }
+}
+
+/*******************************************************
+ * C11 6.7.2.1-4 bit fields
+ */
+extern (C++) class BitFieldDeclaration : VarDeclaration
+{
+ Expression width;
+
+ uint fieldWidth;
+ uint bitOffset;
+
+ final extern (D) this(const ref Loc loc, Type type, Identifier ident, Expression width)
+ {
+ super(loc, type, ident, null);
+
+ this.width = width;
+ this.storage_class |= STC.field;
+ }
+
+ override BitFieldDeclaration syntaxCopy(Dsymbol s)
+ {
+ //printf("BitFieldDeclaration::syntaxCopy(%s)\n", toChars());
+ assert(!s);
+ auto bf = new BitFieldDeclaration(loc, type ? type.syntaxCopy() : null, ident, width.syntaxCopy());
+ bf.comment = comment;
+ return bf;
+ }
+
+ override final inout(BitFieldDeclaration) isBitFieldDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
+ {
+ //printf("BitFieldDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
+
+ Type t = type.toBasetype();
+
+ // List in ad.fields. Even if the type is error, it's necessary to avoid
+ // pointless error diagnostic "more initializers than fields" on struct literal.
+ if (!isAnonymous())
+ ad.fields.push(this);
+
+ if (t.ty == Terror)
+ return;
+
+ const sz = t.size(loc);
+ assert(sz != SIZE_INVALID && sz < uint.max);
+ uint memsize = cast(uint)sz; // size of member
+ uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
+
+ if (fieldWidth == 0 && !isAnonymous())
+ error(loc, "named bit fields cannot have 0 width");
+ if (fieldWidth > memsize * 8)
+ error(loc, "bit field width %d is larger than type", fieldWidth);
+
+ void startNewField()
+ {
+ offset = AggregateDeclaration.placeField(
+ &fieldState.offset,
+ memsize, memalignsize, alignment,
+ &ad.structsize, &ad.alignsize,
+ isunion);
+
+ fieldState.inFlight = true;
+ fieldState.fieldOffset = offset;
+ fieldState.bitOffset = 0;
+ fieldState.fieldSize = memsize;
+ }
+
+ if (!fieldState.inFlight || fieldWidth == 0)
+ {
+ startNewField();
+ }
+
+ if (0 && target.os & Target.OS.Posix)
+ {
+ if ((fieldState.offset%4 * 8) + fieldState.bitOffset + fieldWidth > int.sizeof * 8)
+ {
+ startNewField();
+ }
+ }
+ else if (1 || target.os == Target.OS.Windows)
+ {
+ if (memsize != fieldState.fieldSize ||
+ fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8)
+ {
+ startNewField();
+ }
+ }
+
+ offset = fieldState.fieldOffset;
+ bitOffset = fieldState.bitOffset;
+ if (0 && target.os & Target.OS.Posix)
+ {
+ while (bitOffset > memsize * 8)
+ {
+ bitOffset -= 8;
+ offset += 1;
+ }
+ }
+
+ //fieldState.fieldSize = memsize;
+ if (!isunion)
+ {
+ fieldState.bitOffset += fieldWidth;
+ }
+
+ //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
+ //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
+ }
+}
+
+/***********************************************************
+ * This is a shell around a back end symbol
+ */
+extern (C++) final class SymbolDeclaration : Declaration
+{
+ StructDeclaration dsym;
+
+ extern (D) this(const ref Loc loc, StructDeclaration dsym)
+ {
+ super(loc, dsym.ident);
+ this.dsym = dsym;
+ storage_class |= STC.const_;
+ }
+
+ // Eliminate need for dynamic_cast
+ override inout(SymbolDeclaration) isSymbolDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) class TypeInfoDeclaration : VarDeclaration
+{
+ Type tinfo;
+
+ final extern (D) this(Type tinfo)
+ {
+ super(Loc.initial, Type.dtypeinfo.type, tinfo.getTypeInfoIdent(), null);
+ this.tinfo = tinfo;
+ storage_class = STC.static_ | STC.gshared;
+ visibility = Visibility(Visibility.Kind.public_);
+ linkage = LINK.c;
+ alignment = target.ptrsize;
+ }
+
+ static TypeInfoDeclaration create(Type tinfo)
+ {
+ return new TypeInfoDeclaration(tinfo);
+ }
+
+ override final TypeInfoDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(0); // should never be produced by syntax
+ }
+
+ override final const(char)* toChars() const
+ {
+ //printf("TypeInfoDeclaration::toChars() tinfo = %s\n", tinfo.toChars());
+ OutBuffer buf;
+ buf.writestring("typeid(");
+ buf.writestring(tinfo.toChars());
+ buf.writeByte(')');
+ return buf.extractChars();
+ }
+
+ override final inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout @nogc nothrow pure @safe
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoStructDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfostruct)
+ {
+ ObjectNotFound(Id.TypeInfo_Struct);
+ }
+ type = Type.typeinfostruct.type;
+ }
+
+ static TypeInfoStructDeclaration create(Type tinfo)
+ {
+ return new TypeInfoStructDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoClassDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfoclass)
+ {
+ ObjectNotFound(Id.TypeInfo_Class);
+ }
+ type = Type.typeinfoclass.type;
+ }
+
+ static TypeInfoClassDeclaration create(Type tinfo)
+ {
+ return new TypeInfoClassDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoInterfaceDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfointerface)
+ {
+ ObjectNotFound(Id.TypeInfo_Interface);
+ }
+ type = Type.typeinfointerface.type;
+ }
+
+ static TypeInfoInterfaceDeclaration create(Type tinfo)
+ {
+ return new TypeInfoInterfaceDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoPointerDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfopointer)
+ {
+ ObjectNotFound(Id.TypeInfo_Pointer);
+ }
+ type = Type.typeinfopointer.type;
+ }
+
+ static TypeInfoPointerDeclaration create(Type tinfo)
+ {
+ return new TypeInfoPointerDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoArrayDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfoarray)
+ {
+ ObjectNotFound(Id.TypeInfo_Array);
+ }
+ type = Type.typeinfoarray.type;
+ }
+
+ static TypeInfoArrayDeclaration create(Type tinfo)
+ {
+ return new TypeInfoArrayDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoStaticArrayDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfostaticarray)
+ {
+ ObjectNotFound(Id.TypeInfo_StaticArray);
+ }
+ type = Type.typeinfostaticarray.type;
+ }
+
+ static TypeInfoStaticArrayDeclaration create(Type tinfo)
+ {
+ return new TypeInfoStaticArrayDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfoassociativearray)
+ {
+ ObjectNotFound(Id.TypeInfo_AssociativeArray);
+ }
+ type = Type.typeinfoassociativearray.type;
+ }
+
+ static TypeInfoAssociativeArrayDeclaration create(Type tinfo)
+ {
+ return new TypeInfoAssociativeArrayDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoEnumDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfoenum)
+ {
+ ObjectNotFound(Id.TypeInfo_Enum);
+ }
+ type = Type.typeinfoenum.type;
+ }
+
+ static TypeInfoEnumDeclaration create(Type tinfo)
+ {
+ return new TypeInfoEnumDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoFunctionDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfofunction)
+ {
+ ObjectNotFound(Id.TypeInfo_Function);
+ }
+ type = Type.typeinfofunction.type;
+ }
+
+ static TypeInfoFunctionDeclaration create(Type tinfo)
+ {
+ return new TypeInfoFunctionDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoDelegateDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfodelegate)
+ {
+ ObjectNotFound(Id.TypeInfo_Delegate);
+ }
+ type = Type.typeinfodelegate.type;
+ }
+
+ static TypeInfoDelegateDeclaration create(Type tinfo)
+ {
+ return new TypeInfoDelegateDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoTupleDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfotypelist)
+ {
+ ObjectNotFound(Id.TypeInfo_Tuple);
+ }
+ type = Type.typeinfotypelist.type;
+ }
+
+ static TypeInfoTupleDeclaration create(Type tinfo)
+ {
+ return new TypeInfoTupleDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoConstDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfoconst)
+ {
+ ObjectNotFound(Id.TypeInfo_Const);
+ }
+ type = Type.typeinfoconst.type;
+ }
+
+ static TypeInfoConstDeclaration create(Type tinfo)
+ {
+ return new TypeInfoConstDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoInvariantDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfoinvariant)
+ {
+ ObjectNotFound(Id.TypeInfo_Invariant);
+ }
+ type = Type.typeinfoinvariant.type;
+ }
+
+ static TypeInfoInvariantDeclaration create(Type tinfo)
+ {
+ return new TypeInfoInvariantDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoSharedDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfoshared)
+ {
+ ObjectNotFound(Id.TypeInfo_Shared);
+ }
+ type = Type.typeinfoshared.type;
+ }
+
+ static TypeInfoSharedDeclaration create(Type tinfo)
+ {
+ return new TypeInfoSharedDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoWildDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfowild)
+ {
+ ObjectNotFound(Id.TypeInfo_Wild);
+ }
+ type = Type.typeinfowild.type;
+ }
+
+ static TypeInfoWildDeclaration create(Type tinfo)
+ {
+ return new TypeInfoWildDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeInfoVectorDeclaration : TypeInfoDeclaration
+{
+ extern (D) this(Type tinfo)
+ {
+ super(tinfo);
+ if (!Type.typeinfovector)
+ {
+ ObjectNotFound(Id.TypeInfo_Vector);
+ }
+ type = Type.typeinfovector.type;
+ }
+
+ static TypeInfoVectorDeclaration create(Type tinfo)
+ {
+ return new TypeInfoVectorDeclaration(tinfo);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * For the "this" parameter to member functions
+ */
+extern (C++) final class ThisDeclaration : VarDeclaration
+{
+ extern (D) this(const ref Loc loc, Type t)
+ {
+ super(loc, t, Id.This, null);
+ storage_class |= STC.nodtor;
+ }
+
+ override ThisDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(0); // should never be produced by syntax
+ }
+
+ override inout(ThisDeclaration) isThisDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 55c8142..1c56def 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -13,115 +13,98 @@
#include "dsymbol.h"
#include "mtype.h"
#include "objc.h"
+#include "tokens.h"
class Expression;
class Statement;
class LabelDsymbol;
class Initializer;
-class Module;
class ForeachStatement;
struct Ensure
{
Identifier *id;
Statement *ensure;
-
- Ensure();
- Ensure(Identifier *id, Statement *ensure);
- Ensure syntaxCopy();
- static Ensures *arraySyntaxCopy(Ensures *a);
};
-class AliasDeclaration;
class FuncDeclaration;
-class ExpInitializer;
class StructDeclaration;
-struct InterState;
-struct CompiledCtfeFunction;
-struct ObjcSelector;
struct IntRange;
-enum LINK;
-enum TOK;
-enum MATCH;
-enum PURE;
-enum PINLINE;
-
-#define STCundefined 0LL
-#define STCstatic 1LL
-#define STCextern 2LL
-#define STCconst 4LL
-#define STCfinal 8LL
-#define STCabstract 0x10LL
-#define STCparameter 0x20LL
-#define STCfield 0x40LL
-#define STCoverride 0x80LL
-#define STCauto 0x100LL
-#define STCsynchronized 0x200LL
-#define STCdeprecated 0x400LL
-#define STCin 0x800LL // in parameter
-#define STCout 0x1000LL // out parameter
-#define STClazy 0x2000LL // lazy parameter
-#define STCforeach 0x4000LL // variable for foreach loop
-#define STCvariadic 0x10000LL // the 'variadic' parameter in: T foo(T a, U b, V variadic...)
-#define STCctorinit 0x20000LL // can only be set inside constructor
-#define STCtemplateparameter 0x40000LL // template parameter
-#define STCscope 0x80000LL
-#define STCimmutable 0x100000LL
-#define STCref 0x200000LL
-#define STCinit 0x400000LL // has explicit initializer
-#define STCmanifest 0x800000LL // manifest constant
-#define STCnodtor 0x1000000LL // don't run destructor
-#define STCnothrow 0x2000000LL // never throws exceptions
-#define STCpure 0x4000000LL // pure function
-#define STCtls 0x8000000LL // thread local
-#define STCalias 0x10000000LL // alias parameter
-#define STCshared 0x20000000LL // accessible from multiple threads
-// accessible from multiple threads
-// but not typed as "shared"
-#define STCgshared 0x40000000LL
-#define STCwild 0x80000000LL // for "wild" type constructor
+//enum STC : ulong from astenums.d:
+
+ #define STCundefined 0ULL
+
+ #define STCstatic 1ULL /// `static`
+ #define STCextern 2ULL /// `extern`
+ #define STCconst 4ULL /// `const`
+ #define STCfinal 8ULL /// `final`
+
+ #define STCabstract 0x10ULL /// `abstract`
+ #define STCparameter 0x20ULL /// is function parameter
+ #define STCfield 0x40ULL /// is field of struct, union or class
+ #define STCoverride 0x80ULL /// `override`
+
+ #define STCauto 0x100ULL /// `auto`
+ #define STCsynchronized 0x200ULL /// `synchronized`
+ #define STCdeprecated 0x400ULL /// `deprecated`
+ #define STCin 0x800ULL /// `in` parameter
+
+ #define STCout 0x1000ULL /// `out` parameter
+ #define STClazy 0x2000ULL /// `lazy` parameter
+ #define STCforeach 0x4000ULL /// variable for foreach loop
+ #define STCvariadic 0x8000ULL /// the `variadic` parameter in: T foo(T a, U b, V variadic...)
+
+ #define STCctorinit 0x10000ULL /// can only be set inside constructor
+ #define STCtemplateparameter 0x20000ULL /// template parameter
+ #define STCref 0x40000ULL /// `ref`
+ #define STCscope 0x80000ULL /// `scope`
+
+ #define STCmaybescope 0x100000ULL /// parameter might be `scope`
+ #define STCscopeinferred 0x200000ULL /// `scope` has been inferred and should not be part of mangling, `scope` must also be set
+ #define STCreturn 0x400000ULL /// 'return ref' or 'return scope' for function parameters
+ #define STCreturnScope 0x800000ULL /// if `ref return scope` then resolve to `ref` and `return scope`
+
+ #define STCreturninferred 0x1000000ULL /// `return` has been inferred and should not be part of mangling, `return` must also be set
+ #define STCimmutable 0x2000000ULL /// `immutable`
+ #define STCinit 0x4000000ULL /// has explicit initializer
+ #define STCmanifest 0x8000000ULL /// manifest constant
+
+ #define STCnodtor 0x10000000ULL /// do not run destructor
+ #define STCnothrow 0x20000000ULL /// `nothrow` meaning never throws exceptions
+ #define STCpure 0x40000000ULL /// `pure` function
+ #define STCtls 0x80000000ULL /// thread local
+
+ #define STCalias 0x100000000ULL /// `alias` parameter
+ #define STCshared 0x200000000ULL /// accessible from multiple threads
+ #define STCgshared 0x400000000ULL /// accessible from multiple threads, but not typed as `shared`
+ #define STCwild 0x800000000ULL /// for wild type constructor
+
+ #define STCproperty 0x1000000000ULL /// `@property`
+ #define STCsafe 0x2000000000ULL /// `@safe`
+ #define STCtrusted 0x4000000000ULL /// `@trusted`
+ #define STCsystem 0x8000000000ULL /// `@system`
+
+ #define STCctfe 0x10000000000ULL /// can be used in CTFE, even if it is static
+ #define STCdisable 0x20000000000ULL /// for functions that are not callable
+ #define STCresult 0x40000000000ULL /// for result variables passed to out contracts
+ #define STCnodefaultctor 0x80000000000ULL /// must be set inside constructor
+
+ #define STCtemp 0x100000000000ULL /// temporary variable
+ #define STCrvalue 0x200000000000ULL /// force rvalue for variables
+ #define STCnogc 0x400000000000ULL /// `@nogc`
+ #define STCautoref 0x800000000000ULL /// Mark for the already deduced `auto ref` parameter
+
+ #define STCinference 0x1000000000000ULL /// do attribute inference
+ #define STCexptemp 0x2000000000000ULL /// temporary variable that has lifetime restricted to an expression
+ #define STCfuture 0x4000000000000ULL /// introducing new base class function
+ #define STClocal 0x8000000000000ULL /// do not forward (see dmd.dsymbol.ForwardingScopeDsymbol).
+
+ #define STClive 0x10000000000000ULL /// function `@live` attribute
+ #define STCregister 0x20000000000000ULL /// `register` storage class (ImportC)
+ #define STCvolatile 0x40000000000000ULL /// destined for volatile in the back end
+
#define STC_TYPECTOR (STCconst | STCimmutable | STCshared | STCwild)
#define STC_FUNCATTR (STCref | STCnothrow | STCnogc | STCpure | STCproperty | STCsafe | STCtrusted | STCsystem)
-#define STCproperty 0x100000000LL
-#define STCsafe 0x200000000LL
-#define STCtrusted 0x400000000LL
-#define STCsystem 0x800000000LL
-#define STCctfe 0x1000000000LL // can be used in CTFE, even if it is static
-#define STCdisable 0x2000000000LL // for functions that are not callable
-#define STCresult 0x4000000000LL // for result variables passed to out contracts
-#define STCnodefaultctor 0x8000000000LL // must be set inside constructor
-#define STCtemp 0x10000000000LL // temporary variable
-#define STCrvalue 0x20000000000LL // force rvalue for variables
-#define STCnogc 0x40000000000LL // @nogc
-#define STCvolatile 0x80000000000LL // destined for volatile in the back end
-#define STCreturn 0x100000000000LL // 'return ref' or 'return scope' for function parameters
-#define STCautoref 0x200000000000LL // Mark for the already deduced 'auto ref' parameter
-#define STCinference 0x400000000000LL // do attribute inference
-#define STCexptemp 0x800000000000LL // temporary variable that has lifetime restricted to an expression
-#define STCmaybescope 0x1000000000000LL // parameter might be 'scope'
-#define STCscopeinferred 0x2000000000000LL // 'scope' has been inferred and should not be part of mangling
-#define STCfuture 0x4000000000000LL // introducing new base class function
-#define STClocal 0x8000000000000LL // do not forward (see ddmd.dsymbol.ForwardingScopeDsymbol).
-
-const StorageClass STCStorageClass = (STCauto | STCscope | STCstatic | STCextern | STCconst | STCfinal |
- STCabstract | STCsynchronized | STCdeprecated | STCfuture | STCoverride | STClazy | STCalias |
- STCout | STCin |
- STCmanifest | STCimmutable | STCshared | STCwild | STCnothrow | STCnogc | STCpure | STCref | STCtls |
- STCgshared | STCproperty | STCsafe | STCtrusted | STCsystem | STCdisable | STClocal);
-
-struct Match
-{
- int count; // number of matches found
- MATCH last; // match level of lastf
- FuncDeclaration *lastf; // last matching function we found
- FuncDeclaration *nextf; // current matching function
- FuncDeclaration *anyf; // pick a func, any func, to use for error recovery
-};
-
-void functionResolve(Match *m, Dsymbol *fd, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs, const char **pMessage = NULL);
-int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *));
-void aliasSemantic(AliasDeclaration *ds, Scope *sc);
-
void ObjectNotFound(Identifier *id);
/**************************************************************/
@@ -132,47 +115,45 @@ public:
Type *type;
Type *originalType; // before semantic analysis
StorageClass storage_class;
- Prot protection;
+ Visibility visibility;
LINK linkage;
- int inuse; // used to detect cycles
+ short inuse; // used to detect cycles
+ uint8_t adFlags;
DString mangleOverride; // overridden symbol with pragma(mangle, "...")
- Declaration(Identifier *id);
const char *kind() const;
- d_uns64 size(Loc loc);
- bool checkDisabled(Loc loc, Scope *sc, bool isAliasedDeclaration = false);
- int checkModify(Loc loc, Scope *sc, Type *t, Expression *e1, int flag);
+ d_uns64 size(const Loc &loc);
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
- bool isStatic() { return (storage_class & STCstatic) != 0; }
+ bool isStatic() const { return (storage_class & STCstatic) != 0; }
virtual bool isDelete();
virtual bool isDataseg();
virtual bool isThreadlocal();
virtual bool isCodeseg() const;
- bool isCtorinit() { return (storage_class & STCctorinit) != 0; }
- bool isFinal() { return (storage_class & STCfinal) != 0; }
- bool isAbstract() { return (storage_class & STCabstract) != 0; }
- bool isConst() { return (storage_class & STCconst) != 0; }
- bool isImmutable() { return (storage_class & STCimmutable) != 0; }
- bool isWild() { return (storage_class & STCwild) != 0; }
- bool isAuto() { return (storage_class & STCauto) != 0; }
- bool isScope() { return (storage_class & STCscope) != 0; }
- bool isSynchronized() { return (storage_class & STCsynchronized) != 0; }
- bool isParameter() { return (storage_class & STCparameter) != 0; }
- bool isDeprecated() { return (storage_class & STCdeprecated) != 0; }
- bool isDisabled() { return (storage_class & STCdisable) != 0; }
- bool isOverride() { return (storage_class & STCoverride) != 0; }
- bool isResult() { return (storage_class & STCresult) != 0; }
- bool isField() { return (storage_class & STCfield) != 0; }
-
- bool isIn() { return (storage_class & STCin) != 0; }
- bool isOut() { return (storage_class & STCout) != 0; }
- bool isRef() { return (storage_class & STCref) != 0; }
-
- bool isFuture() { return (storage_class & STCfuture) != 0; }
-
- Prot prot();
+ bool isCtorinit() const { return (storage_class & STCctorinit) != 0; }
+ bool isFinal() const { return (storage_class & STCfinal) != 0; }
+ virtual bool isAbstract() { return (storage_class & STCabstract) != 0; }
+ bool isConst() const { return (storage_class & STCconst) != 0; }
+ bool isImmutable() const { return (storage_class & STCimmutable) != 0; }
+ bool isWild() const { return (storage_class & STCwild) != 0; }
+ bool isAuto() const { return (storage_class & STCauto) != 0; }
+ bool isScope() const { return (storage_class & STCscope) != 0; }
+ bool isSynchronized() const { return (storage_class & STCsynchronized) != 0; }
+ bool isParameter() const { return (storage_class & STCparameter) != 0; }
+ bool isDeprecated() const { return (storage_class & STCdeprecated) != 0; }
+ bool isOverride() const { return (storage_class & STCoverride) != 0; }
+ bool isResult() const { return (storage_class & STCresult) != 0; }
+ bool isField() const { return (storage_class & STCfield) != 0; }
+
+ bool isIn() const { return (storage_class & STCin) != 0; }
+ bool isOut() const { return (storage_class & STCout) != 0; }
+ bool isRef() const { return (storage_class & STCref) != 0; }
+ bool isReference() const { return (storage_class & (STCref | STCout)) != 0; }
+
+ bool isFuture() const { return (storage_class & STCfuture) != 0; }
+
+ Visibility visible();
Declaration *isDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
@@ -188,8 +169,7 @@ public:
TypeTuple *tupletype; // !=NULL if this is a type tuple
- TupleDeclaration(Loc loc, Identifier *ident, Objects *objects);
- Dsymbol *syntaxCopy(Dsymbol *);
+ TupleDeclaration *syntaxCopy(Dsymbol *);
const char *kind() const;
Type *getType();
Dsymbol *toAlias2();
@@ -208,16 +188,14 @@ public:
Dsymbol *overnext; // next in overload list
Dsymbol *_import; // !=NULL if unresolved internal alias for selective import
- AliasDeclaration(Loc loc, Identifier *ident, Type *type);
- AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s);
static AliasDeclaration *create(Loc loc, Identifier *id, Type *type);
- Dsymbol *syntaxCopy(Dsymbol *);
+ AliasDeclaration *syntaxCopy(Dsymbol *);
bool overloadInsert(Dsymbol *s);
const char *kind() const;
Type *getType();
Dsymbol *toAlias();
Dsymbol *toAlias2();
- bool isOverloadable();
+ bool isOverloadable() const;
AliasDeclaration *isAliasDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
@@ -230,16 +208,14 @@ class OverDeclaration : public Declaration
public:
Dsymbol *overnext; // next in overload list
Dsymbol *aliassym;
- bool hasOverloads;
- OverDeclaration(Identifier *ident, Dsymbol *s, bool hasOverloads = true);
const char *kind() const;
- bool equals(RootObject *o);
+ bool equals(const RootObject *o) const;
bool overloadInsert(Dsymbol *s);
Dsymbol *toAlias();
Dsymbol *isUnique();
- bool isOverloadable();
+ bool isOverloadable() const;
OverDeclaration *isOverDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
@@ -251,33 +227,40 @@ class VarDeclaration : public Declaration
{
public:
Initializer *_init;
+ FuncDeclarations nestedrefs; // referenced by these lexically nested functions
+ Dsymbol *aliassym; // if redone as alias to another symbol
+ VarDeclaration *lastVar; // Linked list of variables for goto-skips-init detection
+ Expression *edtor; // if !=NULL, does the destruction of the variable
+ IntRange *range; // if !NULL, the variable is known to be within the range
+ VarDeclarations *maybes; // STCmaybescope variables that are assigned to this STCmaybescope variable
+
+ unsigned endlinnum; // line number of end of scope that this var lives in
unsigned offset;
unsigned sequenceNumber; // order the variables are declared
- FuncDeclarations nestedrefs; // referenced by these lexically nested functions
- bool isargptr; // if parameter that _argptr points to
structalign_t alignment;
+
+ // When interpreting, these point to the value (NULL if value not determinable)
+ // The index of this variable on the CTFE stack, ~0u if not allocated
+ unsigned ctfeAdrOnStack;
+
+ bool isargptr; // if parameter that _argptr points to
bool ctorinit; // it has been initialized in a ctor
+ bool iscatchvar; // this is the exception object variable in catch() clause
+ bool isowner; // this is an Owner, despite it being `scope`
bool onstack; // it is a class that was allocated on the stack
bool mynew; // it is a class new'd with custom operator new
- int canassign; // it can be assigned to
+ char canassign; // it can be assigned to
bool overlapped; // if it is a field and has overlapping
bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe
bool doNotInferScope; // do not infer 'scope' for this variable
+ bool doNotInferReturn; // do not infer 'return' for this variable
unsigned char isdataseg; // private data for isDataseg
- Dsymbol *aliassym; // if redone as alias to another symbol
- VarDeclaration *lastVar; // Linked list of variables for goto-skips-init detection
- unsigned endlinnum; // line number of end of scope that this var lives in
-
- // When interpreting, these point to the value (NULL if value not determinable)
- // The index of this variable on the CTFE stack, -1 if not allocated
- int ctfeAdrOnStack;
- Expression *edtor; // if !=NULL, does the destruction of the variable
- IntRange *range; // if !NULL, the variable is known to be within the range
+ bool isArgDtorVar; // temporary created to handle scope destruction of a function argument
- VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init);
- static VarDeclaration *create(Loc loc, Type *t, Identifier *id, Initializer *init);
- Dsymbol *syntaxCopy(Dsymbol *);
- void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+public:
+ static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
+ VarDeclaration *syntaxCopy(Dsymbol *);
+ void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
const char *kind() const;
AggregateDeclaration *isThis();
bool needThis();
@@ -291,11 +274,7 @@ public:
bool canTakeAddressOf();
bool needsScopeDtor();
bool enclosesLifetimeOf(VarDeclaration *v) const;
- Expression *callScopeDtor(Scope *sc);
- Expression *getConstInitializer(bool needFullType = true);
- Expression *expandInitializer(Loc loc);
void checkCtorConstInit();
- bool checkNestedReference(Scope *sc, Loc loc);
Dsymbol *toAlias();
// Eliminate need for dynamic_cast
VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; }
@@ -304,6 +283,21 @@ public:
/**************************************************************/
+class BitFieldDeclaration : public VarDeclaration
+{
+public:
+ Expression *width;
+
+ unsigned fieldWidth;
+ unsigned bitOffset;
+
+ BitFieldDeclaration *syntaxCopy(Dsymbol*);
+ BitFieldDeclaration *isBitFieldDeclaration() { return this; }
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+/**************************************************************/
+
// This is a shell around a back end symbol
class SymbolDeclaration : public Declaration
@@ -311,8 +305,6 @@ class SymbolDeclaration : public Declaration
public:
StructDeclaration *dsym;
- SymbolDeclaration(Loc loc, StructDeclaration *dsym);
-
// Eliminate need for dynamic_cast
SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; }
void accept(Visitor *v) { v->visit(this); }
@@ -323,10 +315,9 @@ class TypeInfoDeclaration : public VarDeclaration
public:
Type *tinfo;
- TypeInfoDeclaration(Type *tinfo);
static TypeInfoDeclaration *create(Type *tinfo);
- Dsymbol *syntaxCopy(Dsymbol *);
- const char *toChars();
+ TypeInfoDeclaration *syntaxCopy(Dsymbol *);
+ const char *toChars() const;
TypeInfoDeclaration *isTypeInfoDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
@@ -335,7 +326,6 @@ public:
class TypeInfoStructDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoStructDeclaration(Type *tinfo);
static TypeInfoStructDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -344,7 +334,6 @@ public:
class TypeInfoClassDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoClassDeclaration(Type *tinfo);
static TypeInfoClassDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -353,7 +342,6 @@ public:
class TypeInfoInterfaceDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoInterfaceDeclaration(Type *tinfo);
static TypeInfoInterfaceDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -362,7 +350,6 @@ public:
class TypeInfoPointerDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoPointerDeclaration(Type *tinfo);
static TypeInfoPointerDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -371,7 +358,6 @@ public:
class TypeInfoArrayDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoArrayDeclaration(Type *tinfo);
static TypeInfoArrayDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -380,7 +366,6 @@ public:
class TypeInfoStaticArrayDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoStaticArrayDeclaration(Type *tinfo);
static TypeInfoStaticArrayDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -389,7 +374,6 @@ public:
class TypeInfoAssociativeArrayDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoAssociativeArrayDeclaration(Type *tinfo);
static TypeInfoAssociativeArrayDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -398,7 +382,6 @@ public:
class TypeInfoEnumDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoEnumDeclaration(Type *tinfo);
static TypeInfoEnumDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -407,7 +390,6 @@ public:
class TypeInfoFunctionDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoFunctionDeclaration(Type *tinfo);
static TypeInfoFunctionDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -416,7 +398,6 @@ public:
class TypeInfoDelegateDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoDelegateDeclaration(Type *tinfo);
static TypeInfoDelegateDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -425,7 +406,6 @@ public:
class TypeInfoTupleDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoTupleDeclaration(Type *tinfo);
static TypeInfoTupleDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -434,7 +414,6 @@ public:
class TypeInfoConstDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoConstDeclaration(Type *tinfo);
static TypeInfoConstDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -443,7 +422,6 @@ public:
class TypeInfoInvariantDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoInvariantDeclaration(Type *tinfo);
static TypeInfoInvariantDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -452,7 +430,6 @@ public:
class TypeInfoSharedDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoSharedDeclaration(Type *tinfo);
static TypeInfoSharedDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -461,7 +438,6 @@ public:
class TypeInfoWildDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoWildDeclaration(Type *tinfo);
static TypeInfoWildDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -470,7 +446,6 @@ public:
class TypeInfoVectorDeclaration : public TypeInfoDeclaration
{
public:
- TypeInfoVectorDeclaration(Type *tinfo);
static TypeInfoVectorDeclaration *create(Type *tinfo);
void accept(Visitor *v) { v->visit(this); }
@@ -481,13 +456,12 @@ public:
class ThisDeclaration : public VarDeclaration
{
public:
- ThisDeclaration(Loc loc, Type *t);
- Dsymbol *syntaxCopy(Dsymbol *);
+ ThisDeclaration *syntaxCopy(Dsymbol *);
ThisDeclaration *isThisDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
-enum ILS
+enum class ILS : unsigned char
{
ILSuninitialized, // not computed yet
ILSno, // cannot inline
@@ -496,68 +470,53 @@ enum ILS
/**************************************************************/
-enum BUILTIN
-{
- BUILTINunknown = 255, /// not known if this is a builtin
- BUILTINunimp = 0, /// this is not a builtin
- BUILTINgcc, /// this is a GCC builtin
- BUILTINllvm, /// this is an LLVM builtin
- BUILTINsin,
- BUILTINcos,
- BUILTINtan,
- BUILTINsqrt,
- BUILTINfabs,
- BUILTINldexp,
- BUILTINlog,
- BUILTINlog2,
- BUILTINlog10,
- BUILTINexp,
- BUILTINexpm1,
- BUILTINexp2,
- BUILTINround,
- BUILTINfloor,
- BUILTINceil,
- BUILTINtrunc,
- BUILTINcopysign,
- BUILTINpow,
- BUILTINfmin,
- BUILTINfmax,
- BUILTINfma,
- BUILTINisnan,
- BUILTINisinfinity,
- BUILTINisfinite,
- BUILTINbsf,
- BUILTINbsr,
- BUILTINbswap,
- BUILTINpopcnt,
- BUILTINyl2x,
- BUILTINyl2xp1,
- BUILTINtoPrecFloat,
- BUILTINtoPrecDouble,
- BUILTINtoPrecReal
+enum class BUILTIN : unsigned char
+{
+ unknown = 255, /// not known if this is a builtin
+ unimp = 0, /// this is not a builtin
+ gcc, /// this is a GCC builtin
+ llvm, /// this is an LLVM builtin
+ sin,
+ cos,
+ tan,
+ sqrt,
+ fabs,
+ ldexp,
+ log,
+ log2,
+ log10,
+ exp,
+ expm1,
+ exp2,
+ round,
+ floor,
+ ceil,
+ trunc,
+ copysign,
+ pow,
+ fmin,
+ fmax,
+ fma,
+ isnan,
+ isinfinity,
+ isfinite,
+ bsf,
+ bsr,
+ bswap,
+ popcnt,
+ yl2x,
+ yl2xp1,
+ toPrecFloat,
+ toPrecDouble,
+ toPrecReal
};
Expression *eval_builtin(Loc loc, FuncDeclaration *fd, Expressions *arguments);
BUILTIN isBuiltin(FuncDeclaration *fd);
-typedef Expression *(*builtin_fp)(Loc loc, FuncDeclaration *fd, Expressions *arguments);
-void add_builtin(const char *mangle, builtin_fp fp);
-void builtin_init();
-
-#define FUNCFLAGpurityInprocess 1 // working on determining purity
-#define FUNCFLAGsafetyInprocess 2 // working on determining safety
-#define FUNCFLAGnothrowInprocess 4 // working on determining nothrow
-#define FUNCFLAGnogcInprocess 8 // working on determining @nogc
-#define FUNCFLAGreturnInprocess 0x10 // working on inferring 'return' for parameters
-#define FUNCFLAGinlineScanned 0x20 // function has been scanned for inline possibilities
-#define FUNCFLAGinferScope 0x40 // infer 'scope' for parameters
-#define FUNCFLAGprintf 0x200 // is a printf-like function
-#define FUNCFLAGscanf 0x400 // is a scanf-like function
-
class FuncDeclaration : public Declaration
{
public:
- Types *fthrows; // Array of Type's of exceptions (not used)
Statements *frequires; // in contracts
Ensures *fensures; // out contracts
Statement *frequire; // lowered in contract
@@ -568,6 +527,9 @@ public:
FuncDeclaration *fdrequire; // function that does the in contract
FuncDeclaration *fdensure; // function that does the out contract
+ Expressions *fdrequireParams; // argument list for __require
+ Expressions *fdensureParams; // argument list for __ensure
+
const char *mangleString; // mangled symbol created from mangleExact()
VarDeclaration *vresult; // result variable for out contracts
@@ -577,8 +539,9 @@ public:
// scopes from having the same name
DsymbolTable *localsymtab;
VarDeclaration *vthis; // 'this' parameter (member and nested)
+ bool isThis2; // has a dual-context 'this' parameter
VarDeclaration *v_arguments; // '_arguments' parameter
- ObjcSelector* selector; // Objective-C method selector (member function only)
+
VarDeclaration *v_argptr; // '_argptr' variable
VarDeclarations *parameters; // Array of VarDeclaration's for parameters
DsymbolTable *labtab; // statement label symbol table
@@ -589,13 +552,16 @@ public:
bool naked; // true if naked
bool generated; // true if function was generated by the compiler rather than
// supplied by the user
+ bool hasAlwaysInlines; // contains references to functions that must be inlined
+ unsigned char isCrtCtorDtor; // has attribute pragma(crt_constructor(1)/crt_destructor(2))
+ // not set before the glue layer
ILS inlineStatusStmt;
ILS inlineStatusExp;
PINLINE inlining;
- CompiledCtfeFunction *ctfeCode; // Compiled code for interpreter
int inlineNest; // !=0 if nested inline
- bool isArrayOp; // true if array operation
+ bool eh_none; /// true if no exception unwinding is needed
+
// true if errors in semantic3 this function's frame ptr
bool semantic3Errors;
ForeachStatement *fes; // if foreach body, this is the foreach
@@ -635,6 +601,12 @@ public:
// local variables in this function which are referenced by nested functions
VarDeclarations closureVars;
+
+ /** Outer variables which are referenced by this nested function
+ * (the inverse of closureVars)
+ */
+ VarDeclarations outerVars;
+
// Sibling nested functions which called this one
FuncDeclarations siblingCallers;
@@ -642,76 +614,62 @@ public:
unsigned flags; // FUNCFLAGxxxxx
- FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type);
- static FuncDeclaration *create(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type);
- Dsymbol *syntaxCopy(Dsymbol *);
+ // Data for a function declaration that is needed for the Objective-C
+ // integration.
+ ObjcFuncDeclaration objc;
+
+ static FuncDeclaration *create(const Loc &loc, const Loc &endloc, Identifier *id, StorageClass storage_class, Type *type, bool noreturn = false);
+ FuncDeclaration *syntaxCopy(Dsymbol *);
bool functionSemantic();
bool functionSemantic3();
- bool checkForwardRef(Loc loc);
- // called from semantic3
- VarDeclaration *declareThis(Scope *sc, AggregateDeclaration *ad);
- bool equals(RootObject *o);
+ bool equals(const RootObject *o) const;
int overrides(FuncDeclaration *fd);
- int findVtblIndex(Dsymbols *vtbl, int dim, bool fix17349 = true);
+ int findVtblIndex(Dsymbols *vtbl, int dim);
BaseClass *overrideInterface();
bool overloadInsert(Dsymbol *s);
- FuncDeclaration *overloadExactMatch(Type *t);
- FuncDeclaration *overloadModMatch(Loc loc, Type *tthis, bool &hasOverloads);
- TemplateDeclaration *findTemplateDeclRoot();
bool inUnittest();
MATCH leastAsSpecialized(FuncDeclaration *g);
- LabelDsymbol *searchLabel(Identifier *ident);
- int getLevel(Loc loc, Scope *sc, FuncDeclaration *fd); // lexical nesting level difference
+ LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc);
+ int getLevel(FuncDeclaration *fd, int intypeof); // lexical nesting level difference
+ int getLevelAndCheck(const Loc &loc, Scope *sc, FuncDeclaration *fd);
const char *toPrettyChars(bool QualifyTypes = false);
const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure'
- bool isMain();
- bool isCMain();
- bool isWinMain();
- bool isDllMain();
+ bool isMain() const;
+ bool isCMain() const;
+ bool isWinMain() const;
+ bool isDllMain() const;
bool isExport() const;
bool isImportedSymbol() const;
bool isCodeseg() const;
- bool isOverloadable();
+ bool isOverloadable() const;
+ bool isAbstract();
PURE isPure();
PURE isPureBypassingInference();
- bool setImpure();
bool isSafe();
bool isSafeBypassingInference();
bool isTrusted();
- bool setUnsafe();
bool isNogc();
bool isNogcBypassingInference();
- bool setGC();
- void printGCUsage(Loc loc, const char *warn);
- bool isolateReturn();
- bool parametersIntersect(Type *t);
- virtual bool isNested();
+ virtual bool isNested() const;
AggregateDeclaration *isThis();
bool needThis();
bool isVirtualMethod();
- virtual bool isVirtual();
- virtual bool isFinalFunc();
+ virtual bool isVirtual() const;
+ bool isFinalFunc() const;
virtual bool addPreInvariant();
virtual bool addPostInvariant();
const char *kind() const;
- FuncDeclaration *isUnique();
- bool checkNestedReference(Scope *sc, Loc loc);
+ bool isUnique();
bool needsClosure();
- bool checkClosure();
bool hasNestedFrameRefs();
- void buildResultVar(Scope *sc, Type *tret);
- Statement *mergeFrequire(Statement *);
- static bool needsFensure(FuncDeclaration *fd);
- void buildEnsureRequire();
- Statement *mergeFensure(Statement *, Identifier *oid);
ParameterList getParameterList();
static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0);
static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0);
- void checkDmain();
+
bool checkNRVO();
FuncDeclaration *isFuncDeclaration() { return this; }
@@ -720,20 +678,12 @@ public:
void accept(Visitor *v) { v->visit(this); }
};
-FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
- Objects *tiargs,
- Type *tthis,
- Expressions *arguments,
- int flags = 0);
-
class FuncAliasDeclaration : public FuncDeclaration
{
public:
FuncDeclaration *funcalias;
bool hasOverloads;
- FuncAliasDeclaration(Identifier *ident, FuncDeclaration *funcalias, bool hasOverloads = true);
-
FuncAliasDeclaration *isFuncAliasDeclaration() { return this; }
const char *kind() const;
@@ -750,12 +700,10 @@ public:
// backend
bool deferToObj;
- FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, TOK tok,
- ForeachStatement *fes, Identifier *id = NULL);
- Dsymbol *syntaxCopy(Dsymbol *);
- bool isNested();
+ FuncLiteralDeclaration *syntaxCopy(Dsymbol *);
+ bool isNested() const;
AggregateDeclaration *isThis();
- bool isVirtual();
+ bool isVirtual() const;
bool addPreInvariant();
bool addPostInvariant();
@@ -770,11 +718,11 @@ public:
class CtorDeclaration : public FuncDeclaration
{
public:
- CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type);
- Dsymbol *syntaxCopy(Dsymbol *);
+ bool isCpCtor;
+ CtorDeclaration *syntaxCopy(Dsymbol *);
const char *kind() const;
- const char *toChars();
- bool isVirtual();
+ const char *toChars() const;
+ bool isVirtual() const;
bool addPreInvariant();
bool addPostInvariant();
@@ -785,9 +733,8 @@ public:
class PostBlitDeclaration : public FuncDeclaration
{
public:
- PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id);
- Dsymbol *syntaxCopy(Dsymbol *);
- bool isVirtual();
+ PostBlitDeclaration *syntaxCopy(Dsymbol *);
+ bool isVirtual() const;
bool addPreInvariant();
bool addPostInvariant();
bool overloadInsert(Dsymbol *s);
@@ -799,12 +746,10 @@ public:
class DtorDeclaration : public FuncDeclaration
{
public:
- DtorDeclaration(Loc loc, Loc endloc);
- DtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id);
- Dsymbol *syntaxCopy(Dsymbol *);
+ DtorDeclaration *syntaxCopy(Dsymbol *);
const char *kind() const;
- const char *toChars();
- bool isVirtual();
+ const char *toChars() const;
+ bool isVirtual() const;
bool addPreInvariant();
bool addPostInvariant();
bool overloadInsert(Dsymbol *s);
@@ -816,11 +761,9 @@ public:
class StaticCtorDeclaration : public FuncDeclaration
{
public:
- StaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
- StaticCtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc);
- Dsymbol *syntaxCopy(Dsymbol *);
+ StaticCtorDeclaration *syntaxCopy(Dsymbol *);
AggregateDeclaration *isThis();
- bool isVirtual();
+ bool isVirtual() const;
bool addPreInvariant();
bool addPostInvariant();
bool hasStaticCtorOrDtor();
@@ -832,8 +775,7 @@ public:
class SharedStaticCtorDeclaration : public StaticCtorDeclaration
{
public:
- SharedStaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
- Dsymbol *syntaxCopy(Dsymbol *);
+ SharedStaticCtorDeclaration *syntaxCopy(Dsymbol *);
SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
@@ -844,11 +786,9 @@ class StaticDtorDeclaration : public FuncDeclaration
public:
VarDeclaration *vgate; // 'gate' variable
- StaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
- StaticDtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc);
- Dsymbol *syntaxCopy(Dsymbol *);
+ StaticDtorDeclaration *syntaxCopy(Dsymbol *);
AggregateDeclaration *isThis();
- bool isVirtual();
+ bool isVirtual() const;
bool hasStaticCtorOrDtor();
bool addPreInvariant();
bool addPostInvariant();
@@ -860,8 +800,7 @@ public:
class SharedStaticDtorDeclaration : public StaticDtorDeclaration
{
public:
- SharedStaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc);
- Dsymbol *syntaxCopy(Dsymbol *);
+ SharedStaticDtorDeclaration *syntaxCopy(Dsymbol *);
SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
@@ -870,9 +809,8 @@ public:
class InvariantDeclaration : public FuncDeclaration
{
public:
- InvariantDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id = NULL);
- Dsymbol *syntaxCopy(Dsymbol *);
- bool isVirtual();
+ InvariantDeclaration *syntaxCopy(Dsymbol *);
+ bool isVirtual() const;
bool addPreInvariant();
bool addPostInvariant();
@@ -888,10 +826,9 @@ public:
// toObjFile() these nested functions after this one
FuncDeclarations deferredNested;
- UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc);
- Dsymbol *syntaxCopy(Dsymbol *);
+ UnitTestDeclaration *syntaxCopy(Dsymbol *);
AggregateDeclaration *isThis();
- bool isVirtual();
+ bool isVirtual() const;
bool addPreInvariant();
bool addPostInvariant();
@@ -905,31 +842,12 @@ public:
Parameters *parameters;
VarArg varargs;
- NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments, VarArg varargs);
- Dsymbol *syntaxCopy(Dsymbol *);
+ NewDeclaration *syntaxCopy(Dsymbol *);
const char *kind() const;
- bool isVirtual();
+ bool isVirtual() const;
bool addPreInvariant();
bool addPostInvariant();
NewDeclaration *isNewDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
-
-
-class DeleteDeclaration : public FuncDeclaration
-{
-public:
- Parameters *parameters;
-
- DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *arguments);
- Dsymbol *syntaxCopy(Dsymbol *);
- const char *kind() const;
- bool isDelete();
- bool isVirtual();
- bool addPreInvariant();
- bool addPostInvariant();
-
- DeleteDeclaration *isDeleteDeclaration() { return this; }
- void accept(Visitor *v) { v->visit(this); }
-};
diff --git a/gcc/d/dmd/delegatize.c b/gcc/d/dmd/delegatize.c
deleted file mode 100644
index b3019aa..0000000
--- a/gcc/d/dmd/delegatize.c
+++ /dev/null
@@ -1,208 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/delegatize.c
- */
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "expression.h"
-#include "statement.h"
-#include "mtype.h"
-#include "utf.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "scope.h"
-#include "init.h"
-#include "tokens.h"
-
-
-bool walkPostorder(Expression *e, StoppableVisitor *v);
-void lambdaSetParent(Expression *e, Scope *sc);
-bool lambdaCheckForNestedRef(Expression *e, Scope *sc);
-
-/********************************************
- * Convert from expression to delegate that returns the expression,
- * i.e. convert:
- * expr
- * to:
- * typeof(expr) delegate() { return expr; }
- */
-Expression *toDelegate(Expression *e, Type* t, Scope *sc)
-{
- //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), e->toChars());
- Loc loc = e->loc;
-
- TypeFunction *tf = new TypeFunction(ParameterList(), t, LINKd);
- if (t->hasWild())
- tf->mod = MODwild;
- FuncLiteralDeclaration *fld =
- new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL);
-
- sc = sc->push();
- sc->parent = fld; // set current function to be the delegate
- lambdaSetParent(e, sc);
- bool r = lambdaCheckForNestedRef(e, sc);
- sc = sc->pop();
-
- if (r)
- return new ErrorExp();
-
- Statement *s;
- if (t->ty == Tvoid)
- s = new ExpStatement(loc, e);
- else
- s = new ReturnStatement(loc, e);
- fld->fbody = s;
-
- e = new FuncExp(loc, fld);
- e = expressionSemantic(e, sc);
- return e;
-}
-
-/******************************************
- * Patch the parent of declarations to be the new function literal.
- */
-void lambdaSetParent(Expression *e, Scope *sc)
-{
- class LambdaSetParent : public StoppableVisitor
- {
- Scope *sc;
- public:
- LambdaSetParent(Scope *sc) : sc(sc) {}
-
- void visit(Expression *)
- {
- }
-
- void visit(DeclarationExp *e)
- {
- e->declaration->parent = sc->parent;
- }
-
- void visit(IndexExp *e)
- {
- if (e->lengthVar)
- {
- //printf("lengthVar\n");
- e->lengthVar->parent = sc->parent;
- }
- }
-
- void visit(SliceExp *e)
- {
- if (e->lengthVar)
- {
- //printf("lengthVar\n");
- e->lengthVar->parent = sc->parent;
- }
- }
- };
-
- LambdaSetParent lsp(sc);
- walkPostorder(e, &lsp);
-}
-
-/*******************************************
- * Look for references to variables in a scope enclosing the new function literal.
- * Returns true if error occurs.
- */
-bool lambdaCheckForNestedRef(Expression *e, Scope *sc)
-{
- class LambdaCheckForNestedRef : public StoppableVisitor
- {
- public:
- Scope *sc;
- bool result;
-
- LambdaCheckForNestedRef(Scope *sc)
- : sc(sc), result(false)
- {
- }
-
- void visit(Expression *)
- {
- }
-
- void visit(SymOffExp *e)
- {
- VarDeclaration *v = e->var->isVarDeclaration();
- if (v)
- result = v->checkNestedReference(sc, Loc());
- }
-
- void visit(VarExp *e)
- {
- VarDeclaration *v = e->var->isVarDeclaration();
- if (v)
- result = v->checkNestedReference(sc, Loc());
- }
-
- void visit(ThisExp *e)
- {
- if (e->var)
- result = e->var->checkNestedReference(sc, Loc());
- }
-
- void visit(DeclarationExp *e)
- {
- VarDeclaration *v = e->declaration->isVarDeclaration();
- if (v)
- {
- result = v->checkNestedReference(sc, Loc());
- if (result)
- return;
-
- /* Some expressions cause the frontend to create a temporary.
- * For example, structs with cpctors replace the original
- * expression e with:
- * __cpcttmp = __cpcttmp.cpctor(e);
- *
- * In this instance, we need to ensure that the original
- * expression e does not have any nested references by
- * checking the declaration initializer too.
- */
- if (v->_init && v->_init->isExpInitializer())
- {
- Expression *ie = initializerToExpression(v->_init);
- result = lambdaCheckForNestedRef(ie, sc);
- }
- }
- }
- };
-
- LambdaCheckForNestedRef v(sc);
- walkPostorder(e, &v);
- return v.result;
-}
-
-bool checkNestedRef(Dsymbol *s, Dsymbol *p)
-{
- while (s)
- {
- if (s == p) // hit!
- return false;
-
- if (FuncDeclaration *fd = s->isFuncDeclaration())
- {
- if (!fd->isThis() && !fd->isNested())
- break;
-
- // Bugzilla 15332: change to delegate if fd is actually nested.
- if (FuncLiteralDeclaration *fld = fd->isFuncLiteralDeclaration())
- fld->tok = TOKdelegate;
- }
- if (AggregateDeclaration *ad = s->isAggregateDeclaration())
- {
- if (ad->storage_class & STCstatic)
- break;
- }
- s = s->toParent2();
- }
- return true;
-}
diff --git a/gcc/d/dmd/delegatize.d b/gcc/d/dmd/delegatize.d
new file mode 100644
index 0000000..07c1bbd
--- /dev/null
+++ b/gcc/d/dmd/delegatize.d
@@ -0,0 +1,305 @@
+/**
+ * Implements conversion from expressions to delegates for lazy parameters.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/function.html#lazy-params, Lazy Parameters)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/delegatize.d, _delegatize.d)
+ * Documentation: https://dlang.org/phobos/dmd_delegatize.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/delegatize.d
+ */
+
+module dmd.delegatize;
+
+import core.stdc.stdio;
+import dmd.apply;
+import dmd.astenums;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.init;
+import dmd.initsem;
+import dmd.mtype;
+import dmd.statement;
+import dmd.tokens;
+import dmd.visitor;
+
+
+/*********************************
+ * Convert expression into a delegate.
+ *
+ * Used to convert the argument to a lazy parameter.
+ *
+ * Params:
+ * e = argument to convert to a delegate
+ * t = the type to be returned by the delegate
+ * sc = context
+ * Returns:
+ * A delegate literal
+ */
+Expression toDelegate(Expression e, Type t, Scope* sc)
+{
+ //printf("Expression::toDelegate(t = %s) %s\n", t.toChars(), e.toChars());
+ Loc loc = e.loc;
+ auto tf = new TypeFunction(ParameterList(), t, LINK.d);
+ if (t.hasWild())
+ tf.mod = MODFlags.wild;
+ auto fld = new FuncLiteralDeclaration(loc, loc, tf, TOK.delegate_, null);
+ lambdaSetParent(e, fld);
+
+ sc = sc.push();
+ sc.parent = fld; // set current function to be the delegate
+ bool r = lambdaCheckForNestedRef(e, sc);
+ sc = sc.pop();
+ if (r)
+ return ErrorExp.get();
+
+ Statement s;
+ if (t.ty == Tvoid)
+ s = new ExpStatement(loc, e);
+ else
+ s = new ReturnStatement(loc, e);
+ fld.fbody = s;
+ e = new FuncExp(loc, fld);
+ e = e.expressionSemantic(sc);
+ return e;
+}
+
+/******************************************
+ * Patch the parent of declarations to be the new function literal.
+ *
+ * Since the expression is going to be moved into a function literal,
+ * the parent for declarations in the expression needs to be
+ * reset to that function literal.
+ * Params:
+ * e = expression to check
+ * fd = function literal symbol (the new parent)
+ */
+private void lambdaSetParent(Expression e, FuncDeclaration fd)
+{
+ extern (C++) final class LambdaSetParent : StoppableVisitor
+ {
+ alias visit = typeof(super).visit;
+ FuncDeclaration fd;
+
+ private void setParent(Dsymbol s)
+ {
+ VarDeclaration vd = s.isVarDeclaration();
+ FuncDeclaration pfd = s.parent ? s.parent.isFuncDeclaration() : null;
+ s.parent = fd;
+ if (!vd || !pfd)
+ return;
+ // move to fd's closure when applicable
+ foreach (i; 0 .. pfd.closureVars.dim)
+ {
+ if (vd == pfd.closureVars[i])
+ {
+ pfd.closureVars.remove(i);
+ fd.closureVars.push(vd);
+ break;
+ }
+ }
+ }
+
+ public:
+ extern (D) this(FuncDeclaration fd)
+ {
+ this.fd = fd;
+ }
+
+ override void visit(Expression)
+ {
+ }
+
+ override void visit(DeclarationExp e)
+ {
+ setParent(e.declaration);
+ e.declaration.accept(this);
+ }
+
+ override void visit(IndexExp e)
+ {
+ if (e.lengthVar)
+ {
+ //printf("lengthVar\n");
+ setParent(e.lengthVar);
+ e.lengthVar.accept(this);
+ }
+ }
+
+ override void visit(SliceExp e)
+ {
+ if (e.lengthVar)
+ {
+ //printf("lengthVar\n");
+ setParent(e.lengthVar);
+ e.lengthVar.accept(this);
+ }
+ }
+
+ override void visit(Dsymbol)
+ {
+ }
+
+ override void visit(VarDeclaration v)
+ {
+ if (v._init)
+ v._init.accept(this);
+ }
+
+ override void visit(Initializer)
+ {
+ }
+
+ override void visit(ExpInitializer ei)
+ {
+ walkPostorder(ei.exp ,this);
+ }
+
+ override void visit(StructInitializer si)
+ {
+ foreach (i, const id; si.field)
+ if (Initializer iz = si.value[i])
+ iz.accept(this);
+ }
+
+ override void visit(ArrayInitializer ai)
+ {
+ foreach (i, ex; ai.index)
+ {
+ if (ex)
+ walkPostorder(ex, this);
+ if (Initializer iz = ai.value[i])
+ iz.accept(this);
+ }
+ }
+ }
+
+ scope LambdaSetParent lsp = new LambdaSetParent(fd);
+ walkPostorder(e, lsp);
+}
+
+/*******************************************
+ * Look for references to variables in a scope enclosing the new function literal.
+ *
+ * Essentially just calls `checkNestedReference() for each variable reference in `e`.
+ * Params:
+ * sc = context
+ * e = expression to check
+ * Returns:
+ * true if error occurs.
+ */
+bool lambdaCheckForNestedRef(Expression e, Scope* sc)
+{
+ extern (C++) final class LambdaCheckForNestedRef : StoppableVisitor
+ {
+ alias visit = typeof(super).visit;
+ public:
+ Scope* sc;
+ bool result;
+
+ extern (D) this(Scope* sc)
+ {
+ this.sc = sc;
+ }
+
+ override void visit(Expression)
+ {
+ }
+
+ override void visit(SymOffExp e)
+ {
+ VarDeclaration v = e.var.isVarDeclaration();
+ if (v)
+ result = v.checkNestedReference(sc, Loc.initial);
+ }
+
+ override void visit(VarExp e)
+ {
+ VarDeclaration v = e.var.isVarDeclaration();
+ if (v)
+ result = v.checkNestedReference(sc, Loc.initial);
+ }
+
+ override void visit(ThisExp e)
+ {
+ if (e.var)
+ result = e.var.checkNestedReference(sc, Loc.initial);
+ }
+
+ override void visit(DeclarationExp e)
+ {
+ VarDeclaration v = e.declaration.isVarDeclaration();
+ if (v)
+ {
+ result = v.checkNestedReference(sc, Loc.initial);
+ if (result)
+ return;
+ /* Some expressions cause the frontend to create a temporary.
+ * For example, structs with cpctors replace the original
+ * expression e with:
+ * __cpcttmp = __cpcttmp.cpctor(e);
+ *
+ * In this instance, we need to ensure that the original
+ * expression e does not have any nested references by
+ * checking the declaration initializer too.
+ */
+ if (v._init && v._init.isExpInitializer())
+ {
+ Expression ie = v._init.initializerToExpression();
+ result = lambdaCheckForNestedRef(ie, sc);
+ }
+ }
+ }
+ }
+
+ scope LambdaCheckForNestedRef v = new LambdaCheckForNestedRef(sc);
+ walkPostorder(e, v);
+ return v.result;
+}
+
+/*****************************************
+ * See if context `s` is nested within context `p`, meaning
+ * it `p` is reachable at runtime by walking the static links.
+ * If any of the intervening contexts are function literals,
+ * make sure they are delegates.
+ * Params:
+ * s = inner context
+ * p = outer context
+ * Returns:
+ * true means it is accessible by walking the context pointers at runtime
+ * References:
+ * for static links see https://en.wikipedia.org/wiki/Call_stack#Functions_of_the_call_stack
+ */
+bool ensureStaticLinkTo(Dsymbol s, Dsymbol p)
+{
+ while (s)
+ {
+ if (s == p) // hit!
+ return true;
+
+ if (auto fd = s.isFuncDeclaration())
+ {
+ if (!fd.isThis() && !fd.isNested())
+ break;
+
+ // https://issues.dlang.org/show_bug.cgi?id=15332
+ // change to delegate if fd is actually nested.
+ if (auto fld = fd.isFuncLiteralDeclaration())
+ fld.tok = TOK.delegate_;
+ }
+ if (auto ad = s.isAggregateDeclaration())
+ {
+ if (ad.storage_class & STC.static_)
+ break;
+ }
+ s = s.toParentP(p);
+ }
+ return false;
+}
diff --git a/gcc/d/dmd/denum.c b/gcc/d/dmd/denum.c
deleted file mode 100644
index b00eaa0..0000000
--- a/gcc/d/dmd/denum.c
+++ /dev/null
@@ -1,388 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/enum.c
- */
-
-#include "root/dsystem.h"
-#include "root/root.h"
-
-#include "errors.h"
-#include "enum.h"
-#include "attrib.h"
-#include "mtype.h"
-#include "scope.h"
-#include "id.h"
-#include "expression.h"
-#include "module.h"
-#include "declaration.h"
-#include "init.h"
-
-bool isSpecialEnumIdent(const Identifier *ident)
-{
- return ident == Id::__c_long ||
- ident == Id::__c_ulong ||
- ident == Id::__c_longlong ||
- ident == Id::__c_ulonglong ||
- ident == Id::__c_long_double ||
- ident == Id::__c_wchar_t ||
- ident == Id::__c_complex_float ||
- ident == Id::__c_complex_double ||
- ident == Id::__c_complex_real;
-}
-
-/********************************* EnumDeclaration ****************************/
-
-EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
- : ScopeDsymbol(id)
-{
- //printf("EnumDeclaration() %s\n", toChars());
- this->loc = loc;
- type = new TypeEnum(this);
- this->memtype = memtype;
- maxval = NULL;
- minval = NULL;
- defaultval = NULL;
- sinit = NULL;
- isdeprecated = false;
- protection = Prot(Prot::undefined);
- parent = NULL;
- added = false;
- inuse = 0;
-}
-
-Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- EnumDeclaration *ed = new EnumDeclaration(loc, ident,
- memtype ? memtype->syntaxCopy() : NULL);
- return ScopeDsymbol::syntaxCopy(ed);
-}
-
-void EnumDeclaration::setScope(Scope *sc)
-{
- if (semanticRun > PASSinit)
- return;
- ScopeDsymbol::setScope(sc);
-}
-
-void EnumDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
-{
- /* Anonymous enum members get added to enclosing scope.
- */
- ScopeDsymbol *scopesym = isAnonymous() ? sds : this;
-
- if (!isAnonymous())
- {
- ScopeDsymbol::addMember(sc, sds);
-
- if (!symtab)
- symtab = new DsymbolTable();
- }
-
- if (members)
- {
- for (size_t i = 0; i < members->length; i++)
- {
- EnumMember *em = (*members)[i]->isEnumMember();
- em->ed = this;
- //printf("add %s to scope %s\n", em->toChars(), scopesym->toChars());
- em->addMember(sc, isAnonymous() ? scopesym : this);
- }
- }
- added = true;
-}
-
-/******************************
- * Get the value of the .max/.min property as an Expression
- * Input:
- * id Id::max or Id::min
- */
-
-Expression *EnumDeclaration::getMaxMinValue(Loc loc, Identifier *id)
-{
- //printf("EnumDeclaration::getMaxValue()\n");
- bool first = true;
-
- Expression **pval = (id == Id::max) ? &maxval : &minval;
-
- if (inuse)
- {
- error(loc, "recursive definition of .%s property", id->toChars());
- goto Lerrors;
- }
- if (*pval)
- goto Ldone;
-
- if (_scope)
- dsymbolSemantic(this, _scope);
- if (errors)
- goto Lerrors;
- if (!members)
- {
- if (isSpecial())
- {
- /* Allow these special enums to not need a member list
- */
- return memtype->getProperty(loc, id, 0);
- }
-
- error(loc, "is opaque and has no `.%s`", id->toChars());
- goto Lerrors;
- }
- if (!(memtype && memtype->isintegral()))
- {
- error(loc, "has no .%s property because base type %s is not an integral type",
- id->toChars(),
- memtype ? memtype->toChars() : "");
- goto Lerrors;
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- EnumMember *em = (*members)[i]->isEnumMember();
- if (!em)
- continue;
- if (em->errors)
- {
- errors = true;
- continue;
- }
-
- if (em->semanticRun < PASSsemanticdone)
- {
- em->error("is forward referenced looking for `.%s`", id->toChars());
- errors = true;
- continue;
- }
-
- if (first)
- {
- *pval = em->value();
- first = false;
- }
- else
- {
- /* In order to work successfully with UDTs,
- * build expressions to do the comparisons,
- * and let the semantic analyzer and constant
- * folder give us the result.
- */
-
- /* Compute:
- * if (e > maxval)
- * maxval = e;
- */
- Expression *e = em->value();
- Expression *ec = new CmpExp(id == Id::max ? TOKgt : TOKlt, em->loc, e, *pval);
- inuse++;
- ec = expressionSemantic(ec, em->_scope);
- inuse--;
- ec = ec->ctfeInterpret();
- if (ec->op == TOKerror)
- {
- errors = true;
- continue;
- }
- if (ec->toInteger())
- *pval = e;
- }
- }
- if (errors)
- goto Lerrors;
-Ldone:
- {
- Expression *e = *pval;
- if (e->op != TOKerror)
- {
- e = e->copy();
- e->loc = loc;
- }
- return e;
- }
-
-Lerrors:
- *pval = new ErrorExp();
- return *pval;
-}
-
-/****************
- * Determine if enum is a 'special' one.
- * Returns:
- * true if special
- */
-bool EnumDeclaration::isSpecial() const
-{
- return isSpecialEnumIdent(ident) && memtype;
-}
-
-Expression *EnumDeclaration::getDefaultValue(Loc loc)
-{
- //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars());
- if (defaultval)
- return defaultval;
-
- if (_scope)
- dsymbolSemantic(this, _scope);
- if (errors)
- goto Lerrors;
- if (!members)
- {
- if (isSpecial())
- {
- /* Allow these special enums to not need a member list
- */
- defaultval = memtype->defaultInit(loc);
- return defaultval;
- }
-
- error(loc, "is opaque and has no default initializer");
- goto Lerrors;
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- EnumMember *em = (*members)[i]->isEnumMember();
- if (em)
- {
- if (em->semanticRun < PASSsemanticdone)
- {
- error(loc, "forward reference of `%s.init`", toChars());
- goto Lerrors;
- }
-
- defaultval = em->value();
- return defaultval;
- }
- }
-
-Lerrors:
- defaultval = new ErrorExp();
- return defaultval;
-}
-
-Type *EnumDeclaration::getMemtype(Loc loc)
-{
- if (loc.linnum == 0)
- loc = this->loc;
- if (_scope)
- {
- /* Enum is forward referenced. We don't need to resolve the whole thing,
- * just the base type
- */
- if (memtype)
- memtype = typeSemantic(memtype, loc, _scope);
- }
- if (!memtype)
- {
- if (!isAnonymous() && (members || semanticRun >= PASSsemanticdone))
- memtype = Type::tint32;
- else
- {
- error(loc, "is forward referenced looking for base type");
- return Type::terror;
- }
- }
- return memtype;
-}
-
-bool EnumDeclaration::oneMember(Dsymbol **ps, Identifier *ident)
-{
- if (isAnonymous())
- return Dsymbol::oneMembers(members, ps, ident);
- return Dsymbol::oneMember(ps, ident);
-}
-
-Type *EnumDeclaration::getType()
-{
- return type;
-}
-
-const char *EnumDeclaration::kind() const
-{
- return "enum";
-}
-
-bool EnumDeclaration::isDeprecated()
-{
- return isdeprecated;
-}
-
-Prot EnumDeclaration::prot()
-{
- return protection;
-}
-
-Dsymbol *EnumDeclaration::search(const Loc &loc, Identifier *ident, int flags)
-{
- //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars());
- if (_scope)
- {
- // Try one last time to resolve this enum
- dsymbolSemantic(this, _scope);
- }
-
- Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
- return s;
-}
-
-/********************************* EnumMember ****************************/
-
-EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *origType)
- : VarDeclaration(loc, NULL, id ? id : Id::empty, new ExpInitializer(loc, value))
-{
- this->ed = NULL;
- this->origValue = value;
- this->origType = origType;
-}
-
-EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *memType,
- StorageClass stc, UserAttributeDeclaration *uad, DeprecatedDeclaration *dd)
- : VarDeclaration(loc, NULL, id ? id : Id::empty, new ExpInitializer(loc, value))
-{
- this->ed = NULL;
- this->origValue = value;
- this->origType = memType;
- this->storage_class = stc;
- this->userAttribDecl = uad;
- this->depdecl = dd;
-}
-
-Expression *&EnumMember::value()
-{
- return ((ExpInitializer*)_init)->exp;
-}
-
-Dsymbol *EnumMember::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- return new EnumMember(loc, ident,
- value() ? value()->syntaxCopy() : NULL,
- origType ? origType->syntaxCopy() : NULL);
-}
-
-const char *EnumMember::kind() const
-{
- return "enum member";
-}
-
-Expression *EnumMember::getVarExp(Loc loc, Scope *sc)
-{
- dsymbolSemantic(this, sc);
- if (errors)
- return new ErrorExp();
- checkDisabled(loc, sc);
-
- if (depdecl && !depdecl->_scope)
- depdecl->_scope = sc;
- checkDeprecated(loc, sc);
-
- if (errors)
- return new ErrorExp();
- Expression *e = new VarExp(loc, this);
- return expressionSemantic(e, sc);
-}
diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d
new file mode 100644
index 0000000..54467d8
--- /dev/null
+++ b/gcc/d/dmd/denum.d
@@ -0,0 +1,333 @@
+/**
+ * Define `enum` declarations and `enum` members.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/enum.html, Enums)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/denum.d, _denum.d)
+ * Documentation: https://dlang.org/phobos/dmd_denum.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/denum.d
+ * References: https://dlang.org/spec/enum.html
+ */
+
+module dmd.denum;
+
+import core.stdc.stdio;
+
+import dmd.attrib;
+import dmd.gluelayer;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.expression;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.mtype;
+import dmd.tokens;
+import dmd.typesem;
+import dmd.visitor;
+
+/***********************************************************
+ * AST node for `EnumDeclaration`
+ * https://dlang.org/spec/enum.html#EnumDeclaration
+ */
+extern (C++) final class EnumDeclaration : ScopeDsymbol
+{
+ /* The separate, and distinct, cases are:
+ * 1. enum { ... }
+ * 2. enum : memtype { ... }
+ * 3. enum id { ... }
+ * 4. enum id : memtype { ... }
+ * 5. enum id : memtype;
+ * 6. enum id;
+ */
+ Type type; // the TypeEnum
+ Type memtype; // type of the members
+
+ Visibility visibility;
+ Expression maxval;
+ Expression minval;
+ Expression defaultval; // default initializer
+ bool isdeprecated;
+ bool added;
+ int inuse;
+
+ extern (D) this(const ref Loc loc, Identifier ident, Type memtype)
+ {
+ super(loc, ident);
+ //printf("EnumDeclaration() %s\n", toChars());
+ type = new TypeEnum(this);
+ this.memtype = memtype;
+ visibility = Visibility(Visibility.Kind.undefined);
+ }
+
+ override EnumDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto ed = new EnumDeclaration(loc, ident, memtype ? memtype.syntaxCopy() : null);
+ ScopeDsymbol.syntaxCopy(ed);
+ return ed;
+ }
+
+ override void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ version (none)
+ {
+ printf("EnumDeclaration::addMember() %s\n", toChars());
+ for (size_t i = 0; i < members.dim; i++)
+ {
+ EnumMember em = (*members)[i].isEnumMember();
+ printf(" member %s\n", em.toChars());
+ }
+ }
+ if (!isAnonymous())
+ {
+ ScopeDsymbol.addMember(sc, sds);
+ }
+
+ addEnumMembers(this, sc, sds);
+ }
+
+ override void setScope(Scope* sc)
+ {
+ if (semanticRun > PASS.init)
+ return;
+ ScopeDsymbol.setScope(sc);
+ }
+
+ override bool oneMember(Dsymbol* ps, Identifier ident)
+ {
+ if (isAnonymous())
+ return Dsymbol.oneMembers(members, ps, ident);
+ return Dsymbol.oneMember(ps, ident);
+ }
+
+ override Type getType()
+ {
+ return type;
+ }
+
+ override const(char)* kind() const
+ {
+ return "enum";
+ }
+
+ override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
+ {
+ //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident.toChars());
+ if (_scope)
+ {
+ // Try one last time to resolve this enum
+ dsymbolSemantic(this, _scope);
+ }
+
+ Dsymbol s = ScopeDsymbol.search(loc, ident, flags);
+ return s;
+ }
+
+ // is Dsymbol deprecated?
+ override bool isDeprecated() const
+ {
+ return isdeprecated;
+ }
+
+ override Visibility visible() pure nothrow @nogc @safe
+ {
+ return visibility;
+ }
+
+
+ /****************
+ * Determine if enum is a special one.
+ * Returns:
+ * `true` if special
+ */
+ bool isSpecial() const nothrow @nogc
+ {
+ return isSpecialEnumIdent(ident) && memtype;
+ }
+
+ Expression getDefaultValue(const ref Loc loc)
+ {
+ Expression handleErrors(){
+ defaultval = ErrorExp.get();
+ return defaultval;
+ }
+ //printf("EnumDeclaration::getDefaultValue() %p %s\n", this, toChars());
+ if (defaultval)
+ return defaultval;
+
+ if (_scope)
+ dsymbolSemantic(this, _scope);
+ if (errors)
+ return handleErrors();
+ if (!members)
+ {
+ if (isSpecial())
+ {
+ /* Allow these special enums to not need a member list
+ */
+ return defaultval = memtype.defaultInit(loc);
+ }
+
+ error(loc, "is opaque and has no default initializer");
+ return handleErrors();
+ }
+
+ foreach (const i; 0 .. members.dim)
+ {
+ EnumMember em = (*members)[i].isEnumMember();
+ if (em)
+ {
+ if (em.semanticRun < PASS.semanticdone)
+ {
+ error(loc, "forward reference of `%s.init`", toChars());
+ return handleErrors();
+ }
+
+ defaultval = em.value;
+ return defaultval;
+ }
+ }
+ return handleErrors();
+ }
+
+ Type getMemtype(const ref Loc loc)
+ {
+ if (_scope)
+ {
+ /* Enum is forward referenced. We don't need to resolve the whole thing,
+ * just the base type
+ */
+ if (memtype)
+ {
+ Loc locx = loc.isValid() ? loc : this.loc;
+ memtype = memtype.typeSemantic(locx, _scope);
+ }
+ else
+ {
+ // Run semantic to get the type from a possible first member value
+ dsymbolSemantic(this, _scope);
+ }
+ }
+ if (!memtype)
+ {
+ if (!isAnonymous() && (members || semanticRun >= PASS.semanticdone))
+ memtype = Type.tint32;
+ else
+ {
+ Loc locx = loc.isValid() ? loc : this.loc;
+ error(locx, "is forward referenced looking for base type");
+ return Type.terror;
+ }
+ }
+ return memtype;
+ }
+
+ override inout(EnumDeclaration) isEnumDeclaration() inout
+ {
+ return this;
+ }
+
+ Symbol* sinit;
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * AST node representing a member of an enum.
+ * https://dlang.org/spec/enum.html#EnumMember
+ * https://dlang.org/spec/enum.html#AnonymousEnumMember
+ */
+extern (C++) final class EnumMember : VarDeclaration
+{
+ /* Can take the following forms:
+ * 1. id
+ * 2. id = value
+ * 3. type id = value
+ */
+ @property ref value() { return (cast(ExpInitializer)_init).exp; }
+
+ // A cast() is injected to 'value' after dsymbolSemantic(),
+ // but 'origValue' will preserve the original value,
+ // or previous value + 1 if none was specified.
+ Expression origValue;
+
+ Type origType;
+
+ EnumDeclaration ed;
+
+ extern (D) this(const ref Loc loc, Identifier id, Expression value, Type origType)
+ {
+ super(loc, null, id ? id : Id.empty, new ExpInitializer(loc, value));
+ this.origValue = value;
+ this.origType = origType;
+ }
+
+ extern(D) this(Loc loc, Identifier id, Expression value, Type memtype,
+ StorageClass stc, UserAttributeDeclaration uad, DeprecatedDeclaration dd)
+ {
+ this(loc, id, value, memtype);
+ storage_class = stc;
+ userAttribDecl = uad;
+ depdecl = dd;
+ }
+
+ override EnumMember syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ return new EnumMember(
+ loc, ident,
+ value ? value.syntaxCopy() : null,
+ origType ? origType.syntaxCopy() : null,
+ storage_class,
+ userAttribDecl ? userAttribDecl.syntaxCopy(s) : null,
+ depdecl ? depdecl.syntaxCopy(s) : null);
+ }
+
+ override const(char)* kind() const
+ {
+ return "enum member";
+ }
+
+ override inout(EnumMember) isEnumMember() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/******************************************
+ * Check for special enum names.
+ *
+ * Special enum names are used by the C++ name mangler to represent
+ * C++ types that are not basic D types.
+ * Params:
+ * ident = identifier to check for specialness
+ * Returns:
+ * `true` if it is special
+ */
+bool isSpecialEnumIdent(const Identifier ident) @nogc nothrow
+{
+ return ident == Id.__c_long ||
+ ident == Id.__c_ulong ||
+ ident == Id.__c_longlong ||
+ ident == Id.__c_ulonglong ||
+ ident == Id.__c_long_double ||
+ ident == Id.__c_wchar_t ||
+ ident == Id.__c_complex_float ||
+ ident == Id.__c_complex_double ||
+ ident == Id.__c_complex_real;
+}
diff --git a/gcc/d/dmd/dimport.c b/gcc/d/dmd/dimport.c
deleted file mode 100644
index 7b63a18..0000000
--- a/gcc/d/dmd/dimport.c
+++ /dev/null
@@ -1,320 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/import.c
- */
-
-#include "root/dsystem.h"
-#include "root/root.h"
-
-#include "mars.h"
-#include "dsymbol.h"
-#include "import.h"
-#include "identifier.h"
-#include "module.h"
-#include "scope.h"
-#include "mtype.h"
-#include "declaration.h"
-#include "id.h"
-#include "attrib.h"
-#include "hdrgen.h"
-
-/********************************* Import ****************************/
-
-Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId,
- int isstatic)
- : Dsymbol(NULL)
-{
- assert(id);
- this->loc = loc;
- this->packages = packages;
- this->id = id;
- this->aliasId = aliasId;
- this->isstatic = isstatic;
- this->protection = Prot(Prot::private_); // default to private
- this->pkg = NULL;
- this->mod = NULL;
-
- // Set symbol name (bracketed)
- if (aliasId)
- {
- // import [cstdio] = std.stdio;
- this->ident = aliasId;
- }
- else if (packages && packages->length)
- {
- // import [std].stdio;
- this->ident = (*packages)[0];
- }
- else
- {
- // import [foo];
- this->ident = id;
- }
-}
-
-void Import::addAlias(Identifier *name, Identifier *alias)
-{
- if (isstatic)
- error("cannot have an import bind list");
-
- if (!aliasId)
- this->ident = NULL; // make it an anonymous import
-
- names.push(name);
- aliases.push(alias);
-}
-
-const char *Import::kind() const
-{
- return isstatic ? "static import" : "import";
-}
-
-Prot Import::prot()
-{
- return protection;
-}
-
-Dsymbol *Import::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
-
- Import *si = new Import(loc, packages, id, aliasId, isstatic);
-
- for (size_t i = 0; i < names.length; i++)
- {
- si->addAlias(names[i], aliases[i]);
- }
-
- return si;
-}
-
-void Import::load(Scope *sc)
-{
- //printf("Import::load('%s') %p\n", toPrettyChars(), this);
-
- // See if existing module
- DsymbolTable *dst = Package::resolve(packages, NULL, &pkg);
- Dsymbol *s = dst->lookup(id);
- if (s)
- {
- if (s->isModule())
- mod = (Module *)s;
- else
- {
- if (s->isAliasDeclaration())
- {
- ::error(loc, "%s %s conflicts with %s", s->kind(), s->toPrettyChars(), id->toChars());
- }
- else if (Package *p = s->isPackage())
- {
- if (p->isPkgMod == PKGunknown)
- {
- mod = Module::load(loc, packages, id);
- if (!mod)
- p->isPkgMod = PKGpackage;
- else
- {
- // mod is a package.d, or a normal module which conflicts with the package name.
- assert(mod->isPackageFile == (p->isPkgMod == PKGmodule));
- if (mod->isPackageFile)
- mod->tag = p->tag; // reuse the same package tag
- }
- }
- else
- {
- mod = p->isPackageMod();
- }
- if (!mod)
- {
- ::error(loc, "can only import from a module, not from package %s.%s",
- p->toPrettyChars(), id->toChars());
- }
- }
- else if (pkg)
- {
- ::error(loc, "can only import from a module, not from package %s.%s",
- pkg->toPrettyChars(), id->toChars());
- }
- else
- {
- ::error(loc, "can only import from a module, not from package %s",
- id->toChars());
- }
- }
- }
-
- if (!mod)
- {
- // Load module
- mod = Module::load(loc, packages, id);
- if (mod)
- {
- dst->insert(id, mod); // id may be different from mod->ident,
- // if so then insert alias
- }
- }
- if (mod && !mod->importedFrom)
- mod->importedFrom = sc ? sc->_module->importedFrom : Module::rootModule;
- if (!pkg)
- {
- if (mod && mod->isPackageFile)
- {
- // one level depth package.d file (import pkg; ./pkg/package.d)
- // it's necessary to use the wrapping Package already created
- pkg = mod->pkg;
- }
- else
- pkg = mod;
- }
-
- //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
-}
-
-void Import::importAll(Scope *sc)
-{
- if (mod) return; // Already done
- load(sc);
- if (!mod) return; // Failed
-
- if (sc->stc & STCstatic)
- isstatic = true;
- mod->importAll(NULL);
- if (mod->md && mod->md->isdeprecated)
- {
- Expression *msg = mod->md->msg;
- if (StringExp *se = msg ? msg->toStringExp() : NULL)
- mod->deprecation(loc, "is deprecated - %s", se->string);
- else
- mod->deprecation(loc, "is deprecated");
- }
- if (sc->explicitProtection)
- protection = sc->protection;
- if (!isstatic && !aliasId && !names.length)
- sc->scopesym->importScope(mod, protection);
- // Enable access to pkgs/mod as soon as posible, because compiler
- // can traverse them before the import gets semantic (Issue: 21501)
- if (!aliasId && !names.length)
- addPackageAccess(sc->scopesym);
-}
-
-/*******************************
- * Mark the imported packages as accessible from the current
- * scope. This access check is necessary when using FQN b/c
- * we're using a single global package tree.
- * https://issues.dlang.org/show_bug.cgi?id=313
- */
-void Import::addPackageAccess(ScopeDsymbol *scopesym)
-{
- //printf("Import::addPackageAccess('%s') %p\n", toPrettyChars(), this);
- if (packages)
- {
- // import a.b.c.d;
- Package *p = pkg; // a
- scopesym->addAccessiblePackage(p, protection);
- for (size_t i = 1; i < packages->length; i++) // [b, c]
- {
- Identifier *id = (*packages)[i];
- p = (Package *) p->symtab->lookup(id);
- // https://issues.dlang.org/show_bug.cgi?id=17991
- // An import of truly empty file/package can happen
- // https://issues.dlang.org/show_bug.cgi?id=20151
- // Package in the path conflicts with a module name
- if (p == NULL)
- return;
- scopesym->addAccessiblePackage(p, protection);
- }
- }
- scopesym->addAccessiblePackage(mod, protection); // d
-}
-
-Dsymbol *Import::toAlias()
-{
- if (aliasId)
- return mod;
- return this;
-}
-
-/*****************************
- * Add import to sd's symbol table.
- */
-
-void Import::addMember(Scope *sc, ScopeDsymbol *sd)
-{
- //printf("Import::addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd->toChars(), sc);
- if (names.length == 0)
- return Dsymbol::addMember(sc, sd);
-
- if (aliasId)
- Dsymbol::addMember(sc, sd);
-
- /* Instead of adding the import to sd's symbol table,
- * add each of the alias=name pairs
- */
- for (size_t i = 0; i < names.length; i++)
- {
- Identifier *name = names[i];
- Identifier *alias = aliases[i];
-
- if (!alias)
- alias = name;
-
- TypeIdentifier *tname = new TypeIdentifier(loc, name);
- AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname);
- ad->_import = this;
- ad->addMember(sc, sd);
-
- aliasdecls.push(ad);
- }
-}
-
-void Import::setScope(Scope *sc)
-{
- Dsymbol::setScope(sc);
- if (aliasdecls.length)
- {
- if (!mod)
- importAll(sc);
-
- sc = sc->push(mod);
- sc->protection = protection;
- for (size_t i = 0; i < aliasdecls.length; i++)
- {
- AliasDeclaration *ad = aliasdecls[i];
- ad->setScope(sc);
- }
- sc = sc->pop();
- }
-}
-
-Dsymbol *Import::search(const Loc &loc, Identifier *ident, int flags)
-{
- //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
-
- if (!pkg)
- {
- load(NULL);
- mod->importAll(NULL);
- dsymbolSemantic(mod, NULL);
- }
-
- // Forward it to the package/module
- return pkg->search(loc, ident, flags);
-}
-
-bool Import::overloadInsert(Dsymbol *s)
-{
- /* Allow multiple imports with the same package base, but disallow
- * alias collisions (Bugzilla 5412).
- */
- assert(ident && ident == s->ident);
- Import *imp;
- if (!aliasId && (imp = s->isImport()) != NULL && !imp->aliasId)
- return true;
- else
- return false;
-}
diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d
new file mode 100644
index 0000000..8cd4364
--- /dev/null
+++ b/gcc/d/dmd/dimport.d
@@ -0,0 +1,358 @@
+/**
+ * A `Dsymbol` representing a renamed import.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dimport.d, _dimport.d)
+ * Documentation: https://dlang.org/phobos/dmd_dimport.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dimport.d
+ */
+
+module dmd.dimport;
+
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.declaration;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.errors;
+import dmd.expression;
+import dmd.globals;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.visitor;
+
+/***********************************************************
+ */
+extern (C++) final class Import : Dsymbol
+{
+ /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2;
+ */
+ Identifier[] packages; // array of Identifier's representing packages
+ Identifier id; // module Identifier
+ Identifier aliasId;
+ int isstatic; // !=0 if static import
+ Visibility visibility;
+
+ // Pairs of alias=name to bind into current namespace
+ Identifiers names;
+ Identifiers aliases;
+
+ Module mod;
+ Package pkg; // leftmost package/module
+
+ // corresponding AliasDeclarations for alias=name pairs
+ AliasDeclarations aliasdecls;
+
+ extern (D) this(const ref Loc loc, Identifier[] packages, Identifier id, Identifier aliasId, int isstatic)
+ {
+ Identifier selectIdent()
+ {
+ // select Dsymbol identifier (bracketed)
+ if (aliasId)
+ {
+ // import [aliasId] = std.stdio;
+ return aliasId;
+ }
+ else if (packages.length > 0)
+ {
+ // import [std].stdio;
+ return packages[0];
+ }
+ else
+ {
+ // import [id];
+ return id;
+ }
+ }
+
+ super(loc, selectIdent());
+
+ assert(id);
+ version (none)
+ {
+ printf("Import::Import(");
+ foreach (id; packages)
+ {
+ printf("%s.", id.toChars());
+ }
+ printf("%s)\n", id.toChars());
+ }
+ this.packages = packages;
+ this.id = id;
+ this.aliasId = aliasId;
+ this.isstatic = isstatic;
+ this.visibility = Visibility.Kind.private_; // default to private
+ }
+
+ extern (D) void addAlias(Identifier name, Identifier _alias)
+ {
+ if (isstatic)
+ error("cannot have an import bind list");
+ if (!aliasId)
+ this.ident = null; // make it an anonymous import
+ names.push(name);
+ aliases.push(_alias);
+ }
+
+ override const(char)* kind() const
+ {
+ return isstatic ? "static import" : "import";
+ }
+
+ override Visibility visible() pure nothrow @nogc @safe
+ {
+ return visibility;
+ }
+
+ // copy only syntax trees
+ override Import syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto si = new Import(loc, packages, id, aliasId, isstatic);
+ si.comment = comment;
+ for (size_t i = 0; i < names.dim; i++)
+ {
+ si.addAlias(names[i], aliases[i]);
+ }
+ return si;
+ }
+
+ /*******************************
+ * Load this module.
+ * Returns:
+ * true for errors, false for success
+ */
+ bool load(Scope* sc)
+ {
+ //printf("Import::load('%s') %p\n", toPrettyChars(), this);
+ // See if existing module
+ const errors = global.errors;
+ DsymbolTable dst = Package.resolve(packages, null, &pkg);
+ version (none)
+ {
+ if (pkg && pkg.isModule())
+ {
+ .error(loc, "can only import from a module, not from a member of module `%s`. Did you mean `import %s : %s`?", pkg.toChars(), pkg.toPrettyChars(), id.toChars());
+ mod = pkg.isModule(); // Error recovery - treat as import of that module
+ return true;
+ }
+ }
+ Dsymbol s = dst.lookup(id);
+ if (s)
+ {
+ if (s.isModule())
+ mod = cast(Module)s;
+ else
+ {
+ if (s.isAliasDeclaration())
+ {
+ .error(loc, "%s `%s` conflicts with `%s`", s.kind(), s.toPrettyChars(), id.toChars());
+ }
+ else if (Package p = s.isPackage())
+ {
+ if (p.isPkgMod == PKG.unknown)
+ {
+ uint preverrors = global.errors;
+ mod = Module.load(loc, packages, id);
+ if (!mod)
+ p.isPkgMod = PKG.package_;
+ else
+ {
+ // mod is a package.d, or a normal module which conflicts with the package name.
+ if (mod.isPackageFile)
+ mod.tag = p.tag; // reuse the same package tag
+ else
+ {
+ // show error if Module.load does not
+ if (preverrors == global.errors)
+ .error(loc, "%s `%s` from file %s conflicts with %s `%s`", mod.kind(), mod.toPrettyChars(), mod.srcfile.toChars, p.kind(), p.toPrettyChars());
+ return true;
+ }
+ }
+ }
+ else
+ {
+ mod = p.isPackageMod();
+ }
+ if (!mod)
+ {
+ .error(loc, "can only import from a module, not from package `%s.%s`", p.toPrettyChars(), id.toChars());
+ }
+ }
+ else if (pkg)
+ {
+ .error(loc, "can only import from a module, not from package `%s.%s`", pkg.toPrettyChars(), id.toChars());
+ }
+ else
+ {
+ .error(loc, "can only import from a module, not from package `%s`", id.toChars());
+ }
+ }
+ }
+ if (!mod)
+ {
+ // Load module
+ mod = Module.load(loc, packages, id);
+ if (mod)
+ {
+ // id may be different from mod.ident, if so then insert alias
+ dst.insert(id, mod);
+ }
+ }
+ if (mod && !mod.importedFrom)
+ mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule;
+ if (!pkg)
+ {
+ if (mod && mod.isPackageFile)
+ {
+ // one level depth package.d file (import pkg; ./pkg/package.d)
+ // it's necessary to use the wrapping Package already created
+ pkg = mod.pkg;
+ }
+ else
+ pkg = mod;
+ }
+ //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
+ return global.errors != errors;
+ }
+
+ override void importAll(Scope* sc)
+ {
+ if (mod) return; // Already done
+ load(sc);
+ if (!mod) return; // Failed
+
+ if (sc.stc & STC.static_)
+ isstatic = true;
+ mod.importAll(null);
+ mod.checkImportDeprecation(loc, sc);
+ if (sc.explicitVisibility)
+ visibility = sc.visibility;
+ if (!isstatic && !aliasId && !names.dim)
+ sc.scopesym.importScope(mod, visibility);
+ // Enable access to pkgs/mod as soon as posible, because compiler
+ // can traverse them before the import gets semantic (Issue: 21501)
+ if (!aliasId && !names.dim)
+ addPackageAccess(sc.scopesym);
+ }
+
+ /*******************************
+ * Mark the imported packages as accessible from the current
+ * scope. This access check is necessary when using FQN b/c
+ * we're using a single global package tree.
+ * https://issues.dlang.org/show_bug.cgi?id=313
+ */
+ extern (D) void addPackageAccess(ScopeDsymbol scopesym)
+ {
+ //printf("Import::addPackageAccess('%s') %p\n", toPrettyChars(), this);
+ if (packages.length > 0)
+ {
+ // import a.b.c.d;
+ auto p = pkg; // a
+ scopesym.addAccessiblePackage(p, visibility);
+ foreach (id; packages[1 .. $]) // [b, c]
+ {
+ p = cast(Package) p.symtab.lookup(id);
+ // https://issues.dlang.org/show_bug.cgi?id=17991
+ // An import of truly empty file/package can happen
+ // https://issues.dlang.org/show_bug.cgi?id=20151
+ // Package in the path conflicts with a module name
+ if (p is null)
+ break;
+ scopesym.addAccessiblePackage(p, visibility);
+ }
+ }
+ scopesym.addAccessiblePackage(mod, visibility); // d
+ }
+
+ override Dsymbol toAlias()
+ {
+ if (aliasId)
+ return mod;
+ return this;
+ }
+
+ /*****************************
+ * Add import to sd's symbol table.
+ */
+ override void addMember(Scope* sc, ScopeDsymbol sd)
+ {
+ //printf("Import.addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd.toChars(), sc);
+ if (names.dim == 0)
+ return Dsymbol.addMember(sc, sd);
+ if (aliasId)
+ Dsymbol.addMember(sc, sd);
+ /* Instead of adding the import to sd's symbol table,
+ * add each of the alias=name pairs
+ */
+ for (size_t i = 0; i < names.dim; i++)
+ {
+ Identifier name = names[i];
+ Identifier _alias = aliases[i];
+ if (!_alias)
+ _alias = name;
+ auto tname = new TypeIdentifier(loc, name);
+ auto ad = new AliasDeclaration(loc, _alias, tname);
+ ad._import = this;
+ ad.addMember(sc, sd);
+ aliasdecls.push(ad);
+ }
+ }
+
+ override void setScope(Scope* sc)
+ {
+ Dsymbol.setScope(sc);
+ if (aliasdecls.dim)
+ {
+ if (!mod)
+ importAll(sc);
+
+ sc = sc.push(mod);
+ sc.visibility = visibility;
+ foreach (ad; aliasdecls)
+ ad.setScope(sc);
+ sc = sc.pop();
+ }
+ }
+
+ override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
+ {
+ //printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
+ if (!pkg)
+ {
+ load(null);
+ mod.importAll(null);
+ mod.dsymbolSemantic(null);
+ }
+ // Forward it to the package/module
+ return pkg.search(loc, ident, flags);
+ }
+
+ override bool overloadInsert(Dsymbol s)
+ {
+ /* Allow multiple imports with the same package base, but disallow
+ * alias collisions
+ * https://issues.dlang.org/show_bug.cgi?id=5412
+ */
+ assert(ident && ident == s.ident);
+ Import imp;
+ if (!aliasId && (imp = s.isImport()) !is null && !imp.aliasId)
+ return true;
+ else
+ return false;
+ }
+
+ override inout(Import) isImport() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
diff --git a/gcc/d/dmd/dinterpret.c b/gcc/d/dmd/dinterpret.c
deleted file mode 100644
index ab9d88c..0000000
--- a/gcc/d/dmd/dinterpret.c
+++ /dev/null
@@ -1,7017 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/interpret.c
- */
-
-#include "root/dsystem.h" // mem{cpy|set}()
-#include "root/rmem.h"
-
-#include "mars.h"
-#include "statement.h"
-#include "expression.h"
-#include "cond.h"
-#include "init.h"
-#include "staticassert.h"
-#include "mtype.h"
-#include "scope.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "id.h"
-#include "utf.h"
-#include "attrib.h" // for AttribDeclaration
-
-#include "template.h"
-#include "ctfe.h"
-
-/* Interpreter: what form of return value expression is required?
- */
-enum CtfeGoal
-{
- ctfeNeedRvalue, // Must return an Rvalue (== CTFE value)
- ctfeNeedLvalue, // Must return an Lvalue (== CTFE reference)
- ctfeNeedNothing // The return value is not required
-};
-
-bool walkPostorder(Expression *e, StoppableVisitor *v);
-Expression *interpret(Statement *s, InterState *istate);
-Expression *interpret(Expression *e, InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
-
-static Expression *interpret(UnionExp *pue, Expression *e, InterState *istate, CtfeGoal goal = ctfeNeedRvalue);
-static Expression *interpret(UnionExp *pue, Statement *s, InterState *istate);
-
-#define SHOWPERFORMANCE 0
-
-// Maximum allowable recursive function calls in CTFE
-#define CTFE_RECURSION_LIMIT 1000
-
-/**
- The values of all CTFE variables
-*/
-struct CtfeStack
-{
-private:
- /* The stack. Every declaration we encounter is pushed here,
- together with the VarDeclaration, and the previous
- stack address of that variable, so that we can restore it
- when we leave the stack frame.
- Note that when a function is forward referenced, the interpreter must
- run semantic3, and that may start CTFE again with a NULL istate. Thus
- the stack might not be empty when CTFE begins.
-
- Ctfe Stack addresses are just 0-based integers, but we save
- them as 'void *' because Array can only do pointers.
- */
- Expressions values; // values on the stack
- VarDeclarations vars; // corresponding variables
- Array<void *> savedId; // id of the previous state of that var
-
- Array<void *> frames; // all previous frame pointers
- Expressions savedThis; // all previous values of localThis
-
- /* Global constants get saved here after evaluation, so we never
- * have to redo them. This saves a lot of time and memory.
- */
- Expressions globalValues; // values of global constants
-
- size_t framepointer; // current frame pointer
- size_t maxStackPointer; // most stack we've ever used
- Expression *localThis; // value of 'this', or NULL if none
-public:
- CtfeStack();
-
- size_t stackPointer();
-
- // The current value of 'this', or NULL if none
- Expression *getThis();
-
- // Largest number of stack positions we've used
- size_t maxStackUsage();
- // Start a new stack frame, using the provided 'this'.
- void startFrame(Expression *thisexp);
- void endFrame();
- bool isInCurrentFrame(VarDeclaration *v);
- Expression *getValue(VarDeclaration *v);
- void setValue(VarDeclaration *v, Expression *e);
- void push(VarDeclaration *v);
- void pop(VarDeclaration *v);
- void popAll(size_t stackpointer);
- void saveGlobalConstant(VarDeclaration *v, Expression *e);
-};
-
-struct InterState
-{
- InterState *caller; // calling function's InterState
- FuncDeclaration *fd; // function being interpreted
- Statement *start; // if !=NULL, start execution at this statement
- /* target of CTFEExp result; also
- * target of labelled CTFEExp or
- * CTFEExp. (NULL if no label).
- */
- Statement *gotoTarget;
-
- InterState();
-};
-
-/************** CtfeStack ********************************************/
-
-CtfeStack ctfeStack;
-
-CtfeStack::CtfeStack() : framepointer(0), maxStackPointer(0)
-{
-}
-
-size_t CtfeStack::stackPointer()
-{
- return values.length;
-}
-
-Expression *CtfeStack::getThis()
-{
- return localThis;
-}
-
-// Largest number of stack positions we've used
-size_t CtfeStack::maxStackUsage()
-{
- return maxStackPointer;
-}
-
-void CtfeStack::startFrame(Expression *thisexp)
-{
- frames.push((void *)(size_t)(framepointer));
- savedThis.push(localThis);
- framepointer = stackPointer();
- localThis = thisexp;
-}
-
-void CtfeStack::endFrame()
-{
- size_t oldframe = (size_t)(frames[frames.length-1]);
- localThis = savedThis[savedThis.length-1];
- popAll(framepointer);
- framepointer = oldframe;
- frames.setDim(frames.length - 1);
- savedThis.setDim(savedThis.length -1);
-}
-
-bool CtfeStack::isInCurrentFrame(VarDeclaration *v)
-{
- if (v->isDataseg() && !v->isCTFE())
- return false; // It's a global
- return v->ctfeAdrOnStack >= (int)framepointer;
-}
-
-Expression *CtfeStack::getValue(VarDeclaration *v)
-{
- if ((v->isDataseg() || v->storage_class & STCmanifest) && !v->isCTFE())
- {
- assert(v->ctfeAdrOnStack >= 0 &&
- v->ctfeAdrOnStack < (int)globalValues.length);
- return globalValues[v->ctfeAdrOnStack];
- }
- assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < (int)stackPointer());
- return values[v->ctfeAdrOnStack];
-}
-
-void CtfeStack::setValue(VarDeclaration *v, Expression *e)
-{
- assert(!v->isDataseg() || v->isCTFE());
- assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < (int)stackPointer());
- values[v->ctfeAdrOnStack] = e;
-}
-
-void CtfeStack::push(VarDeclaration *v)
-{
- assert(!v->isDataseg() || v->isCTFE());
- if (v->ctfeAdrOnStack != -1 &&
- v->ctfeAdrOnStack >= (int)framepointer)
- {
- // Already exists in this frame, reuse it.
- values[v->ctfeAdrOnStack] = NULL;
- return;
- }
- savedId.push((void *)(size_t)(v->ctfeAdrOnStack));
- v->ctfeAdrOnStack = (int)values.length;
- vars.push(v);
- values.push(NULL);
-}
-
-void CtfeStack::pop(VarDeclaration *v)
-{
- assert(!v->isDataseg() || v->isCTFE());
- assert(!(v->storage_class & (STCref | STCout)));
- int oldid = v->ctfeAdrOnStack;
- v->ctfeAdrOnStack = (int)(size_t)(savedId[oldid]);
- if (v->ctfeAdrOnStack == (int)values.length - 1)
- {
- values.pop();
- vars.pop();
- savedId.pop();
- }
-}
-
-void CtfeStack::popAll(size_t stackpointer)
-{
- if (stackPointer() > maxStackPointer)
- maxStackPointer = stackPointer();
- assert(values.length >= stackpointer);
- for (size_t i = stackpointer; i < values.length; ++i)
- {
- VarDeclaration *v = vars[i];
- v->ctfeAdrOnStack = (int)(size_t)(savedId[i]);
- }
- values.setDim(stackpointer);
- vars.setDim(stackpointer);
- savedId.setDim(stackpointer);
-}
-
-void CtfeStack::saveGlobalConstant(VarDeclaration *v, Expression *e)
-{
- assert(v->_init && (v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) && !v->isCTFE());
- v->ctfeAdrOnStack = (int)globalValues.length;
- globalValues.push(e);
-}
-
-/************** InterState ********************************************/
-
-InterState::InterState()
-{
- memset(this, 0, sizeof(InterState));
-}
-
-/************** CtfeStatus ********************************************/
-
-int CtfeStatus::callDepth = 0;
-int CtfeStatus::stackTraceCallsToSuppress = 0;
-int CtfeStatus::maxCallDepth = 0;
-int CtfeStatus::numArrayAllocs = 0;
-int CtfeStatus::numAssignments = 0;
-
-// CTFE diagnostic information
-void printCtfePerformanceStats()
-{
-#if SHOWPERFORMANCE
- printf(" ---- CTFE Performance ----\n");
- printf("max call depth = %d\tmax stack = %d\n", CtfeStatus::maxCallDepth, ctfeStack.maxStackUsage());
- printf("array allocs = %d\tassignments = %d\n\n", CtfeStatus::numArrayAllocs, CtfeStatus::numAssignments);
-#endif
-}
-
-static Expression *evaluateIfBuiltin(UnionExp *pue, InterState *istate, Loc loc,
- FuncDeclaration *fd, Expressions *arguments, Expression *pthis);
-static Expression *evaluatePostblit(InterState *istate, Expression *e);
-static Expression *evaluateDtor(InterState *istate, Expression *e);
-
-static bool isEntirelyVoid(Expressions* elems);
-static Expression *scrubArray(Loc loc, Expressions *elems, bool structlit = false);
-static Expression *scrubStructLiteral(Loc loc, StructLiteralExp *sle);
-static Expression *scrubReturnValue(Loc loc, Expression *e);
-static Expression *scrubArrayCache(Expressions *elems);
-static Expression *scrubStructLiteralCache(StructLiteralExp *sle);
-static Expression *scrubCacheValue(Expression *e);
-
-
-/*************************************
- * CTFE-object code for a single function
- *
- * Currently only counts the number of local variables in the function
- */
-struct CompiledCtfeFunction
-{
- FuncDeclaration *func; // Function being compiled, NULL if global scope
- int numVars; // Number of variables declared in this function
- Loc callingloc;
-
- CompiledCtfeFunction(FuncDeclaration *f)
- {
- func = f;
- numVars = 0;
- }
-
- void onDeclaration(VarDeclaration *)
- {
- //printf("%s CTFE declare %s\n", v->loc.toChars(), v->toChars());
- ++numVars;
- }
-
- void onExpression(Expression *e)
- {
- class VarWalker : public StoppableVisitor
- {
- public:
- CompiledCtfeFunction *ccf;
-
- VarWalker(CompiledCtfeFunction *ccf)
- : ccf(ccf)
- {
- }
-
- void visit(Expression *)
- {
- }
-
- void visit(ErrorExp *e)
- {
- // Currently there's a front-end bug: silent errors
- // can occur inside delegate literals inside is(typeof()).
- // Suppress the check in this case.
- if (global.gag && ccf->func)
- {
- stop = 1;
- return;
- }
-
- ::error(e->loc, "CTFE internal error: ErrorExp in %s\n", ccf->func ? ccf->func->loc.toChars() : ccf->callingloc.toChars());
- assert(0);
- }
-
- void visit(DeclarationExp *e)
- {
- VarDeclaration *v = e->declaration->isVarDeclaration();
- if (!v)
- return;
- TupleDeclaration *td = v->toAlias()->isTupleDeclaration();
- if (td)
- {
- if (!td->objects)
- return;
- for (size_t i= 0; i < td->objects->length; ++i)
- {
- RootObject *o = td->objects->tdata()[i];
- Expression *ex = isExpression(o);
- DsymbolExp *s = (ex && ex->op == TOKdsymbol) ? (DsymbolExp *)ex : NULL;
- assert(s);
- VarDeclaration *v2 = s->s->isVarDeclaration();
- assert(v2);
- if (!v2->isDataseg() || v2->isCTFE())
- ccf->onDeclaration(v2);
- }
- }
- else if (!(v->isDataseg() || v->storage_class & STCmanifest) || v->isCTFE())
- ccf->onDeclaration(v);
- Dsymbol *s = v->toAlias();
- if (s == v && !v->isStatic() && v->_init)
- {
- ExpInitializer *ie = v->_init->isExpInitializer();
- if (ie)
- ccf->onExpression(ie->exp);
- }
- }
-
- void visit(IndexExp *e)
- {
- if (e->lengthVar)
- ccf->onDeclaration(e->lengthVar);
- }
-
- void visit(SliceExp *e)
- {
- if (e->lengthVar)
- ccf->onDeclaration(e->lengthVar);
- }
- };
-
- VarWalker v(this);
- walkPostorder(e, &v);
- }
-};
-
-class CtfeCompiler : public Visitor
-{
-public:
- CompiledCtfeFunction *ccf;
-
- CtfeCompiler(CompiledCtfeFunction *ccf)
- : ccf(ccf)
- {
- }
-
- void visit(Statement *)
- {
- assert(0);
- }
-
- void visit(ExpStatement *s)
- {
- if (s->exp)
- ccf->onExpression(s->exp);
- }
-
- void visit(CompoundStatement *s)
- {
- for (size_t i = 0; i < s->statements->length; i++)
- {
- Statement *sx = (*s->statements)[i];
- if (sx)
- ctfeCompile(sx);
- }
- }
-
- void visit(UnrolledLoopStatement *s)
- {
- for (size_t i = 0; i < s->statements->length; i++)
- {
- Statement *sx = (*s->statements)[i];
- if (sx)
- ctfeCompile(sx);
- }
- }
-
- void visit(IfStatement *s)
- {
- ccf->onExpression(s->condition);
- if (s->ifbody)
- ctfeCompile(s->ifbody);
- if (s->elsebody)
- ctfeCompile(s->elsebody);
- }
-
- void visit(ScopeStatement *s)
- {
- if (s->statement)
- ctfeCompile(s->statement);
- }
-
- void visit(ScopeGuardStatement *)
- {
- // rewritten to try/catch/finally
- assert(0);
- }
-
- void visit(DoStatement *s)
- {
- ccf->onExpression(s->condition);
- if (s->_body)
- ctfeCompile(s->_body);
- }
-
- void visit(WhileStatement *)
- {
- // rewritten to ForStatement
- assert(0);
- }
-
- void visit(ForStatement *s)
- {
- if (s->_init)
- ctfeCompile(s->_init);
- if (s->condition)
- ccf->onExpression(s->condition);
- if (s->increment)
- ccf->onExpression(s->increment);
- if (s->_body)
- ctfeCompile(s->_body);
- }
-
- void visit(ForeachStatement *)
- {
- // rewritten for ForStatement
- assert(0);
- }
-
- void visit(SwitchStatement *s)
- {
- ccf->onExpression(s->condition);
- // Note that the body contains the the Case and Default
- // statements, so we only need to compile the expressions
- for (size_t i = 0; i < s->cases->length; i++)
- {
- ccf->onExpression((*s->cases)[i]->exp);
- }
- if (s->_body)
- ctfeCompile(s->_body);
- }
-
- void visit(CaseStatement *s)
- {
- if (s->statement)
- ctfeCompile(s->statement);
- }
-
- void visit(DefaultStatement *s)
- {
- if (s->statement)
- ctfeCompile(s->statement);
- }
-
- void visit(GotoDefaultStatement *)
- {
- }
-
- void visit(GotoCaseStatement *)
- {
- }
-
- void visit(SwitchErrorStatement *)
- {
- }
-
- void visit(ReturnStatement *s)
- {
- if (s->exp)
- ccf->onExpression(s->exp);
- }
-
- void visit(BreakStatement *)
- {
- }
-
- void visit(ContinueStatement *)
- {
- }
-
- void visit(WithStatement *s)
- {
- // If it is with(Enum) {...}, just execute the body.
- if (s->exp->op == TOKscope || s->exp->op == TOKtype)
- {
- }
- else
- {
- ccf->onDeclaration(s->wthis);
- ccf->onExpression(s->exp);
- }
- if (s->_body)
- ctfeCompile(s->_body);
- }
-
- void visit(TryCatchStatement *s)
- {
- if (s->_body)
- ctfeCompile(s->_body);
- for (size_t i = 0; i < s->catches->length; i++)
- {
- Catch *ca = (*s->catches)[i];
- if (ca->var)
- ccf->onDeclaration(ca->var);
- if (ca->handler)
- ctfeCompile(ca->handler);
- }
- }
-
- void visit(TryFinallyStatement *s)
- {
- if (s->_body)
- ctfeCompile(s->_body);
- if (s->finalbody)
- ctfeCompile(s->finalbody);
- }
-
- void visit(ThrowStatement *s)
- {
- ccf->onExpression(s->exp);
- }
-
- void visit(GotoStatement *)
- {
- }
-
- void visit(LabelStatement *s)
- {
- if (s->statement)
- ctfeCompile(s->statement);
- }
-
- void visit(ImportStatement *)
- {
- // Contains no variables or executable code
- }
-
- void visit(ForeachRangeStatement *)
- {
- // rewritten for ForStatement
- assert(0);
- }
-
- void visit(AsmStatement *)
- {
- // we can't compile asm statements
- }
-
- void ctfeCompile(Statement *s)
- {
- s->accept(this);
- }
-};
-
-/*************************************
- * Compile this function for CTFE.
- * At present, this merely allocates variables.
- */
-void ctfeCompile(FuncDeclaration *fd)
-{
- assert(!fd->ctfeCode);
- assert(!fd->semantic3Errors);
- assert(fd->semanticRun == PASSsemantic3done);
-
- fd->ctfeCode = new CompiledCtfeFunction(fd);
- if (fd->parameters)
- {
- Type *tb = fd->type->toBasetype();
- assert(tb->ty == Tfunction);
- for (size_t i = 0; i < fd->parameters->length; i++)
- {
- VarDeclaration *v = (*fd->parameters)[i];
- fd->ctfeCode->onDeclaration(v);
- }
- }
- if (fd->vresult)
- fd->ctfeCode->onDeclaration(fd->vresult);
- CtfeCompiler v(fd->ctfeCode);
- v.ctfeCompile(fd->fbody);
-}
-
-/*************************************
- * Entry point for CTFE.
- * A compile-time result is required. Give an error if not possible.
- *
- * `e` must be semantically valid expression. In other words, it should not
- * contain any `ErrorExp`s in it. But, CTFE interpretation will cross over
- * functions and may invoke a function that contains `ErrorStatement` in its body.
- * If that, the "CTFE failed because of previous errors" error is raised.
- */
-Expression *ctfeInterpret(Expression *e)
-{
- switch (e->op)
- {
- case TOKint64:
- case TOKfloat64:
- case TOKcomplex80:
- case TOKnull:
- case TOKvoid:
- case TOKstring:
- case TOKthis:
- case TOKsuper:
- case TOKtype:
- case TOKtypeid:
- case TOKtemplate: // non-eponymous template/instance
- case TOKscope: // ditto
- case TOKdottd: // ditto, e.e1 doesn't matter here
- case TOKdot: // ditto
- if (e->type->ty == Terror)
- return new ErrorExp();
- /* fall through */
-
- case TOKerror:
- return e;
-
- default:
- break;
- }
-
- assert(e->type); // Bugzilla 14642
- //assert(e->type->ty != Terror); // FIXME
- if (e->type->ty == Terror)
- return new ErrorExp();
-
- // This code is outside a function, but still needs to be compiled
- // (there are compiler-generated temporary variables such as __dollar).
- // However, this will only be run once and can then be discarded.
- CompiledCtfeFunction ctfeCodeGlobal(NULL);
- ctfeCodeGlobal.callingloc = e->loc;
- ctfeCodeGlobal.onExpression(e);
-
- Expression *result = interpret(e, NULL);
- if (!CTFEExp::isCantExp(result))
- result = scrubReturnValue(e->loc, result);
- if (CTFEExp::isCantExp(result))
- result = new ErrorExp();
- return result;
-}
-
-/* Run CTFE on the expression, but allow the expression to be a TypeExp
- * or a tuple containing a TypeExp. (This is required by pragma(msg)).
- */
-Expression *ctfeInterpretForPragmaMsg(Expression *e)
-{
- if (e->op == TOKerror || e->op == TOKtype)
- return e;
-
- // It's also OK for it to be a function declaration (happens only with
- // __traits(getOverloads))
- if (e->op == TOKvar && ((VarExp *)e)->var->isFuncDeclaration())
- {
- return e;
- }
-
- if (e->op != TOKtuple)
- return e->ctfeInterpret();
-
- // Tuples need to be treated seperately, since they are
- // allowed to contain a TypeExp in this case.
-
- TupleExp *tup = (TupleExp *)e;
- Expressions *expsx = NULL;
- for (size_t i = 0; i < tup->exps->length; ++i)
- {
- Expression *g = (*tup->exps)[i];
- Expression *h = g;
- h = ctfeInterpretForPragmaMsg(g);
- if (h != g)
- {
- if (!expsx)
- {
- expsx = new Expressions();
- expsx->setDim(tup->exps->length);
- for (size_t j = 0; j < tup->exps->length; j++)
- (*expsx)[j] = (*tup->exps)[j];
- }
- (*expsx)[i] = h;
- }
- }
- if (expsx)
- {
- TupleExp *te = new TupleExp(e->loc, expsx);
- expandTuples(te->exps);
- te->type = new TypeTuple(te->exps);
- return te;
- }
- return e;
-}
-
-/*************************************
- * Attempt to interpret a function given the arguments.
- * Input:
- * pue storage for result
- * fd function being called
- * istate state for calling function (NULL if none)
- * arguments function arguments
- * thisarg 'this', if a needThis() function, NULL if not.
- *
- * Return result expression if successful, TOKcantexp if not,
- * or CTFEExp if function returned void.
- */
-
-static Expression *interpretFunction(UnionExp *pue, FuncDeclaration *fd, InterState *istate, Expressions *arguments, Expression *thisarg)
-{
- assert(pue);
- if (fd->semanticRun == PASSsemantic3)
- {
- fd->error("circular dependency. Functions cannot be interpreted while being compiled");
- return CTFEExp::cantexp;
- }
- if (!fd->functionSemantic3())
- return CTFEExp::cantexp;
- if (fd->semanticRun < PASSsemantic3done)
- return CTFEExp::cantexp;
-
- // CTFE-compile the function
- if (!fd->ctfeCode)
- ctfeCompile(fd);
-
- Type *tb = fd->type->toBasetype();
- assert(tb->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)tb;
- if (tf->parameterList.varargs != VARARGnone && arguments &&
- ((fd->parameters && arguments->length != fd->parameters->length) || (!fd->parameters && arguments->length)))
- {
- fd->error("C-style variadic functions are not yet implemented in CTFE");
- return CTFEExp::cantexp;
- }
-
- // Nested functions always inherit the 'this' pointer from the parent,
- // except for delegates. (Note that the 'this' pointer may be null).
- // Func literals report isNested() even if they are in global scope,
- // so we need to check that the parent is a function.
- if (fd->isNested() && fd->toParent2()->isFuncDeclaration() && !thisarg && istate)
- thisarg = ctfeStack.getThis();
-
- if (fd->needThis() && !thisarg)
- {
- // error, no this. Prevent segfault.
- // Here should be unreachable by the strict 'this' check in front-end.
- fd->error("need `this` to access member %s", fd->toChars());
- return CTFEExp::cantexp;
- }
-
- // Place to hold all the arguments to the function while
- // we are evaluating them.
- Expressions eargs;
- size_t dim = arguments ? arguments->length : 0;
- assert((fd->parameters ? fd->parameters->length : 0) == dim);
-
- /* Evaluate all the arguments to the function,
- * store the results in eargs[]
- */
- eargs.setDim(dim);
- for (size_t i = 0; i < dim; i++)
- {
- Expression *earg = (*arguments)[i];
- Parameter *fparam = tf->parameterList[i];
-
- if (fparam->storageClass & (STCout | STCref))
- {
- if (!istate && (fparam->storageClass & STCout))
- {
- // initializing an out parameter involves writing to it.
- earg->error("global %s cannot be passed as an `out` parameter at compile time", earg->toChars());
- return CTFEExp::cantexp;
- }
- // Convert all reference arguments into lvalue references
- earg = interpret(earg, istate, ctfeNeedLvalue);
- if (CTFEExp::isCantExp(earg))
- return earg;
- }
- else if (fparam->storageClass & STClazy)
- {
- }
- else
- {
- /* Value parameters
- */
- Type *ta = fparam->type->toBasetype();
- if (ta->ty == Tsarray && earg->op == TOKaddress)
- {
- /* Static arrays are passed by a simple pointer.
- * Skip past this to get at the actual arg.
- */
- earg = ((AddrExp *)earg)->e1;
- }
- earg = interpret(earg, istate);
- if (CTFEExp::isCantExp(earg))
- return earg;
- /* Struct literals are passed by value, but we don't need to
- * copy them if they are passed as const
- */
- if (earg->op == TOKstructliteral && !(fparam->storageClass & (STCconst | STCimmutable)))
- earg = copyLiteral(earg).copy();
- }
- if (earg->op == TOKthrownexception)
- {
- if (istate)
- return earg;
- ((ThrownExceptionExp *)earg)->generateUncaughtError();
- return CTFEExp::cantexp;
- }
- eargs[i] = earg;
- }
-
- // Now that we've evaluated all the arguments, we can start the frame
- // (this is the moment when the 'call' actually takes place).
- InterState istatex;
- istatex.caller = istate;
- istatex.fd = fd;
- ctfeStack.startFrame(thisarg);
- if (fd->vthis && thisarg)
- {
- ctfeStack.push(fd->vthis);
- setValue(fd->vthis, thisarg);
- }
-
- for (size_t i = 0; i < dim; i++)
- {
- Expression *earg = eargs[i];
- Parameter *fparam = tf->parameterList[i];
- VarDeclaration *v = (*fd->parameters)[i];
- ctfeStack.push(v);
-
- if ((fparam->storageClass & (STCout | STCref)) &&
- earg->op == TOKvar && ((VarExp *)earg)->var->toParent2() == fd)
- {
- VarDeclaration *vx = ((VarExp *)earg)->var->isVarDeclaration();
- if (!vx)
- {
- fd->error("cannot interpret %s as a ref parameter", earg->toChars());
- return CTFEExp::cantexp;
- }
-
- /* vx is a variable that is declared in fd.
- * It means that fd is recursively called. e.g.
- *
- * void fd(int n, ref int v = dummy) {
- * int vx;
- * if (n == 1) fd(2, vx);
- * }
- * fd(1);
- *
- * The old value of vx on the stack in fd(1)
- * should be saved at the start of fd(2, vx) call.
- */
- int oldadr = vx->ctfeAdrOnStack;
-
- ctfeStack.push(vx);
- assert(!hasValue(vx)); // vx is made uninitialized
-
- // Bugzilla 14299: v->ctfeAdrOnStack should be saved already
- // in the stack before the overwrite.
- v->ctfeAdrOnStack = oldadr;
- assert(hasValue(v)); // ref parameter v should refer existing value.
- }
- else
- {
- // Value parameters and non-trivial references
- setValueWithoutChecking(v, earg);
- }
- }
-
- if (fd->vresult)
- ctfeStack.push(fd->vresult);
-
- // Enter the function
- ++CtfeStatus::callDepth;
- if (CtfeStatus::callDepth > CtfeStatus::maxCallDepth)
- CtfeStatus::maxCallDepth = CtfeStatus::callDepth;
-
- Expression *e = NULL;
- while (1)
- {
- if (CtfeStatus::callDepth > CTFE_RECURSION_LIMIT)
- {
- // This is a compiler error. It must not be suppressed.
- global.gag = 0;
- fd->error("CTFE recursion limit exceeded");
- e = CTFEExp::cantexp;
- break;
- }
- e = interpret(pue, fd->fbody, &istatex);
-
- if (istatex.start)
- {
- fd->error("CTFE internal error: failed to resume at statement %s", istatex.start->toChars());
- return CTFEExp::cantexp;
- }
-
- /* This is how we deal with a recursive statement AST
- * that has arbitrary goto statements in it.
- * Bubble up a 'result' which is the target of the goto
- * statement, then go recursively down the AST looking
- * for that statement, then execute starting there.
- */
- if (CTFEExp::isGotoExp(e))
- {
- istatex.start = istatex.gotoTarget; // set starting statement
- istatex.gotoTarget = NULL;
- }
- else
- {
- assert(!e || (e->op != TOKcontinue && e->op != TOKbreak));
- break;
- }
- }
- // If fell off the end of a void function, return void
- if (!e && tf->next->ty == Tvoid)
- e = CTFEExp::voidexp;
- if (tf->isref && e->op == TOKvar && ((VarExp *)e)->var == fd->vthis)
- e = thisarg;
- assert(e != NULL);
-
- // Leave the function
- --CtfeStatus::callDepth;
-
- ctfeStack.endFrame();
-
- // If it generated an uncaught exception, report error.
- if (!istate && e->op == TOKthrownexception)
- {
- if (e == pue->exp())
- e = pue->copy();
- ((ThrownExceptionExp *)e)->generateUncaughtError();
- e = CTFEExp::cantexp;
- }
-
- return e;
-}
-
-class Interpreter : public Visitor
-{
-public:
- InterState *istate;
- CtfeGoal goal;
-
- Expression *result;
- UnionExp *pue; // storage for `result`
-
- Interpreter(UnionExp *pue, InterState *istate, CtfeGoal goal)
- : istate(istate), goal(goal), pue(pue)
- {
- result = NULL;
- }
-
- // If e is TOKthrowexception or TOKcantexp,
- // set it to 'result' and returns true.
- bool exceptionOrCant(Expression *e)
- {
- if (exceptionOrCantInterpret(e))
- {
- // Make sure e is not pointing to a stack temporary
- result = (e->op == TOKcantexp) ? CTFEExp::cantexp : e;
- return true;
- }
- return false;
- }
-
- static Expressions *copyArrayOnWrite(Expressions *exps, Expressions *original)
- {
- if (exps == original)
- {
- if (!original)
- exps = new Expressions();
- else
- exps = original->copy();
- ++CtfeStatus::numArrayAllocs;
- }
- return exps;
- }
-
- /******************************** Statement ***************************/
-
- void visit(Statement *s)
- {
- if (istate->start)
- {
- if (istate->start != s)
- return;
- istate->start = NULL;
- }
-
- s->error("statement %s cannot be interpreted at compile time", s->toChars());
- result = CTFEExp::cantexp;
- }
-
- void visit(ExpStatement *s)
- {
- if (istate->start)
- {
- if (istate->start != s)
- return;
- istate->start = NULL;
- }
-
- Expression *e = interpret(pue, s->exp, istate, ctfeNeedNothing);
- if (exceptionOrCant(e))
- return;
- }
-
- void visit(CompoundStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
-
- const size_t dim = s->statements ? s->statements->length : 0;
- for (size_t i = 0; i < dim; i++)
- {
- Statement *sx = (*s->statements)[i];
- result = interpret(pue, sx, istate);
- if (result)
- break;
- }
- }
-
- void visit(UnrolledLoopStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
-
- const size_t dim = s->statements ? s->statements->length : 0;
- for (size_t i = 0; i < dim; i++)
- {
- Statement *sx = (*s->statements)[i];
- Expression *e = interpret(pue, sx, istate);
- if (!e) // suceeds to interpret, or goto target
- continue; // was not fonnd when istate->start != NULL
- if (exceptionOrCant(e))
- return;
- if (e->op == TOKbreak)
- {
- if (istate->gotoTarget && istate->gotoTarget != s)
- {
- result = e; // break at a higher level
- return;
- }
- istate->gotoTarget = NULL;
- result = NULL;
- return;
- }
- if (e->op == TOKcontinue)
- {
- if (istate->gotoTarget && istate->gotoTarget != s)
- {
- result = e; // continue at a higher level
- return;
- }
- istate->gotoTarget = NULL;
- continue;
- }
-
- // expression from return statement, or thrown exception
- result = e;
- break;
- }
- }
-
- void visit(IfStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
- if (istate->start)
- {
- Expression *e = NULL;
- e = interpret(s->ifbody, istate);
- if (!e && istate->start)
- e = interpret(s->elsebody, istate);
- result = e;
- return;
- }
-
- UnionExp ue;
- Expression *e = interpret(&ue, s->condition, istate);
- assert(e);
- if (exceptionOrCant(e))
- return;
-
- if (isTrueBool(e))
- result = interpret(pue, s->ifbody, istate);
- else if (e->isBool(false))
- result = interpret(pue, s->elsebody, istate);
- else
- {
- // no error, or assert(0)?
- result = CTFEExp::cantexp;
- }
- }
-
- void visit(ScopeStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
-
- result = interpret(pue, s->statement, istate);
- }
-
- /**
- Given an expression e which is about to be returned from the current
- function, generate an error if it contains pointers to local variables.
-
- Only checks expressions passed by value (pointers to local variables
- may already be stored in members of classes, arrays, or AAs which
- were passed as mutable function parameters).
- Returns:
- true if it is safe to return, false if an error was generated.
- */
-
- static bool stopPointersEscaping(Loc loc, Expression *e)
- {
- if (!e->type->hasPointers())
- return true;
- if (isPointer(e->type))
- {
- Expression *x = e;
- if (e->op == TOKaddress)
- x = ((AddrExp *)e)->e1;
- VarDeclaration *v;
- while (x->op == TOKvar &&
- (v = ((VarExp *)x)->var->isVarDeclaration()) != NULL)
- {
- if (v->storage_class & STCref)
- {
- x = getValue(v);
- if (e->op == TOKaddress)
- ((AddrExp *)e)->e1 = x;
- continue;
- }
- if (ctfeStack.isInCurrentFrame(v))
- {
- error(loc, "returning a pointer to a local stack variable");
- return false;
- }
- else
- break;
- }
- // TODO: If it is a TOKdotvar or TOKindex, we should check that it is not
- // pointing to a local struct or static array.
- }
- if (e->op == TOKstructliteral)
- {
- StructLiteralExp *se = (StructLiteralExp *)e;
- return stopPointersEscapingFromArray(loc, se->elements);
- }
- if (e->op == TOKarrayliteral)
- {
- return stopPointersEscapingFromArray(loc, ((ArrayLiteralExp *)e)->elements);
- }
- if (e->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
- if (!stopPointersEscapingFromArray(loc, aae->keys))
- return false;
- return stopPointersEscapingFromArray(loc, aae->values);
- }
- return true;
- }
-
- // Check all members of an array for escaping local variables. Return false if error
- static bool stopPointersEscapingFromArray(Loc loc, Expressions *elems)
- {
- for (size_t i = 0; i < elems->length; i++)
- {
- Expression *m = (*elems)[i];
- if (!m)
- continue;
- if (!stopPointersEscaping(loc, m))
- return false;
- }
- return true;
- }
-
- void visit(ReturnStatement *s)
- {
- if (istate->start)
- {
- if (istate->start != s)
- return;
- istate->start = NULL;
- }
-
- if (!s->exp)
- {
- result = CTFEExp::voidexp;
- return;
- }
-
- assert(istate && istate->fd && istate->fd->type && istate->fd->type->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)istate->fd->type;
-
- /* If the function returns a ref AND it's been called from an assignment,
- * we need to return an lvalue. Otherwise, just do an (rvalue) interpret.
- */
- if (tf->isref)
- {
- result = interpret(pue, s->exp, istate, ctfeNeedLvalue);
- return;
- }
- if (tf->next && tf->next->ty == Tdelegate && istate->fd->closureVars.length > 0)
- {
- // To support this, we need to copy all the closure vars
- // into the delegate literal.
- s->error("closures are not yet supported in CTFE");
- result = CTFEExp::cantexp;
- return;
- }
-
- // We need to treat pointers specially, because TOKsymoff can be used to
- // return a value OR a pointer
- Expression *e = interpret(pue, s->exp, istate);
- if (exceptionOrCant(e))
- return;
-
- // Disallow returning pointers to stack-allocated variables (bug 7876)
- if (!stopPointersEscaping(s->loc, e))
- {
- result = CTFEExp::cantexp;
- return;
- }
-
- if (needToCopyLiteral(e))
- e = copyLiteral(e).copy();
- result = e;
- }
-
- static Statement *findGotoTarget(InterState *istate, Identifier *ident)
- {
- Statement *target = NULL;
- if (ident)
- {
- LabelDsymbol *label = istate->fd->searchLabel(ident);
- assert(label && label->statement);
- LabelStatement *ls = label->statement;
- target = ls->gotoTarget ? ls->gotoTarget : ls->statement;
- }
- return target;
- }
-
- void visit(BreakStatement *s)
- {
- if (istate->start)
- {
- if (istate->start != s)
- return;
- istate->start = NULL;
- }
-
- istate->gotoTarget = findGotoTarget(istate, s->ident);
- result = CTFEExp::breakexp;
- }
-
- void visit(ContinueStatement *s)
- {
- if (istate->start)
- {
- if (istate->start != s)
- return;
- istate->start = NULL;
- }
-
- istate->gotoTarget = findGotoTarget(istate, s->ident);
- result = CTFEExp::continueexp;
- }
-
- void visit(WhileStatement *)
- {
- assert(0); // rewritten to ForStatement
- }
-
- void visit(DoStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
-
- while (1)
- {
- Expression *e = interpret(s->_body, istate);
- if (!e && istate->start) // goto target was not found
- return;
- assert(!istate->start);
-
- if (exceptionOrCant(e))
- return;
- if (e && e->op == TOKbreak)
- {
- if (istate->gotoTarget && istate->gotoTarget != s)
- {
- result = e; // break at a higher level
- return;
- }
- istate->gotoTarget = NULL;
- break;
- }
- if (e && e->op == TOKcontinue)
- {
- if (istate->gotoTarget && istate->gotoTarget != s)
- {
- result = e; // continue at a higher level
- return;
- }
- istate->gotoTarget = NULL;
- e = NULL;
- }
- if (e)
- {
- result = e; // bubbled up from ReturnStatement
- return;
- }
-
- UnionExp ue;
- e = interpret(&ue, s->condition, istate);
- if (exceptionOrCant(e))
- return;
- if (!e->isConst())
- {
- result = CTFEExp::cantexp;
- return;
- }
- if (e->isBool(false))
- break;
- assert(isTrueBool(e));
- }
- assert(result == NULL);
- }
-
- void visit(ForStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
-
- UnionExp ueinit;
- Expression *ei = interpret(&ueinit, s->_init, istate);
- if (exceptionOrCant(ei))
- return;
- assert(!ei); // s->init never returns from function, or jumps out from it
-
- while (1)
- {
- if (s->condition && !istate->start)
- {
- UnionExp ue;
- Expression *e = interpret(&ue, s->condition, istate);
- if (exceptionOrCant(e))
- return;
- if (e->isBool(false))
- break;
- assert(isTrueBool(e));
- }
-
- Expression *e = interpret(pue, s->_body, istate);
- if (!e && istate->start) // goto target was not found
- return;
- assert(!istate->start);
-
- if (exceptionOrCant(e))
- return;
- if (e && e->op == TOKbreak)
- {
- if (istate->gotoTarget && istate->gotoTarget != s)
- {
- result = e; // break at a higher level
- return;
- }
- istate->gotoTarget = NULL;
- break;
- }
- if (e && e->op == TOKcontinue)
- {
- if (istate->gotoTarget && istate->gotoTarget != s)
- {
- result = e; // continue at a higher level
- return;
- }
- istate->gotoTarget = NULL;
- e = NULL;
- }
- if (e)
- {
- result = e; // bubbled up from ReturnStatement
- return;
- }
-
- UnionExp uei;
- e = interpret(&uei, s->increment, istate, ctfeNeedNothing);
- if (exceptionOrCant(e))
- return;
- }
- assert(result == NULL);
- }
-
- void visit(ForeachStatement *)
- {
- assert(0); // rewritten to ForStatement
- }
-
- void visit(ForeachRangeStatement *)
- {
- assert(0); // rewritten to ForStatement
- }
-
- void visit(SwitchStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
- if (istate->start)
- {
- Expression *e = interpret(s->_body, istate);
- if (istate->start) // goto target was not found
- return;
- if (exceptionOrCant(e))
- return;
- if (e && e->op == TOKbreak)
- {
- if (istate->gotoTarget && istate->gotoTarget != s)
- {
- result = e; // break at a higher level
- return;
- }
- istate->gotoTarget = NULL;
- e = NULL;
- }
- result = e;
- return;
- }
-
- UnionExp uecond;
- Expression *econdition = interpret(&uecond, s->condition, istate);
- if (exceptionOrCant(econdition))
- return;
-
- Statement *scase = NULL;
- size_t dim = s->cases ? s->cases->length : 0;
- for (size_t i = 0; i < dim; i++)
- {
- CaseStatement *cs = (*s->cases)[i];
- UnionExp uecase;
- Expression *ecase = interpret(&uecase, cs->exp, istate);
- if (exceptionOrCant(ecase))
- return;
- if (ctfeEqual(cs->exp->loc, TOKequal, econdition, ecase))
- {
- scase = cs;
- break;
- }
- }
- if (!scase)
- {
- if (s->hasNoDefault)
- s->error("no default or case for %s in switch statement", econdition->toChars());
- scase = s->sdefault;
- }
-
- assert(scase);
-
- /* Jump to scase
- */
- istate->start = scase;
- Expression *e = interpret(pue, s->_body, istate);
- assert(!istate->start); // jump must not fail
- if (e && e->op == TOKbreak)
- {
- if (istate->gotoTarget && istate->gotoTarget != s)
- {
- result = e; // break at a higher level
- return;
- }
- istate->gotoTarget = NULL;
- e = NULL;
- }
- result = e;
- }
-
- void visit(CaseStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
-
- result = interpret(pue, s->statement, istate);
- }
-
- void visit(DefaultStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
-
- result = interpret(pue, s->statement, istate);
- }
-
- void visit(GotoStatement *s)
- {
- if (istate->start)
- {
- if (istate->start != s)
- return;
- istate->start = NULL;
- }
-
- assert(s->label && s->label->statement);
- istate->gotoTarget = s->label->statement;
- result = CTFEExp::gotoexp;
- }
-
- void visit(GotoCaseStatement *s)
- {
- if (istate->start)
- {
- if (istate->start != s)
- return;
- istate->start = NULL;
- }
-
- assert(s->cs);
- istate->gotoTarget = s->cs;
- result = CTFEExp::gotoexp;
- }
-
- void visit(GotoDefaultStatement *s)
- {
- if (istate->start)
- {
- if (istate->start != s)
- return;
- istate->start = NULL;
- }
-
- assert(s->sw && s->sw->sdefault);
- istate->gotoTarget = s->sw->sdefault;
- result = CTFEExp::gotoexp;
- }
-
- void visit(LabelStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
-
- result = interpret(pue, s->statement, istate);
- }
-
- void visit(TryCatchStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
- if (istate->start)
- {
- Expression *e = NULL;
- e = interpret(pue, s->_body, istate);
- for (size_t i = 0; i < s->catches->length; i++)
- {
- if (e || !istate->start) // goto target was found
- break;
- Catch *ca = (*s->catches)[i];
- e = interpret(ca->handler, istate);
- }
- result = e;
- return;
- }
-
- Expression *e = interpret(pue, s->_body, istate);
-
- // An exception was thrown
- if (e && e->op == TOKthrownexception)
- {
- ThrownExceptionExp *ex = (ThrownExceptionExp *)e;
- Type *extype = ex->thrown->originalClass()->type;
-
- // Search for an appropriate catch clause.
- for (size_t i = 0; i < s->catches->length; i++)
- {
- Catch *ca = (*s->catches)[i];
- Type *catype = ca->type;
- if (!catype->equals(extype) && !catype->isBaseOf(extype, NULL))
- continue;
-
- // Execute the handler
- if (ca->var)
- {
- ctfeStack.push(ca->var);
- setValue(ca->var, ex->thrown);
- }
- e = interpret(ca->handler, istate);
- if (CTFEExp::isGotoExp(e))
- {
- /* This is an optimization that relies on the locality of the jump target.
- * If the label is in the same catch handler, the following scan
- * would find it quickly and can reduce jump cost.
- * Otherwise, the catch block may be unnnecessary scanned again
- * so it would make CTFE speed slower.
- */
- InterState istatex = *istate;
- istatex.start = istate->gotoTarget; // set starting statement
- istatex.gotoTarget = NULL;
- Expression *eh = interpret(ca->handler, &istatex);
- if (!istatex.start)
- {
- istate->gotoTarget = NULL;
- e = eh;
- }
- }
- break;
- }
- }
- result = e;
- }
-
- static bool isAnErrorException(ClassDeclaration *cd)
- {
- return cd == ClassDeclaration::errorException || ClassDeclaration::errorException->isBaseOf(cd, NULL);
- }
-
- static ThrownExceptionExp *chainExceptions(ThrownExceptionExp *oldest, ThrownExceptionExp *newest)
- {
- // Little sanity check to make sure it's really a Throwable
- ClassReferenceExp *boss = oldest->thrown;
- const int next = 4; // index of Throwable.next
- assert((*boss->value->elements)[next]->type->ty == Tclass); // Throwable.next
- ClassReferenceExp *collateral = newest->thrown;
- if ( isAnErrorException(collateral->originalClass()) &&
- !isAnErrorException(boss->originalClass()))
- {
- /* Find the index of the Error.bypassException field
- */
- int bypass = next + 1;
- if ((*collateral->value->elements)[bypass]->type->ty == Tuns32)
- bypass += 1; // skip over _refcount field
- assert((*collateral->value->elements)[bypass]->type->ty == Tclass);
-
- // The new exception bypass the existing chain
- (*collateral->value->elements)[bypass] = boss;
- return newest;
- }
- while ((*boss->value->elements)[next]->op == TOKclassreference)
- {
- boss = (ClassReferenceExp *)(*boss->value->elements)[next];
- }
- (*boss->value->elements)[next] = collateral;
- return oldest;
- }
-
- void visit(TryFinallyStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
- if (istate->start)
- {
- Expression *e = NULL;
- e = interpret(pue, s->_body, istate);
- // Jump into/out from finalbody is disabled in semantic analysis.
- // and jump inside will be handled by the ScopeStatement == finalbody.
- result = e;
- return;
- }
-
- Expression *ex = interpret(s->_body, istate);
- if (CTFEExp::isCantExp(ex))
- {
- result = ex;
- return;
- }
- while (CTFEExp::isGotoExp(ex))
- {
- // If the goto target is within the body, we must not interpret the finally statement,
- // because that will call destructors for objects within the scope, which we should not do.
- InterState istatex = *istate;
- istatex.start = istate->gotoTarget; // set starting statement
- istatex.gotoTarget = NULL;
- Expression *bex = interpret(s->_body, &istatex);
- if (istatex.start)
- {
- // The goto target is outside the current scope.
- break;
- }
- // The goto target was within the body.
- if (CTFEExp::isCantExp(bex))
- {
- result = bex;
- return;
- }
- *istate = istatex;
- ex = bex;
- }
- Expression *ey = interpret(s->finalbody, istate);
- if (CTFEExp::isCantExp(ey))
- {
- result = ey;
- return;
- }
- if (ey && ey->op == TOKthrownexception)
- {
- // Check for collided exceptions
- if (ex && ex->op == TOKthrownexception)
- ex = chainExceptions((ThrownExceptionExp *)ex, (ThrownExceptionExp *)ey);
- else
- ex = ey;
- }
- result = ex;
- }
-
- void visit(ThrowStatement *s)
- {
- if (istate->start)
- {
- if (istate->start != s)
- return;
- istate->start = NULL;
- }
-
- Expression *e = interpret(s->exp, istate);
- if (exceptionOrCant(e))
- return;
-
- assert(e->op == TOKclassreference);
- result = new ThrownExceptionExp(s->loc, (ClassReferenceExp *)e);
- }
-
- void visit(ScopeGuardStatement *)
- {
- assert(0);
- }
-
- void visit(WithStatement *s)
- {
- if (istate->start == s)
- istate->start = NULL;
- if (istate->start)
- {
- result = s->_body ? interpret(s->_body, istate) : NULL;
- return;
- }
-
- // If it is with(Enum) {...}, just execute the body.
- if (s->exp->op == TOKscope || s->exp->op == TOKtype)
- {
- result = interpret(pue, s->_body, istate);
- return;
- }
-
- Expression *e = interpret(s->exp, istate);
- if (exceptionOrCant(e))
- return;
-
- if (s->wthis->type->ty == Tpointer && s->exp->type->ty != Tpointer)
- {
- e = new AddrExp(s->loc, e, s->wthis->type);
- }
- ctfeStack.push(s->wthis);
- setValue(s->wthis, e);
- e = interpret(s->_body, istate);
- if (CTFEExp::isGotoExp(e))
- {
- /* This is an optimization that relies on the locality of the jump target.
- * If the label is in the same WithStatement, the following scan
- * would find it quickly and can reduce jump cost.
- * Otherwise, the statement body may be unnnecessary scanned again
- * so it would make CTFE speed slower.
- */
- InterState istatex = *istate;
- istatex.start = istate->gotoTarget; // set starting statement
- istatex.gotoTarget = NULL;
- Expression *ex = interpret(s->_body, &istatex);
- if (!istatex.start)
- {
- istate->gotoTarget = NULL;
- e = ex;
- }
- }
- ctfeStack.pop(s->wthis);
- result = e;
- }
-
- void visit(AsmStatement *s)
- {
- if (istate->start)
- {
- if (istate->start != s)
- return;
- istate->start = NULL;
- }
-
- s->error("asm statements cannot be interpreted at compile time");
- result = CTFEExp::cantexp;
- }
-
- void visit(ImportStatement *s)
- {
- if (istate->start)
- {
- if (istate->start != s)
- return;
- istate->start = NULL;
- }
- }
-
- /******************************** Expression ***************************/
-
- void visit(Expression *e)
- {
- e->error("cannot interpret %s at compile time", e->toChars());
- result = CTFEExp::cantexp;
- }
-
- void visit(ThisExp *e)
- {
- if (goal == ctfeNeedLvalue)
- {
- // We might end up here with istate being zero (see bugzilla 16382)
- if (istate && istate->fd->vthis)
- {
- result = new VarExp(e->loc, istate->fd->vthis);
- result->type = e->type;
- }
- else
- result = e;
- return;
- }
-
- result = ctfeStack.getThis();
- if (result)
- {
- assert(result->op == TOKstructliteral ||
- result->op == TOKclassreference);
- return;
- }
- e->error("value of `this` is not known at compile time");
- result = CTFEExp::cantexp;
- }
-
- void visit(NullExp *e)
- {
- result = e;
- }
-
- void visit(IntegerExp *e)
- {
- result = e;
- }
-
- void visit(RealExp *e)
- {
- result = e;
- }
-
- void visit(ComplexExp *e)
- {
- result = e;
- }
-
- void visit(StringExp *e)
- {
- /* Attempts to modify string literals are prevented
- * in BinExp::interpretAssignCommon.
- */
- result = e;
- }
-
- void visit(FuncExp *e)
- {
- result = e;
- }
-
- void visit(SymOffExp *e)
- {
- if (e->var->isFuncDeclaration() && e->offset == 0)
- {
- result = e;
- return;
- }
- if (isTypeInfo_Class(e->type) && e->offset == 0)
- {
- result = e;
- return;
- }
- if (e->type->ty != Tpointer)
- {
- // Probably impossible
- e->error("cannot interpret %s at compile time", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- Type *pointee = ((TypePointer *)e->type)->next;
- if (e->var->isThreadlocal())
- {
- e->error("cannot take address of thread-local variable %s at compile time", e->var->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- // Check for taking an address of a shared variable.
- // If the shared variable is an array, the offset might not be zero.
- Type *fromType = NULL;
- if (e->var->type->ty == Tarray || e->var->type->ty == Tsarray)
- {
- fromType = ((TypeArray *)(e->var->type))->next;
- }
- if (e->var->isDataseg() &&
- ((e->offset == 0 && isSafePointerCast(e->var->type, pointee)) ||
- (fromType && isSafePointerCast(fromType, pointee))))
- {
- result = e;
- return;
- }
- Expression *val = getVarExp(e->loc, istate, e->var, goal);
- if (exceptionOrCant(val))
- return;
- if (val->type->ty == Tarray || val->type->ty == Tsarray)
- {
- // Check for unsupported type painting operations
- Type *elemtype = ((TypeArray *)(val->type))->next;
- d_uns64 elemsize = elemtype->size();
-
- // It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*.
- if (val->type->ty == Tsarray && pointee->ty == Tsarray &&
- elemsize == pointee->nextOf()->size())
- {
- size_t d = (size_t)((TypeSArray *)pointee)->dim->toInteger();
- Expression *elwr = new IntegerExp(e->loc, e->offset / elemsize, Type::tsize_t);
- Expression *eupr = new IntegerExp(e->loc, e->offset / elemsize + d, Type::tsize_t);
-
- // Create a CTFE pointer &val[ofs..ofs+d]
- SliceExp *se = new SliceExp(e->loc, val, elwr, eupr);
- se->type = pointee;
- new(pue) AddrExp(e->loc, se, e->type);
- result = pue->exp();
- return;
- }
-
- if (!isSafePointerCast(elemtype, pointee))
- {
- // It's also OK to cast from &string to string*.
- if (e->offset == 0 && isSafePointerCast(e->var->type, pointee))
- {
- // Create a CTFE pointer &var
- VarExp *ve = new VarExp(e->loc, e->var);
- ve->type = elemtype;
- new(pue) AddrExp(e->loc, ve, e->type);
- result = pue->exp();
- return;
- }
- e->error("reinterpreting cast from %s to %s is not supported in CTFE",
- val->type->toChars(), e->type->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- const dinteger_t sz = pointee->size();
- dinteger_t indx = e->offset / sz;
- assert(sz * indx == e->offset);
- Expression *aggregate = NULL;
- if (val->op == TOKarrayliteral || val->op == TOKstring)
- {
- aggregate = val;
- }
- else if (val->op == TOKslice)
- {
- aggregate = ((SliceExp *)val)->e1;
- UnionExp uelwr;
- Expression *lwr = interpret(&uelwr, ((SliceExp *)val)->lwr, istate);
- indx += lwr->toInteger();
- }
- if (aggregate)
- {
- // Create a CTFE pointer &aggregate[ofs]
- IntegerExp *ofs = new IntegerExp(e->loc, indx, Type::tsize_t);
- IndexExp *ei = new IndexExp(e->loc, aggregate, ofs);
- ei->type = elemtype;
- new(pue) AddrExp(e->loc, ei, e->type);
- result = pue->exp();
- return;
- }
- }
- else if (e->offset == 0 && isSafePointerCast(e->var->type, pointee))
- {
- // Create a CTFE pointer &var
- VarExp *ve = new VarExp(e->loc, e->var);
- ve->type = e->var->type;
- new(pue) AddrExp(e->loc, ve, e->type);
- result = pue->exp();
- return;
- }
-
- e->error("cannot convert &%s to %s at compile time", e->var->type->toChars(), e->type->toChars());
- result = CTFEExp::cantexp;
- }
-
- void visit(AddrExp *e)
- {
- if (e->e1->op == TOKvar && ((VarExp *)e->e1)->var->isDataseg())
- {
- // Normally this is already done by optimize()
- // Do it here in case optimize(WANTvalue) wasn't run before CTFE
- new(pue) SymOffExp(e->loc, ((VarExp *)e->e1)->var, 0);
- result = pue->exp();
- result->type = e->type;
- return;
- }
- Expression *er = interpret(e->e1, istate, ctfeNeedLvalue);
- if (er->op == TOKvar && ((VarExp *)er)->var == istate->fd->vthis)
- er = interpret(er, istate);
- if (exceptionOrCant(er))
- return;
-
- // Return a simplified address expression
- new(pue) AddrExp(e->loc, er, e->type);
- result = pue->exp();
- }
-
- void visit(DelegateExp *e)
- {
- // TODO: Really we should create a CTFE-only delegate expression
- // of a pointer and a funcptr.
-
- // If it is &nestedfunc, just return it
- // TODO: We should save the context pointer
- if (e->e1->op == TOKvar && ((VarExp *)e->e1)->var == e->func)
- {
- result = e;
- return;
- }
-
- Expression *er = interpret(pue, e->e1, istate);
- if (exceptionOrCant(er))
- return;
- if (er == e->e1)
- {
- // If it has already been CTFE'd, just return it
- result = e;
- }
- else
- {
- er = (er == pue->exp()) ? pue->copy() : er;
- new(pue) DelegateExp(e->loc, er, e->func, false);
- result = pue->exp();
- result->type = e->type;
- }
- }
-
- static Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal)
- {
- Expression *e = CTFEExp::cantexp;
- if (VarDeclaration *v = d->isVarDeclaration())
- {
- /* Magic variable __ctfe always returns true when interpreting
- */
- if (v->ident == Id::ctfe)
- return new IntegerExp(loc, 1, Type::tbool);
-
- if (!v->originalType && v->semanticRun < PASSsemanticdone) // semantic() not yet run
- {
- dsymbolSemantic(v, NULL);
- if (v->type->ty == Terror)
- return CTFEExp::cantexp;
- }
-
- if ((v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) &&
- !hasValue(v) &&
- v->_init && !v->isCTFE())
- {
- if (v->inuse)
- {
- error(loc, "circular initialization of %s `%s`", v->kind(), v->toPrettyChars());
- return CTFEExp::cantexp;
- }
- if (v->_scope)
- {
- v->inuse++;
- v->_init = initializerSemantic(v->_init, v->_scope, v->type, INITinterpret); // might not be run on aggregate members
- v->inuse--;
- }
- e = initializerToExpression(v->_init, v->type);
- if (!e)
- return CTFEExp::cantexp;
- assert(e->type);
-
- if (e->op == TOKconstruct || e->op == TOKblit)
- {
- AssignExp *ae = (AssignExp *)e;
- e = ae->e2;
- }
-
- if (e->op == TOKerror)
- {
- // FIXME: Ultimately all errors should be detected in prior semantic analysis stage.
- }
- else if (v->isDataseg() || (v->storage_class & STCmanifest))
- {
- /* Bugzilla 14304: e is a value that is not yet owned by CTFE.
- * Mark as "cached", and use it directly during interpretation.
- */
- e = scrubCacheValue(e);
- ctfeStack.saveGlobalConstant(v, e);
- }
- else
- {
- v->inuse++;
- e = interpret(e, istate);
- v->inuse--;
- if (CTFEExp::isCantExp(e) && !global.gag && !CtfeStatus::stackTraceCallsToSuppress)
- errorSupplemental(loc, "while evaluating %s.init", v->toChars());
- if (exceptionOrCantInterpret(e))
- return e;
- }
- }
- else if (v->isCTFE() && !hasValue(v))
- {
- if (v->_init && v->type->size() != 0)
- {
- if (v->_init->isVoidInitializer())
- {
- // var should have been initialized when it was created
- error(loc, "CTFE internal error: trying to access uninitialized var");
- assert(0);
- return CTFEExp::cantexp;
- }
- e = initializerToExpression(v->_init);
- }
- else
- e = v->type->defaultInitLiteral(e->loc);
-
- e = interpret(e, istate);
- }
- else if (!(v->isDataseg() || v->storage_class & STCmanifest) && !v->isCTFE() && !istate)
- {
- error(loc, "variable %s cannot be read at compile time", v->toChars());
- return CTFEExp::cantexp;
- }
- else
- {
- e = hasValue(v) ? getValue(v) : NULL;
- if (!e && !v->isCTFE() && v->isDataseg())
- {
- error(loc, "static variable %s cannot be read at compile time", v->toChars());
- return CTFEExp::cantexp;
- }
- if (!e)
- {
- assert(!(v->_init && v->_init->isVoidInitializer()));
- // CTFE initiated from inside a function
- error(loc, "variable %s cannot be read at compile time", v->toChars());
- return CTFEExp::cantexp;
- }
- if (e->op == TOKvoid)
- {
- VoidInitExp *ve = (VoidInitExp *)e;
- error(loc, "cannot read uninitialized variable %s in ctfe", v->toPrettyChars());
- errorSupplemental(ve->var->loc, "%s was uninitialized and used before set", ve->var->toChars());
- return CTFEExp::cantexp;
- }
- if (goal != ctfeNeedLvalue && (v->isRef() || v->isOut()))
- e = interpret(e, istate, goal);
- }
- if (!e)
- e = CTFEExp::cantexp;
- }
- else if (SymbolDeclaration *s = d->isSymbolDeclaration())
- {
- // Struct static initializers, for example
- e = s->dsym->type->defaultInitLiteral(loc);
- if (e->op == TOKerror)
- error(loc, "CTFE failed because of previous errors in %s.init", s->toChars());
- e = expressionSemantic(e, NULL);
- if (e->op == TOKerror)
- e = CTFEExp::cantexp;
- else // Convert NULL to CTFEExp
- e = interpret(e, istate, goal);
- }
- else
- error(loc, "cannot interpret declaration %s at compile time", d->toChars());
- return e;
- }
-
- void visit(VarExp *e)
- {
- if (e->var->isFuncDeclaration())
- {
- result = e;
- return;
- }
-
- if (goal == ctfeNeedLvalue)
- {
- VarDeclaration *v = e->var->isVarDeclaration();
- if (v && !v->isDataseg() && !v->isCTFE() && !istate)
- {
- e->error("variable %s cannot be read at compile time", v->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- if (v && !hasValue(v))
- {
- if (!v->isCTFE() && v->isDataseg())
- e->error("static variable %s cannot be read at compile time", v->toChars());
- else // CTFE initiated from inside a function
- e->error("variable %s cannot be read at compile time", v->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- if (v && (v->storage_class & (STCout | STCref)) && hasValue(v))
- {
- // Strip off the nest of ref variables
- Expression *ev = getValue(v);
- if (ev->op == TOKvar || ev->op == TOKindex || ev->op == TOKdotvar)
- {
- result = interpret(pue, ev, istate, goal);
- return;
- }
- }
- result = e;
- return;
- }
- result = getVarExp(e->loc, istate, e->var, goal);
- if (exceptionOrCant(result))
- return;
- if ((e->var->storage_class & (STCref | STCout)) == 0 &&
- e->type->baseElemOf()->ty != Tstruct)
- {
- /* Ultimately, STCref|STCout check should be enough to see the
- * necessity of type repainting. But currently front-end paints
- * non-ref struct variables by the const type.
- *
- * auto foo(ref const S cs);
- * S s;
- * foo(s); // VarExp('s') will have const(S)
- */
- // A VarExp may include an implicit cast. It must be done explicitly.
- result = paintTypeOntoLiteral(pue, e->type, result);
- }
- }
-
- void visit(DeclarationExp *e)
- {
- Dsymbol *s = e->declaration;
- if (VarDeclaration *v = s->isVarDeclaration())
- {
- if (TupleDeclaration *td = v->toAlias()->isTupleDeclaration())
- {
- result = NULL;
-
- // Reserve stack space for all tuple members
- if (!td->objects)
- return;
- for (size_t i = 0; i < td->objects->length; ++i)
- {
- RootObject * o = (*td->objects)[i];
- Expression *ex = isExpression(o);
- DsymbolExp *ds = (ex && ex->op == TOKdsymbol) ? (DsymbolExp *)ex : NULL;
- VarDeclaration *v2 = ds ? ds->s->isVarDeclaration() : NULL;
- assert(v2);
- if (v2->isDataseg() && !v2->isCTFE())
- continue;
-
- ctfeStack.push(v2);
- if (v2->_init)
- {
- Expression *einit;
- if (ExpInitializer *ie = v2->_init->isExpInitializer())
- {
- einit = interpret(ie->exp, istate, goal);
- if (exceptionOrCant(einit))
- return;
- }
- else if (v2->_init->isVoidInitializer())
- {
- einit = voidInitLiteral(v2->type, v2).copy();
- }
- else
- {
- e->error("declaration %s is not yet implemented in CTFE", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- setValue(v2, einit);
- }
- }
- return;
- }
- if (v->isStatic())
- {
- // Just ignore static variables which aren't read or written yet
- result = NULL;
- return;
- }
- if (!(v->isDataseg() || v->storage_class & STCmanifest) || v->isCTFE())
- ctfeStack.push(v);
- if (v->_init)
- {
- if (ExpInitializer *ie = v->_init->isExpInitializer())
- {
- result = interpret(ie->exp, istate, goal);
- }
- else if (v->_init->isVoidInitializer())
- {
- result = voidInitLiteral(v->type, v).copy();
- // There is no AssignExp for void initializers,
- // so set it here.
- setValue(v, result);
- }
- else
- {
- e->error("declaration %s is not yet implemented in CTFE", e->toChars());
- result = CTFEExp::cantexp;
- }
- }
- else if (v->type->size() == 0)
- {
- // Zero-length arrays don't need an initializer
- result = v->type->defaultInitLiteral(e->loc);
- }
- else
- {
- e->error("variable %s cannot be modified at compile time", v->toChars());
- result = CTFEExp::cantexp;
- }
- return;
- }
- if (s->isAttribDeclaration() ||
- s->isTemplateMixin() ||
- s->isTupleDeclaration())
- {
- // Check for static struct declarations, which aren't executable
- AttribDeclaration *ad = e->declaration->isAttribDeclaration();
- if (ad && ad->decl && ad->decl->length == 1)
- {
- Dsymbol *sparent = (*ad->decl)[0];
- if (sparent->isAggregateDeclaration() ||
- sparent->isTemplateDeclaration() ||
- sparent->isAliasDeclaration())
- {
- result = NULL;
- return; // static (template) struct declaration. Nothing to do.
- }
- }
-
- // These can be made to work, too lazy now
- e->error("declaration %s is not yet implemented in CTFE", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- // Others should not contain executable code, so are trivial to evaluate
- result = NULL;
- }
-
- void visit(TypeidExp *e)
- {
- if (isType(e->obj))
- {
- result = e;
- return;
- }
- if (Expression *ex = isExpression(e->obj))
- {
- result = interpret(pue, ex, istate);
- if (exceptionOrCant(ex))
- return;
-
- if (result->op == TOKnull)
- {
- e->error("null pointer dereference evaluating typeid. `%s` is null", ex->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- if (result->op != TOKclassreference)
- {
- e->error("CTFE internal error: determining classinfo");
- result = CTFEExp::cantexp;
- return;
- }
-
- ClassDeclaration *cd = ((ClassReferenceExp *)result)->originalClass();
- assert(cd);
-
- new(pue) TypeidExp(e->loc, cd->type);
- result = pue->exp();
- result->type = e->type;
- return;
- }
- visit((Expression *)e);
- }
-
- void visit(TupleExp *e)
- {
- if (exceptionOrCant(interpret(e->e0, istate, ctfeNeedNothing)))
- return;
-
- Expressions *expsx = e->exps;
- for (size_t i = 0; i < expsx->length; i++)
- {
- Expression *exp = (*expsx)[i];
- Expression *ex = interpret(exp, istate);
- if (exceptionOrCant(ex))
- return;
-
- // A tuple of assignments can contain void (Bug 5676).
- if (goal == ctfeNeedNothing)
- continue;
- if (ex->op == TOKvoidexp)
- {
- e->error("CTFE internal error: void element %s in tuple", exp->toChars());
- assert(0);
- }
-
- /* If any changes, do Copy On Write
- */
- if (ex != exp)
- {
- expsx = copyArrayOnWrite(expsx, e->exps);
- (*expsx)[i] = ex;
- }
- }
- if (expsx != e->exps)
- {
- expandTuples(expsx);
- new(pue) TupleExp(e->loc, expsx);
- result = pue->exp();
- result->type = new TypeTuple(expsx);
- }
- else
- result = e;
- }
-
- void visit(ArrayLiteralExp *e)
- {
- if (e->ownedByCtfe >= OWNEDctfe) // We've already interpreted all the elements
- {
- result = e;
- return;
- }
-
- Type *tn = e->type->toBasetype()->nextOf()->toBasetype();
- bool wantCopy = (tn->ty == Tsarray || tn->ty == Tstruct);
-
- Expression *basis = interpret(e->basis, istate);
- if (exceptionOrCant(basis))
- return;
-
- Expressions *expsx = e->elements;
- size_t dim = expsx ? expsx->length : 0;
- for (size_t i = 0; i < dim; i++)
- {
- Expression *exp = (*expsx)[i];
- Expression *ex;
- if (!exp)
- {
- ex = copyLiteral(basis).copy();
- }
- else
- {
- // segfault bug 6250
- assert(exp->op != TOKindex || ((IndexExp *)exp)->e1 != e);
-
- ex = interpret(exp, istate);
- if (exceptionOrCant(ex))
- return;
-
- /* Each elements should have distinct CFE memory.
- * int[1] z = 7;
- * int[1][] pieces = [z,z]; // here
- */
- if (wantCopy)
- ex = copyLiteral(ex).copy();
- }
-
- /* If any changes, do Copy On Write
- */
- if (ex != exp)
- {
- expsx = copyArrayOnWrite(expsx, e->elements);
- (*expsx)[i] = ex;
- }
- }
-
- if (expsx != e->elements)
- {
- // todo: all tuple expansions should go in semantic phase.
- expandTuples(expsx);
- if (expsx->length != dim)
- {
- e->error("CTFE internal error: invalid array literal");
- result = CTFEExp::cantexp;
- return;
- }
- new(pue) ArrayLiteralExp(e->loc, e->type, basis, expsx);
- ArrayLiteralExp *ale = (ArrayLiteralExp *)pue->exp();
- ale->ownedByCtfe = OWNEDctfe;
- result = ale;
- }
- else if (((TypeNext *)e->type)->next->mod & (MODconst | MODimmutable))
- {
- // If it's immutable, we don't need to dup it
- result = e;
- }
- else
- {
- *pue = copyLiteral(e);
- result = pue->exp();
- }
- }
-
- void visit(AssocArrayLiteralExp *e)
- {
- if (e->ownedByCtfe >= OWNEDctfe) // We've already interpreted all the elements
- {
- result = e;
- return;
- }
-
- Expressions *keysx = e->keys;
- Expressions *valuesx = e->values;
- for (size_t i = 0; i < keysx->length; i++)
- {
- Expression *ekey = (*keysx)[i];
- Expression *evalue = (*valuesx)[i];
-
- Expression *ek = interpret(ekey, istate);
- if (exceptionOrCant(ek))
- return;
- Expression *ev = interpret(evalue, istate);
- if (exceptionOrCant(ev))
- return;
-
- /* If any changes, do Copy On Write
- */
- if (ek != ekey ||
- ev != evalue)
- {
- keysx = copyArrayOnWrite(keysx, e->keys);
- valuesx = copyArrayOnWrite(valuesx, e->values);
- (*keysx)[i] = ek;
- (*valuesx)[i] = ev;
- }
- }
- if (keysx != e->keys)
- expandTuples(keysx);
- if (valuesx != e->values)
- expandTuples(valuesx);
- if (keysx->length != valuesx->length)
- {
- e->error("CTFE internal error: invalid AA");
- result = CTFEExp::cantexp;
- return;
- }
-
- /* Remove duplicate keys
- */
- for (size_t i = 1; i < keysx->length; i++)
- {
- Expression *ekey = (*keysx)[i - 1];
- for (size_t j = i; j < keysx->length; j++)
- {
- Expression *ekey2 = (*keysx)[j];
- if (!ctfeEqual(e->loc, TOKequal, ekey, ekey2))
- continue;
-
- // Remove ekey
- keysx = copyArrayOnWrite(keysx, e->keys);
- valuesx = copyArrayOnWrite(valuesx, e->values);
- keysx->remove(i - 1);
- valuesx->remove(i - 1);
-
- i -= 1; // redo the i'th iteration
- break;
- }
- }
-
- if (keysx != e->keys ||
- valuesx != e->values)
- {
- assert(keysx != e->keys &&
- valuesx != e->values);
- AssocArrayLiteralExp *ae = new AssocArrayLiteralExp(e->loc, keysx, valuesx);
- ae->type = e->type;
- ae->ownedByCtfe = OWNEDctfe;
- result = ae;
- }
- else
- {
- *pue = copyLiteral(e);
- result = pue->exp();
- }
- }
-
- void visit(StructLiteralExp *e)
- {
- if (e->ownedByCtfe >= OWNEDctfe)
- {
- result = e;
- return;
- }
-
- size_t dim = e->elements ? e->elements->length : 0;
- Expressions *expsx = e->elements;
-
- if (dim != e->sd->fields.length)
- {
- // guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral
- assert(e->sd->isNested() && dim == e->sd->fields.length - 1);
-
- /* If a nested struct has no initialized hidden pointer,
- * set it to null to match the runtime behaviour.
- */
- NullExp *ne = new NullExp(e->loc);
- ne->type = e->sd->vthis->type;
-
- expsx = copyArrayOnWrite(expsx, e->elements);
- expsx->push(ne);
- ++dim;
- }
- assert(dim == e->sd->fields.length);
-
- for (size_t i = 0; i < dim; i++)
- {
- VarDeclaration *v = e->sd->fields[i];
- Expression *exp = (*expsx)[i];
- Expression *ex = NULL;
- if (!exp)
- {
- ex = voidInitLiteral(v->type, v).copy();
- }
- else
- {
- ex = interpret(exp, istate);
- if (exceptionOrCant(ex))
- return;
- if ((v->type->ty != ex->type->ty) && v->type->ty == Tsarray)
- {
- // Block assignment from inside struct literals
- TypeSArray *tsa = (TypeSArray *)v->type;
- size_t len = (size_t)tsa->dim->toInteger();
- UnionExp ue;
- ex = createBlockDuplicatedArrayLiteral(&ue, ex->loc, v->type, ex, len);
- if (ex == ue.exp())
- ex = ue.copy();
- }
- }
-
- /* If any changes, do Copy On Write
- */
- if (ex != exp)
- {
- expsx = copyArrayOnWrite(expsx, e->elements);
- (*expsx)[i] = ex;
- }
- }
-
- if (expsx != e->elements)
- {
- expandTuples(expsx);
- if (expsx->length != e->sd->fields.length)
- {
- e->error("CTFE internal error: invalid struct literal");
- result = CTFEExp::cantexp;
- return;
- }
- new(pue) StructLiteralExp(e->loc, e->sd, expsx);
- StructLiteralExp *sle = (StructLiteralExp *)pue->exp();
- sle->type = e->type;
- sle->ownedByCtfe = OWNEDctfe;
- sle->origin = e->origin;
- result = sle;
- }
- else
- {
- *pue = copyLiteral(e);
- result = pue->exp();
- }
- }
-
- // Create an array literal of type 'newtype' with dimensions given by
- // 'arguments'[argnum..$]
- static Expression *recursivelyCreateArrayLiteral(UnionExp *pue, Loc loc, Type *newtype, InterState *istate,
- Expressions *arguments, int argnum)
- {
- Expression *lenExpr = interpret(pue, (*arguments)[argnum], istate);
- if (exceptionOrCantInterpret(lenExpr))
- return lenExpr;
- size_t len = (size_t)(lenExpr->toInteger());
- Type *elemType = ((TypeArray *)newtype)->next;
- if (elemType->ty == Tarray && argnum < (int)arguments->length - 1)
- {
- Expression *elem = recursivelyCreateArrayLiteral(pue, loc, elemType, istate,
- arguments, argnum + 1);
- if (exceptionOrCantInterpret(elem))
- return elem;
-
- Expressions *elements = new Expressions();
- elements->setDim(len);
- for (size_t i = 0; i < len; i++)
- (*elements)[i] = copyLiteral(elem).copy();
- new(pue) ArrayLiteralExp(loc, newtype, elements);
- ArrayLiteralExp *ae = (ArrayLiteralExp *)pue->exp();
- ae->ownedByCtfe = OWNEDctfe;
- return ae;
- }
- assert(argnum == (int)arguments->length - 1);
- if (elemType->ty == Tchar || elemType->ty == Twchar || elemType->ty == Tdchar)
- {
- const unsigned ch = (unsigned)elemType->defaultInitLiteral(loc)->toInteger();
- const unsigned char sz = (unsigned char)elemType->size();
- return createBlockDuplicatedStringLiteral(pue, loc, newtype, ch, len, sz);
- }
- else
- {
- Expression *el = interpret(elemType->defaultInitLiteral(loc), istate);
- return createBlockDuplicatedArrayLiteral(pue, loc, newtype, el, len);
- }
- }
-
- void visit(NewExp *e)
- {
- if (e->allocator)
- {
- e->error("member allocators not supported by CTFE");
- result = CTFEExp::cantexp;
- return;
- }
-
- Expression *epre = interpret(pue, e->argprefix, istate, ctfeNeedNothing);
- if (exceptionOrCant(epre))
- return;
-
- if (e->newtype->ty == Tarray && e->arguments)
- {
- result = recursivelyCreateArrayLiteral(pue, e->loc, e->newtype, istate, e->arguments, 0);
- return;
- }
- if (e->newtype->toBasetype()->ty == Tstruct)
- {
- if (e->member)
- {
- Expression *se = e->newtype->defaultInitLiteral(e->loc);
- se = interpret(se, istate);
- if (exceptionOrCant(se))
- return;
- result = interpretFunction(pue, e->member, istate, e->arguments, se);
-
- // Repaint as same as CallExp::interpret() does.
- result->loc = e->loc;
- }
- else
- {
- StructDeclaration *sd = ((TypeStruct *)e->newtype->toBasetype())->sym;
- Expressions *exps = new Expressions();
- exps->reserve(sd->fields.length);
- if (e->arguments)
- {
- exps->setDim(e->arguments->length);
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *ex = (*e->arguments)[i];
- ex = interpret(ex, istate);
- if (exceptionOrCant(ex))
- return;
- (*exps)[i] = ex;
- }
- }
- sd->fill(e->loc, exps, false);
-
- StructLiteralExp *se = new StructLiteralExp(e->loc, sd, exps, e->newtype);
- se->type = e->newtype;
- se->ownedByCtfe = OWNEDctfe;
- result = interpret(pue, se, istate);
- }
- if (exceptionOrCant(result))
- return;
- Expression *ev = (result == pue->exp()) ? pue->copy() : result;
- new(pue) AddrExp(e->loc, ev, e->type);
- result = pue->exp();
- return;
- }
- if (e->newtype->toBasetype()->ty == Tclass)
- {
- ClassDeclaration *cd = ((TypeClass *)e->newtype->toBasetype())->sym;
- size_t totalFieldCount = 0;
- for (ClassDeclaration *c = cd; c; c = c->baseClass)
- totalFieldCount += c->fields.length;
- Expressions *elems = new Expressions;
- elems->setDim(totalFieldCount);
- size_t fieldsSoFar = totalFieldCount;
- for (ClassDeclaration *c = cd; c; c = c->baseClass)
- {
- fieldsSoFar -= c->fields.length;
- for (size_t i = 0; i < c->fields.length; i++)
- {
- VarDeclaration *v = c->fields[i];
- if (v->inuse)
- {
- e->error("circular reference to `%s`", v->toPrettyChars());
- result = CTFEExp::cantexp;
- return;
- }
- Expression *m;
- if (v->_init)
- {
- if (v->_init->isVoidInitializer())
- m = voidInitLiteral(v->type, v).copy();
- else
- m = v->getConstInitializer(true);
- }
- else
- m = v->type->defaultInitLiteral(e->loc);
- if (exceptionOrCant(m))
- return;
- (*elems)[fieldsSoFar+i] = copyLiteral(m).copy();
- }
- }
- // Hack: we store a ClassDeclaration instead of a StructDeclaration.
- // We probably won't get away with this.
- StructLiteralExp *se = new StructLiteralExp(e->loc, (StructDeclaration *)cd, elems, e->newtype);
- se->ownedByCtfe = OWNEDctfe;
- new(pue) ClassReferenceExp(e->loc, se, e->type);
- Expression *eref = pue->exp();
- if (e->member)
- {
- // Call constructor
- if (!e->member->fbody)
- {
- Expression *ctorfail = evaluateIfBuiltin(pue, istate, e->loc, e->member, e->arguments, eref);
- if (ctorfail)
- {
- if (exceptionOrCant(ctorfail))
- return;
- result = eref;
- return;
- }
- e->member->error("%s cannot be constructed at compile time, because the constructor has no available source code", e->newtype->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- UnionExp ue;
- Expression *ctorfail = interpretFunction(&ue, e->member, istate, e->arguments, eref);
- if (exceptionOrCant(ctorfail))
- return;
-
- /* Bugzilla 14465: Repaint the loc, because a super() call
- * in the constructor modifies the loc of ClassReferenceExp
- * in CallExp::interpret().
- */
- eref->loc = e->loc;
- }
- result = eref;
- return;
- }
- if (e->newtype->toBasetype()->isscalar())
- {
- Expression *newval;
- if (e->arguments && e->arguments->length)
- newval = (*e->arguments)[0];
- else
- newval = e->newtype->defaultInitLiteral(e->loc);
- newval = interpret(newval, istate);
- if (exceptionOrCant(newval))
- return;
-
- // Create a CTFE pointer &[newval][0]
- Expressions *elements = new Expressions();
- elements->setDim(1);
- (*elements)[0] = newval;
- ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, e->newtype->arrayOf(), elements);
- ae->ownedByCtfe = OWNEDctfe;
-
- IndexExp *ei = new IndexExp(e->loc, ae, new IntegerExp(Loc(), 0, Type::tsize_t));
- ei->type = e->newtype;
- new(pue) AddrExp(e->loc, ei, e->type);
- result = pue->exp();
- return;
- }
- e->error("cannot interpret %s at compile time", e->toChars());
- result = CTFEExp::cantexp;
- }
-
- void visit(UnaExp *e)
- {
- UnionExp ue;
- Expression *e1 = interpret(&ue, e->e1, istate);
- if (exceptionOrCant(e1))
- return;
- switch (e->op)
- {
- case TOKneg: *pue = Neg(e->type, e1); break;
- case TOKtilde: *pue = Com(e->type, e1); break;
- case TOKnot: *pue = Not(e->type, e1); break;
- default: assert(0);
- }
- result = (*pue).exp();
- }
-
- void visit(DotTypeExp *e)
- {
- UnionExp ue;
- Expression *e1 = interpret(&ue, e->e1, istate);
- if (exceptionOrCant(e1))
- return;
-
- if (e1 == e->e1)
- result = e; // optimize: reuse this CTFE reference
- else
- {
- DotTypeExp *edt = (DotTypeExp *)e->copy();
- edt->e1 = (e1 == ue.exp()) ? e1->copy() : e1; // don't return pointer to ue
- result = edt;
- }
- }
-
- bool evalOperand(UnionExp *pue, Expression *e, Expression *ex, Expression *&er)
- {
- er = interpret(pue, ex, istate);
- if (exceptionOrCant(er))
- return false;
- if (er->isConst() != 1)
- {
- if (er->op == TOKarrayliteral)
- // Until we get it to work, issue a reasonable error message
- e->error("cannot interpret array literal expression %s at compile time", e->toChars());
- else
- e->error("CTFE internal error: non-constant value %s", ex->toChars());
- result = CTFEExp::cantexp;
- return false;
- }
- return true;
- }
-
- void interpretCommon(BinExp *e, fp_t fp)
- {
- if (e->e1->type->ty == Tpointer && e->e2->type->ty == Tpointer && e->op == TOKmin)
- {
- UnionExp ue1;
- Expression *e1 = interpret(&ue1, e->e1, istate);
- if (exceptionOrCant(e1))
- return;
- UnionExp ue2;
- Expression *e2 = interpret(&ue2, e->e2, istate);
- if (exceptionOrCant(e2))
- return;
- *pue = pointerDifference(e->loc, e->type, e1, e2);
- result = (*pue).exp();
- return;
- }
- if (e->e1->type->ty == Tpointer && e->e2->type->isintegral())
- {
- UnionExp ue1;
- Expression *e1 = interpret(&ue1, e->e1, istate);
- if (exceptionOrCant(e1))
- return;
- UnionExp ue2;
- Expression *e2 = interpret(&ue2, e->e2, istate);
- if (exceptionOrCant(e2))
- return;
- *pue = pointerArithmetic(e->loc, e->op, e->type, e1, e2);
- result = (*pue).exp();
- return;
- }
- if (e->e2->type->ty == Tpointer && e->e1->type->isintegral() && e->op == TOKadd)
- {
- UnionExp ue1;
- Expression *e1 = interpret(&ue1, e->e1, istate);
- if (exceptionOrCant(e1))
- return;
- UnionExp ue2;
- Expression *e2 = interpret(&ue2, e->e2, istate);
- if (exceptionOrCant(e2))
- return;
- *pue = pointerArithmetic(e->loc, e->op, e->type, e2, e1);
- result = (*pue).exp();
- return;
- }
- if (e->e1->type->ty == Tpointer || e->e2->type->ty == Tpointer)
- {
- e->error("pointer expression %s cannot be interpreted at compile time", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- UnionExp ue1;
- Expression *e1;
- if (!evalOperand(&ue1, e, e->e1, e1))
- return;
- UnionExp ue2;
- Expression *e2;
- if (!evalOperand(&ue2, e, e->e2, e2))
- return;
-
- if (e->op == TOKshr || e->op == TOKshl || e->op == TOKushr)
- {
- const sinteger_t i2 = e2->toInteger();
- const d_uns64 sz = e1->type->size() * 8;
- if (i2 < 0 || (d_uns64)i2 >= sz)
- {
- e->error("shift by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1);
- result = CTFEExp::cantexp;
- return;
- }
- }
- *pue = (*fp)(e->loc, e->type, e1, e2);
- result = (*pue).exp();
- if (CTFEExp::isCantExp(result))
- e->error("%s cannot be interpreted at compile time", e->toChars());
- }
-
- void interpretCompareCommon(BinExp *e, fp2_t fp)
- {
- UnionExp ue1;
- UnionExp ue2;
- if (e->e1->type->ty == Tpointer && e->e2->type->ty == Tpointer)
- {
- Expression *e1 = interpret(&ue1, e->e1, istate);
- if (exceptionOrCant(e1))
- return;
- Expression *e2 = interpret(&ue2, e->e2, istate);
- if (exceptionOrCant(e2))
- return;
- //printf("e1 = %s %s, e2 = %s %s\n", e1->type->toChars(), e1->toChars(), e2->type->toChars(), e2->toChars());
- dinteger_t ofs1, ofs2;
- Expression *agg1 = getAggregateFromPointer(e1, &ofs1);
- Expression *agg2 = getAggregateFromPointer(e2, &ofs2);
- //printf("agg1 = %p %s, agg2 = %p %s\n", agg1, agg1->toChars(), agg2, agg2->toChars());
- const int cmp = comparePointers(e->op, agg1, ofs1, agg2, ofs2);
- if (cmp == -1)
- {
- char dir = (e->op == TOKgt || e->op == TOKge) ? '<' : '>';
- e->error("the ordering of pointers to unrelated memory blocks is indeterminate in CTFE."
- " To check if they point to the same memory block, use both > and < inside && or ||, "
- "eg (%s && %s %c= %s + 1)",
- e->toChars(), e->e1->toChars(), dir, e->e2->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- new(pue) IntegerExp(e->loc, cmp, e->type);
- result = (*pue).exp();
- return;
- }
- Expression *e1 = interpret(&ue1, e->e1, istate);
- if (exceptionOrCant(e1))
- return;
- if (!isCtfeComparable(e1))
- {
- e->error("cannot compare %s at compile time", e1->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- Expression *e2 = interpret(&ue2, e->e2, istate);
- if (exceptionOrCant(e2))
- return;
- if (!isCtfeComparable(e2))
- {
- e->error("cannot compare %s at compile time", e2->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- const int cmp = (*fp)(e->loc, e->op, e1, e2);
- new(pue) IntegerExp(e->loc, cmp, e->type);
- result = (*pue).exp();
- }
-
- void visit(BinExp *e)
- {
- switch (e->op)
- {
- case TOKadd: interpretCommon(e, &Add); return;
- case TOKmin: interpretCommon(e, &Min); return;
- case TOKmul: interpretCommon(e, &Mul); return;
- case TOKdiv: interpretCommon(e, &Div); return;
- case TOKmod: interpretCommon(e, &Mod); return;
- case TOKshl: interpretCommon(e, &Shl); return;
- case TOKshr: interpretCommon(e, &Shr); return;
- case TOKushr: interpretCommon(e, &Ushr); return;
- case TOKand: interpretCommon(e, &And); return;
- case TOKor: interpretCommon(e, &Or); return;
- case TOKxor: interpretCommon(e, &Xor); return;
- case TOKpow: interpretCommon(e, &Pow); return;
- case TOKequal:
- case TOKnotequal:
- interpretCompareCommon(e, &ctfeEqual);
- return;
- case TOKidentity:
- case TOKnotidentity:
- interpretCompareCommon(e, &ctfeIdentity);
- return;
- case TOKlt:
- case TOKle:
- case TOKgt:
- case TOKge:
- interpretCompareCommon(e, &ctfeCmp);
- return;
- default:
- printf("be = '%s' %s at [%s]\n", Token::toChars(e->op), e->toChars(), e->loc.toChars());
- assert(0);
- return;
- }
- }
-
- /* Helper functions for BinExp::interpretAssignCommon
- */
-
- // Returns the variable which is eventually modified, or NULL if an rvalue.
- // thisval is the current value of 'this'.
- static VarDeclaration *findParentVar(Expression *e)
- {
- for (;;)
- {
- if (e->op == TOKvar)
- break;
- if (e->op == TOKindex)
- e = ((IndexExp *)e)->e1;
- else if (e->op == TOKdotvar)
- e = ((DotVarExp *)e)->e1;
- else if (e->op == TOKdotti)
- e = ((DotTemplateInstanceExp *)e)->e1;
- else if (e->op == TOKslice)
- e = ((SliceExp *)e)->e1;
- else
- return NULL;
- }
- VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
- assert(v);
- return v;
- }
-
- void interpretAssignCommon(BinExp *e, fp_t fp, int post = 0)
- {
- result = CTFEExp::cantexp;
- Expression *e1 = e->e1;
- if (!istate)
- {
- e->error("value of %s is not known at compile time", e1->toChars());
- return;
- }
-
- ++CtfeStatus::numAssignments;
-
- /* Before we begin, we need to know if this is a reference assignment
- * (dynamic array, AA, or class) or a value assignment.
- * Determining this for slice assignments are tricky: we need to know
- * if it is a block assignment (a[] = e) rather than a direct slice
- * assignment (a[] = b[]). Note that initializers of multi-dimensional
- * static arrays can have 2D block assignments (eg, int[7][7] x = 6;).
- * So we need to recurse to determine if it is a block assignment.
- */
- bool isBlockAssignment = false;
- if (e1->op == TOKslice)
- {
- // a[] = e can have const e. So we compare the naked types.
- Type *tdst = e1->type->toBasetype();
- Type *tsrc = e->e2->type->toBasetype();
- while (tdst->ty == Tsarray || tdst->ty == Tarray)
- {
- tdst = ((TypeArray *)tdst)->next->toBasetype();
- if (tsrc->equivalent(tdst))
- {
- isBlockAssignment = true;
- break;
- }
- }
- }
-
- // ---------------------------------------
- // Deal with reference assignment
- // ---------------------------------------
- // If it is a construction of a ref variable, it is a ref assignment
- if ((e->op == TOKconstruct || e->op == TOKblit) &&
- (((AssignExp *)e)->memset & referenceInit))
- {
- assert(!fp);
-
- Expression *newval = interpret(e->e2, istate, ctfeNeedLvalue);
- if (exceptionOrCant(newval))
- return;
-
- VarDeclaration *v = ((VarExp *)e1)->var->isVarDeclaration();
- setValue(v, newval);
-
- // Get the value to return. Note that 'newval' is an Lvalue,
- // so if we need an Rvalue, we have to interpret again.
- if (goal == ctfeNeedRvalue)
- result = interpret(newval, istate);
- else
- result = e1; // VarExp is a CTFE reference
- return;
- }
-
- if (fp)
- {
- while (e1->op == TOKcast)
- {
- CastExp *ce = (CastExp *)e1;
- e1 = ce->e1;
- }
- }
-
- // ---------------------------------------
- // Interpret left hand side
- // ---------------------------------------
- AssocArrayLiteralExp *existingAA = NULL;
- Expression *lastIndex = NULL;
- Expression *oldval = NULL;
- if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray)
- {
- // ---------------------------------------
- // Deal with AA index assignment
- // ---------------------------------------
- /* This needs special treatment if the AA doesn't exist yet.
- * There are two special cases:
- * (1) If the AA is itself an index of another AA, we may need to create
- * multiple nested AA literals before we can insert the new value.
- * (2) If the ultimate AA is null, no insertion happens at all. Instead,
- * we create nested AA literals, and change it into a assignment.
- */
- IndexExp *ie = (IndexExp *)e1;
- int depth = 0; // how many nested AA indices are there?
- while (ie->e1->op == TOKindex &&
- ((IndexExp *)ie->e1)->e1->type->toBasetype()->ty == Taarray)
- {
- assert(ie->modifiable);
- ie = (IndexExp *)ie->e1;
- ++depth;
- }
-
- // Get the AA value to be modified.
- Expression *aggregate = interpret(ie->e1, istate);
- if (exceptionOrCant(aggregate))
- return;
- if (aggregate->op == TOKassocarrayliteral)
- {
- existingAA = (AssocArrayLiteralExp *)aggregate;
-
- // Normal case, ultimate parent AA already exists
- // We need to walk from the deepest index up, checking that an AA literal
- // already exists on each level.
- lastIndex = interpret(((IndexExp *)e1)->e2, istate);
- lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
- if (exceptionOrCant(lastIndex))
- return;
-
- while (depth > 0)
- {
- // Walk the syntax tree to find the indexExp at this depth
- IndexExp *xe = (IndexExp *)e1;
- for (int d= 0; d < depth; ++d)
- xe = (IndexExp *)xe->e1;
-
- Expression *ekey = interpret(xe->e2, istate);
- if (exceptionOrCant(ekey))
- return;
- UnionExp ekeyTmp;
- ekey = resolveSlice(ekey, &ekeyTmp); // only happens with AA assignment
-
- // Look up this index in it up in the existing AA, to get the next level of AA.
- AssocArrayLiteralExp *newAA = (AssocArrayLiteralExp *)findKeyInAA(e->loc, existingAA, ekey);
- if (exceptionOrCant(newAA))
- return;
- if (!newAA)
- {
- // Doesn't exist yet, create an empty AA...
- Expressions *keysx = new Expressions();
- Expressions *valuesx = new Expressions();
- newAA = new AssocArrayLiteralExp(e->loc, keysx, valuesx);
- newAA->type = xe->type;
- newAA->ownedByCtfe = OWNEDctfe;
- //... and insert it into the existing AA.
- existingAA->keys->push(ekey);
- existingAA->values->push(newAA);
- }
- existingAA = newAA;
- --depth;
- }
-
- if (fp)
- {
- oldval = findKeyInAA(e->loc, existingAA, lastIndex);
- if (!oldval)
- oldval = copyLiteral(e->e1->type->defaultInitLiteral(e->loc)).copy();
- }
- }
- else
- {
- /* The AA is currently null. 'aggregate' is actually a reference to
- * whatever contains it. It could be anything: var, dotvarexp, ...
- * We rewrite the assignment from:
- * aa[i][j] op= newval;
- * into:
- * aa = [i:[j:T.init]];
- * aa[j] op= newval;
- */
- oldval = copyLiteral(e->e1->type->defaultInitLiteral(e->loc)).copy();
-
- Expression *newaae = oldval;
- while (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray)
- {
- Expression *ekey = interpret(((IndexExp *)e1)->e2, istate);
- if (exceptionOrCant(ekey))
- return;
- ekey = resolveSlice(ekey); // only happens with AA assignment
- Expressions *keysx = new Expressions();
- Expressions *valuesx = new Expressions();
- keysx->push(ekey);
- valuesx->push(newaae);
- AssocArrayLiteralExp *aae = new AssocArrayLiteralExp(e->loc, keysx, valuesx);
- aae->type = ((IndexExp *)e1)->e1->type;
- aae->ownedByCtfe = OWNEDctfe;
- if (!existingAA)
- {
- existingAA = aae;
- lastIndex = ekey;
- }
- newaae = aae;
- e1 = ((IndexExp *)e1)->e1;
- }
-
- // We must set to aggregate with newaae
- e1 = interpret(e1, istate, ctfeNeedLvalue);
- if (exceptionOrCant(e1))
- return;
- e1 = assignToLvalue(e, e1, newaae);
- if (exceptionOrCant(e1))
- return;
- }
- assert(existingAA && lastIndex);
- e1 = NULL; // stomp
- }
- else if (e1->op == TOKarraylength)
- {
- oldval = interpret(e1, istate);
- if (exceptionOrCant(oldval))
- return;
- }
- else if (e->op == TOKconstruct || e->op == TOKblit)
- {
- // Unless we have a simple var assignment, we're
- // only modifying part of the variable. So we need to make sure
- // that the parent variable exists.
- VarDeclaration *ultimateVar = findParentVar(e1);
- if (e1->op == TOKvar)
- {
- VarDeclaration *v = ((VarExp *)e1)->var->isVarDeclaration();
- assert(v);
- if (v->storage_class & STCout)
- goto L1;
- }
- else if (ultimateVar && !getValue(ultimateVar))
- {
- Expression *ex = interpret(ultimateVar->type->defaultInitLiteral(e->loc), istate);
- if (exceptionOrCant(ex))
- return;
- setValue(ultimateVar, ex);
- }
- else
- goto L1;
- }
- else
- {
- L1:
- e1 = interpret(e1, istate, ctfeNeedLvalue);
- if (exceptionOrCant(e1))
- return;
-
- if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray)
- {
- IndexExp *ie = (IndexExp *)e1;
- assert(ie->e1->op == TOKassocarrayliteral);
- existingAA = (AssocArrayLiteralExp *)ie->e1;
- lastIndex = ie->e2;
- }
- }
-
- // ---------------------------------------
- // Interpret right hand side
- // ---------------------------------------
- Expression *newval = interpret(e->e2, istate);
- if (exceptionOrCant(newval))
- return;
- if (e->op == TOKblit && newval->op == TOKint64)
- {
- Type *tbn = e->type->baseElemOf();
- if (tbn->ty == Tstruct)
- {
- /* Look for special case of struct being initialized with 0.
- */
- newval = e->type->defaultInitLiteral(e->loc);
- if (newval->op == TOKerror)
- {
- result = CTFEExp::cantexp;
- return;
- }
- newval = interpret(newval, istate); // copy and set ownedByCtfe flag
- if (exceptionOrCant(newval))
- return;
- }
- }
-
- // ----------------------------------------------------
- // Deal with read-modify-write assignments.
- // Set 'newval' to the final assignment value
- // Also determine the return value (except for slice
- // assignments, which are more complicated)
- // ----------------------------------------------------
- if (fp)
- {
- if (!oldval)
- {
- // Load the left hand side after interpreting the right hand side.
- oldval = interpret(e1, istate);
- if (exceptionOrCant(oldval))
- return;
- }
-
- if (e->e1->type->ty != Tpointer)
- {
- // ~= can create new values (see bug 6052)
- if (e->op == TOKcatass)
- {
- // We need to dup it and repaint the type. For a dynamic array
- // we can skip duplication, because it gets copied later anyway.
- if (newval->type->ty != Tarray)
- {
- newval = copyLiteral(newval).copy();
- newval->type = e->e2->type; // repaint type
- }
- else
- {
- newval = paintTypeOntoLiteral(e->e2->type, newval);
- newval = resolveSlice(newval);
- }
- }
- oldval = resolveSlice(oldval);
-
- newval = (*fp)(e->loc, e->type, oldval, newval).copy();
- }
- else if (e->e2->type->isintegral() &&
- (e->op == TOKaddass ||
- e->op == TOKminass ||
- e->op == TOKplusplus ||
- e->op == TOKminusminus))
- {
- newval = pointerArithmetic(e->loc, e->op, e->type, oldval, newval).copy();
- }
- else
- {
- e->error("pointer expression %s cannot be interpreted at compile time", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- if (exceptionOrCant(newval))
- {
- if (CTFEExp::isCantExp(newval))
- e->error("cannot interpret %s at compile time", e->toChars());
- return;
- }
- }
-
- if (existingAA)
- {
- if (existingAA->ownedByCtfe != OWNEDctfe)
- {
- e->error("cannot modify read-only constant %s", existingAA->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n",
- // __LINE__, existingAA->toChars(), lastIndex->toChars(), oldval ? oldval->toChars() : NULL, newval->toChars());
- assignAssocArrayElement(e->loc, existingAA, lastIndex, newval);
-
- // Determine the return value
- result = ctfeCast(pue, e->loc, e->type, e->type, fp && post ? oldval : newval);
- return;
- }
- if (e1->op == TOKarraylength)
- {
- /* Change the assignment from:
- * arr.length = n;
- * into:
- * arr = new_length_array; (result is n)
- */
-
- // Determine the return value
- result = ctfeCast(pue, e->loc, e->type, e->type, fp && post ? oldval : newval);
- if (exceptionOrCant(result))
- return;
-
- if (result == pue->exp())
- result = pue->copy();
-
- size_t oldlen = (size_t)oldval->toInteger();
- size_t newlen = (size_t)newval->toInteger();
- if (oldlen == newlen) // no change required -- we're done!
- return;
-
- // We have changed it into a reference assignment
- // Note that returnValue is still the new length.
- e1 = ((ArrayLengthExp *)e1)->e1;
- Type *t = e1->type->toBasetype();
- if (t->ty != Tarray)
- {
- e->error("%s is not yet supported at compile time", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- e1 = interpret(e1, istate, ctfeNeedLvalue);
- if (exceptionOrCant(e1))
- return;
-
- if (oldlen != 0) // Get the old array literal.
- oldval = interpret(e1, istate);
- newval = changeArrayLiteralLength(e->loc, (TypeArray *)t, oldval,
- oldlen, newlen).copy();
-
- e1 = assignToLvalue(e, e1, newval);
- if (exceptionOrCant(e1))
- return;
-
- return;
- }
-
- if (!isBlockAssignment)
- {
- newval = ctfeCast(pue, e->loc, e->type, e->type, newval);
- if (exceptionOrCant(newval))
- return;
- if (newval == pue->exp())
- newval = pue->copy();
-
- // Determine the return value
- if (goal == ctfeNeedLvalue) // Bugzilla 14371
- result = e1;
- else
- {
- result = ctfeCast(pue, e->loc, e->type, e->type, fp && post ? oldval : newval);
- if (result == pue->exp())
- result = pue->copy();
- }
- if (exceptionOrCant(result))
- return;
- }
- if (exceptionOrCant(newval))
- return;
-
- /* Block assignment or element-wise assignment.
- */
- if (e1->op == TOKslice ||
- e1->op == TOKvector ||
- e1->op == TOKarrayliteral ||
- e1->op == TOKstring ||
- (e1->op == TOKnull && e1->type->toBasetype()->ty == Tarray))
- {
- // Note that slice assignments don't support things like ++, so
- // we don't need to remember 'returnValue'.
- result = interpretAssignToSlice(pue, e, e1, newval, isBlockAssignment);
- if (exceptionOrCant(result))
- return;
- if (e->e1->op == TOKslice)
- {
- Expression *e1x = interpret(((SliceExp*)e->e1)->e1, istate, ctfeNeedLvalue);
- if (e1x->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp*)e1x;
- Expression *ex = dve->e1;
- StructLiteralExp *sle = ex->op == TOKstructliteral ? ((StructLiteralExp *)ex)
- : ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value
- : NULL;
- VarDeclaration *v = dve->var->isVarDeclaration();
- if (!sle || !v)
- {
- e->error("CTFE internal error: dotvar slice assignment");
- result = CTFEExp::cantexp;
- return;
- }
- stompOverlappedFields(sle, v);
- }
- }
- return;
- }
-
- assert(result);
-
- /* Assignment to a CTFE reference.
- */
- if (Expression *ex = assignToLvalue(e, e1, newval))
- result = ex;
-
- return;
- }
-
- /* Set all sibling fields which overlap with v to VoidExp.
- */
- void stompOverlappedFields(StructLiteralExp *sle, VarDeclaration *v)
- {
- if (!v->overlapped)
- return;
-
- for (size_t i = 0; i < sle->sd->fields.length; i++)
- {
- VarDeclaration *v2 = sle->sd->fields[i];
- if (v == v2 || !v->isOverlappedWith(v2))
- continue;
- Expression *e = (*sle->elements)[i];
- if (e->op != TOKvoid)
- (*sle->elements)[i] = voidInitLiteral(e->type, v).copy();
- }
- }
-
- Expression *assignToLvalue(BinExp *e, Expression *e1, Expression *newval)
- {
- VarDeclaration *vd = NULL;
- Expression **payload = NULL; // dead-store to prevent spurious warning
- Expression *oldval;
-
- if (e1->op == TOKvar)
- {
- vd = ((VarExp *)e1)->var->isVarDeclaration();
- oldval = getValue(vd);
- }
- else if (e1->op == TOKdotvar)
- {
- /* Assignment to member variable of the form:
- * e.v = newval
- */
- Expression *ex = ((DotVarExp *)e1)->e1;
- StructLiteralExp *sle =
- ex->op == TOKstructliteral ? ((StructLiteralExp *)ex):
- ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value
- : NULL;
- VarDeclaration *v = ((DotVarExp *)e1)->var->isVarDeclaration();
- if (!sle || !v)
- {
- e->error("CTFE internal error: dotvar assignment");
- return CTFEExp::cantexp;
- }
- if (sle->ownedByCtfe != OWNEDctfe)
- {
- e->error("cannot modify read-only constant %s", sle->toChars());
- return CTFEExp::cantexp;
- }
-
- int fieldi = ex->op == TOKstructliteral
- ? findFieldIndexByName(sle->sd, v)
- : ((ClassReferenceExp *)ex)->findFieldIndexByName(v);
- if (fieldi == -1)
- {
- e->error("CTFE internal error: cannot find field %s in %s", v->toChars(), ex->toChars());
- return CTFEExp::cantexp;
- }
- assert(0 <= fieldi && fieldi < (int)sle->elements->length);
-
- // If it's a union, set all other members of this union to void
- stompOverlappedFields(sle, v);
-
- payload = &(*sle->elements)[fieldi];
- oldval = *payload;
- }
- else if (e1->op == TOKindex)
- {
- IndexExp *ie = (IndexExp *)e1;
- assert(ie->e1->type->toBasetype()->ty != Taarray);
-
- Expression *aggregate;
- uinteger_t indexToModify;
- if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true))
- {
- return CTFEExp::cantexp;
- }
- size_t index = (size_t)indexToModify;
-
- if (aggregate->op == TOKstring)
- {
- StringExp *existingSE = (StringExp *)aggregate;
- if (existingSE->ownedByCtfe != OWNEDctfe)
- {
- e->error("cannot modify read-only string literal %s", ie->e1->toChars());
- return CTFEExp::cantexp;
- }
- void *s = existingSE->string;
- dinteger_t value = newval->toInteger();
- switch (existingSE->sz)
- {
- case 1: (( utf8_t *)s)[index] = ( utf8_t)value; break;
- case 2: ((utf16_t *)s)[index] = (utf16_t)value; break;
- case 4: ((utf32_t *)s)[index] = (utf32_t)value; break;
- default: assert(0); break;
- }
- return NULL;
- }
- if (aggregate->op != TOKarrayliteral)
- {
- e->error("index assignment %s is not yet supported in CTFE ", e->toChars());
- return CTFEExp::cantexp;
- }
-
- ArrayLiteralExp *existingAE = (ArrayLiteralExp *)aggregate;
- if (existingAE->ownedByCtfe != OWNEDctfe)
- {
- e->error("cannot modify read-only constant %s", existingAE->toChars());
- return CTFEExp::cantexp;
- }
-
- payload = &(*existingAE->elements)[index];
- oldval = *payload;
- }
- else
- {
- e->error("%s cannot be evaluated at compile time", e->toChars());
- return CTFEExp::cantexp;
- }
-
- Type *t1b = e1->type->toBasetype();
- bool wantCopy = t1b->baseElemOf()->ty == Tstruct;
-
- if (newval->op == TOKstructliteral && oldval)
- {
- newval = copyLiteral(newval).copy();
- assignInPlace(oldval, newval);
- }
- else if (wantCopy && e->op == TOKassign)
- {
- // Currently postblit/destructor calls on static array are done
- // in the druntime internal functions so they don't appear in AST.
- // Therefore interpreter should handle them specially.
-
- assert(oldval);
- #if 1 // todo: instead we can directly access to each elements of the slice
- newval = resolveSlice(newval);
- if (CTFEExp::isCantExp(newval))
- {
- e->error("CTFE internal error: assignment %s", e->toChars());
- return CTFEExp::cantexp;
- }
- #endif
- assert(oldval->op == TOKarrayliteral);
- assert(newval->op == TOKarrayliteral);
-
- Expressions *oldelems = ((ArrayLiteralExp *)oldval)->elements;
- Expressions *newelems = ((ArrayLiteralExp *)newval)->elements;
- assert(oldelems->length == newelems->length);
-
- Type *elemtype = oldval->type->nextOf();
- for (size_t i = 0; i < newelems->length; i++)
- {
- Expression *oldelem = (*oldelems)[i];
- Expression *newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]);
- // Bugzilla 9245
- if (e->e2->isLvalue())
- {
- if (Expression *ex = evaluatePostblit(istate, newelem))
- return ex;
- }
- // Bugzilla 13661
- if (Expression *ex = evaluateDtor(istate, oldelem))
- return ex;
- (*oldelems)[i] = newelem;
- }
- }
- else
- {
- // e1 has its own payload, so we have to create a new literal.
- if (wantCopy)
- newval = copyLiteral(newval).copy();
-
- if (t1b->ty == Tsarray && e->op == TOKconstruct && e->e2->isLvalue())
- {
- // Bugzilla 9245
- if (Expression *ex = evaluatePostblit(istate, newval))
- return ex;
- }
-
- oldval = newval;
- }
-
- if (vd)
- setValue(vd, oldval);
- else
- *payload = oldval;
-
- // Blit assignment should return the newly created value.
- if (e->op == TOKblit)
- return oldval;
-
- return NULL;
- }
-
- /*************
- * Deal with assignments of the form:
- * dest[] = newval
- * dest[low..upp] = newval
- * where newval has already been interpreted
- *
- * This could be a slice assignment or a block assignment, and
- * dest could be either an array literal, or a string.
- *
- * Returns TOKcantexp on failure. If there are no errors,
- * it returns aggregate[low..upp], except that as an optimisation,
- * if goal == ctfeNeedNothing, it will return NULL
- */
- Expression *interpretAssignToSlice(UnionExp *pue, BinExp *e,
- Expression *e1, Expression *newval, bool isBlockAssignment)
- {
- dinteger_t lowerbound;
- dinteger_t upperbound;
-
- Expression *aggregate;
- dinteger_t firstIndex;
-
- if (e1->op == TOKslice)
- {
- // ------------------------------
- // aggregate[] = newval
- // aggregate[low..upp] = newval
- // ------------------------------
-
- SliceExp *se = (SliceExp *)e1;
- #if 1 // should be move in interpretAssignCommon as the evaluation of e1
- Expression *oldval = interpret(se->e1, istate);
-
- // Set the $ variable
- uinteger_t dollar = resolveArrayLength(oldval);
- if (se->lengthVar)
- {
- Expression *dollarExp = new IntegerExp(e1->loc, dollar, Type::tsize_t);
- ctfeStack.push(se->lengthVar);
- setValue(se->lengthVar, dollarExp);
- }
- Expression *lwr = interpret(se->lwr, istate);
- if (exceptionOrCantInterpret(lwr))
- {
- if (se->lengthVar)
- ctfeStack.pop(se->lengthVar);
- return lwr;
- }
- Expression *upr = interpret(se->upr, istate);
- if (exceptionOrCantInterpret(upr))
- {
- if (se->lengthVar)
- ctfeStack.pop(se->lengthVar);
- return upr;
- }
- if (se->lengthVar)
- ctfeStack.pop(se->lengthVar); // $ is defined only in [L..U]
-
- unsigned dim = (unsigned)dollar;
- lowerbound = (int)(lwr ? lwr->toInteger() : 0);
- upperbound = (size_t)(upr ? upr->toInteger() : dim);
-
- if ((int)lowerbound < 0 || dim < upperbound)
- {
- e->error("array bounds [0..%d] exceeded in slice [%d..%d]",
- dim, lowerbound, upperbound);
- return CTFEExp::cantexp;
- }
- #endif
- aggregate = oldval;
- firstIndex = lowerbound;
-
- if (aggregate->op == TOKslice)
- {
- // Slice of a slice --> change the bounds
- SliceExp *oldse = (SliceExp *)aggregate;
- if (oldse->upr->toInteger() < upperbound + oldse->lwr->toInteger())
- {
- e->error("slice [%d..%d] exceeds array bounds [0..%lld]",
- lowerbound, upperbound,
- oldse->upr->toInteger() - oldse->lwr->toInteger());
- return CTFEExp::cantexp;
- }
- aggregate = oldse->e1;
- firstIndex = lowerbound + oldse->lwr->toInteger();
- }
- }
- else
- {
- if (e1->op == TOKarrayliteral)
- {
- lowerbound = 0;
- upperbound = ((ArrayLiteralExp *)e1)->elements->length;
- }
- else if (e1->op == TOKstring)
- {
- lowerbound = 0;
- upperbound = ((StringExp *)e1)->len;
- }
- else if (e1->op == TOKnull)
- {
- lowerbound = 0;
- upperbound = 0;
- }
- else
- assert(0);
-
- aggregate = e1;
- firstIndex = lowerbound;
- }
- if (upperbound == lowerbound)
- return newval;
-
- // For slice assignment, we check that the lengths match.
- if (!isBlockAssignment)
- {
- size_t srclen = (size_t)resolveArrayLength(newval);
- if (srclen != (upperbound - lowerbound))
- {
- e->error("array length mismatch assigning [0..%d] to [%d..%d]",
- srclen, lowerbound, upperbound);
- return CTFEExp::cantexp;
- }
- }
-
- if (aggregate->op == TOKstring)
- {
- StringExp *existingSE = (StringExp *)aggregate;
- if (existingSE->ownedByCtfe != OWNEDctfe)
- {
- e->error("cannot modify read-only string literal %s", existingSE->toChars());
- return CTFEExp::cantexp;
- }
-
- if (newval->op == TOKslice)
- {
- SliceExp *se = (SliceExp *)newval;
- Expression *aggr2 = se->e1;
- const dinteger_t srclower = se->lwr->toInteger();
- const dinteger_t srcupper = se->upr->toInteger();
-
- if (aggregate == aggr2 &&
- lowerbound < srcupper && srclower < upperbound)
- {
- e->error("overlapping slice assignment [%d..%d] = [%llu..%llu]",
- lowerbound, upperbound, srclower, srcupper);
- return CTFEExp::cantexp;
- }
- #if 1 // todo: instead we can directly access to each elements of the slice
- Expression *orignewval = newval;
- newval = resolveSlice(newval);
- if (CTFEExp::isCantExp(newval))
- {
- e->error("CTFE internal error: slice %s", orignewval->toChars());
- return CTFEExp::cantexp;
- }
- #endif
- assert(newval->op != TOKslice);
- }
- if (newval->op == TOKstring)
- {
- sliceAssignStringFromString((StringExp *)existingSE, (StringExp *)newval, (size_t)firstIndex);
- return newval;
- }
- if (newval->op == TOKarrayliteral)
- {
- /* Mixed slice: it was initialized as a string literal.
- * Now a slice of it is being set with an array literal.
- */
- sliceAssignStringFromArrayLiteral(existingSE, (ArrayLiteralExp *)newval, (size_t)firstIndex);
- return newval;
- }
-
- // String literal block slice assign
- dinteger_t value = newval->toInteger();
- void *s = existingSE->string;
- for (size_t i = 0; i < upperbound - lowerbound; i++)
- {
- switch (existingSE->sz)
- {
- case 1: (( utf8_t *)s)[(size_t)(i + firstIndex)] = ( utf8_t)value; break;
- case 2: ((utf16_t *)s)[(size_t)(i + firstIndex)] = (utf16_t)value; break;
- case 4: ((utf32_t *)s)[(size_t)(i + firstIndex)] = (utf32_t)value; break;
- default: assert(0); break;
- }
- }
- if (goal == ctfeNeedNothing)
- return NULL; // avoid creating an unused literal
- SliceExp *retslice = new SliceExp(e->loc, existingSE,
- new IntegerExp(e->loc, firstIndex, Type::tsize_t),
- new IntegerExp(e->loc, firstIndex + upperbound - lowerbound, Type::tsize_t));
- retslice->type = e->type;
- return interpret(pue, retslice, istate);
- }
- if (aggregate->op == TOKarrayliteral)
- {
- ArrayLiteralExp *existingAE = (ArrayLiteralExp *)aggregate;
- if (existingAE->ownedByCtfe != OWNEDctfe)
- {
- e->error("cannot modify read-only constant %s", existingAE->toChars());
- return CTFEExp::cantexp;
- }
-
- if (newval->op == TOKslice && !isBlockAssignment)
- {
- SliceExp *se = (SliceExp *)newval;
- Expression *aggr2 = se->e1;
- const dinteger_t srclower = se->lwr->toInteger();
- const dinteger_t srcupper = se->upr->toInteger();
- const bool wantCopy = (newval->type->toBasetype()->nextOf()->baseElemOf()->ty == Tstruct);
-
- //printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n",
- // aggregate, aggregate->toChars(), lowerbound, upperbound,
- // aggr2, aggr2->toChars(), srclower, srcupper, wantCopy);
- if (wantCopy)
- {
- // Currently overlapping for struct array is allowed.
- // The order of elements processing depends on the overlapping.
- // See bugzilla 14024.
- assert(aggr2->op == TOKarrayliteral);
- Expressions *oldelems = existingAE->elements;
- Expressions *newelems = ((ArrayLiteralExp *)aggr2)->elements;
-
- Type *elemtype = aggregate->type->nextOf();
- bool needsPostblit = e->e2->isLvalue();
-
- if (aggregate == aggr2 &&
- srclower < lowerbound && lowerbound < srcupper)
- {
- // reverse order
- for (size_t i = upperbound - lowerbound; 0 < i--; )
- {
- Expression *oldelem = (*oldelems)[(size_t)(i + firstIndex)];
- Expression *newelem = (*newelems)[(size_t)(i + srclower)];
- newelem = copyLiteral(newelem).copy();
- newelem->type = elemtype;
- if (needsPostblit)
- {
- if (Expression *x = evaluatePostblit(istate, newelem))
- return x;
- }
- if (Expression *x = evaluateDtor(istate, oldelem))
- return x;
- (*oldelems)[lowerbound + i] = newelem;
- }
- }
- else
- {
- // normal order
- for (size_t i = 0; i < upperbound - lowerbound; i++)
- {
- Expression *oldelem = (*oldelems)[(size_t)(i + firstIndex)];
- Expression *newelem = (*newelems)[(size_t)(i + srclower)];
- newelem = copyLiteral(newelem).copy();
- newelem->type = elemtype;
- if (needsPostblit)
- {
- if (Expression *x = evaluatePostblit(istate, newelem))
- return x;
- }
- if (Expression *x = evaluateDtor(istate, oldelem))
- return x;
- (*oldelems)[lowerbound + i] = newelem;
- }
- }
-
- //assert(0);
- return newval; // oldval?
- }
- if (aggregate == aggr2 &&
- lowerbound < srcupper && srclower < upperbound)
- {
- e->error("overlapping slice assignment [%d..%d] = [%llu..%llu]",
- lowerbound, upperbound, srclower, srcupper);
- return CTFEExp::cantexp;
- }
- #if 1 // todo: instead we can directly access to each elements of the slice
- Expression *orignewval = newval;
- newval = resolveSlice(newval);
- if (CTFEExp::isCantExp(newval))
- {
- e->error("CTFE internal error: slice %s", orignewval->toChars());
- return CTFEExp::cantexp;
- }
- #endif
- // no overlapping
- //length?
- assert(newval->op != TOKslice);
- }
- if (newval->op == TOKstring && !isBlockAssignment)
- {
- /* Mixed slice: it was initialized as an array literal of chars/integers.
- * Now a slice of it is being set with a string.
- */
- sliceAssignArrayLiteralFromString(existingAE, (StringExp *)newval, (size_t)firstIndex);
- return newval;
- }
- if (newval->op == TOKarrayliteral && !isBlockAssignment)
- {
- Expressions *oldelems = existingAE->elements;
- Expressions *newelems = ((ArrayLiteralExp *)newval)->elements;
- Type *elemtype = existingAE->type->nextOf();
- bool needsPostblit = e->op != TOKblit && e->e2->isLvalue();
- for (size_t j = 0; j < newelems->length; j++)
- {
- Expression *newelem = (*newelems)[j];
- newelem = paintTypeOntoLiteral(elemtype, newelem);
- if (needsPostblit)
- {
- Expression *x = evaluatePostblit(istate, newelem);
- if (exceptionOrCantInterpret(x))
- return x;
- }
- (*oldelems)[(size_t)(j + firstIndex)] = newelem;
- }
- return newval;
- }
-
- /* Block assignment, initialization of static arrays
- * x[] = newval
- * x may be a multidimensional static array. (Note that this
- * only happens with array literals, never with strings).
- */
- struct RecursiveBlock
- {
- InterState *istate;
- Expression *newval;
- bool refCopy;
- bool needsPostblit;
- bool needsDtor;
-
- Expression *assignTo(ArrayLiteralExp *ae)
- {
- return assignTo(ae, 0, ae->elements->length);
- }
-
- Expression *assignTo(ArrayLiteralExp *ae, size_t lwr, size_t upr)
- {
- Expressions *w = ae->elements;
-
- assert(ae->type->ty == Tsarray ||
- ae->type->ty == Tarray);
- bool directblk = ((TypeArray *)ae->type)->next->equivalent(newval->type);
-
- for (size_t k = lwr; k < upr; k++)
- {
- if (!directblk && (*w)[k]->op == TOKarrayliteral)
- {
- // Multidimensional array block assign
- if (Expression *ex = assignTo((ArrayLiteralExp *)(*w)[k]))
- return ex;
- }
- else if (refCopy)
- {
- (*w)[k] = newval;
- }
- else if (!needsPostblit && !needsDtor)
- {
- assignInPlace((*w)[k], newval);
- }
- else
- {
- Expression *oldelem = (*w)[k];
- Expression *tmpelem = needsDtor ? copyLiteral(oldelem).copy() : NULL;
-
- assignInPlace(oldelem, newval);
-
- if (needsPostblit)
- {
- if (Expression *ex = evaluatePostblit(istate, oldelem))
- return ex;
- }
- if (needsDtor)
- {
- // Bugzilla 14860
- if (Expression *ex = evaluateDtor(istate, tmpelem))
- return ex;
- }
- }
- }
- return NULL;
- }
- };
-
- Type *tn = newval->type->toBasetype();
- bool wantRef = (tn->ty == Tarray || isAssocArray(tn) ||tn->ty == Tclass);
- bool cow = newval->op != TOKstructliteral &&
- newval->op != TOKarrayliteral &&
- newval->op != TOKstring;
- Type *tb = tn->baseElemOf();
- StructDeclaration *sd = (tb->ty == Tstruct ? ((TypeStruct *)tb)->sym : NULL);
-
- RecursiveBlock rb;
- rb.istate = istate;
- rb.newval = newval;
- rb.refCopy = wantRef || cow;
- rb.needsPostblit = sd && sd->postblit && e->op != TOKblit && e->e2->isLvalue();
- rb.needsDtor = sd && sd->dtor && e->op == TOKassign;
-
- if (Expression *ex = rb.assignTo(existingAE, lowerbound, upperbound))
- return ex;
-
- if (goal == ctfeNeedNothing)
- return NULL; // avoid creating an unused literal
- SliceExp *retslice = new SliceExp(e->loc, existingAE,
- new IntegerExp(e->loc, firstIndex, Type::tsize_t),
- new IntegerExp(e->loc, firstIndex + upperbound - lowerbound, Type::tsize_t));
- retslice->type = e->type;
- return interpret(pue, retslice, istate);
- }
-
- e->error("slice operation %s = %s cannot be evaluated at compile time",
- e1->toChars(), newval->toChars());
- return CTFEExp::cantexp;
- }
-
- void visit(AssignExp *e)
- {
- interpretAssignCommon(e, NULL);
- }
-
- void visit(BinAssignExp *e)
- {
- switch (e->op)
- {
- case TOKaddass: interpretAssignCommon(e, &Add); return;
- case TOKminass: interpretAssignCommon(e, &Min); return;
- case TOKcatass: interpretAssignCommon(e, &ctfeCat); return;
- case TOKmulass: interpretAssignCommon(e, &Mul); return;
- case TOKdivass: interpretAssignCommon(e, &Div); return;
- case TOKmodass: interpretAssignCommon(e, &Mod); return;
- case TOKshlass: interpretAssignCommon(e, &Shl); return;
- case TOKshrass: interpretAssignCommon(e, &Shr); return;
- case TOKushrass: interpretAssignCommon(e, &Ushr); return;
- case TOKandass: interpretAssignCommon(e, &And); return;
- case TOKorass: interpretAssignCommon(e, &Or); return;
- case TOKxorass: interpretAssignCommon(e, &Xor); return;
- case TOKpowass: interpretAssignCommon(e, &Pow); return;
- default:
- assert(0);
- return;
- }
- }
-
- void visit(PostExp *e)
- {
- if (e->op == TOKplusplus)
- interpretAssignCommon(e, &Add, 1);
- else
- interpretAssignCommon(e, &Min, 1);
- }
-
- /* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison;
- * -1 if e is a p1 < p2 or p1 <= p2 pointer comparison;
- * 0 otherwise
- */
- static int isPointerCmpExp(Expression *e, Expression **p1, Expression **p2)
- {
- int ret = 1;
- while (e->op == TOKnot)
- {
- ret *= -1;
- e = ((NotExp *)e)->e1;
- }
- switch (e->op)
- {
- case TOKlt:
- case TOKle:
- ret *= -1;
- /* fall through */
- case TOKgt:
- case TOKge:
- *p1 = ((BinExp *)e)->e1;
- *p2 = ((BinExp *)e)->e2;
- if (!(isPointer((*p1)->type) && isPointer((*p2)->type)))
- ret = 0;
- break;
- default:
- ret = 0;
- break;
- }
- return ret;
- }
-
- /** Negate a relational operator, eg >= becomes <
- */
- static TOK reverseRelation(TOK op)
- {
- switch (op)
- {
- case TOKge: return TOKlt;
- case TOKgt: return TOKle;
- case TOKle: return TOKgt;
- case TOKlt: return TOKge;
- default:
- return assert(0), TOKreserved;
- }
- }
-
- /** If this is a four pointer relation, evaluate it, else return NULL.
- *
- * This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2)
- * where p1, p2 are expressions yielding pointers to memory block p,
- * and q1, q2 are expressions yielding pointers to memory block q.
- * This expression is valid even if p and q are independent memory
- * blocks and are therefore not normally comparable; the && form returns true
- * if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns
- * true if [p1..p2] lies outside [q1..q2], and false otherwise.
- *
- * Within the expression, any ordering of p1, p2, q1, q2 is permissible;
- * the comparison operators can be any of >, <, <=, >=, provided that
- * both directions (p > q and p < q) are checked. Additionally the
- * relational sub-expressions can be negated, eg
- * (!(q1 < p1) && p2 <= q2) is valid.
- */
- void interpretFourPointerRelation(UnionExp *pue, BinExp *e)
- {
- assert(e->op == TOKandand || e->op == TOKoror);
-
- /* It can only be an isInside expression, if both e1 and e2 are
- * directional pointer comparisons.
- * Note that this check can be made statically; it does not depends on
- * any runtime values. This allows a JIT implementation to compile a
- * special AndAndPossiblyInside, keeping the normal AndAnd case efficient.
- */
-
- // Save the pointer expressions and the comparison directions,
- // so we can use them later.
- Expression *p1 = NULL;
- Expression *p2 = NULL;
- Expression *p3 = NULL;
- Expression *p4 = NULL;
- int dir1 = isPointerCmpExp(e->e1, &p1, &p2);
- int dir2 = isPointerCmpExp(e->e2, &p3, &p4);
- if (dir1 == 0 || dir2 == 0)
- {
- result = NULL;
- return;
- }
-
- //printf("FourPointerRelation %s\n", toChars());
- UnionExp ue1;
- UnionExp ue2;
- UnionExp ue3;
- UnionExp ue4;
-
- // Evaluate the first two pointers
- p1 = interpret(&ue1, p1, istate);
- if (exceptionOrCant(p1))
- return;
- p2 = interpret(&ue2, p2, istate);
- if (exceptionOrCant(p2))
- return;
- dinteger_t ofs1, ofs2;
- Expression *agg1 = getAggregateFromPointer(p1, &ofs1);
- Expression *agg2 = getAggregateFromPointer(p2, &ofs2);
-
- if (!pointToSameMemoryBlock(agg1, agg2) &&
- agg1->op != TOKnull &&
- agg2->op != TOKnull)
- {
- // Here it is either CANT_INTERPRET,
- // or an IsInside comparison returning false.
- p3 = interpret(&ue3, p3, istate);
- if (CTFEExp::isCantExp(p3))
- return;
- // Note that it is NOT legal for it to throw an exception!
- Expression *except = NULL;
- if (exceptionOrCantInterpret(p3))
- except = p3;
- else
- {
- p4 = interpret(&ue4, p4, istate);
- if (CTFEExp::isCantExp(p4))
- {
- result = p4;
- return;
- }
- if (exceptionOrCantInterpret(p4))
- except = p4;
- }
- if (except)
- {
- e->error("comparison %s of pointers to unrelated memory blocks remains "
- "indeterminate at compile time "
- "because exception %s was thrown while evaluating %s",
- e->e1->toChars(), except->toChars(), e->e2->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- dinteger_t ofs3, ofs4;
- Expression *agg3 = getAggregateFromPointer(p3, &ofs3);
- Expression *agg4 = getAggregateFromPointer(p4, &ofs4);
- // The valid cases are:
- // p1 > p2 && p3 > p4 (same direction, also for < && <)
- // p1 > p2 && p3 < p4 (different direction, also < && >)
- // Changing any > into >= doesnt affect the result
- if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) ||
- (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
- {
- // it's a legal two-sided comparison
- new(pue) IntegerExp(e->loc, (e->op == TOKandand) ? 0 : 1, e->type);
- result = pue->exp();
- return;
- }
- // It's an invalid four-pointer comparison. Either the second
- // comparison is in the same direction as the first, or else
- // more than two memory blocks are involved (either two independent
- // invalid comparisons are present, or else agg3 == agg4).
- e->error("comparison %s of pointers to unrelated memory blocks is "
- "indeterminate at compile time, even when combined with %s.",
- e->e1->toChars(), e->e2->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- // The first pointer expression didn't need special treatment, so we
- // we need to interpret the entire expression exactly as a normal && or ||.
- // This is easy because we haven't evaluated e2 at all yet, and we already
- // know it will return a bool.
- // But we mustn't evaluate the pointer expressions in e1 again, in case
- // they have side-effects.
- bool nott = false;
- Expression *ex = e->e1;
- while (ex->op == TOKnot)
- {
- nott = !nott;
- ex = ((NotExp *)ex)->e1;
- }
- const TOK cmpop = nott ? reverseRelation(ex->op) : ex->op;
- const int cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
- // We already know this is a valid comparison.
- assert(cmp >= 0);
- if ((e->op == TOKandand && cmp == 1) ||
- (e->op == TOKoror && cmp == 0))
- {
- result = interpret(pue, e->e2, istate);
- return;
- }
- new(pue) IntegerExp(e->loc, (e->op == TOKandand) ? 0 : 1, e->type);
- result = pue->exp();
- }
-
- void visit(LogicalExp *e)
- {
- // Check for an insidePointer expression, evaluate it if so
- interpretFourPointerRelation(pue, e);
- if (result)
- return;
-
- result = interpret(e->e1, istate);
- if (exceptionOrCant(result))
- return;
-
- int res;
- const bool andand = e->op == TOKandand;
- if (andand ? result->isBool(false) : isTrueBool(result))
- res = !andand;
- else if (andand ? isTrueBool(result) : result->isBool(false))
- {
- UnionExp ue2;
- result = interpret(&ue2, e->e2, istate);
- if (exceptionOrCant(result))
- return;
- if (result->op == TOKvoidexp)
- {
- assert(e->type->ty == Tvoid);
- result = NULL;
- return;
- }
- if (result->isBool(false))
- res = 0;
- else if (isTrueBool(result))
- res = 1;
- else
- {
- result->error("`%s` does not evaluate to a boolean", result->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- }
- else
- {
- result->error("`%s` cannot be interpreted as a boolean", result->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- if (goal != ctfeNeedNothing)
- {
- new(pue) IntegerExp(e->loc, res, e->type);
- result = pue->exp();
- }
- }
-
- // Print a stack trace, starting from callingExp which called fd.
- // To shorten the stack trace, try to detect recursion.
- void showCtfeBackTrace(CallExp * callingExp, FuncDeclaration *fd)
- {
- if (CtfeStatus::stackTraceCallsToSuppress > 0)
- {
- --CtfeStatus::stackTraceCallsToSuppress;
- return;
- }
- errorSupplemental(callingExp->loc, "called from here: %s", callingExp->toChars());
- // Quit if it's not worth trying to compress the stack trace
- if (CtfeStatus::callDepth < 6 || global.params.verbose)
- return;
- // Recursion happens if the current function already exists in the call stack.
- int numToSuppress = 0;
- int recurseCount = 0;
- int depthSoFar = 0;
- InterState *lastRecurse = istate;
- for (InterState * cur = istate; cur; cur = cur->caller)
- {
- if (cur->fd == fd)
- {
- ++recurseCount;
- numToSuppress = depthSoFar;
- lastRecurse = cur;
- }
- ++depthSoFar;
- }
- // We need at least three calls to the same function, to make compression worthwhile
- if (recurseCount < 2)
- return;
- // We found a useful recursion. Print all the calls involved in the recursion
- errorSupplemental(fd->loc, "%d recursive calls to function %s", recurseCount, fd->toChars());
- for (InterState *cur = istate; cur->fd != fd; cur = cur->caller)
- {
- errorSupplemental(cur->fd->loc, "recursively called from function %s", cur->fd->toChars());
- }
- // We probably didn't enter the recursion in this function.
- // Go deeper to find the real beginning.
- InterState * cur = istate;
- while (lastRecurse->caller && cur->fd == lastRecurse->caller->fd)
- {
- cur = cur->caller;
- lastRecurse = lastRecurse->caller;
- ++numToSuppress;
- }
- CtfeStatus::stackTraceCallsToSuppress = numToSuppress;
- }
-
- void visit(CallExp *e)
- {
- Expression *pthis = NULL;
- FuncDeclaration *fd = NULL;
-
- Expression *ecall = interpret(e->e1, istate);
- if (exceptionOrCant(ecall))
- return;
-
- if (ecall->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp *)ecall;
-
- // Calling a member function
- pthis = dve->e1;
- fd = dve->var->isFuncDeclaration();
- assert(fd);
-
- if (pthis->op == TOKdottype)
- pthis = ((DotTypeExp *)dve->e1)->e1;
- }
- else if (ecall->op == TOKvar)
- {
- fd = ((VarExp *)ecall)->var->isFuncDeclaration();
- assert(fd);
-
- if (fd->ident == Id::__ArrayPostblit ||
- fd->ident == Id::__ArrayDtor)
- {
- assert(e->arguments->length == 1);
- Expression *ea = (*e->arguments)[0];
- //printf("1 ea = %s %s\n", ea->type->toChars(), ea->toChars());
- if (ea->op == TOKslice)
- ea = ((SliceExp *)ea)->e1;
- if (ea->op == TOKcast)
- ea = ((CastExp *)ea)->e1;
-
- //printf("2 ea = %s, %s %s\n", ea->type->toChars(), Token::toChars(ea->op), ea->toChars());
- if (ea->op == TOKvar || ea->op == TOKsymoff)
- result = getVarExp(e->loc, istate, ((SymbolExp *)ea)->var, ctfeNeedRvalue);
- else if (ea->op == TOKaddress)
- result = interpret(((AddrExp *)ea)->e1, istate);
- // https://issues.dlang.org/show_bug.cgi?id=18871
- // https://issues.dlang.org/show_bug.cgi?id=18819
- else if (ea->op == TOKarrayliteral)
- result = interpret((ArrayLiteralExp *)ea, istate);
- else
- assert(0);
- if (CTFEExp::isCantExp(result))
- return;
-
- if (fd->ident == Id::__ArrayPostblit)
- result = evaluatePostblit(istate, result);
- else
- result = evaluateDtor(istate, result);
- if (!result)
- result = CTFEExp::voidexp;
- return;
- }
- }
- else if (ecall->op == TOKsymoff)
- {
- SymOffExp *soe = (SymOffExp *)ecall;
- fd = soe->var->isFuncDeclaration();
- assert(fd && soe->offset == 0);
- }
- else if (ecall->op == TOKdelegate)
- {
- // Calling a delegate
- fd = ((DelegateExp *)ecall)->func;
- pthis = ((DelegateExp *)ecall)->e1;
-
- // Special handling for: &nestedfunc --> DelegateExp(VarExp(nestedfunc), nestedfunc)
- if (pthis->op == TOKvar && ((VarExp *)pthis)->var == fd)
- pthis = NULL; // context is not necessary for CTFE
- }
- else if (ecall->op == TOKfunction)
- {
- // Calling a delegate literal
- fd = ((FuncExp *)ecall)->fd;
- }
- else
- {
- // delegate.funcptr()
- // others
- e->error("cannot call %s at compile time", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- if (!fd)
- {
- e->error("CTFE internal error: cannot evaluate %s at compile time", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- if (pthis)
- {
- // Member function call
-
- // Currently this is satisfied because closure is not yet supported.
- assert(!fd->isNested());
-
- if (pthis->op == TOKtypeid)
- {
- pthis->error("static variable %s cannot be read at compile time", pthis->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- assert(pthis);
-
- if (pthis->op == TOKnull)
- {
- assert(pthis->type->toBasetype()->ty == Tclass);
- e->error("function call through null class reference %s", pthis->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- assert(pthis->op == TOKstructliteral || pthis->op == TOKclassreference);
-
- if (fd->isVirtual() && !e->directcall)
- {
- // Make a virtual function call.
- // Get the function from the vtable of the original class
- assert(pthis->op == TOKclassreference);
- ClassDeclaration *cd = ((ClassReferenceExp *)pthis)->originalClass();
-
- // We can't just use the vtable index to look it up, because
- // vtables for interfaces don't get populated until the glue layer.
- fd = cd->findFunc(fd->ident, (TypeFunction *)fd->type);
- assert(fd);
- }
- }
-
- if (fd && fd->semanticRun >= PASSsemantic3done && fd->semantic3Errors)
- {
- e->error("CTFE failed because of previous errors in %s", fd->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- // Check for built-in functions
- result = evaluateIfBuiltin(pue, istate, e->loc, fd, e->arguments, pthis);
- if (result)
- return;
-
- if (!fd->fbody)
- {
- e->error("%s cannot be interpreted at compile time,"
- " because it has no available source code", fd->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- result = interpretFunction(pue, fd, istate, e->arguments, pthis);
- if (result->op == TOKvoidexp)
- return;
- if (!exceptionOrCantInterpret(result))
- {
- if (goal != ctfeNeedLvalue) // Peel off CTFE reference if it's unnecessary
- {
- if (result == pue->exp())
- result = pue->copy();
- result = interpret(pue, result, istate);
- }
- }
- if (!exceptionOrCantInterpret(result))
- {
- result = paintTypeOntoLiteral(e->type, result);
- result->loc = e->loc;
- }
- else if (CTFEExp::isCantExp(result) && !global.gag)
- showCtfeBackTrace(e, fd); // Print a stack trace.
- }
-
- void endTempStackFrame(InterState *pistateComma)
- {
- // If we created a temporary stack frame, end it now.
- if (istate == pistateComma)
- ctfeStack.endFrame();
- }
-
- void visit(CommaExp *e)
- {
- CommaExp *firstComma = e;
- while (firstComma->e1->op == TOKcomma)
- firstComma = (CommaExp *)firstComma->e1;
-
- // If it creates a variable, and there's no context for
- // the variable to be created in, we need to create one now.
- InterState istateComma;
- if (!istate && firstComma->e1->op == TOKdeclaration)
- {
- ctfeStack.startFrame(NULL);
- istate = &istateComma;
- }
-
- result = CTFEExp::cantexp;
-
- // If the comma returns a temporary variable, it needs to be an lvalue
- // (this is particularly important for struct constructors)
- if (e->e1->op == TOKdeclaration && e->e2->op == TOKvar &&
- ((DeclarationExp *)e->e1)->declaration == ((VarExp*)e->e2)->var &&
- ((VarExp*)e->e2)->var->storage_class & STCctfe) // same as Expression::isTemp
- {
- VarExp *ve = (VarExp *)e->e2;
- VarDeclaration *v = ve->var->isVarDeclaration();
- ctfeStack.push(v);
- if (!v->_init && !getValue(v))
- {
- setValue(v, copyLiteral(v->type->defaultInitLiteral(e->loc)).copy());
- }
- if (!getValue(v))
- {
- Expression *newval = initializerToExpression(v->_init);
- // Bug 4027. Copy constructors are a weird case where the
- // initializer is a void function (the variable is modified
- // through a reference parameter instead).
- newval = interpret(newval, istate);
- if (exceptionOrCant(newval))
- return endTempStackFrame(&istateComma);
- if (newval->op != TOKvoidexp)
- {
- // v isn't necessarily null.
- setValueWithoutChecking(v, copyLiteral(newval).copy());
- }
- }
- }
- else
- {
- UnionExp ue;
- Expression *e1 = interpret(&ue, e->e1, istate, ctfeNeedNothing);
- if (exceptionOrCant(e1))
- return endTempStackFrame(&istateComma);
- }
- result = interpret(pue, e->e2, istate, goal);
- return endTempStackFrame(&istateComma);
- }
-
- void visit(CondExp *e)
- {
- UnionExp uecond;
- Expression *econd;
- econd = interpret(&uecond, e->econd, istate);
- if (exceptionOrCant(econd))
- return;
-
- if (isPointer(e->econd->type))
- {
- if (econd->op != TOKnull)
- {
- new(&uecond) IntegerExp(e->loc, 1, Type::tbool);
- econd = uecond.exp();
- }
- }
-
- if (isTrueBool(econd))
- result = interpret(pue, e->e1, istate, goal);
- else if (econd->isBool(false))
- result = interpret(pue, e->e2, istate, goal);
- else
- {
- e->error("%s does not evaluate to boolean result at compile time", e->econd->toChars());
- result = CTFEExp::cantexp;
- }
- }
-
- void visit(ArrayLengthExp *e)
- {
- UnionExp ue1;
- Expression *e1 = interpret(&ue1, e->e1, istate);
- assert(e1);
- if (exceptionOrCant(e1))
- return;
- if (e1->op != TOKstring &&
- e1->op != TOKarrayliteral &&
- e1->op != TOKslice &&
- e1->op != TOKnull)
- {
- e->error("%s cannot be evaluated at compile time", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- new(pue) IntegerExp(e->loc, resolveArrayLength(e1), e->type);
- result = pue->exp();
- }
-
- /**
- * Interpret the vector expression as an array literal.
- * Params:
- * pue = non-null pointer to temporary storage that can be used to store the return value
- * e = Expression to interpret
- * Returns:
- * resulting array literal or 'e' if unable to interpret
- */
- static Expression *interpretVectorToArray(UnionExp *pue, VectorExp *e)
- {
- if (e->e1->op == TOKarrayliteral)
- return (ArrayLiteralExp *)e->e1;
- if (e->e1->op == TOKint64 || e->e1->op == TOKfloat64)
- {
- // Convert literal __vector(int) -> __vector([array])
- Expressions *elements = new Expressions();
- elements->setDim(e->dim);
- for (size_t i = 0; i < elements->length; i++)
- (*elements)[i] = copyLiteral(e->e1).copy();
- TypeSArray *type = NULL;
- if (e->type->ty == Tvector)
- {
- TypeVector *tv = (TypeVector *)e->type;
- if (tv->basetype->ty == Tsarray)
- type = (TypeSArray *)tv->basetype;
- }
- else if (e->type->ty == Tsarray)
- type = (TypeSArray *)e->type;
- assert(type);
- new(pue) ArrayLiteralExp(e->loc, type, elements);
- ArrayLiteralExp *ale = (ArrayLiteralExp *)pue->exp();
- ale->ownedByCtfe = OWNEDctfe;
- return ale;
- }
- return e;
- }
-
- void visit(VectorExp *e)
- {
- if (e->ownedByCtfe >= OWNEDctfe) // We've already interpreted all the elements
- {
- result = e;
- return;
- }
- Expression *e1 = interpret(pue, e->e1, istate);
- assert(e1);
- if (exceptionOrCant(e1))
- return;
- if (e1->op != TOKarrayliteral && e1->op != TOKint64 && e1->op != TOKfloat64)
- {
- e->error("`%s` cannot be evaluated at compile time", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- if (e1 == pue->exp())
- e1 = pue->copy();
- new(pue) VectorExp(e->loc, e1, e->to);
- VectorExp *ve = (VectorExp *)pue->exp();
- ve->type = e->type;
- ve->dim = e->dim;
- ve->ownedByCtfe = OWNEDctfe;
- result = ve;
- }
-
- void visit(VectorArrayExp *e)
- {
- Expression *e1 = interpret(pue, e->e1, istate);
- assert(e1);
- if (exceptionOrCant(e1))
- return;
- if (e1->op == TOKvector)
- {
- VectorExp *ve = (VectorExp *)e1;
- result = interpretVectorToArray(pue, ve);
- if (result->op != TOKvector)
- return;
- }
- e->error("`%s` cannot be evaluated at compile time", e->toChars());
- result = CTFEExp::cantexp;
- }
-
- void visit(DelegatePtrExp *e)
- {
- Expression *e1 = interpret(pue, e->e1, istate);
- assert(e1);
- if (exceptionOrCant(e1))
- return;
- e->error("%s cannot be evaluated at compile time", e->toChars());
- result = CTFEExp::cantexp;
- }
-
- void visit(DelegateFuncptrExp *e)
- {
- Expression *e1 = interpret(pue, e->e1, istate);
- assert(e1);
- if (exceptionOrCant(e1))
- return;
- e->error("%s cannot be evaluated at compile time", e->toChars());
- result = CTFEExp::cantexp;
- }
-
- static bool resolveIndexing(IndexExp *e, InterState *istate, Expression **pagg, uinteger_t *pidx, bool modify)
- {
- assert(e->e1->type->toBasetype()->ty != Taarray);
-
- if (e->e1->type->toBasetype()->ty == Tpointer)
- {
- // Indexing a pointer. Note that there is no $ in this case.
- Expression *e1 = interpret(e->e1, istate);
- if (exceptionOrCantInterpret(e1))
- return false;
-
- Expression *e2 = interpret(e->e2, istate);
- if (exceptionOrCantInterpret(e2))
- return false;
- sinteger_t indx = e2->toInteger();
-
- dinteger_t ofs;
- Expression *agg = getAggregateFromPointer(e1, &ofs);
-
- if (agg->op == TOKnull)
- {
- e->error("cannot index through null pointer %s", e->e1->toChars());
- return false;
- }
- if (agg->op == TOKint64)
- {
- e->error("cannot index through invalid pointer %s of value %s",
- e->e1->toChars(), e1->toChars());
- return false;
- }
- // Pointer to a non-array variable
- if (agg->op == TOKsymoff)
- {
- e->error("mutable variable %s cannot be %s at compile time, even through a pointer",
- (modify ? "modified" : "read"), ((SymOffExp *)agg)->var->toChars());
- return false;
- }
-
- if (agg->op == TOKarrayliteral || agg->op == TOKstring)
- {
- dinteger_t len = resolveArrayLength(agg);
- if (ofs + indx >= len)
- {
- e->error("pointer index [%lld] exceeds allocated memory block [0..%lld]",
- ofs + indx, len);
- return false;
- }
- }
- else
- {
- if (ofs + indx != 0)
- {
- e->error("pointer index [%lld] lies outside memory block [0..1]",
- ofs + indx);
- return false;
- }
- }
- *pagg = agg;
- *pidx = ofs + indx;
- return true;
- }
-
- Expression *e1 = interpret(e->e1, istate);
- if (exceptionOrCantInterpret(e1))
- return false;
- if (e1->op == TOKnull)
- {
- e->error("cannot index null array %s", e->e1->toChars());
- return false;
- }
- if (e1->op == TOKvector)
- {
- UnionExp ue;
- e1 = interpretVectorToArray(&ue, (VectorExp *)e1);
- e1 = (e1 == ue.exp()) ? ue.copy() : e1;
- }
-
- // Set the $ variable, and find the array literal to modify
- if (e1->op != TOKarrayliteral &&
- e1->op != TOKstring &&
- e1->op != TOKslice &&
- e1->op != TOKvector)
- {
- e->error("cannot determine length of %s at compile time",
- e->e1->toChars());
- return false;
- }
-
- dinteger_t len = resolveArrayLength(e1);
- if (e->lengthVar)
- {
- Expression *dollarExp = new IntegerExp(e->loc, len, Type::tsize_t);
- ctfeStack.push(e->lengthVar);
- setValue(e->lengthVar, dollarExp);
- }
- Expression *e2 = interpret(e->e2, istate);
- if (e->lengthVar)
- ctfeStack.pop(e->lengthVar); // $ is defined only inside []
- if (exceptionOrCantInterpret(e2))
- return false;
- if (e2->op != TOKint64)
- {
- e->error("CTFE internal error: non-integral index [%s]", e->e2->toChars());
- return false;
- }
-
- if (e1->op == TOKslice)
- {
- // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx']
- uinteger_t index = e2->toInteger();
- uinteger_t ilwr = ((SliceExp *)e1)->lwr->toInteger();
- uinteger_t iupr = ((SliceExp *)e1)->upr->toInteger();
-
- if (index > iupr - ilwr)
- {
- e->error("index %llu exceeds array length %llu", index, iupr - ilwr);
- return false;
- }
- *pagg = ((SliceExp *)e1)->e1;
- *pidx = index + ilwr;
- }
- else
- {
- *pagg = e1;
- *pidx = e2->toInteger();
- if (len <= *pidx)
- {
- e->error("array index %lld is out of bounds [0..%lld]",
- *pidx, len);
- return false;
- }
- }
- return true;
- }
-
- void visit(IndexExp *e)
- {
- if (e->e1->type->toBasetype()->ty == Tpointer)
- {
- Expression *agg;
- uinteger_t indexToAccess;
- if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
- {
- result = CTFEExp::cantexp;
- return;
- }
- if (agg->op == TOKarrayliteral || agg->op == TOKstring)
- {
- if (goal == ctfeNeedLvalue)
- {
- // if we need a reference, IndexExp shouldn't be interpreting
- // the expression to a value, it should stay as a reference
- new(pue) IndexExp(e->loc, agg, new IntegerExp(e->e2->loc, indexToAccess, e->e2->type));
- result = pue->exp();
- result->type = e->type;
- return;
- }
- result = ctfeIndex(e->loc, e->type, agg, indexToAccess);
- return;
- }
- else
- {
- assert(indexToAccess == 0);
- result = interpret(agg, istate, goal);
- if (exceptionOrCant(result))
- return;
- result = paintTypeOntoLiteral(e->type, result);
- return;
- }
- }
-
- if (e->e1->type->toBasetype()->ty == Taarray)
- {
- Expression *e1 = interpret(e->e1, istate);
- if (exceptionOrCant(e1))
- return;
- if (e1->op == TOKnull)
- {
- if (goal == ctfeNeedLvalue && e1->type->ty == Taarray && e->modifiable)
- {
- assert(0); // does not reach here?
- return;
- }
- e->error("cannot index null array %s", e->e1->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- Expression *e2 = interpret(e->e2, istate);
- if (exceptionOrCant(e2))
- return;
-
- if (goal == ctfeNeedLvalue)
- {
- // Pointer or reference of a scalar type
- if (e1 == e->e1 && e2 == e->e2)
- result = e;
- else
- {
- new(pue) IndexExp(e->loc, e1, e2);
- result = pue->exp();
- result->type = e->type;
- }
- return;
- }
-
- assert(e1->op == TOKassocarrayliteral);
- UnionExp e2tmp;
- e2 = resolveSlice(e2, &e2tmp);
- result = findKeyInAA(e->loc, (AssocArrayLiteralExp *)e1, e2);
- if (!result)
- {
- e->error("key %s not found in associative array %s", e2->toChars(), e->e1->toChars());
- result = CTFEExp::cantexp;
- }
- return;
- }
-
- Expression *agg;
- uinteger_t indexToAccess;
- if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
- {
- result = CTFEExp::cantexp;
- return;
- }
-
- if (goal == ctfeNeedLvalue)
- {
- Expression *e2 = new IntegerExp(e->e2->loc, indexToAccess, Type::tsize_t);
- new(pue) IndexExp(e->loc, agg, e2);
- result = pue->exp();
- result->type = e->type;
- return;
- }
-
- result = ctfeIndex(e->loc, e->type, agg, indexToAccess);
- if (exceptionOrCant(result))
- return;
- if (result->op == TOKvoid)
- {
- e->error("%s is used before initialized", e->toChars());
- errorSupplemental(result->loc, "originally uninitialized here");
- result = CTFEExp::cantexp;
- return;
- }
- result = paintTypeOntoLiteral(e->type, result);
- }
-
- void visit(SliceExp *e)
- {
- if (e->e1->type->toBasetype()->ty == Tpointer)
- {
- // Slicing a pointer. Note that there is no $ in this case.
- Expression *e1 = interpret(e->e1, istate);
- if (exceptionOrCant(e1))
- return;
- if (e1->op == TOKint64)
- {
- e->error("cannot slice invalid pointer %s of value %s", e->e1->toChars(), e1->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- /* Evaluate lower and upper bounds of slice
- */
- Expression *lwr = interpret(e->lwr, istate);
- if (exceptionOrCant(lwr))
- return;
- Expression *upr = interpret(e->upr, istate);
- if (exceptionOrCant(upr))
- return;
- uinteger_t ilwr = lwr->toInteger();
- uinteger_t iupr = upr->toInteger();
-
- dinteger_t ofs;
- Expression *agg = getAggregateFromPointer(e1, &ofs);
- ilwr += ofs;
- iupr += ofs;
- if (agg->op == TOKnull)
- {
- if (iupr == ilwr)
- {
- result = new NullExp(e->loc);
- result->type = e->type;
- return;
- }
- e->error("cannot slice null pointer %s", e->e1->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- if (agg->op == TOKsymoff)
- {
- e->error("slicing pointers to static variables is not supported in CTFE");
- result = CTFEExp::cantexp;
- return;
- }
- if (agg->op != TOKarrayliteral && agg->op != TOKstring)
- {
- e->error("pointer %s cannot be sliced at compile time (it does not point to an array)", e->e1->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- assert(agg->op == TOKarrayliteral || agg->op == TOKstring);
- dinteger_t len = ArrayLength(Type::tsize_t, agg).exp()->toInteger();
- //Type *pointee = ((TypePointer *)agg->type)->next;
- if (iupr > (len + 1) || iupr < ilwr)
- {
- e->error("pointer slice [%lld..%lld] exceeds allocated memory block [0..%lld]", ilwr, iupr, len);
- result = CTFEExp::cantexp;
- return;
- }
- if (ofs != 0)
- {
- lwr = new IntegerExp(e->loc, ilwr, lwr->type);
- upr = new IntegerExp(e->loc, iupr, upr->type);
- }
- new(pue) SliceExp(e->loc, agg, lwr, upr);
- result = pue->exp();
- result->type = e->type;
- return;
- }
-
- Expression *e1 = interpret(e->e1, istate);
- if (exceptionOrCant(e1))
- return;
-
- if (!e->lwr)
- {
- result = paintTypeOntoLiteral(e->type, e1);
- return;
- }
-
- if (e1->op == TOKvector)
- {
- e1 = interpretVectorToArray(pue, (VectorExp *)e1);
- e1 = (e1 == pue->exp()) ? pue->copy() : e1;
- }
-
- /* Set the $ variable
- */
- if (e1->op != TOKarrayliteral && e1->op != TOKstring && e1->op != TOKnull && e1->op != TOKslice && e1->op != TOKvector)
- {
- e->error("cannot determine length of %s at compile time", e1->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- uinteger_t dollar = resolveArrayLength(e1);
- if (e->lengthVar)
- {
- IntegerExp *dollarExp = new IntegerExp(e->loc, dollar, Type::tsize_t);
- ctfeStack.push(e->lengthVar);
- setValue(e->lengthVar, dollarExp);
- }
-
- /* Evaluate lower and upper bounds of slice
- */
- Expression *lwr = interpret(e->lwr, istate);
- if (exceptionOrCant(lwr))
- {
- if (e->lengthVar)
- ctfeStack.pop(e->lengthVar);
- return;
- }
- Expression *upr = interpret(e->upr, istate);
- if (exceptionOrCant(upr))
- {
- if (e->lengthVar)
- ctfeStack.pop(e->lengthVar);
- return;
- }
- if (e->lengthVar)
- ctfeStack.pop(e->lengthVar); // $ is defined only inside [L..U]
-
- uinteger_t ilwr = lwr->toInteger();
- uinteger_t iupr = upr->toInteger();
- if (e1->op == TOKnull)
- {
- if (ilwr == 0 && iupr == 0)
- {
- result = e1;
- return;
- }
- e1->error("slice [%llu..%llu] is out of bounds", ilwr, iupr);
- result = CTFEExp::cantexp;
- return;
- }
- if (e1->op == TOKslice)
- {
- SliceExp *se = (SliceExp *)e1;
- // Simplify slice of slice:
- // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
- uinteger_t lo1 = se->lwr->toInteger();
- uinteger_t up1 = se->upr->toInteger();
- if (ilwr > iupr || iupr > up1 - lo1)
- {
- e->error("slice[%llu..%llu] exceeds array bounds[%llu..%llu]", ilwr, iupr, lo1, up1);
- result = CTFEExp::cantexp;
- return;
- }
- ilwr += lo1;
- iupr += lo1;
- new(pue) SliceExp(e->loc, se->e1, new IntegerExp(e->loc, ilwr, lwr->type), new IntegerExp(e->loc, iupr, upr->type));
- result = pue->exp();
- result->type = e->type;
- return;
- }
- if (e1->op == TOKarrayliteral || e1->op == TOKstring)
- {
- if (iupr < ilwr || dollar < iupr)
- {
- e->error("slice [%lld..%lld] exceeds array bounds [0..%lld]", ilwr, iupr, dollar);
- result = CTFEExp::cantexp;
- return;
- }
- }
- new(pue) SliceExp(e->loc, e1, lwr, upr);
- result = pue->exp();
- result->type = e->type;
- }
-
- void visit(InExp *e)
- {
- Expression *e1 = interpret(e->e1, istate);
- if (exceptionOrCant(e1))
- return;
- Expression *e2 = interpret(e->e2, istate);
- if (exceptionOrCant(e2))
- return;
- if (e2->op == TOKnull)
- {
- new(pue) NullExp(e->loc, e->type);
- result = pue->exp();
- return;
- }
- if (e2->op != TOKassocarrayliteral)
- {
- e->error("%s cannot be interpreted at compile time", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- e1 = resolveSlice(e1);
- result = findKeyInAA(e->loc, (AssocArrayLiteralExp *)e2, e1);
- if (exceptionOrCant(result))
- return;
- if (!result)
- {
- new(pue) NullExp(e->loc, e->type);
- result = pue->exp();
- }
- else
- {
- // Create a CTFE pointer &aa[index]
- result = new IndexExp(e->loc, e2, e1);
- result->type = e->type->nextOf();
- new(pue) AddrExp(e->loc, result, e->type);
- result = pue->exp();
- }
- }
-
- void visit(CatExp *e)
- {
- UnionExp ue1;
- Expression *e1 = interpret(&ue1, e->e1, istate);
- if (exceptionOrCant(e1))
- return;
-
- UnionExp ue2;
- Expression *e2 = interpret(&ue2, e->e2, istate);
- if (exceptionOrCant(e2))
- return;
-
- UnionExp e1tmp;
- e1 = resolveSlice(e1, &e1tmp);
-
- UnionExp e2tmp;
- e2 = resolveSlice(e2, &e2tmp);
-
- /* e1 and e2 can't go on the stack because of x~[y] and [x]~y will
- * result in [x,y] and then x or y is on the stack.
- * But if they are both strings, we can, because it isn't the x~[y] case.
- */
- if (!(e1->op == TOKstring && e2->op == TOKstring))
- {
- if (e1 == ue1.exp())
- e1 = ue1.copy();
- if (e2 == ue2.exp())
- e2 = ue2.copy();
- }
-
- *pue = ctfeCat(e->loc, e->type, e1, e2);
- result = pue->exp();
-
- if (CTFEExp::isCantExp(result))
- {
- e->error("%s cannot be interpreted at compile time", e->toChars());
- return;
- }
- // We know we still own it, because we interpreted both e1 and e2
- if (result->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)result;
- ale->ownedByCtfe = OWNEDctfe;
-
- // Bugzilla 14686
- for (size_t i = 0; i < ale->elements->length; i++)
- {
- Expression *ex = evaluatePostblit(istate, (*ale->elements)[i]);
- if (exceptionOrCant(ex))
- return;
- }
- }
- if (result->op == TOKstring)
- ((StringExp *)result)->ownedByCtfe = OWNEDctfe;
- }
-
- void visit(DeleteExp *e)
- {
- result = interpret(e->e1, istate);
- if (exceptionOrCant(result))
- return;
-
- if (result->op == TOKnull)
- {
- result = CTFEExp::voidexp;
- return;
- }
-
- Type *tb = e->e1->type->toBasetype();
- switch (tb->ty)
- {
- case Tclass:
- {
- if (result->op != TOKclassreference)
- {
- e->error("delete on invalid class reference `%s`", result->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- ClassReferenceExp *cre = (ClassReferenceExp *)result;
- ClassDeclaration *cd = cre->originalClass();
- if (cd->aggDelete)
- {
- e->error("member deallocators not supported by CTFE");
- result = CTFEExp::cantexp;
- return;
- }
-
- if (cd->dtor)
- {
- result = interpretFunction(pue, cd->dtor, istate, NULL, cre);
- if (exceptionOrCant(result))
- return;
- }
- break;
- }
-
- case Tpointer:
- {
- tb = ((TypePointer *)tb)->next->toBasetype();
- if (tb->ty == Tstruct)
- {
- if (result->op != TOKaddress ||
- ((AddrExp *)result)->e1->op != TOKstructliteral)
- {
- e->error("delete on invalid struct pointer `%s`", result->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- StructDeclaration *sd = ((TypeStruct *)tb)->sym;
- StructLiteralExp *sle = (StructLiteralExp *)((AddrExp *)result)->e1;
- if (sd->aggDelete)
- {
- e->error("member deallocators not supported by CTFE");
- result = CTFEExp::cantexp;
- return;
- }
-
- if (sd->dtor)
- {
- result = interpretFunction(pue, sd->dtor, istate, NULL, sle);
- if (exceptionOrCant(result))
- return;
- }
- }
- break;
- }
-
- case Tarray:
- {
- Type *tv = tb->nextOf()->baseElemOf();
- if (tv->ty == Tstruct)
- {
- if (result->op != TOKarrayliteral)
- {
- e->error("delete on invalid struct array `%s`", result->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- StructDeclaration *sd = ((TypeStruct *)tv)->sym;
- if (sd->aggDelete)
- {
- e->error("member deallocators not supported by CTFE");
- result = CTFEExp::cantexp;
- return;
- }
-
- if (sd->dtor)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)result;
- for (size_t i = 0; i < ale->elements->length; i++)
- {
- Expression *el = (*ale->elements)[i];
- result = interpretFunction(pue, sd->dtor, istate, NULL, el);
- if (exceptionOrCant(result))
- return;
- }
- }
- }
- break;
- }
-
- default:
- assert(0);
- }
- result = CTFEExp::voidexp;
- }
-
- void visit(CastExp *e)
- {
- Expression *e1 = interpret(e->e1, istate, goal);
- if (exceptionOrCant(e1))
- return;
- // If the expression has been cast to void, do nothing.
- if (e->to->ty == Tvoid)
- {
- result = CTFEExp::voidexp;
- return;
- }
- if (e->to->ty == Tpointer && e1->op != TOKnull)
- {
- Type *pointee = ((TypePointer *)e->type)->next;
- // Implement special cases of normally-unsafe casts
- if (e1->op == TOKint64)
- {
- // Happens with Windows HANDLEs, for example.
- result = paintTypeOntoLiteral(pue, e->to, e1);
- return;
- }
- bool castToSarrayPointer = false;
- bool castBackFromVoid = false;
- if (e1->type->ty == Tarray || e1->type->ty == Tsarray || e1->type->ty == Tpointer)
- {
- // Check for unsupported type painting operations
- // For slices, we need the type being sliced,
- // since it may have already been type painted
- Type *elemtype = e1->type->nextOf();
- if (e1->op == TOKslice)
- elemtype = ((SliceExp *)e1)->e1->type->nextOf();
- // Allow casts from X* to void *, and X** to void** for any X.
- // But don't allow cast from X* to void**.
- // So, we strip all matching * from source and target to find X.
- // Allow casts to X* from void* only if the 'void' was originally an X;
- // we check this later on.
- Type *ultimatePointee = pointee;
- Type *ultimateSrc = elemtype;
- while (ultimatePointee->ty == Tpointer && ultimateSrc->ty == Tpointer)
- {
- ultimatePointee = ultimatePointee->nextOf();
- ultimateSrc = ultimateSrc->nextOf();
- }
- if (ultimatePointee->ty == Tsarray && ultimatePointee->nextOf()->equivalent(ultimateSrc))
- {
- castToSarrayPointer = true;
- }
- else if (ultimatePointee->ty != Tvoid && ultimateSrc->ty != Tvoid &&
- !isSafePointerCast(elemtype, pointee))
- {
- e->error("reinterpreting cast from %s* to %s* is not supported in CTFE",
- elemtype->toChars(), pointee->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- if (ultimateSrc->ty == Tvoid)
- castBackFromVoid = true;
- }
-
- if (e1->op == TOKslice)
- {
- SliceExp *se = (SliceExp *)e1;
- if (se->e1->op == TOKnull)
- {
- result = paintTypeOntoLiteral(pue, e->type, se->e1);
- return;
- }
- // Create a CTFE pointer &aggregate[1..2]
- IndexExp *ei = new IndexExp(e->loc, se->e1, se->lwr);
- ei->type = e->type->nextOf();
- new(pue) AddrExp(e->loc, ei, e->type);
- result = pue->exp();
- return;
- }
- if (e1->op == TOKarrayliteral || e1->op == TOKstring)
- {
- // Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
- IndexExp *ei = new IndexExp(e->loc, e1, new IntegerExp(e->loc, 0, Type::tsize_t));
- ei->type = e->type->nextOf();
- new(pue) AddrExp(e->loc, ei, e->type);
- result = pue->exp();
- return;
- }
- if (e1->op == TOKindex && !((IndexExp *)e1)->e1->type->equals(e1->type))
- {
- // type painting operation
- IndexExp *ie = (IndexExp *)e1;
- if (castBackFromVoid)
- {
- // get the original type. For strings, it's just the type...
- Type *origType = ie->e1->type->nextOf();
- // ..but for arrays of type void*, it's the type of the element
- if (ie->e1->op == TOKarrayliteral && ie->e2->op == TOKint64)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)ie->e1;
- const size_t indx = (size_t)ie->e2->toInteger();
- if (indx < ale->elements->length)
- {
- Expression *xx = (*ale->elements)[indx];
- if (xx)
- {
- if (xx->op == TOKindex)
- origType = ((IndexExp *)xx)->e1->type->nextOf();
- else if (xx->op == TOKaddress)
- origType= ((AddrExp *)xx)->e1->type;
- else if (xx->op == TOKvar)
- origType = ((VarExp *)xx)->var->type;
- }
- }
- }
- if (!isSafePointerCast(origType, pointee))
- {
- e->error("using void* to reinterpret cast from %s* to %s* is not supported in CTFE", origType->toChars(), pointee->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- }
- new(pue) IndexExp(e1->loc, ie->e1, ie->e2);
- result = pue->exp();
- result->type = e->type;
- return;
- }
- if (e1->op == TOKaddress)
- {
- AddrExp *ae = (AddrExp *)e1;
- Type *origType = ae->e1->type;
- if (isSafePointerCast(origType, pointee))
- {
- new(pue) AddrExp(e->loc, ae->e1, e->type);
- result = pue->exp();
- return;
- }
- if (castToSarrayPointer && pointee->toBasetype()->ty == Tsarray && ae->e1->op == TOKindex)
- {
- // &val[idx]
- dinteger_t dim = ((TypeSArray *)pointee->toBasetype())->dim->toInteger();
- IndexExp *ie = (IndexExp *)ae->e1;
- Expression *lwr = ie->e2;
- Expression *upr = new IntegerExp(ie->e2->loc, ie->e2->toInteger() + dim, Type::tsize_t);
-
- // Create a CTFE pointer &val[idx..idx+dim]
- SliceExp *er = new SliceExp(e->loc, ie->e1, lwr, upr);
- er->type = pointee;
- new(pue) AddrExp(e->loc, er, e->type);
- result = pue->exp();
- return;
- }
- }
- if (e1->op == TOKvar || e1->op == TOKsymoff)
- {
- // type painting operation
- Type *origType = ((SymbolExp *)e1)->var->type;
- if (castBackFromVoid && !isSafePointerCast(origType, pointee))
- {
- e->error("using void* to reinterpret cast from %s* to %s* is not supported in CTFE", origType->toChars(), pointee->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- if (e1->op == TOKvar)
- new(pue) VarExp(e->loc, ((VarExp *)e1)->var);
- else
- new(pue) SymOffExp(e->loc, ((SymOffExp *)e1)->var, ((SymOffExp *)e1)->offset);
- result = pue->exp();
- result->type = e->to;
- return;
- }
-
- // Check if we have a null pointer (eg, inside a struct)
- e1 = interpret(e1, istate);
- if (e1->op != TOKnull)
- {
- e->error("pointer cast from %s to %s is not supported at compile time", e1->type->toChars(), e->to->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- }
- if (e->to->ty == Tsarray && e->e1->type->ty == Tvector)
- {
- // Special handling for: cast(float[4])__vector([w, x, y, z])
- e1 = interpret(e->e1, istate);
- if (exceptionOrCant(e1))
- return;
- assert(e1->op == TOKvector);
- e1 = interpretVectorToArray(pue, (VectorExp *)e1);
- }
- if (e->to->ty == Tarray && e1->op == TOKslice)
- {
- // Note that the slice may be void[], so when checking for dangerous
- // casts, we need to use the original type, which is se->e1.
- SliceExp *se = (SliceExp *)e1;
- if (!isSafePointerCast(se->e1->type->nextOf(), e->to->nextOf()))
- {
- e->error("array cast from %s to %s is not supported at compile time", se->e1->type->toChars(), e->to->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- new(pue) SliceExp(e1->loc, se->e1, se->lwr, se->upr);
- result = pue->exp();
- result->type = e->to;
- return;
- }
- // Disallow array type painting, except for conversions between built-in
- // types of identical size.
- if ((e->to->ty == Tsarray || e->to->ty == Tarray) && (e1->type->ty == Tsarray || e1->type->ty == Tarray) && !isSafePointerCast(e1->type->nextOf(), e->to->nextOf()))
- {
- e->error("array cast from %s to %s is not supported at compile time", e1->type->toChars(), e->to->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- if (e->to->ty == Tsarray)
- e1 = resolveSlice(e1);
- if (e->to->toBasetype()->ty == Tbool && e1->type->ty == Tpointer)
- {
- new(pue) IntegerExp(e->loc, e1->op != TOKnull, e->to);
- result = pue->exp();
- return;
- }
- result = ctfeCast(pue, e->loc, e->type, e->to, e1);
- }
-
- void visit(AssertExp *e)
- {
- Expression *e1 = interpret(pue, e->e1, istate);
- if (exceptionOrCant(e1))
- return;
- if (isTrueBool(e1))
- {
- }
- else if (e1->isBool(false))
- {
- if (e->msg)
- {
- UnionExp ue;
- result = interpret(&ue, e->msg, istate);
- if (exceptionOrCant(result))
- return;
- e->error("%s", result->toChars());
- }
- else
- e->error("%s failed", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- else
- {
- e->error("%s is not a compile time boolean expression", e1->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- result = e1;
- return;
- }
-
- void visit(PtrExp *e)
- {
- // Check for int<->float and long<->double casts.
- if (e->e1->op == TOKsymoff)
- {
- SymOffExp *soe = (SymOffExp *)e->e1;
- if (soe->offset == 0 && soe->var->isVarDeclaration() && isFloatIntPaint(e->type, soe->var->type))
- {
- // *(cast(int*)&v), where v is a float variable
- result = paintFloatInt(pue, getVarExp(e->loc, istate, soe->var, ctfeNeedRvalue), e->type);
- return;
- }
- }
-
- if (e->e1->op == TOKcast)
- {
- CastExp *ce1 = (CastExp *)e->e1;
- if (ce1->e1->op == TOKaddress)
- {
- AddrExp *ae11 = (AddrExp *)ce1->e1;
- // *(cast(int*)&x), where x is a float expression
- Expression *x = ae11->e1;
- if (isFloatIntPaint(e->type, x->type))
- {
- result = paintFloatInt(pue, interpret(x, istate), e->type);
- return;
- }
- }
- }
-
- // Constant fold *(&structliteral + offset)
- if (e->e1->op == TOKadd)
- {
- AddExp *ae = (AddExp *)e->e1;
- if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64)
- {
- AddrExp *ade = (AddrExp *)ae->e1;
- Expression *ex = interpret(ade->e1, istate);
- if (exceptionOrCant(ex))
- return;
- if (ex->op == TOKstructliteral)
- {
- StructLiteralExp *se = (StructLiteralExp *)ex;
- dinteger_t offset = ae->e2->toInteger();
- result = se->getField(e->type, (unsigned)offset);
- if (result)
- return;
- }
- }
- }
-
- // It's possible we have an array bounds error. We need to make sure it
- // errors with this line number, not the one where the pointer was set.
- result = interpret(e->e1, istate);
- if (exceptionOrCant(result))
- return;
-
- if (result->op == TOKfunction)
- return;
- if (result->op == TOKsymoff)
- {
- SymOffExp *soe = (SymOffExp *)result;
- if (soe->offset == 0 && soe->var->isFuncDeclaration())
- return;
- e->error("cannot dereference pointer to static variable %s at compile time", soe->var->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- if (result->op != TOKaddress)
- {
- if (result->op == TOKnull)
- e->error("dereference of null pointer `%s`", e->e1->toChars());
- else
- e->error("dereference of invalid pointer `%s`", result->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- // *(&x) ==> x
- result = ((AddrExp *)result)->e1;
-
- if (result->op == TOKslice && e->type->toBasetype()->ty == Tsarray)
- {
- /* aggr[lwr..upr]
- * upr may exceed the upper boundary of aggr, but the check is deferred
- * until those out-of-bounds elements will be touched.
- */
- return;
- }
- result = interpret(pue, result, istate, goal);
- if (exceptionOrCant(result))
- return;
- }
-
- void visit(DotVarExp *e)
- {
- Expression *ex = interpret(e->e1, istate);
- if (exceptionOrCant(ex))
- return;
-
- if (FuncDeclaration *f = e->var->isFuncDeclaration())
- {
- if (ex == e->e1)
- result = e; // optimize: reuse this CTFE reference
- else
- {
- new(pue) DotVarExp(e->loc, ex, f, false);
- result = pue->exp();
- result->type = e->type;
- }
- return;
- }
-
- VarDeclaration *v = e->var->isVarDeclaration();
- if (!v)
- {
- e->error("CTFE internal error: %s", e->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- if (ex->op == TOKnull)
- {
- if (ex->type->toBasetype()->ty == Tclass)
- e->error("class `%s` is null and cannot be dereferenced", e->e1->toChars());
- else
- e->error("CTFE internal error: null this `%s`", e->e1->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- if (ex->op != TOKstructliteral && ex->op != TOKclassreference)
- {
- e->error("%s.%s is not yet implemented at compile time", e->e1->toChars(), e->var->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- StructLiteralExp *se;
- int i;
-
- // We can't use getField, because it makes a copy
- if (ex->op == TOKclassreference)
- {
- se = ((ClassReferenceExp *)ex)->value;
- i = ((ClassReferenceExp *)ex)->findFieldIndexByName(v);
- }
- else
- {
- se = (StructLiteralExp *)ex;
- i = findFieldIndexByName(se->sd, v);
- }
- if (i == -1)
- {
- e->error("couldn't find field %s of type %s in %s", v->toChars(), e->type->toChars(), se->toChars());
- result = CTFEExp::cantexp;
- return;
- }
-
- if (goal == ctfeNeedLvalue)
- {
- Expression *ev = (*se->elements)[i];
- if (!ev || ev->op == TOKvoid)
- (*se->elements)[i] = voidInitLiteral(e->type, v).copy();
- // just return the (simplified) dotvar expression as a CTFE reference
- if (e->e1 == ex)
- result = e;
- else
- {
- new(pue) DotVarExp(e->loc, ex, v);
- result = pue->exp();
- result->type = e->type;
- }
- return;
- }
-
- result = (*se->elements)[i];
- if (!result)
- {
- // https://issues.dlang.org/show_bug.cgi?id=19897
- // Zero-length fields don't have an initializer.
- if (v->type->size() == 0)
- result = voidInitLiteral(e->type, v).copy();
- else
- {
- e->error("Internal Compiler Error: null field %s", v->toChars());
- result = CTFEExp::cantexp;
- return;
- }
- }
- if (result->op == TOKvoid)
- {
- VoidInitExp *ve = (VoidInitExp *)result;
- const char *s = ve->var->toChars();
- if (v->overlapped)
- {
- e->error("reinterpretation through overlapped field %s is not allowed in CTFE", s);
- result = CTFEExp::cantexp;
- return;
- }
- e->error("cannot read uninitialized variable %s in CTFE", s);
- result = CTFEExp::cantexp;
- return;
- }
-
- if (v->type->ty != result->type->ty && v->type->ty == Tsarray)
- {
- // Block assignment from inside struct literals
- TypeSArray *tsa = (TypeSArray *)v->type;
- size_t len = (size_t)tsa->dim->toInteger();
- UnionExp ue;
- result = createBlockDuplicatedArrayLiteral(&ue, ex->loc, v->type, ex, len);
- if (result == ue.exp())
- result = ue.copy();
- (*se->elements)[i] = result;
- }
- }
-
- void visit(RemoveExp *e)
- {
- Expression *agg = interpret(e->e1, istate);
- if (exceptionOrCant(agg))
- return;
- Expression *index = interpret(e->e2, istate);
- if (exceptionOrCant(index))
- return;
- if (agg->op == TOKnull)
- {
- result = CTFEExp::voidexp;
- return;
- }
- assert(agg->op == TOKassocarrayliteral);
- AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)agg;
- Expressions *keysx = aae->keys;
- Expressions *valuesx = aae->values;
- size_t removed = 0;
- for (size_t j = 0; j < valuesx->length; ++j)
- {
- Expression *ekey = (*keysx)[j];
- int eq = ctfeEqual(e->loc, TOKequal, ekey, index);
- if (eq)
- ++removed;
- else if (removed != 0)
- {
- (*keysx)[j - removed] = ekey;
- (*valuesx)[j - removed] = (*valuesx)[j];
- }
- }
- valuesx->length = valuesx->length - removed;
- keysx->length = keysx->length - removed;
- new(pue) IntegerExp(e->loc, removed ? 1 : 0, Type::tbool);
- result = pue->exp();
- }
-
- void visit(ClassReferenceExp *e)
- {
- //printf("ClassReferenceExp::interpret() %s\n", e->value->toChars());
- result = e;
- }
-
- void visit(VoidInitExp *e)
- {
- e->error("CTFE internal error: trying to read uninitialized variable");
- assert(0);
- result = CTFEExp::cantexp;
- }
-
- void visit(ThrownExceptionExp *e)
- {
- assert(0); // This should never be interpreted
- result = e;
- }
-
-};
-
-/********************************************
- * Interpret the expression.
- * Params:
- * pue = non-null pointer to temporary storage that can be used to store the return value
- * e = Expression to interpret
- * istate = context
- * goal = what the result will be used for
- * Returns:
- * resulting expression
- */
-
-static Expression *interpret(UnionExp *pue, Expression *e, InterState *istate, CtfeGoal goal)
-{
- if (!e)
- return NULL;
- Interpreter v(pue, istate, goal);
- e->accept(&v);
- Expression *ex = v.result;
- assert(goal == ctfeNeedNothing || ex != NULL);
- return ex;
-}
-
-///
-Expression *interpret(Expression *e, InterState *istate, CtfeGoal goal)
-{
- UnionExp ue;
- Expression *result = interpret(&ue, e, istate, goal);
- if (result == ue.exp())
- result = ue.copy();
- return result;
-}
-
-/***********************************
- * Interpret the statement.
- * Params:
- * pue = non-null pointer to temporary storage that can be used to store the return value
- * s = Statement to interpret
- * istate = context
- * Returns:
- * NULL continue to next statement
- * TOKcantexp cannot interpret statement at compile time
- * !NULL expression from return statement, or thrown exception
- */
-
-static Expression *interpret(UnionExp *pue, Statement *s, InterState *istate)
-{
- if (!s)
- return NULL;
- Interpreter v(pue, istate, ctfeNeedNothing);
- s->accept(&v);
- return v.result;
-}
-
-Expression *interpret(Statement *s, InterState *istate)
-{
- UnionExp ue;
- Expression *result = interpret(&ue, s, istate);
- if (result == ue.exp())
- result = ue.copy();
- return result;
-}
-
-/**
- * All results destined for use outside of CTFE need to have their CTFE-specific
- * features removed.
- * In particular,
- * 1. all slices must be resolved.
- * 2. all .ownedByCtfe set to OWNEDcode
- */
-Expression *scrubReturnValue(Loc loc, Expression *e)
-{
- if (e->op == TOKclassreference)
- {
- StructLiteralExp *sle = ((ClassReferenceExp*)e)->value;
- if (Expression *ex = scrubStructLiteral(loc, sle))
- return ex;
- }
- else if (e->op == TOKvoid)
- {
- error(loc, "uninitialized variable `%s` cannot be returned from CTFE", ((VoidInitExp *)e)->var->toChars());
- return new ErrorExp();
- }
-
- e = resolveSlice(e);
-
- if (e->op == TOKstructliteral)
- {
- StructLiteralExp *sle = (StructLiteralExp *)e;
- if (Expression *ex = scrubStructLiteral(loc, sle))
- return ex;
- }
- else if (e->op == TOKstring)
- {
- ((StringExp *)e)->ownedByCtfe = OWNEDcode;
- }
- else if (e->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
- ale->ownedByCtfe = OWNEDcode;
- if (Expression *ex = scrubArray(loc, ale->elements))
- return ex;
- }
- else if (e->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
- aae->ownedByCtfe = OWNEDcode;
- if (Expression *ex = scrubArray(loc, aae->keys))
- return ex;
- if (Expression *ex = scrubArray(loc, aae->values))
- return ex;
- aae->type = toBuiltinAAType(aae->type);
- }
- else if (e->op == TOKvector)
- {
- VectorExp *ve = (VectorExp *)e;
- ve->ownedByCtfe = OWNEDcode;
- if (ve->e1->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)ve->e1;
- ale->ownedByCtfe = OWNEDcode;
- if (Expression *ex = scrubArray(loc, ale->elements))
- return ex;
- }
- }
- return e;
-}
-
-/* Returns: true if e is void,
- * or is an array literal or struct literal of void elements.
- */
-static bool isVoid(Expression *e, bool checkArray = false)
-{
- if (e->op == TOKvoid)
- return true;
-
- if (checkArray && e->type->ty != Tsarray)
- return false;
-
- if (e->op == TOKarrayliteral)
- return isEntirelyVoid(((ArrayLiteralExp *)e)->elements);
-
- if (e->op == TOKstructliteral)
- return isEntirelyVoid(((StructLiteralExp *)e)->elements);
-
- return false;
-}
-
-// Return true if every element is either void,
-// or is an array literal or struct literal of void elements.
-bool isEntirelyVoid(Expressions *elems)
-{
- for (size_t i = 0; i < elems->length; i++)
- {
- Expression *e = (*elems)[i];
- // It can be NULL for performance reasons,
- // see StructLiteralExp::interpret().
- if (e && !isVoid(e))
- return false;
- }
- return true;
-}
-
-// Scrub all members of an array. Return false if error
-Expression *scrubArray(Loc loc, Expressions *elems, bool structlit)
-{
- for (size_t i = 0; i < elems->length; i++)
- {
- Expression *e = (*elems)[i];
- // It can be NULL for performance reasons,
- // see StructLiteralExp::interpret().
- if (!e)
- continue;
-
- // A struct .init may contain void members.
- // Static array members are a weird special case (bug 10994).
- if (structlit && isVoid(e, true))
- {
- e = NULL;
- }
- else
- {
- e = scrubReturnValue(loc, e);
- if (CTFEExp::isCantExp(e) || e->op == TOKerror)
- return e;
- }
- (*elems)[i] = e;
- }
- return NULL;
-}
-
-Expression *scrubStructLiteral(Loc loc, StructLiteralExp *sle)
-{
- sle->ownedByCtfe = OWNEDcode;
- if (!(sle->stageflags & stageScrub))
- {
- const int old = sle->stageflags;
- sle->stageflags |= stageScrub; // prevent infinite recursion
- if (Expression *ex = scrubArray(loc, sle->elements, true))
- return ex;
- sle->stageflags = old;
- }
- return NULL;
-}
-
-/**************************************
- * Transitively set all .ownedByCtfe to OWNEDcache
- */
-Expression *scrubCacheValue(Expression *e)
-{
- if (!e)
- return e;
-
- if (e->op == TOKclassreference)
- {
- StructLiteralExp *sle = ((ClassReferenceExp*)e)->value;
- if (Expression *ex = scrubStructLiteralCache(sle))
- return ex;
- }
- else if (e->op == TOKstructliteral)
- {
- StructLiteralExp *sle = (StructLiteralExp *)e;
- if (Expression *ex = scrubStructLiteralCache(sle))
- return ex;
- }
- else if (e->op == TOKstring)
- {
- ((StringExp *)e)->ownedByCtfe = OWNEDcache;
- }
- else if (e->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
- ale->ownedByCtfe = OWNEDcache;
- if (Expression *ex = scrubArrayCache(ale->elements))
- return ex;
- }
- else if (e->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e;
- aae->ownedByCtfe = OWNEDcache;
- if (Expression *ex = scrubArrayCache(aae->keys))
- return ex;
- if (Expression *ex = scrubArrayCache(aae->values))
- return ex;
- }
- else if (e->op == TOKvector)
- {
- VectorExp *ve = (VectorExp *)e;
- ve->ownedByCtfe = OWNEDcache;
- if (ve->e1->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)ve->e1;
- ale->ownedByCtfe = OWNEDcache;
- if (Expression *ex = scrubArrayCache(ale->elements))
- return ex;
- }
- }
- return e;
-}
-
-Expression *scrubArrayCache(Expressions *elems)
-{
- for (size_t i = 0; i < elems->length; i++)
- {
- Expression *e = (*elems)[i];
- (*elems)[i] = scrubCacheValue(e);
- }
- return NULL;
-}
-
-Expression *scrubStructLiteralCache(StructLiteralExp *sle)
-{
- sle->ownedByCtfe = OWNEDcache;
- if (!(sle->stageflags & stageScrub))
- {
- const int old = sle->stageflags;
- sle->stageflags |= stageScrub; // prevent infinite recursion
- if (Expression *ex = scrubArrayCache(sle->elements))
- return ex;
- sle->stageflags = old;
- }
- return NULL;
-}
-
-/******************************* Special Functions ***************************/
-
-static Expression *interpret_length(UnionExp *pue, InterState *istate, Expression *earg)
-{
- //printf("interpret_length()\n");
- earg = interpret(pue, earg, istate);
- if (exceptionOrCantInterpret(earg))
- return earg;
- dinteger_t len = 0;
- if (earg->op == TOKassocarrayliteral)
- len = ((AssocArrayLiteralExp *)earg)->keys->length;
- else
- assert(earg->op == TOKnull);
- new(pue) IntegerExp(earg->loc, len, Type::tsize_t);
- return pue->exp();
-}
-
-static Expression *interpret_keys(UnionExp *pue, InterState *istate, Expression *earg, Type *returnType)
-{
- earg = interpret(pue, earg, istate);
- if (exceptionOrCantInterpret(earg))
- return earg;
- if (earg->op == TOKnull)
- {
- new(pue) NullExp(earg->loc, earg->type);
- return pue->exp();
- }
- if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
- return NULL;
- assert(earg->op == TOKassocarrayliteral);
- AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
- ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, returnType, aae->keys);
- ae->ownedByCtfe = aae->ownedByCtfe;
- *pue = copyLiteral(ae);
- return pue->exp();
-}
-
-static Expression *interpret_values(UnionExp *pue, InterState *istate, Expression *earg, Type *returnType)
-{
- earg = interpret(pue, earg, istate);
- if (exceptionOrCantInterpret(earg))
- return earg;
- if (earg->op == TOKnull)
- {
- new(pue) NullExp(earg->loc, earg->type);
- return pue->exp();
- }
- if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
- return NULL;
- assert(earg->op == TOKassocarrayliteral);
- AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg;
- ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, returnType, aae->values);
- ae->ownedByCtfe = aae->ownedByCtfe;
- //printf("result is %s\n", e->toChars());
- *pue = copyLiteral(ae);
- return pue->exp();
-}
-
-Expression *interpret_dup(UnionExp *pue, InterState *istate, Expression *earg)
-{
- earg = interpret(pue, earg, istate);
- if (exceptionOrCantInterpret(earg))
- return earg;
- if (earg->op == TOKnull)
- {
- new(pue) NullExp(earg->loc, earg->type);
- return pue->exp();
- }
- if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray)
- return NULL;
- assert(earg->op == TOKassocarrayliteral);
- AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)copyLiteral(earg).copy();
- for (size_t i = 0; i < aae->keys->length; i++)
- {
- if (Expression *e = evaluatePostblit(istate, (*aae->keys)[i]))
- return e;
- if (Expression *e = evaluatePostblit(istate, (*aae->values)[i]))
- return e;
- }
- aae->type = earg->type->mutableOf(); // repaint type from const(int[int]) to const(int)[int]
- //printf("result is %s\n", aae->toChars());
- return aae;
-}
-
-// signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
-Expression *interpret_aaApply(UnionExp *pue, InterState *istate, Expression *aa, Expression *deleg)
-{
- aa = interpret(aa, istate);
- if (exceptionOrCantInterpret(aa))
- return aa;
- if (aa->op != TOKassocarrayliteral)
- {
- new(pue) IntegerExp(deleg->loc, 0, Type::tsize_t);
- return pue->exp();
- }
-
- FuncDeclaration *fd = NULL;
- Expression *pthis = NULL;
- if (deleg->op == TOKdelegate)
- {
- fd = ((DelegateExp *)deleg)->func;
- pthis = ((DelegateExp *)deleg)->e1;
- }
- else if (deleg->op == TOKfunction)
- fd = ((FuncExp*)deleg)->fd;
-
- assert(fd && fd->fbody);
- assert(fd->parameters);
- size_t numParams = fd->parameters->length;
- assert(numParams == 1 || numParams == 2);
-
- Parameter *fparam = ((TypeFunction *)fd->type)->parameterList[numParams - 1];
- bool wantRefValue = 0 != (fparam->storageClass & (STCout | STCref));
-
- Expressions args;
- args.setDim(numParams);
-
- AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)aa;
- if (!ae->keys || ae->keys->length == 0)
- return new IntegerExp(deleg->loc, 0, Type::tsize_t);
- Expression *eresult;
-
- for (size_t i = 0; i < ae->keys->length; ++i)
- {
- Expression *ekey = (*ae->keys)[i];
- Expression *evalue = (*ae->values)[i];
- if (wantRefValue)
- {
- Type *t = evalue->type;
- evalue = new IndexExp(deleg->loc, ae, ekey);
- evalue->type = t;
- }
- args[numParams - 1] = evalue;
- if (numParams == 2)
- args[0] = ekey;
-
- UnionExp ue;
- eresult = interpretFunction(&ue, fd, istate, &args, pthis);
- if (eresult == ue.exp())
- eresult = ue.copy();
- if (exceptionOrCantInterpret(eresult))
- return eresult;
-
- assert(eresult->op == TOKint64);
- if (((IntegerExp *)eresult)->getInteger() != 0)
- return eresult;
- }
- return eresult;
-}
-
-/* Decoding UTF strings for foreach loops. Duplicates the functionality of
- * the twelve _aApplyXXn functions in aApply.d in the runtime.
- */
-static Expression *foreachApplyUtf(UnionExp *pue, InterState *istate, Expression *str, Expression *deleg, bool rvs)
-{
- FuncDeclaration *fd = NULL;
- Expression *pthis = NULL;
- if (deleg->op == TOKdelegate)
- {
- fd = ((DelegateExp *)deleg)->func;
- pthis = ((DelegateExp *)deleg)->e1;
- }
- else if (deleg->op == TOKfunction)
- fd = ((FuncExp*)deleg)->fd;
-
- assert(fd && fd->fbody);
- assert(fd->parameters);
- size_t numParams = fd->parameters->length;
- assert(numParams == 1 || numParams == 2);
- Type *charType = (*fd->parameters)[numParams-1]->type;
- Type *indexType = numParams == 2 ? (*fd->parameters)[0]->type
- : Type::tsize_t;
- size_t len = (size_t)resolveArrayLength(str);
- if (len == 0)
- {
- new(pue) IntegerExp(deleg->loc, 0, indexType);
- return pue->exp();
- }
-
- str = resolveSlice(str);
-
- StringExp *se = NULL;
- ArrayLiteralExp *ale = NULL;
- if (str->op == TOKstring)
- se = (StringExp *) str;
- else if (str->op == TOKarrayliteral)
- ale = (ArrayLiteralExp *)str;
- else
- {
- str->error("CTFE internal error: cannot foreach %s", str->toChars());
- return CTFEExp::cantexp;
- }
- Expressions args;
- args.setDim(numParams);
-
- Expression *eresult = NULL; // ded-store to prevent spurious warning
-
- // Buffers for encoding; also used for decoding array literals
- utf8_t utf8buf[4];
- unsigned short utf16buf[2];
-
- size_t start = rvs ? len : 0;
- size_t end = rvs ? 0: len;
- for (size_t indx = start; indx != end;)
- {
- // Step 1: Decode the next dchar from the string.
-
- const char *errmsg = NULL; // Used for reporting decoding errors
- dchar_t rawvalue; // Holds the decoded dchar
- size_t currentIndex = indx; // The index of the decoded character
-
- if (ale)
- {
- // If it is an array literal, copy the code points into the buffer
- size_t buflen = 1; // #code points in the buffer
- size_t n = 1; // #code points in this char
- size_t sz = (size_t)ale->type->nextOf()->size();
-
- switch (sz)
- {
- case 1:
- if (rvs)
- {
- // find the start of the string
- --indx;
- buflen = 1;
- while (indx > 0 && buflen < 4)
- {
- Expression * r = (*ale->elements)[indx];
- assert(r->op == TOKint64);
- utf8_t x = (utf8_t)(((IntegerExp *)r)->getInteger());
- if ((x & 0xC0) != 0x80)
- break;
- ++buflen;
- }
- }
- else
- buflen = (indx + 4 > len) ? len - indx : 4;
- for (size_t i = 0; i < buflen; ++i)
- {
- Expression * r = (*ale->elements)[indx + i];
- assert(r->op == TOKint64);
- utf8buf[i] = (utf8_t)(((IntegerExp *)r)->getInteger());
- }
- n = 0;
- errmsg = utf_decodeChar(&utf8buf[0], buflen, &n, &rawvalue);
- break;
- case 2:
- if (rvs)
- {
- // find the start of the string
- --indx;
- buflen = 1;
- Expression * r = (*ale->elements)[indx];
- assert(r->op == TOKint64);
- unsigned short x = (unsigned short)(((IntegerExp *)r)->getInteger());
- if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
- {
- --indx;
- ++buflen;
- }
- }
- else
- buflen = (indx + 2 > len) ? len - indx : 2;
- for (size_t i=0; i < buflen; ++i)
- {
- Expression * r = (*ale->elements)[indx + i];
- assert(r->op == TOKint64);
- utf16buf[i] = (unsigned short)(((IntegerExp *)r)->getInteger());
- }
- n = 0;
- errmsg = utf_decodeWchar(&utf16buf[0], buflen, &n, &rawvalue);
- break;
- case 4:
- {
- if (rvs)
- --indx;
-
- Expression * r = (*ale->elements)[indx];
- assert(r->op == TOKint64);
- rawvalue = (dchar_t)((IntegerExp *)r)->getInteger();
- n = 1;
- }
- break;
- default:
- assert(0);
- }
- if (!rvs)
- indx += n;
- }
- else
- {
- // String literals
- size_t saveindx; // used for reverse iteration
-
- switch (se->sz)
- {
- case 1:
- if (rvs)
- {
- // find the start of the string
- utf8_t *s = (utf8_t *)se->string;
- --indx;
- while (indx > 0 && ((s[indx]&0xC0) == 0x80))
- --indx;
- saveindx = indx;
- }
- errmsg = utf_decodeChar((utf8_t *)se->string, se->len, &indx, &rawvalue);
- if (rvs)
- indx = saveindx;
- break;
- case 2:
- if (rvs)
- {
- // find the start
- unsigned short *s = (unsigned short *)se->string;
- --indx;
- if (s[indx] >= 0xDC00 && s[indx]<= 0xDFFF)
- --indx;
- saveindx = indx;
- }
- errmsg = utf_decodeWchar((unsigned short *)se->string, se->len, &indx, &rawvalue);
- if (rvs)
- indx = saveindx;
- break;
- case 4:
- if (rvs)
- --indx;
- rawvalue = ((unsigned *)(se->string))[indx];
- if (!rvs)
- ++indx;
- break;
- default:
- assert(0);
- }
- }
- if (errmsg)
- {
- deleg->error("%s", errmsg);
- return CTFEExp::cantexp;
- }
-
- // Step 2: encode the dchar in the target encoding
-
- int charlen = 1; // How many codepoints are involved?
- switch (charType->size())
- {
- case 1:
- charlen = utf_codeLengthChar(rawvalue);
- utf_encodeChar(&utf8buf[0], rawvalue);
- break;
- case 2:
- charlen = utf_codeLengthWchar(rawvalue);
- utf_encodeWchar(&utf16buf[0], rawvalue);
- break;
- case 4:
- break;
- default:
- assert(0);
- }
- if (rvs)
- currentIndex = indx;
-
- // Step 3: call the delegate once for each code point
-
- // The index only needs to be set once
- if (numParams == 2)
- args[0] = new IntegerExp(deleg->loc, currentIndex, indexType);
-
- Expression *val = NULL;
-
- for (int k= 0; k < charlen; ++k)
- {
- dchar_t codepoint;
- switch (charType->size())
- {
- case 1:
- codepoint = utf8buf[k];
- break;
- case 2:
- codepoint = utf16buf[k];
- break;
- case 4:
- codepoint = rawvalue;
- break;
- default:
- assert(0);
- }
- val = new IntegerExp(str->loc, codepoint, charType);
-
- args[numParams - 1] = val;
-
- UnionExp ue;
- eresult = interpretFunction(&ue, fd, istate, &args, pthis);
- if (eresult == ue.exp())
- eresult = ue.copy();
- if (exceptionOrCantInterpret(eresult))
- return eresult;
- assert(eresult->op == TOKint64);
- if (((IntegerExp *)eresult)->getInteger() != 0)
- return eresult;
- }
- }
- return eresult;
-}
-
-/* If this is a built-in function, return the interpreted result,
- * Otherwise, return NULL.
- */
-Expression *evaluateIfBuiltin(UnionExp *pue, InterState *istate, Loc loc,
- FuncDeclaration *fd, Expressions *arguments, Expression *pthis)
-{
- Expression *e = NULL;
- size_t nargs = arguments ? arguments->length : 0;
- if (!pthis)
- {
- if (isBuiltin(fd) != BUILTINunimp)
- {
- Expressions args;
- args.setDim(nargs);
- for (size_t i = 0; i < args.length; i++)
- {
- Expression *earg = (*arguments)[i];
- earg = interpret(earg, istate);
- if (exceptionOrCantInterpret(earg))
- return earg;
- args[i] = earg;
- }
- e = eval_builtin(loc, fd, &args);
- if (!e)
- {
- error(loc, "cannot evaluate unimplemented builtin %s at compile time", fd->toChars());
- e = CTFEExp::cantexp;
- }
- }
- }
- if (!pthis)
- {
- Expression *firstarg = nargs > 0 ? (*arguments)[0] : NULL;
- if (firstarg && firstarg->type->toBasetype()->ty == Taarray)
- {
- TypeAArray *firstAAtype = (TypeAArray *)firstarg->type;
- const Identifier *id = fd->ident;
- if (nargs == 1)
- {
- if (fd->ident == Id::aaLen)
- return interpret_length(pue, istate, firstarg);
-
- if (fd->toParent2()->ident == Id::object)
- {
- if (id == Id::keys)
- return interpret_keys(pue, istate, firstarg, firstAAtype->index->arrayOf());
- if (id == Id::values)
- return interpret_values(pue, istate, firstarg, firstAAtype->nextOf()->arrayOf());
- if (id == Id::rehash)
- return interpret(pue, firstarg, istate);
- if (id == Id::dup)
- return interpret_dup(pue, istate, firstarg);
- }
- }
- else // (nargs == 3)
- {
- if (id == Id::_aaApply)
- return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
- if (id == Id::_aaApply2)
- return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
- }
- }
- }
- if (pthis && !fd->fbody && fd->isCtorDeclaration() && fd->parent && fd->parent->parent && fd->parent->parent->ident == Id::object)
- {
- if (pthis->op == TOKclassreference && fd->parent->ident == Id::Throwable)
- {
- // At present, the constructors just copy their arguments into the struct.
- // But we might need some magic if stack tracing gets added to druntime.
- StructLiteralExp *se = ((ClassReferenceExp *)pthis)->value;
- assert(arguments->length <= se->elements->length);
- for (size_t i = 0; i < arguments->length; ++i)
- {
- e = interpret((*arguments)[i], istate);
- if (exceptionOrCantInterpret(e))
- return e;
- (*se->elements)[i] = e;
- }
- return CTFEExp::voidexp;
- }
- }
- if (nargs == 1 && !pthis &&
- (fd->ident == Id::criticalenter || fd->ident == Id::criticalexit))
- {
- // Support synchronized{} as a no-op
- return CTFEExp::voidexp;
- }
- if (!pthis)
- {
- const char *id = fd->ident->toChars();
- size_t idlen = strlen(id);
- if (nargs == 2 && (idlen == 10 || idlen == 11) &&
- !strncmp(id, "_aApply", 7))
- {
- // Functions from aApply.d and aApplyR.d in the runtime
- bool rvs = (idlen == 11); // true if foreach_reverse
- char c = id[idlen-3]; // char width: 'c', 'w', or 'd'
- char s = id[idlen-2]; // string width: 'c', 'w', or 'd'
- char n = id[idlen-1]; // numParams: 1 or 2.
- // There are 12 combinations
- if ((n == '1' || n == '2') &&
- (c == 'c' || c == 'w' || c == 'd') &&
- (s == 'c' || s == 'w' || s == 'd') && c != s)
- {
- Expression *str = (*arguments)[0];
- str = interpret(str, istate);
- if (exceptionOrCantInterpret(str))
- return str;
- return foreachApplyUtf(pue, istate, str, (*arguments)[1], rvs);
- }
- }
- }
- return e;
-}
-
-Expression *evaluatePostblit(InterState *istate, Expression *e)
-{
- Type *tb = e->type->baseElemOf();
- if (tb->ty != Tstruct)
- return NULL;
- StructDeclaration *sd = ((TypeStruct *)tb)->sym;
- if (!sd->postblit)
- return NULL;
-
- if (e->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e;
- for (size_t i = 0; i < ale->elements->length; i++)
- {
- e = evaluatePostblit(istate, (*ale->elements)[i]);
- if (e)
- return e;
- }
- return NULL;
- }
- if (e->op == TOKstructliteral)
- {
- // e.__postblit()
- UnionExp ue;
- e = interpretFunction(&ue, sd->postblit, istate, NULL, e);
- if (e == ue.exp())
- e = ue.copy();
- if (exceptionOrCantInterpret(e))
- return e;
- return NULL;
- }
- assert(0);
- return NULL;
-}
-
-Expression *evaluateDtor(InterState *istate, Expression *e)
-{
- Type *tb = e->type->baseElemOf();
- if (tb->ty != Tstruct)
- return NULL;
- StructDeclaration *sd = ((TypeStruct *)tb)->sym;
- if (!sd->dtor)
- return NULL;
-
- UnionExp ue;
- if (e->op == TOKarrayliteral)
- {
- ArrayLiteralExp *alex = (ArrayLiteralExp *)e;
- for (size_t i = alex->elements->length; 0 < i--; )
- e = evaluateDtor(istate, (*alex->elements)[i]);
- }
- else if (e->op == TOKstructliteral)
- {
- // e.__dtor()
- e = interpretFunction(&ue, sd->dtor, istate, NULL, e);
- }
- else
- assert(0);
- if (exceptionOrCantInterpret(e))
- {
- if (e == ue.exp())
- e = ue.copy();
- return e;
- }
- return NULL;
-}
-
-/*************************** CTFE Sanity Checks ***************************/
-
-/* Setter functions for CTFE variable values.
- * These functions exist to check for compiler CTFE bugs.
- */
-bool hasValue(VarDeclaration *vd)
-{
- if (vd->ctfeAdrOnStack == -1)
- return false;
- return NULL != getValue(vd);
-}
-
-Expression *getValue(VarDeclaration *vd)
-{
- return ctfeStack.getValue(vd);
-}
-
-void setValueNull(VarDeclaration *vd)
-{
- ctfeStack.setValue(vd, NULL);
-}
-
-// Don't check for validity
-void setValueWithoutChecking(VarDeclaration *vd, Expression *newval)
-{
- ctfeStack.setValue(vd, newval);
-}
-
-void setValue(VarDeclaration *vd, Expression *newval)
-{
- assert((vd->storage_class & (STCout | STCref))
- ? isCtfeReferenceValid(newval)
- : isCtfeValueValid(newval));
- ctfeStack.setValue(vd, newval);
-}
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
new file mode 100644
index 0000000..541fac7
--- /dev/null
+++ b/gcc/d/dmd/dinterpret.d
@@ -0,0 +1,7487 @@
+/**
+ * The entry point for CTFE.
+ *
+ * Specification: ($LINK2 https://dlang.org/spec/function.html#interpretation, Compile Time Function Execution (CTFE))
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d, _dinterpret.d)
+ * Documentation: https://dlang.org/phobos/dmd_dinterpret.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dinterpret.d
+ */
+
+module dmd.dinterpret;
+
+import core.stdc.stdio;
+import core.stdc.stdlib;
+import core.stdc.string;
+import dmd.apply;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.builtin;
+import dmd.constfold;
+import dmd.ctfeexpr;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.initsem;
+import dmd.mtype;
+import dmd.printast;
+import dmd.root.rmem;
+import dmd.root.array;
+import dmd.root.region;
+import dmd.root.rootobject;
+import dmd.statement;
+import dmd.tokens;
+import dmd.utf;
+import dmd.visitor;
+
+/*************************************
+ * Entry point for CTFE.
+ * A compile-time result is required. Give an error if not possible.
+ *
+ * `e` must be semantically valid expression. In other words, it should not
+ * contain any `ErrorExp`s in it. But, CTFE interpretation will cross over
+ * functions and may invoke a function that contains `ErrorStatement` in its body.
+ * If that, the "CTFE failed because of previous errors" error is raised.
+ */
+public Expression ctfeInterpret(Expression e)
+{
+ switch (e.op)
+ {
+ case TOK.int64:
+ case TOK.float64:
+ case TOK.complex80:
+ case TOK.null_:
+ case TOK.void_:
+ case TOK.string_:
+ case TOK.this_:
+ case TOK.super_:
+ case TOK.type:
+ case TOK.typeid_:
+ case TOK.template_: // non-eponymous template/instance
+ case TOK.scope_: // ditto
+ case TOK.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here
+ case TOK.dot: // ditto
+ if (e.type.ty == Terror)
+ return ErrorExp.get();
+ goto case TOK.error;
+
+ case TOK.error:
+ return e;
+
+ default:
+ break;
+ }
+
+ assert(e.type); // https://issues.dlang.org/show_bug.cgi?id=14642
+ //assert(e.type.ty != Terror); // FIXME
+ if (e.type.ty == Terror)
+ return ErrorExp.get();
+
+ auto rgnpos = ctfeGlobals.region.savePos();
+
+ Expression result = interpret(e, null);
+
+ result = copyRegionExp(result);
+
+ if (!CTFEExp.isCantExp(result))
+ result = scrubReturnValue(e.loc, result);
+ if (CTFEExp.isCantExp(result))
+ result = ErrorExp.get();
+
+ ctfeGlobals.region.release(rgnpos);
+
+ return result;
+}
+
+/* Run CTFE on the expression, but allow the expression to be a TypeExp
+ * or a tuple containing a TypeExp. (This is required by pragma(msg)).
+ */
+public Expression ctfeInterpretForPragmaMsg(Expression e)
+{
+ if (e.op == TOK.error || e.op == TOK.type)
+ return e;
+
+ // It's also OK for it to be a function declaration (happens only with
+ // __traits(getOverloads))
+ if (auto ve = e.isVarExp())
+ if (ve.var.isFuncDeclaration())
+ {
+ return e;
+ }
+
+ auto tup = e.isTupleExp();
+ if (!tup)
+ return e.ctfeInterpret();
+
+ // Tuples need to be treated separately, since they are
+ // allowed to contain a TypeExp in this case.
+
+ Expressions* expsx = null;
+ foreach (i, g; *tup.exps)
+ {
+ auto h = ctfeInterpretForPragmaMsg(g);
+ if (h != g)
+ {
+ if (!expsx)
+ {
+ expsx = tup.exps.copy();
+ }
+ (*expsx)[i] = h;
+ }
+ }
+ if (expsx)
+ {
+ auto te = new TupleExp(e.loc, expsx);
+ expandTuples(te.exps);
+ te.type = new TypeTuple(te.exps);
+ return te;
+ }
+ return e;
+}
+
+public extern (C++) Expression getValue(VarDeclaration vd)
+{
+ return ctfeGlobals.stack.getValue(vd);
+}
+
+/*************************************************
+ * Allocate an Expression in the ctfe region.
+ * Params:
+ * T = type of Expression to allocate
+ * args = arguments to Expression's constructor
+ * Returns:
+ * allocated Expression
+ */
+T ctfeEmplaceExp(T : Expression, Args...)(Args args)
+{
+ if (mem.isGCEnabled)
+ return new T(args);
+ auto p = ctfeGlobals.region.malloc(__traits(classInstanceSize, T));
+ emplaceExp!T(p, args);
+ return cast(T)p;
+}
+
+// CTFE diagnostic information
+public extern (C++) void printCtfePerformanceStats()
+{
+ debug (SHOWPERFORMANCE)
+ {
+ printf(" ---- CTFE Performance ----\n");
+ printf("max call depth = %d\tmax stack = %d\n", ctfeGlobals.maxCallDepth, ctfeGlobals.stack.maxStackUsage());
+ printf("array allocs = %d\tassignments = %d\n\n", ctfeGlobals.numArrayAllocs, ctfeGlobals.numAssignments);
+ }
+}
+
+/**************************
+ */
+
+void incArrayAllocs()
+{
+ ++ctfeGlobals.numArrayAllocs;
+}
+
+/* ================================================ Implementation ======================================= */
+
+private:
+
+/***************
+ * Collect together globals used by CTFE
+ */
+struct CtfeGlobals
+{
+ Region region;
+
+ CtfeStack stack;
+
+ int callDepth = 0; // current number of recursive calls
+
+ // When printing a stack trace, suppress this number of calls
+ int stackTraceCallsToSuppress = 0;
+
+ int maxCallDepth = 0; // highest number of recursive calls
+ int numArrayAllocs = 0; // Number of allocated arrays
+ int numAssignments = 0; // total number of assignments executed
+}
+
+__gshared CtfeGlobals ctfeGlobals;
+
+enum CTFEGoal : int
+{
+ RValue, /// Must return an Rvalue (== CTFE value)
+ LValue, /// Must return an Lvalue (== CTFE reference)
+ Nothing, /// The return value is not required
+}
+
+//debug = LOG;
+//debug = LOGASSIGN;
+//debug = LOGCOMPILE;
+//debug = SHOWPERFORMANCE;
+
+// Maximum allowable recursive function calls in CTFE
+enum CTFE_RECURSION_LIMIT = 1000;
+
+/**
+ The values of all CTFE variables
+ */
+struct CtfeStack
+{
+private:
+ /* The stack. Every declaration we encounter is pushed here,
+ * together with the VarDeclaration, and the previous
+ * stack address of that variable, so that we can restore it
+ * when we leave the stack frame.
+ * Note that when a function is forward referenced, the interpreter must
+ * run semantic3, and that may start CTFE again with a NULL istate. Thus
+ * the stack might not be empty when CTFE begins.
+ *
+ * Ctfe Stack addresses are just 0-based integers, but we save
+ * them as 'void *' because Array can only do pointers.
+ */
+ Expressions values; // values on the stack
+ VarDeclarations vars; // corresponding variables
+ Array!(void*) savedId; // id of the previous state of that var
+
+ Array!(void*) frames; // all previous frame pointers
+ Expressions savedThis; // all previous values of localThis
+
+ /* Global constants get saved here after evaluation, so we never
+ * have to redo them. This saves a lot of time and memory.
+ */
+ Expressions globalValues; // values of global constants
+
+ size_t framepointer; // current frame pointer
+ size_t maxStackPointer; // most stack we've ever used
+ Expression localThis; // value of 'this', or NULL if none
+
+public:
+ extern (C++) size_t stackPointer()
+ {
+ return values.dim;
+ }
+
+ // The current value of 'this', or NULL if none
+ extern (C++) Expression getThis()
+ {
+ return localThis;
+ }
+
+ // Largest number of stack positions we've used
+ extern (C++) size_t maxStackUsage()
+ {
+ return maxStackPointer;
+ }
+
+ // Start a new stack frame, using the provided 'this'.
+ extern (C++) void startFrame(Expression thisexp)
+ {
+ frames.push(cast(void*)cast(size_t)framepointer);
+ savedThis.push(localThis);
+ framepointer = stackPointer();
+ localThis = thisexp;
+ }
+
+ extern (C++) void endFrame()
+ {
+ size_t oldframe = cast(size_t)frames[frames.dim - 1];
+ localThis = savedThis[savedThis.dim - 1];
+ popAll(framepointer);
+ framepointer = oldframe;
+ frames.setDim(frames.dim - 1);
+ savedThis.setDim(savedThis.dim - 1);
+ }
+
+ extern (C++) bool isInCurrentFrame(VarDeclaration v)
+ {
+ if (v.isDataseg() && !v.isCTFE())
+ return false; // It's a global
+ return v.ctfeAdrOnStack >= framepointer;
+ }
+
+ extern (C++) Expression getValue(VarDeclaration v)
+ {
+ //printf("getValue() %s\n", v.toChars());
+ if ((v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE())
+ {
+ assert(v.ctfeAdrOnStack < globalValues.dim);
+ return globalValues[v.ctfeAdrOnStack];
+ }
+ assert(v.ctfeAdrOnStack < stackPointer());
+ return values[v.ctfeAdrOnStack];
+ }
+
+ extern (C++) void setValue(VarDeclaration v, Expression e)
+ {
+ //printf("setValue() %s : %s\n", v.toChars(), e.toChars());
+ assert(!v.isDataseg() || v.isCTFE());
+ assert(v.ctfeAdrOnStack < stackPointer());
+ values[v.ctfeAdrOnStack] = e;
+ }
+
+ extern (C++) void push(VarDeclaration v)
+ {
+ //printf("push() %s\n", v.toChars());
+ assert(!v.isDataseg() || v.isCTFE());
+ if (v.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone && v.ctfeAdrOnStack >= framepointer)
+ {
+ // Already exists in this frame, reuse it.
+ values[v.ctfeAdrOnStack] = null;
+ return;
+ }
+ savedId.push(cast(void*)cast(size_t)v.ctfeAdrOnStack);
+ v.ctfeAdrOnStack = cast(uint)values.dim;
+ vars.push(v);
+ values.push(null);
+ }
+
+ extern (C++) void pop(VarDeclaration v)
+ {
+ assert(!v.isDataseg() || v.isCTFE());
+ assert(!v.isReference());
+ const oldid = v.ctfeAdrOnStack;
+ v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[oldid];
+ if (v.ctfeAdrOnStack == values.dim - 1)
+ {
+ values.pop();
+ vars.pop();
+ savedId.pop();
+ }
+ }
+
+ extern (C++) void popAll(size_t stackpointer)
+ {
+ if (stackPointer() > maxStackPointer)
+ maxStackPointer = stackPointer();
+ assert(values.dim >= stackpointer);
+ for (size_t i = stackpointer; i < values.dim; ++i)
+ {
+ VarDeclaration v = vars[i];
+ v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[i];
+ }
+ values.setDim(stackpointer);
+ vars.setDim(stackpointer);
+ savedId.setDim(stackpointer);
+ }
+
+ extern (C++) void saveGlobalConstant(VarDeclaration v, Expression e)
+ {
+ assert(v._init && (v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !v.isCTFE());
+ v.ctfeAdrOnStack = cast(uint)globalValues.dim;
+ globalValues.push(copyRegionExp(e));
+ }
+}
+
+private struct InterState
+{
+ InterState* caller; // calling function's InterState
+ FuncDeclaration fd; // function being interpreted
+ Statement start; // if !=NULL, start execution at this statement
+
+ /* target of CTFEExp result; also
+ * target of labelled CTFEExp or
+ * CTFEExp. (null if no label).
+ */
+ Statement gotoTarget;
+}
+
+/*************************************
+ * Attempt to interpret a function given the arguments.
+ * Params:
+ * pue = storage for result
+ * fd = function being called
+ * istate = state for calling function (NULL if none)
+ * arguments = function arguments
+ * thisarg = 'this', if a needThis() function, NULL if not.
+ *
+ * Returns:
+ * result expression if successful, TOK.cantExpression if not,
+ * or CTFEExp if function returned void.
+ */
+private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterState* istate, Expressions* arguments, Expression thisarg)
+{
+ debug (LOG)
+ {
+ printf("\n********\n%s FuncDeclaration::interpret(istate = %p) %s\n", fd.loc.toChars(), istate, fd.toChars());
+ }
+ assert(pue);
+ if (fd.semanticRun == PASS.semantic3)
+ {
+ fd.error("circular dependency. Functions cannot be interpreted while being compiled");
+ return CTFEExp.cantexp;
+ }
+ if (!fd.functionSemantic3())
+ return CTFEExp.cantexp;
+ if (fd.semanticRun < PASS.semantic3done)
+ {
+ fd.error("circular dependency. Functions cannot be interpreted while being compiled");
+ return CTFEExp.cantexp;
+ }
+
+ auto tf = fd.type.toBasetype().isTypeFunction();
+ if (tf.parameterList.varargs != VarArg.none && arguments &&
+ ((fd.parameters && arguments.dim != fd.parameters.dim) || (!fd.parameters && arguments.dim)))
+ {
+ fd.error("C-style variadic functions are not yet implemented in CTFE");
+ return CTFEExp.cantexp;
+ }
+
+ // Nested functions always inherit the 'this' pointer from the parent,
+ // except for delegates. (Note that the 'this' pointer may be null).
+ // Func literals report isNested() even if they are in global scope,
+ // so we need to check that the parent is a function.
+ if (fd.isNested() && fd.toParentLocal().isFuncDeclaration() && !thisarg && istate)
+ thisarg = ctfeGlobals.stack.getThis();
+
+ if (fd.needThis() && !thisarg)
+ {
+ // error, no this. Prevent segfault.
+ // Here should be unreachable by the strict 'this' check in front-end.
+ fd.error("need `this` to access member `%s`", fd.toChars());
+ return CTFEExp.cantexp;
+ }
+
+ // Place to hold all the arguments to the function while
+ // we are evaluating them.
+ size_t dim = arguments ? arguments.dim : 0;
+ assert((fd.parameters ? fd.parameters.dim : 0) == dim);
+
+ /* Evaluate all the arguments to the function,
+ * store the results in eargs[]
+ */
+ Expressions eargs = Expressions(dim);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Expression earg = (*arguments)[i];
+ Parameter fparam = tf.parameterList[i];
+
+ if (fparam.isReference())
+ {
+ if (!istate && (fparam.storageClass & STC.out_))
+ {
+ // initializing an out parameter involves writing to it.
+ earg.error("global `%s` cannot be passed as an `out` parameter at compile time", earg.toChars());
+ return CTFEExp.cantexp;
+ }
+ // Convert all reference arguments into lvalue references
+ earg = interpretRegion(earg, istate, CTFEGoal.LValue);
+ if (CTFEExp.isCantExp(earg))
+ return earg;
+ }
+ else if (fparam.storageClass & STC.lazy_)
+ {
+ }
+ else
+ {
+ /* Value parameters
+ */
+ Type ta = fparam.type.toBasetype();
+ if (ta.ty == Tsarray)
+ if (auto eaddr = earg.isAddrExp())
+ {
+ /* Static arrays are passed by a simple pointer.
+ * Skip past this to get at the actual arg.
+ */
+ earg = eaddr.e1;
+ }
+
+ earg = interpretRegion(earg, istate);
+ if (CTFEExp.isCantExp(earg))
+ return earg;
+
+ /* Struct literals are passed by value, but we don't need to
+ * copy them if they are passed as const
+ */
+ if (earg.op == TOK.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_)))
+ earg = copyLiteral(earg).copy();
+ }
+ if (auto tee = earg.isThrownExceptionExp())
+ {
+ if (istate)
+ return tee;
+ tee.generateUncaughtError();
+ return CTFEExp.cantexp;
+ }
+ eargs[i] = earg;
+ }
+
+ // Now that we've evaluated all the arguments, we can start the frame
+ // (this is the moment when the 'call' actually takes place).
+ InterState istatex;
+ istatex.caller = istate;
+ istatex.fd = fd;
+
+ if (fd.isThis2)
+ {
+ Expression arg0 = thisarg;
+ if (arg0 && arg0.type.ty == Tstruct)
+ {
+ Type t = arg0.type.pointerTo();
+ arg0 = ctfeEmplaceExp!AddrExp(arg0.loc, arg0);
+ arg0.type = t;
+ }
+ auto elements = new Expressions(2);
+ (*elements)[0] = arg0;
+ (*elements)[1] = ctfeGlobals.stack.getThis();
+ Type t2 = Type.tvoidptr.sarrayOf(2);
+ const loc = thisarg ? thisarg.loc : fd.loc;
+ thisarg = ctfeEmplaceExp!ArrayLiteralExp(loc, t2, elements);
+ thisarg = ctfeEmplaceExp!AddrExp(loc, thisarg);
+ thisarg.type = t2.pointerTo();
+ }
+
+ ctfeGlobals.stack.startFrame(thisarg);
+ if (fd.vthis && thisarg)
+ {
+ ctfeGlobals.stack.push(fd.vthis);
+ setValue(fd.vthis, thisarg);
+ }
+
+ for (size_t i = 0; i < dim; i++)
+ {
+ Expression earg = eargs[i];
+ Parameter fparam = tf.parameterList[i];
+ VarDeclaration v = (*fd.parameters)[i];
+ debug (LOG)
+ {
+ printf("arg[%zu] = %s\n", i, earg.toChars());
+ }
+ ctfeGlobals.stack.push(v);
+
+ if (fparam.isReference() && earg.op == TOK.variable &&
+ earg.isVarExp().var.toParent2() == fd)
+ {
+ VarDeclaration vx = earg.isVarExp().var.isVarDeclaration();
+ if (!vx)
+ {
+ fd.error("cannot interpret `%s` as a `ref` parameter", earg.toChars());
+ return CTFEExp.cantexp;
+ }
+
+ /* vx is a variable that is declared in fd.
+ * It means that fd is recursively called. e.g.
+ *
+ * void fd(int n, ref int v = dummy) {
+ * int vx;
+ * if (n == 1) fd(2, vx);
+ * }
+ * fd(1);
+ *
+ * The old value of vx on the stack in fd(1)
+ * should be saved at the start of fd(2, vx) call.
+ */
+ const oldadr = vx.ctfeAdrOnStack;
+
+ ctfeGlobals.stack.push(vx);
+ assert(!hasValue(vx)); // vx is made uninitialized
+
+ // https://issues.dlang.org/show_bug.cgi?id=14299
+ // v.ctfeAdrOnStack should be saved already
+ // in the stack before the overwrite.
+ v.ctfeAdrOnStack = oldadr;
+ assert(hasValue(v)); // ref parameter v should refer existing value.
+ }
+ else
+ {
+ // Value parameters and non-trivial references
+ setValueWithoutChecking(v, earg);
+ }
+ debug (LOG)
+ {
+ printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
+ showCtfeExpr(earg);
+ }
+ debug (LOGASSIGN)
+ {
+ printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
+ showCtfeExpr(earg);
+ }
+ }
+
+ if (fd.vresult)
+ ctfeGlobals.stack.push(fd.vresult);
+
+ // Enter the function
+ ++ctfeGlobals.callDepth;
+ if (ctfeGlobals.callDepth > ctfeGlobals.maxCallDepth)
+ ctfeGlobals.maxCallDepth = ctfeGlobals.callDepth;
+
+ Expression e = null;
+ while (1)
+ {
+ if (ctfeGlobals.callDepth > CTFE_RECURSION_LIMIT)
+ {
+ // This is a compiler error. It must not be suppressed.
+ global.gag = 0;
+ fd.error("CTFE recursion limit exceeded");
+ e = CTFEExp.cantexp;
+ break;
+ }
+ e = interpret(pue, fd.fbody, &istatex);
+ if (CTFEExp.isCantExp(e))
+ {
+ debug (LOG)
+ {
+ printf("function body failed to interpret\n");
+ }
+ }
+
+ if (istatex.start)
+ {
+ fd.error("CTFE internal error: failed to resume at statement `%s`", istatex.start.toChars());
+ return CTFEExp.cantexp;
+ }
+
+ /* This is how we deal with a recursive statement AST
+ * that has arbitrary goto statements in it.
+ * Bubble up a 'result' which is the target of the goto
+ * statement, then go recursively down the AST looking
+ * for that statement, then execute starting there.
+ */
+ if (CTFEExp.isGotoExp(e))
+ {
+ istatex.start = istatex.gotoTarget; // set starting statement
+ istatex.gotoTarget = null;
+ }
+ else
+ {
+ assert(!e || (e.op != TOK.continue_ && e.op != TOK.break_));
+ break;
+ }
+ }
+ // If fell off the end of a void function, return void
+ if (!e && tf.next.ty == Tvoid)
+ e = CTFEExp.voidexp;
+ if (tf.isref && e.op == TOK.variable && e.isVarExp().var == fd.vthis)
+ e = thisarg;
+ if (tf.isref && fd.isThis2 && e.op == TOK.index)
+ {
+ auto ie = e.isIndexExp();
+ auto pe = ie.e1.isPtrExp();
+ auto ve = !pe ? null : pe.e1.isVarExp();
+ if (ve && ve.var == fd.vthis)
+ {
+ auto ne = ie.e2.isIntegerExp();
+ assert(ne);
+ auto ale = thisarg.isAddrExp().e1.isArrayLiteralExp();
+ e = (*ale.elements)[cast(size_t)ne.getInteger()];
+ if (auto ae = e.isAddrExp())
+ {
+ e = ae.e1;
+ }
+ }
+ }
+ assert(e !is null);
+
+ // Leave the function
+ --ctfeGlobals.callDepth;
+
+ ctfeGlobals.stack.endFrame();
+
+ // If it generated an uncaught exception, report error.
+ if (!istate && e.isThrownExceptionExp())
+ {
+ if (e == pue.exp())
+ e = pue.copy();
+ e.isThrownExceptionExp().generateUncaughtError();
+ e = CTFEExp.cantexp;
+ }
+
+ return e;
+}
+
+/// used to collect coverage information in ctfe
+void incUsageCtfe(InterState* istate, const ref Loc loc)
+{
+ if (global.params.ctfe_cov && istate)
+ {
+ auto line = loc.linnum;
+ auto mod = istate.fd.getModule();
+
+ ++mod.ctfe_cov[line];
+ }
+}
+
+private extern (C++) final class Interpreter : Visitor
+{
+ alias visit = Visitor.visit;
+public:
+ InterState* istate;
+ CTFEGoal goal;
+ Expression result;
+ UnionExp* pue; // storage for `result`
+
+ extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal)
+ {
+ this.pue = pue;
+ this.istate = istate;
+ this.goal = goal;
+ }
+
+ // If e is TOK.throw_exception or TOK.cantExpression,
+ // set it to 'result' and returns true.
+ bool exceptionOrCant(Expression e)
+ {
+ if (exceptionOrCantInterpret(e))
+ {
+ // Make sure e is not pointing to a stack temporary
+ result = (e.op == TOK.cantExpression) ? CTFEExp.cantexp : e;
+ return true;
+ }
+ return false;
+ }
+
+ static Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original)
+ {
+ if (exps is original)
+ {
+ if (!original)
+ exps = new Expressions();
+ else
+ exps = original.copy();
+ ++ctfeGlobals.numArrayAllocs;
+ }
+ return exps;
+ }
+
+ /******************************** Statement ***************************/
+
+ override void visit(Statement s)
+ {
+ debug (LOG)
+ {
+ printf("%s Statement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start)
+ {
+ if (istate.start != s)
+ return;
+ istate.start = null;
+ }
+
+ s.error("statement `%s` cannot be interpreted at compile time", s.toChars());
+ result = CTFEExp.cantexp;
+ }
+
+ override void visit(ExpStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s ExpStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
+ }
+ if (istate.start)
+ {
+ if (istate.start != s)
+ return;
+ istate.start = null;
+ }
+ if (s.exp && s.exp.hasCode)
+ incUsageCtfe(istate, s.loc);
+
+ Expression e = interpret(pue, s.exp, istate, CTFEGoal.Nothing);
+ if (exceptionOrCant(e))
+ return;
+ }
+
+ override void visit(CompoundStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s CompoundStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start == s)
+ istate.start = null;
+
+ const dim = s.statements ? s.statements.dim : 0;
+ foreach (i; 0 .. dim)
+ {
+ Statement sx = (*s.statements)[i];
+ result = interpret(pue, sx, istate);
+ if (result)
+ break;
+ }
+ debug (LOG)
+ {
+ printf("%s -CompoundStatement::interpret() %p\n", s.loc.toChars(), result);
+ }
+ }
+
+ override void visit(UnrolledLoopStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s UnrolledLoopStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start == s)
+ istate.start = null;
+
+ const dim = s.statements ? s.statements.dim : 0;
+ foreach (i; 0 .. dim)
+ {
+ Statement sx = (*s.statements)[i];
+ Expression e = interpret(pue, sx, istate);
+ if (!e) // succeeds to interpret, or goto target was not found
+ continue;
+ if (exceptionOrCant(e))
+ return;
+ if (e.op == TOK.break_)
+ {
+ if (istate.gotoTarget && istate.gotoTarget != s)
+ {
+ result = e; // break at a higher level
+ return;
+ }
+ istate.gotoTarget = null;
+ result = null;
+ return;
+ }
+ if (e.op == TOK.continue_)
+ {
+ if (istate.gotoTarget && istate.gotoTarget != s)
+ {
+ result = e; // continue at a higher level
+ return;
+ }
+ istate.gotoTarget = null;
+ continue;
+ }
+
+ // expression from return statement, or thrown exception
+ result = e;
+ break;
+ }
+ }
+
+ override void visit(IfStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s IfStatement::interpret(%s)\n", s.loc.toChars(), s.condition.toChars());
+ }
+ incUsageCtfe(istate, s.loc);
+ if (istate.start == s)
+ istate.start = null;
+ if (istate.start)
+ {
+ Expression e = null;
+ e = interpret(s.ifbody, istate);
+ if (!e && istate.start)
+ e = interpret(s.elsebody, istate);
+ result = e;
+ return;
+ }
+
+ UnionExp ue = void;
+ Expression e = interpret(&ue, s.condition, istate);
+ assert(e);
+ if (exceptionOrCant(e))
+ return;
+
+ if (isTrueBool(e))
+ result = interpret(pue, s.ifbody, istate);
+ else if (e.isBool(false))
+ result = interpret(pue, s.elsebody, istate);
+ else
+ {
+ // no error, or assert(0)?
+ result = CTFEExp.cantexp;
+ }
+ }
+
+ override void visit(ScopeStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s ScopeStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start == s)
+ istate.start = null;
+
+ result = interpret(pue, s.statement, istate);
+ }
+
+ /**
+ Given an expression e which is about to be returned from the current
+ function, generate an error if it contains pointers to local variables.
+
+ Only checks expressions passed by value (pointers to local variables
+ may already be stored in members of classes, arrays, or AAs which
+ were passed as mutable function parameters).
+ Returns:
+ true if it is safe to return, false if an error was generated.
+ */
+ static bool stopPointersEscaping(const ref Loc loc, Expression e)
+ {
+ if (!e.type.hasPointers())
+ return true;
+ if (isPointer(e.type))
+ {
+ Expression x = e;
+ if (auto eaddr = e.isAddrExp())
+ x = eaddr.e1;
+ VarDeclaration v;
+ while (x.op == TOK.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null)
+ {
+ if (v.storage_class & STC.ref_)
+ {
+ x = getValue(v);
+ if (auto eaddr = e.isAddrExp())
+ eaddr.e1 = x;
+ continue;
+ }
+ if (ctfeGlobals.stack.isInCurrentFrame(v))
+ {
+ error(loc, "returning a pointer to a local stack variable");
+ return false;
+ }
+ else
+ break;
+ }
+ // TODO: If it is a TOK.dotVariable or TOK.index, we should check that it is not
+ // pointing to a local struct or static array.
+ }
+ if (auto se = e.isStructLiteralExp())
+ {
+ return stopPointersEscapingFromArray(loc, se.elements);
+ }
+ if (auto ale = e.isArrayLiteralExp())
+ {
+ return stopPointersEscapingFromArray(loc, ale.elements);
+ }
+ if (auto aae = e.isAssocArrayLiteralExp())
+ {
+ if (!stopPointersEscapingFromArray(loc, aae.keys))
+ return false;
+ return stopPointersEscapingFromArray(loc, aae.values);
+ }
+ return true;
+ }
+
+ // Check all elements of an array for escaping local variables. Return false if error
+ static bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems)
+ {
+ foreach (e; *elems)
+ {
+ if (e && !stopPointersEscaping(loc, e))
+ return false;
+ }
+ return true;
+ }
+
+ override void visit(ReturnStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s ReturnStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
+ }
+ if (istate.start)
+ {
+ if (istate.start != s)
+ return;
+ istate.start = null;
+ }
+
+ if (!s.exp)
+ {
+ result = CTFEExp.voidexp;
+ return;
+ }
+
+ incUsageCtfe(istate, s.loc);
+ assert(istate && istate.fd && istate.fd.type && istate.fd.type.ty == Tfunction);
+ TypeFunction tf = cast(TypeFunction)istate.fd.type;
+
+ /* If the function returns a ref AND it's been called from an assignment,
+ * we need to return an lvalue. Otherwise, just do an (rvalue) interpret.
+ */
+ if (tf.isref)
+ {
+ result = interpret(pue, s.exp, istate, CTFEGoal.LValue);
+ return;
+ }
+ if (tf.next && tf.next.ty == Tdelegate && istate.fd.closureVars.dim > 0)
+ {
+ // To support this, we need to copy all the closure vars
+ // into the delegate literal.
+ s.error("closures are not yet supported in CTFE");
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ // We need to treat pointers specially, because TOK.symbolOffset can be used to
+ // return a value OR a pointer
+ Expression e = interpret(pue, s.exp, istate);
+ if (exceptionOrCant(e))
+ return;
+
+ // Disallow returning pointers to stack-allocated variables (bug 7876)
+ if (!stopPointersEscaping(s.loc, e))
+ {
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ if (needToCopyLiteral(e))
+ e = copyLiteral(e).copy();
+ debug (LOGASSIGN)
+ {
+ printf("RETURN %s\n", s.loc.toChars());
+ showCtfeExpr(e);
+ }
+ result = e;
+ }
+
+ static Statement findGotoTarget(InterState* istate, Identifier ident)
+ {
+ Statement target = null;
+ if (ident)
+ {
+ LabelDsymbol label = istate.fd.searchLabel(ident);
+ assert(label && label.statement);
+ LabelStatement ls = label.statement;
+ target = ls.gotoTarget ? ls.gotoTarget : ls.statement;
+ }
+ return target;
+ }
+
+ override void visit(BreakStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s BreakStatement::interpret()\n", s.loc.toChars());
+ }
+ incUsageCtfe(istate, s.loc);
+ if (istate.start)
+ {
+ if (istate.start != s)
+ return;
+ istate.start = null;
+ }
+
+ istate.gotoTarget = findGotoTarget(istate, s.ident);
+ result = CTFEExp.breakexp;
+ }
+
+ override void visit(ContinueStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s ContinueStatement::interpret()\n", s.loc.toChars());
+ }
+ incUsageCtfe(istate, s.loc);
+ if (istate.start)
+ {
+ if (istate.start != s)
+ return;
+ istate.start = null;
+ }
+
+ istate.gotoTarget = findGotoTarget(istate, s.ident);
+ result = CTFEExp.continueexp;
+ }
+
+ override void visit(WhileStatement s)
+ {
+ debug (LOG)
+ {
+ printf("WhileStatement::interpret()\n");
+ }
+ assert(0); // rewritten to ForStatement
+ }
+
+ override void visit(DoStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s DoStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start == s)
+ istate.start = null;
+
+ while (1)
+ {
+ Expression e = interpret(s._body, istate);
+ if (!e && istate.start) // goto target was not found
+ return;
+ assert(!istate.start);
+
+ if (exceptionOrCant(e))
+ return;
+ if (e && e.op == TOK.break_)
+ {
+ if (istate.gotoTarget && istate.gotoTarget != s)
+ {
+ result = e; // break at a higher level
+ return;
+ }
+ istate.gotoTarget = null;
+ break;
+ }
+ if (e && e.op == TOK.continue_)
+ {
+ if (istate.gotoTarget && istate.gotoTarget != s)
+ {
+ result = e; // continue at a higher level
+ return;
+ }
+ istate.gotoTarget = null;
+ e = null;
+ }
+ if (e)
+ {
+ result = e; // bubbled up from ReturnStatement
+ return;
+ }
+
+ UnionExp ue = void;
+ incUsageCtfe(istate, s.condition.loc);
+ e = interpret(&ue, s.condition, istate);
+ if (exceptionOrCant(e))
+ return;
+ if (!e.isConst())
+ {
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (e.isBool(false))
+ break;
+ assert(isTrueBool(e));
+ }
+ assert(result is null);
+ }
+
+ override void visit(ForStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s ForStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start == s)
+ istate.start = null;
+
+ UnionExp ueinit = void;
+ Expression ei = interpret(&ueinit, s._init, istate);
+ if (exceptionOrCant(ei))
+ return;
+ assert(!ei); // s.init never returns from function, or jumps out from it
+
+ while (1)
+ {
+ if (s.condition && !istate.start)
+ {
+ UnionExp ue = void;
+ incUsageCtfe(istate, s.condition.loc);
+ Expression e = interpret(&ue, s.condition, istate);
+ if (exceptionOrCant(e))
+ return;
+ if (e.isBool(false))
+ break;
+ assert(isTrueBool(e));
+ }
+
+ Expression e = interpret(pue, s._body, istate);
+ if (!e && istate.start) // goto target was not found
+ return;
+ assert(!istate.start);
+
+ if (exceptionOrCant(e))
+ return;
+ if (e && e.op == TOK.break_)
+ {
+ if (istate.gotoTarget && istate.gotoTarget != s)
+ {
+ result = e; // break at a higher level
+ return;
+ }
+ istate.gotoTarget = null;
+ break;
+ }
+ if (e && e.op == TOK.continue_)
+ {
+ if (istate.gotoTarget && istate.gotoTarget != s)
+ {
+ result = e; // continue at a higher level
+ return;
+ }
+ istate.gotoTarget = null;
+ e = null;
+ }
+ if (e)
+ {
+ result = e; // bubbled up from ReturnStatement
+ return;
+ }
+
+ UnionExp uei = void;
+ if (s.increment)
+ incUsageCtfe(istate, s.increment.loc);
+ e = interpret(&uei, s.increment, istate, CTFEGoal.Nothing);
+ if (exceptionOrCant(e))
+ return;
+ }
+ assert(result is null);
+ }
+
+ override void visit(ForeachStatement s)
+ {
+ assert(0); // rewritten to ForStatement
+ }
+
+ override void visit(ForeachRangeStatement s)
+ {
+ assert(0); // rewritten to ForStatement
+ }
+
+ override void visit(SwitchStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s SwitchStatement::interpret()\n", s.loc.toChars());
+ }
+ incUsageCtfe(istate, s.loc);
+ if (istate.start == s)
+ istate.start = null;
+ if (istate.start)
+ {
+ Expression e = interpret(s._body, istate);
+ if (istate.start) // goto target was not found
+ return;
+ if (exceptionOrCant(e))
+ return;
+ if (e && e.op == TOK.break_)
+ {
+ if (istate.gotoTarget && istate.gotoTarget != s)
+ {
+ result = e; // break at a higher level
+ return;
+ }
+ istate.gotoTarget = null;
+ e = null;
+ }
+ result = e;
+ return;
+ }
+
+ UnionExp uecond = void;
+ Expression econdition = interpret(&uecond, s.condition, istate);
+ if (exceptionOrCant(econdition))
+ return;
+
+ Statement scase = null;
+ if (s.cases)
+ foreach (cs; *s.cases)
+ {
+ UnionExp uecase = void;
+ Expression ecase = interpret(&uecase, cs.exp, istate);
+ if (exceptionOrCant(ecase))
+ return;
+ if (ctfeEqual(cs.exp.loc, TOK.equal, econdition, ecase))
+ {
+ scase = cs;
+ break;
+ }
+ }
+ if (!scase)
+ {
+ if (s.hasNoDefault)
+ s.error("no `default` or `case` for `%s` in `switch` statement", econdition.toChars());
+ scase = s.sdefault;
+ }
+
+ assert(scase);
+
+ /* Jump to scase
+ */
+ istate.start = scase;
+ Expression e = interpret(pue, s._body, istate);
+ assert(!istate.start); // jump must not fail
+ if (e && e.op == TOK.break_)
+ {
+ if (istate.gotoTarget && istate.gotoTarget != s)
+ {
+ result = e; // break at a higher level
+ return;
+ }
+ istate.gotoTarget = null;
+ e = null;
+ }
+ result = e;
+ }
+
+ override void visit(CaseStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s CaseStatement::interpret(%s) this = %p\n", s.loc.toChars(), s.exp.toChars(), s);
+ }
+ incUsageCtfe(istate, s.loc);
+ if (istate.start == s)
+ istate.start = null;
+
+ result = interpret(pue, s.statement, istate);
+ }
+
+ override void visit(DefaultStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s DefaultStatement::interpret()\n", s.loc.toChars());
+ }
+ incUsageCtfe(istate, s.loc);
+ if (istate.start == s)
+ istate.start = null;
+
+ result = interpret(pue, s.statement, istate);
+ }
+
+ override void visit(GotoStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s GotoStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start)
+ {
+ if (istate.start != s)
+ return;
+ istate.start = null;
+ }
+ incUsageCtfe(istate, s.loc);
+
+ assert(s.label && s.label.statement);
+ istate.gotoTarget = s.label.statement;
+ result = CTFEExp.gotoexp;
+ }
+
+ override void visit(GotoCaseStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s GotoCaseStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start)
+ {
+ if (istate.start != s)
+ return;
+ istate.start = null;
+ }
+ incUsageCtfe(istate, s.loc);
+
+ assert(s.cs);
+ istate.gotoTarget = s.cs;
+ result = CTFEExp.gotoexp;
+ }
+
+ override void visit(GotoDefaultStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s GotoDefaultStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start)
+ {
+ if (istate.start != s)
+ return;
+ istate.start = null;
+ }
+ incUsageCtfe(istate, s.loc);
+
+ assert(s.sw && s.sw.sdefault);
+ istate.gotoTarget = s.sw.sdefault;
+ result = CTFEExp.gotoexp;
+ }
+
+ override void visit(LabelStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s LabelStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start == s)
+ istate.start = null;
+
+ result = interpret(pue, s.statement, istate);
+ }
+
+ override void visit(TryCatchStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s TryCatchStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start == s)
+ istate.start = null;
+ if (istate.start)
+ {
+ Expression e = null;
+ e = interpret(pue, s._body, istate);
+ foreach (ca; *s.catches)
+ {
+ if (e || !istate.start) // goto target was found
+ break;
+ e = interpret(pue, ca.handler, istate);
+ }
+ result = e;
+ return;
+ }
+
+ Expression e = interpret(s._body, istate);
+
+ // An exception was thrown
+ if (e && e.isThrownExceptionExp())
+ {
+ ThrownExceptionExp ex = e.isThrownExceptionExp();
+ Type extype = ex.thrown.originalClass().type;
+
+ // Search for an appropriate catch clause.
+ foreach (ca; *s.catches)
+ {
+ Type catype = ca.type;
+ if (!catype.equals(extype) && !catype.isBaseOf(extype, null))
+ continue;
+
+ // Execute the handler
+ if (ca.var)
+ {
+ ctfeGlobals.stack.push(ca.var);
+ setValue(ca.var, ex.thrown);
+ }
+ e = interpret(ca.handler, istate);
+ if (CTFEExp.isGotoExp(e))
+ {
+ /* This is an optimization that relies on the locality of the jump target.
+ * If the label is in the same catch handler, the following scan
+ * would find it quickly and can reduce jump cost.
+ * Otherwise, the catch block may be unnnecessary scanned again
+ * so it would make CTFE speed slower.
+ */
+ InterState istatex = *istate;
+ istatex.start = istate.gotoTarget; // set starting statement
+ istatex.gotoTarget = null;
+ Expression eh = interpret(ca.handler, &istatex);
+ if (!istatex.start)
+ {
+ istate.gotoTarget = null;
+ e = eh;
+ }
+ }
+ break;
+ }
+ }
+ result = e;
+ }
+
+ static bool isAnErrorException(ClassDeclaration cd)
+ {
+ return cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null);
+ }
+
+ static ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp newest)
+ {
+ debug (LOG)
+ {
+ printf("Collided exceptions %s %s\n", oldest.thrown.toChars(), newest.thrown.toChars());
+ }
+ // Little sanity check to make sure it's really a Throwable
+ ClassReferenceExp boss = oldest.thrown;
+ const next = 4; // index of Throwable.next
+ assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next
+ ClassReferenceExp collateral = newest.thrown;
+ if (isAnErrorException(collateral.originalClass()) && !isAnErrorException(boss.originalClass()))
+ {
+ /* Find the index of the Error.bypassException field
+ */
+ auto bypass = next + 1;
+ if ((*collateral.value.elements)[bypass].type.ty == Tuns32)
+ bypass += 1; // skip over _refcount field
+ assert((*collateral.value.elements)[bypass].type.ty == Tclass);
+
+ // The new exception bypass the existing chain
+ (*collateral.value.elements)[bypass] = boss;
+ return newest;
+ }
+ while ((*boss.value.elements)[next].op == TOK.classReference)
+ {
+ boss = cast(ClassReferenceExp)(*boss.value.elements)[next];
+ }
+ (*boss.value.elements)[next] = collateral;
+ return oldest;
+ }
+
+ override void visit(TryFinallyStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s TryFinallyStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start == s)
+ istate.start = null;
+ if (istate.start)
+ {
+ Expression e = null;
+ e = interpret(pue, s._body, istate);
+ // Jump into/out from finalbody is disabled in semantic analysis.
+ // and jump inside will be handled by the ScopeStatement == finalbody.
+ result = e;
+ return;
+ }
+
+ Expression ex = interpret(s._body, istate);
+ if (CTFEExp.isCantExp(ex))
+ {
+ result = ex;
+ return;
+ }
+ while (CTFEExp.isGotoExp(ex))
+ {
+ // If the goto target is within the body, we must not interpret the finally statement,
+ // because that will call destructors for objects within the scope, which we should not do.
+ InterState istatex = *istate;
+ istatex.start = istate.gotoTarget; // set starting statement
+ istatex.gotoTarget = null;
+ Expression bex = interpret(s._body, &istatex);
+ if (istatex.start)
+ {
+ // The goto target is outside the current scope.
+ break;
+ }
+ // The goto target was within the body.
+ if (CTFEExp.isCantExp(bex))
+ {
+ result = bex;
+ return;
+ }
+ *istate = istatex;
+ ex = bex;
+ }
+
+ Expression ey = interpret(s.finalbody, istate);
+ if (CTFEExp.isCantExp(ey))
+ {
+ result = ey;
+ return;
+ }
+ if (ey && ey.isThrownExceptionExp())
+ {
+ // Check for collided exceptions
+ if (ex && ex.isThrownExceptionExp())
+ ex = chainExceptions(ex.isThrownExceptionExp(), ey.isThrownExceptionExp());
+ else
+ ex = ey;
+ }
+ result = ex;
+ }
+
+ override void visit(ThrowStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s ThrowStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start)
+ {
+ if (istate.start != s)
+ return;
+ istate.start = null;
+ }
+
+ incUsageCtfe(istate, s.loc);
+
+ Expression e = interpretRegion(s.exp, istate);
+ if (exceptionOrCant(e))
+ return;
+
+ assert(e.op == TOK.classReference);
+ result = ctfeEmplaceExp!ThrownExceptionExp(s.loc, e.isClassReferenceExp());
+ }
+
+ override void visit(ScopeGuardStatement s)
+ {
+ assert(0);
+ }
+
+ override void visit(WithStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s WithStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start == s)
+ istate.start = null;
+ if (istate.start)
+ {
+ result = s._body ? interpret(s._body, istate) : null;
+ return;
+ }
+
+ // If it is with(Enum) {...}, just execute the body.
+ if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type)
+ {
+ result = interpret(pue, s._body, istate);
+ return;
+ }
+
+ incUsageCtfe(istate, s.loc);
+
+ Expression e = interpret(s.exp, istate);
+ if (exceptionOrCant(e))
+ return;
+
+ if (s.wthis.type.ty == Tpointer && s.exp.type.ty != Tpointer)
+ {
+ e = ctfeEmplaceExp!AddrExp(s.loc, e, s.wthis.type);
+ }
+ ctfeGlobals.stack.push(s.wthis);
+ setValue(s.wthis, e);
+ e = interpret(s._body, istate);
+ if (CTFEExp.isGotoExp(e))
+ {
+ /* This is an optimization that relies on the locality of the jump target.
+ * If the label is in the same WithStatement, the following scan
+ * would find it quickly and can reduce jump cost.
+ * Otherwise, the statement body may be unnnecessary scanned again
+ * so it would make CTFE speed slower.
+ */
+ InterState istatex = *istate;
+ istatex.start = istate.gotoTarget; // set starting statement
+ istatex.gotoTarget = null;
+ Expression ex = interpret(s._body, &istatex);
+ if (!istatex.start)
+ {
+ istate.gotoTarget = null;
+ e = ex;
+ }
+ }
+ ctfeGlobals.stack.pop(s.wthis);
+ result = e;
+ }
+
+ override void visit(AsmStatement s)
+ {
+ debug (LOG)
+ {
+ printf("%s AsmStatement::interpret()\n", s.loc.toChars());
+ }
+ if (istate.start)
+ {
+ if (istate.start != s)
+ return;
+ istate.start = null;
+ }
+ s.error("`asm` statements cannot be interpreted at compile time");
+ result = CTFEExp.cantexp;
+ }
+
+ override void visit(ImportStatement s)
+ {
+ debug (LOG)
+ {
+ printf("ImportStatement::interpret()\n");
+ }
+ if (istate.start)
+ {
+ if (istate.start != s)
+ return;
+ istate.start = null;
+ }
+ }
+
+ /******************************** Expression ***************************/
+
+ override void visit(Expression e)
+ {
+ debug (LOG)
+ {
+ printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars());
+ printf("type = %s\n", e.type.toChars());
+ showCtfeExpr(e);
+ }
+ e.error("cannot interpret `%s` at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ }
+
+ override void visit(TypeExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s TypeExp.interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ result = e;
+ }
+
+ override void visit(ThisExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s ThisExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ if (goal == CTFEGoal.LValue)
+ {
+ // We might end up here with istate being zero
+ // https://issues.dlang.org/show_bug.cgi?id=16382
+ if (istate && istate.fd.vthis)
+ {
+ result = ctfeEmplaceExp!VarExp(e.loc, istate.fd.vthis);
+ if (istate.fd.isThis2)
+ {
+ result = ctfeEmplaceExp!PtrExp(e.loc, result);
+ result.type = Type.tvoidptr.sarrayOf(2);
+ result = ctfeEmplaceExp!IndexExp(e.loc, result, IntegerExp.literal!0);
+ }
+ result.type = e.type;
+ }
+ else
+ result = e;
+ return;
+ }
+
+ result = ctfeGlobals.stack.getThis();
+ if (result)
+ {
+ if (istate && istate.fd.isThis2)
+ {
+ assert(result.op == TOK.address);
+ result = (cast(AddrExp)result).e1;
+ assert(result.op == TOK.arrayLiteral);
+ result = (*(cast(ArrayLiteralExp)result).elements)[0];
+ if (e.type.ty == Tstruct)
+ {
+ result = (cast(AddrExp)result).e1;
+ }
+ return;
+ }
+ assert(result.op == TOK.structLiteral || result.op == TOK.classReference || result.op == TOK.type);
+ return;
+ }
+ e.error("value of `this` is not known at compile time");
+ result = CTFEExp.cantexp;
+ }
+
+ override void visit(NullExp e)
+ {
+ result = e;
+ }
+
+ override void visit(IntegerExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s IntegerExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ result = e;
+ }
+
+ override void visit(RealExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s RealExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ result = e;
+ }
+
+ override void visit(ComplexExp e)
+ {
+ result = e;
+ }
+
+ override void visit(StringExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s StringExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ /* Attempts to modify string literals are prevented
+ * in BinExp::interpretAssignCommon.
+ */
+ result = e;
+ }
+
+ override void visit(FuncExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s FuncExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ result = e;
+ }
+
+ override void visit(SymOffExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s SymOffExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ if (e.var.isFuncDeclaration() && e.offset == 0)
+ {
+ result = e;
+ return;
+ }
+ if (isTypeInfo_Class(e.type) && e.offset == 0)
+ {
+ result = e;
+ return;
+ }
+ if (e.type.ty != Tpointer)
+ {
+ // Probably impossible
+ e.error("cannot interpret `%s` at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ Type pointee = (cast(TypePointer)e.type).next;
+ if (e.var.isThreadlocal())
+ {
+ e.error("cannot take address of thread-local variable %s at compile time", e.var.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ // Check for taking an address of a shared variable.
+ // If the shared variable is an array, the offset might not be zero.
+ Type fromType = null;
+ if (e.var.type.ty == Tarray || e.var.type.ty == Tsarray)
+ {
+ fromType = (cast(TypeArray)e.var.type).next;
+ }
+ if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) || (fromType && isSafePointerCast(fromType, pointee))))
+ {
+ result = e;
+ return;
+ }
+
+ Expression val = getVarExp(e.loc, istate, e.var, goal);
+ if (exceptionOrCant(val))
+ return;
+ if (val.type.ty == Tarray || val.type.ty == Tsarray)
+ {
+ // Check for unsupported type painting operations
+ Type elemtype = (cast(TypeArray)val.type).next;
+ d_uns64 elemsize = elemtype.size();
+
+ // It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*.
+ if (val.type.ty == Tsarray && pointee.ty == Tsarray && elemsize == pointee.nextOf().size())
+ {
+ size_t d = cast(size_t)(cast(TypeSArray)pointee).dim.toInteger();
+ Expression elwr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize, Type.tsize_t);
+ Expression eupr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize + d, Type.tsize_t);
+
+ // Create a CTFE pointer &val[ofs..ofs+d]
+ auto se = ctfeEmplaceExp!SliceExp(e.loc, val, elwr, eupr);
+ se.type = pointee;
+ emplaceExp!(AddrExp)(pue, e.loc, se, e.type);
+ result = pue.exp();
+ return;
+ }
+
+ if (!isSafePointerCast(elemtype, pointee))
+ {
+ // It's also OK to cast from &string to string*.
+ if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
+ {
+ // Create a CTFE pointer &var
+ auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
+ ve.type = elemtype;
+ emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
+ result = pue.exp();
+ return;
+ }
+ e.error("reinterpreting cast from `%s` to `%s` is not supported in CTFE", val.type.toChars(), e.type.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ const dinteger_t sz = pointee.size();
+ dinteger_t indx = e.offset / sz;
+ assert(sz * indx == e.offset);
+ Expression aggregate = null;
+ if (val.op == TOK.arrayLiteral || val.op == TOK.string_)
+ {
+ aggregate = val;
+ }
+ else if (auto se = val.isSliceExp())
+ {
+ aggregate = se.e1;
+ UnionExp uelwr = void;
+ Expression lwr = interpret(&uelwr, se.lwr, istate);
+ indx += lwr.toInteger();
+ }
+ if (aggregate)
+ {
+ // Create a CTFE pointer &aggregate[ofs]
+ auto ofs = ctfeEmplaceExp!IntegerExp(e.loc, indx, Type.tsize_t);
+ auto ei = ctfeEmplaceExp!IndexExp(e.loc, aggregate, ofs);
+ ei.type = elemtype;
+ emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
+ result = pue.exp();
+ return;
+ }
+ }
+ else if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
+ {
+ // Create a CTFE pointer &var
+ auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
+ ve.type = e.var.type;
+ emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
+ result = pue.exp();
+ return;
+ }
+
+ e.error("cannot convert `&%s` to `%s` at compile time", e.var.type.toChars(), e.type.toChars());
+ result = CTFEExp.cantexp;
+ }
+
+ override void visit(AddrExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s AddrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ if (auto ve = e.e1.isVarExp())
+ {
+ Declaration decl = ve.var;
+
+ // We cannot take the address of an imported symbol at compile time
+ if (decl.isImportedSymbol()) {
+ e.error("cannot take address of imported symbol `%s` at compile time", decl.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ if (decl.isDataseg()) {
+ // Normally this is already done by optimize()
+ // Do it here in case optimize(WANTvalue) wasn't run before CTFE
+ emplaceExp!(SymOffExp)(pue, e.loc, (cast(VarExp)e.e1).var, 0);
+ result = pue.exp();
+ result.type = e.type;
+ return;
+ }
+ }
+ auto er = interpret(e.e1, istate, CTFEGoal.LValue);
+ if (auto ve = er.isVarExp())
+ if (ve.var == istate.fd.vthis)
+ er = interpret(er, istate);
+
+ if (exceptionOrCant(er))
+ return;
+
+ // Return a simplified address expression
+ emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
+ result = pue.exp();
+ }
+
+ override void visit(DelegateExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s DelegateExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ // TODO: Really we should create a CTFE-only delegate expression
+ // of a pointer and a funcptr.
+
+ // If it is &nestedfunc, just return it
+ // TODO: We should save the context pointer
+ if (auto ve1 = e.e1.isVarExp())
+ if (ve1.var == e.func)
+ {
+ result = e;
+ return;
+ }
+
+ auto er = interpret(pue, e.e1, istate);
+ if (exceptionOrCant(er))
+ return;
+ if (er == e.e1)
+ {
+ // If it has already been CTFE'd, just return it
+ result = e;
+ }
+ else
+ {
+ er = (er == pue.exp()) ? pue.copy() : er;
+ emplaceExp!(DelegateExp)(pue, e.loc, er, e.func, false);
+ result = pue.exp();
+ result.type = e.type;
+ }
+ }
+
+ static Expression getVarExp(const ref Loc loc, InterState* istate, Declaration d, CTFEGoal goal)
+ {
+ Expression e = CTFEExp.cantexp;
+ if (VarDeclaration v = d.isVarDeclaration())
+ {
+ /* Magic variable __ctfe always returns true when interpreting
+ */
+ if (v.ident == Id.ctfe)
+ return IntegerExp.createBool(true);
+
+ if (!v.originalType && v.semanticRun < PASS.semanticdone) // semantic() not yet run
+ {
+ v.dsymbolSemantic(null);
+ if (v.type.ty == Terror)
+ return CTFEExp.cantexp;
+ }
+
+ if ((v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !hasValue(v) && v._init && !v.isCTFE())
+ {
+ if (v.inuse)
+ {
+ error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
+ return CTFEExp.cantexp;
+ }
+ if (v._scope)
+ {
+ v.inuse++;
+ v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret); // might not be run on aggregate members
+ v.inuse--;
+ }
+ e = v._init.initializerToExpression(v.type);
+ if (!e)
+ return CTFEExp.cantexp;
+ assert(e.type);
+
+ if (e.op == TOK.construct || e.op == TOK.blit)
+ {
+ AssignExp ae = cast(AssignExp)e;
+ e = ae.e2;
+ }
+
+ if (e.op == TOK.error)
+ {
+ // FIXME: Ultimately all errors should be detected in prior semantic analysis stage.
+ }
+ else if (v.isDataseg() || (v.storage_class & STC.manifest))
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=14304
+ * e is a value that is not yet owned by CTFE.
+ * Mark as "cached", and use it directly during interpretation.
+ */
+ e = scrubCacheValue(e);
+ ctfeGlobals.stack.saveGlobalConstant(v, e);
+ }
+ else
+ {
+ v.inuse++;
+ e = interpret(e, istate);
+ v.inuse--;
+ if (CTFEExp.isCantExp(e) && !global.gag && !ctfeGlobals.stackTraceCallsToSuppress)
+ errorSupplemental(loc, "while evaluating %s.init", v.toChars());
+ if (exceptionOrCantInterpret(e))
+ return e;
+ }
+ }
+ else if (v.isCTFE() && !hasValue(v))
+ {
+ if (v._init && v.type.size() != 0)
+ {
+ if (v._init.isVoidInitializer())
+ {
+ // var should have been initialized when it was created
+ error(loc, "CTFE internal error: trying to access uninitialized var");
+ assert(0);
+ }
+ e = v._init.initializerToExpression();
+ }
+ else
+ // Zero-length arrays don't have an initializer
+ e = v.type.defaultInitLiteral(e.loc);
+
+ e = interpret(e, istate);
+ }
+ else if (!(v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE() && !istate)
+ {
+ error(loc, "variable `%s` cannot be read at compile time", v.toChars());
+ return CTFEExp.cantexp;
+ }
+ else
+ {
+ e = hasValue(v) ? getValue(v) : null;
+ if (!e)
+ {
+ // Zero-length arrays don't have an initializer
+ if (v.type.size() == 0)
+ e = v.type.defaultInitLiteral(loc);
+ else if (!v.isCTFE() && v.isDataseg())
+ {
+ error(loc, "static variable `%s` cannot be read at compile time", v.toChars());
+ return CTFEExp.cantexp;
+ }
+ else
+ {
+ assert(!(v._init && v._init.isVoidInitializer()));
+ // CTFE initiated from inside a function
+ error(loc, "variable `%s` cannot be read at compile time", v.toChars());
+ return CTFEExp.cantexp;
+ }
+ }
+ if (auto vie = e.isVoidInitExp())
+ {
+ error(loc, "cannot read uninitialized variable `%s` in ctfe", v.toPrettyChars());
+ errorSupplemental(vie.var.loc, "`%s` was uninitialized and used before set", vie.var.toChars());
+ return CTFEExp.cantexp;
+ }
+ if (goal != CTFEGoal.LValue && v.isReference())
+ e = interpret(e, istate, goal);
+ }
+ if (!e)
+ e = CTFEExp.cantexp;
+ }
+ else if (SymbolDeclaration s = d.isSymbolDeclaration())
+ {
+ // Struct static initializers, for example
+ e = s.dsym.type.defaultInitLiteral(loc);
+ if (e.op == TOK.error)
+ error(loc, "CTFE failed because of previous errors in `%s.init`", s.toChars());
+ e = e.expressionSemantic(null);
+ if (e.op == TOK.error)
+ e = CTFEExp.cantexp;
+ else // Convert NULL to CTFEExp
+ e = interpret(e, istate, goal);
+ }
+ else
+ error(loc, "cannot interpret declaration `%s` at compile time", d.toChars());
+ return e;
+ }
+
+ override void visit(VarExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s VarExp::interpret() `%s`, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
+ }
+ if (e.var.isFuncDeclaration())
+ {
+ result = e;
+ return;
+ }
+
+ // Note: This is a workaround for
+ // https://issues.dlang.org/show_bug.cgi?id=17351
+ // The aforementioned bug triggers when passing manifest constant by `ref`.
+ // If there was not a previous reference to them, they are
+ // not cached and trigger a "cannot be read at compile time".
+ // This fix is a crude solution to get it to work. A more proper
+ // approach would be to resolve the forward reference, but that is
+ // much more involved.
+ if (goal == CTFEGoal.LValue && e.var.type.isMutable())
+ {
+ if (auto v = e.var.isVarDeclaration())
+ {
+ if (!v.isDataseg() && !v.isCTFE() && !istate)
+ {
+ e.error("variable `%s` cannot be read at compile time", v.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (!hasValue(v))
+ {
+ if (!v.isCTFE() && v.isDataseg())
+ e.error("static variable `%s` cannot be read at compile time", v.toChars());
+ else // CTFE initiated from inside a function
+ e.error("variable `%s` cannot be read at compile time", v.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ if (v.storage_class & (STC.out_ | STC.ref_))
+ {
+ // Strip off the nest of ref variables
+ Expression ev = getValue(v);
+ if (ev.op == TOK.variable ||
+ ev.op == TOK.index ||
+ ev.op == TOK.slice ||
+ ev.op == TOK.dotVariable)
+ {
+ result = interpret(pue, ev, istate, goal);
+ return;
+ }
+ }
+ }
+ result = e;
+ return;
+ }
+ result = getVarExp(e.loc, istate, e.var, goal);
+ if (exceptionOrCant(result))
+ return;
+
+ // Visit the default initializer for noreturn variables
+ // (Custom initializers would abort the current function call and exit above)
+ if (result.type.ty == Tnoreturn)
+ {
+ result.accept(this);
+ return;
+ }
+
+ if ((e.var.storage_class & (STC.ref_ | STC.out_)) == 0 && e.type.baseElemOf().ty != Tstruct)
+ {
+ /* Ultimately, STC.ref_|STC.out_ check should be enough to see the
+ * necessity of type repainting. But currently front-end paints
+ * non-ref struct variables by the const type.
+ *
+ * auto foo(ref const S cs);
+ * S s;
+ * foo(s); // VarExp('s') will have const(S)
+ */
+ // A VarExp may include an implicit cast. It must be done explicitly.
+ result = paintTypeOntoLiteral(pue, e.type, result);
+ }
+ }
+
+ override void visit(DeclarationExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s DeclarationExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ Dsymbol s = e.declaration;
+ while (s.isAttribDeclaration())
+ {
+ auto ad = cast(AttribDeclaration)s;
+ assert(ad.decl && ad.decl.dim == 1); // Currently, only one allowed when parsing
+ s = (*ad.decl)[0];
+ }
+ if (VarDeclaration v = s.isVarDeclaration())
+ {
+ if (TupleDeclaration td = v.toAlias().isTupleDeclaration())
+ {
+ result = null;
+
+ // Reserve stack space for all tuple members
+ if (!td.objects)
+ return;
+ foreach (o; *td.objects)
+ {
+ Expression ex = isExpression(o);
+ DsymbolExp ds = ex ? ex.isDsymbolExp() : null;
+ VarDeclaration v2 = ds ? ds.s.isVarDeclaration() : null;
+ assert(v2);
+ if (v2.isDataseg() && !v2.isCTFE())
+ continue;
+
+ ctfeGlobals.stack.push(v2);
+ if (v2._init)
+ {
+ Expression einit;
+ if (ExpInitializer ie = v2._init.isExpInitializer())
+ {
+ einit = interpretRegion(ie.exp, istate, goal);
+ if (exceptionOrCant(einit))
+ return;
+ }
+ else if (v2._init.isVoidInitializer())
+ {
+ einit = voidInitLiteral(v2.type, v2).copy();
+ }
+ else
+ {
+ e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ setValue(v2, einit);
+ }
+ }
+ return;
+ }
+ if (v.isStatic())
+ {
+ // Just ignore static variables which aren't read or written yet
+ result = null;
+ return;
+ }
+ if (!(v.isDataseg() || v.storage_class & STC.manifest) || v.isCTFE())
+ ctfeGlobals.stack.push(v);
+ if (v._init)
+ {
+ if (ExpInitializer ie = v._init.isExpInitializer())
+ {
+ result = interpretRegion(ie.exp, istate, goal);
+ }
+ else if (v._init.isVoidInitializer())
+ {
+ result = voidInitLiteral(v.type, v).copy();
+ // There is no AssignExp for void initializers,
+ // so set it here.
+ setValue(v, result);
+ }
+ else
+ {
+ e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
+ result = CTFEExp.cantexp;
+ }
+ }
+ else if (v.type.size() == 0)
+ {
+ // Zero-length arrays don't need an initializer
+ result = v.type.defaultInitLiteral(e.loc);
+ }
+ else
+ {
+ e.error("variable `%s` cannot be modified at compile time", v.toChars());
+ result = CTFEExp.cantexp;
+ }
+ return;
+ }
+ if (s.isTemplateMixin() || s.isTupleDeclaration())
+ {
+ // These can be made to work, too lazy now
+ e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ // Others should not contain executable code, so are trivial to evaluate
+ result = null;
+ debug (LOG)
+ {
+ printf("-DeclarationExp::interpret(%s): %p\n", e.toChars(), result);
+ }
+ }
+
+ override void visit(TypeidExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s TypeidExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ if (Type t = isType(e.obj))
+ {
+ result = e;
+ return;
+ }
+ if (Expression ex = isExpression(e.obj))
+ {
+ result = interpret(pue, ex, istate);
+ if (exceptionOrCant(ex))
+ return;
+
+ if (result.op == TOK.null_)
+ {
+ e.error("null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (result.op != TOK.classReference)
+ {
+ e.error("CTFE internal error: determining classinfo");
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ ClassDeclaration cd = (cast(ClassReferenceExp)result).originalClass();
+ assert(cd);
+
+ emplaceExp!(TypeidExp)(pue, e.loc, cd.type);
+ result = pue.exp();
+ result.type = e.type;
+ return;
+ }
+ visit(cast(Expression)e);
+ }
+
+ override void visit(TupleExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s TupleExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ if (exceptionOrCant(interpretRegion(e.e0, istate, CTFEGoal.Nothing)))
+ return;
+
+ auto expsx = e.exps;
+ foreach (i, exp; *expsx)
+ {
+ Expression ex = interpretRegion(exp, istate);
+ if (exceptionOrCant(ex))
+ return;
+
+ // A tuple of assignments can contain void (Bug 5676).
+ if (goal == CTFEGoal.Nothing)
+ continue;
+ if (ex.op == TOK.voidExpression)
+ {
+ e.error("CTFE internal error: void element `%s` in tuple", exp.toChars());
+ assert(0);
+ }
+
+ /* If any changes, do Copy On Write
+ */
+ if (ex !is exp)
+ {
+ expsx = copyArrayOnWrite(expsx, e.exps);
+ (*expsx)[i] = copyRegionExp(ex);
+ }
+ }
+
+ if (expsx !is e.exps)
+ {
+ expandTuples(expsx);
+ emplaceExp!(TupleExp)(pue, e.loc, expsx);
+ result = pue.exp();
+ result.type = new TypeTuple(expsx);
+ }
+ else
+ result = e;
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s ArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
+ {
+ result = e;
+ return;
+ }
+
+ Type tn = e.type.toBasetype().nextOf().toBasetype();
+ bool wantCopy = (tn.ty == Tsarray || tn.ty == Tstruct);
+
+ auto basis = interpretRegion(e.basis, istate);
+ if (exceptionOrCant(basis))
+ return;
+
+ auto expsx = e.elements;
+ size_t dim = expsx ? expsx.dim : 0;
+ for (size_t i = 0; i < dim; i++)
+ {
+ Expression exp = (*expsx)[i];
+ Expression ex;
+ if (!exp)
+ {
+ ex = copyLiteral(basis).copy();
+ }
+ else
+ {
+ // segfault bug 6250
+ assert(exp.op != TOK.index || (cast(IndexExp)exp).e1 != e);
+
+ ex = interpretRegion(exp, istate);
+ if (exceptionOrCant(ex))
+ return;
+
+ /* Each elements should have distinct CTFE memory.
+ * int[1] z = 7;
+ * int[1][] pieces = [z,z]; // here
+ */
+ if (wantCopy)
+ ex = copyLiteral(ex).copy();
+ }
+
+ /* If any changes, do Copy On Write
+ */
+ if (ex !is exp)
+ {
+ expsx = copyArrayOnWrite(expsx, e.elements);
+ (*expsx)[i] = ex;
+ }
+ }
+
+ if (expsx !is e.elements)
+ {
+ // todo: all tuple expansions should go in semantic phase.
+ expandTuples(expsx);
+ if (expsx.dim != dim)
+ {
+ e.error("CTFE internal error: invalid array literal");
+ result = CTFEExp.cantexp;
+ return;
+ }
+ emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx);
+ auto ale = cast(ArrayLiteralExp)pue.exp();
+ ale.ownedByCtfe = OwnedBy.ctfe;
+ result = ale;
+ }
+ else if ((cast(TypeNext)e.type).next.mod & (MODFlags.const_ | MODFlags.immutable_))
+ {
+ // If it's immutable, we don't need to dup it
+ result = e;
+ }
+ else
+ {
+ *pue = copyLiteral(e);
+ result = pue.exp();
+ }
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s AssocArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
+ {
+ result = e;
+ return;
+ }
+
+ auto keysx = e.keys;
+ auto valuesx = e.values;
+ foreach (i, ekey; *keysx)
+ {
+ auto evalue = (*valuesx)[i];
+
+ auto ek = interpretRegion(ekey, istate);
+ if (exceptionOrCant(ek))
+ return;
+ auto ev = interpretRegion(evalue, istate);
+ if (exceptionOrCant(ev))
+ return;
+
+ /* If any changes, do Copy On Write
+ */
+ if (ek !is ekey ||
+ ev !is evalue)
+ {
+ keysx = copyArrayOnWrite(keysx, e.keys);
+ valuesx = copyArrayOnWrite(valuesx, e.values);
+ (*keysx)[i] = ek;
+ (*valuesx)[i] = ev;
+ }
+ }
+ if (keysx !is e.keys)
+ expandTuples(keysx);
+ if (valuesx !is e.values)
+ expandTuples(valuesx);
+ if (keysx.dim != valuesx.dim)
+ {
+ e.error("CTFE internal error: invalid AA");
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ /* Remove duplicate keys
+ */
+ for (size_t i = 1; i < keysx.dim; i++)
+ {
+ auto ekey = (*keysx)[i - 1];
+ for (size_t j = i; j < keysx.dim; j++)
+ {
+ auto ekey2 = (*keysx)[j];
+ if (!ctfeEqual(e.loc, TOK.equal, ekey, ekey2))
+ continue;
+
+ // Remove ekey
+ keysx = copyArrayOnWrite(keysx, e.keys);
+ valuesx = copyArrayOnWrite(valuesx, e.values);
+ keysx.remove(i - 1);
+ valuesx.remove(i - 1);
+
+ i -= 1; // redo the i'th iteration
+ break;
+ }
+ }
+
+ if (keysx !is e.keys ||
+ valuesx !is e.values)
+ {
+ assert(keysx !is e.keys &&
+ valuesx !is e.values);
+ auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
+ aae.type = e.type;
+ aae.ownedByCtfe = OwnedBy.ctfe;
+ result = aae;
+ }
+ else
+ {
+ *pue = copyLiteral(e);
+ result = pue.exp();
+ }
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s StructLiteralExp::interpret() %s ownedByCtfe = %d\n", e.loc.toChars(), e.toChars(), e.ownedByCtfe);
+ }
+ if (e.ownedByCtfe >= OwnedBy.ctfe)
+ {
+ result = e;
+ return;
+ }
+
+ size_t dim = e.elements ? e.elements.dim : 0;
+ auto expsx = e.elements;
+
+ if (dim != e.sd.fields.dim)
+ {
+ // guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral
+ const nvthis = e.sd.fields.dim - e.sd.nonHiddenFields();
+ assert(e.sd.fields.dim - dim == nvthis);
+
+ /* If a nested struct has no initialized hidden pointer,
+ * set it to null to match the runtime behaviour.
+ */
+ foreach (const i; 0 .. nvthis)
+ {
+ auto ne = ctfeEmplaceExp!NullExp(e.loc);
+ auto vthis = i == 0 ? e.sd.vthis : e.sd.vthis2;
+ ne.type = vthis.type;
+
+ expsx = copyArrayOnWrite(expsx, e.elements);
+ expsx.push(ne);
+ ++dim;
+ }
+ }
+ assert(dim == e.sd.fields.dim);
+
+ foreach (i; 0 .. dim)
+ {
+ auto v = e.sd.fields[i];
+ Expression exp = (*expsx)[i];
+ Expression ex;
+ if (!exp)
+ {
+ ex = voidInitLiteral(v.type, v).copy();
+ }
+ else
+ {
+ ex = interpretRegion(exp, istate);
+ if (exceptionOrCant(ex))
+ return;
+ if ((v.type.ty != ex.type.ty) && v.type.ty == Tsarray)
+ {
+ // Block assignment from inside struct literals
+ auto tsa = cast(TypeSArray)v.type;
+ auto len = cast(size_t)tsa.dim.toInteger();
+ UnionExp ue = void;
+ ex = createBlockDuplicatedArrayLiteral(&ue, ex.loc, v.type, ex, len);
+ if (ex == ue.exp())
+ ex = ue.copy();
+ }
+ }
+
+ /* If any changes, do Copy On Write
+ */
+ if (ex !is exp)
+ {
+ expsx = copyArrayOnWrite(expsx, e.elements);
+ (*expsx)[i] = ex;
+ }
+ }
+
+ if (expsx !is e.elements)
+ {
+ expandTuples(expsx);
+ if (expsx.dim != e.sd.fields.dim)
+ {
+ e.error("CTFE internal error: invalid struct literal");
+ result = CTFEExp.cantexp;
+ return;
+ }
+ emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx);
+ auto sle = cast(StructLiteralExp)pue.exp();
+ sle.type = e.type;
+ sle.ownedByCtfe = OwnedBy.ctfe;
+ sle.origin = e.origin;
+ result = sle;
+ }
+ else
+ {
+ *pue = copyLiteral(e);
+ result = pue.exp();
+ }
+ }
+
+ // Create an array literal of type 'newtype' with dimensions given by
+ // 'arguments'[argnum..$]
+ static Expression recursivelyCreateArrayLiteral(UnionExp* pue, const ref Loc loc, Type newtype, InterState* istate, Expressions* arguments, int argnum)
+ {
+ Expression lenExpr = interpret(pue, (*arguments)[argnum], istate);
+ if (exceptionOrCantInterpret(lenExpr))
+ return lenExpr;
+ size_t len = cast(size_t)lenExpr.toInteger();
+ Type elemType = (cast(TypeArray)newtype).next;
+ if (elemType.ty == Tarray && argnum < arguments.dim - 1)
+ {
+ Expression elem = recursivelyCreateArrayLiteral(pue, loc, elemType, istate, arguments, argnum + 1);
+ if (exceptionOrCantInterpret(elem))
+ return elem;
+
+ auto elements = new Expressions(len);
+ foreach (ref element; *elements)
+ element = copyLiteral(elem).copy();
+ emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements);
+ auto ae = cast(ArrayLiteralExp)pue.exp();
+ ae.ownedByCtfe = OwnedBy.ctfe;
+ return ae;
+ }
+ assert(argnum == arguments.dim - 1);
+ if (elemType.ty.isSomeChar)
+ {
+ const ch = cast(dchar)elemType.defaultInitLiteral(loc).toInteger();
+ const sz = cast(ubyte)elemType.size();
+ return createBlockDuplicatedStringLiteral(pue, loc, newtype, ch, len, sz);
+ }
+ else
+ {
+ auto el = interpret(elemType.defaultInitLiteral(loc), istate);
+ return createBlockDuplicatedArrayLiteral(pue, loc, newtype, el, len);
+ }
+ }
+
+ override void visit(NewExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+
+ Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
+ if (exceptionOrCant(epre))
+ return;
+
+ if (e.newtype.ty == Tarray && e.arguments)
+ {
+ result = recursivelyCreateArrayLiteral(pue, e.loc, e.newtype, istate, e.arguments, 0);
+ return;
+ }
+ if (auto ts = e.newtype.toBasetype().isTypeStruct())
+ {
+ if (e.member)
+ {
+ Expression se = e.newtype.defaultInitLiteral(e.loc);
+ se = interpret(se, istate);
+ if (exceptionOrCant(se))
+ return;
+ result = interpretFunction(pue, e.member, istate, e.arguments, se);
+
+ // Repaint as same as CallExp::interpret() does.
+ result.loc = e.loc;
+ }
+ else
+ {
+ StructDeclaration sd = ts.sym;
+ auto exps = new Expressions();
+ exps.reserve(sd.fields.dim);
+ if (e.arguments)
+ {
+ exps.setDim(e.arguments.dim);
+ foreach (i, ex; *e.arguments)
+ {
+ ex = interpretRegion(ex, istate);
+ if (exceptionOrCant(ex))
+ return;
+ (*exps)[i] = ex;
+ }
+ }
+ sd.fill(e.loc, exps, false);
+
+ auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, sd, exps, e.newtype);
+ se.origin = se;
+ se.type = e.newtype;
+ se.ownedByCtfe = OwnedBy.ctfe;
+ result = interpret(pue, se, istate);
+ }
+ if (exceptionOrCant(result))
+ return;
+ Expression ev = (result == pue.exp()) ? pue.copy() : result;
+ emplaceExp!(AddrExp)(pue, e.loc, ev, e.type);
+ result = pue.exp();
+ return;
+ }
+ if (auto tc = e.newtype.toBasetype().isTypeClass())
+ {
+ ClassDeclaration cd = tc.sym;
+ size_t totalFieldCount = 0;
+ for (ClassDeclaration c = cd; c; c = c.baseClass)
+ totalFieldCount += c.fields.dim;
+ auto elems = new Expressions(totalFieldCount);
+ size_t fieldsSoFar = totalFieldCount;
+ for (ClassDeclaration c = cd; c; c = c.baseClass)
+ {
+ fieldsSoFar -= c.fields.dim;
+ foreach (i, v; c.fields)
+ {
+ if (v.inuse)
+ {
+ e.error("circular reference to `%s`", v.toPrettyChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ Expression m;
+ if (v._init)
+ {
+ if (v._init.isVoidInitializer())
+ m = voidInitLiteral(v.type, v).copy();
+ else
+ m = v.getConstInitializer(true);
+ }
+ else
+ m = v.type.defaultInitLiteral(e.loc);
+ if (exceptionOrCant(m))
+ return;
+ (*elems)[fieldsSoFar + i] = copyLiteral(m).copy();
+ }
+ }
+ // Hack: we store a ClassDeclaration instead of a StructDeclaration.
+ // We probably won't get away with this.
+// auto se = new StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
+ auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
+ se.origin = se;
+ se.ownedByCtfe = OwnedBy.ctfe;
+ emplaceExp!(ClassReferenceExp)(pue, e.loc, se, e.type);
+ Expression eref = pue.exp();
+ if (e.member)
+ {
+ // Call constructor
+ if (!e.member.fbody)
+ {
+ Expression ctorfail = evaluateIfBuiltin(pue, istate, e.loc, e.member, e.arguments, eref);
+ if (ctorfail)
+ {
+ if (exceptionOrCant(ctorfail))
+ return;
+ result = eref;
+ return;
+ }
+ e.member.error("`%s` cannot be constructed at compile time, because the constructor has no available source code", e.newtype.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ UnionExp ue = void;
+ Expression ctorfail = interpretFunction(&ue, e.member, istate, e.arguments, eref);
+ if (exceptionOrCant(ctorfail))
+ return;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=14465
+ * Repaint the loc, because a super() call
+ * in the constructor modifies the loc of ClassReferenceExp
+ * in CallExp::interpret().
+ */
+ eref.loc = e.loc;
+ }
+ result = eref;
+ return;
+ }
+ if (e.newtype.toBasetype().isscalar())
+ {
+ Expression newval;
+ if (e.arguments && e.arguments.dim)
+ newval = (*e.arguments)[0];
+ else
+ newval = e.newtype.defaultInitLiteral(e.loc);
+ newval = interpretRegion(newval, istate);
+ if (exceptionOrCant(newval))
+ return;
+
+ // Create a CTFE pointer &[newval][0]
+ auto elements = new Expressions(1);
+ (*elements)[0] = newval;
+ auto ae = ctfeEmplaceExp!ArrayLiteralExp(e.loc, e.newtype.arrayOf(), elements);
+ ae.ownedByCtfe = OwnedBy.ctfe;
+
+ auto ei = ctfeEmplaceExp!IndexExp(e.loc, ae, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t));
+ ei.type = e.newtype;
+ emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
+ result = pue.exp();
+ return;
+ }
+ e.error("cannot interpret `%s` at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ }
+
+ override void visit(UnaExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s UnaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ UnionExp ue = void;
+ Expression e1 = interpret(&ue, e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ switch (e.op)
+ {
+ case TOK.negate:
+ *pue = Neg(e.type, e1);
+ break;
+
+ case TOK.tilde:
+ *pue = Com(e.type, e1);
+ break;
+
+ case TOK.not:
+ *pue = Not(e.type, e1);
+ break;
+
+ default:
+ assert(0);
+ }
+ result = (*pue).exp();
+ }
+
+ override void visit(DotTypeExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s DotTypeExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ UnionExp ue = void;
+ Expression e1 = interpret(&ue, e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ if (e1 == e.e1)
+ result = e; // optimize: reuse this CTFE reference
+ else
+ {
+ auto edt = cast(DotTypeExp)e.copy();
+ edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue
+ result = edt;
+ }
+ }
+
+ extern (D) private void interpretCommon(BinExp e, fp_t fp)
+ {
+ debug (LOG)
+ {
+ printf("%s BinExp::interpretCommon() %s\n", e.loc.toChars(), e.toChars());
+ }
+ if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == TOK.min)
+ {
+ UnionExp ue1 = void;
+ Expression e1 = interpret(&ue1, e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ UnionExp ue2 = void;
+ Expression e2 = interpret(&ue2, e.e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ *pue = pointerDifference(e.loc, e.type, e1, e2);
+ result = (*pue).exp();
+ return;
+ }
+ if (e.e1.type.ty == Tpointer && e.e2.type.isintegral())
+ {
+ UnionExp ue1 = void;
+ Expression e1 = interpret(&ue1, e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ UnionExp ue2 = void;
+ Expression e2 = interpret(&ue2, e.e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ *pue = pointerArithmetic(e.loc, e.op, e.type, e1, e2);
+ result = (*pue).exp();
+ return;
+ }
+ if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == TOK.add)
+ {
+ UnionExp ue1 = void;
+ Expression e1 = interpret(&ue1, e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ UnionExp ue2 = void;
+ Expression e2 = interpret(&ue2, e.e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ *pue = pointerArithmetic(e.loc, e.op, e.type, e2, e1);
+ result = (*pue).exp();
+ return;
+ }
+ if (e.e1.type.ty == Tpointer || e.e2.type.ty == Tpointer)
+ {
+ e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ bool evalOperand(UnionExp* pue, Expression ex, out Expression er)
+ {
+ er = interpret(pue, ex, istate);
+ if (exceptionOrCant(er))
+ return false;
+ return true;
+ }
+
+ UnionExp ue1 = void;
+ Expression e1;
+ if (!evalOperand(&ue1, e.e1, e1))
+ return;
+
+ UnionExp ue2 = void;
+ Expression e2;
+ if (!evalOperand(&ue2, e.e2, e2))
+ return;
+
+ if (e.op == TOK.rightShift || e.op == TOK.leftShift || e.op == TOK.unsignedRightShift)
+ {
+ const sinteger_t i2 = e2.toInteger();
+ const d_uns64 sz = e1.type.size() * 8;
+ if (i2 < 0 || i2 >= sz)
+ {
+ e.error("shift by %lld is outside the range 0..%llu", i2, cast(ulong)sz - 1);
+ result = CTFEExp.cantexp;
+ return;
+ }
+ }
+
+ /******************************************
+ * Perform the operation fp on operands e1 and e2.
+ */
+ UnionExp evaluate(Loc loc, Type type, Expression e1, Expression e2)
+ {
+ UnionExp ue = void;
+ auto ae1 = e1.isArrayLiteralExp();
+ auto ae2 = e2.isArrayLiteralExp();
+ if (ae1 || ae2)
+ {
+ /* Cases:
+ * 1. T[] op T[]
+ * 2. T op T[]
+ * 3. T[] op T
+ */
+ if (ae1 && e2.implicitConvTo(e1.type.toBasetype().nextOf())) // case 3
+ ae2 = null;
+ else if (ae2 && e1.implicitConvTo(e2.type.toBasetype().nextOf())) // case 2
+ ae1 = null;
+ // else case 1
+
+ auto aex = ae1 ? ae1 : ae2;
+ if (!aex.elements)
+ {
+ emplaceExp!ArrayLiteralExp(&ue, loc, type, cast(Expressions*) null);
+ return ue;
+ }
+ const length = aex.elements.length;
+ Expressions* elements = new Expressions(length);
+
+ emplaceExp!ArrayLiteralExp(&ue, loc, type, elements);
+ foreach (i; 0 .. length)
+ {
+ Expression e1x = ae1 ? ae1[i] : e1;
+ Expression e2x = ae2 ? ae2[i] : e2;
+ UnionExp uex = evaluate(loc, e1x.type, e1x, e2x);
+ // This can be made more efficient by making use of ue.basis
+ (*elements)[i] = uex.copy();
+ }
+ return ue;
+ }
+
+ if (e1.isConst() != 1)
+ {
+ // The following should really be an assert()
+ e1.error("CTFE internal error: non-constant value `%s`", e1.toChars());
+ emplaceExp!CTFEExp(&ue, TOK.cantExpression);
+ return ue;
+ }
+ if (e2.isConst() != 1)
+ {
+ e2.error("CTFE internal error: non-constant value `%s`", e2.toChars());
+ emplaceExp!CTFEExp(&ue, TOK.cantExpression);
+ return ue;
+ }
+
+ return (*fp)(loc, type, e1, e2);
+ }
+
+ *pue = evaluate(e.loc, e.type, e1, e2);
+ result = (*pue).exp();
+ if (CTFEExp.isCantExp(result))
+ e.error("`%s` cannot be interpreted at compile time", e.toChars());
+ }
+
+ extern (D) private void interpretCompareCommon(BinExp e, fp2_t fp)
+ {
+ debug (LOG)
+ {
+ printf("%s BinExp::interpretCompareCommon() %s\n", e.loc.toChars(), e.toChars());
+ }
+ UnionExp ue1 = void;
+ UnionExp ue2 = void;
+ if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer)
+ {
+ Expression e1 = interpret(&ue1, e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ Expression e2 = interpret(&ue2, e.e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ //printf("e1 = %s %s, e2 = %s %s\n", e1.type.toChars(), e1.toChars(), e2.type.toChars(), e2.toChars());
+ dinteger_t ofs1, ofs2;
+ Expression agg1 = getAggregateFromPointer(e1, &ofs1);
+ Expression agg2 = getAggregateFromPointer(e2, &ofs2);
+ //printf("agg1 = %p %s, agg2 = %p %s\n", agg1, agg1.toChars(), agg2, agg2.toChars());
+ const cmp = comparePointers(e.op, agg1, ofs1, agg2, ofs2);
+ if (cmp == -1)
+ {
+ char dir = (e.op == TOK.greaterThan || e.op == TOK.greaterOrEqual) ? '<' : '>';
+ e.error("the ordering of pointers to unrelated memory blocks is indeterminate in CTFE. To check if they point to the same memory block, use both `>` and `<` inside `&&` or `||`, eg `%s && %s %c= %s + 1`", e.toChars(), e.e1.toChars(), dir, e.e2.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (e.type.equals(Type.tbool))
+ result = IntegerExp.createBool(cmp != 0);
+ else
+ {
+ emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
+ result = (*pue).exp();
+ }
+ return;
+ }
+ Expression e1 = interpret(&ue1, e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ if (!isCtfeComparable(e1))
+ {
+ e.error("cannot compare `%s` at compile time", e1.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ Expression e2 = interpret(&ue2, e.e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ if (!isCtfeComparable(e2))
+ {
+ e.error("cannot compare `%s` at compile time", e2.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ const cmp = (*fp)(e.loc, e.op, e1, e2);
+ if (e.type.equals(Type.tbool))
+ result = IntegerExp.createBool(cmp);
+ else
+ {
+ emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
+ result = (*pue).exp();
+ }
+ }
+
+ override void visit(BinExp e)
+ {
+ switch (e.op)
+ {
+ case TOK.add:
+ interpretCommon(e, &Add);
+ return;
+
+ case TOK.min:
+ interpretCommon(e, &Min);
+ return;
+
+ case TOK.mul:
+ interpretCommon(e, &Mul);
+ return;
+
+ case TOK.div:
+ interpretCommon(e, &Div);
+ return;
+
+ case TOK.mod:
+ interpretCommon(e, &Mod);
+ return;
+
+ case TOK.leftShift:
+ interpretCommon(e, &Shl);
+ return;
+
+ case TOK.rightShift:
+ interpretCommon(e, &Shr);
+ return;
+
+ case TOK.unsignedRightShift:
+ interpretCommon(e, &Ushr);
+ return;
+
+ case TOK.and:
+ interpretCommon(e, &And);
+ return;
+
+ case TOK.or:
+ interpretCommon(e, &Or);
+ return;
+
+ case TOK.xor:
+ interpretCommon(e, &Xor);
+ return;
+
+ case TOK.pow:
+ interpretCommon(e, &Pow);
+ return;
+
+ case TOK.equal:
+ case TOK.notEqual:
+ interpretCompareCommon(e, &ctfeEqual);
+ return;
+
+ case TOK.identity:
+ case TOK.notIdentity:
+ interpretCompareCommon(e, &ctfeIdentity);
+ return;
+
+ case TOK.lessThan:
+ case TOK.lessOrEqual:
+ case TOK.greaterThan:
+ case TOK.greaterOrEqual:
+ interpretCompareCommon(e, &ctfeCmp);
+ return;
+
+ default:
+ printf("be = '%s' %s at [%s]\n", Token.toChars(e.op), e.toChars(), e.loc.toChars());
+ assert(0);
+ }
+ }
+
+ /* Helper functions for BinExp::interpretAssignCommon
+ */
+ // Returns the variable which is eventually modified, or NULL if an rvalue.
+ // thisval is the current value of 'this'.
+ static VarDeclaration findParentVar(Expression e)
+ {
+ for (;;)
+ {
+ if (auto ve = e.isVarExp())
+ {
+ VarDeclaration v = ve.var.isVarDeclaration();
+ assert(v);
+ return v;
+ }
+ if (auto ie = e.isIndexExp())
+ e = ie.e1;
+ else if (auto dve = e.isDotVarExp())
+ e = dve.e1;
+ else if (auto dtie = e.isDotTemplateInstanceExp())
+ e = dtie.e1;
+ else if (auto se = e.isSliceExp())
+ e = se.e1;
+ else
+ return null;
+ }
+ }
+
+ extern (D) private void interpretAssignCommon(BinExp e, fp_t fp, int post = 0)
+ {
+ debug (LOG)
+ {
+ printf("%s BinExp::interpretAssignCommon() %s\n", e.loc.toChars(), e.toChars());
+ }
+ result = CTFEExp.cantexp;
+
+ Expression e1 = e.e1;
+ if (!istate)
+ {
+ e.error("value of `%s` is not known at compile time", e1.toChars());
+ return;
+ }
+
+ ++ctfeGlobals.numAssignments;
+
+ /* Before we begin, we need to know if this is a reference assignment
+ * (dynamic array, AA, or class) or a value assignment.
+ * Determining this for slice assignments are tricky: we need to know
+ * if it is a block assignment (a[] = e) rather than a direct slice
+ * assignment (a[] = b[]). Note that initializers of multi-dimensional
+ * static arrays can have 2D block assignments (eg, int[7][7] x = 6;).
+ * So we need to recurse to determine if it is a block assignment.
+ */
+ bool isBlockAssignment = false;
+ if (e1.op == TOK.slice)
+ {
+ // a[] = e can have const e. So we compare the naked types.
+ Type tdst = e1.type.toBasetype();
+ Type tsrc = e.e2.type.toBasetype();
+ while (tdst.ty == Tsarray || tdst.ty == Tarray)
+ {
+ tdst = (cast(TypeArray)tdst).next.toBasetype();
+ if (tsrc.equivalent(tdst))
+ {
+ isBlockAssignment = true;
+ break;
+ }
+ }
+ }
+
+ // ---------------------------------------
+ // Deal with reference assignment
+ // ---------------------------------------
+ // If it is a construction of a ref variable, it is a ref assignment
+ if ((e.op == TOK.construct || e.op == TOK.blit) &&
+ ((cast(AssignExp)e).memset == MemorySet.referenceInit))
+ {
+ assert(!fp);
+
+ Expression newval = interpretRegion(e.e2, istate, CTFEGoal.LValue);
+ if (exceptionOrCant(newval))
+ return;
+
+ VarDeclaration v = (cast(VarExp)e1).var.isVarDeclaration();
+ setValue(v, newval);
+
+ // Get the value to return. Note that 'newval' is an Lvalue,
+ // so if we need an Rvalue, we have to interpret again.
+ if (goal == CTFEGoal.RValue)
+ result = interpretRegion(newval, istate);
+ else
+ result = e1; // VarExp is a CTFE reference
+ return;
+ }
+
+ if (fp)
+ {
+ while (e1.op == TOK.cast_)
+ {
+ CastExp ce = cast(CastExp)e1;
+ e1 = ce.e1;
+ }
+ }
+
+ // ---------------------------------------
+ // Interpret left hand side
+ // ---------------------------------------
+ AssocArrayLiteralExp existingAA = null;
+ Expression lastIndex = null;
+ Expression oldval = null;
+ if (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+ {
+ // ---------------------------------------
+ // Deal with AA index assignment
+ // ---------------------------------------
+ /* This needs special treatment if the AA doesn't exist yet.
+ * There are two special cases:
+ * (1) If the AA is itself an index of another AA, we may need to create
+ * multiple nested AA literals before we can insert the new value.
+ * (2) If the ultimate AA is null, no insertion happens at all. Instead,
+ * we create nested AA literals, and change it into a assignment.
+ */
+ IndexExp ie = cast(IndexExp)e1;
+ int depth = 0; // how many nested AA indices are there?
+ while (ie.e1.op == TOK.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray)
+ {
+ assert(ie.modifiable);
+ ie = cast(IndexExp)ie.e1;
+ ++depth;
+ }
+
+ // Get the AA value to be modified.
+ Expression aggregate = interpretRegion(ie.e1, istate);
+ if (exceptionOrCant(aggregate))
+ return;
+ if ((existingAA = aggregate.isAssocArrayLiteralExp()) !is null)
+ {
+ // Normal case, ultimate parent AA already exists
+ // We need to walk from the deepest index up, checking that an AA literal
+ // already exists on each level.
+ lastIndex = interpretRegion((cast(IndexExp)e1).e2, istate);
+ lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
+ if (exceptionOrCant(lastIndex))
+ return;
+
+ while (depth > 0)
+ {
+ // Walk the syntax tree to find the indexExp at this depth
+ IndexExp xe = cast(IndexExp)e1;
+ foreach (d; 0 .. depth)
+ xe = cast(IndexExp)xe.e1;
+
+ Expression ekey = interpretRegion(xe.e2, istate);
+ if (exceptionOrCant(ekey))
+ return;
+ UnionExp ekeyTmp = void;
+ ekey = resolveSlice(ekey, &ekeyTmp); // only happens with AA assignment
+
+ // Look up this index in it up in the existing AA, to get the next level of AA.
+ AssocArrayLiteralExp newAA = cast(AssocArrayLiteralExp)findKeyInAA(e.loc, existingAA, ekey);
+ if (exceptionOrCant(newAA))
+ return;
+ if (!newAA)
+ {
+ // Doesn't exist yet, create an empty AA...
+ auto keysx = new Expressions();
+ auto valuesx = new Expressions();
+ newAA = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
+ newAA.type = xe.type;
+ newAA.ownedByCtfe = OwnedBy.ctfe;
+ //... and insert it into the existing AA.
+ existingAA.keys.push(ekey);
+ existingAA.values.push(newAA);
+ }
+ existingAA = newAA;
+ --depth;
+ }
+
+ if (fp)
+ {
+ oldval = findKeyInAA(e.loc, existingAA, lastIndex);
+ if (!oldval)
+ oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
+ }
+ }
+ else
+ {
+ /* The AA is currently null. 'aggregate' is actually a reference to
+ * whatever contains it. It could be anything: var, dotvarexp, ...
+ * We rewrite the assignment from:
+ * aa[i][j] op= newval;
+ * into:
+ * aa = [i:[j:T.init]];
+ * aa[j] op= newval;
+ */
+ oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
+
+ Expression newaae = oldval;
+ while (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+ {
+ Expression ekey = interpretRegion((cast(IndexExp)e1).e2, istate);
+ if (exceptionOrCant(ekey))
+ return;
+ ekey = resolveSlice(ekey); // only happens with AA assignment
+
+ auto keysx = new Expressions();
+ auto valuesx = new Expressions();
+ keysx.push(ekey);
+ valuesx.push(newaae);
+
+ auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
+ aae.type = (cast(IndexExp)e1).e1.type;
+ aae.ownedByCtfe = OwnedBy.ctfe;
+ if (!existingAA)
+ {
+ existingAA = aae;
+ lastIndex = ekey;
+ }
+ newaae = aae;
+ e1 = (cast(IndexExp)e1).e1;
+ }
+
+ // We must set to aggregate with newaae
+ e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
+ if (exceptionOrCant(e1))
+ return;
+ e1 = assignToLvalue(e, e1, newaae);
+ if (exceptionOrCant(e1))
+ return;
+ }
+ assert(existingAA && lastIndex);
+ e1 = null; // stomp
+ }
+ else if (e1.op == TOK.arrayLength)
+ {
+ oldval = interpretRegion(e1, istate);
+ if (exceptionOrCant(oldval))
+ return;
+ }
+ else if (e.op == TOK.construct || e.op == TOK.blit)
+ {
+ // Unless we have a simple var assignment, we're
+ // only modifying part of the variable. So we need to make sure
+ // that the parent variable exists.
+ VarDeclaration ultimateVar = findParentVar(e1);
+ if (auto ve = e1.isVarExp())
+ {
+ VarDeclaration v = ve.var.isVarDeclaration();
+ assert(v);
+ if (v.storage_class & STC.out_)
+ goto L1;
+ }
+ else if (ultimateVar && !getValue(ultimateVar))
+ {
+ Expression ex = interpretRegion(ultimateVar.type.defaultInitLiteral(e.loc), istate);
+ if (exceptionOrCant(ex))
+ return;
+ setValue(ultimateVar, ex);
+ }
+ else
+ goto L1;
+ }
+ else
+ {
+ L1:
+ e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
+ if (exceptionOrCant(e1))
+ return;
+
+ if (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+ {
+ IndexExp ie = cast(IndexExp)e1;
+ assert(ie.e1.op == TOK.assocArrayLiteral);
+ existingAA = cast(AssocArrayLiteralExp)ie.e1;
+ lastIndex = ie.e2;
+ }
+ }
+
+ // ---------------------------------------
+ // Interpret right hand side
+ // ---------------------------------------
+ Expression newval = interpretRegion(e.e2, istate);
+ if (exceptionOrCant(newval))
+ return;
+ if (e.op == TOK.blit && newval.op == TOK.int64)
+ {
+ Type tbn = e.type.baseElemOf();
+ if (tbn.ty == Tstruct)
+ {
+ /* Look for special case of struct being initialized with 0.
+ */
+ newval = e.type.defaultInitLiteral(e.loc);
+ if (newval.op == TOK.error)
+ {
+ result = CTFEExp.cantexp;
+ return;
+ }
+ newval = interpretRegion(newval, istate); // copy and set ownedByCtfe flag
+ if (exceptionOrCant(newval))
+ return;
+ }
+ }
+
+ // ----------------------------------------------------
+ // Deal with read-modify-write assignments.
+ // Set 'newval' to the final assignment value
+ // Also determine the return value (except for slice
+ // assignments, which are more complicated)
+ // ----------------------------------------------------
+ if (fp)
+ {
+ if (!oldval)
+ {
+ // Load the left hand side after interpreting the right hand side.
+ oldval = interpretRegion(e1, istate);
+ if (exceptionOrCant(oldval))
+ return;
+ }
+
+ if (e.e1.type.ty != Tpointer)
+ {
+ // ~= can create new values (see bug 6052)
+ if (e.op == TOK.concatenateAssign || e.op == TOK.concatenateElemAssign || e.op == TOK.concatenateDcharAssign)
+ {
+ // We need to dup it and repaint the type. For a dynamic array
+ // we can skip duplication, because it gets copied later anyway.
+ if (newval.type.ty != Tarray)
+ {
+ newval = copyLiteral(newval).copy();
+ newval.type = e.e2.type; // repaint type
+ }
+ else
+ {
+ newval = paintTypeOntoLiteral(e.e2.type, newval);
+ newval = resolveSlice(newval);
+ }
+ }
+ oldval = resolveSlice(oldval);
+
+ newval = (*fp)(e.loc, e.type, oldval, newval).copy();
+ }
+ else if (e.e2.type.isintegral() &&
+ (e.op == TOK.addAssign ||
+ e.op == TOK.minAssign ||
+ e.op == TOK.plusPlus ||
+ e.op == TOK.minusMinus))
+ {
+ newval = pointerArithmetic(e.loc, e.op, e.type, oldval, newval).copy();
+ }
+ else
+ {
+ e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (exceptionOrCant(newval))
+ {
+ if (CTFEExp.isCantExp(newval))
+ e.error("cannot interpret `%s` at compile time", e.toChars());
+ return;
+ }
+ }
+
+ if (existingAA)
+ {
+ if (existingAA.ownedByCtfe != OwnedBy.ctfe)
+ {
+ e.error("cannot modify read-only constant `%s`", existingAA.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n",
+ // __LINE__, existingAA.toChars(), lastIndex.toChars(), oldval ? oldval.toChars() : NULL, newval.toChars());
+ assignAssocArrayElement(e.loc, existingAA, lastIndex, newval);
+
+ // Determine the return value
+ result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
+ return;
+ }
+ if (e1.op == TOK.arrayLength)
+ {
+ /* Change the assignment from:
+ * arr.length = n;
+ * into:
+ * arr = new_length_array; (result is n)
+ */
+
+ // Determine the return value
+ result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
+ if (exceptionOrCant(result))
+ return;
+
+ if (result == pue.exp())
+ result = pue.copy();
+
+ size_t oldlen = cast(size_t)oldval.toInteger();
+ size_t newlen = cast(size_t)newval.toInteger();
+ if (oldlen == newlen) // no change required -- we're done!
+ return;
+
+ // We have changed it into a reference assignment
+ // Note that returnValue is still the new length.
+ e1 = (cast(ArrayLengthExp)e1).e1;
+ Type t = e1.type.toBasetype();
+ if (t.ty != Tarray)
+ {
+ e.error("`%s` is not yet supported at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
+ if (exceptionOrCant(e1))
+ return;
+
+ if (oldlen != 0) // Get the old array literal.
+ oldval = interpretRegion(e1, istate);
+ UnionExp utmp = void;
+ oldval = resolveSlice(oldval, &utmp);
+
+ newval = changeArrayLiteralLength(e.loc, cast(TypeArray)t, oldval, oldlen, newlen).copy();
+
+ e1 = assignToLvalue(e, e1, newval);
+ if (exceptionOrCant(e1))
+ return;
+
+ return;
+ }
+
+ if (!isBlockAssignment)
+ {
+ newval = ctfeCast(pue, e.loc, e.type, e.type, newval);
+ if (exceptionOrCant(newval))
+ return;
+ if (newval == pue.exp())
+ newval = pue.copy();
+
+ // Determine the return value
+ if (goal == CTFEGoal.LValue) // https://issues.dlang.org/show_bug.cgi?id=14371
+ result = e1;
+ else
+ {
+ result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
+ if (result == pue.exp())
+ result = pue.copy();
+ }
+ if (exceptionOrCant(result))
+ return;
+ }
+ if (exceptionOrCant(newval))
+ return;
+
+ debug (LOGASSIGN)
+ {
+ printf("ASSIGN: %s=%s\n", e1.toChars(), newval.toChars());
+ showCtfeExpr(newval);
+ }
+
+ /* Block assignment or element-wise assignment.
+ */
+ if (e1.op == TOK.slice ||
+ e1.op == TOK.vector ||
+ e1.op == TOK.arrayLiteral ||
+ e1.op == TOK.string_ ||
+ e1.op == TOK.null_ && e1.type.toBasetype().ty == Tarray)
+ {
+ // Note that slice assignments don't support things like ++, so
+ // we don't need to remember 'returnValue'.
+ result = interpretAssignToSlice(pue, e, e1, newval, isBlockAssignment);
+ if (exceptionOrCant(result))
+ return;
+ if (auto se = e.e1.isSliceExp())
+ {
+ Expression e1x = interpretRegion(se.e1, istate, CTFEGoal.LValue);
+ if (auto dve = e1x.isDotVarExp())
+ {
+ auto ex = dve.e1;
+ auto sle = ex.op == TOK.structLiteral ? (cast(StructLiteralExp)ex)
+ : ex.op == TOK.classReference ? (cast(ClassReferenceExp)ex).value
+ : null;
+ auto v = dve.var.isVarDeclaration();
+ if (!sle || !v)
+ {
+ e.error("CTFE internal error: dotvar slice assignment");
+ result = CTFEExp.cantexp;
+ return;
+ }
+ stompOverlappedFields(sle, v);
+ }
+ }
+ return;
+ }
+ assert(result);
+
+ /* Assignment to a CTFE reference.
+ */
+ if (Expression ex = assignToLvalue(e, e1, newval))
+ result = ex;
+
+ return;
+ }
+
+ /* Set all sibling fields which overlap with v to VoidExp.
+ */
+ private void stompOverlappedFields(StructLiteralExp sle, VarDeclaration v)
+ {
+ if (!v.overlapped)
+ return;
+ foreach (size_t i, v2; sle.sd.fields)
+ {
+ if (v is v2 || !v.isOverlappedWith(v2))
+ continue;
+ auto e = (*sle.elements)[i];
+ if (e.op != TOK.void_)
+ (*sle.elements)[i] = voidInitLiteral(e.type, v).copy();
+ }
+ }
+
+ private Expression assignToLvalue(BinExp e, Expression e1, Expression newval)
+ {
+ //printf("assignToLvalue() e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars());
+ VarDeclaration vd = null;
+ Expression* payload = null; // dead-store to prevent spurious warning
+ Expression oldval;
+
+ if (auto ve = e1.isVarExp())
+ {
+ vd = ve.var.isVarDeclaration();
+ oldval = getValue(vd);
+ }
+ else if (auto dve = e1.isDotVarExp())
+ {
+ /* Assignment to member variable of the form:
+ * e.v = newval
+ */
+ auto ex = dve.e1;
+ auto sle = ex.op == TOK.structLiteral ? (cast(StructLiteralExp)ex)
+ : ex.op == TOK.classReference ? (cast(ClassReferenceExp)ex).value
+ : null;
+ auto v = (cast(DotVarExp)e1).var.isVarDeclaration();
+ if (!sle || !v)
+ {
+ e.error("CTFE internal error: dotvar assignment");
+ return CTFEExp.cantexp;
+ }
+ if (sle.ownedByCtfe != OwnedBy.ctfe)
+ {
+ e.error("cannot modify read-only constant `%s`", sle.toChars());
+ return CTFEExp.cantexp;
+ }
+
+ int fieldi = ex.op == TOK.structLiteral ? findFieldIndexByName(sle.sd, v)
+ : (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
+ if (fieldi == -1)
+ {
+ e.error("CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars());
+ return CTFEExp.cantexp;
+ }
+ assert(0 <= fieldi && fieldi < sle.elements.dim);
+
+ // If it's a union, set all other members of this union to void
+ stompOverlappedFields(sle, v);
+
+ payload = &(*sle.elements)[fieldi];
+ oldval = *payload;
+ }
+ else if (auto ie = e1.isIndexExp())
+ {
+ assert(ie.e1.type.toBasetype().ty != Taarray);
+
+ Expression aggregate;
+ uinteger_t indexToModify;
+ if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true))
+ {
+ return CTFEExp.cantexp;
+ }
+ size_t index = cast(size_t)indexToModify;
+
+ if (auto existingSE = aggregate.isStringExp())
+ {
+ if (existingSE.ownedByCtfe != OwnedBy.ctfe)
+ {
+ e.error("cannot modify read-only string literal `%s`", ie.e1.toChars());
+ return CTFEExp.cantexp;
+ }
+ existingSE.setCodeUnit(index, cast(dchar)newval.toInteger());
+ return null;
+ }
+ if (aggregate.op != TOK.arrayLiteral)
+ {
+ e.error("index assignment `%s` is not yet supported in CTFE ", e.toChars());
+ return CTFEExp.cantexp;
+ }
+
+ ArrayLiteralExp existingAE = cast(ArrayLiteralExp)aggregate;
+ if (existingAE.ownedByCtfe != OwnedBy.ctfe)
+ {
+ e.error("cannot modify read-only constant `%s`", existingAE.toChars());
+ return CTFEExp.cantexp;
+ }
+
+ payload = &(*existingAE.elements)[index];
+ oldval = *payload;
+ }
+ else
+ {
+ e.error("`%s` cannot be evaluated at compile time", e.toChars());
+ return CTFEExp.cantexp;
+ }
+
+ Type t1b = e1.type.toBasetype();
+ bool wantCopy = t1b.baseElemOf().ty == Tstruct;
+
+ if (auto ve = newval.isVectorExp())
+ {
+ // Ensure ve is an array literal, and not a broadcast
+ if (ve.e1.op == TOK.int64 || ve.e1.op == TOK.float64) // if broadcast
+ {
+ UnionExp ue = void;
+ Expression ex = interpretVectorToArray(&ue, ve);
+ ve.e1 = (ex == ue.exp()) ? ue.copy() : ex;
+ }
+ }
+
+ if (newval.op == TOK.structLiteral && oldval)
+ {
+ assert(oldval.op == TOK.structLiteral || oldval.op == TOK.arrayLiteral || oldval.op == TOK.string_);
+ newval = copyLiteral(newval).copy();
+ assignInPlace(oldval, newval);
+ }
+ else if (wantCopy && e.op == TOK.assign)
+ {
+ // Currently postblit/destructor calls on static array are done
+ // in the druntime internal functions so they don't appear in AST.
+ // Therefore interpreter should handle them specially.
+
+ assert(oldval);
+ version (all) // todo: instead we can directly access to each elements of the slice
+ {
+ newval = resolveSlice(newval);
+ if (CTFEExp.isCantExp(newval))
+ {
+ e.error("CTFE internal error: assignment `%s`", e.toChars());
+ return CTFEExp.cantexp;
+ }
+ }
+ assert(oldval.op == TOK.arrayLiteral);
+ assert(newval.op == TOK.arrayLiteral);
+
+ Expressions* oldelems = (cast(ArrayLiteralExp)oldval).elements;
+ Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
+ assert(oldelems.dim == newelems.dim);
+
+ Type elemtype = oldval.type.nextOf();
+ foreach (i, ref oldelem; *oldelems)
+ {
+ Expression newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]);
+ // https://issues.dlang.org/show_bug.cgi?id=9245
+ if (e.e2.isLvalue())
+ {
+ if (Expression ex = evaluatePostblit(istate, newelem))
+ return ex;
+ }
+ // https://issues.dlang.org/show_bug.cgi?id=13661
+ if (Expression ex = evaluateDtor(istate, oldelem))
+ return ex;
+ oldelem = newelem;
+ }
+ }
+ else
+ {
+ // e1 has its own payload, so we have to create a new literal.
+ if (wantCopy)
+ newval = copyLiteral(newval).copy();
+
+ if (t1b.ty == Tsarray && e.op == TOK.construct && e.e2.isLvalue())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=9245
+ if (Expression ex = evaluatePostblit(istate, newval))
+ return ex;
+ }
+
+ oldval = newval;
+ }
+
+ if (vd)
+ setValue(vd, oldval);
+ else
+ *payload = oldval;
+
+ // Blit assignment should return the newly created value.
+ if (e.op == TOK.blit)
+ return oldval;
+
+ return null;
+ }
+
+ /*************
+ * Deal with assignments of the form:
+ * dest[] = newval
+ * dest[low..upp] = newval
+ * where newval has already been interpreted
+ *
+ * This could be a slice assignment or a block assignment, and
+ * dest could be either an array literal, or a string.
+ *
+ * Returns TOK.cantExpression on failure. If there are no errors,
+ * it returns aggregate[low..upp], except that as an optimisation,
+ * if goal == CTFEGoal.Nothing, it will return NULL
+ */
+ private Expression interpretAssignToSlice(UnionExp* pue, BinExp e, Expression e1, Expression newval, bool isBlockAssignment)
+ {
+ dinteger_t lowerbound;
+ dinteger_t upperbound;
+ dinteger_t firstIndex;
+
+ Expression aggregate;
+
+ if (auto se = e1.isSliceExp())
+ {
+ // ------------------------------
+ // aggregate[] = newval
+ // aggregate[low..upp] = newval
+ // ------------------------------
+ version (all) // should be move in interpretAssignCommon as the evaluation of e1
+ {
+ Expression oldval = interpretRegion(se.e1, istate);
+
+ // Set the $ variable
+ uinteger_t dollar = resolveArrayLength(oldval);
+ if (se.lengthVar)
+ {
+ Expression dollarExp = ctfeEmplaceExp!IntegerExp(e1.loc, dollar, Type.tsize_t);
+ ctfeGlobals.stack.push(se.lengthVar);
+ setValue(se.lengthVar, dollarExp);
+ }
+ Expression lwr = interpretRegion(se.lwr, istate);
+ if (exceptionOrCantInterpret(lwr))
+ {
+ if (se.lengthVar)
+ ctfeGlobals.stack.pop(se.lengthVar);
+ return lwr;
+ }
+ Expression upr = interpretRegion(se.upr, istate);
+ if (exceptionOrCantInterpret(upr))
+ {
+ if (se.lengthVar)
+ ctfeGlobals.stack.pop(se.lengthVar);
+ return upr;
+ }
+ if (se.lengthVar)
+ ctfeGlobals.stack.pop(se.lengthVar); // $ is defined only in [L..U]
+
+ const dim = dollar;
+ lowerbound = lwr ? lwr.toInteger() : 0;
+ upperbound = upr ? upr.toInteger() : dim;
+
+ if (lowerbound < 0 || dim < upperbound)
+ {
+ e.error("array bounds `[0..%llu]` exceeded in slice `[%llu..%llu]`",
+ ulong(dim), ulong(lowerbound), ulong(upperbound));
+ return CTFEExp.cantexp;
+ }
+ }
+ aggregate = oldval;
+ firstIndex = lowerbound;
+
+ if (auto oldse = aggregate.isSliceExp())
+ {
+ // Slice of a slice --> change the bounds
+ if (oldse.upr.toInteger() < upperbound + oldse.lwr.toInteger())
+ {
+ e.error("slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`",
+ ulong(lowerbound), ulong(upperbound), oldse.upr.toInteger() - oldse.lwr.toInteger());
+ return CTFEExp.cantexp;
+ }
+ aggregate = oldse.e1;
+ firstIndex = lowerbound + oldse.lwr.toInteger();
+ }
+ }
+ else
+ {
+ if (auto ale = e1.isArrayLiteralExp())
+ {
+ lowerbound = 0;
+ upperbound = ale.elements.dim;
+ }
+ else if (auto se = e1.isStringExp())
+ {
+ lowerbound = 0;
+ upperbound = se.len;
+ }
+ else if (e1.op == TOK.null_)
+ {
+ lowerbound = 0;
+ upperbound = 0;
+ }
+ else if (VectorExp ve = e1.isVectorExp())
+ {
+ // ve is not handled but a proper error message is returned
+ // this is to prevent https://issues.dlang.org/show_bug.cgi?id=20042
+ lowerbound = 0;
+ upperbound = ve.dim;
+ }
+ else
+ assert(0);
+
+ aggregate = e1;
+ firstIndex = lowerbound;
+ }
+ if (upperbound == lowerbound)
+ return newval;
+
+ // For slice assignment, we check that the lengths match.
+ if (!isBlockAssignment)
+ {
+ const srclen = resolveArrayLength(newval);
+ if (srclen != (upperbound - lowerbound))
+ {
+ e.error("array length mismatch assigning `[0..%llu]` to `[%llu..%llu]`",
+ ulong(srclen), ulong(lowerbound), ulong(upperbound));
+ return CTFEExp.cantexp;
+ }
+ }
+
+ if (auto existingSE = aggregate.isStringExp())
+ {
+ if (existingSE.ownedByCtfe != OwnedBy.ctfe)
+ {
+ e.error("cannot modify read-only string literal `%s`", existingSE.toChars());
+ return CTFEExp.cantexp;
+ }
+
+ if (auto se = newval.isSliceExp())
+ {
+ auto aggr2 = se.e1;
+ const srclower = se.lwr.toInteger();
+ const srcupper = se.upr.toInteger();
+
+ if (aggregate == aggr2 &&
+ lowerbound < srcupper && srclower < upperbound)
+ {
+ e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
+ ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
+ return CTFEExp.cantexp;
+ }
+ version (all) // todo: instead we can directly access to each elements of the slice
+ {
+ Expression orignewval = newval;
+ newval = resolveSlice(newval);
+ if (CTFEExp.isCantExp(newval))
+ {
+ e.error("CTFE internal error: slice `%s`", orignewval.toChars());
+ return CTFEExp.cantexp;
+ }
+ }
+ assert(newval.op != TOK.slice);
+ }
+ if (auto se = newval.isStringExp())
+ {
+ sliceAssignStringFromString(existingSE, se, cast(size_t)firstIndex);
+ return newval;
+ }
+ if (auto ale = newval.isArrayLiteralExp())
+ {
+ /* Mixed slice: it was initialized as a string literal.
+ * Now a slice of it is being set with an array literal.
+ */
+ sliceAssignStringFromArrayLiteral(existingSE, ale, cast(size_t)firstIndex);
+ return newval;
+ }
+
+ // String literal block slice assign
+ const value = cast(dchar)newval.toInteger();
+ foreach (i; 0 .. upperbound - lowerbound)
+ {
+ existingSE.setCodeUnit(cast(size_t)(i + firstIndex), value);
+ }
+ if (goal == CTFEGoal.Nothing)
+ return null; // avoid creating an unused literal
+ auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingSE,
+ ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
+ ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
+ retslice.type = e.type;
+ return interpret(pue, retslice, istate);
+ }
+ if (auto existingAE = aggregate.isArrayLiteralExp())
+ {
+ if (existingAE.ownedByCtfe != OwnedBy.ctfe)
+ {
+ e.error("cannot modify read-only constant `%s`", existingAE.toChars());
+ return CTFEExp.cantexp;
+ }
+
+ if (newval.op == TOK.slice && !isBlockAssignment)
+ {
+ auto se = cast(SliceExp)newval;
+ auto aggr2 = se.e1;
+ const srclower = se.lwr.toInteger();
+ const srcupper = se.upr.toInteger();
+ const wantCopy = (newval.type.toBasetype().nextOf().baseElemOf().ty == Tstruct);
+
+ //printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n",
+ // aggregate, aggregate.toChars(), lowerbound, upperbound,
+ // aggr2, aggr2.toChars(), srclower, srcupper, wantCopy);
+ if (wantCopy)
+ {
+ // Currently overlapping for struct array is allowed.
+ // The order of elements processing depends on the overlapping.
+ // https://issues.dlang.org/show_bug.cgi?id=14024
+ assert(aggr2.op == TOK.arrayLiteral);
+ Expressions* oldelems = existingAE.elements;
+ Expressions* newelems = (cast(ArrayLiteralExp)aggr2).elements;
+
+ Type elemtype = aggregate.type.nextOf();
+ bool needsPostblit = e.e2.isLvalue();
+
+ if (aggregate == aggr2 && srclower < lowerbound && lowerbound < srcupper)
+ {
+ // reverse order
+ for (auto i = upperbound - lowerbound; 0 < i--;)
+ {
+ Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
+ Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
+ newelem = copyLiteral(newelem).copy();
+ newelem.type = elemtype;
+ if (needsPostblit)
+ {
+ if (Expression x = evaluatePostblit(istate, newelem))
+ return x;
+ }
+ if (Expression x = evaluateDtor(istate, oldelem))
+ return x;
+ (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
+ }
+ }
+ else
+ {
+ // normal order
+ for (auto i = 0; i < upperbound - lowerbound; i++)
+ {
+ Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
+ Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
+ newelem = copyLiteral(newelem).copy();
+ newelem.type = elemtype;
+ if (needsPostblit)
+ {
+ if (Expression x = evaluatePostblit(istate, newelem))
+ return x;
+ }
+ if (Expression x = evaluateDtor(istate, oldelem))
+ return x;
+ (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
+ }
+ }
+
+ //assert(0);
+ return newval; // oldval?
+ }
+ if (aggregate == aggr2 &&
+ lowerbound < srcupper && srclower < upperbound)
+ {
+ e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
+ ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
+ return CTFEExp.cantexp;
+ }
+ version (all) // todo: instead we can directly access to each elements of the slice
+ {
+ Expression orignewval = newval;
+ newval = resolveSlice(newval);
+ if (CTFEExp.isCantExp(newval))
+ {
+ e.error("CTFE internal error: slice `%s`", orignewval.toChars());
+ return CTFEExp.cantexp;
+ }
+ }
+ // no overlapping
+ //length?
+ assert(newval.op != TOK.slice);
+ }
+ if (newval.op == TOK.string_ && !isBlockAssignment)
+ {
+ /* Mixed slice: it was initialized as an array literal of chars/integers.
+ * Now a slice of it is being set with a string.
+ */
+ sliceAssignArrayLiteralFromString(existingAE, cast(StringExp)newval, cast(size_t)firstIndex);
+ return newval;
+ }
+ if (newval.op == TOK.arrayLiteral && !isBlockAssignment)
+ {
+ Expressions* oldelems = existingAE.elements;
+ Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
+ Type elemtype = existingAE.type.nextOf();
+ bool needsPostblit = e.op != TOK.blit && e.e2.isLvalue();
+ foreach (j, newelem; *newelems)
+ {
+ newelem = paintTypeOntoLiteral(elemtype, newelem);
+ if (needsPostblit)
+ {
+ Expression x = evaluatePostblit(istate, newelem);
+ if (exceptionOrCantInterpret(x))
+ return x;
+ }
+ (*oldelems)[cast(size_t)(j + firstIndex)] = newelem;
+ }
+ return newval;
+ }
+
+ /* Block assignment, initialization of static arrays
+ * x[] = newval
+ * x may be a multidimensional static array. (Note that this
+ * only happens with array literals, never with strings).
+ */
+ struct RecursiveBlock
+ {
+ InterState* istate;
+ Expression newval;
+ bool refCopy;
+ bool needsPostblit;
+ bool needsDtor;
+
+ extern (C++) Expression assignTo(ArrayLiteralExp ae)
+ {
+ return assignTo(ae, 0, ae.elements.dim);
+ }
+
+ extern (C++) Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr)
+ {
+ Expressions* w = ae.elements;
+ assert(ae.type.ty == Tsarray || ae.type.ty == Tarray);
+ bool directblk = (cast(TypeArray)ae.type).next.equivalent(newval.type);
+ for (size_t k = lwr; k < upr; k++)
+ {
+ if (!directblk && (*w)[k].op == TOK.arrayLiteral)
+ {
+ // Multidimensional array block assign
+ if (Expression ex = assignTo(cast(ArrayLiteralExp)(*w)[k]))
+ return ex;
+ }
+ else if (refCopy)
+ {
+ (*w)[k] = newval;
+ }
+ else if (!needsPostblit && !needsDtor)
+ {
+ assignInPlace((*w)[k], newval);
+ }
+ else
+ {
+ Expression oldelem = (*w)[k];
+ Expression tmpelem = needsDtor ? copyLiteral(oldelem).copy() : null;
+ assignInPlace(oldelem, newval);
+ if (needsPostblit)
+ {
+ if (Expression ex = evaluatePostblit(istate, oldelem))
+ return ex;
+ }
+ if (needsDtor)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=14860
+ if (Expression ex = evaluateDtor(istate, tmpelem))
+ return ex;
+ }
+ }
+ }
+ return null;
+ }
+ }
+
+ Type tn = newval.type.toBasetype();
+ bool wantRef = (tn.ty == Tarray || isAssocArray(tn) || tn.ty == Tclass);
+ bool cow = newval.op != TOK.structLiteral && newval.op != TOK.arrayLiteral && newval.op != TOK.string_;
+ Type tb = tn.baseElemOf();
+ StructDeclaration sd = (tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null);
+
+ RecursiveBlock rb;
+ rb.istate = istate;
+ rb.newval = newval;
+ rb.refCopy = wantRef || cow;
+ rb.needsPostblit = sd && sd.postblit && e.op != TOK.blit && e.e2.isLvalue();
+ rb.needsDtor = sd && sd.dtor && e.op == TOK.assign;
+ if (Expression ex = rb.assignTo(existingAE, cast(size_t)lowerbound, cast(size_t)upperbound))
+ return ex;
+
+ if (goal == CTFEGoal.Nothing)
+ return null; // avoid creating an unused literal
+ auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingAE,
+ ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
+ ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
+ retslice.type = e.type;
+ return interpret(pue, retslice, istate);
+ }
+
+ e.error("slice operation `%s = %s` cannot be evaluated at compile time", e1.toChars(), newval.toChars());
+ return CTFEExp.cantexp;
+ }
+
+ override void visit(AssignExp e)
+ {
+ interpretAssignCommon(e, null);
+ }
+
+ override void visit(BinAssignExp e)
+ {
+ switch (e.op)
+ {
+ case TOK.addAssign:
+ interpretAssignCommon(e, &Add);
+ return;
+
+ case TOK.minAssign:
+ interpretAssignCommon(e, &Min);
+ return;
+
+ case TOK.concatenateAssign:
+ case TOK.concatenateElemAssign:
+ case TOK.concatenateDcharAssign:
+ interpretAssignCommon(e, &ctfeCat);
+ return;
+
+ case TOK.mulAssign:
+ interpretAssignCommon(e, &Mul);
+ return;
+
+ case TOK.divAssign:
+ interpretAssignCommon(e, &Div);
+ return;
+
+ case TOK.modAssign:
+ interpretAssignCommon(e, &Mod);
+ return;
+
+ case TOK.leftShiftAssign:
+ interpretAssignCommon(e, &Shl);
+ return;
+
+ case TOK.rightShiftAssign:
+ interpretAssignCommon(e, &Shr);
+ return;
+
+ case TOK.unsignedRightShiftAssign:
+ interpretAssignCommon(e, &Ushr);
+ return;
+
+ case TOK.andAssign:
+ interpretAssignCommon(e, &And);
+ return;
+
+ case TOK.orAssign:
+ interpretAssignCommon(e, &Or);
+ return;
+
+ case TOK.xorAssign:
+ interpretAssignCommon(e, &Xor);
+ return;
+
+ case TOK.powAssign:
+ interpretAssignCommon(e, &Pow);
+ return;
+
+ default:
+ assert(0);
+ }
+ }
+
+ override void visit(PostExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s PostExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ if (e.op == TOK.plusPlus)
+ interpretAssignCommon(e, &Add, 1);
+ else
+ interpretAssignCommon(e, &Min, 1);
+ debug (LOG)
+ {
+ if (CTFEExp.isCantExp(result))
+ printf("PostExp::interpret() CANT\n");
+ }
+ }
+
+ /* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison;
+ * -1 if e is a p1 < p2 or p1 <= p2 pointer comparison;
+ * 0 otherwise
+ */
+ static int isPointerCmpExp(Expression e, Expression* p1, Expression* p2)
+ {
+ int ret = 1;
+ while (e.op == TOK.not)
+ {
+ ret *= -1;
+ e = (cast(NotExp)e).e1;
+ }
+ switch (e.op)
+ {
+ case TOK.lessThan:
+ case TOK.lessOrEqual:
+ ret *= -1;
+ goto case; /+ fall through +/
+ case TOK.greaterThan:
+ case TOK.greaterOrEqual:
+ *p1 = (cast(BinExp)e).e1;
+ *p2 = (cast(BinExp)e).e2;
+ if (!(isPointer((*p1).type) && isPointer((*p2).type)))
+ ret = 0;
+ break;
+
+ default:
+ ret = 0;
+ break;
+ }
+ return ret;
+ }
+
+ /** If this is a four pointer relation, evaluate it, else return NULL.
+ *
+ * This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2)
+ * where p1, p2 are expressions yielding pointers to memory block p,
+ * and q1, q2 are expressions yielding pointers to memory block q.
+ * This expression is valid even if p and q are independent memory
+ * blocks and are therefore not normally comparable; the && form returns true
+ * if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns
+ * true if [p1..p2] lies outside [q1..q2], and false otherwise.
+ *
+ * Within the expression, any ordering of p1, p2, q1, q2 is permissible;
+ * the comparison operators can be any of >, <, <=, >=, provided that
+ * both directions (p > q and p < q) are checked. Additionally the
+ * relational sub-expressions can be negated, eg
+ * (!(q1 < p1) && p2 <= q2) is valid.
+ */
+ private void interpretFourPointerRelation(UnionExp* pue, BinExp e)
+ {
+ assert(e.op == TOK.andAnd || e.op == TOK.orOr);
+
+ /* It can only be an isInside expression, if both e1 and e2 are
+ * directional pointer comparisons.
+ * Note that this check can be made statically; it does not depends on
+ * any runtime values. This allows a JIT implementation to compile a
+ * special AndAndPossiblyInside, keeping the normal AndAnd case efficient.
+ */
+
+ // Save the pointer expressions and the comparison directions,
+ // so we can use them later.
+ Expression p1 = null;
+ Expression p2 = null;
+ Expression p3 = null;
+ Expression p4 = null;
+ int dir1 = isPointerCmpExp(e.e1, &p1, &p2);
+ int dir2 = isPointerCmpExp(e.e2, &p3, &p4);
+ if (dir1 == 0 || dir2 == 0)
+ {
+ result = null;
+ return;
+ }
+
+ //printf("FourPointerRelation %s\n", toChars());
+
+ UnionExp ue1 = void;
+ UnionExp ue2 = void;
+ UnionExp ue3 = void;
+ UnionExp ue4 = void;
+
+ // Evaluate the first two pointers
+ p1 = interpret(&ue1, p1, istate);
+ if (exceptionOrCant(p1))
+ return;
+ p2 = interpret(&ue2, p2, istate);
+ if (exceptionOrCant(p2))
+ return;
+ dinteger_t ofs1, ofs2;
+ Expression agg1 = getAggregateFromPointer(p1, &ofs1);
+ Expression agg2 = getAggregateFromPointer(p2, &ofs2);
+
+ if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != TOK.null_ && agg2.op != TOK.null_)
+ {
+ // Here it is either CANT_INTERPRET,
+ // or an IsInside comparison returning false.
+ p3 = interpret(&ue3, p3, istate);
+ if (CTFEExp.isCantExp(p3))
+ return;
+ // Note that it is NOT legal for it to throw an exception!
+ Expression except = null;
+ if (exceptionOrCantInterpret(p3))
+ except = p3;
+ else
+ {
+ p4 = interpret(&ue4, p4, istate);
+ if (CTFEExp.isCantExp(p4))
+ {
+ result = p4;
+ return;
+ }
+ if (exceptionOrCantInterpret(p4))
+ except = p4;
+ }
+ if (except)
+ {
+ e.error("comparison `%s` of pointers to unrelated memory blocks remains indeterminate at compile time because exception `%s` was thrown while evaluating `%s`", e.e1.toChars(), except.toChars(), e.e2.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ dinteger_t ofs3, ofs4;
+ Expression agg3 = getAggregateFromPointer(p3, &ofs3);
+ Expression agg4 = getAggregateFromPointer(p4, &ofs4);
+ // The valid cases are:
+ // p1 > p2 && p3 > p4 (same direction, also for < && <)
+ // p1 > p2 && p3 < p4 (different direction, also < && >)
+ // Changing any > into >= doesn't affect the result
+ if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) ||
+ (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
+ {
+ // it's a legal two-sided comparison
+ emplaceExp!(IntegerExp)(pue, e.loc, (e.op == TOK.andAnd) ? 0 : 1, e.type);
+ result = pue.exp();
+ return;
+ }
+ // It's an invalid four-pointer comparison. Either the second
+ // comparison is in the same direction as the first, or else
+ // more than two memory blocks are involved (either two independent
+ // invalid comparisons are present, or else agg3 == agg4).
+ e.error("comparison `%s` of pointers to unrelated memory blocks is indeterminate at compile time, even when combined with `%s`.", e.e1.toChars(), e.e2.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ // The first pointer expression didn't need special treatment, so we
+ // we need to interpret the entire expression exactly as a normal && or ||.
+ // This is easy because we haven't evaluated e2 at all yet, and we already
+ // know it will return a bool.
+ // But we mustn't evaluate the pointer expressions in e1 again, in case
+ // they have side-effects.
+ bool nott = false;
+ Expression ex = e.e1;
+ while (1)
+ {
+ if (auto ne = ex.isNotExp())
+ {
+ nott = !nott;
+ ex = ne.e1;
+ }
+ else
+ break;
+ }
+
+ /** Negate relational operator, eg >= becomes <
+ * Params:
+ * op = comparison operator to negate
+ * Returns:
+ * negate operator
+ */
+ static TOK negateRelation(TOK op) pure
+ {
+ switch (op)
+ {
+ case TOK.greaterOrEqual: op = TOK.lessThan; break;
+ case TOK.greaterThan: op = TOK.lessOrEqual; break;
+ case TOK.lessOrEqual: op = TOK.greaterThan; break;
+ case TOK.lessThan: op = TOK.greaterOrEqual; break;
+ default: assert(0);
+ }
+ return op;
+ }
+
+ const TOK cmpop = nott ? negateRelation(ex.op) : ex.op;
+ const cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
+ // We already know this is a valid comparison.
+ assert(cmp >= 0);
+ if (e.op == TOK.andAnd && cmp == 1 || e.op == TOK.orOr && cmp == 0)
+ {
+ result = interpret(pue, e.e2, istate);
+ return;
+ }
+ emplaceExp!(IntegerExp)(pue, e.loc, (e.op == TOK.andAnd) ? 0 : 1, e.type);
+ result = pue.exp();
+ }
+
+ override void visit(LogicalExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s LogicalExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ // Check for an insidePointer expression, evaluate it if so
+ interpretFourPointerRelation(pue, e);
+ if (result)
+ return;
+
+ UnionExp ue1 = void;
+ result = interpret(&ue1, e.e1, istate);
+ if (exceptionOrCant(result))
+ return;
+
+ bool res;
+ const andand = e.op == TOK.andAnd;
+ if (andand ? result.isBool(false) : isTrueBool(result))
+ res = !andand;
+ else if (andand ? isTrueBool(result) : result.isBool(false))
+ {
+ UnionExp ue2 = void;
+ result = interpret(&ue2, e.e2, istate);
+ if (exceptionOrCant(result))
+ return;
+ if (result.op == TOK.voidExpression)
+ {
+ assert(e.type.ty == Tvoid);
+ result = null;
+ return;
+ }
+ if (result.isBool(false))
+ res = false;
+ else if (isTrueBool(result))
+ res = true;
+ else
+ {
+ e.error("`%s` does not evaluate to a `bool`", result.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ }
+ else
+ {
+ e.error("`%s` cannot be interpreted as a `bool`", result.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ incUsageCtfe(istate, e.e2.loc);
+
+ if (goal != CTFEGoal.Nothing)
+ {
+ if (e.type.equals(Type.tbool))
+ result = IntegerExp.createBool(res);
+ else
+ {
+ emplaceExp!(IntegerExp)(pue, e.loc, res, e.type);
+ result = pue.exp();
+ }
+ }
+ }
+
+
+ // Print a stack trace, starting from callingExp which called fd.
+ // To shorten the stack trace, try to detect recursion.
+ private void showCtfeBackTrace(CallExp callingExp, FuncDeclaration fd)
+ {
+ if (ctfeGlobals.stackTraceCallsToSuppress > 0)
+ {
+ --ctfeGlobals.stackTraceCallsToSuppress;
+ return;
+ }
+ errorSupplemental(callingExp.loc, "called from here: `%s`", callingExp.toChars());
+ // Quit if it's not worth trying to compress the stack trace
+ if (ctfeGlobals.callDepth < 6 || global.params.verbose)
+ return;
+ // Recursion happens if the current function already exists in the call stack.
+ int numToSuppress = 0;
+ int recurseCount = 0;
+ int depthSoFar = 0;
+ InterState* lastRecurse = istate;
+ for (InterState* cur = istate; cur; cur = cur.caller)
+ {
+ if (cur.fd == fd)
+ {
+ ++recurseCount;
+ numToSuppress = depthSoFar;
+ lastRecurse = cur;
+ }
+ ++depthSoFar;
+ }
+ // We need at least three calls to the same function, to make compression worthwhile
+ if (recurseCount < 2)
+ return;
+ // We found a useful recursion. Print all the calls involved in the recursion
+ errorSupplemental(fd.loc, "%d recursive calls to function `%s`", recurseCount, fd.toChars());
+ for (InterState* cur = istate; cur.fd != fd; cur = cur.caller)
+ {
+ errorSupplemental(cur.fd.loc, "recursively called from function `%s`", cur.fd.toChars());
+ }
+ // We probably didn't enter the recursion in this function.
+ // Go deeper to find the real beginning.
+ InterState* cur = istate;
+ while (lastRecurse.caller && cur.fd == lastRecurse.caller.fd)
+ {
+ cur = cur.caller;
+ lastRecurse = lastRecurse.caller;
+ ++numToSuppress;
+ }
+ ctfeGlobals.stackTraceCallsToSuppress = numToSuppress;
+ }
+
+ override void visit(CallExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s CallExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ Expression pthis = null;
+ FuncDeclaration fd = null;
+
+ Expression ecall = interpretRegion(e.e1, istate);
+ if (exceptionOrCant(ecall))
+ return;
+
+ if (auto dve = ecall.isDotVarExp())
+ {
+ // Calling a member function
+ pthis = dve.e1;
+ fd = dve.var.isFuncDeclaration();
+ assert(fd);
+
+ if (auto dte = pthis.isDotTypeExp())
+ pthis = dte.e1;
+ }
+ else if (auto ve = ecall.isVarExp())
+ {
+ fd = ve.var.isFuncDeclaration();
+ assert(fd);
+
+ // If `_d_HookTraceImpl` is found, resolve the underlying hook and replace `e` and `fd` with it.
+ removeHookTraceImpl(e, fd);
+
+ if (fd.ident == Id.__ArrayPostblit || fd.ident == Id.__ArrayDtor)
+ {
+ assert(e.arguments.dim == 1);
+ Expression ea = (*e.arguments)[0];
+ // printf("1 ea = %s %s\n", ea.type.toChars(), ea.toChars());
+ if (auto se = ea.isSliceExp())
+ ea = se.e1;
+ if (auto ce = ea.isCastExp())
+ ea = ce.e1;
+
+ // printf("2 ea = %s, %s %s\n", ea.type.toChars(), Token.toChars(ea.op), ea.toChars());
+ if (ea.op == TOK.variable || ea.op == TOK.symbolOffset)
+ result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, CTFEGoal.RValue);
+ else if (auto ae = ea.isAddrExp())
+ result = interpretRegion(ae.e1, istate);
+
+ // https://issues.dlang.org/show_bug.cgi?id=18871
+ // https://issues.dlang.org/show_bug.cgi?id=18819
+ else if (auto ale = ea.isArrayLiteralExp())
+ result = interpretRegion(ale, istate);
+
+ else
+ assert(0);
+ if (CTFEExp.isCantExp(result))
+ return;
+
+ if (fd.ident == Id.__ArrayPostblit)
+ result = evaluatePostblit(istate, result);
+ else
+ result = evaluateDtor(istate, result);
+ if (!result)
+ result = CTFEExp.voidexp;
+ return;
+ }
+ else if (fd.ident == Id._d_arraysetlengthT)
+ {
+ // In expressionsem.d `ea.length = eb;` got lowered to `_d_arraysetlengthT(ea, eb);`.
+ // The following code will rewrite it back to `ea.length = eb` and then interpret that expression.
+ assert(e.arguments.dim == 2);
+
+ Expression ea = (*e.arguments)[0];
+ Expression eb = (*e.arguments)[1];
+
+ auto ale = ctfeEmplaceExp!ArrayLengthExp(e.loc, ea);
+ ale.type = Type.tsize_t;
+ AssignExp ae = ctfeEmplaceExp!AssignExp(e.loc, ale, eb);
+ ae.type = ea.type;
+
+ // if (global.params.verbose)
+ // message("interpret %s =>\n %s", e.toChars(), ae.toChars());
+ result = interpretRegion(ae, istate);
+ return;
+ }
+ }
+ else if (auto soe = ecall.isSymOffExp())
+ {
+ fd = soe.var.isFuncDeclaration();
+ assert(fd && soe.offset == 0);
+ }
+ else if (auto de = ecall.isDelegateExp())
+ {
+ // Calling a delegate
+ fd = de.func;
+ pthis = de.e1;
+
+ // Special handling for: &nestedfunc --> DelegateExp(VarExp(nestedfunc), nestedfunc)
+ if (auto ve = pthis.isVarExp())
+ if (ve.var == fd)
+ pthis = null; // context is not necessary for CTFE
+ }
+ else if (auto fe = ecall.isFuncExp())
+ {
+ // Calling a delegate literal
+ fd = fe.fd;
+ }
+ else
+ {
+ // delegate.funcptr()
+ // others
+ e.error("cannot call `%s` at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (!fd)
+ {
+ e.error("CTFE internal error: cannot evaluate `%s` at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (pthis)
+ {
+ // Member function call
+
+ // Currently this is satisfied because closure is not yet supported.
+ assert(!fd.isNested() || fd.needThis());
+
+ if (pthis.op == TOK.typeid_)
+ {
+ pthis.error("static variable `%s` cannot be read at compile time", pthis.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ assert(pthis);
+
+ if (pthis.op == TOK.null_)
+ {
+ assert(pthis.type.toBasetype().ty == Tclass);
+ e.error("function call through null class reference `%s`", pthis.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ assert(pthis.op == TOK.structLiteral || pthis.op == TOK.classReference || pthis.op == TOK.type);
+
+ if (fd.isVirtual() && !e.directcall)
+ {
+ // Make a virtual function call.
+ // Get the function from the vtable of the original class
+ ClassDeclaration cd = pthis.isClassReferenceExp().originalClass();
+
+ // We can't just use the vtable index to look it up, because
+ // vtables for interfaces don't get populated until the glue layer.
+ fd = cd.findFunc(fd.ident, fd.type.isTypeFunction());
+ assert(fd);
+ }
+ }
+
+ if (fd && fd.semanticRun >= PASS.semantic3done && fd.semantic3Errors)
+ {
+ e.error("CTFE failed because of previous errors in `%s`", fd.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ // Check for built-in functions
+ result = evaluateIfBuiltin(pue, istate, e.loc, fd, e.arguments, pthis);
+ if (result)
+ return;
+
+ if (!fd.fbody)
+ {
+ e.error("`%s` cannot be interpreted at compile time, because it has no available source code", fd.toChars());
+ result = CTFEExp.showcontext;
+ return;
+ }
+
+ result = interpretFunction(pue, fd, istate, e.arguments, pthis);
+ if (result.op == TOK.voidExpression)
+ return;
+ if (!exceptionOrCantInterpret(result))
+ {
+ if (goal != CTFEGoal.LValue) // Peel off CTFE reference if it's unnecessary
+ {
+ if (result == pue.exp())
+ result = pue.copy();
+ result = interpret(pue, result, istate);
+ }
+ }
+ if (!exceptionOrCantInterpret(result))
+ {
+ result = paintTypeOntoLiteral(pue, e.type, result);
+ result.loc = e.loc;
+ }
+ else if (CTFEExp.isCantExp(result) && !global.gag)
+ showCtfeBackTrace(e, fd); // Print a stack trace.
+ }
+
+ override void visit(CommaExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s CommaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+
+ // If it creates a variable, and there's no context for
+ // the variable to be created in, we need to create one now.
+ InterState istateComma;
+ if (!istate && firstComma(e.e1).op == TOK.declaration)
+ {
+ ctfeGlobals.stack.startFrame(null);
+ istate = &istateComma;
+ }
+
+ void endTempStackFrame()
+ {
+ // If we created a temporary stack frame, end it now.
+ if (istate == &istateComma)
+ ctfeGlobals.stack.endFrame();
+ }
+
+ result = CTFEExp.cantexp;
+
+ // If the comma returns a temporary variable, it needs to be an lvalue
+ // (this is particularly important for struct constructors)
+ if (e.e1.op == TOK.declaration &&
+ e.e2.op == TOK.variable &&
+ e.e1.isDeclarationExp().declaration == e.e2.isVarExp().var &&
+ e.e2.isVarExp().var.storage_class & STC.ctfe)
+ {
+ VarExp ve = e.e2.isVarExp();
+ VarDeclaration v = ve.var.isVarDeclaration();
+ ctfeGlobals.stack.push(v);
+ if (!v._init && !getValue(v))
+ {
+ setValue(v, copyLiteral(v.type.defaultInitLiteral(e.loc)).copy());
+ }
+ if (!getValue(v))
+ {
+ Expression newval = v._init.initializerToExpression();
+ // Bug 4027. Copy constructors are a weird case where the
+ // initializer is a void function (the variable is modified
+ // through a reference parameter instead).
+ newval = interpretRegion(newval, istate);
+ if (exceptionOrCant(newval))
+ return endTempStackFrame();
+ if (newval.op != TOK.voidExpression)
+ {
+ // v isn't necessarily null.
+ setValueWithoutChecking(v, copyLiteral(newval).copy());
+ }
+ }
+ }
+ else
+ {
+ UnionExp ue = void;
+ auto e1 = interpret(&ue, e.e1, istate, CTFEGoal.Nothing);
+ if (exceptionOrCant(e1))
+ return endTempStackFrame();
+ }
+ result = interpret(pue, e.e2, istate, goal);
+ return endTempStackFrame();
+ }
+
+ override void visit(CondExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s CondExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ UnionExp uecond = void;
+ Expression econd;
+ econd = interpret(&uecond, e.econd, istate);
+ if (exceptionOrCant(econd))
+ return;
+
+ if (isPointer(e.econd.type))
+ {
+ if (econd.op != TOK.null_)
+ {
+ econd = IntegerExp.createBool(true);
+ }
+ }
+
+ if (isTrueBool(econd))
+ {
+ result = interpret(pue, e.e1, istate, goal);
+ incUsageCtfe(istate, e.e1.loc);
+ }
+ else if (econd.isBool(false))
+ {
+ result = interpret(pue, e.e2, istate, goal);
+ incUsageCtfe(istate, e.e2.loc);
+ }
+ else
+ {
+ e.error("`%s` does not evaluate to boolean result at compile time", e.econd.toChars());
+ result = CTFEExp.cantexp;
+ }
+ }
+
+ override void visit(ArrayLengthExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s ArrayLengthExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ UnionExp ue1;
+ Expression e1 = interpret(&ue1, e.e1, istate);
+ assert(e1);
+ if (exceptionOrCant(e1))
+ return;
+ if (e1.op != TOK.string_ && e1.op != TOK.arrayLiteral && e1.op != TOK.slice && e1.op != TOK.null_)
+ {
+ e.error("`%s` cannot be evaluated at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ emplaceExp!(IntegerExp)(pue, e.loc, resolveArrayLength(e1), e.type);
+ result = pue.exp();
+ }
+
+ /**
+ * Interpret the vector expression as an array literal.
+ * Params:
+ * pue = non-null pointer to temporary storage that can be used to store the return value
+ * e = Expression to interpret
+ * Returns:
+ * resulting array literal or 'e' if unable to interpret
+ */
+ static Expression interpretVectorToArray(UnionExp* pue, VectorExp e)
+ {
+ if (auto ale = e.e1.isArrayLiteralExp())
+ return ale; // it's already an array literal
+ if (e.e1.op == TOK.int64 || e.e1.op == TOK.float64)
+ {
+ // Convert literal __vector(int) -> __vector([array])
+ auto elements = new Expressions(e.dim);
+ foreach (ref element; *elements)
+ element = copyLiteral(e.e1).copy();
+ auto type = (e.type.ty == Tvector) ? e.type.isTypeVector().basetype : e.type.isTypeSArray();
+ assert(type);
+ emplaceExp!(ArrayLiteralExp)(pue, e.loc, type, elements);
+ auto ale = pue.exp().isArrayLiteralExp();
+ ale.ownedByCtfe = OwnedBy.ctfe;
+ return ale;
+ }
+ return e;
+ }
+
+ override void visit(VectorExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s VectorExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
+ {
+ result = e;
+ return;
+ }
+ Expression e1 = interpret(pue, e.e1, istate);
+ assert(e1);
+ if (exceptionOrCant(e1))
+ return;
+ if (e1.op != TOK.arrayLiteral && e1.op != TOK.int64 && e1.op != TOK.float64)
+ {
+ e.error("`%s` cannot be evaluated at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (e1 == pue.exp())
+ e1 = pue.copy();
+ emplaceExp!(VectorExp)(pue, e.loc, e1, e.to);
+ auto ve = pue.exp().isVectorExp();
+ ve.type = e.type;
+ ve.dim = e.dim;
+ ve.ownedByCtfe = OwnedBy.ctfe;
+ result = ve;
+ }
+
+ override void visit(VectorArrayExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s VectorArrayExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ Expression e1 = interpret(pue, e.e1, istate);
+ assert(e1);
+ if (exceptionOrCant(e1))
+ return;
+ if (auto ve = e1.isVectorExp())
+ {
+ result = interpretVectorToArray(pue, ve);
+ if (result.op != TOK.vector)
+ return;
+ }
+ e.error("`%s` cannot be evaluated at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ }
+
+ override void visit(DelegatePtrExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s DelegatePtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ Expression e1 = interpret(pue, e.e1, istate);
+ assert(e1);
+ if (exceptionOrCant(e1))
+ return;
+ e.error("`%s` cannot be evaluated at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ }
+
+ override void visit(DelegateFuncptrExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s DelegateFuncptrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ Expression e1 = interpret(pue, e.e1, istate);
+ assert(e1);
+ if (exceptionOrCant(e1))
+ return;
+ e.error("`%s` cannot be evaluated at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ }
+
+ static bool resolveIndexing(IndexExp e, InterState* istate, Expression* pagg, uinteger_t* pidx, bool modify)
+ {
+ assert(e.e1.type.toBasetype().ty != Taarray);
+
+ if (e.e1.type.toBasetype().ty == Tpointer)
+ {
+ // Indexing a pointer. Note that there is no $ in this case.
+ Expression e1 = interpretRegion(e.e1, istate);
+ if (exceptionOrCantInterpret(e1))
+ return false;
+
+ Expression e2 = interpretRegion(e.e2, istate);
+ if (exceptionOrCantInterpret(e2))
+ return false;
+ sinteger_t indx = e2.toInteger();
+
+ dinteger_t ofs;
+ Expression agg = getAggregateFromPointer(e1, &ofs);
+
+ if (agg.op == TOK.null_)
+ {
+ e.error("cannot index through null pointer `%s`", e.e1.toChars());
+ return false;
+ }
+ if (agg.op == TOK.int64)
+ {
+ e.error("cannot index through invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
+ return false;
+ }
+ // Pointer to a non-array variable
+ if (agg.op == TOK.symbolOffset)
+ {
+ e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), (cast(SymOffExp)agg).var.toChars());
+ return false;
+ }
+
+ if (agg.op == TOK.arrayLiteral || agg.op == TOK.string_)
+ {
+ dinteger_t len = resolveArrayLength(agg);
+ if (ofs + indx >= len)
+ {
+ e.error("pointer index `[%lld]` exceeds allocated memory block `[0..%lld]`", ofs + indx, len);
+ return false;
+ }
+ }
+ else
+ {
+ if (ofs + indx != 0)
+ {
+ e.error("pointer index `[%lld]` lies outside memory block `[0..1]`", ofs + indx);
+ return false;
+ }
+ }
+ *pagg = agg;
+ *pidx = ofs + indx;
+ return true;
+ }
+
+ Expression e1 = interpretRegion(e.e1, istate);
+ if (exceptionOrCantInterpret(e1))
+ return false;
+ if (e1.op == TOK.null_)
+ {
+ e.error("cannot index null array `%s`", e.e1.toChars());
+ return false;
+ }
+ if (auto ve = e1.isVectorExp())
+ {
+ UnionExp ue = void;
+ e1 = interpretVectorToArray(&ue, ve);
+ e1 = (e1 == ue.exp()) ? ue.copy() : e1;
+ }
+
+ // Set the $ variable, and find the array literal to modify
+ dinteger_t len;
+ if (e1.op == TOK.variable && e1.type.toBasetype().ty == Tsarray)
+ len = e1.type.toBasetype().isTypeSArray().dim.toInteger();
+ else
+ {
+ if (e1.op != TOK.arrayLiteral && e1.op != TOK.string_ && e1.op != TOK.slice && e1.op != TOK.vector)
+ {
+ e.error("cannot determine length of `%s` at compile time", e.e1.toChars());
+ return false;
+ }
+ len = resolveArrayLength(e1);
+ }
+
+ if (e.lengthVar)
+ {
+ Expression dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, len, Type.tsize_t);
+ ctfeGlobals.stack.push(e.lengthVar);
+ setValue(e.lengthVar, dollarExp);
+ }
+ Expression e2 = interpretRegion(e.e2, istate);
+ if (e.lengthVar)
+ ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside []
+ if (exceptionOrCantInterpret(e2))
+ return false;
+ if (e2.op != TOK.int64)
+ {
+ e.error("CTFE internal error: non-integral index `[%s]`", e.e2.toChars());
+ return false;
+ }
+
+ if (auto se = e1.isSliceExp())
+ {
+ // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx']
+ uinteger_t index = e2.toInteger();
+ uinteger_t ilwr = se.lwr.toInteger();
+ uinteger_t iupr = se.upr.toInteger();
+
+ if (index > iupr - ilwr)
+ {
+ e.error("index %llu exceeds array length %llu", index, iupr - ilwr);
+ return false;
+ }
+ *pagg = (cast(SliceExp)e1).e1;
+ *pidx = index + ilwr;
+ }
+ else
+ {
+ *pagg = e1;
+ *pidx = e2.toInteger();
+ if (len <= *pidx)
+ {
+ e.error("array index %lld is out of bounds `[0..%lld]`", *pidx, len);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ override void visit(IndexExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s IndexExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
+ }
+ if (e.e1.type.toBasetype().ty == Tpointer)
+ {
+ Expression agg;
+ uinteger_t indexToAccess;
+ if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
+ {
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (agg.op == TOK.arrayLiteral || agg.op == TOK.string_)
+ {
+ if (goal == CTFEGoal.LValue)
+ {
+ // if we need a reference, IndexExp shouldn't be interpreting
+ // the expression to a value, it should stay as a reference
+ emplaceExp!(IndexExp)(pue, e.loc, agg, ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, e.e2.type));
+ result = pue.exp();
+ result.type = e.type;
+ return;
+ }
+ result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
+ return;
+ }
+ else
+ {
+ assert(indexToAccess == 0);
+ result = interpretRegion(agg, istate, goal);
+ if (exceptionOrCant(result))
+ return;
+ result = paintTypeOntoLiteral(pue, e.type, result);
+ return;
+ }
+ }
+
+ if (e.e1.type.toBasetype().ty == Taarray)
+ {
+ Expression e1 = interpretRegion(e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ if (e1.op == TOK.null_)
+ {
+ if (goal == CTFEGoal.LValue && e1.type.ty == Taarray && e.modifiable)
+ {
+ assert(0); // does not reach here?
+ }
+ e.error("cannot index null array `%s`", e.e1.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ Expression e2 = interpretRegion(e.e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+
+ if (goal == CTFEGoal.LValue)
+ {
+ // Pointer or reference of a scalar type
+ if (e1 == e.e1 && e2 == e.e2)
+ result = e;
+ else
+ {
+ emplaceExp!(IndexExp)(pue, e.loc, e1, e2);
+ result = pue.exp();
+ result.type = e.type;
+ }
+ return;
+ }
+
+ assert(e1.op == TOK.assocArrayLiteral);
+ UnionExp e2tmp = void;
+ e2 = resolveSlice(e2, &e2tmp);
+ result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e1, e2);
+ if (!result)
+ {
+ e.error("key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars());
+ result = CTFEExp.cantexp;
+ }
+ return;
+ }
+
+ Expression agg;
+ uinteger_t indexToAccess;
+ if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
+ {
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ if (goal == CTFEGoal.LValue)
+ {
+ Expression e2 = ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, Type.tsize_t);
+ emplaceExp!(IndexExp)(pue, e.loc, agg, e2);
+ result = pue.exp();
+ result.type = e.type;
+ return;
+ }
+
+ result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
+ if (exceptionOrCant(result))
+ return;
+ if (result.op == TOK.void_)
+ {
+ e.error("`%s` is used before initialized", e.toChars());
+ errorSupplemental(result.loc, "originally uninitialized here");
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (result == pue.exp())
+ result = result.copy();
+ }
+
+ override void visit(SliceExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s SliceExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ if (e.e1.type.toBasetype().ty == Tpointer)
+ {
+ // Slicing a pointer. Note that there is no $ in this case.
+ Expression e1 = interpretRegion(e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ if (e1.op == TOK.int64)
+ {
+ e.error("cannot slice invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ /* Evaluate lower and upper bounds of slice
+ */
+ Expression lwr = interpretRegion(e.lwr, istate);
+ if (exceptionOrCant(lwr))
+ return;
+ Expression upr = interpretRegion(e.upr, istate);
+ if (exceptionOrCant(upr))
+ return;
+ uinteger_t ilwr = lwr.toInteger();
+ uinteger_t iupr = upr.toInteger();
+
+ dinteger_t ofs;
+ Expression agg = getAggregateFromPointer(e1, &ofs);
+ ilwr += ofs;
+ iupr += ofs;
+ if (agg.op == TOK.null_)
+ {
+ if (iupr == ilwr)
+ {
+ result = ctfeEmplaceExp!NullExp(e.loc);
+ result.type = e.type;
+ return;
+ }
+ e.error("cannot slice null pointer `%s`", e.e1.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (agg.op == TOK.symbolOffset)
+ {
+ e.error("slicing pointers to static variables is not supported in CTFE");
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (agg.op != TOK.arrayLiteral && agg.op != TOK.string_)
+ {
+ e.error("pointer `%s` cannot be sliced at compile time (it does not point to an array)", e.e1.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ assert(agg.op == TOK.arrayLiteral || agg.op == TOK.string_);
+ dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger();
+ //Type *pointee = ((TypePointer *)agg.type)->next;
+ if (iupr > (len + 1) || iupr < ilwr)
+ {
+ e.error("pointer slice `[%lld..%lld]` exceeds allocated memory block `[0..%lld]`", ilwr, iupr, len);
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (ofs != 0)
+ {
+ lwr = ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type);
+ upr = ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type);
+ }
+ emplaceExp!(SliceExp)(pue, e.loc, agg, lwr, upr);
+ result = pue.exp();
+ result.type = e.type;
+ return;
+ }
+
+ CTFEGoal goal1 = CTFEGoal.RValue;
+ if (goal == CTFEGoal.LValue)
+ {
+ if (e.e1.type.toBasetype().ty == Tsarray)
+ if (auto ve = e.e1.isVarExp())
+ if (auto vd = ve.var.isVarDeclaration())
+ if (vd.storage_class & STC.ref_)
+ goal1 = CTFEGoal.LValue;
+ }
+ Expression e1 = interpret(e.e1, istate, goal1);
+ if (exceptionOrCant(e1))
+ return;
+
+ if (!e.lwr)
+ {
+ result = paintTypeOntoLiteral(pue, e.type, e1);
+ return;
+ }
+ if (auto ve = e1.isVectorExp())
+ {
+ e1 = interpretVectorToArray(pue, ve);
+ e1 = (e1 == pue.exp()) ? pue.copy() : e1;
+ }
+
+ /* Set dollar to the length of the array
+ */
+ uinteger_t dollar;
+ if ((e1.op == TOK.variable || e1.op == TOK.dotVariable) && e1.type.toBasetype().ty == Tsarray)
+ dollar = e1.type.toBasetype().isTypeSArray().dim.toInteger();
+ else
+ {
+ if (e1.op != TOK.arrayLiteral && e1.op != TOK.string_ && e1.op != TOK.null_ && e1.op != TOK.slice && e1.op != TOK.vector)
+ {
+ e.error("cannot determine length of `%s` at compile time", e1.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ dollar = resolveArrayLength(e1);
+ }
+
+ /* Set the $ variable
+ */
+ if (e.lengthVar)
+ {
+ auto dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, dollar, Type.tsize_t);
+ ctfeGlobals.stack.push(e.lengthVar);
+ setValue(e.lengthVar, dollarExp);
+ }
+
+ /* Evaluate lower and upper bounds of slice
+ */
+ Expression lwr = interpretRegion(e.lwr, istate);
+ if (exceptionOrCant(lwr))
+ {
+ if (e.lengthVar)
+ ctfeGlobals.stack.pop(e.lengthVar);
+ return;
+ }
+ Expression upr = interpretRegion(e.upr, istate);
+ if (exceptionOrCant(upr))
+ {
+ if (e.lengthVar)
+ ctfeGlobals.stack.pop(e.lengthVar);
+ return;
+ }
+ if (e.lengthVar)
+ ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside [L..U]
+
+ uinteger_t ilwr = lwr.toInteger();
+ uinteger_t iupr = upr.toInteger();
+ if (e1.op == TOK.null_)
+ {
+ if (ilwr == 0 && iupr == 0)
+ {
+ result = e1;
+ return;
+ }
+ e1.error("slice `[%llu..%llu]` is out of bounds", ilwr, iupr);
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (auto se = e1.isSliceExp())
+ {
+ // Simplify slice of slice:
+ // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
+ uinteger_t lo1 = se.lwr.toInteger();
+ uinteger_t up1 = se.upr.toInteger();
+ if (ilwr > iupr || iupr > up1 - lo1)
+ {
+ e.error("slice `[%llu..%llu]` exceeds array bounds `[%llu..%llu]`", ilwr, iupr, lo1, up1);
+ result = CTFEExp.cantexp;
+ return;
+ }
+ ilwr += lo1;
+ iupr += lo1;
+ emplaceExp!(SliceExp)(pue, e.loc, se.e1,
+ ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type),
+ ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type));
+ result = pue.exp();
+ result.type = e.type;
+ return;
+ }
+ if (e1.op == TOK.arrayLiteral || e1.op == TOK.string_)
+ {
+ if (iupr < ilwr || dollar < iupr)
+ {
+ e.error("slice `[%lld..%lld]` exceeds array bounds `[0..%lld]`", ilwr, iupr, dollar);
+ result = CTFEExp.cantexp;
+ return;
+ }
+ }
+ emplaceExp!(SliceExp)(pue, e.loc, e1, lwr, upr);
+ result = pue.exp();
+ result.type = e.type;
+ }
+
+ override void visit(InExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s InExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ Expression e1 = interpretRegion(e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ Expression e2 = interpretRegion(e.e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+ if (e2.op == TOK.null_)
+ {
+ emplaceExp!(NullExp)(pue, e.loc, e.type);
+ result = pue.exp();
+ return;
+ }
+ if (e2.op != TOK.assocArrayLiteral)
+ {
+ e.error("`%s` cannot be interpreted at compile time", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ e1 = resolveSlice(e1);
+ result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e2, e1);
+ if (exceptionOrCant(result))
+ return;
+ if (!result)
+ {
+ emplaceExp!(NullExp)(pue, e.loc, e.type);
+ result = pue.exp();
+ }
+ else
+ {
+ // Create a CTFE pointer &aa[index]
+ result = ctfeEmplaceExp!IndexExp(e.loc, e2, e1);
+ result.type = e.type.nextOf();
+ emplaceExp!(AddrExp)(pue, e.loc, result, e.type);
+ result = pue.exp();
+ }
+ }
+
+ override void visit(CatExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s CatExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+
+ UnionExp ue1 = void;
+ Expression e1 = interpret(&ue1, e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+
+ UnionExp ue2 = void;
+ Expression e2 = interpret(&ue2, e.e2, istate);
+ if (exceptionOrCant(e2))
+ return;
+
+ UnionExp e1tmp = void;
+ e1 = resolveSlice(e1, &e1tmp);
+
+ UnionExp e2tmp = void;
+ e2 = resolveSlice(e2, &e2tmp);
+
+ /* e1 and e2 can't go on the stack because of x~[y] and [x]~y will
+ * result in [x,y] and then x or y is on the stack.
+ * But if they are both strings, we can, because it isn't the x~[y] case.
+ */
+ if (!(e1.op == TOK.string_ && e2.op == TOK.string_))
+ {
+ if (e1 == ue1.exp())
+ e1 = ue1.copy();
+ if (e2 == ue2.exp())
+ e2 = ue2.copy();
+ }
+
+ *pue = ctfeCat(e.loc, e.type, e1, e2);
+ result = pue.exp();
+
+ if (CTFEExp.isCantExp(result))
+ {
+ e.error("`%s` cannot be interpreted at compile time", e.toChars());
+ return;
+ }
+ // We know we still own it, because we interpreted both e1 and e2
+ if (auto ale = result.isArrayLiteralExp())
+ {
+ ale.ownedByCtfe = OwnedBy.ctfe;
+
+ // https://issues.dlang.org/show_bug.cgi?id=14686
+ foreach (elem; *ale.elements)
+ {
+ Expression ex = evaluatePostblit(istate, elem);
+ if (exceptionOrCant(ex))
+ return;
+ }
+ }
+ else if (auto se = result.isStringExp())
+ se.ownedByCtfe = OwnedBy.ctfe;
+ }
+
+ override void visit(DeleteExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s DeleteExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ result = interpretRegion(e.e1, istate);
+ if (exceptionOrCant(result))
+ return;
+
+ if (result.op == TOK.null_)
+ {
+ result = CTFEExp.voidexp;
+ return;
+ }
+
+ auto tb = e.e1.type.toBasetype();
+ switch (tb.ty)
+ {
+ case Tclass:
+ if (result.op != TOK.classReference)
+ {
+ e.error("`delete` on invalid class reference `%s`", result.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ auto cre = cast(ClassReferenceExp)result;
+ auto cd = cre.originalClass();
+
+ // Find dtor(s) in inheritance chain
+ do
+ {
+ if (cd.dtor)
+ {
+ result = interpretFunction(pue, cd.dtor, istate, null, cre);
+ if (exceptionOrCant(result))
+ return;
+
+ // Dtors of Non-extern(D) classes use implicit chaining (like structs)
+ import dmd.aggregate : ClassKind;
+ if (cd.classKind != ClassKind.d)
+ break;
+ }
+
+ // Emulate manual chaining as done in rt_finalize2
+ cd = cd.baseClass;
+
+ } while (cd); // Stop after Object
+
+ break;
+
+ case Tpointer:
+ tb = (cast(TypePointer)tb).next.toBasetype();
+ if (tb.ty == Tstruct)
+ {
+ if (result.op != TOK.address ||
+ (cast(AddrExp)result).e1.op != TOK.structLiteral)
+ {
+ e.error("`delete` on invalid struct pointer `%s`", result.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ auto sd = (cast(TypeStruct)tb).sym;
+ auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1;
+
+ if (sd.dtor)
+ {
+ result = interpretFunction(pue, sd.dtor, istate, null, sle);
+ if (exceptionOrCant(result))
+ return;
+ }
+ }
+ break;
+
+ case Tarray:
+ auto tv = tb.nextOf().baseElemOf();
+ if (tv.ty == Tstruct)
+ {
+ if (result.op != TOK.arrayLiteral)
+ {
+ e.error("`delete` on invalid struct array `%s`", result.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ auto sd = (cast(TypeStruct)tv).sym;
+
+ if (sd.dtor)
+ {
+ auto ale = cast(ArrayLiteralExp)result;
+ foreach (el; *ale.elements)
+ {
+ result = interpretFunction(pue, sd.dtor, istate, null, el);
+ if (exceptionOrCant(result))
+ return;
+ }
+ }
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+ result = CTFEExp.voidexp;
+ }
+
+ override void visit(CastExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s CastExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ Expression e1 = interpretRegion(e.e1, istate, goal);
+ if (exceptionOrCant(e1))
+ return;
+ // If the expression has been cast to void, do nothing.
+ if (e.to.ty == Tvoid)
+ {
+ result = CTFEExp.voidexp;
+ return;
+ }
+ if (e.to.ty == Tpointer && e1.op != TOK.null_)
+ {
+ Type pointee = (cast(TypePointer)e.type).next;
+ // Implement special cases of normally-unsafe casts
+ if (e1.op == TOK.int64)
+ {
+ // Happens with Windows HANDLEs, for example.
+ result = paintTypeOntoLiteral(pue, e.to, e1);
+ return;
+ }
+
+ bool castToSarrayPointer = false;
+ bool castBackFromVoid = false;
+ if (e1.type.ty == Tarray || e1.type.ty == Tsarray || e1.type.ty == Tpointer)
+ {
+ // Check for unsupported type painting operations
+ // For slices, we need the type being sliced,
+ // since it may have already been type painted
+ Type elemtype = e1.type.nextOf();
+ if (auto se = e1.isSliceExp())
+ elemtype = se.e1.type.nextOf();
+
+ // Allow casts from X* to void *, and X** to void** for any X.
+ // But don't allow cast from X* to void**.
+ // So, we strip all matching * from source and target to find X.
+ // Allow casts to X* from void* only if the 'void' was originally an X;
+ // we check this later on.
+ Type ultimatePointee = pointee;
+ Type ultimateSrc = elemtype;
+ while (ultimatePointee.ty == Tpointer && ultimateSrc.ty == Tpointer)
+ {
+ ultimatePointee = ultimatePointee.nextOf();
+ ultimateSrc = ultimateSrc.nextOf();
+ }
+ if (ultimatePointee.ty == Tsarray && ultimatePointee.nextOf().equivalent(ultimateSrc))
+ {
+ castToSarrayPointer = true;
+ }
+ else if (ultimatePointee.ty != Tvoid && ultimateSrc.ty != Tvoid && !isSafePointerCast(elemtype, pointee))
+ {
+ e.error("reinterpreting cast from `%s*` to `%s*` is not supported in CTFE", elemtype.toChars(), pointee.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (ultimateSrc.ty == Tvoid)
+ castBackFromVoid = true;
+ }
+
+ if (auto se = e1.isSliceExp())
+ {
+ if (se.e1.op == TOK.null_)
+ {
+ result = paintTypeOntoLiteral(pue, e.type, se.e1);
+ return;
+ }
+ // Create a CTFE pointer &aggregate[1..2]
+ auto ei = ctfeEmplaceExp!IndexExp(e.loc, se.e1, se.lwr);
+ ei.type = e.type.nextOf();
+ emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
+ result = pue.exp();
+ return;
+ }
+ if (e1.op == TOK.arrayLiteral || e1.op == TOK.string_)
+ {
+ // Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
+ auto ei = ctfeEmplaceExp!IndexExp(e.loc, e1, ctfeEmplaceExp!IntegerExp(e.loc, 0, Type.tsize_t));
+ ei.type = e.type.nextOf();
+ emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
+ result = pue.exp();
+ return;
+ }
+ if (e1.op == TOK.index && !(cast(IndexExp)e1).e1.type.equals(e1.type))
+ {
+ // type painting operation
+ IndexExp ie = cast(IndexExp)e1;
+ if (castBackFromVoid)
+ {
+ // get the original type. For strings, it's just the type...
+ Type origType = ie.e1.type.nextOf();
+ // ..but for arrays of type void*, it's the type of the element
+ if (ie.e1.op == TOK.arrayLiteral && ie.e2.op == TOK.int64)
+ {
+ ArrayLiteralExp ale = cast(ArrayLiteralExp)ie.e1;
+ const indx = cast(size_t)ie.e2.toInteger();
+ if (indx < ale.elements.dim)
+ {
+ if (Expression xx = (*ale.elements)[indx])
+ {
+ if (auto iex = xx.isIndexExp())
+ origType = iex.e1.type.nextOf();
+ else if (auto ae = xx.isAddrExp())
+ origType = ae.e1.type;
+ else if (auto ve = xx.isVarExp())
+ origType = ve.var.type;
+ }
+ }
+ }
+ if (!isSafePointerCast(origType, pointee))
+ {
+ e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ }
+ emplaceExp!(IndexExp)(pue, e1.loc, ie.e1, ie.e2);
+ result = pue.exp();
+ result.type = e.type;
+ return;
+ }
+
+ if (auto ae = e1.isAddrExp())
+ {
+ Type origType = ae.e1.type;
+ if (isSafePointerCast(origType, pointee))
+ {
+ emplaceExp!(AddrExp)(pue, e.loc, ae.e1, e.type);
+ result = pue.exp();
+ return;
+ }
+
+ if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == TOK.index)
+ {
+ // &val[idx]
+ dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
+ IndexExp ie = cast(IndexExp)ae.e1;
+ Expression lwr = ie.e2;
+ Expression upr = ctfeEmplaceExp!IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t);
+
+ // Create a CTFE pointer &val[idx..idx+dim]
+ auto er = ctfeEmplaceExp!SliceExp(e.loc, ie.e1, lwr, upr);
+ er.type = pointee;
+ emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
+ result = pue.exp();
+ return;
+ }
+ }
+
+ if (e1.op == TOK.variable || e1.op == TOK.symbolOffset)
+ {
+ // type painting operation
+ Type origType = (cast(SymbolExp)e1).var.type;
+ if (castBackFromVoid && !isSafePointerCast(origType, pointee))
+ {
+ e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (auto ve = e1.isVarExp())
+ emplaceExp!(VarExp)(pue, e.loc, ve.var);
+ else
+ emplaceExp!(SymOffExp)(pue, e.loc, (cast(SymOffExp)e1).var, (cast(SymOffExp)e1).offset);
+ result = pue.exp();
+ result.type = e.to;
+ return;
+ }
+
+ // Check if we have a null pointer (eg, inside a struct)
+ e1 = interpretRegion(e1, istate);
+ if (e1.op != TOK.null_)
+ {
+ e.error("pointer cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ }
+ if (e.to.ty == Tsarray && e.e1.type.ty == Tvector)
+ {
+ // Special handling for: cast(float[4])__vector([w, x, y, z])
+ e1 = interpretRegion(e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ assert(e1.op == TOK.vector);
+ e1 = interpretVectorToArray(pue, e1.isVectorExp());
+ }
+ if (e.to.ty == Tarray && e1.op == TOK.slice)
+ {
+ // Note that the slice may be void[], so when checking for dangerous
+ // casts, we need to use the original type, which is se.e1.
+ SliceExp se = cast(SliceExp)e1;
+ if (!isSafePointerCast(se.e1.type.nextOf(), e.to.nextOf()))
+ {
+ e.error("array cast from `%s` to `%s` is not supported at compile time", se.e1.type.toChars(), e.to.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ emplaceExp!(SliceExp)(pue, e1.loc, se.e1, se.lwr, se.upr);
+ result = pue.exp();
+ result.type = e.to;
+ return;
+ }
+ // Disallow array type painting, except for conversions between built-in
+ // types of identical size.
+ if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf()))
+ {
+ e.error("array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (e.to.ty == Tsarray)
+ e1 = resolveSlice(e1);
+ if (e.to.toBasetype().ty == Tbool && e1.type.ty == Tpointer)
+ {
+ emplaceExp!(IntegerExp)(pue, e.loc, e1.op != TOK.null_, e.to);
+ result = pue.exp();
+ return;
+ }
+ result = ctfeCast(pue, e.loc, e.type, e.to, e1);
+ }
+
+ override void visit(AssertExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s AssertExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ Expression e1 = interpret(pue, e.e1, istate);
+ if (exceptionOrCant(e1))
+ return;
+ if (isTrueBool(e1))
+ {
+ }
+ else if (e1.isBool(false))
+ {
+ if (e.msg)
+ {
+ UnionExp ue = void;
+ result = interpret(&ue, e.msg, istate);
+ if (exceptionOrCant(result))
+ return;
+ e.error("`%s`", result.toChars());
+ }
+ else
+ e.error("`%s` failed", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ else
+ {
+ e.error("`%s` is not a compile time boolean expression", e1.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ result = e1;
+ return;
+ }
+
+ override void visit(PtrExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s PtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ // Check for int<->float and long<->double casts.
+ if (auto soe1 = e.e1.isSymOffExp())
+ if (soe1.offset == 0 && soe1.var.isVarDeclaration() && isFloatIntPaint(e.type, soe1.var.type))
+ {
+ // *(cast(int*)&v), where v is a float variable
+ result = paintFloatInt(pue, getVarExp(e.loc, istate, soe1.var, CTFEGoal.RValue), e.type);
+ return;
+ }
+
+ if (auto ce1 = e.e1.isCastExp())
+ if (auto ae11 = ce1.e1.isAddrExp())
+ {
+ // *(cast(int*)&x), where x is a float expression
+ Expression x = ae11.e1;
+ if (isFloatIntPaint(e.type, x.type))
+ {
+ result = paintFloatInt(pue, interpretRegion(x, istate), e.type);
+ return;
+ }
+ }
+
+ // Constant fold *(&structliteral + offset)
+ if (auto ae = e.e1.isAddExp())
+ {
+ if (ae.e1.op == TOK.address && ae.e2.op == TOK.int64)
+ {
+ AddrExp ade = cast(AddrExp)ae.e1;
+ Expression ex = interpretRegion(ade.e1, istate);
+ if (exceptionOrCant(ex))
+ return;
+ if (auto se = ex.isStructLiteralExp())
+ {
+ dinteger_t offset = ae.e2.toInteger();
+ result = se.getField(e.type, cast(uint)offset);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ // It's possible we have an array bounds error. We need to make sure it
+ // errors with this line number, not the one where the pointer was set.
+ result = interpretRegion(e.e1, istate);
+ if (exceptionOrCant(result))
+ return;
+
+ if (result.op == TOK.function_)
+ return;
+ if (auto soe = result.isSymOffExp())
+ {
+ if (soe.offset == 0 && soe.var.isFuncDeclaration())
+ return;
+ e.error("cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ if (result.isStringExp())
+ return;
+
+ if (result.op != TOK.address)
+ {
+ if (result.op == TOK.null_)
+ e.error("dereference of null pointer `%s`", e.e1.toChars());
+ else
+ e.error("dereference of invalid pointer `%s`", result.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ // *(&x) ==> x
+ result = (cast(AddrExp)result).e1;
+
+ if (result.op == TOK.slice && e.type.toBasetype().ty == Tsarray)
+ {
+ /* aggr[lwr..upr]
+ * upr may exceed the upper boundary of aggr, but the check is deferred
+ * until those out-of-bounds elements will be touched.
+ */
+ return;
+ }
+ result = interpret(pue, result, istate, goal);
+ if (exceptionOrCant(result))
+ return;
+
+ debug (LOG)
+ {
+ if (CTFEExp.isCantExp(result))
+ printf("PtrExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
+ }
+ }
+
+ override void visit(DotVarExp e)
+ {
+ void notImplementedYet()
+ {
+ e.error("`%s.%s` is not yet implemented at compile time", e.e1.toChars(), e.var.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ debug (LOG)
+ {
+ printf("%s DotVarExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
+ }
+ Expression ex = interpretRegion(e.e1, istate);
+ if (exceptionOrCant(ex))
+ return;
+
+ if (FuncDeclaration f = e.var.isFuncDeclaration())
+ {
+ if (ex == e.e1)
+ result = e; // optimize: reuse this CTFE reference
+ else
+ {
+ emplaceExp!(DotVarExp)(pue, e.loc, ex, f, false);
+ result = pue.exp();
+ result.type = e.type;
+ }
+ return;
+ }
+
+ VarDeclaration v = e.var.isVarDeclaration();
+ if (!v)
+ {
+ e.error("CTFE internal error: `%s`", e.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ if (ex.op == TOK.null_)
+ {
+ if (ex.type.toBasetype().ty == Tclass)
+ e.error("class `%s` is `null` and cannot be dereferenced", e.e1.toChars());
+ else
+ e.error("CTFE internal error: null this `%s`", e.e1.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ StructLiteralExp se;
+ int i;
+
+ if (ex.op != TOK.structLiteral && ex.op != TOK.classReference && ex.op != TOK.typeid_)
+ {
+ return notImplementedYet();
+ }
+
+ // We can't use getField, because it makes a copy
+ if (ex.op == TOK.classReference)
+ {
+ se = (cast(ClassReferenceExp)ex).value;
+ i = (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
+ }
+ else if (ex.op == TOK.typeid_)
+ {
+ if (v.ident == Identifier.idPool("name"))
+ {
+ if (auto t = isType(ex.isTypeidExp().obj))
+ {
+ auto sym = t.toDsymbol(null);
+ if (auto ident = (sym ? sym.ident : null))
+ {
+ result = new StringExp(e.loc, ident.toString());
+ result.expressionSemantic(null);
+ return ;
+ }
+ }
+ }
+ return notImplementedYet();
+ }
+ else
+ {
+ se = cast(StructLiteralExp)ex;
+ i = findFieldIndexByName(se.sd, v);
+ }
+ if (i == -1)
+ {
+ e.error("couldn't find field `%s` of type `%s` in `%s`", v.toChars(), e.type.toChars(), se.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=19897
+ // https://issues.dlang.org/show_bug.cgi?id=20710
+ // Zero-elements fields don't have an initializer. See: scrubArray function
+ if ((*se.elements)[i] is null)
+ (*se.elements)[i] = voidInitLiteral(e.type, v).copy();
+
+ if (goal == CTFEGoal.LValue)
+ {
+ // just return the (simplified) dotvar expression as a CTFE reference
+ if (e.e1 == ex)
+ result = e;
+ else
+ {
+ emplaceExp!(DotVarExp)(pue, e.loc, ex, v);
+ result = pue.exp();
+ result.type = e.type;
+ }
+ return;
+ }
+
+ result = (*se.elements)[i];
+ if (!result)
+ {
+ e.error("Internal Compiler Error: null field `%s`", v.toChars());
+ result = CTFEExp.cantexp;
+ return;
+ }
+ if (auto vie = result.isVoidInitExp())
+ {
+ const s = vie.var.toChars();
+ if (v.overlapped)
+ {
+ e.error("reinterpretation through overlapped field `%s` is not allowed in CTFE", s);
+ result = CTFEExp.cantexp;
+ return;
+ }
+ e.error("cannot read uninitialized variable `%s` in CTFE", s);
+ result = CTFEExp.cantexp;
+ return;
+ }
+
+ if (v.type.ty != result.type.ty && v.type.ty == Tsarray)
+ {
+ // Block assignment from inside struct literals
+ auto tsa = cast(TypeSArray)v.type;
+ auto len = cast(size_t)tsa.dim.toInteger();
+ UnionExp ue = void;
+ result = createBlockDuplicatedArrayLiteral(&ue, ex.loc, v.type, ex, len);
+ if (result == ue.exp())
+ result = ue.copy();
+ (*se.elements)[i] = result;
+ }
+ debug (LOG)
+ {
+ if (CTFEExp.isCantExp(result))
+ printf("DotVarExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
+ }
+ }
+
+ override void visit(RemoveExp e)
+ {
+ debug (LOG)
+ {
+ printf("%s RemoveExp::interpret() %s\n", e.loc.toChars(), e.toChars());
+ }
+ Expression agg = interpret(e.e1, istate);
+ if (exceptionOrCant(agg))
+ return;
+ Expression index = interpret(e.e2, istate);
+ if (exceptionOrCant(index))
+ return;
+ if (agg.op == TOK.null_)
+ {
+ result = CTFEExp.voidexp;
+ return;
+ }
+
+ AssocArrayLiteralExp aae = agg.isAssocArrayLiteralExp();
+ Expressions* keysx = aae.keys;
+ Expressions* valuesx = aae.values;
+ size_t removed = 0;
+ foreach (j, evalue; *valuesx)
+ {
+ Expression ekey = (*keysx)[j];
+ int eq = ctfeEqual(e.loc, TOK.equal, ekey, index);
+ if (eq)
+ ++removed;
+ else if (removed != 0)
+ {
+ (*keysx)[j - removed] = ekey;
+ (*valuesx)[j - removed] = evalue;
+ }
+ }
+ valuesx.dim = valuesx.dim - removed;
+ keysx.dim = keysx.dim - removed;
+ result = IntegerExp.createBool(removed != 0);
+ }
+
+ override void visit(ClassReferenceExp e)
+ {
+ //printf("ClassReferenceExp::interpret() %s\n", e.value.toChars());
+ result = e;
+ }
+
+ override void visit(VoidInitExp e)
+ {
+ e.error("CTFE internal error: trying to read uninitialized variable");
+ assert(0);
+ }
+
+ override void visit(ThrownExceptionExp e)
+ {
+ assert(0); // This should never be interpreted
+ }
+}
+
+/********************************************
+ * Interpret the expression.
+ * Params:
+ * pue = non-null pointer to temporary storage that can be used to store the return value
+ * e = Expression to interpret
+ * istate = context
+ * goal = what the result will be used for
+ * Returns:
+ * resulting expression
+ */
+
+Expression interpret(UnionExp* pue, Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
+{
+ if (!e)
+ return null;
+ scope Interpreter v = new Interpreter(pue, istate, goal);
+ e.accept(v);
+ Expression ex = v.result;
+ assert(goal == CTFEGoal.Nothing || ex !is null);
+ return ex;
+}
+
+///
+Expression interpret(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
+{
+ UnionExp ue = void;
+ auto result = interpret(&ue, e, istate, goal);
+ if (result == ue.exp())
+ result = ue.copy();
+ return result;
+}
+
+/*****************************
+ * Same as interpret(), but return result allocated in Region.
+ * Params:
+ * e = Expression to interpret
+ * istate = context
+ * goal = what the result will be used for
+ * Returns:
+ * resulting expression
+ */
+Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
+{
+ UnionExp ue = void;
+ auto result = interpret(&ue, e, istate, goal);
+ auto uexp = ue.exp();
+ if (result != uexp)
+ return result;
+ if (mem.isGCEnabled)
+ return ue.copy();
+
+ // mimicking UnionExp.copy, but with region allocation
+ switch (uexp.op)
+ {
+ case TOK.cantExpression: return CTFEExp.cantexp;
+ case TOK.voidExpression: return CTFEExp.voidexp;
+ case TOK.break_: return CTFEExp.breakexp;
+ case TOK.continue_: return CTFEExp.continueexp;
+ case TOK.goto_: return CTFEExp.gotoexp;
+ default: break;
+ }
+ auto p = ctfeGlobals.region.malloc(uexp.size);
+ return cast(Expression)memcpy(p, cast(void*)uexp, uexp.size);
+}
+
+/***********************************
+ * Interpret the statement.
+ * Params:
+ * pue = non-null pointer to temporary storage that can be used to store the return value
+ * s = Statement to interpret
+ * istate = context
+ * Returns:
+ * NULL continue to next statement
+ * TOK.cantExpression cannot interpret statement at compile time
+ * !NULL expression from return statement, or thrown exception
+ */
+Expression interpret(UnionExp* pue, Statement s, InterState* istate)
+{
+ if (!s)
+ return null;
+ scope Interpreter v = new Interpreter(pue, istate, CTFEGoal.Nothing);
+ s.accept(v);
+ return v.result;
+}
+
+///
+Expression interpret(Statement s, InterState* istate)
+{
+ UnionExp ue = void;
+ auto result = interpret(&ue, s, istate);
+ if (result == ue.exp())
+ result = ue.copy();
+ return result;
+}
+
+/**
+ * All results destined for use outside of CTFE need to have their CTFE-specific
+ * features removed.
+ * In particular,
+ * 1. all slices must be resolved.
+ * 2. all .ownedByCtfe set to OwnedBy.code
+ */
+private Expression scrubReturnValue(const ref Loc loc, Expression e)
+{
+ /* Returns: true if e is void,
+ * or is an array literal or struct literal of void elements.
+ */
+ static bool isVoid(const Expression e, bool checkArrayType = false) pure
+ {
+ if (e.op == TOK.void_)
+ return true;
+
+ static bool isEntirelyVoid(const Expressions* elems)
+ {
+ foreach (e; *elems)
+ {
+ // It can be NULL for performance reasons,
+ // see StructLiteralExp::interpret().
+ if (e && !isVoid(e))
+ return false;
+ }
+ return true;
+ }
+
+ if (auto sle = e.isStructLiteralExp())
+ return isEntirelyVoid(sle.elements);
+
+ if (checkArrayType && e.type.ty != Tsarray)
+ return false;
+
+ if (auto ale = e.isArrayLiteralExp())
+ return isEntirelyVoid(ale.elements);
+
+ return false;
+ }
+
+
+ /* Scrub all elements of elems[].
+ * Returns: null for success, error Expression for failure
+ */
+ Expression scrubArray(Expressions* elems, bool structlit = false)
+ {
+ foreach (ref e; *elems)
+ {
+ // It can be NULL for performance reasons,
+ // see StructLiteralExp::interpret().
+ if (!e)
+ continue;
+
+ // A struct .init may contain void members.
+ // Static array members are a weird special case https://issues.dlang.org/show_bug.cgi?id=10994
+ if (structlit && isVoid(e, true))
+ {
+ e = null;
+ }
+ else
+ {
+ e = scrubReturnValue(loc, e);
+ if (CTFEExp.isCantExp(e) || e.op == TOK.error)
+ return e;
+ }
+ }
+ return null;
+ }
+
+ Expression scrubSE(StructLiteralExp sle)
+ {
+ sle.ownedByCtfe = OwnedBy.code;
+ if (!(sle.stageflags & stageScrub))
+ {
+ const old = sle.stageflags;
+ sle.stageflags |= stageScrub; // prevent infinite recursion
+ if (auto ex = scrubArray(sle.elements, true))
+ return ex;
+ sle.stageflags = old;
+ }
+ return null;
+ }
+
+ if (e.op == TOK.classReference)
+ {
+ StructLiteralExp sle = (cast(ClassReferenceExp)e).value;
+ if (auto ex = scrubSE(sle))
+ return ex;
+ }
+ else if (auto vie = e.isVoidInitExp())
+ {
+ error(loc, "uninitialized variable `%s` cannot be returned from CTFE", vie.var.toChars());
+ return ErrorExp.get();
+ }
+
+ e = resolveSlice(e);
+
+ if (auto sle = e.isStructLiteralExp())
+ {
+ if (auto ex = scrubSE(sle))
+ return ex;
+ }
+ else if (auto se = e.isStringExp())
+ {
+ se.ownedByCtfe = OwnedBy.code;
+ }
+ else if (auto ale = e.isArrayLiteralExp())
+ {
+ ale.ownedByCtfe = OwnedBy.code;
+ if (auto ex = scrubArray(ale.elements))
+ return ex;
+ }
+ else if (auto aae = e.isAssocArrayLiteralExp())
+ {
+ aae.ownedByCtfe = OwnedBy.code;
+ if (auto ex = scrubArray(aae.keys))
+ return ex;
+ if (auto ex = scrubArray(aae.values))
+ return ex;
+ aae.type = toBuiltinAAType(aae.type);
+ }
+ else if (auto ve = e.isVectorExp())
+ {
+ ve.ownedByCtfe = OwnedBy.code;
+ if (auto ale = ve.e1.isArrayLiteralExp())
+ {
+ ale.ownedByCtfe = OwnedBy.code;
+ if (auto ex = scrubArray(ale.elements))
+ return ex;
+ }
+ }
+ return e;
+}
+
+/**************************************
+ * Transitively set all .ownedByCtfe to OwnedBy.cache
+ */
+private Expression scrubCacheValue(Expression e)
+{
+ if (!e)
+ return e;
+
+ Expression scrubArrayCache(Expressions* elems)
+ {
+ foreach (ref e; *elems)
+ e = scrubCacheValue(e);
+ return null;
+ }
+
+ Expression scrubSE(StructLiteralExp sle)
+ {
+ sle.ownedByCtfe = OwnedBy.cache;
+ if (!(sle.stageflags & stageScrub))
+ {
+ const old = sle.stageflags;
+ sle.stageflags |= stageScrub; // prevent infinite recursion
+ if (auto ex = scrubArrayCache(sle.elements))
+ return ex;
+ sle.stageflags = old;
+ }
+ return null;
+ }
+
+ if (e.op == TOK.classReference)
+ {
+ if (auto ex = scrubSE((cast(ClassReferenceExp)e).value))
+ return ex;
+ }
+ else if (auto sle = e.isStructLiteralExp())
+ {
+ if (auto ex = scrubSE(sle))
+ return ex;
+ }
+ else if (auto se = e.isStringExp())
+ {
+ se.ownedByCtfe = OwnedBy.cache;
+ }
+ else if (auto ale = e.isArrayLiteralExp())
+ {
+ ale.ownedByCtfe = OwnedBy.cache;
+ if (Expression ex = scrubArrayCache(ale.elements))
+ return ex;
+ }
+ else if (auto aae = e.isAssocArrayLiteralExp())
+ {
+ aae.ownedByCtfe = OwnedBy.cache;
+ if (auto ex = scrubArrayCache(aae.keys))
+ return ex;
+ if (auto ex = scrubArrayCache(aae.values))
+ return ex;
+ }
+ else if (auto ve = e.isVectorExp())
+ {
+ ve.ownedByCtfe = OwnedBy.cache;
+ if (auto ale = ve.e1.isArrayLiteralExp())
+ {
+ ale.ownedByCtfe = OwnedBy.cache;
+ if (auto ex = scrubArrayCache(ale.elements))
+ return ex;
+ }
+ }
+ return e;
+}
+
+/********************************************
+ * Transitively replace all Expressions allocated in ctfeGlobals.region
+ * with Mem owned copies.
+ * Params:
+ * e = possible ctfeGlobals.region owned expression
+ * Returns:
+ * Mem owned expression
+ */
+private Expression copyRegionExp(Expression e)
+{
+ if (!e)
+ return e;
+
+ static void copyArray(Expressions* elems)
+ {
+ foreach (ref e; *elems)
+ {
+ auto ex = e;
+ e = null;
+ e = copyRegionExp(ex);
+ }
+ }
+
+ static void copySE(StructLiteralExp sle)
+ {
+ if (1 || !(sle.stageflags & stageScrub))
+ {
+ const old = sle.stageflags;
+ sle.stageflags |= stageScrub; // prevent infinite recursion
+ copyArray(sle.elements);
+ sle.stageflags = old;
+ }
+ }
+
+ switch (e.op)
+ {
+ case TOK.classReference:
+ {
+ auto cre = e.isClassReferenceExp();
+ cre.value = copyRegionExp(cre.value).isStructLiteralExp();
+ break;
+ }
+
+ case TOK.structLiteral:
+ {
+ auto sle = e.isStructLiteralExp();
+
+ /* The following is to take care of updating sle.origin correctly,
+ * which may have multiple objects pointing to it.
+ */
+ if (sle.isOriginal && !ctfeGlobals.region.contains(cast(void*)sle.origin))
+ {
+ /* This means sle has already been moved out of the region,
+ * and sle.origin is the new location.
+ */
+ return sle.origin;
+ }
+ copySE(sle);
+ sle.isOriginal = sle is sle.origin;
+
+ auto slec = ctfeGlobals.region.contains(cast(void*)e)
+ ? e.copy().isStructLiteralExp() // move sle out of region to slec
+ : sle;
+
+ if (ctfeGlobals.region.contains(cast(void*)sle.origin))
+ {
+ auto sleo = sle.origin == sle ? slec : sle.origin.copy().isStructLiteralExp();
+ sle.origin = sleo;
+ slec.origin = sleo;
+ }
+ return slec;
+ }
+
+ case TOK.arrayLiteral:
+ {
+ auto ale = e.isArrayLiteralExp();
+ ale.basis = copyRegionExp(ale.basis);
+ copyArray(ale.elements);
+ break;
+ }
+
+ case TOK.assocArrayLiteral:
+ copyArray(e.isAssocArrayLiteralExp().keys);
+ copyArray(e.isAssocArrayLiteralExp().values);
+ break;
+
+ case TOK.slice:
+ {
+ auto se = e.isSliceExp();
+ se.e1 = copyRegionExp(se.e1);
+ se.upr = copyRegionExp(se.upr);
+ se.lwr = copyRegionExp(se.lwr);
+ break;
+ }
+
+ case TOK.tuple:
+ {
+ auto te = e.isTupleExp();
+ te.e0 = copyRegionExp(te.e0);
+ copyArray(te.exps);
+ break;
+ }
+
+ case TOK.address:
+ case TOK.delegate_:
+ case TOK.vector:
+ case TOK.dotVariable:
+ {
+ UnaExp ue = cast(UnaExp)e;
+ ue.e1 = copyRegionExp(ue.e1);
+ break;
+ }
+
+ case TOK.index:
+ {
+ BinExp be = cast(BinExp)e;
+ be.e1 = copyRegionExp(be.e1);
+ be.e2 = copyRegionExp(be.e2);
+ break;
+ }
+
+ case TOK.this_:
+ case TOK.super_:
+ case TOK.variable:
+ case TOK.type:
+ case TOK.function_:
+ case TOK.typeid_:
+ case TOK.string_:
+ case TOK.int64:
+ case TOK.error:
+ case TOK.float64:
+ case TOK.complex80:
+ case TOK.null_:
+ case TOK.void_:
+ case TOK.symbolOffset:
+ case TOK.char_:
+ break;
+
+ case TOK.cantExpression:
+ case TOK.voidExpression:
+ case TOK.showCtfeContext:
+ return e;
+
+ default:
+ printf("e: %s, %s\n", Token.toChars(e.op), e.toChars());
+ assert(0);
+ }
+
+ if (ctfeGlobals.region.contains(cast(void*)e))
+ {
+ return e.copy();
+ }
+ return e;
+}
+
+/******************************* Special Functions ***************************/
+
+private Expression interpret_length(UnionExp* pue, InterState* istate, Expression earg)
+{
+ //printf("interpret_length()\n");
+ earg = interpret(pue, earg, istate);
+ if (exceptionOrCantInterpret(earg))
+ return earg;
+ dinteger_t len = 0;
+ if (auto aae = earg.isAssocArrayLiteralExp())
+ len = aae.keys.dim;
+ else
+ assert(earg.op == TOK.null_);
+ emplaceExp!(IntegerExp)(pue, earg.loc, len, Type.tsize_t);
+ return pue.exp();
+}
+
+private Expression interpret_keys(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
+{
+ debug (LOG)
+ {
+ printf("interpret_keys()\n");
+ }
+ earg = interpret(pue, earg, istate);
+ if (exceptionOrCantInterpret(earg))
+ return earg;
+ if (earg.op == TOK.null_)
+ {
+ emplaceExp!(NullExp)(pue, earg.loc, earg.type);
+ return pue.exp();
+ }
+ if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
+ return null;
+ AssocArrayLiteralExp aae = earg.isAssocArrayLiteralExp();
+ auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.keys);
+ ae.ownedByCtfe = aae.ownedByCtfe;
+ *pue = copyLiteral(ae);
+ return pue.exp();
+}
+
+private Expression interpret_values(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
+{
+ debug (LOG)
+ {
+ printf("interpret_values()\n");
+ }
+ earg = interpret(pue, earg, istate);
+ if (exceptionOrCantInterpret(earg))
+ return earg;
+ if (earg.op == TOK.null_)
+ {
+ emplaceExp!(NullExp)(pue, earg.loc, earg.type);
+ return pue.exp();
+ }
+ if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
+ return null;
+ auto aae = earg.isAssocArrayLiteralExp();
+ auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.values);
+ ae.ownedByCtfe = aae.ownedByCtfe;
+ //printf("result is %s\n", e.toChars());
+ *pue = copyLiteral(ae);
+ return pue.exp();
+}
+
+private Expression interpret_dup(UnionExp* pue, InterState* istate, Expression earg)
+{
+ debug (LOG)
+ {
+ printf("interpret_dup()\n");
+ }
+ earg = interpret(pue, earg, istate);
+ if (exceptionOrCantInterpret(earg))
+ return earg;
+ if (earg.op == TOK.null_)
+ {
+ emplaceExp!(NullExp)(pue, earg.loc, earg.type);
+ return pue.exp();
+ }
+ if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
+ return null;
+ auto aae = copyLiteral(earg).copy().isAssocArrayLiteralExp();
+ for (size_t i = 0; i < aae.keys.dim; i++)
+ {
+ if (Expression e = evaluatePostblit(istate, (*aae.keys)[i]))
+ return e;
+ if (Expression e = evaluatePostblit(istate, (*aae.values)[i]))
+ return e;
+ }
+ aae.type = earg.type.mutableOf(); // repaint type from const(int[int]) to const(int)[int]
+ //printf("result is %s\n", aae.toChars());
+ return aae;
+}
+
+// signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
+private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expression aa, Expression deleg)
+{
+ aa = interpret(aa, istate);
+ if (exceptionOrCantInterpret(aa))
+ return aa;
+ if (aa.op != TOK.assocArrayLiteral)
+ {
+ emplaceExp!(IntegerExp)(pue, deleg.loc, 0, Type.tsize_t);
+ return pue.exp();
+ }
+
+ FuncDeclaration fd = null;
+ Expression pthis = null;
+ if (auto de = deleg.isDelegateExp())
+ {
+ fd = de.func;
+ pthis = de.e1;
+ }
+ else if (auto fe = deleg.isFuncExp())
+ fd = fe.fd;
+
+ assert(fd && fd.fbody);
+ assert(fd.parameters);
+ size_t numParams = fd.parameters.dim;
+ assert(numParams == 1 || numParams == 2);
+
+ Parameter fparam = fd.type.isTypeFunction().parameterList[numParams - 1];
+ const wantRefValue = fparam.isReference();
+
+ Expressions args = Expressions(numParams);
+
+ AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)aa;
+ if (!ae.keys || ae.keys.dim == 0)
+ return ctfeEmplaceExp!IntegerExp(deleg.loc, 0, Type.tsize_t);
+ Expression eresult;
+
+ for (size_t i = 0; i < ae.keys.dim; ++i)
+ {
+ Expression ekey = (*ae.keys)[i];
+ Expression evalue = (*ae.values)[i];
+ if (wantRefValue)
+ {
+ Type t = evalue.type;
+ evalue = ctfeEmplaceExp!IndexExp(deleg.loc, ae, ekey);
+ evalue.type = t;
+ }
+ args[numParams - 1] = evalue;
+ if (numParams == 2)
+ args[0] = ekey;
+
+ UnionExp ue = void;
+ eresult = interpretFunction(&ue, fd, istate, &args, pthis);
+ if (eresult == ue.exp())
+ eresult = ue.copy();
+ if (exceptionOrCantInterpret(eresult))
+ return eresult;
+
+ if (eresult.isIntegerExp().getInteger() != 0)
+ return eresult;
+ }
+ return eresult;
+}
+
+/* Decoding UTF strings for foreach loops. Duplicates the functionality of
+ * the twelve _aApplyXXn functions in aApply.d in the runtime.
+ */
+private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression str, Expression deleg, bool rvs)
+{
+ debug (LOG)
+ {
+ printf("foreachApplyUtf(%s, %s)\n", str.toChars(), deleg.toChars());
+ }
+ FuncDeclaration fd = null;
+ Expression pthis = null;
+ if (auto de = deleg.isDelegateExp())
+ {
+ fd = de.func;
+ pthis = de.e1;
+ }
+ else if (auto fe = deleg.isFuncExp())
+ fd = fe.fd;
+
+ assert(fd && fd.fbody);
+ assert(fd.parameters);
+ size_t numParams = fd.parameters.dim;
+ assert(numParams == 1 || numParams == 2);
+ Type charType = (*fd.parameters)[numParams - 1].type;
+ Type indexType = numParams == 2 ? (*fd.parameters)[0].type : Type.tsize_t;
+ size_t len = cast(size_t)resolveArrayLength(str);
+ if (len == 0)
+ {
+ emplaceExp!(IntegerExp)(pue, deleg.loc, 0, indexType);
+ return pue.exp();
+ }
+
+ UnionExp strTmp = void;
+ str = resolveSlice(str, &strTmp);
+
+ auto se = str.isStringExp();
+ auto ale = str.isArrayLiteralExp();
+ if (!se && !ale)
+ {
+ str.error("CTFE internal error: cannot foreach `%s`", str.toChars());
+ return CTFEExp.cantexp;
+ }
+ Expressions args = Expressions(numParams);
+
+ Expression eresult = null; // ded-store to prevent spurious warning
+
+ // Buffers for encoding; also used for decoding array literals
+ char[4] utf8buf = void;
+ wchar[2] utf16buf = void;
+
+ size_t start = rvs ? len : 0;
+ size_t end = rvs ? 0 : len;
+ for (size_t indx = start; indx != end;)
+ {
+ // Step 1: Decode the next dchar from the string.
+
+ string errmsg = null; // Used for reporting decoding errors
+ dchar rawvalue; // Holds the decoded dchar
+ size_t currentIndex = indx; // The index of the decoded character
+
+ if (ale)
+ {
+ // If it is an array literal, copy the code points into the buffer
+ size_t buflen = 1; // #code points in the buffer
+ size_t n = 1; // #code points in this char
+ size_t sz = cast(size_t)ale.type.nextOf().size();
+
+ switch (sz)
+ {
+ case 1:
+ if (rvs)
+ {
+ // find the start of the string
+ --indx;
+ buflen = 1;
+ while (indx > 0 && buflen < 4)
+ {
+ Expression r = (*ale.elements)[indx];
+ char x = cast(char)r.isIntegerExp().getInteger();
+ if ((x & 0xC0) != 0x80)
+ break;
+ --indx;
+ ++buflen;
+ }
+ }
+ else
+ buflen = (indx + 4 > len) ? len - indx : 4;
+ for (size_t i = 0; i < buflen; ++i)
+ {
+ Expression r = (*ale.elements)[indx + i];
+ utf8buf[i] = cast(char)r.isIntegerExp().getInteger();
+ }
+ n = 0;
+ errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue);
+ break;
+
+ case 2:
+ if (rvs)
+ {
+ // find the start of the string
+ --indx;
+ buflen = 1;
+ Expression r = (*ale.elements)[indx];
+ ushort x = cast(ushort)r.isIntegerExp().getInteger();
+ if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
+ {
+ --indx;
+ ++buflen;
+ }
+ }
+ else
+ buflen = (indx + 2 > len) ? len - indx : 2;
+ for (size_t i = 0; i < buflen; ++i)
+ {
+ Expression r = (*ale.elements)[indx + i];
+ utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger();
+ }
+ n = 0;
+ errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue);
+ break;
+
+ case 4:
+ {
+ if (rvs)
+ --indx;
+ Expression r = (*ale.elements)[indx];
+ rawvalue = cast(dchar)r.isIntegerExp().getInteger();
+ n = 1;
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+ if (!rvs)
+ indx += n;
+ }
+ else
+ {
+ // String literals
+ size_t saveindx; // used for reverse iteration
+
+ switch (se.sz)
+ {
+ case 1:
+ {
+ if (rvs)
+ {
+ // find the start of the string
+ --indx;
+ while (indx > 0 && ((se.getCodeUnit(indx) & 0xC0) == 0x80))
+ --indx;
+ saveindx = indx;
+ }
+ auto slice = se.peekString();
+ errmsg = utf_decodeChar(slice, indx, rawvalue);
+ if (rvs)
+ indx = saveindx;
+ break;
+ }
+
+ case 2:
+ if (rvs)
+ {
+ // find the start
+ --indx;
+ auto wc = se.getCodeUnit(indx);
+ if (wc >= 0xDC00 && wc <= 0xDFFF)
+ --indx;
+ saveindx = indx;
+ }
+ const slice = se.peekWstring();
+ errmsg = utf_decodeWchar(slice, indx, rawvalue);
+ if (rvs)
+ indx = saveindx;
+ break;
+
+ case 4:
+ if (rvs)
+ --indx;
+ rawvalue = se.getCodeUnit(indx);
+ if (!rvs)
+ ++indx;
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ if (errmsg)
+ {
+ deleg.error("`%.*s`", cast(int)errmsg.length, errmsg.ptr);
+ return CTFEExp.cantexp;
+ }
+
+ // Step 2: encode the dchar in the target encoding
+
+ int charlen = 1; // How many codepoints are involved?
+ switch (charType.size())
+ {
+ case 1:
+ charlen = utf_codeLengthChar(rawvalue);
+ utf_encodeChar(&utf8buf[0], rawvalue);
+ break;
+ case 2:
+ charlen = utf_codeLengthWchar(rawvalue);
+ utf_encodeWchar(&utf16buf[0], rawvalue);
+ break;
+ case 4:
+ break;
+ default:
+ assert(0);
+ }
+ if (rvs)
+ currentIndex = indx;
+
+ // Step 3: call the delegate once for each code point
+
+ // The index only needs to be set once
+ if (numParams == 2)
+ args[0] = ctfeEmplaceExp!IntegerExp(deleg.loc, currentIndex, indexType);
+
+ Expression val = null;
+
+ foreach (k; 0 .. charlen)
+ {
+ dchar codepoint;
+ switch (charType.size())
+ {
+ case 1:
+ codepoint = utf8buf[k];
+ break;
+ case 2:
+ codepoint = utf16buf[k];
+ break;
+ case 4:
+ codepoint = rawvalue;
+ break;
+ default:
+ assert(0);
+ }
+ val = ctfeEmplaceExp!IntegerExp(str.loc, codepoint, charType);
+
+ args[numParams - 1] = val;
+
+ UnionExp ue = void;
+ eresult = interpretFunction(&ue, fd, istate, &args, pthis);
+ if (eresult == ue.exp())
+ eresult = ue.copy();
+ if (exceptionOrCantInterpret(eresult))
+ return eresult;
+ if (eresult.isIntegerExp().getInteger() != 0)
+ return eresult;
+ }
+ }
+ return eresult;
+}
+
+/* If this is a built-in function, return the interpreted result,
+ * Otherwise, return NULL.
+ */
+private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const ref Loc loc, FuncDeclaration fd, Expressions* arguments, Expression pthis)
+{
+ Expression e = null;
+ size_t nargs = arguments ? arguments.dim : 0;
+ if (!pthis)
+ {
+ if (isBuiltin(fd) != BUILTIN.unimp)
+ {
+ Expressions args = Expressions(nargs);
+ foreach (i, ref arg; args)
+ {
+ Expression earg = (*arguments)[i];
+ earg = interpret(earg, istate);
+ if (exceptionOrCantInterpret(earg))
+ return earg;
+ arg = earg;
+ }
+ e = eval_builtin(loc, fd, &args);
+ if (!e)
+ {
+ error(loc, "cannot evaluate unimplemented builtin `%s` at compile time", fd.toChars());
+ e = CTFEExp.cantexp;
+ }
+ }
+ }
+ if (!pthis)
+ {
+ if (nargs == 1 || nargs == 3)
+ {
+ Expression firstarg = (*arguments)[0];
+ if (auto firstAAtype = firstarg.type.toBasetype().isTypeAArray())
+ {
+ const id = fd.ident;
+ if (nargs == 1)
+ {
+ if (id == Id.aaLen)
+ return interpret_length(pue, istate, firstarg);
+
+ if (fd.toParent2().ident == Id.object)
+ {
+ if (id == Id.keys)
+ return interpret_keys(pue, istate, firstarg, firstAAtype.index.arrayOf());
+ if (id == Id.values)
+ return interpret_values(pue, istate, firstarg, firstAAtype.nextOf().arrayOf());
+ if (id == Id.rehash)
+ return interpret(pue, firstarg, istate);
+ if (id == Id.dup)
+ return interpret_dup(pue, istate, firstarg);
+ }
+ }
+ else // (nargs == 3)
+ {
+ if (id == Id._aaApply)
+ return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
+ if (id == Id._aaApply2)
+ return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
+ }
+ }
+ }
+ }
+ if (pthis && !fd.fbody && fd.isCtorDeclaration() && fd.parent && fd.parent.parent && fd.parent.parent.ident == Id.object)
+ {
+ if (pthis.op == TOK.classReference && fd.parent.ident == Id.Throwable)
+ {
+ // At present, the constructors just copy their arguments into the struct.
+ // But we might need some magic if stack tracing gets added to druntime.
+ StructLiteralExp se = (cast(ClassReferenceExp)pthis).value;
+ assert(arguments.dim <= se.elements.dim);
+ foreach (i, arg; *arguments)
+ {
+ auto elem = interpret(arg, istate);
+ if (exceptionOrCantInterpret(elem))
+ return elem;
+ (*se.elements)[i] = elem;
+ }
+ return CTFEExp.voidexp;
+ }
+ }
+ if (nargs == 1 && !pthis && (fd.ident == Id.criticalenter || fd.ident == Id.criticalexit))
+ {
+ // Support synchronized{} as a no-op
+ return CTFEExp.voidexp;
+ }
+ if (!pthis)
+ {
+ const idlen = fd.ident.toString().length;
+ const id = fd.ident.toChars();
+ if (nargs == 2 && (idlen == 10 || idlen == 11) && !strncmp(id, "_aApply", 7))
+ {
+ // Functions from aApply.d and aApplyR.d in the runtime
+ bool rvs = (idlen == 11); // true if foreach_reverse
+ char c = id[idlen - 3]; // char width: 'c', 'w', or 'd'
+ char s = id[idlen - 2]; // string width: 'c', 'w', or 'd'
+ char n = id[idlen - 1]; // numParams: 1 or 2.
+ // There are 12 combinations
+ if ((n == '1' || n == '2') &&
+ (c == 'c' || c == 'w' || c == 'd') &&
+ (s == 'c' || s == 'w' || s == 'd') &&
+ c != s)
+ {
+ Expression str = (*arguments)[0];
+ str = interpret(str, istate);
+ if (exceptionOrCantInterpret(str))
+ return str;
+ return foreachApplyUtf(pue, istate, str, (*arguments)[1], rvs);
+ }
+ }
+ }
+ return e;
+}
+
+private Expression evaluatePostblit(InterState* istate, Expression e)
+{
+ auto ts = e.type.baseElemOf().isTypeStruct();
+ if (!ts)
+ return null;
+ StructDeclaration sd = ts.sym;
+ if (!sd.postblit)
+ return null;
+
+ if (auto ale = e.isArrayLiteralExp())
+ {
+ foreach (elem; *ale.elements)
+ {
+ if (auto ex = evaluatePostblit(istate, elem))
+ return ex;
+ }
+ return null;
+ }
+ if (e.op == TOK.structLiteral)
+ {
+ // e.__postblit()
+ UnionExp ue = void;
+ e = interpretFunction(&ue, sd.postblit, istate, null, e);
+ if (e == ue.exp())
+ e = ue.copy();
+ if (exceptionOrCantInterpret(e))
+ return e;
+ return null;
+ }
+ assert(0);
+}
+
+private Expression evaluateDtor(InterState* istate, Expression e)
+{
+ auto ts = e.type.baseElemOf().isTypeStruct();
+ if (!ts)
+ return null;
+ StructDeclaration sd = ts.sym;
+ if (!sd.dtor)
+ return null;
+
+ UnionExp ue = void;
+ if (auto ale = e.isArrayLiteralExp())
+ {
+ foreach_reverse (elem; *ale.elements)
+ e = evaluateDtor(istate, elem);
+ }
+ else if (e.op == TOK.structLiteral)
+ {
+ // e.__dtor()
+ e = interpretFunction(&ue, sd.dtor, istate, null, e);
+ }
+ else
+ assert(0);
+ if (exceptionOrCantInterpret(e))
+ {
+ if (e == ue.exp())
+ e = ue.copy();
+ return e;
+ }
+ return null;
+}
+
+/*************************** CTFE Sanity Checks ***************************/
+/* Setter functions for CTFE variable values.
+ * These functions exist to check for compiler CTFE bugs.
+ */
+private bool hasValue(VarDeclaration vd)
+{
+ return vd.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone &&
+ getValue(vd) !is null;
+}
+
+// Don't check for validity
+private void setValueWithoutChecking(VarDeclaration vd, Expression newval)
+{
+ ctfeGlobals.stack.setValue(vd, newval);
+}
+
+private void setValue(VarDeclaration vd, Expression newval)
+{
+ //printf("setValue() vd: %s newval: %s\n", vd.toChars(), newval.toChars());
+ version (none)
+ {
+ if (!((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval)))
+ {
+ printf("[%s] vd = %s %s, newval = %s\n", vd.loc.toChars(), vd.type.toChars(), vd.toChars(), newval.toChars());
+ }
+ }
+ assert((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval));
+ ctfeGlobals.stack.setValue(vd, newval);
+}
+
+/**
+ * Removes `_d_HookTraceImpl` if found from `ce` and `fd`.
+ * This is needed for the CTFE interception code to be able to find hooks that are called though the hook's `*Trace`
+ * wrapper.
+ *
+ * This is done by replacing `_d_HookTraceImpl!(T, Hook, errMsg)(..., parameters)` with `Hook(parameters)`.
+ * Parameters:
+ * ce = The CallExp that possible will be be replaced
+ * fd = Fully resolve function declaration that `ce` would call
+ */
+private void removeHookTraceImpl(ref CallExp ce, ref FuncDeclaration fd)
+{
+ if (fd.ident != Id._d_HookTraceImpl)
+ return;
+
+ auto oldCE = ce;
+
+ // Get the Hook from the second template parameter
+ TemplateInstance templateInstance = fd.parent.isTemplateInstance;
+ RootObject hook = (*templateInstance.tiargs)[1];
+ assert(hook.dyncast() == DYNCAST.dsymbol, "Expected _d_HookTraceImpl's second template parameter to be an alias to the hook!");
+ fd = (cast(Dsymbol)hook).isFuncDeclaration;
+
+ // Remove the first three trace parameters
+ auto arguments = new Expressions();
+ arguments.reserve(ce.arguments.dim - 3);
+ arguments.pushSlice((*ce.arguments)[3 .. $]);
+
+ ce = ctfeEmplaceExp!CallExp(ce.loc, ctfeEmplaceExp!VarExp(ce.loc, fd, false), arguments);
+
+ if (global.params.verbose)
+ message("strip %s =>\n %s", oldCE.toChars(), ce.toChars());
+}
diff --git a/gcc/d/dmd/dmacro.c b/gcc/d/dmd/dmacro.c
deleted file mode 100644
index 91cbe50..0000000
--- a/gcc/d/dmd/dmacro.c
+++ /dev/null
@@ -1,458 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/macro.c
- */
-
-/* Simple macro text processor.
- */
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "errors.h"
-#include "root/rmem.h"
-#include "root/root.h"
-
-#include "macro.h"
-
-bool isIdStart(const utf8_t *p);
-bool isIdTail(const utf8_t *p);
-int utfStride(const utf8_t *p);
-
-utf8_t *memdup(const utf8_t *p, size_t len)
-{
- return (utf8_t *)memcpy(mem.xmalloc(len), p, len);
-}
-
-Macro::Macro(const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen)
-{
- next = NULL;
-
- this->name = name;
- this->namelen = namelen;
-
- this->text = text;
- this->textlen = textlen;
- inuse = 0;
-}
-
-
-Macro *Macro::search(const utf8_t *name, size_t namelen)
-{ Macro *table;
-
- //printf("Macro::search(%.*s)\n", namelen, name);
- for (table = this; table; table = table->next)
- {
- if (table->namelen == namelen &&
- memcmp(table->name, name, namelen) == 0)
- {
- //printf("\tfound %d\n", table->textlen);
- break;
- }
- }
- return table;
-}
-
-Macro *Macro::define(Macro **ptable, const utf8_t *name, size_t namelen, const utf8_t *text, size_t textlen)
-{
- //printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text);
-
- Macro *table;
-
- //assert(ptable);
- for (table = *ptable; table; table = table->next)
- {
- if (table->namelen == namelen &&
- memcmp(table->name, name, namelen) == 0)
- {
- table->text = text;
- table->textlen = textlen;
- return table;
- }
- }
- table = new Macro(name, namelen, text, textlen);
- table->next = *ptable;
- *ptable = table;
- return table;
-}
-
-/**********************************************************
- * Given buffer p[0..end], extract argument marg[0..marglen].
- * Params:
- * n 0: get entire argument
- * 1..9: get nth argument
- * -1: get 2nd through end
- */
-
-size_t extractArgN(const utf8_t *p, size_t end, const utf8_t **pmarg, size_t *pmarglen, int n)
-{
- /* Scan forward for matching right parenthesis.
- * Nest parentheses.
- * Skip over "..." and '...' strings inside HTML tags.
- * Skip over <!-- ... --> comments.
- * Skip over previous macro insertions
- * Set marglen.
- */
- unsigned parens = 1;
- unsigned char instring = 0;
- unsigned incomment = 0;
- unsigned intag = 0;
- unsigned inexp = 0;
- int argn = 0;
-
- size_t v = 0;
-
- Largstart:
- // Skip first space, if any, to find the start of the macro argument
- if (n != 1 && v < end && isspace(p[v]))
- v++;
- *pmarg = p + v;
-
- for (; v < end; v++)
- { utf8_t c = p[v];
-
- switch (c)
- {
- case ',':
- if (!inexp && !instring && !incomment && parens == 1)
- {
- argn++;
- if (argn == 1 && n == -1)
- { v++;
- goto Largstart;
- }
- if (argn == n)
- break;
- if (argn + 1 == n)
- { v++;
- goto Largstart;
- }
- }
- continue;
-
- case '(':
- if (!inexp && !instring && !incomment)
- parens++;
- continue;
-
- case ')':
- if (!inexp && !instring && !incomment && --parens == 0)
- {
- break;
- }
- continue;
-
- case '"':
- case '\'':
- if (!inexp && !incomment && intag)
- {
- if (c == instring)
- instring = 0;
- else if (!instring)
- instring = c;
- }
- continue;
-
- case '<':
- if (!inexp && !instring && !incomment)
- {
- if (v + 6 < end &&
- p[v + 1] == '!' &&
- p[v + 2] == '-' &&
- p[v + 3] == '-')
- {
- incomment = 1;
- v += 3;
- }
- else if (v + 2 < end &&
- isalpha(p[v + 1]))
- intag = 1;
- }
- continue;
-
- case '>':
- if (!inexp)
- intag = 0;
- continue;
-
- case '-':
- if (!inexp &&
- !instring &&
- incomment &&
- v + 2 < end &&
- p[v + 1] == '-' &&
- p[v + 2] == '>')
- {
- incomment = 0;
- v += 2;
- }
- continue;
-
- case 0xFF:
- if (v + 1 < end)
- {
- if (p[v + 1] == '{')
- inexp++;
- else if (p[v + 1] == '}')
- inexp--;
- }
- continue;
-
- default:
- continue;
- }
- break;
- }
- if (argn == 0 && n == -1)
- *pmarg = p + v;
- *pmarglen = p + v - *pmarg;
- //printf("extractArg%d('%.*s') = '%.*s'\n", n, end, p, *pmarglen, *pmarg);
- return v;
-}
-
-
-/*****************************************************
- * Expand macro in place in buf.
- * Only look at the text in buf from start to end.
- */
-
-void Macro::expand(OutBuffer *buf, size_t start, size_t *pend,
- const utf8_t *arg, size_t arglen)
-{
- // limit recursive expansion
- static int nest;
- if (nest > global.recursionLimit)
- {
- error(Loc(), "DDoc macro expansion limit exceeded; more than %d expansions.",
- global.recursionLimit);
- return;
- }
- nest++;
-
- size_t end = *pend;
- assert(start <= end);
- assert(end <= buf->length());
-
- /* First pass - replace $0
- */
- arg = memdup(arg, arglen);
- for (size_t u = start; u + 1 < end; )
- {
- utf8_t *p = (utf8_t *)buf->slice().ptr; // buf->slice().ptr is not loop invariant
-
- /* Look for $0, but not $$0, and replace it with arg.
- */
- if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+'))
- {
- if (u > start && p[u - 1] == '$')
- { // Don't expand $$0, but replace it with $0
- buf->remove(u - 1, 1);
- end--;
- u += 1; // now u is one past the closing '1'
- continue;
- }
-
- utf8_t c = p[u + 1];
- int n = (c == '+') ? -1 : c - '0';
-
- const utf8_t *marg;
- size_t marglen;
- if (n == 0)
- {
- marg = arg;
- marglen = arglen;
- }
- else
- extractArgN(arg, arglen, &marg, &marglen, n);
- if (marglen == 0)
- { // Just remove macro invocation
- //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
- buf->remove(u, 2);
- end -= 2;
- }
- else if (c == '+')
- {
- // Replace '$+' with 'arg'
- //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg);
- buf->remove(u, 2);
- buf->insert(u, marg, marglen);
- end += marglen - 2;
-
- // Scan replaced text for further expansion
- size_t mend = u + marglen;
- expand(buf, u, &mend, NULL, 0);
- end += mend - (u + marglen);
- u = mend;
- }
- else
- {
- // Replace '$1' with '\xFF{arg\xFF}'
- //printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], marglen, marg);
- buf->slice().ptr[u] = 0xFF;
- buf->slice().ptr[u + 1] = '{';
- buf->insert(u + 2, marg, marglen);
- buf->insert(u + 2 + marglen, (const char *)"\xFF}", 2);
- end += -2 + 2 + marglen + 2;
-
- // Scan replaced text for further expansion
- size_t mend = u + 2 + marglen;
- expand(buf, u + 2, &mend, NULL, 0);
- end += mend - (u + 2 + marglen);
- u = mend;
- }
- //printf("u = %d, end = %d\n", u, end);
- //printf("#%.*s#\n", end, &buf->slice().ptr[0]);
- continue;
- }
-
- u++;
- }
-
- /* Second pass - replace other macros
- */
- for (size_t u = start; u + 4 < end; )
- {
- utf8_t *p = (utf8_t *)buf->slice().ptr; // buf->slice().ptr is not loop invariant
-
- /* A valid start of macro expansion is $(c, where c is
- * an id start character, and not $$(c.
- */
- if (p[u] == '$' && p[u + 1] == '(' && isIdStart(p+u+2))
- {
- //printf("\tfound macro start '%c'\n", p[u + 2]);
- utf8_t *name = p + u + 2;
- size_t namelen = 0;
-
- const utf8_t *marg;
- size_t marglen;
-
- size_t v;
- /* Scan forward to find end of macro name and
- * beginning of macro argument (marg).
- */
- for (v = u + 2; v < end; v+=utfStride(p+v))
- {
-
- if (!isIdTail(p+v))
- { // We've gone past the end of the macro name.
- namelen = v - (u + 2);
- break;
- }
- }
-
- v += extractArgN(p + v, end - v, &marg, &marglen, 0);
- assert(v <= end);
-
- if (v < end)
- { // v is on the closing ')'
- if (u > start && p[u - 1] == '$')
- { // Don't expand $$(NAME), but replace it with $(NAME)
- buf->remove(u - 1, 1);
- end--;
- u = v; // now u is one past the closing ')'
- continue;
- }
-
- Macro *m = search(name, namelen);
-
- if (!m)
- {
- static const char undef[] = "DDOC_UNDEFINED_MACRO";
- m = search((const utf8_t *)undef, strlen(undef));
- if (m)
- {
- // Macro was not defined, so this is an expansion of
- // DDOC_UNDEFINED_MACRO. Prepend macro name to args.
- // marg = name[ ] ~ "," ~ marg[ ];
- if (marglen)
- {
- utf8_t *q = (utf8_t *)mem.xmalloc(namelen + 1 + marglen);
- assert(q);
- memcpy(q, name, namelen);
- q[namelen] = ',';
- memcpy(q + namelen + 1, marg, marglen);
- marg = q;
- marglen += namelen + 1;
- }
- else
- {
- marg = name;
- marglen = namelen;
- }
- }
- }
-
- if (m)
- {
- if (m->inuse && marglen == 0)
- { // Remove macro invocation
- buf->remove(u, v + 1 - u);
- end -= v + 1 - u;
- }
- else if (m->inuse &&
- ((arglen == marglen && memcmp(arg, marg, arglen) == 0) ||
- (arglen + 4 == marglen &&
- marg[0] == 0xFF &&
- marg[1] == '{' &&
- memcmp(arg, marg + 2, arglen) == 0 &&
- marg[marglen - 2] == 0xFF &&
- marg[marglen - 1] == '}'
- )
- )
- )
- {
- /* Recursive expansion:
- * marg is same as arg (with blue paint added)
- * Just leave in place.
- */
- }
- else
- {
- //printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", m->namelen, m->name, marglen, marg, m->textlen, m->text);
- marg = memdup(marg, marglen);
- // Insert replacement text
- buf->spread(v + 1, 2 + m->textlen + 2);
- buf->slice().ptr[v + 1] = 0xFF;
- buf->slice().ptr[v + 2] = '{';
- memcpy(buf->slice().ptr + v + 3, m->text, m->textlen);
- buf->slice().ptr[v + 3 + m->textlen] = 0xFF;
- buf->slice().ptr[v + 3 + m->textlen + 1] = '}';
-
- end += 2 + m->textlen + 2;
-
- // Scan replaced text for further expansion
- m->inuse++;
- size_t mend = v + 1 + 2+m->textlen+2;
- expand(buf, v + 1, &mend, marg, marglen);
- end += mend - (v + 1 + 2+m->textlen+2);
- m->inuse--;
-
- buf->remove(u, v + 1 - u);
- end -= v + 1 - u;
- u += mend - (v + 1);
- mem.xfree(const_cast<utf8_t *>(marg));
- //printf("u = %d, end = %d\n", u, end);
- //printf("#%.*s#\n", end - u, &buf->slice().ptr[u]);
- continue;
- }
- }
- else
- {
- // Replace $(NAME) with nothing
- buf->remove(u, v + 1 - u);
- end -= (v + 1 - u);
- continue;
- }
- }
- }
- u++;
- }
- mem.xfree(const_cast<utf8_t *>(arg));
- *pend = end;
- nest--;
-}
diff --git a/gcc/d/dmd/dmacro.d b/gcc/d/dmd/dmacro.d
new file mode 100644
index 0000000..ddfee2c
--- /dev/null
+++ b/gcc/d/dmd/dmacro.d
@@ -0,0 +1,435 @@
+/**
+ * Text macro processor for Ddoc.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmacro.d, _dmacro.d)
+ * Documentation: https://dlang.org/phobos/dmd_dmacro.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmacro.d
+ */
+
+module dmd.dmacro;
+
+import core.stdc.ctype;
+import core.stdc.string;
+import dmd.doc;
+import dmd.errors;
+import dmd.globals;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+
+extern (C++) struct MacroTable
+{
+ /**********************************
+ * Define name=text macro.
+ * If macro `name` already exists, replace the text for it.
+ * Params:
+ * name = name of macro
+ * text = text of macro
+ */
+ extern (D) void define(const(char)[] name, const(char)[] text)
+ {
+ //printf("MacroTable::define('%.*s' = '%.*s')\n", cast(int)name.length, name.ptr, text.length, text.ptr);
+ Macro* table;
+ for (table = mactab; table; table = table.next)
+ {
+ if (table.name == name)
+ {
+ table.text = text;
+ return;
+ }
+ }
+ table = new Macro(name, text);
+ table.next = mactab;
+ mactab = table;
+ }
+
+ /*****************************************************
+ * Look for macros in buf and expand them in place.
+ * Only look at the text in buf from start to pend.
+ */
+ extern (D) void expand(ref OutBuffer buf, size_t start, ref size_t pend, const(char)[] arg)
+ {
+ version (none)
+ {
+ printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, pend, cast(int)arg.length, arg.ptr);
+ printf("Buf is: '%.*s'\n", cast(int)(pend - start), buf.data + start);
+ }
+ // limit recursive expansion
+ __gshared int nest;
+ if (nest > global.recursionLimit)
+ {
+ error(Loc.initial, "DDoc macro expansion limit exceeded; more than %d expansions.",
+ global.recursionLimit);
+ return;
+ }
+ nest++;
+ size_t end = pend;
+ assert(start <= end);
+ assert(end <= buf.length);
+ /* First pass - replace $0
+ */
+ arg = memdup(arg);
+ for (size_t u = start; u + 1 < end;)
+ {
+ char* p = cast(char*)buf[].ptr; // buf.data is not loop invariant
+ /* Look for $0, but not $$0, and replace it with arg.
+ */
+ if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+'))
+ {
+ if (u > start && p[u - 1] == '$')
+ {
+ // Don't expand $$0, but replace it with $0
+ buf.remove(u - 1, 1);
+ end--;
+ u += 1; // now u is one past the closing '1'
+ continue;
+ }
+ char c = p[u + 1];
+ int n = (c == '+') ? -1 : c - '0';
+ const(char)[] marg;
+ if (n == 0)
+ {
+ marg = arg;
+ }
+ else
+ extractArgN(arg, marg, n);
+ if (marg.length == 0)
+ {
+ // Just remove macro invocation
+ //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], cast(int)marg.length, marg.ptr);
+ buf.remove(u, 2);
+ end -= 2;
+ }
+ else if (c == '+')
+ {
+ // Replace '$+' with 'arg'
+ //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], cast(int)marg.length, marg.ptr);
+ buf.remove(u, 2);
+ buf.insert(u, marg);
+ end += marg.length - 2;
+ // Scan replaced text for further expansion
+ size_t mend = u + marg.length;
+ expand(buf, u, mend, null);
+ end += mend - (u + marg.length);
+ u = mend;
+ }
+ else
+ {
+ // Replace '$1' with '\xFF{arg\xFF}'
+ //printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], cast(int)marg.length, marg.ptr);
+ ubyte[] slice = cast(ubyte[])buf[];
+ slice[u] = 0xFF;
+ slice[u + 1] = '{';
+ buf.insert(u + 2, marg);
+ buf.insert(u + 2 + marg.length, "\xFF}");
+ end += -2 + 2 + marg.length + 2;
+ // Scan replaced text for further expansion
+ size_t mend = u + 2 + marg.length;
+ expand(buf, u + 2, mend, null);
+ end += mend - (u + 2 + marg.length);
+ u = mend;
+ }
+ //printf("u = %d, end = %d\n", u, end);
+ //printf("#%.*s#\n", cast(int)end, &buf.data[0]);
+ continue;
+ }
+ u++;
+ }
+ /* Second pass - replace other macros
+ */
+ for (size_t u = start; u + 4 < end;)
+ {
+ char* p = cast(char*)buf[].ptr; // buf.data is not loop invariant
+ /* A valid start of macro expansion is $(c, where c is
+ * an id start character, and not $$(c.
+ */
+ if (p[u] == '$' && p[u + 1] == '(' && isIdStart(p + u + 2))
+ {
+ //printf("\tfound macro start '%c'\n", p[u + 2]);
+ char* name = p + u + 2;
+ size_t namelen = 0;
+ const(char)[] marg;
+ size_t v;
+ /* Scan forward to find end of macro name and
+ * beginning of macro argument (marg).
+ */
+ for (v = u + 2; v < end; v += utfStride(p + v))
+ {
+ if (!isIdTail(p + v))
+ {
+ // We've gone past the end of the macro name.
+ namelen = v - (u + 2);
+ break;
+ }
+ }
+ v += extractArgN(p[v .. end], marg, 0);
+ assert(v <= end);
+ if (v < end)
+ {
+ // v is on the closing ')'
+ if (u > start && p[u - 1] == '$')
+ {
+ // Don't expand $$(NAME), but replace it with $(NAME)
+ buf.remove(u - 1, 1);
+ end--;
+ u = v; // now u is one past the closing ')'
+ continue;
+ }
+ Macro* m = search(name[0 .. namelen]);
+ if (!m)
+ {
+ immutable undef = "DDOC_UNDEFINED_MACRO";
+ m = search(undef);
+ if (m)
+ {
+ // Macro was not defined, so this is an expansion of
+ // DDOC_UNDEFINED_MACRO. Prepend macro name to args.
+ // marg = name[ ] ~ "," ~ marg[ ];
+ if (marg.length)
+ {
+ char* q = cast(char*)mem.xmalloc(namelen + 1 + marg.length);
+ assert(q);
+ memcpy(q, name, namelen);
+ q[namelen] = ',';
+ memcpy(q + namelen + 1, marg.ptr, marg.length);
+ marg = q[0 .. marg.length + namelen + 1];
+ }
+ else
+ {
+ marg = name[0 .. namelen];
+ }
+ }
+ }
+ if (m)
+ {
+ if (m.inuse && marg.length == 0)
+ {
+ // Remove macro invocation
+ buf.remove(u, v + 1 - u);
+ end -= v + 1 - u;
+ }
+ else if (m.inuse && ((arg.length == marg.length && memcmp(arg.ptr, marg.ptr, arg.length) == 0) ||
+ (arg.length + 4 == marg.length && marg[0] == 0xFF && marg[1] == '{' && memcmp(arg.ptr, marg.ptr + 2, arg.length) == 0 && marg[marg.length - 2] == 0xFF && marg[marg.length - 1] == '}')))
+ {
+ /* Recursive expansion:
+ * marg is same as arg (with blue paint added)
+ * Just leave in place.
+ */
+ }
+ else
+ {
+ //printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", cast(int)m.namelen, m.name, cast(int)marg.length, marg.ptr, cast(int)m.textlen, m.text);
+ marg = memdup(marg);
+ // Insert replacement text
+ buf.spread(v + 1, 2 + m.text.length + 2);
+ ubyte[] slice = cast(ubyte[])buf[];
+ slice[v + 1] = 0xFF;
+ slice[v + 2] = '{';
+ slice[v + 3 .. v + 3 + m.text.length] = cast(ubyte[])m.text[];
+ slice[v + 3 + m.text.length] = 0xFF;
+ slice[v + 3 + m.text.length + 1] = '}';
+ end += 2 + m.text.length + 2;
+ // Scan replaced text for further expansion
+ m.inuse++;
+ size_t mend = v + 1 + 2 + m.text.length + 2;
+ expand(buf, v + 1, mend, marg);
+ end += mend - (v + 1 + 2 + m.text.length + 2);
+ m.inuse--;
+ buf.remove(u, v + 1 - u);
+ end -= v + 1 - u;
+ u += mend - (v + 1);
+ mem.xfree(cast(char*)marg.ptr);
+ //printf("u = %d, end = %d\n", u, end);
+ //printf("#%.*s#\n", cast(int)(end - u), &buf.data[u]);
+ continue;
+ }
+ }
+ else
+ {
+ // Replace $(NAME) with nothing
+ buf.remove(u, v + 1 - u);
+ end -= (v + 1 - u);
+ continue;
+ }
+ }
+ }
+ u++;
+ }
+ mem.xfree(cast(char*)arg);
+ pend = end;
+ nest--;
+ }
+
+ private:
+
+ extern (D) Macro* search(const(char)[] name)
+ {
+ Macro* table;
+ //printf("Macro::search(%.*s)\n", cast(int)name.length, name.ptr);
+ for (table = mactab; table; table = table.next)
+ {
+ if (table.name == name)
+ {
+ //printf("\tfound %d\n", table.textlen);
+ break;
+ }
+ }
+ return table;
+ }
+
+ Macro* mactab;
+}
+
+/* ************************************************************************ */
+
+private:
+
+struct Macro
+{
+ Macro* next; // next in list
+ const(char)[] name; // macro name
+ const(char)[] text; // macro replacement text
+ int inuse; // macro is in use (don't expand)
+
+ this(const(char)[] name, const(char)[] text)
+ {
+ this.name = name;
+ this.text = text;
+ }
+}
+
+/************************
+ * Make mutable copy of slice p.
+ * Params:
+ * p = slice
+ * Returns:
+ * copy allocated with mem.xmalloc()
+ */
+
+char[] memdup(const(char)[] p)
+{
+ size_t len = p.length;
+ return (cast(char*)memcpy(mem.xmalloc(len), p.ptr, len))[0 .. len];
+}
+
+/**********************************************************
+ * Given buffer buf[], extract argument marg[].
+ * Params:
+ * buf = source string
+ * marg = set to slice of buf[]
+ * n = 0: get entire argument
+ * 1..9: get nth argument
+ * -1: get 2nd through end
+ */
+size_t extractArgN(const(char)[] buf, out const(char)[] marg, int n)
+{
+ /* Scan forward for matching right parenthesis.
+ * Nest parentheses.
+ * Skip over "..." and '...' strings inside HTML tags.
+ * Skip over <!-- ... --> comments.
+ * Skip over previous macro insertions
+ * Set marg.
+ */
+ uint parens = 1;
+ ubyte instring = 0;
+ uint incomment = 0;
+ uint intag = 0;
+ uint inexp = 0;
+ uint argn = 0;
+ size_t v = 0;
+ const p = buf.ptr;
+ const end = buf.length;
+Largstart:
+ // Skip first space, if any, to find the start of the macro argument
+ if (n != 1 && v < end && isspace(p[v]))
+ v++;
+ size_t vstart = v;
+ for (; v < end; v++)
+ {
+ char c = p[v];
+ switch (c)
+ {
+ case ',':
+ if (!inexp && !instring && !incomment && parens == 1)
+ {
+ argn++;
+ if (argn == 1 && n == -1)
+ {
+ v++;
+ goto Largstart;
+ }
+ if (argn == n)
+ break;
+ if (argn + 1 == n)
+ {
+ v++;
+ goto Largstart;
+ }
+ }
+ continue;
+ case '(':
+ if (!inexp && !instring && !incomment)
+ parens++;
+ continue;
+ case ')':
+ if (!inexp && !instring && !incomment && --parens == 0)
+ {
+ break;
+ }
+ continue;
+ case '"':
+ case '\'':
+ if (!inexp && !incomment && intag)
+ {
+ if (c == instring)
+ instring = 0;
+ else if (!instring)
+ instring = c;
+ }
+ continue;
+ case '<':
+ if (!inexp && !instring && !incomment)
+ {
+ if (v + 6 < end && p[v + 1] == '!' && p[v + 2] == '-' && p[v + 3] == '-')
+ {
+ incomment = 1;
+ v += 3;
+ }
+ else if (v + 2 < end && isalpha(p[v + 1]))
+ intag = 1;
+ }
+ continue;
+ case '>':
+ if (!inexp)
+ intag = 0;
+ continue;
+ case '-':
+ if (!inexp && !instring && incomment && v + 2 < end && p[v + 1] == '-' && p[v + 2] == '>')
+ {
+ incomment = 0;
+ v += 2;
+ }
+ continue;
+ case 0xFF:
+ if (v + 1 < end)
+ {
+ if (p[v + 1] == '{')
+ inexp++;
+ else if (p[v + 1] == '}')
+ inexp--;
+ }
+ continue;
+ default:
+ continue;
+ }
+ break;
+ }
+ if (argn == 0 && n == -1)
+ marg = p[v .. v];
+ else
+ marg = p[vstart .. v];
+ //printf("extractArg%d('%.*s') = '%.*s'\n", n, cast(int)end, p, cast(int)marg.length, marg.ptr);
+ return v;
+}
diff --git a/gcc/d/dmd/dmangle.c b/gcc/d/dmd/dmangle.c
deleted file mode 100644
index 83f4c18..0000000
--- a/gcc/d/dmd/dmangle.c
+++ /dev/null
@@ -1,1122 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/mangle.c
- */
-
-#include "root/dsystem.h"
-#include "root/root.h"
-#include "root/aav.h"
-
-#include "mangle.h"
-#include "init.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "mtype.h"
-#include "attrib.h"
-#include "target.h"
-#include "template.h"
-#include "id.h"
-#include "module.h"
-#include "enum.h"
-#include "expression.h"
-#include "utf.h"
-
-typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param);
-int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL);
-
-static const char *mangleChar[TMAX];
-
-void initTypeMangle()
-{
- mangleChar[Tarray] = "A";
- mangleChar[Tsarray] = "G";
- mangleChar[Taarray] = "H";
- mangleChar[Tpointer] = "P";
- mangleChar[Treference] = "R";
- mangleChar[Tfunction] = "F";
- mangleChar[Tident] = "I";
- mangleChar[Tclass] = "C";
- mangleChar[Tstruct] = "S";
- mangleChar[Tenum] = "E";
- mangleChar[Tdelegate] = "D";
-
- mangleChar[Tnone] = "n";
- mangleChar[Tvoid] = "v";
- mangleChar[Tint8] = "g";
- mangleChar[Tuns8] = "h";
- mangleChar[Tint16] = "s";
- mangleChar[Tuns16] = "t";
- mangleChar[Tint32] = "i";
- mangleChar[Tuns32] = "k";
- mangleChar[Tint64] = "l";
- mangleChar[Tuns64] = "m";
- mangleChar[Tint128] = "zi";
- mangleChar[Tuns128] = "zk";
- mangleChar[Tfloat32] = "f";
- mangleChar[Tfloat64] = "d";
- mangleChar[Tfloat80] = "e";
-
- mangleChar[Timaginary32] = "o";
- mangleChar[Timaginary64] = "p";
- mangleChar[Timaginary80] = "j";
- mangleChar[Tcomplex32] = "q";
- mangleChar[Tcomplex64] = "r";
- mangleChar[Tcomplex80] = "c";
-
- mangleChar[Tbool] = "b";
- mangleChar[Tchar] = "a";
- mangleChar[Twchar] = "u";
- mangleChar[Tdchar] = "w";
-
- // '@' shouldn't appear anywhere in the deco'd names
- mangleChar[Tinstance] = "@";
- mangleChar[Terror] = "@";
- mangleChar[Ttypeof] = "@";
- mangleChar[Ttuple] = "B";
- mangleChar[Tslice] = "@";
- mangleChar[Treturn] = "@";
- mangleChar[Tvector] = "@";
- mangleChar[Ttraits] = "@";
- mangleChar[Tmixin] = "@";
- mangleChar[Tnoreturn] = "@"; // becomes 'Nn'
-
- mangleChar[Tnull] = "n"; // same as TypeNone
-
- for (size_t i = 0; i < TMAX; i++)
- {
- if (!mangleChar[i])
- fprintf(stderr, "ty = %llu\n", (ulonglong)i);
- assert(mangleChar[i]);
- }
-}
-
-/*********************************
- * Mangling for mod.
- */
-void MODtoDecoBuffer(OutBuffer *buf, MOD mod)
-{
- switch (mod)
- {
- case 0:
- break;
- case MODconst:
- buf->writeByte('x');
- break;
- case MODimmutable:
- buf->writeByte('y');
- break;
- case MODshared:
- buf->writeByte('O');
- break;
- case MODshared | MODconst:
- buf->writestring("Ox");
- break;
- case MODwild:
- buf->writestring("Ng");
- break;
- case MODwildconst:
- buf->writestring("Ngx");
- break;
- case MODshared | MODwild:
- buf->writestring("ONg");
- break;
- case MODshared | MODwildconst:
- buf->writestring("ONgx");
- break;
- default:
- assert(0);
- }
-}
-
-class Mangler : public Visitor
-{
-public:
- AA *types;
- AA *idents;
- OutBuffer *buf;
-
- Mangler(OutBuffer *buf)
- {
- this->types = NULL;
- this->idents = NULL;
- this->buf = buf;
- }
-
- /**
- * writes a back reference with the relative position encoded with base 26
- * using upper case letters for all digits but the last digit which uses
- * a lower case letter.
- * The decoder has to look up the referenced position to determine
- * whether the back reference is an identifier (starts with a digit)
- * or a type (starts with a letter).
- *
- * Params:
- * pos = relative position to encode
- */
- void writeBackRef(size_t pos)
- {
- buf->writeByte('Q');
- const size_t base = 26;
- size_t mul = 1;
- while (pos >= mul * base)
- mul *= base;
- while (mul >= base)
- {
- unsigned char dig = (unsigned char)(pos / mul);
- buf->writeByte('A' + dig);
- pos -= dig * mul;
- mul /= base;
- }
- buf->writeByte('a' + (unsigned char)pos);
- }
-
- /**
- * Back references a non-basic type
- *
- * The encoded mangling is
- * 'Q' <relative position of first occurrence of type>
- *
- * Params:
- * t = the type to encode via back referencing
- *
- * Returns:
- * true if the type was found. A back reference has been encoded.
- * false if the type was not found. The current position is saved for later back references.
- */
- bool backrefType(Type *t)
- {
- if (!t->isTypeBasic())
- {
- size_t *p = (size_t *)dmd_aaGet(&types, (void *)t);
- if (*p)
- {
- writeBackRef(buf->length() - *p);
- return true;
- }
- *p = buf->length();
- }
- return false;
- }
-
- /**
- * Back references a single identifier
- *
- * The encoded mangling is
- * 'Q' <relative position of first occurrence of type>
- *
- * Params:
- * id = the identifier to encode via back referencing
- *
- * Returns:
- * true if the identifier was found. A back reference has been encoded.
- * false if the identifier was not found. The current position is saved for later back references.
- */
- bool backrefIdentifier(Identifier *id)
- {
- size_t *p = (size_t *)dmd_aaGet(&idents, (void *)id);
- if (*p)
- {
- writeBackRef(buf->length() - *p);
- return true;
- }
- *p = buf->length();
- return false;
- }
-
- void mangleSymbol(Dsymbol *s)
- {
- s->accept(this);
- }
-
- void mangleType(Type *t)
- {
- if (!backrefType(t))
- t->accept(this);
- }
-
- void mangleIdentifier(Identifier *id, Dsymbol *s)
- {
- if (!backrefIdentifier(id))
- toBuffer(id->toChars(), s);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- /**************************************************
- * Type mangling
- */
-
- void visitWithMask(Type *t, unsigned char modMask)
- {
- if (modMask != t->mod)
- {
- MODtoDecoBuffer(buf, t->mod);
- }
- mangleType(t);
- }
-
- void visit(Type *t)
- {
- buf->writestring(mangleChar[t->ty]);
- }
-
- void visit(TypeNext *t)
- {
- visit((Type *)t);
- visitWithMask(t->next, t->mod);
- }
-
- void visit(TypeVector *t)
- {
- buf->writestring("Nh");
- visitWithMask(t->basetype, t->mod);
- }
-
- void visit(TypeSArray *t)
- {
- visit((Type *)t);
- if (t->dim)
- buf->print(t->dim->toInteger());
- if (t->next)
- visitWithMask(t->next, t->mod);
- }
-
- void visit(TypeDArray *t)
- {
- visit((Type *)t);
- if (t->next)
- visitWithMask(t->next, t->mod);
- }
-
- void visit(TypeAArray *t)
- {
- visit((Type *)t);
- visitWithMask(t->index, 0);
- visitWithMask(t->next, t->mod);
- }
-
- void visit(TypeFunction *t)
- {
- //printf("TypeFunction::toDecoBuffer() t = %p %s\n", t, t->toChars());
- //static int nest; if (++nest == 50) *(char*)0=0;
-
- mangleFuncType(t, t, t->mod, t->next);
- }
-
- void mangleFuncType(TypeFunction *t, TypeFunction *ta, unsigned char modMask, Type *tret)
- {
- //printf("mangleFuncType() %s\n", t->toChars());
- if (t->inuse && tret)
- {
- // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t->toChars());
- t->inuse = 2; // flag error to caller
- return;
- }
- t->inuse++;
-
- if (modMask != t->mod)
- MODtoDecoBuffer(buf, t->mod);
-
- unsigned char mc;
- switch (t->linkage)
- {
- case LINKd: mc = 'F'; break;
- case LINKc: mc = 'U'; break;
- case LINKwindows: mc = 'W'; break;
- case LINKcpp: mc = 'R'; break;
- case LINKobjc: mc = 'Y'; break;
- default:
- assert(0);
- }
- buf->writeByte(mc);
-
- if (ta->purity || ta->isnothrow || ta->isnogc || ta->isproperty || ta->isref || ta->trust || ta->isreturn || ta->isscope)
- {
- if (ta->purity)
- buf->writestring("Na");
- if (ta->isnothrow)
- buf->writestring("Nb");
- if (ta->isref)
- buf->writestring("Nc");
- if (ta->isproperty)
- buf->writestring("Nd");
- if (ta->isnogc)
- buf->writestring("Ni");
- if (ta->isreturn)
- buf->writestring("Nj");
- if (ta->isscope && !ta->isreturn && !ta->isscopeinferred)
- buf->writestring("Nl");
- switch (ta->trust)
- {
- case TRUSTtrusted:
- buf->writestring("Ne");
- break;
- case TRUSTsafe:
- buf->writestring("Nf");
- break;
- default:
- break;
- }
- }
-
- // Write argument types
- paramsToDecoBuffer(t->parameterList.parameters);
- //if (buf->slice().ptr[buf->length() - 1] == '@') halt();
- buf->writeByte('Z' - t->parameterList.varargs); // mark end of arg list
- if (tret != NULL)
- visitWithMask(tret, 0);
-
- t->inuse--;
- }
-
- void visit(TypeIdentifier *t)
- {
- visit((Type *)t);
- const char *name = t->ident->toChars();
- size_t len = strlen(name);
- buf->print(len);
- buf->writestring(name);
- }
-
- void visit(TypeEnum *t)
- {
- visit((Type *)t);
- mangleSymbol(t->sym);
- }
-
- void visit(TypeStruct *t)
- {
- //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", t->toChars(), name);
- visit((Type *)t);
- mangleSymbol(t->sym);
- }
-
- void visit(TypeClass *t)
- {
- //printf("TypeClass::toDecoBuffer('%s' mod=%x) = '%s'\n", t->toChars(), mod, name);
- visit((Type *)t);
- mangleSymbol(t->sym);
- }
-
- void visit(TypeTuple *t)
- {
- //printf("TypeTuple::toDecoBuffer() t = %p, %s\n", t, t->toChars());
- visit((Type *)t);
- paramsToDecoBuffer(t->arguments);
- buf->writeByte('Z');
- }
-
- void visit(TypeNull *t)
- {
- visit((Type *)t);
- }
-
- void visit(TypeNoreturn *)
- {
- buf->writestring("Nn");
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- void mangleDecl(Declaration *sthis)
- {
- mangleParent(sthis);
-
- assert(sthis->ident);
- mangleIdentifier(sthis->ident, sthis);
- if (FuncDeclaration *fd = sthis->isFuncDeclaration())
- {
- mangleFunc(fd, false);
- }
- else if (sthis->type)
- {
- visitWithMask(sthis->type, 0);
- }
- else
- assert(0);
- }
-
- void mangleParent(Dsymbol *s)
- {
- Dsymbol *p;
- if (TemplateInstance *ti = s->isTemplateInstance())
- p = ti->isTemplateMixin() ? ti->parent : ti->tempdecl->parent;
- else
- p = s->parent;
-
- if (p)
- {
- mangleParent(p);
- TemplateInstance *ti = p->isTemplateInstance();
- if (ti && !ti->isTemplateMixin())
- {
- mangleTemplateInstance(ti);
- }
- else if (p->getIdent())
- {
- mangleIdentifier(p->ident, s);
- if (FuncDeclaration *f = p->isFuncDeclaration())
- mangleFunc(f, true);
- }
- else
- buf->writeByte('0');
- }
- }
-
- void mangleFunc(FuncDeclaration *fd, bool inParent)
- {
- //printf("deco = '%s'\n", fd->type->deco ? fd->type->deco : "null");
- //printf("fd->type = %s\n", fd->type->toChars());
- if (fd->needThis() || fd->isNested())
- buf->writeByte('M');
- if (inParent)
- {
- TypeFunction *tf = (TypeFunction *)fd->type;
- TypeFunction *tfo = (TypeFunction *)fd->originalType;
- mangleFuncType(tf, tfo, 0, NULL);
- }
- else if (fd->type)
- {
- visitWithMask(fd->type, 0);
- }
- else
- {
- printf("[%s] %s no type\n", fd->loc.toChars(), fd->toChars());
- assert(0); // don't mangle function until semantic3 done.
- }
- }
-
- /************************************************************
- * Write length prefixed string to buf.
- */
- void toBuffer(const char *id, Dsymbol *s)
- {
- size_t len = strlen(id);
- if (buf->length() + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
- s->error("excessive length %llu for symbol, possible recursive expansion?", buf->length() + len);
- else
- {
- buf->print(len);
- buf->write(id, len);
- }
- }
-
- static const char *externallyMangledIdentifier(Declaration *d)
- {
- if (!d->parent || d->parent->isModule() || d->linkage == LINKcpp) // if at global scope
- {
- switch (d->linkage)
- {
- case LINKd:
- break;
- case LINKc:
- case LINKwindows:
- case LINKobjc:
- return d->ident->toChars();
- case LINKcpp:
- return target.cpp.toMangle(d);
- case LINKdefault:
- d->error("forward declaration");
- return d->ident->toChars();
- default:
- fprintf(stderr, "'%s', linkage = %d\n", d->toChars(), d->linkage);
- assert(0);
- }
- }
- return NULL;
- }
-
- void visit(Declaration *d)
- {
- //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
- // d, d->toChars(), d->parent ? d->parent->toChars() : "null", d->linkage);
- if (const char *id = externallyMangledIdentifier(d))
- {
- buf->writestring(id);
- return;
- }
- buf->writestring("_D");
- mangleDecl(d);
- }
-
- /******************************************************************************
- * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
- * If and only if there is no overloads, mangle() could return
- * exact mangled name.
- *
- * module test;
- * void foo(long) {} // _D4test3fooFlZv
- * void foo(string) {} // _D4test3fooFAyaZv
- *
- * // from FuncDeclaration::mangle().
- * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo"
- * // by calling Dsymbol::mangle()
- *
- * // from FuncAliasDeclaration::mangle()
- * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv"
- * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv"
- *
- * If a function has no overloads, .mangleof property still returns exact mangled name.
- *
- * void bar() {}
- * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv"
- * // by calling FuncDeclaration::mangleExact().
- */
- void visit(FuncDeclaration *fd)
- {
- if (fd->isUnique())
- mangleExact(fd);
- else
- visit((Dsymbol *)fd);
- }
-
- // ditto
- void visit(FuncAliasDeclaration *fd)
- {
- FuncDeclaration *f = fd->toAliasFunc();
- FuncAliasDeclaration *fa = f->isFuncAliasDeclaration();
- if (!fd->hasOverloads && !fa)
- {
- mangleExact(f);
- return;
- }
- if (fa)
- {
- mangleSymbol(fa);
- return;
- }
- visit((Dsymbol *)fd);
- }
-
- void visit(OverDeclaration *od)
- {
- if (od->overnext)
- {
- visit((Dsymbol *)od);
- return;
- }
-
- if (FuncDeclaration *fd = od->aliassym->isFuncDeclaration())
- {
- if (!od->hasOverloads || fd->isUnique())
- {
- mangleExact(fd);
- return;
- }
- }
- if (TemplateDeclaration *td = od->aliassym->isTemplateDeclaration())
- {
- if (!od->hasOverloads || td->overnext == NULL)
- {
- mangleSymbol(td);
- return;
- }
- }
- visit((Dsymbol *)od);
- }
-
- void mangleExact(FuncDeclaration *fd)
- {
- assert(!fd->isFuncAliasDeclaration());
-
- if (fd->mangleOverride.length)
- {
- buf->writestring(fd->mangleOverride.ptr);
- return;
- }
-
- if (fd->isMain())
- {
- buf->writestring("_Dmain");
- return;
- }
-
- if (fd->isWinMain() || fd->isDllMain() || fd->ident == Id::tls_get_addr)
- {
- buf->writestring(fd->ident->toChars());
- return;
- }
-
- visit((Declaration *)fd);
- }
-
- void visit(VarDeclaration *vd)
- {
- if (vd->mangleOverride.length)
- {
- buf->writestring(vd->mangleOverride.ptr);
- return;
- }
-
- visit((Declaration *)vd);
- }
-
- void visit(AggregateDeclaration *ad)
- {
- ClassDeclaration *cd = ad->isClassDeclaration();
- Dsymbol *parentsave = ad->parent;
- if (cd)
- {
- /* These are reserved to the compiler, so keep simple
- * names for them.
- */
- if ((cd->ident == Id::Exception && cd->parent->ident == Id::object) ||
- cd->ident == Id::TypeInfo ||
- cd->ident == Id::TypeInfo_Struct ||
- cd->ident == Id::TypeInfo_Class ||
- cd->ident == Id::TypeInfo_Tuple ||
- cd == ClassDeclaration::object ||
- cd == Type::typeinfoclass ||
- cd == Module::moduleinfo ||
- strncmp(cd->ident->toChars(), "TypeInfo_", 9) == 0)
- {
- // Don't mangle parent
- ad->parent = NULL;
- }
- }
-
- visit((Dsymbol *)ad);
-
- ad->parent = parentsave;
- }
-
- void visit(TemplateInstance *ti)
- {
- if (!ti->tempdecl)
- ti->error("is not defined");
- else
- mangleParent(ti);
-
- if (ti->isTemplateMixin() && ti->ident)
- mangleIdentifier(ti->ident, ti);
- else
- mangleTemplateInstance(ti);
- }
-
- void mangleTemplateInstance(TemplateInstance *ti)
- {
- TemplateDeclaration *tempdecl = ti->tempdecl->isTemplateDeclaration();
- assert(tempdecl);
-
- // Use "__U" for the symbols declared inside template constraint.
- const char T = ti->members ? 'T' : 'U';
- buf->printf("__%c", T);
- mangleIdentifier(tempdecl->ident, tempdecl);
-
- Objects *args = ti->tiargs;
- size_t nparams = tempdecl->parameters->length - (tempdecl->isVariadic() ? 1 : 0);
- for (size_t i = 0; i < args->length; i++)
- {
- RootObject *o = (*args)[i];
- Type *ta = isType(o);
- Expression *ea = isExpression(o);
- Dsymbol *sa = isDsymbol(o);
- Tuple *va = isTuple(o);
- //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
- if (i < nparams && (*tempdecl->parameters)[i]->specialization())
- buf->writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574
- if (ta)
- {
- buf->writeByte('T');
- visitWithMask(ta, 0);
- }
- else if (ea)
- {
- // Don't interpret it yet, it might actually be an alias template parameter.
- // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
- const bool keepLvalue = true;
- ea = ea->optimize(WANTvalue, keepLvalue);
- if (ea->op == TOKvar)
- {
- sa = ((VarExp *)ea)->var;
- ea = NULL;
- goto Lsa;
- }
- if (ea->op == TOKthis)
- {
- sa = ((ThisExp *)ea)->var;
- ea = NULL;
- goto Lsa;
- }
- if (ea->op == TOKfunction)
- {
- if (((FuncExp *)ea)->td)
- sa = ((FuncExp *)ea)->td;
- else
- sa = ((FuncExp *)ea)->fd;
- ea = NULL;
- goto Lsa;
- }
- buf->writeByte('V');
- if (ea->op == TOKtuple)
- {
- ea->error("tuple is not a valid template value argument");
- continue;
- }
- // Now that we know it is not an alias, we MUST obtain a value
- unsigned olderr = global.errors;
- ea = ea->ctfeInterpret();
- if (ea->op == TOKerror || olderr != global.errors)
- continue;
-
- /* Use type mangling that matches what it would be for a function parameter
- */
- visitWithMask(ea->type, 0);
- ea->accept(this);
- }
- else if (sa)
- {
- Lsa:
- sa = sa->toAlias();
- if (Declaration *d = sa->isDeclaration())
- {
- if (FuncAliasDeclaration *fad = d->isFuncAliasDeclaration())
- d = fad->toAliasFunc();
- if (d->mangleOverride.length)
- {
- buf->writeByte('X');
- toBuffer(d->mangleOverride.ptr, d);
- continue;
- }
- if (const char *id = externallyMangledIdentifier(d))
- {
- buf->writeByte('X');
- toBuffer(id, d);
- continue;
- }
- if (!d->type || !d->type->deco)
- {
- ti->error("forward reference of %s %s", d->kind(), d->toChars());
- continue;
- }
- }
- buf->writeByte('S');
- mangleSymbol(sa);
- }
- else if (va)
- {
- assert(i + 1 == args->length); // must be last one
- args = &va->objects;
- i = -(size_t)1;
- }
- else
- assert(0);
- }
- buf->writeByte('Z');
- }
-
- void visit(Dsymbol *s)
- {
- mangleParent(s);
- if (s->ident)
- mangleIdentifier(s->ident, s);
- else
- toBuffer(s->toChars(), s);
- //printf("Dsymbol::mangle() %s = %s\n", s->toChars(), id);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- void visit(Expression *e)
- {
- e->error("expression %s is not a valid template value argument", e->toChars());
- }
-
- void visit(IntegerExp *e)
- {
- if ((sinteger_t)e->value < 0)
- {
- buf->writeByte('N');
- buf->print(-e->value);
- }
- else
- {
- buf->writeByte('i');
- buf->print(e->value);
- }
- }
-
- void visit(RealExp *e)
- {
- buf->writeByte('e');
- realToMangleBuffer(e->value);
- }
-
- void realToMangleBuffer(real_t value)
- {
- /* Rely on %A to get portable mangling.
- * Must munge result to get only identifier characters.
- *
- * Possible values from %A => mangled result
- * NAN => NAN
- * -INF => NINF
- * INF => INF
- * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
- * 0X1.9P+2 => 19P2
- */
-
- if (CTFloat::isNaN(value))
- buf->writestring("NAN"); // no -NAN bugs
- else if (CTFloat::isInfinity(value))
- buf->writestring(value < CTFloat::zero ? "NINF" : "INF");
- else
- {
- const size_t BUFFER_LEN = 36;
- char buffer[BUFFER_LEN];
- size_t n = CTFloat::sprint(buffer, 'A', value);
- assert(n < BUFFER_LEN);
- for (size_t i = 0; i < n; i++)
- {
- char c = buffer[i];
- switch (c)
- {
- case '-':
- buf->writeByte('N');
- break;
-
- case '+':
- case 'X':
- case '.':
- break;
-
- case '0':
- if (i < 2)
- break; // skip leading 0X
- /* fall through */
- default:
- buf->writeByte(c);
- break;
- }
- }
- }
- }
-
- void visit(ComplexExp *e)
- {
- buf->writeByte('c');
- realToMangleBuffer(e->toReal());
- buf->writeByte('c'); // separate the two
- realToMangleBuffer(e->toImaginary());
- }
-
- void visit(NullExp *)
- {
- buf->writeByte('n');
- }
-
- void visit(StringExp *e)
- {
- char m;
- OutBuffer tmp;
- utf8_t *q;
- size_t qlen;
-
- /* Write string in UTF-8 format
- */
- switch (e->sz)
- {
- case 1:
- m = 'a';
- q = (utf8_t *)e->string;
- qlen = e->len;
- break;
-
- case 2:
- m = 'w';
- for (size_t u = 0; u < e->len; )
- {
- unsigned c;
- const char *p = utf_decodeWchar((unsigned short *)e->string, e->len, &u, &c);
- if (p)
- e->error("%s", p);
- else
- tmp.writeUTF8(c);
- }
- q = (utf8_t *)tmp.slice().ptr;
- qlen = tmp.length();
- break;
-
- case 4:
- m = 'd';
- for (size_t u = 0; u < e->len; u++)
- {
- unsigned c = ((unsigned *)e->string)[u];
- if (!utf_isValidDchar(c))
- e->error("invalid UCS-32 char \\U%08x", c);
- else
- tmp.writeUTF8(c);
- }
- q = (utf8_t *)tmp.slice().ptr;
- qlen = tmp.length();
- break;
-
- default:
- assert(0);
- }
- buf->reserve(1 + 11 + 2 * qlen);
- buf->writeByte(m);
- buf->print(qlen);
- buf->writeByte('_'); // nbytes <= 11
-
- for (utf8_t *p = (utf8_t *)buf->slice().ptr + buf->length(), *pend = p + 2 * qlen;
- p < pend; p += 2, ++q)
- {
- utf8_t hi = *q >> 4 & 0xF;
- p[0] = (utf8_t)(hi < 10 ? hi + '0' : hi - 10 + 'a');
- utf8_t lo = *q & 0xF;
- p[1] = (utf8_t)(lo < 10 ? lo + '0' : lo - 10 + 'a');
- }
- buf->setsize(buf->length() + 2 * qlen);
- }
-
- void visit(ArrayLiteralExp *e)
- {
- size_t dim = e->elements ? e->elements->length : 0;
- buf->writeByte('A');
- buf->print(dim);
- for (size_t i = 0; i < dim; i++)
- {
- e->getElement(i)->accept(this);
- }
- }
-
- void visit(AssocArrayLiteralExp *e)
- {
- size_t dim = e->keys->length;
- buf->writeByte('A');
- buf->print(dim);
- for (size_t i = 0; i < dim; i++)
- {
- (*e->keys)[i]->accept(this);
- (*e->values)[i]->accept(this);
- }
- }
-
- void visit(StructLiteralExp *e)
- {
- size_t dim = e->elements ? e->elements->length : 0;
- buf->writeByte('S');
- buf->print(dim);
- for (size_t i = 0; i < dim; i++)
- {
- Expression *ex = (*e->elements)[i];
- if (ex)
- ex->accept(this);
- else
- buf->writeByte('v'); // 'v' for void
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- void paramsToDecoBuffer(Parameters *parameters)
- {
- //printf("Parameter::paramsToDecoBuffer()\n");
- Parameter_foreach(parameters, &paramsToDecoBufferDg, (void *)this);
- }
-
- static int paramsToDecoBufferDg(void *ctx, size_t, Parameter *p)
- {
- p->accept((Visitor *)ctx);
- return 0;
- }
-
- void visit(Parameter *p)
- {
- if (p->storageClass & STCscope && !(p->storageClass & STCscopeinferred))
- buf->writeByte('M');
- // 'return inout ref' is the same as 'inout ref'
- if ((p->storageClass & (STCreturn | STCwild)) == STCreturn)
- buf->writestring("Nk");
- switch (p->storageClass & (STCin | STCout | STCref | STClazy))
- {
- case 0:
- case STCin:
- break;
- case STCout:
- buf->writeByte('J');
- break;
- case STCref:
- buf->writeByte('K');
- break;
- case STClazy:
- buf->writeByte('L');
- break;
- default:
- assert(0);
- }
- visitWithMask(p->type, 0);
- }
-};
-
-/******************************************************************************
- * Returns exact mangled name of function.
- */
-const char *mangleExact(FuncDeclaration *fd)
-{
- if (!fd->mangleString)
- {
- OutBuffer buf;
- Mangler v(&buf);
- v.mangleExact(fd);
- fd->mangleString = buf.extractChars();
- }
- return fd->mangleString;
-}
-
-void mangleToBuffer(Type *t, OutBuffer *buf)
-{
- Mangler v(buf);
- v.visitWithMask(t, 0);
-}
-
-void mangleToBuffer(Expression *e, OutBuffer *buf)
-{
- Mangler v(buf);
- e->accept(&v);
-}
-
-void mangleToBuffer(Dsymbol *s, OutBuffer *buf)
-{
- Mangler v(buf);
- s->accept(&v);
-}
-
-void mangleToBuffer(TemplateInstance *ti, OutBuffer *buf)
-{
- Mangler v(buf);
- v.mangleTemplateInstance(ti);
-}
-
-/**********************************************
- * Convert a string representing a type (the deco) and
- * return its equivalent Type.
- * Params:
- * deco = string containing the deco
- * Returns:
- * null for failed to convert
- * Type for succeeded
- */
-
-Type *decoToType(const char *deco)
-{
- if (!deco)
- return NULL;
-
- //printf("decoToType(): %s\n", deco)
- if (StringValue *sv = Type::stringtable.lookup(deco, strlen(deco)))
- {
- if (sv->ptrvalue)
- {
- Type *t = (Type *)sv->ptrvalue;
- assert(t->deco);
- return t;
- }
- }
- return NULL;
-}
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d
new file mode 100644
index 0000000..71b8c7a
--- /dev/null
+++ b/gcc/d/dmd/dmangle.d
@@ -0,0 +1,1297 @@
+/**
+ * Does name mangling for `extern(D)` symbols.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/abi.html#name_mangling, Name Mangling)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d, _dmangle.d)
+ * Documentation: https://dlang.org/phobos/dmd_dmangle.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmangle.d
+ * References: https://dlang.org/blog/2017/12/20/ds-newfangled-name-mangling/
+ */
+
+module dmd.dmangle;
+
+import dmd.astenums;
+
+/******************************************************************************
+ * Returns exact mangled name of function.
+ */
+extern (C++) const(char)* mangleExact(FuncDeclaration fd)
+{
+ if (!fd.mangleString)
+ {
+ OutBuffer buf;
+ scope Mangler v = new Mangler(&buf);
+ v.mangleExact(fd);
+ fd.mangleString = buf.extractChars();
+ }
+ return fd.mangleString;
+}
+
+extern (C++) void mangleToBuffer(Type t, OutBuffer* buf)
+{
+ if (t.deco)
+ buf.writestring(t.deco);
+ else
+ {
+ scope Mangler v = new Mangler(buf, t);
+ v.visitWithMask(t, 0);
+ }
+}
+
+extern (C++) void mangleToBuffer(Expression e, OutBuffer* buf)
+{
+ scope Mangler v = new Mangler(buf);
+ e.accept(v);
+}
+
+extern (C++) void mangleToBuffer(Dsymbol s, OutBuffer* buf)
+{
+ scope Mangler v = new Mangler(buf);
+ s.accept(v);
+}
+
+extern (C++) void mangleToBuffer(TemplateInstance ti, OutBuffer* buf)
+{
+ scope Mangler v = new Mangler(buf);
+ v.mangleTemplateInstance(ti);
+}
+
+/// Returns: `true` if the given character is a valid mangled character
+package bool isValidMangling(dchar c) nothrow
+{
+ return
+ c >= 'A' && c <= 'Z' ||
+ c >= 'a' && c <= 'z' ||
+ c >= '0' && c <= '9' ||
+ c != 0 && strchr("$%().:?@[]_", c) ||
+ isUniAlpha(c);
+}
+
+// valid mangled characters
+unittest
+{
+ assert('a'.isValidMangling);
+ assert('B'.isValidMangling);
+ assert('2'.isValidMangling);
+ assert('@'.isValidMangling);
+ assert('_'.isValidMangling);
+}
+
+// invalid mangled characters
+unittest
+{
+ assert(!'-'.isValidMangling);
+ assert(!0.isValidMangling);
+ assert(!'/'.isValidMangling);
+ assert(!'\\'.isValidMangling);
+}
+
+/**********************************************
+ * Convert a string representing a type (the deco) and
+ * return its equivalent Type.
+ * Params:
+ * deco = string containing the deco
+ * Returns:
+ * null for failed to convert
+ * Type for succeeded
+ */
+
+public Type decoToType(const(char)[] deco)
+{
+ //printf("decoToType(): %.*s\n", cast(int)deco.length, deco.ptr);
+ if (auto sv = Type.stringtable.lookup(deco))
+ {
+ if (sv.value)
+ {
+ Type t = cast(Type)sv.value;
+ assert(t.deco);
+ return t;
+ }
+ }
+ return null;
+}
+
+
+/***************************************** private ***************************************/
+
+private:
+
+
+import core.stdc.ctype;
+import core.stdc.stdio;
+import core.stdc.string;
+
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dmodule;
+import dmd.dsymbol;
+import dmd.dtemplate;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.root.ctfloat;
+import dmd.root.outbuffer;
+import dmd.root.aav;
+import dmd.root.string;
+import dmd.root.stringtable;
+import dmd.target;
+import dmd.tokens;
+import dmd.utf;
+import dmd.visitor;
+
+private immutable char[TMAX] mangleChar =
+[
+ Tchar : 'a',
+ Tbool : 'b',
+ Tcomplex80 : 'c',
+ Tfloat64 : 'd',
+ Tfloat80 : 'e',
+ Tfloat32 : 'f',
+ Tint8 : 'g',
+ Tuns8 : 'h',
+ Tint32 : 'i',
+ Timaginary80 : 'j',
+ Tuns32 : 'k',
+ Tint64 : 'l',
+ Tuns64 : 'm',
+ Tnull : 'n',
+ Timaginary32 : 'o',
+ Timaginary64 : 'p',
+ Tcomplex32 : 'q',
+ Tcomplex64 : 'r',
+ Tint16 : 's',
+ Tuns16 : 't',
+ Twchar : 'u',
+ Tvoid : 'v',
+ Tdchar : 'w',
+ // x // const
+ // y // immutable
+ Tint128 : 'z', // zi
+ Tuns128 : 'z', // zk
+
+ Tarray : 'A',
+ Ttuple : 'B',
+ Tclass : 'C',
+ Tdelegate : 'D',
+ Tenum : 'E',
+ Tfunction : 'F', // D function
+ Tsarray : 'G',
+ Taarray : 'H',
+ // I // in
+ // J // out
+ // K // ref
+ // L // lazy
+ // M // has this, or scope
+ // N // Nh:vector Ng:wild Nn:noreturn
+ // O // shared
+ Tpointer : 'P',
+ // Q // Type/symbol/identifier backward reference
+ Treference : 'R',
+ Tstruct : 'S',
+ // T // Ttypedef
+ // U // C function
+ // W // Windows function
+ // X // variadic T t...)
+ // Y // variadic T t,...)
+ // Z // not variadic, end of parameters
+
+ // '@' shouldn't appear anywhere in the deco'd names
+ Tnone : '@',
+ Tident : '@',
+ Tinstance : '@',
+ Terror : '@',
+ Ttypeof : '@',
+ Tslice : '@',
+ Treturn : '@',
+ Tvector : '@',
+ Ttraits : '@',
+ Tmixin : '@',
+ Ttag : '@',
+ Tnoreturn : '@', // becomes 'Nn'
+];
+
+unittest
+{
+ foreach (i, mangle; mangleChar)
+ {
+ if (mangle == char.init)
+ {
+ fprintf(stderr, "ty = %u\n", cast(uint)i);
+ assert(0);
+ }
+ }
+}
+
+/***********************
+ * Mangle basic type ty to buf.
+ */
+
+private void tyToDecoBuffer(OutBuffer* buf, int ty)
+{
+ const c = mangleChar[ty];
+ buf.writeByte(c);
+ if (c == 'z')
+ buf.writeByte(ty == Tint128 ? 'i' : 'k');
+}
+
+/*********************************
+ * Mangling for mod.
+ */
+private void MODtoDecoBuffer(OutBuffer* buf, MOD mod)
+{
+ switch (mod)
+ {
+ case 0:
+ break;
+ case MODFlags.const_:
+ buf.writeByte('x');
+ break;
+ case MODFlags.immutable_:
+ buf.writeByte('y');
+ break;
+ case MODFlags.shared_:
+ buf.writeByte('O');
+ break;
+ case MODFlags.shared_ | MODFlags.const_:
+ buf.writestring("Ox");
+ break;
+ case MODFlags.wild:
+ buf.writestring("Ng");
+ break;
+ case MODFlags.wildconst:
+ buf.writestring("Ngx");
+ break;
+ case MODFlags.shared_ | MODFlags.wild:
+ buf.writestring("ONg");
+ break;
+ case MODFlags.shared_ | MODFlags.wildconst:
+ buf.writestring("ONgx");
+ break;
+ default:
+ assert(0);
+ }
+}
+
+private extern (C++) final class Mangler : Visitor
+{
+ alias visit = Visitor.visit;
+public:
+ static assert(Key.sizeof == size_t.sizeof);
+ AssocArray!(Type, size_t) types; // Type => (offset+1) in buf
+ AssocArray!(Identifier, size_t) idents; // Identifier => (offset+1) in buf
+ OutBuffer* buf;
+ Type rootType;
+
+ extern (D) this(OutBuffer* buf, Type rootType = null)
+ {
+ this.buf = buf;
+ this.rootType = rootType;
+ }
+
+ /**
+ * writes a back reference with the relative position encoded with base 26
+ * using upper case letters for all digits but the last digit which uses
+ * a lower case letter.
+ * The decoder has to look up the referenced position to determine
+ * whether the back reference is an identifier (starts with a digit)
+ * or a type (starts with a letter).
+ *
+ * Params:
+ * pos = relative position to encode
+ */
+ void writeBackRef(size_t pos)
+ {
+ buf.writeByte('Q');
+ enum base = 26;
+ size_t mul = 1;
+ while (pos >= mul * base)
+ mul *= base;
+ while (mul >= base)
+ {
+ auto dig = cast(ubyte)(pos / mul);
+ buf.writeByte('A' + dig);
+ pos -= dig * mul;
+ mul /= base;
+ }
+ buf.writeByte('a' + cast(ubyte)pos);
+ }
+
+ /**
+ * Back references a non-basic type
+ *
+ * The encoded mangling is
+ * 'Q' <relative position of first occurrence of type>
+ *
+ * Params:
+ * t = the type to encode via back referencing
+ *
+ * Returns:
+ * true if the type was found. A back reference has been encoded.
+ * false if the type was not found. The current position is saved for later back references.
+ */
+ bool backrefType(Type t)
+ {
+ if (t.isTypeBasic())
+ return false;
+
+ /**
+ * https://issues.dlang.org/show_bug.cgi?id=21591
+ *
+ * Special case for unmerged TypeFunctions: use the generic merged
+ * function type as backref cache key to avoid missed backrefs.
+ *
+ * Merging is based on mangling, so we need to avoid an infinite
+ * recursion by excluding the case where `t` is the root type passed to
+ * `mangleToBuffer()`.
+ */
+ if (t != rootType)
+ {
+ if (t.isFunction_Delegate_PtrToFunction())
+ {
+ t = t.merge2();
+ }
+ }
+
+ return backrefImpl(types, t);
+ }
+
+ /**
+ * Back references a single identifier
+ *
+ * The encoded mangling is
+ * 'Q' <relative position of first occurrence of type>
+ *
+ * Params:
+ * id = the identifier to encode via back referencing
+ *
+ * Returns:
+ * true if the identifier was found. A back reference has been encoded.
+ * false if the identifier was not found. The current position is saved for later back references.
+ */
+ bool backrefIdentifier(Identifier id)
+ {
+ return backrefImpl(idents, id);
+ }
+
+ private extern(D) bool backrefImpl(T)(ref AssocArray!(T, size_t) aa, T key)
+ {
+ auto p = aa.getLvalue(key);
+ if (*p)
+ {
+ const offset = *p - 1;
+ writeBackRef(buf.length - offset);
+ return true;
+ }
+ *p = buf.length + 1;
+ return false;
+ }
+
+ void mangleSymbol(Dsymbol s)
+ {
+ s.accept(this);
+ }
+
+ void mangleType(Type t)
+ {
+ if (!backrefType(t))
+ t.accept(this);
+ }
+
+ void mangleIdentifier(Identifier id, Dsymbol s)
+ {
+ if (!backrefIdentifier(id))
+ toBuffer(id.toString(), s);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ /**************************************************
+ * Type mangling
+ */
+ void visitWithMask(Type t, ubyte modMask)
+ {
+ if (modMask != t.mod)
+ {
+ MODtoDecoBuffer(buf, t.mod);
+ }
+ mangleType(t);
+ }
+
+ override void visit(Type t)
+ {
+ tyToDecoBuffer(buf, t.ty);
+ }
+
+ override void visit(TypeNext t)
+ {
+ visit(cast(Type)t);
+ visitWithMask(t.next, t.mod);
+ }
+
+ override void visit(TypeVector t)
+ {
+ buf.writestring("Nh");
+ visitWithMask(t.basetype, t.mod);
+ }
+
+ override void visit(TypeSArray t)
+ {
+ visit(cast(Type)t);
+ if (t.dim)
+ buf.print(t.dim.toInteger());
+ if (t.next)
+ visitWithMask(t.next, t.mod);
+ }
+
+ override void visit(TypeDArray t)
+ {
+ visit(cast(Type)t);
+ if (t.next)
+ visitWithMask(t.next, t.mod);
+ }
+
+ override void visit(TypeAArray t)
+ {
+ visit(cast(Type)t);
+ visitWithMask(t.index, 0);
+ visitWithMask(t.next, t.mod);
+ }
+
+ override void visit(TypeFunction t)
+ {
+ //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars());
+ //static int nest; if (++nest == 50) *(char*)0=0;
+ mangleFuncType(t, t, t.mod, t.next);
+ }
+
+ void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret)
+ {
+ //printf("mangleFuncType() %s\n", t.toChars());
+ if (t.inuse && tret)
+ {
+ // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars());
+ t.inuse = 2; // flag error to caller
+ return;
+ }
+ t.inuse++;
+ if (modMask != t.mod)
+ MODtoDecoBuffer(buf, t.mod);
+
+ char mc;
+ final switch (t.linkage)
+ {
+ case LINK.default_:
+ case LINK.system:
+ case LINK.d:
+ mc = 'F';
+ break;
+ case LINK.c:
+ mc = 'U';
+ break;
+ case LINK.windows:
+ mc = 'W';
+ break;
+ case LINK.cpp:
+ mc = 'R';
+ break;
+ case LINK.objc:
+ mc = 'Y';
+ break;
+ }
+ buf.writeByte(mc);
+
+ if (ta.purity)
+ buf.writestring("Na");
+ if (ta.isnothrow)
+ buf.writestring("Nb");
+ if (ta.isref)
+ buf.writestring("Nc");
+ if (ta.isproperty)
+ buf.writestring("Nd");
+ if (ta.isnogc)
+ buf.writestring("Ni");
+
+ if (ta.isreturn && !ta.isreturninferred)
+ buf.writestring("Nj");
+ else if (ta.isScopeQual && !ta.isscopeinferred)
+ buf.writestring("Nl");
+
+ if (ta.islive)
+ buf.writestring("Nm");
+
+ switch (ta.trust)
+ {
+ case TRUST.trusted:
+ buf.writestring("Ne");
+ break;
+ case TRUST.safe:
+ buf.writestring("Nf");
+ break;
+ default:
+ break;
+ }
+
+ // Write argument types
+ foreach (idx, param; t.parameterList)
+ param.accept(this);
+ //if (buf.data[buf.length - 1] == '@') assert(0);
+ buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list
+ if (tret !is null)
+ visitWithMask(tret, 0);
+ t.inuse--;
+ }
+
+ override void visit(TypeIdentifier t)
+ {
+ visit(cast(Type)t);
+ auto name = t.ident.toString();
+ buf.print(cast(int)name.length);
+ buf.writestring(name);
+ }
+
+ override void visit(TypeEnum t)
+ {
+ visit(cast(Type)t);
+ mangleSymbol(t.sym);
+ }
+
+ override void visit(TypeStruct t)
+ {
+ //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
+ visit(cast(Type)t);
+ mangleSymbol(t.sym);
+ }
+
+ override void visit(TypeClass t)
+ {
+ //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
+ visit(cast(Type)t);
+ mangleSymbol(t.sym);
+ }
+
+ override void visit(TypeTuple t)
+ {
+ //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
+ visit(cast(Type)t);
+ Parameter._foreach(t.arguments, (idx, param) {
+ param.accept(this);
+ return 0;
+ });
+ buf.writeByte('Z');
+ }
+
+ override void visit(TypeNull t)
+ {
+ visit(cast(Type)t);
+ }
+
+ override void visit(TypeNoreturn t)
+ {
+ buf.writestring("Nn");
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ void mangleDecl(Declaration sthis)
+ {
+ mangleParent(sthis);
+ assert(sthis.ident);
+ mangleIdentifier(sthis.ident, sthis);
+ if (FuncDeclaration fd = sthis.isFuncDeclaration())
+ {
+ mangleFunc(fd, false);
+ }
+ else if (sthis.type)
+ {
+ visitWithMask(sthis.type, 0);
+ }
+ else
+ assert(0);
+ }
+
+ void mangleParent(Dsymbol s)
+ {
+ //printf("mangleParent() %s %s\n", s.kind(), s.toChars());
+ Dsymbol p;
+ if (TemplateInstance ti = s.isTemplateInstance())
+ p = ti.isTemplateMixin() ? ti.parent : ti.tempdecl.parent;
+ else
+ p = s.parent;
+ if (p)
+ {
+ uint localNum = s.localNum;
+ mangleParent(p);
+ auto ti = p.isTemplateInstance();
+ if (ti && !ti.isTemplateMixin())
+ {
+ localNum = ti.tempdecl.localNum;
+ mangleTemplateInstance(ti);
+ }
+ else if (p.getIdent())
+ {
+ mangleIdentifier(p.ident, s);
+ if (FuncDeclaration f = p.isFuncDeclaration())
+ mangleFunc(f, true);
+ }
+ else
+ buf.writeByte('0');
+
+ /* There can be multiple different declarations in the same
+ * function that have the same mangled name.
+ * This results in localNum having a non-zero number, which
+ * is used to add a fake parent of the form `__Sddd` to make
+ * the mangled names unique.
+ * https://issues.dlang.org/show_bug.cgi?id=20565
+ */
+ if (localNum)
+ {
+ uint ndigits = 1;
+ auto n = localNum;
+ while (n >= 10)
+ {
+ n /= 10;
+ ++ndigits;
+ }
+ buf.printf("%u__S%u", ndigits + 3, localNum);
+ }
+ }
+ }
+
+ void mangleFunc(FuncDeclaration fd, bool inParent)
+ {
+ //printf("deco = '%s'\n", fd.type.deco ? fd.type.deco : "null");
+ //printf("fd.type = %s\n", fd.type.toChars());
+ if (fd.needThis() || fd.isNested())
+ buf.writeByte('M');
+
+ if (!fd.type || fd.type.ty == Terror)
+ {
+ // never should have gotten here, but could be the result of
+ // failed speculative compilation
+ buf.writestring("9__error__FZ");
+
+ //printf("[%s] %s no type\n", fd.loc.toChars(), fd.toChars());
+ //assert(0); // don't mangle function until semantic3 done.
+ }
+ else if (inParent)
+ {
+ TypeFunction tf = fd.type.isTypeFunction();
+ TypeFunction tfo = fd.originalType.isTypeFunction();
+ mangleFuncType(tf, tfo, 0, null);
+ }
+ else
+ {
+ visitWithMask(fd.type, 0);
+ }
+ }
+
+ /************************************************************
+ * Write length prefixed string to buf.
+ */
+ extern (D) void toBuffer(const(char)[] id, Dsymbol s)
+ {
+ const len = id.length;
+ if (buf.length + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
+ s.error("excessive length %llu for symbol, possible recursive expansion?", cast(ulong)(buf.length + len));
+ else
+ {
+ buf.print(len);
+ buf.writestring(id);
+ }
+ }
+
+ /************************************************************
+ * Try to obtain an externally mangled identifier from a declaration.
+ * If the declaration is at global scope or mixed in at global scope,
+ * the user might want to call it externally, so an externally mangled
+ * name is returned. Member functions or nested functions can't be called
+ * externally in C, so in that case null is returned. C++ does support
+ * namespaces, so extern(C++) always gives a C++ mangled name.
+ *
+ * See also: https://issues.dlang.org/show_bug.cgi?id=20012
+ *
+ * Params:
+ * d = declaration to mangle
+ *
+ * Returns:
+ * an externally mangled name or null if the declaration cannot be called externally
+ */
+ extern (D) static const(char)[] externallyMangledIdentifier(Declaration d)
+ {
+ const par = d.toParent(); //toParent() skips over mixin templates
+ if (!par || par.isModule() || d.linkage == LINK.cpp)
+ {
+ if (d.linkage != LINK.d && d.localNum)
+ d.error("the same declaration cannot be in multiple scopes with non-D linkage");
+ final switch (d.linkage)
+ {
+ case LINK.d:
+ break;
+ case LINK.c:
+ case LINK.windows:
+ case LINK.objc:
+ return d.ident.toString();
+ case LINK.cpp:
+ {
+ const p = target.cpp.toMangle(d);
+ return p.toDString();
+ }
+ case LINK.default_:
+ case LINK.system:
+ d.error("forward declaration");
+ return d.ident.toString();
+ }
+ }
+ return null;
+ }
+
+ override void visit(Declaration d)
+ {
+ //printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
+ // d, d.toChars(), d.parent ? d.parent.toChars() : "null", d.linkage);
+ if (const id = externallyMangledIdentifier(d))
+ {
+ buf.writestring(id);
+ return;
+ }
+ buf.writestring("_D");
+ mangleDecl(d);
+ debug
+ {
+ const slice = (*buf)[];
+ assert(slice.length);
+ for (size_t pos; pos < slice.length; )
+ {
+ dchar c;
+ auto ppos = pos;
+ const s = utf_decodeChar(slice, pos, c);
+ assert(s is null, s);
+ assert(c.isValidMangling, "The mangled name '" ~ slice ~ "' " ~
+ "contains an invalid character: " ~ slice[ppos..pos]);
+ }
+ }
+ }
+
+ /******************************************************************************
+ * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
+ * If and only if there is no overloads, mangle() could return
+ * exact mangled name.
+ *
+ * module test;
+ * void foo(long) {} // _D4test3fooFlZv
+ * void foo(string) {} // _D4test3fooFAyaZv
+ *
+ * // from FuncDeclaration.mangle().
+ * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo"
+ * // by calling Dsymbol.mangle()
+ *
+ * // from FuncAliasDeclaration.mangle()
+ * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv"
+ * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv"
+ *
+ * If a function has no overloads, .mangleof property still returns exact mangled name.
+ *
+ * void bar() {}
+ * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv"
+ * // by calling FuncDeclaration.mangleExact().
+ */
+ override void visit(FuncDeclaration fd)
+ {
+ if (fd.isUnique())
+ mangleExact(fd);
+ else
+ visit(cast(Dsymbol)fd);
+ }
+
+ // ditto
+ override void visit(FuncAliasDeclaration fd)
+ {
+ FuncDeclaration f = fd.toAliasFunc();
+ FuncAliasDeclaration fa = f.isFuncAliasDeclaration();
+ if (!fd.hasOverloads && !fa)
+ {
+ mangleExact(f);
+ return;
+ }
+ if (fa)
+ {
+ mangleSymbol(fa);
+ return;
+ }
+ visit(cast(Dsymbol)fd);
+ }
+
+ override void visit(OverDeclaration od)
+ {
+ if (od.overnext)
+ {
+ visit(cast(Dsymbol)od);
+ return;
+ }
+ if (FuncDeclaration fd = od.aliassym.isFuncDeclaration())
+ {
+ if (fd.isUnique())
+ {
+ mangleExact(fd);
+ return;
+ }
+ }
+ if (TemplateDeclaration td = od.aliassym.isTemplateDeclaration())
+ {
+ if (td.overnext is null)
+ {
+ mangleSymbol(td);
+ return;
+ }
+ }
+ visit(cast(Dsymbol)od);
+ }
+
+ void mangleExact(FuncDeclaration fd)
+ {
+ assert(!fd.isFuncAliasDeclaration());
+ if (fd.mangleOverride)
+ {
+ buf.writestring(fd.mangleOverride);
+ return;
+ }
+ if (fd.isMain())
+ {
+ buf.writestring("_Dmain");
+ return;
+ }
+ if (fd.isWinMain() || fd.isDllMain())
+ {
+ buf.writestring(fd.ident.toString());
+ return;
+ }
+ visit(cast(Declaration)fd);
+ }
+
+ override void visit(VarDeclaration vd)
+ {
+ if (vd.mangleOverride)
+ {
+ buf.writestring(vd.mangleOverride);
+ return;
+ }
+ visit(cast(Declaration)vd);
+ }
+
+ override void visit(AggregateDeclaration ad)
+ {
+ ClassDeclaration cd = ad.isClassDeclaration();
+ Dsymbol parentsave = ad.parent;
+ if (cd)
+ {
+ /* These are reserved to the compiler, so keep simple
+ * names for them.
+ */
+ if (cd.ident == Id.Exception && cd.parent.ident == Id.object || cd.ident == Id.TypeInfo || cd.ident == Id.TypeInfo_Struct || cd.ident == Id.TypeInfo_Class || cd.ident == Id.TypeInfo_Tuple || cd == ClassDeclaration.object || cd == Type.typeinfoclass || cd == Module.moduleinfo || strncmp(cd.ident.toChars(), "TypeInfo_", 9) == 0)
+ {
+ // Don't mangle parent
+ ad.parent = null;
+ }
+ }
+ visit(cast(Dsymbol)ad);
+ ad.parent = parentsave;
+ }
+
+ override void visit(TemplateInstance ti)
+ {
+ version (none)
+ {
+ printf("TemplateInstance.mangle() %p %s", ti, ti.toChars());
+ if (ti.parent)
+ printf(" parent = %s %s", ti.parent.kind(), ti.parent.toChars());
+ printf("\n");
+ }
+ if (!ti.tempdecl)
+ ti.error("is not defined");
+ else
+ mangleParent(ti);
+
+ if (ti.isTemplateMixin() && ti.ident)
+ mangleIdentifier(ti.ident, ti);
+ else
+ mangleTemplateInstance(ti);
+ }
+
+ void mangleTemplateInstance(TemplateInstance ti)
+ {
+ TemplateDeclaration tempdecl = ti.tempdecl.isTemplateDeclaration();
+ assert(tempdecl);
+
+ // Use "__U" for the symbols declared inside template constraint.
+ const char T = ti.members ? 'T' : 'U';
+ buf.printf("__%c", T);
+ mangleIdentifier(tempdecl.ident, tempdecl);
+
+ auto args = ti.tiargs;
+ size_t nparams = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0);
+ for (size_t i = 0; i < args.dim; i++)
+ {
+ auto o = (*args)[i];
+ Type ta = isType(o);
+ Expression ea = isExpression(o);
+ Dsymbol sa = isDsymbol(o);
+ Tuple va = isTuple(o);
+ //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
+ if (i < nparams && (*tempdecl.parameters)[i].specialization())
+ buf.writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574
+ if (ta)
+ {
+ buf.writeByte('T');
+ visitWithMask(ta, 0);
+ }
+ else if (ea)
+ {
+ // Don't interpret it yet, it might actually be an alias template parameter.
+ // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
+ enum keepLvalue = true;
+ ea = ea.optimize(WANTvalue, keepLvalue);
+ if (auto ev = ea.isVarExp())
+ {
+ sa = ev.var;
+ ea = null;
+ goto Lsa;
+ }
+ if (auto et = ea.isThisExp())
+ {
+ sa = et.var;
+ ea = null;
+ goto Lsa;
+ }
+ if (auto ef = ea.isFuncExp())
+ {
+ if (ef.td)
+ sa = ef.td;
+ else
+ sa = ef.fd;
+ ea = null;
+ goto Lsa;
+ }
+ buf.writeByte('V');
+ if (ea.op == TOK.tuple)
+ {
+ ea.error("tuple is not a valid template value argument");
+ continue;
+ }
+ // Now that we know it is not an alias, we MUST obtain a value
+ uint olderr = global.errors;
+ ea = ea.ctfeInterpret();
+ if (ea.op == TOK.error || olderr != global.errors)
+ continue;
+
+ /* Use type mangling that matches what it would be for a function parameter
+ */
+ visitWithMask(ea.type, 0);
+ ea.accept(this);
+ }
+ else if (sa)
+ {
+ Lsa:
+ sa = sa.toAlias();
+ if (sa.isDeclaration() && !sa.isOverDeclaration())
+ {
+ Declaration d = sa.isDeclaration();
+
+ if (auto fad = d.isFuncAliasDeclaration())
+ d = fad.toAliasFunc();
+ if (d.mangleOverride)
+ {
+ buf.writeByte('X');
+ toBuffer(d.mangleOverride, d);
+ continue;
+ }
+ if (const id = externallyMangledIdentifier(d))
+ {
+ buf.writeByte('X');
+ toBuffer(id, d);
+ continue;
+ }
+ if (!d.type || !d.type.deco)
+ {
+ ti.error("forward reference of %s `%s`", d.kind(), d.toChars());
+ continue;
+ }
+ }
+ buf.writeByte('S');
+ mangleSymbol(sa);
+ }
+ else if (va)
+ {
+ assert(i + 1 == args.dim); // must be last one
+ args = &va.objects;
+ i = -cast(size_t)1;
+ }
+ else
+ assert(0);
+ }
+ buf.writeByte('Z');
+ }
+
+ override void visit(Dsymbol s)
+ {
+ version (none)
+ {
+ printf("Dsymbol.mangle() '%s'", s.toChars());
+ if (s.parent)
+ printf(" parent = %s %s", s.parent.kind(), s.parent.toChars());
+ printf("\n");
+ }
+ mangleParent(s);
+ if (s.ident)
+ mangleIdentifier(s.ident, s);
+ else
+ toBuffer(s.toString(), s);
+ //printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ override void visit(Expression e)
+ {
+ e.error("expression `%s` is not a valid template value argument", e.toChars());
+ }
+
+ override void visit(IntegerExp e)
+ {
+ const v = e.toInteger();
+ if (cast(sinteger_t)v < 0)
+ {
+ buf.writeByte('N');
+ buf.print(-v);
+ }
+ else
+ {
+ buf.writeByte('i');
+ buf.print(v);
+ }
+ }
+
+ override void visit(RealExp e)
+ {
+ buf.writeByte('e');
+ realToMangleBuffer(e.value);
+ }
+
+ void realToMangleBuffer(real_t value)
+ {
+ /* Rely on %A to get portable mangling.
+ * Must munge result to get only identifier characters.
+ *
+ * Possible values from %A => mangled result
+ * NAN => NAN
+ * -INF => NINF
+ * INF => INF
+ * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
+ * 0X1.9P+2 => 19P2
+ */
+ if (CTFloat.isNaN(value))
+ {
+ buf.writestring("NAN"); // no -NAN bugs
+ return;
+ }
+
+ if (value < CTFloat.zero)
+ {
+ buf.writeByte('N');
+ value = -value;
+ }
+
+ if (CTFloat.isInfinity(value))
+ {
+ buf.writestring("INF");
+ return;
+ }
+
+ char[36] buffer = void;
+ // 'A' format yields [-]0xh.hhhhp+-d
+ const n = CTFloat.sprint(buffer.ptr, 'A', value);
+ assert(n < buffer.length);
+ foreach (const c; buffer[2 .. n])
+ {
+ switch (c)
+ {
+ case '-':
+ buf.writeByte('N');
+ break;
+
+ case '+':
+ case '.':
+ break;
+
+ default:
+ buf.writeByte(c);
+ break;
+ }
+ }
+ }
+
+ override void visit(ComplexExp e)
+ {
+ buf.writeByte('c');
+ realToMangleBuffer(e.toReal());
+ buf.writeByte('c'); // separate the two
+ realToMangleBuffer(e.toImaginary());
+ }
+
+ override void visit(NullExp e)
+ {
+ buf.writeByte('n');
+ }
+
+ override void visit(StringExp e)
+ {
+ char m;
+ OutBuffer tmp;
+ const(char)[] q;
+ /* Write string in UTF-8 format
+ */
+ switch (e.sz)
+ {
+ case 1:
+ m = 'a';
+ q = e.peekString();
+ break;
+ case 2:
+ {
+ m = 'w';
+ const slice = e.peekWstring();
+ for (size_t u = 0; u < e.len;)
+ {
+ dchar c;
+ if (const s = utf_decodeWchar(slice, u, c))
+ e.error("%.*s", cast(int)s.length, s.ptr);
+ else
+ tmp.writeUTF8(c);
+ }
+ q = tmp[];
+ break;
+ }
+ case 4:
+ {
+ m = 'd';
+ const slice = e.peekDstring();
+ foreach (c; slice)
+ {
+ if (!utf_isValidDchar(c))
+ e.error("invalid UCS-32 char \\U%08x", c);
+ else
+ tmp.writeUTF8(c);
+ }
+ q = tmp[];
+ break;
+ }
+
+ default:
+ assert(0);
+ }
+ buf.reserve(1 + 11 + 2 * q.length);
+ buf.writeByte(m);
+ buf.print(q.length);
+ buf.writeByte('_'); // nbytes <= 11
+ auto slice = buf.allocate(2 * q.length);
+ foreach (i, c; q)
+ {
+ char hi = (c >> 4) & 0xF;
+ slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a');
+ char lo = c & 0xF;
+ slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a');
+ }
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ const dim = e.elements ? e.elements.dim : 0;
+ buf.writeByte('A');
+ buf.print(dim);
+ foreach (i; 0 .. dim)
+ {
+ e[i].accept(this);
+ }
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ const dim = e.keys.dim;
+ buf.writeByte('A');
+ buf.print(dim);
+ foreach (i; 0 .. dim)
+ {
+ (*e.keys)[i].accept(this);
+ (*e.values)[i].accept(this);
+ }
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ const dim = e.elements ? e.elements.dim : 0;
+ buf.writeByte('S');
+ buf.print(dim);
+ foreach (i; 0 .. dim)
+ {
+ Expression ex = (*e.elements)[i];
+ if (ex)
+ ex.accept(this);
+ else
+ buf.writeByte('v'); // 'v' for void
+ }
+ }
+
+ override void visit(FuncExp e)
+ {
+ buf.writeByte('f');
+ if (e.td)
+ mangleSymbol(e.td);
+ else
+ mangleSymbol(e.fd);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ override void visit(Parameter p)
+ {
+ if (p.storageClass & STC.scope_ && !(p.storageClass & STC.scopeinferred))
+ buf.writeByte('M');
+
+ // 'return inout ref' is the same as 'inout ref'
+ if ((p.storageClass & (STC.return_ | STC.wild)) == STC.return_ &&
+ !(p.storageClass & STC.returninferred))
+ buf.writestring("Nk");
+ switch (p.storageClass & (STC.IOR | STC.lazy_))
+ {
+ case 0:
+ break;
+ case STC.in_:
+ buf.writeByte('I');
+ break;
+ case STC.in_ | STC.ref_:
+ buf.writestring("IK");
+ break;
+ case STC.out_:
+ buf.writeByte('J');
+ break;
+ case STC.ref_:
+ buf.writeByte('K');
+ break;
+ case STC.lazy_:
+ buf.writeByte('L');
+ break;
+ default:
+ debug
+ {
+ printf("storageClass = x%llx\n", p.storageClass & (STC.IOR | STC.lazy_));
+ }
+ assert(0);
+ }
+ visitWithMask(p.type, (p.storageClass & STC.in_) ? MODFlags.const_ : 0);
+ }
+}
diff --git a/gcc/d/dmd/dmodule.c b/gcc/d/dmd/dmodule.c
deleted file mode 100644
index 472b2b9..0000000
--- a/gcc/d/dmd/dmodule.c
+++ /dev/null
@@ -1,1276 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/module.c
- */
-
-#include "root/dsystem.h"
-#include "root/rmem.h"
-
-#include "mars.h"
-#include "module.h"
-#include "parse.h"
-#include "scope.h"
-#include "identifier.h"
-#include "id.h"
-#include "import.h"
-#include "dsymbol.h"
-#include "expression.h"
-#include "lexer.h"
-#include "attrib.h"
-
-AggregateDeclaration *Module::moduleinfo;
-
-Module *Module::rootModule;
-DsymbolTable *Module::modules;
-Modules Module::amodules;
-
-Dsymbols Module::deferred; // deferred Dsymbol's needing semantic() run on them
-Dsymbols Module::deferred2; // deferred Dsymbol's needing semantic2() run on them
-Dsymbols Module::deferred3; // deferred Dsymbol's needing semantic3() run on them
-unsigned Module::dprogress;
-
-void Module::_init()
-{
- modules = new DsymbolTable();
-}
-
-Module::Module(const char *filename, Identifier *ident, int doDocComment, int doHdrGen)
- : Package(ident)
-{
- const char *srcfilename;
-
-// printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars());
- this->arg = filename;
- md = NULL;
- errors = 0;
- numlines = 0;
- members = NULL;
- isDocFile = 0;
- isPackageFile = false;
- pkg = NULL;
- needmoduleinfo = 0;
- selfimports = 0;
- rootimports = 0;
- insearch = 0;
- searchCacheIdent = NULL;
- searchCacheSymbol = NULL;
- searchCacheFlags = 0;
- decldefs = NULL;
- sictor = NULL;
- sctor = NULL;
- sdtor = NULL;
- ssharedctor = NULL;
- sshareddtor = NULL;
- stest = NULL;
- sfilename = NULL;
- importedFrom = NULL;
- srcfile = NULL;
- docfile = NULL;
-
- debuglevel = 0;
- debugids = NULL;
- debugidsNot = NULL;
- versionlevel = 0;
- versionids = NULL;
- versionidsNot = NULL;
-
- macrotable = NULL;
- escapetable = NULL;
- doppelganger = 0;
- cov = NULL;
- covb = NULL;
-
- nameoffset = 0;
- namelen = 0;
-
- srcfilename = FileName::defaultExt(filename, global.mars_ext.ptr);
-
- if (global.run_noext && global.params.run &&
- !FileName::ext(filename) &&
- FileName::exists(srcfilename) == 0 &&
- FileName::exists(filename) == 1)
- {
- FileName::free(srcfilename);
- srcfilename = FileName::removeExt(filename); // just does a mem.strdup(filename)
- }
- else if (!FileName::equalsExt(srcfilename, global.mars_ext.ptr) &&
- !FileName::equalsExt(srcfilename, global.hdr_ext.ptr) &&
- !FileName::equalsExt(srcfilename, "dd"))
- {
- error("source file name '%s' must have .%s extension", srcfilename, global.mars_ext);
- fatal();
- }
- srcfile = new File(srcfilename);
- objfile = setOutfile(global.params.objname.ptr, global.params.objdir.ptr, filename, global.obj_ext.ptr);
-
- if (doDocComment)
- setDocfile();
-
- if (doHdrGen)
- hdrfile = setOutfile(global.params.hdrname.ptr, global.params.hdrdir.ptr, arg, global.hdr_ext.ptr);
-
- //objfile = new File(objfilename);
-}
-
-Module *Module::create(const char *filename, Identifier *ident, int doDocComment, int doHdrGen)
-{
- return new Module(filename, ident, doDocComment, doHdrGen);
-}
-
-void Module::setDocfile()
-{
- docfile = setOutfile(global.params.docname.ptr, global.params.docdir.ptr, arg, global.doc_ext.ptr);
-}
-
-/*********************************************
- * Combines things into output file name for .html and .di files.
- * Input:
- * name Command line name given for the file, NULL if none
- * dir Command line directory given for the file, NULL if none
- * arg Name of the source file
- * ext File name extension to use if 'name' is NULL
- * global.params.preservePaths get output path from arg
- * srcfile Input file - output file name must not match input file
- */
-
-File *Module::setOutfile(const char *name, const char *dir, const char *arg, const char *ext)
-{
- const char *docfilename;
-
- if (name)
- {
- docfilename = name;
- }
- else
- {
- const char *argdoc;
- if (global.params.preservePaths)
- argdoc = arg;
- else
- argdoc = FileName::name(arg);
-
- // If argdoc doesn't have an absolute path, make it relative to dir
- if (!FileName::absolute(argdoc))
- { //FileName::ensurePathExists(dir);
- argdoc = FileName::combine(dir, argdoc);
- }
- docfilename = FileName::forceExt(argdoc, ext);
- }
-
- if (FileName::equals(docfilename, srcfile->name->str))
- {
- error("source file and output file have same name '%s'", srcfile->name->str);
- fatal();
- }
-
- return new File(docfilename);
-}
-
-void Module::deleteObjFile()
-{
- if (global.params.obj)
- objfile->remove();
- if (docfile)
- docfile->remove();
-}
-
-const char *Module::kind() const
-{
- return "module";
-}
-
-static void checkModFileAlias(OutBuffer *buf, OutBuffer *dotmods,
- Array<const char *> *ms, size_t msdim, const char *p)
-{
- /* Check and replace the contents of buf[] with
- * an alias string from global.params.modFileAliasStrings[]
- */
- dotmods->writestring(p);
- for (size_t j = msdim; j--;)
- {
- const char *m = (*ms)[j];
- const char *q = strchr(m, '=');
- assert(q);
- if (dotmods->length() == (size_t)(q - m) && memcmp(dotmods->peekChars(), m, q - m) == 0)
- {
- buf->reset();
- size_t qlen = strlen(q + 1);
- if (qlen && (q[qlen] == '/' || q[qlen] == '\\'))
- --qlen; // remove trailing separator
- buf->write(q + 1, qlen);
- break; // last matching entry in ms[] wins
- }
- }
- dotmods->writeByte('.');
-}
-
-/**
- * Converts a chain of identifiers to the filename of the module
- *
- * Params:
- * packages = the names of the "parent" packages
- * ident = the name of the child package or module
- *
- * Returns:
- * the filename of the child package or module
- */
-static const char *getFilename(Identifiers *packages, Identifier *ident)
-{
- const char *filename = ident->toChars();
-
- if (packages == NULL || packages->length == 0)
- return filename;
-
- OutBuffer buf;
- OutBuffer dotmods;
- Array<const char *> *ms = &global.params.modFileAliasStrings;
- const size_t msdim = ms ? ms->length : 0;
-
- for (size_t i = 0; i < packages->length; i++)
- {
- Identifier *pid = (*packages)[i];
- const char *p = pid->toChars();
- buf.writestring(p);
- if (msdim)
- checkModFileAlias(&buf, &dotmods, ms, msdim, p);
-#if _WIN32
- buf.writeByte('\\');
-#else
- buf.writeByte('/');
-#endif
- }
- buf.writestring(filename);
- if (msdim)
- checkModFileAlias(&buf, &dotmods, ms, msdim, filename);
- buf.writeByte(0);
- filename = (char *)buf.extractData();
-
- return filename;
-}
-
-/********************************************
- * Look for the source file if it's different from filename.
- * Look for .di, .d, directory, and along global.path.
- * Does not open the file.
- * Input:
- * filename as supplied by the user
- * global.path
- * Returns:
- * NULL if it's not different from filename.
- */
-
-static const char *lookForSourceFile(const char *filename)
-{
- /* Search along global.path for .di file, then .d file.
- */
- const char *sdi = FileName::forceExt(filename, global.hdr_ext.ptr);
- if (FileName::exists(sdi) == 1)
- return sdi;
-
- const char *sd = FileName::forceExt(filename, global.mars_ext.ptr);
- if (FileName::exists(sd) == 1)
- return sd;
-
- if (FileName::exists(filename) == 2)
- {
- /* The filename exists and it's a directory.
- * Therefore, the result should be: filename/package.d
- * iff filename/package.d is a file
- */
- const char *ni = FileName::combine(filename, "package.di");
- if (FileName::exists(ni) == 1)
- return ni;
- FileName::free(ni);
- const char *n = FileName::combine(filename, "package.d");
- if (FileName::exists(n) == 1)
- return n;
- FileName::free(n);
- }
-
- if (FileName::absolute(filename))
- return NULL;
-
- if (!global.path)
- return NULL;
-
- for (size_t i = 0; i < global.path->length; i++)
- {
- const char *p = (*global.path)[i];
- const char *n = FileName::combine(p, sdi);
- if (FileName::exists(n) == 1)
- {
- return n;
- }
- FileName::free(n);
-
- n = FileName::combine(p, sd);
- if (FileName::exists(n) == 1)
- {
- return n;
- }
- FileName::free(n);
-
- const char *b = FileName::removeExt(filename);
- n = FileName::combine(p, b);
- FileName::free(b);
- if (FileName::exists(n) == 2)
- {
- const char *n2i = FileName::combine(n, "package.di");
- if (FileName::exists(n2i) == 1)
- return n2i;
- FileName::free(n2i);
- const char *n2 = FileName::combine(n, "package.d");
- if (FileName::exists(n2) == 1)
- {
- return n2;
- }
- FileName::free(n2);
- }
- FileName::free(n);
- }
- return NULL;
-}
-
-Module *Module::load(Loc loc, Identifiers *packages, Identifier *ident)
-{
- //printf("Module::load(ident = '%s')\n", ident->toChars());
-
- // Build module filename by turning:
- // foo.bar.baz
- // into:
- // foo\bar\baz
- const char *filename = getFilename(packages, ident);
- // Look for the source file
- const char *result = lookForSourceFile(filename);
- if (result)
- filename = result;
-
- Module *m = new Module(filename, ident, 0, 0);
- m->loc = loc;
-
- if (!m->read(loc))
- return NULL;
-
- if (global.params.verbose)
- {
- OutBuffer buf;
- if (packages)
- {
- for (size_t i = 0; i < packages->length; i++)
- {
- Identifier *pid = (*packages)[i];
- buf.writestring(pid->toChars());
- buf.writeByte('.');
- }
- }
- buf.printf("%s\t(%s)", ident->toChars(), m->srcfile->toChars());
- message("import %s", buf.peekChars());
- }
-
- m = m->parse();
-
- // Call onImport here because if the module is going to be compiled then we
- // need to determine it early because it affects semantic analysis. This is
- // being done after parsing the module so the full module name can be taken
- // from whatever was declared in the file.
- if (!m->isRoot() && Compiler::onImport(m))
- {
- m->importedFrom = m;
- assert(m->isRoot());
- }
- return m;
-}
-
-bool Module::read(Loc loc)
-{
- //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars());
- if (srcfile->read())
- {
- if (!strcmp(srcfile->toChars(), "object.d"))
- {
- ::error(loc, "cannot find source code for runtime library file 'object.d'");
- errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions.");
- const char *dmdConfFile = global.inifilename.length ? FileName::canonicalName(global.inifilename.ptr) : NULL;
- errorSupplemental(loc, "config file: %s", dmdConfFile ? dmdConfFile : "not found");
- }
- else
- {
- // if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module
- bool isPackageMod = (strcmp(toChars(), "package") != 0) &&
- (strcmp(srcfile->name->name(), "package.d") == 0 || (strcmp(srcfile->name->name(), "package.di") == 0));
-
- if (isPackageMod)
- ::error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'",
- toChars(), srcfile->toChars());
- else
- error(loc, "is in file '%s' which cannot be read", srcfile->toChars());
- }
-
- if (!global.gag)
- {
- /* Print path
- */
- if (global.path)
- {
- for (size_t i = 0; i < global.path->length; i++)
- {
- const char *p = (*global.path)[i];
- fprintf(stderr, "import path[%llu] = %s\n", (ulonglong)i, p);
- }
- }
- else
- fprintf(stderr, "Specify path to file '%s' with -I switch\n", srcfile->toChars());
- fatal();
- }
- return false;
- }
- return true;
-}
-
-Module *Module::parse()
-{
- //printf("Module::parse(srcfile='%s') this=%p\n", srcfile->name->toChars(), this);
-
- const char *srcname = srcfile->name->toChars();
- //printf("Module::parse(srcname = '%s')\n", srcname);
-
- isPackageFile = (strcmp(srcfile->name->name(), "package.d") == 0 ||
- strcmp(srcfile->name->name(), "package.di") == 0);
-
- utf8_t *buf = (utf8_t *)srcfile->buffer;
- size_t buflen = srcfile->len;
-
- if (buflen >= 2)
- {
- /* Convert all non-UTF-8 formats to UTF-8.
- * BOM : http://www.unicode.org/faq/utf_bom.html
- * 00 00 FE FF UTF-32BE, big-endian
- * FF FE 00 00 UTF-32LE, little-endian
- * FE FF UTF-16BE, big-endian
- * FF FE UTF-16LE, little-endian
- * EF BB BF UTF-8
- */
-
- unsigned le;
- unsigned bom = 1; // assume there's a BOM
- if (buf[0] == 0xFF && buf[1] == 0xFE)
- {
- if (buflen >= 4 && buf[2] == 0 && buf[3] == 0)
- { // UTF-32LE
- le = 1;
-
- Lutf32:
- OutBuffer dbuf;
- unsigned *pu = (unsigned *)(buf);
- unsigned *pumax = &pu[buflen / 4];
-
- if (buflen & 3)
- { error("odd length of UTF-32 char source %u", buflen);
- fatal();
- }
-
- dbuf.reserve(buflen / 4);
- for (pu += bom; pu < pumax; pu++)
- { unsigned u;
-
- u = le ? Port::readlongLE(pu) : Port::readlongBE(pu);
- if (u & ~0x7F)
- {
- if (u > 0x10FFFF)
- { error("UTF-32 value %08x greater than 0x10FFFF", u);
- fatal();
- }
- dbuf.writeUTF8(u);
- }
- else
- dbuf.writeByte(u);
- }
- dbuf.writeByte(0); // add 0 as sentinel for scanner
- buflen = dbuf.length() - 1; // don't include sentinel in count
- buf = (utf8_t *) dbuf.extractData();
- }
- else
- { // UTF-16LE (X86)
- // Convert it to UTF-8
- le = 1;
-
- Lutf16:
- OutBuffer dbuf;
- unsigned short *pu = (unsigned short *)(buf);
- unsigned short *pumax = &pu[buflen / 2];
-
- if (buflen & 1)
- { error("odd length of UTF-16 char source %u", buflen);
- fatal();
- }
-
- dbuf.reserve(buflen / 2);
- for (pu += bom; pu < pumax; pu++)
- { unsigned u;
-
- u = le ? Port::readwordLE(pu) : Port::readwordBE(pu);
- if (u & ~0x7F)
- { if (u >= 0xD800 && u <= 0xDBFF)
- { unsigned u2;
-
- if (++pu > pumax)
- { error("surrogate UTF-16 high value %04x at EOF", u);
- fatal();
- }
- u2 = le ? Port::readwordLE(pu) : Port::readwordBE(pu);
- if (u2 < 0xDC00 || u2 > 0xDFFF)
- { error("surrogate UTF-16 low value %04x out of range", u2);
- fatal();
- }
- u = (u - 0xD7C0) << 10;
- u |= (u2 - 0xDC00);
- }
- else if (u >= 0xDC00 && u <= 0xDFFF)
- { error("unpaired surrogate UTF-16 value %04x", u);
- fatal();
- }
- else if (u == 0xFFFE || u == 0xFFFF)
- { error("illegal UTF-16 value %04x", u);
- fatal();
- }
- dbuf.writeUTF8(u);
- }
- else
- dbuf.writeByte(u);
- }
- dbuf.writeByte(0); // add 0 as sentinel for scanner
- buflen = dbuf.length() - 1; // don't include sentinel in count
- buf = (utf8_t *) dbuf.extractData();
- }
- }
- else if (buf[0] == 0xFE && buf[1] == 0xFF)
- { // UTF-16BE
- le = 0;
- goto Lutf16;
- }
- else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF)
- { // UTF-32BE
- le = 0;
- goto Lutf32;
- }
- else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
- { // UTF-8
-
- buf += 3;
- buflen -= 3;
- }
- else
- {
- /* There is no BOM. Make use of Arcane Jill's insight that
- * the first char of D source must be ASCII to
- * figure out the encoding.
- */
-
- bom = 0;
- if (buflen >= 4)
- { if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
- { // UTF-32LE
- le = 1;
- goto Lutf32;
- }
- else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0)
- { // UTF-32BE
- le = 0;
- goto Lutf32;
- }
- }
- if (buflen >= 2)
- {
- if (buf[1] == 0)
- { // UTF-16LE
- le = 1;
- goto Lutf16;
- }
- else if (buf[0] == 0)
- { // UTF-16BE
- le = 0;
- goto Lutf16;
- }
- }
-
- // It's UTF-8
- if (buf[0] >= 0x80)
- { error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]);
- fatal();
- }
- }
- }
-
- /* If it starts with the string "Ddoc", then it's a documentation
- * source file.
- */
- if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0)
- {
- comment = buf + 4;
- isDocFile = 1;
- if (!docfile)
- setDocfile();
- return this;
- }
- {
- Parser p(this, buf, buflen, docfile != NULL);
- p.nextToken();
- members = p.parseModule();
- md = p.md;
- numlines = p.scanloc.linnum;
- if (p.errors)
- ++global.errors;
- }
-
- if (srcfile->ref == 0)
- ::free(srcfile->buffer);
- srcfile->buffer = NULL;
- srcfile->len = 0;
-
- /* The symbol table into which the module is to be inserted.
- */
- DsymbolTable *dst;
-
- if (md)
- {
- /* A ModuleDeclaration, md, was provided.
- * The ModuleDeclaration sets the packages this module appears in, and
- * the name of this module.
- */
- this->ident = md->id;
- Package *ppack = NULL;
- dst = Package::resolve(md->packages, &this->parent, &ppack);
- assert(dst);
-
- Module *m = ppack ? ppack->isModule() : NULL;
- if (m && (strcmp(m->srcfile->name->name(), "package.d") != 0 &&
- strcmp(m->srcfile->name->name(), "package.di") != 0))
- {
- ::error(md->loc, "package name '%s' conflicts with usage as a module name in file %s",
- ppack->toPrettyChars(), m->srcfile->toChars());
- }
- }
- else
- {
- /* The name of the module is set to the source file name.
- * There are no packages.
- */
- dst = modules; // and so this module goes into global module symbol table
-
- /* Check to see if module name is a valid identifier
- */
- if (!Identifier::isValidIdentifier(this->ident->toChars()))
- error("has non-identifier characters in filename, use module declaration instead");
- }
-
- // Insert module into the symbol table
- Dsymbol *s = this;
- if (isPackageFile)
- {
- /* If the source tree is as follows:
- * pkg/
- * +- package.d
- * +- common.d
- * the 'pkg' will be incorporated to the internal package tree in two ways:
- * import pkg;
- * and:
- * import pkg.common;
- *
- * If both are used in one compilation, 'pkg' as a module (== pkg/package.d)
- * and a package name 'pkg' will conflict each other.
- *
- * To avoid the conflict:
- * 1. If preceding package name insertion had occurred by Package::resolve,
- * reuse the previous wrapping 'Package' if it exists
- * 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here.
- *
- * Then change Package::isPkgMod to PKGmodule and set Package::mod.
- *
- * Note that the 'wrapping Package' is the Package that contains package.d and other submodules,
- * the one inserted to the symbol table.
- */
- Dsymbol *ps = dst->lookup(ident);
- Package *p = ps ? ps->isPackage() : NULL;
- if (p == NULL)
- {
- p = new Package(ident);
- p->tag = this->tag; // reuse the same package tag
- p->symtab = new DsymbolTable();
- }
- this->tag= p->tag; // reuse the 'older' package tag
- this->pkg = p;
- p->parent = this->parent;
- p->isPkgMod = PKGmodule;
- p->mod = this;
- s = p;
- }
- if (!dst->insert(s))
- {
- /* It conflicts with a name that is already in the symbol table.
- * Figure out what went wrong, and issue error message.
- */
- Dsymbol *prev = dst->lookup(ident);
- assert(prev);
- if (Module *mprev = prev->isModule())
- {
- if (FileName::compare(srcname, mprev->srcfile->toChars()) != 0)
- error(loc, "from file %s conflicts with another module %s from file %s",
- srcname, mprev->toChars(), mprev->srcfile->toChars());
- else if (isRoot() && mprev->isRoot())
- error(loc, "from file %s is specified twice on the command line",
- srcname);
- else
- error(loc, "from file %s must be imported with 'import %s;'",
- srcname, toPrettyChars());
-
- // Bugzilla 14446: Return previously parsed module to avoid AST duplication ICE.
- return mprev;
- }
- else if (Package *pkg = prev->isPackage())
- {
- // 'package.d' loaded after a previous 'Package' insertion
- if (isPackageFile)
- amodules.push(this); // Add to global array of all modules
- else
- error(md ? md->loc : loc, "from file %s conflicts with package name %s",
- srcname, pkg->toChars());
- }
- else
- assert(global.errors);
- }
- else
- {
- // Add to global array of all modules
- amodules.push(this);
- }
- Compiler::onParseModule(this);
- return this;
-}
-
-void Module::importAll(Scope *)
-{
- //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
-
- if (_scope)
- return; // already done
-
- if (isDocFile)
- {
- error("is a Ddoc file, cannot import it");
- return;
- }
-
- /* Note that modules get their own scope, from scratch.
- * This is so regardless of where in the syntax a module
- * gets imported, it is unaffected by context.
- * Ignore prevsc.
- */
- Scope *sc = Scope::createGlobal(this); // create root scope
-
- if (md && md->msg)
- md->msg = semanticString(sc, md->msg, "deprecation message");
-
- // Add import of "object", even for the "object" module.
- // If it isn't there, some compiler rewrites, like
- // classinst == classinst -> .object.opEquals(classinst, classinst)
- // would fail inside object.d.
- if (members->length == 0 || ((*members)[0])->ident != Id::object ||
- (*members)[0]->isImport() == NULL)
- {
- Import *im = new Import(Loc(), NULL, Id::object, NULL, 0);
- members->shift(im);
- }
-
- if (!symtab)
- {
- // Add all symbols into module's symbol table
- symtab = new DsymbolTable();
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->addMember(sc, sc->scopesym);
- }
- }
- // anything else should be run after addMember, so version/debug symbols are defined
-
- /* Set scope for the symbols so that if we forward reference
- * a symbol, it can possibly be resolved on the spot.
- * If this works out well, it can be extended to all modules
- * before any semantic() on any of them.
- */
- setScope(sc); // remember module scope for semantic
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->setScope(sc);
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->importAll(sc);
- }
-
- sc = sc->pop();
- sc->pop(); // 2 pops because Scope::createGlobal() created 2
-}
-
-/**********************************
- * Determine if we need to generate an instance of ModuleInfo
- * for this Module.
- */
-
-int Module::needModuleInfo()
-{
- //printf("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov);
- return needmoduleinfo || global.params.cov;
-}
-
-Dsymbol *Module::search(const Loc &loc, Identifier *ident, int flags)
-{
- /* Since modules can be circularly referenced,
- * need to stop infinite recursive searches.
- * This is done with the cache.
- */
-
- //printf("%s Module::search('%s', flags = x%x) insearch = %d\n", toChars(), ident->toChars(), flags, insearch);
- if (insearch)
- return NULL;
-
- /* Qualified module searches always search their imports,
- * even if SearchLocalsOnly
- */
- if (!(flags & SearchUnqualifiedModule))
- flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly);
-
- if (searchCacheIdent == ident && searchCacheFlags == flags)
- {
- //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n",
- // toChars(), ident->toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol->toChars() : "null");
- return searchCacheSymbol;
- }
-
- unsigned int errors = global.errors;
-
- insearch = 1;
- Dsymbol *s = ScopeDsymbol::search(loc, ident, flags);
- insearch = 0;
-
- if (errors == global.errors)
- {
- // Bugzilla 10752: We can cache the result only when it does not cause
- // access error so the side-effect should be reproduced in later search.
- searchCacheIdent = ident;
- searchCacheSymbol = s;
- searchCacheFlags = flags;
- }
- return s;
-}
-
-bool Module::isPackageAccessible(Package *p, Prot protection, int flags)
-{
- if (insearch) // don't follow import cycles
- return false;
- if (flags & IgnorePrivateImports)
- protection = Prot(Prot::public_); // only consider public imports
- insearch = true;
- bool r = ScopeDsymbol::isPackageAccessible(p, protection);
- insearch = false;
- return r;
-}
-
-Dsymbol *Module::symtabInsert(Dsymbol *s)
-{
- searchCacheIdent = NULL; // symbol is inserted, so invalidate cache
- return Package::symtabInsert(s);
-}
-
-void Module::clearCache()
-{
- for (size_t i = 0; i < amodules.length; i++)
- {
- Module *m = amodules[i];
- m->searchCacheIdent = NULL;
- }
-}
-
-/*******************************************
- * Can't run semantic on s now, try again later.
- */
-
-void Module::addDeferredSemantic(Dsymbol *s)
-{
- // Don't add it if it is already there
- for (size_t i = 0; i < deferred.length; i++)
- {
- Dsymbol *sd = deferred[i];
-
- if (sd == s)
- return;
- }
-
- //printf("Module::addDeferredSemantic('%s')\n", s->toChars());
- deferred.push(s);
-}
-
-void Module::addDeferredSemantic2(Dsymbol *s)
-{
- //printf("Module::addDeferredSemantic2('%s')\n", s->toChars());
- deferred2.push(s);
-}
-
-void Module::addDeferredSemantic3(Dsymbol *s)
-{
- //printf("Module::addDeferredSemantic3('%s')\n", s->toChars());
- deferred3.push(s);
-}
-
-/******************************************
- * Run semantic() on deferred symbols.
- */
-
-void Module::runDeferredSemantic()
-{
- if (dprogress == 0)
- return;
-
- static int nested;
- if (nested)
- return;
- //if (deferred.length) printf("+Module::runDeferredSemantic(), len = %d\n", deferred.length);
- nested++;
-
- size_t len;
- do
- {
- dprogress = 0;
- len = deferred.length;
- if (!len)
- break;
-
- Dsymbol **todo;
- Dsymbol **todoalloc = NULL;
- Dsymbol *tmp;
- if (len == 1)
- {
- todo = &tmp;
- }
- else
- {
- todo = (Dsymbol **)mem.xmalloc(len * sizeof(Dsymbol *));
- todoalloc = todo;
- }
- memcpy(todo, deferred.tdata(), len * sizeof(Dsymbol *));
- deferred.setDim(0);
-
- for (size_t i = 0; i < len; i++)
- {
- Dsymbol *s = todo[i];
-
- dsymbolSemantic(s, NULL);
- //printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars());
- }
- //printf("\tdeferred.length = %d, len = %d, dprogress = %d\n", deferred.length, len, dprogress);
- if (todoalloc)
- free(todoalloc);
- } while (deferred.length < len || dprogress); // while making progress
- nested--;
- //printf("-Module::runDeferredSemantic(), len = %d\n", deferred.length);
-}
-
-void Module::runDeferredSemantic2()
-{
- Module::runDeferredSemantic();
-
- Dsymbols *a = &Module::deferred2;
- for (size_t i = 0; i < a->length; i++)
- {
- Dsymbol *s = (*a)[i];
- //printf("[%d] %s semantic2a\n", i, s->toPrettyChars());
- semantic2(s, NULL);
-
- if (global.errors)
- break;
- }
- a->setDim(0);
-}
-
-void Module::runDeferredSemantic3()
-{
- Module::runDeferredSemantic2();
-
- Dsymbols *a = &Module::deferred3;
- for (size_t i = 0; i < a->length; i++)
- {
- Dsymbol *s = (*a)[i];
- //printf("[%d] %s semantic3a\n", i, s->toPrettyChars());
-
- semantic3(s, NULL);
-
- if (global.errors)
- break;
- }
- a->setDim(0);
-}
-
-/************************************
- * Recursively look at every module this module imports,
- * return true if it imports m.
- * Can be used to detect circular imports.
- */
-
-int Module::imports(Module *m)
-{
- //printf("%s Module::imports(%s)\n", toChars(), m->toChars());
- for (size_t i = 0; i < aimports.length; i++)
- {
- Module *mi = aimports[i];
- if (mi == m)
- return true;
- if (!mi->insearch)
- {
- mi->insearch = 1;
- int r = mi->imports(m);
- if (r)
- return r;
- }
- }
- return false;
-}
-
-/*************************************
- * Return true if module imports itself.
- */
-
-bool Module::selfImports()
-{
- //printf("Module::selfImports() %s\n", toChars());
- if (selfimports == 0)
- {
- for (size_t i = 0; i < amodules.length; i++)
- amodules[i]->insearch = 0;
-
- selfimports = imports(this) + 1;
-
- for (size_t i = 0; i < amodules.length; i++)
- amodules[i]->insearch = 0;
- }
- return selfimports == 2;
-}
-
-/*************************************
- * Return true if module imports root module.
- */
-
-bool Module::rootImports()
-{
- //printf("Module::rootImports() %s\n", toChars());
- if (rootimports == 0)
- {
- for (size_t i = 0; i < amodules.length; i++)
- amodules[i]->insearch = 0;
-
- rootimports = 1;
- for (size_t i = 0; i < amodules.length; ++i)
- {
- Module *m = amodules[i];
- if (m->isRoot() && imports(m))
- {
- rootimports = 2;
- break;
- }
- }
-
- for (size_t i = 0; i < amodules.length; i++)
- amodules[i]->insearch = 0;
- }
- return rootimports == 2;
-}
-
-bool Module::isCoreModule(Identifier *ident)
-{
- return this->ident == ident && parent && parent->ident == Id::core && !parent->parent;
-}
-
-/* =========================== ModuleDeclaration ===================== */
-
-ModuleDeclaration::ModuleDeclaration(Loc loc, Identifiers *packages, Identifier *id)
-{
- this->loc = loc;
- this->packages = packages;
- this->id = id;
- this->isdeprecated = false;
- this->msg = NULL;
-}
-
-const char *ModuleDeclaration::toChars()
-{
- OutBuffer buf;
-
- if (packages && packages->length)
- {
- for (size_t i = 0; i < packages->length; i++)
- {
- Identifier *pid = (*packages)[i];
- buf.writestring(pid->toChars());
- buf.writeByte('.');
- }
- }
- buf.writestring(id->toChars());
- return buf.extractChars();
-}
-
-/* =========================== Package ===================== */
-
-Package::Package(Identifier *ident)
- : ScopeDsymbol(ident)
-{
- this->isPkgMod = PKGunknown;
- this->mod = NULL;
- static unsigned packageTag = 0;
- this->tag = packageTag++;
-}
-
-
-const char *Package::kind() const
-{
- return "package";
-}
-
-Module *Package::isPackageMod()
-{
- if (isPkgMod == PKGmodule)
- {
- return mod;
- }
- return NULL;
-}
-
-/**
- * Checks for the existence of a package.d to set isPkgMod appropriately
- * if isPkgMod == PKGunknown
- */
-void Package::resolvePKGunknown()
-{
- if (isModule())
- return;
- if (isPkgMod != PKGunknown)
- return;
-
- Identifiers packages;
- for (Dsymbol *s = this->parent; s; s = s->parent)
- packages.insert(0, s->ident);
-
- if (lookForSourceFile(getFilename(&packages, ident)))
- Module::load(Loc(), &packages, this->ident);
- else
- isPkgMod = PKGpackage;
-}
-
-/**
- * Checks if pkg is a sub-package of this
- *
- * For example, if this qualifies to 'a1.a2' and pkg - to 'a1.a2.a3',
- * this function returns 'true'. If it is other way around or qualified
- * package paths conflict function returns 'false'.
- *
- * Params:
- * pkg = possible subpackage
- *
- * Returns:
- * see description
- */
-bool Package::isAncestorPackageOf(const Package * const pkg) const
-{
- if (this == pkg)
- return true;
- if (!pkg || !pkg->parent)
- return false;
- return isAncestorPackageOf(pkg->parent->isPackage());
-}
-
-/****************************************************
- * Input:
- * packages[] the pkg1.pkg2 of pkg1.pkg2.mod
- * Returns:
- * the symbol table that mod should be inserted into
- * Output:
- * *pparent the rightmost package, i.e. pkg2, or NULL if no packages
- * *ppkg the leftmost package, i.e. pkg1, or NULL if no packages
- */
-
-DsymbolTable *Package::resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg)
-{
- DsymbolTable *dst = Module::modules;
- Dsymbol *parent = NULL;
-
- //printf("Package::resolve()\n");
- if (ppkg)
- *ppkg = NULL;
-
- if (packages)
- {
- for (size_t i = 0; i < packages->length; i++)
- {
- Identifier *pid = (*packages)[i];
- Package *pkg;
- Dsymbol *p = dst->lookup(pid);
- if (!p)
- {
- pkg = new Package(pid);
- dst->insert(pkg);
- pkg->parent = parent;
- pkg->symtab = new DsymbolTable();
- }
- else
- {
- pkg = p->isPackage();
- assert(pkg);
- // It might already be a module, not a package, but that needs
- // to be checked at a higher level, where a nice error message
- // can be generated.
- // dot net needs modules and packages with same name
-
- // But we still need a symbol table for it
- if (!pkg->symtab)
- pkg->symtab = new DsymbolTable();
- }
- parent = pkg;
- dst = pkg->symtab;
- if (ppkg && !*ppkg)
- *ppkg = pkg;
- if (pkg->isModule())
- {
- // Return the module so that a nice error message can be generated
- if (ppkg)
- *ppkg = (Package *)p;
- break;
- }
- }
- }
- if (pparent)
- *pparent = parent;
- return dst;
-}
-
-Dsymbol *Package::search(const Loc &loc, Identifier *ident, int flags)
-{
- //printf("%s Package::search('%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
- flags &= ~SearchLocalsOnly; // searching an import is always transitive
- if (!isModule() && mod)
- {
- // Prefer full package name.
- Dsymbol *s = symtab ? symtab->lookup(ident) : NULL;
- if (s)
- return s;
- //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars());
- return mod->search(loc, ident, flags);
- }
-
- return ScopeDsymbol::search(loc, ident, flags);
-}
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
new file mode 100644
index 0000000..768eaa0
--- /dev/null
+++ b/gcc/d/dmd/dmodule.d
@@ -0,0 +1,1608 @@
+/**
+ * Defines a package and module.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/module.html, Modules)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmodule.d, _dmodule.d)
+ * Documentation: https://dlang.org/phobos/dmd_dmodule.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmodule.d
+ */
+
+module dmd.dmodule;
+
+import core.stdc.stdio;
+import core.stdc.stdlib;
+import core.stdc.string;
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astcodegen;
+import dmd.astenums;
+import dmd.compiler;
+import dmd.gluelayer;
+import dmd.dimport;
+import dmd.dmacro;
+import dmd.doc;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.parse;
+import dmd.cparse;
+import dmd.root.array;
+import dmd.root.file;
+import dmd.root.filename;
+import dmd.root.outbuffer;
+import dmd.root.port;
+import dmd.root.rmem;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.semantic2;
+import dmd.semantic3;
+import dmd.target;
+import dmd.utils;
+import dmd.visitor;
+
+enum package_d = "package." ~ mars_ext;
+enum package_di = "package." ~ hdr_ext;
+
+/********************************************
+ * Look for the source file if it's different from filename.
+ * Look for .di, .d, directory, and along global.path.
+ * Does not open the file.
+ * Params:
+ * filename = as supplied by the user
+ * path = path to look for filename
+ * Returns:
+ * the found file name or
+ * `null` if it is not different from filename.
+ */
+private const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
+{
+ //printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
+ /* Search along path[] for .di file, then .d file, then .i file, then .c file.
+ */
+ const sdi = FileName.forceExt(filename, hdr_ext);
+ if (FileName.exists(sdi) == 1)
+ return sdi;
+ scope(exit) FileName.free(sdi.ptr);
+
+ const sd = FileName.forceExt(filename, mars_ext);
+ if (FileName.exists(sd) == 1)
+ return sd;
+ scope(exit) FileName.free(sd.ptr);
+
+ const si = FileName.forceExt(filename, i_ext);
+ if (FileName.exists(si) == 1)
+ return si;
+ scope(exit) FileName.free(si.ptr);
+
+ const sc = FileName.forceExt(filename, c_ext);
+ if (FileName.exists(sc) == 1)
+ return sc;
+ scope(exit) FileName.free(sc.ptr);
+
+ if (FileName.exists(filename) == 2)
+ {
+ /* The filename exists and it's a directory.
+ * Therefore, the result should be: filename/package.d
+ * iff filename/package.d is a file
+ */
+ const ni = FileName.combine(filename, package_di);
+ if (FileName.exists(ni) == 1)
+ return ni;
+ FileName.free(ni.ptr);
+
+ const n = FileName.combine(filename, package_d);
+ if (FileName.exists(n) == 1)
+ return n;
+ FileName.free(n.ptr);
+ }
+ if (FileName.absolute(filename))
+ return null;
+ if (!path.length)
+ return null;
+ foreach (entry; path)
+ {
+ const p = entry.toDString();
+
+ const(char)[] n = FileName.combine(p, sdi);
+ if (FileName.exists(n) == 1) {
+ return n;
+ }
+ FileName.free(n.ptr);
+
+ n = FileName.combine(p, sd);
+ if (FileName.exists(n) == 1) {
+ return n;
+ }
+ FileName.free(n.ptr);
+
+ n = FileName.combine(p, si);
+ if (FileName.exists(n) == 1) {
+ return n;
+ }
+ FileName.free(n.ptr);
+
+ n = FileName.combine(p, sc);
+ if (FileName.exists(n) == 1) {
+ return n;
+ }
+ FileName.free(n.ptr);
+
+ const b = FileName.removeExt(filename);
+ n = FileName.combine(p, b);
+ FileName.free(b.ptr);
+ if (FileName.exists(n) == 2)
+ {
+ const n2i = FileName.combine(n, package_di);
+ if (FileName.exists(n2i) == 1)
+ return n2i;
+ FileName.free(n2i.ptr);
+ const n2 = FileName.combine(n, package_d);
+ if (FileName.exists(n2) == 1) {
+ return n2;
+ }
+ FileName.free(n2.ptr);
+ }
+ FileName.free(n.ptr);
+ }
+ return null;
+}
+
+// function used to call semantic3 on a module's dependencies
+void semantic3OnDependencies(Module m)
+{
+ if (!m)
+ return;
+
+ if (m.semanticRun > PASS.semantic3)
+ return;
+
+ m.semantic3(null);
+
+ foreach (i; 1 .. m.aimports.dim)
+ semantic3OnDependencies(m.aimports[i]);
+}
+
+/**
+ * Remove generated .di files on error and exit
+ */
+void removeHdrFilesAndFail(ref Param params, ref Modules modules)
+{
+ if (params.doHdrGeneration)
+ {
+ foreach (m; modules)
+ {
+ if (m.isHdrFile)
+ continue;
+ File.remove(m.hdrfile.toChars());
+ }
+ }
+
+ fatal();
+}
+
+/**
+ * Converts a chain of identifiers to the filename of the module
+ *
+ * Params:
+ * packages = the names of the "parent" packages
+ * ident = the name of the child package or module
+ *
+ * Returns:
+ * the filename of the child package or module
+ */
+private const(char)[] getFilename(Identifier[] packages, Identifier ident)
+{
+ const(char)[] filename = ident.toString();
+
+ if (packages.length == 0)
+ return filename;
+
+ OutBuffer buf;
+ OutBuffer dotmods;
+ auto modAliases = &global.params.modFileAliasStrings;
+
+ void checkModFileAlias(const(char)[] p)
+ {
+ /* Check and replace the contents of buf[] with
+ * an alias string from global.params.modFileAliasStrings[]
+ */
+ dotmods.writestring(p);
+ foreach_reverse (const m; *modAliases)
+ {
+ const q = strchr(m, '=');
+ assert(q);
+ if (dotmods.length == q - m && memcmp(dotmods.peekChars(), m, q - m) == 0)
+ {
+ buf.setsize(0);
+ auto rhs = q[1 .. strlen(q)];
+ if (rhs.length > 0 && (rhs[$ - 1] == '/' || rhs[$ - 1] == '\\'))
+ rhs = rhs[0 .. $ - 1]; // remove trailing separator
+ buf.writestring(rhs);
+ break; // last matching entry in ms[] wins
+ }
+ }
+ dotmods.writeByte('.');
+ }
+
+ foreach (pid; packages)
+ {
+ const p = pid.toString();
+ buf.writestring(p);
+ if (modAliases.dim)
+ checkModFileAlias(p);
+ version (Windows)
+ enum FileSeparator = '\\';
+ else
+ enum FileSeparator = '/';
+ buf.writeByte(FileSeparator);
+ }
+ buf.writestring(filename);
+ if (modAliases.dim)
+ checkModFileAlias(filename);
+ buf.writeByte(0);
+ filename = buf.extractSlice()[0 .. $ - 1];
+
+ return filename;
+}
+
+/***********************************************************
+ */
+extern (C++) class Package : ScopeDsymbol
+{
+ PKG isPkgMod = PKG.unknown;
+ uint tag; // auto incremented tag, used to mask package tree in scopes
+ Module mod; // !=null if isPkgMod == PKG.module_
+
+ final extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ super(loc, ident);
+ __gshared uint packageTag;
+ this.tag = packageTag++;
+ }
+
+ override const(char)* kind() const
+ {
+ return "package";
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ // custom 'equals' for bug 17441. "package a" and "module a" are not equal
+ if (this == o)
+ return true;
+ auto p = cast(Package)o;
+ return p && isModule() == p.isModule() && ident.equals(p.ident);
+ }
+
+ /****************************************************
+ * Input:
+ * packages[] the pkg1.pkg2 of pkg1.pkg2.mod
+ * Returns:
+ * the symbol table that mod should be inserted into
+ * Output:
+ * *pparent the rightmost package, i.e. pkg2, or NULL if no packages
+ * *ppkg the leftmost package, i.e. pkg1, or NULL if no packages
+ */
+ extern (D) static DsymbolTable resolve(Identifier[] packages, Dsymbol* pparent, Package* ppkg)
+ {
+ DsymbolTable dst = Module.modules;
+ Dsymbol parent = null;
+ //printf("Package::resolve()\n");
+ if (ppkg)
+ *ppkg = null;
+ foreach (pid; packages)
+ {
+ Package pkg;
+ Dsymbol p = dst.lookup(pid);
+ if (!p)
+ {
+ pkg = new Package(Loc.initial, pid);
+ dst.insert(pkg);
+ pkg.parent = parent;
+ pkg.symtab = new DsymbolTable();
+ }
+ else
+ {
+ pkg = p.isPackage();
+ assert(pkg);
+ // It might already be a module, not a package, but that needs
+ // to be checked at a higher level, where a nice error message
+ // can be generated.
+ // dot net needs modules and packages with same name
+ // But we still need a symbol table for it
+ if (!pkg.symtab)
+ pkg.symtab = new DsymbolTable();
+ }
+ parent = pkg;
+ dst = pkg.symtab;
+ if (ppkg && !*ppkg)
+ *ppkg = pkg;
+ if (pkg.isModule())
+ {
+ // Return the module so that a nice error message can be generated
+ if (ppkg)
+ *ppkg = cast(Package)p;
+ break;
+ }
+ }
+
+ if (pparent)
+ *pparent = parent;
+ return dst;
+ }
+
+ override final inout(Package) isPackage() inout
+ {
+ return this;
+ }
+
+ /**
+ * Checks if pkg is a sub-package of this
+ *
+ * For example, if this qualifies to 'a1.a2' and pkg - to 'a1.a2.a3',
+ * this function returns 'true'. If it is other way around or qualified
+ * package paths conflict function returns 'false'.
+ *
+ * Params:
+ * pkg = possible subpackage
+ *
+ * Returns:
+ * see description
+ */
+ final bool isAncestorPackageOf(const Package pkg) const
+ {
+ if (this == pkg)
+ return true;
+ if (!pkg || !pkg.parent)
+ return false;
+ return isAncestorPackageOf(pkg.parent.isPackage());
+ }
+
+ override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
+ {
+ //printf("%s Package.search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
+ flags &= ~SearchLocalsOnly; // searching an import is always transitive
+ if (!isModule() && mod)
+ {
+ // Prefer full package name.
+ Dsymbol s = symtab ? symtab.lookup(ident) : null;
+ if (s)
+ return s;
+ //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars());
+ return mod.search(loc, ident, flags);
+ }
+ return ScopeDsymbol.search(loc, ident, flags);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ final Module isPackageMod()
+ {
+ if (isPkgMod == PKG.module_)
+ {
+ return mod;
+ }
+ return null;
+ }
+
+ /**
+ * Checks for the existence of a package.d to set isPkgMod appropriately
+ * if isPkgMod == PKG.unknown
+ */
+ final void resolvePKGunknown()
+ {
+ if (isModule())
+ return;
+ if (isPkgMod != PKG.unknown)
+ return;
+
+ Identifier[] packages;
+ for (Dsymbol s = this.parent; s; s = s.parent)
+ packages ~= s.ident;
+ reverse(packages);
+
+ if (lookForSourceFile(getFilename(packages, ident), global.path ? (*global.path)[] : null))
+ Module.load(Loc(), packages, this.ident);
+ else
+ isPkgMod = PKG.package_;
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class Module : Package
+{
+ extern (C++) __gshared Module rootModule;
+ extern (C++) __gshared DsymbolTable modules; // symbol table of all modules
+ extern (C++) __gshared Modules amodules; // array of all modules
+ extern (C++) __gshared Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them
+ extern (C++) __gshared Dsymbols deferred2; // deferred Dsymbol's needing semantic2() run on them
+ extern (C++) __gshared Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them
+ extern (C++) __gshared uint dprogress; // progress resolving the deferred list
+
+ static void _init()
+ {
+ modules = new DsymbolTable();
+ }
+
+ /**
+ * Deinitializes the global state of the compiler.
+ *
+ * This can be used to restore the state set by `_init` to its original
+ * state.
+ */
+ static void deinitialize()
+ {
+ modules = modules.init;
+ }
+
+ extern (C++) __gshared AggregateDeclaration moduleinfo;
+
+ const(char)[] arg; // original argument name
+ ModuleDeclaration* md; // if !=null, the contents of the ModuleDeclaration declaration
+ const FileName srcfile; // input source file
+ const FileName objfile; // output .obj file
+ const FileName hdrfile; // 'header' file
+ FileName docfile; // output documentation file
+ FileBuffer* srcBuffer; // set during load(), free'd in parse()
+ uint errors; // if any errors in file
+ uint numlines; // number of lines in source file
+ bool isHdrFile; // if it is a header (.di) file
+ bool isCFile; // if it is a C (.c) file
+ bool isDocFile; // if it is a documentation input file, not D source
+ bool hasAlwaysInlines; // contains references to functions that must be inlined
+ bool isPackageFile; // if it is a package.d
+ Package pkg; // if isPackageFile is true, the Package that contains this package.d
+ Strings contentImportedFiles; // array of files whose content was imported
+ int needmoduleinfo;
+ int selfimports; // 0: don't know, 1: does not, 2: does
+ Dsymbol[void*] tagSymTab; /// ImportC: tag symbols that conflict with other symbols used as the index
+
+ /*************************************
+ * Return true if module imports itself.
+ */
+ bool selfImports()
+ {
+ //printf("Module::selfImports() %s\n", toChars());
+ if (selfimports == 0)
+ {
+ foreach (Module m; amodules)
+ m.insearch = 0;
+ selfimports = imports(this) + 1;
+ foreach (Module m; amodules)
+ m.insearch = 0;
+ }
+ return selfimports == 2;
+ }
+
+ int rootimports; // 0: don't know, 1: does not, 2: does
+
+ /*************************************
+ * Return true if module imports root module.
+ */
+ bool rootImports()
+ {
+ //printf("Module::rootImports() %s\n", toChars());
+ if (rootimports == 0)
+ {
+ foreach (Module m; amodules)
+ m.insearch = 0;
+ rootimports = 1;
+ foreach (Module m; amodules)
+ {
+ if (m.isRoot() && imports(m))
+ {
+ rootimports = 2;
+ break;
+ }
+ }
+ foreach (Module m; amodules)
+ m.insearch = 0;
+ }
+ return rootimports == 2;
+ }
+
+ int insearch;
+ Identifier searchCacheIdent;
+ Dsymbol searchCacheSymbol; // cached value of search
+ int searchCacheFlags; // cached flags
+
+ /**
+ * A root module is one that will be compiled all the way to
+ * object code. This field holds the root module that caused
+ * this module to be loaded. If this module is a root module,
+ * then it will be set to `this`. This is used to determine
+ * ownership of template instantiation.
+ */
+ Module importedFrom;
+
+ Dsymbols* decldefs; // top level declarations for this Module
+
+ Modules aimports; // all imported modules
+
+ uint debuglevel; // debug level
+ Identifiers* debugids; // debug identifiers
+ Identifiers* debugidsNot; // forward referenced debug identifiers
+
+ uint versionlevel; // version level
+ Identifiers* versionids; // version identifiers
+ Identifiers* versionidsNot; // forward referenced version identifiers
+
+ MacroTable macrotable; // document comment macros
+ Escape* _escapetable; // document comment escapes
+
+ size_t nameoffset; // offset of module name from start of ModuleInfo
+ size_t namelen; // length of module name in characters
+
+ extern (D) this(const ref Loc loc, const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen)
+ {
+ super(loc, ident);
+ const(char)[] srcfilename;
+ //printf("Module::Module(filename = '%.*s', ident = '%s')\n", cast(int)filename.length, filename.ptr, ident.toChars());
+ this.arg = filename;
+ srcfilename = FileName.defaultExt(filename, mars_ext);
+ if (target.run_noext && global.params.run &&
+ !FileName.ext(filename) &&
+ FileName.exists(srcfilename) == 0 &&
+ FileName.exists(filename) == 1)
+ {
+ FileName.free(srcfilename.ptr);
+ srcfilename = FileName.removeExt(filename); // just does a mem.strdup(filename)
+ }
+ else if (!FileName.equalsExt(srcfilename, mars_ext) &&
+ !FileName.equalsExt(srcfilename, hdr_ext) &&
+ !FileName.equalsExt(srcfilename, c_ext) &&
+ !FileName.equalsExt(srcfilename, i_ext) &&
+ !FileName.equalsExt(srcfilename, dd_ext))
+ {
+
+ error("source file name '%.*s' must have .%.*s extension",
+ cast(int)srcfilename.length, srcfilename.ptr,
+ cast(int)mars_ext.length, mars_ext.ptr);
+ fatal();
+ }
+
+ srcfile = FileName(srcfilename);
+ objfile = setOutfilename(global.params.objname, global.params.objdir, filename, target.obj_ext);
+ if (doDocComment)
+ setDocfile();
+ if (doHdrGen)
+ hdrfile = setOutfilename(global.params.hdrname, global.params.hdrdir, arg, hdr_ext);
+ }
+
+ extern (D) this(const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen)
+ {
+ this(Loc.initial, filename, ident, doDocComment, doHdrGen);
+ }
+
+ static Module create(const(char)* filename, Identifier ident, int doDocComment, int doHdrGen)
+ {
+ return create(filename.toDString, ident, doDocComment, doHdrGen);
+ }
+
+ extern (D) static Module create(const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen)
+ {
+ return new Module(Loc.initial, filename, ident, doDocComment, doHdrGen);
+ }
+
+ extern (C++) static Module load(Loc loc, Identifiers* packages, Identifier ident)
+ {
+ return load(loc, packages ? (*packages)[] : null, ident);
+ }
+
+ extern (D) static Module load(Loc loc, Identifier[] packages, Identifier ident)
+ {
+ //printf("Module::load(ident = '%s')\n", ident.toChars());
+ // Build module filename by turning:
+ // foo.bar.baz
+ // into:
+ // foo\bar\baz
+ const(char)[] filename = getFilename(packages, ident);
+ // Look for the source file
+ if (const result = lookForSourceFile(filename, global.path ? (*global.path)[] : null))
+ filename = result; // leaks
+
+ auto m = new Module(loc, filename, ident, 0, 0);
+
+ if (!m.read(loc))
+ return null;
+ if (global.params.verbose)
+ {
+ OutBuffer buf;
+ foreach (pid; packages)
+ {
+ buf.writestring(pid.toString());
+ buf.writeByte('.');
+ }
+ buf.printf("%s\t(%s)", ident.toChars(), m.srcfile.toChars());
+ message("import %s", buf.peekChars());
+ }
+ m = m.parse();
+
+ // Call onImport here because if the module is going to be compiled then we
+ // need to determine it early because it affects semantic analysis. This is
+ // being done after parsing the module so the full module name can be taken
+ // from whatever was declared in the file.
+ if (!m.isRoot() && Compiler.onImport(m))
+ {
+ m.importedFrom = m;
+ assert(m.isRoot());
+ }
+ return m;
+ }
+
+ override const(char)* kind() const
+ {
+ return "module";
+ }
+
+ /*********************************************
+ * Combines things into output file name for .html and .di files.
+ * Input:
+ * name Command line name given for the file, NULL if none
+ * dir Command line directory given for the file, NULL if none
+ * arg Name of the source file
+ * ext File name extension to use if 'name' is NULL
+ * global.params.preservePaths get output path from arg
+ * srcfile Input file - output file name must not match input file
+ */
+ extern(D) FileName setOutfilename(const(char)[] name, const(char)[] dir, const(char)[] arg, const(char)[] ext)
+ {
+ const(char)[] docfilename;
+ if (name)
+ {
+ docfilename = name;
+ }
+ else
+ {
+ const(char)[] argdoc;
+ OutBuffer buf;
+ if (arg == "__stdin.d")
+ {
+ version (Posix)
+ import core.sys.posix.unistd : getpid;
+ else version (Windows)
+ import core.sys.windows.winbase : getpid = GetCurrentProcessId;
+ buf.printf("__stdin_%d.d", getpid());
+ arg = buf[];
+ }
+ if (global.params.preservePaths)
+ argdoc = arg;
+ else
+ argdoc = FileName.name(arg);
+ // If argdoc doesn't have an absolute path, make it relative to dir
+ if (!FileName.absolute(argdoc))
+ {
+ //FileName::ensurePathExists(dir);
+ argdoc = FileName.combine(dir, argdoc);
+ }
+ docfilename = FileName.forceExt(argdoc, ext);
+ }
+ if (FileName.equals(docfilename, srcfile.toString()))
+ {
+ error("source file and output file have same name '%s'", srcfile.toChars());
+ fatal();
+ }
+ return FileName(docfilename);
+ }
+
+ extern (D) void setDocfile()
+ {
+ docfile = setOutfilename(global.params.docname, global.params.docdir, arg, doc_ext);
+ }
+
+ /**
+ * Loads the source buffer from the given read result into `this.srcBuffer`.
+ *
+ * Will take ownership of the buffer located inside `readResult`.
+ *
+ * Params:
+ * loc = the location
+ * readResult = the result of reading a file containing the source code
+ *
+ * Returns: `true` if successful
+ */
+ bool loadSourceBuffer(const ref Loc loc, ref File.ReadResult readResult)
+ {
+ //printf("Module::loadSourceBuffer('%s') file '%s'\n", toChars(), srcfile.toChars());
+ // take ownership of buffer
+ srcBuffer = new FileBuffer(readResult.extractSlice());
+ if (readResult.success)
+ return true;
+
+ if (FileName.equals(srcfile.toString(), "object.d"))
+ {
+ .error(loc, "cannot find source code for runtime library file 'object.d'");
+ errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions.");
+ const dmdConfFile = global.inifilename.length ? FileName.canonicalName(global.inifilename) : "not found";
+ errorSupplemental(loc, "config file: %.*s", cast(int)dmdConfFile.length, dmdConfFile.ptr);
+ }
+ else
+ {
+ // if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module
+ bool isPackageMod = (strcmp(toChars(), "package") != 0) && (strcmp(srcfile.name(), package_d) == 0 || (strcmp(srcfile.name(), package_di) == 0));
+ if (isPackageMod)
+ .error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'", toChars(), srcfile.toChars());
+ else
+ error(loc, "is in file '%s' which cannot be read", srcfile.toChars());
+ }
+ if (!global.gag)
+ {
+ /* Print path
+ */
+ if (global.path)
+ {
+ foreach (i, p; *global.path)
+ fprintf(stderr, "import path[%llu] = %s\n", cast(ulong)i, p);
+ }
+ else
+ {
+ fprintf(stderr, "Specify path to file '%s' with -I switch\n", srcfile.toChars());
+ }
+
+ removeHdrFilesAndFail(global.params, Module.amodules);
+ }
+ return false;
+ }
+
+ /**
+ * Reads the file from `srcfile` and loads the source buffer.
+ *
+ * If makefile module dependency is requested, we add this module
+ * to the list of dependencies from here.
+ *
+ * Params:
+ * loc = the location
+ *
+ * Returns: `true` if successful
+ * See_Also: loadSourceBuffer
+ */
+ bool read(const ref Loc loc)
+ {
+ if (srcBuffer)
+ return true; // already read
+
+ //printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
+ auto readResult = File.read(srcfile.toChars());
+
+ if (global.params.emitMakeDeps)
+ {
+ global.params.makeDeps.push(srcfile.toChars());
+ }
+
+ return loadSourceBuffer(loc, readResult);
+ }
+
+ /// syntactic parse
+ Module parse()
+ {
+ return parseModule!ASTCodegen();
+ }
+
+ /// ditto
+ extern (D) Module parseModule(AST)()
+ {
+ enum Endian { little, big}
+ enum SourceEncoding { utf16, utf32}
+
+ /*
+ * Convert a buffer from UTF32 to UTF8
+ * Params:
+ * Endian = is the buffer big/little endian
+ * buf = buffer of UTF32 data
+ * Returns:
+ * input buffer reencoded as UTF8
+ */
+
+ char[] UTF32ToUTF8(Endian endian)(const(char)[] buf)
+ {
+ static if (endian == Endian.little)
+ alias readNext = Port.readlongLE;
+ else
+ alias readNext = Port.readlongBE;
+
+ if (buf.length & 3)
+ {
+ error("odd length of UTF-32 char source %llu", cast(ulong) buf.length);
+ fatal();
+ }
+
+ const (uint)[] eBuf = cast(const(uint)[])buf;
+
+ OutBuffer dbuf;
+ dbuf.reserve(eBuf.length);
+
+ foreach (i; 0 .. eBuf.length)
+ {
+ const u = readNext(&eBuf[i]);
+ if (u & ~0x7F)
+ {
+ if (u > 0x10FFFF)
+ {
+ error("UTF-32 value %08x greater than 0x10FFFF", u);
+ fatal();
+ }
+ dbuf.writeUTF8(u);
+ }
+ else
+ dbuf.writeByte(u);
+ }
+ dbuf.writeByte(0); //add null terminator
+ return dbuf.extractSlice();
+ }
+
+ /*
+ * Convert a buffer from UTF16 to UTF8
+ * Params:
+ * Endian = is the buffer big/little endian
+ * buf = buffer of UTF16 data
+ * Returns:
+ * input buffer reencoded as UTF8
+ */
+
+ char[] UTF16ToUTF8(Endian endian)(const(char)[] buf)
+ {
+ static if (endian == Endian.little)
+ alias readNext = Port.readwordLE;
+ else
+ alias readNext = Port.readwordBE;
+
+ if (buf.length & 1)
+ {
+ error("odd length of UTF-16 char source %llu", cast(ulong) buf.length);
+ fatal();
+ }
+
+ const (ushort)[] eBuf = cast(const(ushort)[])buf;
+
+ OutBuffer dbuf;
+ dbuf.reserve(eBuf.length);
+
+ //i will be incremented in the loop for high codepoints
+ foreach (ref i; 0 .. eBuf.length)
+ {
+ uint u = readNext(&eBuf[i]);
+ if (u & ~0x7F)
+ {
+ if (0xD800 <= u && u < 0xDC00)
+ {
+ i++;
+ if (i >= eBuf.length)
+ {
+ error("surrogate UTF-16 high value %04x at end of file", u);
+ fatal();
+ }
+ const u2 = readNext(&eBuf[i]);
+ if (u2 < 0xDC00 || 0xE000 <= u2)
+ {
+ error("surrogate UTF-16 low value %04x out of range", u2);
+ fatal();
+ }
+ u = (u - 0xD7C0) << 10;
+ u |= (u2 - 0xDC00);
+ }
+ else if (u >= 0xDC00 && u <= 0xDFFF)
+ {
+ error("unpaired surrogate UTF-16 value %04x", u);
+ fatal();
+ }
+ else if (u == 0xFFFE || u == 0xFFFF)
+ {
+ error("illegal UTF-16 value %04x", u);
+ fatal();
+ }
+ dbuf.writeUTF8(u);
+ }
+ else
+ dbuf.writeByte(u);
+ }
+ dbuf.writeByte(0); //add a terminating null byte
+ return dbuf.extractSlice();
+ }
+
+ const(char)* srcname = srcfile.toChars();
+ //printf("Module::parse(srcname = '%s')\n", srcname);
+ isPackageFile = (strcmp(srcfile.name(), package_d) == 0 ||
+ strcmp(srcfile.name(), package_di) == 0);
+ const(char)[] buf = cast(const(char)[]) srcBuffer.data;
+
+ bool needsReencoding = true;
+ bool hasBOM = true; //assume there's a BOM
+ Endian endian;
+ SourceEncoding sourceEncoding;
+
+ if (buf.length >= 2)
+ {
+ /* Convert all non-UTF-8 formats to UTF-8.
+ * BOM : http://www.unicode.org/faq/utf_bom.html
+ * 00 00 FE FF UTF-32BE, big-endian
+ * FF FE 00 00 UTF-32LE, little-endian
+ * FE FF UTF-16BE, big-endian
+ * FF FE UTF-16LE, little-endian
+ * EF BB BF UTF-8
+ */
+ if (buf[0] == 0xFF && buf[1] == 0xFE)
+ {
+ endian = Endian.little;
+
+ sourceEncoding = buf.length >= 4 && buf[2] == 0 && buf[3] == 0
+ ? SourceEncoding.utf32
+ : SourceEncoding.utf16;
+ }
+ else if (buf[0] == 0xFE && buf[1] == 0xFF)
+ {
+ endian = Endian.big;
+ sourceEncoding = SourceEncoding.utf16;
+ }
+ else if (buf.length >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF)
+ {
+ endian = Endian.big;
+ sourceEncoding = SourceEncoding.utf32;
+ }
+ else if (buf.length >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF)
+ {
+ needsReencoding = false;//utf8 with BOM
+ }
+ else
+ {
+ /* There is no BOM. Make use of Arcane Jill's insight that
+ * the first char of D source must be ASCII to
+ * figure out the encoding.
+ */
+ hasBOM = false;
+ if (buf.length >= 4 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0)
+ {
+ endian = Endian.little;
+ sourceEncoding = SourceEncoding.utf32;
+ }
+ else if (buf.length >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0)
+ {
+ endian = Endian.big;
+ sourceEncoding = SourceEncoding.utf32;
+ }
+ else if (buf.length >= 2 && buf[1] == 0) //try to check for UTF-16
+ {
+ endian = Endian.little;
+ sourceEncoding = SourceEncoding.utf16;
+ }
+ else if (buf[0] == 0)
+ {
+ endian = Endian.big;
+ sourceEncoding = SourceEncoding.utf16;
+ }
+ else {
+ // It's UTF-8
+ needsReencoding = false;
+ if (buf[0] >= 0x80)
+ {
+ error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]);
+ fatal();
+ }
+ }
+ }
+ //throw away BOM
+ if (hasBOM)
+ {
+ if (!needsReencoding) buf = buf[3..$];// utf-8 already
+ else if (sourceEncoding == SourceEncoding.utf32) buf = buf[4..$];
+ else buf = buf[2..$]; //utf 16
+ }
+ }
+ // Assume the buffer is from memory and has not be read from disk. Assume UTF-8.
+ else if (buf.length >= 1 && (buf[0] == '\0' || buf[0] == 0x1A))
+ needsReencoding = false;
+ //printf("%s, %d, %d, %d\n", srcfile.name.toChars(), needsReencoding, endian == Endian.little, sourceEncoding == SourceEncoding.utf16);
+ if (needsReencoding)
+ {
+ if (sourceEncoding == SourceEncoding.utf16)
+ {
+ buf = endian == Endian.little
+ ? UTF16ToUTF8!(Endian.little)(buf)
+ : UTF16ToUTF8!(Endian.big)(buf);
+ }
+ else
+ {
+ buf = endian == Endian.little
+ ? UTF32ToUTF8!(Endian.little)(buf)
+ : UTF32ToUTF8!(Endian.big)(buf);
+ }
+ }
+
+ /* If it starts with the string "Ddoc", then it's a documentation
+ * source file.
+ */
+ if (buf.length>= 4 && buf[0..4] == "Ddoc")
+ {
+ comment = buf.ptr + 4;
+ isDocFile = true;
+ if (!docfile)
+ setDocfile();
+ return this;
+ }
+ /* If it has the extension ".dd", it is also a documentation
+ * source file. Documentation source files may begin with "Ddoc"
+ * but do not have to if they have the .dd extension.
+ * https://issues.dlang.org/show_bug.cgi?id=15465
+ */
+ if (FileName.equalsExt(arg, dd_ext))
+ {
+ comment = buf.ptr; // the optional Ddoc, if present, is handled above.
+ isDocFile = true;
+ if (!docfile)
+ setDocfile();
+ return this;
+ }
+ /* If it has the extension ".di", it is a "header" file.
+ */
+ if (FileName.equalsExt(arg, hdr_ext))
+ {
+ isHdrFile = true;
+ }
+
+ /* If it has the extension ".c", it is a "C" file.
+ * If it has the extension ".i", it is a preprocessed "C" file.
+ */
+ if (FileName.equalsExt(arg, c_ext) || FileName.equalsExt(arg, i_ext))
+ {
+ isCFile = true;
+
+ scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c);
+ p.nextToken();
+ members = p.parseModule();
+ md = p.md;
+ numlines = p.scanloc.linnum;
+ }
+ else
+ {
+ scope p = new Parser!AST(this, buf, cast(bool) docfile);
+ p.nextToken();
+ members = p.parseModule();
+ md = p.md;
+ numlines = p.scanloc.linnum;
+ }
+ srcBuffer.destroy();
+ srcBuffer = null;
+ /* The symbol table into which the module is to be inserted.
+ */
+ DsymbolTable dst;
+ if (md)
+ {
+ /* A ModuleDeclaration, md, was provided.
+ * The ModuleDeclaration sets the packages this module appears in, and
+ * the name of this module.
+ */
+ this.ident = md.id;
+ Package ppack = null;
+ dst = Package.resolve(md.packages, &this.parent, &ppack);
+
+ // Mark the package path as accessible from the current module
+ // https://issues.dlang.org/show_bug.cgi?id=21661
+ // Code taken from Import.addPackageAccess()
+ if (md.packages.length > 0)
+ {
+ // module a.b.c.d;
+ auto p = ppack; // a
+ addAccessiblePackage(p, Visibility(Visibility.Kind.private_));
+ foreach (id; md.packages[1 .. $]) // [b, c]
+ {
+ p = cast(Package) p.symtab.lookup(id);
+ if (p is null)
+ break;
+ addAccessiblePackage(p, Visibility(Visibility.Kind.private_));
+ }
+ }
+ assert(dst);
+ Module m = ppack ? ppack.isModule() : null;
+ if (m && (strcmp(m.srcfile.name(), package_d) != 0 &&
+ strcmp(m.srcfile.name(), package_di) != 0))
+ {
+ .error(md.loc, "package name '%s' conflicts with usage as a module name in file %s", ppack.toPrettyChars(), m.srcfile.toChars());
+ }
+ }
+ else
+ {
+ /* The name of the module is set to the source file name.
+ * There are no packages.
+ */
+ dst = modules; // and so this module goes into global module symbol table
+ /* Check to see if module name is a valid identifier
+ */
+ if (!Identifier.isValidIdentifier(this.ident.toChars()))
+ error("has non-identifier characters in filename, use module declaration instead");
+ }
+ // Insert module into the symbol table
+ Dsymbol s = this;
+ if (isPackageFile)
+ {
+ /* If the source tree is as follows:
+ * pkg/
+ * +- package.d
+ * +- common.d
+ * the 'pkg' will be incorporated to the internal package tree in two ways:
+ * import pkg;
+ * and:
+ * import pkg.common;
+ *
+ * If both are used in one compilation, 'pkg' as a module (== pkg/package.d)
+ * and a package name 'pkg' will conflict each other.
+ *
+ * To avoid the conflict:
+ * 1. If preceding package name insertion had occurred by Package::resolve,
+ * reuse the previous wrapping 'Package' if it exists
+ * 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here.
+ *
+ * Then change Package::isPkgMod to PKG.module_ and set Package::mod.
+ *
+ * Note that the 'wrapping Package' is the Package that contains package.d and other submodules,
+ * the one inserted to the symbol table.
+ */
+ auto ps = dst.lookup(ident);
+ Package p = ps ? ps.isPackage() : null;
+ if (p is null)
+ {
+ p = new Package(Loc.initial, ident);
+ p.tag = this.tag; // reuse the same package tag
+ p.symtab = new DsymbolTable();
+ }
+ this.tag = p.tag; // reuse the 'older' package tag
+ this.pkg = p;
+ p.parent = this.parent;
+ p.isPkgMod = PKG.module_;
+ p.mod = this;
+ s = p;
+ }
+ if (!dst.insert(s))
+ {
+ /* It conflicts with a name that is already in the symbol table.
+ * Figure out what went wrong, and issue error message.
+ */
+ Dsymbol prev = dst.lookup(ident);
+ assert(prev);
+ if (Module mprev = prev.isModule())
+ {
+ if (!FileName.equals(srcname, mprev.srcfile.toChars()))
+ error(loc, "from file %s conflicts with another module %s from file %s", srcname, mprev.toChars(), mprev.srcfile.toChars());
+ else if (isRoot() && mprev.isRoot())
+ error(loc, "from file %s is specified twice on the command line", srcname);
+ else
+ error(loc, "from file %s must be imported with 'import %s;'", srcname, toPrettyChars());
+ // https://issues.dlang.org/show_bug.cgi?id=14446
+ // Return previously parsed module to avoid AST duplication ICE.
+ return mprev;
+ }
+ else if (Package pkg = prev.isPackage())
+ {
+ // 'package.d' loaded after a previous 'Package' insertion
+ if (isPackageFile)
+ amodules.push(this); // Add to global array of all modules
+ else
+ error(md ? md.loc : loc, "from file %s conflicts with package name %s", srcname, pkg.toChars());
+ }
+ else
+ assert(global.errors);
+ }
+ else
+ {
+ // Add to global array of all modules
+ amodules.push(this);
+ }
+ Compiler.onParseModule(this);
+ return this;
+ }
+
+ override void importAll(Scope* prevsc)
+ {
+ //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+ if (_scope)
+ return; // already done
+ if (isDocFile)
+ {
+ error("is a Ddoc file, cannot import it");
+ return;
+ }
+
+ /* Note that modules get their own scope, from scratch.
+ * This is so regardless of where in the syntax a module
+ * gets imported, it is unaffected by context.
+ * Ignore prevsc.
+ */
+ Scope* sc = Scope.createGlobal(this); // create root scope
+
+ if (md && md.msg)
+ md.msg = semanticString(sc, md.msg, "deprecation message");
+
+ // Add import of "object", even for the "object" module.
+ // If it isn't there, some compiler rewrites, like
+ // classinst == classinst -> .object.opEquals(classinst, classinst)
+ // would fail inside object.d.
+ if (members.dim == 0 || (*members)[0].ident != Id.object ||
+ (*members)[0].isImport() is null)
+ {
+ auto im = new Import(Loc.initial, null, Id.object, null, 0);
+ members.shift(im);
+ }
+ if (!symtab)
+ {
+ // Add all symbols into module's symbol table
+ symtab = new DsymbolTable();
+ for (size_t i = 0; i < members.dim; i++)
+ {
+ Dsymbol s = (*members)[i];
+ s.addMember(sc, sc.scopesym);
+ }
+ }
+ // anything else should be run after addMember, so version/debug symbols are defined
+ /* Set scope for the symbols so that if we forward reference
+ * a symbol, it can possibly be resolved on the spot.
+ * If this works out well, it can be extended to all modules
+ * before any semantic() on any of them.
+ */
+ setScope(sc); // remember module scope for semantic
+ for (size_t i = 0; i < members.dim; i++)
+ {
+ Dsymbol s = (*members)[i];
+ s.setScope(sc);
+ }
+ for (size_t i = 0; i < members.dim; i++)
+ {
+ Dsymbol s = (*members)[i];
+ s.importAll(sc);
+ }
+ sc = sc.pop();
+ sc.pop(); // 2 pops because Scope.createGlobal() created 2
+ }
+
+ /**********************************
+ * Determine if we need to generate an instance of ModuleInfo
+ * for this Module.
+ */
+ int needModuleInfo()
+ {
+ //printf("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov);
+ return needmoduleinfo || global.params.cov;
+ }
+
+ /*******************************************
+ * Print deprecation warning if we're deprecated, when
+ * this module is imported from scope sc.
+ *
+ * Params:
+ * sc = the scope into which we are imported
+ * loc = the location of the import statement
+ */
+ void checkImportDeprecation(const ref Loc loc, Scope* sc)
+ {
+ if (md && md.isdeprecated && !sc.isDeprecated)
+ {
+ Expression msg = md.msg;
+ if (StringExp se = msg ? msg.toStringExp() : null)
+ {
+ const slice = se.peekString();
+ deprecation(loc, "is deprecated - %.*s", cast(int)slice.length, slice.ptr);
+ }
+ else
+ deprecation(loc, "is deprecated");
+ }
+ }
+
+ override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
+ {
+ /* Since modules can be circularly referenced,
+ * need to stop infinite recursive searches.
+ * This is done with the cache.
+ */
+ //printf("%s Module.search('%s', flags = x%x) insearch = %d\n", toChars(), ident.toChars(), flags, insearch);
+ if (insearch)
+ return null;
+
+ /* Qualified module searches always search their imports,
+ * even if SearchLocalsOnly
+ */
+ if (!(flags & SearchUnqualifiedModule))
+ flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly);
+
+ if (searchCacheIdent == ident && searchCacheFlags == flags)
+ {
+ //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n",
+ // toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null");
+ return searchCacheSymbol;
+ }
+
+ uint errors = global.errors;
+
+ insearch = 1;
+ Dsymbol s = ScopeDsymbol.search(loc, ident, flags);
+ insearch = 0;
+
+ if (errors == global.errors)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=10752
+ // Can cache the result only when it does not cause
+ // access error so the side-effect should be reproduced in later search.
+ searchCacheIdent = ident;
+ searchCacheSymbol = s;
+ searchCacheFlags = flags;
+ }
+ return s;
+ }
+
+ override bool isPackageAccessible(Package p, Visibility visibility, int flags = 0)
+ {
+ if (insearch) // don't follow import cycles
+ return false;
+ insearch = true;
+ scope (exit)
+ insearch = false;
+ if (flags & IgnorePrivateImports)
+ visibility = Visibility(Visibility.Kind.public_); // only consider public imports
+ return super.isPackageAccessible(p, visibility);
+ }
+
+ override Dsymbol symtabInsert(Dsymbol s)
+ {
+ searchCacheIdent = null; // symbol is inserted, so invalidate cache
+ return Package.symtabInsert(s);
+ }
+
+ void deleteObjFile()
+ {
+ if (global.params.obj)
+ File.remove(objfile.toChars());
+ if (docfile)
+ File.remove(docfile.toChars());
+ }
+
+ /*******************************************
+ * Can't run semantic on s now, try again later.
+ */
+ extern (D) static void addDeferredSemantic(Dsymbol s)
+ {
+ //printf("Module::addDeferredSemantic('%s')\n", s.toChars());
+ deferred.push(s);
+ }
+
+ extern (D) static void addDeferredSemantic2(Dsymbol s)
+ {
+ //printf("Module::addDeferredSemantic2('%s')\n", s.toChars());
+ deferred2.push(s);
+ }
+
+ extern (D) static void addDeferredSemantic3(Dsymbol s)
+ {
+ //printf("Module::addDeferredSemantic3('%s')\n", s.toChars());
+ deferred3.push(s);
+ }
+
+ /******************************************
+ * Run semantic() on deferred symbols.
+ */
+ static void runDeferredSemantic()
+ {
+ if (dprogress == 0)
+ return;
+
+ __gshared int nested;
+ if (nested)
+ return;
+ //if (deferred.dim) printf("+Module::runDeferredSemantic(), len = %d\n", deferred.dim);
+ nested++;
+
+ size_t len;
+ do
+ {
+ dprogress = 0;
+ len = deferred.dim;
+ if (!len)
+ break;
+
+ Dsymbol* todo;
+ Dsymbol* todoalloc = null;
+ Dsymbol tmp;
+ if (len == 1)
+ {
+ todo = &tmp;
+ }
+ else
+ {
+ todo = cast(Dsymbol*)Mem.check(malloc(len * Dsymbol.sizeof));
+ todoalloc = todo;
+ }
+ memcpy(todo, deferred.tdata(), len * Dsymbol.sizeof);
+ deferred.setDim(0);
+
+ foreach (i; 0..len)
+ {
+ Dsymbol s = todo[i];
+ s.dsymbolSemantic(null);
+ //printf("deferred: %s, parent = %s\n", s.toChars(), s.parent.toChars());
+ }
+ //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress);
+ if (todoalloc)
+ free(todoalloc);
+ }
+ while (deferred.dim < len || dprogress); // while making progress
+ nested--;
+ //printf("-Module::runDeferredSemantic(), len = %d\n", deferred.dim);
+ }
+
+ static void runDeferredSemantic2()
+ {
+ Module.runDeferredSemantic();
+
+ Dsymbols* a = &Module.deferred2;
+ for (size_t i = 0; i < a.dim; i++)
+ {
+ Dsymbol s = (*a)[i];
+ //printf("[%d] %s semantic2a\n", i, s.toPrettyChars());
+ s.semantic2(null);
+
+ if (global.errors)
+ break;
+ }
+ a.setDim(0);
+ }
+
+ static void runDeferredSemantic3()
+ {
+ Module.runDeferredSemantic2();
+
+ Dsymbols* a = &Module.deferred3;
+ for (size_t i = 0; i < a.dim; i++)
+ {
+ Dsymbol s = (*a)[i];
+ //printf("[%d] %s semantic3a\n", i, s.toPrettyChars());
+ s.semantic3(null);
+
+ if (global.errors)
+ break;
+ }
+ a.setDim(0);
+ }
+
+ extern (D) static void clearCache()
+ {
+ foreach (Module m; amodules)
+ m.searchCacheIdent = null;
+ }
+
+ /************************************
+ * Recursively look at every module this module imports,
+ * return true if it imports m.
+ * Can be used to detect circular imports.
+ */
+ int imports(Module m)
+ {
+ //printf("%s Module::imports(%s)\n", toChars(), m.toChars());
+ version (none)
+ {
+ foreach (i, Module mi; aimports)
+ printf("\t[%d] %s\n", cast(int) i, mi.toChars());
+ }
+ foreach (Module mi; aimports)
+ {
+ if (mi == m)
+ return true;
+ if (!mi.insearch)
+ {
+ mi.insearch = 1;
+ int r = mi.imports(m);
+ if (r)
+ return r;
+ }
+ }
+ return false;
+ }
+
+ bool isRoot()
+ {
+ return this.importedFrom == this;
+ }
+
+ // true if the module source file is directly
+ // listed in command line.
+ bool isCoreModule(Identifier ident)
+ {
+ return this.ident == ident && parent && parent.ident == Id.core && !parent.parent;
+ }
+
+ // Back end
+ int doppelganger; // sub-module
+ Symbol* cov; // private uint[] __coverage;
+ uint* covb; // bit array of valid code line numbers
+ Symbol* sictor; // module order independent constructor
+ Symbol* sctor; // module constructor
+ Symbol* sdtor; // module destructor
+ Symbol* ssharedctor; // module shared constructor
+ Symbol* sshareddtor; // module shared destructor
+ Symbol* stest; // module unit test
+ Symbol* sfilename; // symbol for filename
+
+ uint[uint] ctfe_cov; /// coverage information from ctfe execution_count[line]
+
+ override inout(Module) isModule() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ /***********************************************
+ * Writes this module's fully-qualified name to buf
+ * Params:
+ * buf = The buffer to write to
+ */
+ void fullyQualifiedName(ref OutBuffer buf)
+ {
+ buf.writestring(ident.toString());
+
+ for (auto package_ = parent; package_ !is null; package_ = package_.parent)
+ {
+ buf.prependstring(".");
+ buf.prependstring(package_.ident.toChars());
+ }
+ }
+
+ /** Lazily initializes and returns the escape table.
+ Turns out it eats a lot of memory.
+ */
+ extern(D) Escape* escapetable()
+ {
+ if (!_escapetable)
+ _escapetable = new Escape();
+ return _escapetable;
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) struct ModuleDeclaration
+{
+ Loc loc;
+ Identifier id;
+ Identifier[] packages; // array of Identifier's representing packages
+ bool isdeprecated; // if it is a deprecated module
+ Expression msg;
+
+ extern (D) this(const ref Loc loc, Identifier[] packages, Identifier id, Expression msg, bool isdeprecated)
+ {
+ this.loc = loc;
+ this.packages = packages;
+ this.id = id;
+ this.msg = msg;
+ this.isdeprecated = isdeprecated;
+ }
+
+ extern (C++) const(char)* toChars() const
+ {
+ OutBuffer buf;
+ foreach (pid; packages)
+ {
+ buf.writestring(pid.toString());
+ buf.writeByte('.');
+ }
+ buf.writestring(id.toString());
+ return buf.extractChars();
+ }
+
+ /// Provide a human readable representation
+ extern (D) const(char)[] toString() const
+ {
+ return this.toChars().toDString;
+ }
+}
diff --git a/gcc/d/dmd/doc.c b/gcc/d/dmd/doc.c
deleted file mode 100644
index 5d2da1c..0000000
--- a/gcc/d/dmd/doc.c
+++ /dev/null
@@ -1,2807 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/doc.c
- */
-
-// This implements the Ddoc capability.
-
-#include "root/dsystem.h"
-#include "root/rmem.h"
-#include "root/root.h"
-#include "root/port.h"
-#include "root/aav.h"
-
-#include "attrib.h"
-#include "cond.h"
-#include "mars.h"
-#include "dsymbol.h"
-#include "macro.h"
-#include "template.h"
-#include "lexer.h"
-#include "aggregate.h"
-#include "declaration.h"
-#include "statement.h"
-#include "enum.h"
-#include "id.h"
-#include "module.h"
-#include "scope.h"
-#include "hdrgen.h"
-#include "doc.h"
-#include "mtype.h"
-#include "utf.h"
-
-void emitMemberComments(ScopeDsymbol *sds, OutBuffer *buf, Scope *sc);
-void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc);
-void emitComment(Dsymbol *s, OutBuffer *buf, Scope *sc);
-
-struct Escape
-{
- const char *strings[256];
-
- const char *escapeChar(unsigned c);
-};
-
-class Section
-{
-public:
- const utf8_t *name;
- size_t namelen;
-
- const utf8_t *body;
- size_t bodylen;
-
- int nooutput;
-
- virtual void write(Loc loc, DocComment *dc, Scope *sc, Dsymbols *a, OutBuffer *buf);
-};
-
-class ParamSection : public Section
-{
-public:
- void write(Loc loc, DocComment *dc, Scope *sc, Dsymbols *a, OutBuffer *buf);
-};
-
-class MacroSection : public Section
-{
-public:
- void write(Loc loc, DocComment *dc, Scope *sc, Dsymbols *a, OutBuffer *buf);
-};
-
-typedef Array<Section *> Sections;
-
-struct DocComment
-{
- Sections sections; // Section*[]
-
- Section *summary;
- Section *copyright;
- Section *macros;
- Macro **pmacrotable;
- Escape **pescapetable;
-
- Dsymbols a;
-
- DocComment() :
- summary(NULL), copyright(NULL), macros(NULL), pmacrotable(NULL), pescapetable(NULL)
- { }
-
- static DocComment *parse(Dsymbol *s, const utf8_t *comment);
- static void parseMacros(Escape **pescapetable, Macro **pmacrotable, const utf8_t *m, size_t mlen);
- static void parseEscapes(Escape **pescapetable, const utf8_t *textstart, size_t textlen);
-
- void parseSections(const utf8_t *comment);
- void writeSections(Scope *sc, Dsymbols *a, OutBuffer *buf);
-};
-
-
-int cmp(const char *stringz, const void *s, size_t slen);
-int icmp(const char *stringz, const void *s, size_t slen);
-bool isDitto(const utf8_t *comment);
-const utf8_t *skipwhitespace(const utf8_t *p);
-size_t skiptoident(OutBuffer *buf, size_t i);
-size_t skippastident(OutBuffer *buf, size_t i);
-size_t skippastURL(OutBuffer *buf, size_t i);
-void highlightText(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset);
-void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset);
-void highlightCode(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset);
-void highlightCode2(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset);
-void highlightCode3(Scope *sc, OutBuffer *buf, const utf8_t *p, const utf8_t *pend);
-TypeFunction *isTypeFunction(Dsymbol *s);
-Parameter *isFunctionParameter(Dsymbols *a, const utf8_t *p, size_t len);
-TemplateParameter *isTemplateParameter(Dsymbols *a, const utf8_t *p, size_t len);
-
-bool isIdStart(const utf8_t *p);
-bool isCVariadicArg(const utf8_t *p, size_t len);
-bool isIdTail(const utf8_t *p);
-bool isIndentWS(const utf8_t *p);
-int utfStride(const utf8_t *p);
-
-// Workaround for missing Parameter instance for variadic params. (it's unnecessary to instantiate one).
-bool isCVariadicParameter(Dsymbols *a, const utf8_t *p, size_t len)
-{
- for (size_t i = 0; i < a->length; i++)
- {
- TypeFunction *tf = isTypeFunction((*a)[i]);
- if (tf && tf->parameterList.varargs == VARARGvariadic && cmp("...", p, len) == 0)
- return true;
- }
- return false;
-}
-
-/****************************************************
- */
-static Parameter *isFunctionParameter(Dsymbol *s, const utf8_t *p, size_t len)
-{
- TypeFunction *tf = isTypeFunction(s);
- if (tf && tf->parameterList.parameters)
- {
- for (size_t k = 0; k < tf->parameterList.parameters->length; k++)
- {
- Parameter *fparam = (*tf->parameterList.parameters)[k];
- if (fparam->ident && cmp(fparam->ident->toChars(), p, len) == 0)
- {
- return fparam;
- }
- }
- }
- return NULL;
-}
-
-static Dsymbol *getEponymousMember(TemplateDeclaration *td)
-{
- if (!td->onemember)
- return NULL;
-
- if (AggregateDeclaration *ad = td->onemember->isAggregateDeclaration())
- return ad;
- if (FuncDeclaration *fd = td->onemember->isFuncDeclaration())
- return fd;
- if (td->onemember->isEnumMember())
- return NULL; // Keep backward compatibility. See compilable/ddoc9.d
- if (VarDeclaration *vd = td->onemember->isVarDeclaration())
- return td->constraint ? NULL : vd;
-
- return NULL;
-}
-
-/****************************************************
- */
-static Parameter *isEponymousFunctionParameter(Dsymbols *a, const utf8_t *p, size_t len)
-{
- for (size_t i = 0; i < a->length; i++)
- {
- TemplateDeclaration *td = (*a)[i]->isTemplateDeclaration();
- if (td && td->onemember)
- {
- /* Case 1: we refer to a template declaration inside the template
-
- /// ...ddoc...
- template case1(T) {
- void case1(R)() {}
- }
- */
- td = td->onemember->isTemplateDeclaration();
- }
- if (!td)
- {
- /* Case 2: we're an alias to a template declaration
-
- /// ...ddoc...
- alias case2 = case1!int;
- */
- AliasDeclaration *ad = (*a)[i]->isAliasDeclaration();
- if (ad && ad->aliassym)
- {
- td = ad->aliassym->isTemplateDeclaration();
- }
- }
- while (td)
- {
- Dsymbol *sym = getEponymousMember(td);
- if (sym)
- {
- Parameter *fparam = isFunctionParameter(sym, p, len);
- if (fparam)
- {
- return fparam;
- }
- }
- td = td->overnext;
- }
- }
- return NULL;
-}
-
-static TemplateDeclaration *getEponymousParent(Dsymbol *s)
-{
- if (!s->parent)
- return NULL;
- TemplateDeclaration *td = s->parent->isTemplateDeclaration();
- return (td && getEponymousMember(td)) ? td : NULL;
-}
-
-static const char ddoc_default[] = "\
-DDOC = <html><head>\n\
- <META http-equiv=\"content-type\" content=\"text/html; charset=utf-8\">\n\
- <title>$(TITLE)</title>\n\
- </head><body>\n\
- <h1>$(TITLE)</h1>\n\
- $(BODY)\n\
- <hr>$(SMALL Page generated by $(LINK2 http://dlang.org/ddoc.html, Ddoc). $(COPYRIGHT))\n\
- </body></html>\n\
-\n\
-B = <b>$0</b>\n\
-I = <i>$0</i>\n\
-U = <u>$0</u>\n\
-P = <p>$0</p>\n\
-DL = <dl>$0</dl>\n\
-DT = <dt>$0</dt>\n\
-DD = <dd>$0</dd>\n\
-TABLE = <table>$0</table>\n\
-TR = <tr>$0</tr>\n\
-TH = <th>$0</th>\n\
-TD = <td>$0</td>\n\
-OL = <ol>$0</ol>\n\
-UL = <ul>$0</ul>\n\
-LI = <li>$0</li>\n\
-BIG = <big>$0</big>\n\
-SMALL = <small>$0</small>\n\
-BR = <br>\n\
-LINK = <a href=\"$0\">$0</a>\n\
-LINK2 = <a href=\"$1\">$+</a>\n\
-LPAREN= (\n\
-RPAREN= )\n\
-BACKTICK= `\n\
-DOLLAR= $\n\
-DEPRECATED= $0\n\
-\n\
-RED = <font color=red>$0</font>\n\
-BLUE = <font color=blue>$0</font>\n\
-GREEN = <font color=green>$0</font>\n\
-YELLOW =<font color=yellow>$0</font>\n\
-BLACK = <font color=black>$0</font>\n\
-WHITE = <font color=white>$0</font>\n\
-\n\
-D_CODE = <pre class=\"d_code\">$0</pre>\n\
-DDOC_BACKQUOTED = $(D_INLINECODE $0)\n\
-D_INLINECODE = <pre style=\"display:inline;\" class=\"d_inline_code\">$0</pre>\n\
-D_COMMENT = $(GREEN $0)\n\
-D_STRING = $(RED $0)\n\
-D_KEYWORD = $(BLUE $0)\n\
-D_PSYMBOL = $(U $0)\n\
-D_PARAM = $(I $0)\n\
-\n\
-DDOC_COMMENT = <!-- $0 -->\n\
-DDOC_DECL = $(DT $(BIG $0))\n\
-DDOC_DECL_DD = $(DD $0)\n\
-DDOC_DITTO = $(BR)$0\n\
-DDOC_SECTIONS = $0\n\
-DDOC_SUMMARY = $0$(BR)$(BR)\n\
-DDOC_DESCRIPTION = $0$(BR)$(BR)\n\
-DDOC_AUTHORS = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_BUGS = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_DATE = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_EXAMPLES = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_HISTORY = $(B History:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_LICENSE = $(B License:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_RETURNS = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_SEE_ALSO = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_THROWS = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_VERSION = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\
-DDOC_SECTION_H = $(B $0)$(BR)\n\
-DDOC_SECTION = $0$(BR)$(BR)\n\
-DDOC_MEMBERS = $(DL $0)\n\
-DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\
-DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)\n\
-DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\
-DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)\n\
-DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\
-DDOC_ENUM_BASETYPE = $0\n\
-DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\
-DDOC_PARAM_ROW = $(TR $0)\n\
-DDOC_PARAM_ID = $(TD $0)\n\
-DDOC_PARAM_DESC = $(TD $0)\n\
-DDOC_BLANKLINE = $(BR)$(BR)\n\
-\n\
-DDOC_ANCHOR = <a name=\"$1\"></a>\n\
-DDOC_PSYMBOL = $(U $0)\n\
-DDOC_PSUPER_SYMBOL = $(U $0)\n\
-DDOC_KEYWORD = $(B $0)\n\
-DDOC_PARAM = $(I $0)\n\
-\n\
-ESCAPES = /</&lt;/\n\
- />/&gt;/\n\
- /&/&amp;/\n\
-";
-
-static const char ddoc_decl_s[] = "$(DDOC_DECL ";
-static const char ddoc_decl_e[] = ")\n";
-
-static const char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD ";
-static const char ddoc_decl_dd_e[] = ")\n";
-
-
-/****************************************************
- */
-
-void gendocfile(Module *m)
-{
- static OutBuffer mbuf;
- static int mbuf_done;
-
- OutBuffer buf;
-
- //printf("Module::gendocfile()\n");
-
- if (!mbuf_done) // if not already read the ddoc files
- {
- mbuf_done = 1;
-
- // Use our internal default
- mbuf.write(ddoc_default, strlen(ddoc_default));
-
- // Override with DDOCFILE specified in the sc.ini file
- char *p = getenv("DDOCFILE");
- if (p)
- global.params.ddocfiles.shift(p);
-
- // Override with the ddoc macro files from the command line
- for (size_t i = 0; i < global.params.ddocfiles.length; i++)
- {
- FileName f(global.params.ddocfiles[i]);
- File file(&f);
- readFile(m->loc, &file);
- // BUG: convert file contents to UTF-8 before use
-
- //printf("file: '%.*s'\n", file.len, file.buffer);
- mbuf.write(file.buffer, file.len);
- }
- }
- DocComment::parseMacros(&m->escapetable, &m->macrotable, (utf8_t *)mbuf.slice().ptr, mbuf.length());
-
- Scope *sc = Scope::createGlobal(m); // create root scope
-
- DocComment *dc = DocComment::parse(m, m->comment);
- dc->pmacrotable = &m->macrotable;
- dc->pescapetable = &m->escapetable;
- sc->lastdc = dc;
-
- // Generate predefined macros
-
- // Set the title to be the name of the module
- {
- const char *p = m->toPrettyChars();
- Macro::define(&m->macrotable, (const utf8_t *)"TITLE", 5, (const utf8_t *)p, strlen(p));
- }
-
- // Set time macros
- {
- time_t t;
- time(&t);
- char *p = ctime(&t);
- p = mem.xstrdup(p);
- Macro::define(&m->macrotable, (const utf8_t *)"DATETIME", 8, (const utf8_t *)p, strlen(p));
- Macro::define(&m->macrotable, (const utf8_t *)"YEAR", 4, (const utf8_t *)p + 20, 4);
- }
-
- const char *srcfilename = m->srcfile->toChars();
- Macro::define(&m->macrotable, (const utf8_t *)"SRCFILENAME", 11, (const utf8_t *)srcfilename, strlen(srcfilename));
-
- const char *docfilename = m->docfile->toChars();
- Macro::define(&m->macrotable, (const utf8_t *)"DOCFILENAME", 11, (const utf8_t *)docfilename, strlen(docfilename));
-
- if (dc->copyright)
- {
- dc->copyright->nooutput = 1;
- Macro::define(&m->macrotable, (const utf8_t *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen);
- }
-
- buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", m->srcfile->toChars());
- if (m->isDocFile)
- {
- Loc loc = m->md ? m->md->loc : m->loc;
- size_t commentlen = strlen((const char *)m->comment);
- Dsymbols a;
- // Bugzilla 9764: Don't push m in a, to prevent emphasize ddoc file name.
- if (dc->macros)
- {
- commentlen = dc->macros->name - m->comment;
- dc->macros->write(loc, dc, sc, &a, &buf);
- }
- buf.write(m->comment, commentlen);
- highlightText(sc, &a, &buf, 0);
- }
- else
- {
- Dsymbols a;
- a.push(m);
- dc->writeSections(sc, &a, &buf);
- emitMemberComments(m, &buf, sc);
- }
-
- //printf("BODY= '%.*s'\n", buf.length(), buf.slice().ptr);
- Macro::define(&m->macrotable, (const utf8_t *)"BODY", 4, (const utf8_t *)buf.slice().ptr, buf.length());
-
- OutBuffer buf2;
- buf2.writestring("$(DDOC)\n");
- size_t end = buf2.length();
- m->macrotable->expand(&buf2, 0, &end, NULL, 0);
-
- /* Remove all the escape sequences from buf2,
- * and make CR-LF the newline.
- */
- {
- buf.setsize(0);
- buf.reserve(buf2.length());
- utf8_t *p = (utf8_t *)buf2.slice().ptr;
- for (size_t j = 0; j < buf2.length(); j++)
- {
- utf8_t c = p[j];
- if (c == 0xFF && j + 1 < buf2.length())
- {
- j++;
- continue;
- }
- if (c == '\n')
- buf.writeByte('\r');
- else if (c == '\r')
- {
- buf.writestring("\r\n");
- if (j + 1 < buf2.length() && p[j + 1] == '\n')
- {
- j++;
- }
- continue;
- }
- buf.writeByte(c);
- }
- }
-
- // Transfer image to file
- assert(m->docfile);
- m->docfile->setbuffer(buf.slice().ptr, buf.length());
- m->docfile->ref = 1;
- ensurePathToNameExists(Loc(), m->docfile->toChars());
- writeFile(m->loc, m->docfile);
-}
-
-/****************************************************
- * Having unmatched parentheses can hose the output of Ddoc,
- * as the macros depend on properly nested parentheses.
- * This function replaces all ( with $(LPAREN) and ) with $(RPAREN)
- * to preserve text literally. This also means macros in the
- * text won't be expanded.
- */
-void escapeDdocString(OutBuffer *buf, size_t start)
-{
- for (size_t u = start; u < buf->length(); u++)
- {
- utf8_t c = buf->slice().ptr[u];
- switch(c)
- {
- case '$':
- buf->remove(u, 1);
- buf->insert(u, (const char *)"$(DOLLAR)", 9);
- u += 8;
- break;
-
- case '(':
- buf->remove(u, 1); //remove the (
- buf->insert(u, (const char *)"$(LPAREN)", 9); //insert this instead
- u += 8; //skip over newly inserted macro
- break;
-
- case ')':
- buf->remove(u, 1); //remove the )
- buf->insert(u, (const char *)"$(RPAREN)", 9); //insert this instead
- u += 8; //skip over newly inserted macro
- break;
- }
- }
-}
-
-/****************************************************
- * Having unmatched parentheses can hose the output of Ddoc,
- * as the macros depend on properly nested parentheses.
-
- * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN).
- */
-void escapeStrayParenthesis(Loc loc, OutBuffer *buf, size_t start)
-{
- unsigned par_open = 0;
-
- for (size_t u = start; u < buf->length(); u++)
- {
- utf8_t c = buf->slice().ptr[u];
- switch(c)
- {
- case '(':
- par_open++;
- break;
-
- case ')':
- if (par_open == 0)
- {
- //stray ')'
- warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output."
- " Use $(RPAREN) instead for unpaired right parentheses.");
- buf->remove(u, 1); //remove the )
- buf->insert(u, (const char *)"$(RPAREN)", 9); //insert this instead
- u += 8; //skip over newly inserted macro
- }
- else
- par_open--;
- break;
- }
- }
-
- if (par_open) // if any unmatched lparens
- {
- par_open = 0;
- for (size_t u = buf->length(); u > start;)
- {
- u--;
- utf8_t c = buf->slice().ptr[u];
- switch(c)
- {
- case ')':
- par_open++;
- break;
-
- case '(':
- if (par_open == 0)
- {
- //stray '('
- warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output."
- " Use $(LPAREN) instead for unpaired left parentheses.");
- buf->remove(u, 1); //remove the (
- buf->insert(u, (const char *)"$(LPAREN)", 9); //insert this instead
- }
- else
- par_open--;
- break;
- }
- }
- }
-}
-
-// Basically, this is to skip over things like private{} blocks in a struct or
-// class definition that don't add any components to the qualified name.
-static Scope *skipNonQualScopes(Scope *sc)
-{
- while (sc && !sc->scopesym)
- sc = sc->enclosing;
- return sc;
-}
-
-static bool emitAnchorName(OutBuffer *buf, Dsymbol *s, Scope *sc)
-{
- if (!s || s->isPackage() || s->isModule())
- return false;
-
- // Add parent names first
- bool dot = false;
- if (s->parent)
- dot = emitAnchorName(buf, s->parent, sc);
- else if (sc)
- dot = emitAnchorName(buf, sc->scopesym, skipNonQualScopes(sc->enclosing));
-
- // Eponymous template members can share the parent anchor name
- if (getEponymousParent(s))
- return dot;
- if (dot)
- buf->writeByte('.');
-
- // Use "this" not "__ctor"
- TemplateDeclaration *td;
- if (s->isCtorDeclaration() || ((td = s->isTemplateDeclaration()) != NULL &&
- td->onemember && td->onemember->isCtorDeclaration()))
- {
- buf->writestring("this");
- }
- else
- {
- /* We just want the identifier, not overloads like TemplateDeclaration::toChars.
- * We don't want the template parameter list and constraints. */
- buf->writestring(s->Dsymbol::toChars());
- }
- return true;
-}
-
-static void emitAnchor(OutBuffer *buf, Dsymbol *s, Scope *sc)
-{
- Identifier *ident;
- {
- OutBuffer anc;
- emitAnchorName(&anc, s, skipNonQualScopes(sc));
- ident = Identifier::idPool(anc.peekChars());
- }
- size_t *count = (size_t*)dmd_aaGet(&sc->anchorCounts, (void *)ident);
- TemplateDeclaration *td = getEponymousParent(s);
- // don't write an anchor for matching consecutive ditto symbols
- if (*count > 0 && sc->prevAnchor == ident &&
- sc->lastdc && (isDitto(s->comment) || (td && isDitto(td->comment))))
- return;
-
- (*count)++;
- // cache anchor name
- sc->prevAnchor = ident;
-
- buf->writestring("$(DDOC_ANCHOR ");
- buf->writestring(ident->toChars());
- // only append count once there's a duplicate
- if (*count != 1)
- buf->printf(".%u", *count);
- buf->writeByte(')');
-}
-
-/******************************* emitComment **********************************/
-
-/** Get leading indentation from 'src' which represents lines of code. */
-static size_t getCodeIndent(const char *src)
-{
- while (src && (*src == '\r' || *src == '\n'))
- ++src; // skip until we find the first non-empty line
-
- size_t codeIndent = 0;
- while (src && (*src == ' ' || *src == '\t'))
- {
- codeIndent++;
- src++;
- }
- return codeIndent;
-}
-
-/** Recursively expand template mixin member docs into the scope. */
-static void expandTemplateMixinComments(TemplateMixin *tm, OutBuffer *buf, Scope *sc)
-{
- if (!tm->semanticRun)
- dsymbolSemantic(tm, sc);
- TemplateDeclaration *td = (tm && tm->tempdecl) ?
- tm->tempdecl->isTemplateDeclaration() : NULL;
- if (td && td->members)
- {
- for (size_t i = 0; i < td->members->length; i++)
- {
- Dsymbol *sm = (*td->members)[i];
- TemplateMixin *tmc = sm->isTemplateMixin();
- if (tmc && tmc->comment)
- expandTemplateMixinComments(tmc, buf, sc);
- else
- emitComment(sm, buf, sc);
- }
- }
-}
-
-void emitMemberComments(ScopeDsymbol *sds, OutBuffer *buf, Scope *sc)
-{
- if (!sds->members)
- return;
-
- //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars());
-
- const char *m = "$(DDOC_MEMBERS ";
- if (sds->isTemplateDeclaration())
- m = "$(DDOC_TEMPLATE_MEMBERS ";
- else if (sds->isClassDeclaration())
- m = "$(DDOC_CLASS_MEMBERS ";
- else if (sds->isStructDeclaration())
- m = "$(DDOC_STRUCT_MEMBERS ";
- else if (sds->isEnumDeclaration())
- m = "$(DDOC_ENUM_MEMBERS ";
- else if (sds->isModule())
- m = "$(DDOC_MODULE_MEMBERS ";
-
- size_t offset1 = buf->length(); // save starting offset
- buf->writestring(m);
- size_t offset2 = buf->length(); // to see if we write anything
-
- sc = sc->push(sds);
-
- for (size_t i = 0; i < sds->members->length; i++)
- {
- Dsymbol *s = (*sds->members)[i];
- //printf("\ts = '%s'\n", s->toChars());
-
- // only expand if parent is a non-template (semantic won't work)
- if (s->comment && s->isTemplateMixin() && s->parent && !s->parent->isTemplateDeclaration())
- expandTemplateMixinComments((TemplateMixin *)s, buf, sc);
-
- emitComment(s, buf, sc);
- }
- emitComment(NULL, buf, sc);
-
- sc->pop();
-
- if (buf->length() == offset2)
- {
- /* Didn't write out any members, so back out last write
- */
- buf->setsize(offset1);
- }
- else
- buf->writestring(")\n");
-}
-
-void emitProtection(OutBuffer *buf, Prot prot)
-{
- if (prot.kind != Prot::undefined && prot.kind != Prot::public_)
- {
- protectionToBuffer(buf, prot);
- buf->writeByte(' ');
- }
-}
-
-void emitComment(Dsymbol *s, OutBuffer *buf, Scope *sc)
-{
- class EmitComment : public Visitor
- {
- public:
- OutBuffer *buf;
- Scope *sc;
-
- EmitComment(OutBuffer *buf, Scope *sc)
- : buf(buf), sc(sc)
- {
- }
-
- void visit(Dsymbol *) {}
- void visit(InvariantDeclaration *) {}
- void visit(UnitTestDeclaration *) {}
- void visit(PostBlitDeclaration *) {}
- void visit(DtorDeclaration *) {}
- void visit(StaticCtorDeclaration *) {}
- void visit(StaticDtorDeclaration *) {}
- void visit(TypeInfoDeclaration *) {}
-
- void emit(Scope *sc, Dsymbol *s, const utf8_t *com)
- {
- if (s && sc->lastdc && isDitto(com))
- {
- sc->lastdc->a.push(s);
- return;
- }
-
- // Put previous doc comment if exists
- if (DocComment *dc = sc->lastdc)
- {
- // Put the declaration signatures as the document 'title'
- buf->writestring(ddoc_decl_s);
- for (size_t i = 0; i < dc->a.length; i++)
- {
- Dsymbol *sx = dc->a[i];
-
- if (i == 0)
- {
- size_t o = buf->length();
- toDocBuffer(sx, buf, sc);
- highlightCode(sc, sx, buf, o);
- continue;
- }
-
- buf->writestring("$(DDOC_DITTO ");
- {
- size_t o = buf->length();
- toDocBuffer(sx, buf, sc);
- highlightCode(sc, sx, buf, o);
- }
- buf->writeByte(')');
- }
- buf->writestring(ddoc_decl_e);
-
- // Put the ddoc comment as the document 'description'
- buf->writestring(ddoc_decl_dd_s);
- {
- dc->writeSections(sc, &dc->a, buf);
- if (ScopeDsymbol *sds = dc->a[0]->isScopeDsymbol())
- emitMemberComments(sds, buf, sc);
- }
- buf->writestring(ddoc_decl_dd_e);
- //printf("buf.2 = [[%.*s]]\n", buf->length() - o0, buf->slice().ptr + o0);
- }
-
- if (s)
- {
- DocComment *dc = DocComment::parse(s, com);
- dc->pmacrotable = &sc->_module->macrotable;
- sc->lastdc = dc;
- }
- }
-
- void visit(Declaration *d)
- {
- //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", d, d->toChars(), d->comment);
- //printf("type = %p\n", d->type);
- const utf8_t *com = d->comment;
- if (TemplateDeclaration *td = getEponymousParent(d))
- {
- if (isDitto(td->comment))
- com = td->comment;
- else
- com = Lexer::combineComments(td->comment, com);
- }
- else
- {
- if (!d->ident)
- return;
- if (!d->type && !d->isCtorDeclaration() && !d->isAliasDeclaration())
- return;
- if (d->protection.kind == Prot::private_ || sc->protection.kind == Prot::private_)
- return;
- }
- if (!com)
- return;
-
- emit(sc, d, com);
- }
-
- void visit(AggregateDeclaration *ad)
- {
- //printf("AggregateDeclaration::emitComment() '%s'\n", ad->toChars());
- const utf8_t *com = ad->comment;
- if (TemplateDeclaration *td = getEponymousParent(ad))
- {
- if (isDitto(td->comment))
- com = td->comment;
- else
- com = Lexer::combineComments(td->comment, com);
- }
- else
- {
- if (ad->prot().kind == Prot::private_ || sc->protection.kind == Prot::private_)
- return;
- if (!ad->comment)
- return;
- }
- if (!com)
- return;
-
- emit(sc, ad, com);
- }
-
- void visit(TemplateDeclaration *td)
- {
- //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", td->toChars(), td->kind());
- if (td->prot().kind == Prot::private_ || sc->protection.kind == Prot::private_)
- return;
- if (!td->comment)
- return;
-
- if (Dsymbol *ss = getEponymousMember(td))
- {
- ss->accept(this);
- return;
- }
- emit(sc, td, td->comment);
- }
-
- void visit(EnumDeclaration *ed)
- {
- if (ed->prot().kind == Prot::private_ || sc->protection.kind == Prot::private_)
- return;
- if (ed->isAnonymous() && ed->members)
- {
- for (size_t i = 0; i < ed->members->length; i++)
- {
- Dsymbol *s = (*ed->members)[i];
- emitComment(s, buf, sc);
- }
- return;
- }
- if (!ed->comment)
- return;
- if (ed->isAnonymous())
- return;
-
- emit(sc, ed, ed->comment);
- }
-
- void visit(EnumMember *em)
- {
- //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", em, em->toChars(), em->comment);
- if (em->prot().kind == Prot::private_ || sc->protection.kind == Prot::private_)
- return;
- if (!em->comment)
- return;
-
- emit(sc, em, em->comment);
- }
-
- void visit(AttribDeclaration *ad)
- {
- //printf("AttribDeclaration::emitComment(sc = %p)\n", sc);
-
- /* A general problem with this, illustrated by BUGZILLA 2516,
- * is that attributes are not transmitted through to the underlying
- * member declarations for template bodies, because semantic analysis
- * is not done for template declaration bodies
- * (only template instantiations).
- * Hence, Ddoc omits attributes from template members.
- */
-
- Dsymbols *d = ad->include(NULL);
-
- if (d)
- {
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- //printf("AttribDeclaration::emitComment %s\n", s->toChars());
- emitComment(s, buf, sc);
- }
- }
- }
-
- void visit(ProtDeclaration *pd)
- {
- if (pd->decl)
- {
- Scope *scx = sc;
- sc = sc->copy();
- sc->protection = pd->protection;
- visit((AttribDeclaration *)pd);
- scx->lastdc = sc->lastdc;
- sc = sc->pop();
- }
- }
-
- void visit(ConditionalDeclaration *cd)
- {
- //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc);
- if (cd->condition->inc)
- {
- visit((AttribDeclaration *)cd);
- return;
- }
-
- /* If generating doc comment, be careful because if we're inside
- * a template, then include(NULL) will fail.
- */
- Dsymbols *d = cd->decl ? cd->decl : cd->elsedecl;
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- emitComment(s, buf, sc);
- }
- }
- };
-
- EmitComment v(buf, sc);
-
- if (!s)
- v.emit(sc, NULL, NULL);
- else
- s->accept(&v);
-}
-
-/******************************* toDocBuffer **********************************/
-
-void toDocBuffer(Dsymbol *s, OutBuffer *buf, Scope *sc)
-{
- class ToDocBuffer : public Visitor
- {
- public:
- OutBuffer *buf;
- Scope *sc;
-
- ToDocBuffer(OutBuffer *buf, Scope *sc)
- : buf(buf), sc(sc)
- {
- }
-
- void visit(Dsymbol *s)
- {
- //printf("Dsymbol::toDocbuffer() %s\n", s->toChars());
- HdrGenState hgs;
- hgs.ddoc = true;
- ::toCBuffer(s, buf, &hgs);
- }
-
- void prefix(Dsymbol *s)
- {
- if (s->isDeprecated())
- buf->writestring("deprecated ");
-
- if (Declaration *d = s->isDeclaration())
- {
- emitProtection(buf, d->protection);
-
- if (d->isStatic())
- buf->writestring("static ");
- else if (d->isFinal())
- buf->writestring("final ");
- else if (d->isAbstract())
- buf->writestring("abstract ");
-
- if (!d->isFuncDeclaration()) // functionToBufferFull handles this
- {
- if (d->isConst())
- buf->writestring("const ");
- if (d->isImmutable())
- buf->writestring("immutable ");
- if (d->isSynchronized())
- buf->writestring("synchronized ");
-
- if (d->storage_class & STCmanifest)
- buf->writestring("enum ");
- }
- }
- }
-
- void visit(Declaration *d)
- {
- if (!d->ident)
- return;
-
- TemplateDeclaration *td = getEponymousParent(d);
- //printf("Declaration::toDocbuffer() %s, originalType = %s, td = %s\n", d->toChars(), d->originalType ? d->originalType->toChars() : "--", td ? td->toChars() : "--");
-
- HdrGenState hgs;
- hgs.ddoc = true;
-
- if (d->isDeprecated())
- buf->writestring("$(DEPRECATED ");
-
- prefix(d);
-
- if (d->type)
- {
- Type *origType = d->originalType ? d->originalType : d->type;
- if (origType->ty == Tfunction)
- {
- functionToBufferFull((TypeFunction *)origType, buf, d->ident, &hgs, td);
- }
- else
- ::toCBuffer(origType, buf, d->ident, &hgs);
- }
- else
- buf->writestring(d->ident->toChars());
-
- if (d->isVarDeclaration() && td)
- {
- buf->writeByte('(');
- if (td->origParameters && td->origParameters->length)
- {
- for (size_t i = 0; i < td->origParameters->length; i++)
- {
- if (i)
- buf->writestring(", ");
- toCBuffer((*td->origParameters)[i], buf, &hgs);
- }
- }
- buf->writeByte(')');
- }
-
- // emit constraints if declaration is a templated declaration
- if (td && td->constraint)
- {
- buf->writestring(" if (");
- ::toCBuffer(td->constraint, buf, &hgs);
- buf->writeByte(')');
- }
-
- if (d->isDeprecated())
- buf->writestring(")");
-
- buf->writestring(";\n");
- }
-
- void visit(AliasDeclaration *ad)
- {
- //printf("AliasDeclaration::toDocbuffer() %s\n", ad->toChars());
- if (!ad->ident)
- return;
-
- if (ad->isDeprecated())
- buf->writestring("deprecated ");
-
- emitProtection(buf, ad->protection);
- buf->printf("alias %s = ", ad->toChars());
-
- if (Dsymbol *sa = ad->aliassym) // ident alias
- {
- prettyPrintDsymbol(sa, ad->parent);
- }
- else if (Type *type = ad->getType()) // type alias
- {
- if (type->ty == Tclass || type->ty == Tstruct || type->ty == Tenum)
- {
- if (Dsymbol *s = type->toDsymbol(NULL)) // elaborate type
- prettyPrintDsymbol(s, ad->parent);
- else
- buf->writestring(type->toChars());
- }
- else
- {
- // simple type
- buf->writestring(type->toChars());
- }
- }
-
- buf->writestring(";\n");
- }
-
- void parentToBuffer(Dsymbol *s)
- {
- if (s && !s->isPackage() && !s->isModule())
- {
- parentToBuffer(s->parent);
- buf->writestring(s->toChars());
- buf->writestring(".");
- }
- }
-
- static bool inSameModule(Dsymbol *s, Dsymbol *p)
- {
- for ( ; s ; s = s->parent)
- {
- if (s->isModule())
- break;
- }
-
- for ( ; p ; p = p->parent)
- {
- if (p->isModule())
- break;
- }
-
- return s == p;
- }
-
- void prettyPrintDsymbol(Dsymbol *s, Dsymbol *parent)
- {
- if (s->parent && (s->parent == parent)) // in current scope -> naked name
- {
- buf->writestring(s->toChars());
- }
- else if (!inSameModule(s, parent)) // in another module -> full name
- {
- buf->writestring(s->toPrettyChars());
- }
- else // nested in a type in this module -> full name w/o module name
- {
- // if alias is nested in a user-type use module-scope lookup
- if (!parent->isModule() && !parent->isPackage())
- buf->writestring(".");
-
- parentToBuffer(s->parent);
- buf->writestring(s->toChars());
- }
- }
-
- void visit(AggregateDeclaration *ad)
- {
- if (!ad->ident)
- return;
-
- buf->printf("%s %s", ad->kind(), ad->toChars());
- buf->writestring(";\n");
- }
-
- void visit(StructDeclaration *sd)
- {
- //printf("StructDeclaration::toDocbuffer() %s\n", sd->toChars());
- if (!sd->ident)
- return;
-
- if (TemplateDeclaration *td = getEponymousParent(sd))
- {
- toDocBuffer(td, buf, sc);
- }
- else
- {
- buf->printf("%s %s", sd->kind(), sd->toChars());
- }
- buf->writestring(";\n");
- }
-
- void visit(ClassDeclaration *cd)
- {
- //printf("ClassDeclaration::toDocbuffer() %s\n", cd->toChars());
- if (!cd->ident)
- return;
-
- if (TemplateDeclaration *td = getEponymousParent(cd))
- {
- toDocBuffer(td, buf, sc);
- }
- else
- {
- if (!cd->isInterfaceDeclaration() && cd->isAbstract())
- buf->writestring("abstract ");
- buf->printf("%s %s", cd->kind(), cd->toChars());
- }
- int any = 0;
- for (size_t i = 0; i < cd->baseclasses->length; i++)
- {
- BaseClass *bc = (*cd->baseclasses)[i];
-
- if (bc->sym && bc->sym->ident == Id::Object)
- continue;
-
- if (any)
- buf->writestring(", ");
- else
- {
- buf->writestring(": ");
- any = 1;
- }
- emitProtection(buf, Prot(Prot::public_));
- if (bc->sym)
- {
- buf->printf("$(DDOC_PSUPER_SYMBOL %s)", bc->sym->toPrettyChars());
- }
- else
- {
- HdrGenState hgs;
- ::toCBuffer(bc->type, buf, NULL, &hgs);
- }
- }
- buf->writestring(";\n");
- }
-
- void visit(EnumDeclaration *ed)
- {
- if (!ed->ident)
- return;
-
- buf->printf("%s %s", ed->kind(), ed->toChars());
- if (ed->memtype)
- {
- buf->writestring(": $(DDOC_ENUM_BASETYPE ");
- HdrGenState hgs;
- ::toCBuffer(ed->memtype, buf, NULL, &hgs);
- buf->writestring(")");
- }
- buf->writestring(";\n");
- }
-
- void visit(EnumMember *em)
- {
- if (!em->ident)
- return;
-
- buf->writestring(em->toChars());
- }
- };
-
- ToDocBuffer v(buf, sc);
- s->accept(&v);
-}
-
-/********************************* DocComment *********************************/
-
-DocComment *DocComment::parse(Dsymbol *s, const utf8_t *comment)
-{
- //printf("parse(%s): '%s'\n", s->toChars(), comment);
- DocComment *dc = new DocComment();
- dc->a.push(s);
- if (!comment)
- return dc;
-
- dc->parseSections(comment);
-
- for (size_t i = 0; i < dc->sections.length; i++)
- {
- Section *sec = dc->sections[i];
-
- if (icmp("copyright", sec->name, sec->namelen) == 0)
- {
- dc->copyright = sec;
- }
- if (icmp("macros", sec->name, sec->namelen) == 0)
- {
- dc->macros = sec;
- }
- }
-
- return dc;
-}
-
-/*****************************************
- * Parse next paragraph out of *pcomment.
- * Update *pcomment to point past paragraph.
- * Returns NULL if no more paragraphs.
- * If paragraph ends in 'identifier:',
- * then (*pcomment)[0 .. idlen] is the identifier.
- */
-
-void DocComment::parseSections(const utf8_t *comment)
-{
- const utf8_t *p;
- const utf8_t *pstart;
- const utf8_t *pend;
- const utf8_t *idstart = NULL; // dead-store to prevent spurious warning
- size_t idlen;
-
- const utf8_t *name = NULL;
- size_t namelen = 0;
-
- //printf("parseSections('%s')\n", comment);
- p = comment;
- while (*p)
- {
- const utf8_t *pstart0 = p;
- p = skipwhitespace(p);
- pstart = p;
- pend = p;
-
- /* Find end of section, which is ended by one of:
- * 'identifier:' (but not inside a code section)
- * '\0'
- */
- idlen = 0;
- int inCode = 0;
- while (1)
- {
- // Check for start/end of a code section
- if (*p == '-')
- {
- if (!inCode)
- {
- // restore leading indentation
- while (pstart0 < pstart && isIndentWS(pstart-1)) --pstart;
- }
-
- int numdash = 0;
- while (*p == '-')
- {
- ++numdash;
- p++;
- }
- // BUG: handle UTF PS and LS too
- if ((!*p || *p == '\r' || *p == '\n') && numdash >= 3)
- inCode ^= 1;
- pend = p;
- }
-
- if (!inCode && isIdStart(p))
- {
- const utf8_t *q = p + utfStride(p);
- while (isIdTail(q))
- q += utfStride(q);
- // Detected tag ends it
- if (*q == ':' && isupper(*p)
- && (isspace(q[1]) || q[1] == 0))
- {
- idlen = q - p;
- idstart = p;
- for (pend = p; pend > pstart; pend--)
- {
- if (pend[-1] == '\n')
- break;
- }
- p = q + 1;
- break;
- }
- }
- while (1)
- {
- if (!*p)
- goto L1;
- if (*p == '\n')
- {
- p++;
- if (*p == '\n' && !summary && !namelen && !inCode)
- {
- pend = p;
- p++;
- goto L1;
- }
- break;
- }
- p++;
- pend = p;
- }
- p = skipwhitespace(p);
- }
- L1:
-
- if (namelen || pstart < pend)
- {
- Section *s;
- if (icmp("Params", name, namelen) == 0)
- s = new ParamSection();
- else if (icmp("Macros", name, namelen) == 0)
- s = new MacroSection();
- else
- s = new Section();
- s->name = name;
- s->namelen = namelen;
- s->body = pstart;
- s->bodylen = pend - pstart;
- s->nooutput = 0;
-
- //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body);
-
- sections.push(s);
-
- if (!summary && !namelen)
- summary = s;
- }
-
- if (idlen)
- {
- name = idstart;
- namelen = idlen;
- }
- else
- {
- name = NULL;
- namelen = 0;
- if (!*p)
- break;
- }
- }
-}
-
-void DocComment::writeSections(Scope *sc, Dsymbols *a, OutBuffer *buf)
-{
- assert(a->length);
-
- //printf("DocComment::writeSections()\n");
- Loc loc = (*a)[0]->loc;
- if (Module *m = (*a)[0]->isModule())
- {
- if (m->md)
- loc = m->md->loc;
- }
-
- size_t offset1 = buf->length();
- buf->writestring("$(DDOC_SECTIONS ");
- size_t offset2 = buf->length();
-
- for (size_t i = 0; i < sections.length; i++)
- {
- Section *sec = sections[i];
- if (sec->nooutput)
- continue;
-
- //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body);
- if (!sec->namelen && i == 0)
- {
- buf->writestring("$(DDOC_SUMMARY ");
- size_t o = buf->length();
- buf->write(sec->body, sec->bodylen);
- escapeStrayParenthesis(loc, buf, o);
- highlightText(sc, a, buf, o);
- buf->writestring(")\n");
- }
- else
- sec->write(loc, this, sc, a, buf);
- }
-
- for (size_t i = 0; i < a->length; i++)
- {
- Dsymbol *s = (*a)[i];
- if (Dsymbol *td = getEponymousParent(s))
- s = td;
-
- for (UnitTestDeclaration *utd = s->ddocUnittest; utd; utd = utd->ddocUnittest)
- {
- if (utd->protection.kind == Prot::private_ || !utd->comment || !utd->fbody)
- continue;
-
- // Strip whitespaces to avoid showing empty summary
- const utf8_t *c = utd->comment;
- while (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r') ++c;
-
- buf->writestring("$(DDOC_EXAMPLES ");
-
- size_t o = buf->length();
- buf->writestring((const char *)c);
-
- if (utd->codedoc)
- {
- size_t n = getCodeIndent(utd->codedoc);
- while (n--) buf->writeByte(' ');
- buf->writestring("----\n");
- buf->writestring(utd->codedoc);
- buf->writestring("----\n");
- highlightText(sc, a, buf, o);
- }
-
- buf->writestring(")");
- }
- }
-
- if (buf->length() == offset2)
- {
- /* Didn't write out any sections, so back out last write
- */
- buf->setsize(offset1);
- buf->writestring("$(DDOC_BLANKLINE)\n");
- }
- else
- buf->writestring(")\n");
-}
-
-/***************************************************
- */
-
-void Section::write(Loc loc, DocComment *, Scope *sc, Dsymbols *a, OutBuffer *buf)
-{
- assert(a->length);
-
- if (namelen)
- {
- static const char *table[] =
- {
- "AUTHORS", "BUGS", "COPYRIGHT", "DATE",
- "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE",
- "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS",
- "VERSION", NULL
- };
-
- for (size_t i = 0; table[i]; i++)
- {
- if (icmp(table[i], name, namelen) == 0)
- {
- buf->printf("$(DDOC_%s ", table[i]);
- goto L1;
- }
- }
-
- buf->writestring("$(DDOC_SECTION ");
-
- // Replace _ characters with spaces
- buf->writestring("$(DDOC_SECTION_H ");
- size_t o = buf->length();
- for (size_t u = 0; u < namelen; u++)
- {
- utf8_t c = name[u];
- buf->writeByte((c == '_') ? ' ' : c);
- }
- escapeStrayParenthesis(loc, buf, o);
- buf->writestring(":)\n");
- }
- else
- {
- buf->writestring("$(DDOC_DESCRIPTION ");
- }
- L1:
- size_t o = buf->length();
- buf->write(body, bodylen);
- escapeStrayParenthesis(loc, buf, o);
- highlightText(sc, a, buf, o);
- buf->writestring(")\n");
-}
-
-/***************************************************
- */
-
-void ParamSection::write(Loc loc, DocComment *, Scope *sc, Dsymbols *a, OutBuffer *buf)
-{
- assert(a->length);
- Dsymbol *s = (*a)[0]; // test
-
- const utf8_t *p = body;
- size_t len = bodylen;
- const utf8_t *pend = p + len;
-
- const utf8_t *tempstart = NULL;
- size_t templen = 0;
-
- const utf8_t *namestart = NULL;
- size_t namelen = 0; // !=0 if line continuation
-
- const utf8_t *textstart = NULL;
- size_t textlen = 0;
-
- size_t paramcount = 0;
-
- buf->writestring("$(DDOC_PARAMS ");
- while (p < pend)
- {
- // Skip to start of macro
- while (1)
- {
- switch (*p)
- {
- case ' ':
- case '\t':
- p++;
- continue;
-
- case '\n':
- p++;
- goto Lcont;
-
- default:
- if (isIdStart(p) || isCVariadicArg(p, pend - p))
- break;
- if (namelen)
- goto Ltext; // continuation of prev macro
- goto Lskipline;
- }
- break;
- }
- tempstart = p;
-
- while (isIdTail(p))
- p += utfStride(p);
- if (isCVariadicArg(p, pend - p))
- p += 3;
-
- templen = p - tempstart;
-
- while (*p == ' ' || *p == '\t')
- p++;
-
- if (*p != '=')
- {
- if (namelen)
- goto Ltext; // continuation of prev macro
- goto Lskipline;
- }
- p++;
-
- if (namelen)
- {
- // Output existing param
-
- L1:
- //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart);
- ++paramcount;
- HdrGenState hgs;
- buf->writestring("$(DDOC_PARAM_ROW ");
- {
- buf->writestring("$(DDOC_PARAM_ID ");
- {
- size_t o = buf->length();
- Parameter *fparam = isFunctionParameter(a, namestart, namelen);
- if (!fparam)
- {
- // Comments on a template might refer to function parameters within.
- // Search the parameters of nested eponymous functions (with the same name.)
- fparam = isEponymousFunctionParameter(a, namestart, namelen);
- }
- bool isCVariadic = isCVariadicParameter(a, namestart, namelen);
- if (isCVariadic)
- {
- buf->writestring("...");
- }
- else if (fparam && fparam->type && fparam->ident)
- {
- ::toCBuffer(fparam->type, buf, fparam->ident, &hgs);
- }
- else
- {
- if (isTemplateParameter(a, namestart, namelen))
- {
- // 10236: Don't count template parameters for params check
- --paramcount;
- }
- else if (!fparam)
- {
- warning(s->loc, "Ddoc: function declaration has no parameter '%.*s'", (int)namelen, namestart);
- }
- buf->write(namestart, namelen);
- }
- escapeStrayParenthesis(loc, buf, o);
- highlightCode(sc, a, buf, o);
- }
- buf->writestring(")\n");
-
- buf->writestring("$(DDOC_PARAM_DESC ");
- {
- size_t o = buf->length();
- buf->write(textstart, textlen);
- escapeStrayParenthesis(loc, buf, o);
- highlightText(sc, a, buf, o);
- }
- buf->writestring(")");
- }
- buf->writestring(")\n");
- namelen = 0;
- if (p >= pend)
- break;
- }
-
- namestart = tempstart;
- namelen = templen;
-
- while (*p == ' ' || *p == '\t')
- p++;
- textstart = p;
-
- Ltext:
- while (*p != '\n')
- p++;
- textlen = p - textstart;
- p++;
-
- Lcont:
- continue;
-
- Lskipline:
- // Ignore this line
- while (*p++ != '\n')
- ;
- }
- if (namelen)
- goto L1; // write out last one
- buf->writestring(")\n");
-
- TypeFunction *tf = a->length == 1 ? isTypeFunction(s) : NULL;
- if (tf)
- {
- size_t pcount = (tf->parameterList.parameters ? tf->parameterList.parameters->length : 0) +
- (int)(tf->parameterList.varargs == VARARGvariadic);
- if (pcount != paramcount)
- {
- warning(s->loc, "Ddoc: parameter count mismatch");
- }
- }
-}
-
-/***************************************************
- */
-
-void MacroSection::write(Loc, DocComment *dc, Scope *, Dsymbols *, OutBuffer *)
-{
- //printf("MacroSection::write()\n");
- DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen);
-}
-
-/************************************************
- * Parse macros out of Macros: section.
- * Macros are of the form:
- * name1 = value1
- *
- * name2 = value2
- */
-
-void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, const utf8_t *m, size_t mlen)
-{
- const utf8_t *p = m;
- size_t len = mlen;
- const utf8_t *pend = p + len;
-
- const utf8_t *tempstart = NULL;
- size_t templen = 0;
-
- const utf8_t *namestart = NULL;
- size_t namelen = 0; // !=0 if line continuation
-
- const utf8_t *textstart = NULL;
- size_t textlen = 0;
-
- while (p < pend)
- {
- // Skip to start of macro
- while (1)
- {
- if (p >= pend)
- goto Ldone;
- switch (*p)
- {
- case ' ':
- case '\t':
- p++;
- continue;
-
- case '\r':
- case '\n':
- p++;
- goto Lcont;
-
- default:
- if (isIdStart(p))
- break;
- if (namelen)
- goto Ltext; // continuation of prev macro
- goto Lskipline;
- }
- break;
- }
- tempstart = p;
-
- while (1)
- {
- if (p >= pend)
- goto Ldone;
- if (!isIdTail(p))
- break;
- p += utfStride(p);
- }
- templen = p - tempstart;
-
- while (1)
- {
- if (p >= pend)
- goto Ldone;
- if (!(*p == ' ' || *p == '\t'))
- break;
- p++;
- }
-
- if (*p != '=')
- {
- if (namelen)
- goto Ltext; // continuation of prev macro
- goto Lskipline;
- }
- p++;
- if (p >= pend)
- goto Ldone;
-
- if (namelen)
- {
- // Output existing macro
- L1:
- //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart);
- if (icmp("ESCAPES", namestart, namelen) == 0)
- parseEscapes(pescapetable, textstart, textlen);
- else
- Macro::define(pmacrotable, namestart, namelen, textstart, textlen);
- namelen = 0;
- if (p >= pend)
- break;
- }
-
- namestart = tempstart;
- namelen = templen;
-
- while (p < pend && (*p == ' ' || *p == '\t'))
- p++;
- textstart = p;
-
- Ltext:
- while (p < pend && *p != '\r' && *p != '\n')
- p++;
- textlen = p - textstart;
-
- p++;
- //printf("p = %p, pend = %p\n", p, pend);
-
- Lcont:
- continue;
-
- Lskipline:
- // Ignore this line
- while (p < pend && *p != '\r' && *p != '\n')
- p++;
- }
-Ldone:
- if (namelen)
- goto L1; // write out last one
-}
-
-/**************************************
- * Parse escapes of the form:
- * /c/string/
- * where c is a single character.
- * Multiple escapes can be separated
- * by whitespace and/or commas.
- */
-
-void DocComment::parseEscapes(Escape **pescapetable, const utf8_t *textstart, size_t textlen)
-{
- Escape *escapetable = *pescapetable;
-
- if (!escapetable)
- {
- escapetable = new Escape;
- memset(escapetable, 0, sizeof(Escape));
- *pescapetable = escapetable;
- }
- //printf("parseEscapes('%.*s') pescapetable = %p\n", textlen, textstart, pescapetable);
- const utf8_t *p = textstart;
- const utf8_t *pend = p + textlen;
-
- while (1)
- {
- while (1)
- {
- if (p + 4 >= pend)
- return;
- if (!(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == ','))
- break;
- p++;
- }
- if (p[0] != '/' || p[2] != '/')
- return;
- utf8_t c = p[1];
- p += 3;
- const utf8_t *start = p;
- while (1)
- {
- if (p >= pend)
- return;
- if (*p == '/')
- break;
- p++;
- }
- size_t len = p - start;
- char *s = (char *)memcpy(mem.xmalloc(len + 1), start, len);
- s[len] = 0;
- escapetable->strings[c] = s;
- //printf("\t%c = '%s'\n", c, s);
- p++;
- }
-}
-
-
-/******************************************
- * Compare 0-terminated string with length terminated string.
- * Return < 0, ==0, > 0
- */
-
-int cmp(const char *stringz, const void *s, size_t slen)
-{
- size_t len1 = strlen(stringz);
-
- if (len1 != slen)
- return (int)(len1 - slen);
- return memcmp(stringz, s, slen);
-}
-
-int icmp(const char *stringz, const void *s, size_t slen)
-{
- size_t len1 = strlen(stringz);
-
- if (len1 != slen)
- return (int)(len1 - slen);
- return Port::memicmp(stringz, (const char *)s, slen);
-}
-
-/*****************************************
- * Return true if comment consists entirely of "ditto".
- */
-
-bool isDitto(const utf8_t *comment)
-{
- if (comment)
- {
- const utf8_t *p = skipwhitespace(comment);
-
- if (Port::memicmp((const char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0)
- return true;
- }
- return false;
-}
-
-/**********************************************
- * Skip white space.
- */
-
-const utf8_t *skipwhitespace(const utf8_t *p)
-{
- for (; 1; p++)
- {
- switch (*p)
- {
- case ' ':
- case '\t':
- case '\n':
- continue;
- }
- break;
- }
- return p;
-}
-
-
-/************************************************
- * Scan forward to one of:
- * start of identifier
- * beginning of next line
- * end of buf
- */
-
-size_t skiptoident(OutBuffer *buf, size_t i)
-{
- while (i < buf->length())
- {
- dchar_t c;
-
- size_t oi = i;
- if (utf_decodeChar((utf8_t *)buf->slice().ptr, buf->length(), &i, &c))
- {
- /* Ignore UTF errors, but still consume input
- */
- break;
- }
- if (c >= 0x80)
- {
- if (!isUniAlpha(c))
- continue;
- }
- else if (!(isalpha(c) || c == '_' || c == '\n'))
- continue;
- i = oi;
- break;
- }
- return i;
-}
-
-/************************************************
- * Scan forward past end of identifier.
- */
-
-size_t skippastident(OutBuffer *buf, size_t i)
-{
- while (i < buf->length())
- {
- dchar_t c;
-
- size_t oi = i;
- if (utf_decodeChar((utf8_t *)buf->slice().ptr, buf->length(), &i, &c))
- {
- /* Ignore UTF errors, but still consume input
- */
- break;
- }
- if (c >= 0x80)
- {
- if (isUniAlpha(c))
- continue;
- }
- else if (isalnum(c) || c == '_')
- continue;
- i = oi;
- break;
- }
- return i;
-}
-
-
-/************************************************
- * Scan forward past URL starting at i.
- * We don't want to highlight parts of a URL.
- * Returns:
- * i if not a URL
- * index just past it if it is a URL
- */
-
-size_t skippastURL(OutBuffer *buf, size_t i)
-{
- size_t length = buf->length() - i;
- utf8_t *p = (utf8_t *)&buf->slice().ptr[i];
- size_t j;
- unsigned sawdot = 0;
-
- if (length > 7 && Port::memicmp((char *)p, "http://", 7) == 0)
- {
- j = 7;
- }
- else if (length > 8 && Port::memicmp((char *)p, "https://", 8) == 0)
- {
- j = 8;
- }
- else
- goto Lno;
-
- for (; j < length; j++)
- {
- utf8_t c = p[j];
- if (isalnum(c))
- continue;
- if (c == '-' || c == '_' || c == '?' ||
- c == '=' || c == '%' || c == '&' ||
- c == '/' || c == '+' || c == '#' ||
- c == '~')
- continue;
- if (c == '.')
- {
- sawdot = 1;
- continue;
- }
- break;
- }
- if (sawdot)
- return i + j;
-
-Lno:
- return i;
-}
-
-
-/****************************************************
- */
-
-bool isIdentifier(Dsymbols *a, const utf8_t *p, size_t len)
-{
- for (size_t i = 0; i < a->length; i++)
- {
- const char *s = (*a)[i]->ident->toChars();
- if (cmp(s, p, len) == 0)
- return true;
- }
- return false;
-}
-
-/****************************************************
- */
-
-bool isKeyword(utf8_t *p, size_t len)
-{
- static const char *table[] = { "true", "false", "null", NULL };
-
- for (int i = 0; table[i]; i++)
- {
- if (cmp(table[i], p, len) == 0)
- return true;
- }
- return false;
-}
-
-/****************************************************
- */
-
-TypeFunction *isTypeFunction(Dsymbol *s)
-{
- FuncDeclaration *f = s->isFuncDeclaration();
-
- /* f->type may be NULL for template members.
- */
- if (f && f->type)
- {
- Type *t = f->originalType ? f->originalType : f->type;
- if (t->ty == Tfunction)
- return (TypeFunction *)t;
- }
- return NULL;
-}
-
-/****************************************************
- */
-
-Parameter *isFunctionParameter(Dsymbols *a, const utf8_t *p, size_t len)
-{
- for (size_t i = 0; i < a->length; i++)
- {
- Parameter *fparam = isFunctionParameter((*a)[i], p, len);
- if (fparam)
- {
- return fparam;
- }
- }
- return NULL;
-}
-
-/****************************************************
- */
-
-TemplateParameter *isTemplateParameter(Dsymbols *a, const utf8_t *p, size_t len)
-{
- for (size_t i = 0; i < a->length; i++)
- {
- TemplateDeclaration *td = (*a)[i]->isTemplateDeclaration();
- // Check for the parent, if the current symbol is not a template declaration.
- if (!td)
- td = getEponymousParent((*a)[i]);
- if (td && td->origParameters)
- {
- for (size_t k = 0; k < td->origParameters->length; k++)
- {
- TemplateParameter *tp = (*td->origParameters)[k];
- if (tp->ident && cmp(tp->ident->toChars(), p, len) == 0)
- {
- return tp;
- }
- }
- }
- }
- return NULL;
-}
-
-/****************************************************
- * Return true if str is a reserved symbol name
- * that starts with a double underscore.
- */
-
-bool isReservedName(utf8_t *str, size_t len)
-{
- static const char *table[] = {
- "__ctor", "__dtor", "__postblit", "__invariant", "__unitTest",
- "__require", "__ensure", "__dollar", "__ctfe", "__withSym", "__result",
- "__returnLabel", "__vptr", "__monitor", "__gate", "__xopEquals", "__xopCmp",
- "__LINE__", "__FILE__", "__MODULE__", "__FUNCTION__", "__PRETTY_FUNCTION__",
- "__DATE__", "__TIME__", "__TIMESTAMP__", "__VENDOR__", "__VERSION__",
- "__EOF__", "__LOCAL_SIZE", "___tls_get_addr", "__entrypoint", NULL };
-
- for (int i = 0; table[i]; i++)
- {
- if (cmp(table[i], str, len) == 0)
- return true;
- }
- return false;
-}
-
-/**************************************************
- * Highlight text section.
- */
-
-void highlightText(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset)
-{
- Dsymbol *s = a->length ? (*a)[0] : NULL; // test
-
- //printf("highlightText()\n");
-
- int leadingBlank = 1;
- int inCode = 0;
- int inBacktick = 0;
- //int inComment = 0; // in <!-- ... --> comment
- size_t iCodeStart = 0; // start of code section
- size_t codeIndent = 0;
-
- size_t iLineStart = offset;
-
- for (size_t i = offset; i < buf->length(); i++)
- {
- utf8_t c = buf->slice().ptr[i];
-
- Lcont:
- switch (c)
- {
- case ' ':
- case '\t':
- break;
-
- case '\n':
- if (inBacktick)
- {
- // `inline code` is only valid if contained on a single line
- // otherwise, the backticks should be output literally.
- //
- // This lets things like `output from the linker' display
- // unmolested while keeping the feature consistent with GitHub.
-
- inBacktick = false;
- inCode = false; // the backtick also assumes we're in code
-
- // Nothing else is necessary since the DDOC_BACKQUOTED macro is
- // inserted lazily at the close quote, meaning the rest of the
- // text is already OK.
- }
-
- if (!sc->_module->isDocFile &&
- !inCode && i == iLineStart && i + 1 < buf->length()) // if "\n\n"
- {
- static const char blankline[] = "$(DDOC_BLANKLINE)\n";
-
- i = buf->insert(i, blankline, strlen(blankline));
- }
- leadingBlank = 1;
- iLineStart = i + 1;
- break;
-
- case '<':
- {
- leadingBlank = 0;
- if (inCode)
- break;
- utf8_t *p = (utf8_t *)&buf->slice().ptr[i];
- const char *se = sc->_module->escapetable->escapeChar('<');
- if (se && strcmp(se, "&lt;") == 0)
- {
- // Generating HTML
- // Skip over comments
- if (p[1] == '!' && p[2] == '-' && p[3] == '-')
- {
- size_t j = i + 4;
- p += 4;
- while (1)
- {
- if (j == buf->length())
- goto L1;
- if (p[0] == '-' && p[1] == '-' && p[2] == '>')
- {
- i = j + 2; // place on closing '>'
- break;
- }
- j++;
- p++;
- }
- break;
- }
-
- // Skip over HTML tag
- if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2])))
- {
- size_t j = i + 2;
- p += 2;
- while (1)
- {
- if (j == buf->length())
- break;
- if (p[0] == '>')
- {
- i = j; // place on closing '>'
- break;
- }
- j++;
- p++;
- }
- break;
- }
- }
- L1:
- // Replace '<' with '&lt;' character entity
- if (se)
- {
- size_t len = strlen(se);
- buf->remove(i, 1);
- i = buf->insert(i, se, len);
- i--; // point to ';'
- }
- break;
- }
- case '>':
- {
- leadingBlank = 0;
- if (inCode)
- break;
- // Replace '>' with '&gt;' character entity
- const char *se = sc->_module->escapetable->escapeChar('>');
- if (se)
- {
- size_t len = strlen(se);
- buf->remove(i, 1);
- i = buf->insert(i, se, len);
- i--; // point to ';'
- }
- break;
- }
- case '&':
- {
- leadingBlank = 0;
- if (inCode)
- break;
- utf8_t *p = (utf8_t *)&buf->slice().ptr[i];
- if (p[1] == '#' || isalpha(p[1]))
- break; // already a character entity
- // Replace '&' with '&amp;' character entity
- const char *se = sc->_module->escapetable->escapeChar('&');
- if (se)
- {
- size_t len = strlen(se);
- buf->remove(i, 1);
- i = buf->insert(i, se, len);
- i--; // point to ';'
- }
- break;
- }
- case '`':
- {
- if (inBacktick)
- {
- inBacktick = 0;
- inCode = 0;
-
- OutBuffer codebuf;
-
- codebuf.write(buf->slice().ptr + iCodeStart + 1, i - (iCodeStart + 1));
-
- // escape the contents, but do not perform highlighting except for DDOC_PSYMBOL
- highlightCode(sc, a, &codebuf, 0);
-
- buf->remove(iCodeStart, i - iCodeStart + 1); // also trimming off the current `
-
- static const char pre[] = "$(DDOC_BACKQUOTED ";
- i = buf->insert(iCodeStart, pre, strlen(pre));
- i = buf->insert(i, (char *)codebuf.slice().ptr, codebuf.length());
- i = buf->insert(i, ")", 1);
-
- i--; // point to the ending ) so when the for loop does i++, it will see the next character
-
- break;
- }
-
- if (inCode)
- break;
-
- inCode = 1;
- inBacktick = 1;
- codeIndent = 0; // inline code is not indented
-
- // All we do here is set the code flags and record
- // the location. The macro will be inserted lazily
- // so we can easily cancel the inBacktick if we come
- // across a newline character.
- iCodeStart = i;
-
- break;
- }
- case '-':
- /* A line beginning with --- delimits a code section.
- * inCode tells us if it is start or end of a code section.
- */
- if (leadingBlank)
- {
- size_t istart = i;
- size_t eollen = 0;
-
- leadingBlank = 0;
- while (1)
- {
- ++i;
- if (i >= buf->length())
- break;
- c = buf->slice().ptr[i];
- if (c == '\n')
- {
- eollen = 1;
- break;
- }
- if (c == '\r')
- {
- eollen = 1;
- if (i + 1 >= buf->length())
- break;
- if (buf->slice().ptr[i + 1] == '\n')
- {
- eollen = 2;
- break;
- }
- }
- // BUG: handle UTF PS and LS too
- if (c != '-')
- goto Lcont;
- }
- if (i - istart < 3)
- goto Lcont;
-
- // We have the start/end of a code section
-
- // Remove the entire --- line, including blanks and \n
- buf->remove(iLineStart, i - iLineStart + eollen);
- i = iLineStart;
-
- if (inCode && (i <= iCodeStart))
- {
- // Empty code section, just remove it completely.
- inCode = 0;
- break;
- }
-
- if (inCode)
- {
- inCode = 0;
- // The code section is from iCodeStart to i
- OutBuffer codebuf;
-
- codebuf.write(buf->slice().ptr + iCodeStart, i - iCodeStart);
- codebuf.writeByte(0);
-
- // Remove leading indentations from all lines
- bool lineStart = true;
- utf8_t *endp = (utf8_t *)codebuf.slice().ptr + codebuf.length();
- for (utf8_t *p = (utf8_t *)codebuf.slice().ptr; p < endp; )
- {
- if (lineStart)
- {
- size_t j = codeIndent;
- utf8_t *q = p;
- while (j-- > 0 && q < endp && isIndentWS(q))
- ++q;
- codebuf.remove(p - (utf8_t *)codebuf.slice().ptr, q - p);
- assert((utf8_t *)codebuf.slice().ptr <= p);
- assert(p < (utf8_t *)codebuf.slice().ptr + codebuf.length());
- lineStart = false;
- endp = (utf8_t *)codebuf.slice().ptr + codebuf.length(); // update
- continue;
- }
- if (*p == '\n')
- lineStart = true;
- ++p;
- }
-
- highlightCode2(sc, a, &codebuf, 0);
- buf->remove(iCodeStart, i - iCodeStart);
- i = buf->insert(iCodeStart, codebuf.slice().ptr, codebuf.length());
- i = buf->insert(i, (const char *)")\n", 2);
- i -= 2; // in next loop, c should be '\n'
- }
- else
- {
- static const char d_code[] = "$(D_CODE ";
-
- inCode = 1;
- codeIndent = istart - iLineStart; // save indent count
- i = buf->insert(i, d_code, strlen(d_code));
- iCodeStart = i;
- i--; // place i on >
- leadingBlank = true;
- }
- }
- break;
-
- default:
- leadingBlank = 0;
- if (sc->_module->isDocFile || inCode)
- break;
-
- utf8_t *start = (utf8_t *)buf->slice().ptr + i;
- if (isIdStart(start))
- {
- size_t j = skippastident(buf, i);
- if (i < j)
- {
- size_t k = skippastURL(buf, i);
- if (i < k)
- {
- i = k - 1;
- break;
- }
- }
- else
- break;
- size_t len = j - i;
-
- // leading '_' means no highlight unless it's a reserved symbol name
- if (c == '_' &&
- (i == 0 || !isdigit(*(start - 1))) &&
- (i == buf->length() - 1 || !isReservedName(start, len)))
- {
- buf->remove(i, 1);
- i = j - 1;
- break;
- }
- if (isIdentifier(a, start, len))
- {
- i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1;
- break;
- }
- if (isKeyword(start, len))
- {
- i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1;
- break;
- }
- if (isFunctionParameter(a, start, len))
- {
- //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
- i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1;
- break;
- }
-
- i = j - 1;
- }
- break;
- }
- }
- if (inCode)
- error(s ? s->loc : Loc(), "unmatched --- in DDoc comment");
-}
-
-/**************************************************
- * Highlight code for DDOC section.
- */
-
-void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, size_t offset)
-{
- //printf("highlightCode(s = %s '%s')\n", s->kind(), s->toChars());
- OutBuffer ancbuf;
- emitAnchor(&ancbuf, s, sc);
- buf->insert(offset, (char *)ancbuf.slice().ptr, ancbuf.length());
- offset += ancbuf.length();
-
- Dsymbols a;
- a.push(s);
- highlightCode(sc, &a, buf, offset);
-}
-
-/****************************************************
- */
-
-void highlightCode(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset)
-{
- //printf("highlightCode(a = '%s')\n", a->toChars());
-
- for (size_t i = offset; i < buf->length(); i++)
- {
- utf8_t c = buf->slice().ptr[i];
- const char *se = sc->_module->escapetable->escapeChar(c);
- if (se)
- {
- size_t len = strlen(se);
- buf->remove(i, 1);
- i = buf->insert(i, se, len);
- i--; // point to ';'
- continue;
- }
-
- utf8_t *start = (utf8_t *)buf->slice().ptr + i;
- if (isIdStart(start))
- {
- size_t j = skippastident(buf, i);
- if (i < j)
- {
- size_t len = j - i;
- if (isIdentifier(a, start, len))
- {
- i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1;
- continue;
- }
- if (isFunctionParameter(a, start, len))
- {
- //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
- i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1;
- continue;
- }
- i = j - 1;
- }
- }
- }
-}
-
-/****************************************
- */
-
-void highlightCode3(Scope *sc, OutBuffer *buf, const utf8_t *p, const utf8_t *pend)
-{
- for (; p < pend; p++)
- {
- const char *s = sc->_module->escapetable->escapeChar(*p);
- if (s)
- buf->writestring(s);
- else
- buf->writeByte(*p);
- }
-}
-
-/**************************************************
- * Highlight code for CODE section.
- */
-
-void highlightCode2(Scope *sc, Dsymbols *a, OutBuffer *buf, size_t offset)
-{
- unsigned errorsave = global.errors;
- Lexer lex(NULL, (utf8_t *)buf->slice().ptr, 0, buf->length() - 1, 0, 1);
- OutBuffer res;
- const utf8_t *lastp = (utf8_t *)buf->slice().ptr;
-
- //printf("highlightCode2('%.*s')\n", buf->length() - 1, buf->slice().ptr);
- res.reserve(buf->length());
- while (1)
- {
- Token tok;
- lex.scan(&tok);
- highlightCode3(sc, &res, lastp, tok.ptr);
-
- const char *highlight = NULL;
- switch (tok.value)
- {
- case TOKidentifier:
- {
- if (!sc)
- break;
- size_t len = lex.p - tok.ptr;
- if (isIdentifier(a, tok.ptr, len))
- {
- highlight = "$(D_PSYMBOL ";
- break;
- }
- if (isFunctionParameter(a, tok.ptr, len))
- {
- //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j);
- highlight = "$(D_PARAM ";
- break;
- }
- break;
- }
- case TOKcomment:
- highlight = "$(D_COMMENT ";
- break;
-
- case TOKstring:
- highlight = "$(D_STRING ";
- break;
-
- default:
- if (tok.isKeyword())
- highlight = "$(D_KEYWORD ";
- break;
- }
- if (highlight)
- {
- res.writestring(highlight);
- size_t o = res.length();
- highlightCode3(sc, &res, tok.ptr, lex.p);
- if (tok.value == TOKcomment || tok.value == TOKstring)
- escapeDdocString(&res, o); // Bugzilla 7656, 7715, and 10519
- res.writeByte(')');
- }
- else
- highlightCode3(sc, &res, tok.ptr, lex.p);
- if (tok.value == TOKeof)
- break;
- lastp = lex.p;
- }
- buf->setsize(offset);
- buf->write(&res);
- global.errors = errorsave;
-}
-
-/***************************************
- * Find character string to replace c with.
- */
-
-const char *Escape::escapeChar(unsigned c)
-{
- assert(c < 256);
- //printf("escapeChar('%c') => %p, %p\n", c, strings, strings[c]);
- return strings[c];
-}
-
-/****************************************
- * Determine if p points to the start of a "..." parameter identifier.
- */
-
-bool isCVariadicArg(const utf8_t *p, size_t len)
-{
- return len >= 3 && cmp("...", p, 3) == 0;
-}
-
-/****************************************
- * Determine if p points to the start of an identifier.
- */
-
-bool isIdStart(const utf8_t *p)
-{
- unsigned c = *p;
- if (isalpha(c) || c == '_')
- return true;
- if (c >= 0x80)
- {
- size_t i = 0;
- if (utf_decodeChar(p, 4, &i, &c))
- return false; // ignore errors
- if (isUniAlpha(c))
- return true;
- }
- return false;
-}
-
-/****************************************
- * Determine if p points to the rest of an identifier.
- */
-
-bool isIdTail(const utf8_t *p)
-{
- unsigned c = *p;
- if (isalnum(c) || c == '_')
- return true;
- if (c >= 0x80)
- {
- size_t i = 0;
- if (utf_decodeChar(p, 4, &i, &c))
- return false; // ignore errors
- if (isUniAlpha(c))
- return true;
- }
- return false;
-}
-
-/****************************************
- * Determine if p points to the indentation space.
- */
-
-bool isIndentWS(const utf8_t *p)
-{
- return (*p == ' ') || (*p == '\t');
-}
-
-/*****************************************
- * Return number of bytes in UTF character.
- */
-
-int utfStride(const utf8_t *p)
-{
- unsigned c = *p;
- if (c < 0x80)
- return 1;
- size_t i = 0;
- utf_decodeChar(p, 4, &i, &c); // ignore errors, but still consume input
- return (int)i;
-}
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
new file mode 100644
index 0000000..9b4329b
--- /dev/null
+++ b/gcc/d/dmd/doc.d
@@ -0,0 +1,5388 @@
+/**
+ * Ddoc documentation generation.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/ddoc.html, Documentation Generator)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/doc.d, _doc.d)
+ * Documentation: https://dlang.org/phobos/dmd_doc.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/doc.d
+ */
+
+module dmd.doc;
+
+import core.stdc.ctype;
+import core.stdc.stdlib;
+import core.stdc.stdio;
+import core.stdc.string;
+import core.stdc.time;
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.cond;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dimport;
+import dmd.dmacro;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.func;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.lexer;
+import dmd.mtype;
+import dmd.root.array;
+import dmd.root.file;
+import dmd.root.filename;
+import dmd.root.outbuffer;
+import dmd.root.port;
+import dmd.root.rmem;
+import dmd.root.string;
+import dmd.tokens;
+import dmd.utf;
+import dmd.utils;
+import dmd.visitor;
+
+struct Escape
+{
+ const(char)[][char.max] strings;
+
+ /***************************************
+ * Find character string to replace c with.
+ */
+ const(char)[] escapeChar(char c)
+ {
+ version (all)
+ {
+ //printf("escapeChar('%c') => %p, %p\n", c, strings, strings[c].ptr);
+ return strings[c];
+ }
+ else
+ {
+ const(char)[] s;
+ switch (c)
+ {
+ case '<':
+ s = "&lt;";
+ break;
+ case '>':
+ s = "&gt;";
+ break;
+ case '&':
+ s = "&amp;";
+ break;
+ default:
+ s = null;
+ break;
+ }
+ return s;
+ }
+ }
+}
+
+/***********************************************************
+ */
+private class Section
+{
+ const(char)[] name;
+ const(char)[] body_;
+ int nooutput;
+
+ override string toString() const
+ {
+ assert(0);
+ }
+
+ void write(Loc loc, DocComment* dc, Scope* sc, Dsymbols* a, OutBuffer* buf)
+ {
+ assert(a.dim);
+ if (name.length)
+ {
+ static immutable table =
+ [
+ "AUTHORS",
+ "BUGS",
+ "COPYRIGHT",
+ "DATE",
+ "DEPRECATED",
+ "EXAMPLES",
+ "HISTORY",
+ "LICENSE",
+ "RETURNS",
+ "SEE_ALSO",
+ "STANDARDS",
+ "THROWS",
+ "VERSION",
+ ];
+ foreach (entry; table)
+ {
+ if (iequals(entry, name))
+ {
+ buf.printf("$(DDOC_%s ", entry.ptr);
+ goto L1;
+ }
+ }
+ buf.writestring("$(DDOC_SECTION ");
+ // Replace _ characters with spaces
+ buf.writestring("$(DDOC_SECTION_H ");
+ size_t o = buf.length;
+ foreach (char c; name)
+ buf.writeByte((c == '_') ? ' ' : c);
+ escapeStrayParenthesis(loc, buf, o, false);
+ buf.writestring(")");
+ }
+ else
+ {
+ buf.writestring("$(DDOC_DESCRIPTION ");
+ }
+ L1:
+ size_t o = buf.length;
+ buf.write(body_);
+ escapeStrayParenthesis(loc, buf, o, true);
+ highlightText(sc, a, loc, *buf, o);
+ buf.writestring(")");
+ }
+}
+
+/***********************************************************
+ */
+private final class ParamSection : Section
+{
+ override void write(Loc loc, DocComment* dc, Scope* sc, Dsymbols* a, OutBuffer* buf)
+ {
+ assert(a.dim);
+ Dsymbol s = (*a)[0]; // test
+ const(char)* p = body_.ptr;
+ size_t len = body_.length;
+ const(char)* pend = p + len;
+ const(char)* tempstart = null;
+ size_t templen = 0;
+ const(char)* namestart = null;
+ size_t namelen = 0; // !=0 if line continuation
+ const(char)* textstart = null;
+ size_t textlen = 0;
+ size_t paramcount = 0;
+ buf.writestring("$(DDOC_PARAMS ");
+ while (p < pend)
+ {
+ // Skip to start of macro
+ while (1)
+ {
+ switch (*p)
+ {
+ case ' ':
+ case '\t':
+ p++;
+ continue;
+ case '\n':
+ p++;
+ goto Lcont;
+ default:
+ if (isIdStart(p) || isCVariadicArg(p[0 .. cast(size_t)(pend - p)]))
+ break;
+ if (namelen)
+ goto Ltext;
+ // continuation of prev macro
+ goto Lskipline;
+ }
+ break;
+ }
+ tempstart = p;
+ while (isIdTail(p))
+ p += utfStride(p);
+ if (isCVariadicArg(p[0 .. cast(size_t)(pend - p)]))
+ p += 3;
+ templen = p - tempstart;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p != '=')
+ {
+ if (namelen)
+ goto Ltext;
+ // continuation of prev macro
+ goto Lskipline;
+ }
+ p++;
+ if (namelen)
+ {
+ // Output existing param
+ L1:
+ //printf("param '%.*s' = '%.*s'\n", cast(int)namelen, namestart, cast(int)textlen, textstart);
+ ++paramcount;
+ HdrGenState hgs;
+ buf.writestring("$(DDOC_PARAM_ROW ");
+ {
+ buf.writestring("$(DDOC_PARAM_ID ");
+ {
+ size_t o = buf.length;
+ Parameter fparam = isFunctionParameter(a, namestart, namelen);
+ if (!fparam)
+ {
+ // Comments on a template might refer to function parameters within.
+ // Search the parameters of nested eponymous functions (with the same name.)
+ fparam = isEponymousFunctionParameter(a, namestart, namelen);
+ }
+ bool isCVariadic = isCVariadicParameter(a, namestart[0 .. namelen]);
+ if (isCVariadic)
+ {
+ buf.writestring("...");
+ }
+ else if (fparam && fparam.type && fparam.ident)
+ {
+ .toCBuffer(fparam.type, buf, fparam.ident, &hgs);
+ }
+ else
+ {
+ if (isTemplateParameter(a, namestart, namelen))
+ {
+ // 10236: Don't count template parameters for params check
+ --paramcount;
+ }
+ else if (!fparam)
+ {
+ warning(s.loc, "Ddoc: function declaration has no parameter '%.*s'", cast(int)namelen, namestart);
+ }
+ buf.write(namestart[0 .. namelen]);
+ }
+ escapeStrayParenthesis(loc, buf, o, true);
+ highlightCode(sc, a, *buf, o);
+ }
+ buf.writestring(")");
+ buf.writestring("$(DDOC_PARAM_DESC ");
+ {
+ size_t o = buf.length;
+ buf.write(textstart[0 .. textlen]);
+ escapeStrayParenthesis(loc, buf, o, true);
+ highlightText(sc, a, loc, *buf, o);
+ }
+ buf.writestring(")");
+ }
+ buf.writestring(")");
+ namelen = 0;
+ if (p >= pend)
+ break;
+ }
+ namestart = tempstart;
+ namelen = templen;
+ while (*p == ' ' || *p == '\t')
+ p++;
+ textstart = p;
+ Ltext:
+ while (*p != '\n')
+ p++;
+ textlen = p - textstart;
+ p++;
+ Lcont:
+ continue;
+ Lskipline:
+ // Ignore this line
+ while (*p++ != '\n')
+ {
+ }
+ }
+ if (namelen)
+ goto L1;
+ // write out last one
+ buf.writestring(")");
+ TypeFunction tf = a.dim == 1 ? isTypeFunction(s) : null;
+ if (tf)
+ {
+ size_t pcount = (tf.parameterList.parameters ? tf.parameterList.parameters.dim : 0) +
+ cast(int)(tf.parameterList.varargs == VarArg.variadic);
+ if (pcount != paramcount)
+ {
+ warning(s.loc, "Ddoc: parameter count mismatch, expected %llu, got %llu",
+ cast(ulong) pcount, cast(ulong) paramcount);
+ if (paramcount == 0)
+ {
+ // Chances are someone messed up the format
+ warningSupplemental(s.loc, "Note that the format is `param = description`");
+ }
+ }
+ }
+ }
+}
+
+/***********************************************************
+ */
+private final class MacroSection : Section
+{
+ override void write(Loc loc, DocComment* dc, Scope* sc, Dsymbols* a, OutBuffer* buf)
+ {
+ //printf("MacroSection::write()\n");
+ DocComment.parseMacros(dc.escapetable, *dc.pmacrotable, body_);
+ }
+}
+
+private alias Sections = Array!(Section);
+
+// Workaround for missing Parameter instance for variadic params. (it's unnecessary to instantiate one).
+private bool isCVariadicParameter(Dsymbols* a, const(char)[] p)
+{
+ foreach (member; *a)
+ {
+ TypeFunction tf = isTypeFunction(member);
+ if (tf && tf.parameterList.varargs == VarArg.variadic && p == "...")
+ return true;
+ }
+ return false;
+}
+
+private Dsymbol getEponymousMember(TemplateDeclaration td)
+{
+ if (!td.onemember)
+ return null;
+ if (AggregateDeclaration ad = td.onemember.isAggregateDeclaration())
+ return ad;
+ if (FuncDeclaration fd = td.onemember.isFuncDeclaration())
+ return fd;
+ if (auto em = td.onemember.isEnumMember())
+ return null; // Keep backward compatibility. See compilable/ddoc9.d
+ if (VarDeclaration vd = td.onemember.isVarDeclaration())
+ return td.constraint ? null : vd;
+ return null;
+}
+
+private TemplateDeclaration getEponymousParent(Dsymbol s)
+{
+ if (!s.parent)
+ return null;
+ TemplateDeclaration td = s.parent.isTemplateDeclaration();
+ return (td && getEponymousMember(td)) ? td : null;
+}
+
+private immutable ddoc_default = import("default_ddoc_theme." ~ ddoc_ext);
+private immutable ddoc_decl_s = "$(DDOC_DECL ";
+private immutable ddoc_decl_e = ")\n";
+private immutable ddoc_decl_dd_s = "$(DDOC_DECL_DD ";
+private immutable ddoc_decl_dd_e = ")\n";
+
+/****************************************************
+ */
+extern(C++) void gendocfile(Module m)
+{
+ __gshared OutBuffer mbuf;
+ __gshared int mbuf_done;
+ OutBuffer buf;
+ //printf("Module::gendocfile()\n");
+ if (!mbuf_done) // if not already read the ddoc files
+ {
+ mbuf_done = 1;
+ // Use our internal default
+ mbuf.writestring(ddoc_default);
+ // Override with DDOCFILE specified in the sc.ini file
+ char* p = getenv("DDOCFILE");
+ if (p)
+ global.params.ddocfiles.shift(p);
+ // Override with the ddoc macro files from the command line
+ for (size_t i = 0; i < global.params.ddocfiles.dim; i++)
+ {
+ auto buffer = readFile(m.loc, global.params.ddocfiles[i]);
+ // BUG: convert file contents to UTF-8 before use
+ const data = buffer.data;
+ //printf("file: '%.*s'\n", cast(int)data.length, data.ptr);
+ mbuf.write(data);
+ }
+ }
+ DocComment.parseMacros(m.escapetable, m.macrotable, mbuf[]);
+ Scope* sc = Scope.createGlobal(m); // create root scope
+ DocComment* dc = DocComment.parse(m, m.comment);
+ dc.pmacrotable = &m.macrotable;
+ dc.escapetable = m.escapetable;
+ sc.lastdc = dc;
+ // Generate predefined macros
+ // Set the title to be the name of the module
+ {
+ const p = m.toPrettyChars().toDString;
+ m.macrotable.define("TITLE", p);
+ }
+ // Set time macros
+ {
+ time_t t;
+ time(&t);
+ char* p = ctime(&t);
+ p = mem.xstrdup(p);
+ m.macrotable.define("DATETIME", p.toDString());
+ m.macrotable.define("YEAR", p[20 .. 20 + 4]);
+ }
+ const srcfilename = m.srcfile.toString();
+ m.macrotable.define("SRCFILENAME", srcfilename);
+ const docfilename = m.docfile.toString();
+ m.macrotable.define("DOCFILENAME", docfilename);
+ if (dc.copyright)
+ {
+ dc.copyright.nooutput = 1;
+ m.macrotable.define("COPYRIGHT", dc.copyright.body_);
+ }
+ if (m.isDocFile)
+ {
+ const ploc = m.md ? &m.md.loc : &m.loc;
+ const loc = Loc(ploc.filename ? ploc.filename : srcfilename.ptr,
+ ploc.linnum,
+ ploc.charnum);
+
+ size_t commentlen = strlen(cast(char*)m.comment);
+ Dsymbols a;
+ // https://issues.dlang.org/show_bug.cgi?id=9764
+ // Don't push m in a, to prevent emphasize ddoc file name.
+ if (dc.macros)
+ {
+ commentlen = dc.macros.name.ptr - m.comment;
+ dc.macros.write(loc, dc, sc, &a, &buf);
+ }
+ buf.write(m.comment[0 .. commentlen]);
+ highlightText(sc, &a, loc, buf, 0);
+ }
+ else
+ {
+ Dsymbols a;
+ a.push(m);
+ dc.writeSections(sc, &a, &buf);
+ emitMemberComments(m, buf, sc);
+ }
+ //printf("BODY= '%.*s'\n", cast(int)buf.length, buf.data);
+ m.macrotable.define("BODY", buf[]);
+ OutBuffer buf2;
+ buf2.writestring("$(DDOC)");
+ size_t end = buf2.length;
+ m.macrotable.expand(buf2, 0, end, null);
+ version (all)
+ {
+ /* Remove all the escape sequences from buf2,
+ * and make CR-LF the newline.
+ */
+ {
+ const slice = buf2[];
+ buf.setsize(0);
+ buf.reserve(slice.length);
+ auto p = slice.ptr;
+ for (size_t j = 0; j < slice.length; j++)
+ {
+ char c = p[j];
+ if (c == 0xFF && j + 1 < slice.length)
+ {
+ j++;
+ continue;
+ }
+ if (c == '\n')
+ buf.writeByte('\r');
+ else if (c == '\r')
+ {
+ buf.writestring("\r\n");
+ if (j + 1 < slice.length && p[j + 1] == '\n')
+ {
+ j++;
+ }
+ continue;
+ }
+ buf.writeByte(c);
+ }
+ }
+ writeFile(m.loc, m.docfile.toString(), buf[]);
+ }
+ else
+ {
+ /* Remove all the escape sequences from buf2
+ */
+ {
+ size_t i = 0;
+ char* p = buf2.data;
+ for (size_t j = 0; j < buf2.length; j++)
+ {
+ if (p[j] == 0xFF && j + 1 < buf2.length)
+ {
+ j++;
+ continue;
+ }
+ p[i] = p[j];
+ i++;
+ }
+ buf2.setsize(i);
+ }
+ writeFile(m.loc, m.docfile.toString(), buf2[]);
+ }
+}
+
+/****************************************************
+ * Having unmatched parentheses can hose the output of Ddoc,
+ * as the macros depend on properly nested parentheses.
+ * This function replaces all ( with $(LPAREN) and ) with $(RPAREN)
+ * to preserve text literally. This also means macros in the
+ * text won't be expanded.
+ */
+void escapeDdocString(OutBuffer* buf, size_t start)
+{
+ for (size_t u = start; u < buf.length; u++)
+ {
+ char c = (*buf)[u];
+ switch (c)
+ {
+ case '$':
+ buf.remove(u, 1);
+ buf.insert(u, "$(DOLLAR)");
+ u += 8;
+ break;
+ case '(':
+ buf.remove(u, 1); //remove the (
+ buf.insert(u, "$(LPAREN)"); //insert this instead
+ u += 8; //skip over newly inserted macro
+ break;
+ case ')':
+ buf.remove(u, 1); //remove the )
+ buf.insert(u, "$(RPAREN)"); //insert this instead
+ u += 8; //skip over newly inserted macro
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+/****************************************************
+ * Having unmatched parentheses can hose the output of Ddoc,
+ * as the macros depend on properly nested parentheses.
+ *
+ * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN).
+ *
+ * Params:
+ * loc = source location of start of text. It is a mutable copy to allow incrementing its linenum, for printing the correct line number when an error is encountered in a multiline block of ddoc.
+ * buf = an OutBuffer containing the DDoc
+ * start = the index within buf to start replacing unmatched parentheses
+ * respectBackslashEscapes = if true, always replace parentheses that are
+ * directly preceeded by a backslash with $(LPAREN) or $(RPAREN) instead of
+ * counting them as stray parentheses
+ */
+private void escapeStrayParenthesis(Loc loc, OutBuffer* buf, size_t start, bool respectBackslashEscapes)
+{
+ uint par_open = 0;
+ char inCode = 0;
+ bool atLineStart = true;
+ for (size_t u = start; u < buf.length; u++)
+ {
+ char c = (*buf)[u];
+ switch (c)
+ {
+ case '(':
+ if (!inCode)
+ par_open++;
+ atLineStart = false;
+ break;
+ case ')':
+ if (!inCode)
+ {
+ if (par_open == 0)
+ {
+ //stray ')'
+ warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output. Use $(RPAREN) instead for unpaired right parentheses.");
+ buf.remove(u, 1); //remove the )
+ buf.insert(u, "$(RPAREN)"); //insert this instead
+ u += 8; //skip over newly inserted macro
+ }
+ else
+ par_open--;
+ }
+ atLineStart = false;
+ break;
+ case '\n':
+ atLineStart = true;
+ version (none)
+ {
+ // For this to work, loc must be set to the beginning of the passed
+ // text which is currently not possible
+ // (loc is set to the Loc of the Dsymbol)
+ loc.linnum++;
+ }
+ break;
+ case ' ':
+ case '\r':
+ case '\t':
+ break;
+ case '-':
+ case '`':
+ case '~':
+ // Issue 15465: don't try to escape unbalanced parens inside code
+ // blocks.
+ int numdash = 1;
+ for (++u; u < buf.length && (*buf)[u] == c; ++u)
+ ++numdash;
+ --u;
+ if (c == '`' || (atLineStart && numdash >= 3))
+ {
+ if (inCode == c)
+ inCode = 0;
+ else if (!inCode)
+ inCode = c;
+ }
+ atLineStart = false;
+ break;
+ case '\\':
+ // replace backslash-escaped parens with their macros
+ if (!inCode && respectBackslashEscapes && u+1 < buf.length && global.params.markdown)
+ {
+ if ((*buf)[u+1] == '(' || (*buf)[u+1] == ')')
+ {
+ const paren = (*buf)[u+1] == '(' ? "$(LPAREN)" : "$(RPAREN)";
+ buf.remove(u, 2); //remove the \)
+ buf.insert(u, paren); //insert this instead
+ u += 8; //skip over newly inserted macro
+ }
+ else if ((*buf)[u+1] == '\\')
+ ++u;
+ }
+ break;
+ default:
+ atLineStart = false;
+ break;
+ }
+ }
+ if (par_open) // if any unmatched lparens
+ {
+ par_open = 0;
+ for (size_t u = buf.length; u > start;)
+ {
+ u--;
+ char c = (*buf)[u];
+ switch (c)
+ {
+ case ')':
+ par_open++;
+ break;
+ case '(':
+ if (par_open == 0)
+ {
+ //stray '('
+ warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output. Use $(LPAREN) instead for unpaired left parentheses.");
+ buf.remove(u, 1); //remove the (
+ buf.insert(u, "$(LPAREN)"); //insert this instead
+ }
+ else
+ par_open--;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+// Basically, this is to skip over things like private{} blocks in a struct or
+// class definition that don't add any components to the qualified name.
+private Scope* skipNonQualScopes(Scope* sc)
+{
+ while (sc && !sc.scopesym)
+ sc = sc.enclosing;
+ return sc;
+}
+
+private bool emitAnchorName(ref OutBuffer buf, Dsymbol s, Scope* sc, bool includeParent)
+{
+ if (!s || s.isPackage() || s.isModule())
+ return false;
+ // Add parent names first
+ bool dot = false;
+ auto eponymousParent = getEponymousParent(s);
+ if (includeParent && s.parent || eponymousParent)
+ dot = emitAnchorName(buf, s.parent, sc, includeParent);
+ else if (includeParent && sc)
+ dot = emitAnchorName(buf, sc.scopesym, skipNonQualScopes(sc.enclosing), includeParent);
+ // Eponymous template members can share the parent anchor name
+ if (eponymousParent)
+ return dot;
+ if (dot)
+ buf.writeByte('.');
+ // Use "this" not "__ctor"
+ TemplateDeclaration td;
+ if (s.isCtorDeclaration() || ((td = s.isTemplateDeclaration()) !is null && td.onemember && td.onemember.isCtorDeclaration()))
+ {
+ buf.writestring("this");
+ }
+ else
+ {
+ /* We just want the identifier, not overloads like TemplateDeclaration::toChars.
+ * We don't want the template parameter list and constraints. */
+ buf.writestring(s.Dsymbol.toChars());
+ }
+ return true;
+}
+
+private void emitAnchor(ref OutBuffer buf, Dsymbol s, Scope* sc, bool forHeader = false)
+{
+ Identifier ident;
+ {
+ OutBuffer anc;
+ emitAnchorName(anc, s, skipNonQualScopes(sc), true);
+ ident = Identifier.idPool(anc[]);
+ }
+
+ auto pcount = cast(void*)ident in sc.anchorCounts;
+ typeof(*pcount) count;
+ if (!forHeader)
+ {
+ if (pcount)
+ {
+ // Existing anchor,
+ // don't write an anchor for matching consecutive ditto symbols
+ TemplateDeclaration td = getEponymousParent(s);
+ if (sc.prevAnchor == ident && sc.lastdc && (isDitto(s.comment) || (td && isDitto(td.comment))))
+ return;
+
+ count = ++*pcount;
+ }
+ else
+ {
+ sc.anchorCounts[cast(void*)ident] = 1;
+ count = 1;
+ }
+ }
+
+ // cache anchor name
+ sc.prevAnchor = ident;
+ auto macroName = forHeader ? "DDOC_HEADER_ANCHOR" : "DDOC_ANCHOR";
+
+ if (auto imp = s.isImport())
+ {
+ // For example: `public import core.stdc.string : memcpy, memcmp;`
+ if (imp.aliases.dim > 0)
+ {
+ for(int i = 0; i < imp.aliases.dim; i++)
+ {
+ // Need to distinguish between
+ // `public import core.stdc.string : memcpy, memcmp;` and
+ // `public import core.stdc.string : copy = memcpy, compare = memcmp;`
+ auto a = imp.aliases[i];
+ auto id = a ? a : imp.names[i];
+ auto loc = Loc.init;
+ if (auto symFromId = sc.search(loc, id, null))
+ {
+ emitAnchor(buf, symFromId, sc, forHeader);
+ }
+ }
+ }
+ else
+ {
+ // For example: `public import str = core.stdc.string;`
+ if (imp.aliasId)
+ {
+ auto symbolName = imp.aliasId.toString();
+
+ buf.printf("$(%.*s %.*s", cast(int) macroName.length, macroName.ptr,
+ cast(int) symbolName.length, symbolName.ptr);
+
+ if (forHeader)
+ {
+ buf.printf(", %.*s", cast(int) symbolName.length, symbolName.ptr);
+ }
+ }
+ else
+ {
+ // The general case: `public import core.stdc.string;`
+
+ // fully qualify imports so `core.stdc.string` doesn't appear as `core`
+ void printFullyQualifiedImport()
+ {
+ foreach (const pid; imp.packages)
+ {
+ buf.printf("%s.", pid.toChars());
+ }
+ buf.writestring(imp.id.toString());
+ }
+
+ buf.printf("$(%.*s ", cast(int) macroName.length, macroName.ptr);
+ printFullyQualifiedImport();
+
+ if (forHeader)
+ {
+ buf.printf(", ");
+ printFullyQualifiedImport();
+ }
+ }
+
+ buf.writeByte(')');
+ }
+ }
+ else
+ {
+ auto symbolName = ident.toString();
+ buf.printf("$(%.*s %.*s", cast(int) macroName.length, macroName.ptr,
+ cast(int) symbolName.length, symbolName.ptr);
+
+ // only append count once there's a duplicate
+ if (count > 1)
+ buf.printf(".%u", count);
+
+ if (forHeader)
+ {
+ Identifier shortIdent;
+ {
+ OutBuffer anc;
+ emitAnchorName(anc, s, skipNonQualScopes(sc), false);
+ shortIdent = Identifier.idPool(anc[]);
+ }
+
+ auto shortName = shortIdent.toString();
+ buf.printf(", %.*s", cast(int) shortName.length, shortName.ptr);
+ }
+
+ buf.writeByte(')');
+ }
+}
+
+/******************************* emitComment **********************************/
+
+/** Get leading indentation from 'src' which represents lines of code. */
+private size_t getCodeIndent(const(char)* src)
+{
+ while (src && (*src == '\r' || *src == '\n'))
+ ++src; // skip until we find the first non-empty line
+ size_t codeIndent = 0;
+ while (src && (*src == ' ' || *src == '\t'))
+ {
+ codeIndent++;
+ src++;
+ }
+ return codeIndent;
+}
+
+/** Recursively expand template mixin member docs into the scope. */
+private void expandTemplateMixinComments(TemplateMixin tm, ref OutBuffer buf, Scope* sc)
+{
+ if (!tm.semanticRun)
+ tm.dsymbolSemantic(sc);
+ TemplateDeclaration td = (tm && tm.tempdecl) ? tm.tempdecl.isTemplateDeclaration() : null;
+ if (td && td.members)
+ {
+ for (size_t i = 0; i < td.members.dim; i++)
+ {
+ Dsymbol sm = (*td.members)[i];
+ TemplateMixin tmc = sm.isTemplateMixin();
+ if (tmc && tmc.comment)
+ expandTemplateMixinComments(tmc, buf, sc);
+ else
+ emitComment(sm, buf, sc);
+ }
+ }
+}
+
+private void emitMemberComments(ScopeDsymbol sds, ref OutBuffer buf, Scope* sc)
+{
+ if (!sds.members)
+ return;
+ //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars());
+ const(char)[] m = "$(DDOC_MEMBERS ";
+ if (sds.isTemplateDeclaration())
+ m = "$(DDOC_TEMPLATE_MEMBERS ";
+ else if (sds.isClassDeclaration())
+ m = "$(DDOC_CLASS_MEMBERS ";
+ else if (sds.isStructDeclaration())
+ m = "$(DDOC_STRUCT_MEMBERS ";
+ else if (sds.isEnumDeclaration())
+ m = "$(DDOC_ENUM_MEMBERS ";
+ else if (sds.isModule())
+ m = "$(DDOC_MODULE_MEMBERS ";
+ size_t offset1 = buf.length; // save starting offset
+ buf.writestring(m);
+ size_t offset2 = buf.length; // to see if we write anything
+ sc = sc.push(sds);
+ for (size_t i = 0; i < sds.members.dim; i++)
+ {
+ Dsymbol s = (*sds.members)[i];
+ //printf("\ts = '%s'\n", s.toChars());
+ // only expand if parent is a non-template (semantic won't work)
+ if (s.comment && s.isTemplateMixin() && s.parent && !s.parent.isTemplateDeclaration())
+ expandTemplateMixinComments(cast(TemplateMixin)s, buf, sc);
+ emitComment(s, buf, sc);
+ }
+ emitComment(null, buf, sc);
+ sc.pop();
+ if (buf.length == offset2)
+ {
+ /* Didn't write out any members, so back out last write
+ */
+ buf.setsize(offset1);
+ }
+ else
+ buf.writestring(")");
+}
+
+private void emitVisibility(ref OutBuffer buf, Import i)
+{
+ // imports are private by default, which is different from other declarations
+ // so they should explicitly show their visibility
+ emitVisibility(buf, i.visibility);
+}
+
+private void emitVisibility(ref OutBuffer buf, Declaration d)
+{
+ auto vis = d.visibility;
+ if (vis.kind != Visibility.Kind.undefined && vis.kind != Visibility.Kind.public_)
+ {
+ emitVisibility(buf, vis);
+ }
+}
+
+private void emitVisibility(ref OutBuffer buf, Visibility vis)
+{
+ visibilityToBuffer(&buf, vis);
+ buf.writeByte(' ');
+}
+
+private void emitComment(Dsymbol s, ref OutBuffer buf, Scope* sc)
+{
+ extern (C++) final class EmitComment : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ OutBuffer* buf;
+ Scope* sc;
+
+ extern (D) this(ref OutBuffer buf, Scope* sc)
+ {
+ this.buf = &buf;
+ this.sc = sc;
+ }
+
+ override void visit(Dsymbol)
+ {
+ }
+
+ override void visit(InvariantDeclaration)
+ {
+ }
+
+ override void visit(UnitTestDeclaration)
+ {
+ }
+
+ override void visit(PostBlitDeclaration)
+ {
+ }
+
+ override void visit(DtorDeclaration)
+ {
+ }
+
+ override void visit(StaticCtorDeclaration)
+ {
+ }
+
+ override void visit(StaticDtorDeclaration)
+ {
+ }
+
+ override void visit(TypeInfoDeclaration)
+ {
+ }
+
+ void emit(Scope* sc, Dsymbol s, const(char)* com)
+ {
+ if (s && sc.lastdc && isDitto(com))
+ {
+ sc.lastdc.a.push(s);
+ return;
+ }
+ // Put previous doc comment if exists
+ if (DocComment* dc = sc.lastdc)
+ {
+ assert(dc.a.dim > 0, "Expects at least one declaration for a" ~
+ "documentation comment");
+
+ auto symbol = dc.a[0];
+
+ buf.writestring("$(DDOC_MEMBER");
+ buf.writestring("$(DDOC_MEMBER_HEADER");
+ emitAnchor(*buf, symbol, sc, true);
+ buf.writeByte(')');
+
+ // Put the declaration signatures as the document 'title'
+ buf.writestring(ddoc_decl_s);
+ for (size_t i = 0; i < dc.a.dim; i++)
+ {
+ Dsymbol sx = dc.a[i];
+ // the added linebreaks in here make looking at multiple
+ // signatures more appealing
+ if (i == 0)
+ {
+ size_t o = buf.length;
+ toDocBuffer(sx, *buf, sc);
+ highlightCode(sc, sx, *buf, o);
+ buf.writestring("$(DDOC_OVERLOAD_SEPARATOR)");
+ continue;
+ }
+ buf.writestring("$(DDOC_DITTO ");
+ {
+ size_t o = buf.length;
+ toDocBuffer(sx, *buf, sc);
+ highlightCode(sc, sx, *buf, o);
+ }
+ buf.writestring("$(DDOC_OVERLOAD_SEPARATOR)");
+ buf.writeByte(')');
+ }
+ buf.writestring(ddoc_decl_e);
+ // Put the ddoc comment as the document 'description'
+ buf.writestring(ddoc_decl_dd_s);
+ {
+ dc.writeSections(sc, &dc.a, buf);
+ if (ScopeDsymbol sds = dc.a[0].isScopeDsymbol())
+ emitMemberComments(sds, *buf, sc);
+ }
+ buf.writestring(ddoc_decl_dd_e);
+ buf.writeByte(')');
+ //printf("buf.2 = [[%.*s]]\n", cast(int)(buf.length - o0), buf.data + o0);
+ }
+ if (s)
+ {
+ DocComment* dc = DocComment.parse(s, com);
+ dc.pmacrotable = &sc._module.macrotable;
+ sc.lastdc = dc;
+ }
+ }
+
+ override void visit(Import imp)
+ {
+ if (imp.visible().kind != Visibility.Kind.public_ && sc.visibility.kind != Visibility.Kind.export_)
+ return;
+
+ if (imp.comment)
+ emit(sc, imp, imp.comment);
+ }
+
+ override void visit(Declaration d)
+ {
+ //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", d, d.toChars(), d.comment);
+ //printf("type = %p\n", d.type);
+ const(char)* com = d.comment;
+ if (TemplateDeclaration td = getEponymousParent(d))
+ {
+ if (isDitto(td.comment))
+ com = td.comment;
+ else
+ com = Lexer.combineComments(td.comment.toDString(), com.toDString(), true);
+ }
+ else
+ {
+ if (!d.ident)
+ return;
+ if (!d.type)
+ {
+ if (!d.isCtorDeclaration() &&
+ !d.isAliasDeclaration() &&
+ !d.isVarDeclaration())
+ {
+ return;
+ }
+ }
+ if (d.visibility.kind == Visibility.Kind.private_ || sc.visibility.kind == Visibility.Kind.private_)
+ return;
+ }
+ if (!com)
+ return;
+ emit(sc, d, com);
+ }
+
+ override void visit(AggregateDeclaration ad)
+ {
+ //printf("AggregateDeclaration::emitComment() '%s'\n", ad.toChars());
+ const(char)* com = ad.comment;
+ if (TemplateDeclaration td = getEponymousParent(ad))
+ {
+ if (isDitto(td.comment))
+ com = td.comment;
+ else
+ com = Lexer.combineComments(td.comment.toDString(), com.toDString(), true);
+ }
+ else
+ {
+ if (ad.visible().kind == Visibility.Kind.private_ || sc.visibility.kind == Visibility.Kind.private_)
+ return;
+ if (!ad.comment)
+ return;
+ }
+ if (!com)
+ return;
+ emit(sc, ad, com);
+ }
+
+ override void visit(TemplateDeclaration td)
+ {
+ //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", td.toChars(), td.kind());
+ if (td.visible().kind == Visibility.Kind.private_ || sc.visibility.kind == Visibility.Kind.private_)
+ return;
+ if (!td.comment)
+ return;
+ if (Dsymbol ss = getEponymousMember(td))
+ {
+ ss.accept(this);
+ return;
+ }
+ emit(sc, td, td.comment);
+ }
+
+ override void visit(EnumDeclaration ed)
+ {
+ if (ed.visible().kind == Visibility.Kind.private_ || sc.visibility.kind == Visibility.Kind.private_)
+ return;
+ if (ed.isAnonymous() && ed.members)
+ {
+ for (size_t i = 0; i < ed.members.dim; i++)
+ {
+ Dsymbol s = (*ed.members)[i];
+ emitComment(s, *buf, sc);
+ }
+ return;
+ }
+ if (!ed.comment)
+ return;
+ if (ed.isAnonymous())
+ return;
+ emit(sc, ed, ed.comment);
+ }
+
+ override void visit(EnumMember em)
+ {
+ //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", em, em.toChars(), em.comment);
+ if (em.visible().kind == Visibility.Kind.private_ || sc.visibility.kind == Visibility.Kind.private_)
+ return;
+ if (!em.comment)
+ return;
+ emit(sc, em, em.comment);
+ }
+
+ override void visit(AttribDeclaration ad)
+ {
+ //printf("AttribDeclaration::emitComment(sc = %p)\n", sc);
+ /* A general problem with this,
+ * illustrated by https://issues.dlang.org/show_bug.cgi?id=2516
+ * is that attributes are not transmitted through to the underlying
+ * member declarations for template bodies, because semantic analysis
+ * is not done for template declaration bodies
+ * (only template instantiations).
+ * Hence, Ddoc omits attributes from template members.
+ */
+ Dsymbols* d = ad.include(null);
+ if (d)
+ {
+ for (size_t i = 0; i < d.dim; i++)
+ {
+ Dsymbol s = (*d)[i];
+ //printf("AttribDeclaration::emitComment %s\n", s.toChars());
+ emitComment(s, *buf, sc);
+ }
+ }
+ }
+
+ override void visit(VisibilityDeclaration pd)
+ {
+ if (pd.decl)
+ {
+ Scope* scx = sc;
+ sc = sc.copy();
+ sc.visibility = pd.visibility;
+ visit(cast(AttribDeclaration)pd);
+ scx.lastdc = sc.lastdc;
+ sc = sc.pop();
+ }
+ }
+
+ override void visit(ConditionalDeclaration cd)
+ {
+ //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc);
+ if (cd.condition.inc != Include.notComputed)
+ {
+ visit(cast(AttribDeclaration)cd);
+ return;
+ }
+ /* If generating doc comment, be careful because if we're inside
+ * a template, then include(null) will fail.
+ */
+ Dsymbols* d = cd.decl ? cd.decl : cd.elsedecl;
+ for (size_t i = 0; i < d.dim; i++)
+ {
+ Dsymbol s = (*d)[i];
+ emitComment(s, *buf, sc);
+ }
+ }
+ }
+
+ scope EmitComment v = new EmitComment(buf, sc);
+ if (!s)
+ v.emit(sc, null, null);
+ else
+ s.accept(v);
+}
+
+private void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc)
+{
+ extern (C++) final class ToDocBuffer : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ OutBuffer* buf;
+ Scope* sc;
+
+ extern (D) this(ref OutBuffer buf, Scope* sc)
+ {
+ this.buf = &buf;
+ this.sc = sc;
+ }
+
+ override void visit(Dsymbol s)
+ {
+ //printf("Dsymbol::toDocbuffer() %s\n", s.toChars());
+ HdrGenState hgs;
+ hgs.ddoc = true;
+ .toCBuffer(s, buf, &hgs);
+ }
+
+ void prefix(Dsymbol s)
+ {
+ if (s.isDeprecated())
+ buf.writestring("deprecated ");
+ if (Declaration d = s.isDeclaration())
+ {
+ emitVisibility(*buf, d);
+ if (d.isStatic())
+ buf.writestring("static ");
+ else if (d.isFinal())
+ buf.writestring("final ");
+ else if (d.isAbstract())
+ buf.writestring("abstract ");
+
+ if (d.isFuncDeclaration()) // functionToBufferFull handles this
+ return;
+
+ if (d.isImmutable())
+ buf.writestring("immutable ");
+ if (d.storage_class & STC.shared_)
+ buf.writestring("shared ");
+ if (d.isWild())
+ buf.writestring("inout ");
+ if (d.isConst())
+ buf.writestring("const ");
+
+ if (d.isSynchronized())
+ buf.writestring("synchronized ");
+
+ if (d.storage_class & STC.manifest)
+ buf.writestring("enum ");
+
+ // Add "auto" for the untyped variable in template members
+ if (!d.type && d.isVarDeclaration() &&
+ !d.isImmutable() && !(d.storage_class & STC.shared_) && !d.isWild() && !d.isConst() &&
+ !d.isSynchronized())
+ {
+ buf.writestring("auto ");
+ }
+ }
+ }
+
+ override void visit(Import i)
+ {
+ HdrGenState hgs;
+ hgs.ddoc = true;
+ emitVisibility(*buf, i);
+ .toCBuffer(i, buf, &hgs);
+ }
+
+ override void visit(Declaration d)
+ {
+ if (!d.ident)
+ return;
+ TemplateDeclaration td = getEponymousParent(d);
+ //printf("Declaration::toDocbuffer() %s, originalType = %s, td = %s\n", d.toChars(), d.originalType ? d.originalType.toChars() : "--", td ? td.toChars() : "--");
+ HdrGenState hgs;
+ hgs.ddoc = true;
+ if (d.isDeprecated())
+ buf.writestring("$(DEPRECATED ");
+ prefix(d);
+ if (d.type)
+ {
+ Type origType = d.originalType ? d.originalType : d.type;
+ if (origType.ty == Tfunction)
+ {
+ functionToBufferFull(cast(TypeFunction)origType, buf, d.ident, &hgs, td);
+ }
+ else
+ .toCBuffer(origType, buf, d.ident, &hgs);
+ }
+ else
+ buf.writestring(d.ident.toString());
+ if (d.isVarDeclaration() && td)
+ {
+ buf.writeByte('(');
+ if (td.origParameters && td.origParameters.dim)
+ {
+ for (size_t i = 0; i < td.origParameters.dim; i++)
+ {
+ if (i)
+ buf.writestring(", ");
+ toCBuffer((*td.origParameters)[i], buf, &hgs);
+ }
+ }
+ buf.writeByte(')');
+ }
+ // emit constraints if declaration is a templated declaration
+ if (td && td.constraint)
+ {
+ bool noFuncDecl = td.isFuncDeclaration() is null;
+ if (noFuncDecl)
+ {
+ buf.writestring("$(DDOC_CONSTRAINT ");
+ }
+
+ .toCBuffer(td.constraint, buf, &hgs);
+
+ if (noFuncDecl)
+ {
+ buf.writestring(")");
+ }
+ }
+ if (d.isDeprecated())
+ buf.writestring(")");
+ buf.writestring(";\n");
+ }
+
+ override void visit(AliasDeclaration ad)
+ {
+ //printf("AliasDeclaration::toDocbuffer() %s\n", ad.toChars());
+ if (!ad.ident)
+ return;
+ if (ad.isDeprecated())
+ buf.writestring("deprecated ");
+ emitVisibility(*buf, ad);
+ buf.printf("alias %s = ", ad.toChars());
+ if (Dsymbol s = ad.aliassym) // ident alias
+ {
+ prettyPrintDsymbol(s, ad.parent);
+ }
+ else if (Type type = ad.getType()) // type alias
+ {
+ if (type.ty == Tclass || type.ty == Tstruct || type.ty == Tenum)
+ {
+ if (Dsymbol s = type.toDsymbol(null)) // elaborate type
+ prettyPrintDsymbol(s, ad.parent);
+ else
+ buf.writestring(type.toChars());
+ }
+ else
+ {
+ // simple type
+ buf.writestring(type.toChars());
+ }
+ }
+ buf.writestring(";\n");
+ }
+
+ void parentToBuffer(Dsymbol s)
+ {
+ if (s && !s.isPackage() && !s.isModule())
+ {
+ parentToBuffer(s.parent);
+ buf.writestring(s.toChars());
+ buf.writestring(".");
+ }
+ }
+
+ static bool inSameModule(Dsymbol s, Dsymbol p)
+ {
+ for (; s; s = s.parent)
+ {
+ if (s.isModule())
+ break;
+ }
+ for (; p; p = p.parent)
+ {
+ if (p.isModule())
+ break;
+ }
+ return s == p;
+ }
+
+ void prettyPrintDsymbol(Dsymbol s, Dsymbol parent)
+ {
+ if (s.parent && (s.parent == parent)) // in current scope -> naked name
+ {
+ buf.writestring(s.toChars());
+ }
+ else if (!inSameModule(s, parent)) // in another module -> full name
+ {
+ buf.writestring(s.toPrettyChars());
+ }
+ else // nested in a type in this module -> full name w/o module name
+ {
+ // if alias is nested in a user-type use module-scope lookup
+ if (!parent.isModule() && !parent.isPackage())
+ buf.writestring(".");
+ parentToBuffer(s.parent);
+ buf.writestring(s.toChars());
+ }
+ }
+
+ override void visit(AggregateDeclaration ad)
+ {
+ if (!ad.ident)
+ return;
+ version (none)
+ {
+ emitVisibility(buf, ad);
+ }
+ buf.printf("%s %s", ad.kind(), ad.toChars());
+ buf.writestring(";\n");
+ }
+
+ override void visit(StructDeclaration sd)
+ {
+ //printf("StructDeclaration::toDocbuffer() %s\n", sd.toChars());
+ if (!sd.ident)
+ return;
+ version (none)
+ {
+ emitVisibility(buf, sd);
+ }
+ if (TemplateDeclaration td = getEponymousParent(sd))
+ {
+ toDocBuffer(td, *buf, sc);
+ }
+ else
+ {
+ buf.printf("%s %s", sd.kind(), sd.toChars());
+ }
+ buf.writestring(";\n");
+ }
+
+ override void visit(ClassDeclaration cd)
+ {
+ //printf("ClassDeclaration::toDocbuffer() %s\n", cd.toChars());
+ if (!cd.ident)
+ return;
+ version (none)
+ {
+ emitVisibility(*buf, cd);
+ }
+ if (TemplateDeclaration td = getEponymousParent(cd))
+ {
+ toDocBuffer(td, *buf, sc);
+ }
+ else
+ {
+ if (!cd.isInterfaceDeclaration() && cd.isAbstract())
+ buf.writestring("abstract ");
+ buf.printf("%s %s", cd.kind(), cd.toChars());
+ }
+ int any = 0;
+ for (size_t i = 0; i < cd.baseclasses.dim; i++)
+ {
+ BaseClass* bc = (*cd.baseclasses)[i];
+ if (bc.sym && bc.sym.ident == Id.Object)
+ continue;
+ if (any)
+ buf.writestring(", ");
+ else
+ {
+ buf.writestring(": ");
+ any = 1;
+ }
+
+ if (bc.sym)
+ {
+ buf.printf("$(DDOC_PSUPER_SYMBOL %s)", bc.sym.toPrettyChars());
+ }
+ else
+ {
+ HdrGenState hgs;
+ .toCBuffer(bc.type, buf, null, &hgs);
+ }
+ }
+ buf.writestring(";\n");
+ }
+
+ override void visit(EnumDeclaration ed)
+ {
+ if (!ed.ident)
+ return;
+ buf.printf("%s %s", ed.kind(), ed.toChars());
+ if (ed.memtype)
+ {
+ buf.writestring(": $(DDOC_ENUM_BASETYPE ");
+ HdrGenState hgs;
+ .toCBuffer(ed.memtype, buf, null, &hgs);
+ buf.writestring(")");
+ }
+ buf.writestring(";\n");
+ }
+
+ override void visit(EnumMember em)
+ {
+ if (!em.ident)
+ return;
+ buf.writestring(em.toChars());
+ }
+ }
+
+ scope ToDocBuffer v = new ToDocBuffer(buf, sc);
+ s.accept(v);
+}
+
+/***********************************************************
+ */
+struct DocComment
+{
+ Sections sections; // Section*[]
+ Section summary;
+ Section copyright;
+ Section macros;
+ MacroTable* pmacrotable;
+ Escape* escapetable;
+ Dsymbols a;
+
+ static DocComment* parse(Dsymbol s, const(char)* comment)
+ {
+ //printf("parse(%s): '%s'\n", s.toChars(), comment);
+ auto dc = new DocComment();
+ dc.a.push(s);
+ if (!comment)
+ return dc;
+ dc.parseSections(comment);
+ for (size_t i = 0; i < dc.sections.dim; i++)
+ {
+ Section sec = dc.sections[i];
+ if (iequals("copyright", sec.name))
+ {
+ dc.copyright = sec;
+ }
+ if (iequals("macros", sec.name))
+ {
+ dc.macros = sec;
+ }
+ }
+ return dc;
+ }
+
+ /************************************************
+ * Parse macros out of Macros: section.
+ * Macros are of the form:
+ * name1 = value1
+ *
+ * name2 = value2
+ */
+ extern(D) static void parseMacros(
+ Escape* escapetable, ref MacroTable pmacrotable, const(char)[] m)
+ {
+ const(char)* p = m.ptr;
+ size_t len = m.length;
+ const(char)* pend = p + len;
+ const(char)* tempstart = null;
+ size_t templen = 0;
+ const(char)* namestart = null;
+ size_t namelen = 0; // !=0 if line continuation
+ const(char)* textstart = null;
+ size_t textlen = 0;
+ while (p < pend)
+ {
+ // Skip to start of macro
+ while (1)
+ {
+ if (p >= pend)
+ goto Ldone;
+ switch (*p)
+ {
+ case ' ':
+ case '\t':
+ p++;
+ continue;
+ case '\r':
+ case '\n':
+ p++;
+ goto Lcont;
+ default:
+ if (isIdStart(p))
+ break;
+ if (namelen)
+ goto Ltext; // continuation of prev macro
+ goto Lskipline;
+ }
+ break;
+ }
+ tempstart = p;
+ while (1)
+ {
+ if (p >= pend)
+ goto Ldone;
+ if (!isIdTail(p))
+ break;
+ p += utfStride(p);
+ }
+ templen = p - tempstart;
+ while (1)
+ {
+ if (p >= pend)
+ goto Ldone;
+ if (!(*p == ' ' || *p == '\t'))
+ break;
+ p++;
+ }
+ if (*p != '=')
+ {
+ if (namelen)
+ goto Ltext; // continuation of prev macro
+ goto Lskipline;
+ }
+ p++;
+ if (p >= pend)
+ goto Ldone;
+ if (namelen)
+ {
+ // Output existing macro
+ L1:
+ //printf("macro '%.*s' = '%.*s'\n", cast(int)namelen, namestart, cast(int)textlen, textstart);
+ if (iequals("ESCAPES", namestart[0 .. namelen]))
+ parseEscapes(escapetable, textstart[0 .. textlen]);
+ else
+ pmacrotable.define(namestart[0 .. namelen], textstart[0 .. textlen]);
+ namelen = 0;
+ if (p >= pend)
+ break;
+ }
+ namestart = tempstart;
+ namelen = templen;
+ while (p < pend && (*p == ' ' || *p == '\t'))
+ p++;
+ textstart = p;
+ Ltext:
+ while (p < pend && *p != '\r' && *p != '\n')
+ p++;
+ textlen = p - textstart;
+ p++;
+ //printf("p = %p, pend = %p\n", p, pend);
+ Lcont:
+ continue;
+ Lskipline:
+ // Ignore this line
+ while (p < pend && *p != '\r' && *p != '\n')
+ p++;
+ }
+ Ldone:
+ if (namelen)
+ goto L1; // write out last one
+ }
+
+ /**************************************
+ * Parse escapes of the form:
+ * /c/string/
+ * where c is a single character.
+ * Multiple escapes can be separated
+ * by whitespace and/or commas.
+ */
+ static void parseEscapes(Escape* escapetable, const(char)[] text)
+ {
+ if (!escapetable)
+ {
+ escapetable = new Escape();
+ memset(escapetable, 0, Escape.sizeof);
+ }
+ //printf("parseEscapes('%.*s') pescapetable = %p\n", cast(int)text.length, text.ptr, escapetable);
+ const(char)* p = text.ptr;
+ const(char)* pend = p + text.length;
+ while (1)
+ {
+ while (1)
+ {
+ if (p + 4 >= pend)
+ return;
+ if (!(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == ','))
+ break;
+ p++;
+ }
+ if (p[0] != '/' || p[2] != '/')
+ return;
+ char c = p[1];
+ p += 3;
+ const(char)* start = p;
+ while (1)
+ {
+ if (p >= pend)
+ return;
+ if (*p == '/')
+ break;
+ p++;
+ }
+ size_t len = p - start;
+ char* s = cast(char*)memcpy(mem.xmalloc(len + 1), start, len);
+ s[len] = 0;
+ escapetable.strings[c] = s[0 .. len];
+ //printf("\t%c = '%s'\n", c, s);
+ p++;
+ }
+ }
+
+ /*****************************************
+ * Parse next paragraph out of *pcomment.
+ * Update *pcomment to point past paragraph.
+ * Returns NULL if no more paragraphs.
+ * If paragraph ends in 'identifier:',
+ * then (*pcomment)[0 .. idlen] is the identifier.
+ */
+ void parseSections(const(char)* comment)
+ {
+ const(char)* p;
+ const(char)* pstart;
+ const(char)* pend;
+ const(char)* idstart = null; // dead-store to prevent spurious warning
+ size_t idlen;
+ const(char)* name = null;
+ size_t namelen = 0;
+ //printf("parseSections('%s')\n", comment);
+ p = comment;
+ while (*p)
+ {
+ const(char)* pstart0 = p;
+ p = skipwhitespace(p);
+ pstart = p;
+ pend = p;
+
+ // Undo indent if starting with a list item
+ if ((*p == '-' || *p == '+' || *p == '*') && (*(p+1) == ' ' || *(p+1) == '\t'))
+ pstart = pstart0;
+ else
+ {
+ const(char)* pitem = p;
+ while (*pitem >= '0' && *pitem <= '9')
+ ++pitem;
+ if (pitem > p && *pitem == '.' && (*(pitem+1) == ' ' || *(pitem+1) == '\t'))
+ pstart = pstart0;
+ }
+
+ /* Find end of section, which is ended by one of:
+ * 'identifier:' (but not inside a code section)
+ * '\0'
+ */
+ idlen = 0;
+ int inCode = 0;
+ while (1)
+ {
+ // Check for start/end of a code section
+ if (*p == '-' || *p == '`' || *p == '~')
+ {
+ char c = *p;
+ int numdash = 0;
+ while (*p == c)
+ {
+ ++numdash;
+ p++;
+ }
+ // BUG: handle UTF PS and LS too
+ if ((!*p || *p == '\r' || *p == '\n' || (!inCode && c != '-')) && numdash >= 3)
+ {
+ inCode = inCode == c ? false : c;
+ if (inCode)
+ {
+ // restore leading indentation
+ while (pstart0 < pstart && isIndentWS(pstart - 1))
+ --pstart;
+ }
+ }
+ pend = p;
+ }
+ if (!inCode && isIdStart(p))
+ {
+ const(char)* q = p + utfStride(p);
+ while (isIdTail(q))
+ q += utfStride(q);
+
+ // Detected tag ends it
+ if (*q == ':' && isupper(*p)
+ && (isspace(q[1]) || q[1] == 0))
+ {
+ idlen = q - p;
+ idstart = p;
+ for (pend = p; pend > pstart; pend--)
+ {
+ if (pend[-1] == '\n')
+ break;
+ }
+ p = q + 1;
+ break;
+ }
+ }
+ while (1)
+ {
+ if (!*p)
+ goto L1;
+ if (*p == '\n')
+ {
+ p++;
+ if (*p == '\n' && !summary && !namelen && !inCode)
+ {
+ pend = p;
+ p++;
+ goto L1;
+ }
+ break;
+ }
+ p++;
+ pend = p;
+ }
+ p = skipwhitespace(p);
+ }
+ L1:
+ if (namelen || pstart < pend)
+ {
+ Section s;
+ if (iequals("Params", name[0 .. namelen]))
+ s = new ParamSection();
+ else if (iequals("Macros", name[0 .. namelen]))
+ s = new MacroSection();
+ else
+ s = new Section();
+ s.name = name[0 .. namelen];
+ s.body_ = pstart[0 .. pend - pstart];
+ s.nooutput = 0;
+ //printf("Section: '%.*s' = '%.*s'\n", cast(int)s.namelen, s.name, cast(int)s.bodylen, s.body);
+ sections.push(s);
+ if (!summary && !namelen)
+ summary = s;
+ }
+ if (idlen)
+ {
+ name = idstart;
+ namelen = idlen;
+ }
+ else
+ {
+ name = null;
+ namelen = 0;
+ if (!*p)
+ break;
+ }
+ }
+ }
+
+ void writeSections(Scope* sc, Dsymbols* a, OutBuffer* buf)
+ {
+ assert(a.dim);
+ //printf("DocComment::writeSections()\n");
+ Loc loc = (*a)[0].loc;
+ if (Module m = (*a)[0].isModule())
+ {
+ if (m.md)
+ loc = m.md.loc;
+ }
+ size_t offset1 = buf.length;
+ buf.writestring("$(DDOC_SECTIONS ");
+ size_t offset2 = buf.length;
+ for (size_t i = 0; i < sections.dim; i++)
+ {
+ Section sec = sections[i];
+ if (sec.nooutput)
+ continue;
+ //printf("Section: '%.*s' = '%.*s'\n", cast(int)sec.namelen, sec.name, cast(int)sec.bodylen, sec.body);
+ if (!sec.name.length && i == 0)
+ {
+ buf.writestring("$(DDOC_SUMMARY ");
+ size_t o = buf.length;
+ buf.write(sec.body_);
+ escapeStrayParenthesis(loc, buf, o, true);
+ highlightText(sc, a, loc, *buf, o);
+ buf.writestring(")");
+ }
+ else
+ sec.write(loc, &this, sc, a, buf);
+ }
+ for (size_t i = 0; i < a.dim; i++)
+ {
+ Dsymbol s = (*a)[i];
+ if (Dsymbol td = getEponymousParent(s))
+ s = td;
+ for (UnitTestDeclaration utd = s.ddocUnittest; utd; utd = utd.ddocUnittest)
+ {
+ if (utd.visibility.kind == Visibility.Kind.private_ || !utd.comment || !utd.fbody)
+ continue;
+ // Strip whitespaces to avoid showing empty summary
+ const(char)* c = utd.comment;
+ while (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')
+ ++c;
+ buf.writestring("$(DDOC_EXAMPLES ");
+ size_t o = buf.length;
+ buf.writestring(cast(char*)c);
+ if (utd.codedoc)
+ {
+ auto codedoc = utd.codedoc.stripLeadingNewlines;
+ size_t n = getCodeIndent(codedoc);
+ while (n--)
+ buf.writeByte(' ');
+ buf.writestring("----\n");
+ buf.writestring(codedoc);
+ buf.writestring("----\n");
+ highlightText(sc, a, loc, *buf, o);
+ }
+ buf.writestring(")");
+ }
+ }
+ if (buf.length == offset2)
+ {
+ /* Didn't write out any sections, so back out last write
+ */
+ buf.setsize(offset1);
+ buf.writestring("\n");
+ }
+ else
+ buf.writestring(")");
+ }
+}
+
+/*****************************************
+ * Return true if comment consists entirely of "ditto".
+ */
+private bool isDitto(const(char)* comment)
+{
+ if (comment)
+ {
+ const(char)* p = skipwhitespace(comment);
+ if (Port.memicmp(p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0)
+ return true;
+ }
+ return false;
+}
+
+/**********************************************
+ * Skip white space.
+ */
+private const(char)* skipwhitespace(const(char)* p)
+{
+ return skipwhitespace(p.toDString).ptr;
+}
+
+/// Ditto
+private const(char)[] skipwhitespace(const(char)[] p)
+{
+ foreach (idx, char c; p)
+ {
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ case '\n':
+ continue;
+ default:
+ return p[idx .. $];
+ }
+ }
+ return p[$ .. $];
+}
+
+/************************************************
+ * Scan past all instances of the given characters.
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` to start scanning from
+ * chars = the characters to skip; order is unimportant
+ * Returns: the index after skipping characters.
+ */
+private size_t skipChars(ref OutBuffer buf, size_t i, string chars)
+{
+ Outer:
+ foreach (j, c; buf[][i..$])
+ {
+ foreach (d; chars)
+ {
+ if (d == c)
+ continue Outer;
+ }
+ return i + j;
+ }
+ return buf.length;
+}
+
+unittest {
+ OutBuffer buf;
+ string data = "test ---\r\n\r\nend";
+ buf.write(data);
+
+ assert(skipChars(buf, 0, "-") == 0);
+ assert(skipChars(buf, 4, "-") == 4);
+ assert(skipChars(buf, 4, " -") == 8);
+ assert(skipChars(buf, 8, "\r\n") == 12);
+ assert(skipChars(buf, 12, "dne") == 15);
+}
+
+/****************************************************
+ * Replace all instances of `c` with `r` in the given string
+ * Params:
+ * s = the string to do replacements in
+ * c = the character to look for
+ * r = the string to replace `c` with
+ * Returns: `s` with `c` replaced with `r`
+ */
+private inout(char)[] replaceChar(inout(char)[] s, char c, string r) pure
+{
+ int count = 0;
+ foreach (char sc; s)
+ if (sc == c)
+ ++count;
+ if (count == 0)
+ return s;
+
+ char[] result;
+ result.reserve(s.length - count + (r.length * count));
+ size_t start = 0;
+ foreach (i, char sc; s)
+ {
+ if (sc == c)
+ {
+ result ~= s[start..i];
+ result ~= r;
+ start = i+1;
+ }
+ }
+ result ~= s[start..$];
+ return result;
+}
+
+///
+unittest
+{
+ assert("".replaceChar(',', "$(COMMA)") == "");
+ assert("ab".replaceChar(',', "$(COMMA)") == "ab");
+ assert("a,b".replaceChar(',', "$(COMMA)") == "a$(COMMA)b");
+ assert("a,,b".replaceChar(',', "$(COMMA)") == "a$(COMMA)$(COMMA)b");
+ assert(",ab".replaceChar(',', "$(COMMA)") == "$(COMMA)ab");
+ assert("ab,".replaceChar(',', "$(COMMA)") == "ab$(COMMA)");
+}
+
+/**
+ * Return a lowercased copy of a string.
+ * Params:
+ * s = the string to lowercase
+ * Returns: the lowercase version of the string or the original if already lowercase
+ */
+private string toLowercase(string s) pure
+{
+ string lower;
+ foreach (size_t i; 0..s.length)
+ {
+ char c = s[i];
+// TODO: maybe unicode lowercase, somehow
+ if (c >= 'A' && c <= 'Z')
+ {
+ if (!lower.length) {
+ lower.reserve(s.length);
+ }
+ lower ~= s[lower.length..i];
+ c += 'a' - 'A';
+ lower ~= c;
+ }
+ }
+ if (lower.length)
+ lower ~= s[lower.length..$];
+ else
+ lower = s;
+ return lower;
+}
+
+///
+unittest
+{
+ assert("".toLowercase == "");
+ assert("abc".toLowercase == "abc");
+ assert("ABC".toLowercase == "abc");
+ assert("aBc".toLowercase == "abc");
+}
+
+/************************************************
+ * Get the indent from one index to another, counting tab stops as four spaces wide
+ * per the Markdown spec.
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * from = the index within `buf` to start counting from, inclusive
+ * to = the index within `buf` to stop counting at, exclusive
+ * Returns: the indent
+ */
+private int getMarkdownIndent(ref OutBuffer buf, size_t from, size_t to)
+{
+ const slice = buf[];
+ if (to > slice.length)
+ to = slice.length;
+ int indent = 0;
+ foreach (const c; slice[from..to])
+ indent += (c == '\t') ? 4 - (indent % 4) : 1;
+ return indent;
+}
+
+/************************************************
+ * Scan forward to one of:
+ * start of identifier
+ * beginning of next line
+ * end of buf
+ */
+size_t skiptoident(ref OutBuffer buf, size_t i)
+{
+ const slice = buf[];
+ while (i < slice.length)
+ {
+ dchar c;
+ size_t oi = i;
+ if (utf_decodeChar(slice, i, c))
+ {
+ /* Ignore UTF errors, but still consume input
+ */
+ break;
+ }
+ if (c >= 0x80)
+ {
+ if (!isUniAlpha(c))
+ continue;
+ }
+ else if (!(isalpha(c) || c == '_' || c == '\n'))
+ continue;
+ i = oi;
+ break;
+ }
+ return i;
+}
+
+/************************************************
+ * Scan forward past end of identifier.
+ */
+private size_t skippastident(ref OutBuffer buf, size_t i)
+{
+ const slice = buf[];
+ while (i < slice.length)
+ {
+ dchar c;
+ size_t oi = i;
+ if (utf_decodeChar(slice, i, c))
+ {
+ /* Ignore UTF errors, but still consume input
+ */
+ break;
+ }
+ if (c >= 0x80)
+ {
+ if (isUniAlpha(c))
+ continue;
+ }
+ else if (isalnum(c) || c == '_')
+ continue;
+ i = oi;
+ break;
+ }
+ return i;
+}
+
+/************************************************
+ * Scan forward past end of an identifier that might
+ * contain dots (e.g. `abc.def`)
+ */
+private size_t skipPastIdentWithDots(ref OutBuffer buf, size_t i)
+{
+ const slice = buf[];
+ bool lastCharWasDot;
+ while (i < slice.length)
+ {
+ dchar c;
+ size_t oi = i;
+ if (utf_decodeChar(slice, i, c))
+ {
+ /* Ignore UTF errors, but still consume input
+ */
+ break;
+ }
+ if (c == '.')
+ {
+ // We need to distinguish between `abc.def`, abc..def`, and `abc.`
+ // Only `abc.def` is a valid identifier
+
+ if (lastCharWasDot)
+ {
+ i = oi;
+ break;
+ }
+
+ lastCharWasDot = true;
+ continue;
+ }
+ else
+ {
+ if (c >= 0x80)
+ {
+ if (isUniAlpha(c))
+ {
+ lastCharWasDot = false;
+ continue;
+ }
+ }
+ else if (isalnum(c) || c == '_')
+ {
+ lastCharWasDot = false;
+ continue;
+ }
+ i = oi;
+ break;
+ }
+ }
+
+ // if `abc.`
+ if (lastCharWasDot)
+ return i - 1;
+
+ return i;
+}
+
+/************************************************
+ * Scan forward past URL starting at i.
+ * We don't want to highlight parts of a URL.
+ * Returns:
+ * i if not a URL
+ * index just past it if it is a URL
+ */
+private size_t skippastURL(ref OutBuffer buf, size_t i)
+{
+ const slice = buf[][i .. $];
+ size_t j;
+ bool sawdot = false;
+ if (slice.length > 7 && Port.memicmp(slice.ptr, "http://", 7) == 0)
+ {
+ j = 7;
+ }
+ else if (slice.length > 8 && Port.memicmp(slice.ptr, "https://", 8) == 0)
+ {
+ j = 8;
+ }
+ else
+ goto Lno;
+ for (; j < slice.length; j++)
+ {
+ const c = slice[j];
+ if (isalnum(c))
+ continue;
+ if (c == '-' || c == '_' || c == '?' || c == '=' || c == '%' ||
+ c == '&' || c == '/' || c == '+' || c == '#' || c == '~')
+ continue;
+ if (c == '.')
+ {
+ sawdot = true;
+ continue;
+ }
+ break;
+ }
+ if (sawdot)
+ return i + j;
+Lno:
+ return i;
+}
+
+/****************************************************
+ * Remove a previously-inserted blank line macro.
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * iAt = the index within `buf` of the start of the `$(DDOC_BLANKLINE)`
+ * macro. Upon function return its value is set to `0`.
+ * i = an index within `buf`. If `i` is after `iAt` then it gets
+ * reduced by the length of the removed macro.
+ */
+private void removeBlankLineMacro(ref OutBuffer buf, ref size_t iAt, ref size_t i)
+{
+ if (!iAt)
+ return;
+
+ enum macroLength = "$(DDOC_BLANKLINE)".length;
+ buf.remove(iAt, macroLength);
+ if (i > iAt)
+ i -= macroLength;
+ iAt = 0;
+}
+
+/****************************************************
+ * Attempt to detect and replace a Markdown thematic break (HR). These are three
+ * or more of the same delimiter, optionally with spaces or tabs between any of
+ * them, e.g. `\n- - -\n` becomes `\n$(HR)\n`
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` of the first character of a potential
+ * thematic break. If the replacement is made `i` changes to
+ * point to the closing parenthesis of the `$(HR)` macro.
+ * iLineStart = the index within `buf` that the thematic break's line starts at
+ * loc = the current location within the file
+ * Returns: whether a thematic break was replaced
+ */
+private bool replaceMarkdownThematicBreak(ref OutBuffer buf, ref size_t i, size_t iLineStart, const ref Loc loc)
+{
+ if (!global.params.markdown)
+ return false;
+
+ const slice = buf[];
+ const c = buf[i];
+ size_t j = i + 1;
+ int repeat = 1;
+ for (; j < slice.length; j++)
+ {
+ if (buf[j] == c)
+ ++repeat;
+ else if (buf[j] != ' ' && buf[j] != '\t')
+ break;
+ }
+ if (repeat >= 3)
+ {
+ if (j >= buf.length || buf[j] == '\n' || buf[j] == '\r')
+ {
+ if (global.params.vmarkdown)
+ {
+ const s = buf[][i..j];
+ message(loc, "Ddoc: converted '%.*s' to a thematic break", cast(int)s.length, s.ptr);
+ }
+
+ buf.remove(iLineStart, j - iLineStart);
+ i = buf.insert(iLineStart, "$(HR)") - 1;
+ return true;
+ }
+ }
+ return false;
+}
+
+/****************************************************
+ * Detect the level of an ATX-style heading, e.g. `## This is a heading` would
+ * have a level of `2`.
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` of the first `#` character
+ * Returns:
+ * the detected heading level from 1 to 6, or
+ * 0 if not at an ATX heading
+ */
+private int detectAtxHeadingLevel(ref OutBuffer buf, const size_t i)
+{
+ if (!global.params.markdown)
+ return 0;
+
+ const iHeadingStart = i;
+ const iAfterHashes = skipChars(buf, i, "#");
+ const headingLevel = cast(int) (iAfterHashes - iHeadingStart);
+ if (headingLevel > 6)
+ return 0;
+
+ const iTextStart = skipChars(buf, iAfterHashes, " \t");
+ const emptyHeading = buf[iTextStart] == '\r' || buf[iTextStart] == '\n';
+
+ // require whitespace
+ if (!emptyHeading && iTextStart == iAfterHashes)
+ return 0;
+
+ return headingLevel;
+}
+
+/****************************************************
+ * Remove any trailing `##` suffix from an ATX-style heading.
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` to start looking for a suffix at
+ */
+private void removeAnyAtxHeadingSuffix(ref OutBuffer buf, size_t i)
+{
+ size_t j = i;
+ size_t iSuffixStart = 0;
+ size_t iWhitespaceStart = j;
+ const slice = buf[];
+ for (; j < slice.length; j++)
+ {
+ switch (slice[j])
+ {
+ case '#':
+ if (iWhitespaceStart && !iSuffixStart)
+ iSuffixStart = j;
+ continue;
+ case ' ':
+ case '\t':
+ if (!iWhitespaceStart)
+ iWhitespaceStart = j;
+ continue;
+ case '\r':
+ case '\n':
+ break;
+ default:
+ iSuffixStart = 0;
+ iWhitespaceStart = 0;
+ continue;
+ }
+ break;
+ }
+ if (iSuffixStart)
+ buf.remove(iWhitespaceStart, j - iWhitespaceStart);
+}
+
+/****************************************************
+ * Wrap text in a Markdown heading macro, e.g. `$(H2 heading text`).
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * iStart = the index within `buf` that the Markdown heading starts at
+ * iEnd = the index within `buf` of the character after the last
+ * heading character. Is incremented by the length of the
+ * inserted heading macro when this function ends.
+ * loc = the location of the Ddoc within the file
+ * headingLevel = the level (1-6) of heading to end. Is set to `0` when this
+ * function ends.
+ */
+private void endMarkdownHeading(ref OutBuffer buf, size_t iStart, ref size_t iEnd, const ref Loc loc, ref int headingLevel)
+{
+ if (!global.params.markdown)
+ return;
+ if (global.params.vmarkdown)
+ {
+ const s = buf[][iStart..iEnd];
+ message(loc, "Ddoc: added heading '%.*s'", cast(int)s.length, s.ptr);
+ }
+
+ char[5] heading = "$(H0 ";
+ heading[3] = cast(char) ('0' + headingLevel);
+ buf.insert(iStart, heading);
+ iEnd += 5;
+ size_t iBeforeNewline = iEnd;
+ while (buf[iBeforeNewline-1] == '\r' || buf[iBeforeNewline-1] == '\n')
+ --iBeforeNewline;
+ buf.insert(iBeforeNewline, ")");
+ headingLevel = 0;
+}
+
+/****************************************************
+ * End all nested Markdown quotes, if inside any.
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` of the character after the quote text.
+ * quoteLevel = the current quote level. Is set to `0` when this function ends.
+ * Returns: the amount that `i` was moved
+ */
+private size_t endAllMarkdownQuotes(ref OutBuffer buf, size_t i, ref int quoteLevel)
+{
+ const length = quoteLevel;
+ for (; quoteLevel > 0; --quoteLevel)
+ i = buf.insert(i, ")");
+ return length;
+}
+
+/****************************************************
+ * Convenience function to end all Markdown lists and quotes, if inside any, and
+ * set `quoteMacroLevel` to `0`.
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` of the character after the list and/or
+ * quote text. Is adjusted when this function ends if any lists
+ * and/or quotes were ended.
+ * nestedLists = a set of nested lists. Upon return it will be empty.
+ * quoteLevel = the current quote level. Is set to `0` when this function ends.
+ * quoteMacroLevel = the macro level that the quote was started at. Is set to
+ * `0` when this function ends.
+ * Returns: the amount that `i` was moved
+ */
+private size_t endAllListsAndQuotes(ref OutBuffer buf, ref size_t i, ref MarkdownList[] nestedLists, ref int quoteLevel, out int quoteMacroLevel)
+{
+ quoteMacroLevel = 0;
+ const i0 = i;
+ i += MarkdownList.endAllNestedLists(buf, i, nestedLists);
+ i += endAllMarkdownQuotes(buf, i, quoteLevel);
+ return i - i0;
+}
+
+/****************************************************
+ * Replace Markdown emphasis with the appropriate macro,
+ * e.g. `*very* **nice**` becomes `$(EM very) $(STRONG nice)`.
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * loc = the current location within the file
+ * inlineDelimiters = the collection of delimiters found within a paragraph. When this function returns its length will be reduced to `downToLevel`.
+ * downToLevel = the length within `inlineDelimiters`` to reduce emphasis to
+ * Returns: the number of characters added to the buffer by the replacements
+ */
+private size_t replaceMarkdownEmphasis(ref OutBuffer buf, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, int downToLevel = 0)
+{
+ if (!global.params.markdown)
+ return 0;
+
+ size_t replaceEmphasisPair(ref MarkdownDelimiter start, ref MarkdownDelimiter end)
+ {
+ immutable count = start.count == 1 || end.count == 1 ? 1 : 2;
+
+ size_t iStart = start.iStart;
+ size_t iEnd = end.iStart;
+ end.count -= count;
+ start.count -= count;
+ iStart += start.count;
+
+ if (!start.count)
+ start.type = 0;
+ if (!end.count)
+ end.type = 0;
+
+ if (global.params.vmarkdown)
+ {
+ const s = buf[][iStart + count..iEnd];
+ message(loc, "Ddoc: emphasized text '%.*s'", cast(int)s.length, s.ptr);
+ }
+
+ buf.remove(iStart, count);
+ iEnd -= count;
+ buf.remove(iEnd, count);
+
+ string macroName = count >= 2 ? "$(STRONG " : "$(EM ";
+ buf.insert(iEnd, ")");
+ buf.insert(iStart, macroName);
+
+ const delta = 1 + macroName.length - (count + count);
+ end.iStart += count;
+ return delta;
+ }
+
+ size_t delta = 0;
+ int start = (cast(int) inlineDelimiters.length) - 1;
+ while (start >= downToLevel)
+ {
+ // find start emphasis
+ while (start >= downToLevel &&
+ (inlineDelimiters[start].type != '*' || !inlineDelimiters[start].leftFlanking))
+ --start;
+ if (start < downToLevel)
+ break;
+
+ // find the nearest end emphasis
+ int end = start + 1;
+ while (end < inlineDelimiters.length &&
+ (inlineDelimiters[end].type != inlineDelimiters[start].type ||
+ inlineDelimiters[end].macroLevel != inlineDelimiters[start].macroLevel ||
+ !inlineDelimiters[end].rightFlanking))
+ ++end;
+ if (end == inlineDelimiters.length)
+ {
+ // the start emphasis has no matching end; if it isn't an end itself then kill it
+ if (!inlineDelimiters[start].rightFlanking)
+ inlineDelimiters[start].type = 0;
+ --start;
+ continue;
+ }
+
+ // multiple-of-3 rule
+ if (((inlineDelimiters[start].leftFlanking && inlineDelimiters[start].rightFlanking) ||
+ (inlineDelimiters[end].leftFlanking && inlineDelimiters[end].rightFlanking)) &&
+ (inlineDelimiters[start].count + inlineDelimiters[end].count) % 3 == 0)
+ {
+ --start;
+ continue;
+ }
+
+ immutable delta0 = replaceEmphasisPair(inlineDelimiters[start], inlineDelimiters[end]);
+
+ for (; end < inlineDelimiters.length; ++end)
+ inlineDelimiters[end].iStart += delta0;
+ delta += delta0;
+ }
+
+ inlineDelimiters.length = downToLevel;
+ return delta;
+}
+
+/****************************************************
+ */
+private bool isIdentifier(Dsymbols* a, const(char)* p, size_t len)
+{
+ foreach (member; *a)
+ {
+ if (auto imp = member.isImport())
+ {
+ // For example: `public import str = core.stdc.string;`
+ // This checks if `p` is equal to `str`
+ if (imp.aliasId)
+ {
+ if (p[0 .. len] == imp.aliasId.toString())
+ return true;
+ }
+ else
+ {
+ // The general case: `public import core.stdc.string;`
+
+ // fully qualify imports so `core.stdc.string` doesn't appear as `core`
+ string fullyQualifiedImport;
+ foreach (const pid; imp.packages)
+ {
+ fullyQualifiedImport ~= pid.toString() ~ ".";
+ }
+ fullyQualifiedImport ~= imp.id.toString();
+
+ // Check if `p` == `core.stdc.string`
+ if (p[0 .. len] == fullyQualifiedImport)
+ return true;
+ }
+ }
+ else if (member.ident)
+ {
+ if (p[0 .. len] == member.ident.toString())
+ return true;
+ }
+
+ }
+ return false;
+}
+
+/****************************************************
+ */
+private bool isKeyword(const(char)* p, size_t len)
+{
+ immutable string[3] table = ["true", "false", "null"];
+ foreach (s; table)
+ {
+ if (p[0 .. len] == s)
+ return true;
+ }
+ return false;
+}
+
+/****************************************************
+ */
+private TypeFunction isTypeFunction(Dsymbol s)
+{
+ FuncDeclaration f = s.isFuncDeclaration();
+ /* f.type may be NULL for template members.
+ */
+ if (f && f.type)
+ {
+ Type t = f.originalType ? f.originalType : f.type;
+ if (t.ty == Tfunction)
+ return cast(TypeFunction)t;
+ }
+ return null;
+}
+
+/****************************************************
+ */
+private Parameter isFunctionParameter(Dsymbol s, const(char)* p, size_t len)
+{
+ TypeFunction tf = isTypeFunction(s);
+ if (tf && tf.parameterList.parameters)
+ {
+ foreach (fparam; *tf.parameterList.parameters)
+ {
+ if (fparam.ident && p[0 .. len] == fparam.ident.toString())
+ {
+ return fparam;
+ }
+ }
+ }
+ return null;
+}
+
+/****************************************************
+ */
+private Parameter isFunctionParameter(Dsymbols* a, const(char)* p, size_t len)
+{
+ for (size_t i = 0; i < a.dim; i++)
+ {
+ Parameter fparam = isFunctionParameter((*a)[i], p, len);
+ if (fparam)
+ {
+ return fparam;
+ }
+ }
+ return null;
+}
+
+/****************************************************
+ */
+private Parameter isEponymousFunctionParameter(Dsymbols *a, const(char) *p, size_t len)
+{
+ for (size_t i = 0; i < a.dim; i++)
+ {
+ TemplateDeclaration td = (*a)[i].isTemplateDeclaration();
+ if (td && td.onemember)
+ {
+ /* Case 1: we refer to a template declaration inside the template
+
+ /// ...ddoc...
+ template case1(T) {
+ void case1(R)() {}
+ }
+ */
+ td = td.onemember.isTemplateDeclaration();
+ }
+ if (!td)
+ {
+ /* Case 2: we're an alias to a template declaration
+
+ /// ...ddoc...
+ alias case2 = case1!int;
+ */
+ AliasDeclaration ad = (*a)[i].isAliasDeclaration();
+ if (ad && ad.aliassym)
+ {
+ td = ad.aliassym.isTemplateDeclaration();
+ }
+ }
+ while (td)
+ {
+ Dsymbol sym = getEponymousMember(td);
+ if (sym)
+ {
+ Parameter fparam = isFunctionParameter(sym, p, len);
+ if (fparam)
+ {
+ return fparam;
+ }
+ }
+ td = td.overnext;
+ }
+ }
+ return null;
+}
+
+/****************************************************
+ */
+private TemplateParameter isTemplateParameter(Dsymbols* a, const(char)* p, size_t len)
+{
+ for (size_t i = 0; i < a.dim; i++)
+ {
+ TemplateDeclaration td = (*a)[i].isTemplateDeclaration();
+ // Check for the parent, if the current symbol is not a template declaration.
+ if (!td)
+ td = getEponymousParent((*a)[i]);
+ if (td && td.origParameters)
+ {
+ foreach (tp; *td.origParameters)
+ {
+ if (tp.ident && p[0 .. len] == tp.ident.toString())
+ {
+ return tp;
+ }
+ }
+ }
+ }
+ return null;
+}
+
+/****************************************************
+ * Return true if str is a reserved symbol name
+ * that starts with a double underscore.
+ */
+private bool isReservedName(const(char)[] str)
+{
+ immutable string[] table =
+ [
+ "__ctor",
+ "__dtor",
+ "__postblit",
+ "__invariant",
+ "__unitTest",
+ "__require",
+ "__ensure",
+ "__dollar",
+ "__ctfe",
+ "__withSym",
+ "__result",
+ "__returnLabel",
+ "__vptr",
+ "__monitor",
+ "__gate",
+ "__xopEquals",
+ "__xopCmp",
+ "__LINE__",
+ "__FILE__",
+ "__MODULE__",
+ "__FUNCTION__",
+ "__PRETTY_FUNCTION__",
+ "__DATE__",
+ "__TIME__",
+ "__TIMESTAMP__",
+ "__VENDOR__",
+ "__VERSION__",
+ "__EOF__",
+ "__CXXLIB__",
+ "__LOCAL_SIZE",
+ "__entrypoint",
+ ];
+ foreach (s; table)
+ {
+ if (str == s)
+ return true;
+ }
+ return false;
+}
+
+/****************************************************
+ * A delimiter for Markdown inline content like emphasis and links.
+ */
+private struct MarkdownDelimiter
+{
+ size_t iStart; /// the index where this delimiter starts
+ int count; /// the length of this delimeter's start sequence
+ int macroLevel; /// the count of nested DDoc macros when the delimiter is started
+ bool leftFlanking; /// whether the delimiter is left-flanking, as defined by the CommonMark spec
+ bool rightFlanking; /// whether the delimiter is right-flanking, as defined by the CommonMark spec
+ bool atParagraphStart; /// whether the delimiter is at the start of a paragraph
+ char type; /// the type of delimiter, defined by its starting character
+
+ /// whether this describes a valid delimiter
+ @property bool isValid() const { return count != 0; }
+
+ /// flag this delimiter as invalid
+ void invalidate() { count = 0; }
+}
+
+/****************************************************
+ * Info about a Markdown list.
+ */
+private struct MarkdownList
+{
+ string orderedStart; /// an optional start number--if present then the list starts at this number
+ size_t iStart; /// the index where the list item starts
+ size_t iContentStart; /// the index where the content starts after the list delimiter
+ int delimiterIndent; /// the level of indent the list delimiter starts at
+ int contentIndent; /// the level of indent the content starts at
+ int macroLevel; /// the count of nested DDoc macros when the list is started
+ char type; /// the type of list, defined by its starting character
+
+ /// whether this describes a valid list
+ @property bool isValid() const { return type != type.init; }
+
+ /****************************************************
+ * Try to parse a list item, returning whether successful.
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * iLineStart = the index within `buf` of the first character of the line
+ * i = the index within `buf` of the potential list item
+ * Returns: the parsed list item. Its `isValid` property describes whether parsing succeeded.
+ */
+ static MarkdownList parseItem(ref OutBuffer buf, size_t iLineStart, size_t i)
+ {
+ if (!global.params.markdown)
+ return MarkdownList();
+
+ if (buf[i] == '+' || buf[i] == '-' || buf[i] == '*')
+ return parseUnorderedListItem(buf, iLineStart, i);
+ else
+ return parseOrderedListItem(buf, iLineStart, i);
+ }
+
+ /****************************************************
+ * Return whether the context is at a list item of the same type as this list.
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * iLineStart = the index within `buf` of the first character of the line
+ * i = the index within `buf` of the list item
+ * Returns: whether `i` is at a list item of the same type as this list
+ */
+ private bool isAtItemInThisList(ref OutBuffer buf, size_t iLineStart, size_t i)
+ {
+ MarkdownList item = (type == '.' || type == ')') ?
+ parseOrderedListItem(buf, iLineStart, i) :
+ parseUnorderedListItem(buf, iLineStart, i);
+ if (item.type == type)
+ return item.delimiterIndent < contentIndent && item.contentIndent > delimiterIndent;
+ return false;
+ }
+
+ /****************************************************
+ * Start a Markdown list item by creating/deleting nested lists and starting the item.
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * iLineStart = the index within `buf` of the first character of the line. If this function succeeds it will be adjuested to equal `i`.
+ * i = the index within `buf` of the list item. If this function succeeds `i` will be adjusted to fit the inserted macro.
+ * iPrecedingBlankLine = the index within `buf` of the preceeding blank line. If non-zero and a new list was started, the preceeding blank line is removed and this value is set to `0`.
+ * nestedLists = a set of nested lists. If this function succeeds it may contain a new nested list.
+ * loc = the location of the Ddoc within the file
+ * Returns: `true` if a list was created
+ */
+ bool startItem(ref OutBuffer buf, ref size_t iLineStart, ref size_t i, ref size_t iPrecedingBlankLine, ref MarkdownList[] nestedLists, const ref Loc loc)
+ {
+ buf.remove(iStart, iContentStart - iStart);
+
+ if (!nestedLists.length ||
+ delimiterIndent >= nestedLists[$-1].contentIndent ||
+ buf[iLineStart - 4..iLineStart] == "$(LI")
+ {
+ // start a list macro
+ nestedLists ~= this;
+ if (type == '.')
+ {
+ if (orderedStart.length)
+ {
+ iStart = buf.insert(iStart, "$(OL_START ");
+ iStart = buf.insert(iStart, orderedStart);
+ iStart = buf.insert(iStart, ",\n");
+ }
+ else
+ iStart = buf.insert(iStart, "$(OL\n");
+ }
+ else
+ iStart = buf.insert(iStart, "$(UL\n");
+
+ removeBlankLineMacro(buf, iPrecedingBlankLine, iStart);
+ }
+ else if (nestedLists.length)
+ {
+ nestedLists[$-1].delimiterIndent = delimiterIndent;
+ nestedLists[$-1].contentIndent = contentIndent;
+ }
+
+ iStart = buf.insert(iStart, "$(LI\n");
+ i = iStart - 1;
+ iLineStart = i;
+
+ if (global.params.vmarkdown)
+ {
+ size_t iEnd = iStart;
+ while (iEnd < buf.length && buf[iEnd] != '\r' && buf[iEnd] != '\n')
+ ++iEnd;
+ const s = buf[][iStart..iEnd];
+ message(loc, "Ddoc: starting list item '%.*s'", cast(int)s.length, s.ptr);
+ }
+
+ return true;
+ }
+
+ /****************************************************
+ * End all nested Markdown lists.
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` to end lists at.
+ * nestedLists = a set of nested lists. Upon return it will be empty.
+ * Returns: the amount that `i` changed
+ */
+ static size_t endAllNestedLists(ref OutBuffer buf, size_t i, ref MarkdownList[] nestedLists)
+ {
+ const iStart = i;
+ for (; nestedLists.length; --nestedLists.length)
+ i = buf.insert(i, ")\n)");
+ return i - iStart;
+ }
+
+ /****************************************************
+ * Look for a sibling list item or the end of nested list(s).
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` to end lists at. If there was a sibling or ending lists `i` will be adjusted to fit the macro endings.
+ * iParagraphStart = the index within `buf` to start the next paragraph at at. May be adjusted upon return.
+ * nestedLists = a set of nested lists. Some nested lists may have been removed from it upon return.
+ */
+ static void handleSiblingOrEndingList(ref OutBuffer buf, ref size_t i, ref size_t iParagraphStart, ref MarkdownList[] nestedLists)
+ {
+ size_t iAfterSpaces = skipChars(buf, i + 1, " \t");
+
+ if (nestedLists[$-1].isAtItemInThisList(buf, i + 1, iAfterSpaces))
+ {
+ // end a sibling list item
+ i = buf.insert(i, ")");
+ iParagraphStart = skipChars(buf, i, " \t\r\n");
+ }
+ else if (iAfterSpaces >= buf.length || (buf[iAfterSpaces] != '\r' && buf[iAfterSpaces] != '\n'))
+ {
+ // end nested lists that are indented more than this content
+ const indent = getMarkdownIndent(buf, i + 1, iAfterSpaces);
+ while (nestedLists.length && nestedLists[$-1].contentIndent > indent)
+ {
+ i = buf.insert(i, ")\n)");
+ --nestedLists.length;
+ iParagraphStart = skipChars(buf, i, " \t\r\n");
+
+ if (nestedLists.length && nestedLists[$-1].isAtItemInThisList(buf, i + 1, iParagraphStart))
+ {
+ i = buf.insert(i, ")");
+ ++iParagraphStart;
+ break;
+ }
+ }
+ }
+ }
+
+ /****************************************************
+ * Parse an unordered list item at the current position
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * iLineStart = the index within `buf` of the first character of the line
+ * i = the index within `buf` of the list item
+ * Returns: the parsed list item, or a list item with type `.init` if no list item is available
+ */
+ private static MarkdownList parseUnorderedListItem(ref OutBuffer buf, size_t iLineStart, size_t i)
+ {
+ if (i+1 < buf.length &&
+ (buf[i] == '-' ||
+ buf[i] == '*' ||
+ buf[i] == '+') &&
+ (buf[i+1] == ' ' ||
+ buf[i+1] == '\t' ||
+ buf[i+1] == '\r' ||
+ buf[i+1] == '\n'))
+ {
+ const iContentStart = skipChars(buf, i + 1, " \t");
+ const delimiterIndent = getMarkdownIndent(buf, iLineStart, i);
+ const contentIndent = getMarkdownIndent(buf, iLineStart, iContentStart);
+ auto list = MarkdownList(null, iLineStart, iContentStart, delimiterIndent, contentIndent, 0, buf[i]);
+ return list;
+ }
+ return MarkdownList();
+ }
+
+ /****************************************************
+ * Parse an ordered list item at the current position
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * iLineStart = the index within `buf` of the first character of the line
+ * i = the index within `buf` of the list item
+ * Returns: the parsed list item, or a list item with type `.init` if no list item is available
+ */
+ private static MarkdownList parseOrderedListItem(ref OutBuffer buf, size_t iLineStart, size_t i)
+ {
+ size_t iAfterNumbers = skipChars(buf, i, "0123456789");
+ if (iAfterNumbers - i > 0 &&
+ iAfterNumbers - i <= 9 &&
+ iAfterNumbers + 1 < buf.length &&
+ buf[iAfterNumbers] == '.' &&
+ (buf[iAfterNumbers+1] == ' ' ||
+ buf[iAfterNumbers+1] == '\t' ||
+ buf[iAfterNumbers+1] == '\r' ||
+ buf[iAfterNumbers+1] == '\n'))
+ {
+ const iContentStart = skipChars(buf, iAfterNumbers + 1, " \t");
+ const delimiterIndent = getMarkdownIndent(buf, iLineStart, i);
+ const contentIndent = getMarkdownIndent(buf, iLineStart, iContentStart);
+ size_t iNumberStart = skipChars(buf, i, "0");
+ if (iNumberStart == iAfterNumbers)
+ --iNumberStart;
+ auto orderedStart = buf[][iNumberStart .. iAfterNumbers];
+ if (orderedStart == "1")
+ orderedStart = null;
+ return MarkdownList(orderedStart.idup, iLineStart, iContentStart, delimiterIndent, contentIndent, 0, buf[iAfterNumbers]);
+ }
+ return MarkdownList();
+ }
+}
+
+/****************************************************
+ * A Markdown link.
+ */
+private struct MarkdownLink
+{
+ string href; /// the link destination
+ string title; /// an optional title for the link
+ string label; /// an optional label for the link
+ Dsymbol symbol; /// an optional symbol to link to
+
+ /****************************************************
+ * Replace a Markdown link or link definition in the form of:
+ * - Inline link: `[foo](url/ 'optional title')`
+ * - Reference link: `[foo][bar]`, `[foo][]` or `[foo]`
+ * - Link reference definition: `[bar]: url/ 'optional title'`
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` that points to the `]` character of the potential link.
+ * If this function succeeds it will be adjusted to fit the inserted link macro.
+ * loc = the current location within the file
+ * inlineDelimiters = previously parsed Markdown delimiters, including emphasis and link/image starts
+ * delimiterIndex = the index within `inlineDelimiters` of the nearest link/image starting delimiter
+ * linkReferences = previously parsed link references. When this function returns it may contain
+ * additional previously unparsed references.
+ * Returns: whether a reference link was found and replaced at `i`
+ */
+ static bool replaceLink(ref OutBuffer buf, ref size_t i, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, int delimiterIndex, ref MarkdownLinkReferences linkReferences)
+ {
+ const delimiter = inlineDelimiters[delimiterIndex];
+ MarkdownLink link;
+
+ size_t iEnd = link.parseReferenceDefinition(buf, i, delimiter);
+ if (iEnd > i)
+ {
+ i = delimiter.iStart;
+ link.storeAndReplaceDefinition(buf, i, iEnd, linkReferences, loc);
+ inlineDelimiters.length = delimiterIndex;
+ return true;
+ }
+
+ iEnd = link.parseInlineLink(buf, i);
+ if (iEnd == i)
+ {
+ iEnd = link.parseReferenceLink(buf, i, delimiter);
+ if (iEnd > i)
+ {
+ const label = link.label;
+ link = linkReferences.lookupReference(label, buf, i, loc);
+ // check rightFlanking to avoid replacing things like int[string]
+ if (!link.href.length && !delimiter.rightFlanking)
+ link = linkReferences.lookupSymbol(label);
+ if (!link.href.length)
+ return false;
+ }
+ }
+
+ if (iEnd == i)
+ return false;
+
+ immutable delta = replaceMarkdownEmphasis(buf, loc, inlineDelimiters, delimiterIndex);
+ iEnd += delta;
+ i += delta;
+
+ if (global.params.vmarkdown)
+ {
+ const s = buf[][delimiter.iStart..iEnd];
+ message(loc, "Ddoc: linking '%.*s' to '%.*s'", cast(int)s.length, s.ptr, cast(int)link.href.length, link.href.ptr);
+ }
+
+ link.replaceLink(buf, i, iEnd, delimiter);
+ return true;
+ }
+
+ /****************************************************
+ * Replace a Markdown link definition in the form of `[bar]: url/ 'optional title'`
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` that points to the `]` character of the potential link.
+ * If this function succeeds it will be adjusted to fit the inserted link macro.
+ * inlineDelimiters = previously parsed Markdown delimiters, including emphasis and link/image starts
+ * delimiterIndex = the index within `inlineDelimiters` of the nearest link/image starting delimiter
+ * linkReferences = previously parsed link references. When this function returns it may contain
+ * additional previously unparsed references.
+ * loc = the current location in the file
+ * Returns: whether a reference link was found and replaced at `i`
+ */
+ static bool replaceReferenceDefinition(ref OutBuffer buf, ref size_t i, ref MarkdownDelimiter[] inlineDelimiters, int delimiterIndex, ref MarkdownLinkReferences linkReferences, const ref Loc loc)
+ {
+ const delimiter = inlineDelimiters[delimiterIndex];
+ MarkdownLink link;
+ size_t iEnd = link.parseReferenceDefinition(buf, i, delimiter);
+ if (iEnd == i)
+ return false;
+
+ i = delimiter.iStart;
+ link.storeAndReplaceDefinition(buf, i, iEnd, linkReferences, loc);
+ inlineDelimiters.length = delimiterIndex;
+ return true;
+ }
+
+ /****************************************************
+ * Parse a Markdown inline link in the form of `[foo](url/ 'optional title')`
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` that points to the `]` character of the inline link.
+ * Returns: the index at the end of parsing the link, or `i` if parsing failed.
+ */
+ private size_t parseInlineLink(ref OutBuffer buf, size_t i)
+ {
+ size_t iEnd = i + 1;
+ if (iEnd >= buf.length || buf[iEnd] != '(')
+ return i;
+ ++iEnd;
+
+ if (!parseHref(buf, iEnd))
+ return i;
+
+ iEnd = skipChars(buf, iEnd, " \t\r\n");
+ if (buf[iEnd] != ')')
+ {
+ if (parseTitle(buf, iEnd))
+ iEnd = skipChars(buf, iEnd, " \t\r\n");
+ }
+
+ if (buf[iEnd] != ')')
+ return i;
+
+ return iEnd + 1;
+ }
+
+ /****************************************************
+ * Parse a Markdown reference link in the form of `[foo][bar]`, `[foo][]` or `[foo]`
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` that points to the `]` character of the inline link.
+ * delimiter = the delimiter that starts this link
+ * Returns: the index at the end of parsing the link, or `i` if parsing failed.
+ */
+ private size_t parseReferenceLink(ref OutBuffer buf, size_t i, MarkdownDelimiter delimiter)
+ {
+ size_t iStart = i + 1;
+ size_t iEnd = iStart;
+ if (iEnd >= buf.length || buf[iEnd] != '[' || (iEnd+1 < buf.length && buf[iEnd+1] == ']'))
+ {
+ // collapsed reference [foo][] or shortcut reference [foo]
+ iStart = delimiter.iStart + delimiter.count - 1;
+ if (buf[iEnd] == '[')
+ iEnd += 2;
+ }
+
+ parseLabel(buf, iStart);
+ if (!label.length)
+ return i;
+
+ if (iEnd < iStart)
+ iEnd = iStart;
+ return iEnd;
+ }
+
+ /****************************************************
+ * Parse a Markdown reference definition in the form of `[bar]: url/ 'optional title'`
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` that points to the `]` character of the inline link.
+ * delimiter = the delimiter that starts this link
+ * Returns: the index at the end of parsing the link, or `i` if parsing failed.
+ */
+ private size_t parseReferenceDefinition(ref OutBuffer buf, size_t i, MarkdownDelimiter delimiter)
+ {
+ if (!delimiter.atParagraphStart || delimiter.type != '[' ||
+ i+1 >= buf.length || buf[i+1] != ':')
+ return i;
+
+ size_t iEnd = delimiter.iStart;
+ parseLabel(buf, iEnd);
+ if (label.length == 0 || iEnd != i + 1)
+ return i;
+
+ ++iEnd;
+ iEnd = skipChars(buf, iEnd, " \t");
+ skipOneNewline(buf, iEnd);
+
+ if (!parseHref(buf, iEnd) || href.length == 0)
+ return i;
+
+ iEnd = skipChars(buf, iEnd, " \t");
+ const requireNewline = !skipOneNewline(buf, iEnd);
+ const iBeforeTitle = iEnd;
+
+ if (parseTitle(buf, iEnd))
+ {
+ iEnd = skipChars(buf, iEnd, " \t");
+ if (iEnd < buf.length && buf[iEnd] != '\r' && buf[iEnd] != '\n')
+ {
+ // the title must end with a newline
+ title.length = 0;
+ iEnd = iBeforeTitle;
+ }
+ }
+
+ iEnd = skipChars(buf, iEnd, " \t");
+ if (requireNewline && iEnd < buf.length-1 && buf[iEnd] != '\r' && buf[iEnd] != '\n')
+ return i;
+
+ return iEnd;
+ }
+
+ /****************************************************
+ * Parse and normalize a Markdown reference label
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` that points to the `[` character at the start of the label.
+ * If this function returns a non-empty label then `i` will point just after the ']' at the end of the label.
+ * Returns: the parsed and normalized label, possibly empty
+ */
+ private bool parseLabel(ref OutBuffer buf, ref size_t i)
+ {
+ if (buf[i] != '[')
+ return false;
+
+ const slice = buf[];
+ size_t j = i + 1;
+
+ // Some labels have already been en-symboled; handle that
+ const inSymbol = j+15 < slice.length && slice[j..j+15] == "$(DDOC_PSYMBOL ";
+ if (inSymbol)
+ j += 15;
+
+ for (; j < slice.length; ++j)
+ {
+ const c = slice[j];
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ if (label.length && label[$-1] != ' ')
+ label ~= ' ';
+ break;
+ case ')':
+ if (inSymbol && j+1 < slice.length && slice[j+1] == ']')
+ {
+ ++j;
+ goto case ']';
+ }
+ goto default;
+ case '[':
+ if (slice[j-1] != '\\')
+ {
+ label.length = 0;
+ return false;
+ }
+ break;
+ case ']':
+ if (label.length && label[$-1] == ' ')
+ --label.length;
+ if (label.length)
+ {
+ i = j + 1;
+ return true;
+ }
+ return false;
+ default:
+ label ~= c;
+ break;
+ }
+ }
+ label.length = 0;
+ return false;
+ }
+
+ /****************************************************
+ * Parse and store a Markdown link URL, optionally enclosed in `<>` brackets
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` that points to the first character of the URL.
+ * If this function succeeds `i` will point just after the the end of the URL.
+ * Returns: whether a URL was found and parsed
+ */
+ private bool parseHref(ref OutBuffer buf, ref size_t i)
+ {
+ size_t j = skipChars(buf, i, " \t");
+
+ size_t iHrefStart = j;
+ size_t parenDepth = 1;
+ bool inPointy = false;
+ const slice = buf[];
+ for (; j < slice.length; j++)
+ {
+ switch (slice[j])
+ {
+ case '<':
+ if (!inPointy && j == iHrefStart)
+ {
+ inPointy = true;
+ ++iHrefStart;
+ }
+ break;
+ case '>':
+ if (inPointy && slice[j-1] != '\\')
+ goto LReturnHref;
+ break;
+ case '(':
+ if (!inPointy && slice[j-1] != '\\')
+ ++parenDepth;
+ break;
+ case ')':
+ if (!inPointy && slice[j-1] != '\\')
+ {
+ --parenDepth;
+ if (!parenDepth)
+ goto LReturnHref;
+ }
+ break;
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ if (inPointy)
+ {
+ // invalid link
+ return false;
+ }
+ goto LReturnHref;
+ default:
+ break;
+ }
+ }
+ if (inPointy)
+ return false;
+ LReturnHref:
+ auto href = slice[iHrefStart .. j].dup;
+ this.href = cast(string) percentEncode(removeEscapeBackslashes(href)).replaceChar(',', "$(COMMA)");
+ i = j;
+ if (inPointy)
+ ++i;
+ return true;
+ }
+
+ /****************************************************
+ * Parse and store a Markdown link title, enclosed in parentheses or `'` or `"` quotes
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` that points to the first character of the title.
+ * If this function succeeds `i` will point just after the the end of the title.
+ * Returns: whether a title was found and parsed
+ */
+ private bool parseTitle(ref OutBuffer buf, ref size_t i)
+ {
+ size_t j = skipChars(buf, i, " \t");
+ if (j >= buf.length)
+ return false;
+
+ char type = buf[j];
+ if (type != '"' && type != '\'' && type != '(')
+ return false;
+ if (type == '(')
+ type = ')';
+
+ const iTitleStart = j + 1;
+ size_t iNewline = 0;
+ const slice = buf[];
+ for (j = iTitleStart; j < slice.length; j++)
+ {
+ const c = slice[j];
+ switch (c)
+ {
+ case ')':
+ case '"':
+ case '\'':
+ if (type == c && slice[j-1] != '\\')
+ goto LEndTitle;
+ iNewline = 0;
+ break;
+ case ' ':
+ case '\t':
+ case '\r':
+ break;
+ case '\n':
+ if (iNewline)
+ {
+ // no blank lines in titles
+ return false;
+ }
+ iNewline = j;
+ break;
+ default:
+ iNewline = 0;
+ break;
+ }
+ }
+ return false;
+ LEndTitle:
+ auto title = slice[iTitleStart .. j].dup;
+ this.title = cast(string) removeEscapeBackslashes(title).
+ replaceChar(',', "$(COMMA)").
+ replaceChar('"', "$(QUOTE)");
+ i = j + 1;
+ return true;
+ }
+
+ /****************************************************
+ * Replace a Markdown link or image with the appropriate macro
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` that points to the `]` character of the inline link.
+ * When this function returns it will be adjusted to the end of the inserted macro.
+ * iLinkEnd = the index within `buf` that points just after the last character of the link
+ * delimiter = the Markdown delimiter that started the link or image
+ */
+ private void replaceLink(ref OutBuffer buf, ref size_t i, size_t iLinkEnd, MarkdownDelimiter delimiter)
+ {
+ size_t iAfterLink = i - delimiter.count;
+ string macroName;
+ if (symbol)
+ {
+ macroName = "$(SYMBOL_LINK ";
+ }
+ else if (title.length)
+ {
+ if (delimiter.type == '[')
+ macroName = "$(LINK_TITLE ";
+ else
+ macroName = "$(IMAGE_TITLE ";
+ }
+ else
+ {
+ if (delimiter.type == '[')
+ macroName = "$(LINK2 ";
+ else
+ macroName = "$(IMAGE ";
+ }
+ buf.remove(delimiter.iStart, delimiter.count);
+ buf.remove(i - delimiter.count, iLinkEnd - i);
+ iLinkEnd = buf.insert(delimiter.iStart, macroName);
+ iLinkEnd = buf.insert(iLinkEnd, href);
+ iLinkEnd = buf.insert(iLinkEnd, ", ");
+ iAfterLink += macroName.length + href.length + 2;
+ if (title.length)
+ {
+ iLinkEnd = buf.insert(iLinkEnd, title);
+ iLinkEnd = buf.insert(iLinkEnd, ", ");
+ iAfterLink += title.length + 2;
+
+ // Link macros with titles require escaping commas
+ for (size_t j = iLinkEnd; j < iAfterLink; ++j)
+ if (buf[j] == ',')
+ {
+ buf.remove(j, 1);
+ j = buf.insert(j, "$(COMMA)") - 1;
+ iAfterLink += 7;
+ }
+ }
+// TODO: if image, remove internal macros, leaving only text
+ buf.insert(iAfterLink, ")");
+ i = iAfterLink;
+ }
+
+ /****************************************************
+ * Store the Markdown link definition and remove it from `buf`
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` that points to the `[` character at the start of the link definition.
+ * When this function returns it will be adjusted to exclude the link definition.
+ * iEnd = the index within `buf` that points just after the end of the definition
+ * linkReferences = previously parsed link references. When this function returns it may contain
+ * an additional reference.
+ * loc = the current location in the file
+ */
+ private void storeAndReplaceDefinition(ref OutBuffer buf, ref size_t i, size_t iEnd, ref MarkdownLinkReferences linkReferences, const ref Loc loc)
+ {
+ if (global.params.vmarkdown)
+ message(loc, "Ddoc: found link reference '%.*s' to '%.*s'", cast(int)label.length, label.ptr, cast(int)href.length, href.ptr);
+
+ // Remove the definition and trailing whitespace
+ iEnd = skipChars(buf, iEnd, " \t\r\n");
+ buf.remove(i, iEnd - i);
+ i -= 2;
+
+ string lowercaseLabel = label.toLowercase();
+ if (lowercaseLabel !in linkReferences.references)
+ linkReferences.references[lowercaseLabel] = this;
+ }
+
+ /****************************************************
+ * Remove Markdown escaping backslashes from the given string
+ * Params:
+ * s = the string to remove escaping backslashes from
+ * Returns: `s` without escaping backslashes in it
+ */
+ private static char[] removeEscapeBackslashes(char[] s)
+ {
+ if (!s.length)
+ return s;
+
+ // avoid doing anything if there isn't anything to escape
+ size_t i;
+ for (i = 0; i < s.length-1; ++i)
+ if (s[i] == '\\' && ispunct(s[i+1]))
+ break;
+ if (i == s.length-1)
+ return s;
+
+ // copy characters backwards, then truncate
+ size_t j = i + 1;
+ s[i] = s[j];
+ for (++i, ++j; j < s.length; ++i, ++j)
+ {
+ if (j < s.length-1 && s[j] == '\\' && ispunct(s[j+1]))
+ ++j;
+ s[i] = s[j];
+ }
+ s.length -= (j - i);
+ return s;
+ }
+
+ ///
+ unittest
+ {
+ assert(removeEscapeBackslashes("".dup) == "");
+ assert(removeEscapeBackslashes(`\a`.dup) == `\a`);
+ assert(removeEscapeBackslashes(`.\`.dup) == `.\`);
+ assert(removeEscapeBackslashes(`\.\`.dup) == `.\`);
+ assert(removeEscapeBackslashes(`\.`.dup) == `.`);
+ assert(removeEscapeBackslashes(`\.\.`.dup) == `..`);
+ assert(removeEscapeBackslashes(`a\.b\.c`.dup) == `a.b.c`);
+ }
+
+ /****************************************************
+ * Percent-encode (AKA URL-encode) the given string
+ * Params:
+ * s = the string to percent-encode
+ * Returns: `s` with special characters percent-encoded
+ */
+ private static inout(char)[] percentEncode(inout(char)[] s) pure
+ {
+ static bool shouldEncode(char c)
+ {
+ return ((c < '0' && c != '!' && c != '#' && c != '$' && c != '%' && c != '&' && c != '\'' && c != '(' &&
+ c != ')' && c != '*' && c != '+' && c != ',' && c != '-' && c != '.' && c != '/')
+ || (c > '9' && c < 'A' && c != ':' && c != ';' && c != '=' && c != '?' && c != '@')
+ || (c > 'Z' && c < 'a' && c != '[' && c != ']' && c != '_')
+ || (c > 'z' && c != '~'));
+ }
+
+ for (size_t i = 0; i < s.length; ++i)
+ {
+ if (shouldEncode(s[i]))
+ {
+ immutable static hexDigits = "0123456789ABCDEF";
+ immutable encoded1 = hexDigits[s[i] >> 4];
+ immutable encoded2 = hexDigits[s[i] & 0x0F];
+ s = s[0..i] ~ '%' ~ encoded1 ~ encoded2 ~ s[i+1..$];
+ i += 2;
+ }
+ }
+ return s;
+ }
+
+ ///
+ unittest
+ {
+ assert(percentEncode("") == "");
+ assert(percentEncode("aB12-._~/?") == "aB12-._~/?");
+ assert(percentEncode("<\n>") == "%3C%0A%3E");
+ }
+
+ /**************************************************
+ * Skip a single newline at `i`
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` to start looking at.
+ * If this function succeeds `i` will point after the newline.
+ * Returns: whether a newline was skipped
+ */
+ private static bool skipOneNewline(ref OutBuffer buf, ref size_t i) pure
+ {
+ if (i < buf.length && buf[i] == '\r')
+ ++i;
+ if (i < buf.length && buf[i] == '\n')
+ {
+ ++i;
+ return true;
+ }
+ return false;
+ }
+}
+
+/**************************************************
+ * A set of Markdown link references.
+ */
+private struct MarkdownLinkReferences
+{
+ MarkdownLink[string] references; // link references keyed by normalized label
+ MarkdownLink[string] symbols; // link symbols keyed by name
+ Scope* _scope; // the current scope
+ bool extractedAll; // the index into the buffer of the last-parsed reference
+
+ /**************************************************
+ * Look up a reference by label, searching through the rest of the buffer if needed.
+ * Symbols in the current scope are searched for if the DDoc doesn't define the reference.
+ * Params:
+ * label = the label to find the reference for
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` to start searching for references at
+ * loc = the current location in the file
+ * Returns: a link. If the `href` member has a value then the reference is valid.
+ */
+ MarkdownLink lookupReference(string label, ref OutBuffer buf, size_t i, const ref Loc loc)
+ {
+ const lowercaseLabel = label.toLowercase();
+ if (lowercaseLabel !in references)
+ extractReferences(buf, i, loc);
+
+ if (lowercaseLabel in references)
+ return references[lowercaseLabel];
+
+ return MarkdownLink();
+ }
+
+ /**
+ * Look up the link for the D symbol with the given name.
+ * If found, the link is cached in the `symbols` member.
+ * Params:
+ * name = the name of the symbol
+ * Returns: the link for the symbol or a link with a `null` href
+ */
+ MarkdownLink lookupSymbol(string name)
+ {
+ if (name in symbols)
+ return symbols[name];
+
+ const ids = split(name, '.');
+
+ MarkdownLink link;
+ auto id = Identifier.lookup(ids[0].ptr, ids[0].length);
+ if (id)
+ {
+ auto loc = Loc();
+ auto symbol = _scope.search(loc, id, null, IgnoreErrors);
+ for (size_t i = 1; symbol && i < ids.length; ++i)
+ {
+ id = Identifier.lookup(ids[i].ptr, ids[i].length);
+ symbol = id !is null ? symbol.search(loc, id, IgnoreErrors) : null;
+ }
+ if (symbol)
+ link = MarkdownLink(createHref(symbol), null, name, symbol);
+ }
+
+ symbols[name] = link;
+ return link;
+ }
+
+ /**************************************************
+ * Remove and store all link references from the document, in the form of
+ * `[label]: href "optional title"`
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` to start looking at
+ * loc = the current location in the file
+ * Returns: whether a reference was extracted
+ */
+ private void extractReferences(ref OutBuffer buf, size_t i, const ref Loc loc)
+ {
+ static bool isFollowedBySpace(ref OutBuffer buf, size_t i)
+ {
+ return i+1 < buf.length && (buf[i+1] == ' ' || buf[i+1] == '\t');
+ }
+
+ if (extractedAll)
+ return;
+
+ bool leadingBlank = false;
+ int inCode = false;
+ bool newParagraph = true;
+ MarkdownDelimiter[] delimiters;
+ for (; i < buf.length; ++i)
+ {
+ const c = buf[i];
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ break;
+ case '\n':
+ if (leadingBlank && !inCode)
+ newParagraph = true;
+ leadingBlank = true;
+ break;
+ case '\\':
+ ++i;
+ break;
+ case '#':
+ if (leadingBlank && !inCode)
+ newParagraph = true;
+ leadingBlank = false;
+ break;
+ case '>':
+ if (leadingBlank && !inCode)
+ newParagraph = true;
+ break;
+ case '+':
+ if (leadingBlank && !inCode && isFollowedBySpace(buf, i))
+ newParagraph = true;
+ else
+ leadingBlank = false;
+ break;
+ case '0':
+ ..
+ case '9':
+ if (leadingBlank && !inCode)
+ {
+ i = skipChars(buf, i, "0123456789");
+ if (i < buf.length &&
+ (buf[i] == '.' || buf[i] == ')') &&
+ isFollowedBySpace(buf, i))
+ newParagraph = true;
+ else
+ leadingBlank = false;
+ }
+ break;
+ case '*':
+ if (leadingBlank && !inCode)
+ {
+ newParagraph = true;
+ if (!isFollowedBySpace(buf, i))
+ leadingBlank = false;
+ }
+ break;
+ case '`':
+ case '~':
+ if (leadingBlank && i+2 < buf.length && buf[i+1] == c && buf[i+2] == c)
+ {
+ inCode = inCode == c ? false : c;
+ i = skipChars(buf, i, [c]) - 1;
+ newParagraph = true;
+ }
+ leadingBlank = false;
+ break;
+ case '-':
+ if (leadingBlank && !inCode && isFollowedBySpace(buf, i))
+ goto case '+';
+ else
+ goto case '`';
+ case '[':
+ if (leadingBlank && !inCode && newParagraph)
+ delimiters ~= MarkdownDelimiter(i, 1, 0, false, false, true, c);
+ break;
+ case ']':
+ if (delimiters.length && !inCode &&
+ MarkdownLink.replaceReferenceDefinition(buf, i, delimiters, cast(int) delimiters.length - 1, this, loc))
+ --i;
+ break;
+ default:
+ if (leadingBlank)
+ newParagraph = false;
+ leadingBlank = false;
+ break;
+ }
+ }
+ extractedAll = true;
+ }
+
+ /**
+ * Split a string by a delimiter, excluding the delimiter.
+ * Params:
+ * s = the string to split
+ * delimiter = the character to split by
+ * Returns: the resulting array of strings
+ */
+ private static string[] split(string s, char delimiter) pure
+ {
+ string[] result;
+ size_t iStart = 0;
+ foreach (size_t i; 0..s.length)
+ if (s[i] == delimiter)
+ {
+ result ~= s[iStart..i];
+ iStart = i + 1;
+ }
+ result ~= s[iStart..$];
+ return result;
+ }
+
+ ///
+ unittest
+ {
+ assert(split("", ',') == [""]);
+ assert(split("ab", ',') == ["ab"]);
+ assert(split("a,b", ',') == ["a", "b"]);
+ assert(split("a,,b", ',') == ["a", "", "b"]);
+ assert(split(",ab", ',') == ["", "ab"]);
+ assert(split("ab,", ',') == ["ab", ""]);
+ }
+
+ /**
+ * Create a HREF for the given D symbol.
+ * The HREF is relative to the current location if possible.
+ * Params:
+ * symbol = the symbol to create a HREF for.
+ * Returns: the resulting href
+ */
+ private string createHref(Dsymbol symbol)
+ {
+ Dsymbol root = symbol;
+
+ const(char)[] lref;
+ while (symbol && symbol.ident && !symbol.isModule())
+ {
+ if (lref.length)
+ lref = '.' ~ lref;
+ lref = symbol.ident.toString() ~ lref;
+ symbol = symbol.parent;
+ }
+
+ const(char)[] path;
+ if (symbol && symbol.ident && symbol.isModule() != _scope._module)
+ {
+ do
+ {
+ root = symbol;
+
+ // If the module has a file name, we're done
+ if (const m = symbol.isModule())
+ if (m.docfile)
+ {
+ path = m.docfile.toString();
+ break;
+ }
+
+ if (path.length)
+ path = '_' ~ path;
+ path = symbol.ident.toString() ~ path;
+ symbol = symbol.parent;
+ } while (symbol && symbol.ident);
+
+ if (!symbol && path.length)
+ path ~= "$(DOC_EXTENSION)";
+ }
+
+ // Attempt an absolute URL if not in the same package
+ while (root.parent)
+ root = root.parent;
+ Dsymbol scopeRoot = _scope._module;
+ while (scopeRoot.parent)
+ scopeRoot = scopeRoot.parent;
+ if (scopeRoot != root)
+ {
+ path = "$(DOC_ROOT_" ~ root.ident.toString() ~ ')' ~ path;
+ lref = '.' ~ lref; // remote URIs like Phobos and Mir use .prefixes
+ }
+
+ return cast(string) (path ~ '#' ~ lref);
+ }
+}
+
+private enum TableColumnAlignment
+{
+ none,
+ left,
+ center,
+ right
+}
+
+/****************************************************
+ * Parse a Markdown table delimiter row in the form of `| -- | :-- | :--: | --: |`
+ * where the example text has four columns with the following alignments:
+ * default, left, center, and right. The first and last pipes are optional. If a
+ * delimiter row is found it will be removed from `buf`.
+ *
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * iStart = the index within `buf` that the delimiter row starts at
+ * inQuote = whether the table is inside a quote
+ * columnAlignments = alignments to populate for each column
+ * Returns: the index of the end of the parsed delimiter, or `0` if not found
+ */
+private size_t parseTableDelimiterRow(ref OutBuffer buf, const size_t iStart, bool inQuote, ref TableColumnAlignment[] columnAlignments)
+{
+ size_t i = skipChars(buf, iStart, inQuote ? ">| \t" : "| \t");
+ while (i < buf.length && buf[i] != '\r' && buf[i] != '\n')
+ {
+ const leftColon = buf[i] == ':';
+ if (leftColon)
+ ++i;
+
+ if (i >= buf.length || buf[i] != '-')
+ break;
+ i = skipChars(buf, i, "-");
+
+ const rightColon = i < buf.length && buf[i] == ':';
+ i = skipChars(buf, i, ": \t");
+
+ if (i >= buf.length || (buf[i] != '|' && buf[i] != '\r' && buf[i] != '\n'))
+ break;
+ i = skipChars(buf, i, "| \t");
+
+ columnAlignments ~= (leftColon && rightColon) ? TableColumnAlignment.center :
+ leftColon ? TableColumnAlignment.left :
+ rightColon ? TableColumnAlignment.right :
+ TableColumnAlignment.none;
+ }
+
+ if (i < buf.length && buf[i] != '\r' && buf[i] != '\n' && buf[i] != ')')
+ {
+ columnAlignments.length = 0;
+ return 0;
+ }
+
+ if (i < buf.length && buf[i] == '\r') ++i;
+ if (i < buf.length && buf[i] == '\n') ++i;
+ return i;
+}
+
+/****************************************************
+ * Look for a table delimiter row, and if found parse the previous row as a
+ * table header row. If both exist with a matching number of columns, start a
+ * table.
+ *
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * iStart = the index within `buf` that the table header row starts at, inclusive
+ * iEnd = the index within `buf` that the table header row ends at, exclusive
+ * loc = the current location in the file
+ * inQuote = whether the table is inside a quote
+ * inlineDelimiters = delimiters containing columns separators and any inline emphasis
+ * columnAlignments = the parsed alignments for each column
+ * Returns: the number of characters added by starting the table, or `0` if unchanged
+ */
+private size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, bool inQuote, ref MarkdownDelimiter[] inlineDelimiters, out TableColumnAlignment[] columnAlignments)
+{
+ const iDelimiterRowEnd = parseTableDelimiterRow(buf, iEnd + 1, inQuote, columnAlignments);
+ if (iDelimiterRowEnd)
+ {
+ const delta = replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, true);
+ if (delta)
+ {
+ buf.remove(iEnd + delta, iDelimiterRowEnd - iEnd);
+ buf.insert(iEnd + delta, "$(TBODY ");
+ buf.insert(iStart, "$(TABLE ");
+ return delta + 15;
+ }
+ }
+
+ columnAlignments.length = 0;
+ return 0;
+}
+
+/****************************************************
+ * Replace a Markdown table row in the form of table cells delimited by pipes:
+ * `| cell | cell | cell`. The first and last pipes are optional.
+ *
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * iStart = the index within `buf` that the table row starts at, inclusive
+ * iEnd = the index within `buf` that the table row ends at, exclusive
+ * loc = the current location in the file
+ * inlineDelimiters = delimiters containing columns separators and any inline emphasis
+ * columnAlignments = alignments for each column
+ * headerRow = if `true` then the number of columns will be enforced to match
+ * `columnAlignments.length` and the row will be surrounded by a
+ * `THEAD` macro
+ * Returns: the number of characters added by replacing the row, or `0` if unchanged
+ */
+private size_t replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, TableColumnAlignment[] columnAlignments, bool headerRow)
+{
+ if (!columnAlignments.length || iStart == iEnd)
+ return 0;
+
+ iStart = skipChars(buf, iStart, " \t");
+ int cellCount = 0;
+ foreach (delimiter; inlineDelimiters)
+ if (delimiter.type == '|' && !delimiter.leftFlanking)
+ ++cellCount;
+ bool ignoreLast = inlineDelimiters.length > 0 && inlineDelimiters[$-1].type == '|';
+ if (ignoreLast)
+ {
+ const iLast = skipChars(buf, inlineDelimiters[$-1].iStart + inlineDelimiters[$-1].count, " \t");
+ ignoreLast = iLast >= iEnd;
+ }
+ if (!ignoreLast)
+ ++cellCount;
+
+ if (headerRow && cellCount != columnAlignments.length)
+ return 0;
+
+ if (headerRow && global.params.vmarkdown)
+ {
+ const s = buf[][iStart..iEnd];
+ message(loc, "Ddoc: formatting table '%.*s'", cast(int)s.length, s.ptr);
+ }
+
+ size_t delta = 0;
+
+ void replaceTableCell(size_t iCellStart, size_t iCellEnd, int cellIndex, int di)
+ {
+ const eDelta = replaceMarkdownEmphasis(buf, loc, inlineDelimiters, di);
+ delta += eDelta;
+ iCellEnd += eDelta;
+
+ // strip trailing whitespace and delimiter
+ size_t i = iCellEnd - 1;
+ while (i > iCellStart && (buf[i] == '|' || buf[i] == ' ' || buf[i] == '\t'))
+ --i;
+ ++i;
+ buf.remove(i, iCellEnd - i);
+ delta -= iCellEnd - i;
+ iCellEnd = i;
+
+ buf.insert(iCellEnd, ")");
+ ++delta;
+
+ // strip initial whitespace and delimiter
+ i = skipChars(buf, iCellStart, "| \t");
+ buf.remove(iCellStart, i - iCellStart);
+ delta -= i - iCellStart;
+
+ switch (columnAlignments[cellIndex])
+ {
+ case TableColumnAlignment.none:
+ buf.insert(iCellStart, headerRow ? "$(TH " : "$(TD ");
+ delta += 5;
+ break;
+ case TableColumnAlignment.left:
+ buf.insert(iCellStart, "left, ");
+ delta += 6;
+ goto default;
+ case TableColumnAlignment.center:
+ buf.insert(iCellStart, "center, ");
+ delta += 8;
+ goto default;
+ case TableColumnAlignment.right:
+ buf.insert(iCellStart, "right, ");
+ delta += 7;
+ goto default;
+ default:
+ buf.insert(iCellStart, headerRow ? "$(TH_ALIGN " : "$(TD_ALIGN ");
+ delta += 11;
+ break;
+ }
+ }
+
+ int cellIndex = cellCount - 1;
+ size_t iCellEnd = iEnd;
+ foreach_reverse (di, delimiter; inlineDelimiters)
+ {
+ if (delimiter.type == '|')
+ {
+ if (ignoreLast && di == inlineDelimiters.length-1)
+ {
+ ignoreLast = false;
+ continue;
+ }
+
+ if (cellIndex >= columnAlignments.length)
+ {
+ // kill any extra cells
+ buf.remove(delimiter.iStart, iEnd + delta - delimiter.iStart);
+ delta -= iEnd + delta - delimiter.iStart;
+ iCellEnd = iEnd + delta;
+ --cellIndex;
+ continue;
+ }
+
+ replaceTableCell(delimiter.iStart, iCellEnd, cellIndex, cast(int) di);
+ iCellEnd = delimiter.iStart;
+ --cellIndex;
+ }
+ }
+
+ // if no starting pipe, replace from the start
+ if (cellIndex >= 0)
+ replaceTableCell(iStart, iCellEnd, cellIndex, 0);
+
+ buf.insert(iEnd + delta, ")");
+ buf.insert(iStart, "$(TR ");
+ delta += 6;
+
+ if (headerRow)
+ {
+ buf.insert(iEnd + delta, ")");
+ buf.insert(iStart, "$(THEAD ");
+ delta += 9;
+ }
+
+ return delta;
+}
+
+/****************************************************
+ * End a table, if in one.
+ *
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * i = the index within `buf` to end the table at
+ * columnAlignments = alignments for each column; upon return is set to length `0`
+ * Returns: the number of characters added by ending the table, or `0` if unchanged
+ */
+private size_t endTable(ref OutBuffer buf, size_t i, ref TableColumnAlignment[] columnAlignments)
+{
+ if (!columnAlignments.length)
+ return 0;
+
+ buf.insert(i, "))");
+ columnAlignments.length = 0;
+ return 2;
+}
+
+/****************************************************
+ * End a table row and then the table itself.
+ *
+ * Params:
+ * buf = an OutBuffer containing the DDoc
+ * iStart = the index within `buf` that the table row starts at, inclusive
+ * iEnd = the index within `buf` that the table row ends at, exclusive
+ * loc = the current location in the file
+ * inlineDelimiters = delimiters containing columns separators and any inline emphasis
+ * columnAlignments = alignments for each column; upon return is set to length `0`
+ * Returns: the number of characters added by replacing the row, or `0` if unchanged
+ */
+private size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, ref TableColumnAlignment[] columnAlignments)
+{
+ size_t delta = replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, false);
+ delta += endTable(buf, iEnd + delta, columnAlignments);
+ return delta;
+}
+
+/**************************************************
+ * Highlight text section.
+ *
+ * Params:
+ * scope = the current parse scope
+ * a = an array of D symbols at the current scope
+ * loc = source location of start of text. It is a mutable copy to allow incrementing its linenum, for printing the correct line number when an error is encountered in a multiline block of ddoc.
+ * buf = an OutBuffer containing the DDoc
+ * offset = the index within buf to start highlighting
+ */
+private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t offset)
+{
+ const incrementLoc = loc.linnum == 0 ? 1 : 0;
+ loc.linnum += incrementLoc;
+ loc.charnum = 0;
+ //printf("highlightText()\n");
+ bool leadingBlank = true;
+ size_t iParagraphStart = offset;
+ size_t iPrecedingBlankLine = 0;
+ int headingLevel = 0;
+ int headingMacroLevel = 0;
+ int quoteLevel = 0;
+ bool lineQuoted = false;
+ int quoteMacroLevel = 0;
+ MarkdownList[] nestedLists;
+ MarkdownDelimiter[] inlineDelimiters;
+ MarkdownLinkReferences linkReferences;
+ TableColumnAlignment[] columnAlignments;
+ bool tableRowDetected = false;
+ int inCode = 0;
+ int inBacktick = 0;
+ int macroLevel = 0;
+ int previousMacroLevel = 0;
+ int parenLevel = 0;
+ size_t iCodeStart = 0; // start of code section
+ size_t codeFenceLength = 0;
+ size_t codeIndent = 0;
+ string codeLanguage;
+ size_t iLineStart = offset;
+ linkReferences._scope = sc;
+ for (size_t i = offset; i < buf.length; i++)
+ {
+ char c = buf[i];
+ Lcont:
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ break;
+ case '\n':
+ if (inBacktick)
+ {
+ // `inline code` is only valid if contained on a single line
+ // otherwise, the backticks should be output literally.
+ //
+ // This lets things like `output from the linker' display
+ // unmolested while keeping the feature consistent with GitHub.
+ inBacktick = false;
+ inCode = false; // the backtick also assumes we're in code
+ // Nothing else is necessary since the DDOC_BACKQUOTED macro is
+ // inserted lazily at the close quote, meaning the rest of the
+ // text is already OK.
+ }
+ if (headingLevel)
+ {
+ i += replaceMarkdownEmphasis(buf, loc, inlineDelimiters);
+ endMarkdownHeading(buf, iParagraphStart, i, loc, headingLevel);
+ removeBlankLineMacro(buf, iPrecedingBlankLine, i);
+ ++i;
+ iParagraphStart = skipChars(buf, i, " \t\r\n");
+ }
+
+ if (tableRowDetected && !columnAlignments.length)
+ i += startTable(buf, iLineStart, i, loc, lineQuoted, inlineDelimiters, columnAlignments);
+ else if (columnAlignments.length)
+ {
+ const delta = replaceTableRow(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments, false);
+ if (delta)
+ i += delta;
+ else
+ i += endTable(buf, i, columnAlignments);
+ }
+
+ if (!inCode && nestedLists.length && !quoteLevel)
+ MarkdownList.handleSiblingOrEndingList(buf, i, iParagraphStart, nestedLists);
+
+ iPrecedingBlankLine = 0;
+ if (!inCode && i == iLineStart && i + 1 < buf.length) // if "\n\n"
+ {
+ i += endTable(buf, i, columnAlignments);
+ if (!lineQuoted && quoteLevel)
+ endAllListsAndQuotes(buf, i, nestedLists, quoteLevel, quoteMacroLevel);
+ i += replaceMarkdownEmphasis(buf, loc, inlineDelimiters);
+
+ // if we don't already know about this paragraph break then
+ // insert a blank line and record the paragraph break
+ if (iParagraphStart <= i)
+ {
+ iPrecedingBlankLine = i;
+ i = buf.insert(i, "$(DDOC_BLANKLINE)");
+ iParagraphStart = i + 1;
+ }
+ }
+ else if (inCode &&
+ i == iLineStart &&
+ i + 1 < buf.length &&
+ !lineQuoted &&
+ quoteLevel) // if "\n\n" in quoted code
+ {
+ inCode = false;
+ i = buf.insert(i, ")");
+ i += endAllMarkdownQuotes(buf, i, quoteLevel);
+ quoteMacroLevel = 0;
+ }
+ leadingBlank = true;
+ lineQuoted = false;
+ tableRowDetected = false;
+ iLineStart = i + 1;
+ loc.linnum += incrementLoc;
+
+ // update the paragraph start if we just entered a macro
+ if (previousMacroLevel < macroLevel && iParagraphStart < iLineStart)
+ iParagraphStart = iLineStart;
+ previousMacroLevel = macroLevel;
+ break;
+
+ case '<':
+ {
+ leadingBlank = false;
+ if (inCode)
+ break;
+ const slice = buf[];
+ auto p = &slice[i];
+ const se = sc._module.escapetable.escapeChar('<');
+ if (se == "&lt;")
+ {
+ // Generating HTML
+ // Skip over comments
+ if (p[1] == '!' && p[2] == '-' && p[3] == '-')
+ {
+ size_t j = i + 4;
+ p += 4;
+ while (1)
+ {
+ if (j == slice.length)
+ goto L1;
+ if (p[0] == '-' && p[1] == '-' && p[2] == '>')
+ {
+ i = j + 2; // place on closing '>'
+ break;
+ }
+ j++;
+ p++;
+ }
+ break;
+ }
+ // Skip over HTML tag
+ if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2])))
+ {
+ size_t j = i + 2;
+ p += 2;
+ while (1)
+ {
+ if (j == slice.length)
+ break;
+ if (p[0] == '>')
+ {
+ i = j; // place on closing '>'
+ break;
+ }
+ j++;
+ p++;
+ }
+ break;
+ }
+ }
+ L1:
+ // Replace '<' with '&lt;' character entity
+ if (se.length)
+ {
+ buf.remove(i, 1);
+ i = buf.insert(i, se);
+ i--; // point to ';'
+ }
+ break;
+ }
+
+ case '>':
+ {
+ if (leadingBlank && (!inCode || quoteLevel) && global.params.markdown)
+ {
+ if (!quoteLevel && global.params.vmarkdown)
+ {
+ size_t iEnd = i + 1;
+ while (iEnd < buf.length && buf[iEnd] != '\n')
+ ++iEnd;
+ const s = buf[][i .. iEnd];
+ message(loc, "Ddoc: starting quote block with '%.*s'", cast(int)s.length, s.ptr);
+ }
+
+ lineQuoted = true;
+ int lineQuoteLevel = 1;
+ size_t iAfterDelimiters = i + 1;
+ for (; iAfterDelimiters < buf.length; ++iAfterDelimiters)
+ {
+ const c0 = buf[iAfterDelimiters];
+ if (c0 == '>')
+ ++lineQuoteLevel;
+ else if (c0 != ' ' && c0 != '\t')
+ break;
+ }
+ if (!quoteMacroLevel)
+ quoteMacroLevel = macroLevel;
+ buf.remove(i, iAfterDelimiters - i);
+
+ if (quoteLevel < lineQuoteLevel)
+ {
+ i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ if (nestedLists.length)
+ {
+ const indent = getMarkdownIndent(buf, iLineStart, i);
+ if (indent < nestedLists[$-1].contentIndent)
+ i += MarkdownList.endAllNestedLists(buf, i, nestedLists);
+ }
+
+ for (; quoteLevel < lineQuoteLevel; ++quoteLevel)
+ {
+ i = buf.insert(i, "$(BLOCKQUOTE\n");
+ iLineStart = iParagraphStart = i;
+ }
+ --i;
+ }
+ else
+ {
+ --i;
+ if (nestedLists.length)
+ MarkdownList.handleSiblingOrEndingList(buf, i, iParagraphStart, nestedLists);
+ }
+ break;
+ }
+
+ leadingBlank = false;
+ if (inCode)
+ break;
+ // Replace '>' with '&gt;' character entity
+ const se = sc._module.escapetable.escapeChar('>');
+ if (se.length)
+ {
+ buf.remove(i, 1);
+ i = buf.insert(i, se);
+ i--; // point to ';'
+ }
+ break;
+ }
+
+ case '&':
+ {
+ leadingBlank = false;
+ if (inCode)
+ break;
+ char* p = cast(char*)&buf[].ptr[i];
+ if (p[1] == '#' || isalpha(p[1]))
+ break;
+ // already a character entity
+ // Replace '&' with '&amp;' character entity
+ const se = sc._module.escapetable.escapeChar('&');
+ if (se)
+ {
+ buf.remove(i, 1);
+ i = buf.insert(i, se);
+ i--; // point to ';'
+ }
+ break;
+ }
+
+ case '`':
+ {
+ const iAfterDelimiter = skipChars(buf, i, "`");
+ const count = iAfterDelimiter - i;
+
+ if (inBacktick == count)
+ {
+ inBacktick = 0;
+ inCode = 0;
+ OutBuffer codebuf;
+ codebuf.write(buf[iCodeStart + count .. i]);
+ // escape the contents, but do not perform highlighting except for DDOC_PSYMBOL
+ highlightCode(sc, a, codebuf, 0);
+ escapeStrayParenthesis(loc, &codebuf, 0, false);
+ buf.remove(iCodeStart, i - iCodeStart + count); // also trimming off the current `
+ immutable pre = "$(DDOC_BACKQUOTED ";
+ i = buf.insert(iCodeStart, pre);
+ i = buf.insert(i, codebuf[]);
+ i = buf.insert(i, ")");
+ i--; // point to the ending ) so when the for loop does i++, it will see the next character
+ break;
+ }
+
+ // Perhaps we're starting or ending a Markdown code block
+ if (leadingBlank && global.params.markdown && count >= 3)
+ {
+ bool moreBackticks = false;
+ for (size_t j = iAfterDelimiter; !moreBackticks && j < buf.length; ++j)
+ if (buf[j] == '`')
+ moreBackticks = true;
+ else if (buf[j] == '\r' || buf[j] == '\n')
+ break;
+ if (!moreBackticks)
+ goto case '-';
+ }
+
+ if (inCode)
+ {
+ if (inBacktick)
+ i = iAfterDelimiter - 1;
+ break;
+ }
+ inCode = c;
+ inBacktick = cast(int) count;
+ codeIndent = 0; // inline code is not indented
+ // All we do here is set the code flags and record
+ // the location. The macro will be inserted lazily
+ // so we can easily cancel the inBacktick if we come
+ // across a newline character.
+ iCodeStart = i;
+ i = iAfterDelimiter - 1;
+ break;
+ }
+
+ case '#':
+ {
+ /* A line beginning with # indicates an ATX-style heading. */
+ if (leadingBlank && !inCode)
+ {
+ leadingBlank = false;
+
+ headingLevel = detectAtxHeadingLevel(buf, i);
+ if (!headingLevel)
+ break;
+
+ i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ if (!lineQuoted && quoteLevel)
+ i += endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
+
+ // remove the ### prefix, including whitespace
+ i = skipChars(buf, i + headingLevel, " \t");
+ buf.remove(iLineStart, i - iLineStart);
+ i = iParagraphStart = iLineStart;
+
+ removeAnyAtxHeadingSuffix(buf, i);
+ --i;
+
+ headingMacroLevel = macroLevel;
+ }
+ break;
+ }
+
+ case '~':
+ {
+ if (leadingBlank && global.params.markdown)
+ {
+ // Perhaps we're starting or ending a Markdown code block
+ const iAfterDelimiter = skipChars(buf, i, "~");
+ if (iAfterDelimiter - i >= 3)
+ goto case '-';
+ }
+ leadingBlank = false;
+ break;
+ }
+
+ case '-':
+ /* A line beginning with --- delimits a code section.
+ * inCode tells us if it is start or end of a code section.
+ */
+ if (leadingBlank)
+ {
+ if (!inCode && c == '-')
+ {
+ const list = MarkdownList.parseItem(buf, iLineStart, i);
+ if (list.isValid)
+ {
+ if (replaceMarkdownThematicBreak(buf, i, iLineStart, loc))
+ {
+ removeBlankLineMacro(buf, iPrecedingBlankLine, i);
+ iParagraphStart = skipChars(buf, i+1, " \t\r\n");
+ break;
+ }
+ else
+ goto case '+';
+ }
+ }
+
+ size_t istart = i;
+ size_t eollen = 0;
+ leadingBlank = false;
+ const c0 = c; // if we jumped here from case '`' or case '~'
+ size_t iInfoString = 0;
+ if (!inCode)
+ codeLanguage.length = 0;
+ while (1)
+ {
+ ++i;
+ if (i >= buf.length)
+ break;
+ c = buf[i];
+ if (c == '\n')
+ {
+ eollen = 1;
+ break;
+ }
+ if (c == '\r')
+ {
+ eollen = 1;
+ if (i + 1 >= buf.length)
+ break;
+ if (buf[i + 1] == '\n')
+ {
+ eollen = 2;
+ break;
+ }
+ }
+ // BUG: handle UTF PS and LS too
+ if (c != c0 || iInfoString)
+ {
+ if (global.params.markdown && !iInfoString && !inCode && i - istart >= 3)
+ {
+ // Start a Markdown info string, like ```ruby
+ codeFenceLength = i - istart;
+ i = iInfoString = skipChars(buf, i, " \t");
+ }
+ else if (iInfoString && c != '`')
+ {
+ if (!codeLanguage.length && (c == ' ' || c == '\t'))
+ codeLanguage = cast(string) buf[iInfoString..i].idup;
+ }
+ else
+ {
+ iInfoString = 0;
+ goto Lcont;
+ }
+ }
+ }
+ if (i - istart < 3 || (inCode && (inCode != c0 || (inCode != '-' && i - istart < codeFenceLength))))
+ goto Lcont;
+ if (iInfoString)
+ {
+ if (!codeLanguage.length)
+ codeLanguage = cast(string) buf[iInfoString..i].idup;
+ }
+ else
+ codeFenceLength = i - istart;
+
+ // We have the start/end of a code section
+ // Remove the entire --- line, including blanks and \n
+ buf.remove(iLineStart, i - iLineStart + eollen);
+ i = iLineStart;
+ if (eollen)
+ leadingBlank = true;
+ if (inCode && (i <= iCodeStart))
+ {
+ // Empty code section, just remove it completely.
+ inCode = 0;
+ break;
+ }
+ if (inCode)
+ {
+ inCode = 0;
+ // The code section is from iCodeStart to i
+ OutBuffer codebuf;
+ codebuf.write(buf[iCodeStart .. i]);
+ codebuf.writeByte(0);
+ // Remove leading indentations from all lines
+ bool lineStart = true;
+ char* endp = cast(char*)codebuf[].ptr + codebuf.length;
+ for (char* p = cast(char*)codebuf[].ptr; p < endp;)
+ {
+ if (lineStart)
+ {
+ size_t j = codeIndent;
+ char* q = p;
+ while (j-- > 0 && q < endp && isIndentWS(q))
+ ++q;
+ codebuf.remove(p - cast(char*)codebuf[].ptr, q - p);
+ assert(cast(char*)codebuf[].ptr <= p);
+ assert(p < cast(char*)codebuf[].ptr + codebuf.length);
+ lineStart = false;
+ endp = cast(char*)codebuf[].ptr + codebuf.length; // update
+ continue;
+ }
+ if (*p == '\n')
+ lineStart = true;
+ ++p;
+ }
+ if (!codeLanguage.length || codeLanguage == "dlang" || codeLanguage == "d")
+ highlightCode2(sc, a, codebuf, 0);
+ else
+ codebuf.remove(codebuf.length-1, 1); // remove the trailing 0 byte
+ escapeStrayParenthesis(loc, &codebuf, 0, false);
+ buf.remove(iCodeStart, i - iCodeStart);
+ i = buf.insert(iCodeStart, codebuf[]);
+ i = buf.insert(i, ")\n");
+ i -= 2; // in next loop, c should be '\n'
+ }
+ else
+ {
+ i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ if (!lineQuoted && quoteLevel)
+ {
+ const delta = endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
+ i += delta;
+ istart += delta;
+ }
+
+ inCode = c0;
+ codeIndent = istart - iLineStart; // save indent count
+ if (codeLanguage.length && codeLanguage != "dlang" && codeLanguage != "d")
+ {
+ // backslash-escape
+ for (size_t j; j < codeLanguage.length - 1; ++j)
+ if (codeLanguage[j] == '\\' && ispunct(codeLanguage[j + 1]))
+ codeLanguage = codeLanguage[0..j] ~ codeLanguage[j + 1..$];
+
+ if (global.params.vmarkdown)
+ message(loc, "Ddoc: adding code block for language '%.*s'", cast(int)codeLanguage.length, codeLanguage.ptr);
+
+ i = buf.insert(i, "$(OTHER_CODE ");
+ i = buf.insert(i, codeLanguage);
+ i = buf.insert(i, ",");
+ }
+ else
+ i = buf.insert(i, "$(D_CODE ");
+ iCodeStart = i;
+ i--; // place i on >
+ leadingBlank = true;
+ }
+ }
+ break;
+
+ case '_':
+ {
+ if (leadingBlank && !inCode && replaceMarkdownThematicBreak(buf, i, iLineStart, loc))
+ {
+ i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ if (!lineQuoted && quoteLevel)
+ i += endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
+ removeBlankLineMacro(buf, iPrecedingBlankLine, i);
+ iParagraphStart = skipChars(buf, i+1, " \t\r\n");
+ break;
+ }
+ goto default;
+ }
+
+ case '+':
+ case '0':
+ ..
+ case '9':
+ {
+ if (leadingBlank && !inCode)
+ {
+ MarkdownList list = MarkdownList.parseItem(buf, iLineStart, i);
+ if (list.isValid)
+ {
+ // Avoid starting a numbered list in the middle of a paragraph
+ if (!nestedLists.length && list.orderedStart.length &&
+ iParagraphStart < iLineStart)
+ {
+ i += list.orderedStart.length - 1;
+ break;
+ }
+
+ i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ if (!lineQuoted && quoteLevel)
+ {
+ const delta = endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
+ i += delta;
+ list.iStart += delta;
+ list.iContentStart += delta;
+ }
+
+ list.macroLevel = macroLevel;
+ list.startItem(buf, iLineStart, i, iPrecedingBlankLine, nestedLists, loc);
+ break;
+ }
+ }
+ leadingBlank = false;
+ break;
+ }
+
+ case '*':
+ {
+ if (inCode || inBacktick || !global.params.markdown)
+ {
+ leadingBlank = false;
+ break;
+ }
+
+ if (leadingBlank)
+ {
+ // Check for a thematic break
+ if (replaceMarkdownThematicBreak(buf, i, iLineStart, loc))
+ {
+ i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ if (!lineQuoted && quoteLevel)
+ i += endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
+ removeBlankLineMacro(buf, iPrecedingBlankLine, i);
+ iParagraphStart = skipChars(buf, i+1, " \t\r\n");
+ break;
+ }
+
+ // An initial * indicates a Markdown list item
+ const list = MarkdownList.parseItem(buf, iLineStart, i);
+ if (list.isValid)
+ goto case '+';
+ }
+
+ // Markdown emphasis
+ const leftC = i > offset ? buf[i-1] : '\0';
+ size_t iAfterEmphasis = skipChars(buf, i+1, "*");
+ const rightC = iAfterEmphasis < buf.length ? buf[iAfterEmphasis] : '\0';
+ int count = cast(int) (iAfterEmphasis - i);
+ const leftFlanking = (rightC != '\0' && !isspace(rightC)) && (!ispunct(rightC) || leftC == '\0' || isspace(leftC) || ispunct(leftC));
+ const rightFlanking = (leftC != '\0' && !isspace(leftC)) && (!ispunct(leftC) || rightC == '\0' || isspace(rightC) || ispunct(rightC));
+ auto emphasis = MarkdownDelimiter(i, count, macroLevel, leftFlanking, rightFlanking, false, c);
+
+ if (!emphasis.leftFlanking && !emphasis.rightFlanking)
+ {
+ i = iAfterEmphasis - 1;
+ break;
+ }
+
+ inlineDelimiters ~= emphasis;
+ i += emphasis.count;
+ --i;
+ break;
+ }
+
+ case '!':
+ {
+ leadingBlank = false;
+
+ if (inCode || !global.params.markdown)
+ break;
+
+ if (i < buf.length-1 && buf[i+1] == '[')
+ {
+ const imageStart = MarkdownDelimiter(i, 2, macroLevel, false, false, false, c);
+ inlineDelimiters ~= imageStart;
+ ++i;
+ }
+ break;
+ }
+ case '[':
+ {
+ if (inCode || !global.params.markdown)
+ {
+ leadingBlank = false;
+ break;
+ }
+
+ const leftC = i > offset ? buf[i-1] : '\0';
+ const rightFlanking = leftC != '\0' && !isspace(leftC) && !ispunct(leftC);
+ const atParagraphStart = leadingBlank && iParagraphStart >= iLineStart;
+ const linkStart = MarkdownDelimiter(i, 1, macroLevel, false, rightFlanking, atParagraphStart, c);
+ inlineDelimiters ~= linkStart;
+ leadingBlank = false;
+ break;
+ }
+ case ']':
+ {
+ leadingBlank = false;
+
+ if (inCode || !global.params.markdown)
+ break;
+
+ for (int d = cast(int) inlineDelimiters.length - 1; d >= 0; --d)
+ {
+ const delimiter = inlineDelimiters[d];
+ if (delimiter.type == '[' || delimiter.type == '!')
+ {
+ if (delimiter.isValid &&
+ MarkdownLink.replaceLink(buf, i, loc, inlineDelimiters, d, linkReferences))
+ {
+ // if we removed a reference link then we're at line start
+ if (i <= delimiter.iStart)
+ leadingBlank = true;
+
+ // don't nest links
+ if (delimiter.type == '[')
+ for (--d; d >= 0; --d)
+ if (inlineDelimiters[d].type == '[')
+ inlineDelimiters[d].invalidate();
+ }
+ else
+ {
+ // nothing found, so kill the delimiter
+ inlineDelimiters = inlineDelimiters[0..d] ~ inlineDelimiters[d+1..$];
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ case '|':
+ {
+ if (inCode || !global.params.markdown)
+ {
+ leadingBlank = false;
+ break;
+ }
+
+ tableRowDetected = true;
+ inlineDelimiters ~= MarkdownDelimiter(i, 1, macroLevel, leadingBlank, false, false, c);
+ leadingBlank = false;
+ break;
+ }
+
+ case '\\':
+ {
+ leadingBlank = false;
+ if (inCode || i+1 >= buf.length || !global.params.markdown)
+ break;
+
+ /* Escape Markdown special characters */
+ char c1 = buf[i+1];
+ if (ispunct(c1))
+ {
+ if (global.params.vmarkdown)
+ message(loc, "Ddoc: backslash-escaped %c", c1);
+
+ buf.remove(i, 1);
+
+ auto se = sc._module.escapetable.escapeChar(c1);
+ if (!se)
+ se = c1 == '$' ? "$(DOLLAR)" : c1 == ',' ? "$(COMMA)" : null;
+ if (se)
+ {
+ buf.remove(i, 1);
+ i = buf.insert(i, se);
+ i--; // point to escaped char
+ }
+ }
+ break;
+ }
+
+ case '$':
+ {
+ /* Look for the start of a macro, '$(Identifier'
+ */
+ leadingBlank = false;
+ if (inCode || inBacktick)
+ break;
+ const slice = buf[];
+ auto p = &slice[i];
+ if (p[1] == '(' && isIdStart(&p[2]))
+ ++macroLevel;
+ break;
+ }
+
+ case '(':
+ {
+ if (!inCode && i > offset && buf[i-1] != '$')
+ ++parenLevel;
+ break;
+ }
+
+ case ')':
+ { /* End of macro
+ */
+ leadingBlank = false;
+ if (inCode || inBacktick)
+ break;
+ if (parenLevel > 0)
+ --parenLevel;
+ else if (macroLevel)
+ {
+ int downToLevel = cast(int) inlineDelimiters.length;
+ while (downToLevel > 0 && inlineDelimiters[downToLevel - 1].macroLevel >= macroLevel)
+ --downToLevel;
+ if (headingLevel && headingMacroLevel >= macroLevel)
+ {
+ endMarkdownHeading(buf, iParagraphStart, i, loc, headingLevel);
+ removeBlankLineMacro(buf, iPrecedingBlankLine, i);
+ }
+ i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ while (nestedLists.length && nestedLists[$-1].macroLevel >= macroLevel)
+ {
+ i = buf.insert(i, ")\n)");
+ --nestedLists.length;
+ }
+ if (quoteLevel && quoteMacroLevel >= macroLevel)
+ i += endAllMarkdownQuotes(buf, i, quoteLevel);
+ i += replaceMarkdownEmphasis(buf, loc, inlineDelimiters, downToLevel);
+
+ --macroLevel;
+ quoteMacroLevel = 0;
+ }
+ break;
+ }
+
+ default:
+ leadingBlank = false;
+ if (sc._module.isDocFile || inCode)
+ break;
+ const start = cast(char*)buf[].ptr + i;
+ if (isIdStart(start))
+ {
+ size_t j = skippastident(buf, i);
+ if (i < j)
+ {
+ size_t k = skippastURL(buf, i);
+ if (i < k)
+ {
+ /* The URL is buf[i..k]
+ */
+ if (macroLevel)
+ /* Leave alone if already in a macro
+ */
+ i = k - 1;
+ else
+ {
+ /* Replace URL with '$(DDOC_LINK_AUTODETECT URL)'
+ */
+ i = buf.bracket(i, "$(DDOC_LINK_AUTODETECT ", k, ")") - 1;
+ }
+ break;
+ }
+ }
+ else
+ break;
+ size_t len = j - i;
+ // leading '_' means no highlight unless it's a reserved symbol name
+ if (c == '_' && (i == 0 || !isdigit(*(start - 1))) && (i == buf.length - 1 || !isReservedName(start[0 .. len])))
+ {
+ buf.remove(i, 1);
+ i = buf.bracket(i, "$(DDOC_AUTO_PSYMBOL_SUPPRESS ", j - 1, ")") - 1;
+ break;
+ }
+ if (isIdentifier(a, start, len))
+ {
+ i = buf.bracket(i, "$(DDOC_AUTO_PSYMBOL ", j, ")") - 1;
+ break;
+ }
+ if (isKeyword(start, len))
+ {
+ i = buf.bracket(i, "$(DDOC_AUTO_KEYWORD ", j, ")") - 1;
+ break;
+ }
+ if (isFunctionParameter(a, start, len))
+ {
+ //printf("highlighting arg '%s', i = %d, j = %d\n", arg.ident.toChars(), i, j);
+ i = buf.bracket(i, "$(DDOC_AUTO_PARAM ", j, ")") - 1;
+ break;
+ }
+ i = j - 1;
+ }
+ break;
+ }
+ }
+
+ if (inCode == '-')
+ error(loc, "unmatched `---` in DDoc comment");
+ else if (inCode)
+ buf.insert(buf.length, ")");
+
+ size_t i = buf.length;
+ if (headingLevel)
+ {
+ endMarkdownHeading(buf, iParagraphStart, i, loc, headingLevel);
+ removeBlankLineMacro(buf, iPrecedingBlankLine, i);
+ }
+ i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+ i += replaceMarkdownEmphasis(buf, loc, inlineDelimiters);
+ endAllListsAndQuotes(buf, i, nestedLists, quoteLevel, quoteMacroLevel);
+}
+
+/**************************************************
+ * Highlight code for DDOC section.
+ */
+private void highlightCode(Scope* sc, Dsymbol s, ref OutBuffer buf, size_t offset)
+{
+ auto imp = s.isImport();
+ if (imp && imp.aliases.dim > 0)
+ {
+ // For example: `public import core.stdc.string : memcpy, memcmp;`
+ for(int i = 0; i < imp.aliases.dim; i++)
+ {
+ // Need to distinguish between
+ // `public import core.stdc.string : memcpy, memcmp;` and
+ // `public import core.stdc.string : copy = memcpy, compare = memcmp;`
+ auto a = imp.aliases[i];
+ auto id = a ? a : imp.names[i];
+ auto loc = Loc.init;
+ if (auto symFromId = sc.search(loc, id, null))
+ {
+ highlightCode(sc, symFromId, buf, offset);
+ }
+ }
+ }
+ else
+ {
+ OutBuffer ancbuf;
+ emitAnchor(ancbuf, s, sc);
+ buf.insert(offset, ancbuf[]);
+ offset += ancbuf.length;
+
+ Dsymbols a;
+ a.push(s);
+ highlightCode(sc, &a, buf, offset);
+ }
+}
+
+/****************************************************
+ */
+private void highlightCode(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset)
+{
+ //printf("highlightCode(a = '%s')\n", a.toChars());
+ bool resolvedTemplateParameters = false;
+
+ for (size_t i = offset; i < buf.length; i++)
+ {
+ char c = buf[i];
+ const se = sc._module.escapetable.escapeChar(c);
+ if (se.length)
+ {
+ buf.remove(i, 1);
+ i = buf.insert(i, se);
+ i--; // point to ';'
+ continue;
+ }
+ char* start = cast(char*)buf[].ptr + i;
+ if (isIdStart(start))
+ {
+ size_t j = skipPastIdentWithDots(buf, i);
+ if (i < j)
+ {
+ size_t len = j - i;
+ if (isIdentifier(a, start, len))
+ {
+ i = buf.bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1;
+ continue;
+ }
+ }
+
+ j = skippastident(buf, i);
+ if (i < j)
+ {
+ size_t len = j - i;
+ if (isIdentifier(a, start, len))
+ {
+ i = buf.bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1;
+ continue;
+ }
+ if (isFunctionParameter(a, start, len))
+ {
+ //printf("highlighting arg '%s', i = %d, j = %d\n", arg.ident.toChars(), i, j);
+ i = buf.bracket(i, "$(DDOC_PARAM ", j, ")") - 1;
+ continue;
+ }
+ i = j - 1;
+ }
+ }
+ else if (!resolvedTemplateParameters)
+ {
+ size_t previ = i;
+
+ // hunt for template declarations:
+ foreach (symi; 0 .. a.dim)
+ {
+ FuncDeclaration fd = (*a)[symi].isFuncDeclaration();
+
+ if (!fd || !fd.parent || !fd.parent.isTemplateDeclaration())
+ {
+ continue;
+ }
+
+ TemplateDeclaration td = fd.parent.isTemplateDeclaration();
+
+ // build the template parameters
+ Array!(size_t) paramLens;
+ paramLens.reserve(td.parameters.dim);
+
+ OutBuffer parametersBuf;
+ HdrGenState hgs;
+
+ parametersBuf.writeByte('(');
+
+ foreach (parami; 0 .. td.parameters.dim)
+ {
+ TemplateParameter tp = (*td.parameters)[parami];
+
+ if (parami)
+ parametersBuf.writestring(", ");
+
+ size_t lastOffset = parametersBuf.length;
+
+ .toCBuffer(tp, &parametersBuf, &hgs);
+
+ paramLens[parami] = parametersBuf.length - lastOffset;
+ }
+ parametersBuf.writeByte(')');
+
+ const templateParams = parametersBuf[];
+
+ //printf("templateDecl: %s\ntemplateParams: %s\nstart: %s\n", td.toChars(), templateParams, start);
+ if (start[0 .. templateParams.length] == templateParams)
+ {
+ immutable templateParamListMacro = "$(DDOC_TEMPLATE_PARAM_LIST ";
+ buf.bracket(i, templateParamListMacro.ptr, i + templateParams.length, ")");
+
+ // We have the parameter list. While we're here we might
+ // as well wrap the parameters themselves as well
+
+ // + 1 here to take into account the opening paren of the
+ // template param list
+ i += templateParamListMacro.length + 1;
+
+ foreach (const len; paramLens)
+ {
+ i = buf.bracket(i, "$(DDOC_TEMPLATE_PARAM ", i + len, ")");
+ // increment two here for space + comma
+ i += 2;
+ }
+
+ resolvedTemplateParameters = true;
+ // reset i to be positioned back before we found the template
+ // param list this assures that anything within the template
+ // param list that needs to be escaped or otherwise altered
+ // has an opportunity for that to happen outside of this context
+ i = previ;
+
+ continue;
+ }
+ }
+ }
+ }
+}
+
+/****************************************
+ */
+private void highlightCode3(Scope* sc, ref OutBuffer buf, const(char)* p, const(char)* pend)
+{
+ for (; p < pend; p++)
+ {
+ const se = sc._module.escapetable.escapeChar(*p);
+ if (se.length)
+ buf.writestring(se);
+ else
+ buf.writeByte(*p);
+ }
+}
+
+/**************************************************
+ * Highlight code for CODE section.
+ */
+private void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t offset)
+{
+ uint errorsave = global.startGagging();
+
+ scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1);
+ OutBuffer res;
+ const(char)* lastp = cast(char*)buf[].ptr;
+ //printf("highlightCode2('%.*s')\n", cast(int)(buf.length - 1), buf[].ptr);
+ res.reserve(buf.length);
+ while (1)
+ {
+ Token tok;
+ lex.scan(&tok);
+ highlightCode3(sc, res, lastp, tok.ptr);
+ string highlight = null;
+ switch (tok.value)
+ {
+ case TOK.identifier:
+ {
+ if (!sc)
+ break;
+ size_t len = lex.p - tok.ptr;
+ if (isIdentifier(a, tok.ptr, len))
+ {
+ highlight = "$(D_PSYMBOL ";
+ break;
+ }
+ if (isFunctionParameter(a, tok.ptr, len))
+ {
+ //printf("highlighting arg '%s', i = %d, j = %d\n", arg.ident.toChars(), i, j);
+ highlight = "$(D_PARAM ";
+ break;
+ }
+ break;
+ }
+ case TOK.comment:
+ highlight = "$(D_COMMENT ";
+ break;
+ case TOK.string_:
+ highlight = "$(D_STRING ";
+ break;
+ default:
+ if (tok.isKeyword())
+ highlight = "$(D_KEYWORD ";
+ break;
+ }
+ if (highlight)
+ {
+ res.writestring(highlight);
+ size_t o = res.length;
+ highlightCode3(sc, res, tok.ptr, lex.p);
+ if (tok.value == TOK.comment || tok.value == TOK.string_)
+ /* https://issues.dlang.org/show_bug.cgi?id=7656
+ * https://issues.dlang.org/show_bug.cgi?id=7715
+ * https://issues.dlang.org/show_bug.cgi?id=10519
+ */
+ escapeDdocString(&res, o);
+ res.writeByte(')');
+ }
+ else
+ highlightCode3(sc, res, tok.ptr, lex.p);
+ if (tok.value == TOK.endOfFile)
+ break;
+ lastp = lex.p;
+ }
+ buf.setsize(offset);
+ buf.write(&res);
+ global.endGagging(errorsave);
+}
+
+/****************************************
+ * Determine if p points to the start of a "..." parameter identifier.
+ */
+private bool isCVariadicArg(const(char)[] p)
+{
+ return p.length >= 3 && p[0 .. 3] == "...";
+}
+
+/****************************************
+ * Determine if p points to the start of an identifier.
+ */
+bool isIdStart(const(char)* p)
+{
+ dchar c = *p;
+ if (isalpha(c) || c == '_')
+ return true;
+ if (c >= 0x80)
+ {
+ size_t i = 0;
+ if (utf_decodeChar(p[0 .. 4], i, c))
+ return false; // ignore errors
+ if (isUniAlpha(c))
+ return true;
+ }
+ return false;
+}
+
+/****************************************
+ * Determine if p points to the rest of an identifier.
+ */
+bool isIdTail(const(char)* p)
+{
+ dchar c = *p;
+ if (isalnum(c) || c == '_')
+ return true;
+ if (c >= 0x80)
+ {
+ size_t i = 0;
+ if (utf_decodeChar(p[0 .. 4], i, c))
+ return false; // ignore errors
+ if (isUniAlpha(c))
+ return true;
+ }
+ return false;
+}
+
+/****************************************
+ * Determine if p points to the indentation space.
+ */
+private bool isIndentWS(const(char)* p)
+{
+ return (*p == ' ') || (*p == '\t');
+}
+
+/*****************************************
+ * Return number of bytes in UTF character.
+ */
+int utfStride(const(char)* p)
+{
+ dchar c = *p;
+ if (c < 0x80)
+ return 1;
+ size_t i = 0;
+ utf_decodeChar(p[0 .. 4], i, c); // ignore errors, but still consume input
+ return cast(int)i;
+}
+
+private inout(char)* stripLeadingNewlines(inout(char)* s)
+{
+ while (s && *s == '\n' || *s == '\r')
+ s++;
+
+ return s;
+}
diff --git a/gcc/d/dmd/doc.h b/gcc/d/dmd/doc.h
index 6d13ab1..a144417 100644
--- a/gcc/d/dmd/doc.h
+++ b/gcc/d/dmd/doc.h
@@ -5,15 +5,11 @@
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/doc.h
+ * https://github.com/dlang/dmd/blob/master/src/dmd/doc.h
*/
#pragma once
-#include "root/dsystem.h"
-
class Module;
-struct OutBuffer;
-void escapeDdocString(OutBuffer *buf, size_t start);
void gendocfile(Module *m);
diff --git a/gcc/d/dmd/dscope.c b/gcc/d/dmd/dscope.c
deleted file mode 100644
index e56f393..0000000
--- a/gcc/d/dmd/dscope.c
+++ /dev/null
@@ -1,646 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/scope.c
- */
-
-#include "root/dsystem.h" // strlen()
-#include "root/root.h"
-#include "root/rmem.h"
-#include "root/speller.h"
-
-#include "mars.h"
-#include "init.h"
-#include "identifier.h"
-#include "scope.h"
-#include "attrib.h"
-#include "dsymbol.h"
-#include "declaration.h"
-#include "statement.h"
-#include "aggregate.h"
-#include "module.h"
-#include "id.h"
-#include "target.h"
-#include "template.h"
-
-Scope *Scope::freelist = NULL;
-
-void allocFieldinit(Scope *sc, size_t dim)
-{
- sc->fieldinit = (unsigned *)mem.xcalloc(sizeof(unsigned), dim);
- sc->fieldinit_dim = dim;
-}
-
-void freeFieldinit(Scope *sc)
-{
- if (sc->fieldinit)
- mem.xfree(sc->fieldinit);
- sc->fieldinit = NULL;
- sc->fieldinit_dim = 0;
-}
-
-Scope *Scope::alloc()
-{
- if (freelist)
- {
- Scope *s = freelist;
- freelist = s->enclosing;
- //printf("freelist %p\n", s);
- assert(s->flags & SCOPEfree);
- s->flags &= ~SCOPEfree;
- return s;
- }
-
- return new Scope();
-}
-
-Scope::Scope()
-{
- // Create root scope
-
- //printf("Scope::Scope() %p\n", this);
- this->_module = NULL;
- this->scopesym = NULL;
- this->enclosing = NULL;
- this->parent = NULL;
- this->sw = NULL;
- this->tf = NULL;
- this->os = NULL;
- this->tinst = NULL;
- this->minst = NULL;
- this->sbreak = NULL;
- this->scontinue = NULL;
- this->fes = NULL;
- this->callsc = NULL;
- this->aligndecl = NULL;
- this->func = NULL;
- this->slabel = NULL;
- this->linkage = LINKd;
- this->cppmangle = CPPMANGLEdefault;
- this->inlining = PINLINEdefault;
- this->protection = Prot(Prot::public_);
- this->explicitProtection = 0;
- this->stc = 0;
- this->depdecl = NULL;
- this->inunion = 0;
- this->nofree = 0;
- this->noctor = 0;
- this->intypeof = 0;
- this->lastVar = NULL;
- this->callSuper = 0;
- this->fieldinit = NULL;
- this->fieldinit_dim = 0;
- this->flags = 0;
- this->lastdc = NULL;
- this->anchorCounts = NULL;
- this->prevAnchor = NULL;
- this->userAttribDecl = NULL;
-}
-
-Scope *Scope::copy()
-{
- Scope *sc = Scope::alloc();
- *sc = *this; // memcpy
-
- /* Bugzilla 11777: The copied scope should not inherit fieldinit.
- */
- sc->fieldinit = NULL;
-
- return sc;
-}
-
-Scope *Scope::createGlobal(Module *_module)
-{
- Scope *sc = Scope::alloc();
- *sc = Scope(); // memset
-
- sc->aligndecl = NULL;
- sc->linkage = LINKd;
- sc->inlining = PINLINEdefault;
- sc->protection = Prot(Prot::public_);
-
- sc->_module = _module;
-
- sc->tinst = NULL;
- sc->minst = _module;
-
- sc->scopesym = new ScopeDsymbol();
- sc->scopesym->symtab = new DsymbolTable();
-
- // Add top level package as member of this global scope
- Dsymbol *m = _module;
- while (m->parent)
- m = m->parent;
- m->addMember(NULL, sc->scopesym);
- m->parent = NULL; // got changed by addMember()
-
- // Create the module scope underneath the global scope
- sc = sc->push(_module);
- sc->parent = _module;
- return sc;
-}
-
-Scope *Scope::push()
-{
- Scope *s = copy();
-
- //printf("Scope::push(this = %p) new = %p\n", this, s);
- assert(!(flags & SCOPEfree));
- s->scopesym = NULL;
- s->enclosing = this;
- s->slabel = NULL;
- s->nofree = 0;
- s->fieldinit = saveFieldInit();
- s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint |
- SCOPEnoaccesscheck | SCOPEignoresymbolvisibility |
- SCOPEprintf | SCOPEscanf));
- s->lastdc = NULL;
-
- assert(this != s);
- return s;
-}
-
-Scope *Scope::push(ScopeDsymbol *ss)
-{
- //printf("Scope::push(%s)\n", ss->toChars());
- Scope *s = push();
- s->scopesym = ss;
- return s;
-}
-
-Scope *Scope::pop()
-{
- //printf("Scope::pop() %p nofree = %d\n", this, nofree);
- Scope *enc = enclosing;
-
- if (enclosing)
- {
- enclosing->callSuper |= callSuper;
- if (fieldinit)
- {
- if (enclosing->fieldinit)
- {
- assert(fieldinit != enclosing->fieldinit);
- size_t dim = fieldinit_dim;
- for (size_t i = 0; i < dim; i++)
- enclosing->fieldinit[i] |= fieldinit[i];
- }
- freeFieldinit(this);
- }
- }
-
- if (!nofree)
- {
- enclosing = freelist;
- freelist = this;
- flags |= SCOPEfree;
- }
-
- return enc;
-}
-
-Scope *Scope::startCTFE()
-{
- Scope *sc = this->push();
- sc->flags = this->flags | SCOPEctfe;
- return sc;
-}
-
-Scope *Scope::endCTFE()
-{
- assert(flags & SCOPEctfe);
- return pop();
-}
-
-void Scope::mergeCallSuper(Loc loc, unsigned cs)
-{
- // This does a primitive flow analysis to support the restrictions
- // regarding when and how constructors can appear.
- // It merges the results of two paths.
- // The two paths are callSuper and cs; the result is merged into callSuper.
-
- if (cs != callSuper)
- {
- // Have ALL branches called a constructor?
- int aAll = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0;
- int bAll = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0;
-
- // Have ANY branches called a constructor?
- bool aAny = (cs & CSXany_ctor) != 0;
- bool bAny = (callSuper & CSXany_ctor) != 0;
-
- // Have any branches returned?
- bool aRet = (cs & CSXreturn) != 0;
- bool bRet = (callSuper & CSXreturn) != 0;
-
- // Have any branches halted?
- bool aHalt = (cs & CSXhalt) != 0;
- bool bHalt = (callSuper & CSXhalt) != 0;
-
- bool ok = true;
-
- if (aHalt && bHalt)
- {
- callSuper = CSXhalt;
- }
- else if ((!aHalt && aRet && !aAny && bAny) ||
- (!bHalt && bRet && !bAny && aAny))
- {
- // If one has returned without a constructor call, there must be never
- // have been ctor calls in the other.
- ok = false;
- }
- else if (aHalt || (aRet && aAll))
- {
- // If one branch has called a ctor and then exited, anything the
- // other branch has done is OK (except returning without a
- // ctor call, but we already checked that).
- callSuper |= cs & (CSXany_ctor | CSXlabel);
- }
- else if (bHalt || (bRet && bAll))
- {
- callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel));
- }
- else
- {
- // Both branches must have called ctors, or both not.
- ok = (aAll == bAll);
- // If one returned without a ctor, we must remember that
- // (Don't bother if we've already found an error)
- if (ok && aRet && !aAny)
- callSuper |= CSXreturn;
- callSuper |= cs & (CSXany_ctor | CSXlabel);
- }
- if (!ok)
- error(loc, "one path skips constructor");
- }
-}
-
-unsigned *Scope::saveFieldInit()
-{
- unsigned *fi = NULL;
- if (fieldinit) // copy
- {
- size_t dim = fieldinit_dim;
- fi = (unsigned *)mem.xmalloc(sizeof(unsigned) * dim);
- for (size_t i = 0; i < dim; i++)
- fi[i] = fieldinit[i];
- }
- return fi;
-}
-
-/****************************************
- * Merge `b` flow analysis results into `a`.
- * Params:
- * a = the path to merge fi into
- * b = the other path
- * Returns:
- * false means either `a` or `b` skips initialization
- */
-static bool mergeFieldInit(unsigned &a, const unsigned b)
-{
- if (b == a)
- return true;
-
- // Have any branches returned?
- bool aRet = (a & CSXreturn) != 0;
- bool bRet = (b & CSXreturn) != 0;
-
- // Have any branches halted?
- bool aHalt = (a & CSXhalt) != 0;
- bool bHalt = (b & CSXhalt) != 0;
-
- if (aHalt && bHalt)
- {
- a = CSXhalt;
- return true;
- }
-
- // The logic here is to prefer the branch that neither halts nor returns.
- bool ok;
- if (!bHalt && bRet)
- {
- // Branch b returns, no merging required.
- ok = (b & CSXthis_ctor);
- }
- else if (!aHalt && aRet)
- {
- // Branch a returns, but b doesn't, b takes precedence.
- ok = (a & CSXthis_ctor);
- a = b;
- }
- else if (bHalt)
- {
- // Branch b halts, no merging required.
- ok = (a & CSXthis_ctor);
- }
- else if (aHalt)
- {
- // Branch a halts, but b doesn't, b takes precedence
- ok = (b & CSXthis_ctor);
- a = b;
- }
- else
- {
- // Neither branch returns nor halts, merge flags
- ok = !((a ^ b) & CSXthis_ctor);
- a |= b;
- }
- return ok;
-}
-
-void Scope::mergeFieldInit(Loc loc, unsigned *fies)
-{
- if (fieldinit && fies)
- {
- FuncDeclaration *f = func;
- if (fes) f = fes->func;
- AggregateDeclaration *ad = f->isMember2();
- assert(ad);
-
- for (size_t i = 0; i < ad->fields.length; i++)
- {
- VarDeclaration *v = ad->fields[i];
- bool mustInit = (v->storage_class & STCnodefaultctor ||
- v->type->needsNested());
-
- if (!::mergeFieldInit(fieldinit[i], fies[i]) && mustInit)
- {
- ::error(loc, "one path skips field %s", v->toChars());
- }
- }
- }
-}
-
-Module *Scope::instantiatingModule()
-{
- // TODO: in speculative context, returning 'module' is correct?
- return minst ? minst : _module;
-}
-
-static Dsymbol *searchScopes(Scope *scope, Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
-{
- for (Scope *sc = scope; sc; sc = sc->enclosing)
- {
- assert(sc != sc->enclosing);
- if (!sc->scopesym)
- continue;
- //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc->scopesym->toChars(), sc->scopesym->kind(), flags);
-
- if (sc->scopesym->isModule())
- flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
-
- if (Dsymbol *s = sc->scopesym->search(loc, ident, flags))
- {
- if (!(flags & (SearchImportsOnly | IgnoreErrors)) &&
- ident == Id::length && sc->scopesym->isArrayScopeSymbol() &&
- sc->enclosing && sc->enclosing->search(loc, ident, NULL, flags))
- {
- warning(s->loc, "array `length` hides other `length` name in outer scope");
- }
- if (pscopesym)
- *pscopesym = sc->scopesym;
- return s;
- }
- // Stop when we hit a module, but keep going if that is not just under the global scope
- if (sc->scopesym->isModule() && !(sc->enclosing && !sc->enclosing->enclosing))
- break;
- }
- return NULL;
-}
-
-/************************************
- * Perform unqualified name lookup by following the chain of scopes up
- * until found.
- *
- * Params:
- * loc = location to use for error messages
- * ident = name to look up
- * pscopesym = if supplied and name is found, set to scope that ident was found in
- * flags = modify search based on flags
- *
- * Returns:
- * symbol if found, null if not
- */
-Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags)
-{
- // This function is called only for unqualified lookup
- assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
-
- /* If ident is "start at module scope", only look at module scope
- */
- if (ident == Id::empty)
- {
- // Look for module scope
- for (Scope *sc = this; sc; sc = sc->enclosing)
- {
- assert(sc != sc->enclosing);
- if (!sc->scopesym)
- continue;
-
- if (Dsymbol *s = sc->scopesym->isModule())
- {
- if (pscopesym)
- *pscopesym = sc->scopesym;
- return s;
- }
- }
- return NULL;
- }
-
- if (this->flags & SCOPEignoresymbolvisibility)
- flags |= IgnoreSymbolVisibility;
-
- // First look in local scopes
- Dsymbol *s = searchScopes(this, loc, ident, pscopesym, flags | SearchLocalsOnly);
- if (!s)
- {
- // Second look in imported modules
- s = searchScopes(this, loc, ident, pscopesym, flags | SearchImportsOnly);
- }
- return s;
-}
-
-Dsymbol *Scope::insert(Dsymbol *s)
-{
- if (VarDeclaration *vd = s->isVarDeclaration())
- {
- if (lastVar)
- vd->lastVar = lastVar;
- lastVar = vd;
- }
- else if (WithScopeSymbol *ss = s->isWithScopeSymbol())
- {
- if (VarDeclaration *wthis = ss->withstate->wthis)
- {
- if (lastVar)
- wthis->lastVar = lastVar;
- lastVar = wthis;
- }
- return NULL;
- }
- for (Scope *sc = this; sc; sc = sc->enclosing)
- {
- //printf("\tsc = %p\n", sc);
- if (sc->scopesym)
- {
- //printf("\t\tsc->scopesym = %p\n", sc->scopesym);
- if (!sc->scopesym->symtab)
- sc->scopesym->symtab = new DsymbolTable();
- return sc->scopesym->symtabInsert(s);
- }
- }
- assert(0);
- return NULL;
-}
-
-/********************************************
- * Search enclosing scopes for ClassDeclaration.
- */
-
-ClassDeclaration *Scope::getClassScope()
-{
- for (Scope *sc = this; sc; sc = sc->enclosing)
- {
- if (!sc->scopesym)
- continue;
-
- ClassDeclaration *cd = sc->scopesym->isClassDeclaration();
- if (cd)
- return cd;
- }
- return NULL;
-}
-
-/********************************************
- * Search enclosing scopes for ClassDeclaration.
- */
-
-AggregateDeclaration *Scope::getStructClassScope()
-{
- for (Scope *sc = this; sc; sc = sc->enclosing)
- {
- if (!sc->scopesym)
- continue;
-
- AggregateDeclaration *ad = sc->scopesym->isClassDeclaration();
- if (ad)
- return ad;
- ad = sc->scopesym->isStructDeclaration();
- if (ad)
- return ad;
- }
- return NULL;
-}
-
-/*******************************************
- * For TemplateDeclarations, we need to remember the Scope
- * where it was declared. So mark the Scope as not
- * to be free'd.
- */
-
-void Scope::setNoFree()
-{
- //int i = 0;
-
- //printf("Scope::setNoFree(this = %p)\n", this);
- for (Scope *sc = this; sc; sc = sc->enclosing)
- {
- //printf("\tsc = %p\n", sc);
- sc->nofree = 1;
-
- assert(!(flags & SCOPEfree));
- //assert(sc != sc->enclosing);
- //assert(!sc->enclosing || sc != sc->enclosing->enclosing);
- //if (++i == 10)
- //assert(0);
- }
-}
-
-structalign_t Scope::alignment()
-{
- if (aligndecl)
- return aligndecl->getAlignment(this);
- else
- return STRUCTALIGN_DEFAULT;
-}
-
-/************************************************
- * Given the failed search attempt, try to find
- * one with a close spelling.
- */
-
-static void *scope_search_fp(void *arg, const char *seed, int* cost)
-{
- //printf("scope_search_fp('%s')\n", seed);
-
- /* If not in the lexer's string table, it certainly isn't in the symbol table.
- * Doing this first is a lot faster.
- */
- size_t len = strlen(seed);
- if (!len)
- return NULL;
- Identifier *id = Identifier::lookup(seed, len);
- if (!id)
- return NULL;
-
- Scope *sc = (Scope *)arg;
- Module::clearCache();
- Dsymbol *scopesym = NULL;
- Dsymbol *s = sc->search(Loc(), id, &scopesym, IgnoreErrors);
- if (s)
- {
- for (*cost = 0; sc; sc = sc->enclosing, (*cost)++)
- if (sc->scopesym == scopesym)
- break;
- if (scopesym != s->parent)
- {
- (*cost)++; // got to the symbol through an import
- if (s->prot().kind == Prot::private_)
- return NULL;
- }
- }
- return (void*)s;
-}
-
-Dsymbol *Scope::search_correct(Identifier *ident)
-{
- if (global.gag)
- return NULL; // don't do it for speculative compiles; too time consuming
-
- Dsymbol *scopesym = NULL;
- // search for exact name first
- if (Dsymbol *s = search(Loc(), ident, &scopesym, IgnoreErrors))
- return s;
- return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars);
-}
-
-/************************************
- * Maybe `ident` was a C or C++ name. Check for that,
- * and suggest the D equivalent.
- * Params:
- * ident = unknown identifier
- * Returns:
- * D identifier string if found, null if not
- */
-const char *Scope::search_correct_C(Identifier *ident)
-{
- TOK tok;
- if (ident == Id::C_NULL)
- tok = TOKnull;
- else if (ident == Id::C_TRUE)
- tok = TOKtrue;
- else if (ident == Id::C_FALSE)
- tok = TOKfalse;
- else if (ident == Id::C_unsigned)
- tok = TOKuns32;
- else if (ident == Id::C_wchar_t)
- tok = target.c.twchar_t->ty == Twchar ? TOKwchar : TOKdchar;
- else
- return NULL;
- return Token::toChars(tok);
-}
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
new file mode 100644
index 0000000..638fc7e
--- /dev/null
+++ b/gcc/d/dmd/dscope.d
@@ -0,0 +1,768 @@
+/**
+ * A scope as defined by curly braces `{}`.
+ *
+ * Not to be confused with the `scope` storage class.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dscope.d, _dscope.d)
+ * Documentation: https://dlang.org/phobos/dmd_dscope.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dscope.d
+ */
+
+module dmd.dscope;
+
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.ctorflow;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dmodule;
+import dmd.doc;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.expression;
+import dmd.errors;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+import dmd.root.speller;
+import dmd.statement;
+import dmd.target;
+import dmd.tokens;
+
+//version=LOGSEARCH;
+
+
+// List of flags that can be applied to this `Scope`
+enum SCOPE
+{
+ ctor = 0x0001, /// constructor type
+ noaccesscheck = 0x0002, /// don't do access checks
+ condition = 0x0004, /// inside static if/assert condition
+ debug_ = 0x0008, /// inside debug conditional
+ constraint = 0x0010, /// inside template constraint
+ invariant_ = 0x0020, /// inside invariant code
+ require = 0x0040, /// inside in contract code
+ ensure = 0x0060, /// inside out contract code
+ contract = 0x0060, /// [mask] we're inside contract code
+ ctfe = 0x0080, /// inside a ctfe-only expression
+ compile = 0x0100, /// inside __traits(compile)
+ ignoresymbolvisibility = 0x0200, /// ignore symbol visibility
+ /// https://issues.dlang.org/show_bug.cgi?id=15907
+ onlysafeaccess = 0x0400, /// unsafe access is not allowed for @safe code
+ Cfile = 0x0800, /// C semantics apply
+ free = 0x8000, /// is on free list
+
+ fullinst = 0x10000, /// fully instantiate templates
+ alias_ = 0x20000, /// inside alias declaration.
+
+ // The following are mutually exclusive
+ printf = 0x4_0000, /// printf-style function
+ scanf = 0x8_0000, /// scanf-style function
+}
+
+/// Flags that are carried along with a scope push()
+private enum PersistentFlags =
+ SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint |
+ SCOPE.noaccesscheck | SCOPE.onlysafeaccess | SCOPE.ignoresymbolvisibility |
+ SCOPE.printf | SCOPE.scanf | SCOPE.Cfile;
+
+struct Scope
+{
+ Scope* enclosing; /// enclosing Scope
+
+ Module _module; /// Root module
+ ScopeDsymbol scopesym; /// current symbol
+ FuncDeclaration func; /// function we are in
+ Dsymbol parent; /// parent to use
+ LabelStatement slabel; /// enclosing labelled statement
+ SwitchStatement sw; /// enclosing switch statement
+ Statement tryBody; /// enclosing _body of TryCatchStatement or TryFinallyStatement
+ TryFinallyStatement tf; /// enclosing try finally statement
+ ScopeGuardStatement os; /// enclosing scope(xxx) statement
+ Statement sbreak; /// enclosing statement that supports "break"
+ Statement scontinue; /// enclosing statement that supports "continue"
+ ForeachStatement fes; /// if nested function for ForeachStatement, this is it
+ Scope* callsc; /// used for __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__
+ Dsymbol inunion; /// != null if processing members of a union
+ bool nofree; /// true if shouldn't free it
+ bool inLoop; /// true if inside a loop (where constructor calls aren't allowed)
+ int intypeof; /// in typeof(exp)
+ VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init
+
+ /* If minst && !tinst, it's in definitely non-speculative scope (eg. module member scope).
+ * If !minst && !tinst, it's in definitely speculative scope (eg. template constraint).
+ * If minst && tinst, it's in instantiated code scope without speculation.
+ * If !minst && tinst, it's in instantiated code scope with speculation.
+ */
+ Module minst; /// root module where the instantiated templates should belong to
+ TemplateInstance tinst; /// enclosing template instance
+
+ CtorFlow ctorflow; /// flow analysis for constructors
+
+ /// alignment for struct members
+ AlignDeclaration aligndecl;
+
+ /// C++ namespace this symbol is in
+ CPPNamespaceDeclaration namespace;
+
+ /// linkage for external functions
+ LINK linkage = LINK.d;
+
+ /// mangle type
+ CPPMANGLE cppmangle = CPPMANGLE.def;
+
+ /// inlining strategy for functions
+ PragmaDeclaration inlining;
+
+ /// visibility for class members
+ Visibility visibility = Visibility(Visibility.Kind.public_);
+ int explicitVisibility; /// set if in an explicit visibility attribute
+
+ StorageClass stc; /// storage class
+
+ DeprecatedDeclaration depdecl; /// customized deprecation message
+
+ uint flags;
+
+ // user defined attributes
+ UserAttributeDeclaration userAttribDecl;
+
+ DocComment* lastdc; /// documentation comment for last symbol at this scope
+ uint[void*] anchorCounts; /// lookup duplicate anchor name count
+ Identifier prevAnchor; /// qualified symbol name of last doc anchor
+
+ AliasDeclaration aliasAsg; /// if set, then aliasAsg is being assigned a new value,
+ /// do not set wasRead for it
+
+ extern (D) __gshared Scope* freelist;
+
+ extern (D) static Scope* alloc()
+ {
+ if (freelist)
+ {
+ Scope* s = freelist;
+ freelist = s.enclosing;
+ //printf("freelist %p\n", s);
+ assert(s.flags & SCOPE.free);
+ s.flags &= ~SCOPE.free;
+ return s;
+ }
+ return new Scope();
+ }
+
+ extern (D) static Scope* createGlobal(Module _module)
+ {
+ Scope* sc = Scope.alloc();
+ *sc = Scope.init;
+ sc._module = _module;
+ sc.minst = _module;
+ sc.scopesym = new ScopeDsymbol();
+ sc.scopesym.symtab = new DsymbolTable();
+ // Add top level package as member of this global scope
+ Dsymbol m = _module;
+ while (m.parent)
+ m = m.parent;
+ m.addMember(null, sc.scopesym);
+ m.parent = null; // got changed by addMember()
+ if (_module.isCFile)
+ sc.flags |= SCOPE.Cfile;
+ // Create the module scope underneath the global scope
+ sc = sc.push(_module);
+ sc.parent = _module;
+ return sc;
+ }
+
+ extern (C++) Scope* copy()
+ {
+ Scope* sc = Scope.alloc();
+ *sc = this;
+ /* https://issues.dlang.org/show_bug.cgi?id=11777
+ * The copied scope should not inherit fieldinit.
+ */
+ sc.ctorflow.fieldinit = null;
+ return sc;
+ }
+
+ extern (C++) Scope* push()
+ {
+ Scope* s = copy();
+ //printf("Scope::push(this = %p) new = %p\n", this, s);
+ assert(!(flags & SCOPE.free));
+ s.scopesym = null;
+ s.enclosing = &this;
+ debug
+ {
+ if (enclosing)
+ assert(!(enclosing.flags & SCOPE.free));
+ if (s == enclosing)
+ {
+ printf("this = %p, enclosing = %p, enclosing.enclosing = %p\n", s, &this, enclosing);
+ }
+ assert(s != enclosing);
+ }
+ s.slabel = null;
+ s.nofree = false;
+ s.ctorflow.fieldinit = ctorflow.fieldinit.arraydup;
+ s.flags = (flags & PersistentFlags);
+ s.lastdc = null;
+ assert(&this != s);
+ return s;
+ }
+
+ extern (C++) Scope* push(ScopeDsymbol ss)
+ {
+ //printf("Scope::push(%s)\n", ss.toChars());
+ Scope* s = push();
+ s.scopesym = ss;
+ return s;
+ }
+
+ extern (C++) Scope* pop()
+ {
+ //printf("Scope::pop() %p nofree = %d\n", this, nofree);
+ if (enclosing)
+ enclosing.ctorflow.OR(ctorflow);
+ ctorflow.freeFieldinit();
+
+ Scope* enc = enclosing;
+ if (!nofree)
+ {
+ if (mem.isGCEnabled)
+ this = this.init;
+ enclosing = freelist;
+ freelist = &this;
+ flags |= SCOPE.free;
+ }
+ return enc;
+ }
+
+ /*************************
+ * Similar to pop(), but the results in `this` are not folded
+ * into `enclosing`.
+ */
+ extern (D) void detach()
+ {
+ ctorflow.freeFieldinit();
+ enclosing = null;
+ pop();
+ }
+
+ extern (C++) Scope* startCTFE()
+ {
+ Scope* sc = this.push();
+ sc.flags = this.flags | SCOPE.ctfe;
+ version (none)
+ {
+ /* TODO: Currently this is not possible, because we need to
+ * unspeculative some types and symbols if they are necessary for the
+ * final executable. Consider:
+ *
+ * struct S(T) {
+ * string toString() const { return "instantiated"; }
+ * }
+ * enum x = S!int();
+ * void main() {
+ * // To call x.toString in runtime, compiler should unspeculative S!int.
+ * assert(x.toString() == "instantiated");
+ * }
+ */
+ // If a template is instantiated from CT evaluated expression,
+ // compiler can elide its code generation.
+ sc.tinst = null;
+ sc.minst = null;
+ }
+ return sc;
+ }
+
+ extern (C++) Scope* endCTFE()
+ {
+ assert(flags & SCOPE.ctfe);
+ return pop();
+ }
+
+
+ /*******************************
+ * Merge results of `ctorflow` into `this`.
+ * Params:
+ * loc = for error messages
+ * ctorflow = flow results to merge in
+ */
+ extern (D) void merge(const ref Loc loc, const ref CtorFlow ctorflow)
+ {
+ if (!mergeCallSuper(this.ctorflow.callSuper, ctorflow.callSuper))
+ error(loc, "one path skips constructor");
+
+ const fies = ctorflow.fieldinit;
+ if (this.ctorflow.fieldinit.length && fies.length)
+ {
+ FuncDeclaration f = func;
+ if (fes)
+ f = fes.func;
+ auto ad = f.isMemberDecl();
+ assert(ad);
+ foreach (i, v; ad.fields)
+ {
+ bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested());
+ auto fieldInit = &this.ctorflow.fieldinit[i];
+ const fiesCurrent = fies[i];
+ if (fieldInit.loc is Loc.init)
+ fieldInit.loc = fiesCurrent.loc;
+ if (!mergeFieldInit(this.ctorflow.fieldinit[i].csx, fiesCurrent.csx) && mustInit)
+ {
+ error(loc, "one path skips field `%s`", v.toChars());
+ }
+ }
+ }
+ }
+
+ /************************************
+ * Perform unqualified name lookup by following the chain of scopes up
+ * until found.
+ *
+ * Params:
+ * loc = location to use for error messages
+ * ident = name to look up
+ * pscopesym = if supplied and name is found, set to scope that ident was found in
+ * flags = modify search based on flags
+ *
+ * Returns:
+ * symbol if found, null if not
+ */
+ extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone)
+ {
+ version (LOGSEARCH)
+ {
+ printf("Scope.search(%p, '%s' flags=x%x)\n", &this, ident.toChars(), flags);
+ // Print scope chain
+ for (Scope* sc = &this; sc; sc = sc.enclosing)
+ {
+ if (!sc.scopesym)
+ continue;
+ printf("\tscope %s\n", sc.scopesym.toChars());
+ }
+
+ static void printMsg(string txt, Dsymbol s)
+ {
+ printf("%.*s %s.%s, kind = '%s'\n", cast(int)txt.length, txt.ptr,
+ s.parent ? s.parent.toChars() : "", s.toChars(), s.kind());
+ }
+ }
+
+ // This function is called only for unqualified lookup
+ assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
+
+ /* If ident is "start at module scope", only look at module scope
+ */
+ if (ident == Id.empty)
+ {
+ // Look for module scope
+ for (Scope* sc = &this; sc; sc = sc.enclosing)
+ {
+ assert(sc != sc.enclosing);
+ if (!sc.scopesym)
+ continue;
+ if (Dsymbol s = sc.scopesym.isModule())
+ {
+ //printMsg("\tfound", s);
+ if (pscopesym)
+ *pscopesym = sc.scopesym;
+ return s;
+ }
+ }
+ return null;
+ }
+
+ Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, int flags, Expression* exp)
+ {
+ import dmd.mtype;
+ if (!ad || !ad.aliasthis)
+ return null;
+
+ Declaration decl = ad.aliasthis.sym.isDeclaration();
+ if (!decl)
+ return null;
+
+ Type t = decl.type;
+ ScopeDsymbol sds;
+ TypeClass tc;
+ TypeStruct ts;
+ switch(t.ty)
+ {
+ case Tstruct:
+ ts = cast(TypeStruct)t;
+ sds = ts.sym;
+ break;
+ case Tclass:
+ tc = cast(TypeClass)t;
+ sds = tc.sym;
+ break;
+ case Tinstance:
+ sds = (cast(TypeInstance)t).tempinst;
+ break;
+ case Tenum:
+ sds = (cast(TypeEnum)t).sym;
+ break;
+ default: break;
+ }
+
+ if (!sds)
+ return null;
+
+ Dsymbol ret = sds.search(loc, ident, flags);
+ if (ret)
+ {
+ *exp = new DotIdExp(loc, *exp, ad.aliasthis.ident);
+ *exp = new DotIdExp(loc, *exp, ident);
+ return ret;
+ }
+
+ if (!ts && !tc)
+ return null;
+
+ Dsymbol s;
+ *exp = new DotIdExp(loc, *exp, ad.aliasthis.ident);
+ if (ts && !(ts.att & AliasThisRec.tracing))
+ {
+ ts.att = cast(AliasThisRec)(ts.att | AliasThisRec.tracing);
+ s = checkAliasThis(sds.isAggregateDeclaration(), ident, flags, exp);
+ ts.att = cast(AliasThisRec)(ts.att & ~AliasThisRec.tracing);
+ }
+ else if(tc && !(tc.att & AliasThisRec.tracing))
+ {
+ tc.att = cast(AliasThisRec)(tc.att | AliasThisRec.tracing);
+ s = checkAliasThis(sds.isAggregateDeclaration(), ident, flags, exp);
+ tc.att = cast(AliasThisRec)(tc.att & ~AliasThisRec.tracing);
+ }
+ return s;
+ }
+
+ Dsymbol searchScopes(int flags)
+ {
+ for (Scope* sc = &this; sc; sc = sc.enclosing)
+ {
+ assert(sc != sc.enclosing);
+ if (!sc.scopesym)
+ continue;
+ //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags);
+
+ if (sc.scopesym.isModule())
+ flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
+
+ if (Dsymbol s = sc.scopesym.search(loc, ident, flags))
+ {
+ if (flags & TagNameSpace)
+ {
+ // ImportC: if symbol is not a tag, look for it in tag table
+ if (!s.isScopeDsymbol())
+ {
+ auto ps = cast(void*)s in sc._module.tagSymTab;
+ if (!ps)
+ goto NotFound;
+ s = *ps;
+ }
+ }
+ if (!(flags & (SearchImportsOnly | IgnoreErrors)) &&
+ ident == Id.length && sc.scopesym.isArrayScopeSymbol() &&
+ sc.enclosing && sc.enclosing.search(loc, ident, null, flags))
+ {
+ warning(s.loc, "array `length` hides other `length` name in outer scope");
+ }
+ //printMsg("\tfound local", s);
+ if (pscopesym)
+ *pscopesym = sc.scopesym;
+ return s;
+ }
+
+ NotFound:
+ if (global.params.fixAliasThis)
+ {
+ Expression exp = new ThisExp(loc);
+ Dsymbol aliasSym = checkAliasThis(sc.scopesym.isAggregateDeclaration(), ident, flags, &exp);
+ if (aliasSym)
+ {
+ //printf("found aliassym: %s\n", aliasSym.toChars());
+ if (pscopesym)
+ *pscopesym = new ExpressionDsymbol(exp);
+ return aliasSym;
+ }
+ }
+
+ // Stop when we hit a module, but keep going if that is not just under the global scope
+ if (sc.scopesym.isModule() && !(sc.enclosing && !sc.enclosing.enclosing))
+ break;
+ }
+ return null;
+ }
+
+ if (this.flags & SCOPE.ignoresymbolvisibility)
+ flags |= IgnoreSymbolVisibility;
+
+ // First look in local scopes
+ Dsymbol s = searchScopes(flags | SearchLocalsOnly);
+ version (LOGSEARCH) if (s) printMsg("-Scope.search() found local", s);
+ if (!s)
+ {
+ // Second look in imported modules
+ s = searchScopes(flags | SearchImportsOnly);
+ version (LOGSEARCH) if (s) printMsg("-Scope.search() found import", s);
+ }
+ return s;
+ }
+
+ extern (D) Dsymbol search_correct(Identifier ident)
+ {
+ if (global.gag)
+ return null; // don't do it for speculative compiles; too time consuming
+
+ /************************************************
+ * Given the failed search attempt, try to find
+ * one with a close spelling.
+ * Params:
+ * seed = identifier to search for
+ * cost = set to the cost, which rises with each outer scope
+ * Returns:
+ * Dsymbol if found, null if not
+ */
+ extern (D) Dsymbol scope_search_fp(const(char)[] seed, out int cost)
+ {
+ //printf("scope_search_fp('%s')\n", seed);
+ /* If not in the lexer's string table, it certainly isn't in the symbol table.
+ * Doing this first is a lot faster.
+ */
+ if (!seed.length)
+ return null;
+ Identifier id = Identifier.lookup(seed);
+ if (!id)
+ return null;
+ Scope* sc = &this;
+ Module.clearCache();
+ Dsymbol scopesym = null;
+ Dsymbol s = sc.search(Loc.initial, id, &scopesym, IgnoreErrors);
+ if (!s)
+ return null;
+
+ // Do not show `@disable`d declarations
+ if (auto decl = s.isDeclaration())
+ if (decl.storage_class & STC.disable)
+ return null;
+ // Or `deprecated` ones if we're not in a deprecated scope
+ if (s.isDeprecated() && !sc.isDeprecated())
+ return null;
+
+ for (cost = 0; sc; sc = sc.enclosing, ++cost)
+ if (sc.scopesym == scopesym)
+ break;
+ if (scopesym != s.parent)
+ {
+ ++cost; // got to the symbol through an import
+ if (s.visible().kind == Visibility.Kind.private_)
+ return null;
+ }
+ return s;
+ }
+
+ Dsymbol scopesym = null;
+ // search for exact name first
+ if (auto s = search(Loc.initial, ident, &scopesym, IgnoreErrors))
+ return s;
+ return speller!scope_search_fp(ident.toString());
+ }
+
+ /************************************
+ * Maybe `ident` was a C or C++ name. Check for that,
+ * and suggest the D equivalent.
+ * Params:
+ * ident = unknown identifier
+ * Returns:
+ * D identifier string if found, null if not
+ */
+ extern (D) static const(char)* search_correct_C(Identifier ident)
+ {
+ import dmd.astenums : Twchar;
+ TOK tok;
+ if (ident == Id.NULL)
+ tok = TOK.null_;
+ else if (ident == Id.TRUE)
+ tok = TOK.true_;
+ else if (ident == Id.FALSE)
+ tok = TOK.false_;
+ else if (ident == Id.unsigned)
+ tok = TOK.uns32;
+ else if (ident == Id.wchar_t)
+ tok = target.c.wchar_tsize == 2 ? TOK.wchar_ : TOK.dchar_;
+ else
+ return null;
+ return Token.toChars(tok);
+ }
+
+ /***************************
+ * Find the innermost scope with a symbol table.
+ * Returns:
+ * innermost scope, null if none
+ */
+ extern (D) Scope* inner() return
+ {
+ for (Scope* sc = &this; sc; sc = sc.enclosing)
+ {
+ if (sc.scopesym)
+ return sc;
+ }
+ return null;
+ }
+
+ /******************************
+ * Add symbol s to innermost symbol table.
+ * Params:
+ * s = symbol to insert
+ * Returns:
+ * null if already in table, `s` if not
+ */
+ extern (D) Dsymbol insert(Dsymbol s)
+ {
+ //printf("insert() %s\n", s.toChars());
+ if (VarDeclaration vd = s.isVarDeclaration())
+ {
+ if (lastVar)
+ vd.lastVar = lastVar;
+ lastVar = vd;
+ }
+ else if (WithScopeSymbol ss = s.isWithScopeSymbol())
+ {
+ if (VarDeclaration vd = ss.withstate.wthis)
+ {
+ if (lastVar)
+ vd.lastVar = lastVar;
+ lastVar = vd;
+ }
+ return null;
+ }
+
+ auto scopesym = inner().scopesym;
+ //printf("\t\tscopesym = %p\n", scopesym);
+ if (!scopesym.symtab)
+ scopesym.symtab = new DsymbolTable();
+ if (!(flags & SCOPE.Cfile))
+ return scopesym.symtabInsert(s);
+
+ // ImportC insert
+ if (!scopesym.symtabInsert(s)) // if already in table
+ {
+ Dsymbol s2 = scopesym.symtabLookup(s, s.ident); // s2 is existing entry
+ return handleTagSymbols(this, s, s2, scopesym);
+ }
+ return s; // inserted
+ }
+
+ /********************************************
+ * Search enclosing scopes for ScopeDsymbol.
+ */
+ ScopeDsymbol getScopesym()
+ {
+ for (Scope* sc = &this; sc; sc = sc.enclosing)
+ {
+ if (sc.scopesym)
+ return sc.scopesym;
+ }
+ return null; // not found
+ }
+
+ /********************************************
+ * Search enclosing scopes for ClassDeclaration.
+ */
+ extern (C++) ClassDeclaration getClassScope()
+ {
+ for (Scope* sc = &this; sc; sc = sc.enclosing)
+ {
+ if (!sc.scopesym)
+ continue;
+ if (ClassDeclaration cd = sc.scopesym.isClassDeclaration())
+ return cd;
+ }
+ return null;
+ }
+
+ /********************************************
+ * Search enclosing scopes for ClassDeclaration.
+ */
+ extern (C++) AggregateDeclaration getStructClassScope()
+ {
+ for (Scope* sc = &this; sc; sc = sc.enclosing)
+ {
+ if (!sc.scopesym)
+ continue;
+ if (AggregateDeclaration ad = sc.scopesym.isClassDeclaration())
+ return ad;
+ if (AggregateDeclaration ad = sc.scopesym.isStructDeclaration())
+ return ad;
+ }
+ return null;
+ }
+
+ /*******************************************
+ * For TemplateDeclarations, we need to remember the Scope
+ * where it was declared. So mark the Scope as not
+ * to be free'd.
+ */
+ extern (D) void setNoFree()
+ {
+ //int i = 0;
+ //printf("Scope::setNoFree(this = %p)\n", this);
+ for (Scope* sc = &this; sc; sc = sc.enclosing)
+ {
+ //printf("\tsc = %p\n", sc);
+ sc.nofree = true;
+ assert(!(flags & SCOPE.free));
+ //assert(sc != sc.enclosing);
+ //assert(!sc.enclosing || sc != sc.enclosing.enclosing);
+ //if (++i == 10)
+ // assert(0);
+ }
+ }
+
+ structalign_t alignment()
+ {
+ if (aligndecl)
+ return aligndecl.getAlignment(&this);
+ else
+ return STRUCTALIGN_DEFAULT;
+ }
+
+ /**********************************
+ * Checks whether the current scope (or any of its parents) is deprecated.
+ *
+ * Returns: `true` if this or any parent scope is deprecated, `false` otherwise`
+ */
+ extern(C++) bool isDeprecated() @safe @nogc pure nothrow const
+ {
+ for (const(Dsymbol)* sp = &(this.parent); *sp; sp = &(sp.parent))
+ {
+ if (sp.isDeprecated())
+ return true;
+ }
+ for (const(Scope)* sc2 = &this; sc2; sc2 = sc2.enclosing)
+ {
+ if (sc2.scopesym && sc2.scopesym.isDeprecated())
+ return true;
+
+ // If inside a StorageClassDeclaration that is deprecated
+ if (sc2.stc & STC.deprecated_)
+ return true;
+ }
+ if (_module.md && _module.md.isdeprecated)
+ {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/gcc/d/dmd/dstruct.c b/gcc/d/dmd/dstruct.c
deleted file mode 100644
index 9862159..0000000
--- a/gcc/d/dmd/dstruct.c
+++ /dev/null
@@ -1,1303 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/struct.c
- */
-
-#include "root/dsystem.h"
-#include "root/root.h"
-
-#include "errors.h"
-#include "aggregate.h"
-#include "scope.h"
-#include "mtype.h"
-#include "init.h"
-#include "declaration.h"
-#include "module.h"
-#include "id.h"
-#include "statement.h"
-#include "template.h"
-#include "tokens.h"
-#include "target.h"
-#include "utf.h"
-#include "root/ctfloat.h"
-
-Type *getTypeInfoType(Loc loc, Type *t, Scope *sc);
-void unSpeculative(Scope *sc, RootObject *o);
-bool MODimplicitConv(MOD modfrom, MOD modto);
-Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-
-FuncDeclaration *StructDeclaration::xerreq; // object.xopEquals
-FuncDeclaration *StructDeclaration::xerrcmp; // object.xopCmp
-
-/***************************************
- * Search toString member function for TypeInfo_Struct.
- * string toString();
- */
-FuncDeclaration *search_toString(StructDeclaration *sd)
-{
- Dsymbol *s = search_function(sd, Id::tostring);
- FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
- if (fd)
- {
- static TypeFunction *tftostring;
- if (!tftostring)
- {
- tftostring = new TypeFunction(ParameterList(), Type::tstring, LINKd);
- tftostring = tftostring->merge()->toTypeFunction();
- }
-
- fd = fd->overloadExactMatch(tftostring);
- }
- return fd;
-}
-
-/***************************************
- * Request additonal semantic analysis for TypeInfo generation.
- */
-void semanticTypeInfo(Scope *sc, Type *t)
-{
- class FullTypeInfoVisitor : public Visitor
- {
- public:
- Scope *sc;
-
- void visit(Type *t)
- {
- Type *tb = t->toBasetype();
- if (tb != t)
- tb->accept(this);
- }
- void visit(TypeNext *t)
- {
- if (t->next)
- t->next->accept(this);
- }
- void visit(TypeBasic *) { }
- void visit(TypeVector *t)
- {
- t->basetype->accept(this);
- }
- void visit(TypeAArray *t)
- {
- t->index->accept(this);
- visit((TypeNext *)t);
- }
- void visit(TypeFunction *t)
- {
- visit((TypeNext *)t);
- // Currently TypeInfo_Function doesn't store parameter types.
- }
- void visit(TypeStruct *t)
- {
- //printf("semanticTypeInfo::visit(TypeStruct = %s)\n", t->toChars());
- StructDeclaration *sd = t->sym;
-
- /* Step 1: create TypeInfoDeclaration
- */
- if (!sc) // inline may request TypeInfo.
- {
- Scope scx;
- scx._module = sd->getModule();
- getTypeInfoType(sd->loc, t, &scx);
- sd->requestTypeInfo = true;
- }
- else if (!sc->minst)
- {
- // don't yet have to generate TypeInfo instance if
- // the typeid(T) expression exists in speculative scope.
- }
- else
- {
- getTypeInfoType(sd->loc, t, sc);
- sd->requestTypeInfo = true;
-
- // Bugzilla 15149, if the typeid operand type comes from a
- // result of auto function, it may be yet speculative.
- // unSpeculative(sc, sd);
- }
-
- /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
- * This should be done even if typeid(T) exists in speculative scope.
- * Because it may appear later in non-speculative scope.
- */
- if (!sd->members)
- return; // opaque struct
- if (!sd->xeq && !sd->xcmp && !sd->postblit &&
- !sd->dtor && !sd->xhash && !search_toString(sd))
- return; // none of TypeInfo-specific members
-
- // If the struct is in a non-root module, run semantic3 to get
- // correct symbols for the member function.
- if (sd->semanticRun >= PASSsemantic3)
- {
- // semantic3 is already done
- }
- else if (TemplateInstance *ti = sd->isInstantiated())
- {
- if (ti->minst && !ti->minst->isRoot())
- Module::addDeferredSemantic3(sd);
- }
- else
- {
- if (sd->inNonRoot())
- {
- //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd->toChars(), sd->inNonRoot());
- Module::addDeferredSemantic3(sd);
- }
- }
- }
- void visit(TypeClass *) { }
- void visit(TypeTuple *t)
- {
- if (t->arguments)
- {
- for (size_t i = 0; i < t->arguments->length; i++)
- {
- Type *tprm = (*t->arguments)[i]->type;
- if (tprm)
- tprm->accept(this);
- }
- }
- }
- };
-
- if (sc)
- {
- if (!sc->func)
- return;
- if (sc->intypeof)
- return;
- if (sc->flags & (SCOPEctfe | SCOPEcompile))
- return;
- }
-
- FullTypeInfoVisitor v;
- v.sc = sc;
- t->accept(&v);
-}
-
-/********************************* AggregateDeclaration ****************************/
-
-AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id)
- : ScopeDsymbol(id)
-{
- this->loc = loc;
-
- storage_class = 0;
- protection = Prot(Prot::public_);
- type = NULL;
- structsize = 0; // size of struct
- alignsize = 0; // size of struct for alignment purposes
- sizeok = SIZEOKnone; // size not determined yet
- deferred = NULL;
- isdeprecated = false;
- classKind = ClassKind::d;
- inv = NULL;
- aggNew = NULL;
- aggDelete = NULL;
-
- stag = NULL;
- sinit = NULL;
- enclosing = NULL;
- vthis = NULL;
-
- ctor = NULL;
- defaultCtor = NULL;
- aliasthis = NULL;
- noDefaultCtor = false;
- dtor = NULL;
- getRTInfo = NULL;
-}
-
-Prot AggregateDeclaration::prot()
-{
- return protection;
-}
-
-/***************************************
- * Create a new scope from sc.
- * semantic, semantic2 and semantic3 will use this for aggregate members.
- */
-Scope *AggregateDeclaration::newScope(Scope *sc)
-{
- Scope *sc2 = sc->push(this);
- sc2->stc &= STCsafe | STCtrusted | STCsystem;
- sc2->parent = this;
- if (isUnionDeclaration())
- sc2->inunion = 1;
- sc2->protection = Prot(Prot::public_);
- sc2->explicitProtection = 0;
- sc2->aligndecl = NULL;
- sc2->userAttribDecl = NULL;
- return sc2;
-}
-
-void AggregateDeclaration::setScope(Scope *sc)
-{
- // Might need a scope to resolve forward references. The check for
- // semanticRun prevents unnecessary setting of _scope during deferred
- // setScope phases for aggregates which already finished semantic().
- // Also see https://issues.dlang.org/show_bug.cgi?id=16607
- if (semanticRun < PASSsemanticdone)
- ScopeDsymbol::setScope(sc);
-}
-
-/***************************************
- * Find all instance fields, then push them into `fields`.
- *
- * Runs semantic() for all instance field variables, but also
- * the field types can reamin yet not resolved forward references,
- * except direct recursive definitions.
- * After the process sizeok is set to SIZEOKfwd.
- *
- * Returns:
- * false if any errors occur.
- */
-bool AggregateDeclaration::determineFields()
-{
- if (_scope)
- dsymbolSemantic(this, NULL);
- if (sizeok != SIZEOKnone)
- return true;
-
- //printf("determineFields() %s, fields.length = %d\n", toChars(), fields.length);
- fields.setDim(0);
-
- struct SV
- {
- AggregateDeclaration *agg;
-
- static int func(Dsymbol *s, void *param)
- {
- VarDeclaration *v = s->isVarDeclaration();
- if (!v)
- return 0;
- if (v->storage_class & STCmanifest)
- return 0;
-
- AggregateDeclaration *ad = ((SV *)param)->agg;
-
- if (v->semanticRun < PASSsemanticdone)
- dsymbolSemantic(v, NULL);
- // Note: Aggregate fields or size could have determined during v->semantic.
- if (ad->sizeok != SIZEOKnone)
- return 1;
-
- if (v->aliassym)
- return 0; // If this variable was really a tuple, skip it.
-
- if (v->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCctfe | STCtemplateparameter))
- return 0;
- if (!v->isField() || v->semanticRun < PASSsemanticdone)
- return 1; // unresolvable forward reference
-
- ad->fields.push(v);
-
- if (v->storage_class & STCref)
- return 0;
- Type *tv = v->type->baseElemOf();
- if (tv->ty != Tstruct)
- return 0;
- if (ad == ((TypeStruct *)tv)->sym)
- {
- const char *psz = (v->type->toBasetype()->ty == Tsarray) ? "static array of " : "";
- ad->error("cannot have field %s with %ssame struct type", v->toChars(), psz);
- ad->type = Type::terror;
- ad->errors = true;
- return 1;
- }
- return 0;
- }
- };
- SV sv;
- sv.agg = this;
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- if (s->apply(&SV::func, &sv))
- {
- if (sizeok != SIZEOKnone)
- return true;
- return false;
- }
- }
-
- if (sizeok != SIZEOKdone)
- sizeok = SIZEOKfwd;
-
- return true;
-}
-
-/***************************************
- * Collect all instance fields, then determine instance size.
- * Returns:
- * false if failed to determine the size.
- */
-bool AggregateDeclaration::determineSize(Loc loc)
-{
- //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
-
- // The previous instance size finalizing had:
- if (type->ty == Terror)
- return false; // failed already
- if (sizeok == SIZEOKdone)
- return true; // succeeded
-
- if (!members)
- {
- error(loc, "unknown size");
- return false;
- }
-
- if (_scope)
- dsymbolSemantic(this, NULL);
-
- // Determine the instance size of base class first.
- if (ClassDeclaration *cd = isClassDeclaration())
- {
- cd = cd->baseClass;
- if (cd && !cd->determineSize(loc))
- goto Lfail;
- }
-
- // Determine instance fields when sizeok == SIZEOKnone
- if (!determineFields())
- goto Lfail;
- if (sizeok != SIZEOKdone)
- finalizeSize();
-
- // this aggregate type has:
- if (type->ty == Terror)
- return false; // marked as invalid during the finalizing.
- if (sizeok == SIZEOKdone)
- return true; // succeeded to calculate instance size.
-
-Lfail:
- // There's unresolvable forward reference.
- if (type != Type::terror)
- error(loc, "no size because of forward reference");
- // Don't cache errors from speculative semantic, might be resolvable later.
- // https://issues.dlang.org/show_bug.cgi?id=16574
- if (!global.gag)
- {
- type = Type::terror;
- errors = true;
- }
- return false;
-}
-
-void StructDeclaration::semanticTypeInfoMembers()
-{
- if (xeq &&
- xeq->_scope &&
- xeq->semanticRun < PASSsemantic3done)
- {
- unsigned errors = global.startGagging();
- semantic3(xeq, xeq->_scope);
- if (global.endGagging(errors))
- xeq = xerreq;
- }
-
- if (xcmp &&
- xcmp->_scope &&
- xcmp->semanticRun < PASSsemantic3done)
- {
- unsigned errors = global.startGagging();
- semantic3(xcmp, xcmp->_scope);
- if (global.endGagging(errors))
- xcmp = xerrcmp;
- }
-
- FuncDeclaration *ftostr = search_toString(this);
- if (ftostr &&
- ftostr->_scope &&
- ftostr->semanticRun < PASSsemantic3done)
- {
- semantic3(ftostr, ftostr->_scope);
- }
-
- if (xhash &&
- xhash->_scope &&
- xhash->semanticRun < PASSsemantic3done)
- {
- semantic3(xhash, xhash->_scope);
- }
-
- if (postblit &&
- postblit->_scope &&
- postblit->semanticRun < PASSsemantic3done)
- {
- semantic3(postblit, postblit->_scope);
- }
-
- if (dtor &&
- dtor->_scope &&
- dtor->semanticRun < PASSsemantic3done)
- {
- semantic3(dtor, dtor->_scope);
- }
-}
-
-d_uns64 AggregateDeclaration::size(Loc loc)
-{
- //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
- bool ok = determineSize(loc);
- //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
- return ok ? structsize : SIZE_INVALID;
-}
-
-Type *AggregateDeclaration::getType()
-{
- return type;
-}
-
-bool AggregateDeclaration::isDeprecated()
-{
- return isdeprecated;
-}
-
-bool AggregateDeclaration::isExport() const
-{
- return protection.kind == Prot::export_;
-}
-
-/***************************************
- * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
- * field initializers have unique memory space on instance.
- * Returns:
- * true if any errors happen.
- */
-
-bool AggregateDeclaration::checkOverlappedFields()
-{
- //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
- assert(sizeok == SIZEOKdone);
- size_t nfields = fields.length;
- if (isNested())
- {
- ClassDeclaration *cd = isClassDeclaration();
- if (!cd || !cd->baseClass || !cd->baseClass->isNested())
- nfields--;
- }
- bool errors = false;
-
- // Fill in missing any elements with default initializers
- for (size_t i = 0; i < nfields; i++)
- {
- VarDeclaration *vd = fields[i];
- if (vd->errors)
- {
- errors = true;
- continue;
- }
-
- VarDeclaration *vx = vd;
- if (vd->_init && vd->_init->isVoidInitializer())
- vx = NULL;
-
- // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
- for (size_t j = 0; j < nfields; j++)
- {
- if (i == j)
- continue;
- VarDeclaration *v2 = fields[j];
- if (v2->errors)
- {
- errors = true;
- continue;
- }
- if (!vd->isOverlappedWith(v2))
- continue;
-
- // vd and v2 are overlapping.
- vd->overlapped = true;
- v2->overlapped = true;
-
- if (!MODimplicitConv(vd->type->mod, v2->type->mod))
- v2->overlapUnsafe = true;
- if (!MODimplicitConv(v2->type->mod, vd->type->mod))
- vd->overlapUnsafe = true;
-
- if (!vx)
- continue;
- if (v2->_init && v2->_init->isVoidInitializer())
- continue;
-
- if (vx->_init && v2->_init)
- {
- ::error(loc, "overlapping default initialization for field %s and %s", v2->toChars(), vd->toChars());
- errors = true;
- }
- }
- }
- return errors;
-}
-
-/***************************************
- * Fill out remainder of elements[] with default initializers for fields[].
- * Input:
- * loc: location
- * elements: explicit arguments which given to construct object.
- * ctorinit: true if the elements will be used for default initialization.
- * Returns:
- * false if any errors occur.
- * Otherwise, returns true and the missing arguments will be pushed in elements[].
- */
-bool AggregateDeclaration::fill(Loc loc, Expressions *elements, bool ctorinit)
-{
- //printf("AggregateDeclaration::fill() %s\n", toChars());
- assert(sizeok == SIZEOKdone);
- assert(elements);
- size_t nfields = fields.length - isNested();
- bool errors = false;
-
- size_t dim = elements->length;
- elements->setDim(nfields);
- for (size_t i = dim; i < nfields; i++)
- (*elements)[i] = NULL;
-
- // Fill in missing any elements with default initializers
- for (size_t i = 0; i < nfields; i++)
- {
- if ((*elements)[i])
- continue;
-
- VarDeclaration *vd = fields[i];
- VarDeclaration *vx = vd;
- if (vd->_init && vd->_init->isVoidInitializer())
- vx = NULL;
-
- // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
- size_t fieldi = i;
- for (size_t j = 0; j < nfields; j++)
- {
- if (i == j)
- continue;
- VarDeclaration *v2 = fields[j];
- if (!vd->isOverlappedWith(v2))
- continue;
-
- if ((*elements)[j])
- {
- vx = NULL;
- break;
- }
- if (v2->_init && v2->_init->isVoidInitializer())
- continue;
-
- if (1)
- {
- /* Prefer first found non-void-initialized field
- * union U { int a; int b = 2; }
- * U u; // Error: overlapping initialization for field a and b
- */
- if (!vx)
- {
- vx = v2;
- fieldi = j;
- }
- else if (v2->_init)
- {
- ::error(loc, "overlapping initialization for field %s and %s",
- v2->toChars(), vd->toChars());
- errors = true;
- }
- }
- else
- {
- // Will fix Bugzilla 1432 by enabling this path always
-
- /* Prefer explicitly initialized field
- * union U { int a; int b = 2; }
- * U u; // OK (u.b == 2)
- */
- if (!vx || (!vx->_init && v2->_init))
- {
- vx = v2;
- fieldi = j;
- }
- else if (vx != vd && !vx->isOverlappedWith(v2))
- {
- // Both vx and v2 fills vd, but vx and v2 does not overlap
- }
- else if (vx->_init && v2->_init)
- {
- ::error(loc, "overlapping default initialization for field %s and %s",
- v2->toChars(), vd->toChars());
- errors = true;
- }
- else
- assert(vx->_init || (!vx->_init && !v2->_init));
- }
- }
- if (vx)
- {
- Expression *e;
- if (vx->type->size() == 0)
- {
- e = NULL;
- }
- else if (vx->_init)
- {
- assert(!vx->_init->isVoidInitializer());
- if (vx->inuse) // https://issues.dlang.org/show_bug.cgi?id=18057
- {
- vx->error(loc, "recursive initialization of field");
- errors = true;
- e = NULL;
- }
- else
- e = vx->getConstInitializer(false);
- }
- else
- {
- if ((vx->storage_class & STCnodefaultctor) && !ctorinit)
- {
- ::error(loc, "field %s.%s must be initialized because it has no default constructor",
- type->toChars(), vx->toChars());
- errors = true;
- }
-
- /* Bugzilla 12509: Get the element of static array type.
- */
- Type *telem = vx->type;
- if (telem->ty == Tsarray)
- {
- /* We cannot use Type::baseElemOf() here.
- * If the bottom of the Tsarray is an enum type, baseElemOf()
- * will return the base of the enum, and its default initializer
- * would be different from the enum's.
- */
- while (telem->toBasetype()->ty == Tsarray)
- telem = ((TypeSArray *)telem->toBasetype())->next;
-
- if (telem->ty == Tvoid)
- telem = Type::tuns8->addMod(telem->mod);
- }
- if (telem->needsNested() && ctorinit)
- e = telem->defaultInit(loc);
- else
- e = telem->defaultInitLiteral(loc);
- }
- (*elements)[fieldi] = e;
- }
- }
-
- for (size_t i = 0; i < elements->length; i++)
- {
- Expression *e = (*elements)[i];
- if (e && e->op == TOKerror)
- return false;
- }
-
- return !errors;
-}
-
-/****************************
- * Do byte or word alignment as necessary.
- * Align sizes of 0, as we may not know array sizes yet.
- *
- * alignment: struct alignment that is in effect
- * size: alignment requirement of field
- */
-
-void AggregateDeclaration::alignmember(
- structalign_t alignment,
- unsigned size,
- unsigned *poffset)
-{
- //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset);
- switch (alignment)
- {
- case (structalign_t) 1:
- // No alignment
- break;
-
- case (structalign_t) STRUCTALIGN_DEFAULT:
- // Alignment in target.fieldalignsize must match what the
- // corresponding C compiler's default alignment behavior is.
- assert(size > 0 && !(size & (size - 1)));
- *poffset = (*poffset + size - 1) & ~(size - 1);
- break;
-
- default:
- // Align on alignment boundary, which must be a positive power of 2
- assert(alignment > 0 && !(alignment & (alignment - 1)));
- *poffset = (*poffset + alignment - 1) & ~(alignment - 1);
- break;
- }
-}
-
-/****************************************
- * Place a member (mem) into an aggregate (agg), which can be a struct, union or class
- * Returns:
- * offset to place field at
- *
- * nextoffset: next location in aggregate
- * memsize: size of member
- * memalignsize: natural alignment of member
- * alignment: alignment in effect for this member
- * paggsize: size of aggregate (updated)
- * paggalignsize: alignment of aggregate (updated)
- * isunion: the aggregate is a union
- */
-unsigned AggregateDeclaration::placeField(
- unsigned *nextoffset,
- unsigned memsize,
- unsigned memalignsize,
- structalign_t alignment,
- unsigned *paggsize,
- unsigned *paggalignsize,
- bool isunion
- )
-{
- unsigned ofs = *nextoffset;
-
- const unsigned actualAlignment =
- alignment == STRUCTALIGN_DEFAULT ? memalignsize : alignment;
-
- alignmember(alignment, memalignsize, &ofs);
- unsigned memoffset = ofs;
- ofs += memsize;
- if (ofs > *paggsize)
- *paggsize = ofs;
- if (!isunion)
- *nextoffset = ofs;
-
- if (*paggalignsize < actualAlignment)
- *paggalignsize = actualAlignment;
-
- return memoffset;
-}
-
-
-/****************************************
- * Returns true if there's an extra member which is the 'this'
- * pointer to the enclosing context (enclosing aggregate or function)
- */
-
-bool AggregateDeclaration::isNested()
-{
- return enclosing != NULL;
-}
-
-/* Append vthis field (this->tupleof[$-1]) to make this aggregate type nested.
- */
-void AggregateDeclaration::makeNested()
-{
- if (enclosing) // if already nested
- return;
- if (sizeok == SIZEOKdone)
- return;
- if (isUnionDeclaration() || isInterfaceDeclaration())
- return;
- if (storage_class & STCstatic)
- return;
-
- // If nested struct, add in hidden 'this' pointer to outer scope
- Dsymbol *s = toParent2();
- if (!s)
- return;
- Type *t = NULL;
- if (FuncDeclaration *fd = s->isFuncDeclaration())
- {
- enclosing = fd;
-
- /* Bugzilla 14422: If a nested class parent is a function, its
- * context pointer (== `outer`) should be void* always.
- */
- t = Type::tvoidptr;
- }
- else if (AggregateDeclaration *ad = s->isAggregateDeclaration())
- {
- if (isClassDeclaration() && ad->isClassDeclaration())
- {
- enclosing = ad;
- }
- else if (isStructDeclaration())
- {
- if (TemplateInstance *ti = ad->parent->isTemplateInstance())
- {
- enclosing = ti->enclosing;
- }
- }
-
- t = ad->handleType();
- }
- if (enclosing)
- {
- //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing->toChars());
- assert(t);
- if (t->ty == Tstruct)
- t = Type::tvoidptr; // t should not be a ref type
- assert(!vthis);
- vthis = new ThisDeclaration(loc, t);
- //vthis->storage_class |= STCref;
-
- // Emulate vthis->addMember()
- members->push(vthis);
-
- // Emulate vthis->semantic()
- vthis->storage_class |= STCfield;
- vthis->parent = this;
- vthis->protection = Prot(Prot::public_);
- vthis->alignment = t->alignment();
- vthis->semanticRun = PASSsemanticdone;
-
- if (sizeok == SIZEOKfwd)
- fields.push(vthis);
- }
-}
-
-/*******************************************
- * Look for constructor declaration.
- */
-Dsymbol *AggregateDeclaration::searchCtor()
-{
- Dsymbol *s = search(Loc(), Id::ctor);
- if (s)
- {
- if (!(s->isCtorDeclaration() ||
- s->isTemplateDeclaration() ||
- s->isOverloadSet()))
- {
- s->error("is not a constructor; identifiers starting with __ are reserved for the implementation");
- errors = true;
- s = NULL;
- }
- }
- if (s && s->toParent() != this)
- s = NULL; // search() looks through ancestor classes
- if (s)
- {
- // Finish all constructors semantics to determine this->noDefaultCtor.
- struct SearchCtor
- {
- static int fp(Dsymbol *s, void *)
- {
- CtorDeclaration *f = s->isCtorDeclaration();
- if (f && f->semanticRun == PASSinit)
- dsymbolSemantic(f, NULL);
- return 0;
- }
- };
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *sm = (*members)[i];
- sm->apply(&SearchCtor::fp, NULL);
- }
- }
- return s;
-}
-
-/********************************* StructDeclaration ****************************/
-
-StructDeclaration::StructDeclaration(Loc loc, Identifier *id, bool inObject)
- : AggregateDeclaration(loc, id)
-{
- zeroInit = 0; // assume false until we do semantic processing
- hasIdentityAssign = false;
- hasIdentityEquals = false;
- postblit = NULL;
-
- xeq = NULL;
- xcmp = NULL;
- xhash = NULL;
- alignment = 0;
- ispod = ISPODfwd;
- arg1type = NULL;
- arg2type = NULL;
- requestTypeInfo = false;
-
- // For forward references
- type = new TypeStruct(this);
-
- if (inObject)
- {
- if (id == Id::ModuleInfo && !Module::moduleinfo)
- Module::moduleinfo = this;
- }
-}
-
-StructDeclaration *StructDeclaration::create(Loc loc, Identifier *id, bool inObject)
-{
- return new StructDeclaration(loc, id, inObject);
-}
-
-Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s)
-{
- StructDeclaration *sd =
- s ? (StructDeclaration *)s
- : new StructDeclaration(loc, ident, false);
- return ScopeDsymbol::syntaxCopy(sd);
-}
-
-Dsymbol *StructDeclaration::search(const Loc &loc, Identifier *ident, int flags)
-{
- //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
-
- if (_scope && !symtab)
- dsymbolSemantic(this, _scope);
-
- if (!members || !symtab) // opaque or semantic() is not yet called
- {
- error("is forward referenced when looking for `%s`", ident->toChars());
- return NULL;
- }
-
- return ScopeDsymbol::search(loc, ident, flags);
-}
-
-/**********************************
- * Determine if exp is all binary zeros.
- * Params:
- * exp = expression to check
- * Returns:
- * true if it's all binary 0
- */
-static bool isZeroInit(Expression *exp)
-{
- switch (exp->op)
- {
- case TOKint64:
- return exp->toInteger() == 0;
-
- case TOKnull:
- case TOKfalse:
- return true;
-
- case TOKstructliteral:
- {
- StructLiteralExp *sle = (StructLiteralExp *) exp;
- for (size_t i = 0; i < sle->sd->fields.length; i++)
- {
- VarDeclaration *field = sle->sd->fields[i];
- if (field->type->size(field->loc))
- {
- Expression *e = (*sle->elements)[i];
- if (e ? !isZeroInit(e)
- : !field->type->isZeroInit(field->loc))
- return false;
- }
- }
- return true;
- }
-
- case TOKarrayliteral:
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *) exp;
-
- const size_t dim = ale->elements ? ale->elements->length : 0;
-
- if (ale->type->toBasetype()->ty == Tarray) // if initializing a dynamic array
- return dim == 0;
-
- for (size_t i = 0; i < dim; i++)
- {
- if (!isZeroInit(ale->getElement(i)))
- return false;
- }
- /* Note that true is returned for all T[0]
- */
- return true;
- }
-
- case TOKstring:
- {
- StringExp *se = exp->toStringExp();
-
- if (se->type->toBasetype()->ty == Tarray) // if initializing a dynamic array
- return se->len == 0;
-
- void *s = se->string;
- for (size_t i = 0; i < se->len; i++)
- {
- dinteger_t val;
- switch (se->sz)
- {
- case 1: val = (( utf8_t *)s)[i]; break;
- case 2: val = ((utf16_t *)s)[i]; break;
- case 4: val = ((utf32_t *)s)[i]; break;
- default: assert(0); break;
- }
- if (val)
- return false;
- }
- return true;
- }
-
- case TOKvector:
- {
- VectorExp *ve = (VectorExp *) exp;
- return isZeroInit(ve->e1);
- }
-
- case TOKfloat64:
- case TOKcomplex80:
- {
- return (exp->toReal() == CTFloat::zero) &&
- (exp->toImaginary() == CTFloat::zero);
- }
-
- default:
- return false;
- }
-}
-
-void StructDeclaration::finalizeSize()
-{
- //printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
- assert(sizeok != SIZEOKdone);
-
- //printf("+StructDeclaration::finalizeSize() %s, fields.length = %d, sizeok = %d\n", toChars(), fields.length, sizeok);
-
- fields.setDim(0); // workaround
-
- // Set the offsets of the fields and determine the size of the struct
- unsigned offset = 0;
- bool isunion = isUnionDeclaration() != NULL;
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->setFieldOffset(this, &offset, isunion);
- }
- if (type->ty == Terror)
- return;
-
- // 0 sized struct's are set to 1 byte
- if (structsize == 0)
- {
- structsize = 1;
- alignsize = 1;
- }
-
- // Round struct size up to next alignsize boundary.
- // This will ensure that arrays of structs will get their internals
- // aligned properly.
- if (alignment == STRUCTALIGN_DEFAULT)
- structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
- else
- structsize = (structsize + alignment - 1) & ~(alignment - 1);
-
- sizeok = SIZEOKdone;
-
- //printf("-StructDeclaration::finalizeSize() %s, fields.length = %d, structsize = %d\n", toChars(), fields.length, structsize);
-
- if (errors)
- return;
-
- // Calculate fields[i]->overlapped
- if (checkOverlappedFields())
- {
- errors = true;
- return;
- }
-
- // Determine if struct is all zeros or not
- zeroInit = 1;
- for (size_t i = 0; i < fields.length; i++)
- {
- VarDeclaration *vd = fields[i];
- if (vd->_init)
- {
- if (vd->_init->isVoidInitializer())
- /* Treat as 0 for the purposes of putting the initializer
- * in the BSS segment, or doing a mass set to 0
- */
- continue;
-
- // Zero size fields are zero initialized
- if (vd->type->size(vd->loc) == 0)
- continue;
-
- // Examine init to see if it is all 0s.
- Expression *exp = vd->getConstInitializer();
- if (!exp || !isZeroInit(exp))
- {
- zeroInit = 0;
- break;
- }
- }
- else if (!vd->type->isZeroInit(loc))
- {
- zeroInit = 0;
- break;
- }
- }
-
- TypeTuple *tt = target.toArgTypes(type);
- size_t dim = tt ? tt->arguments->length : 0;
- if (dim >= 1)
- {
- assert(dim <= 2);
- arg1type = (*tt->arguments)[0]->type;
- if (dim == 2)
- arg2type = (*tt->arguments)[1]->type;
- }
-}
-
-/***************************************
- * Fit elements[] to the corresponding type of field[].
- * Input:
- * loc
- * sc
- * elements The explicit arguments that given to construct object.
- * stype The constructed object type.
- * Returns false if any errors occur.
- * Otherwise, returns true and elements[] are rewritten for the output.
- */
-bool StructDeclaration::fit(Loc loc, Scope *sc, Expressions *elements, Type *stype)
-{
- if (!elements)
- return true;
-
- size_t nfields = fields.length - isNested();
- size_t offset = 0;
- for (size_t i = 0; i < elements->length; i++)
- {
- Expression *e = (*elements)[i];
- if (!e)
- continue;
-
- e = resolveProperties(sc, e);
- if (i >= nfields)
- {
- if (i == fields.length - 1 && isNested() && e->op == TOKnull)
- {
- // CTFE sometimes creates null as hidden pointer; we'll allow this.
- continue;
- }
- ::error(loc, "more initializers than fields (%d) of %s", (int)nfields, toChars());
- return false;
- }
- VarDeclaration *v = fields[i];
- if (v->offset < offset)
- {
- ::error(loc, "overlapping initialization for %s", v->toChars());
- return false;
- }
- offset = (unsigned)(v->offset + v->type->size());
-
- Type *t = v->type;
- if (stype)
- t = t->addMod(stype->mod);
- Type *origType = t;
- Type *tb = t->toBasetype();
-
- /* Look for case of initializing a static array with a too-short
- * string literal, such as:
- * char[5] foo = "abc";
- * Allow this by doing an explicit cast, which will lengthen the string
- * literal.
- */
- if (e->op == TOKstring && tb->ty == Tsarray)
- {
- StringExp *se = (StringExp *)e;
- Type *typeb = se->type->toBasetype();
- TY tynto = tb->nextOf()->ty;
- if (!se->committed &&
- (typeb->ty == Tarray || typeb->ty == Tsarray) &&
- (tynto == Tchar || tynto == Twchar || tynto == Tdchar) &&
- se->numberOfCodeUnits(tynto) < ((TypeSArray *)tb)->dim->toInteger())
- {
- e = se->castTo(sc, t);
- goto L1;
- }
- }
-
- while (!e->implicitConvTo(t) && tb->ty == Tsarray)
- {
- /* Static array initialization, as in:
- * T[3][5] = e;
- */
- t = tb->nextOf();
- tb = t->toBasetype();
- }
- if (!e->implicitConvTo(t))
- t = origType; // restore type for better diagnostic
-
- e = e->implicitCastTo(sc, t);
- L1:
- if (e->op == TOKerror)
- return false;
-
- (*elements)[i] = doCopyOrMove(sc, e);
- }
- return true;
-}
-
-/***************************************
- * Return true if struct is POD (Plain Old Data).
- * This is defined as:
- * not nested
- * no postblits, destructors, or assignment operators
- * no 'ref' fields or fields that are themselves non-POD
- * The idea being these are compatible with C structs.
- */
-bool StructDeclaration::isPOD()
-{
- // If we've already determined whether this struct is POD.
- if (ispod != ISPODfwd)
- return (ispod == ISPODyes);
-
- ispod = ISPODyes;
-
- if (enclosing || postblit || dtor)
- ispod = ISPODno;
-
- // Recursively check all fields are POD.
- for (size_t i = 0; i < fields.length; i++)
- {
- VarDeclaration *v = fields[i];
- if (v->storage_class & STCref)
- {
- ispod = ISPODno;
- break;
- }
-
- Type *tv = v->type->baseElemOf();
- if (tv->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)tv;
- StructDeclaration *sd = ts->sym;
- if (!sd->isPOD())
- {
- ispod = ISPODno;
- break;
- }
- }
- }
-
- return (ispod == ISPODyes);
-}
-
-const char *StructDeclaration::kind() const
-{
- return "struct";
-}
-
-/********************************* UnionDeclaration ****************************/
-
-UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id)
- : StructDeclaration(loc, id, false)
-{
-}
-
-Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- UnionDeclaration *ud = new UnionDeclaration(loc, ident);
- return StructDeclaration::syntaxCopy(ud);
-}
-
-const char *UnionDeclaration::kind() const
-{
- return "union";
-}
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
new file mode 100644
index 0000000..80ecd36
--- /dev/null
+++ b/gcc/d/dmd/dstruct.d
@@ -0,0 +1,610 @@
+/**
+ * Struct and union declarations.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dstruct.d, _dstruct.d)
+ * Documentation: https://dlang.org/phobos/dmd_dstruct.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dstruct.d
+ */
+
+module dmd.dstruct;
+
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.declaration;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.opover;
+import dmd.target;
+import dmd.tokens;
+import dmd.typesem;
+import dmd.typinf;
+import dmd.visitor;
+
+/***************************************
+ * Search sd for a member function of the form:
+ * `extern (D) string toString();`
+ * Params:
+ * sd = struct declaration to search
+ * Returns:
+ * FuncDeclaration of `toString()` if found, `null` if not
+ */
+extern (C++) FuncDeclaration search_toString(StructDeclaration sd)
+{
+ Dsymbol s = search_function(sd, Id.tostring);
+ FuncDeclaration fd = s ? s.isFuncDeclaration() : null;
+ if (fd)
+ {
+ __gshared TypeFunction tftostring;
+ if (!tftostring)
+ {
+ tftostring = new TypeFunction(ParameterList(), Type.tstring, LINK.d);
+ tftostring = tftostring.merge().toTypeFunction();
+ }
+ fd = fd.overloadExactMatch(tftostring);
+ }
+ return fd;
+}
+
+/***************************************
+ * Request additional semantic analysis for TypeInfo generation.
+ * Params:
+ * sc = context
+ * t = type that TypeInfo is being generated for
+ */
+extern (C++) void semanticTypeInfo(Scope* sc, Type t)
+{
+ if (sc)
+ {
+ if (sc.intypeof)
+ return;
+ if (sc.flags & (SCOPE.ctfe | SCOPE.compile))
+ return;
+ }
+
+ if (!t)
+ return;
+
+ void visitVector(TypeVector t)
+ {
+ semanticTypeInfo(sc, t.basetype);
+ }
+
+ void visitAArray(TypeAArray t)
+ {
+ semanticTypeInfo(sc, t.index);
+ semanticTypeInfo(sc, t.next);
+ }
+
+ void visitStruct(TypeStruct t)
+ {
+ //printf("semanticTypeInfo.visit(TypeStruct = %s)\n", t.toChars());
+ StructDeclaration sd = t.sym;
+
+ /* Step 1: create TypeInfoDeclaration
+ */
+ if (!sc) // inline may request TypeInfo.
+ {
+ Scope scx;
+ scx._module = sd.getModule();
+ getTypeInfoType(sd.loc, t, &scx);
+ sd.requestTypeInfo = true;
+ }
+ else if (!sc.minst)
+ {
+ // don't yet have to generate TypeInfo instance if
+ // the typeid(T) expression exists in speculative scope.
+ }
+ else
+ {
+ getTypeInfoType(sd.loc, t, sc);
+ sd.requestTypeInfo = true;
+
+ // https://issues.dlang.org/show_bug.cgi?id=15149
+ // if the typeid operand type comes from a
+ // result of auto function, it may be yet speculative.
+ // unSpeculative(sc, sd);
+ }
+
+ /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
+ * This should be done even if typeid(T) exists in speculative scope.
+ * Because it may appear later in non-speculative scope.
+ */
+ if (!sd.members)
+ return; // opaque struct
+ if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.dtor && !sd.xhash && !search_toString(sd))
+ return; // none of TypeInfo-specific members
+
+ // If the struct is in a non-root module, run semantic3 to get
+ // correct symbols for the member function.
+ if (sd.semanticRun >= PASS.semantic3)
+ {
+ // semantic3 is already done
+ }
+ else if (TemplateInstance ti = sd.isInstantiated())
+ {
+ if (ti.minst && !ti.minst.isRoot())
+ Module.addDeferredSemantic3(sd);
+ }
+ else
+ {
+ if (sd.inNonRoot())
+ {
+ //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd.toChars(), sd.inNonRoot());
+ Module.addDeferredSemantic3(sd);
+ }
+ }
+ }
+
+ void visitTuple(TypeTuple t)
+ {
+ if (t.arguments)
+ {
+ foreach (arg; *t.arguments)
+ {
+ semanticTypeInfo(sc, arg.type);
+ }
+ }
+ }
+
+ /* Note structural similarity of this Type walker to that in isSpeculativeType()
+ */
+
+ Type tb = t.toBasetype();
+ switch (tb.ty)
+ {
+ case Tvector: visitVector(tb.isTypeVector()); break;
+ case Taarray: visitAArray(tb.isTypeAArray()); break;
+ case Tstruct: visitStruct(tb.isTypeStruct()); break;
+ case Ttuple: visitTuple (tb.isTypeTuple()); break;
+
+ case Tclass:
+ case Tenum: break;
+
+ default: semanticTypeInfo(sc, tb.nextOf()); break;
+ }
+}
+
+enum StructFlags : int
+{
+ none = 0x0,
+ hasPointers = 0x1, // NB: should use noPointers as in ClassFlags
+}
+
+/***********************************************************
+ * All `struct` declarations are an instance of this.
+ */
+extern (C++) class StructDeclaration : AggregateDeclaration
+{
+ bool zeroInit; // !=0 if initialize with 0 fill
+ bool hasIdentityAssign; // true if has identity opAssign
+ bool hasBlitAssign; // true if opAssign is a blit
+ bool hasIdentityEquals; // true if has identity opEquals
+ bool hasNoFields; // has no fields
+ bool hasCopyCtor; // copy constructor
+ // Even if struct is defined as non-root symbol, some built-in operations
+ // (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
+ // For those, today TypeInfo_Struct is generated in COMDAT.
+ bool requestTypeInfo;
+
+ FuncDeclarations postblits; // Array of postblit functions
+ FuncDeclaration postblit; // aggregate postblit
+
+ FuncDeclaration xeq; // TypeInfo_Struct.xopEquals
+ FuncDeclaration xcmp; // TypeInfo_Struct.xopCmp
+ FuncDeclaration xhash; // TypeInfo_Struct.xtoHash
+ extern (C++) __gshared FuncDeclaration xerreq; // object.xopEquals
+ extern (C++) __gshared FuncDeclaration xerrcmp; // object.xopCmp
+
+ structalign_t alignment; // alignment applied outside of the struct
+ ThreeState ispod; // if struct is POD
+
+ // ABI-specific type(s) if the struct can be passed in registers
+ TypeTuple argTypes;
+
+ extern (D) this(const ref Loc loc, Identifier id, bool inObject)
+ {
+ super(loc, id);
+ zeroInit = false; // assume false until we do semantic processing
+ ispod = ThreeState.none;
+ // For forward references
+ type = new TypeStruct(this);
+
+ if (inObject)
+ {
+ if (id == Id.ModuleInfo && !Module.moduleinfo)
+ Module.moduleinfo = this;
+ }
+ }
+
+ static StructDeclaration create(Loc loc, Identifier id, bool inObject)
+ {
+ return new StructDeclaration(loc, id, inObject);
+ }
+
+ override StructDeclaration syntaxCopy(Dsymbol s)
+ {
+ StructDeclaration sd =
+ s ? cast(StructDeclaration)s
+ : new StructDeclaration(loc, ident, false);
+ ScopeDsymbol.syntaxCopy(sd);
+ return sd;
+ }
+
+ override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
+ {
+ //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
+ if (_scope && !symtab)
+ dsymbolSemantic(this, _scope);
+
+ if (!members || !symtab) // opaque or semantic() is not yet called
+ {
+ // .stringof is always defined (but may be hidden by some other symbol)
+ if(ident != Id.stringof && !(flags & IgnoreErrors) && semanticRun < PASS.semanticdone)
+ error("is forward referenced when looking for `%s`", ident.toChars());
+ return null;
+ }
+
+ return ScopeDsymbol.search(loc, ident, flags);
+ }
+
+ override const(char)* kind() const
+ {
+ return "struct";
+ }
+
+ override final void finalizeSize()
+ {
+ //printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
+ assert(sizeok != Sizeok.done);
+
+ if (sizeok == Sizeok.inProcess)
+ {
+ return;
+ }
+ sizeok = Sizeok.inProcess;
+
+ //printf("+StructDeclaration::finalizeSize() %s, fields.dim = %d, sizeok = %d\n", toChars(), fields.dim, sizeok);
+
+ fields.setDim(0); // workaround
+
+ // Set the offsets of the fields and determine the size of the struct
+ FieldState fieldState;
+ bool isunion = isUnionDeclaration() !is null;
+ for (size_t i = 0; i < members.dim; i++)
+ {
+ Dsymbol s = (*members)[i];
+ s.setFieldOffset(this, fieldState, isunion);
+ }
+ if (type.ty == Terror)
+ {
+ errors = true;
+ return;
+ }
+
+ // 0 sized struct's are set to 1 byte
+ if (structsize == 0)
+ {
+ hasNoFields = true;
+ alignsize = 1;
+ if (classKind != classKind.c) // C gets a struct size of 0
+ structsize = 1;
+ }
+
+ // Round struct size up to next alignsize boundary.
+ // This will ensure that arrays of structs will get their internals
+ // aligned properly.
+ if (alignment == STRUCTALIGN_DEFAULT)
+ structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
+ else
+ structsize = (structsize + alignment - 1) & ~(alignment - 1);
+
+ sizeok = Sizeok.done;
+
+ //printf("-StructDeclaration::finalizeSize() %s, fields.dim = %d, structsize = %d\n", toChars(), fields.dim, structsize);
+
+ if (errors)
+ return;
+
+ // Calculate fields[i].overlapped
+ if (checkOverlappedFields())
+ {
+ errors = true;
+ return;
+ }
+
+ // Determine if struct is all zeros or not
+ zeroInit = true;
+ foreach (vd; fields)
+ {
+ if (vd._init)
+ {
+ if (vd._init.isVoidInitializer())
+ /* Treat as 0 for the purposes of putting the initializer
+ * in the BSS segment, or doing a mass set to 0
+ */
+ continue;
+
+ // Zero size fields are zero initialized
+ if (vd.type.size(vd.loc) == 0)
+ continue;
+
+ // Examine init to see if it is all 0s.
+ auto exp = vd.getConstInitializer();
+ if (!exp || !_isZeroInit(exp))
+ {
+ zeroInit = false;
+ break;
+ }
+ }
+ else if (!vd.type.isZeroInit(loc))
+ {
+ zeroInit = false;
+ break;
+ }
+ }
+
+ argTypes = target.toArgTypes(type);
+ }
+
+ /***************************************
+ * Determine if struct is POD (Plain Old Data).
+ *
+ * POD is defined as:
+ * $(OL
+ * $(LI not nested)
+ * $(LI no postblits, destructors, or assignment operators)
+ * $(LI no `ref` fields or fields that are themselves non-POD)
+ * )
+ * The idea being these are compatible with C structs.
+ *
+ * Returns:
+ * true if struct is POD
+ */
+ final bool isPOD()
+ {
+ // If we've already determined whether this struct is POD.
+ if (ispod != ThreeState.none)
+ return (ispod == ThreeState.yes);
+
+ ispod = ThreeState.yes;
+
+ if (enclosing || postblit || dtor || hasCopyCtor)
+ {
+ ispod = ThreeState.no;
+ return false;
+ }
+
+ // Recursively check all fields are POD.
+ for (size_t i = 0; i < fields.dim; i++)
+ {
+ VarDeclaration v = fields[i];
+ if (v.storage_class & STC.ref_)
+ {
+ ispod = ThreeState.no;
+ return false;
+ }
+
+ Type tv = v.type.baseElemOf();
+ if (tv.ty == Tstruct)
+ {
+ TypeStruct ts = cast(TypeStruct)tv;
+ StructDeclaration sd = ts.sym;
+ if (!sd.isPOD())
+ {
+ ispod = ThreeState.no;
+ return false;
+ }
+ }
+ }
+
+ return (ispod == ThreeState.yes);
+ }
+
+ override final inout(StructDeclaration) isStructDeclaration() inout @nogc nothrow pure @safe
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ final uint numArgTypes() const
+ {
+ return argTypes && argTypes.arguments ? cast(uint) argTypes.arguments.dim : 0;
+ }
+
+ final Type argType(uint index)
+ {
+ return index < numArgTypes() ? (*argTypes.arguments)[index].type : null;
+ }
+
+
+ /***************************************
+ * Verifies whether the struct declaration has a
+ * constructor that is not a copy constructor.
+ * Optionally, it can check whether the struct
+ * declaration has a regular constructor, that
+ * is not disabled.
+ *
+ * Params:
+ * checkDisabled = if the struct has a regular
+ non-disabled constructor
+ * Returns:
+ * true, if the struct has a regular (optionally,
+ * not disabled) constructor, false otherwise.
+ */
+ final bool hasRegularCtor(bool checkDisabled = false)
+ {
+ if (!ctor)
+ return false;
+
+ bool result;
+ overloadApply(ctor, (Dsymbol s)
+ {
+ if (auto td = s.isTemplateDeclaration())
+ {
+ if (checkDisabled && td.onemember)
+ {
+ if (auto ctorDecl = td.onemember.isCtorDeclaration())
+ {
+ if (ctorDecl.storage_class & STC.disable)
+ return 0;
+ }
+ }
+ result = true;
+ return 1;
+ }
+ if (auto ctorDecl = s.isCtorDeclaration())
+ {
+ if (!ctorDecl.isCpCtor && (!checkDisabled || !(ctorDecl.storage_class & STC.disable)))
+ {
+ result = true;
+ return 1;
+ }
+ }
+ return 0;
+ });
+ return result;
+ }
+}
+
+/**********************************
+ * Determine if exp is all binary zeros.
+ * Params:
+ * exp = expression to check
+ * Returns:
+ * true if it's all binary 0
+ */
+private bool _isZeroInit(Expression exp)
+{
+ switch (exp.op)
+ {
+ case TOK.int64:
+ return exp.toInteger() == 0;
+
+ case TOK.null_:
+ case TOK.false_:
+ return true;
+
+ case TOK.structLiteral:
+ {
+ auto sle = cast(StructLiteralExp) exp;
+ foreach (i; 0 .. sle.sd.fields.dim)
+ {
+ auto field = sle.sd.fields[i];
+ if (field.type.size(field.loc))
+ {
+ auto e = (*sle.elements)[i];
+ if (e ? !_isZeroInit(e)
+ : !field.type.isZeroInit(field.loc))
+ return false;
+ }
+ }
+ return true;
+ }
+
+ case TOK.arrayLiteral:
+ {
+ auto ale = cast(ArrayLiteralExp)exp;
+
+ const dim = ale.elements ? ale.elements.dim : 0;
+
+ if (ale.type.toBasetype().ty == Tarray) // if initializing a dynamic array
+ return dim == 0;
+
+ foreach (i; 0 .. dim)
+ {
+ if (!_isZeroInit(ale[i]))
+ return false;
+ }
+
+ /* Note that true is returned for all T[0]
+ */
+ return true;
+ }
+
+ case TOK.string_:
+ {
+ StringExp se = cast(StringExp)exp;
+
+ if (se.type.toBasetype().ty == Tarray) // if initializing a dynamic array
+ return se.len == 0;
+
+ foreach (i; 0 .. se.len)
+ {
+ if (se.getCodeUnit(i))
+ return false;
+ }
+ return true;
+ }
+
+ case TOK.vector:
+ {
+ auto ve = cast(VectorExp) exp;
+ return _isZeroInit(ve.e1);
+ }
+
+ case TOK.float64:
+ case TOK.complex80:
+ {
+ import dmd.root.ctfloat : CTFloat;
+ return (exp.toReal() is CTFloat.zero) &&
+ (exp.toImaginary() is CTFloat.zero);
+ }
+
+ default:
+ return false;
+ }
+}
+
+/***********************************************************
+ * Unions are a variation on structs.
+ */
+extern (C++) final class UnionDeclaration : StructDeclaration
+{
+ extern (D) this(const ref Loc loc, Identifier id)
+ {
+ super(loc, id, false);
+ }
+
+ override UnionDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto ud = new UnionDeclaration(loc, ident);
+ StructDeclaration.syntaxCopy(ud);
+ return ud;
+ }
+
+ override const(char)* kind() const
+ {
+ return "union";
+ }
+
+ override inout(UnionDeclaration) isUnionDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
diff --git a/gcc/d/dmd/dsymbol.c b/gcc/d/dmd/dsymbol.c
deleted file mode 100644
index f0c1cf6..0000000
--- a/gcc/d/dmd/dsymbol.c
+++ /dev/null
@@ -1,1803 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/dsymbol.c
- */
-
-#include "root/dsystem.h"
-#include "root/rmem.h"
-#include "root/speller.h"
-#include "root/aav.h"
-
-#include "mars.h"
-#include "dsymbol.h"
-#include "aggregate.h"
-#include "identifier.h"
-#include "module.h"
-#include "mtype.h"
-#include "expression.h"
-#include "statement.h"
-#include "declaration.h"
-#include "id.h"
-#include "scope.h"
-#include "init.h"
-#include "import.h"
-#include "template.h"
-#include "attrib.h"
-#include "enum.h"
-#include "lexer.h"
-#include "nspace.h"
-
-bool symbolIsVisible(Dsymbol *origin, Dsymbol *s);
-typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s);
-int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL);
-
-
-/****************************** Dsymbol ******************************/
-
-Dsymbol::Dsymbol()
-{
- //printf("Dsymbol::Dsymbol(%p)\n", this);
- this->ident = NULL;
- this->parent = NULL;
- this->csym = NULL;
- this->isym = NULL;
- this->loc = Loc();
- this->comment = NULL;
- this->_scope = NULL;
- this->prettystring = NULL;
- this->semanticRun = PASSinit;
- this->errors = false;
- this->depdecl = NULL;
- this->userAttribDecl = NULL;
- this->ddocUnittest = NULL;
-}
-
-Dsymbol::Dsymbol(Identifier *ident)
-{
- //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
- this->ident = ident;
- this->parent = NULL;
- this->csym = NULL;
- this->isym = NULL;
- this->loc = Loc();
- this->comment = NULL;
- this->_scope = NULL;
- this->prettystring = NULL;
- this->semanticRun = PASSinit;
- this->errors = false;
- this->depdecl = NULL;
- this->userAttribDecl = NULL;
- this->ddocUnittest = NULL;
-}
-
-Dsymbol *Dsymbol::create(Identifier *ident)
-{
- return new Dsymbol(ident);
-}
-
-bool Dsymbol::equals(RootObject *o)
-{
- if (this == o)
- return true;
- Dsymbol *s = (Dsymbol *)(o);
- // Overload sets don't have an ident
- if (s && ident && s->ident && ident->equals(s->ident))
- return true;
- return false;
-}
-
-/**************************************
- * Copy the syntax.
- * Used for template instantiations.
- * If s is NULL, allocate the new object, otherwise fill it in.
- */
-
-Dsymbol *Dsymbol::syntaxCopy(Dsymbol *)
-{
- print();
- printf("%s %s\n", kind(), toChars());
- assert(0);
- return NULL;
-}
-
-/**************************************
- * Determine if this symbol is only one.
- * Returns:
- * false, *ps = NULL: There are 2 or more symbols
- * true, *ps = NULL: There are zero symbols
- * true, *ps = symbol: The one and only one symbol
- */
-
-bool Dsymbol::oneMember(Dsymbol **ps, Identifier *)
-{
- //printf("Dsymbol::oneMember()\n");
- *ps = this;
- return true;
-}
-
-/*****************************************
- * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
- */
-
-bool Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident)
-{
- //printf("Dsymbol::oneMembers() %d\n", members ? members->length : 0);
- Dsymbol *s = NULL;
-
- if (members)
- {
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *sx = (*members)[i];
- bool x = sx->oneMember(ps, ident);
- //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps);
- if (!x)
- {
- //printf("\tfalse 1\n");
- assert(*ps == NULL);
- return false;
- }
- if (*ps)
- {
- assert(ident);
- if (!(*ps)->ident || !(*ps)->ident->equals(ident))
- continue;
- if (!s)
- s = *ps;
- else if (s->isOverloadable() && (*ps)->isOverloadable())
- {
- // keep head of overload set
- FuncDeclaration *f1 = s->isFuncDeclaration();
- FuncDeclaration *f2 = (*ps)->isFuncDeclaration();
- if (f1 && f2)
- {
- assert(!f1->isFuncAliasDeclaration());
- assert(!f2->isFuncAliasDeclaration());
- for (; f1 != f2; f1 = f1->overnext0)
- {
- if (f1->overnext0 == NULL)
- {
- f1->overnext0 = f2;
- break;
- }
- }
- }
- }
- else // more than one symbol
- {
- *ps = NULL;
- //printf("\tfalse 2\n");
- return false;
- }
- }
- }
- }
- *ps = s; // s is the one symbol, NULL if none
- //printf("\ttrue\n");
- return true;
-}
-
-/*****************************************
- * Is Dsymbol a variable that contains pointers?
- */
-
-bool Dsymbol::hasPointers()
-{
- //printf("Dsymbol::hasPointers() %s\n", toChars());
- return false;
-}
-
-bool Dsymbol::hasStaticCtorOrDtor()
-{
- //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
- return false;
-}
-
-void Dsymbol::setFieldOffset(AggregateDeclaration *, unsigned *, bool)
-{
-}
-
-Identifier *Dsymbol::getIdent()
-{
- return ident;
-}
-
-const char *Dsymbol::toChars()
-{
- return ident ? ident->toChars() : "__anonymous";
-}
-
-const char *Dsymbol::toPrettyCharsHelper()
-{
- return toChars();
-}
-
-const char *Dsymbol::toPrettyChars(bool QualifyTypes)
-{
- if (prettystring && !QualifyTypes)
- return (const char *)prettystring;
-
- //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
- if (!parent)
- {
- const char *s = toChars();
- if (!QualifyTypes)
- prettystring = (const utf8_t *)s;
- return s;
- }
-
- // Computer number of components
- size_t complength = 0;
- for (Dsymbol *p = this; p; p = p->parent)
- ++complength;
-
- // Allocate temporary array comp[]
- const char **comp = (const char **)mem.xmalloc(complength * sizeof(char**));
-
- // Fill in comp[] and compute length of final result
- size_t length = 0;
- int i = 0;
- for (Dsymbol *p = this; p; p = p->parent)
- {
- const char *s = QualifyTypes ? p->toPrettyCharsHelper() : p->toChars();
- const size_t len = strlen(s);
- comp[i] = s;
- ++i;
- length += len + 1;
- }
-
- char *s = (char *)mem.xmalloc(length);
- char *q = s + length - 1;
- *q = 0;
- for (size_t j = 0; j < complength; j++)
- {
- const char *t = comp[j];
- const size_t len = strlen(t);
- q -= len;
- memcpy(q, t, len);
- if (q == s)
- break;
- *--q = '.';
- }
- free(comp);
- if (!QualifyTypes)
- prettystring = (utf8_t *)s;
- return s;
-}
-
-Loc& Dsymbol::getLoc()
-{
- if (!loc.filename) // avoid bug 5861.
- {
- Module *m = getModule();
-
- if (m && m->srcfile)
- loc.filename = m->srcfile->toChars();
- }
- return loc;
-}
-
-const char *Dsymbol::locToChars()
-{
- return getLoc().toChars();
-}
-
-const char *Dsymbol::kind() const
-{
- return "symbol";
-}
-
-/*********************************
- * If this symbol is really an alias for another,
- * return that other.
- * If needed, semantic() is invoked due to resolve forward reference.
- */
-Dsymbol *Dsymbol::toAlias()
-{
- return this;
-}
-
-/*********************************
- * Resolve recursive tuple expansion in eponymous template.
- */
-Dsymbol *Dsymbol::toAlias2()
-{
- return toAlias();
-}
-
-/**
- * `pastMixin` returns the enclosing symbol if this is a template mixin.
- *
- * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that
- * are mangleOnly.
- *
- * See also `parent`, `toParent`, `toParent2` and `toParent3`.
- */
-Dsymbol *Dsymbol::pastMixin()
-{
- //printf("Dsymbol::pastMixin() %s\n", toChars());
- if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
- return this;
- if (!parent)
- return NULL;
- return parent->pastMixin();
-}
-
-/// ditto
-Dsymbol *Dsymbol::pastMixinAndNspace()
-{
- //printf("Dsymbol::pastMixinAndNspace() %s\n", toChars());
- Nspace *ns = isNspace();
- if (!(ns && ns->mangleOnly) &&
- !isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
- return this;
- if (!parent)
- return NULL;
- return parent->pastMixinAndNspace();
-}
-
-/**********************************
- * `parent` field returns a lexically enclosing scope symbol this is a member of.
- *
- * `toParent()` returns a logically enclosing scope symbol this is a member of.
- * It skips over TemplateMixin's and Nspaces that are mangleOnly.
- *
- * `toParent2()` returns an enclosing scope symbol this is living at runtime.
- * It skips over both TemplateInstance's and TemplateMixin's.
- * It's used when looking for the 'this' pointer of the enclosing function/class.
- *
- * `toParent3()` returns a logically enclosing scope symbol this is a member of.
- * It skips over TemplateMixin's.
- *
- * Examples:
- * module mod;
- * template Foo(alias a) { mixin Bar!(); }
- * mixin template Bar() {
- * public { // ProtDeclaration
- * void baz() { a = 2; }
- * }
- * }
- * void test() {
- * int v = 1;
- * alias foo = Foo!(v);
- * foo.baz();
- * assert(v == 2);
- * }
- *
- * // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()')
- * // s.parent == TemplateMixin('mod.test.Foo!().Bar!()')
- * // s.toParent() == TemplateInstance('mod.test.Foo!()')
- * // s.toParent2() == FuncDeclaration('mod.test')
- */
-Dsymbol *Dsymbol::toParent()
-{
- return parent ? parent->pastMixinAndNspace() : NULL;
-}
-
-/// ditto
-Dsymbol *Dsymbol::toParent2()
-{
- if (!parent ||
- (!parent->isTemplateInstance() &&
- !parent->isForwardingAttribDeclaration() &&
- !parent->isForwardingScopeDsymbol()))
- return parent;
- return parent->toParent2();
-}
-
-/// ditto
-Dsymbol *Dsymbol::toParent3()
-{
- return parent ? parent->pastMixin() : NULL;
-}
-
-TemplateInstance *Dsymbol::isInstantiated()
-{
- for (Dsymbol *s = parent; s; s = s->parent)
- {
- TemplateInstance *ti = s->isTemplateInstance();
- if (ti && !ti->isTemplateMixin())
- return ti;
- }
- return NULL;
-}
-
-// Check if this function is a member of a template which has only been
-// instantiated speculatively, eg from inside is(typeof()).
-// Return the speculative template instance it is part of,
-// or NULL if not speculative.
-TemplateInstance *Dsymbol::isSpeculative()
-{
- Dsymbol *par = parent;
- while (par)
- {
- TemplateInstance *ti = par->isTemplateInstance();
- if (ti && ti->gagged)
- return ti;
- par = par->toParent();
- }
- return NULL;
-}
-
-Ungag Dsymbol::ungagSpeculative()
-{
- unsigned oldgag = global.gag;
-
- if (global.gag && !isSpeculative() && !toParent2()->isFuncDeclaration())
- global.gag = 0;
-
- return Ungag(oldgag);
-}
-
-bool Dsymbol::isAnonymous()
-{
- return ident == NULL;
-}
-
-/*************************************
- * Set scope for future semantic analysis so we can
- * deal better with forward references.
- */
-
-void Dsymbol::setScope(Scope *sc)
-{
- //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc->stc);
- if (!sc->nofree)
- sc->setNoFree(); // may need it even after semantic() finishes
- _scope = sc;
- if (sc->depdecl)
- depdecl = sc->depdecl;
-
- if (!userAttribDecl)
- userAttribDecl = sc->userAttribDecl;
-}
-
-void Dsymbol::importAll(Scope *)
-{
-}
-
-/*********************************************
- * Search for ident as member of s.
- * Params:
- * loc = location to print for error messages
- * ident = identifier to search for
- * flags = IgnoreXXXX
- * Returns:
- * NULL if not found
- */
-
-Dsymbol *Dsymbol::search(const Loc &, Identifier *, int)
-{
- //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
- return NULL;
-}
-
-/***************************************************
- * Search for symbol with correct spelling.
- */
-
-void *symbol_search_fp(void *arg, const char *seed, int *cost)
-{
- /* If not in the lexer's string table, it certainly isn't in the symbol table.
- * Doing this first is a lot faster.
- */
- size_t len = strlen(seed);
- if (!len)
- return NULL;
- Identifier *id = Identifier::lookup(seed, len);
- if (!id)
- return NULL;
-
- *cost = 0;
- Dsymbol *s = (Dsymbol *)arg;
- Module::clearCache();
- return (void *)s->search(Loc(), id, IgnoreErrors);
-}
-
-Dsymbol *Dsymbol::search_correct(Identifier *ident)
-{
- if (global.gag)
- return NULL; // don't do it for speculative compiles; too time consuming
- // search for exact name first
- if (Dsymbol *s = search(Loc(), ident, IgnoreErrors))
- return s;
- return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, (void *)this, idchars);
-}
-
-/***************************************
- * Search for identifier id as a member of 'this'.
- * id may be a template instance.
- * Returns:
- * symbol found, NULL if not
- */
-Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id, int flags)
-{
- //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
- Dsymbol *s = toAlias();
- Dsymbol *sm;
-
- if (Declaration *d = s->isDeclaration())
- {
- if (d->inuse)
- {
- ::error(loc, "circular reference to `%s`", d->toPrettyChars());
- return NULL;
- }
- }
-
- switch (id->dyncast())
- {
- case DYNCAST_IDENTIFIER:
- sm = s->search(loc, (Identifier *)id, flags);
- break;
-
- case DYNCAST_DSYMBOL:
- {
- // It's a template instance
- //printf("\ttemplate instance id\n");
- Dsymbol *st = (Dsymbol *)id;
- TemplateInstance *ti = st->isTemplateInstance();
- sm = s->search(loc, ti->name);
- if (!sm)
- {
- sm = s->search_correct(ti->name);
- if (sm)
- ::error(loc, "template identifier `%s` is not a member of %s `%s`, did you mean %s `%s`?",
- ti->name->toChars(), s->kind(), s->toPrettyChars(), sm->kind(), sm->toChars());
- else
- ::error(loc, "template identifier `%s` is not a member of %s `%s`",
- ti->name->toChars(), s->kind(), s->toPrettyChars());
- return NULL;
- }
- sm = sm->toAlias();
- TemplateDeclaration *td = sm->isTemplateDeclaration();
- if (!td)
- {
- ::error(loc, "%s.%s is not a template, it is a %s", s->toPrettyChars(), ti->name->toChars(), sm->kind());
- return NULL;
- }
- ti->tempdecl = td;
- if (!ti->semanticRun)
- dsymbolSemantic(ti, sc);
- sm = ti->toAlias();
- break;
- }
-
- case DYNCAST_TYPE:
- case DYNCAST_EXPRESSION:
- default:
- assert(0);
- }
- return sm;
-}
-
-bool Dsymbol::overloadInsert(Dsymbol *)
-{
- //printf("Dsymbol::overloadInsert('%s')\n", s->toChars());
- return false;
-}
-
-d_uns64 Dsymbol::size(Loc)
-{
- error("Dsymbol `%s` has no size", toChars());
- return SIZE_INVALID;
-}
-
-bool Dsymbol::isforwardRef()
-{
- return false;
-}
-
-AggregateDeclaration *Dsymbol::isThis()
-{
- return NULL;
-}
-
-bool Dsymbol::isExport() const
-{
- return false;
-}
-
-bool Dsymbol::isImportedSymbol() const
-{
- return false;
-}
-
-bool Dsymbol::isDeprecated()
-{
- return false;
-}
-
-bool Dsymbol::isOverloadable()
-{
- return false;
-}
-
-LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()?
-{
- return NULL;
-}
-
-/// Returns an AggregateDeclaration when toParent() is that.
-AggregateDeclaration *Dsymbol::isMember()
-{
- //printf("Dsymbol::isMember() %s\n", toChars());
- Dsymbol *parent = toParent();
- //printf("parent is %s %s\n", parent->kind(), parent->toChars());
- return parent ? parent->isAggregateDeclaration() : NULL;
-}
-
-/// Returns an AggregateDeclaration when toParent2() is that.
-AggregateDeclaration *Dsymbol::isMember2()
-{
- //printf("Dsymbol::isMember2() %s\n", toChars());
- Dsymbol *parent = toParent2();
- //printf("parent is %s %s\n", parent->kind(), parent->toChars());
- return parent ? parent->isAggregateDeclaration() : NULL;
-}
-
-// is this a member of a ClassDeclaration?
-ClassDeclaration *Dsymbol::isClassMember()
-{
- AggregateDeclaration *ad = isMember();
- return ad ? ad->isClassDeclaration() : NULL;
-}
-
-Type *Dsymbol::getType()
-{
- return NULL;
-}
-
-bool Dsymbol::needThis()
-{
- return false;
-}
-
-/*********************************
- * Iterate this dsymbol or members of this scoped dsymbol, then
- * call `fp` with the found symbol and `param`.
- * Params:
- * fp = function pointer to process the iterated symbol.
- * If it returns nonzero, the iteration will be aborted.
- * param = a parameter passed to fp.
- * Returns:
- * nonzero if the iteration is aborted by the return value of fp,
- * or 0 if it's completed.
- */
-int Dsymbol::apply(Dsymbol_apply_ft_t fp, void *param)
-{
- return (*fp)(this, param);
-}
-
-void Dsymbol::addMember(Scope *, ScopeDsymbol *sds)
-{
- //printf("Dsymbol::addMember('%s')\n", toChars());
- //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds->toChars());
- //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds->symtab = %p)\n", this, toChars(), sds, sds->symtab);
- parent = sds;
- if (!isAnonymous()) // no name, so can't add it to symbol table
- {
- if (!sds->symtabInsert(this)) // if name is already defined
- {
- Dsymbol *s2 = sds->symtabLookup(this, ident);
- if (!s2->overloadInsert(this))
- {
- sds->multiplyDefined(Loc(), this, s2);
- errors = true;
- }
- }
- if (sds->isAggregateDeclaration() || sds->isEnumDeclaration())
- {
- if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::_mangleof)
- {
- error(".%s property cannot be redefined", ident->toChars());
- errors = true;
- }
- }
- }
-}
-
-void Dsymbol::error(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- ::verror(getLoc(), format, ap, kind(), toPrettyChars());
- va_end(ap);
-}
-
-void Dsymbol::error(Loc loc, const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- ::verror(loc, format, ap, kind(), toPrettyChars());
- va_end(ap);
-}
-
-void Dsymbol::deprecation(Loc loc, const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- ::vdeprecation(loc, format, ap, kind(), toPrettyChars());
- va_end(ap);
-}
-
-void Dsymbol::deprecation(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- ::vdeprecation(getLoc(), format, ap, kind(), toPrettyChars());
- va_end(ap);
-}
-
-bool Dsymbol::checkDeprecated(Loc loc, Scope *sc)
-{
- if (global.params.useDeprecated != DIAGNOSTICoff && isDeprecated())
- {
- // Don't complain if we're inside a deprecated symbol's scope
- for (Dsymbol *sp = sc->parent; sp; sp = sp->parent)
- {
- if (sp->isDeprecated())
- return false;
- }
-
- for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing)
- {
- if (sc2->scopesym && sc2->scopesym->isDeprecated())
- return false;
-
- // If inside a StorageClassDeclaration that is deprecated
- if (sc2->stc & STCdeprecated)
- return false;
- }
-
- const char *message = NULL;
- for (Dsymbol *p = this; p; p = p->parent)
- {
- message = p->depdecl ? p->depdecl->getMessage() : NULL;
- if (message)
- break;
- }
-
- if (message)
- deprecation(loc, "is deprecated - %s", message);
- else
- deprecation(loc, "is deprecated");
-
- return true;
- }
-
- return false;
-}
-
-/**********************************
- * Determine which Module a Dsymbol is in.
- */
-
-Module *Dsymbol::getModule()
-{
- //printf("Dsymbol::getModule()\n");
- if (TemplateInstance *ti = isInstantiated())
- return ti->tempdecl->getModule();
-
- Dsymbol *s = this;
- while (s)
- {
- //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars());
- Module *m = s->isModule();
- if (m)
- return m;
- s = s->parent;
- }
- return NULL;
-}
-
-/**********************************
- * Determine which Module a Dsymbol is in, as far as access rights go.
- */
-
-Module *Dsymbol::getAccessModule()
-{
- //printf("Dsymbol::getAccessModule()\n");
- if (TemplateInstance *ti = isInstantiated())
- return ti->tempdecl->getAccessModule();
-
- Dsymbol *s = this;
- while (s)
- {
- //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars());
- Module *m = s->isModule();
- if (m)
- return m;
- TemplateInstance *ti = s->isTemplateInstance();
- if (ti && ti->enclosing)
- {
- /* Because of local template instantiation, the parent isn't where the access
- * rights come from - it's the template declaration
- */
- s = ti->tempdecl;
- }
- else
- s = s->parent;
- }
- return NULL;
-}
-
-/*************************************
- */
-
-Prot Dsymbol::prot()
-{
- return Prot(Prot::public_);
-}
-
-/*************************************
- * Do syntax copy of an array of Dsymbol's.
- */
-
-Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a)
-{
-
- Dsymbols *b = NULL;
- if (a)
- {
- b = a->copy();
- for (size_t i = 0; i < b->length; i++)
- {
- (*b)[i] = (*b)[i]->syntaxCopy(NULL);
- }
- }
- return b;
-}
-
-/****************************************
- * Add documentation comment to Dsymbol.
- * Ignore NULL comments.
- */
-
-void Dsymbol::addComment(const utf8_t *comment)
-{
- //if (comment)
- //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
-
- if (!this->comment)
- this->comment = comment;
- else if (comment && strcmp((const char *)comment, (const char *)this->comment) != 0)
- { // Concatenate the two
- this->comment = Lexer::combineComments(this->comment, comment);
- }
-}
-
-/****************************************
- * Returns true if this symbol is defined in a non-root module without instantiation.
- */
-bool Dsymbol::inNonRoot()
-{
- Dsymbol *s = parent;
- for (; s; s = s->toParent())
- {
- if (s->isTemplateInstance())
- {
- return false;
- }
- if (Module *m = s->isModule())
- {
- if (!m->isRoot())
- return true;
- break;
- }
- }
- return false;
-}
-
-/********************************* OverloadSet ****************************/
-
-OverloadSet::OverloadSet(Identifier *ident, OverloadSet *os)
- : Dsymbol(ident)
-{
- if (os)
- {
- for (size_t i = 0; i < os->a.length; i++)
- {
- a.push(os->a[i]);
- }
- }
-}
-
-void OverloadSet::push(Dsymbol *s)
-{
- a.push(s);
-}
-
-const char *OverloadSet::kind() const
-{
- return "overloadset";
-}
-
-
-/********************************* ForwardingScopeDsymbol ******************/
-
-ForwardingScopeDsymbol::ForwardingScopeDsymbol(ScopeDsymbol *forward)
- : ScopeDsymbol()
-{
- this->forward = forward;
-}
-
-Dsymbol *ForwardingScopeDsymbol::symtabInsert(Dsymbol *s)
-{
- assert(forward);
- if (Declaration *d = s->isDeclaration())
- {
- if (d->storage_class & STClocal)
- {
- // Symbols with storage class STClocal are not
- // forwarded, but stored in the local symbol
- // table. (Those are the `static foreach` variables.)
- if (!symtab)
- {
- symtab = new DsymbolTable();
- }
- return ScopeDsymbol::symtabInsert(s); // insert locally
- }
- }
- if (!forward->symtab)
- {
- forward->symtab = new DsymbolTable();
- }
- // Non-STClocal symbols are forwarded to `forward`.
- return forward->symtabInsert(s);
-}
-
-/************************
- * This override handles the following two cases:
- * static foreach (i, i; [0]) { ... }
- * and
- * static foreach (i; [0]) { enum i = 2; }
- */
-Dsymbol *ForwardingScopeDsymbol::symtabLookup(Dsymbol *s, Identifier *id)
-{
- assert(forward);
- // correctly diagnose clashing foreach loop variables.
- if (Declaration *d = s->isDeclaration())
- {
- if (d->storage_class & STClocal)
- {
- if (!symtab)
- {
- symtab = new DsymbolTable();
- }
- return ScopeDsymbol::symtabLookup(s,id);
- }
- }
- // Declarations within `static foreach` do not clash with
- // `static foreach` loop variables.
- if (!forward->symtab)
- {
- forward->symtab = new DsymbolTable();
- }
- return forward->symtabLookup(s,id);
-}
-
-void ForwardingScopeDsymbol::importScope(Dsymbol *s, Prot protection)
-{
- forward->importScope(s, protection);
-}
-
-const char *ForwardingScopeDsymbol::kind() const
-{
- return "local scope";
-}
-
-/********************************* ScopeDsymbol ****************************/
-
-ScopeDsymbol::ScopeDsymbol()
- : Dsymbol()
-{
- members = NULL;
- symtab = NULL;
- endlinnum = 0;
- importedScopes = NULL;
- prots = NULL;
-}
-
-ScopeDsymbol::ScopeDsymbol(Identifier *id)
- : Dsymbol(id)
-{
- members = NULL;
- symtab = NULL;
- endlinnum = 0;
- importedScopes = NULL;
- prots = NULL;
-}
-
-Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s)
-{
- //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
- ScopeDsymbol *sds = s ? (ScopeDsymbol *)s : new ScopeDsymbol(ident);
- sds->members = arraySyntaxCopy(members);
- sds->endlinnum = endlinnum;
- return sds;
-}
-
-/*****************************************
- * This function is #1 on the list of functions that eat cpu time.
- * Be very, very careful about slowing it down.
- */
-
-Dsymbol *ScopeDsymbol::search(const Loc &loc, Identifier *ident, int flags)
-{
- //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags);
- //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0;
-
- // Look in symbols declared in this module
- if (symtab && !(flags & SearchImportsOnly))
- {
- //printf(" look in locals\n");
- Dsymbol *s1 = symtab->lookup(ident);
- if (s1)
- {
- //printf("\tfound in locals = '%s.%s'\n",toChars(),s1->toChars());
- return s1;
- }
- }
- //printf(" not found in locals\n");
-
- // Look in imported scopes
- if (importedScopes)
- {
- //printf(" look in imports\n");
- Dsymbol *s = NULL;
- OverloadSet *a = NULL;
-
- // Look in imported modules
- for (size_t i = 0; i < importedScopes->length; i++)
- {
- // If private import, don't search it
- if ((flags & IgnorePrivateImports) && prots[i] == Prot::private_)
- continue;
-
- int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches
- Dsymbol *ss = (*importedScopes)[i];
-
- //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport());
-
- if (ss->isModule())
- {
- if (flags & SearchLocalsOnly)
- continue;
- }
- else // mixin template
- {
- if (flags & SearchImportsOnly)
- continue;
- sflags |= SearchLocalsOnly;
- }
-
- /* Don't find private members if ss is a module
- */
- Dsymbol *s2 = ss->search(loc, ident, sflags | (ss->isModule() ? IgnorePrivateImports : IgnoreNone));
- if (!s2 || (!(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2)))
- continue;
- if (!s)
- {
- s = s2;
- if (s && s->isOverloadSet())
- a = mergeOverloadSet(ident, a, s);
- }
- else if (s2 && s != s2)
- {
- if (s->toAlias() == s2->toAlias() ||
- (s->getType() == s2->getType() && s->getType()))
- {
- /* After following aliases, we found the same
- * symbol, so it's not an ambiguity. But if one
- * alias is deprecated or less accessible, prefer
- * the other.
- */
- if (s->isDeprecated() ||
- (s->prot().isMoreRestrictiveThan(s2->prot()) && s2->prot().kind != Prot::none))
- s = s2;
- }
- else
- {
- /* Two imports of the same module should be regarded as
- * the same.
- */
- Import *i1 = s->isImport();
- Import *i2 = s2->isImport();
- if (!(i1 && i2 &&
- (i1->mod == i2->mod ||
- (!i1->parent->isImport() && !i2->parent->isImport() &&
- i1->ident->equals(i2->ident))
- )
- )
- )
- {
- /* Bugzilla 8668:
- * Public selective import adds AliasDeclaration in module.
- * To make an overload set, resolve aliases in here and
- * get actual overload roots which accessible via s and s2.
- */
- s = s->toAlias();
- s2 = s2->toAlias();
-
- /* If both s2 and s are overloadable (though we only
- * need to check s once)
- */
- if ((s2->isOverloadSet() || s2->isOverloadable()) &&
- (a || s->isOverloadable()))
- {
- a = mergeOverloadSet(ident, a, s2);
- continue;
- }
- if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
- return NULL;
- if (!(flags & IgnoreErrors))
- ScopeDsymbol::multiplyDefined(loc, s, s2);
- break;
- }
- }
- }
- }
-
- if (s)
- {
- /* Build special symbol if we had multiple finds
- */
- if (a)
- {
- if (!s->isOverloadSet())
- a = mergeOverloadSet(ident, a, s);
- s = a;
- }
- //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
- return s;
- }
- //printf(" not found in imports\n");
- }
-
- return NULL;
-}
-
-OverloadSet *ScopeDsymbol::mergeOverloadSet(Identifier *ident, OverloadSet *os, Dsymbol *s)
-{
- if (!os)
- {
- os = new OverloadSet(ident);
- os->parent = this;
- }
- if (OverloadSet *os2 = s->isOverloadSet())
- {
- // Merge the cross-module overload set 'os2' into 'os'
- if (os->a.length == 0)
- {
- os->a.setDim(os2->a.length);
- memcpy(os->a.tdata(), os2->a.tdata(), sizeof(os->a[0]) * os2->a.length);
- }
- else
- {
- for (size_t i = 0; i < os2->a.length; i++)
- {
- os = mergeOverloadSet(ident, os, os2->a[i]);
- }
- }
- }
- else
- {
- assert(s->isOverloadable());
-
- /* Don't add to os[] if s is alias of previous sym
- */
- for (size_t j = 0; j < os->a.length; j++)
- {
- Dsymbol *s2 = os->a[j];
- if (s->toAlias() == s2->toAlias())
- {
- if (s2->isDeprecated() ||
- (s2->prot().isMoreRestrictiveThan(s->prot()) &&
- s->prot().kind != Prot::none))
- {
- os->a[j] = s;
- }
- goto Lcontinue;
- }
- }
- os->push(s);
- Lcontinue:
- ;
- }
- return os;
-}
-
-void ScopeDsymbol::importScope(Dsymbol *s, Prot protection)
-{
- //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection);
-
- // No circular or redundant import's
- if (s != this)
- {
- if (!importedScopes)
- importedScopes = new Dsymbols();
- else
- {
- for (size_t i = 0; i < importedScopes->length; i++)
- {
- Dsymbol *ss = (*importedScopes)[i];
- if (ss == s) // if already imported
- {
- if (protection.kind > prots[i])
- prots[i] = protection.kind; // upgrade access
- return;
- }
- }
- }
- importedScopes->push(s);
- prots = (Prot::Kind *)mem.xrealloc(prots, importedScopes->length * sizeof(prots[0]));
- prots[importedScopes->length - 1] = protection.kind;
- }
-}
-
-#define BITS_PER_INDEX (sizeof(size_t) * CHAR_BIT)
-
-static void bitArraySet(BitArray *array, size_t idx)
-{
- array->ptr[idx / BITS_PER_INDEX] |= 1ULL << (idx % BITS_PER_INDEX);
-}
-
-static bool bitArrayGet(BitArray *array, size_t idx)
-{
- const size_t boffset = idx % BITS_PER_INDEX;
- return (array->ptr[idx / BITS_PER_INDEX] & (1ULL << boffset)) >> boffset;
-}
-
-static void bitArrayLength(BitArray *array, size_t len)
-{
- if (array->len < len)
- {
- const size_t obytes = (array->len + BITS_PER_INDEX - 1) / BITS_PER_INDEX;
- const size_t nbytes = (len + BITS_PER_INDEX - 1) / BITS_PER_INDEX;
-
- if (!array->ptr)
- array->ptr = (size_t *)mem.xmalloc(nbytes * sizeof(size_t));
- else
- array->ptr = (size_t *)mem.xrealloc(array->ptr, nbytes * sizeof(size_t));
-
- for (size_t i = obytes; i < nbytes; i++)
- array->ptr[i] = 0;
-
- array->len = nbytes * BITS_PER_INDEX;
- }
-}
-
-void ScopeDsymbol::addAccessiblePackage(Package *p, Prot protection)
-{
- BitArray *pary = protection.kind == Prot::private_ ? &privateAccessiblePackages : &accessiblePackages;
- if (pary->len <= p->tag)
- bitArrayLength(pary, p->tag + 1);
- bitArraySet(pary, p->tag);
-}
-
-bool ScopeDsymbol::isPackageAccessible(Package *p, Prot protection, int)
-{
- if ((p->tag < accessiblePackages.len && bitArrayGet(&accessiblePackages, p->tag)) ||
- (protection.kind == Prot::private_ && p->tag < privateAccessiblePackages.len && bitArrayGet(&privateAccessiblePackages, p->tag)))
- return true;
- if (importedScopes)
- {
- for (size_t i = 0; i < importedScopes->length; i++)
- {
- // only search visible scopes && imported modules should ignore private imports
- Dsymbol *ss = (*importedScopes)[i];
- if (protection.kind <= prots[i] &&
- ss->isScopeDsymbol()->isPackageAccessible(p, protection, IgnorePrivateImports))
- return true;
- }
- }
- return false;
-}
-
-bool ScopeDsymbol::isforwardRef()
-{
- return (members == NULL);
-}
-
-void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2)
-{
- if (loc.filename)
- { ::error(loc, "%s at %s conflicts with %s at %s",
- s1->toPrettyChars(),
- s1->locToChars(),
- s2->toPrettyChars(),
- s2->locToChars());
- }
- else
- {
- s1->error(s1->loc, "conflicts with %s %s at %s",
- s2->kind(),
- s2->toPrettyChars(),
- s2->locToChars());
- }
-}
-
-const char *ScopeDsymbol::kind() const
-{
- return "ScopeDsymbol";
-}
-
-Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s)
-{
- return symtab->insert(s);
-}
-
-/****************************************
- * Look up identifier in symbol table.
- */
-
-Dsymbol *ScopeDsymbol::symtabLookup(Dsymbol *, Identifier *id)
-{
- return symtab->lookup(id);
-}
-
-/****************************************
- * Return true if any of the members are static ctors or static dtors, or if
- * any members have members that are.
- */
-
-bool ScopeDsymbol::hasStaticCtorOrDtor()
-{
- if (members)
- {
- for (size_t i = 0; i < members->length; i++)
- { Dsymbol *member = (*members)[i];
-
- if (member->hasStaticCtorOrDtor())
- return true;
- }
- }
- return false;
-}
-
-/***************************************
- * Determine number of Dsymbols, folding in AttribDeclaration members.
- */
-
-static int dimDg(void *ctx, size_t, Dsymbol *)
-{
- ++*(size_t *)ctx;
- return 0;
-}
-
-size_t ScopeDsymbol::dim(Dsymbols *members)
-{
- size_t n = 0;
- ScopeDsymbol_foreach(NULL, members, &dimDg, &n);
- return n;
-}
-
-/***************************************
- * Get nth Dsymbol, folding in AttribDeclaration members.
- * Returns:
- * Dsymbol* nth Dsymbol
- * NULL not found, *pn gets incremented by the number
- * of Dsymbols
- */
-
-struct GetNthSymbolCtx
-{
- size_t nth;
- Dsymbol *sym;
-};
-
-static int getNthSymbolDg(void *ctx, size_t n, Dsymbol *sym)
-{
- GetNthSymbolCtx *p = (GetNthSymbolCtx *)ctx;
- if (n == p->nth)
- { p->sym = sym;
- return 1;
- }
- return 0;
-}
-
-Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *)
-{
- GetNthSymbolCtx ctx = { nth, NULL };
- int res = ScopeDsymbol_foreach(NULL, members, &getNthSymbolDg, &ctx);
- return res ? ctx.sym : NULL;
-}
-
-/***************************************
- * Expands attribute declarations in members in depth first
- * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each
- * member.
- * If dg returns !=0, stops and returns that value else returns 0.
- * Use this function to avoid the O(N + N^2/2) complexity of
- * calculating dim and calling N times getNth.
- */
-
-int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn)
-{
- assert(dg);
- if (!members)
- return 0;
-
- size_t n = pn ? *pn : 0; // take over index
- int result = 0;
- for (size_t i = 0; i < members->length; i++)
- { Dsymbol *s = (*members)[i];
-
- if (AttribDeclaration *a = s->isAttribDeclaration())
- result = ScopeDsymbol_foreach(sc, a->include(sc), dg, ctx, &n);
- else if (TemplateMixin *tm = s->isTemplateMixin())
- result = ScopeDsymbol_foreach(sc, tm->members, dg, ctx, &n);
- else if (s->isTemplateInstance())
- ;
- else if (s->isUnitTestDeclaration())
- ;
- else
- result = dg(ctx, n++, s);
-
- if (result)
- break;
- }
-
- if (pn)
- *pn = n; // update index
- return result;
-}
-
-/*******************************************
- * Look for member of the form:
- * const(MemberInfo)[] getMembers(string);
- * Returns NULL if not found
- */
-
-FuncDeclaration *ScopeDsymbol::findGetMembers()
-{
- Dsymbol *s = search_function(this, Id::getmembers);
- FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL;
-
- if (fdx && fdx->isVirtual())
- fdx = NULL;
-
- return fdx;
-}
-
-
-/****************************** WithScopeSymbol ******************************/
-
-WithScopeSymbol::WithScopeSymbol(WithStatement *withstate)
- : ScopeDsymbol()
-{
- this->withstate = withstate;
-}
-
-Dsymbol *WithScopeSymbol::search(const Loc &loc, Identifier *ident, int flags)
-{
- //printf("WithScopeSymbol::search(%s)\n", ident->toChars());
- if (flags & SearchImportsOnly)
- return NULL;
-
- // Acts as proxy to the with class declaration
- Dsymbol *s = NULL;
- Expression *eold = NULL;
- for (Expression *e = withstate->exp; e != eold; e = resolveAliasThis(_scope, e))
- {
- if (e->op == TOKscope)
- {
- s = ((ScopeExp *)e)->sds;
- }
- else if (e->op == TOKtype)
- {
- s = e->type->toDsymbol(NULL);
- }
- else
- {
- Type *t = e->type->toBasetype();
- s = t->toDsymbol(NULL);
- }
- if (s)
- {
- s = s->search(loc, ident, flags);
- if (s)
- return s;
- }
- eold = e;
- }
- return NULL;
-}
-
-/****************************** ArrayScopeSymbol ******************************/
-
-ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e)
- : ScopeDsymbol()
-{
- assert(e->op == TOKindex || e->op == TOKslice || e->op == TOKarray);
- exp = e;
- type = NULL;
- td = NULL;
- this->sc = sc;
-}
-
-ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t)
- : ScopeDsymbol()
-{
- exp = NULL;
- type = t;
- td = NULL;
- this->sc = sc;
-}
-
-ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s)
- : ScopeDsymbol()
-{
- exp = NULL;
- type = NULL;
- td = s;
- this->sc = sc;
-}
-
-Dsymbol *ArrayScopeSymbol::search(const Loc &loc, Identifier *ident, int)
-{
- //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags);
- if (ident == Id::dollar)
- {
- VarDeclaration **pvar;
- Expression *ce;
-
- L1:
- if (td)
- {
- /* $ gives the number of elements in the tuple
- */
- VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
- Expression *e = new IntegerExp(Loc(), td->objects->length, Type::tsize_t);
- v->_init = new ExpInitializer(Loc(), e);
- v->storage_class |= STCtemp | STCstatic | STCconst;
- dsymbolSemantic(v, sc);
- return v;
- }
-
- if (type)
- {
- /* $ gives the number of type entries in the type tuple
- */
- VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL);
- Expression *e = new IntegerExp(Loc(), type->arguments->length, Type::tsize_t);
- v->_init = new ExpInitializer(Loc(), e);
- v->storage_class |= STCtemp | STCstatic | STCconst;
- dsymbolSemantic(v, sc);
- return v;
- }
-
- if (exp->op == TOKindex)
- {
- /* array[index] where index is some function of $
- */
- IndexExp *ie = (IndexExp *)exp;
- pvar = &ie->lengthVar;
- ce = ie->e1;
- }
- else if (exp->op == TOKslice)
- {
- /* array[lwr .. upr] where lwr or upr is some function of $
- */
- SliceExp *se = (SliceExp *)exp;
- pvar = &se->lengthVar;
- ce = se->e1;
- }
- else if (exp->op == TOKarray)
- {
- /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
- * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
- */
- ArrayExp *ae = (ArrayExp *)exp;
- pvar = &ae->lengthVar;
- ce = ae->e1;
- }
- else
- {
- /* Didn't find $, look in enclosing scope(s).
- */
- return NULL;
- }
-
- while (ce->op == TOKcomma)
- ce = ((CommaExp *)ce)->e2;
-
- /* If we are indexing into an array that is really a type
- * tuple, rewrite this as an index into a type tuple and
- * try again.
- */
- if (ce->op == TOKtype)
- {
- Type *t = ((TypeExp *)ce)->type;
- if (t->ty == Ttuple)
- {
- type = (TypeTuple *)t;
- goto L1;
- }
- }
-
- /* *pvar is lazily initialized, so if we refer to $
- * multiple times, it gets set only once.
- */
- if (!*pvar) // if not already initialized
- {
- /* Create variable v and set it to the value of $
- */
- VarDeclaration *v;
- Type *t;
- if (ce->op == TOKtuple)
- {
- /* It is for an expression tuple, so the
- * length will be a const.
- */
- Expression *e = new IntegerExp(Loc(), ((TupleExp *)ce)->exps->length, Type::tsize_t);
- v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, new ExpInitializer(Loc(), e));
- v->storage_class |= STCtemp | STCstatic | STCconst;
- }
- else if (ce->type && (t = ce->type->toBasetype()) != NULL &&
- (t->ty == Tstruct || t->ty == Tclass))
- {
- // Look for opDollar
- assert(exp->op == TOKarray || exp->op == TOKslice);
- AggregateDeclaration *ad = isAggregate(t);
- assert(ad);
-
- Dsymbol *s = ad->search(loc, Id::opDollar);
- if (!s) // no dollar exists -- search in higher scope
- return NULL;
- s = s->toAlias();
-
- Expression *e = NULL;
- // Check for multi-dimensional opDollar(dim) template.
- if (TemplateDeclaration *td = s->isTemplateDeclaration())
- {
- dinteger_t dim = 0;
- if (exp->op == TOKarray)
- {
- dim = ((ArrayExp *)exp)->currentDimension;
- }
- else if (exp->op == TOKslice)
- {
- dim = 0; // slices are currently always one-dimensional
- }
- else
- {
- assert(0);
- }
-
- Objects *tiargs = new Objects();
- Expression *edim = new IntegerExp(Loc(), dim, Type::tsize_t);
- edim = expressionSemantic(edim, sc);
- tiargs->push(edim);
- e = new DotTemplateInstanceExp(loc, ce, td->ident, tiargs);
- }
- else
- {
- /* opDollar exists, but it's not a template.
- * This is acceptable ONLY for single-dimension indexing.
- * Note that it's impossible to have both template & function opDollar,
- * because both take no arguments.
- */
- if (exp->op == TOKarray && ((ArrayExp *)exp)->arguments->length != 1)
- {
- exp->error("%s only defines opDollar for one dimension", ad->toChars());
- return NULL;
- }
- Declaration *d = s->isDeclaration();
- assert(d);
- e = new DotVarExp(loc, ce, d);
- }
- e = expressionSemantic(e, sc);
- if (!e->type)
- exp->error("%s has no value", e->toChars());
- t = e->type->toBasetype();
- if (t && t->ty == Tfunction)
- e = new CallExp(e->loc, e);
- v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(Loc(), e));
- v->storage_class |= STCtemp | STCctfe | STCrvalue;
- }
- else
- {
- /* For arrays, $ will either be a compile-time constant
- * (in which case its value in set during constant-folding),
- * or a variable (in which case an expression is created in
- * toir.c).
- */
- VoidInitializer *e = new VoidInitializer(Loc());
- e->type = Type::tsize_t;
- v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, e);
- v->storage_class |= STCtemp | STCctfe; // it's never a true static variable
- }
- *pvar = v;
- }
- dsymbolSemantic(*pvar, sc);
- return (*pvar);
- }
- return NULL;
-}
-
-
-/****************************** DsymbolTable ******************************/
-
-DsymbolTable::DsymbolTable()
-{
- tab = NULL;
-}
-
-Dsymbol *DsymbolTable::lookup(Identifier const * const ident)
-{
- //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string);
- return (Dsymbol *)dmd_aaGetRvalue(tab, const_cast<void *>((const void *)ident));
-}
-
-Dsymbol *DsymbolTable::insert(Dsymbol *s)
-{
- //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars());
- Identifier *ident = s->ident;
- Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, (void *)ident);
- if (*ps)
- return NULL; // already in table
- *ps = s;
- return s;
-}
-
-Dsymbol *DsymbolTable::insert(Identifier const * const ident, Dsymbol *s)
-{
- //printf("DsymbolTable::insert()\n");
- Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, const_cast<void *>((const void *)ident));
- if (*ps)
- return NULL; // already in table
- *ps = s;
- return s;
-}
-
-Dsymbol *DsymbolTable::update(Dsymbol *s)
-{
- Identifier *ident = s->ident;
- Dsymbol **ps = (Dsymbol **)dmd_aaGet(&tab, (void *)ident);
- *ps = s;
- return s;
-}
-
-/****************************** Prot ******************************/
-
-Prot::Prot()
-{
- this->kind = Prot::undefined;
- this->pkg = NULL;
-}
-
-Prot::Prot(Prot::Kind kind)
-{
- this->kind = kind;
- this->pkg = NULL;
-}
-
-/**
- * Checks if `this` is superset of `other` restrictions.
- * For example, "protected" is more restrictive than "public".
- */
-bool Prot::isMoreRestrictiveThan(const Prot other) const
-{
- return this->kind < other.kind;
-}
-
-/**
- * Checks if `this` is absolutely identical protection attribute to `other`
- */
-bool Prot::operator==(const Prot& other) const
-{
- if (this->kind == other.kind)
- {
- if (this->kind == Prot::package_)
- return this->pkg == other.pkg;
- return true;
- }
- return false;
-}
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
new file mode 100644
index 0000000..3a6dff2
--- /dev/null
+++ b/gcc/d/dmd/dsymbol.d
@@ -0,0 +1,2386 @@
+/**
+ * The base class for a D symbol, which can be a module, variable, function, enum, etc.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbol.d, _dsymbol.d)
+ * Documentation: https://dlang.org/phobos/dmd_dsymbol.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dsymbol.d
+ */
+
+module dmd.dsymbol;
+
+import core.stdc.stdarg;
+import core.stdc.stdio;
+import core.stdc.string;
+import core.stdc.stdlib;
+
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arraytypes;
+import dmd.attrib;
+import dmd.astenums;
+import dmd.ast_node;
+import dmd.gluelayer;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dimport;
+import dmd.dmodule;
+import dmd.dversion;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.lexer;
+import dmd.mtype;
+import dmd.nspace;
+import dmd.opover;
+import dmd.root.aav;
+import dmd.root.rmem;
+import dmd.root.rootobject;
+import dmd.root.speller;
+import dmd.root.string;
+import dmd.statement;
+import dmd.tokens;
+import dmd.visitor;
+
+/***************************************
+ * Calls dg(Dsymbol *sym) for each Dsymbol.
+ * If dg returns !=0, stops and returns that value else returns 0.
+ * Params:
+ * symbols = Dsymbols
+ * dg = delegate to call for each Dsymbol
+ * Returns:
+ * last value returned by dg()
+ *
+ * See_Also: $(REF each, dmd, root, array)
+ */
+int foreachDsymbol(Dsymbols* symbols, scope int delegate(Dsymbol) dg)
+{
+ assert(dg);
+ if (symbols)
+ {
+ /* Do not use foreach, as the size of the array may expand during iteration
+ */
+ for (size_t i = 0; i < symbols.dim; ++i)
+ {
+ Dsymbol s = (*symbols)[i];
+ const result = dg(s);
+ if (result)
+ return result;
+ }
+ }
+ return 0;
+}
+
+/***************************************
+ * Calls dg(Dsymbol *sym) for each Dsymbol.
+ * Params:
+ * symbols = Dsymbols
+ * dg = delegate to call for each Dsymbol
+ *
+ * See_Also: $(REF each, dmd, root, array)
+ */
+void foreachDsymbol(Dsymbols* symbols, scope void delegate(Dsymbol) dg)
+{
+ assert(dg);
+ if (symbols)
+ {
+ /* Do not use foreach, as the size of the array may expand during iteration
+ */
+ for (size_t i = 0; i < symbols.dim; ++i)
+ {
+ Dsymbol s = (*symbols)[i];
+ dg(s);
+ }
+ }
+}
+
+
+struct Ungag
+{
+ uint oldgag;
+
+ extern (D) this(uint old)
+ {
+ this.oldgag = old;
+ }
+
+ extern (C++) ~this()
+ {
+ global.gag = oldgag;
+ }
+}
+
+struct Visibility
+{
+ ///
+ enum Kind : ubyte
+ {
+ undefined,
+ none, // no access
+ private_,
+ package_,
+ protected_,
+ public_,
+ export_,
+ }
+
+ Kind kind;
+ Package pkg;
+
+ extern (D):
+
+ this(Visibility.Kind kind) pure nothrow @nogc @safe
+ {
+ this.kind = kind;
+ }
+
+ /**
+ * Checks if `this` is less or more visible than `other`
+ *
+ * Params:
+ * other = Visibility to compare `this` to.
+ *
+ * Returns:
+ * A value `< 0` if `this` is less visible than `other`,
+ * a value `> 0` if `this` is more visible than `other`,
+ * and `0` if they are at the same level.
+ * Note that `package` visibility with different packages
+ * will also return `0`.
+ */
+ int opCmp(const Visibility other) const pure nothrow @nogc @safe
+ {
+ return this.kind - other.kind;
+ }
+
+ ///
+ unittest
+ {
+ assert(Visibility(Visibility.Kind.public_) > Visibility(Visibility.Kind.private_));
+ assert(Visibility(Visibility.Kind.private_) < Visibility(Visibility.Kind.protected_));
+ assert(Visibility(Visibility.Kind.package_) >= Visibility(Visibility.Kind.package_));
+ }
+
+ /**
+ * Checks if `this` is absolutely identical visibility attribute to `other`
+ */
+ bool opEquals(ref const Visibility other) const
+ {
+ if (this.kind == other.kind)
+ {
+ if (this.kind == Visibility.Kind.package_)
+ return this.pkg == other.pkg;
+ return true;
+ }
+ return false;
+ }
+}
+
+enum PASS : int
+{
+ init, // initial state
+ semantic, // semantic() started
+ semanticdone, // semantic() done
+ semantic2, // semantic2() started
+ semantic2done, // semantic2() done
+ semantic3, // semantic3() started
+ semantic3done, // semantic3() done
+ inline, // inline started
+ inlinedone, // inline done
+ obj, // toObjFile() run
+}
+
+// Search options
+enum : int
+{
+ IgnoreNone = 0x00, // default
+ IgnorePrivateImports = 0x01, // don't search private imports
+ IgnoreErrors = 0x02, // don't give error messages
+ IgnoreAmbiguous = 0x04, // return NULL if ambiguous
+ SearchLocalsOnly = 0x08, // only look at locals (don't search imports)
+ SearchImportsOnly = 0x10, // only look in imports
+ SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
+ // meaning don't search imports in that scope,
+ // because qualified module searches search
+ // their imports
+ IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols
+ TagNameSpace = 0x100, // search ImportC tag symbol table
+}
+
+/***********************************************************
+ * Struct/Class/Union field state.
+ * Used for transitory information when setting field offsets, such
+ * as bit fields.
+ */
+struct FieldState
+{
+ uint offset; /// offset for next field
+
+ uint fieldOffset; /// offset for the start of the bit field
+ uint bitOffset; /// bit offset for field
+ uint fieldSize; /// size of field in bytes
+ bool inFlight; /// bit field is in flight
+}
+
+/***********************************************************
+ */
+extern (C++) class Dsymbol : ASTNode
+{
+ Identifier ident;
+ Dsymbol parent;
+ /// C++ namespace this symbol belongs to
+ CPPNamespaceDeclaration cppnamespace;
+ Symbol* csym; // symbol for code generator
+ Symbol* isym; // import version of csym
+ const(char)* comment; // documentation comment for this Dsymbol
+ const Loc loc; // where defined
+ Scope* _scope; // !=null means context to use for semantic()
+ const(char)* prettystring; // cached value of toPrettyChars()
+ bool errors; // this symbol failed to pass semantic()
+ PASS semanticRun = PASS.init;
+ ushort localNum; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
+
+ DeprecatedDeclaration depdecl; // customized deprecation message
+ UserAttributeDeclaration userAttribDecl; // user defined attributes
+
+ // !=null means there's a ddoc unittest associated with this symbol
+ // (only use this with ddoc)
+ UnitTestDeclaration ddocUnittest;
+
+ final extern (D) this()
+ {
+ //printf("Dsymbol::Dsymbol(%p)\n", this);
+ loc = Loc(null, 0, 0);
+ }
+
+ final extern (D) this(Identifier ident)
+ {
+ //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
+ this.loc = Loc(null, 0, 0);
+ this.ident = ident;
+ }
+
+ final extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
+ this.loc = loc;
+ this.ident = ident;
+ }
+
+ static Dsymbol create(Identifier ident)
+ {
+ return new Dsymbol(ident);
+ }
+
+ override const(char)* toChars() const
+ {
+ return ident ? ident.toChars() : "__anonymous";
+ }
+
+ // helper to print fully qualified (template) arguments
+ const(char)* toPrettyCharsHelper()
+ {
+ return toChars();
+ }
+
+ final const(Loc) getLoc()
+ {
+ if (!loc.isValid()) // avoid bug 5861.
+ if (const m = getModule())
+ return Loc(m.srcfile.toChars(), 0, 0);
+ return loc;
+ }
+
+ final const(char)* locToChars()
+ {
+ return getLoc().toChars();
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+ if (o.dyncast() != DYNCAST.dsymbol)
+ return false;
+ auto s = cast(Dsymbol)o;
+ // Overload sets don't have an ident
+ // Function-local declarations may have identical names
+ // if they are declared in different scopes
+ if (s && ident && s.ident && ident.equals(s.ident) && localNum == s.localNum)
+ return true;
+ return false;
+ }
+
+ final bool isAnonymous() const
+ {
+ return ident is null || ident.isAnonymous;
+ }
+
+ extern(D) private const(char)[] prettyFormatHelper()
+ {
+ const cstr = toPrettyChars();
+ return '`' ~ cstr.toDString() ~ "`\0";
+ }
+
+ static if (__VERSION__ < 2092)
+ {
+ final void error(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
+ va_end(ap);
+ }
+
+ final void error(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ const loc = getLoc();
+ .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
+ va_end(ap);
+ }
+
+ final void deprecation(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
+ va_end(ap);
+ }
+
+ final void deprecation(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ const loc = getLoc();
+ .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
+ va_end(ap);
+ }
+ }
+ else
+ {
+ pragma(printf) final void error(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
+ va_end(ap);
+ }
+
+ pragma(printf) final void error(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ const loc = getLoc();
+ .verror(loc, format, ap, kind(), prettyFormatHelper().ptr);
+ va_end(ap);
+ }
+
+ pragma(printf) final void deprecation(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
+ va_end(ap);
+ }
+
+ pragma(printf) final void deprecation(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ const loc = getLoc();
+ .vdeprecation(loc, format, ap, kind(), prettyFormatHelper().ptr);
+ va_end(ap);
+ }
+ }
+
+ final bool checkDeprecated(const ref Loc loc, Scope* sc)
+ {
+ if (global.params.useDeprecated == DiagnosticReporting.off)
+ return false;
+ if (!this.isDeprecated())
+ return false;
+ // Don't complain if we're inside a deprecated symbol's scope
+ if (sc.isDeprecated())
+ return false;
+ // Don't complain if we're inside a template constraint
+ // https://issues.dlang.org/show_bug.cgi?id=21831
+ if (sc.flags & SCOPE.constraint)
+ return false;
+
+ const(char)* message = null;
+ for (Dsymbol p = this; p; p = p.parent)
+ {
+ message = p.depdecl ? p.depdecl.getMessage() : null;
+ if (message)
+ break;
+ }
+ if (message)
+ deprecation(loc, "is deprecated - %s", message);
+ else
+ deprecation(loc, "is deprecated");
+
+ if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
+ ti.printInstantiationTrace(Classification.deprecation);
+ else if (auto ti = sc.parent ? sc.parent.isTemplateInstance() : null)
+ ti.printInstantiationTrace(Classification.deprecation);
+
+ return true;
+ }
+
+ /**********************************
+ * Determine which Module a Dsymbol is in.
+ */
+ final Module getModule()
+ {
+ //printf("Dsymbol::getModule()\n");
+ if (TemplateInstance ti = isInstantiated())
+ return ti.tempdecl.getModule();
+ Dsymbol s = this;
+ while (s)
+ {
+ //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
+ Module m = s.isModule();
+ if (m)
+ return m;
+ s = s.parent;
+ }
+ return null;
+ }
+
+ /**********************************
+ * Determine which Module a Dsymbol is in, as far as access rights go.
+ */
+ final Module getAccessModule()
+ {
+ //printf("Dsymbol::getAccessModule()\n");
+ if (TemplateInstance ti = isInstantiated())
+ return ti.tempdecl.getAccessModule();
+ Dsymbol s = this;
+ while (s)
+ {
+ //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
+ Module m = s.isModule();
+ if (m)
+ return m;
+ TemplateInstance ti = s.isTemplateInstance();
+ if (ti && ti.enclosing)
+ {
+ /* Because of local template instantiation, the parent isn't where the access
+ * rights come from - it's the template declaration
+ */
+ s = ti.tempdecl;
+ }
+ else
+ s = s.parent;
+ }
+ return null;
+ }
+
+ /**
+ * `pastMixin` returns the enclosing symbol if this is a template mixin.
+ *
+ * `pastMixinAndNspace` does likewise, additionally skipping over Nspaces that
+ * are mangleOnly.
+ *
+ * See also `parent`, `toParent` and `toParent2`.
+ */
+ final inout(Dsymbol) pastMixin() inout
+ {
+ //printf("Dsymbol::pastMixin() %s\n", toChars());
+ if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
+ return this;
+ if (!parent)
+ return null;
+ return parent.pastMixin();
+ }
+
+ /**********************************
+ * `parent` field returns a lexically enclosing scope symbol this is a member of.
+ *
+ * `toParent()` returns a logically enclosing scope symbol this is a member of.
+ * It skips over TemplateMixin's.
+ *
+ * `toParent2()` returns an enclosing scope symbol this is living at runtime.
+ * It skips over both TemplateInstance's and TemplateMixin's.
+ * It's used when looking for the 'this' pointer of the enclosing function/class.
+ *
+ * `toParentDecl()` similar to `toParent2()` but always follows the template declaration scope
+ * instead of the instantiation scope.
+ *
+ * `toParentLocal()` similar to `toParentDecl()` but follows the instantiation scope
+ * if a template declaration is non-local i.e. global or static.
+ *
+ * Examples:
+ * ---
+ * module mod;
+ * template Foo(alias a) { mixin Bar!(); }
+ * mixin template Bar() {
+ * public { // VisibilityDeclaration
+ * void baz() { a = 2; }
+ * }
+ * }
+ * void test() {
+ * int v = 1;
+ * alias foo = Foo!(v);
+ * foo.baz();
+ * assert(v == 2);
+ * }
+ *
+ * // s == FuncDeclaration('mod.test.Foo!().Bar!().baz()')
+ * // s.parent == TemplateMixin('mod.test.Foo!().Bar!()')
+ * // s.toParent() == TemplateInstance('mod.test.Foo!()')
+ * // s.toParent2() == FuncDeclaration('mod.test')
+ * // s.toParentDecl() == Module('mod')
+ * // s.toParentLocal() == FuncDeclaration('mod.test')
+ * ---
+ */
+ final inout(Dsymbol) toParent() inout
+ {
+ return parent ? parent.pastMixin() : null;
+ }
+
+ /// ditto
+ final inout(Dsymbol) toParent2() inout
+ {
+ if (!parent || !parent.isTemplateInstance && !parent.isForwardingAttribDeclaration() && !parent.isForwardingScopeDsymbol())
+ return parent;
+ return parent.toParent2;
+ }
+
+ /// ditto
+ final inout(Dsymbol) toParentDecl() inout
+ {
+ return toParentDeclImpl(false);
+ }
+
+ /// ditto
+ final inout(Dsymbol) toParentLocal() inout
+ {
+ return toParentDeclImpl(true);
+ }
+
+ private inout(Dsymbol) toParentDeclImpl(bool localOnly) inout
+ {
+ auto p = toParent();
+ if (!p || !p.isTemplateInstance())
+ return p;
+ auto ti = p.isTemplateInstance();
+ if (ti.tempdecl && (!localOnly || !(cast(TemplateDeclaration)ti.tempdecl).isstatic))
+ return ti.tempdecl.toParentDeclImpl(localOnly);
+ return parent.toParentDeclImpl(localOnly);
+ }
+
+ /**
+ * Returns the declaration scope scope of `this` unless any of the symbols
+ * `p1` or `p2` resides in its enclosing instantiation scope then the
+ * latter is returned.
+ */
+ final Dsymbol toParentP(Dsymbol p1, Dsymbol p2 = null)
+ {
+ return followInstantiationContext(p1, p2) ? toParent2() : toParentLocal();
+ }
+
+ final inout(TemplateInstance) isInstantiated() inout
+ {
+ if (!parent)
+ return null;
+ auto ti = parent.isTemplateInstance();
+ if (ti && !ti.isTemplateMixin())
+ return ti;
+ return parent.isInstantiated();
+ }
+
+ /***
+ * Returns true if any of the symbols `p1` or `p2` resides in the enclosing
+ * instantiation scope of `this`.
+ */
+ final bool followInstantiationContext(Dsymbol p1, Dsymbol p2 = null)
+ {
+ static bool has2This(Dsymbol s)
+ {
+ if (auto f = s.isFuncDeclaration())
+ return f.isThis2;
+ if (auto ad = s.isAggregateDeclaration())
+ return ad.vthis2 !is null;
+ return false;
+ }
+
+ if (has2This(this))
+ {
+ assert(p1);
+ auto outer = toParent();
+ while (outer)
+ {
+ auto ti = outer.isTemplateInstance();
+ if (!ti)
+ break;
+ foreach (oarg; *ti.tiargs)
+ {
+ auto sa = getDsymbol(oarg);
+ if (!sa)
+ continue;
+ sa = sa.toAlias().toParent2();
+ if (!sa)
+ continue;
+ if (sa == p1)
+ return true;
+ else if (p2 && sa == p2)
+ return true;
+ }
+ outer = ti.tempdecl.toParent();
+ }
+ return false;
+ }
+ return false;
+ }
+
+ // Check if this function is a member of a template which has only been
+ // instantiated speculatively, eg from inside is(typeof()).
+ // Return the speculative template instance it is part of,
+ // or NULL if not speculative.
+ final inout(TemplateInstance) isSpeculative() inout
+ {
+ if (!parent)
+ return null;
+ auto ti = parent.isTemplateInstance();
+ if (ti && ti.gagged)
+ return ti;
+ if (!parent.toParent())
+ return null;
+ return parent.isSpeculative();
+ }
+
+ final Ungag ungagSpeculative() const
+ {
+ uint oldgag = global.gag;
+ if (global.gag && !isSpeculative() && !toParent2().isFuncDeclaration())
+ global.gag = 0;
+ return Ungag(oldgag);
+ }
+
+ // kludge for template.isSymbol()
+ override final DYNCAST dyncast() const
+ {
+ return DYNCAST.dsymbol;
+ }
+
+ /*************************************
+ * Do syntax copy of an array of Dsymbol's.
+ */
+ extern (D) static Dsymbols* arraySyntaxCopy(Dsymbols* a)
+ {
+ Dsymbols* b = null;
+ if (a)
+ {
+ b = a.copy();
+ for (size_t i = 0; i < b.dim; i++)
+ {
+ (*b)[i] = (*b)[i].syntaxCopy(null);
+ }
+ }
+ return b;
+ }
+
+ Identifier getIdent()
+ {
+ return ident;
+ }
+
+ const(char)* toPrettyChars(bool QualifyTypes = false)
+ {
+ if (prettystring && !QualifyTypes)
+ return prettystring;
+
+ //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
+ if (!parent)
+ {
+ auto s = toChars();
+ if (!QualifyTypes)
+ prettystring = s;
+ return s;
+ }
+
+ // Computer number of components
+ size_t complength = 0;
+ for (Dsymbol p = this; p; p = p.parent)
+ ++complength;
+
+ // Allocate temporary array comp[]
+ alias T = const(char)[];
+ auto compptr = cast(T*)Mem.check(malloc(complength * T.sizeof));
+ auto comp = compptr[0 .. complength];
+
+ // Fill in comp[] and compute length of final result
+ size_t length = 0;
+ int i;
+ for (Dsymbol p = this; p; p = p.parent)
+ {
+ const s = QualifyTypes ? p.toPrettyCharsHelper() : p.toChars();
+ const len = strlen(s);
+ comp[i] = s[0 .. len];
+ ++i;
+ length += len + 1;
+ }
+
+ auto s = cast(char*)mem.xmalloc_noscan(length);
+ auto q = s + length - 1;
+ *q = 0;
+ foreach (j; 0 .. complength)
+ {
+ const t = comp[j].ptr;
+ const len = comp[j].length;
+ q -= len;
+ memcpy(q, t, len);
+ if (q == s)
+ break;
+ *--q = '.';
+ }
+ free(comp.ptr);
+ if (!QualifyTypes)
+ prettystring = s;
+ return s;
+ }
+
+ const(char)* kind() const pure nothrow @nogc @safe
+ {
+ return "symbol";
+ }
+
+ /*********************************
+ * If this symbol is really an alias for another,
+ * return that other.
+ * If needed, semantic() is invoked due to resolve forward reference.
+ */
+ Dsymbol toAlias()
+ {
+ return this;
+ }
+
+ /*********************************
+ * Resolve recursive tuple expansion in eponymous template.
+ */
+ Dsymbol toAlias2()
+ {
+ return toAlias();
+ }
+
+ void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ //printf("Dsymbol::addMember('%s')\n", toChars());
+ //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars());
+ //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab);
+ parent = sds;
+ if (isAnonymous()) // no name, so can't add it to symbol table
+ return;
+
+ if (!sds.symtabInsert(this)) // if name is already defined
+ {
+ if (isAliasDeclaration() && !_scope)
+ setScope(sc);
+ Dsymbol s2 = sds.symtabLookup(this,ident);
+
+ // If using C tag/prototype/forward declaration rules
+ if (sc.flags & SCOPE.Cfile &&
+ handleTagSymbols(*sc, this, s2, sds))
+ return;
+
+ if (!s2.overloadInsert(this))
+ {
+ sds.multiplyDefined(Loc.initial, this, s2);
+ errors = true;
+ }
+ }
+ if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
+ {
+ if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
+ {
+ error("`.%s` property cannot be redefined", ident.toChars());
+ errors = true;
+ }
+ }
+ }
+
+ /*************************************
+ * Set scope for future semantic analysis so we can
+ * deal better with forward references.
+ */
+ void setScope(Scope* sc)
+ {
+ //printf("Dsymbol::setScope() %p %s, %p stc = %llx\n", this, toChars(), sc, sc.stc);
+ if (!sc.nofree)
+ sc.setNoFree(); // may need it even after semantic() finishes
+ _scope = sc;
+ if (sc.depdecl)
+ depdecl = sc.depdecl;
+ if (!userAttribDecl)
+ userAttribDecl = sc.userAttribDecl;
+ }
+
+ void importAll(Scope* sc)
+ {
+ }
+
+ /*********************************************
+ * Search for ident as member of s.
+ * Params:
+ * loc = location to print for error messages
+ * ident = identifier to search for
+ * flags = IgnoreXXXX
+ * Returns:
+ * null if not found
+ */
+ Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
+ {
+ //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
+ return null;
+ }
+
+ extern (D) final Dsymbol search_correct(Identifier ident)
+ {
+ /***************************************************
+ * Search for symbol with correct spelling.
+ */
+ extern (D) Dsymbol symbol_search_fp(const(char)[] seed, out int cost)
+ {
+ /* If not in the lexer's string table, it certainly isn't in the symbol table.
+ * Doing this first is a lot faster.
+ */
+ if (!seed.length)
+ return null;
+ Identifier id = Identifier.lookup(seed);
+ if (!id)
+ return null;
+ cost = 0; // all the same cost
+ Dsymbol s = this;
+ Module.clearCache();
+ return s.search(Loc.initial, id, IgnoreErrors);
+ }
+
+ if (global.gag)
+ return null; // don't do it for speculative compiles; too time consuming
+ // search for exact name first
+ if (auto s = search(Loc.initial, ident, IgnoreErrors))
+ return s;
+ return speller!symbol_search_fp(ident.toString());
+ }
+
+ /***************************************
+ * Search for identifier id as a member of `this`.
+ * `id` may be a template instance.
+ *
+ * Params:
+ * loc = location to print the error messages
+ * sc = the scope where the symbol is located
+ * id = the id of the symbol
+ * flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
+ *
+ * Returns:
+ * symbol found, NULL if not
+ */
+ extern (D) final Dsymbol searchX(const ref Loc loc, Scope* sc, RootObject id, int flags)
+ {
+ //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
+ Dsymbol s = toAlias();
+ Dsymbol sm;
+ if (Declaration d = s.isDeclaration())
+ {
+ if (d.inuse)
+ {
+ .error(loc, "circular reference to `%s`", d.toPrettyChars());
+ return null;
+ }
+ }
+ switch (id.dyncast())
+ {
+ case DYNCAST.identifier:
+ sm = s.search(loc, cast(Identifier)id, flags);
+ break;
+ case DYNCAST.dsymbol:
+ {
+ // It's a template instance
+ //printf("\ttemplate instance id\n");
+ Dsymbol st = cast(Dsymbol)id;
+ TemplateInstance ti = st.isTemplateInstance();
+ sm = s.search(loc, ti.name);
+ if (!sm)
+ {
+ sm = s.search_correct(ti.name);
+ if (sm)
+ .error(loc, "template identifier `%s` is not a member of %s `%s`, did you mean %s `%s`?", ti.name.toChars(), s.kind(), s.toPrettyChars(), sm.kind(), sm.toChars());
+ else
+ .error(loc, "template identifier `%s` is not a member of %s `%s`", ti.name.toChars(), s.kind(), s.toPrettyChars());
+ return null;
+ }
+ sm = sm.toAlias();
+ TemplateDeclaration td = sm.isTemplateDeclaration();
+ if (!td)
+ {
+ .error(loc, "`%s.%s` is not a template, it is a %s", s.toPrettyChars(), ti.name.toChars(), sm.kind());
+ return null;
+ }
+ ti.tempdecl = td;
+ if (!ti.semanticRun)
+ ti.dsymbolSemantic(sc);
+ sm = ti.toAlias();
+ break;
+ }
+ case DYNCAST.type:
+ case DYNCAST.expression:
+ default:
+ assert(0);
+ }
+ return sm;
+ }
+
+ bool overloadInsert(Dsymbol s)
+ {
+ //printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
+ return false;
+ }
+
+ /*********************************
+ * Returns:
+ * SIZE_INVALID when the size cannot be determined
+ */
+ d_uns64 size(const ref Loc loc)
+ {
+ error("Dsymbol `%s` has no size", toChars());
+ return SIZE_INVALID;
+ }
+
+ bool isforwardRef()
+ {
+ return false;
+ }
+
+ // is a 'this' required to access the member
+ inout(AggregateDeclaration) isThis() inout
+ {
+ return null;
+ }
+
+ // is Dsymbol exported?
+ bool isExport() const
+ {
+ return false;
+ }
+
+ // is Dsymbol imported?
+ bool isImportedSymbol() const
+ {
+ return false;
+ }
+
+ // is Dsymbol deprecated?
+ bool isDeprecated() @safe @nogc pure nothrow const
+ {
+ return false;
+ }
+
+ bool isOverloadable() const
+ {
+ return false;
+ }
+
+ // is this a LabelDsymbol()?
+ LabelDsymbol isLabel()
+ {
+ return null;
+ }
+
+ /// Returns an AggregateDeclaration when toParent() is that.
+ final inout(AggregateDeclaration) isMember() inout
+ {
+ //printf("Dsymbol::isMember() %s\n", toChars());
+ auto p = toParent();
+ //printf("parent is %s %s\n", p.kind(), p.toChars());
+ return p ? p.isAggregateDeclaration() : null;
+ }
+
+ /// Returns an AggregateDeclaration when toParent2() is that.
+ final inout(AggregateDeclaration) isMember2() inout
+ {
+ //printf("Dsymbol::isMember2() '%s'\n", toChars());
+ auto p = toParent2();
+ //printf("parent is %s %s\n", p.kind(), p.toChars());
+ return p ? p.isAggregateDeclaration() : null;
+ }
+
+ /// Returns an AggregateDeclaration when toParentDecl() is that.
+ final inout(AggregateDeclaration) isMemberDecl() inout
+ {
+ //printf("Dsymbol::isMemberDecl() '%s'\n", toChars());
+ auto p = toParentDecl();
+ //printf("parent is %s %s\n", p.kind(), p.toChars());
+ return p ? p.isAggregateDeclaration() : null;
+ }
+
+ /// Returns an AggregateDeclaration when toParentLocal() is that.
+ final inout(AggregateDeclaration) isMemberLocal() inout
+ {
+ //printf("Dsymbol::isMemberLocal() '%s'\n", toChars());
+ auto p = toParentLocal();
+ //printf("parent is %s %s\n", p.kind(), p.toChars());
+ return p ? p.isAggregateDeclaration() : null;
+ }
+
+ // is this a member of a ClassDeclaration?
+ final ClassDeclaration isClassMember()
+ {
+ auto ad = isMember();
+ return ad ? ad.isClassDeclaration() : null;
+ }
+
+ // is this a type?
+ Type getType()
+ {
+ return null;
+ }
+
+ // need a 'this' pointer?
+ bool needThis()
+ {
+ return false;
+ }
+
+ /*************************************
+ */
+ Visibility visible() pure nothrow @nogc @safe
+ {
+ return Visibility(Visibility.Kind.public_);
+ }
+
+ /**************************************
+ * Copy the syntax.
+ * Used for template instantiations.
+ * If s is NULL, allocate the new object, otherwise fill it in.
+ */
+ Dsymbol syntaxCopy(Dsymbol s)
+ {
+ printf("%s %s\n", kind(), toChars());
+ assert(0);
+ }
+
+ /**************************************
+ * Determine if this symbol is only one.
+ * Returns:
+ * false, *ps = NULL: There are 2 or more symbols
+ * true, *ps = NULL: There are zero symbols
+ * true, *ps = symbol: The one and only one symbol
+ */
+ bool oneMember(Dsymbol* ps, Identifier ident)
+ {
+ //printf("Dsymbol::oneMember()\n");
+ *ps = this;
+ return true;
+ }
+
+ /*****************************************
+ * Same as Dsymbol::oneMember(), but look at an array of Dsymbols.
+ */
+ extern (D) static bool oneMembers(Dsymbols* members, Dsymbol* ps, Identifier ident)
+ {
+ //printf("Dsymbol::oneMembers() %d\n", members ? members.dim : 0);
+ Dsymbol s = null;
+ if (!members)
+ {
+ *ps = null;
+ return true;
+ }
+
+ for (size_t i = 0; i < members.dim; i++)
+ {
+ Dsymbol sx = (*members)[i];
+ bool x = sx.oneMember(ps, ident);
+ //printf("\t[%d] kind %s = %d, s = %p\n", i, sx.kind(), x, *ps);
+ if (!x)
+ {
+ //printf("\tfalse 1\n");
+ assert(*ps is null);
+ return false;
+ }
+ if (*ps)
+ {
+ assert(ident);
+ if (!(*ps).ident || !(*ps).ident.equals(ident))
+ continue;
+ if (!s)
+ s = *ps;
+ else if (s.isOverloadable() && (*ps).isOverloadable())
+ {
+ // keep head of overload set
+ FuncDeclaration f1 = s.isFuncDeclaration();
+ FuncDeclaration f2 = (*ps).isFuncDeclaration();
+ if (f1 && f2)
+ {
+ assert(!f1.isFuncAliasDeclaration());
+ assert(!f2.isFuncAliasDeclaration());
+ for (; f1 != f2; f1 = f1.overnext0)
+ {
+ if (f1.overnext0 is null)
+ {
+ f1.overnext0 = f2;
+ break;
+ }
+ }
+ }
+ }
+ else // more than one symbol
+ {
+ *ps = null;
+ //printf("\tfalse 2\n");
+ return false;
+ }
+ }
+ }
+ *ps = s; // s is the one symbol, null if none
+ //printf("\ttrue\n");
+ return true;
+ }
+
+ void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
+ {
+ }
+
+ /*****************************************
+ * Is Dsymbol a variable that contains pointers?
+ */
+ bool hasPointers()
+ {
+ //printf("Dsymbol::hasPointers() %s\n", toChars());
+ return false;
+ }
+
+ bool hasStaticCtorOrDtor()
+ {
+ //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars());
+ return false;
+ }
+
+ void addLocalClass(ClassDeclarations*)
+ {
+ }
+
+ void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
+ {
+ }
+
+ void checkCtorConstInit()
+ {
+ }
+
+ /****************************************
+ * Add documentation comment to Dsymbol.
+ * Ignore NULL comments.
+ */
+ void addComment(const(char)* comment)
+ {
+ //if (comment)
+ // printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
+ if (!this.comment)
+ this.comment = comment;
+ else if (comment && strcmp(cast(char*)comment, cast(char*)this.comment) != 0)
+ {
+ // Concatenate the two
+ this.comment = Lexer.combineComments(this.comment.toDString(), comment.toDString(), true);
+ }
+ }
+
+ /****************************************
+ * Returns true if this symbol is defined in a non-root module without instantiation.
+ */
+ final bool inNonRoot()
+ {
+ Dsymbol s = parent;
+ for (; s; s = s.toParent())
+ {
+ if (auto ti = s.isTemplateInstance())
+ {
+ return false;
+ }
+ if (auto m = s.isModule())
+ {
+ if (!m.isRoot())
+ return true;
+ break;
+ }
+ }
+ return false;
+ }
+
+ /************
+ */
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ pure nothrow @safe @nogc:
+
+ // Eliminate need for dynamic_cast
+ inout(Package) isPackage() inout { return null; }
+ inout(Module) isModule() inout { return null; }
+ inout(EnumMember) isEnumMember() inout { return null; }
+ inout(TemplateDeclaration) isTemplateDeclaration() inout { return null; }
+ inout(TemplateInstance) isTemplateInstance() inout { return null; }
+ inout(TemplateMixin) isTemplateMixin() inout { return null; }
+ inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return null; }
+ inout(Nspace) isNspace() inout { return null; }
+ inout(Declaration) isDeclaration() inout { return null; }
+ inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return null; }
+ inout(ExpressionDsymbol) isExpressionDsymbol() inout { return null; }
+ inout(AliasAssign) isAliasAssign() inout { return null; }
+ inout(ThisDeclaration) isThisDeclaration() inout { return null; }
+ inout(BitFieldDeclaration) isBitFieldDeclaration() inout { return null; }
+ inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout { return null; }
+ inout(TupleDeclaration) isTupleDeclaration() inout { return null; }
+ inout(AliasDeclaration) isAliasDeclaration() inout { return null; }
+ inout(AggregateDeclaration) isAggregateDeclaration() inout { return null; }
+ inout(FuncDeclaration) isFuncDeclaration() inout { return null; }
+ inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout { return null; }
+ inout(OverDeclaration) isOverDeclaration() inout { return null; }
+ inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout { return null; }
+ inout(CtorDeclaration) isCtorDeclaration() inout { return null; }
+ inout(PostBlitDeclaration) isPostBlitDeclaration() inout { return null; }
+ inout(DtorDeclaration) isDtorDeclaration() inout { return null; }
+ inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout { return null; }
+ inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout { return null; }
+ inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout { return null; }
+ inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout { return null; }
+ inout(InvariantDeclaration) isInvariantDeclaration() inout { return null; }
+ inout(UnitTestDeclaration) isUnitTestDeclaration() inout { return null; }
+ inout(NewDeclaration) isNewDeclaration() inout { return null; }
+ inout(VarDeclaration) isVarDeclaration() inout { return null; }
+ inout(VersionSymbol) isVersionSymbol() inout { return null; }
+ inout(DebugSymbol) isDebugSymbol() inout { return null; }
+ inout(ClassDeclaration) isClassDeclaration() inout { return null; }
+ inout(StructDeclaration) isStructDeclaration() inout { return null; }
+ inout(UnionDeclaration) isUnionDeclaration() inout { return null; }
+ inout(InterfaceDeclaration) isInterfaceDeclaration() inout { return null; }
+ inout(ScopeDsymbol) isScopeDsymbol() inout { return null; }
+ inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout { return null; }
+ inout(WithScopeSymbol) isWithScopeSymbol() inout { return null; }
+ inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return null; }
+ inout(Import) isImport() inout { return null; }
+ inout(EnumDeclaration) isEnumDeclaration() inout { return null; }
+ inout(SymbolDeclaration) isSymbolDeclaration() inout { return null; }
+ inout(AttribDeclaration) isAttribDeclaration() inout { return null; }
+ inout(AnonDeclaration) isAnonDeclaration() inout { return null; }
+ inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return null; }
+ inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; }
+ inout(OverloadSet) isOverloadSet() inout { return null; }
+ inout(CompileDeclaration) isCompileDeclaration() inout { return null; }
+}
+
+/***********************************************************
+ * Dsymbol that generates a scope
+ */
+extern (C++) class ScopeDsymbol : Dsymbol
+{
+ Dsymbols* members; // all Dsymbol's in this scope
+ DsymbolTable symtab; // members[] sorted into table
+ uint endlinnum; // the linnumber of the statement after the scope (0 if unknown)
+
+private:
+ /// symbols whose members have been imported, i.e. imported modules and template mixins
+ Dsymbols* importedScopes;
+ Visibility.Kind* visibilities; // array of Visibility.Kind, one for each import
+
+ import dmd.root.bitarray;
+ BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages
+
+public:
+ final extern (D) this()
+ {
+ }
+
+ final extern (D) this(Identifier ident)
+ {
+ super(ident);
+ }
+
+ final extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ super(loc, ident);
+ }
+
+ override ScopeDsymbol syntaxCopy(Dsymbol s)
+ {
+ //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars());
+ ScopeDsymbol sds = s ? cast(ScopeDsymbol)s : new ScopeDsymbol(ident);
+ sds.comment = comment;
+ sds.members = arraySyntaxCopy(members);
+ sds.endlinnum = endlinnum;
+ return sds;
+ }
+
+ /*****************************************
+ * This function is #1 on the list of functions that eat cpu time.
+ * Be very, very careful about slowing it down.
+ */
+ override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
+ {
+ //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
+ //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
+
+ // Look in symbols declared in this module
+ if (symtab && !(flags & SearchImportsOnly))
+ {
+ //printf(" look in locals\n");
+ auto s1 = symtab.lookup(ident);
+ if (s1)
+ {
+ //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
+ return s1;
+ }
+ }
+ //printf(" not found in locals\n");
+
+ // Look in imported scopes
+ if (!importedScopes)
+ return null;
+
+ //printf(" look in imports\n");
+ Dsymbol s = null;
+ OverloadSet a = null;
+ // Look in imported modules
+ for (size_t i = 0; i < importedScopes.dim; i++)
+ {
+ // If private import, don't search it
+ if ((flags & IgnorePrivateImports) && visibilities[i] == Visibility.Kind.private_)
+ continue;
+ int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches
+ Dsymbol ss = (*importedScopes)[i];
+ //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport());
+
+ if (ss.isModule())
+ {
+ if (flags & SearchLocalsOnly)
+ continue;
+ }
+ else // mixin template
+ {
+ if (flags & SearchImportsOnly)
+ continue;
+
+ sflags |= SearchLocalsOnly;
+ }
+
+ /* Don't find private members if ss is a module
+ */
+ Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
+ import dmd.access : symbolIsVisible;
+ if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2))
+ continue;
+ if (!s)
+ {
+ s = s2;
+ if (s && s.isOverloadSet())
+ a = mergeOverloadSet(ident, a, s);
+ }
+ else if (s2 && s != s2)
+ {
+ if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType())
+ {
+ /* After following aliases, we found the same
+ * symbol, so it's not an ambiguity. But if one
+ * alias is deprecated or less accessible, prefer
+ * the other.
+ */
+ if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none)
+ s = s2;
+ }
+ else
+ {
+ /* Two imports of the same module should be regarded as
+ * the same.
+ */
+ Import i1 = s.isImport();
+ Import i2 = s2.isImport();
+ if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident)))))
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=8668
+ * Public selective import adds AliasDeclaration in module.
+ * To make an overload set, resolve aliases in here and
+ * get actual overload roots which accessible via s and s2.
+ */
+ s = s.toAlias();
+ s2 = s2.toAlias();
+ /* If both s2 and s are overloadable (though we only
+ * need to check s once)
+ */
+
+ auto so2 = s2.isOverloadSet();
+ if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable()))
+ {
+ if (symbolIsVisible(this, s2))
+ {
+ a = mergeOverloadSet(ident, a, s2);
+ }
+ if (!symbolIsVisible(this, s))
+ s = s2;
+ continue;
+ }
+
+ /* Two different overflow sets can have the same members
+ * https://issues.dlang.org/show_bug.cgi?id=16709
+ */
+ auto so = s.isOverloadSet();
+ if (so && so2)
+ {
+ if (so.a.length == so2.a.length)
+ {
+ foreach (j; 0 .. so.a.length)
+ {
+ if (so.a[j] !is so2.a[j])
+ goto L1;
+ }
+ continue; // the same
+ L1:
+ { } // different
+ }
+ }
+
+ if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
+ return null;
+ if (!(flags & IgnoreErrors))
+ ScopeDsymbol.multiplyDefined(loc, s, s2);
+ break;
+ }
+ }
+ }
+ }
+ if (s)
+ {
+ /* Build special symbol if we had multiple finds
+ */
+ if (a)
+ {
+ if (!s.isOverloadSet())
+ a = mergeOverloadSet(ident, a, s);
+ s = a;
+ }
+ //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
+ return s;
+ }
+ //printf(" not found in imports\n");
+ return null;
+ }
+
+ extern (D) private OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s)
+ {
+ if (!os)
+ {
+ os = new OverloadSet(ident);
+ os.parent = this;
+ }
+ if (OverloadSet os2 = s.isOverloadSet())
+ {
+ // Merge the cross-module overload set 'os2' into 'os'
+ if (os.a.dim == 0)
+ {
+ os.a.setDim(os2.a.dim);
+ memcpy(os.a.tdata(), os2.a.tdata(), (os.a[0]).sizeof * os2.a.dim);
+ }
+ else
+ {
+ for (size_t i = 0; i < os2.a.dim; i++)
+ {
+ os = mergeOverloadSet(ident, os, os2.a[i]);
+ }
+ }
+ }
+ else
+ {
+ assert(s.isOverloadable());
+ /* Don't add to os[] if s is alias of previous sym
+ */
+ for (size_t j = 0; j < os.a.dim; j++)
+ {
+ Dsymbol s2 = os.a[j];
+ if (s.toAlias() == s2.toAlias())
+ {
+ if (s2.isDeprecated() || (s2.visible() < s.visible() && s.visible().kind != Visibility.Kind.none))
+ {
+ os.a[j] = s;
+ }
+ goto Lcontinue;
+ }
+ }
+ os.push(s);
+ Lcontinue:
+ }
+ return os;
+ }
+
+ void importScope(Dsymbol s, Visibility visibility)
+ {
+ //printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), visibility);
+ // No circular or redundant import's
+ if (s != this)
+ {
+ if (!importedScopes)
+ importedScopes = new Dsymbols();
+ else
+ {
+ for (size_t i = 0; i < importedScopes.dim; i++)
+ {
+ Dsymbol ss = (*importedScopes)[i];
+ if (ss == s) // if already imported
+ {
+ if (visibility.kind > visibilities[i])
+ visibilities[i] = visibility.kind; // upgrade access
+ return;
+ }
+ }
+ }
+ importedScopes.push(s);
+ visibilities = cast(Visibility.Kind*)mem.xrealloc(visibilities, importedScopes.dim * (visibilities[0]).sizeof);
+ visibilities[importedScopes.dim - 1] = visibility.kind;
+ }
+ }
+
+ extern (D) final void addAccessiblePackage(Package p, Visibility visibility)
+ {
+ auto pary = visibility.kind == Visibility.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages;
+ if (pary.length <= p.tag)
+ pary.length = p.tag + 1;
+ (*pary)[p.tag] = true;
+ }
+
+ bool isPackageAccessible(Package p, Visibility visibility, int flags = 0)
+ {
+ if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
+ visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
+ return true;
+ foreach (i, ss; importedScopes ? (*importedScopes)[] : null)
+ {
+ // only search visible scopes && imported modules should ignore private imports
+ if (visibility.kind <= visibilities[i] &&
+ ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports))
+ return true;
+ }
+ return false;
+ }
+
+ override final bool isforwardRef()
+ {
+ return (members is null);
+ }
+
+ static void multiplyDefined(const ref Loc loc, Dsymbol s1, Dsymbol s2)
+ {
+ version (none)
+ {
+ printf("ScopeDsymbol::multiplyDefined()\n");
+ printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1.toChars(), s1.kind(), s1.parent ? s1.parent.toChars() : "");
+ printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2.toChars(), s2.kind(), s2.parent ? s2.parent.toChars() : "");
+ }
+ if (loc.isValid())
+ {
+ .error(loc, "%s `%s` at %s conflicts with %s `%s` at %s",
+ s1.kind(), s1.toPrettyChars(), s1.locToChars(),
+ s2.kind(), s2.toPrettyChars(), s2.locToChars());
+
+ static if (0)
+ {
+ if (auto so = s1.isOverloadSet())
+ {
+ printf("first %p:\n", so);
+ foreach (s; so.a[])
+ {
+ printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
+ }
+ }
+ if (auto so = s2.isOverloadSet())
+ {
+ printf("second %p:\n", so);
+ foreach (s; so.a[])
+ {
+ printf(" %p %s `%s` at %s\n", s, s.kind(), s.toPrettyChars(), s.locToChars());
+ }
+ }
+ }
+ }
+ else
+ {
+ s1.error(s1.loc, "conflicts with %s `%s` at %s", s2.kind(), s2.toPrettyChars(), s2.locToChars());
+ }
+ }
+
+ override const(char)* kind() const
+ {
+ return "ScopeDsymbol";
+ }
+
+ /*******************************************
+ * Look for member of the form:
+ * const(MemberInfo)[] getMembers(string);
+ * Returns NULL if not found
+ */
+ final FuncDeclaration findGetMembers()
+ {
+ Dsymbol s = search_function(this, Id.getmembers);
+ FuncDeclaration fdx = s ? s.isFuncDeclaration() : null;
+ version (none)
+ {
+ // Finish
+ __gshared TypeFunction tfgetmembers;
+ if (!tfgetmembers)
+ {
+ Scope sc;
+ auto parameters = new Parameters();
+ Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null);
+ parameters.push(p);
+ Type tret = null;
+ tfgetmembers = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
+ tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc);
+ }
+ if (fdx)
+ fdx = fdx.overloadExactMatch(tfgetmembers);
+ }
+ if (fdx && fdx.isVirtual())
+ fdx = null;
+ return fdx;
+ }
+
+ /********************************
+ * Insert Dsymbol in table.
+ * Params:
+ * s = symbol to add
+ * Returns:
+ * null if already in table, `s` if inserted
+ */
+ Dsymbol symtabInsert(Dsymbol s)
+ {
+ return symtab.insert(s);
+ }
+
+ /****************************************
+ * Look up identifier in symbol table.
+ * Params:
+ * s = symbol
+ * id = identifier to look up
+ * Returns:
+ * Dsymbol if found, null if not
+ */
+ Dsymbol symtabLookup(Dsymbol s, Identifier id)
+ {
+ return symtab.lookup(id);
+ }
+
+ /****************************************
+ * Return true if any of the members are static ctors or static dtors, or if
+ * any members have members that are.
+ */
+ override bool hasStaticCtorOrDtor()
+ {
+ if (members)
+ {
+ for (size_t i = 0; i < members.dim; i++)
+ {
+ Dsymbol member = (*members)[i];
+ if (member.hasStaticCtorOrDtor())
+ return true;
+ }
+ }
+ return false;
+ }
+
+ extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s);
+
+ /***************************************
+ * Expands attribute declarations in members in depth first
+ * order. Calls dg(size_t symidx, Dsymbol *sym) for each
+ * member.
+ * If dg returns !=0, stops and returns that value else returns 0.
+ * Use this function to avoid the O(N + N^2/2) complexity of
+ * calculating dim and calling N times getNth.
+ * Returns:
+ * last value returned by dg()
+ */
+ extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
+ {
+ assert(dg);
+ if (!members)
+ return 0;
+ size_t n = pn ? *pn : 0; // take over index
+ int result = 0;
+ foreach (size_t i; 0 .. members.dim)
+ {
+ Dsymbol s = (*members)[i];
+ if (AttribDeclaration a = s.isAttribDeclaration())
+ result = _foreach(sc, a.include(sc), dg, &n);
+ else if (TemplateMixin tm = s.isTemplateMixin())
+ result = _foreach(sc, tm.members, dg, &n);
+ else if (s.isTemplateInstance())
+ {
+ }
+ else if (s.isUnitTestDeclaration())
+ {
+ }
+ else
+ result = dg(n++, s);
+ if (result)
+ break;
+ }
+ if (pn)
+ *pn = n; // update index
+ return result;
+ }
+
+ override final inout(ScopeDsymbol) isScopeDsymbol() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * With statement scope
+ */
+extern (C++) final class WithScopeSymbol : ScopeDsymbol
+{
+ WithStatement withstate;
+
+ extern (D) this(WithStatement withstate)
+ {
+ this.withstate = withstate;
+ }
+
+ override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
+ {
+ //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
+ if (flags & SearchImportsOnly)
+ return null;
+ // Acts as proxy to the with class declaration
+ Dsymbol s = null;
+ Expression eold = null;
+ for (Expression e = withstate.exp; e != eold; e = resolveAliasThis(_scope, e))
+ {
+ if (e.op == TOK.scope_)
+ {
+ s = (cast(ScopeExp)e).sds;
+ }
+ else if (e.op == TOK.type)
+ {
+ s = e.type.toDsymbol(null);
+ }
+ else
+ {
+ Type t = e.type.toBasetype();
+ s = t.toDsymbol(null);
+ }
+ if (s)
+ {
+ s = s.search(loc, ident, flags);
+ if (s)
+ return s;
+ }
+ eold = e;
+ }
+ return null;
+ }
+
+ override inout(WithScopeSymbol) isWithScopeSymbol() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Array Index/Slice scope
+ */
+extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
+{
+ // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
+ // Discriminated using DYNCAST and, for expressions, also TOK
+ private RootObject arrayContent;
+ Scope* sc;
+
+ extern (D) this(Scope* sc, Expression exp)
+ {
+ super(exp.loc, null);
+ assert(exp.op == TOK.index || exp.op == TOK.slice || exp.op == TOK.array);
+ this.sc = sc;
+ this.arrayContent = exp;
+ }
+
+ extern (D) this(Scope* sc, TypeTuple type)
+ {
+ this.sc = sc;
+ this.arrayContent = type;
+ }
+
+ extern (D) this(Scope* sc, TupleDeclaration td)
+ {
+ this.sc = sc;
+ this.arrayContent = td;
+ }
+
+ /// This override is used to solve `$`
+ override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
+ {
+ //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
+ if (ident != Id.dollar)
+ return null;
+
+ VarDeclaration* pvar;
+ Expression ce;
+
+ static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc)
+ {
+
+ /* $ gives the number of type entries in the type tuple
+ */
+ auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
+ Expression e = new IntegerExp(Loc.initial, tt.arguments.dim, Type.tsize_t);
+ v._init = new ExpInitializer(Loc.initial, e);
+ v.storage_class |= STC.temp | STC.static_ | STC.const_;
+ v.dsymbolSemantic(sc);
+ return v;
+ }
+
+ const DYNCAST kind = arrayContent.dyncast();
+ if (kind == DYNCAST.dsymbol)
+ {
+ TupleDeclaration td = cast(TupleDeclaration) arrayContent;
+ /* $ gives the number of elements in the tuple
+ */
+ auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
+ Expression e = new IntegerExp(Loc.initial, td.objects.dim, Type.tsize_t);
+ v._init = new ExpInitializer(Loc.initial, e);
+ v.storage_class |= STC.temp | STC.static_ | STC.const_;
+ v.dsymbolSemantic(sc);
+ return v;
+ }
+ if (kind == DYNCAST.type)
+ {
+ return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc);
+ }
+ Expression exp = cast(Expression) arrayContent;
+ if (auto ie = exp.isIndexExp())
+ {
+ /* array[index] where index is some function of $
+ */
+ pvar = &ie.lengthVar;
+ ce = ie.e1;
+ }
+ else if (auto se = exp.isSliceExp())
+ {
+ /* array[lwr .. upr] where lwr or upr is some function of $
+ */
+ pvar = &se.lengthVar;
+ ce = se.e1;
+ }
+ else if (auto ae = exp.isArrayExp())
+ {
+ /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
+ * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
+ */
+ pvar = &ae.lengthVar;
+ ce = ae.e1;
+ }
+ else
+ {
+ /* Didn't find $, look in enclosing scope(s).
+ */
+ return null;
+ }
+ ce = ce.lastComma();
+ /* If we are indexing into an array that is really a type
+ * tuple, rewrite this as an index into a type tuple and
+ * try again.
+ */
+ if (auto te = ce.isTypeExp())
+ {
+ if (auto ttp = te.type.isTypeTuple())
+ return dollarFromTypeTuple(loc, ttp, sc);
+ }
+ /* *pvar is lazily initialized, so if we refer to $
+ * multiple times, it gets set only once.
+ */
+ if (!*pvar) // if not already initialized
+ {
+ /* Create variable v and set it to the value of $
+ */
+ VarDeclaration v;
+ Type t;
+ if (auto tupexp = ce.isTupleExp())
+ {
+ /* It is for an expression tuple, so the
+ * length will be a const.
+ */
+ Expression e = new IntegerExp(Loc.initial, tupexp.exps.dim, Type.tsize_t);
+ v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e));
+ v.storage_class |= STC.temp | STC.static_ | STC.const_;
+ }
+ else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
+ {
+ // Look for opDollar
+ assert(exp.op == TOK.array || exp.op == TOK.slice);
+ AggregateDeclaration ad = isAggregate(t);
+ assert(ad);
+ Dsymbol s = ad.search(loc, Id.opDollar);
+ if (!s) // no dollar exists -- search in higher scope
+ return null;
+ s = s.toAlias();
+ Expression e = null;
+ // Check for multi-dimensional opDollar(dim) template.
+ if (TemplateDeclaration td = s.isTemplateDeclaration())
+ {
+ dinteger_t dim = 0;
+ if (exp.op == TOK.array)
+ {
+ dim = (cast(ArrayExp)exp).currentDimension;
+ }
+ else if (exp.op == TOK.slice)
+ {
+ dim = 0; // slices are currently always one-dimensional
+ }
+ else
+ {
+ assert(0);
+ }
+ auto tiargs = new Objects();
+ Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t);
+ edim = edim.expressionSemantic(sc);
+ tiargs.push(edim);
+ e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
+ }
+ else
+ {
+ /* opDollar exists, but it's not a template.
+ * This is acceptable ONLY for single-dimension indexing.
+ * Note that it's impossible to have both template & function opDollar,
+ * because both take no arguments.
+ */
+ if (exp.op == TOK.array && (cast(ArrayExp)exp).arguments.dim != 1)
+ {
+ exp.error("`%s` only defines opDollar for one dimension", ad.toChars());
+ return null;
+ }
+ Declaration d = s.isDeclaration();
+ assert(d);
+ e = new DotVarExp(loc, ce, d);
+ }
+ e = e.expressionSemantic(sc);
+ if (!e.type)
+ exp.error("`%s` has no value", e.toChars());
+ t = e.type.toBasetype();
+ if (t && t.ty == Tfunction)
+ e = new CallExp(e.loc, e);
+ v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e));
+ v.storage_class |= STC.temp | STC.ctfe | STC.rvalue;
+ }
+ else
+ {
+ /* For arrays, $ will either be a compile-time constant
+ * (in which case its value in set during constant-folding),
+ * or a variable (in which case an expression is created in
+ * toir.c).
+ */
+ auto e = new VoidInitializer(Loc.initial);
+ e.type = Type.tsize_t;
+ v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e);
+ v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable
+ }
+ *pvar = v;
+ }
+ (*pvar).dsymbolSemantic(sc);
+ return (*pvar);
+ }
+
+ override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Overload Sets
+ */
+extern (C++) final class OverloadSet : Dsymbol
+{
+ Dsymbols a; // array of Dsymbols
+
+ extern (D) this(Identifier ident, OverloadSet os = null)
+ {
+ super(ident);
+ if (os)
+ {
+ a.pushSlice(os.a[]);
+ }
+ }
+
+ void push(Dsymbol s)
+ {
+ a.push(s);
+ }
+
+ override inout(OverloadSet) isOverloadSet() inout
+ {
+ return this;
+ }
+
+ override const(char)* kind() const
+ {
+ return "overloadset";
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Forwarding ScopeDsymbol. Used by ForwardingAttribDeclaration and
+ * ForwardingScopeDeclaration to forward symbol insertions to another
+ * scope. See `dmd.attrib.ForwardingAttribDeclaration` for more
+ * details.
+ */
+extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
+{
+ /*************************
+ * Symbol to forward insertions to.
+ * Can be `null` before being lazily initialized.
+ */
+ ScopeDsymbol forward;
+ extern (D) this(ScopeDsymbol forward)
+ {
+ super(null);
+ this.forward = forward;
+ }
+ override Dsymbol symtabInsert(Dsymbol s)
+ {
+ assert(forward);
+ if (auto d = s.isDeclaration())
+ {
+ if (d.storage_class & STC.local)
+ {
+ // Symbols with storage class STC.local are not
+ // forwarded, but stored in the local symbol
+ // table. (Those are the `static foreach` variables.)
+ if (!symtab)
+ {
+ symtab = new DsymbolTable();
+ }
+ return super.symtabInsert(s); // insert locally
+ }
+ }
+ if (!forward.symtab)
+ {
+ forward.symtab = new DsymbolTable();
+ }
+ // Non-STC.local symbols are forwarded to `forward`.
+ return forward.symtabInsert(s);
+ }
+
+ /************************
+ * This override handles the following two cases:
+ * static foreach (i, i; [0]) { ... }
+ * and
+ * static foreach (i; [0]) { enum i = 2; }
+ */
+ override Dsymbol symtabLookup(Dsymbol s, Identifier id)
+ {
+ assert(forward);
+ // correctly diagnose clashing foreach loop variables.
+ if (auto d = s.isDeclaration())
+ {
+ if (d.storage_class & STC.local)
+ {
+ if (!symtab)
+ {
+ symtab = new DsymbolTable();
+ }
+ return super.symtabLookup(s,id);
+ }
+ }
+ // Declarations within `static foreach` do not clash with
+ // `static foreach` loop variables.
+ if (!forward.symtab)
+ {
+ forward.symtab = new DsymbolTable();
+ }
+ return forward.symtabLookup(s,id);
+ }
+
+ override void importScope(Dsymbol s, Visibility visibility)
+ {
+ forward.importScope(s, visibility);
+ }
+
+ override const(char)* kind()const{ return "local scope"; }
+
+ override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout
+ {
+ return this;
+ }
+
+}
+
+/**
+ * Class that holds an expression in a Dsymbol wrapper.
+ * This is not an AST node, but a class used to pass
+ * an expression as a function parameter of type Dsymbol.
+ */
+extern (C++) final class ExpressionDsymbol : Dsymbol
+{
+ Expression exp;
+ this(Expression exp)
+ {
+ super();
+ this.exp = exp;
+ }
+
+ override inout(ExpressionDsymbol) isExpressionDsymbol() inout
+ {
+ return this;
+ }
+}
+
+/**********************************************
+ * Encapsulate assigning to an alias:
+ * `identifier = type;`
+ * `identifier = symbol;`
+ * where `identifier` is an AliasDeclaration in scope.
+ */
+extern (C++) final class AliasAssign : Dsymbol
+{
+ Identifier ident; /// Dsymbol's ident will be null, as this class is anonymous
+ Type type; /// replace previous RHS of AliasDeclaration with `type`
+ Dsymbol aliassym; /// replace previous RHS of AliasDeclaration with `aliassym`
+ /// only one of type and aliassym can be != null
+
+ extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym)
+ {
+ super(loc, null);
+ this.ident = ident;
+ this.type = type;
+ this.aliassym = aliassym;
+ }
+
+ override AliasAssign syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ AliasAssign aa = new AliasAssign(loc, ident,
+ type ? type.syntaxCopy() : null,
+ aliassym ? aliassym.syntaxCopy(null) : null);
+ return aa;
+ }
+
+ override inout(AliasAssign) isAliasAssign() inout
+ {
+ return this;
+ }
+
+ override const(char)* kind() const
+ {
+ return "alias assignment";
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Table of Dsymbol's
+ */
+extern (C++) final class DsymbolTable : RootObject
+{
+ AssocArray!(Identifier, Dsymbol) tab;
+
+ /***************************
+ * Look up Identifier in symbol table
+ * Params:
+ * ident = identifer to look up
+ * Returns:
+ * Dsymbol if found, null if not
+ */
+ Dsymbol lookup(const Identifier ident)
+ {
+ //printf("DsymbolTable::lookup(%s)\n", ident.toChars());
+ return tab[ident];
+ }
+
+ /**********
+ * Replace existing symbol in symbol table with `s`.
+ * If it's not there, add it.
+ * Params:
+ * s = replacement symbol with same identifier
+ */
+ void update(Dsymbol s)
+ {
+ *tab.getLvalue(s.ident) = s;
+ }
+
+ /**************************
+ * Insert Dsymbol in table.
+ * Params:
+ * s = symbol to add
+ * Returns:
+ * null if already in table, `s` if inserted
+ */
+ Dsymbol insert(Dsymbol s)
+ {
+ return insert(s.ident, s);
+ }
+
+ /**************************
+ * Insert Dsymbol in table.
+ * Params:
+ * ident = identifier to serve as index
+ * s = symbol to add
+ * Returns:
+ * null if already in table, `s` if inserted
+ */
+ Dsymbol insert(const Identifier ident, Dsymbol s)
+ {
+ //printf("DsymbolTable.insert(this = %p, '%s')\n", this, s.ident.toChars());
+ Dsymbol* ps = tab.getLvalue(ident);
+ if (*ps)
+ return null; // already in table
+ *ps = s;
+ return s;
+ }
+
+ /*****************
+ * Returns:
+ * number of symbols in symbol table
+ */
+ size_t length() const pure
+ {
+ return tab.length;
+ }
+}
+
+/**********************************************
+ * ImportC tag symbols sit in a parallel symbol table,
+ * so that this C code works:
+ * ---
+ * struct S { a; };
+ * int S;
+ * struct S s;
+ * ---
+ * But there are relatively few such tag symbols, so that would be
+ * a waste of memory and complexity. An additional problem is we'd like the D side
+ * to find the tag symbols with ordinary lookup, not lookup in both
+ * tables, if the tag symbol is not conflicting with an ordinary symbol.
+ * The solution is to put the tag symbols that conflict into an associative
+ * array, indexed by the address of the ordinary symbol that conflicts with it.
+ * C has no modules, so this associative array is tagSymTab[] in ModuleDeclaration.
+ * A side effect of our approach is that D code cannot access a tag symbol that is
+ * hidden by an ordinary symbol. This is more of a theoretical problem, as nobody
+ * has mentioned it when importing C headers. If someone wants to do it,
+ * too bad so sad. Change the C code.
+ * This function fixes up the symbol table when faced with adding a new symbol
+ * `s` when there is an existing symbol `s2` with the same name.
+ * C also allows forward and prototype declarations of tag symbols,
+ * this function merges those.
+ * Params:
+ * sc = context
+ * s = symbol to add to symbol table
+ * s2 = existing declaration
+ * sds = symbol table
+ * Returns:
+ * if s and s2 are successfully put in symbol table then return the merged symbol,
+ * null if they conflict
+ */
+Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
+{
+ enum log = false;
+ if (log) printf("handleTagSymbols('%s')\n", s.toChars());
+ auto sd = s.isScopeDsymbol(); // new declaration
+ auto sd2 = s2.isScopeDsymbol(); // existing declaration
+
+ if (!sd2)
+ {
+ /* Look in tag table
+ */
+ if (log) printf(" look in tag table\n");
+ if (auto p = cast(void*)s2 in sc._module.tagSymTab)
+ {
+ Dsymbol s2tag = *p;
+ sd2 = s2tag.isScopeDsymbol();
+ assert(sd2); // only tags allowed in tag symbol table
+ }
+ }
+
+ if (sd && sd2) // `s` is a tag, `sd2` is the same tag
+ {
+ if (log) printf(" tag is already defined\n");
+
+ if (sd.kind() != sd2.kind()) // being enum/struct/union must match
+ return null; // conflict
+
+ /* Not a redeclaration if one is a forward declaration.
+ * Move members to the first declared type, which is sd2.
+ */
+ if (sd2.members)
+ {
+ if (!sd.members)
+ return sd2; // ignore the sd redeclaration
+ }
+ else if (sd.members)
+ {
+ sd2.members = sd.members; // transfer definition to sd2
+ sd.members = null;
+ return sd2;
+ }
+ else
+ return sd2; // ignore redeclaration
+ }
+ else if (sd) // `s` is a tag, `s2` is not
+ {
+ if (log) printf(" s is tag, s2 is not\n");
+ /* add `s` as tag indexed by s2
+ */
+ sc._module.tagSymTab[cast(void*)s2] = s;
+ return s;
+ }
+ else if (s2 is sd2) // `s2` is a tag, `s` is not
+ {
+ if (log) printf(" s2 is tag, s is not\n");
+ /* replace `s2` in symbol table with `s`,
+ * then add `s2` as tag indexed by `s`
+ */
+ sds.symtab.update(s);
+ sc._module.tagSymTab[cast(void*)s] = s2;
+ return s;
+ }
+ if (log) printf(" collision\n");
+ return null;
+}
+
+
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index ce0ce45..f43bc83 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -11,17 +11,18 @@
#pragma once
#include "root/port.h"
-#include "root/stringtable.h"
#include "ast_node.h"
#include "globals.h"
#include "arraytypes.h"
#include "visitor.h"
+class CPPNamespaceDeclaration;
class Identifier;
struct Scope;
class DsymbolTable;
class Declaration;
class ThisDeclaration;
+class BitFieldDeclaration;
class TypeInfoDeclaration;
class TupleDeclaration;
class AliasDeclaration;
@@ -47,6 +48,7 @@ class UnitTestDeclaration;
class NewDeclaration;
class VarDeclaration;
class AttribDeclaration;
+class VisibilityDeclaration;
class Package;
class Module;
class Import;
@@ -66,7 +68,8 @@ class WithScopeSymbol;
class ArrayScopeSymbol;
class SymbolDeclaration;
class Expression;
-class DeleteDeclaration;
+class ExpressionDsymbol;
+class AliasAssign;
class OverloadSet;
struct AA;
#ifdef IN_GCC
@@ -84,10 +87,10 @@ struct Ungag
};
void dsymbolSemantic(Dsymbol *dsym, Scope *sc);
-void semantic2(Dsymbol *dsym, Scope* sc);
+void semantic2(Dsymbol *dsym, Scope *sc);
void semantic3(Dsymbol *dsym, Scope* sc);
-struct Prot
+struct Visibility
{
enum Kind
{
@@ -101,18 +104,8 @@ struct Prot
};
Kind kind;
Package *pkg;
-
- Prot();
- Prot(Kind kind);
-
- bool isMoreRestrictiveThan(const Prot other) const;
- bool operator==(const Prot& other) const;
};
-// in hdrgen.c
-void protectionToBuffer(OutBuffer *buf, Prot prot);
-const char *protectionToChars(Prot::Kind kind);
-
/* State of symbol in winding its way through the passes of the compiler
*/
enum PASS
@@ -143,16 +136,27 @@ enum
// meaning don't search imports in that scope,
// because qualified module searches search
// their imports
- IgnoreSymbolVisibility = 0x80 // also find private and package protected symbols
+ IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols
+ TagNameSpace = 0x100, // search ImportC tag symbol table
};
-typedef int (*Dsymbol_apply_ft_t)(Dsymbol *, void *);
+struct FieldState
+{
+ unsigned offset;
+
+ unsigned fieldOffset;
+ unsigned bitOffset;
+ unsigned fieldSice;
+ bool inFlight;
+};
class Dsymbol : public ASTNode
{
public:
Identifier *ident;
Dsymbol *parent;
+ /// C++ namespace this symbol belongs to
+ CPPNamespaceDeclaration *namespace_;
Symbol *csym; // symbol for code generator
Symbol *isym; // import version of csym
const utf8_t *comment; // documentation comment for this Dsymbol
@@ -161,74 +165,72 @@ public:
const utf8_t *prettystring;
bool errors; // this symbol failed to pass semantic()
PASS semanticRun;
+ unsigned short localNum; // perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
DeprecatedDeclaration *depdecl; // customized deprecation message
UserAttributeDeclaration *userAttribDecl; // user defined attributes
UnitTestDeclaration *ddocUnittest; // !=NULL means there's a ddoc unittest associated with this symbol (only use this with ddoc)
- Dsymbol();
- Dsymbol(Identifier *);
static Dsymbol *create(Identifier *);
- const char *toChars();
+ const char *toChars() const;
virtual const char *toPrettyCharsHelper(); // helper to print fully qualified (template) arguments
- Loc& getLoc();
+ Loc getLoc();
const char *locToChars();
- bool equals(RootObject *o);
- bool isAnonymous();
- void error(Loc loc, const char *format, ...);
+ bool equals(const RootObject *o) const;
+ bool isAnonymous() const;
+ void error(const Loc &loc, const char *format, ...);
void error(const char *format, ...);
- void deprecation(Loc loc, const char *format, ...);
+ void deprecation(const Loc &loc, const char *format, ...);
void deprecation(const char *format, ...);
- bool checkDeprecated(Loc loc, Scope *sc);
+ bool checkDeprecated(const Loc &loc, Scope *sc);
Module *getModule();
Module *getAccessModule();
Dsymbol *pastMixin();
- Dsymbol *pastMixinAndNspace();
Dsymbol *toParent();
Dsymbol *toParent2();
- Dsymbol *toParent3();
+ Dsymbol *toParentDecl();
+ Dsymbol *toParentLocal();
+ Dsymbol *toParentP(Dsymbol *p1, Dsymbol *p2 = NULL);
TemplateInstance *isInstantiated();
+ bool followInstantiationContext(Dsymbol *p1, Dsymbol *p2 = NULL);
TemplateInstance *isSpeculative();
Ungag ungagSpeculative();
// kludge for template.isSymbol()
- int dyncast() const { return DYNCAST_DSYMBOL; }
-
- static Dsymbols *arraySyntaxCopy(Dsymbols *a);
+ DYNCAST dyncast() const { return DYNCAST_DSYMBOL; }
virtual Identifier *getIdent();
virtual const char *toPrettyChars(bool QualifyTypes = false);
virtual const char *kind() const;
virtual Dsymbol *toAlias(); // resolve real symbol
virtual Dsymbol *toAlias2();
- virtual int apply(Dsymbol_apply_ft_t fp, void *param);
virtual void addMember(Scope *sc, ScopeDsymbol *sds);
virtual void setScope(Scope *sc);
virtual void importAll(Scope *sc);
virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone);
- Dsymbol *search_correct(Identifier *id);
- Dsymbol *searchX(Loc loc, Scope *sc, RootObject *id, int flags);
virtual bool overloadInsert(Dsymbol *s);
- virtual d_uns64 size(Loc loc);
+ virtual d_uns64 size(const Loc &loc);
virtual bool isforwardRef();
virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member
virtual bool isExport() const; // is Dsymbol exported?
virtual bool isImportedSymbol() const; // is Dsymbol imported?
- virtual bool isDeprecated(); // is Dsymbol deprecated?
- virtual bool isOverloadable();
+ virtual bool isDeprecated() const; // is Dsymbol deprecated?
+ virtual bool isOverloadable() const;
virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol?
- AggregateDeclaration *isMember(); // is this a member of an AggregateDeclaration?
- AggregateDeclaration *isMember2(); // is this a member of an AggregateDeclaration?
- ClassDeclaration *isClassMember(); // is this a member of a ClassDeclaration?
+ AggregateDeclaration *isMember(); // is toParent() an AggregateDeclaration?
+ AggregateDeclaration *isMember2(); // is toParent2() an AggregateDeclaration?
+ AggregateDeclaration *isMemberDecl(); // is toParentDecl() an AggregateDeclaration?
+ AggregateDeclaration *isMemberLocal(); // is toParentLocal() an AggregateDeclaration?
+ ClassDeclaration *isClassMember(); // isMember() is a ClassDeclaration?
virtual Type *getType(); // is this a type?
virtual bool needThis(); // need a 'this' pointer?
- virtual Prot prot();
+ virtual Visibility visible();
virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
virtual bool oneMember(Dsymbol **ps, Identifier *ident);
- static bool oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident);
- virtual void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+ virtual void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
virtual bool hasPointers();
virtual bool hasStaticCtorOrDtor();
virtual void addLocalClass(ClassDeclarations *) { }
+ virtual void addObjcSymbols(ClassDeclarations *, ClassDeclarations *) { }
virtual void checkCtorConstInit() { }
virtual void addComment(const utf8_t *comment);
@@ -246,7 +248,10 @@ public:
virtual Nspace *isNspace() { return NULL; }
virtual Declaration *isDeclaration() { return NULL; }
virtual StorageClassDeclaration *isStorageClassDeclaration(){ return NULL; }
+ virtual ExpressionDsymbol *isExpressionDsymbol() { return NULL; }
+ virtual AliasAssign *isAliasAssign() { return NULL; }
virtual ThisDeclaration *isThisDeclaration() { return NULL; }
+ virtual BitFieldDeclaration *isBitFieldDeclaration() { return NULL; }
virtual TypeInfoDeclaration *isTypeInfoDeclaration() { return NULL; }
virtual TupleDeclaration *isTupleDeclaration() { return NULL; }
virtual AliasDeclaration *isAliasDeclaration() { return NULL; }
@@ -278,11 +283,13 @@ public:
virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; }
virtual Import *isImport() { return NULL; }
virtual EnumDeclaration *isEnumDeclaration() { return NULL; }
- virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; }
virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; }
virtual AttribDeclaration *isAttribDeclaration() { return NULL; }
virtual AnonDeclaration *isAnonDeclaration() { return NULL; }
+ virtual CPPNamespaceDeclaration *isCPPNamespaceDeclaration() { return NULL; }
+ virtual VisibilityDeclaration *isVisibilityDeclaration() { return NULL; }
virtual OverloadSet *isOverloadSet() { return NULL; }
+ virtual CompileDeclaration *isCompileDeclaration() { return NULL; }
void accept(Visitor *v) { v->visit(this); }
};
@@ -297,30 +304,23 @@ public:
private:
Dsymbols *importedScopes; // imported Dsymbol's
- Prot::Kind *prots; // array of PROTKIND, one for each import
+ Visibility::Kind *visibilities; // array of `Visibility.Kind`, one for each import
BitArray accessiblePackages, privateAccessiblePackages;
public:
- ScopeDsymbol();
- ScopeDsymbol(Identifier *id);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ ScopeDsymbol *syntaxCopy(Dsymbol *s);
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
- OverloadSet *mergeOverloadSet(Identifier *ident, OverloadSet *os, Dsymbol *s);
- virtual void importScope(Dsymbol *s, Prot protection);
- void addAccessiblePackage(Package *p, Prot protection);
- virtual bool isPackageAccessible(Package *p, Prot protection, int flags = 0);
+ virtual void importScope(Dsymbol *s, Visibility visibility);
+ virtual bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0);
bool isforwardRef();
- static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2);
+ static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2);
const char *kind() const;
FuncDeclaration *findGetMembers();
virtual Dsymbol *symtabInsert(Dsymbol *s);
virtual Dsymbol *symtabLookup(Dsymbol *s, Identifier *id);
bool hasStaticCtorOrDtor();
- static size_t dim(Dsymbols *members);
- static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL);
-
ScopeDsymbol *isScopeDsymbol() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
@@ -332,7 +332,6 @@ class WithScopeSymbol : public ScopeDsymbol
public:
WithStatement *withstate;
- WithScopeSymbol(WithStatement *withstate);
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
WithScopeSymbol *isWithScopeSymbol() { return this; }
@@ -343,15 +342,11 @@ public:
class ArrayScopeSymbol : public ScopeDsymbol
{
+private:
+ RootObject *arrayContent;
public:
- Expression *exp; // IndexExp or SliceExp
- TypeTuple *type; // for tuple[length]
- TupleDeclaration *td; // for tuples of objects
Scope *sc;
- ArrayScopeSymbol(Scope *sc, Expression *e);
- ArrayScopeSymbol(Scope *sc, TypeTuple *t);
- ArrayScopeSymbol(Scope *sc, TupleDeclaration *td);
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone);
ArrayScopeSymbol *isArrayScopeSymbol() { return this; }
@@ -365,7 +360,6 @@ class OverloadSet : public Dsymbol
public:
Dsymbols a; // array of Dsymbols
- OverloadSet(Identifier *ident, OverloadSet *os = NULL);
void push(Dsymbol *s);
OverloadSet *isOverloadSet() { return this; }
const char *kind() const;
@@ -379,15 +373,22 @@ class ForwardingScopeDsymbol : public ScopeDsymbol
public:
ScopeDsymbol *forward;
- ForwardingScopeDsymbol(ScopeDsymbol *forward);
Dsymbol *symtabInsert(Dsymbol *s);
Dsymbol *symtabLookup(Dsymbol *s, Identifier *id);
- void importScope(Dsymbol *s, Prot protection);
+ void importScope(Dsymbol *s, Visibility visibility);
const char *kind() const;
ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return this; }
};
+class ExpressionDsymbol : public Dsymbol
+{
+public:
+ Expression *exp;
+
+ ExpressionDsymbol *isExpressionDsymbol() { return this; }
+};
+
// Table of Dsymbol's
class DsymbolTable : public RootObject
@@ -395,15 +396,16 @@ class DsymbolTable : public RootObject
public:
AA *tab;
- DsymbolTable();
-
// Look up Identifier. Return Dsymbol if found, NULL if not.
Dsymbol *lookup(Identifier const * const ident);
+ // Look for Dsymbol in table. If there, return it. If not, insert s and return that.
+ void update(Dsymbol *s);
+
// Insert Dsymbol in table. Return NULL if already there.
Dsymbol *insert(Dsymbol *s);
-
- // Look for Dsymbol in table. If there, return it. If not, insert s and return that.
- Dsymbol *update(Dsymbol *s);
Dsymbol *insert(Identifier const * const ident, Dsymbol *s); // when ident and s are not the same
+
+ // Number of symbols in symbol table
+ size_t length() const;
};
diff --git a/gcc/d/dmd/dsymbolsem.c b/gcc/d/dmd/dsymbolsem.c
deleted file mode 100644
index 7a44ed2..0000000
--- a/gcc/d/dmd/dsymbolsem.c
+++ /dev/null
@@ -1,5620 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- */
-
-#include "root/dsystem.h"
-#include "root/aav.h"
-
-#include "dsymbol.h"
-#include "aggregate.h"
-#include "aliasthis.h"
-#include "attrib.h"
-#include "cond.h"
-#include "declaration.h"
-#include "enum.h"
-#include "errors.h"
-#include "hdrgen.h"
-#include "id.h"
-#include "import.h"
-#include "init.h"
-#include "mars.h"
-#include "module.h"
-#include "nspace.h"
-#include "objc.h"
-#include "parse.h"
-#include "scope.h"
-#include "statement.h"
-#include "staticassert.h"
-#include "target.h"
-#include "template.h"
-#include "utf.h"
-#include "version.h"
-#include "visitor.h"
-
-bool allowsContractWithoutBody(FuncDeclaration *funcdecl);
-bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t istart = 0);
-VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
-Initializer *inferType(Initializer *init, Scope *sc);
-void MODtoBuffer(OutBuffer *buf, MOD mod);
-bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0);
-bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
-bool symbolIsVisible(Scope *sc, Dsymbol *s);
-Objc *objc();
-
-static unsigned setMangleOverride(Dsymbol *s, char *sym)
-{
- AttribDeclaration *ad = s->isAttribDeclaration();
-
- if (ad)
- {
- Dsymbols *decls = ad->include(NULL);
- unsigned nestedCount = 0;
-
- if (decls && decls->length)
- for (size_t i = 0; i < decls->length; ++i)
- nestedCount += setMangleOverride((*decls)[i], sym);
-
- return nestedCount;
- }
- else if (s->isFuncDeclaration() || s->isVarDeclaration())
- {
- s->isDeclaration()->mangleOverride = sym;
- return 1;
- }
- else
- return 0;
-}
-
-/**********************************
- * Decide if attributes for this function can be inferred from examining
- * the function body.
- * Returns:
- * true if can
- */
-static bool canInferAttributes(FuncDeclaration *fd, Scope *sc)
-{
- if (!fd->fbody)
- return false;
-
- if (fd->isVirtualMethod())
- return false; // since they may be overridden
-
- if (sc->func &&
- /********** this is for backwards compatibility for the moment ********/
- (!fd->isMember() || (sc->func->isSafeBypassingInference() && !fd->isInstantiated())))
- return true;
-
- if (fd->isFuncLiteralDeclaration() || // externs are not possible with literals
- (fd->storage_class & STCinference) || // do attribute inference
- (fd->inferRetType && !fd->isCtorDeclaration()))
- return true;
-
- if (fd->isInstantiated())
- {
- TemplateInstance *ti = fd->parent->isTemplateInstance();
- if (ti == NULL || ti->isTemplateMixin() || ti->tempdecl->ident == fd->ident)
- return true;
- }
-
- return false;
-}
-
-/*****************************************
- * Initialize for inferring the attributes of this function.
- */
-static void initInferAttributes(FuncDeclaration *fd)
-{
- //printf("initInferAttributes() for %s\n", toPrettyChars());
- TypeFunction *tf = fd->type->toTypeFunction();
- if (tf->purity == PUREimpure) // purity not specified
- fd->flags |= FUNCFLAGpurityInprocess;
-
- if (tf->trust == TRUSTdefault)
- fd->flags |= FUNCFLAGsafetyInprocess;
-
- if (!tf->isnothrow)
- fd->flags |= FUNCFLAGnothrowInprocess;
-
- if (!tf->isnogc)
- fd->flags |= FUNCFLAGnogcInprocess;
-
- if (!fd->isVirtual() || fd->introducing)
- fd->flags |= FUNCFLAGreturnInprocess;
-
- // Initialize for inferring STCscope
- if (global.params.vsafe)
- fd->flags |= FUNCFLAGinferScope;
-}
-
-static void badObjectDotD(ClassDeclaration *cd)
-{
- cd->error("missing or corrupt object.d");
- fatal();
-}
-
-/* Bugzilla 12078, 12143 and 15733:
- * While resolving base classes and interfaces, a base may refer
- * the member of this derived class. In that time, if all bases of
- * this class can be determined, we can go forward the semantc process
- * beyond the Lancestorsdone. To do the recursive semantic analysis,
- * temporarily set and unset `_scope` around exp().
- */
-static Type *resolveBase(ClassDeclaration *cd, Scope *sc, Scope *&scx, Type *type)
-{
- if (!scx)
- {
- scx = sc->copy();
- scx->setNoFree();
- }
- cd->_scope = scx;
- Type *t = typeSemantic(type, cd->loc, sc);
- cd->_scope = NULL;
- return t;
-}
-
-static void resolveBase(ClassDeclaration *cd, Scope *sc, Scope *&scx, ClassDeclaration *sym)
-{
- if (!scx)
- {
- scx = sc->copy();
- scx->setNoFree();
- }
- cd->_scope = scx;
- dsymbolSemantic(sym, NULL);
- cd->_scope = NULL;
-}
-
-class DsymbolSemanticVisitor : public Visitor
-{
-public:
- Scope *sc;
-
- DsymbolSemanticVisitor(Scope *sc)
- {
- this->sc = sc;
- }
-
- void visit(Dsymbol *dsym)
- {
- dsym->error("%p has no semantic routine", dsym);
- }
-
- void visit(ScopeDsymbol *) { }
- void visit(Declaration *) { }
-
- void visit(AliasThis *dsym)
- {
- if (dsym->semanticRun != PASSinit)
- return;
-
- if (dsym->_scope)
- {
- sc = dsym->_scope;
- dsym->_scope = NULL;
- }
-
- if (!sc)
- return;
-
- dsym->semanticRun = PASSsemantic;
-
- Dsymbol *p = sc->parent->pastMixin();
- AggregateDeclaration *ad = p->isAggregateDeclaration();
- if (!ad)
- {
- error(dsym->loc, "alias this can only be a member of aggregate, not %s %s",
- p->kind(), p->toChars());
- return;
- }
-
- assert(ad->members);
- Dsymbol *s = ad->search(dsym->loc, dsym->ident);
- if (!s)
- {
- s = sc->search(dsym->loc, dsym->ident, NULL);
- if (s)
- error(dsym->loc, "%s is not a member of %s", s->toChars(), ad->toChars());
- else
- error(dsym->loc, "undefined identifier %s", dsym->ident->toChars());
- return;
- }
- else if (ad->aliasthis && s != ad->aliasthis)
- {
- error(dsym->loc, "there can be only one alias this");
- return;
- }
-
- if (ad->type->ty == Tstruct && ((TypeStruct *)ad->type)->sym != ad)
- {
- AggregateDeclaration *ad2 = ((TypeStruct *)ad->type)->sym;
- assert(ad2->type == Type::terror);
- ad->aliasthis = ad2->aliasthis;
- return;
- }
-
- /* disable the alias this conversion so the implicit conversion check
- * doesn't use it.
- */
- ad->aliasthis = NULL;
-
- Dsymbol *sx = s;
- if (sx->isAliasDeclaration())
- sx = sx->toAlias();
- Declaration *d = sx->isDeclaration();
- if (d && !d->isTupleDeclaration())
- {
- Type *t = d->type;
- assert(t);
- if (ad->type->implicitConvTo(t) > MATCHnomatch)
- {
- error(dsym->loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars());
- }
- }
-
- ad->aliasthis = s;
- dsym->semanticRun = PASSsemanticdone;
- }
-
- void visit(AliasDeclaration *dsym)
- {
- if (dsym->semanticRun >= PASSsemanticdone)
- return;
- assert(dsym->semanticRun <= PASSsemantic);
-
- dsym->storage_class |= sc->stc & STCdeprecated;
- dsym->protection = sc->protection;
- dsym->userAttribDecl = sc->userAttribDecl;
-
- if (!sc->func && dsym->inNonRoot())
- return;
-
- aliasSemantic(dsym, sc);
- }
-
- void visit(VarDeclaration *dsym)
- {
- //if (dsym->semanticRun > PASSinit)
- // return;
- //dsym->semanticRun = PASSsemantic;
-
- if (dsym->semanticRun >= PASSsemanticdone)
- return;
-
- Scope *scx = NULL;
- if (dsym->_scope)
- {
- sc = dsym->_scope;
- scx = sc;
- dsym->_scope = NULL;
- }
-
- if (!sc)
- return;
-
- dsym->semanticRun = PASSsemantic;
-
- /* Pick up storage classes from context, but except synchronized,
- * override, abstract, and final.
- */
- dsym->storage_class |= (sc->stc & ~(STCsynchronized | STCoverride | STCabstract | STCfinal));
- if (dsym->storage_class & STCextern && dsym->_init)
- dsym->error("extern symbols cannot have initializers");
-
- dsym->userAttribDecl = sc->userAttribDecl;
-
- AggregateDeclaration *ad = dsym->isThis();
- if (ad)
- dsym->storage_class |= ad->storage_class & STC_TYPECTOR;
-
- /* If auto type inference, do the inference
- */
- int inferred = 0;
- if (!dsym->type)
- {
- dsym->inuse++;
-
- // Infering the type requires running semantic,
- // so mark the scope as ctfe if required
- bool needctfe = (dsym->storage_class & (STCmanifest | STCstatic)) != 0;
- if (needctfe) sc = sc->startCTFE();
-
- //printf("inferring type for %s with init %s\n", dsym->toChars(), dsym->_init->toChars());
- dsym->_init = inferType(dsym->_init, sc);
- dsym->type = initializerToExpression(dsym->_init)->type;
-
- if (needctfe) sc = sc->endCTFE();
-
- dsym->inuse--;
- inferred = 1;
-
- /* This is a kludge to support the existing syntax for RAII
- * declarations.
- */
- dsym->storage_class &= ~STCauto;
- dsym->originalType = dsym->type->syntaxCopy();
- }
- else
- {
- if (!dsym->originalType)
- dsym->originalType = dsym->type->syntaxCopy();
-
- /* Prefix function attributes of variable declaration can affect
- * its type:
- * pure nothrow void function() fp;
- * static assert(is(typeof(fp) == void function() pure nothrow));
- */
- Scope *sc2 = sc->push();
- sc2->stc |= (dsym->storage_class & STC_FUNCATTR);
- dsym->inuse++;
- dsym->type = typeSemantic(dsym->type, dsym->loc, sc2);
- dsym->inuse--;
- sc2->pop();
- }
- //printf(" semantic type = %s\n", dsym->type ? dsym->type->toChars() : "null");
- if (dsym->type->ty == Terror)
- dsym->errors = true;
-
- dsym->type->checkDeprecated(dsym->loc, sc);
- dsym->linkage = sc->linkage;
- dsym->parent = sc->parent;
- //printf("this = %p, parent = %p, '%s'\n", dsym, dsym->parent, dsym->parent->toChars());
- dsym->protection = sc->protection;
-
- /* If scope's alignment is the default, use the type's alignment,
- * otherwise the scope overrrides.
- */
- dsym->alignment = sc->alignment();
- if (dsym->alignment == STRUCTALIGN_DEFAULT)
- dsym->alignment = dsym->type->alignment(); // use type's alignment
-
- //printf("sc->stc = %x\n", sc->stc);
- //printf("storage_class = x%x\n", dsym->storage_class);
-
- if (global.params.vcomplex)
- dsym->type->checkComplexTransition(dsym->loc);
-
- // Calculate type size + safety checks
- if (sc->func && !sc->intypeof)
- {
- if ((dsym->storage_class & STCgshared) && !dsym->isMember())
- {
- if (sc->func->setUnsafe())
- dsym->error("__gshared not allowed in safe functions; use shared");
- }
- }
-
- Dsymbol *parent = dsym->toParent();
-
- Type *tb = dsym->type->toBasetype();
- Type *tbn = tb->baseElemOf();
- if (tb->ty == Tvoid && !(dsym->storage_class & STClazy))
- {
- if (inferred)
- {
- dsym->error("type %s is inferred from initializer %s, and variables cannot be of type void",
- dsym->type->toChars(), dsym->_init->toChars());
- }
- else
- dsym->error("variables cannot be of type void");
- dsym->type = Type::terror;
- tb = dsym->type;
- }
- if (tb->ty == Tfunction)
- {
- dsym->error("cannot be declared to be a function");
- dsym->type = Type::terror;
- tb = dsym->type;
- }
- if (tb->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)tb;
- if (!ts->sym->members)
- {
- dsym->error("no definition of struct `%s`", ts->toChars());
-
- // Explain why the definition is required when it's part of another type
- if (!dsym->type->isTypeStruct())
- {
- // Prefer Loc of the dependant type
- Dsymbol *s = dsym->type->toDsymbol(sc);
- Loc loc = s ? s->loc : dsym->loc;
- errorSupplemental(loc, "required by type `%s`", dsym->type->toChars());
- }
-
- // Flag variable as error to avoid invalid error messages due to unknown size
- dsym->type = Type::terror;
- }
- }
- if ((dsym->storage_class & STCauto) && !inferred)
- dsym->error("storage class `auto` has no effect if type is not inferred, did you mean `scope`?");
-
- if (tb->ty == Ttuple)
- {
- /* Instead, declare variables for each of the tuple elements
- * and add those.
- */
- TypeTuple *tt = (TypeTuple *)tb;
- size_t nelems = Parameter::dim(tt->arguments);
- Expression *ie = (dsym->_init && !dsym->_init->isVoidInitializer()) ? initializerToExpression(dsym->_init) : NULL;
- if (ie)
- ie = expressionSemantic(ie, sc);
-
- if (nelems > 0 && ie)
- {
- Expressions *iexps = new Expressions();
- iexps->push(ie);
-
- Expressions *exps = new Expressions();
-
- for (size_t pos = 0; pos < iexps->length; pos++)
- {
- Lexpand1:
- Expression *e = (*iexps)[pos];
- Parameter *arg = Parameter::getNth(tt->arguments, pos);
- arg->type = typeSemantic(arg->type, dsym->loc, sc);
- //printf("[%d] iexps->length = %d, ", pos, iexps->length);
- //printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars());
- //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
-
- if (e != ie)
- {
- if (iexps->length > nelems)
- goto Lnomatch;
- if (e->type->implicitConvTo(arg->type))
- continue;
- }
-
- if (e->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)e;
- if (iexps->length - 1 + te->exps->length > nelems)
- goto Lnomatch;
-
- iexps->remove(pos);
- iexps->insert(pos, te->exps);
- (*iexps)[pos] = Expression::combine(te->e0, (*iexps)[pos]);
- goto Lexpand1;
- }
- else if (isAliasThisTuple(e))
- {
- VarDeclaration *v = copyToTemp(0, "__tup", e);
- dsymbolSemantic(v, sc);
- VarExp *ve = new VarExp(dsym->loc, v);
- ve->type = e->type;
-
- exps->setDim(1);
- (*exps)[0] = ve;
- expandAliasThisTuples(exps, 0);
-
- for (size_t u = 0; u < exps->length ; u++)
- {
- Lexpand2:
- Expression *ee = (*exps)[u];
- arg = Parameter::getNth(tt->arguments, pos + u);
- arg->type = typeSemantic(arg->type, dsym->loc, sc);
- //printf("[%d+%d] exps->length = %d, ", pos, u, exps->length);
- //printf("ee = (%s %s, %s), ", Token::tochars[ee->op], ee->toChars(), ee->type->toChars());
- //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
-
- size_t iexps_dim = iexps->length - 1 + exps->length;
- if (iexps_dim > nelems)
- goto Lnomatch;
- if (ee->type->implicitConvTo(arg->type))
- continue;
-
- if (expandAliasThisTuples(exps, u) != -1)
- goto Lexpand2;
- }
-
- if ((*exps)[0] != ve)
- {
- Expression *e0 = (*exps)[0];
- (*exps)[0] = new CommaExp(dsym->loc, new DeclarationExp(dsym->loc, v), e0);
- (*exps)[0]->type = e0->type;
-
- iexps->remove(pos);
- iexps->insert(pos, exps);
- goto Lexpand1;
- }
- }
- }
- if (iexps->length < nelems)
- goto Lnomatch;
-
- ie = new TupleExp(dsym->_init->loc, iexps);
- }
- Lnomatch:
-
- if (ie && ie->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)ie;
- size_t tedim = te->exps->length;
- if (tedim != nelems)
- {
- error(dsym->loc, "tuple of %d elements cannot be assigned to tuple of %d elements", (int)tedim, (int)nelems);
- for (size_t u = tedim; u < nelems; u++) // fill dummy expression
- te->exps->push(new ErrorExp());
- }
- }
-
- Objects *exps = new Objects();
- exps->setDim(nelems);
- for (size_t i = 0; i < nelems; i++)
- {
- Parameter *arg = Parameter::getNth(tt->arguments, i);
-
- OutBuffer buf;
- buf.printf("__%s_field_%llu", dsym->ident->toChars(), (ulonglong)i);
- const char *name = buf.extractChars();
- Identifier *id = Identifier::idPool(name);
-
- Initializer *ti;
- if (ie)
- {
- Expression *einit = ie;
- if (ie->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)ie;
- einit = (*te->exps)[i];
- if (i == 0)
- einit = Expression::combine(te->e0, einit);
- }
- ti = new ExpInitializer(einit->loc, einit);
- }
- else
- ti = dsym->_init ? dsym->_init->syntaxCopy() : NULL;
-
- VarDeclaration *v = new VarDeclaration(dsym->loc, arg->type, id, ti);
- v->storage_class |= STCtemp | STClocal | dsym->storage_class;
- if (arg->storageClass & STCparameter)
- v->storage_class |= arg->storageClass;
- //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars());
- dsymbolSemantic(v, sc);
-
- if (sc->scopesym)
- {
- //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars());
- if (sc->scopesym->members)
- sc->scopesym->members->push(v);
- }
-
- Expression *e = new DsymbolExp(dsym->loc, v);
- (*exps)[i] = e;
- }
- TupleDeclaration *v2 = new TupleDeclaration(dsym->loc, dsym->ident, exps);
- v2->parent = dsym->parent;
- v2->isexp = true;
- dsym->aliassym = v2;
- dsym->semanticRun = PASSsemanticdone;
- return;
- }
-
- /* Storage class can modify the type
- */
- dsym->type = dsym->type->addStorageClass(dsym->storage_class);
-
- /* Adjust storage class to reflect type
- */
- if (dsym->type->isConst())
- {
- dsym->storage_class |= STCconst;
- if (dsym->type->isShared())
- dsym->storage_class |= STCshared;
- }
- else if (dsym->type->isImmutable())
- dsym->storage_class |= STCimmutable;
- else if (dsym->type->isShared())
- dsym->storage_class |= STCshared;
- else if (dsym->type->isWild())
- dsym->storage_class |= STCwild;
-
- if (StorageClass stc = dsym->storage_class & (STCsynchronized | STCoverride | STCabstract | STCfinal))
- {
- if (stc == STCfinal)
- dsym->error("cannot be final, perhaps you meant const?");
- else
- {
- OutBuffer buf;
- stcToBuffer(&buf, stc);
- dsym->error("cannot be %s", buf.peekChars());
- }
- dsym->storage_class &= ~stc; // strip off
- }
-
- if (dsym->storage_class & STCscope)
- {
- StorageClass stc = dsym->storage_class & (STCstatic | STCextern | STCmanifest | STCtls | STCgshared);
- if (stc)
- {
- OutBuffer buf;
- stcToBuffer(&buf, stc);
- dsym->error("cannot be `scope` and `%s`", buf.peekChars());
- }
- else if (dsym->isMember())
- {
- dsym->error("field cannot be `scope`");
- }
- else if (!dsym->type->hasPointers())
- {
- dsym->storage_class &= ~STCscope; // silently ignore; may occur in generic code
- }
- }
-
- if (dsym->storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared | STCctfe))
- {
- }
- else
- {
- AggregateDeclaration *aad = parent->isAggregateDeclaration();
- if (aad)
- {
- if (global.params.vfield &&
- dsym->storage_class & (STCconst | STCimmutable) && dsym->_init && !dsym->_init->isVoidInitializer())
- {
- const char *s = (dsym->storage_class & STCimmutable) ? "immutable" : "const";
- message(dsym->loc, "`%s.%s` is `%s` field", ad->toPrettyChars(), dsym->toChars(), s);
- }
- dsym->storage_class |= STCfield;
- if (tbn->ty == Tstruct && ((TypeStruct *)tbn)->sym->noDefaultCtor)
- {
- if (!dsym->isThisDeclaration() && !dsym->_init)
- aad->noDefaultCtor = true;
- }
- }
-
- InterfaceDeclaration *id = parent->isInterfaceDeclaration();
- if (id)
- {
- dsym->error("field not allowed in interface");
- }
- else if (aad && aad->sizeok == SIZEOKdone)
- {
- dsym->error("cannot be further field because it will change the determined %s size", aad->toChars());
- }
-
- /* Templates cannot add fields to aggregates
- */
- TemplateInstance *ti = parent->isTemplateInstance();
- if (ti)
- {
- // Take care of nested templates
- while (1)
- {
- TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance();
- if (!ti2)
- break;
- ti = ti2;
- }
-
- // If it's a member template
- AggregateDeclaration *ad2 = ti->tempdecl->isMember();
- if (ad2 && dsym->storage_class != STCundefined)
- {
- dsym->error("cannot use template to add field to aggregate `%s`", ad2->toChars());
- }
- }
- }
-
- if ((dsym->storage_class & (STCref | STCparameter | STCforeach | STCtemp | STCresult)) == STCref && dsym->ident != Id::This)
- {
- dsym->error("only parameters or foreach declarations can be ref");
- }
-
- if (dsym->type->hasWild())
- {
- if (dsym->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield) ||
- dsym->isDataseg()
- )
- {
- dsym->error("only parameters or stack based variables can be inout");
- }
- FuncDeclaration *func = sc->func;
- if (func)
- {
- if (func->fes)
- func = func->fes->func;
- bool isWild = false;
- for (FuncDeclaration *fd = func; fd; fd = fd->toParent2()->isFuncDeclaration())
- {
- if (((TypeFunction *)fd->type)->iswild)
- {
- isWild = true;
- break;
- }
- }
- if (!isWild)
- {
- dsym->error("inout variables can only be declared inside inout functions");
- }
- }
- }
-
- if (!(dsym->storage_class & (STCctfe | STCref | STCresult)) && tbn->ty == Tstruct &&
- ((TypeStruct *)tbn)->sym->noDefaultCtor)
- {
- if (!dsym->_init)
- {
- if (dsym->isField())
- {
- /* For fields, we'll check the constructor later to make sure it is initialized
- */
- dsym->storage_class |= STCnodefaultctor;
- }
- else if (dsym->storage_class & STCparameter)
- ;
- else
- dsym->error("default construction is disabled for type %s", dsym->type->toChars());
- }
- }
-
- FuncDeclaration *fd = parent->isFuncDeclaration();
- if (dsym->type->isscope() && !(dsym->storage_class & STCnodtor))
- {
- if (dsym->storage_class & (STCfield | STCout | STCref | STCstatic | STCmanifest | STCtls | STCgshared) || !fd)
- {
- dsym->error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope");
- }
-
- if (!(dsym->storage_class & STCscope))
- {
- if (!(dsym->storage_class & STCparameter) && dsym->ident != Id::withSym)
- dsym->error("reference to scope class must be scope");
- }
- }
-
- // Calculate type size + safety checks
- if (sc->func && !sc->intypeof)
- {
- if (dsym->_init && dsym->_init->isVoidInitializer() && dsym->type->hasPointers()) // get type size
- {
- if (sc->func->setUnsafe())
- dsym->error("void initializers for pointers not allowed in safe functions");
- }
- else if (!dsym->_init &&
- !(dsym->storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield | STCparameter)) &&
- dsym->type->hasVoidInitPointers())
- {
- if (sc->func->setUnsafe())
- dsym->error("void initializers for pointers not allowed in safe functions");
- }
- }
-
- if (!dsym->_init && !fd)
- {
- // If not mutable, initializable by constructor only
- dsym->storage_class |= STCctorinit;
- }
-
- if (dsym->_init)
- dsym->storage_class |= STCinit; // remember we had an explicit initializer
- else if (dsym->storage_class & STCmanifest)
- dsym->error("manifest constants must have initializers");
-
- bool isBlit = false;
- d_uns64 sz = 0;
- if (!dsym->_init && !sc->inunion && !(dsym->storage_class & (STCstatic | STCgshared | STCextern)) && fd &&
- (!(dsym->storage_class & (STCfield | STCin | STCforeach | STCparameter | STCresult))
- || (dsym->storage_class & STCout)) &&
- (sz = dsym->type->size()) != 0)
- {
- // Provide a default initializer
- //printf("Providing default initializer for '%s'\n", dsym->toChars());
- if (sz == SIZE_INVALID && dsym->type->ty != Terror)
- dsym->error("size of type %s is invalid", dsym->type->toChars());
-
- Type *tv = dsym->type;
- while (tv->ty == Tsarray) // Don't skip Tenum
- tv = tv->nextOf();
- if (tv->needsNested())
- {
- /* Nested struct requires valid enclosing frame pointer.
- * In StructLiteralExp::toElem(), it's calculated.
- */
- assert(tv->toBasetype()->ty == Tstruct);
- checkFrameAccess(dsym->loc, sc, ((TypeStruct *)tbn)->sym);
-
- Expression *e = tv->defaultInitLiteral(dsym->loc);
- e = new BlitExp(dsym->loc, new VarExp(dsym->loc, dsym), e);
- e = expressionSemantic(e, sc);
- dsym->_init = new ExpInitializer(dsym->loc, e);
- goto Ldtor;
- }
- if (tv->ty == Tstruct && ((TypeStruct *)tv)->sym->zeroInit == 1)
- {
- /* If a struct is all zeros, as a special case
- * set it's initializer to the integer 0.
- * In AssignExp::toElem(), we check for this and issue
- * a memset() to initialize the struct.
- * Must do same check in interpreter.
- */
- Expression *e = new IntegerExp(dsym->loc, 0, Type::tint32);
- e = new BlitExp(dsym->loc, new VarExp(dsym->loc, dsym), e);
- e->type = dsym->type; // don't type check this, it would fail
- dsym->_init = new ExpInitializer(dsym->loc, e);
- goto Ldtor;
- }
- if (dsym->type->baseElemOf()->ty == Tvoid)
- {
- dsym->error("%s does not have a default initializer", dsym->type->toChars());
- }
- else if (Expression *e = dsym->type->defaultInit(dsym->loc))
- {
- dsym->_init = new ExpInitializer(dsym->loc, e);
- }
- // Default initializer is always a blit
- isBlit = true;
- }
-
- if (dsym->_init)
- {
- sc = sc->push();
- sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCnogc | STCref | STCdisable);
-
- ExpInitializer *ei = dsym->_init->isExpInitializer();
- if (ei) // Bugzilla 13424: Preset the required type to fail in FuncLiteralDeclaration::semantic3
- ei->exp = inferType(ei->exp, dsym->type);
-
- // If inside function, there is no semantic3() call
- if (sc->func || sc->intypeof == 1)
- {
- // If local variable, use AssignExp to handle all the various
- // possibilities.
- if (fd &&
- !(dsym->storage_class & (STCmanifest | STCstatic | STCtls | STCgshared | STCextern)) &&
- !dsym->_init->isVoidInitializer())
- {
- //printf("fd = '%s', var = '%s'\n", fd->toChars(), dsym->toChars());
- if (!ei)
- {
- ArrayInitializer *ai = dsym->_init->isArrayInitializer();
- Expression *e;
- if (ai && tb->ty == Taarray)
- e = ai->toAssocArrayLiteral();
- else
- e = initializerToExpression(dsym->_init);
- if (!e)
- {
- // Run semantic, but don't need to interpret
- dsym->_init = initializerSemantic(dsym->_init, sc, dsym->type, INITnointerpret);
- e = initializerToExpression(dsym->_init);
- if (!e)
- {
- dsym->error("is not a static and cannot have static initializer");
- e = new ErrorExp();
- }
- }
- ei = new ExpInitializer(dsym->_init->loc, e);
- dsym->_init = ei;
- }
-
- Expression *exp = ei->exp;
- Expression *e1 = new VarExp(dsym->loc, dsym);
- if (isBlit)
- exp = new BlitExp(dsym->loc, e1, exp);
- else
- exp = new ConstructExp(dsym->loc, e1, exp);
- dsym->canassign++;
- exp = expressionSemantic(exp, sc);
- dsym->canassign--;
- exp = exp->optimize(WANTvalue);
-
- if (exp->op == TOKerror)
- {
- dsym->_init = new ErrorInitializer();
- ei = NULL;
- }
- else
- ei->exp = exp;
-
- if (ei && dsym->isScope())
- {
- Expression *ex = ei->exp;
- while (ex->op == TOKcomma)
- ex = ((CommaExp *)ex)->e2;
- if (ex->op == TOKblit || ex->op == TOKconstruct)
- ex = ((AssignExp *)ex)->e2;
- if (ex->op == TOKnew)
- {
- // See if initializer is a NewExp that can be allocated on the stack
- NewExp *ne = (NewExp *)ex;
- if (dsym->type->toBasetype()->ty == Tclass)
- {
- if (ne->newargs && ne->newargs->length > 1)
- {
- dsym->mynew = true;
- }
- else
- {
- ne->onstack = true;
- dsym->onstack = true;
- }
- }
- }
- else if (ex->op == TOKfunction)
- {
- // or a delegate that doesn't escape a reference to the function
- FuncDeclaration *f = ((FuncExp *)ex)->fd;
- f->tookAddressOf--;
- }
- }
- }
- else
- {
- // Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof
- dsym->_init = initializerSemantic(dsym->_init, sc, dsym->type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
- }
- }
- else if (parent->isAggregateDeclaration())
- {
- dsym->_scope = scx ? scx : sc->copy();
- dsym->_scope->setNoFree();
- }
- else if (dsym->storage_class & (STCconst | STCimmutable | STCmanifest) ||
- dsym->type->isConst() || dsym->type->isImmutable())
- {
- /* Because we may need the results of a const declaration in a
- * subsequent type, such as an array dimension, before semantic2()
- * gets ordinarily run, try to run semantic2() now.
- * Ignore failure.
- */
-
- if (!inferred)
- {
- unsigned errors = global.errors;
- dsym->inuse++;
- if (ei)
- {
- Expression *exp = ei->exp->syntaxCopy();
-
- bool needctfe = dsym->isDataseg() || (dsym->storage_class & STCmanifest);
- if (needctfe) sc = sc->startCTFE();
- exp = expressionSemantic(exp, sc);
- exp = resolveProperties(sc, exp);
- if (needctfe) sc = sc->endCTFE();
-
- Type *tb2 = dsym->type->toBasetype();
- Type *ti = exp->type->toBasetype();
-
- /* The problem is the following code:
- * struct CopyTest {
- * double x;
- * this(double a) { x = a * 10.0;}
- * this(this) { x += 2.0; }
- * }
- * const CopyTest z = CopyTest(5.3); // ok
- * const CopyTest w = z; // not ok, postblit not run
- * static assert(w.x == 55.0);
- * because the postblit doesn't get run on the initialization of w.
- */
- if (ti->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)ti)->sym;
- /* Look to see if initializer involves a copy constructor
- * (which implies a postblit)
- */
- // there is a copy constructor
- // and exp is the same struct
- if (sd->postblit &&
- tb2->toDsymbol(NULL) == sd)
- {
- // The only allowable initializer is a (non-copy) constructor
- if (exp->isLvalue())
- dsym->error("of type struct %s uses this(this), which is not allowed in static initialization", tb2->toChars());
- }
- }
- ei->exp = exp;
- }
- dsym->_init = initializerSemantic(dsym->_init, sc, dsym->type, INITinterpret);
- dsym->inuse--;
- if (global.errors > errors)
- {
- dsym->_init = new ErrorInitializer();
- dsym->type = Type::terror;
- }
- }
- else
- {
- dsym->_scope = scx ? scx : sc->copy();
- dsym->_scope->setNoFree();
- }
- }
- sc = sc->pop();
- }
-
- Ldtor:
- /* Build code to execute destruction, if necessary
- */
- dsym->edtor = dsym->callScopeDtor(sc);
- if (dsym->edtor)
- {
- if (sc->func && dsym->storage_class & (STCstatic | STCgshared))
- dsym->edtor = expressionSemantic(dsym->edtor, sc->_module->_scope);
- else
- dsym->edtor = expressionSemantic(dsym->edtor, sc);
-
- #if 0 // currently disabled because of std.stdio.stdin, stdout and stderr
- if (dsym->isDataseg() && !(dsym->storage_class & STCextern))
- dsym->error("static storage variables cannot have destructors");
- #endif
- }
-
- dsym->semanticRun = PASSsemanticdone;
-
- if (dsym->type->toBasetype()->ty == Terror)
- dsym->errors = true;
-
- if (sc->scopesym && !sc->scopesym->isAggregateDeclaration())
- {
- for (ScopeDsymbol *sym = sc->scopesym; sym && dsym->endlinnum == 0;
- sym = sym->parent ? sym->parent->isScopeDsymbol() : NULL)
- dsym->endlinnum = sym->endlinnum;
- }
- }
-
- void visit(TypeInfoDeclaration *dsym)
- {
- assert(dsym->linkage == LINKc);
- }
-
- void visit(Import *imp)
- {
- //printf("Import::semantic('%s') %s\n", toPrettyChars(), imp->id->toChars());
- if (imp->semanticRun > PASSinit)
- return;
-
- if (imp->_scope)
- {
- sc = imp->_scope;
- imp->_scope = NULL;
- }
- if (!sc)
- return;
-
- imp->semanticRun = PASSsemantic;
-
- // Load if not already done so
- if (!imp->mod)
- {
- imp->load(sc);
- if (imp->mod)
- imp->mod->importAll(NULL);
- }
-
- if (imp->mod)
- {
- // Modules need a list of each imported module
- //printf("%s imports %s\n", sc->_module->toChars(), imp->mod->toChars());
- sc->_module->aimports.push(imp->mod);
-
- if (sc->explicitProtection)
- imp->protection = sc->protection;
-
- if (!imp->aliasId && !imp->names.length) // neither a selective nor a renamed import
- {
- ScopeDsymbol *scopesym = NULL;
- if (sc->explicitProtection)
- imp->protection = sc->protection.kind;
- for (Scope *scd = sc; scd; scd = scd->enclosing)
- {
- if (!scd->scopesym)
- continue;
- scopesym = scd->scopesym;
- break;
- }
-
- if (!imp->isstatic)
- {
- scopesym->importScope(imp->mod, imp->protection);
- }
-
- imp->addPackageAccess(scopesym);
- }
-
- dsymbolSemantic(imp->mod, NULL);
-
- if (imp->mod->needmoduleinfo)
- {
- //printf("module4 %s because of %s\n", sc->_module->toChars(), imp->mod->toChars());
- sc->_module->needmoduleinfo = 1;
- }
-
- sc = sc->push(imp->mod);
- sc->protection = imp->protection;
- for (size_t i = 0; i < imp->aliasdecls.length; i++)
- {
- AliasDeclaration *ad = imp->aliasdecls[i];
- //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), imp->aliases[i]->toChars(), imp->names[i]->toChars(), ad->_scope);
- Dsymbol *sym = imp->mod->search(imp->loc, imp->names[i], IgnorePrivateImports);
- if (sym)
- {
- if (!symbolIsVisible(sc, sym))
- imp->mod->error(imp->loc, "member `%s` is not visible from module `%s`",
- imp->names[i]->toChars(), sc->_module->toChars());
- dsymbolSemantic(ad, sc);
- // If the import declaration is in non-root module,
- // analysis of the aliased symbol is deferred.
- // Therefore, don't see the ad->aliassym or ad->type here.
- }
- else
- {
- Dsymbol *s = imp->mod->search_correct(imp->names[i]);
- if (s)
- imp->mod->error(imp->loc, "import `%s` not found, did you mean %s `%s`?", imp->names[i]->toChars(), s->kind(), s->toPrettyChars());
- else
- imp->mod->error(imp->loc, "import `%s` not found", imp->names[i]->toChars());
- ad->type = Type::terror;
- }
- }
- sc = sc->pop();
- }
-
- imp->semanticRun = PASSsemanticdone;
-
- // object self-imports itself, so skip that (Bugzilla 7547)
- // don't list pseudo modules __entrypoint.d, __main.d (Bugzilla 11117, 11164)
- if (global.params.moduleDeps != NULL &&
- !(imp->id == Id::object && sc->_module->ident == Id::object) &&
- sc->_module->ident != Id::entrypoint &&
- strcmp(sc->_module->ident->toChars(), "__main") != 0)
- {
- /* The grammar of the file is:
- * ImportDeclaration
- * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
- * ModuleAliasIdentifier ] "\n"
- *
- * BasicImportDeclaration
- * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string"
- * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
- *
- * FilePath
- * - any string with '(', ')' and '\' escaped with the '\' character
- */
-
- OutBuffer *ob = global.params.moduleDeps;
- Module* imod = sc->instantiatingModule();
- if (!global.params.moduleDepsFile.length)
- ob->writestring("depsImport ");
- ob->writestring(imod->toPrettyChars());
- ob->writestring(" (");
- escapePath(ob, imod->srcfile->toChars());
- ob->writestring(") : ");
-
- // use protection instead of sc->protection because it couldn't be
- // resolved yet, see the comment above
- protectionToBuffer(ob, imp->protection);
- ob->writeByte(' ');
- if (imp->isstatic)
- {
- stcToBuffer(ob, STCstatic);
- ob->writeByte(' ');
- }
- ob->writestring(": ");
-
- if (imp->packages)
- {
- for (size_t i = 0; i < imp->packages->length; i++)
- {
- Identifier *pid = (*imp->packages)[i];
- ob->printf("%s.", pid->toChars());
- }
- }
-
- ob->writestring(imp->id->toChars());
- ob->writestring(" (");
- if (imp->mod)
- escapePath(ob, imp->mod->srcfile->toChars());
- else
- ob->writestring("???");
- ob->writeByte(')');
-
- for (size_t i = 0; i < imp->names.length; i++)
- {
- if (i == 0)
- ob->writeByte(':');
- else
- ob->writeByte(',');
-
- Identifier *name = imp->names[i];
- Identifier *alias = imp->aliases[i];
-
- if (!alias)
- {
- ob->printf("%s", name->toChars());
- alias = name;
- }
- else
- ob->printf("%s=%s", alias->toChars(), name->toChars());
- }
-
- if (imp->aliasId)
- ob->printf(" -> %s", imp->aliasId->toChars());
-
- ob->writenl();
- }
-
- //printf("-Import::semantic('%s'), pkg = %p\n", imp->toChars(), imp->pkg);
- }
-
- void attribSemantic(AttribDeclaration *ad)
- {
- if (ad->semanticRun != PASSinit)
- return;
- ad->semanticRun = PASSsemantic;
- Dsymbols *d = ad->include(sc);
- //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d);
- if (d)
- {
- Scope *sc2 = ad->newScope(sc);
- bool errors = false;
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- dsymbolSemantic(s, sc2);
- errors |= s->errors;
- }
- ad->errors |= errors;
- if (sc2 != sc)
- sc2->pop();
- }
- ad->semanticRun = PASSsemanticdone;
- }
-
- void visit(AttribDeclaration *atd)
- {
- attribSemantic(atd);
- }
-
- void visit(AnonDeclaration *scd)
- {
- //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", scd);
- assert(sc->parent);
- Dsymbol *p = sc->parent->pastMixin();
- AggregateDeclaration *ad = p->isAggregateDeclaration();
- if (!ad)
- {
- error(scd->loc, "%s can only be a part of an aggregate, not %s %s",
- scd->kind(), p->kind(), p->toChars());
- scd->errors = true;
- return;
- }
-
- if (scd->decl)
- {
- sc = sc->push();
- sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared);
- sc->inunion = scd->isunion;
- sc->flags = 0;
-
- for (size_t i = 0; i < scd->decl->length; i++)
- {
- Dsymbol *s = (*scd->decl)[i];
- dsymbolSemantic(s, sc);
- }
- sc = sc->pop();
- }
- }
-
- void visit(PragmaDeclaration *pd)
- {
- // Should be merged with PragmaStatement
- //printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
- if (pd->ident == Id::msg)
- {
- if (pd->args)
- {
- for (size_t i = 0; i < pd->args->length; i++)
- {
- Expression *e = (*pd->args)[i];
-
- sc = sc->startCTFE();
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
- sc = sc->endCTFE();
- e = ctfeInterpretForPragmaMsg(e);
- if (e->op == TOKerror)
- {
- errorSupplemental(pd->loc, "while evaluating pragma(msg, %s)", (*pd->args)[i]->toChars());
- return;
- }
- StringExp *se = e->toStringExp();
- if (se)
- {
- se = se->toUTF8(sc);
- fprintf(stderr, "%.*s", (int)se->len, (char *)se->string);
- }
- else
- fprintf(stderr, "%s", e->toChars());
- }
- fprintf(stderr, "\n");
- }
- goto Lnodecl;
- }
- else if (pd->ident == Id::lib)
- {
- if (!pd->args || pd->args->length != 1)
- pd->error("string expected for library name");
- else
- {
- StringExp *se = semanticString(sc, (*pd->args)[0], "library name");
- if (!se)
- goto Lnodecl;
- (*pd->args)[0] = se;
-
- char *name = (char *)mem.xmalloc(se->len + 1);
- memcpy(name, se->string, se->len);
- name[se->len] = 0;
- if (global.params.verbose)
- message("library %s", name);
- if (global.params.moduleDeps && !global.params.moduleDepsFile.length)
- {
- OutBuffer *ob = global.params.moduleDeps;
- Module *imod = sc->instantiatingModule();
- ob->writestring("depsLib ");
- ob->writestring(imod->toPrettyChars());
- ob->writestring(" (");
- escapePath(ob, imod->srcfile->toChars());
- ob->writestring(") : ");
- ob->writestring((char *) name);
- ob->writenl();
- }
- mem.xfree(name);
- }
- goto Lnodecl;
- }
- else if (pd->ident == Id::startaddress)
- {
- if (!pd->args || pd->args->length != 1)
- pd->error("function name expected for start address");
- else
- {
- /* Bugzilla 11980:
- * resolveProperties and ctfeInterpret call are not necessary.
- */
- Expression *e = (*pd->args)[0];
-
- sc = sc->startCTFE();
- e = expressionSemantic(e, sc);
- sc = sc->endCTFE();
-
- (*pd->args)[0] = e;
- Dsymbol *sa = getDsymbol(e);
- if (!sa || !sa->isFuncDeclaration())
- pd->error("function name expected for start address, not `%s`", e->toChars());
- }
- goto Lnodecl;
- }
- else if (pd->ident == Id::Pinline)
- {
- goto Ldecl;
- }
- else if (pd->ident == Id::mangle)
- {
- if (!pd->args)
- pd->args = new Expressions();
- if (pd->args->length != 1)
- {
- pd->error("string expected for mangled name");
- pd->args->setDim(1);
- (*pd->args)[0] = new ErrorExp(); // error recovery
- goto Ldecl;
- }
-
- StringExp *se = semanticString(sc, (*pd->args)[0], "mangled name");
- if (!se)
- goto Ldecl;
- (*pd->args)[0] = se; // Will be used for later
-
- if (!se->len)
- {
- pd->error("zero-length string not allowed for mangled name");
- goto Ldecl;
- }
- if (se->sz != 1)
- {
- pd->error("mangled name characters can only be of type char");
- goto Ldecl;
- }
-
- /* Note: D language specification should not have any assumption about backend
- * implementation. Ideally pragma(mangle) can accept a string of any content.
- *
- * Therefore, this validation is compiler implementation specific.
- */
- for (size_t i = 0; i < se->len; )
- {
- utf8_t *p = (utf8_t *)se->string;
- dchar_t c = p[i];
- if (c < 0x80)
- {
- if ((c >= 'A' && c <= 'Z') ||
- (c >= 'a' && c <= 'z') ||
- (c >= '0' && c <= '9') ||
- (c != 0 && strchr("$%().:?@[]_", c)))
- {
- ++i;
- continue;
- }
- else
- {
- pd->error("char 0x%02x not allowed in mangled name", c);
- break;
- }
- }
-
- if (const char* msg = utf_decodeChar((utf8_t *)se->string, se->len, &i, &c))
- {
- pd->error("%s", msg);
- break;
- }
-
- if (!isUniAlpha(c))
- {
- pd->error("char 0x%04x not allowed in mangled name", c);
- break;
- }
- }
- }
- else if (pd->ident == Id::printf || pd->ident == Id::scanf)
- {
- if (pd->args && pd->args->length != 0)
- pd->error("takes no argument");
- goto Ldecl;
- }
- else if (global.params.ignoreUnsupportedPragmas)
- {
- if (global.params.verbose)
- {
- /* Print unrecognized pragmas
- */
- OutBuffer buf;
- buf.writestring(pd->ident->toChars());
- if (pd->args)
- {
- for (size_t i = 0; i < pd->args->length; i++)
- {
- Expression *e = (*pd->args)[i];
-
- sc = sc->startCTFE();
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
- sc = sc->endCTFE();
-
- e = e->ctfeInterpret();
- if (i == 0)
- buf.writestring(" (");
- else
- buf.writeByte(',');
- buf.writestring(e->toChars());
- }
- if (pd->args->length)
- buf.writeByte(')');
- }
- message("pragma %s", buf.peekChars());
- }
- goto Lnodecl;
- }
- else
- error(pd->loc, "unrecognized pragma(%s)", pd->ident->toChars());
-
- Ldecl:
- if (pd->decl)
- {
- Scope *sc2 = pd->newScope(sc);
-
- for (size_t i = 0; i < pd->decl->length; i++)
- {
- Dsymbol *s = (*pd->decl)[i];
-
- dsymbolSemantic(s, sc2);
-
- if (pd->ident == Id::mangle)
- {
- assert(pd->args && pd->args->length == 1);
- if (StringExp *se = (*pd->args)[0]->toStringExp())
- {
- char *name = (char *)mem.xmalloc(se->len + 1);
- memcpy(name, se->string, se->len);
- name[se->len] = 0;
-
- unsigned cnt = setMangleOverride(s, name);
- if (cnt > 1)
- pd->error("can only apply to a single declaration");
- }
- }
- }
-
- if (sc2 != sc)
- sc2->pop();
- }
- return;
-
- Lnodecl:
- if (pd->decl)
- {
- pd->error("pragma is missing closing `;`");
- goto Ldecl; // do them anyway, to avoid segfaults.
- }
- }
-
- void visit(StaticIfDeclaration *sid)
- {
- attribSemantic(sid);
- }
-
- void visit(StaticForeachDeclaration *sfd)
- {
- attribSemantic(sfd);
- }
-
- Dsymbols *compileIt(CompileDeclaration *cd)
- {
- //printf("CompileDeclaration::compileIt(loc = %d) %s\n", cd->loc.linnum, cd->exp->toChars());
- OutBuffer buf;
- if (expressionsToString(buf, sc, cd->exps))
- return NULL;
-
- unsigned errors = global.errors;
- const size_t len = buf.length();
- const char *str = buf.extractChars();
- Parser p(cd->loc, sc->_module, (const utf8_t *)str, len, false);
- p.nextToken();
-
- Dsymbols *d = p.parseDeclDefs(0);
- if (global.errors != errors)
- return NULL;
-
- if (p.token.value != TOKeof)
- {
- cd->error("incomplete mixin declaration (%s)", str);
- return NULL;
- }
- return d;
- }
-
- void visit(CompileDeclaration *cd)
- {
- //printf("CompileDeclaration::semantic()\n");
- if (!cd->compiled)
- {
- cd->decl = compileIt(cd);
- cd->AttribDeclaration::addMember(sc, cd->scopesym);
- cd->compiled = true;
-
- if (cd->_scope && cd->decl)
- {
- for (size_t i = 0; i < cd->decl->length; i++)
- {
- Dsymbol *s = (*cd->decl)[i];
- s->setScope(cd->_scope);
- }
- }
- }
- attribSemantic(cd);
- }
-
- void visit(UserAttributeDeclaration *uad)
- {
- //printf("UserAttributeDeclaration::semantic() %p\n", this);
- if (uad->decl && !uad->_scope)
- uad->Dsymbol::setScope(sc); // for function local symbols
-
- attribSemantic(uad);
- }
-
- void visit(StaticAssert *sa)
- {
- if (sa->semanticRun < PASSsemanticdone)
- sa->semanticRun = PASSsemanticdone;
- }
-
- void visit(DebugSymbol *ds)
- {
- //printf("DebugSymbol::semantic() %s\n", ds->toChars());
- if (ds->semanticRun < PASSsemanticdone)
- ds->semanticRun = PASSsemanticdone;
- }
-
- void visit(VersionSymbol *vs)
- {
- if (vs->semanticRun < PASSsemanticdone)
- vs->semanticRun = PASSsemanticdone;
- }
-
- void visit(Package *pkg)
- {
- if (pkg->semanticRun < PASSsemanticdone)
- pkg->semanticRun = PASSsemanticdone;
- }
-
- void visit(Module *m)
- {
- if (m->semanticRun != PASSinit)
- return;
-
- //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, m->toChars(), parent);
- m->semanticRun = PASSsemantic;
-
- // Note that modules get their own scope, from scratch.
- // This is so regardless of where in the syntax a module
- // gets imported, it is unaffected by context.
- Scope *sc = m->_scope; // see if already got one from importAll()
- if (!sc)
- {
- sc = Scope::createGlobal(m); // create root scope
- }
-
- //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage);
-
- // Pass 1 semantic routines: do public side of the definition
- for (size_t i = 0; i < m->members->length; i++)
- {
- Dsymbol *s = (*m->members)[i];
-
- //printf("\tModule('%s'): '%s'.semantic()\n", m->toChars(), s->toChars());
- dsymbolSemantic(s, sc);
- m->runDeferredSemantic();
- }
-
- if (m->userAttribDecl)
- {
- dsymbolSemantic(m->userAttribDecl, sc);
- }
-
- if (!m->_scope)
- {
- sc = sc->pop();
- sc->pop(); // 2 pops because Scope::createGlobal() created 2
- }
- m->semanticRun = PASSsemanticdone;
- //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", m, m->toChars(), parent);
- }
-
- void visit(EnumDeclaration *ed)
- {
- //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), ed->toChars());
- //printf("EnumDeclaration::semantic() %p %s\n", ed, ed->toChars());
- if (ed->semanticRun >= PASSsemanticdone)
- return; // semantic() already completed
- if (ed->semanticRun == PASSsemantic)
- {
- assert(ed->memtype);
- error(ed->loc, "circular reference to enum base type %s", ed->memtype->toChars());
- ed->errors = true;
- ed->semanticRun = PASSsemanticdone;
- return;
- }
- unsigned dprogress_save = Module::dprogress;
-
- Scope *scx = NULL;
- if (ed->_scope)
- {
- sc = ed->_scope;
- scx = ed->_scope; // save so we don't make redundant copies
- ed->_scope = NULL;
- }
-
- if (!sc)
- return;
-
- ed->parent = sc->parent;
- ed->type = typeSemantic(ed->type, ed->loc, sc);
-
- ed->protection = sc->protection;
- if (sc->stc & STCdeprecated)
- ed->isdeprecated = true;
- ed->userAttribDecl = sc->userAttribDecl;
-
- ed->semanticRun = PASSsemantic;
-
- if (!ed->members && !ed->memtype) // enum ident;
- {
- ed->semanticRun = PASSsemanticdone;
- return;
- }
-
- if (!ed->symtab)
- ed->symtab = new DsymbolTable();
-
- /* The separate, and distinct, cases are:
- * 1. enum { ... }
- * 2. enum : memtype { ... }
- * 3. enum ident { ... }
- * 4. enum ident : memtype { ... }
- * 5. enum ident : memtype;
- * 6. enum ident;
- */
-
- if (ed->memtype)
- {
- ed->memtype = typeSemantic(ed->memtype, ed->loc, sc);
-
- /* Check to see if memtype is forward referenced
- */
- if (ed->memtype->ty == Tenum)
- {
- EnumDeclaration *sym = (EnumDeclaration *)ed->memtype->toDsymbol(sc);
- if (!sym->memtype || !sym->members || !sym->symtab || sym->_scope)
- {
- // memtype is forward referenced, so try again later
- ed->_scope = scx ? scx : sc->copy();
- ed->_scope->setNoFree();
- Module::addDeferredSemantic(ed);
- Module::dprogress = dprogress_save;
- //printf("\tdeferring %s\n", ed->toChars());
- ed->semanticRun = PASSinit;
- return;
- }
- else
- // Ensure that semantic is run to detect. e.g. invalid forward references
- dsymbolSemantic(sym, sc);
- }
- if (ed->memtype->ty == Tvoid)
- {
- ed->error("base type must not be void");
- ed->memtype = Type::terror;
- }
- if (ed->memtype->ty == Terror)
- {
- ed->errors = true;
- if (ed->members)
- {
- for (size_t i = 0; i < ed->members->length; i++)
- {
- Dsymbol *s = (*ed->members)[i];
- s->errors = true; // poison all the members
- }
- }
- ed->semanticRun = PASSsemanticdone;
- return;
- }
- }
-
- ed->semanticRun = PASSsemanticdone;
-
- if (!ed->members) // enum ident : memtype;
- return;
-
- if (ed->members->length == 0)
- {
- ed->error("enum %s must have at least one member", ed->toChars());
- ed->errors = true;
- return;
- }
-
- Module::dprogress++;
-
- Scope *sce;
- if (ed->isAnonymous())
- sce = sc;
- else
- {
- sce = sc->push(ed);
- sce->parent = ed;
- }
- sce = sce->startCTFE();
- sce->setNoFree(); // needed for getMaxMinValue()
-
- /* Each enum member gets the sce scope
- */
- for (size_t i = 0; i < ed->members->length; i++)
- {
- EnumMember *em = (*ed->members)[i]->isEnumMember();
- if (em)
- em->_scope = sce;
- }
-
- if (!ed->added)
- {
- /* addMember() is not called when the EnumDeclaration appears as a function statement,
- * so we have to do what addMember() does and install the enum members in the right symbol
- * table
- */
- ScopeDsymbol *scopesym = NULL;
- if (ed->isAnonymous())
- {
- /* Anonymous enum members get added to enclosing scope.
- */
- for (Scope *sct = sce; 1; sct = sct->enclosing)
- {
- assert(sct);
- if (sct->scopesym)
- {
- scopesym = sct->scopesym;
- if (!sct->scopesym->symtab)
- sct->scopesym->symtab = new DsymbolTable();
- break;
- }
- }
- }
- else
- {
- // Otherwise enum members are in the EnumDeclaration's symbol table
- scopesym = ed;
- }
-
- for (size_t i = 0; i < ed->members->length; i++)
- {
- EnumMember *em = (*ed->members)[i]->isEnumMember();
- if (em)
- {
- em->ed = ed;
- em->addMember(sc, scopesym);
- }
- }
- }
-
- for (size_t i = 0; i < ed->members->length; i++)
- {
- EnumMember *em = (*ed->members)[i]->isEnumMember();
- if (em)
- dsymbolSemantic(em, em->_scope);
- }
- //printf("defaultval = %lld\n", defaultval);
-
- //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars());
- //printf("members = %s\n", ed->members->toChars());
- }
-
- void visit(EnumMember *em)
- {
- //printf("EnumMember::semantic() %s\n", em->toChars());
- if (em->errors || em->semanticRun >= PASSsemanticdone)
- return;
- if (em->semanticRun == PASSsemantic)
- {
- em->error("circular reference to enum member");
- Lerrors:
- em->errors = true;
- em->semanticRun = PASSsemanticdone;
- return;
- }
- assert(em->ed);
-
- dsymbolSemantic(em->ed, sc);
- if (em->ed->errors)
- goto Lerrors;
-
- if (em->errors || em->semanticRun >= PASSsemanticdone)
- return;
-
- if (em->_scope)
- sc = em->_scope;
- if (!sc)
- return;
-
- em->semanticRun = PASSsemantic;
-
- em->protection = em->ed->isAnonymous() ? em->ed->protection : Prot(Prot::public_);
- em->linkage = LINKd;
- em->storage_class |= STCmanifest;
-
- // https://issues.dlang.org/show_bug.cgi?id=9701
- if (em->ed->isAnonymous())
- {
- if (em->userAttribDecl)
- em->userAttribDecl->userAttribDecl = em->ed->userAttribDecl;
- else
- em->userAttribDecl = em->ed->userAttribDecl;
- }
-
- // The first enum member is special
- bool first = (em == (*em->ed->members)[0]);
-
- if (em->origType)
- {
- em->origType = typeSemantic(em->origType, em->loc, sc);
- em->type = em->origType;
- assert(em->value()); // "type id;" is not a valid enum member declaration
- }
-
- if (em->value())
- {
- Expression *e = em->value();
- assert(e->dyncast() == DYNCAST_EXPRESSION);
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
- e = e->ctfeInterpret();
- if (e->op == TOKerror)
- goto Lerrors;
- if (first && !em->ed->memtype && !em->ed->isAnonymous())
- {
- em->ed->memtype = e->type;
- if (em->ed->memtype->ty == Terror)
- {
- em->ed->errors = true;
- goto Lerrors;
- }
- if (em->ed->memtype->ty != Terror)
- {
- /* Bugzilla 11746: All of named enum members should have same type
- * with the first member. If the following members were referenced
- * during the first member semantic, their types should be unified.
- */
- for (size_t i = 0; i < em->ed->members->length; i++)
- {
- EnumMember *enm = (*em->ed->members)[i]->isEnumMember();
- if (!enm || enm == em || enm->semanticRun < PASSsemanticdone || enm->origType)
- continue;
-
- //printf("[%d] enm = %s, enm->semanticRun = %d\n", i, enm->toChars(), enm->semanticRun);
- Expression *ev = enm->value();
- ev = ev->implicitCastTo(sc, em->ed->memtype);
- ev = ev->ctfeInterpret();
- ev = ev->castTo(sc, em->ed->type);
- if (ev->op == TOKerror)
- em->ed->errors = true;
- enm->value() = ev;
- }
- if (em->ed->errors)
- {
- em->ed->memtype = Type::terror;
- goto Lerrors;
- }
- }
- }
-
- if (em->ed->memtype && !em->origType)
- {
- e = e->implicitCastTo(sc, em->ed->memtype);
- e = e->ctfeInterpret();
-
- // save origValue for better json output
- em->origValue = e;
-
- if (!em->ed->isAnonymous())
- {
- e = e->castTo(sc, em->ed->type);
- e = e->ctfeInterpret();
- }
- }
- else if (em->origType)
- {
- e = e->implicitCastTo(sc, em->origType);
- e = e->ctfeInterpret();
- assert(em->ed->isAnonymous());
-
- // save origValue for better json output
- em->origValue = e;
- }
- em->value() = e;
- }
- else if (first)
- {
- Type *t;
- if (em->ed->memtype)
- t = em->ed->memtype;
- else
- {
- t = Type::tint32;
- if (!em->ed->isAnonymous())
- em->ed->memtype = t;
- }
- Expression *e = new IntegerExp(em->loc, 0, Type::tint32);
- e = e->implicitCastTo(sc, t);
- e = e->ctfeInterpret();
-
- // save origValue for better json output
- em->origValue = e;
-
- if (!em->ed->isAnonymous())
- {
- e = e->castTo(sc, em->ed->type);
- e = e->ctfeInterpret();
- }
- em->value() = e;
- }
- else
- {
- /* Find the previous enum member,
- * and set this to be the previous value + 1
- */
- EnumMember *emprev = NULL;
- for (size_t i = 0; i < em->ed->members->length; i++)
- {
- EnumMember *enm = (*em->ed->members)[i]->isEnumMember();
- if (enm)
- {
- if (enm == em)
- break;
- emprev = enm;
- }
- }
- assert(emprev);
- if (emprev->semanticRun < PASSsemanticdone) // if forward reference
- dsymbolSemantic(emprev, emprev->_scope); // resolve it
- if (emprev->errors)
- goto Lerrors;
-
- Expression *eprev = emprev->value();
- Type *tprev = eprev->type->equals(em->ed->type) ? em->ed->memtype : eprev->type;
-
- Expression *emax = tprev->getProperty(em->ed->loc, Id::max, 0);
- emax = expressionSemantic(emax, sc);
- emax = emax->ctfeInterpret();
-
- // Set value to (eprev + 1).
- // But first check that (eprev != emax)
- assert(eprev);
- Expression *e = new EqualExp(TOKequal, em->loc, eprev, emax);
- e = expressionSemantic(e, sc);
- e = e->ctfeInterpret();
- if (e->toInteger())
- {
- em->error("initialization with (%s.%s + 1) causes overflow for type `%s`", emprev->ed->toChars(), emprev->toChars(), em->ed->type->toBasetype()->toChars());
- goto Lerrors;
- }
-
- // Now set e to (eprev + 1)
- e = new AddExp(em->loc, eprev, new IntegerExp(em->loc, 1, Type::tint32));
- e = expressionSemantic(e, sc);
- e = e->castTo(sc, eprev->type);
- e = e->ctfeInterpret();
-
- // save origValue (without cast) for better json output
- if (e->op != TOKerror) // avoid duplicate diagnostics
- {
- assert(emprev->origValue);
- em->origValue = new AddExp(em->loc, emprev->origValue, new IntegerExp(em->loc, 1, Type::tint32));
- em->origValue = expressionSemantic(em->origValue, sc);
- em->origValue = em->origValue->ctfeInterpret();
- }
-
- if (e->op == TOKerror)
- goto Lerrors;
- if (e->type->isfloating())
- {
- // Check that e != eprev (not always true for floats)
- Expression *etest = new EqualExp(TOKequal, em->loc, e, eprev);
- etest = expressionSemantic(etest, sc);
- etest = etest->ctfeInterpret();
- if (etest->toInteger())
- {
- em->error("has inexact value, due to loss of precision");
- goto Lerrors;
- }
- }
- em->value() = e;
- }
- if (!em->origType)
- em->type = em->value()->type;
-
- assert(em->origValue);
- em->semanticRun = PASSsemanticdone;
- }
-
- void visit(TemplateDeclaration *tempdecl)
- {
- if (tempdecl->semanticRun != PASSinit)
- return; // semantic() already run
-
- // Remember templates defined in module object that we need to know about
- if (sc->_module && sc->_module->ident == Id::object)
- {
- if (tempdecl->ident == Id::RTInfo)
- Type::rtinfo = tempdecl;
- }
-
- /* Remember Scope for later instantiations, but make
- * a copy since attributes can change.
- */
- if (!tempdecl->_scope)
- {
- tempdecl->_scope = sc->copy();
- tempdecl->_scope->setNoFree();
- }
-
- tempdecl->semanticRun = PASSsemantic;
-
- tempdecl->parent = sc->parent;
- tempdecl->protection = sc->protection;
- tempdecl->isstatic = tempdecl->toParent()->isModule() || (tempdecl->_scope->stc & STCstatic);
-
- if (!tempdecl->isstatic)
- {
- if (AggregateDeclaration *ad = tempdecl->parent->pastMixin()->isAggregateDeclaration())
- ad->makeNested();
- }
-
- // Set up scope for parameters
- ScopeDsymbol *paramsym = new ScopeDsymbol();
- paramsym->parent = tempdecl->parent;
- Scope *paramscope = sc->push(paramsym);
- paramscope->stc = 0;
-
- if (global.params.doDocComments)
- {
- tempdecl->origParameters = new TemplateParameters();
- tempdecl->origParameters->setDim(tempdecl->parameters->length);
- for (size_t i = 0; i < tempdecl->parameters->length; i++)
- {
- TemplateParameter *tp = (*tempdecl->parameters)[i];
- (*tempdecl->origParameters)[i] = tp->syntaxCopy();
- }
- }
-
- for (size_t i = 0; i < tempdecl->parameters->length; i++)
- {
- TemplateParameter *tp = (*tempdecl->parameters)[i];
-
- if (!tp->declareParameter(paramscope))
- {
- error(tp->loc, "parameter `%s` multiply defined", tp->ident->toChars());
- tempdecl->errors = true;
- }
- if (!tpsemantic(tp, paramscope, tempdecl->parameters))
- {
- tempdecl->errors = true;
- }
- if (i + 1 != tempdecl->parameters->length && tp->isTemplateTupleParameter())
- {
- tempdecl->error("template tuple parameter must be last one");
- tempdecl->errors = true;
- }
- }
-
- /* Calculate TemplateParameter::dependent
- */
- TemplateParameters tparams;
- tparams.setDim(1);
- for (size_t i = 0; i < tempdecl->parameters->length; i++)
- {
- TemplateParameter *tp = (*tempdecl->parameters)[i];
- tparams[0] = tp;
-
- for (size_t j = 0; j < tempdecl->parameters->length; j++)
- {
- // Skip cases like: X(T : T)
- if (i == j)
- continue;
-
- if (TemplateTypeParameter *ttp = (*tempdecl->parameters)[j]->isTemplateTypeParameter())
- {
- if (reliesOnTident(ttp->specType, &tparams))
- tp->dependent = true;
- }
- else if (TemplateAliasParameter *tap = (*tempdecl->parameters)[j]->isTemplateAliasParameter())
- {
- if (reliesOnTident(tap->specType, &tparams) ||
- reliesOnTident(isType(tap->specAlias), &tparams))
- {
- tp->dependent = true;
- }
- }
- }
- }
-
- paramscope->pop();
-
- // Compute again
- tempdecl->onemember = NULL;
- if (tempdecl->members)
- {
- Dsymbol *s;
- if (Dsymbol::oneMembers(tempdecl->members, &s, tempdecl->ident) && s)
- {
- tempdecl->onemember = s;
- s->parent = tempdecl;
- }
- }
-
- /* BUG: should check:
- * o no virtual functions or non-static data members of classes
- */
- tempdecl->semanticRun = PASSsemanticdone;
- }
-
- void visit(TemplateInstance *ti)
- {
- templateInstanceSemantic(ti, sc, NULL);
- }
-
- void visit(TemplateMixin *tm)
- {
- if (tm->semanticRun != PASSinit)
- {
- // When a class/struct contains mixin members, and is done over
- // because of forward references, never reach here so semanticRun
- // has been reset to PASSinit.
- return;
- }
- tm->semanticRun = PASSsemantic;
-
- Scope *scx = NULL;
- if (tm->_scope)
- {
- sc = tm->_scope;
- scx = tm->_scope; // save so we don't make redundant copies
- tm->_scope = NULL;
- }
-
- /* Run semantic on each argument, place results in tiargs[],
- * then find best match template with tiargs
- */
- if (!tm->findTempDecl(sc) ||
- !tm->semanticTiargs(sc) ||
- !tm->findBestMatch(sc, NULL))
- {
- if (tm->semanticRun == PASSinit) // forward reference had occured
- {
- //printf("forward reference - deferring\n");
- tm->_scope = scx ? scx : sc->copy();
- tm->_scope->setNoFree();
- Module::addDeferredSemantic(tm);
- return;
- }
-
- tm->inst = tm;
- tm->errors = true;
- return; // error recovery
- }
- TemplateDeclaration *tempdecl = tm->tempdecl->isTemplateDeclaration();
- assert(tempdecl);
-
- if (!tm->ident)
- {
- /* Assign scope local unique identifier, as same as lambdas.
- */
- const char *s = "__mixin";
-
- if (FuncDeclaration *func = sc->parent->isFuncDeclaration())
- {
- tm->symtab = func->localsymtab;
- if (tm->symtab)
- {
- // Inside template constraint, symtab is not set yet.
- goto L1;
- }
- }
- else
- {
- tm->symtab = sc->parent->isScopeDsymbol()->symtab;
- L1:
- assert(tm->symtab);
- int num = (int)dmd_aaLen(tm->symtab->tab) + 1;
- tm->ident = Identifier::generateId(s, num);
- tm->symtab->insert(tm);
- }
- }
-
- tm->inst = tm;
- tm->parent = sc->parent;
-
- /* Detect recursive mixin instantiations.
- */
- for (Dsymbol *s = tm->parent; s; s = s->parent)
- {
- //printf("\ts = '%s'\n", s->toChars());
- TemplateMixin *tmix = s->isTemplateMixin();
- if (!tmix || tempdecl != tmix->tempdecl)
- continue;
-
- /* Different argument list lengths happen with variadic args
- */
- if (tm->tiargs->length != tmix->tiargs->length)
- continue;
-
- for (size_t i = 0; i < tm->tiargs->length; i++)
- {
- RootObject *o = (*tm->tiargs)[i];
- Type *ta = isType(o);
- Expression *ea = isExpression(o);
- Dsymbol *sa = isDsymbol(o);
- RootObject *tmo = (*tmix->tiargs)[i];
- if (ta)
- {
- Type *tmta = isType(tmo);
- if (!tmta)
- goto Lcontinue;
- if (!ta->equals(tmta))
- goto Lcontinue;
- }
- else if (ea)
- {
- Expression *tme = isExpression(tmo);
- if (!tme || !ea->equals(tme))
- goto Lcontinue;
- }
- else if (sa)
- {
- Dsymbol *tmsa = isDsymbol(tmo);
- if (sa != tmsa)
- goto Lcontinue;
- }
- else
- assert(0);
- }
- tm->error("recursive mixin instantiation");
- return;
-
- Lcontinue:
- continue;
- }
-
- // Copy the syntax trees from the TemplateDeclaration
- tm->members = Dsymbol::arraySyntaxCopy(tempdecl->members);
- if (!tm->members)
- return;
-
- tm->symtab = new DsymbolTable();
-
- for (Scope *sce = sc; 1; sce = sce->enclosing)
- {
- ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym;
- if (sds)
- {
- sds->importScope(tm, Prot(Prot::public_));
- break;
- }
- }
-
- Scope *scy = sc->push(tm);
- scy->parent = tm;
-
- tm->argsym = new ScopeDsymbol();
- tm->argsym->parent = scy->parent;
- Scope *argscope = scy->push(tm->argsym);
-
- unsigned errorsave = global.errors;
-
- // Declare each template parameter as an alias for the argument type
- tm->declareParameters(argscope);
-
- // Add members to enclosing scope, as well as this scope
- for (size_t i = 0; i < tm->members->length; i++)
- {
- Dsymbol *s = (*tm->members)[i];
- s->addMember(argscope, tm);
- //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym);
- //printf("s->parent = %s\n", s->parent->toChars());
- }
-
- // Do semantic() analysis on template instance members
- Scope *sc2 = argscope->push(tm);
- //size_t deferred_dim = Module::deferred.length;
-
- static int nest;
- //printf("%d\n", nest);
- if (++nest > global.recursionLimit)
- {
- global.gag = 0; // ensure error message gets printed
- tm->error("recursive expansion");
- fatal();
- }
-
- for (size_t i = 0; i < tm->members->length; i++)
- {
- Dsymbol *s = (*tm->members)[i];
- s->setScope(sc2);
- }
-
- for (size_t i = 0; i < tm->members->length; i++)
- {
- Dsymbol *s = (*tm->members)[i];
- s->importAll(sc2);
- }
-
- for (size_t i = 0; i < tm->members->length; i++)
- {
- Dsymbol *s = (*tm->members)[i];
- dsymbolSemantic(s, sc2);
- }
-
- nest--;
-
- /* In DeclDefs scope, TemplateMixin does not have to handle deferred symbols.
- * Because the members would already call Module::addDeferredSemantic() for themselves.
- * See Struct, Class, Interface, and EnumDeclaration::semantic().
- */
- //if (!sc->func && Module::deferred.length > deferred_dim) {}
-
- AggregateDeclaration *ad = tm->toParent()->isAggregateDeclaration();
- if (sc->func && !ad)
- {
- semantic2(tm, sc2);
- semantic3(tm, sc2);
- }
-
- // Give additional context info if error occurred during instantiation
- if (global.errors != errorsave)
- {
- tm->error("error instantiating");
- tm->errors = true;
- }
-
- sc2->pop();
- argscope->pop();
- scy->pop();
- }
-
- void visit(Nspace *ns)
- {
- if (ns->semanticRun != PASSinit)
- return;
- if (ns->_scope)
- {
- sc = ns->_scope;
- ns->_scope = NULL;
- }
- if (!sc)
- return;
-
- ns->semanticRun = PASSsemantic;
- ns->parent = sc->parent;
- if (ns->members)
- {
- assert(sc);
- sc = sc->push(ns);
- sc->linkage = LINKcpp; // note that namespaces imply C++ linkage
- sc->parent = ns;
-
- for (size_t i = 0; i < ns->members->length; i++)
- {
- Dsymbol *s = (*ns->members)[i];
- s->importAll(sc);
- }
-
- for (size_t i = 0; i < ns->members->length; i++)
- {
- Dsymbol *s = (*ns->members)[i];
- dsymbolSemantic(s, sc);
- }
- sc->pop();
- }
- ns->semanticRun = PASSsemanticdone;
- }
-
-
-private:
- static bool isPointerToChar(Parameter *p)
- {
- if (TypePointer *tptr = p->type->isTypePointer())
- {
- return tptr->next->ty == Tchar;
- }
- return false;
- }
-
- static bool isVa_list(Parameter *p, FuncDeclaration *funcdecl, Scope *sc)
- {
- return p->type->equals(target.va_listType(funcdecl->loc, sc));
- }
-
-public:
- void funcDeclarationSemantic(FuncDeclaration *funcdecl)
- {
- TypeFunction *f;
- AggregateDeclaration *ad;
- InterfaceDeclaration *id;
-
- if (funcdecl->semanticRun != PASSinit && funcdecl->isFuncLiteralDeclaration())
- {
- /* Member functions that have return types that are
- * forward references can have semantic() run more than
- * once on them.
- * See test\interface2.d, test20
- */
- return;
- }
-
- if (funcdecl->semanticRun >= PASSsemanticdone)
- return;
- assert(funcdecl->semanticRun <= PASSsemantic);
- funcdecl->semanticRun = PASSsemantic;
-
- if (funcdecl->_scope)
- {
- sc = funcdecl->_scope;
- funcdecl->_scope = NULL;
- }
-
- if (!sc || funcdecl->errors)
- return;
-
- funcdecl->parent = sc->parent;
- Dsymbol *parent = funcdecl->toParent();
-
- funcdecl->foverrides.setDim(0); // reset in case semantic() is being retried for this function
-
- funcdecl->storage_class |= sc->stc & ~STCref;
- ad = funcdecl->isThis();
- // Don't nest structs b/c of generated methods which should not access the outer scopes.
- // https://issues.dlang.org/show_bug.cgi?id=16627
- if (ad && !funcdecl->generated)
- {
- funcdecl->storage_class |= ad->storage_class & (STC_TYPECTOR | STCsynchronized);
- ad->makeNested();
- }
- if (sc->func)
- funcdecl->storage_class |= sc->func->storage_class & STCdisable;
- // Remove prefix storage classes silently.
- if ((funcdecl->storage_class & STC_TYPECTOR) && !(ad || funcdecl->isNested()))
- funcdecl->storage_class &= ~STC_TYPECTOR;
-
- //printf("function storage_class = x%llx, sc->stc = x%llx, %x\n", funcdecl->storage_class, sc->stc, Declaration::isFinal());
-
- FuncLiteralDeclaration *fld = funcdecl->isFuncLiteralDeclaration();
- if (fld && fld->treq)
- {
- Type *treq = fld->treq;
- assert(treq->nextOf()->ty == Tfunction);
- if (treq->ty == Tdelegate)
- fld->tok = TOKdelegate;
- else if (treq->ty == Tpointer && treq->nextOf()->ty == Tfunction)
- fld->tok = TOKfunction;
- else
- assert(0);
- funcdecl->linkage = treq->nextOf()->toTypeFunction()->linkage;
- }
- else
- funcdecl->linkage = sc->linkage;
- funcdecl->inlining = sc->inlining;
- funcdecl->protection = sc->protection;
- funcdecl->userAttribDecl = sc->userAttribDecl;
-
- if (!funcdecl->originalType)
- funcdecl->originalType = funcdecl->type->syntaxCopy();
- if (funcdecl->type->ty != Tfunction)
- {
- if (funcdecl->type->ty != Terror)
- {
- funcdecl->error("%s must be a function instead of %s", funcdecl->toChars(), funcdecl->type->toChars());
- funcdecl->type = Type::terror;
- }
- funcdecl->errors = true;
- return;
- }
- if (!funcdecl->type->deco)
- {
- sc = sc->push();
- sc->stc |= funcdecl->storage_class & (STCdisable | STCdeprecated); // forward to function type
- TypeFunction *tf = funcdecl->type->toTypeFunction();
-
- if (sc->func)
- {
- /* If the nesting parent is pure without inference,
- * then this function defaults to pure too.
- *
- * auto foo() pure {
- * auto bar() {} // become a weak purity funciton
- * class C { // nested class
- * auto baz() {} // become a weak purity funciton
- * }
- *
- * static auto boo() {} // typed as impure
- * // Even though, boo cannot call any impure functions.
- * // See also Expression::checkPurity().
- * }
- */
- if (tf->purity == PUREimpure && (funcdecl->isNested() || funcdecl->isThis()))
- {
- FuncDeclaration *fd = NULL;
- for (Dsymbol *p = funcdecl->toParent2(); p; p = p->toParent2())
- {
- if (AggregateDeclaration *adx = p->isAggregateDeclaration())
- {
- if (adx->isNested())
- continue;
- break;
- }
- if ((fd = p->isFuncDeclaration()) != NULL)
- break;
- }
-
- /* If the parent's purity is inferred, then this function's purity needs
- * to be inferred first.
- */
- if (fd && fd->isPureBypassingInference() >= PUREweak &&
- !funcdecl->isInstantiated())
- {
- tf->purity = PUREfwdref; // default to pure
- }
- }
- }
-
- if (tf->isref) sc->stc |= STCref;
- if (tf->isscope) sc->stc |= STCscope;
- if (tf->isnothrow) sc->stc |= STCnothrow;
- if (tf->isnogc) sc->stc |= STCnogc;
- if (tf->isproperty) sc->stc |= STCproperty;
- if (tf->purity == PUREfwdref) sc->stc |= STCpure;
- if (tf->trust != TRUSTdefault)
- sc->stc &= ~(STCsafe | STCsystem | STCtrusted);
- if (tf->trust == TRUSTsafe) sc->stc |= STCsafe;
- if (tf->trust == TRUSTsystem) sc->stc |= STCsystem;
- if (tf->trust == TRUSTtrusted) sc->stc |= STCtrusted;
-
- if (funcdecl->isCtorDeclaration())
- {
- sc->flags |= SCOPEctor;
-
- Type *tret = ad->handleType();
- assert(tret);
- tret = tret->addStorageClass(funcdecl->storage_class | sc->stc);
- tret = tret->addMod(funcdecl->type->mod);
- tf->next = tret;
-
- if (ad->isStructDeclaration())
- sc->stc |= STCref;
- }
-
- // 'return' on a non-static class member function implies 'scope' as well
- if (ad && ad->isClassDeclaration() && (tf->isreturn || sc->stc & STCreturn) && !(sc->stc & STCstatic))
- sc->stc |= STCscope;
-
- // If 'this' has no pointers, remove 'scope' as it has no meaning
- if (sc->stc & STCscope && ad && ad->isStructDeclaration() && !ad->type->hasPointers())
- {
- sc->stc &= ~STCscope;
- tf->isscope = false;
- }
-
- sc->linkage = funcdecl->linkage;
-
- if (!tf->isNaked() && !(funcdecl->isThis() || funcdecl->isNested()))
- {
- OutBuffer buf;
- MODtoBuffer(&buf, tf->mod);
- funcdecl->error("without `this` cannot be %s", buf.peekChars());
- tf->mod = 0; // remove qualifiers
- }
-
- /* Apply const, immutable, wild and shared storage class
- * to the function type. Do this before type semantic.
- */
- StorageClass stc = funcdecl->storage_class;
- if (funcdecl->type->isImmutable())
- stc |= STCimmutable;
- if (funcdecl->type->isConst())
- stc |= STCconst;
- if (funcdecl->type->isShared() || funcdecl->storage_class & STCsynchronized)
- stc |= STCshared;
- if (funcdecl->type->isWild())
- stc |= STCwild;
- switch (stc & STC_TYPECTOR)
- {
- case STCimmutable:
- case STCimmutable | STCconst:
- case STCimmutable | STCwild:
- case STCimmutable | STCwild | STCconst:
- case STCimmutable | STCshared:
- case STCimmutable | STCshared | STCconst:
- case STCimmutable | STCshared | STCwild:
- case STCimmutable | STCshared | STCwild | STCconst:
- // Don't use immutableOf(), as that will do a merge()
- funcdecl->type = funcdecl->type->makeImmutable();
- break;
-
- case STCconst:
- funcdecl->type = funcdecl->type->makeConst();
- break;
-
- case STCwild:
- funcdecl->type = funcdecl->type->makeWild();
- break;
-
- case STCwild | STCconst:
- funcdecl->type = funcdecl->type->makeWildConst();
- break;
-
- case STCshared:
- funcdecl->type = funcdecl->type->makeShared();
- break;
-
- case STCshared | STCconst:
- funcdecl->type = funcdecl->type->makeSharedConst();
- break;
-
- case STCshared | STCwild:
- funcdecl->type = funcdecl->type->makeSharedWild();
- break;
-
- case STCshared | STCwild | STCconst:
- funcdecl->type = funcdecl->type->makeSharedWildConst();
- break;
-
- case 0:
- break;
-
- default:
- assert(0);
- }
-
- funcdecl->type = typeSemantic(funcdecl->type, funcdecl->loc, sc);
- sc = sc->pop();
- }
- if (funcdecl->type->ty != Tfunction)
- {
- if (funcdecl->type->ty != Terror)
- {
- funcdecl->error("%s must be a function instead of %s", funcdecl->toChars(), funcdecl->type->toChars());
- funcdecl->type = Type::terror;
- }
- funcdecl->errors = true;
- return;
- }
- else
- {
- // Merge back function attributes into 'originalType'.
- // It's used for mangling, ddoc, and json output.
- TypeFunction *tfo = funcdecl->originalType->toTypeFunction();
- TypeFunction *tfx = funcdecl->type->toTypeFunction();
- tfo->mod = tfx->mod;
- tfo->isscope = tfx->isscope;
- tfo->isscopeinferred = tfx->isscopeinferred;
- tfo->isref = tfx->isref;
- tfo->isnothrow = tfx->isnothrow;
- tfo->isnogc = tfx->isnogc;
- tfo->isproperty = tfx->isproperty;
- tfo->purity = tfx->purity;
- tfo->trust = tfx->trust;
-
- funcdecl->storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR);
- }
-
- f = (TypeFunction *)funcdecl->type;
-
- if ((funcdecl->storage_class & STCauto) && !f->isref && !funcdecl->inferRetType)
- funcdecl->error("storage class `auto` has no effect if return type is not inferred");
- /* Functions can only be 'scope' if they have a 'this'
- */
- if (f->isscope && !funcdecl->isNested() && !ad)
- {
- funcdecl->error("functions cannot be scope");
- }
-
- if (f->isreturn && !funcdecl->needThis() && !funcdecl->isNested())
- {
- /* Non-static nested functions have a hidden 'this' pointer to which
- * the 'return' applies
- */
- funcdecl->error("static member has no `this` to which `return` can apply");
- }
-
- if (funcdecl->isAbstract() && !funcdecl->isVirtual())
- {
- const char *sfunc;
- if (funcdecl->isStatic())
- sfunc = "static";
- else if (funcdecl->protection.kind == Prot::private_ || funcdecl->protection.kind == Prot::package_)
- sfunc = protectionToChars(funcdecl->protection.kind);
- else
- sfunc = "non-virtual";
- funcdecl->error("%s functions cannot be abstract", sfunc);
- }
-
- if (funcdecl->isOverride() && !funcdecl->isVirtual())
- {
- Prot::Kind kind = funcdecl->prot().kind;
- if ((kind == Prot::private_ || kind == Prot::package_) && funcdecl->isMember())
- funcdecl->error("%s method is not virtual and cannot override", protectionToChars(kind));
- else
- funcdecl->error("cannot override a non-virtual function");
- }
-
- if (funcdecl->isAbstract() && funcdecl->isFinalFunc())
- funcdecl->error("cannot be both final and abstract");
-
- if (const unsigned pors = sc->flags & (SCOPEprintf | SCOPEscanf))
- {
- /* printf/scanf-like functions must be of the form:
- * extern (C/C++) T printf([parameters...], const(char)* format, ...);
- * or:
- * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list);
- */
- const size_t nparams = f->parameterList.length();
- if ((f->linkage == LINKc || f->linkage == LINKcpp) &&
-
- ((f->parameterList.varargs == VARARGvariadic &&
- nparams >= 1 &&
- isPointerToChar(f->parameterList[nparams - 1])) ||
- (f->parameterList.varargs == VARARGnone &&
- nparams >= 2 &&
- isPointerToChar(f->parameterList[nparams - 2]) &&
- isVa_list(f->parameterList[nparams - 1], funcdecl, sc))
- )
- )
- {
- funcdecl->flags |= (pors == SCOPEprintf) ? FUNCFLAGprintf : FUNCFLAGscanf;
- }
- else
- {
- const char *p = (pors == SCOPEprintf ? Id::printf : Id::scanf)->toChars();
- if (f->parameterList.varargs == VARARGvariadic)
- {
- funcdecl->error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, ...)`"
- " not `%s`",
- p, f->next->toChars(), funcdecl->toChars(), funcdecl->type->toChars());
- }
- else
- {
- funcdecl->error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, va_list)`",
- p, f->next->toChars(), funcdecl->toChars());
- }
- }
- }
-
- id = parent->isInterfaceDeclaration();
- if (id)
- {
- funcdecl->storage_class |= STCabstract;
-
- if (funcdecl->isCtorDeclaration() ||
- funcdecl->isPostBlitDeclaration() ||
- funcdecl->isDtorDeclaration() ||
- funcdecl->isInvariantDeclaration() ||
- funcdecl->isNewDeclaration() || funcdecl->isDelete())
- funcdecl->error("constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface %s", id->toChars());
- if (funcdecl->fbody && funcdecl->isVirtual())
- funcdecl->error("function body only allowed in final functions in interface %s", id->toChars());
- }
-
- if (UnionDeclaration *ud = parent->isUnionDeclaration())
- {
- if (funcdecl->isPostBlitDeclaration() ||
- funcdecl->isDtorDeclaration() ||
- funcdecl->isInvariantDeclaration())
- funcdecl->error("destructors, postblits and invariants are not allowed in union %s", ud->toChars());
- }
-
- if (parent->isStructDeclaration())
- {
- if (funcdecl->isCtorDeclaration())
- {
- goto Ldone;
- }
- }
-
- if (ClassDeclaration *cd = parent->isClassDeclaration())
- {
- if (funcdecl->isCtorDeclaration())
- {
- goto Ldone;
- }
-
- if (funcdecl->storage_class & STCabstract)
- cd->isabstract = ABSyes;
-
- // if static function, do not put in vtbl[]
- if (!funcdecl->isVirtual())
- {
- //printf("\tnot virtual\n");
- goto Ldone;
- }
- // Suppress further errors if the return type is an error
- if (funcdecl->type->nextOf() == Type::terror)
- goto Ldone;
-
- bool may_override = false;
- for (size_t i = 0; i < cd->baseclasses->length; i++)
- {
- BaseClass *b = (*cd->baseclasses)[i];
- ClassDeclaration *cbd = b->type->toBasetype()->isClassHandle();
- if (!cbd)
- continue;
- for (size_t j = 0; j < cbd->vtbl.length; j++)
- {
- FuncDeclaration *f2 = cbd->vtbl[j]->isFuncDeclaration();
- if (!f2 || f2->ident != funcdecl->ident)
- continue;
- if (cbd->parent && cbd->parent->isTemplateInstance())
- {
- if (!f2->functionSemantic())
- goto Ldone;
- }
- may_override = true;
- }
- }
- if (may_override && funcdecl->type->nextOf() == NULL)
- {
- /* If same name function exists in base class but 'this' is auto return,
- * cannot find index of base class's vtbl[] to override.
- */
- funcdecl->error("return type inference is not supported if may override base class function");
- }
-
- /* Find index of existing function in base class's vtbl[] to override
- * (the index will be the same as in cd's current vtbl[])
- */
- int vi = cd->baseClass ? funcdecl->findVtblIndex((Dsymbols*)&cd->baseClass->vtbl, (int)cd->baseClass->vtbl.length)
- : -1;
-
- bool doesoverride = false;
- switch (vi)
- {
- case -1:
- Lintro:
- /* Didn't find one, so
- * This is an 'introducing' function which gets a new
- * slot in the vtbl[].
- */
-
- // Verify this doesn't override previous final function
- if (cd->baseClass)
- {
- Dsymbol *s = cd->baseClass->search(funcdecl->loc, funcdecl->ident);
- if (s)
- {
- FuncDeclaration *f2 = s->isFuncDeclaration();
- if (f2)
- {
- f2 = f2->overloadExactMatch(funcdecl->type);
- if (f2 && f2->isFinalFunc() && f2->prot().kind != Prot::private_)
- funcdecl->error("cannot override final function %s", f2->toPrettyChars());
- }
- }
- }
-
- /* These quirky conditions mimic what VC++ appears to do
- */
- if (global.params.mscoff && cd->isCPPclass() &&
- cd->baseClass && cd->baseClass->vtbl.length)
- {
- /* if overriding an interface function, then this is not
- * introducing and don't put it in the class vtbl[]
- */
- funcdecl->interfaceVirtual = funcdecl->overrideInterface();
- if (funcdecl->interfaceVirtual)
- {
- //printf("\tinterface function %s\n", funcdecl->toChars());
- cd->vtblFinal.push(funcdecl);
- goto Linterfaces;
- }
- }
-
- if (funcdecl->isFinalFunc())
- {
- // Don't check here, as it may override an interface function
- //if (funcdecl->isOverride())
- //funcdecl->error("is marked as override, but does not override any function");
- cd->vtblFinal.push(funcdecl);
- }
- else
- {
- //printf("\tintroducing function %s\n", funcdecl->toChars());
- funcdecl->introducing = 1;
- if (cd->isCPPclass() && target.cpp.reverseOverloads)
- {
- // with dmc, overloaded functions are grouped and in reverse order
- funcdecl->vtblIndex = (int)cd->vtbl.length;
- for (int i = 0; i < (int)cd->vtbl.length; i++)
- {
- if (cd->vtbl[i]->ident == funcdecl->ident && cd->vtbl[i]->parent == parent)
- {
- funcdecl->vtblIndex = (int)i;
- break;
- }
- }
- // shift all existing functions back
- for (int i = (int)cd->vtbl.length; i > funcdecl->vtblIndex; i--)
- {
- FuncDeclaration *fd = cd->vtbl[i-1]->isFuncDeclaration();
- assert(fd);
- fd->vtblIndex++;
- }
- cd->vtbl.insert(funcdecl->vtblIndex, funcdecl);
- }
- else
- {
- // Append to end of vtbl[]
- vi = (int)cd->vtbl.length;
- cd->vtbl.push(funcdecl);
- funcdecl->vtblIndex = vi;
- }
- }
- break;
-
- case -2:
- // can't determine because of forward references
- funcdecl->errors = true;
- return;
-
- default:
- {
- FuncDeclaration *fdv = cd->baseClass->vtbl[vi]->isFuncDeclaration();
- FuncDeclaration *fdc = cd->vtbl[vi]->isFuncDeclaration();
- // This function is covariant with fdv
-
- if (fdc == funcdecl)
- {
- doesoverride = true;
- break;
- }
-
- if (fdc->toParent() == parent)
- {
- //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n",
- // vi, funcdecl, funcdecl->toChars(), funcdecl->type->toChars(), funcdecl->loc.toChars(),
- // fdc, fdc ->toChars(), fdc ->type->toChars(), fdc ->loc.toChars(),
- // fdv, fdv ->toChars(), fdv ->type->toChars(), fdv ->loc.toChars());
-
- // fdc overrides fdv exactly, then this introduces new function.
- if (fdc->type->mod == fdv->type->mod && funcdecl->type->mod != fdv->type->mod)
- goto Lintro;
- }
-
- // This function overrides fdv
- if (fdv->isFinalFunc())
- funcdecl->error("cannot override final function %s", fdv->toPrettyChars());
-
- if (!funcdecl->isOverride())
- {
- if (fdv->isFuture())
- {
- ::deprecation(funcdecl->loc, "@__future base class method %s is being overridden by %s; rename the latter",
- fdv->toPrettyChars(), funcdecl->toPrettyChars());
- // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[]
- goto Lintro;
- }
- else
- {
- int vi2 = funcdecl->findVtblIndex(&cd->baseClass->vtbl, (int)cd->baseClass->vtbl.length, false);
- if (vi2 < 0)
- // https://issues.dlang.org/show_bug.cgi?id=17349
- ::deprecation(funcdecl->loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute",
- fdv->toPrettyChars(), funcdecl->toPrettyChars());
- else
- error(funcdecl->loc, "implicitly overriding base class method %s with %s deprecated; add `override` attribute",
- fdv->toPrettyChars(), funcdecl->toPrettyChars());
- }
- }
-
- doesoverride = true;
- if (fdc->toParent() == parent)
- {
- // If both are mixins, or both are not, then error.
- // If either is not, the one that is not overrides the other.
- bool thismixin = funcdecl->parent->isClassDeclaration() != NULL;
- bool fdcmixin = fdc->parent->isClassDeclaration() != NULL;
- if (thismixin == fdcmixin)
- {
- funcdecl->error("multiple overrides of same function");
- }
- else if (!thismixin) // fdc overrides fdv
- {
- // this doesn't override any function
- break;
- }
- }
- cd->vtbl[vi] = funcdecl;
- funcdecl->vtblIndex = vi;
-
- /* Remember which functions this overrides
- */
- funcdecl->foverrides.push(fdv);
-
- /* This works by whenever this function is called,
- * it actually returns tintro, which gets dynamically
- * cast to type. But we know that tintro is a base
- * of type, so we could optimize it by not doing a
- * dynamic cast, but just subtracting the isBaseOf()
- * offset if the value is != null.
- */
-
- if (fdv->tintro)
- funcdecl->tintro = fdv->tintro;
- else if (!funcdecl->type->equals(fdv->type))
- {
- /* Only need to have a tintro if the vptr
- * offsets differ
- */
- int offset;
- if (fdv->type->nextOf()->isBaseOf(funcdecl->type->nextOf(), &offset))
- {
- funcdecl->tintro = fdv->type;
- }
- }
- break;
- }
- }
-
- /* Go through all the interface bases.
- * If this function is covariant with any members of those interface
- * functions, set the tintro.
- */
- Linterfaces:
- for (size_t i = 0; i < cd->interfaces.length; i++)
- {
- BaseClass *b = cd->interfaces.ptr[i];
- vi = funcdecl->findVtblIndex((Dsymbols *)&b->sym->vtbl, (int)b->sym->vtbl.length);
- switch (vi)
- {
- case -1:
- break;
-
- case -2:
- // can't determine because of forward references
- funcdecl->errors = true;
- return;
-
- default:
- {
- FuncDeclaration *fdv = (FuncDeclaration *)b->sym->vtbl[vi];
- Type *ti = NULL;
-
- /* Remember which functions this overrides
- */
- funcdecl->foverrides.push(fdv);
-
- /* Should we really require 'override' when implementing
- * an interface function?
- */
- //if (!funcdecl->isOverride())
- //warning(funcdecl->loc, "overrides base class function %s, but is not marked with `override`", fdv->toPrettyChars());
-
- if (fdv->tintro)
- ti = fdv->tintro;
- else if (!funcdecl->type->equals(fdv->type))
- {
- /* Only need to have a tintro if the vptr
- * offsets differ
- */
- int offset;
- if (fdv->type->nextOf()->isBaseOf(funcdecl->type->nextOf(), &offset))
- {
- ti = fdv->type;
- }
- }
- if (ti)
- {
- if (funcdecl->tintro)
- {
- if (!funcdecl->tintro->nextOf()->equals(ti->nextOf()) &&
- !funcdecl->tintro->nextOf()->isBaseOf(ti->nextOf(), NULL) &&
- !ti->nextOf()->isBaseOf(funcdecl->tintro->nextOf(), NULL))
- {
- funcdecl->error("incompatible covariant types %s and %s", funcdecl->tintro->toChars(), ti->toChars());
- }
- }
- funcdecl->tintro = ti;
- }
- goto L2;
- }
- }
- }
-
- if (!doesoverride && funcdecl->isOverride() && (funcdecl->type->nextOf() || !may_override))
- {
- BaseClass *bc = NULL;
- Dsymbol *s = NULL;
- for (size_t i = 0; i < cd->baseclasses->length; i++)
- {
- bc = (*cd->baseclasses)[i];
- s = bc->sym->search_correct(funcdecl->ident);
- if (s) break;
- }
-
- if (s)
- funcdecl->error("does not override any function, did you mean to override `%s%s`?",
- bc->sym->isCPPclass() ? "extern (C++) " : "", s->toPrettyChars());
- else
- funcdecl->error("does not override any function");
- }
-
- L2: ;
-
- /* Go through all the interface bases.
- * Disallow overriding any final functions in the interface(s).
- */
- for (size_t i = 0; i < cd->interfaces.length; i++)
- {
- BaseClass *b = cd->interfaces.ptr[i];
- if (b->sym)
- {
- Dsymbol *s = search_function(b->sym, funcdecl->ident);
- if (s)
- {
- FuncDeclaration *f2 = s->isFuncDeclaration();
- if (f2)
- {
- f2 = f2->overloadExactMatch(funcdecl->type);
- if (f2 && f2->isFinalFunc() && f2->prot().kind != Prot::private_)
- funcdecl->error("cannot override final function %s.%s", b->sym->toChars(), f2->toPrettyChars());
- }
- }
- }
- }
-
- if (funcdecl->isOverride())
- {
- if (funcdecl->storage_class & STCdisable)
- funcdecl->deprecation("overridden functions cannot be annotated @disable");
- if (funcdecl->isDeprecated())
- funcdecl->deprecation("deprecated functions cannot be annotated @disable");
- }
- }
- else if (funcdecl->isOverride() && !parent->isTemplateInstance())
- funcdecl->error("override only applies to class member functions");
-
- // Reflect this->type to f because it could be changed by findVtblIndex
- f = funcdecl->type->toTypeFunction();
-
- Ldone:
- /* Contracts can only appear without a body when they are virtual interface functions
- */
- if (!funcdecl->fbody && !allowsContractWithoutBody(funcdecl))
- funcdecl->error("in and out contracts can only appear without a body when they are virtual interface functions or abstract");
-
- /* Do not allow template instances to add virtual functions
- * to a class.
- */
- if (funcdecl->isVirtual())
- {
- TemplateInstance *ti = parent->isTemplateInstance();
- if (ti)
- {
- // Take care of nested templates
- while (1)
- {
- TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance();
- if (!ti2)
- break;
- ti = ti2;
- }
-
- // If it's a member template
- ClassDeclaration *cd = ti->tempdecl->isClassMember();
- if (cd)
- {
- funcdecl->error("cannot use template to add virtual function to class `%s`", cd->toChars());
- }
- }
- }
-
- if (funcdecl->isMain())
- funcdecl->checkDmain(); // Check main() parameters and return type
-
- /* Purity and safety can be inferred for some functions by examining
- * the function body.
- */
- if (canInferAttributes(funcdecl, sc))
- initInferAttributes(funcdecl);
-
- Module::dprogress++;
- funcdecl->semanticRun = PASSsemanticdone;
-
- /* Save scope for possible later use (if we need the
- * function internals)
- */
- funcdecl->_scope = sc->copy();
- funcdecl->_scope->setNoFree();
-
- static bool printedMain = false; // semantic might run more than once
- if (global.params.verbose && !printedMain)
- {
- const char *type = funcdecl->isMain() ? "main" : funcdecl->isWinMain() ? "winmain" : funcdecl->isDllMain() ? "dllmain" : (const char *)NULL;
- Module *mod = sc->_module;
-
- if (type && mod)
- {
- printedMain = true;
- const char *name = mod->srcfile->toChars();
- const char *path = FileName::searchPath(global.path, name, true);
- message("entry %-10s\t%s", type, path ? path : name);
- }
- }
-
- if (funcdecl->fbody && funcdecl->isMain() && sc->_module->isRoot())
- Compiler::genCmain(sc);
-
- assert(funcdecl->type->ty != Terror || funcdecl->errors);
-
- // semantic for parameters' UDAs
- const size_t nparams = f->parameterList.length();
- for (size_t i = 0; i < nparams; i++)
- {
- Parameter *param = f->parameterList[i];
- if (param && param->userAttribDecl)
- dsymbolSemantic(param->userAttribDecl, sc);
- }
- }
-
- // Do the semantic analysis on the external interface to the function.
- void visit(FuncDeclaration *funcdecl)
- {
- funcDeclarationSemantic(funcdecl);
- }
-
- void visit(CtorDeclaration *ctd)
- {
- //printf("CtorDeclaration::semantic() %s\n", ctd->toChars());
- if (ctd->semanticRun >= PASSsemanticdone)
- return;
- if (ctd->_scope)
- {
- sc = ctd->_scope;
- ctd->_scope = NULL;
- }
-
- ctd->parent = sc->parent;
- Dsymbol *p = ctd->toParent2();
- AggregateDeclaration *ad = p->isAggregateDeclaration();
- if (!ad)
- {
- error(ctd->loc, "constructor can only be a member of aggregate, not %s %s",
- p->kind(), p->toChars());
- ctd->type = Type::terror;
- ctd->errors = true;
- return;
- }
-
- sc = sc->push();
- sc->stc &= ~STCstatic; // not a static constructor
- sc->flags |= SCOPEctor;
-
- funcDeclarationSemantic(ctd);
-
- sc->pop();
-
- if (ctd->errors)
- return;
-
- TypeFunction *tf = ctd->type->toTypeFunction();
-
- /* See if it's the default constructor
- * But, template constructor should not become a default constructor.
- */
- if (ad && (!ctd->parent->isTemplateInstance() || ctd->parent->isTemplateMixin()))
- {
- const size_t dim = tf->parameterList.length();
-
- if (StructDeclaration *sd = ad->isStructDeclaration())
- {
- if (dim == 0 && tf->parameterList.varargs == VARARGnone) // empty default ctor w/o any varargs
- {
- if (ctd->fbody || !(ctd->storage_class & STCdisable) || dim)
- {
- ctd->error("default constructor for structs only allowed "
- "with @disable, no body, and no parameters");
- ctd->storage_class |= STCdisable;
- ctd->fbody = NULL;
- }
- sd->noDefaultCtor = true;
- }
- else if (dim == 0 && tf->parameterList.varargs) // allow varargs only ctor
- {
- }
- else if (dim && tf->parameterList[0]->defaultArg)
- {
- // if the first parameter has a default argument, then the rest does as well
- if (ctd->storage_class & STCdisable)
- {
- ctd->deprecation("@disable'd constructor cannot have default "
- "arguments for all parameters.");
- deprecationSupplemental(ctd->loc, "Use @disable this(); if you want to disable default initialization.");
- }
- else
- ctd->deprecation("all parameters have default arguments, "
- "but structs cannot have default constructors.");
- }
-
- }
- else if (dim == 0 && tf->parameterList.varargs == VARARGnone)
- {
- ad->defaultCtor = ctd;
- }
- }
- }
-
- void visit(PostBlitDeclaration *pbd)
- {
- //printf("PostBlitDeclaration::semantic() %s\n", pbd->toChars());
- //printf("ident: %s, %s, %p, %p\n", pbd->ident->toChars(), Id::dtor->toChars(), pbd->ident, Id::dtor);
- //printf("stc = x%llx\n", sc->stc);
- if (pbd->semanticRun >= PASSsemanticdone)
- return;
- if (pbd->_scope)
- {
- sc = pbd->_scope;
- pbd->_scope = NULL;
- }
-
- pbd->parent = sc->parent;
- Dsymbol *p = pbd->toParent2();
- StructDeclaration *ad = p->isStructDeclaration();
- if (!ad)
- {
- error(pbd->loc, "postblit can only be a member of struct/union, not %s %s",
- p->kind(), p->toChars());
- pbd->type = Type::terror;
- pbd->errors = true;
- return;
- }
- if (pbd->ident == Id::postblit && pbd->semanticRun < PASSsemantic)
- ad->postblits.push(pbd);
- if (!pbd->type)
- pbd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, pbd->storage_class);
-
- sc = sc->push();
- sc->stc &= ~STCstatic; // not static
- sc->linkage = LINKd;
-
- funcDeclarationSemantic(pbd);
-
- sc->pop();
- }
-
- void visit(DtorDeclaration *dd)
- {
- //printf("DtorDeclaration::semantic() %s\n", dd->toChars());
- //printf("ident: %s, %s, %p, %p\n", dd->ident->toChars(), Id::dtor->toChars(), dd->ident, Id::dtor);
- if (dd->semanticRun >= PASSsemanticdone)
- return;
- if (dd->_scope)
- {
- sc = dd->_scope;
- dd->_scope = NULL;
- }
-
- dd->parent = sc->parent;
- Dsymbol *p = dd->toParent2();
- AggregateDeclaration *ad = p->isAggregateDeclaration();
- if (!ad)
- {
- error(dd->loc, "destructor can only be a member of aggregate, not %s %s",
- p->kind(), p->toChars());
- dd->type = Type::terror;
- dd->errors = true;
- return;
- }
- if (dd->ident == Id::dtor && dd->semanticRun < PASSsemantic)
- ad->dtors.push(dd);
- if (!dd->type)
- dd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, dd->storage_class);
-
- sc = sc->push();
- sc->stc &= ~STCstatic; // not a static destructor
- if (sc->linkage != LINKcpp)
- sc->linkage = LINKd;
-
- funcDeclarationSemantic(dd);
-
- sc->pop();
- }
-
- void visit(StaticCtorDeclaration *scd)
- {
- //printf("StaticCtorDeclaration::semantic()\n");
- if (scd->semanticRun >= PASSsemanticdone)
- return;
- if (scd->_scope)
- {
- sc = scd->_scope;
- scd->_scope = NULL;
- }
-
- scd->parent = sc->parent;
- Dsymbol *p = scd->parent->pastMixin();
- if (!p->isScopeDsymbol())
- {
- const char *s = (scd->isSharedStaticCtorDeclaration() ? "shared " : "");
- error(scd->loc, "%sstatic constructor can only be member of module/aggregate/template, not %s %s",
- s, p->kind(), p->toChars());
- scd->type = Type::terror;
- scd->errors = true;
- return;
- }
- if (!scd->type)
- scd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, scd->storage_class);
-
- /* If the static ctor appears within a template instantiation,
- * it could get called multiple times by the module constructors
- * for different modules. Thus, protect it with a gate.
- */
- if (scd->isInstantiated() && scd->semanticRun < PASSsemantic)
- {
- /* Add this prefix to the function:
- * static int gate;
- * if (++gate != 1) return;
- * Note that this is not thread safe; should not have threads
- * during static construction.
- */
- VarDeclaration *v = new VarDeclaration(Loc(), Type::tint32, Id::gate, NULL);
- v->storage_class = STCtemp | (scd->isSharedStaticCtorDeclaration() ? STCstatic : STCtls);
- Statements *sa = new Statements();
- Statement *s = new ExpStatement(Loc(), v);
- sa->push(s);
- Expression *e = new IdentifierExp(Loc(), v->ident);
- e = new AddAssignExp(Loc(), e, new IntegerExp(1));
- e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(1));
- s = new IfStatement(Loc(), NULL, e, new ReturnStatement(Loc(), NULL), NULL, Loc());
- sa->push(s);
- if (scd->fbody)
- sa->push(scd->fbody);
- scd->fbody = new CompoundStatement(Loc(), sa);
- }
-
- funcDeclarationSemantic(scd);
-
- // We're going to need ModuleInfo
- Module *m = scd->getModule();
- if (!m)
- m = sc->_module;
- if (m)
- {
- m->needmoduleinfo = 1;
- //printf("module1 %s needs moduleinfo\n", m->toChars());
- }
- }
-
- void visit(StaticDtorDeclaration *sdd)
- {
- if (sdd->semanticRun >= PASSsemanticdone)
- return;
- if (sdd->_scope)
- {
- sc = sdd->_scope;
- sdd->_scope = NULL;
- }
-
- sdd->parent = sc->parent;
- Dsymbol *p = sdd->parent->pastMixin();
- if (!p->isScopeDsymbol())
- {
- const char *s = (sdd->isSharedStaticDtorDeclaration() ? "shared " : "");
- error(sdd->loc, "%sstatic destructor can only be member of module/aggregate/template, not %s %s",
- s, p->kind(), p->toChars());
- sdd->type = Type::terror;
- sdd->errors = true;
- return;
- }
- if (!sdd->type)
- sdd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, sdd->storage_class);
-
- /* If the static ctor appears within a template instantiation,
- * it could get called multiple times by the module constructors
- * for different modules. Thus, protect it with a gate.
- */
- if (sdd->isInstantiated() && sdd->semanticRun < PASSsemantic)
- {
- /* Add this prefix to the function:
- * static int gate;
- * if (--gate != 0) return;
- * Increment gate during constructor execution.
- * Note that this is not thread safe; should not have threads
- * during static destruction.
- */
- VarDeclaration *v = new VarDeclaration(Loc(), Type::tint32, Id::gate, NULL);
- v->storage_class = STCtemp | (sdd->isSharedStaticDtorDeclaration() ? STCstatic : STCtls);
- Statements *sa = new Statements();
- Statement *s = new ExpStatement(Loc(), v);
- sa->push(s);
- Expression *e = new IdentifierExp(Loc(), v->ident);
- e = new AddAssignExp(Loc(), e, new IntegerExp(-1));
- e = new EqualExp(TOKnotequal, Loc(), e, new IntegerExp(0));
- s = new IfStatement(Loc(), NULL, e, new ReturnStatement(Loc(), NULL), NULL, Loc());
- sa->push(s);
- if (sdd->fbody)
- sa->push(sdd->fbody);
- sdd->fbody = new CompoundStatement(Loc(), sa);
- sdd->vgate = v;
- }
-
- funcDeclarationSemantic(sdd);
-
- // We're going to need ModuleInfo
- Module *m = sdd->getModule();
- if (!m)
- m = sc->_module;
- if (m)
- {
- m->needmoduleinfo = 1;
- //printf("module2 %s needs moduleinfo\n", m->toChars());
- }
- }
-
- void visit(InvariantDeclaration *invd)
- {
- if (invd->semanticRun >= PASSsemanticdone)
- return;
- if (invd->_scope)
- {
- sc = invd->_scope;
- invd->_scope = NULL;
- }
-
- invd->parent = sc->parent;
- Dsymbol *p = invd->parent->pastMixin();
- AggregateDeclaration *ad = p->isAggregateDeclaration();
- if (!ad)
- {
- error(invd->loc, "invariant can only be a member of aggregate, not %s %s",
- p->kind(), p->toChars());
- invd->type = Type::terror;
- invd->errors = true;
- return;
- }
- if (invd->ident != Id::classInvariant &&
- invd->semanticRun < PASSsemantic &&
- !ad->isUnionDeclaration() // users are on their own with union fields
- )
- ad->invs.push(invd);
- if (!invd->type)
- invd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, invd->storage_class);
-
- sc = sc->push();
- sc->stc &= ~STCstatic; // not a static invariant
- sc->stc |= STCconst; // invariant() is always const
- sc->flags = (sc->flags & ~SCOPEcontract) | SCOPEinvariant;
- sc->linkage = LINKd;
-
- funcDeclarationSemantic(invd);
-
- sc->pop();
- }
-
- void visit(UnitTestDeclaration *utd)
- {
- if (utd->semanticRun >= PASSsemanticdone)
- return;
- if (utd->_scope)
- {
- sc = utd->_scope;
- utd->_scope = NULL;
- }
-
- utd->protection = sc->protection;
-
- utd->parent = sc->parent;
- Dsymbol *p = utd->parent->pastMixin();
- if (!p->isScopeDsymbol())
- {
- error(utd->loc, "unittest can only be a member of module/aggregate/template, not %s %s",
- p->kind(), p->toChars());
- utd->type = Type::terror;
- utd->errors = true;
- return;
- }
-
- if (global.params.useUnitTests)
- {
- if (!utd->type)
- utd->type = new TypeFunction(ParameterList(), Type::tvoid, LINKd, utd->storage_class);
- Scope *sc2 = sc->push();
- sc2->linkage = LINKd;
- funcDeclarationSemantic(utd);
- sc2->pop();
- }
- }
-
- void visit(NewDeclaration *nd)
- {
- //printf("NewDeclaration::semantic()\n");
- if (nd->semanticRun >= PASSsemanticdone)
- return;
- if (nd->_scope)
- {
- sc = nd->_scope;
- nd->_scope = NULL;
- }
-
- nd->parent = sc->parent;
- Dsymbol *p = nd->parent->pastMixin();
- if (!p->isAggregateDeclaration())
- {
- error(nd->loc, "allocator can only be a member of aggregate, not %s %s",
- p->kind(), p->toChars());
- nd->type = Type::terror;
- nd->errors = true;
- return;
- }
- Type *tret = Type::tvoid->pointerTo();
- if (!nd->type)
- nd->type = new TypeFunction(ParameterList(nd->parameters, nd->varargs), tret, LINKd, nd->storage_class);
-
- nd->type = typeSemantic(nd->type, nd->loc, sc);
-
- // Check that there is at least one argument of type size_t
- TypeFunction *tf = nd->type->toTypeFunction();
- if (tf->parameterList.length() < 1)
- {
- nd->error("at least one argument of type size_t expected");
- }
- else
- {
- Parameter *fparam = tf->parameterList[0];
- if (!fparam->type->equals(Type::tsize_t))
- nd->error("first argument must be type size_t, not %s", fparam->type->toChars());
- }
-
- funcDeclarationSemantic(nd);
- }
-
- void visit(DeleteDeclaration *deld)
- {
- //printf("DeleteDeclaration::semantic()\n");
- if (deld->semanticRun >= PASSsemanticdone)
- return;
- if (deld->_scope)
- {
- sc = deld->_scope;
- deld->_scope = NULL;
- }
-
- deld->parent = sc->parent;
- Dsymbol *p = deld->parent->pastMixin();
- if (!p->isAggregateDeclaration())
- {
- error(deld->loc, "deallocator can only be a member of aggregate, not %s %s",
- p->kind(), p->toChars());
- deld->type = Type::terror;
- deld->errors = true;
- return;
- }
- if (!deld->type)
- deld->type = new TypeFunction(ParameterList(deld->parameters), Type::tvoid, LINKd, deld->storage_class);
-
- deld->type = typeSemantic(deld->type, deld->loc, sc);
-
- // Check that there is only one argument of type void*
- TypeFunction *tf = deld->type->toTypeFunction();
- if (tf->parameterList.length() != 1)
- {
- deld->error("one argument of type void* expected");
- }
- else
- {
- Parameter *fparam = tf->parameterList[0];
- if (!fparam->type->equals(Type::tvoid->pointerTo()))
- deld->error("one argument of type void* expected, not %s", fparam->type->toChars());
- }
-
- funcDeclarationSemantic(deld);
- }
-
- void visit(StructDeclaration *sd)
- {
- //printf("StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", sd, sd->parent->toChars(), sd->toChars(), sizeok);
-
- //static int count; if (++count == 20) halt();
-
- if (sd->semanticRun >= PASSsemanticdone)
- return;
- unsigned errors = global.errors;
-
- //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", sd, sd->parent->toChars(), sd->toChars(), sizeok);
- Scope *scx = NULL;
- if (sd->_scope)
- {
- sc = sd->_scope;
- scx = sd->_scope; // save so we don't make redundant copies
- sd->_scope = NULL;
- }
-
- if (!sd->parent)
- {
- assert(sc->parent && sc->func);
- sd->parent = sc->parent;
- }
- assert(sd->parent && !sd->isAnonymous());
-
- if (sd->errors)
- sd->type = Type::terror;
- if (sd->semanticRun == PASSinit)
- sd->type = sd->type->addSTC(sc->stc | sd->storage_class);
- sd->type = typeSemantic(sd->type, sd->loc, sc);
-
- if (sd->type->ty == Tstruct && ((TypeStruct *)sd->type)->sym != sd)
- {
- TemplateInstance *ti = ((TypeStruct *)sd->type)->sym->isInstantiated();
- if (ti && isError(ti))
- ((TypeStruct *)sd->type)->sym = sd;
- }
-
- // Ungag errors when not speculative
- Ungag ungag = sd->ungagSpeculative();
-
- if (sd->semanticRun == PASSinit)
- {
- sd->protection = sc->protection;
-
- sd->alignment = sc->alignment();
-
- sd->storage_class |= sc->stc;
- if (sd->storage_class & STCdeprecated)
- sd->isdeprecated = true;
- if (sd->storage_class & STCabstract)
- sd->error("structs, unions cannot be abstract");
- sd->userAttribDecl = sc->userAttribDecl;
-
- if (sc->linkage == LINKcpp)
- sd->classKind = ClassKind::cpp;
- }
- else if (sd->symtab && !scx)
- {
- return;
- }
- sd->semanticRun = PASSsemantic;
-
- if (!sd->members) // if opaque declaration
- {
- sd->semanticRun = PASSsemanticdone;
- return;
- }
- if (!sd->symtab)
- {
- sd->symtab = new DsymbolTable();
-
- for (size_t i = 0; i < sd->members->length; i++)
- {
- Dsymbol *s = (*sd->members)[i];
- //printf("adding member '%s' to '%s'\n", s->toChars(), sd->toChars());
- s->addMember(sc, sd);
- }
- }
-
- Scope *sc2 = sd->newScope(sc);
-
- /* Set scope so if there are forward references, we still might be able to
- * resolve individual members like enums.
- */
- for (size_t i = 0; i < sd->members->length; i++)
- {
- Dsymbol *s = (*sd->members)[i];
- //printf("struct: setScope %s %s\n", s->kind(), s->toChars());
- s->setScope(sc2);
- }
-
- for (size_t i = 0; i < sd->members->length; i++)
- {
- Dsymbol *s = (*sd->members)[i];
- s->importAll(sc2);
- }
-
- for (size_t i = 0; i < sd->members->length; i++)
- {
- Dsymbol *s = (*sd->members)[i];
- dsymbolSemantic(s, sc2);
- }
-
- if (!sd->determineFields())
- {
- assert(sd->type->ty == Terror);
- sc2->pop();
- sd->semanticRun = PASSsemanticdone;
- return;
- }
-
- /* Following special member functions creation needs semantic analysis
- * completion of sub-structs in each field types. For example, buildDtor
- * needs to check existence of elaborate dtor in type of each fields.
- * See the case in compilable/test14838.d
- */
- for (size_t i = 0; i < sd->fields.length; i++)
- {
- VarDeclaration *v = sd->fields[i];
- Type *tb = v->type->baseElemOf();
- if (tb->ty != Tstruct)
- continue;
- StructDeclaration *sdec = ((TypeStruct *)tb)->sym;
- if (sdec->semanticRun >= PASSsemanticdone)
- continue;
-
- sc2->pop();
-
- sd->_scope = scx ? scx : sc->copy();
- sd->_scope->setNoFree();
- Module::addDeferredSemantic(sd);
-
- //printf("\tdeferring %s\n", sd->toChars());
- return;
- }
-
- /* Look for special member functions.
- */
- sd->aggNew = (NewDeclaration *)sd->search(Loc(), Id::classNew);
- sd->aggDelete = (DeleteDeclaration *)sd->search(Loc(), Id::classDelete);
-
- // Look for the constructor
- sd->ctor = sd->searchCtor();
-
- sd->dtor = buildDtor(sd, sc2);
- sd->postblit = buildPostBlit(sd, sc2);
-
- buildOpAssign(sd, sc2);
- buildOpEquals(sd, sc2);
-
- if (global.params.useTypeInfo && Type::dtypeinfo) // these functions are used for TypeInfo
- {
- sd->xeq = buildXopEquals(sd, sc2);
- sd->xcmp = buildXopCmp(sd, sc2);
- sd->xhash = buildXtoHash(sd, sc2);
- }
-
- sd->inv = buildInv(sd, sc2);
-
- Module::dprogress++;
- sd->semanticRun = PASSsemanticdone;
- //printf("-StructDeclaration::semantic(this=%p, '%s')\n", sd, sd->toChars());
-
- sc2->pop();
-
- if (sd->ctor)
- {
- Dsymbol *scall = sd->search(Loc(), Id::call);
- if (scall)
- {
- unsigned xerrors = global.startGagging();
- sc = sc->push();
- sc->tinst = NULL;
- sc->minst = NULL;
- FuncDeclaration *fcall = resolveFuncCall(sd->loc, sc, scall, NULL, NULL, NULL, 1);
- sc = sc->pop();
- global.endGagging(xerrors);
-
- if (fcall && fcall->isStatic())
- {
- sd->error(fcall->loc, "`static opCall` is hidden by constructors and can never be called");
- errorSupplemental(fcall->loc, "Please use a factory method instead, or replace all constructors with `static opCall`.");
- }
- }
- }
-
- if (sd->type->ty == Tstruct && ((TypeStruct *)sd->type)->sym != sd)
- {
- // https://issues.dlang.org/show_bug.cgi?id=19024
- StructDeclaration *sym = ((TypeStruct *)sd->type)->sym;
- sd->error("already exists at %s. Perhaps in another function with the same name?", sym->loc.toChars());
- }
-
- if (global.errors != errors)
- {
- // The type is no good.
- sd->type = Type::terror;
- sd->errors = true;
- if (sd->deferred)
- sd->deferred->errors = true;
- }
-
- if (sd->deferred && !global.gag)
- {
- semantic2(sd->deferred, sc);
- semantic3(sd->deferred, sc);
- }
- }
-
- void interfaceSemantic(ClassDeclaration *cd)
- {
- cd->vtblInterfaces = new BaseClasses();
- cd->vtblInterfaces->reserve(cd->interfaces.length);
-
- for (size_t i = 0; i < cd->interfaces.length; i++)
- {
- BaseClass *b = cd->interfaces.ptr[i];
- cd->vtblInterfaces->push(b);
- b->copyBaseInterfaces(cd->vtblInterfaces);
- }
- }
-
- void visit(ClassDeclaration *cldec)
- {
- //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", cldec->toChars(), cldec->type, sizeok, cldec);
- //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : "");
- //printf("sc->stc = %x\n", sc->stc);
-
- //{ static int n; if (++n == 20) *(char*)0=0; }
-
- if (cldec->semanticRun >= PASSsemanticdone)
- return;
- unsigned errors = global.errors;
-
- //printf("+ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", cldec->toChars(), cldec->type, sizeok, cldec);
-
- Scope *scx = NULL;
- if (cldec->_scope)
- {
- sc = cldec->_scope;
- scx = cldec->_scope; // save so we don't make redundant copies
- cldec->_scope = NULL;
- }
-
- if (!cldec->parent)
- {
- assert(sc->parent);
- cldec->parent = sc->parent;
- }
-
- if (cldec->errors)
- cldec->type = Type::terror;
- cldec->type = typeSemantic(cldec->type, cldec->loc, sc);
-
- if (cldec->type->ty == Tclass && ((TypeClass *)cldec->type)->sym != cldec)
- {
- TemplateInstance *ti = ((TypeClass *)cldec->type)->sym->isInstantiated();
- if (ti && isError(ti))
- ((TypeClass *)cldec->type)->sym = cldec;
- }
-
- // Ungag errors when not speculative
- Ungag ungag = cldec->ungagSpeculative();
-
- if (cldec->semanticRun == PASSinit)
- {
- cldec->protection = sc->protection;
-
- cldec->storage_class |= sc->stc;
- if (cldec->storage_class & STCdeprecated)
- cldec->isdeprecated = true;
- if (cldec->storage_class & STCauto)
- cldec->error("storage class `auto` is invalid when declaring a class, did you mean to use `scope`?");
- if (cldec->storage_class & STCscope)
- cldec->isscope = true;
- if (cldec->storage_class & STCabstract)
- cldec->isabstract = ABSyes;
-
- cldec->userAttribDecl = sc->userAttribDecl;
-
- if (sc->linkage == LINKcpp)
- cldec->classKind = ClassKind::cpp;
- if (sc->linkage == LINKobjc)
- objc()->setObjc(cldec);
- }
- else if (cldec->symtab && !scx)
- {
- return;
- }
- cldec->semanticRun = PASSsemantic;
-
- if (cldec->baseok < BASEOKdone)
- {
- cldec->baseok = BASEOKin;
-
- // Expand any tuples in baseclasses[]
- for (size_t i = 0; i < cldec->baseclasses->length; )
- {
- BaseClass *b = (*cldec->baseclasses)[i];
- b->type = resolveBase(cldec, sc, scx, b->type);
-
- Type *tb = b->type->toBasetype();
- if (tb->ty == Ttuple)
- {
- TypeTuple *tup = (TypeTuple *)tb;
- cldec->baseclasses->remove(i);
- size_t dim = Parameter::dim(tup->arguments);
- for (size_t j = 0; j < dim; j++)
- {
- Parameter *arg = Parameter::getNth(tup->arguments, j);
- b = new BaseClass(arg->type);
- cldec->baseclasses->insert(i + j, b);
- }
- }
- else
- i++;
- }
-
- if (cldec->baseok >= BASEOKdone)
- {
- //printf("%s already semantic analyzed, semanticRun = %d\n", cldec->toChars(), cldec->semanticRun);
- if (cldec->semanticRun >= PASSsemanticdone)
- return;
- goto Lancestorsdone;
- }
-
- // See if there's a base class as first in baseclasses[]
- if (cldec->baseclasses->length)
- {
- BaseClass *b = (*cldec->baseclasses)[0];
- Type *tb = b->type->toBasetype();
- TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
- if (!tc)
- {
- if (b->type != Type::terror)
- cldec->error("base type must be class or interface, not %s", b->type->toChars());
- cldec->baseclasses->remove(0);
- goto L7;
- }
-
- if (tc->sym->isDeprecated())
- {
- if (!cldec->isDeprecated())
- {
- // Deriving from deprecated class makes this one deprecated too
- cldec->isdeprecated = true;
-
- tc->checkDeprecated(cldec->loc, sc);
- }
- }
-
- if (tc->sym->isInterfaceDeclaration())
- goto L7;
-
- for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass)
- {
- if (cdb == cldec)
- {
- cldec->error("circular inheritance");
- cldec->baseclasses->remove(0);
- goto L7;
- }
- }
-
- /* Bugzilla 11034: Essentially, class inheritance hierarchy
- * and instance size of each classes are orthogonal information.
- * Therefore, even if tc->sym->sizeof == SIZEOKnone,
- * we need to set baseClass field for class covariance check.
- */
- cldec->baseClass = tc->sym;
- b->sym = cldec->baseClass;
-
- if (tc->sym->baseok < BASEOKdone)
- resolveBase(cldec, sc, scx, tc->sym); // Try to resolve forward reference
- if (tc->sym->baseok < BASEOKdone)
- {
- //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
- if (tc->sym->_scope)
- Module::addDeferredSemantic(tc->sym);
- cldec->baseok = BASEOKnone;
- }
- L7: ;
- }
-
- // Treat the remaining entries in baseclasses as interfaces
- // Check for errors, handle forward references
- for (size_t i = (cldec->baseClass ? 1 : 0); i < cldec->baseclasses->length; )
- {
- BaseClass *b = (*cldec->baseclasses)[i];
- Type *tb = b->type->toBasetype();
- TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
- if (!tc || !tc->sym->isInterfaceDeclaration())
- {
- if (b->type != Type::terror)
- cldec->error("base type must be interface, not %s", b->type->toChars());
- cldec->baseclasses->remove(i);
- continue;
- }
-
- // Check for duplicate interfaces
- for (size_t j = (cldec->baseClass ? 1 : 0); j < i; j++)
- {
- BaseClass *b2 = (*cldec->baseclasses)[j];
- if (b2->sym == tc->sym)
- {
- cldec->error("inherits from duplicate interface %s", b2->sym->toChars());
- cldec->baseclasses->remove(i);
- continue;
- }
- }
-
- if (tc->sym->isDeprecated())
- {
- if (!cldec->isDeprecated())
- {
- // Deriving from deprecated class makes this one deprecated too
- cldec->isdeprecated = true;
-
- tc->checkDeprecated(cldec->loc, sc);
- }
- }
-
- b->sym = tc->sym;
-
- if (tc->sym->baseok < BASEOKdone)
- resolveBase(cldec, sc, scx, tc->sym); // Try to resolve forward reference
- if (tc->sym->baseok < BASEOKdone)
- {
- //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
- if (tc->sym->_scope)
- Module::addDeferredSemantic(tc->sym);
- cldec->baseok = BASEOKnone;
- }
- i++;
- }
- if (cldec->baseok == BASEOKnone)
- {
- // Forward referencee of one or more bases, try again later
- cldec->_scope = scx ? scx : sc->copy();
- cldec->_scope->setNoFree();
- Module::addDeferredSemantic(cldec);
- //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, cldec->toChars());
- return;
- }
- cldec->baseok = BASEOKdone;
-
- // If no base class, and this is not an Object, use Object as base class
- if (!cldec->baseClass && cldec->ident != Id::Object && !cldec->isCPPclass())
- {
- if (!ClassDeclaration::object || ClassDeclaration::object->errors)
- badObjectDotD(cldec);
-
- Type *t = ClassDeclaration::object->type;
- t = typeSemantic(t, cldec->loc, sc)->toBasetype();
- if (t->ty == Terror)
- badObjectDotD(cldec);
- assert(t->ty == Tclass);
- TypeClass *tc = (TypeClass *)t;
-
- BaseClass *b = new BaseClass(tc);
- cldec->baseclasses->shift(b);
-
- cldec->baseClass = tc->sym;
- assert(!cldec->baseClass->isInterfaceDeclaration());
- b->sym = cldec->baseClass;
- }
- if (cldec->baseClass)
- {
- if (cldec->baseClass->storage_class & STCfinal)
- cldec->error("cannot inherit from final class %s", cldec->baseClass->toChars());
-
- // Inherit properties from base class
- if (cldec->baseClass->isCOMclass())
- cldec->com = true;
- if (cldec->baseClass->isCPPclass())
- cldec->classKind = ClassKind::cpp;
- if (cldec->baseClass->isscope)
- cldec->isscope = true;
- cldec->enclosing = cldec->baseClass->enclosing;
- cldec->storage_class |= cldec->baseClass->storage_class & STC_TYPECTOR;
- }
-
- cldec->interfaces.length = cldec->baseclasses->length - (cldec->baseClass ? 1 : 0);
- cldec->interfaces.ptr = cldec->baseclasses->tdata() + (cldec->baseClass ? 1 : 0);
-
- for (size_t i = 0; i < cldec->interfaces.length; i++)
- {
- BaseClass *b = cldec->interfaces.ptr[i];
- // If this is an interface, and it derives from a COM interface,
- // then this is a COM interface too.
- if (b->sym->isCOMinterface())
- cldec->com = true;
- if (cldec->isCPPclass() && !b->sym->isCPPinterface())
- {
- error(cldec->loc, "C++ class `%s` cannot implement D interface `%s`",
- cldec->toPrettyChars(), b->sym->toPrettyChars());
- }
- }
-
- interfaceSemantic(cldec);
- }
- Lancestorsdone:
- //printf("\tClassDeclaration::semantic(%s) baseok = %d\n", cldec->toChars(), cldec->baseok);
-
- if (!cldec->members) // if opaque declaration
- {
- cldec->semanticRun = PASSsemanticdone;
- return;
- }
- if (!cldec->symtab)
- {
- cldec->symtab = new DsymbolTable();
-
- /* Bugzilla 12152: The semantic analysis of base classes should be finished
- * before the members semantic analysis of this class, in order to determine
- * vtbl in this class. However if a base class refers the member of this class,
- * it can be resolved as a normal forward reference.
- * Call addMember() and setScope() to make this class members visible from the base classes.
- */
- for (size_t i = 0; i < cldec->members->length; i++)
- {
- Dsymbol *s = (*cldec->members)[i];
- s->addMember(sc, cldec);
- }
-
- Scope *sc2 = cldec->newScope(sc);
-
- /* Set scope so if there are forward references, we still might be able to
- * resolve individual members like enums.
- */
- for (size_t i = 0; i < cldec->members->length; i++)
- {
- Dsymbol *s = (*cldec->members)[i];
- //printf("[%d] setScope %s %s, sc2 = %p\n", i, s->kind(), s->toChars(), sc2);
- s->setScope(sc2);
- }
-
- sc2->pop();
- }
-
- for (size_t i = 0; i < cldec->baseclasses->length; i++)
- {
- BaseClass *b = (*cldec->baseclasses)[i];
- Type *tb = b->type->toBasetype();
- assert(tb->ty == Tclass);
- TypeClass *tc = (TypeClass *)tb;
-
- if (tc->sym->semanticRun < PASSsemanticdone)
- {
- // Forward referencee of one or more bases, try again later
- cldec->_scope = scx ? scx : sc->copy();
- cldec->_scope->setNoFree();
- if (tc->sym->_scope)
- Module::addDeferredSemantic(tc->sym);
- Module::addDeferredSemantic(cldec);
- //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, cldec->toChars());
- return;
- }
- }
-
- if (cldec->baseok == BASEOKdone)
- {
- cldec->baseok = BASEOKsemanticdone;
-
- // initialize vtbl
- if (cldec->baseClass)
- {
- if (cldec->isCPPclass() && cldec->baseClass->vtbl.length == 0)
- {
- cldec->error("C++ base class %s needs at least one virtual function", cldec->baseClass->toChars());
- }
-
- // Copy vtbl[] from base class
- cldec->vtbl.setDim(cldec->baseClass->vtbl.length);
- memcpy(cldec->vtbl.tdata(), cldec->baseClass->vtbl.tdata(), sizeof(void *) * cldec->vtbl.length);
-
- cldec->vthis = cldec->baseClass->vthis;
- }
- else
- {
- // No base class, so this is the root of the class hierarchy
- cldec->vtbl.setDim(0);
- if (cldec->vtblOffset())
- cldec->vtbl.push(cldec); // leave room for classinfo as first member
- }
-
- /* If this is a nested class, add the hidden 'this'
- * member which is a pointer to the enclosing scope.
- */
- if (cldec->vthis) // if inheriting from nested class
- {
- // Use the base class's 'this' member
- if (cldec->storage_class & STCstatic)
- cldec->error("static class cannot inherit from nested class %s", cldec->baseClass->toChars());
- if (cldec->toParent2() != cldec->baseClass->toParent2() &&
- (!cldec->toParent2() ||
- !cldec->baseClass->toParent2()->getType() ||
- !cldec->baseClass->toParent2()->getType()->isBaseOf(cldec->toParent2()->getType(), NULL)))
- {
- if (cldec->toParent2())
- {
- cldec->error("is nested within %s, but super class %s is nested within %s",
- cldec->toParent2()->toChars(),
- cldec->baseClass->toChars(),
- cldec->baseClass->toParent2()->toChars());
- }
- else
- {
- cldec->error("is not nested, but super class %s is nested within %s",
- cldec->baseClass->toChars(),
- cldec->baseClass->toParent2()->toChars());
- }
- cldec->enclosing = NULL;
- }
- }
- else
- cldec->makeNested();
- }
-
- Scope *sc2 = cldec->newScope(sc);
-
- for (size_t i = 0; i < cldec->members->length; i++)
- {
- Dsymbol *s = (*cldec->members)[i];
- s->importAll(sc2);
- }
-
- // Note that members.length can grow due to tuple expansion during semantic()
- for (size_t i = 0; i < cldec->members->length; i++)
- {
- Dsymbol *s = (*cldec->members)[i];
- dsymbolSemantic(s, sc2);
- }
-
- if (!cldec->determineFields())
- {
- assert(cldec->type == Type::terror);
- sc2->pop();
- return;
- }
-
- /* Following special member functions creation needs semantic analysis
- * completion of sub-structs in each field types.
- */
- for (size_t i = 0; i < cldec->fields.length; i++)
- {
- VarDeclaration *v = cldec->fields[i];
- Type *tb = v->type->baseElemOf();
- if (tb->ty != Tstruct)
- continue;
- StructDeclaration *sd = ((TypeStruct *)tb)->sym;
- if (sd->semanticRun >= PASSsemanticdone)
- continue;
-
- sc2->pop();
-
- cldec->_scope = scx ? scx : sc->copy();
- cldec->_scope->setNoFree();
- Module::addDeferredSemantic(cldec);
- //printf("\tdeferring %s\n", cldec->toChars());
- return;
- }
-
- /* Look for special member functions.
- * They must be in this class, not in a base class.
- */
-
- // Can be in base class
- cldec->aggNew = (NewDeclaration *)cldec->search(Loc(), Id::classNew);
- cldec->aggDelete = (DeleteDeclaration *)cldec->search(Loc(), Id::classDelete);
-
- // Look for the constructor
- cldec->ctor = cldec->searchCtor();
-
- if (!cldec->ctor && cldec->noDefaultCtor)
- {
- // A class object is always created by constructor, so this check is legitimate.
- for (size_t i = 0; i < cldec->fields.length; i++)
- {
- VarDeclaration *v = cldec->fields[i];
- if (v->storage_class & STCnodefaultctor)
- error(v->loc, "field %s must be initialized in constructor", v->toChars());
- }
- }
-
- // If this class has no constructor, but base class has a default
- // ctor, create a constructor:
- // this() { }
- if (!cldec->ctor && cldec->baseClass && cldec->baseClass->ctor)
- {
- FuncDeclaration *fd = resolveFuncCall(cldec->loc, sc2, cldec->baseClass->ctor, NULL, cldec->type, NULL, 1);
- if (!fd) // try shared base ctor instead
- fd = resolveFuncCall(cldec->loc, sc2, cldec->baseClass->ctor, NULL, cldec->type->sharedOf(), NULL, 1);
- if (fd && !fd->errors)
- {
- //printf("Creating default this(){} for class %s\n", cldec->toChars());
- TypeFunction *btf = fd->type->toTypeFunction();
- TypeFunction *tf = new TypeFunction(ParameterList(), NULL, LINKd, fd->storage_class);
- tf->mod = btf->mod;
- tf->purity = btf->purity;
- tf->isnothrow = btf->isnothrow;
- tf->isnogc = btf->isnogc;
- tf->trust = btf->trust;
-
- CtorDeclaration *ctor = new CtorDeclaration(cldec->loc, Loc(), 0, tf);
- ctor->fbody = new CompoundStatement(Loc(), new Statements());
-
- cldec->members->push(ctor);
- ctor->addMember(sc, cldec);
- dsymbolSemantic(ctor, sc2);
-
- cldec->ctor = ctor;
- cldec->defaultCtor = ctor;
- }
- else
- {
- cldec->error("cannot implicitly generate a default ctor when base class %s is missing a default ctor",
- cldec->baseClass->toPrettyChars());
- }
- }
-
- cldec->dtor = buildDtor(cldec, sc2);
-
- if (FuncDeclaration *f = hasIdentityOpAssign(cldec, sc2))
- {
- if (!(f->storage_class & STCdisable))
- cldec->error(f->loc, "identity assignment operator overload is illegal");
- }
-
- cldec->inv = buildInv(cldec, sc2);
-
- Module::dprogress++;
- cldec->semanticRun = PASSsemanticdone;
- //printf("-ClassDeclaration.semantic(%s), type = %p\n", cldec->toChars(), cldec->type);
- //members.print();
-
- sc2->pop();
-
- if (cldec->type->ty == Tclass && ((TypeClass *)cldec->type)->sym != cldec)
- {
- // https://issues.dlang.org/show_bug.cgi?id=17492
- ClassDeclaration *cd = ((TypeClass *)cldec->type)->sym;
- cldec->error("already exists at %s. Perhaps in another function with the same name?", cd->loc.toChars());
- }
-
- if (global.errors != errors)
- {
- // The type is no good.
- cldec->type = Type::terror;
- cldec->errors = true;
- if (cldec->deferred)
- cldec->deferred->errors = true;
- }
-
- // Verify fields of a synchronized class are not public
- if (cldec->storage_class & STCsynchronized)
- {
- for (size_t i = 0; i < cldec->fields.length; i++)
- {
- VarDeclaration *vd = cldec->fields[i];
- if (!vd->isThisDeclaration() &&
- !vd->prot().isMoreRestrictiveThan(Prot(Prot::public_)))
- {
- vd->error("Field members of a synchronized class cannot be %s",
- protectionToChars(vd->prot().kind));
- }
- }
- }
-
- if (cldec->deferred && !global.gag)
- {
- semantic2(cldec->deferred, sc);
- semantic3(cldec->deferred, sc);
- }
- //printf("-ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", cldec->toChars(), cldec->type, sizeok, cldec);
- }
-
- void visit(InterfaceDeclaration *idec)
- {
- //printf("InterfaceDeclaration::semantic(%s), type = %p\n", idec->toChars(), idec->type);
- if (idec->semanticRun >= PASSsemanticdone)
- return;
- unsigned errors = global.errors;
-
- //printf("+InterfaceDeclaration.semantic(%s), type = %p\n", idec->toChars(), idec->type);
-
- Scope *scx = NULL;
- if (idec->_scope)
- {
- sc = idec->_scope;
- scx = idec->_scope; // save so we don't make redundant copies
- idec->_scope = NULL;
- }
-
- if (!idec->parent)
- {
- assert(sc->parent && sc->func);
- idec->parent = sc->parent;
- }
- assert(idec->parent && !idec->isAnonymous());
-
- if (idec->errors)
- idec->type = Type::terror;
- idec->type = typeSemantic(idec->type, idec->loc, sc);
-
- if (idec->type->ty == Tclass && ((TypeClass *)idec->type)->sym != idec)
- {
- TemplateInstance *ti = ((TypeClass *)idec->type)->sym->isInstantiated();
- if (ti && isError(ti))
- ((TypeClass *)idec->type)->sym = idec;
- }
-
- // Ungag errors when not speculative
- Ungag ungag = idec->ungagSpeculative();
-
- if (idec->semanticRun == PASSinit)
- {
- idec->protection = sc->protection;
-
- idec->storage_class |= sc->stc;
- if (idec->storage_class & STCdeprecated)
- idec->isdeprecated = true;
-
- idec->userAttribDecl = sc->userAttribDecl;
- }
- else if (idec->symtab)
- {
- if (idec->sizeok == SIZEOKdone || !scx)
- {
- idec->semanticRun = PASSsemanticdone;
- return;
- }
- }
- idec->semanticRun = PASSsemantic;
-
- if (idec->baseok < BASEOKdone)
- {
- idec->baseok = BASEOKin;
-
- // Expand any tuples in baseclasses[]
- for (size_t i = 0; i < idec->baseclasses->length; )
- {
- BaseClass *b = (*idec->baseclasses)[i];
- b->type = resolveBase(idec, sc, scx, b->type);
-
- Type *tb = b->type->toBasetype();
- if (tb->ty == Ttuple)
- {
- TypeTuple *tup = (TypeTuple *)tb;
- idec->baseclasses->remove(i);
- size_t dim = Parameter::dim(tup->arguments);
- for (size_t j = 0; j < dim; j++)
- {
- Parameter *arg = Parameter::getNth(tup->arguments, j);
- b = new BaseClass(arg->type);
- idec->baseclasses->insert(i + j, b);
- }
- }
- else
- i++;
- }
-
- if (idec->baseok >= BASEOKdone)
- {
- //printf("%s already semantic analyzed, semanticRun = %d\n", idec->toChars(), idec->semanticRun);
- if (idec->semanticRun >= PASSsemanticdone)
- return;
- goto Lancestorsdone;
- }
-
- if (!idec->baseclasses->length && sc->linkage == LINKcpp)
- idec->classKind = ClassKind::cpp;
- if (sc->linkage == LINKobjc)
- objc()->setObjc(idec);
-
- // Check for errors, handle forward references
- for (size_t i = 0; i < idec->baseclasses->length; )
- {
- BaseClass *b = (*idec->baseclasses)[i];
- Type *tb = b->type->toBasetype();
- TypeClass *tc = (tb->ty == Tclass) ? (TypeClass *)tb : NULL;
- if (!tc || !tc->sym->isInterfaceDeclaration())
- {
- if (b->type != Type::terror)
- idec->error("base type must be interface, not %s", b->type->toChars());
- idec->baseclasses->remove(i);
- continue;
- }
-
- // Check for duplicate interfaces
- for (size_t j = 0; j < i; j++)
- {
- BaseClass *b2 = (*idec->baseclasses)[j];
- if (b2->sym == tc->sym)
- {
- idec->error("inherits from duplicate interface %s", b2->sym->toChars());
- idec->baseclasses->remove(i);
- continue;
- }
- }
-
- if (tc->sym == idec || idec->isBaseOf2(tc->sym))
- {
- idec->error("circular inheritance of interface");
- idec->baseclasses->remove(i);
- continue;
- }
-
- if (tc->sym->isDeprecated())
- {
- if (!idec->isDeprecated())
- {
- // Deriving from deprecated class makes this one deprecated too
- idec->isdeprecated = true;
-
- tc->checkDeprecated(idec->loc, sc);
- }
- }
-
- b->sym = tc->sym;
-
- if (tc->sym->baseok < BASEOKdone)
- resolveBase(idec, sc, scx, tc->sym); // Try to resolve forward reference
- if (tc->sym->baseok < BASEOKdone)
- {
- //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
- if (tc->sym->_scope)
- Module::addDeferredSemantic(tc->sym);
- idec->baseok = BASEOKnone;
- }
- i++;
- }
- if (idec->baseok == BASEOKnone)
- {
- // Forward referencee of one or more bases, try again later
- idec->_scope = scx ? scx : sc->copy();
- idec->_scope->setNoFree();
- Module::addDeferredSemantic(idec);
- return;
- }
- idec->baseok = BASEOKdone;
-
- idec->interfaces.length = idec->baseclasses->length;
- idec->interfaces.ptr = idec->baseclasses->tdata();
-
- for (size_t i = 0; i < idec->interfaces.length; i++)
- {
- BaseClass *b = idec->interfaces.ptr[i];
- // If this is an interface, and it derives from a COM interface,
- // then this is a COM interface too.
- if (b->sym->isCOMinterface())
- idec->com = true;
- if (b->sym->isCPPinterface())
- idec->classKind = ClassKind::cpp;
- }
-
- interfaceSemantic(idec);
- }
- Lancestorsdone:
-
- if (!idec->members) // if opaque declaration
- {
- idec->semanticRun = PASSsemanticdone;
- return;
- }
- if (!idec->symtab)
- idec->symtab = new DsymbolTable();
-
- for (size_t i = 0; i < idec->baseclasses->length; i++)
- {
- BaseClass *b = (*idec->baseclasses)[i];
- Type *tb = b->type->toBasetype();
- assert(tb->ty == Tclass);
- TypeClass *tc = (TypeClass *)tb;
-
- if (tc->sym->semanticRun < PASSsemanticdone)
- {
- // Forward referencee of one or more bases, try again later
- idec->_scope = scx ? scx : sc->copy();
- idec->_scope->setNoFree();
- if (tc->sym->_scope)
- Module::addDeferredSemantic(tc->sym);
- Module::addDeferredSemantic(idec);
- return;
- }
- }
-
- if (idec->baseok == BASEOKdone)
- {
- idec->baseok = BASEOKsemanticdone;
-
- // initialize vtbl
- if (idec->vtblOffset())
- idec->vtbl.push(idec); // leave room at vtbl[0] for classinfo
-
- // Cat together the vtbl[]'s from base cldec->interfaces
- for (size_t i = 0; i < idec->interfaces.length; i++)
- {
- BaseClass *b = idec->interfaces.ptr[i];
-
- // Skip if b has already appeared
- for (size_t k = 0; k < i; k++)
- {
- if (b == idec->interfaces.ptr[k])
- goto Lcontinue;
- }
-
- // Copy vtbl[] from base class
- if (b->sym->vtblOffset())
- {
- size_t d = b->sym->vtbl.length;
- if (d > 1)
- {
- idec->vtbl.reserve(d - 1);
- for (size_t j = 1; j < d; j++)
- idec->vtbl.push(b->sym->vtbl[j]);
- }
- }
- else
- {
- idec->vtbl.append(&b->sym->vtbl);
- }
-
- Lcontinue:
- ;
- }
- }
-
- for (size_t i = 0; i < idec->members->length; i++)
- {
- Dsymbol *s = (*idec->members)[i];
- s->addMember(sc, idec);
- }
-
- Scope *sc2 = idec->newScope(sc);
-
- /* Set scope so if there are forward references, we still might be able to
- * resolve individual members like enums.
- */
- for (size_t i = 0; i < idec->members->length; i++)
- {
- Dsymbol *s = (*idec->members)[i];
- //printf("setScope %s %s\n", s->kind(), s->toChars());
- s->setScope(sc2);
- }
-
- for (size_t i = 0; i < idec->members->length; i++)
- {
- Dsymbol *s = (*idec->members)[i];
- s->importAll(sc2);
- }
-
- for (size_t i = 0; i < idec->members->length; i++)
- {
- Dsymbol *s = (*idec->members)[i];
- dsymbolSemantic(s, sc2);
- }
-
- Module::dprogress++;
- idec->semanticRun = PASSsemanticdone;
- //printf("-InterfaceDeclaration.semantic(%s), type = %p\n", idec->toChars(), idec->type);
- //members->print();
-
- sc2->pop();
-
- if (global.errors != errors)
- {
- // The type is no good.
- idec->type = Type::terror;
- }
-
- assert(idec->type->ty != Tclass || ((TypeClass *)idec->type)->sym == idec);
- }
-};
-
-/******************************************************
- * Do template instance semantic for isAliasSeq templates.
- * This is a greatly simplified version of TemplateInstance::semantic().
- */
-static void aliasSeqInstanceSemantic(TemplateInstance *tempinst, Scope *sc, TemplateDeclaration *tempdecl)
-{
- //printf("[%s] aliasSeqInstanceSemantic('%s')\n", tempinst->loc.toChars(), tempinst->toChars());
- Scope *paramscope = sc->push();
- paramscope->stc = 0;
- paramscope->protection = Prot(Prot::public_);
-
- TemplateTupleParameter *ttp = (*tempdecl->parameters)[0]->isTemplateTupleParameter();
- Tuple *va = isTuple(tempinst->tdtypes[0]);
- Declaration *d = new TupleDeclaration(tempinst->loc, ttp->ident, &va->objects);
- d->storage_class |= STCtemplateparameter;
- dsymbolSemantic(d, sc);
-
- paramscope->pop();
-
- tempinst->aliasdecl = d;
-
- tempinst->semanticRun = PASSsemanticdone;
-}
-
-/******************************************************
- * Do template instance semantic for isAlias templates.
- * This is a greatly simplified version of TemplateInstance::semantic().
- */
-static void aliasInstanceSemantic(TemplateInstance *tempinst, Scope *sc, TemplateDeclaration *tempdecl)
-{
- //printf("[%s] aliasInstanceSemantic('%s')\n", tempinst->loc.toChars(), tempinst->toChars());
- Scope *paramscope = sc->push();
- paramscope->stc = 0;
- paramscope->protection = Prot(Prot::public_);
-
- TemplateTypeParameter *ttp = (*tempdecl->parameters)[0]->isTemplateTypeParameter();
- Type *ta = isType(tempinst->tdtypes[0]);
- AliasDeclaration *ad = tempdecl->onemember->isAliasDeclaration();
-
- // Note: qualifiers can be in both 'ad.type.mod' and 'ad.storage_class'
- Declaration *d = new AliasDeclaration(tempinst->loc, ttp->ident, ta->addMod(ad->type->mod));
- d->storage_class |= STCtemplateparameter | ad->storage_class;
- dsymbolSemantic(d, sc);
-
- paramscope->pop();
-
- tempinst->aliasdecl = d;
-
- tempinst->semanticRun = PASSsemanticdone;
-}
-
-void templateInstanceSemantic(TemplateInstance *tempinst, Scope *sc, Expressions *fargs)
-{
- //printf("[%s] TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", tempinst->loc.toChars(), tempinst->toChars(), tempinst, global.gag, sc);
- if (tempinst->inst) // if semantic() was already run
- {
- return;
- }
- if (tempinst->semanticRun != PASSinit)
- {
- Ungag ungag(global.gag);
- if (!tempinst->gagged)
- global.gag = 0;
- tempinst->error(tempinst->loc, "recursive template expansion");
- if (tempinst->gagged)
- tempinst->semanticRun = PASSinit;
- else
- tempinst->inst = tempinst;
- tempinst->errors = true;
- return;
- }
-
- // Get the enclosing template instance from the scope tinst
- tempinst->tinst = sc->tinst;
-
- // Get the instantiating module from the scope minst
- tempinst->minst = sc->minst;
- // Bugzilla 10920: If the enclosing function is non-root symbol,
- // this instance should be speculative.
- if (!tempinst->tinst && sc->func && sc->func->inNonRoot())
- {
- tempinst->minst = NULL;
- }
-
- tempinst->gagged = (global.gag > 0);
-
- tempinst->semanticRun = PASSsemantic;
-
- /* Find template declaration first,
- * then run semantic on each argument (place results in tiargs[]),
- * last find most specialized template from overload list/set.
- */
- if (!tempinst->findTempDecl(sc, NULL) ||
- !tempinst->semanticTiargs(sc) ||
- !tempinst->findBestMatch(sc, fargs))
- {
-Lerror:
- if (tempinst->gagged)
- {
- // Bugzilla 13220: Rollback status for later semantic re-running.
- tempinst->semanticRun = PASSinit;
- }
- else
- tempinst->inst = tempinst;
- tempinst->errors = true;
- return;
- }
- TemplateDeclaration *tempdecl = tempinst->tempdecl->isTemplateDeclaration();
- assert(tempdecl);
-
- // If tempdecl is a mixin, disallow it
- if (tempdecl->ismixin)
- {
- tempinst->error("mixin templates are not regular templates");
- goto Lerror;
- }
-
- tempinst->hasNestedArgs(tempinst->tiargs, tempdecl->isstatic);
- if (tempinst->errors)
- goto Lerror;
-
- /* Greatly simplified semantic processing for AliasSeq templates
- */
- if (tempdecl->isTrivialAliasSeq)
- {
- tempinst->inst = tempinst;
- return aliasSeqInstanceSemantic(tempinst, sc, tempdecl);
- }
- /* Greatly simplified semantic processing for Alias templates
- */
- else if (tempdecl->isTrivialAlias)
- {
- tempinst->inst = tempinst;
- return aliasInstanceSemantic(tempinst, sc, tempdecl);
- }
-
- /* See if there is an existing TemplateInstantiation that already
- * implements the typeargs. If so, just refer to that one instead.
- */
- tempinst->inst = tempdecl->findExistingInstance(tempinst, fargs);
- TemplateInstance *errinst = NULL;
- if (!tempinst->inst)
- {
- // So, we need to implement 'this' instance.
- }
- else if (tempinst->inst->gagged && !tempinst->gagged && tempinst->inst->errors)
- {
- // If the first instantiation had failed, re-run semantic,
- // so that error messages are shown.
- errinst = tempinst->inst;
- }
- else
- {
- // It's a match
- tempinst->parent = tempinst->inst->parent;
- tempinst->errors = tempinst->inst->errors;
-
- // If both this and the previous instantiation were gagged,
- // use the number of errors that happened last time.
- global.errors += tempinst->errors;
- global.gaggedErrors += tempinst->errors;
-
- // If the first instantiation was gagged, but this is not:
- if (tempinst->inst->gagged)
- {
- // It had succeeded, mark it is a non-gagged instantiation,
- // and reuse it.
- tempinst->inst->gagged = tempinst->gagged;
- }
-
- tempinst->tnext = tempinst->inst->tnext;
- tempinst->inst->tnext = tempinst;
-
- /* A module can have explicit template instance and its alias
- * in module scope (e,g, `alias Base64 = Base64Impl!('+', '/');`).
- * If the first instantiation 'inst' had happened in non-root module,
- * compiler can assume that its instantiated code would be included
- * in the separately compiled obj/lib file (e.g. phobos.lib).
- *
- * However, if 'this' second instantiation happened in root module,
- * compiler might need to invoke its codegen (Bugzilla 2500 & 2644).
- * But whole import graph is not determined until all semantic pass finished,
- * so 'inst' should conservatively finish the semantic3 pass for the codegen.
- */
- if (tempinst->minst && tempinst->minst->isRoot() && !(tempinst->inst->minst && tempinst->inst->minst->isRoot()))
- {
- /* Swap the position of 'inst' and 'this' in the instantiation graph.
- * Then, the primary instance `inst` will be changed to a root instance,
- * along with all members of `inst` having their scopes updated.
- *
- * Before:
- * non-root -> A!() -> B!()[inst] -> C!() { members[non-root] }
- * |
- * root -> D!() -> B!()[this]
- *
- * After:
- * non-root -> A!() -> B!()[this]
- * |
- * root -> D!() -> B!()[inst] -> C!() { members[root] }
- */
- Module *mi = tempinst->minst;
- TemplateInstance *ti = tempinst->tinst;
- tempinst->minst = tempinst->inst->minst;
- tempinst->tinst = tempinst->inst->tinst;
- tempinst->inst->minst = mi;
- tempinst->inst->tinst = ti;
-
- /* https://issues.dlang.org/show_bug.cgi?id=21299
- `minst` has been updated on the primary instance `inst` so it is
- now coming from a root module, however all Dsymbol `inst.members`
- of the instance still have their `_scope.minst` pointing at the
- original non-root module. We must now propagate `minst` to all
- members so that forward referenced dependencies that get
- instantiated will also be appended to the root module, otherwise
- there will be undefined references at link-time. */
- class InstMemberWalker : public Visitor
- {
- public:
- TemplateInstance *inst;
-
- InstMemberWalker(TemplateInstance *inst)
- : inst(inst) { }
-
- void visit(Dsymbol *d)
- {
- if (d->_scope)
- d->_scope->minst = inst->minst;
- }
-
- void visit(ScopeDsymbol *sds)
- {
- if (!sds->members)
- return;
- for (size_t i = 0; i < sds->members->length; i++)
- {
- Dsymbol *s = (*sds->members)[i];
- s->accept(this);
- }
- visit((Dsymbol *)sds);
- }
-
- void visit(AttribDeclaration *ad)
- {
- Dsymbols *d = ad->include(NULL);
- if (!d)
- return;
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- s->accept(this);
- }
- visit((Dsymbol *)ad);
- }
-
- void visit(ConditionalDeclaration *cd)
- {
- if (cd->condition->inc)
- visit((AttribDeclaration *)cd);
- else
- visit((Dsymbol *)cd);
- }
- };
- InstMemberWalker v(tempinst->inst);
- tempinst->inst->accept(&v);
-
- if (tempinst->minst) // if inst was not speculative
- {
- /* Add 'inst' once again to the root module members[], then the
- * instance members will get codegen chances.
- */
- tempinst->inst->appendToModuleMember();
- }
- }
-
- return;
- }
- unsigned errorsave = global.errors;
-
- tempinst->inst = tempinst;
- tempinst->parent = tempinst->enclosing ? tempinst->enclosing : tempdecl->parent;
- //printf("parent = '%s'\n", tempinst->parent->kind());
-
- TemplateInstance *tempdecl_instance_idx = tempdecl->addInstance(tempinst);
-
- //getIdent();
-
- // Store the place we added it to in target_symbol_list(_idx) so we can
- // remove it later if we encounter an error.
- Dsymbols *target_symbol_list = tempinst->appendToModuleMember();
- size_t target_symbol_list_idx = target_symbol_list ? target_symbol_list->length - 1 : 0;
-
- // Copy the syntax trees from the TemplateDeclaration
- tempinst->members = Dsymbol::arraySyntaxCopy(tempdecl->members);
-
- // resolve TemplateThisParameter
- for (size_t i = 0; i < tempdecl->parameters->length; i++)
- {
- if ((*tempdecl->parameters)[i]->isTemplateThisParameter() == NULL)
- continue;
- Type *t = isType((*tempinst->tiargs)[i]);
- assert(t);
- if (StorageClass stc = ModToStc(t->mod))
- {
- //printf("t = %s, stc = x%llx\n", t->toChars(), stc);
- Dsymbols *s = new Dsymbols();
- s->push(new StorageClassDeclaration(stc, tempinst->members));
- tempinst->members = s;
- }
- break;
- }
-
- // Create our own scope for the template parameters
- Scope *scope = tempdecl->_scope;
- if (tempdecl->semanticRun == PASSinit)
- {
- tempinst->error("template instantiation %s forward references template declaration %s", tempinst->toChars(), tempdecl->toChars());
- return;
- }
-
- tempinst->argsym = new ScopeDsymbol();
- tempinst->argsym->parent = scope->parent;
- scope = scope->push(tempinst->argsym);
- scope->tinst = tempinst;
- scope->minst = tempinst->minst;
- //scope->stc = 0;
-
- // Declare each template parameter as an alias for the argument type
- Scope *paramscope = scope->push();
- paramscope->stc = 0;
- paramscope->protection = Prot(Prot::public_); // Bugzilla 14169: template parameters should be public
- tempinst->declareParameters(paramscope);
- paramscope->pop();
-
- // Add members of template instance to template instance symbol table
-// tempinst->parent = scope->scopesym;
- tempinst->symtab = new DsymbolTable();
- for (size_t i = 0; i < tempinst->members->length; i++)
- {
- Dsymbol *s = (*tempinst->members)[i];
- s->addMember(scope, tempinst);
- }
-
- /* See if there is only one member of template instance, and that
- * member has the same name as the template instance.
- * If so, this template instance becomes an alias for that member.
- */
- //printf("members->length = %d\n", tempinst->members->length);
- if (tempinst->members->length)
- {
- Dsymbol *s;
- if (Dsymbol::oneMembers(tempinst->members, &s, tempdecl->ident) && s)
- {
- //printf("tempdecl->ident = %s, s = '%s'\n", tempdecl->ident->toChars(), s->kind(), s->toPrettyChars());
- //printf("setting aliasdecl\n");
- tempinst->aliasdecl = s;
- }
- }
-
- /* If function template declaration
- */
- if (fargs && tempinst->aliasdecl)
- {
- FuncDeclaration *fd = tempinst->aliasdecl->isFuncDeclaration();
- if (fd)
- {
- /* Transmit fargs to type so that TypeFunction::semantic() can
- * resolve any "auto ref" storage classes.
- */
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (tf && tf->ty == Tfunction)
- tf->fargs = fargs;
- }
- }
-
- // Do semantic() analysis on template instance members
- Scope *sc2;
- sc2 = scope->push(tempinst);
- //printf("enclosing = %d, sc->parent = %s\n", tempinst->enclosing, sc->parent->toChars());
- sc2->parent = tempinst;
- sc2->tinst = tempinst;
- sc2->minst = tempinst->minst;
-
- tempinst->tryExpandMembers(sc2);
-
- tempinst->semanticRun = PASSsemanticdone;
-
- /* ConditionalDeclaration may introduce eponymous declaration,
- * so we should find it once again after semantic.
- */
- if (tempinst->members->length)
- {
- Dsymbol *s;
- if (Dsymbol::oneMembers(tempinst->members, &s, tempdecl->ident) && s)
- {
- if (!tempinst->aliasdecl || tempinst->aliasdecl != s)
- {
- //printf("tempdecl->ident = %s, s = '%s'\n", tempdecl->ident->toChars(), s->kind(), s->toPrettyChars());
- //printf("setting aliasdecl 2\n");
- tempinst->aliasdecl = s;
- }
- }
- }
-
- if (global.errors != errorsave)
- goto Laftersemantic;
-
- /* If any of the instantiation members didn't get semantic() run
- * on them due to forward references, we cannot run semantic2()
- * or semantic3() yet.
- */
- {
- bool found_deferred_ad = false;
- for (size_t i = 0; i < Module::deferred.length; i++)
- {
- Dsymbol *sd = Module::deferred[i];
- AggregateDeclaration *ad = sd->isAggregateDeclaration();
- if (ad && ad->parent && ad->parent->isTemplateInstance())
- {
- //printf("deferred template aggregate: %s %s\n",
- // sd->parent->toChars(), sd->toChars());
- found_deferred_ad = true;
- if (ad->parent == tempinst)
- {
- ad->deferred = tempinst;
- break;
- }
- }
- }
- if (found_deferred_ad || Module::deferred.length)
- goto Laftersemantic;
- }
-
- /* The problem is when to parse the initializer for a variable.
- * Perhaps VarDeclaration::semantic() should do it like it does
- * for initializers inside a function.
- */
- //if (sc->parent->isFuncDeclaration())
- {
- /* BUG 782: this has problems if the classes this depends on
- * are forward referenced. Find a way to defer semantic()
- * on this template.
- */
- semantic2(tempinst, sc2);
- }
- if (global.errors != errorsave)
- goto Laftersemantic;
-
- if ((sc->func || (sc->flags & SCOPEfullinst)) && !tempinst->tinst)
- {
- /* If a template is instantiated inside function, the whole instantiation
- * should be done at that position. But, immediate running semantic3 of
- * dependent templates may cause unresolved forward reference (Bugzilla 9050).
- * To avoid the issue, don't run semantic3 until semantic and semantic2 done.
- */
- TemplateInstances deferred;
- tempinst->deferred = &deferred;
-
- //printf("Run semantic3 on %s\n", tempinst->toChars());
- tempinst->trySemantic3(sc2);
-
- for (size_t i = 0; i < deferred.length; i++)
- {
- //printf("+ run deferred semantic3 on %s\n", deferred[i]->toChars());
- semantic3(deferred[i], NULL);
- }
-
- tempinst->deferred = NULL;
- }
- else if (tempinst->tinst)
- {
- bool doSemantic3 = false;
- if (sc->func && tempinst->aliasdecl && tempinst->aliasdecl->toAlias()->isFuncDeclaration())
- {
- /* Template function instantiation should run semantic3 immediately
- * for attribute inference.
- */
- tempinst->trySemantic3(sc2);
- }
- else if (sc->func)
- {
- /* A lambda function in template arguments might capture the
- * instantiated scope context. For the correct context inference,
- * all instantiated functions should run the semantic3 immediately.
- * See also compilable/test14973.d
- */
- for (size_t i = 0; i < tempinst->tdtypes.length; i++)
- {
- RootObject *oarg = tempinst->tdtypes[i];
- Dsymbol *s = getDsymbol(oarg);
- if (!s)
- continue;
-
- if (TemplateDeclaration *td = s->isTemplateDeclaration())
- {
- if (!td->literal)
- continue;
- assert(td->members && td->members->length == 1);
- s = (*td->members)[0];
- }
- if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
- {
- if (fld->tok == TOKreserved)
- {
- doSemantic3 = true;
- break;
- }
- }
- }
- //printf("[%s] %s doSemantic3 = %d\n", tempinst->loc.toChars(), tempinst->toChars(), doSemantic3);
- }
- if (doSemantic3)
- tempinst->trySemantic3(sc2);
-
- TemplateInstance *ti = tempinst->tinst;
- int nest = 0;
- while (ti && !ti->deferred && ti->tinst)
- {
- ti = ti->tinst;
- if (++nest > global.recursionLimit)
- {
- global.gag = 0; // ensure error message gets printed
- tempinst->error("recursive expansion");
- fatal();
- }
- }
- if (ti && ti->deferred)
- {
- //printf("deferred semantic3 of %p %s, ti = %s, ti->deferred = %p\n", tempinst, tempinst->toChars(), ti->toChars());
- for (size_t i = 0; ; i++)
- {
- if (i == ti->deferred->length)
- {
- ti->deferred->push(tempinst);
- break;
- }
- if ((*ti->deferred)[i] == tempinst)
- break;
- }
- }
- }
-
- if (tempinst->aliasdecl)
- {
- /* Bugzilla 13816: AliasDeclaration tries to resolve forward reference
- * twice (See inuse check in AliasDeclaration::toAlias()). It's
- * necessary to resolve mutual references of instantiated symbols, but
- * it will left a true recursive alias in tuple declaration - an
- * AliasDeclaration A refers TupleDeclaration B, and B contains A
- * in its elements. To correctly make it an error, we strictly need to
- * resolve the alias of eponymous member.
- */
- tempinst->aliasdecl = tempinst->aliasdecl->toAlias2();
- }
-
- Laftersemantic:
- sc2->pop();
-
- scope->pop();
-
- // Give additional context info if error occurred during instantiation
- if (global.errors != errorsave)
- {
- if (!tempinst->errors)
- {
- if (!tempdecl->literal)
- tempinst->error(tempinst->loc, "error instantiating");
- if (tempinst->tinst)
- tempinst->tinst->printInstantiationTrace();
- }
- tempinst->errors = true;
- if (tempinst->gagged)
- {
- // Errors are gagged, so remove the template instance from the
- // instance/symbol lists we added it to and reset our state to
- // finish clean and so we can try to instantiate it again later
- // (see bugzilla 4302 and 6602).
- tempdecl->removeInstance(tempdecl_instance_idx);
- if (target_symbol_list)
- {
- // Because we added 'this' in the last position above, we
- // should be able to remove it without messing other indices up.
- assert((*target_symbol_list)[target_symbol_list_idx] == tempinst);
- target_symbol_list->remove(target_symbol_list_idx);
- tempinst->memberOf = NULL; // no longer a member
- }
- tempinst->semanticRun = PASSinit;
- tempinst->inst = NULL;
- tempinst->symtab = NULL;
- }
- }
- else if (errinst)
- {
- /* Bugzilla 14541: If the previous gagged instance had failed by
- * circular references, currrent "error reproduction instantiation"
- * might succeed, because of the difference of instantiated context.
- * On such case, the cached error instance needs to be overridden by the
- * succeeded instance.
- */
- //printf("replaceInstance()\n");
- TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)tempdecl->instances, (void *)tempinst->hash);
- assert(tinstances);
- for (size_t i = 0; i < tinstances->length; i++)
- {
- TemplateInstance *ti = (*tinstances)[i];
- if (ti == errinst)
- {
- (*tinstances)[i] = tempinst; // override
- break;
- }
- }
- }
-}
-
-// function used to perform semantic on AliasDeclaration
-void aliasSemantic(AliasDeclaration *ds, Scope *sc)
-{
- //printf("AliasDeclaration::semantic() %s\n", ds->toChars());
-
- // as AliasDeclaration::semantic, in case we're called first.
- // see https://issues.dlang.org/show_bug.cgi?id=21001
- ds->storage_class |= sc->stc & STCdeprecated;
- ds->protection = sc->protection;
- ds->userAttribDecl = sc->userAttribDecl;
-
- // TypeTraits needs to know if it's located in an AliasDeclaration
- const unsigned oldflags = sc->flags;
- sc->flags |= SCOPEalias;
-
- if (ds->aliassym)
- {
- FuncDeclaration *fd = ds->aliassym->isFuncLiteralDeclaration();
- TemplateDeclaration *td = ds->aliassym->isTemplateDeclaration();
- if (fd || (td && td->literal))
- {
- if (fd && fd->semanticRun >= PASSsemanticdone)
- {
- sc->flags = oldflags;
- return;
- }
-
- Expression *e = new FuncExp(ds->loc, ds->aliassym);
- e = expressionSemantic(e, sc);
- if (e->op == TOKfunction)
- {
- FuncExp *fe = (FuncExp *)e;
- ds->aliassym = fe->td ? (Dsymbol *)fe->td : fe->fd;
- }
- else
- {
- ds->aliassym = NULL;
- ds->type = Type::terror;
- }
- sc->flags = oldflags;
- return;
- }
-
- if (ds->aliassym->isTemplateInstance())
- dsymbolSemantic(ds->aliassym, sc);
- sc->flags = oldflags;
- return;
- }
- ds->inuse = 1;
-
- // Given:
- // alias foo.bar.abc def;
- // it is not knowable from the syntax whether this is an alias
- // for a type or an alias for a symbol. It is up to the semantic()
- // pass to distinguish.
- // If it is a type, then type is set and getType() will return that
- // type. If it is a symbol, then aliassym is set and type is NULL -
- // toAlias() will return aliasssym.
-
- unsigned int errors = global.errors;
- Type *oldtype = ds->type;
-
- // Ungag errors when not instantiated DeclDefs scope alias
- Ungag ungag(global.gag);
- //printf("%s parent = %s, gag = %d, instantiated = %d\n", ds->toChars(), ds->parent, global.gag, ds->isInstantiated());
- if (ds->parent && global.gag && !ds->isInstantiated() && !ds->toParent2()->isFuncDeclaration())
- {
- //printf("%s type = %s\n", ds->toPrettyChars(), ds->type->toChars());
- global.gag = 0;
- }
-
- /* This section is needed because Type::resolve() will:
- * const x = 3;
- * alias y = x;
- * try to convert identifier x to 3.
- */
- Dsymbol *s = ds->type->toDsymbol(sc);
- if (errors != global.errors)
- {
- s = NULL;
- ds->type = Type::terror;
- }
- if (s && s == ds)
- {
- ds->error("cannot resolve");
- s = NULL;
- ds->type = Type::terror;
- }
- if (!s || !s->isEnumMember())
- {
- Type *t;
- Expression *e;
- Scope *sc2 = sc;
- if (ds->storage_class & (STCref | STCnothrow | STCnogc | STCpure | STCdisable))
- {
- // For 'ref' to be attached to function types, and picked
- // up by Type::resolve(), it has to go into sc.
- sc2 = sc->push();
- sc2->stc |= ds->storage_class & (STCref | STCnothrow | STCnogc | STCpure | STCshared | STCdisable);
- }
- ds->type = ds->type->addSTC(ds->storage_class);
- ds->type->resolve(ds->loc, sc2, &e, &t, &s);
- if (sc2 != sc)
- sc2->pop();
-
- if (e) // Try to convert Expression to Dsymbol
- {
- s = getDsymbol(e);
- if (!s)
- {
- if (e->op != TOKerror)
- ds->error("cannot alias an expression %s", e->toChars());
- t = Type::terror;
- }
- }
- ds->type = t;
- }
- if (s == ds)
- {
- assert(global.errors);
- ds->type = Type::terror;
- s = NULL;
- }
- if (!s) // it's a type alias
- {
- //printf("alias %s resolved to type %s\n", ds->toChars(), ds->type->toChars());
- ds->type = typeSemantic(ds->type, ds->loc, sc);
- ds->aliassym = NULL;
- }
- else // it's a symbolic alias
- {
- //printf("alias %s resolved to %s %s\n", ds->toChars(), s->kind(), s->toChars());
- ds->type = NULL;
- ds->aliassym = s;
- }
- if (global.gag && errors != global.errors)
- {
- ds->type = oldtype;
- ds->aliassym = NULL;
- }
- ds->inuse = 0;
- ds->semanticRun = PASSsemanticdone;
-
- if (Dsymbol *sx = ds->overnext)
- {
- ds->overnext = NULL;
-
- if (!ds->overloadInsert(sx))
- ScopeDsymbol::multiplyDefined(Loc(), sx, ds);
- }
- sc->flags = oldflags;
-}
-
-
-/*************************************
- * Does semantic analysis on the public face of declarations.
- */
-void dsymbolSemantic(Dsymbol *dsym, Scope *sc)
-{
- DsymbolSemanticVisitor v(sc);
- dsym->accept(&v);
-}
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
new file mode 100644
index 0000000..eac2095
--- /dev/null
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -0,0 +1,6654 @@
+/**
+ * Does the semantic 1 pass on the AST, which looks at symbol declarations but not initializers
+ * or function bodies.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dsymbolsem.d, _dsymbolsem.d)
+ * Documentation: https://dlang.org/phobos/dmd_dsymbolsem.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dsymbolsem.d
+ */
+
+module dmd.dsymbolsem;
+
+import core.stdc.stdio;
+import core.stdc.string;
+
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.apply;
+import dmd.arraytypes;
+import dmd.astcodegen;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.blockexit;
+import dmd.clone;
+import dmd.compiler;
+import dmd.dcast;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dimport;
+import dmd.dinterpret;
+import dmd.dmangle;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dtemplate;
+import dmd.dversion;
+import dmd.errors;
+import dmd.escape;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.initsem;
+import dmd.hdrgen;
+import dmd.mtype;
+import dmd.nogc;
+import dmd.nspace;
+import dmd.objc;
+import dmd.opover;
+import dmd.parse;
+import dmd.root.filename;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+import dmd.root.rootobject;
+import dmd.semantic2;
+import dmd.semantic3;
+import dmd.sideeffect;
+import dmd.statementsem;
+import dmd.staticassert;
+import dmd.tokens;
+import dmd.utf;
+import dmd.utils;
+import dmd.statement;
+import dmd.target;
+import dmd.templateparamsem;
+import dmd.typesem;
+import dmd.visitor;
+
+enum LOG = false;
+
+private uint setMangleOverride(Dsymbol s, const(char)[] sym)
+{
+ if (s.isFuncDeclaration() || s.isVarDeclaration())
+ {
+ s.isDeclaration().mangleOverride = sym;
+ return 1;
+ }
+
+ if (auto ad = s.isAttribDeclaration())
+ {
+ uint nestedCount = 0;
+
+ ad.include(null).foreachDsymbol( (s) { nestedCount += setMangleOverride(s, sym); } );
+
+ return nestedCount;
+ }
+ return 0;
+}
+
+/*************************************
+ * Does semantic analysis on the public face of declarations.
+ */
+extern(C++) void dsymbolSemantic(Dsymbol dsym, Scope* sc)
+{
+ scope v = new DsymbolSemanticVisitor(sc);
+ dsym.accept(v);
+}
+
+/***************************************************
+ * Determine the numerical value of the AlignmentDeclaration
+ * Params:
+ * ad = AlignmentDeclaration
+ * sc = context
+ * Returns:
+ * alignment as numerical value that is never 0.
+ * STRUCTALIGN_DEFAULT is used instead.
+ * STRUCTALIGN_DEFAULT is returned for errors
+ */
+structalign_t getAlignment(AlignDeclaration ad, Scope* sc)
+{
+ if (ad.salign != ad.UNKNOWN) // UNKNOWN is 0
+ return ad.salign;
+
+ if (!ad.exps)
+ return ad.salign = STRUCTALIGN_DEFAULT;
+
+ dinteger_t strictest = 0; // strictest alignment
+ bool errors;
+ foreach (ref exp; (*ad.exps)[])
+ {
+ sc = sc.startCTFE();
+ auto e = exp.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ sc = sc.endCTFE();
+ e = e.ctfeInterpret();
+ exp = e; // could be re-evaluated if exps are assigned to more than one AlignDeclaration by CParser.applySpecifier(),
+ // e.g. `_Alignas(8) int a, b;`
+ if (e.op == TOK.error)
+ errors = true;
+ else
+ {
+ auto n = e.toInteger();
+ if (sc.flags & SCOPE.Cfile && n == 0) // C11 6.7.5-6 allows 0 for alignment
+ continue;
+
+ if (n < 1 || n & (n - 1) || structalign_t.max < n || !e.type.isintegral())
+ {
+ error(ad.loc, "alignment must be an integer positive power of 2, not 0x%llx", cast(ulong)n);
+ errors = true;
+ }
+ if (n > strictest) // C11 6.7.5-6
+ strictest = n;
+ }
+ }
+
+ ad.salign = (errors || strictest == 0) // C11 6.7.5-6 says alignment of 0 means no effect
+ ? STRUCTALIGN_DEFAULT
+ : cast(structalign_t) strictest;
+ return ad.salign;
+}
+
+const(char)* getMessage(DeprecatedDeclaration dd)
+{
+ if (auto sc = dd._scope)
+ {
+ dd._scope = null;
+
+ sc = sc.startCTFE();
+ dd.msg = dd.msg.expressionSemantic(sc);
+ dd.msg = resolveProperties(sc, dd.msg);
+ sc = sc.endCTFE();
+ dd.msg = dd.msg.ctfeInterpret();
+
+ if (auto se = dd.msg.toStringExp())
+ dd.msgstr = se.toStringz().ptr;
+ else
+ dd.msg.error("compile time constant expected, not `%s`", dd.msg.toChars());
+ }
+ return dd.msgstr;
+}
+
+
+// Returns true if a contract can appear without a function body.
+package bool allowsContractWithoutBody(FuncDeclaration funcdecl)
+{
+ assert(!funcdecl.fbody);
+
+ /* Contracts can only appear without a body when they are virtual
+ * interface functions or abstract.
+ */
+ Dsymbol parent = funcdecl.toParent();
+ InterfaceDeclaration id = parent.isInterfaceDeclaration();
+
+ if (!funcdecl.isAbstract() &&
+ (funcdecl.fensures || funcdecl.frequires) &&
+ !(id && funcdecl.isVirtual()))
+ {
+ auto cd = parent.isClassDeclaration();
+ if (!(cd && cd.isAbstract()))
+ return false;
+ }
+ return true;
+}
+
+private extern(C++) final class DsymbolSemanticVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+
+ Scope* sc;
+ this(Scope* sc)
+ {
+ this.sc = sc;
+ }
+
+ // Save the scope and defer semantic analysis on the Dsymbol.
+ private void deferDsymbolSemantic(Dsymbol s, Scope *scx)
+ {
+ s._scope = scx ? scx : sc.copy();
+ s._scope.setNoFree();
+ Module.addDeferredSemantic(s);
+ }
+
+ override void visit(Dsymbol dsym)
+ {
+ dsym.error("%p has no semantic routine", dsym);
+ }
+
+ override void visit(ScopeDsymbol) { }
+ override void visit(Declaration) { }
+
+ override void visit(AliasThis dsym)
+ {
+ if (dsym.semanticRun != PASS.init)
+ return;
+
+ if (dsym._scope)
+ {
+ sc = dsym._scope;
+ dsym._scope = null;
+ }
+
+ if (!sc)
+ return;
+
+ dsym.semanticRun = PASS.semantic;
+ dsym.isDeprecated_ = !!(sc.stc & STC.deprecated_);
+
+ Dsymbol p = sc.parent.pastMixin();
+ AggregateDeclaration ad = p.isAggregateDeclaration();
+ if (!ad)
+ {
+ error(dsym.loc, "alias this can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars());
+ return;
+ }
+
+ assert(ad.members);
+ Dsymbol s = ad.search(dsym.loc, dsym.ident);
+ if (!s)
+ {
+ s = sc.search(dsym.loc, dsym.ident, null);
+ if (s)
+ error(dsym.loc, "`%s` is not a member of `%s`", s.toChars(), ad.toChars());
+ else
+ error(dsym.loc, "undefined identifier `%s`", dsym.ident.toChars());
+ return;
+ }
+ if (ad.aliasthis && s != ad.aliasthis)
+ {
+ error(dsym.loc, "there can be only one alias this");
+ return;
+ }
+
+ /* disable the alias this conversion so the implicit conversion check
+ * doesn't use it.
+ */
+ ad.aliasthis = null;
+
+ Dsymbol sx = s;
+ if (sx.isAliasDeclaration())
+ sx = sx.toAlias();
+ Declaration d = sx.isDeclaration();
+ if (d && !d.isTupleDeclaration())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=18429
+ *
+ * If the identifier in the AliasThis declaration
+ * is defined later and is a voldemort type, we must
+ * perform semantic on the declaration to deduce the type.
+ */
+ if (!d.type)
+ d.dsymbolSemantic(sc);
+
+ Type t = d.type;
+ assert(t);
+ if (ad.type.implicitConvTo(t) > MATCH.nomatch)
+ {
+ error(dsym.loc, "alias this is not reachable as `%s` already converts to `%s`", ad.toChars(), t.toChars());
+ }
+ }
+
+ dsym.sym = s;
+ // Restore alias this
+ ad.aliasthis = dsym;
+ dsym.semanticRun = PASS.semanticdone;
+ }
+
+ override void visit(AliasDeclaration dsym)
+ {
+ if (dsym.semanticRun >= PASS.semanticdone)
+ return;
+ assert(dsym.semanticRun <= PASS.semantic);
+
+ dsym.storage_class |= sc.stc & STC.deprecated_;
+ dsym.visibility = sc.visibility;
+ dsym.userAttribDecl = sc.userAttribDecl;
+
+ if (!sc.func && dsym.inNonRoot())
+ return;
+
+ aliasSemantic(dsym, sc);
+ }
+
+ override void visit(AliasAssign dsym)
+ {
+ //printf("visit(AliasAssign)\n");
+ if (dsym.semanticRun >= PASS.semanticdone)
+ return;
+ assert(dsym.semanticRun <= PASS.semantic);
+
+ if (!sc.func && dsym.inNonRoot())
+ return;
+
+ aliasAssignSemantic(dsym, sc);
+ }
+
+ override void visit(VarDeclaration dsym)
+ {
+ version (none)
+ {
+ printf("VarDeclaration::semantic('%s', parent = '%s') sem = %d\n",
+ dsym.toChars(), sc.parent ? sc.parent.toChars() : null, dsym.semanticRun);
+ printf(" type = %s\n", dsym.type ? dsym.type.toChars() : "null");
+ printf(" stc = x%llx\n", dsym.storage_class);
+ printf(" storage_class = x%llx\n", dsym.storage_class);
+ printf("linkage = %d\n", dsym.linkage);
+ //if (strcmp(toChars(), "mul") == 0) assert(0);
+ }
+ //if (semanticRun > PASS.init)
+ // return;
+ //semanticRun = PSSsemantic;
+
+ if (dsym.semanticRun >= PASS.semanticdone)
+ return;
+
+ if (sc && sc.inunion && sc.inunion.isAnonDeclaration())
+ dsym.overlapped = true;
+
+ Scope* scx = null;
+ if (dsym._scope)
+ {
+ sc = dsym._scope;
+ scx = sc;
+ dsym._scope = null;
+ }
+
+ if (!sc)
+ return;
+
+ dsym.semanticRun = PASS.semantic;
+
+ /* Pick up storage classes from context, but except synchronized,
+ * override, abstract, and final.
+ */
+ dsym.storage_class |= (sc.stc & ~(STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_));
+ if (dsym.storage_class & STC.extern_ && dsym._init)
+ dsym.error("extern symbols cannot have initializers");
+
+ dsym.userAttribDecl = sc.userAttribDecl;
+ dsym.cppnamespace = sc.namespace;
+
+ AggregateDeclaration ad = dsym.isThis();
+ if (ad)
+ dsym.storage_class |= ad.storage_class & STC.TYPECTOR;
+
+ /* If auto type inference, do the inference
+ */
+ int inferred = 0;
+ if (!dsym.type)
+ {
+ dsym.inuse++;
+
+ // Infering the type requires running semantic,
+ // so mark the scope as ctfe if required
+ bool needctfe = (dsym.storage_class & (STC.manifest | STC.static_)) != 0;
+ if (needctfe)
+ {
+ sc.flags |= SCOPE.condition;
+ sc = sc.startCTFE();
+ }
+ //printf("inferring type for %s with init %s\n", dsym.toChars(), dsym._init.toChars());
+ dsym._init = dsym._init.inferType(sc);
+ dsym.type = dsym._init.initializerToExpression().type;
+ if (needctfe)
+ sc = sc.endCTFE();
+
+ dsym.inuse--;
+ inferred = 1;
+
+ /* This is a kludge to support the existing syntax for RAII
+ * declarations.
+ */
+ dsym.storage_class &= ~STC.auto_;
+ dsym.originalType = dsym.type.syntaxCopy();
+ }
+ else
+ {
+ if (!dsym.originalType)
+ dsym.originalType = dsym.type.syntaxCopy();
+
+ /* Prefix function attributes of variable declaration can affect
+ * its type:
+ * pure nothrow void function() fp;
+ * static assert(is(typeof(fp) == void function() pure nothrow));
+ */
+ Scope* sc2 = sc.push();
+ sc2.stc |= (dsym.storage_class & STC.FUNCATTR);
+ dsym.inuse++;
+ dsym.type = dsym.type.typeSemantic(dsym.loc, sc2);
+ dsym.inuse--;
+ sc2.pop();
+ }
+ //printf(" semantic type = %s\n", dsym.type ? dsym.type.toChars() : "null");
+ if (dsym.type.ty == Terror)
+ dsym.errors = true;
+
+ dsym.type.checkDeprecated(dsym.loc, sc);
+ dsym.linkage = sc.linkage;
+ dsym.parent = sc.parent;
+ //printf("this = %p, parent = %p, '%s'\n", dsym, dsym.parent, dsym.parent.toChars());
+ dsym.visibility = sc.visibility;
+
+ /* If scope's alignment is the default, use the type's alignment,
+ * otherwise the scope overrrides.
+ */
+ dsym.alignment = sc.alignment();
+ if (dsym.alignment == STRUCTALIGN_DEFAULT)
+ dsym.alignment = dsym.type.alignment(); // use type's alignment
+
+ //printf("sc.stc = %x\n", sc.stc);
+ //printf("storage_class = x%x\n", storage_class);
+
+ if (global.params.vcomplex)
+ dsym.type.checkComplexTransition(dsym.loc, sc);
+
+ // Calculate type size + safety checks
+ if (sc.func && !sc.intypeof)
+ {
+ if (dsym.storage_class & STC.gshared && !dsym.isMember())
+ {
+ if (sc.func.setUnsafe())
+ dsym.error("__gshared not allowed in safe functions; use shared");
+ }
+ }
+
+ Dsymbol parent = dsym.toParent();
+
+ Type tb = dsym.type.toBasetype();
+ Type tbn = tb.baseElemOf();
+ if (tb.ty == Tvoid && !(dsym.storage_class & STC.lazy_))
+ {
+ if (inferred)
+ {
+ dsym.error("type `%s` is inferred from initializer `%s`, and variables cannot be of type `void`", dsym.type.toChars(), dsym._init.toChars());
+ }
+ else
+ dsym.error("variables cannot be of type `void`");
+ dsym.type = Type.terror;
+ tb = dsym.type;
+ }
+ if (tb.ty == Tfunction)
+ {
+ dsym.error("cannot be declared to be a function");
+ dsym.type = Type.terror;
+ tb = dsym.type;
+ }
+ if (auto ts = tb.isTypeStruct())
+ {
+ // Require declarations, except when it's just a reference (as done for pointers)
+ // or when the variable is defined externally
+ if (!ts.sym.members && !(dsym.storage_class & (STC.ref_ | STC.extern_)))
+ {
+ dsym.error("no definition of struct `%s`", ts.toChars());
+
+ // Explain why the definition is required when it's part of another type
+ if (!dsym.type.isTypeStruct())
+ {
+ // Prefer Loc of the dependant type
+ const s = dsym.type.toDsymbol(sc);
+ const loc = (s ? s : dsym).loc;
+ loc.errorSupplemental("required by type `%s`", dsym.type.toChars());
+ }
+
+ // Flag variable as error to avoid invalid error messages due to unknown size
+ dsym.type = Type.terror;
+ }
+ }
+ if ((dsym.storage_class & STC.auto_) && !inferred)
+ dsym.error("storage class `auto` has no effect if type is not inferred, did you mean `scope`?");
+
+ if (auto tt = tb.isTypeTuple())
+ {
+ /* Instead, declare variables for each of the tuple elements
+ * and add those.
+ */
+ size_t nelems = Parameter.dim(tt.arguments);
+ Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression() : null;
+ if (ie)
+ ie = ie.expressionSemantic(sc);
+ if (nelems > 0 && ie)
+ {
+ auto iexps = new Expressions();
+ iexps.push(ie);
+ auto exps = new Expressions();
+ for (size_t pos = 0; pos < iexps.dim; pos++)
+ {
+ Lexpand1:
+ Expression e = (*iexps)[pos];
+ Parameter arg = Parameter.getNth(tt.arguments, pos);
+ arg.type = arg.type.typeSemantic(dsym.loc, sc);
+ //printf("[%d] iexps.dim = %d, ", pos, iexps.dim);
+ //printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars());
+ //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
+
+ if (e != ie)
+ {
+ if (iexps.dim > nelems)
+ goto Lnomatch;
+ if (e.type.implicitConvTo(arg.type))
+ continue;
+ }
+
+ if (auto te = e.isTupleExp())
+ {
+ if (iexps.dim - 1 + te.exps.dim > nelems)
+ goto Lnomatch;
+
+ iexps.remove(pos);
+ iexps.insert(pos, te.exps);
+ (*iexps)[pos] = Expression.combine(te.e0, (*iexps)[pos]);
+ goto Lexpand1;
+ }
+ else if (isAliasThisTuple(e))
+ {
+ auto v = copyToTemp(0, "__tup", e);
+ v.dsymbolSemantic(sc);
+ auto ve = new VarExp(dsym.loc, v);
+ ve.type = e.type;
+
+ exps.setDim(1);
+ (*exps)[0] = ve;
+ expandAliasThisTuples(exps, 0);
+
+ for (size_t u = 0; u < exps.dim; u++)
+ {
+ Lexpand2:
+ Expression ee = (*exps)[u];
+ arg = Parameter.getNth(tt.arguments, pos + u);
+ arg.type = arg.type.typeSemantic(dsym.loc, sc);
+ //printf("[%d+%d] exps.dim = %d, ", pos, u, exps.dim);
+ //printf("ee = (%s %s, %s), ", Token::tochars[ee.op], ee.toChars(), ee.type.toChars());
+ //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
+
+ size_t iexps_dim = iexps.dim - 1 + exps.dim;
+ if (iexps_dim > nelems)
+ goto Lnomatch;
+ if (ee.type.implicitConvTo(arg.type))
+ continue;
+
+ if (expandAliasThisTuples(exps, u) != -1)
+ goto Lexpand2;
+ }
+
+ if ((*exps)[0] != ve)
+ {
+ Expression e0 = (*exps)[0];
+ (*exps)[0] = new CommaExp(dsym.loc, new DeclarationExp(dsym.loc, v), e0);
+ (*exps)[0].type = e0.type;
+
+ iexps.remove(pos);
+ iexps.insert(pos, exps);
+ goto Lexpand1;
+ }
+ }
+ }
+ if (iexps.dim < nelems)
+ goto Lnomatch;
+
+ ie = new TupleExp(dsym._init.loc, iexps);
+ }
+ Lnomatch:
+
+ if (ie && ie.op == TOK.tuple)
+ {
+ auto te = ie.isTupleExp();
+ size_t tedim = te.exps.dim;
+ if (tedim != nelems)
+ {
+ error(dsym.loc, "tuple of %d elements cannot be assigned to tuple of %d elements", cast(int)tedim, cast(int)nelems);
+ for (size_t u = tedim; u < nelems; u++) // fill dummy expression
+ te.exps.push(ErrorExp.get());
+ }
+ }
+
+ auto exps = new Objects(nelems);
+ for (size_t i = 0; i < nelems; i++)
+ {
+ Parameter arg = Parameter.getNth(tt.arguments, i);
+
+ OutBuffer buf;
+ buf.printf("__%s_field_%llu", dsym.ident.toChars(), cast(ulong)i);
+ auto id = Identifier.idPool(buf[]);
+
+ Initializer ti;
+ if (ie)
+ {
+ Expression einit = ie;
+ if (auto te = ie.isTupleExp())
+ {
+ einit = (*te.exps)[i];
+ if (i == 0)
+ einit = Expression.combine(te.e0, einit);
+ }
+ ti = new ExpInitializer(einit.loc, einit);
+ }
+ else
+ ti = dsym._init ? dsym._init.syntaxCopy() : null;
+
+ StorageClass storage_class = STC.temp | STC.local | dsym.storage_class;
+ if ((dsym.storage_class & STC.parameter) && (arg.storageClass & STC.parameter))
+ storage_class |= arg.storageClass;
+ auto v = new VarDeclaration(dsym.loc, arg.type, id, ti, storage_class);
+ //printf("declaring field %s of type %s\n", v.toChars(), v.type.toChars());
+ v.dsymbolSemantic(sc);
+
+ if (sc.scopesym)
+ {
+ //printf("adding %s to %s\n", v.toChars(), sc.scopesym.toChars());
+ if (sc.scopesym.members)
+ // Note this prevents using foreach() over members, because the limits can change
+ sc.scopesym.members.push(v);
+ }
+
+ Expression e = new DsymbolExp(dsym.loc, v);
+ (*exps)[i] = e;
+ }
+ auto v2 = new TupleDeclaration(dsym.loc, dsym.ident, exps);
+ v2.parent = dsym.parent;
+ v2.isexp = true;
+ dsym.aliassym = v2;
+ dsym.semanticRun = PASS.semanticdone;
+ return;
+ }
+
+ /* Storage class can modify the type
+ */
+ dsym.type = dsym.type.addStorageClass(dsym.storage_class);
+
+ /* Adjust storage class to reflect type
+ */
+ if (dsym.type.isConst())
+ {
+ dsym.storage_class |= STC.const_;
+ if (dsym.type.isShared())
+ dsym.storage_class |= STC.shared_;
+ }
+ else if (dsym.type.isImmutable())
+ dsym.storage_class |= STC.immutable_;
+ else if (dsym.type.isShared())
+ dsym.storage_class |= STC.shared_;
+ else if (dsym.type.isWild())
+ dsym.storage_class |= STC.wild;
+
+ if (StorageClass stc = dsym.storage_class & (STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_))
+ {
+ if (stc == STC.final_)
+ dsym.error("cannot be `final`, perhaps you meant `const`?");
+ else
+ {
+ OutBuffer buf;
+ stcToBuffer(&buf, stc);
+ dsym.error("cannot be `%s`", buf.peekChars());
+ }
+ dsym.storage_class &= ~stc; // strip off
+ }
+
+ // At this point we can add `scope` to the STC instead of `in`,
+ // because we are never going to use this variable's STC for user messages
+ if (dsym.storage_class & STC.in_ && global.params.previewIn)
+ dsym.storage_class |= STC.scope_;
+
+ if (dsym.storage_class & STC.scope_)
+ {
+ StorageClass stc = dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.tls | STC.gshared);
+ if (stc)
+ {
+ OutBuffer buf;
+ stcToBuffer(&buf, stc);
+ dsym.error("cannot be `scope` and `%s`", buf.peekChars());
+ }
+ else if (dsym.isMember())
+ {
+ dsym.error("field cannot be `scope`");
+ }
+ else if (!dsym.type.hasPointers())
+ {
+ dsym.storage_class &= ~STC.scope_; // silently ignore; may occur in generic code
+ }
+ }
+
+ if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.manifest | STC.templateparameter | STC.tls | STC.gshared | STC.ctfe))
+ {
+ }
+ else
+ {
+ AggregateDeclaration aad = parent.isAggregateDeclaration();
+ if (aad)
+ {
+ if (global.params.vfield && dsym.storage_class & (STC.const_ | STC.immutable_) && dsym._init && !dsym._init.isVoidInitializer())
+ {
+ const(char)* s = (dsym.storage_class & STC.immutable_) ? "immutable" : "const";
+ message(dsym.loc, "`%s.%s` is `%s` field", ad.toPrettyChars(), dsym.toChars(), s);
+ }
+ dsym.storage_class |= STC.field;
+ if (auto ts = tbn.isTypeStruct())
+ if (ts.sym.noDefaultCtor)
+ {
+ if (!dsym.isThisDeclaration() && !dsym._init)
+ aad.noDefaultCtor = true;
+ }
+ }
+
+ InterfaceDeclaration id = parent.isInterfaceDeclaration();
+ if (id)
+ {
+ dsym.error("field not allowed in interface");
+ }
+ else if (aad && aad.sizeok == Sizeok.done)
+ {
+ dsym.error("cannot be further field because it will change the determined %s size", aad.toChars());
+ }
+
+ /* Templates cannot add fields to aggregates
+ */
+ TemplateInstance ti = parent.isTemplateInstance();
+ if (ti)
+ {
+ // Take care of nested templates
+ while (1)
+ {
+ TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance();
+ if (!ti2)
+ break;
+ ti = ti2;
+ }
+ // If it's a member template
+ AggregateDeclaration ad2 = ti.tempdecl.isMember();
+ if (ad2 && dsym.storage_class != STC.undefined_)
+ {
+ dsym.error("cannot use template to add field to aggregate `%s`", ad2.toChars());
+ }
+ }
+ }
+
+ if ((dsym.storage_class & (STC.ref_ | STC.parameter | STC.foreach_ | STC.temp | STC.result)) == STC.ref_ && dsym.ident != Id.This)
+ {
+ dsym.error("only parameters or `foreach` declarations can be `ref`");
+ }
+
+ if (dsym.type.hasWild())
+ {
+ if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.field) || dsym.isDataseg())
+ {
+ dsym.error("only parameters or stack based variables can be `inout`");
+ }
+ FuncDeclaration func = sc.func;
+ if (func)
+ {
+ if (func.fes)
+ func = func.fes.func;
+ bool isWild = false;
+ for (FuncDeclaration fd = func; fd; fd = fd.toParentDecl().isFuncDeclaration())
+ {
+ if (fd.type.isTypeFunction().iswild)
+ {
+ isWild = true;
+ break;
+ }
+ }
+ if (!isWild)
+ {
+ dsym.error("`inout` variables can only be declared inside `inout` functions");
+ }
+ }
+ }
+
+ if (!(dsym.storage_class & (STC.ctfe | STC.extern_ | STC.ref_ | STC.result)) &&
+ tbn.ty == Tstruct && tbn.isTypeStruct().sym.noDefaultCtor)
+ {
+ if (!dsym._init)
+ {
+ if (dsym.isField())
+ {
+ /* For fields, we'll check the constructor later to make sure it is initialized
+ */
+ dsym.storage_class |= STC.nodefaultctor;
+ }
+ else if (dsym.storage_class & STC.parameter)
+ {
+ }
+ else
+ dsym.error("default construction is disabled for type `%s`", dsym.type.toChars());
+ }
+ }
+
+ FuncDeclaration fd = parent.isFuncDeclaration();
+ if (dsym.type.isscope() && !(dsym.storage_class & STC.nodtor))
+ {
+ if (dsym.storage_class & (STC.field | STC.out_ | STC.ref_ | STC.static_ | STC.manifest | STC.tls | STC.gshared) || !fd)
+ {
+ dsym.error("globals, statics, fields, manifest constants, ref and out parameters cannot be `scope`");
+ }
+
+ // @@@DEPRECATED@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+ // Deprecated in 2.087
+ // Remove this when the feature is removed from the language
+ if (0 && // deprecation disabled for now to accommodate existing extensive use
+ !(dsym.storage_class & STC.scope_))
+ {
+ if (!(dsym.storage_class & STC.parameter) && dsym.ident != Id.withSym)
+ dsym.error("reference to `scope class` must be `scope`");
+ }
+ }
+
+ // Calculate type size + safety checks
+ if (sc.func && !sc.intypeof)
+ {
+ if (dsym._init && dsym._init.isVoidInitializer() &&
+ (dsym.type.hasPointers() || dsym.type.hasInvariant())) // also computes type size
+ {
+ if (sc.func.setUnsafe())
+ {
+ if (dsym.type.hasPointers())
+ dsym.error("`void` initializers for pointers not allowed in safe functions");
+ else
+ dsym.error("`void` initializers for structs with invariants are not allowed in safe functions");
+ }
+ }
+ else if (!dsym._init &&
+ !(dsym.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.field | STC.parameter)) &&
+ dsym.type.hasVoidInitPointers())
+ {
+ if (sc.func.setUnsafe())
+ dsym.error("`void` initializers for pointers not allowed in safe functions");
+ }
+ }
+
+ if ((!dsym._init || dsym._init.isVoidInitializer) && !fd)
+ {
+ // If not mutable, initializable by constructor only
+ dsym.storage_class |= STC.ctorinit;
+ }
+
+ if (dsym._init)
+ dsym.storage_class |= STC.init; // remember we had an explicit initializer
+ else if (dsym.storage_class & STC.manifest)
+ dsym.error("manifest constants must have initializers");
+
+ bool isBlit = false;
+ d_uns64 sz;
+ if (!dsym._init &&
+ !(dsym.storage_class & (STC.static_ | STC.gshared | STC.extern_)) &&
+ fd &&
+ (!(dsym.storage_class & (STC.field | STC.in_ | STC.foreach_ | STC.parameter | STC.result)) ||
+ (dsym.storage_class & STC.out_)) &&
+ (sz = dsym.type.size()) != 0)
+ {
+ // Provide a default initializer
+
+ //printf("Providing default initializer for '%s'\n", toChars());
+ if (sz == SIZE_INVALID && dsym.type.ty != Terror)
+ dsym.error("size of type `%s` is invalid", dsym.type.toChars());
+
+ Type tv = dsym.type;
+ while (tv.ty == Tsarray) // Don't skip Tenum
+ tv = tv.nextOf();
+ if (tv.needsNested())
+ {
+ /* Nested struct requires valid enclosing frame pointer.
+ * In StructLiteralExp::toElem(), it's calculated.
+ */
+ assert(tbn.ty == Tstruct);
+ checkFrameAccess(dsym.loc, sc, tbn.isTypeStruct().sym);
+
+ Expression e = tv.defaultInitLiteral(dsym.loc);
+ e = new BlitExp(dsym.loc, new VarExp(dsym.loc, dsym), e);
+ e = e.expressionSemantic(sc);
+ dsym._init = new ExpInitializer(dsym.loc, e);
+ goto Ldtor;
+ }
+ if (tv.ty == Tstruct && tv.isTypeStruct().sym.zeroInit)
+ {
+ /* If a struct is all zeros, as a special case
+ * set its initializer to the integer 0.
+ * In AssignExp::toElem(), we check for this and issue
+ * a memset() to initialize the struct.
+ * Must do same check in interpreter.
+ */
+ Expression e = IntegerExp.literal!0;
+ e = new BlitExp(dsym.loc, new VarExp(dsym.loc, dsym), e);
+ e.type = dsym.type; // don't type check this, it would fail
+ dsym._init = new ExpInitializer(dsym.loc, e);
+ goto Ldtor;
+ }
+ if (dsym.type.baseElemOf().ty == Tvoid)
+ {
+ dsym.error("`%s` does not have a default initializer", dsym.type.toChars());
+ }
+ else if (auto e = dsym.type.defaultInit(dsym.loc))
+ {
+ dsym._init = new ExpInitializer(dsym.loc, e);
+ }
+
+ // Default initializer is always a blit
+ isBlit = true;
+ }
+ if (dsym._init)
+ {
+ sc = sc.push();
+ sc.stc &= ~(STC.TYPECTOR | STC.pure_ | STC.nothrow_ | STC.nogc | STC.ref_ | STC.disable);
+
+ ExpInitializer ei = dsym._init.isExpInitializer();
+
+ if (ei) // https://issues.dlang.org/show_bug.cgi?id=13424
+ // Preset the required type to fail in FuncLiteralDeclaration::semantic3
+ ei.exp = inferType(ei.exp, dsym.type);
+
+ // If inside function, there is no semantic3() call
+ if (sc.func || sc.intypeof == 1)
+ {
+ // If local variable, use AssignExp to handle all the various
+ // possibilities.
+ if (fd && !(dsym.storage_class & (STC.manifest | STC.static_ | STC.tls | STC.gshared | STC.extern_)) && !dsym._init.isVoidInitializer())
+ {
+ //printf("fd = '%s', var = '%s'\n", fd.toChars(), toChars());
+ if (!ei)
+ {
+ ArrayInitializer ai = dsym._init.isArrayInitializer();
+ Expression e;
+ if (ai && tb.ty == Taarray)
+ e = ai.toAssocArrayLiteral();
+ else
+ e = dsym._init.initializerToExpression();
+ if (!e)
+ {
+ // Run semantic, but don't need to interpret
+ dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITnointerpret);
+ e = dsym._init.initializerToExpression();
+ if (!e)
+ {
+ dsym.error("is not a static and cannot have static initializer");
+ e = ErrorExp.get();
+ }
+ }
+ ei = new ExpInitializer(dsym._init.loc, e);
+ dsym._init = ei;
+ }
+
+ Expression exp = ei.exp;
+ Expression e1 = new VarExp(dsym.loc, dsym);
+ if (isBlit)
+ exp = new BlitExp(dsym.loc, e1, exp);
+ else
+ exp = new ConstructExp(dsym.loc, e1, exp);
+ dsym.canassign++;
+ exp = exp.expressionSemantic(sc);
+ dsym.canassign--;
+ exp = exp.optimize(WANTvalue);
+ if (exp.op == TOK.error)
+ {
+ dsym._init = new ErrorInitializer();
+ ei = null;
+ }
+ else
+ ei.exp = exp;
+
+ if (ei && dsym.isScope())
+ {
+ Expression ex = ei.exp.lastComma();
+ if (ex.op == TOK.blit || ex.op == TOK.construct)
+ ex = (cast(AssignExp)ex).e2;
+ if (auto ne = ex.isNewExp())
+ {
+ // See if initializer is a NewExp that can be allocated on the stack
+ if (dsym.type.toBasetype().ty == Tclass)
+ {
+ if (ne.newargs && ne.newargs.dim > 1)
+ {
+ dsym.mynew = true;
+ }
+ else
+ {
+ ne.onstack = 1;
+ dsym.onstack = true;
+ }
+ }
+ }
+ else if (auto fe = ex.isFuncExp())
+ {
+ // or a delegate that doesn't escape a reference to the function
+ FuncDeclaration f = fe.fd;
+ if (f.tookAddressOf)
+ f.tookAddressOf--;
+ }
+ }
+ }
+ else
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=14166
+ // Don't run CTFE for the temporary variables inside typeof
+ dsym._init = dsym._init.initializerSemantic(sc, dsym.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret);
+ const init_err = dsym._init.isExpInitializer();
+ if (init_err && init_err.exp.op == TOK.showCtfeContext)
+ {
+ errorSupplemental(dsym.loc, "compile time context created here");
+ }
+ }
+ }
+ else if (parent.isAggregateDeclaration())
+ {
+ dsym._scope = scx ? scx : sc.copy();
+ dsym._scope.setNoFree();
+ }
+ else if (dsym.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) ||
+ dsym.type.isConst() || dsym.type.isImmutable() ||
+ sc.flags & SCOPE.Cfile)
+ {
+ /* Because we may need the results of a const declaration in a
+ * subsequent type, such as an array dimension, before semantic2()
+ * gets ordinarily run, try to run semantic2() now.
+ * If a C array is of unknown size, the initializer can provide the size. Do this
+ * eagerly because C does it eagerly.
+ * Ignore failure.
+ */
+ if (!inferred)
+ {
+ uint errors = global.errors;
+ dsym.inuse++;
+ // Bug 20549. Don't try this on modules or packages, syntaxCopy
+ // could crash (inf. recursion) on a mod/pkg referencing itself
+ if (ei && (ei.exp.op != TOK.scope_ ? true : !ei.exp.isScopeExp().sds.isPackage()))
+ {
+ Expression exp = ei.exp.syntaxCopy();
+
+ bool needctfe = dsym.isDataseg() || (dsym.storage_class & STC.manifest);
+ if (needctfe)
+ sc = sc.startCTFE();
+ exp = exp.expressionSemantic(sc);
+ exp = resolveProperties(sc, exp);
+ if (needctfe)
+ sc = sc.endCTFE();
+
+ Type tb2 = dsym.type.toBasetype();
+ Type ti = exp.type.toBasetype();
+
+ /* The problem is the following code:
+ * struct CopyTest {
+ * double x;
+ * this(double a) { x = a * 10.0;}
+ * this(this) { x += 2.0; }
+ * }
+ * const CopyTest z = CopyTest(5.3); // ok
+ * const CopyTest w = z; // not ok, postblit not run
+ * static assert(w.x == 55.0);
+ * because the postblit doesn't get run on the initialization of w.
+ */
+ if (auto ts = ti.isTypeStruct())
+ {
+ StructDeclaration sd = ts.sym;
+ /* Look to see if initializer involves a copy constructor
+ * (which implies a postblit)
+ */
+ // there is a copy constructor
+ // and exp is the same struct
+ if (sd.postblit && tb2.toDsymbol(null) == sd)
+ {
+ // The only allowable initializer is a (non-copy) constructor
+ if (exp.isLvalue())
+ dsym.error("of type struct `%s` uses `this(this)`, which is not allowed in static initialization", tb2.toChars());
+ }
+ }
+ ei.exp = exp;
+ }
+
+ dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITinterpret);
+ dsym.inuse--;
+ if (global.errors > errors)
+ {
+ dsym._init = new ErrorInitializer();
+ dsym.type = Type.terror;
+ }
+ }
+ else
+ {
+ dsym._scope = scx ? scx : sc.copy();
+ dsym._scope.setNoFree();
+ }
+ }
+ sc = sc.pop();
+ }
+
+ Ldtor:
+ /* Build code to execute destruction, if necessary
+ */
+ dsym.edtor = dsym.callScopeDtor(sc);
+ if (dsym.edtor)
+ {
+ /* If dsym is a local variable, who's type is a struct with a scope destructor,
+ * then make dsym scope, too.
+ */
+ if (global.params.useDIP1000 == FeatureState.enabled &&
+ !(dsym.storage_class & (STC.parameter | STC.temp | STC.field | STC.in_ | STC.foreach_ | STC.result | STC.manifest)) &&
+ !dsym.isDataseg() &&
+ !dsym.doNotInferScope &&
+ dsym.type.hasPointers())
+ {
+ auto tv = dsym.type.baseElemOf();
+ if (tv.ty == Tstruct &&
+ tv.isTypeStruct().sym.dtor.storage_class & STC.scope_)
+ {
+ dsym.storage_class |= STC.scope_;
+ }
+ }
+
+ if (sc.func && dsym.storage_class & (STC.static_ | STC.gshared))
+ dsym.edtor = dsym.edtor.expressionSemantic(sc._module._scope);
+ else
+ dsym.edtor = dsym.edtor.expressionSemantic(sc);
+
+ version (none)
+ {
+ // currently disabled because of std.stdio.stdin, stdout and stderr
+ if (dsym.isDataseg() && !(dsym.storage_class & STC.extern_))
+ dsym.error("static storage variables cannot have destructors");
+ }
+ }
+
+ dsym.semanticRun = PASS.semanticdone;
+
+ if (dsym.type.toBasetype().ty == Terror)
+ dsym.errors = true;
+
+ if(sc.scopesym && !sc.scopesym.isAggregateDeclaration())
+ {
+ for (ScopeDsymbol sym = sc.scopesym; sym && dsym.endlinnum == 0;
+ sym = sym.parent ? sym.parent.isScopeDsymbol() : null)
+ dsym.endlinnum = sym.endlinnum;
+ }
+ }
+
+ override void visit(TypeInfoDeclaration dsym)
+ {
+ assert(dsym.linkage == LINK.c);
+ }
+
+ override void visit(BitFieldDeclaration dsym)
+ {
+ //printf("BitField::semantic('%s') %s\n", toPrettyChars(), id.toChars());
+ if (dsym.semanticRun >= PASS.semanticdone)
+ return;
+
+ visit(cast(VarDeclaration)dsym);
+ if (dsym.errors)
+ return;
+
+ sc = sc.startCTFE();
+ auto width = dsym.width.expressionSemantic(sc);
+ sc = sc.endCTFE();
+ width = width.ctfeInterpret();
+ if (!dsym.type.isintegral())
+ {
+ // C11 6.7.2.1-5
+ width.error("bit-field type `%s` is not an integer type", dsym.type.toChars());
+ dsym.errors = true;
+ }
+ if (!width.isIntegerExp())
+ {
+ width.error("bit-field width `%s` is not an integer constant", dsym.width.toChars());
+ dsym.errors = true;
+ }
+ const uwidth = width.toInteger(); // uwidth is unsigned
+ if (uwidth == 0 && !dsym.isAnonymous())
+ {
+ width.error("bit-field `%s` has zero width", dsym.toChars());
+ dsym.errors = true;
+ }
+ const max_width = dsym.type.size() * 8;
+ if (uwidth > max_width)
+ {
+ width.error("width `%lld` of bit-field `%s` does not fit in type `%s`", cast(long)uwidth, dsym.toChars(), dsym.type.toChars());
+ dsym.errors = true;
+ }
+ dsym.fieldWidth = cast(uint)uwidth;
+ }
+
+ override void visit(Import imp)
+ {
+ //printf("Import::semantic('%s') %s\n", toPrettyChars(), id.toChars());
+ if (imp.semanticRun > PASS.init)
+ return;
+
+ if (imp._scope)
+ {
+ sc = imp._scope;
+ imp._scope = null;
+ }
+ if (!sc)
+ return;
+
+ imp.parent = sc.parent;
+
+ imp.semanticRun = PASS.semantic;
+
+ // Load if not already done so
+ bool loadErrored = false;
+ if (!imp.mod)
+ {
+ loadErrored = imp.load(sc);
+ if (imp.mod)
+ {
+ imp.mod.importAll(null);
+ imp.mod.checkImportDeprecation(imp.loc, sc);
+ }
+ }
+ if (imp.mod)
+ {
+ // Modules need a list of each imported module
+
+ // if inside a template instantiation, the instantianting
+ // module gets the import.
+ // https://issues.dlang.org/show_bug.cgi?id=17181
+ Module importer = sc._module;
+ if (sc.minst && sc.tinst)
+ {
+ importer = sc.minst;
+ if (!sc.tinst.importedModules.contains(imp.mod))
+ sc.tinst.importedModules.push(imp.mod);
+ }
+ //printf("%s imports %s\n", importer.toChars(), imp.mod.toChars());
+ if (!importer.aimports.contains(imp.mod))
+ importer.aimports.push(imp.mod);
+
+ if (sc.explicitVisibility)
+ imp.visibility = sc.visibility;
+
+ if (!imp.aliasId && !imp.names.dim) // neither a selective nor a renamed import
+ {
+ ScopeDsymbol scopesym = sc.getScopesym();
+
+ if (!imp.isstatic)
+ {
+ scopesym.importScope(imp.mod, imp.visibility);
+ }
+
+
+ imp.addPackageAccess(scopesym);
+ }
+
+ if (!loadErrored)
+ {
+ imp.mod.dsymbolSemantic(null);
+ }
+
+ if (imp.mod.needmoduleinfo)
+ {
+ //printf("module4 %s because of %s\n", importer.toChars(), imp.mod.toChars());
+ importer.needmoduleinfo = 1;
+ }
+
+ sc = sc.push(imp.mod);
+ sc.visibility = imp.visibility;
+ for (size_t i = 0; i < imp.aliasdecls.dim; i++)
+ {
+ AliasDeclaration ad = imp.aliasdecls[i];
+ //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope);
+ Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], IgnorePrivateImports);
+ if (sym)
+ {
+ import dmd.access : symbolIsVisible;
+ if (!symbolIsVisible(sc, sym))
+ imp.mod.error(imp.loc, "member `%s` is not visible from module `%s`",
+ imp.names[i].toChars(), sc._module.toChars());
+ ad.dsymbolSemantic(sc);
+ // If the import declaration is in non-root module,
+ // analysis of the aliased symbol is deferred.
+ // Therefore, don't see the ad.aliassym or ad.type here.
+ }
+ else
+ {
+ Dsymbol s = imp.mod.search_correct(imp.names[i]);
+ if (s)
+ imp.mod.error(imp.loc, "import `%s` not found, did you mean %s `%s`?", imp.names[i].toChars(), s.kind(), s.toPrettyChars());
+ else
+ imp.mod.error(imp.loc, "import `%s` not found", imp.names[i].toChars());
+ ad.type = Type.terror;
+ }
+ }
+ sc = sc.pop();
+ }
+
+ imp.semanticRun = PASS.semanticdone;
+
+ // object self-imports itself, so skip that
+ // https://issues.dlang.org/show_bug.cgi?id=7547
+ // don't list pseudo modules __entrypoint.d, __main.d
+ // https://issues.dlang.org/show_bug.cgi?id=11117
+ // https://issues.dlang.org/show_bug.cgi?id=11164
+ if (global.params.moduleDeps !is null && !(imp.id == Id.object && sc._module.ident == Id.object) &&
+ strcmp(sc._module.ident.toChars(), "__main") != 0)
+ {
+ /* The grammar of the file is:
+ * ImportDeclaration
+ * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
+ * ModuleAliasIdentifier ] "\n"
+ *
+ * BasicImportDeclaration
+ * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string"
+ * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
+ *
+ * FilePath
+ * - any string with '(', ')' and '\' escaped with the '\' character
+ */
+ OutBuffer* ob = global.params.moduleDeps;
+ Module imod = sc._module;
+ if (!global.params.moduleDepsFile)
+ ob.writestring("depsImport ");
+ ob.writestring(imod.toPrettyChars());
+ ob.writestring(" (");
+ escapePath(ob, imod.srcfile.toChars());
+ ob.writestring(") : ");
+ // use visibility instead of sc.visibility because it couldn't be
+ // resolved yet, see the comment above
+ visibilityToBuffer(ob, imp.visibility);
+ ob.writeByte(' ');
+ if (imp.isstatic)
+ {
+ stcToBuffer(ob, STC.static_);
+ ob.writeByte(' ');
+ }
+ ob.writestring(": ");
+ foreach (pid; imp.packages)
+ {
+ ob.printf("%s.", pid.toChars());
+ }
+ ob.writestring(imp.id.toString());
+ ob.writestring(" (");
+ if (imp.mod)
+ escapePath(ob, imp.mod.srcfile.toChars());
+ else
+ ob.writestring("???");
+ ob.writeByte(')');
+ foreach (i, name; imp.names)
+ {
+ if (i == 0)
+ ob.writeByte(':');
+ else
+ ob.writeByte(',');
+ Identifier _alias = imp.aliases[i];
+ if (!_alias)
+ {
+ ob.printf("%s", name.toChars());
+ _alias = name;
+ }
+ else
+ ob.printf("%s=%s", _alias.toChars(), name.toChars());
+ }
+ if (imp.aliasId)
+ ob.printf(" -> %s", imp.aliasId.toChars());
+ ob.writenl();
+ }
+ //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg);
+ }
+
+ void attribSemantic(AttribDeclaration ad)
+ {
+ if (ad.semanticRun != PASS.init)
+ return;
+ ad.semanticRun = PASS.semantic;
+ Dsymbols* d = ad.include(sc);
+ //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d);
+ if (d)
+ {
+ Scope* sc2 = ad.newScope(sc);
+ bool errors;
+ for (size_t i = 0; i < d.dim; i++)
+ {
+ Dsymbol s = (*d)[i];
+ s.dsymbolSemantic(sc2);
+ errors |= s.errors;
+ }
+ ad.errors |= errors;
+ if (sc2 != sc)
+ sc2.pop();
+ }
+ ad.semanticRun = PASS.semanticdone;
+ }
+
+ override void visit(AttribDeclaration atd)
+ {
+ attribSemantic(atd);
+ }
+
+ override void visit(AnonDeclaration scd)
+ {
+ //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
+ assert(sc.parent);
+ auto p = sc.parent.pastMixin();
+ auto ad = p.isAggregateDeclaration();
+ if (!ad)
+ {
+ error(scd.loc, "%s can only be a part of an aggregate, not %s `%s`", scd.kind(), p.kind(), p.toChars());
+ scd.errors = true;
+ return;
+ }
+
+ if (scd.decl)
+ {
+ sc = sc.push();
+ sc.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.gshared);
+ sc.inunion = scd.isunion ? scd : null;
+ sc.flags = 0;
+ for (size_t i = 0; i < scd.decl.dim; i++)
+ {
+ Dsymbol s = (*scd.decl)[i];
+ s.dsymbolSemantic(sc);
+ }
+ sc = sc.pop();
+ }
+ }
+
+ override void visit(PragmaDeclaration pd)
+ {
+ StringExp verifyMangleString(ref Expression e)
+ {
+ auto se = semanticString(sc, e, "mangled name");
+ if (!se)
+ return null;
+ e = se;
+ if (!se.len)
+ {
+ pd.error("zero-length string not allowed for mangled name");
+ return null;
+ }
+ if (se.sz != 1)
+ {
+ pd.error("mangled name characters can only be of type `char`");
+ return null;
+ }
+ version (all)
+ {
+ /* Note: D language specification should not have any assumption about backend
+ * implementation. Ideally pragma(mangle) can accept a string of any content.
+ *
+ * Therefore, this validation is compiler implementation specific.
+ */
+ auto slice = se.peekString();
+ for (size_t i = 0; i < se.len;)
+ {
+ dchar c = slice[i];
+ if (c < 0x80)
+ {
+ if (c.isValidMangling)
+ {
+ ++i;
+ continue;
+ }
+ else
+ {
+ pd.error("char 0x%02x not allowed in mangled name", c);
+ break;
+ }
+ }
+ if (const msg = utf_decodeChar(slice, i, c))
+ {
+ pd.error("%.*s", cast(int)msg.length, msg.ptr);
+ break;
+ }
+ if (!isUniAlpha(c))
+ {
+ pd.error("char `0x%04x` not allowed in mangled name", c);
+ break;
+ }
+ }
+ }
+ return se;
+ }
+ void declarations()
+ {
+ if (!pd.decl)
+ return;
+
+ Scope* sc2 = pd.newScope(sc);
+ scope(exit)
+ if (sc2 != sc)
+ sc2.pop();
+
+ foreach (s; (*pd.decl)[])
+ {
+ s.dsymbolSemantic(sc2);
+ if (pd.ident != Id.mangle)
+ continue;
+ assert(pd.args);
+ if (auto ad = s.isAggregateDeclaration())
+ {
+ Expression e = (*pd.args)[0];
+ sc2 = sc2.startCTFE();
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc2, e);
+ sc2 = sc2.endCTFE();
+ AggregateDeclaration agg;
+ if (auto tc = e.type.isTypeClass())
+ agg = tc.sym;
+ else if (auto ts = e.type.isTypeStruct())
+ agg = ts.sym;
+ ad.mangleOverride = new MangleOverride;
+ void setString(ref Expression e)
+ {
+ if (auto se = verifyMangleString(e))
+ {
+ const name = (cast(const(char)[])se.peekData()).xarraydup;
+ ad.mangleOverride.id = Identifier.idPool(name);
+ e = se;
+ }
+ else
+ e.error("must be a string");
+ }
+ if (agg)
+ {
+ ad.mangleOverride.agg = agg;
+ if (pd.args.dim == 2)
+ {
+ setString((*pd.args)[1]);
+ }
+ else
+ ad.mangleOverride.id = agg.ident;
+ }
+ else
+ setString((*pd.args)[0]);
+ }
+ else if (auto td = s.isTemplateDeclaration())
+ {
+ pd.error("cannot apply to a template declaration");
+ errorSupplemental(pd.loc, "use `template Class(Args...){ pragma(mangle, \"other_name\") class Class {} }`");
+ }
+ else if (auto se = verifyMangleString((*pd.args)[0]))
+ {
+ const name = (cast(const(char)[])se.peekData()).xarraydup;
+ uint cnt = setMangleOverride(s, name);
+ if (cnt > 1)
+ pd.error("can only apply to a single declaration");
+ }
+ }
+ }
+
+ void noDeclarations()
+ {
+ if (pd.decl)
+ {
+ pd.error("is missing a terminating `;`");
+ declarations();
+ // do them anyway, to avoid segfaults.
+ }
+ }
+
+ // Should be merged with PragmaStatement
+ //printf("\tPragmaDeclaration::semantic '%s'\n", pd.toChars());
+ if (target.mscoff)
+ {
+ if (pd.ident == Id.linkerDirective)
+ {
+ if (!pd.args || pd.args.dim != 1)
+ pd.error("one string argument expected for pragma(linkerDirective)");
+ else
+ {
+ auto se = semanticString(sc, (*pd.args)[0], "linker directive");
+ if (!se)
+ return noDeclarations();
+ (*pd.args)[0] = se;
+ if (global.params.verbose)
+ message("linkopt %.*s", cast(int)se.len, se.peekString().ptr);
+ }
+ return noDeclarations();
+ }
+ }
+ if (pd.ident == Id.msg)
+ {
+ if (pd.args)
+ {
+ for (size_t i = 0; i < pd.args.dim; i++)
+ {
+ Expression e = (*pd.args)[i];
+ sc = sc.startCTFE();
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ sc = sc.endCTFE();
+ e = ctfeInterpretForPragmaMsg(e);
+ if (e.op == TOK.error)
+ {
+ errorSupplemental(pd.loc, "while evaluating `pragma(msg, %s)`", (*pd.args)[i].toChars());
+ return;
+ }
+ StringExp se = e.toStringExp();
+ if (se)
+ {
+ se = se.toUTF8(sc);
+ fprintf(stderr, "%.*s", cast(int)se.len, se.peekString().ptr);
+ }
+ else
+ fprintf(stderr, "%s", e.toChars());
+ }
+ fprintf(stderr, "\n");
+ }
+ return noDeclarations();
+ }
+ else if (pd.ident == Id.lib)
+ {
+ if (!pd.args || pd.args.dim != 1)
+ pd.error("string expected for library name");
+ else
+ {
+ auto se = semanticString(sc, (*pd.args)[0], "library name");
+ if (!se)
+ return noDeclarations();
+ (*pd.args)[0] = se;
+
+ auto name = se.peekString().xarraydup;
+ if (global.params.verbose)
+ message("library %s", name.ptr);
+ if (global.params.moduleDeps && !global.params.moduleDepsFile)
+ {
+ OutBuffer* ob = global.params.moduleDeps;
+ Module imod = sc._module;
+ ob.writestring("depsLib ");
+ ob.writestring(imod.toPrettyChars());
+ ob.writestring(" (");
+ escapePath(ob, imod.srcfile.toChars());
+ ob.writestring(") : ");
+ ob.writestring(name);
+ ob.writenl();
+ }
+ mem.xfree(name.ptr);
+ }
+ return noDeclarations();
+ }
+ else if (pd.ident == Id.startaddress)
+ {
+ if (!pd.args || pd.args.dim != 1)
+ pd.error("function name expected for start address");
+ else
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=11980
+ * resolveProperties and ctfeInterpret call are not necessary.
+ */
+ Expression e = (*pd.args)[0];
+ sc = sc.startCTFE();
+ e = e.expressionSemantic(sc);
+ sc = sc.endCTFE();
+ (*pd.args)[0] = e;
+ Dsymbol sa = getDsymbol(e);
+ if (!sa || !sa.isFuncDeclaration())
+ pd.error("function name expected for start address, not `%s`", e.toChars());
+ }
+ return noDeclarations();
+ }
+ else if (pd.ident == Id.Pinline)
+ {
+ if (pd.args && pd.args.dim > 1)
+ {
+ pd.error("one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) pd.args.dim);
+ pd.args.setDim(1);
+ (*pd.args)[0] = ErrorExp.get();
+ }
+
+ // this pragma now gets evaluated on demand in function semantic
+
+ return declarations();
+ }
+ else if (pd.ident == Id.mangle)
+ {
+ if (!pd.args)
+ pd.args = new Expressions();
+ if (pd.args.dim == 0 || pd.args.dim > 2)
+ {
+ pd.error(pd.args.dim == 0 ? "string expected for mangled name"
+ : "expected 1 or 2 arguments");
+ pd.args.setDim(1);
+ (*pd.args)[0] = ErrorExp.get(); // error recovery
+ }
+ return declarations();
+ }
+ else if (pd.ident == Id.crt_constructor || pd.ident == Id.crt_destructor)
+ {
+ if (pd.args && pd.args.dim != 0)
+ pd.error("takes no argument");
+ return declarations();
+ }
+ else if (pd.ident == Id.printf || pd.ident == Id.scanf)
+ {
+ if (pd.args && pd.args.dim != 0)
+ pd.error("takes no argument");
+ return declarations();
+ }
+ else if (!global.params.ignoreUnsupportedPragmas)
+ {
+ error(pd.loc, "unrecognized `pragma(%s)`", pd.ident.toChars());
+ return declarations();
+ }
+
+ if (!global.params.verbose)
+ return declarations();
+
+ /* Print unrecognized pragmas
+ */
+ OutBuffer buf;
+ buf.writestring(pd.ident.toString());
+ if (pd.args)
+ {
+ const errors_save = global.startGagging();
+ for (size_t i = 0; i < pd.args.dim; i++)
+ {
+ Expression e = (*pd.args)[i];
+ sc = sc.startCTFE();
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ sc = sc.endCTFE();
+ e = e.ctfeInterpret();
+ if (i == 0)
+ buf.writestring(" (");
+ else
+ buf.writeByte(',');
+ buf.writestring(e.toChars());
+ }
+ if (pd.args.dim)
+ buf.writeByte(')');
+ global.endGagging(errors_save);
+ }
+ message("pragma %s", buf.peekChars());
+ return declarations();
+ }
+
+ override void visit(StaticIfDeclaration sid)
+ {
+ attribSemantic(sid);
+ }
+
+ override void visit(StaticForeachDeclaration sfd)
+ {
+ attribSemantic(sfd);
+ }
+
+ private Dsymbols* compileIt(CompileDeclaration cd)
+ {
+ //printf("CompileDeclaration::compileIt(loc = %d) %s\n", cd.loc.linnum, cd.exp.toChars());
+ OutBuffer buf;
+ if (expressionsToString(buf, sc, cd.exps))
+ return null;
+
+ const errors = global.errors;
+ const len = buf.length;
+ buf.writeByte(0);
+ const str = buf.extractSlice()[0 .. len];
+ scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false);
+ p.nextToken();
+
+ auto d = p.parseDeclDefs(0);
+ if (global.errors != errors)
+ return null;
+
+ if (p.token.value != TOK.endOfFile)
+ {
+ cd.error("incomplete mixin declaration `%s`", str.ptr);
+ return null;
+ }
+ return d;
+ }
+
+ /***********************************************************
+ * https://dlang.org/spec/module.html#mixin-declaration
+ */
+ override void visit(CompileDeclaration cd)
+ {
+ //printf("CompileDeclaration::semantic()\n");
+ if (!cd.compiled)
+ {
+ cd.decl = compileIt(cd);
+ cd.AttribDeclaration.addMember(sc, cd.scopesym);
+ cd.compiled = true;
+
+ if (cd._scope && cd.decl)
+ {
+ for (size_t i = 0; i < cd.decl.dim; i++)
+ {
+ Dsymbol s = (*cd.decl)[i];
+ s.setScope(cd._scope);
+ }
+ }
+ }
+ attribSemantic(cd);
+ }
+
+ override void visit(CPPNamespaceDeclaration ns)
+ {
+ Identifier identFromSE (StringExp se)
+ {
+ const sident = se.toStringz();
+ if (!sident.length || !Identifier.isValidIdentifier(sident))
+ {
+ ns.exp.error("expected valid identifier for C++ namespace but got `%.*s`",
+ cast(int)sident.length, sident.ptr);
+ return null;
+ }
+ else
+ return Identifier.idPool(sident);
+ }
+
+ if (ns.ident is null)
+ {
+ ns.cppnamespace = sc.namespace;
+ sc = sc.startCTFE();
+ ns.exp = ns.exp.expressionSemantic(sc);
+ ns.exp = resolveProperties(sc, ns.exp);
+ sc = sc.endCTFE();
+ ns.exp = ns.exp.ctfeInterpret();
+ // Can be either a tuple of strings or a string itself
+ if (auto te = ns.exp.isTupleExp())
+ {
+ expandTuples(te.exps);
+ CPPNamespaceDeclaration current = ns.cppnamespace;
+ for (size_t d = 0; d < te.exps.dim; ++d)
+ {
+ auto exp = (*te.exps)[d];
+ auto prev = d ? current : ns.cppnamespace;
+ current = (d + 1) != te.exps.dim
+ ? new CPPNamespaceDeclaration(ns.loc, exp, null)
+ : ns;
+ current.exp = exp;
+ current.cppnamespace = prev;
+ if (auto se = exp.toStringExp())
+ {
+ current.ident = identFromSE(se);
+ if (current.ident is null)
+ return; // An error happened in `identFromSE`
+ }
+ else
+ ns.exp.error("`%s`: index %llu is not a string constant, it is a `%s`",
+ ns.exp.toChars(), cast(ulong) d, ns.exp.type.toChars());
+ }
+ }
+ else if (auto se = ns.exp.toStringExp())
+ ns.ident = identFromSE(se);
+ // Empty Tuple
+ else if (ns.exp.isTypeExp() && ns.exp.isTypeExp().type.toBasetype().isTypeTuple())
+ {
+ }
+ else
+ ns.exp.error("compile time string constant (or tuple) expected, not `%s`",
+ ns.exp.toChars());
+ }
+ attribSemantic(ns);
+ }
+
+ override void visit(UserAttributeDeclaration uad)
+ {
+ //printf("UserAttributeDeclaration::semantic() %p\n", this);
+ if (uad.decl && !uad._scope)
+ uad.Dsymbol.setScope(sc); // for function local symbols
+ arrayExpressionSemantic(uad.atts, sc, true);
+ return attribSemantic(uad);
+ }
+
+ override void visit(StaticAssert sa)
+ {
+ if (sa.semanticRun < PASS.semanticdone)
+ sa.semanticRun = PASS.semanticdone;
+ }
+
+ override void visit(DebugSymbol ds)
+ {
+ //printf("DebugSymbol::semantic() %s\n", toChars());
+ if (ds.semanticRun < PASS.semanticdone)
+ ds.semanticRun = PASS.semanticdone;
+ }
+
+ override void visit(VersionSymbol vs)
+ {
+ if (vs.semanticRun < PASS.semanticdone)
+ vs.semanticRun = PASS.semanticdone;
+ }
+
+ override void visit(Package pkg)
+ {
+ if (pkg.semanticRun < PASS.semanticdone)
+ pkg.semanticRun = PASS.semanticdone;
+ }
+
+ override void visit(Module m)
+ {
+ if (m.semanticRun != PASS.init)
+ return;
+ //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+ m.semanticRun = PASS.semantic;
+ // Note that modules get their own scope, from scratch.
+ // This is so regardless of where in the syntax a module
+ // gets imported, it is unaffected by context.
+ Scope* sc = m._scope; // see if already got one from importAll()
+ if (!sc)
+ {
+ sc = Scope.createGlobal(m); // create root scope
+ }
+
+ //printf("Module = %p, linkage = %d\n", sc.scopesym, sc.linkage);
+ // Pass 1 semantic routines: do public side of the definition
+ m.members.foreachDsymbol( (s)
+ {
+ //printf("\tModule('%s'): '%s'.dsymbolSemantic()\n", toChars(), s.toChars());
+ s.dsymbolSemantic(sc);
+ m.runDeferredSemantic();
+ });
+
+ if (m.userAttribDecl)
+ {
+ m.userAttribDecl.dsymbolSemantic(sc);
+ }
+ if (!m._scope)
+ {
+ sc = sc.pop();
+ sc.pop(); // 2 pops because Scope.createGlobal() created 2
+ }
+ m.semanticRun = PASS.semanticdone;
+ //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
+ }
+
+ override void visit(EnumDeclaration ed)
+ {
+ //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars());
+ //printf("EnumDeclaration::semantic() %p %s\n", this, ed.toChars());
+ if (ed.semanticRun >= PASS.semanticdone)
+ return; // semantic() already completed
+ if (ed.semanticRun == PASS.semantic)
+ {
+ assert(ed.memtype);
+ error(ed.loc, "circular reference to enum base type `%s`", ed.memtype.toChars());
+ ed.errors = true;
+ ed.semanticRun = PASS.semanticdone;
+ return;
+ }
+ uint dprogress_save = Module.dprogress;
+
+ Scope* scx = null;
+ if (ed._scope)
+ {
+ sc = ed._scope;
+ scx = ed._scope; // save so we don't make redundant copies
+ ed._scope = null;
+ }
+
+ if (!sc)
+ return;
+
+ ed.parent = sc.parent;
+ ed.type = ed.type.typeSemantic(ed.loc, sc);
+
+ ed.visibility = sc.visibility;
+ if (sc.stc & STC.deprecated_)
+ ed.isdeprecated = true;
+ ed.userAttribDecl = sc.userAttribDecl;
+ ed.cppnamespace = sc.namespace;
+
+ ed.semanticRun = PASS.semantic;
+ UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage);
+
+ if (!ed.members && !ed.memtype) // enum ident;
+ {
+ ed.semanticRun = PASS.semanticdone;
+ return;
+ }
+
+ if (!ed.symtab)
+ ed.symtab = new DsymbolTable();
+
+ /* The separate, and distinct, cases are:
+ * 1. enum { ... }
+ * 2. enum : memtype { ... }
+ * 3. enum ident { ... }
+ * 4. enum ident : memtype { ... }
+ * 5. enum ident : memtype;
+ * 6. enum ident;
+ */
+
+ if (ed.memtype)
+ {
+ ed.memtype = ed.memtype.typeSemantic(ed.loc, sc);
+
+ /* Check to see if memtype is forward referenced
+ */
+ if (auto te = ed.memtype.isTypeEnum())
+ {
+ auto sym = te.toDsymbol(sc).isEnumDeclaration();
+ // Special enums like __c_[u]long[long] are fine to forward reference
+ // see https://issues.dlang.org/show_bug.cgi?id=20599
+ if (!sym.isSpecial() && (!sym.memtype || !sym.members || !sym.symtab || sym._scope))
+ {
+ // memtype is forward referenced, so try again later
+ deferDsymbolSemantic(ed, scx);
+ Module.dprogress = dprogress_save;
+ //printf("\tdeferring %s\n", toChars());
+ ed.semanticRun = PASS.init;
+ return;
+ }
+ else
+ // Ensure that semantic is run to detect. e.g. invalid forward references
+ sym.dsymbolSemantic(sc);
+ }
+ if (ed.memtype.ty == Tvoid)
+ {
+ ed.error("base type must not be `void`");
+ ed.memtype = Type.terror;
+ }
+ if (ed.memtype.ty == Terror)
+ {
+ ed.errors = true;
+ // poison all the members
+ ed.members.foreachDsymbol( (s) { s.errors = true; } );
+ ed.semanticRun = PASS.semanticdone;
+ return;
+ }
+ }
+
+ if (!ed.members) // enum ident : memtype;
+ {
+ ed.semanticRun = PASS.semanticdone;
+ return;
+ }
+
+ if (ed.members.dim == 0)
+ {
+ ed.error("enum `%s` must have at least one member", ed.toChars());
+ ed.errors = true;
+ ed.semanticRun = PASS.semanticdone;
+ return;
+ }
+
+ if (!(sc.flags & SCOPE.Cfile)) // C enum remains incomplete until members are done
+ ed.semanticRun = PASS.semanticdone;
+
+ Module.dprogress++;
+
+ Scope* sce;
+ if (ed.isAnonymous())
+ sce = sc;
+ else
+ {
+ sce = sc.push(ed);
+ sce.parent = ed;
+ }
+ sce = sce.startCTFE();
+ sce.setNoFree(); // needed for getMaxMinValue()
+
+ /* Each enum member gets the sce scope
+ */
+ ed.members.foreachDsymbol( (s)
+ {
+ EnumMember em = s.isEnumMember();
+ if (em)
+ em._scope = sce;
+ });
+
+ /* addMember() is not called when the EnumDeclaration appears as a function statement,
+ * so we have to do what addMember() does and install the enum members in the right symbol
+ * table
+ */
+ addEnumMembers(ed, sc, sc.getScopesym());
+
+ if (sc.flags & SCOPE.Cfile)
+ {
+ /* C11 6.7.2.2
+ */
+ ed.memtype = Type.tint32; // C11 6.7.2.2-4 implementation defined
+ int nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0
+
+ void emSemantic(EnumMember em, ref int nextValue)
+ {
+ static void errorReturn(EnumMember em)
+ {
+ em.errors = true;
+ em.semanticRun = PASS.semanticdone;
+ }
+
+ em.semanticRun = PASS.semantic;
+ em.type = Type.tint32;
+ em.linkage = LINK.c;
+ em.storage_class |= STC.manifest;
+ if (em.value)
+ {
+ Expression e = em.value;
+ assert(e.dyncast() == DYNCAST.expression);
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ e = e.integralPromotions(sc);
+ e = e.ctfeInterpret();
+ if (e.op == TOK.error)
+ return errorReturn(em);
+ auto ie = e.isIntegerExp();
+ if (!ie)
+ {
+ // C11 6.7.2.2-2
+ em.error("enum member must be an integral constant expression, not `%s` of type `%s`", e.toChars(), e.type.toChars());
+ return errorReturn(em);
+ }
+ const sinteger_t v = ie.toInteger();
+ if (v < int.min || v > uint.max)
+ {
+ // C11 6.7.2.2-2
+ em.error("enum member value `%s` does not fit in an `int`", e.toChars());
+ return errorReturn(em);
+ }
+ em.value = new IntegerExp(em.loc, cast(int)v, Type.tint32);
+ nextValue = cast(int)v;
+ }
+ else
+ {
+ em.value = new IntegerExp(em.loc, nextValue, Type.tint32);
+ }
+ ++nextValue; // C11 6.7.2.2-3 add 1 to value of previous enumeration constant
+ em.semanticRun = PASS.semanticdone;
+ }
+
+ ed.members.foreachDsymbol( (s)
+ {
+ if (EnumMember em = s.isEnumMember())
+ emSemantic(em, nextValue);
+ });
+ ed.semanticRun = PASS.semanticdone;
+ return;
+ }
+
+ ed.members.foreachDsymbol( (s)
+ {
+ if (EnumMember em = s.isEnumMember())
+ em.dsymbolSemantic(em._scope);
+ });
+ //printf("defaultval = %lld\n", defaultval);
+
+ //if (defaultval) printf("defaultval: %s %s\n", defaultval.toChars(), defaultval.type.toChars());
+ //printf("members = %s\n", members.toChars());
+ }
+
+ override void visit(EnumMember em)
+ {
+ //printf("EnumMember::semantic() %s\n", em.toChars());
+
+ void errorReturn()
+ {
+ em.errors = true;
+ em.semanticRun = PASS.semanticdone;
+ }
+
+ if (em.errors || em.semanticRun >= PASS.semanticdone)
+ return;
+ if (em.semanticRun == PASS.semantic)
+ {
+ em.error("circular reference to `enum` member");
+ return errorReturn();
+ }
+ assert(em.ed);
+
+ em.ed.dsymbolSemantic(sc);
+ if (em.ed.errors)
+ return errorReturn();
+ if (em.errors || em.semanticRun >= PASS.semanticdone)
+ return;
+
+ if (em._scope)
+ sc = em._scope;
+ if (!sc)
+ return;
+
+ em.semanticRun = PASS.semantic;
+
+ em.visibility = em.ed.isAnonymous() ? em.ed.visibility : Visibility(Visibility.Kind.public_);
+ em.linkage = LINK.d;
+ em.storage_class |= STC.manifest;
+
+ // https://issues.dlang.org/show_bug.cgi?id=9701
+ if (em.ed.isAnonymous())
+ {
+ if (em.userAttribDecl)
+ em.userAttribDecl.userAttribDecl = em.ed.userAttribDecl;
+ else
+ em.userAttribDecl = em.ed.userAttribDecl;
+ }
+
+ // Eval UDA in this same scope. Issues 19344, 20835, 21122
+ if (em.userAttribDecl)
+ {
+ // Set scope but avoid extra sc.uda attachment inside setScope()
+ auto inneruda = em.userAttribDecl.userAttribDecl;
+ em.userAttribDecl.setScope(sc);
+ em.userAttribDecl.userAttribDecl = inneruda;
+ }
+
+ // The first enum member is special
+ bool first = (em == (*em.ed.members)[0]);
+
+ if (em.origType)
+ {
+ em.origType = em.origType.typeSemantic(em.loc, sc);
+ em.type = em.origType;
+ assert(em.value); // "type id;" is not a valid enum member declaration
+ }
+
+ if (em.value)
+ {
+ Expression e = em.value;
+ assert(e.dyncast() == DYNCAST.expression);
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ e = e.ctfeInterpret();
+ if (e.op == TOK.error)
+ return errorReturn();
+ if (first && !em.ed.memtype && !em.ed.isAnonymous())
+ {
+ em.ed.memtype = e.type;
+ if (em.ed.memtype.ty == Terror)
+ {
+ em.ed.errors = true;
+ return errorReturn();
+ }
+ if (em.ed.memtype.ty != Terror)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=11746
+ * All of named enum members should have same type
+ * with the first member. If the following members were referenced
+ * during the first member semantic, their types should be unified.
+ */
+ em.ed.members.foreachDsymbol( (s)
+ {
+ EnumMember enm = s.isEnumMember();
+ if (!enm || enm == em || enm.semanticRun < PASS.semanticdone || enm.origType)
+ return;
+
+ //printf("[%d] em = %s, em.semanticRun = %d\n", i, toChars(), em.semanticRun);
+ Expression ev = enm.value;
+ ev = ev.implicitCastTo(sc, em.ed.memtype);
+ ev = ev.ctfeInterpret();
+ ev = ev.castTo(sc, em.ed.type);
+ if (ev.op == TOK.error)
+ em.ed.errors = true;
+ enm.value = ev;
+ });
+
+ if (em.ed.errors)
+ {
+ em.ed.memtype = Type.terror;
+ return errorReturn();
+ }
+ }
+ }
+
+ if (em.ed.memtype && !em.origType)
+ {
+ e = e.implicitCastTo(sc, em.ed.memtype);
+ e = e.ctfeInterpret();
+
+ // save origValue for better json output
+ em.origValue = e;
+
+ if (!em.ed.isAnonymous())
+ {
+ e = e.castTo(sc, em.ed.type.addMod(e.type.mod)); // https://issues.dlang.org/show_bug.cgi?id=12385
+ e = e.ctfeInterpret();
+ }
+ }
+ else if (em.origType)
+ {
+ e = e.implicitCastTo(sc, em.origType);
+ e = e.ctfeInterpret();
+ assert(em.ed.isAnonymous());
+
+ // save origValue for better json output
+ em.origValue = e;
+ }
+ em.value = e;
+ }
+ else if (first)
+ {
+ Type t;
+ if (em.ed.memtype)
+ t = em.ed.memtype;
+ else
+ {
+ t = Type.tint32;
+ if (!em.ed.isAnonymous())
+ em.ed.memtype = t;
+ }
+ Expression e = new IntegerExp(em.loc, 0, t);
+ e = e.ctfeInterpret();
+
+ // save origValue for better json output
+ em.origValue = e;
+
+ if (!em.ed.isAnonymous())
+ {
+ e = e.castTo(sc, em.ed.type);
+ e = e.ctfeInterpret();
+ }
+ em.value = e;
+ }
+ else
+ {
+ /* Find the previous enum member,
+ * and set this to be the previous value + 1
+ */
+ EnumMember emprev = null;
+ em.ed.members.foreachDsymbol( (s)
+ {
+ if (auto enm = s.isEnumMember())
+ {
+ if (enm == em)
+ return 1; // found
+ emprev = enm;
+ }
+ return 0; // continue
+ });
+
+ assert(emprev);
+ if (emprev.semanticRun < PASS.semanticdone) // if forward reference
+ emprev.dsymbolSemantic(emprev._scope); // resolve it
+ if (emprev.errors)
+ return errorReturn();
+
+ Expression eprev = emprev.value;
+ // .toHeadMutable() due to https://issues.dlang.org/show_bug.cgi?id=18645
+ Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable())
+ ? em.ed.memtype
+ : eprev.type;
+
+ Expression emax = tprev.getProperty(sc, em.ed.loc, Id.max, 0);
+ emax = emax.expressionSemantic(sc);
+ emax = emax.ctfeInterpret();
+
+ // Set value to (eprev + 1).
+ // But first check that (eprev != emax)
+ assert(eprev);
+ Expression e = new EqualExp(TOK.equal, em.loc, eprev, emax);
+ e = e.expressionSemantic(sc);
+ e = e.ctfeInterpret();
+ if (e.toInteger())
+ {
+ em.error("initialization with `%s.%s+1` causes overflow for type `%s`",
+ emprev.ed.toChars(), emprev.toChars(), em.ed.memtype.toChars());
+ return errorReturn();
+ }
+
+ // Now set e to (eprev + 1)
+ e = new AddExp(em.loc, eprev, IntegerExp.literal!1);
+ e = e.expressionSemantic(sc);
+ e = e.castTo(sc, eprev.type);
+ e = e.ctfeInterpret();
+
+ // save origValue (without cast) for better json output
+ if (e.op != TOK.error) // avoid duplicate diagnostics
+ {
+ assert(emprev.origValue);
+ em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1);
+ em.origValue = em.origValue.expressionSemantic(sc);
+ em.origValue = em.origValue.ctfeInterpret();
+ }
+
+ if (e.op == TOK.error)
+ return errorReturn();
+ if (e.type.isfloating())
+ {
+ // Check that e != eprev (not always true for floats)
+ Expression etest = new EqualExp(TOK.equal, em.loc, e, eprev);
+ etest = etest.expressionSemantic(sc);
+ etest = etest.ctfeInterpret();
+ if (etest.toInteger())
+ {
+ em.error("has inexact value due to loss of precision");
+ return errorReturn();
+ }
+ }
+ em.value = e;
+ }
+ if (!em.origType)
+ em.type = em.value.type;
+
+ assert(em.origValue);
+ em.semanticRun = PASS.semanticdone;
+ }
+
+ override void visit(TemplateDeclaration tempdecl)
+ {
+ static if (LOG)
+ {
+ printf("TemplateDeclaration.dsymbolSemantic(this = %p, id = '%s')\n", this, tempdecl.ident.toChars());
+ printf("sc.stc = %llx\n", sc.stc);
+ printf("sc.module = %s\n", sc._module.toChars());
+ }
+ if (tempdecl.semanticRun != PASS.init)
+ return; // semantic() already run
+
+ if (tempdecl._scope)
+ {
+ sc = tempdecl._scope;
+ tempdecl._scope = null;
+ }
+ if (!sc)
+ return;
+
+ // Remember templates defined in module object that we need to know about
+ if (sc._module && sc._module.ident == Id.object)
+ {
+ if (tempdecl.ident == Id.RTInfo)
+ Type.rtinfo = tempdecl;
+ }
+
+ /* Remember Scope for later instantiations, but make
+ * a copy since attributes can change.
+ */
+ if (!tempdecl._scope)
+ {
+ tempdecl._scope = sc.copy();
+ tempdecl._scope.setNoFree();
+ }
+
+ tempdecl.semanticRun = PASS.semantic;
+
+ tempdecl.parent = sc.parent;
+ tempdecl.visibility = sc.visibility;
+ tempdecl.cppnamespace = sc.namespace;
+ tempdecl.isstatic = tempdecl.toParent().isModule() || (tempdecl._scope.stc & STC.static_);
+ tempdecl.deprecated_ = !!(sc.stc & STC.deprecated_);
+
+ UserAttributeDeclaration.checkGNUABITag(tempdecl, sc.linkage);
+
+ if (!tempdecl.isstatic)
+ {
+ if (auto ad = tempdecl.parent.pastMixin().isAggregateDeclaration())
+ ad.makeNested();
+ }
+
+ // Set up scope for parameters
+ auto paramsym = new ScopeDsymbol();
+ paramsym.parent = tempdecl.parent;
+ Scope* paramscope = sc.push(paramsym);
+ paramscope.stc = 0;
+
+ if (global.params.doDocComments)
+ {
+ tempdecl.origParameters = new TemplateParameters(tempdecl.parameters.dim);
+ for (size_t i = 0; i < tempdecl.parameters.dim; i++)
+ {
+ TemplateParameter tp = (*tempdecl.parameters)[i];
+ (*tempdecl.origParameters)[i] = tp.syntaxCopy();
+ }
+ }
+
+ for (size_t i = 0; i < tempdecl.parameters.dim; i++)
+ {
+ TemplateParameter tp = (*tempdecl.parameters)[i];
+ if (!tp.declareParameter(paramscope))
+ {
+ error(tp.loc, "parameter `%s` multiply defined", tp.ident.toChars());
+ tempdecl.errors = true;
+ }
+ if (!tp.tpsemantic(paramscope, tempdecl.parameters))
+ {
+ tempdecl.errors = true;
+ }
+ if (i + 1 != tempdecl.parameters.dim && tp.isTemplateTupleParameter())
+ {
+ tempdecl.error("template tuple parameter must be last one");
+ tempdecl.errors = true;
+ }
+ }
+
+ /* Calculate TemplateParameter.dependent
+ */
+ TemplateParameters tparams = TemplateParameters(1);
+ for (size_t i = 0; i < tempdecl.parameters.dim; i++)
+ {
+ TemplateParameter tp = (*tempdecl.parameters)[i];
+ tparams[0] = tp;
+
+ for (size_t j = 0; j < tempdecl.parameters.dim; j++)
+ {
+ // Skip cases like: X(T : T)
+ if (i == j)
+ continue;
+
+ if (TemplateTypeParameter ttp = (*tempdecl.parameters)[j].isTemplateTypeParameter())
+ {
+ if (reliesOnTident(ttp.specType, &tparams))
+ tp.dependent = true;
+ }
+ else if (TemplateAliasParameter tap = (*tempdecl.parameters)[j].isTemplateAliasParameter())
+ {
+ if (reliesOnTident(tap.specType, &tparams) ||
+ reliesOnTident(isType(tap.specAlias), &tparams))
+ {
+ tp.dependent = true;
+ }
+ }
+ }
+ }
+
+ paramscope.pop();
+
+ // Compute again
+ tempdecl.onemember = null;
+ if (tempdecl.members)
+ {
+ Dsymbol s;
+ if (Dsymbol.oneMembers(tempdecl.members, &s, tempdecl.ident) && s)
+ {
+ tempdecl.onemember = s;
+ s.parent = tempdecl;
+ }
+ }
+
+ /* BUG: should check:
+ * 1. template functions must not introduce virtual functions, as they
+ * cannot be accomodated in the vtbl[]
+ * 2. templates cannot introduce non-static data members (i.e. fields)
+ * as they would change the instance size of the aggregate.
+ */
+
+ tempdecl.semanticRun = PASS.semanticdone;
+ }
+
+ override void visit(TemplateInstance ti)
+ {
+ templateInstanceSemantic(ti, sc, null);
+ }
+
+ override void visit(TemplateMixin tm)
+ {
+ static if (LOG)
+ {
+ printf("+TemplateMixin.dsymbolSemantic('%s', this=%p)\n", tm.toChars(), tm);
+ fflush(stdout);
+ }
+ if (tm.semanticRun != PASS.init)
+ {
+ // When a class/struct contains mixin members, and is done over
+ // because of forward references, never reach here so semanticRun
+ // has been reset to PASS.init.
+ static if (LOG)
+ {
+ printf("\tsemantic done\n");
+ }
+ return;
+ }
+ tm.semanticRun = PASS.semantic;
+ static if (LOG)
+ {
+ printf("\tdo semantic\n");
+ }
+
+ Scope* scx = null;
+ if (tm._scope)
+ {
+ sc = tm._scope;
+ scx = tm._scope; // save so we don't make redundant copies
+ tm._scope = null;
+ }
+
+ /* Run semantic on each argument, place results in tiargs[],
+ * then find best match template with tiargs
+ */
+ if (!tm.findTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, null))
+ {
+ if (tm.semanticRun == PASS.init) // forward reference had occurred
+ {
+ //printf("forward reference - deferring\n");
+ return deferDsymbolSemantic(tm, scx);
+ }
+
+ tm.inst = tm;
+ tm.errors = true;
+ return; // error recovery
+ }
+
+ auto tempdecl = tm.tempdecl.isTemplateDeclaration();
+ assert(tempdecl);
+
+ if (!tm.ident)
+ {
+ /* Assign scope local unique identifier, as same as lambdas.
+ */
+ const(char)[] s = "__mixin";
+
+ if (FuncDeclaration func = sc.parent.isFuncDeclaration())
+ {
+ tm.symtab = func.localsymtab;
+ if (tm.symtab)
+ {
+ // Inside template constraint, symtab is not set yet.
+ goto L1;
+ }
+ }
+ else
+ {
+ tm.symtab = sc.parent.isScopeDsymbol().symtab;
+ L1:
+ assert(tm.symtab);
+ tm.ident = Identifier.generateId(s, tm.symtab.length + 1);
+ tm.symtab.insert(tm);
+ }
+ }
+
+ tm.inst = tm;
+ tm.parent = sc.parent;
+
+ /* Detect recursive mixin instantiations.
+ */
+ for (Dsymbol s = tm.parent; s; s = s.parent)
+ {
+ //printf("\ts = '%s'\n", s.toChars());
+ TemplateMixin tmix = s.isTemplateMixin();
+ if (!tmix || tempdecl != tmix.tempdecl)
+ continue;
+
+ /* Different argument list lengths happen with variadic args
+ */
+ if (tm.tiargs.dim != tmix.tiargs.dim)
+ continue;
+
+ for (size_t i = 0; i < tm.tiargs.dim; i++)
+ {
+ RootObject o = (*tm.tiargs)[i];
+ Type ta = isType(o);
+ Expression ea = isExpression(o);
+ Dsymbol sa = isDsymbol(o);
+ RootObject tmo = (*tmix.tiargs)[i];
+ if (ta)
+ {
+ Type tmta = isType(tmo);
+ if (!tmta)
+ goto Lcontinue;
+ if (!ta.equals(tmta))
+ goto Lcontinue;
+ }
+ else if (ea)
+ {
+ Expression tme = isExpression(tmo);
+ if (!tme || !ea.equals(tme))
+ goto Lcontinue;
+ }
+ else if (sa)
+ {
+ Dsymbol tmsa = isDsymbol(tmo);
+ if (sa != tmsa)
+ goto Lcontinue;
+ }
+ else
+ assert(0);
+ }
+ tm.error("recursive mixin instantiation");
+ return;
+
+ Lcontinue:
+ continue;
+ }
+
+ // Copy the syntax trees from the TemplateDeclaration
+ tm.members = Dsymbol.arraySyntaxCopy(tempdecl.members);
+ if (!tm.members)
+ return;
+
+ tm.symtab = new DsymbolTable();
+
+ sc.getScopesym().importScope(tm, Visibility(Visibility.Kind.public_));
+
+ static if (LOG)
+ {
+ printf("\tcreate scope for template parameters '%s'\n", tm.toChars());
+ }
+ Scope* scy = sc.push(tm);
+ scy.parent = tm;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=930
+ *
+ * If the template that is to be mixed in is in the scope of a template
+ * instance, we have to also declare the type aliases in the new mixin scope.
+ */
+ auto parentInstance = tempdecl.parent ? tempdecl.parent.isTemplateInstance() : null;
+ if (parentInstance)
+ parentInstance.declareParameters(scy);
+
+ tm.argsym = new ScopeDsymbol();
+ tm.argsym.parent = scy.parent;
+ Scope* argscope = scy.push(tm.argsym);
+
+ uint errorsave = global.errors;
+
+ // Declare each template parameter as an alias for the argument type
+ tm.declareParameters(argscope);
+
+ // Add members to enclosing scope, as well as this scope
+ tm.members.foreachDsymbol(s => s.addMember(argscope, tm));
+
+ // Do semantic() analysis on template instance members
+ static if (LOG)
+ {
+ printf("\tdo semantic() on template instance members '%s'\n", tm.toChars());
+ }
+ Scope* sc2 = argscope.push(tm);
+ //size_t deferred_dim = Module.deferred.dim;
+
+ __gshared int nest;
+ //printf("%d\n", nest);
+ if (++nest > global.recursionLimit)
+ {
+ global.gag = 0; // ensure error message gets printed
+ tm.error("recursive expansion");
+ fatal();
+ }
+
+ tm.members.foreachDsymbol( s => s.setScope(sc2) );
+
+ tm.members.foreachDsymbol( s => s.importAll(sc2) );
+
+ tm.members.foreachDsymbol( s => s.dsymbolSemantic(sc2) );
+
+ nest--;
+
+ /* In DeclDefs scope, TemplateMixin does not have to handle deferred symbols.
+ * Because the members would already call Module.addDeferredSemantic() for themselves.
+ * See Struct, Class, Interface, and EnumDeclaration.dsymbolSemantic().
+ */
+ //if (!sc.func && Module.deferred.dim > deferred_dim) {}
+
+ AggregateDeclaration ad = tm.toParent().isAggregateDeclaration();
+ if (sc.func && !ad)
+ {
+ tm.semantic2(sc2);
+ tm.semantic3(sc2);
+ }
+
+ // Give additional context info if error occurred during instantiation
+ if (global.errors != errorsave)
+ {
+ tm.error("error instantiating");
+ tm.errors = true;
+ }
+
+ sc2.pop();
+ argscope.pop();
+ scy.pop();
+
+ static if (LOG)
+ {
+ printf("-TemplateMixin.dsymbolSemantic('%s', this=%p)\n", tm.toChars(), tm);
+ }
+ }
+
+ override void visit(Nspace ns)
+ {
+ if (ns.semanticRun != PASS.init)
+ return;
+ static if (LOG)
+ {
+ printf("+Nspace::semantic('%s')\n", ns.toChars());
+ }
+ if (ns._scope)
+ {
+ sc = ns._scope;
+ ns._scope = null;
+ }
+ if (!sc)
+ return;
+
+ bool repopulateMembers = false;
+ if (ns.identExp)
+ {
+ // resolve the namespace identifier
+ sc = sc.startCTFE();
+ Expression resolved = ns.identExp.expressionSemantic(sc);
+ resolved = resolveProperties(sc, resolved);
+ sc = sc.endCTFE();
+ resolved = resolved.ctfeInterpret();
+ StringExp name = resolved.toStringExp();
+ TupleExp tup = name ? null : resolved.toTupleExp();
+ if (!tup && !name)
+ {
+ error(ns.loc, "expected string expression for namespace name, got `%s`", ns.identExp.toChars());
+ return;
+ }
+ ns.identExp = resolved; // we don't need to keep the old AST around
+ if (name)
+ {
+ const(char)[] ident = name.toStringz();
+ if (ident.length == 0 || !Identifier.isValidIdentifier(ident))
+ {
+ error(ns.loc, "expected valid identifier for C++ namespace but got `%.*s`", cast(int)ident.length, ident.ptr);
+ return;
+ }
+ ns.ident = Identifier.idPool(ident);
+ }
+ else
+ {
+ // create namespace stack from the tuple
+ Nspace parentns = ns;
+ foreach (i, exp; *tup.exps)
+ {
+ name = exp.toStringExp();
+ if (!name)
+ {
+ error(ns.loc, "expected string expression for namespace name, got `%s`", exp.toChars());
+ return;
+ }
+ const(char)[] ident = name.toStringz();
+ if (ident.length == 0 || !Identifier.isValidIdentifier(ident))
+ {
+ error(ns.loc, "expected valid identifier for C++ namespace but got `%.*s`", cast(int)ident.length, ident.ptr);
+ return;
+ }
+ if (i == 0)
+ {
+ ns.ident = Identifier.idPool(ident);
+ }
+ else
+ {
+ // insert the new namespace
+ Nspace childns = new Nspace(ns.loc, Identifier.idPool(ident), null, parentns.members);
+ parentns.members = new Dsymbols;
+ parentns.members.push(childns);
+ parentns = childns;
+ repopulateMembers = true;
+ }
+ }
+ }
+ }
+
+ ns.semanticRun = PASS.semantic;
+ ns.parent = sc.parent;
+ // Link does not matter here, if the UDA is present it will error
+ UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp);
+
+ if (ns.members)
+ {
+ assert(sc);
+ sc = sc.push(ns);
+ sc.linkage = LINK.cpp; // note that namespaces imply C++ linkage
+ sc.parent = ns;
+ foreach (s; *ns.members)
+ {
+ if (repopulateMembers)
+ {
+ s.addMember(sc, sc.scopesym);
+ s.setScope(sc);
+ }
+ s.importAll(sc);
+ }
+ foreach (s; *ns.members)
+ {
+ static if (LOG)
+ {
+ printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
+ }
+ s.dsymbolSemantic(sc);
+ }
+ sc.pop();
+ }
+ ns.semanticRun = PASS.semanticdone;
+ static if (LOG)
+ {
+ printf("-Nspace::semantic('%s')\n", ns.toChars());
+ }
+ }
+
+ void funcDeclarationSemantic(FuncDeclaration funcdecl)
+ {
+ TypeFunction f;
+ AggregateDeclaration ad;
+ InterfaceDeclaration id;
+
+ version (none)
+ {
+ printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, funcdecl, funcdecl.toPrettyChars(), sc.linkage);
+ if (funcdecl.isFuncLiteralDeclaration())
+ printf("\tFuncLiteralDeclaration()\n");
+ printf("sc.parent = %s, parent = %s\n", sc.parent.toChars(), funcdecl.parent ? funcdecl.parent.toChars() : "");
+ printf("type: %p, %s\n", funcdecl.type, funcdecl.type.toChars());
+ }
+
+ if (funcdecl.semanticRun != PASS.init && funcdecl.isFuncLiteralDeclaration())
+ {
+ /* Member functions that have return types that are
+ * forward references can have semantic() run more than
+ * once on them.
+ * See test\interface2.d, test20
+ */
+ return;
+ }
+
+ if (funcdecl.semanticRun >= PASS.semanticdone)
+ return;
+ assert(funcdecl.semanticRun <= PASS.semantic);
+ funcdecl.semanticRun = PASS.semantic;
+
+ if (funcdecl._scope)
+ {
+ sc = funcdecl._scope;
+ funcdecl._scope = null;
+ }
+
+ if (!sc || funcdecl.errors)
+ return;
+
+ funcdecl.cppnamespace = sc.namespace;
+ funcdecl.parent = sc.parent;
+ Dsymbol parent = funcdecl.toParent();
+
+ funcdecl.foverrides.setDim(0); // reset in case semantic() is being retried for this function
+
+ funcdecl.storage_class |= sc.stc & ~STC.ref_;
+ ad = funcdecl.isThis();
+ // Don't nest structs b/c of generated methods which should not access the outer scopes.
+ // https://issues.dlang.org/show_bug.cgi?id=16627
+ if (ad && !funcdecl.generated)
+ {
+ funcdecl.storage_class |= ad.storage_class & (STC.TYPECTOR | STC.synchronized_);
+ ad.makeNested();
+ }
+ if (sc.func)
+ funcdecl.storage_class |= sc.func.storage_class & STC.disable;
+ // Remove prefix storage classes silently.
+ if ((funcdecl.storage_class & STC.TYPECTOR) && !(ad || funcdecl.isNested()))
+ funcdecl.storage_class &= ~STC.TYPECTOR;
+
+ //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration::isFinal());
+
+ if (sc.flags & SCOPE.compile)
+ funcdecl.flags |= FUNCFLAG.compileTimeOnly; // don't emit code for this function
+
+ FuncLiteralDeclaration fld = funcdecl.isFuncLiteralDeclaration();
+ if (fld && fld.treq)
+ {
+ Type treq = fld.treq;
+ assert(treq.nextOf().ty == Tfunction);
+ if (treq.ty == Tdelegate)
+ fld.tok = TOK.delegate_;
+ else if (treq.isPtrToFunction())
+ fld.tok = TOK.function_;
+ else
+ assert(0);
+ funcdecl.linkage = treq.nextOf().toTypeFunction().linkage;
+ }
+ else
+ funcdecl.linkage = sc.linkage;
+
+ // evaluate pragma(inline)
+ if (auto pragmadecl = sc.inlining)
+ funcdecl.inlining = pragmadecl.evalPragmaInline(sc);
+
+ funcdecl.visibility = sc.visibility;
+ funcdecl.userAttribDecl = sc.userAttribDecl;
+ UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl.linkage);
+
+ if (!funcdecl.originalType)
+ funcdecl.originalType = funcdecl.type.syntaxCopy();
+ if (funcdecl.type.ty != Tfunction)
+ {
+ if (funcdecl.type.ty != Terror)
+ {
+ funcdecl.error("`%s` must be a function instead of `%s`", funcdecl.toChars(), funcdecl.type.toChars());
+ funcdecl.type = Type.terror;
+ }
+ funcdecl.errors = true;
+ return;
+ }
+ if (!funcdecl.type.deco)
+ {
+ sc = sc.push();
+ sc.stc |= funcdecl.storage_class & (STC.disable | STC.deprecated_); // forward to function type
+
+ TypeFunction tf = funcdecl.type.toTypeFunction();
+ if (sc.func)
+ {
+ /* If the nesting parent is pure without inference,
+ * then this function defaults to pure too.
+ *
+ * auto foo() pure {
+ * auto bar() {} // become a weak purity function
+ * class C { // nested class
+ * auto baz() {} // become a weak purity function
+ * }
+ *
+ * static auto boo() {} // typed as impure
+ * // Even though, boo cannot call any impure functions.
+ * // See also Expression::checkPurity().
+ * }
+ */
+ if (tf.purity == PURE.impure && (funcdecl.isNested() || funcdecl.isThis()))
+ {
+ FuncDeclaration fd = null;
+ for (Dsymbol p = funcdecl.toParent2(); p; p = p.toParent2())
+ {
+ if (AggregateDeclaration adx = p.isAggregateDeclaration())
+ {
+ if (adx.isNested())
+ continue;
+ break;
+ }
+ if ((fd = p.isFuncDeclaration()) !is null)
+ break;
+ }
+
+ /* If the parent's purity is inferred, then this function's purity needs
+ * to be inferred first.
+ */
+ if (fd && fd.isPureBypassingInference() >= PURE.weak && !funcdecl.isInstantiated())
+ {
+ tf.purity = PURE.fwdref; // default to pure
+ }
+ }
+ }
+
+ if (tf.isref)
+ sc.stc |= STC.ref_;
+ if (tf.isScopeQual)
+ sc.stc |= STC.scope_;
+ if (tf.isnothrow)
+ sc.stc |= STC.nothrow_;
+ if (tf.isnogc)
+ sc.stc |= STC.nogc;
+ if (tf.isproperty)
+ sc.stc |= STC.property;
+ if (tf.purity == PURE.fwdref)
+ sc.stc |= STC.pure_;
+ if (tf.trust != TRUST.default_)
+ sc.stc &= ~STC.safeGroup;
+ if (tf.trust == TRUST.safe)
+ sc.stc |= STC.safe;
+ if (tf.trust == TRUST.system)
+ sc.stc |= STC.system;
+ if (tf.trust == TRUST.trusted)
+ sc.stc |= STC.trusted;
+
+ if (funcdecl.isCtorDeclaration())
+ {
+ tf.isctor = true;
+ Type tret = ad.handleType();
+ assert(tret);
+ tret = tret.addStorageClass(funcdecl.storage_class | sc.stc);
+ tret = tret.addMod(funcdecl.type.mod);
+ tf.next = tret;
+ if (ad.isStructDeclaration())
+ sc.stc |= STC.ref_;
+ }
+
+ // 'return' on a non-static class member function implies 'scope' as well
+ if (ad && ad.isClassDeclaration() && (tf.isreturn || sc.stc & STC.return_) && !(sc.stc & STC.static_))
+ sc.stc |= STC.scope_;
+
+ // If 'this' has no pointers, remove 'scope' as it has no meaning
+ if (sc.stc & STC.scope_ && ad && ad.isStructDeclaration() && !ad.type.hasPointers())
+ {
+ sc.stc &= ~STC.scope_;
+ tf.isScopeQual = false;
+ }
+
+ sc.linkage = funcdecl.linkage;
+
+ if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested()))
+ {
+ OutBuffer buf;
+ MODtoBuffer(&buf, tf.mod);
+ funcdecl.error("without `this` cannot be `%s`", buf.peekChars());
+ tf.mod = 0; // remove qualifiers
+ }
+
+ /* Apply const, immutable, wild and shared storage class
+ * to the function type. Do this before type semantic.
+ */
+ auto stc = funcdecl.storage_class;
+ if (funcdecl.type.isImmutable())
+ stc |= STC.immutable_;
+ if (funcdecl.type.isConst())
+ stc |= STC.const_;
+ if (funcdecl.type.isShared() || funcdecl.storage_class & STC.synchronized_)
+ stc |= STC.shared_;
+ if (funcdecl.type.isWild())
+ stc |= STC.wild;
+ funcdecl.type = funcdecl.type.addSTC(stc);
+
+ funcdecl.type = funcdecl.type.typeSemantic(funcdecl.loc, sc);
+ sc = sc.pop();
+ }
+ if (funcdecl.type.ty != Tfunction)
+ {
+ if (funcdecl.type.ty != Terror)
+ {
+ funcdecl.error("`%s` must be a function instead of `%s`", funcdecl.toChars(), funcdecl.type.toChars());
+ funcdecl.type = Type.terror;
+ }
+ funcdecl.errors = true;
+ return;
+ }
+ else
+ {
+ // Merge back function attributes into 'originalType'.
+ // It's used for mangling, ddoc, and json output.
+ TypeFunction tfo = funcdecl.originalType.toTypeFunction();
+ TypeFunction tfx = funcdecl.type.toTypeFunction();
+ tfo.mod = tfx.mod;
+ tfo.isScopeQual = tfx.isScopeQual;
+ tfo.isreturninferred = tfx.isreturninferred;
+ tfo.isscopeinferred = tfx.isscopeinferred;
+ tfo.isref = tfx.isref;
+ tfo.isnothrow = tfx.isnothrow;
+ tfo.isnogc = tfx.isnogc;
+ tfo.isproperty = tfx.isproperty;
+ tfo.purity = tfx.purity;
+ tfo.trust = tfx.trust;
+
+ funcdecl.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
+ }
+
+ f = cast(TypeFunction)funcdecl.type;
+
+ if ((funcdecl.storage_class & STC.auto_) && !f.isref && !funcdecl.inferRetType)
+ funcdecl.error("storage class `auto` has no effect if return type is not inferred");
+
+ /* Functions can only be 'scope' if they have a 'this'
+ */
+ if (f.isScopeQual && !funcdecl.isNested() && !ad)
+ {
+ funcdecl.error("functions cannot be `scope`");
+ }
+
+ if (f.isreturn && !funcdecl.needThis() && !funcdecl.isNested())
+ {
+ /* Non-static nested functions have a hidden 'this' pointer to which
+ * the 'return' applies
+ */
+ if (sc.scopesym && sc.scopesym.isAggregateDeclaration())
+ funcdecl.error("`static` member has no `this` to which `return` can apply");
+ else
+ error(funcdecl.loc, "Top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars());
+ }
+
+ if (funcdecl.isAbstract() && !funcdecl.isVirtual())
+ {
+ const(char)* sfunc;
+ if (funcdecl.isStatic())
+ sfunc = "static";
+ else if (funcdecl.visibility.kind == Visibility.Kind.private_ || funcdecl.visibility.kind == Visibility.Kind.package_)
+ sfunc = visibilityToChars(funcdecl.visibility.kind);
+ else
+ sfunc = "final";
+ funcdecl.error("`%s` functions cannot be `abstract`", sfunc);
+ }
+
+ if (funcdecl.isOverride() && !funcdecl.isVirtual() && !funcdecl.isFuncLiteralDeclaration())
+ {
+ Visibility.Kind kind = funcdecl.visible().kind;
+ if ((kind == Visibility.Kind.private_ || kind == Visibility.Kind.package_) && funcdecl.isMember())
+ funcdecl.error("`%s` method is not virtual and cannot override", visibilityToChars(kind));
+ else
+ funcdecl.error("cannot override a non-virtual function");
+ }
+
+ if (funcdecl.isAbstract() && funcdecl.isFinalFunc())
+ funcdecl.error("cannot be both `final` and `abstract`");
+ version (none)
+ {
+ if (funcdecl.isAbstract() && funcdecl.fbody)
+ funcdecl.error("`abstract` functions cannot have bodies");
+ }
+
+ version (none)
+ {
+ if (funcdecl.isStaticConstructor() || funcdecl.isStaticDestructor())
+ {
+ if (!funcdecl.isStatic() || funcdecl.type.nextOf().ty != Tvoid)
+ funcdecl.error("static constructors / destructors must be `static void`");
+ if (f.arguments && f.arguments.dim)
+ funcdecl.error("static constructors / destructors must have empty parameter list");
+ // BUG: check for invalid storage classes
+ }
+ }
+
+ if (const pors = sc.flags & (SCOPE.printf | SCOPE.scanf))
+ {
+ /* printf/scanf-like functions must be of the form:
+ * extern (C/C++) T printf([parameters...], const(char)* format, ...);
+ * or:
+ * extern (C/C++) T vprintf([parameters...], const(char)* format, va_list);
+ */
+
+ static bool isPointerToChar(Parameter p)
+ {
+ if (auto tptr = p.type.isTypePointer())
+ {
+ return tptr.next.ty == Tchar;
+ }
+ return false;
+ }
+
+ bool isVa_list(Parameter p)
+ {
+ return p.type.equals(target.va_listType(funcdecl.loc, sc));
+ }
+
+ const nparams = f.parameterList.length;
+ if ((f.linkage == LINK.c || f.linkage == LINK.cpp) &&
+
+ (f.parameterList.varargs == VarArg.variadic &&
+ nparams >= 1 &&
+ isPointerToChar(f.parameterList[nparams - 1]) ||
+
+ f.parameterList.varargs == VarArg.none &&
+ nparams >= 2 &&
+ isPointerToChar(f.parameterList[nparams - 2]) &&
+ isVa_list(f.parameterList[nparams - 1])
+ )
+ )
+ {
+ funcdecl.flags |= (pors == SCOPE.printf) ? FUNCFLAG.printf : FUNCFLAG.scanf;
+ }
+ else
+ {
+ const p = (pors == SCOPE.printf ? Id.printf : Id.scanf).toChars();
+ if (f.parameterList.varargs == VarArg.variadic)
+ {
+ funcdecl.error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, ...)`"
+ ~ " not `%s`",
+ p, f.next.toChars(), funcdecl.toChars(), funcdecl.type.toChars());
+ }
+ else
+ {
+ funcdecl.error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, va_list)`",
+ p, f.next.toChars(), funcdecl.toChars());
+ }
+ }
+ }
+
+ id = parent.isInterfaceDeclaration();
+ if (id)
+ {
+ funcdecl.storage_class |= STC.abstract_;
+ if (funcdecl.isCtorDeclaration() || funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration() || funcdecl.isNewDeclaration() || funcdecl.isDelete())
+ funcdecl.error("constructors, destructors, postblits, invariants, new and delete functions are not allowed in interface `%s`", id.toChars());
+ if (funcdecl.fbody && funcdecl.isVirtual())
+ funcdecl.error("function body only allowed in `final` functions in interface `%s`", id.toChars());
+ }
+ if (UnionDeclaration ud = parent.isUnionDeclaration())
+ {
+ if (funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration())
+ funcdecl.error("destructors, postblits and invariants are not allowed in union `%s`", ud.toChars());
+ }
+
+ if (StructDeclaration sd = parent.isStructDeclaration())
+ {
+ if (funcdecl.isCtorDeclaration())
+ {
+ goto Ldone;
+ }
+ }
+
+ if (ClassDeclaration cd = parent.isClassDeclaration())
+ {
+ parent = cd = objc.getParent(funcdecl, cd);
+
+ if (funcdecl.isCtorDeclaration())
+ {
+ goto Ldone;
+ }
+
+ if (funcdecl.storage_class & STC.abstract_)
+ cd.isabstract = ThreeState.yes;
+
+ // if static function, do not put in vtbl[]
+ if (!funcdecl.isVirtual())
+ {
+ //printf("\tnot virtual\n");
+ goto Ldone;
+ }
+ // Suppress further errors if the return type is an error
+ if (funcdecl.type.nextOf() == Type.terror)
+ goto Ldone;
+
+ bool may_override = false;
+ for (size_t i = 0; i < cd.baseclasses.dim; i++)
+ {
+ BaseClass* b = (*cd.baseclasses)[i];
+ ClassDeclaration cbd = b.type.toBasetype().isClassHandle();
+ if (!cbd)
+ continue;
+ for (size_t j = 0; j < cbd.vtbl.dim; j++)
+ {
+ FuncDeclaration f2 = cbd.vtbl[j].isFuncDeclaration();
+ if (!f2 || f2.ident != funcdecl.ident)
+ continue;
+ if (cbd.parent && cbd.parent.isTemplateInstance())
+ {
+ if (!f2.functionSemantic())
+ goto Ldone;
+ }
+ may_override = true;
+ }
+ }
+ if (may_override && funcdecl.type.nextOf() is null)
+ {
+ /* If same name function exists in base class but 'this' is auto return,
+ * cannot find index of base class's vtbl[] to override.
+ */
+ funcdecl.error("return type inference is not supported if may override base class function");
+ }
+
+ /* Find index of existing function in base class's vtbl[] to override
+ * (the index will be the same as in cd's current vtbl[])
+ */
+ int vi = cd.baseClass ? funcdecl.findVtblIndex(&cd.baseClass.vtbl, cast(int)cd.baseClass.vtbl.dim) : -1;
+
+ bool doesoverride = false;
+ switch (vi)
+ {
+ case -1:
+ Lintro:
+ /* Didn't find one, so
+ * This is an 'introducing' function which gets a new
+ * slot in the vtbl[].
+ */
+
+ // Verify this doesn't override previous final function
+ if (cd.baseClass)
+ {
+ Dsymbol s = cd.baseClass.search(funcdecl.loc, funcdecl.ident);
+ if (s)
+ {
+ FuncDeclaration f2 = s.isFuncDeclaration();
+ if (f2)
+ {
+ f2 = f2.overloadExactMatch(funcdecl.type);
+ if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_)
+ funcdecl.error("cannot override `final` function `%s`", f2.toPrettyChars());
+ }
+ }
+ }
+
+ /* These quirky conditions mimic what VC++ appears to do
+ */
+ if (target.mscoff && cd.classKind == ClassKind.cpp &&
+ cd.baseClass && cd.baseClass.vtbl.dim)
+ {
+ /* if overriding an interface function, then this is not
+ * introducing and don't put it in the class vtbl[]
+ */
+ funcdecl.interfaceVirtual = funcdecl.overrideInterface();
+ if (funcdecl.interfaceVirtual)
+ {
+ //printf("\tinterface function %s\n", toChars());
+ cd.vtblFinal.push(funcdecl);
+ goto Linterfaces;
+ }
+ }
+
+ if (funcdecl.isFinalFunc())
+ {
+ // Don't check here, as it may override an interface function
+ //if (isOverride())
+ // error("is marked as override, but does not override any function");
+ cd.vtblFinal.push(funcdecl);
+ }
+ else
+ {
+ //printf("\tintroducing function %s\n", funcdecl.toChars());
+ funcdecl.introducing = 1;
+ if (cd.classKind == ClassKind.cpp && target.cpp.reverseOverloads)
+ {
+ /* Overloaded functions with same name are grouped and in reverse order.
+ * Search for first function of overload group, and insert
+ * funcdecl into vtbl[] immediately before it.
+ */
+ funcdecl.vtblIndex = cast(int)cd.vtbl.dim;
+ bool found;
+ foreach (const i, s; cd.vtbl)
+ {
+ if (found)
+ // the rest get shifted forward
+ ++s.isFuncDeclaration().vtblIndex;
+ else if (s.ident == funcdecl.ident && s.parent == parent)
+ {
+ // found first function of overload group
+ funcdecl.vtblIndex = cast(int)i;
+ found = true;
+ ++s.isFuncDeclaration().vtblIndex;
+ }
+ }
+ cd.vtbl.insert(funcdecl.vtblIndex, funcdecl);
+
+ debug foreach (const i, s; cd.vtbl)
+ {
+ // a C++ dtor gets its vtblIndex later (and might even be added twice to the vtbl),
+ // e.g. when compiling druntime with a debug compiler, namely with core.stdcpp.exception.
+ if (auto fd = s.isFuncDeclaration())
+ assert(fd.vtblIndex == i ||
+ (cd.classKind == ClassKind.cpp && fd.isDtorDeclaration) ||
+ funcdecl.parent.isInterfaceDeclaration); // interface functions can be in multiple vtbls
+ }
+ }
+ else
+ {
+ // Append to end of vtbl[]
+ vi = cast(int)cd.vtbl.dim;
+ cd.vtbl.push(funcdecl);
+ funcdecl.vtblIndex = vi;
+ }
+ }
+ break;
+
+ case -2:
+ // can't determine because of forward references
+ funcdecl.errors = true;
+ return;
+
+ default:
+ {
+ FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration();
+ FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration();
+ // This function is covariant with fdv
+
+ if (fdc == funcdecl)
+ {
+ doesoverride = true;
+ break;
+ }
+
+ if (fdc.toParent() == parent)
+ {
+ //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc = %p %s %s @ [%s]\n\tfdv = %p %s %s @ [%s]\n",
+ // vi, this, this.toChars(), this.type.toChars(), this.loc.toChars(),
+ // fdc, fdc .toChars(), fdc .type.toChars(), fdc .loc.toChars(),
+ // fdv, fdv .toChars(), fdv .type.toChars(), fdv .loc.toChars());
+
+ // fdc overrides fdv exactly, then this introduces new function.
+ if (fdc.type.mod == fdv.type.mod && funcdecl.type.mod != fdv.type.mod)
+ goto Lintro;
+ }
+
+ if (fdv.isDeprecated)
+ deprecation(funcdecl.loc, "`%s` is overriding the deprecated method `%s`",
+ funcdecl.toPrettyChars, fdv.toPrettyChars);
+
+ // This function overrides fdv
+ if (fdv.isFinalFunc())
+ funcdecl.error("cannot override `final` function `%s`", fdv.toPrettyChars());
+
+ if (!funcdecl.isOverride())
+ {
+ if (fdv.isFuture())
+ {
+ deprecation(funcdecl.loc, "`@__future` base class method `%s` is being overridden by `%s`; rename the latter", fdv.toPrettyChars(), funcdecl.toPrettyChars());
+ // Treat 'this' as an introducing function, giving it a separate hierarchy in the vtbl[]
+ goto Lintro;
+ }
+ else
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=17349
+ error(funcdecl.loc, "cannot implicitly override base class method `%s` with `%s`; add `override` attribute",
+ fdv.toPrettyChars(), funcdecl.toPrettyChars());
+ }
+ }
+ doesoverride = true;
+ if (fdc.toParent() == parent)
+ {
+ // If both are mixins, or both are not, then error.
+ // If either is not, the one that is not overrides the other.
+ bool thismixin = funcdecl.parent.isClassDeclaration() !is null;
+ bool fdcmixin = fdc.parent.isClassDeclaration() !is null;
+ if (thismixin == fdcmixin)
+ {
+ funcdecl.error("multiple overrides of same function");
+ }
+ /*
+ * https://issues.dlang.org/show_bug.cgi?id=711
+ *
+ * If an overriding method is introduced through a mixin,
+ * we need to update the vtbl so that both methods are
+ * present.
+ */
+ else if (thismixin)
+ {
+ /* if the mixin introduced the overriding method, then reintroduce it
+ * in the vtbl. The initial entry for the mixined method
+ * will be updated at the end of the enclosing `if` block
+ * to point to the current (non-mixined) function.
+ */
+ auto vitmp = cast(int)cd.vtbl.dim;
+ cd.vtbl.push(fdc);
+ fdc.vtblIndex = vitmp;
+ }
+ else if (fdcmixin)
+ {
+ /* if the current overriding function is coming from a
+ * mixined block, then push the current function in the
+ * vtbl, but keep the previous (non-mixined) function as
+ * the overriding one.
+ */
+ auto vitmp = cast(int)cd.vtbl.dim;
+ cd.vtbl.push(funcdecl);
+ funcdecl.vtblIndex = vitmp;
+ break;
+ }
+ else // fdc overrides fdv
+ {
+ // this doesn't override any function
+ break;
+ }
+ }
+ cd.vtbl[vi] = funcdecl;
+ funcdecl.vtblIndex = vi;
+
+ /* Remember which functions this overrides
+ */
+ funcdecl.foverrides.push(fdv);
+
+ /* This works by whenever this function is called,
+ * it actually returns tintro, which gets dynamically
+ * cast to type. But we know that tintro is a base
+ * of type, so we could optimize it by not doing a
+ * dynamic cast, but just subtracting the isBaseOf()
+ * offset if the value is != null.
+ */
+
+ if (fdv.tintro)
+ funcdecl.tintro = fdv.tintro;
+ else if (!funcdecl.type.equals(fdv.type))
+ {
+ /* Only need to have a tintro if the vptr
+ * offsets differ
+ */
+ int offset;
+ if (fdv.type.nextOf().isBaseOf(funcdecl.type.nextOf(), &offset))
+ {
+ funcdecl.tintro = fdv.type;
+ }
+ }
+ break;
+ }
+ }
+
+ /* Go through all the interface bases.
+ * If this function is covariant with any members of those interface
+ * functions, set the tintro.
+ */
+ Linterfaces:
+ bool foundVtblMatch = false;
+
+ for (ClassDeclaration bcd = cd; !foundVtblMatch && bcd; bcd = bcd.baseClass)
+ {
+ foreach (b; bcd.interfaces)
+ {
+ vi = funcdecl.findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim);
+ switch (vi)
+ {
+ case -1:
+ break;
+
+ case -2:
+ // can't determine because of forward references
+ funcdecl.errors = true;
+ return;
+
+ default:
+ {
+ auto fdv = cast(FuncDeclaration)b.sym.vtbl[vi];
+ Type ti = null;
+
+ foundVtblMatch = true;
+
+ /* Remember which functions this overrides
+ */
+ funcdecl.foverrides.push(fdv);
+
+ /* Should we really require 'override' when implementing
+ * an interface function?
+ */
+ //if (!isOverride())
+ // warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv.toPrettyChars());
+
+ if (fdv.tintro)
+ ti = fdv.tintro;
+ else if (!funcdecl.type.equals(fdv.type))
+ {
+ /* Only need to have a tintro if the vptr
+ * offsets differ
+ */
+ int offset;
+ if (fdv.type.nextOf().isBaseOf(funcdecl.type.nextOf(), &offset))
+ {
+ ti = fdv.type;
+ }
+ }
+ if (ti)
+ {
+ if (funcdecl.tintro)
+ {
+ if (!funcdecl.tintro.nextOf().equals(ti.nextOf()) && !funcdecl.tintro.nextOf().isBaseOf(ti.nextOf(), null) && !ti.nextOf().isBaseOf(funcdecl.tintro.nextOf(), null))
+ {
+ funcdecl.error("incompatible covariant types `%s` and `%s`", funcdecl.tintro.toChars(), ti.toChars());
+ }
+ }
+ else
+ {
+ funcdecl.tintro = ti;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (foundVtblMatch)
+ {
+ goto L2;
+ }
+
+ if (!doesoverride && funcdecl.isOverride() && (funcdecl.type.nextOf() || !may_override))
+ {
+ BaseClass* bc = null;
+ Dsymbol s = null;
+ for (size_t i = 0; i < cd.baseclasses.dim; i++)
+ {
+ bc = (*cd.baseclasses)[i];
+ s = bc.sym.search_correct(funcdecl.ident);
+ if (s)
+ break;
+ }
+
+ if (s)
+ {
+ HdrGenState hgs;
+ OutBuffer buf;
+
+ auto fd = s.isFuncDeclaration();
+ functionToBufferFull(cast(TypeFunction)(funcdecl.type), &buf,
+ new Identifier(funcdecl.toPrettyChars()), &hgs, null);
+ const(char)* funcdeclToChars = buf.peekChars();
+
+ if (fd)
+ {
+ OutBuffer buf1;
+
+ if (fd.ident == funcdecl.ident)
+ hgs.fullQual = true;
+ functionToBufferFull(cast(TypeFunction)(fd.type), &buf1,
+ new Identifier(fd.toPrettyChars()), &hgs, null);
+
+ error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?",
+ funcdeclToChars, buf1.peekChars());
+ }
+ else
+ {
+ error(funcdecl.loc, "function `%s` does not override any function, did you mean to override %s `%s`?",
+ funcdeclToChars, s.kind, s.toPrettyChars());
+ errorSupplemental(funcdecl.loc, "Functions are the only declarations that may be overriden");
+ }
+ }
+ else
+ funcdecl.error("does not override any function");
+ }
+
+ L2:
+ objc.setSelector(funcdecl, sc);
+ objc.checkLinkage(funcdecl);
+ objc.addToClassMethodList(funcdecl, cd);
+ objc.setAsOptional(funcdecl, sc);
+
+ /* Go through all the interface bases.
+ * Disallow overriding any final functions in the interface(s).
+ */
+ foreach (b; cd.interfaces)
+ {
+ if (b.sym)
+ {
+ Dsymbol s = search_function(b.sym, funcdecl.ident);
+ if (s)
+ {
+ FuncDeclaration f2 = s.isFuncDeclaration();
+ if (f2)
+ {
+ f2 = f2.overloadExactMatch(funcdecl.type);
+ if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_)
+ funcdecl.error("cannot override `final` function `%s.%s`", b.sym.toChars(), f2.toPrettyChars());
+ }
+ }
+ }
+ }
+
+ if (funcdecl.isOverride)
+ {
+ if (funcdecl.storage_class & STC.disable)
+ deprecation(funcdecl.loc,
+ "`%s` cannot be annotated with `@disable` because it is overriding a function in the base class",
+ funcdecl.toPrettyChars);
+ if (funcdecl.isDeprecated)
+ deprecation(funcdecl.loc,
+ "`%s` cannot be marked as `deprecated` because it is overriding a function in the base class",
+ funcdecl.toPrettyChars);
+ }
+
+ }
+ else if (funcdecl.isOverride() && !parent.isTemplateInstance())
+ funcdecl.error("`override` only applies to class member functions");
+
+ if (auto ti = parent.isTemplateInstance)
+ {
+ objc.setSelector(funcdecl, sc);
+ objc.setAsOptional(funcdecl, sc);
+ }
+
+ objc.validateSelector(funcdecl);
+ objc.validateOptional(funcdecl);
+ // Reflect this.type to f because it could be changed by findVtblIndex
+ f = funcdecl.type.toTypeFunction();
+
+ Ldone:
+ if (!funcdecl.fbody && !funcdecl.allowsContractWithoutBody())
+ funcdecl.error("`in` and `out` contracts can only appear without a body when they are virtual interface functions or abstract");
+
+ /* Do not allow template instances to add virtual functions
+ * to a class.
+ */
+ if (funcdecl.isVirtual())
+ {
+ TemplateInstance ti = parent.isTemplateInstance();
+ if (ti)
+ {
+ // Take care of nested templates
+ while (1)
+ {
+ TemplateInstance ti2 = ti.tempdecl.parent.isTemplateInstance();
+ if (!ti2)
+ break;
+ ti = ti2;
+ }
+
+ // If it's a member template
+ ClassDeclaration cd = ti.tempdecl.isClassMember();
+ if (cd)
+ {
+ funcdecl.error("cannot use template to add virtual function to class `%s`", cd.toChars());
+ }
+ }
+ }
+
+ if (funcdecl.isMain())
+ funcdecl.checkDmain(); // Check main() parameters and return type
+
+ /* Purity and safety can be inferred for some functions by examining
+ * the function body.
+ */
+ if (funcdecl.canInferAttributes(sc))
+ funcdecl.initInferAttributes();
+
+ Module.dprogress++;
+ funcdecl.semanticRun = PASS.semanticdone;
+
+ /* Save scope for possible later use (if we need the
+ * function internals)
+ */
+ funcdecl._scope = sc.copy();
+ funcdecl._scope.setNoFree();
+
+ __gshared bool printedMain = false; // semantic might run more than once
+ if (global.params.verbose && !printedMain)
+ {
+ const(char)* type = funcdecl.isMain() ? "main" : funcdecl.isWinMain() ? "winmain" : funcdecl.isDllMain() ? "dllmain" : cast(const(char)*)null;
+ Module mod = sc._module;
+
+ if (type && mod)
+ {
+ printedMain = true;
+ auto name = mod.srcfile.toChars();
+ auto path = FileName.searchPath(global.path, name, true);
+ message("entry %-10s\t%s", type, path ? path : name);
+ }
+ }
+
+ if (funcdecl.fbody && funcdecl.isMain() && sc._module.isRoot())
+ {
+ // check if `_d_cmain` is defined
+ bool cmainTemplateExists()
+ {
+ auto rootSymbol = sc.search(funcdecl.loc, Id.empty, null);
+ if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object))
+ if (moduleSymbol.search(funcdecl.loc, Id.CMain))
+ return true;
+
+ return false;
+ }
+
+ // Only mixin `_d_cmain` if it is defined
+ if (cmainTemplateExists())
+ {
+ // add `mixin _d_cmain!();` to the declaring module
+ auto tqual = new TypeIdentifier(funcdecl.loc, Id.CMain);
+ auto tm = new TemplateMixin(funcdecl.loc, null, tqual, null);
+ sc._module.members.push(tm);
+ }
+ }
+
+ assert(funcdecl.type.ty != Terror || funcdecl.errors);
+
+ // semantic for parameters' UDAs
+ foreach (i, param; f.parameterList)
+ {
+ if (param && param.userAttribDecl)
+ param.userAttribDecl.dsymbolSemantic(sc);
+ }
+ }
+
+ /// Do the semantic analysis on the external interface to the function.
+ override void visit(FuncDeclaration funcdecl)
+ {
+ funcDeclarationSemantic(funcdecl);
+ }
+
+ override void visit(CtorDeclaration ctd)
+ {
+ //printf("CtorDeclaration::semantic() %s\n", toChars());
+ if (ctd.semanticRun >= PASS.semanticdone)
+ return;
+ if (ctd._scope)
+ {
+ sc = ctd._scope;
+ ctd._scope = null;
+ }
+
+ ctd.parent = sc.parent;
+ Dsymbol p = ctd.toParentDecl();
+ AggregateDeclaration ad = p.isAggregateDeclaration();
+ if (!ad)
+ {
+ error(ctd.loc, "constructor can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars());
+ ctd.type = Type.terror;
+ ctd.errors = true;
+ return;
+ }
+
+ sc = sc.push();
+
+ if (sc.stc & STC.static_)
+ {
+ if (sc.stc & STC.shared_)
+ error(ctd.loc, "`shared static` has no effect on a constructor inside a `shared static` block. Use `shared static this()`");
+ else
+ error(ctd.loc, "`static` has no effect on a constructor inside a `static` block. Use `static this()`");
+ }
+
+ sc.stc &= ~STC.static_; // not a static constructor
+
+ funcDeclarationSemantic(ctd);
+
+ sc.pop();
+
+ if (ctd.errors)
+ return;
+
+ TypeFunction tf = ctd.type.toTypeFunction();
+
+ /* See if it's the default constructor
+ * But, template constructor should not become a default constructor.
+ */
+ if (ad && (!ctd.parent.isTemplateInstance() || ctd.parent.isTemplateMixin()))
+ {
+ immutable dim = tf.parameterList.length;
+
+ if (auto sd = ad.isStructDeclaration())
+ {
+ if (dim == 0 && tf.parameterList.varargs == VarArg.none) // empty default ctor w/o any varargs
+ {
+ if (ctd.fbody || !(ctd.storage_class & STC.disable))
+ {
+ ctd.error("default constructor for structs only allowed " ~
+ "with `@disable`, no body, and no parameters");
+ ctd.storage_class |= STC.disable;
+ ctd.fbody = null;
+ }
+ sd.noDefaultCtor = true;
+ }
+ else if (dim == 0 && tf.parameterList.varargs != VarArg.none) // allow varargs only ctor
+ {
+ }
+ else if (dim && tf.parameterList[0].defaultArg)
+ {
+ // if the first parameter has a default argument, then the rest does as well
+ if (ctd.storage_class & STC.disable)
+ {
+ ctd.error("is marked `@disable`, so it cannot have default "~
+ "arguments for all parameters.");
+ errorSupplemental(ctd.loc, "Use `@disable this();` if you want to disable default initialization.");
+ }
+ else
+ ctd.error("all parameters have default arguments, "~
+ "but structs cannot have default constructors.");
+ }
+ else if ((dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg)))
+ {
+ //printf("tf: %s\n", tf.toChars());
+ auto param = tf.parameterList[0];
+ if (param.storageClass & STC.ref_ && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
+ {
+ //printf("copy constructor\n");
+ ctd.isCpCtor = true;
+ }
+ }
+ }
+ else if (dim == 0 && tf.parameterList.varargs == VarArg.none)
+ {
+ ad.defaultCtor = ctd;
+ }
+ }
+ }
+
+ override void visit(PostBlitDeclaration pbd)
+ {
+ //printf("PostBlitDeclaration::semantic() %s\n", toChars());
+ //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id::dtor.toChars(), ident, Id::dtor);
+ //printf("stc = x%llx\n", sc.stc);
+ if (pbd.semanticRun >= PASS.semanticdone)
+ return;
+ if (pbd._scope)
+ {
+ sc = pbd._scope;
+ pbd._scope = null;
+ }
+
+ pbd.parent = sc.parent;
+ Dsymbol p = pbd.toParent2();
+ StructDeclaration ad = p.isStructDeclaration();
+ if (!ad)
+ {
+ error(pbd.loc, "postblit can only be a member of struct, not %s `%s`", p.kind(), p.toChars());
+ pbd.type = Type.terror;
+ pbd.errors = true;
+ return;
+ }
+ if (pbd.ident == Id.postblit && pbd.semanticRun < PASS.semantic)
+ ad.postblits.push(pbd);
+ if (!pbd.type)
+ pbd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, pbd.storage_class);
+
+ sc = sc.push();
+ sc.stc &= ~STC.static_; // not static
+ sc.linkage = LINK.d;
+
+ funcDeclarationSemantic(pbd);
+
+ sc.pop();
+ }
+
+ override void visit(DtorDeclaration dd)
+ {
+ //printf("DtorDeclaration::semantic() %s\n", toChars());
+ //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id::dtor.toChars(), ident, Id::dtor);
+ if (dd.semanticRun >= PASS.semanticdone)
+ return;
+ if (dd._scope)
+ {
+ sc = dd._scope;
+ dd._scope = null;
+ }
+
+ dd.parent = sc.parent;
+ Dsymbol p = dd.toParent2();
+ AggregateDeclaration ad = p.isAggregateDeclaration();
+ if (!ad)
+ {
+ error(dd.loc, "destructor can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars());
+ dd.type = Type.terror;
+ dd.errors = true;
+ return;
+ }
+ if (dd.ident == Id.dtor && dd.semanticRun < PASS.semantic)
+ ad.dtors.push(dd);
+ if (!dd.type)
+ {
+ dd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, dd.storage_class);
+ if (ad.classKind == ClassKind.cpp && dd.ident == Id.dtor)
+ {
+ if (auto cldec = ad.isClassDeclaration())
+ {
+ assert (cldec.cppDtorVtblIndex == -1); // double-call check already by dd.type
+ if (cldec.baseClass && cldec.baseClass.cppDtorVtblIndex != -1)
+ {
+ // override the base virtual
+ cldec.cppDtorVtblIndex = cldec.baseClass.cppDtorVtblIndex;
+ }
+ else if (!dd.isFinal())
+ {
+ // reserve the dtor slot for the destructor (which we'll create later)
+ cldec.cppDtorVtblIndex = cast(int)cldec.vtbl.dim;
+ cldec.vtbl.push(dd);
+ if (target.cpp.twoDtorInVtable)
+ cldec.vtbl.push(dd); // deleting destructor uses a second slot
+ }
+ }
+ }
+ }
+
+ sc = sc.push();
+ sc.stc &= ~STC.static_; // not a static destructor
+ if (sc.linkage != LINK.cpp)
+ sc.linkage = LINK.d;
+
+ funcDeclarationSemantic(dd);
+
+ sc.pop();
+ }
+
+ override void visit(StaticCtorDeclaration scd)
+ {
+ //printf("StaticCtorDeclaration::semantic()\n");
+ if (scd.semanticRun >= PASS.semanticdone)
+ return;
+ if (scd._scope)
+ {
+ sc = scd._scope;
+ scd._scope = null;
+ }
+
+ scd.parent = sc.parent;
+ Dsymbol p = scd.parent.pastMixin();
+ if (!p.isScopeDsymbol())
+ {
+ const(char)* s = (scd.isSharedStaticCtorDeclaration() ? "shared " : "");
+ error(scd.loc, "`%sstatic` constructor can only be member of module/aggregate/template, not %s `%s`", s, p.kind(), p.toChars());
+ scd.type = Type.terror;
+ scd.errors = true;
+ return;
+ }
+ if (!scd.type)
+ scd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, scd.storage_class);
+
+ /* If the static ctor appears within a template instantiation,
+ * it could get called multiple times by the module constructors
+ * for different modules. Thus, protect it with a gate.
+ */
+ if (scd.isInstantiated() && scd.semanticRun < PASS.semantic)
+ {
+ /* Add this prefix to the function:
+ * static int gate;
+ * if (++gate != 1) return;
+ * Note that this is not thread safe; should not have threads
+ * during static construction.
+ */
+ auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null);
+ v.storage_class = STC.temp | (scd.isSharedStaticCtorDeclaration() ? STC.static_ : STC.tls);
+
+ auto sa = new Statements();
+ Statement s = new ExpStatement(Loc.initial, v);
+ sa.push(s);
+
+ Expression e = new IdentifierExp(Loc.initial, v.ident);
+ e = new AddAssignExp(Loc.initial, e, IntegerExp.literal!1);
+ e = new EqualExp(TOK.notEqual, Loc.initial, e, IntegerExp.literal!1);
+ s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial);
+
+ sa.push(s);
+ if (scd.fbody)
+ sa.push(scd.fbody);
+
+ scd.fbody = new CompoundStatement(Loc.initial, sa);
+ }
+
+ const LINK save = sc.linkage;
+ if (save != LINK.d)
+ {
+ const(char)* s = (scd.isSharedStaticCtorDeclaration() ? "shared " : "");
+ deprecation(scd.loc, "`%sstatic` constructor can only be of D linkage", s);
+ // Just correct it
+ sc.linkage = LINK.d;
+ }
+ funcDeclarationSemantic(scd);
+ sc.linkage = save;
+
+ // We're going to need ModuleInfo
+ Module m = scd.getModule();
+ if (!m)
+ m = sc._module;
+ if (m)
+ {
+ m.needmoduleinfo = 1;
+ //printf("module1 %s needs moduleinfo\n", m.toChars());
+ }
+ }
+
+ override void visit(StaticDtorDeclaration sdd)
+ {
+ if (sdd.semanticRun >= PASS.semanticdone)
+ return;
+ if (sdd._scope)
+ {
+ sc = sdd._scope;
+ sdd._scope = null;
+ }
+
+ sdd.parent = sc.parent;
+ Dsymbol p = sdd.parent.pastMixin();
+ if (!p.isScopeDsymbol())
+ {
+ const(char)* s = (sdd.isSharedStaticDtorDeclaration() ? "shared " : "");
+ error(sdd.loc, "`%sstatic` destructor can only be member of module/aggregate/template, not %s `%s`", s, p.kind(), p.toChars());
+ sdd.type = Type.terror;
+ sdd.errors = true;
+ return;
+ }
+ if (!sdd.type)
+ sdd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, sdd.storage_class);
+
+ /* If the static ctor appears within a template instantiation,
+ * it could get called multiple times by the module constructors
+ * for different modules. Thus, protect it with a gate.
+ */
+ if (sdd.isInstantiated() && sdd.semanticRun < PASS.semantic)
+ {
+ /* Add this prefix to the function:
+ * static int gate;
+ * if (--gate != 0) return;
+ * Increment gate during constructor execution.
+ * Note that this is not thread safe; should not have threads
+ * during static destruction.
+ */
+ auto v = new VarDeclaration(Loc.initial, Type.tint32, Id.gate, null);
+ v.storage_class = STC.temp | (sdd.isSharedStaticDtorDeclaration() ? STC.static_ : STC.tls);
+
+ auto sa = new Statements();
+ Statement s = new ExpStatement(Loc.initial, v);
+ sa.push(s);
+
+ Expression e = new IdentifierExp(Loc.initial, v.ident);
+ e = new AddAssignExp(Loc.initial, e, IntegerExp.literal!(-1));
+ e = new EqualExp(TOK.notEqual, Loc.initial, e, IntegerExp.literal!0);
+ s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial);
+
+ sa.push(s);
+ if (sdd.fbody)
+ sa.push(sdd.fbody);
+
+ sdd.fbody = new CompoundStatement(Loc.initial, sa);
+
+ sdd.vgate = v;
+ }
+
+ const LINK save = sc.linkage;
+ if (save != LINK.d)
+ {
+ const(char)* s = (sdd.isSharedStaticDtorDeclaration() ? "shared " : "");
+ deprecation(sdd.loc, "`%sstatic` destructor can only be of D linkage", s);
+ // Just correct it
+ sc.linkage = LINK.d;
+ }
+ funcDeclarationSemantic(sdd);
+ sc.linkage = save;
+
+ // We're going to need ModuleInfo
+ Module m = sdd.getModule();
+ if (!m)
+ m = sc._module;
+ if (m)
+ {
+ m.needmoduleinfo = 1;
+ //printf("module2 %s needs moduleinfo\n", m.toChars());
+ }
+ }
+
+ override void visit(InvariantDeclaration invd)
+ {
+ if (invd.semanticRun >= PASS.semanticdone)
+ return;
+ if (invd._scope)
+ {
+ sc = invd._scope;
+ invd._scope = null;
+ }
+
+ invd.parent = sc.parent;
+ Dsymbol p = invd.parent.pastMixin();
+ AggregateDeclaration ad = p.isAggregateDeclaration();
+ if (!ad)
+ {
+ error(invd.loc, "`invariant` can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars());
+ invd.type = Type.terror;
+ invd.errors = true;
+ return;
+ }
+ if (invd.ident != Id.classInvariant &&
+ invd.semanticRun < PASS.semantic &&
+ !ad.isUnionDeclaration() // users are on their own with union fields
+ )
+ ad.invs.push(invd);
+ if (!invd.type)
+ invd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, invd.storage_class);
+
+ sc = sc.push();
+ sc.stc &= ~STC.static_; // not a static invariant
+ sc.stc |= STC.const_; // invariant() is always const
+ sc.flags = (sc.flags & ~SCOPE.contract) | SCOPE.invariant_;
+ sc.linkage = LINK.d;
+
+ funcDeclarationSemantic(invd);
+
+ sc.pop();
+ }
+
+ override void visit(UnitTestDeclaration utd)
+ {
+ if (utd.semanticRun >= PASS.semanticdone)
+ return;
+ if (utd._scope)
+ {
+ sc = utd._scope;
+ utd._scope = null;
+ }
+
+ utd.visibility = sc.visibility;
+
+ utd.parent = sc.parent;
+ Dsymbol p = utd.parent.pastMixin();
+ if (!p.isScopeDsymbol())
+ {
+ error(utd.loc, "`unittest` can only be a member of module/aggregate/template, not %s `%s`", p.kind(), p.toChars());
+ utd.type = Type.terror;
+ utd.errors = true;
+ return;
+ }
+
+ if (global.params.useUnitTests)
+ {
+ if (!utd.type)
+ utd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, utd.storage_class);
+ Scope* sc2 = sc.push();
+ sc2.linkage = LINK.d;
+ funcDeclarationSemantic(utd);
+ sc2.pop();
+ }
+
+ version (none)
+ {
+ // We're going to need ModuleInfo even if the unit tests are not
+ // compiled in, because other modules may import this module and refer
+ // to this ModuleInfo.
+ // (This doesn't make sense to me?)
+ Module m = utd.getModule();
+ if (!m)
+ m = sc._module;
+ if (m)
+ {
+ //printf("module3 %s needs moduleinfo\n", m.toChars());
+ m.needmoduleinfo = 1;
+ }
+ }
+ }
+
+ override void visit(NewDeclaration nd)
+ {
+ //printf("NewDeclaration::semantic()\n");
+ if (nd.semanticRun >= PASS.semanticdone)
+ return;
+ if (!nd.type)
+ nd.type = new TypeFunction(ParameterList(), Type.tvoid.pointerTo(), LINK.d, nd.storage_class);
+
+ funcDeclarationSemantic(nd);
+ }
+
+ override void visit(StructDeclaration sd)
+ {
+ //printf("StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
+
+ //static int count; if (++count == 20) assert(0);
+
+ if (sd.semanticRun >= PASS.semanticdone)
+ return;
+ int errors = global.errors;
+
+ //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, sd.toPrettyChars(), sd.sizeok);
+ Scope* scx = null;
+ if (sd._scope)
+ {
+ sc = sd._scope;
+ scx = sd._scope; // save so we don't make redundant copies
+ sd._scope = null;
+ }
+
+ if (!sd.parent)
+ {
+ assert(sc.parent && sc.func);
+ sd.parent = sc.parent;
+ }
+ assert(sd.parent && !sd.isAnonymous());
+
+ if (sd.errors)
+ sd.type = Type.terror;
+ if (sd.semanticRun == PASS.init)
+ sd.type = sd.type.addSTC(sc.stc | sd.storage_class);
+ sd.type = sd.type.typeSemantic(sd.loc, sc);
+ if (auto ts = sd.type.isTypeStruct())
+ if (ts.sym != sd)
+ {
+ auto ti = ts.sym.isInstantiated();
+ if (ti && isError(ti))
+ ts.sym = sd;
+ }
+
+ // Ungag errors when not speculative
+ Ungag ungag = sd.ungagSpeculative();
+
+ if (sd.semanticRun == PASS.init)
+ {
+ sd.visibility = sc.visibility;
+
+ sd.alignment = sc.alignment();
+
+ sd.storage_class |= sc.stc;
+ if (sd.storage_class & STC.abstract_)
+ sd.error("structs, unions cannot be `abstract`");
+
+ sd.userAttribDecl = sc.userAttribDecl;
+
+ if (sc.linkage == LINK.cpp)
+ sd.classKind = ClassKind.cpp;
+ else if (sc.linkage == LINK.c)
+ sd.classKind = ClassKind.c;
+ sd.cppnamespace = sc.namespace;
+ sd.cppmangle = sc.cppmangle;
+ }
+ else if (sd.symtab && !scx)
+ return;
+
+ sd.semanticRun = PASS.semantic;
+ UserAttributeDeclaration.checkGNUABITag(sd, sc.linkage);
+
+ if (!sd.members) // if opaque declaration
+ {
+ sd.semanticRun = PASS.semanticdone;
+ return;
+ }
+ if (!sd.symtab)
+ {
+ sd.symtab = new DsymbolTable();
+
+ sd.members.foreachDsymbol( s => s.addMember(sc, sd) );
+ }
+
+ auto sc2 = sd.newScope(sc);
+
+ /* Set scope so if there are forward references, we still might be able to
+ * resolve individual members like enums.
+ */
+ sd.members.foreachDsymbol( s => s.setScope(sc2) );
+ sd.members.foreachDsymbol( s => s.importAll(sc2) );
+ sd.members.foreachDsymbol( (s) { s.dsymbolSemantic(sc2); sd.errors |= s.errors; } );
+
+ if (sd.errors)
+ sd.type = Type.terror;
+
+ if (!sd.determineFields())
+ {
+ if (sd.type.ty != Terror)
+ {
+ sd.error(sd.loc, "circular or forward reference");
+ sd.errors = true;
+ sd.type = Type.terror;
+ }
+
+ sc2.pop();
+ sd.semanticRun = PASS.semanticdone;
+ return;
+ }
+ /* Following special member functions creation needs semantic analysis
+ * completion of sub-structs in each field types. For example, buildDtor
+ * needs to check existence of elaborate dtor in type of each fields.
+ * See the case in compilable/test14838.d
+ */
+ foreach (v; sd.fields)
+ {
+ Type tb = v.type.baseElemOf();
+ if (tb.ty != Tstruct)
+ continue;
+ auto sdec = (cast(TypeStruct)tb).sym;
+ if (sdec.semanticRun >= PASS.semanticdone)
+ continue;
+
+ sc2.pop();
+
+ //printf("\tdeferring %s\n", toChars());
+ return deferDsymbolSemantic(sd, scx);
+ }
+
+ /* Look for special member functions.
+ */
+ sd.disableNew = sd.search(Loc.initial, Id.classNew) !is null;
+
+ // Look for the constructor
+ sd.ctor = sd.searchCtor();
+
+ sd.dtor = buildDtor(sd, sc2);
+ sd.tidtor = buildExternDDtor(sd, sc2);
+ sd.hasCopyCtor = buildCopyCtor(sd, sc2);
+ sd.postblit = buildPostBlit(sd, sc2);
+
+ buildOpAssign(sd, sc2);
+ buildOpEquals(sd, sc2);
+
+ if (global.params.useTypeInfo && Type.dtypeinfo) // these functions are used for TypeInfo
+ {
+ sd.xeq = buildXopEquals(sd, sc2);
+ sd.xcmp = buildXopCmp(sd, sc2);
+ sd.xhash = buildXtoHash(sd, sc2);
+ }
+
+ sd.inv = buildInv(sd, sc2);
+
+ Module.dprogress++;
+ sd.semanticRun = PASS.semanticdone;
+ //printf("-StructDeclaration::semantic(this=%p, '%s')\n", sd, sd.toChars());
+
+ sc2.pop();
+
+ if (sd.ctor)
+ {
+ Dsymbol scall = sd.search(Loc.initial, Id.call);
+ if (scall)
+ {
+ uint xerrors = global.startGagging();
+ sc = sc.push();
+ sc.tinst = null;
+ sc.minst = null;
+ auto fcall = resolveFuncCall(sd.loc, sc, scall, null, null, null, FuncResolveFlag.quiet);
+ sc = sc.pop();
+ global.endGagging(xerrors);
+
+ if (fcall && fcall.isStatic())
+ {
+ sd.error(fcall.loc, "`static opCall` is hidden by constructors and can never be called");
+ errorSupplemental(fcall.loc, "Please use a factory method instead, or replace all constructors with `static opCall`.");
+ }
+ }
+ }
+
+ if (sd.type.ty == Tstruct && (cast(TypeStruct)sd.type).sym != sd)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=19024
+ StructDeclaration sym = (cast(TypeStruct)sd.type).sym;
+ version (none)
+ {
+ printf("this = %p %s\n", sd, sd.toChars());
+ printf("type = %d sym = %p, %s\n", sd.type.ty, sym, sym.toPrettyChars());
+ }
+ sd.error("already exists at %s. Perhaps in another function with the same name?", sym.loc.toChars());
+ }
+
+ if (global.errors != errors)
+ {
+ // The type is no good.
+ sd.type = Type.terror;
+ sd.errors = true;
+ if (sd.deferred)
+ sd.deferred.errors = true;
+ }
+
+ if (sd.deferred && !global.gag)
+ {
+ sd.deferred.semantic2(sc);
+ sd.deferred.semantic3(sc);
+ }
+ }
+
+ void interfaceSemantic(ClassDeclaration cd)
+ {
+ cd.vtblInterfaces = new BaseClasses();
+ cd.vtblInterfaces.reserve(cd.interfaces.length);
+ foreach (b; cd.interfaces)
+ {
+ cd.vtblInterfaces.push(b);
+ b.copyBaseInterfaces(cd.vtblInterfaces);
+ }
+ }
+
+ override void visit(ClassDeclaration cldec)
+ {
+ //printf("ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", cldec.toChars(), cldec.type, cldec.sizeok, this);
+ //printf("\tparent = %p, '%s'\n", sc.parent, sc.parent ? sc.parent.toChars() : "");
+ //printf("sc.stc = %x\n", sc.stc);
+
+ //{ static int n; if (++n == 20) *(char*)0=0; }
+
+ if (cldec.semanticRun >= PASS.semanticdone)
+ return;
+ int errors = global.errors;
+
+ //printf("+ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
+
+ Scope* scx = null;
+ if (cldec._scope)
+ {
+ sc = cldec._scope;
+ scx = cldec._scope; // save so we don't make redundant copies
+ cldec._scope = null;
+ }
+
+ if (!cldec.parent)
+ {
+ assert(sc.parent);
+ cldec.parent = sc.parent;
+ }
+
+ if (cldec.errors)
+ cldec.type = Type.terror;
+ cldec.type = cldec.type.typeSemantic(cldec.loc, sc);
+ if (auto tc = cldec.type.isTypeClass())
+ if (tc.sym != cldec)
+ {
+ auto ti = tc.sym.isInstantiated();
+ if (ti && isError(ti))
+ tc.sym = cldec;
+ }
+
+ // Ungag errors when not speculative
+ Ungag ungag = cldec.ungagSpeculative();
+
+ if (cldec.semanticRun == PASS.init)
+ {
+ cldec.visibility = sc.visibility;
+
+ cldec.storage_class |= sc.stc;
+ if (cldec.storage_class & STC.auto_)
+ cldec.error("storage class `auto` is invalid when declaring a class, did you mean to use `scope`?");
+ if (cldec.storage_class & STC.scope_)
+ cldec.stack = true;
+ if (cldec.storage_class & STC.abstract_)
+ cldec.isabstract = ThreeState.yes;
+
+ cldec.userAttribDecl = sc.userAttribDecl;
+
+ if (sc.linkage == LINK.cpp)
+ cldec.classKind = ClassKind.cpp;
+ cldec.cppnamespace = sc.namespace;
+ cldec.cppmangle = sc.cppmangle;
+ if (sc.linkage == LINK.objc)
+ objc.setObjc(cldec);
+ }
+ else if (cldec.symtab && !scx)
+ {
+ return;
+ }
+ cldec.semanticRun = PASS.semantic;
+ UserAttributeDeclaration.checkGNUABITag(cldec, sc.linkage);
+
+ if (cldec.baseok < Baseok.done)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=12078
+ * https://issues.dlang.org/show_bug.cgi?id=12143
+ * https://issues.dlang.org/show_bug.cgi?id=15733
+ * While resolving base classes and interfaces, a base may refer
+ * the member of this derived class. In that time, if all bases of
+ * this class can be determined, we can go forward the semantc process
+ * beyond the Lancestorsdone. To do the recursive semantic analysis,
+ * temporarily set and unset `_scope` around exp().
+ */
+ T resolveBase(T)(lazy T exp)
+ {
+ if (!scx)
+ {
+ scx = sc.copy();
+ scx.setNoFree();
+ }
+ static if (!is(T == void))
+ {
+ cldec._scope = scx;
+ auto r = exp();
+ cldec._scope = null;
+ return r;
+ }
+ else
+ {
+ cldec._scope = scx;
+ exp();
+ cldec._scope = null;
+ }
+ }
+
+ cldec.baseok = Baseok.start;
+
+ // Expand any tuples in baseclasses[]
+ for (size_t i = 0; i < cldec.baseclasses.dim;)
+ {
+ auto b = (*cldec.baseclasses)[i];
+ b.type = resolveBase(b.type.typeSemantic(cldec.loc, sc));
+
+ Type tb = b.type.toBasetype();
+ if (auto tup = tb.isTypeTuple())
+ {
+ cldec.baseclasses.remove(i);
+ size_t dim = Parameter.dim(tup.arguments);
+ for (size_t j = 0; j < dim; j++)
+ {
+ Parameter arg = Parameter.getNth(tup.arguments, j);
+ b = new BaseClass(arg.type);
+ cldec.baseclasses.insert(i + j, b);
+ }
+ }
+ else
+ i++;
+ }
+
+ if (cldec.baseok >= Baseok.done)
+ {
+ //printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun);
+ if (cldec.semanticRun >= PASS.semanticdone)
+ return;
+ goto Lancestorsdone;
+ }
+
+ // See if there's a base class as first in baseclasses[]
+ if (cldec.baseclasses.dim)
+ {
+ BaseClass* b = (*cldec.baseclasses)[0];
+ Type tb = b.type.toBasetype();
+ TypeClass tc = tb.isTypeClass();
+ if (!tc)
+ {
+ if (b.type != Type.terror)
+ cldec.error("base type must be `class` or `interface`, not `%s`", b.type.toChars());
+ cldec.baseclasses.remove(0);
+ goto L7;
+ }
+ if (tc.sym.isDeprecated())
+ {
+ if (!cldec.isDeprecated())
+ {
+ // Deriving from deprecated class makes this one deprecated too
+ cldec.setDeprecated();
+ tc.checkDeprecated(cldec.loc, sc);
+ }
+ }
+ if (tc.sym.isInterfaceDeclaration())
+ goto L7;
+
+ for (ClassDeclaration cdb = tc.sym; cdb; cdb = cdb.baseClass)
+ {
+ if (cdb == cldec)
+ {
+ cldec.error("circular inheritance");
+ cldec.baseclasses.remove(0);
+ goto L7;
+ }
+ }
+
+ /* https://issues.dlang.org/show_bug.cgi?id=11034
+ * Class inheritance hierarchy
+ * and instance size of each classes are orthogonal information.
+ * Therefore, even if tc.sym.sizeof == Sizeok.none,
+ * we need to set baseClass field for class covariance check.
+ */
+ cldec.baseClass = tc.sym;
+ b.sym = cldec.baseClass;
+
+ if (tc.sym.baseok < Baseok.done)
+ resolveBase(tc.sym.dsymbolSemantic(null)); // Try to resolve forward reference
+ if (tc.sym.baseok < Baseok.done)
+ {
+ //printf("\ttry later, forward reference of base class %s\n", tc.sym.toChars());
+ if (tc.sym._scope)
+ Module.addDeferredSemantic(tc.sym);
+ cldec.baseok = Baseok.none;
+ }
+ L7:
+ }
+
+ // Treat the remaining entries in baseclasses as interfaces
+ // Check for errors, handle forward references
+ int multiClassError = cldec.baseClass is null ? 0 : 1;
+
+ BCLoop:
+ for (size_t i = (cldec.baseClass ? 1 : 0); i < cldec.baseclasses.dim;)
+ {
+ BaseClass* b = (*cldec.baseclasses)[i];
+ Type tb = b.type.toBasetype();
+ TypeClass tc = tb.isTypeClass();
+ if (!tc || !tc.sym.isInterfaceDeclaration())
+ {
+ // It's a class
+ if (tc)
+ {
+ if (multiClassError == 0)
+ {
+ error(cldec.loc,"`%s`: base class must be specified first, " ~
+ "before any interfaces.", cldec.toPrettyChars());
+ multiClassError += 1;
+ }
+ else if (multiClassError >= 1)
+ {
+ if(multiClassError == 1)
+ error(cldec.loc,"`%s`: multiple class inheritance is not supported." ~
+ " Use multiple interface inheritance and/or composition.", cldec.toPrettyChars());
+ multiClassError += 1;
+
+ if (tc.sym.fields.dim)
+ errorSupplemental(cldec.loc,"`%s` has fields, consider making it a member of `%s`",
+ b.type.toChars(), cldec.type.toChars());
+ else
+ errorSupplemental(cldec.loc,"`%s` has no fields, consider making it an `interface`",
+ b.type.toChars());
+ }
+ }
+ // It's something else: e.g. `int` in `class Foo : Bar, int { ... }`
+ else if (b.type != Type.terror)
+ {
+ error(cldec.loc,"`%s`: base type must be `interface`, not `%s`",
+ cldec.toPrettyChars(), b.type.toChars());
+ }
+ cldec.baseclasses.remove(i);
+ continue;
+ }
+
+ // Check for duplicate interfaces
+ for (size_t j = (cldec.baseClass ? 1 : 0); j < i; j++)
+ {
+ BaseClass* b2 = (*cldec.baseclasses)[j];
+ if (b2.sym == tc.sym)
+ {
+ cldec.error("inherits from duplicate interface `%s`", b2.sym.toChars());
+ cldec.baseclasses.remove(i);
+ continue BCLoop;
+ }
+ }
+ if (tc.sym.isDeprecated())
+ {
+ if (!cldec.isDeprecated())
+ {
+ // Deriving from deprecated class makes this one deprecated too
+ cldec.setDeprecated();
+ tc.checkDeprecated(cldec.loc, sc);
+ }
+ }
+
+ b.sym = tc.sym;
+
+ if (tc.sym.baseok < Baseok.done)
+ resolveBase(tc.sym.dsymbolSemantic(null)); // Try to resolve forward reference
+ if (tc.sym.baseok < Baseok.done)
+ {
+ //printf("\ttry later, forward reference of base %s\n", tc.sym.toChars());
+ if (tc.sym._scope)
+ Module.addDeferredSemantic(tc.sym);
+ cldec.baseok = Baseok.none;
+ }
+ i++;
+ }
+ if (cldec.baseok == Baseok.none)
+ {
+ // Forward referencee of one or more bases, try again later
+ //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars());
+ return deferDsymbolSemantic(cldec, scx);
+ }
+ cldec.baseok = Baseok.done;
+
+ if (cldec.classKind == ClassKind.objc || (cldec.baseClass && cldec.baseClass.classKind == ClassKind.objc))
+ cldec.classKind = ClassKind.objc; // Objective-C classes do not inherit from Object
+
+ // If no base class, and this is not an Object, use Object as base class
+ if (!cldec.baseClass && cldec.ident != Id.Object && cldec.object && cldec.classKind == ClassKind.d)
+ {
+ void badObjectDotD()
+ {
+ cldec.error("missing or corrupt object.d");
+ fatal();
+ }
+
+ if (!cldec.object || cldec.object.errors)
+ badObjectDotD();
+
+ Type t = cldec.object.type;
+ t = t.typeSemantic(cldec.loc, sc).toBasetype();
+ if (t.ty == Terror)
+ badObjectDotD();
+ TypeClass tc = t.isTypeClass();
+ assert(tc);
+
+ auto b = new BaseClass(tc);
+ cldec.baseclasses.shift(b);
+
+ cldec.baseClass = tc.sym;
+ assert(!cldec.baseClass.isInterfaceDeclaration());
+ b.sym = cldec.baseClass;
+ }
+ if (cldec.baseClass)
+ {
+ if (cldec.baseClass.storage_class & STC.final_)
+ cldec.error("cannot inherit from class `%s` because it is `final`", cldec.baseClass.toChars());
+
+ // Inherit properties from base class
+ if (cldec.baseClass.isCOMclass())
+ cldec.com = true;
+ if (cldec.baseClass.isCPPclass())
+ cldec.classKind = ClassKind.cpp;
+ if (cldec.baseClass.stack)
+ cldec.stack = true;
+ cldec.enclosing = cldec.baseClass.enclosing;
+ cldec.storage_class |= cldec.baseClass.storage_class & STC.TYPECTOR;
+ }
+
+ cldec.interfaces = cldec.baseclasses.tdata()[(cldec.baseClass ? 1 : 0) .. cldec.baseclasses.dim];
+ foreach (b; cldec.interfaces)
+ {
+ // If this is an interface, and it derives from a COM interface,
+ // then this is a COM interface too.
+ if (b.sym.isCOMinterface())
+ cldec.com = true;
+ if (cldec.classKind == ClassKind.cpp && !b.sym.isCPPinterface())
+ {
+ error(cldec.loc, "C++ class `%s` cannot implement D interface `%s`",
+ cldec.toPrettyChars(), b.sym.toPrettyChars());
+ }
+ }
+ interfaceSemantic(cldec);
+ }
+ Lancestorsdone:
+ //printf("\tClassDeclaration.dsymbolSemantic(%s) baseok = %d\n", toChars(), baseok);
+
+ if (!cldec.members) // if opaque declaration
+ {
+ cldec.semanticRun = PASS.semanticdone;
+ return;
+ }
+ if (!cldec.symtab)
+ {
+ cldec.symtab = new DsymbolTable();
+
+ /* https://issues.dlang.org/show_bug.cgi?id=12152
+ * The semantic analysis of base classes should be finished
+ * before the members semantic analysis of this class, in order to determine
+ * vtbl in this class. However if a base class refers the member of this class,
+ * it can be resolved as a normal forward reference.
+ * Call addMember() and setScope() to make this class members visible from the base classes.
+ */
+ cldec.members.foreachDsymbol( s => s.addMember(sc, cldec) );
+
+ auto sc2 = cldec.newScope(sc);
+
+ /* Set scope so if there are forward references, we still might be able to
+ * resolve individual members like enums.
+ */
+ cldec.members.foreachDsymbol( s => s.setScope(sc2) );
+
+ sc2.pop();
+ }
+
+ for (size_t i = 0; i < cldec.baseclasses.dim; i++)
+ {
+ BaseClass* b = (*cldec.baseclasses)[i];
+ Type tb = b.type.toBasetype();
+ TypeClass tc = tb.isTypeClass();
+ if (tc.sym.semanticRun < PASS.semanticdone)
+ {
+ // Forward referencee of one or more bases, try again later
+ if (tc.sym._scope)
+ Module.addDeferredSemantic(tc.sym);
+ //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, toChars());
+ return deferDsymbolSemantic(cldec, scx);
+ }
+ }
+
+ if (cldec.baseok == Baseok.done)
+ {
+ cldec.baseok = Baseok.semanticdone;
+ objc.setMetaclass(cldec, sc);
+
+ // initialize vtbl
+ if (cldec.baseClass)
+ {
+ if (cldec.classKind == ClassKind.cpp && cldec.baseClass.vtbl.dim == 0)
+ {
+ cldec.error("C++ base class `%s` needs at least one virtual function", cldec.baseClass.toChars());
+ }
+
+ // Copy vtbl[] from base class
+ cldec.vtbl.setDim(cldec.baseClass.vtbl.dim);
+ memcpy(cldec.vtbl.tdata(), cldec.baseClass.vtbl.tdata(), (void*).sizeof * cldec.vtbl.dim);
+
+ cldec.vthis = cldec.baseClass.vthis;
+ cldec.vthis2 = cldec.baseClass.vthis2;
+ }
+ else
+ {
+ // No base class, so this is the root of the class hierarchy
+ cldec.vtbl.setDim(0);
+ if (cldec.vtblOffset())
+ cldec.vtbl.push(cldec); // leave room for classinfo as first member
+ }
+
+ /* If this is a nested class, add the hidden 'this'
+ * member which is a pointer to the enclosing scope.
+ */
+ if (cldec.vthis) // if inheriting from nested class
+ {
+ // Use the base class's 'this' member
+ if (cldec.storage_class & STC.static_)
+ cldec.error("static class cannot inherit from nested class `%s`", cldec.baseClass.toChars());
+ if (cldec.toParentLocal() != cldec.baseClass.toParentLocal() &&
+ (!cldec.toParentLocal() ||
+ !cldec.baseClass.toParentLocal().getType() ||
+ !cldec.baseClass.toParentLocal().getType().isBaseOf(cldec.toParentLocal().getType(), null)))
+ {
+ if (cldec.toParentLocal())
+ {
+ cldec.error("is nested within `%s`, but super class `%s` is nested within `%s`",
+ cldec.toParentLocal().toChars(),
+ cldec.baseClass.toChars(),
+ cldec.baseClass.toParentLocal().toChars());
+ }
+ else
+ {
+ cldec.error("is not nested, but super class `%s` is nested within `%s`",
+ cldec.baseClass.toChars(),
+ cldec.baseClass.toParentLocal().toChars());
+ }
+ cldec.enclosing = null;
+ }
+ if (cldec.vthis2)
+ {
+ if (cldec.toParent2() != cldec.baseClass.toParent2() &&
+ (!cldec.toParent2() ||
+ !cldec.baseClass.toParent2().getType() ||
+ !cldec.baseClass.toParent2().getType().isBaseOf(cldec.toParent2().getType(), null)))
+ {
+ if (cldec.toParent2() && cldec.toParent2() != cldec.toParentLocal())
+ {
+ cldec.error("needs the frame pointer of `%s`, but super class `%s` needs the frame pointer of `%s`",
+ cldec.toParent2().toChars(),
+ cldec.baseClass.toChars(),
+ cldec.baseClass.toParent2().toChars());
+ }
+ else
+ {
+ cldec.error("doesn't need a frame pointer, but super class `%s` needs the frame pointer of `%s`",
+ cldec.baseClass.toChars(),
+ cldec.baseClass.toParent2().toChars());
+ }
+ }
+ }
+ else
+ cldec.makeNested2();
+ }
+ else
+ cldec.makeNested();
+ }
+
+ auto sc2 = cldec.newScope(sc);
+
+ cldec.members.foreachDsymbol( s => s.importAll(sc2) );
+
+ // Note that members.dim can grow due to tuple expansion during semantic()
+ cldec.members.foreachDsymbol( s => s.dsymbolSemantic(sc2) );
+
+ if (!cldec.determineFields())
+ {
+ assert(cldec.type == Type.terror);
+ sc2.pop();
+ return;
+ }
+ /* Following special member functions creation needs semantic analysis
+ * completion of sub-structs in each field types.
+ */
+ foreach (v; cldec.fields)
+ {
+ Type tb = v.type.baseElemOf();
+ if (tb.ty != Tstruct)
+ continue;
+ auto sd = (cast(TypeStruct)tb).sym;
+ if (sd.semanticRun >= PASS.semanticdone)
+ continue;
+
+ sc2.pop();
+
+ //printf("\tdeferring %s\n", toChars());
+ return deferDsymbolSemantic(cldec, scx);
+ }
+
+ /* Look for special member functions.
+ * They must be in this class, not in a base class.
+ */
+ // Can be in base class
+ cldec.disableNew = cldec.search(Loc.initial, Id.classNew) !is null;
+
+ // Look for the constructor
+ cldec.ctor = cldec.searchCtor();
+
+ if (!cldec.ctor && cldec.noDefaultCtor)
+ {
+ // A class object is always created by constructor, so this check is legitimate.
+ foreach (v; cldec.fields)
+ {
+ if (v.storage_class & STC.nodefaultctor)
+ error(v.loc, "field `%s` must be initialized in constructor", v.toChars());
+ }
+ }
+
+ // If this class has no constructor, but base class has a default
+ // ctor, create a constructor:
+ // this() { }
+ if (!cldec.ctor && cldec.baseClass && cldec.baseClass.ctor)
+ {
+ auto fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type, null, FuncResolveFlag.quiet);
+ if (!fd) // try shared base ctor instead
+ fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type.sharedOf, null, FuncResolveFlag.quiet);
+ if (fd && !fd.errors)
+ {
+ //printf("Creating default this(){} for class %s\n", toChars());
+ auto btf = fd.type.toTypeFunction();
+ auto tf = new TypeFunction(ParameterList(), null, LINK.d, fd.storage_class);
+ tf.mod = btf.mod;
+ // Don't copy @safe, ... from the base class constructor and let it be inferred instead
+ // This is required if other lowerings add code to the generated constructor which
+ // is less strict (e.g. `preview=dtorfields` might introduce a call to a less qualified dtor)
+
+ auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf);
+ ctor.storage_class |= STC.inference;
+ ctor.generated = true;
+ ctor.fbody = new CompoundStatement(Loc.initial, new Statements());
+
+ cldec.members.push(ctor);
+ ctor.addMember(sc, cldec);
+ ctor.dsymbolSemantic(sc2);
+
+ cldec.ctor = ctor;
+ cldec.defaultCtor = ctor;
+ }
+ else
+ {
+ cldec.error("cannot implicitly generate a default constructor when base class `%s` is missing a default constructor",
+ cldec.baseClass.toPrettyChars());
+ }
+ }
+
+ cldec.dtor = buildDtor(cldec, sc2);
+ cldec.tidtor = buildExternDDtor(cldec, sc2);
+
+ if (cldec.classKind == ClassKind.cpp && cldec.cppDtorVtblIndex != -1)
+ {
+ // now we've built the aggregate destructor, we'll make it virtual and assign it to the reserved vtable slot
+ cldec.dtor.vtblIndex = cldec.cppDtorVtblIndex;
+ cldec.vtbl[cldec.cppDtorVtblIndex] = cldec.dtor;
+
+ if (target.cpp.twoDtorInVtable)
+ {
+ // TODO: create a C++ compatible deleting destructor (call out to `operator delete`)
+ // for the moment, we'll call the non-deleting destructor and leak
+ cldec.vtbl[cldec.cppDtorVtblIndex + 1] = cldec.dtor;
+ }
+ }
+
+ if (auto f = hasIdentityOpAssign(cldec, sc2))
+ {
+ if (!(f.storage_class & STC.disable))
+ cldec.error(f.loc, "identity assignment operator overload is illegal");
+ }
+
+ cldec.inv = buildInv(cldec, sc2);
+
+ Module.dprogress++;
+ cldec.semanticRun = PASS.semanticdone;
+ //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type);
+
+ sc2.pop();
+
+ /* isAbstract() is undecidable in some cases because of circular dependencies.
+ * Now that semantic is finished, get a definitive result, and error if it is not the same.
+ */
+ if (cldec.isabstract != ThreeState.none) // if evaluated it before completion
+ {
+ const isabstractsave = cldec.isabstract;
+ cldec.isabstract = ThreeState.none;
+ cldec.isAbstract(); // recalculate
+ if (cldec.isabstract != isabstractsave)
+ {
+ cldec.error("cannot infer `abstract` attribute due to circular dependencies");
+ }
+ }
+
+ if (cldec.type.ty == Tclass && (cast(TypeClass)cldec.type).sym != cldec)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=17492
+ ClassDeclaration cd = (cast(TypeClass)cldec.type).sym;
+ version (none)
+ {
+ printf("this = %p %s\n", cldec, cldec.toPrettyChars());
+ printf("type = %d sym = %p, %s\n", cldec.type.ty, cd, cd.toPrettyChars());
+ }
+ cldec.error("already exists at %s. Perhaps in another function with the same name?", cd.loc.toChars());
+ }
+
+ if (global.errors != errors)
+ {
+ // The type is no good.
+ cldec.type = Type.terror;
+ cldec.errors = true;
+ if (cldec.deferred)
+ cldec.deferred.errors = true;
+ }
+
+ // Verify fields of a synchronized class are not public
+ if (cldec.storage_class & STC.synchronized_)
+ {
+ foreach (vd; cldec.fields)
+ {
+ if (!vd.isThisDeclaration() &&
+ vd.visible() >= Visibility(Visibility.Kind.public_))
+ {
+ vd.error("Field members of a `synchronized` class cannot be `%s`",
+ visibilityToChars(vd.visible().kind));
+ }
+ }
+ }
+
+ if (cldec.deferred && !global.gag)
+ {
+ cldec.deferred.semantic2(sc);
+ cldec.deferred.semantic3(sc);
+ }
+ //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
+
+ // @@@DEPRECATED@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+ // Deprecated in 2.087
+ // Make an error in 2.091
+ // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036
+ if (0 && // deprecation disabled for now to accommodate existing extensive use
+ cldec.storage_class & STC.scope_)
+ deprecation(cldec.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site.");
+ }
+
+ override void visit(InterfaceDeclaration idec)
+ {
+ /// Returns: `true` is this is an anonymous Objective-C metaclass
+ static bool isAnonymousMetaclass(InterfaceDeclaration idec)
+ {
+ return idec.classKind == ClassKind.objc &&
+ idec.objc.isMeta &&
+ idec.isAnonymous;
+ }
+
+ //printf("InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type);
+ if (idec.semanticRun >= PASS.semanticdone)
+ return;
+ int errors = global.errors;
+
+ //printf("+InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type);
+
+ Scope* scx = null;
+ if (idec._scope)
+ {
+ sc = idec._scope;
+ scx = idec._scope; // save so we don't make redundant copies
+ idec._scope = null;
+ }
+
+ if (!idec.parent)
+ {
+ assert(sc.parent && sc.func);
+ idec.parent = sc.parent;
+ }
+ // Objective-C metaclasses are anonymous
+ assert(idec.parent && !idec.isAnonymous || isAnonymousMetaclass(idec));
+
+ if (idec.errors)
+ idec.type = Type.terror;
+ idec.type = idec.type.typeSemantic(idec.loc, sc);
+ if (idec.type.ty == Tclass && (cast(TypeClass)idec.type).sym != idec)
+ {
+ auto ti = (cast(TypeClass)idec.type).sym.isInstantiated();
+ if (ti && isError(ti))
+ (cast(TypeClass)idec.type).sym = idec;
+ }
+
+ // Ungag errors when not speculative
+ Ungag ungag = idec.ungagSpeculative();
+
+ if (idec.semanticRun == PASS.init)
+ {
+ idec.visibility = sc.visibility;
+
+ idec.storage_class |= sc.stc;
+ idec.userAttribDecl = sc.userAttribDecl;
+ }
+ else if (idec.symtab)
+ {
+ if (idec.sizeok == Sizeok.done || !scx)
+ {
+ idec.semanticRun = PASS.semanticdone;
+ return;
+ }
+ }
+ idec.semanticRun = PASS.semantic;
+
+ if (idec.baseok < Baseok.done)
+ {
+ T resolveBase(T)(lazy T exp)
+ {
+ if (!scx)
+ {
+ scx = sc.copy();
+ scx.setNoFree();
+ }
+ static if (!is(T == void))
+ {
+ idec._scope = scx;
+ auto r = exp();
+ idec._scope = null;
+ return r;
+ }
+ else
+ {
+ idec._scope = scx;
+ exp();
+ idec._scope = null;
+ }
+ }
+
+ idec.baseok = Baseok.start;
+
+ // Expand any tuples in baseclasses[]
+ for (size_t i = 0; i < idec.baseclasses.dim;)
+ {
+ auto b = (*idec.baseclasses)[i];
+ b.type = resolveBase(b.type.typeSemantic(idec.loc, sc));
+
+ Type tb = b.type.toBasetype();
+ if (auto tup = tb.isTypeTuple())
+ {
+ idec.baseclasses.remove(i);
+ size_t dim = Parameter.dim(tup.arguments);
+ for (size_t j = 0; j < dim; j++)
+ {
+ Parameter arg = Parameter.getNth(tup.arguments, j);
+ b = new BaseClass(arg.type);
+ idec.baseclasses.insert(i + j, b);
+ }
+ }
+ else
+ i++;
+ }
+
+ if (idec.baseok >= Baseok.done)
+ {
+ //printf("%s already semantic analyzed, semanticRun = %d\n", toChars(), semanticRun);
+ if (idec.semanticRun >= PASS.semanticdone)
+ return;
+ goto Lancestorsdone;
+ }
+
+ if (!idec.baseclasses.dim && sc.linkage == LINK.cpp)
+ idec.classKind = ClassKind.cpp;
+ idec.cppnamespace = sc.namespace;
+ UserAttributeDeclaration.checkGNUABITag(idec, sc.linkage);
+
+ if (sc.linkage == LINK.objc)
+ objc.setObjc(idec);
+
+ // Check for errors, handle forward references
+ BCLoop:
+ for (size_t i = 0; i < idec.baseclasses.dim;)
+ {
+ BaseClass* b = (*idec.baseclasses)[i];
+ Type tb = b.type.toBasetype();
+ TypeClass tc = (tb.ty == Tclass) ? cast(TypeClass)tb : null;
+ if (!tc || !tc.sym.isInterfaceDeclaration())
+ {
+ if (b.type != Type.terror)
+ idec.error("base type must be `interface`, not `%s`", b.type.toChars());
+ idec.baseclasses.remove(i);
+ continue;
+ }
+
+ // Check for duplicate interfaces
+ for (size_t j = 0; j < i; j++)
+ {
+ BaseClass* b2 = (*idec.baseclasses)[j];
+ if (b2.sym == tc.sym)
+ {
+ idec.error("inherits from duplicate interface `%s`", b2.sym.toChars());
+ idec.baseclasses.remove(i);
+ continue BCLoop;
+ }
+ }
+ if (tc.sym == idec || idec.isBaseOf2(tc.sym))
+ {
+ idec.error("circular inheritance of interface");
+ idec.baseclasses.remove(i);
+ continue;
+ }
+ if (tc.sym.isDeprecated())
+ {
+ if (!idec.isDeprecated())
+ {
+ // Deriving from deprecated interface makes this one deprecated too
+ idec.setDeprecated();
+ tc.checkDeprecated(idec.loc, sc);
+ }
+ }
+
+ b.sym = tc.sym;
+
+ if (tc.sym.baseok < Baseok.done)
+ resolveBase(tc.sym.dsymbolSemantic(null)); // Try to resolve forward reference
+ if (tc.sym.baseok < Baseok.done)
+ {
+ //printf("\ttry later, forward reference of base %s\n", tc.sym.toChars());
+ if (tc.sym._scope)
+ Module.addDeferredSemantic(tc.sym);
+ idec.baseok = Baseok.none;
+ }
+ i++;
+ }
+ if (idec.baseok == Baseok.none)
+ {
+ // Forward referencee of one or more bases, try again later
+ return deferDsymbolSemantic(idec, scx);
+ }
+ idec.baseok = Baseok.done;
+
+ idec.interfaces = idec.baseclasses.tdata()[0 .. idec.baseclasses.dim];
+ foreach (b; idec.interfaces)
+ {
+ // If this is an interface, and it derives from a COM interface,
+ // then this is a COM interface too.
+ if (b.sym.isCOMinterface())
+ idec.com = true;
+ if (b.sym.isCPPinterface())
+ idec.classKind = ClassKind.cpp;
+ }
+
+ interfaceSemantic(idec);
+ }
+ Lancestorsdone:
+
+ if (!idec.members) // if opaque declaration
+ {
+ idec.semanticRun = PASS.semanticdone;
+ return;
+ }
+ if (!idec.symtab)
+ idec.symtab = new DsymbolTable();
+
+ for (size_t i = 0; i < idec.baseclasses.dim; i++)
+ {
+ BaseClass* b = (*idec.baseclasses)[i];
+ Type tb = b.type.toBasetype();
+ TypeClass tc = tb.isTypeClass();
+ if (tc.sym.semanticRun < PASS.semanticdone)
+ {
+ // Forward referencee of one or more bases, try again later
+ if (tc.sym._scope)
+ Module.addDeferredSemantic(tc.sym);
+ return deferDsymbolSemantic(idec, scx);
+ }
+ }
+
+ if (idec.baseok == Baseok.done)
+ {
+ idec.baseok = Baseok.semanticdone;
+ objc.setMetaclass(idec, sc);
+
+ // initialize vtbl
+ if (idec.vtblOffset())
+ idec.vtbl.push(idec); // leave room at vtbl[0] for classinfo
+
+ // Cat together the vtbl[]'s from base interfaces
+ foreach (i, b; idec.interfaces)
+ {
+ // Skip if b has already appeared
+ for (size_t k = 0; k < i; k++)
+ {
+ if (b == idec.interfaces[k])
+ goto Lcontinue;
+ }
+
+ // Copy vtbl[] from base class
+ if (b.sym.vtblOffset())
+ {
+ size_t d = b.sym.vtbl.dim;
+ if (d > 1)
+ {
+ idec.vtbl.pushSlice(b.sym.vtbl[1 .. d]);
+ }
+ }
+ else
+ {
+ idec.vtbl.append(&b.sym.vtbl);
+ }
+
+ Lcontinue:
+ }
+ }
+
+ idec.members.foreachDsymbol( s => s.addMember(sc, idec) );
+
+ auto sc2 = idec.newScope(sc);
+
+ /* Set scope so if there are forward references, we still might be able to
+ * resolve individual members like enums.
+ */
+ idec.members.foreachDsymbol( s => s.setScope(sc2) );
+
+ idec.members.foreachDsymbol( s => s.importAll(sc2) );
+
+ idec.members.foreachDsymbol( s => s.dsymbolSemantic(sc2) );
+
+ Module.dprogress++;
+ idec.semanticRun = PASS.semanticdone;
+ //printf("-InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type);
+
+ sc2.pop();
+
+ if (global.errors != errors)
+ {
+ // The type is no good.
+ idec.type = Type.terror;
+ }
+
+ version (none)
+ {
+ if (type.ty == Tclass && (cast(TypeClass)idec.type).sym != idec)
+ {
+ printf("this = %p %s\n", idec, idec.toChars());
+ printf("type = %d sym = %p\n", idec.type.ty, (cast(TypeClass)idec.type).sym);
+ }
+ }
+ assert(idec.type.ty != Tclass || (cast(TypeClass)idec.type).sym == idec);
+
+ // @@@DEPRECATED@@@https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+ // Deprecated in 2.087
+ // Remove in 2.091
+ // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036
+ if (idec.storage_class & STC.scope_)
+ deprecation(idec.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site.");
+ }
+}
+
+/*******************************************
+ * Add members of EnumDeclaration to the symbol table(s).
+ * Params:
+ * ed = EnumDeclaration
+ * sc = context of `ed`
+ * sds = symbol table that `ed` resides in
+ */
+void addEnumMembers(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds)
+{
+ if (ed.added)
+ return;
+ ed.added = true;
+
+ if (!ed.members)
+ return;
+
+ const bool isCEnum = (sc.flags & SCOPE.Cfile) != 0; // it's an ImportC enum
+ const bool isAnon = ed.isAnonymous();
+
+ if ((isCEnum || isAnon) && !sds.symtab)
+ sds.symtab = new DsymbolTable();
+
+ if ((isCEnum || !isAnon) && !ed.symtab)
+ ed.symtab = new DsymbolTable();
+
+ ed.members.foreachDsymbol( (s)
+ {
+ if (EnumMember em = s.isEnumMember())
+ {
+ em.ed = ed;
+ if (isCEnum)
+ {
+ em.addMember(sc, ed); // add em to ed's symbol table
+ em.addMember(sc, sds); // add em to symbol table that ed is in
+ em.parent = ed; // restore it after previous addMember() changed it
+ }
+ else
+ {
+ em.addMember(sc, isAnon ? sds : ed);
+ }
+ }
+ });
+}
+
+void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* fargs)
+{
+ //printf("[%s] TemplateInstance.dsymbolSemantic('%s', this=%p, gag = %d, sc = %p)\n", tempinst.loc.toChars(), tempinst.toChars(), tempinst, global.gag, sc);
+ version (none)
+ {
+ for (Dsymbol s = tempinst; s; s = s.parent)
+ {
+ printf("\t%s\n", s.toChars());
+ }
+ printf("Scope\n");
+ for (Scope* scx = sc; scx; scx = scx.enclosing)
+ {
+ printf("\t%s parent %s\n", scx._module ? scx._module.toChars() : "null", scx.parent ? scx.parent.toChars() : "null");
+ }
+ }
+
+ static if (LOG)
+ {
+ printf("\n+TemplateInstance.dsymbolSemantic('%s', this=%p)\n", tempinst.toChars(), tempinst);
+ }
+ if (tempinst.inst) // if semantic() was already run
+ {
+ static if (LOG)
+ {
+ printf("-TemplateInstance.dsymbolSemantic('%s', this=%p) already run\n",
+ tempinst.inst.toChars(), tempinst.inst);
+ }
+ return;
+ }
+ if (tempinst.semanticRun != PASS.init)
+ {
+ static if (LOG)
+ {
+ printf("Recursive template expansion\n");
+ }
+ auto ungag = Ungag(global.gag);
+ if (!tempinst.gagged)
+ global.gag = 0;
+ tempinst.error(tempinst.loc, "recursive template expansion");
+ if (tempinst.gagged)
+ tempinst.semanticRun = PASS.init;
+ else
+ tempinst.inst = tempinst;
+ tempinst.errors = true;
+ return;
+ }
+
+ // Get the enclosing template instance from the scope tinst
+ tempinst.tinst = sc.tinst;
+
+ // Get the instantiating module from the scope minst
+ tempinst.minst = sc.minst;
+ // https://issues.dlang.org/show_bug.cgi?id=10920
+ // If the enclosing function is non-root symbol,
+ // this instance should be speculative.
+ if (!tempinst.tinst && sc.func && sc.func.inNonRoot())
+ {
+ tempinst.minst = null;
+ }
+
+ tempinst.gagged = (global.gag > 0);
+
+ tempinst.semanticRun = PASS.semantic;
+
+ static if (LOG)
+ {
+ printf("\tdo semantic\n");
+ }
+ /* Find template declaration first,
+ * then run semantic on each argument (place results in tiargs[]),
+ * last find most specialized template from overload list/set.
+ */
+ if (!tempinst.findTempDecl(sc, null) || !tempinst.semanticTiargs(sc) || !tempinst.findBestMatch(sc, fargs))
+ {
+ Lerror:
+ if (tempinst.gagged)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=13220
+ // Roll back status for later semantic re-running
+ tempinst.semanticRun = PASS.init;
+ }
+ else
+ tempinst.inst = tempinst;
+ tempinst.errors = true;
+ return;
+ }
+ TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration();
+ assert(tempdecl);
+
+ TemplateStats.incInstance(tempdecl, tempinst);
+
+ tempdecl.checkDeprecated(tempinst.loc, sc);
+
+ // If tempdecl is a mixin, disallow it
+ if (tempdecl.ismixin)
+ {
+ tempinst.error("mixin templates are not regular templates");
+ goto Lerror;
+ }
+
+ tempinst.hasNestedArgs(tempinst.tiargs, tempdecl.isstatic);
+ if (tempinst.errors)
+ goto Lerror;
+
+ // Copy the tempdecl namespace (not the scope one)
+ tempinst.cppnamespace = tempdecl.cppnamespace;
+ if (tempinst.cppnamespace)
+ tempinst.cppnamespace.dsymbolSemantic(sc);
+
+ /* Greatly simplified semantic processing for AliasSeq templates
+ */
+ if (tempdecl.isTrivialAliasSeq)
+ {
+ tempinst.inst = tempinst;
+ return aliasSeqInstanceSemantic(tempinst, sc, tempdecl);
+ }
+
+ /* Greatly simplified semantic processing for Alias templates
+ */
+ else if (tempdecl.isTrivialAlias)
+ {
+ tempinst.inst = tempinst;
+ return aliasInstanceSemantic(tempinst, sc, tempdecl);
+ }
+
+ /* See if there is an existing TemplateInstantiation that already
+ * implements the typeargs. If so, just refer to that one instead.
+ */
+ tempinst.inst = tempdecl.findExistingInstance(tempinst, fargs);
+ TemplateInstance errinst = null;
+ if (!tempinst.inst)
+ {
+ // So, we need to implement 'this' instance.
+ }
+ else if (tempinst.inst.gagged && !tempinst.gagged && tempinst.inst.errors)
+ {
+ // If the first instantiation had failed, re-run semantic,
+ // so that error messages are shown.
+ errinst = tempinst.inst;
+ }
+ else
+ {
+ // It's a match
+ tempinst.parent = tempinst.inst.parent;
+ tempinst.errors = tempinst.inst.errors;
+
+ // If both this and the previous instantiation were gagged,
+ // use the number of errors that happened last time.
+ global.errors += tempinst.errors;
+ global.gaggedErrors += tempinst.errors;
+
+ // If the first instantiation was gagged, but this is not:
+ if (tempinst.inst.gagged)
+ {
+ // It had succeeded, mark it is a non-gagged instantiation,
+ // and reuse it.
+ tempinst.inst.gagged = tempinst.gagged;
+ }
+
+ tempinst.tnext = tempinst.inst.tnext;
+ tempinst.inst.tnext = tempinst;
+
+ /* A module can have explicit template instance and its alias
+ * in module scope (e,g, `alias Base64 = Base64Impl!('+', '/');`).
+ * If the first instantiation 'inst' had happened in non-root module,
+ * compiler can assume that its instantiated code would be included
+ * in the separately compiled obj/lib file (e.g. phobos.lib).
+ *
+ * However, if 'this' second instantiation happened in root module,
+ * compiler might need to invoke its codegen
+ * (https://issues.dlang.org/show_bug.cgi?id=2500 & https://issues.dlang.org/show_bug.cgi?id=2644).
+ * But whole import graph is not determined until all semantic pass finished,
+ * so 'inst' should conservatively finish the semantic3 pass for the codegen.
+ */
+ if (tempinst.minst && tempinst.minst.isRoot() && !(tempinst.inst.minst && tempinst.inst.minst.isRoot()))
+ {
+ /* Swap the position of 'inst' and 'this' in the instantiation graph.
+ * Then, the primary instance `inst` will be changed to a root instance,
+ * along with all members of `inst` having their scopes updated.
+ *
+ * Before:
+ * non-root -> A!() -> B!()[inst] -> C!() { members[non-root] }
+ * |
+ * root -> D!() -> B!()[this]
+ *
+ * After:
+ * non-root -> A!() -> B!()[this]
+ * |
+ * root -> D!() -> B!()[inst] -> C!() { members[root] }
+ */
+ Module mi = tempinst.minst;
+ TemplateInstance ti = tempinst.tinst;
+ tempinst.minst = tempinst.inst.minst;
+ tempinst.tinst = tempinst.inst.tinst;
+ tempinst.inst.minst = mi;
+ tempinst.inst.tinst = ti;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=21299
+ `minst` has been updated on the primary instance `inst` so it is
+ now coming from a root module, however all Dsymbol `inst.members`
+ of the instance still have their `_scope.minst` pointing at the
+ original non-root module. We must now propagate `minst` to all
+ members so that forward referenced dependencies that get
+ instantiated will also be appended to the root module, otherwise
+ there will be undefined references at link-time. */
+ extern (C++) final class InstMemberWalker : Visitor
+ {
+ alias visit = Visitor.visit;
+ TemplateInstance inst;
+
+ extern (D) this(TemplateInstance inst)
+ {
+ this.inst = inst;
+ }
+
+ override void visit(Dsymbol d)
+ {
+ if (d._scope)
+ d._scope.minst = inst.minst;
+ }
+
+ override void visit(ScopeDsymbol sds)
+ {
+ sds.members.foreachDsymbol( s => s.accept(this) );
+ visit(cast(Dsymbol)sds);
+ }
+
+ override void visit(AttribDeclaration ad)
+ {
+ ad.include(null).foreachDsymbol( s => s.accept(this) );
+ visit(cast(Dsymbol)ad);
+ }
+
+ override void visit(ConditionalDeclaration cd)
+ {
+ if (cd.condition.inc)
+ visit(cast(AttribDeclaration)cd);
+ else
+ visit(cast(Dsymbol)cd);
+ }
+ }
+ scope v = new InstMemberWalker(tempinst.inst);
+ tempinst.inst.accept(v);
+
+ if (tempinst.minst) // if inst was not speculative
+ {
+ /* Add 'inst' once again to the root module members[], then the
+ * instance members will get codegen chances.
+ */
+ tempinst.inst.appendToModuleMember();
+ }
+ }
+
+ // modules imported by an existing instance should be added to the module
+ // that instantiates the instance.
+ if (tempinst.minst)
+ foreach(imp; tempinst.inst.importedModules)
+ if (!tempinst.minst.aimports.contains(imp))
+ tempinst.minst.aimports.push(imp);
+
+ static if (LOG)
+ {
+ printf("\tit's a match with instance %p, %d\n", tempinst.inst, tempinst.inst.semanticRun);
+ }
+ return;
+ }
+ static if (LOG)
+ {
+ printf("\timplement template instance %s '%s'\n", tempdecl.parent.toChars(), tempinst.toChars());
+ printf("\ttempdecl %s\n", tempdecl.toChars());
+ }
+ uint errorsave = global.errors;
+
+ tempinst.inst = tempinst;
+ tempinst.parent = tempinst.enclosing ? tempinst.enclosing : tempdecl.parent;
+ //printf("parent = '%s'\n", parent.kind());
+
+ TemplateStats.incUnique(tempdecl, tempinst);
+
+ TemplateInstance tempdecl_instance_idx = tempdecl.addInstance(tempinst);
+
+ //getIdent();
+
+ // Store the place we added it to in target_symbol_list(_idx) so we can
+ // remove it later if we encounter an error.
+ Dsymbols* target_symbol_list = tempinst.appendToModuleMember();
+ size_t target_symbol_list_idx = target_symbol_list ? target_symbol_list.dim - 1 : 0;
+
+ // Copy the syntax trees from the TemplateDeclaration
+ tempinst.members = Dsymbol.arraySyntaxCopy(tempdecl.members);
+
+ // resolve TemplateThisParameter
+ for (size_t i = 0; i < tempdecl.parameters.dim; i++)
+ {
+ if ((*tempdecl.parameters)[i].isTemplateThisParameter() is null)
+ continue;
+ Type t = isType((*tempinst.tiargs)[i]);
+ assert(t);
+ if (StorageClass stc = ModToStc(t.mod))
+ {
+ //printf("t = %s, stc = x%llx\n", t.toChars(), stc);
+ auto s = new Dsymbols();
+ s.push(new StorageClassDeclaration(stc, tempinst.members));
+ tempinst.members = s;
+ }
+ break;
+ }
+
+ // Create our own scope for the template parameters
+ Scope* _scope = tempdecl._scope;
+ if (tempdecl.semanticRun == PASS.init)
+ {
+ tempinst.error("template instantiation `%s` forward references template declaration `%s`", tempinst.toChars(), tempdecl.toChars());
+ return;
+ }
+
+ static if (LOG)
+ {
+ printf("\tcreate scope for template parameters '%s'\n", tempinst.toChars());
+ }
+ tempinst.argsym = new ScopeDsymbol();
+ tempinst.argsym.parent = _scope.parent;
+ _scope = _scope.push(tempinst.argsym);
+ _scope.tinst = tempinst;
+ _scope.minst = tempinst.minst;
+ //scope.stc = 0;
+
+ // Declare each template parameter as an alias for the argument type
+ Scope* paramscope = _scope.push();
+ paramscope.stc = 0;
+ paramscope.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=14169
+ // template parameters should be public
+ tempinst.declareParameters(paramscope);
+ paramscope.pop();
+
+ // Add members of template instance to template instance symbol table
+ //parent = scope.scopesym;
+ tempinst.symtab = new DsymbolTable();
+
+ tempinst.members.foreachDsymbol( (s)
+ {
+ static if (LOG)
+ {
+ printf("\t adding member '%s' %p kind %s to '%s'\n", s.toChars(), s, s.kind(), tempinst.toChars());
+ }
+ s.addMember(_scope, tempinst);
+ });
+
+ static if (LOG)
+ {
+ printf("adding members done\n");
+ }
+
+ /* See if there is only one member of template instance, and that
+ * member has the same name as the template instance.
+ * If so, this template instance becomes an alias for that member.
+ */
+ //printf("members.dim = %d\n", tempinst.members.dim);
+ if (tempinst.members.dim)
+ {
+ Dsymbol s;
+ if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s)
+ {
+ //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars());
+ //printf("setting aliasdecl\n");
+ tempinst.aliasdecl = s;
+ }
+ }
+
+ /* If function template declaration
+ */
+ if (fargs && tempinst.aliasdecl)
+ {
+ if (auto fd = tempinst.aliasdecl.isFuncDeclaration())
+ {
+ /* Transmit fargs to type so that TypeFunction.dsymbolSemantic() can
+ * resolve any "auto ref" storage classes.
+ */
+ if (fd.type)
+ if (auto tf = fd.type.isTypeFunction())
+ tf.fargs = fargs;
+ }
+ }
+
+ // Do semantic() analysis on template instance members
+ static if (LOG)
+ {
+ printf("\tdo semantic() on template instance members '%s'\n", tempinst.toChars());
+ }
+ Scope* sc2;
+ sc2 = _scope.push(tempinst);
+ //printf("enclosing = %d, sc.parent = %s\n", tempinst.enclosing, sc.parent.toChars());
+ sc2.parent = tempinst;
+ sc2.tinst = tempinst;
+ sc2.minst = tempinst.minst;
+ sc2.stc &= ~STC.deprecated_;
+ tempinst.tryExpandMembers(sc2);
+
+ tempinst.semanticRun = PASS.semanticdone;
+
+ /* ConditionalDeclaration may introduce eponymous declaration,
+ * so we should find it once again after semantic.
+ */
+ if (tempinst.members.dim)
+ {
+ Dsymbol s;
+ if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s)
+ {
+ if (!tempinst.aliasdecl || tempinst.aliasdecl != s)
+ {
+ //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars());
+ //printf("setting aliasdecl 2\n");
+ tempinst.aliasdecl = s;
+ }
+ }
+ }
+
+ if (global.errors != errorsave)
+ goto Laftersemantic;
+
+ /* If any of the instantiation members didn't get semantic() run
+ * on them due to forward references, we cannot run semantic2()
+ * or semantic3() yet.
+ */
+ {
+ bool found_deferred_ad = false;
+ for (size_t i = 0; i < Module.deferred.dim; i++)
+ {
+ Dsymbol sd = Module.deferred[i];
+ AggregateDeclaration ad = sd.isAggregateDeclaration();
+ if (ad && ad.parent && ad.parent.isTemplateInstance())
+ {
+ //printf("deferred template aggregate: %s %s\n",
+ // sd.parent.toChars(), sd.toChars());
+ found_deferred_ad = true;
+ if (ad.parent == tempinst)
+ {
+ ad.deferred = tempinst;
+ break;
+ }
+ }
+ }
+ if (found_deferred_ad || Module.deferred.dim)
+ goto Laftersemantic;
+ }
+
+ /* The problem is when to parse the initializer for a variable.
+ * Perhaps VarDeclaration.dsymbolSemantic() should do it like it does
+ * for initializers inside a function.
+ */
+ //if (sc.parent.isFuncDeclaration())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=782
+ * this has problems if the classes this depends on
+ * are forward referenced. Find a way to defer semantic()
+ * on this template.
+ */
+ tempinst.semantic2(sc2);
+ }
+ if (global.errors != errorsave)
+ goto Laftersemantic;
+
+ if ((sc.func || (sc.flags & SCOPE.fullinst)) && !tempinst.tinst)
+ {
+ /* If a template is instantiated inside function, the whole instantiation
+ * should be done at that position. But, immediate running semantic3 of
+ * dependent templates may cause unresolved forward reference.
+ * https://issues.dlang.org/show_bug.cgi?id=9050
+ * To avoid the issue, don't run semantic3 until semantic and semantic2 done.
+ */
+ TemplateInstances deferred;
+ tempinst.deferred = &deferred;
+
+ //printf("Run semantic3 on %s\n", toChars());
+ tempinst.trySemantic3(sc2);
+
+ for (size_t i = 0; i < deferred.dim; i++)
+ {
+ //printf("+ run deferred semantic3 on %s\n", deferred[i].toChars());
+ deferred[i].semantic3(null);
+ }
+
+ tempinst.deferred = null;
+ }
+ else if (tempinst.tinst)
+ {
+ bool doSemantic3 = false;
+ FuncDeclaration fd;
+ if (tempinst.aliasdecl)
+ fd = tempinst.aliasdecl.toAlias2().isFuncDeclaration();
+
+ if (fd)
+ {
+ /* Template function instantiation should run semantic3 immediately
+ * for attribute inference.
+ */
+ scope fld = fd.isFuncLiteralDeclaration();
+ if (fld && fld.tok == TOK.reserved)
+ doSemantic3 = true;
+ else if (sc.func)
+ doSemantic3 = true;
+ }
+ else if (sc.func)
+ {
+ /* A lambda function in template arguments might capture the
+ * instantiated scope context. For the correct context inference,
+ * all instantiated functions should run the semantic3 immediately.
+ * See also compilable/test14973.d
+ */
+ foreach (oarg; tempinst.tdtypes)
+ {
+ auto s = getDsymbol(oarg);
+ if (!s)
+ continue;
+
+ if (auto td = s.isTemplateDeclaration())
+ {
+ if (!td.literal)
+ continue;
+ assert(td.members && td.members.dim == 1);
+ s = (*td.members)[0];
+ }
+ if (auto fld = s.isFuncLiteralDeclaration())
+ {
+ if (fld.tok == TOK.reserved)
+ {
+ doSemantic3 = true;
+ break;
+ }
+ }
+ }
+ //printf("[%s] %s doSemantic3 = %d\n", tempinst.tinst.loc.toChars(), tempinst.tinst.toChars(), doSemantic3);
+ }
+ if (doSemantic3)
+ tempinst.trySemantic3(sc2);
+
+ TemplateInstance ti = tempinst.tinst;
+ int nest = 0;
+ while (ti && !ti.deferred && ti.tinst)
+ {
+ ti = ti.tinst;
+ if (++nest > global.recursionLimit)
+ {
+ global.gag = 0; // ensure error message gets printed
+ tempinst.error("recursive expansion");
+ fatal();
+ }
+ }
+ if (ti && ti.deferred)
+ {
+ //printf("deferred semantic3 of %p %s, ti = %s, ti.deferred = %p\n", this, toChars(), ti.toChars());
+ for (size_t i = 0;; i++)
+ {
+ if (i == ti.deferred.dim)
+ {
+ ti.deferred.push(tempinst);
+ break;
+ }
+ if ((*ti.deferred)[i] == tempinst)
+ break;
+ }
+ }
+ }
+
+ if (tempinst.aliasdecl)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=13816
+ * AliasDeclaration tries to resolve forward reference
+ * twice (See inuse check in AliasDeclaration.toAlias()). It's
+ * necessary to resolve mutual references of instantiated symbols, but
+ * it will left a true recursive alias in tuple declaration - an
+ * AliasDeclaration A refers TupleDeclaration B, and B contains A
+ * in its elements. To correctly make it an error, we strictly need to
+ * resolve the alias of eponymous member.
+ */
+ tempinst.aliasdecl = tempinst.aliasdecl.toAlias2();
+ }
+
+Laftersemantic:
+ sc2.pop();
+ _scope.pop();
+
+ // Give additional context info if error occurred during instantiation
+ if (global.errors != errorsave)
+ {
+ if (!tempinst.errors)
+ {
+ if (!tempdecl.literal)
+ tempinst.error(tempinst.loc, "error instantiating");
+ if (tempinst.tinst)
+ tempinst.tinst.printInstantiationTrace();
+ }
+ tempinst.errors = true;
+ if (tempinst.gagged)
+ {
+ // Errors are gagged, so remove the template instance from the
+ // instance/symbol lists we added it to and reset our state to
+ // finish clean and so we can try to instantiate it again later
+ // (see https://issues.dlang.org/show_bug.cgi?id=4302 and https://issues.dlang.org/show_bug.cgi?id=6602).
+ tempdecl.removeInstance(tempdecl_instance_idx);
+ if (target_symbol_list)
+ {
+ // Because we added 'this' in the last position above, we
+ // should be able to remove it without messing other indices up.
+ assert((*target_symbol_list)[target_symbol_list_idx] == tempinst);
+ target_symbol_list.remove(target_symbol_list_idx);
+ tempinst.memberOf = null; // no longer a member
+ }
+ tempinst.semanticRun = PASS.init;
+ tempinst.inst = null;
+ tempinst.symtab = null;
+ }
+ }
+ else if (errinst)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=14541
+ * If the previous gagged instance had failed by
+ * circular references, currrent "error reproduction instantiation"
+ * might succeed, because of the difference of instantiated context.
+ * On such case, the cached error instance needs to be overridden by the
+ * succeeded instance.
+ */
+ //printf("replaceInstance()\n");
+ assert(errinst.errors);
+ auto ti1 = TemplateInstanceBox(errinst);
+ tempdecl.instances.remove(ti1);
+
+ auto ti2 = TemplateInstanceBox(tempinst);
+ tempdecl.instances[ti2] = tempinst;
+ }
+
+ static if (LOG)
+ {
+ printf("-TemplateInstance.dsymbolSemantic('%s', this=%p)\n", tempinst.toChars(), tempinst);
+ }
+}
+
+/******************************************************
+ * Do template instance semantic for isAliasSeq templates.
+ * This is a greatly simplified version of templateInstanceSemantic().
+ */
+private
+void aliasSeqInstanceSemantic(TemplateInstance tempinst, Scope* sc, TemplateDeclaration tempdecl)
+{
+ //printf("[%s] aliasSeqInstance.dsymbolSemantic('%s')\n", tempinst.loc.toChars(), tempinst.toChars());
+ Scope* paramscope = sc.push();
+ paramscope.stc = 0;
+ paramscope.visibility = Visibility(Visibility.Kind.public_);
+
+ TemplateTupleParameter ttp = (*tempdecl.parameters)[0].isTemplateTupleParameter();
+ Tuple va = tempinst.tdtypes[0].isTuple();
+ Declaration d = new TupleDeclaration(tempinst.loc, ttp.ident, &va.objects);
+ d.storage_class |= STC.templateparameter;
+ d.dsymbolSemantic(sc);
+
+ paramscope.pop();
+
+ tempinst.aliasdecl = d;
+
+ tempinst.semanticRun = PASS.semanticdone;
+}
+
+/******************************************************
+ * Do template instance semantic for isAlias templates.
+ * This is a greatly simplified version of templateInstanceSemantic().
+ */
+private
+void aliasInstanceSemantic(TemplateInstance tempinst, Scope* sc, TemplateDeclaration tempdecl)
+{
+ //printf("[%s] aliasInstance.dsymbolSemantic('%s')\n", tempinst.loc.toChars(), tempinst.toChars());
+ Scope* paramscope = sc.push();
+ paramscope.stc = 0;
+ paramscope.visibility = Visibility(Visibility.Kind.public_);
+
+ TemplateTypeParameter ttp = (*tempdecl.parameters)[0].isTemplateTypeParameter();
+ Type ta = tempinst.tdtypes[0].isType();
+ auto ad = tempdecl.onemember.isAliasDeclaration();
+
+ // Note: qualifiers can be in both 'ad.type.mod' and 'ad.storage_class'
+ Declaration d = new AliasDeclaration(tempinst.loc, ttp.ident, ta.addMod(ad.type.mod));
+ d.storage_class |= STC.templateparameter | ad.storage_class;
+ d.dsymbolSemantic(sc);
+
+ paramscope.pop();
+
+ tempinst.aliasdecl = d;
+
+ tempinst.semanticRun = PASS.semanticdone;
+}
+
+// function used to perform semantic on AliasDeclaration
+void aliasSemantic(AliasDeclaration ds, Scope* sc)
+{
+ //printf("AliasDeclaration::semantic() %s\n", ds.toChars());
+
+ // as DsymbolSemanticVisitor::visit(AliasDeclaration), in case we're called first.
+ // see https://issues.dlang.org/show_bug.cgi?id=21001
+ ds.storage_class |= sc.stc & STC.deprecated_;
+ ds.visibility = sc.visibility;
+ ds.userAttribDecl = sc.userAttribDecl;
+
+ // TypeTraits needs to know if it's located in an AliasDeclaration
+ const oldflags = sc.flags;
+ sc.flags |= SCOPE.alias_;
+
+ void normalRet()
+ {
+ sc.flags = oldflags;
+ ds.inuse = 0;
+ ds.semanticRun = PASS.semanticdone;
+
+ if (auto sx = ds.overnext)
+ {
+ ds.overnext = null;
+ if (!ds.overloadInsert(sx))
+ ScopeDsymbol.multiplyDefined(Loc.initial, sx, ds);
+ }
+ }
+
+ void errorRet()
+ {
+ ds.aliassym = null;
+ ds.type = Type.terror;
+ ds.inuse = 0;
+ normalRet();
+ }
+
+ // preserve the original type
+ if (!ds.originalType && ds.type)
+ ds.originalType = ds.type.syntaxCopy();
+
+ if (ds.aliassym)
+ {
+ auto fd = ds.aliassym.isFuncLiteralDeclaration();
+ auto td = ds.aliassym.isTemplateDeclaration();
+ if (fd || td && td.literal)
+ {
+ if (fd && fd.semanticRun >= PASS.semanticdone)
+ return normalRet();
+
+ Expression e = new FuncExp(ds.loc, ds.aliassym);
+ e = e.expressionSemantic(sc);
+ if (auto fe = e.isFuncExp())
+ {
+ ds.aliassym = fe.td ? cast(Dsymbol)fe.td : fe.fd;
+ return normalRet();
+ }
+ else
+ return errorRet();
+ }
+
+ if (ds.aliassym.isTemplateInstance())
+ ds.aliassym.dsymbolSemantic(sc);
+ return normalRet();
+ }
+ ds.inuse = 1;
+
+ // Given:
+ // alias foo.bar.abc def;
+ // it is not knowable from the syntax whether `def` is an alias
+ // for type `foo.bar.abc` or an alias for symbol `foo.bar.abc`. It is up to the semantic()
+ // pass to distinguish.
+ // If it is a type, then `.type` is set and getType() will return that
+ // type. If it is a symbol, then `.aliassym` is set and type is `null` -
+ // toAlias() will return `.aliassym`
+
+ const errors = global.errors;
+ Type oldtype = ds.type;
+
+ // Ungag errors when not instantiated DeclDefs scope alias
+ auto ungag = Ungag(global.gag);
+ //printf("%s parent = %s, gag = %d, instantiated = %d\n", toChars(), parent, global.gag, isInstantiated());
+ if (ds.parent && global.gag && !ds.isInstantiated() && !ds.toParent2().isFuncDeclaration())
+ {
+ //printf("%s type = %s\n", toPrettyChars(), type.toChars());
+ global.gag = 0;
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=18480
+ // Detect `alias sym = sym;` to prevent creating loops in overload overnext lists.
+ if (auto tident = ds.type.isTypeIdentifier())
+ {
+ // Selective imports are allowed to alias to the same name `import mod : sym=sym`.
+ if (!ds._import)
+ {
+ if (tident.ident is ds.ident && !tident.idents.dim)
+ {
+ error(ds.loc, "`alias %s = %s;` cannot alias itself, use a qualified name to create an overload set",
+ ds.ident.toChars(), tident.ident.toChars());
+ ds.type = Type.terror;
+ }
+ }
+ }
+ /* This section is needed because Type.resolve() will:
+ * const x = 3;
+ * alias y = x;
+ * try to convert identifier x to 3.
+ */
+ auto s = ds.type.toDsymbol(sc);
+ if (errors != global.errors)
+ return errorRet();
+ if (s == ds)
+ {
+ ds.error("cannot resolve");
+ return errorRet();
+ }
+ if (!s || !s.isEnumMember())
+ {
+ Type t;
+ Expression e;
+ Scope* sc2 = sc;
+ if (ds.storage_class & (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.disable))
+ {
+ // For 'ref' to be attached to function types, and picked
+ // up by Type.resolve(), it has to go into sc.
+ sc2 = sc.push();
+ sc2.stc |= ds.storage_class & (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.shared_ | STC.disable);
+ }
+ ds.type = ds.type.addSTC(ds.storage_class);
+ ds.type.resolve(ds.loc, sc2, e, t, s);
+ if (sc2 != sc)
+ sc2.pop();
+
+ if (e) // Try to convert Expression to Dsymbol
+ {
+ // TupleExp is naturally converted to a TupleDeclaration
+ if (auto te = e.isTupleExp())
+ s = new TupleDeclaration(te.loc, ds.ident, cast(Objects*)te.exps);
+ else
+ {
+ s = getDsymbol(e);
+ if (!s)
+ {
+ if (e.op != TOK.error)
+ ds.error("cannot alias an expression `%s`", e.toChars());
+ return errorRet();
+ }
+ }
+ }
+ ds.type = t;
+ }
+ if (s == ds)
+ {
+ assert(global.errors);
+ return errorRet();
+ }
+ if (s) // it's a symbolic alias
+ {
+ //printf("alias %s resolved to %s %s\n", toChars(), s.kind(), s.toChars());
+ ds.type = null;
+ ds.aliassym = s;
+ }
+ else // it's a type alias
+ {
+ //printf("alias %s resolved to type %s\n", toChars(), type.toChars());
+ ds.type = ds.type.typeSemantic(ds.loc, sc);
+ ds.aliassym = null;
+ }
+
+ if (global.gag && errors != global.errors)
+ return errorRet();
+
+ normalRet();
+}
+
+/********************
+ * Perform semantic on AliasAssignment.
+ * Has a lot of similarities to aliasSemantic(). Perhaps they should share code.
+ */
+private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
+{
+ //printf("AliasAssign::semantic() %p, %s\n", ds, ds.ident.toChars());
+
+ void errorRet()
+ {
+ ds.errors = true;
+ ds.type = Type.terror;
+ ds.semanticRun = PASS.semanticdone;
+ return;
+ }
+
+ /* Find the AliasDeclaration corresponding to ds.
+ * Returns: AliasDeclaration if found, null if error
+ */
+ AliasDeclaration findAliasDeclaration(AliasAssign ds, Scope* sc)
+ {
+ Dsymbol scopesym;
+ Dsymbol as = sc.search(ds.loc, ds.ident, &scopesym);
+ if (!as)
+ {
+ ds.error("undefined identifier `%s`", ds.ident.toChars());
+ return null;
+ }
+ if (as.errors)
+ return null;
+
+ auto ad = as.isAliasDeclaration();
+ if (!ad)
+ {
+ ds.error("identifier `%s` must be an alias declaration", as.toChars());
+ return null;
+ }
+
+ if (ad.overnext)
+ {
+ ds.error("cannot reassign overloaded alias");
+ return null;
+ }
+
+ // Check constraints on the parent
+ auto adParent = ad.toParent();
+ if (adParent != ds.toParent())
+ {
+ if (!adParent)
+ adParent = ds.toParent();
+ error(ds.loc, "`%s` must have same parent `%s` as alias `%s`", ds.ident.toChars(), adParent.toChars(), ad.toChars());
+ return null;
+ }
+ if (!adParent.isTemplateInstance())
+ {
+ ds.error("must be a member of a template");
+ return null;
+ }
+
+ return ad;
+ }
+
+ auto aliassym = findAliasDeclaration(ds, sc);
+ if (!aliassym)
+ return errorRet();
+
+ if (aliassym.adFlags & Declaration.wasRead)
+ {
+ if (!aliassym.errors)
+ error(ds.loc, "%s was read, so cannot reassign", aliassym.toChars());
+ aliassym.errors = true;
+ return errorRet();
+ }
+
+ aliassym.adFlags |= Declaration.ignoreRead; // temporarilly allow reads of aliassym
+
+ const storage_class = sc.stc & (STC.deprecated_ | STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.shared_ | STC.disable);
+
+ if (ds.aliassym)
+ {
+ auto fd = ds.aliassym.isFuncLiteralDeclaration();
+ auto td = ds.aliassym.isTemplateDeclaration();
+ if (fd && fd.semanticRun >= PASS.semanticdone)
+ {
+ }
+ else if (fd || td && td.literal)
+ {
+
+ Expression e = new FuncExp(ds.loc, ds.aliassym);
+ e = e.expressionSemantic(sc);
+ auto fe = e.isFuncExp();
+ if (!fe)
+ return errorRet();
+ ds.aliassym = fe.td ? cast(Dsymbol)fe.td : fe.fd;
+ }
+ else if (ds.aliassym.isTemplateInstance())
+ ds.aliassym.dsymbolSemantic(sc);
+
+ aliassym.type = null;
+ aliassym.aliassym = ds.aliassym;
+ return;
+ }
+
+ /* Given:
+ * abc = def;
+ * it is not knownable from the syntax whether `def` is a type or a symbol.
+ * It appears here as `ds.type`. Do semantic analysis on `def` to disambiguate.
+ */
+
+ const errors = global.errors;
+
+ /* This section is needed because Type.resolve() will:
+ * const x = 3;
+ * alias y = x;
+ * try to convert identifier x to 3.
+ */
+ auto s = ds.type.toDsymbol(sc);
+ if (errors != global.errors)
+ return errorRet();
+ if (s == aliassym)
+ {
+ ds.error("cannot resolve");
+ return errorRet();
+ }
+
+ if (!s || !s.isEnumMember())
+ {
+ Type t;
+ Expression e;
+ Scope* sc2 = sc;
+ if (storage_class & (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.shared_ | STC.disable))
+ {
+ // For 'ref' to be attached to function types, and picked
+ // up by Type.resolve(), it has to go into sc.
+ sc2 = sc.push();
+ sc2.stc |= storage_class & (STC.ref_ | STC.nothrow_ | STC.nogc | STC.pure_ | STC.shared_ | STC.disable);
+ }
+ ds.type = ds.type.addSTC(storage_class);
+ ds.type.resolve(ds.loc, sc2, e, t, s);
+ if (sc2 != sc)
+ sc2.pop();
+
+ if (e) // Try to convert Expression to Dsymbol
+ {
+ // TupleExp is naturally converted to a TupleDeclaration
+ if (auto te = e.isTupleExp())
+ s = new TupleDeclaration(te.loc, ds.ident, cast(Objects*)te.exps);
+ else
+ {
+ s = getDsymbol(e);
+ if (!s)
+ {
+ if (e.op != TOK.error)
+ ds.error("cannot alias an expression `%s`", e.toChars());
+ return errorRet();
+ }
+ }
+ }
+ ds.type = t;
+ }
+ if (s == aliassym)
+ {
+ assert(global.errors);
+ return errorRet();
+ }
+
+ if (s) // it's a symbolic alias
+ {
+ //printf("alias %s resolved to %s %s\n", toChars(), s.kind(), s.toChars());
+ aliassym.type = null;
+ aliassym.aliassym = s;
+ aliassym.storage_class |= sc.stc & STC.deprecated_;
+ aliassym.visibility = sc.visibility;
+ aliassym.userAttribDecl = sc.userAttribDecl;
+ }
+ else // it's a type alias
+ {
+ //printf("alias %s resolved to type %s\n", toChars(), type.toChars());
+ aliassym.type = ds.type.typeSemantic(ds.loc, sc);
+ aliassym.aliassym = null;
+ }
+
+
+ aliassym.adFlags &= ~Declaration.ignoreRead;
+
+ if (aliassym.type && aliassym.type.ty == Terror ||
+ global.gag && errors != global.errors)
+ {
+ aliassym.type = Type.terror;
+ aliassym.aliassym = null;
+ return errorRet();
+ }
+
+ ds.semanticRun = PASS.semanticdone;
+}
+
+/***************************************
+ * Find all instance fields in `ad`, then push them into `fields`.
+ *
+ * Runs semantic() for all instance field variables, but also
+ * the field types can remain yet not resolved forward references,
+ * except direct recursive definitions.
+ * After the process sizeok is set to Sizeok.fwd.
+ *
+ * Params:
+ * ad = the AggregateDeclaration to examine
+ * Returns:
+ * false if any errors occur.
+ */
+bool determineFields(AggregateDeclaration ad)
+{
+ if (ad._scope)
+ dsymbolSemantic(ad, null);
+ if (ad.sizeok != Sizeok.none)
+ return true;
+
+ //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim);
+ // determineFields can be called recursively from one of the fields's v.semantic
+ ad.fields.setDim(0);
+
+ static int func(Dsymbol s, AggregateDeclaration ad)
+ {
+ auto v = s.isVarDeclaration();
+ if (!v)
+ return 0;
+ if (v.storage_class & STC.manifest)
+ return 0;
+
+ if (v.semanticRun < PASS.semanticdone)
+ v.dsymbolSemantic(null);
+ // Return in case a recursive determineFields triggered by v.semantic already finished
+ if (ad.sizeok != Sizeok.none)
+ return 1;
+
+ if (v.aliassym)
+ return 0; // If this variable was really a tuple, skip it.
+
+ if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter))
+ return 0;
+ if (!v.isField() || v.semanticRun < PASS.semanticdone)
+ return 1; // unresolvable forward reference
+
+ ad.fields.push(v);
+
+ if (v.storage_class & STC.ref_)
+ return 0;
+ auto tv = v.type.baseElemOf();
+ if (auto tvs = tv.isTypeStruct())
+ {
+ if (ad == tvs.sym)
+ {
+ const(char)* psz = (v.type.toBasetype().ty == Tsarray) ? "static array of " : "";
+ ad.error("cannot have field `%s` with %ssame struct type", v.toChars(), psz);
+ ad.type = Type.terror;
+ ad.errors = true;
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ if (ad.members)
+ {
+ for (size_t i = 0; i < ad.members.dim; i++)
+ {
+ auto s = (*ad.members)[i];
+ if (s.apply(&func, ad))
+ {
+ if (ad.sizeok != Sizeok.none)
+ {
+ // recursive determineFields already finished
+ return true;
+ }
+ return false;
+ }
+ }
+ }
+
+ if (ad.sizeok != Sizeok.done)
+ ad.sizeok = Sizeok.fwd;
+
+ return true;
+}
diff --git a/gcc/d/dmd/dtemplate.c b/gcc/d/dmd/dtemplate.c
deleted file mode 100644
index 20036f2..0000000
--- a/gcc/d/dmd/dtemplate.c
+++ /dev/null
@@ -1,7581 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/template.c
- */
-
-// Handle template implementation
-
-#include "root/dsystem.h"
-#include "root/root.h"
-#include "root/aav.h"
-#include "root/rmem.h"
-#include "root/stringtable.h"
-#include "root/hash.h"
-
-#include "mangle.h"
-#include "mtype.h"
-#include "template.h"
-#include "init.h"
-#include "expression.h"
-#include "scope.h"
-#include "module.h"
-#include "aggregate.h"
-#include "declaration.h"
-#include "dsymbol.h"
-#include "mars.h"
-#include "dsymbol.h"
-#include "identifier.h"
-#include "hdrgen.h"
-#include "id.h"
-#include "attrib.h"
-#include "cond.h"
-#include "tokens.h"
-
-#define IDX_NOTFOUND (0x12345678) // index is not found
-
-Type *rawTypeMerge(Type *t1, Type *t2);
-bool MODimplicitConv(MOD modfrom, MOD modto);
-MATCH MODmethodConv(MOD modfrom, MOD modto);
-MOD MODmerge(MOD mod1, MOD mod2);
-
-static size_t templateParameterLookup(Type *tparam, TemplateParameters *parameters);
-static int arrayObjectMatch(Objects *oa1, Objects *oa2);
-static unsigned char deduceWildHelper(Type *t, Type **at, Type *tparam);
-static MATCH deduceTypeHelper(Type *t, Type **at, Type *tparam);
-bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0);
-bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
-
-/********************************************
- * These functions substitute for dynamic_cast. dynamic_cast does not work
- * on earlier versions of gcc.
- */
-
-Expression *isExpression(RootObject *o)
-{
- //return dynamic_cast<Expression *>(o);
- if (!o || o->dyncast() != DYNCAST_EXPRESSION)
- return NULL;
- return (Expression *)o;
-}
-
-Dsymbol *isDsymbol(RootObject *o)
-{
- //return dynamic_cast<Dsymbol *>(o);
- if (!o || o->dyncast() != DYNCAST_DSYMBOL)
- return NULL;
- return (Dsymbol *)o;
-}
-
-Type *isType(RootObject *o)
-{
- //return dynamic_cast<Type *>(o);
- if (!o || o->dyncast() != DYNCAST_TYPE)
- return NULL;
- return (Type *)o;
-}
-
-Tuple *isTuple(RootObject *o)
-{
- //return dynamic_cast<Tuple *>(o);
- if (!o || o->dyncast() != DYNCAST_TUPLE)
- return NULL;
- return (Tuple *)o;
-}
-
-Parameter *isParameter(RootObject *o)
-{
- //return dynamic_cast<Parameter *>(o);
- if (!o || o->dyncast() != DYNCAST_PARAMETER)
- return NULL;
- return (Parameter *)o;
-}
-
-/**************************************
- * Is this Object an error?
- */
-bool isError(RootObject *o)
-{
- Type *t = isType(o);
- if (t)
- return (t->ty == Terror);
- Expression *e = isExpression(o);
- if (e)
- return (e->op == TOKerror || !e->type || e->type->ty == Terror);
- Tuple *v = isTuple(o);
- if (v)
- return arrayObjectIsError(&v->objects);
- Dsymbol *s = isDsymbol(o);
- assert(s);
- if (s->errors)
- return true;
- return s->parent ? isError(s->parent) : false;
-}
-
-/**************************************
- * Are any of the Objects an error?
- */
-bool arrayObjectIsError(Objects *args)
-{
- for (size_t i = 0; i < args->length; i++)
- {
- RootObject *o = (*args)[i];
- if (isError(o))
- return true;
- }
- return false;
-}
-
-/***********************
- * Try to get arg as a type.
- */
-
-Type *getType(RootObject *o)
-{
- Type *t = isType(o);
- if (!t)
- {
- Expression *e = isExpression(o);
- if (e)
- t = e->type;
- }
- return t;
-}
-
-Dsymbol *getDsymbol(RootObject *oarg)
-{
- //printf("getDsymbol()\n");
- //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg));
-
- Dsymbol *sa;
- Expression *ea = isExpression(oarg);
- if (ea)
- {
- // Try to convert Expression to symbol
- if (VarExp *ve = ea->isVarExp())
- sa = ve->var;
- else if (FuncExp *fe = ea->isFuncExp())
- sa = fe->td ? (Dsymbol *)fe->td : (Dsymbol *)fe->fd;
- else if (TemplateExp *te = ea->isTemplateExp())
- sa = te->td;
- else if (ScopeExp *se = ea->isScopeExp())
- sa = se->sds;
- else
- sa = NULL;
- }
- else
- {
- // Try to convert Type to symbol
- Type *ta = isType(oarg);
- if (ta)
- sa = ta->toDsymbol(NULL);
- else
- sa = isDsymbol(oarg); // if already a symbol
- }
- return sa;
-}
-
-/***********************
- * Try to get value from manifest constant
- */
-
-static Expression *getValue(Expression *e)
-{
- if (e && e->op == TOKvar)
- {
- VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
- if (v && v->storage_class & STCmanifest)
- {
- e = v->getConstInitializer();
- }
- }
- return e;
-}
-
-static Expression *getValue(Dsymbol *&s)
-{
- Expression *e = NULL;
- if (s)
- {
- VarDeclaration *v = s->isVarDeclaration();
- if (v && v->storage_class & STCmanifest)
- {
- e = v->getConstInitializer();
- }
- }
- return e;
-}
-
-/**********************************
- * Return true if e could be valid only as a template value parameter.
- * Return false if it might be an alias or tuple.
- * (Note that even in this case, it could still turn out to be a value).
- */
-bool definitelyValueParameter(Expression *e)
-{
- // None of these can be value parameters
- if (e->op == TOKtuple || e->op == TOKscope ||
- e->op == TOKtype || e->op == TOKdottype ||
- e->op == TOKtemplate || e->op == TOKdottd ||
- e->op == TOKfunction || e->op == TOKerror ||
- e->op == TOKthis || e->op == TOKsuper ||
- e->op == TOKdot)
- return false;
-
- if (e->op != TOKdotvar)
- return true;
-
- /* Template instantiations involving a DotVar expression are difficult.
- * In most cases, they should be treated as a value parameter, and interpreted.
- * But they might also just be a fully qualified name, which should be treated
- * as an alias.
- */
-
- // x.y.f cannot be a value
- FuncDeclaration *f = ((DotVarExp *)e)->var->isFuncDeclaration();
- if (f)
- return false;
-
- while (e->op == TOKdotvar)
- {
- e = ((DotVarExp *)e)->e1;
- }
- // this.x.y and super.x.y couldn't possibly be valid values.
- if (e->op == TOKthis || e->op == TOKsuper)
- return false;
-
- // e.type.x could be an alias
- if (e->op == TOKdottype)
- return false;
-
- // var.x.y is the only other possible form of alias
- if (e->op != TOKvar)
- return true;
-
- VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
-
- // func.x.y is not an alias
- if (!v)
- return true;
-
- // TODO: Should we force CTFE if it is a global constant?
-
- return false;
-}
-
-static Expression *getExpression(RootObject *o)
-{
- Dsymbol *s = isDsymbol(o);
- return s ? getValue(s) : getValue(isExpression(o));
-}
-
-/******************************
- * If o1 matches o2, return true.
- * Else, return false.
- */
-
-static bool match(RootObject *o1, RootObject *o2)
-{
- //printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n",
- // o1, o1->toChars(), o1->dyncast(), o2, o2->toChars(), o2->dyncast());
-
- /* A proper implementation of the various equals() overrides
- * should make it possible to just do o1->equals(o2), but
- * we'll do that another day.
- */
-
- /* Manifest constants should be compared by their values,
- * at least in template arguments.
- */
-
- if (Type *t1 = isType(o1))
- {
- Type *t2 = isType(o2);
- if (!t2)
- goto Lnomatch;
-
- //printf("\tt1 = %s\n", t1->toChars());
- //printf("\tt2 = %s\n", t2->toChars());
- if (!t1->equals(t2))
- goto Lnomatch;
-
- goto Lmatch;
- }
- if (Expression *e1 = getExpression(o1))
- {
- Expression *e2 = getExpression(o2);
- if (!e2)
- goto Lnomatch;
-
- //printf("\te1 = %s %s %s\n", e1->type->toChars(), Token::toChars(e1->op), e1->toChars());
- //printf("\te2 = %s %s %s\n", e2->type->toChars(), Token::toChars(e2->op), e2->toChars());
-
- // two expressions can be equal although they do not have the same
- // type; that happens when they have the same value. So check type
- // as well as expression equality to ensure templates are properly
- // matched.
- if (!e1->type->equals(e2->type) || !e1->equals(e2))
- goto Lnomatch;
-
- goto Lmatch;
- }
- if (Dsymbol *s1 = isDsymbol(o1))
- {
- Dsymbol *s2 = isDsymbol(o2);
- if (!s2)
- goto Lnomatch;
-
- //printf("\ts1 = %s\n", s1->toChars());
- //printf("\ts2 = %s\n", s2->toChars());
- if (!s1->equals(s2))
- goto Lnomatch;
- if (s1->parent != s2->parent && !s1->isFuncDeclaration() && !s2->isFuncDeclaration())
- goto Lnomatch;
-
- goto Lmatch;
- }
- if (Tuple *u1 = isTuple(o1))
- {
- Tuple *u2 = isTuple(o2);
- if (!u2)
- goto Lnomatch;
-
- //printf("\tu1 = %s\n", u1->toChars());
- //printf("\tu2 = %s\n", u2->toChars());
- if (!arrayObjectMatch(&u1->objects, &u2->objects))
- goto Lnomatch;
-
- goto Lmatch;
- }
-Lmatch:
- //printf("\t-> match\n");
- return true;
-
-Lnomatch:
- //printf("\t-> nomatch\n");
- return false;
-}
-
-
-/************************************
- * Match an array of them.
- */
-int arrayObjectMatch(Objects *oa1, Objects *oa2)
-{
- if (oa1 == oa2)
- return 1;
- if (oa1->length != oa2->length)
- return 0;
- for (size_t j = 0; j < oa1->length; j++)
- {
- RootObject *o1 = (*oa1)[j];
- RootObject *o2 = (*oa2)[j];
- if (!match(o1, o2))
- {
- return 0;
- }
- }
- return 1;
-}
-
-
-/************************************
- * Computes hash of expression.
- * Handles all Expression classes and MUST match their equals method,
- * i.e. e1->equals(e2) implies expressionHash(e1) == expressionHash(e2).
- */
-static hash_t expressionHash(Expression *e)
-{
- switch (e->op)
- {
- case TOKint64:
- return (size_t) ((IntegerExp *)e)->getInteger();
-
- case TOKfloat64:
- return CTFloat::hash(((RealExp *)e)->value);
-
- case TOKcomplex80:
- {
- ComplexExp *ce = (ComplexExp *)e;
- return mixHash(CTFloat::hash(ce->toReal()), CTFloat::hash(ce->toImaginary()));
- }
-
- case TOKidentifier:
- return (size_t)(void *) ((IdentifierExp *)e)->ident;
-
- case TOKnull:
- return (size_t)(void *) ((NullExp *)e)->type;
-
- case TOKstring:
- {
- StringExp *se = (StringExp *)e;
- return calcHash((const char *)se->string, se->len * se->sz);
- }
-
- case TOKtuple:
- {
- TupleExp *te = (TupleExp *)e;
- size_t hash = 0;
- hash += te->e0 ? expressionHash(te->e0) : 0;
- for (size_t i = 0; i < te->exps->length; i++)
- {
- Expression *elem = (*te->exps)[i];
- hash = mixHash(hash, expressionHash(elem));
- }
- return hash;
- }
-
- case TOKarrayliteral:
- {
- ArrayLiteralExp *ae = (ArrayLiteralExp *)e;
- size_t hash = 0;
- for (size_t i = 0; i < ae->elements->length; i++)
- hash = mixHash(hash, expressionHash(ae->getElement(i)));
- return hash;
- }
-
- case TOKassocarrayliteral:
- {
- AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
- size_t hash = 0;
- for (size_t i = 0; i < ae->keys->length; i++)
- // reduction needs associative op as keys are unsorted (use XOR)
- hash ^= mixHash(expressionHash((*ae->keys)[i]), expressionHash((*ae->values)[i]));
- return hash;
- }
-
- case TOKstructliteral:
- {
- StructLiteralExp *se = (StructLiteralExp *)e;
- size_t hash = 0;
- for (size_t i = 0; i < se->elements->length; i++)
- {
- Expression *elem = (*se->elements)[i];
- hash = mixHash(hash, elem ? expressionHash(elem) : 0);
- }
- return hash;
- }
-
- case TOKvar:
- return (size_t)(void *) ((VarExp *)e)->var;
-
- case TOKfunction:
- return (size_t)(void *) ((FuncExp *)e)->fd;
-
- default:
- // no custom equals for this expression
- // equals based on identity
- return (size_t)(void *) e;
- }
-}
-
-
-/************************************
- * Return hash of Objects.
- */
-static hash_t arrayObjectHash(Objects *oa1)
-{
- hash_t hash = 0;
- for (size_t j = 0; j < oa1->length; j++)
- {
- /* Must follow the logic of match()
- */
- RootObject *o1 = (*oa1)[j];
- if (Type *t1 = isType(o1))
- hash = mixHash(hash, (size_t)t1->deco);
- else if (Expression *e1 = getExpression(o1))
- hash = mixHash(hash, expressionHash(e1));
- else if (Dsymbol *s1 = isDsymbol(o1))
- {
- FuncAliasDeclaration *fa1 = s1->isFuncAliasDeclaration();
- if (fa1)
- s1 = fa1->toAliasFunc();
- hash = mixHash(hash, mixHash((size_t)(void *)s1->getIdent(), (size_t)(void *)s1->parent));
- }
- else if (Tuple *u1 = isTuple(o1))
- hash = mixHash(hash, arrayObjectHash(&u1->objects));
- }
- return hash;
-}
-
-RootObject *objectSyntaxCopy(RootObject *o)
-{
- if (!o)
- return NULL;
- if (Type *t = isType(o))
- return t->syntaxCopy();
- if (Expression *e = isExpression(o))
- return e->syntaxCopy();
- return o;
-}
-
-
-/* ======================== TemplateDeclaration ============================= */
-
-TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id,
- TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs, bool ismixin, bool literal)
- : ScopeDsymbol(id)
-{
- this->loc = loc;
- this->parameters = parameters;
- this->origParameters = parameters;
- this->constraint = constraint;
- this->members = decldefs;
- this->overnext = NULL;
- this->overroot = NULL;
- this->funcroot = NULL;
- this->onemember = NULL;
- this->literal = literal;
- this->ismixin = ismixin;
- this->isstatic = true;
- this->isTrivialAliasSeq = false;
- this->isTrivialAlias = false;
- this->previous = NULL;
- this->protection = Prot(Prot::undefined);
- this->inuse = 0;
- this->instances = NULL;
-
- // Compute in advance for Ddoc's use
- // Bugzilla 11153: ident could be NULL if parsing fails.
- if (!members || !ident)
- return;
-
- Dsymbol *s;
- if (!Dsymbol::oneMembers(members, &s, ident) || !s)
- return;
-
- onemember = s;
- s->parent = this;
-
- /* Set isTrivialAliasSeq if this fits the pattern:
- * template AliasSeq(T...) { alias AliasSeq = T; }
- * or set isTrivialAlias if this fits the pattern:
- * template Alias(T) { alias Alias = qualifiers(T); }
- */
- if (!(parameters && parameters->length == 1))
- return;
-
- AliasDeclaration *ad = s->isAliasDeclaration();
- if (!ad || !ad->type)
- return;
-
- TypeIdentifier *ti = ad->type->isTypeIdentifier();
- if (!ti || ti->idents.length != 0)
- return;
-
- if (TemplateTupleParameter *ttp = (*parameters)[0]->isTemplateTupleParameter())
- {
- if (ti->ident == ttp->ident && ti->mod == 0)
- {
- //printf("found isAliasSeq %s %s\n", s->toChars(), ad->type->toChars());
- isTrivialAliasSeq = true;
- }
- }
- else if (TemplateTypeParameter *ttp = (*parameters)[0]->isTemplateTypeParameter())
- {
- if (ti->ident == ttp->ident)
- {
- //printf("found isAlias %s %s\n", s->toChars(), ad->type->toChars());
- isTrivialAlias = true;
- }
- }
-}
-
-Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *)
-{
- //printf("TemplateDeclaration::syntaxCopy()\n");
- TemplateParameters *p = NULL;
- if (parameters)
- {
- p = new TemplateParameters();
- p->setDim(parameters->length);
- for (size_t i = 0; i < p->length; i++)
- (*p)[i] = (*parameters)[i]->syntaxCopy();
- }
- return new TemplateDeclaration(loc, ident, p,
- constraint ? constraint->syntaxCopy() : NULL,
- Dsymbol::arraySyntaxCopy(members), ismixin, literal);
-}
-
-const char *TemplateDeclaration::kind() const
-{
- return (onemember && onemember->isAggregateDeclaration())
- ? onemember->kind()
- : "template";
-}
-
-/**********************************
- * Overload existing TemplateDeclaration 'this' with the new one 's'.
- * Return true if successful; i.e. no conflict.
- */
-
-bool TemplateDeclaration::overloadInsert(Dsymbol *s)
-{
- FuncDeclaration *fd = s->isFuncDeclaration();
- if (fd)
- {
- if (funcroot)
- return funcroot->overloadInsert(fd);
- funcroot = fd;
- return funcroot->overloadInsert(this);
- }
-
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (!td)
- return false;
-
- TemplateDeclaration *pthis = this;
- TemplateDeclaration **ptd;
- for (ptd = &pthis; *ptd; ptd = &(*ptd)->overnext)
- {
- }
-
- td->overroot = this;
- *ptd = td;
- return true;
-}
-
-/****************************
- * Check to see if constraint is satisfied.
- */
-bool TemplateDeclaration::evaluateConstraint(
- TemplateInstance *ti, Scope *sc, Scope *paramscope,
- Objects *dedargs, FuncDeclaration *fd)
-{
- /* Detect recursive attempts to instantiate this template declaration,
- * Bugzilla 4072
- * void foo(T)(T x) if (is(typeof(foo(x)))) { }
- * static assert(!is(typeof(foo(7))));
- * Recursive attempts are regarded as a constraint failure.
- */
- /* There's a chicken-and-egg problem here. We don't know yet if this template
- * instantiation will be a local one (enclosing is set), and we won't know until
- * after selecting the correct template. Thus, function we're nesting inside
- * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel().
- * Workaround the problem by setting a flag to relax the checking on frame errors.
- */
-
- for (TemplatePrevious *p = previous; p; p = p->prev)
- {
- if (arrayObjectMatch(p->dedargs, dedargs))
- {
- //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars());
- /* It must be a subscope of p->sc, other scope chains are not recursive
- * instantiations.
- */
- for (Scope *scx = sc; scx; scx = scx->enclosing)
- {
- if (scx == p->sc)
- return false;
- }
- }
- /* BUG: should also check for ref param differences
- */
- }
-
- TemplatePrevious pr;
- pr.prev = previous;
- pr.sc = paramscope;
- pr.dedargs = dedargs;
- previous = &pr; // add this to threaded list
-
- Scope *scx = paramscope->push(ti);
- scx->parent = ti;
- scx->tinst = NULL;
- scx->minst = NULL;
-
- assert(!ti->symtab);
- if (fd)
- {
- /* Declare all the function parameters as variables and add them to the scope
- * Making parameters is similar to FuncDeclaration::semantic3
- */
- TypeFunction *tf = (TypeFunction *)fd->type;
- assert(tf->ty == Tfunction);
-
- scx->parent = fd;
-
- Parameters *fparameters = tf->parameterList.parameters;
- VarArg fvarargs = tf->parameterList.varargs;
-
- size_t nfparams = Parameter::dim(fparameters);
- for (size_t i = 0; i < nfparams; i++)
- {
- Parameter *fparam = Parameter::getNth(fparameters, i);
- fparam->storageClass &= (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor);
- fparam->storageClass |= STCparameter;
- if (fvarargs == VARARGtypesafe && i + 1 == nfparams)
- fparam->storageClass |= STCvariadic;
- }
- for (size_t i = 0; i < fparameters->length; i++)
- {
- Parameter *fparam = (*fparameters)[i];
- if (!fparam->ident)
- continue; // don't add it, if it has no name
- VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL);
- v->storage_class = fparam->storageClass;
- dsymbolSemantic(v, scx);
- if (!ti->symtab)
- ti->symtab = new DsymbolTable();
- if (!scx->insert(v))
- error("parameter %s.%s is already defined", toChars(), v->toChars());
- else
- v->parent = fd;
- }
- if (isstatic)
- fd->storage_class |= STCstatic;
-
- fd->vthis = fd->declareThis(scx, fd->isThis());
- }
-
- Expression *e = constraint->syntaxCopy();
-
- assert(ti->inst == NULL);
- ti->inst = ti; // temporary instantiation to enable genIdent()
-
- scx->flags |= SCOPEconstraint;
- bool errors = false;
- bool result = evalStaticCondition(scx, constraint, e, errors);
- ti->inst = NULL;
- ti->symtab = NULL;
- scx = scx->pop();
- previous = pr.prev; // unlink from threaded list
- if (errors)
- return false;
- return result;
-}
-
-/***************************************
- * Given that ti is an instance of this TemplateDeclaration,
- * deduce the types of the parameters to this, and store
- * those deduced types in dedtypes[].
- * Input:
- * flag 1: don't do semantic() because of dummy types
- * 2: don't change types in matchArg()
- * Output:
- * dedtypes deduced arguments
- * Return match level.
- */
-
-MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti,
- Objects *dedtypes, Expressions *fargs, int flag)
-{
- MATCH m;
- size_t dedtypes_dim = dedtypes->length;
-
- dedtypes->zero();
-
- if (errors)
- return MATCHnomatch;
-
- size_t parameters_dim = parameters->length;
- int variadic = isVariadic() != NULL;
-
- // If more arguments than parameters, no match
- if (ti->tiargs->length > parameters_dim && !variadic)
- {
- return MATCHnomatch;
- }
-
- assert(dedtypes_dim == parameters_dim);
- assert(dedtypes_dim >= ti->tiargs->length || variadic);
-
- assert(_scope);
-
- // Set up scope for template parameters
- ScopeDsymbol *paramsym = new ScopeDsymbol();
- paramsym->parent = _scope->parent;
- Scope *paramscope = _scope->push(paramsym);
- paramscope->tinst = ti;
- paramscope->minst = sc->minst;
- paramscope->callsc = sc;
- paramscope->stc = 0;
-
- // Attempt type deduction
- m = MATCHexact;
- for (size_t i = 0; i < dedtypes_dim; i++)
- {
- MATCH m2;
- TemplateParameter *tp = (*parameters)[i];
- Declaration *sparam;
-
- //printf("\targument [%d]\n", i);
- inuse++;
- m2 = tp->matchArg(ti->loc, paramscope, ti->tiargs, i, parameters, dedtypes, &sparam);
- inuse--;
- //printf("\tm2 = %d\n", m2);
-
- if (m2 == MATCHnomatch)
- {
- goto Lnomatch;
- }
-
- if (m2 < m)
- m = m2;
-
- if (!flag)
- dsymbolSemantic(sparam, paramscope);
- if (!paramscope->insert(sparam)) // TODO: This check can make more early
- goto Lnomatch; // in TemplateDeclaration::semantic, and
- // then we don't need to make sparam if flags == 0
- }
-
- if (!flag)
- {
- /* Any parameter left without a type gets the type of
- * its corresponding arg
- */
- for (size_t i = 0; i < dedtypes_dim; i++)
- {
- if (!(*dedtypes)[i])
- {
- assert(i < ti->tiargs->length);
- (*dedtypes)[i] = (Type *)(*ti->tiargs)[i];
- }
- }
- }
-
- if (m > MATCHnomatch && constraint && !flag)
- {
- if (ti->hasNestedArgs(ti->tiargs, this->isstatic)) // TODO: should gag error
- ti->parent = ti->enclosing;
- else
- ti->parent = this->parent;
-
- // Similar to doHeaderInstantiation
- FuncDeclaration *fd = onemember ? onemember->isFuncDeclaration() : NULL;
- if (fd)
- {
- assert(fd->type->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)fd->type->syntaxCopy();
-
- fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, tf);
- fd->parent = ti;
- fd->inferRetType = true;
-
- // Shouldn't run semantic on default arguments and return type.
- for (size_t i = 0; i < tf->parameterList.parameters->length; i++)
- (*tf->parameterList.parameters)[i]->defaultArg = NULL;
- tf->next = NULL;
-
- // Resolve parameter types and 'auto ref's.
- tf->fargs = fargs;
- unsigned olderrors = global.startGagging();
- fd->type = typeSemantic(tf, loc, paramscope);
- if (global.endGagging(olderrors))
- {
- assert(fd->type->ty != Tfunction);
- goto Lnomatch;
- }
- assert(fd->type->ty == Tfunction);
- fd->originalType = fd->type; // for mangling
- }
-
- // TODO: dedtypes => ti->tiargs ?
- if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd))
- goto Lnomatch;
- }
-
- goto Lret;
-
-Lnomatch:
- m = MATCHnomatch;
-
-Lret:
- paramscope->pop();
- return m;
-}
-
-/********************************************
- * Determine partial specialization order of 'this' vs td2.
- * Returns:
- * match this is at least as specialized as td2
- * 0 td2 is more specialized than this
- */
-
-MATCH TemplateDeclaration::leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs)
-{
- /* This works by taking the template parameters to this template
- * declaration and feeding them to td2 as if it were a template
- * instance.
- * If it works, then this template is at least as specialized
- * as td2.
- */
-
- TemplateInstance ti(Loc(), ident); // create dummy template instance
- // Set type arguments to dummy template instance to be types
- // generated from the parameters to this template declaration
- ti.tiargs = new Objects();
- ti.tiargs->reserve(parameters->length);
- for (size_t i = 0; i < parameters->length; i++)
- {
- TemplateParameter *tp = (*parameters)[i];
- if (tp->dependent)
- break;
- RootObject *p = (RootObject *)tp->dummyArg();
- if (!p)
- break;
-
- ti.tiargs->push(p);
- }
-
- // Temporary Array to hold deduced types
- Objects dedtypes;
- dedtypes.setDim(td2->parameters->length);
-
- // Attempt a type deduction
- MATCH m = td2->matchWithInstance(sc, &ti, &dedtypes, fargs, 1);
- if (m > MATCHnomatch)
- {
- /* A non-variadic template is more specialized than a
- * variadic one.
- */
- TemplateTupleParameter *tp = isVariadic();
- if (tp && !tp->dependent && !td2->isVariadic())
- goto L1;
-
- return m;
- }
- L1:
- return MATCHnomatch;
-}
-
-static Expression *emptyArrayElement = NULL;
-
-class TypeDeduced : public Type
-{
-public:
- Type *tded;
- Expressions argexps; // corresponding expressions
- Types tparams; // tparams[i]->mod
-
- TypeDeduced(Type *tt, Expression *e, Type *tparam)
- : Type(Tnone)
- {
- tded = tt;
- argexps.push(e);
- tparams.push(tparam);
- }
-
- virtual ~TypeDeduced()
- {
- }
-
- void update(Expression *e, Type *tparam)
- {
- argexps.push(e);
- tparams.push(tparam);
- }
- void update(Type *tt, Expression *e, Type *tparam)
- {
- tded = tt;
- argexps.push(e);
- tparams.push(tparam);
- }
- MATCH matchAll(Type *tt)
- {
- MATCH match = MATCHexact;
- for (size_t j = 0; j < argexps.length; j++)
- {
- Expression *e = argexps[j];
- assert(e);
- if (e == emptyArrayElement)
- continue;
-
- Type *t = tt->addMod(tparams[j]->mod)->substWildTo(MODconst);
-
- MATCH m = e->implicitConvTo(t);
- if (match > m)
- match = m;
- if (match <= MATCHnomatch)
- break;
- }
- return match;
- }
-};
-
-/*************************************************
- * Match function arguments against a specific template function.
- * Input:
- * ti
- * sc instantiation scope
- * fd
- * tthis 'this' argument if !NULL
- * fargs arguments to function
- * Output:
- * fd Partially instantiated function declaration
- * ti->tdtypes Expression/Type deduced template arguments
- * Returns:
- * match level
- * bit 0-3 Match template parameters by inferred template arguments
- * bit 4-7 Match template parameters by initial template arguments
- */
-
-MATCH TemplateDeclaration::deduceFunctionTemplateMatch(
- TemplateInstance *ti, Scope *sc,
- FuncDeclaration *&fd, Type *tthis, Expressions *fargs)
-{
- size_t nfparams;
- size_t nfargs;
- size_t ntargs; // array size of tiargs
- size_t fptupindex = IDX_NOTFOUND;
- MATCH match = MATCHexact;
- MATCH matchTiargs = MATCHexact;
- ParameterList fparameters; // function parameter list
- unsigned wildmatch = 0;
- size_t inferStart = 0;
-
- Loc instLoc = ti->loc;
- Objects *tiargs = ti->tiargs;
- Objects *dedargs = new Objects();
- Objects* dedtypes = &ti->tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T
-
- assert(_scope);
-
- dedargs->setDim(parameters->length);
- dedargs->zero();
-
- dedtypes->setDim(parameters->length);
- dedtypes->zero();
-
- if (errors || fd->errors)
- return MATCHnomatch;
-
- // Set up scope for parameters
- ScopeDsymbol *paramsym = new ScopeDsymbol();
- paramsym->parent = _scope->parent; // should use hasnestedArgs and enclosing?
- Scope *paramscope = _scope->push(paramsym);
- paramscope->tinst = ti;
- paramscope->minst = sc->minst;
- paramscope->callsc = sc;
- paramscope->stc = 0;
-
- TemplateTupleParameter *tp = isVariadic();
- Tuple *declaredTuple = NULL;
-
- ntargs = 0;
- if (tiargs)
- {
- // Set initial template arguments
- ntargs = tiargs->length;
- size_t n = parameters->length;
- if (tp)
- n--;
- if (ntargs > n)
- {
- if (!tp)
- goto Lnomatch;
-
- /* The extra initial template arguments
- * now form the tuple argument.
- */
- Tuple *t = new Tuple();
- assert(parameters->length);
- (*dedargs)[parameters->length - 1] = t;
-
- t->objects.setDim(ntargs - n);
- for (size_t i = 0; i < t->objects.length; i++)
- {
- t->objects[i] = (*tiargs)[n + i];
- }
- declareParameter(paramscope, tp, t);
- declaredTuple = t;
- }
- else
- n = ntargs;
-
- memcpy(dedargs->tdata(), tiargs->tdata(), n * sizeof(*dedargs->tdata()));
-
- for (size_t i = 0; i < n; i++)
- {
- assert(i < parameters->length);
- Declaration *sparam = NULL;
- MATCH m = (*parameters)[i]->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam);
- //printf("\tdeduceType m = %d\n", m);
- if (m <= MATCHnomatch)
- goto Lnomatch;
- if (m < matchTiargs)
- matchTiargs = m;
-
- dsymbolSemantic(sparam, paramscope);
- if (!paramscope->insert(sparam))
- goto Lnomatch;
- }
- if (n < parameters->length && !declaredTuple)
- {
- inferStart = n;
- }
- else
- inferStart = parameters->length;
- //printf("tiargs matchTiargs = %d\n", matchTiargs);
- }
-
- fparameters = fd->getParameterList();
- nfparams = fparameters.length(); // number of function parameters
- nfargs = fargs ? fargs->length : 0; // number of function arguments
-
- /* Check for match of function arguments with variadic template
- * parameter, such as:
- *
- * void foo(T, A...)(T t, A a);
- * void main() { foo(1,2,3); }
- */
- if (tp) // if variadic
- {
- // TemplateTupleParameter always makes most lesser matching.
- matchTiargs = MATCHconvert;
-
- if (nfparams == 0 && nfargs != 0) // if no function parameters
- {
- if (!declaredTuple)
- {
- Tuple *t = new Tuple();
- //printf("t = %p\n", t);
- (*dedargs)[parameters->length - 1] = t;
- declareParameter(paramscope, tp, t);
- declaredTuple = t;
- }
- }
- else
- {
- /* Figure out which of the function parameters matches
- * the tuple template parameter. Do this by matching
- * type identifiers.
- * Set the index of this function parameter to fptupindex.
- */
- for (fptupindex = 0; fptupindex < nfparams; fptupindex++)
- {
- Parameter *fparam = (*fparameters.parameters)[fptupindex];
- if (fparam->type->ty != Tident)
- continue;
- TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
- if (!tp->ident->equals(tid->ident) || tid->idents.length)
- continue;
-
- if (fparameters.varargs != VARARGnone) // variadic function doesn't
- goto Lnomatch; // go with variadic template
-
- goto L1;
- }
- fptupindex = IDX_NOTFOUND;
- L1:
- ;
- }
- }
-
- if (toParent()->isModule() || (_scope->stc & STCstatic))
- tthis = NULL;
- if (tthis)
- {
- bool hasttp = false;
-
- // Match 'tthis' to any TemplateThisParameter's
- for (size_t i = 0; i < parameters->length; i++)
- {
- TemplateThisParameter *ttp = (*parameters)[i]->isTemplateThisParameter();
- if (ttp)
- {
- hasttp = true;
-
- Type *t = new TypeIdentifier(Loc(), ttp->ident);
- MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes);
- if (m <= MATCHnomatch)
- goto Lnomatch;
- if (m < match)
- match = m; // pick worst match
- }
- }
-
- // Match attributes of tthis against attributes of fd
- if (fd->type && !fd->isCtorDeclaration())
- {
- StorageClass stc = _scope->stc | fd->storage_class2;
- // Propagate parent storage class (see bug 5504)
- Dsymbol *p = parent;
- while (p->isTemplateDeclaration() || p->isTemplateInstance())
- p = p->parent;
- AggregateDeclaration *ad = p->isAggregateDeclaration();
- if (ad)
- stc |= ad->storage_class;
-
- unsigned char mod = fd->type->mod;
- if (stc & STCimmutable)
- mod = MODimmutable;
- else
- {
- if (stc & (STCshared | STCsynchronized))
- mod |= MODshared;
- if (stc & STCconst)
- mod |= MODconst;
- if (stc & STCwild)
- mod |= MODwild;
- }
-
- unsigned char thismod = tthis->mod;
- if (hasttp)
- mod = MODmerge(thismod, mod);
- MATCH m = MODmethodConv(thismod, mod);
- if (m <= MATCHnomatch)
- goto Lnomatch;
- if (m < match)
- match = m;
- }
- }
-
- // Loop through the function parameters
- {
- //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple->objects.length : 0);
- //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple->toChars() : NULL);
- size_t argi = 0;
- size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs
- for (size_t parami = 0; parami < nfparams; parami++)
- {
- Parameter *fparam = fparameters[parami];
-
- // Apply function parameter storage classes to parameter types
- Type *prmtype = fparam->type->addStorageClass(fparam->storageClass);
-
- Expression *farg;
-
- /* See function parameters which wound up
- * as part of a template tuple parameter.
- */
- if (fptupindex != IDX_NOTFOUND && parami == fptupindex)
- {
- assert(prmtype->ty == Tident);
- TypeIdentifier *tid = (TypeIdentifier *)prmtype;
- if (!declaredTuple)
- {
- /* The types of the function arguments
- * now form the tuple argument.
- */
- declaredTuple = new Tuple();
- (*dedargs)[parameters->length - 1] = declaredTuple;
-
- /* Count function parameters following a tuple parameter.
- * void foo(U, T...)(int y, T, U, int) {} // rem == 2 (U, int)
- */
- size_t rem = 0;
- for (size_t j = parami + 1; j < nfparams; j++)
- {
- Parameter *p = fparameters[j];
- if (!reliesOnTident(p->type, parameters, inferStart))
- {
- Type *pt = typeSemantic(p->type->syntaxCopy(), fd->loc, paramscope);
- rem += pt->ty == Ttuple ? ((TypeTuple *)pt)->arguments->length : 1;
- }
- else
- {
- ++rem;
- }
- }
-
- if (nfargs2 - argi < rem)
- goto Lnomatch;
- declaredTuple->objects.setDim(nfargs2 - argi - rem);
- for (size_t i = 0; i < declaredTuple->objects.length; i++)
- {
- farg = (*fargs)[argi + i];
-
- // Check invalid arguments to detect errors early.
- if (farg->op == TOKerror || farg->type->ty == Terror)
- goto Lnomatch;
-
- if (!(fparam->storageClass & STClazy) && farg->type->ty == Tvoid)
- goto Lnomatch;
-
- Type *tt;
- MATCH m;
- if (unsigned char wm = deduceWildHelper(farg->type, &tt, tid))
- {
- wildmatch |= wm;
- m = MATCHconst;
- }
- else
- {
- m = deduceTypeHelper(farg->type, &tt, tid);
- }
- if (m <= MATCHnomatch)
- goto Lnomatch;
- if (m < match)
- match = m;
-
- /* Remove top const for dynamic array types and pointer types
- */
- if ((tt->ty == Tarray || tt->ty == Tpointer) &&
- !tt->isMutable() &&
- (!(fparam->storageClass & STCref) ||
- ((fparam->storageClass & STCauto) && !farg->isLvalue())))
- {
- tt = tt->mutableOf();
- }
- declaredTuple->objects[i] = tt;
- }
- declareParameter(paramscope, tp, declaredTuple);
- }
- else
- {
- // Bugzilla 6810: If declared tuple is not a type tuple,
- // it cannot be function parameter types.
- for (size_t i = 0; i < declaredTuple->objects.length; i++)
- {
- if (!isType(declaredTuple->objects[i]))
- goto Lnomatch;
- }
- }
- assert(declaredTuple);
- argi += declaredTuple->objects.length;
- continue;
- }
-
- // If parameter type doesn't depend on inferred template parameters,
- // semantic it to get actual type.
- if (!reliesOnTident(prmtype, parameters, inferStart))
- {
- // should copy prmtype to avoid affecting semantic result
- prmtype = typeSemantic(prmtype->syntaxCopy(), fd->loc, paramscope);
-
- if (prmtype->ty == Ttuple)
- {
- TypeTuple *tt = (TypeTuple *)prmtype;
- size_t tt_dim = tt->arguments->length;
- for (size_t j = 0; j < tt_dim; j++, ++argi)
- {
- Parameter *p = (*tt->arguments)[j];
- if (j == tt_dim - 1 && fparameters.varargs == VARARGtypesafe &&
- parami + 1 == nfparams && argi < nfargs)
- {
- prmtype = p->type;
- goto Lvarargs;
- }
- if (argi >= nfargs)
- {
- if (p->defaultArg)
- continue;
- goto Lnomatch;
- }
- farg = (*fargs)[argi];
- if (!farg->implicitConvTo(p->type))
- goto Lnomatch;
- }
- continue;
- }
- }
-
- if (argi >= nfargs) // if not enough arguments
- {
- if (!fparam->defaultArg)
- goto Lvarargs;
-
- /* Bugzilla 2803: Before the starting of type deduction from the function
- * default arguments, set the already deduced parameters into paramscope.
- * It's necessary to avoid breaking existing acceptable code. Cases:
- *
- * 1. Already deduced template parameters can appear in fparam->defaultArg:
- * auto foo(A, B)(A a, B b = A.stringof);
- * foo(1);
- * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int'
- *
- * 2. If prmtype depends on default-specified template parameter, the
- * default type should be preferred.
- * auto foo(N = size_t, R)(R r, N start = 0)
- * foo([1,2,3]);
- * // at fparam `N start = 0`, N should be 'size_t' before
- * // the deduction result from fparam->defaultArg.
- */
- if (argi == nfargs)
- {
- for (size_t i = 0; i < dedtypes->length; i++)
- {
- Type *at = isType((*dedtypes)[i]);
- if (at && at->ty == Tnone)
- {
- TypeDeduced *xt = (TypeDeduced *)at;
- (*dedtypes)[i] = xt->tded; // 'unbox'
- delete xt;
- }
- }
- for (size_t i = ntargs; i < dedargs->length; i++)
- {
- TemplateParameter *tparam = (*parameters)[i];
-
- RootObject *oarg = (*dedargs)[i];
- RootObject *oded = (*dedtypes)[i];
- if (!oarg)
- {
- if (oded)
- {
- if (tparam->specialization() || !tparam->isTemplateTypeParameter())
- {
- /* The specialization can work as long as afterwards
- * the oded == oarg
- */
- (*dedargs)[i] = oded;
- MATCH m2 = tparam->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, NULL);
- //printf("m2 = %d\n", m2);
- if (m2 <= MATCHnomatch)
- goto Lnomatch;
- if (m2 < matchTiargs)
- matchTiargs = m2; // pick worst match
- if (!(*dedtypes)[i]->equals(oded))
- error("specialization not allowed for deduced parameter %s", tparam->ident->toChars());
- }
- else
- {
- if (MATCHconvert < matchTiargs)
- matchTiargs = MATCHconvert;
- }
- (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
- }
- else
- {
- inuse++;
- oded = tparam->defaultArg(instLoc, paramscope);
- inuse--;
- if (oded)
- (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
- }
- }
- }
- }
- nfargs2 = argi + 1;
-
- /* If prmtype does not depend on any template parameters:
- *
- * auto foo(T)(T v, double x = 0);
- * foo("str");
- * // at fparam == 'double x = 0'
- *
- * or, if all template parameters in the prmtype are already deduced:
- *
- * auto foo(R)(R range, ElementType!R sum = 0);
- * foo([1,2,3]);
- * // at fparam == 'ElementType!R sum = 0'
- *
- * Deducing prmtype from fparam->defaultArg is not necessary.
- */
- if (prmtype->deco ||
- prmtype->syntaxCopy()->trySemantic(loc, paramscope))
- {
- ++argi;
- continue;
- }
-
- // Deduce prmtype from the defaultArg.
- farg = fparam->defaultArg->syntaxCopy();
- farg = expressionSemantic(farg, paramscope);
- farg = resolveProperties(paramscope, farg);
- }
- else
- {
- farg = (*fargs)[argi];
- }
- {
- // Check invalid arguments to detect errors early.
- if (farg->op == TOKerror || farg->type->ty == Terror)
- goto Lnomatch;
-
- Type *att = NULL;
- Lretry:
- Type *argtype = farg->type;
-
- if (!(fparam->storageClass & STClazy) && argtype->ty == Tvoid && farg->op != TOKfunction)
- goto Lnomatch;
-
- // Bugzilla 12876: optimize arugument to allow CT-known length matching
- farg = farg->optimize(WANTvalue, (fparam->storageClass & (STCref | STCout)) != 0);
- //printf("farg = %s %s\n", farg->type->toChars(), farg->toChars());
-
- RootObject *oarg = farg;
- if ((fparam->storageClass & STCref) &&
- (!(fparam->storageClass & STCauto) || farg->isLvalue()))
- {
- /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
- */
- Type *taai;
- if (argtype->ty == Tarray &&
- (prmtype->ty == Tsarray ||
- (prmtype->ty == Taarray && (taai = ((TypeAArray *)prmtype)->index)->ty == Tident &&
- ((TypeIdentifier *)taai)->idents.length == 0)))
- {
- if (farg->op == TOKstring)
- {
- StringExp *se = (StringExp *)farg;
- argtype = se->type->nextOf()->sarrayOf(se->len);
- }
- else if (farg->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ae = (ArrayLiteralExp *)farg;
- argtype = ae->type->nextOf()->sarrayOf(ae->elements->length);
- }
- else if (farg->op == TOKslice)
- {
- SliceExp *se = (SliceExp *)farg;
- if (Type *tsa = toStaticArrayType(se))
- argtype = tsa;
- }
- }
-
- oarg = argtype;
- }
- else if ((fparam->storageClass & STCout) == 0 &&
- (argtype->ty == Tarray || argtype->ty == Tpointer) &&
- templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND &&
- ((TypeIdentifier *)prmtype)->idents.length == 0)
- {
- /* The farg passing to the prmtype always make a copy. Therefore,
- * we can shrink the set of the deduced type arguments for prmtype
- * by adjusting top-qualifier of the argtype.
- *
- * prmtype argtype ta
- * T <- const(E)[] const(E)[]
- * T <- const(E[]) const(E)[]
- * qualifier(T) <- const(E)[] const(E[])
- * qualifier(T) <- const(E[]) const(E[])
- */
- Type *ta = argtype->castMod(prmtype->mod ? argtype->nextOf()->mod : 0);
- if (ta != argtype)
- {
- Expression *ea = farg->copy();
- ea->type = ta;
- oarg = ea;
- }
- }
-
- if (fparameters.varargs == VARARGtypesafe && parami + 1 == nfparams && argi + 1 < nfargs)
- goto Lvarargs;
-
- unsigned wm = 0;
- MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &wm, inferStart);
- //printf("\tL%d deduceType m = %d, wm = x%x, wildmatch = x%x\n", __LINE__, m, wm, wildmatch);
- wildmatch |= wm;
-
- /* If no match, see if the argument can be matched by using
- * implicit conversions.
- */
- if (m == MATCHnomatch && prmtype->deco)
- m = farg->implicitConvTo(prmtype);
-
- if (m == MATCHnomatch)
- {
- AggregateDeclaration *ad = isAggregate(farg->type);
- if (ad && ad->aliasthis && argtype != att)
- {
- if (!att && argtype->checkAliasThisRec()) // Bugzilla 12537
- att = argtype;
-
- /* If a semantic error occurs while doing alias this,
- * eg purity(bug 7295), just regard it as not a match.
- */
- if (Expression *e = resolveAliasThis(sc, farg, true))
- {
- farg = e;
- goto Lretry;
- }
- }
- }
-
- if (m > MATCHnomatch && (fparam->storageClass & (STCref | STCauto)) == STCref)
- {
- if (!farg->isLvalue())
- {
- if ((farg->op == TOKstring || farg->op == TOKslice) &&
- (prmtype->ty == Tsarray || prmtype->ty == Taarray))
- {
- // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
- }
- else
- goto Lnomatch;
- }
- }
- if (m > MATCHnomatch && (fparam->storageClass & STCout))
- {
- if (!farg->isLvalue())
- goto Lnomatch;
- if (!farg->type->isMutable()) // Bugzilla 11916
- goto Lnomatch;
- }
- if (m == MATCHnomatch && (fparam->storageClass & STClazy) && prmtype->ty == Tvoid &&
- farg->type->ty != Tvoid)
- m = MATCHconvert;
-
- if (m != MATCHnomatch)
- {
- if (m < match)
- match = m; // pick worst match
- argi++;
- continue;
- }
- }
-
- Lvarargs:
- /* The following code for variadic arguments closely
- * matches TypeFunction::callMatch()
- */
- if (!(fparameters.varargs == VARARGtypesafe && parami + 1 == nfparams))
- goto Lnomatch;
-
- /* Check for match with function parameter T...
- */
- Type *tb = prmtype->toBasetype();
- switch (tb->ty)
- {
- // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
- case Tsarray:
- case Taarray:
- // Perhaps we can do better with this, see TypeFunction::callMatch()
- if (tb->ty == Tsarray)
- {
- TypeSArray *tsa = (TypeSArray *)tb;
- dinteger_t sz = tsa->dim->toInteger();
- if (sz != nfargs - argi)
- goto Lnomatch;
- }
- else if (tb->ty == Taarray)
- {
- TypeAArray *taa = (TypeAArray *)tb;
- Expression *dim = new IntegerExp(instLoc, nfargs - argi, Type::tsize_t);
-
- size_t i = templateParameterLookup(taa->index, parameters);
- if (i == IDX_NOTFOUND)
- {
- Expression *e;
- Type *t;
- Dsymbol *s;
- Scope *sco;
-
- unsigned errors = global.startGagging();
- /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
- * The parameter isn't part of the template
- * ones, let's try to find it in the
- * instantiation scope 'sc' and the one
- * belonging to the template itself. */
- sco = sc;
- taa->index->resolve(instLoc, sco, &e, &t, &s);
- if (!e)
- {
- sco = paramscope;
- taa->index->resolve(instLoc, sco, &e, &t, &s);
- }
- global.endGagging(errors);
-
- if (!e)
- {
- goto Lnomatch;
- }
-
- e = e->ctfeInterpret();
- e = e->implicitCastTo(sco, Type::tsize_t);
- e = e->optimize(WANTvalue);
- if (!dim->equals(e))
- goto Lnomatch;
- }
- else
- {
- // This code matches code in TypeInstance::deduceType()
- TemplateParameter *tprm = (*parameters)[i];
- TemplateValueParameter *tvp = tprm->isTemplateValueParameter();
- if (!tvp)
- goto Lnomatch;
- Expression *e = (Expression *)(*dedtypes)[i];
- if (e)
- {
- if (!dim->equals(e))
- goto Lnomatch;
- }
- else
- {
- Type *vt = typeSemantic(tvp->valType, Loc(), sc);
- MATCH m = (MATCH)dim->implicitConvTo(vt);
- if (m <= MATCHnomatch)
- goto Lnomatch;
- (*dedtypes)[i] = dim;
- }
- }
- }
- /* fall through */
- case Tarray:
- {
- TypeArray *ta = (TypeArray *)tb;
- Type *tret = fparam->isLazyArray();
- for (; argi < nfargs; argi++)
- {
- Expression *arg = (*fargs)[argi];
- assert(arg);
-
- MATCH m;
- /* If lazy array of delegates,
- * convert arg(s) to delegate(s)
- */
- if (tret)
- {
- if (ta->next->equals(arg->type))
- {
- m = MATCHexact;
- }
- else
- {
- m = arg->implicitConvTo(tret);
- if (m == MATCHnomatch)
- {
- if (tret->toBasetype()->ty == Tvoid)
- m = MATCHconvert;
- }
- }
- }
- else
- {
- unsigned wm = 0;
- m = deduceType(arg, paramscope, ta->next, parameters, dedtypes, &wm, inferStart);
- wildmatch |= wm;
- }
- if (m == MATCHnomatch)
- goto Lnomatch;
- if (m < match)
- match = m;
- }
- goto Lmatch;
- }
- case Tclass:
- case Tident:
- goto Lmatch;
-
- default:
- goto Lnomatch;
- }
- ++argi;
- }
- //printf("-> argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
- if (argi != nfargs2 && fparameters.varargs == VARARGnone)
- goto Lnomatch;
- }
-
-Lmatch:
-
- for (size_t i = 0; i < dedtypes->length; i++)
- {
- Type *at = isType((*dedtypes)[i]);
- if (at)
- {
- if (at->ty == Tnone)
- {
- TypeDeduced *xt = (TypeDeduced *)at;
- at = xt->tded; // 'unbox'
- delete xt;
- }
- (*dedtypes)[i] = at->merge2();
- }
- }
- for (size_t i = ntargs; i < dedargs->length; i++)
- {
- TemplateParameter *tparam = (*parameters)[i];
- //printf("tparam[%d] = %s\n", i, tparam->ident->toChars());
- /* For T:T*, the dedargs is the T*, dedtypes is the T
- * But for function templates, we really need them to match
- */
- RootObject *oarg = (*dedargs)[i];
- RootObject *oded = (*dedtypes)[i];
- //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
- //if (oarg) printf("oarg: %s\n", oarg->toChars());
- //if (oded) printf("oded: %s\n", oded->toChars());
- if (!oarg)
- {
- if (oded)
- {
- if (tparam->specialization() || !tparam->isTemplateTypeParameter())
- {
- /* The specialization can work as long as afterwards
- * the oded == oarg
- */
- (*dedargs)[i] = oded;
- MATCH m2 = tparam->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, NULL);
- //printf("m2 = %d\n", m2);
- if (m2 <= MATCHnomatch)
- goto Lnomatch;
- if (m2 < matchTiargs)
- matchTiargs = m2; // pick worst match
- if (!(*dedtypes)[i]->equals(oded))
- error("specialization not allowed for deduced parameter %s", tparam->ident->toChars());
- }
- else
- {
- if (MATCHconvert < matchTiargs)
- matchTiargs = MATCHconvert;
- }
- }
- else
- {
- inuse++;
- oded = tparam->defaultArg(instLoc, paramscope);
- inuse--;
- if (!oded)
- {
- // if tuple parameter and
- // tuple parameter was not in function parameter list and
- // we're one or more arguments short (i.e. no tuple argument)
- if (tparam == tp &&
- fptupindex == IDX_NOTFOUND &&
- ntargs <= dedargs->length - 1)
- {
- // make tuple argument an empty tuple
- oded = (RootObject *)new Tuple();
- }
- else
- goto Lnomatch;
- }
- if (isError(oded))
- goto Lerror;
- ntargs++;
-
- /* At the template parameter T, the picked default template argument
- * X!int should be matched to T in order to deduce dependent
- * template parameter A.
- * auto foo(T : X!A = X!int, A...)() { ... }
- * foo(); // T <-- X!int, A <-- (int)
- */
- if (tparam->specialization())
- {
- (*dedargs)[i] = oded;
- MATCH m2 = tparam->matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, NULL);
- //printf("m2 = %d\n", m2);
- if (m2 <= MATCHnomatch)
- goto Lnomatch;
- if (m2 < matchTiargs)
- matchTiargs = m2; // pick worst match
- if (!(*dedtypes)[i]->equals(oded))
- error("specialization not allowed for deduced parameter %s", tparam->ident->toChars());
- }
- }
- oded = declareParameter(paramscope, tparam, oded);
- (*dedargs)[i] = oded;
- }
- }
-
- /* Bugzilla 7469: As same as the code for 7469 in findBestMatch,
- * expand a Tuple in dedargs to normalize template arguments.
- */
- if (size_t d = dedargs->length)
- {
- if (Tuple *va = isTuple((*dedargs)[d - 1]))
- {
- if (va->objects.length)
- {
- dedargs->setDim(d - 1);
- dedargs->insert(d - 1, &va->objects);
- }
- }
- }
- ti->tiargs = dedargs; // update to the normalized template arguments.
-
- // Partially instantiate function for constraint and fd->leastAsSpecialized()
- {
- assert(paramsym);
- Scope *sc2 = _scope;
- sc2 = sc2->push(paramsym);
- sc2 = sc2->push(ti);
- sc2->parent = ti;
- sc2->tinst = ti;
- sc2->minst = sc->minst;
-
- fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs);
-
- sc2 = sc2->pop();
- sc2 = sc2->pop();
-
- if (!fd)
- goto Lnomatch;
- }
-
- if (constraint)
- {
- if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd))
- goto Lnomatch;
- }
-
- paramscope->pop();
- //printf("\tmatch %d\n", match);
- return (MATCH)(match | (matchTiargs<<4));
-
-Lnomatch:
- paramscope->pop();
- //printf("\tnomatch\n");
- return MATCHnomatch;
-
-Lerror: // todo: for the future improvement
- paramscope->pop();
- //printf("\terror\n");
- return MATCHnomatch;
-}
-
-/**************************************************
- * Declare template parameter tp with value o, and install it in the scope sc.
- */
-
-RootObject *TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o)
-{
- //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o);
-
- Type *ta = isType(o);
- Expression *ea = isExpression(o);
- Dsymbol *sa = isDsymbol(o);
- Tuple *va = isTuple(o);
-
- Declaration *d;
- VarDeclaration *v = NULL;
-
- if (ea && ea->op == TOKtype)
- ta = ea->type;
- else if (ea && ea->op == TOKscope)
- sa = ((ScopeExp *)ea)->sds;
- else if (ea && (ea->op == TOKthis || ea->op == TOKsuper))
- sa = ((ThisExp *)ea)->var;
- else if (ea && ea->op == TOKfunction)
- {
- if (((FuncExp *)ea)->td)
- sa = ((FuncExp *)ea)->td;
- else
- sa = ((FuncExp *)ea)->fd;
- }
-
- if (ta)
- {
- //printf("type %s\n", ta->toChars());
- d = new AliasDeclaration(Loc(), tp->ident, ta);
- }
- else if (sa)
- {
- //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars());
- d = new AliasDeclaration(Loc(), tp->ident, sa);
- }
- else if (ea)
- {
- // tdtypes.data[i] always matches ea here
- Initializer *init = new ExpInitializer(loc, ea);
- TemplateValueParameter *tvp = tp->isTemplateValueParameter();
-
- Type *t = tvp ? tvp->valType : NULL;
-
- v = new VarDeclaration(loc, t, tp->ident, init);
- v->storage_class = STCmanifest | STCtemplateparameter;
- d = v;
- }
- else if (va)
- {
- //printf("\ttuple\n");
- d = new TupleDeclaration(loc, tp->ident, &va->objects);
- }
- else
- {
- assert(0);
- }
-
- d->storage_class |= STCtemplateparameter;
- if (ta)
- {
- Type *t = ta;
- // consistent with Type::checkDeprecated()
- while (t->ty != Tenum)
- {
- if (!t->nextOf()) break;
- t = ((TypeNext *)t)->next;
- }
- if (Dsymbol *s = t->toDsymbol(sc))
- {
- if (s->isDeprecated())
- d->storage_class |= STCdeprecated;
- }
- }
- else if (sa)
- {
- if (sa->isDeprecated())
- d->storage_class |= STCdeprecated;
- }
-
- if (!sc->insert(d))
- error("declaration %s is already defined", tp->ident->toChars());
- dsymbolSemantic(d, sc);
-
- /* So the caller's o gets updated with the result of semantic() being run on o
- */
- if (v)
- o = initializerToExpression(v->_init);
- return o;
-}
-
-/**************************************
- * Determine if TemplateDeclaration is variadic.
- */
-
-TemplateTupleParameter *isVariadic(TemplateParameters *parameters)
-{
- size_t dim = parameters->length;
- TemplateTupleParameter *tp = NULL;
-
- if (dim)
- tp = ((*parameters)[dim - 1])->isTemplateTupleParameter();
- return tp;
-}
-
-TemplateTupleParameter *TemplateDeclaration::isVariadic()
-{
- return ::isVariadic(parameters);
-}
-
-/***********************************
- * We can overload templates.
- */
-
-bool TemplateDeclaration::isOverloadable()
-{
- return true;
-}
-
-/*************************************************
- * Given function arguments, figure out which template function
- * to expand, and return matching result.
- * Params:
- * m = matching result
- * dstart = the root of overloaded function templates
- * loc = instantiation location
- * sc = instantiation scope
- * tiargs = initial list of template arguments
- * tthis = if !NULL, the 'this' pointer argument
- * fargs = arguments to function
- * pMessage = address to store error message, or null
- */
-
-void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
- Objects *tiargs, Type *tthis, Expressions *fargs, const char **pMessage)
-{
- struct ParamDeduce
- {
- // context
- Loc loc;
- Scope *sc;
- Type *tthis;
- Objects *tiargs;
- Expressions *fargs;
- const char **pMessage;
- // result
- Match *m;
- int property; // 0: unintialized
- // 1: seen @property
- // 2: not @property
- size_t ov_index;
- TemplateDeclaration *td_best;
- TemplateInstance *ti_best;
- MATCH ta_last;
- Type *tthis_best;
-
- static int fp(void *param, Dsymbol *s)
- {
- if (s->errors)
- return 0;
- if (FuncDeclaration *fd = s->isFuncDeclaration())
- return ((ParamDeduce *)param)->applyFunction(fd);
- if (TemplateDeclaration *td = s->isTemplateDeclaration())
- return ((ParamDeduce *)param)->applyTemplate(td);
- return 0;
- }
-
- int applyFunction(FuncDeclaration *fd)
- {
- // skip duplicates
- if (fd == m->lastf)
- return 0;
- // explicitly specified tiargs never match to non template function
- if (tiargs && tiargs->length > 0)
- return 0;
-
- // constructors need a valid scope in order to detect semantic errors
- if (!fd->isCtorDeclaration() &&
- fd->semanticRun < PASSsemanticdone)
- {
- Ungag ungag = fd->ungagSpeculative();
- dsymbolSemantic(fd, NULL);
- }
- if (fd->semanticRun < PASSsemanticdone)
- {
- ::error(loc, "forward reference to template %s", fd->toChars());
- return 1;
- }
- //printf("fd = %s %s, fargs = %s\n", fd->toChars(), fd->type->toChars(), fargs->toChars());
- m->anyf = fd;
- TypeFunction *tf = (TypeFunction *)fd->type;
-
- int prop = (tf->isproperty) ? 1 : 2;
- if (property == 0)
- property = prop;
- else if (property != prop)
- error(fd->loc, "cannot overload both property and non-property functions");
-
- /* For constructors, qualifier check will be opposite direction.
- * Qualified constructor always makes qualified object, then will be checked
- * that it is implicitly convertible to tthis.
- */
- Type *tthis_fd = fd->needThis() ? tthis : NULL;
- bool isCtorCall = tthis_fd && fd->isCtorDeclaration();
- if (isCtorCall)
- {
- //printf("%s tf->mod = x%x tthis_fd->mod = x%x %d\n", tf->toChars(),
- // tf->mod, tthis_fd->mod, fd->isolateReturn());
- if (MODimplicitConv(tf->mod, tthis_fd->mod) ||
- (tf->isWild() && tf->isShared() == tthis_fd->isShared()) ||
- fd->isolateReturn())
- {
- /* && tf->isShared() == tthis_fd->isShared()*/
- // Uniquely constructed object can ignore shared qualifier.
- // TODO: Is this appropriate?
- tthis_fd = NULL;
- }
- else
- return 0; // MATCHnomatch
- }
- MATCH mfa = tf->callMatch(tthis_fd, fargs, 0, pMessage);
- //printf("test1: mfa = %d\n", mfa);
- if (mfa > MATCHnomatch)
- {
- if (mfa > m->last) goto LfIsBetter;
- if (mfa < m->last) goto LlastIsBetter;
-
- /* See if one of the matches overrides the other.
- */
- assert(m->lastf);
- if (m->lastf->overrides(fd)) goto LlastIsBetter;
- if (fd->overrides(m->lastf)) goto LfIsBetter;
-
- /* Try to disambiguate using template-style partial ordering rules.
- * In essence, if f() and g() are ambiguous, if f() can call g(),
- * but g() cannot call f(), then pick f().
- * This is because f() is "more specialized."
- */
- {
- MATCH c1 = fd->leastAsSpecialized(m->lastf);
- MATCH c2 = m->lastf->leastAsSpecialized(fd);
- //printf("c1 = %d, c2 = %d\n", c1, c2);
- if (c1 > c2) goto LfIsBetter;
- if (c1 < c2) goto LlastIsBetter;
- }
-
- /* The 'overrides' check above does covariant checking only
- * for virtual member functions. It should do it for all functions,
- * but in order to not risk breaking code we put it after
- * the 'leastAsSpecialized' check.
- * In the future try moving it before.
- * I.e. a not-the-same-but-covariant match is preferred,
- * as it is more restrictive.
- */
- if (!m->lastf->type->equals(fd->type))
- {
- //printf("cov: %d %d\n", m->lastf->type->covariant(fd->type), fd->type->covariant(m->lastf->type));
- if (m->lastf->type->covariant(fd->type) == 1) goto LlastIsBetter;
- if (fd->type->covariant(m->lastf->type) == 1) goto LfIsBetter;
- }
-
- /* If the two functions are the same function, like:
- * int foo(int);
- * int foo(int x) { ... }
- * then pick the one with the body.
- */
- if (tf->equals(m->lastf->type) &&
- fd->storage_class == m->lastf->storage_class &&
- fd->parent == m->lastf->parent &&
- fd->protection == m->lastf->protection &&
- fd->linkage == m->lastf->linkage)
- {
- if ( fd->fbody && !m->lastf->fbody) goto LfIsBetter;
- if (!fd->fbody && m->lastf->fbody) goto LlastIsBetter;
- }
-
- // Bugzilla 14450: Prefer exact qualified constructor for the creating object type
- if (isCtorCall && tf->mod != m->lastf->type->mod)
- {
- if (tthis->mod == tf->mod) goto LfIsBetter;
- if (tthis->mod == m->lastf->type->mod) goto LlastIsBetter;
- }
-
- m->nextf = fd;
- m->count++;
- return 0;
-
- LlastIsBetter:
- return 0;
-
- LfIsBetter:
- td_best = NULL;
- ti_best = NULL;
- ta_last = MATCHexact;
- m->last = mfa;
- m->lastf = fd;
- tthis_best = tthis_fd;
- ov_index = 0;
- m->count = 1;
- return 0;
- }
- return 0;
- }
-
- int applyTemplate(TemplateDeclaration *td)
- {
- //printf("applyTemplate()\n");
- if (td->inuse)
- {
- td->error(loc, "recursive template expansion");
- return 1;
- }
- if (td == td_best) // skip duplicates
- return 0;
-
- if (!sc)
- sc = td->_scope; // workaround for Type::aliasthisOf
-
- if (td->semanticRun == PASSinit && td->_scope)
- {
- // Try to fix forward reference. Ungag errors while doing so.
- Ungag ungag = td->ungagSpeculative();
- dsymbolSemantic(td, td->_scope);
- }
- if (td->semanticRun == PASSinit)
- {
- ::error(loc, "forward reference to template %s", td->toChars());
- Lerror:
- m->lastf = NULL;
- m->count = 0;
- m->last = MATCHnomatch;
- return 1;
- }
- //printf("td = %s\n", td->toChars());
-
- FuncDeclaration *f;
- f = td->onemember ? td->onemember->isFuncDeclaration() : NULL;
- if (!f)
- {
- if (!tiargs)
- tiargs = new Objects();
- TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
- Objects dedtypes;
- dedtypes.setDim(td->parameters->length);
- assert(td->semanticRun != PASSinit);
- MATCH mta = td->matchWithInstance(sc, ti, &dedtypes, fargs, 0);
- //printf("matchWithInstance = %d\n", mta);
- if (mta <= MATCHnomatch || mta < ta_last) // no match or less match
- return 0;
-
- templateInstanceSemantic(ti, sc, fargs);
- if (!ti->inst) // if template failed to expand
- return 0;
-
- Dsymbol *s = ti->inst->toAlias();
- FuncDeclaration *fd;
- if (TemplateDeclaration *tdx = s->isTemplateDeclaration())
- {
- Objects dedtypesX; // empty tiargs
-
- // Bugzilla 11553: Check for recursive instantiation of tdx.
- for (TemplatePrevious *p = tdx->previous; p; p = p->prev)
- {
- if (arrayObjectMatch(p->dedargs, &dedtypesX))
- {
- //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars());
- /* It must be a subscope of p->sc, other scope chains are not recursive
- * instantiations.
- */
- for (Scope *scx = sc; scx; scx = scx->enclosing)
- {
- if (scx == p->sc)
- {
- error(loc, "recursive template expansion while looking for %s.%s", ti->toChars(), tdx->toChars());
- goto Lerror;
- }
- }
- }
- /* BUG: should also check for ref param differences
- */
- }
-
- TemplatePrevious pr;
- pr.prev = tdx->previous;
- pr.sc = sc;
- pr.dedargs = &dedtypesX;
- tdx->previous = &pr; // add this to threaded list
-
- fd = resolveFuncCall(loc, sc, s, NULL, tthis, fargs, 1);
-
- tdx->previous = pr.prev; // unlink from threaded list
- }
- else if (s->isFuncDeclaration())
- {
- fd = resolveFuncCall(loc, sc, s, NULL, tthis, fargs, 1);
- }
- else
- goto Lerror;
-
- if (!fd)
- return 0;
-
- if (fd->type->ty != Tfunction)
- {
- m->lastf = fd; // to propagate "error match"
- m->count = 1;
- m->last = MATCHnomatch;
- return 1;
- }
-
- Type *tthis_fd = fd->needThis() && !fd->isCtorDeclaration() ? tthis : NULL;
-
- TypeFunction *tf = (TypeFunction *)fd->type;
- MATCH mfa = tf->callMatch(tthis_fd, fargs);
- if (mfa < m->last)
- return 0;
-
- if (mta < ta_last) goto Ltd_best2;
- if (mta > ta_last) goto Ltd2;
-
- if (mfa < m->last) goto Ltd_best2;
- if (mfa > m->last) goto Ltd2;
-
- //printf("Lambig2\n");
- m->nextf = fd;
- m->count++;
- return 0;
-
- Ltd_best2:
- return 0;
-
- Ltd2:
- // td is the new best match
- assert(td->_scope);
- td_best = td;
- ti_best = NULL;
- property = 0; // (backward compatibility)
- ta_last = mta;
- m->last = mfa;
- m->lastf = fd;
- tthis_best = tthis_fd;
- ov_index = 0;
- m->nextf = NULL;
- m->count = 1;
- return 0;
- }
-
- //printf("td = %s\n", td->toChars());
- for (size_t ovi = 0; f; f = f->overnext0, ovi++)
- {
- if (f->type->ty != Tfunction || f->errors)
- goto Lerror;
-
- /* This is a 'dummy' instance to evaluate constraint properly.
- */
- TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
- ti->parent = td->parent; // Maybe calculating valid 'enclosing' is unnecessary.
-
- FuncDeclaration *fd = f;
- int x = td->deduceFunctionTemplateMatch(ti, sc, fd, tthis, fargs);
- MATCH mta = (MATCH)(x >> 4);
- MATCH mfa = (MATCH)(x & 0xF);
- //printf("match:t/f = %d/%d\n", mta, mfa);
- if (!fd || mfa == MATCHnomatch)
- continue;
-
- Type *tthis_fd = fd->needThis() ? tthis : NULL;
-
- bool isCtorCall = tthis_fd && fd->isCtorDeclaration();
- if (isCtorCall)
- {
- // Constructor call requires additional check.
-
- TypeFunction *tf = (TypeFunction *)fd->type;
- assert(tf->next);
- if (MODimplicitConv(tf->mod, tthis_fd->mod) ||
- (tf->isWild() && tf->isShared() == tthis_fd->isShared()) ||
- fd->isolateReturn())
- {
- tthis_fd = NULL;
- }
- else
- continue; // MATCHnomatch
- }
-
- if (mta < ta_last) goto Ltd_best;
- if (mta > ta_last) goto Ltd;
-
- if (mfa < m->last) goto Ltd_best;
- if (mfa > m->last) goto Ltd;
-
- if (td_best)
- {
- // Disambiguate by picking the most specialized TemplateDeclaration
- MATCH c1 = td->leastAsSpecialized(sc, td_best, fargs);
- MATCH c2 = td_best->leastAsSpecialized(sc, td, fargs);
- //printf("1: c1 = %d, c2 = %d\n", c1, c2);
- if (c1 > c2) goto Ltd;
- if (c1 < c2) goto Ltd_best;
- }
- assert(fd && m->lastf);
- {
- // Disambiguate by tf->callMatch
- TypeFunction *tf1 = (TypeFunction *)fd->type;
- assert(tf1->ty == Tfunction);
- TypeFunction *tf2 = (TypeFunction *)m->lastf->type;
- assert(tf2->ty == Tfunction);
- MATCH c1 = tf1->callMatch(tthis_fd, fargs);
- MATCH c2 = tf2->callMatch(tthis_best, fargs);
- //printf("2: c1 = %d, c2 = %d\n", c1, c2);
- if (c1 > c2) goto Ltd;
- if (c1 < c2) goto Ltd_best;
- }
- {
- // Disambiguate by picking the most specialized FunctionDeclaration
- MATCH c1 = fd->leastAsSpecialized(m->lastf);
- MATCH c2 = m->lastf->leastAsSpecialized(fd);
- //printf("3: c1 = %d, c2 = %d\n", c1, c2);
- if (c1 > c2) goto Ltd;
- if (c1 < c2) goto Ltd_best;
- }
-
- // Bugzilla 14450: Prefer exact qualified constructor for the creating object type
- if (isCtorCall && fd->type->mod != m->lastf->type->mod)
- {
- if (tthis->mod == fd->type->mod) goto Ltd;
- if (tthis->mod == m->lastf->type->mod) goto Ltd_best;
- }
-
- m->nextf = fd;
- m->count++;
- continue;
-
- Ltd_best: // td_best is the best match so far
- //printf("Ltd_best\n");
- continue;
-
- Ltd: // td is the new best match
- //printf("Ltd\n");
- assert(td->_scope);
- td_best = td;
- ti_best = ti;
- property = 0; // (backward compatibility)
- ta_last = mta;
- m->last = mfa;
- m->lastf = fd;
- tthis_best = tthis_fd;
- ov_index = ovi;
- m->nextf = NULL;
- m->count = 1;
- continue;
- }
- return 0;
- }
- };
- ParamDeduce p;
- // context
- p.loc = loc;
- p.sc = sc;
- p.tthis = tthis;
- p.tiargs = tiargs;
- p.fargs = fargs;
- p.pMessage = pMessage;
-
- // result
- p.m = m;
- p.property = 0;
- p.ov_index = 0;
- p.td_best = NULL;
- p.ti_best = NULL;
- p.ta_last = m->last != MATCHnomatch ? MATCHexact : MATCHnomatch;
- p.tthis_best = NULL;
-
- TemplateDeclaration *td = dstart->isTemplateDeclaration();
- if (td && td->funcroot)
- dstart = td->funcroot;
-
- overloadApply(dstart, &p, &ParamDeduce::fp);
-
- //printf("td_best = %p, m->lastf = %p\n", p.td_best, m->lastf);
- if (p.td_best && p.ti_best && m->count == 1)
- {
- // Matches to template function
- assert(p.td_best->onemember && p.td_best->onemember->isFuncDeclaration());
-
- /* The best match is td_best with arguments tdargs.
- * Now instantiate the template.
- */
- assert(p.td_best->_scope);
- if (!sc)
- sc = p.td_best->_scope; // workaround for Type::aliasthisOf
-
- TemplateInstance *ti = new TemplateInstance(loc, p.td_best, p.ti_best->tiargs);
- templateInstanceSemantic(ti, sc, fargs);
-
- m->lastf = ti->toAlias()->isFuncDeclaration();
- if (!m->lastf)
- goto Lnomatch;
- if (ti->errors)
- {
- Lerror:
- m->count = 1;
- assert(m->lastf);
- m->last = MATCHnomatch;
- return;
- }
-
- // look forward instantiated overload function
- // Dsymbol::oneMembers is alredy called in TemplateInstance::semantic.
- // it has filled overnext0d
- while (p.ov_index--)
- {
- m->lastf = m->lastf->overnext0;
- assert(m->lastf);
- }
-
- p.tthis_best = m->lastf->needThis() && !m->lastf->isCtorDeclaration() ? tthis : NULL;
-
- TypeFunction *tf = (TypeFunction *)m->lastf->type;
- if (tf->ty == Terror)
- goto Lerror;
- assert(tf->ty == Tfunction);
- if (!tf->callMatch(p.tthis_best, fargs))
- goto Lnomatch;
-
- /* As Bugzilla 3682 shows, a template instance can be matched while instantiating
- * that same template. Thus, the function type can be incomplete. Complete it.
- *
- * Bugzilla 9208: For auto function, completion should be deferred to the end of
- * its semantic3. Should not complete it in here.
- */
- if (tf->next && !m->lastf->inferRetType)
- {
- m->lastf->type = typeSemantic(tf, loc, sc);
- }
- }
- else if (m->lastf)
- {
- // Matches to non template function,
- // or found matches were ambiguous.
- assert(m->count >= 1);
- }
- else
- {
- Lnomatch:
- m->count = 0;
- m->lastf = NULL;
- m->last = MATCHnomatch;
- }
-}
-
-/*************************************************
- * Limited function template instantiation for using fd->leastAsSpecialized()
- */
-FuncDeclaration *TemplateDeclaration::doHeaderInstantiation(
- TemplateInstance *ti, Scope *sc2,
- FuncDeclaration *fd, Type *tthis, Expressions *fargs)
-{
- assert(fd);
-
- // function body and contracts are not need
- if (fd->isCtorDeclaration())
- fd = new CtorDeclaration(fd->loc, fd->endloc, fd->storage_class, fd->type->syntaxCopy());
- else
- fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, fd->type->syntaxCopy());
- fd->parent = ti;
-
- assert(fd->type->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)fd->type;
- tf->fargs = fargs;
-
- if (tthis)
- {
- // Match 'tthis' to any TemplateThisParameter's
- bool hasttp = false;
- for (size_t i = 0; i < parameters->length; i++)
- {
- TemplateParameter *tp = (*parameters)[i];
- TemplateThisParameter *ttp = tp->isTemplateThisParameter();
- if (ttp)
- hasttp = true;
- }
- if (hasttp)
- {
- tf = (TypeFunction *)tf->addSTC(ModToStc(tthis->mod));
- assert(!tf->deco);
- }
- }
-
- Scope *scx = sc2->push();
-
- // Shouldn't run semantic on default arguments and return type.
- for (size_t i = 0; i < tf->parameterList.parameters->length; i++)
- (*tf->parameterList.parameters)[i]->defaultArg = NULL;
- if (fd->isCtorDeclaration())
- {
- // For constructors, emitting return type is necessary for
- // isolateReturn() in functionResolve.
- scx->flags |= SCOPEctor;
-
- Dsymbol *parent = toParent2();
- Type *tret;
- AggregateDeclaration *ad = parent->isAggregateDeclaration();
- if (!ad || parent->isUnionDeclaration())
- {
- tret = Type::tvoid;
- }
- else
- {
- tret = ad->handleType();
- assert(tret);
- tret = tret->addStorageClass(fd->storage_class | scx->stc);
- tret = tret->addMod(tf->mod);
- }
- tf->next = tret;
- if (ad && ad->isStructDeclaration())
- tf->isref = 1;
- //printf("tf = %s\n", tf->toChars());
- }
- else
- tf->next = NULL;
- fd->type = tf;
- fd->type = fd->type->addSTC(scx->stc);
- fd->type = typeSemantic(fd->type, fd->loc, scx);
- scx = scx->pop();
-
- if (fd->type->ty != Tfunction)
- return NULL;
-
- fd->originalType = fd->type; // for mangling
- //printf("\t[%s] fd->type = %s, mod = %x, ", loc.toChars(), fd->type->toChars(), fd->type->mod);
- //printf("fd->needThis() = %d\n", fd->needThis());
-
- return fd;
-}
-
-bool TemplateDeclaration::hasStaticCtorOrDtor()
-{
- return false; // don't scan uninstantiated templates
-}
-
-const char *TemplateDeclaration::toChars()
-{
- if (literal)
- return Dsymbol::toChars();
-
- OutBuffer buf;
- HdrGenState hgs;
-
- buf.writestring(ident->toChars());
- buf.writeByte('(');
- for (size_t i = 0; i < parameters->length; i++)
- {
- TemplateParameter *tp = (*parameters)[i];
- if (i)
- buf.writestring(", ");
- ::toCBuffer(tp, &buf, &hgs);
- }
- buf.writeByte(')');
-
- if (onemember)
- {
- FuncDeclaration *fd = onemember->isFuncDeclaration();
- if (fd && fd->type)
- {
- TypeFunction *tf = (TypeFunction *)fd->type;
- buf.writestring(parametersTypeToChars(tf->parameterList));
- }
- }
-
- if (constraint)
- {
- buf.writestring(" if (");
- ::toCBuffer(constraint, &buf, &hgs);
- buf.writeByte(')');
- }
- return buf.extractChars();
-}
-
-Prot TemplateDeclaration::prot()
-{
- return protection;
-}
-
-/****************************************************
- * Given a new instance tithis of this TemplateDeclaration,
- * see if there already exists an instance.
- * If so, return that existing instance.
- */
-
-TemplateInstance *TemplateDeclaration::findExistingInstance(TemplateInstance *tithis, Expressions *fargs)
-{
- //printf("findExistingInstance(%p)\n", tithis);
- tithis->fargs = fargs;
- TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)instances, (void *)tithis->toHash());
- if (tinstances)
- {
- for (size_t i = 0; i < tinstances->length; i++)
- {
- TemplateInstance *ti = (*tinstances)[i];
- if (tithis->compare(ti) == 0)
- return ti;
- }
- }
- return NULL;
-}
-
-/********************************************
- * Add instance ti to TemplateDeclaration's table of instances.
- * Return a handle we can use to later remove it if it fails instantiation.
- */
-
-TemplateInstance *TemplateDeclaration::addInstance(TemplateInstance *ti)
-{
- //printf("addInstance() %p %p\n", instances, ti);
- TemplateInstances **ptinstances = (TemplateInstances **)dmd_aaGet((AA **)&instances, (void *)ti->toHash());
- if (!*ptinstances)
- *ptinstances = new TemplateInstances();
- (*ptinstances)->push(ti);
- return ti;
-}
-
-/*******************************************
- * Remove TemplateInstance from table of instances.
- * Input:
- * handle returned by addInstance()
- */
-
-void TemplateDeclaration::removeInstance(TemplateInstance *handle)
-{
- //printf("removeInstance()\n");
- TemplateInstances *tinstances = (TemplateInstances *)dmd_aaGetRvalue((AA *)instances, (void *)handle->toHash());
- if (tinstances)
- {
- for (size_t i = 0; i < tinstances->length; i++)
- {
- TemplateInstance *ti = (*tinstances)[i];
- if (handle == ti)
- {
- tinstances->remove(i);
- break;
- }
- }
- }
-}
-
-/* ======================== Type ============================================ */
-
-/****
- * Given an identifier, figure out which TemplateParameter it is.
- * Return IDX_NOTFOUND if not found.
- */
-
-static size_t templateIdentifierLookup(Identifier *id, TemplateParameters *parameters)
-{
- for (size_t i = 0; i < parameters->length; i++)
- {
- TemplateParameter *tp = (*parameters)[i];
- if (tp->ident->equals(id))
- return i;
- }
- return IDX_NOTFOUND;
-}
-
-size_t templateParameterLookup(Type *tparam, TemplateParameters *parameters)
-{
- if (tparam->ty == Tident)
- {
- TypeIdentifier *tident = (TypeIdentifier *)tparam;
- //printf("\ttident = '%s'\n", tident->toChars());
- return templateIdentifierLookup(tident->ident, parameters);
- }
- return IDX_NOTFOUND;
-}
-
-unsigned char deduceWildHelper(Type *t, Type **at, Type *tparam)
-{
- if ((tparam->mod & MODwild) == 0)
- return 0;
-
- *at = NULL;
-
- #define X(U,T) ((U) << 4) | (T)
- switch (X(tparam->mod, t->mod))
- {
- case X(MODwild, 0):
- case X(MODwild, MODconst):
- case X(MODwild, MODshared):
- case X(MODwild, MODshared | MODconst):
- case X(MODwild, MODimmutable):
- case X(MODwildconst, 0):
- case X(MODwildconst, MODconst):
- case X(MODwildconst, MODshared):
- case X(MODwildconst, MODshared | MODconst):
- case X(MODwildconst, MODimmutable):
- case X(MODshared | MODwild, MODshared):
- case X(MODshared | MODwild, MODshared | MODconst):
- case X(MODshared | MODwild, MODimmutable):
- case X(MODshared | MODwildconst, MODshared):
- case X(MODshared | MODwildconst, MODshared | MODconst):
- case X(MODshared | MODwildconst, MODimmutable):
- {
- unsigned char wm = (t->mod & ~MODshared);
- if (wm == 0)
- wm = MODmutable;
- unsigned char m = (t->mod & (MODconst | MODimmutable)) | (tparam->mod & t->mod & MODshared);
- *at = t->unqualify(m);
- return wm;
- }
-
- case X(MODwild, MODwild):
- case X(MODwild, MODwildconst):
- case X(MODwild, MODshared | MODwild):
- case X(MODwild, MODshared | MODwildconst):
- case X(MODwildconst, MODwild):
- case X(MODwildconst, MODwildconst):
- case X(MODwildconst, MODshared | MODwild):
- case X(MODwildconst, MODshared | MODwildconst):
- case X(MODshared | MODwild, MODshared | MODwild):
- case X(MODshared | MODwild, MODshared | MODwildconst):
- case X(MODshared | MODwildconst, MODshared | MODwild):
- case X(MODshared | MODwildconst, MODshared | MODwildconst):
- {
- *at = t->unqualify(tparam->mod & t->mod);
- return MODwild;
- }
-
- default:
- return 0;
- }
- #undef X
-}
-
-MATCH deduceTypeHelper(Type *t, Type **at, Type *tparam)
-{
- // 9*9 == 81 cases
-
- #define X(U,T) ((U) << 4) | (T)
- switch (X(tparam->mod, t->mod))
- {
- case X(0, 0):
- case X(0, MODconst):
- case X(0, MODwild):
- case X(0, MODwildconst):
- case X(0, MODshared):
- case X(0, MODshared | MODconst):
- case X(0, MODshared | MODwild):
- case X(0, MODshared | MODwildconst):
- case X(0, MODimmutable):
- // foo(U) T => T
- // foo(U) const(T) => const(T)
- // foo(U) inout(T) => inout(T)
- // foo(U) inout(const(T)) => inout(const(T))
- // foo(U) shared(T) => shared(T)
- // foo(U) shared(const(T)) => shared(const(T))
- // foo(U) shared(inout(T)) => shared(inout(T))
- // foo(U) shared(inout(const(T))) => shared(inout(const(T)))
- // foo(U) immutable(T) => immutable(T)
- {
- *at = t;
- return MATCHexact;
- }
-
- case X(MODconst, MODconst):
- case X(MODwild, MODwild):
- case X(MODwildconst, MODwildconst):
- case X(MODshared, MODshared):
- case X(MODshared | MODconst, MODshared | MODconst):
- case X(MODshared | MODwild, MODshared | MODwild):
- case X(MODshared | MODwildconst, MODshared | MODwildconst):
- case X(MODimmutable, MODimmutable):
- // foo(const(U)) const(T) => T
- // foo(inout(U)) inout(T) => T
- // foo(inout(const(U))) inout(const(T)) => T
- // foo(shared(U)) shared(T) => T
- // foo(shared(const(U))) shared(const(T)) => T
- // foo(shared(inout(U))) shared(inout(T)) => T
- // foo(shared(inout(const(U)))) shared(inout(const(T))) => T
- // foo(immutable(U)) immutable(T) => T
- {
- *at = t->mutableOf()->unSharedOf();
- return MATCHexact;
- }
-
- case X(MODconst, 0):
- case X(MODconst, MODwild):
- case X(MODconst, MODwildconst):
- case X(MODconst, MODshared | MODconst):
- case X(MODconst, MODshared | MODwild):
- case X(MODconst, MODshared | MODwildconst):
- case X(MODconst, MODimmutable):
- case X(MODwild, MODshared | MODwild):
- case X(MODwildconst, MODshared | MODwildconst):
- case X(MODshared | MODconst, MODimmutable):
- // foo(const(U)) T => T
- // foo(const(U)) inout(T) => T
- // foo(const(U)) inout(const(T)) => T
- // foo(const(U)) shared(const(T)) => shared(T)
- // foo(const(U)) shared(inout(T)) => shared(T)
- // foo(const(U)) shared(inout(const(T))) => shared(T)
- // foo(const(U)) immutable(T) => T
- // foo(inout(U)) shared(inout(T)) => shared(T)
- // foo(inout(const(U))) shared(inout(const(T))) => shared(T)
- // foo(shared(const(U))) immutable(T) => T
- {
- *at = t->mutableOf();
- return MATCHconst;
- }
-
- case X(MODconst, MODshared):
- // foo(const(U)) shared(T) => shared(T)
- {
- *at = t;
- return MATCHconst;
- }
-
- case X(MODshared, MODshared | MODconst):
- case X(MODshared, MODshared | MODwild):
- case X(MODshared, MODshared | MODwildconst):
- case X(MODshared | MODconst, MODshared):
- // foo(shared(U)) shared(const(T)) => const(T)
- // foo(shared(U)) shared(inout(T)) => inout(T)
- // foo(shared(U)) shared(inout(const(T))) => inout(const(T))
- // foo(shared(const(U))) shared(T) => T
- {
- *at = t->unSharedOf();
- return MATCHconst;
- }
-
- case X(MODwildconst, MODimmutable):
- case X(MODshared | MODconst, MODshared | MODwildconst):
- case X(MODshared | MODwildconst, MODimmutable):
- case X(MODshared | MODwildconst, MODshared | MODwild):
- // foo(inout(const(U))) immutable(T) => T
- // foo(shared(const(U))) shared(inout(const(T))) => T
- // foo(shared(inout(const(U)))) immutable(T) => T
- // foo(shared(inout(const(U)))) shared(inout(T)) => T
- {
- *at = t->unSharedOf()->mutableOf();
- return MATCHconst;
- }
-
- case X(MODshared | MODconst, MODshared | MODwild):
- // foo(shared(const(U))) shared(inout(T)) => T
- {
- *at = t->unSharedOf()->mutableOf();
- return MATCHconst;
- }
-
- case X(MODwild, 0):
- case X(MODwild, MODconst):
- case X(MODwild, MODwildconst):
- case X(MODwild, MODimmutable):
- case X(MODwild, MODshared):
- case X(MODwild, MODshared | MODconst):
- case X(MODwild, MODshared | MODwildconst):
- case X(MODwildconst, 0):
- case X(MODwildconst, MODconst):
- case X(MODwildconst, MODwild):
- case X(MODwildconst, MODshared):
- case X(MODwildconst, MODshared | MODconst):
- case X(MODwildconst, MODshared | MODwild):
- case X(MODshared, 0):
- case X(MODshared, MODconst):
- case X(MODshared, MODwild):
- case X(MODshared, MODwildconst):
- case X(MODshared, MODimmutable):
- case X(MODshared | MODconst, 0):
- case X(MODshared | MODconst, MODconst):
- case X(MODshared | MODconst, MODwild):
- case X(MODshared | MODconst, MODwildconst):
- case X(MODshared | MODwild, 0):
- case X(MODshared | MODwild, MODconst):
- case X(MODshared | MODwild, MODwild):
- case X(MODshared | MODwild, MODwildconst):
- case X(MODshared | MODwild, MODimmutable):
- case X(MODshared | MODwild, MODshared):
- case X(MODshared | MODwild, MODshared | MODconst):
- case X(MODshared | MODwild, MODshared | MODwildconst):
- case X(MODshared | MODwildconst, 0):
- case X(MODshared | MODwildconst, MODconst):
- case X(MODshared | MODwildconst, MODwild):
- case X(MODshared | MODwildconst, MODwildconst):
- case X(MODshared | MODwildconst, MODshared):
- case X(MODshared | MODwildconst, MODshared | MODconst):
- case X(MODimmutable, 0):
- case X(MODimmutable, MODconst):
- case X(MODimmutable, MODwild):
- case X(MODimmutable, MODwildconst):
- case X(MODimmutable, MODshared):
- case X(MODimmutable, MODshared | MODconst):
- case X(MODimmutable, MODshared | MODwild):
- case X(MODimmutable, MODshared | MODwildconst):
- // foo(inout(U)) T => nomatch
- // foo(inout(U)) const(T) => nomatch
- // foo(inout(U)) inout(const(T)) => nomatch
- // foo(inout(U)) immutable(T) => nomatch
- // foo(inout(U)) shared(T) => nomatch
- // foo(inout(U)) shared(const(T)) => nomatch
- // foo(inout(U)) shared(inout(const(T))) => nomatch
- // foo(inout(const(U))) T => nomatch
- // foo(inout(const(U))) const(T) => nomatch
- // foo(inout(const(U))) inout(T) => nomatch
- // foo(inout(const(U))) shared(T) => nomatch
- // foo(inout(const(U))) shared(const(T)) => nomatch
- // foo(inout(const(U))) shared(inout(T)) => nomatch
- // foo(shared(U)) T => nomatch
- // foo(shared(U)) const(T) => nomatch
- // foo(shared(U)) inout(T) => nomatch
- // foo(shared(U)) inout(const(T)) => nomatch
- // foo(shared(U)) immutable(T) => nomatch
- // foo(shared(const(U))) T => nomatch
- // foo(shared(const(U))) const(T) => nomatch
- // foo(shared(const(U))) inout(T) => nomatch
- // foo(shared(const(U))) inout(const(T)) => nomatch
- // foo(shared(inout(U))) T => nomatch
- // foo(shared(inout(U))) const(T) => nomatch
- // foo(shared(inout(U))) inout(T) => nomatch
- // foo(shared(inout(U))) inout(const(T)) => nomatch
- // foo(shared(inout(U))) immutable(T) => nomatch
- // foo(shared(inout(U))) shared(T) => nomatch
- // foo(shared(inout(U))) shared(const(T)) => nomatch
- // foo(shared(inout(U))) shared(inout(const(T))) => nomatch
- // foo(shared(inout(const(U)))) T => nomatch
- // foo(shared(inout(const(U)))) const(T) => nomatch
- // foo(shared(inout(const(U)))) inout(T) => nomatch
- // foo(shared(inout(const(U)))) inout(const(T)) => nomatch
- // foo(shared(inout(const(U)))) shared(T) => nomatch
- // foo(shared(inout(const(U)))) shared(const(T)) => nomatch
- // foo(immutable(U)) T => nomatch
- // foo(immutable(U)) const(T) => nomatch
- // foo(immutable(U)) inout(T) => nomatch
- // foo(immutable(U)) inout(const(T)) => nomatch
- // foo(immutable(U)) shared(T) => nomatch
- // foo(immutable(U)) shared(const(T)) => nomatch
- // foo(immutable(U)) shared(inout(T)) => nomatch
- // foo(immutable(U)) shared(inout(const(T))) => nomatch
- return MATCHnomatch;
-
- default:
- assert(0);
- return MATCHnomatch; // silence compiler warning about missing return
- }
- #undef X
-}
-
-/* These form the heart of template argument deduction.
- * Given 'this' being the type argument to the template instance,
- * it is matched against the template declaration parameter specialization
- * 'tparam' to determine the type to be used for the parameter.
- * Example:
- * template Foo(T:T*) // template declaration
- * Foo!(int*) // template instantiation
- * Input:
- * this = int*
- * tparam = T*
- * parameters = [ T:T* ] // Array of TemplateParameter's
- * Output:
- * dedtypes = [ int ] // Array of Expression/Type's
- */
-MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *parameters,
- Objects *dedtypes, unsigned *wm, size_t inferStart)
-{
- class DeduceType : public Visitor
- {
- public:
- Scope *sc;
- Type *tparam;
- TemplateParameters *parameters;
- Objects *dedtypes;
- unsigned *wm;
- size_t inferStart;
- MATCH result;
-
- DeduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wm, size_t inferStart)
- : sc(sc), tparam(tparam), parameters(parameters), dedtypes(dedtypes), wm(wm), inferStart(inferStart)
- {
- result = MATCHnomatch;
- }
-
- void visit(Type *t)
- {
- if (!tparam)
- goto Lnomatch;
-
- if (t == tparam)
- goto Lexact;
-
- if (tparam->ty == Tident)
- {
- // Determine which parameter tparam is
- size_t i = templateParameterLookup(tparam, parameters);
- if (i == IDX_NOTFOUND)
- {
- if (!sc)
- goto Lnomatch;
-
- /* Need a loc to go with the semantic routine.
- */
- Loc loc;
- if (parameters->length)
- {
- TemplateParameter *tp = (*parameters)[0];
- loc = tp->loc;
- }
-
- /* BUG: what if tparam is a template instance, that
- * has as an argument another Tident?
- */
- tparam = typeSemantic(tparam, loc, sc);
- assert(tparam->ty != Tident);
- result = deduceType(t, sc, tparam, parameters, dedtypes, wm);
- return;
- }
-
- TemplateParameter *tp = (*parameters)[i];
-
- TypeIdentifier *tident = (TypeIdentifier *)tparam;
- if (tident->idents.length > 0)
- {
- //printf("matching %s to %s\n", tparam->toChars(), t->toChars());
- Dsymbol *s = t->toDsymbol(sc);
- for (size_t j = tident->idents.length; j-- > 0; )
- {
- RootObject *id = tident->idents[j];
- if (id->dyncast() == DYNCAST_IDENTIFIER)
- {
- if (!s || !s->parent)
- goto Lnomatch;
- Dsymbol *s2 = s->parent->search(Loc(), (Identifier *)id);
- if (!s2)
- goto Lnomatch;
- s2 = s2->toAlias();
- //printf("[%d] s = %s %s, s2 = %s %s\n", j, s->kind(), s->toChars(), s2->kind(), s2->toChars());
- if (s != s2)
- {
- if (Type *tx = s2->getType())
- {
- if (s != tx->toDsymbol(sc))
- goto Lnomatch;
- }
- else
- goto Lnomatch;
- }
- s = s->parent;
- }
- else
- goto Lnomatch;
- }
- //printf("[e] s = %s\n", s?s->toChars():"(null)");
- if (tp->isTemplateTypeParameter())
- {
- Type *tt = s->getType();
- if (!tt)
- goto Lnomatch;
- Type *at = (Type *)(*dedtypes)[i];
- if (at && at->ty == Tnone)
- at = ((TypeDeduced *)at)->tded;
- if (!at || tt->equals(at))
- {
- (*dedtypes)[i] = tt;
- goto Lexact;
- }
- }
- if (tp->isTemplateAliasParameter())
- {
- Dsymbol *s2 = (Dsymbol *)(*dedtypes)[i];
- if (!s2 || s == s2)
- {
- (*dedtypes)[i] = s;
- goto Lexact;
- }
- }
- goto Lnomatch;
- }
-
- // Found the corresponding parameter tp
- if (!tp->isTemplateTypeParameter())
- goto Lnomatch;
-
- Type *at = (Type *)(*dedtypes)[i];
- Type *tt;
- if (unsigned char wx = wm ? deduceWildHelper(t, &tt, tparam) : 0)
- {
- // type vs (none)
- if (!at)
- {
- (*dedtypes)[i] = tt;
- *wm |= wx;
- result = MATCHconst;
- return;
- }
-
- // type vs expressions
- if (at->ty == Tnone)
- {
- TypeDeduced *xt = (TypeDeduced *)at;
- result = xt->matchAll(tt);
- if (result > MATCHnomatch)
- {
- (*dedtypes)[i] = tt;
- if (result > MATCHconst)
- result = MATCHconst; // limit level for inout matches
- delete xt;
- }
- return;
- }
-
- // type vs type
- if (tt->equals(at))
- {
- (*dedtypes)[i] = tt; // Prefer current type match
- goto Lconst;
- }
- if (tt->implicitConvTo(at->constOf()))
- {
- (*dedtypes)[i] = at->constOf()->mutableOf();
- *wm |= MODconst;
- goto Lconst;
- }
- if (at->implicitConvTo(tt->constOf()))
- {
- (*dedtypes)[i] = tt->constOf()->mutableOf();
- *wm |= MODconst;
- goto Lconst;
- }
- goto Lnomatch;
- }
- else if (MATCH m = deduceTypeHelper(t, &tt, tparam))
- {
- // type vs (none)
- if (!at)
- {
- (*dedtypes)[i] = tt;
- result = m;
- return;
- }
-
- // type vs expressions
- if (at->ty == Tnone)
- {
- TypeDeduced *xt = (TypeDeduced *)at;
- result = xt->matchAll(tt);
- if (result > MATCHnomatch)
- {
- (*dedtypes)[i] = tt;
- delete xt;
- }
- return;
- }
-
- // type vs type
- if (tt->equals(at))
- {
- goto Lexact;
- }
- if (tt->ty == Tclass && at->ty == Tclass)
- {
- result = tt->implicitConvTo(at);
- return;
- }
- if (tt->ty == Tsarray && at->ty == Tarray &&
- tt->nextOf()->implicitConvTo(at->nextOf()) >= MATCHconst)
- {
- goto Lexact;
- }
- }
- goto Lnomatch;
- }
-
- if (tparam->ty == Ttypeof)
- {
- /* Need a loc to go with the semantic routine.
- */
- Loc loc;
- if (parameters->length)
- {
- TemplateParameter *tp = (*parameters)[0];
- loc = tp->loc;
- }
-
- tparam = typeSemantic(tparam, loc, sc);
- }
- if (t->ty != tparam->ty)
- {
- if (Dsymbol *sym = t->toDsymbol(sc))
- {
- if (sym->isforwardRef() && !tparam->deco)
- goto Lnomatch;
- }
-
- MATCH m = t->implicitConvTo(tparam);
- if (m == MATCHnomatch)
- {
- if (t->ty == Tclass)
- {
- TypeClass *tc = (TypeClass *)t;
- if (tc->sym->aliasthis && !(tc->att & RECtracingDT))
- {
- tc->att = (AliasThisRec)(tc->att | RECtracingDT);
- m = deduceType(t->aliasthisOf(), sc, tparam, parameters, dedtypes, wm);
- tc->att = (AliasThisRec)(tc->att & ~RECtracingDT);
- }
- }
- else if (t->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)t;
- if (ts->sym->aliasthis && !(ts->att & RECtracingDT))
- {
- ts->att = (AliasThisRec)(ts->att | RECtracingDT);
- m = deduceType(t->aliasthisOf(), sc, tparam, parameters, dedtypes, wm);
- ts->att = (AliasThisRec)(ts->att & ~RECtracingDT);
- }
- }
- }
- result = m;
- return;
- }
-
- if (t->nextOf())
- {
- if (tparam->deco && !tparam->hasWild())
- {
- result = t->implicitConvTo(tparam);
- return;
- }
-
- Type *tpn = tparam->nextOf();
- if (wm && t->ty == Taarray && tparam->isWild())
- {
- // Bugzilla 12403: In IFTI, stop inout matching on transitive part of AA types.
- tpn = tpn->substWildTo(MODmutable);
- }
-
- result = deduceType(t->nextOf(), sc, tpn, parameters, dedtypes, wm);
- return;
- }
-
- Lexact:
- result = MATCHexact;
- return;
-
- Lnomatch:
- result = MATCHnomatch;
- return;
-
- Lconst:
- result = MATCHconst;
- }
-
- void visit(TypeVector *t)
- {
- if (tparam->ty == Tvector)
- {
- TypeVector *tp = (TypeVector *)tparam;
- result = deduceType(t->basetype, sc, tp->basetype, parameters, dedtypes, wm);
- return;
- }
- visit((Type *)t);
- }
-
- void visit(TypeDArray *t)
- {
- visit((Type *)t);
- }
-
- void visit(TypeSArray *t)
- {
- // Extra check that array dimensions must match
- if (tparam)
- {
- if (tparam->ty == Tarray)
- {
- MATCH m = deduceType(t->next, sc, tparam->nextOf(), parameters, dedtypes, wm);
- result = (m >= MATCHconst) ? MATCHconvert : MATCHnomatch;
- return;
- }
-
- TemplateParameter *tp = NULL;
- Expression *edim = NULL;
- size_t i;
- if (tparam->ty == Tsarray)
- {
- TypeSArray *tsa = (TypeSArray *)tparam;
- if (tsa->dim->op == TOKvar &&
- ((VarExp *)tsa->dim)->var->storage_class & STCtemplateparameter)
- {
- Identifier *id = ((VarExp *)tsa->dim)->var->ident;
- i = templateIdentifierLookup(id, parameters);
- assert(i != IDX_NOTFOUND);
- tp = (*parameters)[i];
- }
- else
- edim = tsa->dim;
- }
- else if (tparam->ty == Taarray)
- {
- TypeAArray *taa = (TypeAArray *)tparam;
- i = templateParameterLookup(taa->index, parameters);
- if (i != IDX_NOTFOUND)
- tp = (*parameters)[i];
- else
- {
- Expression *e;
- Type *tx;
- Dsymbol *s;
- taa->index->resolve(Loc(), sc, &e, &tx, &s);
- edim = s ? getValue(s) : getValue(e);
- }
- }
- if ((tp && tp->matchArg(sc, t->dim, i, parameters, dedtypes, NULL)) ||
- (edim && edim->toInteger() == t->dim->toInteger()))
- {
- result = deduceType(t->next, sc, tparam->nextOf(), parameters, dedtypes, wm);
- return;
- }
- }
- visit((Type *)t);
- return;
-
- result = MATCHnomatch;
- }
-
- void visit(TypeAArray *t)
- {
- // Extra check that index type must match
- if (tparam && tparam->ty == Taarray)
- {
- TypeAArray *tp = (TypeAArray *)tparam;
- if (!deduceType(t->index, sc, tp->index, parameters, dedtypes))
- {
- result = MATCHnomatch;
- return;
- }
- }
- visit((Type *)t);
- }
-
- void visit(TypeFunction *t)
- {
- //printf("TypeFunction::deduceType()\n");
- //printf("\tthis = %d, ", t->ty); t->print();
- //printf("\ttparam = %d, ", tparam->ty); tparam->print();
-
- // Extra check that function characteristics must match
- if (tparam && tparam->ty == Tfunction)
- {
- TypeFunction *tp = (TypeFunction *)tparam;
- if (t->parameterList.varargs != tp->parameterList.varargs ||
- t->linkage != tp->linkage)
- {
- result = MATCHnomatch;
- return;
- }
-
- size_t nfargs = t->parameterList.length();
- size_t nfparams = tp->parameterList.length();
-
- // bug 2579 fix: Apply function parameter storage classes to parameter types
- for (size_t i = 0; i < nfparams; i++)
- {
- Parameter *fparam = tp->parameterList[i];
- fparam->type = fparam->type->addStorageClass(fparam->storageClass);
- fparam->storageClass &= ~(STC_TYPECTOR | STCin);
- }
- //printf("\t-> this = %d, ", t->ty); t->print();
- //printf("\t-> tparam = %d, ", tparam->ty); tparam->print();
-
- /* See if tuple match
- */
- if (nfparams > 0 && nfargs >= nfparams - 1)
- {
- /* See if 'A' of the template parameter matches 'A'
- * of the type of the last function parameter.
- */
- Parameter *fparam = tp->parameterList[nfparams - 1];
- assert(fparam);
- assert(fparam->type);
- if (fparam->type->ty != Tident)
- goto L1;
- TypeIdentifier *tid = (TypeIdentifier *)fparam->type;
- if (tid->idents.length)
- goto L1;
-
- /* Look through parameters to find tuple matching tid->ident
- */
- size_t tupi = 0;
- for (; 1; tupi++)
- {
- if (tupi == parameters->length)
- goto L1;
- TemplateParameter *tx = (*parameters)[tupi];
- TemplateTupleParameter *tup = tx->isTemplateTupleParameter();
- if (tup && tup->ident->equals(tid->ident))
- break;
- }
-
- /* The types of the function arguments [nfparams - 1 .. nfargs]
- * now form the tuple argument.
- */
- size_t tuple_dim = nfargs - (nfparams - 1);
-
- /* See if existing tuple, and whether it matches or not
- */
- RootObject *o = (*dedtypes)[tupi];
- if (o)
- {
- // Existing deduced argument must be a tuple, and must match
- Tuple *tup = isTuple(o);
- if (!tup || tup->objects.length != tuple_dim)
- {
- result = MATCHnomatch;
- return;
- }
- for (size_t i = 0; i < tuple_dim; i++)
- {
- Parameter *arg = t->parameterList[nfparams - 1 + i];
- if (!arg->type->equals(tup->objects[i]))
- {
- result = MATCHnomatch;
- return;
- }
- }
- }
- else
- {
- // Create new tuple
- Tuple *tup = new Tuple();
- tup->objects.setDim(tuple_dim);
- for (size_t i = 0; i < tuple_dim; i++)
- {
- Parameter *arg = t->parameterList[nfparams - 1 + i];
- tup->objects[i] = arg->type;
- }
- (*dedtypes)[tupi] = tup;
- }
- nfparams--; // don't consider the last parameter for type deduction
- goto L2;
- }
-
- L1:
- if (nfargs != nfparams)
- {
- result = MATCHnomatch;
- return;
- }
- L2:
- for (size_t i = 0; i < nfparams; i++)
- {
- Parameter *a = t->parameterList[i];
- Parameter *ap = tp->parameterList[i];
-
- if (!a->isCovariant(t->isref, ap) ||
- !deduceType(a->type, sc, ap->type, parameters, dedtypes))
- {
- result = MATCHnomatch;
- return;
- }
- }
- }
- visit((Type *)t);
- }
-
- void visit(TypeIdentifier *t)
- {
- // Extra check
- if (tparam && tparam->ty == Tident)
- {
- TypeIdentifier *tp = (TypeIdentifier *)tparam;
-
- for (size_t i = 0; i < t->idents.length; i++)
- {
- RootObject *id1 = t->idents[i];
- RootObject *id2 = tp->idents[i];
-
- if (!id1->equals(id2))
- {
- result = MATCHnomatch;
- return;
- }
- }
- }
- visit((Type *)t);
- }
-
- void visit(TypeInstance *t)
- {
- // Extra check
- if (tparam && tparam->ty == Tinstance && t->tempinst->tempdecl)
- {
- TemplateDeclaration *tempdecl = t->tempinst->tempdecl->isTemplateDeclaration();
- assert(tempdecl);
-
- TypeInstance *tp = (TypeInstance *)tparam;
-
- //printf("tempinst->tempdecl = %p\n", tempdecl);
- //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl);
- if (!tp->tempinst->tempdecl)
- {
- //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars());
-
- /* Handle case of:
- * template Foo(T : sa!(T), alias sa)
- */
- size_t i = templateIdentifierLookup(tp->tempinst->name, parameters);
- if (i == IDX_NOTFOUND)
- {
- /* Didn't find it as a parameter identifier. Try looking
- * it up and seeing if is an alias. See Bugzilla 1454
- */
- TypeIdentifier *tid = new TypeIdentifier(tp->loc, tp->tempinst->name);
- Type *tx;
- Expression *e;
- Dsymbol *s;
- tid->resolve(tp->loc, sc, &e, &tx, &s);
- if (tx)
- {
- s = tx->toDsymbol(sc);
- if (TemplateInstance *ti = s ? s->parent->isTemplateInstance() : NULL)
- {
- // Bugzilla 14290: Try to match with ti->tempecl,
- // only when ti is an enclosing instance.
- Dsymbol *p = sc->parent;
- while (p && p != ti)
- p = p->parent;
- if (p)
- s = ti->tempdecl;
- }
- }
- if (s)
- {
- s = s->toAlias();
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (td)
- {
- if (td->overroot)
- td = td->overroot;
- for (; td; td = td->overnext)
- {
- if (td == tempdecl)
- goto L2;
- }
- }
- }
- goto Lnomatch;
- }
- TemplateParameter *tpx = (*parameters)[i];
- if (!tpx->matchArg(sc, tempdecl, i, parameters, dedtypes, NULL))
- goto Lnomatch;
- }
- else if (tempdecl != tp->tempinst->tempdecl)
- goto Lnomatch;
-
- L2:
-
- for (size_t i = 0; 1; i++)
- {
- //printf("\ttest: tempinst->tiargs[%d]\n", i);
- RootObject *o1 = NULL;
- if (i < t->tempinst->tiargs->length)
- o1 = (*t->tempinst->tiargs)[i];
- else if (i < t->tempinst->tdtypes.length && i < tp->tempinst->tiargs->length)
- {
- // Pick up default arg
- o1 = t->tempinst->tdtypes[i];
- }
- else if (i >= tp->tempinst->tiargs->length)
- break;
-
- if (i >= tp->tempinst->tiargs->length)
- {
- size_t dim = tempdecl->parameters->length - (tempdecl->isVariadic() ? 1 : 0);
- while (i < dim && ((*tempdecl->parameters)[i]->dependent ||
- (*tempdecl->parameters)[i]->hasDefaultArg()))
- {
- i++;
- }
- if (i >= dim)
- break; // match if all remained parameters are dependent
- goto Lnomatch;
- }
-
- RootObject *o2 = (*tp->tempinst->tiargs)[i];
- Type *t2 = isType(o2);
-
- size_t j = (t2 && t2->ty == Tident && i == tp->tempinst->tiargs->length - 1)
- ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND;
- if (j != IDX_NOTFOUND && j == parameters->length - 1 &&
- (*parameters)[j]->isTemplateTupleParameter())
- {
- /* Given:
- * struct A(B...) {}
- * alias A!(int, float) X;
- * static if (is(X Y == A!(Z), Z...)) {}
- * deduce that Z is a tuple(int, float)
- */
-
- /* Create tuple from remaining args
- */
- Tuple *vt = new Tuple();
- size_t vtdim = (tempdecl->isVariadic()
- ? t->tempinst->tiargs->length : t->tempinst->tdtypes.length) - i;
- vt->objects.setDim(vtdim);
- for (size_t k = 0; k < vtdim; k++)
- {
- RootObject *o;
- if (k < t->tempinst->tiargs->length)
- o = (*t->tempinst->tiargs)[i + k];
- else // Pick up default arg
- o = t->tempinst->tdtypes[i + k];
- vt->objects[k] = o;
- }
-
- Tuple *v = (Tuple *)(*dedtypes)[j];
- if (v)
- {
- if (!match(v, vt))
- goto Lnomatch;
- }
- else
- (*dedtypes)[j] = vt;
- break;
- }
- else if (!o1)
- break;
-
- Type *t1 = isType(o1);
- Dsymbol *s1 = isDsymbol(o1);
- Dsymbol *s2 = isDsymbol(o2);
- Expression *e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
- Expression *e2 = isExpression(o2);
-
- if (t1 && t2)
- {
- if (!deduceType(t1, sc, t2, parameters, dedtypes))
- goto Lnomatch;
- }
- else if (e1 && e2)
- {
- Le:
- e1 = e1->ctfeInterpret();
-
- /* If it is one of the template parameters for this template,
- * we should not attempt to interpret it. It already has a value.
- */
- if (e2->op == TOKvar &&
- (((VarExp *)e2)->var->storage_class & STCtemplateparameter))
- {
- /*
- * (T:Number!(e2), int e2)
- */
- j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters);
- if (j != IDX_NOTFOUND)
- goto L1;
- // The template parameter was not from this template
- // (it may be from a parent template, for example)
- }
-
- e2 = expressionSemantic(e2, sc); // Bugzilla 13417
- e2 = e2->ctfeInterpret();
-
- //printf("e1 = %s, type = %s %d\n", e1->toChars(), e1->type->toChars(), e1->type->ty);
- //printf("e2 = %s, type = %s %d\n", e2->toChars(), e2->type->toChars(), e2->type->ty);
- if (!e1->equals(e2))
- {
- if (!e2->implicitConvTo(e1->type))
- goto Lnomatch;
-
- e2 = e2->implicitCastTo(sc, e1->type);
- e2 = e2->ctfeInterpret();
- if (!e1->equals(e2))
- goto Lnomatch;
- }
- }
- else if (e1 && t2 && t2->ty == Tident)
- {
- j = templateParameterLookup(t2, parameters);
- L1:
- if (j == IDX_NOTFOUND)
- {
- t2->resolve(((TypeIdentifier *)t2)->loc, sc, &e2, &t2, &s2);
- if (e2)
- goto Le;
- goto Lnomatch;
- }
- if (!(*parameters)[j]->matchArg(sc, e1, j, parameters, dedtypes, NULL))
- goto Lnomatch;
- }
- else if (s1 && s2)
- {
- Ls:
- if (!s1->equals(s2))
- goto Lnomatch;
- }
- else if (s1 && t2 && t2->ty == Tident)
- {
- j = templateParameterLookup(t2, parameters);
- if (j == IDX_NOTFOUND)
- {
- t2->resolve(((TypeIdentifier *)t2)->loc, sc, &e2, &t2, &s2);
- if (s2)
- goto Ls;
- goto Lnomatch;
- }
- if (!(*parameters)[j]->matchArg(sc, s1, j, parameters, dedtypes, NULL))
- goto Lnomatch;
- }
- else
- goto Lnomatch;
- }
- }
- visit((Type *)t);
- return;
-
- Lnomatch:
- //printf("no match\n");
- result = MATCHnomatch;
- }
-
- void visit(TypeStruct *t)
- {
- /* If this struct is a template struct, and we're matching
- * it against a template instance, convert the struct type
- * to a template instance, too, and try again.
- */
- TemplateInstance *ti = t->sym->parent->isTemplateInstance();
-
- if (tparam && tparam->ty == Tinstance)
- {
- if (ti && ti->toAlias() == t->sym)
- {
- TypeInstance *tx = new TypeInstance(Loc(), ti);
- result = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
- return;
- }
-
- /* Match things like:
- * S!(T).foo
- */
- TypeInstance *tpi = (TypeInstance *)tparam;
- if (tpi->idents.length)
- {
- RootObject *id = tpi->idents[tpi->idents.length - 1];
- if (id->dyncast() == DYNCAST_IDENTIFIER && t->sym->ident->equals((Identifier *)id))
- {
- Type *tparent = t->sym->parent->getType();
- if (tparent)
- {
- /* Slice off the .foo in S!(T).foo
- */
- tpi->idents.length--;
- result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
- tpi->idents.length++;
- return;
- }
- }
- }
- }
-
- // Extra check
- if (tparam && tparam->ty == Tstruct)
- {
- TypeStruct *tp = (TypeStruct *)tparam;
-
- //printf("\t%d\n", (MATCH) t->implicitConvTo(tp));
- if (wm && t->deduceWild(tparam, false))
- {
- result = MATCHconst;
- return;
- }
- result = t->implicitConvTo(tp);
- return;
- }
- visit((Type *)t);
- }
-
- void visit(TypeEnum *t)
- {
- // Extra check
- if (tparam && tparam->ty == Tenum)
- {
- TypeEnum *tp = (TypeEnum *)tparam;
- if (t->sym == tp->sym)
- visit((Type *)t);
- else
- result = MATCHnomatch;
- return;
- }
- Type *tb = t->toBasetype();
- if (tb->ty == tparam->ty ||
- (tb->ty == Tsarray && tparam->ty == Taarray))
- {
- result = deduceType(tb, sc, tparam, parameters, dedtypes, wm);
- return;
- }
- visit((Type *)t);
- }
-
- /* Helper for TypeClass::deduceType().
- * Classes can match with implicit conversion to a base class or interface.
- * This is complicated, because there may be more than one base class which
- * matches. In such cases, one or more parameters remain ambiguous.
- * For example,
- *
- * interface I(X, Y) {}
- * class C : I(uint, double), I(char, double) {}
- * C x;
- * foo(T, U)( I!(T, U) x)
- *
- * deduces that U is double, but T remains ambiguous (could be char or uint).
- *
- * Given a baseclass b, and initial deduced types 'dedtypes', this function
- * tries to match tparam with b, and also tries all base interfaces of b.
- * If a match occurs, numBaseClassMatches is incremented, and the new deduced
- * types are ANDed with the current 'best' estimate for dedtypes.
- */
- static void deduceBaseClassParameters(BaseClass *b,
- Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes,
- Objects *best, int &numBaseClassMatches)
- {
- TemplateInstance *parti = b->sym ? b->sym->parent->isTemplateInstance() : NULL;
- if (parti)
- {
- // Make a temporary copy of dedtypes so we don't destroy it
- Objects *tmpdedtypes = new Objects();
- tmpdedtypes->setDim(dedtypes->length);
- memcpy(tmpdedtypes->tdata(), dedtypes->tdata(), dedtypes->length * sizeof(void *));
-
- TypeInstance *t = new TypeInstance(Loc(), parti);
- MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes);
- if (m > MATCHnomatch)
- {
- // If this is the first ever match, it becomes our best estimate
- if (numBaseClassMatches==0)
- memcpy(best->tdata(), tmpdedtypes->tdata(), tmpdedtypes->length * sizeof(void *));
- else for (size_t k = 0; k < tmpdedtypes->length; ++k)
- {
- // If we've found more than one possible type for a parameter,
- // mark it as unknown.
- if ((*tmpdedtypes)[k] != (*best)[k])
- (*best)[k] = (*dedtypes)[k];
- }
- ++numBaseClassMatches;
- }
- }
- // Now recursively test the inherited interfaces
- for (size_t j = 0; j < b->baseInterfaces.length; ++j)
- {
- BaseClass *bi = &b->baseInterfaces.ptr[j];
- deduceBaseClassParameters(bi,
- sc, tparam, parameters, dedtypes,
- best, numBaseClassMatches);
- }
-
- }
-
- void visit(TypeClass *t)
- {
- //printf("TypeClass::deduceType(this = %s)\n", t->toChars());
-
- /* If this class is a template class, and we're matching
- * it against a template instance, convert the class type
- * to a template instance, too, and try again.
- */
- TemplateInstance *ti = t->sym->parent->isTemplateInstance();
-
- if (tparam && tparam->ty == Tinstance)
- {
- if (ti && ti->toAlias() == t->sym)
- {
- TypeInstance *tx = new TypeInstance(Loc(), ti);
- MATCH m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
- // Even if the match fails, there is still a chance it could match
- // a base class.
- if (m != MATCHnomatch)
- {
- result = m;
- return;
- }
- }
-
- /* Match things like:
- * S!(T).foo
- */
- TypeInstance *tpi = (TypeInstance *)tparam;
- if (tpi->idents.length)
- {
- RootObject *id = tpi->idents[tpi->idents.length - 1];
- if (id->dyncast() == DYNCAST_IDENTIFIER && t->sym->ident->equals((Identifier *)id))
- {
- Type *tparent = t->sym->parent->getType();
- if (tparent)
- {
- /* Slice off the .foo in S!(T).foo
- */
- tpi->idents.length--;
- result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
- tpi->idents.length++;
- return;
- }
- }
- }
-
- // If it matches exactly or via implicit conversion, we're done
- visit((Type *)t);
- if (result != MATCHnomatch)
- return;
-
- /* There is still a chance to match via implicit conversion to
- * a base class or interface. Because there could be more than one such
- * match, we need to check them all.
- */
-
- int numBaseClassMatches = 0; // Have we found an interface match?
-
- // Our best guess at dedtypes
- Objects *best = new Objects();
- best->setDim(dedtypes->length);
-
- ClassDeclaration *s = t->sym;
- while (s && s->baseclasses->length > 0)
- {
- // Test the base class
- deduceBaseClassParameters((*s->baseclasses)[0],
- sc, tparam, parameters, dedtypes,
- best, numBaseClassMatches);
-
- // Test the interfaces inherited by the base class
- for (size_t i = 0; i < s->interfaces.length; ++i)
- {
- BaseClass *b = s->interfaces.ptr[i];
- deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes,
- best, numBaseClassMatches);
- }
- s = (*s->baseclasses)[0]->sym;
- }
-
- if (numBaseClassMatches == 0)
- {
- result = MATCHnomatch;
- return;
- }
-
- // If we got at least one match, copy the known types into dedtypes
- memcpy(dedtypes->tdata(), best->tdata(), best->length * sizeof(void *));
- result = MATCHconvert;
- return;
- }
-
- // Extra check
- if (tparam && tparam->ty == Tclass)
- {
- TypeClass *tp = (TypeClass *)tparam;
-
- //printf("\t%d\n", (MATCH) t->implicitConvTo(tp));
- if (wm && t->deduceWild(tparam, false))
- {
- result = MATCHconst;
- return;
- }
- result = t->implicitConvTo(tp);
- return;
- }
- visit((Type *)t);
- }
-
- void visit(Expression *e)
- {
- //printf("Expression::deduceType(e = %s)\n", e->toChars());
- size_t i = templateParameterLookup(tparam, parameters);
- if (i == IDX_NOTFOUND || ((TypeIdentifier *)tparam)->idents.length > 0)
- {
- if (e == emptyArrayElement && tparam->ty == Tarray)
- {
- Type *tn = ((TypeNext *)tparam)->next;
- result = deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
- return;
- }
- e->type->accept(this);
- return;
- }
-
- TemplateTypeParameter *tp = (*parameters)[i]->isTemplateTypeParameter();
- if (!tp)
- return; // nomatch
-
- if (e == emptyArrayElement)
- {
- if ((*dedtypes)[i])
- {
- result = MATCHexact;
- return;
- }
- if (tp->defaultType)
- {
- tp->defaultType->accept(this);
- return;
- }
- }
-
- Type *at = (Type *)(*dedtypes)[i];
- Type *tt;
- if (unsigned char wx = deduceWildHelper(e->type, &tt, tparam))
- {
- *wm |= wx;
- result = MATCHconst;
- }
- else if (MATCH m = deduceTypeHelper(e->type, &tt, tparam))
- {
- result = m;
- }
- else
- return; // nomatch
-
- // expression vs (none)
- if (!at)
- {
- (*dedtypes)[i] = new TypeDeduced(tt, e, tparam);
- return;
- }
-
- TypeDeduced *xt = NULL;
- if (at->ty == Tnone)
- {
- xt = (TypeDeduced *)at;
- at = xt->tded;
- }
-
- // From previous matched expressions to current deduced type
- MATCH match1 = xt ? xt->matchAll(tt) : MATCHnomatch;
-
- // From current expresssion to previous deduced type
- Type *pt = at->addMod(tparam->mod);
- if (*wm)
- pt = pt->substWildTo(*wm);
- MATCH match2 = e->implicitConvTo(pt);
-
- if (match1 > MATCHnomatch && match2 > MATCHnomatch)
- {
- if (at->implicitConvTo(tt) <= MATCHnomatch)
- match1 = MATCHnomatch; // Prefer at
- else if (tt->implicitConvTo(at) <= MATCHnomatch)
- match2 = MATCHnomatch; // Prefer tt
- else if (tt->isTypeBasic() && tt->ty == at->ty && tt->mod != at->mod)
- {
- if (!tt->isMutable() && !at->isMutable())
- tt = tt->mutableOf()->addMod(MODmerge(tt->mod, at->mod));
- else if (tt->isMutable())
- {
- if (at->mod == 0) // Prefer unshared
- match1 = MATCHnomatch;
- else
- match2 = MATCHnomatch;
- }
- else if (at->isMutable())
- {
- if (tt->mod == 0) // Prefer unshared
- match2 = MATCHnomatch;
- else
- match1 = MATCHnomatch;
- }
- //printf("tt = %s, at = %s\n", tt->toChars(), at->toChars());
- }
- else
- {
- match1 = MATCHnomatch;
- match2 = MATCHnomatch;
- }
- }
- if (match1 > MATCHnomatch)
- {
- // Prefer current match: tt
- if (xt)
- xt->update(tt, e, tparam);
- else
- (*dedtypes)[i] = tt;
- result = match1;
- return;
- }
- if (match2 > MATCHnomatch)
- {
- // Prefer previous match: (*dedtypes)[i]
- if (xt)
- xt->update(e, tparam);
- result = match2;
- return;
- }
-
- /* Deduce common type
- */
- if (Type *t = rawTypeMerge(at, tt))
- {
- if (xt)
- xt->update(t, e, tparam);
- else
- (*dedtypes)[i] = t;
-
- pt = tt->addMod(tparam->mod);
- if (*wm)
- pt = pt->substWildTo(*wm);
- result = e->implicitConvTo(pt);
- return;
- }
-
- result = MATCHnomatch;
- }
-
- MATCH deduceEmptyArrayElement()
- {
- if (!emptyArrayElement)
- {
- emptyArrayElement = new IdentifierExp(Loc(), Id::p); // dummy
- emptyArrayElement->type = Type::tvoid;
- }
- assert(tparam->ty == Tarray);
-
- Type *tn = ((TypeNext *)tparam)->next;
- return deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
- }
-
- void visit(NullExp *e)
- {
- if (tparam->ty == Tarray && e->type->ty == Tnull)
- {
- // tparam:T[] <- e:null (void[])
- result = deduceEmptyArrayElement();
- return;
- }
- visit((Expression *)e);
- }
-
- void visit(StringExp *e)
- {
- Type *taai;
- if (e->type->ty == Tarray &&
- (tparam->ty == Tsarray ||
- (tparam->ty == Taarray && (taai = ((TypeAArray *)tparam)->index)->ty == Tident &&
- ((TypeIdentifier *)taai)->idents.length == 0)))
- {
- // Consider compile-time known boundaries
- e->type->nextOf()->sarrayOf(e->len)->accept(this);
- return;
- }
- visit((Expression *)e);
- }
-
- void visit(ArrayLiteralExp *e)
- {
- // https://issues.dlang.org/show_bug.cgi?id=20092
- if (e->elements && e->elements->length &&
- e->type->toBasetype()->nextOf()->ty == Tvoid)
- {
- result = deduceEmptyArrayElement();
- return;
- }
- if ((!e->elements || !e->elements->length) &&
- e->type->toBasetype()->nextOf()->ty == Tvoid &&
- tparam->ty == Tarray)
- {
- // tparam:T[] <- e:[] (void[])
- result = deduceEmptyArrayElement();
- return;
- }
-
- if (tparam->ty == Tarray && e->elements && e->elements->length)
- {
- Type *tn = ((TypeDArray *)tparam)->next;
- result = MATCHexact;
- if (e->basis)
- {
- MATCH m = deduceType(e->basis, sc, tn, parameters, dedtypes, wm);
- if (m < result)
- result = m;
- }
- for (size_t i = 0; i < e->elements->length; i++)
- {
- if (result <= MATCHnomatch)
- break;
- Expression *el = (*e->elements)[i];
- if (!el)
- continue;
- MATCH m = deduceType(el, sc, tn, parameters, dedtypes, wm);
- if (m < result)
- result = m;
- }
- return;
- }
-
- Type *taai;
- if (e->type->ty == Tarray &&
- (tparam->ty == Tsarray ||
- (tparam->ty == Taarray && (taai = ((TypeAArray *)tparam)->index)->ty == Tident &&
- ((TypeIdentifier *)taai)->idents.length == 0)))
- {
- // Consider compile-time known boundaries
- e->type->nextOf()->sarrayOf(e->elements->length)->accept(this);
- return;
- }
- visit((Expression *)e);
- }
-
- void visit(AssocArrayLiteralExp *e)
- {
- if (tparam->ty == Taarray && e->keys && e->keys->length)
- {
- TypeAArray *taa = (TypeAArray *)tparam;
- result = MATCHexact;
- for (size_t i = 0; i < e->keys->length; i++)
- {
- MATCH m1 = deduceType((*e->keys)[i], sc, taa->index, parameters, dedtypes, wm);
- if (m1 < result)
- result = m1;
- if (result <= MATCHnomatch)
- break;
- MATCH m2 = deduceType((*e->values)[i], sc, taa->next, parameters, dedtypes, wm);
- if (m2 < result)
- result = m2;
- if (result <= MATCHnomatch)
- break;
- }
- return;
- }
- visit((Expression *)e);
- }
-
- void visit(FuncExp *e)
- {
- //printf("e->type = %s, tparam = %s\n", e->type->toChars(), tparam->toChars());
- if (e->td)
- {
- Type *to = tparam;
- if (!to->nextOf() || to->nextOf()->ty != Tfunction)
- return;
- TypeFunction *tof = (TypeFunction *)to->nextOf();
-
- // Parameter types inference from 'tof'
- assert(e->td->_scope);
- TypeFunction *tf = (TypeFunction *)e->fd->type;
- //printf("\ttof = %s\n", tof->toChars());
- //printf("\ttf = %s\n", tf->toChars());
- size_t dim = tf->parameterList.length();
-
- if (tof->parameterList.length() != dim ||
- tof->parameterList.varargs != tf->parameterList.varargs)
- return;
-
- Objects *tiargs = new Objects();
- tiargs->reserve(e->td->parameters->length);
-
- for (size_t i = 0; i < e->td->parameters->length; i++)
- {
- TemplateParameter *tp = (*e->td->parameters)[i];
- size_t u = 0;
- for (; u < dim; u++)
- {
- Parameter *p = tf->parameterList[u];
- if (p->type->ty == Tident &&
- ((TypeIdentifier *)p->type)->ident == tp->ident)
- {
- break;
- }
- }
- assert(u < dim);
- Parameter *pto = tof->parameterList[u];
- if (!pto)
- break;
- Type *t = pto->type->syntaxCopy(); // Bugzilla 11774
- if (reliesOnTident(t, parameters, inferStart))
- return;
- t = typeSemantic(t, e->loc, sc);
- if (t->ty == Terror)
- return;
- tiargs->push(t);
- }
-
- // Set target of return type inference
- if (!tf->next && tof->next)
- e->fd->treq = tparam;
-
- TemplateInstance *ti = new TemplateInstance(e->loc, e->td, tiargs);
- Expression *ex = new ScopeExp(e->loc, ti);
- ex = expressionSemantic(ex, e->td->_scope);
-
- // Reset inference target for the later re-semantic
- e->fd->treq = NULL;
-
- if (ex->op == TOKerror)
- return;
- if (ex->op != TOKfunction)
- return;
- visit(ex->type);
- return;
- }
-
- Type *t = e->type;
-
- if (t->ty == Tdelegate && tparam->ty == Tpointer)
- return;
-
- // Allow conversion from implicit function pointer to delegate
- if (e->tok == TOKreserved &&
- t->ty == Tpointer && tparam->ty == Tdelegate)
- {
- TypeFunction *tf = (TypeFunction *)t->nextOf();
- t = (new TypeDelegate(tf))->merge();
- }
- //printf("tparam = %s <= e->type = %s, t = %s\n", tparam->toChars(), e->type->toChars(), t->toChars());
- visit(t);
- }
-
- void visit(SliceExp *e)
- {
- Type *taai;
- if (e->type->ty == Tarray &&
- (tparam->ty == Tsarray ||
- (tparam->ty == Taarray && (taai = ((TypeAArray *)tparam)->index)->ty == Tident &&
- ((TypeIdentifier *)taai)->idents.length == 0)))
- {
- // Consider compile-time known boundaries
- if (Type *tsa = toStaticArrayType(e))
- {
- tsa->accept(this);
- return;
- }
- }
- visit((Expression *)e);
- }
-
- void visit(CommaExp *e)
- {
- ((CommaExp *)e)->e2->accept(this);
- }
- };
-
- DeduceType v(sc, tparam, parameters, dedtypes, wm, inferStart);
- if (Type *t = isType(o))
- t->accept(&v);
- else
- {
- assert(isExpression(o) && wm);
- ((Expression *)o)->accept(&v);
- }
- return v.result;
-}
-
-/*******************************
- * Input:
- * t Tested type, if NULL, returns NULL.
- * tparams Optional template parameters.
- * == NULL:
- * If one of the subtypes of this type is a TypeIdentifier,
- * i.e. it's an unresolved type, return that type.
- * != NULL:
- * Only when the TypeIdentifier is one of template parameters,
- * return that type.
- */
-
-bool reliesOnTident(Type *t, TemplateParameters *tparams, size_t iStart)
-{
- class ReliesOnTident : public Visitor
- {
- public:
- TemplateParameters *tparams;
- size_t iStart;
- bool result;
-
- ReliesOnTident(TemplateParameters *tparams, size_t iStart)
- : tparams(tparams), iStart(iStart)
- {
- result = false;
- }
-
- void visit(Type *)
- {
- }
-
- void visit(TypeNext *t)
- {
- t->next->accept(this);
- }
-
- void visit(TypeVector *t)
- {
- t->basetype->accept(this);
- }
-
- void visit(TypeAArray *t)
- {
- visit((TypeNext *)t);
- if (!result)
- t->index->accept(this);
- }
-
- void visit(TypeFunction *t)
- {
- size_t dim = t->parameterList.length();
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *fparam = t->parameterList[i];
- fparam->type->accept(this);
- if (result)
- return;
- }
- if (t->next)
- t->next->accept(this);
- }
-
- void visit(TypeIdentifier *t)
- {
- if (!tparams)
- {
- result = true;
- return;
- }
-
- for (size_t i = iStart; i < tparams->length; i++)
- {
- TemplateParameter *tp = (*tparams)[i];
- if (tp->ident->equals(t->ident))
- {
- result = true;
- return;
- }
- }
- }
-
- void visit(TypeInstance *t)
- {
- if (!tparams)
- return;
-
- for (size_t i = iStart; i < tparams->length; i++)
- {
- TemplateParameter *tp = (*tparams)[i];
- if (t->tempinst->name == tp->ident)
- {
- result = true;
- return;
- }
- }
- if (!t->tempinst->tiargs)
- return;
- for (size_t i = 0; i < t->tempinst->tiargs->length; i++)
- {
- Type *ta = isType((*t->tempinst->tiargs)[i]);
- if (ta)
- {
- ta->accept(this);
- if (result)
- return;
- }
- }
- }
-
- void visit(TypeTypeof *t)
- {
- //printf("TypeTypeof::reliesOnTident('%s')\n", t->toChars());
- t->exp->accept(this);
- }
-
- void visit(TypeTuple *t)
- {
- if (t->arguments)
- {
- for (size_t i = 0; i < t->arguments->length; i++)
- {
- Parameter *arg = (*t->arguments)[i];
- arg->type->accept(this);
- if (result)
- return;
- }
- }
- }
-
- void visit(Expression *)
- {
- //printf("Expression::reliesOnTident('%s')\n", e->toChars());
- }
-
- void visit(IdentifierExp *e)
- {
- //printf("IdentifierExp::reliesOnTident('%s')\n", e->toChars());
- for (size_t i = iStart; i < tparams->length; i++)
- {
- TemplateParameter *tp = (*tparams)[i];
- if (e->ident == tp->ident)
- {
- result = true;
- return;
- }
- }
- }
-
- void visit(TupleExp *e)
- {
- //printf("TupleExp::reliesOnTident('%s')\n", e->toChars());
- if (e->exps)
- {
- for (size_t i = 0; i < e->exps->length; i++)
- {
- Expression *ea = (*e->exps)[i];
- ea->accept(this);
- if (result)
- return;
- }
- }
- }
-
- void visit(ArrayLiteralExp *e)
- {
- //printf("ArrayLiteralExp::reliesOnTident('%s')\n", e->toChars());
- if (e->elements)
- {
- for (size_t i = 0; i < e->elements->length; i++)
- {
- Expression *el = (*e->elements)[i];
- el->accept(this);
- if (result)
- return;
- }
- }
- }
-
- void visit(AssocArrayLiteralExp *e)
- {
- //printf("AssocArrayLiteralExp::reliesOnTident('%s')\n", e->toChars());
- for (size_t i = 0; i < e->keys->length; i++)
- {
- Expression *ek = (*e->keys)[i];
- ek->accept(this);
- if (result)
- return;
- }
- for (size_t i = 0; i < e->values->length; i++)
- {
- Expression *ev = (*e->values)[i];
- ev->accept(this);
- if (result)
- return;
- }
- }
-
- void visit(StructLiteralExp *e)
- {
- //printf("StructLiteralExp::reliesOnTident('%s')\n", e->toChars());
- if (e->elements)
- {
- for (size_t i = 0; i < e->elements->length; i++)
- {
- Expression *ea = (*e->elements)[i];
- ea->accept(this);
- if (result)
- return;
- }
- }
- }
-
- void visit(TypeExp *e)
- {
- //printf("TypeExp::reliesOnTident('%s')\n", e->toChars());
- e->type->accept(this);
- }
-
- void visit(NewExp *e)
- {
- //printf("NewExp::reliesOnTident('%s')\n", e->toChars());
- if (e->thisexp)
- e->thisexp->accept(this);
- if (!result && e->newargs)
- {
- for (size_t i = 0; i < e->newargs->length; i++)
- {
- Expression *ea = (*e->newargs)[i];
- ea->accept(this);
- if (result)
- return;
- }
- }
- e->newtype->accept(this);
- if (!result && e->arguments)
- {
- for (size_t i = 0; i < e->arguments->length; i++)
- {
- Expression *ea = (*e->arguments)[i];
- ea->accept(this);
- if (result)
- return;
- }
- }
- }
-
- void visit(NewAnonClassExp *)
- {
- //printf("NewAnonClassExp::reliesOnTident('%s')\n", e->toChars());
- result = true;
- }
-
- void visit(FuncExp *)
- {
- //printf("FuncExp::reliesOnTident('%s')\n", e->toChars());
- result = true;
- }
-
- void visit(TypeidExp *e)
- {
- //printf("TypeidExp::reliesOnTident('%s')\n", e->toChars());
- if (Expression *ea = isExpression(e->obj))
- ea->accept(this);
- else if (Type *ta = isType(e->obj))
- ta->accept(this);
- }
-
- void visit(TraitsExp *e)
- {
- //printf("TraitsExp::reliesOnTident('%s')\n", e->toChars());
- if (e->args)
- {
- for (size_t i = 0; i < e->args->length; i++)
- {
- RootObject *oa = (*e->args)[i];
- if (Expression *ea = isExpression(oa))
- ea->accept(this);
- else if (Type *ta = isType(oa))
- ta->accept(this);
- if (result)
- return;
- }
- }
- }
-
- void visit(IsExp *e)
- {
- //printf("IsExp::reliesOnTident('%s')\n", e->toChars());
- e->targ->accept(this);
- }
-
- void visit(UnaExp *e)
- {
- //printf("UnaExp::reliesOnTident('%s')\n", e->toChars());
- e->e1->accept(this);
- }
-
- void visit(DotTemplateInstanceExp *e)
- {
- //printf("DotTemplateInstanceExp::reliesOnTident('%s')\n", e->toChars());
- visit((UnaExp *)e);
- if (!result && e->ti->tiargs)
- {
- for (size_t i = 0; i < e->ti->tiargs->length; i++)
- {
- RootObject *oa = (*e->ti->tiargs)[i];
- if (Expression *ea = isExpression(oa))
- ea->accept(this);
- else if (Type *ta = isType(oa))
- ta->accept(this);
- if (result)
- return;
- }
- }
- }
-
- void visit(CallExp *e)
- {
- //printf("CallExp::reliesOnTident('%s')\n", e->toChars());
- visit((UnaExp *)e);
- if (!result && e->arguments)
- {
- for (size_t i = 0; i < e->arguments->length; i++)
- {
- Expression *ea = (*e->arguments)[i];
- ea->accept(this);
- if (result)
- return;
- }
- }
- }
-
- void visit(CastExp *e)
- {
- //printf("CastExp::reliesOnTident('%s')\n", e->toChars());
- visit((UnaExp *)e);
- // e.to can be null for cast() with no type
- if (!result && e->to)
- e->to->accept(this);
- }
-
- void visit(SliceExp *e)
- {
- //printf("SliceExp::reliesOnTident('%s')\n", e->toChars());
- visit((UnaExp *)e);
- if (!result && e->lwr)
- e->lwr->accept(this);
- if (!result && e->upr)
- e->upr->accept(this);
- }
-
- void visit(IntervalExp *e)
- {
- //printf("IntervalExp::reliesOnTident('%s')\n", e->toChars());
- e->lwr->accept(this);
- if (!result)
- e->upr->accept(this);
- }
-
- void visit(ArrayExp *e)
- {
- //printf("ArrayExp::reliesOnTident('%s')\n", e->toChars());
- visit((UnaExp *)e);
- if (!result && e->arguments)
- {
- for (size_t i = 0; i < e->arguments->length; i++)
- {
- Expression *ea = (*e->arguments)[i];
- ea->accept(this);
- }
- }
- }
-
- void visit(BinExp *e)
- {
- //printf("BinExp::reliesOnTident('%s')\n", e->toChars());
- e->e1->accept(this);
- if (!result)
- e->e2->accept(this);
- }
-
- void visit(CondExp *e)
- {
- //printf("BinExp::reliesOnTident('%s')\n", e->toChars());
- e->econd->accept(this);
- if (!result)
- visit((BinExp *)e);
- }
- };
-
- if (!t)
- return false;
-
- ReliesOnTident v(tparams, iStart);
- t->accept(&v);
- return v.result;
-}
-
-/* ======================== TemplateParameter =============================== */
-
-TemplateParameter::TemplateParameter(Loc loc, Identifier *ident)
-{
- this->loc = loc;
- this->ident = ident;
- this->dependent = false;
-}
-
-TemplateTypeParameter *TemplateParameter::isTemplateTypeParameter()
-{
- return NULL;
-}
-
-TemplateValueParameter *TemplateParameter::isTemplateValueParameter()
-{
- return NULL;
-}
-
-TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter()
-{
- return NULL;
-}
-
-TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter()
-{
- return NULL;
-}
-
-TemplateThisParameter *TemplateParameter::isTemplateThisParameter()
-{
- return NULL;
-}
-
-/*******************************************
- * Match to a particular TemplateParameter.
- * Input:
- * instLoc location that the template is instantiated.
- * tiargs[] actual arguments to template instance
- * i i'th argument
- * parameters[] template parameters
- * dedtypes[] deduced arguments to template instance
- * *psparam set to symbol declared and initialized to dedtypes[i]
- */
-MATCH TemplateParameter::matchArg(Loc instLoc, Scope *sc, Objects *tiargs,
- size_t i, TemplateParameters *parameters, Objects *dedtypes,
- Declaration **psparam)
-{
- RootObject *oarg;
-
- if (i < tiargs->length)
- oarg = (*tiargs)[i];
- else
- {
- // Get default argument instead
- oarg = defaultArg(instLoc, sc);
- if (!oarg)
- {
- assert(i < dedtypes->length);
- // It might have already been deduced
- oarg = (*dedtypes)[i];
- if (!oarg)
- goto Lnomatch;
- }
- }
- return matchArg(sc, oarg, i, parameters, dedtypes, psparam);
-
-Lnomatch:
- if (psparam)
- *psparam = NULL;
- return MATCHnomatch;
-}
-
-/* ======================== TemplateTypeParameter =========================== */
-
-// type-parameter
-
-Type *TemplateTypeParameter::tdummy = NULL;
-
-TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType,
- Type *defaultType)
- : TemplateParameter(loc, ident)
-{
- this->ident = ident;
- this->specType = specType;
- this->defaultType = defaultType;
-}
-
-TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter()
-{
- return this;
-}
-
-TemplateParameter *TemplateTypeParameter::syntaxCopy()
-{
- return new TemplateTypeParameter(loc, ident,
- specType ? specType->syntaxCopy() : NULL,
- defaultType ? defaultType->syntaxCopy() : NULL);
-}
-
-bool TemplateTypeParameter::declareParameter(Scope *sc)
-{
- //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars());
- TypeIdentifier *ti = new TypeIdentifier(loc, ident);
- Declaration *ad = new AliasDeclaration(loc, ident, ti);
- return sc->insert(ad) != NULL;
-}
-
-MATCH TemplateTypeParameter::matchArg(Scope *sc, RootObject *oarg,
- size_t i, TemplateParameters *parameters, Objects *dedtypes,
- Declaration **psparam)
-{
- //printf("TemplateTypeParameter::matchArg('%s')\n", ident->toChars());
- MATCH m = MATCHexact;
- Type *ta = isType(oarg);
- if (!ta)
- {
- //printf("%s %p %p %p\n", oarg->toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg));
- goto Lnomatch;
- }
- //printf("ta is %s\n", ta->toChars());
-
- if (specType)
- {
- if (!ta || ta == tdummy)
- goto Lnomatch;
-
- //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars());
- MATCH m2 = deduceType(ta, sc, specType, parameters, dedtypes);
- if (m2 <= MATCHnomatch)
- {
- //printf("\tfailed deduceType\n");
- goto Lnomatch;
- }
-
- if (m2 < m)
- m = m2;
- if ((*dedtypes)[i])
- {
- Type *t = (Type *)(*dedtypes)[i];
-
- if (dependent && !t->equals(ta)) // Bugzilla 14357
- goto Lnomatch;
-
- /* This is a self-dependent parameter. For example:
- * template X(T : T*) {}
- * template X(T : S!T, alias S) {}
- */
- //printf("t = %s ta = %s\n", t->toChars(), ta->toChars());
- ta = t;
- }
- }
- else
- {
- if ((*dedtypes)[i])
- {
- // Must match already deduced type
- Type *t = (Type *)(*dedtypes)[i];
-
- if (!t->equals(ta))
- {
- //printf("t = %s ta = %s\n", t->toChars(), ta->toChars());
- goto Lnomatch;
- }
- }
- else
- {
- // So that matches with specializations are better
- m = MATCHconvert;
- }
- }
- (*dedtypes)[i] = ta;
-
- if (psparam)
- *psparam = new AliasDeclaration(loc, ident, ta);
- //printf("\tm = %d\n", m);
- return dependent ? MATCHexact : m;
-
-Lnomatch:
- if (psparam)
- *psparam = NULL;
- //printf("\tm = %d\n", MATCHnomatch);
- return MATCHnomatch;
-}
-
-
-void TemplateTypeParameter::print(RootObject *oarg, RootObject *oded)
-{
- printf(" %s\n", ident->toChars());
-
- Type *t = isType(oarg);
- Type *ta = isType(oded);
-
- assert(ta);
-
- if (specType)
- printf("\tSpecialization: %s\n", specType->toChars());
- if (defaultType)
- printf("\tDefault: %s\n", defaultType->toChars());
- printf("\tParameter: %s\n", t ? t->toChars() : "NULL");
- printf("\tDeduced Type: %s\n", ta->toChars());
-}
-
-void *TemplateTypeParameter::dummyArg()
-{
- Type *t = specType;
- if (!t)
- {
- // Use this for alias-parameter's too (?)
- if (!tdummy)
- tdummy = new TypeIdentifier(loc, ident);
- t = tdummy;
- }
- return (void *)t;
-}
-
-
-RootObject *TemplateTypeParameter::specialization()
-{
- return specType;
-}
-
-RootObject *TemplateTypeParameter::defaultArg(Loc, Scope *sc)
-{
- Type *t = defaultType;
- if (t)
- {
- t = t->syntaxCopy();
- t = typeSemantic(t, loc, sc); // use the parameter loc
- }
- return t;
-}
-
-bool TemplateTypeParameter::hasDefaultArg()
-{
- return defaultType != NULL;
-}
-
-/* ======================== TemplateThisParameter =========================== */
-
-// this-parameter
-
-TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident,
- Type *specType,
- Type *defaultType)
- : TemplateTypeParameter(loc, ident, specType, defaultType)
-{
-}
-
-TemplateThisParameter *TemplateThisParameter::isTemplateThisParameter()
-{
- return this;
-}
-
-TemplateParameter *TemplateThisParameter::syntaxCopy()
-{
- return new TemplateThisParameter(loc, ident,
- specType ? specType->syntaxCopy() : NULL,
- defaultType ? defaultType->syntaxCopy() : NULL);
-}
-
-/* ======================== TemplateAliasParameter ========================== */
-
-// alias-parameter
-
-Dsymbol *TemplateAliasParameter::sdummy = NULL;
-
-TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident,
- Type *specType, RootObject *specAlias, RootObject *defaultAlias)
- : TemplateParameter(loc, ident)
-{
- this->ident = ident;
- this->specType = specType;
- this->specAlias = specAlias;
- this->defaultAlias = defaultAlias;
-}
-
-TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter()
-{
- return this;
-}
-
-TemplateParameter *TemplateAliasParameter::syntaxCopy()
-{
- return new TemplateAliasParameter(loc, ident,
- specType ? specType->syntaxCopy() : NULL,
- objectSyntaxCopy(specAlias),
- objectSyntaxCopy(defaultAlias));
-}
-
-bool TemplateAliasParameter::declareParameter(Scope *sc)
-{
- TypeIdentifier *ti = new TypeIdentifier(loc, ident);
- Declaration *ad = new AliasDeclaration(loc, ident, ti);
- return sc->insert(ad) != NULL;
-}
-
-MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg,
- size_t i, TemplateParameters *parameters, Objects *dedtypes,
- Declaration **psparam)
-{
- //printf("TemplateAliasParameter::matchArg('%s')\n", ident->toChars());
- MATCH m = MATCHexact;
- Type *ta = isType(oarg);
- RootObject *sa = ta && !ta->deco ? NULL : getDsymbol(oarg);
- Expression *ea = isExpression(oarg);
- if (ea && (ea->op == TOKthis || ea->op == TOKsuper))
- sa = ((ThisExp *)ea)->var;
- else if (ea && ea->op == TOKscope)
- sa = ((ScopeExp *)ea)->sds;
- if (sa)
- {
- if (((Dsymbol *)sa)->isAggregateDeclaration())
- m = MATCHconvert;
-
- /* specType means the alias must be a declaration with a type
- * that matches specType.
- */
- if (specType)
- {
- Declaration *d = ((Dsymbol *)sa)->isDeclaration();
- if (!d)
- goto Lnomatch;
- if (!d->type->equals(specType))
- goto Lnomatch;
- }
- }
- else
- {
- sa = oarg;
- if (ea)
- {
- if (specType)
- {
- if (!ea->type->equals(specType))
- goto Lnomatch;
- }
- }
- else if (ta && ta->ty == Tinstance && !specAlias)
- {
- /* Bugzilla xxxxx: Specialized parameter should be prefeerd
- * match to the template type parameter.
- * template X(alias a) {} // a == this
- * template X(alias a : B!A, alias B, A...) {} // B!A => ta
- */
- }
- else if (sa && sa == TemplateTypeParameter::tdummy)
- {
- /* Bugzilla 2025: Aggregate Types should preferentially
- * match to the template type parameter.
- * template X(alias a) {} // a == this
- * template X(T) {} // T => sa
- */
- }
- else if (ta && ta->ty != Tident)
- {
- /* Match any type that's not a TypeIdentifier to alias parameters,
- * but prefer type parameter.
- * template X(alias a) { } // a == ta
- *
- * TypeIdentifiers are excluded because they might be not yet resolved aliases.
- */
- m = MATCHconvert;
- }
- else
- goto Lnomatch;
- }
-
- if (specAlias)
- {
- if (sa == sdummy)
- goto Lnomatch;
- Dsymbol *sx = isDsymbol(sa);
- if (sa != specAlias && sx)
- {
- Type *talias = isType(specAlias);
- if (!talias)
- goto Lnomatch;
-
- TemplateInstance *ti = sx->isTemplateInstance();
- if (!ti && sx->parent)
- {
- ti = sx->parent->isTemplateInstance();
- if (ti && ti->name != sx->ident)
- goto Lnomatch;
- }
- if (!ti)
- goto Lnomatch;
-
- Type *t = new TypeInstance(Loc(), ti);
- MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes);
- if (m2 <= MATCHnomatch)
- goto Lnomatch;
- }
- }
- else if ((*dedtypes)[i])
- {
- // Must match already deduced symbol
- RootObject *si = (*dedtypes)[i];
- if (!sa || si != sa)
- goto Lnomatch;
- }
- (*dedtypes)[i] = sa;
-
- if (psparam)
- {
- if (Dsymbol *s = isDsymbol(sa))
- {
- *psparam = new AliasDeclaration(loc, ident, s);
- }
- else if (Type *t = isType(sa))
- {
- *psparam = new AliasDeclaration(loc, ident, t);
- }
- else
- {
- assert(ea);
-
- // Declare manifest constant
- Initializer *init = new ExpInitializer(loc, ea);
- VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
- v->storage_class = STCmanifest;
- dsymbolSemantic(v, sc);
- *psparam = v;
- }
- }
- return dependent ? MATCHexact : m;
-
-Lnomatch:
- if (psparam)
- *psparam = NULL;
- //printf("\tm = %d\n", MATCHnomatch);
- return MATCHnomatch;
-}
-
-
-void TemplateAliasParameter::print(RootObject *, RootObject *oded)
-{
- printf(" %s\n", ident->toChars());
-
- Dsymbol *sa = isDsymbol(oded);
- assert(sa);
-
- printf("\tParameter alias: %s\n", sa->toChars());
-}
-
-void *TemplateAliasParameter::dummyArg()
-{
- RootObject *s = specAlias;
- if (!s)
- {
- if (!sdummy)
- sdummy = new Dsymbol();
- s = sdummy;
- }
- return (void*)s;
-}
-
-
-RootObject *TemplateAliasParameter::specialization()
-{
- return specAlias;
-}
-
-RootObject *TemplateAliasParameter::defaultArg(Loc, Scope *sc)
-{
- RootObject *da = defaultAlias;
- Type *ta = isType(defaultAlias);
- if (ta)
- {
- if (ta->ty == Tinstance)
- {
- // If the default arg is a template, instantiate for each type
- da = ta->syntaxCopy();
- }
- }
-
- RootObject *o = aliasParameterSemantic(loc, sc, da, NULL); // use the parameter loc
- return o;
-}
-
-bool TemplateAliasParameter::hasDefaultArg()
-{
- return defaultAlias != NULL;
-}
-
-/* ======================== TemplateValueParameter ========================== */
-
-// value-parameter
-
-AA *TemplateValueParameter::edummies = NULL;
-
-TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType,
- Expression *specValue, Expression *defaultValue)
- : TemplateParameter(loc, ident)
-{
- this->ident = ident;
- this->valType = valType;
- this->specValue = specValue;
- this->defaultValue = defaultValue;
-}
-
-TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter()
-{
- return this;
-}
-
-TemplateParameter *TemplateValueParameter::syntaxCopy()
-{
- return new TemplateValueParameter(loc, ident,
- valType->syntaxCopy(),
- specValue ? specValue->syntaxCopy() : NULL,
- defaultValue ? defaultValue->syntaxCopy() : NULL);
-}
-
-bool TemplateValueParameter::declareParameter(Scope *sc)
-{
- VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL);
- v->storage_class = STCtemplateparameter;
- return sc->insert(v) != NULL;
-}
-
-MATCH TemplateValueParameter::matchArg(Scope *sc, RootObject *oarg,
- size_t i, TemplateParameters *, Objects *dedtypes, Declaration **psparam)
-{
- //printf("TemplateValueParameter::matchArg('%s')\n", ident->toChars());
-
- MATCH m = MATCHexact;
-
- Expression *ei = isExpression(oarg);
- Type *vt;
-
- if (!ei && oarg)
- {
- Dsymbol *si = isDsymbol(oarg);
- FuncDeclaration *f = si ? si->isFuncDeclaration() : NULL;
- if (!f || !f->fbody || f->needThis())
- goto Lnomatch;
-
- ei = new VarExp(loc, f);
- ei = expressionSemantic(ei, sc);
-
- /* If a function is really property-like, and then
- * it's CTFEable, ei will be a literal expression.
- */
- unsigned int olderrors = global.startGagging();
- ei = resolveProperties(sc, ei);
- ei = ei->ctfeInterpret();
- if (global.endGagging(olderrors) || ei->op == TOKerror)
- goto Lnomatch;
-
- /* Bugzilla 14520: A property-like function can match to both
- * TemplateAlias and ValueParameter. But for template overloads,
- * it should always prefer alias parameter to be consistent
- * template match result.
- *
- * template X(alias f) { enum X = 1; }
- * template X(int val) { enum X = 2; }
- * int f1() { return 0; } // CTFEable
- * int f2(); // body-less function is not CTFEable
- * enum x1 = X!f1; // should be 1
- * enum x2 = X!f2; // should be 1
- *
- * e.g. The x1 value must be same even if the f1 definition will be moved
- * into di while stripping body code.
- */
- m = MATCHconvert;
- }
-
- if (ei && ei->op == TOKvar)
- {
- // Resolve const variables that we had skipped earlier
- ei = ei->ctfeInterpret();
- }
-
- //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty);
- vt = typeSemantic(valType, loc, sc);
- //printf("ei: %s, ei->type: %s\n", ei->toChars(), ei->type->toChars());
- //printf("vt = %s\n", vt->toChars());
-
- if (ei->type)
- {
- MATCH m2 = ei->implicitConvTo(vt);
- //printf("m: %d\n", m);
- if (m2 < m)
- m = m2;
- if (m <= MATCHnomatch)
- goto Lnomatch;
- ei = ei->implicitCastTo(sc, vt);
- ei = ei->ctfeInterpret();
- }
-
- if (specValue)
- {
- if (!ei || (Expression *)dmd_aaGetRvalue(edummies, (void *)ei->type) == ei)
- goto Lnomatch;
-
- Expression *e = specValue;
-
- sc = sc->startCTFE();
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
- sc = sc->endCTFE();
- e = e->implicitCastTo(sc, vt);
- e = e->ctfeInterpret();
-
- ei = ei->syntaxCopy();
- sc = sc->startCTFE();
- ei = expressionSemantic(ei, sc);
- sc = sc->endCTFE();
- ei = ei->implicitCastTo(sc, vt);
- ei = ei->ctfeInterpret();
- //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars());
- //printf("\te : %s, %s\n", e->toChars(), e->type->toChars());
- if (!ei->equals(e))
- goto Lnomatch;
- }
- else
- {
- if ((*dedtypes)[i])
- {
- // Must match already deduced value
- Expression *e = (Expression *)(*dedtypes)[i];
-
- if (!ei || !ei->equals(e))
- goto Lnomatch;
- }
- }
- (*dedtypes)[i] = ei;
-
- if (psparam)
- {
- Initializer *init = new ExpInitializer(loc, ei);
- Declaration *sparam = new VarDeclaration(loc, vt, ident, init);
- sparam->storage_class = STCmanifest;
- *psparam = sparam;
- }
- return dependent ? MATCHexact : m;
-
-Lnomatch:
- //printf("\tno match\n");
- if (psparam)
- *psparam = NULL;
- return MATCHnomatch;
-}
-
-
-void TemplateValueParameter::print(RootObject *, RootObject *oded)
-{
- printf(" %s\n", ident->toChars());
-
- Expression *ea = isExpression(oded);
-
- if (specValue)
- printf("\tSpecialization: %s\n", specValue->toChars());
- printf("\tParameter Value: %s\n", ea ? ea->toChars() : "NULL");
-}
-
-void *TemplateValueParameter::dummyArg()
-{
- Expression *e = specValue;
- if (!e)
- {
- // Create a dummy value
- Expression **pe = (Expression **)dmd_aaGet(&edummies, (void *)valType);
- if (!*pe)
- *pe = valType->defaultInit();
- e = *pe;
- }
- return (void *)e;
-}
-
-
-RootObject *TemplateValueParameter::specialization()
-{
- return specValue;
-}
-
-RootObject *TemplateValueParameter::defaultArg(Loc instLoc, Scope *sc)
-{
- Expression *e = defaultValue;
- if (e)
- {
- e = e->syntaxCopy();
- unsigned olderrs = global.errors;
- if ((e = expressionSemantic(e, sc)) == NULL)
- return NULL;
- if ((e = resolveProperties(sc, e)) == NULL)
- return NULL;
- e = e->resolveLoc(instLoc, sc); // use the instantiated loc
- e = e->optimize(WANTvalue);
- if (global.errors != olderrs)
- e = new ErrorExp();
- }
- return e;
-}
-
-bool TemplateValueParameter::hasDefaultArg()
-{
- return defaultValue != NULL;
-}
-
-/* ======================== TemplateTupleParameter ========================== */
-
-// variadic-parameter
-
-TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident)
- : TemplateParameter(loc, ident)
-{
- this->ident = ident;
-}
-
-TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter()
-{
- return this;
-}
-
-TemplateParameter *TemplateTupleParameter::syntaxCopy()
-{
- return new TemplateTupleParameter(loc, ident);
-}
-
-bool TemplateTupleParameter::declareParameter(Scope *sc)
-{
- TypeIdentifier *ti = new TypeIdentifier(loc, ident);
- Declaration *ad = new AliasDeclaration(loc, ident, ti);
- return sc->insert(ad) != NULL;
-}
-
-MATCH TemplateTupleParameter::matchArg(Loc, Scope *sc, Objects *tiargs,
- size_t i, TemplateParameters *parameters, Objects *dedtypes,
- Declaration **psparam)
-{
- /* The rest of the actual arguments (tiargs[]) form the match
- * for the variadic parameter.
- */
- assert(i + 1 == dedtypes->length); // must be the last one
- Tuple *ovar;
-
- if (Tuple *u = isTuple((*dedtypes)[i]))
- {
- // It has already been deduced
- ovar = u;
- }
- else if (i + 1 == tiargs->length && isTuple((*tiargs)[i]))
- ovar = isTuple((*tiargs)[i]);
- else
- {
- ovar = new Tuple();
- //printf("ovar = %p\n", ovar);
- if (i < tiargs->length)
- {
- //printf("i = %d, tiargs->length = %d\n", i, tiargs->length);
- ovar->objects.setDim(tiargs->length - i);
- for (size_t j = 0; j < ovar->objects.length; j++)
- ovar->objects[j] = (*tiargs)[i + j];
- }
- }
- return matchArg(sc, ovar, i, parameters, dedtypes, psparam);
-}
-
-MATCH TemplateTupleParameter::matchArg(Scope *, RootObject *oarg,
- size_t i, TemplateParameters *, Objects *dedtypes, Declaration **psparam)
-{
- //printf("TemplateTupleParameter::matchArg('%s')\n", ident->toChars());
- Tuple *ovar = isTuple(oarg);
- if (!ovar)
- return MATCHnomatch;
- if ((*dedtypes)[i])
- {
- Tuple *tup = isTuple((*dedtypes)[i]);
- if (!tup)
- return MATCHnomatch;
- if (!match(tup, ovar))
- return MATCHnomatch;
- }
- (*dedtypes)[i] = ovar;
-
- if (psparam)
- *psparam = new TupleDeclaration(loc, ident, &ovar->objects);
- return dependent ? MATCHexact : MATCHconvert;
-}
-
-
-void TemplateTupleParameter::print(RootObject *, RootObject *oded)
-{
- printf(" %s... [", ident->toChars());
- Tuple *v = isTuple(oded);
- assert(v);
-
- //printf("|%d| ", v->objects.length);
- for (size_t i = 0; i < v->objects.length; i++)
- {
- if (i)
- printf(", ");
-
- RootObject *o = v->objects[i];
-
- Dsymbol *sa = isDsymbol(o);
- if (sa)
- printf("alias: %s", sa->toChars());
-
- Type *ta = isType(o);
- if (ta)
- printf("type: %s", ta->toChars());
-
- Expression *ea = isExpression(o);
- if (ea)
- printf("exp: %s", ea->toChars());
-
- assert(!isTuple(o)); // no nested Tuple arguments
- }
-
- printf("]\n");
-}
-
-void *TemplateTupleParameter::dummyArg()
-{
- return NULL;
-}
-
-
-RootObject *TemplateTupleParameter::specialization()
-{
- return NULL;
-}
-
-RootObject *TemplateTupleParameter::defaultArg(Loc, Scope *)
-{
- return NULL;
-}
-
-bool TemplateTupleParameter::hasDefaultArg()
-{
- return false;
-}
-
-/* ======================== TemplateInstance ================================ */
-
-TemplateInstance::TemplateInstance(Loc loc, Identifier *ident)
- : ScopeDsymbol(NULL)
-{
- this->loc = loc;
- this->name = ident;
- this->tiargs = NULL;
- this->tempdecl = NULL;
- this->inst = NULL;
- this->tinst = NULL;
- this->tnext = NULL;
- this->minst = NULL;
- this->deferred = NULL;
- this->memberOf = NULL;
- this->argsym = NULL;
- this->aliasdecl = NULL;
- this->semantictiargsdone = false;
- this->inuse = 0;
- this->nest = 0;
- this->havetempdecl = false;
- this->enclosing = NULL;
- this->gagged = false;
- this->hash = 0;
- this->fargs = NULL;
-}
-
-/*****************
- * This constructor is only called when we figured out which function
- * template to instantiate.
- */
-
-TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs)
- : ScopeDsymbol(NULL)
-{
- this->loc = loc;
- this->name = td->ident;
- this->tiargs = tiargs;
- this->tempdecl = td;
- this->inst = NULL;
- this->tinst = NULL;
- this->tnext = NULL;
- this->minst = NULL;
- this->deferred = NULL;
- this->memberOf = NULL;
- this->argsym = NULL;
- this->aliasdecl = NULL;
- this->semantictiargsdone = true;
- this->inuse = 0;
- this->nest = 0;
- this->havetempdecl = true;
- this->enclosing = NULL;
- this->gagged = false;
- this->hash = 0;
- this->fargs = NULL;
-
- assert(tempdecl->_scope);
-}
-
-
-Objects *TemplateInstance::arraySyntaxCopy(Objects *objs)
-{
- Objects *a = NULL;
- if (objs)
- {
- a = new Objects();
- a->setDim(objs->length);
- for (size_t i = 0; i < objs->length; i++)
- (*a)[i] = objectSyntaxCopy((*objs)[i]);
- }
- return a;
-}
-
-Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s)
-{
- TemplateInstance *ti =
- s ? (TemplateInstance *)s
- : new TemplateInstance(loc, name);
- ti->tiargs = arraySyntaxCopy(tiargs);
- TemplateDeclaration *td;
- if (inst && tempdecl && (td = tempdecl->isTemplateDeclaration()) != NULL)
- td->ScopeDsymbol::syntaxCopy(ti);
- else
- ScopeDsymbol::syntaxCopy(ti);
- return ti;
-}
-
-void TemplateInstance::expandMembers(Scope *sc2)
-{
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->setScope(sc2);
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->importAll(sc2);
- }
-
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars());
- //printf("test: enclosing = %d, sc2->parent = %s\n", enclosing, sc2->parent->toChars());
-// if (enclosing)
-// s->parent = sc->parent;
- //printf("test3: enclosing = %d, s->parent = %s\n", enclosing, s->parent->toChars());
- dsymbolSemantic(s, sc2);
- //printf("test4: enclosing = %d, s->parent = %s\n", enclosing, s->parent->toChars());
- Module::runDeferredSemantic();
- }
-}
-
-void TemplateInstance::tryExpandMembers(Scope *sc2)
-{
- static int nest;
- // extracted to a function to allow windows SEH to work without destructors in the same function
- //printf("%d\n", nest);
- if (++nest > global.recursionLimit)
- {
- global.gag = 0; // ensure error message gets printed
- error("recursive expansion exceeded allowed nesting limit");
- fatal();
- }
-
- expandMembers(sc2);
-
- nest--;
-}
-
-void TemplateInstance::trySemantic3(Scope *sc2)
-{
- // extracted to a function to allow windows SEH to work without destructors in the same function
- static int nest;
- //printf("%d\n", nest);
- if (++nest > global.recursionLimit)
- {
- global.gag = 0; // ensure error message gets printed
- error("recursive expansion exceeded allowed nesting limit");
- fatal();
- }
- semantic3(this, sc2);
-
- --nest;
-}
-
-/**********************************************
- * Find template declaration corresponding to template instance.
- *
- * Returns:
- * false if finding fails.
- * Note:
- * This function is reentrant against error occurrence. If returns false,
- * any members of this object won't be modified, and repetition call will
- * reproduce same error.
- */
-
-bool TemplateInstance::findTempDecl(Scope *sc, WithScopeSymbol **pwithsym)
-{
- if (pwithsym)
- *pwithsym = NULL;
-
- if (havetempdecl)
- return true;
-
- //printf("TemplateInstance::findTempDecl() %s\n", toChars());
- if (!tempdecl)
- {
- /* Given:
- * foo!( ... )
- * figure out which TemplateDeclaration foo refers to.
- */
- Identifier *id = name;
- Dsymbol *scopesym;
- Dsymbol *s = sc->search(loc, id, &scopesym);
- if (!s)
- {
- s = sc->search_correct(id);
- if (s)
- error("template `%s` is not defined, did you mean %s?", id->toChars(), s->toChars());
- else
- error("template `%s` is not defined", id->toChars());
- return false;
- }
-
- if (pwithsym)
- *pwithsym = scopesym->isWithScopeSymbol();
-
- /* We might have found an alias within a template when
- * we really want the template.
- */
- TemplateInstance *ti;
- if (s->parent &&
- (ti = s->parent->isTemplateInstance()) != NULL)
- {
- if (ti->tempdecl && ti->tempdecl->ident == id)
- {
- /* This is so that one can refer to the enclosing
- * template, even if it has the same name as a member
- * of the template, if it has a !(arguments)
- */
- TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration();
- assert(td);
- if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
- td = td->overroot; // then get the start
- s = td;
- }
- }
-
- if (!updateTempDecl(sc, s))
- {
- return false;
- }
- }
- assert(tempdecl);
-
- struct ParamFwdTi
- {
- static int fp(void *param, Dsymbol *s)
- {
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (!td)
- return 0;
-
- TemplateInstance *ti = (TemplateInstance *)param;
- if (td->semanticRun == PASSinit)
- {
- if (td->_scope)
- {
- // Try to fix forward reference. Ungag errors while doing so.
- Ungag ungag = td->ungagSpeculative();
- dsymbolSemantic(td, td->_scope);
- }
- if (td->semanticRun == PASSinit)
- {
- ti->error("%s forward references template declaration %s", ti->toChars(), td->toChars());
- return 1;
- }
- }
- return 0;
- }
- };
- // Look for forward references
- OverloadSet *tovers = tempdecl->isOverloadSet();
- size_t overs_dim = tovers ? tovers->a.length : 1;
- for (size_t oi = 0; oi < overs_dim; oi++)
- {
- if (overloadApply(tovers ? tovers->a[oi] : tempdecl, (void *)this, &ParamFwdTi::fp))
- return false;
- }
- return true;
-}
-
-/**********************************************
- * Confirm s is a valid template, then store it.
- * Input:
- * sc
- * s candidate symbol of template. It may be:
- * TemplateDeclaration
- * FuncDeclaration with findTemplateDeclRoot() != NULL
- * OverloadSet which contains candidates
- * Returns:
- * true if updating succeeds.
- */
-
-bool TemplateInstance::updateTempDecl(Scope *sc, Dsymbol *s)
-{
- if (s)
- {
- Identifier *id = name;
- s = s->toAlias();
-
- /* If an OverloadSet, look for a unique member that is a template declaration
- */
- OverloadSet *os = s->isOverloadSet();
- if (os)
- {
- s = NULL;
- for (size_t i = 0; i < os->a.length; i++)
- {
- Dsymbol *s2 = os->a[i];
- if (FuncDeclaration *f = s2->isFuncDeclaration())
- s2 = f->findTemplateDeclRoot();
- else
- s2 = s2->isTemplateDeclaration();
- if (s2)
- {
- if (s)
- {
- tempdecl = os;
- return true;
- }
- s = s2;
- }
- }
- if (!s)
- {
- error("template `%s` is not defined", id->toChars());
- return false;
- }
- }
-
- OverDeclaration *od = s->isOverDeclaration();
- if (od)
- {
- tempdecl = od; // TODO: more strict check
- return true;
- }
-
- /* It should be a TemplateDeclaration, not some other symbol
- */
- if (FuncDeclaration *f = s->isFuncDeclaration())
- tempdecl = f->findTemplateDeclRoot();
- else
- tempdecl = s->isTemplateDeclaration();
- if (!tempdecl)
- {
- if (!s->parent && global.errors)
- return false;
- if (!s->parent && s->getType())
- {
- Dsymbol *s2 = s->getType()->toDsymbol(sc);
- if (!s2)
- {
- error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
- return false;
- }
- s = s2;
- }
- //assert(s->parent);
- TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL;
- if (ti &&
- (ti->name == s->ident ||
- ti->toAlias()->ident == s->ident)
- &&
- ti->tempdecl)
- {
- /* This is so that one can refer to the enclosing
- * template, even if it has the same name as a member
- * of the template, if it has a !(arguments)
- */
- TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration();
- assert(td);
- if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
- td = td->overroot; // then get the start
- tempdecl = td;
- }
- else
- {
- error("%s is not a template declaration, it is a %s", id->toChars(), s->kind());
- return false;
- }
- }
- }
- return (tempdecl != NULL);
-}
-
-/**********************************
- * Run semantic on the elements of tiargs.
- * Input:
- * sc
- * Returns:
- * false if one or more arguments have errors.
- * Note:
- * This function is reentrant against error occurrence. If returns false,
- * all elements of tiargs won't be modified.
- */
-
-bool TemplateInstance::semanticTiargs(Scope *sc)
-{
- //printf("+TemplateInstance::semanticTiargs() %s\n", toChars());
- if (semantictiargsdone)
- return true;
- if (semanticTiargs(loc, sc, tiargs, 0))
- {
- // cache the result iff semantic analysis succeeded entirely
- semantictiargsdone = 1;
- return true;
- }
- return false;
-}
-
-/**********************************
- * Run semantic of tiargs as arguments of template.
- * Input:
- * loc
- * sc
- * tiargs array of template arguments
- * flags 1: replace const variables with their initializers
- * 2: don't devolve Parameter to Type
- * Returns:
- * false if one or more arguments have errors.
- */
-
-bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags)
-{
- // Run semantic on each argument, place results in tiargs[]
- //printf("+TemplateInstance::semanticTiargs()\n");
- if (!tiargs)
- return true;
- bool err = false;
- for (size_t j = 0; j < tiargs->length; j++)
- {
- RootObject *o = (*tiargs)[j];
- Type *ta = isType(o);
- Expression *ea = isExpression(o);
- Dsymbol *sa = isDsymbol(o);
-
- //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
- if (ta)
- {
- //printf("type %s\n", ta->toChars());
-
- // It might really be an Expression or an Alias
- ta->resolve(loc, sc, &ea, &ta, &sa, (flags & 1) != 0);
- if (ea) goto Lexpr;
- if (sa) goto Ldsym;
- if (ta == NULL)
- {
- assert(global.errors);
- ta = Type::terror;
- }
-
- Ltype:
- if (ta->ty == Ttuple)
- {
- // Expand tuple
- TypeTuple *tt = (TypeTuple *)ta;
- size_t dim = tt->arguments->length;
- tiargs->remove(j);
- if (dim)
- {
- tiargs->reserve(dim);
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *arg = (*tt->arguments)[i];
- if (flags & 2 && (arg->ident || arg->userAttribDecl))
- tiargs->insert(j + i, arg);
- else
- tiargs->insert(j + i, arg->type);
- }
- }
- j--;
- continue;
- }
- if (ta->ty == Terror)
- {
- err = true;
- continue;
- }
- (*tiargs)[j] = ta->merge2();
- }
- else if (ea)
- {
- Lexpr:
- //printf("+[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars());
- if (flags & 1) // only used by __traits
- {
- ea = expressionSemantic(ea, sc);
-
- // must not interpret the args, excepting template parameters
- if (ea->op != TOKvar ||
- (((VarExp *)ea)->var->storage_class & STCtemplateparameter))
- {
- ea = ea->optimize(WANTvalue);
- }
- }
- else
- {
- sc = sc->startCTFE();
- ea = expressionSemantic(ea, sc);
- sc = sc->endCTFE();
-
- if (ea->op == TOKvar)
- {
- /* This test is to skip substituting a const var with
- * its initializer. The problem is the initializer won't
- * match with an 'alias' parameter. Instead, do the
- * const substitution in TemplateValueParameter::matchArg().
- */
- }
- else if (definitelyValueParameter(ea))
- {
- if (ea->checkValue()) // check void expression
- ea = new ErrorExp();
- unsigned int olderrs = global.errors;
- ea = ea->ctfeInterpret();
- if (global.errors != olderrs)
- ea = new ErrorExp();
- }
- }
- //printf("-[%d] ea = %s %s\n", j, Token::toChars(ea->op), ea->toChars());
- if (ea->op == TOKtuple)
- {
- // Expand tuple
- TupleExp *te = (TupleExp *)ea;
- size_t dim = te->exps->length;
- tiargs->remove(j);
- if (dim)
- {
- tiargs->reserve(dim);
- for (size_t i = 0; i < dim; i++)
- tiargs->insert(j + i, (*te->exps)[i]);
- }
- j--;
- continue;
- }
- if (ea->op == TOKerror)
- {
- err = true;
- continue;
- }
- (*tiargs)[j] = ea;
-
- if (ea->op == TOKtype)
- {
- ta = ea->type;
- goto Ltype;
- }
- if (ea->op == TOKscope)
- {
- sa = ((ScopeExp *)ea)->sds;
- goto Ldsym;
- }
- if (ea->op == TOKfunction)
- {
- FuncExp *fe = (FuncExp *)ea;
- /* A function literal, that is passed to template and
- * already semanticed as function pointer, never requires
- * outer frame. So convert it to global function is valid.
- */
- if (fe->fd->tok == TOKreserved && fe->type->ty == Tpointer)
- {
- // change to non-nested
- fe->fd->tok = TOKfunction;
- fe->fd->vthis = NULL;
- }
- else if (fe->td)
- {
- /* If template argument is a template lambda,
- * get template declaration itself. */
- //sa = fe->td;
- //goto Ldsym;
- }
- }
- if (ea->op == TOKdotvar && !(flags & 1))
- {
- // translate expression to dsymbol.
- sa = ((DotVarExp *)ea)->var;
- goto Ldsym;
- }
- if (ea->op == TOKtemplate)
- {
- sa = ((TemplateExp *)ea)->td;
- goto Ldsym;
- }
- if (ea->op == TOKdottd && !(flags & 1))
- {
- // translate expression to dsymbol.
- sa = ((DotTemplateExp *)ea)->td;
- goto Ldsym;
- }
- if (ea->op == TOKdot)
- {
- if (ScopeExp *se = ((DotExp *)ea)->e2->isScopeExp())
- {
- sa = se->sds;
- goto Ldsym;
- }
- }
- }
- else if (sa)
- {
- Ldsym:
- //printf("dsym %s %s\n", sa->kind(), sa->toChars());
- if (sa->errors)
- {
- err = true;
- continue;
- }
-
- TupleDeclaration *d = sa->toAlias()->isTupleDeclaration();
- if (d)
- {
- // Expand tuple
- tiargs->remove(j);
- tiargs->insert(j, d->objects);
- j--;
- continue;
- }
- if (FuncAliasDeclaration *fa = sa->isFuncAliasDeclaration())
- {
- FuncDeclaration *f = fa->toAliasFunc();
- if (!fa->hasOverloads && f->isUnique())
- {
- // Strip FuncAlias only when the aliased function
- // does not have any overloads.
- sa = f;
- }
- }
- (*tiargs)[j] = sa;
-
- TemplateDeclaration *td = sa->isTemplateDeclaration();
- if (td && td->semanticRun == PASSinit && td->literal)
- {
- dsymbolSemantic(td, sc);
- }
- FuncDeclaration *fd = sa->isFuncDeclaration();
- if (fd)
- fd->functionSemantic();
- }
- else if (isParameter(o))
- {
- }
- else
- {
- assert(0);
- }
- //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
- }
- return !err;
-}
-
-bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
-{
- if (havetempdecl)
- {
- TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
- assert(tempdecl);
- assert(tempdecl->_scope);
- // Deduce tdtypes
- tdtypes.setDim(tempdecl->parameters->length);
- if (!tempdecl->matchWithInstance(sc, this, &tdtypes, fargs, 2))
- {
- error("incompatible arguments for template instantiation");
- return false;
- }
- // TODO: Normalizing tiargs for bugzilla 7469 is necessary?
- return true;
- }
-
- unsigned errs = global.errors;
- TemplateDeclaration *td_last = NULL;
-
- struct ParamBest
- {
- // context
- Scope *sc;
- TemplateInstance *ti;
- Objects dedtypes;
- // result
- TemplateDeclaration *td_best;
- TemplateDeclaration *td_ambig;
- MATCH m_best;
-
- static int fp(void *param, Dsymbol *s)
- {
- return ((ParamBest *)param)->fp(s);
- }
- int fp(Dsymbol *s)
- {
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (!td)
- return 0;
- if (td->inuse)
- {
- td->error(ti->loc, "recursive template expansion");
- return 1;
- }
- if (td == td_best) // skip duplicates
- return 0;
-
- //printf("td = %s\n", td->toPrettyChars());
-
- // If more arguments than parameters,
- // then this is no match.
- if (td->parameters->length < ti->tiargs->length)
- {
- if (!td->isVariadic())
- return 0;
- }
-
- dedtypes.setDim(td->parameters->length);
- dedtypes.zero();
- assert(td->semanticRun != PASSinit);
- MATCH m = td->matchWithInstance(sc, ti, &dedtypes, ti->fargs, 0);
- //printf("matchWithInstance = %d\n", m);
- if (m <= MATCHnomatch) // no match at all
- return 0;
-
- if (m < m_best) goto Ltd_best;
- if (m > m_best) goto Ltd;
-
- {
- // Disambiguate by picking the most specialized TemplateDeclaration
- MATCH c1 = td->leastAsSpecialized(sc, td_best, ti->fargs);
- MATCH c2 = td_best->leastAsSpecialized(sc, td, ti->fargs);
- //printf("c1 = %d, c2 = %d\n", c1, c2);
- if (c1 > c2) goto Ltd;
- if (c1 < c2) goto Ltd_best;
- }
-
- td_ambig = td;
- return 0;
-
- Ltd_best: // td_best is the best match so far
- td_ambig = NULL;
- return 0;
-
- Ltd: // td is the new best match
- td_ambig = NULL;
- td_best = td;
- m_best = m;
- ti->tdtypes.setDim(dedtypes.length);
- memcpy(ti->tdtypes.tdata(), dedtypes.tdata(), ti->tdtypes.length * sizeof(void *));
- return 0;
- }
- };
- ParamBest p;
- // context
- p.ti = this;
- p.sc = sc;
-
- /* Since there can be multiple TemplateDeclaration's with the same
- * name, look for the best match.
- */
- OverloadSet *tovers = tempdecl->isOverloadSet();
- size_t overs_dim = tovers ? tovers->a.length : 1;
- for (size_t oi = 0; oi < overs_dim; oi++)
- {
- // result
- p.td_best = NULL;
- p.td_ambig = NULL;
- p.m_best = MATCHnomatch;
-
- Dsymbol *dstart = tovers ? tovers->a[oi] : tempdecl;
- overloadApply(dstart, &p, &ParamBest::fp);
-
- if (p.td_ambig)
- {
- ::error(loc, "%s %s.%s matches more than one template declaration:\n%s: %s\nand\n%s: %s",
- p.td_best->kind(), p.td_best->parent->toPrettyChars(), p.td_best->ident->toChars(),
- p.td_best->loc.toChars() , p.td_best->toChars(),
- p.td_ambig->loc.toChars(), p.td_ambig->toChars());
- return false;
- }
- if (p.td_best)
- {
- if (!td_last)
- td_last = p.td_best;
- else if (td_last != p.td_best)
- {
- ScopeDsymbol::multiplyDefined(loc, td_last, p.td_best);
- return false;
- }
- }
- }
-
- if (td_last)
- {
- /* Bugzilla 7469: Normalize tiargs by using corresponding deduced
- * template value parameters and tuples for the correct mangling.
- *
- * By doing this before hasNestedArgs, CTFEable local variable will be
- * accepted as a value parameter. For example:
- *
- * void foo() {
- * struct S(int n) {} // non-global template
- * const int num = 1; // CTFEable local variable
- * S!num s; // S!1 is instantiated, not S!num
- * }
- */
- size_t dim = td_last->parameters->length - (td_last->isVariadic() ? 1 : 0);
- for (size_t i = 0; i < dim; i++)
- {
- if (tiargs->length <= i)
- tiargs->push(tdtypes[i]);
- assert(i < tiargs->length);
-
- TemplateValueParameter *tvp = (*td_last->parameters)[i]->isTemplateValueParameter();
- if (!tvp)
- continue;
- assert(tdtypes[i]);
- // tdtypes[i] is already normalized to the required type in matchArg
-
- (*tiargs)[i] = tdtypes[i];
- }
- if (td_last->isVariadic() && tiargs->length == dim && tdtypes[dim])
- {
- Tuple *va = isTuple(tdtypes[dim]);
- assert(va);
- for (size_t i = 0; i < va->objects.length; i++)
- tiargs->push(va->objects[i]);
- }
- }
- else if (errors && inst)
- {
- // instantiation was failed with error reporting
- assert(global.errors);
- return false;
- }
- else
- {
- TemplateDeclaration *tdecl = tempdecl->isTemplateDeclaration();
-
- if (errs != global.errors)
- errorSupplemental(loc, "while looking for match for %s", toChars());
- else if (tdecl && !tdecl->overnext)
- {
- // Only one template, so we can give better error message
- error("does not match template declaration %s", tdecl->toChars());
- }
- else
- ::error(loc, "%s %s.%s does not match any template declaration",
- tempdecl->kind(), tempdecl->parent->toPrettyChars(), tempdecl->ident->toChars());
- return false;
- }
-
- /* The best match is td_last
- */
- tempdecl = td_last;
-
- return (errs == global.errors);
-}
-
-/*****************************************************
- * Determine if template instance is really a template function,
- * and that template function needs to infer types from the function
- * arguments.
- *
- * Like findBestMatch, iterate possible template candidates,
- * but just looks only the necessity of type inference.
- */
-
-bool TemplateInstance::needsTypeInference(Scope *sc, int flag)
-{
- //printf("TemplateInstance::needsTypeInference() %s\n", toChars());
- if (semanticRun != PASSinit)
- return false;
-
- struct ParamNeedsInf
- {
- // context
- Scope *sc;
- TemplateInstance *ti;
- int flag;
- // result
- Objects dedtypes;
- size_t count;
-
- static int fp(void *param, Dsymbol *s)
- {
- return ((ParamNeedsInf *)param)->fp(s);
- }
- int fp(Dsymbol *s)
- {
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (!td)
- return 0;
- if (td->inuse)
- {
- td->error(ti->loc, "recursive template expansion");
- return 1;
- }
-
- /* If any of the overloaded template declarations need inference,
- * then return true
- */
- FuncDeclaration *fd;
- if (!td->onemember)
- return 0;
- if (TemplateDeclaration *td2 = td->onemember->isTemplateDeclaration())
- {
- if (!td2->onemember || !td2->onemember->isFuncDeclaration())
- return 0;
- if (ti->tiargs->length >= td->parameters->length - (td->isVariadic() ? 1 : 0))
- return 0;
- return 1;
- }
- if ((fd = td->onemember->isFuncDeclaration()) == NULL ||
- fd->type->ty != Tfunction)
- {
- return 0;
- }
-
- for (size_t i = 0; i < td->parameters->length; i++)
- {
- if ((*td->parameters)[i]->isTemplateThisParameter())
- return 1;
- }
-
- /* Determine if the instance arguments, tiargs, are all that is necessary
- * to instantiate the template.
- */
- //printf("tp = %p, td->parameters->length = %d, tiargs->length = %d\n", tp, td->parameters->length, ti->tiargs->length);
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (size_t dim = tf->parameterList.length())
- {
- TemplateParameter *tp = td->isVariadic();
- if (tp && td->parameters->length > 1)
- return 1;
-
- if (!tp && ti->tiargs->length < td->parameters->length)
- {
- // Can remain tiargs be filled by default arguments?
- for (size_t i = ti->tiargs->length; i < td->parameters->length; i++)
- {
- if (!(*td->parameters)[i]->hasDefaultArg())
- return 1;
- }
- }
-
- for (size_t i = 0; i < dim; i++)
- {
- // 'auto ref' needs inference.
- if (tf->parameterList[i]->storageClass & STCauto)
- return 1;
- }
- }
-
- if (!flag)
- {
- /* Calculate the need for overload resolution.
- * When only one template can match with tiargs, inference is not necessary.
- */
- dedtypes.setDim(td->parameters->length);
- dedtypes.zero();
- if (td->semanticRun == PASSinit)
- {
- if (td->_scope)
- {
- // Try to fix forward reference. Ungag errors while doing so.
- Ungag ungag = td->ungagSpeculative();
- dsymbolSemantic(td, td->_scope);
- }
- if (td->semanticRun == PASSinit)
- {
- ti->error("%s forward references template declaration %s", ti->toChars(), td->toChars());
- return 1;
- }
- }
- assert(td->semanticRun != PASSinit);
- MATCH m = td->matchWithInstance(sc, ti, &dedtypes, NULL, 0);
- if (m <= MATCHnomatch)
- return 0;
- }
-
- /* If there is more than one function template which matches, we may
- * need type inference (see Bugzilla 4430)
- */
- if (++count > 1)
- return 1;
-
- return 0;
- }
- };
- ParamNeedsInf p;
- // context
- p.ti = this;
- p.sc = sc;
- p.flag = flag;
- // result
- p.count = 0;
-
- OverloadSet *tovers = tempdecl->isOverloadSet();
- size_t overs_dim = tovers ? tovers->a.length : 1;
- unsigned olderrs = global.errors;
- for (size_t oi = 0; oi < overs_dim; oi++)
- {
- if (overloadApply(tovers ? tovers->a[oi] : tempdecl, &p, &ParamNeedsInf::fp))
- return true;
- }
- if (olderrs != global.errors)
- {
- if (!global.gag)
- {
- errorSupplemental(loc, "while looking for match for %s", toChars());
- semanticRun = PASSsemanticdone;
- inst = this;
- }
- errors = true;
- }
- //printf("false\n");
- return false;
-}
-
-
-/*****************************************
- * Determines if a TemplateInstance will need a nested
- * generation of the TemplateDeclaration.
- * Sets enclosing property if so, and returns != 0;
- */
-
-bool TemplateInstance::hasNestedArgs(Objects *args, bool isstatic)
-{
- int nested = 0;
- //printf("TemplateInstance::hasNestedArgs('%s')\n", tempdecl->ident->toChars());
-
- /* A nested instance happens when an argument references a local
- * symbol that is on the stack.
- */
- for (size_t i = 0; i < args->length; i++)
- {
- RootObject *o = (*args)[i];
- Expression *ea = isExpression(o);
- Dsymbol *sa = isDsymbol(o);
- Tuple *va = isTuple(o);
- if (ea)
- {
- if (ea->op == TOKvar)
- {
- sa = ((VarExp *)ea)->var;
- goto Lsa;
- }
- if (ea->op == TOKthis)
- {
- sa = ((ThisExp *)ea)->var;
- goto Lsa;
- }
- if (ea->op == TOKfunction)
- {
- if (((FuncExp *)ea)->td)
- sa = ((FuncExp *)ea)->td;
- else
- sa = ((FuncExp *)ea)->fd;
- goto Lsa;
- }
- // Emulate Expression::toMangleBuffer call that had exist in TemplateInstance::genIdent.
- if (ea->op != TOKint64 &&
- ea->op != TOKfloat64 &&
- ea->op != TOKcomplex80 &&
- ea->op != TOKnull &&
- ea->op != TOKstring &&
- ea->op != TOKarrayliteral &&
- ea->op != TOKassocarrayliteral &&
- ea->op != TOKstructliteral)
- {
- ea->error("expression %s is not a valid template value argument", ea->toChars());
- errors = true;
- }
- }
- else if (sa)
- {
- Lsa:
- sa = sa->toAlias();
- TemplateDeclaration *td = sa->isTemplateDeclaration();
- if (td)
- {
- TemplateInstance *ti = sa->toParent()->isTemplateInstance();
- if (ti && ti->enclosing)
- sa = ti;
- }
- TemplateInstance *ti = sa->isTemplateInstance();
- Declaration *d = sa->isDeclaration();
- if ((td && td->literal) ||
- (ti && ti->enclosing) ||
- (d && !d->isDataseg() &&
- !(d->storage_class & STCmanifest) &&
- (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) &&
- !isTemplateMixin()
- ))
- {
- // if module level template
- if (isstatic)
- {
- Dsymbol *dparent = sa->toParent2();
- if (!enclosing)
- enclosing = dparent;
- else if (enclosing != dparent)
- {
- /* Select the more deeply nested of the two.
- * Error if one is not nested inside the other.
- */
- for (Dsymbol *p = enclosing; p; p = p->parent)
- {
- if (p == dparent)
- goto L1; // enclosing is most nested
- }
- for (Dsymbol *p = dparent; p; p = p->parent)
- {
- if (p == enclosing)
- {
- enclosing = dparent;
- goto L1; // dparent is most nested
- }
- }
- error("%s is nested in both %s and %s",
- toChars(), enclosing->toChars(), dparent->toChars());
- errors = true;
- }
- L1:
- //printf("\tnested inside %s\n", enclosing->toChars());
- nested |= 1;
- }
- else
- {
- error("cannot use local `%s` as parameter to non-global template %s", sa->toChars(), tempdecl->toChars());
- errors = true;
- }
- }
- }
- else if (va)
- {
- nested |= (int)hasNestedArgs(&va->objects, isstatic);
- }
- }
- //printf("-TemplateInstance::hasNestedArgs('%s') = %d\n", tempdecl->ident->toChars(), nested);
- return nested != 0;
-}
-
-/*****************************************
- * Append 'this' to the specific module members[]
- */
-Dsymbols *TemplateInstance::appendToModuleMember()
-{
- Module *mi = minst; // instantiated -> inserted module
-
- if (global.params.useUnitTests)
- {
- // Turn all non-root instances to speculative
- if (mi && !mi->isRoot())
- mi = NULL;
- }
-
- //printf("%s->appendToModuleMember() enclosing = %s mi = %s\n",
- // toPrettyChars(),
- // enclosing ? enclosing->toPrettyChars() : NULL,
- // mi ? mi->toPrettyChars() : NULL);
- if (!mi || mi->isRoot())
- {
- /* If the instantiated module is speculative or root, insert to the
- * member of a root module. Then:
- * - semantic3 pass will get called on the instance members.
- * - codegen pass will get a selection chance to do/skip it.
- */
-
- struct N
- {
- static Dsymbol *getStrictEnclosing(TemplateInstance *ti)
- {
- do
- {
- if (ti->enclosing)
- return ti->enclosing;
- ti = ti->tempdecl->isInstantiated();
- }
- while (ti);
- return NULL;
- }
- };
- Dsymbol *enc = N::getStrictEnclosing(this);
-
- // insert target is made stable by using the module
- // where tempdecl is declared.
- mi = (enc ? enc : tempdecl)->getModule();
- if (!mi->isRoot())
- mi = mi->importedFrom;
- assert(mi->isRoot());
- }
- else
- {
- /* If the instantiated module is non-root, insert to the member of the
- * non-root module. Then:
- * - semantic3 pass won't be called on the instance.
- * - codegen pass won't reach to the instance.
- */
- }
- //printf("\t--> mi = %s\n", mi->toPrettyChars());
-
- if (memberOf == mi) // already a member
- {
- return NULL;
- }
-
- Dsymbols *a = mi->members;
- a->push(this);
- memberOf = mi;
- if (mi->semanticRun >= PASSsemantic2done && mi->isRoot())
- Module::addDeferredSemantic2(this);
- if (mi->semanticRun >= PASSsemantic3done && mi->isRoot())
- Module::addDeferredSemantic3(this);
- return a;
-}
-
-/****************************************
- * This instance needs an identifier for name mangling purposes.
- * Create one by taking the template declaration name and adding
- * the type signature for it.
- */
-
-Identifier *TemplateInstance::genIdent(Objects *args)
-{
- //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars());
- assert(args == tiargs);
- OutBuffer buf;
- mangleToBuffer(this, &buf);
- //printf("\tgenIdent = %s\n", id);
- return Identifier::idPool(buf.peekChars());
-}
-
-/*************************************
- * Lazily generate identifier for template instance.
- * This is because 75% of the ident's are never needed.
- */
-
-Identifier *TemplateInstance::getIdent()
-{
- if (!ident && inst && !errors)
- ident = genIdent(tiargs); // need an identifier for name mangling purposes.
- return ident;
-}
-
-/****************************************************
- * Declare parameters of template instance, initialize them with the
- * template instance arguments.
- */
-
-void TemplateInstance::declareParameters(Scope *sc)
-{
- TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
- assert(tempdecl);
-
- //printf("TemplateInstance::declareParameters()\n");
- for (size_t i = 0; i < tdtypes.length; i++)
- {
- TemplateParameter *tp = (*tempdecl->parameters)[i];
- //RootObject *o = (*tiargs)[i];
- RootObject *o = tdtypes[i]; // initializer for tp
-
- //printf("\ttdtypes[%d] = %p\n", i, o);
- tempdecl->declareParameter(sc, tp, o);
- }
-}
-
-/**************************************
- * Given an error instantiating the TemplateInstance,
- * give the nested TemplateInstance instantiations that got
- * us here. Those are a list threaded into the nested scopes.
- */
-void TemplateInstance::printInstantiationTrace()
-{
- if (global.gag)
- return;
-
- const unsigned max_shown = 6;
- const char format[] = "instantiated from here: %s";
-
- // determine instantiation depth and number of recursive instantiations
- unsigned n_instantiations = 1;
- unsigned n_totalrecursions = 0;
- for (TemplateInstance *cur = this; cur; cur = cur->tinst)
- {
- ++n_instantiations;
- // If two instantiations use the same declaration, they are recursive.
- // (this works even if they are instantiated from different places in the
- // same template).
- // In principle, we could also check for multiple-template recursion, but it's
- // probably not worthwhile.
- if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl
- && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc))
- ++n_totalrecursions;
- }
-
- // show full trace only if it's short or verbose is on
- if (n_instantiations <= max_shown || global.params.verbose)
- {
- for (TemplateInstance *cur = this; cur; cur = cur->tinst)
- {
- cur->errors = true;
- errorSupplemental(cur->loc, format, cur->toChars());
- }
- }
- else if (n_instantiations - n_totalrecursions <= max_shown)
- {
- // By collapsing recursive instantiations into a single line,
- // we can stay under the limit.
- int recursionDepth=0;
- for (TemplateInstance *cur = this; cur; cur = cur->tinst)
- {
- cur->errors = true;
- if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl
- && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc))
- {
- ++recursionDepth;
- }
- else
- {
- if (recursionDepth)
- errorSupplemental(cur->loc, "%d recursive instantiations from here: %s", recursionDepth+2, cur->toChars());
- else
- errorSupplemental(cur->loc, format, cur->toChars());
- recursionDepth = 0;
- }
- }
- }
- else
- {
- // Even after collapsing the recursions, the depth is too deep.
- // Just display the first few and last few instantiations.
- unsigned i = 0;
- for (TemplateInstance *cur = this; cur; cur = cur->tinst)
- {
- cur->errors = true;
-
- if (i == max_shown / 2)
- errorSupplemental(cur->loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown);
-
- if (i < max_shown / 2 ||
- i >= n_instantiations - max_shown + max_shown / 2)
- errorSupplemental(cur->loc, format, cur->toChars());
- ++i;
- }
- }
-}
-
-Dsymbol *TemplateInstance::toAlias()
-{
- if (!inst)
- {
- // Maybe we can resolve it
- if (_scope)
- {
- dsymbolSemantic(this, _scope);
- }
- if (!inst)
- {
- error("cannot resolve forward reference");
- errors = true;
- return this;
- }
- }
-
- if (inst != this)
- return inst->toAlias();
-
- if (aliasdecl)
- {
- return aliasdecl->toAlias();
- }
-
- return inst;
-}
-
-const char *TemplateInstance::kind() const
-{
- return "template instance";
-}
-
-bool TemplateInstance::oneMember(Dsymbol **ps, Identifier *)
-{
- *ps = NULL;
- return true;
-}
-
-const char *TemplateInstance::toChars()
-{
- OutBuffer buf;
- toCBufferInstance(this, &buf);
- return buf.extractChars();
-}
-
-const char *TemplateInstance::toPrettyCharsHelper()
-{
- OutBuffer buf;
- toCBufferInstance(this, &buf, true);
- return buf.extractChars();
-}
-
-/*************************************
- * Compare proposed template instantiation with existing template instantiation.
- * Note that this is not commutative because of the auto ref check.
- * Params:
- * this = proposed template instantiation
- * o = existing template instantiation
- * Returns:
- * 0 for match, 1 for no match
- */
-int TemplateInstance::compare(RootObject *o)
-{
- TemplateInstance *ti = (TemplateInstance *)o;
-
- //printf("this = %p, ti = %p\n", this, ti);
- assert(tdtypes.length == ti->tdtypes.length);
-
- // Nesting must match
- if (enclosing != ti->enclosing)
- {
- //printf("test2 enclosing %s ti->enclosing %s\n", enclosing ? enclosing->toChars() : "", ti->enclosing ? ti->enclosing->toChars() : "");
- goto Lnotequals;
- }
- //printf("parent = %s, ti->parent = %s\n", parent->toPrettyChars(), ti->parent->toPrettyChars());
-
- if (!arrayObjectMatch(&tdtypes, &ti->tdtypes))
- goto Lnotequals;
-
- /* Template functions may have different instantiations based on
- * "auto ref" parameters.
- */
- if (FuncDeclaration *fd = ti->toAlias()->isFuncDeclaration())
- {
- if (!fd->errors)
- {
- ParameterList fparameters = fd->getParameterList();
- size_t nfparams = fparameters.length(); // Num function parameters
- for (size_t j = 0; j < nfparams; j++)
- {
- Parameter *fparam = fparameters[j];
- if (fparam->storageClass & STCautoref) // if "auto ref"
- {
- if (!fargs)
- goto Lnotequals;
- if (fargs->length <= j)
- break;
- Expression *farg = (*fargs)[j];
- if (farg->isLvalue())
- {
- if (!(fparam->storageClass & STCref))
- goto Lnotequals; // auto ref's don't match
- }
- else
- {
- if (fparam->storageClass & STCref)
- goto Lnotequals; // auto ref's don't match
- }
- }
- }
- }
- }
- return 0;
-
- Lnotequals:
- return 1;
-}
-
-hash_t TemplateInstance::toHash()
-{
- if (!hash)
- {
- hash = (size_t)(void *)enclosing;
- hash += arrayObjectHash(&tdtypes);
- hash += hash == 0;
- }
- return hash;
-}
-
-/**************************************
- * IsExpression can evaluate the specified type speculatively, and even if
- * it instantiates any symbols, they are normally unnecessary for the
- * final executable.
- * However, if those symbols leak to the actual code, compiler should remark
- * them as non-speculative to generate their code and link to the final executable.
- */
-void unSpeculative(Scope *sc, RootObject *o)
-{
- if (!o)
- return;
-
- if (Tuple *tup = isTuple(o))
- {
- for (size_t i = 0; i < tup->objects.length; i++)
- {
- unSpeculative(sc, tup->objects[i]);
- }
- return;
- }
-
- Dsymbol *s = getDsymbol(o);
- if (!s)
- return;
-
- if (Declaration *d = s->isDeclaration())
- {
- if (VarDeclaration *vd = d->isVarDeclaration())
- o = vd->type;
- else if (AliasDeclaration *ad = d->isAliasDeclaration())
- {
- o = ad->getType();
- if (!o)
- o = ad->toAlias();
- }
- else
- o = d->toAlias();
-
- s = getDsymbol(o);
- if (!s)
- return;
- }
-
- if (TemplateInstance *ti = s->isTemplateInstance())
- {
- // If the instance is already non-speculative,
- // or it is leaked to the speculative scope.
- if (ti->minst != NULL || sc->minst == NULL)
- return;
-
- // Remark as non-speculative instance.
- ti->minst = sc->minst;
- if (!ti->tinst)
- ti->tinst = sc->tinst;
-
- unSpeculative(sc, ti->tempdecl);
- }
-
- if (TemplateInstance *ti = s->isInstantiated())
- unSpeculative(sc, ti);
-}
-
-/**
- Returns: true if the instances' innards are discardable.
-
- The idea of this function is to see if the template instantiation
- can be 100% replaced with its eponymous member. All other members
- can be discarded, even in the compiler to free memory (for example,
- the template could be expanded in a region allocator, deemed trivial,
- the end result copied back out independently and the entire region freed),
- and can be elided entirely from the binary.
-
- The current implementation affects code that generally looks like:
-
- ---
- template foo(args...) {
- some_basic_type_or_string helper() { .... }
- enum foo = helper();
- }
- ---
-
- since it was the easiest starting point of implementation but it can and
- should be expanded more later.
-*/
-static bool isDiscardable(TemplateInstance *ti)
-{
- if (ti->aliasdecl == NULL)
- return false;
-
- VarDeclaration *v = ti->aliasdecl->isVarDeclaration();
- if (v == NULL)
- return false;
-
- if (!(v->storage_class & STCmanifest))
- return false;
-
- // Currently only doing basic types here because it is the easiest proof-of-concept
- // implementation with minimal risk of side effects, but it could likely be
- // expanded to any type that already exists outside this particular instance.
- if (!(v->type->equals(Type::tstring) || (v->type->isTypeBasic() != NULL)))
- return false;
-
- // Static ctors and dtors, even in an eponymous enum template, are still run,
- // so if any of them are in here, we'd better not assume it is trivial lest
- // we break useful code
- for (size_t i = 0; i < ti->members->length; i++)
- {
- Dsymbol *member = (*ti->members)[i];
- if (member->hasStaticCtorOrDtor())
- return false;
- if (member->isStaticDtorDeclaration())
- return false;
- if (member->isStaticCtorDeclaration())
- return false;
- }
-
- // but if it passes through this gauntlet... it should be fine. D code will
- // see only the eponymous member, outside stuff can never access it, even through
- // reflection; the outside world ought to be none the wiser. Even dmd should be
- // able to simply free the memory of everything except the final result.
-
- return true;
-}
-
-/***********************************************
- * Returns true if this is not instantiated in non-root module, and
- * is a part of non-speculative instantiatiation.
- *
- * Note: minst does not stabilize until semantic analysis is completed,
- * so don't call this function during semantic analysis to return precise result.
- */
-bool TemplateInstance::needsCodegen()
-{
- if (!minst)
- {
- // If this is a speculative instantiation,
- // 1. do codegen if ancestors really needs codegen.
- // 2. become non-speculative if siblings are not speculative
-
- TemplateInstance *tnext = this->tnext;
- TemplateInstance *tinst = this->tinst;
- // At first, disconnect chain first to prevent infinite recursion.
- this->tnext = NULL;
- this->tinst = NULL;
-
- // Determine necessity of tinst before tnext.
- if (tinst && tinst->needsCodegen())
- {
- minst = tinst->minst; // cache result
- if (global.params.allInst && minst)
- {
- return true;
- }
- assert(minst);
- assert(minst->isRoot() || minst->rootImports());
- return true;
- }
- if (tnext && (tnext->needsCodegen() || tnext->minst))
- {
- minst = tnext->minst; // cache result
- if (global.params.allInst && minst)
- {
- return true;
- }
- assert(minst);
- return minst->isRoot() || minst->rootImports();
- }
-
- // Elide codegen because this is really speculative.
- return false;
- }
-
- if (global.params.allInst)
- {
- return true;
- }
-
- if (isDiscardable(this))
- {
- return false;
- }
-
- /* Even when this is reached to the codegen pass,
- * a non-root nested template should not generate code,
- * due to avoid ODR violation.
- */
- if (enclosing && enclosing->inNonRoot())
- {
- if (tinst)
- {
- bool r = tinst->needsCodegen();
- minst = tinst->minst; // cache result
- return r;
- }
- if (tnext)
- {
- bool r = tnext->needsCodegen();
- minst = tnext->minst; // cache result
- return r;
- }
- return false;
- }
-
- if (global.params.useUnitTests)
- {
- // Prefer instantiations from root modules, to maximize link-ability.
- if (minst->isRoot())
- return true;
-
- TemplateInstance *tnext = this->tnext;
- TemplateInstance *tinst = this->tinst;
- this->tnext = NULL;
- this->tinst = NULL;
-
- if (tinst && tinst->needsCodegen())
- {
- minst = tinst->minst; // cache result
- assert(minst);
- assert(minst->isRoot() || minst->rootImports());
- return true;
- }
- if (tnext && tnext->needsCodegen())
- {
- minst = tnext->minst; // cache result
- assert(minst);
- assert(minst->isRoot() || minst->rootImports());
- return true;
- }
-
- // Bugzilla 2500 case
- if (minst->rootImports())
- return true;
-
- // Elide codegen because this is not included in root instances.
- return false;
- }
- else
- {
- // Prefer instantiations from non-root module, to minimize object code size.
-
- /* If a TemplateInstance is ever instantiated by non-root modules,
- * we do not have to generate code for it,
- * because it will be generated when the non-root module is compiled.
- *
- * But, if the non-root 'minst' imports any root modules, it might still need codegen.
- *
- * The problem is if A imports B, and B imports A, and both A
- * and B instantiate the same template, does the compilation of A
- * or the compilation of B do the actual instantiation?
- *
- * See Bugzilla 2500.
- */
- if (!minst->isRoot() && !minst->rootImports())
- return false;
-
- TemplateInstance *tnext = this->tnext;
- this->tnext = NULL;
-
- if (tnext && !tnext->needsCodegen() && tnext->minst)
- {
- minst = tnext->minst; // cache result
- assert(!minst->isRoot());
- return false;
- }
-
- // Do codegen because this is not included in non-root instances.
- return true;
- }
-}
-
-/* ======================== TemplateMixin ================================ */
-
-TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, TypeQualified *tqual, Objects *tiargs)
- : TemplateInstance(loc, tqual->idents.length ? (Identifier *)tqual->idents[tqual->idents.length - 1]
- : ((TypeIdentifier *)tqual)->ident)
-{
- //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : "");
- this->ident = ident;
- this->tqual = tqual;
- this->tiargs = tiargs ? tiargs : new Objects();
-}
-
-Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *)
-{
- TemplateMixin *tm = new TemplateMixin(loc, ident,
- (TypeQualified *)tqual->syntaxCopy(), tiargs);
- return TemplateInstance::syntaxCopy(tm);
-}
-
-bool TemplateMixin::findTempDecl(Scope *sc)
-{
- // Follow qualifications to find the TemplateDeclaration
- if (!tempdecl)
- {
- Expression *e;
- Type *t;
- Dsymbol *s;
- tqual->resolve(loc, sc, &e, &t, &s);
- if (!s)
- {
- error("is not defined");
- return false;
- }
- s = s->toAlias();
- tempdecl = s->isTemplateDeclaration();
- OverloadSet *os = s->isOverloadSet();
-
- /* If an OverloadSet, look for a unique member that is a template declaration
- */
- if (os)
- {
- Dsymbol *ds = NULL;
- for (size_t i = 0; i < os->a.length; i++)
- {
- Dsymbol *s2 = os->a[i]->isTemplateDeclaration();
- if (s2)
- {
- if (ds)
- {
- tempdecl = os;
- break;
- }
- ds = s2;
- }
- }
- }
- if (!tempdecl)
- {
- error("%s isn't a template", s->toChars());
- return false;
- }
- }
- assert(tempdecl);
-
- struct ParamFwdResTm
- {
- static int fp(void *param, Dsymbol *s)
- {
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (!td)
- return 0;
-
- TemplateMixin *tm = (TemplateMixin *)param;
- if (td->semanticRun == PASSinit)
- {
- if (td->_scope)
- dsymbolSemantic(td, td->_scope);
- else
- {
- tm->semanticRun = PASSinit;
- return 1;
- }
- }
- return 0;
- }
- };
- // Look for forward references
- OverloadSet *tovers = tempdecl->isOverloadSet();
- size_t overs_dim = tovers ? tovers->a.length : 1;
- for (size_t oi = 0; oi < overs_dim; oi++)
- {
- if (overloadApply(tovers ? tovers->a[oi] : tempdecl, (void *)this, &ParamFwdResTm::fp))
- return false;
- }
- return true;
-}
-
-const char *TemplateMixin::kind() const
-{
- return "mixin";
-}
-
-bool TemplateMixin::oneMember(Dsymbol **ps, Identifier *ident)
-{
- return Dsymbol::oneMember(ps, ident);
-}
-
-int TemplateMixin::apply(Dsymbol_apply_ft_t fp, void *param)
-{
- if (_scope) // if fwd reference
- dsymbolSemantic(this, NULL); // try to resolve it
- if (members)
- {
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- if (s)
- {
- if (s->apply(fp, param))
- return 1;
- }
- }
- }
- return 0;
-}
-
-bool TemplateMixin::hasPointers()
-{
- //printf("TemplateMixin::hasPointers() %s\n", toChars());
-
- if (members)
- {
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- //printf(" s = %s %s\n", s->kind(), s->toChars());
- if (s->hasPointers())
- {
- return true;
- }
- }
- }
- return false;
-}
-
-void TemplateMixin::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
-{
- //printf("TemplateMixin::setFieldOffset() %s\n", toChars());
- if (_scope) // if fwd reference
- dsymbolSemantic(this, NULL); // try to resolve it
- if (members)
- {
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- //printf("\t%s\n", s->toChars());
- s->setFieldOffset(ad, poffset, isunion);
- }
- }
-}
-
-const char *TemplateMixin::toChars()
-{
- OutBuffer buf;
- toCBufferInstance(this, &buf);
- return buf.extractChars();
-}
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
new file mode 100644
index 0000000..c3503bb
--- /dev/null
+++ b/gcc/d/dmd/dtemplate.d
@@ -0,0 +1,8415 @@
+/**
+ * Defines `TemplateDeclaration`, `TemplateInstance` and a few utilities
+ *
+ * This modules holds the two main template types:
+ * `TemplateDeclaration`, which is the user-provided declaration of a template,
+ * and `TemplateInstance`, which is an instance of a `TemplateDeclaration`
+ * with specific arguments.
+ *
+ * Template_Parameter:
+ * Additionally, the classes for template parameters are defined in this module.
+ * The base class, `TemplateParameter`, is inherited by:
+ * - `TemplateTypeParameter`
+ * - `TemplateThisParameter`
+ * - `TemplateValueParameter`
+ * - `TemplateAliasParameter`
+ * - `TemplateTupleParameter`
+ *
+ * Templates_semantic:
+ * The start of the template instantiation process looks like this:
+ * - A `TypeInstance` or `TypeIdentifier` is encountered.
+ * `TypeInstance` have a bang (e.g. `Foo!(arg)`) while `TypeIdentifier` don't.
+ * - A `TemplateInstance` is instantiated
+ * - Semantic is run on the `TemplateInstance` (see `dmd.dsymbolsem`)
+ * - The `TemplateInstance` search for its `TemplateDeclaration`,
+ * runs semantic on the template arguments and deduce the best match
+ * among the possible overloads.
+ * - The `TemplateInstance` search for existing instances with the same
+ * arguments, and uses it if found.
+ * - Otherwise, the rest of semantic is run on the `TemplateInstance`.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtemplate.d, _dtemplate.d)
+ * Documentation: https://dlang.org/phobos/dmd_dtemplate.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtemplate.d
+ */
+
+module dmd.dtemplate;
+
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.ast_node;
+import dmd.dcast;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dmangle;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.impcnvtab;
+import dmd.init;
+import dmd.initsem;
+import dmd.mtype;
+import dmd.opover;
+import dmd.root.array;
+import dmd.root.outbuffer;
+import dmd.root.rootobject;
+import dmd.semantic2;
+import dmd.semantic3;
+import dmd.tokens;
+import dmd.typesem;
+import dmd.visitor;
+
+import dmd.templateparamsem;
+
+//debug = FindExistingInstance; // print debug stats of findExistingInstance
+private enum LOG = false;
+
+enum IDX_NOTFOUND = 0x12345678;
+
+pure nothrow @nogc
+{
+
+/********************************************
+ * These functions substitute for dynamic_cast. dynamic_cast does not work
+ * on earlier versions of gcc.
+ */
+extern (C++) inout(Expression) isExpression(inout RootObject o)
+{
+ //return dynamic_cast<Expression *>(o);
+ if (!o || o.dyncast() != DYNCAST.expression)
+ return null;
+ return cast(inout(Expression))o;
+}
+
+extern (C++) inout(Dsymbol) isDsymbol(inout RootObject o)
+{
+ //return dynamic_cast<Dsymbol *>(o);
+ if (!o || o.dyncast() != DYNCAST.dsymbol)
+ return null;
+ return cast(inout(Dsymbol))o;
+}
+
+extern (C++) inout(Type) isType(inout RootObject o)
+{
+ //return dynamic_cast<Type *>(o);
+ if (!o || o.dyncast() != DYNCAST.type)
+ return null;
+ return cast(inout(Type))o;
+}
+
+extern (C++) inout(Tuple) isTuple(inout RootObject o)
+{
+ //return dynamic_cast<Tuple *>(o);
+ if (!o || o.dyncast() != DYNCAST.tuple)
+ return null;
+ return cast(inout(Tuple))o;
+}
+
+extern (C++) inout(Parameter) isParameter(inout RootObject o)
+{
+ //return dynamic_cast<Parameter *>(o);
+ if (!o || o.dyncast() != DYNCAST.parameter)
+ return null;
+ return cast(inout(Parameter))o;
+}
+
+extern (C++) inout(TemplateParameter) isTemplateParameter(inout RootObject o)
+{
+ if (!o || o.dyncast() != DYNCAST.templateparameter)
+ return null;
+ return cast(inout(TemplateParameter))o;
+}
+
+/**************************************
+ * Is this Object an error?
+ */
+extern (C++) bool isError(const RootObject o)
+{
+ if (const t = isType(o))
+ return (t.ty == Terror);
+ if (const e = isExpression(o))
+ return (e.op == TOK.error || !e.type || e.type.ty == Terror);
+ if (const v = isTuple(o))
+ return arrayObjectIsError(&v.objects);
+ const s = isDsymbol(o);
+ assert(s);
+ if (s.errors)
+ return true;
+ return s.parent ? isError(s.parent) : false;
+}
+
+/**************************************
+ * Are any of the Objects an error?
+ */
+bool arrayObjectIsError(const Objects* args)
+{
+ foreach (const o; *args)
+ {
+ if (isError(o))
+ return true;
+ }
+ return false;
+}
+
+/***********************
+ * Try to get arg as a type.
+ */
+inout(Type) getType(inout RootObject o)
+{
+ inout t = isType(o);
+ if (!t)
+ {
+ if (inout e = isExpression(o))
+ return e.type;
+ }
+ return t;
+}
+
+}
+
+Dsymbol getDsymbol(RootObject oarg)
+{
+ //printf("getDsymbol()\n");
+ //printf("e %p s %p t %p v %p\n", isExpression(oarg), isDsymbol(oarg), isType(oarg), isTuple(oarg));
+ if (auto ea = isExpression(oarg))
+ {
+ // Try to convert Expression to symbol
+ if (auto ve = ea.isVarExp())
+ return ve.var;
+ else if (auto fe = ea.isFuncExp())
+ return fe.td ? fe.td : fe.fd;
+ else if (auto te = ea.isTemplateExp())
+ return te.td;
+ else if (auto te = ea.isScopeExp())
+ return te.sds;
+ else
+ return null;
+ }
+ else
+ {
+ // Try to convert Type to symbol
+ if (auto ta = isType(oarg))
+ return ta.toDsymbol(null);
+ else
+ return isDsymbol(oarg); // if already a symbol
+ }
+}
+
+
+private Expression getValue(ref Dsymbol s)
+{
+ if (s)
+ {
+ if (VarDeclaration v = s.isVarDeclaration())
+ {
+ if (v.storage_class & STC.manifest)
+ return v.getConstInitializer();
+ }
+ }
+ return null;
+}
+
+/***********************
+ * Try to get value from manifest constant
+ */
+private Expression getValue(Expression e)
+{
+ if (!e)
+ return null;
+ if (auto ve = e.isVarExp())
+ {
+ if (auto v = ve.var.isVarDeclaration())
+ {
+ if (v.storage_class & STC.manifest)
+ {
+ e = v.getConstInitializer();
+ }
+ }
+ }
+ return e;
+}
+
+private Expression getExpression(RootObject o)
+{
+ auto s = isDsymbol(o);
+ return s ? .getValue(s) : .getValue(isExpression(o));
+}
+
+/******************************
+ * If o1 matches o2, return true.
+ * Else, return false.
+ */
+private bool match(RootObject o1, RootObject o2)
+{
+ enum log = false;
+
+ static if (log)
+ {
+ printf("match() o1 = %p %s (%d), o2 = %p %s (%d)\n",
+ o1, o1.toChars(), o1.dyncast(), o2, o2.toChars(), o2.dyncast());
+ }
+
+ /* A proper implementation of the various equals() overrides
+ * should make it possible to just do o1.equals(o2), but
+ * we'll do that another day.
+ */
+ /* Manifest constants should be compared by their values,
+ * at least in template arguments.
+ */
+
+ if (auto t1 = isType(o1))
+ {
+ auto t2 = isType(o2);
+ if (!t2)
+ goto Lnomatch;
+
+ static if (log)
+ {
+ printf("\tt1 = %s\n", t1.toChars());
+ printf("\tt2 = %s\n", t2.toChars());
+ }
+ if (!t1.equals(t2))
+ goto Lnomatch;
+
+ goto Lmatch;
+ }
+ if (auto e1 = getExpression(o1))
+ {
+ auto e2 = getExpression(o2);
+ if (!e2)
+ goto Lnomatch;
+
+ static if (log)
+ {
+ printf("\te1 = %s '%s' %s\n", e1.type ? e1.type.toChars() : "null", Token.toChars(e1.op), e1.toChars());
+ printf("\te2 = %s '%s' %s\n", e2.type ? e2.type.toChars() : "null", Token.toChars(e2.op), e2.toChars());
+ }
+
+ // two expressions can be equal although they do not have the same
+ // type; that happens when they have the same value. So check type
+ // as well as expression equality to ensure templates are properly
+ // matched.
+ if (!(e1.type && e2.type && e1.type.equals(e2.type)) || !e1.equals(e2))
+ goto Lnomatch;
+
+ goto Lmatch;
+ }
+ if (auto s1 = isDsymbol(o1))
+ {
+ auto s2 = isDsymbol(o2);
+ if (!s2)
+ goto Lnomatch;
+
+ static if (log)
+ {
+ printf("\ts1 = %s \n", s1.kind(), s1.toChars());
+ printf("\ts2 = %s \n", s2.kind(), s2.toChars());
+ }
+ if (!s1.equals(s2))
+ goto Lnomatch;
+ if (s1.parent != s2.parent && !s1.isFuncDeclaration() && !s2.isFuncDeclaration())
+ goto Lnomatch;
+
+ goto Lmatch;
+ }
+ if (auto u1 = isTuple(o1))
+ {
+ auto u2 = isTuple(o2);
+ if (!u2)
+ goto Lnomatch;
+
+ static if (log)
+ {
+ printf("\tu1 = %s\n", u1.toChars());
+ printf("\tu2 = %s\n", u2.toChars());
+ }
+ if (!arrayObjectMatch(&u1.objects, &u2.objects))
+ goto Lnomatch;
+
+ goto Lmatch;
+ }
+Lmatch:
+ static if (log)
+ printf("\t. match\n");
+ return true;
+
+Lnomatch:
+ static if (log)
+ printf("\t. nomatch\n");
+ return false;
+}
+
+/************************************
+ * Match an array of them.
+ */
+private bool arrayObjectMatch(Objects* oa1, Objects* oa2)
+{
+ if (oa1 == oa2)
+ return true;
+ if (oa1.dim != oa2.dim)
+ return false;
+ immutable oa1dim = oa1.dim;
+ auto oa1d = (*oa1)[].ptr;
+ auto oa2d = (*oa2)[].ptr;
+ foreach (j; 0 .. oa1dim)
+ {
+ RootObject o1 = oa1d[j];
+ RootObject o2 = oa2d[j];
+ if (!match(o1, o2))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+/************************************
+ * Return hash of Objects.
+ */
+private size_t arrayObjectHash(Objects* oa1)
+{
+ import dmd.root.hash : mixHash;
+
+ size_t hash = 0;
+ foreach (o1; *oa1)
+ {
+ /* Must follow the logic of match()
+ */
+ if (auto t1 = isType(o1))
+ hash = mixHash(hash, cast(size_t)t1.deco);
+ else if (auto e1 = getExpression(o1))
+ hash = mixHash(hash, expressionHash(e1));
+ else if (auto s1 = isDsymbol(o1))
+ {
+ auto fa1 = s1.isFuncAliasDeclaration();
+ if (fa1)
+ s1 = fa1.toAliasFunc();
+ hash = mixHash(hash, mixHash(cast(size_t)cast(void*)s1.getIdent(), cast(size_t)cast(void*)s1.parent));
+ }
+ else if (auto u1 = isTuple(o1))
+ hash = mixHash(hash, arrayObjectHash(&u1.objects));
+ }
+ return hash;
+}
+
+
+/************************************
+ * Computes hash of expression.
+ * Handles all Expression classes and MUST match their equals method,
+ * i.e. e1.equals(e2) implies expressionHash(e1) == expressionHash(e2).
+ */
+private size_t expressionHash(Expression e)
+{
+ import dmd.root.ctfloat : CTFloat;
+ import dmd.root.hash : calcHash, mixHash;
+
+ switch (e.op)
+ {
+ case TOK.int64:
+ return cast(size_t) e.isIntegerExp().getInteger();
+
+ case TOK.float64:
+ return CTFloat.hash(e.isRealExp().value);
+
+ case TOK.complex80:
+ auto ce = e.isComplexExp();
+ return mixHash(CTFloat.hash(ce.toReal), CTFloat.hash(ce.toImaginary));
+
+ case TOK.identifier:
+ return cast(size_t)cast(void*) e.isIdentifierExp().ident;
+
+ case TOK.null_:
+ return cast(size_t)cast(void*) e.isNullExp().type;
+
+ case TOK.string_:
+ return calcHash(e.isStringExp.peekData());
+
+ case TOK.tuple:
+ {
+ auto te = e.isTupleExp();
+ size_t hash = 0;
+ hash += te.e0 ? expressionHash(te.e0) : 0;
+ foreach (elem; *te.exps)
+ hash = mixHash(hash, expressionHash(elem));
+ return hash;
+ }
+
+ case TOK.arrayLiteral:
+ {
+ auto ae = e.isArrayLiteralExp();
+ size_t hash;
+ foreach (i; 0 .. ae.elements.dim)
+ hash = mixHash(hash, expressionHash(ae[i]));
+ return hash;
+ }
+
+ case TOK.assocArrayLiteral:
+ {
+ auto ae = e.isAssocArrayLiteralExp();
+ size_t hash;
+ foreach (i; 0 .. ae.keys.dim)
+ // reduction needs associative op as keys are unsorted (use XOR)
+ hash ^= mixHash(expressionHash((*ae.keys)[i]), expressionHash((*ae.values)[i]));
+ return hash;
+ }
+
+ case TOK.structLiteral:
+ {
+ auto se = e.isStructLiteralExp();
+ size_t hash;
+ foreach (elem; *se.elements)
+ hash = mixHash(hash, elem ? expressionHash(elem) : 0);
+ return hash;
+ }
+
+ case TOK.variable:
+ return cast(size_t)cast(void*) e.isVarExp().var;
+
+ case TOK.function_:
+ return cast(size_t)cast(void*) e.isFuncExp().fd;
+
+ default:
+ // no custom equals for this expression
+ assert((&e.equals).funcptr is &RootObject.equals);
+ // equals based on identity
+ return cast(size_t)cast(void*) e;
+ }
+}
+
+RootObject objectSyntaxCopy(RootObject o)
+{
+ if (!o)
+ return null;
+ if (Type t = isType(o))
+ return t.syntaxCopy();
+ if (Expression e = isExpression(o))
+ return e.syntaxCopy();
+ return o;
+}
+
+extern (C++) final class Tuple : RootObject
+{
+ Objects objects;
+
+ extern (D) this() {}
+
+ /**
+ Params:
+ numObjects = The initial number of objects.
+ */
+ extern (D) this(size_t numObjects)
+ {
+ objects.setDim(numObjects);
+ }
+
+ // kludge for template.isType()
+ override DYNCAST dyncast() const
+ {
+ return DYNCAST.tuple;
+ }
+
+ override const(char)* toChars() const
+ {
+ return objects.toChars();
+ }
+}
+
+struct TemplatePrevious
+{
+ TemplatePrevious* prev;
+ Scope* sc;
+ Objects* dedargs;
+}
+
+/***********************************************************
+ * [mixin] template Identifier (parameters) [Constraint]
+ * https://dlang.org/spec/template.html
+ * https://dlang.org/spec/template-mixin.html
+ */
+extern (C++) final class TemplateDeclaration : ScopeDsymbol
+{
+ import dmd.root.array : Array;
+
+ TemplateParameters* parameters; // array of TemplateParameter's
+ TemplateParameters* origParameters; // originals for Ddoc
+
+ Expression constraint;
+
+ // Hash table to look up TemplateInstance's of this TemplateDeclaration
+ TemplateInstance[TemplateInstanceBox] instances;
+
+ TemplateDeclaration overnext; // next overloaded TemplateDeclaration
+ TemplateDeclaration overroot; // first in overnext list
+ FuncDeclaration funcroot; // first function in unified overload list
+
+ Dsymbol onemember; // if !=null then one member of this template
+
+ bool literal; // this template declaration is a literal
+ bool ismixin; // this is a mixin template declaration
+ bool isstatic; // this is static template declaration
+ bool isTrivialAliasSeq; /// matches pattern `template AliasSeq(T...) { alias AliasSeq = T; }`
+ bool isTrivialAlias; /// matches pattern `template Alias(T) { alias Alias = qualifiers(T); }`
+ bool deprecated_; /// this template declaration is deprecated
+ Visibility visibility;
+ int inuse; /// for recursive expansion detection
+
+ // threaded list of previous instantiation attempts on stack
+ TemplatePrevious* previous;
+
+ private Expression lastConstraint; /// the constraint after the last failed evaluation
+ private Array!Expression lastConstraintNegs; /// its negative parts
+ private Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint`
+
+ extern (D) this(const ref Loc loc, Identifier ident, TemplateParameters* parameters, Expression constraint, Dsymbols* decldefs, bool ismixin = false, bool literal = false)
+ {
+ super(loc, ident);
+ static if (LOG)
+ {
+ printf("TemplateDeclaration(this = %p, id = '%s')\n", this, ident.toChars());
+ }
+ version (none)
+ {
+ if (parameters)
+ for (int i = 0; i < parameters.dim; i++)
+ {
+ TemplateParameter tp = (*parameters)[i];
+ //printf("\tparameter[%d] = %p\n", i, tp);
+ TemplateTypeParameter ttp = tp.isTemplateTypeParameter();
+ if (ttp)
+ {
+ printf("\tparameter[%d] = %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : "");
+ }
+ }
+ }
+ this.parameters = parameters;
+ this.origParameters = parameters;
+ this.constraint = constraint;
+ this.members = decldefs;
+ this.literal = literal;
+ this.ismixin = ismixin;
+ this.isstatic = true;
+ this.visibility = Visibility(Visibility.Kind.undefined);
+
+ // Compute in advance for Ddoc's use
+ // https://issues.dlang.org/show_bug.cgi?id=11153: ident could be NULL if parsing fails.
+ if (!members || !ident)
+ return;
+
+ Dsymbol s;
+ if (!Dsymbol.oneMembers(members, &s, ident) || !s)
+ return;
+
+ onemember = s;
+ s.parent = this;
+
+ /* Set isTrivialAliasSeq if this fits the pattern:
+ * template AliasSeq(T...) { alias AliasSeq = T; }
+ * or set isTrivialAlias if this fits the pattern:
+ * template Alias(T) { alias Alias = qualifiers(T); }
+ */
+ if (!(parameters && parameters.length == 1))
+ return;
+
+ auto ad = s.isAliasDeclaration();
+ if (!ad || !ad.type)
+ return;
+
+ auto ti = ad.type.isTypeIdentifier();
+
+ if (!ti || ti.idents.length != 0)
+ return;
+
+ if (auto ttp = (*parameters)[0].isTemplateTupleParameter())
+ {
+ if (ti.ident is ttp.ident &&
+ ti.mod == 0)
+ {
+ //printf("found isTrivialAliasSeq %s %s\n", s.toChars(), ad.type.toChars());
+ isTrivialAliasSeq = true;
+ }
+ }
+ else if (auto ttp = (*parameters)[0].isTemplateTypeParameter())
+ {
+ if (ti.ident is ttp.ident)
+ {
+ //printf("found isTrivialAlias %s %s\n", s.toChars(), ad.type.toChars());
+ isTrivialAlias = true;
+ }
+ }
+ }
+
+ override TemplateDeclaration syntaxCopy(Dsymbol)
+ {
+ //printf("TemplateDeclaration.syntaxCopy()\n");
+ TemplateParameters* p = null;
+ if (parameters)
+ {
+ p = new TemplateParameters(parameters.dim);
+ foreach (i, ref param; *p)
+ param = (*parameters)[i].syntaxCopy();
+ }
+ return new TemplateDeclaration(loc, ident, p, constraint ? constraint.syntaxCopy() : null, Dsymbol.arraySyntaxCopy(members), ismixin, literal);
+ }
+
+ /**********************************
+ * Overload existing TemplateDeclaration 'this' with the new one 's'.
+ * Return true if successful; i.e. no conflict.
+ */
+ override bool overloadInsert(Dsymbol s)
+ {
+ static if (LOG)
+ {
+ printf("TemplateDeclaration.overloadInsert('%s')\n", s.toChars());
+ }
+ FuncDeclaration fd = s.isFuncDeclaration();
+ if (fd)
+ {
+ if (funcroot)
+ return funcroot.overloadInsert(fd);
+ funcroot = fd;
+ return funcroot.overloadInsert(this);
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=15795
+ // if candidate is an alias and its sema is not run then
+ // insertion can fail because the thing it alias is not known
+ if (AliasDeclaration ad = s.isAliasDeclaration())
+ {
+ if (s._scope)
+ aliasSemantic(ad, s._scope);
+ if (ad.aliassym && ad.aliassym is this)
+ return false;
+ }
+ TemplateDeclaration td = s.toAlias().isTemplateDeclaration();
+ if (!td)
+ return false;
+
+ TemplateDeclaration pthis = this;
+ TemplateDeclaration* ptd;
+ for (ptd = &pthis; *ptd; ptd = &(*ptd).overnext)
+ {
+ }
+
+ td.overroot = this;
+ *ptd = td;
+ static if (LOG)
+ {
+ printf("\ttrue: no conflict\n");
+ }
+ return true;
+ }
+
+ override bool hasStaticCtorOrDtor()
+ {
+ return false; // don't scan uninstantiated templates
+ }
+
+ override const(char)* kind() const
+ {
+ return (onemember && onemember.isAggregateDeclaration()) ? onemember.kind() : "template";
+ }
+
+ override const(char)* toChars() const
+ {
+ return toCharsMaybeConstraints(true);
+ }
+
+ /****************************
+ * Similar to `toChars`, but does not print the template constraints
+ */
+ const(char)* toCharsNoConstraints() const
+ {
+ return toCharsMaybeConstraints(false);
+ }
+
+ const(char)* toCharsMaybeConstraints(bool includeConstraints) const
+ {
+ if (literal)
+ return Dsymbol.toChars();
+
+ OutBuffer buf;
+ HdrGenState hgs;
+
+ buf.writestring(ident.toString());
+ buf.writeByte('(');
+ foreach (i, const tp; *parameters)
+ {
+ if (i)
+ buf.writestring(", ");
+ .toCBuffer(tp, &buf, &hgs);
+ }
+ buf.writeByte(')');
+
+ if (onemember)
+ {
+ const FuncDeclaration fd = onemember.isFuncDeclaration();
+ if (fd && fd.type)
+ {
+ TypeFunction tf = cast(TypeFunction)fd.type;
+ buf.writestring(parametersTypeToChars(tf.parameterList));
+ }
+ }
+
+ if (includeConstraints &&
+ constraint)
+ {
+ buf.writestring(" if (");
+ .toCBuffer(constraint, &buf, &hgs);
+ buf.writeByte(')');
+ }
+
+ return buf.extractChars();
+ }
+
+ override Visibility visible() pure nothrow @nogc @safe
+ {
+ return visibility;
+ }
+
+ /****************************
+ * Check to see if constraint is satisfied.
+ */
+ extern (D) bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd)
+ {
+ /* Detect recursive attempts to instantiate this template declaration,
+ * https://issues.dlang.org/show_bug.cgi?id=4072
+ * void foo(T)(T x) if (is(typeof(foo(x)))) { }
+ * static assert(!is(typeof(foo(7))));
+ * Recursive attempts are regarded as a constraint failure.
+ */
+ /* There's a chicken-and-egg problem here. We don't know yet if this template
+ * instantiation will be a local one (enclosing is set), and we won't know until
+ * after selecting the correct template. Thus, function we're nesting inside
+ * is not on the sc scope chain, and this can cause errors in FuncDeclaration.getLevel().
+ * Workaround the problem by setting a flag to relax the checking on frame errors.
+ */
+
+ for (TemplatePrevious* p = previous; p; p = p.prev)
+ {
+ if (!arrayObjectMatch(p.dedargs, dedargs))
+ continue;
+ //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
+ /* It must be a subscope of p.sc, other scope chains are not recursive
+ * instantiations.
+ * the chain of enclosing scopes is broken by paramscope (its enclosing
+ * scope is _scope, but paramscope.callsc is the instantiating scope). So
+ * it's good enough to check the chain of callsc
+ */
+ for (Scope* scx = paramscope.callsc; scx; scx = scx.callsc)
+ {
+ // The first scx might be identical for nested eponymeous templates, e.g.
+ // template foo() { void foo()() {...} }
+ if (scx == p.sc && scx !is paramscope.callsc)
+ return false;
+ }
+ /* BUG: should also check for ref param differences
+ */
+ }
+
+ TemplatePrevious pr;
+ pr.prev = previous;
+ pr.sc = paramscope.callsc;
+ pr.dedargs = dedargs;
+ previous = &pr; // add this to threaded list
+
+ Scope* scx = paramscope.push(ti);
+ scx.parent = ti;
+ scx.tinst = null;
+ scx.minst = null;
+ // Set SCOPE.constraint before declaring function parameters for the static condition
+ // (previously, this was immediately before calling evalStaticCondition), so the
+ // semantic pass knows not to issue deprecation warnings for these throw-away decls.
+ // https://issues.dlang.org/show_bug.cgi?id=21831
+ scx.flags |= SCOPE.constraint;
+
+ assert(!ti.symtab);
+ if (fd)
+ {
+ /* Declare all the function parameters as variables and add them to the scope
+ * Making parameters is similar to FuncDeclaration.semantic3
+ */
+ auto tf = fd.type.isTypeFunction();
+
+ scx.parent = fd;
+
+ Parameters* fparameters = tf.parameterList.parameters;
+ const nfparams = tf.parameterList.length;
+ foreach (i, fparam; tf.parameterList)
+ {
+ fparam.storageClass &= (STC.IOR | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor);
+ fparam.storageClass |= STC.parameter;
+ if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nfparams)
+ {
+ fparam.storageClass |= STC.variadic;
+ /* Don't need to set STC.scope_ because this will only
+ * be evaluated at compile time
+ */
+ }
+ }
+ foreach (fparam; *fparameters)
+ {
+ if (!fparam.ident)
+ continue;
+ // don't add it, if it has no name
+ auto v = new VarDeclaration(loc, fparam.type, fparam.ident, null);
+ fparam.storageClass |= STC.parameter;
+ v.storage_class = fparam.storageClass;
+ v.dsymbolSemantic(scx);
+ if (!ti.symtab)
+ ti.symtab = new DsymbolTable();
+ if (!scx.insert(v))
+ error("parameter `%s.%s` is already defined", toChars(), v.toChars());
+ else
+ v.parent = fd;
+ }
+ if (isstatic)
+ fd.storage_class |= STC.static_;
+ fd.declareThis(scx);
+ }
+
+ lastConstraint = constraint.syntaxCopy();
+ lastConstraintTiargs = ti.tiargs;
+ lastConstraintNegs.setDim(0);
+
+ import dmd.staticcond;
+
+ assert(ti.inst is null);
+ ti.inst = ti; // temporary instantiation to enable genIdent()
+ bool errors;
+ const bool result = evalStaticCondition(scx, constraint, lastConstraint, errors, &lastConstraintNegs);
+ if (result || errors)
+ {
+ lastConstraint = null;
+ lastConstraintTiargs = null;
+ lastConstraintNegs.setDim(0);
+ }
+ ti.inst = null;
+ ti.symtab = null;
+ scx = scx.pop();
+ previous = pr.prev; // unlink from threaded list
+ if (errors)
+ return false;
+ return result;
+ }
+
+ /****************************
+ * Destructively get the error message from the last constraint evaluation
+ * Params:
+ * tip = tip to show after printing all overloads
+ */
+ const(char)* getConstraintEvalError(ref const(char)* tip)
+ {
+ import dmd.staticcond;
+
+ // there will be a full tree view in verbose mode, and more compact list in the usual
+ const full = global.params.verbose;
+ uint count;
+ const msg = visualizeStaticCondition(constraint, lastConstraint, lastConstraintNegs[], full, count);
+ scope (exit)
+ {
+ lastConstraint = null;
+ lastConstraintTiargs = null;
+ lastConstraintNegs.setDim(0);
+ }
+ if (!msg)
+ return null;
+
+ OutBuffer buf;
+
+ assert(parameters && lastConstraintTiargs);
+ if (parameters.length > 0)
+ {
+ formatParamsWithTiargs(*lastConstraintTiargs, buf);
+ buf.writenl();
+ }
+ if (!full)
+ {
+ // choosing singular/plural
+ const s = (count == 1) ?
+ " must satisfy the following constraint:" :
+ " must satisfy one of the following constraints:";
+ buf.writestring(s);
+ buf.writenl();
+ // the constraints
+ buf.writeByte('`');
+ buf.writestring(msg);
+ buf.writeByte('`');
+ }
+ else
+ {
+ buf.writestring(" whose parameters have the following constraints:");
+ buf.writenl();
+ const sep = " `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`";
+ buf.writestring(sep);
+ buf.writenl();
+ // the constraints
+ buf.writeByte('`');
+ buf.writestring(msg);
+ buf.writeByte('`');
+ buf.writestring(sep);
+ tip = "not satisfied constraints are marked with `>`";
+ }
+ return buf.extractChars();
+ }
+
+ private void formatParamsWithTiargs(ref Objects tiargs, ref OutBuffer buf)
+ {
+ buf.writestring(" with `");
+
+ // write usual arguments line-by-line
+ // skips trailing default ones - they are not present in `tiargs`
+ const bool variadic = isVariadic() !is null;
+ const end = cast(int)parameters.length - (variadic ? 1 : 0);
+ uint i;
+ for (; i < tiargs.length && i < end; i++)
+ {
+ if (i > 0)
+ {
+ buf.writeByte(',');
+ buf.writenl();
+ buf.writestring(" ");
+ }
+ buf.write((*parameters)[i]);
+ buf.writestring(" = ");
+ buf.write(tiargs[i]);
+ }
+ // write remaining variadic arguments on the last line
+ if (variadic)
+ {
+ if (i > 0)
+ {
+ buf.writeByte(',');
+ buf.writenl();
+ buf.writestring(" ");
+ }
+ buf.write((*parameters)[end]);
+ buf.writestring(" = ");
+ buf.writeByte('(');
+ if (cast(int)tiargs.length - end > 0)
+ {
+ buf.write(tiargs[end]);
+ foreach (j; parameters.length .. tiargs.length)
+ {
+ buf.writestring(", ");
+ buf.write(tiargs[j]);
+ }
+ }
+ buf.writeByte(')');
+ }
+ buf.writeByte('`');
+ }
+
+ /******************************
+ * Create a scope for the parameters of the TemplateInstance
+ * `ti` in the parent scope sc from the ScopeDsymbol paramsym.
+ *
+ * If paramsym is null a new ScopeDsymbol is used in place of
+ * paramsym.
+ * Params:
+ * ti = the TemplateInstance whose parameters to generate the scope for.
+ * sc = the parent scope of ti
+ * Returns:
+ * a scope for the parameters of ti
+ */
+ Scope* scopeForTemplateParameters(TemplateInstance ti, Scope* sc)
+ {
+ ScopeDsymbol paramsym = new ScopeDsymbol();
+ paramsym.parent = _scope.parent;
+ Scope* paramscope = _scope.push(paramsym);
+ paramscope.tinst = ti;
+ paramscope.minst = sc.minst;
+ paramscope.callsc = sc;
+ paramscope.stc = 0;
+ return paramscope;
+ }
+
+ /***************************************
+ * Given that ti is an instance of this TemplateDeclaration,
+ * deduce the types of the parameters to this, and store
+ * those deduced types in dedtypes[].
+ * Input:
+ * flag 1: don't do semantic() because of dummy types
+ * 2: don't change types in matchArg()
+ * Output:
+ * dedtypes deduced arguments
+ * Return match level.
+ */
+ extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, Expressions* fargs, int flag)
+ {
+ enum LOGM = 0;
+ static if (LOGM)
+ {
+ printf("\n+TemplateDeclaration.matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti.toChars(), flag);
+ }
+ version (none)
+ {
+ printf("dedtypes.dim = %d, parameters.dim = %d\n", dedtypes.dim, parameters.dim);
+ if (ti.tiargs.dim)
+ printf("ti.tiargs.dim = %d, [0] = %p\n", ti.tiargs.dim, (*ti.tiargs)[0]);
+ }
+ MATCH nomatch()
+ {
+ static if (LOGM)
+ {
+ printf(" no match\n");
+ }
+ return MATCH.nomatch;
+ }
+ MATCH m;
+ size_t dedtypes_dim = dedtypes.dim;
+
+ dedtypes.zero();
+
+ if (errors)
+ return MATCH.nomatch;
+
+ size_t parameters_dim = parameters.dim;
+ int variadic = isVariadic() !is null;
+
+ // If more arguments than parameters, no match
+ if (ti.tiargs.dim > parameters_dim && !variadic)
+ {
+ static if (LOGM)
+ {
+ printf(" no match: more arguments than parameters\n");
+ }
+ return MATCH.nomatch;
+ }
+
+ assert(dedtypes_dim == parameters_dim);
+ assert(dedtypes_dim >= ti.tiargs.dim || variadic);
+
+ assert(_scope);
+
+ // Set up scope for template parameters
+ Scope* paramscope = scopeForTemplateParameters(ti,sc);
+
+ // Attempt type deduction
+ m = MATCH.exact;
+ for (size_t i = 0; i < dedtypes_dim; i++)
+ {
+ MATCH m2;
+ TemplateParameter tp = (*parameters)[i];
+ Declaration sparam;
+
+ //printf("\targument [%d]\n", i);
+ static if (LOGM)
+ {
+ //printf("\targument [%d] is %s\n", i, oarg ? oarg.toChars() : "null");
+ TemplateTypeParameter ttp = tp.isTemplateTypeParameter();
+ if (ttp)
+ printf("\tparameter[%d] is %s : %s\n", i, tp.ident.toChars(), ttp.specType ? ttp.specType.toChars() : "");
+ }
+
+ inuse++;
+ m2 = tp.matchArg(ti.loc, paramscope, ti.tiargs, i, parameters, dedtypes, &sparam);
+ inuse--;
+ //printf("\tm2 = %d\n", m2);
+ if (m2 == MATCH.nomatch)
+ {
+ version (none)
+ {
+ printf("\tmatchArg() for parameter %i failed\n", i);
+ }
+ return nomatch();
+ }
+
+ if (m2 < m)
+ m = m2;
+
+ if (!flag)
+ sparam.dsymbolSemantic(paramscope);
+ if (!paramscope.insert(sparam)) // TODO: This check can make more early
+ {
+ // in TemplateDeclaration.semantic, and
+ // then we don't need to make sparam if flags == 0
+ return nomatch();
+ }
+ }
+
+ if (!flag)
+ {
+ /* Any parameter left without a type gets the type of
+ * its corresponding arg
+ */
+ foreach (i, ref dedtype; *dedtypes)
+ {
+ if (!dedtype)
+ {
+ assert(i < ti.tiargs.dim);
+ dedtype = cast(Type)(*ti.tiargs)[i];
+ }
+ }
+ }
+
+ if (m > MATCH.nomatch && constraint && !flag)
+ {
+ if (ti.hasNestedArgs(ti.tiargs, this.isstatic)) // TODO: should gag error
+ ti.parent = ti.enclosing;
+ else
+ ti.parent = this.parent;
+
+ // Similar to doHeaderInstantiation
+ FuncDeclaration fd = onemember ? onemember.isFuncDeclaration() : null;
+ if (fd)
+ {
+ TypeFunction tf = fd.type.isTypeFunction().syntaxCopy();
+
+ fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
+ fd.parent = ti;
+ fd.inferRetType = true;
+
+ // Shouldn't run semantic on default arguments and return type.
+ foreach (ref param; *tf.parameterList.parameters)
+ param.defaultArg = null;
+
+ tf.next = null;
+ tf.incomplete = true;
+
+ // Resolve parameter types and 'auto ref's.
+ tf.fargs = fargs;
+ uint olderrors = global.startGagging();
+ fd.type = tf.typeSemantic(loc, paramscope);
+ global.endGagging(olderrors);
+ if (fd.type.ty != Tfunction)
+ return nomatch();
+ fd.originalType = fd.type; // for mangling
+ }
+
+ // TODO: dedtypes => ti.tiargs ?
+ if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd))
+ return nomatch();
+ }
+
+ static if (LOGM)
+ {
+ // Print out the results
+ printf("--------------------------\n");
+ printf("template %s\n", toChars());
+ printf("instance %s\n", ti.toChars());
+ if (m > MATCH.nomatch)
+ {
+ for (size_t i = 0; i < dedtypes_dim; i++)
+ {
+ TemplateParameter tp = (*parameters)[i];
+ RootObject oarg;
+ printf(" [%d]", i);
+ if (i < ti.tiargs.dim)
+ oarg = (*ti.tiargs)[i];
+ else
+ oarg = null;
+ tp.print(oarg, (*dedtypes)[i]);
+ }
+ }
+ else
+ return nomatch();
+ }
+ static if (LOGM)
+ {
+ printf(" match = %d\n", m);
+ }
+
+ paramscope.pop();
+ static if (LOGM)
+ {
+ printf("-TemplateDeclaration.matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m);
+ }
+ return m;
+ }
+
+ /********************************************
+ * Determine partial specialization order of 'this' vs td2.
+ * Returns:
+ * match this is at least as specialized as td2
+ * 0 td2 is more specialized than this
+ */
+ MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, Expressions* fargs)
+ {
+ enum LOG_LEASTAS = 0;
+ static if (LOG_LEASTAS)
+ {
+ printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars());
+ }
+
+ /* This works by taking the template parameters to this template
+ * declaration and feeding them to td2 as if it were a template
+ * instance.
+ * If it works, then this template is at least as specialized
+ * as td2.
+ */
+
+ // Set type arguments to dummy template instance to be types
+ // generated from the parameters to this template declaration
+ auto tiargs = new Objects();
+ tiargs.reserve(parameters.dim);
+ foreach (tp; *parameters)
+ {
+ if (tp.dependent)
+ break;
+ RootObject p = tp.dummyArg();
+ if (!p) //TemplateTupleParameter
+ break;
+
+ tiargs.push(p);
+ }
+ scope TemplateInstance ti = new TemplateInstance(Loc.initial, ident, tiargs); // create dummy template instance
+
+ // Temporary Array to hold deduced types
+ Objects dedtypes = Objects(td2.parameters.dim);
+
+ // Attempt a type deduction
+ MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, fargs, 1);
+ if (m > MATCH.nomatch)
+ {
+ /* A non-variadic template is more specialized than a
+ * variadic one.
+ */
+ TemplateTupleParameter tp = isVariadic();
+ if (tp && !tp.dependent && !td2.isVariadic())
+ goto L1;
+
+ static if (LOG_LEASTAS)
+ {
+ printf(" matches %d, so is least as specialized\n", m);
+ }
+ return m;
+ }
+ L1:
+ static if (LOG_LEASTAS)
+ {
+ printf(" doesn't match, so is not as specialized\n");
+ }
+ return MATCH.nomatch;
+ }
+
+ /*************************************************
+ * Match function arguments against a specific template function.
+ * Input:
+ * ti
+ * sc instantiation scope
+ * fd
+ * tthis 'this' argument if !NULL
+ * fargs arguments to function
+ * Output:
+ * fd Partially instantiated function declaration
+ * ti.tdtypes Expression/Type deduced template arguments
+ * Returns:
+ * match pair of initial and inferred template arguments
+ */
+ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, Expressions* fargs)
+ {
+ size_t nfparams;
+ size_t nfargs;
+ size_t ntargs; // array size of tiargs
+ size_t fptupindex = IDX_NOTFOUND;
+ MATCH match = MATCH.exact;
+ MATCH matchTiargs = MATCH.exact;
+ ParameterList fparameters; // function parameter list
+ VarArg fvarargs; // function varargs
+ uint wildmatch = 0;
+ size_t inferStart = 0;
+
+ Loc instLoc = ti.loc;
+ Objects* tiargs = ti.tiargs;
+ auto dedargs = new Objects();
+ Objects* dedtypes = &ti.tdtypes; // for T:T*, the dedargs is the T*, dedtypes is the T
+
+ version (none)
+ {
+ printf("\nTemplateDeclaration.deduceFunctionTemplateMatch() %s\n", toChars());
+ for (size_t i = 0; i < (fargs ? fargs.dim : 0); i++)
+ {
+ Expression e = (*fargs)[i];
+ printf("\tfarg[%d] is %s, type is %s\n", i, e.toChars(), e.type.toChars());
+ }
+ printf("fd = %s\n", fd.toChars());
+ printf("fd.type = %s\n", fd.type.toChars());
+ if (tthis)
+ printf("tthis = %s\n", tthis.toChars());
+ }
+
+ assert(_scope);
+
+ dedargs.setDim(parameters.dim);
+ dedargs.zero();
+
+ dedtypes.setDim(parameters.dim);
+ dedtypes.zero();
+
+ if (errors || fd.errors)
+ return MATCHpair(MATCH.nomatch, MATCH.nomatch);
+
+ // Set up scope for parameters
+ Scope* paramscope = scopeForTemplateParameters(ti,sc);
+
+ MATCHpair nomatch()
+ {
+ paramscope.pop();
+ //printf("\tnomatch\n");
+ return MATCHpair(MATCH.nomatch, MATCH.nomatch);
+ }
+
+ MATCHpair matcherror()
+ {
+ // todo: for the future improvement
+ paramscope.pop();
+ //printf("\terror\n");
+ return MATCHpair(MATCH.nomatch, MATCH.nomatch);
+ }
+ // Mark the parameter scope as deprecated if the templated
+ // function is deprecated (since paramscope.enclosing is the
+ // calling scope already)
+ paramscope.stc |= fd.storage_class & STC.deprecated_;
+
+ TemplateTupleParameter tp = isVariadic();
+ Tuple declaredTuple = null;
+
+ version (none)
+ {
+ for (size_t i = 0; i < dedargs.dim; i++)
+ {
+ printf("\tdedarg[%d] = ", i);
+ RootObject oarg = (*dedargs)[i];
+ if (oarg)
+ printf("%s", oarg.toChars());
+ printf("\n");
+ }
+ }
+
+ ntargs = 0;
+ if (tiargs)
+ {
+ // Set initial template arguments
+ ntargs = tiargs.dim;
+ size_t n = parameters.dim;
+ if (tp)
+ n--;
+ if (ntargs > n)
+ {
+ if (!tp)
+ return nomatch();
+
+ /* The extra initial template arguments
+ * now form the tuple argument.
+ */
+ auto t = new Tuple(ntargs - n);
+ assert(parameters.dim);
+ (*dedargs)[parameters.dim - 1] = t;
+
+ for (size_t i = 0; i < t.objects.dim; i++)
+ {
+ t.objects[i] = (*tiargs)[n + i];
+ }
+ declareParameter(paramscope, tp, t);
+ declaredTuple = t;
+ }
+ else
+ n = ntargs;
+
+ memcpy(dedargs.tdata(), tiargs.tdata(), n * (*dedargs.tdata()).sizeof);
+
+ for (size_t i = 0; i < n; i++)
+ {
+ assert(i < parameters.dim);
+ Declaration sparam = null;
+ MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam);
+ //printf("\tdeduceType m = %d\n", m);
+ if (m == MATCH.nomatch)
+ return nomatch();
+ if (m < matchTiargs)
+ matchTiargs = m;
+
+ sparam.dsymbolSemantic(paramscope);
+ if (!paramscope.insert(sparam))
+ return nomatch();
+ }
+ if (n < parameters.dim && !declaredTuple)
+ {
+ inferStart = n;
+ }
+ else
+ inferStart = parameters.dim;
+ //printf("tiargs matchTiargs = %d\n", matchTiargs);
+ }
+ version (none)
+ {
+ for (size_t i = 0; i < dedargs.dim; i++)
+ {
+ printf("\tdedarg[%d] = ", i);
+ RootObject oarg = (*dedargs)[i];
+ if (oarg)
+ printf("%s", oarg.toChars());
+ printf("\n");
+ }
+ }
+
+ fparameters = fd.getParameterList();
+ nfparams = fparameters.length; // number of function parameters
+ nfargs = fargs ? fargs.dim : 0; // number of function arguments
+
+ /* Check for match of function arguments with variadic template
+ * parameter, such as:
+ *
+ * void foo(T, A...)(T t, A a);
+ * void main() { foo(1,2,3); }
+ */
+ if (tp) // if variadic
+ {
+ // TemplateTupleParameter always makes most lesser matching.
+ matchTiargs = MATCH.convert;
+
+ if (nfparams == 0 && nfargs != 0) // if no function parameters
+ {
+ if (!declaredTuple)
+ {
+ auto t = new Tuple();
+ //printf("t = %p\n", t);
+ (*dedargs)[parameters.dim - 1] = t;
+ declareParameter(paramscope, tp, t);
+ declaredTuple = t;
+ }
+ }
+ else
+ {
+ /* Figure out which of the function parameters matches
+ * the tuple template parameter. Do this by matching
+ * type identifiers.
+ * Set the index of this function parameter to fptupindex.
+ */
+ for (fptupindex = 0; fptupindex < nfparams; fptupindex++)
+ {
+ auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ?
+ if (fparam.type.ty != Tident)
+ continue;
+ TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
+ if (!tp.ident.equals(tid.ident) || tid.idents.dim)
+ continue;
+
+ if (fparameters.varargs != VarArg.none) // variadic function doesn't
+ return nomatch(); // go with variadic template
+
+ goto L1;
+ }
+ fptupindex = IDX_NOTFOUND;
+ L1:
+ }
+ }
+
+ if (toParent().isModule() || (_scope.stc & STC.static_))
+ tthis = null;
+ if (tthis)
+ {
+ bool hasttp = false;
+
+ // Match 'tthis' to any TemplateThisParameter's
+ foreach (param; *parameters)
+ {
+ if (auto ttp = param.isTemplateThisParameter())
+ {
+ hasttp = true;
+
+ Type t = new TypeIdentifier(Loc.initial, ttp.ident);
+ MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes);
+ if (m == MATCH.nomatch)
+ return nomatch();
+ if (m < match)
+ match = m; // pick worst match
+ }
+ }
+
+ // Match attributes of tthis against attributes of fd
+ if (fd.type && !fd.isCtorDeclaration())
+ {
+ StorageClass stc = _scope.stc | fd.storage_class2;
+ // Propagate parent storage class, https://issues.dlang.org/show_bug.cgi?id=5504
+ Dsymbol p = parent;
+ while (p.isTemplateDeclaration() || p.isTemplateInstance())
+ p = p.parent;
+ AggregateDeclaration ad = p.isAggregateDeclaration();
+ if (ad)
+ stc |= ad.storage_class;
+
+ ubyte mod = fd.type.mod;
+ if (stc & STC.immutable_)
+ mod = MODFlags.immutable_;
+ else
+ {
+ if (stc & (STC.shared_ | STC.synchronized_))
+ mod |= MODFlags.shared_;
+ if (stc & STC.const_)
+ mod |= MODFlags.const_;
+ if (stc & STC.wild)
+ mod |= MODFlags.wild;
+ }
+
+ ubyte thismod = tthis.mod;
+ if (hasttp)
+ mod = MODmerge(thismod, mod);
+ MATCH m = MODmethodConv(thismod, mod);
+ if (m == MATCH.nomatch)
+ return nomatch();
+ if (m < match)
+ match = m;
+ }
+ }
+
+ // Loop through the function parameters
+ {
+ //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.dim : 0);
+ //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL);
+ size_t argi = 0;
+ size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs
+ for (size_t parami = 0; parami < nfparams; parami++)
+ {
+ Parameter fparam = fparameters[parami];
+
+ // Apply function parameter storage classes to parameter types
+ Type prmtype = fparam.type.addStorageClass(fparam.storageClass);
+
+ Expression farg;
+
+ /* See function parameters which wound up
+ * as part of a template tuple parameter.
+ */
+ if (fptupindex != IDX_NOTFOUND && parami == fptupindex)
+ {
+ assert(prmtype.ty == Tident);
+ TypeIdentifier tid = cast(TypeIdentifier)prmtype;
+ if (!declaredTuple)
+ {
+ /* The types of the function arguments
+ * now form the tuple argument.
+ */
+ declaredTuple = new Tuple();
+ (*dedargs)[parameters.dim - 1] = declaredTuple;
+
+ /* Count function parameters with no defaults following a tuple parameter.
+ * void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double)
+ */
+ size_t rem = 0;
+ for (size_t j = parami + 1; j < nfparams; j++)
+ {
+ Parameter p = fparameters[j];
+ if (p.defaultArg)
+ {
+ break;
+ }
+ if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.dim]))
+ {
+ Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope);
+ rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.dim : 1;
+ }
+ else
+ {
+ ++rem;
+ }
+ }
+
+ if (nfargs2 - argi < rem)
+ return nomatch();
+ declaredTuple.objects.setDim(nfargs2 - argi - rem);
+ for (size_t i = 0; i < declaredTuple.objects.dim; i++)
+ {
+ farg = (*fargs)[argi + i];
+
+ // Check invalid arguments to detect errors early.
+ if (farg.op == TOK.error || farg.type.ty == Terror)
+ return nomatch();
+
+ if (!(fparam.storageClass & STC.lazy_) && farg.type.ty == Tvoid)
+ return nomatch();
+
+ Type tt;
+ MATCH m;
+ if (ubyte wm = deduceWildHelper(farg.type, &tt, tid))
+ {
+ wildmatch |= wm;
+ m = MATCH.constant;
+ }
+ else
+ {
+ m = deduceTypeHelper(farg.type, &tt, tid);
+ }
+ if (m == MATCH.nomatch)
+ return nomatch();
+ if (m < match)
+ match = m;
+
+ /* Remove top const for dynamic array types and pointer types
+ */
+ if ((tt.ty == Tarray || tt.ty == Tpointer) && !tt.isMutable() && (!(fparam.storageClass & STC.ref_) || (fparam.storageClass & STC.auto_) && !farg.isLvalue()))
+ {
+ tt = tt.mutableOf();
+ }
+ declaredTuple.objects[i] = tt;
+ }
+ declareParameter(paramscope, tp, declaredTuple);
+ }
+ else
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=6810
+ // If declared tuple is not a type tuple,
+ // it cannot be function parameter types.
+ for (size_t i = 0; i < declaredTuple.objects.dim; i++)
+ {
+ if (!isType(declaredTuple.objects[i]))
+ return nomatch();
+ }
+ }
+ assert(declaredTuple);
+ argi += declaredTuple.objects.dim;
+ continue;
+ }
+
+ // If parameter type doesn't depend on inferred template parameters,
+ // semantic it to get actual type.
+ if (!reliesOnTemplateParameters(prmtype, (*parameters)[inferStart .. parameters.dim]))
+ {
+ // should copy prmtype to avoid affecting semantic result
+ prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope);
+
+ if (prmtype.ty == Ttuple)
+ {
+ TypeTuple tt = cast(TypeTuple)prmtype;
+ size_t tt_dim = tt.arguments.dim;
+ for (size_t j = 0; j < tt_dim; j++, ++argi)
+ {
+ Parameter p = (*tt.arguments)[j];
+ if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe &&
+ parami + 1 == nfparams && argi < nfargs)
+ {
+ prmtype = p.type;
+ goto Lvarargs;
+ }
+ if (argi >= nfargs)
+ {
+ if (p.defaultArg)
+ continue;
+
+ // https://issues.dlang.org/show_bug.cgi?id=19888
+ if (fparam.defaultArg)
+ break;
+
+ return nomatch();
+ }
+ farg = (*fargs)[argi];
+ if (!farg.implicitConvTo(p.type))
+ return nomatch();
+ }
+ continue;
+ }
+ }
+
+ if (argi >= nfargs) // if not enough arguments
+ {
+ if (!fparam.defaultArg)
+ goto Lvarargs;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=2803
+ * Before the starting of type deduction from the function
+ * default arguments, set the already deduced parameters into paramscope.
+ * It's necessary to avoid breaking existing acceptable code. Cases:
+ *
+ * 1. Already deduced template parameters can appear in fparam.defaultArg:
+ * auto foo(A, B)(A a, B b = A.stringof);
+ * foo(1);
+ * // at fparam == 'B b = A.string', A is equivalent with the deduced type 'int'
+ *
+ * 2. If prmtype depends on default-specified template parameter, the
+ * default type should be preferred.
+ * auto foo(N = size_t, R)(R r, N start = 0)
+ * foo([1,2,3]);
+ * // at fparam `N start = 0`, N should be 'size_t' before
+ * // the deduction result from fparam.defaultArg.
+ */
+ if (argi == nfargs)
+ {
+ foreach (ref dedtype; *dedtypes)
+ {
+ Type at = isType(dedtype);
+ if (at && at.ty == Tnone)
+ {
+ TypeDeduced xt = cast(TypeDeduced)at;
+ dedtype = xt.tded; // 'unbox'
+ }
+ }
+ for (size_t i = ntargs; i < dedargs.dim; i++)
+ {
+ TemplateParameter tparam = (*parameters)[i];
+
+ RootObject oarg = (*dedargs)[i];
+ RootObject oded = (*dedtypes)[i];
+ if (oarg)
+ continue;
+
+ if (oded)
+ {
+ if (tparam.specialization() || !tparam.isTemplateTypeParameter())
+ {
+ /* The specialization can work as long as afterwards
+ * the oded == oarg
+ */
+ (*dedargs)[i] = oded;
+ MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
+ //printf("m2 = %d\n", m2);
+ if (m2 == MATCH.nomatch)
+ return nomatch();
+ if (m2 < matchTiargs)
+ matchTiargs = m2; // pick worst match
+ if (!(*dedtypes)[i].equals(oded))
+ error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars());
+ }
+ else
+ {
+ if (MATCH.convert < matchTiargs)
+ matchTiargs = MATCH.convert;
+ }
+ (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
+ }
+ else
+ {
+ inuse++;
+ oded = tparam.defaultArg(instLoc, paramscope);
+ inuse--;
+ if (oded)
+ (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
+ }
+ }
+ }
+ nfargs2 = argi + 1;
+
+ /* If prmtype does not depend on any template parameters:
+ *
+ * auto foo(T)(T v, double x = 0);
+ * foo("str");
+ * // at fparam == 'double x = 0'
+ *
+ * or, if all template parameters in the prmtype are already deduced:
+ *
+ * auto foo(R)(R range, ElementType!R sum = 0);
+ * foo([1,2,3]);
+ * // at fparam == 'ElementType!R sum = 0'
+ *
+ * Deducing prmtype from fparam.defaultArg is not necessary.
+ */
+ if (prmtype.deco || prmtype.syntaxCopy().trySemantic(loc, paramscope))
+ {
+ ++argi;
+ continue;
+ }
+
+ // Deduce prmtype from the defaultArg.
+ farg = fparam.defaultArg.syntaxCopy();
+ farg = farg.expressionSemantic(paramscope);
+ farg = resolveProperties(paramscope, farg);
+ }
+ else
+ {
+ farg = (*fargs)[argi];
+ }
+ {
+ // Check invalid arguments to detect errors early.
+ if (farg.op == TOK.error || farg.type.ty == Terror)
+ return nomatch();
+
+ Type att = null;
+ Lretry:
+ version (none)
+ {
+ printf("\tfarg.type = %s\n", farg.type.toChars());
+ printf("\tfparam.type = %s\n", prmtype.toChars());
+ }
+ Type argtype = farg.type;
+
+ if (!(fparam.storageClass & STC.lazy_) && argtype.ty == Tvoid && farg.op != TOK.function_)
+ return nomatch();
+
+ // https://issues.dlang.org/show_bug.cgi?id=12876
+ // Optimize argument to allow CT-known length matching
+ farg = farg.optimize(WANTvalue, fparam.isReference());
+ //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars());
+
+ RootObject oarg = farg;
+ if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue()))
+ {
+ /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
+ */
+ Type taai;
+ if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
+ {
+ if (farg.op == TOK.string_)
+ {
+ StringExp se = cast(StringExp)farg;
+ argtype = se.type.nextOf().sarrayOf(se.len);
+ }
+ else if (farg.op == TOK.arrayLiteral)
+ {
+ ArrayLiteralExp ae = cast(ArrayLiteralExp)farg;
+ argtype = ae.type.nextOf().sarrayOf(ae.elements.dim);
+ }
+ else if (farg.op == TOK.slice)
+ {
+ SliceExp se = cast(SliceExp)farg;
+ if (Type tsa = toStaticArrayType(se))
+ argtype = tsa;
+ }
+ }
+
+ oarg = argtype;
+ }
+ else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && (cast(TypeIdentifier)prmtype).idents.dim == 0)
+ {
+ /* The farg passing to the prmtype always make a copy. Therefore,
+ * we can shrink the set of the deduced type arguments for prmtype
+ * by adjusting top-qualifier of the argtype.
+ *
+ * prmtype argtype ta
+ * T <- const(E)[] const(E)[]
+ * T <- const(E[]) const(E)[]
+ * qualifier(T) <- const(E)[] const(E[])
+ * qualifier(T) <- const(E[]) const(E[])
+ */
+ Type ta = argtype.castMod(prmtype.mod ? argtype.nextOf().mod : 0);
+ if (ta != argtype)
+ {
+ Expression ea = farg.copy();
+ ea.type = ta;
+ oarg = ea;
+ }
+ }
+
+ if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < nfargs)
+ goto Lvarargs;
+
+ uint wm = 0;
+ MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &wm, inferStart);
+ //printf("\tL%d deduceType m = %d, wm = x%x, wildmatch = x%x\n", __LINE__, m, wm, wildmatch);
+ wildmatch |= wm;
+
+ /* If no match, see if the argument can be matched by using
+ * implicit conversions.
+ */
+ if (m == MATCH.nomatch && prmtype.deco)
+ m = farg.implicitConvTo(prmtype);
+
+ if (m == MATCH.nomatch)
+ {
+ AggregateDeclaration ad = isAggregate(farg.type);
+ if (ad && ad.aliasthis && !isRecursiveAliasThis(att, argtype))
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=12537
+ // The isRecursiveAliasThis() call above
+
+ /* If a semantic error occurs while doing alias this,
+ * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295),
+ * just regard it as not a match.
+ */
+ if (auto e = resolveAliasThis(sc, farg, true))
+ {
+ farg = e;
+ goto Lretry;
+ }
+ }
+ }
+
+ if (m > MATCH.nomatch && (fparam.storageClass & (STC.ref_ | STC.auto_)) == STC.ref_)
+ {
+ if (!farg.isLvalue())
+ {
+ if ((farg.op == TOK.string_ || farg.op == TOK.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray))
+ {
+ // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
+ }
+ else if (global.params.rvalueRefParam)
+ {
+ // Allow implicit conversion to ref
+ }
+ else
+ return nomatch();
+ }
+ }
+ if (m > MATCH.nomatch && (fparam.storageClass & STC.out_))
+ {
+ if (!farg.isLvalue())
+ return nomatch();
+ if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916
+ return nomatch();
+ }
+ if (m == MATCH.nomatch && (fparam.storageClass & STC.lazy_) && prmtype.ty == Tvoid && farg.type.ty != Tvoid)
+ m = MATCH.convert;
+ if (m != MATCH.nomatch)
+ {
+ if (m < match)
+ match = m; // pick worst match
+ argi++;
+ continue;
+ }
+ }
+
+ Lvarargs:
+ /* The following code for variadic arguments closely
+ * matches TypeFunction.callMatch()
+ */
+ if (!(fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams))
+ return nomatch();
+
+ /* Check for match with function parameter T...
+ */
+ Type tb = prmtype.toBasetype();
+ switch (tb.ty)
+ {
+ // 6764 fix - TypeAArray may be TypeSArray have not yet run semantic().
+ case Tsarray:
+ case Taarray:
+ {
+ // Perhaps we can do better with this, see TypeFunction.callMatch()
+ if (tb.ty == Tsarray)
+ {
+ TypeSArray tsa = cast(TypeSArray)tb;
+ dinteger_t sz = tsa.dim.toInteger();
+ if (sz != nfargs - argi)
+ return nomatch();
+ }
+ else if (tb.ty == Taarray)
+ {
+ TypeAArray taa = cast(TypeAArray)tb;
+ Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t);
+
+ size_t i = templateParameterLookup(taa.index, parameters);
+ if (i == IDX_NOTFOUND)
+ {
+ Expression e;
+ Type t;
+ Dsymbol s;
+ Scope *sco;
+
+ uint errors = global.startGagging();
+ /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
+ * The parameter isn't part of the template
+ * ones, let's try to find it in the
+ * instantiation scope 'sc' and the one
+ * belonging to the template itself. */
+ sco = sc;
+ taa.index.resolve(instLoc, sco, e, t, s);
+ if (!e)
+ {
+ sco = paramscope;
+ taa.index.resolve(instLoc, sco, e, t, s);
+ }
+ global.endGagging(errors);
+
+ if (!e)
+ return nomatch();
+
+ e = e.ctfeInterpret();
+ e = e.implicitCastTo(sco, Type.tsize_t);
+ e = e.optimize(WANTvalue);
+ if (!dim.equals(e))
+ return nomatch();
+ }
+ else
+ {
+ // This code matches code in TypeInstance.deduceType()
+ TemplateParameter tprm = (*parameters)[i];
+ TemplateValueParameter tvp = tprm.isTemplateValueParameter();
+ if (!tvp)
+ return nomatch();
+ Expression e = cast(Expression)(*dedtypes)[i];
+ if (e)
+ {
+ if (!dim.equals(e))
+ return nomatch();
+ }
+ else
+ {
+ Type vt = tvp.valType.typeSemantic(Loc.initial, sc);
+ MATCH m = dim.implicitConvTo(vt);
+ if (m == MATCH.nomatch)
+ return nomatch();
+ (*dedtypes)[i] = dim;
+ }
+ }
+ }
+ goto case Tarray;
+ }
+ case Tarray:
+ {
+ TypeArray ta = cast(TypeArray)tb;
+ Type tret = fparam.isLazyArray();
+ for (; argi < nfargs; argi++)
+ {
+ Expression arg = (*fargs)[argi];
+ assert(arg);
+
+ MATCH m;
+ /* If lazy array of delegates,
+ * convert arg(s) to delegate(s)
+ */
+ if (tret)
+ {
+ if (ta.next.equals(arg.type))
+ {
+ m = MATCH.exact;
+ }
+ else
+ {
+ m = arg.implicitConvTo(tret);
+ if (m == MATCH.nomatch)
+ {
+ if (tret.toBasetype().ty == Tvoid)
+ m = MATCH.convert;
+ }
+ }
+ }
+ else
+ {
+ uint wm = 0;
+ m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart);
+ wildmatch |= wm;
+ }
+ if (m == MATCH.nomatch)
+ return nomatch();
+ if (m < match)
+ match = m;
+ }
+ goto Lmatch;
+ }
+ case Tclass:
+ case Tident:
+ goto Lmatch;
+
+ default:
+ return nomatch();
+ }
+ assert(0);
+ }
+ //printf(". argi = %d, nfargs = %d, nfargs2 = %d\n", argi, nfargs, nfargs2);
+ if (argi != nfargs2 && fparameters.varargs == VarArg.none)
+ return nomatch();
+ }
+
+ Lmatch:
+ foreach (ref dedtype; *dedtypes)
+ {
+ Type at = isType(dedtype);
+ if (at)
+ {
+ if (at.ty == Tnone)
+ {
+ TypeDeduced xt = cast(TypeDeduced)at;
+ at = xt.tded; // 'unbox'
+ }
+ dedtype = at.merge2();
+ }
+ }
+ for (size_t i = ntargs; i < dedargs.dim; i++)
+ {
+ TemplateParameter tparam = (*parameters)[i];
+ //printf("tparam[%d] = %s\n", i, tparam.ident.toChars());
+
+ /* For T:T*, the dedargs is the T*, dedtypes is the T
+ * But for function templates, we really need them to match
+ */
+ RootObject oarg = (*dedargs)[i];
+ RootObject oded = (*dedtypes)[i];
+ //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded);
+ //if (oarg) printf("oarg: %s\n", oarg.toChars());
+ //if (oded) printf("oded: %s\n", oded.toChars());
+ if (oarg)
+ continue;
+
+ if (oded)
+ {
+ if (tparam.specialization() || !tparam.isTemplateTypeParameter())
+ {
+ /* The specialization can work as long as afterwards
+ * the oded == oarg
+ */
+ (*dedargs)[i] = oded;
+ MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
+ //printf("m2 = %d\n", m2);
+ if (m2 == MATCH.nomatch)
+ return nomatch();
+ if (m2 < matchTiargs)
+ matchTiargs = m2; // pick worst match
+ if (!(*dedtypes)[i].equals(oded))
+ error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars());
+ }
+ else
+ {
+ // Discussion: https://issues.dlang.org/show_bug.cgi?id=16484
+ if (MATCH.convert < matchTiargs)
+ matchTiargs = MATCH.convert;
+ }
+ }
+ else
+ {
+ inuse++;
+ oded = tparam.defaultArg(instLoc, paramscope);
+ inuse--;
+ if (!oded)
+ {
+ // if tuple parameter and
+ // tuple parameter was not in function parameter list and
+ // we're one or more arguments short (i.e. no tuple argument)
+ if (tparam == tp &&
+ fptupindex == IDX_NOTFOUND &&
+ ntargs <= dedargs.dim - 1)
+ {
+ // make tuple argument an empty tuple
+ oded = new Tuple();
+ }
+ else
+ return nomatch();
+ }
+ if (isError(oded))
+ return matcherror();
+ ntargs++;
+
+ /* At the template parameter T, the picked default template argument
+ * X!int should be matched to T in order to deduce dependent
+ * template parameter A.
+ * auto foo(T : X!A = X!int, A...)() { ... }
+ * foo(); // T <-- X!int, A <-- (int)
+ */
+ if (tparam.specialization())
+ {
+ (*dedargs)[i] = oded;
+ MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
+ //printf("m2 = %d\n", m2);
+ if (m2 == MATCH.nomatch)
+ return nomatch();
+ if (m2 < matchTiargs)
+ matchTiargs = m2; // pick worst match
+ if (!(*dedtypes)[i].equals(oded))
+ error("specialization not allowed for deduced parameter `%s`", tparam.ident.toChars());
+ }
+ }
+ oded = declareParameter(paramscope, tparam, oded);
+ (*dedargs)[i] = oded;
+ }
+
+ /* https://issues.dlang.org/show_bug.cgi?id=7469
+ * As same as the code for 7469 in findBestMatch,
+ * expand a Tuple in dedargs to normalize template arguments.
+ */
+ if (auto d = dedargs.dim)
+ {
+ if (auto va = isTuple((*dedargs)[d - 1]))
+ {
+ dedargs.setDim(d - 1);
+ dedargs.insert(d - 1, &va.objects);
+ }
+ }
+ ti.tiargs = dedargs; // update to the normalized template arguments.
+
+ // Partially instantiate function for constraint and fd.leastAsSpecialized()
+ {
+ assert(paramscope.scopesym);
+ Scope* sc2 = _scope;
+ sc2 = sc2.push(paramscope.scopesym);
+ sc2 = sc2.push(ti);
+ sc2.parent = ti;
+ sc2.tinst = ti;
+ sc2.minst = sc.minst;
+ sc2.stc |= fd.storage_class & STC.deprecated_;
+
+ fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs);
+
+ sc2 = sc2.pop();
+ sc2 = sc2.pop();
+
+ if (!fd)
+ return nomatch();
+ }
+
+ if (constraint)
+ {
+ if (!evaluateConstraint(ti, sc, paramscope, dedargs, fd))
+ return nomatch();
+ }
+
+ version (none)
+ {
+ for (size_t i = 0; i < dedargs.dim; i++)
+ {
+ RootObject o = (*dedargs)[i];
+ printf("\tdedargs[%d] = %d, %s\n", i, o.dyncast(), o.toChars());
+ }
+ }
+
+ paramscope.pop();
+ //printf("\tmatch %d\n", match);
+ return MATCHpair(matchTiargs, match);
+ }
+
+ /**************************************************
+ * Declare template parameter tp with value o, and install it in the scope sc.
+ */
+ RootObject declareParameter(Scope* sc, TemplateParameter tp, RootObject o)
+ {
+ //printf("TemplateDeclaration.declareParameter('%s', o = %p)\n", tp.ident.toChars(), o);
+ Type ta = isType(o);
+ Expression ea = isExpression(o);
+ Dsymbol sa = isDsymbol(o);
+ Tuple va = isTuple(o);
+
+ Declaration d;
+ VarDeclaration v = null;
+
+ if (ea && ea.op == TOK.type)
+ ta = ea.type;
+ else if (ea && ea.op == TOK.scope_)
+ sa = (cast(ScopeExp)ea).sds;
+ else if (ea && (ea.op == TOK.this_ || ea.op == TOK.super_))
+ sa = (cast(ThisExp)ea).var;
+ else if (ea && ea.op == TOK.function_)
+ {
+ if ((cast(FuncExp)ea).td)
+ sa = (cast(FuncExp)ea).td;
+ else
+ sa = (cast(FuncExp)ea).fd;
+ }
+
+ if (ta)
+ {
+ //printf("type %s\n", ta.toChars());
+ auto ad = new AliasDeclaration(Loc.initial, tp.ident, ta);
+ ad.storage_class |= STC.templateparameter;
+ d = ad;
+ }
+ else if (sa)
+ {
+ //printf("Alias %s %s;\n", sa.ident.toChars(), tp.ident.toChars());
+ auto ad = new AliasDeclaration(Loc.initial, tp.ident, sa);
+ ad.storage_class |= STC.templateparameter;
+ d = ad;
+ }
+ else if (ea)
+ {
+ // tdtypes.data[i] always matches ea here
+ Initializer _init = new ExpInitializer(loc, ea);
+ TemplateValueParameter tvp = tp.isTemplateValueParameter();
+ Type t = tvp ? tvp.valType : null;
+ v = new VarDeclaration(loc, t, tp.ident, _init);
+ v.storage_class = STC.manifest | STC.templateparameter;
+ d = v;
+ }
+ else if (va)
+ {
+ //printf("\ttuple\n");
+ d = new TupleDeclaration(loc, tp.ident, &va.objects);
+ }
+ else
+ {
+ assert(0);
+ }
+ d.storage_class |= STC.templateparameter;
+
+ if (ta)
+ {
+ Type t = ta;
+ // consistent with Type.checkDeprecated()
+ while (t.ty != Tenum)
+ {
+ if (!t.nextOf())
+ break;
+ t = (cast(TypeNext)t).next;
+ }
+ if (Dsymbol s = t.toDsymbol(sc))
+ {
+ if (s.isDeprecated())
+ d.storage_class |= STC.deprecated_;
+ }
+ }
+ else if (sa)
+ {
+ if (sa.isDeprecated())
+ d.storage_class |= STC.deprecated_;
+ }
+
+ if (!sc.insert(d))
+ error("declaration `%s` is already defined", tp.ident.toChars());
+ d.dsymbolSemantic(sc);
+ /* So the caller's o gets updated with the result of semantic() being run on o
+ */
+ if (v)
+ o = v._init.initializerToExpression();
+ return o;
+ }
+
+ /*************************************************
+ * Limited function template instantiation for using fd.leastAsSpecialized()
+ */
+ extern (D) FuncDeclaration doHeaderInstantiation(TemplateInstance ti, Scope* sc2, FuncDeclaration fd, Type tthis, Expressions* fargs)
+ {
+ assert(fd);
+ version (none)
+ {
+ printf("doHeaderInstantiation this = %s\n", toChars());
+ }
+
+ // function body and contracts are not need
+ if (fd.isCtorDeclaration())
+ fd = new CtorDeclaration(fd.loc, fd.endloc, fd.storage_class, fd.type.syntaxCopy());
+ else
+ fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, fd.type.syntaxCopy());
+ fd.parent = ti;
+
+ assert(fd.type.ty == Tfunction);
+ auto tf = fd.type.isTypeFunction();
+ tf.fargs = fargs;
+
+ if (tthis)
+ {
+ // Match 'tthis' to any TemplateThisParameter's
+ bool hasttp = false;
+ foreach (tp; *parameters)
+ {
+ TemplateThisParameter ttp = tp.isTemplateThisParameter();
+ if (ttp)
+ hasttp = true;
+ }
+ if (hasttp)
+ {
+ tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod));
+ assert(!tf.deco);
+ }
+ }
+
+ Scope* scx = sc2.push();
+
+ // Shouldn't run semantic on default arguments and return type.
+ foreach (ref params; *tf.parameterList.parameters)
+ params.defaultArg = null;
+ tf.incomplete = true;
+
+ if (fd.isCtorDeclaration())
+ {
+ // For constructors, emitting return type is necessary for
+ // isReturnIsolated() in functionResolve.
+ tf.isctor = true;
+
+ Dsymbol parent = toParentDecl();
+ Type tret;
+ AggregateDeclaration ad = parent.isAggregateDeclaration();
+ if (!ad || parent.isUnionDeclaration())
+ {
+ tret = Type.tvoid;
+ }
+ else
+ {
+ tret = ad.handleType();
+ assert(tret);
+ tret = tret.addStorageClass(fd.storage_class | scx.stc);
+ tret = tret.addMod(tf.mod);
+ }
+ tf.next = tret;
+ if (ad && ad.isStructDeclaration())
+ tf.isref = 1;
+ //printf("tf = %s\n", tf.toChars());
+ }
+ else
+ tf.next = null;
+ fd.type = tf;
+ fd.type = fd.type.addSTC(scx.stc);
+ fd.type = fd.type.typeSemantic(fd.loc, scx);
+ scx = scx.pop();
+
+ if (fd.type.ty != Tfunction)
+ return null;
+
+ fd.originalType = fd.type; // for mangling
+ //printf("\t[%s] fd.type = %s, mod = %x, ", loc.toChars(), fd.type.toChars(), fd.type.mod);
+ //printf("fd.needThis() = %d\n", fd.needThis());
+
+ return fd;
+ }
+
+ debug (FindExistingInstance)
+ {
+ __gshared uint nFound, nNotFound, nAdded, nRemoved;
+
+ shared static ~this()
+ {
+ printf("debug (FindExistingInstance) nFound %u, nNotFound: %u, nAdded: %u, nRemoved: %u\n",
+ nFound, nNotFound, nAdded, nRemoved);
+ }
+ }
+
+ /****************************************************
+ * Given a new instance tithis of this TemplateDeclaration,
+ * see if there already exists an instance.
+ * If so, return that existing instance.
+ */
+ extern (D) TemplateInstance findExistingInstance(TemplateInstance tithis, Expressions* fargs)
+ {
+ //printf("findExistingInstance() %s\n", tithis.toChars());
+ tithis.fargs = fargs;
+ auto tibox = TemplateInstanceBox(tithis);
+ auto p = tibox in instances;
+ debug (FindExistingInstance) ++(p ? nFound : nNotFound);
+ //if (p) printf("\tfound %p\n", *p); else printf("\tnot found\n");
+ return p ? *p : null;
+ }
+
+ /********************************************
+ * Add instance ti to TemplateDeclaration's table of instances.
+ * Return a handle we can use to later remove it if it fails instantiation.
+ */
+ extern (D) TemplateInstance addInstance(TemplateInstance ti)
+ {
+ //printf("addInstance() %p %s\n", instances, ti.toChars());
+ auto tibox = TemplateInstanceBox(ti);
+ instances[tibox] = ti;
+ debug (FindExistingInstance) ++nAdded;
+ return ti;
+ }
+
+ /*******************************************
+ * Remove TemplateInstance from table of instances.
+ * Input:
+ * handle returned by addInstance()
+ */
+ extern (D) void removeInstance(TemplateInstance ti)
+ {
+ //printf("removeInstance() %s\n", ti.toChars());
+ auto tibox = TemplateInstanceBox(ti);
+ debug (FindExistingInstance) ++nRemoved;
+ instances.remove(tibox);
+ }
+
+ override inout(TemplateDeclaration) isTemplateDeclaration() inout
+ {
+ return this;
+ }
+
+ /**
+ * Check if the last template parameter is a tuple one,
+ * and returns it if so, else returns `null`.
+ *
+ * Returns:
+ * The last template parameter if it's a `TemplateTupleParameter`
+ */
+ TemplateTupleParameter isVariadic()
+ {
+ size_t dim = parameters.dim;
+ if (dim == 0)
+ return null;
+ return (*parameters)[dim - 1].isTemplateTupleParameter();
+ }
+
+ extern(C++) override bool isDeprecated() const
+ {
+ return this.deprecated_;
+ }
+
+ /***********************************
+ * We can overload templates.
+ */
+ override bool isOverloadable() const
+ {
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+extern (C++) final class TypeDeduced : Type
+{
+ Type tded;
+ Expressions argexps; // corresponding expressions
+ Types tparams; // tparams[i].mod
+
+ extern (D) this(Type tt, Expression e, Type tparam)
+ {
+ super(Tnone);
+ tded = tt;
+ argexps.push(e);
+ tparams.push(tparam);
+ }
+
+ void update(Expression e, Type tparam)
+ {
+ argexps.push(e);
+ tparams.push(tparam);
+ }
+
+ void update(Type tt, Expression e, Type tparam)
+ {
+ tded = tt;
+ argexps.push(e);
+ tparams.push(tparam);
+ }
+
+ MATCH matchAll(Type tt)
+ {
+ MATCH match = MATCH.exact;
+ foreach (j, e; argexps)
+ {
+ assert(e);
+ if (e == emptyArrayElement)
+ continue;
+
+ Type t = tt.addMod(tparams[j].mod).substWildTo(MODFlags.const_);
+
+ MATCH m = e.implicitConvTo(t);
+ if (match > m)
+ match = m;
+ if (match == MATCH.nomatch)
+ break;
+ }
+ return match;
+ }
+}
+
+
+/*************************************************
+ * Given function arguments, figure out which template function
+ * to expand, and return matching result.
+ * Params:
+ * m = matching result
+ * dstart = the root of overloaded function templates
+ * loc = instantiation location
+ * sc = instantiation scope
+ * tiargs = initial list of template arguments
+ * tthis = if !NULL, the 'this' pointer argument
+ * fargs = arguments to function
+ * pMessage = address to store error message, or null
+ */
+void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs,
+ Type tthis, Expressions* fargs, const(char)** pMessage = null)
+{
+ Expression[] fargs_ = fargs.peekSlice();
+ version (none)
+ {
+ printf("functionResolve() dstart = %s\n", dstart.toChars());
+ printf(" tiargs:\n");
+ if (tiargs)
+ {
+ for (size_t i = 0; i < tiargs.dim; i++)
+ {
+ RootObject arg = (*tiargs)[i];
+ printf("\t%s\n", arg.toChars());
+ }
+ }
+ printf(" fargs:\n");
+ for (size_t i = 0; i < (fargs ? fargs.dim : 0); i++)
+ {
+ Expression arg = (*fargs)[i];
+ printf("\t%s %s\n", arg.type.toChars(), arg.toChars());
+ //printf("\tty = %d\n", arg.type.ty);
+ }
+ //printf("stc = %llx\n", dstart.scope.stc);
+ //printf("match:t/f = %d/%d\n", ta_last, m.last);
+ }
+
+ // results
+ int property = 0; // 0: uninitialized
+ // 1: seen @property
+ // 2: not @property
+ size_t ov_index = 0;
+ TemplateDeclaration td_best;
+ TemplateInstance ti_best;
+ MATCH ta_last = m.last != MATCH.nomatch ? MATCH.exact : MATCH.nomatch;
+ Type tthis_best;
+
+ int applyFunction(FuncDeclaration fd)
+ {
+ // skip duplicates
+ if (fd == m.lastf)
+ return 0;
+ // explicitly specified tiargs never match to non template function
+ if (tiargs && tiargs.dim > 0)
+ return 0;
+
+ // constructors need a valid scope in order to detect semantic errors
+ if (!fd.isCtorDeclaration &&
+ fd.semanticRun < PASS.semanticdone)
+ {
+ Ungag ungag = fd.ungagSpeculative();
+ fd.dsymbolSemantic(null);
+ }
+ if (fd.semanticRun < PASS.semanticdone)
+ {
+ .error(loc, "forward reference to template `%s`", fd.toChars());
+ return 1;
+ }
+ //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars());
+ auto tf = cast(TypeFunction)fd.type;
+
+ int prop = tf.isproperty ? 1 : 2;
+ if (property == 0)
+ property = prop;
+ else if (property != prop)
+ error(fd.loc, "cannot overload both property and non-property functions");
+
+ /* For constructors, qualifier check will be opposite direction.
+ * Qualified constructor always makes qualified object, then will be checked
+ * that it is implicitly convertible to tthis.
+ */
+ Type tthis_fd = fd.needThis() ? tthis : null;
+ bool isCtorCall = tthis_fd && fd.isCtorDeclaration();
+ if (isCtorCall)
+ {
+ //printf("%s tf.mod = x%x tthis_fd.mod = x%x %d\n", tf.toChars(),
+ // tf.mod, tthis_fd.mod, fd.isReturnIsolated());
+ if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
+ tf.isWild() && tf.isShared() == tthis_fd.isShared() ||
+ fd.isReturnIsolated())
+ {
+ /* && tf.isShared() == tthis_fd.isShared()*/
+ // Uniquely constructed object can ignore shared qualifier.
+ // TODO: Is this appropriate?
+ tthis_fd = null;
+ }
+ else
+ return 0; // MATCH.nomatch
+ }
+ /* Fix Issue 17970:
+ If a struct is declared as shared the dtor is automatically
+ considered to be shared, but when the struct is instantiated
+ the instance is no longer considered to be shared when the
+ function call matching is done. The fix makes it so that if a
+ struct declaration is shared, when the destructor is called,
+ the instantiated struct is also considered shared.
+ */
+ if (auto dt = fd.isDtorDeclaration())
+ {
+ auto dtmod = dt.type.toTypeFunction();
+ auto shared_dtor = dtmod.mod & MODFlags.shared_;
+ auto shared_this = tthis_fd !is null ?
+ tthis_fd.mod & MODFlags.shared_ : 0;
+ if (shared_dtor && !shared_this)
+ tthis_fd = dtmod;
+ else if (shared_this && !shared_dtor && tthis_fd !is null)
+ tf.mod = tthis_fd.mod;
+ }
+ MATCH mfa = tf.callMatch(tthis_fd, fargs_, 0, pMessage, sc);
+ //printf("test1: mfa = %d\n", mfa);
+ if (mfa == MATCH.nomatch)
+ return 0;
+
+ if (mfa > m.last) goto LfIsBetter;
+ if (mfa < m.last) goto LlastIsBetter;
+
+ /* See if one of the matches overrides the other.
+ */
+ assert(m.lastf);
+ if (m.lastf.overrides(fd)) goto LlastIsBetter;
+ if (fd.overrides(m.lastf)) goto LfIsBetter;
+
+ /* Try to disambiguate using template-style partial ordering rules.
+ * In essence, if f() and g() are ambiguous, if f() can call g(),
+ * but g() cannot call f(), then pick f().
+ * This is because f() is "more specialized."
+ */
+ {
+ MATCH c1 = fd.leastAsSpecialized(m.lastf);
+ MATCH c2 = m.lastf.leastAsSpecialized(fd);
+ //printf("c1 = %d, c2 = %d\n", c1, c2);
+ if (c1 > c2) goto LfIsBetter;
+ if (c1 < c2) goto LlastIsBetter;
+ }
+
+ /* The 'overrides' check above does covariant checking only
+ * for virtual member functions. It should do it for all functions,
+ * but in order to not risk breaking code we put it after
+ * the 'leastAsSpecialized' check.
+ * In the future try moving it before.
+ * I.e. a not-the-same-but-covariant match is preferred,
+ * as it is more restrictive.
+ */
+ if (!m.lastf.type.equals(fd.type))
+ {
+ //printf("cov: %d %d\n", m.lastf.type.covariant(fd.type), fd.type.covariant(m.lastf.type));
+ const lastCovariant = m.lastf.type.covariant(fd.type);
+ const firstCovariant = fd.type.covariant(m.lastf.type);
+
+ if (lastCovariant == Covariant.yes || lastCovariant == Covariant.no)
+ {
+ if (firstCovariant != Covariant.yes && firstCovariant != Covariant.no)
+ {
+ goto LlastIsBetter;
+ }
+ }
+ else if (firstCovariant == Covariant.yes || firstCovariant == Covariant.no)
+ {
+ goto LfIsBetter;
+ }
+ }
+
+ /* If the two functions are the same function, like:
+ * int foo(int);
+ * int foo(int x) { ... }
+ * then pick the one with the body.
+ *
+ * If none has a body then don't care because the same
+ * real function would be linked to the decl (e.g from object file)
+ */
+ if (tf.equals(m.lastf.type) &&
+ fd.storage_class == m.lastf.storage_class &&
+ fd.parent == m.lastf.parent &&
+ fd.visibility == m.lastf.visibility &&
+ fd.linkage == m.lastf.linkage)
+ {
+ if (fd.fbody && !m.lastf.fbody)
+ goto LfIsBetter;
+ if (!fd.fbody)
+ goto LlastIsBetter;
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=14450
+ // Prefer exact qualified constructor for the creating object type
+ if (isCtorCall && tf.mod != m.lastf.type.mod)
+ {
+ if (tthis.mod == tf.mod) goto LfIsBetter;
+ if (tthis.mod == m.lastf.type.mod) goto LlastIsBetter;
+ }
+
+ m.nextf = fd;
+ m.count++;
+ return 0;
+
+ LlastIsBetter:
+ return 0;
+
+ LfIsBetter:
+ td_best = null;
+ ti_best = null;
+ ta_last = MATCH.exact;
+ m.last = mfa;
+ m.lastf = fd;
+ tthis_best = tthis_fd;
+ ov_index = 0;
+ m.count = 1;
+ return 0;
+
+ }
+
+ int applyTemplate(TemplateDeclaration td)
+ {
+ //printf("applyTemplate()\n");
+ if (td.inuse)
+ {
+ td.error(loc, "recursive template expansion");
+ return 1;
+ }
+ if (td == td_best) // skip duplicates
+ return 0;
+
+ if (!sc)
+ sc = td._scope; // workaround for Type.aliasthisOf
+
+ if (td.semanticRun == PASS.init && td._scope)
+ {
+ // Try to fix forward reference. Ungag errors while doing so.
+ Ungag ungag = td.ungagSpeculative();
+ td.dsymbolSemantic(td._scope);
+ }
+ if (td.semanticRun == PASS.init)
+ {
+ .error(loc, "forward reference to template `%s`", td.toChars());
+ Lerror:
+ m.lastf = null;
+ m.count = 0;
+ m.last = MATCH.nomatch;
+ return 1;
+ }
+ //printf("td = %s\n", td.toChars());
+
+ auto f = td.onemember ? td.onemember.isFuncDeclaration() : null;
+ if (!f)
+ {
+ if (!tiargs)
+ tiargs = new Objects();
+ auto ti = new TemplateInstance(loc, td, tiargs);
+ Objects dedtypes = Objects(td.parameters.dim);
+ assert(td.semanticRun != PASS.init);
+ MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, fargs, 0);
+ //printf("matchWithInstance = %d\n", mta);
+ if (mta == MATCH.nomatch || mta < ta_last) // no match or less match
+ return 0;
+
+ ti.templateInstanceSemantic(sc, fargs);
+ if (!ti.inst) // if template failed to expand
+ return 0;
+
+ Dsymbol s = ti.inst.toAlias();
+ FuncDeclaration fd;
+ if (auto tdx = s.isTemplateDeclaration())
+ {
+ Objects dedtypesX; // empty tiargs
+
+ // https://issues.dlang.org/show_bug.cgi?id=11553
+ // Check for recursive instantiation of tdx.
+ for (TemplatePrevious* p = tdx.previous; p; p = p.prev)
+ {
+ if (arrayObjectMatch(p.dedargs, &dedtypesX))
+ {
+ //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
+ /* It must be a subscope of p.sc, other scope chains are not recursive
+ * instantiations.
+ */
+ for (Scope* scx = sc; scx; scx = scx.enclosing)
+ {
+ if (scx == p.sc)
+ {
+ error(loc, "recursive template expansion while looking for `%s.%s`", ti.toChars(), tdx.toChars());
+ goto Lerror;
+ }
+ }
+ }
+ /* BUG: should also check for ref param differences
+ */
+ }
+
+ TemplatePrevious pr;
+ pr.prev = tdx.previous;
+ pr.sc = sc;
+ pr.dedargs = &dedtypesX;
+ tdx.previous = &pr; // add this to threaded list
+
+ fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, FuncResolveFlag.quiet);
+
+ tdx.previous = pr.prev; // unlink from threaded list
+ }
+ else if (s.isFuncDeclaration())
+ {
+ fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, FuncResolveFlag.quiet);
+ }
+ else
+ goto Lerror;
+
+ if (!fd)
+ return 0;
+
+ if (fd.type.ty != Tfunction)
+ {
+ m.lastf = fd; // to propagate "error match"
+ m.count = 1;
+ m.last = MATCH.nomatch;
+ return 1;
+ }
+
+ Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null;
+
+ auto tf = cast(TypeFunction)fd.type;
+ MATCH mfa = tf.callMatch(tthis_fd, fargs_, 0, null, sc);
+ if (mfa < m.last)
+ return 0;
+
+ if (mta < ta_last) goto Ltd_best2;
+ if (mta > ta_last) goto Ltd2;
+
+ if (mfa < m.last) goto Ltd_best2;
+ if (mfa > m.last) goto Ltd2;
+
+ // td_best and td are ambiguous
+ //printf("Lambig2\n");
+ m.nextf = fd;
+ m.count++;
+ return 0;
+
+ Ltd_best2:
+ return 0;
+
+ Ltd2:
+ // td is the new best match
+ assert(td._scope);
+ td_best = td;
+ ti_best = null;
+ property = 0; // (backward compatibility)
+ ta_last = mta;
+ m.last = mfa;
+ m.lastf = fd;
+ tthis_best = tthis_fd;
+ ov_index = 0;
+ m.nextf = null;
+ m.count = 1;
+ return 0;
+ }
+
+ //printf("td = %s\n", td.toChars());
+ for (size_t ovi = 0; f; f = f.overnext0, ovi++)
+ {
+ if (f.type.ty != Tfunction || f.errors)
+ goto Lerror;
+
+ /* This is a 'dummy' instance to evaluate constraint properly.
+ */
+ auto ti = new TemplateInstance(loc, td, tiargs);
+ ti.parent = td.parent; // Maybe calculating valid 'enclosing' is unnecessary.
+
+ auto fd = f;
+ MATCHpair x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, fargs);
+ MATCH mta = x.mta;
+ MATCH mfa = x.mfa;
+ //printf("match:t/f = %d/%d\n", mta, mfa);
+ if (!fd || mfa == MATCH.nomatch)
+ continue;
+
+ Type tthis_fd = fd.needThis() ? tthis : null;
+
+ bool isCtorCall = tthis_fd && fd.isCtorDeclaration();
+ if (isCtorCall)
+ {
+ // Constructor call requires additional check.
+
+ auto tf = cast(TypeFunction)fd.type;
+ assert(tf.next);
+ if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
+ tf.isWild() && tf.isShared() == tthis_fd.isShared() ||
+ fd.isReturnIsolated())
+ {
+ tthis_fd = null;
+ }
+ else
+ continue; // MATCH.nomatch
+ }
+
+ if (mta < ta_last) goto Ltd_best;
+ if (mta > ta_last) goto Ltd;
+
+ if (mfa < m.last) goto Ltd_best;
+ if (mfa > m.last) goto Ltd;
+
+ if (td_best)
+ {
+ // Disambiguate by picking the most specialized TemplateDeclaration
+ MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs);
+ MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs);
+ //printf("1: c1 = %d, c2 = %d\n", c1, c2);
+ if (c1 > c2) goto Ltd;
+ if (c1 < c2) goto Ltd_best;
+ }
+ assert(fd && m.lastf);
+ {
+ // Disambiguate by tf.callMatch
+ auto tf1 = fd.type.isTypeFunction();
+ auto tf2 = m.lastf.type.isTypeFunction();
+ MATCH c1 = tf1.callMatch(tthis_fd, fargs_, 0, null, sc);
+ MATCH c2 = tf2.callMatch(tthis_best, fargs_, 0, null, sc);
+ //printf("2: c1 = %d, c2 = %d\n", c1, c2);
+ if (c1 > c2) goto Ltd;
+ if (c1 < c2) goto Ltd_best;
+ }
+ {
+ // Disambiguate by picking the most specialized FunctionDeclaration
+ MATCH c1 = fd.leastAsSpecialized(m.lastf);
+ MATCH c2 = m.lastf.leastAsSpecialized(fd);
+ //printf("3: c1 = %d, c2 = %d\n", c1, c2);
+ if (c1 > c2) goto Ltd;
+ if (c1 < c2) goto Ltd_best;
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=14450
+ // Prefer exact qualified constructor for the creating object type
+ if (isCtorCall && fd.type.mod != m.lastf.type.mod)
+ {
+ if (tthis.mod == fd.type.mod) goto Ltd;
+ if (tthis.mod == m.lastf.type.mod) goto Ltd_best;
+ }
+
+ m.nextf = fd;
+ m.count++;
+ continue;
+
+ Ltd_best: // td_best is the best match so far
+ //printf("Ltd_best\n");
+ continue;
+
+ Ltd: // td is the new best match
+ //printf("Ltd\n");
+ assert(td._scope);
+ td_best = td;
+ ti_best = ti;
+ property = 0; // (backward compatibility)
+ ta_last = mta;
+ m.last = mfa;
+ m.lastf = fd;
+ tthis_best = tthis_fd;
+ ov_index = ovi;
+ m.nextf = null;
+ m.count = 1;
+ continue;
+ }
+ return 0;
+ }
+
+ auto td = dstart.isTemplateDeclaration();
+ if (td && td.funcroot)
+ dstart = td.funcroot;
+ overloadApply(dstart, (Dsymbol s)
+ {
+ if (s.errors)
+ return 0;
+ if (auto fd = s.isFuncDeclaration())
+ return applyFunction(fd);
+ if (auto td = s.isTemplateDeclaration())
+ return applyTemplate(td);
+ return 0;
+ }, sc);
+
+ //printf("td_best = %p, m.lastf = %p\n", td_best, m.lastf);
+ if (td_best && ti_best && m.count == 1)
+ {
+ // Matches to template function
+ assert(td_best.onemember && td_best.onemember.isFuncDeclaration());
+ /* The best match is td_best with arguments tdargs.
+ * Now instantiate the template.
+ */
+ assert(td_best._scope);
+ if (!sc)
+ sc = td_best._scope; // workaround for Type.aliasthisOf
+
+ auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs);
+ ti.templateInstanceSemantic(sc, fargs);
+
+ m.lastf = ti.toAlias().isFuncDeclaration();
+ if (!m.lastf)
+ goto Lnomatch;
+ if (ti.errors)
+ {
+ Lerror:
+ m.count = 1;
+ assert(m.lastf);
+ m.last = MATCH.nomatch;
+ return;
+ }
+
+ // look forward instantiated overload function
+ // Dsymbol.oneMembers is alredy called in TemplateInstance.semantic.
+ // it has filled overnext0d
+ while (ov_index--)
+ {
+ m.lastf = m.lastf.overnext0;
+ assert(m.lastf);
+ }
+
+ tthis_best = m.lastf.needThis() && !m.lastf.isCtorDeclaration() ? tthis : null;
+
+ if (m.lastf.type.ty == Terror)
+ goto Lerror;
+ auto tf = m.lastf.type.isTypeFunction();
+ if (!tf.callMatch(tthis_best, fargs_, 0, null, sc))
+ goto Lnomatch;
+
+ /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows,
+ * a template instance can be matched while instantiating
+ * that same template. Thus, the function type can be incomplete. Complete it.
+ *
+ * https://issues.dlang.org/show_bug.cgi?id=9208
+ * For auto function, completion should be deferred to the end of
+ * its semantic3. Should not complete it in here.
+ */
+ if (tf.next && !m.lastf.inferRetType)
+ {
+ m.lastf.type = tf.typeSemantic(loc, sc);
+ }
+ }
+ else if (m.lastf)
+ {
+ // Matches to non template function,
+ // or found matches were ambiguous.
+ assert(m.count >= 1);
+ }
+ else
+ {
+ Lnomatch:
+ m.count = 0;
+ m.lastf = null;
+ m.last = MATCH.nomatch;
+ }
+}
+
+/* ======================== Type ============================================ */
+
+/****
+ * Given an identifier, figure out which TemplateParameter it is.
+ * Return IDX_NOTFOUND if not found.
+ */
+private size_t templateIdentifierLookup(Identifier id, TemplateParameters* parameters)
+{
+ for (size_t i = 0; i < parameters.dim; i++)
+ {
+ TemplateParameter tp = (*parameters)[i];
+ if (tp.ident.equals(id))
+ return i;
+ }
+ return IDX_NOTFOUND;
+}
+
+private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters)
+{
+ if (tparam.ty == Tident)
+ {
+ TypeIdentifier tident = cast(TypeIdentifier)tparam;
+ //printf("\ttident = '%s'\n", tident.toChars());
+ return templateIdentifierLookup(tident.ident, parameters);
+ }
+ return IDX_NOTFOUND;
+}
+
+private ubyte deduceWildHelper(Type t, Type* at, Type tparam)
+{
+ if ((tparam.mod & MODFlags.wild) == 0)
+ return 0;
+
+ *at = null;
+
+ auto X(T, U)(T U, U T)
+ {
+ return (U << 4) | T;
+ }
+
+ switch (X(tparam.mod, t.mod))
+ {
+ case X(MODFlags.wild, 0):
+ case X(MODFlags.wild, MODFlags.const_):
+ case X(MODFlags.wild, MODFlags.shared_):
+ case X(MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
+ case X(MODFlags.wild, MODFlags.immutable_):
+ case X(MODFlags.wildconst, 0):
+ case X(MODFlags.wildconst, MODFlags.const_):
+ case X(MODFlags.wildconst, MODFlags.shared_):
+ case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
+ case X(MODFlags.wildconst, MODFlags.immutable_):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.immutable_):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.immutable_):
+ {
+ ubyte wm = (t.mod & ~MODFlags.shared_);
+ if (wm == 0)
+ wm = MODFlags.mutable;
+ ubyte m = (t.mod & (MODFlags.const_ | MODFlags.immutable_)) | (tparam.mod & t.mod & MODFlags.shared_);
+ *at = t.unqualify(m);
+ return wm;
+ }
+ case X(MODFlags.wild, MODFlags.wild):
+ case X(MODFlags.wild, MODFlags.wildconst):
+ case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
+ case X(MODFlags.wildconst, MODFlags.wild):
+ case X(MODFlags.wildconst, MODFlags.wildconst):
+ case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
+ {
+ *at = t.unqualify(tparam.mod & t.mod);
+ return MODFlags.wild;
+ }
+ default:
+ return 0;
+ }
+}
+
+/**
+ * Returns the common type of the 2 types.
+ */
+private Type rawTypeMerge(Type t1, Type t2)
+{
+ if (t1.equals(t2))
+ return t1;
+ if (t1.equivalent(t2))
+ return t1.castMod(MODmerge(t1.mod, t2.mod));
+
+ auto t1b = t1.toBasetype();
+ auto t2b = t2.toBasetype();
+ if (t1b.equals(t2b))
+ return t1b;
+ if (t1b.equivalent(t2b))
+ return t1b.castMod(MODmerge(t1b.mod, t2b.mod));
+
+ auto ty = implicitConvCommonTy(t1b.ty, t2b.ty);
+ if (ty != Terror)
+ return Type.basic[ty];
+
+ return null;
+}
+
+private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
+{
+ // 9*9 == 81 cases
+
+ auto X(T, U)(T U, U T)
+ {
+ return (U << 4) | T;
+ }
+
+ switch (X(tparam.mod, t.mod))
+ {
+ case X(0, 0):
+ case X(0, MODFlags.const_):
+ case X(0, MODFlags.wild):
+ case X(0, MODFlags.wildconst):
+ case X(0, MODFlags.shared_):
+ case X(0, MODFlags.shared_ | MODFlags.const_):
+ case X(0, MODFlags.shared_ | MODFlags.wild):
+ case X(0, MODFlags.shared_ | MODFlags.wildconst):
+ case X(0, MODFlags.immutable_):
+ // foo(U) T => T
+ // foo(U) const(T) => const(T)
+ // foo(U) inout(T) => inout(T)
+ // foo(U) inout(const(T)) => inout(const(T))
+ // foo(U) shared(T) => shared(T)
+ // foo(U) shared(const(T)) => shared(const(T))
+ // foo(U) shared(inout(T)) => shared(inout(T))
+ // foo(U) shared(inout(const(T))) => shared(inout(const(T)))
+ // foo(U) immutable(T) => immutable(T)
+ {
+ *at = t;
+ return MATCH.exact;
+ }
+ case X(MODFlags.const_, MODFlags.const_):
+ case X(MODFlags.wild, MODFlags.wild):
+ case X(MODFlags.wildconst, MODFlags.wildconst):
+ case X(MODFlags.shared_, MODFlags.shared_):
+ case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.const_):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
+ case X(MODFlags.immutable_, MODFlags.immutable_):
+ // foo(const(U)) const(T) => T
+ // foo(inout(U)) inout(T) => T
+ // foo(inout(const(U))) inout(const(T)) => T
+ // foo(shared(U)) shared(T) => T
+ // foo(shared(const(U))) shared(const(T)) => T
+ // foo(shared(inout(U))) shared(inout(T)) => T
+ // foo(shared(inout(const(U)))) shared(inout(const(T))) => T
+ // foo(immutable(U)) immutable(T) => T
+ {
+ *at = t.mutableOf().unSharedOf();
+ return MATCH.exact;
+ }
+ case X(MODFlags.const_, MODFlags.shared_ | MODFlags.const_):
+ case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wildconst):
+ // foo(const(U)) shared(const(T)) => shared(T)
+ // foo(inout(U)) shared(inout(T)) => shared(T)
+ // foo(inout(const(U))) shared(inout(const(T))) => shared(T)
+ {
+ *at = t.mutableOf();
+ return MATCH.exact;
+ }
+ case X(MODFlags.const_, 0):
+ case X(MODFlags.const_, MODFlags.wild):
+ case X(MODFlags.const_, MODFlags.wildconst):
+ case X(MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.const_, MODFlags.shared_ | MODFlags.wildconst):
+ case X(MODFlags.const_, MODFlags.immutable_):
+ case X(MODFlags.shared_ | MODFlags.const_, MODFlags.immutable_):
+ // foo(const(U)) T => T
+ // foo(const(U)) inout(T) => T
+ // foo(const(U)) inout(const(T)) => T
+ // foo(const(U)) shared(inout(T)) => shared(T)
+ // foo(const(U)) shared(inout(const(T))) => shared(T)
+ // foo(const(U)) immutable(T) => T
+ // foo(shared(const(U))) immutable(T) => T
+ {
+ *at = t.mutableOf();
+ return MATCH.constant;
+ }
+ case X(MODFlags.const_, MODFlags.shared_):
+ // foo(const(U)) shared(T) => shared(T)
+ {
+ *at = t;
+ return MATCH.constant;
+ }
+ case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.const_):
+ case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wildconst):
+ // foo(shared(U)) shared(const(T)) => const(T)
+ // foo(shared(U)) shared(inout(T)) => inout(T)
+ // foo(shared(U)) shared(inout(const(T))) => inout(const(T))
+ {
+ *at = t.unSharedOf();
+ return MATCH.exact;
+ }
+ case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_):
+ // foo(shared(const(U))) shared(T) => T
+ {
+ *at = t.unSharedOf();
+ return MATCH.constant;
+ }
+ case X(MODFlags.wildconst, MODFlags.immutable_):
+ case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wildconst):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.immutable_):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
+ // foo(inout(const(U))) immutable(T) => T
+ // foo(shared(const(U))) shared(inout(const(T))) => T
+ // foo(shared(inout(const(U)))) immutable(T) => T
+ // foo(shared(inout(const(U)))) shared(inout(T)) => T
+ {
+ *at = t.unSharedOf().mutableOf();
+ return MATCH.constant;
+ }
+ case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
+ // foo(shared(const(U))) shared(inout(T)) => T
+ {
+ *at = t.unSharedOf().mutableOf();
+ return MATCH.constant;
+ }
+ case X(MODFlags.wild, 0):
+ case X(MODFlags.wild, MODFlags.const_):
+ case X(MODFlags.wild, MODFlags.wildconst):
+ case X(MODFlags.wild, MODFlags.immutable_):
+ case X(MODFlags.wild, MODFlags.shared_):
+ case X(MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
+ case X(MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
+ case X(MODFlags.wildconst, 0):
+ case X(MODFlags.wildconst, MODFlags.const_):
+ case X(MODFlags.wildconst, MODFlags.wild):
+ case X(MODFlags.wildconst, MODFlags.shared_):
+ case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
+ case X(MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.shared_, 0):
+ case X(MODFlags.shared_, MODFlags.const_):
+ case X(MODFlags.shared_, MODFlags.wild):
+ case X(MODFlags.shared_, MODFlags.wildconst):
+ case X(MODFlags.shared_, MODFlags.immutable_):
+ case X(MODFlags.shared_ | MODFlags.const_, 0):
+ case X(MODFlags.shared_ | MODFlags.const_, MODFlags.const_):
+ case X(MODFlags.shared_ | MODFlags.const_, MODFlags.wild):
+ case X(MODFlags.shared_ | MODFlags.const_, MODFlags.wildconst):
+ case X(MODFlags.shared_ | MODFlags.wild, 0):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.const_):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.wild):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.wildconst):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.immutable_):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.const_):
+ case X(MODFlags.shared_ | MODFlags.wild, MODFlags.shared_ | MODFlags.wildconst):
+ case X(MODFlags.shared_ | MODFlags.wildconst, 0):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.const_):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.wild):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.wildconst):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.const_):
+ case X(MODFlags.immutable_, 0):
+ case X(MODFlags.immutable_, MODFlags.const_):
+ case X(MODFlags.immutable_, MODFlags.wild):
+ case X(MODFlags.immutable_, MODFlags.wildconst):
+ case X(MODFlags.immutable_, MODFlags.shared_):
+ case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.const_):
+ case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.immutable_, MODFlags.shared_ | MODFlags.wildconst):
+ // foo(inout(U)) T => nomatch
+ // foo(inout(U)) const(T) => nomatch
+ // foo(inout(U)) inout(const(T)) => nomatch
+ // foo(inout(U)) immutable(T) => nomatch
+ // foo(inout(U)) shared(T) => nomatch
+ // foo(inout(U)) shared(const(T)) => nomatch
+ // foo(inout(U)) shared(inout(const(T))) => nomatch
+ // foo(inout(const(U))) T => nomatch
+ // foo(inout(const(U))) const(T) => nomatch
+ // foo(inout(const(U))) inout(T) => nomatch
+ // foo(inout(const(U))) shared(T) => nomatch
+ // foo(inout(const(U))) shared(const(T)) => nomatch
+ // foo(inout(const(U))) shared(inout(T)) => nomatch
+ // foo(shared(U)) T => nomatch
+ // foo(shared(U)) const(T) => nomatch
+ // foo(shared(U)) inout(T) => nomatch
+ // foo(shared(U)) inout(const(T)) => nomatch
+ // foo(shared(U)) immutable(T) => nomatch
+ // foo(shared(const(U))) T => nomatch
+ // foo(shared(const(U))) const(T) => nomatch
+ // foo(shared(const(U))) inout(T) => nomatch
+ // foo(shared(const(U))) inout(const(T)) => nomatch
+ // foo(shared(inout(U))) T => nomatch
+ // foo(shared(inout(U))) const(T) => nomatch
+ // foo(shared(inout(U))) inout(T) => nomatch
+ // foo(shared(inout(U))) inout(const(T)) => nomatch
+ // foo(shared(inout(U))) immutable(T) => nomatch
+ // foo(shared(inout(U))) shared(T) => nomatch
+ // foo(shared(inout(U))) shared(const(T)) => nomatch
+ // foo(shared(inout(U))) shared(inout(const(T))) => nomatch
+ // foo(shared(inout(const(U)))) T => nomatch
+ // foo(shared(inout(const(U)))) const(T) => nomatch
+ // foo(shared(inout(const(U)))) inout(T) => nomatch
+ // foo(shared(inout(const(U)))) inout(const(T)) => nomatch
+ // foo(shared(inout(const(U)))) shared(T) => nomatch
+ // foo(shared(inout(const(U)))) shared(const(T)) => nomatch
+ // foo(immutable(U)) T => nomatch
+ // foo(immutable(U)) const(T) => nomatch
+ // foo(immutable(U)) inout(T) => nomatch
+ // foo(immutable(U)) inout(const(T)) => nomatch
+ // foo(immutable(U)) shared(T) => nomatch
+ // foo(immutable(U)) shared(const(T)) => nomatch
+ // foo(immutable(U)) shared(inout(T)) => nomatch
+ // foo(immutable(U)) shared(inout(const(T))) => nomatch
+ return MATCH.nomatch;
+
+ default:
+ assert(0);
+ }
+}
+
+__gshared Expression emptyArrayElement = null;
+
+/* These form the heart of template argument deduction.
+ * Given 'this' being the type argument to the template instance,
+ * it is matched against the template declaration parameter specialization
+ * 'tparam' to determine the type to be used for the parameter.
+ * Example:
+ * template Foo(T:T*) // template declaration
+ * Foo!(int*) // template instantiation
+ * Input:
+ * this = int*
+ * tparam = T*
+ * parameters = [ T:T* ] // Array of TemplateParameter's
+ * Output:
+ * dedtypes = [ int ] // Array of Expression/Type's
+ */
+MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false)
+{
+ extern (C++) final class DeduceType : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ Scope* sc;
+ Type tparam;
+ TemplateParameters* parameters;
+ Objects* dedtypes;
+ uint* wm;
+ size_t inferStart;
+ bool ignoreAliasThis;
+ MATCH result;
+
+ extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart, bool ignoreAliasThis)
+ {
+ this.sc = sc;
+ this.tparam = tparam;
+ this.parameters = parameters;
+ this.dedtypes = dedtypes;
+ this.wm = wm;
+ this.inferStart = inferStart;
+ this.ignoreAliasThis = ignoreAliasThis;
+ result = MATCH.nomatch;
+ }
+
+ override void visit(Type t)
+ {
+ if (!tparam)
+ goto Lnomatch;
+
+ if (t == tparam)
+ goto Lexact;
+
+ if (tparam.ty == Tident)
+ {
+ // Determine which parameter tparam is
+ size_t i = templateParameterLookup(tparam, parameters);
+ if (i == IDX_NOTFOUND)
+ {
+ if (!sc)
+ goto Lnomatch;
+
+ /* Need a loc to go with the semantic routine.
+ */
+ Loc loc;
+ if (parameters.dim)
+ {
+ TemplateParameter tp = (*parameters)[0];
+ loc = tp.loc;
+ }
+
+ /* BUG: what if tparam is a template instance, that
+ * has as an argument another Tident?
+ */
+ tparam = tparam.typeSemantic(loc, sc);
+ assert(tparam.ty != Tident);
+ result = deduceType(t, sc, tparam, parameters, dedtypes, wm);
+ return;
+ }
+
+ TemplateParameter tp = (*parameters)[i];
+
+ TypeIdentifier tident = cast(TypeIdentifier)tparam;
+ if (tident.idents.dim > 0)
+ {
+ //printf("matching %s to %s\n", tparam.toChars(), t.toChars());
+ Dsymbol s = t.toDsymbol(sc);
+ for (size_t j = tident.idents.dim; j-- > 0;)
+ {
+ RootObject id = tident.idents[j];
+ if (id.dyncast() == DYNCAST.identifier)
+ {
+ if (!s || !s.parent)
+ goto Lnomatch;
+ Dsymbol s2 = s.parent.search(Loc.initial, cast(Identifier)id);
+ if (!s2)
+ goto Lnomatch;
+ s2 = s2.toAlias();
+ //printf("[%d] s = %s %s, s2 = %s %s\n", j, s.kind(), s.toChars(), s2.kind(), s2.toChars());
+ if (s != s2)
+ {
+ if (Type tx = s2.getType())
+ {
+ if (s != tx.toDsymbol(sc))
+ goto Lnomatch;
+ }
+ else
+ goto Lnomatch;
+ }
+ s = s.parent;
+ }
+ else
+ goto Lnomatch;
+ }
+ //printf("[e] s = %s\n", s?s.toChars():"(null)");
+ if (tp.isTemplateTypeParameter())
+ {
+ Type tt = s.getType();
+ if (!tt)
+ goto Lnomatch;
+ Type at = cast(Type)(*dedtypes)[i];
+ if (at && at.ty == Tnone)
+ at = (cast(TypeDeduced)at).tded;
+ if (!at || tt.equals(at))
+ {
+ (*dedtypes)[i] = tt;
+ goto Lexact;
+ }
+ }
+ if (tp.isTemplateAliasParameter())
+ {
+ Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i];
+ if (!s2 || s == s2)
+ {
+ (*dedtypes)[i] = s;
+ goto Lexact;
+ }
+ }
+ goto Lnomatch;
+ }
+
+ // Found the corresponding parameter tp
+ if (!tp.isTemplateTypeParameter())
+ goto Lnomatch;
+ Type at = cast(Type)(*dedtypes)[i];
+ Type tt;
+ if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0)
+ {
+ // type vs (none)
+ if (!at)
+ {
+ (*dedtypes)[i] = tt;
+ *wm |= wx;
+ result = MATCH.constant;
+ return;
+ }
+
+ // type vs expressions
+ if (at.ty == Tnone)
+ {
+ TypeDeduced xt = cast(TypeDeduced)at;
+ result = xt.matchAll(tt);
+ if (result > MATCH.nomatch)
+ {
+ (*dedtypes)[i] = tt;
+ if (result > MATCH.constant)
+ result = MATCH.constant; // limit level for inout matches
+ }
+ return;
+ }
+
+ // type vs type
+ if (tt.equals(at))
+ {
+ (*dedtypes)[i] = tt; // Prefer current type match
+ goto Lconst;
+ }
+ if (tt.implicitConvTo(at.constOf()))
+ {
+ (*dedtypes)[i] = at.constOf().mutableOf();
+ *wm |= MODFlags.const_;
+ goto Lconst;
+ }
+ if (at.implicitConvTo(tt.constOf()))
+ {
+ (*dedtypes)[i] = tt.constOf().mutableOf();
+ *wm |= MODFlags.const_;
+ goto Lconst;
+ }
+ goto Lnomatch;
+ }
+ else if (MATCH m = deduceTypeHelper(t, &tt, tparam))
+ {
+ // type vs (none)
+ if (!at)
+ {
+ (*dedtypes)[i] = tt;
+ result = m;
+ return;
+ }
+
+ // type vs expressions
+ if (at.ty == Tnone)
+ {
+ TypeDeduced xt = cast(TypeDeduced)at;
+ result = xt.matchAll(tt);
+ if (result > MATCH.nomatch)
+ {
+ (*dedtypes)[i] = tt;
+ }
+ return;
+ }
+
+ // type vs type
+ if (tt.equals(at))
+ {
+ goto Lexact;
+ }
+ if (tt.ty == Tclass && at.ty == Tclass)
+ {
+ result = tt.implicitConvTo(at);
+ return;
+ }
+ if (tt.ty == Tsarray && at.ty == Tarray && tt.nextOf().implicitConvTo(at.nextOf()) >= MATCH.constant)
+ {
+ goto Lexact;
+ }
+ }
+ goto Lnomatch;
+ }
+
+ if (tparam.ty == Ttypeof)
+ {
+ /* Need a loc to go with the semantic routine.
+ */
+ Loc loc;
+ if (parameters.dim)
+ {
+ TemplateParameter tp = (*parameters)[0];
+ loc = tp.loc;
+ }
+
+ tparam = tparam.typeSemantic(loc, sc);
+ }
+ if (t.ty != tparam.ty)
+ {
+ if (Dsymbol sym = t.toDsymbol(sc))
+ {
+ if (sym.isforwardRef() && !tparam.deco)
+ goto Lnomatch;
+ }
+
+ MATCH m = t.implicitConvTo(tparam);
+ if (m == MATCH.nomatch && !ignoreAliasThis)
+ {
+ if (t.ty == Tclass)
+ {
+ TypeClass tc = cast(TypeClass)t;
+ if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT))
+ {
+ if (auto ato = t.aliasthisOf())
+ {
+ tc.att = cast(AliasThisRec)(tc.att | AliasThisRec.tracingDT);
+ m = deduceType(ato, sc, tparam, parameters, dedtypes, wm);
+ tc.att = cast(AliasThisRec)(tc.att & ~AliasThisRec.tracingDT);
+ }
+ }
+ }
+ else if (t.ty == Tstruct)
+ {
+ TypeStruct ts = cast(TypeStruct)t;
+ if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT))
+ {
+ if (auto ato = t.aliasthisOf())
+ {
+ ts.att = cast(AliasThisRec)(ts.att | AliasThisRec.tracingDT);
+ m = deduceType(ato, sc, tparam, parameters, dedtypes, wm);
+ ts.att = cast(AliasThisRec)(ts.att & ~AliasThisRec.tracingDT);
+ }
+ }
+ }
+ }
+ result = m;
+ return;
+ }
+
+ if (t.nextOf())
+ {
+ if (tparam.deco && !tparam.hasWild())
+ {
+ result = t.implicitConvTo(tparam);
+ return;
+ }
+
+ Type tpn = tparam.nextOf();
+ if (wm && t.ty == Taarray && tparam.isWild())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=12403
+ // In IFTI, stop inout matching on transitive part of AA types.
+ tpn = tpn.substWildTo(MODFlags.mutable);
+ }
+
+ result = deduceType(t.nextOf(), sc, tpn, parameters, dedtypes, wm);
+ return;
+ }
+
+ Lexact:
+ result = MATCH.exact;
+ return;
+
+ Lnomatch:
+ result = MATCH.nomatch;
+ return;
+
+ Lconst:
+ result = MATCH.constant;
+ }
+
+ override void visit(TypeVector t)
+ {
+ if (tparam.ty == Tvector)
+ {
+ TypeVector tp = cast(TypeVector)tparam;
+ result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm);
+ return;
+ }
+ visit(cast(Type)t);
+ }
+
+ override void visit(TypeDArray t)
+ {
+ visit(cast(Type)t);
+ }
+
+ override void visit(TypeSArray t)
+ {
+ // Extra check that array dimensions must match
+ if (tparam)
+ {
+ if (tparam.ty == Tarray)
+ {
+ MATCH m = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
+ result = (m >= MATCH.constant) ? MATCH.convert : MATCH.nomatch;
+ return;
+ }
+
+ TemplateParameter tp = null;
+ Expression edim = null;
+ size_t i;
+ if (tparam.ty == Tsarray)
+ {
+ TypeSArray tsa = cast(TypeSArray)tparam;
+ if (tsa.dim.op == TOK.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter)
+ {
+ Identifier id = (cast(VarExp)tsa.dim).var.ident;
+ i = templateIdentifierLookup(id, parameters);
+ assert(i != IDX_NOTFOUND);
+ tp = (*parameters)[i];
+ }
+ else
+ edim = tsa.dim;
+ }
+ else if (tparam.ty == Taarray)
+ {
+ TypeAArray taa = cast(TypeAArray)tparam;
+ i = templateParameterLookup(taa.index, parameters);
+ if (i != IDX_NOTFOUND)
+ tp = (*parameters)[i];
+ else
+ {
+ Expression e;
+ Type tx;
+ Dsymbol s;
+ taa.index.resolve(Loc.initial, sc, e, tx, s);
+ edim = s ? getValue(s) : getValue(e);
+ }
+ }
+ if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger())
+ {
+ result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
+ return;
+ }
+ }
+ visit(cast(Type)t);
+ }
+
+ override void visit(TypeAArray t)
+ {
+ // Extra check that index type must match
+ if (tparam && tparam.ty == Taarray)
+ {
+ TypeAArray tp = cast(TypeAArray)tparam;
+ if (!deduceType(t.index, sc, tp.index, parameters, dedtypes))
+ {
+ result = MATCH.nomatch;
+ return;
+ }
+ }
+ visit(cast(Type)t);
+ }
+
+ override void visit(TypeFunction t)
+ {
+ // Extra check that function characteristics must match
+ if (!tparam)
+ return visit(cast(Type)t);
+
+ if (auto tp = tparam.isTypeFunction())
+ {
+ if (t.parameterList.varargs != tp.parameterList.varargs || t.linkage != tp.linkage)
+ {
+ result = MATCH.nomatch;
+ return;
+ }
+
+ foreach (fparam; *tp.parameterList.parameters)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=2579
+ // Apply function parameter storage classes to parameter types
+ fparam.type = fparam.type.addStorageClass(fparam.storageClass);
+ fparam.storageClass &= ~(STC.TYPECTOR | STC.in_);
+
+ // https://issues.dlang.org/show_bug.cgi?id=15243
+ // Resolve parameter type if it's not related with template parameters
+ if (!reliesOnTemplateParameters(fparam.type, (*parameters)[inferStart .. parameters.dim]))
+ {
+ auto tx = fparam.type.typeSemantic(Loc.initial, sc);
+ if (tx.ty == Terror)
+ {
+ result = MATCH.nomatch;
+ return;
+ }
+ fparam.type = tx;
+ }
+ }
+
+ size_t nfargs = t.parameterList.length;
+ size_t nfparams = tp.parameterList.length;
+
+ /* See if tuple match
+ */
+ if (nfparams > 0 && nfargs >= nfparams - 1)
+ {
+ /* See if 'A' of the template parameter matches 'A'
+ * of the type of the last function parameter.
+ */
+ Parameter fparam = tp.parameterList[nfparams - 1];
+ assert(fparam);
+ assert(fparam.type);
+ if (fparam.type.ty != Tident)
+ goto L1;
+ TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
+ if (tid.idents.dim)
+ goto L1;
+
+ /* Look through parameters to find tuple matching tid.ident
+ */
+ size_t tupi = 0;
+ for (; 1; tupi++)
+ {
+ if (tupi == parameters.dim)
+ goto L1;
+ TemplateParameter tx = (*parameters)[tupi];
+ TemplateTupleParameter tup = tx.isTemplateTupleParameter();
+ if (tup && tup.ident.equals(tid.ident))
+ break;
+ }
+
+ /* The types of the function arguments [nfparams - 1 .. nfargs]
+ * now form the tuple argument.
+ */
+ size_t tuple_dim = nfargs - (nfparams - 1);
+
+ /* See if existing tuple, and whether it matches or not
+ */
+ RootObject o = (*dedtypes)[tupi];
+ if (o)
+ {
+ // Existing deduced argument must be a tuple, and must match
+ Tuple tup = isTuple(o);
+ if (!tup || tup.objects.dim != tuple_dim)
+ {
+ result = MATCH.nomatch;
+ return;
+ }
+ for (size_t i = 0; i < tuple_dim; i++)
+ {
+ Parameter arg = t.parameterList[nfparams - 1 + i];
+ if (!arg.type.equals(tup.objects[i]))
+ {
+ result = MATCH.nomatch;
+ return;
+ }
+ }
+ }
+ else
+ {
+ // Create new tuple
+ auto tup = new Tuple(tuple_dim);
+ for (size_t i = 0; i < tuple_dim; i++)
+ {
+ Parameter arg = t.parameterList[nfparams - 1 + i];
+ tup.objects[i] = arg.type;
+ }
+ (*dedtypes)[tupi] = tup;
+ }
+ nfparams--; // don't consider the last parameter for type deduction
+ goto L2;
+ }
+
+ L1:
+ if (nfargs != nfparams)
+ {
+ result = MATCH.nomatch;
+ return;
+ }
+ L2:
+ assert(nfparams <= tp.parameterList.length);
+ foreach (i, ap; tp.parameterList)
+ {
+ if (i == nfparams)
+ break;
+
+ Parameter a = t.parameterList[i];
+
+ if (!a.isCovariant(t.isref, ap) ||
+ !deduceType(a.type, sc, ap.type, parameters, dedtypes))
+ {
+ result = MATCH.nomatch;
+ return;
+ }
+ }
+ }
+ visit(cast(Type)t);
+ }
+
+ override void visit(TypeIdentifier t)
+ {
+ // Extra check
+ if (tparam && tparam.ty == Tident)
+ {
+ TypeIdentifier tp = cast(TypeIdentifier)tparam;
+ for (size_t i = 0; i < t.idents.dim; i++)
+ {
+ RootObject id1 = t.idents[i];
+ RootObject id2 = tp.idents[i];
+ if (!id1.equals(id2))
+ {
+ result = MATCH.nomatch;
+ return;
+ }
+ }
+ }
+ visit(cast(Type)t);
+ }
+
+ override void visit(TypeInstance t)
+ {
+ // Extra check
+ if (tparam && tparam.ty == Tinstance && t.tempinst.tempdecl)
+ {
+ TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration();
+ assert(tempdecl);
+
+ TypeInstance tp = cast(TypeInstance)tparam;
+
+ //printf("tempinst.tempdecl = %p\n", tempdecl);
+ //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl);
+ if (!tp.tempinst.tempdecl)
+ {
+ //printf("tp.tempinst.name = '%s'\n", tp.tempinst.name.toChars());
+
+ /* Handle case of:
+ * template Foo(T : sa!(T), alias sa)
+ */
+ size_t i = templateIdentifierLookup(tp.tempinst.name, parameters);
+ if (i == IDX_NOTFOUND)
+ {
+ /* Didn't find it as a parameter identifier. Try looking
+ * it up and seeing if is an alias.
+ * https://issues.dlang.org/show_bug.cgi?id=1454
+ */
+ auto tid = new TypeIdentifier(tp.loc, tp.tempinst.name);
+ Type tx;
+ Expression e;
+ Dsymbol s;
+ tid.resolve(tp.loc, sc, e, tx, s);
+ if (tx)
+ {
+ s = tx.toDsymbol(sc);
+ if (TemplateInstance ti = s ? s.parent.isTemplateInstance() : null)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=14290
+ // Try to match with ti.tempecl,
+ // only when ti is an enclosing instance.
+ Dsymbol p = sc.parent;
+ while (p && p != ti)
+ p = p.parent;
+ if (p)
+ s = ti.tempdecl;
+ }
+ }
+ if (s)
+ {
+ s = s.toAlias();
+ TemplateDeclaration td = s.isTemplateDeclaration();
+ if (td)
+ {
+ if (td.overroot)
+ td = td.overroot;
+ for (; td; td = td.overnext)
+ {
+ if (td == tempdecl)
+ goto L2;
+ }
+ }
+ }
+ goto Lnomatch;
+ }
+ TemplateParameter tpx = (*parameters)[i];
+ if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null))
+ goto Lnomatch;
+ }
+ else if (tempdecl != tp.tempinst.tempdecl)
+ goto Lnomatch;
+
+ L2:
+ for (size_t i = 0; 1; i++)
+ {
+ //printf("\ttest: tempinst.tiargs[%d]\n", i);
+ RootObject o1 = null;
+ if (i < t.tempinst.tiargs.dim)
+ o1 = (*t.tempinst.tiargs)[i];
+ else if (i < t.tempinst.tdtypes.dim && i < tp.tempinst.tiargs.dim)
+ {
+ // Pick up default arg
+ o1 = t.tempinst.tdtypes[i];
+ }
+ else if (i >= tp.tempinst.tiargs.dim)
+ break;
+
+ if (i >= tp.tempinst.tiargs.dim)
+ {
+ size_t dim = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0);
+ while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg()))
+ {
+ i++;
+ }
+ if (i >= dim)
+ break; // match if all remained parameters are dependent
+ goto Lnomatch;
+ }
+
+ RootObject o2 = (*tp.tempinst.tiargs)[i];
+ Type t2 = isType(o2);
+
+ size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.dim - 1)
+ ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND;
+ if (j != IDX_NOTFOUND && j == parameters.dim - 1 &&
+ (*parameters)[j].isTemplateTupleParameter())
+ {
+ /* Given:
+ * struct A(B...) {}
+ * alias A!(int, float) X;
+ * static if (is(X Y == A!(Z), Z...)) {}
+ * deduce that Z is a tuple(int, float)
+ */
+
+ /* Create tuple from remaining args
+ */
+ size_t vtdim = (tempdecl.isVariadic() ? t.tempinst.tiargs.dim : t.tempinst.tdtypes.dim) - i;
+ auto vt = new Tuple(vtdim);
+ for (size_t k = 0; k < vtdim; k++)
+ {
+ RootObject o;
+ if (k < t.tempinst.tiargs.dim)
+ o = (*t.tempinst.tiargs)[i + k];
+ else // Pick up default arg
+ o = t.tempinst.tdtypes[i + k];
+ vt.objects[k] = o;
+ }
+
+ Tuple v = cast(Tuple)(*dedtypes)[j];
+ if (v)
+ {
+ if (!match(v, vt))
+ goto Lnomatch;
+ }
+ else
+ (*dedtypes)[j] = vt;
+ break;
+ }
+ else if (!o1)
+ break;
+
+ Type t1 = isType(o1);
+ Dsymbol s1 = isDsymbol(o1);
+ Dsymbol s2 = isDsymbol(o2);
+ Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
+ Expression e2 = isExpression(o2);
+ version (none)
+ {
+ Tuple v1 = isTuple(o1);
+ Tuple v2 = isTuple(o2);
+ if (t1)
+ printf("t1 = %s\n", t1.toChars());
+ if (t2)
+ printf("t2 = %s\n", t2.toChars());
+ if (e1)
+ printf("e1 = %s\n", e1.toChars());
+ if (e2)
+ printf("e2 = %s\n", e2.toChars());
+ if (s1)
+ printf("s1 = %s\n", s1.toChars());
+ if (s2)
+ printf("s2 = %s\n", s2.toChars());
+ if (v1)
+ printf("v1 = %s\n", v1.toChars());
+ if (v2)
+ printf("v2 = %s\n", v2.toChars());
+ }
+
+ if (t1 && t2)
+ {
+ if (!deduceType(t1, sc, t2, parameters, dedtypes))
+ goto Lnomatch;
+ }
+ else if (e1 && e2)
+ {
+ Le:
+ e1 = e1.ctfeInterpret();
+
+ /* If it is one of the template parameters for this template,
+ * we should not attempt to interpret it. It already has a value.
+ */
+ if (e2.op == TOK.variable && ((cast(VarExp)e2).var.storage_class & STC.templateparameter))
+ {
+ /*
+ * (T:Number!(e2), int e2)
+ */
+ j = templateIdentifierLookup((cast(VarExp)e2).var.ident, parameters);
+ if (j != IDX_NOTFOUND)
+ goto L1;
+ // The template parameter was not from this template
+ // (it may be from a parent template, for example)
+ }
+
+ e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417
+ e2 = e2.ctfeInterpret();
+
+ //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
+ //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
+ if (!e1.equals(e2))
+ {
+ if (!e2.implicitConvTo(e1.type))
+ goto Lnomatch;
+
+ e2 = e2.implicitCastTo(sc, e1.type);
+ e2 = e2.ctfeInterpret();
+ if (!e1.equals(e2))
+ goto Lnomatch;
+ }
+ }
+ else if (e1 && t2 && t2.ty == Tident)
+ {
+ j = templateParameterLookup(t2, parameters);
+ L1:
+ if (j == IDX_NOTFOUND)
+ {
+ t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
+ if (e2)
+ goto Le;
+ goto Lnomatch;
+ }
+ if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null))
+ goto Lnomatch;
+ }
+ else if (s1 && s2)
+ {
+ Ls:
+ if (!s1.equals(s2))
+ goto Lnomatch;
+ }
+ else if (s1 && t2 && t2.ty == Tident)
+ {
+ j = templateParameterLookup(t2, parameters);
+ if (j == IDX_NOTFOUND)
+ {
+ t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
+ if (s2)
+ goto Ls;
+ goto Lnomatch;
+ }
+ if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null))
+ goto Lnomatch;
+ }
+ else
+ goto Lnomatch;
+ }
+ }
+ visit(cast(Type)t);
+ return;
+
+ Lnomatch:
+ //printf("no match\n");
+ result = MATCH.nomatch;
+ }
+
+ override void visit(TypeStruct t)
+ {
+ /* If this struct is a template struct, and we're matching
+ * it against a template instance, convert the struct type
+ * to a template instance, too, and try again.
+ */
+ TemplateInstance ti = t.sym.parent.isTemplateInstance();
+
+ if (tparam && tparam.ty == Tinstance)
+ {
+ if (ti && ti.toAlias() == t.sym)
+ {
+ auto tx = new TypeInstance(Loc.initial, ti);
+ result = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
+ return;
+ }
+
+ /* Match things like:
+ * S!(T).foo
+ */
+ TypeInstance tpi = cast(TypeInstance)tparam;
+ if (tpi.idents.dim)
+ {
+ RootObject id = tpi.idents[tpi.idents.dim - 1];
+ if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id))
+ {
+ Type tparent = t.sym.parent.getType();
+ if (tparent)
+ {
+ /* Slice off the .foo in S!(T).foo
+ */
+ tpi.idents.dim--;
+ result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
+ tpi.idents.dim++;
+ return;
+ }
+ }
+ }
+ }
+
+ // Extra check
+ if (tparam && tparam.ty == Tstruct)
+ {
+ TypeStruct tp = cast(TypeStruct)tparam;
+
+ //printf("\t%d\n", (MATCH) t.implicitConvTo(tp));
+ if (wm && t.deduceWild(tparam, false))
+ {
+ result = MATCH.constant;
+ return;
+ }
+ result = t.implicitConvTo(tp);
+ return;
+ }
+ visit(cast(Type)t);
+ }
+
+ override void visit(TypeEnum t)
+ {
+ // Extra check
+ if (tparam && tparam.ty == Tenum)
+ {
+ TypeEnum tp = cast(TypeEnum)tparam;
+ if (t.sym == tp.sym)
+ visit(cast(Type)t);
+ else
+ result = MATCH.nomatch;
+ return;
+ }
+ Type tb = t.toBasetype();
+ if (tb.ty == tparam.ty || tb.ty == Tsarray && tparam.ty == Taarray)
+ {
+ result = deduceType(tb, sc, tparam, parameters, dedtypes, wm);
+ if (result == MATCH.exact)
+ result = MATCH.convert;
+ return;
+ }
+ visit(cast(Type)t);
+ }
+
+ /* Helper for TypeClass.deduceType().
+ * Classes can match with implicit conversion to a base class or interface.
+ * This is complicated, because there may be more than one base class which
+ * matches. In such cases, one or more parameters remain ambiguous.
+ * For example,
+ *
+ * interface I(X, Y) {}
+ * class C : I(uint, double), I(char, double) {}
+ * C x;
+ * foo(T, U)( I!(T, U) x)
+ *
+ * deduces that U is double, but T remains ambiguous (could be char or uint).
+ *
+ * Given a baseclass b, and initial deduced types 'dedtypes', this function
+ * tries to match tparam with b, and also tries all base interfaces of b.
+ * If a match occurs, numBaseClassMatches is incremented, and the new deduced
+ * types are ANDed with the current 'best' estimate for dedtypes.
+ */
+ static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches)
+ {
+ TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null;
+ if (parti)
+ {
+ // Make a temporary copy of dedtypes so we don't destroy it
+ auto tmpdedtypes = new Objects(dedtypes.dim);
+ memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.dim * (void*).sizeof);
+
+ auto t = new TypeInstance(Loc.initial, parti);
+ MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes);
+ if (m > MATCH.nomatch)
+ {
+ // If this is the first ever match, it becomes our best estimate
+ if (numBaseClassMatches == 0)
+ memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.dim * (void*).sizeof);
+ else
+ for (size_t k = 0; k < tmpdedtypes.dim; ++k)
+ {
+ // If we've found more than one possible type for a parameter,
+ // mark it as unknown.
+ if ((*tmpdedtypes)[k] != (*best)[k])
+ (*best)[k] = (*dedtypes)[k];
+ }
+ ++numBaseClassMatches;
+ }
+ }
+
+ // Now recursively test the inherited interfaces
+ foreach (ref bi; b.baseInterfaces)
+ {
+ deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
+ }
+ }
+
+ override void visit(TypeClass t)
+ {
+ //printf("TypeClass.deduceType(this = %s)\n", t.toChars());
+
+ /* If this class is a template class, and we're matching
+ * it against a template instance, convert the class type
+ * to a template instance, too, and try again.
+ */
+ TemplateInstance ti = t.sym.parent.isTemplateInstance();
+
+ if (tparam && tparam.ty == Tinstance)
+ {
+ if (ti && ti.toAlias() == t.sym)
+ {
+ auto tx = new TypeInstance(Loc.initial, ti);
+ MATCH m = deduceType(tx, sc, tparam, parameters, dedtypes, wm);
+ // Even if the match fails, there is still a chance it could match
+ // a base class.
+ if (m != MATCH.nomatch)
+ {
+ result = m;
+ return;
+ }
+ }
+
+ /* Match things like:
+ * S!(T).foo
+ */
+ TypeInstance tpi = cast(TypeInstance)tparam;
+ if (tpi.idents.dim)
+ {
+ RootObject id = tpi.idents[tpi.idents.dim - 1];
+ if (id.dyncast() == DYNCAST.identifier && t.sym.ident.equals(cast(Identifier)id))
+ {
+ Type tparent = t.sym.parent.getType();
+ if (tparent)
+ {
+ /* Slice off the .foo in S!(T).foo
+ */
+ tpi.idents.dim--;
+ result = deduceType(tparent, sc, tpi, parameters, dedtypes, wm);
+ tpi.idents.dim++;
+ return;
+ }
+ }
+ }
+
+ // If it matches exactly or via implicit conversion, we're done
+ visit(cast(Type)t);
+ if (result != MATCH.nomatch)
+ return;
+
+ /* There is still a chance to match via implicit conversion to
+ * a base class or interface. Because there could be more than one such
+ * match, we need to check them all.
+ */
+
+ int numBaseClassMatches = 0; // Have we found an interface match?
+
+ // Our best guess at dedtypes
+ auto best = new Objects(dedtypes.dim);
+
+ ClassDeclaration s = t.sym;
+ while (s && s.baseclasses.dim > 0)
+ {
+ // Test the base class
+ deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
+
+ // Test the interfaces inherited by the base class
+ foreach (b; s.interfaces)
+ {
+ deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
+ }
+ s = (*s.baseclasses)[0].sym;
+ }
+
+ if (numBaseClassMatches == 0)
+ {
+ result = MATCH.nomatch;
+ return;
+ }
+
+ // If we got at least one match, copy the known types into dedtypes
+ memcpy(dedtypes.tdata(), best.tdata(), best.dim * (void*).sizeof);
+ result = MATCH.convert;
+ return;
+ }
+
+ // Extra check
+ if (tparam && tparam.ty == Tclass)
+ {
+ TypeClass tp = cast(TypeClass)tparam;
+
+ //printf("\t%d\n", (MATCH) t.implicitConvTo(tp));
+ if (wm && t.deduceWild(tparam, false))
+ {
+ result = MATCH.constant;
+ return;
+ }
+ result = t.implicitConvTo(tp);
+ return;
+ }
+ visit(cast(Type)t);
+ }
+
+ override void visit(Expression e)
+ {
+ //printf("Expression.deduceType(e = %s)\n", e.toChars());
+ size_t i = templateParameterLookup(tparam, parameters);
+ if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.dim > 0)
+ {
+ if (e == emptyArrayElement && tparam.ty == Tarray)
+ {
+ Type tn = (cast(TypeNext)tparam).next;
+ result = deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
+ return;
+ }
+ e.type.accept(this);
+ return;
+ }
+
+ TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter();
+ if (!tp)
+ return; // nomatch
+
+ if (e == emptyArrayElement)
+ {
+ if ((*dedtypes)[i])
+ {
+ result = MATCH.exact;
+ return;
+ }
+ if (tp.defaultType)
+ {
+ tp.defaultType.accept(this);
+ return;
+ }
+ }
+
+ /* Returns `true` if `t` is a reference type, or an array of reference types
+ */
+ bool isTopRef(Type t)
+ {
+ auto tb = t.baseElemOf();
+ return tb.ty == Tclass ||
+ tb.ty == Taarray ||
+ tb.ty == Tstruct && tb.hasPointers();
+ }
+
+ Type at = cast(Type)(*dedtypes)[i];
+ Type tt;
+ if (ubyte wx = deduceWildHelper(e.type, &tt, tparam))
+ {
+ *wm |= wx;
+ result = MATCH.constant;
+ }
+ else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam))
+ {
+ result = m;
+ }
+ else if (!isTopRef(e.type))
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=15653
+ * In IFTI, recognize top-qualifier conversions
+ * through the value copy, e.g.
+ * int --> immutable(int)
+ * immutable(string[]) --> immutable(string)[]
+ */
+ tt = e.type.mutableOf();
+ result = MATCH.convert;
+ }
+ else
+ return; // nomatch
+
+ // expression vs (none)
+ if (!at)
+ {
+ (*dedtypes)[i] = new TypeDeduced(tt, e, tparam);
+ return;
+ }
+
+ TypeDeduced xt = null;
+ if (at.ty == Tnone)
+ {
+ xt = cast(TypeDeduced)at;
+ at = xt.tded;
+ }
+
+ // From previous matched expressions to current deduced type
+ MATCH match1 = xt ? xt.matchAll(tt) : MATCH.nomatch;
+
+ // From current expressions to previous deduced type
+ Type pt = at.addMod(tparam.mod);
+ if (*wm)
+ pt = pt.substWildTo(*wm);
+ MATCH match2 = e.implicitConvTo(pt);
+
+ if (match1 > MATCH.nomatch && match2 > MATCH.nomatch)
+ {
+ if (at.implicitConvTo(tt) == MATCH.nomatch)
+ match1 = MATCH.nomatch; // Prefer at
+ else if (tt.implicitConvTo(at) == MATCH.nomatch)
+ match2 = MATCH.nomatch; // Prefer tt
+ else if (tt.isTypeBasic() && tt.ty == at.ty && tt.mod != at.mod)
+ {
+ if (!tt.isMutable() && !at.isMutable())
+ tt = tt.mutableOf().addMod(MODmerge(tt.mod, at.mod));
+ else if (tt.isMutable())
+ {
+ if (at.mod == 0) // Prefer unshared
+ match1 = MATCH.nomatch;
+ else
+ match2 = MATCH.nomatch;
+ }
+ else if (at.isMutable())
+ {
+ if (tt.mod == 0) // Prefer unshared
+ match2 = MATCH.nomatch;
+ else
+ match1 = MATCH.nomatch;
+ }
+ //printf("tt = %s, at = %s\n", tt.toChars(), at.toChars());
+ }
+ else
+ {
+ match1 = MATCH.nomatch;
+ match2 = MATCH.nomatch;
+ }
+ }
+ if (match1 > MATCH.nomatch)
+ {
+ // Prefer current match: tt
+ if (xt)
+ xt.update(tt, e, tparam);
+ else
+ (*dedtypes)[i] = tt;
+ result = match1;
+ return;
+ }
+ if (match2 > MATCH.nomatch)
+ {
+ // Prefer previous match: (*dedtypes)[i]
+ if (xt)
+ xt.update(e, tparam);
+ result = match2;
+ return;
+ }
+
+ /* Deduce common type
+ */
+ if (Type t = rawTypeMerge(at, tt))
+ {
+ if (xt)
+ xt.update(t, e, tparam);
+ else
+ (*dedtypes)[i] = t;
+
+ pt = tt.addMod(tparam.mod);
+ if (*wm)
+ pt = pt.substWildTo(*wm);
+ result = e.implicitConvTo(pt);
+ return;
+ }
+
+ result = MATCH.nomatch;
+ }
+
+ MATCH deduceEmptyArrayElement()
+ {
+ if (!emptyArrayElement)
+ {
+ emptyArrayElement = new IdentifierExp(Loc.initial, Id.p); // dummy
+ emptyArrayElement.type = Type.tvoid;
+ }
+ assert(tparam.ty == Tarray);
+
+ Type tn = (cast(TypeNext)tparam).next;
+ return deduceType(emptyArrayElement, sc, tn, parameters, dedtypes, wm);
+ }
+
+ override void visit(NullExp e)
+ {
+ if (tparam.ty == Tarray && e.type.ty == Tnull)
+ {
+ // tparam:T[] <- e:null (void[])
+ result = deduceEmptyArrayElement();
+ return;
+ }
+ visit(cast(Expression)e);
+ }
+
+ override void visit(StringExp e)
+ {
+ Type taai;
+ if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
+ {
+ // Consider compile-time known boundaries
+ e.type.nextOf().sarrayOf(e.len).accept(this);
+ return;
+ }
+ visit(cast(Expression)e);
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=20092
+ if (e.elements && e.elements.dim && e.type.toBasetype().nextOf().ty == Tvoid)
+ {
+ result = deduceEmptyArrayElement();
+ return;
+ }
+ if ((!e.elements || !e.elements.dim) && e.type.toBasetype().nextOf().ty == Tvoid && tparam.ty == Tarray)
+ {
+ // tparam:T[] <- e:[] (void[])
+ result = deduceEmptyArrayElement();
+ return;
+ }
+
+ if (tparam.ty == Tarray && e.elements && e.elements.dim)
+ {
+ Type tn = (cast(TypeDArray)tparam).next;
+ result = MATCH.exact;
+ if (e.basis)
+ {
+ MATCH m = deduceType(e.basis, sc, tn, parameters, dedtypes, wm);
+ if (m < result)
+ result = m;
+ }
+ foreach (el; *e.elements)
+ {
+ if (result == MATCH.nomatch)
+ break;
+ if (!el)
+ continue;
+ MATCH m = deduceType(el, sc, tn, parameters, dedtypes, wm);
+ if (m < result)
+ result = m;
+ }
+ return;
+ }
+
+ Type taai;
+ if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
+ {
+ // Consider compile-time known boundaries
+ e.type.nextOf().sarrayOf(e.elements.dim).accept(this);
+ return;
+ }
+ visit(cast(Expression)e);
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ if (tparam.ty == Taarray && e.keys && e.keys.dim)
+ {
+ TypeAArray taa = cast(TypeAArray)tparam;
+ result = MATCH.exact;
+ foreach (i, key; *e.keys)
+ {
+ MATCH m1 = deduceType(key, sc, taa.index, parameters, dedtypes, wm);
+ if (m1 < result)
+ result = m1;
+ if (result == MATCH.nomatch)
+ break;
+ MATCH m2 = deduceType((*e.values)[i], sc, taa.next, parameters, dedtypes, wm);
+ if (m2 < result)
+ result = m2;
+ if (result == MATCH.nomatch)
+ break;
+ }
+ return;
+ }
+ visit(cast(Expression)e);
+ }
+
+ override void visit(FuncExp e)
+ {
+ //printf("e.type = %s, tparam = %s\n", e.type.toChars(), tparam.toChars());
+ if (e.td)
+ {
+ Type to = tparam;
+ if (!to.nextOf())
+ return;
+ auto tof = to.nextOf().isTypeFunction();
+ if (!tof)
+ return;
+
+ // Parameter types inference from 'tof'
+ assert(e.td._scope);
+ TypeFunction tf = cast(TypeFunction)e.fd.type;
+ //printf("\ttof = %s\n", tof.toChars());
+ //printf("\ttf = %s\n", tf.toChars());
+ const dim = tf.parameterList.length;
+
+ if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
+ return;
+
+ auto tiargs = new Objects();
+ tiargs.reserve(e.td.parameters.dim);
+
+ foreach (tp; *e.td.parameters)
+ {
+ size_t u = 0;
+ foreach (i, p; tf.parameterList)
+ {
+ if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
+ break;
+ ++u;
+ }
+ assert(u < dim);
+ Parameter pto = tof.parameterList[u];
+ if (!pto)
+ break;
+ Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774
+ if (reliesOnTemplateParameters(t, (*parameters)[inferStart .. parameters.dim]))
+ return;
+ t = t.typeSemantic(e.loc, sc);
+ if (t.ty == Terror)
+ return;
+ tiargs.push(t);
+ }
+
+ // Set target of return type inference
+ if (!tf.next && tof.next)
+ e.fd.treq = tparam;
+
+ auto ti = new TemplateInstance(e.loc, e.td, tiargs);
+ Expression ex = (new ScopeExp(e.loc, ti)).expressionSemantic(e.td._scope);
+
+ // Reset inference target for the later re-semantic
+ e.fd.treq = null;
+
+ if (ex.op == TOK.error)
+ return;
+ if (ex.op != TOK.function_)
+ return;
+ visit(ex.type);
+ return;
+ }
+
+ Type t = e.type;
+
+ if (t.ty == Tdelegate && tparam.ty == Tpointer)
+ return;
+
+ // Allow conversion from implicit function pointer to delegate
+ if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate)
+ {
+ TypeFunction tf = cast(TypeFunction)t.nextOf();
+ t = (new TypeDelegate(tf)).merge();
+ }
+ //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars());
+ visit(t);
+ }
+
+ override void visit(SliceExp e)
+ {
+ Type taai;
+ if (e.type.ty == Tarray && (tparam.ty == Tsarray || tparam.ty == Taarray && (taai = (cast(TypeAArray)tparam).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
+ {
+ // Consider compile-time known boundaries
+ if (Type tsa = toStaticArrayType(e))
+ {
+ tsa.accept(this);
+ if (result > MATCH.convert)
+ result = MATCH.convert; // match with implicit conversion at most
+ return;
+ }
+ }
+ visit(cast(Expression)e);
+ }
+
+ override void visit(CommaExp e)
+ {
+ e.e2.accept(this);
+ }
+ }
+
+ scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart, ignoreAliasThis);
+ if (Type t = isType(o))
+ t.accept(v);
+ else if (Expression e = isExpression(o))
+ {
+ assert(wm);
+ e.accept(v);
+ }
+ else
+ assert(0);
+ return v.result;
+}
+
+/***********************************************************
+ * Check whether the type t representation relies on one or more the template parameters.
+ * Params:
+ * t = Tested type, if null, returns false.
+ * tparams = Template parameters.
+ * iStart = Start index of tparams to limit the tested parameters. If it's
+ * nonzero, tparams[0..iStart] will be excluded from the test target.
+ */
+bool reliesOnTident(Type t, TemplateParameters* tparams, size_t iStart = 0)
+{
+ return reliesOnTemplateParameters(t, (*tparams)[0 .. tparams.dim]);
+}
+
+/***********************************************************
+ * Check whether the type t representation relies on one or more the template parameters.
+ * Params:
+ * t = Tested type, if null, returns false.
+ * tparams = Template parameters.
+ */
+private bool reliesOnTemplateParameters(Type t, TemplateParameter[] tparams)
+{
+ bool visitVector(TypeVector t)
+ {
+ return t.basetype.reliesOnTemplateParameters(tparams);
+ }
+
+ bool visitAArray(TypeAArray t)
+ {
+ return t.next.reliesOnTemplateParameters(tparams) ||
+ t.index.reliesOnTemplateParameters(tparams);
+ }
+
+ bool visitFunction(TypeFunction t)
+ {
+ foreach (i, fparam; t.parameterList)
+ {
+ if (fparam.type.reliesOnTemplateParameters(tparams))
+ return true;
+ }
+ return t.next.reliesOnTemplateParameters(tparams);
+ }
+
+ bool visitIdentifier(TypeIdentifier t)
+ {
+ foreach (tp; tparams)
+ {
+ if (tp.ident.equals(t.ident))
+ return true;
+ }
+ return false;
+ }
+
+ bool visitInstance(TypeInstance t)
+ {
+ foreach (tp; tparams)
+ {
+ if (t.tempinst.name == tp.ident)
+ return true;
+ }
+
+ if (t.tempinst.tiargs)
+ foreach (arg; *t.tempinst.tiargs)
+ {
+ if (Type ta = isType(arg))
+ {
+ if (ta.reliesOnTemplateParameters(tparams))
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool visitTypeof(TypeTypeof t)
+ {
+ //printf("TypeTypeof.reliesOnTemplateParameters('%s')\n", t.toChars());
+ return t.exp.reliesOnTemplateParameters(tparams);
+ }
+
+ bool visitTuple(TypeTuple t)
+ {
+ if (t.arguments)
+ foreach (arg; *t.arguments)
+ {
+ if (arg.type.reliesOnTemplateParameters(tparams))
+ return true;
+ }
+
+ return false;
+ }
+
+ if (!t)
+ return false;
+
+ Type tb = t.toBasetype();
+ switch (tb.ty)
+ {
+ case Tvector: return visitVector(tb.isTypeVector());
+ case Taarray: return visitAArray(tb.isTypeAArray());
+ case Tfunction: return visitFunction(tb.isTypeFunction());
+ case Tident: return visitIdentifier(tb.isTypeIdentifier());
+ case Tinstance: return visitInstance(tb.isTypeInstance());
+ case Ttypeof: return visitTypeof(tb.isTypeTypeof());
+ case Ttuple: return visitTuple(tb.isTypeTuple());
+ case Tenum: return false;
+ default: return tb.nextOf().reliesOnTemplateParameters(tparams);
+ }
+}
+
+/***********************************************************
+ * Check whether the expression representation relies on one or more the template parameters.
+ * Params:
+ * e = expression to test
+ * tparams = Template parameters.
+ * Returns:
+ * true if it does
+ */
+private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparams)
+{
+ extern (C++) final class ReliesOnTemplateParameters : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ TemplateParameter[] tparams;
+ bool result;
+
+ extern (D) this(TemplateParameter[] tparams)
+ {
+ this.tparams = tparams;
+ }
+
+ override void visit(Expression e)
+ {
+ //printf("Expression.reliesOnTemplateParameters('%s')\n", e.toChars());
+ }
+
+ override void visit(IdentifierExp e)
+ {
+ //printf("IdentifierExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ foreach (tp; tparams)
+ {
+ if (e.ident == tp.ident)
+ {
+ result = true;
+ return;
+ }
+ }
+ }
+
+ override void visit(TupleExp e)
+ {
+ //printf("TupleExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ if (e.exps)
+ {
+ foreach (ea; *e.exps)
+ {
+ ea.accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ //printf("ArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ if (e.elements)
+ {
+ foreach (el; *e.elements)
+ {
+ el.accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ //printf("AssocArrayLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ foreach (ek; *e.keys)
+ {
+ ek.accept(this);
+ if (result)
+ return;
+ }
+ foreach (ev; *e.values)
+ {
+ ev.accept(this);
+ if (result)
+ return;
+ }
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ //printf("StructLiteralExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ if (e.elements)
+ {
+ foreach (ea; *e.elements)
+ {
+ ea.accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ override void visit(TypeExp e)
+ {
+ //printf("TypeExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ result = e.type.reliesOnTemplateParameters(tparams);
+ }
+
+ override void visit(NewExp e)
+ {
+ //printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ if (e.thisexp)
+ e.thisexp.accept(this);
+ if (!result && e.newargs)
+ {
+ foreach (ea; *e.newargs)
+ {
+ ea.accept(this);
+ if (result)
+ return;
+ }
+ }
+ result = e.newtype.reliesOnTemplateParameters(tparams);
+ if (!result && e.arguments)
+ {
+ foreach (ea; *e.arguments)
+ {
+ ea.accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ override void visit(NewAnonClassExp e)
+ {
+ //printf("NewAnonClassExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ result = true;
+ }
+
+ override void visit(FuncExp e)
+ {
+ //printf("FuncExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ result = true;
+ }
+
+ override void visit(TypeidExp e)
+ {
+ //printf("TypeidExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ if (auto ea = isExpression(e.obj))
+ ea.accept(this);
+ else if (auto ta = isType(e.obj))
+ result = ta.reliesOnTemplateParameters(tparams);
+ }
+
+ override void visit(TraitsExp e)
+ {
+ //printf("TraitsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ if (e.args)
+ {
+ foreach (oa; *e.args)
+ {
+ if (auto ea = isExpression(oa))
+ ea.accept(this);
+ else if (auto ta = isType(oa))
+ result = ta.reliesOnTemplateParameters(tparams);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ override void visit(IsExp e)
+ {
+ //printf("IsExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ result = e.targ.reliesOnTemplateParameters(tparams);
+ }
+
+ override void visit(UnaExp e)
+ {
+ //printf("UnaExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ e.e1.accept(this);
+ }
+
+ override void visit(DotTemplateInstanceExp e)
+ {
+ //printf("DotTemplateInstanceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ visit(cast(UnaExp)e);
+ if (!result && e.ti.tiargs)
+ {
+ foreach (oa; *e.ti.tiargs)
+ {
+ if (auto ea = isExpression(oa))
+ ea.accept(this);
+ else if (auto ta = isType(oa))
+ result = ta.reliesOnTemplateParameters(tparams);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ override void visit(CallExp e)
+ {
+ //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ visit(cast(UnaExp)e);
+ if (!result && e.arguments)
+ {
+ foreach (ea; *e.arguments)
+ {
+ ea.accept(this);
+ if (result)
+ return;
+ }
+ }
+ }
+
+ override void visit(CastExp e)
+ {
+ //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ visit(cast(UnaExp)e);
+ // e.to can be null for cast() with no type
+ if (!result && e.to)
+ result = e.to.reliesOnTemplateParameters(tparams);
+ }
+
+ override void visit(SliceExp e)
+ {
+ //printf("SliceExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ visit(cast(UnaExp)e);
+ if (!result && e.lwr)
+ e.lwr.accept(this);
+ if (!result && e.upr)
+ e.upr.accept(this);
+ }
+
+ override void visit(IntervalExp e)
+ {
+ //printf("IntervalExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ e.lwr.accept(this);
+ if (!result)
+ e.upr.accept(this);
+ }
+
+ override void visit(ArrayExp e)
+ {
+ //printf("ArrayExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ visit(cast(UnaExp)e);
+ if (!result && e.arguments)
+ {
+ foreach (ea; *e.arguments)
+ ea.accept(this);
+ }
+ }
+
+ override void visit(BinExp e)
+ {
+ //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ e.e1.accept(this);
+ if (!result)
+ e.e2.accept(this);
+ }
+
+ override void visit(CondExp e)
+ {
+ //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars());
+ e.econd.accept(this);
+ if (!result)
+ visit(cast(BinExp)e);
+ }
+ }
+
+ scope ReliesOnTemplateParameters v = new ReliesOnTemplateParameters(tparams);
+ e.accept(v);
+ return v.result;
+}
+
+/***********************************************************
+ * https://dlang.org/spec/template.html#TemplateParameter
+ */
+extern (C++) class TemplateParameter : ASTNode
+{
+ Loc loc;
+ Identifier ident;
+
+ /* True if this is a part of precedent parameter specialization pattern.
+ *
+ * template A(T : X!TL, alias X, TL...) {}
+ * // X and TL are dependent template parameter
+ *
+ * A dependent template parameter should return MATCH.exact in matchArg()
+ * to respect the match level of the corresponding precedent parameter.
+ */
+ bool dependent;
+
+ /* ======================== TemplateParameter =============================== */
+ extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ this.loc = loc;
+ this.ident = ident;
+ }
+
+ TemplateTypeParameter isTemplateTypeParameter()
+ {
+ return null;
+ }
+
+ TemplateValueParameter isTemplateValueParameter()
+ {
+ return null;
+ }
+
+ TemplateAliasParameter isTemplateAliasParameter()
+ {
+ return null;
+ }
+
+ TemplateThisParameter isTemplateThisParameter()
+ {
+ return null;
+ }
+
+ TemplateTupleParameter isTemplateTupleParameter()
+ {
+ return null;
+ }
+
+ abstract TemplateParameter syntaxCopy();
+
+ abstract bool declareParameter(Scope* sc);
+
+ abstract void print(RootObject oarg, RootObject oded);
+
+ abstract RootObject specialization();
+
+ abstract RootObject defaultArg(Loc instLoc, Scope* sc);
+
+ abstract bool hasDefaultArg();
+
+ override const(char)* toChars() const
+ {
+ return this.ident.toChars();
+ }
+
+ override DYNCAST dyncast() const pure @nogc nothrow @safe
+ {
+ return DYNCAST.templateparameter;
+ }
+
+ /* Create dummy argument based on parameter.
+ */
+ abstract RootObject dummyArg();
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/template.html#TemplateTypeParameter
+ * Syntax:
+ * ident : specType = defaultType
+ */
+extern (C++) class TemplateTypeParameter : TemplateParameter
+{
+ Type specType; // if !=null, this is the type specialization
+ Type defaultType;
+
+ extern (D) __gshared Type tdummy = null;
+
+ extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType)
+ {
+ super(loc, ident);
+ this.specType = specType;
+ this.defaultType = defaultType;
+ }
+
+ override final TemplateTypeParameter isTemplateTypeParameter()
+ {
+ return this;
+ }
+
+ override TemplateTypeParameter syntaxCopy()
+ {
+ return new TemplateTypeParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
+ }
+
+ override final bool declareParameter(Scope* sc)
+ {
+ //printf("TemplateTypeParameter.declareParameter('%s')\n", ident.toChars());
+ auto ti = new TypeIdentifier(loc, ident);
+ Declaration ad = new AliasDeclaration(loc, ident, ti);
+ return sc.insert(ad) !is null;
+ }
+
+ override final void print(RootObject oarg, RootObject oded)
+ {
+ printf(" %s\n", ident.toChars());
+
+ Type t = isType(oarg);
+ Type ta = isType(oded);
+ assert(ta);
+
+ if (specType)
+ printf("\tSpecialization: %s\n", specType.toChars());
+ if (defaultType)
+ printf("\tDefault: %s\n", defaultType.toChars());
+ printf("\tParameter: %s\n", t ? t.toChars() : "NULL");
+ printf("\tDeduced Type: %s\n", ta.toChars());
+ }
+
+ override final RootObject specialization()
+ {
+ return specType;
+ }
+
+ override final RootObject defaultArg(Loc instLoc, Scope* sc)
+ {
+ Type t = defaultType;
+ if (t)
+ {
+ t = t.syntaxCopy();
+ t = t.typeSemantic(loc, sc); // use the parameter loc
+ }
+ return t;
+ }
+
+ override final bool hasDefaultArg()
+ {
+ return defaultType !is null;
+ }
+
+ override final RootObject dummyArg()
+ {
+ Type t = specType;
+ if (!t)
+ {
+ // Use this for alias-parameter's too (?)
+ if (!tdummy)
+ tdummy = new TypeIdentifier(loc, ident);
+ t = tdummy;
+ }
+ return t;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/template.html#TemplateThisParameter
+ * Syntax:
+ * this ident : specType = defaultType
+ */
+extern (C++) final class TemplateThisParameter : TemplateTypeParameter
+{
+ extern (D) this(const ref Loc loc, Identifier ident, Type specType, Type defaultType)
+ {
+ super(loc, ident, specType, defaultType);
+ }
+
+ override TemplateThisParameter isTemplateThisParameter()
+ {
+ return this;
+ }
+
+ override TemplateThisParameter syntaxCopy()
+ {
+ return new TemplateThisParameter(loc, ident, specType ? specType.syntaxCopy() : null, defaultType ? defaultType.syntaxCopy() : null);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/template.html#TemplateValueParameter
+ * Syntax:
+ * valType ident : specValue = defaultValue
+ */
+extern (C++) final class TemplateValueParameter : TemplateParameter
+{
+ Type valType;
+ Expression specValue;
+ Expression defaultValue;
+
+ extern (D) __gshared Expression[void*] edummies;
+
+ extern (D) this(const ref Loc loc, Identifier ident, Type valType,
+ Expression specValue, Expression defaultValue)
+ {
+ super(loc, ident);
+ this.valType = valType;
+ this.specValue = specValue;
+ this.defaultValue = defaultValue;
+ }
+
+ override TemplateValueParameter isTemplateValueParameter()
+ {
+ return this;
+ }
+
+ override TemplateValueParameter syntaxCopy()
+ {
+ return new TemplateValueParameter(loc, ident,
+ valType.syntaxCopy(),
+ specValue ? specValue.syntaxCopy() : null,
+ defaultValue ? defaultValue.syntaxCopy() : null);
+ }
+
+ override bool declareParameter(Scope* sc)
+ {
+ auto v = new VarDeclaration(loc, valType, ident, null);
+ v.storage_class = STC.templateparameter;
+ return sc.insert(v) !is null;
+ }
+
+ override void print(RootObject oarg, RootObject oded)
+ {
+ printf(" %s\n", ident.toChars());
+ Expression ea = isExpression(oded);
+ if (specValue)
+ printf("\tSpecialization: %s\n", specValue.toChars());
+ printf("\tParameter Value: %s\n", ea ? ea.toChars() : "NULL");
+ }
+
+ override RootObject specialization()
+ {
+ return specValue;
+ }
+
+ override RootObject defaultArg(Loc instLoc, Scope* sc)
+ {
+ Expression e = defaultValue;
+ if (e)
+ {
+ e = e.syntaxCopy();
+ uint olderrs = global.errors;
+ if ((e = e.expressionSemantic(sc)) is null)
+ return null;
+ if ((e = resolveProperties(sc, e)) is null)
+ return null;
+ e = e.resolveLoc(instLoc, sc); // use the instantiated loc
+ e = e.optimize(WANTvalue);
+ if (global.errors != olderrs)
+ e = ErrorExp.get();
+ }
+ return e;
+ }
+
+ override bool hasDefaultArg()
+ {
+ return defaultValue !is null;
+ }
+
+ override RootObject dummyArg()
+ {
+ Expression e = specValue;
+ if (!e)
+ {
+ // Create a dummy value
+ auto pe = cast(void*)valType in edummies;
+ if (!pe)
+ {
+ e = valType.defaultInit(Loc.initial);
+ edummies[cast(void*)valType] = e;
+ }
+ else
+ e = *pe;
+ }
+ return e;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/template.html#TemplateAliasParameter
+ * Syntax:
+ * specType ident : specAlias = defaultAlias
+ */
+extern (C++) final class TemplateAliasParameter : TemplateParameter
+{
+ Type specType;
+ RootObject specAlias;
+ RootObject defaultAlias;
+
+ extern (D) __gshared Dsymbol sdummy = null;
+
+ extern (D) this(const ref Loc loc, Identifier ident, Type specType, RootObject specAlias, RootObject defaultAlias)
+ {
+ super(loc, ident);
+ this.specType = specType;
+ this.specAlias = specAlias;
+ this.defaultAlias = defaultAlias;
+ }
+
+ override TemplateAliasParameter isTemplateAliasParameter()
+ {
+ return this;
+ }
+
+ override TemplateAliasParameter syntaxCopy()
+ {
+ return new TemplateAliasParameter(loc, ident, specType ? specType.syntaxCopy() : null, objectSyntaxCopy(specAlias), objectSyntaxCopy(defaultAlias));
+ }
+
+ override bool declareParameter(Scope* sc)
+ {
+ auto ti = new TypeIdentifier(loc, ident);
+ Declaration ad = new AliasDeclaration(loc, ident, ti);
+ return sc.insert(ad) !is null;
+ }
+
+ override void print(RootObject oarg, RootObject oded)
+ {
+ printf(" %s\n", ident.toChars());
+ Dsymbol sa = isDsymbol(oded);
+ assert(sa);
+ printf("\tParameter alias: %s\n", sa.toChars());
+ }
+
+ override RootObject specialization()
+ {
+ return specAlias;
+ }
+
+ override RootObject defaultArg(Loc instLoc, Scope* sc)
+ {
+ RootObject da = defaultAlias;
+ Type ta = isType(defaultAlias);
+ if (ta)
+ {
+ if (ta.ty == Tinstance)
+ {
+ // If the default arg is a template, instantiate for each type
+ da = ta.syntaxCopy();
+ }
+ }
+
+ RootObject o = aliasParameterSemantic(loc, sc, da, null); // use the parameter loc
+ return o;
+ }
+
+ override bool hasDefaultArg()
+ {
+ return defaultAlias !is null;
+ }
+
+ override RootObject dummyArg()
+ {
+ RootObject s = specAlias;
+ if (!s)
+ {
+ if (!sdummy)
+ sdummy = new Dsymbol();
+ s = sdummy;
+ }
+ return s;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/template.html#TemplateSequenceParameter
+ * Syntax:
+ * ident ...
+ */
+extern (C++) final class TemplateTupleParameter : TemplateParameter
+{
+ extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ super(loc, ident);
+ }
+
+ override TemplateTupleParameter isTemplateTupleParameter()
+ {
+ return this;
+ }
+
+ override TemplateTupleParameter syntaxCopy()
+ {
+ return new TemplateTupleParameter(loc, ident);
+ }
+
+ override bool declareParameter(Scope* sc)
+ {
+ auto ti = new TypeIdentifier(loc, ident);
+ Declaration ad = new AliasDeclaration(loc, ident, ti);
+ return sc.insert(ad) !is null;
+ }
+
+ override void print(RootObject oarg, RootObject oded)
+ {
+ printf(" %s... [", ident.toChars());
+ Tuple v = isTuple(oded);
+ assert(v);
+
+ //printf("|%d| ", v.objects.dim);
+ foreach (i, o; v.objects)
+ {
+ if (i)
+ printf(", ");
+
+ Dsymbol sa = isDsymbol(o);
+ if (sa)
+ printf("alias: %s", sa.toChars());
+ Type ta = isType(o);
+ if (ta)
+ printf("type: %s", ta.toChars());
+ Expression ea = isExpression(o);
+ if (ea)
+ printf("exp: %s", ea.toChars());
+
+ assert(!isTuple(o)); // no nested Tuple arguments
+ }
+ printf("]\n");
+ }
+
+ override RootObject specialization()
+ {
+ return null;
+ }
+
+ override RootObject defaultArg(Loc instLoc, Scope* sc)
+ {
+ return null;
+ }
+
+ override bool hasDefaultArg()
+ {
+ return false;
+ }
+
+ override RootObject dummyArg()
+ {
+ return null;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/template.html#explicit_tmp_instantiation
+ * Given:
+ * foo!(args) =>
+ * name = foo
+ * tiargs = args
+ */
+extern (C++) class TemplateInstance : ScopeDsymbol
+{
+ Identifier name;
+
+ // Array of Types/Expressions of template
+ // instance arguments [int*, char, 10*10]
+ Objects* tiargs;
+
+ // Array of Types/Expressions corresponding
+ // to TemplateDeclaration.parameters
+ // [int, char, 100]
+ Objects tdtypes;
+
+ // Modules imported by this template instance
+ Modules importedModules;
+
+ Dsymbol tempdecl; // referenced by foo.bar.abc
+ Dsymbol enclosing; // if referencing local symbols, this is the context
+ Dsymbol aliasdecl; // !=null if instance is an alias for its sole member
+ TemplateInstance inst; // refer to existing instance
+ ScopeDsymbol argsym; // argument symbol table
+ size_t hash; // cached result of toHash()
+ Expressions* fargs; // for function template, these are the function arguments
+
+ TemplateInstances* deferred;
+
+ Module memberOf; // if !null, then this TemplateInstance appears in memberOf.members[]
+
+ // Used to determine the instance needs code generation.
+ // Note that these are inaccurate until semantic analysis phase completed.
+ TemplateInstance tinst; // enclosing template instance
+ TemplateInstance tnext; // non-first instantiated instances
+ Module minst; // the top module that instantiated this instance
+
+ private ushort _nest; // for recursive pretty printing detection, 3 MSBs reserved for flags (below)
+ ubyte inuse; // for recursive expansion detection
+
+ private enum Flag : uint
+ {
+ semantictiargsdone = 1u << (_nest.sizeof * 8 - 1), // MSB of _nest
+ havetempdecl = semantictiargsdone >> 1,
+ gagged = semantictiargsdone >> 2,
+ available = gagged - 1 // always last flag minus one, 1s for all available bits
+ }
+
+ extern(D) final @safe @property pure nothrow @nogc
+ {
+ ushort nest() const { return _nest & Flag.available; }
+ void nestUp() { assert(nest() < Flag.available); ++_nest; }
+ void nestDown() { assert(nest() > 0); --_nest; }
+ /// has semanticTiargs() been done?
+ bool semantictiargsdone() const { return (_nest & Flag.semantictiargsdone) != 0; }
+ void semantictiargsdone(bool x)
+ {
+ if (x) _nest |= Flag.semantictiargsdone;
+ else _nest &= ~Flag.semantictiargsdone;
+ }
+ /// if used second constructor
+ bool havetempdecl() const { return (_nest & Flag.havetempdecl) != 0; }
+ void havetempdecl(bool x)
+ {
+ if (x) _nest |= Flag.havetempdecl;
+ else _nest &= ~Flag.havetempdecl;
+ }
+ /// if the instantiation is done with error gagging
+ bool gagged() const { return (_nest & Flag.gagged) != 0; }
+ void gagged(bool x)
+ {
+ if (x) _nest |= Flag.gagged;
+ else _nest &= ~Flag.gagged;
+ }
+ }
+
+ extern (D) this(const ref Loc loc, Identifier ident, Objects* tiargs)
+ {
+ super(loc, null);
+ static if (LOG)
+ {
+ printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident.toChars() : "null");
+ }
+ this.name = ident;
+ this.tiargs = tiargs;
+ }
+
+ /*****************
+ * This constructor is only called when we figured out which function
+ * template to instantiate.
+ */
+ extern (D) this(const ref Loc loc, TemplateDeclaration td, Objects* tiargs)
+ {
+ super(loc, null);
+ static if (LOG)
+ {
+ printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td.toChars());
+ }
+ this.name = td.ident;
+ this.tiargs = tiargs;
+ this.tempdecl = td;
+ this.semantictiargsdone = true;
+ this.havetempdecl = true;
+ assert(tempdecl._scope);
+ }
+
+ extern (D) static Objects* arraySyntaxCopy(Objects* objs)
+ {
+ Objects* a = null;
+ if (objs)
+ {
+ a = new Objects(objs.dim);
+ foreach (i, o; *objs)
+ (*a)[i] = objectSyntaxCopy(o);
+ }
+ return a;
+ }
+
+ override TemplateInstance syntaxCopy(Dsymbol s)
+ {
+ TemplateInstance ti = s ? cast(TemplateInstance)s : new TemplateInstance(loc, name, null);
+ ti.tiargs = arraySyntaxCopy(tiargs);
+ TemplateDeclaration td;
+ if (inst && tempdecl && (td = tempdecl.isTemplateDeclaration()) !is null)
+ td.ScopeDsymbol.syntaxCopy(ti);
+ else
+ ScopeDsymbol.syntaxCopy(ti);
+ return ti;
+ }
+
+ // resolve real symbol
+ override final Dsymbol toAlias()
+ {
+ static if (LOG)
+ {
+ printf("TemplateInstance.toAlias()\n");
+ }
+ if (!inst)
+ {
+ // Maybe we can resolve it
+ if (_scope)
+ {
+ dsymbolSemantic(this, _scope);
+ }
+ if (!inst)
+ {
+ error("cannot resolve forward reference");
+ errors = true;
+ return this;
+ }
+ }
+
+ if (inst != this)
+ return inst.toAlias();
+
+ if (aliasdecl)
+ {
+ return aliasdecl.toAlias();
+ }
+
+ return inst;
+ }
+
+ override const(char)* kind() const
+ {
+ return "template instance";
+ }
+
+ override bool oneMember(Dsymbol* ps, Identifier ident)
+ {
+ *ps = null;
+ return true;
+ }
+
+ override const(char)* toChars() const
+ {
+ OutBuffer buf;
+ toCBufferInstance(this, &buf);
+ return buf.extractChars();
+ }
+
+ override final const(char)* toPrettyCharsHelper()
+ {
+ OutBuffer buf;
+ toCBufferInstance(this, &buf, true);
+ return buf.extractChars();
+ }
+
+ /**************************************
+ * Given an error instantiating the TemplateInstance,
+ * give the nested TemplateInstance instantiations that got
+ * us here. Those are a list threaded into the nested scopes.
+ */
+ extern(D) final void printInstantiationTrace(Classification cl = Classification.error)
+ {
+ if (global.gag)
+ return;
+
+ // Print full trace for verbose mode, otherwise only short traces
+ const(uint) max_shown = !global.params.verbose ? 6 : uint.max;
+ const(char)* format = "instantiated from here: `%s`";
+
+ // This returns a function pointer
+ scope printFn = () {
+ final switch (cl)
+ {
+ case Classification.error:
+ return &errorSupplemental;
+ case Classification.warning:
+ return &warningSupplemental;
+ case Classification.deprecation:
+ return &deprecationSupplemental;
+ case Classification.gagged, Classification.tip:
+ assert(0);
+ }
+ }();
+
+ // determine instantiation depth and number of recursive instantiations
+ int n_instantiations = 1;
+ int n_totalrecursions = 0;
+ for (TemplateInstance cur = this; cur; cur = cur.tinst)
+ {
+ ++n_instantiations;
+ // Set error here as we don't want it to depend on the number of
+ // entries that are being printed.
+ if (cl == Classification.error ||
+ (cl == Classification.warning && global.params.warnings == DiagnosticReporting.error) ||
+ (cl == Classification.deprecation && global.params.useDeprecated == DiagnosticReporting.error))
+ cur.errors = true;
+
+ // If two instantiations use the same declaration, they are recursive.
+ // (this works even if they are instantiated from different places in the
+ // same template).
+ // In principle, we could also check for multiple-template recursion, but it's
+ // probably not worthwhile.
+ if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
+ ++n_totalrecursions;
+ }
+
+ if (n_instantiations <= max_shown)
+ {
+ for (TemplateInstance cur = this; cur; cur = cur.tinst)
+ printFn(cur.loc, format, cur.toChars());
+ }
+ else if (n_instantiations - n_totalrecursions <= max_shown)
+ {
+ // By collapsing recursive instantiations into a single line,
+ // we can stay under the limit.
+ int recursionDepth = 0;
+ for (TemplateInstance cur = this; cur; cur = cur.tinst)
+ {
+ if (cur.tinst && cur.tempdecl && cur.tinst.tempdecl && cur.tempdecl.loc.equals(cur.tinst.tempdecl.loc))
+ {
+ ++recursionDepth;
+ }
+ else
+ {
+ if (recursionDepth)
+ printFn(cur.loc, "%d recursive instantiations from here: `%s`", recursionDepth + 2, cur.toChars());
+ else
+ printFn(cur.loc, format, cur.toChars());
+ recursionDepth = 0;
+ }
+ }
+ }
+ else
+ {
+ // Even after collapsing the recursions, the depth is too deep.
+ // Just display the first few and last few instantiations.
+ uint i = 0;
+ for (TemplateInstance cur = this; cur; cur = cur.tinst)
+ {
+ if (i == max_shown / 2)
+ printFn(cur.loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown);
+
+ if (i < max_shown / 2 || i >= n_instantiations - max_shown + max_shown / 2)
+ printFn(cur.loc, format, cur.toChars());
+ ++i;
+ }
+ }
+ }
+
+ /*************************************
+ * Lazily generate identifier for template instance.
+ * This is because 75% of the ident's are never needed.
+ */
+ override final Identifier getIdent()
+ {
+ if (!ident && inst && !errors)
+ ident = genIdent(tiargs); // need an identifier for name mangling purposes.
+ return ident;
+ }
+
+ /*************************************
+ * Compare proposed template instantiation with existing template instantiation.
+ * Note that this is not commutative because of the auto ref check.
+ * Params:
+ * ti = existing template instantiation
+ * Returns:
+ * true for match
+ */
+ final bool equalsx(TemplateInstance ti)
+ {
+ //printf("this = %p, ti = %p\n", this, ti);
+ assert(tdtypes.dim == ti.tdtypes.dim);
+
+ // Nesting must match
+ if (enclosing != ti.enclosing)
+ {
+ //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : "");
+ goto Lnotequals;
+ }
+ //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
+
+ if (!arrayObjectMatch(&tdtypes, &ti.tdtypes))
+ goto Lnotequals;
+
+ /* Template functions may have different instantiations based on
+ * "auto ref" parameters.
+ */
+ if (auto fd = ti.toAlias().isFuncDeclaration())
+ {
+ if (!fd.errors)
+ {
+ auto fparameters = fd.getParameterList();
+ size_t nfparams = fparameters.length; // Num function parameters
+ for (size_t j = 0; j < nfparams; j++)
+ {
+ Parameter fparam = fparameters[j];
+ if (fparam.storageClass & STC.autoref) // if "auto ref"
+ {
+ Expression farg = fargs && j < fargs.dim ? (*fargs)[j] : fparam.defaultArg;
+ if (!farg)
+ goto Lnotequals;
+ if (farg.isLvalue())
+ {
+ if (!(fparam.storageClass & STC.ref_))
+ goto Lnotequals; // auto ref's don't match
+ }
+ else
+ {
+ if (fparam.storageClass & STC.ref_)
+ goto Lnotequals; // auto ref's don't match
+ }
+ }
+ }
+ }
+ }
+ return true;
+
+ Lnotequals:
+ return false;
+ }
+
+ final size_t toHash()
+ {
+ if (!hash)
+ {
+ hash = cast(size_t)cast(void*)enclosing;
+ hash += arrayObjectHash(&tdtypes);
+ hash += hash == 0;
+ }
+ return hash;
+ }
+
+ /**
+ Returns: true if the instances' innards are discardable.
+
+ The idea of this function is to see if the template instantiation
+ can be 100% replaced with its eponymous member. All other members
+ can be discarded, even in the compiler to free memory (for example,
+ the template could be expanded in a region allocator, deemed trivial,
+ the end result copied back out independently and the entire region freed),
+ and can be elided entirely from the binary.
+
+ The current implementation affects code that generally looks like:
+
+ ---
+ template foo(args...) {
+ some_basic_type_or_string helper() { .... }
+ enum foo = helper();
+ }
+ ---
+
+ since it was the easiest starting point of implementation but it can and
+ should be expanded more later.
+ */
+ final bool isDiscardable()
+ {
+ if (aliasdecl is null)
+ return false;
+
+ auto v = aliasdecl.isVarDeclaration();
+ if (v is null)
+ return false;
+
+ if (!(v.storage_class & STC.manifest))
+ return false;
+
+ // Currently only doing basic types here because it is the easiest proof-of-concept
+ // implementation with minimal risk of side effects, but it could likely be
+ // expanded to any type that already exists outside this particular instance.
+ if (!(v.type.equals(Type.tstring) || (v.type.isTypeBasic() !is null)))
+ return false;
+
+ // Static ctors and dtors, even in an eponymous enum template, are still run,
+ // so if any of them are in here, we'd better not assume it is trivial lest
+ // we break useful code
+ foreach(member; *members)
+ {
+ if(member.hasStaticCtorOrDtor())
+ return false;
+ if(member.isStaticDtorDeclaration())
+ return false;
+ if(member.isStaticCtorDeclaration())
+ return false;
+ }
+
+ // but if it passes through this gauntlet... it should be fine. D code will
+ // see only the eponymous member, outside stuff can never access it, even through
+ // reflection; the outside world ought to be none the wiser. Even dmd should be
+ // able to simply free the memory of everything except the final result.
+
+ return true;
+ }
+
+
+ /***********************************************
+ * Returns true if this is not instantiated in non-root module, and
+ * is a part of non-speculative instantiatiation.
+ *
+ * Note: minst does not stabilize until semantic analysis is completed,
+ * so don't call this function during semantic analysis to return precise result.
+ */
+ final bool needsCodegen()
+ {
+ if (!minst)
+ {
+ // If this is a speculative instantiation,
+ // 1. do codegen if ancestors really needs codegen.
+ // 2. become non-speculative if siblings are not speculative
+
+ TemplateInstance tnext = this.tnext;
+ TemplateInstance tinst = this.tinst;
+ // At first, disconnect chain first to prevent infinite recursion.
+ this.tnext = null;
+ this.tinst = null;
+
+ // Determine necessity of tinst before tnext.
+ if (tinst && tinst.needsCodegen())
+ {
+ minst = tinst.minst; // cache result
+ if (global.params.allInst && minst)
+ {
+ return true;
+ }
+ assert(minst);
+ assert(minst.isRoot() || minst.rootImports());
+ return true;
+ }
+ if (tnext && (tnext.needsCodegen() || tnext.minst))
+ {
+ minst = tnext.minst; // cache result
+ if (global.params.allInst && minst)
+ {
+ return true;
+ }
+ assert(minst);
+ return minst.isRoot() || minst.rootImports();
+ }
+
+ // Elide codegen because this is really speculative.
+ return false;
+ }
+
+ if (global.params.allInst)
+ {
+ return true;
+ }
+
+ if (isDiscardable())
+ {
+ return false;
+ }
+
+ /* Even when this is reached to the codegen pass,
+ * a non-root nested template should not generate code,
+ * due to avoid ODR violation.
+ */
+ if (enclosing && enclosing.inNonRoot())
+ {
+ if (tinst)
+ {
+ auto r = tinst.needsCodegen();
+ minst = tinst.minst; // cache result
+ return r;
+ }
+ if (tnext)
+ {
+ auto r = tnext.needsCodegen();
+ minst = tnext.minst; // cache result
+ return r;
+ }
+ return false;
+ }
+
+ if (global.params.useUnitTests)
+ {
+ // Prefer instantiations from root modules, to maximize link-ability.
+ if (minst.isRoot())
+ return true;
+
+ TemplateInstance tnext = this.tnext;
+ TemplateInstance tinst = this.tinst;
+ this.tnext = null;
+ this.tinst = null;
+
+ if (tinst && tinst.needsCodegen())
+ {
+ minst = tinst.minst; // cache result
+ assert(minst);
+ assert(minst.isRoot() || minst.rootImports());
+ return true;
+ }
+ if (tnext && tnext.needsCodegen())
+ {
+ minst = tnext.minst; // cache result
+ assert(minst);
+ assert(minst.isRoot() || minst.rootImports());
+ return true;
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=2500 case
+ if (minst.rootImports())
+ return true;
+
+ // Elide codegen because this is not included in root instances.
+ return false;
+ }
+ else
+ {
+ // Prefer instantiations from non-root module, to minimize object code size.
+
+ /* If a TemplateInstance is ever instantiated by non-root modules,
+ * we do not have to generate code for it,
+ * because it will be generated when the non-root module is compiled.
+ *
+ * But, if the non-root 'minst' imports any root modules, it might still need codegen.
+ *
+ * The problem is if A imports B, and B imports A, and both A
+ * and B instantiate the same template, does the compilation of A
+ * or the compilation of B do the actual instantiation?
+ *
+ * See https://issues.dlang.org/show_bug.cgi?id=2500.
+ */
+ if (!minst.isRoot() && !minst.rootImports())
+ return false;
+
+ TemplateInstance tnext = this.tnext;
+ this.tnext = null;
+
+ if (tnext && !tnext.needsCodegen() && tnext.minst)
+ {
+ minst = tnext.minst; // cache result
+ assert(!minst.isRoot());
+ return false;
+ }
+
+ // Do codegen because this is not included in non-root instances.
+ return true;
+ }
+ }
+
+ /**********************************************
+ * Find template declaration corresponding to template instance.
+ *
+ * Returns:
+ * false if finding fails.
+ * Note:
+ * This function is reentrant against error occurrence. If returns false,
+ * any members of this object won't be modified, and repetition call will
+ * reproduce same error.
+ */
+ extern (D) final bool findTempDecl(Scope* sc, WithScopeSymbol* pwithsym)
+ {
+ if (pwithsym)
+ *pwithsym = null;
+
+ if (havetempdecl)
+ return true;
+
+ //printf("TemplateInstance.findTempDecl() %s\n", toChars());
+ if (!tempdecl)
+ {
+ /* Given:
+ * foo!( ... )
+ * figure out which TemplateDeclaration foo refers to.
+ */
+ Identifier id = name;
+ Dsymbol scopesym;
+ Dsymbol s = sc.search(loc, id, &scopesym);
+ if (!s)
+ {
+ s = sc.search_correct(id);
+ if (s)
+ error("template `%s` is not defined, did you mean %s?", id.toChars(), s.toChars());
+ else
+ error("template `%s` is not defined", id.toChars());
+ return false;
+ }
+ static if (LOG)
+ {
+ printf("It's an instance of '%s' kind '%s'\n", s.toChars(), s.kind());
+ if (s.parent)
+ printf("s.parent = '%s'\n", s.parent.toChars());
+ }
+ if (pwithsym)
+ *pwithsym = scopesym.isWithScopeSymbol();
+
+ /* We might have found an alias within a template when
+ * we really want the template.
+ */
+ TemplateInstance ti;
+ if (s.parent && (ti = s.parent.isTemplateInstance()) !is null)
+ {
+ if (ti.tempdecl && ti.tempdecl.ident == id)
+ {
+ /* This is so that one can refer to the enclosing
+ * template, even if it has the same name as a member
+ * of the template, if it has a !(arguments)
+ */
+ TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
+ assert(td);
+ if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
+ td = td.overroot; // then get the start
+ s = td;
+ }
+ }
+
+ // The template might originate from a selective import which implies that
+ // s is a lowered AliasDeclaration of the actual TemplateDeclaration.
+ // This is the last place where we see the deprecated alias because it is
+ // stripped below, so check if the selective import was deprecated.
+ // See https://issues.dlang.org/show_bug.cgi?id=20840.
+ if (s.isAliasDeclaration())
+ s.checkDeprecated(this.loc, sc);
+
+ if (!updateTempDecl(sc, s))
+ {
+ return false;
+ }
+ }
+ assert(tempdecl);
+
+ // Look for forward references
+ auto tovers = tempdecl.isOverloadSet();
+ foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
+ {
+ Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
+ int r = overloadApply(dstart, (Dsymbol s)
+ {
+ auto td = s.isTemplateDeclaration();
+ if (!td)
+ return 0;
+
+ if (td.semanticRun == PASS.init)
+ {
+ if (td._scope)
+ {
+ // Try to fix forward reference. Ungag errors while doing so.
+ Ungag ungag = td.ungagSpeculative();
+ td.dsymbolSemantic(td._scope);
+ }
+ if (td.semanticRun == PASS.init)
+ {
+ error("`%s` forward references template declaration `%s`",
+ toChars(), td.toChars());
+ return 1;
+ }
+ }
+ return 0;
+ });
+ if (r)
+ return false;
+ }
+ return true;
+ }
+
+ /**********************************************
+ * Confirm s is a valid template, then store it.
+ * Input:
+ * sc
+ * s candidate symbol of template. It may be:
+ * TemplateDeclaration
+ * FuncDeclaration with findTemplateDeclRoot() != NULL
+ * OverloadSet which contains candidates
+ * Returns:
+ * true if updating succeeds.
+ */
+ extern (D) final bool updateTempDecl(Scope* sc, Dsymbol s)
+ {
+ if (!s)
+ return tempdecl !is null;
+
+ Identifier id = name;
+ s = s.toAlias();
+
+ /* If an OverloadSet, look for a unique member that is a template declaration
+ */
+ if (OverloadSet os = s.isOverloadSet())
+ {
+ s = null;
+ foreach (s2; os.a)
+ {
+ if (FuncDeclaration f = s2.isFuncDeclaration())
+ s2 = f.findTemplateDeclRoot();
+ else
+ s2 = s2.isTemplateDeclaration();
+ if (s2)
+ {
+ if (s)
+ {
+ tempdecl = os;
+ return true;
+ }
+ s = s2;
+ }
+ }
+ if (!s)
+ {
+ error("template `%s` is not defined", id.toChars());
+ return false;
+ }
+ }
+
+ if (OverDeclaration od = s.isOverDeclaration())
+ {
+ tempdecl = od; // TODO: more strict check
+ return true;
+ }
+
+ /* It should be a TemplateDeclaration, not some other symbol
+ */
+ if (FuncDeclaration f = s.isFuncDeclaration())
+ tempdecl = f.findTemplateDeclRoot();
+ else
+ tempdecl = s.isTemplateDeclaration();
+
+ // We're done
+ if (tempdecl)
+ return true;
+
+ // Error already issued, just return `false`
+ if (!s.parent && global.errors)
+ return false;
+
+ if (!s.parent && s.getType())
+ {
+ Dsymbol s2 = s.getType().toDsymbol(sc);
+ if (!s2)
+ {
+ .error(loc, "`%s` is not a valid template instance, because `%s` is not a template declaration but a type (`%s == %s`)", toChars(), id.toChars(), id.toChars(), s.getType.kind());
+ return false;
+ }
+ // because s can be the alias created for a TemplateParameter
+ const AliasDeclaration ad = s.isAliasDeclaration();
+ version (none)
+ {
+ if (ad && ad.isAliasedTemplateParameter())
+ printf("`%s` is an alias created from a template parameter\n", s.toChars());
+ }
+ if (!ad || !ad.isAliasedTemplateParameter())
+ s = s2;
+ }
+
+ TemplateInstance ti = s.parent ? s.parent.isTemplateInstance() : null;
+ if (ti && (ti.name == s.ident || ti.toAlias().ident == s.ident) && ti.tempdecl)
+ {
+ /* This is so that one can refer to the enclosing
+ * template, even if it has the same name as a member
+ * of the template, if it has a !(arguments)
+ */
+ TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
+ assert(td);
+ if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
+ td = td.overroot; // then get the start
+ tempdecl = td;
+ return true;
+ }
+ else
+ {
+ error("`%s` is not a template declaration, it is a %s", id.toChars(), s.kind());
+ return false;
+ }
+ }
+
+ /**********************************
+ * Run semantic of tiargs as arguments of template.
+ * Input:
+ * loc
+ * sc
+ * tiargs array of template arguments
+ * flags 1: replace const variables with their initializers
+ * 2: don't devolve Parameter to Type
+ * Returns:
+ * false if one or more arguments have errors.
+ */
+ extern (D) static bool semanticTiargs(const ref Loc loc, Scope* sc, Objects* tiargs, int flags)
+ {
+ // Run semantic on each argument, place results in tiargs[]
+ //printf("+TemplateInstance.semanticTiargs()\n");
+ if (!tiargs)
+ return true;
+ bool err = false;
+ for (size_t j = 0; j < tiargs.dim; j++)
+ {
+ RootObject o = (*tiargs)[j];
+ Type ta = isType(o);
+ Expression ea = isExpression(o);
+ Dsymbol sa = isDsymbol(o);
+
+ //printf("1: (*tiargs)[%d] = %p, s=%p, v=%p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta);
+ if (ta)
+ {
+ //printf("type %s\n", ta.toChars());
+
+ // It might really be an Expression or an Alias
+ ta.resolve(loc, sc, ea, ta, sa, (flags & 1) != 0);
+ if (ea)
+ goto Lexpr;
+ if (sa)
+ goto Ldsym;
+ if (ta is null)
+ {
+ assert(global.errors);
+ ta = Type.terror;
+ }
+
+ Ltype:
+ if (ta.ty == Ttuple)
+ {
+ // Expand tuple
+ TypeTuple tt = cast(TypeTuple)ta;
+ size_t dim = tt.arguments.dim;
+ tiargs.remove(j);
+ if (dim)
+ {
+ tiargs.reserve(dim);
+ foreach (i, arg; *tt.arguments)
+ {
+ if (flags & 2 && (arg.storageClass & STC.parameter))
+ tiargs.insert(j + i, arg);
+ else
+ tiargs.insert(j + i, arg.type);
+ }
+ }
+ j--;
+ continue;
+ }
+ if (ta.ty == Terror)
+ {
+ err = true;
+ continue;
+ }
+ (*tiargs)[j] = ta.merge2();
+ }
+ else if (ea)
+ {
+ Lexpr:
+ //printf("+[%d] ea = %s %s\n", j, Token.toChars(ea.op), ea.toChars());
+ if (flags & 1) // only used by __traits
+ {
+ ea = ea.expressionSemantic(sc);
+
+ // must not interpret the args, excepting template parameters
+ if (ea.op != TOK.variable || ((cast(VarExp)ea).var.storage_class & STC.templateparameter))
+ {
+ ea = ea.optimize(WANTvalue);
+ }
+ }
+ else
+ {
+ sc = sc.startCTFE();
+ ea = ea.expressionSemantic(sc);
+ sc = sc.endCTFE();
+
+ if (ea.op == TOK.variable)
+ {
+ /* If the parameter is a function that is not called
+ * explicitly, i.e. `foo!func` as opposed to `foo!func()`,
+ * then it is a dsymbol, not the return value of `func()`
+ */
+ Declaration vd = (cast(VarExp)ea).var;
+ if (auto fd = vd.isFuncDeclaration())
+ {
+ sa = fd;
+ goto Ldsym;
+ }
+ /* Otherwise skip substituting a const var with
+ * its initializer. The problem is the initializer won't
+ * match with an 'alias' parameter. Instead, do the
+ * const substitution in TemplateValueParameter.matchArg().
+ */
+ }
+ else if (definitelyValueParameter(ea))
+ {
+ if (ea.checkValue()) // check void expression
+ ea = ErrorExp.get();
+ uint olderrs = global.errors;
+ ea = ea.ctfeInterpret();
+ if (global.errors != olderrs)
+ ea = ErrorExp.get();
+ }
+ }
+ //printf("-[%d] ea = %s %s\n", j, Token.toChars(ea.op), ea.toChars());
+ if (ea.op == TOK.tuple)
+ {
+ // Expand tuple
+ TupleExp te = cast(TupleExp)ea;
+ size_t dim = te.exps.dim;
+ tiargs.remove(j);
+ if (dim)
+ {
+ tiargs.reserve(dim);
+ foreach (i, exp; *te.exps)
+ tiargs.insert(j + i, exp);
+ }
+ j--;
+ continue;
+ }
+ if (ea.op == TOK.error)
+ {
+ err = true;
+ continue;
+ }
+ (*tiargs)[j] = ea;
+
+ if (ea.op == TOK.type)
+ {
+ ta = ea.type;
+ goto Ltype;
+ }
+ if (ea.op == TOK.scope_)
+ {
+ sa = (cast(ScopeExp)ea).sds;
+ goto Ldsym;
+ }
+ if (ea.op == TOK.function_)
+ {
+ FuncExp fe = cast(FuncExp)ea;
+ /* A function literal, that is passed to template and
+ * already semanticed as function pointer, never requires
+ * outer frame. So convert it to global function is valid.
+ */
+ if (fe.fd.tok == TOK.reserved && fe.type.ty == Tpointer)
+ {
+ // change to non-nested
+ fe.fd.tok = TOK.function_;
+ fe.fd.vthis = null;
+ }
+ else if (fe.td)
+ {
+ /* If template argument is a template lambda,
+ * get template declaration itself. */
+ //sa = fe.td;
+ //goto Ldsym;
+ }
+ }
+ if (ea.op == TOK.dotVariable && !(flags & 1))
+ {
+ // translate expression to dsymbol.
+ sa = (cast(DotVarExp)ea).var;
+ goto Ldsym;
+ }
+ if (ea.op == TOK.template_)
+ {
+ sa = (cast(TemplateExp)ea).td;
+ goto Ldsym;
+ }
+ if (ea.op == TOK.dotTemplateDeclaration && !(flags & 1))
+ {
+ // translate expression to dsymbol.
+ sa = (cast(DotTemplateExp)ea).td;
+ goto Ldsym;
+ }
+ if (ea.op == TOK.dot)
+ {
+ if (auto se = (cast(DotExp)ea).e2.isScopeExp())
+ {
+ sa = se.sds;
+ goto Ldsym;
+ }
+ }
+ }
+ else if (sa)
+ {
+ Ldsym:
+ //printf("dsym %s %s\n", sa.kind(), sa.toChars());
+ if (sa.errors)
+ {
+ err = true;
+ continue;
+ }
+
+ TupleDeclaration d = sa.toAlias().isTupleDeclaration();
+ if (d)
+ {
+ // Expand tuple
+ tiargs.remove(j);
+ tiargs.insert(j, d.objects);
+ j--;
+ continue;
+ }
+ if (FuncAliasDeclaration fa = sa.isFuncAliasDeclaration())
+ {
+ FuncDeclaration f = fa.toAliasFunc();
+ if (!fa.hasOverloads && f.isUnique())
+ {
+ // Strip FuncAlias only when the aliased function
+ // does not have any overloads.
+ sa = f;
+ }
+ }
+ (*tiargs)[j] = sa;
+
+ TemplateDeclaration td = sa.isTemplateDeclaration();
+ if (td && td.semanticRun == PASS.init && td.literal)
+ {
+ td.dsymbolSemantic(sc);
+ }
+ FuncDeclaration fd = sa.isFuncDeclaration();
+ if (fd)
+ fd.functionSemantic();
+ }
+ else if (isParameter(o))
+ {
+ }
+ else
+ {
+ assert(0);
+ }
+ //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
+ }
+ version (none)
+ {
+ printf("-TemplateInstance.semanticTiargs()\n");
+ for (size_t j = 0; j < tiargs.dim; j++)
+ {
+ RootObject o = (*tiargs)[j];
+ Type ta = isType(o);
+ Expression ea = isExpression(o);
+ Dsymbol sa = isDsymbol(o);
+ Tuple va = isTuple(o);
+ printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va);
+ }
+ }
+ return !err;
+ }
+
+ /**********************************
+ * Run semantic on the elements of tiargs.
+ * Input:
+ * sc
+ * Returns:
+ * false if one or more arguments have errors.
+ * Note:
+ * This function is reentrant against error occurrence. If returns false,
+ * all elements of tiargs won't be modified.
+ */
+ extern (D) final bool semanticTiargs(Scope* sc)
+ {
+ //printf("+TemplateInstance.semanticTiargs() %s\n", toChars());
+ if (semantictiargsdone)
+ return true;
+ if (semanticTiargs(loc, sc, tiargs, 0))
+ {
+ // cache the result iff semantic analysis succeeded entirely
+ semantictiargsdone = 1;
+ return true;
+ }
+ return false;
+ }
+
+ /**********************************
+ * Find the TemplateDeclaration that matches this TemplateInstance best.
+ *
+ * Params:
+ * sc = the scope this TemplateInstance resides in
+ * fargs = function arguments in case of a template function, null otherwise
+ *
+ * Returns:
+ * `true` if a match was found, `false` otherwise
+ */
+ extern (D) final bool findBestMatch(Scope* sc, Expressions* fargs)
+ {
+ if (havetempdecl)
+ {
+ TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();
+ assert(tempdecl);
+ assert(tempdecl._scope);
+ // Deduce tdtypes
+ tdtypes.setDim(tempdecl.parameters.dim);
+ if (!tempdecl.matchWithInstance(sc, this, &tdtypes, fargs, 2))
+ {
+ error("incompatible arguments for template instantiation");
+ return false;
+ }
+ // TODO: Normalizing tiargs for https://issues.dlang.org/show_bug.cgi?id=7469 is necessary?
+ return true;
+ }
+
+ static if (LOG)
+ {
+ printf("TemplateInstance.findBestMatch()\n");
+ }
+
+ uint errs = global.errors;
+ TemplateDeclaration td_last = null;
+ Objects dedtypes;
+
+ /* Since there can be multiple TemplateDeclaration's with the same
+ * name, look for the best match.
+ */
+ auto tovers = tempdecl.isOverloadSet();
+ foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
+ {
+ TemplateDeclaration td_best;
+ TemplateDeclaration td_ambig;
+ MATCH m_best = MATCH.nomatch;
+
+ Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
+ overloadApply(dstart, (Dsymbol s)
+ {
+ auto td = s.isTemplateDeclaration();
+ if (!td)
+ return 0;
+ if (td.inuse)
+ {
+ td.error(loc, "recursive template expansion");
+ return 1;
+ }
+ if (td == td_best) // skip duplicates
+ return 0;
+
+ //printf("td = %s\n", td.toPrettyChars());
+ // If more arguments than parameters,
+ // then this is no match.
+ if (td.parameters.dim < tiargs.dim)
+ {
+ if (!td.isVariadic())
+ return 0;
+ }
+
+ dedtypes.setDim(td.parameters.dim);
+ dedtypes.zero();
+ assert(td.semanticRun != PASS.init);
+
+ MATCH m = td.matchWithInstance(sc, this, &dedtypes, fargs, 0);
+ //printf("matchWithInstance = %d\n", m);
+ if (m == MATCH.nomatch) // no match at all
+ return 0;
+ if (m < m_best) goto Ltd_best;
+ if (m > m_best) goto Ltd;
+
+ // Disambiguate by picking the most specialized TemplateDeclaration
+ {
+ MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs);
+ MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs);
+ //printf("c1 = %d, c2 = %d\n", c1, c2);
+ if (c1 > c2) goto Ltd;
+ if (c1 < c2) goto Ltd_best;
+ }
+
+ td_ambig = td;
+ return 0;
+
+ Ltd_best:
+ // td_best is the best match so far
+ td_ambig = null;
+ return 0;
+
+ Ltd:
+ // td is the new best match
+ td_ambig = null;
+ td_best = td;
+ m_best = m;
+ tdtypes.setDim(dedtypes.dim);
+ memcpy(tdtypes.tdata(), dedtypes.tdata(), tdtypes.dim * (void*).sizeof);
+ return 0;
+ });
+
+ if (td_ambig)
+ {
+ .error(loc, "%s `%s.%s` matches more than one template declaration:\n%s: `%s`\nand\n%s: `%s`",
+ td_best.kind(), td_best.parent.toPrettyChars(), td_best.ident.toChars(),
+ td_best.loc.toChars(), td_best.toChars(),
+ td_ambig.loc.toChars(), td_ambig.toChars());
+ return false;
+ }
+ if (td_best)
+ {
+ if (!td_last)
+ td_last = td_best;
+ else if (td_last != td_best)
+ {
+ ScopeDsymbol.multiplyDefined(loc, td_last, td_best);
+ return false;
+ }
+ }
+ }
+
+ if (td_last)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=7469
+ * Normalize tiargs by using corresponding deduced
+ * template value parameters and tuples for the correct mangling.
+ *
+ * By doing this before hasNestedArgs, CTFEable local variable will be
+ * accepted as a value parameter. For example:
+ *
+ * void foo() {
+ * struct S(int n) {} // non-global template
+ * const int num = 1; // CTFEable local variable
+ * S!num s; // S!1 is instantiated, not S!num
+ * }
+ */
+ size_t dim = td_last.parameters.dim - (td_last.isVariadic() ? 1 : 0);
+ for (size_t i = 0; i < dim; i++)
+ {
+ if (tiargs.dim <= i)
+ tiargs.push(tdtypes[i]);
+ assert(i < tiargs.dim);
+
+ auto tvp = (*td_last.parameters)[i].isTemplateValueParameter();
+ if (!tvp)
+ continue;
+ assert(tdtypes[i]);
+ // tdtypes[i] is already normalized to the required type in matchArg
+
+ (*tiargs)[i] = tdtypes[i];
+ }
+ if (td_last.isVariadic() && tiargs.dim == dim && tdtypes[dim])
+ {
+ Tuple va = isTuple(tdtypes[dim]);
+ assert(va);
+ tiargs.pushSlice(va.objects[]);
+ }
+ }
+ else if (errors && inst)
+ {
+ // instantiation was failed with error reporting
+ assert(global.errors);
+ return false;
+ }
+ else
+ {
+ auto tdecl = tempdecl.isTemplateDeclaration();
+
+ if (errs != global.errors)
+ errorSupplemental(loc, "while looking for match for `%s`", toChars());
+ else if (tdecl && !tdecl.overnext)
+ {
+ // Only one template, so we can give better error message
+ const(char)* msg = "does not match template declaration";
+ const(char)* tip;
+ const tmsg = tdecl.toCharsNoConstraints();
+ const cmsg = tdecl.getConstraintEvalError(tip);
+ if (cmsg)
+ {
+ error("%s `%s`\n%s", msg, tmsg, cmsg);
+ if (tip)
+ .tip(tip);
+ }
+ else
+ {
+ error("%s `%s`", msg, tmsg);
+
+ if (tdecl.parameters.dim == tiargs.dim)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=7352
+ // print additional information, e.g. `foo` is not a type
+ foreach (i, param; *tdecl.parameters)
+ {
+ MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, &dedtypes, null);
+ auto arg = (*tiargs)[i];
+ auto sym = arg.isDsymbol;
+ auto exp = arg.isExpression;
+
+ if (exp)
+ exp = exp.optimize(WANTvalue);
+
+ if (match == MATCH.nomatch &&
+ ((sym && sym.isFuncDeclaration) ||
+ (exp && exp.isVarExp)))
+ {
+ if (param.isTemplateTypeParameter)
+ errorSupplemental(loc, "`%s` is not a type", arg.toChars);
+ else if (auto tvp = param.isTemplateValueParameter)
+ errorSupplemental(loc, "`%s` is not of a value of type `%s`",
+ arg.toChars, tvp.valType.toChars);
+
+ }
+ }
+ }
+ }
+ }
+ else
+ .error(loc, "%s `%s.%s` does not match any template declaration", tempdecl.kind(), tempdecl.parent.toPrettyChars(), tempdecl.ident.toChars());
+ return false;
+ }
+
+ /* The best match is td_last
+ */
+ tempdecl = td_last;
+
+ static if (LOG)
+ {
+ printf("\tIt's a match with template declaration '%s'\n", tempdecl.toChars());
+ }
+ return (errs == global.errors);
+ }
+
+ /*****************************************************
+ * Determine if template instance is really a template function,
+ * and that template function needs to infer types from the function
+ * arguments.
+ *
+ * Like findBestMatch, iterate possible template candidates,
+ * but just looks only the necessity of type inference.
+ */
+ extern (D) final bool needsTypeInference(Scope* sc, int flag = 0)
+ {
+ //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
+ if (semanticRun != PASS.init)
+ return false;
+
+ uint olderrs = global.errors;
+ Objects dedtypes;
+ size_t count = 0;
+
+ auto tovers = tempdecl.isOverloadSet();
+ foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
+ {
+ Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
+ int r = overloadApply(dstart, (Dsymbol s)
+ {
+ auto td = s.isTemplateDeclaration();
+ if (!td)
+ return 0;
+ if (td.inuse)
+ {
+ td.error(loc, "recursive template expansion");
+ return 1;
+ }
+
+ /* If any of the overloaded template declarations need inference,
+ * then return true
+ */
+ if (!td.onemember)
+ return 0;
+ if (auto td2 = td.onemember.isTemplateDeclaration())
+ {
+ if (!td2.onemember || !td2.onemember.isFuncDeclaration())
+ return 0;
+ if (tiargs.dim >= td.parameters.dim - (td.isVariadic() ? 1 : 0))
+ return 0;
+ return 1;
+ }
+ auto fd = td.onemember.isFuncDeclaration();
+ if (!fd || fd.type.ty != Tfunction)
+ return 0;
+
+ foreach (tp; *td.parameters)
+ {
+ if (tp.isTemplateThisParameter())
+ return 1;
+ }
+
+ /* Determine if the instance arguments, tiargs, are all that is necessary
+ * to instantiate the template.
+ */
+ //printf("tp = %p, td.parameters.dim = %d, tiargs.dim = %d\n", tp, td.parameters.dim, tiargs.dim);
+ auto tf = cast(TypeFunction)fd.type;
+ if (tf.parameterList.length)
+ {
+ auto tp = td.isVariadic();
+ if (tp && td.parameters.dim > 1)
+ return 1;
+
+ if (!tp && tiargs.dim < td.parameters.dim)
+ {
+ // Can remain tiargs be filled by default arguments?
+ foreach (size_t i; tiargs.dim .. td.parameters.dim)
+ {
+ if (!(*td.parameters)[i].hasDefaultArg())
+ return 1;
+ }
+ }
+
+ foreach (i, fparam; tf.parameterList)
+ {
+ // 'auto ref' needs inference.
+ if (fparam.storageClass & STC.auto_)
+ return 1;
+ }
+ }
+
+ if (!flag)
+ {
+ /* Calculate the need for overload resolution.
+ * When only one template can match with tiargs, inference is not necessary.
+ */
+ dedtypes.setDim(td.parameters.dim);
+ dedtypes.zero();
+ if (td.semanticRun == PASS.init)
+ {
+ if (td._scope)
+ {
+ // Try to fix forward reference. Ungag errors while doing so.
+ Ungag ungag = td.ungagSpeculative();
+ td.dsymbolSemantic(td._scope);
+ }
+ if (td.semanticRun == PASS.init)
+ {
+ error("`%s` forward references template declaration `%s`", toChars(), td.toChars());
+ return 1;
+ }
+ }
+ MATCH m = td.matchWithInstance(sc, this, &dedtypes, null, 0);
+ if (m == MATCH.nomatch)
+ return 0;
+ }
+
+ /* If there is more than one function template which matches, we may
+ * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430)
+ */
+ return ++count > 1 ? 1 : 0;
+ });
+ if (r)
+ return true;
+ }
+
+ if (olderrs != global.errors)
+ {
+ if (!global.gag)
+ {
+ errorSupplemental(loc, "while looking for match for `%s`", toChars());
+ semanticRun = PASS.semanticdone;
+ inst = this;
+ }
+ errors = true;
+ }
+ //printf("false\n");
+ return false;
+ }
+
+ /*****************************************
+ * Determines if a TemplateInstance will need a nested
+ * generation of the TemplateDeclaration.
+ * Sets enclosing property if so, and returns != 0;
+ */
+ extern (D) final bool hasNestedArgs(Objects* args, bool isstatic)
+ {
+ int nested = 0;
+ //printf("TemplateInstance.hasNestedArgs('%s')\n", tempdecl.ident.toChars());
+
+ // arguments from parent instances are also accessible
+ if (!enclosing)
+ {
+ if (TemplateInstance ti = tempdecl.toParent().isTemplateInstance())
+ enclosing = ti.enclosing;
+ }
+
+ /* A nested instance happens when an argument references a local
+ * symbol that is on the stack.
+ */
+ foreach (o; *args)
+ {
+ Expression ea = isExpression(o);
+ Dsymbol sa = isDsymbol(o);
+ Tuple va = isTuple(o);
+ if (ea)
+ {
+ if (ea.op == TOK.variable)
+ {
+ sa = (cast(VarExp)ea).var;
+ goto Lsa;
+ }
+ if (ea.op == TOK.this_)
+ {
+ sa = (cast(ThisExp)ea).var;
+ goto Lsa;
+ }
+ if (ea.op == TOK.function_)
+ {
+ if ((cast(FuncExp)ea).td)
+ sa = (cast(FuncExp)ea).td;
+ else
+ sa = (cast(FuncExp)ea).fd;
+ goto Lsa;
+ }
+ // Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent.
+ if (ea.op != TOK.int64 && ea.op != TOK.float64 && ea.op != TOK.complex80 && ea.op != TOK.null_ && ea.op != TOK.string_ && ea.op != TOK.arrayLiteral && ea.op != TOK.assocArrayLiteral && ea.op != TOK.structLiteral)
+ {
+ ea.error("expression `%s` is not a valid template value argument", ea.toChars());
+ errors = true;
+ }
+ }
+ else if (sa)
+ {
+ Lsa:
+ sa = sa.toAlias();
+ TemplateDeclaration td = sa.isTemplateDeclaration();
+ if (td)
+ {
+ TemplateInstance ti = sa.toParent().isTemplateInstance();
+ if (ti && ti.enclosing)
+ sa = ti;
+ }
+ TemplateInstance ti = sa.isTemplateInstance();
+ Declaration d = sa.isDeclaration();
+ if ((td && td.literal) || (ti && ti.enclosing) || (d && !d.isDataseg() && !(d.storage_class & STC.manifest) && (!d.isFuncDeclaration() || d.isFuncDeclaration().isNested()) && !isTemplateMixin()))
+ {
+ Dsymbol dparent = sa.toParent2();
+ if (!dparent)
+ goto L1;
+ else if (!enclosing)
+ enclosing = dparent;
+ else if (enclosing != dparent)
+ {
+ /* Select the more deeply nested of the two.
+ * Error if one is not nested inside the other.
+ */
+ for (Dsymbol p = enclosing; p; p = p.parent)
+ {
+ if (p == dparent)
+ goto L1; // enclosing is most nested
+ }
+ for (Dsymbol p = dparent; p; p = p.parent)
+ {
+ if (p == enclosing)
+ {
+ enclosing = dparent;
+ goto L1; // dparent is most nested
+ }
+ }
+ error("`%s` is nested in both `%s` and `%s`", toChars(), enclosing.toChars(), dparent.toChars());
+ errors = true;
+ }
+ L1:
+ //printf("\tnested inside %s\n", enclosing.toChars());
+ nested |= 1;
+ }
+ }
+ else if (va)
+ {
+ nested |= cast(int)hasNestedArgs(&va.objects, isstatic);
+ }
+ }
+ //printf("-TemplateInstance.hasNestedArgs('%s') = %d\n", tempdecl.ident.toChars(), nested);
+ return nested != 0;
+ }
+
+ /*****************************************
+ * Append 'this' to the specific module members[]
+ */
+ extern (D) final Dsymbols* appendToModuleMember()
+ {
+ Module mi = minst; // instantiated . inserted module
+
+ if (global.params.useUnitTests)
+ {
+ // Turn all non-root instances to speculative
+ if (mi && !mi.isRoot())
+ mi = null;
+ }
+
+ //printf("%s.appendToModuleMember() enclosing = %s mi = %s\n",
+ // toPrettyChars(),
+ // enclosing ? enclosing.toPrettyChars() : null,
+ // mi ? mi.toPrettyChars() : null);
+ if (!mi || mi.isRoot())
+ {
+ /* If the instantiated module is speculative or root, insert to the
+ * member of a root module. Then:
+ * - semantic3 pass will get called on the instance members.
+ * - codegen pass will get a selection chance to do/skip it.
+ */
+ static Dsymbol getStrictEnclosing(TemplateInstance ti)
+ {
+ do
+ {
+ if (ti.enclosing)
+ return ti.enclosing;
+ ti = ti.tempdecl.isInstantiated();
+ } while (ti);
+ return null;
+ }
+
+ Dsymbol enc = getStrictEnclosing(this);
+ // insert target is made stable by using the module
+ // where tempdecl is declared.
+ mi = (enc ? enc : tempdecl).getModule();
+ if (!mi.isRoot())
+ mi = mi.importedFrom;
+ assert(mi.isRoot());
+ }
+ else
+ {
+ /* If the instantiated module is non-root, insert to the member of the
+ * non-root module. Then:
+ * - semantic3 pass won't be called on the instance.
+ * - codegen pass won't reach to the instance.
+ */
+ }
+ //printf("\t-. mi = %s\n", mi.toPrettyChars());
+
+ if (memberOf is mi) // already a member
+ {
+ debug // make sure it really is a member
+ {
+ auto a = mi.members;
+ for (size_t i = 0; 1; ++i)
+ {
+ assert(i != a.dim);
+ if (this == (*a)[i])
+ break;
+ }
+ }
+ return null;
+ }
+
+ Dsymbols* a = mi.members;
+ a.push(this);
+ memberOf = mi;
+ if (mi.semanticRun >= PASS.semantic2done && mi.isRoot())
+ Module.addDeferredSemantic2(this);
+ if (mi.semanticRun >= PASS.semantic3done && mi.isRoot())
+ Module.addDeferredSemantic3(this);
+ return a;
+ }
+
+ /****************************************************
+ * Declare parameters of template instance, initialize them with the
+ * template instance arguments.
+ */
+ extern (D) final void declareParameters(Scope* sc)
+ {
+ TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration();
+ assert(tempdecl);
+
+ //printf("TemplateInstance.declareParameters()\n");
+ foreach (i, o; tdtypes) // initializer for tp
+ {
+ TemplateParameter tp = (*tempdecl.parameters)[i];
+ //printf("\ttdtypes[%d] = %p\n", i, o);
+ tempdecl.declareParameter(sc, tp, o);
+ }
+ }
+
+ /****************************************
+ * This instance needs an identifier for name mangling purposes.
+ * Create one by taking the template declaration name and adding
+ * the type signature for it.
+ */
+ extern (D) final Identifier genIdent(Objects* args)
+ {
+ //printf("TemplateInstance.genIdent('%s')\n", tempdecl.ident.toChars());
+ assert(args is tiargs);
+ OutBuffer buf;
+ mangleToBuffer(this, &buf);
+ //printf("\tgenIdent = %s\n", buf.peekChars());
+ return Identifier.idPool(buf[]);
+ }
+
+ extern (D) final void expandMembers(Scope* sc2)
+ {
+ members.foreachDsymbol( (s) { s.setScope (sc2); } );
+
+ members.foreachDsymbol( (s) { s.importAll(sc2); } );
+
+ void symbolDg(Dsymbol s)
+ {
+ //printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars());
+ //printf("test: enclosing = %d, sc2.parent = %s\n", enclosing, sc2.parent.toChars());
+ //if (enclosing)
+ // s.parent = sc.parent;
+ //printf("test3: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
+ s.dsymbolSemantic(sc2);
+ //printf("test4: enclosing = %d, s.parent = %s\n", enclosing, s.parent.toChars());
+ Module.runDeferredSemantic();
+ }
+
+ members.foreachDsymbol(&symbolDg);
+ }
+
+ extern (D) final void tryExpandMembers(Scope* sc2)
+ {
+ __gshared int nest;
+ // extracted to a function to allow windows SEH to work without destructors in the same function
+ //printf("%d\n", nest);
+ if (++nest > global.recursionLimit)
+ {
+ global.gag = 0; // ensure error message gets printed
+ error("recursive expansion exceeded allowed nesting limit");
+ fatal();
+ }
+
+ expandMembers(sc2);
+
+ nest--;
+ }
+
+ extern (D) final void trySemantic3(Scope* sc2)
+ {
+ // extracted to a function to allow windows SEH to work without destructors in the same function
+ __gshared int nest;
+ //printf("%d\n", nest);
+ if (++nest > global.recursionLimit)
+ {
+ global.gag = 0; // ensure error message gets printed
+ error("recursive expansion exceeded allowed nesting limit");
+ fatal();
+ }
+
+ semantic3(this, sc2);
+
+ --nest;
+ }
+
+ override final inout(TemplateInstance) isTemplateInstance() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/**************************************
+ * IsExpression can evaluate the specified type speculatively, and even if
+ * it instantiates any symbols, they are normally unnecessary for the
+ * final executable.
+ * However, if those symbols leak to the actual code, compiler should remark
+ * them as non-speculative to generate their code and link to the final executable.
+ */
+void unSpeculative(Scope* sc, RootObject o)
+{
+ if (!o)
+ return;
+
+ if (Tuple tup = isTuple(o))
+ {
+ foreach (obj; tup.objects)
+ {
+ unSpeculative(sc, obj);
+ }
+ return;
+ }
+
+ Dsymbol s = getDsymbol(o);
+ if (!s)
+ return;
+
+ if (Declaration d = s.isDeclaration())
+ {
+ if (VarDeclaration vd = d.isVarDeclaration())
+ o = vd.type;
+ else if (AliasDeclaration ad = d.isAliasDeclaration())
+ {
+ o = ad.getType();
+ if (!o)
+ o = ad.toAlias();
+ }
+ else
+ o = d.toAlias();
+
+ s = getDsymbol(o);
+ if (!s)
+ return;
+ }
+
+ if (TemplateInstance ti = s.isTemplateInstance())
+ {
+ // If the instance is already non-speculative,
+ // or it is leaked to the speculative scope.
+ if (ti.minst !is null || sc.minst is null)
+ return;
+
+ // Remark as non-speculative instance.
+ ti.minst = sc.minst;
+ if (!ti.tinst)
+ ti.tinst = sc.tinst;
+
+ unSpeculative(sc, ti.tempdecl);
+ }
+
+ if (TemplateInstance ti = s.isInstantiated())
+ unSpeculative(sc, ti);
+}
+
+/**********************************
+ * Return true if e could be valid only as a template value parameter.
+ * Return false if it might be an alias or tuple.
+ * (Note that even in this case, it could still turn out to be a value).
+ */
+bool definitelyValueParameter(Expression e)
+{
+ // None of these can be value parameters
+ if (e.op == TOK.tuple || e.op == TOK.scope_ ||
+ e.op == TOK.type || e.op == TOK.dotType ||
+ e.op == TOK.template_ || e.op == TOK.dotTemplateDeclaration ||
+ e.op == TOK.function_ || e.op == TOK.error ||
+ e.op == TOK.this_ || e.op == TOK.super_ ||
+ e.op == TOK.dot)
+ return false;
+
+ if (e.op != TOK.dotVariable)
+ return true;
+
+ /* Template instantiations involving a DotVar expression are difficult.
+ * In most cases, they should be treated as a value parameter, and interpreted.
+ * But they might also just be a fully qualified name, which should be treated
+ * as an alias.
+ */
+
+ // x.y.f cannot be a value
+ FuncDeclaration f = (cast(DotVarExp)e).var.isFuncDeclaration();
+ if (f)
+ return false;
+
+ while (e.op == TOK.dotVariable)
+ {
+ e = (cast(DotVarExp)e).e1;
+ }
+ // this.x.y and super.x.y couldn't possibly be valid values.
+ if (e.op == TOK.this_ || e.op == TOK.super_)
+ return false;
+
+ // e.type.x could be an alias
+ if (e.op == TOK.dotType)
+ return false;
+
+ // var.x.y is the only other possible form of alias
+ if (e.op != TOK.variable)
+ return true;
+
+ VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
+ // func.x.y is not an alias
+ if (!v)
+ return true;
+
+ // https://issues.dlang.org/show_bug.cgi?id=16685
+ // var.x.y where var is a constant available at compile time
+ if (v.storage_class & STC.manifest)
+ return true;
+
+ // TODO: Should we force CTFE if it is a global constant?
+ return false;
+}
+
+/***********************************************************
+ * https://dlang.org/spec/template-mixin.html
+ * Syntax:
+ * mixin MixinTemplateName [TemplateArguments] [Identifier];
+ */
+extern (C++) final class TemplateMixin : TemplateInstance
+{
+ TypeQualified tqual;
+
+ extern (D) this(const ref Loc loc, Identifier ident, TypeQualified tqual, Objects* tiargs)
+ {
+ super(loc,
+ tqual.idents.dim ? cast(Identifier)tqual.idents[tqual.idents.dim - 1] : (cast(TypeIdentifier)tqual).ident,
+ tiargs ? tiargs : new Objects());
+ //printf("TemplateMixin(ident = '%s')\n", ident ? ident.toChars() : "");
+ this.ident = ident;
+ this.tqual = tqual;
+ }
+
+ override TemplateInstance syntaxCopy(Dsymbol s)
+ {
+ auto tm = new TemplateMixin(loc, ident, tqual.syntaxCopy(), tiargs);
+ return TemplateInstance.syntaxCopy(tm);
+ }
+
+ override const(char)* kind() const
+ {
+ return "mixin";
+ }
+
+ override bool oneMember(Dsymbol* ps, Identifier ident)
+ {
+ return Dsymbol.oneMember(ps, ident);
+ }
+
+ override bool hasPointers()
+ {
+ //printf("TemplateMixin.hasPointers() %s\n", toChars());
+ return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
+ }
+
+ override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
+ {
+ //printf("TemplateMixin.setFieldOffset() %s\n", toChars());
+ if (_scope) // if fwd reference
+ dsymbolSemantic(this, null); // try to resolve it
+
+ members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } );
+ }
+
+ override const(char)* toChars() const
+ {
+ OutBuffer buf;
+ toCBufferInstance(this, &buf);
+ return buf.extractChars();
+ }
+
+ extern (D) bool findTempDecl(Scope* sc)
+ {
+ // Follow qualifications to find the TemplateDeclaration
+ if (!tempdecl)
+ {
+ Expression e;
+ Type t;
+ Dsymbol s;
+ tqual.resolve(loc, sc, e, t, s);
+ if (!s)
+ {
+ error("is not defined");
+ return false;
+ }
+ s = s.toAlias();
+ tempdecl = s.isTemplateDeclaration();
+ OverloadSet os = s.isOverloadSet();
+
+ /* If an OverloadSet, look for a unique member that is a template declaration
+ */
+ if (os)
+ {
+ Dsymbol ds = null;
+ foreach (i, sym; os.a)
+ {
+ Dsymbol s2 = sym.isTemplateDeclaration();
+ if (s2)
+ {
+ if (ds)
+ {
+ tempdecl = os;
+ break;
+ }
+ ds = s2;
+ }
+ }
+ }
+ if (!tempdecl)
+ {
+ error("`%s` isn't a template", s.toChars());
+ return false;
+ }
+ }
+ assert(tempdecl);
+
+ // Look for forward references
+ auto tovers = tempdecl.isOverloadSet();
+ foreach (size_t oi; 0 .. tovers ? tovers.a.dim : 1)
+ {
+ Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
+ int r = overloadApply(dstart, (Dsymbol s)
+ {
+ auto td = s.isTemplateDeclaration();
+ if (!td)
+ return 0;
+
+ if (td.semanticRun == PASS.init)
+ {
+ if (td._scope)
+ td.dsymbolSemantic(td._scope);
+ else
+ {
+ semanticRun = PASS.init;
+ return 1;
+ }
+ }
+ return 0;
+ });
+ if (r)
+ return false;
+ }
+ return true;
+ }
+
+ override inout(TemplateMixin) isTemplateMixin() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/************************************
+ * This struct is needed for TemplateInstance to be the key in an associative array.
+ * Fixing https://issues.dlang.org/show_bug.cgi?id=15812 and
+ * https://issues.dlang.org/show_bug.cgi?id=15813 would make it unnecessary.
+ */
+struct TemplateInstanceBox
+{
+ TemplateInstance ti;
+
+ this(TemplateInstance ti)
+ {
+ this.ti = ti;
+ this.ti.toHash();
+ assert(this.ti.hash);
+ }
+
+ size_t toHash() const @trusted pure nothrow
+ {
+ assert(ti.hash);
+ return ti.hash;
+ }
+
+ bool opEquals(ref const TemplateInstanceBox s) @trusted const
+ {
+ bool res = void;
+ if (ti.inst && s.ti.inst)
+ /* This clause is only used when an instance with errors
+ * is replaced with a correct instance.
+ */
+ res = ti is s.ti;
+ else
+ /* Used when a proposed instance is used to see if there's
+ * an existing instance.
+ */
+ res = (cast()s.ti).equalsx(cast()ti);
+
+ debug (FindExistingInstance) ++(res ? nHits : nCollisions);
+ return res;
+ }
+
+ debug (FindExistingInstance)
+ {
+ __gshared uint nHits, nCollisions;
+
+ shared static ~this()
+ {
+ printf("debug (FindExistingInstance) TemplateInstanceBox.equals hits: %u collisions: %u\n",
+ nHits, nCollisions);
+ }
+ }
+}
+
+/*******************************************
+ * Match to a particular TemplateParameter.
+ * Input:
+ * instLoc location that the template is instantiated.
+ * tiargs[] actual arguments to template instance
+ * i i'th argument
+ * parameters[] template parameters
+ * dedtypes[] deduced arguments to template instance
+ * *psparam set to symbol declared and initialized to dedtypes[i]
+ */
+MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
+{
+ MATCH matchArgNoMatch()
+ {
+ if (psparam)
+ *psparam = null;
+ return MATCH.nomatch;
+ }
+
+ MATCH matchArgParameter()
+ {
+ RootObject oarg;
+
+ if (i < tiargs.dim)
+ oarg = (*tiargs)[i];
+ else
+ {
+ // Get default argument instead
+ oarg = tp.defaultArg(instLoc, sc);
+ if (!oarg)
+ {
+ assert(i < dedtypes.dim);
+ // It might have already been deduced
+ oarg = (*dedtypes)[i];
+ if (!oarg)
+ return matchArgNoMatch();
+ }
+ }
+ return tp.matchArg(sc, oarg, i, parameters, dedtypes, psparam);
+ }
+
+ MATCH matchArgTuple(TemplateTupleParameter ttp)
+ {
+ /* The rest of the actual arguments (tiargs[]) form the match
+ * for the variadic parameter.
+ */
+ assert(i + 1 == dedtypes.dim); // must be the last one
+ Tuple ovar;
+
+ if (Tuple u = isTuple((*dedtypes)[i]))
+ {
+ // It has already been deduced
+ ovar = u;
+ }
+ else if (i + 1 == tiargs.dim && isTuple((*tiargs)[i]))
+ ovar = isTuple((*tiargs)[i]);
+ else
+ {
+ ovar = new Tuple();
+ //printf("ovar = %p\n", ovar);
+ if (i < tiargs.dim)
+ {
+ //printf("i = %d, tiargs.dim = %d\n", i, tiargs.dim);
+ ovar.objects.setDim(tiargs.dim - i);
+ foreach (j, ref obj; ovar.objects)
+ obj = (*tiargs)[i + j];
+ }
+ }
+ return ttp.matchArg(sc, ovar, i, parameters, dedtypes, psparam);
+ }
+
+ if (auto ttp = tp.isTemplateTupleParameter())
+ return matchArgTuple(ttp);
+ else
+ return matchArgParameter();
+}
+
+MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
+{
+ MATCH matchArgNoMatch()
+ {
+ //printf("\tm = %d\n", MATCH.nomatch);
+ if (psparam)
+ *psparam = null;
+ return MATCH.nomatch;
+ }
+
+ MATCH matchArgType(TemplateTypeParameter ttp)
+ {
+ //printf("TemplateTypeParameter.matchArg('%s')\n", ttp.ident.toChars());
+ MATCH m = MATCH.exact;
+ Type ta = isType(oarg);
+ if (!ta)
+ {
+ //printf("%s %p %p %p\n", oarg.toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg));
+ return matchArgNoMatch();
+ }
+ //printf("ta is %s\n", ta.toChars());
+
+ if (ttp.specType)
+ {
+ if (!ta || ta == TemplateTypeParameter.tdummy)
+ return matchArgNoMatch();
+
+ //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars());
+ MATCH m2 = deduceType(ta, sc, ttp.specType, parameters, dedtypes);
+ if (m2 == MATCH.nomatch)
+ {
+ //printf("\tfailed deduceType\n");
+ return matchArgNoMatch();
+ }
+
+ if (m2 < m)
+ m = m2;
+ if ((*dedtypes)[i])
+ {
+ Type t = cast(Type)(*dedtypes)[i];
+
+ if (ttp.dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357
+ return matchArgNoMatch();
+
+ /* This is a self-dependent parameter. For example:
+ * template X(T : T*) {}
+ * template X(T : S!T, alias S) {}
+ */
+ //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
+ ta = t;
+ }
+ }
+ else
+ {
+ if ((*dedtypes)[i])
+ {
+ // Must match already deduced type
+ Type t = cast(Type)(*dedtypes)[i];
+
+ if (!t.equals(ta))
+ {
+ //printf("t = %s ta = %s\n", t.toChars(), ta.toChars());
+ return matchArgNoMatch();
+ }
+ }
+ else
+ {
+ // So that matches with specializations are better
+ m = MATCH.convert;
+ }
+ }
+ (*dedtypes)[i] = ta;
+
+ if (psparam)
+ *psparam = new AliasDeclaration(ttp.loc, ttp.ident, ta);
+ //printf("\tm = %d\n", m);
+ return ttp.dependent ? MATCH.exact : m;
+ }
+
+ MATCH matchArgValue(TemplateValueParameter tvp)
+ {
+ //printf("TemplateValueParameter.matchArg('%s')\n", tvp.ident.toChars());
+ MATCH m = MATCH.exact;
+
+ Expression ei = isExpression(oarg);
+ Type vt;
+
+ if (!ei && oarg)
+ {
+ Dsymbol si = isDsymbol(oarg);
+ FuncDeclaration f = si ? si.isFuncDeclaration() : null;
+ if (!f || !f.fbody || f.needThis())
+ return matchArgNoMatch();
+
+ ei = new VarExp(tvp.loc, f);
+ ei = ei.expressionSemantic(sc);
+
+ /* If a function is really property-like, and then
+ * it's CTFEable, ei will be a literal expression.
+ */
+ uint olderrors = global.startGagging();
+ ei = resolveProperties(sc, ei);
+ ei = ei.ctfeInterpret();
+ if (global.endGagging(olderrors) || ei.op == TOK.error)
+ return matchArgNoMatch();
+
+ /* https://issues.dlang.org/show_bug.cgi?id=14520
+ * A property-like function can match to both
+ * TemplateAlias and ValueParameter. But for template overloads,
+ * it should always prefer alias parameter to be consistent
+ * template match result.
+ *
+ * template X(alias f) { enum X = 1; }
+ * template X(int val) { enum X = 2; }
+ * int f1() { return 0; } // CTFEable
+ * int f2(); // body-less function is not CTFEable
+ * enum x1 = X!f1; // should be 1
+ * enum x2 = X!f2; // should be 1
+ *
+ * e.g. The x1 value must be same even if the f1 definition will be moved
+ * into di while stripping body code.
+ */
+ m = MATCH.convert;
+ }
+
+ if (ei && ei.op == TOK.variable)
+ {
+ // Resolve const variables that we had skipped earlier
+ ei = ei.ctfeInterpret();
+ }
+
+ //printf("\tvalType: %s, ty = %d\n", tvp.valType.toChars(), tvp.valType.ty);
+ vt = tvp.valType.typeSemantic(tvp.loc, sc);
+ //printf("ei: %s, ei.type: %s\n", ei.toChars(), ei.type.toChars());
+ //printf("vt = %s\n", vt.toChars());
+
+ if (ei.type)
+ {
+ MATCH m2 = ei.implicitConvTo(vt);
+ //printf("m: %d\n", m);
+ if (m2 < m)
+ m = m2;
+ if (m == MATCH.nomatch)
+ return matchArgNoMatch();
+ ei = ei.implicitCastTo(sc, vt);
+ ei = ei.ctfeInterpret();
+ }
+
+ if (tvp.specValue)
+ {
+ if (ei is null || (cast(void*)ei.type in TemplateValueParameter.edummies &&
+ TemplateValueParameter.edummies[cast(void*)ei.type] == ei))
+ return matchArgNoMatch();
+
+ Expression e = tvp.specValue;
+
+ sc = sc.startCTFE();
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ sc = sc.endCTFE();
+ e = e.implicitCastTo(sc, vt);
+ e = e.ctfeInterpret();
+
+ ei = ei.syntaxCopy();
+ sc = sc.startCTFE();
+ ei = ei.expressionSemantic(sc);
+ sc = sc.endCTFE();
+ ei = ei.implicitCastTo(sc, vt);
+ ei = ei.ctfeInterpret();
+ //printf("\tei: %s, %s\n", ei.toChars(), ei.type.toChars());
+ //printf("\te : %s, %s\n", e.toChars(), e.type.toChars());
+ if (!ei.equals(e))
+ return matchArgNoMatch();
+ }
+ else
+ {
+ if ((*dedtypes)[i])
+ {
+ // Must match already deduced value
+ Expression e = cast(Expression)(*dedtypes)[i];
+ if (!ei || !ei.equals(e))
+ return matchArgNoMatch();
+ }
+ }
+ (*dedtypes)[i] = ei;
+
+ if (psparam)
+ {
+ Initializer _init = new ExpInitializer(tvp.loc, ei);
+ Declaration sparam = new VarDeclaration(tvp.loc, vt, tvp.ident, _init);
+ sparam.storage_class = STC.manifest;
+ *psparam = sparam;
+ }
+ return tvp.dependent ? MATCH.exact : m;
+ }
+
+ MATCH matchArgAlias(TemplateAliasParameter tap)
+ {
+ //printf("TemplateAliasParameter.matchArg('%s')\n", tap.ident.toChars());
+ MATCH m = MATCH.exact;
+ Type ta = isType(oarg);
+ RootObject sa = ta && !ta.deco ? null : getDsymbol(oarg);
+ Expression ea = isExpression(oarg);
+ if (ea && (ea.op == TOK.this_ || ea.op == TOK.super_))
+ sa = (cast(ThisExp)ea).var;
+ else if (ea && ea.op == TOK.scope_)
+ sa = (cast(ScopeExp)ea).sds;
+ if (sa)
+ {
+ if ((cast(Dsymbol)sa).isAggregateDeclaration())
+ m = MATCH.convert;
+
+ /* specType means the alias must be a declaration with a type
+ * that matches specType.
+ */
+ if (tap.specType)
+ {
+ Declaration d = (cast(Dsymbol)sa).isDeclaration();
+ if (!d)
+ return matchArgNoMatch();
+ if (!d.type.equals(tap.specType))
+ return matchArgNoMatch();
+ }
+ }
+ else
+ {
+ sa = oarg;
+ if (ea)
+ {
+ if (tap.specType)
+ {
+ if (!ea.type.equals(tap.specType))
+ return matchArgNoMatch();
+ }
+ }
+ else if (ta && ta.ty == Tinstance && !tap.specAlias)
+ {
+ /* Specialized parameter should be preferred
+ * match to the template type parameter.
+ * template X(alias a) {} // a == this
+ * template X(alias a : B!A, alias B, A...) {} // B!A => ta
+ */
+ }
+ else if (sa && sa == TemplateTypeParameter.tdummy)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=2025
+ * Aggregate Types should preferentially
+ * match to the template type parameter.
+ * template X(alias a) {} // a == this
+ * template X(T) {} // T => sa
+ */
+ }
+ else if (ta && ta.ty != Tident)
+ {
+ /* Match any type that's not a TypeIdentifier to alias parameters,
+ * but prefer type parameter.
+ * template X(alias a) { } // a == ta
+ *
+ * TypeIdentifiers are excluded because they might be not yet resolved aliases.
+ */
+ m = MATCH.convert;
+ }
+ else
+ return matchArgNoMatch();
+ }
+
+ if (tap.specAlias)
+ {
+ if (sa == TemplateAliasParameter.sdummy)
+ return matchArgNoMatch();
+ // check specialization if template arg is a symbol
+ Dsymbol sx = isDsymbol(sa);
+ if (sa != tap.specAlias && sx)
+ {
+ Type talias = isType(tap.specAlias);
+ if (!talias)
+ return matchArgNoMatch();
+
+ TemplateInstance ti = sx.isTemplateInstance();
+ if (!ti && sx.parent)
+ {
+ ti = sx.parent.isTemplateInstance();
+ if (ti && ti.name != sx.ident)
+ return matchArgNoMatch();
+ }
+ if (!ti)
+ return matchArgNoMatch();
+
+ Type t = new TypeInstance(Loc.initial, ti);
+ MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes);
+ if (m2 == MATCH.nomatch)
+ return matchArgNoMatch();
+ }
+ // check specialization if template arg is a type
+ else if (ta)
+ {
+ if (Type tspec = isType(tap.specAlias))
+ {
+ MATCH m2 = ta.implicitConvTo(tspec);
+ if (m2 == MATCH.nomatch)
+ return matchArgNoMatch();
+ }
+ else
+ {
+ error(tap.loc, "template parameter specialization for a type must be a type and not `%s`",
+ tap.specAlias.toChars());
+ return matchArgNoMatch();
+ }
+ }
+ }
+ else if ((*dedtypes)[i])
+ {
+ // Must match already deduced symbol
+ RootObject si = (*dedtypes)[i];
+ if (!sa || si != sa)
+ return matchArgNoMatch();
+ }
+ (*dedtypes)[i] = sa;
+
+ if (psparam)
+ {
+ if (Dsymbol s = isDsymbol(sa))
+ {
+ *psparam = new AliasDeclaration(tap.loc, tap.ident, s);
+ }
+ else if (Type t = isType(sa))
+ {
+ *psparam = new AliasDeclaration(tap.loc, tap.ident, t);
+ }
+ else
+ {
+ assert(ea);
+
+ // Declare manifest constant
+ Initializer _init = new ExpInitializer(tap.loc, ea);
+ auto v = new VarDeclaration(tap.loc, null, tap.ident, _init);
+ v.storage_class = STC.manifest;
+ v.dsymbolSemantic(sc);
+ *psparam = v;
+ }
+ }
+ return tap.dependent ? MATCH.exact : m;
+ }
+
+ MATCH matchArgTuple(TemplateTupleParameter ttp)
+ {
+ //printf("TemplateTupleParameter.matchArg('%s')\n", ttp.ident.toChars());
+ Tuple ovar = isTuple(oarg);
+ if (!ovar)
+ return MATCH.nomatch;
+ if ((*dedtypes)[i])
+ {
+ Tuple tup = isTuple((*dedtypes)[i]);
+ if (!tup)
+ return MATCH.nomatch;
+ if (!match(tup, ovar))
+ return MATCH.nomatch;
+ }
+ (*dedtypes)[i] = ovar;
+
+ if (psparam)
+ *psparam = new TupleDeclaration(ttp.loc, ttp.ident, &ovar.objects);
+ return ttp.dependent ? MATCH.exact : MATCH.convert;
+ }
+
+ if (auto ttp = tp.isTemplateTypeParameter())
+ return matchArgType(ttp);
+ else if (auto tvp = tp.isTemplateValueParameter())
+ return matchArgValue(tvp);
+ else if (auto tap = tp.isTemplateAliasParameter())
+ return matchArgAlias(tap);
+ else if (auto ttp = tp.isTemplateTupleParameter())
+ return matchArgTuple(ttp);
+ else
+ assert(0);
+}
+
+
+/***********************************************
+ * Collect and print statistics on template instantiations.
+ */
+struct TemplateStats
+{
+ __gshared TemplateStats[const void*] stats;
+
+ uint numInstantiations; // number of instantiations of the template
+ uint uniqueInstantiations; // number of unique instantiations of the template
+
+ TemplateInstances* allInstances;
+
+ /*******************************
+ * Add this instance
+ */
+ static void incInstance(const TemplateDeclaration td,
+ const TemplateInstance ti)
+ {
+ void log(ref TemplateStats ts)
+ {
+ if (ts.allInstances is null)
+ ts.allInstances = new TemplateInstances();
+ if (global.params.vtemplatesListInstances)
+ ts.allInstances.push(cast() ti);
+ }
+
+ // message(ti.loc, "incInstance %p %p", td, ti);
+ if (!global.params.vtemplates)
+ return;
+ if (!td)
+ return;
+ assert(ti);
+ if (auto ts = cast(const void*) td in stats)
+ {
+ log(*ts);
+ ++ts.numInstantiations;
+ }
+ else
+ {
+ stats[cast(const void*) td] = TemplateStats(1, 0);
+ log(stats[cast(const void*) td]);
+ }
+ }
+
+ /*******************************
+ * Add this unique instance
+ */
+ static void incUnique(const TemplateDeclaration td,
+ const TemplateInstance ti)
+ {
+ // message(ti.loc, "incUnique %p %p", td, ti);
+ if (!global.params.vtemplates)
+ return;
+ if (!td)
+ return;
+ assert(ti);
+ if (auto ts = cast(const void*) td in stats)
+ ++ts.uniqueInstantiations;
+ else
+ stats[cast(const void*) td] = TemplateStats(0, 1);
+ }
+}
+
+void printTemplateStats()
+{
+ static struct TemplateDeclarationStats
+ {
+ TemplateDeclaration td;
+ TemplateStats ts;
+ static int compare(scope const TemplateDeclarationStats* a,
+ scope const TemplateDeclarationStats* b) @safe nothrow @nogc pure
+ {
+ auto diff = b.ts.uniqueInstantiations - a.ts.uniqueInstantiations;
+ if (diff)
+ return diff;
+ else
+ return b.ts.numInstantiations - a.ts.numInstantiations;
+ }
+ }
+
+ if (!global.params.vtemplates)
+ return;
+
+ Array!(TemplateDeclarationStats) sortedStats;
+ sortedStats.reserve(TemplateStats.stats.length);
+ foreach (td_, ref ts; TemplateStats.stats)
+ {
+ sortedStats.push(TemplateDeclarationStats(cast(TemplateDeclaration) td_, ts));
+ }
+
+ sortedStats.sort!(TemplateDeclarationStats.compare);
+
+ foreach (const ref ss; sortedStats[])
+ {
+ if (global.params.vtemplatesListInstances &&
+ ss.ts.allInstances)
+ {
+ message(ss.td.loc,
+ "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:",
+ ss.ts.numInstantiations,
+ ss.ts.uniqueInstantiations,
+ ss.td.toCharsNoConstraints());
+ foreach (const ti; (*ss.ts.allInstances)[])
+ {
+ if (ti.tinst) // if has enclosing instance
+ message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars());
+ else
+ message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars());
+ }
+ }
+ else
+ {
+ message(ss.td.loc,
+ "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found",
+ ss.ts.numInstantiations,
+ ss.ts.uniqueInstantiations,
+ ss.td.toCharsNoConstraints());
+ }
+ }
+}
+
+/// Pair of MATCHes
+private struct MATCHpair
+{
+ MATCH mta; /// match template parameters by initial template arguments
+ MATCH mfa; /// match template parameters by inferred template arguments
+
+ debug this(MATCH mta, MATCH mfa)
+ {
+ assert(MATCH.min <= mta && mta <= MATCH.max);
+ assert(MATCH.min <= mfa && mfa <= MATCH.max);
+ this.mta = mta;
+ this.mfa = mfa;
+ }
+}
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
new file mode 100644
index 0000000..28054d0
--- /dev/null
+++ b/gcc/d/dmd/dtoh.d
@@ -0,0 +1,3225 @@
+/**
+ * This module contains the implementation of the C++ header generation available through
+ * the command line switch -Hc.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtohd, _dtoh.d)
+ * Documentation: https://dlang.org/phobos/dmd_dtoh.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtoh.d
+ */
+module dmd.dtoh;
+
+import core.stdc.stdio;
+import core.stdc.string;
+import core.stdc.ctype;
+
+import dmd.astcodegen;
+import dmd.arraytypes;
+import dmd.dsymbol;
+import dmd.errors;
+import dmd.globals;
+import dmd.identifier;
+import dmd.root.filename;
+import dmd.visitor;
+import dmd.tokens;
+
+import dmd.root.outbuffer;
+import dmd.utils;
+
+//debug = Debug_DtoH;
+
+// Generate asserts to validate the header
+//debug = Debug_DtoH_Checks;
+
+/**
+ * Generates a C++ header containing bindings for all `extern(C[++])` declarations
+ * found in the supplied modules.
+ *
+ * Params:
+ * ms = the modules
+ *
+ * Notes:
+ * - the header is written to `<global.params.cxxhdrdir>/<global.params.cxxhdrfile>`
+ * or `stdout` if no explicit file was specified
+ * - bindings conform to the C++ standard defined in `global.params.cplusplus`
+ * - ignored declarations are mentioned in a comment if `global.params.doCxxHdrGeneration`
+ * is set to `CxxHeaderMode.verbose`
+ */
+extern(C++) void genCppHdrFiles(ref Modules ms)
+{
+ initialize();
+
+ OutBuffer fwd;
+ OutBuffer done;
+ OutBuffer decl;
+
+ // enable indent by spaces on buffers
+ fwd.doindent = true;
+ fwd.spaces = true;
+ decl.doindent = true;
+ decl.spaces = true;
+
+ scope v = new ToCppBuffer(&fwd, &done, &decl);
+
+ // Conditionally include another buffer for sanity checks
+ debug (Debug_DtoH_Checks)
+ {
+ OutBuffer check;
+ check.doindent = true;
+ check.spaces = true;
+ v.checkbuf = &check;
+ }
+
+ OutBuffer buf;
+ buf.doindent = true;
+ buf.spaces = true;
+
+ foreach (m; ms)
+ m.accept(v);
+
+ if (global.params.doCxxHdrGeneration == CxxHeaderMode.verbose)
+ buf.printf("// Automatically generated by %s Compiler v%d", global.vendor.ptr, global.versionNumber());
+ else
+ buf.printf("// Automatically generated by %s Compiler", global.vendor.ptr);
+
+ buf.writenl();
+ buf.writenl();
+ buf.writestringln("#pragma once");
+ buf.writenl();
+ hashInclude(buf, "<assert.h>");
+ hashInclude(buf, "<stddef.h>");
+ hashInclude(buf, "<stdint.h>");
+ hashInclude(buf, "<math.h>");
+// buf.writestring(buf, "#include <stdio.h>\n");
+// buf.writestring("#include <string.h>\n");
+
+ // Emit array compatibility because extern(C++) types may have slices
+ // as members (as opposed to function parameters)
+ buf.writestring(`
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+`);
+
+ if (v.hasReal)
+ {
+ hashIf(buf, "!defined(_d_real)");
+ {
+ hashDefine(buf, "_d_real long double");
+ }
+ hashEndIf(buf);
+ }
+ buf.writenl();
+ // buf.writestringln("// fwd:");
+ buf.write(&fwd);
+ if (fwd.length > 0)
+ buf.writenl();
+
+ // buf.writestringln("// done:");
+ buf.write(&done);
+
+ // buf.writestringln("// decl:");
+ buf.write(&decl);
+
+ debug (Debug_DtoH_Checks)
+ {
+ // buf.writestringln("// check:");
+ buf.writestring(`
+#if OFFSETS
+ template <class T>
+ size_t getSlotNumber(int dummy, ...)
+ {
+ T c;
+ va_list ap;
+ va_start(ap, dummy);
+
+ void *f = va_arg(ap, void*);
+ for (size_t i = 0; ; i++)
+ {
+ if ( (*(void***)&c)[i] == f)
+ return i;
+ }
+ va_end(ap);
+ }
+
+ void testOffsets()
+ {
+`);
+ buf.write(&check);
+ buf.writestring(`
+ }
+#endif
+`);
+ }
+
+ if (global.params.cxxhdrname is null)
+ {
+ // Write to stdout; assume it succeeds
+ size_t n = fwrite(buf[].ptr, 1, buf.length, stdout);
+ assert(n == buf.length); // keep gcc happy about return values
+ }
+ else
+ {
+ const(char)[] name = FileName.combine(global.params.cxxhdrdir, global.params.cxxhdrname);
+ writeFile(Loc.initial, name, buf[]);
+ }
+}
+
+private:
+
+/****************************************************
+ * Visitor that writes bindings for `extern(C[++]` declarations.
+ */
+extern(C++) final class ToCppBuffer : Visitor
+{
+ alias visit = Visitor.visit;
+public:
+ enum EnumKind
+ {
+ Int,
+ Numeric,
+ String,
+ Enum,
+ Other
+ }
+
+ /// Namespace providing the actual AST nodes
+ alias AST = ASTCodegen;
+
+ /// Visited nodes
+ bool[void*] visited;
+
+ /// Forward declared nodes (which might not be emitted yet)
+ bool[void*] forwarded;
+
+ /// Buffer for forward declarations
+ OutBuffer* fwdbuf;
+
+ /// Buffer for integrity checks
+ debug (Debug_DtoH_Checks) OutBuffer* checkbuf;
+
+ /// Buffer for declarations that must emitted before the currently
+ /// visited node but can't be forward declared (see `includeSymbol`)
+ OutBuffer* donebuf;
+
+ /// Default buffer for the currently visited declaration
+ OutBuffer* buf;
+
+ /// The generated header uses `real` emitted as `_d_real`?
+ bool hasReal;
+
+ /// The generated header should contain comments for skipped declarations?
+ const bool printIgnored;
+
+ /// State specific to the current context which depends
+ /// on the currently visited node and it's parents
+ static struct Context
+ {
+ /// Default linkage in the current scope (e.g. LINK.c inside `extern(C) { ... }`)
+ LINK linkage = LINK.d;
+
+ /// Enclosing class / struct / union
+ AST.AggregateDeclaration adparent;
+
+ /// Enclosing template declaration
+ AST.TemplateDeclaration tdparent;
+
+ /// Identifier of the currently visited `VarDeclaration`
+ /// (required to write variables of funtion pointers)
+ Identifier ident;
+
+ /// Original type of the currently visited declaration
+ AST.Type* origType;
+
+ /// Last written visibility level applying to the current scope
+ AST.Visibility.Kind currentVisibility;
+
+ /// Currently applicable storage classes
+ AST.STC storageClass;
+
+ /// How many symbols were ignored
+ int ignoredCounter;
+
+ /// Currently visited types are required by another declaration
+ /// and hence must be emitted
+ bool mustEmit;
+
+ /// Processing a type that can be forward referenced
+ bool forwarding;
+
+ /// Inside of an anonymous struct/union (AnonDeclaration)
+ bool inAnonymousDecl;
+ }
+
+ /// Informations about the current context in the AST
+ Context context;
+ alias context this;
+
+ this(OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf)
+ {
+ this.fwdbuf = fwdbuf;
+ this.donebuf = donebuf;
+ this.buf = buf;
+ this.printIgnored = global.params.doCxxHdrGeneration == CxxHeaderMode.verbose;
+ }
+
+ /**
+ * Emits `dsym` into `donebuf` s.t. it is declared before the currently
+ * visited symbol that written to `buf`.
+ *
+ * Temporarily clears `context` to behave as if it was visited normally.
+ */
+ private void includeSymbol(AST.Dsymbol dsym)
+ {
+ debug (Debug_DtoH)
+ {
+ printf("[includeSymbol(AST.Dsymbol) enter] %s\n", dsym.toChars());
+ scope(exit) printf("[includeSymbol(AST.Dsymbol) exit] %s\n", dsym.toChars());
+ }
+
+ auto ptr = cast(void*) dsym in visited;
+ if (ptr && *ptr)
+ return;
+
+ // Temporary replacement for `buf` which is appended to `donebuf`
+ OutBuffer decl;
+ decl.doindent = true;
+ decl.spaces = true;
+ scope (exit) donebuf.write(&decl);
+
+ auto ctxStash = this.context;
+ auto bufStash = this.buf;
+
+ this.context = Context.init;
+ this.buf = &decl;
+ this.mustEmit = true;
+
+ dsym.accept(this);
+
+ this.context = ctxStash;
+ this.buf = bufStash;
+ }
+
+ /// Determines what kind of enum `type` is (see `EnumKind`)
+ private EnumKind getEnumKind(AST.Type type)
+ {
+ if (type) switch (type.ty)
+ {
+ case AST.Tint32:
+ return EnumKind.Int;
+ case AST.Tbool,
+ AST.Tchar, AST.Twchar, AST.Tdchar,
+ AST.Tint8, AST.Tuns8,
+ AST.Tint16, AST.Tuns16,
+ AST.Tuns32,
+ AST.Tint64, AST.Tuns64:
+ return EnumKind.Numeric;
+ case AST.Tarray:
+ if (type.isString())
+ return EnumKind.String;
+ break;
+ case AST.Tenum:
+ return EnumKind.Enum;
+ default:
+ break;
+ }
+ return EnumKind.Other;
+ }
+
+ /// Determines the type used to represent `type` in C++.
+ /// Returns: `const [w,d]char*` for `[w,d]string` or `type`
+ private AST.Type determineEnumType(AST.Type type)
+ {
+ if (auto arr = type.isTypeDArray())
+ {
+ switch (arr.next.ty)
+ {
+ case AST.Tchar: return AST.Type.tchar.constOf.pointerTo;
+ case AST.Twchar: return AST.Type.twchar.constOf.pointerTo;
+ case AST.Tdchar: return AST.Type.tdchar.constOf.pointerTo;
+ default: break;
+ }
+ }
+ return type;
+ }
+
+ /// Writes a final `;` and insert an empty line outside of aggregates
+ private void writeDeclEnd()
+ {
+ buf.writestringln(";");
+
+ if (!adparent)
+ buf.writenl();
+ }
+
+ /// Writes the corresponding access specifier if necessary
+ private void writeProtection(const AST.Visibility.Kind kind)
+ {
+ // Don't write visibility for global declarations
+ if (!adparent || inAnonymousDecl)
+ return;
+
+ string token;
+
+ switch(kind) with(AST.Visibility.Kind)
+ {
+ case none, private_:
+ if (this.currentVisibility == AST.Visibility.Kind.private_)
+ return;
+ this.currentVisibility = AST.Visibility.Kind.private_;
+ token = "private:";
+ break;
+
+ case package_, protected_:
+ if (this.currentVisibility == AST.Visibility.Kind.protected_)
+ return;
+ this.currentVisibility = AST.Visibility.Kind.protected_;
+ token = "protected:";
+ break;
+
+ case undefined, public_, export_:
+ if (this.currentVisibility == AST.Visibility.Kind.public_)
+ return;
+ this.currentVisibility = AST.Visibility.Kind.public_;
+ token = "public:";
+ break;
+
+ default:
+ printf("Unexpected visibility: %d!\n", kind);
+ assert(0);
+ }
+
+ buf.level--;
+ buf.writestringln(token);
+ buf.level++;
+ }
+
+ /**
+ * Writes an identifier into `buf` and checks for reserved identifiers. The
+ * parameter `canFix` determines how this function handles C++ keywords:
+ *
+ * `false` => Raise a warning and print the identifier as-is
+ * `true` => Append an underscore to the identifier
+ *
+ * Params:
+ * s = the symbol denoting the identifier
+ * canFixup = whether the identifier may be changed without affecting
+ * binary compatibility
+ */
+ private void writeIdentifier(const AST.Dsymbol s, const bool canFix = false)
+ {
+ writeIdentifier(s.ident, s.loc, s.kind(), canFix);
+ }
+
+ /** Overload of `writeIdentifier` used for all AST nodes not descending from Dsymbol **/
+ private void writeIdentifier(const Identifier ident, const Loc loc, const char* kind, const bool canFix = false)
+ {
+ bool needsFix;
+
+ void warnCxxCompat(const(char)* reason)
+ {
+ if (canFix)
+ {
+ needsFix = true;
+ return;
+ }
+
+ __gshared bool warned = false;
+ warning(loc, "%s `%s` is a %s", kind, ident.toChars(), reason);
+
+ if (!warned)
+ {
+ warningSupplemental(loc, "The generated C++ header will contain " ~
+ "identifiers that are keywords in C++");
+ warned = true;
+ }
+ }
+
+ if (global.params.warnings != DiagnosticReporting.off || canFix)
+ {
+ // Warn about identifiers that are keywords in C++.
+ if (auto kc = keywordClass(ident))
+ warnCxxCompat(kc);
+ }
+ buf.writestring(ident.toString());
+ if (needsFix)
+ buf.writeByte('_');
+ }
+
+ /// Checks whether `t` is a type that can be exported to C++
+ private bool isSupportedType(AST.Type t)
+ {
+ if (!t)
+ {
+ assert(tdparent);
+ return true;
+ }
+
+ switch (t.ty)
+ {
+ // Nested types
+ case AST.Tarray:
+ case AST.Tsarray:
+ case AST.Tpointer:
+ case AST.Treference:
+ case AST.Tdelegate:
+ return isSupportedType((cast(AST.TypeNext) t).next);
+
+ // Function pointers
+ case AST.Tfunction:
+ {
+ auto tf = cast(AST.TypeFunction) t;
+ if (!isSupportedType(tf.next))
+ return false;
+ foreach (_, param; tf.parameterList)
+ {
+ if (!isSupportedType(param.type))
+ return false;
+ }
+ return true;
+ }
+
+ // Noreturn has a different mangling
+ case AST.Tnoreturn:
+
+ // _Imaginary is C only.
+ case AST.Timaginary32:
+ case AST.Timaginary64:
+ case AST.Timaginary80:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ override void visit(AST.Dsymbol s)
+ {
+ debug (Debug_DtoH)
+ {
+ mixin(traceVisit!s);
+ import dmd.asttypename;
+ printf("[AST.Dsymbol enter] %s\n", s.astTypeName().ptr);
+ }
+ }
+
+ override void visit(AST.Import i)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!i);
+
+ /// Writes `using <alias_> = <sym.ident>` into `buf`
+ const(char*) writeImport(AST.Dsymbol sym, const Identifier alias_)
+ {
+ /// `using` was introduced in C++ 11 and only works for types...
+ if (global.params.cplusplus < CppStdRevision.cpp11)
+ return "requires C++11";
+
+ if (auto ad = sym.isAliasDeclaration())
+ {
+ sym = ad.toAlias();
+ ad = sym.isAliasDeclaration();
+
+ // Might be an alias to a basic type
+ if (ad && !ad.aliassym && ad.type)
+ goto Emit;
+ }
+
+ // Restricted to types and other aliases
+ if (!sym.isScopeDsymbol() && !sym.isAggregateDeclaration())
+ return "only supports types";
+
+ // Write `using <alias_> = `<sym>`
+ Emit:
+ buf.writestring("using ");
+ writeIdentifier(alias_, i.loc, "renamed import");
+ buf.writestring(" = ");
+ // Start at module scope to avoid collisions with local symbols
+ if (this.context.adparent)
+ buf.writestring("::");
+ buf.writestring(sym.ident.toString());
+ writeDeclEnd();
+ return null;
+ }
+
+ // Only missing without semantic analysis
+ // FIXME: Templates need work due to missing parent & imported module
+ if (!i.parent)
+ {
+ assert(tdparent);
+ ignored("`%s` because it's inside of a template declaration", i.toChars());
+ return;
+ }
+
+ // Non-public imports don't create new symbols, include as needed
+ if (i.visibility.kind < AST.Visibility.Kind.public_)
+ return;
+
+ // Symbols from static imports should be emitted inline
+ if (i.isstatic)
+ return;
+
+ const isLocal = !i.parent.isModule();
+
+ // Need module for symbol lookup
+ assert(i.mod);
+
+ // Emit an alias for each public module member
+ if (isLocal && i.names.length == 0)
+ {
+ assert(i.mod.symtab);
+
+ // Sort alphabetically s.t. slight changes in semantic don't cause
+ // massive changes in the order of declarations
+ AST.Dsymbols entries;
+ entries.reserve(i.mod.symtab.length);
+
+ foreach (entry; i.mod.symtab.tab.asRange)
+ {
+ // Skip anonymous / invisible members
+ import dmd.access : symbolIsVisible;
+ if (!entry.key.isAnonymous() && symbolIsVisible(i, entry.value))
+ entries.push(entry.value);
+ }
+
+ // Seperate function because of a spurious dual-context deprecation
+ static int compare(const AST.Dsymbol* a, const AST.Dsymbol* b)
+ {
+ return strcmp(a.ident.toChars(), b.ident.toChars());
+ }
+ entries.sort!compare();
+
+ foreach (sym; entries)
+ {
+ includeSymbol(sym);
+ if (auto err = writeImport(sym, sym.ident))
+ ignored("public import for `%s` because `using` %s", sym.ident.toChars(), err);
+ }
+ return;
+ }
+
+ // Include all public imports and emit using declarations for each alias
+ foreach (const idx, name; i.names)
+ {
+ // Search the imported symbol
+ auto sym = i.mod.search(Loc.initial, name);
+ assert(sym); // Missing imports should error during semantic
+
+ includeSymbol(sym);
+
+ // Detect the assigned name for renamed import
+ auto alias_ = i.aliases[idx];
+ if (!alias_)
+ continue;
+
+ if (auto err = writeImport(sym, alias_))
+ ignored("renamed import `%s = %s` because `using` %s", alias_.toChars(), name.toChars(), err);
+ }
+ }
+
+ override void visit(AST.AttribDeclaration pd)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!pd);
+
+ Dsymbols* decl = pd.include(null);
+ if (!decl)
+ return;
+
+ foreach (s; *decl)
+ {
+ if (adparent || s.visible().kind >= AST.Visibility.Kind.public_)
+ s.accept(this);
+ }
+ }
+
+ override void visit(AST.StorageClassDeclaration scd)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!scd);
+
+ const stcStash = this.storageClass;
+ this.storageClass |= scd.stc;
+ visit(cast(AST.AttribDeclaration) scd);
+ this.storageClass = stcStash;
+ }
+
+ override void visit(AST.LinkDeclaration ld)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!ld);
+
+ auto save = linkage;
+ linkage = ld.linkage;
+ visit(cast(AST.AttribDeclaration)ld);
+ linkage = save;
+ }
+
+ override void visit(AST.CPPMangleDeclaration md)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!md);
+
+ const oldLinkage = this.linkage;
+ this.linkage = LINK.cpp;
+ visit(cast(AST.AttribDeclaration) md);
+ this.linkage = oldLinkage;
+ }
+
+ override void visit(AST.Module m)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!m);
+
+ foreach (s; *m.members)
+ {
+ if (s.visible().kind < AST.Visibility.Kind.public_)
+ continue;
+ s.accept(this);
+ }
+ }
+
+ override void visit(AST.FuncDeclaration fd)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!fd);
+
+ if (cast(void*)fd in visited)
+ return;
+ // printf("FuncDeclaration %s %s\n", fd.toPrettyChars(), fd.type.toChars());
+ visited[cast(void*)fd] = true;
+
+ // Note that tf might be null for templated (member) functions
+ auto tf = cast(AST.TypeFunction)fd.type;
+ if ((tf && tf.linkage != LINK.c && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
+ {
+ ignored("function %s because of linkage", fd.toPrettyChars());
+ return checkVirtualFunction(fd);
+ }
+ if (!adparent && !fd.fbody)
+ {
+ ignored("function %s because it is extern", fd.toPrettyChars());
+ return;
+ }
+ if (fd.visibility.kind == AST.Visibility.Kind.none || fd.visibility.kind == AST.Visibility.Kind.private_)
+ {
+ ignored("function %s because it is private", fd.toPrettyChars());
+ return;
+ }
+ if (tf && !isSupportedType(tf.next))
+ {
+ ignored("function %s because its return type cannot be mapped to C++", fd.toPrettyChars());
+ return checkVirtualFunction(fd);
+ }
+ if (tf) foreach (i, fparam; tf.parameterList)
+ {
+ if (!isSupportedType(fparam.type))
+ {
+ ignored("function %s because one of its parameters has type `%s` which cannot be mapped to C++",
+ fd.toPrettyChars(), fparam.type.toChars());
+ return checkVirtualFunction(fd);
+ }
+ }
+
+ writeProtection(fd.visibility.kind);
+
+ if (tf && tf.linkage == LINK.c)
+ buf.writestring("extern \"C\" ");
+ else if (!adparent)
+ buf.writestring("extern ");
+ if (adparent && fd.isStatic())
+ buf.writestring("static ");
+ else if (adparent && (
+ // Virtual functions in non-templated classes
+ (fd.vtblIndex != -1 && !fd.isOverride()) ||
+
+ // Virtual functions in templated classes (fd.vtblIndex still -1)
+ (tdparent && adparent.isClassDeclaration() && !(this.storageClass & AST.STC.final_ || fd.isFinal))))
+ buf.writestring("virtual ");
+
+ debug (Debug_DtoH_Checks)
+ if (adparent && !tdparent)
+ {
+ auto s = adparent.search(Loc.initial, fd.ident);
+ auto cd = adparent.isClassDeclaration();
+
+ if (!(adparent.storage_class & AST.STC.abstract_) &&
+ !(cd && cd.isAbstract()) &&
+ s is fd && !fd.overnext)
+ {
+ const cn = adparent.ident.toChars();
+ const fn = fd.ident.toChars();
+ const vi = fd.vtblIndex;
+
+ checkbuf.printf("assert(getSlotNumber <%s>(0, &%s::%s) == %d);",
+ cn, cn, fn, vi);
+ checkbuf.writenl();
+ }
+ }
+
+ if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11)
+ writeProtection(AST.Visibility.Kind.private_);
+ funcToBuffer(tf, fd);
+ // FIXME: How to determine if fd is const without tf?
+ if (adparent && tf && (tf.isConst() || tf.isImmutable()))
+ {
+ bool fdOverridesAreConst = true;
+ foreach (fdv; fd.foverrides)
+ {
+ auto tfv = cast(AST.TypeFunction)fdv.type;
+ if (!tfv.isConst() && !tfv.isImmutable())
+ {
+ fdOverridesAreConst = false;
+ break;
+ }
+ }
+
+ buf.writestring(fdOverridesAreConst ? " const" : " /* const */");
+ }
+ if (adparent && fd.isAbstract())
+ buf.writestring(" = 0");
+ if (adparent && fd.isDisabled && global.params.cplusplus >= CppStdRevision.cpp11)
+ buf.writestring(" = delete");
+ buf.writestringln(";");
+ if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11)
+ writeProtection(AST.Visibility.Kind.public_);
+
+ if (!adparent)
+ buf.writenl();
+
+ }
+
+ /// Checks whether `fd` is a virtual function and emits a dummy declaration
+ /// if required to ensure proper vtable layout
+ private void checkVirtualFunction(AST.FuncDeclaration fd)
+ {
+ // Omit redundant declarations - the slot was already
+ // reserved in the base class
+ if (fd.isVirtual() && fd.introducing)
+ {
+ // Hide placeholders because they are not ABI compatible
+ writeProtection(AST.Visibility.Kind.private_);
+
+ __gshared int counter; // Ensure unique names in all cases
+ buf.printf("virtual void __vtable_slot_%u();", counter++);
+ buf.writenl();
+ }
+ }
+
+ override void visit(AST.UnitTestDeclaration utd)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!utd);
+ }
+
+ override void visit(AST.VarDeclaration vd)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!vd);
+
+ if (!shouldEmitAndMarkVisited(vd))
+ return;
+
+ // Tuple field are expanded into multiple VarDeclarations
+ // (we'll visit them later)
+ if (vd.type && vd.type.isTypeTuple())
+ return;
+
+ if (vd.originalType && vd.type == AST.Type.tsize_t)
+ origType = &vd.originalType;
+ scope(exit) origType = null;
+
+ if (vd.alignment != STRUCTALIGN_DEFAULT)
+ {
+ buf.printf("// Ignoring var %s alignment %u", vd.toChars(), vd.alignment);
+ buf.writenl();
+ }
+
+ // Determine the variable type which might be missing inside of
+ // template declarations. Infer the type from the initializer then
+ AST.Type type = vd.type;
+ if (!type)
+ {
+ assert(tdparent);
+
+ // Just a precaution, implicit type without initializer should be rejected
+ if (!vd._init)
+ return;
+
+ if (auto ei = vd._init.isExpInitializer())
+ type = ei.exp.type;
+
+ // Can happen if the expression needs further semantic
+ if (!type)
+ {
+ ignored("%s because the type could not be determined", vd.toPrettyChars());
+ return;
+ }
+
+ // Apply const/immutable to the inferred type
+ if (vd.storage_class & (AST.STC.const_ | AST.STC.immutable_))
+ type = type.constOf();
+ }
+
+ if (vd.storage_class & AST.STC.manifest)
+ {
+ EnumKind kind = getEnumKind(type);
+
+ if (vd.visibility.kind == AST.Visibility.Kind.none || vd.visibility.kind == AST.Visibility.Kind.private_) {
+ ignored("enum `%s` because it is `%s`.", vd.toPrettyChars(), AST.visibilityToChars(vd.visibility.kind));
+ return;
+ }
+
+ writeProtection(vd.visibility.kind);
+
+ final switch (kind)
+ {
+ case EnumKind.Int, EnumKind.Numeric:
+ // 'enum : type' is only available from C++-11 onwards.
+ if (global.params.cplusplus < CppStdRevision.cpp11)
+ goto case;
+ buf.writestring("enum : ");
+ determineEnumType(type).accept(this);
+ buf.writestring(" { ");
+ writeIdentifier(vd, true);
+ buf.writestring(" = ");
+ auto ie = AST.initializerToExpression(vd._init).isIntegerExp();
+ visitInteger(ie.toInteger(), type);
+ buf.writestring(" };");
+ break;
+
+ case EnumKind.String, EnumKind.Enum:
+ buf.writestring("static ");
+ auto target = determineEnumType(type);
+ target.accept(this);
+ buf.writestring(" const ");
+ writeIdentifier(vd, true);
+ buf.writestring(" = ");
+ auto e = AST.initializerToExpression(vd._init);
+ printExpressionFor(target, e);
+ buf.writestring(";");
+ break;
+
+ case EnumKind.Other:
+ ignored("enum `%s` because type `%s` is currently not supported for enum constants.", vd.toPrettyChars(), type.toChars());
+ return;
+ }
+ buf.writenl();
+ buf.writenl();
+ return;
+ }
+
+ if (vd.storage_class & (AST.STC.static_ | AST.STC.extern_ | AST.STC.tls | AST.STC.gshared) ||
+ vd.parent && vd.parent.isModule())
+ {
+ if (vd.linkage != LINK.c && vd.linkage != LINK.cpp && !(tdparent && (this.linkage == LINK.c || this.linkage == LINK.cpp)))
+ {
+ ignored("variable %s because of linkage", vd.toPrettyChars());
+ return;
+ }
+ if (vd.storage_class & AST.STC.tls)
+ {
+ ignored("variable %s because of thread-local storage", vd.toPrettyChars());
+ return;
+ }
+ if (!isSupportedType(type))
+ {
+ ignored("variable %s because its type cannot be mapped to C++", vd.toPrettyChars());
+ return;
+ }
+ if (auto kc = keywordClass(vd.ident))
+ {
+ ignored("variable %s because its name is a %s", vd.toPrettyChars(), kc);
+ return;
+ }
+ writeProtection(vd.visibility.kind);
+ if (vd.linkage == LINK.c)
+ buf.writestring("extern \"C\" ");
+ else if (!adparent)
+ buf.writestring("extern ");
+ if (adparent)
+ buf.writestring("static ");
+ typeToBuffer(type, vd);
+ writeDeclEnd();
+ return;
+ }
+
+ if (adparent)
+ {
+ writeProtection(vd.visibility.kind);
+ typeToBuffer(type, vd, true);
+ buf.writestringln(";");
+
+ debug (Debug_DtoH_Checks)
+ {
+ checkbuf.level++;
+ const pn = adparent.ident.toChars();
+ const vn = vd.ident.toChars();
+ const vo = vd.offset;
+ checkbuf.printf("assert(offsetof(%s, %s) == %d);",
+ pn, vn, vo);
+ checkbuf.writenl();
+ checkbuf.level--;
+ }
+ return;
+ }
+
+ visit(cast(AST.Dsymbol)vd);
+ }
+
+ override void visit(AST.TypeInfoDeclaration tid)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!tid);
+ }
+
+ override void visit(AST.AliasDeclaration ad)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!ad);
+
+ if (!shouldEmitAndMarkVisited(ad))
+ return;
+
+ writeProtection(ad.visibility.kind);
+
+ if (auto t = ad.type)
+ {
+ if (t.ty == AST.Tdelegate || t.ty == AST.Tident)
+ {
+ visit(cast(AST.Dsymbol)ad);
+ return;
+ }
+
+ // for function pointers we need to original type
+ if (ad.originalType && ad.type.ty == AST.Tpointer &&
+ (cast(AST.TypePointer)t).nextOf.ty == AST.Tfunction)
+ {
+ origType = &ad.originalType;
+ }
+ scope(exit) origType = null;
+
+ buf.writestring("typedef ");
+ typeToBuffer(origType ? *origType : t, ad);
+ writeDeclEnd();
+ return;
+ }
+ if (!ad.aliassym)
+ {
+ assert(0);
+ }
+ if (auto ti = ad.aliassym.isTemplateInstance())
+ {
+ visitTi(ti);
+ return;
+ }
+ if (auto sd = ad.aliassym.isStructDeclaration())
+ {
+ buf.writestring("typedef ");
+ sd.type.accept(this);
+ buf.writestring(" ");
+ writeIdentifier(ad);
+ writeDeclEnd();
+ return;
+ }
+ else if (auto td = ad.aliassym.isTemplateDeclaration())
+ {
+ if (global.params.cplusplus < CppStdRevision.cpp11)
+ {
+ ignored("%s because `using` declarations require C++ 11", ad.toPrettyChars());
+ return;
+ }
+
+ printTemplateParams(td);
+ buf.writestring("using ");
+ writeIdentifier(ad);
+ buf.writestring(" = ");
+ writeFullName(td);
+ buf.writeByte('<');
+
+ foreach (const idx, const p; *td.parameters)
+ {
+ if (idx)
+ buf.writestring(", ");
+ writeIdentifier(p.ident, p.loc, "parameter", true);
+ }
+ buf.writestringln(">;");
+ return;
+ }
+
+ auto fd = ad.aliassym.isFuncDeclaration();
+
+ if (fd && (fd.generated || fd.isDtorDeclaration()))
+ {
+ // Ignore. It's taken care of while visiting FuncDeclaration
+ return;
+ }
+
+ // Recognize member function aliases, e.g. alias visit = Parent.visit;
+ if (adparent && fd)
+ {
+ auto pd = fd.isMember();
+ if (!pd)
+ {
+ ignored("%s because free functions cannot be aliased in C++", ad.toPrettyChars());
+ }
+ else if (global.params.cplusplus < CppStdRevision.cpp11)
+ {
+ ignored("%s because `using` declarations require C++ 11", ad.toPrettyChars());
+ }
+ else if (ad.ident != fd.ident)
+ {
+ ignored("%s because `using` cannot rename functions in aggregates", ad.toPrettyChars());
+ }
+ else if (fd.toAliasFunc().parent.isTemplateMixin())
+ {
+ // Member's of template mixins are directly emitted into the aggregate
+ }
+ else
+ {
+ buf.writestring("using ");
+
+ // Print prefix of the base class if this function originates from a superclass
+ // because alias might be resolved through multiple classes, e.g.
+ // e.g. for alias visit = typeof(super).visit in the visitors
+ if (!fd.introducing)
+ printPrefix(ad.toParent().isClassDeclaration().baseClass);
+ else
+ printPrefix(pd);
+
+ buf.writestring(fd.ident.toChars());
+ buf.writestringln(";");
+ }
+ return;
+ }
+
+ ignored("%s %s", ad.aliassym.kind(), ad.aliassym.toPrettyChars());
+ }
+
+ override void visit(AST.Nspace ns)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!ns);
+ handleNspace(ns, ns.members);
+ }
+
+ override void visit(AST.CPPNamespaceDeclaration ns)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!ns);
+ handleNspace(ns, ns.decl);
+ }
+
+ /// Writes the namespace declaration and visits all members
+ private void handleNspace(AST.Dsymbol namespace, Dsymbols* members)
+ {
+ buf.writestring("namespace ");
+ writeIdentifier(namespace);
+ buf.writenl();
+ buf.writestring("{");
+ buf.writenl();
+ buf.level++;
+ foreach(decl;(*members))
+ {
+ decl.accept(this);
+ }
+ buf.level--;
+ buf.writestring("}");
+ buf.writenl();
+ }
+
+ override void visit(AST.AnonDeclaration ad)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!ad);
+
+ const anonStash = inAnonymousDecl;
+ inAnonymousDecl = true;
+ scope (exit) inAnonymousDecl = anonStash;
+
+ buf.writestringln(ad.isunion ? "union" : "struct");
+ buf.writestringln("{");
+ buf.level++;
+ foreach (s; *ad.decl)
+ {
+ s.accept(this);
+ }
+ buf.level--;
+ buf.writestringln("};");
+ }
+
+ private bool memberField(AST.VarDeclaration vd)
+ {
+ if (!vd.type || !vd.type.deco || !vd.ident)
+ return false;
+ if (!vd.isField())
+ return false;
+ if (vd.type.ty == AST.Tfunction)
+ return false;
+ if (vd.type.ty == AST.Tsarray)
+ return false;
+ return true;
+ }
+
+ override void visit(AST.StructDeclaration sd)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!sd);
+
+ if (!shouldEmitAndMarkVisited(sd))
+ return;
+
+ const ignoredStash = this.ignoredCounter;
+ scope (exit) this.ignoredCounter = ignoredStash;
+
+ pushAlignToBuffer(sd.alignment);
+
+ writeProtection(sd.visibility.kind);
+
+ const structAsClass = sd.cppmangle == CPPMANGLE.asClass;
+ if (sd.isUnionDeclaration())
+ buf.writestring("union ");
+ else
+ buf.writestring(structAsClass ? "class " : "struct ");
+
+ writeIdentifier(sd);
+ if (!sd.members)
+ {
+ buf.writestringln(";");
+ buf.writenl();
+ return;
+ }
+
+ // D structs are always final
+ if (!sd.isUnionDeclaration())
+ buf.writestring(" final");
+
+ buf.writenl();
+ buf.writestring("{");
+
+ const protStash = this.currentVisibility;
+ this.currentVisibility = structAsClass ? AST.Visibility.Kind.private_ : AST.Visibility.Kind.public_;
+ scope (exit) this.currentVisibility = protStash;
+
+ buf.level++;
+ buf.writenl();
+ auto save = adparent;
+ adparent = sd;
+
+ foreach (m; *sd.members)
+ {
+ m.accept(this);
+ }
+ // Generate default ctor
+ if (!sd.noDefaultCtor && !sd.isUnionDeclaration())
+ {
+ writeProtection(AST.Visibility.Kind.public_);
+ buf.printf("%s()", sd.ident.toChars());
+ size_t varCount;
+ bool first = true;
+ buf.level++;
+ foreach (m; *sd.members)
+ {
+ if (auto vd = m.isVarDeclaration())
+ {
+ if (!memberField(vd))
+ continue;
+ varCount++;
+
+ if (!vd._init && !vd.type.isTypeBasic() && !vd.type.isTypePointer && !vd.type.isTypeStruct &&
+ !vd.type.isTypeClass && !vd.type.isTypeDArray && !vd.type.isTypeSArray)
+ {
+ continue;
+ }
+ if (vd._init && vd._init.isVoidInitializer())
+ continue;
+
+ if (first)
+ {
+ buf.writestringln(" :");
+ first = false;
+ }
+ else
+ {
+ buf.writestringln(",");
+ }
+ writeIdentifier(vd, true);
+ buf.writeByte('(');
+
+ if (vd._init)
+ {
+ auto e = AST.initializerToExpression(vd._init);
+ printExpressionFor(vd.type, e, true);
+ }
+ buf.printf(")");
+ }
+ }
+ buf.level--;
+ buf.writenl();
+ buf.writestringln("{");
+ buf.writestringln("}");
+ auto ctor = sd.ctor ? sd.ctor.isFuncDeclaration() : null;
+ if (varCount && (!ctor || ctor.storage_class & AST.STC.disable))
+ {
+ buf.printf("%s(", sd.ident.toChars());
+ first = true;
+ foreach (m; *sd.members)
+ {
+ if (auto vd = m.isVarDeclaration())
+ {
+ if (!memberField(vd))
+ continue;
+ if (!first)
+ buf.writestring(", ");
+ assert(vd.type);
+ assert(vd.ident);
+ typeToBuffer(vd.type, vd, true);
+ // Don't print default value for first parameter to not clash
+ // with the default ctor defined above
+ if (!first)
+ {
+ buf.writestring(" = ");
+ printExpressionFor(vd.type, findDefaultInitializer(vd));
+ }
+ first = false;
+ }
+ }
+ buf.writestring(") :");
+ buf.level++;
+ buf.writenl();
+
+ first = true;
+ foreach (m; *sd.members)
+ {
+ if (auto vd = m.isVarDeclaration())
+ {
+ if (!memberField(vd))
+ continue;
+
+ if (first)
+ first = false;
+ else
+ buf.writestringln(",");
+
+ writeIdentifier(vd, true);
+ buf.writeByte('(');
+ writeIdentifier(vd, true);
+ buf.writeByte(')');
+ }
+ }
+ buf.writenl();
+ buf.writestringln("{}");
+ buf.level--;
+ }
+ }
+
+ buf.level--;
+ adparent = save;
+ buf.writestringln("};");
+
+ popAlignToBuffer(sd.alignment);
+ buf.writenl();
+
+ // Workaround because size triggers a forward-reference error
+ // for struct templates (the size is undetermined even if the
+ // size doesn't depend on the parameters)
+ debug (Debug_DtoH_Checks)
+ if (!tdparent)
+ {
+ checkbuf.level++;
+ const sn = sd.ident.toChars();
+ const sz = sd.size(Loc.initial);
+ checkbuf.printf("assert(sizeof(%s) == %llu);", sn, sz);
+ checkbuf.writenl();
+ checkbuf.level--;
+ }
+ }
+
+ /// Starts a custom alignment section using `#pragma pack` if
+ /// `alignment` specifies a custom alignment
+ private void pushAlignToBuffer(uint alignment)
+ {
+ // DMD ensures alignment is a power of two
+ //assert(alignment > 0 && ((alignment & (alignment - 1)) == 0),
+ // "Invalid alignment size");
+
+ // When no alignment is specified, `uint.max` is the default
+ // FIXME: alignment is 0 for structs templated members
+ if (alignment == STRUCTALIGN_DEFAULT || (tdparent && alignment == 0))
+ {
+ return;
+ }
+
+ buf.printf("#pragma pack(push, %d)", alignment);
+ buf.writenl();
+ }
+
+ /// Ends a custom alignment section using `#pragma pack` if
+ /// `alignment` specifies a custom alignment
+ private void popAlignToBuffer(uint alignment)
+ {
+ if (alignment == STRUCTALIGN_DEFAULT || (tdparent && alignment == 0))
+ return;
+
+ buf.writestringln("#pragma pack(pop)");
+ }
+
+ override void visit(AST.ClassDeclaration cd)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!cd);
+
+ if (cd.baseClass && shouldEmit(cd))
+ includeSymbol(cd.baseClass);
+
+ if (!shouldEmitAndMarkVisited(cd))
+ return;
+
+ writeProtection(cd.visibility.kind);
+
+ const classAsStruct = cd.cppmangle == CPPMANGLE.asStruct;
+ buf.writestring(classAsStruct ? "struct " : "class ");
+ writeIdentifier(cd);
+
+ if (cd.storage_class & AST.STC.final_ || (tdparent && this.storageClass & AST.STC.final_))
+ buf.writestring(" final");
+
+ assert(cd.baseclasses);
+
+ foreach (i, base; *cd.baseclasses)
+ {
+ buf.writestring(i == 0 ? " : public " : ", public ");
+
+ // Base classes/interfaces might depend on template parameters,
+ // e.g. class A(T) : B!T { ... }
+ if (base.sym is null)
+ {
+ base.type.accept(this);
+ }
+ else
+ {
+ writeFullName(base.sym);
+ }
+ }
+
+ if (!cd.members)
+ {
+ buf.writestring(";");
+ buf.writenl();
+ buf.writenl();
+ return;
+ }
+
+ buf.writenl();
+ buf.writestringln("{");
+
+ const protStash = this.currentVisibility;
+ this.currentVisibility = classAsStruct ? AST.Visibility.Kind.public_ : AST.Visibility.Kind.private_;
+ scope (exit) this.currentVisibility = protStash;
+
+ auto save = adparent;
+ adparent = cd;
+ buf.level++;
+ foreach (m; *cd.members)
+ {
+ m.accept(this);
+ }
+ buf.level--;
+ adparent = save;
+
+ buf.writestringln("};");
+ buf.writenl();
+ }
+
+ override void visit(AST.EnumDeclaration ed)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!ed);
+
+ if (!shouldEmitAndMarkVisited(ed))
+ return;
+
+ if (ed.isSpecial())
+ {
+ //ignored("%s because it is a special C++ type", ed.toPrettyChars());
+ return;
+ }
+
+ // we need to know a bunch of stuff about the enum...
+ bool isAnonymous = ed.ident is null;
+ const isOpaque = !ed.members;
+ AST.Type type = ed.memtype;
+ if (!type && !isOpaque)
+ {
+ // check all keys have matching type
+ foreach (_m; *ed.members)
+ {
+ auto m = _m.isEnumMember();
+ if (!type)
+ type = m.type;
+ else if (m.type !is type)
+ {
+ type = null;
+ break;
+ }
+ }
+ }
+ EnumKind kind = getEnumKind(type);
+
+ if (isOpaque)
+ {
+ // Opaque enums were introduced in C++ 11 (workaround?)
+ if (global.params.cplusplus < CppStdRevision.cpp11)
+ {
+ ignored("%s because opaque enums require C++ 11", ed.toPrettyChars());
+ return;
+ }
+ // Opaque enum defaults to int but the type might not be set
+ else if (!type)
+ {
+ kind = EnumKind.Int;
+ }
+ // Cannot apply namespace workaround for non-integral types
+ else if (kind != EnumKind.Int && kind != EnumKind.Numeric)
+ {
+ ignored("enum %s because of its base type", ed.toPrettyChars());
+ return;
+ }
+ }
+
+ // determine if this is an enum, or just a group of manifest constants
+ bool manifestConstants = !isOpaque && (!type || (isAnonymous && kind == EnumKind.Other));
+ assert(!manifestConstants || isAnonymous);
+
+ writeProtection(ed.visibility.kind);
+
+ // write the enum header
+ if (!manifestConstants)
+ {
+ if (kind == EnumKind.Int || kind == EnumKind.Numeric)
+ {
+ buf.writestring("enum");
+ // D enums are strong enums, but there exists only a direct mapping
+ // with 'enum class' from C++-11 onwards.
+ if (global.params.cplusplus >= CppStdRevision.cpp11)
+ {
+ if (!isAnonymous)
+ {
+ buf.writestring(" class ");
+ writeIdentifier(ed);
+ }
+ if (kind == EnumKind.Numeric)
+ {
+ buf.writestring(" : ");
+ determineEnumType(type).accept(this);
+ }
+ }
+ else if (!isAnonymous)
+ {
+ buf.writeByte(' ');
+ writeIdentifier(ed);
+ }
+ }
+ else
+ {
+ buf.writestring("namespace");
+ if(!isAnonymous)
+ {
+ buf.writeByte(' ');
+ writeIdentifier(ed);
+ }
+ }
+ // Opaque enums have no members, hence skip the body
+ if (isOpaque)
+ {
+ buf.writestringln(";");
+ return;
+ }
+ else
+ {
+ buf.writenl();
+ buf.writestringln("{");
+ }
+ }
+
+ // emit constant for each member
+ if (!manifestConstants)
+ buf.level++;
+
+ foreach (_m; *ed.members)
+ {
+ auto m = _m.isEnumMember();
+ AST.Type memberType = type ? type : m.type;
+ const EnumKind memberKind = type ? kind : getEnumKind(memberType);
+
+ if (!manifestConstants && (kind == EnumKind.Int || kind == EnumKind.Numeric))
+ {
+ // C++-98 compatible enums must use the typename as a prefix to avoid
+ // collisions with other identifiers in scope. For consistency with D,
+ // the enum member `Type.member` is emitted as `Type_member` in C++-98.
+ if (!isAnonymous && global.params.cplusplus < CppStdRevision.cpp11)
+ {
+ writeIdentifier(ed);
+ buf.writeByte('_');
+ }
+ writeIdentifier(m, true);
+ buf.writestring(" = ");
+
+ auto ie = cast(AST.IntegerExp)m.value;
+ visitInteger(ie.toInteger(), memberType);
+ buf.writestring(",");
+ }
+ else if (global.params.cplusplus >= CppStdRevision.cpp11 &&
+ manifestConstants && (memberKind == EnumKind.Int || memberKind == EnumKind.Numeric))
+ {
+ buf.writestring("enum : ");
+ determineEnumType(memberType).accept(this);
+ buf.writestring(" { ");
+ writeIdentifier(m, true);
+ buf.writestring(" = ");
+
+ auto ie = cast(AST.IntegerExp)m.value;
+ visitInteger(ie.toInteger(), memberType);
+ buf.writestring(" };");
+ }
+ else
+ {
+ buf.writestring("static ");
+ auto target = determineEnumType(memberType);
+ target.accept(this);
+ buf.writestring(" const ");
+ writeIdentifier(m, true);
+ buf.writestring(" = ");
+ printExpressionFor(target, m.origValue);
+ buf.writestring(";");
+ }
+ buf.writenl();
+ }
+
+ if (!manifestConstants)
+ buf.level--;
+ // write the enum tail
+ if (!manifestConstants)
+ buf.writestring("};");
+ buf.writenl();
+ buf.writenl();
+ }
+
+ override void visit(AST.EnumMember em)
+ {
+ assert(em.ed);
+
+ // Members of anonymous members are reachable without referencing the
+ // EnumDeclaration, e.g. public import foo : someEnumMember;
+ if (em.ed.isAnonymous())
+ {
+ visit(em.ed);
+ return;
+ }
+
+ assert(false, "This node type should be handled in the EnumDeclaration");
+ }
+
+ /**
+ * Prints a member/parameter/variable declaration into `buf`.
+ *
+ * Params:
+ * t = the type (used if `this.origType` is null)
+ * s = the symbol denoting the identifier
+ * canFixup = whether the identifier may be changed without affecting
+ * binary compatibility (forwarded to `writeIdentifier`)
+ */
+ private void typeToBuffer(AST.Type t, AST.Dsymbol s, const bool canFixup = false)
+ {
+ debug (Debug_DtoH)
+ {
+ printf("[typeToBuffer(AST.Type, AST.Dsymbol) enter] %s sym %s\n", t.toChars(), s.toChars());
+ scope(exit) printf("[typeToBuffer(AST.Type, AST.Dsymbol) exit] %s sym %s\n", t.toChars(), s.toChars());
+ }
+
+ this.ident = s.ident;
+ auto type = origType ? *origType : t;
+ AST.Dsymbol customLength;
+
+ // Check for quirks that are usually resolved during semantic
+ if (tdparent)
+ {
+ // Declarations within template declarations might use TypeAArray
+ // instead of TypeSArray when the length is not an IntegerExp,
+ // e.g. int[SOME_CONSTANT]
+ if (auto taa = type.isTypeAArray())
+ {
+ // Try to resolve the symbol from the key if it's not an actual type
+ Identifier id;
+ if (auto ti = taa.index.isTypeIdentifier())
+ id = ti.ident;
+
+ if (id)
+ {
+ auto sym = findSymbol(id, adparent ? adparent : tdparent);
+ if (!sym)
+ {
+ // Couldn't resolve, assume actual AA
+ }
+ else if (AST.isType(sym))
+ {
+ // a real associative array, forward to visit
+ }
+ else if (auto vd = sym.isVarDeclaration())
+ {
+ // Actually a static array with length symbol
+ customLength = sym;
+ type = taa.next; // visit the element type, length is written below
+ }
+ else
+ {
+ printf("Resolved unexpected symbol while determining static array length: %s\n", sym.toChars());
+ fflush(stdout);
+ fatal();
+ }
+ }
+ }
+ }
+ type.accept(this);
+ if (this.ident)
+ {
+ buf.writeByte(' ');
+ writeIdentifier(s, canFixup);
+ }
+ this.ident = null;
+
+ // Size is either taken from the type or resolved above
+ auto tsa = t.isTypeSArray();
+ if (tsa || customLength)
+ {
+ buf.writeByte('[');
+ if (tsa)
+ tsa.dim.accept(this);
+ else
+ writeFullName(customLength);
+ buf.writeByte(']');
+ }
+ else if (t.isTypeNoreturn())
+ buf.writestring("[0]");
+ }
+
+ override void visit(AST.Type t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+ printf("Invalid type: %s\n", t.toPrettyChars());
+ assert(0);
+ }
+
+ override void visit(AST.TypeNoreturn t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+
+ buf.writestring("/* noreturn */ char");
+ }
+
+ override void visit(AST.TypeIdentifier t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+
+ // Try to resolve the referenced symbol
+ if (auto sym = findSymbol(t.ident))
+ ensureDeclared(outermostSymbol(sym));
+
+ if (t.idents.length)
+ buf.writestring("typename ");
+
+ writeIdentifier(t.ident, t.loc, "type", tdparent !is null);
+
+ foreach (arg; t.idents)
+ {
+ buf.writestring("::");
+
+ import dmd.root.rootobject;
+ // Is this even possible?
+ if (arg.dyncast != DYNCAST.identifier)
+ {
+ printf("arg.dyncast() = %d\n", arg.dyncast());
+ assert(false);
+ }
+ buf.writestring((cast(Identifier) arg).toChars());
+ }
+ }
+
+ override void visit(AST.TypeNull t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+
+ if (global.params.cplusplus >= CppStdRevision.cpp11)
+ buf.writestring("nullptr_t");
+ else
+ buf.writestring("void*");
+
+ }
+
+ override void visit(AST.TypeTypeof t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+
+ assert(t.exp);
+
+ if (t.exp.type)
+ {
+ t.exp.type.accept(this);
+ }
+ else if (t.exp.isThisExp())
+ {
+ // Short circuit typeof(this) => <Aggregate name>
+ assert(adparent);
+ buf.writestring(adparent.ident.toChars());
+ }
+ else
+ {
+ // Relying on C++'s typeof might produce wrong results
+ // but it's the best we've got here.
+ buf.writestring("typeof(");
+ t.exp.accept(this);
+ buf.writeByte(')');
+ }
+ }
+
+ override void visit(AST.TypeBasic t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+
+ if (t.isConst() || t.isImmutable())
+ buf.writestring("const ");
+ string typeName;
+ switch (t.ty)
+ {
+ case AST.Tvoid: typeName = "void"; break;
+ case AST.Tbool: typeName = "bool"; break;
+ case AST.Tchar: typeName = "char"; break;
+ case AST.Twchar: typeName = "char16_t"; break;
+ case AST.Tdchar: typeName = "char32_t"; break;
+ case AST.Tint8: typeName = "int8_t"; break;
+ case AST.Tuns8: typeName = "uint8_t"; break;
+ case AST.Tint16: typeName = "int16_t"; break;
+ case AST.Tuns16: typeName = "uint16_t"; break;
+ case AST.Tint32: typeName = "int32_t"; break;
+ case AST.Tuns32: typeName = "uint32_t"; break;
+ case AST.Tint64: typeName = "int64_t"; break;
+ case AST.Tuns64: typeName = "uint64_t"; break;
+ case AST.Tfloat32: typeName = "float"; break;
+ case AST.Tfloat64: typeName = "double"; break;
+ case AST.Tfloat80:
+ typeName = "_d_real";
+ hasReal = true;
+ break;
+ case AST.Tcomplex32: typeName = "_Complex float"; break;
+ case AST.Tcomplex64: typeName = "_Complex double"; break;
+ case AST.Tcomplex80:
+ typeName = "_Complex _d_real";
+ hasReal = true;
+ break;
+ // ???: This is not strictly correct, but it should be ignored
+ // in all places where it matters most (variables, functions, ...).
+ case AST.Timaginary32: typeName = "float"; break;
+ case AST.Timaginary64: typeName = "double"; break;
+ case AST.Timaginary80:
+ typeName = "_d_real";
+ hasReal = true;
+ break;
+ default:
+ //t.print();
+ assert(0);
+ }
+ buf.writestring(typeName);
+ }
+
+ override void visit(AST.TypePointer t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+
+ auto ts = t.next.isTypeStruct();
+ if (ts && !strcmp(ts.sym.ident.toChars(), "__va_list_tag"))
+ {
+ buf.writestring("va_list");
+ return;
+ }
+
+ // Pointer targets can be forward referenced
+ const fwdSave = forwarding;
+ forwarding = true;
+ scope (exit) forwarding = fwdSave;
+
+ t.next.accept(this);
+ if (t.next.ty != AST.Tfunction)
+ buf.writeByte('*');
+ if (t.isConst() || t.isImmutable())
+ buf.writestring(" const");
+ }
+
+ override void visit(AST.TypeSArray t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+ t.next.accept(this);
+ }
+
+ override void visit(AST.TypeAArray t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+ AST.Type.tvoidptr.accept(this);
+ }
+
+ override void visit(AST.TypeFunction tf)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!tf);
+
+ tf.next.accept(this);
+ buf.writeByte('(');
+ buf.writeByte('*');
+ if (ident)
+ buf.writestring(ident.toChars());
+ ident = null;
+ buf.writeByte(')');
+ buf.writeByte('(');
+ foreach (i, fparam; tf.parameterList)
+ {
+ if (i)
+ buf.writestring(", ");
+ fparam.accept(this);
+ }
+ if (tf.parameterList.varargs)
+ {
+ if (tf.parameterList.parameters.dim && tf.parameterList.varargs == 1)
+ buf.writestring(", ");
+ buf.writestring("...");
+ }
+ buf.writeByte(')');
+ }
+
+ /// Writes the type that represents `ed` into `buf`.
+ /// (Might not be `ed` for special enums or enums that were emitted as namespaces)
+ private void enumToBuffer(AST.EnumDeclaration ed)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!ed);
+
+ if (ed.isSpecial())
+ {
+ if (ed.ident == DMDType.c_long)
+ buf.writestring("long");
+ else if (ed.ident == DMDType.c_ulong)
+ buf.writestring("unsigned long");
+ else if (ed.ident == DMDType.c_longlong)
+ buf.writestring("long long");
+ else if (ed.ident == DMDType.c_ulonglong)
+ buf.writestring("unsigned long long");
+ else if (ed.ident == DMDType.c_long_double)
+ buf.writestring("long double");
+ else if (ed.ident == DMDType.c_wchar_t)
+ buf.writestring("wchar_t");
+ else if (ed.ident == DMDType.c_complex_float)
+ buf.writestring("_Complex float");
+ else if (ed.ident == DMDType.c_complex_double)
+ buf.writestring("_Complex double");
+ else if (ed.ident == DMDType.c_complex_real)
+ buf.writestring("_Complex long double");
+ else
+ {
+ //ed.print();
+ assert(0);
+ }
+ return;
+ }
+
+ const kind = getEnumKind(ed.memtype);
+
+ // Check if the enum was emitted as a real enum
+ if (kind == EnumKind.Int || kind == EnumKind.Numeric)
+ {
+ writeFullName(ed);
+ }
+ else
+ {
+ // Use the base type if the enum was emitted as a namespace
+ buf.printf("/* %s */ ", ed.ident.toChars());
+ ed.memtype.accept(this);
+ }
+ }
+
+ override void visit(AST.TypeEnum t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+
+ if (t.isConst() || t.isImmutable())
+ buf.writestring("const ");
+ enumToBuffer(t.sym);
+ }
+
+ override void visit(AST.TypeStruct t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+
+ if (t.isConst() || t.isImmutable())
+ buf.writestring("const ");
+ writeFullName(t.sym);
+ }
+
+ override void visit(AST.TypeDArray t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+
+ if (t.isConst() || t.isImmutable())
+ buf.writestring("const ");
+ buf.writestring("_d_dynamicArray< ");
+ t.next.accept(this);
+ buf.writestring(" >");
+ }
+
+ override void visit(AST.TypeInstance t)
+ {
+ visitTi(t.tempinst);
+ }
+
+ private void visitTi(AST.TemplateInstance ti)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!ti);
+
+ // Ensure that the TD appears before the instance
+ if (auto td = findTemplateDeclaration(ti))
+ ensureDeclared(td);
+
+ foreach (o; *ti.tiargs)
+ {
+ if (!AST.isType(o))
+ return;
+ }
+ buf.writestring(ti.name.toChars());
+ buf.writeByte('<');
+ foreach (i, o; *ti.tiargs)
+ {
+ if (i)
+ buf.writestring(", ");
+ if (auto tt = AST.isType(o))
+ {
+ tt.accept(this);
+ }
+ else
+ {
+ //ti.print();
+ //o.print();
+ assert(0);
+ }
+ }
+ buf.writestring(" >");
+ }
+
+ override void visit(AST.TemplateDeclaration td)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!td);
+
+ if (!shouldEmitAndMarkVisited(td))
+ return;
+
+ if (!td.parameters || !td.onemember || (!td.onemember.isStructDeclaration && !td.onemember.isClassDeclaration && !td.onemember.isFuncDeclaration))
+ {
+ visit(cast(AST.Dsymbol)td);
+ return;
+ }
+
+ // Explicitly disallow templates with non-type parameters or specialization.
+ foreach (p; *td.parameters)
+ {
+ if (!p.isTemplateTypeParameter() || p.specialization())
+ {
+ visit(cast(AST.Dsymbol)td);
+ return;
+ }
+ }
+
+ auto save = tdparent;
+ tdparent = td;
+ const bookmark = buf.length;
+ printTemplateParams(td);
+
+ const oldIgnored = this.ignoredCounter;
+ td.onemember.accept(this);
+
+ // Remove "template<...>" if the symbol could not be emitted
+ if (oldIgnored != this.ignoredCounter)
+ buf.setsize(bookmark);
+
+ tdparent = save;
+ }
+
+ /// Writes the template<...> header for the supplied template declaration
+ private void printTemplateParams(const AST.TemplateDeclaration td)
+ {
+ buf.writestring("template <");
+ bool first = true;
+ foreach (p; *td.parameters)
+ {
+ if (first)
+ first = false;
+ else
+ buf.writestring(", ");
+ buf.writestring("typename ");
+ writeIdentifier(p.ident, p.loc, "template parameter", true);
+ }
+ buf.writestringln(">");
+ }
+
+ /// Emit declarations of the TemplateMixin in the current scope
+ override void visit(AST.TemplateMixin tm)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!tm);
+
+ auto members = tm.members;
+
+ // members are missing for instances inside of TemplateDeclarations, e.g.
+ // template Foo(T) { mixin Bar!T; }
+ if (!members)
+ {
+ if (auto td = findTemplateDeclaration(tm))
+ members = td.members; // Emit members of the template
+ else
+ return; // Cannot emit mixin
+ }
+
+ foreach (s; *members)
+ {
+ // kind is undefined without semantic
+ const kind = s.visible().kind;
+ if (kind == AST.Visibility.Kind.public_ || kind == AST.Visibility.Kind.undefined)
+ s.accept(this);
+ }
+ }
+
+ /**
+ * Finds a symbol with the identifier `name` by iterating the linked list of parent
+ * symbols, starting from `context`.
+ *
+ * Returns: the symbol or `null` if missing
+ */
+ private AST.Dsymbol findSymbol(Identifier name, AST.Dsymbol context)
+ {
+ // Follow the declaration context
+ for (auto par = context; par; par = par.toParentDecl())
+ {
+ // Check that `name` doesn't refer to a template parameter
+ if (auto td = par.isTemplateDeclaration())
+ {
+ foreach (const p; *td.parameters)
+ {
+ if (p.ident == name)
+ return null;
+ }
+ }
+
+ if (auto mem = findMember(par, name))
+ {
+ return mem;
+ }
+ }
+ return null;
+ }
+
+ /// ditto
+ private AST.Dsymbol findSymbol(Identifier name)
+ {
+ AST.Dsymbol sym;
+ if (adparent)
+ sym = findSymbol(name, adparent);
+
+ if (!sym && tdparent)
+ sym = findSymbol(name, tdparent);
+
+ return sym;
+ }
+
+ /// Finds the template declaration for instance `ti`
+ private AST.TemplateDeclaration findTemplateDeclaration(AST.TemplateInstance ti)
+ {
+ if (ti.tempdecl)
+ return ti.tempdecl.isTemplateDeclaration();
+
+ assert(tdparent); // Only missing inside of templates
+
+ // Search for the TemplateDeclaration, starting from the enclosing scope
+ // if known or the enclosing template.
+ auto sym = findSymbol(ti.name, ti.parent ? ti.parent : tdparent);
+ return sym ? sym.isTemplateDeclaration() : null;
+ }
+
+ override void visit(AST.TypeClass t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+
+ // Classes are emitted as pointer and hence can be forwarded
+ const fwdSave = forwarding;
+ forwarding = true;
+ scope (exit) forwarding = fwdSave;
+
+ if (t.isConst() || t.isImmutable())
+ buf.writestring("const ");
+ writeFullName(t.sym);
+ buf.writeByte('*');
+ if (t.isConst() || t.isImmutable())
+ buf.writestring(" const");
+ }
+
+ /**
+ * Writes the function signature to `buf`.
+ *
+ * Params:
+ * fd = the function to print
+ * tf = fd's type
+ */
+ private void funcToBuffer(AST.TypeFunction tf, AST.FuncDeclaration fd)
+ {
+ debug (Debug_DtoH)
+ {
+ printf("[funcToBuffer(AST.TypeFunction) enter] %s\n", fd.toChars());
+ scope(exit) printf("[funcToBuffer(AST.TypeFunction) exit] %s\n", fd.toChars());
+ }
+
+ auto originalType = cast(AST.TypeFunction)fd.originalType;
+
+ if (fd.isCtorDeclaration() || fd.isDtorDeclaration())
+ {
+ if (fd.isDtorDeclaration())
+ {
+ buf.writeByte('~');
+ }
+ buf.writestring(adparent.toChars());
+ if (!tf)
+ {
+ assert(fd.isDtorDeclaration());
+ buf.writestring("()");
+ return;
+ }
+ }
+ else
+ {
+ import dmd.root.string : toDString;
+ assert(tf.next, fd.loc.toChars().toDString());
+
+ tf.next == AST.Type.tsize_t ? originalType.next.accept(this) : tf.next.accept(this);
+ if (tf.isref)
+ buf.writeByte('&');
+ buf.writeByte(' ');
+ writeIdentifier(fd);
+ }
+
+ buf.writeByte('(');
+ foreach (i, fparam; tf.parameterList)
+ {
+ if (i)
+ buf.writestring(", ");
+ if (fparam.type == AST.Type.tsize_t && originalType)
+ {
+ fparam = originalType.parameterList[i];
+ }
+ fparam.accept(this);
+ }
+ if (tf.parameterList.varargs)
+ {
+ if (tf.parameterList.parameters.dim && tf.parameterList.varargs == 1)
+ buf.writestring(", ");
+ buf.writestring("...");
+ }
+ buf.writeByte(')');
+ }
+
+ override void visit(AST.Parameter p)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!p);
+
+ ident = p.ident;
+
+ {
+ // Reference parameters can be forwarded
+ const fwdStash = this.forwarding;
+ this.forwarding = !!(p.storageClass & AST.STC.ref_);
+ p.type.accept(this);
+ this.forwarding = fwdStash;
+ }
+
+ if (p.storageClass & AST.STC.ref_)
+ buf.writeByte('&');
+ buf.writeByte(' ');
+ if (ident)
+ // FIXME: Parameter is missing a Loc
+ writeIdentifier(ident, Loc.initial, "parameter", true);
+ ident = null;
+
+ if (p.defaultArg)
+ {
+ //printf("%s %d\n", p.defaultArg.toChars, p.defaultArg.op);
+ buf.writestring(" = ");
+ printExpressionFor(p.type, p.defaultArg);
+ }
+ }
+
+ /**
+ * Prints `exp` as an expression of type `target` while inserting
+ * appropriate code when implicit conversion does not translate
+ * directly to C++, e.g. from an enum to its base type.
+ *
+ * Params:
+ * target = the type `exp` is converted to
+ * exp = the expression to print
+ * isCtor = if `exp` is a ctor argument
+ */
+ private void printExpressionFor(AST.Type target, AST.Expression exp, const bool isCtor = false)
+ {
+ /// Determines if a static_cast is required
+ static bool needsCast(AST.Type target, AST.Expression exp)
+ {
+ // import std.stdio;
+ // writefln("%s:%s: target = %s, type = %s (%s)", exp.loc.linnum, exp.loc.charnum, target, exp.type, exp.op);
+
+ auto source = exp.type;
+
+ // DotVarExp resolve conversions, e.g from an enum to its base type
+ if (auto dve = exp.isDotVarExp())
+ source = dve.var.type;
+
+ if (!source)
+ // Defensively assume that the cast is required
+ return true;
+
+ // Conversions from enum class to base type require static_cast
+ if (global.params.cplusplus >= CppStdRevision.cpp11 &&
+ source.isTypeEnum && !target.isTypeEnum)
+ return true;
+
+ return false;
+ }
+
+ // Slices are emitted as a special struct, hence we need to fix up
+ // any expression initialising a slice variable/member
+ if (auto ta = target.isTypeDArray())
+ {
+ if (exp.isNullExp())
+ {
+ if (isCtor)
+ {
+ // Don't emit, use default ctor
+ }
+ else if (global.params.cplusplus >= CppStdRevision.cpp11)
+ {
+ // Prefer initializer list
+ buf.writestring("{}");
+ }
+ else
+ {
+ // Write __d_dynamic_array<TYPE>()
+ visit(ta);
+ buf.writestring("()");
+ }
+ return;
+ }
+
+ if (auto se = exp.isStringExp())
+ {
+ // Rewrite as <length> + <literal> pair optionally
+ // wrapped in a initializer list/ctor call
+
+ const initList = global.params.cplusplus >= CppStdRevision.cpp11;
+ if (!isCtor)
+ {
+ if (initList)
+ buf.writestring("{ ");
+ else
+ {
+ visit(ta);
+ buf.writestring("( ");
+ }
+ }
+
+ buf.printf("%zu, ", se.len);
+ visit(se);
+
+ if (!isCtor)
+ buf.writestring(initList ? " }" : " )");
+
+ return;
+ }
+ }
+ else if (auto ce = exp.isCastExp())
+ {
+ buf.writeByte('(');
+ if (ce.to)
+ ce.to.accept(this);
+ else if (ce.e1.type)
+ // Try the expression type with modifiers in case of cast(const) in templates
+ ce.e1.type.castMod(ce.mod).accept(this);
+ else
+ // Fallback, not necessarily correct but the best we've got here
+ target.accept(this);
+ buf.writestring(") ");
+ ce.e1.accept(this);
+ }
+ else if (needsCast(target, exp))
+ {
+ buf.writestring("static_cast<");
+ target.accept(this);
+ buf.writestring(">(");
+ exp.accept(this);
+ buf.writeByte(')');
+ }
+ else
+ {
+ exp.accept(this);
+ }
+ }
+
+ override void visit(AST.Expression e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+
+ // Valid in most cases, others should be overriden below
+ // to use the appropriate operators (:: and ->)
+ buf.writestring(e.toString());
+ }
+
+ override void visit(AST.UnaExp e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+
+ buf.writestring(tokToString(e.op));
+ e.e1.accept(this);
+ }
+
+ override void visit(AST.BinExp e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+
+ e.e1.accept(this);
+ buf.writeByte(' ');
+ buf.writestring(tokToString(e.op));
+ buf.writeByte(' ');
+ e.e2.accept(this);
+ }
+
+ /// Translates operator `op` into the C++ representation
+ private extern(D) static string tokToString(const TOK op)
+ {
+ switch (op) with (TOK)
+ {
+ case identity: return "==";
+ case notIdentity: return "!=";
+ default:
+ return Token.toString(op);
+ }
+ }
+
+ override void visit(AST.VarExp e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+
+ // Local members don't need another prefix and might've been renamed
+ if (e.var.isThis())
+ {
+ includeSymbol(e.var);
+ writeIdentifier(e.var, true);
+ }
+ else
+ writeFullName(e.var);
+ }
+
+ /// Partially prints the FQN including parent aggregates
+ private void printPrefix(AST.Dsymbol var)
+ {
+ if (!var || var is adparent || var.isModule())
+ return;
+
+ writeFullName(var);
+ buf.writestring("::");
+ }
+
+ override void visit(AST.CallExp e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+
+ // Dereferencing function pointers requires additional braces: (*f)(args)
+ const isFp = e.e1.isPtrExp();
+ if (isFp)
+ buf.writeByte('(');
+ else if (e.f)
+ includeSymbol(outermostSymbol(e.f));
+
+ e.e1.accept(this);
+
+ if (isFp) buf.writeByte(')');
+
+ assert(e.arguments);
+ buf.writeByte('(');
+ foreach (i, arg; *e.arguments)
+ {
+ if (i)
+ buf.writestring(", ");
+ arg.accept(this);
+ }
+ buf.writeByte(')');
+ }
+
+ override void visit(AST.DotVarExp e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+
+ if (auto sym = symbolFromType(e.e1.type))
+ includeSymbol(outermostSymbol(sym));
+
+ // Accessing members through a pointer?
+ if (auto pe = e.e1.isPtrExp)
+ {
+ pe.e1.accept(this);
+ buf.writestring("->");
+ }
+ else
+ {
+ e.e1.accept(this);
+ buf.writeByte('.');
+ }
+
+ // Should only be used to access non-static members
+ assert(e.var.isThis());
+
+ writeIdentifier(e.var, true);
+ }
+
+ override void visit(AST.DotIdExp e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+
+ e.e1.accept(this);
+ buf.writestring("::");
+ buf.writestring(e.ident.toChars());
+ }
+
+ override void visit(AST.ScopeExp e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+
+ // Usually a template instance in a TemplateDeclaration
+ if (auto ti = e.sds.isTemplateInstance())
+ visitTi(ti);
+ else
+ writeFullName(e.sds);
+ }
+
+ override void visit(AST.NullExp e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+
+ if (global.params.cplusplus >= CppStdRevision.cpp11)
+ buf.writestring("nullptr");
+ else
+ buf.writestring("NULL");
+ }
+
+ override void visit(AST.ArrayLiteralExp e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+ buf.writestring("arrayliteral");
+ }
+
+ override void visit(AST.StringExp e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+
+ if (e.sz == 2)
+ buf.writeByte('u');
+ else if (e.sz == 4)
+ buf.writeByte('U');
+ buf.writeByte('"');
+
+ for (size_t i = 0; i < e.len; i++)
+ {
+ uint c = e.charAt(i);
+ switch (c)
+ {
+ case '"':
+ case '\\':
+ buf.writeByte('\\');
+ goto default;
+ default:
+ if (c <= 0xFF)
+ {
+ if (c >= 0x20 && c < 0x80)
+ buf.writeByte(c);
+ else
+ buf.printf("\\x%02x", c);
+ }
+ else if (c <= 0xFFFF)
+ buf.printf("\\u%04x", c);
+ else
+ buf.printf("\\U%08x", c);
+ break;
+ }
+ }
+ buf.writeByte('"');
+ }
+
+ override void visit(AST.RealExp e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+
+ import dmd.root.ctfloat : CTFloat;
+
+ // Special case NaN and Infinity because floatToBuffer
+ // uses D literals (`nan` and `infinity`)
+ if (CTFloat.isNaN(e.value))
+ {
+ buf.writestring("NAN");
+ }
+ else if (CTFloat.isInfinity(e.value))
+ {
+ if (e.value < CTFloat.zero)
+ buf.writeByte('-');
+ buf.writestring("INFINITY");
+ }
+ else
+ {
+ import dmd.hdrgen;
+ // Hex floating point literals were introduced in C++ 17
+ const allowHex = global.params.cplusplus >= CppStdRevision.cpp17;
+ floatToBuffer(e.type, e.value, buf, allowHex);
+ }
+ }
+
+ override void visit(AST.IntegerExp e)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!e);
+ visitInteger(e.toInteger, e.type);
+ }
+
+ /// Writes `v` as type `t` into `buf`
+ private void visitInteger(dinteger_t v, AST.Type t)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!t);
+
+ switch (t.ty)
+ {
+ case AST.Tenum:
+ auto te = cast(AST.TypeEnum)t;
+ buf.writestring("(");
+ enumToBuffer(te.sym);
+ buf.writestring(")");
+ visitInteger(v, te.sym.memtype);
+ break;
+ case AST.Tbool:
+ buf.writestring(v ? "true" : "false");
+ break;
+ case AST.Tint8:
+ buf.printf("%d", cast(byte)v);
+ break;
+ case AST.Tuns8:
+ buf.printf("%uu", cast(ubyte)v);
+ break;
+ case AST.Tint16:
+ buf.printf("%d", cast(short)v);
+ break;
+ case AST.Tuns16:
+ case AST.Twchar:
+ buf.printf("%uu", cast(ushort)v);
+ break;
+ case AST.Tint32:
+ case AST.Tdchar:
+ buf.printf("%d", cast(int)v);
+ break;
+ case AST.Tuns32:
+ buf.printf("%uu", cast(uint)v);
+ break;
+ case AST.Tint64:
+ buf.printf("%lldLL", v);
+ break;
+ case AST.Tuns64:
+ buf.printf("%lluLLU", v);
+ break;
+ case AST.Tchar:
+ if (v > 0x20 && v < 0x80)
+ buf.printf("'%c'", cast(int)v);
+ else
+ buf.printf("%uu", cast(ubyte)v);
+ break;
+ default:
+ //t.print();
+ assert(0);
+ }
+ }
+
+ override void visit(AST.StructLiteralExp sle)
+ {
+ debug (Debug_DtoH) mixin(traceVisit!sle);
+
+ const isUnion = sle.sd.isUnionDeclaration();
+ sle.sd.type.accept(this);
+ buf.writeByte('(');
+ foreach(i, e; *sle.elements)
+ {
+ if (i)
+ buf.writestring(", ");
+
+ auto vd = sle.sd.fields[i];
+
+ // Expression may be null for unspecified elements
+ if (!e)
+ e = findDefaultInitializer(vd);
+
+ printExpressionFor(vd.type, e);
+
+ // Only emit the initializer of the first union member
+ if (isUnion)
+ break;
+ }
+ buf.writeByte(')');
+ }
+
+ /// Finds the default initializer for the given VarDeclaration
+ private static AST.Expression findDefaultInitializer(AST.VarDeclaration vd)
+ {
+ if (vd._init && !vd._init.isVoidInitializer())
+ return AST.initializerToExpression(vd._init);
+ else
+ return vd.type.defaultInitLiteral(Loc.initial);
+ }
+
+ static if (__VERSION__ < 2092)
+ {
+ private void ignored(const char* format, ...) nothrow
+ {
+ this.ignoredCounter++;
+
+ import core.stdc.stdarg;
+ if (!printIgnored)
+ return;
+
+ va_list ap;
+ va_start(ap, format);
+ buf.writestring("// Ignored ");
+ buf.vprintf(format, ap);
+ buf.writenl();
+ va_end(ap);
+ }
+ }
+ else
+ {
+ /// Writes a formatted message into `buf` if `printIgnored` is true
+ /// and increments `ignoredCounter`
+ pragma(printf)
+ private void ignored(const char* format, ...) nothrow
+ {
+ this.ignoredCounter++;
+
+ import core.stdc.stdarg;
+ if (!printIgnored)
+ return;
+
+ va_list ap;
+ va_start(ap, format);
+ buf.writestring("// Ignored ");
+ buf.vprintf(format, ap);
+ buf.writenl();
+ va_end(ap);
+ }
+ }
+
+ /**
+ * Determines whether `s` should be emitted. This requires that `sym`
+ * - is `extern(C[++]`)
+ * - is not instantiated from a template (visits the `TemplateDeclaration` instead)
+ *
+ * Params:
+ * sym = the symbol
+ *
+ * Returns: whether `sym` should be emitted
+ */
+ private bool shouldEmit(AST.Dsymbol sym)
+ {
+ import dmd.aggregate : ClassKind;
+ debug (Debug_DtoH)
+ {
+ printf("[shouldEmitAndMarkVisited enter] %s\n", sym.toPrettyChars());
+ scope(exit) printf("[shouldEmitAndMarkVisited exit] %s\n", sym.toPrettyChars());
+ }
+
+ // Template *instances* should not be emitted
+ if (sym.isInstantiated())
+ return false;
+
+ // Matching linkage (except extern(C) classes which don't make sense)
+ if (linkage == LINK.cpp || (linkage == LINK.c && !sym.isClassDeclaration()))
+ return true;
+
+ // Check against the internal information which might be missing, e.g. inside of template declarations
+ if (auto dec = sym.isDeclaration())
+ return dec.linkage == LINK.cpp || dec.linkage == LINK.c;
+
+ if (auto ad = sym.isAggregateDeclaration())
+ return ad.classKind == ClassKind.cpp;
+
+ return false;
+ }
+
+ /**
+ * Determines whether `s` should be emitted. This requires that `sym`
+ * - was not visited before
+ * - is `extern(C[++]`)
+ * - is not instantiated from a template (visits the `TemplateDeclaration` instead)
+ * The result is cached in the visited nodes array.
+ *
+ * Params:
+ * sym = the symbol
+ *
+ * Returns: whether `sym` should be emitted
+ **/
+ private bool shouldEmitAndMarkVisited(AST.Dsymbol sym)
+ {
+ debug (Debug_DtoH)
+ {
+ printf("[shouldEmitAndMarkVisited enter] %s\n", sym.toPrettyChars());
+ scope(exit) printf("[shouldEmitAndMarkVisited exit] %s\n", sym.toPrettyChars());
+ }
+
+ auto statePtr = (cast(void*) sym) in visited;
+
+ // `sym` was already emitted or skipped and isn't required
+ if (statePtr && (*statePtr || !mustEmit))
+ return false;
+
+ // Template *instances* should not be emitted, forward to the declaration
+ if (auto ti = sym.isInstantiated())
+ {
+ auto td = findTemplateDeclaration(ti);
+ assert(td);
+ visit(td);
+ return false;
+ }
+
+ // Required or matching linkage (except extern(C) classes which don't make sense)
+ bool res = mustEmit || linkage == LINK.cpp || (linkage == LINK.c && !sym.isClassDeclaration());
+ if (!res)
+ {
+ // Check against the internal information which might be missing, e.g. inside of template declarations
+ auto dec = sym.isDeclaration();
+ res = dec && (dec.linkage == LINK.cpp || dec.linkage == LINK.c);
+ }
+
+ // Remember result for later calls
+ if (statePtr)
+ *statePtr = res;
+ else
+ visited[(cast(void*) sym)] = res;
+
+ // Print a warning when the symbol is ignored for the first time
+ // Might not be correct if it is required by symbol the is visited
+ // AFTER the current node
+ if (!statePtr && !res)
+ ignored("%s %s because of linkage", sym.kind(), sym.toPrettyChars());
+
+ return res;
+ }
+
+ /**
+ * Ensures that `sym` is declared before the current position in `buf` by
+ * either creating a forward reference in `fwdbuf` if possible or
+ * calling `includeSymbol` to emit the entire declaration into `donebuf`.
+ */
+ private void ensureDeclared(AST.Dsymbol sym)
+ {
+ auto par = sym.toParent2();
+ auto ed = sym.isEnumDeclaration();
+
+ // Eagerly include the symbol if we cannot create a valid forward declaration
+ // Forwarding of scoped enums requires C++11 or above
+ if (!forwarding || (par && !par.isModule()) || (ed && global.params.cplusplus < CppStdRevision.cpp11))
+ {
+ // Emit the entire enclosing declaration if any
+ includeSymbol(outermostSymbol(sym));
+ return;
+ }
+
+ auto ti = sym.isInstantiated();
+ auto td = ti ? findTemplateDeclaration(ti) : null;
+ auto check = cast(void*) (td ? td : sym);
+
+ // Omit redundant fwd-declaration if we already emitted the entire declaration
+ if (visited.get(check, false))
+ return;
+
+ // Already created a fwd-declaration?
+ if (check in forwarded)
+ return;
+ forwarded[check] = true;
+
+ // Print template<...>
+ if (ti)
+ {
+ auto bufSave = buf;
+ buf = fwdbuf;
+ printTemplateParams(td);
+ buf = bufSave;
+ }
+
+ // Determine the kind of symbol that is forwared: struct, ...
+ const(char)* kind;
+
+ if (auto ad = sym.isAggregateDeclaration())
+ {
+ // Look for extern(C++, class) <some aggregate>
+ if (ad.cppmangle == CPPMANGLE.def)
+ kind = ad.kind();
+ else if (ad.cppmangle == CPPMANGLE.asStruct)
+ kind = "struct";
+ else
+ kind = "class";
+ }
+ else if (ed)
+ {
+ // Only called from enumToBuffer, so should always be emitted as an actual enum
+ kind = "enum class";
+ }
+ else
+ kind = sym.kind(); // Should be unreachable but just to be sure
+
+ fwdbuf.writestring(kind);
+ fwdbuf.writeByte(' ');
+ fwdbuf.writestring(sym.toChars());
+ fwdbuf.writestringln(";");
+ }
+
+ /**
+ * Writes the qualified name of `sym` into `buf` including parent
+ * symbols and template parameters.
+ *
+ * Params:
+ * sym = the symbol
+ * mustInclude = whether sym may not be forward declared
+ */
+ private void writeFullName(AST.Dsymbol sym, const bool mustInclude = false)
+ in
+ {
+ assert(sym);
+ assert(sym.ident, sym.toString());
+ // Should never be called directly with a TI, only onemember
+ assert(!sym.isTemplateInstance(), sym.toString());
+ }
+ do
+ {
+ debug (Debug_DtoH)
+ {
+ printf("[writeFullName enter] %s\n", sym.toPrettyChars());
+ scope(exit) printf("[writeFullName exit] %s\n", sym.toPrettyChars());
+ }
+
+ /// Checks whether `sym` is nested in `par` and hence doesn't need the FQN
+ static bool isNestedIn(AST.Dsymbol sym, AST.Dsymbol par)
+ {
+ while (par)
+ {
+ if (sym is par)
+ return true;
+ par = par.toParent();
+ }
+ return false;
+ }
+ AST.TemplateInstance ti;
+ bool nested;
+
+ // Check if the `sym` is nested into another symbol and hence requires `Parent::sym`
+ if (auto par = sym.toParent())
+ {
+ // toParent() yields the template instance if `sym` is the onemember of a TI
+ ti = par.isTemplateInstance();
+
+ // Skip the TI because Foo!int.Foo is folded into Foo<int>
+ if (ti) par = ti.toParent();
+
+ // Prefix the name with any enclosing declaration
+ // Stop at either module or enclosing aggregate
+ nested = !par.isModule();
+ if (nested && !isNestedIn(par, adparent))
+ {
+ writeFullName(par, true);
+ buf.writestring("::");
+ }
+ }
+
+ if (!nested)
+ {
+ // Cannot forward the symbol when called recursively
+ // for a nested symbol
+ if (mustInclude)
+ includeSymbol(sym);
+ else
+ ensureDeclared(sym);
+ }
+
+ if (ti)
+ visitTi(ti);
+ else
+ buf.writestring(sym.ident.toString());
+ }
+}
+
+/// Namespace for identifiers used to represent special enums in C++
+struct DMDType
+{
+ __gshared Identifier c_long;
+ __gshared Identifier c_ulong;
+ __gshared Identifier c_longlong;
+ __gshared Identifier c_ulonglong;
+ __gshared Identifier c_long_double;
+ __gshared Identifier c_wchar_t;
+ __gshared Identifier c_complex_float;
+ __gshared Identifier c_complex_double;
+ __gshared Identifier c_complex_real;
+
+ static void _init()
+ {
+ c_long = Identifier.idPool("__c_long");
+ c_ulong = Identifier.idPool("__c_ulong");
+ c_longlong = Identifier.idPool("__c_longlong");
+ c_ulonglong = Identifier.idPool("__c_ulonglong");
+ c_long_double = Identifier.idPool("__c_long_double");
+ c_wchar_t = Identifier.idPool("__c_wchar_t");
+ c_complex_float = Identifier.idPool("__c_complex_float");
+ c_complex_double = Identifier.idPool("__c_complex_double");
+ c_complex_real = Identifier.idPool("__c_complex_real");
+ }
+}
+
+/// Initializes all data structures used by the header generator
+void initialize()
+{
+ __gshared bool initialized;
+
+ if (!initialized)
+ {
+ initialized = true;
+
+ DMDType._init();
+ }
+}
+
+/// Writes `#if <content>` into the supplied buffer
+void hashIf(ref OutBuffer buf, string content)
+{
+ buf.writestring("#if ");
+ buf.writestringln(content);
+}
+
+/// Writes `#elif <content>` into the supplied buffer
+void hashElIf(ref OutBuffer buf, string content)
+{
+ buf.writestring("#elif ");
+ buf.writestringln(content);
+}
+
+/// Writes `#endif` into the supplied buffer
+void hashEndIf(ref OutBuffer buf)
+{
+ buf.writestringln("#endif");
+}
+
+/// Writes `#define <content>` into the supplied buffer
+void hashDefine(ref OutBuffer buf, string content)
+{
+ buf.writestring("# define ");
+ buf.writestringln(content);
+}
+
+/// Writes `#include <content>` into the supplied buffer
+void hashInclude(ref OutBuffer buf, string content)
+{
+ buf.writestring("#include ");
+ buf.writestringln(content);
+}
+
+/// Determines whether `ident` is a reserved keyword in C++
+/// Returns: the kind of keyword or `null`
+const(char*) keywordClass(const Identifier ident)
+{
+ if (!ident)
+ return null;
+
+ const name = ident.toString();
+ switch (name)
+ {
+ // C++ operators
+ case "and":
+ case "and_eq":
+ case "bitand":
+ case "bitor":
+ case "compl":
+ case "not":
+ case "not_eq":
+ case "or":
+ case "or_eq":
+ case "xor":
+ case "xor_eq":
+ return "special operator in C++";
+
+ // C++ keywords
+ case "_Complex":
+ case "const_cast":
+ case "delete":
+ case "dynamic_cast":
+ case "explicit":
+ case "friend":
+ case "inline":
+ case "mutable":
+ case "namespace":
+ case "operator":
+ case "register":
+ case "reinterpret_cast":
+ case "signed":
+ case "static_cast":
+ case "typedef":
+ case "typename":
+ case "unsigned":
+ case "using":
+ case "virtual":
+ case "volatile":
+ return "keyword in C++";
+
+ // Common macros imported by this header
+ // stddef.h
+ case "offsetof":
+ case "NULL":
+ return "default macro in C++";
+
+ // C++11 keywords
+ case "alignas":
+ case "alignof":
+ case "char16_t":
+ case "char32_t":
+ case "constexpr":
+ case "decltype":
+ case "noexcept":
+ case "nullptr":
+ case "static_assert":
+ case "thread_local":
+ case "wchar_t":
+ if (global.params.cplusplus >= CppStdRevision.cpp11)
+ return "keyword in C++11";
+ return null;
+
+ // C++20 keywords
+ case "char8_t":
+ case "consteval":
+ case "constinit":
+ // Concepts-related keywords
+ case "concept":
+ case "requires":
+ // Coroutines-related keywords
+ case "co_await":
+ case "co_yield":
+ case "co_return":
+ if (global.params.cplusplus >= CppStdRevision.cpp20)
+ return "keyword in C++20";
+ return null;
+
+ default:
+ // Identifiers starting with __ are reserved
+ if (name.length >= 2 && name[0..2] == "__")
+ return "reserved identifier in C++";
+
+ return null;
+ }
+}
+
+/// Finds the outermost symbol if `sym` is nested.
+/// Returns `sym` if it appears at module scope
+ASTCodegen.Dsymbol outermostSymbol(ASTCodegen.Dsymbol sym)
+{
+ assert(sym);
+ while (true)
+ {
+ auto par = sym.toParent();
+ if (!par || par.isModule())
+ return sym;
+ sym = par;
+ }
+}
+
+/// Fetches the symbol for user-defined types from the type `t`
+/// if `t` is either `TypeClass`, `TypeStruct` or `TypeEnum`
+ASTCodegen.Dsymbol symbolFromType(ASTCodegen.Type t)
+{
+ if (auto tc = t.isTypeClass())
+ return tc.sym;
+ if (auto ts = t.isTypeStruct())
+ return ts.sym;
+ if (auto te = t.isTypeEnum())
+ return te.sym;
+ return null;
+}
+
+/**
+ * Searches `sym` for a member with the given name.
+ *
+ * This method usually delegates to `Dsymbol.search` but might also
+ * manually check the members if the symbol did not receive semantic
+ * analysis.
+ *
+ * Params:
+ * sym = symbol to search
+ * name = identifier of the requested symbol
+ *
+ * Returns: the symbol or `null` if not found
+ */
+ASTCodegen.Dsymbol findMember(ASTCodegen.Dsymbol sym, Identifier name)
+{
+ if (auto mem = sym.search(Loc.initial, name, ASTCodegen.IgnoreErrors))
+ return mem;
+
+ // search doesn't work for declarations inside of uninstantiated
+ // `TemplateDeclaration`s due to the missing symtab.
+ if (sym.semanticRun >= ASTCodegen.PASS.semanticdone)
+ return null;
+
+ // Manually check the members if present
+ auto sds = sym.isScopeDsymbol();
+ if (!sds || !sds.members)
+ return null;
+
+ /// Recursively searches for `name` without entering nested aggregates, ...
+ static ASTCodegen.Dsymbol search(ASTCodegen.Dsymbols* members, Identifier name)
+ {
+ foreach (mem; *members)
+ {
+ if (mem.ident == name)
+ return mem;
+
+ // Look inside of private:, ...
+ if (auto ad = mem.isAttribDeclaration())
+ {
+ if (auto s = search(ad.decl, name))
+ return s;
+ }
+ }
+ return null;
+ }
+
+ return search(sds.members, name);
+}
+
+debug (Debug_DtoH)
+{
+ /// Generates code to trace the entry and exit of the enclosing `visit` function
+ string traceVisit(alias node)()
+ {
+ const type = typeof(node).stringof;
+ const method = __traits(hasMember, node, "toPrettyChars") ? "toPrettyChars" : "toChars";
+ const arg = __traits(identifier, node) ~ '.' ~ method;
+
+ return `printf("[` ~ type ~ ` enter] %s\n", ` ~ arg ~ `());
+ scope(exit) printf("[` ~ type ~ ` exit] %s\n", ` ~ arg ~ `());`;
+ }
+}
diff --git a/gcc/d/dmd/dversion.c b/gcc/d/dmd/dversion.c
deleted file mode 100644
index 269d924..0000000
--- a/gcc/d/dmd/dversion.c
+++ /dev/null
@@ -1,187 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/version.c
- */
-
-#include "root/dsystem.h"
-#include "root/root.h"
-
-#include "identifier.h"
-#include "dsymbol.h"
-#include "cond.h"
-#include "version.h"
-#include "module.h"
-
-void checkReserved(Loc loc, const char *ident);
-
-/* ================================================== */
-
-/* DebugSymbol's happen for statements like:
- * debug = identifier;
- * debug = integer;
- */
-
-DebugSymbol::DebugSymbol(Loc loc, Identifier *ident)
- : Dsymbol(ident)
-{
- this->loc = loc;
-}
-
-DebugSymbol::DebugSymbol(Loc loc, unsigned level)
- : Dsymbol()
-{
- this->level = level;
- this->loc = loc;
-}
-
-const char *DebugSymbol::toChars()
-{
- if (ident)
- return ident->toChars();
- else
- {
- OutBuffer buf;
- buf.printf("%d", level);
- return buf.extractChars();
- }
-}
-
-Dsymbol *DebugSymbol::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- DebugSymbol *ds = new DebugSymbol(loc, ident);
- ds->level = level;
- return ds;
-}
-
-void DebugSymbol::addMember(Scope *, ScopeDsymbol *sds)
-{
- //printf("DebugSymbol::addMember('%s') %s\n", sds->toChars(), toChars());
- Module *m = sds->isModule();
-
- // Do not add the member to the symbol table,
- // just make sure subsequent debug declarations work.
- if (ident)
- {
- if (!m)
- {
- error("declaration must be at module level");
- errors = true;
- }
- else
- {
- if (findCondition(m->debugidsNot, ident))
- {
- error("defined after use");
- errors = true;
- }
- if (!m->debugids)
- m->debugids = new Identifiers();
- m->debugids->push(ident);
- }
- }
- else
- {
- if (!m)
- {
- error("level declaration must be at module level");
- errors = true;
- }
- else
- m->debuglevel = level;
- }
-}
-
-const char *DebugSymbol::kind() const
-{
- return "debug";
-}
-
-/* ================================================== */
-
-/* VersionSymbol's happen for statements like:
- * version = identifier;
- * version = integer;
- */
-
-VersionSymbol::VersionSymbol(Loc loc, Identifier *ident)
- : Dsymbol(ident)
-{
- this->loc = loc;
-}
-
-VersionSymbol::VersionSymbol(Loc loc, unsigned level)
- : Dsymbol()
-{
- this->level = level;
- this->loc = loc;
-}
-
-const char *VersionSymbol::toChars()
-{
- if (ident)
- return ident->toChars();
- else
- {
- OutBuffer buf;
- buf.printf("%d", level);
- return buf.extractChars();
- }
-}
-
-Dsymbol *VersionSymbol::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- VersionSymbol *ds = ident ? new VersionSymbol(loc, ident)
- : new VersionSymbol(loc, level);
- return ds;
-}
-
-void VersionSymbol::addMember(Scope *, ScopeDsymbol *sds)
-{
- //printf("VersionSymbol::addMember('%s') %s\n", sds->toChars(), toChars());
- Module *m = sds->isModule();
-
- // Do not add the member to the symbol table,
- // just make sure subsequent debug declarations work.
- if (ident)
- {
- checkReserved(loc, ident->toChars());
- if (!m)
- {
- error("declaration must be at module level");
- errors = true;
- }
- else
- {
- if (findCondition(m->versionidsNot, ident))
- {
- error("defined after use");
- errors = true;
- }
- if (!m->versionids)
- m->versionids = new Identifiers();
- m->versionids->push(ident);
- }
- }
- else
- {
- if (!m)
- {
- error("level declaration must be at module level");
- errors = true;
- }
- else
- m->versionlevel = level;
- }
-}
-
-const char *VersionSymbol::kind() const
-{
- return "version";
-}
diff --git a/gcc/d/dmd/dversion.d b/gcc/d/dmd/dversion.d
new file mode 100644
index 0000000..0dff754
--- /dev/null
+++ b/gcc/d/dmd/dversion.d
@@ -0,0 +1,215 @@
+/**
+ * Defines a `Dsymbol` for `version = identifier` and `debug = identifier` statements.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/version.html#version-specification, Version Specification),
+ * $(LINK2 https://dlang.org/spec/version.html#debug_specification, Debug Specification).
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dversion.d, _dversion.d)
+ * Documentation: https://dlang.org/phobos/dmd_dversion.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dversion.d
+ */
+
+module dmd.dversion;
+
+import dmd.arraytypes;
+import dmd.cond;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.globals;
+import dmd.identifier;
+import dmd.root.outbuffer;
+import dmd.visitor;
+
+/***********************************************************
+ * DebugSymbol's happen for statements like:
+ * debug = identifier;
+ * debug = integer;
+ */
+extern (C++) final class DebugSymbol : Dsymbol
+{
+ uint level;
+
+ extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ super(loc, ident);
+ }
+
+ extern (D) this(const ref Loc loc, uint level)
+ {
+ super(loc, null);
+ this.level = level;
+ }
+
+ override DebugSymbol syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto ds = new DebugSymbol(loc, ident);
+ ds.comment = comment;
+ ds.level = level;
+ return ds;
+ }
+
+ override const(char)* toChars() const nothrow
+ {
+ if (ident)
+ return ident.toChars();
+ else
+ {
+ OutBuffer buf;
+ buf.print(level);
+ return buf.extractChars();
+ }
+ }
+
+ override void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ //printf("DebugSymbol::addMember('%s') %s\n", sds.toChars(), toChars());
+ Module m = sds.isModule();
+ // Do not add the member to the symbol table,
+ // just make sure subsequent debug declarations work.
+ if (ident)
+ {
+ if (!m)
+ {
+ error("declaration must be at module level");
+ errors = true;
+ }
+ else
+ {
+ if (findCondition(m.debugidsNot, ident))
+ {
+ error("defined after use");
+ errors = true;
+ }
+ if (!m.debugids)
+ m.debugids = new Identifiers();
+ m.debugids.push(ident);
+ }
+ }
+ else
+ {
+ if (!m)
+ {
+ error("level declaration must be at module level");
+ errors = true;
+ }
+ else
+ m.debuglevel = level;
+ }
+ }
+
+ override const(char)* kind() const nothrow
+ {
+ return "debug";
+ }
+
+ override inout(DebugSymbol) isDebugSymbol() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * VersionSymbol's happen for statements like:
+ * version = identifier;
+ * version = integer;
+ */
+extern (C++) final class VersionSymbol : Dsymbol
+{
+ uint level;
+
+ extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ super(loc, ident);
+ }
+
+ extern (D) this(const ref Loc loc, uint level)
+ {
+ super(loc, null);
+ this.level = level;
+ }
+
+ override VersionSymbol syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto ds = ident ? new VersionSymbol(loc, ident)
+ : new VersionSymbol(loc, level);
+ ds.comment = comment;
+ return ds;
+ }
+
+ override const(char)* toChars() const nothrow
+ {
+ if (ident)
+ return ident.toChars();
+ else
+ {
+ OutBuffer buf;
+ buf.print(level);
+ return buf.extractChars();
+ }
+ }
+
+ override void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ //printf("VersionSymbol::addMember('%s') %s\n", sds.toChars(), toChars());
+ Module m = sds.isModule();
+ // Do not add the member to the symbol table,
+ // just make sure subsequent debug declarations work.
+ if (ident)
+ {
+ VersionCondition.checkReserved(loc, ident.toString());
+ if (!m)
+ {
+ error("declaration must be at module level");
+ errors = true;
+ }
+ else
+ {
+ if (findCondition(m.versionidsNot, ident))
+ {
+ error("defined after use");
+ errors = true;
+ }
+ if (!m.versionids)
+ m.versionids = new Identifiers();
+ m.versionids.push(ident);
+ }
+ }
+ else
+ {
+ if (!m)
+ {
+ error("level declaration must be at module level");
+ errors = true;
+ }
+ else
+ m.versionlevel = level;
+ }
+ }
+
+ override const(char)* kind() const nothrow
+ {
+ return "version";
+ }
+
+ override inout(VersionSymbol) isVersionSymbol() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
diff --git a/gcc/d/dmd/entity.c b/gcc/d/dmd/entity.c
deleted file mode 100644
index cac901d..0000000
--- a/gcc/d/dmd/entity.c
+++ /dev/null
@@ -1,2390 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/entity.c
- */
-
-#include "root/dsystem.h"
-#include "root/port.h"
-
-/*********************************************
- * Convert from named entity to its encoding.
- * For reference:
- * http://www.htmlhelp.com/reference/html40/entities/
- * http://www.w3.org/2003/entities/2007/w3centities-f.ent
- */
-
-struct NameId
-{
- const char *name;
- unsigned value;
-};
-
-static NameId namesA[]={
- {"Aacgr", 0x00386}, // GREEK CAPITAL LETTER ALPHA WITH TONOS
- {"aacgr", 0x003AC}, // GREEK SMALL LETTER ALPHA WITH TONOS
- {"Aacute", 0x000C1}, // LATIN CAPITAL LETTER A WITH ACUTE
- {"aacute", 0x000E1}, // LATIN SMALL LETTER A WITH ACUTE
- {"Abreve", 0x00102}, // LATIN CAPITAL LETTER A WITH BREVE
- {"abreve", 0x00103}, // LATIN SMALL LETTER A WITH BREVE
- {"ac", 0x0223E}, // INVERTED LAZY S
- {"acd", 0x0223F}, // SINE WAVE
-// {"acE", 0x0223E;0x00333}, // INVERTED LAZY S with double underline
- {"Acirc", 0x000C2}, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX
- {"acirc", 0x000E2}, // LATIN SMALL LETTER A WITH CIRCUMFLEX
- {"acute", 0x000B4}, // ACUTE ACCENT
- {"Acy", 0x00410}, // CYRILLIC CAPITAL LETTER A
- {"acy", 0x00430}, // CYRILLIC SMALL LETTER A
- {"AElig", 0x000C6}, // LATIN CAPITAL LETTER AE
- {"aelig", 0x000E6}, // LATIN SMALL LETTER AE
- {"af", 0x02061}, // FUNCTION APPLICATION
- {"Afr", 0x1D504}, // MATHEMATICAL FRAKTUR CAPITAL A
- {"afr", 0x1D51E}, // MATHEMATICAL FRAKTUR SMALL A
- {"Agr", 0x00391}, // GREEK CAPITAL LETTER ALPHA
- {"agr", 0x003B1}, // GREEK SMALL LETTER ALPHA
- {"Agrave", 0x000C0}, // LATIN CAPITAL LETTER A WITH GRAVE
- {"agrave", 0x000E0}, // LATIN SMALL LETTER A WITH GRAVE
- {"alefsym", 0x02135}, // ALEF SYMBOL
- {"aleph", 0x02135}, // ALEF SYMBOL
- {"Alpha", 0x00391}, // GREEK CAPITAL LETTER ALPHA
- {"alpha", 0x003B1}, // GREEK SMALL LETTER ALPHA
- {"Amacr", 0x00100}, // LATIN CAPITAL LETTER A WITH MACRON
- {"amacr", 0x00101}, // LATIN SMALL LETTER A WITH MACRON
- {"amalg", 0x02A3F}, // AMALGAMATION OR COPRODUCT
- {"amp", 0x00026}, // AMPERSAND
- {"AMP", 0x00026}, // AMPERSAND
- {"and", 0x02227}, // LOGICAL AND
- {"And", 0x02A53}, // DOUBLE LOGICAL AND
- {"andand", 0x02A55}, // TWO INTERSECTING LOGICAL AND
- {"andd", 0x02A5C}, // LOGICAL AND WITH HORIZONTAL DASH
- {"andslope", 0x02A58}, // SLOPING LARGE AND
- {"andv", 0x02A5A}, // LOGICAL AND WITH MIDDLE STEM
- {"ang", 0x02220}, // ANGLE
- {"ange", 0x029A4}, // ANGLE WITH UNDERBAR
- {"angle", 0x02220}, // ANGLE
- {"angmsd", 0x02221}, // MEASURED ANGLE
- {"angmsdaa", 0x029A8}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT
- {"angmsdab", 0x029A9}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT
- {"angmsdac", 0x029AA}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT
- {"angmsdad", 0x029AB}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT
- {"angmsdae", 0x029AC}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP
- {"angmsdaf", 0x029AD}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP
- {"angmsdag", 0x029AE}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN
- {"angmsdah", 0x029AF}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN
- {"angrt", 0x0221F}, // RIGHT ANGLE
- {"angrtvb", 0x022BE}, // RIGHT ANGLE WITH ARC
- {"angrtvbd", 0x0299D}, // MEASURED RIGHT ANGLE WITH DOT
- {"angsph", 0x02222}, // SPHERICAL ANGLE
- {"angst", 0x000C5}, // LATIN CAPITAL LETTER A WITH RING ABOVE
- {"angzarr", 0x0237C}, // RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW
- {"Aogon", 0x00104}, // LATIN CAPITAL LETTER A WITH OGONEK
- {"aogon", 0x00105}, // LATIN SMALL LETTER A WITH OGONEK
- {"Aopf", 0x1D538}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL A
- {"aopf", 0x1D552}, // MATHEMATICAL DOUBLE-STRUCK SMALL A
- {"ap", 0x02248}, // ALMOST EQUAL TO
- {"apacir", 0x02A6F}, // ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT
- {"ape", 0x0224A}, // ALMOST EQUAL OR EQUAL TO
- {"apE", 0x02A70}, // APPROXIMATELY EQUAL OR EQUAL TO
- {"apid", 0x0224B}, // TRIPLE TILDE
- {"apos", 0x00027}, // APOSTROPHE
- {"ApplyFunction", 0x02061}, // FUNCTION APPLICATION
- {"approx", 0x02248}, // ALMOST EQUAL TO
- {"approxeq", 0x0224A}, // ALMOST EQUAL OR EQUAL TO
- {"Aring", 0x000C5}, // LATIN CAPITAL LETTER A WITH RING ABOVE
- {"aring", 0x000E5}, // LATIN SMALL LETTER A WITH RING ABOVE
- {"Ascr", 0x1D49C}, // MATHEMATICAL SCRIPT CAPITAL A
- {"ascr", 0x1D4B6}, // MATHEMATICAL SCRIPT SMALL A
- {"Assign", 0x02254}, // COLON EQUALS
- {"ast", 0x0002A}, // ASTERISK
- {"asymp", 0x02248}, // ALMOST EQUAL TO
- {"asympeq", 0x0224D}, // EQUIVALENT TO
- {"Atilde", 0x000C3}, // LATIN CAPITAL LETTER A WITH TILDE
- {"atilde", 0x000E3}, // LATIN SMALL LETTER A WITH TILDE
- {"Auml", 0x000C4}, // LATIN CAPITAL LETTER A WITH DIAERESIS
- {"auml", 0x000E4}, // LATIN SMALL LETTER A WITH DIAERESIS
- {"awconint", 0x02233}, // ANTICLOCKWISE CONTOUR INTEGRAL
- {"awint", 0x02A11}, // ANTICLOCKWISE INTEGRATION
- {NULL, 0}
-};
-
-static NameId namesB[]={
- {"backcong", 0x0224C}, // ALL EQUAL TO
- {"backepsilon", 0x003F6}, // GREEK REVERSED LUNATE EPSILON SYMBOL
- {"backprime", 0x02035}, // REVERSED PRIME
- {"backsim", 0x0223D}, // REVERSED TILDE
- {"backsimeq", 0x022CD}, // REVERSED TILDE EQUALS
- {"Backslash", 0x02216}, // SET MINUS
-// "b.alpha", 0x1D6C2}, // MATHEMATICAL BOLD SMALL ALPHA
- {"Barv", 0x02AE7}, // SHORT DOWN TACK WITH OVERBAR
- {"barvee", 0x022BD}, // NOR
- {"barwed", 0x02305}, // PROJECTIVE
- {"Barwed", 0x02306}, // PERSPECTIVE
- {"barwedge", 0x02305}, // PROJECTIVE
-// "b.beta", 0x1D6C3}, // MATHEMATICAL BOLD SMALL BETA
- {"bbrk", 0x023B5}, // BOTTOM SQUARE BRACKET
- {"bbrktbrk", 0x023B6}, // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET
-// "b.chi", 0x1D6D8}, // MATHEMATICAL BOLD SMALL CHI
- {"bcong", 0x0224C}, // ALL EQUAL TO
- {"Bcy", 0x00411}, // CYRILLIC CAPITAL LETTER BE
- {"bcy", 0x00431}, // CYRILLIC SMALL LETTER BE
-// "b.Delta", 0x1D6AB}, // MATHEMATICAL BOLD CAPITAL DELTA
-// "b.delta", 0x1D6C5}, // MATHEMATICAL BOLD SMALL DELTA
- {"bdquo", 0x0201E}, // DOUBLE LOW-9 QUOTATION MARK
- {"becaus", 0x02235}, // BECAUSE
- {"because", 0x02235}, // BECAUSE
- {"Because", 0x02235}, // BECAUSE
- {"bemptyv", 0x029B0}, // REVERSED EMPTY SET
- {"bepsi", 0x003F6}, // GREEK REVERSED LUNATE EPSILON SYMBOL
-// "b.epsi", 0x1D6C6}, // MATHEMATICAL BOLD SMALL EPSILON
-// "b.epsiv", 0x1D6DC}, // MATHEMATICAL BOLD EPSILON SYMBOL
- {"bernou", 0x0212C}, // SCRIPT CAPITAL B
- {"Bernoullis", 0x0212C}, // SCRIPT CAPITAL B
- {"Beta", 0x00392}, // GREEK CAPITAL LETTER BETA
- {"beta", 0x003B2}, // GREEK SMALL LETTER BETA
-// "b.eta", 0x1D6C8}, // MATHEMATICAL BOLD SMALL ETA
- {"beth", 0x02136}, // BET SYMBOL
- {"between", 0x0226C}, // BETWEEN
- {"Bfr", 0x1D505}, // MATHEMATICAL FRAKTUR CAPITAL B
- {"bfr", 0x1D51F}, // MATHEMATICAL FRAKTUR SMALL B
-// "b.Gamma", 0x1D6AA}, // MATHEMATICAL BOLD CAPITAL GAMMA
-// "b.gamma", 0x1D6C4}, // MATHEMATICAL BOLD SMALL GAMMA
-// "b.Gammad", 0x1D7CA}, // MATHEMATICAL BOLD CAPITAL DIGAMMA
-// "b.gammad", 0x1D7CB}, // MATHEMATICAL BOLD SMALL DIGAMMA
- {"Bgr", 0x00392}, // GREEK CAPITAL LETTER BETA
- {"bgr", 0x003B2}, // GREEK SMALL LETTER BETA
- {"bigcap", 0x022C2}, // N-ARY INTERSECTION
- {"bigcirc", 0x025EF}, // LARGE CIRCLE
- {"bigcup", 0x022C3}, // N-ARY UNION
- {"bigodot", 0x02A00}, // N-ARY CIRCLED DOT OPERATOR
- {"bigoplus", 0x02A01}, // N-ARY CIRCLED PLUS OPERATOR
- {"bigotimes", 0x02A02}, // N-ARY CIRCLED TIMES OPERATOR
- {"bigsqcup", 0x02A06}, // N-ARY SQUARE UNION OPERATOR
- {"bigstar", 0x02605}, // BLACK STAR
- {"bigtriangledown", 0x025BD}, // WHITE DOWN-POINTING TRIANGLE
- {"bigtriangleup", 0x025B3}, // WHITE UP-POINTING TRIANGLE
- {"biguplus", 0x02A04}, // N-ARY UNION OPERATOR WITH PLUS
- {"bigvee", 0x022C1}, // N-ARY LOGICAL OR
- {"bigwedge", 0x022C0}, // N-ARY LOGICAL AND
-// "b.iota", 0x1D6CA}, // MATHEMATICAL BOLD SMALL IOTA
-// "b.kappa", 0x1D6CB}, // MATHEMATICAL BOLD SMALL KAPPA
-// "b.kappav", 0x1D6DE}, // MATHEMATICAL BOLD KAPPA SYMBOL
- {"bkarow", 0x0290D}, // RIGHTWARDS DOUBLE DASH ARROW
- {"blacklozenge", 0x029EB}, // BLACK LOZENGE
- {"blacksquare", 0x025AA}, // BLACK SMALL SQUARE
- {"blacktriangle", 0x025B4}, // BLACK UP-POINTING SMALL TRIANGLE
- {"blacktriangledown", 0x025BE}, // BLACK DOWN-POINTING SMALL TRIANGLE
- {"blacktriangleleft", 0x025C2}, // BLACK LEFT-POINTING SMALL TRIANGLE
- {"blacktriangleright", 0x025B8}, // BLACK RIGHT-POINTING SMALL TRIANGLE
-// "b.Lambda", 0x1D6B2}, // MATHEMATICAL BOLD CAPITAL LAMDA
-// "b.lambda", 0x1D6CC}, // MATHEMATICAL BOLD SMALL LAMDA
- {"blank", 0x02423}, // OPEN BOX
- {"blk12", 0x02592}, // MEDIUM SHADE
- {"blk14", 0x02591}, // LIGHT SHADE
- {"blk34", 0x02593}, // DARK SHADE
- {"block", 0x02588}, // FULL BLOCK
-// "b.mu", 0x1D6CD}, // MATHEMATICAL BOLD SMALL MU
-// "bne", 0x0003D;0x020E5}, // EQUALS SIGN with reverse slash
-// "bnequiv", 0x02261;0x020E5}, // IDENTICAL TO with reverse slash
- {"bnot", 0x02310}, // REVERSED NOT SIGN
- {"bNot", 0x02AED}, // REVERSED DOUBLE STROKE NOT SIGN
-// "b.nu", 0x1D6CE}, // MATHEMATICAL BOLD SMALL NU
-// "b.Omega", 0x1D6C0}, // MATHEMATICAL BOLD CAPITAL OMEGA
-// "b.omega", 0x1D6DA}, // MATHEMATICAL BOLD SMALL OMEGA
- {"Bopf", 0x1D539}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL B
- {"bopf", 0x1D553}, // MATHEMATICAL DOUBLE-STRUCK SMALL B
- {"bot", 0x022A5}, // UP TACK
- {"bottom", 0x022A5}, // UP TACK
- {"bowtie", 0x022C8}, // BOWTIE
- {"boxbox", 0x029C9}, // TWO JOINED SQUARES
- {"boxdl", 0x02510}, // BOX DRAWINGS LIGHT DOWN AND LEFT
- {"boxdL", 0x02555}, // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
- {"boxDl", 0x02556}, // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
- {"boxDL", 0x02557}, // BOX DRAWINGS DOUBLE DOWN AND LEFT
- {"boxdr", 0x0250C}, // BOX DRAWINGS LIGHT DOWN AND RIGHT
- {"boxdR", 0x02552}, // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
- {"boxDr", 0x02553}, // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
- {"boxDR", 0x02554}, // BOX DRAWINGS DOUBLE DOWN AND RIGHT
- {"boxh", 0x02500}, // BOX DRAWINGS LIGHT HORIZONTAL
- {"boxH", 0x02550}, // BOX DRAWINGS DOUBLE HORIZONTAL
- {"boxhd", 0x0252C}, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
- {"boxHd", 0x02564}, // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
- {"boxhD", 0x02565}, // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
- {"boxHD", 0x02566}, // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
- {"boxhu", 0x02534}, // BOX DRAWINGS LIGHT UP AND HORIZONTAL
- {"boxHu", 0x02567}, // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
- {"boxhU", 0x02568}, // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
- {"boxHU", 0x02569}, // BOX DRAWINGS DOUBLE UP AND HORIZONTAL
- {"boxminus", 0x0229F}, // SQUARED MINUS
- {"boxplus", 0x0229E}, // SQUARED PLUS
- {"boxtimes", 0x022A0}, // SQUARED TIMES
- {"boxul", 0x02518}, // BOX DRAWINGS LIGHT UP AND LEFT
- {"boxuL", 0x0255B}, // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
- {"boxUl", 0x0255C}, // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
- {"boxUL", 0x0255D}, // BOX DRAWINGS DOUBLE UP AND LEFT
- {"boxur", 0x02514}, // BOX DRAWINGS LIGHT UP AND RIGHT
- {"boxuR", 0x02558}, // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
- {"boxUr", 0x02559}, // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
- {"boxUR", 0x0255A}, // BOX DRAWINGS DOUBLE UP AND RIGHT
- {"boxv", 0x02502}, // BOX DRAWINGS LIGHT VERTICAL
- {"boxV", 0x02551}, // BOX DRAWINGS DOUBLE VERTICAL
- {"boxvh", 0x0253C}, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
- {"boxvH", 0x0256A}, // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
- {"boxVh", 0x0256B}, // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
- {"boxVH", 0x0256C}, // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
- {"boxvl", 0x02524}, // BOX DRAWINGS LIGHT VERTICAL AND LEFT
- {"boxvL", 0x02561}, // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
- {"boxVl", 0x02562}, // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
- {"boxVL", 0x02563}, // BOX DRAWINGS DOUBLE VERTICAL AND LEFT
- {"boxvr", 0x0251C}, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
- {"boxvR", 0x0255E}, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
- {"boxVr", 0x0255F}, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
- {"boxVR", 0x02560}, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
-// "b.Phi", 0x1D6BD}, // MATHEMATICAL BOLD CAPITAL PHI
-// "b.phi", 0x1D6D7}, // MATHEMATICAL BOLD SMALL PHI
-// "b.phiv", 0x1D6DF}, // MATHEMATICAL BOLD PHI SYMBOL
-// "b.Pi", 0x1D6B7}, // MATHEMATICAL BOLD CAPITAL PI
-// "b.pi", 0x1D6D1}, // MATHEMATICAL BOLD SMALL PI
-// "b.piv", 0x1D6E1}, // MATHEMATICAL BOLD PI SYMBOL
- {"bprime", 0x02035}, // REVERSED PRIME
-// "b.Psi", 0x1D6BF}, // MATHEMATICAL BOLD CAPITAL PSI
-// "b.psi", 0x1D6D9}, // MATHEMATICAL BOLD SMALL PSI
- {"breve", 0x002D8}, // BREVE
- {"Breve", 0x002D8}, // BREVE
-// "b.rho", 0x1D6D2}, // MATHEMATICAL BOLD SMALL RHO
-// "b.rhov", 0x1D6E0}, // MATHEMATICAL BOLD RHO SYMBOL
- {"brvbar", 0x000A6}, // BROKEN BAR
- {"Bscr", 0x0212C}, // SCRIPT CAPITAL B
- {"bscr", 0x1D4B7}, // MATHEMATICAL SCRIPT SMALL B
- {"bsemi", 0x0204F}, // REVERSED SEMICOLON
-// "b.Sigma", 0x1D6BA}, // MATHEMATICAL BOLD CAPITAL SIGMA
-// "b.sigma", 0x1D6D4}, // MATHEMATICAL BOLD SMALL SIGMA
-// "b.sigmav", 0x1D6D3}, // MATHEMATICAL BOLD SMALL FINAL SIGMA
- {"bsim", 0x0223D}, // REVERSED TILDE
- {"bsime", 0x022CD}, // REVERSED TILDE EQUALS
- {"bsol", 0x0005C}, // REVERSE SOLIDUS
- {"bsolb", 0x029C5}, // SQUARED FALLING DIAGONAL SLASH
- {"bsolhsub", 0x027C8}, // REVERSE SOLIDUS PRECEDING SUBSET
-// "b.tau", 0x1D6D5}, // MATHEMATICAL BOLD SMALL TAU
-// "b.Theta", 0x1D6AF}, // MATHEMATICAL BOLD CAPITAL THETA
-// "b.thetas", 0x1D6C9}, // MATHEMATICAL BOLD SMALL THETA
-// "b.thetav", 0x1D6DD}, // MATHEMATICAL BOLD THETA SYMBOL
- {"bull", 0x02022}, // BULLET
- {"bullet", 0x02022}, // BULLET
- {"bump", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO
- {"bumpe", 0x0224F}, // DIFFERENCE BETWEEN
- {"bumpE", 0x02AAE}, // EQUALS SIGN WITH BUMPY ABOVE
- {"Bumpeq", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO
- {"bumpeq", 0x0224F}, // DIFFERENCE BETWEEN
-// "b.Upsi", 0x1D6BC}, // MATHEMATICAL BOLD CAPITAL UPSILON
-// "b.upsi", 0x1D6D6}, // MATHEMATICAL BOLD SMALL UPSILON
-// "b.Xi", 0x1D6B5}, // MATHEMATICAL BOLD CAPITAL XI
-// "b.xi", 0x1D6CF}, // MATHEMATICAL BOLD SMALL XI
-// "b.zeta", 0x1D6C7}, // MATHEMATICAL BOLD SMALL ZETA
- {NULL, 0}
-};
-
-static NameId namesC[]={
- {"Cacute", 0x00106}, // LATIN CAPITAL LETTER C WITH ACUTE
- {"cacute", 0x00107}, // LATIN SMALL LETTER C WITH ACUTE
- {"cap", 0x02229}, // INTERSECTION
- {"Cap", 0x022D2}, // DOUBLE INTERSECTION
- {"capand", 0x02A44}, // INTERSECTION WITH LOGICAL AND
- {"capbrcup", 0x02A49}, // INTERSECTION ABOVE BAR ABOVE UNION
- {"capcap", 0x02A4B}, // INTERSECTION BESIDE AND JOINED WITH INTERSECTION
- {"capcup", 0x02A47}, // INTERSECTION ABOVE UNION
- {"capdot", 0x02A40}, // INTERSECTION WITH DOT
- {"CapitalDifferentialD", 0x02145}, // DOUBLE-STRUCK ITALIC CAPITAL D
-// "caps", 0x02229;0x0FE00}, // INTERSECTION with serifs
- {"caret", 0x02041}, // CARET INSERTION POINT
- {"caron", 0x002C7}, // CARON
- {"Cayleys", 0x0212D}, // BLACK-LETTER CAPITAL C
- {"ccaps", 0x02A4D}, // CLOSED INTERSECTION WITH SERIFS
- {"Ccaron", 0x0010C}, // LATIN CAPITAL LETTER C WITH CARON
- {"ccaron", 0x0010D}, // LATIN SMALL LETTER C WITH CARON
- {"Ccedil", 0x000C7}, // LATIN CAPITAL LETTER C WITH CEDILLA
- {"ccedil", 0x000E7}, // LATIN SMALL LETTER C WITH CEDILLA
- {"Ccirc", 0x00108}, // LATIN CAPITAL LETTER C WITH CIRCUMFLEX
- {"ccirc", 0x00109}, // LATIN SMALL LETTER C WITH CIRCUMFLEX
- {"Cconint", 0x02230}, // VOLUME INTEGRAL
- {"ccups", 0x02A4C}, // CLOSED UNION WITH SERIFS
- {"ccupssm", 0x02A50}, // CLOSED UNION WITH SERIFS AND SMASH PRODUCT
- {"Cdot", 0x0010A}, // LATIN CAPITAL LETTER C WITH DOT ABOVE
- {"cdot", 0x0010B}, // LATIN SMALL LETTER C WITH DOT ABOVE
- {"cedil", 0x000B8}, // CEDILLA
- {"Cedilla", 0x000B8}, // CEDILLA
- {"cemptyv", 0x029B2}, // EMPTY SET WITH SMALL CIRCLE ABOVE
- {"cent", 0x000A2}, // CENT SIGN
- {"centerdot", 0x000B7}, // MIDDLE DOT
- {"CenterDot", 0x000B7}, // MIDDLE DOT
- {"Cfr", 0x0212D}, // BLACK-LETTER CAPITAL C
- {"cfr", 0x1D520}, // MATHEMATICAL FRAKTUR SMALL C
- {"CHcy", 0x00427}, // CYRILLIC CAPITAL LETTER CHE
- {"chcy", 0x00447}, // CYRILLIC SMALL LETTER CHE
- {"check", 0x02713}, // CHECK MARK
- {"checkmark", 0x02713}, // CHECK MARK
- {"Chi", 0x003A7}, // GREEK CAPITAL LETTER CHI
- {"chi", 0x003C7}, // GREEK SMALL LETTER CHI
- {"cir", 0x025CB}, // WHITE CIRCLE
- {"circ", 0x002C6}, // MODIFIER LETTER CIRCUMFLEX ACCENT
- {"circeq", 0x02257}, // RING EQUAL TO
- {"circlearrowleft", 0x021BA}, // ANTICLOCKWISE OPEN CIRCLE ARROW
- {"circlearrowright", 0x021BB}, // CLOCKWISE OPEN CIRCLE ARROW
- {"circledast", 0x0229B}, // CIRCLED ASTERISK OPERATOR
- {"circledcirc", 0x0229A}, // CIRCLED RING OPERATOR
- {"circleddash", 0x0229D}, // CIRCLED DASH
- {"CircleDot", 0x02299}, // CIRCLED DOT OPERATOR
- {"circledR", 0x000AE}, // REGISTERED SIGN
- {"circledS", 0x024C8}, // CIRCLED LATIN CAPITAL LETTER S
- {"CircleMinus", 0x02296}, // CIRCLED MINUS
- {"CirclePlus", 0x02295}, // CIRCLED PLUS
- {"CircleTimes", 0x02297}, // CIRCLED TIMES
- {"cire", 0x02257}, // RING EQUAL TO
- {"cirE", 0x029C3}, // CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT
- {"cirfnint", 0x02A10}, // CIRCULATION FUNCTION
- {"cirmid", 0x02AEF}, // VERTICAL LINE WITH CIRCLE ABOVE
- {"cirscir", 0x029C2}, // CIRCLE WITH SMALL CIRCLE TO THE RIGHT
- {"ClockwiseContourIntegral", 0x02232}, // CLOCKWISE CONTOUR INTEGRAL
- {"CloseCurlyDoubleQuote", 0x0201D}, // RIGHT DOUBLE QUOTATION MARK
- {"CloseCurlyQuote", 0x02019}, // RIGHT SINGLE QUOTATION MARK
- {"clubs", 0x02663}, // BLACK CLUB SUIT
- {"clubsuit", 0x02663}, // BLACK CLUB SUIT
- {"colon", 0x0003A}, // COLON
- {"Colon", 0x02237}, // PROPORTION
- {"colone", 0x02254}, // COLON EQUALS
- {"Colone", 0x02A74}, // DOUBLE COLON EQUAL
- {"coloneq", 0x02254}, // COLON EQUALS
- {"comma", 0x0002C}, // COMMA
- {"commat", 0x00040}, // COMMERCIAL AT
- {"comp", 0x02201}, // COMPLEMENT
- {"compfn", 0x02218}, // RING OPERATOR
- {"complement", 0x02201}, // COMPLEMENT
- {"complexes", 0x02102}, // DOUBLE-STRUCK CAPITAL C
- {"cong", 0x02245}, // APPROXIMATELY EQUAL TO
- {"congdot", 0x02A6D}, // CONGRUENT WITH DOT ABOVE
- {"Congruent", 0x02261}, // IDENTICAL TO
- {"conint", 0x0222E}, // CONTOUR INTEGRAL
- {"Conint", 0x0222F}, // SURFACE INTEGRAL
- {"ContourIntegral", 0x0222E}, // CONTOUR INTEGRAL
- {"Copf", 0x02102}, // DOUBLE-STRUCK CAPITAL C
- {"copf", 0x1D554}, // MATHEMATICAL DOUBLE-STRUCK SMALL C
- {"coprod", 0x02210}, // N-ARY COPRODUCT
- {"Coproduct", 0x02210}, // N-ARY COPRODUCT
- {"copy", 0x000A9}, // COPYRIGHT SIGN
- {"COPY", 0x000A9}, // COPYRIGHT SIGN
- {"copysr", 0x02117}, // SOUND RECORDING COPYRIGHT
- {"CounterClockwiseContourIntegral", 0x02233}, // ANTICLOCKWISE CONTOUR INTEGRAL
- {"crarr", 0x021B5}, // DOWNWARDS ARROW WITH CORNER LEFTWARDS
- {"cross", 0x02717}, // BALLOT X
- {"Cross", 0x02A2F}, // VECTOR OR CROSS PRODUCT
- {"Cscr", 0x1D49E}, // MATHEMATICAL SCRIPT CAPITAL C
- {"cscr", 0x1D4B8}, // MATHEMATICAL SCRIPT SMALL C
- {"csub", 0x02ACF}, // CLOSED SUBSET
- {"csube", 0x02AD1}, // CLOSED SUBSET OR EQUAL TO
- {"csup", 0x02AD0}, // CLOSED SUPERSET
- {"csupe", 0x02AD2}, // CLOSED SUPERSET OR EQUAL TO
- {"ctdot", 0x022EF}, // MIDLINE HORIZONTAL ELLIPSIS
- {"cudarrl", 0x02938}, // RIGHT-SIDE ARC CLOCKWISE ARROW
- {"cudarrr", 0x02935}, // ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS
- {"cuepr", 0x022DE}, // EQUAL TO OR PRECEDES
- {"cuesc", 0x022DF}, // EQUAL TO OR SUCCEEDS
- {"cularr", 0x021B6}, // ANTICLOCKWISE TOP SEMICIRCLE ARROW
- {"cularrp", 0x0293D}, // TOP ARC ANTICLOCKWISE ARROW WITH PLUS
- {"cup", 0x0222A}, // UNION
- {"Cup", 0x022D3}, // DOUBLE UNION
- {"cupbrcap", 0x02A48}, // UNION ABOVE BAR ABOVE INTERSECTION
- {"CupCap", 0x0224D}, // EQUIVALENT TO
- {"cupcap", 0x02A46}, // UNION ABOVE INTERSECTION
- {"cupcup", 0x02A4A}, // UNION BESIDE AND JOINED WITH UNION
- {"cupdot", 0x0228D}, // MULTISET MULTIPLICATION
- {"cupor", 0x02A45}, // UNION WITH LOGICAL OR
-// "cups", 0x0222A;0x0FE00}, // UNION with serifs
- {"curarr", 0x021B7}, // CLOCKWISE TOP SEMICIRCLE ARROW
- {"curarrm", 0x0293C}, // TOP ARC CLOCKWISE ARROW WITH MINUS
- {"curlyeqprec", 0x022DE}, // EQUAL TO OR PRECEDES
- {"curlyeqsucc", 0x022DF}, // EQUAL TO OR SUCCEEDS
- {"curlyvee", 0x022CE}, // CURLY LOGICAL OR
- {"curlywedge", 0x022CF}, // CURLY LOGICAL AND
- {"curren", 0x000A4}, // CURRENCY SIGN
- {"curvearrowleft", 0x021B6}, // ANTICLOCKWISE TOP SEMICIRCLE ARROW
- {"curvearrowright", 0x021B7}, // CLOCKWISE TOP SEMICIRCLE ARROW
- {"cuvee", 0x022CE}, // CURLY LOGICAL OR
- {"cuwed", 0x022CF}, // CURLY LOGICAL AND
- {"cwconint", 0x02232}, // CLOCKWISE CONTOUR INTEGRAL
- {"cwint", 0x02231}, // CLOCKWISE INTEGRAL
- {"cylcty", 0x0232D}, // CYLINDRICITY
- {NULL, 0}
-};
-
-static NameId namesD[]={
- {"dagger", 0x02020}, // DAGGER
- {"Dagger", 0x02021}, // DOUBLE DAGGER
- {"daleth", 0x02138}, // DALET SYMBOL
- {"darr", 0x02193}, // DOWNWARDS ARROW
- {"Darr", 0x021A1}, // DOWNWARDS TWO HEADED ARROW
- {"dArr", 0x021D3}, // DOWNWARDS DOUBLE ARROW
- {"dash", 0x02010}, // HYPHEN
- {"dashv", 0x022A3}, // LEFT TACK
- {"Dashv", 0x02AE4}, // VERTICAL BAR DOUBLE LEFT TURNSTILE
- {"dbkarow", 0x0290F}, // RIGHTWARDS TRIPLE DASH ARROW
- {"dblac", 0x002DD}, // DOUBLE ACUTE ACCENT
- {"Dcaron", 0x0010E}, // LATIN CAPITAL LETTER D WITH CARON
- {"dcaron", 0x0010F}, // LATIN SMALL LETTER D WITH CARON
- {"Dcy", 0x00414}, // CYRILLIC CAPITAL LETTER DE
- {"dcy", 0x00434}, // CYRILLIC SMALL LETTER DE
- {"DD", 0x02145}, // DOUBLE-STRUCK ITALIC CAPITAL D
- {"dd", 0x02146}, // DOUBLE-STRUCK ITALIC SMALL D
- {"ddagger", 0x02021}, // DOUBLE DAGGER
- {"ddarr", 0x021CA}, // DOWNWARDS PAIRED ARROWS
- {"DDotrahd", 0x02911}, // RIGHTWARDS ARROW WITH DOTTED STEM
- {"ddotseq", 0x02A77}, // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW
- {"deg", 0x000B0}, // DEGREE SIGN
- {"Del", 0x02207}, // NABLA
- {"Delta", 0x00394}, // GREEK CAPITAL LETTER DELTA
- {"delta", 0x003B4}, // GREEK SMALL LETTER DELTA
- {"demptyv", 0x029B1}, // EMPTY SET WITH OVERBAR
- {"dfisht", 0x0297F}, // DOWN FISH TAIL
- {"Dfr", 0x1D507}, // MATHEMATICAL FRAKTUR CAPITAL D
- {"dfr", 0x1D521}, // MATHEMATICAL FRAKTUR SMALL D
- {"Dgr", 0x00394}, // GREEK CAPITAL LETTER DELTA
- {"dgr", 0x003B4}, // GREEK SMALL LETTER DELTA
- {"dHar", 0x02965}, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
- {"dharl", 0x021C3}, // DOWNWARDS HARPOON WITH BARB LEFTWARDS
- {"dharr", 0x021C2}, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
- {"DiacriticalAcute", 0x000B4}, // ACUTE ACCENT
- {"DiacriticalDot", 0x002D9}, // DOT ABOVE
- {"DiacriticalDoubleAcute", 0x002DD}, // DOUBLE ACUTE ACCENT
- {"DiacriticalGrave", 0x00060}, // GRAVE ACCENT
- {"DiacriticalTilde", 0x002DC}, // SMALL TILDE
- {"diam", 0x022C4}, // DIAMOND OPERATOR
- {"diamond", 0x022C4}, // DIAMOND OPERATOR
- {"Diamond", 0x022C4}, // DIAMOND OPERATOR
- {"diamondsuit", 0x02666}, // BLACK DIAMOND SUIT
- {"diams", 0x02666}, // BLACK DIAMOND SUIT
- {"die", 0x000A8}, // DIAERESIS
- {"DifferentialD", 0x02146}, // DOUBLE-STRUCK ITALIC SMALL D
- {"digamma", 0x003DD}, // GREEK SMALL LETTER DIGAMMA
- {"disin", 0x022F2}, // ELEMENT OF WITH LONG HORIZONTAL STROKE
- {"div", 0x000F7}, // DIVISION SIGN
- {"divide", 0x000F7}, // DIVISION SIGN
- {"divideontimes", 0x022C7}, // DIVISION TIMES
- {"divonx", 0x022C7}, // DIVISION TIMES
- {"DJcy", 0x00402}, // CYRILLIC CAPITAL LETTER DJE
- {"djcy", 0x00452}, // CYRILLIC SMALL LETTER DJE
- {"dlcorn", 0x0231E}, // BOTTOM LEFT CORNER
- {"dlcrop", 0x0230D}, // BOTTOM LEFT CROP
- {"dollar", 0x00024}, // DOLLAR SIGN
- {"Dopf", 0x1D53B}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL D
- {"dopf", 0x1D555}, // MATHEMATICAL DOUBLE-STRUCK SMALL D
- {"Dot", 0x000A8}, // DIAERESIS
- {"dot", 0x002D9}, // DOT ABOVE
- {"DotDot", 0x020DC}, // COMBINING FOUR DOTS ABOVE
- {"doteq", 0x02250}, // APPROACHES THE LIMIT
- {"doteqdot", 0x02251}, // GEOMETRICALLY EQUAL TO
- {"DotEqual", 0x02250}, // APPROACHES THE LIMIT
- {"dotminus", 0x02238}, // DOT MINUS
- {"dotplus", 0x02214}, // DOT PLUS
- {"dotsquare", 0x022A1}, // SQUARED DOT OPERATOR
- {"doublebarwedge", 0x02306}, // PERSPECTIVE
- {"DoubleContourIntegral", 0x0222F}, // SURFACE INTEGRAL
- {"DoubleDot", 0x000A8}, // DIAERESIS
- {"DoubleDownArrow", 0x021D3}, // DOWNWARDS DOUBLE ARROW
- {"DoubleLeftArrow", 0x021D0}, // LEFTWARDS DOUBLE ARROW
- {"DoubleLeftRightArrow", 0x021D4}, // LEFT RIGHT DOUBLE ARROW
- {"DoubleLeftTee", 0x02AE4}, // VERTICAL BAR DOUBLE LEFT TURNSTILE
- {"DoubleLongLeftArrow", 0x027F8}, // LONG LEFTWARDS DOUBLE ARROW
- {"DoubleLongLeftRightArrow", 0x027FA}, // LONG LEFT RIGHT DOUBLE ARROW
- {"DoubleLongRightArrow", 0x027F9}, // LONG RIGHTWARDS DOUBLE ARROW
- {"DoubleRightArrow", 0x021D2}, // RIGHTWARDS DOUBLE ARROW
- {"DoubleRightTee", 0x022A8}, // TRUE
- {"DoubleUpArrow", 0x021D1}, // UPWARDS DOUBLE ARROW
- {"DoubleUpDownArrow", 0x021D5}, // UP DOWN DOUBLE ARROW
- {"DoubleVerticalBar", 0x02225}, // PARALLEL TO
- {"downarrow", 0x02193}, // DOWNWARDS ARROW
- {"DownArrow", 0x02193}, // DOWNWARDS ARROW
- {"Downarrow", 0x021D3}, // DOWNWARDS DOUBLE ARROW
- {"DownArrowBar", 0x02913}, // DOWNWARDS ARROW TO BAR
- {"DownArrowUpArrow", 0x021F5}, // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW
- {"DownBreve", 0x00311}, // COMBINING INVERTED BREVE
- {"downdownarrows", 0x021CA}, // DOWNWARDS PAIRED ARROWS
- {"downharpoonleft", 0x021C3}, // DOWNWARDS HARPOON WITH BARB LEFTWARDS
- {"downharpoonright", 0x021C2}, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
- {"DownLeftRightVector", 0x02950}, // LEFT BARB DOWN RIGHT BARB DOWN HARPOON
- {"DownLeftTeeVector", 0x0295E}, // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR
- {"DownLeftVector", 0x021BD}, // LEFTWARDS HARPOON WITH BARB DOWNWARDS
- {"DownLeftVectorBar", 0x02956}, // LEFTWARDS HARPOON WITH BARB DOWN TO BAR
- {"DownRightTeeVector", 0x0295F}, // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR
- {"DownRightVector", 0x021C1}, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
- {"DownRightVectorBar", 0x02957}, // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR
- {"DownTee", 0x022A4}, // DOWN TACK
- {"DownTeeArrow", 0x021A7}, // DOWNWARDS ARROW FROM BAR
- {"drbkarow", 0x02910}, // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW
- {"drcorn", 0x0231F}, // BOTTOM RIGHT CORNER
- {"drcrop", 0x0230C}, // BOTTOM RIGHT CROP
- {"Dscr", 0x1D49F}, // MATHEMATICAL SCRIPT CAPITAL D
- {"dscr", 0x1D4B9}, // MATHEMATICAL SCRIPT SMALL D
- {"DScy", 0x00405}, // CYRILLIC CAPITAL LETTER DZE
- {"dscy", 0x00455}, // CYRILLIC SMALL LETTER DZE
- {"dsol", 0x029F6}, // SOLIDUS WITH OVERBAR
- {"Dstrok", 0x00110}, // LATIN CAPITAL LETTER D WITH STROKE
- {"dstrok", 0x00111}, // LATIN SMALL LETTER D WITH STROKE
- {"dtdot", 0x022F1}, // DOWN RIGHT DIAGONAL ELLIPSIS
- {"dtri", 0x025BF}, // WHITE DOWN-POINTING SMALL TRIANGLE
- {"dtrif", 0x025BE}, // BLACK DOWN-POINTING SMALL TRIANGLE
- {"duarr", 0x021F5}, // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW
- {"duhar", 0x0296F}, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
- {"dwangle", 0x029A6}, // OBLIQUE ANGLE OPENING UP
- {"DZcy", 0x0040F}, // CYRILLIC CAPITAL LETTER DZHE
- {"dzcy", 0x0045F}, // CYRILLIC SMALL LETTER DZHE
- {"dzigrarr", 0x027FF}, // LONG RIGHTWARDS SQUIGGLE ARROW
- {NULL, 0}
-};
-
-static NameId namesE[]={
- {"Eacgr", 0x00388}, // GREEK CAPITAL LETTER EPSILON WITH TONOS
- {"eacgr", 0x003AD}, // GREEK SMALL LETTER EPSILON WITH TONOS
- {"Eacute", 0x000C9}, // LATIN CAPITAL LETTER E WITH ACUTE
- {"eacute", 0x000E9}, // LATIN SMALL LETTER E WITH ACUTE
- {"easter", 0x02A6E}, // EQUALS WITH ASTERISK
- {"Ecaron", 0x0011A}, // LATIN CAPITAL LETTER E WITH CARON
- {"ecaron", 0x0011B}, // LATIN SMALL LETTER E WITH CARON
- {"ecir", 0x02256}, // RING IN EQUAL TO
- {"Ecirc", 0x000CA}, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX
- {"ecirc", 0x000EA}, // LATIN SMALL LETTER E WITH CIRCUMFLEX
- {"ecolon", 0x02255}, // EQUALS COLON
- {"Ecy", 0x0042D}, // CYRILLIC CAPITAL LETTER E
- {"ecy", 0x0044D}, // CYRILLIC SMALL LETTER E
- {"eDDot", 0x02A77}, // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW
- {"Edot", 0x00116}, // LATIN CAPITAL LETTER E WITH DOT ABOVE
- {"edot", 0x00117}, // LATIN SMALL LETTER E WITH DOT ABOVE
- {"eDot", 0x02251}, // GEOMETRICALLY EQUAL TO
- {"ee", 0x02147}, // DOUBLE-STRUCK ITALIC SMALL E
- {"EEacgr", 0x00389}, // GREEK CAPITAL LETTER ETA WITH TONOS
- {"eeacgr", 0x003AE}, // GREEK SMALL LETTER ETA WITH TONOS
- {"EEgr", 0x00397}, // GREEK CAPITAL LETTER ETA
- {"eegr", 0x003B7}, // GREEK SMALL LETTER ETA
- {"efDot", 0x02252}, // APPROXIMATELY EQUAL TO OR THE IMAGE OF
- {"Efr", 0x1D508}, // MATHEMATICAL FRAKTUR CAPITAL E
- {"efr", 0x1D522}, // MATHEMATICAL FRAKTUR SMALL E
- {"eg", 0x02A9A}, // DOUBLE-LINE EQUAL TO OR GREATER-THAN
- {"Egr", 0x00395}, // GREEK CAPITAL LETTER EPSILON
- {"egr", 0x003B5}, // GREEK SMALL LETTER EPSILON
- {"Egrave", 0x000C8}, // LATIN CAPITAL LETTER E WITH GRAVE
- {"egrave", 0x000E8}, // LATIN SMALL LETTER E WITH GRAVE
- {"egs", 0x02A96}, // SLANTED EQUAL TO OR GREATER-THAN
- {"egsdot", 0x02A98}, // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE
- {"el", 0x02A99}, // DOUBLE-LINE EQUAL TO OR LESS-THAN
- {"Element", 0x02208}, // ELEMENT OF
- {"elinters", 0x023E7}, // ELECTRICAL INTERSECTION
- {"ell", 0x02113}, // SCRIPT SMALL L
- {"els", 0x02A95}, // SLANTED EQUAL TO OR LESS-THAN
- {"elsdot", 0x02A97}, // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE
- {"Emacr", 0x00112}, // LATIN CAPITAL LETTER E WITH MACRON
- {"emacr", 0x00113}, // LATIN SMALL LETTER E WITH MACRON
- {"empty", 0x02205}, // EMPTY SET
- {"emptyset", 0x02205}, // EMPTY SET
- {"EmptySmallSquare", 0x025FB}, // WHITE MEDIUM SQUARE
- {"emptyv", 0x02205}, // EMPTY SET
- {"EmptyVerySmallSquare", 0x025AB}, // WHITE SMALL SQUARE
- {"emsp", 0x02003}, // EM SPACE
- {"emsp13", 0x02004}, // THREE-PER-EM SPACE
- {"emsp14", 0x02005}, // FOUR-PER-EM SPACE
- {"ENG", 0x0014A}, // LATIN CAPITAL LETTER ENG
- {"eng", 0x0014B}, // LATIN SMALL LETTER ENG
- {"ensp", 0x02002}, // EN SPACE
- {"Eogon", 0x00118}, // LATIN CAPITAL LETTER E WITH OGONEK
- {"eogon", 0x00119}, // LATIN SMALL LETTER E WITH OGONEK
- {"Eopf", 0x1D53C}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL E
- {"eopf", 0x1D556}, // MATHEMATICAL DOUBLE-STRUCK SMALL E
- {"epar", 0x022D5}, // EQUAL AND PARALLEL TO
- {"eparsl", 0x029E3}, // EQUALS SIGN AND SLANTED PARALLEL
- {"eplus", 0x02A71}, // EQUALS SIGN ABOVE PLUS SIGN
- {"epsi", 0x003B5}, // GREEK SMALL LETTER EPSILON
- {"Epsilon", 0x00395}, // GREEK CAPITAL LETTER EPSILON
- {"epsilon", 0x003B5}, // GREEK SMALL LETTER EPSILON
- {"epsiv", 0x003F5}, // GREEK LUNATE EPSILON SYMBOL
- {"eqcirc", 0x02256}, // RING IN EQUAL TO
- {"eqcolon", 0x02255}, // EQUALS COLON
- {"eqsim", 0x02242}, // MINUS TILDE
- {"eqslantgtr", 0x02A96}, // SLANTED EQUAL TO OR GREATER-THAN
- {"eqslantless", 0x02A95}, // SLANTED EQUAL TO OR LESS-THAN
- {"Equal", 0x02A75}, // TWO CONSECUTIVE EQUALS SIGNS
- {"equals", 0x0003D}, // EQUALS SIGN
- {"EqualTilde", 0x02242}, // MINUS TILDE
- {"equest", 0x0225F}, // QUESTIONED EQUAL TO
- {"Equilibrium", 0x021CC}, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
- {"equiv", 0x02261}, // IDENTICAL TO
- {"equivDD", 0x02A78}, // EQUIVALENT WITH FOUR DOTS ABOVE
- {"eqvparsl", 0x029E5}, // IDENTICAL TO AND SLANTED PARALLEL
- {"erarr", 0x02971}, // EQUALS SIGN ABOVE RIGHTWARDS ARROW
- {"erDot", 0x02253}, // IMAGE OF OR APPROXIMATELY EQUAL TO
- {"escr", 0x0212F}, // SCRIPT SMALL E
- {"Escr", 0x02130}, // SCRIPT CAPITAL E
- {"esdot", 0x02250}, // APPROACHES THE LIMIT
- {"esim", 0x02242}, // MINUS TILDE
- {"Esim", 0x02A73}, // EQUALS SIGN ABOVE TILDE OPERATOR
- {"Eta", 0x00397}, // GREEK CAPITAL LETTER ETA
- {"eta", 0x003B7}, // GREEK SMALL LETTER ETA
- {"ETH", 0x000D0}, // LATIN CAPITAL LETTER ETH
- {"eth", 0x000F0}, // LATIN SMALL LETTER ETH
- {"Euml", 0x000CB}, // LATIN CAPITAL LETTER E WITH DIAERESIS
- {"euml", 0x000EB}, // LATIN SMALL LETTER E WITH DIAERESIS
- {"euro", 0x020AC}, // EURO SIGN
- {"excl", 0x00021}, // EXCLAMATION MARK
- {"exist", 0x02203}, // THERE EXISTS
- {"Exists", 0x02203}, // THERE EXISTS
- {"expectation", 0x02130}, // SCRIPT CAPITAL E
- {"exponentiale", 0x02147}, // DOUBLE-STRUCK ITALIC SMALL E
- {"ExponentialE", 0x02147}, // DOUBLE-STRUCK ITALIC SMALL E
- {NULL, 0}
-};
-
-static NameId namesF[]={
- {"fallingdotseq", 0x02252}, // APPROXIMATELY EQUAL TO OR THE IMAGE OF
- {"Fcy", 0x00424}, // CYRILLIC CAPITAL LETTER EF
- {"fcy", 0x00444}, // CYRILLIC SMALL LETTER EF
- {"female", 0x02640}, // FEMALE SIGN
- {"ffilig", 0x0FB03}, // LATIN SMALL LIGATURE FFI
- {"fflig", 0x0FB00}, // LATIN SMALL LIGATURE FF
- {"ffllig", 0x0FB04}, // LATIN SMALL LIGATURE FFL
- {"Ffr", 0x1D509}, // MATHEMATICAL FRAKTUR CAPITAL F
- {"ffr", 0x1D523}, // MATHEMATICAL FRAKTUR SMALL F
- {"filig", 0x0FB01}, // LATIN SMALL LIGATURE FI
- {"FilledSmallSquare", 0x025FC}, // BLACK MEDIUM SQUARE
- {"FilledVerySmallSquare", 0x025AA}, // BLACK SMALL SQUARE
-// "fjlig", 0x00066;0x0006A}, // fj ligature
- {"flat", 0x0266D}, // MUSIC FLAT SIGN
- {"fllig", 0x0FB02}, // LATIN SMALL LIGATURE FL
- {"fltns", 0x025B1}, // WHITE PARALLELOGRAM
- {"fnof", 0x00192}, // LATIN SMALL LETTER F WITH HOOK
- {"Fopf", 0x1D53D}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL F
- {"fopf", 0x1D557}, // MATHEMATICAL DOUBLE-STRUCK SMALL F
- {"forall", 0x02200}, // FOR ALL
- {"ForAll", 0x02200}, // FOR ALL
- {"fork", 0x022D4}, // PITCHFORK
- {"forkv", 0x02AD9}, // ELEMENT OF OPENING DOWNWARDS
- {"Fouriertrf", 0x02131}, // SCRIPT CAPITAL F
- {"fpartint", 0x02A0D}, // FINITE PART INTEGRAL
- {"frac12", 0x000BD}, // VULGAR FRACTION ONE HALF
- {"frac13", 0x02153}, // VULGAR FRACTION ONE THIRD
- {"frac14", 0x000BC}, // VULGAR FRACTION ONE QUARTER
- {"frac15", 0x02155}, // VULGAR FRACTION ONE FIFTH
- {"frac16", 0x02159}, // VULGAR FRACTION ONE SIXTH
- {"frac18", 0x0215B}, // VULGAR FRACTION ONE EIGHTH
- {"frac23", 0x02154}, // VULGAR FRACTION TWO THIRDS
- {"frac25", 0x02156}, // VULGAR FRACTION TWO FIFTHS
- {"frac34", 0x000BE}, // VULGAR FRACTION THREE QUARTERS
- {"frac35", 0x02157}, // VULGAR FRACTION THREE FIFTHS
- {"frac38", 0x0215C}, // VULGAR FRACTION THREE EIGHTHS
- {"frac45", 0x02158}, // VULGAR FRACTION FOUR FIFTHS
- {"frac56", 0x0215A}, // VULGAR FRACTION FIVE SIXTHS
- {"frac58", 0x0215D}, // VULGAR FRACTION FIVE EIGHTHS
- {"frac78", 0x0215E}, // VULGAR FRACTION SEVEN EIGHTHS
- {"frasl", 0x02044}, // FRACTION SLASH
- {"frown", 0x02322}, // FROWN
- {"Fscr", 0x02131}, // SCRIPT CAPITAL F
- {"fscr", 0x1D4BB}, // MATHEMATICAL SCRIPT SMALL F
- {NULL, 0}
-};
-
-static NameId namesG[]={
- {"gacute", 0x001F5}, // LATIN SMALL LETTER G WITH ACUTE
- {"Gamma", 0x00393}, // GREEK CAPITAL LETTER GAMMA
- {"gamma", 0x003B3}, // GREEK SMALL LETTER GAMMA
- {"Gammad", 0x003DC}, // GREEK LETTER DIGAMMA
- {"gammad", 0x003DD}, // GREEK SMALL LETTER DIGAMMA
- {"gap", 0x02A86}, // GREATER-THAN OR APPROXIMATE
- {"Gbreve", 0x0011E}, // LATIN CAPITAL LETTER G WITH BREVE
- {"gbreve", 0x0011F}, // LATIN SMALL LETTER G WITH BREVE
- {"Gcedil", 0x00122}, // LATIN CAPITAL LETTER G WITH CEDILLA
- {"Gcirc", 0x0011C}, // LATIN CAPITAL LETTER G WITH CIRCUMFLEX
- {"gcirc", 0x0011D}, // LATIN SMALL LETTER G WITH CIRCUMFLEX
- {"Gcy", 0x00413}, // CYRILLIC CAPITAL LETTER GHE
- {"gcy", 0x00433}, // CYRILLIC SMALL LETTER GHE
- {"Gdot", 0x00120}, // LATIN CAPITAL LETTER G WITH DOT ABOVE
- {"gdot", 0x00121}, // LATIN SMALL LETTER G WITH DOT ABOVE
- {"ge", 0x02265}, // GREATER-THAN OR EQUAL TO
- {"gE", 0x02267}, // GREATER-THAN OVER EQUAL TO
- {"gel", 0x022DB}, // GREATER-THAN EQUAL TO OR LESS-THAN
- {"gEl", 0x02A8C}, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
- {"geq", 0x02265}, // GREATER-THAN OR EQUAL TO
- {"geqq", 0x02267}, // GREATER-THAN OVER EQUAL TO
- {"geqslant", 0x02A7E}, // GREATER-THAN OR SLANTED EQUAL TO
- {"ges", 0x02A7E}, // GREATER-THAN OR SLANTED EQUAL TO
- {"gescc", 0x02AA9}, // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
- {"gesdot", 0x02A80}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
- {"gesdoto", 0x02A82}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
- {"gesdotol", 0x02A84}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT
-// "gesl", 0x022DB;0x0FE00}, // GREATER-THAN slanted EQUAL TO OR LESS-THAN
- {"gesles", 0x02A94}, // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL
- {"Gfr", 0x1D50A}, // MATHEMATICAL FRAKTUR CAPITAL G
- {"gfr", 0x1D524}, // MATHEMATICAL FRAKTUR SMALL G
- {"gg", 0x0226B}, // MUCH GREATER-THAN
- {"Gg", 0x022D9}, // VERY MUCH GREATER-THAN
- {"ggg", 0x022D9}, // VERY MUCH GREATER-THAN
- {"Ggr", 0x00393}, // GREEK CAPITAL LETTER GAMMA
- {"ggr", 0x003B3}, // GREEK SMALL LETTER GAMMA
- {"gimel", 0x02137}, // GIMEL SYMBOL
- {"GJcy", 0x00403}, // CYRILLIC CAPITAL LETTER GJE
- {"gjcy", 0x00453}, // CYRILLIC SMALL LETTER GJE
- {"gl", 0x02277}, // GREATER-THAN OR LESS-THAN
- {"gla", 0x02AA5}, // GREATER-THAN BESIDE LESS-THAN
- {"glE", 0x02A92}, // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL
- {"glj", 0x02AA4}, // GREATER-THAN OVERLAPPING LESS-THAN
- {"gnap", 0x02A8A}, // GREATER-THAN AND NOT APPROXIMATE
- {"gnapprox", 0x02A8A}, // GREATER-THAN AND NOT APPROXIMATE
- {"gnE", 0x02269}, // GREATER-THAN BUT NOT EQUAL TO
- {"gne", 0x02A88}, // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO
- {"gneq", 0x02A88}, // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO
- {"gneqq", 0x02269}, // GREATER-THAN BUT NOT EQUAL TO
- {"gnsim", 0x022E7}, // GREATER-THAN BUT NOT EQUIVALENT TO
- {"Gopf", 0x1D53E}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL G
- {"gopf", 0x1D558}, // MATHEMATICAL DOUBLE-STRUCK SMALL G
- {"grave", 0x00060}, // GRAVE ACCENT
- {"GreaterEqual", 0x02265}, // GREATER-THAN OR EQUAL TO
- {"GreaterEqualLess", 0x022DB}, // GREATER-THAN EQUAL TO OR LESS-THAN
- {"GreaterFullEqual", 0x02267}, // GREATER-THAN OVER EQUAL TO
- {"GreaterGreater", 0x02AA2}, // DOUBLE NESTED GREATER-THAN
- {"GreaterLess", 0x02277}, // GREATER-THAN OR LESS-THAN
- {"GreaterSlantEqual", 0x02A7E}, // GREATER-THAN OR SLANTED EQUAL TO
- {"GreaterTilde", 0x02273}, // GREATER-THAN OR EQUIVALENT TO
- {"gscr", 0x0210A}, // SCRIPT SMALL G
- {"Gscr", 0x1D4A2}, // MATHEMATICAL SCRIPT CAPITAL G
- {"gsim", 0x02273}, // GREATER-THAN OR EQUIVALENT TO
- {"gsime", 0x02A8E}, // GREATER-THAN ABOVE SIMILAR OR EQUAL
- {"gsiml", 0x02A90}, // GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN
- {"gt", 0x0003E}, // GREATER-THAN SIGN
- {"GT", 0x0003E}, // GREATER-THAN SIGN
- {"Gt", 0x0226B}, // MUCH GREATER-THAN
- {"gtcc", 0x02AA7}, // GREATER-THAN CLOSED BY CURVE
- {"gtcir", 0x02A7A}, // GREATER-THAN WITH CIRCLE INSIDE
- {"gtdot", 0x022D7}, // GREATER-THAN WITH DOT
- {"gtlPar", 0x02995}, // DOUBLE LEFT ARC GREATER-THAN BRACKET
- {"gtquest", 0x02A7C}, // GREATER-THAN WITH QUESTION MARK ABOVE
- {"gtrapprox", 0x02A86}, // GREATER-THAN OR APPROXIMATE
- {"gtrarr", 0x02978}, // GREATER-THAN ABOVE RIGHTWARDS ARROW
- {"gtrdot", 0x022D7}, // GREATER-THAN WITH DOT
- {"gtreqless", 0x022DB}, // GREATER-THAN EQUAL TO OR LESS-THAN
- {"gtreqqless", 0x02A8C}, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
- {"gtrless", 0x02277}, // GREATER-THAN OR LESS-THAN
- {"gtrsim", 0x02273}, // GREATER-THAN OR EQUIVALENT TO
-// "gvertneqq", 0x02269;0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke
-// "gvnE", 0x02269;0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke
- {NULL, 0}
-};
-
-static NameId namesH[]={
- {"Hacek", 0x002C7}, // CARON
- {"hairsp", 0x0200A}, // HAIR SPACE
- {"half", 0x000BD}, // VULGAR FRACTION ONE HALF
- {"hamilt", 0x0210B}, // SCRIPT CAPITAL H
- {"HARDcy", 0x0042A}, // CYRILLIC CAPITAL LETTER HARD SIGN
- {"hardcy", 0x0044A}, // CYRILLIC SMALL LETTER HARD SIGN
- {"harr", 0x02194}, // LEFT RIGHT ARROW
- {"hArr", 0x021D4}, // LEFT RIGHT DOUBLE ARROW
- {"harrcir", 0x02948}, // LEFT RIGHT ARROW THROUGH SMALL CIRCLE
- {"harrw", 0x021AD}, // LEFT RIGHT WAVE ARROW
- {"Hat", 0x0005E}, // CIRCUMFLEX ACCENT
- {"hbar", 0x0210F}, // PLANCK CONSTANT OVER TWO PI
- {"Hcirc", 0x00124}, // LATIN CAPITAL LETTER H WITH CIRCUMFLEX
- {"hcirc", 0x00125}, // LATIN SMALL LETTER H WITH CIRCUMFLEX
- {"hearts", 0x02665}, // BLACK HEART SUIT
- {"heartsuit", 0x02665}, // BLACK HEART SUIT
- {"hellip", 0x02026}, // HORIZONTAL ELLIPSIS
- {"hercon", 0x022B9}, // HERMITIAN CONJUGATE MATRIX
- {"Hfr", 0x0210C}, // BLACK-LETTER CAPITAL H
- {"hfr", 0x1D525}, // MATHEMATICAL FRAKTUR SMALL H
- {"HilbertSpace", 0x0210B}, // SCRIPT CAPITAL H
- {"hksearow", 0x02925}, // SOUTH EAST ARROW WITH HOOK
- {"hkswarow", 0x02926}, // SOUTH WEST ARROW WITH HOOK
- {"hoarr", 0x021FF}, // LEFT RIGHT OPEN-HEADED ARROW
- {"homtht", 0x0223B}, // HOMOTHETIC
- {"hookleftarrow", 0x021A9}, // LEFTWARDS ARROW WITH HOOK
- {"hookrightarrow", 0x021AA}, // RIGHTWARDS ARROW WITH HOOK
- {"Hopf", 0x0210D}, // DOUBLE-STRUCK CAPITAL H
- {"hopf", 0x1D559}, // MATHEMATICAL DOUBLE-STRUCK SMALL H
- {"horbar", 0x02015}, // HORIZONTAL BAR
- {"HorizontalLine", 0x02500}, // BOX DRAWINGS LIGHT HORIZONTAL
- {"Hscr", 0x0210B}, // SCRIPT CAPITAL H
- {"hscr", 0x1D4BD}, // MATHEMATICAL SCRIPT SMALL H
- {"hslash", 0x0210F}, // PLANCK CONSTANT OVER TWO PI
- {"Hstrok", 0x00126}, // LATIN CAPITAL LETTER H WITH STROKE
- {"hstrok", 0x00127}, // LATIN SMALL LETTER H WITH STROKE
- {"HumpDownHump", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO
- {"HumpEqual", 0x0224F}, // DIFFERENCE BETWEEN
- {"hybull", 0x02043}, // HYPHEN BULLET
- {"hyphen", 0x02010}, // HYPHEN
- {NULL, 0}
-};
-
-static NameId namesI[]={
- {"Iacgr", 0x0038A}, // GREEK CAPITAL LETTER IOTA WITH TONOS
- {"iacgr", 0x003AF}, // GREEK SMALL LETTER IOTA WITH TONOS
- {"Iacute", 0x000CD}, // LATIN CAPITAL LETTER I WITH ACUTE
- {"iacute", 0x000ED}, // LATIN SMALL LETTER I WITH ACUTE
- {"ic", 0x02063}, // INVISIBLE SEPARATOR
- {"Icirc", 0x000CE}, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX
- {"icirc", 0x000EE}, // LATIN SMALL LETTER I WITH CIRCUMFLEX
- {"Icy", 0x00418}, // CYRILLIC CAPITAL LETTER I
- {"icy", 0x00438}, // CYRILLIC SMALL LETTER I
- {"idiagr", 0x00390}, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
- {"Idigr", 0x003AA}, // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
- {"idigr", 0x003CA}, // GREEK SMALL LETTER IOTA WITH DIALYTIKA
- {"Idot", 0x00130}, // LATIN CAPITAL LETTER I WITH DOT ABOVE
- {"IEcy", 0x00415}, // CYRILLIC CAPITAL LETTER IE
- {"iecy", 0x00435}, // CYRILLIC SMALL LETTER IE
- {"iexcl", 0x000A1}, // INVERTED EXCLAMATION MARK
- {"iff", 0x021D4}, // LEFT RIGHT DOUBLE ARROW
- {"Ifr", 0x02111}, // BLACK-LETTER CAPITAL I
- {"ifr", 0x1D526}, // MATHEMATICAL FRAKTUR SMALL I
- {"Igr", 0x00399}, // GREEK CAPITAL LETTER IOTA
- {"igr", 0x003B9}, // GREEK SMALL LETTER IOTA
- {"Igrave", 0x000CC}, // LATIN CAPITAL LETTER I WITH GRAVE
- {"igrave", 0x000EC}, // LATIN SMALL LETTER I WITH GRAVE
- {"ii", 0x02148}, // DOUBLE-STRUCK ITALIC SMALL I
- {"iiiint", 0x02A0C}, // QUADRUPLE INTEGRAL OPERATOR
- {"iiint", 0x0222D}, // TRIPLE INTEGRAL
- {"iinfin", 0x029DC}, // INCOMPLETE INFINITY
- {"iiota", 0x02129}, // TURNED GREEK SMALL LETTER IOTA
- {"IJlig", 0x00132}, // LATIN CAPITAL LIGATURE IJ
- {"ijlig", 0x00133}, // LATIN SMALL LIGATURE IJ
- {"Im", 0x02111}, // BLACK-LETTER CAPITAL I
- {"Imacr", 0x0012A}, // LATIN CAPITAL LETTER I WITH MACRON
- {"imacr", 0x0012B}, // LATIN SMALL LETTER I WITH MACRON
- {"image", 0x02111}, // BLACK-LETTER CAPITAL I
- {"ImaginaryI", 0x02148}, // DOUBLE-STRUCK ITALIC SMALL I
- {"imagline", 0x02110}, // SCRIPT CAPITAL I
- {"imagpart", 0x02111}, // BLACK-LETTER CAPITAL I
- {"imath", 0x00131}, // LATIN SMALL LETTER DOTLESS I
- {"imof", 0x022B7}, // IMAGE OF
- {"imped", 0x001B5}, // LATIN CAPITAL LETTER Z WITH STROKE
- {"Implies", 0x021D2}, // RIGHTWARDS DOUBLE ARROW
- {"in", 0x02208}, // ELEMENT OF
- {"incare", 0x02105}, // CARE OF
- {"infin", 0x0221E}, // INFINITY
- {"infintie", 0x029DD}, // TIE OVER INFINITY
- {"inodot", 0x00131}, // LATIN SMALL LETTER DOTLESS I
- {"int", 0x0222B}, // INTEGRAL
- {"Int", 0x0222C}, // DOUBLE INTEGRAL
- {"intcal", 0x022BA}, // INTERCALATE
- {"integers", 0x02124}, // DOUBLE-STRUCK CAPITAL Z
- {"Integral", 0x0222B}, // INTEGRAL
- {"intercal", 0x022BA}, // INTERCALATE
- {"Intersection", 0x022C2}, // N-ARY INTERSECTION
- {"intlarhk", 0x02A17}, // INTEGRAL WITH LEFTWARDS ARROW WITH HOOK
- {"intprod", 0x02A3C}, // INTERIOR PRODUCT
- {"InvisibleComma", 0x02063}, // INVISIBLE SEPARATOR
- {"InvisibleTimes", 0x02062}, // INVISIBLE TIMES
- {"IOcy", 0x00401}, // CYRILLIC CAPITAL LETTER IO
- {"iocy", 0x00451}, // CYRILLIC SMALL LETTER IO
- {"Iogon", 0x0012E}, // LATIN CAPITAL LETTER I WITH OGONEK
- {"iogon", 0x0012F}, // LATIN SMALL LETTER I WITH OGONEK
- {"Iopf", 0x1D540}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL I
- {"iopf", 0x1D55A}, // MATHEMATICAL DOUBLE-STRUCK SMALL I
- {"Iota", 0x00399}, // GREEK CAPITAL LETTER IOTA
- {"iota", 0x003B9}, // GREEK SMALL LETTER IOTA
- {"iprod", 0x02A3C}, // INTERIOR PRODUCT
- {"iquest", 0x000BF}, // INVERTED QUESTION MARK
- {"Iscr", 0x02110}, // SCRIPT CAPITAL I
- {"iscr", 0x1D4BE}, // MATHEMATICAL SCRIPT SMALL I
- {"isin", 0x02208}, // ELEMENT OF
- {"isindot", 0x022F5}, // ELEMENT OF WITH DOT ABOVE
- {"isinE", 0x022F9}, // ELEMENT OF WITH TWO HORIZONTAL STROKES
- {"isins", 0x022F4}, // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
- {"isinsv", 0x022F3}, // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
- {"isinv", 0x02208}, // ELEMENT OF
- {"it", 0x02062}, // INVISIBLE TIMES
- {"Itilde", 0x00128}, // LATIN CAPITAL LETTER I WITH TILDE
- {"itilde", 0x00129}, // LATIN SMALL LETTER I WITH TILDE
- {"Iukcy", 0x00406}, // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
- {"iukcy", 0x00456}, // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
- {"Iuml", 0x000CF}, // LATIN CAPITAL LETTER I WITH DIAERESIS
- {"iuml", 0x000EF}, // LATIN SMALL LETTER I WITH DIAERESIS
- {NULL, 0}
-};
-
-static NameId namesJ[]={
- {"Jcirc", 0x00134}, // LATIN CAPITAL LETTER J WITH CIRCUMFLEX
- {"jcirc", 0x00135}, // LATIN SMALL LETTER J WITH CIRCUMFLEX
- {"Jcy", 0x00419}, // CYRILLIC CAPITAL LETTER SHORT I
- {"jcy", 0x00439}, // CYRILLIC SMALL LETTER SHORT I
- {"Jfr", 0x1D50D}, // MATHEMATICAL FRAKTUR CAPITAL J
- {"jfr", 0x1D527}, // MATHEMATICAL FRAKTUR SMALL J
- {"jmath", 0x00237}, // LATIN SMALL LETTER DOTLESS J
- {"Jopf", 0x1D541}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL J
- {"jopf", 0x1D55B}, // MATHEMATICAL DOUBLE-STRUCK SMALL J
- {"Jscr", 0x1D4A5}, // MATHEMATICAL SCRIPT CAPITAL J
- {"jscr", 0x1D4BF}, // MATHEMATICAL SCRIPT SMALL J
- {"Jsercy", 0x00408}, // CYRILLIC CAPITAL LETTER JE
- {"jsercy", 0x00458}, // CYRILLIC SMALL LETTER JE
- {"Jukcy", 0x00404}, // CYRILLIC CAPITAL LETTER UKRAINIAN IE
- {"jukcy", 0x00454}, // CYRILLIC SMALL LETTER UKRAINIAN IE
- {NULL, 0}
-};
-
-static NameId namesK[]={
- {"Kappa", 0x0039A}, // GREEK CAPITAL LETTER KAPPA
- {"kappa", 0x003BA}, // GREEK SMALL LETTER KAPPA
- {"kappav", 0x003F0}, // GREEK KAPPA SYMBOL
- {"Kcedil", 0x00136}, // LATIN CAPITAL LETTER K WITH CEDILLA
- {"kcedil", 0x00137}, // LATIN SMALL LETTER K WITH CEDILLA
- {"Kcy", 0x0041A}, // CYRILLIC CAPITAL LETTER KA
- {"kcy", 0x0043A}, // CYRILLIC SMALL LETTER KA
- {"Kfr", 0x1D50E}, // MATHEMATICAL FRAKTUR CAPITAL K
- {"kfr", 0x1D528}, // MATHEMATICAL FRAKTUR SMALL K
- {"Kgr", 0x0039A}, // GREEK CAPITAL LETTER KAPPA
- {"kgr", 0x003BA}, // GREEK SMALL LETTER KAPPA
- {"kgreen", 0x00138}, // LATIN SMALL LETTER KRA
- {"KHcy", 0x00425}, // CYRILLIC CAPITAL LETTER HA
- {"khcy", 0x00445}, // CYRILLIC SMALL LETTER HA
- {"KHgr", 0x003A7}, // GREEK CAPITAL LETTER CHI
- {"khgr", 0x003C7}, // GREEK SMALL LETTER CHI
- {"KJcy", 0x0040C}, // CYRILLIC CAPITAL LETTER KJE
- {"kjcy", 0x0045C}, // CYRILLIC SMALL LETTER KJE
- {"Kopf", 0x1D542}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL K
- {"kopf", 0x1D55C}, // MATHEMATICAL DOUBLE-STRUCK SMALL K
- {"Kscr", 0x1D4A6}, // MATHEMATICAL SCRIPT CAPITAL K
- {"kscr", 0x1D4C0}, // MATHEMATICAL SCRIPT SMALL K
- {NULL, 0}
-};
-
-static NameId namesL[]={
- {"lAarr", 0x021DA}, // LEFTWARDS TRIPLE ARROW
- {"Lacute", 0x00139}, // LATIN CAPITAL LETTER L WITH ACUTE
- {"lacute", 0x0013A}, // LATIN SMALL LETTER L WITH ACUTE
- {"laemptyv", 0x029B4}, // EMPTY SET WITH LEFT ARROW ABOVE
- {"lagran", 0x02112}, // SCRIPT CAPITAL L
- {"Lambda", 0x0039B}, // GREEK CAPITAL LETTER LAMDA
- {"lambda", 0x003BB}, // GREEK SMALL LETTER LAMDA
- {"lang", 0x027E8}, // MATHEMATICAL LEFT ANGLE BRACKET
- {"Lang", 0x027EA}, // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
- {"langd", 0x02991}, // LEFT ANGLE BRACKET WITH DOT
- {"langle", 0x027E8}, // MATHEMATICAL LEFT ANGLE BRACKET
- {"lap", 0x02A85}, // LESS-THAN OR APPROXIMATE
- {"Laplacetrf", 0x02112}, // SCRIPT CAPITAL L
- {"laquo", 0x000AB}, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
- {"larr", 0x02190}, // LEFTWARDS ARROW
- {"Larr", 0x0219E}, // LEFTWARDS TWO HEADED ARROW
- {"lArr", 0x021D0}, // LEFTWARDS DOUBLE ARROW
- {"larrb", 0x021E4}, // LEFTWARDS ARROW TO BAR
- {"larrbfs", 0x0291F}, // LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND
- {"larrfs", 0x0291D}, // LEFTWARDS ARROW TO BLACK DIAMOND
- {"larrhk", 0x021A9}, // LEFTWARDS ARROW WITH HOOK
- {"larrlp", 0x021AB}, // LEFTWARDS ARROW WITH LOOP
- {"larrpl", 0x02939}, // LEFT-SIDE ARC ANTICLOCKWISE ARROW
- {"larrsim", 0x02973}, // LEFTWARDS ARROW ABOVE TILDE OPERATOR
- {"larrtl", 0x021A2}, // LEFTWARDS ARROW WITH TAIL
- {"lat", 0x02AAB}, // LARGER THAN
- {"latail", 0x02919}, // LEFTWARDS ARROW-TAIL
- {"lAtail", 0x0291B}, // LEFTWARDS DOUBLE ARROW-TAIL
- {"late", 0x02AAD}, // LARGER THAN OR EQUAL TO
-// "lates", 0x02AAD;0x0FE00}, // LARGER THAN OR slanted EQUAL
- {"lbarr", 0x0290C}, // LEFTWARDS DOUBLE DASH ARROW
- {"lBarr", 0x0290E}, // LEFTWARDS TRIPLE DASH ARROW
- {"lbbrk", 0x02772}, // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
- {"lbrace", 0x0007B}, // LEFT CURLY BRACKET
- {"lbrack", 0x0005B}, // LEFT SQUARE BRACKET
- {"lbrke", 0x0298B}, // LEFT SQUARE BRACKET WITH UNDERBAR
- {"lbrksld", 0x0298F}, // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
- {"lbrkslu", 0x0298D}, // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
- {"Lcaron", 0x0013D}, // LATIN CAPITAL LETTER L WITH CARON
- {"lcaron", 0x0013E}, // LATIN SMALL LETTER L WITH CARON
- {"Lcedil", 0x0013B}, // LATIN CAPITAL LETTER L WITH CEDILLA
- {"lcedil", 0x0013C}, // LATIN SMALL LETTER L WITH CEDILLA
- {"lceil", 0x02308}, // LEFT CEILING
- {"lcub", 0x0007B}, // LEFT CURLY BRACKET
- {"Lcy", 0x0041B}, // CYRILLIC CAPITAL LETTER EL
- {"lcy", 0x0043B}, // CYRILLIC SMALL LETTER EL
- {"ldca", 0x02936}, // ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS
- {"ldquo", 0x0201C}, // LEFT DOUBLE QUOTATION MARK
- {"ldquor", 0x0201E}, // DOUBLE LOW-9 QUOTATION MARK
- {"ldrdhar", 0x02967}, // LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN
- {"ldrushar", 0x0294B}, // LEFT BARB DOWN RIGHT BARB UP HARPOON
- {"ldsh", 0x021B2}, // DOWNWARDS ARROW WITH TIP LEFTWARDS
- {"le", 0x02264}, // LESS-THAN OR EQUAL TO
- {"lE", 0x02266}, // LESS-THAN OVER EQUAL TO
- {"LeftAngleBracket", 0x027E8}, // MATHEMATICAL LEFT ANGLE BRACKET
- {"leftarrow", 0x02190}, // LEFTWARDS ARROW
- {"LeftArrow", 0x02190}, // LEFTWARDS ARROW
- {"Leftarrow", 0x021D0}, // LEFTWARDS DOUBLE ARROW
- {"LeftArrowBar", 0x021E4}, // LEFTWARDS ARROW TO BAR
- {"LeftArrowRightArrow", 0x021C6}, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
- {"leftarrowtail", 0x021A2}, // LEFTWARDS ARROW WITH TAIL
- {"LeftCeiling", 0x02308}, // LEFT CEILING
- {"LeftDoubleBracket", 0x027E6}, // MATHEMATICAL LEFT WHITE SQUARE BRACKET
- {"LeftDownTeeVector", 0x02961}, // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR
- {"LeftDownVector", 0x021C3}, // DOWNWARDS HARPOON WITH BARB LEFTWARDS
- {"LeftDownVectorBar", 0x02959}, // DOWNWARDS HARPOON WITH BARB LEFT TO BAR
- {"LeftFloor", 0x0230A}, // LEFT FLOOR
- {"leftharpoondown", 0x021BD}, // LEFTWARDS HARPOON WITH BARB DOWNWARDS
- {"leftharpoonup", 0x021BC}, // LEFTWARDS HARPOON WITH BARB UPWARDS
- {"leftleftarrows", 0x021C7}, // LEFTWARDS PAIRED ARROWS
- {"leftrightarrow", 0x02194}, // LEFT RIGHT ARROW
- {"LeftRightArrow", 0x02194}, // LEFT RIGHT ARROW
- {"Leftrightarrow", 0x021D4}, // LEFT RIGHT DOUBLE ARROW
- {"leftrightarrows", 0x021C6}, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
- {"leftrightharpoons", 0x021CB}, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
- {"leftrightsquigarrow", 0x021AD}, // LEFT RIGHT WAVE ARROW
- {"LeftRightVector", 0x0294E}, // LEFT BARB UP RIGHT BARB UP HARPOON
- {"LeftTee", 0x022A3}, // LEFT TACK
- {"LeftTeeArrow", 0x021A4}, // LEFTWARDS ARROW FROM BAR
- {"LeftTeeVector", 0x0295A}, // LEFTWARDS HARPOON WITH BARB UP FROM BAR
- {"leftthreetimes", 0x022CB}, // LEFT SEMIDIRECT PRODUCT
- {"LeftTriangle", 0x022B2}, // NORMAL SUBGROUP OF
- {"LeftTriangleBar", 0x029CF}, // LEFT TRIANGLE BESIDE VERTICAL BAR
- {"LeftTriangleEqual", 0x022B4}, // NORMAL SUBGROUP OF OR EQUAL TO
- {"LeftUpDownVector", 0x02951}, // UP BARB LEFT DOWN BARB LEFT HARPOON
- {"LeftUpTeeVector", 0x02960}, // UPWARDS HARPOON WITH BARB LEFT FROM BAR
- {"LeftUpVector", 0x021BF}, // UPWARDS HARPOON WITH BARB LEFTWARDS
- {"LeftUpVectorBar", 0x02958}, // UPWARDS HARPOON WITH BARB LEFT TO BAR
- {"LeftVector", 0x021BC}, // LEFTWARDS HARPOON WITH BARB UPWARDS
- {"LeftVectorBar", 0x02952}, // LEFTWARDS HARPOON WITH BARB UP TO BAR
- {"leg", 0x022DA}, // LESS-THAN EQUAL TO OR GREATER-THAN
- {"lEg", 0x02A8B}, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN
- {"leq", 0x02264}, // LESS-THAN OR EQUAL TO
- {"leqq", 0x02266}, // LESS-THAN OVER EQUAL TO
- {"leqslant", 0x02A7D}, // LESS-THAN OR SLANTED EQUAL TO
- {"les", 0x02A7D}, // LESS-THAN OR SLANTED EQUAL TO
- {"lescc", 0x02AA8}, // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
- {"lesdot", 0x02A7F}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
- {"lesdoto", 0x02A81}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
- {"lesdotor", 0x02A83}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT
-// "lesg", 0x022DA;0x0FE00}, // LESS-THAN slanted EQUAL TO OR GREATER-THAN
- {"lesges", 0x02A93}, // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL
- {"lessapprox", 0x02A85}, // LESS-THAN OR APPROXIMATE
- {"lessdot", 0x022D6}, // LESS-THAN WITH DOT
- {"lesseqgtr", 0x022DA}, // LESS-THAN EQUAL TO OR GREATER-THAN
- {"lesseqqgtr", 0x02A8B}, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN
- {"LessEqualGreater", 0x022DA}, // LESS-THAN EQUAL TO OR GREATER-THAN
- {"LessFullEqual", 0x02266}, // LESS-THAN OVER EQUAL TO
- {"LessGreater", 0x02276}, // LESS-THAN OR GREATER-THAN
- {"lessgtr", 0x02276}, // LESS-THAN OR GREATER-THAN
- {"LessLess", 0x02AA1}, // DOUBLE NESTED LESS-THAN
- {"lesssim", 0x02272}, // LESS-THAN OR EQUIVALENT TO
- {"LessSlantEqual", 0x02A7D}, // LESS-THAN OR SLANTED EQUAL TO
- {"LessTilde", 0x02272}, // LESS-THAN OR EQUIVALENT TO
- {"lfisht", 0x0297C}, // LEFT FISH TAIL
- {"lfloor", 0x0230A}, // LEFT FLOOR
- {"Lfr", 0x1D50F}, // MATHEMATICAL FRAKTUR CAPITAL L
- {"lfr", 0x1D529}, // MATHEMATICAL FRAKTUR SMALL L
- {"lg", 0x02276}, // LESS-THAN OR GREATER-THAN
- {"lgE", 0x02A91}, // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL
- {"Lgr", 0x0039B}, // GREEK CAPITAL LETTER LAMDA
- {"lgr", 0x003BB}, // GREEK SMALL LETTER LAMDA
- {"lHar", 0x02962}, // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN
- {"lhard", 0x021BD}, // LEFTWARDS HARPOON WITH BARB DOWNWARDS
- {"lharu", 0x021BC}, // LEFTWARDS HARPOON WITH BARB UPWARDS
- {"lharul", 0x0296A}, // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH
- {"lhblk", 0x02584}, // LOWER HALF BLOCK
- {"LJcy", 0x00409}, // CYRILLIC CAPITAL LETTER LJE
- {"ljcy", 0x00459}, // CYRILLIC SMALL LETTER LJE
- {"ll", 0x0226A}, // MUCH LESS-THAN
- {"Ll", 0x022D8}, // VERY MUCH LESS-THAN
- {"llarr", 0x021C7}, // LEFTWARDS PAIRED ARROWS
- {"llcorner", 0x0231E}, // BOTTOM LEFT CORNER
- {"Lleftarrow", 0x021DA}, // LEFTWARDS TRIPLE ARROW
- {"llhard", 0x0296B}, // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH
- {"lltri", 0x025FA}, // LOWER LEFT TRIANGLE
- {"Lmidot", 0x0013F}, // LATIN CAPITAL LETTER L WITH MIDDLE DOT
- {"lmidot", 0x00140}, // LATIN SMALL LETTER L WITH MIDDLE DOT
- {"lmoust", 0x023B0}, // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION
- {"lmoustache", 0x023B0}, // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION
- {"lnap", 0x02A89}, // LESS-THAN AND NOT APPROXIMATE
- {"lnapprox", 0x02A89}, // LESS-THAN AND NOT APPROXIMATE
- {"lnE", 0x02268}, // LESS-THAN BUT NOT EQUAL TO
- {"lne", 0x02A87}, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO
- {"lneq", 0x02A87}, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO
- {"lneqq", 0x02268}, // LESS-THAN BUT NOT EQUAL TO
- {"lnsim", 0x022E6}, // LESS-THAN BUT NOT EQUIVALENT TO
- {"loang", 0x027EC}, // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
- {"loarr", 0x021FD}, // LEFTWARDS OPEN-HEADED ARROW
- {"lobrk", 0x027E6}, // MATHEMATICAL LEFT WHITE SQUARE BRACKET
- {"longleftarrow", 0x027F5}, // LONG LEFTWARDS ARROW
- {"LongLeftArrow", 0x027F5}, // LONG LEFTWARDS ARROW
- {"Longleftarrow", 0x027F8}, // LONG LEFTWARDS DOUBLE ARROW
- {"longleftrightarrow", 0x027F7}, // LONG LEFT RIGHT ARROW
- {"LongLeftRightArrow", 0x027F7}, // LONG LEFT RIGHT ARROW
- {"Longleftrightarrow", 0x027FA}, // LONG LEFT RIGHT DOUBLE ARROW
- {"longmapsto", 0x027FC}, // LONG RIGHTWARDS ARROW FROM BAR
- {"longrightarrow", 0x027F6}, // LONG RIGHTWARDS ARROW
- {"LongRightArrow", 0x027F6}, // LONG RIGHTWARDS ARROW
- {"Longrightarrow", 0x027F9}, // LONG RIGHTWARDS DOUBLE ARROW
- {"looparrowleft", 0x021AB}, // LEFTWARDS ARROW WITH LOOP
- {"looparrowright", 0x021AC}, // RIGHTWARDS ARROW WITH LOOP
- {"lopar", 0x02985}, // LEFT WHITE PARENTHESIS
- {"Lopf", 0x1D543}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL L
- {"lopf", 0x1D55D}, // MATHEMATICAL DOUBLE-STRUCK SMALL L
- {"loplus", 0x02A2D}, // PLUS SIGN IN LEFT HALF CIRCLE
- {"lotimes", 0x02A34}, // MULTIPLICATION SIGN IN LEFT HALF CIRCLE
- {"lowast", 0x02217}, // ASTERISK OPERATOR
- {"lowbar", 0x0005F}, // LOW LINE
- {"LowerLeftArrow", 0x02199}, // SOUTH WEST ARROW
- {"LowerRightArrow", 0x02198}, // SOUTH EAST ARROW
- {"loz", 0x025CA}, // LOZENGE
- {"lozenge", 0x025CA}, // LOZENGE
- {"lozf", 0x029EB}, // BLACK LOZENGE
- {"lpar", 0x00028}, // LEFT PARENTHESIS
- {"lparlt", 0x02993}, // LEFT ARC LESS-THAN BRACKET
- {"lrarr", 0x021C6}, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
- {"lrcorner", 0x0231F}, // BOTTOM RIGHT CORNER
- {"lrhar", 0x021CB}, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
- {"lrhard", 0x0296D}, // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH
- {"lrm", 0x0200E}, // LEFT-TO-RIGHT MARK
- {"lrtri", 0x022BF}, // RIGHT TRIANGLE
- {"lsaquo", 0x02039}, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
- {"Lscr", 0x02112}, // SCRIPT CAPITAL L
- {"lscr", 0x1D4C1}, // MATHEMATICAL SCRIPT SMALL L
- {"lsh", 0x021B0}, // UPWARDS ARROW WITH TIP LEFTWARDS
- {"Lsh", 0x021B0}, // UPWARDS ARROW WITH TIP LEFTWARDS
- {"lsim", 0x02272}, // LESS-THAN OR EQUIVALENT TO
- {"lsime", 0x02A8D}, // LESS-THAN ABOVE SIMILAR OR EQUAL
- {"lsimg", 0x02A8F}, // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN
- {"lsqb", 0x0005B}, // LEFT SQUARE BRACKET
- {"lsquo", 0x02018}, // LEFT SINGLE QUOTATION MARK
- {"lsquor", 0x0201A}, // SINGLE LOW-9 QUOTATION MARK
- {"Lstrok", 0x00141}, // LATIN CAPITAL LETTER L WITH STROKE
- {"lstrok", 0x00142}, // LATIN SMALL LETTER L WITH STROKE
- {"lt", 0x0003C}, // LESS-THAN SIGN
- {"LT", 0x0003C}, // LESS-THAN SIGN
- {"Lt", 0x0226A}, // MUCH LESS-THAN
- {"ltcc", 0x02AA6}, // LESS-THAN CLOSED BY CURVE
- {"ltcir", 0x02A79}, // LESS-THAN WITH CIRCLE INSIDE
- {"ltdot", 0x022D6}, // LESS-THAN WITH DOT
- {"lthree", 0x022CB}, // LEFT SEMIDIRECT PRODUCT
- {"ltimes", 0x022C9}, // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT
- {"ltlarr", 0x02976}, // LESS-THAN ABOVE LEFTWARDS ARROW
- {"ltquest", 0x02A7B}, // LESS-THAN WITH QUESTION MARK ABOVE
- {"ltri", 0x025C3}, // WHITE LEFT-POINTING SMALL TRIANGLE
- {"ltrie", 0x022B4}, // NORMAL SUBGROUP OF OR EQUAL TO
- {"ltrif", 0x025C2}, // BLACK LEFT-POINTING SMALL TRIANGLE
- {"ltrPar", 0x02996}, // DOUBLE RIGHT ARC LESS-THAN BRACKET
- {"lurdshar", 0x0294A}, // LEFT BARB UP RIGHT BARB DOWN HARPOON
- {"luruhar", 0x02966}, // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP
-// "lvertneqq", 0x02268;0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke
-// "lvnE", 0x02268;0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke
- {NULL, 0}
-};
-
-static NameId namesM[]={
- {"macr", 0x000AF}, // MACRON
- {"male", 0x02642}, // MALE SIGN
- {"malt", 0x02720}, // MALTESE CROSS
- {"maltese", 0x02720}, // MALTESE CROSS
- {"map", 0x021A6}, // RIGHTWARDS ARROW FROM BAR
- {"Map", 0x02905}, // RIGHTWARDS TWO-HEADED ARROW FROM BAR
- {"mapsto", 0x021A6}, // RIGHTWARDS ARROW FROM BAR
- {"mapstodown", 0x021A7}, // DOWNWARDS ARROW FROM BAR
- {"mapstoleft", 0x021A4}, // LEFTWARDS ARROW FROM BAR
- {"mapstoup", 0x021A5}, // UPWARDS ARROW FROM BAR
- {"marker", 0x025AE}, // BLACK VERTICAL RECTANGLE
- {"mcomma", 0x02A29}, // MINUS SIGN WITH COMMA ABOVE
- {"Mcy", 0x0041C}, // CYRILLIC CAPITAL LETTER EM
- {"mcy", 0x0043C}, // CYRILLIC SMALL LETTER EM
- {"mdash", 0x02014}, // EM DASH
- {"mDDot", 0x0223A}, // GEOMETRIC PROPORTION
- {"measuredangle", 0x02221}, // MEASURED ANGLE
- {"MediumSpace", 0x0205F}, // MEDIUM MATHEMATICAL SPACE
- {"Mellintrf", 0x02133}, // SCRIPT CAPITAL M
- {"Mfr", 0x1D510}, // MATHEMATICAL FRAKTUR CAPITAL M
- {"mfr", 0x1D52A}, // MATHEMATICAL FRAKTUR SMALL M
- {"Mgr", 0x0039C}, // GREEK CAPITAL LETTER MU
- {"mgr", 0x003BC}, // GREEK SMALL LETTER MU
- {"mho", 0x02127}, // INVERTED OHM SIGN
- {"micro", 0x000B5}, // MICRO SIGN
- {"mid", 0x02223}, // DIVIDES
- {"midast", 0x0002A}, // ASTERISK
- {"midcir", 0x02AF0}, // VERTICAL LINE WITH CIRCLE BELOW
- {"middot", 0x000B7}, // MIDDLE DOT
- {"minus", 0x02212}, // MINUS SIGN
- {"minusb", 0x0229F}, // SQUARED MINUS
- {"minusd", 0x02238}, // DOT MINUS
- {"minusdu", 0x02A2A}, // MINUS SIGN WITH DOT BELOW
- {"MinusPlus", 0x02213}, // MINUS-OR-PLUS SIGN
- {"mlcp", 0x02ADB}, // TRANSVERSAL INTERSECTION
- {"mldr", 0x02026}, // HORIZONTAL ELLIPSIS
- {"mnplus", 0x02213}, // MINUS-OR-PLUS SIGN
- {"models", 0x022A7}, // MODELS
- {"Mopf", 0x1D544}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL M
- {"mopf", 0x1D55E}, // MATHEMATICAL DOUBLE-STRUCK SMALL M
- {"mp", 0x02213}, // MINUS-OR-PLUS SIGN
- {"Mscr", 0x02133}, // SCRIPT CAPITAL M
- {"mscr", 0x1D4C2}, // MATHEMATICAL SCRIPT SMALL M
- {"mstpos", 0x0223E}, // INVERTED LAZY S
- {"Mu", 0x0039C}, // GREEK CAPITAL LETTER MU
- {"mu", 0x003BC}, // GREEK SMALL LETTER MU
- {"multimap", 0x022B8}, // MULTIMAP
- {"mumap", 0x022B8}, // MULTIMAP
- {NULL, 0}
-};
-
-static NameId namesN[]={
- {"nabla", 0x02207}, // NABLA
- {"Nacute", 0x00143}, // LATIN CAPITAL LETTER N WITH ACUTE
- {"nacute", 0x00144}, // LATIN SMALL LETTER N WITH ACUTE
-// "nang", 0x02220;0x020D2}, // ANGLE with vertical line
- {"nap", 0x02249}, // NOT ALMOST EQUAL TO
-// "napE", 0x02A70;0x00338}, // APPROXIMATELY EQUAL OR EQUAL TO with slash
-// "napid", 0x0224B;0x00338}, // TRIPLE TILDE with slash
- {"napos", 0x00149}, // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
- {"napprox", 0x02249}, // NOT ALMOST EQUAL TO
- {"natur", 0x0266E}, // MUSIC NATURAL SIGN
- {"natural", 0x0266E}, // MUSIC NATURAL SIGN
- {"naturals", 0x02115}, // DOUBLE-STRUCK CAPITAL N
- {"nbsp", 0x000A0}, // NO-BREAK SPACE
-// "nbump", 0x0224E;0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash
-// "nbumpe", 0x0224F;0x00338}, // DIFFERENCE BETWEEN with slash
- {"ncap", 0x02A43}, // INTERSECTION WITH OVERBAR
- {"Ncaron", 0x00147}, // LATIN CAPITAL LETTER N WITH CARON
- {"ncaron", 0x00148}, // LATIN SMALL LETTER N WITH CARON
- {"Ncedil", 0x00145}, // LATIN CAPITAL LETTER N WITH CEDILLA
- {"ncedil", 0x00146}, // LATIN SMALL LETTER N WITH CEDILLA
- {"ncong", 0x02247}, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
-// "ncongdot", 0x02A6D;0x00338}, // CONGRUENT WITH DOT ABOVE with slash
- {"ncup", 0x02A42}, // UNION WITH OVERBAR
- {"Ncy", 0x0041D}, // CYRILLIC CAPITAL LETTER EN
- {"ncy", 0x0043D}, // CYRILLIC SMALL LETTER EN
- {"ndash", 0x02013}, // EN DASH
- {"ne", 0x02260}, // NOT EQUAL TO
- {"nearhk", 0x02924}, // NORTH EAST ARROW WITH HOOK
- {"nearr", 0x02197}, // NORTH EAST ARROW
- {"neArr", 0x021D7}, // NORTH EAST DOUBLE ARROW
- {"nearrow", 0x02197}, // NORTH EAST ARROW
-// "nedot", 0x02250;0x00338}, // APPROACHES THE LIMIT with slash
- {"NegativeMediumSpace", 0x0200B}, // ZERO WIDTH SPACE
- {"NegativeThickSpace", 0x0200B}, // ZERO WIDTH SPACE
- {"NegativeThinSpace", 0x0200B}, // ZERO WIDTH SPACE
- {"NegativeVeryThinSpace", 0x0200B}, // ZERO WIDTH SPACE
- {"nequiv", 0x02262}, // NOT IDENTICAL TO
- {"nesear", 0x02928}, // NORTH EAST ARROW AND SOUTH EAST ARROW
-// "nesim", 0x02242;0x00338}, // MINUS TILDE with slash
- {"NestedGreaterGreater", 0x0226B}, // MUCH GREATER-THAN
- {"NestedLessLess", 0x0226A}, // MUCH LESS-THAN
- {"NewLine", 0x0000A}, // LINE FEED (LF)
- {"nexist", 0x02204}, // THERE DOES NOT EXIST
- {"nexists", 0x02204}, // THERE DOES NOT EXIST
- {"Nfr", 0x1D511}, // MATHEMATICAL FRAKTUR CAPITAL N
- {"nfr", 0x1D52B}, // MATHEMATICAL FRAKTUR SMALL N
-// "ngE", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash
- {"nge", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO
- {"ngeq", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO
-// "ngeqq", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash
-// "ngeqslant", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
-// "nges", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
-// "nGg", 0x022D9;0x00338}, // VERY MUCH GREATER-THAN with slash
- {"Ngr", 0x0039D}, // GREEK CAPITAL LETTER NU
- {"ngr", 0x003BD}, // GREEK SMALL LETTER NU
- {"ngsim", 0x02275}, // NEITHER GREATER-THAN NOR EQUIVALENT TO
-// "nGt", 0x0226B;0x020D2}, // MUCH GREATER THAN with vertical line
- {"ngt", 0x0226F}, // NOT GREATER-THAN
- {"ngtr", 0x0226F}, // NOT GREATER-THAN
-// "nGtv", 0x0226B;0x00338}, // MUCH GREATER THAN with slash
- {"nharr", 0x021AE}, // LEFT RIGHT ARROW WITH STROKE
- {"nhArr", 0x021CE}, // LEFT RIGHT DOUBLE ARROW WITH STROKE
- {"nhpar", 0x02AF2}, // PARALLEL WITH HORIZONTAL STROKE
- {"ni", 0x0220B}, // CONTAINS AS MEMBER
- {"nis", 0x022FC}, // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
- {"nisd", 0x022FA}, // CONTAINS WITH LONG HORIZONTAL STROKE
- {"niv", 0x0220B}, // CONTAINS AS MEMBER
- {"NJcy", 0x0040A}, // CYRILLIC CAPITAL LETTER NJE
- {"njcy", 0x0045A}, // CYRILLIC SMALL LETTER NJE
- {"nlarr", 0x0219A}, // LEFTWARDS ARROW WITH STROKE
- {"nlArr", 0x021CD}, // LEFTWARDS DOUBLE ARROW WITH STROKE
- {"nldr", 0x02025}, // TWO DOT LEADER
-// "nlE", 0x02266;0x00338}, // LESS-THAN OVER EQUAL TO with slash
- {"nle", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO
- {"nleftarrow", 0x0219A}, // LEFTWARDS ARROW WITH STROKE
- {"nLeftarrow", 0x021CD}, // LEFTWARDS DOUBLE ARROW WITH STROKE
- {"nleftrightarrow", 0x021AE}, // LEFT RIGHT ARROW WITH STROKE
- {"nLeftrightarrow", 0x021CE}, // LEFT RIGHT DOUBLE ARROW WITH STROKE
- {"nleq", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO
-// "nleqq", 0x02266;0x00338}, // LESS-THAN OVER EQUAL TO with slash
-// "nleqslant", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
-// "nles", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
- {"nless", 0x0226E}, // NOT LESS-THAN
-// "nLl", 0x022D8;0x00338}, // VERY MUCH LESS-THAN with slash
- {"nlsim", 0x02274}, // NEITHER LESS-THAN NOR EQUIVALENT TO
-// "nLt", 0x0226A;0x020D2}, // MUCH LESS THAN with vertical line
- {"nlt", 0x0226E}, // NOT LESS-THAN
- {"nltri", 0x022EA}, // NOT NORMAL SUBGROUP OF
- {"nltrie", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO
-// "nLtv", 0x0226A;0x00338}, // MUCH LESS THAN with slash
- {"nmid", 0x02224}, // DOES NOT DIVIDE
- {"NoBreak", 0x02060}, // WORD JOINER
- {"NonBreakingSpace", 0x000A0}, // NO-BREAK SPACE
- {"Nopf", 0x02115}, // DOUBLE-STRUCK CAPITAL N
- {"nopf", 0x1D55F}, // MATHEMATICAL DOUBLE-STRUCK SMALL N
- {"not", 0x000AC}, // NOT SIGN
- {"Not", 0x02AEC}, // DOUBLE STROKE NOT SIGN
- {"NotCongruent", 0x02262}, // NOT IDENTICAL TO
- {"NotCupCap", 0x0226D}, // NOT EQUIVALENT TO
- {"NotDoubleVerticalBar", 0x02226}, // NOT PARALLEL TO
- {"NotElement", 0x02209}, // NOT AN ELEMENT OF
- {"NotEqual", 0x02260}, // NOT EQUAL TO
-// "NotEqualTilde", 0x02242;0x00338}, // MINUS TILDE with slash
- {"NotExists", 0x02204}, // THERE DOES NOT EXIST
- {"NotGreater", 0x0226F}, // NOT GREATER-THAN
- {"NotGreaterEqual", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO
-// "NotGreaterFullEqual", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash
-// "NotGreaterGreater", 0x0226B;0x00338}, // MUCH GREATER THAN with slash
- {"NotGreaterLess", 0x02279}, // NEITHER GREATER-THAN NOR LESS-THAN
-// "NotGreaterSlantEqual", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
- {"NotGreaterTilde", 0x02275}, // NEITHER GREATER-THAN NOR EQUIVALENT TO
-// "NotHumpDownHump", 0x0224E;0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash
-// "NotHumpEqual", 0x0224F;0x00338}, // DIFFERENCE BETWEEN with slash
- {"notin", 0x02209}, // NOT AN ELEMENT OF
-// "notindot", 0x022F5;0x00338}, // ELEMENT OF WITH DOT ABOVE with slash
-// "notinE", 0x022F9;0x00338}, // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash
- {"notinva", 0x02209}, // NOT AN ELEMENT OF
- {"notinvb", 0x022F7}, // SMALL ELEMENT OF WITH OVERBAR
- {"notinvc", 0x022F6}, // ELEMENT OF WITH OVERBAR
- {"NotLeftTriangle", 0x022EA}, // NOT NORMAL SUBGROUP OF
-// "NotLeftTriangleBar", 0x029CF;0x00338}, // LEFT TRIANGLE BESIDE VERTICAL BAR with slash
- {"NotLeftTriangleEqual", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO
- {"NotLess", 0x0226E}, // NOT LESS-THAN
- {"NotLessEqual", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO
- {"NotLessGreater", 0x02278}, // NEITHER LESS-THAN NOR GREATER-THAN
-// "NotLessLess", 0x0226A;0x00338}, // MUCH LESS THAN with slash
-// "NotLessSlantEqual", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
- {"NotLessTilde", 0x02274}, // NEITHER LESS-THAN NOR EQUIVALENT TO
-// "NotNestedGreaterGreater", 0x02AA2;0x00338}, // DOUBLE NESTED GREATER-THAN with slash
-// "NotNestedLessLess", 0x02AA1;0x00338}, // DOUBLE NESTED LESS-THAN with slash
- {"notni", 0x0220C}, // DOES NOT CONTAIN AS MEMBER
- {"notniva", 0x0220C}, // DOES NOT CONTAIN AS MEMBER
- {"notnivb", 0x022FE}, // SMALL CONTAINS WITH OVERBAR
- {"notnivc", 0x022FD}, // CONTAINS WITH OVERBAR
- {"NotPrecedes", 0x02280}, // DOES NOT PRECEDE
-// "NotPrecedesEqual", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
- {"NotPrecedesSlantEqual", 0x022E0}, // DOES NOT PRECEDE OR EQUAL
- {"NotReverseElement", 0x0220C}, // DOES NOT CONTAIN AS MEMBER
- {"NotRightTriangle", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP
-// "NotRightTriangleBar", 0x029D0;0x00338}, // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash
- {"NotRightTriangleEqual", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
-// "NotSquareSubset", 0x0228F;0x00338}, // SQUARE IMAGE OF with slash
- {"NotSquareSubsetEqual", 0x022E2}, // NOT SQUARE IMAGE OF OR EQUAL TO
-// "NotSquareSuperset", 0x02290;0x00338}, // SQUARE ORIGINAL OF with slash
- {"NotSquareSupersetEqual", 0x022E3}, // NOT SQUARE ORIGINAL OF OR EQUAL TO
-// "NotSubset", 0x02282;0x020D2}, // SUBSET OF with vertical line
- {"NotSubsetEqual", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO
- {"NotSucceeds", 0x02281}, // DOES NOT SUCCEED
-// "NotSucceedsEqual", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
- {"NotSucceedsSlantEqual", 0x022E1}, // DOES NOT SUCCEED OR EQUAL
-// "NotSucceedsTilde", 0x0227F;0x00338}, // SUCCEEDS OR EQUIVALENT TO with slash
-// "NotSuperset", 0x02283;0x020D2}, // SUPERSET OF with vertical line
- {"NotSupersetEqual", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO
- {"NotTilde", 0x02241}, // NOT TILDE
- {"NotTildeEqual", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO
- {"NotTildeFullEqual", 0x02247}, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
- {"NotTildeTilde", 0x02249}, // NOT ALMOST EQUAL TO
- {"NotVerticalBar", 0x02224}, // DOES NOT DIVIDE
- {"npar", 0x02226}, // NOT PARALLEL TO
- {"nparallel", 0x02226}, // NOT PARALLEL TO
-// "nparsl", 0x02AFD;0x020E5}, // DOUBLE SOLIDUS OPERATOR with reverse slash
-// "npart", 0x02202;0x00338}, // PARTIAL DIFFERENTIAL with slash
- {"npolint", 0x02A14}, // LINE INTEGRATION NOT INCLUDING THE POLE
- {"npr", 0x02280}, // DOES NOT PRECEDE
- {"nprcue", 0x022E0}, // DOES NOT PRECEDE OR EQUAL
-// "npre", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
- {"nprec", 0x02280}, // DOES NOT PRECEDE
-// "npreceq", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
- {"nrarr", 0x0219B}, // RIGHTWARDS ARROW WITH STROKE
- {"nrArr", 0x021CF}, // RIGHTWARDS DOUBLE ARROW WITH STROKE
-// "nrarrc", 0x02933;0x00338}, // WAVE ARROW POINTING DIRECTLY RIGHT with slash
-// "nrarrw", 0x0219D;0x00338}, // RIGHTWARDS WAVE ARROW with slash
- {"nrightarrow", 0x0219B}, // RIGHTWARDS ARROW WITH STROKE
- {"nRightarrow", 0x021CF}, // RIGHTWARDS DOUBLE ARROW WITH STROKE
- {"nrtri", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP
- {"nrtrie", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
- {"nsc", 0x02281}, // DOES NOT SUCCEED
- {"nsccue", 0x022E1}, // DOES NOT SUCCEED OR EQUAL
-// "nsce", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
- {"Nscr", 0x1D4A9}, // MATHEMATICAL SCRIPT CAPITAL N
- {"nscr", 0x1D4C3}, // MATHEMATICAL SCRIPT SMALL N
- {"nshortmid", 0x02224}, // DOES NOT DIVIDE
- {"nshortparallel", 0x02226}, // NOT PARALLEL TO
- {"nsim", 0x02241}, // NOT TILDE
- {"nsime", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO
- {"nsimeq", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO
- {"nsmid", 0x02224}, // DOES NOT DIVIDE
- {"nspar", 0x02226}, // NOT PARALLEL TO
- {"nsqsube", 0x022E2}, // NOT SQUARE IMAGE OF OR EQUAL TO
- {"nsqsupe", 0x022E3}, // NOT SQUARE ORIGINAL OF OR EQUAL TO
- {"nsub", 0x02284}, // NOT A SUBSET OF
- {"nsube", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO
-// "nsubE", 0x02AC5;0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash
-// "nsubset", 0x02282;0x020D2}, // SUBSET OF with vertical line
- {"nsubseteq", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO
-// "nsubseteqq", 0x02AC5;0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash
- {"nsucc", 0x02281}, // DOES NOT SUCCEED
-// "nsucceq", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
- {"nsup", 0x02285}, // NOT A SUPERSET OF
- {"nsupe", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO
-// "nsupE", 0x02AC6;0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash
-// "nsupset", 0x02283;0x020D2}, // SUPERSET OF with vertical line
- {"nsupseteq", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO
-// "nsupseteqq", 0x02AC6;0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash
- {"ntgl", 0x02279}, // NEITHER GREATER-THAN NOR LESS-THAN
- {"Ntilde", 0x000D1}, // LATIN CAPITAL LETTER N WITH TILDE
- {"ntilde", 0x000F1}, // LATIN SMALL LETTER N WITH TILDE
- {"ntlg", 0x02278}, // NEITHER LESS-THAN NOR GREATER-THAN
- {"ntriangleleft", 0x022EA}, // NOT NORMAL SUBGROUP OF
- {"ntrianglelefteq", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO
- {"ntriangleright", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP
- {"ntrianglerighteq", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
- {"Nu", 0x0039D}, // GREEK CAPITAL LETTER NU
- {"nu", 0x003BD}, // GREEK SMALL LETTER NU
- {"num", 0x00023}, // NUMBER SIGN
- {"numero", 0x02116}, // NUMERO SIGN
- {"numsp", 0x02007}, // FIGURE SPACE
-// "nvap", 0x0224D;0x020D2}, // EQUIVALENT TO with vertical line
- {"nvdash", 0x022AC}, // DOES NOT PROVE
- {"nvDash", 0x022AD}, // NOT TRUE
- {"nVdash", 0x022AE}, // DOES NOT FORCE
- {"nVDash", 0x022AF}, // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
-// "nvge", 0x02265;0x020D2}, // GREATER-THAN OR EQUAL TO with vertical line
-// "nvgt", 0x0003E;0x020D2}, // GREATER-THAN SIGN with vertical line
- {"nvHarr", 0x02904}, // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE
- {"nvinfin", 0x029DE}, // INFINITY NEGATED WITH VERTICAL BAR
- {"nvlArr", 0x02902}, // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE
-// "nvle", 0x02264;0x020D2}, // LESS-THAN OR EQUAL TO with vertical line
-// "nvlt", 0x0003C;0x020D2}, // LESS-THAN SIGN with vertical line
-// "nvltrie", 0x022B4;0x020D2}, // NORMAL SUBGROUP OF OR EQUAL TO with vertical line
- {"nvrArr", 0x02903}, // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE
-// "nvrtrie", 0x022B5;0x020D2}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line
-// "nvsim", 0x0223C;0x020D2}, // TILDE OPERATOR with vertical line
- {"nwarhk", 0x02923}, // NORTH WEST ARROW WITH HOOK
- {"nwarr", 0x02196}, // NORTH WEST ARROW
- {"nwArr", 0x021D6}, // NORTH WEST DOUBLE ARROW
- {"nwarrow", 0x02196}, // NORTH WEST ARROW
- {"nwnear", 0x02927}, // NORTH WEST ARROW AND NORTH EAST ARROW
- {NULL, 0}
-};
-
-static NameId namesO[]={
- {"Oacgr", 0x0038C}, // GREEK CAPITAL LETTER OMICRON WITH TONOS
- {"oacgr", 0x003CC}, // GREEK SMALL LETTER OMICRON WITH TONOS
- {"Oacute", 0x000D3}, // LATIN CAPITAL LETTER O WITH ACUTE
- {"oacute", 0x000F3}, // LATIN SMALL LETTER O WITH ACUTE
- {"oast", 0x0229B}, // CIRCLED ASTERISK OPERATOR
- {"ocir", 0x0229A}, // CIRCLED RING OPERATOR
- {"Ocirc", 0x000D4}, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX
- {"ocirc", 0x000F4}, // LATIN SMALL LETTER O WITH CIRCUMFLEX
- {"Ocy", 0x0041E}, // CYRILLIC CAPITAL LETTER O
- {"ocy", 0x0043E}, // CYRILLIC SMALL LETTER O
- {"odash", 0x0229D}, // CIRCLED DASH
- {"Odblac", 0x00150}, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
- {"odblac", 0x00151}, // LATIN SMALL LETTER O WITH DOUBLE ACUTE
- {"odiv", 0x02A38}, // CIRCLED DIVISION SIGN
- {"odot", 0x02299}, // CIRCLED DOT OPERATOR
- {"odsold", 0x029BC}, // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN
- {"OElig", 0x00152}, // LATIN CAPITAL LIGATURE OE
- {"oelig", 0x00153}, // LATIN SMALL LIGATURE OE
- {"ofcir", 0x029BF}, // CIRCLED BULLET
- {"Ofr", 0x1D512}, // MATHEMATICAL FRAKTUR CAPITAL O
- {"ofr", 0x1D52C}, // MATHEMATICAL FRAKTUR SMALL O
- {"ogon", 0x002DB}, // OGONEK
- {"Ogr", 0x0039F}, // GREEK CAPITAL LETTER OMICRON
- {"ogr", 0x003BF}, // GREEK SMALL LETTER OMICRON
- {"Ograve", 0x000D2}, // LATIN CAPITAL LETTER O WITH GRAVE
- {"ograve", 0x000F2}, // LATIN SMALL LETTER O WITH GRAVE
- {"ogt", 0x029C1}, // CIRCLED GREATER-THAN
- {"OHacgr", 0x0038F}, // GREEK CAPITAL LETTER OMEGA WITH TONOS
- {"ohacgr", 0x003CE}, // GREEK SMALL LETTER OMEGA WITH TONOS
- {"ohbar", 0x029B5}, // CIRCLE WITH HORIZONTAL BAR
- {"OHgr", 0x003A9}, // GREEK CAPITAL LETTER OMEGA
- {"ohgr", 0x003C9}, // GREEK SMALL LETTER OMEGA
- {"ohm", 0x003A9}, // GREEK CAPITAL LETTER OMEGA
- {"oint", 0x0222E}, // CONTOUR INTEGRAL
- {"olarr", 0x021BA}, // ANTICLOCKWISE OPEN CIRCLE ARROW
- {"olcir", 0x029BE}, // CIRCLED WHITE BULLET
- {"olcross", 0x029BB}, // CIRCLE WITH SUPERIMPOSED X
- {"oline", 0x0203E}, // OVERLINE
- {"olt", 0x029C0}, // CIRCLED LESS-THAN
- {"Omacr", 0x0014C}, // LATIN CAPITAL LETTER O WITH MACRON
- {"omacr", 0x0014D}, // LATIN SMALL LETTER O WITH MACRON
- {"Omega", 0x003A9}, // GREEK CAPITAL LETTER OMEGA
- {"omega", 0x003C9}, // GREEK SMALL LETTER OMEGA
- {"Omicron", 0x0039F}, // GREEK CAPITAL LETTER OMICRON
- {"omicron", 0x003BF}, // GREEK SMALL LETTER OMICRON
- {"omid", 0x029B6}, // CIRCLED VERTICAL BAR
- {"ominus", 0x02296}, // CIRCLED MINUS
- {"Oopf", 0x1D546}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL O
- {"oopf", 0x1D560}, // MATHEMATICAL DOUBLE-STRUCK SMALL O
- {"opar", 0x029B7}, // CIRCLED PARALLEL
- {"OpenCurlyDoubleQuote", 0x0201C}, // LEFT DOUBLE QUOTATION MARK
- {"OpenCurlyQuote", 0x02018}, // LEFT SINGLE QUOTATION MARK
- {"operp", 0x029B9}, // CIRCLED PERPENDICULAR
- {"oplus", 0x02295}, // CIRCLED PLUS
- {"or", 0x02228}, // LOGICAL OR
- {"Or", 0x02A54}, // DOUBLE LOGICAL OR
- {"orarr", 0x021BB}, // CLOCKWISE OPEN CIRCLE ARROW
- {"ord", 0x02A5D}, // LOGICAL OR WITH HORIZONTAL DASH
- {"order", 0x02134}, // SCRIPT SMALL O
- {"orderof", 0x02134}, // SCRIPT SMALL O
- {"ordf", 0x000AA}, // FEMININE ORDINAL INDICATOR
- {"ordm", 0x000BA}, // MASCULINE ORDINAL INDICATOR
- {"origof", 0x022B6}, // ORIGINAL OF
- {"oror", 0x02A56}, // TWO INTERSECTING LOGICAL OR
- {"orslope", 0x02A57}, // SLOPING LARGE OR
- {"orv", 0x02A5B}, // LOGICAL OR WITH MIDDLE STEM
- {"oS", 0x024C8}, // CIRCLED LATIN CAPITAL LETTER S
- {"oscr", 0x02134}, // SCRIPT SMALL O
- {"Oscr", 0x1D4AA}, // MATHEMATICAL SCRIPT CAPITAL O
- {"Oslash", 0x000D8}, // LATIN CAPITAL LETTER O WITH STROKE
- {"oslash", 0x000F8}, // LATIN SMALL LETTER O WITH STROKE
- {"osol", 0x02298}, // CIRCLED DIVISION SLASH
- {"Otilde", 0x000D5}, // LATIN CAPITAL LETTER O WITH TILDE
- {"otilde", 0x000F5}, // LATIN SMALL LETTER O WITH TILDE
- {"otimes", 0x02297}, // CIRCLED TIMES
- {"Otimes", 0x02A37}, // MULTIPLICATION SIGN IN DOUBLE CIRCLE
- {"otimesas", 0x02A36}, // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT
- {"Ouml", 0x000D6}, // LATIN CAPITAL LETTER O WITH DIAERESIS
- {"ouml", 0x000F6}, // LATIN SMALL LETTER O WITH DIAERESIS
- {"ovbar", 0x0233D}, // APL FUNCTIONAL SYMBOL CIRCLE STILE
- {"OverBar", 0x0203E}, // OVERLINE
- {"OverBrace", 0x023DE}, // TOP CURLY BRACKET
- {"OverBracket", 0x023B4}, // TOP SQUARE BRACKET
- {"OverParenthesis", 0x023DC}, // TOP PARENTHESIS
- {NULL, 0}
-};
-
-static NameId namesP[]={
- {"par", 0x02225}, // PARALLEL TO
- {"para", 0x000B6}, // PILCROW SIGN
- {"parallel", 0x02225}, // PARALLEL TO
- {"parsim", 0x02AF3}, // PARALLEL WITH TILDE OPERATOR
- {"parsl", 0x02AFD}, // DOUBLE SOLIDUS OPERATOR
- {"part", 0x02202}, // PARTIAL DIFFERENTIAL
- {"PartialD", 0x02202}, // PARTIAL DIFFERENTIAL
- {"Pcy", 0x0041F}, // CYRILLIC CAPITAL LETTER PE
- {"pcy", 0x0043F}, // CYRILLIC SMALL LETTER PE
- {"percnt", 0x00025}, // PERCENT SIGN
- {"period", 0x0002E}, // FULL STOP
- {"permil", 0x02030}, // PER MILLE SIGN
- {"perp", 0x022A5}, // UP TACK
- {"pertenk", 0x02031}, // PER TEN THOUSAND SIGN
- {"Pfr", 0x1D513}, // MATHEMATICAL FRAKTUR CAPITAL P
- {"pfr", 0x1D52D}, // MATHEMATICAL FRAKTUR SMALL P
- {"Pgr", 0x003A0}, // GREEK CAPITAL LETTER PI
- {"pgr", 0x003C0}, // GREEK SMALL LETTER PI
- {"PHgr", 0x003A6}, // GREEK CAPITAL LETTER PHI
- {"phgr", 0x003C6}, // GREEK SMALL LETTER PHI
- {"Phi", 0x003A6}, // GREEK CAPITAL LETTER PHI
- {"phi", 0x003C6}, // GREEK SMALL LETTER PHI
- {"phiv", 0x003D5}, // GREEK PHI SYMBOL
- {"phmmat", 0x02133}, // SCRIPT CAPITAL M
- {"phone", 0x0260E}, // BLACK TELEPHONE
- {"Pi", 0x003A0}, // GREEK CAPITAL LETTER PI
- {"pi", 0x003C0}, // GREEK SMALL LETTER PI
- {"pitchfork", 0x022D4}, // PITCHFORK
- {"piv", 0x003D6}, // GREEK PI SYMBOL
- {"planck", 0x0210F}, // PLANCK CONSTANT OVER TWO PI
- {"planckh", 0x0210E}, // PLANCK CONSTANT
- {"plankv", 0x0210F}, // PLANCK CONSTANT OVER TWO PI
- {"plus", 0x0002B}, // PLUS SIGN
- {"plusacir", 0x02A23}, // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE
- {"plusb", 0x0229E}, // SQUARED PLUS
- {"pluscir", 0x02A22}, // PLUS SIGN WITH SMALL CIRCLE ABOVE
- {"plusdo", 0x02214}, // DOT PLUS
- {"plusdu", 0x02A25}, // PLUS SIGN WITH DOT BELOW
- {"pluse", 0x02A72}, // PLUS SIGN ABOVE EQUALS SIGN
- {"PlusMinus", 0x000B1}, // PLUS-MINUS SIGN
- {"plusmn", 0x000B1}, // PLUS-MINUS SIGN
- {"plussim", 0x02A26}, // PLUS SIGN WITH TILDE BELOW
- {"plustwo", 0x02A27}, // PLUS SIGN WITH SUBSCRIPT TWO
- {"pm", 0x000B1}, // PLUS-MINUS SIGN
- {"Poincareplane", 0x0210C}, // BLACK-LETTER CAPITAL H
- {"pointint", 0x02A15}, // INTEGRAL AROUND A POINT OPERATOR
- {"Popf", 0x02119}, // DOUBLE-STRUCK CAPITAL P
- {"popf", 0x1D561}, // MATHEMATICAL DOUBLE-STRUCK SMALL P
- {"pound", 0x000A3}, // POUND SIGN
- {"pr", 0x0227A}, // PRECEDES
- {"Pr", 0x02ABB}, // DOUBLE PRECEDES
- {"prap", 0x02AB7}, // PRECEDES ABOVE ALMOST EQUAL TO
- {"prcue", 0x0227C}, // PRECEDES OR EQUAL TO
- {"pre", 0x02AAF}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
- {"prE", 0x02AB3}, // PRECEDES ABOVE EQUALS SIGN
- {"prec", 0x0227A}, // PRECEDES
- {"precapprox", 0x02AB7}, // PRECEDES ABOVE ALMOST EQUAL TO
- {"preccurlyeq", 0x0227C}, // PRECEDES OR EQUAL TO
- {"Precedes", 0x0227A}, // PRECEDES
- {"PrecedesEqual", 0x02AAF}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
- {"PrecedesSlantEqual", 0x0227C}, // PRECEDES OR EQUAL TO
- {"PrecedesTilde", 0x0227E}, // PRECEDES OR EQUIVALENT TO
- {"preceq", 0x02AAF}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
- {"precnapprox", 0x02AB9}, // PRECEDES ABOVE NOT ALMOST EQUAL TO
- {"precneqq", 0x02AB5}, // PRECEDES ABOVE NOT EQUAL TO
- {"precnsim", 0x022E8}, // PRECEDES BUT NOT EQUIVALENT TO
- {"precsim", 0x0227E}, // PRECEDES OR EQUIVALENT TO
- {"prime", 0x02032}, // PRIME
- {"Prime", 0x02033}, // DOUBLE PRIME
- {"primes", 0x02119}, // DOUBLE-STRUCK CAPITAL P
- {"prnap", 0x02AB9}, // PRECEDES ABOVE NOT ALMOST EQUAL TO
- {"prnE", 0x02AB5}, // PRECEDES ABOVE NOT EQUAL TO
- {"prnsim", 0x022E8}, // PRECEDES BUT NOT EQUIVALENT TO
- {"prod", 0x0220F}, // N-ARY PRODUCT
- {"Product", 0x0220F}, // N-ARY PRODUCT
- {"profalar", 0x0232E}, // ALL AROUND-PROFILE
- {"profline", 0x02312}, // ARC
- {"profsurf", 0x02313}, // SEGMENT
- {"prop", 0x0221D}, // PROPORTIONAL TO
- {"Proportion", 0x02237}, // PROPORTION
- {"Proportional", 0x0221D}, // PROPORTIONAL TO
- {"propto", 0x0221D}, // PROPORTIONAL TO
- {"prsim", 0x0227E}, // PRECEDES OR EQUIVALENT TO
- {"prurel", 0x022B0}, // PRECEDES UNDER RELATION
- {"Pscr", 0x1D4AB}, // MATHEMATICAL SCRIPT CAPITAL P
- {"pscr", 0x1D4C5}, // MATHEMATICAL SCRIPT SMALL P
- {"PSgr", 0x003A8}, // GREEK CAPITAL LETTER PSI
- {"psgr", 0x003C8}, // GREEK SMALL LETTER PSI
- {"Psi", 0x003A8}, // GREEK CAPITAL LETTER PSI
- {"psi", 0x003C8}, // GREEK SMALL LETTER PSI
- {"puncsp", 0x02008}, // PUNCTUATION SPACE
- {NULL, 0}
-};
-
-static NameId namesQ[]={
- {"Qfr", 0x1D514}, // MATHEMATICAL FRAKTUR CAPITAL Q
- {"qfr", 0x1D52E}, // MATHEMATICAL FRAKTUR SMALL Q
- {"qint", 0x02A0C}, // QUADRUPLE INTEGRAL OPERATOR
- {"Qopf", 0x0211A}, // DOUBLE-STRUCK CAPITAL Q
- {"qopf", 0x1D562}, // MATHEMATICAL DOUBLE-STRUCK SMALL Q
- {"qprime", 0x02057}, // QUADRUPLE PRIME
- {"Qscr", 0x1D4AC}, // MATHEMATICAL SCRIPT CAPITAL Q
- {"qscr", 0x1D4C6}, // MATHEMATICAL SCRIPT SMALL Q
- {"quaternions", 0x0210D}, // DOUBLE-STRUCK CAPITAL H
- {"quatint", 0x02A16}, // QUATERNION INTEGRAL OPERATOR
- {"quest", 0x0003F}, // QUESTION MARK
- {"questeq", 0x0225F}, // QUESTIONED EQUAL TO
- {"quot", 0x00022}, // QUOTATION MARK
- {"QUOT", 0x00022}, // QUOTATION MARK
- {NULL, 0}
-};
-
-static NameId namesR[]={
- {"rAarr", 0x021DB}, // RIGHTWARDS TRIPLE ARROW
-// "race", 0x0223D;0x00331}, // REVERSED TILDE with underline
- {"Racute", 0x00154}, // LATIN CAPITAL LETTER R WITH ACUTE
- {"racute", 0x00155}, // LATIN SMALL LETTER R WITH ACUTE
- {"radic", 0x0221A}, // SQUARE ROOT
- {"raemptyv", 0x029B3}, // EMPTY SET WITH RIGHT ARROW ABOVE
- {"rang", 0x027E9}, // MATHEMATICAL RIGHT ANGLE BRACKET
- {"Rang", 0x027EB}, // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
- {"rangd", 0x02992}, // RIGHT ANGLE BRACKET WITH DOT
- {"range", 0x029A5}, // REVERSED ANGLE WITH UNDERBAR
- {"rangle", 0x027E9}, // MATHEMATICAL RIGHT ANGLE BRACKET
- {"raquo", 0x000BB}, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
- {"rarr", 0x02192}, // RIGHTWARDS ARROW
- {"Rarr", 0x021A0}, // RIGHTWARDS TWO HEADED ARROW
- {"rArr", 0x021D2}, // RIGHTWARDS DOUBLE ARROW
- {"rarrap", 0x02975}, // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO
- {"rarrb", 0x021E5}, // RIGHTWARDS ARROW TO BAR
- {"rarrbfs", 0x02920}, // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND
- {"rarrc", 0x02933}, // WAVE ARROW POINTING DIRECTLY RIGHT
- {"rarrfs", 0x0291E}, // RIGHTWARDS ARROW TO BLACK DIAMOND
- {"rarrhk", 0x021AA}, // RIGHTWARDS ARROW WITH HOOK
- {"rarrlp", 0x021AC}, // RIGHTWARDS ARROW WITH LOOP
- {"rarrpl", 0x02945}, // RIGHTWARDS ARROW WITH PLUS BELOW
- {"rarrsim", 0x02974}, // RIGHTWARDS ARROW ABOVE TILDE OPERATOR
- {"rarrtl", 0x021A3}, // RIGHTWARDS ARROW WITH TAIL
- {"Rarrtl", 0x02916}, // RIGHTWARDS TWO-HEADED ARROW WITH TAIL
- {"rarrw", 0x0219D}, // RIGHTWARDS WAVE ARROW
- {"ratail", 0x0291A}, // RIGHTWARDS ARROW-TAIL
- {"rAtail", 0x0291C}, // RIGHTWARDS DOUBLE ARROW-TAIL
- {"ratio", 0x02236}, // RATIO
- {"rationals", 0x0211A}, // DOUBLE-STRUCK CAPITAL Q
- {"rbarr", 0x0290D}, // RIGHTWARDS DOUBLE DASH ARROW
- {"rBarr", 0x0290F}, // RIGHTWARDS TRIPLE DASH ARROW
- {"RBarr", 0x02910}, // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW
- {"rbbrk", 0x02773}, // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
- {"rbrace", 0x0007D}, // RIGHT CURLY BRACKET
- {"rbrack", 0x0005D}, // RIGHT SQUARE BRACKET
- {"rbrke", 0x0298C}, // RIGHT SQUARE BRACKET WITH UNDERBAR
- {"rbrksld", 0x0298E}, // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
- {"rbrkslu", 0x02990}, // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
- {"Rcaron", 0x00158}, // LATIN CAPITAL LETTER R WITH CARON
- {"rcaron", 0x00159}, // LATIN SMALL LETTER R WITH CARON
- {"Rcedil", 0x00156}, // LATIN CAPITAL LETTER R WITH CEDILLA
- {"rcedil", 0x00157}, // LATIN SMALL LETTER R WITH CEDILLA
- {"rceil", 0x02309}, // RIGHT CEILING
- {"rcub", 0x0007D}, // RIGHT CURLY BRACKET
- {"Rcy", 0x00420}, // CYRILLIC CAPITAL LETTER ER
- {"rcy", 0x00440}, // CYRILLIC SMALL LETTER ER
- {"rdca", 0x02937}, // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS
- {"rdldhar", 0x02969}, // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN
- {"rdquo", 0x0201D}, // RIGHT DOUBLE QUOTATION MARK
- {"rdquor", 0x0201D}, // RIGHT DOUBLE QUOTATION MARK
- {"rdsh", 0x021B3}, // DOWNWARDS ARROW WITH TIP RIGHTWARDS
- {"Re", 0x0211C}, // BLACK-LETTER CAPITAL R
- {"real", 0x0211C}, // BLACK-LETTER CAPITAL R
- {"realine", 0x0211B}, // SCRIPT CAPITAL R
- {"realpart", 0x0211C}, // BLACK-LETTER CAPITAL R
- {"reals", 0x0211D}, // DOUBLE-STRUCK CAPITAL R
- {"rect", 0x025AD}, // WHITE RECTANGLE
- {"reg", 0x000AE}, // REGISTERED SIGN
- {"REG", 0x000AE}, // REGISTERED SIGN
- {"ReverseElement", 0x0220B}, // CONTAINS AS MEMBER
- {"ReverseEquilibrium", 0x021CB}, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
- {"ReverseUpEquilibrium", 0x0296F}, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
- {"rfisht", 0x0297D}, // RIGHT FISH TAIL
- {"rfloor", 0x0230B}, // RIGHT FLOOR
- {"Rfr", 0x0211C}, // BLACK-LETTER CAPITAL R
- {"rfr", 0x1D52F}, // MATHEMATICAL FRAKTUR SMALL R
- {"Rgr", 0x003A1}, // GREEK CAPITAL LETTER RHO
- {"rgr", 0x003C1}, // GREEK SMALL LETTER RHO
- {"rHar", 0x02964}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN
- {"rhard", 0x021C1}, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
- {"rharu", 0x021C0}, // RIGHTWARDS HARPOON WITH BARB UPWARDS
- {"rharul", 0x0296C}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH
- {"Rho", 0x003A1}, // GREEK CAPITAL LETTER RHO
- {"rho", 0x003C1}, // GREEK SMALL LETTER RHO
- {"rhov", 0x003F1}, // GREEK RHO SYMBOL
- {"RightAngleBracket", 0x027E9}, // MATHEMATICAL RIGHT ANGLE BRACKET
- {"rightarrow", 0x02192}, // RIGHTWARDS ARROW
- {"RightArrow", 0x02192}, // RIGHTWARDS ARROW
- {"Rightarrow", 0x021D2}, // RIGHTWARDS DOUBLE ARROW
- {"RightArrowBar", 0x021E5}, // RIGHTWARDS ARROW TO BAR
- {"RightArrowLeftArrow", 0x021C4}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
- {"rightarrowtail", 0x021A3}, // RIGHTWARDS ARROW WITH TAIL
- {"RightCeiling", 0x02309}, // RIGHT CEILING
- {"RightDoubleBracket", 0x027E7}, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET
- {"RightDownTeeVector", 0x0295D}, // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR
- {"RightDownVector", 0x021C2}, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
- {"RightDownVectorBar", 0x02955}, // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR
- {"RightFloor", 0x0230B}, // RIGHT FLOOR
- {"rightharpoondown", 0x021C1}, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
- {"rightharpoonup", 0x021C0}, // RIGHTWARDS HARPOON WITH BARB UPWARDS
- {"rightleftarrows", 0x021C4}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
- {"rightleftharpoons", 0x021CC}, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
- {"rightrightarrows", 0x021C9}, // RIGHTWARDS PAIRED ARROWS
- {"rightsquigarrow", 0x0219D}, // RIGHTWARDS WAVE ARROW
- {"RightTee", 0x022A2}, // RIGHT TACK
- {"RightTeeArrow", 0x021A6}, // RIGHTWARDS ARROW FROM BAR
- {"RightTeeVector", 0x0295B}, // RIGHTWARDS HARPOON WITH BARB UP FROM BAR
- {"rightthreetimes", 0x022CC}, // RIGHT SEMIDIRECT PRODUCT
- {"RightTriangle", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP
- {"RightTriangleBar", 0x029D0}, // VERTICAL BAR BESIDE RIGHT TRIANGLE
- {"RightTriangleEqual", 0x022B5}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
- {"RightUpDownVector", 0x0294F}, // UP BARB RIGHT DOWN BARB RIGHT HARPOON
- {"RightUpTeeVector", 0x0295C}, // UPWARDS HARPOON WITH BARB RIGHT FROM BAR
- {"RightUpVector", 0x021BE}, // UPWARDS HARPOON WITH BARB RIGHTWARDS
- {"RightUpVectorBar", 0x02954}, // UPWARDS HARPOON WITH BARB RIGHT TO BAR
- {"RightVector", 0x021C0}, // RIGHTWARDS HARPOON WITH BARB UPWARDS
- {"RightVectorBar", 0x02953}, // RIGHTWARDS HARPOON WITH BARB UP TO BAR
- {"ring", 0x002DA}, // RING ABOVE
- {"risingdotseq", 0x02253}, // IMAGE OF OR APPROXIMATELY EQUAL TO
- {"rlarr", 0x021C4}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
- {"rlhar", 0x021CC}, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
- {"rlm", 0x0200F}, // RIGHT-TO-LEFT MARK
- {"rmoust", 0x023B1}, // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION
- {"rmoustache", 0x023B1}, // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION
- {"rnmid", 0x02AEE}, // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH
- {"roang", 0x027ED}, // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
- {"roarr", 0x021FE}, // RIGHTWARDS OPEN-HEADED ARROW
- {"robrk", 0x027E7}, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET
- {"ropar", 0x02986}, // RIGHT WHITE PARENTHESIS
- {"Ropf", 0x0211D}, // DOUBLE-STRUCK CAPITAL R
- {"ropf", 0x1D563}, // MATHEMATICAL DOUBLE-STRUCK SMALL R
- {"roplus", 0x02A2E}, // PLUS SIGN IN RIGHT HALF CIRCLE
- {"rotimes", 0x02A35}, // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE
- {"RoundImplies", 0x02970}, // RIGHT DOUBLE ARROW WITH ROUNDED HEAD
- {"rpar", 0x00029}, // RIGHT PARENTHESIS
- {"rpargt", 0x02994}, // RIGHT ARC GREATER-THAN BRACKET
- {"rppolint", 0x02A12}, // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE
- {"rrarr", 0x021C9}, // RIGHTWARDS PAIRED ARROWS
- {"Rrightarrow", 0x021DB}, // RIGHTWARDS TRIPLE ARROW
- {"rsaquo", 0x0203A}, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
- {"Rscr", 0x0211B}, // SCRIPT CAPITAL R
- {"rscr", 0x1D4C7}, // MATHEMATICAL SCRIPT SMALL R
- {"rsh", 0x021B1}, // UPWARDS ARROW WITH TIP RIGHTWARDS
- {"Rsh", 0x021B1}, // UPWARDS ARROW WITH TIP RIGHTWARDS
- {"rsqb", 0x0005D}, // RIGHT SQUARE BRACKET
- {"rsquo", 0x02019}, // RIGHT SINGLE QUOTATION MARK
- {"rsquor", 0x02019}, // RIGHT SINGLE QUOTATION MARK
- {"rthree", 0x022CC}, // RIGHT SEMIDIRECT PRODUCT
- {"rtimes", 0x022CA}, // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT
- {"rtri", 0x025B9}, // WHITE RIGHT-POINTING SMALL TRIANGLE
- {"rtrie", 0x022B5}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
- {"rtrif", 0x025B8}, // BLACK RIGHT-POINTING SMALL TRIANGLE
- {"rtriltri", 0x029CE}, // RIGHT TRIANGLE ABOVE LEFT TRIANGLE
- {"RuleDelayed", 0x029F4}, // RULE-DELAYED
- {"ruluhar", 0x02968}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP
- {"rx", 0x0211E}, // PRESCRIPTION TAKE
- {NULL, 0}
-};
-
-static NameId namesS[]={
- {"Sacute", 0x0015A}, // LATIN CAPITAL LETTER S WITH ACUTE
- {"sacute", 0x0015B}, // LATIN SMALL LETTER S WITH ACUTE
- {"sbquo", 0x0201A}, // SINGLE LOW-9 QUOTATION MARK
- {"sc", 0x0227B}, // SUCCEEDS
- {"Sc", 0x02ABC}, // DOUBLE SUCCEEDS
- {"scap", 0x02AB8}, // SUCCEEDS ABOVE ALMOST EQUAL TO
- {"Scaron", 0x00160}, // LATIN CAPITAL LETTER S WITH CARON
- {"scaron", 0x00161}, // LATIN SMALL LETTER S WITH CARON
- {"sccue", 0x0227D}, // SUCCEEDS OR EQUAL TO
- {"sce", 0x02AB0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
- {"scE", 0x02AB4}, // SUCCEEDS ABOVE EQUALS SIGN
- {"Scedil", 0x0015E}, // LATIN CAPITAL LETTER S WITH CEDILLA
- {"scedil", 0x0015F}, // LATIN SMALL LETTER S WITH CEDILLA
- {"Scirc", 0x0015C}, // LATIN CAPITAL LETTER S WITH CIRCUMFLEX
- {"scirc", 0x0015D}, // LATIN SMALL LETTER S WITH CIRCUMFLEX
- {"scnap", 0x02ABA}, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO
- {"scnE", 0x02AB6}, // SUCCEEDS ABOVE NOT EQUAL TO
- {"scnsim", 0x022E9}, // SUCCEEDS BUT NOT EQUIVALENT TO
- {"scpolint", 0x02A13}, // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE
- {"scsim", 0x0227F}, // SUCCEEDS OR EQUIVALENT TO
- {"Scy", 0x00421}, // CYRILLIC CAPITAL LETTER ES
- {"scy", 0x00441}, // CYRILLIC SMALL LETTER ES
- {"sdot", 0x022C5}, // DOT OPERATOR
- {"sdotb", 0x022A1}, // SQUARED DOT OPERATOR
- {"sdote", 0x02A66}, // EQUALS SIGN WITH DOT BELOW
- {"searhk", 0x02925}, // SOUTH EAST ARROW WITH HOOK
- {"searr", 0x02198}, // SOUTH EAST ARROW
- {"seArr", 0x021D8}, // SOUTH EAST DOUBLE ARROW
- {"searrow", 0x02198}, // SOUTH EAST ARROW
- {"sect", 0x000A7}, // SECTION SIGN
- {"semi", 0x0003B}, // SEMICOLON
- {"seswar", 0x02929}, // SOUTH EAST ARROW AND SOUTH WEST ARROW
- {"setminus", 0x02216}, // SET MINUS
- {"setmn", 0x02216}, // SET MINUS
- {"sext", 0x02736}, // SIX POINTED BLACK STAR
- {"sfgr", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
- {"Sfr", 0x1D516}, // MATHEMATICAL FRAKTUR CAPITAL S
- {"sfr", 0x1D530}, // MATHEMATICAL FRAKTUR SMALL S
- {"sfrown", 0x02322}, // FROWN
- {"Sgr", 0x003A3}, // GREEK CAPITAL LETTER SIGMA
- {"sgr", 0x003C3}, // GREEK SMALL LETTER SIGMA
- {"sharp", 0x0266F}, // MUSIC SHARP SIGN
- {"SHCHcy", 0x00429}, // CYRILLIC CAPITAL LETTER SHCHA
- {"shchcy", 0x00449}, // CYRILLIC SMALL LETTER SHCHA
- {"SHcy", 0x00428}, // CYRILLIC CAPITAL LETTER SHA
- {"shcy", 0x00448}, // CYRILLIC SMALL LETTER SHA
- {"ShortDownArrow", 0x02193}, // DOWNWARDS ARROW
- {"ShortLeftArrow", 0x02190}, // LEFTWARDS ARROW
- {"shortmid", 0x02223}, // DIVIDES
- {"shortparallel", 0x02225}, // PARALLEL TO
- {"ShortRightArrow", 0x02192}, // RIGHTWARDS ARROW
- {"ShortUpArrow", 0x02191}, // UPWARDS ARROW
- {"shy", 0x000AD}, // SOFT HYPHEN
- {"Sigma", 0x003A3}, // GREEK CAPITAL LETTER SIGMA
- {"sigma", 0x003C3}, // GREEK SMALL LETTER SIGMA
- {"sigmaf", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
- {"sigmav", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
- {"sim", 0x0223C}, // TILDE OPERATOR
- {"simdot", 0x02A6A}, // TILDE OPERATOR WITH DOT ABOVE
- {"sime", 0x02243}, // ASYMPTOTICALLY EQUAL TO
- {"simeq", 0x02243}, // ASYMPTOTICALLY EQUAL TO
- {"simg", 0x02A9E}, // SIMILAR OR GREATER-THAN
- {"simgE", 0x02AA0}, // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN
- {"siml", 0x02A9D}, // SIMILAR OR LESS-THAN
- {"simlE", 0x02A9F}, // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN
- {"simne", 0x02246}, // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO
- {"simplus", 0x02A24}, // PLUS SIGN WITH TILDE ABOVE
- {"simrarr", 0x02972}, // TILDE OPERATOR ABOVE RIGHTWARDS ARROW
- {"slarr", 0x02190}, // LEFTWARDS ARROW
- {"SmallCircle", 0x02218}, // RING OPERATOR
- {"smallsetminus", 0x02216}, // SET MINUS
- {"smashp", 0x02A33}, // SMASH PRODUCT
- {"smeparsl", 0x029E4}, // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE
- {"smid", 0x02223}, // DIVIDES
- {"smile", 0x02323}, // SMILE
- {"smt", 0x02AAA}, // SMALLER THAN
- {"smte", 0x02AAC}, // SMALLER THAN OR EQUAL TO
-// "smtes", 0x02AAC;0x0FE00}, // SMALLER THAN OR slanted EQUAL
- {"SOFTcy", 0x0042C}, // CYRILLIC CAPITAL LETTER SOFT SIGN
- {"softcy", 0x0044C}, // CYRILLIC SMALL LETTER SOFT SIGN
- {"sol", 0x0002F}, // SOLIDUS
- {"solb", 0x029C4}, // SQUARED RISING DIAGONAL SLASH
- {"solbar", 0x0233F}, // APL FUNCTIONAL SYMBOL SLASH BAR
- {"Sopf", 0x1D54A}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL S
- {"sopf", 0x1D564}, // MATHEMATICAL DOUBLE-STRUCK SMALL S
- {"spades", 0x02660}, // BLACK SPADE SUIT
- {"spadesuit", 0x02660}, // BLACK SPADE SUIT
- {"spar", 0x02225}, // PARALLEL TO
- {"sqcap", 0x02293}, // SQUARE CAP
-// "sqcaps", 0x02293;0x0FE00}, // SQUARE CAP with serifs
- {"sqcup", 0x02294}, // SQUARE CUP
-// "sqcups", 0x02294;0x0FE00}, // SQUARE CUP with serifs
- {"Sqrt", 0x0221A}, // SQUARE ROOT
- {"sqsub", 0x0228F}, // SQUARE IMAGE OF
- {"sqsube", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO
- {"sqsubset", 0x0228F}, // SQUARE IMAGE OF
- {"sqsubseteq", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO
- {"sqsup", 0x02290}, // SQUARE ORIGINAL OF
- {"sqsupe", 0x02292}, // SQUARE ORIGINAL OF OR EQUAL TO
- {"sqsupset", 0x02290}, // SQUARE ORIGINAL OF
- {"sqsupseteq", 0x02292}, // SQUARE ORIGINAL OF OR EQUAL TO
- {"squ", 0x025A1}, // WHITE SQUARE
- {"square", 0x025A1}, // WHITE SQUARE
- {"Square", 0x025A1}, // WHITE SQUARE
- {"SquareIntersection", 0x02293}, // SQUARE CAP
- {"SquareSubset", 0x0228F}, // SQUARE IMAGE OF
- {"SquareSubsetEqual", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO
- {"SquareSuperset", 0x02290}, // SQUARE ORIGINAL OF
- {"SquareSupersetEqual", 0x02292}, // SQUARE ORIGINAL OF OR EQUAL TO
- {"SquareUnion", 0x02294}, // SQUARE CUP
- {"squarf", 0x025AA}, // BLACK SMALL SQUARE
- {"squf", 0x025AA}, // BLACK SMALL SQUARE
- {"srarr", 0x02192}, // RIGHTWARDS ARROW
- {"Sscr", 0x1D4AE}, // MATHEMATICAL SCRIPT CAPITAL S
- {"sscr", 0x1D4C8}, // MATHEMATICAL SCRIPT SMALL S
- {"ssetmn", 0x02216}, // SET MINUS
- {"ssmile", 0x02323}, // SMILE
- {"sstarf", 0x022C6}, // STAR OPERATOR
- {"Star", 0x022C6}, // STAR OPERATOR
- {"star", 0x02606}, // WHITE STAR
- {"starf", 0x02605}, // BLACK STAR
- {"straightepsilon", 0x003F5}, // GREEK LUNATE EPSILON SYMBOL
- {"straightphi", 0x003D5}, // GREEK PHI SYMBOL
- {"strns", 0x000AF}, // MACRON
- {"sub", 0x02282}, // SUBSET OF
- {"Sub", 0x022D0}, // DOUBLE SUBSET
- {"subdot", 0x02ABD}, // SUBSET WITH DOT
- {"sube", 0x02286}, // SUBSET OF OR EQUAL TO
- {"subE", 0x02AC5}, // SUBSET OF ABOVE EQUALS SIGN
- {"subedot", 0x02AC3}, // SUBSET OF OR EQUAL TO WITH DOT ABOVE
- {"submult", 0x02AC1}, // SUBSET WITH MULTIPLICATION SIGN BELOW
- {"subne", 0x0228A}, // SUBSET OF WITH NOT EQUAL TO
- {"subnE", 0x02ACB}, // SUBSET OF ABOVE NOT EQUAL TO
- {"subplus", 0x02ABF}, // SUBSET WITH PLUS SIGN BELOW
- {"subrarr", 0x02979}, // SUBSET ABOVE RIGHTWARDS ARROW
- {"subset", 0x02282}, // SUBSET OF
- {"Subset", 0x022D0}, // DOUBLE SUBSET
- {"subseteq", 0x02286}, // SUBSET OF OR EQUAL TO
- {"subseteqq", 0x02AC5}, // SUBSET OF ABOVE EQUALS SIGN
- {"SubsetEqual", 0x02286}, // SUBSET OF OR EQUAL TO
- {"subsetneq", 0x0228A}, // SUBSET OF WITH NOT EQUAL TO
- {"subsetneqq", 0x02ACB}, // SUBSET OF ABOVE NOT EQUAL TO
- {"subsim", 0x02AC7}, // SUBSET OF ABOVE TILDE OPERATOR
- {"subsub", 0x02AD5}, // SUBSET ABOVE SUBSET
- {"subsup", 0x02AD3}, // SUBSET ABOVE SUPERSET
- {"succ", 0x0227B}, // SUCCEEDS
- {"succapprox", 0x02AB8}, // SUCCEEDS ABOVE ALMOST EQUAL TO
- {"succcurlyeq", 0x0227D}, // SUCCEEDS OR EQUAL TO
- {"Succeeds", 0x0227B}, // SUCCEEDS
- {"SucceedsEqual", 0x02AB0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
- {"SucceedsSlantEqual", 0x0227D}, // SUCCEEDS OR EQUAL TO
- {"SucceedsTilde", 0x0227F}, // SUCCEEDS OR EQUIVALENT TO
- {"succeq", 0x02AB0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
- {"succnapprox", 0x02ABA}, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO
- {"succneqq", 0x02AB6}, // SUCCEEDS ABOVE NOT EQUAL TO
- {"succnsim", 0x022E9}, // SUCCEEDS BUT NOT EQUIVALENT TO
- {"succsim", 0x0227F}, // SUCCEEDS OR EQUIVALENT TO
- {"SuchThat", 0x0220B}, // CONTAINS AS MEMBER
- {"sum", 0x02211}, // N-ARY SUMMATION
- {"Sum", 0x02211}, // N-ARY SUMMATION
- {"sung", 0x0266A}, // EIGHTH NOTE
- {"sup", 0x02283}, // SUPERSET OF
- {"Sup", 0x022D1}, // DOUBLE SUPERSET
- {"sup1", 0x000B9}, // SUPERSCRIPT ONE
- {"sup2", 0x000B2}, // SUPERSCRIPT TWO
- {"sup3", 0x000B3}, // SUPERSCRIPT THREE
- {"supdot", 0x02ABE}, // SUPERSET WITH DOT
- {"supdsub", 0x02AD8}, // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET
- {"supe", 0x02287}, // SUPERSET OF OR EQUAL TO
- {"supE", 0x02AC6}, // SUPERSET OF ABOVE EQUALS SIGN
- {"supedot", 0x02AC4}, // SUPERSET OF OR EQUAL TO WITH DOT ABOVE
- {"Superset", 0x02283}, // SUPERSET OF
- {"SupersetEqual", 0x02287}, // SUPERSET OF OR EQUAL TO
- {"suphsol", 0x027C9}, // SUPERSET PRECEDING SOLIDUS
- {"suphsub", 0x02AD7}, // SUPERSET BESIDE SUBSET
- {"suplarr", 0x0297B}, // SUPERSET ABOVE LEFTWARDS ARROW
- {"supmult", 0x02AC2}, // SUPERSET WITH MULTIPLICATION SIGN BELOW
- {"supne", 0x0228B}, // SUPERSET OF WITH NOT EQUAL TO
- {"supnE", 0x02ACC}, // SUPERSET OF ABOVE NOT EQUAL TO
- {"supplus", 0x02AC0}, // SUPERSET WITH PLUS SIGN BELOW
- {"supset", 0x02283}, // SUPERSET OF
- {"Supset", 0x022D1}, // DOUBLE SUPERSET
- {"supseteq", 0x02287}, // SUPERSET OF OR EQUAL TO
- {"supseteqq", 0x02AC6}, // SUPERSET OF ABOVE EQUALS SIGN
- {"supsetneq", 0x0228B}, // SUPERSET OF WITH NOT EQUAL TO
- {"supsetneqq", 0x02ACC}, // SUPERSET OF ABOVE NOT EQUAL TO
- {"supsim", 0x02AC8}, // SUPERSET OF ABOVE TILDE OPERATOR
- {"supsub", 0x02AD4}, // SUPERSET ABOVE SUBSET
- {"supsup", 0x02AD6}, // SUPERSET ABOVE SUPERSET
- {"swarhk", 0x02926}, // SOUTH WEST ARROW WITH HOOK
- {"swarr", 0x02199}, // SOUTH WEST ARROW
- {"swArr", 0x021D9}, // SOUTH WEST DOUBLE ARROW
- {"swarrow", 0x02199}, // SOUTH WEST ARROW
- {"swnwar", 0x0292A}, // SOUTH WEST ARROW AND NORTH WEST ARROW
- {"szlig", 0x000DF}, // LATIN SMALL LETTER SHARP S
- {NULL, 0}
-};
-
-static NameId namesT[]={
- {"Tab", 0x00009}, // CHARACTER TABULATION
- {"target", 0x02316}, // POSITION INDICATOR
- {"Tau", 0x003A4}, // GREEK CAPITAL LETTER TAU
- {"tau", 0x003C4}, // GREEK SMALL LETTER TAU
- {"tbrk", 0x023B4}, // TOP SQUARE BRACKET
- {"Tcaron", 0x00164}, // LATIN CAPITAL LETTER T WITH CARON
- {"tcaron", 0x00165}, // LATIN SMALL LETTER T WITH CARON
- {"Tcedil", 0x00162}, // LATIN CAPITAL LETTER T WITH CEDILLA
- {"tcedil", 0x00163}, // LATIN SMALL LETTER T WITH CEDILLA
- {"Tcy", 0x00422}, // CYRILLIC CAPITAL LETTER TE
- {"tcy", 0x00442}, // CYRILLIC SMALL LETTER TE
- {"tdot", 0x020DB}, // COMBINING THREE DOTS ABOVE
- {"telrec", 0x02315}, // TELEPHONE RECORDER
- {"Tfr", 0x1D517}, // MATHEMATICAL FRAKTUR CAPITAL T
- {"tfr", 0x1D531}, // MATHEMATICAL FRAKTUR SMALL T
- {"Tgr", 0x003A4}, // GREEK CAPITAL LETTER TAU
- {"tgr", 0x003C4}, // GREEK SMALL LETTER TAU
- {"there4", 0x02234}, // THEREFORE
- {"therefore", 0x02234}, // THEREFORE
- {"Therefore", 0x02234}, // THEREFORE
- {"Theta", 0x00398}, // GREEK CAPITAL LETTER THETA
- {"theta", 0x003B8}, // GREEK SMALL LETTER THETA
- {"thetasym", 0x003D1}, // GREEK THETA SYMBOL
- {"thetav", 0x003D1}, // GREEK THETA SYMBOL
- {"THgr", 0x00398}, // GREEK CAPITAL LETTER THETA
- {"thgr", 0x003B8}, // GREEK SMALL LETTER THETA
- {"thickapprox", 0x02248}, // ALMOST EQUAL TO
- {"thicksim", 0x0223C}, // TILDE OPERATOR
-// "ThickSpace", 0x0205F;0x0200A}, // space of width 5/18 em
- {"thinsp", 0x02009}, // THIN SPACE
- {"ThinSpace", 0x02009}, // THIN SPACE
- {"thkap", 0x02248}, // ALMOST EQUAL TO
- {"thksim", 0x0223C}, // TILDE OPERATOR
- {"THORN", 0x000DE}, // LATIN CAPITAL LETTER THORN
- {"thorn", 0x000FE}, // LATIN SMALL LETTER THORN
- {"tilde", 0x002DC}, // SMALL TILDE
- {"Tilde", 0x0223C}, // TILDE OPERATOR
- {"TildeEqual", 0x02243}, // ASYMPTOTICALLY EQUAL TO
- {"TildeFullEqual", 0x02245}, // APPROXIMATELY EQUAL TO
- {"TildeTilde", 0x02248}, // ALMOST EQUAL TO
- {"times", 0x000D7}, // MULTIPLICATION SIGN
- {"timesb", 0x022A0}, // SQUARED TIMES
- {"timesbar", 0x02A31}, // MULTIPLICATION SIGN WITH UNDERBAR
- {"timesd", 0x02A30}, // MULTIPLICATION SIGN WITH DOT ABOVE
- {"tint", 0x0222D}, // TRIPLE INTEGRAL
- {"toea", 0x02928}, // NORTH EAST ARROW AND SOUTH EAST ARROW
- {"top", 0x022A4}, // DOWN TACK
- {"topbot", 0x02336}, // APL FUNCTIONAL SYMBOL I-BEAM
- {"topcir", 0x02AF1}, // DOWN TACK WITH CIRCLE BELOW
- {"Topf", 0x1D54B}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL T
- {"topf", 0x1D565}, // MATHEMATICAL DOUBLE-STRUCK SMALL T
- {"topfork", 0x02ADA}, // PITCHFORK WITH TEE TOP
- {"tosa", 0x02929}, // SOUTH EAST ARROW AND SOUTH WEST ARROW
- {"tprime", 0x02034}, // TRIPLE PRIME
- {"trade", 0x02122}, // TRADE MARK SIGN
- {"TRADE", 0x02122}, // TRADE MARK SIGN
- {"triangle", 0x025B5}, // WHITE UP-POINTING SMALL TRIANGLE
- {"triangledown", 0x025BF}, // WHITE DOWN-POINTING SMALL TRIANGLE
- {"triangleleft", 0x025C3}, // WHITE LEFT-POINTING SMALL TRIANGLE
- {"trianglelefteq", 0x022B4}, // NORMAL SUBGROUP OF OR EQUAL TO
- {"triangleq", 0x0225C}, // DELTA EQUAL TO
- {"triangleright", 0x025B9}, // WHITE RIGHT-POINTING SMALL TRIANGLE
- {"trianglerighteq", 0x022B5}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
- {"tridot", 0x025EC}, // WHITE UP-POINTING TRIANGLE WITH DOT
- {"trie", 0x0225C}, // DELTA EQUAL TO
- {"triminus", 0x02A3A}, // MINUS SIGN IN TRIANGLE
- {"TripleDot", 0x020DB}, // COMBINING THREE DOTS ABOVE
- {"triplus", 0x02A39}, // PLUS SIGN IN TRIANGLE
- {"trisb", 0x029CD}, // TRIANGLE WITH SERIFS AT BOTTOM
- {"tritime", 0x02A3B}, // MULTIPLICATION SIGN IN TRIANGLE
- {"trpezium", 0x023E2}, // WHITE TRAPEZIUM
- {"Tscr", 0x1D4AF}, // MATHEMATICAL SCRIPT CAPITAL T
- {"tscr", 0x1D4C9}, // MATHEMATICAL SCRIPT SMALL T
- {"TScy", 0x00426}, // CYRILLIC CAPITAL LETTER TSE
- {"tscy", 0x00446}, // CYRILLIC SMALL LETTER TSE
- {"TSHcy", 0x0040B}, // CYRILLIC CAPITAL LETTER TSHE
- {"tshcy", 0x0045B}, // CYRILLIC SMALL LETTER TSHE
- {"Tstrok", 0x00166}, // LATIN CAPITAL LETTER T WITH STROKE
- {"tstrok", 0x00167}, // LATIN SMALL LETTER T WITH STROKE
- {"twixt", 0x0226C}, // BETWEEN
- {"twoheadleftarrow", 0x0219E}, // LEFTWARDS TWO HEADED ARROW
- {"twoheadrightarrow", 0x021A0}, // RIGHTWARDS TWO HEADED ARROW
- {NULL, 0}
-};
-
-static NameId namesU[]={
- {"Uacgr", 0x0038E}, // GREEK CAPITAL LETTER UPSILON WITH TONOS
- {"uacgr", 0x003CD}, // GREEK SMALL LETTER UPSILON WITH TONOS
- {"Uacute", 0x000DA}, // LATIN CAPITAL LETTER U WITH ACUTE
- {"uacute", 0x000FA}, // LATIN SMALL LETTER U WITH ACUTE
- {"uarr", 0x02191}, // UPWARDS ARROW
- {"Uarr", 0x0219F}, // UPWARDS TWO HEADED ARROW
- {"uArr", 0x021D1}, // UPWARDS DOUBLE ARROW
- {"Uarrocir", 0x02949}, // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE
- {"Ubrcy", 0x0040E}, // CYRILLIC CAPITAL LETTER SHORT U
- {"ubrcy", 0x0045E}, // CYRILLIC SMALL LETTER SHORT U
- {"Ubreve", 0x0016C}, // LATIN CAPITAL LETTER U WITH BREVE
- {"ubreve", 0x0016D}, // LATIN SMALL LETTER U WITH BREVE
- {"Ucirc", 0x000DB}, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX
- {"ucirc", 0x000FB}, // LATIN SMALL LETTER U WITH CIRCUMFLEX
- {"Ucy", 0x00423}, // CYRILLIC CAPITAL LETTER U
- {"ucy", 0x00443}, // CYRILLIC SMALL LETTER U
- {"udarr", 0x021C5}, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW
- {"Udblac", 0x00170}, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
- {"udblac", 0x00171}, // LATIN SMALL LETTER U WITH DOUBLE ACUTE
- {"udhar", 0x0296E}, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
- {"udiagr", 0x003B0}, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
- {"Udigr", 0x003AB}, // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
- {"udigr", 0x003CB}, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA
- {"ufisht", 0x0297E}, // UP FISH TAIL
- {"Ufr", 0x1D518}, // MATHEMATICAL FRAKTUR CAPITAL U
- {"ufr", 0x1D532}, // MATHEMATICAL FRAKTUR SMALL U
- {"Ugr", 0x003A5}, // GREEK CAPITAL LETTER UPSILON
- {"ugr", 0x003C5}, // GREEK SMALL LETTER UPSILON
- {"Ugrave", 0x000D9}, // LATIN CAPITAL LETTER U WITH GRAVE
- {"ugrave", 0x000F9}, // LATIN SMALL LETTER U WITH GRAVE
- {"uHar", 0x02963}, // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
- {"uharl", 0x021BF}, // UPWARDS HARPOON WITH BARB LEFTWARDS
- {"uharr", 0x021BE}, // UPWARDS HARPOON WITH BARB RIGHTWARDS
- {"uhblk", 0x02580}, // UPPER HALF BLOCK
- {"ulcorn", 0x0231C}, // TOP LEFT CORNER
- {"ulcorner", 0x0231C}, // TOP LEFT CORNER
- {"ulcrop", 0x0230F}, // TOP LEFT CROP
- {"ultri", 0x025F8}, // UPPER LEFT TRIANGLE
- {"Umacr", 0x0016A}, // LATIN CAPITAL LETTER U WITH MACRON
- {"umacr", 0x0016B}, // LATIN SMALL LETTER U WITH MACRON
- {"uml", 0x000A8}, // DIAERESIS
- {"UnderBar", 0x0005F}, // LOW LINE
- {"UnderBrace", 0x023DF}, // BOTTOM CURLY BRACKET
- {"UnderBracket", 0x023B5}, // BOTTOM SQUARE BRACKET
- {"UnderParenthesis", 0x023DD}, // BOTTOM PARENTHESIS
- {"Union", 0x022C3}, // N-ARY UNION
- {"UnionPlus", 0x0228E}, // MULTISET UNION
- {"Uogon", 0x00172}, // LATIN CAPITAL LETTER U WITH OGONEK
- {"uogon", 0x00173}, // LATIN SMALL LETTER U WITH OGONEK
- {"Uopf", 0x1D54C}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL U
- {"uopf", 0x1D566}, // MATHEMATICAL DOUBLE-STRUCK SMALL U
- {"uparrow", 0x02191}, // UPWARDS ARROW
- {"UpArrow", 0x02191}, // UPWARDS ARROW
- {"Uparrow", 0x021D1}, // UPWARDS DOUBLE ARROW
- {"UpArrowBar", 0x02912}, // UPWARDS ARROW TO BAR
- {"UpArrowDownArrow", 0x021C5}, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW
- {"updownarrow", 0x02195}, // UP DOWN ARROW
- {"UpDownArrow", 0x02195}, // UP DOWN ARROW
- {"Updownarrow", 0x021D5}, // UP DOWN DOUBLE ARROW
- {"UpEquilibrium", 0x0296E}, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
- {"upharpoonleft", 0x021BF}, // UPWARDS HARPOON WITH BARB LEFTWARDS
- {"upharpoonright", 0x021BE}, // UPWARDS HARPOON WITH BARB RIGHTWARDS
- {"uplus", 0x0228E}, // MULTISET UNION
- {"UpperLeftArrow", 0x02196}, // NORTH WEST ARROW
- {"UpperRightArrow", 0x02197}, // NORTH EAST ARROW
- {"upsi", 0x003C5}, // GREEK SMALL LETTER UPSILON
- {"Upsi", 0x003D2}, // GREEK UPSILON WITH HOOK SYMBOL
- {"upsih", 0x003D2}, // GREEK UPSILON WITH HOOK SYMBOL
- {"Upsilon", 0x003A5}, // GREEK CAPITAL LETTER UPSILON
- {"upsilon", 0x003C5}, // GREEK SMALL LETTER UPSILON
- {"UpTee", 0x022A5}, // UP TACK
- {"UpTeeArrow", 0x021A5}, // UPWARDS ARROW FROM BAR
- {"upuparrows", 0x021C8}, // UPWARDS PAIRED ARROWS
- {"urcorn", 0x0231D}, // TOP RIGHT CORNER
- {"urcorner", 0x0231D}, // TOP RIGHT CORNER
- {"urcrop", 0x0230E}, // TOP RIGHT CROP
- {"Uring", 0x0016E}, // LATIN CAPITAL LETTER U WITH RING ABOVE
- {"uring", 0x0016F}, // LATIN SMALL LETTER U WITH RING ABOVE
- {"urtri", 0x025F9}, // UPPER RIGHT TRIANGLE
- {"Uscr", 0x1D4B0}, // MATHEMATICAL SCRIPT CAPITAL U
- {"uscr", 0x1D4CA}, // MATHEMATICAL SCRIPT SMALL U
- {"utdot", 0x022F0}, // UP RIGHT DIAGONAL ELLIPSIS
- {"Utilde", 0x00168}, // LATIN CAPITAL LETTER U WITH TILDE
- {"utilde", 0x00169}, // LATIN SMALL LETTER U WITH TILDE
- {"utri", 0x025B5}, // WHITE UP-POINTING SMALL TRIANGLE
- {"utrif", 0x025B4}, // BLACK UP-POINTING SMALL TRIANGLE
- {"uuarr", 0x021C8}, // UPWARDS PAIRED ARROWS
- {"Uuml", 0x000DC}, // LATIN CAPITAL LETTER U WITH DIAERESIS
- {"uuml", 0x000FC}, // LATIN SMALL LETTER U WITH DIAERESIS
- {"uwangle", 0x029A7}, // OBLIQUE ANGLE OPENING DOWN
- {NULL, 0}
-};
-
-static NameId namesV[]={
- {"vangrt", 0x0299C}, // RIGHT ANGLE VARIANT WITH SQUARE
- {"varepsilon", 0x003F5}, // GREEK LUNATE EPSILON SYMBOL
- {"varkappa", 0x003F0}, // GREEK KAPPA SYMBOL
- {"varnothing", 0x02205}, // EMPTY SET
- {"varphi", 0x003D5}, // GREEK PHI SYMBOL
- {"varpi", 0x003D6}, // GREEK PI SYMBOL
- {"varpropto", 0x0221D}, // PROPORTIONAL TO
- {"varr", 0x02195}, // UP DOWN ARROW
- {"vArr", 0x021D5}, // UP DOWN DOUBLE ARROW
- {"varrho", 0x003F1}, // GREEK RHO SYMBOL
- {"varsigma", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
-// "varsubsetneq", 0x0228A;0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
-// "varsubsetneqq", 0x02ACB;0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
-// "varsupsetneq", 0x0228B;0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
-// "varsupsetneqq", 0x02ACC;0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
- {"vartheta", 0x003D1}, // GREEK THETA SYMBOL
- {"vartriangleleft", 0x022B2}, // NORMAL SUBGROUP OF
- {"vartriangleright", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP
- {"vBar", 0x02AE8}, // SHORT UP TACK WITH UNDERBAR
- {"Vbar", 0x02AEB}, // DOUBLE UP TACK
- {"vBarv", 0x02AE9}, // SHORT UP TACK ABOVE SHORT DOWN TACK
- {"Vcy", 0x00412}, // CYRILLIC CAPITAL LETTER VE
- {"vcy", 0x00432}, // CYRILLIC SMALL LETTER VE
- {"vdash", 0x022A2}, // RIGHT TACK
- {"vDash", 0x022A8}, // TRUE
- {"Vdash", 0x022A9}, // FORCES
- {"VDash", 0x022AB}, // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
- {"Vdashl", 0x02AE6}, // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL
- {"vee", 0x02228}, // LOGICAL OR
- {"Vee", 0x022C1}, // N-ARY LOGICAL OR
- {"veebar", 0x022BB}, // XOR
- {"veeeq", 0x0225A}, // EQUIANGULAR TO
- {"vellip", 0x022EE}, // VERTICAL ELLIPSIS
- {"verbar", 0x0007C}, // VERTICAL LINE
- {"Verbar", 0x02016}, // DOUBLE VERTICAL LINE
- {"vert", 0x0007C}, // VERTICAL LINE
- {"Vert", 0x02016}, // DOUBLE VERTICAL LINE
- {"VerticalBar", 0x02223}, // DIVIDES
- {"VerticalLine", 0x0007C}, // VERTICAL LINE
- {"VerticalSeparator", 0x02758}, // LIGHT VERTICAL BAR
- {"VerticalTilde", 0x02240}, // WREATH PRODUCT
- {"VeryThinSpace", 0x0200A}, // HAIR SPACE
- {"Vfr", 0x1D519}, // MATHEMATICAL FRAKTUR CAPITAL V
- {"vfr", 0x1D533}, // MATHEMATICAL FRAKTUR SMALL V
- {"vltri", 0x022B2}, // NORMAL SUBGROUP OF
-// "vnsub", 0x02282;0x020D2}, // SUBSET OF with vertical line
-// "vnsup", 0x02283;0x020D2}, // SUPERSET OF with vertical line
- {"Vopf", 0x1D54D}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL V
- {"vopf", 0x1D567}, // MATHEMATICAL DOUBLE-STRUCK SMALL V
- {"vprop", 0x0221D}, // PROPORTIONAL TO
- {"vrtri", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP
- {"Vscr", 0x1D4B1}, // MATHEMATICAL SCRIPT CAPITAL V
- {"vscr", 0x1D4CB}, // MATHEMATICAL SCRIPT SMALL V
-// "vsubne", 0x0228A;0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
-// "vsubnE", 0x02ACB;0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
-// "vsupne", 0x0228B;0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
-// "vsupnE", 0x02ACC;0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
- {"Vvdash", 0x022AA}, // TRIPLE VERTICAL BAR RIGHT TURNSTILE
- {"vzigzag", 0x0299A}, // VERTICAL ZIGZAG LINE
- {NULL, 0}
-};
-
-static NameId namesW[]={
- {"Wcirc", 0x00174}, // LATIN CAPITAL LETTER W WITH CIRCUMFLEX
- {"wcirc", 0x00175}, // LATIN SMALL LETTER W WITH CIRCUMFLEX
- {"wedbar", 0x02A5F}, // LOGICAL AND WITH UNDERBAR
- {"wedge", 0x02227}, // LOGICAL AND
- {"Wedge", 0x022C0}, // N-ARY LOGICAL AND
- {"wedgeq", 0x02259}, // ESTIMATES
- {"weierp", 0x02118}, // SCRIPT CAPITAL P
- {"Wfr", 0x1D51A}, // MATHEMATICAL FRAKTUR CAPITAL W
- {"wfr", 0x1D534}, // MATHEMATICAL FRAKTUR SMALL W
- {"Wopf", 0x1D54E}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL W
- {"wopf", 0x1D568}, // MATHEMATICAL DOUBLE-STRUCK SMALL W
- {"wp", 0x02118}, // SCRIPT CAPITAL P
- {"wr", 0x02240}, // WREATH PRODUCT
- {"wreath", 0x02240}, // WREATH PRODUCT
- {"Wscr", 0x1D4B2}, // MATHEMATICAL SCRIPT CAPITAL W
- {"wscr", 0x1D4CC}, // MATHEMATICAL SCRIPT SMALL W
- {NULL, 0}
-};
-
-static NameId namesX[]={
- {"xcap", 0x022C2}, // N-ARY INTERSECTION
- {"xcirc", 0x025EF}, // LARGE CIRCLE
- {"xcup", 0x022C3}, // N-ARY UNION
- {"xdtri", 0x025BD}, // WHITE DOWN-POINTING TRIANGLE
- {"Xfr", 0x1D51B}, // MATHEMATICAL FRAKTUR CAPITAL X
- {"xfr", 0x1D535}, // MATHEMATICAL FRAKTUR SMALL X
- {"Xgr", 0x0039E}, // GREEK CAPITAL LETTER XI
- {"xgr", 0x003BE}, // GREEK SMALL LETTER XI
- {"xharr", 0x027F7}, // LONG LEFT RIGHT ARROW
- {"xhArr", 0x027FA}, // LONG LEFT RIGHT DOUBLE ARROW
- {"Xi", 0x0039E}, // GREEK CAPITAL LETTER XI
- {"xi", 0x003BE}, // GREEK SMALL LETTER XI
- {"xlarr", 0x027F5}, // LONG LEFTWARDS ARROW
- {"xlArr", 0x027F8}, // LONG LEFTWARDS DOUBLE ARROW
- {"xmap", 0x027FC}, // LONG RIGHTWARDS ARROW FROM BAR
- {"xnis", 0x022FB}, // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
- {"xodot", 0x02A00}, // N-ARY CIRCLED DOT OPERATOR
- {"Xopf", 0x1D54F}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL X
- {"xopf", 0x1D569}, // MATHEMATICAL DOUBLE-STRUCK SMALL X
- {"xoplus", 0x02A01}, // N-ARY CIRCLED PLUS OPERATOR
- {"xotime", 0x02A02}, // N-ARY CIRCLED TIMES OPERATOR
- {"xrarr", 0x027F6}, // LONG RIGHTWARDS ARROW
- {"xrArr", 0x027F9}, // LONG RIGHTWARDS DOUBLE ARROW
- {"Xscr", 0x1D4B3}, // MATHEMATICAL SCRIPT CAPITAL X
- {"xscr", 0x1D4CD}, // MATHEMATICAL SCRIPT SMALL X
- {"xsqcup", 0x02A06}, // N-ARY SQUARE UNION OPERATOR
- {"xuplus", 0x02A04}, // N-ARY UNION OPERATOR WITH PLUS
- {"xutri", 0x025B3}, // WHITE UP-POINTING TRIANGLE
- {"xvee", 0x022C1}, // N-ARY LOGICAL OR
- {"xwedge", 0x022C0}, // N-ARY LOGICAL AND
- {NULL, 0}
-};
-
-static NameId namesY[]={
- {"Yacute", 0x000DD}, // LATIN CAPITAL LETTER Y WITH ACUTE
- {"yacute", 0x000FD}, // LATIN SMALL LETTER Y WITH ACUTE
- {"YAcy", 0x0042F}, // CYRILLIC CAPITAL LETTER YA
- {"yacy", 0x0044F}, // CYRILLIC SMALL LETTER YA
- {"Ycirc", 0x00176}, // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
- {"ycirc", 0x00177}, // LATIN SMALL LETTER Y WITH CIRCUMFLEX
- {"Ycy", 0x0042B}, // CYRILLIC CAPITAL LETTER YERU
- {"ycy", 0x0044B}, // CYRILLIC SMALL LETTER YERU
- {"yen", 0x000A5}, // YEN SIGN
- {"Yfr", 0x1D51C}, // MATHEMATICAL FRAKTUR CAPITAL Y
- {"yfr", 0x1D536}, // MATHEMATICAL FRAKTUR SMALL Y
- {"YIcy", 0x00407}, // CYRILLIC CAPITAL LETTER YI
- {"yicy", 0x00457}, // CYRILLIC SMALL LETTER YI
- {"Yopf", 0x1D550}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
- {"yopf", 0x1D56A}, // MATHEMATICAL DOUBLE-STRUCK SMALL Y
- {"Yscr", 0x1D4B4}, // MATHEMATICAL SCRIPT CAPITAL Y
- {"yscr", 0x1D4CE}, // MATHEMATICAL SCRIPT SMALL Y
- {"YUcy", 0x0042E}, // CYRILLIC CAPITAL LETTER YU
- {"yucy", 0x0044E}, // CYRILLIC SMALL LETTER YU
- {"yuml", 0x000FF}, // LATIN SMALL LETTER Y WITH DIAERESIS
- {"Yuml", 0x00178}, // LATIN CAPITAL LETTER Y WITH DIAERESIS
- {NULL, 0}
-};
-
-static NameId namesZ[]={
- {"Zacute", 0x00179}, // LATIN CAPITAL LETTER Z WITH ACUTE
- {"zacute", 0x0017A}, // LATIN SMALL LETTER Z WITH ACUTE
- {"Zcaron", 0x0017D}, // LATIN CAPITAL LETTER Z WITH CARON
- {"zcaron", 0x0017E}, // LATIN SMALL LETTER Z WITH CARON
- {"Zcy", 0x00417}, // CYRILLIC CAPITAL LETTER ZE
- {"zcy", 0x00437}, // CYRILLIC SMALL LETTER ZE
- {"Zdot", 0x0017B}, // LATIN CAPITAL LETTER Z WITH DOT ABOVE
- {"zdot", 0x0017C}, // LATIN SMALL LETTER Z WITH DOT ABOVE
- {"zeetrf", 0x02128}, // BLACK-LETTER CAPITAL Z
- {"ZeroWidthSpace", 0x0200B}, // ZERO WIDTH SPACE
- {"Zeta", 0x00396}, // GREEK CAPITAL LETTER ZETA
- {"zeta", 0x003B6}, // GREEK SMALL LETTER ZETA
- {"Zfr", 0x02128}, // BLACK-LETTER CAPITAL Z
- {"zfr", 0x1D537}, // MATHEMATICAL FRAKTUR SMALL Z
- {"Zgr", 0x00396}, // GREEK CAPITAL LETTER ZETA
- {"zgr", 0x003B6}, // GREEK SMALL LETTER ZETA
- {"ZHcy", 0x00416}, // CYRILLIC CAPITAL LETTER ZHE
- {"zhcy", 0x00436}, // CYRILLIC SMALL LETTER ZHE
- {"zigrarr", 0x021DD}, // RIGHTWARDS SQUIGGLE ARROW
- {"Zopf", 0x02124}, // DOUBLE-STRUCK CAPITAL Z
- {"zopf", 0x1D56B}, // MATHEMATICAL DOUBLE-STRUCK SMALL Z
- {"Zscr", 0x1D4B5}, // MATHEMATICAL SCRIPT CAPITAL Z
- {"zscr", 0x1D4CF}, // MATHEMATICAL SCRIPT SMALL Z
- {"zwj", 0x0200D}, // ZERO WIDTH JOINER
- {"zwnj", 0x0200C}, // ZERO WIDTH NON-JOINER
- {NULL, 0}
-};
-
-// @todo@ order namesTable and names? by frequency
-static NameId* namesTable[] = {
- namesA, namesB, namesC, namesD, namesE, namesF, namesG, namesH, namesI,
- namesJ, namesK, namesL, namesM, namesN, namesO, namesP, namesQ, namesR,
- namesS, namesT, namesU, namesV, namesW, namesX, namesY, namesZ, NULL
-};
-
-int HtmlNamedEntity(const utf8_t *p, size_t length)
-{
- int tableIndex = tolower(*p) - 'a';
- if (tableIndex >= 0 && tableIndex < 26)
- {
- NameId* names = namesTable[tableIndex];
-
- for (size_t i = 0; names[i].name; i++)
- {
- if (strncmp(names[i].name, (const char *)p, length) == 0)
- return names[i].value;
- }
- }
- return -1;
-}
-
diff --git a/gcc/d/dmd/entity.d b/gcc/d/dmd/entity.d
new file mode 100644
index 0000000..f22dfdb
--- /dev/null
+++ b/gcc/d/dmd/entity.d
@@ -0,0 +1,2395 @@
+/**
+ * Defines the named entities to support the "\\&amp;Entity;" escape sequence for strings / character literals.
+ *
+ * Specification $(LINK2 https://dlang.org/spec/entity.html, Named Character Entities)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/entity.d, _entity.d)
+ * Documentation: https://dlang.org/phobos/dmd_entity.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/entity.d
+ */
+
+module dmd.entity;
+
+import core.stdc.ctype;
+
+nothrow:
+
+public int HtmlNamedEntity(const(char)* p, size_t length)
+{
+ int tableIndex = tolower(*p) - 'a';
+ if (tableIndex >= 0 && tableIndex < 26)
+ {
+ foreach (entity; namesTable[tableIndex])
+ {
+ if (entity.name == p[0 .. length])
+ return entity.value;
+ }
+ }
+ return -1;
+}
+
+private:
+
+/*********************************************
+ * Convert from named entity to its encoding.
+ * For reference:
+ * http://www.htmlhelp.com/reference/html40/entities/
+ * http://www.w3.org/2003/entities/2007/w3centities-f.ent
+ */
+struct NameId
+{
+ string name;
+ uint value;
+}
+
+// @todo@ order namesTable and names? by frequency
+immutable NameId[][] namesTable =
+[
+ namesA, namesB, namesC, namesD, namesE, namesF, namesG, namesH, namesI,
+ namesJ, namesK, namesL, namesM, namesN, namesO, namesP, namesQ, namesR,
+ namesS, namesT, namesU, namesV, namesW, namesX, namesY, namesZ
+];
+
+immutable NameId[] namesA =
+[
+ {"Aacgr", 0x00386}, // GREEK CAPITAL LETTER ALPHA WITH TONOS
+ {"aacgr", 0x003AC}, // GREEK SMALL LETTER ALPHA WITH TONOS
+ {"Aacute", 0x000C1}, // LATIN CAPITAL LETTER A WITH ACUTE
+ {"aacute", 0x000E1}, // LATIN SMALL LETTER A WITH ACUTE
+ {"Abreve", 0x00102}, // LATIN CAPITAL LETTER A WITH BREVE
+ {"abreve", 0x00103}, // LATIN SMALL LETTER A WITH BREVE
+ {"ac", 0x0223E}, // INVERTED LAZY S
+ {"acd", 0x0223F}, // SINE WAVE
+// {"acE", 0x0223E;0x00333}, // INVERTED LAZY S with double underline
+ {"Acirc", 0x000C2}, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+ {"acirc", 0x000E2}, // LATIN SMALL LETTER A WITH CIRCUMFLEX
+ {"acute", 0x000B4}, // ACUTE ACCENT
+ {"Acy", 0x00410}, // CYRILLIC CAPITAL LETTER A
+ {"acy", 0x00430}, // CYRILLIC SMALL LETTER A
+ {"AElig", 0x000C6}, // LATIN CAPITAL LETTER AE
+ {"aelig", 0x000E6}, // LATIN SMALL LETTER AE
+ {"af", 0x02061}, // FUNCTION APPLICATION
+ {"Afr", 0x1D504}, // MATHEMATICAL FRAKTUR CAPITAL A
+ {"afr", 0x1D51E}, // MATHEMATICAL FRAKTUR SMALL A
+ {"Agr", 0x00391}, // GREEK CAPITAL LETTER ALPHA
+ {"agr", 0x003B1}, // GREEK SMALL LETTER ALPHA
+ {"Agrave", 0x000C0}, // LATIN CAPITAL LETTER A WITH GRAVE
+ {"agrave", 0x000E0}, // LATIN SMALL LETTER A WITH GRAVE
+ {"alefsym", 0x02135}, // ALEF SYMBOL
+ {"aleph", 0x02135}, // ALEF SYMBOL
+ {"Alpha", 0x00391}, // GREEK CAPITAL LETTER ALPHA
+ {"alpha", 0x003B1}, // GREEK SMALL LETTER ALPHA
+ {"Amacr", 0x00100}, // LATIN CAPITAL LETTER A WITH MACRON
+ {"amacr", 0x00101}, // LATIN SMALL LETTER A WITH MACRON
+ {"amalg", 0x02A3F}, // AMALGAMATION OR COPRODUCT
+ {"amp", 0x00026}, // AMPERSAND
+ {"AMP", 0x00026}, // AMPERSAND
+ {"and", 0x02227}, // LOGICAL AND
+ {"And", 0x02A53}, // DOUBLE LOGICAL AND
+ {"andand", 0x02A55}, // TWO INTERSECTING LOGICAL AND
+ {"andd", 0x02A5C}, // LOGICAL AND WITH HORIZONTAL DASH
+ {"andslope", 0x02A58}, // SLOPING LARGE AND
+ {"andv", 0x02A5A}, // LOGICAL AND WITH MIDDLE STEM
+ {"ang", 0x02220}, // ANGLE
+ {"ange", 0x029A4}, // ANGLE WITH UNDERBAR
+ {"angle", 0x02220}, // ANGLE
+ {"angmsd", 0x02221}, // MEASURED ANGLE
+ {"angmsdaa", 0x029A8}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT
+ {"angmsdab", 0x029A9}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT
+ {"angmsdac", 0x029AA}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT
+ {"angmsdad", 0x029AB}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT
+ {"angmsdae", 0x029AC}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP
+ {"angmsdaf", 0x029AD}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP
+ {"angmsdag", 0x029AE}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN
+ {"angmsdah", 0x029AF}, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN
+ {"angrt", 0x0221F}, // RIGHT ANGLE
+ {"angrtvb", 0x022BE}, // RIGHT ANGLE WITH ARC
+ {"angrtvbd", 0x0299D}, // MEASURED RIGHT ANGLE WITH DOT
+ {"angsph", 0x02222}, // SPHERICAL ANGLE
+ {"angst", 0x000C5}, // LATIN CAPITAL LETTER A WITH RING ABOVE
+ {"angzarr", 0x0237C}, // RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW
+ {"Aogon", 0x00104}, // LATIN CAPITAL LETTER A WITH OGONEK
+ {"aogon", 0x00105}, // LATIN SMALL LETTER A WITH OGONEK
+ {"Aopf", 0x1D538}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL A
+ {"aopf", 0x1D552}, // MATHEMATICAL DOUBLE-STRUCK SMALL A
+ {"ap", 0x02248}, // ALMOST EQUAL TO
+ {"apacir", 0x02A6F}, // ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT
+ {"ape", 0x0224A}, // ALMOST EQUAL OR EQUAL TO
+ {"apE", 0x02A70}, // APPROXIMATELY EQUAL OR EQUAL TO
+ {"apid", 0x0224B}, // TRIPLE TILDE
+ {"apos", 0x00027}, // APOSTROPHE
+ {"ApplyFunction", 0x02061}, // FUNCTION APPLICATION
+ {"approx", 0x02248}, // ALMOST EQUAL TO
+ {"approxeq", 0x0224A}, // ALMOST EQUAL OR EQUAL TO
+ {"Aring", 0x000C5}, // LATIN CAPITAL LETTER A WITH RING ABOVE
+ {"aring", 0x000E5}, // LATIN SMALL LETTER A WITH RING ABOVE
+ {"Ascr", 0x1D49C}, // MATHEMATICAL SCRIPT CAPITAL A
+ {"ascr", 0x1D4B6}, // MATHEMATICAL SCRIPT SMALL A
+ {"Assign", 0x02254}, // COLON EQUALS
+ {"ast", 0x0002A}, // ASTERISK
+ {"asymp", 0x02248}, // ALMOST EQUAL TO
+ {"asympeq", 0x0224D}, // EQUIVALENT TO
+ {"Atilde", 0x000C3}, // LATIN CAPITAL LETTER A WITH TILDE
+ {"atilde", 0x000E3}, // LATIN SMALL LETTER A WITH TILDE
+ {"Auml", 0x000C4}, // LATIN CAPITAL LETTER A WITH DIAERESIS
+ {"auml", 0x000E4}, // LATIN SMALL LETTER A WITH DIAERESIS
+ {"awconint", 0x02233}, // ANTICLOCKWISE CONTOUR INTEGRAL
+ {"awint", 0x02A11}, // ANTICLOCKWISE INTEGRATION
+];
+
+immutable NameId[] namesB =
+[
+ {"backcong", 0x0224C}, // ALL EQUAL TO
+ {"backepsilon", 0x003F6}, // GREEK REVERSED LUNATE EPSILON SYMBOL
+ {"backprime", 0x02035}, // REVERSED PRIME
+ {"backsim", 0x0223D}, // REVERSED TILDE
+ {"backsimeq", 0x022CD}, // REVERSED TILDE EQUALS
+ {"Backslash", 0x02216}, // SET MINUS
+// "b.alpha", 0x1D6C2}, // MATHEMATICAL BOLD SMALL ALPHA
+ {"Barv", 0x02AE7}, // SHORT DOWN TACK WITH OVERBAR
+ {"barvee", 0x022BD}, // NOR
+ {"barwed", 0x02305}, // PROJECTIVE
+ {"Barwed", 0x02306}, // PERSPECTIVE
+ {"barwedge", 0x02305}, // PROJECTIVE
+// "b.beta", 0x1D6C3}, // MATHEMATICAL BOLD SMALL BETA
+ {"bbrk", 0x023B5}, // BOTTOM SQUARE BRACKET
+ {"bbrktbrk", 0x023B6}, // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET
+// "b.chi", 0x1D6D8}, // MATHEMATICAL BOLD SMALL CHI
+ {"bcong", 0x0224C}, // ALL EQUAL TO
+ {"Bcy", 0x00411}, // CYRILLIC CAPITAL LETTER BE
+ {"bcy", 0x00431}, // CYRILLIC SMALL LETTER BE
+// "b.Delta", 0x1D6AB}, // MATHEMATICAL BOLD CAPITAL DELTA
+// "b.delta", 0x1D6C5}, // MATHEMATICAL BOLD SMALL DELTA
+ {"bdquo", 0x0201E}, // DOUBLE LOW-9 QUOTATION MARK
+ {"becaus", 0x02235}, // BECAUSE
+ {"because", 0x02235}, // BECAUSE
+ {"Because", 0x02235}, // BECAUSE
+ {"bemptyv", 0x029B0}, // REVERSED EMPTY SET
+ {"bepsi", 0x003F6}, // GREEK REVERSED LUNATE EPSILON SYMBOL
+// "b.epsi", 0x1D6C6}, // MATHEMATICAL BOLD SMALL EPSILON
+// "b.epsiv", 0x1D6DC}, // MATHEMATICAL BOLD EPSILON SYMBOL
+ {"bernou", 0x0212C}, // SCRIPT CAPITAL B
+ {"Bernoullis", 0x0212C}, // SCRIPT CAPITAL B
+ {"Beta", 0x00392}, // GREEK CAPITAL LETTER BETA
+ {"beta", 0x003B2}, // GREEK SMALL LETTER BETA
+// "b.eta", 0x1D6C8}, // MATHEMATICAL BOLD SMALL ETA
+ {"beth", 0x02136}, // BET SYMBOL
+ {"between", 0x0226C}, // BETWEEN
+ {"Bfr", 0x1D505}, // MATHEMATICAL FRAKTUR CAPITAL B
+ {"bfr", 0x1D51F}, // MATHEMATICAL FRAKTUR SMALL B
+// "b.Gamma", 0x1D6AA}, // MATHEMATICAL BOLD CAPITAL GAMMA
+// "b.gamma", 0x1D6C4}, // MATHEMATICAL BOLD SMALL GAMMA
+// "b.Gammad", 0x1D7CA}, // MATHEMATICAL BOLD CAPITAL DIGAMMA
+// "b.gammad", 0x1D7CB}, // MATHEMATICAL BOLD SMALL DIGAMMA
+ {"Bgr", 0x00392}, // GREEK CAPITAL LETTER BETA
+ {"bgr", 0x003B2}, // GREEK SMALL LETTER BETA
+ {"bigcap", 0x022C2}, // N-ARY INTERSECTION
+ {"bigcirc", 0x025EF}, // LARGE CIRCLE
+ {"bigcup", 0x022C3}, // N-ARY UNION
+ {"bigodot", 0x02A00}, // N-ARY CIRCLED DOT OPERATOR
+ {"bigoplus", 0x02A01}, // N-ARY CIRCLED PLUS OPERATOR
+ {"bigotimes", 0x02A02}, // N-ARY CIRCLED TIMES OPERATOR
+ {"bigsqcup", 0x02A06}, // N-ARY SQUARE UNION OPERATOR
+ {"bigstar", 0x02605}, // BLACK STAR
+ {"bigtriangledown", 0x025BD}, // WHITE DOWN-POINTING TRIANGLE
+ {"bigtriangleup", 0x025B3}, // WHITE UP-POINTING TRIANGLE
+ {"biguplus", 0x02A04}, // N-ARY UNION OPERATOR WITH PLUS
+ {"bigvee", 0x022C1}, // N-ARY LOGICAL OR
+ {"bigwedge", 0x022C0}, // N-ARY LOGICAL AND
+// "b.iota", 0x1D6CA}, // MATHEMATICAL BOLD SMALL IOTA
+// "b.kappa", 0x1D6CB}, // MATHEMATICAL BOLD SMALL KAPPA
+// "b.kappav", 0x1D6DE}, // MATHEMATICAL BOLD KAPPA SYMBOL
+ {"bkarow", 0x0290D}, // RIGHTWARDS DOUBLE DASH ARROW
+ {"blacklozenge", 0x029EB}, // BLACK LOZENGE
+ {"blacksquare", 0x025AA}, // BLACK SMALL SQUARE
+ {"blacktriangle", 0x025B4}, // BLACK UP-POINTING SMALL TRIANGLE
+ {"blacktriangledown", 0x025BE}, // BLACK DOWN-POINTING SMALL TRIANGLE
+ {"blacktriangleleft", 0x025C2}, // BLACK LEFT-POINTING SMALL TRIANGLE
+ {"blacktriangleright", 0x025B8}, // BLACK RIGHT-POINTING SMALL TRIANGLE
+// "b.Lambda", 0x1D6B2}, // MATHEMATICAL BOLD CAPITAL LAMDA
+// "b.lambda", 0x1D6CC}, // MATHEMATICAL BOLD SMALL LAMDA
+ {"blank", 0x02423}, // OPEN BOX
+ {"blk12", 0x02592}, // MEDIUM SHADE
+ {"blk14", 0x02591}, // LIGHT SHADE
+ {"blk34", 0x02593}, // DARK SHADE
+ {"block", 0x02588}, // FULL BLOCK
+// "b.mu", 0x1D6CD}, // MATHEMATICAL BOLD SMALL MU
+// "bne", 0x0003D;0x020E5}, // EQUALS SIGN with reverse slash
+// "bnequiv", 0x02261;0x020E5}, // IDENTICAL TO with reverse slash
+ {"bnot", 0x02310}, // REVERSED NOT SIGN
+ {"bNot", 0x02AED}, // REVERSED DOUBLE STROKE NOT SIGN
+// "b.nu", 0x1D6CE}, // MATHEMATICAL BOLD SMALL NU
+// "b.Omega", 0x1D6C0}, // MATHEMATICAL BOLD CAPITAL OMEGA
+// "b.omega", 0x1D6DA}, // MATHEMATICAL BOLD SMALL OMEGA
+ {"Bopf", 0x1D539}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL B
+ {"bopf", 0x1D553}, // MATHEMATICAL DOUBLE-STRUCK SMALL B
+ {"bot", 0x022A5}, // UP TACK
+ {"bottom", 0x022A5}, // UP TACK
+ {"bowtie", 0x022C8}, // BOWTIE
+ {"boxbox", 0x029C9}, // TWO JOINED SQUARES
+ {"boxdl", 0x02510}, // BOX DRAWINGS LIGHT DOWN AND LEFT
+ {"boxdL", 0x02555}, // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE
+ {"boxDl", 0x02556}, // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE
+ {"boxDL", 0x02557}, // BOX DRAWINGS DOUBLE DOWN AND LEFT
+ {"boxdr", 0x0250C}, // BOX DRAWINGS LIGHT DOWN AND RIGHT
+ {"boxdR", 0x02552}, // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE
+ {"boxDr", 0x02553}, // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE
+ {"boxDR", 0x02554}, // BOX DRAWINGS DOUBLE DOWN AND RIGHT
+ {"boxh", 0x02500}, // BOX DRAWINGS LIGHT HORIZONTAL
+ {"boxH", 0x02550}, // BOX DRAWINGS DOUBLE HORIZONTAL
+ {"boxhd", 0x0252C}, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL
+ {"boxHd", 0x02564}, // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE
+ {"boxhD", 0x02565}, // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE
+ {"boxHD", 0x02566}, // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL
+ {"boxhu", 0x02534}, // BOX DRAWINGS LIGHT UP AND HORIZONTAL
+ {"boxHu", 0x02567}, // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE
+ {"boxhU", 0x02568}, // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE
+ {"boxHU", 0x02569}, // BOX DRAWINGS DOUBLE UP AND HORIZONTAL
+ {"boxminus", 0x0229F}, // SQUARED MINUS
+ {"boxplus", 0x0229E}, // SQUARED PLUS
+ {"boxtimes", 0x022A0}, // SQUARED TIMES
+ {"boxul", 0x02518}, // BOX DRAWINGS LIGHT UP AND LEFT
+ {"boxuL", 0x0255B}, // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE
+ {"boxUl", 0x0255C}, // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE
+ {"boxUL", 0x0255D}, // BOX DRAWINGS DOUBLE UP AND LEFT
+ {"boxur", 0x02514}, // BOX DRAWINGS LIGHT UP AND RIGHT
+ {"boxuR", 0x02558}, // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE
+ {"boxUr", 0x02559}, // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE
+ {"boxUR", 0x0255A}, // BOX DRAWINGS DOUBLE UP AND RIGHT
+ {"boxv", 0x02502}, // BOX DRAWINGS LIGHT VERTICAL
+ {"boxV", 0x02551}, // BOX DRAWINGS DOUBLE VERTICAL
+ {"boxvh", 0x0253C}, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL
+ {"boxvH", 0x0256A}, // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE
+ {"boxVh", 0x0256B}, // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE
+ {"boxVH", 0x0256C}, // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL
+ {"boxvl", 0x02524}, // BOX DRAWINGS LIGHT VERTICAL AND LEFT
+ {"boxvL", 0x02561}, // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE
+ {"boxVl", 0x02562}, // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE
+ {"boxVL", 0x02563}, // BOX DRAWINGS DOUBLE VERTICAL AND LEFT
+ {"boxvr", 0x0251C}, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT
+ {"boxvR", 0x0255E}, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE
+ {"boxVr", 0x0255F}, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE
+ {"boxVR", 0x02560}, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT
+// "b.Phi", 0x1D6BD}, // MATHEMATICAL BOLD CAPITAL PHI
+// "b.phi", 0x1D6D7}, // MATHEMATICAL BOLD SMALL PHI
+// "b.phiv", 0x1D6DF}, // MATHEMATICAL BOLD PHI SYMBOL
+// "b.Pi", 0x1D6B7}, // MATHEMATICAL BOLD CAPITAL PI
+// "b.pi", 0x1D6D1}, // MATHEMATICAL BOLD SMALL PI
+// "b.piv", 0x1D6E1}, // MATHEMATICAL BOLD PI SYMBOL
+ {"bprime", 0x02035}, // REVERSED PRIME
+// "b.Psi", 0x1D6BF}, // MATHEMATICAL BOLD CAPITAL PSI
+// "b.psi", 0x1D6D9}, // MATHEMATICAL BOLD SMALL PSI
+ {"breve", 0x002D8}, // BREVE
+ {"Breve", 0x002D8}, // BREVE
+// "b.rho", 0x1D6D2}, // MATHEMATICAL BOLD SMALL RHO
+// "b.rhov", 0x1D6E0}, // MATHEMATICAL BOLD RHO SYMBOL
+ {"brvbar", 0x000A6}, // BROKEN BAR
+ {"Bscr", 0x0212C}, // SCRIPT CAPITAL B
+ {"bscr", 0x1D4B7}, // MATHEMATICAL SCRIPT SMALL B
+ {"bsemi", 0x0204F}, // REVERSED SEMICOLON
+// "b.Sigma", 0x1D6BA}, // MATHEMATICAL BOLD CAPITAL SIGMA
+// "b.sigma", 0x1D6D4}, // MATHEMATICAL BOLD SMALL SIGMA
+// "b.sigmav", 0x1D6D3}, // MATHEMATICAL BOLD SMALL FINAL SIGMA
+ {"bsim", 0x0223D}, // REVERSED TILDE
+ {"bsime", 0x022CD}, // REVERSED TILDE EQUALS
+ {"bsol", 0x0005C}, // REVERSE SOLIDUS
+ {"bsolb", 0x029C5}, // SQUARED FALLING DIAGONAL SLASH
+ {"bsolhsub", 0x027C8}, // REVERSE SOLIDUS PRECEDING SUBSET
+// "b.tau", 0x1D6D5}, // MATHEMATICAL BOLD SMALL TAU
+// "b.Theta", 0x1D6AF}, // MATHEMATICAL BOLD CAPITAL THETA
+// "b.thetas", 0x1D6C9}, // MATHEMATICAL BOLD SMALL THETA
+// "b.thetav", 0x1D6DD}, // MATHEMATICAL BOLD THETA SYMBOL
+ {"bull", 0x02022}, // BULLET
+ {"bullet", 0x02022}, // BULLET
+ {"bump", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO
+ {"bumpe", 0x0224F}, // DIFFERENCE BETWEEN
+ {"bumpE", 0x02AAE}, // EQUALS SIGN WITH BUMPY ABOVE
+ {"Bumpeq", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO
+ {"bumpeq", 0x0224F}, // DIFFERENCE BETWEEN
+// "b.Upsi", 0x1D6BC}, // MATHEMATICAL BOLD CAPITAL UPSILON
+// "b.upsi", 0x1D6D6}, // MATHEMATICAL BOLD SMALL UPSILON
+// "b.Xi", 0x1D6B5}, // MATHEMATICAL BOLD CAPITAL XI
+// "b.xi", 0x1D6CF}, // MATHEMATICAL BOLD SMALL XI
+// "b.zeta", 0x1D6C7}, // MATHEMATICAL BOLD SMALL ZETA
+];
+
+immutable NameId[] namesC =
+[
+ {"Cacute", 0x00106}, // LATIN CAPITAL LETTER C WITH ACUTE
+ {"cacute", 0x00107}, // LATIN SMALL LETTER C WITH ACUTE
+ {"cap", 0x02229}, // INTERSECTION
+ {"Cap", 0x022D2}, // DOUBLE INTERSECTION
+ {"capand", 0x02A44}, // INTERSECTION WITH LOGICAL AND
+ {"capbrcup", 0x02A49}, // INTERSECTION ABOVE BAR ABOVE UNION
+ {"capcap", 0x02A4B}, // INTERSECTION BESIDE AND JOINED WITH INTERSECTION
+ {"capcup", 0x02A47}, // INTERSECTION ABOVE UNION
+ {"capdot", 0x02A40}, // INTERSECTION WITH DOT
+ {"CapitalDifferentialD", 0x02145}, // DOUBLE-STRUCK ITALIC CAPITAL D
+// "caps", 0x02229;0x0FE00}, // INTERSECTION with serifs
+ {"caret", 0x02041}, // CARET INSERTION POINT
+ {"caron", 0x002C7}, // CARON
+ {"Cayleys", 0x0212D}, // BLACK-LETTER CAPITAL C
+ {"ccaps", 0x02A4D}, // CLOSED INTERSECTION WITH SERIFS
+ {"Ccaron", 0x0010C}, // LATIN CAPITAL LETTER C WITH CARON
+ {"ccaron", 0x0010D}, // LATIN SMALL LETTER C WITH CARON
+ {"Ccedil", 0x000C7}, // LATIN CAPITAL LETTER C WITH CEDILLA
+ {"ccedil", 0x000E7}, // LATIN SMALL LETTER C WITH CEDILLA
+ {"Ccirc", 0x00108}, // LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+ {"ccirc", 0x00109}, // LATIN SMALL LETTER C WITH CIRCUMFLEX
+ {"Cconint", 0x02230}, // VOLUME INTEGRAL
+ {"ccups", 0x02A4C}, // CLOSED UNION WITH SERIFS
+ {"ccupssm", 0x02A50}, // CLOSED UNION WITH SERIFS AND SMASH PRODUCT
+ {"Cdot", 0x0010A}, // LATIN CAPITAL LETTER C WITH DOT ABOVE
+ {"cdot", 0x0010B}, // LATIN SMALL LETTER C WITH DOT ABOVE
+ {"cedil", 0x000B8}, // CEDILLA
+ {"Cedilla", 0x000B8}, // CEDILLA
+ {"cemptyv", 0x029B2}, // EMPTY SET WITH SMALL CIRCLE ABOVE
+ {"cent", 0x000A2}, // CENT SIGN
+ {"centerdot", 0x000B7}, // MIDDLE DOT
+ {"CenterDot", 0x000B7}, // MIDDLE DOT
+ {"Cfr", 0x0212D}, // BLACK-LETTER CAPITAL C
+ {"cfr", 0x1D520}, // MATHEMATICAL FRAKTUR SMALL C
+ {"CHcy", 0x00427}, // CYRILLIC CAPITAL LETTER CHE
+ {"chcy", 0x00447}, // CYRILLIC SMALL LETTER CHE
+ {"check", 0x02713}, // CHECK MARK
+ {"checkmark", 0x02713}, // CHECK MARK
+ {"Chi", 0x003A7}, // GREEK CAPITAL LETTER CHI
+ {"chi", 0x003C7}, // GREEK SMALL LETTER CHI
+ {"cir", 0x025CB}, // WHITE CIRCLE
+ {"circ", 0x002C6}, // MODIFIER LETTER CIRCUMFLEX ACCENT
+ {"circeq", 0x02257}, // RING EQUAL TO
+ {"circlearrowleft", 0x021BA}, // ANTICLOCKWISE OPEN CIRCLE ARROW
+ {"circlearrowright", 0x021BB}, // CLOCKWISE OPEN CIRCLE ARROW
+ {"circledast", 0x0229B}, // CIRCLED ASTERISK OPERATOR
+ {"circledcirc", 0x0229A}, // CIRCLED RING OPERATOR
+ {"circleddash", 0x0229D}, // CIRCLED DASH
+ {"CircleDot", 0x02299}, // CIRCLED DOT OPERATOR
+ {"circledR", 0x000AE}, // REGISTERED SIGN
+ {"circledS", 0x024C8}, // CIRCLED LATIN CAPITAL LETTER S
+ {"CircleMinus", 0x02296}, // CIRCLED MINUS
+ {"CirclePlus", 0x02295}, // CIRCLED PLUS
+ {"CircleTimes", 0x02297}, // CIRCLED TIMES
+ {"cire", 0x02257}, // RING EQUAL TO
+ {"cirE", 0x029C3}, // CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT
+ {"cirfnint", 0x02A10}, // CIRCULATION FUNCTION
+ {"cirmid", 0x02AEF}, // VERTICAL LINE WITH CIRCLE ABOVE
+ {"cirscir", 0x029C2}, // CIRCLE WITH SMALL CIRCLE TO THE RIGHT
+ {"ClockwiseContourIntegral", 0x02232}, // CLOCKWISE CONTOUR INTEGRAL
+ {"CloseCurlyDoubleQuote", 0x0201D}, // RIGHT DOUBLE QUOTATION MARK
+ {"CloseCurlyQuote", 0x02019}, // RIGHT SINGLE QUOTATION MARK
+ {"clubs", 0x02663}, // BLACK CLUB SUIT
+ {"clubsuit", 0x02663}, // BLACK CLUB SUIT
+ {"colon", 0x0003A}, // COLON
+ {"Colon", 0x02237}, // PROPORTION
+ {"colone", 0x02254}, // COLON EQUALS
+ {"Colone", 0x02A74}, // DOUBLE COLON EQUAL
+ {"coloneq", 0x02254}, // COLON EQUALS
+ {"comma", 0x0002C}, // COMMA
+ {"commat", 0x00040}, // COMMERCIAL AT
+ {"comp", 0x02201}, // COMPLEMENT
+ {"compfn", 0x02218}, // RING OPERATOR
+ {"complement", 0x02201}, // COMPLEMENT
+ {"complexes", 0x02102}, // DOUBLE-STRUCK CAPITAL C
+ {"cong", 0x02245}, // APPROXIMATELY EQUAL TO
+ {"congdot", 0x02A6D}, // CONGRUENT WITH DOT ABOVE
+ {"Congruent", 0x02261}, // IDENTICAL TO
+ {"conint", 0x0222E}, // CONTOUR INTEGRAL
+ {"Conint", 0x0222F}, // SURFACE INTEGRAL
+ {"ContourIntegral", 0x0222E}, // CONTOUR INTEGRAL
+ {"Copf", 0x02102}, // DOUBLE-STRUCK CAPITAL C
+ {"copf", 0x1D554}, // MATHEMATICAL DOUBLE-STRUCK SMALL C
+ {"coprod", 0x02210}, // N-ARY COPRODUCT
+ {"Coproduct", 0x02210}, // N-ARY COPRODUCT
+ {"copy", 0x000A9}, // COPYRIGHT SIGN
+ {"COPY", 0x000A9}, // COPYRIGHT SIGN
+ {"copysr", 0x02117}, // SOUND RECORDING COPYRIGHT
+ {"CounterClockwiseContourIntegral", 0x02233}, // ANTICLOCKWISE CONTOUR INTEGRAL
+ {"crarr", 0x021B5}, // DOWNWARDS ARROW WITH CORNER LEFTWARDS
+ {"cross", 0x02717}, // BALLOT X
+ {"Cross", 0x02A2F}, // VECTOR OR CROSS PRODUCT
+ {"Cscr", 0x1D49E}, // MATHEMATICAL SCRIPT CAPITAL C
+ {"cscr", 0x1D4B8}, // MATHEMATICAL SCRIPT SMALL C
+ {"csub", 0x02ACF}, // CLOSED SUBSET
+ {"csube", 0x02AD1}, // CLOSED SUBSET OR EQUAL TO
+ {"csup", 0x02AD0}, // CLOSED SUPERSET
+ {"csupe", 0x02AD2}, // CLOSED SUPERSET OR EQUAL TO
+ {"ctdot", 0x022EF}, // MIDLINE HORIZONTAL ELLIPSIS
+ {"cudarrl", 0x02938}, // RIGHT-SIDE ARC CLOCKWISE ARROW
+ {"cudarrr", 0x02935}, // ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS
+ {"cuepr", 0x022DE}, // EQUAL TO OR PRECEDES
+ {"cuesc", 0x022DF}, // EQUAL TO OR SUCCEEDS
+ {"cularr", 0x021B6}, // ANTICLOCKWISE TOP SEMICIRCLE ARROW
+ {"cularrp", 0x0293D}, // TOP ARC ANTICLOCKWISE ARROW WITH PLUS
+ {"cup", 0x0222A}, // UNION
+ {"Cup", 0x022D3}, // DOUBLE UNION
+ {"cupbrcap", 0x02A48}, // UNION ABOVE BAR ABOVE INTERSECTION
+ {"CupCap", 0x0224D}, // EQUIVALENT TO
+ {"cupcap", 0x02A46}, // UNION ABOVE INTERSECTION
+ {"cupcup", 0x02A4A}, // UNION BESIDE AND JOINED WITH UNION
+ {"cupdot", 0x0228D}, // MULTISET MULTIPLICATION
+ {"cupor", 0x02A45}, // UNION WITH LOGICAL OR
+// "cups", 0x0222A;0x0FE00}, // UNION with serifs
+ {"curarr", 0x021B7}, // CLOCKWISE TOP SEMICIRCLE ARROW
+ {"curarrm", 0x0293C}, // TOP ARC CLOCKWISE ARROW WITH MINUS
+ {"curlyeqprec", 0x022DE}, // EQUAL TO OR PRECEDES
+ {"curlyeqsucc", 0x022DF}, // EQUAL TO OR SUCCEEDS
+ {"curlyvee", 0x022CE}, // CURLY LOGICAL OR
+ {"curlywedge", 0x022CF}, // CURLY LOGICAL AND
+ {"curren", 0x000A4}, // CURRENCY SIGN
+ {"curvearrowleft", 0x021B6}, // ANTICLOCKWISE TOP SEMICIRCLE ARROW
+ {"curvearrowright", 0x021B7}, // CLOCKWISE TOP SEMICIRCLE ARROW
+ {"cuvee", 0x022CE}, // CURLY LOGICAL OR
+ {"cuwed", 0x022CF}, // CURLY LOGICAL AND
+ {"cwconint", 0x02232}, // CLOCKWISE CONTOUR INTEGRAL
+ {"cwint", 0x02231}, // CLOCKWISE INTEGRAL
+ {"cylcty", 0x0232D}, // CYLINDRICITY
+];
+
+immutable NameId[] namesD =
+[
+ {"dagger", 0x02020}, // DAGGER
+ {"Dagger", 0x02021}, // DOUBLE DAGGER
+ {"daleth", 0x02138}, // DALET SYMBOL
+ {"darr", 0x02193}, // DOWNWARDS ARROW
+ {"Darr", 0x021A1}, // DOWNWARDS TWO HEADED ARROW
+ {"dArr", 0x021D3}, // DOWNWARDS DOUBLE ARROW
+ {"dash", 0x02010}, // HYPHEN
+ {"dashv", 0x022A3}, // LEFT TACK
+ {"Dashv", 0x02AE4}, // VERTICAL BAR DOUBLE LEFT TURNSTILE
+ {"dbkarow", 0x0290F}, // RIGHTWARDS TRIPLE DASH ARROW
+ {"dblac", 0x002DD}, // DOUBLE ACUTE ACCENT
+ {"Dcaron", 0x0010E}, // LATIN CAPITAL LETTER D WITH CARON
+ {"dcaron", 0x0010F}, // LATIN SMALL LETTER D WITH CARON
+ {"Dcy", 0x00414}, // CYRILLIC CAPITAL LETTER DE
+ {"dcy", 0x00434}, // CYRILLIC SMALL LETTER DE
+ {"DD", 0x02145}, // DOUBLE-STRUCK ITALIC CAPITAL D
+ {"dd", 0x02146}, // DOUBLE-STRUCK ITALIC SMALL D
+ {"ddagger", 0x02021}, // DOUBLE DAGGER
+ {"ddarr", 0x021CA}, // DOWNWARDS PAIRED ARROWS
+ {"DDotrahd", 0x02911}, // RIGHTWARDS ARROW WITH DOTTED STEM
+ {"ddotseq", 0x02A77}, // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW
+ {"deg", 0x000B0}, // DEGREE SIGN
+ {"Del", 0x02207}, // NABLA
+ {"Delta", 0x00394}, // GREEK CAPITAL LETTER DELTA
+ {"delta", 0x003B4}, // GREEK SMALL LETTER DELTA
+ {"demptyv", 0x029B1}, // EMPTY SET WITH OVERBAR
+ {"dfisht", 0x0297F}, // DOWN FISH TAIL
+ {"Dfr", 0x1D507}, // MATHEMATICAL FRAKTUR CAPITAL D
+ {"dfr", 0x1D521}, // MATHEMATICAL FRAKTUR SMALL D
+ {"Dgr", 0x00394}, // GREEK CAPITAL LETTER DELTA
+ {"dgr", 0x003B4}, // GREEK SMALL LETTER DELTA
+ {"dHar", 0x02965}, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
+ {"dharl", 0x021C3}, // DOWNWARDS HARPOON WITH BARB LEFTWARDS
+ {"dharr", 0x021C2}, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
+ {"DiacriticalAcute", 0x000B4}, // ACUTE ACCENT
+ {"DiacriticalDot", 0x002D9}, // DOT ABOVE
+ {"DiacriticalDoubleAcute", 0x002DD}, // DOUBLE ACUTE ACCENT
+ {"DiacriticalGrave", 0x00060}, // GRAVE ACCENT
+ {"DiacriticalTilde", 0x002DC}, // SMALL TILDE
+ {"diam", 0x022C4}, // DIAMOND OPERATOR
+ {"diamond", 0x022C4}, // DIAMOND OPERATOR
+ {"Diamond", 0x022C4}, // DIAMOND OPERATOR
+ {"diamondsuit", 0x02666}, // BLACK DIAMOND SUIT
+ {"diams", 0x02666}, // BLACK DIAMOND SUIT
+ {"die", 0x000A8}, // DIAERESIS
+ {"DifferentialD", 0x02146}, // DOUBLE-STRUCK ITALIC SMALL D
+ {"digamma", 0x003DD}, // GREEK SMALL LETTER DIGAMMA
+ {"disin", 0x022F2}, // ELEMENT OF WITH LONG HORIZONTAL STROKE
+ {"div", 0x000F7}, // DIVISION SIGN
+ {"divide", 0x000F7}, // DIVISION SIGN
+ {"divideontimes", 0x022C7}, // DIVISION TIMES
+ {"divonx", 0x022C7}, // DIVISION TIMES
+ {"DJcy", 0x00402}, // CYRILLIC CAPITAL LETTER DJE
+ {"djcy", 0x00452}, // CYRILLIC SMALL LETTER DJE
+ {"dlcorn", 0x0231E}, // BOTTOM LEFT CORNER
+ {"dlcrop", 0x0230D}, // BOTTOM LEFT CROP
+ {"dollar", 0x00024}, // DOLLAR SIGN
+ {"Dopf", 0x1D53B}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL D
+ {"dopf", 0x1D555}, // MATHEMATICAL DOUBLE-STRUCK SMALL D
+ {"Dot", 0x000A8}, // DIAERESIS
+ {"dot", 0x002D9}, // DOT ABOVE
+ {"DotDot", 0x020DC}, // COMBINING FOUR DOTS ABOVE
+ {"doteq", 0x02250}, // APPROACHES THE LIMIT
+ {"doteqdot", 0x02251}, // GEOMETRICALLY EQUAL TO
+ {"DotEqual", 0x02250}, // APPROACHES THE LIMIT
+ {"dotminus", 0x02238}, // DOT MINUS
+ {"dotplus", 0x02214}, // DOT PLUS
+ {"dotsquare", 0x022A1}, // SQUARED DOT OPERATOR
+ {"doublebarwedge", 0x02306}, // PERSPECTIVE
+ {"DoubleContourIntegral", 0x0222F}, // SURFACE INTEGRAL
+ {"DoubleDot", 0x000A8}, // DIAERESIS
+ {"DoubleDownArrow", 0x021D3}, // DOWNWARDS DOUBLE ARROW
+ {"DoubleLeftArrow", 0x021D0}, // LEFTWARDS DOUBLE ARROW
+ {"DoubleLeftRightArrow", 0x021D4}, // LEFT RIGHT DOUBLE ARROW
+ {"DoubleLeftTee", 0x02AE4}, // VERTICAL BAR DOUBLE LEFT TURNSTILE
+ {"DoubleLongLeftArrow", 0x027F8}, // LONG LEFTWARDS DOUBLE ARROW
+ {"DoubleLongLeftRightArrow", 0x027FA}, // LONG LEFT RIGHT DOUBLE ARROW
+ {"DoubleLongRightArrow", 0x027F9}, // LONG RIGHTWARDS DOUBLE ARROW
+ {"DoubleRightArrow", 0x021D2}, // RIGHTWARDS DOUBLE ARROW
+ {"DoubleRightTee", 0x022A8}, // TRUE
+ {"DoubleUpArrow", 0x021D1}, // UPWARDS DOUBLE ARROW
+ {"DoubleUpDownArrow", 0x021D5}, // UP DOWN DOUBLE ARROW
+ {"DoubleVerticalBar", 0x02225}, // PARALLEL TO
+ {"downarrow", 0x02193}, // DOWNWARDS ARROW
+ {"DownArrow", 0x02193}, // DOWNWARDS ARROW
+ {"Downarrow", 0x021D3}, // DOWNWARDS DOUBLE ARROW
+ {"DownArrowBar", 0x02913}, // DOWNWARDS ARROW TO BAR
+ {"DownArrowUpArrow", 0x021F5}, // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW
+ {"DownBreve", 0x00311}, // COMBINING INVERTED BREVE
+ {"downdownarrows", 0x021CA}, // DOWNWARDS PAIRED ARROWS
+ {"downharpoonleft", 0x021C3}, // DOWNWARDS HARPOON WITH BARB LEFTWARDS
+ {"downharpoonright", 0x021C2}, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
+ {"DownLeftRightVector", 0x02950}, // LEFT BARB DOWN RIGHT BARB DOWN HARPOON
+ {"DownLeftTeeVector", 0x0295E}, // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR
+ {"DownLeftVector", 0x021BD}, // LEFTWARDS HARPOON WITH BARB DOWNWARDS
+ {"DownLeftVectorBar", 0x02956}, // LEFTWARDS HARPOON WITH BARB DOWN TO BAR
+ {"DownRightTeeVector", 0x0295F}, // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR
+ {"DownRightVector", 0x021C1}, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
+ {"DownRightVectorBar", 0x02957}, // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR
+ {"DownTee", 0x022A4}, // DOWN TACK
+ {"DownTeeArrow", 0x021A7}, // DOWNWARDS ARROW FROM BAR
+ {"drbkarow", 0x02910}, // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW
+ {"drcorn", 0x0231F}, // BOTTOM RIGHT CORNER
+ {"drcrop", 0x0230C}, // BOTTOM RIGHT CROP
+ {"Dscr", 0x1D49F}, // MATHEMATICAL SCRIPT CAPITAL D
+ {"dscr", 0x1D4B9}, // MATHEMATICAL SCRIPT SMALL D
+ {"DScy", 0x00405}, // CYRILLIC CAPITAL LETTER DZE
+ {"dscy", 0x00455}, // CYRILLIC SMALL LETTER DZE
+ {"dsol", 0x029F6}, // SOLIDUS WITH OVERBAR
+ {"Dstrok", 0x00110}, // LATIN CAPITAL LETTER D WITH STROKE
+ {"dstrok", 0x00111}, // LATIN SMALL LETTER D WITH STROKE
+ {"dtdot", 0x022F1}, // DOWN RIGHT DIAGONAL ELLIPSIS
+ {"dtri", 0x025BF}, // WHITE DOWN-POINTING SMALL TRIANGLE
+ {"dtrif", 0x025BE}, // BLACK DOWN-POINTING SMALL TRIANGLE
+ {"duarr", 0x021F5}, // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW
+ {"duhar", 0x0296F}, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
+ {"dwangle", 0x029A6}, // OBLIQUE ANGLE OPENING UP
+ {"DZcy", 0x0040F}, // CYRILLIC CAPITAL LETTER DZHE
+ {"dzcy", 0x0045F}, // CYRILLIC SMALL LETTER DZHE
+ {"dzigrarr", 0x027FF}, // LONG RIGHTWARDS SQUIGGLE ARROW
+];
+
+immutable NameId[] namesE =
+[
+ {"Eacgr", 0x00388}, // GREEK CAPITAL LETTER EPSILON WITH TONOS
+ {"eacgr", 0x003AD}, // GREEK SMALL LETTER EPSILON WITH TONOS
+ {"Eacute", 0x000C9}, // LATIN CAPITAL LETTER E WITH ACUTE
+ {"eacute", 0x000E9}, // LATIN SMALL LETTER E WITH ACUTE
+ {"easter", 0x02A6E}, // EQUALS WITH ASTERISK
+ {"Ecaron", 0x0011A}, // LATIN CAPITAL LETTER E WITH CARON
+ {"ecaron", 0x0011B}, // LATIN SMALL LETTER E WITH CARON
+ {"ecir", 0x02256}, // RING IN EQUAL TO
+ {"Ecirc", 0x000CA}, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+ {"ecirc", 0x000EA}, // LATIN SMALL LETTER E WITH CIRCUMFLEX
+ {"ecolon", 0x02255}, // EQUALS COLON
+ {"Ecy", 0x0042D}, // CYRILLIC CAPITAL LETTER E
+ {"ecy", 0x0044D}, // CYRILLIC SMALL LETTER E
+ {"eDDot", 0x02A77}, // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW
+ {"Edot", 0x00116}, // LATIN CAPITAL LETTER E WITH DOT ABOVE
+ {"edot", 0x00117}, // LATIN SMALL LETTER E WITH DOT ABOVE
+ {"eDot", 0x02251}, // GEOMETRICALLY EQUAL TO
+ {"ee", 0x02147}, // DOUBLE-STRUCK ITALIC SMALL E
+ {"EEacgr", 0x00389}, // GREEK CAPITAL LETTER ETA WITH TONOS
+ {"eeacgr", 0x003AE}, // GREEK SMALL LETTER ETA WITH TONOS
+ {"EEgr", 0x00397}, // GREEK CAPITAL LETTER ETA
+ {"eegr", 0x003B7}, // GREEK SMALL LETTER ETA
+ {"efDot", 0x02252}, // APPROXIMATELY EQUAL TO OR THE IMAGE OF
+ {"Efr", 0x1D508}, // MATHEMATICAL FRAKTUR CAPITAL E
+ {"efr", 0x1D522}, // MATHEMATICAL FRAKTUR SMALL E
+ {"eg", 0x02A9A}, // DOUBLE-LINE EQUAL TO OR GREATER-THAN
+ {"Egr", 0x00395}, // GREEK CAPITAL LETTER EPSILON
+ {"egr", 0x003B5}, // GREEK SMALL LETTER EPSILON
+ {"Egrave", 0x000C8}, // LATIN CAPITAL LETTER E WITH GRAVE
+ {"egrave", 0x000E8}, // LATIN SMALL LETTER E WITH GRAVE
+ {"egs", 0x02A96}, // SLANTED EQUAL TO OR GREATER-THAN
+ {"egsdot", 0x02A98}, // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE
+ {"el", 0x02A99}, // DOUBLE-LINE EQUAL TO OR LESS-THAN
+ {"Element", 0x02208}, // ELEMENT OF
+ {"elinters", 0x023E7}, // ELECTRICAL INTERSECTION
+ {"ell", 0x02113}, // SCRIPT SMALL L
+ {"els", 0x02A95}, // SLANTED EQUAL TO OR LESS-THAN
+ {"elsdot", 0x02A97}, // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE
+ {"Emacr", 0x00112}, // LATIN CAPITAL LETTER E WITH MACRON
+ {"emacr", 0x00113}, // LATIN SMALL LETTER E WITH MACRON
+ {"empty", 0x02205}, // EMPTY SET
+ {"emptyset", 0x02205}, // EMPTY SET
+ {"EmptySmallSquare", 0x025FB}, // WHITE MEDIUM SQUARE
+ {"emptyv", 0x02205}, // EMPTY SET
+ {"EmptyVerySmallSquare", 0x025AB}, // WHITE SMALL SQUARE
+ {"emsp", 0x02003}, // EM SPACE
+ {"emsp13", 0x02004}, // THREE-PER-EM SPACE
+ {"emsp14", 0x02005}, // FOUR-PER-EM SPACE
+ {"ENG", 0x0014A}, // LATIN CAPITAL LETTER ENG
+ {"eng", 0x0014B}, // LATIN SMALL LETTER ENG
+ {"ensp", 0x02002}, // EN SPACE
+ {"Eogon", 0x00118}, // LATIN CAPITAL LETTER E WITH OGONEK
+ {"eogon", 0x00119}, // LATIN SMALL LETTER E WITH OGONEK
+ {"Eopf", 0x1D53C}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL E
+ {"eopf", 0x1D556}, // MATHEMATICAL DOUBLE-STRUCK SMALL E
+ {"epar", 0x022D5}, // EQUAL AND PARALLEL TO
+ {"eparsl", 0x029E3}, // EQUALS SIGN AND SLANTED PARALLEL
+ {"eplus", 0x02A71}, // EQUALS SIGN ABOVE PLUS SIGN
+ {"epsi", 0x003B5}, // GREEK SMALL LETTER EPSILON
+ {"Epsilon", 0x00395}, // GREEK CAPITAL LETTER EPSILON
+ {"epsilon", 0x003B5}, // GREEK SMALL LETTER EPSILON
+ {"epsiv", 0x003F5}, // GREEK LUNATE EPSILON SYMBOL
+ {"eqcirc", 0x02256}, // RING IN EQUAL TO
+ {"eqcolon", 0x02255}, // EQUALS COLON
+ {"eqsim", 0x02242}, // MINUS TILDE
+ {"eqslantgtr", 0x02A96}, // SLANTED EQUAL TO OR GREATER-THAN
+ {"eqslantless", 0x02A95}, // SLANTED EQUAL TO OR LESS-THAN
+ {"Equal", 0x02A75}, // TWO CONSECUTIVE EQUALS SIGNS
+ {"equals", 0x0003D}, // EQUALS SIGN
+ {"EqualTilde", 0x02242}, // MINUS TILDE
+ {"equest", 0x0225F}, // QUESTIONED EQUAL TO
+ {"Equilibrium", 0x021CC}, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
+ {"equiv", 0x02261}, // IDENTICAL TO
+ {"equivDD", 0x02A78}, // EQUIVALENT WITH FOUR DOTS ABOVE
+ {"eqvparsl", 0x029E5}, // IDENTICAL TO AND SLANTED PARALLEL
+ {"erarr", 0x02971}, // EQUALS SIGN ABOVE RIGHTWARDS ARROW
+ {"erDot", 0x02253}, // IMAGE OF OR APPROXIMATELY EQUAL TO
+ {"escr", 0x0212F}, // SCRIPT SMALL E
+ {"Escr", 0x02130}, // SCRIPT CAPITAL E
+ {"esdot", 0x02250}, // APPROACHES THE LIMIT
+ {"esim", 0x02242}, // MINUS TILDE
+ {"Esim", 0x02A73}, // EQUALS SIGN ABOVE TILDE OPERATOR
+ {"Eta", 0x00397}, // GREEK CAPITAL LETTER ETA
+ {"eta", 0x003B7}, // GREEK SMALL LETTER ETA
+ {"ETH", 0x000D0}, // LATIN CAPITAL LETTER ETH
+ {"eth", 0x000F0}, // LATIN SMALL LETTER ETH
+ {"Euml", 0x000CB}, // LATIN CAPITAL LETTER E WITH DIAERESIS
+ {"euml", 0x000EB}, // LATIN SMALL LETTER E WITH DIAERESIS
+ {"euro", 0x020AC}, // EURO SIGN
+ {"excl", 0x00021}, // EXCLAMATION MARK
+ {"exist", 0x02203}, // THERE EXISTS
+ {"Exists", 0x02203}, // THERE EXISTS
+ {"expectation", 0x02130}, // SCRIPT CAPITAL E
+ {"exponentiale", 0x02147}, // DOUBLE-STRUCK ITALIC SMALL E
+ {"ExponentialE", 0x02147}, // DOUBLE-STRUCK ITALIC SMALL E
+];
+
+immutable NameId[] namesF =
+[
+ {"fallingdotseq", 0x02252}, // APPROXIMATELY EQUAL TO OR THE IMAGE OF
+ {"Fcy", 0x00424}, // CYRILLIC CAPITAL LETTER EF
+ {"fcy", 0x00444}, // CYRILLIC SMALL LETTER EF
+ {"female", 0x02640}, // FEMALE SIGN
+ {"ffilig", 0x0FB03}, // LATIN SMALL LIGATURE FFI
+ {"fflig", 0x0FB00}, // LATIN SMALL LIGATURE FF
+ {"ffllig", 0x0FB04}, // LATIN SMALL LIGATURE FFL
+ {"Ffr", 0x1D509}, // MATHEMATICAL FRAKTUR CAPITAL F
+ {"ffr", 0x1D523}, // MATHEMATICAL FRAKTUR SMALL F
+ {"filig", 0x0FB01}, // LATIN SMALL LIGATURE FI
+ {"FilledSmallSquare", 0x025FC}, // BLACK MEDIUM SQUARE
+ {"FilledVerySmallSquare", 0x025AA}, // BLACK SMALL SQUARE
+// "fjlig", 0x00066;0x0006A}, // fj ligature
+ {"flat", 0x0266D}, // MUSIC FLAT SIGN
+ {"fllig", 0x0FB02}, // LATIN SMALL LIGATURE FL
+ {"fltns", 0x025B1}, // WHITE PARALLELOGRAM
+ {"fnof", 0x00192}, // LATIN SMALL LETTER F WITH HOOK
+ {"Fopf", 0x1D53D}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL F
+ {"fopf", 0x1D557}, // MATHEMATICAL DOUBLE-STRUCK SMALL F
+ {"forall", 0x02200}, // FOR ALL
+ {"ForAll", 0x02200}, // FOR ALL
+ {"fork", 0x022D4}, // PITCHFORK
+ {"forkv", 0x02AD9}, // ELEMENT OF OPENING DOWNWARDS
+ {"Fouriertrf", 0x02131}, // SCRIPT CAPITAL F
+ {"fpartint", 0x02A0D}, // FINITE PART INTEGRAL
+ {"frac12", 0x000BD}, // VULGAR FRACTION ONE HALF
+ {"frac13", 0x02153}, // VULGAR FRACTION ONE THIRD
+ {"frac14", 0x000BC}, // VULGAR FRACTION ONE QUARTER
+ {"frac15", 0x02155}, // VULGAR FRACTION ONE FIFTH
+ {"frac16", 0x02159}, // VULGAR FRACTION ONE SIXTH
+ {"frac18", 0x0215B}, // VULGAR FRACTION ONE EIGHTH
+ {"frac23", 0x02154}, // VULGAR FRACTION TWO THIRDS
+ {"frac25", 0x02156}, // VULGAR FRACTION TWO FIFTHS
+ {"frac34", 0x000BE}, // VULGAR FRACTION THREE QUARTERS
+ {"frac35", 0x02157}, // VULGAR FRACTION THREE FIFTHS
+ {"frac38", 0x0215C}, // VULGAR FRACTION THREE EIGHTHS
+ {"frac45", 0x02158}, // VULGAR FRACTION FOUR FIFTHS
+ {"frac56", 0x0215A}, // VULGAR FRACTION FIVE SIXTHS
+ {"frac58", 0x0215D}, // VULGAR FRACTION FIVE EIGHTHS
+ {"frac78", 0x0215E}, // VULGAR FRACTION SEVEN EIGHTHS
+ {"frasl", 0x02044}, // FRACTION SLASH
+ {"frown", 0x02322}, // FROWN
+ {"Fscr", 0x02131}, // SCRIPT CAPITAL F
+ {"fscr", 0x1D4BB}, // MATHEMATICAL SCRIPT SMALL F
+];
+
+immutable NameId[] namesG =
+[
+ {"gacute", 0x001F5}, // LATIN SMALL LETTER G WITH ACUTE
+ {"Gamma", 0x00393}, // GREEK CAPITAL LETTER GAMMA
+ {"gamma", 0x003B3}, // GREEK SMALL LETTER GAMMA
+ {"Gammad", 0x003DC}, // GREEK LETTER DIGAMMA
+ {"gammad", 0x003DD}, // GREEK SMALL LETTER DIGAMMA
+ {"gap", 0x02A86}, // GREATER-THAN OR APPROXIMATE
+ {"Gbreve", 0x0011E}, // LATIN CAPITAL LETTER G WITH BREVE
+ {"gbreve", 0x0011F}, // LATIN SMALL LETTER G WITH BREVE
+ {"Gcedil", 0x00122}, // LATIN CAPITAL LETTER G WITH CEDILLA
+ {"Gcirc", 0x0011C}, // LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+ {"gcirc", 0x0011D}, // LATIN SMALL LETTER G WITH CIRCUMFLEX
+ {"Gcy", 0x00413}, // CYRILLIC CAPITAL LETTER GHE
+ {"gcy", 0x00433}, // CYRILLIC SMALL LETTER GHE
+ {"Gdot", 0x00120}, // LATIN CAPITAL LETTER G WITH DOT ABOVE
+ {"gdot", 0x00121}, // LATIN SMALL LETTER G WITH DOT ABOVE
+ {"ge", 0x02265}, // GREATER-THAN OR EQUAL TO
+ {"gE", 0x02267}, // GREATER-THAN OVER EQUAL TO
+ {"gel", 0x022DB}, // GREATER-THAN EQUAL TO OR LESS-THAN
+ {"gEl", 0x02A8C}, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
+ {"geq", 0x02265}, // GREATER-THAN OR EQUAL TO
+ {"geqq", 0x02267}, // GREATER-THAN OVER EQUAL TO
+ {"geqslant", 0x02A7E}, // GREATER-THAN OR SLANTED EQUAL TO
+ {"ges", 0x02A7E}, // GREATER-THAN OR SLANTED EQUAL TO
+ {"gescc", 0x02AA9}, // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
+ {"gesdot", 0x02A80}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
+ {"gesdoto", 0x02A82}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
+ {"gesdotol", 0x02A84}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT
+// "gesl", 0x022DB;0x0FE00}, // GREATER-THAN slanted EQUAL TO OR LESS-THAN
+ {"gesles", 0x02A94}, // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL
+ {"Gfr", 0x1D50A}, // MATHEMATICAL FRAKTUR CAPITAL G
+ {"gfr", 0x1D524}, // MATHEMATICAL FRAKTUR SMALL G
+ {"gg", 0x0226B}, // MUCH GREATER-THAN
+ {"Gg", 0x022D9}, // VERY MUCH GREATER-THAN
+ {"ggg", 0x022D9}, // VERY MUCH GREATER-THAN
+ {"Ggr", 0x00393}, // GREEK CAPITAL LETTER GAMMA
+ {"ggr", 0x003B3}, // GREEK SMALL LETTER GAMMA
+ {"gimel", 0x02137}, // GIMEL SYMBOL
+ {"GJcy", 0x00403}, // CYRILLIC CAPITAL LETTER GJE
+ {"gjcy", 0x00453}, // CYRILLIC SMALL LETTER GJE
+ {"gl", 0x02277}, // GREATER-THAN OR LESS-THAN
+ {"gla", 0x02AA5}, // GREATER-THAN BESIDE LESS-THAN
+ {"glE", 0x02A92}, // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL
+ {"glj", 0x02AA4}, // GREATER-THAN OVERLAPPING LESS-THAN
+ {"gnap", 0x02A8A}, // GREATER-THAN AND NOT APPROXIMATE
+ {"gnapprox", 0x02A8A}, // GREATER-THAN AND NOT APPROXIMATE
+ {"gnE", 0x02269}, // GREATER-THAN BUT NOT EQUAL TO
+ {"gne", 0x02A88}, // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO
+ {"gneq", 0x02A88}, // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO
+ {"gneqq", 0x02269}, // GREATER-THAN BUT NOT EQUAL TO
+ {"gnsim", 0x022E7}, // GREATER-THAN BUT NOT EQUIVALENT TO
+ {"Gopf", 0x1D53E}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL G
+ {"gopf", 0x1D558}, // MATHEMATICAL DOUBLE-STRUCK SMALL G
+ {"grave", 0x00060}, // GRAVE ACCENT
+ {"GreaterEqual", 0x02265}, // GREATER-THAN OR EQUAL TO
+ {"GreaterEqualLess", 0x022DB}, // GREATER-THAN EQUAL TO OR LESS-THAN
+ {"GreaterFullEqual", 0x02267}, // GREATER-THAN OVER EQUAL TO
+ {"GreaterGreater", 0x02AA2}, // DOUBLE NESTED GREATER-THAN
+ {"GreaterLess", 0x02277}, // GREATER-THAN OR LESS-THAN
+ {"GreaterSlantEqual", 0x02A7E}, // GREATER-THAN OR SLANTED EQUAL TO
+ {"GreaterTilde", 0x02273}, // GREATER-THAN OR EQUIVALENT TO
+ {"gscr", 0x0210A}, // SCRIPT SMALL G
+ {"Gscr", 0x1D4A2}, // MATHEMATICAL SCRIPT CAPITAL G
+ {"gsim", 0x02273}, // GREATER-THAN OR EQUIVALENT TO
+ {"gsime", 0x02A8E}, // GREATER-THAN ABOVE SIMILAR OR EQUAL
+ {"gsiml", 0x02A90}, // GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN
+ {"gt", 0x0003E}, // GREATER-THAN SIGN
+ {"GT", 0x0003E}, // GREATER-THAN SIGN
+ {"Gt", 0x0226B}, // MUCH GREATER-THAN
+ {"gtcc", 0x02AA7}, // GREATER-THAN CLOSED BY CURVE
+ {"gtcir", 0x02A7A}, // GREATER-THAN WITH CIRCLE INSIDE
+ {"gtdot", 0x022D7}, // GREATER-THAN WITH DOT
+ {"gtlPar", 0x02995}, // DOUBLE LEFT ARC GREATER-THAN BRACKET
+ {"gtquest", 0x02A7C}, // GREATER-THAN WITH QUESTION MARK ABOVE
+ {"gtrapprox", 0x02A86}, // GREATER-THAN OR APPROXIMATE
+ {"gtrarr", 0x02978}, // GREATER-THAN ABOVE RIGHTWARDS ARROW
+ {"gtrdot", 0x022D7}, // GREATER-THAN WITH DOT
+ {"gtreqless", 0x022DB}, // GREATER-THAN EQUAL TO OR LESS-THAN
+ {"gtreqqless", 0x02A8C}, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN
+ {"gtrless", 0x02277}, // GREATER-THAN OR LESS-THAN
+ {"gtrsim", 0x02273}, // GREATER-THAN OR EQUIVALENT TO
+// "gvertneqq", 0x02269;0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke
+// "gvnE", 0x02269;0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke
+];
+
+immutable NameId[] namesH =
+[
+ {"Hacek", 0x002C7}, // CARON
+ {"hairsp", 0x0200A}, // HAIR SPACE
+ {"half", 0x000BD}, // VULGAR FRACTION ONE HALF
+ {"hamilt", 0x0210B}, // SCRIPT CAPITAL H
+ {"HARDcy", 0x0042A}, // CYRILLIC CAPITAL LETTER HARD SIGN
+ {"hardcy", 0x0044A}, // CYRILLIC SMALL LETTER HARD SIGN
+ {"harr", 0x02194}, // LEFT RIGHT ARROW
+ {"hArr", 0x021D4}, // LEFT RIGHT DOUBLE ARROW
+ {"harrcir", 0x02948}, // LEFT RIGHT ARROW THROUGH SMALL CIRCLE
+ {"harrw", 0x021AD}, // LEFT RIGHT WAVE ARROW
+ {"Hat", 0x0005E}, // CIRCUMFLEX ACCENT
+ {"hbar", 0x0210F}, // PLANCK CONSTANT OVER TWO PI
+ {"Hcirc", 0x00124}, // LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+ {"hcirc", 0x00125}, // LATIN SMALL LETTER H WITH CIRCUMFLEX
+ {"hearts", 0x02665}, // BLACK HEART SUIT
+ {"heartsuit", 0x02665}, // BLACK HEART SUIT
+ {"hellip", 0x02026}, // HORIZONTAL ELLIPSIS
+ {"hercon", 0x022B9}, // HERMITIAN CONJUGATE MATRIX
+ {"Hfr", 0x0210C}, // BLACK-LETTER CAPITAL H
+ {"hfr", 0x1D525}, // MATHEMATICAL FRAKTUR SMALL H
+ {"HilbertSpace", 0x0210B}, // SCRIPT CAPITAL H
+ {"hksearow", 0x02925}, // SOUTH EAST ARROW WITH HOOK
+ {"hkswarow", 0x02926}, // SOUTH WEST ARROW WITH HOOK
+ {"hoarr", 0x021FF}, // LEFT RIGHT OPEN-HEADED ARROW
+ {"homtht", 0x0223B}, // HOMOTHETIC
+ {"hookleftarrow", 0x021A9}, // LEFTWARDS ARROW WITH HOOK
+ {"hookrightarrow", 0x021AA}, // RIGHTWARDS ARROW WITH HOOK
+ {"Hopf", 0x0210D}, // DOUBLE-STRUCK CAPITAL H
+ {"hopf", 0x1D559}, // MATHEMATICAL DOUBLE-STRUCK SMALL H
+ {"horbar", 0x02015}, // HORIZONTAL BAR
+ {"HorizontalLine", 0x02500}, // BOX DRAWINGS LIGHT HORIZONTAL
+ {"Hscr", 0x0210B}, // SCRIPT CAPITAL H
+ {"hscr", 0x1D4BD}, // MATHEMATICAL SCRIPT SMALL H
+ {"hslash", 0x0210F}, // PLANCK CONSTANT OVER TWO PI
+ {"Hstrok", 0x00126}, // LATIN CAPITAL LETTER H WITH STROKE
+ {"hstrok", 0x00127}, // LATIN SMALL LETTER H WITH STROKE
+ {"HumpDownHump", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO
+ {"HumpEqual", 0x0224F}, // DIFFERENCE BETWEEN
+ {"hybull", 0x02043}, // HYPHEN BULLET
+ {"hyphen", 0x02010}, // HYPHEN
+];
+
+immutable NameId[] namesI =
+[
+ {"Iacgr", 0x0038A}, // GREEK CAPITAL LETTER IOTA WITH TONOS
+ {"iacgr", 0x003AF}, // GREEK SMALL LETTER IOTA WITH TONOS
+ {"Iacute", 0x000CD}, // LATIN CAPITAL LETTER I WITH ACUTE
+ {"iacute", 0x000ED}, // LATIN SMALL LETTER I WITH ACUTE
+ {"ic", 0x02063}, // INVISIBLE SEPARATOR
+ {"Icirc", 0x000CE}, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+ {"icirc", 0x000EE}, // LATIN SMALL LETTER I WITH CIRCUMFLEX
+ {"Icy", 0x00418}, // CYRILLIC CAPITAL LETTER I
+ {"icy", 0x00438}, // CYRILLIC SMALL LETTER I
+ {"idiagr", 0x00390}, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+ {"Idigr", 0x003AA}, // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+ {"idigr", 0x003CA}, // GREEK SMALL LETTER IOTA WITH DIALYTIKA
+ {"Idot", 0x00130}, // LATIN CAPITAL LETTER I WITH DOT ABOVE
+ {"IEcy", 0x00415}, // CYRILLIC CAPITAL LETTER IE
+ {"iecy", 0x00435}, // CYRILLIC SMALL LETTER IE
+ {"iexcl", 0x000A1}, // INVERTED EXCLAMATION MARK
+ {"iff", 0x021D4}, // LEFT RIGHT DOUBLE ARROW
+ {"Ifr", 0x02111}, // BLACK-LETTER CAPITAL I
+ {"ifr", 0x1D526}, // MATHEMATICAL FRAKTUR SMALL I
+ {"Igr", 0x00399}, // GREEK CAPITAL LETTER IOTA
+ {"igr", 0x003B9}, // GREEK SMALL LETTER IOTA
+ {"Igrave", 0x000CC}, // LATIN CAPITAL LETTER I WITH GRAVE
+ {"igrave", 0x000EC}, // LATIN SMALL LETTER I WITH GRAVE
+ {"ii", 0x02148}, // DOUBLE-STRUCK ITALIC SMALL I
+ {"iiiint", 0x02A0C}, // QUADRUPLE INTEGRAL OPERATOR
+ {"iiint", 0x0222D}, // TRIPLE INTEGRAL
+ {"iinfin", 0x029DC}, // INCOMPLETE INFINITY
+ {"iiota", 0x02129}, // TURNED GREEK SMALL LETTER IOTA
+ {"IJlig", 0x00132}, // LATIN CAPITAL LIGATURE IJ
+ {"ijlig", 0x00133}, // LATIN SMALL LIGATURE IJ
+ {"Im", 0x02111}, // BLACK-LETTER CAPITAL I
+ {"Imacr", 0x0012A}, // LATIN CAPITAL LETTER I WITH MACRON
+ {"imacr", 0x0012B}, // LATIN SMALL LETTER I WITH MACRON
+ {"image", 0x02111}, // BLACK-LETTER CAPITAL I
+ {"ImaginaryI", 0x02148}, // DOUBLE-STRUCK ITALIC SMALL I
+ {"imagline", 0x02110}, // SCRIPT CAPITAL I
+ {"imagpart", 0x02111}, // BLACK-LETTER CAPITAL I
+ {"imath", 0x00131}, // LATIN SMALL LETTER DOTLESS I
+ {"imof", 0x022B7}, // IMAGE OF
+ {"imped", 0x001B5}, // LATIN CAPITAL LETTER Z WITH STROKE
+ {"Implies", 0x021D2}, // RIGHTWARDS DOUBLE ARROW
+ {"in", 0x02208}, // ELEMENT OF
+ {"incare", 0x02105}, // CARE OF
+ {"infin", 0x0221E}, // INFINITY
+ {"infintie", 0x029DD}, // TIE OVER INFINITY
+ {"inodot", 0x00131}, // LATIN SMALL LETTER DOTLESS I
+ {"int", 0x0222B}, // INTEGRAL
+ {"Int", 0x0222C}, // DOUBLE INTEGRAL
+ {"intcal", 0x022BA}, // INTERCALATE
+ {"integers", 0x02124}, // DOUBLE-STRUCK CAPITAL Z
+ {"Integral", 0x0222B}, // INTEGRAL
+ {"intercal", 0x022BA}, // INTERCALATE
+ {"Intersection", 0x022C2}, // N-ARY INTERSECTION
+ {"intlarhk", 0x02A17}, // INTEGRAL WITH LEFTWARDS ARROW WITH HOOK
+ {"intprod", 0x02A3C}, // INTERIOR PRODUCT
+ {"InvisibleComma", 0x02063}, // INVISIBLE SEPARATOR
+ {"InvisibleTimes", 0x02062}, // INVISIBLE TIMES
+ {"IOcy", 0x00401}, // CYRILLIC CAPITAL LETTER IO
+ {"iocy", 0x00451}, // CYRILLIC SMALL LETTER IO
+ {"Iogon", 0x0012E}, // LATIN CAPITAL LETTER I WITH OGONEK
+ {"iogon", 0x0012F}, // LATIN SMALL LETTER I WITH OGONEK
+ {"Iopf", 0x1D540}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL I
+ {"iopf", 0x1D55A}, // MATHEMATICAL DOUBLE-STRUCK SMALL I
+ {"Iota", 0x00399}, // GREEK CAPITAL LETTER IOTA
+ {"iota", 0x003B9}, // GREEK SMALL LETTER IOTA
+ {"iprod", 0x02A3C}, // INTERIOR PRODUCT
+ {"iquest", 0x000BF}, // INVERTED QUESTION MARK
+ {"Iscr", 0x02110}, // SCRIPT CAPITAL I
+ {"iscr", 0x1D4BE}, // MATHEMATICAL SCRIPT SMALL I
+ {"isin", 0x02208}, // ELEMENT OF
+ {"isindot", 0x022F5}, // ELEMENT OF WITH DOT ABOVE
+ {"isinE", 0x022F9}, // ELEMENT OF WITH TWO HORIZONTAL STROKES
+ {"isins", 0x022F4}, // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+ {"isinsv", 0x022F3}, // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+ {"isinv", 0x02208}, // ELEMENT OF
+ {"it", 0x02062}, // INVISIBLE TIMES
+ {"Itilde", 0x00128}, // LATIN CAPITAL LETTER I WITH TILDE
+ {"itilde", 0x00129}, // LATIN SMALL LETTER I WITH TILDE
+ {"Iukcy", 0x00406}, // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+ {"iukcy", 0x00456}, // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ {"Iuml", 0x000CF}, // LATIN CAPITAL LETTER I WITH DIAERESIS
+ {"iuml", 0x000EF}, // LATIN SMALL LETTER I WITH DIAERESIS
+];
+
+immutable NameId[] namesJ =
+[
+ {"Jcirc", 0x00134}, // LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+ {"jcirc", 0x00135}, // LATIN SMALL LETTER J WITH CIRCUMFLEX
+ {"Jcy", 0x00419}, // CYRILLIC CAPITAL LETTER SHORT I
+ {"jcy", 0x00439}, // CYRILLIC SMALL LETTER SHORT I
+ {"Jfr", 0x1D50D}, // MATHEMATICAL FRAKTUR CAPITAL J
+ {"jfr", 0x1D527}, // MATHEMATICAL FRAKTUR SMALL J
+ {"jmath", 0x00237}, // LATIN SMALL LETTER DOTLESS J
+ {"Jopf", 0x1D541}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL J
+ {"jopf", 0x1D55B}, // MATHEMATICAL DOUBLE-STRUCK SMALL J
+ {"Jscr", 0x1D4A5}, // MATHEMATICAL SCRIPT CAPITAL J
+ {"jscr", 0x1D4BF}, // MATHEMATICAL SCRIPT SMALL J
+ {"Jsercy", 0x00408}, // CYRILLIC CAPITAL LETTER JE
+ {"jsercy", 0x00458}, // CYRILLIC SMALL LETTER JE
+ {"Jukcy", 0x00404}, // CYRILLIC CAPITAL LETTER UKRAINIAN IE
+ {"jukcy", 0x00454}, // CYRILLIC SMALL LETTER UKRAINIAN IE
+];
+
+immutable NameId[] namesK =
+[
+ {"Kappa", 0x0039A}, // GREEK CAPITAL LETTER KAPPA
+ {"kappa", 0x003BA}, // GREEK SMALL LETTER KAPPA
+ {"kappav", 0x003F0}, // GREEK KAPPA SYMBOL
+ {"Kcedil", 0x00136}, // LATIN CAPITAL LETTER K WITH CEDILLA
+ {"kcedil", 0x00137}, // LATIN SMALL LETTER K WITH CEDILLA
+ {"Kcy", 0x0041A}, // CYRILLIC CAPITAL LETTER KA
+ {"kcy", 0x0043A}, // CYRILLIC SMALL LETTER KA
+ {"Kfr", 0x1D50E}, // MATHEMATICAL FRAKTUR CAPITAL K
+ {"kfr", 0x1D528}, // MATHEMATICAL FRAKTUR SMALL K
+ {"Kgr", 0x0039A}, // GREEK CAPITAL LETTER KAPPA
+ {"kgr", 0x003BA}, // GREEK SMALL LETTER KAPPA
+ {"kgreen", 0x00138}, // LATIN SMALL LETTER KRA
+ {"KHcy", 0x00425}, // CYRILLIC CAPITAL LETTER HA
+ {"khcy", 0x00445}, // CYRILLIC SMALL LETTER HA
+ {"KHgr", 0x003A7}, // GREEK CAPITAL LETTER CHI
+ {"khgr", 0x003C7}, // GREEK SMALL LETTER CHI
+ {"KJcy", 0x0040C}, // CYRILLIC CAPITAL LETTER KJE
+ {"kjcy", 0x0045C}, // CYRILLIC SMALL LETTER KJE
+ {"Kopf", 0x1D542}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL K
+ {"kopf", 0x1D55C}, // MATHEMATICAL DOUBLE-STRUCK SMALL K
+ {"Kscr", 0x1D4A6}, // MATHEMATICAL SCRIPT CAPITAL K
+ {"kscr", 0x1D4C0}, // MATHEMATICAL SCRIPT SMALL K
+];
+
+immutable NameId[] namesL =
+[
+ {"lAarr", 0x021DA}, // LEFTWARDS TRIPLE ARROW
+ {"Lacute", 0x00139}, // LATIN CAPITAL LETTER L WITH ACUTE
+ {"lacute", 0x0013A}, // LATIN SMALL LETTER L WITH ACUTE
+ {"laemptyv", 0x029B4}, // EMPTY SET WITH LEFT ARROW ABOVE
+ {"lagran", 0x02112}, // SCRIPT CAPITAL L
+ {"Lambda", 0x0039B}, // GREEK CAPITAL LETTER LAMDA
+ {"lambda", 0x003BB}, // GREEK SMALL LETTER LAMDA
+ {"lang", 0x027E8}, // MATHEMATICAL LEFT ANGLE BRACKET
+ {"Lang", 0x027EA}, // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+ {"langd", 0x02991}, // LEFT ANGLE BRACKET WITH DOT
+ {"langle", 0x027E8}, // MATHEMATICAL LEFT ANGLE BRACKET
+ {"lap", 0x02A85}, // LESS-THAN OR APPROXIMATE
+ {"Laplacetrf", 0x02112}, // SCRIPT CAPITAL L
+ {"laquo", 0x000AB}, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
+ {"larr", 0x02190}, // LEFTWARDS ARROW
+ {"Larr", 0x0219E}, // LEFTWARDS TWO HEADED ARROW
+ {"lArr", 0x021D0}, // LEFTWARDS DOUBLE ARROW
+ {"larrb", 0x021E4}, // LEFTWARDS ARROW TO BAR
+ {"larrbfs", 0x0291F}, // LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND
+ {"larrfs", 0x0291D}, // LEFTWARDS ARROW TO BLACK DIAMOND
+ {"larrhk", 0x021A9}, // LEFTWARDS ARROW WITH HOOK
+ {"larrlp", 0x021AB}, // LEFTWARDS ARROW WITH LOOP
+ {"larrpl", 0x02939}, // LEFT-SIDE ARC ANTICLOCKWISE ARROW
+ {"larrsim", 0x02973}, // LEFTWARDS ARROW ABOVE TILDE OPERATOR
+ {"larrtl", 0x021A2}, // LEFTWARDS ARROW WITH TAIL
+ {"lat", 0x02AAB}, // LARGER THAN
+ {"latail", 0x02919}, // LEFTWARDS ARROW-TAIL
+ {"lAtail", 0x0291B}, // LEFTWARDS DOUBLE ARROW-TAIL
+ {"late", 0x02AAD}, // LARGER THAN OR EQUAL TO
+// "lates", 0x02AAD;0x0FE00}, // LARGER THAN OR slanted EQUAL
+ {"lbarr", 0x0290C}, // LEFTWARDS DOUBLE DASH ARROW
+ {"lBarr", 0x0290E}, // LEFTWARDS TRIPLE DASH ARROW
+ {"lbbrk", 0x02772}, // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT
+ {"lbrace", 0x0007B}, // LEFT CURLY BRACKET
+ {"lbrack", 0x0005B}, // LEFT SQUARE BRACKET
+ {"lbrke", 0x0298B}, // LEFT SQUARE BRACKET WITH UNDERBAR
+ {"lbrksld", 0x0298F}, // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+ {"lbrkslu", 0x0298D}, // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER
+ {"Lcaron", 0x0013D}, // LATIN CAPITAL LETTER L WITH CARON
+ {"lcaron", 0x0013E}, // LATIN SMALL LETTER L WITH CARON
+ {"Lcedil", 0x0013B}, // LATIN CAPITAL LETTER L WITH CEDILLA
+ {"lcedil", 0x0013C}, // LATIN SMALL LETTER L WITH CEDILLA
+ {"lceil", 0x02308}, // LEFT CEILING
+ {"lcub", 0x0007B}, // LEFT CURLY BRACKET
+ {"Lcy", 0x0041B}, // CYRILLIC CAPITAL LETTER EL
+ {"lcy", 0x0043B}, // CYRILLIC SMALL LETTER EL
+ {"ldca", 0x02936}, // ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS
+ {"ldquo", 0x0201C}, // LEFT DOUBLE QUOTATION MARK
+ {"ldquor", 0x0201E}, // DOUBLE LOW-9 QUOTATION MARK
+ {"ldrdhar", 0x02967}, // LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN
+ {"ldrushar", 0x0294B}, // LEFT BARB DOWN RIGHT BARB UP HARPOON
+ {"ldsh", 0x021B2}, // DOWNWARDS ARROW WITH TIP LEFTWARDS
+ {"le", 0x02264}, // LESS-THAN OR EQUAL TO
+ {"lE", 0x02266}, // LESS-THAN OVER EQUAL TO
+ {"LeftAngleBracket", 0x027E8}, // MATHEMATICAL LEFT ANGLE BRACKET
+ {"leftarrow", 0x02190}, // LEFTWARDS ARROW
+ {"LeftArrow", 0x02190}, // LEFTWARDS ARROW
+ {"Leftarrow", 0x021D0}, // LEFTWARDS DOUBLE ARROW
+ {"LeftArrowBar", 0x021E4}, // LEFTWARDS ARROW TO BAR
+ {"LeftArrowRightArrow", 0x021C6}, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
+ {"leftarrowtail", 0x021A2}, // LEFTWARDS ARROW WITH TAIL
+ {"LeftCeiling", 0x02308}, // LEFT CEILING
+ {"LeftDoubleBracket", 0x027E6}, // MATHEMATICAL LEFT WHITE SQUARE BRACKET
+ {"LeftDownTeeVector", 0x02961}, // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR
+ {"LeftDownVector", 0x021C3}, // DOWNWARDS HARPOON WITH BARB LEFTWARDS
+ {"LeftDownVectorBar", 0x02959}, // DOWNWARDS HARPOON WITH BARB LEFT TO BAR
+ {"LeftFloor", 0x0230A}, // LEFT FLOOR
+ {"leftharpoondown", 0x021BD}, // LEFTWARDS HARPOON WITH BARB DOWNWARDS
+ {"leftharpoonup", 0x021BC}, // LEFTWARDS HARPOON WITH BARB UPWARDS
+ {"leftleftarrows", 0x021C7}, // LEFTWARDS PAIRED ARROWS
+ {"leftrightarrow", 0x02194}, // LEFT RIGHT ARROW
+ {"LeftRightArrow", 0x02194}, // LEFT RIGHT ARROW
+ {"Leftrightarrow", 0x021D4}, // LEFT RIGHT DOUBLE ARROW
+ {"leftrightarrows", 0x021C6}, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
+ {"leftrightharpoons", 0x021CB}, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
+ {"leftrightsquigarrow", 0x021AD}, // LEFT RIGHT WAVE ARROW
+ {"LeftRightVector", 0x0294E}, // LEFT BARB UP RIGHT BARB UP HARPOON
+ {"LeftTee", 0x022A3}, // LEFT TACK
+ {"LeftTeeArrow", 0x021A4}, // LEFTWARDS ARROW FROM BAR
+ {"LeftTeeVector", 0x0295A}, // LEFTWARDS HARPOON WITH BARB UP FROM BAR
+ {"leftthreetimes", 0x022CB}, // LEFT SEMIDIRECT PRODUCT
+ {"LeftTriangle", 0x022B2}, // NORMAL SUBGROUP OF
+ {"LeftTriangleBar", 0x029CF}, // LEFT TRIANGLE BESIDE VERTICAL BAR
+ {"LeftTriangleEqual", 0x022B4}, // NORMAL SUBGROUP OF OR EQUAL TO
+ {"LeftUpDownVector", 0x02951}, // UP BARB LEFT DOWN BARB LEFT HARPOON
+ {"LeftUpTeeVector", 0x02960}, // UPWARDS HARPOON WITH BARB LEFT FROM BAR
+ {"LeftUpVector", 0x021BF}, // UPWARDS HARPOON WITH BARB LEFTWARDS
+ {"LeftUpVectorBar", 0x02958}, // UPWARDS HARPOON WITH BARB LEFT TO BAR
+ {"LeftVector", 0x021BC}, // LEFTWARDS HARPOON WITH BARB UPWARDS
+ {"LeftVectorBar", 0x02952}, // LEFTWARDS HARPOON WITH BARB UP TO BAR
+ {"leg", 0x022DA}, // LESS-THAN EQUAL TO OR GREATER-THAN
+ {"lEg", 0x02A8B}, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN
+ {"leq", 0x02264}, // LESS-THAN OR EQUAL TO
+ {"leqq", 0x02266}, // LESS-THAN OVER EQUAL TO
+ {"leqslant", 0x02A7D}, // LESS-THAN OR SLANTED EQUAL TO
+ {"les", 0x02A7D}, // LESS-THAN OR SLANTED EQUAL TO
+ {"lescc", 0x02AA8}, // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL
+ {"lesdot", 0x02A7F}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE
+ {"lesdoto", 0x02A81}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE
+ {"lesdotor", 0x02A83}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT
+// "lesg", 0x022DA;0x0FE00}, // LESS-THAN slanted EQUAL TO OR GREATER-THAN
+ {"lesges", 0x02A93}, // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL
+ {"lessapprox", 0x02A85}, // LESS-THAN OR APPROXIMATE
+ {"lessdot", 0x022D6}, // LESS-THAN WITH DOT
+ {"lesseqgtr", 0x022DA}, // LESS-THAN EQUAL TO OR GREATER-THAN
+ {"lesseqqgtr", 0x02A8B}, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN
+ {"LessEqualGreater", 0x022DA}, // LESS-THAN EQUAL TO OR GREATER-THAN
+ {"LessFullEqual", 0x02266}, // LESS-THAN OVER EQUAL TO
+ {"LessGreater", 0x02276}, // LESS-THAN OR GREATER-THAN
+ {"lessgtr", 0x02276}, // LESS-THAN OR GREATER-THAN
+ {"LessLess", 0x02AA1}, // DOUBLE NESTED LESS-THAN
+ {"lesssim", 0x02272}, // LESS-THAN OR EQUIVALENT TO
+ {"LessSlantEqual", 0x02A7D}, // LESS-THAN OR SLANTED EQUAL TO
+ {"LessTilde", 0x02272}, // LESS-THAN OR EQUIVALENT TO
+ {"lfisht", 0x0297C}, // LEFT FISH TAIL
+ {"lfloor", 0x0230A}, // LEFT FLOOR
+ {"Lfr", 0x1D50F}, // MATHEMATICAL FRAKTUR CAPITAL L
+ {"lfr", 0x1D529}, // MATHEMATICAL FRAKTUR SMALL L
+ {"lg", 0x02276}, // LESS-THAN OR GREATER-THAN
+ {"lgE", 0x02A91}, // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL
+ {"Lgr", 0x0039B}, // GREEK CAPITAL LETTER LAMDA
+ {"lgr", 0x003BB}, // GREEK SMALL LETTER LAMDA
+ {"lHar", 0x02962}, // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN
+ {"lhard", 0x021BD}, // LEFTWARDS HARPOON WITH BARB DOWNWARDS
+ {"lharu", 0x021BC}, // LEFTWARDS HARPOON WITH BARB UPWARDS
+ {"lharul", 0x0296A}, // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH
+ {"lhblk", 0x02584}, // LOWER HALF BLOCK
+ {"LJcy", 0x00409}, // CYRILLIC CAPITAL LETTER LJE
+ {"ljcy", 0x00459}, // CYRILLIC SMALL LETTER LJE
+ {"ll", 0x0226A}, // MUCH LESS-THAN
+ {"Ll", 0x022D8}, // VERY MUCH LESS-THAN
+ {"llarr", 0x021C7}, // LEFTWARDS PAIRED ARROWS
+ {"llcorner", 0x0231E}, // BOTTOM LEFT CORNER
+ {"Lleftarrow", 0x021DA}, // LEFTWARDS TRIPLE ARROW
+ {"llhard", 0x0296B}, // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH
+ {"lltri", 0x025FA}, // LOWER LEFT TRIANGLE
+ {"Lmidot", 0x0013F}, // LATIN CAPITAL LETTER L WITH MIDDLE DOT
+ {"lmidot", 0x00140}, // LATIN SMALL LETTER L WITH MIDDLE DOT
+ {"lmoust", 0x023B0}, // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION
+ {"lmoustache", 0x023B0}, // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION
+ {"lnap", 0x02A89}, // LESS-THAN AND NOT APPROXIMATE
+ {"lnapprox", 0x02A89}, // LESS-THAN AND NOT APPROXIMATE
+ {"lnE", 0x02268}, // LESS-THAN BUT NOT EQUAL TO
+ {"lne", 0x02A87}, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO
+ {"lneq", 0x02A87}, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO
+ {"lneqq", 0x02268}, // LESS-THAN BUT NOT EQUAL TO
+ {"lnsim", 0x022E6}, // LESS-THAN BUT NOT EQUIVALENT TO
+ {"loang", 0x027EC}, // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET
+ {"loarr", 0x021FD}, // LEFTWARDS OPEN-HEADED ARROW
+ {"lobrk", 0x027E6}, // MATHEMATICAL LEFT WHITE SQUARE BRACKET
+ {"longleftarrow", 0x027F5}, // LONG LEFTWARDS ARROW
+ {"LongLeftArrow", 0x027F5}, // LONG LEFTWARDS ARROW
+ {"Longleftarrow", 0x027F8}, // LONG LEFTWARDS DOUBLE ARROW
+ {"longleftrightarrow", 0x027F7}, // LONG LEFT RIGHT ARROW
+ {"LongLeftRightArrow", 0x027F7}, // LONG LEFT RIGHT ARROW
+ {"Longleftrightarrow", 0x027FA}, // LONG LEFT RIGHT DOUBLE ARROW
+ {"longmapsto", 0x027FC}, // LONG RIGHTWARDS ARROW FROM BAR
+ {"longrightarrow", 0x027F6}, // LONG RIGHTWARDS ARROW
+ {"LongRightArrow", 0x027F6}, // LONG RIGHTWARDS ARROW
+ {"Longrightarrow", 0x027F9}, // LONG RIGHTWARDS DOUBLE ARROW
+ {"looparrowleft", 0x021AB}, // LEFTWARDS ARROW WITH LOOP
+ {"looparrowright", 0x021AC}, // RIGHTWARDS ARROW WITH LOOP
+ {"lopar", 0x02985}, // LEFT WHITE PARENTHESIS
+ {"Lopf", 0x1D543}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL L
+ {"lopf", 0x1D55D}, // MATHEMATICAL DOUBLE-STRUCK SMALL L
+ {"loplus", 0x02A2D}, // PLUS SIGN IN LEFT HALF CIRCLE
+ {"lotimes", 0x02A34}, // MULTIPLICATION SIGN IN LEFT HALF CIRCLE
+ {"lowast", 0x02217}, // ASTERISK OPERATOR
+ {"lowbar", 0x0005F}, // LOW LINE
+ {"LowerLeftArrow", 0x02199}, // SOUTH WEST ARROW
+ {"LowerRightArrow", 0x02198}, // SOUTH EAST ARROW
+ {"loz", 0x025CA}, // LOZENGE
+ {"lozenge", 0x025CA}, // LOZENGE
+ {"lozf", 0x029EB}, // BLACK LOZENGE
+ {"lpar", 0x00028}, // LEFT PARENTHESIS
+ {"lparlt", 0x02993}, // LEFT ARC LESS-THAN BRACKET
+ {"lrarr", 0x021C6}, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW
+ {"lrcorner", 0x0231F}, // BOTTOM RIGHT CORNER
+ {"lrhar", 0x021CB}, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
+ {"lrhard", 0x0296D}, // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH
+ {"lrm", 0x0200E}, // LEFT-TO-RIGHT MARK
+ {"lrtri", 0x022BF}, // RIGHT TRIANGLE
+ {"lsaquo", 0x02039}, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
+ {"Lscr", 0x02112}, // SCRIPT CAPITAL L
+ {"lscr", 0x1D4C1}, // MATHEMATICAL SCRIPT SMALL L
+ {"lsh", 0x021B0}, // UPWARDS ARROW WITH TIP LEFTWARDS
+ {"Lsh", 0x021B0}, // UPWARDS ARROW WITH TIP LEFTWARDS
+ {"lsim", 0x02272}, // LESS-THAN OR EQUIVALENT TO
+ {"lsime", 0x02A8D}, // LESS-THAN ABOVE SIMILAR OR EQUAL
+ {"lsimg", 0x02A8F}, // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN
+ {"lsqb", 0x0005B}, // LEFT SQUARE BRACKET
+ {"lsquo", 0x02018}, // LEFT SINGLE QUOTATION MARK
+ {"lsquor", 0x0201A}, // SINGLE LOW-9 QUOTATION MARK
+ {"Lstrok", 0x00141}, // LATIN CAPITAL LETTER L WITH STROKE
+ {"lstrok", 0x00142}, // LATIN SMALL LETTER L WITH STROKE
+ {"lt", 0x0003C}, // LESS-THAN SIGN
+ {"LT", 0x0003C}, // LESS-THAN SIGN
+ {"Lt", 0x0226A}, // MUCH LESS-THAN
+ {"ltcc", 0x02AA6}, // LESS-THAN CLOSED BY CURVE
+ {"ltcir", 0x02A79}, // LESS-THAN WITH CIRCLE INSIDE
+ {"ltdot", 0x022D6}, // LESS-THAN WITH DOT
+ {"lthree", 0x022CB}, // LEFT SEMIDIRECT PRODUCT
+ {"ltimes", 0x022C9}, // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT
+ {"ltlarr", 0x02976}, // LESS-THAN ABOVE LEFTWARDS ARROW
+ {"ltquest", 0x02A7B}, // LESS-THAN WITH QUESTION MARK ABOVE
+ {"ltri", 0x025C3}, // WHITE LEFT-POINTING SMALL TRIANGLE
+ {"ltrie", 0x022B4}, // NORMAL SUBGROUP OF OR EQUAL TO
+ {"ltrif", 0x025C2}, // BLACK LEFT-POINTING SMALL TRIANGLE
+ {"ltrPar", 0x02996}, // DOUBLE RIGHT ARC LESS-THAN BRACKET
+ {"lurdshar", 0x0294A}, // LEFT BARB UP RIGHT BARB DOWN HARPOON
+ {"luruhar", 0x02966}, // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP
+// "lvertneqq", 0x02268;0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke
+// "lvnE", 0x02268;0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke
+];
+
+immutable NameId[] namesM =
+[
+ {"macr", 0x000AF}, // MACRON
+ {"male", 0x02642}, // MALE SIGN
+ {"malt", 0x02720}, // MALTESE CROSS
+ {"maltese", 0x02720}, // MALTESE CROSS
+ {"map", 0x021A6}, // RIGHTWARDS ARROW FROM BAR
+ {"Map", 0x02905}, // RIGHTWARDS TWO-HEADED ARROW FROM BAR
+ {"mapsto", 0x021A6}, // RIGHTWARDS ARROW FROM BAR
+ {"mapstodown", 0x021A7}, // DOWNWARDS ARROW FROM BAR
+ {"mapstoleft", 0x021A4}, // LEFTWARDS ARROW FROM BAR
+ {"mapstoup", 0x021A5}, // UPWARDS ARROW FROM BAR
+ {"marker", 0x025AE}, // BLACK VERTICAL RECTANGLE
+ {"mcomma", 0x02A29}, // MINUS SIGN WITH COMMA ABOVE
+ {"Mcy", 0x0041C}, // CYRILLIC CAPITAL LETTER EM
+ {"mcy", 0x0043C}, // CYRILLIC SMALL LETTER EM
+ {"mdash", 0x02014}, // EM DASH
+ {"mDDot", 0x0223A}, // GEOMETRIC PROPORTION
+ {"measuredangle", 0x02221}, // MEASURED ANGLE
+ {"MediumSpace", 0x0205F}, // MEDIUM MATHEMATICAL SPACE
+ {"Mellintrf", 0x02133}, // SCRIPT CAPITAL M
+ {"Mfr", 0x1D510}, // MATHEMATICAL FRAKTUR CAPITAL M
+ {"mfr", 0x1D52A}, // MATHEMATICAL FRAKTUR SMALL M
+ {"Mgr", 0x0039C}, // GREEK CAPITAL LETTER MU
+ {"mgr", 0x003BC}, // GREEK SMALL LETTER MU
+ {"mho", 0x02127}, // INVERTED OHM SIGN
+ {"micro", 0x000B5}, // MICRO SIGN
+ {"mid", 0x02223}, // DIVIDES
+ {"midast", 0x0002A}, // ASTERISK
+ {"midcir", 0x02AF0}, // VERTICAL LINE WITH CIRCLE BELOW
+ {"middot", 0x000B7}, // MIDDLE DOT
+ {"minus", 0x02212}, // MINUS SIGN
+ {"minusb", 0x0229F}, // SQUARED MINUS
+ {"minusd", 0x02238}, // DOT MINUS
+ {"minusdu", 0x02A2A}, // MINUS SIGN WITH DOT BELOW
+ {"MinusPlus", 0x02213}, // MINUS-OR-PLUS SIGN
+ {"mlcp", 0x02ADB}, // TRANSVERSAL INTERSECTION
+ {"mldr", 0x02026}, // HORIZONTAL ELLIPSIS
+ {"mnplus", 0x02213}, // MINUS-OR-PLUS SIGN
+ {"models", 0x022A7}, // MODELS
+ {"Mopf", 0x1D544}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL M
+ {"mopf", 0x1D55E}, // MATHEMATICAL DOUBLE-STRUCK SMALL M
+ {"mp", 0x02213}, // MINUS-OR-PLUS SIGN
+ {"Mscr", 0x02133}, // SCRIPT CAPITAL M
+ {"mscr", 0x1D4C2}, // MATHEMATICAL SCRIPT SMALL M
+ {"mstpos", 0x0223E}, // INVERTED LAZY S
+ {"Mu", 0x0039C}, // GREEK CAPITAL LETTER MU
+ {"mu", 0x003BC}, // GREEK SMALL LETTER MU
+ {"multimap", 0x022B8}, // MULTIMAP
+ {"mumap", 0x022B8}, // MULTIMAP
+];
+
+immutable NameId[] namesN =
+[
+ {"nabla", 0x02207}, // NABLA
+ {"Nacute", 0x00143}, // LATIN CAPITAL LETTER N WITH ACUTE
+ {"nacute", 0x00144}, // LATIN SMALL LETTER N WITH ACUTE
+// "nang", 0x02220;0x020D2}, // ANGLE with vertical line
+ {"nap", 0x02249}, // NOT ALMOST EQUAL TO
+// "napE", 0x02A70;0x00338}, // APPROXIMATELY EQUAL OR EQUAL TO with slash
+// "napid", 0x0224B;0x00338}, // TRIPLE TILDE with slash
+ {"napos", 0x00149}, // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+ {"napprox", 0x02249}, // NOT ALMOST EQUAL TO
+ {"natur", 0x0266E}, // MUSIC NATURAL SIGN
+ {"natural", 0x0266E}, // MUSIC NATURAL SIGN
+ {"naturals", 0x02115}, // DOUBLE-STRUCK CAPITAL N
+ {"nbsp", 0x000A0}, // NO-BREAK SPACE
+// "nbump", 0x0224E;0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash
+// "nbumpe", 0x0224F;0x00338}, // DIFFERENCE BETWEEN with slash
+ {"ncap", 0x02A43}, // INTERSECTION WITH OVERBAR
+ {"Ncaron", 0x00147}, // LATIN CAPITAL LETTER N WITH CARON
+ {"ncaron", 0x00148}, // LATIN SMALL LETTER N WITH CARON
+ {"Ncedil", 0x00145}, // LATIN CAPITAL LETTER N WITH CEDILLA
+ {"ncedil", 0x00146}, // LATIN SMALL LETTER N WITH CEDILLA
+ {"ncong", 0x02247}, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
+// "ncongdot", 0x02A6D;0x00338}, // CONGRUENT WITH DOT ABOVE with slash
+ {"ncup", 0x02A42}, // UNION WITH OVERBAR
+ {"Ncy", 0x0041D}, // CYRILLIC CAPITAL LETTER EN
+ {"ncy", 0x0043D}, // CYRILLIC SMALL LETTER EN
+ {"ndash", 0x02013}, // EN DASH
+ {"ne", 0x02260}, // NOT EQUAL TO
+ {"nearhk", 0x02924}, // NORTH EAST ARROW WITH HOOK
+ {"nearr", 0x02197}, // NORTH EAST ARROW
+ {"neArr", 0x021D7}, // NORTH EAST DOUBLE ARROW
+ {"nearrow", 0x02197}, // NORTH EAST ARROW
+// "nedot", 0x02250;0x00338}, // APPROACHES THE LIMIT with slash
+ {"NegativeMediumSpace", 0x0200B}, // ZERO WIDTH SPACE
+ {"NegativeThickSpace", 0x0200B}, // ZERO WIDTH SPACE
+ {"NegativeThinSpace", 0x0200B}, // ZERO WIDTH SPACE
+ {"NegativeVeryThinSpace", 0x0200B}, // ZERO WIDTH SPACE
+ {"nequiv", 0x02262}, // NOT IDENTICAL TO
+ {"nesear", 0x02928}, // NORTH EAST ARROW AND SOUTH EAST ARROW
+// "nesim", 0x02242;0x00338}, // MINUS TILDE with slash
+ {"NestedGreaterGreater", 0x0226B}, // MUCH GREATER-THAN
+ {"NestedLessLess", 0x0226A}, // MUCH LESS-THAN
+ {"NewLine", 0x0000A}, // LINE FEED (LF)
+ {"nexist", 0x02204}, // THERE DOES NOT EXIST
+ {"nexists", 0x02204}, // THERE DOES NOT EXIST
+ {"Nfr", 0x1D511}, // MATHEMATICAL FRAKTUR CAPITAL N
+ {"nfr", 0x1D52B}, // MATHEMATICAL FRAKTUR SMALL N
+// "ngE", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash
+ {"nge", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO
+ {"ngeq", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO
+// "ngeqq", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash
+// "ngeqslant", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
+// "nges", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
+// "nGg", 0x022D9;0x00338}, // VERY MUCH GREATER-THAN with slash
+ {"Ngr", 0x0039D}, // GREEK CAPITAL LETTER NU
+ {"ngr", 0x003BD}, // GREEK SMALL LETTER NU
+ {"ngsim", 0x02275}, // NEITHER GREATER-THAN NOR EQUIVALENT TO
+// "nGt", 0x0226B;0x020D2}, // MUCH GREATER THAN with vertical line
+ {"ngt", 0x0226F}, // NOT GREATER-THAN
+ {"ngtr", 0x0226F}, // NOT GREATER-THAN
+// "nGtv", 0x0226B;0x00338}, // MUCH GREATER THAN with slash
+ {"nharr", 0x021AE}, // LEFT RIGHT ARROW WITH STROKE
+ {"nhArr", 0x021CE}, // LEFT RIGHT DOUBLE ARROW WITH STROKE
+ {"nhpar", 0x02AF2}, // PARALLEL WITH HORIZONTAL STROKE
+ {"ni", 0x0220B}, // CONTAINS AS MEMBER
+ {"nis", 0x022FC}, // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+ {"nisd", 0x022FA}, // CONTAINS WITH LONG HORIZONTAL STROKE
+ {"niv", 0x0220B}, // CONTAINS AS MEMBER
+ {"NJcy", 0x0040A}, // CYRILLIC CAPITAL LETTER NJE
+ {"njcy", 0x0045A}, // CYRILLIC SMALL LETTER NJE
+ {"nlarr", 0x0219A}, // LEFTWARDS ARROW WITH STROKE
+ {"nlArr", 0x021CD}, // LEFTWARDS DOUBLE ARROW WITH STROKE
+ {"nldr", 0x02025}, // TWO DOT LEADER
+// "nlE", 0x02266;0x00338}, // LESS-THAN OVER EQUAL TO with slash
+ {"nle", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO
+ {"nleftarrow", 0x0219A}, // LEFTWARDS ARROW WITH STROKE
+ {"nLeftarrow", 0x021CD}, // LEFTWARDS DOUBLE ARROW WITH STROKE
+ {"nleftrightarrow", 0x021AE}, // LEFT RIGHT ARROW WITH STROKE
+ {"nLeftrightarrow", 0x021CE}, // LEFT RIGHT DOUBLE ARROW WITH STROKE
+ {"nleq", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO
+// "nleqq", 0x02266;0x00338}, // LESS-THAN OVER EQUAL TO with slash
+// "nleqslant", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
+// "nles", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
+ {"nless", 0x0226E}, // NOT LESS-THAN
+// "nLl", 0x022D8;0x00338}, // VERY MUCH LESS-THAN with slash
+ {"nlsim", 0x02274}, // NEITHER LESS-THAN NOR EQUIVALENT TO
+// "nLt", 0x0226A;0x020D2}, // MUCH LESS THAN with vertical line
+ {"nlt", 0x0226E}, // NOT LESS-THAN
+ {"nltri", 0x022EA}, // NOT NORMAL SUBGROUP OF
+ {"nltrie", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO
+// "nLtv", 0x0226A;0x00338}, // MUCH LESS THAN with slash
+ {"nmid", 0x02224}, // DOES NOT DIVIDE
+ {"NoBreak", 0x02060}, // WORD JOINER
+ {"NonBreakingSpace", 0x000A0}, // NO-BREAK SPACE
+ {"Nopf", 0x02115}, // DOUBLE-STRUCK CAPITAL N
+ {"nopf", 0x1D55F}, // MATHEMATICAL DOUBLE-STRUCK SMALL N
+ {"not", 0x000AC}, // NOT SIGN
+ {"Not", 0x02AEC}, // DOUBLE STROKE NOT SIGN
+ {"NotCongruent", 0x02262}, // NOT IDENTICAL TO
+ {"NotCupCap", 0x0226D}, // NOT EQUIVALENT TO
+ {"NotDoubleVerticalBar", 0x02226}, // NOT PARALLEL TO
+ {"NotElement", 0x02209}, // NOT AN ELEMENT OF
+ {"NotEqual", 0x02260}, // NOT EQUAL TO
+// "NotEqualTilde", 0x02242;0x00338}, // MINUS TILDE with slash
+ {"NotExists", 0x02204}, // THERE DOES NOT EXIST
+ {"NotGreater", 0x0226F}, // NOT GREATER-THAN
+ {"NotGreaterEqual", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO
+// "NotGreaterFullEqual", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash
+// "NotGreaterGreater", 0x0226B;0x00338}, // MUCH GREATER THAN with slash
+ {"NotGreaterLess", 0x02279}, // NEITHER GREATER-THAN NOR LESS-THAN
+// "NotGreaterSlantEqual", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash
+ {"NotGreaterTilde", 0x02275}, // NEITHER GREATER-THAN NOR EQUIVALENT TO
+// "NotHumpDownHump", 0x0224E;0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash
+// "NotHumpEqual", 0x0224F;0x00338}, // DIFFERENCE BETWEEN with slash
+ {"notin", 0x02209}, // NOT AN ELEMENT OF
+// "notindot", 0x022F5;0x00338}, // ELEMENT OF WITH DOT ABOVE with slash
+// "notinE", 0x022F9;0x00338}, // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash
+ {"notinva", 0x02209}, // NOT AN ELEMENT OF
+ {"notinvb", 0x022F7}, // SMALL ELEMENT OF WITH OVERBAR
+ {"notinvc", 0x022F6}, // ELEMENT OF WITH OVERBAR
+ {"NotLeftTriangle", 0x022EA}, // NOT NORMAL SUBGROUP OF
+// "NotLeftTriangleBar", 0x029CF;0x00338}, // LEFT TRIANGLE BESIDE VERTICAL BAR with slash
+ {"NotLeftTriangleEqual", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO
+ {"NotLess", 0x0226E}, // NOT LESS-THAN
+ {"NotLessEqual", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO
+ {"NotLessGreater", 0x02278}, // NEITHER LESS-THAN NOR GREATER-THAN
+// "NotLessLess", 0x0226A;0x00338}, // MUCH LESS THAN with slash
+// "NotLessSlantEqual", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash
+ {"NotLessTilde", 0x02274}, // NEITHER LESS-THAN NOR EQUIVALENT TO
+// "NotNestedGreaterGreater", 0x02AA2;0x00338}, // DOUBLE NESTED GREATER-THAN with slash
+// "NotNestedLessLess", 0x02AA1;0x00338}, // DOUBLE NESTED LESS-THAN with slash
+ {"notni", 0x0220C}, // DOES NOT CONTAIN AS MEMBER
+ {"notniva", 0x0220C}, // DOES NOT CONTAIN AS MEMBER
+ {"notnivb", 0x022FE}, // SMALL CONTAINS WITH OVERBAR
+ {"notnivc", 0x022FD}, // CONTAINS WITH OVERBAR
+ {"NotPrecedes", 0x02280}, // DOES NOT PRECEDE
+// "NotPrecedesEqual", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
+ {"NotPrecedesSlantEqual", 0x022E0}, // DOES NOT PRECEDE OR EQUAL
+ {"NotReverseElement", 0x0220C}, // DOES NOT CONTAIN AS MEMBER
+ {"NotRightTriangle", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP
+// "NotRightTriangleBar", 0x029D0;0x00338}, // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash
+ {"NotRightTriangleEqual", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
+// "NotSquareSubset", 0x0228F;0x00338}, // SQUARE IMAGE OF with slash
+ {"NotSquareSubsetEqual", 0x022E2}, // NOT SQUARE IMAGE OF OR EQUAL TO
+// "NotSquareSuperset", 0x02290;0x00338}, // SQUARE ORIGINAL OF with slash
+ {"NotSquareSupersetEqual", 0x022E3}, // NOT SQUARE ORIGINAL OF OR EQUAL TO
+// "NotSubset", 0x02282;0x020D2}, // SUBSET OF with vertical line
+ {"NotSubsetEqual", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO
+ {"NotSucceeds", 0x02281}, // DOES NOT SUCCEED
+// "NotSucceedsEqual", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
+ {"NotSucceedsSlantEqual", 0x022E1}, // DOES NOT SUCCEED OR EQUAL
+// "NotSucceedsTilde", 0x0227F;0x00338}, // SUCCEEDS OR EQUIVALENT TO with slash
+// "NotSuperset", 0x02283;0x020D2}, // SUPERSET OF with vertical line
+ {"NotSupersetEqual", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO
+ {"NotTilde", 0x02241}, // NOT TILDE
+ {"NotTildeEqual", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO
+ {"NotTildeFullEqual", 0x02247}, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO
+ {"NotTildeTilde", 0x02249}, // NOT ALMOST EQUAL TO
+ {"NotVerticalBar", 0x02224}, // DOES NOT DIVIDE
+ {"npar", 0x02226}, // NOT PARALLEL TO
+ {"nparallel", 0x02226}, // NOT PARALLEL TO
+// "nparsl", 0x02AFD;0x020E5}, // DOUBLE SOLIDUS OPERATOR with reverse slash
+// "npart", 0x02202;0x00338}, // PARTIAL DIFFERENTIAL with slash
+ {"npolint", 0x02A14}, // LINE INTEGRATION NOT INCLUDING THE POLE
+ {"npr", 0x02280}, // DOES NOT PRECEDE
+ {"nprcue", 0x022E0}, // DOES NOT PRECEDE OR EQUAL
+// "npre", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
+ {"nprec", 0x02280}, // DOES NOT PRECEDE
+// "npreceq", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash
+ {"nrarr", 0x0219B}, // RIGHTWARDS ARROW WITH STROKE
+ {"nrArr", 0x021CF}, // RIGHTWARDS DOUBLE ARROW WITH STROKE
+// "nrarrc", 0x02933;0x00338}, // WAVE ARROW POINTING DIRECTLY RIGHT with slash
+// "nrarrw", 0x0219D;0x00338}, // RIGHTWARDS WAVE ARROW with slash
+ {"nrightarrow", 0x0219B}, // RIGHTWARDS ARROW WITH STROKE
+ {"nRightarrow", 0x021CF}, // RIGHTWARDS DOUBLE ARROW WITH STROKE
+ {"nrtri", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP
+ {"nrtrie", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
+ {"nsc", 0x02281}, // DOES NOT SUCCEED
+ {"nsccue", 0x022E1}, // DOES NOT SUCCEED OR EQUAL
+// "nsce", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
+ {"Nscr", 0x1D4A9}, // MATHEMATICAL SCRIPT CAPITAL N
+ {"nscr", 0x1D4C3}, // MATHEMATICAL SCRIPT SMALL N
+ {"nshortmid", 0x02224}, // DOES NOT DIVIDE
+ {"nshortparallel", 0x02226}, // NOT PARALLEL TO
+ {"nsim", 0x02241}, // NOT TILDE
+ {"nsime", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO
+ {"nsimeq", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO
+ {"nsmid", 0x02224}, // DOES NOT DIVIDE
+ {"nspar", 0x02226}, // NOT PARALLEL TO
+ {"nsqsube", 0x022E2}, // NOT SQUARE IMAGE OF OR EQUAL TO
+ {"nsqsupe", 0x022E3}, // NOT SQUARE ORIGINAL OF OR EQUAL TO
+ {"nsub", 0x02284}, // NOT A SUBSET OF
+ {"nsube", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO
+// "nsubE", 0x02AC5;0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash
+// "nsubset", 0x02282;0x020D2}, // SUBSET OF with vertical line
+ {"nsubseteq", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO
+// "nsubseteqq", 0x02AC5;0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash
+ {"nsucc", 0x02281}, // DOES NOT SUCCEED
+// "nsucceq", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash
+ {"nsup", 0x02285}, // NOT A SUPERSET OF
+ {"nsupe", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO
+// "nsupE", 0x02AC6;0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash
+// "nsupset", 0x02283;0x020D2}, // SUPERSET OF with vertical line
+ {"nsupseteq", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO
+// "nsupseteqq", 0x02AC6;0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash
+ {"ntgl", 0x02279}, // NEITHER GREATER-THAN NOR LESS-THAN
+ {"Ntilde", 0x000D1}, // LATIN CAPITAL LETTER N WITH TILDE
+ {"ntilde", 0x000F1}, // LATIN SMALL LETTER N WITH TILDE
+ {"ntlg", 0x02278}, // NEITHER LESS-THAN NOR GREATER-THAN
+ {"ntriangleleft", 0x022EA}, // NOT NORMAL SUBGROUP OF
+ {"ntrianglelefteq", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO
+ {"ntriangleright", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP
+ {"ntrianglerighteq", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL
+ {"Nu", 0x0039D}, // GREEK CAPITAL LETTER NU
+ {"nu", 0x003BD}, // GREEK SMALL LETTER NU
+ {"num", 0x00023}, // NUMBER SIGN
+ {"numero", 0x02116}, // NUMERO SIGN
+ {"numsp", 0x02007}, // FIGURE SPACE
+// "nvap", 0x0224D;0x020D2}, // EQUIVALENT TO with vertical line
+ {"nvdash", 0x022AC}, // DOES NOT PROVE
+ {"nvDash", 0x022AD}, // NOT TRUE
+ {"nVdash", 0x022AE}, // DOES NOT FORCE
+ {"nVDash", 0x022AF}, // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
+// "nvge", 0x02265;0x020D2}, // GREATER-THAN OR EQUAL TO with vertical line
+// "nvgt", 0x0003E;0x020D2}, // GREATER-THAN SIGN with vertical line
+ {"nvHarr", 0x02904}, // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE
+ {"nvinfin", 0x029DE}, // INFINITY NEGATED WITH VERTICAL BAR
+ {"nvlArr", 0x02902}, // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE
+// "nvle", 0x02264;0x020D2}, // LESS-THAN OR EQUAL TO with vertical line
+// "nvlt", 0x0003C;0x020D2}, // LESS-THAN SIGN with vertical line
+// "nvltrie", 0x022B4;0x020D2}, // NORMAL SUBGROUP OF OR EQUAL TO with vertical line
+ {"nvrArr", 0x02903}, // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE
+// "nvrtrie", 0x022B5;0x020D2}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line
+// "nvsim", 0x0223C;0x020D2}, // TILDE OPERATOR with vertical line
+ {"nwarhk", 0x02923}, // NORTH WEST ARROW WITH HOOK
+ {"nwarr", 0x02196}, // NORTH WEST ARROW
+ {"nwArr", 0x021D6}, // NORTH WEST DOUBLE ARROW
+ {"nwarrow", 0x02196}, // NORTH WEST ARROW
+ {"nwnear", 0x02927}, // NORTH WEST ARROW AND NORTH EAST ARROW
+];
+
+immutable NameId[] namesO =
+[
+ {"Oacgr", 0x0038C}, // GREEK CAPITAL LETTER OMICRON WITH TONOS
+ {"oacgr", 0x003CC}, // GREEK SMALL LETTER OMICRON WITH TONOS
+ {"Oacute", 0x000D3}, // LATIN CAPITAL LETTER O WITH ACUTE
+ {"oacute", 0x000F3}, // LATIN SMALL LETTER O WITH ACUTE
+ {"oast", 0x0229B}, // CIRCLED ASTERISK OPERATOR
+ {"ocir", 0x0229A}, // CIRCLED RING OPERATOR
+ {"Ocirc", 0x000D4}, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+ {"ocirc", 0x000F4}, // LATIN SMALL LETTER O WITH CIRCUMFLEX
+ {"Ocy", 0x0041E}, // CYRILLIC CAPITAL LETTER O
+ {"ocy", 0x0043E}, // CYRILLIC SMALL LETTER O
+ {"odash", 0x0229D}, // CIRCLED DASH
+ {"Odblac", 0x00150}, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+ {"odblac", 0x00151}, // LATIN SMALL LETTER O WITH DOUBLE ACUTE
+ {"odiv", 0x02A38}, // CIRCLED DIVISION SIGN
+ {"odot", 0x02299}, // CIRCLED DOT OPERATOR
+ {"odsold", 0x029BC}, // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN
+ {"OElig", 0x00152}, // LATIN CAPITAL LIGATURE OE
+ {"oelig", 0x00153}, // LATIN SMALL LIGATURE OE
+ {"ofcir", 0x029BF}, // CIRCLED BULLET
+ {"Ofr", 0x1D512}, // MATHEMATICAL FRAKTUR CAPITAL O
+ {"ofr", 0x1D52C}, // MATHEMATICAL FRAKTUR SMALL O
+ {"ogon", 0x002DB}, // OGONEK
+ {"Ogr", 0x0039F}, // GREEK CAPITAL LETTER OMICRON
+ {"ogr", 0x003BF}, // GREEK SMALL LETTER OMICRON
+ {"Ograve", 0x000D2}, // LATIN CAPITAL LETTER O WITH GRAVE
+ {"ograve", 0x000F2}, // LATIN SMALL LETTER O WITH GRAVE
+ {"ogt", 0x029C1}, // CIRCLED GREATER-THAN
+ {"OHacgr", 0x0038F}, // GREEK CAPITAL LETTER OMEGA WITH TONOS
+ {"ohacgr", 0x003CE}, // GREEK SMALL LETTER OMEGA WITH TONOS
+ {"ohbar", 0x029B5}, // CIRCLE WITH HORIZONTAL BAR
+ {"OHgr", 0x003A9}, // GREEK CAPITAL LETTER OMEGA
+ {"ohgr", 0x003C9}, // GREEK SMALL LETTER OMEGA
+ {"ohm", 0x003A9}, // GREEK CAPITAL LETTER OMEGA
+ {"oint", 0x0222E}, // CONTOUR INTEGRAL
+ {"olarr", 0x021BA}, // ANTICLOCKWISE OPEN CIRCLE ARROW
+ {"olcir", 0x029BE}, // CIRCLED WHITE BULLET
+ {"olcross", 0x029BB}, // CIRCLE WITH SUPERIMPOSED X
+ {"oline", 0x0203E}, // OVERLINE
+ {"olt", 0x029C0}, // CIRCLED LESS-THAN
+ {"Omacr", 0x0014C}, // LATIN CAPITAL LETTER O WITH MACRON
+ {"omacr", 0x0014D}, // LATIN SMALL LETTER O WITH MACRON
+ {"Omega", 0x003A9}, // GREEK CAPITAL LETTER OMEGA
+ {"omega", 0x003C9}, // GREEK SMALL LETTER OMEGA
+ {"Omicron", 0x0039F}, // GREEK CAPITAL LETTER OMICRON
+ {"omicron", 0x003BF}, // GREEK SMALL LETTER OMICRON
+ {"omid", 0x029B6}, // CIRCLED VERTICAL BAR
+ {"ominus", 0x02296}, // CIRCLED MINUS
+ {"Oopf", 0x1D546}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL O
+ {"oopf", 0x1D560}, // MATHEMATICAL DOUBLE-STRUCK SMALL O
+ {"opar", 0x029B7}, // CIRCLED PARALLEL
+ {"OpenCurlyDoubleQuote", 0x0201C}, // LEFT DOUBLE QUOTATION MARK
+ {"OpenCurlyQuote", 0x02018}, // LEFT SINGLE QUOTATION MARK
+ {"operp", 0x029B9}, // CIRCLED PERPENDICULAR
+ {"oplus", 0x02295}, // CIRCLED PLUS
+ {"or", 0x02228}, // LOGICAL OR
+ {"Or", 0x02A54}, // DOUBLE LOGICAL OR
+ {"orarr", 0x021BB}, // CLOCKWISE OPEN CIRCLE ARROW
+ {"ord", 0x02A5D}, // LOGICAL OR WITH HORIZONTAL DASH
+ {"order", 0x02134}, // SCRIPT SMALL O
+ {"orderof", 0x02134}, // SCRIPT SMALL O
+ {"ordf", 0x000AA}, // FEMININE ORDINAL INDICATOR
+ {"ordm", 0x000BA}, // MASCULINE ORDINAL INDICATOR
+ {"origof", 0x022B6}, // ORIGINAL OF
+ {"oror", 0x02A56}, // TWO INTERSECTING LOGICAL OR
+ {"orslope", 0x02A57}, // SLOPING LARGE OR
+ {"orv", 0x02A5B}, // LOGICAL OR WITH MIDDLE STEM
+ {"oS", 0x024C8}, // CIRCLED LATIN CAPITAL LETTER S
+ {"oscr", 0x02134}, // SCRIPT SMALL O
+ {"Oscr", 0x1D4AA}, // MATHEMATICAL SCRIPT CAPITAL O
+ {"Oslash", 0x000D8}, // LATIN CAPITAL LETTER O WITH STROKE
+ {"oslash", 0x000F8}, // LATIN SMALL LETTER O WITH STROKE
+ {"osol", 0x02298}, // CIRCLED DIVISION SLASH
+ {"Otilde", 0x000D5}, // LATIN CAPITAL LETTER O WITH TILDE
+ {"otilde", 0x000F5}, // LATIN SMALL LETTER O WITH TILDE
+ {"otimes", 0x02297}, // CIRCLED TIMES
+ {"Otimes", 0x02A37}, // MULTIPLICATION SIGN IN DOUBLE CIRCLE
+ {"otimesas", 0x02A36}, // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT
+ {"Ouml", 0x000D6}, // LATIN CAPITAL LETTER O WITH DIAERESIS
+ {"ouml", 0x000F6}, // LATIN SMALL LETTER O WITH DIAERESIS
+ {"ovbar", 0x0233D}, // APL FUNCTIONAL SYMBOL CIRCLE STILE
+ {"OverBar", 0x0203E}, // OVERLINE
+ {"OverBrace", 0x023DE}, // TOP CURLY BRACKET
+ {"OverBracket", 0x023B4}, // TOP SQUARE BRACKET
+ {"OverParenthesis", 0x023DC}, // TOP PARENTHESIS
+];
+
+immutable NameId[] namesP =
+[
+ {"par", 0x02225}, // PARALLEL TO
+ {"para", 0x000B6}, // PILCROW SIGN
+ {"parallel", 0x02225}, // PARALLEL TO
+ {"parsim", 0x02AF3}, // PARALLEL WITH TILDE OPERATOR
+ {"parsl", 0x02AFD}, // DOUBLE SOLIDUS OPERATOR
+ {"part", 0x02202}, // PARTIAL DIFFERENTIAL
+ {"PartialD", 0x02202}, // PARTIAL DIFFERENTIAL
+ {"Pcy", 0x0041F}, // CYRILLIC CAPITAL LETTER PE
+ {"pcy", 0x0043F}, // CYRILLIC SMALL LETTER PE
+ {"percnt", 0x00025}, // PERCENT SIGN
+ {"period", 0x0002E}, // FULL STOP
+ {"permil", 0x02030}, // PER MILLE SIGN
+ {"perp", 0x022A5}, // UP TACK
+ {"pertenk", 0x02031}, // PER TEN THOUSAND SIGN
+ {"Pfr", 0x1D513}, // MATHEMATICAL FRAKTUR CAPITAL P
+ {"pfr", 0x1D52D}, // MATHEMATICAL FRAKTUR SMALL P
+ {"Pgr", 0x003A0}, // GREEK CAPITAL LETTER PI
+ {"pgr", 0x003C0}, // GREEK SMALL LETTER PI
+ {"PHgr", 0x003A6}, // GREEK CAPITAL LETTER PHI
+ {"phgr", 0x003C6}, // GREEK SMALL LETTER PHI
+ {"Phi", 0x003A6}, // GREEK CAPITAL LETTER PHI
+ {"phi", 0x003C6}, // GREEK SMALL LETTER PHI
+ {"phiv", 0x003D5}, // GREEK PHI SYMBOL
+ {"phmmat", 0x02133}, // SCRIPT CAPITAL M
+ {"phone", 0x0260E}, // BLACK TELEPHONE
+ {"Pi", 0x003A0}, // GREEK CAPITAL LETTER PI
+ {"pi", 0x003C0}, // GREEK SMALL LETTER PI
+ {"pitchfork", 0x022D4}, // PITCHFORK
+ {"piv", 0x003D6}, // GREEK PI SYMBOL
+ {"planck", 0x0210F}, // PLANCK CONSTANT OVER TWO PI
+ {"planckh", 0x0210E}, // PLANCK CONSTANT
+ {"plankv", 0x0210F}, // PLANCK CONSTANT OVER TWO PI
+ {"plus", 0x0002B}, // PLUS SIGN
+ {"plusacir", 0x02A23}, // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE
+ {"plusb", 0x0229E}, // SQUARED PLUS
+ {"pluscir", 0x02A22}, // PLUS SIGN WITH SMALL CIRCLE ABOVE
+ {"plusdo", 0x02214}, // DOT PLUS
+ {"plusdu", 0x02A25}, // PLUS SIGN WITH DOT BELOW
+ {"pluse", 0x02A72}, // PLUS SIGN ABOVE EQUALS SIGN
+ {"PlusMinus", 0x000B1}, // PLUS-MINUS SIGN
+ {"plusmn", 0x000B1}, // PLUS-MINUS SIGN
+ {"plussim", 0x02A26}, // PLUS SIGN WITH TILDE BELOW
+ {"plustwo", 0x02A27}, // PLUS SIGN WITH SUBSCRIPT TWO
+ {"pm", 0x000B1}, // PLUS-MINUS SIGN
+ {"Poincareplane", 0x0210C}, // BLACK-LETTER CAPITAL H
+ {"pointint", 0x02A15}, // INTEGRAL AROUND A POINT OPERATOR
+ {"Popf", 0x02119}, // DOUBLE-STRUCK CAPITAL P
+ {"popf", 0x1D561}, // MATHEMATICAL DOUBLE-STRUCK SMALL P
+ {"pound", 0x000A3}, // POUND SIGN
+ {"pr", 0x0227A}, // PRECEDES
+ {"Pr", 0x02ABB}, // DOUBLE PRECEDES
+ {"prap", 0x02AB7}, // PRECEDES ABOVE ALMOST EQUAL TO
+ {"prcue", 0x0227C}, // PRECEDES OR EQUAL TO
+ {"pre", 0x02AAF}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
+ {"prE", 0x02AB3}, // PRECEDES ABOVE EQUALS SIGN
+ {"prec", 0x0227A}, // PRECEDES
+ {"precapprox", 0x02AB7}, // PRECEDES ABOVE ALMOST EQUAL TO
+ {"preccurlyeq", 0x0227C}, // PRECEDES OR EQUAL TO
+ {"Precedes", 0x0227A}, // PRECEDES
+ {"PrecedesEqual", 0x02AAF}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
+ {"PrecedesSlantEqual", 0x0227C}, // PRECEDES OR EQUAL TO
+ {"PrecedesTilde", 0x0227E}, // PRECEDES OR EQUIVALENT TO
+ {"preceq", 0x02AAF}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN
+ {"precnapprox", 0x02AB9}, // PRECEDES ABOVE NOT ALMOST EQUAL TO
+ {"precneqq", 0x02AB5}, // PRECEDES ABOVE NOT EQUAL TO
+ {"precnsim", 0x022E8}, // PRECEDES BUT NOT EQUIVALENT TO
+ {"precsim", 0x0227E}, // PRECEDES OR EQUIVALENT TO
+ {"prime", 0x02032}, // PRIME
+ {"Prime", 0x02033}, // DOUBLE PRIME
+ {"primes", 0x02119}, // DOUBLE-STRUCK CAPITAL P
+ {"prnap", 0x02AB9}, // PRECEDES ABOVE NOT ALMOST EQUAL TO
+ {"prnE", 0x02AB5}, // PRECEDES ABOVE NOT EQUAL TO
+ {"prnsim", 0x022E8}, // PRECEDES BUT NOT EQUIVALENT TO
+ {"prod", 0x0220F}, // N-ARY PRODUCT
+ {"Product", 0x0220F}, // N-ARY PRODUCT
+ {"profalar", 0x0232E}, // ALL AROUND-PROFILE
+ {"profline", 0x02312}, // ARC
+ {"profsurf", 0x02313}, // SEGMENT
+ {"prop", 0x0221D}, // PROPORTIONAL TO
+ {"Proportion", 0x02237}, // PROPORTION
+ {"Proportional", 0x0221D}, // PROPORTIONAL TO
+ {"propto", 0x0221D}, // PROPORTIONAL TO
+ {"prsim", 0x0227E}, // PRECEDES OR EQUIVALENT TO
+ {"prurel", 0x022B0}, // PRECEDES UNDER RELATION
+ {"Pscr", 0x1D4AB}, // MATHEMATICAL SCRIPT CAPITAL P
+ {"pscr", 0x1D4C5}, // MATHEMATICAL SCRIPT SMALL P
+ {"PSgr", 0x003A8}, // GREEK CAPITAL LETTER PSI
+ {"psgr", 0x003C8}, // GREEK SMALL LETTER PSI
+ {"Psi", 0x003A8}, // GREEK CAPITAL LETTER PSI
+ {"psi", 0x003C8}, // GREEK SMALL LETTER PSI
+ {"puncsp", 0x02008}, // PUNCTUATION SPACE
+];
+
+immutable NameId[] namesQ =
+[
+ {"Qfr", 0x1D514}, // MATHEMATICAL FRAKTUR CAPITAL Q
+ {"qfr", 0x1D52E}, // MATHEMATICAL FRAKTUR SMALL Q
+ {"qint", 0x02A0C}, // QUADRUPLE INTEGRAL OPERATOR
+ {"Qopf", 0x0211A}, // DOUBLE-STRUCK CAPITAL Q
+ {"qopf", 0x1D562}, // MATHEMATICAL DOUBLE-STRUCK SMALL Q
+ {"qprime", 0x02057}, // QUADRUPLE PRIME
+ {"Qscr", 0x1D4AC}, // MATHEMATICAL SCRIPT CAPITAL Q
+ {"qscr", 0x1D4C6}, // MATHEMATICAL SCRIPT SMALL Q
+ {"quaternions", 0x0210D}, // DOUBLE-STRUCK CAPITAL H
+ {"quatint", 0x02A16}, // QUATERNION INTEGRAL OPERATOR
+ {"quest", 0x0003F}, // QUESTION MARK
+ {"questeq", 0x0225F}, // QUESTIONED EQUAL TO
+ {"quot", 0x00022}, // QUOTATION MARK
+ {"QUOT", 0x00022}, // QUOTATION MARK
+];
+
+immutable NameId[] namesR =
+[
+ {"rAarr", 0x021DB}, // RIGHTWARDS TRIPLE ARROW
+// "race", 0x0223D;0x00331}, // REVERSED TILDE with underline
+ {"Racute", 0x00154}, // LATIN CAPITAL LETTER R WITH ACUTE
+ {"racute", 0x00155}, // LATIN SMALL LETTER R WITH ACUTE
+ {"radic", 0x0221A}, // SQUARE ROOT
+ {"raemptyv", 0x029B3}, // EMPTY SET WITH RIGHT ARROW ABOVE
+ {"rang", 0x027E9}, // MATHEMATICAL RIGHT ANGLE BRACKET
+ {"Rang", 0x027EB}, // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+ {"rangd", 0x02992}, // RIGHT ANGLE BRACKET WITH DOT
+ {"range", 0x029A5}, // REVERSED ANGLE WITH UNDERBAR
+ {"rangle", 0x027E9}, // MATHEMATICAL RIGHT ANGLE BRACKET
+ {"raquo", 0x000BB}, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
+ {"rarr", 0x02192}, // RIGHTWARDS ARROW
+ {"Rarr", 0x021A0}, // RIGHTWARDS TWO HEADED ARROW
+ {"rArr", 0x021D2}, // RIGHTWARDS DOUBLE ARROW
+ {"rarrap", 0x02975}, // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO
+ {"rarrb", 0x021E5}, // RIGHTWARDS ARROW TO BAR
+ {"rarrbfs", 0x02920}, // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND
+ {"rarrc", 0x02933}, // WAVE ARROW POINTING DIRECTLY RIGHT
+ {"rarrfs", 0x0291E}, // RIGHTWARDS ARROW TO BLACK DIAMOND
+ {"rarrhk", 0x021AA}, // RIGHTWARDS ARROW WITH HOOK
+ {"rarrlp", 0x021AC}, // RIGHTWARDS ARROW WITH LOOP
+ {"rarrpl", 0x02945}, // RIGHTWARDS ARROW WITH PLUS BELOW
+ {"rarrsim", 0x02974}, // RIGHTWARDS ARROW ABOVE TILDE OPERATOR
+ {"rarrtl", 0x021A3}, // RIGHTWARDS ARROW WITH TAIL
+ {"Rarrtl", 0x02916}, // RIGHTWARDS TWO-HEADED ARROW WITH TAIL
+ {"rarrw", 0x0219D}, // RIGHTWARDS WAVE ARROW
+ {"ratail", 0x0291A}, // RIGHTWARDS ARROW-TAIL
+ {"rAtail", 0x0291C}, // RIGHTWARDS DOUBLE ARROW-TAIL
+ {"ratio", 0x02236}, // RATIO
+ {"rationals", 0x0211A}, // DOUBLE-STRUCK CAPITAL Q
+ {"rbarr", 0x0290D}, // RIGHTWARDS DOUBLE DASH ARROW
+ {"rBarr", 0x0290F}, // RIGHTWARDS TRIPLE DASH ARROW
+ {"RBarr", 0x02910}, // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW
+ {"rbbrk", 0x02773}, // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT
+ {"rbrace", 0x0007D}, // RIGHT CURLY BRACKET
+ {"rbrack", 0x0005D}, // RIGHT SQUARE BRACKET
+ {"rbrke", 0x0298C}, // RIGHT SQUARE BRACKET WITH UNDERBAR
+ {"rbrksld", 0x0298E}, // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER
+ {"rbrkslu", 0x02990}, // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER
+ {"Rcaron", 0x00158}, // LATIN CAPITAL LETTER R WITH CARON
+ {"rcaron", 0x00159}, // LATIN SMALL LETTER R WITH CARON
+ {"Rcedil", 0x00156}, // LATIN CAPITAL LETTER R WITH CEDILLA
+ {"rcedil", 0x00157}, // LATIN SMALL LETTER R WITH CEDILLA
+ {"rceil", 0x02309}, // RIGHT CEILING
+ {"rcub", 0x0007D}, // RIGHT CURLY BRACKET
+ {"Rcy", 0x00420}, // CYRILLIC CAPITAL LETTER ER
+ {"rcy", 0x00440}, // CYRILLIC SMALL LETTER ER
+ {"rdca", 0x02937}, // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS
+ {"rdldhar", 0x02969}, // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN
+ {"rdquo", 0x0201D}, // RIGHT DOUBLE QUOTATION MARK
+ {"rdquor", 0x0201D}, // RIGHT DOUBLE QUOTATION MARK
+ {"rdsh", 0x021B3}, // DOWNWARDS ARROW WITH TIP RIGHTWARDS
+ {"Re", 0x0211C}, // BLACK-LETTER CAPITAL R
+ {"real", 0x0211C}, // BLACK-LETTER CAPITAL R
+ {"realine", 0x0211B}, // SCRIPT CAPITAL R
+ {"realpart", 0x0211C}, // BLACK-LETTER CAPITAL R
+ {"reals", 0x0211D}, // DOUBLE-STRUCK CAPITAL R
+ {"rect", 0x025AD}, // WHITE RECTANGLE
+ {"reg", 0x000AE}, // REGISTERED SIGN
+ {"REG", 0x000AE}, // REGISTERED SIGN
+ {"ReverseElement", 0x0220B}, // CONTAINS AS MEMBER
+ {"ReverseEquilibrium", 0x021CB}, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON
+ {"ReverseUpEquilibrium", 0x0296F}, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
+ {"rfisht", 0x0297D}, // RIGHT FISH TAIL
+ {"rfloor", 0x0230B}, // RIGHT FLOOR
+ {"Rfr", 0x0211C}, // BLACK-LETTER CAPITAL R
+ {"rfr", 0x1D52F}, // MATHEMATICAL FRAKTUR SMALL R
+ {"Rgr", 0x003A1}, // GREEK CAPITAL LETTER RHO
+ {"rgr", 0x003C1}, // GREEK SMALL LETTER RHO
+ {"rHar", 0x02964}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN
+ {"rhard", 0x021C1}, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
+ {"rharu", 0x021C0}, // RIGHTWARDS HARPOON WITH BARB UPWARDS
+ {"rharul", 0x0296C}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH
+ {"Rho", 0x003A1}, // GREEK CAPITAL LETTER RHO
+ {"rho", 0x003C1}, // GREEK SMALL LETTER RHO
+ {"rhov", 0x003F1}, // GREEK RHO SYMBOL
+ {"RightAngleBracket", 0x027E9}, // MATHEMATICAL RIGHT ANGLE BRACKET
+ {"rightarrow", 0x02192}, // RIGHTWARDS ARROW
+ {"RightArrow", 0x02192}, // RIGHTWARDS ARROW
+ {"Rightarrow", 0x021D2}, // RIGHTWARDS DOUBLE ARROW
+ {"RightArrowBar", 0x021E5}, // RIGHTWARDS ARROW TO BAR
+ {"RightArrowLeftArrow", 0x021C4}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
+ {"rightarrowtail", 0x021A3}, // RIGHTWARDS ARROW WITH TAIL
+ {"RightCeiling", 0x02309}, // RIGHT CEILING
+ {"RightDoubleBracket", 0x027E7}, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+ {"RightDownTeeVector", 0x0295D}, // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR
+ {"RightDownVector", 0x021C2}, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS
+ {"RightDownVectorBar", 0x02955}, // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR
+ {"RightFloor", 0x0230B}, // RIGHT FLOOR
+ {"rightharpoondown", 0x021C1}, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS
+ {"rightharpoonup", 0x021C0}, // RIGHTWARDS HARPOON WITH BARB UPWARDS
+ {"rightleftarrows", 0x021C4}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
+ {"rightleftharpoons", 0x021CC}, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
+ {"rightrightarrows", 0x021C9}, // RIGHTWARDS PAIRED ARROWS
+ {"rightsquigarrow", 0x0219D}, // RIGHTWARDS WAVE ARROW
+ {"RightTee", 0x022A2}, // RIGHT TACK
+ {"RightTeeArrow", 0x021A6}, // RIGHTWARDS ARROW FROM BAR
+ {"RightTeeVector", 0x0295B}, // RIGHTWARDS HARPOON WITH BARB UP FROM BAR
+ {"rightthreetimes", 0x022CC}, // RIGHT SEMIDIRECT PRODUCT
+ {"RightTriangle", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP
+ {"RightTriangleBar", 0x029D0}, // VERTICAL BAR BESIDE RIGHT TRIANGLE
+ {"RightTriangleEqual", 0x022B5}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
+ {"RightUpDownVector", 0x0294F}, // UP BARB RIGHT DOWN BARB RIGHT HARPOON
+ {"RightUpTeeVector", 0x0295C}, // UPWARDS HARPOON WITH BARB RIGHT FROM BAR
+ {"RightUpVector", 0x021BE}, // UPWARDS HARPOON WITH BARB RIGHTWARDS
+ {"RightUpVectorBar", 0x02954}, // UPWARDS HARPOON WITH BARB RIGHT TO BAR
+ {"RightVector", 0x021C0}, // RIGHTWARDS HARPOON WITH BARB UPWARDS
+ {"RightVectorBar", 0x02953}, // RIGHTWARDS HARPOON WITH BARB UP TO BAR
+ {"ring", 0x002DA}, // RING ABOVE
+ {"risingdotseq", 0x02253}, // IMAGE OF OR APPROXIMATELY EQUAL TO
+ {"rlarr", 0x021C4}, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW
+ {"rlhar", 0x021CC}, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON
+ {"rlm", 0x0200F}, // RIGHT-TO-LEFT MARK
+ {"rmoust", 0x023B1}, // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION
+ {"rmoustache", 0x023B1}, // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION
+ {"rnmid", 0x02AEE}, // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH
+ {"roang", 0x027ED}, // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET
+ {"roarr", 0x021FE}, // RIGHTWARDS OPEN-HEADED ARROW
+ {"robrk", 0x027E7}, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+ {"ropar", 0x02986}, // RIGHT WHITE PARENTHESIS
+ {"Ropf", 0x0211D}, // DOUBLE-STRUCK CAPITAL R
+ {"ropf", 0x1D563}, // MATHEMATICAL DOUBLE-STRUCK SMALL R
+ {"roplus", 0x02A2E}, // PLUS SIGN IN RIGHT HALF CIRCLE
+ {"rotimes", 0x02A35}, // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE
+ {"RoundImplies", 0x02970}, // RIGHT DOUBLE ARROW WITH ROUNDED HEAD
+ {"rpar", 0x00029}, // RIGHT PARENTHESIS
+ {"rpargt", 0x02994}, // RIGHT ARC GREATER-THAN BRACKET
+ {"rppolint", 0x02A12}, // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE
+ {"rrarr", 0x021C9}, // RIGHTWARDS PAIRED ARROWS
+ {"Rrightarrow", 0x021DB}, // RIGHTWARDS TRIPLE ARROW
+ {"rsaquo", 0x0203A}, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
+ {"Rscr", 0x0211B}, // SCRIPT CAPITAL R
+ {"rscr", 0x1D4C7}, // MATHEMATICAL SCRIPT SMALL R
+ {"rsh", 0x021B1}, // UPWARDS ARROW WITH TIP RIGHTWARDS
+ {"Rsh", 0x021B1}, // UPWARDS ARROW WITH TIP RIGHTWARDS
+ {"rsqb", 0x0005D}, // RIGHT SQUARE BRACKET
+ {"rsquo", 0x02019}, // RIGHT SINGLE QUOTATION MARK
+ {"rsquor", 0x02019}, // RIGHT SINGLE QUOTATION MARK
+ {"rthree", 0x022CC}, // RIGHT SEMIDIRECT PRODUCT
+ {"rtimes", 0x022CA}, // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT
+ {"rtri", 0x025B9}, // WHITE RIGHT-POINTING SMALL TRIANGLE
+ {"rtrie", 0x022B5}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
+ {"rtrif", 0x025B8}, // BLACK RIGHT-POINTING SMALL TRIANGLE
+ {"rtriltri", 0x029CE}, // RIGHT TRIANGLE ABOVE LEFT TRIANGLE
+ {"RuleDelayed", 0x029F4}, // RULE-DELAYED
+ {"ruluhar", 0x02968}, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP
+ {"rx", 0x0211E}, // PRESCRIPTION TAKE
+];
+
+immutable NameId[] namesS =
+[
+ {"Sacute", 0x0015A}, // LATIN CAPITAL LETTER S WITH ACUTE
+ {"sacute", 0x0015B}, // LATIN SMALL LETTER S WITH ACUTE
+ {"sbquo", 0x0201A}, // SINGLE LOW-9 QUOTATION MARK
+ {"sc", 0x0227B}, // SUCCEEDS
+ {"Sc", 0x02ABC}, // DOUBLE SUCCEEDS
+ {"scap", 0x02AB8}, // SUCCEEDS ABOVE ALMOST EQUAL TO
+ {"Scaron", 0x00160}, // LATIN CAPITAL LETTER S WITH CARON
+ {"scaron", 0x00161}, // LATIN SMALL LETTER S WITH CARON
+ {"sccue", 0x0227D}, // SUCCEEDS OR EQUAL TO
+ {"sce", 0x02AB0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
+ {"scE", 0x02AB4}, // SUCCEEDS ABOVE EQUALS SIGN
+ {"Scedil", 0x0015E}, // LATIN CAPITAL LETTER S WITH CEDILLA
+ {"scedil", 0x0015F}, // LATIN SMALL LETTER S WITH CEDILLA
+ {"Scirc", 0x0015C}, // LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+ {"scirc", 0x0015D}, // LATIN SMALL LETTER S WITH CIRCUMFLEX
+ {"scnap", 0x02ABA}, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO
+ {"scnE", 0x02AB6}, // SUCCEEDS ABOVE NOT EQUAL TO
+ {"scnsim", 0x022E9}, // SUCCEEDS BUT NOT EQUIVALENT TO
+ {"scpolint", 0x02A13}, // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE
+ {"scsim", 0x0227F}, // SUCCEEDS OR EQUIVALENT TO
+ {"Scy", 0x00421}, // CYRILLIC CAPITAL LETTER ES
+ {"scy", 0x00441}, // CYRILLIC SMALL LETTER ES
+ {"sdot", 0x022C5}, // DOT OPERATOR
+ {"sdotb", 0x022A1}, // SQUARED DOT OPERATOR
+ {"sdote", 0x02A66}, // EQUALS SIGN WITH DOT BELOW
+ {"searhk", 0x02925}, // SOUTH EAST ARROW WITH HOOK
+ {"searr", 0x02198}, // SOUTH EAST ARROW
+ {"seArr", 0x021D8}, // SOUTH EAST DOUBLE ARROW
+ {"searrow", 0x02198}, // SOUTH EAST ARROW
+ {"sect", 0x000A7}, // SECTION SIGN
+ {"semi", 0x0003B}, // SEMICOLON
+ {"seswar", 0x02929}, // SOUTH EAST ARROW AND SOUTH WEST ARROW
+ {"setminus", 0x02216}, // SET MINUS
+ {"setmn", 0x02216}, // SET MINUS
+ {"sext", 0x02736}, // SIX POINTED BLACK STAR
+ {"sfgr", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
+ {"Sfr", 0x1D516}, // MATHEMATICAL FRAKTUR CAPITAL S
+ {"sfr", 0x1D530}, // MATHEMATICAL FRAKTUR SMALL S
+ {"sfrown", 0x02322}, // FROWN
+ {"Sgr", 0x003A3}, // GREEK CAPITAL LETTER SIGMA
+ {"sgr", 0x003C3}, // GREEK SMALL LETTER SIGMA
+ {"sharp", 0x0266F}, // MUSIC SHARP SIGN
+ {"SHCHcy", 0x00429}, // CYRILLIC CAPITAL LETTER SHCHA
+ {"shchcy", 0x00449}, // CYRILLIC SMALL LETTER SHCHA
+ {"SHcy", 0x00428}, // CYRILLIC CAPITAL LETTER SHA
+ {"shcy", 0x00448}, // CYRILLIC SMALL LETTER SHA
+ {"ShortDownArrow", 0x02193}, // DOWNWARDS ARROW
+ {"ShortLeftArrow", 0x02190}, // LEFTWARDS ARROW
+ {"shortmid", 0x02223}, // DIVIDES
+ {"shortparallel", 0x02225}, // PARALLEL TO
+ {"ShortRightArrow", 0x02192}, // RIGHTWARDS ARROW
+ {"ShortUpArrow", 0x02191}, // UPWARDS ARROW
+ {"shy", 0x000AD}, // SOFT HYPHEN
+ {"Sigma", 0x003A3}, // GREEK CAPITAL LETTER SIGMA
+ {"sigma", 0x003C3}, // GREEK SMALL LETTER SIGMA
+ {"sigmaf", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
+ {"sigmav", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
+ {"sim", 0x0223C}, // TILDE OPERATOR
+ {"simdot", 0x02A6A}, // TILDE OPERATOR WITH DOT ABOVE
+ {"sime", 0x02243}, // ASYMPTOTICALLY EQUAL TO
+ {"simeq", 0x02243}, // ASYMPTOTICALLY EQUAL TO
+ {"simg", 0x02A9E}, // SIMILAR OR GREATER-THAN
+ {"simgE", 0x02AA0}, // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN
+ {"siml", 0x02A9D}, // SIMILAR OR LESS-THAN
+ {"simlE", 0x02A9F}, // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN
+ {"simne", 0x02246}, // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO
+ {"simplus", 0x02A24}, // PLUS SIGN WITH TILDE ABOVE
+ {"simrarr", 0x02972}, // TILDE OPERATOR ABOVE RIGHTWARDS ARROW
+ {"slarr", 0x02190}, // LEFTWARDS ARROW
+ {"SmallCircle", 0x02218}, // RING OPERATOR
+ {"smallsetminus", 0x02216}, // SET MINUS
+ {"smashp", 0x02A33}, // SMASH PRODUCT
+ {"smeparsl", 0x029E4}, // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE
+ {"smid", 0x02223}, // DIVIDES
+ {"smile", 0x02323}, // SMILE
+ {"smt", 0x02AAA}, // SMALLER THAN
+ {"smte", 0x02AAC}, // SMALLER THAN OR EQUAL TO
+// "smtes", 0x02AAC;0x0FE00}, // SMALLER THAN OR slanted EQUAL
+ {"SOFTcy", 0x0042C}, // CYRILLIC CAPITAL LETTER SOFT SIGN
+ {"softcy", 0x0044C}, // CYRILLIC SMALL LETTER SOFT SIGN
+ {"sol", 0x0002F}, // SOLIDUS
+ {"solb", 0x029C4}, // SQUARED RISING DIAGONAL SLASH
+ {"solbar", 0x0233F}, // APL FUNCTIONAL SYMBOL SLASH BAR
+ {"Sopf", 0x1D54A}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL S
+ {"sopf", 0x1D564}, // MATHEMATICAL DOUBLE-STRUCK SMALL S
+ {"spades", 0x02660}, // BLACK SPADE SUIT
+ {"spadesuit", 0x02660}, // BLACK SPADE SUIT
+ {"spar", 0x02225}, // PARALLEL TO
+ {"sqcap", 0x02293}, // SQUARE CAP
+// "sqcaps", 0x02293;0x0FE00}, // SQUARE CAP with serifs
+ {"sqcup", 0x02294}, // SQUARE CUP
+// "sqcups", 0x02294;0x0FE00}, // SQUARE CUP with serifs
+ {"Sqrt", 0x0221A}, // SQUARE ROOT
+ {"sqsub", 0x0228F}, // SQUARE IMAGE OF
+ {"sqsube", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO
+ {"sqsubset", 0x0228F}, // SQUARE IMAGE OF
+ {"sqsubseteq", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO
+ {"sqsup", 0x02290}, // SQUARE ORIGINAL OF
+ {"sqsupe", 0x02292}, // SQUARE ORIGINAL OF OR EQUAL TO
+ {"sqsupset", 0x02290}, // SQUARE ORIGINAL OF
+ {"sqsupseteq", 0x02292}, // SQUARE ORIGINAL OF OR EQUAL TO
+ {"squ", 0x025A1}, // WHITE SQUARE
+ {"square", 0x025A1}, // WHITE SQUARE
+ {"Square", 0x025A1}, // WHITE SQUARE
+ {"SquareIntersection", 0x02293}, // SQUARE CAP
+ {"SquareSubset", 0x0228F}, // SQUARE IMAGE OF
+ {"SquareSubsetEqual", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO
+ {"SquareSuperset", 0x02290}, // SQUARE ORIGINAL OF
+ {"SquareSupersetEqual", 0x02292}, // SQUARE ORIGINAL OF OR EQUAL TO
+ {"SquareUnion", 0x02294}, // SQUARE CUP
+ {"squarf", 0x025AA}, // BLACK SMALL SQUARE
+ {"squf", 0x025AA}, // BLACK SMALL SQUARE
+ {"srarr", 0x02192}, // RIGHTWARDS ARROW
+ {"Sscr", 0x1D4AE}, // MATHEMATICAL SCRIPT CAPITAL S
+ {"sscr", 0x1D4C8}, // MATHEMATICAL SCRIPT SMALL S
+ {"ssetmn", 0x02216}, // SET MINUS
+ {"ssmile", 0x02323}, // SMILE
+ {"sstarf", 0x022C6}, // STAR OPERATOR
+ {"Star", 0x022C6}, // STAR OPERATOR
+ {"star", 0x02606}, // WHITE STAR
+ {"starf", 0x02605}, // BLACK STAR
+ {"straightepsilon", 0x003F5}, // GREEK LUNATE EPSILON SYMBOL
+ {"straightphi", 0x003D5}, // GREEK PHI SYMBOL
+ {"strns", 0x000AF}, // MACRON
+ {"sub", 0x02282}, // SUBSET OF
+ {"Sub", 0x022D0}, // DOUBLE SUBSET
+ {"subdot", 0x02ABD}, // SUBSET WITH DOT
+ {"sube", 0x02286}, // SUBSET OF OR EQUAL TO
+ {"subE", 0x02AC5}, // SUBSET OF ABOVE EQUALS SIGN
+ {"subedot", 0x02AC3}, // SUBSET OF OR EQUAL TO WITH DOT ABOVE
+ {"submult", 0x02AC1}, // SUBSET WITH MULTIPLICATION SIGN BELOW
+ {"subne", 0x0228A}, // SUBSET OF WITH NOT EQUAL TO
+ {"subnE", 0x02ACB}, // SUBSET OF ABOVE NOT EQUAL TO
+ {"subplus", 0x02ABF}, // SUBSET WITH PLUS SIGN BELOW
+ {"subrarr", 0x02979}, // SUBSET ABOVE RIGHTWARDS ARROW
+ {"subset", 0x02282}, // SUBSET OF
+ {"Subset", 0x022D0}, // DOUBLE SUBSET
+ {"subseteq", 0x02286}, // SUBSET OF OR EQUAL TO
+ {"subseteqq", 0x02AC5}, // SUBSET OF ABOVE EQUALS SIGN
+ {"SubsetEqual", 0x02286}, // SUBSET OF OR EQUAL TO
+ {"subsetneq", 0x0228A}, // SUBSET OF WITH NOT EQUAL TO
+ {"subsetneqq", 0x02ACB}, // SUBSET OF ABOVE NOT EQUAL TO
+ {"subsim", 0x02AC7}, // SUBSET OF ABOVE TILDE OPERATOR
+ {"subsub", 0x02AD5}, // SUBSET ABOVE SUBSET
+ {"subsup", 0x02AD3}, // SUBSET ABOVE SUPERSET
+ {"succ", 0x0227B}, // SUCCEEDS
+ {"succapprox", 0x02AB8}, // SUCCEEDS ABOVE ALMOST EQUAL TO
+ {"succcurlyeq", 0x0227D}, // SUCCEEDS OR EQUAL TO
+ {"Succeeds", 0x0227B}, // SUCCEEDS
+ {"SucceedsEqual", 0x02AB0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
+ {"SucceedsSlantEqual", 0x0227D}, // SUCCEEDS OR EQUAL TO
+ {"SucceedsTilde", 0x0227F}, // SUCCEEDS OR EQUIVALENT TO
+ {"succeq", 0x02AB0}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN
+ {"succnapprox", 0x02ABA}, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO
+ {"succneqq", 0x02AB6}, // SUCCEEDS ABOVE NOT EQUAL TO
+ {"succnsim", 0x022E9}, // SUCCEEDS BUT NOT EQUIVALENT TO
+ {"succsim", 0x0227F}, // SUCCEEDS OR EQUIVALENT TO
+ {"SuchThat", 0x0220B}, // CONTAINS AS MEMBER
+ {"sum", 0x02211}, // N-ARY SUMMATION
+ {"Sum", 0x02211}, // N-ARY SUMMATION
+ {"sung", 0x0266A}, // EIGHTH NOTE
+ {"sup", 0x02283}, // SUPERSET OF
+ {"Sup", 0x022D1}, // DOUBLE SUPERSET
+ {"sup1", 0x000B9}, // SUPERSCRIPT ONE
+ {"sup2", 0x000B2}, // SUPERSCRIPT TWO
+ {"sup3", 0x000B3}, // SUPERSCRIPT THREE
+ {"supdot", 0x02ABE}, // SUPERSET WITH DOT
+ {"supdsub", 0x02AD8}, // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET
+ {"supe", 0x02287}, // SUPERSET OF OR EQUAL TO
+ {"supE", 0x02AC6}, // SUPERSET OF ABOVE EQUALS SIGN
+ {"supedot", 0x02AC4}, // SUPERSET OF OR EQUAL TO WITH DOT ABOVE
+ {"Superset", 0x02283}, // SUPERSET OF
+ {"SupersetEqual", 0x02287}, // SUPERSET OF OR EQUAL TO
+ {"suphsol", 0x027C9}, // SUPERSET PRECEDING SOLIDUS
+ {"suphsub", 0x02AD7}, // SUPERSET BESIDE SUBSET
+ {"suplarr", 0x0297B}, // SUPERSET ABOVE LEFTWARDS ARROW
+ {"supmult", 0x02AC2}, // SUPERSET WITH MULTIPLICATION SIGN BELOW
+ {"supne", 0x0228B}, // SUPERSET OF WITH NOT EQUAL TO
+ {"supnE", 0x02ACC}, // SUPERSET OF ABOVE NOT EQUAL TO
+ {"supplus", 0x02AC0}, // SUPERSET WITH PLUS SIGN BELOW
+ {"supset", 0x02283}, // SUPERSET OF
+ {"Supset", 0x022D1}, // DOUBLE SUPERSET
+ {"supseteq", 0x02287}, // SUPERSET OF OR EQUAL TO
+ {"supseteqq", 0x02AC6}, // SUPERSET OF ABOVE EQUALS SIGN
+ {"supsetneq", 0x0228B}, // SUPERSET OF WITH NOT EQUAL TO
+ {"supsetneqq", 0x02ACC}, // SUPERSET OF ABOVE NOT EQUAL TO
+ {"supsim", 0x02AC8}, // SUPERSET OF ABOVE TILDE OPERATOR
+ {"supsub", 0x02AD4}, // SUPERSET ABOVE SUBSET
+ {"supsup", 0x02AD6}, // SUPERSET ABOVE SUPERSET
+ {"swarhk", 0x02926}, // SOUTH WEST ARROW WITH HOOK
+ {"swarr", 0x02199}, // SOUTH WEST ARROW
+ {"swArr", 0x021D9}, // SOUTH WEST DOUBLE ARROW
+ {"swarrow", 0x02199}, // SOUTH WEST ARROW
+ {"swnwar", 0x0292A}, // SOUTH WEST ARROW AND NORTH WEST ARROW
+ {"szlig", 0x000DF}, // LATIN SMALL LETTER SHARP S
+];
+
+immutable NameId[] namesT =
+[
+ {"Tab", 0x00009}, // CHARACTER TABULATION
+ {"target", 0x02316}, // POSITION INDICATOR
+ {"Tau", 0x003A4}, // GREEK CAPITAL LETTER TAU
+ {"tau", 0x003C4}, // GREEK SMALL LETTER TAU
+ {"tbrk", 0x023B4}, // TOP SQUARE BRACKET
+ {"Tcaron", 0x00164}, // LATIN CAPITAL LETTER T WITH CARON
+ {"tcaron", 0x00165}, // LATIN SMALL LETTER T WITH CARON
+ {"Tcedil", 0x00162}, // LATIN CAPITAL LETTER T WITH CEDILLA
+ {"tcedil", 0x00163}, // LATIN SMALL LETTER T WITH CEDILLA
+ {"Tcy", 0x00422}, // CYRILLIC CAPITAL LETTER TE
+ {"tcy", 0x00442}, // CYRILLIC SMALL LETTER TE
+ {"tdot", 0x020DB}, // COMBINING THREE DOTS ABOVE
+ {"telrec", 0x02315}, // TELEPHONE RECORDER
+ {"Tfr", 0x1D517}, // MATHEMATICAL FRAKTUR CAPITAL T
+ {"tfr", 0x1D531}, // MATHEMATICAL FRAKTUR SMALL T
+ {"Tgr", 0x003A4}, // GREEK CAPITAL LETTER TAU
+ {"tgr", 0x003C4}, // GREEK SMALL LETTER TAU
+ {"there4", 0x02234}, // THEREFORE
+ {"therefore", 0x02234}, // THEREFORE
+ {"Therefore", 0x02234}, // THEREFORE
+ {"Theta", 0x00398}, // GREEK CAPITAL LETTER THETA
+ {"theta", 0x003B8}, // GREEK SMALL LETTER THETA
+ {"thetasym", 0x003D1}, // GREEK THETA SYMBOL
+ {"thetav", 0x003D1}, // GREEK THETA SYMBOL
+ {"THgr", 0x00398}, // GREEK CAPITAL LETTER THETA
+ {"thgr", 0x003B8}, // GREEK SMALL LETTER THETA
+ {"thickapprox", 0x02248}, // ALMOST EQUAL TO
+ {"thicksim", 0x0223C}, // TILDE OPERATOR
+// "ThickSpace", 0x0205F;0x0200A}, // space of width 5/18 em
+ {"thinsp", 0x02009}, // THIN SPACE
+ {"ThinSpace", 0x02009}, // THIN SPACE
+ {"thkap", 0x02248}, // ALMOST EQUAL TO
+ {"thksim", 0x0223C}, // TILDE OPERATOR
+ {"THORN", 0x000DE}, // LATIN CAPITAL LETTER THORN
+ {"thorn", 0x000FE}, // LATIN SMALL LETTER THORN
+ {"tilde", 0x002DC}, // SMALL TILDE
+ {"Tilde", 0x0223C}, // TILDE OPERATOR
+ {"TildeEqual", 0x02243}, // ASYMPTOTICALLY EQUAL TO
+ {"TildeFullEqual", 0x02245}, // APPROXIMATELY EQUAL TO
+ {"TildeTilde", 0x02248}, // ALMOST EQUAL TO
+ {"times", 0x000D7}, // MULTIPLICATION SIGN
+ {"timesb", 0x022A0}, // SQUARED TIMES
+ {"timesbar", 0x02A31}, // MULTIPLICATION SIGN WITH UNDERBAR
+ {"timesd", 0x02A30}, // MULTIPLICATION SIGN WITH DOT ABOVE
+ {"tint", 0x0222D}, // TRIPLE INTEGRAL
+ {"toea", 0x02928}, // NORTH EAST ARROW AND SOUTH EAST ARROW
+ {"top", 0x022A4}, // DOWN TACK
+ {"topbot", 0x02336}, // APL FUNCTIONAL SYMBOL I-BEAM
+ {"topcir", 0x02AF1}, // DOWN TACK WITH CIRCLE BELOW
+ {"Topf", 0x1D54B}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL T
+ {"topf", 0x1D565}, // MATHEMATICAL DOUBLE-STRUCK SMALL T
+ {"topfork", 0x02ADA}, // PITCHFORK WITH TEE TOP
+ {"tosa", 0x02929}, // SOUTH EAST ARROW AND SOUTH WEST ARROW
+ {"tprime", 0x02034}, // TRIPLE PRIME
+ {"trade", 0x02122}, // TRADE MARK SIGN
+ {"TRADE", 0x02122}, // TRADE MARK SIGN
+ {"triangle", 0x025B5}, // WHITE UP-POINTING SMALL TRIANGLE
+ {"triangledown", 0x025BF}, // WHITE DOWN-POINTING SMALL TRIANGLE
+ {"triangleleft", 0x025C3}, // WHITE LEFT-POINTING SMALL TRIANGLE
+ {"trianglelefteq", 0x022B4}, // NORMAL SUBGROUP OF OR EQUAL TO
+ {"triangleq", 0x0225C}, // DELTA EQUAL TO
+ {"triangleright", 0x025B9}, // WHITE RIGHT-POINTING SMALL TRIANGLE
+ {"trianglerighteq", 0x022B5}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO
+ {"tridot", 0x025EC}, // WHITE UP-POINTING TRIANGLE WITH DOT
+ {"trie", 0x0225C}, // DELTA EQUAL TO
+ {"triminus", 0x02A3A}, // MINUS SIGN IN TRIANGLE
+ {"TripleDot", 0x020DB}, // COMBINING THREE DOTS ABOVE
+ {"triplus", 0x02A39}, // PLUS SIGN IN TRIANGLE
+ {"trisb", 0x029CD}, // TRIANGLE WITH SERIFS AT BOTTOM
+ {"tritime", 0x02A3B}, // MULTIPLICATION SIGN IN TRIANGLE
+ {"trpezium", 0x023E2}, // WHITE TRAPEZIUM
+ {"Tscr", 0x1D4AF}, // MATHEMATICAL SCRIPT CAPITAL T
+ {"tscr", 0x1D4C9}, // MATHEMATICAL SCRIPT SMALL T
+ {"TScy", 0x00426}, // CYRILLIC CAPITAL LETTER TSE
+ {"tscy", 0x00446}, // CYRILLIC SMALL LETTER TSE
+ {"TSHcy", 0x0040B}, // CYRILLIC CAPITAL LETTER TSHE
+ {"tshcy", 0x0045B}, // CYRILLIC SMALL LETTER TSHE
+ {"Tstrok", 0x00166}, // LATIN CAPITAL LETTER T WITH STROKE
+ {"tstrok", 0x00167}, // LATIN SMALL LETTER T WITH STROKE
+ {"twixt", 0x0226C}, // BETWEEN
+ {"twoheadleftarrow", 0x0219E}, // LEFTWARDS TWO HEADED ARROW
+ {"twoheadrightarrow", 0x021A0}, // RIGHTWARDS TWO HEADED ARROW
+];
+
+immutable NameId[] namesU =
+[
+ {"Uacgr", 0x0038E}, // GREEK CAPITAL LETTER UPSILON WITH TONOS
+ {"uacgr", 0x003CD}, // GREEK SMALL LETTER UPSILON WITH TONOS
+ {"Uacute", 0x000DA}, // LATIN CAPITAL LETTER U WITH ACUTE
+ {"uacute", 0x000FA}, // LATIN SMALL LETTER U WITH ACUTE
+ {"uarr", 0x02191}, // UPWARDS ARROW
+ {"Uarr", 0x0219F}, // UPWARDS TWO HEADED ARROW
+ {"uArr", 0x021D1}, // UPWARDS DOUBLE ARROW
+ {"Uarrocir", 0x02949}, // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE
+ {"Ubrcy", 0x0040E}, // CYRILLIC CAPITAL LETTER SHORT U
+ {"ubrcy", 0x0045E}, // CYRILLIC SMALL LETTER SHORT U
+ {"Ubreve", 0x0016C}, // LATIN CAPITAL LETTER U WITH BREVE
+ {"ubreve", 0x0016D}, // LATIN SMALL LETTER U WITH BREVE
+ {"Ucirc", 0x000DB}, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+ {"ucirc", 0x000FB}, // LATIN SMALL LETTER U WITH CIRCUMFLEX
+ {"Ucy", 0x00423}, // CYRILLIC CAPITAL LETTER U
+ {"ucy", 0x00443}, // CYRILLIC SMALL LETTER U
+ {"udarr", 0x021C5}, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW
+ {"Udblac", 0x00170}, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+ {"udblac", 0x00171}, // LATIN SMALL LETTER U WITH DOUBLE ACUTE
+ {"udhar", 0x0296E}, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
+ {"udiagr", 0x003B0}, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+ {"Udigr", 0x003AB}, // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+ {"udigr", 0x003CB}, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+ {"ufisht", 0x0297E}, // UP FISH TAIL
+ {"Ufr", 0x1D518}, // MATHEMATICAL FRAKTUR CAPITAL U
+ {"ufr", 0x1D532}, // MATHEMATICAL FRAKTUR SMALL U
+ {"Ugr", 0x003A5}, // GREEK CAPITAL LETTER UPSILON
+ {"ugr", 0x003C5}, // GREEK SMALL LETTER UPSILON
+ {"Ugrave", 0x000D9}, // LATIN CAPITAL LETTER U WITH GRAVE
+ {"ugrave", 0x000F9}, // LATIN SMALL LETTER U WITH GRAVE
+ {"uHar", 0x02963}, // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT
+ {"uharl", 0x021BF}, // UPWARDS HARPOON WITH BARB LEFTWARDS
+ {"uharr", 0x021BE}, // UPWARDS HARPOON WITH BARB RIGHTWARDS
+ {"uhblk", 0x02580}, // UPPER HALF BLOCK
+ {"ulcorn", 0x0231C}, // TOP LEFT CORNER
+ {"ulcorner", 0x0231C}, // TOP LEFT CORNER
+ {"ulcrop", 0x0230F}, // TOP LEFT CROP
+ {"ultri", 0x025F8}, // UPPER LEFT TRIANGLE
+ {"Umacr", 0x0016A}, // LATIN CAPITAL LETTER U WITH MACRON
+ {"umacr", 0x0016B}, // LATIN SMALL LETTER U WITH MACRON
+ {"uml", 0x000A8}, // DIAERESIS
+ {"UnderBar", 0x0005F}, // LOW LINE
+ {"UnderBrace", 0x023DF}, // BOTTOM CURLY BRACKET
+ {"UnderBracket", 0x023B5}, // BOTTOM SQUARE BRACKET
+ {"UnderParenthesis", 0x023DD}, // BOTTOM PARENTHESIS
+ {"Union", 0x022C3}, // N-ARY UNION
+ {"UnionPlus", 0x0228E}, // MULTISET UNION
+ {"Uogon", 0x00172}, // LATIN CAPITAL LETTER U WITH OGONEK
+ {"uogon", 0x00173}, // LATIN SMALL LETTER U WITH OGONEK
+ {"Uopf", 0x1D54C}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL U
+ {"uopf", 0x1D566}, // MATHEMATICAL DOUBLE-STRUCK SMALL U
+ {"uparrow", 0x02191}, // UPWARDS ARROW
+ {"UpArrow", 0x02191}, // UPWARDS ARROW
+ {"Uparrow", 0x021D1}, // UPWARDS DOUBLE ARROW
+ {"UpArrowBar", 0x02912}, // UPWARDS ARROW TO BAR
+ {"UpArrowDownArrow", 0x021C5}, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW
+ {"updownarrow", 0x02195}, // UP DOWN ARROW
+ {"UpDownArrow", 0x02195}, // UP DOWN ARROW
+ {"Updownarrow", 0x021D5}, // UP DOWN DOUBLE ARROW
+ {"UpEquilibrium", 0x0296E}, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT
+ {"upharpoonleft", 0x021BF}, // UPWARDS HARPOON WITH BARB LEFTWARDS
+ {"upharpoonright", 0x021BE}, // UPWARDS HARPOON WITH BARB RIGHTWARDS
+ {"uplus", 0x0228E}, // MULTISET UNION
+ {"UpperLeftArrow", 0x02196}, // NORTH WEST ARROW
+ {"UpperRightArrow", 0x02197}, // NORTH EAST ARROW
+ {"upsi", 0x003C5}, // GREEK SMALL LETTER UPSILON
+ {"Upsi", 0x003D2}, // GREEK UPSILON WITH HOOK SYMBOL
+ {"upsih", 0x003D2}, // GREEK UPSILON WITH HOOK SYMBOL
+ {"Upsilon", 0x003A5}, // GREEK CAPITAL LETTER UPSILON
+ {"upsilon", 0x003C5}, // GREEK SMALL LETTER UPSILON
+ {"UpTee", 0x022A5}, // UP TACK
+ {"UpTeeArrow", 0x021A5}, // UPWARDS ARROW FROM BAR
+ {"upuparrows", 0x021C8}, // UPWARDS PAIRED ARROWS
+ {"urcorn", 0x0231D}, // TOP RIGHT CORNER
+ {"urcorner", 0x0231D}, // TOP RIGHT CORNER
+ {"urcrop", 0x0230E}, // TOP RIGHT CROP
+ {"Uring", 0x0016E}, // LATIN CAPITAL LETTER U WITH RING ABOVE
+ {"uring", 0x0016F}, // LATIN SMALL LETTER U WITH RING ABOVE
+ {"urtri", 0x025F9}, // UPPER RIGHT TRIANGLE
+ {"Uscr", 0x1D4B0}, // MATHEMATICAL SCRIPT CAPITAL U
+ {"uscr", 0x1D4CA}, // MATHEMATICAL SCRIPT SMALL U
+ {"utdot", 0x022F0}, // UP RIGHT DIAGONAL ELLIPSIS
+ {"Utilde", 0x00168}, // LATIN CAPITAL LETTER U WITH TILDE
+ {"utilde", 0x00169}, // LATIN SMALL LETTER U WITH TILDE
+ {"utri", 0x025B5}, // WHITE UP-POINTING SMALL TRIANGLE
+ {"utrif", 0x025B4}, // BLACK UP-POINTING SMALL TRIANGLE
+ {"uuarr", 0x021C8}, // UPWARDS PAIRED ARROWS
+ {"Uuml", 0x000DC}, // LATIN CAPITAL LETTER U WITH DIAERESIS
+ {"uuml", 0x000FC}, // LATIN SMALL LETTER U WITH DIAERESIS
+ {"uwangle", 0x029A7}, // OBLIQUE ANGLE OPENING DOWN
+];
+
+immutable NameId[] namesV =
+[
+ {"vangrt", 0x0299C}, // RIGHT ANGLE VARIANT WITH SQUARE
+ {"varepsilon", 0x003F5}, // GREEK LUNATE EPSILON SYMBOL
+ {"varkappa", 0x003F0}, // GREEK KAPPA SYMBOL
+ {"varnothing", 0x02205}, // EMPTY SET
+ {"varphi", 0x003D5}, // GREEK PHI SYMBOL
+ {"varpi", 0x003D6}, // GREEK PI SYMBOL
+ {"varpropto", 0x0221D}, // PROPORTIONAL TO
+ {"varr", 0x02195}, // UP DOWN ARROW
+ {"vArr", 0x021D5}, // UP DOWN DOUBLE ARROW
+ {"varrho", 0x003F1}, // GREEK RHO SYMBOL
+ {"varsigma", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA
+// "varsubsetneq", 0x0228A;0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
+// "varsubsetneqq", 0x02ACB;0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
+// "varsupsetneq", 0x0228B;0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
+// "varsupsetneqq", 0x02ACC;0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
+ {"vartheta", 0x003D1}, // GREEK THETA SYMBOL
+ {"vartriangleleft", 0x022B2}, // NORMAL SUBGROUP OF
+ {"vartriangleright", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP
+ {"vBar", 0x02AE8}, // SHORT UP TACK WITH UNDERBAR
+ {"Vbar", 0x02AEB}, // DOUBLE UP TACK
+ {"vBarv", 0x02AE9}, // SHORT UP TACK ABOVE SHORT DOWN TACK
+ {"Vcy", 0x00412}, // CYRILLIC CAPITAL LETTER VE
+ {"vcy", 0x00432}, // CYRILLIC SMALL LETTER VE
+ {"vdash", 0x022A2}, // RIGHT TACK
+ {"vDash", 0x022A8}, // TRUE
+ {"Vdash", 0x022A9}, // FORCES
+ {"VDash", 0x022AB}, // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE
+ {"Vdashl", 0x02AE6}, // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL
+ {"vee", 0x02228}, // LOGICAL OR
+ {"Vee", 0x022C1}, // N-ARY LOGICAL OR
+ {"veebar", 0x022BB}, // XOR
+ {"veeeq", 0x0225A}, // EQUIANGULAR TO
+ {"vellip", 0x022EE}, // VERTICAL ELLIPSIS
+ {"verbar", 0x0007C}, // VERTICAL LINE
+ {"Verbar", 0x02017}, // DOUBLE VERTICAL LINE
+ {"vert", 0x0007C}, // VERTICAL LINE
+ {"Vert", 0x02017}, // DOUBLE VERTICAL LINE
+ {"VerticalBar", 0x02223}, // DIVIDES
+ {"VerticalLine", 0x0007C}, // VERTICAL LINE
+ {"VerticalSeparator", 0x02758}, // LIGHT VERTICAL BAR
+ {"VerticalTilde", 0x02240}, // WREATH PRODUCT
+ {"VeryThinSpace", 0x0200A}, // HAIR SPACE
+ {"Vfr", 0x1D519}, // MATHEMATICAL FRAKTUR CAPITAL V
+ {"vfr", 0x1D533}, // MATHEMATICAL FRAKTUR SMALL V
+ {"vltri", 0x022B2}, // NORMAL SUBGROUP OF
+// "vnsub", 0x02282;0x020D2}, // SUBSET OF with vertical line
+// "vnsup", 0x02283;0x020D2}, // SUPERSET OF with vertical line
+ {"Vopf", 0x1D54D}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL V
+ {"vopf", 0x1D567}, // MATHEMATICAL DOUBLE-STRUCK SMALL V
+ {"vprop", 0x0221D}, // PROPORTIONAL TO
+ {"vrtri", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP
+ {"Vscr", 0x1D4B1}, // MATHEMATICAL SCRIPT CAPITAL V
+ {"vscr", 0x1D4CB}, // MATHEMATICAL SCRIPT SMALL V
+// "vsubne", 0x0228A;0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
+// "vsubnE", 0x02ACB;0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
+// "vsupne", 0x0228B;0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members
+// "vsupnE", 0x02ACC;0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members
+ {"Vvdash", 0x022AA}, // TRIPLE VERTICAL BAR RIGHT TURNSTILE
+ {"vzigzag", 0x0299A}, // VERTICAL ZIGZAG LINE
+];
+
+immutable NameId[] namesW =
+[
+ {"Wcirc", 0x00174}, // LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+ {"wcirc", 0x00175}, // LATIN SMALL LETTER W WITH CIRCUMFLEX
+ {"wedbar", 0x02A5F}, // LOGICAL AND WITH UNDERBAR
+ {"wedge", 0x02227}, // LOGICAL AND
+ {"Wedge", 0x022C0}, // N-ARY LOGICAL AND
+ {"wedgeq", 0x02259}, // ESTIMATES
+ {"weierp", 0x02118}, // SCRIPT CAPITAL P
+ {"Wfr", 0x1D51A}, // MATHEMATICAL FRAKTUR CAPITAL W
+ {"wfr", 0x1D534}, // MATHEMATICAL FRAKTUR SMALL W
+ {"Wopf", 0x1D54E}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL W
+ {"wopf", 0x1D568}, // MATHEMATICAL DOUBLE-STRUCK SMALL W
+ {"wp", 0x02118}, // SCRIPT CAPITAL P
+ {"wr", 0x02240}, // WREATH PRODUCT
+ {"wreath", 0x02240}, // WREATH PRODUCT
+ {"Wscr", 0x1D4B2}, // MATHEMATICAL SCRIPT CAPITAL W
+ {"wscr", 0x1D4CC}, // MATHEMATICAL SCRIPT SMALL W
+];
+
+immutable NameId[] namesX =
+[
+ {"xcap", 0x022C2}, // N-ARY INTERSECTION
+ {"xcirc", 0x025EF}, // LARGE CIRCLE
+ {"xcup", 0x022C3}, // N-ARY UNION
+ {"xdtri", 0x025BD}, // WHITE DOWN-POINTING TRIANGLE
+ {"Xfr", 0x1D51B}, // MATHEMATICAL FRAKTUR CAPITAL X
+ {"xfr", 0x1D535}, // MATHEMATICAL FRAKTUR SMALL X
+ {"Xgr", 0x0039E}, // GREEK CAPITAL LETTER XI
+ {"xgr", 0x003BE}, // GREEK SMALL LETTER XI
+ {"xharr", 0x027F7}, // LONG LEFT RIGHT ARROW
+ {"xhArr", 0x027FA}, // LONG LEFT RIGHT DOUBLE ARROW
+ {"Xi", 0x0039E}, // GREEK CAPITAL LETTER XI
+ {"xi", 0x003BE}, // GREEK SMALL LETTER XI
+ {"xlarr", 0x027F5}, // LONG LEFTWARDS ARROW
+ {"xlArr", 0x027F8}, // LONG LEFTWARDS DOUBLE ARROW
+ {"xmap", 0x027FC}, // LONG RIGHTWARDS ARROW FROM BAR
+ {"xnis", 0x022FB}, // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE
+ {"xodot", 0x02A00}, // N-ARY CIRCLED DOT OPERATOR
+ {"Xopf", 0x1D54F}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL X
+ {"xopf", 0x1D569}, // MATHEMATICAL DOUBLE-STRUCK SMALL X
+ {"xoplus", 0x02A01}, // N-ARY CIRCLED PLUS OPERATOR
+ {"xotime", 0x02A02}, // N-ARY CIRCLED TIMES OPERATOR
+ {"xrarr", 0x027F6}, // LONG RIGHTWARDS ARROW
+ {"xrArr", 0x027F9}, // LONG RIGHTWARDS DOUBLE ARROW
+ {"Xscr", 0x1D4B3}, // MATHEMATICAL SCRIPT CAPITAL X
+ {"xscr", 0x1D4CD}, // MATHEMATICAL SCRIPT SMALL X
+ {"xsqcup", 0x02A06}, // N-ARY SQUARE UNION OPERATOR
+ {"xuplus", 0x02A04}, // N-ARY UNION OPERATOR WITH PLUS
+ {"xutri", 0x025B3}, // WHITE UP-POINTING TRIANGLE
+ {"xvee", 0x022C1}, // N-ARY LOGICAL OR
+ {"xwedge", 0x022C0}, // N-ARY LOGICAL AND
+];
+
+immutable NameId[] namesY =
+[
+ {"Yacute", 0x000DD}, // LATIN CAPITAL LETTER Y WITH ACUTE
+ {"yacute", 0x000FD}, // LATIN SMALL LETTER Y WITH ACUTE
+ {"YAcy", 0x0042F}, // CYRILLIC CAPITAL LETTER YA
+ {"yacy", 0x0044F}, // CYRILLIC SMALL LETTER YA
+ {"Ycirc", 0x00176}, // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+ {"ycirc", 0x00177}, // LATIN SMALL LETTER Y WITH CIRCUMFLEX
+ {"Ycy", 0x0042B}, // CYRILLIC CAPITAL LETTER YERU
+ {"ycy", 0x0044B}, // CYRILLIC SMALL LETTER YERU
+ {"yen", 0x000A5}, // YEN SIGN
+ {"Yfr", 0x1D51C}, // MATHEMATICAL FRAKTUR CAPITAL Y
+ {"yfr", 0x1D536}, // MATHEMATICAL FRAKTUR SMALL Y
+ {"YIcy", 0x00407}, // CYRILLIC CAPITAL LETTER YI
+ {"yicy", 0x00457}, // CYRILLIC SMALL LETTER YI
+ {"Yopf", 0x1D550}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL Y
+ {"yopf", 0x1D56A}, // MATHEMATICAL DOUBLE-STRUCK SMALL Y
+ {"Yscr", 0x1D4B4}, // MATHEMATICAL SCRIPT CAPITAL Y
+ {"yscr", 0x1D4CE}, // MATHEMATICAL SCRIPT SMALL Y
+ {"YUcy", 0x0042E}, // CYRILLIC CAPITAL LETTER YU
+ {"yucy", 0x0044E}, // CYRILLIC SMALL LETTER YU
+ {"yuml", 0x000FF}, // LATIN SMALL LETTER Y WITH DIAERESIS
+ {"Yuml", 0x00178}, // LATIN CAPITAL LETTER Y WITH DIAERESIS
+];
+
+immutable NameId[] namesZ =
+[
+ {"Zacute", 0x00179}, // LATIN CAPITAL LETTER Z WITH ACUTE
+ {"zacute", 0x0017A}, // LATIN SMALL LETTER Z WITH ACUTE
+ {"Zcaron", 0x0017D}, // LATIN CAPITAL LETTER Z WITH CARON
+ {"zcaron", 0x0017E}, // LATIN SMALL LETTER Z WITH CARON
+ {"Zcy", 0x00417}, // CYRILLIC CAPITAL LETTER ZE
+ {"zcy", 0x00437}, // CYRILLIC SMALL LETTER ZE
+ {"Zdot", 0x0017B}, // LATIN CAPITAL LETTER Z WITH DOT ABOVE
+ {"zdot", 0x0017C}, // LATIN SMALL LETTER Z WITH DOT ABOVE
+ {"zeetrf", 0x02128}, // BLACK-LETTER CAPITAL Z
+ {"ZeroWidthSpace", 0x0200B}, // ZERO WIDTH SPACE
+ {"Zeta", 0x00396}, // GREEK CAPITAL LETTER ZETA
+ {"zeta", 0x003B6}, // GREEK SMALL LETTER ZETA
+ {"Zfr", 0x02128}, // BLACK-LETTER CAPITAL Z
+ {"zfr", 0x1D537}, // MATHEMATICAL FRAKTUR SMALL Z
+ {"Zgr", 0x00396}, // GREEK CAPITAL LETTER ZETA
+ {"zgr", 0x003B6}, // GREEK SMALL LETTER ZETA
+ {"ZHcy", 0x00416}, // CYRILLIC CAPITAL LETTER ZHE
+ {"zhcy", 0x00436}, // CYRILLIC SMALL LETTER ZHE
+ {"zigrarr", 0x021DD}, // RIGHTWARDS SQUIGGLE ARROW
+ {"Zopf", 0x02124}, // DOUBLE-STRUCK CAPITAL Z
+ {"zopf", 0x1D56B}, // MATHEMATICAL DOUBLE-STRUCK SMALL Z
+ {"Zscr", 0x1D4B5}, // MATHEMATICAL SCRIPT CAPITAL Z
+ {"zscr", 0x1D4CF}, // MATHEMATICAL SCRIPT SMALL Z
+ {"zwj", 0x0200D}, // ZERO WIDTH JOINER
+ {"zwnj", 0x0200C}, // ZERO WIDTH NON-JOINER
+];
diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h
index ae5ea21..76c1235 100644
--- a/gcc/d/dmd/enum.h
+++ b/gcc/d/dmd/enum.h
@@ -10,15 +10,12 @@
#pragma once
-#include "root/root.h"
#include "dsymbol.h"
#include "declaration.h"
-#include "tokens.h"
class Identifier;
class Type;
class Expression;
-class VarDeclaration;
class EnumDeclaration : public ScopeDsymbol
{
@@ -33,7 +30,7 @@ public:
*/
Type *type; // the TypeEnum
Type *memtype; // type of the members
- Prot protection;
+ Visibility visibility;
Expression *maxval;
Expression *minval;
@@ -43,20 +40,18 @@ public:
bool added;
int inuse;
- EnumDeclaration(Loc loc, Identifier *id, Type *memtype);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ EnumDeclaration *syntaxCopy(Dsymbol *s);
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope *sc);
bool oneMember(Dsymbol **ps, Identifier *ident);
Type *getType();
const char *kind() const;
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
- bool isDeprecated(); // is Dsymbol deprecated?
- Prot prot();
- Expression *getMaxMinValue(Loc loc, Identifier *id);
+ bool isDeprecated() const; // is Dsymbol deprecated?
+ Visibility visible();
bool isSpecial() const;
- Expression *getDefaultValue(Loc loc);
- Type *getMemtype(Loc loc);
+ Expression *getDefaultValue(const Loc &loc);
+ Type *getMemtype(const Loc &loc);
EnumDeclaration *isEnumDeclaration() { return this; }
@@ -83,12 +78,8 @@ public:
EnumDeclaration *ed;
- EnumMember(Loc loc, Identifier *id, Expression *value, Type *origType);
- EnumMember(Loc loc, Identifier *id, Expression *value, Type *memType,
- StorageClass stc, UserAttributeDeclaration *uad, DeprecatedDeclaration *dd);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ EnumMember *syntaxCopy(Dsymbol *s);
const char *kind() const;
- Expression *getVarExp(Loc loc, Scope *sc);
EnumMember *isEnumMember() { return this; }
void accept(Visitor *v) { v->visit(this); }
diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d
new file mode 100644
index 0000000..91a5c77
--- /dev/null
+++ b/gcc/d/dmd/errors.d
@@ -0,0 +1,446 @@
+/**
+ * Functions for raising errors.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errors.d, _errors.d)
+ * Documentation: https://dlang.org/phobos/dmd_errors.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/errors.d
+ */
+
+module dmd.errors;
+
+import core.stdc.stdarg;
+import dmd.globals;
+
+nothrow:
+
+/**
+ * Color highlighting to classify messages
+ */
+enum Classification : Color
+{
+ error = Color.brightRed, /// for errors
+ gagged = Color.brightBlue, /// for gagged errors
+ warning = Color.brightYellow, /// for warnings
+ deprecation = Color.brightCyan, /// for deprecations
+ tip = Color.brightGreen, /// for tip messages
+}
+
+enum Color : int
+{
+ black = 0,
+ red = 1,
+ green = 2,
+ blue = 4,
+ yellow = red | green,
+ magenta = red | blue,
+ cyan = green | blue,
+ lightGray = red | green | blue,
+ bright = 8,
+ darkGray = bright | black,
+ brightRed = bright | red,
+ brightGreen = bright | green,
+ brightBlue = bright | blue,
+ brightYellow = bright | yellow,
+ brightMagenta = bright | magenta,
+ brightCyan = bright | cyan,
+ white = bright | lightGray,
+}
+
+
+static if (__VERSION__ < 2092)
+ private extern (C++) void noop(const ref Loc loc, const(char)* format, ...) {}
+else
+ pragma(printf) private extern (C++) void noop(const ref Loc loc, const(char)* format, ...) {}
+
+
+package auto previewErrorFunc(bool isDeprecated, FeatureState featureState) @safe @nogc pure nothrow
+{
+ if (featureState == FeatureState.enabled)
+ return &error;
+ else if (featureState == FeatureState.disabled || isDeprecated)
+ return &noop;
+ else
+ return &deprecation;
+}
+
+package auto previewSupplementalFunc(bool isDeprecated, FeatureState featureState) @safe @nogc pure nothrow
+{
+ if (featureState == FeatureState.enabled)
+ return &errorSupplemental;
+ else if (featureState == FeatureState.disabled || isDeprecated)
+ return &noop;
+ else
+ return &deprecationSupplemental;
+}
+
+
+/**
+ * Print an error message, increasing the global error count.
+ * Params:
+ * loc = location of error
+ * format = printf-style format specification
+ * ... = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void error(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ verror(loc, format, ap);
+ va_end(ap);
+ }
+else
+ pragma(printf) extern (C++) void error(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ verror(loc, format, ap);
+ va_end(ap);
+ }
+
+/**
+ * Same as above, but takes a filename and line information arguments as separate parameters.
+ * Params:
+ * filename = source file of error
+ * linnum = line in the source file
+ * charnum = column number on the line
+ * format = printf-style format specification
+ * ... = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void error(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...)
+ {
+ const loc = Loc(filename, linnum, charnum);
+ va_list ap;
+ va_start(ap, format);
+ verror(loc, format, ap);
+ va_end(ap);
+ }
+else
+ pragma(printf) extern (C++) void error(const(char)* filename, uint linnum, uint charnum, const(char)* format, ...)
+ {
+ const loc = Loc(filename, linnum, charnum);
+ va_list ap;
+ va_start(ap, format);
+ verror(loc, format, ap);
+ va_end(ap);
+ }
+
+/**
+ * Print additional details about an error message.
+ * Doesn't increase the error count or print an additional error prefix.
+ * Params:
+ * loc = location of error
+ * format = printf-style format specification
+ * ... = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void errorSupplemental(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ verrorSupplemental(loc, format, ap);
+ va_end(ap);
+ }
+else
+ pragma(printf) extern (C++) void errorSupplemental(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ verrorSupplemental(loc, format, ap);
+ va_end(ap);
+ }
+
+/**
+ * Print a warning message, increasing the global warning count.
+ * Params:
+ * loc = location of warning
+ * format = printf-style format specification
+ * ... = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void warning(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vwarning(loc, format, ap);
+ va_end(ap);
+ }
+else
+ pragma(printf) extern (C++) void warning(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vwarning(loc, format, ap);
+ va_end(ap);
+ }
+
+/**
+ * Print additional details about a warning message.
+ * Doesn't increase the warning count or print an additional warning prefix.
+ * Params:
+ * loc = location of warning
+ * format = printf-style format specification
+ * ... = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void warningSupplemental(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vwarningSupplemental(loc, format, ap);
+ va_end(ap);
+ }
+else
+ pragma(printf) extern (C++) void warningSupplemental(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vwarningSupplemental(loc, format, ap);
+ va_end(ap);
+ }
+
+/**
+ * Print a deprecation message, may increase the global warning or error count
+ * depending on whether deprecations are ignored.
+ * Params:
+ * loc = location of deprecation
+ * format = printf-style format specification
+ * ... = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void deprecation(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vdeprecation(loc, format, ap);
+ va_end(ap);
+ }
+else
+ pragma(printf) extern (C++) void deprecation(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vdeprecation(loc, format, ap);
+ va_end(ap);
+ }
+
+/**
+ * Print additional details about a deprecation message.
+ * Doesn't increase the error count, or print an additional deprecation prefix.
+ * Params:
+ * loc = location of deprecation
+ * format = printf-style format specification
+ * ... = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void deprecationSupplemental(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vdeprecationSupplemental(loc, format, ap);
+ va_end(ap);
+ }
+else
+ pragma(printf) extern (C++) void deprecationSupplemental(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vdeprecationSupplemental(loc, format, ap);
+ va_end(ap);
+ }
+
+/**
+ * Print a verbose message.
+ * Doesn't prefix or highlight messages.
+ * Params:
+ * loc = location of message
+ * format = printf-style format specification
+ * ... = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void message(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vmessage(loc, format, ap);
+ va_end(ap);
+ }
+else
+ pragma(printf) extern (C++) void message(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vmessage(loc, format, ap);
+ va_end(ap);
+ }
+
+/**
+ * Same as above, but doesn't take a location argument.
+ * Params:
+ * format = printf-style format specification
+ * ... = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void message(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vmessage(Loc.initial, format, ap);
+ va_end(ap);
+ }
+else
+ pragma(printf) extern (C++) void message(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vmessage(Loc.initial, format, ap);
+ va_end(ap);
+ }
+
+/**
+ * The type of the diagnostic handler
+ * see verrorPrint for arguments
+ * Returns: true if error handling is done, false to continue printing to stderr
+ */
+alias DiagnosticHandler = bool delegate(const ref Loc location, Color headerColor, const(char)* header, const(char)* messageFormat, va_list args, const(char)* prefix1, const(char)* prefix2);
+
+/**
+ * The diagnostic handler.
+ * If non-null it will be called for every diagnostic message issued by the compiler.
+ * If it returns false, the message will be printed to stderr as usual.
+ */
+__gshared DiagnosticHandler diagnosticHandler;
+
+/**
+ * Print a tip message with the prefix and highlighting.
+ * Params:
+ * format = printf-style format specification
+ * ... = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void tip(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vtip(format, ap);
+ va_end(ap);
+ }
+else
+ pragma(printf) extern (C++) void tip(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ vtip(format, ap);
+ va_end(ap);
+ }
+
+
+/**
+ * Same as $(D error), but takes a va_list parameter, and optionally additional message prefixes.
+ * Params:
+ * loc = location of error
+ * format = printf-style format specification
+ * ap = printf-style variadic arguments
+ * p1 = additional message prefix
+ * p2 = additional message prefix
+ * header = title of error message
+ */
+extern (C++) void verror(const ref Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null, const(char)* header = "Error: ");
+
+/**
+ * Same as $(D errorSupplemental), but takes a va_list parameter.
+ * Params:
+ * loc = location of error
+ * format = printf-style format specification
+ * ap = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap);
+else
+ pragma(printf) extern (C++) void verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap);
+
+/**
+ * Same as $(D warning), but takes a va_list parameter.
+ * Params:
+ * loc = location of warning
+ * format = printf-style format specification
+ * ap = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void vwarning(const ref Loc loc, const(char)* format, va_list ap);
+else
+ pragma(printf) extern (C++) void vwarning(const ref Loc loc, const(char)* format, va_list ap);
+
+/**
+ * Same as $(D warningSupplemental), but takes a va_list parameter.
+ * Params:
+ * loc = location of warning
+ * format = printf-style format specification
+ * ap = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap);
+else
+ pragma(printf) extern (C++) void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap);
+
+/**
+ * Same as $(D deprecation), but takes a va_list parameter, and optionally additional message prefixes.
+ * Params:
+ * loc = location of deprecation
+ * format = printf-style format specification
+ * ap = printf-style variadic arguments
+ * p1 = additional message prefix
+ * p2 = additional message prefix
+ */
+extern (C++) void vdeprecation(const ref Loc loc, const(char)* format, va_list ap, const(char)* p1 = null, const(char)* p2 = null);
+
+/**
+ * Same as $(D message), but takes a va_list parameter.
+ * Params:
+ * loc = location of message
+ * format = printf-style format specification
+ * ap = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void vmessage(const ref Loc loc, const(char)* format, va_list ap);
+else
+ pragma(printf) extern (C++) void vmessage(const ref Loc loc, const(char)* format, va_list ap);
+
+/**
+ * Same as $(D tip), but takes a va_list parameter.
+ * Params:
+ * format = printf-style format specification
+ * ap = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void vtip(const(char)* format, va_list ap);
+else
+ pragma(printf) extern (C++) void vtip(const(char)* format, va_list ap);
+
+/**
+ * Same as $(D deprecationSupplemental), but takes a va_list parameter.
+ * Params:
+ * loc = location of deprecation
+ * format = printf-style format specification
+ * ap = printf-style variadic arguments
+ */
+static if (__VERSION__ < 2092)
+ extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap);
+else
+ pragma(printf) extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap);
+
+/**
+ * Call this after printing out fatal error messages to clean up and exit
+ * the compiler.
+ */
+extern (C++) void fatal();
+
+/**
+ * Try to stop forgetting to remove the breakpoints from
+ * release builds.
+ */
+extern (C++) void halt();
diff --git a/gcc/d/dmd/errors.h b/gcc/d/dmd/errors.h
index a92ae2a..6d9587d 100644
--- a/gcc/d/dmd/errors.h
+++ b/gcc/d/dmd/errors.h
@@ -11,7 +11,8 @@
#pragma once
#include "root/dsystem.h"
-#include "globals.h"
+
+struct Loc;
bool isConsoleColorSupported();
@@ -27,6 +28,7 @@ D_ATTRIBUTE_FORMAT(2, 3) void warningSupplemental(const Loc& loc, const char *fo
D_ATTRIBUTE_FORMAT(2, 3) void deprecation(const Loc& loc, const char *format, ...);
D_ATTRIBUTE_FORMAT(2, 3) void deprecationSupplemental(const Loc& loc, const char *format, ...);
D_ATTRIBUTE_FORMAT(2, 3) void error(const Loc& loc, const char *format, ...);
+D_ATTRIBUTE_FORMAT(4, 5) void error(const char *filename, unsigned linnum, unsigned charnum, const char *format, ...);
D_ATTRIBUTE_FORMAT(2, 3) void errorSupplemental(const Loc& loc, const char *format, ...);
D_ATTRIBUTE_FORMAT(2, 0) void verror(const Loc& loc, const char *format, va_list ap, const char *p1 = NULL, const char *p2 = NULL, const char *header = "Error: ");
D_ATTRIBUTE_FORMAT(2, 0) void verrorSupplemental(const Loc& loc, const char *format, va_list ap);
@@ -36,7 +38,9 @@ D_ATTRIBUTE_FORMAT(2, 0) void vdeprecation(const Loc& loc, const char *format, v
D_ATTRIBUTE_FORMAT(2, 0) void vdeprecationSupplemental(const Loc& loc, const char *format, va_list ap);
D_ATTRIBUTE_FORMAT(1, 2) void message(const char *format, ...);
D_ATTRIBUTE_FORMAT(2, 3) void message(const Loc& loc, const char *format, ...);
-D_ATTRIBUTE_FORMAT(2, 0) void vmessage(const Loc& loc, const char *format, va_list);
+D_ATTRIBUTE_FORMAT(2, 0) void vmessage(const Loc& loc, const char *format, va_list ap);
+D_ATTRIBUTE_FORMAT(1, 2) void tip(const char *format, ...);
+D_ATTRIBUTE_FORMAT(1, 0) void vtip(const char *format, va_list ap);
#if defined(__GNUC__) || defined(__clang__)
#define D_ATTRIBUTE_NORETURN __attribute__((noreturn))
diff --git a/gcc/d/dmd/escape.c b/gcc/d/dmd/escape.c
deleted file mode 100644
index cd0382b..0000000
--- a/gcc/d/dmd/escape.c
+++ /dev/null
@@ -1,1234 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/escape.c
- */
-
-#include "mars.h"
-#include "init.h"
-#include "expression.h"
-#include "scope.h"
-#include "aggregate.h"
-#include "declaration.h"
-#include "module.h"
-
-/************************************
- * Aggregate the data collected by the escapeBy??() functions.
- */
-struct EscapeByResults
-{
- VarDeclarations byref; // array into which variables being returned by ref are inserted
- VarDeclarations byvalue; // array into which variables with values containing pointers are inserted
- FuncDeclarations byfunc; // nested functions that are turned into delegates
- Expressions byexp; // array into which temporaries being returned by ref are inserted
-};
-
-static bool checkReturnEscapeImpl(Scope *sc, Expression *e, bool refs, bool gag);
-static void inferReturn(FuncDeclaration *fd, VarDeclaration *v);
-static void escapeByValue(Expression *e, EscapeByResults *er);
-static void escapeByRef(Expression *e, EscapeByResults *er);
-static void findAllOuterAccessedVariables(FuncDeclaration *fd, VarDeclarations *vars);
-
-/* 'v' is assigned unsafely to 'par'
-*/
-static void unsafeAssign(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag,
- bool &result, VarDeclaration *v, const char *desc)
-{
- if (global.params.vsafe && sc->func->setUnsafe())
- {
- if (!gag)
- error(arg->loc, "%s %s assigned to non-scope parameter %s calling %s",
- desc, v->toChars(),
- par ? par->toChars() : "unnamed",
- fdc ? fdc->toPrettyChars() : "indirectly");
- result = true;
- }
-}
-
-/****************************************
- * Function parameter par is being initialized to arg,
- * and par may escape.
- * Detect if scoped values can escape this way.
- * Print error messages when these are detected.
- * Params:
- * sc = used to determine current function and module
- * par = identifier of function parameter
- * arg = initializer for param
- * gag = do not print error messages
- * Returns:
- * true if pointers to the stack can escape via assignment
- */
-bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag)
-{
- //printf("checkParamArgumentEscape(arg: %s par: %s)\n", arg->toChars(), par->toChars());
- //printf("type = %s, %d\n", arg->type->toChars(), arg->type->hasPointers());
-
- if (!arg->type->hasPointers())
- return false;
-
- EscapeByResults er;
-
- escapeByValue(arg, &er);
-
- if (!er.byref.length && !er.byvalue.length && !er.byfunc.length && !er.byexp.length)
- return false;
-
- bool result = false;
-
- for (size_t i = 0; i < er.byvalue.length; i++)
- {
- //printf("byvalue %s\n", v->toChars());
- VarDeclaration *v = er.byvalue[i];
- if (v->isDataseg())
- continue;
-
- Dsymbol *p = v->toParent2();
-
- v->storage_class &= ~STCmaybescope;
-
- if (v->isScope())
- {
- unsafeAssign(sc, fdc, par, arg, gag, result, v, "scope variable");
- }
- else if (v->storage_class & STCvariadic && p == sc->func)
- {
- Type *tb = v->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- unsafeAssign(sc, fdc, par, arg, gag, result, v, "variadic variable");
- }
- }
- else
- {
- /* v is not 'scope', and is assigned to a parameter that may escape.
- * Therefore, v can never be 'scope'.
- */
- v->doNotInferScope = true;
- }
- }
-
- for (size_t i = 0; i < er.byref.length; i++)
- {
- VarDeclaration *v = er.byref[i];
- if (v->isDataseg())
- continue;
-
- Dsymbol *p = v->toParent2();
-
- v->storage_class &= ~STCmaybescope;
-
- if ((v->storage_class & (STCref | STCout)) == 0 && p == sc->func)
- {
- unsafeAssign(sc, fdc, par, arg, gag, result, v, "reference to local variable");
- continue;
- }
- }
-
- for (size_t i = 0; i < er.byfunc.length; i++)
- {
- FuncDeclaration *fd = er.byfunc[i];
- //printf("fd = %s, %d\n", fd->toChars(), fd->tookAddressOf);
- VarDeclarations vars;
- findAllOuterAccessedVariables(fd, &vars);
-
- for (size_t j = 0; j < vars.length; j++)
- {
- VarDeclaration *v = vars[j];
- //printf("v = %s\n", v->toChars());
- assert(!v->isDataseg()); // these are not put in the closureVars[]
-
- Dsymbol *p = v->toParent2();
-
- v->storage_class &= ~STCmaybescope;
-
- if ((v->storage_class & (STCref | STCout | STCscope)) && p == sc->func)
- {
- unsafeAssign(sc, fdc, par, arg, gag, result, v, "reference to local");
- continue;
- }
- }
- }
-
- for (size_t i = 0; i < er.byexp.length; i++)
- {
- Expression *ee = er.byexp[i];
- if (sc->func->setUnsafe())
- {
- if (!gag)
- error(ee->loc, "reference to stack allocated value returned by %s assigned to non-scope parameter %s",
- ee->toChars(),
- par ? par->toChars() : "unnamed");
- result = true;
- }
- }
-
- return result;
-}
-
-/****************************************
- * Given an AssignExp, determine if the lvalue will cause
- * the contents of the rvalue to escape.
- * Print error messages when these are detected.
- * Infer 'scope' for the lvalue where possible, in order
- * to eliminate the error.
- * Params:
- * sc = used to determine current function and module
- * ae = AssignExp to check for any pointers to the stack
- * gag = do not print error messages
- * Returns:
- * true if pointers to the stack can escape via assignment
- */
-bool checkAssignEscape(Scope *sc, Expression *e, bool gag)
-{
- //printf("checkAssignEscape(e: %s)\n", e->toChars());
- if (e->op != TOKassign && e->op != TOKblit && e->op != TOKconstruct)
- return false;
- AssignExp *ae = (AssignExp *)e;
- Expression *e1 = ae->e1;
- Expression *e2 = ae->e2;
- //printf("type = %s, %d\n", e1->type->toChars(), e1->type->hasPointers());
-
- if (!e1->type->hasPointers())
- return false;
-
- if (e1->op == TOKslice)
- return false;
-
- EscapeByResults er;
-
- escapeByValue(e2, &er);
-
- if (!er.byref.length && !er.byvalue.length && !er.byfunc.length && !er.byexp.length)
- return false;
-
- VarDeclaration *va = NULL;
- while (e1->op == TOKdotvar)
- e1 = ((DotVarExp *)e1)->e1;
-
- if (e1->op == TOKvar)
- va = ((VarExp *)e1)->var->isVarDeclaration();
- else if (e1->op == TOKthis)
- va = ((ThisExp *)e1)->var->isVarDeclaration();
- else if (e1->op == TOKindex)
- {
- IndexExp *ie = (IndexExp *)e1;
- if (ie->e1->op == TOKvar && ie->e1->type->toBasetype()->ty == Tsarray)
- va = ((VarExp *)ie->e1)->var->isVarDeclaration();
- }
-
- // Try to infer 'scope' for va if in a function not marked @system
- bool inferScope = false;
- if (va && sc->func && sc->func->type && sc->func->type->ty == Tfunction)
- inferScope = ((TypeFunction *)sc->func->type)->trust != TRUSTsystem;
-
- bool result = false;
- for (size_t i = 0; i < er.byvalue.length; i++)
- {
- VarDeclaration *v = er.byvalue[i];
- //printf("byvalue: %s\n", v->toChars());
- if (v->isDataseg())
- continue;
-
- Dsymbol *p = v->toParent2();
-
- if (!(va && va->isScope()))
- v->storage_class &= ~STCmaybescope;
-
- if (v->isScope())
- {
- if (va && va->isScope() && va->storage_class & STCreturn && !(v->storage_class & STCreturn) &&
- sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "scope variable %s assigned to return scope %s", v->toChars(), va->toChars());
- result = true;
- continue;
- }
-
- // If va's lifetime encloses v's, then error
- if (va &&
- ((va->enclosesLifetimeOf(v) && !(v->storage_class & STCparameter)) ||
- // va is class reference
- (ae->e1->op == TOKdotvar && va->type->toBasetype()->ty == Tclass && (va->enclosesLifetimeOf(v) || !va->isScope())) ||
- va->storage_class & STCref) &&
- sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "scope variable %s assigned to %s with longer lifetime", v->toChars(), va->toChars());
- result = true;
- continue;
- }
-
- if (va && !va->isDataseg() && !va->doNotInferScope)
- {
- if (!va->isScope() && inferScope)
- { //printf("inferring scope for %s\n", va->toChars());
- va->storage_class |= STCscope | STCscopeinferred;
- va->storage_class |= v->storage_class & STCreturn;
- }
- continue;
- }
- if (sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "scope variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
- result = true;
- }
- }
- else if (v->storage_class & STCvariadic && p == sc->func)
- {
- Type *tb = v->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (va && !va->isDataseg() && !va->doNotInferScope)
- {
- if (!va->isScope() && inferScope)
- { //printf("inferring scope for %s\n", va->toChars());
- va->storage_class |= STCscope | STCscopeinferred;
- }
- continue;
- }
- if (sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "variadic variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
- result = true;
- }
- }
- }
- else
- {
- /* v is not 'scope', and we didn't check the scope of where we assigned it to.
- * It may escape via that assignment, therefore, v can never be 'scope'.
- */
- v->doNotInferScope = true;
- }
- }
-
- for (size_t i = 0; i < er.byref.length; i++)
- {
- VarDeclaration *v = er.byref[i];
- //printf("byref: %s\n", v->toChars());
- if (v->isDataseg())
- continue;
-
- Dsymbol *p = v->toParent2();
-
- // If va's lifetime encloses v's, then error
- if (va &&
- ((va->enclosesLifetimeOf(v) && !(v->storage_class & STCparameter)) || va->storage_class & STCref) &&
- sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "address of variable %s assigned to %s with longer lifetime", v->toChars(), va->toChars());
- result = true;
- continue;
- }
-
- if (!(va && va->isScope()))
- v->storage_class &= ~STCmaybescope;
-
- if ((v->storage_class & (STCref | STCout)) == 0 && p == sc->func)
- {
- if (va && !va->isDataseg() && !va->doNotInferScope)
- {
- if (!va->isScope() && inferScope)
- { //printf("inferring scope for %s\n", va->toChars());
- va->storage_class |= STCscope | STCscopeinferred;
- }
- continue;
- }
- if (sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "reference to local variable %s assigned to non-scope %s", v->toChars(), e1->toChars());
- result = true;
- }
- continue;
- }
- }
-
- for (size_t i = 0; i < er.byfunc.length; i++)
- {
- FuncDeclaration *fd = er.byfunc[i];
- //printf("fd = %s, %d\n", fd->toChars(), fd->tookAddressOf);
- VarDeclarations vars;
- findAllOuterAccessedVariables(fd, &vars);
-
- for (size_t j = 0; j < vars.length; j++)
- {
- VarDeclaration *v = vars[j];
- //printf("v = %s\n", v->toChars());
- assert(!v->isDataseg()); // these are not put in the closureVars[]
-
- Dsymbol *p = v->toParent2();
-
- if (!(va && va->isScope()))
- v->storage_class &= ~STCmaybescope;
-
- if ((v->storage_class & (STCref | STCout | STCscope)) && p == sc->func)
- {
- if (va && !va->isDataseg() && !va->doNotInferScope)
- {
- /* Don't infer STCscope for va, because then a closure
- * won't be generated for sc->func.
- */
- //if (!va->isScope() && inferScope)
- //va->storage_class |= STCscope | STCscopeinferred;
- continue;
- }
- if (sc->func->setUnsafe())
- {
- if (!gag)
- error(ae->loc, "reference to local %s assigned to non-scope %s in @safe code", v->toChars(), e1->toChars());
- result = true;
- }
- continue;
- }
- }
- }
-
- for (size_t i = 0; i < er.byexp.length; i++)
- {
- Expression *ee = er.byexp[i];
- if (va && !va->isDataseg() && !va->doNotInferScope)
- {
- if (!va->isScope() && inferScope)
- { //printf("inferring scope for %s\n", va->toChars());
- va->storage_class |= STCscope | STCscopeinferred;
- }
- continue;
- }
- if (sc->func->setUnsafe())
- {
- if (!gag)
- error(ee->loc, "reference to stack allocated value returned by %s assigned to non-scope %s",
- ee->toChars(), e1->toChars());
- result = true;
- }
- }
-
- return result;
-}
-
-/************************************
- * Detect cases where pointers to the stack can 'escape' the
- * lifetime of the stack frame when throwing `e`.
- * Print error messages when these are detected.
- * Params:
- * sc = used to determine current function and module
- * e = expression to check for any pointers to the stack
- * gag = do not print error messages
- * Returns:
- * true if pointers to the stack can escape
- */
-bool checkThrowEscape(Scope *sc, Expression *e, bool gag)
-{
- //printf("[%s] checkThrowEscape, e = %s\n", e->loc->toChars(), e->toChars());
- EscapeByResults er;
-
- escapeByValue(e, &er);
-
- if (!er.byref.length && !er.byvalue.length && !er.byexp.length)
- return false;
-
- bool result = false;
- for (size_t i = 0; i < er.byvalue.length; i++)
- {
- VarDeclaration *v = er.byvalue[i];
- //printf("byvalue %s\n", v->toChars());
- if (v->isDataseg())
- continue;
-
- if (v->isScope())
- {
- if (sc->_module && sc->_module->isRoot())
- {
- // Only look for errors if in module listed on command line
- if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029
- {
- if (!gag)
- error(e->loc, "scope variable %s may not be thrown", v->toChars());
- result = true;
- }
- continue;
- }
- }
- else
- {
- //printf("no infer for %s\n", v->toChars());
- v->doNotInferScope = true;
- }
- }
- return result;
-}
-
-/************************************
- * Detect cases where pointers to the stack can 'escape' the
- * lifetime of the stack frame by returning 'e' by value.
- * Params:
- * sc = used to determine current function and module
- * e = expression to check for any pointers to the stack
- * gag = do not print error messages
- * Returns:
- * true if pointers to the stack can escape
- */
-
-bool checkReturnEscape(Scope *sc, Expression *e, bool gag)
-{
- //printf("[%s] checkReturnEscape, e = %s\n", e->loc->toChars(), e->toChars());
- return checkReturnEscapeImpl(sc, e, false, gag);
-}
-
-/************************************
- * Detect cases where returning 'e' by ref can result in a reference to the stack
- * being returned.
- * Print error messages when these are detected.
- * Params:
- * sc = used to determine current function and module
- * e = expression to check
- * gag = do not print error messages
- * Returns:
- * true if references to the stack can escape
- */
-bool checkReturnEscapeRef(Scope *sc, Expression *e, bool gag)
-{
- //printf("[%s] checkReturnEscapeRef, e = %s\n", e->loc.toChars(), e->toChars());
- //printf("current function %s\n", sc->func->toChars());
- //printf("parent2 function %s\n", sc->func->toParent2()->toChars());
-
- return checkReturnEscapeImpl(sc, e, true, gag);
-}
-
-static void escapingRef(VarDeclaration *v, Expression *e, bool &result, bool gag)
-{
- if (!gag)
- {
- const char *msg;
- if (v->storage_class & STCparameter)
- msg = "returning `%s` escapes a reference to parameter `%s`, perhaps annotate with `return`";
- else
- msg = "returning `%s` escapes a reference to local variable `%s`";
- error(e->loc, msg, e->toChars(), v->toChars());
- }
- result = true;
-}
-
-static bool checkReturnEscapeImpl(Scope *sc, Expression *e, bool refs, bool gag)
-{
- //printf("[%s] checkReturnEscapeImpl, e = %s\n", e->loc->toChars(), e->toChars());
- EscapeByResults er;
-
- if (refs)
- escapeByRef(e, &er);
- else
- escapeByValue(e, &er);
-
- if (!er.byref.length && !er.byvalue.length && !er.byexp.length)
- return false;
-
- bool result = false;
- for (size_t i = 0; i < er.byvalue.length; i++)
- {
- VarDeclaration *v = er.byvalue[i];
- //printf("byvalue %s\n", v->toChars());
- if (v->isDataseg())
- continue;
-
- Dsymbol *p = v->toParent2();
-
- if ((v->isScope() || (v->storage_class & STCmaybescope)) &&
- !(v->storage_class & STCreturn) &&
- v->isParameter() &&
- sc->func->flags & FUNCFLAGreturnInprocess &&
- p == sc->func)
- {
- inferReturn(sc->func, v); // infer addition of 'return'
- continue;
- }
-
- if (v->isScope())
- {
- if (v->storage_class & STCreturn)
- continue;
-
- if (sc->_module && sc->_module->isRoot() &&
- /* This case comes up when the ReturnStatement of a __foreachbody is
- * checked for escapes by the caller of __foreachbody. Skip it.
- *
- * struct S { static int opApply(int delegate(S*) dg); }
- * S* foo() {
- * foreach (S* s; S) // create __foreachbody for body of foreach
- * return s; // s is inferred as 'scope' but incorrectly tested in foo()
- * return null; }
- */
- !(!refs && p->parent == sc->func))
- {
- // Only look for errors if in module listed on command line
- if (global.params.vsafe) // https://issues.dlang.org/show_bug.cgi?id=17029
- {
- if (!gag)
- error(e->loc, "scope variable %s may not be returned", v->toChars());
- result = true;
- }
- continue;
- }
- }
- else if (v->storage_class & STCvariadic && p == sc->func)
- {
- Type *tb = v->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!gag)
- error(e->loc, "returning `%s` escapes a reference to variadic parameter `%s`", e->toChars(), v->toChars());
- result = false;
- }
- }
- else
- {
- //printf("no infer for %s\n", v->toChars());
- v->doNotInferScope = true;
- }
- }
-
- for (size_t i = 0; i < er.byref.length; i++)
- {
- VarDeclaration *v = er.byref[i];
- //printf("byref %s\n", v->toChars());
- if (v->isDataseg())
- continue;
-
- Dsymbol *p = v->toParent2();
-
- if ((v->storage_class & (STCref | STCout)) == 0)
- {
- if (p == sc->func)
- {
- escapingRef(v, e, result, gag);
- continue;
- }
- FuncDeclaration *fd = p->isFuncDeclaration();
- if (fd && sc->func->flags & FUNCFLAGreturnInprocess)
- {
- /* Code like:
- * int x;
- * auto dg = () { return &x; }
- * Making it:
- * auto dg = () return { return &x; }
- * Because dg.ptr points to x, this is returning dt.ptr+offset
- */
- if (global.params.vsafe)
- sc->func->storage_class |= STCreturn;
- }
- }
-
- /* Check for returning a ref variable by 'ref', but should be 'return ref'
- * Infer the addition of 'return', or set result to be the offending expression.
- */
- if ( (v->storage_class & (STCref | STCout)) &&
- !(v->storage_class & (STCreturn | STCforeach)))
- {
- if ((sc->func->flags & FUNCFLAGreturnInprocess) && p == sc->func)
- {
- inferReturn(sc->func, v); // infer addition of 'return'
- }
- else if (global.params.useDIP25 &&
- sc->_module && sc->_module->isRoot())
- {
- // Only look for errors if in module listed on command line
-
- if (p == sc->func)
- {
- //printf("escaping reference to local ref variable %s\n", v->toChars());
- //printf("storage class = x%llx\n", v->storage_class);
- escapingRef(v, e, result, gag);
- continue;
- }
- // Don't need to be concerned if v's parent does not return a ref
- FuncDeclaration *fd = p->isFuncDeclaration();
- if (fd && fd->type && fd->type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (tf->isref)
- {
- if (!gag)
- error(e->loc, "escaping reference to outer local variable %s", v->toChars());
- result = true;
- continue;
- }
- }
- }
- }
- }
-
- for (size_t i = 0; i < er.byexp.length; i++)
- {
- Expression *ee = er.byexp[i];
- //printf("byexp %s\n", ee->toChars());
- if (!gag)
- error(ee->loc, "escaping reference to stack allocated value returned by %s", ee->toChars());
- result = true;
- }
-
- return result;
-}
-
-
-/*************************************
- * Variable v needs to have 'return' inferred for it.
- * Params:
- * fd = function that v is a parameter to
- * v = parameter that needs to be STCreturn
- */
-
-static void inferReturn(FuncDeclaration *fd, VarDeclaration *v)
-{
- // v is a local in the current function
-
- //printf("for function '%s' inferring 'return' for variable '%s'\n", fd->toChars(), v->toChars());
- v->storage_class |= STCreturn;
-
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (v == fd->vthis)
- {
- /* v is the 'this' reference, so mark the function
- */
- fd->storage_class |= STCreturn;
- if (tf->ty == Tfunction)
- {
- //printf("'this' too %p %s\n", tf, sc->func->toChars());
- tf->isreturn = true;
- }
- }
- else
- {
- // Perform 'return' inference on parameter
- if (tf->ty == Tfunction)
- {
- const size_t dim = tf->parameterList.length();
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *p = tf->parameterList[i];
- if (p->ident == v->ident)
- {
- p->storageClass |= STCreturn;
- break; // there can be only one
- }
- }
- }
- }
-}
-
-
-/****************************************
- * e is an expression to be returned by value, and that value contains pointers.
- * Walk e to determine which variables are possibly being
- * returned by value, such as:
- * int* function(int* p) { return p; }
- * If e is a form of &p, determine which variables have content
- * which is being returned as ref, such as:
- * int* function(int i) { return &i; }
- * Multiple variables can be inserted, because of expressions like this:
- * int function(bool b, int i, int* p) { return b ? &i : p; }
- *
- * No side effects.
- *
- * Params:
- * e = expression to be returned by value
- * er = where to place collected data
- */
-static void escapeByValue(Expression *e, EscapeByResults *er)
-{
- //printf("[%s] escapeByValue, e: %s\n", e->loc.toChars(), e->toChars());
-
- class EscapeVisitor : public Visitor
- {
- public:
- EscapeByResults *er;
-
- EscapeVisitor(EscapeByResults *er)
- : er(er)
- {
- }
-
- void visit(Expression *)
- {
- }
-
- void visit(AddrExp *e)
- {
- escapeByRef(e->e1, er);
- }
-
- void visit(SymOffExp *e)
- {
- VarDeclaration *v = e->var->isVarDeclaration();
- if (v)
- er->byref.push(v);
- }
-
- void visit(VarExp *e)
- {
- VarDeclaration *v = e->var->isVarDeclaration();
- if (v)
- er->byvalue.push(v);
- }
-
- void visit(ThisExp *e)
- {
- if (e->var)
- er->byvalue.push(e->var);
- }
-
- void visit(DotVarExp *e)
- {
- Type *t = e->e1->type->toBasetype();
- if (t->ty == Tstruct)
- e->e1->accept(this);
- }
-
- void visit(DelegateExp *e)
- {
- Type *t = e->e1->type->toBasetype();
- if (t->ty == Tclass || t->ty == Tpointer)
- escapeByValue(e->e1, er);
- else
- escapeByRef(e->e1, er);
- er->byfunc.push(e->func);
- }
-
- void visit(FuncExp *e)
- {
- if (e->fd->tok == TOKdelegate)
- er->byfunc.push(e->fd);
- }
-
- void visit(TupleExp *)
- {
- assert(0); // should have been lowered by now
- }
-
- void visit(ArrayLiteralExp *e)
- {
- Type *tb = e->type->toBasetype();
- if (tb->ty == Tsarray || tb->ty == Tarray)
- {
- if (e->basis)
- e->basis->accept(this);
- for (size_t i = 0; i < e->elements->length; i++)
- {
- Expression *el = (*e->elements)[i];
- if (el)
- el->accept(this);
- }
- }
- }
-
- void visit(StructLiteralExp *e)
- {
- if (e->elements)
- {
- for (size_t i = 0; i < e->elements->length; i++)
- {
- Expression *ex = (*e->elements)[i];
- if (ex)
- ex->accept(this);
- }
- }
- }
-
- void visit(NewExp *e)
- {
- Type *tb = e->newtype->toBasetype();
- if (tb->ty == Tstruct && !e->member && e->arguments)
- {
- for (size_t i = 0; i < e->arguments->length; i++)
- {
- Expression *ex = (*e->arguments)[i];
- if (ex)
- ex->accept(this);
- }
- }
- }
-
- void visit(CastExp *e)
- {
- Type *tb = e->type->toBasetype();
- if (tb->ty == Tarray &&
- e->e1->type->toBasetype()->ty == Tsarray)
- {
- escapeByRef(e->e1, er);
- }
- else
- e->e1->accept(this);
- }
-
- void visit(SliceExp *e)
- {
- if (e->e1->op == TOKvar)
- {
- VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
- Type *tb = e->type->toBasetype();
- if (v)
- {
- if (tb->ty == Tsarray)
- return;
- if (v->storage_class & STCvariadic)
- {
- er->byvalue.push(v);
- return;
- }
- }
- }
- Type *t1b = e->e1->type->toBasetype();
- if (t1b->ty == Tsarray)
- {
- Type *tb = e->type->toBasetype();
- if (tb->ty != Tsarray)
- escapeByRef(e->e1, er);
- }
- else
- e->e1->accept(this);
- }
-
- void visit(BinExp *e)
- {
- Type *tb = e->type->toBasetype();
- if (tb->ty == Tpointer)
- {
- e->e1->accept(this);
- e->e2->accept(this);
- }
- }
-
- void visit(BinAssignExp *e)
- {
- e->e1->accept(this);
- }
-
- void visit(AssignExp *e)
- {
- e->e1->accept(this);
- }
-
- void visit(CommaExp *e)
- {
- e->e2->accept(this);
- }
-
- void visit(CondExp *e)
- {
- e->e1->accept(this);
- e->e2->accept(this);
- }
-
- void visit(CallExp *e)
- {
- //printf("CallExp(): %s\n", e->toChars());
- /* Check each argument that is
- * passed as 'return scope'.
- */
- Type *t1 = e->e1->type->toBasetype();
- TypeFunction *tf = NULL;
- TypeDelegate *dg = NULL;
- if (t1->ty == Tdelegate)
- {
- dg = (TypeDelegate *)t1;
- tf = (TypeFunction *)dg->next;
- }
- else if (t1->ty == Tfunction)
- tf = (TypeFunction *)t1;
- else
- return;
-
- if (e->arguments && e->arguments->length)
- {
- /* j=1 if _arguments[] is first argument,
- * skip it because it is not passed by ref
- */
- size_t j = tf->isDstyleVariadic();
- for (size_t i = j; i < e->arguments->length; ++i)
- {
- Expression *arg = (*e->arguments)[i];
- size_t nparams = tf->parameterList.length();
- if (i - j < nparams && i >= j)
- {
- Parameter *p = tf->parameterList[i - j];
- const StorageClass stc = tf->parameterStorageClass(p);
- if ((stc & (STCscope)) && (stc & STCreturn))
- arg->accept(this);
- else if ((stc & (STCref)) && (stc & STCreturn))
- escapeByRef(arg, er);
- }
- }
- }
- // If 'this' is returned, check it too
- if (e->e1->op == TOKdotvar && t1->ty == Tfunction)
- {
- DotVarExp *dve = (DotVarExp *)e->e1;
- FuncDeclaration *fd = dve->var->isFuncDeclaration();
- AggregateDeclaration *ad = NULL;
- if (global.params.vsafe && tf->isreturn && fd && (ad = fd->isThis()) != NULL)
- {
- if (ad->isClassDeclaration() || tf->isscope) // this is 'return scope'
- dve->e1->accept(this);
- else if (ad->isStructDeclaration()) // this is 'return ref'
- escapeByRef(dve->e1, er);
- }
- else if (dve->var->storage_class & STCreturn || tf->isreturn)
- {
- if (dve->var->storage_class & STCscope)
- dve->e1->accept(this);
- else if (dve->var->storage_class & STCref)
- escapeByRef(dve->e1, er);
- }
- }
-
- /* If returning the result of a delegate call, the .ptr
- * field of the delegate must be checked.
- */
- if (dg)
- {
- if (tf->isreturn)
- e->e1->accept(this);
- }
- }
- };
-
- EscapeVisitor v(er);
- e->accept(&v);
-}
-
-/****************************************
- * e is an expression to be returned by 'ref'.
- * Walk e to determine which variables are possibly being
- * returned by ref, such as:
- * ref int function(int i) { return i; }
- * If e is a form of *p, determine which variables have content
- * which is being returned as ref, such as:
- * ref int function(int* p) { return *p; }
- * Multiple variables can be inserted, because of expressions like this:
- * ref int function(bool b, int i, int* p) { return b ? i : *p; }
- *
- * No side effects.
- *
- * Params:
- * e = expression to be returned by 'ref'
- * er = where to place collected data
- */
-static void escapeByRef(Expression *e, EscapeByResults *er)
-{
- //printf("[%s] escapeByRef, e: %s\n", e->loc->toChars(), e->toChars());
- class EscapeRefVisitor : public Visitor
- {
- public:
- EscapeByResults *er;
-
- EscapeRefVisitor(EscapeByResults *er)
- : er(er)
- {
- }
-
- void visit(Expression *)
- {
- }
-
- void visit(VarExp *e)
- {
- VarDeclaration *v = e->var->isVarDeclaration();
- if (v)
- {
- if (v->storage_class & STCref && v->storage_class & (STCforeach | STCtemp) && v->_init)
- {
- /* If compiler generated ref temporary
- * (ref v = ex; ex)
- * look at the initializer instead
- */
- if (ExpInitializer *ez = v->_init->isExpInitializer())
- {
- assert(ez->exp && ez->exp->op == TOKconstruct);
- Expression *ex = ((ConstructExp *)ez->exp)->e2;
- ex->accept(this);
- }
- }
- else
- er->byref.push(v);
- }
- }
-
- void visit(ThisExp *e)
- {
- if (e->var)
- er->byref.push(e->var);
- }
-
- void visit(PtrExp *e)
- {
- escapeByValue(e->e1, er);
- }
-
- void visit(IndexExp *e)
- {
- Type *tb = e->e1->type->toBasetype();
- if (e->e1->op == TOKvar)
- {
- VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (v->storage_class & STCvariadic)
- {
- er->byref.push(v);
- return;
- }
- }
- }
- if (tb->ty == Tsarray)
- {
- e->e1->accept(this);
- }
- else if (tb->ty == Tarray)
- {
- escapeByValue(e->e1, er);
- }
- }
-
- void visit(DotVarExp *e)
- {
- Type *t1b = e->e1->type->toBasetype();
- if (t1b->ty == Tclass)
- escapeByValue(e->e1, er);
- else
- e->e1->accept(this);
- }
-
- void visit(BinAssignExp *e)
- {
- e->e1->accept(this);
- }
-
- void visit(AssignExp *e)
- {
- e->e1->accept(this);
- }
-
- void visit(CommaExp *e)
- {
- e->e2->accept(this);
- }
-
- void visit(CondExp *e)
- {
- e->e1->accept(this);
- e->e2->accept(this);
- }
-
- void visit(CallExp *e)
- {
- /* If the function returns by ref, check each argument that is
- * passed as 'return ref'.
- */
- Type *t1 = e->e1->type->toBasetype();
- TypeFunction *tf;
- if (t1->ty == Tdelegate)
- tf = (TypeFunction *)((TypeDelegate *)t1)->next;
- else if (t1->ty == Tfunction)
- tf = (TypeFunction *)t1;
- else
- return;
- if (tf->isref)
- {
- if (e->arguments && e->arguments->length)
- {
- /* j=1 if _arguments[] is first argument,
- * skip it because it is not passed by ref
- */
- size_t j = tf->isDstyleVariadic();
-
- for (size_t i = j; i < e->arguments->length; ++i)
- {
- Expression *arg = (*e->arguments)[i];
- size_t nparams = tf->parameterList.length();
- if (i - j < nparams && i >= j)
- {
- Parameter *p = tf->parameterList[i - j];
- const StorageClass stc = tf->parameterStorageClass(p);
- if ((stc & (STCout | STCref)) && (stc & STCreturn))
- arg->accept(this);
- else if ((stc & STCscope) && (stc & STCreturn))
- {
- if (arg->op == TOKdelegate)
- {
- DelegateExp *de = (DelegateExp *)arg;
- if (de->func->isNested())
- er->byexp.push(de);
- }
- else
- escapeByValue(arg, er);
- }
- }
- }
- }
-
- // If 'this' is returned by ref, check it too
- if (e->e1->op == TOKdotvar && t1->ty == Tfunction)
- {
- DotVarExp *dve = (DotVarExp *)e->e1;
- if (dve->var->storage_class & STCreturn || tf->isreturn)
- {
- if ((dve->var->storage_class & STCscope) || tf->isscope)
- escapeByValue(dve->e1, er);
- else if ((dve->var->storage_class & STCref) || tf->isref)
- dve->e1->accept(this);
- }
-
- }
- // If it's a delegate, check it too
- if (e->e1->op == TOKvar && t1->ty == Tdelegate)
- {
- escapeByValue(e->e1, er);
- }
- }
- else
- er->byexp.push(e);
- }
- };
-
- EscapeRefVisitor v(er);
- e->accept(&v);
-}
-
-/*************************
- * Find all variables accessed by this delegate that are
- * in functions enclosing it.
- * Params:
- * fd = function
- * vars = array to append found variables to
- */
-void findAllOuterAccessedVariables(FuncDeclaration *fd, VarDeclarations *vars)
-{
- //printf("findAllOuterAccessedVariables(fd: %s)\n", fd.toChars());
- for (Dsymbol *p = fd->parent; p; p = p->parent)
- {
- FuncDeclaration *fdp = p->isFuncDeclaration();
- if (fdp)
- {
- for (size_t i = 0; i < fdp->closureVars.length; i++)
- {
- VarDeclaration *v = fdp->closureVars[i];
- for (size_t j = 0; j < v->nestedrefs.length; j++)
- {
- FuncDeclaration *fdv = v->nestedrefs[j];
- if (fdv == fd)
- {
- //printf("accessed: %s, type %s\n", v->toChars(), v->type->toChars());
- vars->push(v);
- }
- }
- }
- }
- }
-}
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
new file mode 100644
index 0000000..d502f80
--- /dev/null
+++ b/gcc/d/dmd/escape.d
@@ -0,0 +1,2290 @@
+/**
+ * Most of the logic to implement scoped pointers and scoped references is here.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/escape.d, _escape.d)
+ * Documentation: https://dlang.org/phobos/dmd_escape.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/escape.d
+ */
+
+module dmd.escape;
+
+import core.stdc.stdio : printf;
+import core.stdc.stdlib;
+import core.stdc.string;
+
+import dmd.root.rmem;
+
+import dmd.aggregate;
+import dmd.astenums;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.errors;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.mtype;
+import dmd.printast;
+import dmd.root.rootobject;
+import dmd.tokens;
+import dmd.visitor;
+import dmd.arraytypes;
+
+/******************************************************
+ * Checks memory objects passed to a function.
+ * Checks that if a memory object is passed by ref or by pointer,
+ * all of the refs or pointers are const, or there is only one mutable
+ * ref or pointer to it.
+ * References:
+ * DIP 1021
+ * Params:
+ * sc = used to determine current function and module
+ * fd = function being called
+ * tf = fd's type
+ * ethis = if not null, the `this` pointer
+ * arguments = actual arguments to function
+ * gag = do not print error messages
+ * Returns:
+ * `true` if error
+ */
+bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
+ Expression ethis, Expressions* arguments, bool gag)
+{
+ enum log = false;
+ if (log) printf("[%s] checkMutableArguments, fd: `%s`\n", fd.loc.toChars(), fd.toChars());
+ if (log && ethis) printf("ethis: `%s`\n", ethis.toChars());
+ bool errors = false;
+
+ /* Outer variable references are treated as if they are extra arguments
+ * passed by ref to the function (which they essentially are via the static link).
+ */
+ VarDeclaration[] outerVars = fd ? fd.outerVars[] : null;
+
+ const len = arguments.length + (ethis !is null) + outerVars.length;
+ if (len <= 1)
+ return errors;
+
+ struct EscapeBy
+ {
+ EscapeByResults er;
+ Parameter param; // null if no Parameter for this argument
+ bool isMutable; // true if reference to mutable
+ }
+
+ /* Store escapeBy as static data escapeByStorage so we can keep reusing the same
+ * arrays rather than reallocating them.
+ */
+ __gshared EscapeBy[] escapeByStorage;
+ auto escapeBy = escapeByStorage;
+ if (escapeBy.length < len)
+ {
+ auto newPtr = cast(EscapeBy*)mem.xrealloc(escapeBy.ptr, len * EscapeBy.sizeof);
+ // Clear the new section
+ memset(newPtr + escapeBy.length, 0, (len - escapeBy.length) * EscapeBy.sizeof);
+ escapeBy = newPtr[0 .. len];
+ escapeByStorage = escapeBy;
+ }
+ else
+ escapeBy = escapeBy[0 .. len];
+
+ const paramLength = tf.parameterList.length;
+
+ // Fill in escapeBy[] with arguments[], ethis, and outerVars[]
+ foreach (const i, ref eb; escapeBy)
+ {
+ bool refs;
+ Expression arg;
+ if (i < arguments.length)
+ {
+ arg = (*arguments)[i];
+ if (i < paramLength)
+ {
+ eb.param = tf.parameterList[i];
+ refs = eb.param.isReference();
+ eb.isMutable = eb.param.isReferenceToMutable(arg.type);
+ }
+ else
+ {
+ eb.param = null;
+ refs = false;
+ eb.isMutable = arg.type.isReferenceToMutable();
+ }
+ }
+ else if (ethis)
+ {
+ /* ethis is passed by value if a class reference,
+ * by ref if a struct value
+ */
+ eb.param = null;
+ arg = ethis;
+ auto ad = fd.isThis();
+ assert(ad);
+ assert(ethis);
+ if (ad.isClassDeclaration())
+ {
+ refs = false;
+ eb.isMutable = arg.type.isReferenceToMutable();
+ }
+ else
+ {
+ assert(ad.isStructDeclaration());
+ refs = true;
+ eb.isMutable = arg.type.isMutable();
+ }
+ }
+ else
+ {
+ // outer variables are passed by ref
+ eb.param = null;
+ refs = true;
+ auto var = outerVars[i - (len - outerVars.length)];
+ eb.isMutable = var.type.isMutable();
+ eb.er.byref.push(var);
+ continue;
+ }
+
+ if (refs)
+ escapeByRef(arg, &eb.er);
+ else
+ escapeByValue(arg, &eb.er);
+ }
+
+ void checkOnePair(size_t i, ref EscapeBy eb, ref EscapeBy eb2,
+ VarDeclaration v, VarDeclaration v2, bool of)
+ {
+ if (log) printf("v2: `%s`\n", v2.toChars());
+ if (v2 != v)
+ return;
+ //printf("v %d v2 %d\n", eb.isMutable, eb2.isMutable);
+ if (!(eb.isMutable || eb2.isMutable))
+ return;
+
+ if (!(global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe()))
+ return;
+
+ if (!gag)
+ {
+ // int i; funcThatEscapes(ref int i);
+ // funcThatEscapes(i); // error escaping reference _to_ `i`
+ // int* j; funcThatEscapes2(int* j);
+ // funcThatEscapes2(j); // error escaping reference _of_ `i`
+ const(char)* referenceVerb = of ? "of" : "to";
+ const(char)* msg = eb.isMutable && eb2.isMutable
+ ? "more than one mutable reference %s `%s` in arguments to `%s()`"
+ : "mutable and const references %s `%s` in arguments to `%s()`";
+ error((*arguments)[i].loc, msg,
+ referenceVerb,
+ v.toChars(),
+ fd ? fd.toPrettyChars() : "indirectly");
+ }
+ errors = true;
+ }
+
+ void escape(size_t i, ref EscapeBy eb, bool byval)
+ {
+ foreach (VarDeclaration v; byval ? eb.er.byvalue : eb.er.byref)
+ {
+ if (log)
+ {
+ const(char)* by = byval ? "byval" : "byref";
+ printf("%s %s\n", by, v.toChars());
+ }
+ if (byval && !v.type.hasPointers())
+ continue;
+ foreach (ref eb2; escapeBy[i + 1 .. $])
+ {
+ foreach (VarDeclaration v2; byval ? eb2.er.byvalue : eb2.er.byref)
+ {
+ checkOnePair(i, eb, eb2, v, v2, byval);
+ }
+ }
+ }
+ }
+ foreach (const i, ref eb; escapeBy[0 .. $ - 1])
+ {
+ escape(i, eb, true);
+ escape(i, eb, false);
+ }
+
+ /* Reset the arrays in escapeBy[] so we can reuse them next time through
+ */
+ foreach (ref eb; escapeBy)
+ {
+ eb.er.reset();
+ }
+
+ return errors;
+}
+
+/******************************************
+ * Array literal is going to be allocated on the GC heap.
+ * Check its elements to see if any would escape by going on the heap.
+ * Params:
+ * sc = used to determine current function and module
+ * ae = array literal expression
+ * gag = do not print error messages
+ * Returns:
+ * `true` if any elements escaped
+ */
+bool checkArrayLiteralEscape(Scope *sc, ArrayLiteralExp ae, bool gag)
+{
+ bool errors;
+ if (ae.basis)
+ errors = checkNewEscape(sc, ae.basis, gag);
+ foreach (ex; *ae.elements)
+ {
+ if (ex)
+ errors |= checkNewEscape(sc, ex, gag);
+ }
+ return errors;
+}
+
+/******************************************
+ * Associative array literal is going to be allocated on the GC heap.
+ * Check its elements to see if any would escape by going on the heap.
+ * Params:
+ * sc = used to determine current function and module
+ * ae = associative array literal expression
+ * gag = do not print error messages
+ * Returns:
+ * `true` if any elements escaped
+ */
+bool checkAssocArrayLiteralEscape(Scope *sc, AssocArrayLiteralExp ae, bool gag)
+{
+ bool errors;
+ foreach (ex; *ae.keys)
+ {
+ if (ex)
+ errors |= checkNewEscape(sc, ex, gag);
+ }
+ foreach (ex; *ae.values)
+ {
+ if (ex)
+ errors |= checkNewEscape(sc, ex, gag);
+ }
+ return errors;
+}
+
+/****************************************
+ * Function parameter `par` is being initialized to `arg`,
+ * and `par` may escape.
+ * Detect if scoped values can escape this way.
+ * Print error messages when these are detected.
+ * Params:
+ * sc = used to determine current function and module
+ * fdc = function being called, `null` if called indirectly
+ * par = function parameter (`this` if null)
+ * arg = initializer for param
+ * assertmsg = true if the parameter is the msg argument to assert(bool, msg).
+ * gag = do not print error messages
+ * Returns:
+ * `true` if pointers to the stack can escape via assignment
+ */
+bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Expression arg, bool assertmsg, bool gag)
+{
+ enum log = false;
+ if (log) printf("checkParamArgumentEscape(arg: %s par: %s)\n",
+ arg ? arg.toChars() : "null",
+ par ? par.toChars() : "this");
+ //printf("type = %s, %d\n", arg.type.toChars(), arg.type.hasPointers());
+
+ if (!arg.type.hasPointers())
+ return false;
+
+ EscapeByResults er;
+
+ escapeByValue(arg, &er);
+
+ if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
+ return false;
+
+ bool result = false;
+
+ ScopeRef psr;
+ if (par && fdc && fdc.type.isTypeFunction())
+ psr = buildScopeRef(par.storageClass);
+ else
+ psr = ScopeRef.None;
+
+ /* 'v' is assigned unsafely to 'par'
+ */
+ void unsafeAssign(VarDeclaration v, const char* desc)
+ {
+ if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
+ {
+ if (!gag)
+ {
+ if (assertmsg)
+ {
+ error(arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`",
+ desc, v.toChars());
+ }
+ else
+ {
+ error(arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s",
+ desc, v.toChars(),
+ par ? par.toChars() : "this",
+ fdc ? fdc.toPrettyChars() : "indirectly");
+ }
+ }
+ result = true;
+ }
+ }
+
+ foreach (VarDeclaration v; er.byvalue)
+ {
+ if (log) printf("byvalue %s\n", v.toChars());
+ if (v.isDataseg())
+ continue;
+
+ Dsymbol p = v.toParent2();
+
+ notMaybeScope(v);
+
+ if (v.isScope())
+ {
+ unsafeAssign(v, "scope variable");
+ }
+ else if (v.storage_class & STC.variadic && p == sc.func)
+ {
+ Type tb = v.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ unsafeAssign(v, "variadic variable");
+ }
+ }
+ else
+ {
+ /* v is not 'scope', and is assigned to a parameter that may escape.
+ * Therefore, v can never be 'scope'.
+ */
+ if (log) printf("no infer for %s in %s loc %s, fdc %s, %d\n",
+ v.toChars(), sc.func.ident.toChars(), sc.func.loc.toChars(), fdc.ident.toChars(), __LINE__);
+ v.doNotInferScope = true;
+ }
+ }
+
+ foreach (VarDeclaration v; er.byref)
+ {
+ if (log) printf("byref %s\n", v.toChars());
+ if (v.isDataseg())
+ continue;
+
+ Dsymbol p = v.toParent2();
+
+ notMaybeScope(v);
+
+ if (!v.isReference() && p == sc.func)
+ {
+ if (psr == ScopeRef.Scope ||
+ psr == ScopeRef.RefScope ||
+ psr == ScopeRef.ReturnRef_Scope)
+ {
+ continue;
+ }
+
+ unsafeAssign(v, "reference to local variable");
+ continue;
+ }
+ }
+
+ foreach (FuncDeclaration fd; er.byfunc)
+ {
+ //printf("fd = %s, %d\n", fd.toChars(), fd.tookAddressOf);
+ VarDeclarations vars;
+ findAllOuterAccessedVariables(fd, &vars);
+
+ foreach (v; vars)
+ {
+ //printf("v = %s\n", v.toChars());
+ assert(!v.isDataseg()); // these are not put in the closureVars[]
+
+ Dsymbol p = v.toParent2();
+
+ notMaybeScope(v);
+
+ if ((v.isReference() || v.isScope()) && p == sc.func)
+ {
+ unsafeAssign(v, "reference to local");
+ continue;
+ }
+ }
+ }
+
+ foreach (Expression ee; er.byexp)
+ {
+ if (sc.func && sc.func.setUnsafe())
+ {
+ if (!gag)
+ error(ee.loc, "reference to stack allocated value returned by `%s` assigned to non-scope parameter `%s`",
+ ee.toChars(),
+ par ? par.toChars() : "this");
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+/*****************************************************
+ * Function argument initializes a `return` parameter,
+ * and that parameter gets assigned to `firstArg`.
+ * Essentially, treat as `firstArg = arg;`
+ * Params:
+ * sc = used to determine current function and module
+ * firstArg = `ref` argument through which `arg` may be assigned
+ * arg = initializer for parameter
+ * gag = do not print error messages
+ * Returns:
+ * `true` if assignment to `firstArg` would cause an error
+ */
+bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, bool gag)
+{
+ enum log = false;
+ if (log) printf("checkParamArgumentReturn(firstArg: %s arg: %s)\n",
+ firstArg.toChars(), arg.toChars());
+ //printf("type = %s, %d\n", arg.type.toChars(), arg.type.hasPointers());
+
+ if (!arg.type.hasPointers())
+ return false;
+
+ scope e = new AssignExp(arg.loc, firstArg, arg);
+ return checkAssignEscape(sc, e, gag);
+}
+
+/*****************************************************
+ * Check struct constructor of the form `s.this(args)`, by
+ * checking each `return` parameter to see if it gets
+ * assigned to `s`.
+ * Params:
+ * sc = used to determine current function and module
+ * ce = constructor call of the form `s.this(args)`
+ * gag = do not print error messages
+ * Returns:
+ * `true` if construction would cause an escaping reference error
+ */
+bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag)
+{
+ enum log = false;
+ if (log) printf("checkConstructorEscape(%s, %s)\n", ce.toChars(), ce.type.toChars());
+ Type tthis = ce.type.toBasetype();
+ assert(tthis.ty == Tstruct);
+ if (!tthis.hasPointers())
+ return false;
+
+ if (!ce.arguments && ce.arguments.dim)
+ return false;
+
+ DotVarExp dve = ce.e1.isDotVarExp();
+ CtorDeclaration ctor = dve.var.isCtorDeclaration();
+ TypeFunction tf = ctor.type.isTypeFunction();
+
+ const nparams = tf.parameterList.length;
+ const n = ce.arguments.dim;
+
+ // j=1 if _arguments[] is first argument
+ const j = tf.isDstyleVariadic();
+
+ /* Attempt to assign each `return` arg to the `this` reference
+ */
+ foreach (const i; 0 .. n)
+ {
+ Expression arg = (*ce.arguments)[i];
+ if (!arg.type.hasPointers())
+ return false;
+
+ //printf("\targ[%d]: %s\n", i, arg.toChars());
+
+ if (i - j < nparams && i >= j)
+ {
+ Parameter p = tf.parameterList[i - j];
+
+ if (p.storageClass & STC.return_)
+ {
+ /* Fake `dve.e1 = arg;` and look for scope violations
+ */
+ scope e = new AssignExp(arg.loc, dve.e1, arg);
+ if (checkAssignEscape(sc, e, gag))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/****************************************
+ * Given an `AssignExp`, determine if the lvalue will cause
+ * the contents of the rvalue to escape.
+ * Print error messages when these are detected.
+ * Infer `scope` attribute for the lvalue where possible, in order
+ * to eliminate the error.
+ * Params:
+ * sc = used to determine current function and module
+ * e = `AssignExp` or `CatAssignExp` to check for any pointers to the stack
+ * gag = do not print error messages
+ * Returns:
+ * `true` if pointers to the stack can escape via assignment
+ */
+bool checkAssignEscape(Scope* sc, Expression e, bool gag)
+{
+ enum log = false;
+ if (log) printf("checkAssignEscape(e: %s)\n", e.toChars());
+ if (e.op != TOK.assign && e.op != TOK.blit && e.op != TOK.construct &&
+ e.op != TOK.concatenateAssign && e.op != TOK.concatenateElemAssign && e.op != TOK.concatenateDcharAssign)
+ return false;
+ auto ae = cast(BinExp)e;
+ Expression e1 = ae.e1;
+ Expression e2 = ae.e2;
+ //printf("type = %s, %d\n", e1.type.toChars(), e1.type.hasPointers());
+
+ if (!e1.type.hasPointers())
+ return false;
+
+ if (e1.isSliceExp())
+ return false;
+
+ /* The struct literal case can arise from the S(e2) constructor call:
+ * return S(e2);
+ * and appears in this function as:
+ * structLiteral = e2;
+ * Such an assignment does not necessarily remove scope-ness.
+ */
+ if (e1.isStructLiteralExp())
+ return false;
+
+ EscapeByResults er;
+
+ escapeByValue(e2, &er);
+
+ if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
+ return false;
+
+ VarDeclaration va = expToVariable(e1);
+
+ if (va && e.op == TOK.concatenateElemAssign)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=17842
+ * Draw an equivalence between:
+ * *q = p;
+ * and:
+ * va ~= e;
+ * since we are not assigning to va, but are assigning indirectly through va.
+ */
+ va = null;
+ }
+
+ if (va && e1.isDotVarExp() && va.type.toBasetype().isTypeClass())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=17949
+ * Draw an equivalence between:
+ * *q = p;
+ * and:
+ * va.field = e2;
+ * since we are not assigning to va, but are assigning indirectly through class reference va.
+ */
+ va = null;
+ }
+
+ if (log && va) printf("va: %s\n", va.toChars());
+
+ FuncDeclaration fd = sc.func;
+
+ // Try to infer 'scope' for va if in a function not marked @system
+ bool inferScope = false;
+ if (va && fd && fd.type && fd.type.isTypeFunction())
+ inferScope = fd.type.isTypeFunction().trust != TRUST.system;
+ //printf("inferScope = %d, %d\n", inferScope, (va.storage_class & STCmaybescope) != 0);
+
+ // Determine if va is a parameter that is an indirect reference
+ const bool vaIsRef = va && va.storage_class & STC.parameter &&
+ (va.isReference() || va.type.toBasetype().isTypeClass()); // ref, out, or class
+ if (log && vaIsRef) printf("va is ref `%s`\n", va.toChars());
+
+ /* Determine if va is the first parameter, through which other 'return' parameters
+ * can be assigned.
+ * This works the same as returning the value via a return statement.
+ * Although va is marked as `ref`, it is not regarded as returning by `ref`.
+ * https://dlang.org.spec/function.html#return-ref-parameters
+ */
+ bool isFirstRef()
+ {
+ if (!vaIsRef)
+ return false;
+ Dsymbol p = va.toParent2();
+ if (p == fd && fd.type && fd.type.isTypeFunction())
+ {
+ TypeFunction tf = fd.type.isTypeFunction();
+ if (!tf.nextOf() || (tf.nextOf().ty != Tvoid && !fd.isCtorDeclaration()))
+ return false;
+ if (va == fd.vthis) // `this` of a non-static member function is considered to be the first parameter
+ return true;
+ if (fd.parameters && fd.parameters.length && (*fd.parameters)[0] == va) // va is first parameter
+ return true;
+ }
+ return false;
+ }
+ const bool vaIsFirstRef = isFirstRef();
+ if (log && vaIsFirstRef) printf("va is first ref `%s`\n", va.toChars());
+
+ bool result = false;
+ foreach (VarDeclaration v; er.byvalue)
+ {
+ if (log) printf("byvalue: %s\n", v.toChars());
+ if (v.isDataseg())
+ continue;
+
+ if (v == va)
+ continue;
+
+ Dsymbol p = v.toParent2();
+
+ if (va && !vaIsRef && !va.isScope() && !v.isScope() &&
+ (va.storage_class & v.storage_class & (STC.maybescope | STC.variadic)) == STC.maybescope &&
+ p == fd)
+ {
+ /* Add v to va's list of dependencies
+ */
+ va.addMaybe(v);
+ continue;
+ }
+
+ if (vaIsFirstRef &&
+ (v.isScope() || (v.storage_class & STC.maybescope)) &&
+ !(v.storage_class & STC.return_) &&
+ v.isParameter() &&
+ fd.flags & FUNCFLAG.returnInprocess &&
+ p == fd)
+ {
+ if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars());
+ inferReturn(fd, v); // infer addition of 'return' to make `return scope`
+ }
+
+ if (!(va && va.isScope()) || vaIsRef)
+ notMaybeScope(v);
+
+ if (v.isScope())
+ {
+ if (vaIsFirstRef && v.isParameter() && v.storage_class & STC.return_)
+ {
+ // va=v, where v is `return scope`
+ if (va.isScope())
+ continue;
+
+ if (inferScope && !va.doNotInferScope)
+ {
+ if (log) printf("inferring scope for lvalue %s\n", va.toChars());
+ va.storage_class |= STC.scope_ | STC.scopeinferred;
+ continue;
+ }
+ }
+
+ if (va && va.isScope() && va.storage_class & STC.return_ && !(v.storage_class & STC.return_) &&
+ fd.setUnsafe())
+ {
+ // va may return its value, but v does not allow that, so this is an error
+ if (!gag)
+ error(ae.loc, "scope variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars());
+ result = true;
+ continue;
+ }
+
+ // If va's lifetime encloses v's, then error
+ if (va &&
+ (va.enclosesLifetimeOf(v) && !(v.storage_class & (STC.parameter | STC.temp)) ||
+ // va is class reference
+ ae.e1.isDotVarExp() && va.type.toBasetype().isTypeClass() && (va.enclosesLifetimeOf(v) ||
+ !va.isScope()) ||
+ vaIsRef ||
+ va.isReference() && !(v.storage_class & (STC.parameter | STC.temp))) &&
+ fd.setUnsafe())
+ {
+ if (!gag)
+ error(ae.loc, "scope variable `%s` assigned to `%s` with longer lifetime", v.toChars(), va.toChars());
+ result = true;
+ continue;
+ }
+
+ if (va && !va.isDataseg() && !va.doNotInferScope)
+ {
+ if (!va.isScope() && inferScope)
+ { /* v is scope, and va is not scope, so va needs to
+ * infer scope
+ */
+ if (log) printf("inferring scope for %s\n", va.toChars());
+ va.storage_class |= STC.scope_ | STC.scopeinferred;
+ /* v returns, and va does not return, so va needs
+ * to infer return
+ */
+ if (v.storage_class & STC.return_ &&
+ !(va.storage_class & STC.return_))
+ {
+ if (log) printf("infer return for %s\n", va.toChars());
+ va.storage_class |= STC.return_ | STC.returninferred;
+
+ // Added "return scope" so don't confuse it with "return ref"
+ if (isRefReturnScope(va.storage_class))
+ va.storage_class |= STC.returnScope;
+ }
+ }
+ continue;
+ }
+ if (fd.setUnsafe())
+ {
+ if (!gag)
+ error(ae.loc, "scope variable `%s` assigned to non-scope `%s`", v.toChars(), e1.toChars());
+ result = true;
+ }
+ }
+ else if (v.storage_class & STC.variadic && p == fd)
+ {
+ Type tb = v.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (va && !va.isDataseg() && !va.doNotInferScope)
+ {
+ if (!va.isScope() && inferScope)
+ { //printf("inferring scope for %s\n", va.toChars());
+ va.storage_class |= STC.scope_ | STC.scopeinferred;
+ }
+ continue;
+ }
+ if (fd.setUnsafe())
+ {
+ if (!gag)
+ error(ae.loc, "variadic variable `%s` assigned to non-scope `%s`", v.toChars(), e1.toChars());
+ result = true;
+ }
+ }
+ }
+ else
+ {
+ /* v is not 'scope', and we didn't check the scope of where we assigned it to.
+ * It may escape via that assignment, therefore, v can never be 'scope'.
+ */
+ //printf("no infer for %s in %s, %d\n", v.toChars(), fd.ident.toChars(), __LINE__);
+ v.doNotInferScope = true;
+ }
+ }
+
+ByRef:
+ foreach (VarDeclaration v; er.byref)
+ {
+ if (log) printf("byref: %s\n", v.toChars());
+ if (v.isDataseg())
+ continue;
+
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ {
+ if (va && va.isScope() && !v.isReference())
+ {
+ if (!(va.storage_class & STC.return_))
+ {
+ va.doNotInferReturn = true;
+ }
+ else if (fd.setUnsafe())
+ {
+ if (!gag)
+ error(ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars());
+ result = true;
+ continue;
+ }
+ }
+ }
+
+ Dsymbol p = v.toParent2();
+
+ // If va's lifetime encloses v's, then error
+ if (va &&
+ (va.enclosesLifetimeOf(v) && !(v.isParameter() && v.isRef()) ||
+ va.isDataseg()) &&
+ fd.setUnsafe())
+ {
+ if (!gag)
+ error(ae.loc, "address of variable `%s` assigned to `%s` with longer lifetime", v.toChars(), va.toChars());
+ result = true;
+ continue;
+ }
+
+ if (va && v.isReference())
+ {
+ Dsymbol pva = va.toParent2();
+ for (Dsymbol pv = p; pv; )
+ {
+ pv = pv.toParent2();
+ if (pva == pv) // if v is nested inside pva
+ {
+ if (fd.setUnsafe())
+ {
+ if (!gag)
+ error(ae.loc, "reference `%s` assigned to `%s` with longer lifetime", v.toChars(), va.toChars());
+ result = true;
+ continue ByRef;
+ }
+ break;
+ }
+ }
+ }
+
+ if (!(va && va.isScope()))
+ notMaybeScope(v);
+
+ if ((global.params.useDIP1000 != FeatureState.enabled && v.isReference()) || p != sc.func)
+ continue;
+
+ if (va && !va.isDataseg() && !va.doNotInferScope)
+ {
+ if (!va.isScope() && inferScope)
+ { //printf("inferring scope for %s\n", va.toChars());
+ va.storage_class |= STC.scope_ | STC.scopeinferred;
+ }
+ if (v.storage_class & STC.return_ && !(va.storage_class & STC.return_))
+ va.storage_class |= STC.return_ | STC.returninferred;
+ continue;
+ }
+ if (e1.op == TOK.structLiteral)
+ continue;
+ if (fd.setUnsafe())
+ {
+ if (!gag)
+ error(ae.loc, "reference to local variable `%s` assigned to non-scope `%s`", v.toChars(), e1.toChars());
+ result = true;
+ }
+ }
+
+ foreach (FuncDeclaration func; er.byfunc)
+ {
+ if (log) printf("byfunc: %s, %d\n", func.toChars(), func.tookAddressOf);
+ VarDeclarations vars;
+ findAllOuterAccessedVariables(func, &vars);
+
+ /* https://issues.dlang.org/show_bug.cgi?id=16037
+ * If assigning the address of a delegate to a scope variable,
+ * then uncount that address of. This is so it won't cause a
+ * closure to be allocated.
+ */
+ if (va && va.isScope() && !(va.storage_class & STC.return_) && func.tookAddressOf)
+ --func.tookAddressOf;
+
+ foreach (v; vars)
+ {
+ //printf("v = %s\n", v.toChars());
+ assert(!v.isDataseg()); // these are not put in the closureVars[]
+
+ Dsymbol p = v.toParent2();
+
+ if (!(va && va.isScope()))
+ notMaybeScope(v);
+
+ if (!(v.isReference() || v.isScope()) || p != fd)
+ continue;
+
+ if (va && !va.isDataseg() && !va.doNotInferScope)
+ {
+ /* Don't infer STC.scope_ for va, because then a closure
+ * won't be generated for fd.
+ */
+ //if (!va.isScope() && inferScope)
+ //va.storage_class |= STC.scope_ | STC.scopeinferred;
+ continue;
+ }
+ if (fd.setUnsafe())
+ {
+ if (!gag)
+ error(ae.loc, "reference to local `%s` assigned to non-scope `%s` in @safe code", v.toChars(), e1.toChars());
+ result = true;
+ }
+ }
+ }
+
+ foreach (Expression ee; er.byexp)
+ {
+ if (log) printf("byexp: %s\n", ee.toChars());
+
+ /* Do not allow slicing of a static array returned by a function
+ */
+ if (ee.op == TOK.call && ee.type.toBasetype().isTypeSArray() && e1.type.toBasetype().isTypeDArray() &&
+ !(va && va.storage_class & STC.temp))
+ {
+ if (!gag)
+ deprecation(ee.loc, "slice of static array temporary returned by `%s` assigned to longer lived variable `%s`",
+ ee.toChars(), e1.toChars());
+ //result = true;
+ continue;
+ }
+
+ if (ee.op == TOK.call && ee.type.toBasetype().isTypeStruct() &&
+ (!va || !(va.storage_class & STC.temp)) &&
+ fd.setUnsafe())
+ {
+ if (!gag)
+ error(ee.loc, "address of struct temporary returned by `%s` assigned to longer lived variable `%s`",
+ ee.toChars(), e1.toChars());
+ result = true;
+ continue;
+ }
+
+ if (ee.op == TOK.structLiteral &&
+ (!va || !(va.storage_class & STC.temp)) &&
+ fd.setUnsafe())
+ {
+ if (!gag)
+ error(ee.loc, "address of struct literal `%s` assigned to longer lived variable `%s`",
+ ee.toChars(), e1.toChars());
+ result = true;
+ continue;
+ }
+
+ if (va && !va.isDataseg() && !va.doNotInferScope)
+ {
+ if (!va.isScope() && inferScope)
+ { //printf("inferring scope for %s\n", va.toChars());
+ va.storage_class |= STC.scope_ | STC.scopeinferred;
+ }
+ continue;
+ }
+
+ if (fd.setUnsafe())
+ {
+ if (!gag)
+ error(ee.loc, "reference to stack allocated value returned by `%s` assigned to non-scope `%s`",
+ ee.toChars(), e1.toChars());
+ result = true;
+ }
+ }
+
+ return result;
+}
+
+/************************************
+ * Detect cases where pointers to the stack can escape the
+ * lifetime of the stack frame when throwing `e`.
+ * Print error messages when these are detected.
+ * Params:
+ * sc = used to determine current function and module
+ * e = expression to check for any pointers to the stack
+ * gag = do not print error messages
+ * Returns:
+ * `true` if pointers to the stack can escape
+ */
+bool checkThrowEscape(Scope* sc, Expression e, bool gag)
+{
+ //printf("[%s] checkThrowEscape, e = %s\n", e.loc.toChars(), e.toChars());
+ EscapeByResults er;
+
+ escapeByValue(e, &er);
+
+ if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim)
+ return false;
+
+ bool result = false;
+ foreach (VarDeclaration v; er.byvalue)
+ {
+ //printf("byvalue %s\n", v.toChars());
+ if (v.isDataseg())
+ continue;
+
+ if (v.isScope() && !v.iscatchvar) // special case: allow catch var to be rethrown
+ // despite being `scope`
+ {
+ if (sc._module && sc._module.isRoot())
+ {
+ // Only look for errors if in module listed on command line
+ if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029
+ {
+ if (!gag)
+ error(e.loc, "scope variable `%s` may not be thrown", v.toChars());
+ result = true;
+ }
+ continue;
+ }
+ }
+ else
+ {
+ //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__);
+ v.doNotInferScope = true;
+ }
+ }
+ return result;
+}
+
+/************************************
+ * Detect cases where pointers to the stack can escape the
+ * lifetime of the stack frame by being placed into a GC allocated object.
+ * Print error messages when these are detected.
+ * Params:
+ * sc = used to determine current function and module
+ * e = expression to check for any pointers to the stack
+ * gag = do not print error messages
+ * Returns:
+ * `true` if pointers to the stack can escape
+ */
+bool checkNewEscape(Scope* sc, Expression e, bool gag)
+{
+ import dmd.globals: FeatureState;
+ import dmd.errors: previewErrorFunc;
+
+ //printf("[%s] checkNewEscape, e = %s\n", e.loc.toChars(), e.toChars());
+ enum log = false;
+ if (log) printf("[%s] checkNewEscape, e: `%s`\n", e.loc.toChars(), e.toChars());
+ EscapeByResults er;
+
+ escapeByValue(e, &er);
+
+ if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim)
+ return false;
+
+ bool result = false;
+ foreach (VarDeclaration v; er.byvalue)
+ {
+ if (log) printf("byvalue `%s`\n", v.toChars());
+ if (v.isDataseg())
+ continue;
+
+ Dsymbol p = v.toParent2();
+
+ if (v.isScope())
+ {
+ if (sc._module && sc._module.isRoot() &&
+ /* This case comes up when the ReturnStatement of a __foreachbody is
+ * checked for escapes by the caller of __foreachbody. Skip it.
+ *
+ * struct S { static int opApply(int delegate(S*) dg); }
+ * S* foo() {
+ * foreach (S* s; S) // create __foreachbody for body of foreach
+ * return s; // s is inferred as 'scope' but incorrectly tested in foo()
+ * return null; }
+ */
+ !(p.parent == sc.func))
+ {
+ // Only look for errors if in module listed on command line
+ if (global.params.useDIP1000 == FeatureState.enabled // https://issues.dlang.org/show_bug.cgi?id=17029
+ && sc.func.setUnsafe()) // https://issues.dlang.org/show_bug.cgi?id=20868
+ {
+ if (!gag)
+ error(e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars());
+ result = true;
+ }
+ continue;
+ }
+ }
+ else if (v.storage_class & STC.variadic && p == sc.func)
+ {
+ Type tb = v.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!gag)
+ error(e.loc, "copying `%s` into allocated memory escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars());
+ result = false;
+ }
+ }
+ else
+ {
+ //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__);
+ v.doNotInferScope = true;
+ }
+ }
+
+ foreach (VarDeclaration v; er.byref)
+ {
+ if (log) printf("byref `%s`\n", v.toChars());
+
+ // 'featureState' tells us whether to emit an error or a deprecation,
+ // depending on the flag passed to the CLI for DIP25
+ void escapingRef(VarDeclaration v, FeatureState featureState = FeatureState.enabled)
+ {
+ if (!gag)
+ {
+ const(char)* kind = (v.storage_class & STC.parameter) ? "parameter" : "local";
+ const(char)* msg = "copying `%s` into allocated memory escapes a reference to %s variable `%s`";
+ previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), kind, v.toChars());
+ }
+ result |= (featureState == FeatureState.enabled);
+ }
+
+ if (v.isDataseg())
+ continue;
+
+ Dsymbol p = v.toParent2();
+
+ if (!v.isReference())
+ {
+ if (p == sc.func)
+ {
+ escapingRef(v);
+ continue;
+ }
+ }
+
+ /* Check for returning a ref variable by 'ref', but should be 'return ref'
+ * Infer the addition of 'return', or set result to be the offending expression.
+ */
+ if (!v.isReference())
+ continue;
+
+ if (!sc._module || !sc._module.isRoot())
+ continue;
+
+ // https://dlang.org/spec/function.html#return-ref-parameters
+ // Only look for errors if in module listed on command line
+ if (p == sc.func)
+ {
+ //printf("escaping reference to local ref variable %s\n", v.toChars());
+ //printf("storage class = x%llx\n", v.storage_class);
+ escapingRef(v, global.params.useDIP25);
+ continue;
+ }
+ // Don't need to be concerned if v's parent does not return a ref
+ FuncDeclaration func = p.isFuncDeclaration();
+ if (!func || !func.type)
+ continue;
+ if (auto tf = func.type.isTypeFunction())
+ {
+ if (!tf.isref)
+ continue;
+
+ const(char)* msg = "storing reference to outer local variable `%s` into allocated memory causes it to escape";
+ if (!gag)
+ {
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP25)(e.loc, msg, v.toChars());
+ }
+
+ // If -preview=dip25 is used, the user wants an error
+ // Otherwise, issue a deprecation
+ result |= (global.params.useDIP25 == FeatureState.enabled);
+ }
+ }
+
+ foreach (Expression ee; er.byexp)
+ {
+ if (log) printf("byexp %s\n", ee.toChars());
+ if (!gag)
+ error(ee.loc, "storing reference to stack allocated value returned by `%s` into allocated memory causes it to escape",
+ ee.toChars());
+ result = true;
+ }
+
+ return result;
+}
+
+
+/************************************
+ * Detect cases where pointers to the stack can escape the
+ * lifetime of the stack frame by returning `e` by value.
+ * Print error messages when these are detected.
+ * Params:
+ * sc = used to determine current function and module
+ * e = expression to check for any pointers to the stack
+ * gag = do not print error messages
+ * Returns:
+ * `true` if pointers to the stack can escape
+ */
+bool checkReturnEscape(Scope* sc, Expression e, bool gag)
+{
+ //printf("[%s] checkReturnEscape, e: %s\n", e.loc.toChars(), e.toChars());
+ return checkReturnEscapeImpl(sc, e, false, gag);
+}
+
+/************************************
+ * Detect cases where returning `e` by `ref` can result in a reference to the stack
+ * being returned.
+ * Print error messages when these are detected.
+ * Params:
+ * sc = used to determine current function and module
+ * e = expression to check
+ * gag = do not print error messages
+ * Returns:
+ * `true` if references to the stack can escape
+ */
+bool checkReturnEscapeRef(Scope* sc, Expression e, bool gag)
+{
+ version (none)
+ {
+ printf("[%s] checkReturnEscapeRef, e = %s\n", e.loc.toChars(), e.toChars());
+ printf("current function %s\n", sc.func.toChars());
+ printf("parent2 function %s\n", sc.func.toParent2().toChars());
+ }
+
+ return checkReturnEscapeImpl(sc, e, true, gag);
+}
+
+/***************************************
+ * Implementation of checking for escapes in return expressions.
+ * Params:
+ * sc = used to determine current function and module
+ * e = expression to check
+ * refs = `true`: escape by value, `false`: escape by `ref`
+ * gag = do not print error messages
+ * Returns:
+ * `true` if references to the stack can escape
+ */
+private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
+{
+ enum log = false;
+ if (log) printf("[%s] checkReturnEscapeImpl, refs: %d e: `%s`\n", e.loc.toChars(), refs, e.toChars());
+ EscapeByResults er;
+
+ if (refs)
+ escapeByRef(e, &er);
+ else
+ escapeByValue(e, &er);
+
+ if (!er.byref.dim && !er.byvalue.dim && !er.byexp.dim)
+ return false;
+
+ bool result = false;
+ foreach (VarDeclaration v; er.byvalue)
+ {
+ if (log) printf("byvalue `%s`\n", v.toChars());
+ if (v.isDataseg())
+ continue;
+
+ Dsymbol p = v.toParent2();
+
+ if ((v.isScope() || (v.storage_class & STC.maybescope)) &&
+ !(v.storage_class & STC.return_) &&
+ v.isParameter() &&
+ !v.doNotInferReturn &&
+ sc.func.flags & FUNCFLAG.returnInprocess &&
+ p == sc.func)
+ {
+ inferReturn(sc.func, v); // infer addition of 'return'
+ continue;
+ }
+
+ if (v.isScope())
+ {
+ if (v.storage_class & STC.return_)
+ continue;
+
+ auto pfunc = p.isFuncDeclaration();
+ if (pfunc && sc._module && sc._module.isRoot() &&
+ /* This case comes up when the ReturnStatement of a __foreachbody is
+ * checked for escapes by the caller of __foreachbody. Skip it.
+ *
+ * struct S { static int opApply(int delegate(S*) dg); }
+ * S* foo() {
+ * foreach (S* s; S) // create __foreachbody for body of foreach
+ * return s; // s is inferred as 'scope' but incorrectly tested in foo()
+ * return null; }
+ */
+ !(!refs && p.parent == sc.func && pfunc.fes) &&
+ /*
+ * auto p(scope string s) {
+ * string scfunc() { return s; }
+ * }
+ */
+ !(!refs && sc.func.isFuncDeclaration().getLevel(pfunc, sc.intypeof) > 0)
+ )
+ {
+ // Only look for errors if in module listed on command line
+ if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029
+ {
+ if (!gag)
+ error(e.loc, "scope variable `%s` may not be returned", v.toChars());
+ result = true;
+ }
+ continue;
+ }
+ }
+ else if (v.storage_class & STC.variadic && p == sc.func)
+ {
+ Type tb = v.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!gag)
+ error(e.loc, "returning `%s` escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars());
+ result = false;
+ }
+ }
+ else
+ {
+ //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__);
+ v.doNotInferScope = true;
+ }
+ }
+
+ foreach (VarDeclaration v; er.byref)
+ {
+ if (log)
+ {
+ printf("byref `%s`\n", v.toChars());
+ if (v.storage_class & STC.return_) printf(" return");
+ if (v.storage_class & STC.ref_) printf(" ref");
+ if (v.storage_class & STC.scope_) printf(" scope");
+ printf("\n");
+ }
+
+ // 'featureState' tells us whether to emit an error or a deprecation,
+ // depending on the flag passed to the CLI for DIP25
+ void escapingRef(VarDeclaration v, ScopeRef vsr, FeatureState featureState = FeatureState.enabled)
+ {
+ if (!gag)
+ {
+ const(char)* msg, supplemental;
+ if (v.storage_class & STC.parameter &&
+ (v.type.hasPointers() || v.storage_class & STC.ref_))
+ {
+ msg = "returning `%s` escapes a reference to parameter `%s`";
+ supplemental = vsr == ScopeRef.Ref_ReturnScope
+ ? "perhaps remove `scope` parameter annotation so `return` applies to `ref`"
+ : "perhaps annotate the parameter with `return`";
+ }
+ else
+ {
+ msg = "returning `%s` escapes a reference to local variable `%s`";
+ if (v.ident is Id.This)
+ supplemental = "perhaps annotate the function with `return`";
+ }
+
+ previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), v.toChars());
+ if (supplemental)
+ previewSupplementalFunc(sc.isDeprecated(), featureState)(e.loc, supplemental);
+ }
+ result = true;
+ }
+
+ if (v.isDataseg())
+ continue;
+
+ const vsr = buildScopeRef(v.storage_class);
+
+ Dsymbol p = v.toParent2();
+
+ // https://issues.dlang.org/show_bug.cgi?id=19965
+ if (!refs && sc.func.vthis == v)
+ notMaybeScope(v);
+
+ if (!v.isReference())
+ {
+ if (p == sc.func)
+ {
+ escapingRef(v, vsr, FeatureState.enabled);
+ continue;
+ }
+ FuncDeclaration fd = p.isFuncDeclaration();
+ if (fd && sc.func.flags & FUNCFLAG.returnInprocess)
+ {
+ /* Code like:
+ * int x;
+ * auto dg = () { return &x; }
+ * Making it:
+ * auto dg = () return { return &x; }
+ * Because dg.ptr points to x, this is returning dt.ptr+offset
+ */
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ {
+ sc.func.storage_class |= STC.return_ | STC.returninferred;
+ }
+ }
+ }
+
+ /* Check for returning a ref variable by 'ref', but should be 'return ref'
+ * Infer the addition of 'return', or set result to be the offending expression.
+ */
+ if ((vsr == ScopeRef.Ref ||
+ vsr == ScopeRef.RefScope ||
+ vsr == ScopeRef.Ref_ReturnScope) &&
+ !(v.storage_class & STC.foreach_))
+ {
+ if (sc.func.flags & FUNCFLAG.returnInprocess && p == sc.func &&
+ (vsr == ScopeRef.Ref || vsr == ScopeRef.RefScope))
+ {
+ inferReturn(sc.func, v); // infer addition of 'return'
+ }
+ else if (sc._module && sc._module.isRoot())
+ {
+ // https://dlang.org/spec/function.html#return-ref-parameters
+ // Only look for errors if in module listed on command line
+ if (p == sc.func)
+ {
+ //printf("escaping reference to local ref variable %s\n", v.toChars());
+ //printf("storage class = x%llx\n", v.storage_class);
+ escapingRef(v, vsr, global.params.useDIP25);
+ continue;
+ }
+ // Don't need to be concerned if v's parent does not return a ref
+ FuncDeclaration fd = p.isFuncDeclaration();
+ if (fd && fd.type && fd.type.ty == Tfunction)
+ {
+ TypeFunction tf = fd.type.isTypeFunction();
+ if (tf.isref)
+ {
+ const(char)* msg = "escaping reference to outer local variable `%s`";
+ if (!gag)
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP25)(e.loc, msg, v.toChars());
+ result = true;
+ continue;
+ }
+ }
+
+ }
+ }
+ }
+
+ foreach (Expression ee; er.byexp)
+ {
+ if (log) printf("byexp %s\n", ee.toChars());
+ if (!gag)
+ error(ee.loc, "escaping reference to stack allocated value returned by `%s`", ee.toChars());
+ result = true;
+ }
+
+ return result;
+}
+
+
+/*************************************
+ * Variable v needs to have 'return' inferred for it.
+ * Params:
+ * fd = function that v is a parameter to
+ * v = parameter that needs to be STC.return_
+ */
+
+private void inferReturn(FuncDeclaration fd, VarDeclaration v)
+{
+ // v is a local in the current function
+
+ //printf("for function '%s' inferring 'return' for variable '%s'\n", fd.toChars(), v.toChars());
+ v.storage_class |= STC.return_ | STC.returninferred;
+
+ if (v == fd.vthis)
+ {
+ /* v is the 'this' reference, so mark the function
+ */
+ fd.storage_class |= STC.return_ | STC.returninferred;
+ if (auto tf = fd.type.isTypeFunction())
+ {
+ //printf("'this' too %p %s\n", tf, sc.func.toChars());
+ tf.isreturn = true;
+ tf.isreturninferred = true;
+ }
+ }
+ else
+ {
+ // Perform 'return' inference on parameter
+ if (auto tf = fd.type.isTypeFunction())
+ {
+ foreach (i, p; tf.parameterList)
+ {
+ if (p.ident == v.ident)
+ {
+ p.storageClass |= STC.return_ | STC.returninferred;
+ break; // there can be only one
+ }
+ }
+ }
+ }
+}
+
+
+/****************************************
+ * e is an expression to be returned by value, and that value contains pointers.
+ * Walk e to determine which variables are possibly being
+ * returned by value, such as:
+ * int* function(int* p) { return p; }
+ * If e is a form of &p, determine which variables have content
+ * which is being returned as ref, such as:
+ * int* function(int i) { return &i; }
+ * Multiple variables can be inserted, because of expressions like this:
+ * int function(bool b, int i, int* p) { return b ? &i : p; }
+ *
+ * No side effects.
+ *
+ * Params:
+ * e = expression to be returned by value
+ * er = where to place collected data
+ * live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
+ */
+void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
+{
+ //printf("[%s] escapeByValue, e: %s\n", e.loc.toChars(), e.toChars());
+ extern (C++) final class EscapeVisitor : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ EscapeByResults* er;
+ bool live;
+
+ extern (D) this(EscapeByResults* er, bool live)
+ {
+ this.er = er;
+ this.live = live;
+ }
+
+ override void visit(Expression e)
+ {
+ }
+
+ override void visit(AddrExp e)
+ {
+ /* Taking the address of struct literal is normally not
+ * allowed, but CTFE can generate one out of a new expression,
+ * but it'll be placed in static data so no need to check it.
+ */
+ if (e.e1.op != TOK.structLiteral)
+ escapeByRef(e.e1, er, live);
+ }
+
+ override void visit(SymOffExp e)
+ {
+ VarDeclaration v = e.var.isVarDeclaration();
+ if (v)
+ er.byref.push(v);
+ }
+
+ override void visit(VarExp e)
+ {
+ if (auto v = e.var.isVarDeclaration())
+ {
+ if (v.type.hasPointers() || // not tracking non-pointers
+ v.storage_class & STC.lazy_) // lazy variables are actually pointers
+ er.byvalue.push(v);
+ }
+ }
+
+ override void visit(ThisExp e)
+ {
+ if (e.var)
+ er.byvalue.push(e.var);
+ }
+
+ override void visit(PtrExp e)
+ {
+ if (live && e.type.hasPointers())
+ e.e1.accept(this);
+ }
+
+ override void visit(DotVarExp e)
+ {
+ auto t = e.e1.type.toBasetype();
+ if (e.type.hasPointers() && (live || t.ty == Tstruct))
+ {
+ e.e1.accept(this);
+ }
+ }
+
+ override void visit(DelegateExp e)
+ {
+ Type t = e.e1.type.toBasetype();
+ if (t.ty == Tclass || t.ty == Tpointer)
+ escapeByValue(e.e1, er, live);
+ else
+ escapeByRef(e.e1, er, live);
+ er.byfunc.push(e.func);
+ }
+
+ override void visit(FuncExp e)
+ {
+ if (e.fd.tok == TOK.delegate_)
+ er.byfunc.push(e.fd);
+ }
+
+ override void visit(TupleExp e)
+ {
+ assert(0); // should have been lowered by now
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ Type tb = e.type.toBasetype();
+ if (tb.ty == Tsarray || tb.ty == Tarray)
+ {
+ if (e.basis)
+ e.basis.accept(this);
+ foreach (el; *e.elements)
+ {
+ if (el)
+ el.accept(this);
+ }
+ }
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ if (e.elements)
+ {
+ foreach (ex; *e.elements)
+ {
+ if (ex)
+ ex.accept(this);
+ }
+ }
+ }
+
+ override void visit(NewExp e)
+ {
+ Type tb = e.newtype.toBasetype();
+ if (tb.ty == Tstruct && !e.member && e.arguments)
+ {
+ foreach (ex; *e.arguments)
+ {
+ if (ex)
+ ex.accept(this);
+ }
+ }
+ }
+
+ override void visit(CastExp e)
+ {
+ if (!e.type.hasPointers())
+ return;
+ Type tb = e.type.toBasetype();
+ if (tb.ty == Tarray && e.e1.type.toBasetype().ty == Tsarray)
+ {
+ escapeByRef(e.e1, er, live);
+ }
+ else
+ e.e1.accept(this);
+ }
+
+ override void visit(SliceExp e)
+ {
+ if (auto ve = e.e1.isVarExp())
+ {
+ VarDeclaration v = ve.var.isVarDeclaration();
+ Type tb = e.type.toBasetype();
+ if (v)
+ {
+ if (tb.ty == Tsarray)
+ return;
+ if (v.storage_class & STC.variadic)
+ {
+ er.byvalue.push(v);
+ return;
+ }
+ }
+ }
+ Type t1b = e.e1.type.toBasetype();
+ if (t1b.ty == Tsarray)
+ {
+ Type tb = e.type.toBasetype();
+ if (tb.ty != Tsarray)
+ escapeByRef(e.e1, er, live);
+ }
+ else
+ e.e1.accept(this);
+ }
+
+ override void visit(IndexExp e)
+ {
+ if (e.e1.type.toBasetype().ty == Tsarray ||
+ live && e.type.hasPointers())
+ {
+ e.e1.accept(this);
+ }
+ }
+
+ override void visit(BinExp e)
+ {
+ Type tb = e.type.toBasetype();
+ if (tb.ty == Tpointer)
+ {
+ e.e1.accept(this);
+ e.e2.accept(this);
+ }
+ }
+
+ override void visit(BinAssignExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(AssignExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(CommaExp e)
+ {
+ e.e2.accept(this);
+ }
+
+ override void visit(CondExp e)
+ {
+ e.e1.accept(this);
+ e.e2.accept(this);
+ }
+
+ override void visit(CallExp e)
+ {
+ //printf("CallExp(): %s\n", e.toChars());
+ /* Check each argument that is
+ * passed as 'return scope'.
+ */
+ Type t1 = e.e1.type.toBasetype();
+ TypeFunction tf;
+ TypeDelegate dg;
+ if (t1.ty == Tdelegate)
+ {
+ dg = t1.isTypeDelegate();
+ tf = dg.next.isTypeFunction();
+ }
+ else if (t1.ty == Tfunction)
+ tf = t1.isTypeFunction();
+ else
+ return;
+
+ if (!e.type.hasPointers())
+ return;
+
+ if (e.arguments && e.arguments.dim)
+ {
+ /* j=1 if _arguments[] is first argument,
+ * skip it because it is not passed by ref
+ */
+ int j = tf.isDstyleVariadic();
+ for (size_t i = j; i < e.arguments.dim; ++i)
+ {
+ Expression arg = (*e.arguments)[i];
+ size_t nparams = tf.parameterList.length;
+ if (i - j < nparams && i >= j)
+ {
+ Parameter p = tf.parameterList[i - j];
+ const stc = tf.parameterStorageClass(null, p);
+ if ((stc & (STC.scope_)) && (stc & STC.return_))
+ arg.accept(this);
+ else if ((stc & (STC.ref_)) && (stc & STC.return_))
+ {
+ if (tf.isref)
+ {
+ /* Treat:
+ * ref P foo(return ref P p)
+ * as:
+ * p;
+ */
+ arg.accept(this);
+ }
+ else
+ escapeByRef(arg, er, live);
+ }
+ }
+ }
+ }
+ // If 'this' is returned, check it too
+ if (e.e1.op == TOK.dotVariable && t1.ty == Tfunction)
+ {
+ DotVarExp dve = e.e1.isDotVarExp();
+ FuncDeclaration fd = dve.var.isFuncDeclaration();
+ AggregateDeclaration ad;
+ if (global.params.useDIP1000 == FeatureState.enabled && tf.isreturn && fd && (ad = fd.isThis()) !is null)
+ {
+ if (ad.isClassDeclaration() || tf.isScopeQual) // this is 'return scope'
+ dve.e1.accept(this);
+ else if (ad.isStructDeclaration()) // this is 'return ref'
+ {
+ if (tf.isref)
+ {
+ /* Treat calling:
+ * struct S { ref S foo() return; }
+ * as:
+ * this;
+ */
+ dve.e1.accept(this);
+ }
+ else
+ escapeByRef(dve.e1, er, live);
+ }
+ }
+ else if (dve.var.storage_class & STC.return_ || tf.isreturn)
+ {
+ if (dve.var.storage_class & STC.scope_)
+ dve.e1.accept(this);
+ else if (dve.var.storage_class & STC.ref_)
+ escapeByRef(dve.e1, er, live);
+ }
+ // If it's also a nested function that is 'return scope'
+ if (fd && fd.isNested())
+ {
+ if (tf.isreturn && tf.isScopeQual)
+ er.byexp.push(e);
+ }
+ }
+
+ /* If returning the result of a delegate call, the .ptr
+ * field of the delegate must be checked.
+ */
+ if (dg)
+ {
+ if (tf.isreturn)
+ e.e1.accept(this);
+ }
+
+ /* If it's a nested function that is 'return scope'
+ */
+ if (auto ve = e.e1.isVarExp())
+ {
+ FuncDeclaration fd = ve.var.isFuncDeclaration();
+ if (fd && fd.isNested())
+ {
+ if (tf.isreturn && tf.isScopeQual)
+ er.byexp.push(e);
+ }
+ }
+ }
+ }
+
+ scope EscapeVisitor v = new EscapeVisitor(er, live);
+ e.accept(v);
+}
+
+
+/****************************************
+ * e is an expression to be returned by 'ref'.
+ * Walk e to determine which variables are possibly being
+ * returned by ref, such as:
+ * ref int function(int i) { return i; }
+ * If e is a form of *p, determine which variables have content
+ * which is being returned as ref, such as:
+ * ref int function(int* p) { return *p; }
+ * Multiple variables can be inserted, because of expressions like this:
+ * ref int function(bool b, int i, int* p) { return b ? i : *p; }
+ *
+ * No side effects.
+ *
+ * Params:
+ * e = expression to be returned by 'ref'
+ * er = where to place collected data
+ * live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
+ */
+void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
+{
+ //printf("[%s] escapeByRef, e: %s\n", e.loc.toChars(), e.toChars());
+ extern (C++) final class EscapeRefVisitor : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ EscapeByResults* er;
+ bool live;
+
+ extern (D) this(EscapeByResults* er, bool live)
+ {
+ this.er = er;
+ this.live = live;
+ }
+
+ override void visit(Expression e)
+ {
+ }
+
+ override void visit(VarExp e)
+ {
+ auto v = e.var.isVarDeclaration();
+ if (v)
+ {
+ if (v.storage_class & STC.ref_ && v.storage_class & (STC.foreach_ | STC.temp) && v._init)
+ {
+ /* If compiler generated ref temporary
+ * (ref v = ex; ex)
+ * look at the initializer instead
+ */
+ if (ExpInitializer ez = v._init.isExpInitializer())
+ {
+ if (auto ce = ez.exp.isConstructExp())
+ ce.e2.accept(this);
+ else
+ ez.exp.accept(this);
+ }
+ }
+ else
+ er.byref.push(v);
+ }
+ }
+
+ override void visit(ThisExp e)
+ {
+ if (e.var && e.var.toParent2().isFuncDeclaration().isThis2)
+ escapeByValue(e, er, live);
+ else if (e.var)
+ er.byref.push(e.var);
+ }
+
+ override void visit(PtrExp e)
+ {
+ escapeByValue(e.e1, er, live);
+ }
+
+ override void visit(IndexExp e)
+ {
+ Type tb = e.e1.type.toBasetype();
+ if (auto ve = e.e1.isVarExp())
+ {
+ VarDeclaration v = ve.var.isVarDeclaration();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (v && v.storage_class & STC.variadic)
+ {
+ er.byref.push(v);
+ return;
+ }
+ }
+ }
+ if (tb.ty == Tsarray)
+ {
+ e.e1.accept(this);
+ }
+ else if (tb.ty == Tarray)
+ {
+ escapeByValue(e.e1, er, live);
+ }
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ if (e.elements)
+ {
+ foreach (ex; *e.elements)
+ {
+ if (ex)
+ ex.accept(this);
+ }
+ }
+ er.byexp.push(e);
+ }
+
+ override void visit(DotVarExp e)
+ {
+ Type t1b = e.e1.type.toBasetype();
+ if (t1b.ty == Tclass)
+ escapeByValue(e.e1, er, live);
+ else
+ e.e1.accept(this);
+ }
+
+ override void visit(BinAssignExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(AssignExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(CommaExp e)
+ {
+ e.e2.accept(this);
+ }
+
+ override void visit(CondExp e)
+ {
+ e.e1.accept(this);
+ e.e2.accept(this);
+ }
+
+ override void visit(CallExp e)
+ {
+ //printf("escapeByRef.CallExp(): %s\n", e.toChars());
+ /* If the function returns by ref, check each argument that is
+ * passed as 'return ref'.
+ */
+ Type t1 = e.e1.type.toBasetype();
+ TypeFunction tf;
+ if (t1.ty == Tdelegate)
+ tf = t1.isTypeDelegate().next.isTypeFunction();
+ else if (t1.ty == Tfunction)
+ tf = t1.isTypeFunction();
+ else
+ return;
+ if (tf.isref)
+ {
+ if (e.arguments && e.arguments.dim)
+ {
+ /* j=1 if _arguments[] is first argument,
+ * skip it because it is not passed by ref
+ */
+ int j = tf.isDstyleVariadic();
+ for (size_t i = j; i < e.arguments.dim; ++i)
+ {
+ Expression arg = (*e.arguments)[i];
+ size_t nparams = tf.parameterList.length;
+ if (i - j < nparams && i >= j)
+ {
+ Parameter p = tf.parameterList[i - j];
+ const stc = tf.parameterStorageClass(null, p);
+ if ((stc & (STC.out_ | STC.ref_)) && (stc & STC.return_))
+ arg.accept(this);
+ else if ((stc & STC.scope_) && (stc & STC.return_))
+ {
+ if (auto de = arg.isDelegateExp())
+ {
+ if (de.func.isNested())
+ er.byexp.push(de);
+ }
+ else
+ escapeByValue(arg, er, live);
+ }
+ }
+ }
+ }
+ // If 'this' is returned by ref, check it too
+ if (e.e1.op == TOK.dotVariable && t1.ty == Tfunction)
+ {
+ DotVarExp dve = e.e1.isDotVarExp();
+
+ // https://issues.dlang.org/show_bug.cgi?id=20149#c10
+ if (dve.var.isCtorDeclaration())
+ {
+ er.byexp.push(e);
+ return;
+ }
+
+ if (dve.var.storage_class & STC.return_ || tf.isreturn)
+ {
+ if (dve.var.storage_class & STC.ref_ || tf.isref)
+ dve.e1.accept(this);
+ else if (dve.var.storage_class & STC.scope_ || tf.isScopeQual)
+ escapeByValue(dve.e1, er, live);
+ }
+ // If it's also a nested function that is 'return ref'
+ FuncDeclaration fd = dve.var.isFuncDeclaration();
+ if (fd && fd.isNested())
+ {
+ if (tf.isreturn)
+ er.byexp.push(e);
+ }
+ }
+ // If it's a delegate, check it too
+ if (e.e1.op == TOK.variable && t1.ty == Tdelegate)
+ {
+ escapeByValue(e.e1, er, live);
+ }
+
+ /* If it's a nested function that is 'return ref'
+ */
+ if (auto ve = e.e1.isVarExp())
+ {
+ FuncDeclaration fd = ve.var.isFuncDeclaration();
+ if (fd && fd.isNested())
+ {
+ if (tf.isreturn)
+ er.byexp.push(e);
+ }
+ }
+ }
+ else
+ er.byexp.push(e);
+ }
+ }
+
+ scope EscapeRefVisitor v = new EscapeRefVisitor(er, live);
+ e.accept(v);
+}
+
+
+/************************************
+ * Aggregate the data collected by the escapeBy??() functions.
+ */
+struct EscapeByResults
+{
+ VarDeclarations byref; // array into which variables being returned by ref are inserted
+ VarDeclarations byvalue; // array into which variables with values containing pointers are inserted
+ FuncDeclarations byfunc; // nested functions that are turned into delegates
+ Expressions byexp; // array into which temporaries being returned by ref are inserted
+
+ /** Reset arrays so the storage can be used again
+ */
+ void reset()
+ {
+ byref.setDim(0);
+ byvalue.setDim(0);
+ byfunc.setDim(0);
+ byexp.setDim(0);
+ }
+}
+
+/*************************
+ * Find all variables accessed by this delegate that are
+ * in functions enclosing it.
+ * Params:
+ * fd = function
+ * vars = array to append found variables to
+ */
+public void findAllOuterAccessedVariables(FuncDeclaration fd, VarDeclarations* vars)
+{
+ //printf("findAllOuterAccessedVariables(fd: %s)\n", fd.toChars());
+ for (auto p = fd.parent; p; p = p.parent)
+ {
+ auto fdp = p.isFuncDeclaration();
+ if (!fdp)
+ continue;
+
+ foreach (v; fdp.closureVars)
+ {
+ foreach (const fdv; v.nestedrefs)
+ {
+ if (fdv == fd)
+ {
+ //printf("accessed: %s, type %s\n", v.toChars(), v.type.toChars());
+ vars.push(v);
+ }
+ }
+ }
+ }
+}
+
+/***********************************
+ * Turn off `STC.maybescope` for variable `v`.
+ *
+ * This exists in order to find where `STC.maybescope` is getting turned off.
+ * Params:
+ * v = variable
+ */
+version (none)
+{
+ public void notMaybeScope(string file = __FILE__, int line = __LINE__)(VarDeclaration v)
+ {
+ printf("%.*s(%d): notMaybeScope('%s')\n", cast(int)file.length, file.ptr, line, v.toChars());
+ v.storage_class &= ~STC.maybescope;
+ }
+}
+else
+{
+ public void notMaybeScope(VarDeclaration v)
+ {
+ v.storage_class &= ~STC.maybescope;
+ }
+}
+
+
+/**********************************************
+ * Have some variables that are maybescopes that were
+ * assigned values from other maybescope variables.
+ * Now that semantic analysis of the function is
+ * complete, we can finalize this by turning off
+ * maybescope for array elements that cannot be scope.
+ *
+ * $(TABLE2 Scope Table,
+ * $(THEAD `va`, `v`, =>, `va` , `v` )
+ * $(TROW maybe, maybe, =>, scope, scope)
+ * $(TROW scope, scope, =>, scope, scope)
+ * $(TROW scope, maybe, =>, scope, scope)
+ * $(TROW maybe, scope, =>, scope, scope)
+ * $(TROW - , - , =>, - , - )
+ * $(TROW - , maybe, =>, - , - )
+ * $(TROW - , scope, =>, error, error)
+ * $(TROW maybe, - , =>, scope, - )
+ * $(TROW scope, - , =>, scope, - )
+ * )
+ * Params:
+ * array = array of variables that were assigned to from maybescope variables
+ */
+public void eliminateMaybeScopes(VarDeclaration[] array)
+{
+ enum log = false;
+ if (log) printf("eliminateMaybeScopes()\n");
+ bool changes;
+ do
+ {
+ changes = false;
+ foreach (va; array)
+ {
+ if (log) printf(" va = %s\n", va.toChars());
+ if (!(va.storage_class & (STC.maybescope | STC.scope_)))
+ {
+ if (va.maybes)
+ {
+ foreach (v; *va.maybes)
+ {
+ if (log) printf(" v = %s\n", v.toChars());
+ if (v.storage_class & STC.maybescope)
+ {
+ // v cannot be scope since it is assigned to a non-scope va
+ notMaybeScope(v);
+ if (!v.isReference())
+ v.storage_class &= ~(STC.return_ | STC.returninferred);
+ changes = true;
+ }
+ }
+ }
+ }
+ }
+ } while (changes);
+}
+
+/************************************************
+ * Is type a reference to a mutable value?
+ *
+ * This is used to determine if an argument that does not have a corresponding
+ * Parameter, i.e. a variadic argument, is a pointer to mutable data.
+ * Params:
+ * t = type of the argument
+ * Returns:
+ * true if it's a pointer (or reference) to mutable data
+ */
+bool isReferenceToMutable(Type t)
+{
+ t = t.baseElemOf();
+
+ if (!t.isMutable() ||
+ !t.hasPointers())
+ return false;
+
+ switch (t.ty)
+ {
+ case Tpointer:
+ if (t.nextOf().isTypeFunction())
+ break;
+ goto case;
+
+ case Tarray:
+ case Taarray:
+ case Tdelegate:
+ if (t.nextOf().isMutable())
+ return true;
+ break;
+
+ case Tclass:
+ return true; // even if the class fields are not mutable
+
+ case Tstruct:
+ // Have to look at each field
+ foreach (VarDeclaration v; t.isTypeStruct().sym.fields)
+ {
+ if (v.storage_class & STC.ref_)
+ {
+ if (v.type.isMutable())
+ return true;
+ }
+ else if (v.type.isReferenceToMutable())
+ return true;
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+ return false;
+}
+
+/****************************************
+ * Is parameter a reference to a mutable value?
+ *
+ * This is used if an argument has a corresponding Parameter.
+ * The argument type is necessary if the Parameter is inout.
+ * Params:
+ * p = Parameter to check
+ * t = type of corresponding argument
+ * Returns:
+ * true if it's a pointer (or reference) to mutable data
+ */
+bool isReferenceToMutable(Parameter p, Type t)
+{
+ if (p.isReference())
+ {
+ if (p.type.isConst() || p.type.isImmutable())
+ return false;
+ if (p.type.isWild())
+ {
+ return t.isMutable();
+ }
+ return p.type.isMutable();
+ }
+ return isReferenceToMutable(p.type);
+}
diff --git a/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c
deleted file mode 100644
index 18aa6aa..0000000
--- a/gcc/d/dmd/expression.c
+++ /dev/null
@@ -1,5706 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/expression.c
- */
-
-#include "root/dsystem.h"
-#include "root/rmem.h"
-#include "root/root.h"
-
-#include "errors.h"
-#include "mtype.h"
-#include "init.h"
-#include "expression.h"
-#include "template.h"
-#include "utf.h"
-#include "enum.h"
-#include "scope.h"
-#include "statement.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "import.h"
-#include "id.h"
-#include "dsymbol.h"
-#include "module.h"
-#include "attrib.h"
-#include "hdrgen.h"
-#include "parse.h"
-#include "doc.h"
-#include "root/aav.h"
-#include "nspace.h"
-#include "ctfe.h"
-#include "target.h"
-
-bool walkPostorder(Expression *e, StoppableVisitor *v);
-bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag);
-bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember);
-VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
-Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
-char *MODtoChars(MOD mod);
-bool MODimplicitConv(MOD modfrom, MOD modto);
-void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
-Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
-void toAutoQualChars(const char **result, Type *t1, Type *t2);
-
-/*****************************************
- * Determine if 'this' is available.
- * If it is, return the FuncDeclaration that has it.
- */
-
-FuncDeclaration *hasThis(Scope *sc)
-{
- //printf("hasThis()\n");
- Dsymbol *p = sc->parent;
- while (p && p->isTemplateMixin())
- p = p->parent;
- FuncDeclaration *fdthis = p ? p->isFuncDeclaration() : NULL;
- //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : "");
-
- // Go upwards until we find the enclosing member function
- FuncDeclaration *fd = fdthis;
- while (1)
- {
- if (!fd)
- {
- goto Lno;
- }
- if (!fd->isNested())
- break;
-
- Dsymbol *parent = fd->parent;
- while (1)
- {
- if (!parent)
- goto Lno;
- TemplateInstance *ti = parent->isTemplateInstance();
- if (ti)
- parent = ti->parent;
- else
- break;
- }
- fd = parent->isFuncDeclaration();
- }
-
- if (!fd->isThis())
- { //printf("test '%s'\n", fd->toChars());
- goto Lno;
- }
-
- assert(fd->vthis);
- return fd;
-
-Lno:
- return NULL; // don't have 'this' available
-}
-
-bool isNeedThisScope(Scope *sc, Declaration *d)
-{
- if (sc->intypeof == 1)
- return false;
-
- AggregateDeclaration *ad = d->isThis();
- if (!ad)
- return false;
- //printf("d = %s, ad = %s\n", d->toChars(), ad->toChars());
-
- for (Dsymbol *s = sc->parent; s; s = s->toParent2())
- {
- //printf("\ts = %s %s, toParent2() = %p\n", s->kind(), s->toChars(), s->toParent2());
- if (AggregateDeclaration *ad2 = s->isAggregateDeclaration())
- {
- if (ad2 == ad)
- return false;
- else if (ad2->isNested())
- continue;
- else
- return true;
- }
- if (FuncDeclaration *f = s->isFuncDeclaration())
- {
- if (f->isMember2())
- break;
- }
- }
- return true;
-}
-
-/******************************
- * check e is exp.opDispatch!(tiargs) or not
- * It's used to switch to UFCS the semantic analysis path
- */
-
-bool isDotOpDispatch(Expression *e)
-{
- return e->op == TOKdotti &&
- ((DotTemplateInstanceExp *)e)->ti->name == Id::opDispatch;
-}
-
-/****************************************
- * Expand tuples.
- * Input:
- * exps aray of Expressions
- * Output:
- * exps rewritten in place
- */
-
-void expandTuples(Expressions *exps)
-{
- //printf("expandTuples()\n");
- if (exps)
- {
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *arg = (*exps)[i];
- if (!arg)
- continue;
-
- // Look for tuple with 0 members
- if (arg->op == TOKtype)
- {
- TypeExp *e = (TypeExp *)arg;
- if (e->type->toBasetype()->ty == Ttuple)
- {
- TypeTuple *tt = (TypeTuple *)e->type->toBasetype();
-
- if (!tt->arguments || tt->arguments->length == 0)
- {
- exps->remove(i);
- if (i == exps->length)
- return;
- i--;
- continue;
- }
- }
- }
-
- // Inline expand all the tuples
- while (arg->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)arg;
- exps->remove(i); // remove arg
- exps->insert(i, te->exps); // replace with tuple contents
- if (i == exps->length)
- return; // empty tuple, no more arguments
- (*exps)[i] = Expression::combine(te->e0, (*exps)[i]);
- arg = (*exps)[i];
- }
- }
- }
-}
-
-/****************************************
- * Expand alias this tuples.
- */
-
-TupleDeclaration *isAliasThisTuple(Expression *e)
-{
- if (!e->type)
- return NULL;
-
- Type *t = e->type->toBasetype();
-Lagain:
- if (Dsymbol *s = t->toDsymbol(NULL))
- {
- AggregateDeclaration *ad = s->isAggregateDeclaration();
- if (ad)
- {
- s = ad->aliasthis;
- if (s && s->isVarDeclaration())
- {
- TupleDeclaration *td = s->isVarDeclaration()->toAlias()->isTupleDeclaration();
- if (td && td->isexp)
- return td;
- }
- if (Type *att = t->aliasthisOf())
- {
- t = att;
- goto Lagain;
- }
- }
- }
- return NULL;
-}
-
-int expandAliasThisTuples(Expressions *exps, size_t starti)
-{
- if (!exps || exps->length == 0)
- return -1;
-
- for (size_t u = starti; u < exps->length; u++)
- {
- Expression *exp = (*exps)[u];
- TupleDeclaration *td = isAliasThisTuple(exp);
- if (td)
- {
- exps->remove(u);
- for (size_t i = 0; i<td->objects->length; ++i)
- {
- Expression *e = isExpression((*td->objects)[i]);
- assert(e);
- assert(e->op == TOKdsymbol);
- DsymbolExp *se = (DsymbolExp *)e;
- Declaration *d = se->s->isDeclaration();
- assert(d);
- e = new DotVarExp(exp->loc, exp, d);
- assert(d->type);
- e->type = d->type;
- exps->insert(u + i, e);
- }
- return (int)u;
- }
- }
-
- return -1;
-}
-
-/****************************************
- * Get TemplateDeclaration enclosing FuncDeclaration.
- */
-
-TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s)
-{
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f && f->parent)
- {
- TemplateInstance *ti = f->parent->isTemplateInstance();
- if (ti && !ti->isTemplateMixin() &&
- ti->tempdecl && ((TemplateDeclaration *)ti->tempdecl)->onemember &&
- ti->tempdecl->ident == f->ident)
- {
- return (TemplateDeclaration *)ti->tempdecl;
- }
- }
- return NULL;
-}
-
-/************************************************
- * If we want the value of this expression, but do not want to call
- * the destructor on it.
- */
-
-Expression *valueNoDtor(Expression *e)
-{
- if (e->op == TOKcall)
- {
- /* The struct value returned from the function is transferred
- * so do not call the destructor on it.
- * Recognize:
- * ((S _ctmp = S.init), _ctmp).this(...)
- * and make sure the destructor is not called on _ctmp
- * BUG: if e is a CommaExp, we should go down the right side.
- */
- CallExp *ce = (CallExp *)e;
- if (ce->e1->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp *)ce->e1;
- if (dve->var->isCtorDeclaration())
- {
- // It's a constructor call
- if (dve->e1->op == TOKcomma)
- {
- CommaExp *comma = (CommaExp *)dve->e1;
- if (comma->e2->op == TOKvar)
- {
- VarExp *ve = (VarExp *)comma->e2;
- VarDeclaration *ctmp = ve->var->isVarDeclaration();
- if (ctmp)
- {
- ctmp->storage_class |= STCnodtor;
- assert(!ce->isLvalue());
- }
- }
- }
- }
- }
- }
- else if (e->op == TOKvar)
- {
- VarDeclaration *vtmp = ((VarExp *)e)->var->isVarDeclaration();
- if (vtmp && vtmp->storage_class & STCrvalue)
- {
- vtmp->storage_class |= STCnodtor;
- }
- }
- return e;
-}
-
-/*********************************************
- * If e is an instance of a struct, and that struct has a copy constructor,
- * rewrite e as:
- * (tmp = e),tmp
- * Input:
- * sc just used to specify the scope of created temporary variable
- */
-Expression *callCpCtor(Scope *sc, Expression *e)
-{
- Type *tv = e->type->baseElemOf();
- if (tv->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)tv)->sym;
- if (sd->postblit)
- {
- /* Create a variable tmp, and replace the argument e with:
- * (tmp = e),tmp
- * and let AssignExp() handle the construction.
- * This is not the most efficent, ideally tmp would be constructed
- * directly onto the stack.
- */
- VarDeclaration *tmp = copyToTemp(STCrvalue, "__copytmp", e);
- tmp->storage_class |= STCnodtor;
- dsymbolSemantic(tmp, sc);
- Expression *de = new DeclarationExp(e->loc, tmp);
- Expression *ve = new VarExp(e->loc, tmp);
- de->type = Type::tvoid;
- ve->type = e->type;
- e = Expression::combine(de, ve);
- }
- }
- return e;
-}
-
-/************************************************
- * Handle the postblit call on lvalue, or the move of rvalue.
- */
-Expression *doCopyOrMove(Scope *sc, Expression *e)
-{
- if (e->op == TOKquestion)
- {
- CondExp *ce = (CondExp *)e;
- ce->e1 = doCopyOrMove(sc, ce->e1);
- ce->e2 = doCopyOrMove(sc, ce->e2);
- }
- else
- {
- e = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
- }
- return e;
-}
-
-/******************************** Expression **************************/
-
-Expression::Expression(Loc loc, TOK op, int size)
-{
- //printf("Expression::Expression(op = %d) this = %p\n", op, this);
- this->loc = loc;
- this->op = op;
- this->size = (unsigned char)size;
- this->parens = 0;
- type = NULL;
-}
-
-void Expression::_init()
-{
- CTFEExp::cantexp = new CTFEExp(TOKcantexp);
- CTFEExp::voidexp = new CTFEExp(TOKvoidexp);
- CTFEExp::breakexp = new CTFEExp(TOKbreak);
- CTFEExp::continueexp = new CTFEExp(TOKcontinue);
- CTFEExp::gotoexp = new CTFEExp(TOKgoto);
-}
-
-Expression *Expression::syntaxCopy()
-{
- //printf("Expression::syntaxCopy()\n");
- //print();
- return copy();
-}
-
-/*********************************
- * Does *not* do a deep copy.
- */
-
-Expression *Expression::copy()
-{
- Expression *e;
- if (!size)
- {
- assert(0);
- }
- void *pe = mem.xmalloc(size);
- //printf("Expression::copy(op = %d) e = %p\n", op, pe);
- e = (Expression *)memcpy(pe, (void *)this, size);
- return e;
-}
-
-void Expression::print()
-{
- fprintf(stderr, "%s\n", toChars());
- fflush(stderr);
-}
-
-const char *Expression::toChars()
-{
- OutBuffer buf;
- HdrGenState hgs;
- toCBuffer(this, &buf, &hgs);
- return buf.extractChars();
-}
-
-void Expression::error(const char *format, ...) const
-{
- if (type != Type::terror)
- {
- va_list ap;
- va_start(ap, format);
- ::verror(loc, format, ap);
- va_end( ap );
- }
-}
-
-void Expression::warning(const char *format, ...) const
-{
- if (type != Type::terror)
- {
- va_list ap;
- va_start(ap, format);
- ::vwarning(loc, format, ap);
- va_end( ap );
- }
-}
-
-void Expression::deprecation(const char *format, ...) const
-{
- if (type != Type::terror)
- {
- va_list ap;
- va_start(ap, format);
- ::vdeprecation(loc, format, ap);
- va_end( ap );
- }
-}
-
-/**********************************
- * Combine e1 and e2 by CommaExp if both are not NULL.
- */
-Expression *Expression::combine(Expression *e1, Expression *e2)
-{
- if (e1)
- {
- if (e2)
- {
- e1 = new CommaExp(e1->loc, e1, e2);
- e1->type = e2->type;
- }
- }
- else
- e1 = e2;
- return e1;
-}
-
-/**********************************
- * If 'e' is a tree of commas, returns the leftmost expression
- * by stripping off it from the tree. The remained part of the tree
- * is returned via *pe0.
- * Otherwise 'e' is directly returned and *pe0 is set to NULL.
- */
-Expression *Expression::extractLast(Expression *e, Expression **pe0)
-{
- if (e->op != TOKcomma)
- {
- *pe0 = NULL;
- return e;
- }
-
- CommaExp *ce = (CommaExp *)e;
- if (ce->e2->op != TOKcomma)
- {
- *pe0 = ce->e1;
- return ce->e2;
- }
- else
- {
- *pe0 = e;
-
- Expression **pce = &ce->e2;
- while (((CommaExp *)(*pce))->e2->op == TOKcomma)
- {
- pce = &((CommaExp *)(*pce))->e2;
- }
- assert((*pce)->op == TOKcomma);
- ce = (CommaExp *)(*pce);
- *pce = ce->e1;
-
- return ce->e2;
- }
-}
-
-dinteger_t Expression::toInteger()
-{
- //printf("Expression %s\n", Token::toChars(op));
- error("integer constant expression expected instead of %s", toChars());
- return 0;
-}
-
-uinteger_t Expression::toUInteger()
-{
- //printf("Expression %s\n", Token::toChars(op));
- return (uinteger_t)toInteger();
-}
-
-real_t Expression::toReal()
-{
- error("floating point constant expression expected instead of %s", toChars());
- return CTFloat::zero;
-}
-
-real_t Expression::toImaginary()
-{
- error("floating point constant expression expected instead of %s", toChars());
- return CTFloat::zero;
-}
-
-complex_t Expression::toComplex()
-{
- error("floating point constant expression expected instead of %s", toChars());
- return complex_t(CTFloat::zero);
-}
-
-StringExp *Expression::toStringExp()
-{
- return NULL;
-}
-
-TupleExp *Expression::toTupleExp()
-{
- return NULL;
-}
-
-/***************************************
- * Return !=0 if expression is an lvalue.
- */
-
-bool Expression::isLvalue()
-{
- return false;
-}
-
-/*******************************
- * Give error if we're not an lvalue.
- * If we can, convert expression to be an lvalue.
- */
-
-Expression *Expression::toLvalue(Scope *, Expression *e)
-{
- if (!e)
- e = this;
- else if (!loc.filename)
- loc = e->loc;
-
- if (e->op == TOKtype)
- error("%s `%s` is a type, not an lvalue", e->type->kind(), e->type->toChars());
- else
- error("%s is not an lvalue", e->toChars());
-
- return new ErrorExp();
-}
-
-/***************************************
- * Parameters:
- * sc: scope
- * flag: 1: do not issue error message for invalid modification
- * Returns:
- * 0: is not modifiable
- * 1: is modifiable in default == being related to type->isMutable()
- * 2: is modifiable, because this is a part of initializing.
- */
-
-int Expression::checkModifiable(Scope *, int)
-{
- return type ? 1 : 0; // default modifiable
-}
-
-Expression *Expression::modifiableLvalue(Scope *sc, Expression *e)
-{
- //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars());
-
- // See if this expression is a modifiable lvalue (i.e. not const)
- if (checkModifiable(sc) == 1)
- {
- assert(type);
- if (!type->isMutable())
- {
- error("cannot modify %s expression %s", MODtoChars(type->mod), toChars());
- return new ErrorExp();
- }
- else if (!type->isAssignable())
- {
- error("cannot modify struct %s %s with immutable members", toChars(), type->toChars());
- return new ErrorExp();
- }
- }
- return toLvalue(sc, e);
-}
-
-/****************************************
- * Check that the expression has a valid type.
- * If not, generates an error "... has no type".
- * Returns:
- * true if the expression is not valid.
- * Note:
- * When this function returns true, `checkValue()` should also return true.
- */
-bool Expression::checkType()
-{
- return false;
-}
-
-/****************************************
- * Check that the expression has a valid value.
- * If not, generates an error "... has no value".
- * Returns:
- * true if the expression is not valid or has void type.
- */
-bool Expression::checkValue()
-{
- if (type && type->toBasetype()->ty == Tvoid)
- {
- error("expression %s is void and has no value", toChars());
- //print(); halt();
- if (!global.gag)
- type = Type::terror;
- return true;
- }
- return false;
-}
-
-bool Expression::checkScalar()
-{
- if (op == TOKerror)
- return true;
- if (type->toBasetype()->ty == Terror)
- return true;
- if (!type->isscalar())
- {
- error("`%s` is not a scalar, it is a %s", toChars(), type->toChars());
- return true;
- }
- return checkValue();
-}
-
-bool Expression::checkNoBool()
-{
- if (op == TOKerror)
- return true;
- if (type->toBasetype()->ty == Terror)
- return true;
- if (type->toBasetype()->ty == Tbool)
- {
- error("operation not allowed on bool `%s`", toChars());
- return true;
- }
- return false;
-}
-
-bool Expression::checkIntegral()
-{
- if (op == TOKerror)
- return true;
- if (type->toBasetype()->ty == Terror)
- return true;
- if (!type->isintegral())
- {
- error("`%s` is not of integral type, it is a %s", toChars(), type->toChars());
- return true;
- }
- return checkValue();
-}
-
-bool Expression::checkArithmetic()
-{
- if (op == TOKerror)
- return true;
- if (type->toBasetype()->ty == Terror)
- return true;
- if (!type->isintegral() && !type->isfloating())
- {
- error("`%s` is not of arithmetic type, it is a %s", toChars(), type->toChars());
- return true;
- }
- return checkValue();
-}
-
-bool Expression::checkDeprecated(Scope *sc, Dsymbol *s)
-{
- return s->checkDeprecated(loc, sc);
-}
-
-bool Expression::checkDisabled(Scope *sc, Dsymbol *s)
-{
- if (Declaration *d = s->isDeclaration())
- {
- return d->checkDisabled(loc, sc);
- }
- return false;
-}
-
-/*********************************************
- * Calling function f.
- * Check the purity, i.e. if we're in a pure function
- * we can only call other pure functions.
- * Returns true if error occurs.
- */
-bool Expression::checkPurity(Scope *sc, FuncDeclaration *f)
-{
- if (!sc->func)
- return false;
- if (sc->func == f)
- return false;
- if (sc->intypeof == 1)
- return false;
- if (sc->flags & (SCOPEctfe | SCOPEdebug))
- return false;
-
- /* Given:
- * void f() {
- * pure void g() {
- * /+pure+/ void h() {
- * /+pure+/ void i() { }
- * }
- * }
- * }
- * g() can call h() but not f()
- * i() can call h() and g() but not f()
- */
-
- // Find the closest pure parent of the calling function
- FuncDeclaration *outerfunc = sc->func;
- FuncDeclaration *calledparent = f;
-
- if (outerfunc->isInstantiated())
- {
- // The attributes of outerfunc should be inferred from the call of f.
- }
- else if (f->isInstantiated())
- {
- // The attributes of f are inferred from its body.
- }
- else if (f->isFuncLiteralDeclaration())
- {
- // The attributes of f are always inferred in its declared place.
- }
- else
- {
- /* Today, static local functions are impure by default, but they cannot
- * violate purity of enclosing functions.
- *
- * auto foo() pure { // non instantiated funciton
- * static auto bar() { // static, without pure attribute
- * impureFunc(); // impure call
- * // Although impureFunc is called inside bar, f(= impureFunc)
- * // is not callable inside pure outerfunc(= foo <- bar).
- * }
- *
- * bar();
- * // Although bar is called inside foo, f(= bar) is callable
- * // bacause calledparent(= foo) is same with outerfunc(= foo).
- * }
- */
-
- while (outerfunc->toParent2() &&
- outerfunc->isPureBypassingInference() == PUREimpure &&
- outerfunc->toParent2()->isFuncDeclaration())
- {
- outerfunc = outerfunc->toParent2()->isFuncDeclaration();
- if (outerfunc->type->ty == Terror)
- return true;
- }
- while (calledparent->toParent2() &&
- calledparent->isPureBypassingInference() == PUREimpure &&
- calledparent->toParent2()->isFuncDeclaration())
- {
- calledparent = calledparent->toParent2()->isFuncDeclaration();
- if (calledparent->type->ty == Terror)
- return true;
- }
- }
-
- // If the caller has a pure parent, then either the called func must be pure,
- // OR, they must have the same pure parent.
- if (!f->isPure() && calledparent != outerfunc)
- {
- FuncDeclaration *ff = outerfunc;
- if (sc->flags & SCOPEcompile ? ff->isPureBypassingInference() >= PUREweak : ff->setImpure())
- {
- error("pure %s `%s` cannot call impure %s `%s`",
- ff->kind(), ff->toPrettyChars(), f->kind(), f->toPrettyChars());
- return true;
- }
- }
- return false;
-}
-
-/*******************************************
- * Accessing variable v.
- * Check for purity and safety violations.
- * Returns true if error occurs.
- */
-bool Expression::checkPurity(Scope *sc, VarDeclaration *v)
-{
- //printf("v = %s %s\n", v->type->toChars(), v->toChars());
-
- /* Look for purity and safety violations when accessing variable v
- * from current function.
- */
- if (!sc->func)
- return false;
- if (sc->intypeof == 1)
- return false; // allow violations inside typeof(expression)
- if (sc->flags & (SCOPEctfe | SCOPEdebug))
- return false; // allow violations inside compile-time evaluated expressions and debug conditionals
- if (v->ident == Id::ctfe)
- return false; // magic variable never violates pure and safe
- if (v->isImmutable())
- return false; // always safe and pure to access immutables...
- if (v->isConst() && !v->isRef() && (v->isDataseg() || v->isParameter()) &&
- v->type->implicitConvTo(v->type->immutableOf()))
- return false; // or const global/parameter values which have no mutable indirections
- if (v->storage_class & STCmanifest)
- return false; // ...or manifest constants
-
- bool err = false;
- if (v->isDataseg())
- {
- // Bugzilla 7533: Accessing implicit generated __gate is pure.
- if (v->ident == Id::gate)
- return false;
-
- /* Accessing global mutable state.
- * Therefore, this function and all its immediately enclosing
- * functions must be pure.
- */
- /* Today, static local functions are impure by default, but they cannot
- * violate purity of enclosing functions.
- *
- * auto foo() pure { // non instantiated funciton
- * static auto bar() { // static, without pure attribute
- * globalData++; // impure access
- * // Although globalData is accessed inside bar,
- * // it is not accessible inside pure foo.
- * }
- * }
- */
- for (Dsymbol *s = sc->func; s; s = s->toParent2())
- {
- FuncDeclaration *ff = s->isFuncDeclaration();
- if (!ff)
- break;
- if (sc->flags & SCOPEcompile ? ff->isPureBypassingInference() >= PUREweak : ff->setImpure())
- {
- error("pure %s `%s` cannot access mutable static data `%s`",
- ff->kind(), ff->toPrettyChars(), v->toChars());
- err = true;
- break;
- }
- /* If the enclosing is an instantiated function or a lambda, its
- * attribute inference result is preferred.
- */
- if (ff->isInstantiated())
- break;
- if (ff->isFuncLiteralDeclaration())
- break;
- }
- }
- else
- {
- /* Given:
- * void f() {
- * int fx;
- * pure void g() {
- * int gx;
- * /+pure+/ void h() {
- * int hx;
- * /+pure+/ void i() { }
- * }
- * }
- * }
- * i() can modify hx and gx but not fx
- */
-
- Dsymbol *vparent = v->toParent2();
- for (Dsymbol *s = sc->func; !err && s; s = s->toParent2())
- {
- if (s == vparent)
- break;
-
- if (AggregateDeclaration *ad = s->isAggregateDeclaration())
- {
- if (ad->isNested())
- continue;
- break;
- }
- FuncDeclaration *ff = s->isFuncDeclaration();
- if (!ff)
- break;
- if (ff->isNested() || ff->isThis())
- {
- if (ff->type->isImmutable() ||
- (ff->type->isShared() && !MODimplicitConv(ff->type->mod, v->type->mod)))
- {
- OutBuffer ffbuf;
- OutBuffer vbuf;
- MODMatchToBuffer(&ffbuf, ff->type->mod, v->type->mod);
- MODMatchToBuffer(&vbuf, v->type->mod, ff->type->mod);
- error("%s%s `%s` cannot access %sdata `%s`",
- ffbuf.peekChars(), ff->kind(), ff->toPrettyChars(), vbuf.peekChars(), v->toChars());
- err = true;
- break;
- }
- continue;
- }
- break;
- }
- }
-
- /* Do not allow safe functions to access __gshared data
- */
- if (v->storage_class & STCgshared)
- {
- if (sc->func->setUnsafe())
- {
- error("safe %s `%s` cannot access __gshared data `%s`",
- sc->func->kind(), sc->func->toChars(), v->toChars());
- err = true;
- }
- }
-
- return err;
-}
-
-/*********************************************
- * Calling function f.
- * Check the safety, i.e. if we're in a @safe function
- * we can only call @safe or @trusted functions.
- * Returns true if error occurs.
- */
-bool Expression::checkSafety(Scope *sc, FuncDeclaration *f)
-{
- if (!sc->func)
- return false;
- if (sc->func == f)
- return false;
- if (sc->intypeof == 1)
- return false;
- if (sc->flags & SCOPEctfe)
- return false;
-
- if (!f->isSafe() && !f->isTrusted())
- {
- if (sc->flags & SCOPEcompile ? sc->func->isSafeBypassingInference() : sc->func->setUnsafe())
- {
- if (loc.linnum == 0) // e.g. implicitly generated dtor
- loc = sc->func->loc;
-
- error("@safe %s `%s` cannot call @system %s `%s`",
- sc->func->kind(), sc->func->toPrettyChars(), f->kind(), f->toPrettyChars());
- return true;
- }
- }
- return false;
-}
-
-/*********************************************
- * Calling function f.
- * Check the @nogc-ness, i.e. if we're in a @nogc function
- * we can only call other @nogc functions.
- * Returns true if error occurs.
- */
-bool Expression::checkNogc(Scope *sc, FuncDeclaration *f)
-{
- if (!sc->func)
- return false;
- if (sc->func == f)
- return false;
- if (sc->intypeof == 1)
- return false;
- if (sc->flags & SCOPEctfe)
- return false;
-
- if (!f->isNogc())
- {
- if (sc->flags & SCOPEcompile ? sc->func->isNogcBypassingInference() : sc->func->setGC())
- {
- if (loc.linnum == 0) // e.g. implicitly generated dtor
- loc = sc->func->loc;
-
- error("@nogc %s `%s` cannot call non-@nogc %s `%s`",
- sc->func->kind(), sc->func->toPrettyChars(), f->kind(), f->toPrettyChars());
- return true;
- }
- }
- return false;
-}
-
-/********************************************
- * Check that the postblit is callable if t is an array of structs.
- * Returns true if error happens.
- */
-bool Expression::checkPostblit(Scope *sc, Type *t)
-{
- t = t->baseElemOf();
- if (t->ty == Tstruct)
- {
- if (global.params.useTypeInfo && Type::dtypeinfo)
- {
- // Bugzilla 11395: Require TypeInfo generation for array concatenation
- semanticTypeInfo(sc, t);
- }
-
- StructDeclaration *sd = ((TypeStruct *)t)->sym;
- if (sd->postblit)
- {
- if (sd->postblit->checkDisabled(loc, sc))
- return true;
- //checkDeprecated(sc, sd->postblit); // necessary?
- checkPurity(sc, sd->postblit);
- checkSafety(sc, sd->postblit);
- checkNogc(sc, sd->postblit);
- //checkAccess(sd, loc, sc, sd->postblit); // necessary?
- return false;
- }
- }
- return false;
-}
-
-bool Expression::checkRightThis(Scope *sc)
-{
- if (op == TOKerror)
- return true;
- if (op == TOKvar && type->ty != Terror)
- {
- VarExp *ve = (VarExp *)this;
- if (isNeedThisScope(sc, ve->var))
- {
- //printf("checkRightThis sc->intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
- // sc->intypeof, sc->getStructClassScope(), func, fdthis);
- error("need `this` for `%s` of type `%s`", ve->var->toChars(), ve->var->type->toChars());
- return true;
- }
- }
- return false;
-}
-
-/*******************************
- * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
- * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
- * Returns true if error occurs.
- */
-bool Expression::checkReadModifyWrite(TOK rmwOp, Expression *ex)
-{
- //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex->toChars() : "");
- if (!type || !type->isShared())
- return false;
-
- // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
- switch (rmwOp)
- {
- case TOKplusplus:
- case TOKpreplusplus:
- rmwOp = TOKaddass;
- break;
-
- case TOKminusminus:
- case TOKpreminusminus:
- rmwOp = TOKminass;
- break;
-
- default:
- break;
- }
-
- deprecation("read-modify-write operations are not allowed for shared variables. "
- "Use core.atomic.atomicOp!\"%s\"(%s, %s) instead.",
- Token::tochars[rmwOp], toChars(), ex ? ex->toChars() : "1");
- return false;
-
- // note: enable when deprecation becomes an error.
- // return true;
-}
-
-/*****************************
- * If expression can be tested for true or false,
- * returns the modified expression.
- * Otherwise returns ErrorExp.
- */
-Expression *Expression::toBoolean(Scope *sc)
-{
- // Default is 'yes' - do nothing
- Expression *e = this;
- Type *t = type;
- Type *tb = type->toBasetype();
- Type *att = NULL;
-Lagain:
- // Structs can be converted to bool using opCast(bool)()
- if (tb->ty == Tstruct)
- {
- AggregateDeclaration *ad = ((TypeStruct *)tb)->sym;
- /* Don't really need to check for opCast first, but by doing so we
- * get better error messages if it isn't there.
- */
- Dsymbol *fd = search_function(ad, Id::_cast);
- if (fd)
- {
- e = new CastExp(loc, e, Type::tbool);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- // Forward to aliasthis.
- if (ad->aliasthis && tb != att)
- {
- if (!att && tb->checkAliasThisRec())
- att = tb;
- e = resolveAliasThis(sc, e);
- t = e->type;
- tb = e->type->toBasetype();
- goto Lagain;
- }
- }
-
- if (!t->isBoolean())
- {
- if (tb != Type::terror)
- error("expression %s of type %s does not have a boolean value", toChars(), t->toChars());
- return new ErrorExp();
- }
- return e;
-}
-
-/******************************
- * Take address of expression.
- */
-
-Expression *Expression::addressOf()
-{
- //printf("Expression::addressOf()\n");
- Expression *e = new AddrExp(loc, this);
- e->type = type->pointerTo();
- return e;
-}
-
-/******************************
- * If this is a reference, dereference it.
- */
-
-Expression *Expression::deref()
-{
- //printf("Expression::deref()\n");
- // type could be null if forward referencing an 'auto' variable
- if (type && type->ty == Treference)
- {
- Expression *e = new PtrExp(loc, this);
- e->type = ((TypeReference *)type)->next;
- return e;
- }
- return this;
-}
-
-/********************************
- * Does this expression statically evaluate to a boolean 'result' (true or false)?
- */
-bool Expression::isBool(bool)
-{
- return false;
-}
-
-IntegerExp *Expression::isIntegerExp()
-{
- return op == TOKint64 ? (IntegerExp *)this : NULL;
-}
-
-ErrorExp *Expression::isErrorExp()
-{
- return op == TOKerror ? (ErrorExp *)this : NULL;
-}
-
-VoidInitExp *Expression::isVoidInitExp()
-{
- return op == TOKvoid ? (VoidInitExp *)this : NULL;
-}
-
-RealExp *Expression::isRealExp()
-{
- return op == TOKfloat64 ? (RealExp *)this : NULL;
-}
-
-ComplexExp *Expression::isComplexExp()
-{
- return op == TOKcomplex80 ? (ComplexExp *)this : NULL;
-}
-
-IdentifierExp *Expression::isIdentifierExp()
-{
- return op == TOKidentifier ? (IdentifierExp *)this : NULL;
-}
-
-DollarExp *Expression::isDollarExp()
-{
- return op == TOKdollar ? (DollarExp *)this : NULL;
-}
-
-DsymbolExp *Expression::isDsymbolExp()
-{
- return op == TOKdsymbol ? (DsymbolExp *)this : NULL;
-}
-
-ThisExp *Expression::isThisExp()
-{
- return op == TOKthis ? (ThisExp *)this : NULL;
-}
-
-SuperExp *Expression::isSuperExp()
-{
- return op == TOKsuper ? (SuperExp *)this : NULL;
-}
-
-NullExp *Expression::isNullExp()
-{
- return op == TOKnull ? (NullExp *)this : NULL;
-}
-
-StringExp *Expression::isStringExp()
-{
- return op == TOKstring ? (StringExp *)this : NULL;
-}
-
-TupleExp *Expression::isTupleExp()
-{
- return op == TOKtuple ? (TupleExp *)this : NULL;
-}
-
-ArrayLiteralExp *Expression::isArrayLiteralExp()
-{
- return op == TOKarrayliteral ? (ArrayLiteralExp *)this : NULL;
-}
-
-AssocArrayLiteralExp *Expression::isAssocArrayLiteralExp()
-{
- return op == TOKassocarrayliteral ? (AssocArrayLiteralExp *)this : NULL;
-}
-
-StructLiteralExp *Expression::isStructLiteralExp()
-{
- return op == TOKstructliteral ? (StructLiteralExp *)this : NULL;
-}
-
-TypeExp *Expression::isTypeExp()
-{
- return op == TOKtype ? (TypeExp *)this : NULL;
-}
-
-ScopeExp *Expression::isScopeExp()
-{
- return op == TOKscope ? (ScopeExp *)this : NULL;
-}
-
-TemplateExp *Expression::isTemplateExp()
-{
- return op == TOKtemplate ? (TemplateExp *)this : NULL;
-}
-
-NewExp *Expression::isNewExp()
-{
- return op == TOKnew ? (NewExp *)this : NULL;
-}
-
-NewAnonClassExp *Expression::isNewAnonClassExp()
-{
- return op == TOKnewanonclass ? (NewAnonClassExp *)this : NULL;
-}
-
-SymOffExp *Expression::isSymOffExp()
-{
- return op == TOKsymoff ? (SymOffExp *)this : NULL;
-}
-
-VarExp *Expression::isVarExp()
-{
- return op == TOKvar ? (VarExp *)this : NULL;
-}
-
-OverExp *Expression::isOverExp()
-{
- return op == TOKoverloadset ? (OverExp *)this : NULL;
-}
-
-FuncExp *Expression::isFuncExp()
-{
- return op == TOKfunction ? (FuncExp *)this : NULL;
-}
-
-DeclarationExp *Expression::isDeclarationExp()
-{
- return op == TOKdeclaration ? (DeclarationExp *)this : NULL;
-}
-
-TypeidExp *Expression::isTypeidExp()
-{
- return op == TOKtypeid ? (TypeidExp *)this : NULL;
-}
-
-TraitsExp *Expression::isTraitsExp()
-{
- return op == TOKtraits ? (TraitsExp *)this : NULL;
-}
-
-HaltExp *Expression::isHaltExp()
-{
- return op == TOKhalt ? (HaltExp *)this : NULL;
-}
-
-IsExp *Expression::isExp()
-{
- return op == TOKis ? (IsExp *)this : NULL;
-}
-
-CompileExp *Expression::isCompileExp()
-{
- return op == TOKmixin ? (CompileExp *)this : NULL;
-}
-
-ImportExp *Expression::isImportExp()
-{
- return op == TOKimport ? (ImportExp *)this : NULL;
-}
-
-AssertExp *Expression::isAssertExp()
-{
- return op == TOKassert ? (AssertExp *)this : NULL;
-}
-
-DotIdExp *Expression::isDotIdExp()
-{
- return op == TOKdotid ? (DotIdExp *)this : NULL;
-}
-
-DotTemplateExp *Expression::isDotTemplateExp()
-{
- return op == TOKdotti ? (DotTemplateExp *)this : NULL;
-}
-
-DotVarExp *Expression::isDotVarExp()
-{
- return op == TOKdotvar ? (DotVarExp *)this : NULL;
-}
-
-DotTemplateInstanceExp *Expression::isDotTemplateInstanceExp()
-{
- return op == TOKdotti ? (DotTemplateInstanceExp *)this : NULL;
-}
-
-DelegateExp *Expression::isDelegateExp()
-{
- return op == TOKdelegate ? (DelegateExp *)this : NULL;
-}
-
-DotTypeExp *Expression::isDotTypeExp()
-{
- return op == TOKdottype ? (DotTypeExp *)this : NULL;
-}
-
-CallExp *Expression::isCallExp()
-{
- return op == TOKcall ? (CallExp *)this : NULL;
-}
-
-AddrExp *Expression::isAddrExp()
-{
- return op == TOKaddress ? (AddrExp *)this : NULL;
-}
-
-PtrExp *Expression::isPtrExp()
-{
- return op == TOKstar ? (PtrExp *)this : NULL;
-}
-
-NegExp *Expression::isNegExp()
-{
- return op == TOKneg ? (NegExp *)this : NULL;
-}
-
-UAddExp *Expression::isUAddExp()
-{
- return op == TOKuadd ? (UAddExp *)this : NULL;
-}
-
-ComExp *Expression::isComExp()
-{
- return op == TOKtilde ? (ComExp *)this : NULL;
-}
-
-NotExp *Expression::isNotExp()
-{
- return op == TOKnot ? (NotExp *)this : NULL;
-}
-
-DeleteExp *Expression::isDeleteExp()
-{
- return op == TOKdelete ? (DeleteExp *)this : NULL;
-}
-
-CastExp *Expression::isCastExp()
-{
- return op == TOKcast ? (CastExp *)this : NULL;
-}
-
-VectorExp *Expression::isVectorExp()
-{
- return op == TOKvector ? (VectorExp *)this : NULL;
-}
-
-VectorArrayExp *Expression::isVectorArrayExp()
-{
- return op == TOKvectorarray ? (VectorArrayExp *)this : NULL;
-}
-
-SliceExp *Expression::isSliceExp()
-{
- return op == TOKslice ? (SliceExp *)this : NULL;
-}
-
-ArrayLengthExp *Expression::isArrayLengthExp()
-{
- return op == TOKarraylength ? (ArrayLengthExp *)this : NULL;
-}
-
-ArrayExp *Expression::isArrayExp()
-{
- return op == TOKarray ? (ArrayExp *)this : NULL;
-}
-
-DotExp *Expression::isDotExp()
-{
- return op == TOKdot ? (DotExp *)this : NULL;
-}
-
-CommaExp *Expression::isCommaExp()
-{
- return op == TOKcomma ? (CommaExp *)this : NULL;
-}
-
-IntervalExp *Expression::isIntervalExp()
-{
- return op == TOKinterval ? (IntervalExp *)this : NULL;
-}
-
-DelegatePtrExp *Expression::isDelegatePtrExp()
-{
- return op == TOKdelegateptr ? (DelegatePtrExp *)this : NULL;
-}
-
-DelegateFuncptrExp *Expression::isDelegateFuncptrExp()
-{
- return op == TOKdelegatefuncptr ? (DelegateFuncptrExp *)this : NULL;
-}
-
-IndexExp *Expression::isIndexExp()
-{
- return op == TOKindex ? (IndexExp *)this : NULL;
-}
-
-PostExp *Expression::isPostExp()
-{
- return (op == TOKplusplus || op == TOKminusminus) ? (PostExp *)this : NULL;
-}
-
-PreExp *Expression::isPreExp()
-{
- return (op == TOKpreplusplus || op == TOKpreminusminus) ? (PreExp *)this : NULL;
-}
-
-AssignExp *Expression::isAssignExp()
-{
- return op == TOKassign ? (AssignExp *)this : NULL;
-}
-
-ConstructExp *Expression::isConstructExp()
-{
- return op == TOKconstruct ? (ConstructExp *)this : NULL;
-}
-
-BlitExp *Expression::isBlitExp()
-{
- return op == TOKblit ? (BlitExp *)this : NULL;
-}
-
-AddAssignExp *Expression::isAddAssignExp()
-{
- return op == TOKaddass ? (AddAssignExp *)this : NULL;
-}
-
-MinAssignExp *Expression::isMinAssignExp()
-{
- return op == TOKminass ? (MinAssignExp *)this : NULL;
-}
-
-MulAssignExp *Expression::isMulAssignExp()
-{
- return op == TOKmulass ? (MulAssignExp *)this : NULL;
-}
-
-
-DivAssignExp *Expression::isDivAssignExp()
-{
- return op == TOKdivass ? (DivAssignExp *)this : NULL;
-}
-
-ModAssignExp *Expression::isModAssignExp()
-{
- return op == TOKmodass ? (ModAssignExp *)this : NULL;
-}
-
-AndAssignExp *Expression::isAndAssignExp()
-{
- return op == TOKandass ? (AndAssignExp *)this : NULL;
-}
-
-OrAssignExp *Expression::isOrAssignExp()
-{
- return op == TOKorass ? (OrAssignExp *)this : NULL;
-}
-
-XorAssignExp *Expression::isXorAssignExp()
-{
- return op == TOKxorass ? (XorAssignExp *)this : NULL;
-}
-
-PowAssignExp *Expression::isPowAssignExp()
-{
- return op == TOKpowass ? (PowAssignExp *)this : NULL;
-}
-
-
-ShlAssignExp *Expression::isShlAssignExp()
-{
- return op == TOKshlass ? (ShlAssignExp *)this : NULL;
-}
-
-ShrAssignExp *Expression::isShrAssignExp()
-{
- return op == TOKshrass ? (ShrAssignExp *)this : NULL;
-}
-
-UshrAssignExp *Expression::isUshrAssignExp()
-{
- return op == TOKushrass ? (UshrAssignExp *)this : NULL;
-}
-
-CatAssignExp *Expression::isCatAssignExp()
-{
- return op == TOKcatass ? (CatAssignExp *)this : NULL;
-}
-
-AddExp *Expression::isAddExp()
-{
- return op == TOKadd ? (AddExp *)this : NULL;
-}
-
-MinExp *Expression::isMinExp()
-{
- return op == TOKmin ? (MinExp *)this : NULL;
-}
-
-CatExp *Expression::isCatExp()
-{
- return op == TOKcat ? (CatExp *)this : NULL;
-}
-
-MulExp *Expression::isMulExp()
-{
- return op == TOKmul ? (MulExp *)this : NULL;
-}
-
-DivExp *Expression::isDivExp()
-{
- return op == TOKdiv ? (DivExp *)this : NULL;
-}
-
-ModExp *Expression::isModExp()
-{
- return op == TOKmod ? (ModExp *)this : NULL;
-}
-
-PowExp *Expression::isPowExp()
-{
- return op == TOKpow ? (PowExp *)this : NULL;
-}
-
-ShlExp *Expression::isShlExp()
-{
- return op == TOKshl ? (ShlExp *)this : NULL;
-}
-
-ShrExp *Expression::isShrExp()
-{
- return op == TOKshr ? (ShrExp *)this : NULL;
-}
-
-UshrExp *Expression::isUshrExp()
-{
- return op == TOKushr ? (UshrExp *)this : NULL;
-}
-
-AndExp *Expression::isAndExp()
-{
- return op == TOKand ? (AndExp *)this : NULL;
-}
-
-OrExp *Expression::isOrExp()
-{
- return op == TOKor ? (OrExp *)this : NULL;
-}
-
-XorExp *Expression::isXorExp()
-{
- return op == TOKxor ? (XorExp *)this : NULL;
-}
-
-LogicalExp *Expression::isLogicalExp()
-{
- return (op == TOKandand || op == TOKoror) ? (LogicalExp *)this : NULL;
-}
-
-InExp *Expression::isInExp()
-{
- return op == TOKin ? (InExp *)this : NULL;
-}
-
-RemoveExp *Expression::isRemoveExp()
-{
- return op == TOKremove ? (RemoveExp *)this : NULL;
-}
-
-EqualExp *Expression::isEqualExp()
-{
- return (op == TOKequal || op == TOKnotequal) ? (EqualExp *)this : NULL;
-}
-
-IdentityExp *Expression::isIdentityExp()
-{
- return (op == TOKidentity || op == TOKnotidentity) ? (IdentityExp *)this : NULL;
-}
-
-CondExp *Expression::isCondExp()
-{
- return op == TOKquestion ? (CondExp *)this : NULL;
-}
-
-DefaultInitExp *Expression::isDefaultInitExp()
-{
- return op == TOKdefault ? (DefaultInitExp *)this : NULL;
-}
-
-FileInitExp *Expression::isFileInitExp()
-{
- return (op == TOKfile || op == TOKfilefullpath) ? (FileInitExp *)this : NULL;
-}
-
-LineInitExp *Expression::isLineInitExp()
-{
- return op == TOKline ? (LineInitExp *)this : NULL;
-}
-
-ModuleInitExp *Expression::isModuleInitExp()
-{
- return op == TOKmodulestring ? (ModuleInitExp *)this : NULL;
-}
-
-FuncInitExp *Expression::isFuncInitExp()
-{
- return op == TOKfuncstring ? (FuncInitExp *)this : NULL;
-}
-
-PrettyFuncInitExp *Expression::isPrettyFuncInitExp()
-{
- return op == TOKprettyfunc ? (PrettyFuncInitExp *)this : NULL;
-}
-
-ClassReferenceExp *Expression::isClassReferenceExp()
-{
- return op == TOKclassreference ? (ClassReferenceExp *)this : NULL;
-}
-
-
-/****************************************
- * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE__FULL_PATH__ to loc.
- */
-
-Expression *Expression::resolveLoc(Loc, Scope *)
-{
- return this;
-}
-
-Expressions *Expression::arraySyntaxCopy(Expressions *exps)
-{
- Expressions *a = NULL;
- if (exps)
- {
- a = new Expressions();
- a->setDim(exps->length);
- for (size_t i = 0; i < a->length; i++)
- {
- Expression *e = (*exps)[i];
- (*a)[i] = e ? e->syntaxCopy() : NULL;
- }
- }
- return a;
-}
-
-/************************************************
- * Destructors are attached to VarDeclarations.
- * Hence, if expression returns a temp that needs a destructor,
- * make sure and create a VarDeclaration for that temp.
- */
-
-Expression *Expression::addDtorHook(Scope *)
-{
- return this;
-}
-
-/******************************** IntegerExp **************************/
-
-IntegerExp::IntegerExp(Loc loc, dinteger_t value, Type *type)
- : Expression(loc, TOKint64, sizeof(IntegerExp))
-{
- //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : "");
- assert(type);
- if (!type->isscalar())
- {
- //printf("%s, loc = %d\n", toChars(), loc.linnum);
- if (type->ty != Terror)
- error("integral constant must be scalar type, not %s", type->toChars());
- type = Type::terror;
- }
- this->type = type;
- setInteger(value);
-}
-
-IntegerExp::IntegerExp(dinteger_t value)
- : Expression(Loc(), TOKint64, sizeof(IntegerExp))
-{
- this->type = Type::tint32;
- this->value = (d_int32) value;
-}
-
-IntegerExp *IntegerExp::create(Loc loc, dinteger_t value, Type *type)
-{
- return new IntegerExp(loc, value, type);
-}
-
-bool IntegerExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (((Expression *)o)->op == TOKint64)
- {
- IntegerExp *ne = (IntegerExp *)o;
- if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
- value == ne->value)
- {
- return true;
- }
- }
- return false;
-}
-
-void IntegerExp::setInteger(dinteger_t value)
-{
- this->value = value;
- normalize();
-}
-
-void IntegerExp::normalize()
-{
- /* 'Normalize' the value of the integer to be in range of the type
- */
- switch (type->toBasetype()->ty)
- {
- case Tbool: value = (value != 0); break;
- case Tint8: value = (d_int8) value; break;
- case Tchar:
- case Tuns8: value = (d_uns8) value; break;
- case Tint16: value = (d_int16) value; break;
- case Twchar:
- case Tuns16: value = (d_uns16) value; break;
- case Tint32: value = (d_int32) value; break;
- case Tdchar:
- case Tuns32: value = (d_uns32) value; break;
- case Tint64: value = (d_int64) value; break;
- case Tuns64: value = (d_uns64) value; break;
- case Tpointer:
- if (target.ptrsize == 8)
- value = (d_uns64) value;
- else if (target.ptrsize == 4)
- value = (d_uns32) value;
- else if (target.ptrsize == 2)
- value = (d_uns16) value;
- else
- assert(0);
- break;
- default:
- break;
- }
-}
-
-dinteger_t IntegerExp::toInteger()
-{
- normalize(); // necessary until we fix all the paints of 'type'
- return value;
-}
-
-real_t IntegerExp::toReal()
-{
- normalize(); // necessary until we fix all the paints of 'type'
- Type *t = type->toBasetype();
- if (t->ty == Tuns64)
- return ldouble((d_uns64)value);
- else
- return ldouble((d_int64)value);
-}
-
-real_t IntegerExp::toImaginary()
-{
- return CTFloat::zero;
-}
-
-complex_t IntegerExp::toComplex()
-{
- return (complex_t)toReal();
-}
-
-bool IntegerExp::isBool(bool result)
-{
- bool r = toInteger() != 0;
- return result ? r : !r;
-}
-
-Expression *IntegerExp::toLvalue(Scope *, Expression *e)
-{
- if (!e)
- e = this;
- else if (!loc.filename)
- loc = e->loc;
- e->error("constant %s is not an lvalue", e->toChars());
- return new ErrorExp();
-}
-
-/******************************** ErrorExp **************************/
-
-/* Use this expression for error recovery.
- * It should behave as a 'sink' to prevent further cascaded error messages.
- */
-
-ErrorExp::ErrorExp()
- : Expression(Loc(), TOKerror, sizeof(ErrorExp))
-{
- type = Type::terror;
-}
-
-Expression *ErrorExp::toLvalue(Scope *, Expression *)
-{
- return this;
-}
-
-/******************************** RealExp **************************/
-
-RealExp::RealExp(Loc loc, real_t value, Type *type)
- : Expression(loc, TOKfloat64, sizeof(RealExp))
-{
- //printf("RealExp::RealExp(%Lg)\n", value);
- this->value = value;
- this->type = type;
-}
-
-RealExp *RealExp::create(Loc loc, real_t value, Type *type)
-{
- return new RealExp(loc, value,type);
-}
-
-dinteger_t RealExp::toInteger()
-{
- return (sinteger_t) toReal();
-}
-
-uinteger_t RealExp::toUInteger()
-{
- return (uinteger_t) toReal();
-}
-
-real_t RealExp::toReal()
-{
- return type->isreal() ? value : CTFloat::zero;
-}
-
-real_t RealExp::toImaginary()
-{
- return type->isreal() ? CTFloat::zero : value;
-}
-
-complex_t RealExp::toComplex()
-{
- return complex_t(toReal(), toImaginary());
-}
-
-/********************************
- * Test to see if two reals are the same.
- * Regard NaN's as equivalent.
- * Regard +0 and -0 as different.
- */
-
-int RealEquals(real_t x1, real_t x2)
-{
- return (CTFloat::isNaN(x1) && CTFloat::isNaN(x2)) ||
- CTFloat::isIdentical(x1, x2);
-}
-
-bool RealExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (((Expression *)o)->op == TOKfloat64)
- {
- RealExp *ne = (RealExp *)o;
- if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
- RealEquals(value, ne->value))
- {
- return true;
- }
- }
- return false;
-}
-
-bool RealExp::isBool(bool result)
-{
- return result ? (bool)value : !(bool)value;
-}
-
-/******************************** ComplexExp **************************/
-
-ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type)
- : Expression(loc, TOKcomplex80, sizeof(ComplexExp)), value(value)
-{
- this->type = type;
- //printf("ComplexExp::ComplexExp(%s)\n", toChars());
-}
-
-ComplexExp *ComplexExp::create(Loc loc, complex_t value, Type *type)
-{
- return new ComplexExp(loc, value, type);
-}
-
-dinteger_t ComplexExp::toInteger()
-{
- return (sinteger_t) toReal();
-}
-
-uinteger_t ComplexExp::toUInteger()
-{
- return (uinteger_t) toReal();
-}
-
-real_t ComplexExp::toReal()
-{
- return creall(value);
-}
-
-real_t ComplexExp::toImaginary()
-{
- return cimagl(value);
-}
-
-complex_t ComplexExp::toComplex()
-{
- return value;
-}
-
-bool ComplexExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (((Expression *)o)->op == TOKcomplex80)
- {
- ComplexExp *ne = (ComplexExp *)o;
- if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
- RealEquals(creall(value), creall(ne->value)) &&
- RealEquals(cimagl(value), cimagl(ne->value)))
- {
- return true;
- }
- }
- return false;
-}
-
-bool ComplexExp::isBool(bool result)
-{
- if (result)
- return (bool)(value);
- else
- return !value;
-}
-
-/******************************** IdentifierExp **************************/
-
-IdentifierExp::IdentifierExp(Loc loc, Identifier *ident)
- : Expression(loc, TOKidentifier, sizeof(IdentifierExp))
-{
- this->ident = ident;
-}
-
-IdentifierExp *IdentifierExp::create(Loc loc, Identifier *ident)
-{
- return new IdentifierExp(loc, ident);
-}
-
-bool IdentifierExp::isLvalue()
-{
- return true;
-}
-
-Expression *IdentifierExp::toLvalue(Scope *, Expression *)
-{
- return this;
-}
-
-/******************************** DollarExp **************************/
-
-DollarExp::DollarExp(Loc loc)
- : IdentifierExp(loc, Id::dollar)
-{
-}
-
-/******************************** DsymbolExp **************************/
-
-DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s, bool hasOverloads)
- : Expression(loc, TOKdsymbol, sizeof(DsymbolExp))
-{
- this->s = s;
- this->hasOverloads = hasOverloads;
-}
-
-/****************************************
- * Resolve a symbol `s` and wraps it in an expression object.
- * Params:
- * hasOverloads = works if the aliased symbol is a function.
- * true: it's overloaded and will be resolved later.
- * false: it's exact function symbol.
- */
-Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads)
-{
-Lagain:
- Expression *e;
-
- //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
- //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind());
- Dsymbol *olds = s;
- Declaration *d = s->isDeclaration();
- if (d && (d->storage_class & STCtemplateparameter))
- {
- s = s->toAlias();
- }
- else
- {
- if (!s->isFuncDeclaration()) // functions are checked after overloading
- {
- s->checkDeprecated(loc, sc);
- if (d)
- d->checkDisabled(loc, sc);
- }
-
- // Bugzilla 12023: if 's' is a tuple variable, the tuple is returned.
- s = s->toAlias();
-
- //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis());
- if (s != olds && !s->isFuncDeclaration())
- {
- s->checkDeprecated(loc, sc);
- if (d)
- d->checkDisabled(loc, sc);
- }
- }
-
- if (EnumMember *em = s->isEnumMember())
- {
- return em->getVarExp(loc, sc);
- }
- if (VarDeclaration *v = s->isVarDeclaration())
- {
- //printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars());
- if (!v->type || // during variable type inference
- (!v->type->deco && v->inuse)) // during variable type semantic
- {
- if (v->inuse) // variable type depends on the variable itself
- ::error(loc, "circular reference to %s `%s`", v->kind(), v->toPrettyChars());
- else // variable type cannot be determined
- ::error(loc, "forward reference to %s `%s`", v->kind(), v->toPrettyChars());
- return new ErrorExp();
- }
- if (v->type->ty == Terror)
- return new ErrorExp();
-
- if ((v->storage_class & STCmanifest) && v->_init)
- {
- if (v->inuse)
- {
- ::error(loc, "circular initialization of %s `%s`", v->kind(), v->toPrettyChars());
- return new ErrorExp();
- }
-
- e = v->expandInitializer(loc);
- v->inuse++;
- e = expressionSemantic(e, sc);
- v->inuse--;
- return e;
- }
-
- // Change the ancestor lambdas to delegate before hasThis(sc) call.
- if (v->checkNestedReference(sc, loc))
- return new ErrorExp();
-
- if (v->needThis() && hasThis(sc))
- e = new DotVarExp(loc, new ThisExp(loc), v);
- else
- e = new VarExp(loc, v);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
- {
- //printf("'%s' is a function literal\n", fld->toChars());
- e = new FuncExp(loc, fld);
- return expressionSemantic(e, sc);
- }
- if (FuncDeclaration *f = s->isFuncDeclaration())
- {
- f = f->toAliasFunc();
- if (!f->functionSemantic())
- return new ErrorExp();
-
- if (!hasOverloads && f->checkForwardRef(loc))
- return new ErrorExp();
-
- FuncDeclaration *fd = s->isFuncDeclaration();
- fd->type = f->type;
- return new VarExp(loc, fd, hasOverloads);
- }
- if (OverDeclaration *od = s->isOverDeclaration())
- {
- e = new VarExp(loc, od, true);
- e->type = Type::tvoid;
- return e;
- }
- if (OverloadSet *o = s->isOverloadSet())
- {
- //printf("'%s' is an overload set\n", o->toChars());
- return new OverExp(loc, o);
- }
-
- if (Import *imp = s->isImport())
- {
- if (!imp->pkg)
- {
- ::error(loc, "forward reference of import %s", imp->toChars());
- return new ErrorExp();
- }
- ScopeExp *ie = new ScopeExp(loc, imp->pkg);
- return expressionSemantic(ie, sc);
- }
- if (Package *pkg = s->isPackage())
- {
- ScopeExp *ie = new ScopeExp(loc, pkg);
- return expressionSemantic(ie, sc);
- }
- if (Module *mod = s->isModule())
- {
- ScopeExp *ie = new ScopeExp(loc, mod);
- return expressionSemantic(ie, sc);
- }
-
- if (Nspace *ns = s->isNspace())
- {
- ScopeExp *ie = new ScopeExp(loc, ns);
- return expressionSemantic(ie, sc);
- }
-
- if (Type *t = s->getType())
- {
- return expressionSemantic(new TypeExp(loc, t), sc);
- }
-
- if (TupleDeclaration *tup = s->isTupleDeclaration())
- {
- if (tup->needThis() && hasThis(sc))
- e = new DotVarExp(loc, new ThisExp(loc), tup);
- else
- e = new TupleExp(loc, tup);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- if (TemplateInstance *ti = s->isTemplateInstance())
- {
- dsymbolSemantic(ti, sc);
- if (!ti->inst || ti->errors)
- return new ErrorExp();
- s = ti->toAlias();
- if (!s->isTemplateInstance())
- goto Lagain;
- e = new ScopeExp(loc, ti);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (TemplateDeclaration *td = s->isTemplateDeclaration())
- {
- Dsymbol *p = td->toParent2();
- FuncDeclaration *fdthis = hasThis(sc);
- AggregateDeclaration *ad = p ? p->isAggregateDeclaration() : NULL;
- if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad &&
- (td->_scope->stc & STCstatic) == 0)
- {
- e = new DotTemplateExp(loc, new ThisExp(loc), td);
- }
- else
- e = new TemplateExp(loc, td);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- ::error(loc, "%s `%s` is not a variable", s->kind(), s->toChars());
- return new ErrorExp();
-}
-
-bool DsymbolExp::isLvalue()
-{
- return true;
-}
-
-Expression *DsymbolExp::toLvalue(Scope *, Expression *)
-{
- return this;
-}
-
-/******************************** ThisExp **************************/
-
-ThisExp::ThisExp(Loc loc)
- : Expression(loc, TOKthis, sizeof(ThisExp))
-{
- //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
- var = NULL;
-}
-
-bool ThisExp::isBool(bool result)
-{
- return result ? true : false;
-}
-
-bool ThisExp::isLvalue()
-{
- // Class `this` should be an rvalue; struct `this` should be an lvalue.
- return type->toBasetype()->ty != Tclass;
-}
-
-Expression *ThisExp::toLvalue(Scope *sc, Expression *e)
-{
- if (type->toBasetype()->ty == Tclass)
- {
- // Class `this` is an rvalue; struct `this` is an lvalue.
- return Expression::toLvalue(sc, e);
- }
- return this;
-}
-
-/******************************** SuperExp **************************/
-
-SuperExp::SuperExp(Loc loc)
- : ThisExp(loc)
-{
- op = TOKsuper;
-}
-
-/******************************** NullExp **************************/
-
-NullExp::NullExp(Loc loc, Type *type)
- : Expression(loc, TOKnull, sizeof(NullExp))
-{
- committed = 0;
- this->type = type;
-}
-
-bool NullExp::equals(RootObject *o)
-{
- if (o && o->dyncast() == DYNCAST_EXPRESSION)
- {
- Expression *e = (Expression *)o;
- if (e->op == TOKnull &&
- type->equals(e->type))
- {
- return true;
- }
- }
- return false;
-}
-
-bool NullExp::isBool(bool result)
-{
- return result ? false : true;
-}
-
-StringExp *NullExp::toStringExp()
-{
- if (implicitConvTo(Type::tstring))
- {
- StringExp *se = new StringExp(loc, (char*)mem.xcalloc(1, 1), 0);
- se->type = Type::tstring;
- return se;
- }
- return NULL;
-}
-
-/******************************** StringExp **************************/
-
-StringExp::StringExp(Loc loc, char *string)
- : Expression(loc, TOKstring, sizeof(StringExp))
-{
- this->string = string;
- this->len = strlen(string);
- this->sz = 1;
- this->committed = 0;
- this->postfix = 0;
- this->ownedByCtfe = OWNEDcode;
-}
-
-StringExp::StringExp(Loc loc, void *string, size_t len)
- : Expression(loc, TOKstring, sizeof(StringExp))
-{
- this->string = string;
- this->len = len;
- this->sz = 1;
- this->committed = 0;
- this->postfix = 0;
- this->ownedByCtfe = OWNEDcode;
-}
-
-StringExp::StringExp(Loc loc, void *string, size_t len, utf8_t postfix)
- : Expression(loc, TOKstring, sizeof(StringExp))
-{
- this->string = string;
- this->len = len;
- this->sz = 1;
- this->committed = 0;
- this->postfix = postfix;
- this->ownedByCtfe = OWNEDcode;
-}
-
-StringExp *StringExp::create(Loc loc, char *s)
-{
- return new StringExp(loc, s);
-}
-
-StringExp *StringExp::create(Loc loc, void *string, size_t len)
-{
- return new StringExp(loc, string, len);
-}
-
-bool StringExp::equals(RootObject *o)
-{
- //printf("StringExp::equals('%s') %s\n", o->toChars(), toChars());
- if (o && o->dyncast() == DYNCAST_EXPRESSION)
- {
- Expression *e = (Expression *)o;
- if (e->op == TOKstring)
- {
- return compare(o) == 0;
- }
- }
- return false;
-}
-
-/**********************************
- * Return the number of code units the string would be if it were re-encoded
- * as tynto.
- * Params:
- * tynto = code unit type of the target encoding
- * Returns:
- * number of code units
- */
-
-size_t StringExp::numberOfCodeUnits(int tynto) const
-{
- int encSize;
- switch (tynto)
- {
- case 0: return len;
- case Tchar: encSize = 1; break;
- case Twchar: encSize = 2; break;
- case Tdchar: encSize = 4; break;
- default:
- assert(0);
- }
- if (sz == encSize)
- return len;
-
- size_t result = 0;
- dchar_t c;
-
- switch (sz)
- {
- case 1:
- for (size_t u = 0; u < len;)
- {
- if (const char *p = utf_decodeChar((utf8_t *)string, len, &u, &c))
- {
- error("%s", p);
- return 0;
- }
- result += utf_codeLength(encSize, c);
- }
- break;
-
- case 2:
- for (size_t u = 0; u < len;)
- {
- if (const char *p = utf_decodeWchar((utf16_t *)string, len, &u, &c))
- {
- error("%s", p);
- return 0;
- }
- result += utf_codeLength(encSize, c);
- }
- break;
-
- case 4:
- for (size_t u = 0; u < len;)
- {
- c = *((utf32_t *)((char *)string + u));
- u += 4;
- result += utf_codeLength(encSize, c);
- }
- break;
-
- default:
- assert(0);
- }
- return result;
-}
-
-/**********************************************
- * Write the contents of the string to dest.
- * Use numberOfCodeUnits() to determine size of result.
- * Params:
- * dest = destination
- * tyto = encoding type of the result
- * zero = add terminating 0
- */
-void StringExp::writeTo(void *dest, bool zero, int tyto) const
-{
- int encSize;
- switch (tyto)
- {
- case 0: encSize = sz; break;
- case Tchar: encSize = 1; break;
- case Twchar: encSize = 2; break;
- case Tdchar: encSize = 4; break;
- default:
- assert(0);
- }
- if (sz == encSize)
- {
- memcpy(dest, string, len * sz);
- if (zero)
- memset((char *)dest + len * sz, 0, sz);
- }
- else
- assert(0);
-}
-
-/**************************************************
- * If the string data is UTF-8 and can be accessed directly,
- * return a pointer to it.
- * Do not assume a terminating 0.
- * Returns:
- * pointer to string data if possible, null if not
- */
-char *StringExp::toPtr()
-{
- return (sz == 1) ? (char*)string : NULL;
-}
-
-StringExp *StringExp::toStringExp()
-{
- return this;
-}
-
-/****************************************
- * Convert string to char[].
- */
-
-StringExp *StringExp::toUTF8(Scope *sc)
-{
- if (sz != 1)
- { // Convert to UTF-8 string
- committed = 0;
- Expression *e = castTo(sc, Type::tchar->arrayOf());
- e = e->optimize(WANTvalue);
- assert(e->op == TOKstring);
- StringExp *se = (StringExp *)e;
- assert(se->sz == 1);
- return se;
- }
- return this;
-}
-
-int StringExp::compare(RootObject *obj)
-{
- //printf("StringExp::compare()\n");
- // Used to sort case statement expressions so we can do an efficient lookup
- StringExp *se2 = (StringExp *)(obj);
-
- // This is a kludge so isExpression() in template.c will return 5
- // for StringExp's.
- if (!se2)
- return 5;
-
- assert(se2->op == TOKstring);
-
- size_t len1 = len;
- size_t len2 = se2->len;
-
- //printf("sz = %d, len1 = %d, len2 = %d\n", sz, (int)len1, (int)len2);
- if (len1 == len2)
- {
- switch (sz)
- {
- case 1:
- return memcmp((char *)string, (char *)se2->string, len1);
-
- case 2:
- {
- d_uns16 *s1 = (d_uns16 *)string;
- d_uns16 *s2 = (d_uns16 *)se2->string;
-
- for (size_t u = 0; u < len; u++)
- {
- if (s1[u] != s2[u])
- return s1[u] - s2[u];
- }
- }
- break;
-
- case 4:
- {
- d_uns32 *s1 = (d_uns32 *)string;
- d_uns32 *s2 = (d_uns32 *)se2->string;
-
- for (size_t u = 0; u < len; u++)
- {
- if (s1[u] != s2[u])
- return s1[u] - s2[u];
- }
- }
- break;
-
- default:
- assert(0);
- }
- }
- return (int)(len1 - len2);
-}
-
-bool StringExp::isBool(bool result)
-{
- return result ? true : false;
-}
-
-
-bool StringExp::isLvalue()
-{
- /* string literal is rvalue in default, but
- * conversion to reference of static array is only allowed.
- */
- return (type && type->toBasetype()->ty == Tsarray);
-}
-
-Expression *StringExp::toLvalue(Scope *sc, Expression *e)
-{
- //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type->toChars() : NULL);
- return (type && type->toBasetype()->ty == Tsarray)
- ? this : Expression::toLvalue(sc, e);
-}
-
-Expression *StringExp::modifiableLvalue(Scope *, Expression *)
-{
- error("cannot modify string literal %s", toChars());
- return new ErrorExp();
-}
-
-unsigned StringExp::charAt(uinteger_t i) const
-{ unsigned value;
-
- switch (sz)
- {
- case 1:
- value = ((utf8_t *)string)[(size_t)i];
- break;
-
- case 2:
- value = ((unsigned short *)string)[(size_t)i];
- break;
-
- case 4:
- value = ((unsigned int *)string)[(size_t)i];
- break;
-
- default:
- assert(0);
- break;
- }
- return value;
-}
-
-/************************ ArrayLiteralExp ************************************/
-
-// [ e1, e2, e3, ... ]
-
-ArrayLiteralExp::ArrayLiteralExp(Loc loc, Type *type, Expressions *elements)
- : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
-{
- this->basis = NULL;
- this->type = type;
- this->elements = elements;
- this->ownedByCtfe = OWNEDcode;
-}
-
-ArrayLiteralExp::ArrayLiteralExp(Loc loc, Type *type, Expression *e)
- : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
-{
- this->basis = NULL;
- this->type = type;
- elements = new Expressions;
- elements->push(e);
- this->ownedByCtfe = OWNEDcode;
-}
-
-ArrayLiteralExp::ArrayLiteralExp(Loc loc, Type *type, Expression *basis, Expressions *elements)
- : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
-{
- this->basis = basis;
- this->type = type;
- this->elements = elements;
- this->ownedByCtfe = OWNEDcode;
-}
-
-ArrayLiteralExp *ArrayLiteralExp::create(Loc loc, Expressions *elements)
-{
- return new ArrayLiteralExp(loc, NULL, elements);
-}
-
-bool ArrayLiteralExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (o && o->dyncast() == DYNCAST_EXPRESSION &&
- ((Expression *)o)->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ae = (ArrayLiteralExp *)o;
- if (elements->length != ae->elements->length)
- return false;
- if (elements->length == 0 &&
- !type->equals(ae->type))
- {
- return false;
- }
- for (size_t i = 0; i < elements->length; i++)
- {
- Expression *e1 = (*elements)[i];
- Expression *e2 = (*ae->elements)[i];
- if (!e1)
- e1 = basis;
- if (!e2)
- e2 = basis;
- if (e1 != e2 &&
- (!e1 || !e2 || !e1->equals(e2)))
- return false;
- }
- return true;
- }
- return false;
-}
-
-Expression *ArrayLiteralExp::syntaxCopy()
-{
- return new ArrayLiteralExp(loc,
- NULL,
- basis ? basis->syntaxCopy() : NULL,
- arraySyntaxCopy(elements));
-}
-
-Expression *ArrayLiteralExp::getElement(size_t i)
-{
- Expression *el = (*elements)[i];
- if (!el)
- el = basis;
- return el;
-}
-
-static void appendArrayLiteral(Expressions *elems, ArrayLiteralExp *ale)
-{
- if (!ale->elements)
- return;
- size_t d = elems->length;
- elems->append(ale->elements);
- for (size_t i = d; i < elems->length; i++)
- {
- Expression *el = (*elems)[i];
- if (!el)
- (*elems)[i] = ale->basis;
- }
-}
-
-/* Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s.
- * Params:
- * e1 = If it's ArrayLiteralExp, its `elements` will be copied.
- * Otherwise, `e1` itself will be pushed into the new `Expressions`.
- * e2 = If it's not `null`, it will be pushed/appended to the new
- * `Expressions` by the same way with `e1`.
- * Returns:
- * Newly allocated `Expressions`. Note that it points to the original
- * `Expression` values in e1 and e2.
- */
-Expressions* ArrayLiteralExp::copyElements(Expression *e1, Expression *e2)
-{
- Expressions *elems = new Expressions();
-
- if (e1->op == TOKarrayliteral)
- appendArrayLiteral(elems, (ArrayLiteralExp *)e1);
- else
- elems->push(e1);
-
- if (e2)
- {
- if (e2->op == TOKarrayliteral)
- appendArrayLiteral(elems, (ArrayLiteralExp *)e2);
- else
- elems->push(e2);
- }
-
- return elems;
-}
-
-bool ArrayLiteralExp::isBool(bool result)
-{
- size_t dim = elements ? elements->length : 0;
- return result ? (dim != 0) : (dim == 0);
-}
-
-StringExp *ArrayLiteralExp::toStringExp()
-{
- TY telem = type->nextOf()->toBasetype()->ty;
-
- if (telem == Tchar || telem == Twchar || telem == Tdchar ||
- (telem == Tvoid && (!elements || elements->length == 0)))
- {
- unsigned char sz = 1;
- if (telem == Twchar) sz = 2;
- else if (telem == Tdchar) sz = 4;
-
- OutBuffer buf;
- if (elements)
- {
- for (size_t i = 0; i < elements->length; ++i)
- {
- Expression *ch = getElement(i);
- if (ch->op != TOKint64)
- return NULL;
- if (sz == 1)
- buf.writeByte((unsigned)ch->toInteger());
- else if (sz == 2)
- buf.writeword((unsigned)ch->toInteger());
- else
- buf.write4((unsigned)ch->toInteger());
- }
- }
- char prefix;
- if (sz == 1) { prefix = 'c'; buf.writeByte(0); }
- else if (sz == 2) { prefix = 'w'; buf.writeword(0); }
- else { prefix = 'd'; buf.write4(0); }
-
- const size_t len = buf.length() / sz - 1;
- StringExp *se = new StringExp(loc, buf.extractData(), len, prefix);
- se->sz = sz;
- se->type = type;
- return se;
- }
- return NULL;
-}
-
-/************************ AssocArrayLiteralExp ************************************/
-
-// [ key0 : value0, key1 : value1, ... ]
-
-AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc,
- Expressions *keys, Expressions *values)
- : Expression(loc, TOKassocarrayliteral, sizeof(AssocArrayLiteralExp))
-{
- assert(keys->length == values->length);
- this->keys = keys;
- this->values = values;
- this->ownedByCtfe = OWNEDcode;
-}
-
-bool AssocArrayLiteralExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (o && o->dyncast() == DYNCAST_EXPRESSION &&
- ((Expression *)o)->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)o;
- if (keys->length != ae->keys->length)
- return false;
- size_t count = 0;
- for (size_t i = 0; i < keys->length; i++)
- {
- for (size_t j = 0; j < ae->keys->length; j++)
- {
- if ((*keys)[i]->equals((*ae->keys)[j]))
- {
- if (!(*values)[i]->equals((*ae->values)[j]))
- return false;
- ++count;
- }
- }
- }
- return count == keys->length;
- }
- return false;
-}
-
-Expression *AssocArrayLiteralExp::syntaxCopy()
-{
- return new AssocArrayLiteralExp(loc,
- arraySyntaxCopy(keys), arraySyntaxCopy(values));
-}
-
-bool AssocArrayLiteralExp::isBool(bool result)
-{
- size_t dim = keys->length;
- return result ? (dim != 0) : (dim == 0);
-}
-
-/************************ StructLiteralExp ************************************/
-
-// sd( e1, e2, e3, ... )
-
-StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype)
- : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp))
-{
- this->sd = sd;
- if (!elements)
- elements = new Expressions();
- this->elements = elements;
- this->stype = stype;
- this->useStaticInit = false;
- this->sym = NULL;
- this->ownedByCtfe = OWNEDcode;
- this->origin = this;
- this->stageflags = 0;
- this->inlinecopy = NULL;
- //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
-}
-
-StructLiteralExp *StructLiteralExp::create(Loc loc, StructDeclaration *sd, void *elements, Type *stype)
-{
- return new StructLiteralExp(loc, sd, (Expressions *)elements, stype);
-}
-
-bool StructLiteralExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (o && o->dyncast() == DYNCAST_EXPRESSION &&
- ((Expression *)o)->op == TOKstructliteral)
- {
- StructLiteralExp *se = (StructLiteralExp *)o;
- if (!type->equals(se->type))
- return false;
- if (elements->length != se->elements->length)
- return false;
- for (size_t i = 0; i < elements->length; i++)
- {
- Expression *e1 = (*elements)[i];
- Expression *e2 = (*se->elements)[i];
- if (e1 != e2 &&
- (!e1 || !e2 || !e1->equals(e2)))
- return false;
- }
- return true;
- }
- return false;
-}
-
-Expression *StructLiteralExp::syntaxCopy()
-{
- StructLiteralExp *exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
- exp->origin = this;
- return exp;
-}
-
-Expression *StructLiteralExp::addDtorHook(Scope *sc)
-{
- /* If struct requires a destructor, rewrite as:
- * (S tmp = S()),tmp
- * so that the destructor can be hung on tmp.
- */
- if (sd->dtor && sc->func)
- {
- /* Make an identifier for the temporary of the form:
- * __sl%s%d, where %s is the struct name
- */
- const size_t len = 10;
- char buf[len + 1];
- buf[len] = 0;
- strcpy(buf, "__sl");
- strncat(buf, sd->ident->toChars(), len - 4 - 1);
- assert(buf[len] == 0);
-
- VarDeclaration *tmp = copyToTemp(0, buf, this);
- Expression *ae = new DeclarationExp(loc, tmp);
- Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp));
- e = expressionSemantic(e, sc);
- return e;
- }
- return this;
-}
-
-/**************************************
- * Gets expression at offset of type.
- * Returns NULL if not found.
- */
-
-Expression *StructLiteralExp::getField(Type *type, unsigned offset)
-{
- //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
- // /*toChars()*/"", type->toChars(), offset);
- Expression *e = NULL;
- int i = getFieldIndex(type, offset);
-
- if (i != -1)
- {
- //printf("\ti = %d\n", i);
- if (i == (int)sd->fields.length - 1 && sd->isNested())
- return NULL;
-
- assert(i < (int)elements->length);
- e = (*elements)[i];
- if (e)
- {
- //printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars());
-
- /* If type is a static array, and e is an initializer for that array,
- * then the field initializer should be an array literal of e.
- */
- if (e->type->castMod(0) != type->castMod(0) && type->ty == Tsarray)
- { TypeSArray *tsa = (TypeSArray *)type;
- size_t length = (size_t)tsa->dim->toInteger();
- Expressions *z = new Expressions;
- z->setDim(length);
- for (size_t q = 0; q < length; ++q)
- (*z)[q] = e->copy();
- e = new ArrayLiteralExp(loc, type, z);
- }
- else
- {
- e = e->copy();
- e->type = type;
- }
- if (useStaticInit && e->op == TOKstructliteral &&
- e->type->needsNested())
- {
- StructLiteralExp *se = (StructLiteralExp *)e;
- se->useStaticInit = true;
- }
- }
- }
- return e;
-}
-
-/************************************
- * Get index of field.
- * Returns -1 if not found.
- */
-
-int StructLiteralExp::getFieldIndex(Type *type, unsigned offset)
-{
- /* Find which field offset is by looking at the field offsets
- */
- if (elements->length)
- {
- for (size_t i = 0; i < sd->fields.length; i++)
- {
- VarDeclaration *v = sd->fields[i];
-
- if (offset == v->offset &&
- type->size() == v->type->size())
- {
- /* context field might not be filled. */
- if (i == sd->fields.length - 1 && sd->isNested())
- return (int)i;
- Expression *e = (*elements)[i];
- if (e)
- {
- return (int)i;
- }
- break;
- }
- }
- }
- return -1;
-}
-
-/************************ TypeDotIdExp ************************************/
-
-/* Things like:
- * int.size
- * foo.size
- * (foo).size
- * cast(foo).size
- */
-
-DotIdExp *typeDotIdExp(Loc loc, Type *type, Identifier *ident)
-{
- return new DotIdExp(loc, new TypeExp(loc, type), ident);
-}
-
-
-/************************************************************/
-
-// Mainly just a placeholder
-
-TypeExp::TypeExp(Loc loc, Type *type)
- : Expression(loc, TOKtype, sizeof(TypeExp))
-{
- //printf("TypeExp::TypeExp(%s)\n", type->toChars());
- this->type = type;
-}
-
-Expression *TypeExp::syntaxCopy()
-{
- return new TypeExp(loc, type->syntaxCopy());
-}
-
-bool TypeExp::checkType()
-{
- error("type %s is not an expression", toChars());
- return true;
-}
-
-bool TypeExp::checkValue()
-{
- error("type %s has no value", toChars());
- return true;
-}
-
-/************************************************************/
-
-/***********************************************************
- * Mainly just a placeholder of
- * Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
- *
- * A template instance that requires IFTI:
- * foo!tiargs(fargs) // foo!tiargs
- * is left until CallExp::semantic() or resolveProperties()
- */
-ScopeExp::ScopeExp(Loc loc, ScopeDsymbol *sds)
- : Expression(loc, TOKscope, sizeof(ScopeExp))
-{
- //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds->toChars());
- //static int count; if (++count == 38) *(char*)0=0;
- this->sds = sds;
- assert(!sds->isTemplateDeclaration()); // instead, you should use TemplateExp
-}
-
-Expression *ScopeExp::syntaxCopy()
-{
- return new ScopeExp(loc, (ScopeDsymbol *)sds->syntaxCopy(NULL));
-}
-
-bool ScopeExp::checkType()
-{
- if (sds->isPackage())
- {
- error("%s %s has no type", sds->kind(), sds->toChars());
- return true;
- }
- if (TemplateInstance *ti = sds->isTemplateInstance())
- {
- //assert(ti->needsTypeInference(sc));
- if (ti->tempdecl &&
- ti->semantictiargsdone &&
- ti->semanticRun == PASSinit)
- {
- error("partial %s %s has no type", sds->kind(), toChars());
- return true;
- }
- }
- return false;
-}
-
-bool ScopeExp::checkValue()
-{
- error("%s %s has no value", sds->kind(), sds->toChars());
- return true;
-}
-
-/********************** TemplateExp **************************************/
-
-// Mainly just a placeholder
-
-TemplateExp::TemplateExp(Loc loc, TemplateDeclaration *td, FuncDeclaration *fd)
- : Expression(loc, TOKtemplate, sizeof(TemplateExp))
-{
- //printf("TemplateExp(): %s\n", td->toChars());
- this->td = td;
- this->fd = fd;
-}
-
-bool TemplateExp::checkType()
-{
- error("%s %s has no type", td->kind(), toChars());
- return true;
-}
-
-bool TemplateExp::checkValue()
-{
- error("%s %s has no value", td->kind(), toChars());
- return true;
-}
-
-bool TemplateExp::isLvalue()
-{
- return fd != NULL;
-}
-
-Expression *TemplateExp::toLvalue(Scope *sc, Expression *e)
-{
- if (!fd)
- return Expression::toLvalue(sc, e);
-
- assert(sc);
- return resolve(loc, sc, fd, true);
-}
-
-/********************** NewExp **************************************/
-
-/* thisexp.new(newargs) newtype(arguments) */
-
-NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs,
- Type *newtype, Expressions *arguments)
- : Expression(loc, TOKnew, sizeof(NewExp))
-{
- this->thisexp = thisexp;
- this->newargs = newargs;
- this->newtype = newtype;
- this->arguments = arguments;
- argprefix = NULL;
- member = NULL;
- allocator = NULL;
- onstack = 0;
-}
-
-NewExp *NewExp::create(Loc loc, Expression *thisexp, Expressions *newargs,
- Type *newtype, Expressions *arguments)
-{
- return new NewExp(loc, thisexp, newargs, newtype, arguments);
-}
-
-Expression *NewExp::syntaxCopy()
-{
- return new NewExp(loc,
- thisexp ? thisexp->syntaxCopy() : NULL,
- arraySyntaxCopy(newargs),
- newtype->syntaxCopy(), arraySyntaxCopy(arguments));
-}
-
-/********************** NewAnonClassExp **************************************/
-
-NewAnonClassExp::NewAnonClassExp(Loc loc, Expression *thisexp,
- Expressions *newargs, ClassDeclaration *cd, Expressions *arguments)
- : Expression(loc, TOKnewanonclass, sizeof(NewAnonClassExp))
-{
- this->thisexp = thisexp;
- this->newargs = newargs;
- this->cd = cd;
- this->arguments = arguments;
-}
-
-Expression *NewAnonClassExp::syntaxCopy()
-{
- return new NewAnonClassExp(loc,
- thisexp ? thisexp->syntaxCopy() : NULL,
- arraySyntaxCopy(newargs),
- (ClassDeclaration *)cd->syntaxCopy(NULL),
- arraySyntaxCopy(arguments));
-}
-
-/********************** SymbolExp **************************************/
-
-SymbolExp::SymbolExp(Loc loc, TOK op, int size, Declaration *var, bool hasOverloads)
- : Expression(loc, op, size)
-{
- assert(var);
- this->var = var;
- this->hasOverloads = hasOverloads;
-}
-
-/********************** SymOffExp **************************************/
-
-SymOffExp::SymOffExp(Loc loc, Declaration *var, dinteger_t offset, bool hasOverloads)
- : SymbolExp(loc, TOKsymoff, sizeof(SymOffExp), var,
- var->isVarDeclaration() ? false : hasOverloads)
-{
- if (VarDeclaration *v = var->isVarDeclaration())
- {
- // FIXME: This error report will never be handled anyone.
- // It should be done before the SymOffExp construction.
- if (v->needThis())
- ::error(loc, "need `this` for address of %s", v->toChars());
- }
- this->offset = offset;
-}
-
-bool SymOffExp::isBool(bool result)
-{
- return result ? true : false;
-}
-
-/******************************** VarExp **************************/
-
-VarExp::VarExp(Loc loc, Declaration *var, bool hasOverloads)
- : SymbolExp(loc, TOKvar, sizeof(VarExp), var,
- var->isVarDeclaration() ? false : hasOverloads)
-{
- //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var->toChars(), loc.toChars());
- //if (strcmp(var->ident->toChars(), "func") == 0) halt();
- this->type = var->type;
-}
-
-VarExp *VarExp::create(Loc loc, Declaration *var, bool hasOverloads)
-{
- return new VarExp(loc, var, hasOverloads);
-}
-
-bool VarExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (((Expression *)o)->op == TOKvar)
- {
- VarExp *ne = (VarExp *)o;
- if (type->toHeadMutable()->equals(ne->type->toHeadMutable()) &&
- var == ne->var)
- {
- return true;
- }
- }
- return false;
-}
-
-bool VarExp::isLvalue()
-{
- if (var->storage_class & (STClazy | STCrvalue | STCmanifest))
- return false;
- return true;
-}
-
-Expression *VarExp::toLvalue(Scope *, Expression *)
-{
- if (var->storage_class & STCmanifest)
- {
- error("manifest constant `%s` is not lvalue", var->toChars());
- return new ErrorExp();
- }
- if (var->storage_class & STClazy)
- {
- error("lazy variables cannot be lvalues");
- return new ErrorExp();
- }
- if (var->ident == Id::ctfe)
- {
- error("compiler-generated variable __ctfe is not an lvalue");
- return new ErrorExp();
- }
- if (var->ident == Id::dollar) // Bugzilla 13574
- {
- error("`$` is not an lvalue");
- return new ErrorExp();
- }
- return this;
-}
-
-int VarExp::checkModifiable(Scope *sc, int flag)
-{
- //printf("VarExp::checkModifiable %s", toChars());
- assert(type);
- return var->checkModify(loc, sc, type, NULL, flag);
-}
-
-Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- //printf("VarExp::modifiableLvalue('%s')\n", var->toChars());
- if (var->storage_class & STCmanifest)
- {
- error("cannot modify manifest constant `%s`", toChars());
- return new ErrorExp();
- }
- // See if this expression is a modifiable lvalue (i.e. not const)
- return Expression::modifiableLvalue(sc, e);
-}
-
-
-/******************************** OverExp **************************/
-
-OverExp::OverExp(Loc loc, OverloadSet *s)
- : Expression(loc, TOKoverloadset, sizeof(OverExp))
-{
- //printf("OverExp(this = %p, '%s')\n", this, var->toChars());
- vars = s;
- type = Type::tvoid;
-}
-
-bool OverExp::isLvalue()
-{
- return true;
-}
-
-Expression *OverExp::toLvalue(Scope *, Expression *)
-{
- return this;
-}
-
-/******************************** TupleExp **************************/
-
-TupleExp::TupleExp(Loc loc, Expression *e0, Expressions *exps)
- : Expression(loc, TOKtuple, sizeof(TupleExp))
-{
- //printf("TupleExp(this = %p)\n", this);
- this->e0 = e0;
- this->exps = exps;
-}
-
-TupleExp::TupleExp(Loc loc, Expressions *exps)
- : Expression(loc, TOKtuple, sizeof(TupleExp))
-{
- //printf("TupleExp(this = %p)\n", this);
- this->e0 = NULL;
- this->exps = exps;
-}
-
-TupleExp::TupleExp(Loc loc, TupleDeclaration *tup)
- : Expression(loc, TOKtuple, sizeof(TupleExp))
-{
- this->e0 = NULL;
- this->exps = new Expressions();
-
- this->exps->reserve(tup->objects->length);
- for (size_t i = 0; i < tup->objects->length; i++)
- { RootObject *o = (*tup->objects)[i];
- if (Dsymbol *s = getDsymbol(o))
- {
- /* If tuple element represents a symbol, translate to DsymbolExp
- * to supply implicit 'this' if needed later.
- */
- Expression *e = new DsymbolExp(loc, s);
- this->exps->push(e);
- }
- else if (o->dyncast() == DYNCAST_EXPRESSION)
- {
- Expression *e = ((Expression *)o)->copy();
- e->loc = loc; // Bugzilla 15669
- this->exps->push(e);
- }
- else if (o->dyncast() == DYNCAST_TYPE)
- {
- Type *t = (Type *)o;
- Expression *e = new TypeExp(loc, t);
- this->exps->push(e);
- }
- else
- {
- error("%s is not an expression", o->toChars());
- }
- }
-}
-
-bool TupleExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (((Expression *)o)->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)o;
- if (exps->length != te->exps->length)
- return false;
- if ((e0 && !e0->equals(te->e0)) || (!e0 && te->e0))
- return false;
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e1 = (*exps)[i];
- Expression *e2 = (*te->exps)[i];
- if (!e1->equals(e2))
- return false;
- }
- return true;
- }
- return false;
-}
-
-Expression *TupleExp::syntaxCopy()
-{
- return new TupleExp(loc, e0 ? e0->syntaxCopy() : NULL, arraySyntaxCopy(exps));
-}
-
-TupleExp *TupleExp::toTupleExp()
-{
- return this;
-}
-
-/******************************** FuncExp *********************************/
-
-FuncExp::FuncExp(Loc loc, Dsymbol *s)
- : Expression(loc, TOKfunction, sizeof(FuncExp))
-{
- this->td = s->isTemplateDeclaration();
- this->fd = s->isFuncLiteralDeclaration();
- if (td)
- {
- assert(td->literal);
- assert(td->members && td->members->length == 1);
- fd = (*td->members)[0]->isFuncLiteralDeclaration();
- }
- tok = fd->tok; // save original kind of function/delegate/(infer)
- assert(fd->fbody);
-}
-
-bool FuncExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (o->dyncast() != DYNCAST_EXPRESSION)
- return false;
- if (((Expression *)o)->op == TOKfunction)
- {
- FuncExp *fe = (FuncExp *)o;
- return fd == fe->fd;
- }
- return false;
-}
-
-void FuncExp::genIdent(Scope *sc)
-{
- if (fd->ident == Id::empty)
- {
- const char *s;
- if (fd->fes) s = "__foreachbody";
- else if (fd->tok == TOKreserved) s = "__lambda";
- else if (fd->tok == TOKdelegate) s = "__dgliteral";
- else s = "__funcliteral";
-
- DsymbolTable *symtab;
- if (FuncDeclaration *func = sc->parent->isFuncDeclaration())
- {
- if (func->localsymtab == NULL)
- {
- // Inside template constraint, symtab is not set yet.
- // Initialize it lazily.
- func->localsymtab = new DsymbolTable();
- }
- symtab = func->localsymtab;
- }
- else
- {
- ScopeDsymbol *sds = sc->parent->isScopeDsymbol();
- if (!sds->symtab)
- {
- // Inside template constraint, symtab may not be set yet.
- // Initialize it lazily.
- assert(sds->isTemplateInstance());
- sds->symtab = new DsymbolTable();
- }
- symtab = sds->symtab;
- }
- assert(symtab);
- int num = (int)dmd_aaLen(symtab->tab) + 1;
- Identifier *id = Identifier::generateId(s, num);
- fd->ident = id;
- if (td) td->ident = id;
- symtab->insert(td ? (Dsymbol *)td : (Dsymbol *)fd);
- }
-}
-
-Expression *FuncExp::syntaxCopy()
-{
- if (td)
- return new FuncExp(loc, td->syntaxCopy(NULL));
- else if (fd->semanticRun == PASSinit)
- return new FuncExp(loc, fd->syntaxCopy(NULL));
- else // Bugzilla 13481: Prevent multiple semantic analysis of lambda body.
- return new FuncExp(loc, fd);
-}
-
-MATCH FuncExp::matchType(Type *to, Scope *sc, FuncExp **presult, int flag)
-{
- //printf("FuncExp::matchType('%s'), to=%s\n", type ? type->toChars() : "null", to->toChars());
- if (presult)
- *presult = NULL;
-
- TypeFunction *tof = NULL;
- if (to->ty == Tdelegate)
- {
- if (tok == TOKfunction)
- {
- if (!flag)
- error("cannot match function literal to delegate type `%s`", to->toChars());
- return MATCHnomatch;
- }
- tof = (TypeFunction *)to->nextOf();
- }
- else if (to->ty == Tpointer && to->nextOf()->ty == Tfunction)
- {
- if (tok == TOKdelegate)
- {
- if (!flag)
- error("cannot match delegate literal to function pointer type `%s`", to->toChars());
- return MATCHnomatch;
- }
- tof = (TypeFunction *)to->nextOf();
- }
-
- if (td)
- {
- if (!tof)
- {
- L1:
- if (!flag)
- error("cannot infer parameter types from %s", to->toChars());
- return MATCHnomatch;
- }
-
- // Parameter types inference from 'tof'
- assert(td->_scope);
- TypeFunction *tf = (TypeFunction *)fd->type;
- //printf("\ttof = %s\n", tof->toChars());
- //printf("\ttf = %s\n", tf->toChars());
- size_t dim = tf->parameterList.length();
-
- if (tof->parameterList.length() != dim ||
- tof->parameterList.varargs != tf->parameterList.varargs)
- goto L1;
-
- Objects *tiargs = new Objects();
- tiargs->reserve(td->parameters->length);
-
- for (size_t i = 0; i < td->parameters->length; i++)
- {
- TemplateParameter *tp = (*td->parameters)[i];
- size_t u = 0;
- for (; u < dim; u++)
- {
- Parameter *p = tf->parameterList[u];
- if (p->type->ty == Tident &&
- ((TypeIdentifier *)p->type)->ident == tp->ident)
- {
- break;
- }
- }
- assert(u < dim);
- Parameter *pto = tof->parameterList[u];
- Type *t = pto->type;
- if (t->ty == Terror)
- goto L1;
- tiargs->push(t);
- }
-
- // Set target of return type inference
- if (!tf->next && tof->next)
- fd->treq = to;
-
- TemplateInstance *ti = new TemplateInstance(loc, td, tiargs);
- Expression *ex = new ScopeExp(loc, ti);
- ex = expressionSemantic(ex, td->_scope);
-
- // Reset inference target for the later re-semantic
- fd->treq = NULL;
-
- if (ex->op == TOKerror)
- return MATCHnomatch;
- if (ex->op != TOKfunction)
- goto L1;
- return ((FuncExp *)ex)->matchType(to, sc, presult, flag);
- }
-
- if (!tof || !tof->next)
- return MATCHnomatch;
-
- assert(type && type != Type::tvoid);
- TypeFunction *tfx = (TypeFunction *)fd->type;
- bool convertMatch = (type->ty != to->ty);
-
- if (fd->inferRetType && tfx->next->implicitConvTo(tof->next) == MATCHconvert)
- {
- /* If return type is inferred and covariant return,
- * tweak return statements to required return type.
- *
- * interface I {}
- * class C : Object, I{}
- *
- * I delegate() dg = delegate() { return new class C(); }
- */
- convertMatch = true;
-
- TypeFunction *tfy = new TypeFunction(tfx->parameterList, tof->next, tfx->linkage, STCundefined);
- tfy->mod = tfx->mod;
- tfy->isnothrow = tfx->isnothrow;
- tfy->isnogc = tfx->isnogc;
- tfy->purity = tfx->purity;
- tfy->isproperty = tfx->isproperty;
- tfy->isref = tfx->isref;
- tfy->iswild = tfx->iswild;
- tfy->deco = tfy->merge()->deco;
-
- tfx = tfy;
- }
-
- Type *tx;
- if (tok == TOKdelegate ||
- (tok == TOKreserved && (type->ty == Tdelegate ||
- (type->ty == Tpointer && to->ty == Tdelegate))))
- {
- // Allow conversion from implicit function pointer to delegate
- tx = new TypeDelegate(tfx);
- tx->deco = tx->merge()->deco;
- }
- else
- {
- assert(tok == TOKfunction ||
- (tok == TOKreserved && type->ty == Tpointer));
- tx = tfx->pointerTo();
- }
- //printf("\ttx = %s, to = %s\n", tx->toChars(), to->toChars());
-
- MATCH m = tx->implicitConvTo(to);
- if (m > MATCHnomatch)
- {
- // MATCHexact: exact type match
- // MATCHconst: covairiant type match (eg. attributes difference)
- // MATCHconvert: context conversion
- m = convertMatch ? MATCHconvert : tx->equals(to) ? MATCHexact : MATCHconst;
-
- if (presult)
- {
- (*presult) = (FuncExp *)copy();
- (*presult)->type = to;
-
- // Bugzilla 12508: Tweak function body for covariant returns.
- (*presult)->fd->modifyReturns(sc, tof->next);
- }
- }
- else if (!flag)
- {
- const char *ts[2];
- toAutoQualChars(ts, tx, to);
- error("cannot implicitly convert expression (%s) of type %s to %s",
- toChars(), ts[0], ts[1]);
- }
- return m;
-}
-
-const char *FuncExp::toChars()
-{
- return fd->toChars();
-}
-
-bool FuncExp::checkType()
-{
- if (td)
- {
- error("template lambda has no type");
- return true;
- }
- return false;
-}
-
-bool FuncExp::checkValue()
-{
- if (td)
- {
- error("template lambda has no value");
- return true;
- }
- return false;
-}
-
-/******************************** DeclarationExp **************************/
-
-DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration)
- : Expression(loc, TOKdeclaration, sizeof(DeclarationExp))
-{
- this->declaration = declaration;
-}
-
-Expression *DeclarationExp::syntaxCopy()
-{
- return new DeclarationExp(loc, declaration->syntaxCopy(NULL));
-}
-
-bool DeclarationExp::hasCode()
-{
- if (VarDeclaration *vd = declaration->isVarDeclaration())
- {
- return !(vd->storage_class & (STCmanifest | STCstatic));
- }
- return false;
-}
-
-/************************ TypeidExp ************************************/
-
-/*
- * typeid(int)
- */
-
-TypeidExp::TypeidExp(Loc loc, RootObject *o)
- : Expression(loc, TOKtypeid, sizeof(TypeidExp))
-{
- this->obj = o;
-}
-
-Expression *TypeidExp::syntaxCopy()
-{
- return new TypeidExp(loc, objectSyntaxCopy(obj));
-}
-
-/************************ TraitsExp ************************************/
-/*
- * __traits(identifier, args...)
- */
-
-TraitsExp::TraitsExp(Loc loc, Identifier *ident, Objects *args)
- : Expression(loc, TOKtraits, sizeof(TraitsExp))
-{
- this->ident = ident;
- this->args = args;
-}
-
-Expression *TraitsExp::syntaxCopy()
-{
- return new TraitsExp(loc, ident, TemplateInstance::arraySyntaxCopy(args));
-}
-
-/************************************************************/
-
-HaltExp::HaltExp(Loc loc)
- : Expression(loc, TOKhalt, sizeof(HaltExp))
-{
-}
-
-/************************************************************/
-
-IsExp::IsExp(Loc loc, Type *targ, Identifier *id, TOK tok,
- Type *tspec, TOK tok2, TemplateParameters *parameters)
- : Expression(loc, TOKis, sizeof(IsExp))
-{
- this->targ = targ;
- this->id = id;
- this->tok = tok;
- this->tspec = tspec;
- this->tok2 = tok2;
- this->parameters = parameters;
-}
-
-Expression *IsExp::syntaxCopy()
-{
- // This section is identical to that in TemplateDeclaration::syntaxCopy()
- TemplateParameters *p = NULL;
- if (parameters)
- {
- p = new TemplateParameters();
- p->setDim(parameters->length);
- for (size_t i = 0; i < p->length; i++)
- (*p)[i] = (*parameters)[i]->syntaxCopy();
- }
- return new IsExp(loc,
- targ->syntaxCopy(),
- id,
- tok,
- tspec ? tspec->syntaxCopy() : NULL,
- tok2,
- p);
-}
-
-void unSpeculative(Scope *sc, RootObject *o);
-
-/************************************************************/
-
-UnaExp::UnaExp(Loc loc, TOK op, int size, Expression *e1)
- : Expression(loc, op, size)
-{
- this->e1 = e1;
- this->att1 = NULL;
-}
-
-Expression *UnaExp::syntaxCopy()
-{
- UnaExp *e = (UnaExp *)copy();
- e->type = NULL;
- e->e1 = e->e1->syntaxCopy();
- return e;
-}
-
-/********************************
- * The type for a unary expression is incompatible.
- * Print error message.
- * Returns:
- * ErrorExp
- */
-Expression *UnaExp::incompatibleTypes()
-{
- if (e1->type->toBasetype() == Type::terror)
- return e1;
-
- if (e1->op == TOKtype)
- {
- error("incompatible type for (%s(%s)): cannot use `%s` with types",
- Token::toChars(op), e1->toChars(), Token::toChars(op));
- }
- else
- {
- error("incompatible type for (%s(%s)): `%s`",
- Token::toChars(op), e1->toChars(), e1->type->toChars());
- }
- return new ErrorExp();
-}
-
-Expression *UnaExp::resolveLoc(Loc loc, Scope *sc)
-{
- e1 = e1->resolveLoc(loc, sc);
- return this;
-}
-
-/************************************************************/
-
-BinExp::BinExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2)
- : Expression(loc, op, size)
-{
- this->e1 = e1;
- this->e2 = e2;
-
- this->att1 = NULL;
- this->att2 = NULL;
-}
-
-Expression *BinExp::syntaxCopy()
-{
- BinExp *e = (BinExp *)copy();
- e->type = NULL;
- e->e1 = e->e1->syntaxCopy();
- e->e2 = e->e2->syntaxCopy();
- return e;
-}
-
-Expression *BinExp::checkOpAssignTypes(Scope *sc)
-{
- // At that point t1 and t2 are the merged types. type is the original type of the lhs.
- Type *t1 = e1->type;
- Type *t2 = e2->type;
-
- // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
- // See issue 3841.
- // Should we also prevent double to float (type->isfloating() && type->size() < t2 ->size()) ?
- if (op == TOKaddass || op == TOKminass ||
- op == TOKmulass || op == TOKdivass || op == TOKmodass ||
- op == TOKpowass)
- {
- if ((type->isintegral() && t2->isfloating()))
- {
- warning("%s %s %s is performing truncating conversion",
- type->toChars(), Token::toChars(op), t2->toChars());
- }
- }
-
- // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
- if (op == TOKmulass || op == TOKdivass || op == TOKmodass)
- {
- // Any multiplication by an imaginary or complex number yields a complex result.
- // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
- const char *opstr = Token::toChars(op);
- if (t1->isreal() && t2->iscomplex())
- {
- error("%s %s %s is undefined. Did you mean %s %s %s.re ?",
- t1->toChars(), opstr, t2->toChars(),
- t1->toChars(), opstr, t2->toChars());
- return new ErrorExp();
- }
- else if (t1->isimaginary() && t2->iscomplex())
- {
- error("%s %s %s is undefined. Did you mean %s %s %s.im ?",
- t1->toChars(), opstr, t2->toChars(),
- t1->toChars(), opstr, t2->toChars());
- return new ErrorExp();
- }
- else if ((t1->isreal() || t1->isimaginary()) &&
- t2->isimaginary())
- {
- error("%s %s %s is an undefined operation", t1->toChars(), opstr, t2->toChars());
- return new ErrorExp();
- }
- }
-
- // generate an error if this is a nonsensical += or -=, eg real += imaginary
- if (op == TOKaddass || op == TOKminass)
- {
- // Addition or subtraction of a real and an imaginary is a complex result.
- // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
- if ((t1->isreal() && (t2->isimaginary() || t2->iscomplex())) ||
- (t1->isimaginary() && (t2->isreal() || t2->iscomplex())))
- {
- error("%s %s %s is undefined (result is complex)",
- t1->toChars(), Token::toChars(op), t2->toChars());
- return new ErrorExp();
- }
- if (type->isreal() || type->isimaginary())
- {
- assert(global.errors || t2->isfloating());
- e2 = e2->castTo(sc, t1);
- }
- }
-
- if (op == TOKmulass)
- {
- if (t2->isfloating())
- {
- if (t1->isreal())
- {
- if (t2->isimaginary() || t2->iscomplex())
- {
- e2 = e2->castTo(sc, t1);
- }
- }
- else if (t1->isimaginary())
- {
- if (t2->isimaginary() || t2->iscomplex())
- {
- switch (t1->ty)
- {
- case Timaginary32: t2 = Type::tfloat32; break;
- case Timaginary64: t2 = Type::tfloat64; break;
- case Timaginary80: t2 = Type::tfloat80; break;
- default:
- assert(0);
- }
- e2 = e2->castTo(sc, t2);
- }
- }
- }
- }
- else if (op == TOKdivass)
- {
- if (t2->isimaginary())
- {
- if (t1->isreal())
- {
- // x/iv = i(-x/v)
- // Therefore, the result is 0
- e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat::zero, t1));
- e2->type = t1;
- Expression *e = new AssignExp(loc, e1, e2);
- e->type = t1;
- return e;
- }
- else if (t1->isimaginary())
- {
- Type *t3;
- switch (t1->ty)
- {
- case Timaginary32: t3 = Type::tfloat32; break;
- case Timaginary64: t3 = Type::tfloat64; break;
- case Timaginary80: t3 = Type::tfloat80; break;
- default:
- assert(0);
- }
- e2 = e2->castTo(sc, t3);
- Expression *e = new AssignExp(loc, e1, e2);
- e->type = t1;
- return e;
- }
- }
- }
- else if (op == TOKmodass)
- {
- if (t2->iscomplex())
- {
- error("cannot perform modulo complex arithmetic");
- return new ErrorExp();
- }
- }
- return this;
-}
-
-/********************************
- * The types for a binary expression are incompatible.
- * Print error message.
- * Returns:
- * ErrorExp
- */
-Expression *BinExp::incompatibleTypes()
-{
- if (e1->type->toBasetype() == Type::terror)
- return e1;
- if (e2->type->toBasetype() == Type::terror)
- return e2;
-
- // CondExp uses 'a ? b : c' but we're comparing 'b : c'
- TOK thisOp = (op == TOKquestion) ? TOKcolon : op;
- if (e1->op == TOKtype || e2->op == TOKtype)
- {
- error("incompatible types for ((%s) %s (%s)): cannot use `%s` with types",
- e1->toChars(), Token::toChars(thisOp), e2->toChars(), Token::toChars(op));
- }
- else if (e1->type->equals(e2->type))
- {
- error("incompatible types for ((%s) %s (%s)): both operands are of type `%s`",
- e1->toChars(), Token::toChars(thisOp), e2->toChars(), e1->type->toChars());
- }
- else
- {
- const char *ts[2];
- toAutoQualChars(ts, e1->type, e2->type);
- error("incompatible types for ((%s) %s (%s)): `%s` and `%s`",
- e1->toChars(), Token::toChars(thisOp), e2->toChars(), ts[0], ts[1]);
- }
- return new ErrorExp();
-}
-
-bool BinExp::checkIntegralBin()
-{
- bool r1 = e1->checkIntegral();
- bool r2 = e2->checkIntegral();
- return (r1 || r2);
-}
-
-bool BinExp::checkArithmeticBin()
-{
- bool r1 = e1->checkArithmetic();
- bool r2 = e2->checkArithmetic();
- return (r1 || r2);
-}
-
-/********************** BinAssignExp **************************************/
-
-BinAssignExp::BinAssignExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2)
- : BinExp(loc, op, size, e1, e2)
-{
-}
-
-bool BinAssignExp::isLvalue()
-{
- return true;
-}
-
-Expression *BinAssignExp::toLvalue(Scope *, Expression *)
-{
- // Lvalue-ness will be handled in glue layer.
- return this;
-}
-
-Expression *BinAssignExp::modifiableLvalue(Scope *sc, Expression *)
-{
- // should check e1->checkModifiable() ?
- return toLvalue(sc, this);
-}
-
-/************************************************************/
-
-CompileExp::CompileExp(Loc loc, Expressions *exps)
- : Expression(loc, TOKmixin, sizeof(CompileExp))
-{
- this->exps = exps;
-}
-
-Expression *CompileExp::syntaxCopy()
-{
- return new CompileExp(loc, arraySyntaxCopy(exps));
-}
-
-bool CompileExp::equals(RootObject *o)
-{
- if (this == o)
- return true;
- if (o && o->dyncast() == DYNCAST_EXPRESSION && ((Expression *)o)->op == TOKmixin)
- {
- CompileExp *ce = (CompileExp *)o;
- if (exps->length != ce->exps->length)
- return false;
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e1 = (*exps)[i];
- Expression *e2 = (*ce->exps)[i];
- if (e1 != e2 && (!e1 || !e2 || !e1->equals(e2)))
- return false;
- }
- return true;
- }
- return false;
-}
-
-/************************************************************/
-
-ImportExp::ImportExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKimport, sizeof(ImportExp), e)
-{
-}
-
-/************************************************************/
-
-AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg)
- : UnaExp(loc, TOKassert, sizeof(AssertExp), e)
-{
- this->msg = msg;
-}
-
-Expression *AssertExp::syntaxCopy()
-{
- return new AssertExp(loc, e1->syntaxCopy(), msg ? msg->syntaxCopy() : NULL);
-}
-
-/************************************************************/
-
-DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident)
- : UnaExp(loc, TOKdotid, sizeof(DotIdExp), e)
-{
- this->ident = ident;
- this->wantsym = false;
- this->noderef = false;
-}
-
-DotIdExp *DotIdExp::create(Loc loc, Expression *e, Identifier *ident)
-{
- return new DotIdExp(loc, e, ident);
-}
-
-/********************** DotTemplateExp ***********************************/
-
-// Mainly just a placeholder
-
-DotTemplateExp::DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td)
- : UnaExp(loc, TOKdottd, sizeof(DotTemplateExp), e)
-
-{
- this->td = td;
-}
-
-bool DotTemplateExp::checkType()
-{
- error("%s %s has no type", td->kind(), toChars());
- return true;
-}
-
-bool DotTemplateExp::checkValue()
-{
- error("%s %s has no value", td->kind(), toChars());
- return true;
-}
-
-/************************************************************/
-
-DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *var, bool hasOverloads)
- : UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e)
-{
- //printf("DotVarExp()\n");
- this->var = var;
- this->hasOverloads = var->isVarDeclaration() ? false : hasOverloads;
-}
-
-bool DotVarExp::isLvalue()
-{
- return true;
-}
-
-Expression *DotVarExp::toLvalue(Scope *, Expression *)
-{
- //printf("DotVarExp::toLvalue(%s)\n", toChars());
- return this;
-}
-
-/***********************************************
- * Mark variable v as modified if it is inside a constructor that var
- * is a field in.
- */
-int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1)
-{
- //printf("modifyFieldVar(var = %s)\n", var->toChars());
- Dsymbol *s = sc->func;
- while (1)
- {
- FuncDeclaration *fd = NULL;
- if (s)
- fd = s->isFuncDeclaration();
- if (fd &&
- ((fd->isCtorDeclaration() && var->isField()) ||
- (fd->isStaticCtorDeclaration() && !var->isField())) &&
- fd->toParent2() == var->toParent2() &&
- (!e1 || e1->op == TOKthis)
- )
- {
- bool result = true;
-
- var->ctorinit = true;
- //printf("setting ctorinit\n");
-
- if (var->isField() && sc->fieldinit && !sc->intypeof)
- {
- assert(e1);
- bool mustInit = ((var->storage_class & STCnodefaultctor) != 0 ||
- var->type->needsNested());
-
- size_t dim = sc->fieldinit_dim;
- AggregateDeclaration *ad = fd->isMember2();
- assert(ad);
- size_t i;
- for (i = 0; i < dim; i++) // same as findFieldIndexByName in ctfeexp.c ?
- {
- if (ad->fields[i] == var)
- break;
- }
- assert(i < dim);
- unsigned fi = sc->fieldinit[i];
-
- if (fi & CSXthis_ctor)
- {
- if (var->type->isMutable() && e1->type->isMutable())
- result = false;
- else
- {
- const char *modStr = !var->type->isMutable() ? MODtoChars(var->type->mod) : MODtoChars(e1->type->mod);
- ::error(loc, "%s field `%s` initialized multiple times", modStr, var->toChars());
- }
- }
- else if (sc->noctor || (fi & CSXlabel))
- {
- if (!mustInit && var->type->isMutable() && e1->type->isMutable())
- result = false;
- else
- {
- const char *modStr = !var->type->isMutable() ? MODtoChars(var->type->mod) : MODtoChars(e1->type->mod);
- ::error(loc, "%s field `%s` initialization is not allowed in loops or after labels", modStr, var->toChars());
- }
- }
- sc->fieldinit[i] |= CSXthis_ctor;
- if (var->overlapped) // Bugzilla 15258
- {
- for (size_t j = 0; j < ad->fields.length; j++)
- {
- VarDeclaration *v = ad->fields[j];
- if (v == var || !var->isOverlappedWith(v))
- continue;
- v->ctorinit = true;
- sc->fieldinit[j] = CSXthis_ctor;
- }
- }
- }
- else if (fd != sc->func)
- {
- if (var->type->isMutable())
- result = false;
- else if (sc->func->fes)
- {
- const char *p = var->isField() ? "field" : var->kind();
- ::error(loc, "%s %s `%s` initialization is not allowed in foreach loop",
- MODtoChars(var->type->mod), p, var->toChars());
- }
- else
- {
- const char *p = var->isField() ? "field" : var->kind();
- ::error(loc, "%s %s `%s` initialization is not allowed in nested function `%s`",
- MODtoChars(var->type->mod), p, var->toChars(), sc->func->toChars());
- }
- }
- return result;
- }
- else
- {
- if (s)
- {
- s = s->toParent2();
- continue;
- }
- }
- break;
- }
- return false;
-}
-
-int DotVarExp::checkModifiable(Scope *sc, int flag)
-{
- //printf("DotVarExp::checkModifiable %s %s\n", toChars(), type->toChars());
- if (checkUnsafeAccess(sc, this, false, !flag))
- return 2;
-
- if (e1->op == TOKthis)
- return var->checkModify(loc, sc, type, e1, flag);
-
- //printf("\te1 = %s\n", e1->toChars());
- return e1->checkModifiable(sc, flag);
-}
-
-Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- return Expression::modifiableLvalue(sc, e);
-}
-
-/************************************************************/
-
-/* Things like:
- * foo.bar!(args)
- */
-
-DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs)
- : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e)
-{
- //printf("DotTemplateInstanceExp()\n");
- this->ti = new TemplateInstance(loc, name);
- this->ti->tiargs = tiargs;
-}
-
-DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti)
- : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e)
-{
- this->ti = ti;
-}
-
-Expression *DotTemplateInstanceExp::syntaxCopy()
-{
- return new DotTemplateInstanceExp(loc,
- e1->syntaxCopy(),
- ti->name,
- TemplateInstance::arraySyntaxCopy(ti->tiargs));
-}
-
-bool DotTemplateInstanceExp::findTempDecl(Scope *sc)
-{
- if (ti->tempdecl)
- return true;
-
- Expression *e = new DotIdExp(loc, e1, ti->name);
- e = expressionSemantic(e, sc);
- if (e->op == TOKdot)
- e = ((DotExp *)e)->e2;
-
- Dsymbol *s = NULL;
- switch (e->op)
- {
- case TOKoverloadset: s = ((OverExp *)e)->vars; break;
- case TOKdottd: s = ((DotTemplateExp *)e)->td; break;
- case TOKscope: s = ((ScopeExp *)e)->sds; break;
- case TOKdotvar: s = ((DotVarExp *)e)->var; break;
- case TOKvar: s = ((VarExp *)e)->var; break;
- default: return false;
- }
- return ti->updateTempDecl(sc, s);
-}
-
-/************************************************************/
-
-DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f, bool hasOverloads)
- : UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e)
-{
- this->func = f;
- this->hasOverloads = hasOverloads;
-}
-
-/************************************************************/
-
-DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s)
- : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e)
-{
- this->sym = s;
- this->type = NULL;
-}
-
-/************************************************************/
-
-CallExp::CallExp(Loc loc, Expression *e, Expressions *exps)
- : UnaExp(loc, TOKcall, sizeof(CallExp), e)
-{
- this->arguments = exps;
- this->f = NULL;
- this->directcall = false;
-}
-
-CallExp::CallExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKcall, sizeof(CallExp), e)
-{
- this->arguments = NULL;
- this->f = NULL;
- this->directcall = false;
-}
-
-CallExp::CallExp(Loc loc, Expression *e, Expression *earg1)
- : UnaExp(loc, TOKcall, sizeof(CallExp), e)
-{
- Expressions *arguments = new Expressions();
- if (earg1)
- {
- arguments->setDim(1);
- (*arguments)[0] = earg1;
- }
- this->arguments = arguments;
- this->f = NULL;
- this->directcall = false;
-}
-
-CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2)
- : UnaExp(loc, TOKcall, sizeof(CallExp), e)
-{
- Expressions *arguments = new Expressions();
- arguments->setDim(2);
- (*arguments)[0] = earg1;
- (*arguments)[1] = earg2;
-
- this->arguments = arguments;
- this->f = NULL;
- this->directcall = false;
-}
-
-CallExp *CallExp::create(Loc loc, Expression *e, Expressions *exps)
-{
- return new CallExp(loc, e, exps);
-}
-
-CallExp *CallExp::create(Loc loc, Expression *e)
-{
- return new CallExp(loc, e);
-}
-
-CallExp *CallExp::create(Loc loc, Expression *e, Expression *earg1)
-{
- return new CallExp(loc, e, earg1);
-}
-
-Expression *CallExp::syntaxCopy()
-{
- return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments));
-}
-
-bool CallExp::isLvalue()
-{
- Type *tb = e1->type->toBasetype();
- if (tb->ty == Tdelegate || tb->ty == Tpointer)
- tb = tb->nextOf();
- if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref)
- {
- if (e1->op == TOKdotvar)
- if (((DotVarExp *)e1)->var->isCtorDeclaration())
- return false;
- return true; // function returns a reference
- }
- return false;
-}
-
-Expression *CallExp::toLvalue(Scope *sc, Expression *e)
-{
- if (isLvalue())
- return this;
- return Expression::toLvalue(sc, e);
-}
-
-Expression *CallExp::addDtorHook(Scope *sc)
-{
- /* Only need to add dtor hook if it's a type that needs destruction.
- * Use same logic as VarDeclaration::callScopeDtor()
- */
-
- if (e1->type && e1->type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)e1->type;
- if (tf->isref)
- return this;
- }
-
- Type *tv = type->baseElemOf();
- if (tv->ty == Tstruct)
- {
- TypeStruct *ts = (TypeStruct *)tv;
- StructDeclaration *sd = ts->sym;
- if (sd->dtor)
- {
- /* Type needs destruction, so declare a tmp
- * which the back end will recognize and call dtor on
- */
- VarDeclaration *tmp = copyToTemp(0, "__tmpfordtor", this);
- DeclarationExp *de = new DeclarationExp(loc, tmp);
- VarExp *ve = new VarExp(loc, tmp);
- Expression *e = new CommaExp(loc, de, ve);
- e = expressionSemantic(e, sc);
- return e;
- }
- }
- return this;
-}
-
-FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL)
-{
- if (e->op == TOKaddress)
- {
- Expression *ae1 = ((AddrExp *)e)->e1;
- if (ae1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)ae1;
- if (hasOverloads)
- *hasOverloads = ve->hasOverloads;
- return ve->var->isFuncDeclaration();
- }
- if (ae1->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp *)ae1;
- if (hasOverloads)
- *hasOverloads = dve->hasOverloads;
- return dve->var->isFuncDeclaration();
- }
- }
- else
- {
- if (e->op == TOKsymoff)
- {
- SymOffExp *soe = (SymOffExp *)e;
- if (hasOverloads)
- *hasOverloads = soe->hasOverloads;
- return soe->var->isFuncDeclaration();
- }
- if (e->op == TOKdelegate)
- {
- DelegateExp *dge = (DelegateExp *)e;
- if (hasOverloads)
- *hasOverloads = dge->hasOverloads;
- return dge->func->isFuncDeclaration();
- }
- }
- return NULL;
-}
-
-/************************************************************/
-
-AddrExp::AddrExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKaddress, sizeof(AddrExp), e)
-{
-}
-
-AddrExp::AddrExp(Loc loc, Expression *e, Type *t)
- : UnaExp(loc, TOKaddress, sizeof(AddrExp), e)
-{
- type = t;
-}
-
-/************************************************************/
-
-PtrExp::PtrExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKstar, sizeof(PtrExp), e)
-{
-// if (e->type)
-// type = ((TypePointer *)e->type)->next;
-}
-
-PtrExp::PtrExp(Loc loc, Expression *e, Type *t)
- : UnaExp(loc, TOKstar, sizeof(PtrExp), e)
-{
- type = t;
-}
-
-bool PtrExp::isLvalue()
-{
- return true;
-}
-
-Expression *PtrExp::toLvalue(Scope *, Expression *)
-{
- return this;
-}
-
-int PtrExp::checkModifiable(Scope *sc, int flag)
-{
- if (e1->op == TOKsymoff)
- { SymOffExp *se = (SymOffExp *)e1;
- return se->var->checkModify(loc, sc, type, NULL, flag);
- }
- else if (e1->op == TOKaddress)
- {
- AddrExp *ae = (AddrExp *)e1;
- return ae->e1->checkModifiable(sc, flag);
- }
- return 1;
-}
-
-Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars());
- return Expression::modifiableLvalue(sc, e);
-}
-
-/************************************************************/
-
-NegExp::NegExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKneg, sizeof(NegExp), e)
-{
-}
-
-/************************************************************/
-
-UAddExp::UAddExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKuadd, sizeof(UAddExp), e)
-{
-}
-
-/************************************************************/
-
-ComExp::ComExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKtilde, sizeof(ComExp), e)
-{
-}
-
-/************************************************************/
-
-NotExp::NotExp(Loc loc, Expression *e)
- : UnaExp(loc, TOKnot, sizeof(NotExp), e)
-{
-}
-
-/************************************************************/
-
-DeleteExp::DeleteExp(Loc loc, Expression *e, bool isRAII)
- : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e)
-{
- this->isRAII = isRAII;
-}
-
-Expression *DeleteExp::toBoolean(Scope *)
-{
- error("delete does not give a boolean result");
- return new ErrorExp();
-}
-
-/************************************************************/
-
-CastExp::CastExp(Loc loc, Expression *e, Type *t)
- : UnaExp(loc, TOKcast, sizeof(CastExp), e)
-{
- this->to = t;
- this->mod = (unsigned char)~0;
-}
-
-/* For cast(const) and cast(immutable)
- */
-CastExp::CastExp(Loc loc, Expression *e, unsigned char mod)
- : UnaExp(loc, TOKcast, sizeof(CastExp), e)
-{
- this->to = NULL;
- this->mod = mod;
-}
-
-Expression *CastExp::syntaxCopy()
-{
- return to ? new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy())
- : new CastExp(loc, e1->syntaxCopy(), mod);
-}
-
-/************************************************************/
-
-VectorExp::VectorExp(Loc loc, Expression *e, Type *t)
- : UnaExp(loc, TOKvector, sizeof(VectorExp), e)
-{
- assert(t->ty == Tvector);
- to = (TypeVector *)t;
- dim = ~0;
- ownedByCtfe = OWNEDcode;
-}
-
-VectorExp *VectorExp::create(Loc loc, Expression *e, Type *t)
-{
- return new VectorExp(loc, e, t);
-}
-
-Expression *VectorExp::syntaxCopy()
-{
- return new VectorExp(loc, e1->syntaxCopy(), to->syntaxCopy());
-}
-
-/************************************************************/
-
-VectorArrayExp::VectorArrayExp(Loc loc, Expression *e1)
- : UnaExp(loc, TOKvectorarray, sizeof(VectorArrayExp), e1)
-{
-}
-
-bool VectorArrayExp::isLvalue()
-{
- return e1->isLvalue();
-}
-
-Expression *VectorArrayExp::toLvalue(Scope *sc, Expression *e)
-{
- e1 = e1->toLvalue(sc, e);
- return this;
-}
-
-/************************************************************/
-
-SliceExp::SliceExp(Loc loc, Expression *e1, IntervalExp *ie)
- : UnaExp(loc, TOKslice, sizeof(SliceExp), e1)
-{
- this->upr = ie ? ie->upr : NULL;
- this->lwr = ie ? ie->lwr : NULL;
- lengthVar = NULL;
- upperIsInBounds = false;
- lowerIsLessThanUpper = false;
- arrayop = false;
-}
-
-SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr)
- : UnaExp(loc, TOKslice, sizeof(SliceExp), e1)
-{
- this->upr = upr;
- this->lwr = lwr;
- lengthVar = NULL;
- upperIsInBounds = false;
- lowerIsLessThanUpper = false;
- arrayop = false;
-}
-
-Expression *SliceExp::syntaxCopy()
-{
- SliceExp *se = new SliceExp(loc, e1->syntaxCopy(),
- lwr ? lwr->syntaxCopy() : NULL,
- upr ? upr->syntaxCopy() : NULL);
- se->lengthVar = this->lengthVar; // bug7871
- return se;
-}
-
-int SliceExp::checkModifiable(Scope *sc, int flag)
-{
- //printf("SliceExp::checkModifiable %s\n", toChars());
- if (e1->type->ty == Tsarray ||
- (e1->op == TOKindex && e1->type->ty != Tarray) ||
- e1->op == TOKslice)
- {
- return e1->checkModifiable(sc, flag);
- }
- return 1;
-}
-
-bool SliceExp::isLvalue()
-{
- /* slice expression is rvalue in default, but
- * conversion to reference of static array is only allowed.
- */
- return (type && type->toBasetype()->ty == Tsarray);
-}
-
-Expression *SliceExp::toLvalue(Scope *sc, Expression *e)
-{
- //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type->toChars() : NULL);
- return (type && type->toBasetype()->ty == Tsarray)
- ? this : Expression::toLvalue(sc, e);
-}
-
-Expression *SliceExp::modifiableLvalue(Scope *, Expression *)
-{
- error("slice expression %s is not a modifiable lvalue", toChars());
- return this;
-}
-
-bool SliceExp::isBool(bool result)
-{
- return e1->isBool(result);
-}
-
-/********************** ArrayLength **************************************/
-
-ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1)
- : UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1)
-{
-}
-
-/*********************** IntervalExp ********************************/
-
-// Mainly just a placeholder
-
-IntervalExp::IntervalExp(Loc loc, Expression *lwr, Expression *upr)
- : Expression(loc, TOKinterval, sizeof(IntervalExp))
-{
- this->lwr = lwr;
- this->upr = upr;
-}
-
-Expression *IntervalExp::syntaxCopy()
-{
- return new IntervalExp(loc, lwr->syntaxCopy(), upr->syntaxCopy());
-}
-
-/********************** DelegatePtrExp **************************************/
-
-DelegatePtrExp::DelegatePtrExp(Loc loc, Expression *e1)
- : UnaExp(loc, TOKdelegateptr, sizeof(DelegatePtrExp), e1)
-{
-}
-
-bool DelegatePtrExp::isLvalue()
-{
- return e1->isLvalue();
-}
-
-Expression *DelegatePtrExp::toLvalue(Scope *sc, Expression *e)
-{
- e1 = e1->toLvalue(sc, e);
- return this;
-}
-
-Expression *DelegatePtrExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- if (sc->func->setUnsafe())
- {
- error("cannot modify delegate pointer in @safe code %s", toChars());
- return new ErrorExp();
- }
- return Expression::modifiableLvalue(sc, e);
-}
-
-/********************** DelegateFuncptrExp **************************************/
-
-DelegateFuncptrExp::DelegateFuncptrExp(Loc loc, Expression *e1)
- : UnaExp(loc, TOKdelegatefuncptr, sizeof(DelegateFuncptrExp), e1)
-{
-}
-
-bool DelegateFuncptrExp::isLvalue()
-{
- return e1->isLvalue();
-}
-
-Expression *DelegateFuncptrExp::toLvalue(Scope *sc, Expression *e)
-{
- e1 = e1->toLvalue(sc, e);
- return this;
-}
-
-Expression *DelegateFuncptrExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- if (sc->func->setUnsafe())
- {
- error("cannot modify delegate function pointer in @safe code %s", toChars());
- return new ErrorExp();
- }
- return Expression::modifiableLvalue(sc, e);
-}
-
-/*********************** ArrayExp *************************************/
-
-// e1 [ i1, i2, i3, ... ]
-
-ArrayExp::ArrayExp(Loc loc, Expression *e1, Expression *index)
- : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1)
-{
- arguments = new Expressions();
- if (index)
- arguments->push(index);
- lengthVar = NULL;
- currentDimension = 0;
-}
-
-ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args)
- : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1)
-{
- arguments = args;
- lengthVar = NULL;
- currentDimension = 0;
-}
-
-Expression *ArrayExp::syntaxCopy()
-{
- ArrayExp *ae = new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments));
- ae->lengthVar = this->lengthVar; // bug7871
- return ae;
-}
-
-bool ArrayExp::isLvalue()
-{
- if (type && type->toBasetype()->ty == Tvoid)
- return false;
- return true;
-}
-
-Expression *ArrayExp::toLvalue(Scope *, Expression *)
-{
- if (type && type->toBasetype()->ty == Tvoid)
- error("voids have no value");
- return this;
-}
-
-/************************* DotExp ***********************************/
-
-DotExp::DotExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKdot, sizeof(DotExp), e1, e2)
-{
-}
-
-/************************* CommaExp ***********************************/
-
-CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2, bool generated)
- : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2)
-{
- isGenerated = generated;
- allowCommaExp = generated;
-}
-
-bool CommaExp::isLvalue()
-{
- return e2->isLvalue();
-}
-
-Expression *CommaExp::toLvalue(Scope *sc, Expression *)
-{
- e2 = e2->toLvalue(sc, NULL);
- return this;
-}
-
-int CommaExp::checkModifiable(Scope *sc, int flag)
-{
- return e2->checkModifiable(sc, flag);
-}
-
-Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- e2 = e2->modifiableLvalue(sc, e);
- return this;
-}
-
-bool CommaExp::isBool(bool result)
-{
- return e2->isBool(result);
-}
-
-Expression *CommaExp::toBoolean(Scope *sc)
-{
- Expression *ex2 = e2->toBoolean(sc);
- if (ex2->op == TOKerror)
- return ex2;
- e2 = ex2;
- type = e2->type;
- return this;
-}
-
-Expression *CommaExp::addDtorHook(Scope *sc)
-{
- e2 = e2->addDtorHook(sc);
- return this;
-}
-
-/************************** IndexExp **********************************/
-
-// e1 [ e2 ]
-
-IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2)
-{
- //printf("IndexExp::IndexExp('%s')\n", toChars());
- lengthVar = NULL;
- modifiable = false; // assume it is an rvalue
- indexIsInBounds = false;
-}
-
-Expression *IndexExp::syntaxCopy()
-{
- IndexExp *ie = new IndexExp(loc, e1->syntaxCopy(), e2->syntaxCopy());
- ie->lengthVar = this->lengthVar; // bug7871
- return ie;
-}
-
-bool IndexExp::isLvalue()
-{
- return true;
-}
-
-Expression *IndexExp::toLvalue(Scope *, Expression *)
-{
- return this;
-}
-
-int IndexExp::checkModifiable(Scope *sc, int flag)
-{
- if (e1->type->ty == Tsarray ||
- e1->type->ty == Taarray ||
- (e1->op == TOKindex && e1->type->ty != Tarray) ||
- e1->op == TOKslice)
- {
- return e1->checkModifiable(sc, flag);
- }
- return 1;
-}
-
-Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e)
-{
- //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
- Expression *ex = markSettingAAElem();
- if (ex->op == TOKerror)
- return ex;
-
- return Expression::modifiableLvalue(sc, e);
-}
-
-Expression *IndexExp::markSettingAAElem()
-{
- if (e1->type->toBasetype()->ty == Taarray)
- {
- Type *t2b = e2->type->toBasetype();
- if (t2b->ty == Tarray && t2b->nextOf()->isMutable())
- {
- error("associative arrays can only be assigned values with immutable keys, not %s", e2->type->toChars());
- return new ErrorExp();
- }
- modifiable = true;
-
- if (e1->op == TOKindex)
- {
- Expression *ex = ((IndexExp *)e1)->markSettingAAElem();
- if (ex->op == TOKerror)
- return ex;
- assert(ex == e1);
- }
- }
- return this;
-}
-
-/************************* PostExp ***********************************/
-
-PostExp::PostExp(TOK op, Loc loc, Expression *e)
- : BinExp(loc, op, sizeof(PostExp), e,
- new IntegerExp(loc, 1, Type::tint32))
-{
-}
-
-/************************* PreExp ***********************************/
-
-PreExp::PreExp(TOK op, Loc loc, Expression *e)
- : UnaExp(loc, op, sizeof(PreExp), e)
-{
-}
-
-/************************************************************/
-
-/* op can be TOKassign, TOKconstruct, or TOKblit */
-
-AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2)
-{
- memset = 0;
-}
-
-bool AssignExp::isLvalue()
-{
- // Array-op 'x[] = y[]' should make an rvalue.
- // Setting array length 'x.length = v' should make an rvalue.
- if (e1->op == TOKslice ||
- e1->op == TOKarraylength)
- {
- return false;
- }
- return true;
-}
-
-Expression *AssignExp::toLvalue(Scope *sc, Expression *ex)
-{
- if (e1->op == TOKslice ||
- e1->op == TOKarraylength)
- {
- return Expression::toLvalue(sc, ex);
- }
-
- /* In front-end level, AssignExp should make an lvalue of e1.
- * Taking the address of e1 will be handled in low level layer,
- * so this function does nothing.
- */
- return this;
-}
-
-Expression *AssignExp::toBoolean(Scope *)
-{
- // Things like:
- // if (a = b) ...
- // are usually mistakes.
-
- error("assignment cannot be used as a condition, perhaps == was meant?");
- return new ErrorExp();
-}
-
-/************************************************************/
-
-ConstructExp::ConstructExp(Loc loc, Expression *e1, Expression *e2)
- : AssignExp(loc, e1, e2)
-{
- op = TOKconstruct;
-}
-
-ConstructExp::ConstructExp(Loc loc, VarDeclaration *v, Expression *e2)
- : AssignExp(loc, new VarExp(loc, v), e2)
-{
- assert(v->type && e1->type);
- op = TOKconstruct;
-
- if (v->storage_class & (STCref | STCout))
- memset |= referenceInit;
-}
-
-/************************************************************/
-
-BlitExp::BlitExp(Loc loc, Expression *e1, Expression *e2)
- : AssignExp(loc, e1, e2)
-{
- op = TOKblit;
-}
-
-BlitExp::BlitExp(Loc loc, VarDeclaration *v, Expression *e2)
- : AssignExp(loc, new VarExp(loc, v), e2)
-{
- assert(v->type && e1->type);
- op = TOKblit;
-
- if (v->storage_class & (STCref | STCout))
- memset |= referenceInit;
-}
-
-/************************************************************/
-
-AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2)
-{
-}
-
-/***************** PowAssignExp *******************************************/
-
-PowAssignExp::PowAssignExp(Loc loc, Expression *e1, Expression *e2)
- : BinAssignExp(loc, TOKpowass, sizeof(PowAssignExp), e1, e2)
-{
-}
-
-/************************* AddExp *****************************/
-
-AddExp::AddExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-MinExp::MinExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKmin, sizeof(MinExp), e1, e2)
-{
-}
-
-/************************* CatExp *****************************/
-
-CatExp::CatExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKcat, sizeof(CatExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-MulExp::MulExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKmul, sizeof(MulExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-DivExp::DivExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-ModExp::ModExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-PowExp::PowExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKpow, sizeof(PowExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-ShlExp::ShlExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKshl, sizeof(ShlExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-AndExp::AndExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKand, sizeof(AndExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-OrExp::OrExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKor, sizeof(OrExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-XorExp::XorExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKxor, sizeof(XorExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-LogicalExp::LogicalExp(Loc loc, TOK op, Expression *e1, Expression *e2)
- : BinExp(loc, op, sizeof(LogicalExp), e1, e2)
-{
-}
-
-Expression *LogicalExp::toBoolean(Scope *sc)
-{
- Expression *ex2 = e2->toBoolean(sc);
- if (ex2->op == TOKerror)
- return ex2;
- e2 = ex2;
- return this;
-}
-
-/************************************************************/
-
-InExp::InExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKin, sizeof(InExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-/* This deletes the key e1 from the associative array e2
- */
-
-RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2)
-{
- type = Type::tbool;
-}
-
-/************************************************************/
-
-CmpExp::CmpExp(TOK op, Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, op, sizeof(CmpExp), e1, e2)
-{
-}
-
-/************************************************************/
-
-EqualExp::EqualExp(TOK op, Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, op, sizeof(EqualExp), e1, e2)
-{
- assert(op == TOKequal || op == TOKnotequal);
-}
-
-/************************************************************/
-
-IdentityExp::IdentityExp(TOK op, Loc loc, Expression *e1, Expression *e2)
- : BinExp(loc, op, sizeof(IdentityExp), e1, e2)
-{
-}
-
-/****************************************************************/
-
-CondExp::CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2)
- : BinExp(loc, TOKquestion, sizeof(CondExp), e1, e2)
-{
- this->econd = econd;
-}
-
-Expression *CondExp::syntaxCopy()
-{
- return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy());
-}
-
-void CondExp::hookDtors(Scope *sc)
-{
- class DtorVisitor : public StoppableVisitor
- {
- public:
- Scope *sc;
- CondExp *ce;
- VarDeclaration *vcond;
- bool isThen;
-
- DtorVisitor(Scope *sc, CondExp *ce)
- {
- this->sc = sc;
- this->ce = ce;
- this->vcond = NULL;
- }
-
- void visit(Expression *)
- {
- //printf("(e = %s)\n", e->toChars());
- }
-
- void visit(DeclarationExp *e)
- {
- VarDeclaration *v = e->declaration->isVarDeclaration();
- if (v && !v->isDataseg())
- {
- if (v->_init)
- {
- ExpInitializer *ei = v->_init->isExpInitializer();
- if (ei)
- ei->exp->accept(this);
- }
-
- if (v->needsScopeDtor())
- {
- if (!vcond)
- {
- vcond = copyToTemp(STCvolatile, "__cond", ce->econd);
- dsymbolSemantic(vcond, sc);
-
- Expression *de = new DeclarationExp(ce->econd->loc, vcond);
- de = expressionSemantic(de, sc);
-
- Expression *ve = new VarExp(ce->econd->loc, vcond);
- ce->econd = Expression::combine(de, ve);
- }
-
- //printf("\t++v = %s, v->edtor = %s\n", v->toChars(), v->edtor->toChars());
- Expression *ve = new VarExp(vcond->loc, vcond);
- if (isThen)
- v->edtor = new LogicalExp(v->edtor->loc, TOKandand, ve, v->edtor);
- else
- v->edtor = new LogicalExp(v->edtor->loc, TOKoror, ve, v->edtor);
- v->edtor = expressionSemantic(v->edtor, sc);
- //printf("\t--v = %s, v->edtor = %s\n", v->toChars(), v->edtor->toChars());
- }
- }
- }
- };
-
- DtorVisitor v(sc, this);
- //printf("+%s\n", toChars());
- v.isThen = true; walkPostorder(e1, &v);
- v.isThen = false; walkPostorder(e2, &v);
- //printf("-%s\n", toChars());
-}
-
-bool CondExp::isLvalue()
-{
- return e1->isLvalue() && e2->isLvalue();
-}
-
-
-Expression *CondExp::toLvalue(Scope *sc, Expression *)
-{
- // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
- CondExp *e = (CondExp *)copy();
- e->e1 = e1->toLvalue(sc, NULL)->addressOf();
- e->e2 = e2->toLvalue(sc, NULL)->addressOf();
- e->type = type->pointerTo();
- return new PtrExp(loc, e, type);
-}
-
-int CondExp::checkModifiable(Scope *sc, int flag)
-{
- return e1->checkModifiable(sc, flag) && e2->checkModifiable(sc, flag);
-}
-
-Expression *CondExp::modifiableLvalue(Scope *sc, Expression *)
-{
- //error("conditional expression %s is not a modifiable lvalue", toChars());
- e1 = e1->modifiableLvalue(sc, e1);
- e2 = e2->modifiableLvalue(sc, e2);
- return toLvalue(sc, this);
-}
-
-Expression *CondExp::toBoolean(Scope *sc)
-{
- Expression *ex1 = e1->toBoolean(sc);
- Expression *ex2 = e2->toBoolean(sc);
- if (ex1->op == TOKerror)
- return ex1;
- if (ex2->op == TOKerror)
- return ex2;
- e1 = ex1;
- e2 = ex2;
- return this;
-}
-
-/****************************************************************/
-
-DefaultInitExp::DefaultInitExp(Loc loc, TOK subop, int size)
- : Expression(loc, TOKdefault, size)
-{
- this->subop = subop;
-}
-
-/****************************************************************/
-
-FileInitExp::FileInitExp(Loc loc, TOK tok)
- : DefaultInitExp(loc, tok, sizeof(FileInitExp))
-{
-}
-
-Expression *FileInitExp::resolveLoc(Loc loc, Scope *sc)
-{
- //printf("FileInitExp::resolve() %s\n", toChars());
- const char *s;
- if (subop == TOKfilefullpath)
- s = FileName::toAbsolute(loc.filename != NULL ? loc.filename : sc->_module->srcfile->name->toChars());
- else
- s = loc.filename != NULL ? loc.filename : sc->_module->ident->toChars();
-
- Expression *e = new StringExp(loc, const_cast<char *>(s));
- e = expressionSemantic(e, sc);
- e = e->castTo(sc, type);
- return e;
-}
-
-/****************************************************************/
-
-LineInitExp::LineInitExp(Loc loc)
- : DefaultInitExp(loc, TOKline, sizeof(LineInitExp))
-{
-}
-
-Expression *LineInitExp::resolveLoc(Loc loc, Scope *sc)
-{
- Expression *e = new IntegerExp(loc, loc.linnum, Type::tint32);
- e = e->castTo(sc, type);
- return e;
-}
-
-/****************************************************************/
-
-ModuleInitExp::ModuleInitExp(Loc loc)
- : DefaultInitExp(loc, TOKmodulestring, sizeof(ModuleInitExp))
-{
-}
-
-Expression *ModuleInitExp::resolveLoc(Loc loc, Scope *sc)
-{
- const char *s;
- if (sc->callsc)
- s = sc->callsc->_module->toPrettyChars();
- else
- s = sc->_module->toPrettyChars();
- Expression *e = new StringExp(loc, const_cast<char *>(s));
- e = expressionSemantic(e, sc);
- e = e->castTo(sc, type);
- return e;
-}
-
-/****************************************************************/
-
-FuncInitExp::FuncInitExp(Loc loc)
- : DefaultInitExp(loc, TOKfuncstring, sizeof(FuncInitExp))
-{
-}
-
-Expression *FuncInitExp::resolveLoc(Loc loc, Scope *sc)
-{
- const char *s;
- if (sc->callsc && sc->callsc->func)
- s = sc->callsc->func->Dsymbol::toPrettyChars();
- else if (sc->func)
- s = sc->func->Dsymbol::toPrettyChars();
- else
- s = "";
- Expression *e = new StringExp(loc, const_cast<char *>(s));
- e = expressionSemantic(e, sc);
- e->type = Type::tstring;
- return e;
-}
-
-/****************************************************************/
-
-PrettyFuncInitExp::PrettyFuncInitExp(Loc loc)
- : DefaultInitExp(loc, TOKprettyfunc, sizeof(PrettyFuncInitExp))
-{
-}
-
-Expression *PrettyFuncInitExp::resolveLoc(Loc loc, Scope *sc)
-{
- FuncDeclaration *fd;
- if (sc->callsc && sc->callsc->func)
- fd = sc->callsc->func;
- else
- fd = sc->func;
-
- const char *s;
- if (fd)
- {
- const char *funcStr = fd->Dsymbol::toPrettyChars();
- OutBuffer buf;
- functionToBufferWithIdent((TypeFunction *)fd->type, &buf, funcStr);
- s = buf.extractChars();
- }
- else
- {
- s = "";
- }
-
- Expression *e = new StringExp(loc, const_cast<char *>(s));
- e = expressionSemantic(e, sc);
- e->type = Type::tstring;
- return e;
-}
-
-Expression *BinExp::reorderSettingAAElem(Scope *sc)
-{
- BinExp *be = this;
-
- if (be->e1->op != TOKindex)
- return be;
- IndexExp *ie = (IndexExp *)be->e1;
- if (ie->e1->type->toBasetype()->ty != Taarray)
- return be;
-
- /* Fix evaluation order of setting AA element. (Bugzilla 3825)
- * Rewrite:
- * aa[k1][k2][k3] op= val;
- * as:
- * auto ref __aatmp = aa;
- * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
- * auto ref __aaval = val;
- * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
- */
-
- Expression *e0 = NULL;
- while (1)
- {
- Expression *de = NULL;
- ie->e2 = extractSideEffect(sc, "__aakey", &de, ie->e2);
- e0 = Expression::combine(de, e0);
-
- Expression *ie1 = ie->e1;
- if (ie1->op != TOKindex ||
- ((IndexExp *)ie1)->e1->type->toBasetype()->ty != Taarray)
- {
- break;
- }
- ie = (IndexExp *)ie1;
- }
- assert(ie->e1->type->toBasetype()->ty == Taarray);
-
- Expression *de = NULL;
- ie->e1 = extractSideEffect(sc, "__aatmp", &de, ie->e1);
- e0 = Expression::combine(de, e0);
-
- be->e2 = extractSideEffect(sc, "__aaval", &e0, be->e2, true);
-
- //printf("-e0 = %s, be = %s\n", e0->toChars(), be->toChars());
- return Expression::combine(e0, be);
-}
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
new file mode 100644
index 0000000..0d6fa1e
--- /dev/null
+++ b/gcc/d/dmd/expression.d
@@ -0,0 +1,6985 @@
+/**
+ * Defines the bulk of the classes which represent the AST at the expression level.
+ *
+ * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expression.d, _expression.d)
+ * Documentation: https://dlang.org/phobos/dmd_expression.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expression.d
+ */
+
+module dmd.expression;
+
+import core.stdc.stdarg;
+import core.stdc.stdio;
+import core.stdc.string;
+
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.apply;
+import dmd.arrayop;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.ast_node;
+import dmd.gluelayer;
+import dmd.canthrow;
+import dmd.complex;
+import dmd.constfold;
+import dmd.ctfeexpr;
+import dmd.ctorflow;
+import dmd.dcast;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.delegatize;
+import dmd.dimport;
+import dmd.dinterpret;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.escape;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.inline;
+import dmd.mtype;
+import dmd.nspace;
+import dmd.objc;
+import dmd.opover;
+import dmd.optimize;
+import dmd.root.ctfloat;
+import dmd.root.filename;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.safe;
+import dmd.sideeffect;
+import dmd.target;
+import dmd.tokens;
+import dmd.typesem;
+import dmd.utf;
+import dmd.visitor;
+
+enum LOGSEMANTIC = false;
+void emplaceExp(T : Expression, Args...)(void* p, Args args)
+{
+ scope tmp = new T(args);
+ memcpy(p, cast(void*)tmp, __traits(classInstanceSize, T));
+}
+
+void emplaceExp(T : UnionExp)(T* p, Expression e)
+{
+ memcpy(p, cast(void*)e, e.size);
+}
+
+// Return value for `checkModifiable`
+enum Modifiable
+{
+ /// Not modifiable
+ no,
+ /// Modifiable (the type is mutable)
+ yes,
+ /// Modifiable because it is initialization
+ initialization,
+}
+/**
+ * Specifies how the checkModify deals with certain situations
+ */
+enum ModifyFlags
+{
+ /// Issue error messages on invalid modifications of the variable
+ none,
+ /// No errors are emitted for invalid modifications
+ noError = 0x1,
+ /// The modification occurs for a subfield of the current variable
+ fieldAssign = 0x2,
+}
+
+/****************************************
+ * Find the first non-comma expression.
+ * Params:
+ * e = Expressions connected by commas
+ * Returns:
+ * left-most non-comma expression
+ */
+inout(Expression) firstComma(inout Expression e)
+{
+ Expression ex = cast()e;
+ while (ex.op == TOK.comma)
+ ex = (cast(CommaExp)ex).e1;
+ return cast(inout)ex;
+
+}
+
+/****************************************
+ * Find the last non-comma expression.
+ * Params:
+ * e = Expressions connected by commas
+ * Returns:
+ * right-most non-comma expression
+ */
+
+inout(Expression) lastComma(inout Expression e)
+{
+ Expression ex = cast()e;
+ while (ex.op == TOK.comma)
+ ex = (cast(CommaExp)ex).e2;
+ return cast(inout)ex;
+
+}
+
+/*****************************************
+ * Determine if `this` is available by walking up the enclosing
+ * scopes until a function is found.
+ *
+ * Params:
+ * sc = where to start looking for the enclosing function
+ * Returns:
+ * Found function if it satisfies `isThis()`, otherwise `null`
+ */
+FuncDeclaration hasThis(Scope* sc)
+{
+ //printf("hasThis()\n");
+ Dsymbol p = sc.parent;
+ while (p && p.isTemplateMixin())
+ p = p.parent;
+ FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null;
+ //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : "");
+
+ // Go upwards until we find the enclosing member function
+ FuncDeclaration fd = fdthis;
+ while (1)
+ {
+ if (!fd)
+ {
+ return null;
+ }
+ if (!fd.isNested() || fd.isThis() || (fd.isThis2 && fd.isMember2()))
+ break;
+
+ Dsymbol parent = fd.parent;
+ while (1)
+ {
+ if (!parent)
+ return null;
+ TemplateInstance ti = parent.isTemplateInstance();
+ if (ti)
+ parent = ti.parent;
+ else
+ break;
+ }
+ fd = parent.isFuncDeclaration();
+ }
+
+ if (!fd.isThis() && !(fd.isThis2 && fd.isMember2()))
+ {
+ return null;
+ }
+
+ assert(fd.vthis);
+ return fd;
+
+}
+
+/***********************************
+ * Determine if a `this` is needed to access `d`.
+ * Params:
+ * sc = context
+ * d = declaration to check
+ * Returns:
+ * true means a `this` is needed
+ */
+bool isNeedThisScope(Scope* sc, Declaration d)
+{
+ if (sc.intypeof == 1)
+ return false;
+
+ AggregateDeclaration ad = d.isThis();
+ if (!ad)
+ return false;
+ //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars());
+
+ for (Dsymbol s = sc.parent; s; s = s.toParentLocal())
+ {
+ //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2());
+ if (AggregateDeclaration ad2 = s.isAggregateDeclaration())
+ {
+ if (ad2 == ad)
+ return false;
+ else if (ad2.isNested())
+ continue;
+ else
+ return true;
+ }
+ if (FuncDeclaration f = s.isFuncDeclaration())
+ {
+ if (f.isMemberLocal())
+ break;
+ }
+ }
+ return true;
+}
+
+/******************************
+ * check e is exp.opDispatch!(tiargs) or not
+ * It's used to switch to UFCS the semantic analysis path
+ */
+bool isDotOpDispatch(Expression e)
+{
+ if (auto dtie = e.isDotTemplateInstanceExp())
+ return dtie.ti.name == Id.opDispatch;
+ return false;
+}
+
+/****************************************
+ * Expand tuples.
+ * Input:
+ * exps aray of Expressions
+ * Output:
+ * exps rewritten in place
+ */
+extern (C++) void expandTuples(Expressions* exps)
+{
+ //printf("expandTuples()\n");
+ if (exps is null)
+ return;
+
+ for (size_t i = 0; i < exps.dim; i++)
+ {
+ Expression arg = (*exps)[i];
+ if (!arg)
+ continue;
+
+ // Look for tuple with 0 members
+ if (auto e = arg.isTypeExp())
+ {
+ if (auto tt = e.type.toBasetype().isTypeTuple())
+ {
+ if (!tt.arguments || tt.arguments.dim == 0)
+ {
+ exps.remove(i);
+ if (i == exps.dim)
+ return;
+ }
+ else // Expand a TypeTuple
+ {
+ exps.remove(i);
+ auto texps = new Expressions(tt.arguments.length);
+ foreach (j, a; *tt.arguments)
+ (*texps)[j] = new TypeExp(e.loc, a.type);
+ exps.insert(i, texps);
+ }
+ i--;
+ continue;
+ }
+ }
+
+ // Inline expand all the tuples
+ while (arg.op == TOK.tuple)
+ {
+ TupleExp te = cast(TupleExp)arg;
+ exps.remove(i); // remove arg
+ exps.insert(i, te.exps); // replace with tuple contents
+ if (i == exps.dim)
+ return; // empty tuple, no more arguments
+ (*exps)[i] = Expression.combine(te.e0, (*exps)[i]);
+ arg = (*exps)[i];
+ }
+ }
+}
+
+/****************************************
+ * Expand alias this tuples.
+ */
+TupleDeclaration isAliasThisTuple(Expression e)
+{
+ if (!e.type)
+ return null;
+
+ Type t = e.type.toBasetype();
+ while (true)
+ {
+ if (Dsymbol s = t.toDsymbol(null))
+ {
+ if (auto ad = s.isAggregateDeclaration())
+ {
+ s = ad.aliasthis ? ad.aliasthis.sym : null;
+ if (s && s.isVarDeclaration())
+ {
+ TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
+ if (td && td.isexp)
+ return td;
+ }
+ if (Type att = t.aliasthisOf())
+ {
+ t = att;
+ continue;
+ }
+ }
+ }
+ return null;
+ }
+}
+
+int expandAliasThisTuples(Expressions* exps, size_t starti = 0)
+{
+ if (!exps || exps.dim == 0)
+ return -1;
+
+ for (size_t u = starti; u < exps.dim; u++)
+ {
+ Expression exp = (*exps)[u];
+ if (TupleDeclaration td = exp.isAliasThisTuple)
+ {
+ exps.remove(u);
+ foreach (i, o; *td.objects)
+ {
+ auto d = o.isExpression().isDsymbolExp().s.isDeclaration();
+ auto e = new DotVarExp(exp.loc, exp, d);
+ assert(d.type);
+ e.type = d.type;
+ exps.insert(u + i, e);
+ }
+ version (none)
+ {
+ printf("expansion ->\n");
+ foreach (e; exps)
+ {
+ printf("\texps[%d] e = %s %s\n", i, Token.tochars[e.op], e.toChars());
+ }
+ }
+ return cast(int)u;
+ }
+ }
+ return -1;
+}
+
+/****************************************
+ * If `s` is a function template, i.e. the only member of a template
+ * and that member is a function, return that template.
+ * Params:
+ * s = symbol that might be a function template
+ * Returns:
+ * template for that function, otherwise null
+ */
+TemplateDeclaration getFuncTemplateDecl(Dsymbol s)
+{
+ FuncDeclaration f = s.isFuncDeclaration();
+ if (f && f.parent)
+ {
+ if (auto ti = f.parent.isTemplateInstance())
+ {
+ if (!ti.isTemplateMixin() && ti.tempdecl)
+ {
+ auto td = ti.tempdecl.isTemplateDeclaration();
+ if (td.onemember && td.ident == f.ident)
+ {
+ return td;
+ }
+ }
+ }
+ }
+ return null;
+}
+
+/************************************************
+ * If we want the value of this expression, but do not want to call
+ * the destructor on it.
+ */
+Expression valueNoDtor(Expression e)
+{
+ auto ex = lastComma(e);
+
+ if (auto ce = ex.isCallExp())
+ {
+ /* The struct value returned from the function is transferred
+ * so do not call the destructor on it.
+ * Recognize:
+ * ((S _ctmp = S.init), _ctmp).this(...)
+ * and make sure the destructor is not called on _ctmp
+ * BUG: if ex is a CommaExp, we should go down the right side.
+ */
+ if (auto dve = ce.e1.isDotVarExp())
+ {
+ if (dve.var.isCtorDeclaration())
+ {
+ // It's a constructor call
+ if (auto comma = dve.e1.isCommaExp())
+ {
+ if (auto ve = comma.e2.isVarExp())
+ {
+ VarDeclaration ctmp = ve.var.isVarDeclaration();
+ if (ctmp)
+ {
+ ctmp.storage_class |= STC.nodtor;
+ assert(!ce.isLvalue());
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (auto ve = ex.isVarExp())
+ {
+ auto vtmp = ve.var.isVarDeclaration();
+ if (vtmp && (vtmp.storage_class & STC.rvalue))
+ {
+ vtmp.storage_class |= STC.nodtor;
+ }
+ }
+ return e;
+}
+
+/*********************************************
+ * If e is an instance of a struct, and that struct has a copy constructor,
+ * rewrite e as:
+ * (tmp = e),tmp
+ * Input:
+ * sc = just used to specify the scope of created temporary variable
+ * destinationType = the type of the object on which the copy constructor is called;
+ * may be null if the struct defines a postblit
+ */
+private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
+{
+ if (auto ts = e.type.baseElemOf().isTypeStruct())
+ {
+ StructDeclaration sd = ts.sym;
+ if (sd.postblit || sd.hasCopyCtor)
+ {
+ /* Create a variable tmp, and replace the argument e with:
+ * (tmp = e),tmp
+ * and let AssignExp() handle the construction.
+ * This is not the most efficient, ideally tmp would be constructed
+ * directly onto the stack.
+ */
+ auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
+ if (sd.hasCopyCtor && destinationType)
+ tmp.type = destinationType;
+ tmp.storage_class |= STC.nodtor;
+ tmp.dsymbolSemantic(sc);
+ Expression de = new DeclarationExp(e.loc, tmp);
+ Expression ve = new VarExp(e.loc, tmp);
+ de.type = Type.tvoid;
+ ve.type = e.type;
+ return Expression.combine(de, ve);
+ }
+ }
+ return e;
+}
+
+/************************************************
+ * Handle the postblit call on lvalue, or the move of rvalue.
+ *
+ * Params:
+ * sc = the scope where the expression is encountered
+ * e = the expression the needs to be moved or copied (source)
+ * t = if the struct defines a copy constructor, the type of the destination
+ *
+ * Returns:
+ * The expression that copy constructs or moves the value.
+ */
+extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
+{
+ if (auto ce = e.isCondExp())
+ {
+ ce.e1 = doCopyOrMove(sc, ce.e1);
+ ce.e2 = doCopyOrMove(sc, ce.e2);
+ }
+ else
+ {
+ e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e);
+ }
+ return e;
+}
+
+/****************************************************************/
+/* A type meant as a union of all the Expression types,
+ * to serve essentially as a Variant that will sit on the stack
+ * during CTFE to reduce memory consumption.
+ */
+extern (C++) struct UnionExp
+{
+ // yes, default constructor does nothing
+ extern (D) this(Expression e)
+ {
+ memcpy(&this, cast(void*)e, e.size);
+ }
+
+ /* Extract pointer to Expression
+ */
+ extern (C++) Expression exp() return
+ {
+ return cast(Expression)&u;
+ }
+
+ /* Convert to an allocated Expression
+ */
+ extern (C++) Expression copy()
+ {
+ Expression e = exp();
+ //if (e.size > sizeof(u)) printf("%s\n", Token::toChars(e.op));
+ assert(e.size <= u.sizeof);
+ switch (e.op)
+ {
+ case TOK.cantExpression: return CTFEExp.cantexp;
+ case TOK.voidExpression: return CTFEExp.voidexp;
+ case TOK.break_: return CTFEExp.breakexp;
+ case TOK.continue_: return CTFEExp.continueexp;
+ case TOK.goto_: return CTFEExp.gotoexp;
+ default: return e.copy();
+ }
+ }
+
+private:
+ // Ensure that the union is suitably aligned.
+ align(8) union __AnonStruct__u
+ {
+ char[__traits(classInstanceSize, Expression)] exp;
+ char[__traits(classInstanceSize, IntegerExp)] integerexp;
+ char[__traits(classInstanceSize, ErrorExp)] errorexp;
+ char[__traits(classInstanceSize, RealExp)] realexp;
+ char[__traits(classInstanceSize, ComplexExp)] complexexp;
+ char[__traits(classInstanceSize, SymOffExp)] symoffexp;
+ char[__traits(classInstanceSize, StringExp)] stringexp;
+ char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp;
+ char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp;
+ char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp;
+ char[__traits(classInstanceSize, CompoundLiteralExp)] compoundliteralexp;
+ char[__traits(classInstanceSize, NullExp)] nullexp;
+ char[__traits(classInstanceSize, DotVarExp)] dotvarexp;
+ char[__traits(classInstanceSize, AddrExp)] addrexp;
+ char[__traits(classInstanceSize, IndexExp)] indexexp;
+ char[__traits(classInstanceSize, SliceExp)] sliceexp;
+ char[__traits(classInstanceSize, VectorExp)] vectorexp;
+ }
+
+ __AnonStruct__u u;
+}
+
+/********************************
+ * Test to see if two reals are the same.
+ * Regard NaN's as equivalent.
+ * Regard +0 and -0 as different.
+ * Params:
+ * x1 = first operand
+ * x2 = second operand
+ * Returns:
+ * true if x1 is x2
+ * else false
+ */
+bool RealIdentical(real_t x1, real_t x2)
+{
+ return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2);
+}
+
+/************************ TypeDotIdExp ************************************/
+/* Things like:
+ * int.size
+ * foo.size
+ * (foo).size
+ * cast(foo).size
+ */
+DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident)
+{
+ return new DotIdExp(loc, new TypeExp(loc, type), ident);
+}
+
+/***************************************************
+ * Given an Expression, find the variable it really is.
+ *
+ * For example, `a[index]` is really `a`, and `s.f` is really `s`.
+ * Params:
+ * e = Expression to look at
+ * Returns:
+ * variable if there is one, null if not
+ */
+VarDeclaration expToVariable(Expression e)
+{
+ while (1)
+ {
+ switch (e.op)
+ {
+ case TOK.variable:
+ return (cast(VarExp)e).var.isVarDeclaration();
+
+ case TOK.dotVariable:
+ e = (cast(DotVarExp)e).e1;
+ continue;
+
+ case TOK.index:
+ {
+ IndexExp ei = cast(IndexExp)e;
+ e = ei.e1;
+ Type ti = e.type.toBasetype();
+ if (ti.ty == Tsarray)
+ continue;
+ return null;
+ }
+
+ case TOK.slice:
+ {
+ SliceExp ei = cast(SliceExp)e;
+ e = ei.e1;
+ Type ti = e.type.toBasetype();
+ if (ti.ty == Tsarray)
+ continue;
+ return null;
+ }
+
+ case TOK.this_:
+ case TOK.super_:
+ return (cast(ThisExp)e).var.isVarDeclaration();
+
+ default:
+ return null;
+ }
+ }
+}
+
+enum OwnedBy : ubyte
+{
+ code, // normal code expression in AST
+ ctfe, // value expression for CTFE
+ cache, // constant value cached for CTFE
+}
+
+enum WANTvalue = 0; // default
+enum WANTexpand = 1; // expand const/immutable variables if possible
+
+/***********************************************************
+ * http://dlang.org/spec/expression.html#expression
+ */
+extern (C++) abstract class Expression : ASTNode
+{
+ const TOK op; // to minimize use of dynamic_cast
+ ubyte size; // # of bytes in Expression so we can copy() it
+ ubyte parens; // if this is a parenthesized expression
+ Type type; // !=null means that semantic() has been run
+ Loc loc; // file location
+
+ extern (D) this(const ref Loc loc, TOK op, int size)
+ {
+ //printf("Expression::Expression(op = %d) this = %p\n", op, this);
+ this.loc = loc;
+ this.op = op;
+ this.size = cast(ubyte)size;
+ }
+
+ static void _init()
+ {
+ CTFEExp.cantexp = new CTFEExp(TOK.cantExpression);
+ CTFEExp.voidexp = new CTFEExp(TOK.voidExpression);
+ CTFEExp.breakexp = new CTFEExp(TOK.break_);
+ CTFEExp.continueexp = new CTFEExp(TOK.continue_);
+ CTFEExp.gotoexp = new CTFEExp(TOK.goto_);
+ CTFEExp.showcontext = new CTFEExp(TOK.showCtfeContext);
+ }
+
+ /**
+ * Deinitializes the global state of the compiler.
+ *
+ * This can be used to restore the state set by `_init` to its original
+ * state.
+ */
+ static void deinitialize()
+ {
+ CTFEExp.cantexp = CTFEExp.cantexp.init;
+ CTFEExp.voidexp = CTFEExp.voidexp.init;
+ CTFEExp.breakexp = CTFEExp.breakexp.init;
+ CTFEExp.continueexp = CTFEExp.continueexp.init;
+ CTFEExp.gotoexp = CTFEExp.gotoexp.init;
+ CTFEExp.showcontext = CTFEExp.showcontext.init;
+ }
+
+ /*********************************
+ * Does *not* do a deep copy.
+ */
+ final Expression copy()
+ {
+ Expression e;
+ if (!size)
+ {
+ debug
+ {
+ fprintf(stderr, "No expression copy for: %s\n", toChars());
+ printf("op = %d\n", op);
+ }
+ assert(0);
+ }
+
+ // memory never freed, so can use the faster bump-pointer-allocation
+ e = cast(Expression)allocmemory(size);
+ //printf("Expression::copy(op = %d) e = %p\n", op, e);
+ return cast(Expression)memcpy(cast(void*)e, cast(void*)this, size);
+ }
+
+ Expression syntaxCopy()
+ {
+ //printf("Expression::syntaxCopy()\n");
+ //print();
+ return copy();
+ }
+
+ // kludge for template.isExpression()
+ override final DYNCAST dyncast() const
+ {
+ return DYNCAST.expression;
+ }
+
+ override const(char)* toChars() const
+ {
+ OutBuffer buf;
+ HdrGenState hgs;
+ toCBuffer(this, &buf, &hgs);
+ return buf.extractChars();
+ }
+
+ static if (__VERSION__ < 2092)
+ {
+ final void error(const(char)* format, ...) const
+ {
+ if (type != Type.terror)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .verror(loc, format, ap);
+ va_end(ap);
+ }
+ }
+
+ final void errorSupplemental(const(char)* format, ...)
+ {
+ if (type == Type.terror)
+ return;
+
+ va_list ap;
+ va_start(ap, format);
+ .verrorSupplemental(loc, format, ap);
+ va_end(ap);
+ }
+
+ final void warning(const(char)* format, ...) const
+ {
+ if (type != Type.terror)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .vwarning(loc, format, ap);
+ va_end(ap);
+ }
+ }
+
+ final void deprecation(const(char)* format, ...) const
+ {
+ if (type != Type.terror)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .vdeprecation(loc, format, ap);
+ va_end(ap);
+ }
+ }
+ }
+ else
+ {
+ pragma(printf) final void error(const(char)* format, ...) const
+ {
+ if (type != Type.terror)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .verror(loc, format, ap);
+ va_end(ap);
+ }
+ }
+
+ pragma(printf) final void errorSupplemental(const(char)* format, ...)
+ {
+ if (type == Type.terror)
+ return;
+
+ va_list ap;
+ va_start(ap, format);
+ .verrorSupplemental(loc, format, ap);
+ va_end(ap);
+ }
+
+ pragma(printf) final void warning(const(char)* format, ...) const
+ {
+ if (type != Type.terror)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .vwarning(loc, format, ap);
+ va_end(ap);
+ }
+ }
+
+ pragma(printf) final void deprecation(const(char)* format, ...) const
+ {
+ if (type != Type.terror)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .vdeprecation(loc, format, ap);
+ va_end(ap);
+ }
+ }
+ }
+
+ /**********************************
+ * Combine e1 and e2 by CommaExp if both are not NULL.
+ */
+ extern (D) static Expression combine(Expression e1, Expression e2)
+ {
+ if (e1)
+ {
+ if (e2)
+ {
+ e1 = new CommaExp(e1.loc, e1, e2);
+ e1.type = e2.type;
+ }
+ }
+ else
+ e1 = e2;
+ return e1;
+ }
+
+ extern (D) static Expression combine(Expression e1, Expression e2, Expression e3)
+ {
+ return combine(combine(e1, e2), e3);
+ }
+
+ extern (D) static Expression combine(Expression e1, Expression e2, Expression e3, Expression e4)
+ {
+ return combine(combine(e1, e2), combine(e3, e4));
+ }
+
+ /**********************************
+ * If 'e' is a tree of commas, returns the rightmost expression
+ * by stripping off it from the tree. The remained part of the tree
+ * is returned via e0.
+ * Otherwise 'e' is directly returned and e0 is set to NULL.
+ */
+ extern (D) static Expression extractLast(Expression e, out Expression e0)
+ {
+ if (e.op != TOK.comma)
+ {
+ return e;
+ }
+
+ CommaExp ce = cast(CommaExp)e;
+ if (ce.e2.op != TOK.comma)
+ {
+ e0 = ce.e1;
+ return ce.e2;
+ }
+ else
+ {
+ e0 = e;
+
+ Expression* pce = &ce.e2;
+ while ((cast(CommaExp)(*pce)).e2.op == TOK.comma)
+ {
+ pce = &(cast(CommaExp)(*pce)).e2;
+ }
+ assert((*pce).op == TOK.comma);
+ ce = cast(CommaExp)(*pce);
+ *pce = ce.e1;
+
+ return ce.e2;
+ }
+ }
+
+ extern (D) static Expressions* arraySyntaxCopy(Expressions* exps)
+ {
+ Expressions* a = null;
+ if (exps)
+ {
+ a = new Expressions(exps.dim);
+ foreach (i, e; *exps)
+ {
+ (*a)[i] = e ? e.syntaxCopy() : null;
+ }
+ }
+ return a;
+ }
+
+ dinteger_t toInteger()
+ {
+ //printf("Expression %s\n", Token::toChars(op));
+ error("integer constant expression expected instead of `%s`", toChars());
+ return 0;
+ }
+
+ uinteger_t toUInteger()
+ {
+ //printf("Expression %s\n", Token::toChars(op));
+ return cast(uinteger_t)toInteger();
+ }
+
+ real_t toReal()
+ {
+ error("floating point constant expression expected instead of `%s`", toChars());
+ return CTFloat.zero;
+ }
+
+ real_t toImaginary()
+ {
+ error("floating point constant expression expected instead of `%s`", toChars());
+ return CTFloat.zero;
+ }
+
+ complex_t toComplex()
+ {
+ error("floating point constant expression expected instead of `%s`", toChars());
+ return complex_t(CTFloat.zero);
+ }
+
+ StringExp toStringExp()
+ {
+ return null;
+ }
+
+ TupleExp toTupleExp()
+ {
+ return null;
+ }
+
+ /***************************************
+ * Return !=0 if expression is an lvalue.
+ */
+ bool isLvalue()
+ {
+ return false;
+ }
+
+ /*******************************
+ * Give error if we're not an lvalue.
+ * If we can, convert expression to be an lvalue.
+ */
+ Expression toLvalue(Scope* sc, Expression e)
+ {
+ if (!e)
+ e = this;
+ else if (!loc.isValid())
+ loc = e.loc;
+
+ if (e.op == TOK.type)
+ error("`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind());
+ else
+ error("`%s` is not an lvalue and cannot be modified", e.toChars());
+
+ return ErrorExp.get();
+ }
+
+ Expression modifiableLvalue(Scope* sc, Expression e)
+ {
+ //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type.toChars());
+ // See if this expression is a modifiable lvalue (i.e. not const)
+ if (checkModifiable(this, sc) == Modifiable.yes)
+ {
+ assert(type);
+ if (!type.isMutable())
+ {
+ if (auto dve = this.isDotVarExp())
+ {
+ if (isNeedThisScope(sc, dve.var))
+ for (Dsymbol s = sc.func; s; s = s.toParentLocal())
+ {
+ FuncDeclaration ff = s.isFuncDeclaration();
+ if (!ff)
+ break;
+ if (!ff.type.isMutable)
+ {
+ error("cannot modify `%s` in `%s` function", toChars(), MODtoChars(type.mod));
+ return ErrorExp.get();
+ }
+ }
+ }
+ error("cannot modify `%s` expression `%s`", MODtoChars(type.mod), toChars());
+ return ErrorExp.get();
+ }
+ else if (!type.isAssignable())
+ {
+ error("cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
+ toChars(), type.toChars());
+ return ErrorExp.get();
+ }
+ }
+ return toLvalue(sc, e);
+ }
+
+ final Expression implicitCastTo(Scope* sc, Type t)
+ {
+ return .implicitCastTo(this, sc, t);
+ }
+
+ final MATCH implicitConvTo(Type t)
+ {
+ return .implicitConvTo(this, t);
+ }
+
+ final Expression castTo(Scope* sc, Type t)
+ {
+ return .castTo(this, sc, t);
+ }
+
+ /****************************************
+ * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
+ */
+ Expression resolveLoc(const ref Loc loc, Scope* sc)
+ {
+ this.loc = loc;
+ return this;
+ }
+
+ /****************************************
+ * Check that the expression has a valid type.
+ * If not, generates an error "... has no type".
+ * Returns:
+ * true if the expression is not valid.
+ * Note:
+ * When this function returns true, `checkValue()` should also return true.
+ */
+ bool checkType()
+ {
+ return false;
+ }
+
+ /****************************************
+ * Check that the expression has a valid value.
+ * If not, generates an error "... has no value".
+ * Returns:
+ * true if the expression is not valid or has void type.
+ */
+ bool checkValue()
+ {
+ if (type && type.toBasetype().ty == Tvoid)
+ {
+ error("expression `%s` is `void` and has no value", toChars());
+ //print(); assert(0);
+ if (!global.gag)
+ type = Type.terror;
+ return true;
+ }
+ return false;
+ }
+
+ extern (D) final bool checkScalar()
+ {
+ if (op == TOK.error)
+ return true;
+ if (type.toBasetype().ty == Terror)
+ return true;
+ if (!type.isscalar())
+ {
+ error("`%s` is not a scalar, it is a `%s`", toChars(), type.toChars());
+ return true;
+ }
+ return checkValue();
+ }
+
+ extern (D) final bool checkNoBool()
+ {
+ if (op == TOK.error)
+ return true;
+ if (type.toBasetype().ty == Terror)
+ return true;
+ if (type.toBasetype().ty == Tbool)
+ {
+ error("operation not allowed on `bool` `%s`", toChars());
+ return true;
+ }
+ return false;
+ }
+
+ extern (D) final bool checkIntegral()
+ {
+ if (op == TOK.error)
+ return true;
+ if (type.toBasetype().ty == Terror)
+ return true;
+ if (!type.isintegral())
+ {
+ error("`%s` is not of integral type, it is a `%s`", toChars(), type.toChars());
+ return true;
+ }
+ return checkValue();
+ }
+
+ extern (D) final bool checkArithmetic()
+ {
+ if (op == TOK.error)
+ return true;
+ if (type.toBasetype().ty == Terror)
+ return true;
+ if (!type.isintegral() && !type.isfloating())
+ {
+ error("`%s` is not of arithmetic type, it is a `%s`", toChars(), type.toChars());
+ return true;
+ }
+ return checkValue();
+ }
+
+ final bool checkDeprecated(Scope* sc, Dsymbol s)
+ {
+ return s.checkDeprecated(loc, sc);
+ }
+
+ extern (D) final bool checkDisabled(Scope* sc, Dsymbol s)
+ {
+ if (auto d = s.isDeclaration())
+ {
+ return d.checkDisabled(loc, sc);
+ }
+
+ return false;
+ }
+
+ /*********************************************
+ * Calling function f.
+ * Check the purity, i.e. if we're in a pure function
+ * we can only call other pure functions.
+ * Returns true if error occurs.
+ */
+ extern (D) final bool checkPurity(Scope* sc, FuncDeclaration f)
+ {
+ if (!sc.func)
+ return false;
+ if (sc.func == f)
+ return false;
+ if (sc.intypeof == 1)
+ return false;
+ if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
+ return false;
+
+ // If the call has a pure parent, then the called func must be pure.
+ if (!f.isPure() && checkImpure(sc))
+ {
+ error("`pure` %s `%s` cannot call impure %s `%s`",
+ sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
+ f.toPrettyChars());
+
+ checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure");
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one
+ * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but
+ * the generated dtor is not).
+ * In that case the method will identify and print all members causing the attribute
+ * missmatch.
+ *
+ * Params:
+ * sc = scope
+ * f = potential `DtorDeclaration`
+ * check = current check (e.g. whether it's pure)
+ * checkName = the kind of check (e.g. `"pure"`)
+ */
+ extern (D) final void checkOverridenDtor(Scope* sc, FuncDeclaration f,
+ scope bool function(DtorDeclaration) check, const string checkName
+ ) {
+ auto dd = f.isDtorDeclaration();
+ if (!dd || !dd.generated)
+ return;
+
+ // DtorDeclaration without parents should fail at an earlier stage
+ auto ad = cast(AggregateDeclaration) f.toParent2();
+ assert(ad);
+ assert(ad.dtors.length);
+
+ // Search for the user-defined destructor (if any)
+ foreach(dtor; ad.dtors)
+ {
+ if (dtor.generated)
+ continue;
+
+ if (!check(dtor)) // doesn't match check (e.g. is impure as well)
+ return;
+
+ // Sanity check
+ assert(!check(cast(DtorDeclaration) ad.fieldDtor));
+ break;
+ }
+
+ dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
+ dd.generated ? "generated " : "".ptr,
+ ad.toChars,
+ cast(int) checkName.length, checkName.ptr);
+
+ // Search for the offending fields
+ foreach (field; ad.fields)
+ {
+ // Only structs may define automatically called destructors
+ auto ts = field.type.isTypeStruct();
+ if (!ts)
+ {
+ // But they might be part of a static array
+ auto ta = field.type.isTypeSArray();
+ if (!ta)
+ continue;
+
+ ts = ta.baseElemOf().isTypeStruct();
+ if (!ts)
+ continue;
+ }
+
+ auto fieldSym = ts.toDsymbol(sc);
+ assert(fieldSym); // Resolving ts must succeed because missing defs. should error before
+
+ auto fieldSd = fieldSym.isStructDeclaration();
+ assert(fieldSd); // ts is a TypeStruct, this would imply a malformed ASR
+
+ if (fieldSd.dtor && !check(fieldSd.dtor))
+ {
+ field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars());
+
+ if (fieldSd.dtor.generated)
+ checkOverridenDtor(sc, fieldSd.dtor, check, checkName);
+ else
+ fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here",
+ cast(int) checkName.length, checkName.ptr, fieldSd.toChars());
+ }
+ }
+ }
+
+ /*******************************************
+ * Accessing variable v.
+ * Check for purity and safety violations.
+ * Returns true if error occurs.
+ */
+ extern (D) final bool checkPurity(Scope* sc, VarDeclaration v)
+ {
+ //printf("v = %s %s\n", v.type.toChars(), v.toChars());
+ /* Look for purity and safety violations when accessing variable v
+ * from current function.
+ */
+ if (!sc.func)
+ return false;
+ if (sc.intypeof == 1)
+ return false; // allow violations inside typeof(expression)
+ if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
+ return false; // allow violations inside compile-time evaluated expressions and debug conditionals
+ if (v.ident == Id.ctfe)
+ return false; // magic variable never violates pure and safe
+ if (v.isImmutable())
+ return false; // always safe and pure to access immutables...
+ if (v.isConst() && !v.isRef() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
+ return false; // or const global/parameter values which have no mutable indirections
+ if (v.storage_class & STC.manifest)
+ return false; // ...or manifest constants
+
+ // accessing empty structs is pure
+ if (v.type.ty == Tstruct)
+ {
+ StructDeclaration sd = (cast(TypeStruct)v.type).sym;
+ if (sd.members) // not opaque
+ {
+ sd.determineSize(v.loc);
+ if (sd.hasNoFields)
+ return false;
+ }
+ }
+
+ bool err = false;
+ if (v.isDataseg())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=7533
+ // Accessing implicit generated __gate is pure.
+ if (v.ident == Id.gate)
+ return false;
+
+ if (checkImpure(sc))
+ {
+ error("`pure` %s `%s` cannot access mutable static data `%s`",
+ sc.func.kind(), sc.func.toPrettyChars(), v.toChars());
+ err = true;
+ }
+ }
+ else
+ {
+ /* Given:
+ * void f() {
+ * int fx;
+ * pure void g() {
+ * int gx;
+ * /+pure+/ void h() {
+ * int hx;
+ * /+pure+/ void i() { }
+ * }
+ * }
+ * }
+ * i() can modify hx and gx but not fx
+ */
+
+ Dsymbol vparent = v.toParent2();
+ for (Dsymbol s = sc.func; !err && s; s = s.toParentP(vparent))
+ {
+ if (s == vparent)
+ break;
+
+ if (AggregateDeclaration ad = s.isAggregateDeclaration())
+ {
+ if (ad.isNested())
+ continue;
+ break;
+ }
+ FuncDeclaration ff = s.isFuncDeclaration();
+ if (!ff)
+ break;
+ if (ff.isNested() || ff.isThis())
+ {
+ if (ff.type.isImmutable() ||
+ ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
+ {
+ OutBuffer ffbuf;
+ OutBuffer vbuf;
+ MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
+ MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
+ error("%s%s `%s` cannot access %sdata `%s`",
+ ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
+ err = true;
+ break;
+ }
+ continue;
+ }
+ break;
+ }
+ }
+
+ /* Do not allow safe functions to access __gshared data
+ */
+ if (v.storage_class & STC.gshared)
+ {
+ if (sc.func.setUnsafe())
+ {
+ error("`@safe` %s `%s` cannot access `__gshared` data `%s`",
+ sc.func.kind(), sc.func.toChars(), v.toChars());
+ err = true;
+ }
+ }
+
+ return err;
+ }
+
+ /*
+ Check if sc.func is impure or can be made impure.
+ Returns true on error, i.e. if sc.func is pure and cannot be made impure.
+ */
+ private static bool checkImpure(Scope* sc)
+ {
+ return sc.func && (sc.flags & SCOPE.compile
+ ? sc.func.isPureBypassingInference() >= PURE.weak
+ : sc.func.setImpure());
+ }
+
+ /*********************************************
+ * Calling function f.
+ * Check the safety, i.e. if we're in a @safe function
+ * we can only call @safe or @trusted functions.
+ * Returns true if error occurs.
+ */
+ extern (D) final bool checkSafety(Scope* sc, FuncDeclaration f)
+ {
+ if (!sc.func)
+ return false;
+ if (sc.func == f)
+ return false;
+ if (sc.intypeof == 1)
+ return false;
+ if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
+ return false;
+
+ if (!f.isSafe() && !f.isTrusted())
+ {
+ if (sc.flags & SCOPE.compile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafe())
+ {
+ if (!loc.isValid()) // e.g. implicitly generated dtor
+ loc = sc.func.loc;
+
+ const prettyChars = f.toPrettyChars();
+ error("`@safe` %s `%s` cannot call `@system` %s `%s`",
+ sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
+ prettyChars);
+ .errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
+
+ checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system");
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /*********************************************
+ * Calling function f.
+ * Check the @nogc-ness, i.e. if we're in a @nogc function
+ * we can only call other @nogc functions.
+ * Returns true if error occurs.
+ */
+ extern (D) final bool checkNogc(Scope* sc, FuncDeclaration f)
+ {
+ if (!sc.func)
+ return false;
+ if (sc.func == f)
+ return false;
+ if (sc.intypeof == 1)
+ return false;
+ if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
+ return false;
+
+ if (!f.isNogc())
+ {
+ if (sc.flags & SCOPE.compile ? sc.func.isNogcBypassingInference() : sc.func.setGC())
+ {
+ if (loc.linnum == 0) // e.g. implicitly generated dtor
+ loc = sc.func.loc;
+
+ // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
+ // so don't print anything to avoid double error messages.
+ if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT))
+ error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
+ sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
+
+ checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().isnogc, "non-@nogc");
+
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /********************************************
+ * Check that the postblit is callable if t is an array of structs.
+ * Returns true if error happens.
+ */
+ extern (D) final bool checkPostblit(Scope* sc, Type t)
+ {
+ if (auto ts = t.baseElemOf().isTypeStruct())
+ {
+ if (global.params.useTypeInfo && Type.dtypeinfo)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=11395
+ // Require TypeInfo generation for array concatenation
+ semanticTypeInfo(sc, t);
+ }
+
+ StructDeclaration sd = ts.sym;
+ if (sd.postblit)
+ {
+ if (sd.postblit.checkDisabled(loc, sc))
+ return true;
+
+ //checkDeprecated(sc, sd.postblit); // necessary?
+ checkPurity(sc, sd.postblit);
+ checkSafety(sc, sd.postblit);
+ checkNogc(sc, sd.postblit);
+ //checkAccess(sd, loc, sc, sd.postblit); // necessary?
+ return false;
+ }
+ }
+ return false;
+ }
+
+ extern (D) final bool checkRightThis(Scope* sc)
+ {
+ if (op == TOK.error)
+ return true;
+ if (op == TOK.variable && type.ty != Terror)
+ {
+ VarExp ve = cast(VarExp)this;
+ if (isNeedThisScope(sc, ve.var))
+ {
+ //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
+ // sc.intypeof, sc.getStructClassScope(), func, fdthis);
+ error("need `this` for `%s` of type `%s`", ve.var.toChars(), ve.var.type.toChars());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /*******************************
+ * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
+ * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
+ * Returns true if error occurs.
+ */
+ extern (D) final bool checkReadModifyWrite(TOK rmwOp, Expression ex = null)
+ {
+ //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
+ if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
+ return false;
+
+ // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
+ switch (rmwOp)
+ {
+ case TOK.plusPlus:
+ case TOK.prePlusPlus:
+ rmwOp = TOK.addAssign;
+ break;
+ case TOK.minusMinus:
+ case TOK.preMinusMinus:
+ rmwOp = TOK.minAssign;
+ break;
+ default:
+ break;
+ }
+
+ error("read-modify-write operations are not allowed for `shared` variables");
+ errorSupplemental("Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
+ Token.toChars(rmwOp), toChars(), ex ? ex.toChars() : "1");
+ return true;
+ }
+
+ /************************************************
+ * Destructors are attached to VarDeclarations.
+ * Hence, if expression returns a temp that needs a destructor,
+ * make sure and create a VarDeclaration for that temp.
+ */
+ Expression addDtorHook(Scope* sc)
+ {
+ return this;
+ }
+
+ /******************************
+ * Take address of expression.
+ */
+ final Expression addressOf()
+ {
+ //printf("Expression::addressOf()\n");
+ debug
+ {
+ assert(op == TOK.error || isLvalue());
+ }
+ Expression e = new AddrExp(loc, this, type.pointerTo());
+ return e;
+ }
+
+ /******************************
+ * If this is a reference, dereference it.
+ */
+ final Expression deref()
+ {
+ //printf("Expression::deref()\n");
+ // type could be null if forward referencing an 'auto' variable
+ if (type)
+ if (auto tr = type.isTypeReference())
+ {
+ Expression e = new PtrExp(loc, this, tr.next);
+ return e;
+ }
+ return this;
+ }
+
+ final Expression optimize(int result, bool keepLvalue = false)
+ {
+ return Expression_optimize(this, result, keepLvalue);
+ }
+
+ // Entry point for CTFE.
+ // A compile-time result is required. Give an error if not possible
+ final Expression ctfeInterpret()
+ {
+ return .ctfeInterpret(this);
+ }
+
+ final int isConst()
+ {
+ return .isConst(this);
+ }
+
+ /********************************
+ * Does this expression statically evaluate to a boolean 'result' (true or false)?
+ */
+ bool isBool(bool result)
+ {
+ return false;
+ }
+
+ bool hasCode()
+ {
+ return true;
+ }
+
+ final pure inout nothrow @nogc @safe
+ {
+ inout(IntegerExp) isIntegerExp() { return op == TOK.int64 ? cast(typeof(return))this : null; }
+ inout(ErrorExp) isErrorExp() { return op == TOK.error ? cast(typeof(return))this : null; }
+ inout(VoidInitExp) isVoidInitExp() { return op == TOK.void_ ? cast(typeof(return))this : null; }
+ inout(RealExp) isRealExp() { return op == TOK.float64 ? cast(typeof(return))this : null; }
+ inout(ComplexExp) isComplexExp() { return op == TOK.complex80 ? cast(typeof(return))this : null; }
+ inout(IdentifierExp) isIdentifierExp() { return op == TOK.identifier ? cast(typeof(return))this : null; }
+ inout(DollarExp) isDollarExp() { return op == TOK.dollar ? cast(typeof(return))this : null; }
+ inout(DsymbolExp) isDsymbolExp() { return op == TOK.dSymbol ? cast(typeof(return))this : null; }
+ inout(ThisExp) isThisExp() { return op == TOK.this_ ? cast(typeof(return))this : null; }
+ inout(SuperExp) isSuperExp() { return op == TOK.super_ ? cast(typeof(return))this : null; }
+ inout(NullExp) isNullExp() { return op == TOK.null_ ? cast(typeof(return))this : null; }
+ inout(StringExp) isStringExp() { return op == TOK.string_ ? cast(typeof(return))this : null; }
+ inout(TupleExp) isTupleExp() { return op == TOK.tuple ? cast(typeof(return))this : null; }
+ inout(ArrayLiteralExp) isArrayLiteralExp() { return op == TOK.arrayLiteral ? cast(typeof(return))this : null; }
+ inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == TOK.assocArrayLiteral ? cast(typeof(return))this : null; }
+ inout(StructLiteralExp) isStructLiteralExp() { return op == TOK.structLiteral ? cast(typeof(return))this : null; }
+ inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == TOK.compoundLiteral ? cast(typeof(return))this : null; }
+ inout(TypeExp) isTypeExp() { return op == TOK.type ? cast(typeof(return))this : null; }
+ inout(ScopeExp) isScopeExp() { return op == TOK.scope_ ? cast(typeof(return))this : null; }
+ inout(TemplateExp) isTemplateExp() { return op == TOK.template_ ? cast(typeof(return))this : null; }
+ inout(NewExp) isNewExp() { return op == TOK.new_ ? cast(typeof(return))this : null; }
+ inout(NewAnonClassExp) isNewAnonClassExp() { return op == TOK.newAnonymousClass ? cast(typeof(return))this : null; }
+ inout(SymOffExp) isSymOffExp() { return op == TOK.symbolOffset ? cast(typeof(return))this : null; }
+ inout(VarExp) isVarExp() { return op == TOK.variable ? cast(typeof(return))this : null; }
+ inout(OverExp) isOverExp() { return op == TOK.overloadSet ? cast(typeof(return))this : null; }
+ inout(FuncExp) isFuncExp() { return op == TOK.function_ ? cast(typeof(return))this : null; }
+ inout(DeclarationExp) isDeclarationExp() { return op == TOK.declaration ? cast(typeof(return))this : null; }
+ inout(TypeidExp) isTypeidExp() { return op == TOK.typeid_ ? cast(typeof(return))this : null; }
+ inout(TraitsExp) isTraitsExp() { return op == TOK.traits ? cast(typeof(return))this : null; }
+ inout(HaltExp) isHaltExp() { return op == TOK.halt ? cast(typeof(return))this : null; }
+ inout(IsExp) isExp() { return op == TOK.is_ ? cast(typeof(return))this : null; }
+ inout(MixinExp) isMixinExp() { return op == TOK.mixin_ ? cast(typeof(return))this : null; }
+ inout(ImportExp) isImportExp() { return op == TOK.import_ ? cast(typeof(return))this : null; }
+ inout(AssertExp) isAssertExp() { return op == TOK.assert_ ? cast(typeof(return))this : null; }
+ inout(DotIdExp) isDotIdExp() { return op == TOK.dotIdentifier ? cast(typeof(return))this : null; }
+ inout(DotTemplateExp) isDotTemplateExp() { return op == TOK.dotTemplateDeclaration ? cast(typeof(return))this : null; }
+ inout(DotVarExp) isDotVarExp() { return op == TOK.dotVariable ? cast(typeof(return))this : null; }
+ inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == TOK.dotTemplateInstance ? cast(typeof(return))this : null; }
+ inout(DelegateExp) isDelegateExp() { return op == TOK.delegate_ ? cast(typeof(return))this : null; }
+ inout(DotTypeExp) isDotTypeExp() { return op == TOK.dotType ? cast(typeof(return))this : null; }
+ inout(CallExp) isCallExp() { return op == TOK.call ? cast(typeof(return))this : null; }
+ inout(AddrExp) isAddrExp() { return op == TOK.address ? cast(typeof(return))this : null; }
+ inout(PtrExp) isPtrExp() { return op == TOK.star ? cast(typeof(return))this : null; }
+ inout(NegExp) isNegExp() { return op == TOK.negate ? cast(typeof(return))this : null; }
+ inout(UAddExp) isUAddExp() { return op == TOK.uadd ? cast(typeof(return))this : null; }
+ inout(ComExp) isComExp() { return op == TOK.tilde ? cast(typeof(return))this : null; }
+ inout(NotExp) isNotExp() { return op == TOK.not ? cast(typeof(return))this : null; }
+ inout(DeleteExp) isDeleteExp() { return op == TOK.delete_ ? cast(typeof(return))this : null; }
+ inout(CastExp) isCastExp() { return op == TOK.cast_ ? cast(typeof(return))this : null; }
+ inout(VectorExp) isVectorExp() { return op == TOK.vector ? cast(typeof(return))this : null; }
+ inout(VectorArrayExp) isVectorArrayExp() { return op == TOK.vectorArray ? cast(typeof(return))this : null; }
+ inout(SliceExp) isSliceExp() { return op == TOK.slice ? cast(typeof(return))this : null; }
+ inout(ArrayLengthExp) isArrayLengthExp() { return op == TOK.arrayLength ? cast(typeof(return))this : null; }
+ inout(ArrayExp) isArrayExp() { return op == TOK.array ? cast(typeof(return))this : null; }
+ inout(DotExp) isDotExp() { return op == TOK.dot ? cast(typeof(return))this : null; }
+ inout(CommaExp) isCommaExp() { return op == TOK.comma ? cast(typeof(return))this : null; }
+ inout(IntervalExp) isIntervalExp() { return op == TOK.interval ? cast(typeof(return))this : null; }
+ inout(DelegatePtrExp) isDelegatePtrExp() { return op == TOK.delegatePointer ? cast(typeof(return))this : null; }
+ inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == TOK.delegateFunctionPointer ? cast(typeof(return))this : null; }
+ inout(IndexExp) isIndexExp() { return op == TOK.index ? cast(typeof(return))this : null; }
+ inout(PostExp) isPostExp() { return (op == TOK.plusPlus || op == TOK.minusMinus) ? cast(typeof(return))this : null; }
+ inout(PreExp) isPreExp() { return (op == TOK.prePlusPlus || op == TOK.preMinusMinus) ? cast(typeof(return))this : null; }
+ inout(AssignExp) isAssignExp() { return op == TOK.assign ? cast(typeof(return))this : null; }
+ inout(ConstructExp) isConstructExp() { return op == TOK.construct ? cast(typeof(return))this : null; }
+ inout(BlitExp) isBlitExp() { return op == TOK.blit ? cast(typeof(return))this : null; }
+ inout(AddAssignExp) isAddAssignExp() { return op == TOK.addAssign ? cast(typeof(return))this : null; }
+ inout(MinAssignExp) isMinAssignExp() { return op == TOK.minAssign ? cast(typeof(return))this : null; }
+ inout(MulAssignExp) isMulAssignExp() { return op == TOK.mulAssign ? cast(typeof(return))this : null; }
+
+ inout(DivAssignExp) isDivAssignExp() { return op == TOK.divAssign ? cast(typeof(return))this : null; }
+ inout(ModAssignExp) isModAssignExp() { return op == TOK.modAssign ? cast(typeof(return))this : null; }
+ inout(AndAssignExp) isAndAssignExp() { return op == TOK.andAssign ? cast(typeof(return))this : null; }
+ inout(OrAssignExp) isOrAssignExp() { return op == TOK.orAssign ? cast(typeof(return))this : null; }
+ inout(XorAssignExp) isXorAssignExp() { return op == TOK.xorAssign ? cast(typeof(return))this : null; }
+ inout(PowAssignExp) isPowAssignExp() { return op == TOK.powAssign ? cast(typeof(return))this : null; }
+
+ inout(ShlAssignExp) isShlAssignExp() { return op == TOK.leftShiftAssign ? cast(typeof(return))this : null; }
+ inout(ShrAssignExp) isShrAssignExp() { return op == TOK.rightShiftAssign ? cast(typeof(return))this : null; }
+ inout(UshrAssignExp) isUshrAssignExp() { return op == TOK.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
+
+ inout(CatAssignExp) isCatAssignExp() { return op == TOK.concatenateAssign
+ ? cast(typeof(return))this
+ : null; }
+
+ inout(CatElemAssignExp) isCatElemAssignExp() { return op == TOK.concatenateElemAssign
+ ? cast(typeof(return))this
+ : null; }
+
+ inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == TOK.concatenateDcharAssign
+ ? cast(typeof(return))this
+ : null; }
+
+ inout(AddExp) isAddExp() { return op == TOK.add ? cast(typeof(return))this : null; }
+ inout(MinExp) isMinExp() { return op == TOK.min ? cast(typeof(return))this : null; }
+ inout(CatExp) isCatExp() { return op == TOK.concatenate ? cast(typeof(return))this : null; }
+ inout(MulExp) isMulExp() { return op == TOK.mul ? cast(typeof(return))this : null; }
+ inout(DivExp) isDivExp() { return op == TOK.div ? cast(typeof(return))this : null; }
+ inout(ModExp) isModExp() { return op == TOK.mod ? cast(typeof(return))this : null; }
+ inout(PowExp) isPowExp() { return op == TOK.pow ? cast(typeof(return))this : null; }
+ inout(ShlExp) isShlExp() { return op == TOK.leftShift ? cast(typeof(return))this : null; }
+ inout(ShrExp) isShrExp() { return op == TOK.rightShift ? cast(typeof(return))this : null; }
+ inout(UshrExp) isUshrExp() { return op == TOK.unsignedRightShift ? cast(typeof(return))this : null; }
+ inout(AndExp) isAndExp() { return op == TOK.and ? cast(typeof(return))this : null; }
+ inout(OrExp) isOrExp() { return op == TOK.or ? cast(typeof(return))this : null; }
+ inout(XorExp) isXorExp() { return op == TOK.xor ? cast(typeof(return))this : null; }
+ inout(LogicalExp) isLogicalExp() { return (op == TOK.andAnd || op == TOK.orOr) ? cast(typeof(return))this : null; }
+ //inout(CmpExp) isCmpExp() { return op == TOK. ? cast(typeof(return))this : null; }
+ inout(InExp) isInExp() { return op == TOK.in_ ? cast(typeof(return))this : null; }
+ inout(RemoveExp) isRemoveExp() { return op == TOK.remove ? cast(typeof(return))this : null; }
+ inout(EqualExp) isEqualExp() { return (op == TOK.equal || op == TOK.notEqual) ? cast(typeof(return))this : null; }
+ inout(IdentityExp) isIdentityExp() { return (op == TOK.identity || op == TOK.notIdentity) ? cast(typeof(return))this : null; }
+ inout(CondExp) isCondExp() { return op == TOK.question ? cast(typeof(return))this : null; }
+ inout(GenericExp) isGenericExp() { return op == TOK._Generic ? cast(typeof(return))this : null; }
+ inout(DefaultInitExp) isDefaultInitExp() { return isDefaultInitOp(op) ? cast(typeof(return))this: null; }
+ inout(FileInitExp) isFileInitExp() { return (op == TOK.file || op == TOK.fileFullPath) ? cast(typeof(return))this : null; }
+ inout(LineInitExp) isLineInitExp() { return op == TOK.line ? cast(typeof(return))this : null; }
+ inout(ModuleInitExp) isModuleInitExp() { return op == TOK.moduleString ? cast(typeof(return))this : null; }
+ inout(FuncInitExp) isFuncInitExp() { return op == TOK.functionString ? cast(typeof(return))this : null; }
+ inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == TOK.prettyFunction ? cast(typeof(return))this : null; }
+ inout(ClassReferenceExp) isClassReferenceExp() { return op == TOK.classReference ? cast(typeof(return))this : null; }
+ inout(ThrownExceptionExp) isThrownExceptionExp() { return op == TOK.thrownException ? cast(typeof(return))this : null; }
+ }
+
+ inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
+ {
+ return null;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class IntegerExp : Expression
+{
+ private dinteger_t value;
+
+ extern (D) this(const ref Loc loc, dinteger_t value, Type type)
+ {
+ super(loc, TOK.int64, __traits(classInstanceSize, IntegerExp));
+ //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
+ assert(type);
+ if (!type.isscalar())
+ {
+ //printf("%s, loc = %d\n", toChars(), loc.linnum);
+ if (type.ty != Terror)
+ error("integral constant must be scalar type, not `%s`", type.toChars());
+ type = Type.terror;
+ }
+ this.type = type;
+ this.value = normalize(type.toBasetype().ty, value);
+ }
+
+ extern (D) this(dinteger_t value)
+ {
+ super(Loc.initial, TOK.int64, __traits(classInstanceSize, IntegerExp));
+ this.type = Type.tint32;
+ this.value = cast(d_int32)value;
+ }
+
+ static IntegerExp create(Loc loc, dinteger_t value, Type type)
+ {
+ return new IntegerExp(loc, value, type);
+ }
+
+ // Same as create, but doesn't allocate memory.
+ static void emplace(UnionExp* pue, Loc loc, dinteger_t value, Type type)
+ {
+ emplaceExp!(IntegerExp)(pue, loc, value, type);
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+ if (auto ne = (cast(Expression)o).isIntegerExp())
+ {
+ if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && value == ne.value)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ override dinteger_t toInteger()
+ {
+ // normalize() is necessary until we fix all the paints of 'type'
+ return value = normalize(type.toBasetype().ty, value);
+ }
+
+ override real_t toReal()
+ {
+ // normalize() is necessary until we fix all the paints of 'type'
+ const ty = type.toBasetype().ty;
+ const val = normalize(ty, value);
+ value = val;
+ return (ty == Tuns64)
+ ? real_t(cast(d_uns64)val)
+ : real_t(cast(d_int64)val);
+ }
+
+ override real_t toImaginary()
+ {
+ return CTFloat.zero;
+ }
+
+ override complex_t toComplex()
+ {
+ return complex_t(toReal());
+ }
+
+ override bool isBool(bool result)
+ {
+ bool r = toInteger() != 0;
+ return result ? r : !r;
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ if (!e)
+ e = this;
+ else if (!loc.isValid())
+ loc = e.loc;
+ e.error("cannot modify constant `%s`", e.toChars());
+ return ErrorExp.get();
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ dinteger_t getInteger()
+ {
+ return value;
+ }
+
+ void setInteger(dinteger_t value)
+ {
+ this.value = normalize(type.toBasetype().ty, value);
+ }
+
+ extern (D) static dinteger_t normalize(TY ty, dinteger_t value)
+ {
+ /* 'Normalize' the value of the integer to be in range of the type
+ */
+ dinteger_t result;
+ switch (ty)
+ {
+ case Tbool:
+ result = (value != 0);
+ break;
+
+ case Tint8:
+ result = cast(d_int8)value;
+ break;
+
+ case Tchar:
+ case Tuns8:
+ result = cast(d_uns8)value;
+ break;
+
+ case Tint16:
+ result = cast(d_int16)value;
+ break;
+
+ case Twchar:
+ case Tuns16:
+ result = cast(d_uns16)value;
+ break;
+
+ case Tint32:
+ result = cast(d_int32)value;
+ break;
+
+ case Tdchar:
+ case Tuns32:
+ result = cast(d_uns32)value;
+ break;
+
+ case Tint64:
+ result = cast(d_int64)value;
+ break;
+
+ case Tuns64:
+ result = cast(d_uns64)value;
+ break;
+
+ case Tpointer:
+ if (target.ptrsize == 8)
+ goto case Tuns64;
+ if (target.ptrsize == 4)
+ goto case Tuns32;
+ if (target.ptrsize == 2)
+ goto case Tuns16;
+ assert(0);
+
+ default:
+ break;
+ }
+ return result;
+ }
+
+ override IntegerExp syntaxCopy()
+ {
+ return this;
+ }
+
+ /**
+ * Use this instead of creating new instances for commonly used literals
+ * such as 0 or 1.
+ *
+ * Parameters:
+ * v = The value of the expression
+ * Returns:
+ * A static instance of the expression, typed as `Tint32`.
+ */
+ static IntegerExp literal(int v)()
+ {
+ __gshared IntegerExp theConstant;
+ if (!theConstant)
+ theConstant = new IntegerExp(v);
+ return theConstant;
+ }
+
+ /**
+ * Use this instead of creating new instances for commonly used bools.
+ *
+ * Parameters:
+ * b = The value of the expression
+ * Returns:
+ * A static instance of the expression, typed as `Type.tbool`.
+ */
+ static IntegerExp createBool(bool b)
+ {
+ __gshared IntegerExp trueExp, falseExp;
+ if (!trueExp)
+ {
+ trueExp = new IntegerExp(Loc.initial, 1, Type.tbool);
+ falseExp = new IntegerExp(Loc.initial, 0, Type.tbool);
+ }
+ return b ? trueExp : falseExp;
+ }
+}
+
+/***********************************************************
+ * Use this expression for error recovery.
+ * It should behave as a 'sink' to prevent further cascaded error messages.
+ */
+extern (C++) final class ErrorExp : Expression
+{
+ private extern (D) this()
+ {
+ super(Loc.initial, TOK.error, __traits(classInstanceSize, ErrorExp));
+ type = Type.terror;
+ }
+
+ static ErrorExp get ()
+ {
+ if (errorexp is null)
+ errorexp = new ErrorExp();
+
+ if (global.errors == 0 && global.gaggedErrors == 0)
+ {
+ /* Unfortunately, errors can still leak out of gagged errors,
+ * and we need to set the error count to prevent bogus code
+ * generation. At least give a message.
+ */
+ .error(Loc.initial, "unknown, please file report on issues.dlang.org");
+ }
+
+ return errorexp;
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ extern (C++) __gshared ErrorExp errorexp; // handy shared value
+}
+
+
+/***********************************************************
+ * An uninitialized value,
+ * generated from void initializers.
+ */
+extern (C++) final class VoidInitExp : Expression
+{
+ VarDeclaration var; /// the variable from where the void value came from, null if not known
+ /// Useful for error messages
+
+ extern (D) this(VarDeclaration var)
+ {
+ super(var.loc, TOK.void_, __traits(classInstanceSize, VoidInitExp));
+ this.var = var;
+ this.type = var.type;
+ }
+
+ override const(char)* toChars() const
+ {
+ return "void";
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+
+/***********************************************************
+ */
+extern (C++) final class RealExp : Expression
+{
+ real_t value;
+
+ extern (D) this(const ref Loc loc, real_t value, Type type)
+ {
+ super(loc, TOK.float64, __traits(classInstanceSize, RealExp));
+ //printf("RealExp::RealExp(%Lg)\n", value);
+ this.value = value;
+ this.type = type;
+ }
+
+ static RealExp create(Loc loc, real_t value, Type type)
+ {
+ return new RealExp(loc, value, type);
+ }
+
+ // Same as create, but doesn't allocate memory.
+ static void emplace(UnionExp* pue, Loc loc, real_t value, Type type)
+ {
+ emplaceExp!(RealExp)(pue, loc, value, type);
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+ if (auto ne = (cast(Expression)o).isRealExp())
+ {
+ if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(value, ne.value))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ override dinteger_t toInteger()
+ {
+ return cast(sinteger_t)toReal();
+ }
+
+ override uinteger_t toUInteger()
+ {
+ return cast(uinteger_t)toReal();
+ }
+
+ override real_t toReal()
+ {
+ return type.isreal() ? value : CTFloat.zero;
+ }
+
+ override real_t toImaginary()
+ {
+ return type.isreal() ? CTFloat.zero : value;
+ }
+
+ override complex_t toComplex()
+ {
+ return complex_t(toReal(), toImaginary());
+ }
+
+ override bool isBool(bool result)
+ {
+ return result ? cast(bool)value : !cast(bool)value;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ComplexExp : Expression
+{
+ complex_t value;
+
+ extern (D) this(const ref Loc loc, complex_t value, Type type)
+ {
+ super(loc, TOK.complex80, __traits(classInstanceSize, ComplexExp));
+ this.value = value;
+ this.type = type;
+ //printf("ComplexExp::ComplexExp(%s)\n", toChars());
+ }
+
+ static ComplexExp create(Loc loc, complex_t value, Type type)
+ {
+ return new ComplexExp(loc, value, type);
+ }
+
+ // Same as create, but doesn't allocate memory.
+ static void emplace(UnionExp* pue, Loc loc, complex_t value, Type type)
+ {
+ emplaceExp!(ComplexExp)(pue, loc, value, type);
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+ if (auto ne = (cast(Expression)o).isComplexExp())
+ {
+ if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(creall(value), creall(ne.value)) && RealIdentical(cimagl(value), cimagl(ne.value)))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ override dinteger_t toInteger()
+ {
+ return cast(sinteger_t)toReal();
+ }
+
+ override uinteger_t toUInteger()
+ {
+ return cast(uinteger_t)toReal();
+ }
+
+ override real_t toReal()
+ {
+ return creall(value);
+ }
+
+ override real_t toImaginary()
+ {
+ return cimagl(value);
+ }
+
+ override complex_t toComplex()
+ {
+ return value;
+ }
+
+ override bool isBool(bool result)
+ {
+ if (result)
+ return cast(bool)value;
+ else
+ return !value;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) class IdentifierExp : Expression
+{
+ Identifier ident;
+
+ extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ super(loc, TOK.identifier, __traits(classInstanceSize, IdentifierExp));
+ this.ident = ident;
+ }
+
+ static IdentifierExp create(Loc loc, Identifier ident)
+ {
+ return new IdentifierExp(loc, ident);
+ }
+
+ override final bool isLvalue()
+ {
+ return true;
+ }
+
+ override final Expression toLvalue(Scope* sc, Expression e)
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DollarExp : IdentifierExp
+{
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, Id.dollar);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Won't be generated by parser.
+ */
+extern (C++) final class DsymbolExp : Expression
+{
+ Dsymbol s;
+ bool hasOverloads;
+
+ extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true)
+ {
+ super(loc, TOK.dSymbol, __traits(classInstanceSize, DsymbolExp));
+ this.s = s;
+ this.hasOverloads = hasOverloads;
+ }
+
+ override bool isLvalue()
+ {
+ return true;
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * http://dlang.org/spec/expression.html#this
+ */
+extern (C++) class ThisExp : Expression
+{
+ VarDeclaration var;
+
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, TOK.this_, __traits(classInstanceSize, ThisExp));
+ //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
+ }
+
+ this(const ref Loc loc, const TOK tok)
+ {
+ super(loc, tok, __traits(classInstanceSize, ThisExp));
+ //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
+ }
+
+ override ThisExp syntaxCopy()
+ {
+ auto r = cast(ThisExp) super.syntaxCopy();
+ // require new semantic (possibly new `var` etc.)
+ r.type = null;
+ r.var = null;
+ return r;
+ }
+
+ override final bool isBool(bool result)
+ {
+ return result;
+ }
+
+ override final bool isLvalue()
+ {
+ // Class `this` should be an rvalue; struct `this` should be an lvalue.
+ return type.toBasetype().ty != Tclass;
+ }
+
+ override final Expression toLvalue(Scope* sc, Expression e)
+ {
+ if (type.toBasetype().ty == Tclass)
+ {
+ // Class `this` is an rvalue; struct `this` is an lvalue.
+ return Expression.toLvalue(sc, e);
+ }
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * http://dlang.org/spec/expression.html#super
+ */
+extern (C++) final class SuperExp : ThisExp
+{
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, TOK.super_);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * http://dlang.org/spec/expression.html#null
+ */
+extern (C++) final class NullExp : Expression
+{
+ extern (D) this(const ref Loc loc, Type type = null)
+ {
+ super(loc, TOK.null_, __traits(classInstanceSize, NullExp));
+ this.type = type;
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (auto e = o.isExpression())
+ {
+ if (e.op == TOK.null_ && type.equals(e.type))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ override bool isBool(bool result)
+ {
+ return result ? false : true;
+ }
+
+ override StringExp toStringExp()
+ {
+ if (implicitConvTo(Type.tstring))
+ {
+ auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]);
+ se.type = Type.tstring;
+ return se;
+ }
+ return null;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * http://dlang.org/spec/expression.html#string_literals
+ */
+extern (C++) final class StringExp : Expression
+{
+ private union
+ {
+ char* string; // if sz == 1
+ wchar* wstring; // if sz == 2
+ dchar* dstring; // if sz == 4
+ } // (const if ownedByCtfe == OwnedBy.code)
+ size_t len; // number of code units
+ ubyte sz = 1; // 1: char, 2: wchar, 4: dchar
+ ubyte committed; // !=0 if type is committed
+ enum char NoPostfix = 0;
+ char postfix = NoPostfix; // 'c', 'w', 'd'
+ OwnedBy ownedByCtfe = OwnedBy.code;
+
+ extern (D) this(const ref Loc loc, const(void)[] string)
+ {
+ super(loc, TOK.string_, __traits(classInstanceSize, StringExp));
+ this.string = cast(char*)string.ptr; // note that this.string should be const
+ this.len = string.length;
+ this.sz = 1; // work around LDC bug #1286
+ }
+
+ extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix)
+ {
+ super(loc, TOK.string_, __traits(classInstanceSize, StringExp));
+ this.string = cast(char*)string.ptr; // note that this.string should be const
+ this.len = len;
+ this.sz = sz;
+ this.postfix = postfix;
+ }
+
+ static StringExp create(Loc loc, char* s)
+ {
+ return new StringExp(loc, s.toDString());
+ }
+
+ static StringExp create(Loc loc, void* string, size_t len)
+ {
+ return new StringExp(loc, string[0 .. len]);
+ }
+
+ // Same as create, but doesn't allocate memory.
+ static void emplace(UnionExp* pue, Loc loc, char* s)
+ {
+ emplaceExp!(StringExp)(pue, loc, s.toDString());
+ }
+
+ extern (D) static void emplace(UnionExp* pue, Loc loc, const(void)[] string)
+ {
+ emplaceExp!(StringExp)(pue, loc, string);
+ }
+
+ extern (D) static void emplace(UnionExp* pue, Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix)
+ {
+ emplaceExp!(StringExp)(pue, loc, string, len, sz, postfix);
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars());
+ if (auto e = o.isExpression())
+ {
+ if (auto se = e.isStringExp())
+ {
+ return compare(se) == 0;
+ }
+ }
+ return false;
+ }
+
+ /**********************************
+ * Return the number of code units the string would be if it were re-encoded
+ * as tynto.
+ * Params:
+ * tynto = code unit type of the target encoding
+ * Returns:
+ * number of code units
+ */
+ size_t numberOfCodeUnits(int tynto = 0) const
+ {
+ int encSize;
+ switch (tynto)
+ {
+ case 0: return len;
+ case Tchar: encSize = 1; break;
+ case Twchar: encSize = 2; break;
+ case Tdchar: encSize = 4; break;
+ default:
+ assert(0);
+ }
+ if (sz == encSize)
+ return len;
+
+ size_t result = 0;
+ dchar c;
+
+ switch (sz)
+ {
+ case 1:
+ for (size_t u = 0; u < len;)
+ {
+ if (const s = utf_decodeChar(string[0 .. len], u, c))
+ {
+ error("%.*s", cast(int)s.length, s.ptr);
+ return 0;
+ }
+ result += utf_codeLength(encSize, c);
+ }
+ break;
+
+ case 2:
+ for (size_t u = 0; u < len;)
+ {
+ if (const s = utf_decodeWchar(wstring[0 .. len], u, c))
+ {
+ error("%.*s", cast(int)s.length, s.ptr);
+ return 0;
+ }
+ result += utf_codeLength(encSize, c);
+ }
+ break;
+
+ case 4:
+ foreach (u; 0 .. len)
+ {
+ result += utf_codeLength(encSize, dstring[u]);
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+ return result;
+ }
+
+ /**********************************************
+ * Write the contents of the string to dest.
+ * Use numberOfCodeUnits() to determine size of result.
+ * Params:
+ * dest = destination
+ * tyto = encoding type of the result
+ * zero = add terminating 0
+ */
+ void writeTo(void* dest, bool zero, int tyto = 0) const
+ {
+ int encSize;
+ switch (tyto)
+ {
+ case 0: encSize = sz; break;
+ case Tchar: encSize = 1; break;
+ case Twchar: encSize = 2; break;
+ case Tdchar: encSize = 4; break;
+ default:
+ assert(0);
+ }
+ if (sz == encSize)
+ {
+ memcpy(dest, string, len * sz);
+ if (zero)
+ memset(dest + len * sz, 0, sz);
+ }
+ else
+ assert(0);
+ }
+
+ /*********************************************
+ * Get the code unit at index i
+ * Params:
+ * i = index
+ * Returns:
+ * code unit at index i
+ */
+ dchar getCodeUnit(size_t i) const pure
+ {
+ assert(i < len);
+ final switch (sz)
+ {
+ case 1:
+ return string[i];
+ case 2:
+ return wstring[i];
+ case 4:
+ return dstring[i];
+ }
+ }
+
+ /*********************************************
+ * Set the code unit at index i to c
+ * Params:
+ * i = index
+ * c = code unit to set it to
+ */
+ void setCodeUnit(size_t i, dchar c)
+ {
+ assert(i < len);
+ final switch (sz)
+ {
+ case 1:
+ string[i] = cast(char)c;
+ break;
+ case 2:
+ wstring[i] = cast(wchar)c;
+ break;
+ case 4:
+ dstring[i] = c;
+ break;
+ }
+ }
+
+ override StringExp toStringExp()
+ {
+ return this;
+ }
+
+ /****************************************
+ * Convert string to char[].
+ */
+ StringExp toUTF8(Scope* sc)
+ {
+ if (sz != 1)
+ {
+ // Convert to UTF-8 string
+ committed = 0;
+ Expression e = castTo(sc, Type.tchar.arrayOf());
+ e = e.optimize(WANTvalue);
+ auto se = e.isStringExp();
+ assert(se.sz == 1);
+ return se;
+ }
+ return this;
+ }
+
+ /**
+ * Compare two `StringExp` by length, then value
+ *
+ * The comparison is not the usual C-style comparison as seen with
+ * `strcmp` or `memcmp`, but instead first compare based on the length.
+ * This allows both faster lookup and sorting when comparing sparse data.
+ *
+ * This ordering scheme is relied on by the string-switching feature.
+ * Code in Druntime's `core.internal.switch_` relies on this ordering
+ * when doing a binary search among case statements.
+ *
+ * Both `StringExp` should be of the same encoding.
+ *
+ * Params:
+ * se2 = String expression to compare `this` to
+ *
+ * Returns:
+ * `0` when `this` is equal to se2, a value greater than `0` if
+ * `this` should be considered greater than `se2`,
+ * and a value less than `0` if `this` is lesser than `se2`.
+ */
+ int compare(const StringExp se2) const nothrow pure @nogc
+ {
+ //printf("StringExp::compare()\n");
+ const len1 = len;
+ const len2 = se2.len;
+
+ assert(this.sz == se2.sz, "Comparing string expressions of different sizes");
+ //printf("sz = %d, len1 = %d, len2 = %d\n", sz, (int)len1, (int)len2);
+ if (len1 == len2)
+ {
+ switch (sz)
+ {
+ case 1:
+ return memcmp(string, se2.string, len1);
+
+ case 2:
+ {
+ wchar* s1 = cast(wchar*)string;
+ wchar* s2 = cast(wchar*)se2.string;
+ foreach (u; 0 .. len)
+ {
+ if (s1[u] != s2[u])
+ return s1[u] - s2[u];
+ }
+ }
+ break;
+ case 4:
+ {
+ dchar* s1 = cast(dchar*)string;
+ dchar* s2 = cast(dchar*)se2.string;
+ foreach (u; 0 .. len)
+ {
+ if (s1[u] != s2[u])
+ return s1[u] - s2[u];
+ }
+ }
+ break;
+ default:
+ assert(0);
+ }
+ }
+ return cast(int)(len1 - len2);
+ }
+
+ override bool isBool(bool result)
+ {
+ return result;
+ }
+
+ override bool isLvalue()
+ {
+ /* string literal is rvalue in default, but
+ * conversion to reference of static array is only allowed.
+ */
+ return (type && type.toBasetype().ty == Tsarray);
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
+ return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
+ }
+
+ override Expression modifiableLvalue(Scope* sc, Expression e)
+ {
+ error("cannot modify string literal `%s`", toChars());
+ return ErrorExp.get();
+ }
+
+ uint charAt(uinteger_t i) const
+ {
+ uint value;
+ switch (sz)
+ {
+ case 1:
+ value = (cast(char*)string)[cast(size_t)i];
+ break;
+
+ case 2:
+ value = (cast(ushort*)string)[cast(size_t)i];
+ break;
+
+ case 4:
+ value = (cast(uint*)string)[cast(size_t)i];
+ break;
+
+ default:
+ assert(0);
+ }
+ return value;
+ }
+
+ /********************************
+ * Convert string contents to a 0 terminated string,
+ * allocated by mem.xmalloc().
+ */
+ extern (D) const(char)[] toStringz() const
+ {
+ auto nbytes = len * sz;
+ char* s = cast(char*)mem.xmalloc(nbytes + sz);
+ writeTo(s, true);
+ return s[0 .. nbytes];
+ }
+
+ extern (D) const(char)[] peekString() const
+ {
+ assert(sz == 1);
+ return this.string[0 .. len];
+ }
+
+ extern (D) const(wchar)[] peekWstring() const
+ {
+ assert(sz == 2);
+ return this.wstring[0 .. len];
+ }
+
+ extern (D) const(dchar)[] peekDstring() const
+ {
+ assert(sz == 4);
+ return this.dstring[0 .. len];
+ }
+
+ /*******************
+ * Get a slice of the data.
+ */
+ extern (D) const(ubyte)[] peekData() const
+ {
+ return cast(const(ubyte)[])this.string[0 .. len * sz];
+ }
+
+ /*******************
+ * Borrow a slice of the data, so the caller can modify
+ * it in-place (!)
+ */
+ extern (D) ubyte[] borrowData()
+ {
+ return cast(ubyte[])this.string[0 .. len * sz];
+ }
+
+ /***********************
+ * Set new string data.
+ * `this` becomes the new owner of the data.
+ */
+ extern (D) void setData(void* s, size_t len, ubyte sz)
+ {
+ this.string = cast(char*)s;
+ this.len = len;
+ this.sz = sz;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TupleExp : Expression
+{
+ /* Tuple-field access may need to take out its side effect part.
+ * For example:
+ * foo().tupleof
+ * is rewritten as:
+ * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
+ * The declaration of temporary variable __tup will be stored in TupleExp.e0.
+ */
+ Expression e0;
+
+ Expressions* exps;
+
+ extern (D) this(const ref Loc loc, Expression e0, Expressions* exps)
+ {
+ super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
+ //printf("TupleExp(this = %p)\n", this);
+ this.e0 = e0;
+ this.exps = exps;
+ }
+
+ extern (D) this(const ref Loc loc, Expressions* exps)
+ {
+ super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
+ //printf("TupleExp(this = %p)\n", this);
+ this.exps = exps;
+ }
+
+ extern (D) this(const ref Loc loc, TupleDeclaration tup)
+ {
+ super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
+ this.exps = new Expressions();
+
+ this.exps.reserve(tup.objects.dim);
+ foreach (o; *tup.objects)
+ {
+ if (Dsymbol s = getDsymbol(o))
+ {
+ /* If tuple element represents a symbol, translate to DsymbolExp
+ * to supply implicit 'this' if needed later.
+ */
+ Expression e = new DsymbolExp(loc, s);
+ this.exps.push(e);
+ }
+ else if (auto eo = o.isExpression())
+ {
+ auto e = eo.copy();
+ e.loc = loc; // https://issues.dlang.org/show_bug.cgi?id=15669
+ this.exps.push(e);
+ }
+ else if (auto t = o.isType())
+ {
+ Expression e = new TypeExp(loc, t);
+ this.exps.push(e);
+ }
+ else
+ {
+ error("`%s` is not an expression", o.toChars());
+ }
+ }
+ }
+
+ static TupleExp create(Loc loc, Expressions* exps)
+ {
+ return new TupleExp(loc, exps);
+ }
+
+ override TupleExp toTupleExp()
+ {
+ return this;
+ }
+
+ override TupleExp syntaxCopy()
+ {
+ return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+ if (auto e = o.isExpression())
+ if (auto te = e.isTupleExp())
+ {
+ if (exps.dim != te.exps.dim)
+ return false;
+ if (e0 && !e0.equals(te.e0) || !e0 && te.e0)
+ return false;
+ foreach (i, e1; *exps)
+ {
+ auto e2 = (*te.exps)[i];
+ if (!e1.equals(e2))
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * [ e1, e2, e3, ... ]
+ *
+ * http://dlang.org/spec/expression.html#array_literals
+ */
+extern (C++) final class ArrayLiteralExp : Expression
+{
+ /** If !is null, elements[] can be sparse and basis is used for the
+ * "default" element value. In other words, non-null elements[i] overrides
+ * this 'basis' value.
+ */
+ Expression basis;
+
+ Expressions* elements;
+ OwnedBy ownedByCtfe = OwnedBy.code;
+
+
+ extern (D) this(const ref Loc loc, Type type, Expressions* elements)
+ {
+ super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
+ this.type = type;
+ this.elements = elements;
+ }
+
+ extern (D) this(const ref Loc loc, Type type, Expression e)
+ {
+ super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
+ this.type = type;
+ elements = new Expressions();
+ elements.push(e);
+ }
+
+ extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements)
+ {
+ super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
+ this.type = type;
+ this.basis = basis;
+ this.elements = elements;
+ }
+
+ static ArrayLiteralExp create(Loc loc, Expressions* elements)
+ {
+ return new ArrayLiteralExp(loc, null, elements);
+ }
+
+ // Same as create, but doesn't allocate memory.
+ static void emplace(UnionExp* pue, Loc loc, Expressions* elements)
+ {
+ emplaceExp!(ArrayLiteralExp)(pue, loc, null, elements);
+ }
+
+ override ArrayLiteralExp syntaxCopy()
+ {
+ return new ArrayLiteralExp(loc,
+ null,
+ basis ? basis.syntaxCopy() : null,
+ arraySyntaxCopy(elements));
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+ auto e = o.isExpression();
+ if (!e)
+ return false;
+ if (auto ae = e.isArrayLiteralExp())
+ {
+ if (elements.dim != ae.elements.dim)
+ return false;
+ if (elements.dim == 0 && !type.equals(ae.type))
+ {
+ return false;
+ }
+
+ foreach (i, e1; *elements)
+ {
+ auto e2 = (*ae.elements)[i];
+ auto e1x = e1 ? e1 : basis;
+ auto e2x = e2 ? e2 : ae.basis;
+
+ if (e1x != e2x && (!e1x || !e2x || !e1x.equals(e2x)))
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ Expression getElement(size_t i)
+ {
+ return this[i];
+ }
+
+ Expression opIndex(size_t i)
+ {
+ auto el = (*elements)[i];
+ return el ? el : basis;
+ }
+
+ override bool isBool(bool result)
+ {
+ size_t dim = elements ? elements.dim : 0;
+ return result ? (dim != 0) : (dim == 0);
+ }
+
+ override StringExp toStringExp()
+ {
+ TY telem = type.nextOf().toBasetype().ty;
+ if (telem.isSomeChar || (telem == Tvoid && (!elements || elements.dim == 0)))
+ {
+ ubyte sz = 1;
+ if (telem == Twchar)
+ sz = 2;
+ else if (telem == Tdchar)
+ sz = 4;
+
+ OutBuffer buf;
+ if (elements)
+ {
+ foreach (i; 0 .. elements.dim)
+ {
+ auto ch = this[i];
+ if (ch.op != TOK.int64)
+ return null;
+ if (sz == 1)
+ buf.writeByte(cast(uint)ch.toInteger());
+ else if (sz == 2)
+ buf.writeword(cast(uint)ch.toInteger());
+ else
+ buf.write4(cast(uint)ch.toInteger());
+ }
+ }
+ char prefix;
+ if (sz == 1)
+ {
+ prefix = 'c';
+ buf.writeByte(0);
+ }
+ else if (sz == 2)
+ {
+ prefix = 'w';
+ buf.writeword(0);
+ }
+ else
+ {
+ prefix = 'd';
+ buf.write4(0);
+ }
+
+ const size_t len = buf.length / sz - 1;
+ auto se = new StringExp(loc, buf.extractSlice()[0 .. len * sz], len, sz, prefix);
+ se.sz = sz;
+ se.type = type;
+ return se;
+ }
+ return null;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * [ key0 : value0, key1 : value1, ... ]
+ *
+ * http://dlang.org/spec/expression.html#associative_array_literals
+ */
+extern (C++) final class AssocArrayLiteralExp : Expression
+{
+ Expressions* keys;
+ Expressions* values;
+
+ OwnedBy ownedByCtfe = OwnedBy.code;
+
+ extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values)
+ {
+ super(loc, TOK.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp));
+ assert(keys.dim == values.dim);
+ this.keys = keys;
+ this.values = values;
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+ auto e = o.isExpression();
+ if (!e)
+ return false;
+ if (auto ae = e.isAssocArrayLiteralExp())
+ {
+ if (keys.dim != ae.keys.dim)
+ return false;
+ size_t count = 0;
+ foreach (i, key; *keys)
+ {
+ foreach (j, akey; *ae.keys)
+ {
+ if (key.equals(akey))
+ {
+ if (!(*values)[i].equals((*ae.values)[j]))
+ return false;
+ ++count;
+ }
+ }
+ }
+ return count == keys.dim;
+ }
+ return false;
+ }
+
+ override AssocArrayLiteralExp syntaxCopy()
+ {
+ return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values));
+ }
+
+ override bool isBool(bool result)
+ {
+ size_t dim = keys.dim;
+ return result ? (dim != 0) : (dim == 0);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+enum stageScrub = 0x1; /// scrubReturnValue is running
+enum stageSearchPointers = 0x2; /// hasNonConstPointers is running
+enum stageOptimize = 0x4; /// optimize is running
+enum stageApply = 0x8; /// apply is running
+enum stageInlineScan = 0x10; /// inlineScan is running
+enum stageToCBuffer = 0x20; /// toCBuffer is running
+
+/***********************************************************
+ * sd( e1, e2, e3, ... )
+ */
+extern (C++) final class StructLiteralExp : Expression
+{
+ StructDeclaration sd; /// which aggregate this is for
+ Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip
+ Type stype; /// final type of result (can be different from sd's type)
+
+ Symbol* sym; /// back end symbol to initialize with literal
+
+ /** pointer to the origin instance of the expression.
+ * once a new expression is created, origin is set to 'this'.
+ * anytime when an expression copy is created, 'origin' pointer is set to
+ * 'origin' pointer value of the original expression.
+ */
+ StructLiteralExp origin;
+
+ /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
+ StructLiteralExp inlinecopy;
+
+ /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
+ * current stage and unmarks before return from this function.
+ * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
+ * (with infinite recursion) of this expression.
+ */
+ int stageflags;
+
+ bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol
+ bool isOriginal = false; /// used when moving instances to indicate `this is this.origin`
+ OwnedBy ownedByCtfe = OwnedBy.code;
+
+ extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null)
+ {
+ super(loc, TOK.structLiteral, __traits(classInstanceSize, StructLiteralExp));
+ this.sd = sd;
+ if (!elements)
+ elements = new Expressions();
+ this.elements = elements;
+ this.stype = stype;
+ this.origin = this;
+ //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
+ }
+
+ static StructLiteralExp create(Loc loc, StructDeclaration sd, void* elements, Type stype = null)
+ {
+ return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype);
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+ auto e = o.isExpression();
+ if (!e)
+ return false;
+ if (auto se = e.isStructLiteralExp())
+ {
+ if (!type.equals(se.type))
+ return false;
+ if (elements.dim != se.elements.dim)
+ return false;
+ foreach (i, e1; *elements)
+ {
+ auto e2 = (*se.elements)[i];
+ if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ override StructLiteralExp syntaxCopy()
+ {
+ auto exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
+ exp.origin = this;
+ return exp;
+ }
+
+ /**************************************
+ * Gets expression at offset of type.
+ * Returns NULL if not found.
+ */
+ Expression getField(Type type, uint offset)
+ {
+ //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
+ // /*toChars()*/"", type.toChars(), offset);
+ Expression e = null;
+ int i = getFieldIndex(type, offset);
+
+ if (i != -1)
+ {
+ //printf("\ti = %d\n", i);
+ if (i >= sd.nonHiddenFields())
+ return null;
+
+ assert(i < elements.dim);
+ e = (*elements)[i];
+ if (e)
+ {
+ //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
+
+ /* If type is a static array, and e is an initializer for that array,
+ * then the field initializer should be an array literal of e.
+ */
+ auto tsa = type.isTypeSArray();
+ if (tsa && e.type.castMod(0) != type.castMod(0))
+ {
+ const length = cast(size_t)tsa.dim.toInteger();
+ auto z = new Expressions(length);
+ foreach (ref q; *z)
+ q = e.copy();
+ e = new ArrayLiteralExp(loc, type, z);
+ }
+ else
+ {
+ e = e.copy();
+ e.type = type;
+ }
+ if (useStaticInit && e.type.needsNested())
+ if (auto se = e.isStructLiteralExp())
+ {
+ se.useStaticInit = true;
+ }
+ }
+ }
+ return e;
+ }
+
+ /************************************
+ * Get index of field.
+ * Returns -1 if not found.
+ */
+ int getFieldIndex(Type type, uint offset)
+ {
+ /* Find which field offset is by looking at the field offsets
+ */
+ if (elements.dim)
+ {
+ foreach (i, v; sd.fields)
+ {
+ if (offset == v.offset && type.size() == v.type.size())
+ {
+ /* context fields might not be filled. */
+ if (i >= sd.nonHiddenFields())
+ return cast(int)i;
+ if (auto e = (*elements)[i])
+ {
+ return cast(int)i;
+ }
+ break;
+ }
+ }
+ }
+ return -1;
+ }
+
+ override Expression addDtorHook(Scope* sc)
+ {
+ /* If struct requires a destructor, rewrite as:
+ * (S tmp = S()),tmp
+ * so that the destructor can be hung on tmp.
+ */
+ if (sd.dtor && sc.func)
+ {
+ /* Make an identifier for the temporary of the form:
+ * __sl%s%d, where %s is the struct name
+ */
+ char[10] buf = void;
+ const prefix = "__sl";
+ const ident = sd.ident.toString;
+ const fullLen = prefix.length + ident.length;
+ const len = fullLen < buf.length ? fullLen : buf.length;
+ buf[0 .. prefix.length] = prefix;
+ buf[prefix.length .. len] = ident[0 .. len - prefix.length];
+
+ auto tmp = copyToTemp(0, buf[0 .. len], this);
+ Expression ae = new DeclarationExp(loc, tmp);
+ Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp));
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ return this;
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ if (sc.flags & SCOPE.Cfile)
+ return this; // C struct literals are lvalues
+ else
+ return Expression.toLvalue(sc, e);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * C11 6.5.2.5
+ * ( type-name ) { initializer-list }
+ */
+extern (C++) final class CompoundLiteralExp : Expression
+{
+ Initializer initializer; /// initializer-list
+
+ extern (D) this(const ref Loc loc, Type type_name, Initializer initializer)
+ {
+ super(loc, TOK.compoundLiteral, __traits(classInstanceSize, CompoundLiteralExp));
+ super.type = type_name;
+ this.initializer = initializer;
+ //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars());
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Mainly just a placeholder
+ */
+extern (C++) final class TypeExp : Expression
+{
+ extern (D) this(const ref Loc loc, Type type)
+ {
+ super(loc, TOK.type, __traits(classInstanceSize, TypeExp));
+ //printf("TypeExp::TypeExp(%s)\n", type.toChars());
+ this.type = type;
+ }
+
+ override TypeExp syntaxCopy()
+ {
+ return new TypeExp(loc, type.syntaxCopy());
+ }
+
+ override bool checkType()
+ {
+ error("type `%s` is not an expression", toChars());
+ return true;
+ }
+
+ override bool checkValue()
+ {
+ error("type `%s` has no value", toChars());
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Mainly just a placeholder of
+ * Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
+ *
+ * A template instance that requires IFTI:
+ * foo!tiargs(fargs) // foo!tiargs
+ * is left until CallExp::semantic() or resolveProperties()
+ */
+extern (C++) final class ScopeExp : Expression
+{
+ ScopeDsymbol sds;
+
+ extern (D) this(const ref Loc loc, ScopeDsymbol sds)
+ {
+ super(loc, TOK.scope_, __traits(classInstanceSize, ScopeExp));
+ //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
+ //static int count; if (++count == 38) *(char*)0=0;
+ this.sds = sds;
+ assert(!sds.isTemplateDeclaration()); // instead, you should use TemplateExp
+ }
+
+ override ScopeExp syntaxCopy()
+ {
+ return new ScopeExp(loc, sds.syntaxCopy(null));
+ }
+
+ override bool checkType()
+ {
+ if (sds.isPackage())
+ {
+ error("%s `%s` has no type", sds.kind(), sds.toChars());
+ return true;
+ }
+ if (auto ti = sds.isTemplateInstance())
+ {
+ //assert(ti.needsTypeInference(sc));
+ if (ti.tempdecl &&
+ ti.semantictiargsdone &&
+ ti.semanticRun == PASS.init)
+ {
+ error("partial %s `%s` has no type", sds.kind(), toChars());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ override bool checkValue()
+ {
+ error("%s `%s` has no value", sds.kind(), sds.toChars());
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Mainly just a placeholder
+ */
+extern (C++) final class TemplateExp : Expression
+{
+ TemplateDeclaration td;
+ FuncDeclaration fd;
+
+ extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null)
+ {
+ super(loc, TOK.template_, __traits(classInstanceSize, TemplateExp));
+ //printf("TemplateExp(): %s\n", td.toChars());
+ this.td = td;
+ this.fd = fd;
+ }
+
+ override bool isLvalue()
+ {
+ return fd !is null;
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ if (!fd)
+ return Expression.toLvalue(sc, e);
+
+ assert(sc);
+ return symbolToExp(fd, loc, sc, true);
+ }
+
+ override bool checkType()
+ {
+ error("%s `%s` has no type", td.kind(), toChars());
+ return true;
+ }
+
+ override bool checkValue()
+ {
+ error("%s `%s` has no value", td.kind(), toChars());
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * thisexp.new(newargs) newtype(arguments)
+ */
+extern (C++) final class NewExp : Expression
+{
+ Expression thisexp; // if !=null, 'this' for class being allocated
+ Expressions* newargs; // Array of Expression's to call new operator
+ Type newtype;
+ Expressions* arguments; // Array of Expression's
+
+ Expression argprefix; // expression to be evaluated just before arguments[]
+ CtorDeclaration member; // constructor function
+ bool onstack; // allocate on stack
+ bool thrownew; // this NewExp is the expression of a ThrowStatement
+
+ extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
+ {
+ super(loc, TOK.new_, __traits(classInstanceSize, NewExp));
+ this.thisexp = thisexp;
+ this.newargs = newargs;
+ this.newtype = newtype;
+ this.arguments = arguments;
+ }
+
+ static NewExp create(Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
+ {
+ return new NewExp(loc, thisexp, newargs, newtype, arguments);
+ }
+
+ override NewExp syntaxCopy()
+ {
+ return new NewExp(loc,
+ thisexp ? thisexp.syntaxCopy() : null,
+ arraySyntaxCopy(newargs),
+ newtype.syntaxCopy(),
+ arraySyntaxCopy(arguments));
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * thisexp.new(newargs) class baseclasses { } (arguments)
+ */
+extern (C++) final class NewAnonClassExp : Expression
+{
+ Expression thisexp; // if !=null, 'this' for class being allocated
+ Expressions* newargs; // Array of Expression's to call new operator
+ ClassDeclaration cd; // class being instantiated
+ Expressions* arguments; // Array of Expression's to call class constructor
+
+ extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, ClassDeclaration cd, Expressions* arguments)
+ {
+ super(loc, TOK.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
+ this.thisexp = thisexp;
+ this.newargs = newargs;
+ this.cd = cd;
+ this.arguments = arguments;
+ }
+
+ override NewAnonClassExp syntaxCopy()
+ {
+ return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, arraySyntaxCopy(newargs), cd.syntaxCopy(null), arraySyntaxCopy(arguments));
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) class SymbolExp : Expression
+{
+ Declaration var;
+ Dsymbol originalScope; // original scope before inlining
+ bool hasOverloads;
+
+ extern (D) this(const ref Loc loc, TOK op, int size, Declaration var, bool hasOverloads)
+ {
+ super(loc, op, size);
+ assert(var);
+ this.var = var;
+ this.hasOverloads = hasOverloads;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Offset from symbol
+ */
+extern (C++) final class SymOffExp : SymbolExp
+{
+ dinteger_t offset;
+
+ extern (D) this(const ref Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true)
+ {
+ if (auto v = var.isVarDeclaration())
+ {
+ // FIXME: This error report will never be handled anyone.
+ // It should be done before the SymOffExp construction.
+ if (v.needThis())
+ .error(loc, "need `this` for address of `%s`", v.toChars());
+ hasOverloads = false;
+ }
+ super(loc, TOK.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads);
+ this.offset = offset;
+ }
+
+ override bool isBool(bool result)
+ {
+ return result ? true : false;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Variable
+ */
+extern (C++) final class VarExp : SymbolExp
+{
+ bool delegateWasExtracted;
+ extern (D) this(const ref Loc loc, Declaration var, bool hasOverloads = true)
+ {
+ if (var.isVarDeclaration())
+ hasOverloads = false;
+
+ super(loc, TOK.variable, __traits(classInstanceSize, VarExp), var, hasOverloads);
+ //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
+ //if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
+ this.type = var.type;
+ }
+
+ static VarExp create(Loc loc, Declaration var, bool hasOverloads = true)
+ {
+ return new VarExp(loc, var, hasOverloads);
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+ if (auto ne = o.isExpression().isVarExp())
+ {
+ if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && var == ne.var)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ override bool isLvalue()
+ {
+ if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
+ return false;
+ return true;
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ if (var.storage_class & STC.manifest)
+ {
+ error("manifest constant `%s` cannot be modified", var.toChars());
+ return ErrorExp.get();
+ }
+ if (var.storage_class & STC.lazy_ && !delegateWasExtracted)
+ {
+ error("lazy variable `%s` cannot be modified", var.toChars());
+ return ErrorExp.get();
+ }
+ if (var.ident == Id.ctfe)
+ {
+ error("cannot modify compiler-generated variable `__ctfe`");
+ return ErrorExp.get();
+ }
+ if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574
+ {
+ error("cannot modify operator `$`");
+ return ErrorExp.get();
+ }
+ return this;
+ }
+
+ override Expression modifiableLvalue(Scope* sc, Expression e)
+ {
+ //printf("VarExp::modifiableLvalue('%s')\n", var.toChars());
+ if (var.storage_class & STC.manifest)
+ {
+ error("cannot modify manifest constant `%s`", toChars());
+ return ErrorExp.get();
+ }
+ // See if this expression is a modifiable lvalue (i.e. not const)
+ return Expression.modifiableLvalue(sc, e);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Overload Set
+ */
+extern (C++) final class OverExp : Expression
+{
+ OverloadSet vars;
+
+ extern (D) this(const ref Loc loc, OverloadSet s)
+ {
+ super(loc, TOK.overloadSet, __traits(classInstanceSize, OverExp));
+ //printf("OverExp(this = %p, '%s')\n", this, var.toChars());
+ vars = s;
+ type = Type.tvoid;
+ }
+
+ override bool isLvalue()
+ {
+ return true;
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Function/Delegate literal
+ */
+
+extern (C++) final class FuncExp : Expression
+{
+ FuncLiteralDeclaration fd;
+ TemplateDeclaration td;
+ TOK tok;
+
+ extern (D) this(const ref Loc loc, Dsymbol s)
+ {
+ super(loc, TOK.function_, __traits(classInstanceSize, FuncExp));
+ this.td = s.isTemplateDeclaration();
+ this.fd = s.isFuncLiteralDeclaration();
+ if (td)
+ {
+ assert(td.literal);
+ assert(td.members && td.members.dim == 1);
+ fd = (*td.members)[0].isFuncLiteralDeclaration();
+ }
+ tok = fd.tok; // save original kind of function/delegate/(infer)
+ assert(fd.fbody);
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+ auto e = o.isExpression();
+ if (!e)
+ return false;
+ if (auto fe = e.isFuncExp())
+ {
+ return fd == fe.fd;
+ }
+ return false;
+ }
+
+ extern (D) void genIdent(Scope* sc)
+ {
+ if (fd.ident == Id.empty)
+ {
+ const(char)[] s;
+ if (fd.fes)
+ s = "__foreachbody";
+ else if (fd.tok == TOK.reserved)
+ s = "__lambda";
+ else if (fd.tok == TOK.delegate_)
+ s = "__dgliteral";
+ else
+ s = "__funcliteral";
+
+ DsymbolTable symtab;
+ if (FuncDeclaration func = sc.parent.isFuncDeclaration())
+ {
+ if (func.localsymtab is null)
+ {
+ // Inside template constraint, symtab is not set yet.
+ // Initialize it lazily.
+ func.localsymtab = new DsymbolTable();
+ }
+ symtab = func.localsymtab;
+ }
+ else
+ {
+ ScopeDsymbol sds = sc.parent.isScopeDsymbol();
+ if (!sds.symtab)
+ {
+ // Inside template constraint, symtab may not be set yet.
+ // Initialize it lazily.
+ assert(sds.isTemplateInstance());
+ sds.symtab = new DsymbolTable();
+ }
+ symtab = sds.symtab;
+ }
+ assert(symtab);
+ Identifier id = Identifier.generateId(s, symtab.length() + 1);
+ fd.ident = id;
+ if (td)
+ td.ident = id;
+ symtab.insert(td ? cast(Dsymbol)td : cast(Dsymbol)fd);
+ }
+ }
+
+ override FuncExp syntaxCopy()
+ {
+ if (td)
+ return new FuncExp(loc, td.syntaxCopy(null));
+ else if (fd.semanticRun == PASS.init)
+ return new FuncExp(loc, fd.syntaxCopy(null));
+ else // https://issues.dlang.org/show_bug.cgi?id=13481
+ // Prevent multiple semantic analysis of lambda body.
+ return new FuncExp(loc, fd);
+ }
+
+ extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, int flag = 0)
+ {
+
+ static MATCH cannotInfer(Expression e, Type to, int flag)
+ {
+ if (!flag)
+ e.error("cannot infer parameter types from `%s`", to.toChars());
+ return MATCH.nomatch;
+ }
+
+ //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
+ if (presult)
+ *presult = null;
+
+ TypeFunction tof = null;
+ if (to.ty == Tdelegate)
+ {
+ if (tok == TOK.function_)
+ {
+ if (!flag)
+ error("cannot match function literal to delegate type `%s`", to.toChars());
+ return MATCH.nomatch;
+ }
+ tof = cast(TypeFunction)to.nextOf();
+ }
+ else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
+ {
+ if (tok == TOK.delegate_)
+ {
+ if (!flag)
+ error("cannot match delegate literal to function pointer type `%s`", to.toChars());
+ return MATCH.nomatch;
+ }
+ }
+
+ if (td)
+ {
+ if (!tof)
+ {
+ return cannotInfer(this, to, flag);
+ }
+
+ // Parameter types inference from 'tof'
+ assert(td._scope);
+ TypeFunction tf = fd.type.isTypeFunction();
+ //printf("\ttof = %s\n", tof.toChars());
+ //printf("\ttf = %s\n", tf.toChars());
+ const dim = tf.parameterList.length;
+
+ if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
+ return cannotInfer(this, to, flag);
+
+ auto tiargs = new Objects();
+ tiargs.reserve(td.parameters.dim);
+
+ foreach (tp; *td.parameters)
+ {
+ size_t u = 0;
+ foreach (i, p; tf.parameterList)
+ {
+ if (auto ti = p.type.isTypeIdentifier())
+ if (ti && ti.ident == tp.ident)
+ break;
+
+ ++u;
+ }
+ assert(u < dim);
+ Parameter pto = tof.parameterList[u];
+ Type t = pto.type;
+ if (t.ty == Terror)
+ return cannotInfer(this, to, flag);
+ tiargs.push(t);
+ }
+
+ // Set target of return type inference
+ if (!tf.next && tof.next)
+ fd.treq = to;
+
+ auto ti = new TemplateInstance(loc, td, tiargs);
+ Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
+
+ // Reset inference target for the later re-semantic
+ fd.treq = null;
+
+ if (ex.op == TOK.error)
+ return MATCH.nomatch;
+ if (auto ef = ex.isFuncExp())
+ return ef.matchType(to, sc, presult, flag);
+ else
+ return cannotInfer(this, to, flag);
+ }
+
+ if (!tof || !tof.next)
+ return MATCH.nomatch;
+
+ assert(type && type != Type.tvoid);
+ if (fd.type.ty == Terror)
+ return MATCH.nomatch;
+ auto tfx = fd.type.isTypeFunction();
+ bool convertMatch = (type.ty != to.ty);
+
+ if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
+ {
+ /* If return type is inferred and covariant return,
+ * tweak return statements to required return type.
+ *
+ * interface I {}
+ * class C : Object, I{}
+ *
+ * I delegate() dg = delegate() { return new class C(); }
+ */
+ convertMatch = true;
+
+ auto tfy = new TypeFunction(tfx.parameterList, tof.next,
+ tfx.linkage, STC.undefined_);
+ tfy.mod = tfx.mod;
+ tfy.isnothrow = tfx.isnothrow;
+ tfy.isnogc = tfx.isnogc;
+ tfy.purity = tfx.purity;
+ tfy.isproperty = tfx.isproperty;
+ tfy.isref = tfx.isref;
+ tfy.isInOutParam = tfx.isInOutParam;
+ tfy.isInOutQual = tfx.isInOutQual;
+ tfy.deco = tfy.merge().deco;
+
+ tfx = tfy;
+ }
+ Type tx;
+ if (tok == TOK.delegate_ ||
+ tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
+ {
+ // Allow conversion from implicit function pointer to delegate
+ tx = new TypeDelegate(tfx);
+ tx.deco = tx.merge().deco;
+ }
+ else
+ {
+ assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer);
+ tx = tfx.pointerTo();
+ }
+ //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
+
+ MATCH m = tx.implicitConvTo(to);
+ if (m > MATCH.nomatch)
+ {
+ // MATCH.exact: exact type match
+ // MATCH.constant: covairiant type match (eg. attributes difference)
+ // MATCH.convert: context conversion
+ m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
+
+ if (presult)
+ {
+ (*presult) = cast(FuncExp)copy();
+ (*presult).type = to;
+
+ // https://issues.dlang.org/show_bug.cgi?id=12508
+ // Tweak function body for covariant returns.
+ (*presult).fd.modifyReturns(sc, tof.next);
+ }
+ }
+ else if (!flag)
+ {
+ auto ts = toAutoQualChars(tx, to);
+ error("cannot implicitly convert expression `%s` of type `%s` to `%s`",
+ toChars(), ts[0], ts[1]);
+ }
+ return m;
+ }
+
+ override const(char)* toChars() const
+ {
+ return fd.toChars();
+ }
+
+ override bool checkType()
+ {
+ if (td)
+ {
+ error("template lambda has no type");
+ return true;
+ }
+ return false;
+ }
+
+ override bool checkValue()
+ {
+ if (td)
+ {
+ error("template lambda has no value");
+ return true;
+ }
+ return false;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Declaration of a symbol
+ *
+ * D grammar allows declarations only as statements. However in AST representation
+ * it can be part of any expression. This is used, for example, during internal
+ * syntax re-writes to inject hidden symbols.
+ */
+extern (C++) final class DeclarationExp : Expression
+{
+ Dsymbol declaration;
+
+ extern (D) this(const ref Loc loc, Dsymbol declaration)
+ {
+ super(loc, TOK.declaration, __traits(classInstanceSize, DeclarationExp));
+ this.declaration = declaration;
+ }
+
+ override DeclarationExp syntaxCopy()
+ {
+ return new DeclarationExp(loc, declaration.syntaxCopy(null));
+ }
+
+ override bool hasCode()
+ {
+ if (auto vd = declaration.isVarDeclaration())
+ {
+ return !(vd.storage_class & (STC.manifest | STC.static_));
+ }
+ return false;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * typeid(int)
+ */
+extern (C++) final class TypeidExp : Expression
+{
+ RootObject obj;
+
+ extern (D) this(const ref Loc loc, RootObject o)
+ {
+ super(loc, TOK.typeid_, __traits(classInstanceSize, TypeidExp));
+ this.obj = o;
+ }
+
+ override TypeidExp syntaxCopy()
+ {
+ return new TypeidExp(loc, objectSyntaxCopy(obj));
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * __traits(identifier, args...)
+ */
+extern (C++) final class TraitsExp : Expression
+{
+ Identifier ident;
+ Objects* args;
+
+ extern (D) this(const ref Loc loc, Identifier ident, Objects* args)
+ {
+ super(loc, TOK.traits, __traits(classInstanceSize, TraitsExp));
+ this.ident = ident;
+ this.args = args;
+ }
+
+ override TraitsExp syntaxCopy()
+ {
+ return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class HaltExp : Expression
+{
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, TOK.halt, __traits(classInstanceSize, HaltExp));
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * is(targ id tok tspec)
+ * is(targ id == tok2)
+ */
+extern (C++) final class IsExp : Expression
+{
+ Type targ;
+ Identifier id; // can be null
+ Type tspec; // can be null
+ TemplateParameters* parameters;
+ TOK tok; // ':' or '=='
+ TOK tok2; // 'struct', 'union', etc.
+
+ extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters)
+ {
+ super(loc, TOK.is_, __traits(classInstanceSize, IsExp));
+ this.targ = targ;
+ this.id = id;
+ this.tok = tok;
+ this.tspec = tspec;
+ this.tok2 = tok2;
+ this.parameters = parameters;
+ }
+
+ override IsExp syntaxCopy()
+ {
+ // This section is identical to that in TemplateDeclaration::syntaxCopy()
+ TemplateParameters* p = null;
+ if (parameters)
+ {
+ p = new TemplateParameters(parameters.dim);
+ foreach (i, el; *parameters)
+ (*p)[i] = el.syntaxCopy();
+ }
+ return new IsExp(loc, targ.syntaxCopy(), id, tok, tspec ? tspec.syntaxCopy() : null, tok2, p);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) abstract class UnaExp : Expression
+{
+ Expression e1;
+ Type att1; // Save alias this type to detect recursion
+
+ extern (D) this(const ref Loc loc, TOK op, int size, Expression e1)
+ {
+ super(loc, op, size);
+ this.e1 = e1;
+ }
+
+ override UnaExp syntaxCopy()
+ {
+ UnaExp e = cast(UnaExp)copy();
+ e.type = null;
+ e.e1 = e.e1.syntaxCopy();
+ return e;
+ }
+
+ /********************************
+ * The type for a unary expression is incompatible.
+ * Print error message.
+ * Returns:
+ * ErrorExp
+ */
+ final Expression incompatibleTypes()
+ {
+ if (e1.type.toBasetype() == Type.terror)
+ return e1;
+
+ if (e1.op == TOK.type)
+ {
+ error("incompatible type for `%s(%s)`: cannot use `%s` with types", Token.toChars(op), e1.toChars(), Token.toChars(op));
+ }
+ else
+ {
+ error("incompatible type for `%s(%s)`: `%s`", Token.toChars(op), e1.toChars(), e1.type.toChars());
+ }
+ return ErrorExp.get();
+ }
+
+ /*********************
+ * Mark the operand as will never be dereferenced,
+ * which is useful info for @safe checks.
+ * Do before semantic() on operands rewrites them.
+ */
+ final void setNoderefOperand()
+ {
+ if (auto edi = e1.isDotIdExp())
+ edi.noderef = true;
+
+ }
+
+ override final Expression resolveLoc(const ref Loc loc, Scope* sc)
+ {
+ e1 = e1.resolveLoc(loc, sc);
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression);
+alias fp2_t = bool function(const ref Loc loc, TOK, Expression, Expression);
+
+/***********************************************************
+ */
+extern (C++) abstract class BinExp : Expression
+{
+ Expression e1;
+ Expression e2;
+ Type att1; // Save alias this type to detect recursion
+ Type att2; // Save alias this type to detect recursion
+
+ extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2)
+ {
+ super(loc, op, size);
+ this.e1 = e1;
+ this.e2 = e2;
+ }
+
+ override BinExp syntaxCopy()
+ {
+ BinExp e = cast(BinExp)copy();
+ e.type = null;
+ e.e1 = e.e1.syntaxCopy();
+ e.e2 = e.e2.syntaxCopy();
+ return e;
+ }
+
+ /********************************
+ * The types for a binary expression are incompatible.
+ * Print error message.
+ * Returns:
+ * ErrorExp
+ */
+ final Expression incompatibleTypes()
+ {
+ if (e1.type.toBasetype() == Type.terror)
+ return e1;
+ if (e2.type.toBasetype() == Type.terror)
+ return e2;
+
+ // CondExp uses 'a ? b : c' but we're comparing 'b : c'
+ TOK thisOp = (op == TOK.question) ? TOK.colon : op;
+ if (e1.op == TOK.type || e2.op == TOK.type)
+ {
+ error("incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
+ e1.toChars(), Token.toChars(thisOp), e2.toChars(), Token.toChars(op));
+ }
+ else if (e1.type.equals(e2.type))
+ {
+ error("incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
+ e1.toChars(), Token.toChars(thisOp), e2.toChars(), e1.type.toChars());
+ }
+ else
+ {
+ auto ts = toAutoQualChars(e1.type, e2.type);
+ error("incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
+ e1.toChars(), Token.toChars(thisOp), e2.toChars(), ts[0], ts[1]);
+ }
+ return ErrorExp.get();
+ }
+
+ extern (D) final Expression checkOpAssignTypes(Scope* sc)
+ {
+ // At that point t1 and t2 are the merged types. type is the original type of the lhs.
+ Type t1 = e1.type;
+ Type t2 = e2.type;
+
+ // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
+ // See issue 3841.
+ // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
+ if (op == TOK.addAssign || op == TOK.minAssign ||
+ op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign ||
+ op == TOK.powAssign)
+ {
+ if ((type.isintegral() && t2.isfloating()))
+ {
+ warning("`%s %s %s` is performing truncating conversion", type.toChars(), Token.toChars(op), t2.toChars());
+ }
+ }
+
+ // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
+ if (op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign)
+ {
+ // Any multiplication by an imaginary or complex number yields a complex result.
+ // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
+ const(char)* opstr = Token.toChars(op);
+ if (t1.isreal() && t2.iscomplex())
+ {
+ error("`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
+ return ErrorExp.get();
+ }
+ else if (t1.isimaginary() && t2.iscomplex())
+ {
+ error("`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
+ return ErrorExp.get();
+ }
+ else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
+ {
+ error("`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
+ return ErrorExp.get();
+ }
+ }
+
+ // generate an error if this is a nonsensical += or -=, eg real += imaginary
+ if (op == TOK.addAssign || op == TOK.minAssign)
+ {
+ // Addition or subtraction of a real and an imaginary is a complex result.
+ // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
+ if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
+ {
+ error("`%s %s %s` is undefined (result is complex)", t1.toChars(), Token.toChars(op), t2.toChars());
+ return ErrorExp.get();
+ }
+ if (type.isreal() || type.isimaginary())
+ {
+ assert(global.errors || t2.isfloating());
+ e2 = e2.castTo(sc, t1);
+ }
+ }
+ if (op == TOK.mulAssign)
+ {
+ if (t2.isfloating())
+ {
+ if (t1.isreal())
+ {
+ if (t2.isimaginary() || t2.iscomplex())
+ {
+ e2 = e2.castTo(sc, t1);
+ }
+ }
+ else if (t1.isimaginary())
+ {
+ if (t2.isimaginary() || t2.iscomplex())
+ {
+ switch (t1.ty)
+ {
+ case Timaginary32:
+ t2 = Type.tfloat32;
+ break;
+
+ case Timaginary64:
+ t2 = Type.tfloat64;
+ break;
+
+ case Timaginary80:
+ t2 = Type.tfloat80;
+ break;
+
+ default:
+ assert(0);
+ }
+ e2 = e2.castTo(sc, t2);
+ }
+ }
+ }
+ }
+ else if (op == TOK.divAssign)
+ {
+ if (t2.isimaginary())
+ {
+ if (t1.isreal())
+ {
+ // x/iv = i(-x/v)
+ // Therefore, the result is 0
+ e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
+ e2.type = t1;
+ Expression e = new AssignExp(loc, e1, e2);
+ e.type = t1;
+ return e;
+ }
+ else if (t1.isimaginary())
+ {
+ Type t3;
+ switch (t1.ty)
+ {
+ case Timaginary32:
+ t3 = Type.tfloat32;
+ break;
+
+ case Timaginary64:
+ t3 = Type.tfloat64;
+ break;
+
+ case Timaginary80:
+ t3 = Type.tfloat80;
+ break;
+
+ default:
+ assert(0);
+ }
+ e2 = e2.castTo(sc, t3);
+ Expression e = new AssignExp(loc, e1, e2);
+ e.type = t1;
+ return e;
+ }
+ }
+ }
+ else if (op == TOK.modAssign)
+ {
+ if (t2.iscomplex())
+ {
+ error("cannot perform modulo complex arithmetic");
+ return ErrorExp.get();
+ }
+ }
+ return this;
+ }
+
+ extern (D) final bool checkIntegralBin()
+ {
+ bool r1 = e1.checkIntegral();
+ bool r2 = e2.checkIntegral();
+ return (r1 || r2);
+ }
+
+ extern (D) final bool checkArithmeticBin()
+ {
+ bool r1 = e1.checkArithmetic();
+ bool r2 = e2.checkArithmetic();
+ return (r1 || r2);
+ }
+
+ extern (D) final bool checkSharedAccessBin(Scope* sc)
+ {
+ const r1 = e1.checkSharedAccess(sc);
+ const r2 = e2.checkSharedAccess(sc);
+ return (r1 || r2);
+ }
+
+ /*********************
+ * Mark the operands as will never be dereferenced,
+ * which is useful info for @safe checks.
+ * Do before semantic() on operands rewrites them.
+ */
+ final void setNoderefOperands()
+ {
+ if (auto edi = e1.isDotIdExp())
+ edi.noderef = true;
+ if (auto edi = e2.isDotIdExp())
+ edi.noderef = true;
+
+ }
+
+ final Expression reorderSettingAAElem(Scope* sc)
+ {
+ BinExp be = this;
+
+ auto ie = be.e1.isIndexExp();
+ if (!ie)
+ return be;
+ if (ie.e1.type.toBasetype().ty != Taarray)
+ return be;
+
+ /* Fix evaluation order of setting AA element
+ * https://issues.dlang.org/show_bug.cgi?id=3825
+ * Rewrite:
+ * aa[k1][k2][k3] op= val;
+ * as:
+ * auto ref __aatmp = aa;
+ * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
+ * auto ref __aaval = val;
+ * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
+ */
+
+ Expression e0;
+ while (1)
+ {
+ Expression de;
+ ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
+ e0 = Expression.combine(de, e0);
+
+ auto ie1 = ie.e1.isIndexExp();
+ if (!ie1 ||
+ ie1.e1.type.toBasetype().ty != Taarray)
+ {
+ break;
+ }
+ ie = ie1;
+ }
+ assert(ie.e1.type.toBasetype().ty == Taarray);
+
+ Expression de;
+ ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
+ e0 = Expression.combine(de, e0);
+
+ be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
+
+ //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
+ return Expression.combine(e0, be);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) class BinAssignExp : BinExp
+{
+ extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2)
+ {
+ super(loc, op, size, e1, e2);
+ }
+
+ override final bool isLvalue()
+ {
+ return true;
+ }
+
+ override final Expression toLvalue(Scope* sc, Expression ex)
+ {
+ // Lvalue-ness will be handled in glue layer.
+ return this;
+ }
+
+ override final Expression modifiableLvalue(Scope* sc, Expression e)
+ {
+ // should check e1.checkModifiable() ?
+ return toLvalue(sc, this);
+ }
+
+ override inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc @safe
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/expression.html#mixin_expressions
+ */
+extern (C++) final class MixinExp : Expression
+{
+ Expressions* exps;
+
+ extern (D) this(const ref Loc loc, Expressions* exps)
+ {
+ super(loc, TOK.mixin_, __traits(classInstanceSize, MixinExp));
+ this.exps = exps;
+ }
+
+ override MixinExp syntaxCopy()
+ {
+ return new MixinExp(loc, arraySyntaxCopy(exps));
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+ auto e = o.isExpression();
+ if (!e)
+ return false;
+ if (auto ce = e.isMixinExp())
+ {
+ if (exps.dim != ce.exps.dim)
+ return false;
+ foreach (i, e1; *exps)
+ {
+ auto e2 = (*ce.exps)[i];
+ if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ImportExp : UnaExp
+{
+ extern (D) this(const ref Loc loc, Expression e)
+ {
+ super(loc, TOK.import_, __traits(classInstanceSize, ImportExp), e);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/expression.html#assert_expressions
+ */
+extern (C++) final class AssertExp : UnaExp
+{
+ Expression msg;
+
+ extern (D) this(const ref Loc loc, Expression e, Expression msg = null)
+ {
+ super(loc, TOK.assert_, __traits(classInstanceSize, AssertExp), e);
+ this.msg = msg;
+ }
+
+ override AssertExp syntaxCopy()
+ {
+ return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DotIdExp : UnaExp
+{
+ Identifier ident;
+ bool noderef; // true if the result of the expression will never be dereferenced
+ bool wantsym; // do not replace Symbol with its initializer during semantic()
+
+ extern (D) this(const ref Loc loc, Expression e, Identifier ident)
+ {
+ super(loc, TOK.dotIdentifier, __traits(classInstanceSize, DotIdExp), e);
+ this.ident = ident;
+ }
+
+ static DotIdExp create(Loc loc, Expression e, Identifier ident)
+ {
+ return new DotIdExp(loc, e, ident);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Mainly just a placeholder
+ */
+extern (C++) final class DotTemplateExp : UnaExp
+{
+ TemplateDeclaration td;
+
+ extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td)
+ {
+ super(loc, TOK.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e);
+ this.td = td;
+ }
+
+ override bool checkType()
+ {
+ error("%s `%s` has no type", td.kind(), toChars());
+ return true;
+ }
+
+ override bool checkValue()
+ {
+ error("%s `%s` has no value", td.kind(), toChars());
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DotVarExp : UnaExp
+{
+ Declaration var;
+ bool hasOverloads;
+
+ extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true)
+ {
+ if (var.isVarDeclaration())
+ hasOverloads = false;
+
+ super(loc, TOK.dotVariable, __traits(classInstanceSize, DotVarExp), e);
+ //printf("DotVarExp()\n");
+ this.var = var;
+ this.hasOverloads = hasOverloads;
+ }
+
+ override bool isLvalue()
+ {
+ if (e1.op != TOK.structLiteral)
+ return true;
+ auto vd = var.isVarDeclaration();
+ return !(vd && vd.isField());
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ //printf("DotVarExp::toLvalue(%s)\n", toChars());
+ if (sc && sc.flags & SCOPE.Cfile)
+ {
+ /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
+ * is an lvalue if the first expression is an lvalue.
+ */
+ if (!e1.isLvalue())
+ return Expression.toLvalue(sc, e);
+ }
+ if (!isLvalue())
+ return Expression.toLvalue(sc, e);
+ if (e1.op == TOK.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
+ {
+ if (VarDeclaration vd = var.isVarDeclaration())
+ {
+ auto ad = vd.isMember2();
+ if (ad && ad.fields.dim == sc.ctorflow.fieldinit.length)
+ {
+ foreach (i, f; ad.fields)
+ {
+ if (f == vd)
+ {
+ if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor))
+ {
+ /* If the address of vd is taken, assume it is thereby initialized
+ * https://issues.dlang.org/show_bug.cgi?id=15869
+ */
+ modifyFieldVar(loc, sc, vd, e1);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ return this;
+ }
+
+ override Expression modifiableLvalue(Scope* sc, Expression e)
+ {
+ version (none)
+ {
+ printf("DotVarExp::modifiableLvalue(%s)\n", toChars());
+ printf("e1.type = %s\n", e1.type.toChars());
+ printf("var.type = %s\n", var.type.toChars());
+ }
+
+ return Expression.modifiableLvalue(sc, e);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * foo.bar!(args)
+ */
+extern (C++) final class DotTemplateInstanceExp : UnaExp
+{
+ TemplateInstance ti;
+
+ extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
+ {
+ super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
+ //printf("DotTemplateInstanceExp()\n");
+ this.ti = new TemplateInstance(loc, name, tiargs);
+ }
+
+ extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti)
+ {
+ super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
+ this.ti = ti;
+ }
+
+ override DotTemplateInstanceExp syntaxCopy()
+ {
+ return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs));
+ }
+
+ bool findTempDecl(Scope* sc)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars());
+ }
+ if (ti.tempdecl)
+ return true;
+
+ Expression e = new DotIdExp(loc, e1, ti.name);
+ e = e.expressionSemantic(sc);
+ if (e.op == TOK.dot)
+ e = (cast(DotExp)e).e2;
+
+ Dsymbol s = null;
+ switch (e.op)
+ {
+ case TOK.overloadSet:
+ s = (cast(OverExp)e).vars;
+ break;
+
+ case TOK.dotTemplateDeclaration:
+ s = (cast(DotTemplateExp)e).td;
+ break;
+
+ case TOK.scope_:
+ s = (cast(ScopeExp)e).sds;
+ break;
+
+ case TOK.dotVariable:
+ s = (cast(DotVarExp)e).var;
+ break;
+
+ case TOK.variable:
+ s = (cast(VarExp)e).var;
+ break;
+
+ default:
+ return false;
+ }
+ return ti.updateTempDecl(sc, s);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DelegateExp : UnaExp
+{
+ FuncDeclaration func;
+ bool hasOverloads;
+ VarDeclaration vthis2; // container for multi-context
+
+ extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null)
+ {
+ super(loc, TOK.delegate_, __traits(classInstanceSize, DelegateExp), e);
+ this.func = f;
+ this.hasOverloads = hasOverloads;
+ this.vthis2 = vthis2;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DotTypeExp : UnaExp
+{
+ Dsymbol sym; // symbol that represents a type
+
+ extern (D) this(const ref Loc loc, Expression e, Dsymbol s)
+ {
+ super(loc, TOK.dotType, __traits(classInstanceSize, DotTypeExp), e);
+ this.sym = s;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class CallExp : UnaExp
+{
+ Expressions* arguments; // function arguments
+ FuncDeclaration f; // symbol to call
+ bool directcall; // true if a virtual call is devirtualized
+ bool inDebugStatement; /// true if this was in a debug statement
+ bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code)
+ VarDeclaration vthis2; // container for multi-context
+
+ extern (D) this(const ref Loc loc, Expression e, Expressions* exps)
+ {
+ super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
+ this.arguments = exps;
+ }
+
+ extern (D) this(const ref Loc loc, Expression e)
+ {
+ super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
+ }
+
+ extern (D) this(const ref Loc loc, Expression e, Expression earg1)
+ {
+ super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
+ this.arguments = new Expressions();
+ if (earg1)
+ this.arguments.push(earg1);
+ }
+
+ extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
+ {
+ super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
+ auto arguments = new Expressions(2);
+ (*arguments)[0] = earg1;
+ (*arguments)[1] = earg2;
+ this.arguments = arguments;
+ }
+
+ /***********************************************************
+ * Instatiates a new function call expression
+ * Params:
+ * loc = location
+ * fd = the declaration of the function to call
+ * earg1 = the function argument
+ */
+ extern(D) this(const ref Loc loc, FuncDeclaration fd, Expression earg1)
+ {
+ this(loc, new VarExp(loc, fd, false), earg1);
+ this.f = fd;
+ }
+
+ static CallExp create(Loc loc, Expression e, Expressions* exps)
+ {
+ return new CallExp(loc, e, exps);
+ }
+
+ static CallExp create(Loc loc, Expression e)
+ {
+ return new CallExp(loc, e);
+ }
+
+ static CallExp create(Loc loc, Expression e, Expression earg1)
+ {
+ return new CallExp(loc, e, earg1);
+ }
+
+ /***********************************************************
+ * Creates a new function call expression
+ * Params:
+ * loc = location
+ * fd = the declaration of the function to call
+ * earg1 = the function argument
+ */
+ static CallExp create(Loc loc, FuncDeclaration fd, Expression earg1)
+ {
+ return new CallExp(loc, fd, earg1);
+ }
+
+ override CallExp syntaxCopy()
+ {
+ return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
+ }
+
+ override bool isLvalue()
+ {
+ Type tb = e1.type.toBasetype();
+ if (tb.ty == Tdelegate || tb.ty == Tpointer)
+ tb = tb.nextOf();
+ auto tf = tb.isTypeFunction();
+ if (tf && tf.isref)
+ {
+ if (auto dve = e1.isDotVarExp())
+ if (dve.var.isCtorDeclaration())
+ return false;
+ return true; // function returns a reference
+ }
+ return false;
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ if (isLvalue())
+ return this;
+ return Expression.toLvalue(sc, e);
+ }
+
+ override Expression addDtorHook(Scope* sc)
+ {
+ /* Only need to add dtor hook if it's a type that needs destruction.
+ * Use same logic as VarDeclaration::callScopeDtor()
+ */
+
+ if (auto tf = e1.type.isTypeFunction())
+ {
+ if (tf.isref)
+ return this;
+ }
+
+ Type tv = type.baseElemOf();
+ if (auto ts = tv.isTypeStruct())
+ {
+ StructDeclaration sd = ts.sym;
+ if (sd.dtor)
+ {
+ /* Type needs destruction, so declare a tmp
+ * which the back end will recognize and call dtor on
+ */
+ auto tmp = copyToTemp(0, "__tmpfordtor", this);
+ auto de = new DeclarationExp(loc, tmp);
+ auto ve = new VarExp(loc, tmp);
+ Expression e = new CommaExp(loc, de, ve);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ }
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null)
+{
+ if (auto ae = e.isAddrExp())
+ {
+ auto ae1 = ae.e1;
+ if (auto ve = ae1.isVarExp())
+ {
+ if (hasOverloads)
+ *hasOverloads = ve.hasOverloads;
+ return ve.var.isFuncDeclaration();
+ }
+ if (auto dve = ae1.isDotVarExp())
+ {
+ if (hasOverloads)
+ *hasOverloads = dve.hasOverloads;
+ return dve.var.isFuncDeclaration();
+ }
+ }
+ else
+ {
+ if (auto soe = e.isSymOffExp())
+ {
+ if (hasOverloads)
+ *hasOverloads = soe.hasOverloads;
+ return soe.var.isFuncDeclaration();
+ }
+ if (auto dge = e.isDelegateExp())
+ {
+ if (hasOverloads)
+ *hasOverloads = dge.hasOverloads;
+ return dge.func.isFuncDeclaration();
+ }
+ }
+ return null;
+}
+
+/***********************************************************
+ */
+extern (C++) final class AddrExp : UnaExp
+{
+ extern (D) this(const ref Loc loc, Expression e)
+ {
+ super(loc, TOK.address, __traits(classInstanceSize, AddrExp), e);
+ }
+
+ extern (D) this(const ref Loc loc, Expression e, Type t)
+ {
+ this(loc, e);
+ type = t;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class PtrExp : UnaExp
+{
+ extern (D) this(const ref Loc loc, Expression e)
+ {
+ super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e);
+ //if (e.type)
+ // type = ((TypePointer *)e.type).next;
+ }
+
+ extern (D) this(const ref Loc loc, Expression e, Type t)
+ {
+ super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e);
+ type = t;
+ }
+
+ override bool isLvalue()
+ {
+ return true;
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ return this;
+ }
+
+ override Expression modifiableLvalue(Scope* sc, Expression e)
+ {
+ //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type.toChars());
+ return Expression.modifiableLvalue(sc, e);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class NegExp : UnaExp
+{
+ extern (D) this(const ref Loc loc, Expression e)
+ {
+ super(loc, TOK.negate, __traits(classInstanceSize, NegExp), e);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class UAddExp : UnaExp
+{
+ extern (D) this(const ref Loc loc, Expression e)
+ {
+ super(loc, TOK.uadd, __traits(classInstanceSize, UAddExp), e);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ComExp : UnaExp
+{
+ extern (D) this(const ref Loc loc, Expression e)
+ {
+ super(loc, TOK.tilde, __traits(classInstanceSize, ComExp), e);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class NotExp : UnaExp
+{
+ extern (D) this(const ref Loc loc, Expression e)
+ {
+ super(loc, TOK.not, __traits(classInstanceSize, NotExp), e);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DeleteExp : UnaExp
+{
+ bool isRAII; // true if called automatically as a result of scoped destruction
+
+ extern (D) this(const ref Loc loc, Expression e, bool isRAII)
+ {
+ super(loc, TOK.delete_, __traits(classInstanceSize, DeleteExp), e);
+ this.isRAII = isRAII;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Possible to cast to one type while painting to another type
+ */
+extern (C++) final class CastExp : UnaExp
+{
+ Type to; // type to cast to
+ ubyte mod = cast(ubyte)~0; // MODxxxxx
+
+ extern (D) this(const ref Loc loc, Expression e, Type t)
+ {
+ super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e);
+ this.to = t;
+ }
+
+ /* For cast(const) and cast(immutable)
+ */
+ extern (D) this(const ref Loc loc, Expression e, ubyte mod)
+ {
+ super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e);
+ this.mod = mod;
+ }
+
+ override CastExp syntaxCopy()
+ {
+ return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod);
+ }
+
+ override bool isLvalue()
+ {
+ //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars());
+ if (!e1.isLvalue())
+ return false;
+ return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) ||
+ e1.type.mutableOf().unSharedOf().equals(to.mutableOf().unSharedOf());
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ if (sc && sc.flags & SCOPE.Cfile)
+ {
+ /* C11 6.5.4-5: A cast does not yield an lvalue.
+ */
+ return Expression.toLvalue(sc, e);
+ }
+ if (isLvalue())
+ return this;
+ return Expression.toLvalue(sc, e);
+ }
+
+ override Expression addDtorHook(Scope* sc)
+ {
+ if (to.toBasetype().ty == Tvoid) // look past the cast(void)
+ e1 = e1.addDtorHook(sc);
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class VectorExp : UnaExp
+{
+ TypeVector to; // the target vector type before semantic()
+ uint dim = ~0; // number of elements in the vector
+ OwnedBy ownedByCtfe = OwnedBy.code;
+
+ extern (D) this(const ref Loc loc, Expression e, Type t)
+ {
+ super(loc, TOK.vector, __traits(classInstanceSize, VectorExp), e);
+ assert(t.ty == Tvector);
+ to = cast(TypeVector)t;
+ }
+
+ static VectorExp create(Loc loc, Expression e, Type t)
+ {
+ return new VectorExp(loc, e, t);
+ }
+
+ // Same as create, but doesn't allocate memory.
+ static void emplace(UnionExp* pue, Loc loc, Expression e, Type type)
+ {
+ emplaceExp!(VectorExp)(pue, loc, e, type);
+ }
+
+ override VectorExp syntaxCopy()
+ {
+ return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy());
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * e1.array property for vectors.
+ *
+ * https://dlang.org/spec/simd.html#properties
+ */
+extern (C++) final class VectorArrayExp : UnaExp
+{
+ extern (D) this(const ref Loc loc, Expression e1)
+ {
+ super(loc, TOK.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1);
+ }
+
+ override bool isLvalue()
+ {
+ return e1.isLvalue();
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ e1 = e1.toLvalue(sc, e);
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * e1 [lwr .. upr]
+ *
+ * http://dlang.org/spec/expression.html#slice_expressions
+ */
+extern (C++) final class SliceExp : UnaExp
+{
+ Expression upr; // null if implicit 0
+ Expression lwr; // null if implicit [length - 1]
+
+ VarDeclaration lengthVar;
+ bool upperIsInBounds; // true if upr <= e1.length
+ bool lowerIsLessThanUpper; // true if lwr <= upr
+ bool arrayop; // an array operation, rather than a slice
+
+ /************************************************************/
+ extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie)
+ {
+ super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1);
+ this.upr = ie ? ie.upr : null;
+ this.lwr = ie ? ie.lwr : null;
+ }
+
+ extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr)
+ {
+ super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1);
+ this.upr = upr;
+ this.lwr = lwr;
+ }
+
+ override SliceExp syntaxCopy()
+ {
+ auto se = new SliceExp(loc, e1.syntaxCopy(), lwr ? lwr.syntaxCopy() : null, upr ? upr.syntaxCopy() : null);
+ se.lengthVar = this.lengthVar; // bug7871
+ return se;
+ }
+
+ override bool isLvalue()
+ {
+ /* slice expression is rvalue in default, but
+ * conversion to reference of static array is only allowed.
+ */
+ return (type && type.toBasetype().ty == Tsarray);
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
+ return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
+ }
+
+ override Expression modifiableLvalue(Scope* sc, Expression e)
+ {
+ error("slice expression `%s` is not a modifiable lvalue", toChars());
+ return this;
+ }
+
+ override bool isBool(bool result)
+ {
+ return e1.isBool(result);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ArrayLengthExp : UnaExp
+{
+ extern (D) this(const ref Loc loc, Expression e1)
+ {
+ super(loc, TOK.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * e1 [ a0, a1, a2, a3 ,... ]
+ *
+ * http://dlang.org/spec/expression.html#index_expressions
+ */
+extern (C++) final class ArrayExp : UnaExp
+{
+ Expressions* arguments; // Array of Expression's a0..an
+
+ size_t currentDimension; // for opDollar
+ VarDeclaration lengthVar;
+
+ extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
+ {
+ super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1);
+ arguments = new Expressions();
+ if (index)
+ arguments.push(index);
+ }
+
+ extern (D) this(const ref Loc loc, Expression e1, Expressions* args)
+ {
+ super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1);
+ arguments = args;
+ }
+
+ override ArrayExp syntaxCopy()
+ {
+ auto ae = new ArrayExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
+ ae.lengthVar = this.lengthVar; // bug7871
+ return ae;
+ }
+
+ override bool isLvalue()
+ {
+ if (type && type.toBasetype().ty == Tvoid)
+ return false;
+ return true;
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ if (type && type.toBasetype().ty == Tvoid)
+ error("`void`s have no value");
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DotExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.dot, __traits(classInstanceSize, DotExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class CommaExp : BinExp
+{
+ /// This is needed because AssignExp rewrites CommaExp, hence it needs
+ /// to trigger the deprecation.
+ const bool isGenerated;
+
+ /// Temporary variable to enable / disable deprecation of comma expression
+ /// depending on the context.
+ /// Since most constructor calls are rewritting, the only place where
+ /// false will be passed will be from the parser.
+ bool allowCommaExp;
+
+
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true)
+ {
+ super(loc, TOK.comma, __traits(classInstanceSize, CommaExp), e1, e2);
+ allowCommaExp = isGenerated = generated;
+ }
+
+ override bool isLvalue()
+ {
+ return e2.isLvalue();
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ e2 = e2.toLvalue(sc, null);
+ return this;
+ }
+
+ override Expression modifiableLvalue(Scope* sc, Expression e)
+ {
+ e2 = e2.modifiableLvalue(sc, e);
+ return this;
+ }
+
+ override bool isBool(bool result)
+ {
+ return e2.isBool(result);
+ }
+
+ override Expression addDtorHook(Scope* sc)
+ {
+ e2 = e2.addDtorHook(sc);
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ /**
+ * If the argument is a CommaExp, set a flag to prevent deprecation messages
+ *
+ * It's impossible to know from CommaExp.semantic if the result will
+ * be used, hence when there is a result (type != void), a deprecation
+ * message is always emitted.
+ * However, some construct can produce a result but won't use it
+ * (ExpStatement and for loop increment). Those should call this function
+ * to prevent unwanted deprecations to be emitted.
+ *
+ * Params:
+ * exp = An expression that discards its result.
+ * If the argument is null or not a CommaExp, nothing happens.
+ */
+ static void allow(Expression exp)
+ {
+ if (exp)
+ if (auto ce = exp.isCommaExp())
+ ce.allowCommaExp = true;
+ }
+}
+
+/***********************************************************
+ * Mainly just a placeholder
+ */
+extern (C++) final class IntervalExp : Expression
+{
+ Expression lwr;
+ Expression upr;
+
+ extern (D) this(const ref Loc loc, Expression lwr, Expression upr)
+ {
+ super(loc, TOK.interval, __traits(classInstanceSize, IntervalExp));
+ this.lwr = lwr;
+ this.upr = upr;
+ }
+
+ override Expression syntaxCopy()
+ {
+ return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy());
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+extern (C++) final class DelegatePtrExp : UnaExp
+{
+ extern (D) this(const ref Loc loc, Expression e1)
+ {
+ super(loc, TOK.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1);
+ }
+
+ override bool isLvalue()
+ {
+ return e1.isLvalue();
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ e1 = e1.toLvalue(sc, e);
+ return this;
+ }
+
+ override Expression modifiableLvalue(Scope* sc, Expression e)
+ {
+ if (sc.func.setUnsafe())
+ {
+ error("cannot modify delegate pointer in `@safe` code `%s`", toChars());
+ return ErrorExp.get();
+ }
+ return Expression.modifiableLvalue(sc, e);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DelegateFuncptrExp : UnaExp
+{
+ extern (D) this(const ref Loc loc, Expression e1)
+ {
+ super(loc, TOK.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1);
+ }
+
+ override bool isLvalue()
+ {
+ return e1.isLvalue();
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ e1 = e1.toLvalue(sc, e);
+ return this;
+ }
+
+ override Expression modifiableLvalue(Scope* sc, Expression e)
+ {
+ if (sc.func.setUnsafe())
+ {
+ error("cannot modify delegate function pointer in `@safe` code `%s`", toChars());
+ return ErrorExp.get();
+ }
+ return Expression.modifiableLvalue(sc, e);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * e1 [ e2 ]
+ */
+extern (C++) final class IndexExp : BinExp
+{
+ VarDeclaration lengthVar;
+ bool modifiable = false; // assume it is an rvalue
+ bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
+
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.index, __traits(classInstanceSize, IndexExp), e1, e2);
+ //printf("IndexExp::IndexExp('%s')\n", toChars());
+ }
+
+ override IndexExp syntaxCopy()
+ {
+ auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy());
+ ie.lengthVar = this.lengthVar; // bug7871
+ return ie;
+ }
+
+ override bool isLvalue()
+ {
+ if (e1.op == TOK.assocArrayLiteral)
+ return false;
+ if (e1.type.ty == Tsarray ||
+ (e1.op == TOK.index && e1.type.ty != Tarray))
+ {
+ return e1.isLvalue();
+ }
+ return true;
+ }
+
+ override Expression toLvalue(Scope* sc, Expression e)
+ {
+ if (isLvalue())
+ return this;
+ return Expression.toLvalue(sc, e);
+ }
+
+ override Expression modifiableLvalue(Scope* sc, Expression e)
+ {
+ //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
+ Expression ex = markSettingAAElem();
+ if (ex.op == TOK.error)
+ return ex;
+
+ return Expression.modifiableLvalue(sc, e);
+ }
+
+ extern (D) Expression markSettingAAElem()
+ {
+ if (e1.type.toBasetype().ty == Taarray)
+ {
+ Type t2b = e2.type.toBasetype();
+ if (t2b.ty == Tarray && t2b.nextOf().isMutable())
+ {
+ error("associative arrays can only be assigned values with immutable keys, not `%s`", e2.type.toChars());
+ return ErrorExp.get();
+ }
+ modifiable = true;
+
+ if (auto ie = e1.isIndexExp())
+ {
+ Expression ex = ie.markSettingAAElem();
+ if (ex.op == TOK.error)
+ return ex;
+ assert(ex == e1);
+ }
+ }
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * For both i++ and i--
+ */
+extern (C++) final class PostExp : BinExp
+{
+ extern (D) this(TOK op, const ref Loc loc, Expression e)
+ {
+ super(loc, op, __traits(classInstanceSize, PostExp), e, IntegerExp.literal!1);
+ assert(op == TOK.minusMinus || op == TOK.plusPlus);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * For both ++i and --i
+ */
+extern (C++) final class PreExp : UnaExp
+{
+ extern (D) this(TOK op, const ref Loc loc, Expression e)
+ {
+ super(loc, op, __traits(classInstanceSize, PreExp), e);
+ assert(op == TOK.preMinusMinus || op == TOK.prePlusPlus);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+enum MemorySet
+{
+ none = 0, // simple assignment
+ blockAssign = 1, // setting the contents of an array
+ referenceInit = 2, // setting the reference of STC.ref_ variable
+}
+
+/***********************************************************
+ */
+extern (C++) class AssignExp : BinExp
+{
+ MemorySet memset;
+
+ /************************************************************/
+ /* op can be TOK.assign, TOK.construct, or TOK.blit */
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.assign, __traits(classInstanceSize, AssignExp), e1, e2);
+ }
+
+ this(const ref Loc loc, TOK tok, Expression e1, Expression e2)
+ {
+ super(loc, tok, __traits(classInstanceSize, AssignExp), e1, e2);
+ }
+
+ override final bool isLvalue()
+ {
+ // Array-op 'x[] = y[]' should make an rvalue.
+ // Setting array length 'x.length = v' should make an rvalue.
+ if (e1.op == TOK.slice || e1.op == TOK.arrayLength)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ override final Expression toLvalue(Scope* sc, Expression ex)
+ {
+ if (e1.op == TOK.slice || e1.op == TOK.arrayLength)
+ {
+ return Expression.toLvalue(sc, ex);
+ }
+
+ /* In front-end level, AssignExp should make an lvalue of e1.
+ * Taking the address of e1 will be handled in low level layer,
+ * so this function does nothing.
+ */
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ConstructExp : AssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.construct, e1, e2);
+ }
+
+ // Internal use only. If `v` is a reference variable, the assignment
+ // will become a reference initialization automatically.
+ extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2)
+ {
+ auto ve = new VarExp(loc, v);
+ assert(v.type && ve.type);
+
+ super(loc, TOK.construct, ve, e2);
+
+ if (v.isReference())
+ memset = MemorySet.referenceInit;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class BlitExp : AssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.blit, e1, e2);
+ }
+
+ // Internal use only. If `v` is a reference variable, the assinment
+ // will become a reference rebinding automatically.
+ extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2)
+ {
+ auto ve = new VarExp(loc, v);
+ assert(v.type && ve.type);
+
+ super(loc, TOK.blit, ve, e2);
+
+ if (v.isReference())
+ memset = MemorySet.referenceInit;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class AddAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class MinAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class MulAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DivAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ModAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class AndAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class OrAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class XorAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class PowAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ShlAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ShrAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class UshrAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * The ~= operator. It can have one of the following operators:
+ *
+ * TOK.concatenateAssign - appending T[] to T[]
+ * TOK.concatenateElemAssign - appending T to T[]
+ * TOK.concatenateDcharAssign - appending dchar to T[]
+ *
+ * The parser initially sets it to TOK.concatenateAssign, and semantic() later decides which
+ * of the three it will be set to.
+ */
+extern (C++) class CatAssignExp : BinAssignExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2);
+ }
+
+ extern (D) this(const ref Loc loc, TOK tok, Expression e1, Expression e2)
+ {
+ super(loc, tok, __traits(classInstanceSize, CatAssignExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+///
+extern (C++) final class CatElemAssignExp : CatAssignExp
+{
+ extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
+ {
+ super(loc, TOK.concatenateElemAssign, e1, e2);
+ this.type = type;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+///
+extern (C++) final class CatDcharAssignExp : CatAssignExp
+{
+ extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
+ {
+ super(loc, TOK.concatenateDcharAssign, e1, e2);
+ this.type = type;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * http://dlang.org/spec/expression.html#add_expressions
+ */
+extern (C++) final class AddExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.add, __traits(classInstanceSize, AddExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class MinExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.min, __traits(classInstanceSize, MinExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * http://dlang.org/spec/expression.html#cat_expressions
+ */
+extern (C++) final class CatExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.concatenate, __traits(classInstanceSize, CatExp), e1, e2);
+ }
+
+ override Expression resolveLoc(const ref Loc loc, Scope* sc)
+ {
+ e1 = e1.resolveLoc(loc, sc);
+ e2 = e2.resolveLoc(loc, sc);
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * http://dlang.org/spec/expression.html#mul_expressions
+ */
+extern (C++) final class MulExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.mul, __traits(classInstanceSize, MulExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * http://dlang.org/spec/expression.html#mul_expressions
+ */
+extern (C++) final class DivExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.div, __traits(classInstanceSize, DivExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * http://dlang.org/spec/expression.html#mul_expressions
+ */
+extern (C++) final class ModExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.mod, __traits(classInstanceSize, ModExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * http://dlang.org/spec/expression.html#pow_expressions
+ */
+extern (C++) final class PowExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.pow, __traits(classInstanceSize, PowExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ShlExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.leftShift, __traits(classInstanceSize, ShlExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ShrExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.rightShift, __traits(classInstanceSize, ShrExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class UshrExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class AndExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.and, __traits(classInstanceSize, AndExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class OrExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.or, __traits(classInstanceSize, OrExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class XorExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.xor, __traits(classInstanceSize, XorExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * http://dlang.org/spec/expression.html#andand_expressions
+ * http://dlang.org/spec/expression.html#oror_expressions
+ */
+extern (C++) final class LogicalExp : BinExp
+{
+ extern (D) this(const ref Loc loc, TOK op, Expression e1, Expression e2)
+ {
+ super(loc, op, __traits(classInstanceSize, LogicalExp), e1, e2);
+ assert(op == TOK.andAnd || op == TOK.orOr);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * `op` is one of:
+ * TOK.lessThan, TOK.lessOrEqual, TOK.greaterThan, TOK.greaterOrEqual
+ *
+ * http://dlang.org/spec/expression.html#relation_expressions
+ */
+extern (C++) final class CmpExp : BinExp
+{
+ extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, op, __traits(classInstanceSize, CmpExp), e1, e2);
+ assert(op == TOK.lessThan || op == TOK.lessOrEqual || op == TOK.greaterThan || op == TOK.greaterOrEqual);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class InExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.in_, __traits(classInstanceSize, InExp), e1, e2);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * This deletes the key e1 from the associative array e2
+ */
+extern (C++) final class RemoveExp : BinExp
+{
+ extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, TOK.remove, __traits(classInstanceSize, RemoveExp), e1, e2);
+ type = Type.tbool;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * `==` and `!=`
+ *
+ * TOK.equal and TOK.notEqual
+ *
+ * http://dlang.org/spec/expression.html#equality_expressions
+ */
+extern (C++) final class EqualExp : BinExp
+{
+ extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, op, __traits(classInstanceSize, EqualExp), e1, e2);
+ assert(op == TOK.equal || op == TOK.notEqual);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * `is` and `!is`
+ *
+ * TOK.identity and TOK.notIdentity
+ *
+ * http://dlang.org/spec/expression.html#identity_expressions
+ */
+extern (C++) final class IdentityExp : BinExp
+{
+ extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
+ {
+ super(loc, op, __traits(classInstanceSize, IdentityExp), e1, e2);
+ assert(op == TOK.identity || op == TOK.notIdentity);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * `econd ? e1 : e2`
+ *
+ * http://dlang.org/spec/expression.html#conditional_expressions
+ */
+extern (C++) final class CondExp : BinExp
+{
+ Expression econd;
+
+ extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2)
+ {
+ super(loc, TOK.question, __traits(classInstanceSize, CondExp), e1, e2);
+ this.econd = econd;
+ }
+
+ override CondExp syntaxCopy()
+ {
+ return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy());
+ }
+
+ override bool isLvalue()
+ {
+ return e1.isLvalue() && e2.isLvalue();
+ }
+
+ override Expression toLvalue(Scope* sc, Expression ex)
+ {
+ // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
+ CondExp e = cast(CondExp)copy();
+ e.e1 = e1.toLvalue(sc, null).addressOf();
+ e.e2 = e2.toLvalue(sc, null).addressOf();
+ e.type = type.pointerTo();
+ return new PtrExp(loc, e, type);
+ }
+
+ override Expression modifiableLvalue(Scope* sc, Expression e)
+ {
+ if (!e1.isLvalue() && !e2.isLvalue())
+ {
+ error("conditional expression `%s` is not a modifiable lvalue", toChars());
+ return ErrorExp.get();
+ }
+ e1 = e1.modifiableLvalue(sc, e1);
+ e2 = e2.modifiableLvalue(sc, e2);
+ return toLvalue(sc, this);
+ }
+
+ void hookDtors(Scope* sc)
+ {
+ extern (C++) final class DtorVisitor : StoppableVisitor
+ {
+ alias visit = typeof(super).visit;
+ public:
+ Scope* sc;
+ CondExp ce;
+ VarDeclaration vcond;
+ bool isThen;
+
+ extern (D) this(Scope* sc, CondExp ce)
+ {
+ this.sc = sc;
+ this.ce = ce;
+ }
+
+ override void visit(Expression e)
+ {
+ //printf("(e = %s)\n", e.toChars());
+ }
+
+ override void visit(DeclarationExp e)
+ {
+ auto v = e.declaration.isVarDeclaration();
+ if (v && !v.isDataseg())
+ {
+ if (v._init)
+ {
+ if (auto ei = v._init.isExpInitializer())
+ walkPostorder(ei.exp, this);
+ }
+
+ if (v.edtor)
+ walkPostorder(v.edtor, this);
+
+ if (v.needsScopeDtor())
+ {
+ if (!vcond)
+ {
+ vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd);
+ vcond.dsymbolSemantic(sc);
+
+ Expression de = new DeclarationExp(ce.econd.loc, vcond);
+ de = de.expressionSemantic(sc);
+
+ Expression ve = new VarExp(ce.econd.loc, vcond);
+ ce.econd = Expression.combine(de, ve);
+ }
+
+ //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
+ Expression ve = new VarExp(vcond.loc, vcond);
+ if (isThen)
+ v.edtor = new LogicalExp(v.edtor.loc, TOK.andAnd, ve, v.edtor);
+ else
+ v.edtor = new LogicalExp(v.edtor.loc, TOK.orOr, ve, v.edtor);
+ v.edtor = v.edtor.expressionSemantic(sc);
+ //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
+ }
+ }
+ }
+ }
+
+ scope DtorVisitor v = new DtorVisitor(sc, this);
+ //printf("+%s\n", toChars());
+ v.isThen = true;
+ walkPostorder(e1, v);
+ v.isThen = false;
+ walkPostorder(e2, v);
+ //printf("-%s\n", toChars());
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/// Returns: if this token is the `op` for a derived `DefaultInitExp` class.
+bool isDefaultInitOp(TOK op) pure nothrow @safe @nogc
+{
+ return op == TOK.prettyFunction || op == TOK.functionString ||
+ op == TOK.line || op == TOK.moduleString ||
+ op == TOK.file || op == TOK.fileFullPath ;
+}
+
+/***********************************************************
+ */
+extern (C++) class DefaultInitExp : Expression
+{
+ extern (D) this(const ref Loc loc, TOK op, int size)
+ {
+ super(loc, op, size);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class FileInitExp : DefaultInitExp
+{
+ extern (D) this(const ref Loc loc, TOK tok)
+ {
+ super(loc, tok, __traits(classInstanceSize, FileInitExp));
+ }
+
+ override Expression resolveLoc(const ref Loc loc, Scope* sc)
+ {
+ //printf("FileInitExp::resolve() %s\n", toChars());
+ const(char)* s;
+ if (op == TOK.fileFullPath)
+ s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars());
+ else
+ s = loc.isValid() ? loc.filename : sc._module.ident.toChars();
+
+ Expression e = new StringExp(loc, s.toDString());
+ e = e.expressionSemantic(sc);
+ e = e.castTo(sc, type);
+ return e;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class LineInitExp : DefaultInitExp
+{
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, TOK.line, __traits(classInstanceSize, LineInitExp));
+ }
+
+ override Expression resolveLoc(const ref Loc loc, Scope* sc)
+ {
+ Expression e = new IntegerExp(loc, loc.linnum, Type.tint32);
+ e = e.castTo(sc, type);
+ return e;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ModuleInitExp : DefaultInitExp
+{
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, TOK.moduleString, __traits(classInstanceSize, ModuleInitExp));
+ }
+
+ override Expression resolveLoc(const ref Loc loc, Scope* sc)
+ {
+ const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString();
+ Expression e = new StringExp(loc, s);
+ e = e.expressionSemantic(sc);
+ e = e.castTo(sc, type);
+ return e;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class FuncInitExp : DefaultInitExp
+{
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, TOK.functionString, __traits(classInstanceSize, FuncInitExp));
+ }
+
+ override Expression resolveLoc(const ref Loc loc, Scope* sc)
+ {
+ const(char)* s;
+ if (sc.callsc && sc.callsc.func)
+ s = sc.callsc.func.Dsymbol.toPrettyChars();
+ else if (sc.func)
+ s = sc.func.Dsymbol.toPrettyChars();
+ else
+ s = "";
+ Expression e = new StringExp(loc, s.toDString());
+ e = e.expressionSemantic(sc);
+ e.type = Type.tstring;
+ return e;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class PrettyFuncInitExp : DefaultInitExp
+{
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, TOK.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp));
+ }
+
+ override Expression resolveLoc(const ref Loc loc, Scope* sc)
+ {
+ FuncDeclaration fd = (sc.callsc && sc.callsc.func)
+ ? sc.callsc.func
+ : sc.func;
+
+ const(char)* s;
+ if (fd)
+ {
+ const funcStr = fd.Dsymbol.toPrettyChars();
+ OutBuffer buf;
+ functionToBufferWithIdent(fd.type.isTypeFunction(), &buf, funcStr, fd.isStatic);
+ s = buf.extractChars();
+ }
+ else
+ {
+ s = "";
+ }
+
+ Expression e = new StringExp(loc, s.toDString());
+ e = e.expressionSemantic(sc);
+ e.type = Type.tstring;
+ return e;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/**
+ * Objective-C class reference expression.
+ *
+ * Used to get the metaclass of an Objective-C class, `NSObject.Class`.
+ */
+extern (C++) final class ObjcClassReferenceExp : Expression
+{
+ ClassDeclaration classDeclaration;
+
+ extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
+ {
+ super(loc, TOK.objcClassReference,
+ __traits(classInstanceSize, ObjcClassReferenceExp));
+ this.classDeclaration = classDeclaration;
+ type = objc.getRuntimeMetaclass(classDeclaration).getType();
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/*******************
+ * C11 6.5.1.1 Generic Selection
+ * For ImportC
+ */
+extern (C++) final class GenericExp : Expression
+{
+ Expression cntlExp; /// controlling expression of a generic selection (not evaluated)
+ Types* types; /// type-names for generic associations (null entry for `default`)
+ Expressions* exps; /// 1:1 mapping of typeNames to exps
+
+ extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps)
+ {
+ super(loc, TOK._Generic, __traits(classInstanceSize, GenericExp));
+ this.cntlExp = cntlExp;
+ this.types = types;
+ this.exps = exps;
+ assert(types.length == exps.length); // must be the same and >=1
+ }
+
+ override GenericExp syntaxCopy()
+ {
+ return new GenericExp(loc, cntlExp.syntaxCopy(), Type.arraySyntaxCopy(types), Expression.arraySyntaxCopy(exps));
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***************************************
+ * Parameters:
+ * sc: scope
+ * flag: 1: do not issue error message for invalid modification
+ 2: the exp is a DotVarExp and a subfield of the leftmost
+ variable is modified
+ * Returns:
+ * Whether the type is modifiable
+ */
+extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyFlags.none)
+{
+ switch(exp.op)
+ {
+ case TOK.variable:
+ auto varExp = cast(VarExp)exp;
+
+ //printf("VarExp::checkModifiable %s", varExp.toChars());
+ assert(varExp.type);
+ return varExp.var.checkModify(varExp.loc, sc, null, flag);
+
+ case TOK.dotVariable:
+ auto dotVarExp = cast(DotVarExp)exp;
+
+ //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
+ if (dotVarExp.e1.op == TOK.this_)
+ return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag);
+
+ /* https://issues.dlang.org/show_bug.cgi?id=12764
+ * If inside a constructor and an expression of type `this.field.var`
+ * is encountered, where `field` is a struct declaration with
+ * default construction disabled, we must make sure that
+ * assigning to `var` does not imply that `field` was initialized
+ */
+ if (sc.func && sc.func.isCtorDeclaration())
+ {
+ // if inside a constructor scope and e1 of this DotVarExp
+ // is another DotVarExp, then check if the leftmost expression is a `this` identifier
+ if (auto dve = dotVarExp.e1.isDotVarExp())
+ {
+ // Iterate the chain of DotVarExp to find `this`
+ // Keep track whether access to fields was limited to union members
+ // s.t. one can initialize an entire struct inside nested unions
+ // (but not its members)
+ bool onlyUnion = true;
+ while (true)
+ {
+ auto v = dve.var.isVarDeclaration();
+ assert(v);
+
+ // Accessing union member?
+ auto t = v.type.isTypeStruct();
+ if (!t || !t.sym.isUnionDeclaration())
+ onlyUnion = false;
+
+ // Another DotVarExp left?
+ if (!dve.e1 || dve.e1.op != TOK.dotVariable)
+ break;
+
+ dve = cast(DotVarExp) dve.e1;
+ }
+
+ if (dve.e1.op == TOK.this_)
+ {
+ scope v = dve.var.isVarDeclaration();
+ /* if v is a struct member field with no initializer, no default construction
+ * and v wasn't intialized before
+ */
+ if (v && v.isField() && !v._init && !v.ctorinit)
+ {
+ if (auto ts = v.type.isTypeStruct())
+ {
+ if (ts.sym.noDefaultCtor)
+ {
+ /* checkModify will consider that this is an initialization
+ * of v while it is actually an assignment of a field of v
+ */
+ scope modifyLevel = v.checkModify(dotVarExp.loc, sc, dve.e1, !onlyUnion ? (flag | ModifyFlags.fieldAssign) : flag);
+ if (modifyLevel == Modifiable.initialization)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=22118
+ // v is a union type field that was assigned
+ // a variable, therefore it counts as initialization
+ if (v.ctorinit)
+ return Modifiable.initialization;
+
+ return Modifiable.yes;
+ }
+ return modifyLevel;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //printf("\te1 = %s\n", e1.toChars());
+ return dotVarExp.e1.checkModifiable(sc, flag);
+
+ case TOK.star:
+ auto ptrExp = cast(PtrExp)exp;
+ if (auto se = ptrExp.e1.isSymOffExp())
+ {
+ return se.var.checkModify(ptrExp.loc, sc, null, flag);
+ }
+ else if (auto ae = ptrExp.e1.isAddrExp())
+ {
+ return ae.e1.checkModifiable(sc, flag);
+ }
+ return Modifiable.yes;
+
+ case TOK.slice:
+ auto sliceExp = cast(SliceExp)exp;
+
+ //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
+ auto e1 = sliceExp.e1;
+ if (e1.type.ty == Tsarray || (e1.op == TOK.index && e1.type.ty != Tarray) || e1.op == TOK.slice)
+ {
+ return e1.checkModifiable(sc, flag);
+ }
+ return Modifiable.yes;
+
+ case TOK.comma:
+ return (cast(CommaExp)exp).e2.checkModifiable(sc, flag);
+
+ case TOK.index:
+ auto indexExp = cast(IndexExp)exp;
+ auto e1 = indexExp.e1;
+ if (e1.type.ty == Tsarray ||
+ e1.type.ty == Taarray ||
+ (e1.op == TOK.index && e1.type.ty != Tarray) ||
+ e1.op == TOK.slice)
+ {
+ return e1.checkModifiable(sc, flag);
+ }
+ return Modifiable.yes;
+
+ case TOK.question:
+ auto condExp = cast(CondExp)exp;
+ if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no
+ && condExp.e2.checkModifiable(sc, flag) != Modifiable.no)
+ return Modifiable.yes;
+ return Modifiable.no;
+
+ default:
+ return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable
+ }
+}
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 9413ad9..dec3713 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -13,13 +13,11 @@
#include "ast_node.h"
#include "complex_t.h"
#include "globals.h"
-#include "identifier.h"
#include "arraytypes.h"
-#include "intrange.h"
#include "visitor.h"
#include "tokens.h"
-#include "root/rmem.h"
+#include "root/dcompat.h"
class Type;
class TypeVector;
@@ -28,29 +26,17 @@ class TupleDeclaration;
class VarDeclaration;
class FuncDeclaration;
class FuncLiteralDeclaration;
-class Declaration;
class CtorDeclaration;
-class NewDeclaration;
class Dsymbol;
-class Import;
-class Module;
class ScopeDsymbol;
class Expression;
class Declaration;
-class AggregateDeclaration;
class StructDeclaration;
class TemplateInstance;
class TemplateDeclaration;
class ClassDeclaration;
-class BinExp;
-class UnaExp;
-class DotIdExp;
-class DotTemplateInstanceExp;
class OverloadSet;
-class Initializer;
class StringExp;
-class ArrayExp;
-class SliceExp;
struct UnionExp;
#ifdef IN_GCC
typedef union tree_node Symbol;
@@ -58,113 +44,53 @@ typedef union tree_node Symbol;
struct Symbol; // back end symbol
#endif
-Expression *expressionSemantic(Expression *e, Scope *sc);
-Expression *semanticX(DotIdExp *exp, Scope *sc);
-Expression *semanticY(DotIdExp *exp, Scope *sc, int flag);
-Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag);
-Expression *trySemantic(Expression *e, Scope *sc);
-Expression *unaSemantic(UnaExp *e, Scope *sc);
-Expression *binSemantic(BinExp *e, Scope *sc);
-Expression *binSemanticProp(BinExp *e, Scope *sc);
-StringExp *semanticString(Scope *sc, Expression *exp, const char *s);
-
-Expression *resolveProperties(Scope *sc, Expression *e);
-Expression *resolvePropertiesOnly(Scope *sc, Expression *e1);
-bool checkAccess(Loc loc, Scope *sc, Expression *e, Declaration *d);
-bool checkAccess(Scope *sc, Package *p);
-Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Dsymbol *d);
-Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid);
void expandTuples(Expressions *exps);
-TupleDeclaration *isAliasThisTuple(Expression *e);
-int expandAliasThisTuples(Expressions *exps, size_t starti = 0);
-FuncDeclaration *hasThis(Scope *sc);
-Expression *fromConstInitializer(int result, Expression *e);
-bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors = false);
-TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s);
-Expression *valueNoDtor(Expression *e);
-int modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1);
-Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag = false);
-Expression *doCopyOrMove(Scope *sc, Expression *e);
-Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0);
-Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0);
-Expression *integralPromotions(Expression *e, Scope *sc);
-bool discardValue(Expression *e);
bool isTrivialExp(Expression *e);
-
-int isConst(Expression *e);
-Expression *toDelegate(Expression *e, Type* t, Scope *sc);
-AggregateDeclaration *isAggregate(Type *t);
-IntRange getIntRange(Expression *e);
-bool checkNonAssignmentArrayOp(Expression *e, bool suggestion = false);
-bool isUnaArrayOp(TOK op);
-bool isBinArrayOp(TOK op);
-bool isBinAssignArrayOp(TOK op);
-bool isArrayOpOperand(Expression *e);
-Expression *arrayOp(BinExp *e, Scope *sc);
-Expression *arrayOp(BinAssignExp *e, Scope *sc);
-bool hasSideEffect(Expression *e);
+bool hasSideEffect(Expression *e, bool assumeImpureCalls = false);
bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow);
-Expression *Expression_optimize(Expression *e, int result, bool keepLvalue);
-MATCH implicitConvTo(Expression *e, Type *t);
-Expression *implicitCastTo(Expression *e, Scope *sc, Type *t);
-Expression *castTo(Expression *e, Scope *sc, Type *t);
-Expression *ctfeInterpret(Expression *);
-Expression *inlineCopy(Expression *e, Scope *sc);
-Expression *op_overload(Expression *e, Scope *sc);
-Type *toStaticArrayType(SliceExp *e);
-Expression *scaleFactor(BinExp *be, Scope *sc);
-Expression *typeCombine(BinExp *be, Scope *sc);
-Expression *inferType(Expression *e, Type *t, int flag = 0);
-Expression *semanticTraits(TraitsExp *e, Scope *sc);
-Type *getIndirection(Type *t);
-
-Expression *checkGC(Scope *sc, Expression *e);
-
-/* Run CTFE on the expression, but allow the expression to be a TypeExp
- * or a tuple containing a TypeExp. (This is required by pragma(msg)).
- */
-Expression *ctfeInterpretForPragmaMsg(Expression *e);
-enum OwnedBy
+typedef unsigned char OwnedBy;
+enum
{
OWNEDcode, // normal code expression in AST
OWNEDctfe, // value expression for CTFE
OWNEDcache // constant value cached for CTFE
};
-#define WANTvalue 0 // default
-#define WANTexpand 1 // expand const/immutable variables if possible
+/**
+ * Specifies how the checkModify deals with certain situations
+ */
+enum class ModifyFlags
+{
+ /// Issue error messages on invalid modifications of the variable
+ none,
+ /// No errors are emitted for invalid modifications
+ noError = 0x1,
+ /// The modification occurs for a subfield of the current variable
+ fieldAssign = 0x2,
+};
class Expression : public ASTNode
{
public:
- Loc loc; // file location
- Type *type; // !=NULL means that semantic() has been run
TOK op; // to minimize use of dynamic_cast
unsigned char size; // # of bytes in Expression so we can copy() it
unsigned char parens; // if this is a parenthesized expression
+ Type *type; // !=NULL means that semantic() has been run
+ Loc loc; // file location
- Expression(Loc loc, TOK op, int size);
static void _init();
Expression *copy();
virtual Expression *syntaxCopy();
// kludge for template.isExpression()
- int dyncast() const { return DYNCAST_EXPRESSION; }
+ DYNCAST dyncast() const { return DYNCAST_EXPRESSION; }
- void print();
- const char *toChars();
+ const char *toChars() const;
void error(const char *format, ...) const;
void warning(const char *format, ...) const;
void deprecation(const char *format, ...) const;
- // creates a single expression which is effectively (e1, e2)
- // this new expression does not necessarily need to have valid D source code representation,
- // for example, it may include declaration expressions
- static Expression *combine(Expression *e1, Expression *e2);
- static Expression *extractLast(Expression *e, Expression **pe0);
- static Expressions *arraySyntaxCopy(Expressions *exps);
-
virtual dinteger_t toInteger();
virtual uinteger_t toUInteger();
virtual real_t toReal();
@@ -175,58 +101,24 @@ public:
virtual bool isLvalue();
virtual Expression *toLvalue(Scope *sc, Expression *e);
virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
- Expression *implicitCastTo(Scope *sc, Type *t)
- {
- return ::implicitCastTo(this, sc, t);
- }
- MATCH implicitConvTo(Type *t)
- {
- return ::implicitConvTo(this, t);
- }
- Expression *castTo(Scope *sc, Type *t)
- {
- return ::castTo(this, sc, t);
- }
- virtual Expression *resolveLoc(Loc loc, Scope *sc);
+ Expression *implicitCastTo(Scope *sc, Type *t);
+ MATCH implicitConvTo(Type *t);
+ Expression *castTo(Scope *sc, Type *t);
+ virtual Expression *resolveLoc(const Loc &loc, Scope *sc);
virtual bool checkType();
virtual bool checkValue();
- bool checkScalar();
- bool checkNoBool();
- bool checkIntegral();
- bool checkArithmetic();
bool checkDeprecated(Scope *sc, Dsymbol *s);
- bool checkDisabled(Scope *sc, Dsymbol *s);
- bool checkPurity(Scope *sc, FuncDeclaration *f);
- bool checkPurity(Scope *sc, VarDeclaration *v);
- bool checkSafety(Scope *sc, FuncDeclaration *f);
- bool checkNogc(Scope *sc, FuncDeclaration *f);
- bool checkPostblit(Scope *sc, Type *t);
- bool checkRightThis(Scope *sc);
- bool checkReadModifyWrite(TOK rmwOp, Expression *ex = NULL);
- virtual int checkModifiable(Scope *sc, int flag = 0);
- virtual Expression *toBoolean(Scope *sc);
virtual Expression *addDtorHook(Scope *sc);
Expression *addressOf();
Expression *deref();
- Expression *optimize(int result, bool keepLvalue = false)
- {
- return Expression_optimize(this, result, keepLvalue);
- }
+ Expression *optimize(int result, bool keepLvalue = false);
// Entry point for CTFE.
// A compile-time result is required. Give an error if not possible
- Expression *ctfeInterpret()
- {
- return ::ctfeInterpret(this);
- }
-
- int isConst() { return ::isConst(this); }
+ Expression *ctfeInterpret();
+ int isConst();
virtual bool isBool(bool result);
- Expression *op_overload(Scope *sc)
- {
- return ::op_overload(this, sc);
- }
virtual bool hasCode()
{
@@ -263,7 +155,7 @@ public:
TraitsExp* isTraitsExp();
HaltExp* isHaltExp();
IsExp* isExp();
- CompileExp* isCompileExp();
+ MixinExp* isMixinExp();
ImportExp* isImportExp();
AssertExp* isAssertExp();
DotIdExp* isDotIdExp();
@@ -329,6 +221,7 @@ public:
EqualExp* isEqualExp();
IdentityExp* isIdentityExp();
CondExp* isCondExp();
+ GenericExp* isGenericExp();
DefaultInitExp* isDefaultInitExp();
FileInitExp* isFileInitExp();
LineInitExp* isLineInitExp();
@@ -336,6 +229,7 @@ public:
FuncInitExp* isFuncInitExp();
PrettyFuncInitExp* isPrettyFuncInitExp();
ClassReferenceExp* isClassReferenceExp();
+ virtual BinAssignExp* isBinAssignExp();
void accept(Visitor *v) { v->visit(this); }
};
@@ -345,10 +239,9 @@ class IntegerExp : public Expression
public:
dinteger_t value;
- IntegerExp(Loc loc, dinteger_t value, Type *type);
- IntegerExp(dinteger_t value);
static IntegerExp *create(Loc loc, dinteger_t value, Type *type);
- bool equals(RootObject *o);
+ static void emplace(UnionExp *pue, Loc loc, dinteger_t value, Type *type);
+ bool equals(const RootObject *o) const;
dinteger_t toInteger();
real_t toReal();
real_t toImaginary();
@@ -358,13 +251,13 @@ public:
void accept(Visitor *v) { v->visit(this); }
dinteger_t getInteger() { return value; }
void setInteger(dinteger_t value);
- void normalize();
+ template<int v>
+ static IntegerExp literal();
};
class ErrorExp : public Expression
{
public:
- ErrorExp();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
@@ -376,9 +269,9 @@ class RealExp : public Expression
public:
real_t value;
- RealExp(Loc loc, real_t value, Type *type);
static RealExp *create(Loc loc, real_t value, Type *type);
- bool equals(RootObject *o);
+ static void emplace(UnionExp *pue, Loc loc, real_t value, Type *type);
+ bool equals(const RootObject *o) const;
dinteger_t toInteger();
uinteger_t toUInteger();
real_t toReal();
@@ -393,9 +286,9 @@ class ComplexExp : public Expression
public:
complex_t value;
- ComplexExp(Loc loc, complex_t value, Type *type);
static ComplexExp *create(Loc loc, complex_t value, Type *type);
- bool equals(RootObject *o);
+ static void emplace(UnionExp *pue, Loc loc, complex_t value, Type *type);
+ bool equals(const RootObject *o) const;
dinteger_t toInteger();
uinteger_t toUInteger();
real_t toReal();
@@ -410,7 +303,6 @@ class IdentifierExp : public Expression
public:
Identifier *ident;
- IdentifierExp(Loc loc, Identifier *ident);
static IdentifierExp *create(Loc loc, Identifier *ident);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
@@ -420,7 +312,6 @@ public:
class DollarExp : public IdentifierExp
{
public:
- DollarExp(Loc loc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -430,7 +321,7 @@ public:
Dsymbol *s;
bool hasOverloads;
- DsymbolExp(Loc loc, Dsymbol *s, bool hasOverloads = true);
+ DsymbolExp *syntaxCopy();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
@@ -441,7 +332,7 @@ class ThisExp : public Expression
public:
VarDeclaration *var;
- ThisExp(Loc loc);
+ ThisExp *syntaxCopy();
bool isBool(bool result);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
@@ -452,18 +343,13 @@ public:
class SuperExp : public ThisExp
{
public:
- SuperExp(Loc loc);
-
void accept(Visitor *v) { v->visit(this); }
};
class NullExp : public Expression
{
public:
- unsigned char committed; // !=0 if type is committed
-
- NullExp(Loc loc, Type *t = NULL);
- bool equals(RootObject *o);
+ bool equals(const RootObject *o) const;
bool isBool(bool result);
StringExp *toStringExp();
void accept(Visitor *v) { v->visit(this); }
@@ -479,15 +365,13 @@ public:
utf8_t postfix; // 'c', 'w', 'd'
OwnedBy ownedByCtfe;
- StringExp(Loc loc, char *s);
- StringExp(Loc loc, void *s, size_t len);
- StringExp(Loc loc, void *s, size_t len, utf8_t postfix);
static StringExp *create(Loc loc, char *s);
static StringExp *create(Loc loc, void *s, size_t len);
- bool equals(RootObject *o);
+ static void emplace(UnionExp *pue, Loc loc, char *s);
+ static void emplace(UnionExp *pue, Loc loc, void *s, size_t len);
+ bool equals(const RootObject *o) const;
StringExp *toStringExp();
StringExp *toUTF8(Scope *sc);
- int compare(RootObject *obj);
bool isBool(bool result);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
@@ -496,7 +380,6 @@ public:
void accept(Visitor *v) { v->visit(this); }
size_t numberOfCodeUnits(int tynto = 0) const;
void writeTo(void* dest, bool zero, int tyto = 0) const;
- char *toPtr();
};
// Tuple
@@ -514,12 +397,10 @@ public:
*/
Expressions *exps;
- TupleExp(Loc loc, Expression *e0, Expressions *exps);
- TupleExp(Loc loc, Expressions *exps);
- TupleExp(Loc loc, TupleDeclaration *tup);
+ static TupleExp *create(Loc loc, Expressions *exps);
TupleExp *toTupleExp();
- Expression *syntaxCopy();
- bool equals(RootObject *o);
+ TupleExp *syntaxCopy();
+ bool equals(const RootObject *o) const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -531,14 +412,12 @@ public:
Expressions *elements;
OwnedBy ownedByCtfe;
- ArrayLiteralExp(Loc loc, Type *type, Expressions *elements);
- ArrayLiteralExp(Loc loc, Type *type, Expression *e);
- ArrayLiteralExp(Loc loc, Type *type, Expression *basis, Expressions *elements);
static ArrayLiteralExp *create(Loc loc, Expressions *elements);
- Expression *syntaxCopy();
- bool equals(RootObject *o);
- Expression *getElement(size_t i);
- static Expressions* copyElements(Expression *e1, Expression *e2 = NULL);
+ static void emplace(UnionExp *pue, Loc loc, Expressions *elements);
+ ArrayLiteralExp *syntaxCopy();
+ bool equals(const RootObject *o) const;
+ Expression *getElement(d_size_t i); // use opIndex instead
+ Expression *opIndex(d_size_t i);
bool isBool(bool result);
StringExp *toStringExp();
@@ -552,27 +431,13 @@ public:
Expressions *values;
OwnedBy ownedByCtfe;
- AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values);
- bool equals(RootObject *o);
- Expression *syntaxCopy();
+ bool equals(const RootObject *o) const;
+ AssocArrayLiteralExp *syntaxCopy();
bool isBool(bool result);
void accept(Visitor *v) { v->visit(this); }
};
-// scrubReturnValue is running
-#define stageScrub 0x1
-// hasNonConstPointers is running
-#define stageSearchPointers 0x2
-// optimize is running
-#define stageOptimize 0x4
-// apply is running
-#define stageApply 0x8
-//inlineScan is running
-#define stageInlineScan 0x10
-// toCBuffer is running
-#define stageToCBuffer 0x20
-
class StructLiteralExp : public Expression
{
public:
@@ -580,45 +445,44 @@ public:
Expressions *elements; // parallels sd->fields[] with NULL entries for fields to skip
Type *stype; // final type of result (can be different from sd's type)
- bool useStaticInit; // if this is true, use the StructDeclaration's init symbol
Symbol *sym; // back end symbol to initialize with literal
- OwnedBy ownedByCtfe;
-
- // pointer to the origin instance of the expression.
- // once a new expression is created, origin is set to 'this'.
- // anytime when an expression copy is created, 'origin' pointer is set to
- // 'origin' pointer value of the original expression.
+ /** pointer to the origin instance of the expression.
+ * once a new expression is created, origin is set to 'this'.
+ * anytime when an expression copy is created, 'origin' pointer is set to
+ * 'origin' pointer value of the original expression.
+ */
StructLiteralExp *origin;
// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
StructLiteralExp *inlinecopy;
- // anytime when recursive function is calling, 'stageflags' marks with bit flag of
- // current stage and unmarks before return from this function.
- // 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
- // (with infinite recursion) of this expression.
+ /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
+ * current stage and unmarks before return from this function.
+ * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
+ * (with infinite recursion) of this expression.
+ */
int stageflags;
- StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype = NULL);
+ bool useStaticInit; // if this is true, use the StructDeclaration's init symbol
+ bool isOriginal; // used when moving instances to indicate `this is this.origin`
+ OwnedBy ownedByCtfe;
+
static StructLiteralExp *create(Loc loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
- bool equals(RootObject *o);
- Expression *syntaxCopy();
+ bool equals(const RootObject *o) const;
+ StructLiteralExp *syntaxCopy();
Expression *getField(Type *type, unsigned offset);
int getFieldIndex(Type *type, unsigned offset);
Expression *addDtorHook(Scope *sc);
+ Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
-class DotIdExp;
-DotIdExp *typeDotIdExp(Loc loc, Type *type, Identifier *ident);
-
class TypeExp : public Expression
{
public:
- TypeExp(Loc loc, Type *type);
- Expression *syntaxCopy();
+ TypeExp *syntaxCopy();
bool checkType();
bool checkValue();
void accept(Visitor *v) { v->visit(this); }
@@ -629,8 +493,7 @@ class ScopeExp : public Expression
public:
ScopeDsymbol *sds;
- ScopeExp(Loc loc, ScopeDsymbol *sds);
- Expression *syntaxCopy();
+ ScopeExp *syntaxCopy();
bool checkType();
bool checkValue();
void accept(Visitor *v) { v->visit(this); }
@@ -642,7 +505,6 @@ public:
TemplateDeclaration *td;
FuncDeclaration *fd;
- TemplateExp(Loc loc, TemplateDeclaration *td, FuncDeclaration *fd = NULL);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
bool checkType();
@@ -663,13 +525,11 @@ public:
Expression *argprefix; // expression to be evaluated just before arguments[]
CtorDeclaration *member; // constructor function
- NewDeclaration *allocator; // allocator function
- int onstack; // allocate on stack
+ bool onstack; // allocate on stack
+ bool thrownew; // this NewExp is the expression of a ThrowStatement
- NewExp(Loc loc, Expression *thisexp, Expressions *newargs,
- Type *newtype, Expressions *arguments);
static NewExp *create(Loc loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments);
- Expression *syntaxCopy();
+ NewExp *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -684,9 +544,7 @@ public:
ClassDeclaration *cd; // class being instantiated
Expressions *arguments; // Array of Expression's to call class constructor
- NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs,
- ClassDeclaration *cd, Expressions *arguments);
- Expression *syntaxCopy();
+ NewAnonClassExp *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -694,8 +552,8 @@ class SymbolExp : public Expression
{
public:
Declaration *var;
+ Dsymbol *originalScope;
bool hasOverloads;
- SymbolExp(Loc loc, TOK op, int size, Declaration *var, bool hasOverloads);
void accept(Visitor *v) { v->visit(this); }
};
@@ -707,7 +565,6 @@ class SymOffExp : public SymbolExp
public:
dinteger_t offset;
- SymOffExp(Loc loc, Declaration *var, dinteger_t offset, bool hasOverloads = true);
bool isBool(bool result);
void accept(Visitor *v) { v->visit(this); }
@@ -718,11 +575,9 @@ public:
class VarExp : public SymbolExp
{
public:
- VarExp(Loc loc, Declaration *var, bool hasOverloads = true);
+ bool delegateWasExtracted;
static VarExp *create(Loc loc, Declaration *var, bool hasOverloads = true);
- bool equals(RootObject *o);
- int checkModifiable(Scope *sc, int flag);
- bool checkReadModifyWrite();
+ bool equals(const RootObject *o) const;
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
@@ -737,7 +592,6 @@ class OverExp : public Expression
public:
OverloadSet *vars;
- OverExp(Loc loc, OverloadSet *s);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
@@ -752,12 +606,9 @@ public:
TemplateDeclaration *td;
TOK tok;
- FuncExp(Loc loc, Dsymbol *s);
- bool equals(RootObject *o);
- void genIdent(Scope *sc);
- Expression *syntaxCopy();
- MATCH matchType(Type *to, Scope *sc, FuncExp **pfe, int flag = 0);
- const char *toChars();
+ bool equals(const RootObject *o) const;
+ FuncExp *syntaxCopy();
+ const char *toChars() const;
bool checkType();
bool checkValue();
@@ -774,8 +625,7 @@ class DeclarationExp : public Expression
public:
Dsymbol *declaration;
- DeclarationExp(Loc loc, Dsymbol *declaration);
- Expression *syntaxCopy();
+ DeclarationExp *syntaxCopy();
bool hasCode();
@@ -787,8 +637,7 @@ class TypeidExp : public Expression
public:
RootObject *obj;
- TypeidExp(Loc loc, RootObject *obj);
- Expression *syntaxCopy();
+ TypeidExp *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -798,16 +647,13 @@ public:
Identifier *ident;
Objects *args;
- TraitsExp(Loc loc, Identifier *ident, Objects *args);
- Expression *syntaxCopy();
+ TraitsExp *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class HaltExp : public Expression
{
public:
- HaltExp(Loc loc);
-
void accept(Visitor *v) { v->visit(this); }
};
@@ -819,14 +665,12 @@ public:
*/
Type *targ;
Identifier *id; // can be NULL
- TOK tok; // ':' or '=='
Type *tspec; // can be NULL
- TOK tok2; // 'struct', 'union', etc.
TemplateParameters *parameters;
+ TOK tok; // ':' or '=='
+ TOK tok2; // 'struct', 'union', etc.
- IsExp(Loc loc, Type *targ, Identifier *id, TOK tok, Type *tspec,
- TOK tok2, TemplateParameters *parameters);
- Expression *syntaxCopy();
+ IsExp *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -838,17 +682,13 @@ public:
Expression *e1;
Type *att1; // Save alias this type to detect recursion
- UnaExp(Loc loc, TOK op, int size, Expression *e1);
- Expression *syntaxCopy();
+ UnaExp *syntaxCopy();
Expression *incompatibleTypes();
- Expression *resolveLoc(Loc loc, Scope *sc);
+ Expression *resolveLoc(const Loc &loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
-typedef UnionExp (*fp_t)(Loc loc, Type *, Expression *, Expression *);
-typedef int (*fp2_t)(Loc loc, TOK, Expression *, Expression *);
-
class BinExp : public Expression
{
public:
@@ -858,12 +698,8 @@ public:
Type *att1; // Save alias this type to detect recursion
Type *att2; // Save alias this type to detect recursion
- BinExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2);
- Expression *syntaxCopy();
+ BinExp *syntaxCopy();
Expression *incompatibleTypes();
- Expression *checkOpAssignTypes(Scope *sc);
- bool checkIntegralBin();
- bool checkArithmeticBin();
Expression *reorderSettingAAElem(Scope *sc);
@@ -873,31 +709,24 @@ public:
class BinAssignExp : public BinExp
{
public:
- BinAssignExp(Loc loc, TOK op, int size, Expression *e1, Expression *e2);
-
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *ex);
Expression *modifiableLvalue(Scope *sc, Expression *e);
+ BinAssignExp* isBinAssignExp();
void accept(Visitor *v) { v->visit(this); }
};
/****************************************************************/
-class CompileExp : public Expression
+class MixinExp : public UnaExp
{
public:
- Expressions *exps;
-
- CompileExp(Loc loc, Expressions *exps);
- Expression *syntaxCopy();
- bool equals(RootObject *o);
void accept(Visitor *v) { v->visit(this); }
};
class ImportExp : public UnaExp
{
public:
- ImportExp(Loc loc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
@@ -906,8 +735,7 @@ class AssertExp : public UnaExp
public:
Expression *msg;
- AssertExp(Loc loc, Expression *e, Expression *msg = NULL);
- Expression *syntaxCopy();
+ AssertExp *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -919,7 +747,6 @@ public:
bool noderef; // true if the result of the expression will never be dereferenced
bool wantsym; // do not replace Symbol with its initializer during semantic()
- DotIdExp(Loc loc, Expression *e, Identifier *ident);
static DotIdExp *create(Loc loc, Expression *e, Identifier *ident);
void accept(Visitor *v) { v->visit(this); }
};
@@ -929,7 +756,6 @@ class DotTemplateExp : public UnaExp
public:
TemplateDeclaration *td;
- DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td);
bool checkType();
bool checkValue();
void accept(Visitor *v) { v->visit(this); }
@@ -941,9 +767,6 @@ public:
Declaration *var;
bool hasOverloads;
- DotVarExp(Loc loc, Expression *e, Declaration *var, bool hasOverloads = true);
- int checkModifiable(Scope *sc, int flag);
- bool checkReadModifyWrite();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
@@ -955,9 +778,7 @@ class DotTemplateInstanceExp : public UnaExp
public:
TemplateInstance *ti;
- DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs);
- DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti);
- Expression *syntaxCopy();
+ DotTemplateInstanceExp *syntaxCopy();
bool findTempDecl(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -967,8 +788,8 @@ class DelegateExp : public UnaExp
public:
FuncDeclaration *func;
bool hasOverloads;
+ VarDeclaration *vthis2; // container for multi-context
- DelegateExp(Loc loc, Expression *e, FuncDeclaration *func, bool hasOverloads = true);
void accept(Visitor *v) { v->visit(this); }
};
@@ -978,7 +799,6 @@ class DotTypeExp : public UnaExp
public:
Dsymbol *sym; // symbol that represents a type
- DotTypeExp(Loc loc, Expression *e, Dsymbol *sym);
void accept(Visitor *v) { v->visit(this); }
};
@@ -988,16 +808,16 @@ public:
Expressions *arguments; // function arguments
FuncDeclaration *f; // symbol to call
bool directcall; // true if a virtual call is devirtualized
- CallExp(Loc loc, Expression *e, Expressions *exps);
- CallExp(Loc loc, Expression *e);
- CallExp(Loc loc, Expression *e, Expression *earg1);
- CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2);
+ bool inDebugStatement; // true if this was in a debug statement
+ bool ignoreAttributes; // don't enforce attributes (e.g. call @gc function in @nogc code)
+ VarDeclaration *vthis2; // container for multi-context
static CallExp *create(Loc loc, Expression *e, Expressions *exps);
static CallExp *create(Loc loc, Expression *e);
static CallExp *create(Loc loc, Expression *e, Expression *earg1);
+ static CallExp *create(Loc loc, FuncDeclaration *fd, Expression *earg1);
- Expression *syntaxCopy();
+ CallExp *syntaxCopy();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *addDtorHook(Scope *sc);
@@ -1008,18 +828,12 @@ public:
class AddrExp : public UnaExp
{
public:
- AddrExp(Loc loc, Expression *e);
- AddrExp(Loc loc, Expression *e, Type *t);
-
void accept(Visitor *v) { v->visit(this); }
};
class PtrExp : public UnaExp
{
public:
- PtrExp(Loc loc, Expression *e);
- PtrExp(Loc loc, Expression *e, Type *t);
- int checkModifiable(Scope *sc, int flag);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
@@ -1030,31 +844,24 @@ public:
class NegExp : public UnaExp
{
public:
- NegExp(Loc loc, Expression *e);
-
void accept(Visitor *v) { v->visit(this); }
};
class UAddExp : public UnaExp
{
public:
- UAddExp(Loc loc, Expression *e);
-
void accept(Visitor *v) { v->visit(this); }
};
class ComExp : public UnaExp
{
public:
- ComExp(Loc loc, Expression *e);
-
void accept(Visitor *v) { v->visit(this); }
};
class NotExp : public UnaExp
{
public:
- NotExp(Loc loc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
@@ -1062,8 +869,6 @@ class DeleteExp : public UnaExp
{
public:
bool isRAII;
- DeleteExp(Loc loc, Expression *e, bool isRAII);
- Expression *toBoolean(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -1074,9 +879,9 @@ public:
Type *to; // type to cast to
unsigned char mod; // MODxxxxx
- CastExp(Loc loc, Expression *e, Type *t);
- CastExp(Loc loc, Expression *e, unsigned char mod);
- Expression *syntaxCopy();
+ CastExp *syntaxCopy();
+ bool isLvalue();
+ Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
@@ -1088,16 +893,15 @@ public:
unsigned dim; // number of elements in the vector
OwnedBy ownedByCtfe;
- VectorExp(Loc loc, Expression *e, Type *t);
static VectorExp *create(Loc loc, Expression *e, Type *t);
- Expression *syntaxCopy();
+ static void emplace(UnionExp *pue, Loc loc, Expression *e, Type *t);
+ VectorExp *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class VectorArrayExp : public UnaExp
{
public:
- VectorArrayExp(Loc loc, Expression *e1);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
@@ -1113,10 +917,7 @@ public:
bool lowerIsLessThanUpper; // true if lwr <= upr
bool arrayop; // an array operation, rather than a slice
- SliceExp(Loc loc, Expression *e1, IntervalExp *ie);
- SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr);
- Expression *syntaxCopy();
- int checkModifiable(Scope *sc, int flag);
+ SliceExp *syntaxCopy();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
@@ -1128,8 +929,6 @@ public:
class ArrayLengthExp : public UnaExp
{
public:
- ArrayLengthExp(Loc loc, Expression *e1);
-
void accept(Visitor *v) { v->visit(this); }
};
@@ -1139,15 +938,13 @@ public:
Expression *lwr;
Expression *upr;
- IntervalExp(Loc loc, Expression *lwr, Expression *upr);
- Expression *syntaxCopy();
+ IntervalExp *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class DelegatePtrExp : public UnaExp
{
public:
- DelegatePtrExp(Loc loc, Expression *e1);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
@@ -1157,7 +954,6 @@ public:
class DelegateFuncptrExp : public UnaExp
{
public:
- DelegateFuncptrExp(Loc loc, Expression *e1);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
@@ -1173,9 +969,7 @@ public:
size_t currentDimension; // for opDollar
VarDeclaration *lengthVar;
- ArrayExp(Loc loc, Expression *e1, Expression *index = NULL);
- ArrayExp(Loc loc, Expression *e1, Expressions *args);
- Expression *syntaxCopy();
+ ArrayExp *syntaxCopy();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
@@ -1187,7 +981,6 @@ public:
class DotExp : public BinExp
{
public:
- DotExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
@@ -1196,13 +989,10 @@ class CommaExp : public BinExp
public:
bool isGenerated;
bool allowCommaExp;
- CommaExp(Loc loc, Expression *e1, Expression *e2, bool generated = true);
- int checkModifiable(Scope *sc, int flag);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
bool isBool(bool result);
- Expression *toBoolean(Scope *sc);
Expression *addDtorHook(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -1214,15 +1004,11 @@ public:
bool modifiable;
bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
- IndexExp(Loc loc, Expression *e1, Expression *e2);
- Expression *syntaxCopy();
- int checkModifiable(Scope *sc, int flag);
+ IndexExp *syntaxCopy();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
- Expression *markSettingAAElem();
-
void accept(Visitor *v) { v->visit(this); }
};
@@ -1231,7 +1017,6 @@ public:
class PostExp : public BinExp
{
public:
- PostExp(TOK op, Loc loc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
@@ -1240,12 +1025,12 @@ public:
class PreExp : public UnaExp
{
public:
- PreExp(TOK op, Loc loc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
};
-enum MemorySet
+enum class MemorySet
{
+ none = 0, // simple assignment
blockAssign = 1, // setting the contents of an array
referenceInit = 2 // setting the reference of STCref variable
};
@@ -1253,12 +1038,10 @@ enum MemorySet
class AssignExp : public BinExp
{
public:
- int memset; // combination of MemorySet flags
+ MemorySet memset;
- AssignExp(Loc loc, Expression *e1, Expression *e2);
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *ex);
- Expression *toBoolean(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -1266,242 +1049,192 @@ public:
class ConstructExp : public AssignExp
{
public:
- ConstructExp(Loc loc, Expression *e1, Expression *e2);
- ConstructExp(Loc loc, VarDeclaration *v, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class BlitExp : public AssignExp
{
public:
- BlitExp(Loc loc, Expression *e1, Expression *e2);
- BlitExp(Loc loc, VarDeclaration *v, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class AddAssignExp : public BinAssignExp
{
public:
- AddAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class MinAssignExp : public BinAssignExp
{
public:
- MinAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class MulAssignExp : public BinAssignExp
{
public:
- MulAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class DivAssignExp : public BinAssignExp
{
public:
- DivAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class ModAssignExp : public BinAssignExp
{
public:
- ModAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class AndAssignExp : public BinAssignExp
{
public:
- AndAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class OrAssignExp : public BinAssignExp
{
public:
- OrAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class XorAssignExp : public BinAssignExp
{
public:
- XorAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class PowAssignExp : public BinAssignExp
{
public:
- PowAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class ShlAssignExp : public BinAssignExp
{
public:
- ShlAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class ShrAssignExp : public BinAssignExp
{
public:
- ShrAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class UshrAssignExp : public BinAssignExp
{
public:
- UshrAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class CatAssignExp : public BinAssignExp
{
public:
- CatAssignExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
class AddExp : public BinExp
{
public:
- AddExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class MinExp : public BinExp
{
public:
- MinExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class CatExp : public BinExp
{
public:
- CatExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class MulExp : public BinExp
{
public:
- MulExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class DivExp : public BinExp
{
public:
- DivExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class ModExp : public BinExp
{
public:
- ModExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class PowExp : public BinExp
{
public:
- PowExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class ShlExp : public BinExp
{
public:
- ShlExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class ShrExp : public BinExp
{
public:
- ShrExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class UshrExp : public BinExp
{
public:
- UshrExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class AndExp : public BinExp
{
public:
- AndExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class OrExp : public BinExp
{
public:
- OrExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class XorExp : public BinExp
{
public:
- XorExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class LogicalExp : public BinExp
{
public:
- LogicalExp(Loc loc, TOK op, Expression *e1, Expression *e2);
- Expression *toBoolean(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class CmpExp : public BinExp
{
public:
- CmpExp(TOK op, Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class InExp : public BinExp
{
public:
- InExp(Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
class RemoveExp : public BinExp
{
public:
- RemoveExp(Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
@@ -1510,8 +1243,6 @@ public:
class EqualExp : public BinExp
{
public:
- EqualExp(TOK op, Loc loc, Expression *e1, Expression *e2);
-
void accept(Visitor *v) { v->visit(this); }
};
@@ -1520,7 +1251,6 @@ public:
class IdentityExp : public BinExp
{
public:
- IdentityExp(TOK op, Loc loc, Expression *e1, Expression *e2);
void accept(Visitor *v) { v->visit(this); }
};
@@ -1531,66 +1261,66 @@ class CondExp : public BinExp
public:
Expression *econd;
- CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2);
- Expression *syntaxCopy();
- int checkModifiable(Scope *sc, int flag);
+ CondExp *syntaxCopy();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
- Expression *toBoolean(Scope *sc);
void hookDtors(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
+class GenericExp : Expression
+{
+ Expression cntlExp;
+ Types *types;
+ Expressions *exps;
+
+ GenericExp *syntaxCopy();
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
/****************************************************************/
class DefaultInitExp : public Expression
{
public:
- TOK subop; // which of the derived classes this is
-
- DefaultInitExp(Loc loc, TOK subop, int size);
void accept(Visitor *v) { v->visit(this); }
};
class FileInitExp : public DefaultInitExp
{
public:
- FileInitExp(Loc loc, TOK tok);
- Expression *resolveLoc(Loc loc, Scope *sc);
+ Expression *resolveLoc(const Loc &loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class LineInitExp : public DefaultInitExp
{
public:
- LineInitExp(Loc loc);
- Expression *resolveLoc(Loc loc, Scope *sc);
+ Expression *resolveLoc(const Loc &loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class ModuleInitExp : public DefaultInitExp
{
public:
- ModuleInitExp(Loc loc);
- Expression *resolveLoc(Loc loc, Scope *sc);
+ Expression *resolveLoc(const Loc &loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class FuncInitExp : public DefaultInitExp
{
public:
- FuncInitExp(Loc loc);
- Expression *resolveLoc(Loc loc, Scope *sc);
+ Expression *resolveLoc(const Loc &loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
class PrettyFuncInitExp : public DefaultInitExp
{
public:
- PrettyFuncInitExp(Loc loc);
- Expression *resolveLoc(Loc loc, Scope *sc);
+ Expression *resolveLoc(const Loc &loc, Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -1652,45 +1382,10 @@ private:
/****************************************************************/
-/* Special values used by the interpreter
- */
+class ObjcClassReferenceExp : public Expression
+{
+public:
+ ClassDeclaration* classDeclaration;
-Expression *expType(Type *type, Expression *e);
-
-UnionExp Neg(Type *type, Expression *e1);
-UnionExp Com(Type *type, Expression *e1);
-UnionExp Not(Type *type, Expression *e1);
-UnionExp Bool(Type *type, Expression *e1);
-UnionExp Cast(Loc loc, Type *type, Type *to, Expression *e1);
-UnionExp ArrayLength(Type *type, Expression *e1);
-UnionExp Ptr(Type *type, Expression *e1);
-
-UnionExp Add(Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Min(Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Mul(Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Div(Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Mod(Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Pow(Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Shl(Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Shr(Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Ushr(Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp And(Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Or(Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Xor(Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Index(Type *type, Expression *e1, Expression *e2);
-UnionExp Cat(Type *type, Expression *e1, Expression *e2);
-
-UnionExp Equal(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Cmp(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2);
-UnionExp Identity(TOK op, Loc loc, Type *type, Expression *e1, Expression *e2);
-
-UnionExp Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr);
-
-// Const-folding functions used by CTFE
-
-void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, size_t firstIndex);
-void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, size_t firstIndex);
-void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, size_t firstIndex);
-
-int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len);
-int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len);
+ void accept(Visitor *v) { v->visit(this); }
+};
diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c
deleted file mode 100644
index 5ae5fe6..0000000
--- a/gcc/d/dmd/expressionsem.c
+++ /dev/null
@@ -1,10740 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- */
-
-#include "root/dsystem.h"
-#include "root/rmem.h"
-#include "root/root.h"
-
-#include "mars.h"
-#include "mangle.h"
-#include "mtype.h"
-#include "init.h"
-#include "expression.h"
-#include "template.h"
-#include "utf.h"
-#include "enum.h"
-#include "scope.h"
-#include "statement.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "import.h"
-#include "id.h"
-#include "dsymbol.h"
-#include "module.h"
-#include "attrib.h"
-#include "hdrgen.h"
-#include "parse.h"
-#include "nspace.h"
-#include "ctfe.h"
-#include "target.h"
-
-bool typeMerge(Scope *sc, TOK op, Type **pt, Expression **pe1, Expression **pe2);
-bool isArrayOpValid(Expression *e);
-Expression *expandVar(int result, VarDeclaration *v);
-bool checkAssignEscape(Scope *sc, Expression *e, bool gag);
-bool checkParamArgumentEscape(Scope *sc, FuncDeclaration *fdc, Identifier *par, Expression *arg, bool gag);
-bool checkAccess(AggregateDeclaration *ad, Loc loc, Scope *sc, Dsymbol *smember);
-bool checkNestedRef(Dsymbol *s, Dsymbol *p);
-bool checkFrameAccess(Loc loc, Scope *sc, AggregateDeclaration *ad, size_t istart = 0);
-bool symbolIsVisible(Module *mod, Dsymbol *s);
-bool symbolIsVisible(Scope *sc, Dsymbol *s);
-VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
-Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
-Type *getTypeInfoType(Loc loc, Type *t, Scope *sc);
-char *MODtoChars(MOD mod);
-bool MODimplicitConv(MOD modfrom, MOD modto);
-MOD MODmerge(MOD mod1, MOD mod2);
-MATCH MODmethodConv(MOD modfrom, MOD modto);
-void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
-
-void unSpeculative(Scope *sc, RootObject *o);
-bool isDotOpDispatch(Expression *e);
-bool isNeedThisScope(Scope *sc, Declaration *d);
-bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
-bool isSafeCast(Expression *e, Type *tfrom, Type *tto);
-FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
-Expression *callCpCtor(Scope *sc, Expression *e);
-
-Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-
-bool checkPrintfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list);
-bool checkScanfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list);
-
-/********************************************************
- * Perform semantic analysis and CTFE on expressions to produce
- * a string.
- * Params:
- * buf = append generated string to buffer
- * sc = context
- * exps = array of Expressions
- * Returns:
- * true on error
- */
-bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps)
-{
- if (!exps)
- return false;
-
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *ex = (*exps)[i];
- if (!ex)
- continue;
- Scope *sc2 = sc->startCTFE();
- Expression *e2 = expressionSemantic(ex, sc2);
- Expression *e3 = resolveProperties(sc2, e2);
- sc2->endCTFE();
-
- // allowed to contain types as well as expressions
- Expression *e4 = ctfeInterpretForPragmaMsg(e3);
- if (!e4 || e4->op == TOKerror)
- return true;
-
- // expand tuple
- if (TupleExp *te = e4->isTupleExp())
- {
- if (expressionsToString(buf, sc, te->exps))
- return true;
- continue;
- }
- // char literals exp `.toStringExp` return `null` but we cant override it
- // because in most contexts we don't want the conversion to succeed.
- IntegerExp *ie = e4->isIntegerExp();
- const TY ty = (ie && ie->type) ? ie->type->ty : (TY)Terror;
- if (ty == Tchar || ty == Twchar || ty == Tdchar)
- {
- TypeSArray *tsa = new TypeSArray(ie->type, new IntegerExp(ex->loc, 1, Type::tint32));
- e4 = new ArrayLiteralExp(ex->loc, tsa, ie);
- }
-
- if (StringExp *se = e4->toStringExp())
- buf.writestring(se->toUTF8(sc)->toPtr());
- else
- buf.writestring(e4->toChars());
- }
- return false;
-}
-
-/***********************************************************
- * Resolve `exp` as a compile-time known string.
- * Params:
- * sc = scope
- * exp = Expression which expected as a string
- * s = What the string is expected for, will be used in error diagnostic.
- * Returns:
- * String literal, or `null` if error happens.
- */
-StringExp *semanticString(Scope *sc, Expression *exp, const char *s)
-{
- sc = sc->startCTFE();
- exp = expressionSemantic(exp, sc);
- exp = resolveProperties(sc, exp);
- sc = sc->endCTFE();
-
- if (exp->op == TOKerror)
- return NULL;
-
- Expression *e = exp;
- if (exp->type->isString())
- {
- e = e->ctfeInterpret();
- if (e->op == TOKerror)
- return NULL;
- }
-
- StringExp *se = e->toStringExp();
- if (!se)
- {
- exp->error("string expected for %s, not (%s) of type %s",
- s, exp->toChars(), exp->type->toChars());
- return NULL;
- }
- return se;
-}
-
-/****************************************************************/
-
-static Expression *extractOpDollarSideEffect(Scope *sc, UnaExp *ue)
-{
- Expression *e0;
- Expression *e1 = Expression::extractLast(ue->e1, &e0);
- // Bugzilla 12585: Extract the side effect part if ue->e1 is comma.
-
- if (!isTrivialExp(e1))
- {
- /* Even if opDollar is needed, 'e1' should be evaluate only once. So
- * Rewrite:
- * e1.opIndex( ... use of $ ... )
- * e1.opSlice( ... use of $ ... )
- * as:
- * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
- * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
- */
- e1 = extractSideEffect(sc, "__dop", &e0, e1, false);
- assert(e1->op == TOKvar);
- VarExp *ve = (VarExp *)e1;
- ve->var->storage_class |= STCexptemp; // lifetime limited to expression
- }
- ue->e1 = e1;
- return e0;
-}
-
-/**************************************
- * Runs semantic on ae->arguments. Declares temporary variables
- * if '$' was used.
- */
-Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0)
-{
- assert(!ae->lengthVar);
-
- *pe0 = NULL;
-
- AggregateDeclaration *ad = isAggregate(ae->e1->type);
- Dsymbol *slice = search_function(ad, Id::slice);
- //printf("slice = %s %s\n", slice->kind(), slice->toChars());
-
- for (size_t i = 0; i < ae->arguments->length; i++)
- {
- if (i == 0)
- *pe0 = extractOpDollarSideEffect(sc, ae);
-
- Expression *e = (*ae->arguments)[i];
- if (e->op == TOKinterval && !(slice && slice->isTemplateDeclaration()))
- {
- Lfallback:
- if (ae->arguments->length == 1)
- return NULL;
- ae->error("multi-dimensional slicing requires template opSlice");
- return new ErrorExp();
- }
- //printf("[%d] e = %s\n", i, e->toChars());
-
- // Create scope for '$' variable for this dimension
- ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
- sym->loc = ae->loc;
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
- ae->lengthVar = NULL; // Create it only if required
- ae->currentDimension = i; // Dimension for $, if required
-
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
-
- if (ae->lengthVar && sc->func)
- {
- // If $ was used, declare it now
- Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
- de = expressionSemantic(de, sc);
- *pe0 = Expression::combine(*pe0, de);
- }
- sc = sc->pop();
-
- if (e->op == TOKinterval)
- {
- IntervalExp *ie = (IntervalExp *)e;
-
- Objects *tiargs = new Objects();
- Expression *edim = new IntegerExp(ae->loc, i, Type::tsize_t);
- edim = expressionSemantic(edim, sc);
- tiargs->push(edim);
-
- Expressions *fargs = new Expressions();
- fargs->push(ie->lwr);
- fargs->push(ie->upr);
-
- unsigned xerrors = global.startGagging();
- sc = sc->push();
- FuncDeclaration *fslice = resolveFuncCall(ae->loc, sc, slice, tiargs, ae->e1->type, fargs, 1);
- sc = sc->pop();
- global.endGagging(xerrors);
- if (!fslice)
- goto Lfallback;
-
- e = new DotTemplateInstanceExp(ae->loc, ae->e1, slice->ident, tiargs);
- e = new CallExp(ae->loc, e, fargs);
- e = expressionSemantic(e, sc);
- }
-
- if (!e->type)
- {
- ae->error("%s has no value", e->toChars());
- e = new ErrorExp();
- }
- if (e->op == TOKerror)
- return e;
-
- (*ae->arguments)[i] = e;
- }
-
- return ae;
-}
-
-/**************************************
- * Runs semantic on se->lwr and se->upr. Declares a temporary variable
- * if '$' was used.
- */
-Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0)
-{
- //assert(!ae->lengthVar);
- if (!ie)
- return ae;
-
- VarDeclaration *lengthVar = ae->lengthVar;
-
- // create scope for '$'
- ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
- sym->loc = ae->loc;
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
-
- for (size_t i = 0; i < 2; ++i)
- {
- Expression *e = i == 0 ? ie->lwr : ie->upr;
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
- if (!e->type)
- {
- ae->error("%s has no value", e->toChars());
- return new ErrorExp();
- }
- (i == 0 ? ie->lwr : ie->upr) = e;
- }
-
- if (lengthVar != ae->lengthVar && sc->func)
- {
- // If $ was used, declare it now
- Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
- de = expressionSemantic(de, sc);
- *pe0 = Expression::combine(*pe0, de);
- }
- sc = sc->pop();
-
- return ae;
-}
-
-/******************************
- * Perform semantic() on an array of Expressions.
- */
-
-bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors)
-{
- bool err = false;
- if (exps)
- {
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e = (*exps)[i];
- if (e)
- {
- e = expressionSemantic(e, sc);
- if (e->op == TOKerror)
- err = true;
- if (preserveErrors || e->op != TOKerror)
- (*exps)[i] = e;
- }
- }
- }
- return err;
-}
-
-/******************************
- * Check the tail CallExp is really property function call.
- */
-static bool checkPropertyCall(Expression *e)
-{
- while (e->op == TOKcomma)
- e = ((CommaExp *)e)->e2;
-
- if (e->op == TOKcall)
- {
- CallExp *ce = (CallExp *)e;
- TypeFunction *tf;
- if (ce->f)
- {
- tf = (TypeFunction *)ce->f->type;
- /* If a forward reference to ce->f, try to resolve it
- */
- if (!tf->deco && ce->f->semanticRun < PASSsemanticdone)
- {
- dsymbolSemantic(ce->f, NULL);
- tf = (TypeFunction *)ce->f->type;
- }
- }
- else if (ce->e1->type->ty == Tfunction)
- tf = (TypeFunction *)ce->e1->type;
- else if (ce->e1->type->ty == Tdelegate)
- tf = (TypeFunction *)ce->e1->type->nextOf();
- else if (ce->e1->type->ty == Tpointer && ce->e1->type->nextOf()->ty == Tfunction)
- tf = (TypeFunction *)ce->e1->type->nextOf();
- else
- assert(0);
- }
- return false;
-}
-
-// TODO: merge with Scope::search::searchScopes()
-static Dsymbol *searchScopes(Scope *sc, Loc loc, Identifier *ident, int flags)
-{
- Dsymbol *s = NULL;
- for (Scope *scx = sc; scx; scx = scx->enclosing)
- {
- if (!scx->scopesym)
- continue;
- if (scx->scopesym->isModule())
- flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
- s = scx->scopesym->search(loc, ident, flags);
- if (s)
- {
- // overload set contains only module scope symbols.
- if (s->isOverloadSet())
- break;
- // selective/renamed imports also be picked up
- if (AliasDeclaration *ad = s->isAliasDeclaration())
- {
- if (ad->_import)
- break;
- }
- // See only module scope symbols for UFCS target.
- Dsymbol *p = s->toParent2();
- if (p && p->isModule())
- break;
- }
- s = NULL;
-
- // Stop when we hit a module, but keep going if that is not just under the global scope
- if (scx->scopesym->isModule() && !(scx->enclosing && !scx->enclosing->enclosing))
- break;
- }
- return s;
-}
-
-/******************************
- * Find symbol in accordance with the UFCS name look up rule
- */
-
-static Expression *searchUFCS(Scope *sc, UnaExp *ue, Identifier *ident)
-{
- //printf("searchUFCS(ident = %s)\n", ident->toChars());
- Loc loc = ue->loc;
- int flags = 0;
- Dsymbol *s = NULL;
-
- if (sc->flags & SCOPEignoresymbolvisibility)
- flags |= IgnoreSymbolVisibility;
-
- // First look in local scopes
- s = searchScopes(sc, loc, ident, flags | SearchLocalsOnly);
- if (!s)
- {
- // Second look in imported modules
- s = searchScopes(sc, loc, ident, flags | SearchImportsOnly);
- }
-
- if (!s)
- return ue->e1->type->Type::getProperty(loc, ident, 0);
-
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f)
- {
- TemplateDeclaration *td = getFuncTemplateDecl(f);
- if (td)
- {
- if (td->overroot)
- td = td->overroot;
- s = td;
- }
- }
-
- if (ue->op == TOKdotti)
- {
- DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ue;
- TemplateInstance *ti = new TemplateInstance(loc, s->ident);
- ti->tiargs = dti->ti->tiargs; // for better diagnostic message
- if (!ti->updateTempDecl(sc, s))
- return new ErrorExp();
- return new ScopeExp(loc, ti);
- }
- else
- {
- //printf("-searchUFCS() %s\n", s->toChars());
- return new DsymbolExp(loc, s);
- }
-}
-
-/******************************
- * Pull out callable entity with UFCS.
- */
-
-static Expression *resolveUFCS(Scope *sc, CallExp *ce)
-{
- Loc loc = ce->loc;
- Expression *eleft;
- Expression *e;
-
- if (ce->e1->op == TOKdotid)
- {
- DotIdExp *die = (DotIdExp *)ce->e1;
- Identifier *ident = die->ident;
-
- Expression *ex = semanticX(die, sc);
- if (ex != die)
- {
- ce->e1 = ex;
- return NULL;
- }
- eleft = die->e1;
-
- Type *t = eleft->type->toBasetype();
- if (t->ty == Tarray || t->ty == Tsarray ||
- t->ty == Tnull || (t->isTypeBasic() && t->ty != Tvoid))
- {
- /* Built-in types and arrays have no callable properties, so do shortcut.
- * It is necessary in: e.init()
- */
- }
- else if (t->ty == Taarray)
- {
- if (ident == Id::remove)
- {
- /* Transform:
- * aa.remove(arg) into delete aa[arg]
- */
- if (!ce->arguments || ce->arguments->length != 1)
- {
- ce->error("expected key as argument to aa.remove()");
- return new ErrorExp();
- }
- if (!eleft->type->isMutable())
- {
- ce->error("cannot remove key from %s associative array %s",
- MODtoChars(t->mod), eleft->toChars());
- return new ErrorExp();
- }
- Expression *key = (*ce->arguments)[0];
- key = expressionSemantic(key, sc);
- key = resolveProperties(sc, key);
-
- TypeAArray *taa = (TypeAArray *)t;
- key = key->implicitCastTo(sc, taa->index);
-
- if (key->checkValue())
- return new ErrorExp();
-
- semanticTypeInfo(sc, taa->index);
-
- return new RemoveExp(loc, eleft, key);
- }
- }
- else
- {
- if (Expression *ey = semanticY(die, sc, 1))
- {
- if (ey->op == TOKerror)
- return ey;
- ce->e1 = ey;
- if (isDotOpDispatch(ey))
- {
- unsigned errors = global.startGagging();
- e = expressionSemantic(ce->syntaxCopy(), sc);
- if (!global.endGagging(errors))
- return e;
- /* fall down to UFCS */
- }
- else
- return NULL;
- }
- }
- e = searchUFCS(sc, die, ident);
- }
- else if (ce->e1->op == TOKdotti)
- {
- DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ce->e1;
- if (Expression *ey = semanticY(dti, sc, 1))
- {
- ce->e1 = ey;
- return NULL;
- }
- eleft = dti->e1;
- e = searchUFCS(sc, dti, dti->ti->name);
- }
- else
- return NULL;
-
- // Rewrite
- ce->e1 = e;
- if (!ce->arguments)
- ce->arguments = new Expressions();
- ce->arguments->shift(eleft);
-
- return NULL;
-}
-
-/******************************
- * Pull out property with UFCS.
- */
-
-static Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL)
-{
- Loc loc = e1->loc;
- Expression *eleft;
- Expression *e;
-
- if (e1->op == TOKdotid)
- {
- DotIdExp *die = (DotIdExp *)e1;
- eleft = die->e1;
- e = searchUFCS(sc, die, die->ident);
- }
- else if (e1->op == TOKdotti)
- {
- DotTemplateInstanceExp *dti;
- dti = (DotTemplateInstanceExp *)e1;
- eleft = dti->e1;
- e = searchUFCS(sc, dti, dti->ti->name);
- }
- else
- return NULL;
-
- if (e == NULL)
- return NULL;
-
- // Rewrite
- if (e2)
- {
- // run semantic without gagging
- e2 = expressionSemantic(e2, sc);
-
- /* f(e1) = e2
- */
- Expression *ex = e->copy();
- Expressions *a1 = new Expressions();
- a1->setDim(1);
- (*a1)[0] = eleft;
- ex = new CallExp(loc, ex, a1);
- ex = trySemantic(ex, sc);
-
- /* f(e1, e2)
- */
- Expressions *a2 = new Expressions();
- a2->setDim(2);
- (*a2)[0] = eleft;
- (*a2)[1] = e2;
- e = new CallExp(loc, e, a2);
- if (ex)
- { // if fallback setter exists, gag errors
- e = trySemantic(e, sc);
- if (!e)
- { checkPropertyCall(ex);
- ex = new AssignExp(loc, ex, e2);
- return expressionSemantic(ex, sc);
- }
- }
- else
- { // strict setter prints errors if fails
- e = expressionSemantic(e, sc);
- }
- checkPropertyCall(e);
- return e;
- }
- else
- {
- /* f(e1)
- */
- Expressions *arguments = new Expressions();
- arguments->setDim(1);
- (*arguments)[0] = eleft;
- e = new CallExp(loc, e, arguments);
- e = expressionSemantic(e, sc);
- checkPropertyCall(e);
- return expressionSemantic(e, sc);
- }
-}
-
-/******************************
- * If e1 is a property function (template), resolve it.
- */
-
-Expression *resolvePropertiesOnly(Scope *sc, Expression *e1)
-{
- //printf("e1 = %s %s\n", Token::toChars(e1->op), e1->toChars());
- OverloadSet *os;
- FuncDeclaration *fd;
- TemplateDeclaration *td;
-
- if (e1->op == TOKdot)
- {
- DotExp *de = (DotExp *)e1;
- if (de->e2->op == TOKoverloadset)
- {
- os = ((OverExp *)de->e2)->vars;
- goto Los;
- }
- }
- else if (e1->op == TOKoverloadset)
- {
- os = ((OverExp *)e1)->vars;
- Los:
- assert(os);
- for (size_t i = 0; i < os->a.length; i++)
- {
- Dsymbol *s = os->a[i];
- fd = s->isFuncDeclaration();
- td = s->isTemplateDeclaration();
- if (fd)
- {
- if (((TypeFunction *)fd->type)->isproperty)
- return resolveProperties(sc, e1);
- }
- else if (td && td->onemember &&
- (fd = td->onemember->isFuncDeclaration()) != NULL)
- {
- if (((TypeFunction *)fd->type)->isproperty ||
- (fd->storage_class2 & STCproperty) ||
- (td->_scope->stc & STCproperty))
- {
- return resolveProperties(sc, e1);
- }
- }
- }
- }
- else if (e1->op == TOKdotti)
- {
- DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
- if (dti->ti->tempdecl && (td = dti->ti->tempdecl->isTemplateDeclaration()) != NULL)
- goto Ltd;
- }
- else if (e1->op == TOKdottd)
- {
- td = ((DotTemplateExp *)e1)->td;
- goto Ltd;
- }
- else if (e1->op == TOKscope)
- {
- Dsymbol *s = ((ScopeExp *)e1)->sds;
- TemplateInstance *ti = s->isTemplateInstance();
- if (ti && !ti->semanticRun && ti->tempdecl)
- {
- if ((td = ti->tempdecl->isTemplateDeclaration()) != NULL)
- goto Ltd;
- }
- }
- else if (e1->op == TOKtemplate)
- {
- td = ((TemplateExp *)e1)->td;
- Ltd:
- assert(td);
- if (td->onemember &&
- (fd = td->onemember->isFuncDeclaration()) != NULL)
- {
- if (((TypeFunction *)fd->type)->isproperty ||
- (fd->storage_class2 & STCproperty) ||
- (td->_scope->stc & STCproperty))
- {
- return resolveProperties(sc, e1);
- }
- }
- }
- else if (e1->op == TOKdotvar && e1->type->ty == Tfunction)
- {
- DotVarExp *dve = (DotVarExp *)e1;
- fd = dve->var->isFuncDeclaration();
- goto Lfd;
- }
- else if (e1->op == TOKvar && e1->type->ty == Tfunction &&
- (sc->intypeof || !((VarExp *)e1)->var->needThis()))
- {
- fd = ((VarExp *)e1)->var->isFuncDeclaration();
- Lfd:
- assert(fd);
- if (((TypeFunction *)fd->type)->isproperty)
- return resolveProperties(sc, e1);
- }
- return e1;
-}
-
-/*************************************************************
- * Given var, we need to get the
- * right 'this' pointer if var is in an outer class, but our
- * existing 'this' pointer is in an inner class.
- * Input:
- * e1 existing 'this'
- * ad struct or class we need the correct 'this' for
- * var the specific member of ad we're accessing
- */
-
-static Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad,
- Expression *e1, Declaration *var, int flag = 0)
-{
- //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars());
- L1:
- Type *t = e1->type->toBasetype();
- //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars());
-
- /* If e1 is not the 'this' pointer for ad
- */
- if (ad &&
- !(t->ty == Tpointer && t->nextOf()->ty == Tstruct &&
- ((TypeStruct *)t->nextOf())->sym == ad)
- &&
- !(t->ty == Tstruct &&
- ((TypeStruct *)t)->sym == ad)
- )
- {
- ClassDeclaration *cd = ad->isClassDeclaration();
- ClassDeclaration *tcd = t->isClassHandle();
-
- /* e1 is the right this if ad is a base class of e1
- */
- if (!cd || !tcd ||
- !(tcd == cd || cd->isBaseOf(tcd, NULL))
- )
- {
- /* Only classes can be inner classes with an 'outer'
- * member pointing to the enclosing class instance
- */
- if (tcd && tcd->isNested())
- {
- /* e1 is the 'this' pointer for an inner class: tcd.
- * Rewrite it as the 'this' pointer for the outer class.
- */
-
- e1 = new DotVarExp(loc, e1, tcd->vthis);
- e1->type = tcd->vthis->type;
- e1->type = e1->type->addMod(t->mod);
- // Do not call checkNestedRef()
- //e1 = expressionSemantic(e1, sc);
-
- // Skip up over nested functions, and get the enclosing
- // class type.
- int n = 0;
- Dsymbol *s;
- for (s = tcd->toParent();
- s && s->isFuncDeclaration();
- s = s->toParent())
- {
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f->vthis)
- {
- //printf("rewriting e1 to %s's this\n", f->toChars());
- n++;
- e1 = new VarExp(loc, f->vthis);
- }
- else
- {
- e1->error("need `this` of type %s to access member %s"
- " from static function %s",
- ad->toChars(), var->toChars(), f->toChars());
- e1 = new ErrorExp();
- return e1;
- }
- }
- if (s && s->isClassDeclaration())
- {
- e1->type = s->isClassDeclaration()->type;
- e1->type = e1->type->addMod(t->mod);
- if (n > 1)
- e1 = expressionSemantic(e1, sc);
- }
- else
- e1 = expressionSemantic(e1, sc);
- goto L1;
- }
-
- /* Can't find a path from e1 to ad
- */
- if (flag)
- return NULL;
- e1->error("this for %s needs to be type %s not type %s",
- var->toChars(), ad->toChars(), t->toChars());
- return new ErrorExp();
- }
- }
- return e1;
-}
-
-/***************************************
- * Pull out any properties.
- */
-
-static Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL)
-{
- //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token::toChars(e1->op), e1->toChars(), e2 ? e2->toChars() : NULL);
- Loc loc = e1->loc;
-
- OverloadSet *os;
- Dsymbol *s;
- Objects *tiargs;
- Type *tthis;
- if (e1->op == TOKdot)
- {
- DotExp *de = (DotExp *)e1;
- if (de->e2->op == TOKoverloadset)
- {
- tiargs = NULL;
- tthis = de->e1->type;
- os = ((OverExp *)de->e2)->vars;
- goto Los;
- }
- }
- else if (e1->op == TOKoverloadset)
- {
- tiargs = NULL;
- tthis = NULL;
- os = ((OverExp *)e1)->vars;
- Los:
- assert(os);
- FuncDeclaration *fd = NULL;
- if (e2)
- {
- e2 = expressionSemantic(e2, sc);
- if (e2->op == TOKerror)
- return new ErrorExp();
- e2 = resolveProperties(sc, e2);
-
- Expressions a;
- a.push(e2);
-
- for (size_t i = 0; i < os->a.length; i++)
- {
- FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, &a, 1);
- if (f)
- {
- if (f->errors)
- return new ErrorExp();
- fd = f;
- assert(fd->type->ty == Tfunction);
- }
- }
- if (fd)
- {
- Expression *e = new CallExp(loc, e1, e2);
- return expressionSemantic(e, sc);
- }
- }
- {
- for (size_t i = 0; i < os->a.length; i++)
- {
- FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, NULL, 1);
- if (f)
- {
- if (f->errors)
- return new ErrorExp();
- fd = f;
- assert(fd->type->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (!tf->isref && e2)
- goto Leproplvalue;
- }
- }
- if (fd)
- {
- Expression *e = new CallExp(loc, e1);
- if (e2)
- e = new AssignExp(loc, e, e2);
- return expressionSemantic(e, sc);
- }
- }
- if (e2)
- goto Leprop;
- }
- else if (e1->op == TOKdotti)
- {
- DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
- if (!dti->findTempDecl(sc))
- goto Leprop;
- if (!dti->ti->semanticTiargs(sc))
- goto Leprop;
- tiargs = dti->ti->tiargs;
- tthis = dti->e1->type;
- if ((os = dti->ti->tempdecl->isOverloadSet()) != NULL)
- goto Los;
- if ((s = dti->ti->tempdecl) != NULL)
- goto Lfd;
- }
- else if (e1->op == TOKdottd)
- {
- DotTemplateExp *dte = (DotTemplateExp *)e1;
- s = dte->td;
- tiargs = NULL;
- tthis = dte->e1->type;
- goto Lfd;
- }
- else if (e1->op == TOKscope)
- {
- s = ((ScopeExp *)e1)->sds;
- TemplateInstance *ti = s->isTemplateInstance();
- if (ti && !ti->semanticRun && ti->tempdecl)
- {
- //assert(ti->needsTypeInference(sc));
- if (!ti->semanticTiargs(sc))
- goto Leprop;
- tiargs = ti->tiargs;
- tthis = NULL;
- if ((os = ti->tempdecl->isOverloadSet()) != NULL)
- goto Los;
- if ((s = ti->tempdecl) != NULL)
- goto Lfd;
- }
- }
- else if (e1->op == TOKtemplate)
- {
- s = ((TemplateExp *)e1)->td;
- tiargs = NULL;
- tthis = NULL;
- goto Lfd;
- }
- else if (e1->op == TOKdotvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
- {
- DotVarExp *dve = (DotVarExp *)e1;
- s = dve->var->isFuncDeclaration();
- tiargs = NULL;
- tthis = dve->e1->type;
- goto Lfd;
- }
- else if (e1->op == TOKvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
- {
- s = ((VarExp *)e1)->var->isFuncDeclaration();
- tiargs = NULL;
- tthis = NULL;
- Lfd:
- assert(s);
- if (e2)
- {
- e2 = expressionSemantic(e2, sc);
- if (e2->op == TOKerror)
- return new ErrorExp();
- e2 = resolveProperties(sc, e2);
-
- Expressions a;
- a.push(e2);
-
- FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, 1);
- if (fd && fd->type)
- {
- if (fd->errors)
- return new ErrorExp();
- assert(fd->type->ty == Tfunction);
- Expression *e = new CallExp(loc, e1, e2);
- return expressionSemantic(e, sc);
- }
- }
- {
- FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, NULL, 1);
- if (fd && fd->type)
- {
- if (fd->errors)
- return new ErrorExp();
- assert(fd->type->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)fd->type;
- if (!e2 || tf->isref)
- {
- Expression *e = new CallExp(loc, e1);
- if (e2)
- e = new AssignExp(loc, e, e2);
- return expressionSemantic(e, sc);
- }
- }
- }
- if (FuncDeclaration *fd = s->isFuncDeclaration())
- {
- // Keep better diagnostic message for invalid property usage of functions
- assert(fd->type->ty == Tfunction);
- Expression *e = new CallExp(loc, e1, e2);
- return expressionSemantic(e, sc);
- }
- if (e2)
- goto Leprop;
- }
- if (e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v && ve->checkPurity(sc, v))
- return new ErrorExp();
- }
- if (e2)
- return NULL;
-
- if (e1->type &&
- e1->op != TOKtype) // function type is not a property
- {
- /* Look for e1 being a lazy parameter; rewrite as delegate call
- */
- if (e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e1;
-
- if (ve->var->storage_class & STClazy)
- {
- Expression *e = new CallExp(loc, e1);
- return expressionSemantic(e, sc);
- }
- }
- else if (e1->op == TOKdotvar)
- {
- // Check for reading overlapped pointer field in @safe code.
- if (checkUnsafeAccess(sc, e1, true, true))
- return new ErrorExp();
- }
- else if (e1->op == TOKcall)
- {
- CallExp *ce = (CallExp *)e1;
- // Check for reading overlapped pointer field in @safe code.
- if (checkUnsafeAccess(sc, ce->e1, true, true))
- return new ErrorExp();
- }
- }
-
- if (!e1->type)
- {
- error(loc, "cannot resolve type for %s", e1->toChars());
- e1 = new ErrorExp();
- }
- return e1;
-
-Leprop:
- error(loc, "not a property %s", e1->toChars());
- return new ErrorExp();
-
-Leproplvalue:
- error(loc, "%s is not an lvalue", e1->toChars());
- return new ErrorExp();
-}
-
-Expression *resolveProperties(Scope *sc, Expression *e)
-{
- //printf("resolveProperties(%s)\n", e->toChars());
-
- e = resolvePropertiesX(sc, e);
- if (e->checkRightThis(sc))
- return new ErrorExp();
- return e;
-}
-
-/****************************************
- * The common type is determined by applying ?: to each pair.
- * Output:
- * exps[] properties resolved, implicitly cast to common type, rewritten in place
- * *pt if pt is not NULL, set to the common type
- * Returns:
- * true a semantic error was detected
- */
-
-static bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt)
-{
- /* Still have a problem with:
- * ubyte[][] = [ cast(ubyte[])"hello", [1]];
- * which works if the array literal is initialized top down with the ubyte[][]
- * type, but fails with this function doing bottom up typing.
- */
- //printf("arrayExpressionToCommonType()\n");
- IntegerExp integerexp(0);
- CondExp condexp(Loc(), &integerexp, NULL, NULL);
-
- Type *t0 = NULL;
- Expression *e0 = NULL; // dead-store to prevent spurious warning
- size_t j0 = ~0; // dead-store to prevent spurious warning
- bool foundType = false;
-
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e = (*exps)[i];
- if (!e)
- continue;
-
- e = resolveProperties(sc, e);
- if (!e->type)
- {
- e->error("%s has no value", e->toChars());
- t0 = Type::terror;
- continue;
- }
- if (e->op == TOKtype)
- {
- foundType = true; // do not break immediately, there might be more errors
- e->checkValue(); // report an error "type T has no value"
- t0 = Type::terror;
- continue;
- }
- if (e->type->ty == Tvoid)
- {
- // void expressions do not concur to the determination of the common
- // type.
- continue;
- }
- if (checkNonAssignmentArrayOp(e))
- {
- t0 = Type::terror;
- continue;
- }
-
- e = doCopyOrMove(sc, e);
-
- if (!foundType && t0 && !t0->equals(e->type))
- {
- /* This applies ?: to merge the types. It's backwards;
- * ?: should call this function to merge types.
- */
- condexp.type = NULL;
- condexp.e1 = e0;
- condexp.e2 = e;
- condexp.loc = e->loc;
- Expression *ex = expressionSemantic(&condexp, sc);
- if (ex->op == TOKerror)
- e = ex;
- else
- {
- (*exps)[j0] = condexp.e1;
- e = condexp.e2;
- }
- }
- j0 = i;
- e0 = e;
- t0 = e->type;
- if (e->op != TOKerror)
- (*exps)[i] = e;
- }
-
- if (!t0)
- t0 = Type::tvoid; // [] is typed as void[]
- else if (t0->ty != Terror)
- {
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e = (*exps)[i];
- if (!e)
- continue;
-
- e = e->implicitCastTo(sc, t0);
- //assert(e->op != TOKerror);
- if (e->op == TOKerror)
- {
- /* Bugzilla 13024: a workaround for the bug in typeMerge -
- * it should paint e1 and e2 by deduced common type,
- * but doesn't in this particular case.
- */
- t0 = Type::terror;
- break;
- }
- (*exps)[i] = e;
- }
- }
- if (pt)
- *pt = t0;
-
- return (t0 == Type::terror);
-}
-
-static Expression *opAssignToOp(Loc loc, TOK op, Expression *e1, Expression *e2)
-{ Expression *e;
-
- switch (op)
- {
- case TOKaddass: e = new AddExp(loc, e1, e2); break;
- case TOKminass: e = new MinExp(loc, e1, e2); break;
- case TOKmulass: e = new MulExp(loc, e1, e2); break;
- case TOKdivass: e = new DivExp(loc, e1, e2); break;
- case TOKmodass: e = new ModExp(loc, e1, e2); break;
- case TOKandass: e = new AndExp(loc, e1, e2); break;
- case TOKorass: e = new OrExp (loc, e1, e2); break;
- case TOKxorass: e = new XorExp(loc, e1, e2); break;
- case TOKshlass: e = new ShlExp(loc, e1, e2); break;
- case TOKshrass: e = new ShrExp(loc, e1, e2); break;
- case TOKushrass: e = new UshrExp(loc, e1, e2); break;
- default: assert(0);
- }
- return e;
-}
-
-/*********************
- * Rewrite:
- * array.length op= e2
- * as:
- * array.length = array.length op e2
- * or:
- * auto tmp = &array;
- * (*tmp).length = (*tmp).length op e2
- */
-
-static Expression *rewriteOpAssign(BinExp *exp)
-{
- Expression *e;
-
- assert(exp->e1->op == TOKarraylength);
- ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1;
- if (ale->e1->op == TOKvar)
- {
- e = opAssignToOp(exp->loc, exp->op, ale, exp->e2);
- e = new AssignExp(exp->loc, ale->syntaxCopy(), e);
- }
- else
- {
- /* auto tmp = &array;
- * (*tmp).length = (*tmp).length op e2
- */
- VarDeclaration *tmp = copyToTemp(0, "__arraylength", new AddrExp(ale->loc, ale->e1));
-
- Expression *e1 = new ArrayLengthExp(ale->loc, new PtrExp(ale->loc, new VarExp(ale->loc, tmp)));
- Expression *elvalue = e1->syntaxCopy();
- e = opAssignToOp(exp->loc, exp->op, e1, exp->e2);
- e = new AssignExp(exp->loc, elvalue, e);
- e = new CommaExp(exp->loc, new DeclarationExp(ale->loc, tmp), e);
- }
- return e;
-}
-
-/****************************************
- * Preprocess arguments to function.
- * Output:
- * exps[] tuples expanded, properties resolved, rewritten in place
- * Returns:
- * true a semantic error occurred
- */
-
-static bool preFunctionParameters(Scope *sc, Expressions *exps)
-{
- bool err = false;
- if (exps)
- {
- expandTuples(exps);
-
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *arg = (*exps)[i];
-
- arg = resolveProperties(sc, arg);
- if (arg->op == TOKtype)
- {
- arg->error("cannot pass type %s as a function argument", arg->toChars());
- arg = new ErrorExp();
- err = true;
- }
- else if (arg->type->toBasetype()->ty == Tfunction)
- {
- arg->error("cannot pass type %s as a function argument", arg->toChars());
- arg = new ErrorExp();
- err = true;
- }
- else if (checkNonAssignmentArrayOp(arg))
- {
- arg = new ErrorExp();
- err = true;
- }
- (*exps)[i] = arg;
- }
- }
- return err;
-}
-
-/********************************************
- * Issue an error if default construction is disabled for type t.
- * Default construction is required for arrays and 'out' parameters.
- * Returns:
- * true an error was issued
- */
-static bool checkDefCtor(Loc loc, Type *t)
-{
- t = t->baseElemOf();
- if (t->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)t)->sym;
- if (sd->noDefaultCtor)
- {
- sd->error(loc, "default construction is disabled");
- return true;
- }
- }
- return false;
-}
-
-/****************************************
- * Now that we know the exact type of the function we're calling,
- * the arguments[] need to be adjusted:
- * 1. implicitly convert argument to the corresponding parameter type
- * 2. add default arguments for any missing arguments
- * 3. do default promotions on arguments corresponding to ...
- * 4. add hidden _arguments[] argument
- * 5. call copy constructor for struct value arguments
- * Input:
- * tf type of the function
- * fd the function being called, NULL if called indirectly
- * Output:
- * *prettype return type of function
- * *peprefix expression to execute before arguments[] are evaluated, NULL if none
- * Returns:
- * true errors happened
- */
-
-static bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
- Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix)
-{
- //printf("functionParameters()\n");
- assert(arguments);
- assert(fd || tf->next);
- size_t nargs = arguments ? arguments->length : 0;
- size_t nparams = tf->parameterList.length();
- unsigned olderrors = global.errors;
- bool err = false;
- *prettype = Type::terror;
- Expression *eprefix = NULL;
- *peprefix = NULL;
-
- if (nargs > nparams && tf->parameterList.varargs == VARARGnone)
- {
- error(loc, "expected %llu arguments, not %llu for non-variadic function type %s", (ulonglong)nparams, (ulonglong)nargs, tf->toChars());
- return true;
- }
-
- // If inferring return type, and semantic3() needs to be run if not already run
- if (!tf->next && fd->inferRetType)
- {
- fd->functionSemantic();
- }
- else if (fd && fd->parent)
- {
- TemplateInstance *ti = fd->parent->isTemplateInstance();
- if (ti && ti->tempdecl)
- {
- fd->functionSemantic3();
- }
- }
- bool isCtorCall = fd && fd->needThis() && fd->isCtorDeclaration();
-
- size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
-
- /* If the function return type has wildcards in it, we'll need to figure out the actual type
- * based on the actual argument types.
- */
- MOD wildmatch = 0;
- if (tthis && tf->isWild() && !isCtorCall)
- {
- Type *t = tthis;
- if (t->isImmutable())
- wildmatch = MODimmutable;
- else if (t->isWildConst())
- wildmatch = MODwildconst;
- else if (t->isWild())
- wildmatch = MODwild;
- else if (t->isConst())
- wildmatch = MODconst;
- else
- wildmatch = MODmutable;
- }
-
- int done = 0;
- for (size_t i = 0; i < n; i++)
- {
- Expression *arg;
-
- if (i < nargs)
- arg = (*arguments)[i];
- else
- arg = NULL;
-
- if (i < nparams)
- {
- Parameter *p = tf->parameterList[i];
-
- if (!arg)
- {
- if (!p->defaultArg)
- {
- if (tf->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
- goto L2;
- error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
- return true;
- }
- arg = p->defaultArg;
- arg = inlineCopy(arg, sc);
- // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
- arg = arg->resolveLoc(loc, sc);
- arguments->push(arg);
- nargs++;
- }
-
- if (tf->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
- {
- //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars());
- {
- MATCH m;
- if ((m = arg->implicitConvTo(p->type)) > MATCHnomatch)
- {
- if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()) >= m)
- goto L2;
- else if (nargs != nparams)
- { error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
- return true;
- }
- goto L1;
- }
- }
- L2:
- Type *tb = p->type->toBasetype();
- Type *tret = p->isLazyArray();
- switch (tb->ty)
- {
- case Tsarray:
- case Tarray:
- {
- /* Create a static array variable v of type arg->type:
- * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
- *
- * The array literal in the initializer of the hidden variable
- * is now optimized. See Bugzilla 2356.
- */
- Type *tbn = ((TypeArray *)tb)->next;
-
- Expressions *elements = new Expressions();
- elements->setDim(nargs - i);
- for (size_t u = 0; u < elements->length; u++)
- {
- Expression *a = (*arguments)[i + u];
- if (tret && a->implicitConvTo(tret))
- {
- a = a->implicitCastTo(sc, tret);
- a = a->optimize(WANTvalue);
- a = toDelegate(a, a->type, sc);
- }
- else
- a = a->implicitCastTo(sc, tbn);
- (*elements)[u] = a;
- }
- // Bugzilla 14395: Convert to a static array literal, or its slice.
- arg = new ArrayLiteralExp(loc, tbn->sarrayOf(nargs - i), elements);
- if (tb->ty == Tarray)
- {
- arg = new SliceExp(loc, arg, NULL, NULL);
- arg->type = p->type;
- }
- break;
- }
- case Tclass:
- {
- /* Set arg to be:
- * new Tclass(arg0, arg1, ..., argn)
- */
- Expressions *args = new Expressions();
- args->setDim(nargs - i);
- for (size_t u = i; u < nargs; u++)
- (*args)[u - i] = (*arguments)[u];
- arg = new NewExp(loc, NULL, NULL, p->type, args);
- break;
- }
- default:
- if (!arg)
- {
- error(loc, "not enough arguments");
- return true;
- }
- break;
- }
- arg = expressionSemantic(arg, sc);
- //printf("\targ = '%s'\n", arg->toChars());
- arguments->setDim(i + 1);
- (*arguments)[i] = arg;
- nargs = i + 1;
- done = 1;
- }
-
- L1:
- if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
- {
- bool isRef = (p->storageClass & (STCref | STCout)) != 0;
- if (unsigned char wm = arg->type->deduceWild(p->type, isRef))
- {
- if (wildmatch)
- wildmatch = MODmerge(wildmatch, wm);
- else
- wildmatch = wm;
- //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p->type->toChars(), arg->type->toChars(), wm, wildmatch);
- }
- }
- }
- if (done)
- break;
- }
- if ((wildmatch == MODmutable || wildmatch == MODimmutable) &&
- tf->next->hasWild() &&
- (tf->isref || !tf->next->implicitConvTo(tf->next->immutableOf())))
- {
- if (fd)
- {
- /* If the called function may return the reference to
- * outer inout data, it should be rejected.
- *
- * void foo(ref inout(int) x) {
- * ref inout(int) bar(inout(int)) { return x; }
- * struct S { ref inout(int) bar() inout { return x; } }
- * bar(int.init) = 1; // bad!
- * S().bar() = 1; // bad!
- * }
- */
- Dsymbol *s = NULL;
- if (fd->isThis() || fd->isNested())
- s = fd->toParent2();
- for (; s; s = s->toParent2())
- {
- if (AggregateDeclaration *ad = s->isAggregateDeclaration())
- {
- if (ad->isNested())
- continue;
- break;
- }
- if (FuncDeclaration *ff = s->isFuncDeclaration())
- {
- if (((TypeFunction *)ff->type)->iswild)
- goto Linouterr;
-
- if (ff->isNested() || ff->isThis())
- continue;
- }
- break;
- }
- }
- else if (tf->isWild())
- {
- Linouterr:
- const char *s = wildmatch == MODmutable ? "mutable" : MODtoChars(wildmatch);
- error(loc, "modify inout to %s is not allowed inside inout function", s);
- return true;
- }
- }
-
- assert(nargs >= nparams);
- for (size_t i = 0; i < nargs; i++)
- {
- Expression *arg = (*arguments)[i];
- assert(arg);
- if (i < nparams)
- {
- Parameter *p = tf->parameterList[i];
-
- if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
- {
- Type *tprm = p->type;
- if (p->type->hasWild())
- tprm = p->type->substWildTo(wildmatch);
- if (!tprm->equals(arg->type))
- {
- //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars());
- arg = arg->implicitCastTo(sc, tprm);
- arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
- }
- }
- if (p->storageClass & STCref)
- {
- arg = arg->toLvalue(sc, arg);
-
- // Look for mutable misaligned pointer, etc., in @safe mode
- err |= checkUnsafeAccess(sc, arg, false, true);
- }
- else if (p->storageClass & STCout)
- {
- Type *t = arg->type;
- if (!t->isMutable() || !t->isAssignable()) // check blit assignable
- {
- arg->error("cannot modify struct %s with immutable members", arg->toChars());
- err = true;
- }
- else
- {
- // Look for misaligned pointer, etc., in @safe mode
- err |= checkUnsafeAccess(sc, arg, false, true);
- err |= checkDefCtor(arg->loc, t); // t must be default constructible
- }
- arg = arg->toLvalue(sc, arg);
- }
- else if (p->storageClass & STClazy)
- {
- // Convert lazy argument to a delegate
- if (p->type->ty == Tvoid)
- arg = toDelegate(arg, p->type, sc);
- else
- arg = toDelegate(arg, arg->type, sc);
- }
-
- //printf("arg: %s\n", arg->toChars());
- //printf("type: %s\n", arg->type->toChars());
- if (tf->parameterEscapes(p))
- {
- /* Argument value can escape from the called function.
- * Check arg to see if it matters.
- */
- if (global.params.vsafe)
- err |= checkParamArgumentEscape(sc, fd, p->ident, arg, false);
- }
- else
- {
- /* Argument value cannot escape from the called function.
- */
- Expression *a = arg;
- if (a->op == TOKcast)
- a = ((CastExp *)a)->e1;
-
- if (a->op == TOKfunction)
- {
- /* Function literals can only appear once, so if this
- * appearance was scoped, there cannot be any others.
- */
- FuncExp *fe = (FuncExp *)a;
- fe->fd->tookAddressOf = 0;
- }
- else if (a->op == TOKdelegate)
- {
- /* For passing a delegate to a scoped parameter,
- * this doesn't count as taking the address of it.
- * We only worry about 'escaping' references to the function.
- */
- DelegateExp *de = (DelegateExp *)a;
- if (de->e1->op == TOKvar)
- { VarExp *ve = (VarExp *)de->e1;
- FuncDeclaration *f = ve->var->isFuncDeclaration();
- if (f)
- { f->tookAddressOf--;
- //printf("tookAddressOf = %d\n", f->tookAddressOf);
- }
- }
- }
- }
- arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
- }
- else
- {
- // These will be the trailing ... arguments
-
- // If not D linkage, do promotions
- if (tf->linkage != LINKd)
- {
- // Promote bytes, words, etc., to ints
- arg = integralPromotions(arg, sc);
-
- // Promote floats to doubles
- switch (arg->type->ty)
- {
- case Tfloat32:
- arg = arg->castTo(sc, Type::tfloat64);
- break;
-
- case Timaginary32:
- arg = arg->castTo(sc, Type::timaginary64);
- break;
- }
-
- if (tf->parameterList.varargs == VARARGvariadic)
- {
- const char *p = tf->linkage == LINKc ? "extern(C)" : "extern(C++)";
- if (arg->type->ty == Tarray)
- {
- arg->error("cannot pass dynamic arrays to %s vararg functions", p);
- err = true;
- }
- if (arg->type->ty == Tsarray)
- {
- arg->error("cannot pass static arrays to %s vararg functions", p);
- err = true;
- }
- }
- }
-
- // Do not allow types that need destructors
- if (arg->type->needsDestruction())
- {
- arg->error("cannot pass types that need destruction as variadic arguments");
- err = true;
- }
-
- // Convert static arrays to dynamic arrays
- // BUG: I don't think this is right for D2
- Type *tb = arg->type->toBasetype();
- if (tb->ty == Tsarray)
- {
- TypeSArray *ts = (TypeSArray *)tb;
- Type *ta = ts->next->arrayOf();
- if (ts->size(arg->loc) == 0)
- arg = new NullExp(arg->loc, ta);
- else
- arg = arg->castTo(sc, ta);
- }
- if (tb->ty == Tstruct)
- {
- //arg = callCpCtor(sc, arg);
- }
-
- // Give error for overloaded function addresses
- if (arg->op == TOKsymoff)
- { SymOffExp *se = (SymOffExp *)arg;
- if (se->hasOverloads &&
- !se->var->isFuncDeclaration()->isUnique())
- { arg->error("function %s is overloaded", arg->toChars());
- err = true;
- }
- }
- if (arg->checkValue())
- err = true;
- arg = arg->optimize(WANTvalue);
- }
- (*arguments)[i] = arg;
- }
-
- /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
- */
- const bool isVa_list = tf->parameterList.varargs == VARARGnone;
- if (fd && (fd->flags & FUNCFLAGprintf))
- {
- if (StringExp *se = (*arguments)[nparams - 1 - isVa_list]->isStringExp())
- {
- Expressions argslice;
- argslice.reserve(nargs - nparams);
- for (size_t i = nparams; i < nargs; i++)
- argslice.push((*arguments)[i]);
- checkPrintfFormat(se->loc, se->toPtr(), argslice, isVa_list);
- }
- }
- else if (fd && (fd->flags & FUNCFLAGscanf))
- {
- if (StringExp *se = (*arguments)[nparams - 1 - isVa_list]->isStringExp())
- {
- Expressions argslice;
- argslice.reserve(nargs - nparams);
- for (size_t i = nparams; i < nargs; i++)
- argslice.push((*arguments)[i]);
- checkPrintfFormat(se->loc, se->toPtr(), argslice, isVa_list);
- }
- }
-
- /* Remaining problems:
- * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
- * implemented by calling a function) we'll defer this for now.
- * 2. value structs (or static arrays of them) that need to be copy constructed
- * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
- * function gets called (functions normally destroy their parameters)
- * 2 and 3 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
- * up properly. Pushing arguments on the stack then cannot fail.
- */
- if (1)
- {
- /* TODO: tackle problem 1)
- */
- const bool leftToRight = true; // TODO: something like !fd.isArrayOp
- if (!leftToRight)
- assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
-
- const ptrdiff_t start = (leftToRight ? 0 : (ptrdiff_t)nargs - 1);
- const ptrdiff_t end = (leftToRight ? (ptrdiff_t)nargs : -1);
- const ptrdiff_t step = (leftToRight ? 1 : -1);
-
- /* Compute indices of last throwing argument and first arg needing destruction.
- * Used to not set up destructors unless an arg needs destruction on a throw
- * in a later argument.
- */
- ptrdiff_t lastthrow = -1;
- ptrdiff_t firstdtor = -1;
- for (ptrdiff_t i = start; i != end; i += step)
- {
- Expression *arg = (*arguments)[i];
- if (canThrow(arg, sc->func, false))
- lastthrow = i;
- if (firstdtor == -1 && arg->type->needsDestruction())
- {
- Parameter *p = (i >= (ptrdiff_t)nparams ? NULL : tf->parameterList[i]);
- if (!(p && (p->storageClass & (STClazy | STCref | STCout))))
- firstdtor = i;
- }
- }
-
- /* Does problem 3) apply to this call?
- */
- const bool needsPrefix = (firstdtor >= 0 && lastthrow >= 0
- && (lastthrow - firstdtor) * step > 0);
-
- /* If so, initialize 'eprefix' by declaring the gate
- */
- VarDeclaration *gate = NULL;
- if (needsPrefix)
- {
- // eprefix => bool __gate [= false]
- Identifier *idtmp = Identifier::generateId("__gate");
- gate = new VarDeclaration(loc, Type::tbool, idtmp, NULL);
- gate->storage_class |= STCtemp | STCctfe | STCvolatile;
- dsymbolSemantic(gate, sc);
-
- Expression *ae = new DeclarationExp(loc, gate);
- eprefix = expressionSemantic(ae, sc);
- }
-
- for (ptrdiff_t i = start; i != end; i += step)
- {
- Expression *arg = (*arguments)[i];
-
- Parameter *parameter = (i >= (ptrdiff_t)nparams ? NULL : tf->parameterList[i]);
- const bool isRef = (parameter && (parameter->storageClass & (STCref | STCout)));
- const bool isLazy = (parameter && (parameter->storageClass & STClazy));
-
- /* Skip lazy parameters
- */
- if (isLazy)
- continue;
-
- /* Do we have a gate? Then we have a prefix and we're not yet past the last throwing arg.
- * Declare a temporary variable for this arg and append that declaration to 'eprefix',
- * which will implicitly take care of potential problem 2) for this arg.
- * 'eprefix' will therefore finally contain all args up to and including the last
- * potentially throwing arg, excluding all lazy parameters.
- */
- if (gate)
- {
- const bool needsDtor = (!isRef && arg->type->needsDestruction() && i != lastthrow);
-
- /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
- */
- VarDeclaration *tmp = copyToTemp(0,
- needsDtor ? "__pfx" : "__pfy",
- !isRef ? arg : arg->addressOf());
- dsymbolSemantic(tmp, sc);
-
- /* Modify the destructor so it only runs if gate==false, i.e.,
- * only if there was a throw while constructing the args
- */
- if (!needsDtor)
- {
- if (tmp->edtor)
- {
- assert(i == lastthrow);
- tmp->edtor = NULL;
- }
- }
- else
- {
- // edtor => (__gate || edtor)
- assert(tmp->edtor);
- Expression *e = tmp->edtor;
- e = new LogicalExp(e->loc, TOKoror, new VarExp(e->loc, gate), e);
- tmp->edtor = expressionSemantic(e, sc);
- //printf("edtor: %s\n", tmp->edtor->toChars());
- }
-
- // eprefix => (eprefix, auto __pfx/y = arg)
- DeclarationExp *ae = new DeclarationExp(loc, tmp);
- eprefix = Expression::combine(eprefix, expressionSemantic(ae, sc));
-
- // arg => __pfx/y
- arg = new VarExp(loc, tmp);
- arg = expressionSemantic(arg, sc);
- if (isRef)
- {
- arg = new PtrExp(loc, arg);
- arg = expressionSemantic(arg, sc);
- }
-
- /* Last throwing arg? Then finalize eprefix => (eprefix, gate = true),
- * i.e., disable the dtors right after constructing the last throwing arg.
- * From now on, the callee will take care of destructing the args because
- * the args are implicitly moved into function parameters.
- *
- * Set gate to null to let the next iterations know they don't need to
- * append to eprefix anymore.
- */
- if (i == lastthrow)
- {
- Expression *e = new AssignExp(gate->loc, new VarExp(gate->loc, gate), new IntegerExp(gate->loc, 1, Type::tbool));
- eprefix = Expression::combine(eprefix, expressionSemantic(e, sc));
- gate = NULL;
- }
- }
- else
- {
- /* No gate, no prefix to append to.
- * Handle problem 2) by calling the copy constructor for value structs
- * (or static arrays of them) if appropriate.
- */
- Type *tv = arg->type->baseElemOf();
- if (!isRef && tv->ty == Tstruct)
- arg = doCopyOrMove(sc, arg);
- }
-
- (*arguments)[i] = arg;
- }
- }
- //if (eprefix) printf("eprefix: %s\n", eprefix->toChars());
-
- // If D linkage and variadic, add _arguments[] as first argument
- if (tf->isDstyleVariadic())
- {
- assert(arguments->length >= nparams);
-
- Parameters *args = new Parameters;
- args->setDim(arguments->length - nparams);
- for (size_t i = 0; i < arguments->length - nparams; i++)
- {
- Parameter *arg = new Parameter(STCin, (*arguments)[nparams + i]->type, NULL, NULL, NULL);
- (*args)[i] = arg;
- }
-
- TypeTuple *tup = new TypeTuple(args);
- Expression *e = new TypeidExp(loc, tup);
- e = expressionSemantic(e, sc);
- arguments->insert(0, e);
- }
-
- Type *tret = tf->next;
- if (isCtorCall)
- {
- //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd->toChars(), fd->type->toChars(),
- // wildmatch, tf->isWild(), fd->isolateReturn());
- if (!tthis)
- {
- assert(sc->intypeof || global.errors);
- tthis = fd->isThis()->type->addMod(fd->type->mod);
- }
- if (tf->isWild() && !fd->isolateReturn())
- {
- if (wildmatch)
- tret = tret->substWildTo(wildmatch);
- int offset;
- if (!tret->implicitConvTo(tthis) &&
- !(MODimplicitConv(tret->mod, tthis->mod) && tret->isBaseOf(tthis, &offset) && offset == 0))
- {
- const char* s1 = tret ->isNaked() ? " mutable" : tret ->modToChars();
- const char* s2 = tthis->isNaked() ? " mutable" : tthis->modToChars();
- ::error(loc, "inout constructor %s creates%s object, not%s",
- fd->toPrettyChars(), s1, s2);
- err = true;
- }
- }
- tret = tthis;
- }
- else if (wildmatch && tret)
- {
- /* Adjust function return type based on wildmatch
- */
- //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret->toChars());
- tret = tret->substWildTo(wildmatch);
- }
- *prettype = tret;
- *peprefix = eprefix;
- return (err || olderrors != global.errors);
-}
-
-/**
- * Determines whether a symbol represents a module or package
- * (Used as a helper for is(type == module) and is(type == package))
- *
- * Params:
- * sym = the symbol to be checked
- *
- * Returns:
- * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
- */
-Package *resolveIsPackage(Dsymbol *sym)
-{
- Package *pkg;
- if (Import *imp = sym->isImport())
- {
- if (imp->pkg == NULL)
- {
- error(sym->loc, "Internal Compiler Error: unable to process forward-referenced import `%s`",
- imp->toChars());
- assert(0);
- }
- pkg = imp->pkg;
- }
- else if (Module *mod = sym->isModule())
- pkg = mod->isPackageFile ? mod->pkg : sym->isPackage();
- else
- pkg = sym->isPackage();
- if (pkg)
- pkg->resolvePKGunknown();
- return pkg;
-}
-
-static Module *loadStdMath()
-{
- static Import *impStdMath = NULL;
- if (!impStdMath)
- {
- Identifiers *a = new Identifiers();
- a->push(Id::std);
- Import *s = new Import(Loc(), a, Id::math, NULL, false);
- s->load(NULL);
- if (s->mod)
- {
- s->mod->importAll(NULL);
- dsymbolSemantic(s->mod, NULL);
- }
- impStdMath = s;
- }
- return impStdMath->mod;
-}
-
-class ExpressionSemanticVisitor : public Visitor
-{
-public:
- Expression *result;
- Scope *sc;
-
- ExpressionSemanticVisitor(Scope *sc)
- {
- this->result = NULL;
- this->sc = sc;
- }
-
-private:
- void setError()
- {
- result = new ErrorExp();
- }
-
- /*********************
- * Mark the operand as will never be dereferenced,
- * which is useful info for @safe checks.
- * Do before semantic() on operands rewrites them.
- */
- static void setNoderefOperand(UnaExp *e)
- {
- if (e->e1->op == TOKdotid)
- ((DotIdExp *)e->e1)->noderef = true;
- }
-
- /*********************
- * Mark the operands as will never be dereferenced,
- * which is useful info for @safe checks.
- * Do before semantic() on operands rewrites them.
- */
- static void setNoderefOperands(BinExp *e)
- {
- if (e->e1->op == TOKdotid)
- ((DotIdExp *)e->e1)->noderef = true;
- if (e->e2->op == TOKdotid)
- ((DotIdExp *)e->e2)->noderef = true;
- }
-
- static FuncDeclaration *resolveOverloadSet(Loc loc, Scope *sc,
- OverloadSet *os, Objects* tiargs, Type *tthis, Expressions *arguments)
- {
- FuncDeclaration *f = NULL;
- for (size_t i = 0; i < os->a.length; i++)
- {
- Dsymbol *s = os->a[i];
- if (tiargs && s->isFuncDeclaration())
- continue;
- if (FuncDeclaration *f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, 1))
- {
- if (f2->errors)
- return NULL;
- if (f)
- {
- /* Error if match in more than one overload set,
- * even if one is a 'better' match than the other.
- */
- ScopeDsymbol::multiplyDefined(loc, f, f2);
- }
- else
- f = f2;
- }
- }
- if (!f)
- ::error(loc, "no overload matches for %s", os->toChars());
- else if (f->errors)
- f = NULL;
- return f;
- }
-
- /****************************************************
- * Determine if `exp`, which takes the address of `v`, can do so safely.
- * Params:
- * sc = context
- * exp = expression that takes the address of `v`
- * v = the variable getting its address taken
- * Returns:
- * `true` if ok, `false` for error
- */
- static bool checkAddressVar(Scope *sc, UnaExp *e, VarDeclaration *v)
- {
- if (v)
- {
- if (!v->canTakeAddressOf())
- {
- e->error("cannot take address of %s", e->e1->toChars());
- return false;
- }
- if (sc->func && !sc->intypeof && !v->isDataseg())
- {
- const char *p = v->isParameter() ? "parameter" : "local";
- if (global.params.vsafe)
- {
- // Taking the address of v means it cannot be set to 'scope' later
- v->storage_class &= ~STCmaybescope;
- v->doNotInferScope = true;
- if (v->storage_class & STCscope && sc->func->setUnsafe())
- {
- e->error("cannot take address of scope %s %s in @safe function %s", p, v->toChars(), sc->func->toChars());
- return false;
- }
- }
- else if (sc->func->setUnsafe())
- {
- e->error("cannot take address of %s %s in @safe function %s", p, v->toChars(), sc->func->toChars());
- return false;
- }
- }
- }
- return true;
- }
-
- static bool checkVectorElem(Expression *e, Expression *elem)
- {
- if (elem->isConst() == 1)
- return false;
-
- e->error("constant expression expected, not %s", elem->toChars());
- return true;
- }
-
-public:
- void visit(Expression *e)
- {
- if (e->type)
- e->type = typeSemantic(e->type, e->loc, sc);
- else
- e->type = Type::tvoid;
- result = e;
- }
-
- void visit(IntegerExp *e)
- {
- assert(e->type);
- if (e->type->ty == Terror)
- return setError();
- assert(e->type->deco);
- e->normalize();
- result = e;
- }
-
- void visit(RealExp *e)
- {
- if (!e->type)
- e->type = Type::tfloat64;
- else
- e->type = typeSemantic(e->type, e->loc, sc);
- result = e;
- }
-
- void visit(ComplexExp *e)
- {
- if (!e->type)
- e->type = Type::tcomplex80;
- else
- e->type = typeSemantic(e->type, e->loc, sc);
- result = e;
- }
-
- void visit(IdentifierExp *exp)
- {
- if (exp->type) // This is used as the dummy expression
- {
- result = exp;
- return;
- }
-
- Dsymbol *scopesym;
- Dsymbol *s = sc->search(exp->loc, exp->ident, &scopesym);
- if (s)
- {
- if (s->errors)
- return setError();
-
- Expression *e;
-
- /* See if the symbol was a member of an enclosing 'with'
- */
- WithScopeSymbol *withsym = scopesym->isWithScopeSymbol();
- if (withsym && withsym->withstate->wthis && symbolIsVisible(sc, s))
- {
- /* Disallow shadowing
- */
- // First find the scope of the with
- Scope *scwith = sc;
- while (scwith->scopesym != scopesym)
- {
- scwith = scwith->enclosing;
- assert(scwith);
- }
- // Look at enclosing scopes for symbols with the same name,
- // in the same function
- for (Scope *scx = scwith; scx && scx->func == scwith->func; scx = scx->enclosing)
- {
- Dsymbol *s2;
- if (scx->scopesym && scx->scopesym->symtab &&
- (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL &&
- s != s2)
- {
- exp->error("with symbol %s is shadowing local symbol %s", s->toPrettyChars(), s2->toPrettyChars());
- return setError();
- }
- }
- s = s->toAlias();
-
- // Same as wthis.ident
- // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
- // The redudancy should be removed.
- e = new VarExp(exp->loc, withsym->withstate->wthis);
- e = new DotIdExp(exp->loc, e, exp->ident);
- e = expressionSemantic(e, sc);
- }
- else
- {
- if (withsym)
- {
- if (withsym->withstate->exp->type->ty != Tvoid)
- {
- // with (exp)' is a type expression
- // or 's' is not visible there (for error message)
- e = new TypeExp(exp->loc, withsym->withstate->exp->type);
- }
- else
- {
- // 'with (exp)' is a Package/Module
- e = withsym->withstate->exp;
- }
- e = new DotIdExp(exp->loc, e, exp->ident);
- result = expressionSemantic(e, sc);
- return;
- }
-
- /* If f is really a function template,
- * then replace f with the function template declaration.
- */
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f)
- {
- TemplateDeclaration *td = getFuncTemplateDecl(f);
- if (td)
- {
- if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
- td = td->overroot; // then get the start
- e = new TemplateExp(exp->loc, td, f);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- }
- // Haven't done overload resolution yet, so pass 1
- e = resolve(exp->loc, sc, s, true);
- }
- result = e;
- return;
- }
-
- if (hasThis(sc))
- {
- AggregateDeclaration *ad = sc->getStructClassScope();
- if (ad && ad->aliasthis)
- {
- Expression *e;
- e = new IdentifierExp(exp->loc, Id::This);
- e = new DotIdExp(exp->loc, e, ad->aliasthis->ident);
- e = new DotIdExp(exp->loc, e, exp->ident);
- e = trySemantic(e, sc);
- if (e)
- {
- result = e;
- return;
- }
- }
- }
-
- if (exp->ident == Id::ctfe)
- {
- if (sc->flags & SCOPEctfe)
- {
- exp->error("variable __ctfe cannot be read at compile time");
- return setError();
- }
-
- // Create the magic __ctfe bool variable
- VarDeclaration *vd = new VarDeclaration(exp->loc, Type::tbool, Id::ctfe, NULL);
- vd->storage_class |= STCtemp;
- vd->semanticRun = PASSsemanticdone;
- Expression *e = new VarExp(exp->loc, vd);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- // If we've reached this point and are inside a with() scope then we may
- // try one last attempt by checking whether the 'wthis' object supports
- // dynamic dispatching via opDispatch.
- // This is done by rewriting this expression as wthis.ident.
- for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing)
- {
- if (!sc2->scopesym)
- continue;
-
- if (WithScopeSymbol *ss = sc2->scopesym->isWithScopeSymbol())
- {
- if (ss->withstate->wthis)
- {
- Expression *e;
- e = new VarExp(exp->loc, ss->withstate->wthis);
- e = new DotIdExp(exp->loc, e, exp->ident);
- e = trySemantic(e, sc);
- if (e)
- {
- result = e;
- return;
- }
- }
- break;
- }
- }
-
- /* Look for what user might have meant
- */
- if (const char *n = importHint(exp->ident->toChars()))
- exp->error("`%s` is not defined, perhaps `import %s;` is needed?", exp->ident->toChars(), n);
- else if (Dsymbol *s2 = sc->search_correct(exp->ident))
- exp->error("undefined identifier `%s`, did you mean %s `%s`?", exp->ident->toChars(), s2->kind(), s2->toChars());
- else if (const char *p = Scope::search_correct_C(exp->ident))
- exp->error("undefined identifier `%s`, did you mean `%s`?", exp->ident->toChars(), p);
- else
- exp->error("undefined identifier `%s`", exp->ident->toChars());
- return setError();
- }
-
- void visit(DsymbolExp *e)
- {
- result = resolve(e->loc, sc, e->s, e->hasOverloads);
- }
-
- void visit(ThisExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- FuncDeclaration *fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
-
- /* Special case for typeof(this) and typeof(super) since both
- * should work even if they are not inside a non-static member function
- */
- if (!fd && sc->intypeof == 1)
- {
- // Find enclosing struct or class
- for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent)
- {
- if (!s)
- {
- e->error("%s is not in a class or struct scope", e->toChars());
- goto Lerr;
- }
- ClassDeclaration *cd = s->isClassDeclaration();
- if (cd)
- {
- e->type = cd->type;
- result = e;
- return;
- }
- StructDeclaration *sd = s->isStructDeclaration();
- if (sd)
- {
- e->type = sd->type;
- result = e;
- return;
- }
- }
- }
- if (!fd)
- goto Lerr;
-
- assert(fd->vthis);
- e->var = fd->vthis;
- assert(e->var->parent);
- e->type = e->var->type;
- if (e->var->checkNestedReference(sc, e->loc))
- return setError();
- if (!sc->intypeof)
- sc->callSuper |= CSXthis;
- result = e;
- return;
-
- Lerr:
- e->error("`this` is only defined in non-static member functions, not %s", sc->parent->toChars());
- return setError();
- }
-
- void visit(SuperExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- FuncDeclaration *fd = hasThis(sc);
- ClassDeclaration *cd;
- Dsymbol *s;
-
- /* Special case for typeof(this) and typeof(super) since both
- * should work even if they are not inside a non-static member function
- */
- if (!fd && sc->intypeof == 1)
- {
- // Find enclosing class
- for (s = sc->getStructClassScope(); 1; s = s->parent)
- {
- if (!s)
- {
- e->error("%s is not in a class scope", e->toChars());
- goto Lerr;
- }
- cd = s->isClassDeclaration();
- if (cd)
- {
- cd = cd->baseClass;
- if (!cd)
- {
- e->error("class %s has no `super`", s->toChars());
- goto Lerr;
- }
- e->type = cd->type;
- result = e;
- return;
- }
- }
- }
- if (!fd)
- goto Lerr;
-
- e->var = fd->vthis;
- assert(e->var && e->var->parent);
-
- s = fd->toParent();
- while (s && s->isTemplateInstance())
- s = s->toParent();
- if (s->isTemplateDeclaration()) // allow inside template constraint
- s = s->toParent();
- assert(s);
- cd = s->isClassDeclaration();
- //printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars());
- if (!cd)
- goto Lerr;
- if (!cd->baseClass)
- {
- e->error("no base class for %s", cd->toChars());
- e->type = e->var->type;
- }
- else
- {
- e->type = cd->baseClass->type;
- e->type = e->type->castMod(e->var->type->mod);
- }
-
- if (e->var->checkNestedReference(sc, e->loc))
- return setError();
-
- if (!sc->intypeof)
- sc->callSuper |= CSXsuper;
- result = e;
- return;
-
- Lerr:
- e->error("`super` is only allowed in non-static class member functions");
- return setError();
- }
-
- void visit(NullExp *e)
- {
- // NULL is the same as (void *)0
- if (e->type)
- {
- result = e;
- return;
- }
- e->type = Type::tnull;
- result = e;
- }
-
- void visit(StringExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- OutBuffer buffer;
- size_t newlen = 0;
- const char *p;
- size_t u;
- unsigned c;
-
- switch (e->postfix)
- {
- case 'd':
- for (u = 0; u < e->len;)
- {
- p = utf_decodeChar((utf8_t *)e->string, e->len, &u, &c);
- if (p)
- {
- e->error("%s", p);
- return setError();
- }
- else
- {
- buffer.write4(c);
- newlen++;
- }
- }
- buffer.write4(0);
- e->string = buffer.extractData();
- e->len = newlen;
- e->sz = 4;
- e->type = new TypeDArray(Type::tdchar->immutableOf());
- e->committed = 1;
- break;
-
- case 'w':
- for (u = 0; u < e->len;)
- {
- p = utf_decodeChar((utf8_t *)e->string, e->len, &u, &c);
- if (p)
- {
- e->error("%s", p);
- return setError();
- }
- else
- {
- buffer.writeUTF16(c);
- newlen++;
- if (c >= 0x10000)
- newlen++;
- }
- }
- buffer.writeUTF16(0);
- e->string = buffer.extractData();
- e->len = newlen;
- e->sz = 2;
- e->type = new TypeDArray(Type::twchar->immutableOf());
- e->committed = 1;
- break;
-
- case 'c':
- e->committed = 1;
- /* fall through */
-
- default:
- e->type = new TypeDArray(Type::tchar->immutableOf());
- break;
- }
- e->type = typeSemantic(e->type, e->loc, sc);
- //e->type = e->type->immutableOf();
- //printf("type = %s\n", e->type->toChars());
-
- result = e;
- }
-
- void visit(ArrayLiteralExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- /* Perhaps an empty array literal [ ] should be rewritten as null?
- */
-
- if (e->basis)
- e->basis = expressionSemantic(e->basis, sc);
- if (arrayExpressionSemantic(e->elements, sc) || (e->basis && e->basis->op == TOKerror))
- return setError();
- expandTuples(e->elements);
-
- Type *t0;
- if (e->basis)
- e->elements->push(e->basis);
- bool err = arrayExpressionToCommonType(sc, e->elements, &t0);
- if (e->basis)
- e->elements->pop();
- if (err)
- return setError();
-
- e->type = t0->arrayOf();
- e->type = typeSemantic(e->type, e->loc, sc);
-
- /* Disallow array literals of type void being used.
- */
- if (e->elements->length > 0 && t0->ty == Tvoid)
- {
- e->error("%s of type %s has no value", e->toChars(), e->type->toChars());
- return setError();
- }
-
- if (global.params.useTypeInfo && Type::dtypeinfo)
- semanticTypeInfo(sc, e->type);
-
- result = e;
- }
-
- void visit(AssocArrayLiteralExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- // Run semantic() on each element
- bool err_keys = arrayExpressionSemantic(e->keys, sc);
- bool err_vals = arrayExpressionSemantic(e->values, sc);
- if (err_keys || err_vals)
- return setError();
- expandTuples(e->keys);
- expandTuples(e->values);
- if (e->keys->length != e->values->length)
- {
- e->error("number of keys is %u, must match number of values %u", e->keys->length, e->values->length);
- return setError();
- }
-
- Type *tkey = NULL;
- Type *tvalue = NULL;
- err_keys = arrayExpressionToCommonType(sc, e->keys, &tkey);
- err_vals = arrayExpressionToCommonType(sc, e->values, &tvalue);
- if (err_keys || err_vals)
- return setError();
-
- if (tkey == Type::terror || tvalue == Type::terror)
- return setError();
-
- e->type = new TypeAArray(tvalue, tkey);
- e->type = typeSemantic(e->type, e->loc, sc);
-
- semanticTypeInfo(sc, e->type);
-
- result = e;
- }
-
- void visit(StructLiteralExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- e->sd->size(e->loc);
- if (e->sd->sizeok != SIZEOKdone)
- return setError();
-
- if (arrayExpressionSemantic(e->elements, sc)) // run semantic() on each element
- return setError();
- expandTuples(e->elements);
-
- /* Fit elements[] to the corresponding type of field[].
- */
- if (!e->sd->fit(e->loc, sc, e->elements, e->stype))
- return setError();
-
- /* Fill out remainder of elements[] with default initializers for fields[]
- */
- if (!e->sd->fill(e->loc, e->elements, false))
- {
- /* An error in the initializer needs to be recorded as an error
- * in the enclosing function or template, since the initializer
- * will be part of the stuct declaration.
- */
- global.increaseErrorCount();
- return setError();
- }
-
- if (checkFrameAccess(e->loc, sc, e->sd, e->elements->length))
- return setError();
-
- e->type = e->stype ? e->stype : e->sd->type;
- result = e;
- }
-
- void visit(TypeExp *exp)
- {
- if (exp->type->ty == Terror)
- return setError();
-
- //printf("TypeExp::semantic(%s)\n", exp->type->toChars());
- Expression *e;
- Type *t;
- Dsymbol *s;
-
- exp->type->resolve(exp->loc, sc, &e, &t, &s, true);
- if (e)
- {
- // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
- // then rewrite as `(this.var)` in case it would be followed by a DotVar
- // to fix https://issues.dlang.org/show_bug.cgi?id=9490
- VarExp *ve = e->isVarExp();
- if (ve && ve->var && exp->parens && !ve->var->isStatic() && !(sc->stc & STCstatic) &&
- sc->func && sc->func->needThis() && ve->var->toParent2()->isAggregateDeclaration())
- {
- // printf("apply fix for issue 9490: add `this.` to `%s`...\n", e->toChars());
- e = new DotVarExp(exp->loc, new ThisExp(exp->loc), ve->var, false);
- }
- //printf("e = %s %s\n", Token::toChars(e->op), e->toChars());
- e = expressionSemantic(e, sc);
- }
- else if (t)
- {
- //printf("t = %d %s\n", t->ty, t->toChars());
- exp->type = typeSemantic(t, exp->loc, sc);
- e = exp;
- }
- else if (s)
- {
- //printf("s = %s %s\n", s->kind(), s->toChars());
- e = resolve(exp->loc, sc, s, true);
- }
- else
- assert(0);
-
- if (global.params.vcomplex)
- exp->type->checkComplexTransition(exp->loc);
-
- result = e;
- }
-
- void visit(ScopeExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- ScopeDsymbol *sds2 = exp->sds;
- TemplateInstance *ti = sds2->isTemplateInstance();
- while (ti)
- {
- WithScopeSymbol *withsym;
- if (!ti->findTempDecl(sc, &withsym) ||
- !ti->semanticTiargs(sc))
- return setError();
- if (withsym && withsym->withstate->wthis)
- {
- Expression *e = new VarExp(exp->loc, withsym->withstate->wthis);
- e = new DotTemplateInstanceExp(exp->loc, e, ti);
- result = expressionSemantic(e, sc);
- return;
- }
- if (ti->needsTypeInference(sc))
- {
- if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration())
- {
- Dsymbol *p = td->toParent2();
- FuncDeclaration *fdthis = hasThis(sc);
- AggregateDeclaration *ad = p ? p->isAggregateDeclaration() : NULL;
- if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad &&
- (td->_scope->stc & STCstatic) == 0)
- {
- Expression *e = new DotTemplateInstanceExp(exp->loc, new ThisExp(exp->loc), ti->name, ti->tiargs);
- result = expressionSemantic(e, sc);
- return;
- }
- }
- else if (OverloadSet *os = ti->tempdecl->isOverloadSet())
- {
- FuncDeclaration *fdthis = hasThis(sc);
- AggregateDeclaration *ad = os->parent->isAggregateDeclaration();
- if (fdthis && ad && isAggregate(fdthis->vthis->type) == ad)
- {
- Expression *e = new DotTemplateInstanceExp(exp->loc, new ThisExp(exp->loc), ti->name, ti->tiargs);
- result = expressionSemantic(e, sc);
- return;
- }
- }
- // ti is an instance which requires IFTI.
- exp->sds = ti;
- exp->type = Type::tvoid;
- result = exp;
- return;
- }
- dsymbolSemantic(ti, sc);
- if (!ti->inst || ti->errors)
- return setError();
-
- Dsymbol *s = ti->toAlias();
- if (s == ti)
- {
- exp->sds = ti;
- exp->type = Type::tvoid;
- result = exp;
- return;
- }
- sds2 = s->isScopeDsymbol();
- if (sds2)
- {
- ti = sds2->isTemplateInstance();
- //printf("+ sds2 = %s, '%s'\n", sds2->kind(), sds2->toChars());
- continue;
- }
-
- if (VarDeclaration *v = s->isVarDeclaration())
- {
- if (!v->type)
- {
- exp->error("forward reference of %s %s", v->kind(), v->toChars());
- return setError();
- }
- if ((v->storage_class & STCmanifest) && v->_init)
- {
- /* When an instance that will be converted to a constant exists,
- * the instance representation "foo!tiargs" is treated like a
- * variable name, and its recursive appearance check (note that
- * it's equivalent with a recursive instantiation of foo) is done
- * separately from the circular initialization check for the
- * eponymous enum variable declaration.
- *
- * template foo(T) {
- * enum bool foo = foo; // recursive definition check (v.inuse)
- * }
- * template bar(T) {
- * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
- * }
- */
- if (ti->inuse)
- {
- exp->error("recursive expansion of %s `%s`", ti->kind(), ti->toPrettyChars());
- return setError();
- }
-
- Expression *e = v->expandInitializer(exp->loc);
- ti->inuse++;
- e = expressionSemantic(e, sc);
- ti->inuse--;
- result = e;
- return;
- }
- }
-
- //printf("s = %s, '%s'\n", s->kind(), s->toChars());
- Expression *e = resolve(exp->loc, sc, s, true);
- //printf("-1ScopeExp::semantic()\n");
- result = e;
- return;
- }
-
- //printf("sds2 = %s, '%s'\n", sds2->kind(), sds2->toChars());
- //printf("\tparent = '%s'\n", sds2->parent->toChars());
- dsymbolSemantic(sds2, sc);
-
- if (Type *t = sds2->getType()) // (Aggregate|Enum)Declaration
- {
- Expression *ex = new TypeExp(exp->loc, t);
- result = expressionSemantic(ex, sc);
- return;
- }
-
- if (TemplateDeclaration *td = sds2->isTemplateDeclaration())
- {
- result = expressionSemantic(new TemplateExp(exp->loc, td), sc);
- return;
- }
-
- exp->sds = sds2;
- exp->type = Type::tvoid;
- //printf("-2ScopeExp::semantic() %s\n", exp->toChars());
- result = exp;
- }
-
- void visit(NewExp *exp)
- {
- if (exp->type) // if semantic() already run
- {
- result = exp;
- return;
- }
-
- // Bugzilla 11581: With the syntax `new T[edim]` or `thisexp.new T[edim]`,
- // T should be analyzed first and edim should go into arguments iff it's
- // not a tuple.
- Expression *edim = NULL;
- if (!exp->arguments && exp->newtype->ty == Tsarray)
- {
- edim = ((TypeSArray *)exp->newtype)->dim;
- exp->newtype = ((TypeNext *)exp->newtype)->next;
- }
-
- ClassDeclaration *cdthis = NULL;
- if (exp->thisexp)
- {
- exp->thisexp = expressionSemantic(exp->thisexp, sc);
- if (exp->thisexp->op == TOKerror)
- return setError();
- cdthis = exp->thisexp->type->isClassHandle();
- if (!cdthis)
- {
- exp->error("`this` for nested class must be a class type, not %s", exp->thisexp->type->toChars());
- return setError();
- }
-
- sc = sc->push(cdthis);
- exp->type = typeSemantic(exp->newtype, exp->loc, sc);
- sc = sc->pop();
- }
- else
- {
- exp->type = typeSemantic(exp->newtype, exp->loc, sc);
- }
- if (exp->type->ty == Terror)
- return setError();
-
- if (edim)
- {
- if (exp->type->toBasetype()->ty == Ttuple)
- {
- // --> new T[edim]
- exp->type = new TypeSArray(exp->type, edim);
- exp->type = typeSemantic(exp->type, exp->loc, sc);
- if (exp->type->ty == Terror)
- return setError();
- }
- else
- {
- // --> new T[](edim)
- exp->arguments = new Expressions();
- exp->arguments->push(edim);
- exp->type = exp->type->arrayOf();
- }
- }
-
- exp->newtype = exp->type; // in case type gets cast to something else
- Type *tb = exp->type->toBasetype();
- //printf("tb: %s, deco = %s\n", tb->toChars(), tb->deco);
-
- if (arrayExpressionSemantic(exp->newargs, sc) ||
- preFunctionParameters(sc, exp->newargs))
- {
- return setError();
- }
- if (arrayExpressionSemantic(exp->arguments, sc) ||
- preFunctionParameters(sc, exp->arguments))
- {
- return setError();
- }
-
- if (exp->thisexp && tb->ty != Tclass)
- {
- exp->error("e.new is only for allocating nested classes, not %s", tb->toChars());
- return setError();
- }
-
- size_t nargs = exp->arguments ? exp->arguments->length : 0;
- Expression *newprefix = NULL;
-
- if (tb->ty == Tclass)
- {
- ClassDeclaration *cd = ((TypeClass *)tb)->sym;
- cd->size(exp->loc);
- if (cd->sizeok != SIZEOKdone)
- return setError();
- if (!cd->ctor)
- cd->ctor = cd->searchCtor();
- if (cd->noDefaultCtor && !nargs && !cd->defaultCtor)
- {
- exp->error("default construction is disabled for type %s", cd->type->toChars());
- return setError();
- }
-
- if (cd->isInterfaceDeclaration())
- {
- exp->error("cannot create instance of interface %s", cd->toChars());
- return setError();
- }
- if (cd->isAbstract())
- {
- exp->error("cannot create instance of abstract class %s", cd->toChars());
- for (size_t i = 0; i < cd->vtbl.length; i++)
- {
- FuncDeclaration *fd = cd->vtbl[i]->isFuncDeclaration();
- if (fd && fd->isAbstract())
- errorSupplemental(exp->loc, "function `%s` is not implemented", fd->toFullSignature());
- }
- return setError();
- }
- // checkDeprecated() is already done in newtype->semantic().
-
- if (cd->isNested())
- {
- /* We need a 'this' pointer for the nested class.
- * Ensure we have the right one.
- */
- Dsymbol *s = cd->toParent2();
- //printf("cd isNested, parent = %s '%s'\n", s->kind(), s->toPrettyChars());
- if (ClassDeclaration *cdn = s->isClassDeclaration())
- {
- if (!cdthis)
- {
- // Supply an implicit 'this' and try again
- exp->thisexp = new ThisExp(exp->loc);
- for (Dsymbol *sp = sc->parent; 1; sp = sp->parent)
- {
- if (!sp)
- {
- exp->error("outer class %s `this` needed to `new` nested class %s", cdn->toChars(), cd->toChars());
- return setError();
- }
- ClassDeclaration *cdp = sp->isClassDeclaration();
- if (!cdp)
- continue;
- if (cdp == cdn || cdn->isBaseOf(cdp, NULL))
- break;
- // Add a '.outer' and try again
- exp->thisexp = new DotIdExp(exp->loc, exp->thisexp, Id::outer);
- }
- exp->thisexp = expressionSemantic(exp->thisexp, sc);
- if (exp->thisexp->op == TOKerror)
- return setError();
- cdthis = exp->thisexp->type->isClassHandle();
- }
- if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL))
- {
- //printf("cdthis = %s\n", cdthis->toChars());
- exp->error("`this` for nested class must be of type %s, not %s",
- cdn->toChars(), exp->thisexp->type->toChars());
- return setError();
- }
- if (!MODimplicitConv(exp->thisexp->type->mod, exp->newtype->mod))
- {
- exp->error("nested type %s should have the same or weaker constancy as enclosing type %s",
- exp->newtype->toChars(), exp->thisexp->type->toChars());
- return setError();
- }
- }
- else if (exp->thisexp)
- {
- exp->error("e.new is only for allocating nested classes");
- return setError();
- }
- else if (FuncDeclaration *fdn = s->isFuncDeclaration())
- {
- // make sure the parent context fdn of cd is reachable from sc
- if (checkNestedRef(sc->parent, fdn))
- {
- exp->error("outer function context of %s is needed to `new` nested class %s",
- fdn->toPrettyChars(), cd->toPrettyChars());
- return setError();
- }
- }
- else
- assert(0);
- }
- else if (exp->thisexp)
- {
- exp->error("e.new is only for allocating nested classes");
- return setError();
- }
-
- if (cd->aggNew)
- {
- // Prepend the size argument to newargs[]
- Expression *e = new IntegerExp(exp->loc, cd->size(exp->loc), Type::tsize_t);
- if (!exp->newargs)
- exp->newargs = new Expressions();
- exp->newargs->shift(e);
-
- FuncDeclaration *f = resolveFuncCall(exp->loc, sc, cd->aggNew, NULL, tb, exp->newargs);
- if (!f || f->errors)
- return setError();
- exp->checkDeprecated(sc, f);
- exp->checkDisabled(sc, f);
- exp->checkPurity(sc, f);
- exp->checkSafety(sc, f);
- exp->checkNogc(sc, f);
- checkAccess(cd, exp->loc, sc, f);
-
- TypeFunction *tf = (TypeFunction *)f->type;
- Type *rettype;
- if (functionParameters(exp->loc, sc, tf, NULL, exp->newargs, f, &rettype, &newprefix))
- return setError();
-
- exp->allocator = f->isNewDeclaration();
- assert(exp->allocator);
- }
- else
- {
- if (exp->newargs && exp->newargs->length)
- {
- exp->error("no allocator for %s", cd->toChars());
- return setError();
- }
- }
-
- if (cd->ctor)
- {
- FuncDeclaration *f = resolveFuncCall(exp->loc, sc, cd->ctor, NULL, tb, exp->arguments, 0);
- if (!f || f->errors)
- return setError();
- exp->checkDeprecated(sc, f);
- exp->checkDisabled(sc, f);
- exp->checkPurity(sc, f);
- exp->checkSafety(sc, f);
- exp->checkNogc(sc, f);
- checkAccess(cd, exp->loc, sc, f);
-
- TypeFunction *tf = (TypeFunction *)f->type;
- if (!exp->arguments)
- exp->arguments = new Expressions();
- if (functionParameters(exp->loc, sc, tf, exp->type, exp->arguments, f, &exp->type, &exp->argprefix))
- return setError();
-
- exp->member = f->isCtorDeclaration();
- assert(exp->member);
- }
- else
- {
- if (nargs)
- {
- exp->error("no constructor for %s", cd->toChars());
- return setError();
- }
-
- // https://issues.dlang.org/show_bug.cgi?id=19941
- // Run semantic on all field initializers to resolve any forward
- // references. This is the same as done for structs in sd->fill().
- for (ClassDeclaration *c = cd; c; c = c->baseClass)
- {
- for (size_t i = 0; i < c->fields.length; i++)
- {
- VarDeclaration *v = c->fields[i];
- if (v->inuse || v->_scope == NULL || v->_init == NULL ||
- v->_init->isVoidInitializer())
- continue;
- v->inuse++;
- v->_init = initializerSemantic(v->_init, v->_scope, v->type, INITinterpret);
- v->inuse--;
- }
- }
- }
- }
- else if (tb->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)tb)->sym;
- sd->size(exp->loc);
- if (sd->sizeok != SIZEOKdone)
- return setError();
- if (!sd->ctor)
- sd->ctor = sd->searchCtor();
- if (sd->noDefaultCtor && !nargs)
- {
- exp->error("default construction is disabled for type %s", sd->type->toChars());
- return setError();
- }
- // checkDeprecated() is already done in newtype->semantic().
-
- if (sd->aggNew)
- {
- // Prepend the uint size argument to newargs[]
- Expression *e = new IntegerExp(exp->loc, sd->size(exp->loc), Type::tsize_t);
- if (!exp->newargs)
- exp->newargs = new Expressions();
- exp->newargs->shift(e);
-
- FuncDeclaration *f = resolveFuncCall(exp->loc, sc, sd->aggNew, NULL, tb, exp->newargs);
- if (!f || f->errors)
- return setError();
- exp->checkDeprecated(sc, f);
- exp->checkDisabled(sc, f);
- exp->checkPurity(sc, f);
- exp->checkSafety(sc, f);
- exp->checkNogc(sc, f);
- checkAccess(sd, exp->loc, sc, f);
-
- TypeFunction *tf = (TypeFunction *)f->type;
- Type *rettype;
- if (functionParameters(exp->loc, sc, tf, NULL, exp->newargs, f, &rettype, &newprefix))
- return setError();
-
- exp->allocator = f->isNewDeclaration();
- assert(exp->allocator);
- }
- else
- {
- if (exp->newargs && exp->newargs->length)
- {
- exp->error("no allocator for %s", sd->toChars());
- return setError();
- }
- }
-
- if (sd->ctor && nargs)
- {
- FuncDeclaration *f = resolveFuncCall(exp->loc, sc, sd->ctor, NULL, tb, exp->arguments, 0);
- if (!f || f->errors)
- return setError();
- exp->checkDeprecated(sc, f);
- exp->checkDisabled(sc, f);
- exp->checkPurity(sc, f);
- exp->checkSafety(sc, f);
- exp->checkNogc(sc, f);
- checkAccess(sd, exp->loc, sc, f);
-
- TypeFunction *tf = (TypeFunction *)f->type;
- if (!exp->arguments)
- exp->arguments = new Expressions();
- if (functionParameters(exp->loc, sc, tf, exp->type, exp->arguments, f, &exp->type, &exp->argprefix))
- return setError();
-
- exp->member = f->isCtorDeclaration();
- assert(exp->member);
-
- if (checkFrameAccess(exp->loc, sc, sd, sd->fields.length))
- return setError();
- }
- else
- {
- if (!exp->arguments)
- exp->arguments = new Expressions();
-
- if (!sd->fit(exp->loc, sc, exp->arguments, tb))
- return setError();
- if (!sd->fill(exp->loc, exp->arguments, false))
- return setError();
- if (checkFrameAccess(exp->loc, sc, sd, exp->arguments ? exp->arguments->length : 0))
- return setError();
- }
-
- exp->type = exp->type->pointerTo();
- }
- else if (tb->ty == Tarray && nargs)
- {
- Type *tn = tb->nextOf()->baseElemOf();
- Dsymbol *s = tn->toDsymbol(sc);
- AggregateDeclaration *ad = s ? s->isAggregateDeclaration() : NULL;
- if (ad && ad->noDefaultCtor)
- {
- exp->error("default construction is disabled for type %s", tb->nextOf()->toChars());
- return setError();
- }
- for (size_t i = 0; i < nargs; i++)
- {
- if (tb->ty != Tarray)
- {
- exp->error("too many arguments for array");
- return setError();
- }
-
- Expression *arg = (*exp->arguments)[i];
- arg = resolveProperties(sc, arg);
- arg = arg->implicitCastTo(sc, Type::tsize_t);
- arg = arg->optimize(WANTvalue);
- if (arg->op == TOKint64 && (sinteger_t)arg->toInteger() < 0)
- {
- exp->error("negative array index %s", arg->toChars());
- return setError();
- }
- (*exp->arguments)[i] = arg;
- tb = ((TypeDArray *)tb)->next->toBasetype();
- }
- }
- else if (tb->isscalar())
- {
- if (!nargs)
- {
- }
- else if (nargs == 1)
- {
- Expression *e = (*exp->arguments)[0];
- e = e->implicitCastTo(sc, tb);
- (*exp->arguments)[0] = e;
- }
- else
- {
- exp->error("more than one argument for construction of %s", exp->type->toChars());
- return setError();
- }
-
- exp->type = exp->type->pointerTo();
- }
- else
- {
- exp->error("new can only create structs, dynamic arrays or class objects, not %s's", exp->type->toChars());
- return setError();
- }
-
- //printf("NewExp: '%s'\n", toChars());
- //printf("NewExp:type '%s'\n", exp->type->toChars());
- semanticTypeInfo(sc, exp->type);
-
- if (newprefix)
- {
- result = Expression::combine(newprefix, exp);
- return;
- }
- result = exp;
- }
-
- void visit(NewAnonClassExp *e)
- {
- Expression *d = new DeclarationExp(e->loc, e->cd);
- sc = sc->push(); // just create new scope
- sc->flags &= ~SCOPEctfe; // temporary stop CTFE
- d = expressionSemantic(d, sc);
- sc = sc->pop();
-
- if (!e->cd->errors && sc->intypeof && !sc->parent->inNonRoot())
- {
- ScopeDsymbol *sds = sc->tinst ? (ScopeDsymbol *)sc->tinst : sc->_module;
- sds->members->push(e->cd);
- }
-
- Expression *n = new NewExp(e->loc, e->thisexp, e->newargs, e->cd->type, e->arguments);
-
- Expression *c = new CommaExp(e->loc, d, n);
- result = expressionSemantic(c, sc);
- }
-
- void visit(SymOffExp *e)
- {
- //dsymbolSemantic(var, sc);
- if (!e->type)
- e->type = e->var->type->pointerTo();
- if (VarDeclaration *v = e->var->isVarDeclaration())
- {
- if (v->checkNestedReference(sc, e->loc))
- return setError();
- }
- else if (FuncDeclaration *f = e->var->isFuncDeclaration())
- {
- if (f->checkNestedReference(sc, e->loc))
- return setError();
- }
- result = e;
- }
-
- void visit(VarExp *e)
- {
- VarDeclaration *vd = e->var->isVarDeclaration();
- FuncDeclaration *fd = e->var->isFuncDeclaration();
-
- if (fd)
- {
- //printf("L%d fd = %s\n", __LINE__, f->toChars());
- if (!fd->functionSemantic())
- return setError();
- }
-
- if (!e->type)
- e->type = e->var->type;
-
- if (e->type && !e->type->deco)
- {
- Declaration *decl = e->var->isDeclaration();
- if (decl)
- decl->inuse++;
- e->type = typeSemantic(e->type, e->loc, sc);
- if (decl)
- decl->inuse--;
- }
-
- /* Fix for 1161 doesn't work because it causes protection
- * problems when instantiating imported templates passing private
- * variables as alias template parameters.
- */
- //checkAccess(e->loc, sc, NULL, e->var);
-
- if (vd)
- {
- if (vd->checkNestedReference(sc, e->loc))
- return setError();
- // Bugzilla 12025: If the variable is not actually used in runtime code,
- // the purity violation error is redundant.
- //checkPurity(sc, vd);
- }
- else if (fd)
- {
- // TODO: If fd isn't yet resolved its overload, the checkNestedReference
- // call would cause incorrect validation.
- // Maybe here should be moved in CallExp, or AddrExp for functions.
- if (fd->checkNestedReference(sc, e->loc))
- return setError();
- }
- else if (e->var->isOverDeclaration())
- {
- e->type = Type::tvoid; // ambiguous type?
- }
-
- result = e;
- }
-
- void visit(TupleExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (exp->e0)
- exp->e0 = expressionSemantic(exp->e0, sc);
-
- // Run semantic() on each argument
- bool err = false;
- for (size_t i = 0; i < exp->exps->length; i++)
- {
- Expression *e = (*exp->exps)[i];
- e = expressionSemantic(e, sc);
- if (!e->type)
- {
- exp->error("%s has no value", e->toChars());
- err = true;
- }
- else if (e->op == TOKerror)
- err = true;
- else
- (*exp->exps)[i] = e;
- }
- if (err)
- return setError();
-
- expandTuples(exp->exps);
- exp->type = new TypeTuple(exp->exps);
- exp->type = typeSemantic(exp->type, exp->loc, sc);
- //printf("-TupleExp::semantic(%s)\n", exp->toChars());
- result = exp;
- }
-
- void visit(FuncExp *exp)
- {
- Expression *e = exp;
-
- sc = sc->push(); // just create new scope
- sc->flags &= ~SCOPEctfe; // temporary stop CTFE
- sc->protection = Prot(Prot::public_); // Bugzilla 12506
-
- if (!exp->type || exp->type == Type::tvoid)
- {
- /* fd->treq might be incomplete type,
- * so should not semantic it.
- * void foo(T)(T delegate(int) dg){}
- * foo(a=>a); // in IFTI, treq == T delegate(int)
- */
- //if (exp->fd->treq)
- // exp->fd->treq = typeSemantic(exp->fd->treq, exp->loc, sc);
-
- exp->genIdent(sc);
-
- // Set target of return type inference
- if (exp->fd->treq && !exp->fd->type->nextOf())
- {
- TypeFunction *tfv = NULL;
- if (exp->fd->treq->ty == Tdelegate ||
- (exp->fd->treq->ty == Tpointer && exp->fd->treq->nextOf()->ty == Tfunction))
- tfv = (TypeFunction *)exp->fd->treq->nextOf();
- if (tfv)
- {
- TypeFunction *tfl = (TypeFunction *)exp->fd->type;
- tfl->next = tfv->nextOf();
- }
- }
-
- //printf("td = %p, treq = %p\n", exp->td, exp->fd->treq);
- if (exp->td)
- {
- assert(exp->td->parameters && exp->td->parameters->length);
- dsymbolSemantic(exp->td, sc);
- exp->type = Type::tvoid; // temporary type
-
- if (exp->fd->treq) // defer type determination
- {
- FuncExp *fe;
- if (exp->matchType(exp->fd->treq, sc, &fe) > MATCHnomatch)
- e = fe;
- else
- e = new ErrorExp();
- }
- goto Ldone;
- }
-
- unsigned olderrors = global.errors;
- dsymbolSemantic(exp->fd, sc);
- if (olderrors == global.errors)
- {
- semantic2(exp->fd, sc);
- if (olderrors == global.errors)
- semantic3(exp->fd, sc);
- }
- if (olderrors != global.errors)
- {
- if (exp->fd->type && exp->fd->type->ty == Tfunction && !exp->fd->type->nextOf())
- ((TypeFunction *)exp->fd->type)->next = Type::terror;
- e = new ErrorExp();
- goto Ldone;
- }
-
- // Type is a "delegate to" or "pointer to" the function literal
- if ((exp->fd->isNested() && exp->fd->tok == TOKdelegate) ||
- (exp->tok == TOKreserved && exp->fd->treq && exp->fd->treq->ty == Tdelegate))
- {
- exp->type = new TypeDelegate(exp->fd->type);
- exp->type = typeSemantic(exp->type, exp->loc, sc);
-
- exp->fd->tok = TOKdelegate;
- }
- else
- {
- exp->type = new TypePointer(exp->fd->type);
- exp->type = typeSemantic(exp->type, exp->loc, sc);
- //exp->type = exp->fd->type->pointerTo();
-
- /* A lambda expression deduced to function pointer might become
- * to a delegate literal implicitly.
- *
- * auto foo(void function() fp) { return 1; }
- * assert(foo({}) == 1);
- *
- * So, should keep fd->tok == TOKreserve if fd->treq == NULL.
- */
- if (exp->fd->treq && exp->fd->treq->ty == Tpointer)
- {
- // change to non-nested
- exp->fd->tok = TOKfunction;
- exp->fd->vthis = NULL;
- }
- }
- exp->fd->tookAddressOf++;
- }
- Ldone:
- sc = sc->pop();
- result = e;
- }
-
- // used from CallExp::semantic()
- Expression *callExpSemantic(FuncExp *exp, Scope *sc, Expressions *arguments)
- {
- if ((!exp->type || exp->type == Type::tvoid) && exp->td && arguments && arguments->length)
- {
- for (size_t k = 0; k < arguments->length; k++)
- { Expression *checkarg = (*arguments)[k];
- if (checkarg->op == TOKerror)
- return checkarg;
- }
-
- exp->genIdent(sc);
-
- assert(exp->td->parameters && exp->td->parameters->length);
- dsymbolSemantic(exp->td, sc);
-
- TypeFunction *tfl = (TypeFunction *)exp->fd->type;
- size_t dim = tfl->parameterList.length();
- if (arguments->length < dim)
- { // Default arguments are always typed, so they don't need inference.
- Parameter *p = tfl->parameterList[arguments->length];
- if (p->defaultArg)
- dim = arguments->length;
- }
-
- if ((tfl->parameterList.varargs == VARARGnone && arguments->length == dim) ||
- (tfl->parameterList.varargs != VARARGnone && arguments->length >= dim))
- {
- Objects *tiargs = new Objects();
- tiargs->reserve(exp->td->parameters->length);
-
- for (size_t i = 0; i < exp->td->parameters->length; i++)
- {
- TemplateParameter *tp = (*exp->td->parameters)[i];
- for (size_t u = 0; u < dim; u++)
- { Parameter *p = tfl->parameterList[u];
- if (p->type->ty == Tident &&
- ((TypeIdentifier *)p->type)->ident == tp->ident)
- { Expression *e = (*arguments)[u];
- tiargs->push(e->type);
- u = dim; // break inner loop
- }
- }
- }
-
- TemplateInstance *ti = new TemplateInstance(exp->loc, exp->td, tiargs);
- Expression *se = new ScopeExp(exp->loc, ti);
- return expressionSemantic(se, sc);
- }
- exp->error("cannot infer function literal type");
- return new ErrorExp();
- }
- return expressionSemantic(exp, sc);
- }
-
- void visit(DeclarationExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- unsigned olderrors = global.errors;
-
- /* This is here to support extern(linkage) declaration,
- * where the extern(linkage) winds up being an AttribDeclaration
- * wrapper.
- */
- Dsymbol *s = e->declaration;
-
- while (1)
- {
- AttribDeclaration *ad = s->isAttribDeclaration();
- if (ad)
- {
- if (ad->decl && ad->decl->length == 1)
- {
- s = (*ad->decl)[0];
- continue;
- }
- }
- break;
- }
-
- VarDeclaration *v = s->isVarDeclaration();
- if (v)
- {
- // Do semantic() on initializer first, so:
- // int a = a;
- // will be illegal.
- dsymbolSemantic(e->declaration, sc);
- s->parent = sc->parent;
- }
-
- //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc);
- // Insert into both local scope and function scope.
- // Must be unique in both.
- if (s->ident)
- {
- if (!sc->insert(s))
- {
- e->error("declaration %s is already defined", s->toPrettyChars());
- return setError();
- }
- else if (sc->func)
- {
- // Bugzilla 11720 - include Dataseg variables
- if ((s->isFuncDeclaration() ||
- s->isAggregateDeclaration() ||
- s->isEnumDeclaration() ||
- (v && v->isDataseg())) &&
- !sc->func->localsymtab->insert(s))
- {
- e->error("declaration %s is already defined in another scope in %s",
- s->toPrettyChars(), sc->func->toChars());
- return setError();
- }
- else
- {
- // Disallow shadowing
- for (Scope *scx = sc->enclosing; scx && (scx->func == sc->func || (scx->func && sc->func->fes)); scx = scx->enclosing)
- {
- Dsymbol *s2;
- if (scx->scopesym && scx->scopesym->symtab &&
- (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL &&
- s != s2)
- {
- // allow STClocal symbols to be shadowed
- // TODO: not reallly an optimal design
- Declaration *decl = s2->isDeclaration();
- if (!decl || !(decl->storage_class & STClocal))
- {
- if (sc->func->fes)
- {
- e->deprecation("%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.",
- s->kind(), s->ident->toChars(), s2->kind(), s2->toPrettyChars());
- }
- else
- {
- e->error("%s %s is shadowing %s %s",
- s->kind(), s->ident->toChars(), s2->kind(), s2->toPrettyChars());
- return setError();
- }
- }
- }
- }
- }
- }
- }
- if (!s->isVarDeclaration())
- {
- Scope *sc2 = sc;
- if (sc2->stc & (STCpure | STCnothrow | STCnogc))
- sc2 = sc->push();
- sc2->stc &= ~(STCpure | STCnothrow | STCnogc);
- dsymbolSemantic(e->declaration, sc2);
- if (sc2 != sc)
- sc2->pop();
- s->parent = sc->parent;
- }
- if (global.errors == olderrors)
- {
- semantic2(e->declaration, sc);
- if (global.errors == olderrors)
- {
- semantic3(e->declaration, sc);
- }
- }
- // todo: error in declaration should be propagated.
-
- e->type = Type::tvoid;
- result = e;
- }
-
- void visit(TypeidExp *exp)
- {
- Type *ta = isType(exp->obj);
- Expression *ea = isExpression(exp->obj);
- Dsymbol *sa = isDsymbol(exp->obj);
-
- //printf("ta %p ea %p sa %p\n", ta, ea, sa);
-
- if (ta)
- {
- ta->resolve(exp->loc, sc, &ea, &ta, &sa, true);
- }
-
- if (ea)
- {
- if (Dsymbol *sym = getDsymbol(ea))
- ea = resolve(exp->loc, sc, sym, false);
- else
- ea = expressionSemantic(ea, sc);
- ea = resolveProperties(sc, ea);
- ta = ea->type;
- if (ea->op == TOKtype)
- ea = NULL;
- }
-
- if (!ta)
- {
- //printf("ta %p ea %p sa %p\n", ta, ea, sa);
- exp->error("no type for typeid(%s)", ea ? ea->toChars() : (sa ? sa->toChars() : ""));
- return setError();
- }
-
- if (global.params.vcomplex)
- ta->checkComplexTransition(exp->loc);
-
- Expression *e;
- if (ea && ta->toBasetype()->ty == Tclass)
- {
- if (!Type::typeinfoclass)
- {
- error(exp->loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
- e = new ErrorExp();
- }
- else
- {
- /* Get the dynamic type, which is .classinfo
- */
- ea = expressionSemantic(ea, sc);
- e = new TypeidExp(ea->loc, ea);
- e->type = Type::typeinfoclass->type;
- }
- }
- else if (ta->ty == Terror)
- {
- e = new ErrorExp();
- }
- else
- {
- // Handle this in the glue layer
- e = new TypeidExp(exp->loc, ta);
- e->type = getTypeInfoType(exp->loc, ta, sc);
-
- semanticTypeInfo(sc, ta);
-
- if (ea)
- {
- e = new CommaExp(exp->loc, ea, e); // execute ea
- e = expressionSemantic(e, sc);
- }
- }
- result = e;
- }
-
- void visit(TraitsExp *e)
- {
- result = semanticTraits(e, sc);
- }
-
- void visit(HaltExp *e)
- {
- e->type = Type::tnoreturn;
- result = e;
- }
-
- void visit(IsExp *e)
- {
- /* is(targ id tok tspec)
- * is(targ id : tok2)
- * is(targ id == tok2)
- */
-
- //printf("IsExp::semantic(%s)\n", toChars());
- if (e->id && !(sc->flags & SCOPEcondition))
- {
- e->error("can only declare type aliases within static if conditionals or static asserts");
- return setError();
- }
-
- Type *tded = NULL;
- if (e->tok2 == TOKpackage || e->tok2 == TOKmodule) // These is() expressions are special because they can work on modules, not just types.
- {
- const unsigned oldErrors = global.startGagging();
- Dsymbol *sym = e->targ->toDsymbol(sc);
- global.endGagging(oldErrors);
- if (sym == NULL)
- goto Lno;
- Package *p = resolveIsPackage(sym);
- if (p == NULL)
- goto Lno;
- if (e->tok2 == TOKpackage && p->isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
- goto Lno;
- else if(e->tok2 == TOKmodule && !(p->isModule() || p->isPackageMod()))
- goto Lno;
- tded = e->targ;
- goto Lyes;
- }
-
- {
- Scope *sc2 = sc->copy(); // keep sc->flags
- sc2->tinst = NULL;
- sc2->minst = NULL;
- sc2->flags |= SCOPEfullinst;
- Type *t = e->targ->trySemantic(e->loc, sc2);
- sc2->pop();
- if (!t) // errors, so condition is false
- goto Lno;
- e->targ = t;
- }
-
- if (e->tok2 != TOKreserved)
- {
- switch (e->tok2)
- {
- case TOKstruct:
- if (e->targ->ty != Tstruct)
- goto Lno;
- if (((TypeStruct *)e->targ)->sym->isUnionDeclaration())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKunion:
- if (e->targ->ty != Tstruct)
- goto Lno;
- if (!((TypeStruct *)e->targ)->sym->isUnionDeclaration())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKclass:
- if (e->targ->ty != Tclass)
- goto Lno;
- if (((TypeClass *)e->targ)->sym->isInterfaceDeclaration())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKinterface:
- if (e->targ->ty != Tclass)
- goto Lno;
- if (!((TypeClass *)e->targ)->sym->isInterfaceDeclaration())
- goto Lno;
- tded = e->targ;
- break;
- case TOKconst:
- if (!e->targ->isConst())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKimmutable:
- if (!e->targ->isImmutable())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKshared:
- if (!e->targ->isShared())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKwild:
- if (!e->targ->isWild())
- goto Lno;
- tded = e->targ;
- break;
-
- case TOKsuper:
- // If class or interface, get the base class and interfaces
- if (e->targ->ty != Tclass)
- goto Lno;
- else
- {
- ClassDeclaration *cd = ((TypeClass *)e->targ)->sym;
- Parameters *args = new Parameters;
- args->reserve(cd->baseclasses->length);
- if (cd->semanticRun < PASSsemanticdone)
- dsymbolSemantic(cd, NULL);
- for (size_t i = 0; i < cd->baseclasses->length; i++)
- {
- BaseClass *b = (*cd->baseclasses)[i];
- args->push(new Parameter(STCin, b->type, NULL, NULL, NULL));
- }
- tded = new TypeTuple(args);
- }
- break;
-
- case TOKenum:
- if (e->targ->ty != Tenum)
- goto Lno;
- if (e->id)
- tded = ((TypeEnum *)e->targ)->sym->getMemtype(e->loc);
- else
- tded = e->targ;
- if (tded->ty == Terror)
- return setError();
- break;
-
- case TOKdelegate:
- if (e->targ->ty != Tdelegate)
- goto Lno;
- tded = ((TypeDelegate *)e->targ)->next; // the underlying function type
- break;
-
- case TOKfunction:
- case TOKparameters:
- {
- if (e->targ->ty != Tfunction)
- goto Lno;
- tded = e->targ;
-
- /* Generate tuple from function parameter types.
- */
- assert(tded->ty == Tfunction);
- TypeFunction *tdedf = (TypeFunction *)tded;
- size_t dim = tdedf->parameterList.length();
- Parameters *args = new Parameters;
- args->reserve(dim);
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *arg = tdedf->parameterList[i];
- assert(arg && arg->type);
- /* If one of the default arguments was an error,
- don't return an invalid tuple
- */
- if (e->tok2 == TOKparameters && arg->defaultArg &&
- arg->defaultArg->op == TOKerror)
- return setError();
- args->push(new Parameter(arg->storageClass, arg->type,
- (e->tok2 == TOKparameters) ? arg->ident : NULL,
- (e->tok2 == TOKparameters) ? arg->defaultArg : NULL,
- arg->userAttribDecl));
- }
- tded = new TypeTuple(args);
- break;
- }
- case TOKreturn:
- /* Get the 'return type' for the function,
- * delegate, or pointer to function.
- */
- if (e->targ->ty == Tfunction)
- tded = ((TypeFunction *)e->targ)->next;
- else if (e->targ->ty == Tdelegate)
- {
- tded = ((TypeDelegate *)e->targ)->next;
- tded = ((TypeFunction *)tded)->next;
- }
- else if (e->targ->ty == Tpointer &&
- ((TypePointer *)e->targ)->next->ty == Tfunction)
- {
- tded = ((TypePointer *)e->targ)->next;
- tded = ((TypeFunction *)tded)->next;
- }
- else
- goto Lno;
- break;
-
- case TOKargTypes:
- /* Generate a type tuple of the equivalent types used to determine if a
- * function argument of this type can be passed in registers.
- * The results of this are highly platform dependent, and intended
- * primarly for use in implementing va_arg().
- */
- tded = target.toArgTypes(e->targ);
- if (!tded)
- goto Lno; // not valid for a parameter
- break;
-
- case TOKvector:
- if (e->targ->ty != Tvector)
- goto Lno;
- tded = ((TypeVector *)e->targ)->basetype;
- break;
-
- default:
- assert(0);
- }
- goto Lyes;
- }
- else if (e->tspec && !e->id && !(e->parameters && e->parameters->length))
- {
- /* Evaluate to true if targ matches tspec
- * is(targ == tspec)
- * is(targ : tspec)
- */
- e->tspec = typeSemantic(e->tspec, e->loc, sc);
- //printf("targ = %s, %s\n", e->targ->toChars(), e->targ->deco);
- //printf("tspec = %s, %s\n", e->tspec->toChars(), e->tspec->deco);
- if (e->tok == TOKcolon)
- {
- if (e->targ->implicitConvTo(e->tspec))
- goto Lyes;
- else
- goto Lno;
- }
- else /* == */
- {
- if (e->targ->equals(e->tspec))
- goto Lyes;
- else
- goto Lno;
- }
- }
- else if (e->tspec)
- {
- /* Evaluate to true if targ matches tspec.
- * If true, declare id as an alias for the specialized type.
- * is(targ == tspec, tpl)
- * is(targ : tspec, tpl)
- * is(targ id == tspec)
- * is(targ id : tspec)
- * is(targ id == tspec, tpl)
- * is(targ id : tspec, tpl)
- */
-
- Identifier *tid = e->id ? e->id : Identifier::generateId("__isexp_id");
- e->parameters->insert(0, new TemplateTypeParameter(e->loc, tid, NULL, NULL));
-
- Objects dedtypes;
- dedtypes.setDim(e->parameters->length);
- dedtypes.zero();
-
- MATCH m = deduceType(e->targ, sc, e->tspec, e->parameters, &dedtypes);
- //printf("targ: %s\n", e->targ->toChars());
- //printf("tspec: %s\n", e->tspec->toChars());
- if (m <= MATCHnomatch ||
- (m != MATCHexact && e->tok == TOKequal))
- {
- goto Lno;
- }
- else
- {
- tded = (Type *)dedtypes[0];
- if (!tded)
- tded = e->targ;
- Objects tiargs;
- tiargs.setDim(1);
- tiargs[0] = e->targ;
-
- /* Declare trailing parameters
- */
- for (size_t i = 1; i < e->parameters->length; i++)
- {
- TemplateParameter *tp = (*e->parameters)[i];
- Declaration *s = NULL;
-
- m = tp->matchArg(e->loc, sc, &tiargs, i, e->parameters, &dedtypes, &s);
- if (m <= MATCHnomatch)
- goto Lno;
- dsymbolSemantic(s, sc);
- if (!sc->insert(s))
- e->error("declaration %s is already defined", s->toChars());
-
- unSpeculative(sc, s);
- }
- goto Lyes;
- }
- }
- else if (e->id)
- {
- /* Declare id as an alias for type targ. Evaluate to true
- * is(targ id)
- */
- tded = e->targ;
- goto Lyes;
- }
-
- Lyes:
- if (e->id)
- {
- Dsymbol *s;
- Tuple *tup = isTuple(tded);
- if (tup)
- s = new TupleDeclaration(e->loc, e->id, &(tup->objects));
- else
- s = new AliasDeclaration(e->loc, e->id, tded);
- dsymbolSemantic(s, sc);
- /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
- * More investigation is needed.
- */
- if (!tup && !sc->insert(s))
- e->error("declaration %s is already defined", s->toChars());
-
- unSpeculative(sc, s);
- }
- //printf("Lyes\n");
- result = new IntegerExp(e->loc, 1, Type::tbool);
- return;
-
- Lno:
- //printf("Lno\n");
- result = new IntegerExp(e->loc, 0, Type::tbool);
- }
-
- void visit(BinAssignExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->checkReadModifyWrite(exp->op, exp->e2))
- return setError();
-
- if (exp->e1->op == TOKarraylength)
- {
- // arr.length op= e2;
- e = rewriteOpAssign(exp);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- if (exp->e1->op == TOKslice || exp->e1->type->ty == Tarray || exp->e1->type->ty == Tsarray)
- {
- if (checkNonAssignmentArrayOp(exp->e1))
- return setError();
-
- if (exp->e1->op == TOKslice)
- ((SliceExp *)exp->e1)->arrayop = true;
-
- // T[] op= ...
- if (exp->e2->implicitConvTo(exp->e1->type->nextOf()))
- {
- // T[] op= T
- exp->e2 = exp->e2->castTo(sc, exp->e1->type->nextOf());
- }
- else if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
- exp->type = exp->e1->type;
- result = arrayOp(exp, sc);
- return;
- }
-
- exp->e1 = expressionSemantic(exp->e1, sc);
- exp->e1 = exp->e1->optimize(WANTvalue);
- exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
- exp->type = exp->e1->type;
- if (exp->checkScalar())
- return setError();
-
- int arith = (exp->op == TOKaddass || exp->op == TOKminass || exp->op == TOKmulass ||
- exp->op == TOKdivass || exp->op == TOKmodass || exp->op == TOKpowass);
- int bitwise = (exp->op == TOKandass || exp->op == TOKorass || exp->op == TOKxorass);
- int shift = (exp->op == TOKshlass || exp->op == TOKshrass || exp->op == TOKushrass);
-
- if (bitwise && exp->type->toBasetype()->ty == Tbool)
- exp->e2 = exp->e2->implicitCastTo(sc, exp->type);
- else if (exp->checkNoBool())
- return setError();
-
- if ((exp->op == TOKaddass || exp->op == TOKminass) &&
- exp->e1->type->toBasetype()->ty == Tpointer &&
- exp->e2->type->toBasetype()->isintegral())
- {
- result = scaleFactor(exp, sc);
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- if (arith && exp->checkArithmeticBin())
- return setError();
- if ((bitwise || shift) && exp->checkIntegralBin())
- return setError();
- if (shift)
- {
- if (exp->e2->type->toBasetype()->ty != Tvector)
- exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
- }
-
- if (!target.isVectorOpSupported(exp->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- if (exp->e1->op == TOKerror || exp->e2->op == TOKerror)
- return setError();
-
- e = exp->checkOpAssignTypes(sc);
- if (e->op == TOKerror)
- {
- result = e;
- return;
- }
-
- assert(e->op == TOKassign || e == exp);
- result = ((BinExp *)e)->reorderSettingAAElem(sc);
- }
-
-private:
- Expression *compileIt(CompileExp *exp)
- {
- OutBuffer buf;
- if (expressionsToString(buf, sc, exp->exps))
- return NULL;
-
- unsigned errors = global.errors;
- const size_t len = buf.length();
- const char *str = buf.extractChars();
- Parser p(exp->loc, sc->_module, (const utf8_t *)str, len, false);
- p.nextToken();
- //printf("p.loc.linnum = %d\n", p.loc.linnum);
-
- Expression *e = p.parseExpression();
- if (global.errors != errors)
- return NULL;
-
- if (p.token.value != TOKeof)
- {
- exp->error("incomplete mixin expression (%s)", str);
- return NULL;
- }
- return e;
- }
-
-public:
- void visit(CompileExp *exp)
- {
- //printf("CompileExp::semantic('%s')\n", exp->toChars());
- Expression *e = compileIt(exp);
- if (!e)
- return setError();
- result = expressionSemantic(e, sc);
- }
-
- void visit(ImportExp *e)
- {
- StringExp *se = semanticString(sc, e->e1, "file name argument");
- if (!se)
- return setError();
- se = se->toUTF8(sc);
-
- const char *name = (char *)se->string;
- if (!global.params.fileImppath)
- {
- e->error("need -Jpath switch to import text file %s", name);
- return setError();
- }
-
- /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
- * ('Path Traversal') attacks.
- * http://cwe.mitre.org/data/definitions/22.html
- */
-
- name = FileName::safeSearchPath(global.filePath, name);
- if (!name)
- {
- e->error("file %s cannot be found or not in a path specified with -J", se->toChars());
- return setError();
- }
-
- sc->_module->contentImportedFiles.push(name);
- if (global.params.verbose)
- message("file %.*s\t(%s)", (int)se->len, (char *)se->string, name);
- if (global.params.moduleDeps != NULL)
- {
- OutBuffer *ob = global.params.moduleDeps;
- Module* imod = sc->instantiatingModule();
-
- if (!global.params.moduleDepsFile.length)
- ob->writestring("depsFile ");
- ob->writestring(imod->toPrettyChars());
- ob->writestring(" (");
- escapePath(ob, imod->srcfile->toChars());
- ob->writestring(") : ");
- if (global.params.moduleDepsFile.length)
- ob->writestring("string : ");
- ob->writestring((char *) se->string);
- ob->writestring(" (");
- escapePath(ob, name);
- ob->writestring(")");
- ob->writenl();
- }
-
- {
- File f(name);
- if (f.read())
- {
- e->error("cannot read file %s", f.toChars());
- return setError();
- }
- else
- {
- f.ref = 1;
- se = new StringExp(e->loc, f.buffer, f.len);
- }
- }
- result = expressionSemantic(se, sc);
- }
-
- void visit(AssertExp *exp)
- {
- if (Expression *ex = unaSemantic(exp, sc))
- {
- result = ex;
- return;
- }
- exp->e1 = resolveProperties(sc, exp->e1);
- // BUG: see if we can do compile time elimination of the Assert
- exp->e1 = exp->e1->optimize(WANTvalue);
- exp->e1 = exp->e1->toBoolean(sc);
- if (exp->msg)
- {
- exp->msg = expressionSemantic(exp->msg, sc);
- exp->msg = resolveProperties(sc, exp->msg);
- exp->msg = exp->msg->implicitCastTo(sc, Type::tchar->constOf()->arrayOf());
- exp->msg = exp->msg->optimize(WANTvalue);
- }
-
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- if (exp->msg && exp->msg->op == TOKerror)
- {
- result = exp->msg;
- return;
- }
-
- bool f1 = checkNonAssignmentArrayOp(exp->e1);
- bool f2 = exp->msg && checkNonAssignmentArrayOp(exp->msg);
- if (f1 || f2)
- return setError();
-
- if (exp->e1->isBool(false))
- {
- /* This is an `assert(0)` which means halt program execution
- */
- FuncDeclaration *fd = sc->parent->isFuncDeclaration();
- if (fd)
- fd->hasReturnExp |= 4;
- sc->callSuper |= CSXhalt;
- if (sc->fieldinit)
- {
- for (size_t i = 0; i < sc->fieldinit_dim; i++)
- sc->fieldinit[i] |= CSXhalt;
- }
-
- if (global.params.useAssert == CHECKENABLEoff)
- {
- Expression *e = new HaltExp(exp->loc);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- exp->type = Type::tnoreturn;
- }
- else
- exp->type = Type::tvoid;
- result = exp;
- }
-
- void visit(DotIdExp *exp)
- {
- Expression *e = semanticY(exp, sc, 1);
- if (e && isDotOpDispatch(e))
- {
- unsigned errors = global.startGagging();
- e = resolvePropertiesX(sc, e);
- if (global.endGagging(errors))
- e = NULL; /* fall down to UFCS */
- else
- {
- result = e;
- return;
- }
- }
- if (!e) // if failed to find the property
- {
- /* If ident is not a valid property, rewrite:
- * e1.ident
- * as:
- * .ident(e1)
- */
- e = resolveUFCSProperties(sc, exp);
- }
- result = e;
- }
-
- void visit(DotTemplateExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
- if (Expression *ex = unaSemantic(e, sc))
- {
- result = ex;
- return;
- }
- // 'void' like TemplateExp
- e->type = Type::tvoid;
- result = e;
- }
-
- void visit(DotVarExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- exp->var = exp->var->toAlias()->isDeclaration();
-
- exp->e1 = expressionSemantic(exp->e1, sc);
-
- if (TupleDeclaration *tup = exp->var->isTupleDeclaration())
- {
- /* Replace:
- * e1.tuple(a, b, c)
- * with:
- * tuple(e1.a, e1.b, e1.c)
- */
- Expression *e0 = NULL;
- Expression *ev = sc->func ? extractSideEffect(sc, "__tup", &e0, exp->e1) : exp->e1;
-
- Expressions *exps = new Expressions;
- exps->reserve(tup->objects->length);
- for (size_t i = 0; i < tup->objects->length; i++)
- {
- RootObject *o = (*tup->objects)[i];
- Expression *e;
- if (o->dyncast() == DYNCAST_EXPRESSION)
- {
- e = (Expression *)o;
- if (e->op == TOKdsymbol)
- {
- Dsymbol *s = ((DsymbolExp *)e)->s;
- e = new DotVarExp(exp->loc, ev, s->isDeclaration());
- }
- }
- else if (o->dyncast() == DYNCAST_DSYMBOL)
- {
- e = new DsymbolExp(exp->loc, (Dsymbol *)o);
- }
- else if (o->dyncast() == DYNCAST_TYPE)
- {
- e = new TypeExp(exp->loc, (Type *)o);
- }
- else
- {
- exp->error("%s is not an expression", o->toChars());
- return setError();
- }
- exps->push(e);
- }
-
- Expression *e = new TupleExp(exp->loc, e0, exps);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- exp->e1 = exp->e1->addDtorHook(sc);
-
- Type *t1 = exp->e1->type;
-
- if (FuncDeclaration *fd = exp->var->isFuncDeclaration())
- {
- // for functions, do checks after overload resolution
- if (!fd->functionSemantic())
- return setError();
-
- /* Bugzilla 13843: If fd obviously has no overloads, we should
- * normalize AST, and it will give a chance to wrap fd with FuncExp.
- */
- if (fd->isNested() || fd->isFuncLiteralDeclaration())
- {
- // (e1, fd)
- Expression *e = resolve(exp->loc, sc, fd, false);
- result = Expression::combine(exp->e1, e);
- return;
- }
-
- exp->type = fd->type;
- assert(exp->type);
- }
- else if (exp->var->isOverDeclaration())
- {
- exp->type = Type::tvoid; // ambiguous type?
- }
- else
- {
- exp->type = exp->var->type;
- if (!exp->type && global.errors)
- {
- // var is goofed up, just return 0
- return setError();
- }
- assert(exp->type);
-
- if (t1->ty == Tpointer)
- t1 = t1->nextOf();
-
- exp->type = exp->type->addMod(t1->mod);
-
- Dsymbol *vparent = exp->var->toParent();
- AggregateDeclaration *ad = vparent ? vparent->isAggregateDeclaration() : NULL;
-
- if (Expression *e1x = getRightThis(exp->loc, sc, ad, exp->e1, exp->var, 1))
- exp->e1 = e1x;
- else
- {
- /* Later checkRightThis will report correct error for invalid field variable access.
- */
- Expression *e = new VarExp(exp->loc, exp->var);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- checkAccess(exp->loc, sc, exp->e1, exp->var);
-
- VarDeclaration *v = exp->var->isVarDeclaration();
- if (v && (v->isDataseg() || (v->storage_class & STCmanifest)))
- {
- Expression *e = expandVar(WANTvalue, v);
- if (e)
- {
- result = e;
- return;
- }
- }
-
- if (v && v->isDataseg()) // fix bugzilla 8238
- {
- // (e1, v)
- checkAccess(exp->loc, sc, exp->e1, v);
- Expression *e = new VarExp(exp->loc, v);
- e = new CommaExp(exp->loc, exp->e1, e);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- }
-
- //printf("-DotVarExp::semantic('%s')\n", exp->toChars());
- result = exp;
- }
-
- void visit(DotTemplateInstanceExp *exp)
- {
- // Indicate we need to resolve by UFCS.
- Expression *e = semanticY(exp, sc, 1);
- if (!e)
- e = resolveUFCSProperties(sc, exp);
- result = e;
- }
-
- void visit(DelegateExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- e->e1 = expressionSemantic(e->e1, sc);
- e->type = new TypeDelegate(e->func->type);
- e->type = typeSemantic(e->type, e->loc, sc);
- FuncDeclaration *f = e->func->toAliasFunc();
- AggregateDeclaration *ad = f->toParent()->isAggregateDeclaration();
- if (f->needThis())
- e->e1 = getRightThis(e->loc, sc, ad, e->e1, f);
- if (f->type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)f->type;
- if (!MODmethodConv(e->e1->type->mod, f->type->mod))
- {
- OutBuffer thisBuf, funcBuf;
- MODMatchToBuffer(&thisBuf, e->e1->type->mod, tf->mod);
- MODMatchToBuffer(&funcBuf, tf->mod, e->e1->type->mod);
- e->error("%smethod %s is not callable using a %s%s",
- funcBuf.peekChars(), f->toPrettyChars(), thisBuf.peekChars(), e->e1->toChars());
- return setError();
- }
- }
- if (ad && ad->isClassDeclaration() && ad->type != e->e1->type)
- {
- // A downcast is required for interfaces, see Bugzilla 3706
- e->e1 = new CastExp(e->loc, e->e1, ad->type);
- e->e1 = expressionSemantic(e->e1, sc);
- }
- result = e;
- }
-
- void visit(DotTypeExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *e = unaSemantic(exp, sc))
- {
- result = e;
- return;
- }
-
- exp->type = exp->sym->getType()->addMod(exp->e1->type->mod);
- result = exp;
- }
-
- void visit(CallExp *exp)
- {
- if (exp->type)
- {
- result = exp; // semantic() already run
- return;
- }
-
- Type *t1;
- Objects *tiargs = NULL; // initial list of template arguments
- Expression *ethis = NULL;
- Type *tthis = NULL;
- Expression *e1org = exp->e1;
-
- if (exp->e1->op == TOKcomma)
- {
- /* Rewrite (a,b)(args) as (a,(b(args)))
- */
- CommaExp *ce = (CommaExp *)exp->e1;
- exp->e1 = ce->e2;
- ce->e2 = exp;
- result = expressionSemantic(ce, sc);
- return;
- }
-
- if (exp->e1->op == TOKdelegate)
- {
- DelegateExp *de = (DelegateExp *)exp->e1;
- exp->e1 = new DotVarExp(de->loc, de->e1, de->func, de->hasOverloads);
- result = expressionSemantic(exp, sc);
- return;
- }
-
- if (exp->e1->op == TOKfunction)
- {
- if (arrayExpressionSemantic(exp->arguments, sc) ||
- preFunctionParameters(sc, exp->arguments))
- {
- return setError();
- }
-
- // Run e1 semantic even if arguments have any errors
- FuncExp *fe = (FuncExp *)exp->e1;
- exp->e1 = callExpSemantic(fe, sc, exp->arguments);
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- }
-
- if (Expression *ex = resolveUFCS(sc, exp))
- {
- result = ex;
- return;
- }
-
- /* This recognizes:
- * foo!(tiargs)(funcargs)
- */
- if (exp->e1->op == TOKscope)
- {
- ScopeExp *se = (ScopeExp *)exp->e1;
- TemplateInstance *ti = se->sds->isTemplateInstance();
- if (ti)
- {
- /* Attempt to instantiate ti. If that works, go with it.
- * If not, go with partial explicit specialization.
- */
- WithScopeSymbol *withsym;
- if (!ti->findTempDecl(sc, &withsym) ||
- !ti->semanticTiargs(sc))
- {
- return setError();
- }
- if (withsym && withsym->withstate->wthis)
- {
- exp->e1 = new VarExp(exp->e1->loc, withsym->withstate->wthis);
- exp->e1 = new DotTemplateInstanceExp(exp->e1->loc, exp->e1, ti);
- goto Ldotti;
- }
- if (ti->needsTypeInference(sc, 1))
- {
- /* Go with partial explicit specialization
- */
- tiargs = ti->tiargs;
- assert(ti->tempdecl);
- if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration())
- exp->e1 = new TemplateExp(exp->loc, td);
- else if (OverDeclaration *od = ti->tempdecl->isOverDeclaration())
- exp->e1 = new VarExp(exp->loc, od);
- else
- exp->e1 = new OverExp(exp->loc, ti->tempdecl->isOverloadSet());
- }
- else
- {
- Expression *e1x = expressionSemantic(exp->e1, sc);
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- exp->e1 = e1x;
- }
- }
- }
-
- /* This recognizes:
- * expr.foo!(tiargs)(funcargs)
- */
- Ldotti:
- if (exp->e1->op == TOKdotti && !exp->e1->type)
- {
- DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)exp->e1;
- TemplateInstance *ti = se->ti;
- {
- /* Attempt to instantiate ti. If that works, go with it.
- * If not, go with partial explicit specialization.
- */
- if (!se->findTempDecl(sc) ||
- !ti->semanticTiargs(sc))
- {
- return setError();
- }
- if (ti->needsTypeInference(sc, 1))
- {
- /* Go with partial explicit specialization
- */
- tiargs = ti->tiargs;
- assert(ti->tempdecl);
- if (TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration())
- exp->e1 = new DotTemplateExp(exp->loc, se->e1, td);
- else if (OverDeclaration *od = ti->tempdecl->isOverDeclaration())
- {
- exp->e1 = new DotVarExp(exp->loc, se->e1, od, true);
- }
- else
- exp->e1 = new DotExp(exp->loc, se->e1, new OverExp(exp->loc, ti->tempdecl->isOverloadSet()));
- }
- else
- {
- Expression *e1x = expressionSemantic(exp->e1, sc);
- if (e1x->op == TOKerror)
- {
- result =e1x;
- return;
- }
- exp->e1 = e1x;
- }
- }
- }
-
- Lagain:
- //printf("Lagain: %s\n", exp->toChars());
- exp->f = NULL;
- if (exp->e1->op == TOKthis || exp->e1->op == TOKsuper)
- {
- // semantic() run later for these
- }
- else
- {
- if (exp->e1->op == TOKdotid)
- {
- DotIdExp *die = (DotIdExp *)exp->e1;
- exp->e1 = expressionSemantic(die, sc);
- /* Look for e1 having been rewritten to expr.opDispatch!(string)
- * We handle such earlier, so go back.
- * Note that in the rewrite, we carefully did not run semantic() on e1
- */
- if (exp->e1->op == TOKdotti && !exp->e1->type)
- {
- goto Ldotti;
- }
- }
- else
- {
- static int nest;
- if (++nest > global.recursionLimit)
- {
- exp->error("recursive evaluation of %s", exp->toChars());
- --nest;
- return setError();
- }
- Expression *ex = unaSemantic(exp, sc);
- --nest;
- if (ex)
- {
- result = ex;
- return;
- }
- }
-
- /* Look for e1 being a lazy parameter
- */
- if (exp->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)exp->e1;
- if (ve->var->storage_class & STClazy)
- {
- // lazy paramaters can be called without violating purity and safety
- Type *tw = ve->var->type;
- Type *tc = ve->var->type->substWildTo(MODconst);
- TypeFunction *tf = new TypeFunction(ParameterList(), tc, LINKd, STCsafe | STCpure);
- (tf = (TypeFunction *)typeSemantic(tf, exp->loc, sc))->next = tw; // hack for bug7757
- TypeDelegate *t = new TypeDelegate(tf);
- ve->type = typeSemantic(t, exp->loc, sc);
- }
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v && ve->checkPurity(sc, v))
- return setError();
- }
-
- if (exp->e1->op == TOKsymoff && ((SymOffExp *)exp->e1)->hasOverloads)
- {
- SymOffExp *se = (SymOffExp *)exp->e1;
- exp->e1 = new VarExp(se->loc, se->var, true);
- exp->e1 = expressionSemantic(exp->e1, sc);
- }
- else if (exp->e1->op == TOKdot)
- {
- DotExp *de = (DotExp *) exp->e1;
-
- if (de->e2->op == TOKoverloadset)
- {
- ethis = de->e1;
- tthis = de->e1->type;
- exp->e1 = de->e2;
- }
- }
- else if (exp->e1->op == TOKstar && exp->e1->type->ty == Tfunction)
- {
- // Rewrite (*fp)(arguments) to fp(arguments)
- exp->e1 = ((PtrExp *)exp->e1)->e1;
- }
- }
-
- t1 = exp->e1->type ? exp->e1->type->toBasetype() : NULL;
-
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- if (arrayExpressionSemantic(exp->arguments, sc) ||
- preFunctionParameters(sc, exp->arguments))
- {
- return setError();
- }
-
- // Check for call operator overload
- if (t1)
- {
- if (t1->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)t1)->sym;
- sd->size(exp->loc); // Resolve forward references to construct object
- if (sd->sizeok != SIZEOKdone)
- return setError();
- if (!sd->ctor)
- sd->ctor = sd->searchCtor();
-
- // First look for constructor
- if (exp->e1->op == TOKtype && sd->ctor)
- {
- if (!sd->noDefaultCtor && !(exp->arguments && exp->arguments->length))
- goto Lx;
-
- StructLiteralExp *sle = new StructLiteralExp(exp->loc, sd, NULL, exp->e1->type);
- if (!sd->fill(exp->loc, sle->elements, true))
- return setError();
- if (checkFrameAccess(exp->loc, sc, sd, sle->elements->length))
- return setError();
- // Bugzilla 14556: Set concrete type to avoid further redundant semantic().
- sle->type = exp->e1->type;
-
- /* Constructor takes a mutable object, so don't use
- * the immutable initializer symbol.
- */
- sle->useStaticInit = false;
-
- Expression *e = sle;
- if (CtorDeclaration *cf = sd->ctor->isCtorDeclaration())
- {
- e = new DotVarExp(exp->loc, e, cf, true);
- }
- else if (TemplateDeclaration *td = sd->ctor->isTemplateDeclaration())
- {
- e = new DotTemplateExp(exp->loc, e, td);
- }
- else if (OverloadSet *os = sd->ctor->isOverloadSet())
- {
- e = new DotExp(exp->loc, e, new OverExp(exp->loc, os));
- }
- else
- assert(0);
- e = new CallExp(exp->loc, e, exp->arguments);
- result = expressionSemantic(e, sc);
- return;
- }
- // No constructor, look for overload of opCall
- if (search_function(sd, Id::call))
- goto L1; // overload of opCall, therefore it's a call
-
- if (exp->e1->op != TOKtype)
- {
- if (sd->aliasthis && exp->e1->type != exp->att1)
- {
- if (!exp->att1 && exp->e1->type->checkAliasThisRec())
- exp->att1 = exp->e1->type;
- exp->e1 = resolveAliasThis(sc, exp->e1);
- goto Lagain;
- }
- exp->error("%s %s does not overload ()", sd->kind(), sd->toChars());
- return setError();
- }
-
- /* It's a struct literal
- */
- Lx:
- Expression *e = new StructLiteralExp(exp->loc, sd, exp->arguments, exp->e1->type);
- result = expressionSemantic(e, sc);
- return;
- }
- else if (t1->ty == Tclass)
- {
- L1:
- // Rewrite as e1.call(arguments)
- Expression *e = new DotIdExp(exp->loc, exp->e1, Id::call);
- e = new CallExp(exp->loc, e, exp->arguments);
- result = expressionSemantic(e, sc);
- return;
- }
- else if (exp->e1->op == TOKtype && t1->isscalar())
- {
- Expression *e;
-
- // Make sure to use the the enum type itself rather than its
- // base type (see bugzilla 16346)
- if (exp->e1->type->ty == Tenum)
- {
- t1 = exp->e1->type;
- }
-
- if (!exp->arguments || exp->arguments->length == 0)
- {
- e = t1->defaultInitLiteral(exp->loc);
- }
- else if (exp->arguments->length == 1)
- {
- e = (*exp->arguments)[0];
- e = e->implicitCastTo(sc, t1);
- e = new CastExp(exp->loc, e, t1);
- }
- else
- {
- exp->error("more than one argument for construction of %s", t1->toChars());
- e = new ErrorExp();
- }
- result = expressionSemantic(e, sc);
- return;
- }
- }
-
- if ((exp->e1->op == TOKdotvar && t1->ty == Tfunction) ||
- exp->e1->op == TOKdottd)
- {
- UnaExp *ue = (UnaExp *)(exp->e1);
-
- Expression *ue1 = ue->e1;
- Expression *ue1old = ue1; // need for 'right this' check
- VarDeclaration *v;
- if (ue1->op == TOKvar &&
- (v = ((VarExp *)ue1)->var->isVarDeclaration()) != NULL &&
- v->needThis())
- {
- ue->e1 = new TypeExp(ue1->loc, ue1->type);
- ue1 = NULL;
- }
-
- DotVarExp *dve;
- DotTemplateExp *dte;
- Dsymbol *s;
- if (exp->e1->op == TOKdotvar)
- {
- dve = (DotVarExp *)(exp->e1);
- dte = NULL;
- s = dve->var;
- tiargs = NULL;
- }
- else
- {
- dve = NULL;
- dte = (DotTemplateExp *)(exp->e1);
- s = dte->td;
- }
-
- // Do overload resolution
- exp->f = resolveFuncCall(exp->loc, sc, s, tiargs, ue1 ? ue1->type : NULL, exp->arguments);
- if (!exp->f || exp->f->errors || exp->f->type->ty == Terror)
- return setError();
- if (exp->f->interfaceVirtual)
- {
- /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
- */
- BaseClass *b = exp->f->interfaceVirtual;
- ClassDeclaration *ad2 = b->sym;
- ue->e1 = ue->e1->castTo(sc, ad2->type->addMod(ue->e1->type->mod));
- ue->e1 = expressionSemantic(ue->e1, sc);
- ue1 = ue->e1;
- int vi = exp->f->findVtblIndex((Dsymbols*)&ad2->vtbl, (int)ad2->vtbl.length);
- assert(vi >= 0);
- exp->f = ad2->vtbl[vi]->isFuncDeclaration();
- assert(exp->f);
- }
- if (exp->f->needThis())
- {
- AggregateDeclaration *ad = exp->f->toParent2()->isAggregateDeclaration();
- ue->e1 = getRightThis(exp->loc, sc, ad, ue->e1, exp->f);
- if (ue->e1->op == TOKerror)
- {
- result = ue->e1;
- return;
- }
- ethis = ue->e1;
- tthis = ue->e1->type;
- if (!(exp->f->type->ty == Tfunction && ((TypeFunction *)exp->f->type)->isscope))
- {
- if (global.params.vsafe && checkParamArgumentEscape(sc, exp->f, Id::This, ethis, false))
- return setError();
- }
- }
-
- /* Cannot call public functions from inside invariant
- * (because then the invariant would have infinite recursion)
- */
- if (sc->func && sc->func->isInvariantDeclaration() &&
- ue->e1->op == TOKthis &&
- exp->f->addPostInvariant()
- )
- {
- exp->error("cannot call public/export function %s from invariant", exp->f->toChars());
- return setError();
- }
-
- exp->checkDeprecated(sc, exp->f);
- exp->checkDisabled(sc, exp->f);
- exp->checkPurity(sc, exp->f);
- exp->checkSafety(sc, exp->f);
- exp->checkNogc(sc, exp->f);
- checkAccess(exp->loc, sc, ue->e1, exp->f);
- if (!exp->f->needThis())
- {
- exp->e1 = Expression::combine(ue->e1, new VarExp(exp->loc, exp->f, false));
- }
- else
- {
- if (ue1old->checkRightThis(sc))
- return setError();
- if (exp->e1->op == TOKdotvar)
- {
- dve->var = exp->f;
- exp->e1->type = exp->f->type;
- }
- else
- {
- exp->e1 = new DotVarExp(exp->loc, dte->e1, exp->f, false);
- exp->e1 = expressionSemantic(exp->e1, sc);
- if (exp->e1->op == TOKerror)
- return setError();
- ue = (UnaExp *)exp->e1;
- }
-
- // See if we need to adjust the 'this' pointer
- AggregateDeclaration *ad = exp->f->isThis();
- ClassDeclaration *cd = ue->e1->type->isClassHandle();
- if (ad && cd && ad->isClassDeclaration())
- {
- if (ue->e1->op == TOKdottype)
- {
- ue->e1 = ((DotTypeExp *)ue->e1)->e1;
- exp->directcall = true;
- }
- else if (ue->e1->op == TOKsuper)
- exp->directcall = true;
- else if ((cd->storage_class & STCfinal) != 0) // Bugzilla 14211
- exp->directcall = true;
-
- if (ad != cd)
- {
- ue->e1 = ue->e1->castTo(sc, ad->type->addMod(ue->e1->type->mod));
- ue->e1 = expressionSemantic(ue->e1, sc);
- }
- }
- }
- // If we've got a pointer to a function then deference it
- // https://issues.dlang.org/show_bug.cgi?id=16483
- if (exp->e1->type->ty == Tpointer && exp->e1->type->nextOf()->ty == Tfunction)
- {
- Expression *e = new PtrExp(exp->loc, exp->e1);
- e->type = exp->e1->type->nextOf();
- exp->e1 = e;
- }
- t1 = exp->e1->type;
- }
- else if (exp->e1->op == TOKsuper)
- {
- // Base class constructor call
- AggregateDeclaration *ad = sc->func ? sc->func->isThis() : NULL;
- ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL;
- if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration())
- {
- exp->error("super class constructor call must be in a constructor");
- return setError();
- }
- if (!cd->baseClass->ctor)
- {
- exp->error("no super class constructor for %s", cd->baseClass->toChars());
- return setError();
- }
-
- if (!sc->intypeof && !(sc->callSuper & CSXhalt))
- {
- if (sc->noctor || sc->callSuper & CSXlabel)
- exp->error("constructor calls not allowed in loops or after labels");
- if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
- exp->error("multiple constructor calls");
- if ((sc->callSuper & CSXreturn) && !(sc->callSuper & CSXany_ctor))
- exp->error("an earlier return statement skips constructor");
- sc->callSuper |= CSXany_ctor | CSXsuper_ctor;
- }
-
- tthis = cd->type->addMod(sc->func->type->mod);
- if (OverloadSet *os = cd->baseClass->ctor->isOverloadSet())
- exp->f = resolveOverloadSet(exp->loc, sc, os, NULL, tthis, exp->arguments);
- else
- exp->f = resolveFuncCall(exp->loc, sc, cd->baseClass->ctor, NULL, tthis, exp->arguments, 0);
- if (!exp->f || exp->f->errors)
- return setError();
- exp->checkDeprecated(sc, exp->f);
- exp->checkDisabled(sc, exp->f);
- exp->checkPurity(sc, exp->f);
- exp->checkSafety(sc, exp->f);
- exp->checkNogc(sc, exp->f);
- checkAccess(exp->loc, sc, NULL, exp->f);
-
- exp->e1 = new DotVarExp(exp->e1->loc, exp->e1, exp->f, false);
- exp->e1 = expressionSemantic(exp->e1, sc);
- t1 = exp->e1->type;
- }
- else if (exp->e1->op == TOKthis)
- {
- // same class constructor call
- AggregateDeclaration *ad = sc->func ? sc->func->isThis() : NULL;
- if (!ad || !sc->func->isCtorDeclaration())
- {
- exp->error("constructor call must be in a constructor");
- return setError();
- }
-
- // https://issues.dlang.org/show_bug.cgi?id=18719
- // If `exp` is a call expression to another constructor
- // then it means that all struct/class fields will be
- // initialized after this call.
- for (size_t i = 0; i < sc->fieldinit_dim; i++)
- sc->fieldinit[i] |= CSXthis_ctor;
-
- if (!sc->intypeof && !(sc->callSuper & CSXhalt))
- {
- if (sc->noctor || sc->callSuper & CSXlabel)
- exp->error("constructor calls not allowed in loops or after labels");
- if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor))
- exp->error("multiple constructor calls");
- if ((sc->callSuper & CSXreturn) && !(sc->callSuper & CSXany_ctor))
- exp->error("an earlier return statement skips constructor");
- sc->callSuper |= CSXany_ctor | CSXthis_ctor;
- }
-
- tthis = ad->type->addMod(sc->func->type->mod);
- if (OverloadSet *os = ad->ctor->isOverloadSet())
- exp->f = resolveOverloadSet(exp->loc, sc, os, NULL, tthis, exp->arguments);
- else
- exp->f = resolveFuncCall(exp->loc, sc, ad->ctor, NULL, tthis, exp->arguments, 0);
- if (!exp->f || exp->f->errors)
- return setError();
- exp->checkDeprecated(sc, exp->f);
- exp->checkDisabled(sc, exp->f);
- exp->checkPurity(sc, exp->f);
- exp->checkSafety(sc, exp->f);
- exp->checkNogc(sc, exp->f);
- //checkAccess(exp->loc, sc, NULL, exp->f); // necessary?
-
- exp->e1 = new DotVarExp(exp->e1->loc, exp->e1, exp->f, false);
- exp->e1 = expressionSemantic(exp->e1, sc);
- t1 = exp->e1->type;
-
- // BUG: this should really be done by checking the static
- // call graph
- if (exp->f == sc->func)
- {
- exp->error("cyclic constructor call");
- return setError();
- }
- }
- else if (exp->e1->op == TOKoverloadset)
- {
- OverloadSet *os = ((OverExp *)exp->e1)->vars;
- exp->f = resolveOverloadSet(exp->loc, sc, os, tiargs, tthis, exp->arguments);
- if (!exp->f)
- return setError();
- if (ethis)
- exp->e1 = new DotVarExp(exp->loc, ethis, exp->f, false);
- else
- exp->e1 = new VarExp(exp->loc, exp->f, false);
- goto Lagain;
- }
- else if (!t1)
- {
- exp->error("function expected before (), not `%s`", exp->e1->toChars());
- return setError();
- }
- else if (t1->ty == Terror)
- {
- return setError();
- }
- else if (t1->ty != Tfunction)
- {
- TypeFunction *tf;
- const char *p;
- Dsymbol *s;
- exp->f = NULL;
- if (exp->e1->op == TOKfunction)
- {
- // function literal that direct called is always inferred.
- assert(((FuncExp *)exp->e1)->fd);
- exp->f = ((FuncExp *)exp->e1)->fd;
- tf = (TypeFunction *)exp->f->type;
- p = "function literal";
- }
- else if (t1->ty == Tdelegate)
- {
- TypeDelegate *td = (TypeDelegate *)t1;
- assert(td->next->ty == Tfunction);
- tf = (TypeFunction *)(td->next);
- p = "delegate";
- }
- else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction)
- {
- tf = (TypeFunction *)(((TypePointer *)t1)->next);
- p = "function pointer";
- }
- else if (exp->e1->op == TOKdotvar &&
- ((DotVarExp *)exp->e1)->var->isOverDeclaration())
- {
- DotVarExp *dve = (DotVarExp *)exp->e1;
- exp->f = resolveFuncCall(exp->loc, sc, dve->var, tiargs, dve->e1->type, exp->arguments, 2);
- if (!exp->f)
- return setError();
- if (exp->f->needThis())
- {
- dve->var = exp->f;
- dve->type = exp->f->type;
- dve->hasOverloads = false;
- goto Lagain;
- }
- exp->e1 = new VarExp(dve->loc, exp->f, false);
- Expression *e = new CommaExp(exp->loc, dve->e1, exp);
- result = expressionSemantic(e, sc);
- return;
- }
- else if (exp->e1->op == TOKvar &&
- ((VarExp *)exp->e1)->var->isOverDeclaration())
- {
- s = ((VarExp *)exp->e1)->var;
- goto L2;
- }
- else if (exp->e1->op == TOKtemplate)
- {
- s = ((TemplateExp *)exp->e1)->td;
- L2:
- exp->f = resolveFuncCall(exp->loc, sc, s, tiargs, NULL, exp->arguments);
- if (!exp->f || exp->f->errors)
- return setError();
- if (exp->f->needThis())
- {
- if (hasThis(sc))
- {
- // Supply an implicit 'this', as in
- // this.ident
- Expression *ex = new ThisExp(exp->loc);
- ex = expressionSemantic(ex, sc);
- exp->e1 = new DotVarExp(exp->loc, ex, exp->f, false);
- goto Lagain;
- }
- else if (isNeedThisScope(sc, exp->f))
- {
- exp->error("need `this` for `%s` of type `%s`", exp->f->toChars(), exp->f->type->toChars());
- return setError();
- }
- }
- exp->e1 = new VarExp(exp->e1->loc, exp->f, false);
- goto Lagain;
- }
- else
- {
- exp->error("function expected before (), not %s of type %s", exp->e1->toChars(), exp->e1->type->toChars());
- return setError();
- }
-
- const char *failMessage = NULL;
- if (!tf->callMatch(NULL, exp->arguments, 0, &failMessage))
- {
- OutBuffer buf;
-
- buf.writeByte('(');
- argExpTypesToCBuffer(&buf, exp->arguments);
- buf.writeByte(')');
- if (tthis)
- tthis->modToBuffer(&buf);
-
- //printf("tf = %s, args = %s\n", tf->deco, (*exp->arguments)[0]->type->deco);
- ::error(exp->loc, "%s `%s%s` is not callable using argument types `%s`",
- p, exp->e1->toChars(), parametersTypeToChars(tf->parameterList),
- buf.peekChars());
- if (failMessage)
- errorSupplemental(exp->loc, failMessage);
- return setError();
- }
-
- // Purity and safety check should run after testing arguments matching
- if (exp->f)
- {
- exp->checkPurity(sc, exp->f);
- exp->checkSafety(sc, exp->f);
- exp->checkNogc(sc, exp->f);
- if (exp->f->checkNestedReference(sc, exp->loc))
- return setError();
- }
- else if (sc->func && sc->intypeof != 1 && !(sc->flags & SCOPEctfe))
- {
- bool err = false;
- if (!tf->purity && !(sc->flags & SCOPEdebug) && sc->func->setImpure())
- {
- exp->error("pure %s `%s` cannot call impure %s `%s`",
- sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
- err = true;
- }
- if (!tf->isnogc && sc->func->setGC())
- {
- exp->error("@nogc %s `%s` cannot call non-@nogc %s `%s`",
- sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
- err = true;
- }
- if (tf->trust <= TRUSTsystem && sc->func->setUnsafe())
- {
- exp->error("@safe %s `%s` cannot call @system %s `%s`",
- sc->func->kind(), sc->func->toPrettyChars(), p, exp->e1->toChars());
- err = true;
- }
- if (err)
- return setError();
- }
-
- if (t1->ty == Tpointer)
- {
- Expression *e = new PtrExp(exp->loc, exp->e1);
- e->type = tf;
- exp->e1 = e;
- }
- t1 = tf;
- }
- else if (exp->e1->op == TOKvar)
- {
- // Do overload resolution
- VarExp *ve = (VarExp *)exp->e1;
-
- exp->f = ve->var->isFuncDeclaration();
- assert(exp->f);
- tiargs = NULL;
-
- if (exp->f->overnext)
- exp->f = resolveFuncCall(exp->loc, sc, exp->f, tiargs, NULL, exp->arguments, 2);
- else
- {
- exp->f = exp->f->toAliasFunc();
- TypeFunction *tf = (TypeFunction *)exp->f->type;
- const char *failMessage = NULL;
- if (!tf->callMatch(NULL, exp->arguments, 0, &failMessage))
- {
- OutBuffer buf;
-
- buf.writeByte('(');
- argExpTypesToCBuffer(&buf, exp->arguments);
- buf.writeByte(')');
-
- //printf("tf = %s, args = %s\n", tf->deco, (*exp->arguments)[0]->type->deco);
- ::error(exp->loc, "%s `%s%s` is not callable using argument types `%s`",
- exp->f->kind(), exp->e1->toChars(), parametersTypeToChars(tf->parameterList),
- buf.peekChars());
- if (failMessage)
- errorSupplemental(exp->loc, failMessage);
- exp->f = NULL;
- }
- }
- if (!exp->f || exp->f->errors)
- return setError();
-
- if (exp->f->needThis())
- {
- // Change the ancestor lambdas to delegate before hasThis(sc) call.
- if (exp->f->checkNestedReference(sc, exp->loc))
- return setError();
-
- if (hasThis(sc))
- {
- // Supply an implicit 'this', as in
- // this.ident
-
- Expression *ex = new ThisExp(exp->loc);
- ex = expressionSemantic(ex, sc);
- exp->e1 = new DotVarExp(exp->loc, ex, ve->var);
- // Note: we cannot use f directly, because further overload resolution
- // through the supplied 'this' may cause different result.
- goto Lagain;
- }
- else if (isNeedThisScope(sc, exp->f))
- {
- exp->error("need `this` for `%s` of type `%s`", exp->f->toChars(), exp->f->type->toChars());
- return setError();
- }
- }
-
- exp->checkDeprecated(sc, exp->f);
- exp->checkDisabled(sc, exp->f);
- exp->checkPurity(sc, exp->f);
- exp->checkSafety(sc, exp->f);
- exp->checkNogc(sc, exp->f);
- checkAccess(exp->loc, sc, NULL, exp->f);
- if (exp->f->checkNestedReference(sc, exp->loc))
- return setError();
-
- ethis = NULL;
- tthis = NULL;
-
- if (ve->hasOverloads)
- {
- exp->e1 = new VarExp(ve->loc, exp->f, false);
- exp->e1->type = exp->f->type;
- }
- t1 = exp->f->type;
- }
- assert(t1->ty == Tfunction);
-
- Expression *argprefix;
- if (!exp->arguments)
- exp->arguments = new Expressions();
- if (functionParameters(exp->loc, sc, (TypeFunction *)(t1), tthis, exp->arguments, exp->f, &exp->type, &argprefix))
- return setError();
-
- if (!exp->type)
- {
- exp->e1 = e1org; // Bugzilla 10922, avoid recursive expression printing
- exp->error("forward reference to inferred return type of function call `%s`", exp->toChars());
- return setError();
- }
-
- if (exp->f && exp->f->tintro)
- {
- Type *t = exp->type;
- int offset = 0;
- TypeFunction *tf = (TypeFunction *)exp->f->tintro;
-
- if (tf->next->isBaseOf(t, &offset) && offset)
- {
- exp->type = tf->next;
- result = Expression::combine(argprefix, exp->castTo(sc, t));
- return;
- }
- }
-
- // Handle the case of a direct lambda call
- if (exp->f && exp->f->isFuncLiteralDeclaration() &&
- sc->func && !sc->intypeof)
- {
- exp->f->tookAddressOf = 0;
- }
-
- result = Expression::combine(argprefix, exp);
- }
-
- void visit(AddrExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = unaSemantic(exp, sc))
- {
- result = ex;
- return;
- }
- int wasCond = exp->e1->op == TOKquestion;
- if (exp->e1->op == TOKdotti)
- {
- DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)exp->e1;
- TemplateInstance *ti = dti->ti;
- {
- //assert(ti->needsTypeInference(sc));
- dsymbolSemantic(ti, sc);
- if (!ti->inst || ti->errors) // if template failed to expand
- return setError();
- Dsymbol *s = ti->toAlias();
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f)
- {
- exp->e1 = new DotVarExp(exp->e1->loc, dti->e1, f);
- exp->e1 = expressionSemantic(exp->e1, sc);
- }
- }
- }
- else if (exp->e1->op == TOKscope)
- {
- TemplateInstance *ti = ((ScopeExp *)exp->e1)->sds->isTemplateInstance();
- if (ti)
- {
- //assert(ti->needsTypeInference(sc));
- dsymbolSemantic(ti, sc);
- if (!ti->inst || ti->errors) // if template failed to expand
- return setError();
- Dsymbol *s = ti->toAlias();
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f)
- {
- exp->e1 = new VarExp(exp->e1->loc, f);
- exp->e1 = expressionSemantic(exp->e1, sc);
- }
- }
- }
- exp->e1 = exp->e1->toLvalue(sc, NULL);
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- if (checkNonAssignmentArrayOp(exp->e1))
- return setError();
-
- if (!exp->e1->type)
- {
- exp->error("cannot take address of %s", exp->e1->toChars());
- return setError();
- }
-
- bool hasOverloads = false;
- if (FuncDeclaration *f = isFuncAddress(exp, &hasOverloads))
- {
- if (!hasOverloads && f->checkForwardRef(exp->loc))
- return setError();
- }
- else if (!exp->e1->type->deco)
- {
- if (exp->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)exp->e1;
- Declaration *d = ve->var;
- exp->error("forward reference to %s %s", d->kind(), d->toChars());
- }
- else
- exp->error("forward reference to %s", exp->e1->toChars());
- return setError();
- }
-
- exp->type = exp->e1->type->pointerTo();
-
- // See if this should really be a delegate
- if (exp->e1->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp *)exp->e1;
- FuncDeclaration *f = dve->var->isFuncDeclaration();
- if (f)
- {
- f = f->toAliasFunc(); // FIXME, should see overloads - Bugzilla 1983
- if (!dve->hasOverloads)
- f->tookAddressOf++;
-
- Expression *e;
- if (f->needThis())
- e = new DelegateExp(exp->loc, dve->e1, f, dve->hasOverloads);
- else // It is a function pointer. Convert &v.f() --> (v, &V.f())
- e = new CommaExp(exp->loc, dve->e1, new AddrExp(exp->loc, new VarExp(exp->loc, f, dve->hasOverloads)));
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- // Look for misaligned pointer in @safe mode
- if (checkUnsafeAccess(sc, dve, !exp->type->isMutable(), true))
- return setError();
-
- if (dve->e1->op == TOKvar && global.params.vsafe)
- {
- VarExp *ve = (VarExp *)dve->e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v)
- {
- if (!checkAddressVar(sc, exp, v))
- return setError();
- }
- }
- else if ((dve->e1->op == TOKthis || dve->e1->op == TOKsuper) && global.params.vsafe)
- {
- ThisExp *ve = (ThisExp *)dve->e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v && v->storage_class & STCref)
- {
- if (!checkAddressVar(sc, exp, v))
- return setError();
- }
- }
- }
- else if (exp->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)exp->e1;
-
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v)
- {
- if (!checkAddressVar(sc, exp, v))
- return setError();
-
- ve->checkPurity(sc, v);
- }
-
- FuncDeclaration *f = ve->var->isFuncDeclaration();
- if (f)
- {
- /* Because nested functions cannot be overloaded,
- * mark here that we took its address because castTo()
- * may not be called with an exact match.
- */
- if (!ve->hasOverloads || f->isNested())
- f->tookAddressOf++;
- if (f->isNested())
- {
- if (f->isFuncLiteralDeclaration())
- {
- if (!f->FuncDeclaration::isNested())
- {
- /* Supply a 'null' for a this pointer if no this is available
- */
- Expression *e = new DelegateExp(exp->loc, new NullExp(exp->loc, Type::tnull), f, ve->hasOverloads);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- }
- Expression *e = new DelegateExp(exp->loc, exp->e1, f, ve->hasOverloads);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- if (f->needThis())
- {
- if (hasThis(sc))
- {
- /* Should probably supply 'this' after overload resolution,
- * not before.
- */
- Expression *ethis = new ThisExp(exp->loc);
- Expression *e = new DelegateExp(exp->loc, ethis, f, ve->hasOverloads);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- if (sc->func && !sc->intypeof)
- {
- if (sc->func->setUnsafe())
- {
- exp->error("`this` reference necessary to take address of member %s in @safe function %s",
- f->toChars(), sc->func->toChars());
- }
- }
- }
- }
- }
- else if ((exp->e1->op == TOKthis || exp->e1->op == TOKsuper) && global.params.vsafe)
- {
- ThisExp *ve = (ThisExp *)exp->e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v)
- {
- if (!checkAddressVar(sc, exp, v))
- return setError();
- }
- }
- else if (exp->e1->op == TOKcall)
- {
- CallExp *ce = (CallExp *)exp->e1;
- if (ce->e1->type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)ce->e1->type;
- if (tf->isref && sc->func && !sc->intypeof && sc->func->setUnsafe())
- {
- exp->error("cannot take address of ref return of %s() in @safe function %s",
- ce->e1->toChars(), sc->func->toChars());
- }
- }
- }
- else if (exp->e1->op == TOKindex)
- {
- /* For:
- * int[3] a;
- * &a[i]
- * check 'a' the same as for a regular variable
- */
- IndexExp *ei = (IndexExp *)exp->e1;
- Type *tyi = ei->e1->type->toBasetype();
- if (tyi->ty == Tsarray && ei->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)ei->e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (v)
- {
- if (!checkAddressVar(sc, exp, v))
- return setError();
-
- ve->checkPurity(sc, v);
- }
- }
- }
- else if (wasCond)
- {
- /* a ? b : c was transformed to *(a ? &b : &c), but we still
- * need to do safety checks
- */
- assert(exp->e1->op == TOKstar);
- PtrExp *pe = (PtrExp *)exp->e1;
- assert(pe->e1->op == TOKquestion);
- CondExp *ce = (CondExp *)pe->e1;
- assert(ce->e1->op == TOKaddress);
- assert(ce->e2->op == TOKaddress);
-
- // Re-run semantic on the address expressions only
- ce->e1->type = NULL;
- ce->e1 = expressionSemantic(ce->e1, sc);
- ce->e2->type = NULL;
- ce->e2 = expressionSemantic(ce->e2, sc);
- }
-
- result = exp->optimize(WANTvalue);
- }
-
- void visit(PtrExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- Type *tb = exp->e1->type->toBasetype();
- switch (tb->ty)
- {
- case Tpointer:
- exp->type = ((TypePointer *)tb)->next;
- break;
-
- case Tsarray:
- case Tarray:
- exp->error("using * on an array is no longer supported; use *(%s).ptr instead", exp->e1->toChars());
- exp->type = ((TypeArray *)tb)->next;
- exp->e1 = exp->e1->castTo(sc, exp->type->pointerTo());
- break;
-
- case Tnull:
- exp->type = Type::tnoreturn; // typeof(*null) is bottom type
- break;
-
- default:
- exp->error("can only * a pointer, not a `%s`", exp->e1->type->toChars());
- /* fall through */
-
- case Terror:
- return setError();
- }
- if (exp->checkValue())
- return setError();
-
- result = exp;
- }
-
- void visit(NegExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- exp->type = exp->e1->type;
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp->e1))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (!target.isVectorOpSupported(tb, exp->op))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if (exp->e1->checkNoBool())
- return setError();
- if (exp->e1->checkArithmetic())
- return setError();
-
- result = exp;
- }
-
- void visit(UAddExp *exp)
- {
- assert(!exp->type);
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (!target.isVectorOpSupported(exp->e1->type->toBasetype(), exp->op))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if (exp->e1->checkNoBool())
- return setError();
- if (exp->e1->checkArithmetic())
- return setError();
-
- result = exp->e1;
- }
-
- void visit(ComExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- exp->type = exp->e1->type;
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp->e1))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (!target.isVectorOpSupported(tb, exp->op))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if (exp->e1->checkNoBool())
- return setError();
- if (exp->e1->checkIntegral())
- return setError();
-
- result = exp;
- }
-
- void visit(NotExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- setNoderefOperand(e);
-
- // Note there is no operator overload
- if (Expression *ex = unaSemantic(e, sc))
- {
- result = ex;
- return;
- }
-
- // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (e->e1->op == TOKtype)
- e->e1 = resolveAliasThis(sc, e->e1);
-
- e->e1 = resolveProperties(sc, e->e1);
- e->e1 = e->e1->toBoolean(sc);
- if (e->e1->type == Type::terror)
- {
- result = e->e1;
- return;
- }
-
- if (!target.isVectorOpSupported(e->e1->type->toBasetype(), e->op))
- {
- result = e->incompatibleTypes();
- return;
- }
- // Bugzilla 13910: Today NotExp can take an array as its operand.
- if (checkNonAssignmentArrayOp(e->e1))
- return setError();
-
- e->type = Type::tbool;
- result = e;
- }
-
- void visit(DeleteExp *exp)
- {
- if (Expression *ex = unaSemantic(exp, sc))
- {
- result = ex;
- return;
- }
- exp->e1 = resolveProperties(sc, exp->e1);
- exp->e1 = exp->e1->modifiableLvalue(sc, NULL);
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- exp->type = Type::tvoid;
-
- AggregateDeclaration *ad = NULL;
- Type *tb = exp->e1->type->toBasetype();
- switch (tb->ty)
- { case Tclass:
- {
- ClassDeclaration *cd = ((TypeClass *)tb)->sym;
-
- if (cd->isCOMinterface())
- { /* Because COM classes are deleted by IUnknown.Release()
- */
- exp->error("cannot delete instance of COM interface %s", cd->toChars());
- return setError();
- }
-
- ad = cd;
- break;
- }
- case Tpointer:
- tb = ((TypePointer *)tb)->next->toBasetype();
- if (tb->ty == Tstruct)
- {
- ad = ((TypeStruct *)tb)->sym;
- FuncDeclaration *f = ad->aggDelete;
- FuncDeclaration *fd = ad->dtor;
-
- if (!f)
- {
- semanticTypeInfo(sc, tb);
- break;
- }
-
- /* Construct:
- * ea = copy e1 to a tmp to do side effects only once
- * eb = call destructor
- * ec = call deallocator
- */
- Expression *ea = NULL;
- Expression *eb = NULL;
- Expression *ec = NULL;
- VarDeclaration *v = NULL;
-
- if (fd && f)
- {
- v = copyToTemp(0, "__tmpea", exp->e1);
- dsymbolSemantic(v, sc);
- ea = new DeclarationExp(exp->loc, v);
- ea->type = v->type;
- }
-
- if (fd)
- {
- Expression *e = ea ? new VarExp(exp->loc, v) : exp->e1;
- e = new DotVarExp(Loc(), e, fd, false);
- eb = new CallExp(exp->loc, e);
- eb = expressionSemantic(eb, sc);
- }
-
- if (f)
- {
- Type *tpv = Type::tvoid->pointerTo();
- Expression *e = ea ? new VarExp(exp->loc, v) : exp->e1->castTo(sc, tpv);
- e = new CallExp(exp->loc, new VarExp(exp->loc, f, false), e);
- ec = expressionSemantic(e, sc);
- }
- ea = Expression::combine(ea, eb);
- ea = Expression::combine(ea, ec);
- assert(ea);
- result = ea;
- return;
- }
- break;
-
- case Tarray:
- {
- Type *tv = tb->nextOf()->baseElemOf();
- if (tv->ty == Tstruct)
- {
- ad = ((TypeStruct *)tv)->sym;
- if (ad->dtor)
- semanticTypeInfo(sc, ad->type);
- }
- break;
- }
- default:
- exp->error("cannot delete type %s", exp->e1->type->toChars());
- return setError();
- }
-
- bool err = false;
- if (ad)
- {
- if (ad->dtor)
- {
- err |= exp->checkPurity(sc, ad->dtor);
- err |= exp->checkSafety(sc, ad->dtor);
- err |= exp->checkNogc(sc, ad->dtor);
- }
- if (ad->aggDelete && tb->ty != Tarray)
- {
- err |= exp->checkPurity(sc, ad->aggDelete);
- err |= exp->checkSafety(sc, ad->aggDelete);
- err |= exp->checkNogc(sc, ad->aggDelete);
- }
- if (err)
- return setError();
- }
-
- if (!sc->intypeof && sc->func &&
- !exp->isRAII &&
- sc->func->setUnsafe())
- {
- exp->error("%s is not @safe but is used in @safe function %s", exp->toChars(), sc->func->toChars());
- err = true;
- }
- if (err)
- return setError();
-
- result = exp;
- }
-
- void visit(CastExp *exp)
- {
- //static int x; assert(++x < 10);
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (exp->to)
- {
- exp->to = typeSemantic(exp->to, exp->loc, sc);
- if (exp->to == Type::terror)
- return setError();
-
- if (!exp->to->hasPointers())
- setNoderefOperand(exp);
-
- // When e1 is a template lambda, this cast may instantiate it with
- // the type 'to'.
- exp->e1 = inferType(exp->e1, exp->to);
- }
-
- if (Expression *ex = unaSemantic(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e1x = resolveProperties(sc, exp->e1);
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- if (e1x->checkType())
- return setError();
- exp->e1 = e1x;
-
- if (!exp->e1->type)
- {
- exp->error("cannot cast %s", exp->e1->toChars());
- return setError();
- }
-
- if (!exp->to) // Handle cast(const) and cast(immutable), etc.
- {
- exp->to = exp->e1->type->castMod(exp->mod);
- exp->to = typeSemantic(exp->to, exp->loc, sc);
- if (exp->to == Type::terror)
- return setError();
- }
-
- if (exp->to->ty == Ttuple)
- {
- exp->error("cannot cast %s to tuple type %s", exp->e1->toChars(), exp->to->toChars());
- return setError();
- }
- if (exp->e1->type->ty != Tvoid ||
- (exp->e1->op == TOKfunction && exp->to->ty == Tvoid) ||
- exp->e1->op == TOKtype ||
- exp->e1->op == TOKtemplate)
- {
- if (exp->e1->checkValue())
- return setError();
- }
-
- // cast(void) is used to mark e1 as unused, so it is safe
- if (exp->to->ty == Tvoid)
- {
- exp->type = exp->to;
- result = exp;
- return;
- }
-
- if (!exp->to->equals(exp->e1->type) && exp->mod == (unsigned char)~0)
- {
- if (Expression *e = exp->op_overload(sc))
- {
- result = e->implicitCastTo(sc, exp->to);
- return;
- }
- }
-
- Type *t1b = exp->e1->type->toBasetype();
- Type *tob = exp->to->toBasetype();
-
- if (tob->ty == Tstruct && !tob->equals(t1b))
- {
- /* Look to replace:
- * cast(S)t
- * with:
- * S(t)
- */
-
- // Rewrite as to.call(e1)
- Expression *e = new TypeExp(exp->loc, exp->to);
- e = new CallExp(exp->loc, e, exp->e1);
- e = trySemantic(e, sc);
- if (e)
- {
- result = e;
- return;
- }
- }
-
- if (!t1b->equals(tob) && (t1b->ty == Tarray || t1b->ty == Tsarray))
- {
- if (checkNonAssignmentArrayOp(exp->e1))
- return setError();
- }
-
- // Look for casting to a vector type
- if (tob->ty == Tvector && t1b->ty != Tvector)
- {
- result = new VectorExp(exp->loc, exp->e1, exp->to);
- return;
- }
-
- Expression *ex = exp->e1->castTo(sc, exp->to);
- if (ex->op == TOKerror)
- {
- result = ex;
- return;
- }
-
- // Check for unsafe casts
- if (sc->func && !sc->intypeof &&
- !isSafeCast(ex, t1b, tob) &&
- sc->func->setUnsafe())
- {
- exp->error("cast from %s to %s not allowed in safe code", exp->e1->type->toChars(), exp->to->toChars());
- return setError();
- }
-
- result = ex;
- }
-
- void visit(VectorExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- exp->e1 = expressionSemantic(exp->e1, sc);
- exp->type = typeSemantic(exp->to, exp->loc, sc);
- if (exp->e1->op == TOKerror || exp->type->ty == Terror)
- {
- result = exp->e1;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- assert(tb->ty == Tvector);
- TypeVector *tv = (TypeVector *)tb;
- Type *te = tv->elementType();
- exp->dim = (int)(tv->size(exp->loc) / te->size(exp->loc));
-
- exp->e1 = exp->e1->optimize(WANTvalue);
- bool res = false;
- if (exp->e1->op == TOKarrayliteral)
- {
- for (size_t i = 0; i < exp->dim; i++)
- {
- // Do not stop on first error - check all AST nodes even if error found
- res |= checkVectorElem(exp, ((ArrayLiteralExp *)exp->e1)->getElement(i));
- }
- }
- else if (exp->e1->type->ty == Tvoid)
- res = checkVectorElem(exp, exp->e1);
-
- Expression *e = exp;
- if (res)
- e = new ErrorExp();
- result = e;
- }
-
- void visit(VectorArrayExp *e)
- {
- if (!e->type)
- {
- unaSemantic(e, sc);
- e->e1 = resolveProperties(sc, e->e1);
-
- if (e->e1->op == TOKerror)
- {
- result = e->e1;
- return;
- }
- assert(e->e1->type->ty == Tvector);
- TypeVector *tv = (TypeVector *)e->e1->type;
- e->type = tv->basetype;
- }
- result = e;
- }
-
- void visit(SliceExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- // operator overloading should be handled in ArrayExp already.
-
- if (Expression *ex = unaSemantic(exp, sc))
- {
- result = ex;
- return;
- }
- exp->e1 = resolveProperties(sc, exp->e1);
- if (exp->e1->op == TOKtype && exp->e1->type->ty != Ttuple)
- {
- if (exp->lwr || exp->upr)
- {
- exp->error("cannot slice type `%s`", exp->e1->toChars());
- return setError();
- }
- Expression *e = new TypeExp(exp->loc, exp->e1->type->arrayOf());
- result = expressionSemantic(e, sc);
- return;
- }
- if (!exp->lwr && !exp->upr)
- {
- if (exp->e1->op == TOKarrayliteral)
- {
- // Convert [a,b,c][] to [a,b,c]
- Type *t1b = exp->e1->type->toBasetype();
- Expression *e = exp->e1;
- if (t1b->ty == Tsarray)
- {
- e = e->copy();
- e->type = t1b->nextOf()->arrayOf();
- }
- result = e;
- return;
- }
- if (exp->e1->op == TOKslice)
- {
- // Convert e[][] to e[]
- SliceExp *se = (SliceExp *)exp->e1;
- if (!se->lwr && !se->upr)
- {
- result = se;
- return;
- }
- }
- if (isArrayOpOperand(exp->e1))
- {
- // Convert (a[]+b[])[] to a[]+b[]
- result = exp->e1;
- return;
- }
- }
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- if (exp->e1->type->ty == Terror)
- return setError();
-
- Type *t1b = exp->e1->type->toBasetype();
- if (t1b->ty == Tpointer)
- {
- if (((TypePointer *)t1b)->next->ty == Tfunction)
- {
- exp->error("cannot slice function pointer %s", exp->e1->toChars());
- return setError();
- }
- if (!exp->lwr || !exp->upr)
- {
- exp->error("need upper and lower bound to slice pointer");
- return setError();
- }
- if (sc->func && !sc->intypeof && sc->func->setUnsafe())
- {
- exp->error("pointer slicing not allowed in safe functions");
- return setError();
- }
- }
- else if (t1b->ty == Tarray)
- {
- }
- else if (t1b->ty == Tsarray)
- {
- if (!exp->arrayop && global.params.vsafe)
- {
- /* Slicing a static array is like taking the address of it.
- * Perform checks as if e[] was &e
- */
- VarDeclaration *v = NULL;
- if (exp->e1->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp *)exp->e1;
- if (dve->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)dve->e1;
- v = ve->var->isVarDeclaration();
- }
- else if (dve->e1->op == TOKthis || dve->e1->op == TOKsuper)
- {
- ThisExp *ve = (ThisExp *)dve->e1;
- v = ve->var->isVarDeclaration();
- if (v && !(v->storage_class & STCref))
- v = NULL;
- }
- }
- else if (exp->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)exp->e1;
- v = ve->var->isVarDeclaration();
- }
- else if (exp->e1->op == TOKthis || exp->e1->op == TOKsuper)
- {
- ThisExp *ve = (ThisExp *)exp->e1;
- v = ve->var->isVarDeclaration();
- }
-
- if (v)
- {
- if (!checkAddressVar(sc, exp, v))
- return setError();
- }
- }
- }
- else if (t1b->ty == Ttuple)
- {
- if (!exp->lwr && !exp->upr)
- {
- result = exp->e1;
- return;
- }
- if (!exp->lwr || !exp->upr)
- {
- exp->error("need upper and lower bound to slice tuple");
- return setError();
- }
- }
- else if (t1b->ty == Tvector)
- {
- // Convert e1 to corresponding static array
- TypeVector *tv1 = (TypeVector *)t1b;
- t1b = tv1->basetype;
- t1b = t1b->castMod(tv1->mod);
- exp->e1->type = t1b;
- }
- else
- {
- exp->error("%s cannot be sliced with []",
- t1b->ty == Tvoid ? exp->e1->toChars() : t1b->toChars());
- return setError();
- }
-
- /* Run semantic on lwr and upr.
- */
- Scope *scx = sc;
- if (t1b->ty == Tsarray || t1b->ty == Tarray || t1b->ty == Ttuple)
- {
- // Create scope for 'length' variable
- ScopeDsymbol *sym = new ArrayScopeSymbol(sc, exp);
- sym->loc = exp->loc;
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
- }
- if (exp->lwr)
- {
- if (t1b->ty == Ttuple) sc = sc->startCTFE();
- exp->lwr = expressionSemantic(exp->lwr, sc);
- exp->lwr = resolveProperties(sc, exp->lwr);
- if (t1b->ty == Ttuple) sc = sc->endCTFE();
- exp->lwr = exp->lwr->implicitCastTo(sc, Type::tsize_t);
- }
- if (exp->upr)
- {
- if (t1b->ty == Ttuple) sc = sc->startCTFE();
- exp->upr = expressionSemantic(exp->upr, sc);
- exp->upr = resolveProperties(sc, exp->upr);
- if (t1b->ty == Ttuple) sc = sc->endCTFE();
- exp->upr = exp->upr->implicitCastTo(sc, Type::tsize_t);
- }
- if (sc != scx)
- sc = sc->pop();
- if ((exp->lwr && exp->lwr->type == Type::terror) ||
- (exp->upr && exp->upr->type == Type::terror))
- {
- return setError();
- }
-
- if (t1b->ty == Ttuple)
- {
- exp->lwr = exp->lwr->ctfeInterpret();
- exp->upr = exp->upr->ctfeInterpret();
- uinteger_t i1 = exp->lwr->toUInteger();
- uinteger_t i2 = exp->upr->toUInteger();
-
- TupleExp *te;
- TypeTuple *tup;
- size_t length;
- if (exp->e1->op == TOKtuple) // slicing an expression tuple
- {
- te = (TupleExp *)exp->e1;
- tup = NULL;
- length = te->exps->length;
- }
- else if (exp->e1->op == TOKtype) // slicing a type tuple
- {
- te = NULL;
- tup = (TypeTuple *)t1b;
- length = Parameter::dim(tup->arguments);
- }
- else
- assert(0);
-
- if (i2 < i1 || length < i2)
- {
- exp->error("string slice [%llu .. %llu] is out of bounds", i1, i2);
- return setError();
- }
-
- size_t j1 = (size_t) i1;
- size_t j2 = (size_t) i2;
- Expression *e;
- if (exp->e1->op == TOKtuple)
- {
- Expressions *exps = new Expressions;
- exps->setDim(j2 - j1);
- for (size_t i = 0; i < j2 - j1; i++)
- {
- (*exps)[i] = (*te->exps)[j1 + i];
- }
- e = new TupleExp(exp->loc, te->e0, exps);
- }
- else
- {
- Parameters *args = new Parameters;
- args->reserve(j2 - j1);
- for (size_t i = j1; i < j2; i++)
- {
- Parameter *arg = Parameter::getNth(tup->arguments, i);
- args->push(arg);
- }
- e = new TypeExp(exp->e1->loc, new TypeTuple(args));
- }
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- exp->type = t1b->nextOf()->arrayOf();
- // Allow typedef[] -> typedef[]
- if (exp->type->equals(t1b))
- exp->type = exp->e1->type;
-
- if (exp->lwr && exp->upr)
- {
- exp->lwr = exp->lwr->optimize(WANTvalue);
- exp->upr = exp->upr->optimize(WANTvalue);
-
- IntRange lwrRange = getIntRange(exp->lwr);
- IntRange uprRange = getIntRange(exp->upr);
-
- if (t1b->ty == Tsarray || t1b->ty == Tarray)
- {
- Expression *el = new ArrayLengthExp(exp->loc, exp->e1);
- el = expressionSemantic(el, sc);
- el = el->optimize(WANTvalue);
- if (el->op == TOKint64)
- {
- dinteger_t length = el->toInteger();
- IntRange bounds(SignExtendedNumber(0), SignExtendedNumber(length));
- exp->upperIsInBounds = bounds.contains(uprRange);
- }
- }
- else if (t1b->ty == Tpointer)
- {
- exp->upperIsInBounds = true;
- }
- else
- assert(0);
-
- exp->lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
-
- //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", upperIsInBounds, lowerIsLessThanUpper);
- }
-
- result = exp;
- }
-
- void visit(ArrayLengthExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- if (Expression *ex = unaSemantic(e, sc))
- {
- result = ex;
- return;
- }
- e->e1 = resolveProperties(sc, e->e1);
-
- e->type = Type::tsize_t;
- result = e;
- }
-
- void visit(IntervalExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- Expression *le = e->lwr;
- le = expressionSemantic(le, sc);
- le = resolveProperties(sc, le);
-
- Expression *ue = e->upr;
- ue = expressionSemantic(ue, sc);
- ue = resolveProperties(sc, ue);
-
- if (le->op == TOKerror)
- {
- result = le;
- return;
- }
- if (ue->op == TOKerror)
- {
- result = ue;
- return;
- }
-
- e->lwr = le;
- e->upr = ue;
-
- e->type = Type::tvoid;
- result = e;
- }
-
- void visit(DelegatePtrExp *e)
- {
- if (!e->type)
- {
- unaSemantic(e, sc);
- e->e1 = resolveProperties(sc, e->e1);
-
- if (e->e1->op == TOKerror)
- {
- result = e->e1;
- return;
- }
- e->type = Type::tvoidptr;
- }
- result = e;
- }
-
- void visit(DelegateFuncptrExp *e)
- {
- if (!e->type)
- {
- unaSemantic(e, sc);
- e->e1 = resolveProperties(sc, e->e1);
-
- if (e->e1->op == TOKerror)
- {
- result = e->e1;
- return;
- }
- e->type = e->e1->type->nextOf()->pointerTo();
- }
- result = e;
- }
-
- void visit(ArrayExp *exp)
- {
- assert(!exp->type);
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (isAggregate(exp->e1->type))
- exp->error("no [] operator overload for type %s", exp->e1->type->toChars());
- else
- exp->error("only one index allowed to index %s", exp->e1->type->toChars());
- return setError();
- }
-
- void visit(DotExp *exp)
- {
- exp->e1 = expressionSemantic(exp->e1, sc);
- exp->e2 = expressionSemantic(exp->e2, sc);
-
- if (exp->e1->op == TOKtype)
- {
- result = exp->e2;
- return;
- }
- if (exp->e2->op == TOKtype)
- {
- result = exp->e2;
- return;
- }
- if (exp->e2->op == TOKtemplate)
- {
- TemplateDeclaration *td = ((TemplateExp *)exp->e2)->td;
- Expression *e = new DotTemplateExp(exp->loc, exp->e1, td);
- result = expressionSemantic(e, sc);
- return;
- }
- if (!exp->type)
- exp->type = exp->e2->type;
- result = exp;
- }
-
- void visit(CommaExp *e)
- {
- if (e->type)
- {
- result = e;
- return;
- }
-
- // Allow `((a,b),(x,y))`
- if (e->allowCommaExp)
- {
- if (e->e1 && e->e1->op == TOKcomma)
- ((CommaExp *)e->e1)->allowCommaExp = true;
- if (e->e2 && e->e2->op == TOKcomma)
- ((CommaExp *)e->e2)->allowCommaExp = true;
- }
-
- if (Expression *ex = binSemanticProp(e, sc))
- {
- result = ex;
- return;
- }
- e->e1 = e->e1->addDtorHook(sc);
-
- if (checkNonAssignmentArrayOp(e->e1))
- return setError();
-
- e->type = e->e2->type;
- if (e->type != Type::tvoid && !e->allowCommaExp && !e->isGenerated)
- e->deprecation("Using the result of a comma expression is deprecated");
- result = e;
- }
-
- void visit(IndexExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- // operator overloading should be handled in ArrayExp already.
-
- if (!exp->e1->type)
- exp->e1 = expressionSemantic(exp->e1, sc);
- assert(exp->e1->type); // semantic() should already be run on it
- if (exp->e1->op == TOKtype && exp->e1->type->ty != Ttuple)
- {
- exp->e2 = expressionSemantic(exp->e2, sc);
- exp->e2 = resolveProperties(sc, exp->e2);
- Type *nt;
- if (exp->e2->op == TOKtype)
- nt = new TypeAArray(exp->e1->type, exp->e2->type);
- else
- nt = new TypeSArray(exp->e1->type, exp->e2);
- Expression *e = new TypeExp(exp->loc, nt);
- result = expressionSemantic(e, sc);
- return;
- }
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- if (exp->e1->type->ty == Terror)
- return setError();
-
- // Note that unlike C we do not implement the int[ptr]
-
- Type *t1b = exp->e1->type->toBasetype();
-
- if (t1b->ty == Tvector)
- {
- // Convert e1 to corresponding static array
- TypeVector *tv1 = (TypeVector *)t1b;
- t1b = tv1->basetype;
- t1b = t1b->castMod(tv1->mod);
- exp->e1->type = t1b;
- }
-
- /* Run semantic on e2
- */
- Scope *scx = sc;
- if (t1b->ty == Tsarray || t1b->ty == Tarray || t1b->ty == Ttuple)
- {
- // Create scope for 'length' variable
- ScopeDsymbol *sym = new ArrayScopeSymbol(sc, exp);
- sym->loc = exp->loc;
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
- }
- if (t1b->ty == Ttuple) sc = sc->startCTFE();
- exp->e2 = expressionSemantic(exp->e2, sc);
- exp->e2 = resolveProperties(sc, exp->e2);
- if (t1b->ty == Ttuple) sc = sc->endCTFE();
- if (exp->e2->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)exp->e2;
- if (te->exps && te->exps->length == 1)
- exp->e2 = Expression::combine(te->e0, (*te->exps)[0]); // bug 4444 fix
- }
- if (sc != scx)
- sc = sc->pop();
- if (exp->e2->type == Type::terror)
- return setError();
-
- if (checkNonAssignmentArrayOp(exp->e1))
- return setError();
-
- switch (t1b->ty)
- {
- case Tpointer:
- if (((TypePointer *)t1b)->next->ty == Tfunction)
- {
- exp->error("cannot index function pointer %s", exp->e1->toChars());
- return setError();
- }
- exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
- if (exp->e2->type == Type::terror)
- return setError();
- exp->e2 = exp->e2->optimize(WANTvalue);
- if (exp->e2->op == TOKint64 && exp->e2->toInteger() == 0)
- ;
- else if (sc->func && sc->func->setUnsafe())
- {
- exp->error("safe function `%s` cannot index pointer `%s`",
- sc->func->toPrettyChars(), exp->e1->toChars());
- return setError();
- }
- exp->type = ((TypeNext *)t1b)->next;
- break;
-
- case Tarray:
- exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
- if (exp->e2->type == Type::terror)
- return setError();
- exp->type = ((TypeNext *)t1b)->next;
- break;
-
- case Tsarray:
- {
- exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
- if (exp->e2->type == Type::terror)
- return setError();
- exp->type = t1b->nextOf();
- break;
- }
-
- case Taarray:
- {
- TypeAArray *taa = (TypeAArray *)t1b;
- /* We can skip the implicit conversion if they differ only by
- * constness (Bugzilla 2684, see also bug 2954b)
- */
- if (!arrayTypeCompatibleWithoutCasting(exp->e2->type, taa->index))
- {
- exp->e2 = exp->e2->implicitCastTo(sc, taa->index); // type checking
- if (exp->e2->type == Type::terror)
- return setError();
- }
-
- semanticTypeInfo(sc, taa);
-
- exp->type = taa->next;
- break;
- }
-
- case Ttuple:
- {
- exp->e2 = exp->e2->implicitCastTo(sc, Type::tsize_t);
- if (exp->e2->type == Type::terror)
- return setError();
- exp->e2 = exp->e2->ctfeInterpret();
- uinteger_t index = exp->e2->toUInteger();
-
- TupleExp *te;
- TypeTuple *tup;
- size_t length;
- if (exp->e1->op == TOKtuple)
- {
- te = (TupleExp *)exp->e1;
- tup = NULL;
- length = te->exps->length;
- }
- else if (exp->e1->op == TOKtype)
- {
- te = NULL;
- tup = (TypeTuple *)t1b;
- length = Parameter::dim(tup->arguments);
- }
- else
- assert(0);
-
- if (length <= index)
- {
- exp->error("array index [%llu] is outside array bounds [0 .. %llu]",
- index, (ulonglong)length);
- return setError();
- }
-
- Expression *e;
- if (exp->e1->op == TOKtuple)
- {
- e = (*te->exps)[(size_t)index];
- e = Expression::combine(te->e0, e);
- }
- else
- e = new TypeExp(exp->e1->loc, Parameter::getNth(tup->arguments, (size_t)index)->type);
- result = e;
- return;
- }
-
- default:
- exp->error("%s must be an array or pointer type, not %s",
- exp->e1->toChars(), exp->e1->type->toChars());
- return setError();
- }
-
- if (t1b->ty == Tsarray || t1b->ty == Tarray)
- {
- Expression *el = new ArrayLengthExp(exp->loc, exp->e1);
- el = expressionSemantic(el, sc);
- el = el->optimize(WANTvalue);
- if (el->op == TOKint64)
- {
- exp->e2 = exp->e2->optimize(WANTvalue);
- dinteger_t length = el->toInteger();
- if (length)
- {
- IntRange bounds(SignExtendedNumber(0), SignExtendedNumber(length - 1));
- exp->indexIsInBounds = bounds.contains(getIntRange(exp->e2));
- }
- }
- }
-
- result = exp;
- }
-
- void visit(PostExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemantic(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e1x = resolveProperties(sc, exp->e1);
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- exp->e1 = e1x;
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->checkReadModifyWrite(exp->op))
- return setError();
- if (exp->e1->op == TOKslice)
- {
- const char *s = exp->op == TOKplusplus ? "increment" : "decrement";
- exp->error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp->e1->toChars(), s);
- return setError();
- }
-
- exp->e1 = exp->e1->optimize(WANTvalue);
-
- Type *t1 = exp->e1->type->toBasetype();
- if (t1->ty == Tclass || t1->ty == Tstruct || exp->e1->op == TOKarraylength)
- {
- /* Check for operator overloading,
- * but rewrite in terms of ++e instead of e++
- */
-
- /* If e1 is not trivial, take a reference to it
- */
- Expression *de = NULL;
- if (exp->e1->op != TOKvar && exp->e1->op != TOKarraylength)
- {
- // ref v = e1;
- VarDeclaration *v = copyToTemp(STCref, "__postref", exp->e1);
- de = new DeclarationExp(exp->loc, v);
- exp->e1 = new VarExp(exp->e1->loc, v);
- }
-
- /* Rewrite as:
- * auto tmp = e1; ++e1; tmp
- */
- VarDeclaration *tmp = copyToTemp(0, "__pitmp", exp->e1);
- Expression *ea = new DeclarationExp(exp->loc, tmp);
-
- Expression *eb = exp->e1->syntaxCopy();
- eb = new PreExp(exp->op == TOKplusplus ? TOKpreplusplus : TOKpreminusminus, exp->loc, eb);
-
- Expression *ec = new VarExp(exp->loc, tmp);
-
- // Combine de,ea,eb,ec
- if (de)
- ea = new CommaExp(exp->loc, de, ea);
- e = new CommaExp(exp->loc, ea, eb);
- e = new CommaExp(exp->loc, e, ec);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
-
- e = exp;
- if (exp->e1->checkScalar())
- return setError();
- if (exp->e1->checkNoBool())
- return setError();
-
- if (exp->e1->type->ty == Tpointer)
- e = scaleFactor(exp, sc);
- else
- exp->e2 = exp->e2->castTo(sc, exp->e1->type);
- e->type = exp->e1->type;
- result = e;
- }
-
- void visit(PreExp *exp)
- {
- Expression *e = exp->op_overload(sc);
- // printf("PreExp::semantic('%s')\n", exp->toChars());
-
- if (e)
- {
- result = e;
- return;
- }
-
- // Rewrite as e1+=1 or e1-=1
- if (exp->op == TOKpreplusplus)
- e = new AddAssignExp(exp->loc, exp->e1, new IntegerExp(exp->loc, 1, Type::tint32));
- else
- e = new MinAssignExp(exp->loc, exp->e1, new IntegerExp(exp->loc, 1, Type::tint32));
- result = expressionSemantic(e, sc);
- }
-
- void visit(AssignExp *exp)
- {
- //printf("e1->op = %d, '%s'\n", exp->e1->op, Token::toChars(exp->e1->op));
- //printf("e2->op = %d, '%s'\n", exp->e2->op, Token::toChars(exp->e2->op));
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- Expression *e1old = exp->e1;
-
- if (exp->e2->op == TOKcomma)
- {
- /* Rewrite to get rid of the comma from rvalue
- */
- if (!((CommaExp *)exp->e2)->isGenerated)
- exp->deprecation("Using the result of a comma expression is deprecated");
- Expression *e0;
- exp->e2 = Expression::extractLast(exp->e2, &e0);
- Expression *e = Expression::combine(e0, exp);
- result = expressionSemantic(e, sc);
- return;
- }
-
- /* Look for operator overloading of a[arguments] = e2.
- * Do it before e1->semantic() otherwise the ArrayExp will have been
- * converted to unary operator overloading already.
- */
- if (exp->e1->op == TOKarray)
- {
- Expression *res;
-
- ArrayExp *ae = (ArrayExp *)exp->e1;
- ae->e1 = expressionSemantic(ae->e1, sc);
- ae->e1 = resolveProperties(sc, ae->e1);
- Expression *ae1old = ae->e1;
-
- const bool maybeSlice =
- (ae->arguments->length == 0 ||
- (ae->arguments->length == 1 && (*ae->arguments)[0]->op == TOKinterval));
- IntervalExp *ie = NULL;
- if (maybeSlice && ae->arguments->length)
- {
- assert((*ae->arguments)[0]->op == TOKinterval);
- ie = (IntervalExp *)(*ae->arguments)[0];
- }
-
- while (true)
- {
- if (ae->e1->op == TOKerror)
- {
- result = ae->e1;
- return;
- }
- Expression *e0 = NULL;
- Expression *ae1save = ae->e1;
- ae->lengthVar = NULL;
-
- Type *t1b = ae->e1->type->toBasetype();
- AggregateDeclaration *ad = isAggregate(t1b);
- if (!ad)
- break;
- if (search_function(ad, Id::indexass))
- {
- // Deal with $
- res = resolveOpDollar(sc, ae, &e0);
- if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
- goto Lfallback;
- if (res->op == TOKerror)
- {
- result = res;
- return;
- }
-
- res = expressionSemantic(exp->e2, sc);
- if (res->op == TOKerror)
- {
- result = res;
- return;
- }
- exp->e2 = res;
-
- /* Rewrite (a[arguments] = e2) as:
- * a.opIndexAssign(e2, arguments)
- */
- Expressions *a = (Expressions *)ae->arguments->copy();
- a->insert(0, exp->e2);
- res = new DotIdExp(exp->loc, ae->e1, Id::indexass);
- res = new CallExp(exp->loc, res, a);
- if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
- res = trySemantic(res, sc);
- else
- res = expressionSemantic(res, sc);
- if (res)
- {
- res = Expression::combine(e0, res);
- result = res;
- return;
- }
- }
- Lfallback:
- if (maybeSlice && search_function(ad, Id::sliceass))
- {
- // Deal with $
- res = resolveOpDollar(sc, ae, ie, &e0);
- if (res->op == TOKerror)
- {
- result = res;
- return;
- }
-
- res = expressionSemantic(exp->e2, sc);
- if (res->op == TOKerror)
- {
- result = res;
- return;
- }
- exp->e2 = res;
-
- /* Rewrite (a[i..j] = e2) as:
- * a.opSliceAssign(e2, i, j)
- */
- Expressions *a = new Expressions();
- a->push(exp->e2);
- if (ie)
- {
- a->push(ie->lwr);
- a->push(ie->upr);
- }
- res = new DotIdExp(exp->loc, ae->e1, Id::sliceass);
- res = new CallExp(exp->loc, res, a);
- res = expressionSemantic(res, sc);
- res = Expression::combine(e0, res);
- result = res;
- return;
- }
-
- // No operator overloading member function found yet, but
- // there might be an alias this to try.
- if (ad->aliasthis && t1b != ae->att1)
- {
- if (!ae->att1 && t1b->checkAliasThisRec())
- ae->att1 = t1b;
-
- /* Rewrite (a[arguments] op e2) as:
- * a.aliasthis[arguments] op e2
- */
- ae->e1 = resolveAliasThis(sc, ae1save, true);
- if (ae->e1)
- continue;
- }
- break;
- }
- ae->e1 = ae1old; // recovery
- ae->lengthVar = NULL;
- }
-
- /* Run exp->e1 semantic.
- */
- {
- Expression *e1x = exp->e1;
-
- /* With UFCS, e.f = value
- * Could mean:
- * .f(e, value)
- * or:
- * .f(e) = value
- */
- if (e1x->op == TOKdotti)
- {
- DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)e1x;
- Expression *e = semanticY(dti, sc, 1);
- if (!e)
- {
- result = resolveUFCSProperties(sc, e1x, exp->e2);
- return;
- }
- e1x = e;
- }
- else if (e1x->op == TOKdotid)
- {
- DotIdExp *die = (DotIdExp *)e1x;
- Expression *e = semanticY(die, sc, 1);
- if (e && isDotOpDispatch(e))
- {
- unsigned errors = global.startGagging();
- e = resolvePropertiesX(sc, e, exp->e2);
- if (global.endGagging(errors))
- e = NULL; /* fall down to UFCS */
- else
- {
- result = e;
- return;
- }
- }
- if (!e)
- {
- result = resolveUFCSProperties(sc, e1x, exp->e2);
- return;
- }
- e1x = e;
- }
- else
- {
- if (e1x->op == TOKslice)
- ((SliceExp *)e1x)->arrayop = true;
-
- e1x = expressionSemantic(e1x, sc);
- }
-
- /* We have f = value.
- * Could mean:
- * f(value)
- * or:
- * f() = value
- */
- if (Expression *e = resolvePropertiesX(sc, e1x, exp->e2))
- {
- result = e;
- return;
- }
- if (e1x->checkRightThis(sc))
- return setError();
- exp->e1 = e1x;
- assert(exp->e1->type);
- }
- Type *t1 = exp->e1->type->toBasetype();
-
- /* Run exp->e2 semantic.
- * Different from other binary expressions, the analysis of e2
- * depends on the result of e1 in assignments.
- */
- {
- Expression *e2x = inferType(exp->e2, t1->baseElemOf());
-
- e2x = expressionSemantic(e2x, sc);
- e2x = resolveProperties(sc, e2x);
-
- if (e2x->op == TOKtype)
- e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
- if (e2x->checkValue())
- return setError();
- exp->e2 = e2x;
- }
-
- /* Rewrite tuple assignment as a tuple of assignments.
- */
- {
- Expression *e2x = exp->e2;
-
- Ltupleassign:
- if (exp->e1->op == TOKtuple && e2x->op == TOKtuple)
- {
- TupleExp *tup1 = (TupleExp *)exp->e1;
- TupleExp *tup2 = (TupleExp *)e2x;
- size_t dim = tup1->exps->length;
- Expression *e = NULL;
- if (dim != tup2->exps->length)
- {
- exp->error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->length);
- return setError();
- }
- if (dim == 0)
- {
- e = new IntegerExp(exp->loc, 0, Type::tint32);
- e = new CastExp(exp->loc, e, Type::tvoid); // avoid "has no effect" error
- e = Expression::combine(Expression::combine(tup1->e0, tup2->e0), e);
- }
- else
- {
- Expressions *exps = new Expressions;
- exps->setDim(dim);
- for (size_t i = 0; i < dim; i++)
- {
- Expression *ex1 = (*tup1->exps)[i];
- Expression *ex2 = (*tup2->exps)[i];
- (*exps)[i] = new AssignExp(exp->loc, ex1, ex2);
- }
- e = new TupleExp(exp->loc, Expression::combine(tup1->e0, tup2->e0), exps);
- }
- result = expressionSemantic(e, sc);
- return;
- }
-
- /* Look for form: e1 = e2->aliasthis.
- */
- if (exp->e1->op == TOKtuple)
- {
- TupleDeclaration *td = isAliasThisTuple(e2x);
- if (!td)
- goto Lnomatch;
-
- assert(exp->e1->type->ty == Ttuple);
- TypeTuple *tt = (TypeTuple *)exp->e1->type;
-
- Expression *e0 = NULL;
- Expression *ev = extractSideEffect(sc, "__tup", &e0, e2x);
-
- Expressions *iexps = new Expressions();
- iexps->push(ev);
-
- for (size_t u = 0; u < iexps->length ; u++)
- {
- Lexpand:
- Expression *e = (*iexps)[u];
-
- Parameter *arg = Parameter::getNth(tt->arguments, u);
- //printf("[%d] iexps->length = %d, ", u, iexps->length);
- //printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars());
- //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars());
-
- if (!arg || !e->type->implicitConvTo(arg->type))
- {
- // expand initializer to tuple
- if (expandAliasThisTuples(iexps, u) != -1)
- {
- if (iexps->length <= u)
- break;
- goto Lexpand;
- }
- goto Lnomatch;
- }
- }
- e2x = new TupleExp(e2x->loc, e0, iexps);
- e2x = expressionSemantic(e2x, sc);
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
- // Do not need to overwrite exp->e2
- goto Ltupleassign;
- }
- Lnomatch:
- ;
- }
-
- /* Inside constructor, if this is the first assignment of object field,
- * rewrite this to initializing the field.
- */
- if (exp->op == TOKassign && exp->e1->checkModifiable(sc) == 2)
- {
- //printf("[%s] change to init - %s\n", exp->loc.toChars(), toChars());
- exp->op = TOKconstruct;
-
- // Bugzilla 13515: set Index::modifiable flag for complex AA element initialization
- if (exp->e1->op == TOKindex)
- {
- Expression *e1x = ((IndexExp *)exp->e1)->markSettingAAElem();
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- }
- }
- else if (exp->op == TOKconstruct && exp->e1->op == TOKvar &&
- ((VarExp *)exp->e1)->var->storage_class & (STCout | STCref))
- {
- exp->memset |= referenceInit;
- }
-
- /* If it is an assignment from a 'foreign' type,
- * check for operator overloading.
- */
- if (exp->memset & referenceInit)
- {
- // If this is an initialization of a reference,
- // do nothing
- }
- else if (t1->ty == Tstruct)
- {
- Expression *e1x = exp->e1;
- Expression *e2x = exp->e2;
- StructDeclaration *sd = ((TypeStruct *)t1)->sym;
-
- if (exp->op == TOKconstruct)
- {
- Type *t2 = e2x->type->toBasetype();
- if (t2->ty == Tstruct && sd == ((TypeStruct *)t2)->sym)
- {
- sd->size(exp->loc);
- if (sd->sizeok != SIZEOKdone)
- return setError();
- if (!sd->ctor)
- sd->ctor = sd->searchCtor();
-
- // Bugzilla 15661: Look for the form from last of comma chain.
- Expression *e2y = e2x;
- while (e2y->op == TOKcomma)
- e2y = ((CommaExp *)e2y)->e2;
-
- CallExp *ce = (e2y->op == TOKcall) ? (CallExp *)e2y : NULL;
- DotVarExp *dve = (ce && ce->e1->op == TOKdotvar)
- ? (DotVarExp *)ce->e1 : NULL;
- if (sd->ctor && ce && dve && dve->var->isCtorDeclaration() &&
- e2y->type->implicitConvTo(t1))
- {
- /* Look for form of constructor call which is:
- * __ctmp.ctor(arguments...)
- */
-
- /* Before calling the constructor, initialize
- * variable with a bit copy of the default
- * initializer
- */
- AssignExp *ae = exp;
- if (sd->zeroInit == 1 && !sd->isNested())
- {
- // Bugzilla 14606: Always use BlitExp for the special expression: (struct = 0)
- ae = new BlitExp(ae->loc, ae->e1, new IntegerExp(exp->loc, 0, Type::tint32));
- }
- else
- {
- // Keep ae->op == TOKconstruct
- ae->e2 = sd->isNested() ? t1->defaultInitLiteral(exp->loc) : t1->defaultInit(exp->loc);
- }
- ae->type = e1x->type;
-
- /* Replace __ctmp being constructed with e1.
- * We need to copy constructor call expression,
- * because it may be used in other place.
- */
- DotVarExp *dvx = (DotVarExp *)dve->copy();
- dvx->e1 = e1x;
- CallExp *cx = (CallExp *)ce->copy();
- cx->e1 = dvx;
-
- Expression *e0;
- Expression::extractLast(e2x, &e0);
-
- Expression *e = Expression::combine(ae, cx);
- e = Expression::combine(e0, e);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- if (sd->postblit)
- {
- /* We have a copy constructor for this
- */
- if (e2x->op == TOKquestion)
- {
- /* Rewrite as:
- * a ? e1 = b : e1 = c;
- */
- CondExp *econd = (CondExp *)e2x;
- Expression *ea1 = new ConstructExp(econd->e1->loc, e1x, econd->e1);
- Expression *ea2 = new ConstructExp(econd->e1->loc, e1x, econd->e2);
- Expression *e = new CondExp(exp->loc, econd->econd, ea1, ea2);
- result = expressionSemantic(e, sc);
- return;
- }
-
- if (e2x->isLvalue())
- {
- if (!e2x->type->implicitConvTo(e1x->type))
- {
- exp->error("conversion error from %s to %s", e2x->type->toChars(), e1x->type->toChars());
- return setError();
- }
-
- /* Rewrite as:
- * (e1 = e2).postblit();
- *
- * Blit assignment e1 = e2 returns a reference to the original e1,
- * then call the postblit on it.
- */
- Expression *e = e1x->copy();
- e->type = e->type->mutableOf();
- e = new BlitExp(exp->loc, e, e2x);
- e = new DotVarExp(exp->loc, e, sd->postblit, false);
- e = new CallExp(exp->loc, e);
- result = expressionSemantic(e, sc);
- return;
- }
- else
- {
- /* The struct value returned from the function is transferred
- * so should not call the destructor on it.
- */
- e2x = valueNoDtor(e2x);
- }
- }
- }
- else if (!e2x->implicitConvTo(t1))
- {
- sd->size(exp->loc);
- if (sd->sizeok != SIZEOKdone)
- return setError();
- if (!sd->ctor)
- sd->ctor = sd->searchCtor();
-
- if (sd->ctor)
- {
- /* Look for implicit constructor call
- * Rewrite as:
- * e1 = init, e1.ctor(e2)
- */
- Expression *einit;
- einit = new BlitExp(exp->loc, e1x, e1x->type->defaultInit(exp->loc));
- einit->type = e1x->type;
-
- Expression *e;
- e = new DotIdExp(exp->loc, e1x, Id::ctor);
- e = new CallExp(exp->loc, e, e2x);
- e = new CommaExp(exp->loc, einit, e);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- if (search_function(sd, Id::call))
- {
- /* Look for static opCall
- * (See bugzilla 2702 for more discussion)
- * Rewrite as:
- * e1 = typeof(e1).opCall(arguments)
- */
- e2x = typeDotIdExp(e2x->loc, e1x->type, Id::call);
- e2x = new CallExp(exp->loc, e2x, exp->e2);
-
- e2x = expressionSemantic(e2x, sc);
- e2x = resolveProperties(sc, e2x);
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
- if (e2x->checkValue())
- return setError();
- }
- }
- else // Bugzilla 11355
- {
- AggregateDeclaration *ad2 = isAggregate(e2x->type);
- if (ad2 && ad2->aliasthis && !(exp->att2 && e2x->type == exp->att2))
- {
- if (!exp->att2 && exp->e2->type->checkAliasThisRec())
- exp->att2 = exp->e2->type;
-
- /* Rewrite (e1 op e2) as:
- * (e1 op e2.aliasthis)
- */
- exp->e2 = new DotIdExp(exp->e2->loc, exp->e2, ad2->aliasthis->ident);
- result = expressionSemantic(exp, sc);
- return;
- }
- }
- }
- else if (exp->op == TOKassign)
- {
- if (e1x->op == TOKindex &&
- ((IndexExp *)e1x)->e1->type->toBasetype()->ty == Taarray)
- {
- /*
- * Rewrite:
- * aa[key] = e2;
- * as:
- * ref __aatmp = aa;
- * ref __aakey = key;
- * ref __aaval = e2;
- * (__aakey in __aatmp
- * ? __aatmp[__aakey].opAssign(__aaval)
- * : ConstructExp(__aatmp[__aakey], __aaval));
- */
- IndexExp *ie = (IndexExp *)e1x;
- Type *t2 = e2x->type->toBasetype();
-
- Expression *e0 = NULL;
- Expression *ea = extractSideEffect(sc, "__aatmp", &e0, ie->e1);
- Expression *ek = extractSideEffect(sc, "__aakey", &e0, ie->e2);
- Expression *ev = extractSideEffect(sc, "__aaval", &e0, e2x);
-
- AssignExp *ae = (AssignExp *)exp->copy();
- ae->e1 = new IndexExp(exp->loc, ea, ek);
- ae->e1 = expressionSemantic(ae->e1, sc);
- ae->e1 = ae->e1->optimize(WANTvalue);
- ae->e2 = ev;
- Expression *e = ae->op_overload(sc);
- if (e)
- {
- Expression *ey = NULL;
- if (t2->ty == Tstruct && sd == t2->toDsymbol(sc))
- {
- ey = ev;
- }
- else if (!ev->implicitConvTo(ie->type) && sd->ctor)
- {
- // Look for implicit constructor call
- // Rewrite as S().ctor(e2)
- ey = new StructLiteralExp(exp->loc, sd, NULL);
- ey = new DotIdExp(exp->loc, ey, Id::ctor);
- ey = new CallExp(exp->loc, ey, ev);
- ey = trySemantic(ey, sc);
- }
- if (ey)
- {
- Expression *ex;
- ex = new IndexExp(exp->loc, ea, ek);
- ex = expressionSemantic(ex, sc);
- ex = ex->optimize(WANTvalue);
- ex = ex->modifiableLvalue(sc, ex); // allocate new slot
- ey = new ConstructExp(exp->loc, ex, ey);
- ey = expressionSemantic(ey, sc);
- if (ey->op == TOKerror)
- {
- result = ey;
- return;
- }
- ex = e;
-
- // Bugzilla 14144: The whole expression should have the common type
- // of opAssign() return and assigned AA entry.
- // Even if there's no common type, expression should be typed as void.
- Type *t = NULL;
- if (!typeMerge(sc, TOKquestion, &t, &ex, &ey))
- {
- ex = new CastExp(ex->loc, ex, Type::tvoid);
- ey = new CastExp(ey->loc, ey, Type::tvoid);
- }
- e = new CondExp(exp->loc, new InExp(exp->loc, ek, ea), ex, ey);
- }
- e = Expression::combine(e0, e);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- }
- else
- {
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
- }
- }
- else
- assert(exp->op == TOKblit);
-
- exp->e1 = e1x;
- exp->e2 = e2x;
- }
- else if (t1->ty == Tclass)
- {
- // Disallow assignment operator overloads for same type
- if (exp->op == TOKassign && !exp->e2->implicitConvTo(exp->e1->type))
- {
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
- }
- }
- else if (t1->ty == Tsarray)
- {
- // SliceExp cannot have static array type without context inference.
- assert(exp->e1->op != TOKslice);
-
- Expression *e1x = exp->e1;
- Expression *e2x = exp->e2;
-
- if (e2x->implicitConvTo(e1x->type))
- {
- if (exp->op != TOKblit &&
- ((e2x->op == TOKslice && ((UnaExp *)e2x)->e1->isLvalue()) ||
- (e2x->op == TOKcast && ((UnaExp *)e2x)->e1->isLvalue()) ||
- (e2x->op != TOKslice && e2x->isLvalue())))
- {
- if (e1x->checkPostblit(sc, t1))
- return setError();
- }
-
- // e2 matches to t1 because of the implicit length match, so
- if (isUnaArrayOp(e2x->op) || isBinArrayOp(e2x->op))
- {
- // convert e1 to e1[]
- // e.g. e1[] = a[] + b[];
- SliceExp *sle = new SliceExp(e1x->loc, e1x, NULL, NULL);
- sle->arrayop = true;
- e1x = expressionSemantic(sle, sc);
- }
- else
- {
- // convert e2 to t1 later
- // e.g. e1 = [1, 2, 3];
- }
- }
- else
- {
- if (e2x->implicitConvTo(t1->nextOf()->arrayOf()) > MATCHnomatch)
- {
- uinteger_t dim1 = ((TypeSArray *)t1)->dim->toInteger();
- uinteger_t dim2 = dim1;
- if (e2x->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)e2x;
- dim2 = ale->elements ? ale->elements->length : 0;
- }
- else if (e2x->op == TOKslice)
- {
- Type *tx = toStaticArrayType((SliceExp *)e2x);
- if (tx)
- dim2 = ((TypeSArray *)tx)->dim->toInteger();
- }
- if (dim1 != dim2)
- {
- exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
- return setError();
- }
- }
-
- // May be block or element-wise assignment, so
- // convert e1 to e1[]
- if (exp->op != TOKassign)
- {
- // If multidimensional static array, treat as one large array
- dinteger_t dim = t1->numberOfElems(exp->loc);
- e1x->type = t1->baseElemOf()->sarrayOf(dim);
- }
- SliceExp *sle = new SliceExp(e1x->loc, e1x, NULL, NULL);
- sle->arrayop = true;
- e1x = expressionSemantic(sle, sc);
- }
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
-
- exp->e1 = e1x;
- exp->e2 = e2x;
- t1 = e1x->type->toBasetype();
- }
-
- /* Check the mutability of e1.
- */
- if (exp->e1->op == TOKarraylength)
- {
- // e1 is not an lvalue, but we let code generator handle it
- ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1;
-
- Expression *ale1x = ale->e1;
- ale1x = ale1x->modifiableLvalue(sc, exp->e1);
- if (ale1x->op == TOKerror)
- {
- result = ale1x;
- return;
- }
- ale->e1 = ale1x;
-
- Type *tn = ale->e1->type->toBasetype()->nextOf();
- checkDefCtor(ale->loc, tn);
- semanticTypeInfo(sc, tn);
- }
- else if (exp->e1->op == TOKslice)
- {
- Type *tn = exp->e1->type->nextOf();
- if (exp->op == TOKassign && !tn->isMutable())
- {
- exp->error("slice %s is not mutable", exp->e1->toChars());
- return setError();
- }
-
- // For conditional operator, both branches need conversion.
- SliceExp *se = (SliceExp *)exp->e1;
- while (se->e1->op == TOKslice)
- se = (SliceExp *)se->e1;
- if (se->e1->op == TOKquestion &&
- se->e1->type->toBasetype()->ty == Tsarray)
- {
- se->e1 = se->e1->modifiableLvalue(sc, exp->e1);
- if (se->e1->op == TOKerror)
- {
- result = se->e1;
- return;
- }
- }
- }
- else
- {
- Expression *e1x = exp->e1;
-
- // Try to do a decent error message with the expression
- // before it got constant folded
- if (e1x->op != TOKvar)
- e1x = e1x->optimize(WANTvalue);
-
- if (exp->op == TOKassign)
- e1x = e1x->modifiableLvalue(sc, e1old);
-
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- exp->e1 = e1x;
- }
-
- /* Tweak e2 based on the type of e1.
- */
- Expression *e2x = exp->e2;
- Type *t2 = e2x->type->toBasetype();
-
- // If it is a array, get the element type. Note that it may be
- // multi-dimensional.
- Type *telem = t1;
- while (telem->ty == Tarray)
- telem = telem->nextOf();
-
- if (exp->e1->op == TOKslice &&
- t1->nextOf() && (telem->ty != Tvoid || e2x->op == TOKnull) &&
- e2x->implicitConvTo(t1->nextOf())
- )
- {
- // Check for block assignment. If it is of type void[], void[][], etc,
- // '= null' is the only allowable block assignment (Bug 7493)
- // memset
- exp->memset |= blockAssign; // make it easy for back end to tell what this is
- e2x = e2x->implicitCastTo(sc, t1->nextOf());
- if (exp->op != TOKblit && e2x->isLvalue() &&
- exp->e1->checkPostblit(sc, t1->nextOf()))
- return setError();
- }
- else if (exp->e1->op == TOKslice &&
- (t2->ty == Tarray || t2->ty == Tsarray) &&
- t2->nextOf()->implicitConvTo(t1->nextOf()))
- {
- // Check element-wise assignment.
-
- /* If assigned elements number is known at compile time,
- * check the mismatch.
- */
- SliceExp *se1 = (SliceExp *)exp->e1;
- TypeSArray *tsa1 = (TypeSArray *)toStaticArrayType(se1);
- TypeSArray *tsa2 = NULL;
- if (e2x->op == TOKarrayliteral)
- tsa2 = (TypeSArray *)t2->nextOf()->sarrayOf(((ArrayLiteralExp *)e2x)->elements->length);
- else if (e2x->op == TOKslice)
- tsa2 = (TypeSArray *)toStaticArrayType((SliceExp *)e2x);
- else if (t2->ty == Tsarray)
- tsa2 = (TypeSArray *)t2;
- if (tsa1 && tsa2)
- {
- uinteger_t dim1 = tsa1->dim->toInteger();
- uinteger_t dim2 = tsa2->dim->toInteger();
- if (dim1 != dim2)
- {
- exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
- return setError();
- }
- }
-
- if (exp->op != TOKblit &&
- ((e2x->op == TOKslice && ((UnaExp *)e2x)->e1->isLvalue()) ||
- (e2x->op == TOKcast && ((UnaExp *)e2x)->e1->isLvalue()) ||
- (e2x->op != TOKslice && e2x->isLvalue())))
- {
- if (exp->e1->checkPostblit(sc, t1->nextOf()))
- return setError();
- }
-
- if (0 && global.params.warnings != DIAGNOSTICoff && !global.gag && exp->op == TOKassign &&
- e2x->op != TOKslice && e2x->op != TOKassign &&
- e2x->op != TOKarrayliteral && e2x->op != TOKstring &&
- !(e2x->op == TOKadd || e2x->op == TOKmin ||
- e2x->op == TOKmul || e2x->op == TOKdiv ||
- e2x->op == TOKmod || e2x->op == TOKxor ||
- e2x->op == TOKand || e2x->op == TOKor ||
- e2x->op == TOKpow ||
- e2x->op == TOKtilde || e2x->op == TOKneg))
- {
- const char* e1str = exp->e1->toChars();
- const char* e2str = e2x->toChars();
- exp->warning("explicit element-wise assignment %s = (%s)[] is better than %s = %s",
- e1str, e2str, e1str, e2str);
- }
-
- Type *t2n = t2->nextOf();
- Type *t1n = t1->nextOf();
- int offset;
- if (t2n->equivalent(t1n) ||
- (t1n->isBaseOf(t2n, &offset) && offset == 0))
- {
- /* Allow copy of distinct qualifier elements.
- * eg.
- * char[] dst; const(char)[] src;
- * dst[] = src;
- *
- * class C {} class D : C {}
- * C[2] ca; D[] da;
- * ca[] = da;
- */
- if (isArrayOpValid(e2x))
- {
- // Don't add CastExp to keep AST for array operations
- e2x = e2x->copy();
- e2x->type = exp->e1->type->constOf();
- }
- else
- e2x = e2x->castTo(sc, exp->e1->type->constOf());
- }
- else
- {
- /* Bugzilla 15778: A string literal has an array type of immutable
- * elements by default, and normally it cannot be convertible to
- * array type of mutable elements. But for element-wise assignment,
- * elements need to be const at best. So we should give a chance
- * to change code unit size for polysemous string literal.
- */
- if (e2x->op == TOKstring)
- e2x = e2x->implicitCastTo(sc, exp->e1->type->constOf());
- else
- e2x = e2x->implicitCastTo(sc, exp->e1->type);
- }
- if (t1n->toBasetype()->ty == Tvoid && t2n->toBasetype()->ty == Tvoid)
- {
- if (!sc->intypeof && sc->func && sc->func->setUnsafe())
- {
- exp->error("cannot copy void[] to void[] in @safe code");
- return setError();
- }
- }
- }
- else
- {
- if (0 && global.params.warnings != DIAGNOSTICoff && !global.gag && exp->op == TOKassign &&
- t1->ty == Tarray && t2->ty == Tsarray &&
- e2x->op != TOKslice &&
- t2->implicitConvTo(t1))
- { // Disallow ar[] = sa (Converted to ar[] = sa[])
- // Disallow da = sa (Converted to da = sa[])
- const char* e1str = exp->e1->toChars();
- const char* e2str = e2x->toChars();
- const char* atypestr = exp->e1->op == TOKslice ? "element-wise" : "slice";
- exp->warning("explicit %s assignment %s = (%s)[] is better than %s = %s",
- atypestr, e1str, e2str, e1str, e2str);
- }
- if (exp->op == TOKblit)
- e2x = e2x->castTo(sc, exp->e1->type);
- else
- e2x = e2x->implicitCastTo(sc, exp->e1->type);
- }
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
- exp->e2 = e2x;
- t2 = exp->e2->type->toBasetype();
-
- /* Look for array operations
- */
- if ((t2->ty == Tarray || t2->ty == Tsarray) && isArrayOpValid(exp->e2))
- {
- // Look for valid array operations
- if (!(exp->memset & blockAssign) && exp->e1->op == TOKslice &&
- (isUnaArrayOp(exp->e2->op) || isBinArrayOp(exp->e2->op)))
- {
- exp->type = exp->e1->type;
- if (exp->op == TOKconstruct) // Bugzilla 10282: tweak mutability of e1 element
- exp->e1->type = exp->e1->type->nextOf()->mutableOf()->arrayOf();
- result = arrayOp(exp, sc);
- return;
- }
-
- // Drop invalid array operations in e2
- // d = a[] + b[], d = (a[] + b[])[0..2], etc
- if (checkNonAssignmentArrayOp(exp->e2, !(exp->memset & blockAssign) && exp->op == TOKassign))
- return setError();
-
- // Remains valid array assignments
- // d = d[], d = [1,2,3], etc
- }
-
- /* Don't allow assignment to classes that were allocated on the stack with:
- * scope Class c = new Class();
- */
-
- if (exp->e1->op == TOKvar && exp->op == TOKassign)
- {
- VarExp *ve = (VarExp *)exp->e1;
- VarDeclaration *vd = ve->var->isVarDeclaration();
- if (vd && (vd->onstack || vd->mynew))
- {
- assert(t1->ty == Tclass);
- exp->error("cannot rebind scope variables");
- }
- }
- if (exp->e1->op == TOKvar && ((VarExp *)exp->e1)->var->ident == Id::ctfe)
- {
- exp->error("cannot modify compiler-generated variable __ctfe");
- }
-
- exp->type = exp->e1->type;
- assert(exp->type);
- Expression *res = exp->op == TOKassign ? exp->reorderSettingAAElem(sc) : exp;
- checkAssignEscape(sc, res, false);
- result = res;
- }
-
- void visit(CatAssignExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- //printf("CatAssignExp::semantic() %s\n", toChars());
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->op == TOKslice)
- {
- SliceExp *se = (SliceExp *)exp->e1;
- if (se->e1->type->toBasetype()->ty == Tsarray)
- {
- exp->error("cannot append to static array %s", se->e1->type->toChars());
- return setError();
- }
- }
-
- exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
- if (exp->e1->op == TOKerror)
- {
- result = exp->e1;
- return;
- }
- if (exp->e2->op == TOKerror)
- {
- result = exp->e2;
- return;
- }
-
- if (checkNonAssignmentArrayOp(exp->e2))
- return setError();
-
- Type *tb1 = exp->e1->type->toBasetype();
- Type *tb1next = tb1->nextOf();
- Type *tb2 = exp->e2->type->toBasetype();
-
- if ((tb1->ty == Tarray) &&
- (tb2->ty == Tarray || tb2->ty == Tsarray) &&
- (exp->e2->implicitConvTo(exp->e1->type)
- || (tb2->nextOf()->implicitConvTo(tb1next) &&
- (tb2->nextOf()->size(Loc()) == tb1next->size(Loc())))
- )
- )
- {
- // Append array
- if (exp->e1->checkPostblit(sc, tb1next))
- return setError();
- exp->e2 = exp->e2->castTo(sc, exp->e1->type);
- }
- else if ((tb1->ty == Tarray) &&
- exp->e2->implicitConvTo(tb1next)
- )
- {
- // Append element
- if (exp->e2->checkPostblit(sc, tb2))
- return setError();
- exp->e2 = exp->e2->castTo(sc, tb1next);
- exp->e2 = doCopyOrMove(sc, exp->e2);
- }
- else if (tb1->ty == Tarray &&
- (tb1next->ty == Tchar || tb1next->ty == Twchar) &&
- exp->e2->type->ty != tb1next->ty &&
- exp->e2->implicitConvTo(Type::tdchar)
- )
- { // Append dchar to char[] or wchar[]
- exp->e2 = exp->e2->castTo(sc, Type::tdchar);
-
- /* Do not allow appending wchar to char[] because if wchar happens
- * to be a surrogate pair, nothing good can result.
- */
- }
- else
- {
- exp->error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars());
- return setError();
- }
- if (exp->e2->checkValue())
- return setError();
-
- exp->type = exp->e1->type;
- result = exp->reorderSettingAAElem(sc);
- }
-
- void visit(PowAssignExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->checkReadModifyWrite(exp->op, exp->e2))
- return setError();
-
- assert(exp->e1->type && exp->e2->type);
- if (exp->e1->op == TOKslice || exp->e1->type->ty == Tarray || exp->e1->type->ty == Tsarray)
- {
- if (checkNonAssignmentArrayOp(exp->e1))
- return setError();
-
- // T[] ^^= ...
- if (exp->e2->implicitConvTo(exp->e1->type->nextOf()))
- {
- // T[] ^^= T
- exp->e2 = exp->e2->castTo(sc, exp->e1->type->nextOf());
- }
- else if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- // Check element types are arithmetic
- Type *tb1 = exp->e1->type->nextOf()->toBasetype();
- Type *tb2 = exp->e2->type->toBasetype();
- if (tb2->ty == Tarray || tb2->ty == Tsarray)
- tb2 = tb2->nextOf()->toBasetype();
-
- if ( (tb1->isintegral() || tb1->isfloating()) &&
- (tb2->isintegral() || tb2->isfloating()))
- {
- exp->type = exp->e1->type;
- result = arrayOp(exp, sc);
- return;
- }
- }
- else
- {
- exp->e1 = exp->e1->modifiableLvalue(sc, exp->e1);
- }
-
- if ((exp->e1->type->isintegral() || exp->e1->type->isfloating()) &&
- (exp->e2->type->isintegral() || exp->e2->type->isfloating()))
- {
- Expression *e0 = NULL;
- e = exp->reorderSettingAAElem(sc);
- e = Expression::extractLast(e, &e0);
- assert(e == exp);
-
- if (exp->e1->op == TOKvar)
- {
- // Rewrite: e1 = e1 ^^ e2
- e = new PowExp(exp->loc, exp->e1->syntaxCopy(), exp->e2);
- e = new AssignExp(exp->loc, exp->e1, e);
- }
- else
- {
- // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
- VarDeclaration *v = copyToTemp(STCref, "__powtmp", exp->e1);
- Expression *de = new DeclarationExp(exp->e1->loc, v);
- VarExp *ve = new VarExp(exp->e1->loc, v);
- e = new PowExp(exp->loc, ve, exp->e2);
- e = new AssignExp(exp->loc, new VarExp(exp->e1->loc, v), e);
- e = new CommaExp(exp->loc, de, e);
- }
- e = Expression::combine(e0, e);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- result = exp->incompatibleTypes();
- }
-
- void visit(AddExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- Type *tb1 = exp->e1->type->toBasetype();
- Type *tb2 = exp->e2->type->toBasetype();
-
- bool err = false;
- if (tb1->ty == Tdelegate ||
- (tb1->ty == Tpointer && tb1->nextOf()->ty == Tfunction))
- {
- err |= exp->e1->checkArithmetic();
- }
- if (tb2->ty == Tdelegate ||
- (tb2->ty == Tpointer && tb2->nextOf()->ty == Tfunction))
- {
- err |= exp->e2->checkArithmetic();
- }
- if (err)
- return setError();
-
- if ((tb1->ty == Tpointer && exp->e2->type->isintegral()) ||
- (tb2->ty == Tpointer && exp->e1->type->isintegral()))
- {
- result = scaleFactor(exp, sc);
- return;
- }
-
- if (tb1->ty == Tpointer && tb2->ty == Tpointer)
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- tb1 = exp->e1->type->toBasetype();
- if (!target.isVectorOpSupported(tb1, exp->op, tb2))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if ((tb1->isreal() && exp->e2->type->isimaginary()) ||
- (tb1->isimaginary() && exp->e2->type->isreal()))
- {
- switch (exp->type->toBasetype()->ty)
- {
- case Tfloat32:
- case Timaginary32:
- exp->type = Type::tcomplex32;
- break;
-
- case Tfloat64:
- case Timaginary64:
- exp->type = Type::tcomplex64;
- break;
-
- case Tfloat80:
- case Timaginary80:
- exp->type = Type::tcomplex80;
- break;
-
- default:
- assert(0);
- }
- }
- result = exp;
- }
-
- void visit(MinExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- Type *t1 = exp->e1->type->toBasetype();
- Type *t2 = exp->e2->type->toBasetype();
-
- bool err = false;
- if (t1->ty == Tdelegate ||
- (t1->ty == Tpointer && t1->nextOf()->ty == Tfunction))
- {
- err |= exp->e1->checkArithmetic();
- }
- if (t2->ty == Tdelegate ||
- (t2->ty == Tpointer && t2->nextOf()->ty == Tfunction))
- {
- err |= exp->e2->checkArithmetic();
- }
- if (err)
- return setError();
-
- if (t1->ty == Tpointer)
- {
- if (t2->ty == Tpointer)
- {
- // Need to divide the result by the stride
- // Replace (ptr - ptr) with (ptr - ptr) / stride
- d_int64 stride;
-
- // make sure pointer types are compatible
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- exp->type = Type::tptrdiff_t;
- stride = t2->nextOf()->size();
- if (stride == 0)
- {
- e = new IntegerExp(exp->loc, 0, Type::tptrdiff_t);
- }
- else
- {
- e = new DivExp(exp->loc, exp, new IntegerExp(Loc(), stride, Type::tptrdiff_t));
- e->type = Type::tptrdiff_t;
- }
- }
- else if (t2->isintegral())
- e = scaleFactor(exp, sc);
- else
- {
- exp->error("can't subtract %s from pointer", t2->toChars());
- e = new ErrorExp();
- }
- result = e;
- return;
- }
- if (t2->ty == Tpointer)
- {
- exp->type = exp->e2->type;
- exp->error("can't subtract pointer from %s", exp->e1->type->toChars());
- return setError();
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- t1 = exp->e1->type->toBasetype();
- t2 = exp->e2->type->toBasetype();
- if (!target.isVectorOpSupported(t1, exp->op, t2))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if ((t1->isreal() && t2->isimaginary()) ||
- (t1->isimaginary() && t2->isreal()))
- {
- switch (exp->type->ty)
- {
- case Tfloat32:
- case Timaginary32:
- exp->type = Type::tcomplex32;
- break;
-
- case Tfloat64:
- case Timaginary64:
- exp->type = Type::tcomplex64;
- break;
-
- case Tfloat80:
- case Timaginary80:
- exp->type = Type::tcomplex80;
- break;
-
- default:
- assert(0);
- }
- }
- result = exp;
- }
-
- void visit(CatExp *exp)
- {
- //printf("CatExp::semantic() %s\n", exp->toChars());
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- Type *tb1 = exp->e1->type->toBasetype();
- Type *tb2 = exp->e2->type->toBasetype();
-
- bool f1 = checkNonAssignmentArrayOp(exp->e1);
- bool f2 = checkNonAssignmentArrayOp(exp->e2);
- if (f1 || f2)
- return setError();
-
- /* BUG: Should handle things like:
- * char c;
- * c ~ ' '
- * ' ' ~ c;
- */
- Type *tb1next = tb1->nextOf();
- Type *tb2next = tb2->nextOf();
-
- // Check for: array ~ array
- if (tb1next && tb2next &&
- (tb1next->implicitConvTo(tb2next) >= MATCHconst ||
- tb2next->implicitConvTo(tb1next) >= MATCHconst ||
- (exp->e1->op == TOKarrayliteral && exp->e1->implicitConvTo(tb2)) ||
- (exp->e2->op == TOKarrayliteral && exp->e2->implicitConvTo(tb1))
- )
- )
- {
- /* Bugzilla 9248: Here to avoid the case of:
- * void*[] a = [cast(void*)1];
- * void*[] b = [cast(void*)2];
- * a ~ b;
- * becoming:
- * a ~ [cast(void*)b];
- */
-
- /* Bugzilla 14682: Also to avoid the case of:
- * int[][] a;
- * a ~ [];
- * becoming:
- * a ~ cast(int[])[];
- */
- goto Lpeer;
- }
-
- // Check for: array ~ element
- if ((tb1->ty == Tsarray || tb1->ty == Tarray) && tb2->ty != Tvoid)
- {
- if (exp->e1->op == TOKarrayliteral)
- {
- exp->e2 = exp->e2->isLvalue() ? callCpCtor(sc, exp->e2) : valueNoDtor(exp->e2);
- // Bugzilla 14686: Postblit call appears in AST, and this is
- // finally translated to an ArrayLiteralExp in below otpimize().
- }
- else if (exp->e1->op == TOKstring)
- {
- // No postblit call exists on character (integer) value.
- }
- else
- {
- if (exp->e2->checkPostblit(sc, tb2))
- return setError();
- // Postblit call will be done in runtime helper function
- }
-
- if (exp->e1->op == TOKarrayliteral && exp->e1->implicitConvTo(tb2->arrayOf()))
- {
- exp->e1 = exp->e1->implicitCastTo(sc, tb2->arrayOf());
- exp->type = tb2->arrayOf();
- goto L2elem;
- }
- if (exp->e2->implicitConvTo(tb1next) >= MATCHconvert)
- {
- exp->e2 = exp->e2->implicitCastTo(sc, tb1next);
- exp->type = tb1next->arrayOf();
- L2elem:
- if (tb2->ty == Tarray || tb2->ty == Tsarray)
- {
- // Make e2 into [e2]
- exp->e2 = new ArrayLiteralExp(exp->e2->loc, exp->type, exp->e2);
- }
- result = exp->optimize(WANTvalue);
- return;
- }
- }
- // Check for: element ~ array
- if ((tb2->ty == Tsarray || tb2->ty == Tarray) && tb1->ty != Tvoid)
- {
- if (exp->e2->op == TOKarrayliteral)
- {
- exp->e1 = exp->e1->isLvalue() ? callCpCtor(sc, exp->e1) : valueNoDtor(exp->e1);
- }
- else if (exp->e2->op == TOKstring)
- {
- }
- else
- {
- if (exp->e1->checkPostblit(sc, tb1))
- return setError();
- }
-
- if (exp->e2->op == TOKarrayliteral && exp->e2->implicitConvTo(tb1->arrayOf()))
- {
- exp->e2 = exp->e2->implicitCastTo(sc, tb1->arrayOf());
- exp->type = tb1->arrayOf();
- goto L1elem;
- }
- if (exp->e1->implicitConvTo(tb2next) >= MATCHconvert)
- {
- exp->e1 = exp->e1->implicitCastTo(sc, tb2next);
- exp->type = tb2next->arrayOf();
- L1elem:
- if (tb1->ty == Tarray || tb1->ty == Tsarray)
- {
- // Make e1 into [e1]
- exp->e1 = new ArrayLiteralExp(exp->e1->loc, exp->type, exp->e1);
- }
- result = exp->optimize(WANTvalue);
- return;
- }
- }
-
- Lpeer:
- if ((tb1->ty == Tsarray || tb1->ty == Tarray) &&
- (tb2->ty == Tsarray || tb2->ty == Tarray) &&
- (tb1next->mod || tb2next->mod) &&
- (tb1next->mod != tb2next->mod)
- )
- {
- Type *t1 = tb1next->mutableOf()->constOf()->arrayOf();
- Type *t2 = tb2next->mutableOf()->constOf()->arrayOf();
- if (exp->e1->op == TOKstring && !((StringExp *)exp->e1)->committed)
- exp->e1->type = t1;
- else
- exp->e1 = exp->e1->castTo(sc, t1);
- if (exp->e2->op == TOKstring && !((StringExp *)exp->e2)->committed)
- exp->e2->type = t2;
- else
- exp->e2 = exp->e2->castTo(sc, t2);
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
- exp->type = exp->type->toHeadMutable();
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tsarray)
- exp->type = tb->nextOf()->arrayOf();
- if (exp->type->ty == Tarray && tb1next && tb2next &&
- tb1next->mod != tb2next->mod)
- {
- exp->type = exp->type->nextOf()->toHeadMutable()->arrayOf();
- }
- if (Type *tbn = tb->nextOf())
- {
- if (exp->checkPostblit(sc, tbn))
- return setError();
- }
- Type *t1 = exp->e1->type->toBasetype();
- Type *t2 = exp->e2->type->toBasetype();
- if ((t1->ty == Tarray || t1->ty == Tsarray) &&
- (t2->ty == Tarray || t2->ty == Tsarray))
- {
- // Normalize to ArrayLiteralExp or StringExp as far as possible
- e = exp->optimize(WANTvalue);
- }
- else
- {
- //printf("(%s) ~ (%s)\n", exp->e1->toChars(), exp->e2->toChars());
- result = exp->incompatibleTypes();
- return;
- }
- result = e;
- }
-
- void visit(MulExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (exp->checkArithmeticBin())
- return setError();
-
- if (exp->type->isfloating())
- {
- Type *t1 = exp->e1->type;
- Type *t2 = exp->e2->type;
-
- if (t1->isreal())
- {
- exp->type = t2;
- }
- else if (t2->isreal())
- {
- exp->type = t1;
- }
- else if (t1->isimaginary())
- {
- if (t2->isimaginary())
- {
-
- switch (t1->toBasetype()->ty)
- {
- case Timaginary32:
- exp->type = Type::tfloat32;
- break;
-
- case Timaginary64:
- exp->type = Type::tfloat64;
- break;
-
- case Timaginary80:
- exp->type = Type::tfloat80;
- break;
-
- default:
- assert(0);
- }
-
- // iy * iv = -yv
- exp->e1->type = exp->type;
- exp->e2->type = exp->type;
- e = new NegExp(exp->loc, exp);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- else
- exp->type = t2; // t2 is complex
- }
- else if (t2->isimaginary())
- {
- exp->type = t1; // t1 is complex
- }
- }
- else if (!target.isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- result = exp;
- }
-
- void visit(DivExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (exp->checkArithmeticBin())
- return setError();
-
- if (exp->type->isfloating())
- {
- Type *t1 = exp->e1->type;
- Type *t2 = exp->e2->type;
-
- if (t1->isreal())
- {
- exp->type = t2;
- if (t2->isimaginary())
- {
- // x/iv = i(-x/v)
- exp->e2->type = t1;
- e = new NegExp(exp->loc, exp);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
- }
- else if (t2->isreal())
- {
- exp->type = t1;
- }
- else if (t1->isimaginary())
- {
- if (t2->isimaginary())
- {
- switch (t1->toBasetype()->ty)
- {
- case Timaginary32:
- exp->type = Type::tfloat32;
- break;
-
- case Timaginary64:
- exp->type = Type::tfloat64;
- break;
-
- case Timaginary80:
- exp->type = Type::tfloat80;
- break;
-
- default:
- assert(0);
- }
- }
- else
- exp->type = t2; // t2 is complex
- }
- else if (t2->isimaginary())
- {
- exp->type = t1; // t1 is complex
- }
- }
- else if (!target.isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- result = exp;
- }
-
- void visit(ModExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
- if (!target.isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- if (exp->checkArithmeticBin())
- return setError();
-
- if (exp->type->isfloating())
- {
- exp->type = exp->e1->type;
- if (exp->e2->type->iscomplex())
- {
- exp->error("cannot perform modulo complex arithmetic");
- return setError();
- }
- }
- result = exp;
- }
-
- void visit(PowExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- //printf("PowExp::semantic() %s\n", exp->toChars());
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (exp->checkArithmeticBin())
- return setError();
-
- if (!target.isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- // For built-in numeric types, there are several cases.
- // TODO: backend support, especially for e1 ^^ 2.
-
- // First, attempt to fold the expression.
- e = exp->optimize(WANTvalue);
- if (e->op != TOKpow)
- {
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- // Determine if we're raising to an integer power.
- sinteger_t intpow = 0;
- if (exp->e2->op == TOKint64 && ((sinteger_t)exp->e2->toInteger() == 2 || (sinteger_t)exp->e2->toInteger() == 3))
- intpow = exp->e2->toInteger();
- else if (exp->e2->op == TOKfloat64 && (exp->e2->toReal() == ldouble((sinteger_t)exp->e2->toReal())))
- intpow = (sinteger_t)(exp->e2->toReal());
-
- // Deal with x^^2, x^^3 immediately, since they are of practical importance.
- if (intpow == 2 || intpow == 3)
- {
- // Replace x^^2 with (tmp = x, tmp*tmp)
- // Replace x^^3 with (tmp = x, tmp*tmp*tmp)
- VarDeclaration *tmp = copyToTemp(0, "__powtmp", exp->e1);
- Expression *de = new DeclarationExp(exp->loc, tmp);
- Expression *ve = new VarExp(exp->loc, tmp);
-
- /* Note that we're reusing ve. This should be ok.
- */
- Expression *me = new MulExp(exp->loc, ve, ve);
- if (intpow == 3)
- me = new MulExp(exp->loc, me, ve);
- e = new CommaExp(exp->loc, de, me);
- e = expressionSemantic(e, sc);
- result = e;
- return;
- }
-
- Module *mmath = loadStdMath();
- if (!mmath)
- {
- //exp->error("requires std.math for ^^ operators");
- //fatal();
-
- // Leave handling of PowExp to the backend, or throw
- // an error gracefully if no backend support exists.
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
- result = exp;
- return;
- }
- e = new ScopeExp(exp->loc, mmath);
-
- if (exp->e2->op == TOKfloat64 && exp->e2->toReal() == CTFloat::half)
- {
- // Replace e1 ^^ 0.5 with .std.math.sqrt(x)
- e = new CallExp(exp->loc, new DotIdExp(exp->loc, e, Id::_sqrt), exp->e1);
- }
- else
- {
- // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
- e = new CallExp(exp->loc, new DotIdExp(exp->loc, e, Id::_pow), exp->e1, exp->e2);
- }
- e = expressionSemantic(e, sc);
- result = e;
- }
-
- void visit(ShlExp *exp)
- {
- //printf("ShlExp::semantic(), type = %p\n", exp->type);
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->checkIntegralBin())
- return setError();
- if (!target.isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- exp->e1 = integralPromotions(exp->e1, sc);
- if (exp->e2->type->toBasetype()->ty != Tvector)
- exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
-
- exp->type = exp->e1->type;
- result = exp;
- }
-
- void visit(ShrExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->checkIntegralBin())
- return setError();
- if (!target.isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- exp->e1 = integralPromotions(exp->e1, sc);
- if (exp->e2->type->toBasetype()->ty != Tvector)
- exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
-
- exp->type = exp->e1->type;
- result = exp;
- }
-
- void visit(UshrExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->checkIntegralBin())
- return setError();
- if (!target.isVectorOpSupported(exp->e1->type->toBasetype(), exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- exp->e1 = integralPromotions(exp->e1, sc);
- if (exp->e2->type->toBasetype()->ty != Tvector)
- exp->e2 = exp->e2->castTo(sc, Type::tshiftcnt);
-
- exp->type = exp->e1->type;
- result = exp;
- }
-
- void visit(AndExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->type->toBasetype()->ty == Tbool &&
- exp->e2->type->toBasetype()->ty == Tbool)
- {
- exp->type = exp->e1->type;
- result = exp;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (!target.isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if (exp->checkIntegralBin())
- return setError();
-
- result = exp;
- }
-
- void visit(OrExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->type->toBasetype()->ty == Tbool &&
- exp->e2->type->toBasetype()->ty == Tbool)
- {
- exp->type = exp->e1->type;
- result = exp;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (!target.isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if (exp->checkIntegralBin())
- return setError();
-
- result = exp;
- }
-
- void visit(XorExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- if (exp->e1->type->toBasetype()->ty == Tbool &&
- exp->e2->type->toBasetype()->ty == Tbool)
- {
- exp->type = exp->e1->type;
- result = exp;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- Type *tb = exp->type->toBasetype();
- if (tb->ty == Tarray || tb->ty == Tsarray)
- {
- if (!isArrayOpValid(exp))
- {
- exp->error("invalid array operation %s (possible missing [])", exp->toChars());
- return setError();
- }
- result = exp;
- return;
- }
-
- if (!target.isVectorOpSupported(tb, exp->op, exp->e2->type->toBasetype()))
- {
- result = exp->incompatibleTypes();
- return;
- }
- if (exp->checkIntegralBin())
- return setError();
-
- result = exp;
- }
-
- void visit(LogicalExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- setNoderefOperands(exp);
-
- Expression *e1x = expressionSemantic(exp->e1, sc);
-
- // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (e1x->op == TOKtype)
- e1x = resolveAliasThis(sc, e1x);
-
- e1x = resolveProperties(sc, e1x);
- e1x = e1x->toBoolean(sc);
- unsigned cs1 = sc->callSuper;
-
- if (sc->flags & SCOPEcondition)
- {
- /* If in static if, don't evaluate e2 if we don't have to.
- */
- e1x = e1x->optimize(WANTvalue);
- if (e1x->isBool(exp->op == TOKoror))
- {
- result = new IntegerExp(exp->loc, exp->op == TOKoror, Type::tbool);
- return;
- }
- }
-
- Expression *e2x = expressionSemantic(exp->e2, sc);
- sc->mergeCallSuper(exp->loc, cs1);
-
- // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (e2x->op == TOKtype)
- e2x = resolveAliasThis(sc, e2x);
-
- e2x = resolveProperties(sc, e2x);
-
- bool f1 = checkNonAssignmentArrayOp(e1x);
- bool f2 = checkNonAssignmentArrayOp(e2x);
- if (f1 || f2)
- return setError();
-
- // Unless the right operand is 'void', the expression is converted to 'bool'.
- if (e2x->type->ty != Tvoid)
- e2x = e2x->toBoolean(sc);
-
- if (e2x->op == TOKtype || e2x->op == TOKscope)
- {
- exp->error("%s is not an expression", exp->e2->toChars());
- return setError();
- }
- if (e1x->op == TOKerror || e1x->type->ty == Tnoreturn)
- {
- result = e1x;
- return;
- }
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
-
- // The result type is 'bool', unless the right operand has type 'void'.
- if (e2x->type->ty == Tvoid)
- exp->type = Type::tvoid;
- else
- exp->type = Type::tbool;
-
- exp->e1 = e1x;
- exp->e2 = e2x;
- result = exp;
- }
-
- void visit(InExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- result = e;
- return;
- }
-
- Type *t2b = exp->e2->type->toBasetype();
- switch (t2b->ty)
- {
- case Taarray:
- {
- TypeAArray *ta = (TypeAArray *)t2b;
-
- // Special handling for array keys
- if (!arrayTypeCompatible(exp->e1->loc, exp->e1->type, ta->index))
- {
- // Convert key to type of key
- exp->e1 = exp->e1->implicitCastTo(sc, ta->index);
- }
-
- semanticTypeInfo(sc, ta->index);
-
- // Return type is pointer to value
- exp->type = ta->nextOf()->pointerTo();
- break;
- }
-
- default:
- result = exp->incompatibleTypes();
- return;
-
- case Terror:
- return setError();
- }
- result = exp;
- }
-
- void visit(RemoveExp *e)
- {
- if (Expression *ex = binSemantic(e, sc))
- {
- result = ex;
- return;
- }
- result = e;
- }
-
- void visit(CmpExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- setNoderefOperands(exp);
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
- Type *t1 = exp->e1->type->toBasetype();
- Type *t2 = exp->e2->type->toBasetype();
- if ((t1->ty == Tclass && exp->e2->op == TOKnull) ||
- (t2->ty == Tclass && exp->e1->op == TOKnull))
- {
- exp->error("do not use null when comparing class types");
- return setError();
- }
-
- Expression *e = exp->op_overload(sc);
- if (e)
- {
- if (!e->type->isscalar() && e->type->equals(exp->e1->type))
- {
- exp->error("recursive opCmp expansion");
- return setError();
- }
- if (e->op == TOKcall)
- {
- e = new CmpExp(exp->op, exp->loc, e, new IntegerExp(exp->loc, 0, Type::tint32));
- e = expressionSemantic(e, sc);
- }
- result = e;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- bool f1 = checkNonAssignmentArrayOp(exp->e1);
- bool f2 = checkNonAssignmentArrayOp(exp->e2);
- if (f1 || f2)
- return setError();
-
- exp->type = Type::tbool;
-
- // Special handling for array comparisons
- t1 = exp->e1->type->toBasetype();
- t2 = exp->e2->type->toBasetype();
- if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) &&
- (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer))
- {
- Type *t1next = t1->nextOf();
- Type *t2next = t2->nextOf();
- if (t1next->implicitConvTo(t2next) < MATCHconst &&
- t2next->implicitConvTo(t1next) < MATCHconst &&
- (t1next->ty != Tvoid && t2next->ty != Tvoid))
- {
- exp->error("array comparison type mismatch, %s vs %s", t1next->toChars(), t2next->toChars());
- return setError();
- }
- if ((t1->ty == Tarray || t1->ty == Tsarray) &&
- (t2->ty == Tarray || t2->ty == Tsarray))
- {
- semanticTypeInfo(sc, t1->nextOf());
- }
- }
- else if (t1->ty == Tstruct || t2->ty == Tstruct ||
- (t1->ty == Tclass && t2->ty == Tclass))
- {
- if (t2->ty == Tstruct)
- exp->error("need member function opCmp() for %s %s to compare", t2->toDsymbol(sc)->kind(), t2->toChars());
- else
- exp->error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars());
- return setError();
- }
- else if (t1->iscomplex() || t2->iscomplex())
- {
- exp->error("compare not defined for complex operands");
- return setError();
- }
- else if (t1->ty == Taarray || t2->ty == Taarray)
- {
- exp->error("%s is not defined for associative arrays", Token::toChars(exp->op));
- return setError();
- }
- else if (!target.isVectorOpSupported(t1, exp->op, t2))
- {
- result = exp->incompatibleTypes();
- return;
- }
- else
- {
- bool r1 = exp->e1->checkValue();
- bool r2 = exp->e2->checkValue();
- if (r1 || r2)
- return setError();
- }
-
- TOK altop;
- switch (exp->op)
- {
- // Refer rel_integral[] table
- case TOKunord: altop = TOKerror; break;
- case TOKlg: altop = TOKnotequal; break;
- case TOKleg: altop = TOKerror; break;
- case TOKule: altop = TOKle; break;
- case TOKul: altop = TOKlt; break;
- case TOKuge: altop = TOKge; break;
- case TOKug: altop = TOKgt; break;
- case TOKue: altop = TOKequal; break;
- default: altop = TOKreserved; break;
- }
- if (altop == TOKerror &&
- (t1->ty == Tarray || t1->ty == Tsarray ||
- t2->ty == Tarray || t2->ty == Tsarray))
- {
- exp->error("`%s` is not defined for array comparisons", Token::toChars(exp->op));
- return setError();
- }
- if (altop != TOKreserved)
- {
- if (!t1->isfloating())
- {
- if (altop == TOKerror)
- {
- const char *s = exp->op == TOKunord ? "false" : "true";
- exp->error("floating point operator `%s` always returns %s for non-floating comparisons",
- Token::toChars(exp->op), s);
- }
- else
- {
- exp->error("use `%s` for non-floating comparisons rather than floating point operator `%s`",
- Token::toChars(altop), Token::toChars(exp->op));
- }
- }
- else
- {
- exp->error("use std.math.isNaN to deal with NaN operands rather than floating point operator `%s`",
- Token::toChars(exp->op));
- }
- return setError();
- }
-
- //printf("CmpExp: %s, type = %s\n", e->toChars(), e->type->toChars());
- result = exp;
- }
-
- void visit(EqualExp *exp)
- {
- //printf("EqualExp::semantic('%s')\n", toChars());
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- setNoderefOperands(exp);
-
- if (Expression *e = binSemanticProp(exp, sc))
- {
- result = e;
- return;
- }
- if (exp->e1->op == TOKtype || exp->e2->op == TOKtype)
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- {
- Type *t1 = exp->e1->type;
- Type *t2 = exp->e2->type;
- if (t1->ty == Tenum && t2->ty == Tenum && !t1->equivalent(t2))
- exp->deprecation("Comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
- t1->toChars(), t2->toChars());
- }
-
- /* Before checking for operator overloading, check to see if we're
- * comparing the addresses of two statics. If so, we can just see
- * if they are the same symbol.
- */
- if (exp->e1->op == TOKaddress && exp->e2->op == TOKaddress)
- {
- AddrExp *ae1 = (AddrExp *)exp->e1;
- AddrExp *ae2 = (AddrExp *)exp->e2;
- if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar)
- {
- VarExp *ve1 = (VarExp *)ae1->e1;
- VarExp *ve2 = (VarExp *)ae2->e1;
-
- if (ve1->var == ve2->var)
- {
- // They are the same, result is 'true' for ==, 'false' for !=
- result = new IntegerExp(exp->loc, (exp->op == TOKequal), Type::tbool);
- return;
- }
- }
- }
-
- if (Expression *e = exp->op_overload(sc))
- {
- result = e;
- return;
- }
-
- if (Expression *e = typeCombine(exp, sc))
- {
- result = e;
- return;
- }
-
- bool f1 = checkNonAssignmentArrayOp(exp->e1);
- bool f2 = checkNonAssignmentArrayOp(exp->e2);
- if (f1 || f2)
- return setError();
-
- exp->type = Type::tbool;
-
- // Special handling for array comparisons
- if (!arrayTypeCompatible(exp->loc, exp->e1->type, exp->e2->type))
- {
- if (exp->e1->type != exp->e2->type && exp->e1->type->isfloating() && exp->e2->type->isfloating())
- {
- // Cast both to complex
- exp->e1 = exp->e1->castTo(sc, Type::tcomplex80);
- exp->e2 = exp->e2->castTo(sc, Type::tcomplex80);
- }
- }
- if (exp->e1->type->toBasetype()->ty == Taarray)
- semanticTypeInfo(sc, exp->e1->type->toBasetype());
-
- Type *t1 = exp->e1->type->toBasetype();
- Type *t2 = exp->e2->type->toBasetype();
-
- if (!target.isVectorOpSupported(t1, exp->op, t2))
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- result = exp;
- }
-
- void visit(IdentityExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- setNoderefOperands(exp);
-
- if (Expression *ex = binSemanticProp(exp, sc))
- {
- result = ex;
- return;
- }
-
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
-
- bool f1 = checkNonAssignmentArrayOp(exp->e1);
- bool f2 = checkNonAssignmentArrayOp(exp->e2);
- if (f1 || f2)
- return setError();
-
- if (exp->e1->op == TOKtype || exp->e2->op == TOKtype)
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- exp->type = Type::tbool;
-
- if (exp->e1->type != exp->e2->type && exp->e1->type->isfloating() && exp->e2->type->isfloating())
- {
- // Cast both to complex
- exp->e1 = exp->e1->castTo(sc, Type::tcomplex80);
- exp->e2 = exp->e2->castTo(sc, Type::tcomplex80);
- }
-
- Type *tb1 = exp->e1->type->toBasetype();
- Type *tb2 = exp->e2->type->toBasetype();
- if (!target.isVectorOpSupported(tb1, exp->op, tb2))
- {
- result = exp->incompatibleTypes();
- return;
- }
-
- result = exp;
- }
-
- void visit(CondExp *exp)
- {
- if (exp->type)
- {
- result = exp;
- return;
- }
-
- if (exp->econd->op == TOKdotid)
- ((DotIdExp *)exp->econd)->noderef = true;
-
- Expression *ec = expressionSemantic(exp->econd, sc);
- ec = resolveProperties(sc, ec);
- ec = ec->toBoolean(sc);
-
- unsigned cs0 = sc->callSuper;
- unsigned *fi0 = sc->saveFieldInit();
- Expression *e1x = expressionSemantic(exp->e1, sc);
- e1x = resolveProperties(sc, e1x);
-
- unsigned cs1 = sc->callSuper;
- unsigned *fi1 = sc->fieldinit;
- sc->callSuper = cs0;
- sc->fieldinit = fi0;
- Expression *e2x = expressionSemantic(exp->e2, sc);
- e2x = resolveProperties(sc, e2x);
-
- sc->mergeCallSuper(exp->loc, cs1);
- sc->mergeFieldInit(exp->loc, fi1);
-
- if (ec->op == TOKerror)
- {
- result = ec;
- return;
- }
- if (ec->type == Type::terror)
- return setError();
- exp->econd = ec;
-
- if (e1x->op == TOKerror)
- {
- result = e1x;
- return;
- }
- if (e1x->type == Type::terror)
- return setError();
- exp->e1 = e1x;
-
- if (e2x->op == TOKerror)
- {
- result = e2x;
- return;
- }
- if (e2x->type == Type::terror)
- return setError();
- exp->e2 = e2x;
-
- bool f0 = checkNonAssignmentArrayOp(exp->econd);
- bool f1 = checkNonAssignmentArrayOp(exp->e1);
- bool f2 = checkNonAssignmentArrayOp(exp->e2);
- if (f0 || f1 || f2)
- return setError();
-
- Type *t1 = exp->e1->type;
- Type *t2 = exp->e2->type;
- if (t1->ty == Tnoreturn)
- {
- exp->type = t2;
- }
- else if (t2->ty == Tnoreturn)
- {
- exp->type = t1;
- }
- // If either operand is void the result is void, we have to cast both
- // the expression to void so that we explicitly discard the expression
- // value if any (bugzilla 16598)
- else if (t1->ty == Tvoid || t2->ty == Tvoid)
- {
- exp->type = Type::tvoid;
- exp->e1 = exp->e1->castTo(sc, exp->type);
- exp->e2 = exp->e2->castTo(sc, exp->type);
- }
- else if (t1 == t2)
- exp->type = t1;
- else
- {
- if (Expression *ex = typeCombine(exp, sc))
- {
- result = ex;
- return;
- }
- switch (exp->e1->type->toBasetype()->ty)
- {
- case Tcomplex32:
- case Tcomplex64:
- case Tcomplex80:
- exp->e2 = exp->e2->castTo(sc, exp->e1->type);
- break;
- }
- switch (exp->e2->type->toBasetype()->ty)
- {
- case Tcomplex32:
- case Tcomplex64:
- case Tcomplex80:
- exp->e1 = exp->e1->castTo(sc, exp->e2->type);
- break;
- }
- if (exp->type->toBasetype()->ty == Tarray)
- {
- exp->e1 = exp->e1->castTo(sc, exp->type);
- exp->e2 = exp->e2->castTo(sc, exp->type);
- }
- }
- exp->type = exp->type->merge2();
-
- /* Bugzilla 14696: If either e1 or e2 contain temporaries which need dtor,
- * make them conditional.
- * Rewrite:
- * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
- * to:
- * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
- * and replace edtors of __tmp1 and __tmp2 with:
- * __tmp1->edtor --> __cond && __tmp1.dtor()
- * __tmp2->edtor --> __cond || __tmp2.dtor()
- */
- exp->hookDtors(sc);
-
- result = exp;
- }
-
- void visit(FileInitExp *e)
- {
- //printf("FileInitExp::semantic()\n");
- e->type = Type::tstring;
- result = e;
- }
-
- void visit(LineInitExp *e)
- {
- e->type = Type::tint32;
- result = e;
- }
-
- void visit(ModuleInitExp *e)
- {
- //printf("ModuleInitExp::semantic()\n");
- e->type = Type::tstring;
- result = e;
- }
-
- void visit(FuncInitExp *e)
- {
- //printf("FuncInitExp::semantic()\n");
- e->type = Type::tstring;
- if (sc->func)
- {
- result = e->resolveLoc(Loc(), sc);
- return;
- }
- result = e;
- }
-
- void visit(PrettyFuncInitExp *e)
- {
- //printf("PrettyFuncInitExp::semantic()\n");
- e->type = Type::tstring;
- if (sc->func)
- {
- result = e->resolveLoc(Loc(), sc);
- return;
- }
- result = e;
- }
-};
-
-/**********************************
- * Try to run semantic routines.
- * If they fail, return NULL.
- */
-Expression *trySemantic(Expression *exp, Scope* sc)
-{
- //printf("+trySemantic(%s)\n", toChars());
- unsigned errors = global.startGagging();
- Expression *e = expressionSemantic(exp, sc);
- if (global.endGagging(errors))
- {
- e = NULL;
- }
- //printf("-trySemantic(%s)\n", toChars());
- return e;
-}
-
-/**************************
- * Helper function for easy error propagation.
- * If error occurs, returns ErrorExp. Otherwise returns NULL.
- */
-Expression *unaSemantic(UnaExp *e, Scope *sc)
-{
- Expression *e1x = expressionSemantic(e->e1, sc);
- if (e1x->op == TOKerror)
- return e1x;
- e->e1 = e1x;
- return NULL;
-}
-
-/**************************
- * Helper function for easy error propagation.
- * If error occurs, returns ErrorExp. Otherwise returns NULL.
- */
-Expression *binSemantic(BinExp *e, Scope *sc)
-{
- Expression *e1x = expressionSemantic(e->e1, sc);
- Expression *e2x = expressionSemantic(e->e2, sc);
-
- // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (e1x->op == TOKtype)
- e1x = resolveAliasThis(sc, e1x);
- if (e2x->op == TOKtype)
- e2x = resolveAliasThis(sc, e2x);
-
- if (e1x->op == TOKerror)
- return e1x;
- if (e2x->op == TOKerror)
- return e2x;
- e->e1 = e1x;
- e->e2 = e2x;
- return NULL;
-}
-
-Expression *binSemanticProp(BinExp *e, Scope *sc)
-{
- if (Expression *ex = binSemantic(e, sc))
- return ex;
- Expression *e1x = resolveProperties(sc, e->e1);
- Expression *e2x = resolveProperties(sc, e->e2);
- if (e1x->op == TOKerror)
- return e1x;
- if (e2x->op == TOKerror)
- return e2x;
- e->e1 = e1x;
- e->e2 = e2x;
- return NULL;
-}
-
-// entrypoint for semantic ExpressionSemanticVisitor
-Expression *expressionSemantic(Expression *e, Scope *sc)
-{
- ExpressionSemanticVisitor v = ExpressionSemanticVisitor(sc);
- e->accept(&v);
- return v.result;
-}
-
-Expression *semanticX(DotIdExp *exp, Scope *sc)
-{
- //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
- if (Expression *ex = unaSemantic(exp, sc))
- return ex;
-
- if (exp->ident == Id::_mangleof)
- {
- // symbol.mangleof
- Dsymbol *ds;
- switch (exp->e1->op)
- {
- case TOKscope:
- ds = ((ScopeExp *)exp->e1)->sds;
- goto L1;
- case TOKvar:
- ds = ((VarExp *)exp->e1)->var;
- goto L1;
- case TOKdotvar:
- ds = ((DotVarExp *)exp->e1)->var;
- goto L1;
- case TOKoverloadset:
- ds = ((OverExp *)exp->e1)->vars;
- goto L1;
- case TOKtemplate:
- {
- TemplateExp *te = (TemplateExp *)exp->e1;
- ds = te->fd ? (Dsymbol *)te->fd : te->td;
- }
- L1:
- {
- assert(ds);
- if (FuncDeclaration *f = ds->isFuncDeclaration())
- {
- if (f->checkForwardRef(exp->loc))
- return new ErrorExp();
- }
- OutBuffer buf;
- mangleToBuffer(ds, &buf);
- const char *s = buf.extractChars();
- Expression *e = new StringExp(exp->loc, const_cast<char*>(s), strlen(s));
- e = expressionSemantic(e, sc);
- return e;
- }
- default:
- break;
- }
- }
-
- if (exp->e1->op == TOKvar && exp->e1->type->toBasetype()->ty == Tsarray && exp->ident == Id::length)
- {
- // bypass checkPurity
- return exp->e1->type->dotExp(sc, exp->e1, exp->ident, exp->noderef ? 2 : 0);
- }
-
- if (exp->e1->op == TOKdot)
- {
- }
- else
- {
- exp->e1 = resolvePropertiesX(sc, exp->e1);
- }
- if (exp->e1->op == TOKtuple && exp->ident == Id::offsetof)
- {
- /* 'distribute' the .offsetof to each of the tuple elements.
- */
- TupleExp *te = (TupleExp *)exp->e1;
- Expressions *exps = new Expressions();
- exps->setDim(te->exps->length);
- for (size_t i = 0; i < exps->length; i++)
- {
- Expression *e = (*te->exps)[i];
- e = expressionSemantic(e, sc);
- e = new DotIdExp(e->loc, e, Id::offsetof);
- (*exps)[i] = e;
- }
- // Don't evaluate te->e0 in runtime
- Expression *e = new TupleExp(exp->loc, NULL, exps);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (exp->e1->op == TOKtuple && exp->ident == Id::length)
- {
- TupleExp *te = (TupleExp *)exp->e1;
- // Don't evaluate te->e0 in runtime
- Expression *e = new IntegerExp(exp->loc, te->exps->length, Type::tsize_t);
- return e;
- }
-
- // Bugzilla 14416: Template has no built-in properties except for 'stringof'.
- if ((exp->e1->op == TOKdottd || exp->e1->op == TOKtemplate) && exp->ident != Id::stringof)
- {
- exp->error("template %s does not have property `%s`", exp->e1->toChars(), exp->ident->toChars());
- return new ErrorExp();
- }
-
- if (!exp->e1->type)
- {
- exp->error("expression %s does not have property `%s`", exp->e1->toChars(), exp->ident->toChars());
- return new ErrorExp();
- }
-
- return exp;
-}
-
-// Resolve e1.ident without seeing UFCS.
-// If flag == 1, stop "not a property" error and return NULL.
-Expression *semanticY(DotIdExp *exp, Scope *sc, int flag)
-{
- //printf("DotIdExp::semanticY(this = %p, '%s')\n", this, toChars());
-
- //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
-
- /* Special case: rewrite this.id and super.id
- * to be classtype.id and baseclasstype.id
- * if we have no this pointer.
- */
- if ((exp->e1->op == TOKthis || exp->e1->op == TOKsuper) && !hasThis(sc))
- {
- if (AggregateDeclaration *ad = sc->getStructClassScope())
- {
- if (exp->e1->op == TOKthis)
- {
- exp->e1 = new TypeExp(exp->e1->loc, ad->type);
- }
- else
- {
- ClassDeclaration *cd = ad->isClassDeclaration();
- if (cd && cd->baseClass)
- exp->e1 = new TypeExp(exp->e1->loc, cd->baseClass->type);
- }
- }
- }
-
- Expression *e = semanticX(exp, sc);
- if (e != exp)
- return e;
-
- Expression *eleft;
- Expression *eright;
- if (exp->e1->op == TOKdot)
- {
- DotExp *de = (DotExp *)exp->e1;
- eleft = de->e1;
- eright = de->e2;
- }
- else
- {
- eleft = NULL;
- eright = exp->e1;
- }
-
- Type *t1b = exp->e1->type->toBasetype();
-
- if (eright->op == TOKscope) // also used for template alias's
- {
- ScopeExp *ie = (ScopeExp *)eright;
- int flags = SearchLocalsOnly;
-
- /* Disable access to another module's private imports.
- * The check for 'is sds our current module' is because
- * the current module should have access to its own imports.
- */
- if (ie->sds->isModule() && ie->sds != sc->_module)
- flags |= IgnorePrivateImports;
- if (sc->flags & SCOPEignoresymbolvisibility)
- flags |= IgnoreSymbolVisibility;
- Dsymbol *s = ie->sds->search(exp->loc, exp->ident, flags);
- /* Check for visibility before resolving aliases because public
- * aliases to private symbols are public.
- */
- if (s && !(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc->_module, s))
- {
- s = NULL;
- }
- if (s)
- {
- Package *p = s->isPackage();
- if (p && checkAccess(sc, p))
- {
- s = NULL;
- }
- }
- if (s)
- {
- // if 's' is a tuple variable, the tuple is returned.
- s = s->toAlias();
-
- exp->checkDeprecated(sc, s);
- exp->checkDisabled(sc, s);
-
- EnumMember *em = s->isEnumMember();
- if (em)
- {
- return em->getVarExp(exp->loc, sc);
- }
-
- VarDeclaration *v = s->isVarDeclaration();
- if (v)
- {
- //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars());
- if (!v->type ||
- (!v->type->deco && v->inuse))
- {
- if (v->inuse)
- exp->error("circular reference to %s `%s`", v->kind(), v->toPrettyChars());
- else
- exp->error("forward reference to %s `%s`", v->kind(), v->toPrettyChars());
- return new ErrorExp();
- }
- if (v->type->ty == Terror)
- return new ErrorExp();
-
- if ((v->storage_class & STCmanifest) && v->_init && !exp->wantsym)
- {
- /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
- * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
- * be reverted. `wantsym` is the hack to work around the problem.
- */
- if (v->inuse)
- {
- ::error(exp->loc, "circular initialization of %s `%s`", v->kind(), v->toPrettyChars());
- return new ErrorExp();
- }
- e = v->expandInitializer(exp->loc);
- v->inuse++;
- e = expressionSemantic(e, sc);
- v->inuse--;
- return e;
- }
-
- if (v->needThis())
- {
- if (!eleft)
- eleft = new ThisExp(exp->loc);
- e = new DotVarExp(exp->loc, eleft, v);
- e = expressionSemantic(e, sc);
- }
- else
- {
- e = new VarExp(exp->loc, v);
- if (eleft)
- { e = new CommaExp(exp->loc, eleft, e);
- e->type = v->type;
- }
- }
- e = e->deref();
- return expressionSemantic(e, sc);
- }
-
- FuncDeclaration *f = s->isFuncDeclaration();
- if (f)
- {
- //printf("it's a function\n");
- if (!f->functionSemantic())
- return new ErrorExp();
- if (f->needThis())
- {
- if (!eleft)
- eleft = new ThisExp(exp->loc);
- e = new DotVarExp(exp->loc, eleft, f, true);
- e = expressionSemantic(e, sc);
- }
- else
- {
- e = new VarExp(exp->loc, f, true);
- if (eleft)
- { e = new CommaExp(exp->loc, eleft, e);
- e->type = f->type;
- }
- }
- return e;
- }
- if (TemplateDeclaration *td = s->isTemplateDeclaration())
- {
- if (eleft)
- e = new DotTemplateExp(exp->loc, eleft, td);
- else
- e = new TemplateExp(exp->loc, td);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (OverDeclaration *od = s->isOverDeclaration())
- {
- e = new VarExp(exp->loc, od, true);
- if (eleft)
- {
- e = new CommaExp(exp->loc, eleft, e);
- e->type = Type::tvoid; // ambiguous type?
- }
- return e;
- }
- OverloadSet *o = s->isOverloadSet();
- if (o)
- { //printf("'%s' is an overload set\n", o->toChars());
- return new OverExp(exp->loc, o);
- }
-
- if (Type *t = s->getType())
- {
- return expressionSemantic(new TypeExp(exp->loc, t), sc);
- }
-
- TupleDeclaration *tup = s->isTupleDeclaration();
- if (tup)
- {
- if (eleft)
- {
- e = new DotVarExp(exp->loc, eleft, tup);
- e = expressionSemantic(e, sc);
- return e;
- }
- e = new TupleExp(exp->loc, tup);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- ScopeDsymbol *sds = s->isScopeDsymbol();
- if (sds)
- {
- //printf("it's a ScopeDsymbol %s\n", exp->ident->toChars());
- e = new ScopeExp(exp->loc, sds);
- e = expressionSemantic(e, sc);
- if (eleft)
- e = new DotExp(exp->loc, eleft, e);
- return e;
- }
-
- Import *imp = s->isImport();
- if (imp)
- {
- ie = new ScopeExp(exp->loc, imp->pkg);
- return expressionSemantic(ie, sc);
- }
-
- // BUG: handle other cases like in IdentifierExp::semantic()
- assert(0);
- }
- else if (exp->ident == Id::stringof)
- {
- const char *p = ie->toChars();
- e = new StringExp(exp->loc, const_cast<char *>(p), strlen(p));
- e = expressionSemantic(e, sc);
- return e;
- }
- if (ie->sds->isPackage() ||
- ie->sds->isImport() ||
- ie->sds->isModule())
- {
- flag = 0;
- }
- if (flag)
- return NULL;
- s = ie->sds->search_correct(exp->ident);
- if (s)
- {
- if (s->isPackage())
- exp->error("undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`",
- exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars(), s->toPrettyChars());
- else
- exp->error("undefined identifier `%s` in %s `%s`, did you mean %s `%s`?",
- exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars(), s->kind(), s->toChars());
- }
- else
- exp->error("undefined identifier `%s` in %s `%s`",
- exp->ident->toChars(), ie->sds->kind(), ie->sds->toPrettyChars());
- return new ErrorExp();
- }
- else if (t1b->ty == Tpointer && exp->e1->type->ty != Tenum &&
- exp->ident != Id::_init && exp->ident != Id::__sizeof &&
- exp->ident != Id::__xalignof && exp->ident != Id::offsetof &&
- exp->ident != Id::_mangleof && exp->ident != Id::stringof)
- {
- Type *t1bn = t1b->nextOf();
- if (flag)
- {
- AggregateDeclaration *ad = isAggregate(t1bn);
- if (ad && !ad->members) // Bugzilla 11312
- return NULL;
- }
-
- /* Rewrite:
- * p.ident
- * as:
- * (*p).ident
- */
- if (flag && t1bn->ty == Tvoid)
- return NULL;
- e = new PtrExp(exp->loc, exp->e1);
- e = expressionSemantic(e, sc);
- return e->type->dotExp(sc, e, exp->ident, flag | (exp->noderef ? 2 : 0));
- }
- else
- {
- if (exp->e1->op == TOKtype || exp->e1->op == TOKtemplate)
- flag = 0;
- e = exp->e1->type->dotExp(sc, exp->e1, exp->ident, flag | (exp->noderef ? 2 : 0));
- if (e)
- e = expressionSemantic(e, sc);
- return e;
- }
-}
-
-// Resolve e1.ident!tiargs without seeing UFCS.
-// If flag == 1, stop "not a property" error and return NULL.
-Expression *semanticY(DotTemplateInstanceExp *exp, Scope *sc, int flag)
-{
- DotIdExp *die = new DotIdExp(exp->loc, exp->e1, exp->ti->name);
-
- Expression *e = semanticX(die, sc);
- if (e == die)
- {
- exp->e1 = die->e1; // take back
-
- Type *t1b = exp->e1->type->toBasetype();
- if (t1b->ty == Tarray || t1b->ty == Tsarray || t1b->ty == Taarray ||
- t1b->ty == Tnull || (t1b->isTypeBasic() && t1b->ty != Tvoid))
- {
- /* No built-in type has templatized properties, so do shortcut.
- * It is necessary in: 1024.max!"a < b"
- */
- if (flag)
- return NULL;
- }
- e = semanticY(die, sc, flag);
- if (flag && e && isDotOpDispatch(e))
- {
- /* opDispatch!tiargs would be a function template that needs IFTI,
- * so it's not a template
- */
- e = NULL; /* fall down to UFCS */
- }
- if (flag && !e)
- return NULL;
- }
- assert(e);
-
- if (e->op == TOKerror)
- return e;
- if (e->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp *)e;
- if (FuncDeclaration *fd = dve->var->isFuncDeclaration())
- {
- TemplateDeclaration *td = fd->findTemplateDeclRoot();
- if (td)
- {
- e = new DotTemplateExp(dve->loc, dve->e1, td);
- e = expressionSemantic(e, sc);
- }
- }
- else if (dve->var->isOverDeclaration())
- {
- exp->e1 = dve->e1; // pull semantic() result
- if (!exp->findTempDecl(sc))
- goto Lerr;
- if (exp->ti->needsTypeInference(sc))
- return exp;
- dsymbolSemantic(exp->ti, sc);
- if (!exp->ti->inst || exp->ti->errors) // if template failed to expand
- return new ErrorExp();
- Dsymbol *s = exp->ti->toAlias();
- Declaration *v = s->isDeclaration();
- if (v)
- {
- if (v->type && !v->type->deco)
- v->type = typeSemantic(v->type, v->loc, sc);
- e = new DotVarExp(exp->loc, exp->e1, v);
- e = expressionSemantic(e, sc);
- return e;
- }
- e = new ScopeExp(exp->loc, exp->ti);
- e = new DotExp(exp->loc, exp->e1, e);
- e = expressionSemantic(e, sc);
- return e;
- }
- }
- else if (e->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e;
- if (FuncDeclaration *fd = ve->var->isFuncDeclaration())
- {
- TemplateDeclaration *td = fd->findTemplateDeclRoot();
- if (td)
- {
- e = new TemplateExp(ve->loc, td);
- e = expressionSemantic(e, sc);
- }
- }
- else if (OverDeclaration *od = ve->var->isOverDeclaration())
- {
- exp->ti->tempdecl = od;
- e = new ScopeExp(exp->loc, exp->ti);
- e = expressionSemantic(e, sc);
- return e;
- }
- }
- if (e->op == TOKdottd)
- {
- DotTemplateExp *dte = (DotTemplateExp *)e;
- exp->e1 = dte->e1; // pull semantic() result
-
- exp->ti->tempdecl = dte->td;
- if (!exp->ti->semanticTiargs(sc))
- return new ErrorExp();
- if (exp->ti->needsTypeInference(sc))
- return exp;
- dsymbolSemantic(exp->ti, sc);
- if (!exp->ti->inst || exp->ti->errors) // if template failed to expand
- return new ErrorExp();
- Dsymbol *s = exp->ti->toAlias();
- Declaration *v = s->isDeclaration();
- if (v && (v->isFuncDeclaration() || v->isVarDeclaration()))
- {
- e = new DotVarExp(exp->loc, exp->e1, v);
- e = expressionSemantic(e, sc);
- return e;
- }
- e = new ScopeExp(exp->loc, exp->ti);
- e = new DotExp(exp->loc, exp->e1, e);
- e = expressionSemantic(e, sc);
- return e;
- }
- else if (e->op == TOKtemplate)
- {
- exp->ti->tempdecl = ((TemplateExp *)e)->td;
- e = new ScopeExp(exp->loc, exp->ti);
- e = expressionSemantic(e, sc);
- return e;
- }
- else if (e->op == TOKdot)
- {
- DotExp *de = (DotExp *)e;
-
- if (de->e2->op == TOKoverloadset)
- {
- if (!exp->findTempDecl(sc) ||
- !exp->ti->semanticTiargs(sc))
- {
- return new ErrorExp();
- }
- if (exp->ti->needsTypeInference(sc))
- return exp;
- dsymbolSemantic(exp->ti, sc);
- if (!exp->ti->inst || exp->ti->errors) // if template failed to expand
- return new ErrorExp();
- Dsymbol *s = exp->ti->toAlias();
- Declaration *v = s->isDeclaration();
- if (v)
- {
- if (v->type && !v->type->deco)
- v->type = typeSemantic(v->type, v->loc, sc);
- e = new DotVarExp(exp->loc, exp->e1, v);
- e = expressionSemantic(e, sc);
- return e;
- }
- e = new ScopeExp(exp->loc, exp->ti);
- e = new DotExp(exp->loc, exp->e1, e);
- e = expressionSemantic(e, sc);
- return e;
- }
- }
- else if (e->op == TOKoverloadset)
- {
- OverExp *oe = (OverExp *)e;
- exp->ti->tempdecl = oe->vars;
- e = new ScopeExp(exp->loc, exp->ti);
- e = expressionSemantic(e, sc);
- return e;
- }
-Lerr:
- e->error("%s isn't a template", e->toChars());
- return new ErrorExp();
-}
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
new file mode 100644
index 0000000..3b604af
--- /dev/null
+++ b/gcc/d/dmd/expressionsem.d
@@ -0,0 +1,13058 @@
+/**
+ * Semantic analysis of expressions.
+ *
+ * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d, _expressionsem.d)
+ * Documentation: https://dlang.org/phobos/dmd_expressionsem.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expressionsem.d
+ */
+
+module dmd.expressionsem;
+
+import core.stdc.stdio;
+
+import dmd.access;
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arrayop;
+import dmd.arraytypes;
+import dmd.attrib;
+import dmd.astcodegen;
+import dmd.astenums;
+import dmd.canthrow;
+import dmd.chkformat;
+import dmd.ctorflow;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.declaration;
+import dmd.dclass;
+import dmd.dcast;
+import dmd.delegatize;
+import dmd.denum;
+import dmd.dimport;
+import dmd.dinterpret;
+import dmd.dmangle;
+import dmd.dmodule;
+import dmd.dstruct;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.escape;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.imphint;
+import dmd.init;
+import dmd.initsem;
+import dmd.inline;
+import dmd.intrange;
+import dmd.mtype;
+import dmd.nspace;
+import dmd.opover;
+import dmd.optimize;
+import dmd.parse;
+import dmd.printast;
+import dmd.root.ctfloat;
+import dmd.root.file;
+import dmd.root.filename;
+import dmd.root.outbuffer;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.semantic2;
+import dmd.semantic3;
+import dmd.sideeffect;
+import dmd.safe;
+import dmd.target;
+import dmd.tokens;
+import dmd.traits;
+import dmd.typesem;
+import dmd.typinf;
+import dmd.utf;
+import dmd.utils;
+import dmd.visitor;
+
+enum LOGSEMANTIC = false;
+
+/********************************************************
+ * Perform semantic analysis and CTFE on expressions to produce
+ * a string.
+ * Params:
+ * buf = append generated string to buffer
+ * sc = context
+ * exps = array of Expressions
+ * Returns:
+ * true on error
+ */
+bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
+{
+ if (!exps)
+ return false;
+
+ foreach (ex; *exps)
+ {
+ if (!ex)
+ continue;
+ auto sc2 = sc.startCTFE();
+ auto e2 = ex.expressionSemantic(sc2);
+ auto e3 = resolveProperties(sc2, e2);
+ sc2.endCTFE();
+
+ // allowed to contain types as well as expressions
+ auto e4 = ctfeInterpretForPragmaMsg(e3);
+ if (!e4 || e4.op == TOK.error)
+ return true;
+
+ // expand tuple
+ if (auto te = e4.isTupleExp())
+ {
+ if (expressionsToString(buf, sc, te.exps))
+ return true;
+ continue;
+ }
+ // char literals exp `.toStringExp` return `null` but we cant override it
+ // because in most contexts we don't want the conversion to succeed.
+ IntegerExp ie = e4.isIntegerExp();
+ const ty = (ie && ie.type) ? ie.type.ty : Terror;
+ if (ty.isSomeChar)
+ {
+ auto tsa = new TypeSArray(ie.type, IntegerExp.literal!1);
+ e4 = new ArrayLiteralExp(ex.loc, tsa, ie);
+ }
+
+ if (StringExp se = e4.toStringExp())
+ buf.writestring(se.toUTF8(sc).peekString());
+ else
+ buf.writestring(e4.toString());
+ }
+ return false;
+}
+
+
+/***********************************************************
+ * Resolve `exp` as a compile-time known string.
+ * Params:
+ * sc = scope
+ * exp = Expression which expected as a string
+ * s = What the string is expected for, will be used in error diagnostic.
+ * Returns:
+ * String literal, or `null` if error happens.
+ */
+StringExp semanticString(Scope *sc, Expression exp, const char* s)
+{
+ sc = sc.startCTFE();
+ exp = exp.expressionSemantic(sc);
+ exp = resolveProperties(sc, exp);
+ sc = sc.endCTFE();
+
+ if (exp.op == TOK.error)
+ return null;
+
+ auto e = exp;
+ if (exp.type.isString())
+ {
+ e = e.ctfeInterpret();
+ if (e.op == TOK.error)
+ return null;
+ }
+
+ auto se = e.toStringExp();
+ if (!se)
+ {
+ exp.error("`string` expected for %s, not `(%s)` of type `%s`",
+ s, exp.toChars(), exp.type.toChars());
+ return null;
+ }
+ return se;
+}
+
+private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
+{
+ Expression e0;
+ Expression e1 = Expression.extractLast(ue.e1, e0);
+ // https://issues.dlang.org/show_bug.cgi?id=12585
+ // Extract the side effect part if ue.e1 is comma.
+
+ if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
+ {
+ /* Even if opDollar is needed, 'e1' should be evaluate only once. So
+ * Rewrite:
+ * e1.opIndex( ... use of $ ... )
+ * e1.opSlice( ... use of $ ... )
+ * as:
+ * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
+ * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
+ */
+ e1 = extractSideEffect(sc, "__dop", e0, e1, false);
+ assert(e1.isVarExp());
+ e1.isVarExp().var.storage_class |= STC.exptemp; // lifetime limited to expression
+ }
+ ue.e1 = e1;
+ return e0;
+}
+
+/**************************************
+ * Runs semantic on ae.arguments. Declares temporary variables
+ * if '$' was used.
+ */
+Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
+{
+ assert(!ae.lengthVar);
+ *pe0 = null;
+ AggregateDeclaration ad = isAggregate(ae.e1.type);
+ Dsymbol slice = search_function(ad, Id.slice);
+ //printf("slice = %s %s\n", slice.kind(), slice.toChars());
+ foreach (i, e; *ae.arguments)
+ {
+ if (i == 0)
+ *pe0 = extractOpDollarSideEffect(sc, ae);
+
+ if (e.op == TOK.interval && !(slice && slice.isTemplateDeclaration()))
+ {
+ Lfallback:
+ if (ae.arguments.dim == 1)
+ return null;
+ ae.error("multi-dimensional slicing requires template `opSlice`");
+ return ErrorExp.get();
+ }
+ //printf("[%d] e = %s\n", i, e.toChars());
+
+ // Create scope for '$' variable for this dimension
+ auto sym = new ArrayScopeSymbol(sc, ae);
+ sym.parent = sc.scopesym;
+ sc = sc.push(sym);
+ ae.lengthVar = null; // Create it only if required
+ ae.currentDimension = i; // Dimension for $, if required
+
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+
+ if (ae.lengthVar && sc.func)
+ {
+ // If $ was used, declare it now
+ Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
+ de = de.expressionSemantic(sc);
+ *pe0 = Expression.combine(*pe0, de);
+ }
+ sc = sc.pop();
+
+ if (auto ie = e.isIntervalExp())
+ {
+ auto tiargs = new Objects();
+ Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t);
+ edim = edim.expressionSemantic(sc);
+ tiargs.push(edim);
+
+ auto fargs = new Expressions(2);
+ (*fargs)[0] = ie.lwr;
+ (*fargs)[1] = ie.upr;
+
+ uint xerrors = global.startGagging();
+ sc = sc.push();
+ FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, fargs, FuncResolveFlag.quiet);
+ sc = sc.pop();
+ global.endGagging(xerrors);
+ if (!fslice)
+ goto Lfallback;
+
+ e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs);
+ e = new CallExp(ae.loc, e, fargs);
+ e = e.expressionSemantic(sc);
+ }
+
+ if (!e.type)
+ {
+ ae.error("`%s` has no value", e.toChars());
+ e = ErrorExp.get();
+ }
+ if (e.op == TOK.error)
+ return e;
+
+ (*ae.arguments)[i] = e;
+ }
+ return ae;
+}
+
+/**************************************
+ * Runs semantic on se.lwr and se.upr. Declares a temporary variable
+ * if '$' was used.
+ * Returns:
+ * ae, or ErrorExp if errors occurred
+ */
+Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0)
+{
+ //assert(!ae.lengthVar);
+ if (!ie)
+ return ae;
+
+ VarDeclaration lengthVar = ae.lengthVar;
+ bool errors = false;
+
+ // create scope for '$'
+ auto sym = new ArrayScopeSymbol(sc, ae);
+ sym.parent = sc.scopesym;
+ sc = sc.push(sym);
+
+ Expression sem(Expression e)
+ {
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ if (!e.type)
+ {
+ ae.error("`%s` has no value", e.toChars());
+ errors = true;
+ }
+ return e;
+ }
+
+ ie.lwr = sem(ie.lwr);
+ ie.upr = sem(ie.upr);
+
+ if (lengthVar != ae.lengthVar && sc.func)
+ {
+ // If $ was used, declare it now
+ Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
+ de = de.expressionSemantic(sc);
+ *pe0 = Expression.combine(*pe0, de);
+ }
+
+ sc = sc.pop();
+
+ return errors ? ErrorExp.get() : ae;
+}
+
+/******************************
+ * Perform semantic() on an array of Expressions.
+ */
+bool arrayExpressionSemantic(Expressions* exps, Scope* sc, bool preserveErrors = false)
+{
+ bool err = false;
+ if (exps)
+ {
+ foreach (ref e; *exps)
+ {
+ if (e)
+ {
+ auto e2 = e.expressionSemantic(sc);
+ if (e2.op == TOK.error)
+ err = true;
+ if (preserveErrors || e2.op != TOK.error)
+ e = e2;
+ }
+ }
+ }
+ return err;
+}
+
+/******************************
+ * Check the tail CallExp is really property function call.
+ * Bugs:
+ * This doesn't appear to do anything.
+ */
+private bool checkPropertyCall(Expression e)
+{
+ e = lastComma(e);
+
+ if (auto ce = e.isCallExp())
+ {
+ if (ce.f)
+ {
+ auto tf = ce.f.type.isTypeFunction();
+ /* If a forward reference to ce.f, try to resolve it
+ */
+ if (!tf.deco && ce.f.semanticRun < PASS.semanticdone)
+ {
+ ce.f.dsymbolSemantic(null);
+ tf = ce.f.type.isTypeFunction();
+ }
+ }
+ else if (!ce.e1.type.isFunction_Delegate_PtrToFunction())
+ assert(0);
+ }
+ return false;
+}
+
+/******************************
+ * Find symbol in accordance with the UFCS name look up rule
+ */
+private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
+{
+ //printf("searchUFCS(ident = %s)\n", ident.toChars());
+ Loc loc = ue.loc;
+
+ // TODO: merge with Scope.search.searchScopes()
+ Dsymbol searchScopes(int flags)
+ {
+ Dsymbol s = null;
+ for (Scope* scx = sc; scx; scx = scx.enclosing)
+ {
+ if (!scx.scopesym)
+ continue;
+ if (scx.scopesym.isModule())
+ flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
+ s = scx.scopesym.search(loc, ident, flags);
+ if (s)
+ {
+ // overload set contains only module scope symbols.
+ if (s.isOverloadSet())
+ break;
+ // selective/renamed imports also be picked up
+ if (AliasDeclaration ad = s.isAliasDeclaration())
+ {
+ if (ad._import)
+ break;
+ }
+ // See only module scope symbols for UFCS target.
+ Dsymbol p = s.toParent2();
+ if (p && p.isModule())
+ break;
+ }
+ s = null;
+
+ // Stop when we hit a module, but keep going if that is not just under the global scope
+ if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing))
+ break;
+ }
+ return s;
+ }
+
+ int flags = 0;
+ Dsymbol s;
+
+ if (sc.flags & SCOPE.ignoresymbolvisibility)
+ flags |= IgnoreSymbolVisibility;
+
+ // First look in local scopes
+ s = searchScopes(flags | SearchLocalsOnly);
+ if (!s)
+ {
+ // Second look in imported modules
+ s = searchScopes(flags | SearchImportsOnly);
+ }
+
+ if (!s)
+ return ue.e1.type.Type.getProperty(sc, loc, ident, 0);
+
+ FuncDeclaration f = s.isFuncDeclaration();
+ if (f)
+ {
+ TemplateDeclaration td = getFuncTemplateDecl(f);
+ if (td)
+ {
+ if (td.overroot)
+ td = td.overroot;
+ s = td;
+ }
+ }
+
+ if (auto dti = ue.isDotTemplateInstanceExp())
+ {
+ auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs);
+ if (!ti.updateTempDecl(sc, s))
+ return ErrorExp.get();
+ return new ScopeExp(loc, ti);
+ }
+ else
+ {
+ //printf("-searchUFCS() %s\n", s.toChars());
+ return new DsymbolExp(loc, s);
+ }
+}
+
+/******************************
+ * Pull out callable entity with UFCS.
+ */
+private Expression resolveUFCS(Scope* sc, CallExp ce)
+{
+ Loc loc = ce.loc;
+ Expression eleft;
+ Expression e;
+
+ if (auto die = ce.e1.isDotIdExp())
+ {
+ Identifier ident = die.ident;
+
+ Expression ex = die.semanticX(sc);
+ if (ex != die)
+ {
+ ce.e1 = ex;
+ return null;
+ }
+ eleft = die.e1;
+
+ Type t = eleft.type.toBasetype();
+ if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid))
+ {
+ /* Built-in types and arrays have no callable properties, so do shortcut.
+ * It is necessary in: e.init()
+ */
+ }
+ else if (t.ty == Taarray)
+ {
+ if (ident == Id.remove)
+ {
+ /* Transform:
+ * aa.remove(arg) into delete aa[arg]
+ */
+ if (!ce.arguments || ce.arguments.dim != 1)
+ {
+ ce.error("expected key as argument to `aa.remove()`");
+ return ErrorExp.get();
+ }
+ if (!eleft.type.isMutable())
+ {
+ ce.error("cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars());
+ return ErrorExp.get();
+ }
+ Expression key = (*ce.arguments)[0];
+ key = key.expressionSemantic(sc);
+ key = resolveProperties(sc, key);
+
+ TypeAArray taa = t.isTypeAArray();
+ key = key.implicitCastTo(sc, taa.index);
+
+ if (key.checkValue() || key.checkSharedAccess(sc))
+ return ErrorExp.get();
+
+ semanticTypeInfo(sc, taa.index);
+
+ return new RemoveExp(loc, eleft, key);
+ }
+ }
+ else
+ {
+ if (Expression ey = die.semanticY(sc, 1))
+ {
+ if (ey.op == TOK.error)
+ return ey;
+ ce.e1 = ey;
+ if (isDotOpDispatch(ey))
+ {
+ uint errors = global.startGagging();
+ e = ce.syntaxCopy().expressionSemantic(sc);
+ if (!global.endGagging(errors))
+ return e;
+
+ // even opDispatch and UFCS must have valid arguments,
+ // so now that we've seen indication of a problem,
+ // check them for issues.
+ Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments);
+
+ if (arrayExpressionSemantic(originalArguments, sc))
+ return ErrorExp.get();
+
+ /* fall down to UFCS */
+ }
+ else
+ return null;
+ }
+ }
+
+ /* https://issues.dlang.org/show_bug.cgi?id=13953
+ *
+ * If a struct has an alias this to an associative array
+ * and remove is used on a struct instance, we have to
+ * check first if there is a remove function that can be called
+ * on the struct. If not we must check the alias this.
+ *
+ * struct A
+ * {
+ * string[string] a;
+ * alias a this;
+ * }
+ *
+ * void fun()
+ * {
+ * A s;
+ * s.remove("foo");
+ * }
+ */
+ const errors = global.startGagging();
+ e = searchUFCS(sc, die, ident);
+ // if there were any errors and the identifier was remove
+ if (global.endGagging(errors))
+ {
+ if (ident == Id.remove)
+ {
+ // check alias this
+ Expression alias_e = resolveAliasThis(sc, die.e1, 1);
+ if (alias_e && alias_e != die.e1)
+ {
+ die.e1 = alias_e;
+ CallExp ce2 = ce.syntaxCopy();
+ ce2.e1 = die;
+ e = ce2.isCallExp().trySemantic(sc);
+ if (e)
+ return e;
+ }
+ }
+ // if alias this did not work out, print the initial errors
+ searchUFCS(sc, die, ident);
+ }
+ }
+ else if (auto dti = ce.e1.isDotTemplateInstanceExp())
+ {
+ if (Expression ey = dti.semanticY(sc, 1))
+ {
+ ce.e1 = ey;
+ return null;
+ }
+ eleft = dti.e1;
+ e = searchUFCS(sc, dti, dti.ti.name);
+ }
+ else
+ return null;
+
+ // Rewrite
+ ce.e1 = e;
+ if (!ce.arguments)
+ ce.arguments = new Expressions();
+ ce.arguments.shift(eleft);
+
+ return null;
+}
+
+/******************************
+ * Pull out property with UFCS.
+ */
+private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null)
+{
+ Loc loc = e1.loc;
+ Expression eleft;
+ Expression e;
+
+ if (auto die = e1.isDotIdExp())
+ {
+ eleft = die.e1;
+ e = searchUFCS(sc, die, die.ident);
+ }
+ else if (auto dti = e1.isDotTemplateInstanceExp())
+ {
+ eleft = dti.e1;
+ e = searchUFCS(sc, dti, dti.ti.name);
+ }
+ else
+ return null;
+
+ if (e is null)
+ return null;
+
+ // Rewrite
+ if (e2)
+ {
+ // run semantic without gagging
+ e2 = e2.expressionSemantic(sc);
+
+ /* f(e1) = e2
+ */
+ Expression ex = e.copy();
+ auto a1 = new Expressions(1);
+ (*a1)[0] = eleft;
+ ex = new CallExp(loc, ex, a1);
+ auto e1PassSemantic = ex.trySemantic(sc);
+
+ /* f(e1, e2)
+ */
+ auto a2 = new Expressions(2);
+ (*a2)[0] = eleft;
+ (*a2)[1] = e2;
+ e = new CallExp(loc, e, a2);
+ e = e.trySemantic(sc);
+ if (!e1PassSemantic && !e)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=20448
+ *
+ * If both versions have failed to pass semantic,
+ * f(e1) = e2 gets priority in error printing
+ * because f might be a templated function that
+ * failed to instantiate and we have to print
+ * the instantiation errors.
+ */
+ return e1.expressionSemantic(sc);
+ }
+ else if (ex && !e)
+ {
+ checkPropertyCall(ex);
+ ex = new AssignExp(loc, ex, e2);
+ return ex.expressionSemantic(sc);
+ }
+ else
+ {
+ // strict setter prints errors if fails
+ e = e.expressionSemantic(sc);
+ }
+ checkPropertyCall(e);
+ return e;
+ }
+ else
+ {
+ /* f(e1)
+ */
+ auto arguments = new Expressions(1);
+ (*arguments)[0] = eleft;
+ e = new CallExp(loc, e, arguments);
+ e = e.expressionSemantic(sc);
+ checkPropertyCall(e);
+ return e.expressionSemantic(sc);
+ }
+}
+
+/******************************
+ * If e1 is a property function (template), resolve it.
+ */
+Expression resolvePropertiesOnly(Scope* sc, Expression e1)
+{
+ //printf("e1 = %s %s\n", Token::toChars(e1.op), e1.toChars());
+
+ Expression handleOverloadSet(OverloadSet os)
+ {
+ assert(os);
+ foreach (s; os.a)
+ {
+ auto fd = s.isFuncDeclaration();
+ auto td = s.isTemplateDeclaration();
+ if (fd)
+ {
+ if (fd.type.isTypeFunction().isproperty)
+ return resolveProperties(sc, e1);
+ }
+ else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null)
+ {
+ if (fd.type.isTypeFunction().isproperty ||
+ (fd.storage_class2 & STC.property) ||
+ (td._scope.stc & STC.property))
+ return resolveProperties(sc, e1);
+ }
+ }
+ return e1;
+ }
+
+ Expression handleTemplateDecl(TemplateDeclaration td)
+ {
+ assert(td);
+ if (td.onemember)
+ {
+ if (auto fd = td.onemember.isFuncDeclaration())
+ {
+ if (fd.type.isTypeFunction().isproperty ||
+ (fd.storage_class2 & STC.property) ||
+ (td._scope.stc & STC.property))
+ return resolveProperties(sc, e1);
+ }
+ }
+ return e1;
+ }
+
+ Expression handleFuncDecl(FuncDeclaration fd)
+ {
+ assert(fd);
+ if (fd.type.isTypeFunction().isproperty)
+ return resolveProperties(sc, e1);
+ return e1;
+ }
+
+ if (auto de = e1.isDotExp())
+ {
+ if (auto os = de.e2.isOverExp())
+ return handleOverloadSet(os.vars);
+ }
+ else if (auto oe = e1.isOverExp())
+ return handleOverloadSet(oe.vars);
+ else if (auto dti = e1.isDotTemplateInstanceExp())
+ {
+ if (dti.ti.tempdecl)
+ if (auto td = dti.ti.tempdecl.isTemplateDeclaration())
+ return handleTemplateDecl(td);
+ }
+ else if (auto dte = e1.isDotTemplateExp())
+ return handleTemplateDecl(dte.td);
+ else if (auto se = e1.isScopeExp())
+ {
+ Dsymbol s = se.sds;
+ TemplateInstance ti = s.isTemplateInstance();
+ if (ti && !ti.semanticRun && ti.tempdecl)
+ if (auto td = ti.tempdecl.isTemplateDeclaration())
+ return handleTemplateDecl(td);
+ }
+ else if (auto et = e1.isTemplateExp())
+ return handleTemplateDecl(et.td);
+ else if (e1.isDotVarExp() && e1.type.isTypeFunction())
+ {
+ DotVarExp dve = e1.isDotVarExp();
+ return handleFuncDecl(dve.var.isFuncDeclaration());
+ }
+ else if (e1.isVarExp() && e1.type && e1.type.isTypeFunction() && (sc.intypeof || !e1.isVarExp().var.needThis()))
+ return handleFuncDecl(e1.isVarExp().var.isFuncDeclaration());
+ return e1;
+}
+
+/****************************************
+ * Turn symbol `s` into the expression it represents.
+ *
+ * Params:
+ * s = symbol to resolve
+ * loc = location of use of `s`
+ * sc = context
+ * hasOverloads = applies if `s` represents a function.
+ * true means it's overloaded and will be resolved later,
+ * false means it's the exact function symbol.
+ * Returns:
+ * `s` turned into an expression, `ErrorExp` if an error occurred
+ */
+Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads)
+{
+ static if (LOGSEMANTIC)
+ {
+ printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars());
+ }
+
+Lagain:
+ Expression e;
+
+ //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
+ //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
+ Dsymbol olds = s;
+ Declaration d = s.isDeclaration();
+ if (d && (d.storage_class & STC.templateparameter))
+ {
+ s = s.toAlias();
+ }
+ else
+ {
+ // functions are checked after overloading
+ // templates are checked after matching constraints
+ if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
+ {
+ s.checkDeprecated(loc, sc);
+ if (d)
+ d.checkDisabled(loc, sc);
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=12023
+ // if 's' is a tuple variable, the tuple is returned.
+ s = s.toAlias();
+
+ //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
+ if (s != olds && !s.isFuncDeclaration() && !s.isTemplateDeclaration())
+ {
+ s.checkDeprecated(loc, sc);
+ if (d)
+ d.checkDisabled(loc, sc);
+ }
+ }
+
+ if (auto em = s.isEnumMember())
+ {
+ return em.getVarExp(loc, sc);
+ }
+ if (auto v = s.isVarDeclaration())
+ {
+ //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
+ if (sc.intypeof == 1 && !v.inuse)
+ v.dsymbolSemantic(sc);
+ if (!v.type || // during variable type inference
+ !v.type.deco && v.inuse) // during variable type semantic
+ {
+ if (v.inuse) // variable type depends on the variable itself
+ error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
+ else // variable type cannot be determined
+ error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
+ return ErrorExp.get();
+ }
+ if (v.type.ty == Terror)
+ return ErrorExp.get();
+
+ if ((v.storage_class & STC.manifest) && v._init)
+ {
+ if (v.inuse)
+ {
+ error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
+ return ErrorExp.get();
+ }
+ e = v.expandInitializer(loc);
+ v.inuse++;
+ e = e.expressionSemantic(sc);
+ v.inuse--;
+ return e;
+ }
+
+ // We need to run semantics to correctly set 'STC.field' if it is a member variable
+ // that could be forward referenced. This is needed for 'v.needThis()' to work
+ if (v.isThis())
+ v.dsymbolSemantic(sc);
+
+ // Change the ancestor lambdas to delegate before hasThis(sc) call.
+ if (v.checkNestedReference(sc, loc))
+ return ErrorExp.get();
+
+ if (v.needThis() && hasThis(sc))
+ e = new DotVarExp(loc, new ThisExp(loc), v);
+ else
+ e = new VarExp(loc, v);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ if (auto fld = s.isFuncLiteralDeclaration())
+ {
+ //printf("'%s' is a function literal\n", fld.toChars());
+ e = new FuncExp(loc, fld);
+ return e.expressionSemantic(sc);
+ }
+ if (auto f = s.isFuncDeclaration())
+ {
+ f = f.toAliasFunc();
+ if (!f.functionSemantic())
+ return ErrorExp.get();
+
+ if (!hasOverloads && f.checkForwardRef(loc))
+ return ErrorExp.get();
+
+ auto fd = s.isFuncDeclaration();
+ fd.type = f.type;
+ return new VarExp(loc, fd, hasOverloads);
+ }
+ if (OverDeclaration od = s.isOverDeclaration())
+ {
+ e = new VarExp(loc, od, true);
+ e.type = Type.tvoid;
+ return e;
+ }
+ if (OverloadSet o = s.isOverloadSet())
+ {
+ //printf("'%s' is an overload set\n", o.toChars());
+ return new OverExp(loc, o);
+ }
+
+ if (Import imp = s.isImport())
+ {
+ if (!imp.pkg)
+ {
+ .error(loc, "forward reference of import `%s`", imp.toChars());
+ return ErrorExp.get();
+ }
+ auto ie = new ScopeExp(loc, imp.pkg);
+ return ie.expressionSemantic(sc);
+ }
+ if (Package pkg = s.isPackage())
+ {
+ auto ie = new ScopeExp(loc, pkg);
+ return ie.expressionSemantic(sc);
+ }
+ if (Module mod = s.isModule())
+ {
+ auto ie = new ScopeExp(loc, mod);
+ return ie.expressionSemantic(sc);
+ }
+ if (Nspace ns = s.isNspace())
+ {
+ auto ie = new ScopeExp(loc, ns);
+ return ie.expressionSemantic(sc);
+ }
+
+ if (Type t = s.getType())
+ {
+ return (new TypeExp(loc, t)).expressionSemantic(sc);
+ }
+
+ if (TupleDeclaration tup = s.isTupleDeclaration())
+ {
+ if (tup.needThis() && hasThis(sc))
+ e = new DotVarExp(loc, new ThisExp(loc), tup);
+ else
+ e = new TupleExp(loc, tup);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ if (TemplateInstance ti = s.isTemplateInstance())
+ {
+ ti.dsymbolSemantic(sc);
+ if (!ti.inst || ti.errors)
+ return ErrorExp.get();
+ s = ti.toAlias();
+ if (!s.isTemplateInstance())
+ goto Lagain;
+ e = new ScopeExp(loc, ti);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ if (TemplateDeclaration td = s.isTemplateDeclaration())
+ {
+ Dsymbol p = td.toParentLocal();
+ FuncDeclaration fdthis = hasThis(sc);
+ AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
+ if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
+ {
+ e = new DotTemplateExp(loc, new ThisExp(loc), td);
+ }
+ else
+ e = new TemplateExp(loc, td);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars());
+ return ErrorExp.get();
+}
+
+/*************************************************************
+ * Given var, get the
+ * right `this` pointer if var is in an outer class, but our
+ * existing `this` pointer is in an inner class.
+ * Params:
+ * loc = location to use for error messages
+ * sc = context
+ * ad = struct or class we need the correct `this` for
+ * e1 = existing `this`
+ * var = the specific member of ad we're accessing
+ * flag = if true, return `null` instead of throwing an error
+ * Returns:
+ * Expression representing the `this` for the var
+ */
+private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0)
+{
+ //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
+L1:
+ Type t = e1.type.toBasetype();
+ //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
+
+ if (e1.op == TOK.objcClassReference)
+ {
+ // We already have an Objective-C class reference, just use that as 'this'.
+ return e1;
+ }
+ else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc &&
+ var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
+ var.isFuncDeclaration.objc.selector)
+ {
+ return new ObjcClassReferenceExp(e1.loc, ad.isClassDeclaration());
+ }
+
+ /* Access of a member which is a template parameter in dual-scope scenario
+ * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
+ * class B {int m; inc() { new A().inc!m(); } }
+ */
+ if (e1.op == TOK.this_)
+ {
+ FuncDeclaration f = hasThis(sc);
+ if (f && f.isThis2)
+ {
+ if (f.followInstantiationContext(ad))
+ {
+ e1 = new VarExp(loc, f.vthis);
+ e1 = new PtrExp(loc, e1);
+ e1 = new IndexExp(loc, e1, IntegerExp.literal!1);
+ e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var);
+ if (e1.op == TOK.error)
+ return e1;
+ goto L1;
+ }
+ }
+ }
+
+ /* If e1 is not the 'this' pointer for ad
+ */
+ if (ad &&
+ !(t.isTypePointer() && t.nextOf().isTypeStruct() && t.nextOf().isTypeStruct().sym == ad) &&
+ !(t.isTypeStruct() && t.isTypeStruct().sym == ad))
+ {
+ ClassDeclaration cd = ad.isClassDeclaration();
+ ClassDeclaration tcd = t.isClassHandle();
+
+ /* e1 is the right this if ad is a base class of e1
+ */
+ if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null)))
+ {
+ /* Only classes can be inner classes with an 'outer'
+ * member pointing to the enclosing class instance
+ */
+ if (tcd && tcd.isNested())
+ {
+ /* e1 is the 'this' pointer for an inner class: tcd.
+ * Rewrite it as the 'this' pointer for the outer class.
+ */
+ auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
+ e1 = new DotVarExp(loc, e1, vthis);
+ e1.type = vthis.type;
+ e1.type = e1.type.addMod(t.mod);
+ // Do not call ensureStaticLinkTo()
+ //e1 = e1.semantic(sc);
+
+ // Skip up over nested functions, and get the enclosing
+ // class type.
+ e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var);
+ if (e1.op == TOK.error)
+ return e1;
+ goto L1;
+ }
+
+ /* Can't find a path from e1 to ad
+ */
+ if (flag)
+ return null;
+ e1.error("`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars());
+ return ErrorExp.get();
+ }
+ }
+ return e1;
+}
+
+/***************************************
+ * Pull out any properties.
+ */
+private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null)
+{
+ //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token.toChars(e1.op), e1.toChars(), e2 ? e2.toChars() : null);
+ Loc loc = e1.loc;
+
+ OverloadSet os;
+ Dsymbol s;
+ Objects* tiargs;
+ Type tthis;
+ if (auto de = e1.isDotExp())
+ {
+ if (auto oe = de.e2.isOverExp())
+ {
+ tiargs = null;
+ tthis = de.e1.type;
+ os = oe.vars;
+ goto Los;
+ }
+ }
+ else if (e1.isOverExp())
+ {
+ tiargs = null;
+ tthis = null;
+ os = e1.isOverExp().vars;
+ Los:
+ assert(os);
+ FuncDeclaration fd = null;
+ if (e2)
+ {
+ e2 = e2.expressionSemantic(sc);
+ if (e2.op == TOK.error)
+ return ErrorExp.get();
+ e2 = resolveProperties(sc, e2);
+
+ Expressions a;
+ a.push(e2);
+
+ for (size_t i = 0; i < os.a.dim; i++)
+ {
+ if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, &a, FuncResolveFlag.quiet))
+ {
+ if (f.errors)
+ return ErrorExp.get();
+ fd = f;
+ assert(fd.type.ty == Tfunction);
+ }
+ }
+ if (fd)
+ {
+ Expression e = new CallExp(loc, e1, e2);
+ return e.expressionSemantic(sc);
+ }
+ }
+ {
+ for (size_t i = 0; i < os.a.dim; i++)
+ {
+ if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, null, FuncResolveFlag.quiet))
+ {
+ if (f.errors)
+ return ErrorExp.get();
+ fd = f;
+ assert(fd.type.ty == Tfunction);
+ auto tf = fd.type.isTypeFunction();
+ if (!tf.isref && e2)
+ {
+ error(loc, "%s is not an lvalue", e1.toChars());
+ return ErrorExp.get();
+ }
+ }
+ }
+ if (fd)
+ {
+ Expression e = new CallExp(loc, e1);
+ if (e2)
+ e = new AssignExp(loc, e, e2);
+ return e.expressionSemantic(sc);
+ }
+ }
+ if (e2)
+ goto Leprop;
+ }
+ else if (auto dti = e1.isDotTemplateInstanceExp())
+ {
+ if (!dti.findTempDecl(sc))
+ goto Leprop;
+ if (!dti.ti.semanticTiargs(sc))
+ goto Leprop;
+ tiargs = dti.ti.tiargs;
+ tthis = dti.e1.type;
+ if ((os = dti.ti.tempdecl.isOverloadSet()) !is null)
+ goto Los;
+ if ((s = dti.ti.tempdecl) !is null)
+ goto Lfd;
+ }
+ else if (auto dte = e1.isDotTemplateExp())
+ {
+ s = dte.td;
+ tiargs = null;
+ tthis = dte.e1.type;
+ goto Lfd;
+ }
+ else if (auto se = e1.isScopeExp())
+ {
+ s = se.sds;
+ TemplateInstance ti = s.isTemplateInstance();
+ if (ti && !ti.semanticRun && ti.tempdecl)
+ {
+ //assert(ti.needsTypeInference(sc));
+ if (!ti.semanticTiargs(sc))
+ goto Leprop;
+ tiargs = ti.tiargs;
+ tthis = null;
+ if ((os = ti.tempdecl.isOverloadSet()) !is null)
+ goto Los;
+ if ((s = ti.tempdecl) !is null)
+ goto Lfd;
+ }
+ }
+ else if (auto te = e1.isTemplateExp())
+ {
+ s = te.td;
+ tiargs = null;
+ tthis = null;
+ goto Lfd;
+ }
+ else if (e1.op == TOK.dotVariable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(DotVarExp)e1).var.isOverDeclaration()))
+ {
+ DotVarExp dve = cast(DotVarExp)e1;
+ s = dve.var;
+ tiargs = null;
+ tthis = dve.e1.type;
+ goto Lfd;
+ }
+ else if (e1.op == TOK.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration()))
+ {
+ s = (cast(VarExp)e1).var;
+ tiargs = null;
+ tthis = null;
+ Lfd:
+ assert(s);
+ if (e2)
+ {
+ e2 = e2.expressionSemantic(sc);
+ if (e2.op == TOK.error)
+ return ErrorExp.get();
+ e2 = resolveProperties(sc, e2);
+
+ Expressions a;
+ a.push(e2);
+
+ FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, FuncResolveFlag.quiet);
+ if (fd && fd.type)
+ {
+ if (fd.errors)
+ return ErrorExp.get();
+ if (!checkSymbolAccess(sc, fd))
+ {
+ // @@@DEPRECATED_2020-10@@@
+ // When turning into error, uncomment the return statement
+ TypeFunction tf = cast(TypeFunction)fd.type;
+ deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`",
+ fd.toPrettyChars(), tf.toChars, sc._module.toChars);
+ //return ErrorExp.get();
+ }
+ assert(fd.type.ty == Tfunction);
+ Expression e = new CallExp(loc, e1, e2);
+ return e.expressionSemantic(sc);
+ }
+ }
+ {
+ FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, null, FuncResolveFlag.quiet);
+ if (fd && fd.type)
+ {
+ if (fd.errors)
+ return ErrorExp.get();
+ assert(fd.type.ty == Tfunction);
+ TypeFunction tf = cast(TypeFunction)fd.type;
+ if (!e2 || tf.isref)
+ {
+ if (!checkSymbolAccess(sc, fd))
+ {
+ // @@@DEPRECATED_2020-10@@@
+ // When turning into error, uncomment the return statement
+ deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`",
+ fd.toPrettyChars(), tf.toChars, sc._module.toChars);
+ //return ErrorExp.get();
+ }
+ Expression e = new CallExp(loc, e1);
+ if (e2)
+ e = new AssignExp(loc, e, e2);
+ return e.expressionSemantic(sc);
+ }
+ }
+ }
+ if (FuncDeclaration fd = s.isFuncDeclaration())
+ {
+ // Keep better diagnostic message for invalid property usage of functions
+ assert(fd.type.ty == Tfunction);
+ Expression e = new CallExp(loc, e1, e2);
+ return e.expressionSemantic(sc);
+ }
+ if (e2)
+ goto Leprop;
+ }
+ if (e1.op == TOK.variable)
+ {
+ VarExp ve = cast(VarExp)e1;
+ VarDeclaration v = ve.var.isVarDeclaration();
+ if (v && ve.checkPurity(sc, v))
+ return ErrorExp.get();
+ }
+ if (e2)
+ return null;
+
+ if (e1.type && e1.op != TOK.type) // function type is not a property
+ {
+ /* Look for e1 being a lazy parameter; rewrite as delegate call
+ * only if the symbol wasn't already treated as a delegate
+ */
+ auto ve = e1.isVarExp();
+ if (ve && ve.var.storage_class & STC.lazy_ && !ve.delegateWasExtracted)
+ {
+ Expression e = new CallExp(loc, e1);
+ return e.expressionSemantic(sc);
+ }
+ else if (e1.op == TOK.dotVariable)
+ {
+ // Check for reading overlapped pointer field in @safe code.
+ if (checkUnsafeAccess(sc, e1, true, true))
+ return ErrorExp.get();
+ }
+ else if (e1.op == TOK.call)
+ {
+ CallExp ce = cast(CallExp)e1;
+ // Check for reading overlapped pointer field in @safe code.
+ if (checkUnsafeAccess(sc, ce.e1, true, true))
+ return ErrorExp.get();
+ }
+ }
+
+ if (!e1.type)
+ {
+ error(loc, "cannot resolve type for %s", e1.toChars());
+ e1 = ErrorExp.get();
+ }
+ return e1;
+
+Leprop:
+ error(loc, "not a property %s", e1.toChars());
+ return ErrorExp.get();
+}
+
+extern (C++) Expression resolveProperties(Scope* sc, Expression e)
+{
+ //printf("resolveProperties(%s)\n", e.toChars());
+ e = resolvePropertiesX(sc, e);
+ if (e.checkRightThis(sc))
+ return ErrorExp.get();
+ return e;
+}
+
+/****************************************
+ * The common type is determined by applying ?: to each pair.
+ * Output:
+ * exps[] properties resolved, implicitly cast to common type, rewritten in place
+ * Returns:
+ * The common type, or `null` if an error has occured
+ */
+private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
+{
+ /* Still have a problem with:
+ * ubyte[][] = [ cast(ubyte[])"hello", [1]];
+ * which works if the array literal is initialized top down with the ubyte[][]
+ * type, but fails with this function doing bottom up typing.
+ */
+
+ //printf("arrayExpressionToCommonType()\n");
+ scope IntegerExp integerexp = IntegerExp.literal!0;
+ scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null);
+
+ Type t0 = null;
+ Expression e0 = null;
+ size_t j0 = ~0;
+ bool foundType;
+
+ for (size_t i = 0; i < exps.dim; i++)
+ {
+ Expression e = exps[i];
+ if (!e)
+ continue;
+
+ e = resolveProperties(sc, e);
+ if (!e.type)
+ {
+ e.error("`%s` has no value", e.toChars());
+ t0 = Type.terror;
+ continue;
+ }
+ if (e.op == TOK.type)
+ {
+ foundType = true; // do not break immediately, there might be more errors
+ e.checkValue(); // report an error "type T has no value"
+ t0 = Type.terror;
+ continue;
+ }
+ if (e.type.ty == Tvoid)
+ {
+ // void expressions do not concur to the determination of the common
+ // type.
+ continue;
+ }
+ if (checkNonAssignmentArrayOp(e))
+ {
+ t0 = Type.terror;
+ continue;
+ }
+
+ e = doCopyOrMove(sc, e);
+
+ if (!foundType && t0 && !t0.equals(e.type))
+ {
+ /* This applies ?: to merge the types. It's backwards;
+ * ?: should call this function to merge types.
+ */
+ condexp.type = null;
+ condexp.e1 = e0;
+ condexp.e2 = e;
+ condexp.loc = e.loc;
+ Expression ex = condexp.expressionSemantic(sc);
+ if (ex.op == TOK.error)
+ e = ex;
+ else if (e.op == TOK.function_ || e.op == TOK.delegate_)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=21285
+ // Functions and delegates don't convert correctly with castTo below
+ exps[j0] = condexp.e1;
+ e = condexp.e2;
+ }
+ else
+ {
+ // Convert to common type
+ exps[j0] = condexp.e1.castTo(sc, condexp.type);
+ e = condexp.e2.castTo(sc, condexp.type);
+ }
+ }
+ j0 = i;
+ e0 = e;
+ t0 = e.type;
+ if (e.op != TOK.error)
+ exps[i] = e;
+ }
+
+ // [] is typed as void[]
+ if (!t0)
+ return Type.tvoid;
+
+ // It's an error, don't do the cast
+ if (t0.ty == Terror)
+ return null;
+
+ for (size_t i = 0; i < exps.dim; i++)
+ {
+ Expression e = exps[i];
+ if (!e)
+ continue;
+
+ e = e.implicitCastTo(sc, t0);
+ if (e.op == TOK.error)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=13024
+ * a workaround for the bug in typeMerge -
+ * it should paint e1 and e2 by deduced common type,
+ * but doesn't in this particular case.
+ */
+ return null;
+ }
+ exps[i] = e;
+ }
+ return t0;
+}
+
+private Expression opAssignToOp(const ref Loc loc, TOK op, Expression e1, Expression e2)
+{
+ Expression e;
+ switch (op)
+ {
+ case TOK.addAssign:
+ e = new AddExp(loc, e1, e2);
+ break;
+
+ case TOK.minAssign:
+ e = new MinExp(loc, e1, e2);
+ break;
+
+ case TOK.mulAssign:
+ e = new MulExp(loc, e1, e2);
+ break;
+
+ case TOK.divAssign:
+ e = new DivExp(loc, e1, e2);
+ break;
+
+ case TOK.modAssign:
+ e = new ModExp(loc, e1, e2);
+ break;
+
+ case TOK.andAssign:
+ e = new AndExp(loc, e1, e2);
+ break;
+
+ case TOK.orAssign:
+ e = new OrExp(loc, e1, e2);
+ break;
+
+ case TOK.xorAssign:
+ e = new XorExp(loc, e1, e2);
+ break;
+
+ case TOK.leftShiftAssign:
+ e = new ShlExp(loc, e1, e2);
+ break;
+
+ case TOK.rightShiftAssign:
+ e = new ShrExp(loc, e1, e2);
+ break;
+
+ case TOK.unsignedRightShiftAssign:
+ e = new UshrExp(loc, e1, e2);
+ break;
+
+ default:
+ assert(0);
+ }
+ return e;
+}
+
+/*********************
+ * Rewrite:
+ * array.length op= e2
+ * as:
+ * array.length = array.length op e2
+ * or:
+ * auto tmp = &array;
+ * (*tmp).length = (*tmp).length op e2
+ */
+private Expression rewriteOpAssign(BinExp exp)
+{
+ Expression e;
+
+ assert(exp.e1.op == TOK.arrayLength);
+ ArrayLengthExp ale = cast(ArrayLengthExp)exp.e1;
+ if (ale.e1.op == TOK.variable)
+ {
+ e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
+ e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
+ }
+ else
+ {
+ /* auto tmp = &array;
+ * (*tmp).length = (*tmp).length op e2
+ */
+ auto tmp = copyToTemp(0, "__arraylength", new AddrExp(ale.loc, ale.e1));
+
+ Expression e1 = new ArrayLengthExp(ale.loc, new PtrExp(ale.loc, new VarExp(ale.loc, tmp)));
+ Expression elvalue = e1.syntaxCopy();
+ e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
+ e = new AssignExp(exp.loc, elvalue, e);
+ e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e);
+ }
+ return e;
+}
+
+/****************************************
+ * Preprocess arguments to function.
+ * Input:
+ * reportErrors whether or not to report errors here. Some callers are not
+ * checking actual function params, so they'll do their own error reporting
+ * Output:
+ * exps[] tuples expanded, properties resolved, rewritten in place
+ * Returns:
+ * true a semantic error occurred
+ */
+private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool reportErrors = true)
+{
+ bool err = false;
+ if (exps)
+ {
+ expandTuples(exps);
+
+ for (size_t i = 0; i < exps.dim; i++)
+ {
+ Expression arg = (*exps)[i];
+ arg = resolveProperties(sc, arg);
+ if (arg.op == TOK.type)
+ {
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ arg = resolveAliasThis(sc, arg);
+
+ if (arg.op == TOK.type)
+ {
+ if (reportErrors)
+ {
+ arg.error("cannot pass type `%s` as a function argument", arg.toChars());
+ arg = ErrorExp.get();
+ }
+ err = true;
+ }
+ }
+ else if (arg.type.toBasetype().ty == Tfunction)
+ {
+ if (reportErrors)
+ {
+ arg.error("cannot pass function `%s` as a function argument", arg.toChars());
+ arg = ErrorExp.get();
+ }
+ err = true;
+ }
+ else if (checkNonAssignmentArrayOp(arg))
+ {
+ arg = ErrorExp.get();
+ err = true;
+ }
+ (*exps)[i] = arg;
+ }
+ }
+ return err;
+}
+
+/********************************************
+ * Issue an error if default construction is disabled for type t.
+ * Default construction is required for arrays and 'out' parameters.
+ * Returns:
+ * true an error was issued
+ */
+private bool checkDefCtor(Loc loc, Type t)
+{
+ t = t.baseElemOf();
+ if (t.ty == Tstruct)
+ {
+ StructDeclaration sd = (cast(TypeStruct)t).sym;
+ if (sd.noDefaultCtor)
+ {
+ sd.error(loc, "default construction is disabled");
+ return true;
+ }
+ }
+ return false;
+}
+
+/****************************************
+ * Now that we know the exact type of the function we're calling,
+ * the arguments[] need to be adjusted:
+ * 1. implicitly convert argument to the corresponding parameter type
+ * 2. add default arguments for any missing arguments
+ * 3. do default promotions on arguments corresponding to ...
+ * 4. add hidden _arguments[] argument
+ * 5. call copy constructor for struct value arguments
+ * Params:
+ * loc = location of function call
+ * sc = context
+ * tf = type of the function
+ * ethis = `this` argument, `null` if none or not known
+ * tthis = type of `this` argument, `null` if no `this` argument
+ * arguments = array of actual arguments to function call
+ * fd = the function being called, `null` if called indirectly
+ * prettype = set to return type of function
+ * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none
+ * Returns:
+ * true errors happened
+ */
+private bool functionParameters(const ref Loc loc, Scope* sc,
+ TypeFunction tf, Expression ethis, Type tthis, Expressions* arguments, FuncDeclaration fd,
+ Type* prettype, Expression* peprefix)
+{
+ //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
+ assert(arguments);
+ assert(fd || tf.next);
+ size_t nargs = arguments ? arguments.dim : 0;
+ const size_t nparams = tf.parameterList.length;
+ const olderrors = global.errors;
+ bool err = false;
+ *prettype = Type.terror;
+ Expression eprefix = null;
+ *peprefix = null;
+
+ if (nargs > nparams && tf.parameterList.varargs == VarArg.none)
+ {
+ error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars());
+ return true;
+ }
+
+ // If inferring return type, and semantic3() needs to be run if not already run
+ if (!tf.next && fd.inferRetType)
+ {
+ fd.functionSemantic();
+ }
+ else if (fd && fd.parent)
+ {
+ TemplateInstance ti = fd.parent.isTemplateInstance();
+ if (ti && ti.tempdecl)
+ {
+ fd.functionSemantic3();
+ }
+ }
+
+ /* If calling a pragma(inline, true) function,
+ * set flag to later scan for inlines.
+ */
+ if (fd && fd.inlining == PINLINE.always)
+ {
+ if (sc._module)
+ sc._module.hasAlwaysInlines = true;
+ if (sc.func)
+ sc.func.hasAlwaysInlines = true;
+ }
+
+ const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
+
+ const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
+
+ /* If the function return type has wildcards in it, we'll need to figure out the actual type
+ * based on the actual argument types.
+ * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
+ * of the arguments.
+ */
+ MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0;
+
+ bool done = false;
+ foreach (const i; 0 .. n)
+ {
+ Expression arg = (i < nargs) ? (*arguments)[i] : null;
+
+ if (i < nparams)
+ {
+ bool errorArgs()
+ {
+ error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs);
+ return true;
+ }
+
+ Parameter p = tf.parameterList[i];
+
+ if (!arg)
+ {
+ if (!p.defaultArg)
+ {
+ if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
+ goto L2;
+ return errorArgs();
+ }
+ arg = p.defaultArg;
+ arg = inlineCopy(arg, sc);
+ // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
+ arg = arg.resolveLoc(loc, sc);
+ arguments.push(arg);
+ nargs++;
+ }
+ else
+ {
+ if (isDefaultInitOp(arg.op))
+ {
+ arg = arg.resolveLoc(loc, sc);
+ (*arguments)[i] = arg;
+ }
+ }
+
+
+ if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic
+ {
+ //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
+ {
+ MATCH m;
+ if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch)
+ {
+ if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
+ goto L2;
+ else if (nargs != nparams)
+ return errorArgs();
+ goto L1;
+ }
+ }
+ L2:
+ Type tb = p.type.toBasetype();
+ switch (tb.ty)
+ {
+ case Tsarray:
+ case Tarray:
+ {
+ /* Create a static array variable v of type arg.type:
+ * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
+ *
+ * The array literal in the initializer of the hidden variable
+ * is now optimized.
+ * https://issues.dlang.org/show_bug.cgi?id=2356
+ */
+ Type tbn = (cast(TypeArray)tb).next; // array element type
+ Type tret = p.isLazyArray();
+
+ auto elements = new Expressions(nargs - i);
+ foreach (u; 0 .. elements.dim)
+ {
+ Expression a = (*arguments)[i + u];
+ if (tret && a.implicitConvTo(tret))
+ {
+ // p is a lazy array of delegates, tret is return type of the delegates
+ a = a.implicitCastTo(sc, tret)
+ .optimize(WANTvalue)
+ .toDelegate(tret, sc);
+ }
+ else
+ a = a.implicitCastTo(sc, tbn);
+ a = a.addDtorHook(sc);
+ (*elements)[u] = a;
+ }
+ // https://issues.dlang.org/show_bug.cgi?id=14395
+ // Convert to a static array literal, or its slice.
+ arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements);
+ if (tb.ty == Tarray)
+ {
+ arg = new SliceExp(loc, arg, null, null);
+ arg.type = p.type;
+ }
+ break;
+ }
+ case Tclass:
+ {
+ /* Set arg to be:
+ * new Tclass(arg0, arg1, ..., argn)
+ */
+ auto args = new Expressions(nargs - i);
+ foreach (u; i .. nargs)
+ (*args)[u - i] = (*arguments)[u];
+ arg = new NewExp(loc, null, null, p.type, args);
+ break;
+ }
+ default:
+ if (!arg)
+ {
+ error(loc, "not enough arguments");
+ return true;
+ }
+ break;
+ }
+ arg = arg.expressionSemantic(sc);
+ //printf("\targ = '%s'\n", arg.toChars());
+ arguments.setDim(i + 1);
+ (*arguments)[i] = arg;
+ nargs = i + 1;
+ done = true;
+ }
+
+ L1:
+ if (!(p.storageClass & STC.lazy_ && p.type.ty == Tvoid))
+ {
+ if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
+ {
+ wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm;
+ //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
+ }
+ }
+ }
+ if (done)
+ break;
+ }
+ if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) &&
+ tf.next && tf.next.hasWild() &&
+ (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf())))
+ {
+ bool errorInout(MOD wildmatch)
+ {
+ const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch);
+ error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s);
+ return true;
+ }
+
+ if (fd)
+ {
+ /* If the called function may return the reference to
+ * outer inout data, it should be rejected.
+ *
+ * void foo(ref inout(int) x) {
+ * ref inout(int) bar(inout(int)) { return x; }
+ * struct S {
+ * ref inout(int) bar() inout { return x; }
+ * ref inout(int) baz(alias a)() inout { return x; }
+ * }
+ * bar(int.init) = 1; // bad!
+ * S().bar() = 1; // bad!
+ * }
+ * void test() {
+ * int a;
+ * auto s = foo(a);
+ * s.baz!a() = 1; // bad!
+ * }
+ *
+ */
+ bool checkEnclosingWild(Dsymbol s)
+ {
+ bool checkWild(Dsymbol s)
+ {
+ if (!s)
+ return false;
+ if (auto ad = s.isAggregateDeclaration())
+ {
+ if (ad.isNested())
+ return checkEnclosingWild(s);
+ }
+ else if (auto ff = s.isFuncDeclaration())
+ {
+ if ((cast(TypeFunction)ff.type).iswild)
+ return errorInout(wildmatch);
+
+ if (ff.isNested() || ff.isThis())
+ return checkEnclosingWild(s);
+ }
+ return false;
+ }
+
+ Dsymbol ctx0 = s.toParent2();
+ Dsymbol ctx1 = s.toParentLocal();
+ if (checkWild(ctx0))
+ return true;
+ if (ctx0 != ctx1)
+ return checkWild(ctx1);
+ return false;
+ }
+ if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd))
+ return true;
+ }
+ else if (tf.isWild())
+ return errorInout(wildmatch);
+ }
+
+ Expression firstArg = ((tf.next && tf.next.ty == Tvoid || isCtorCall) &&
+ tthis &&
+ tthis.isMutable() && tthis.toBasetype().ty == Tstruct &&
+ tthis.hasPointers())
+ ? ethis : null;
+
+ assert(nargs >= nparams);
+ foreach (const i, arg; (*arguments)[0 .. nargs])
+ {
+ assert(arg);
+ if (i < nparams)
+ {
+ Parameter p = tf.parameterList[i];
+ Type targ = arg.type; // keep original type for isCopyable() because alias this
+ // resolution may hide an uncopyable type
+
+ if (!(p.storageClass & STC.lazy_ && p.type.ty == Tvoid))
+ {
+ Type tprm = p.type.hasWild()
+ ? p.type.substWildTo(wildmatch)
+ : p.type;
+
+ const hasCopyCtor = (arg.type.ty == Tstruct) && (cast(TypeStruct)arg.type).sym.hasCopyCtor;
+ const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf());
+ if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type)))
+ {
+ //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
+ arg = arg.implicitCastTo(sc, tprm);
+ arg = arg.optimize(WANTvalue, p.isReference());
+ }
+ }
+
+ // Support passing rvalue to `in` parameters
+ if ((p.storageClass & (STC.in_ | STC.ref_)) == (STC.in_ | STC.ref_))
+ {
+ if (!arg.isLvalue())
+ {
+ auto v = copyToTemp(STC.exptemp, "__rvalue", arg);
+ Expression ev = new DeclarationExp(arg.loc, v);
+ ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
+ arg = ev.expressionSemantic(sc);
+ }
+ arg = arg.toLvalue(sc, arg);
+
+ // Look for mutable misaligned pointer, etc., in @safe mode
+ err |= checkUnsafeAccess(sc, arg, false, true);
+ }
+ else if (p.storageClass & STC.ref_)
+ {
+ if (global.params.rvalueRefParam &&
+ !arg.isLvalue() &&
+ targ.isCopyable())
+ { /* allow rvalues to be passed to ref parameters by copying
+ * them to a temp, then pass the temp as the argument
+ */
+ auto v = copyToTemp(0, "__rvalue", arg);
+ Expression ev = new DeclarationExp(arg.loc, v);
+ ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
+ arg = ev.expressionSemantic(sc);
+ }
+ arg = arg.toLvalue(sc, arg);
+
+ // Look for mutable misaligned pointer, etc., in @safe mode
+ err |= checkUnsafeAccess(sc, arg, false, true);
+ }
+ else if (p.storageClass & STC.out_)
+ {
+ Type t = arg.type;
+ if (!t.isMutable() || !t.isAssignable()) // check blit assignable
+ {
+ arg.error("cannot modify struct `%s` with immutable members", arg.toChars());
+ err = true;
+ }
+ else
+ {
+ // Look for misaligned pointer, etc., in @safe mode
+ err |= checkUnsafeAccess(sc, arg, false, true);
+ err |= checkDefCtor(arg.loc, t); // t must be default constructible
+ }
+ arg = arg.toLvalue(sc, arg);
+ }
+ else if (p.storageClass & STC.lazy_)
+ {
+ // Convert lazy argument to a delegate
+ auto t = (p.type.ty == Tvoid) ? p.type : arg.type;
+ arg = toDelegate(arg, t, sc);
+ }
+ //printf("arg: %s\n", arg.toChars());
+ //printf("type: %s\n", arg.type.toChars());
+ //printf("param: %s\n", p.toChars());
+
+ if (firstArg && p.storageClass & STC.return_)
+ {
+ /* Argument value can be assigned to firstArg.
+ * Check arg to see if it matters.
+ */
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ err |= checkParamArgumentReturn(sc, firstArg, arg, false);
+ }
+ else if (tf.parameterEscapes(tthis, p))
+ {
+ /* Argument value can escape from the called function.
+ * Check arg to see if it matters.
+ */
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ err |= checkParamArgumentEscape(sc, fd, p, arg, false, false);
+ }
+ else if (!(p.storageClass & STC.return_))
+ {
+ /* Argument value cannot escape from the called function.
+ */
+ Expression a = arg;
+ if (a.op == TOK.cast_)
+ a = (cast(CastExp)a).e1;
+
+ ArrayLiteralExp ale;
+ if (p.type.toBasetype().ty == Tarray &&
+ (ale = a.isArrayLiteralExp()) !is null)
+ {
+ // allocate the array literal as temporary static array on the stack
+ ale.type = ale.type.nextOf().sarrayOf(ale.elements ? ale.elements.length : 0);
+ auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale);
+ auto declareTmp = new DeclarationExp(ale.loc, tmp);
+ auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp), p.type);
+ arg = CommaExp.combine(declareTmp, castToSlice);
+ arg = arg.expressionSemantic(sc);
+ }
+ else if (a.op == TOK.function_)
+ {
+ /* Function literals can only appear once, so if this
+ * appearance was scoped, there cannot be any others.
+ */
+ FuncExp fe = cast(FuncExp)a;
+ fe.fd.tookAddressOf = 0;
+ }
+ else if (a.op == TOK.delegate_)
+ {
+ /* For passing a delegate to a scoped parameter,
+ * this doesn't count as taking the address of it.
+ * We only worry about 'escaping' references to the function.
+ */
+ DelegateExp de = cast(DelegateExp)a;
+ if (de.e1.op == TOK.variable)
+ {
+ VarExp ve = cast(VarExp)de.e1;
+ FuncDeclaration f = ve.var.isFuncDeclaration();
+ if (f)
+ {
+ if (f.tookAddressOf)
+ --f.tookAddressOf;
+ //printf("--tookAddressOf = %d\n", f.tookAddressOf);
+ }
+ }
+ }
+ }
+ if (!p.isReference())
+ err |= arg.checkSharedAccess(sc);
+
+ arg = arg.optimize(WANTvalue, p.isReference());
+
+ /* Determine if this parameter is the "first reference" parameter through which
+ * later "return" arguments can be stored.
+ */
+ if (i == 0 && !tthis && p.isReference() && p.type &&
+ (tf.next && tf.next.ty == Tvoid || isCtorCall))
+ {
+ Type tb = p.type.baseElemOf();
+ if (tb.isMutable() && tb.hasPointers())
+ {
+ firstArg = arg;
+ }
+ }
+ }
+ else
+ {
+ // These will be the trailing ... arguments
+ // If not D linkage, do promotions
+ if (tf.linkage != LINK.d)
+ {
+ // Promote bytes, words, etc., to ints
+ arg = integralPromotions(arg, sc);
+
+ // Promote floats to doubles
+ switch (arg.type.ty)
+ {
+ case Tfloat32:
+ arg = arg.castTo(sc, Type.tfloat64);
+ break;
+
+ case Timaginary32:
+ arg = arg.castTo(sc, Type.timaginary64);
+ break;
+
+ default:
+ break;
+ }
+ if (tf.parameterList.varargs == VarArg.variadic)
+ {
+ const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)";
+ if (arg.type.ty == Tarray)
+ {
+ arg.error("cannot pass dynamic arrays to `%s` vararg functions", p);
+ err = true;
+ }
+ if (arg.type.ty == Tsarray)
+ {
+ arg.error("cannot pass static arrays to `%s` vararg functions", p);
+ err = true;
+ }
+ }
+ }
+
+ // Do not allow types that need destructors or copy constructors.
+ if (arg.type.needsDestruction())
+ {
+ arg.error("cannot pass types that need destruction as variadic arguments");
+ err = true;
+ }
+ if (arg.type.needsCopyOrPostblit())
+ {
+ arg.error("cannot pass types with postblits or copy constructors as variadic arguments");
+ err = true;
+ }
+
+ // Convert static arrays to dynamic arrays
+ // BUG: I don't think this is right for D2
+ Type tb = arg.type.toBasetype();
+ if (tb.ty == Tsarray)
+ {
+ TypeSArray ts = cast(TypeSArray)tb;
+ Type ta = ts.next.arrayOf();
+ if (ts.size(arg.loc) == 0)
+ arg = new NullExp(arg.loc, ta);
+ else
+ arg = arg.castTo(sc, ta);
+ }
+ if (tb.ty == Tstruct)
+ {
+ //arg = callCpCtor(sc, arg);
+ }
+ // Give error for overloaded function addresses
+ if (arg.op == TOK.symbolOffset)
+ {
+ SymOffExp se = cast(SymOffExp)arg;
+ if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
+ {
+ arg.error("function `%s` is overloaded", arg.toChars());
+ err = true;
+ }
+ }
+ err |= arg.checkValue();
+ err |= arg.checkSharedAccess(sc);
+ arg = arg.optimize(WANTvalue);
+ }
+ (*arguments)[i] = arg;
+ }
+
+ /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
+ */
+ const isVa_list = tf.parameterList.varargs == VarArg.none;
+ if (fd && fd.flags & FUNCFLAG.printf)
+ {
+ if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
+ {
+ checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
+ }
+ }
+ else if (fd && fd.flags & FUNCFLAG.scanf)
+ {
+ if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
+ {
+ checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
+ }
+ }
+ else
+ {
+ // TODO: not checking the "v" functions yet (for those, check format string only, not args)
+ }
+
+ /* Remaining problems:
+ * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
+ * implemented by calling a function) we'll defer this for now.
+ * 2. value structs (or static arrays of them) that need to be copy constructed
+ * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
+ * function gets called.
+ * 4. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
+ * 2, 3 and 4 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
+ * up properly. Pushing arguments on the stack then cannot fail.
+ */
+ {
+ /* TODO: tackle problem 1)
+ */
+ const bool leftToRight = true; // TODO: Any cases that need rightToLeft?
+ if (!leftToRight)
+ assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
+
+ /* Does Problem (4) apply?
+ */
+ const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf);
+
+ const ptrdiff_t start = (leftToRight ? 0 : cast(ptrdiff_t)nargs - 1);
+ const ptrdiff_t end = (leftToRight ? cast(ptrdiff_t)nargs : -1);
+ const ptrdiff_t step = (leftToRight ? 1 : -1);
+
+ /* Compute indices of last throwing argument and first arg needing destruction.
+ * Used to not set up destructors unless an arg needs destruction on a throw
+ * in a later argument.
+ */
+ ptrdiff_t lastthrow = -1; // last argument that may throw
+ ptrdiff_t firstdtor = -1; // first argument that needs destruction
+ ptrdiff_t lastdtor = -1; // last argument that needs destruction
+ for (ptrdiff_t i = start; i != end; i += step)
+ {
+ Expression arg = (*arguments)[i];
+ if (canThrow(arg, sc.func, false))
+ lastthrow = i;
+ if (arg.type.needsDestruction())
+ {
+ Parameter p = (i >= nparams ? null : tf.parameterList[i]);
+ if (!(p && (p.storageClass & (STC.lazy_ | STC.ref_ | STC.out_))))
+ {
+ if (firstdtor == -1)
+ firstdtor = i;
+ lastdtor = i;
+ }
+ }
+ }
+
+ /* Do we need 'eprefix' for problems 3 or 4?
+ */
+ const bool needsPrefix = callerDestroysArgs
+ ? firstdtor >= 0 // true if any argument needs destruction
+ : firstdtor >= 0 && lastthrow >= 0 &&
+ (lastthrow - firstdtor) * step > 0; // last throw after first destruction
+ const ptrdiff_t lastPrefix = callerDestroysArgs
+ ? lastdtor // up to last argument requiring destruction
+ : lastthrow; // up to last potentially throwing argument
+
+ /* Problem 3: initialize 'eprefix' by declaring the gate
+ */
+ VarDeclaration gate;
+ if (needsPrefix && !callerDestroysArgs)
+ {
+ // eprefix => bool __gate [= false]
+ Identifier idtmp = Identifier.generateId("__gate");
+ gate = new VarDeclaration(loc, Type.tbool, idtmp, null);
+ gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_;
+ gate.dsymbolSemantic(sc);
+
+ auto ae = new DeclarationExp(loc, gate);
+ eprefix = ae.expressionSemantic(sc);
+ }
+
+ for (ptrdiff_t i = start; i != end; i += step)
+ {
+ Expression arg = (*arguments)[i];
+ //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
+
+ Parameter parameter = (i >= nparams ? null : tf.parameterList[i]);
+ const bool isRef = parameter && parameter.isReference();
+ const bool isLazy = (parameter && (parameter.storageClass & STC.lazy_));
+
+ /* Skip lazy parameters
+ */
+ if (isLazy)
+ continue;
+
+ /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
+ * Then declare a temporary variable for this arg and append that declaration
+ * to 'eprefix', which will implicitly take care of potential problem 2) for
+ * this arg.
+ * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
+ * excluding all lazy parameters.
+ */
+ if (needsPrefix && (lastPrefix - i) * step >= 0)
+ {
+ const bool needsDtor = !isRef && arg.type.needsDestruction() &&
+ // Problem 3: last throwing arg doesn't require dtor patching
+ (callerDestroysArgs || i != lastPrefix);
+
+ /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
+ */
+ auto tmp = copyToTemp(
+ (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.scope_),
+ needsDtor ? "__pfx" : "__pfy",
+ !isRef ? arg : arg.addressOf());
+ tmp.dsymbolSemantic(sc);
+
+ if (callerDestroysArgs)
+ {
+ /* Problem 4: Normal temporary, destructed after the call
+ */
+ if (needsDtor)
+ tmp.isArgDtorVar = true; // mark it so that the backend passes it by ref to the function being called
+ }
+ else
+ {
+ /* Problem 3: Modify the destructor so it only runs if gate==false,
+ * i.e., only if there was a throw while constructing the args
+ */
+ if (!needsDtor)
+ {
+ if (tmp.edtor)
+ {
+ assert(i == lastPrefix);
+ tmp.edtor = null;
+ }
+ }
+ else
+ {
+ // edtor => (__gate || edtor)
+ assert(tmp.edtor);
+ Expression e = tmp.edtor;
+ e = new LogicalExp(e.loc, TOK.orOr, new VarExp(e.loc, gate), e);
+ tmp.edtor = e.expressionSemantic(sc);
+ //printf("edtor: %s\n", tmp.edtor.toChars());
+ }
+ }
+
+ // eprefix => (eprefix, auto __pfx/y = arg)
+ auto ae = new DeclarationExp(loc, tmp);
+ eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc));
+
+ // arg => __pfx/y
+ arg = new VarExp(loc, tmp);
+ arg = arg.expressionSemantic(sc);
+ if (isRef)
+ {
+ arg = new PtrExp(loc, arg);
+ arg = arg.expressionSemantic(sc);
+ }
+
+ /* Problem 3: Last throwing arg?
+ * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
+ * dtors right after constructing the last throwing arg.
+ * From now on, the callee will take care of destructing the args because
+ * the args are implicitly moved into function parameters.
+ */
+ if (!callerDestroysArgs && i == lastPrefix)
+ {
+ auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true));
+ eprefix = Expression.combine(eprefix, e.expressionSemantic(sc));
+ }
+ }
+ else // not part of 'eprefix'
+ {
+ /* Handle problem 2) by calling the copy constructor for value structs
+ * (or static arrays of them) if appropriate.
+ */
+ Type tv = arg.type.baseElemOf();
+ if (!isRef && tv.ty == Tstruct)
+ arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null);
+ }
+
+ (*arguments)[i] = arg;
+ }
+ }
+ //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
+
+ /* Test compliance with DIP1021
+ */
+ if (global.params.useDIP1021 &&
+ tf.trust != TRUST.system && tf.trust != TRUST.trusted)
+ err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);
+
+ // If D linkage and variadic, add _arguments[] as first argument
+ if (tf.isDstyleVariadic())
+ {
+ assert(arguments.dim >= nparams);
+
+ auto args = new Parameters(arguments.dim - nparams);
+ for (size_t i = 0; i < arguments.dim - nparams; i++)
+ {
+ auto arg = new Parameter(STC.in_, (*arguments)[nparams + i].type, null, null, null);
+ (*args)[i] = arg;
+ }
+ auto tup = new TypeTuple(args);
+ Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc);
+ arguments.insert(0, e);
+ }
+
+ /* Determine function return type: tret
+ */
+ Type tret = tf.next;
+ if (isCtorCall)
+ {
+ //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
+ // wildmatch, tf.isWild(), fd.isReturnIsolated());
+ if (!tthis)
+ {
+ assert(sc.intypeof || global.errors);
+ tthis = fd.isThis().type.addMod(fd.type.mod);
+ }
+ if (tf.isWild() && !fd.isReturnIsolated())
+ {
+ if (wildmatch)
+ tret = tret.substWildTo(wildmatch);
+ int offset;
+ if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0))
+ {
+ const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars();
+ const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars();
+ .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2);
+ err = true;
+ }
+ }
+ tret = tthis;
+ }
+ else if (wildmatch && tret)
+ {
+ /* Adjust function return type based on wildmatch
+ */
+ //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
+ tret = tret.substWildTo(wildmatch);
+ }
+
+ *prettype = tret;
+ *peprefix = eprefix;
+ return (err || olderrors != global.errors);
+}
+
+/**
+ * Determines whether a symbol represents a module or package
+ * (Used as a helper for is(type == module) and is(type == package))
+ *
+ * Params:
+ * sym = the symbol to be checked
+ *
+ * Returns:
+ * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
+ */
+Package resolveIsPackage(Dsymbol sym)
+{
+ Package pkg;
+ if (Import imp = sym.isImport())
+ {
+ if (imp.pkg is null)
+ {
+ .error(sym.loc, "Internal Compiler Error: unable to process forward-referenced import `%s`",
+ imp.toChars());
+ assert(0);
+ }
+ pkg = imp.pkg;
+ }
+ else if (auto mod = sym.isModule())
+ pkg = mod.isPackageFile ? mod.pkg : sym.isPackage();
+ else
+ pkg = sym.isPackage();
+ if (pkg)
+ pkg.resolvePKGunknown();
+ return pkg;
+}
+
+private Module loadStdMath()
+{
+ __gshared Import impStdMath = null;
+ __gshared Identifier[1] stdID;
+ if (!impStdMath)
+ {
+ stdID[0] = Id.std;
+ auto s = new Import(Loc.initial, stdID[], Id.math, null, false);
+ // Module.load will call fatal() if there's no std.math available.
+ // Gag the error here, pushing the error handling to the caller.
+ uint errors = global.startGagging();
+ s.load(null);
+ if (s.mod)
+ {
+ s.mod.importAll(null);
+ s.mod.dsymbolSemantic(null);
+ }
+ global.endGagging(errors);
+ impStdMath = s;
+ }
+ return impStdMath.mod;
+}
+
+private extern (C++) final class ExpressionSemanticVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+
+ Scope* sc;
+ Expression result;
+
+ this(Scope* sc)
+ {
+ this.sc = sc;
+ }
+
+ private void setError()
+ {
+ result = ErrorExp.get();
+ }
+
+ /**************************
+ * Semantically analyze Expression.
+ * Determine types, fold constants, etc.
+ */
+ override void visit(Expression e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("Expression::semantic() %s\n", e.toChars());
+ }
+ if (e.type)
+ e.type = e.type.typeSemantic(e.loc, sc);
+ else
+ e.type = Type.tvoid;
+ result = e;
+ }
+
+ override void visit(IntegerExp e)
+ {
+ assert(e.type);
+ if (e.type.ty == Terror)
+ return setError();
+
+ assert(e.type.deco);
+ e.setInteger(e.getInteger());
+ result = e;
+ }
+
+ override void visit(RealExp e)
+ {
+ if (!e.type)
+ e.type = Type.tfloat64;
+ else
+ e.type = e.type.typeSemantic(e.loc, sc);
+ result = e;
+ }
+
+ override void visit(ComplexExp e)
+ {
+ if (!e.type)
+ e.type = Type.tcomplex80;
+ else
+ e.type = e.type.typeSemantic(e.loc, sc);
+ result = e;
+ }
+
+ override void visit(IdentifierExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars());
+ }
+ if (exp.type) // This is used as the dummy expression
+ {
+ result = exp;
+ return;
+ }
+
+ Dsymbol scopesym;
+ Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
+ if (s)
+ {
+ if (s.errors)
+ return setError();
+
+ Expression e;
+
+ /* See if the symbol was a member of an enclosing 'with'
+ */
+ WithScopeSymbol withsym = scopesym.isWithScopeSymbol();
+ if (withsym && withsym.withstate.wthis && symbolIsVisible(sc, s))
+ {
+ /* Disallow shadowing
+ */
+ // First find the scope of the with
+ Scope* scwith = sc;
+ while (scwith.scopesym != scopesym)
+ {
+ scwith = scwith.enclosing;
+ assert(scwith);
+ }
+ // Look at enclosing scopes for symbols with the same name,
+ // in the same function
+ for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing)
+ {
+ Dsymbol s2;
+ if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
+ {
+ exp.error("with symbol `%s` is shadowing local symbol `%s`", s.toPrettyChars(), s2.toPrettyChars());
+ return setError();
+ }
+ }
+ s = s.toAlias();
+
+ // Same as wthis.ident
+ // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
+ // The redudancy should be removed.
+ e = new VarExp(exp.loc, withsym.withstate.wthis);
+ e = new DotIdExp(exp.loc, e, exp.ident);
+ e = e.expressionSemantic(sc);
+ }
+ else
+ {
+ if (withsym)
+ {
+ if (withsym.withstate.exp.type.ty != Tvoid)
+ {
+ // 'with (exp)' is a type expression
+ // or 's' is not visible there (for error message)
+ e = new TypeExp(exp.loc, withsym.withstate.exp.type);
+ }
+ else
+ {
+ // 'with (exp)' is a Package/Module
+ e = withsym.withstate.exp;
+ }
+ e = new DotIdExp(exp.loc, e, exp.ident);
+ result = e.expressionSemantic(sc);
+ return;
+ }
+
+ /* If f is really a function template,
+ * then replace f with the function template declaration.
+ */
+ FuncDeclaration f = s.isFuncDeclaration();
+ if (f)
+ {
+ TemplateDeclaration td = getFuncTemplateDecl(f);
+ if (td)
+ {
+ if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
+ td = td.overroot; // then get the start
+ e = new TemplateExp(exp.loc, td, f);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ }
+
+ if (global.params.fixAliasThis)
+ {
+ ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol();
+ if (expDsym)
+ {
+ //printf("expDsym = %s\n", expDsym.exp.toChars());
+ result = expDsym.exp.expressionSemantic(sc);
+ return;
+ }
+ }
+ // Haven't done overload resolution yet, so pass 1
+ e = symbolToExp(s, exp.loc, sc, true);
+ }
+ result = e;
+ return;
+ }
+
+ if (!global.params.fixAliasThis && hasThis(sc))
+ {
+ for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
+ {
+ if (ad.aliasthis)
+ {
+ Expression e;
+ e = new ThisExp(exp.loc);
+ e = new DotIdExp(exp.loc, e, ad.aliasthis.ident);
+ e = new DotIdExp(exp.loc, e, exp.ident);
+ e = e.trySemantic(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+
+ auto cd = ad.isClassDeclaration();
+ if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
+ {
+ ad = cd.baseClass;
+ continue;
+ }
+ break;
+ }
+ }
+
+ if (exp.ident == Id.ctfe)
+ {
+ if (sc.flags & SCOPE.ctfe)
+ {
+ exp.error("variable `__ctfe` cannot be read at compile time");
+ return setError();
+ }
+
+ // Create the magic __ctfe bool variable
+ auto vd = new VarDeclaration(exp.loc, Type.tbool, Id.ctfe, null);
+ vd.storage_class |= STC.temp;
+ vd.semanticRun = PASS.semanticdone;
+ Expression e = new VarExp(exp.loc, vd);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+
+ // If we've reached this point and are inside a with() scope then we may
+ // try one last attempt by checking whether the 'wthis' object supports
+ // dynamic dispatching via opDispatch.
+ // This is done by rewriting this expression as wthis.ident.
+ // The innermost with() scope of the hierarchy to satisfy the condition
+ // above wins.
+ // https://issues.dlang.org/show_bug.cgi?id=6400
+ for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing)
+ {
+ if (!sc2.scopesym)
+ continue;
+
+ if (auto ss = sc2.scopesym.isWithScopeSymbol())
+ {
+ if (ss.withstate.wthis)
+ {
+ Expression e;
+ e = new VarExp(exp.loc, ss.withstate.wthis);
+ e = new DotIdExp(exp.loc, e, exp.ident);
+ e = e.trySemantic(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+ // Try Type.opDispatch (so the static version)
+ else if (ss.withstate.exp && ss.withstate.exp.op == TOK.type)
+ {
+ if (Type t = ss.withstate.exp.isTypeExp().type)
+ {
+ Expression e;
+ e = new TypeExp(exp.loc, t);
+ e = new DotIdExp(exp.loc, e, exp.ident);
+ e = e.trySemantic(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ /* Look for what user might have meant
+ */
+ if (const n = importHint(exp.ident.toString()))
+ exp.error("`%s` is not defined, perhaps `import %.*s;` is needed?", exp.ident.toChars(), cast(int)n.length, n.ptr);
+ else if (auto s2 = sc.search_correct(exp.ident))
+ exp.error("undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars());
+ else if (const p = Scope.search_correct_C(exp.ident))
+ exp.error("undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p);
+ else
+ exp.error("undefined identifier `%s`", exp.ident.toChars());
+
+ result = ErrorExp.get();
+ }
+
+ override void visit(DsymbolExp e)
+ {
+ result = symbolToExp(e.s, e.loc, sc, e.hasOverloads);
+ }
+
+ override void visit(ThisExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("ThisExp::semantic()\n");
+ }
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+
+ FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
+ AggregateDeclaration ad;
+
+ /* Special case for typeof(this) and typeof(super) since both
+ * should work even if they are not inside a non-static member function
+ */
+ if (!fd && sc.intypeof == 1)
+ {
+ // Find enclosing struct or class
+ for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent)
+ {
+ if (!s)
+ {
+ e.error("`%s` is not in a class or struct scope", e.toChars());
+ goto Lerr;
+ }
+ ClassDeclaration cd = s.isClassDeclaration();
+ if (cd)
+ {
+ e.type = cd.type;
+ result = e;
+ return;
+ }
+ StructDeclaration sd = s.isStructDeclaration();
+ if (sd)
+ {
+ e.type = sd.type;
+ result = e;
+ return;
+ }
+ }
+ }
+ if (!fd)
+ goto Lerr;
+
+ assert(fd.vthis);
+ e.var = fd.vthis;
+ assert(e.var.parent);
+ ad = fd.isMemberLocal();
+ if (!ad)
+ ad = fd.isMember2();
+ assert(ad);
+ e.type = ad.type.addMod(e.var.type.mod);
+
+ if (e.var.checkNestedReference(sc, e.loc))
+ return setError();
+
+ result = e;
+ return;
+
+ Lerr:
+ e.error("`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars());
+ result = ErrorExp.get();
+ }
+
+ override void visit(SuperExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("SuperExp::semantic('%s')\n", e.toChars());
+ }
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+
+ FuncDeclaration fd = hasThis(sc);
+ ClassDeclaration cd;
+ Dsymbol s;
+
+ /* Special case for typeof(this) and typeof(super) since both
+ * should work even if they are not inside a non-static member function
+ */
+ if (!fd && sc.intypeof == 1)
+ {
+ // Find enclosing class
+ for (s = sc.getStructClassScope(); 1; s = s.parent)
+ {
+ if (!s)
+ {
+ e.error("`%s` is not in a class scope", e.toChars());
+ goto Lerr;
+ }
+ cd = s.isClassDeclaration();
+ if (cd)
+ {
+ cd = cd.baseClass;
+ if (!cd)
+ {
+ e.error("class `%s` has no `super`", s.toChars());
+ goto Lerr;
+ }
+ e.type = cd.type;
+ result = e;
+ return;
+ }
+ }
+ }
+ if (!fd)
+ goto Lerr;
+
+ e.var = fd.vthis;
+ assert(e.var && e.var.parent);
+
+ s = fd.toParentDecl();
+ if (s.isTemplateDeclaration()) // allow inside template constraint
+ s = s.toParent();
+ assert(s);
+ cd = s.isClassDeclaration();
+ //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
+ if (!cd)
+ goto Lerr;
+ if (!cd.baseClass)
+ {
+ e.error("no base class for `%s`", cd.toChars());
+ e.type = cd.type.addMod(e.var.type.mod);
+ }
+ else
+ {
+ e.type = cd.baseClass.type;
+ e.type = e.type.castMod(e.var.type.mod);
+ }
+
+ if (e.var.checkNestedReference(sc, e.loc))
+ return setError();
+
+ result = e;
+ return;
+
+ Lerr:
+ e.error("`super` is only allowed in non-static class member functions");
+ result = ErrorExp.get();
+ }
+
+ override void visit(NullExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("NullExp::semantic('%s')\n", e.toChars());
+ }
+ // NULL is the same as (void *)0
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+ e.type = Type.tnull;
+ result = e;
+ }
+
+ override void visit(StringExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("StringExp::semantic() %s\n", e.toChars());
+ }
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+
+ OutBuffer buffer;
+ size_t newlen = 0;
+ size_t u;
+ dchar c;
+
+ switch (e.postfix)
+ {
+ case 'd':
+ for (u = 0; u < e.len;)
+ {
+ if (const p = utf_decodeChar(e.peekString(), u, c))
+ {
+ e.error("%.*s", cast(int)p.length, p.ptr);
+ return setError();
+ }
+ else
+ {
+ buffer.write4(c);
+ newlen++;
+ }
+ }
+ buffer.write4(0);
+ e.setData(buffer.extractData(), newlen, 4);
+ if (sc && sc.flags & SCOPE.Cfile)
+ e.type = Type.tuns32.pointerTo();
+ else
+ e.type = Type.tdchar.immutableOf().arrayOf();
+ e.committed = 1;
+ break;
+
+ case 'w':
+ for (u = 0; u < e.len;)
+ {
+ if (const p = utf_decodeChar(e.peekString(), u, c))
+ {
+ e.error("%.*s", cast(int)p.length, p.ptr);
+ return setError();
+ }
+ else
+ {
+ buffer.writeUTF16(c);
+ newlen++;
+ if (c >= 0x10000)
+ newlen++;
+ }
+ }
+ buffer.writeUTF16(0);
+ e.setData(buffer.extractData(), newlen, 2);
+ if (sc && sc.flags & SCOPE.Cfile)
+ e.type = Type.tuns16.pointerTo();
+ else
+ e.type = Type.twchar.immutableOf().arrayOf();
+ e.committed = 1;
+ break;
+
+ case 'c':
+ e.committed = 1;
+ goto default;
+
+ default:
+ if (sc && sc.flags & SCOPE.Cfile)
+ e.type = Type.tchar.pointerTo();
+ else
+ e.type = Type.tchar.immutableOf().arrayOf();
+ break;
+ }
+ e.type = e.type.typeSemantic(e.loc, sc);
+ //type = type.immutableOf();
+ //printf("type = %s\n", type.toChars());
+
+ result = e;
+ }
+
+ override void visit(TupleExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("+TupleExp::semantic(%s)\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (exp.e0)
+ exp.e0 = exp.e0.expressionSemantic(sc);
+
+ // Run semantic() on each argument
+ bool err = false;
+ for (size_t i = 0; i < exp.exps.dim; i++)
+ {
+ Expression e = (*exp.exps)[i];
+ e = e.expressionSemantic(sc);
+ if (!e.type)
+ {
+ exp.error("`%s` has no value", e.toChars());
+ err = true;
+ }
+ else if (e.op == TOK.error)
+ err = true;
+ else
+ (*exp.exps)[i] = e;
+ }
+ if (err)
+ return setError();
+
+ expandTuples(exp.exps);
+
+ exp.type = new TypeTuple(exp.exps);
+ exp.type = exp.type.typeSemantic(exp.loc, sc);
+ //printf("-TupleExp::semantic(%s)\n", toChars());
+ result = exp;
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("ArrayLiteralExp::semantic('%s')\n", e.toChars());
+ }
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+
+ /* Perhaps an empty array literal [ ] should be rewritten as null?
+ */
+
+ if (e.basis)
+ e.basis = e.basis.expressionSemantic(sc);
+ if (arrayExpressionSemantic(e.elements, sc) || (e.basis && e.basis.op == TOK.error))
+ return setError();
+
+ expandTuples(e.elements);
+
+ if (e.basis)
+ e.elements.push(e.basis);
+ Type t0 = arrayExpressionToCommonType(sc, *e.elements);
+ if (e.basis)
+ e.basis = e.elements.pop();
+ if (t0 is null)
+ return setError();
+
+ e.type = t0.arrayOf();
+ e.type = e.type.typeSemantic(e.loc, sc);
+
+ /* Disallow array literals of type void being used.
+ */
+ if (e.elements.dim > 0 && t0.ty == Tvoid)
+ {
+ e.error("`%s` of type `%s` has no value", e.toChars(), e.type.toChars());
+ return setError();
+ }
+
+ if (global.params.useTypeInfo && Type.dtypeinfo)
+ semanticTypeInfo(sc, e.type);
+
+ result = e;
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars());
+ }
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+
+ // Run semantic() on each element
+ bool err_keys = arrayExpressionSemantic(e.keys, sc);
+ bool err_vals = arrayExpressionSemantic(e.values, sc);
+ if (err_keys || err_vals)
+ return setError();
+
+ expandTuples(e.keys);
+ expandTuples(e.values);
+ if (e.keys.dim != e.values.dim)
+ {
+ e.error("number of keys is %llu, must match number of values %llu",
+ cast(ulong) e.keys.dim, cast(ulong) e.values.dim);
+ return setError();
+ }
+
+ Type tkey = arrayExpressionToCommonType(sc, *e.keys);
+ Type tvalue = arrayExpressionToCommonType(sc, *e.values);
+ if (tkey is null || tvalue is null)
+ return setError();
+
+ e.type = new TypeAArray(tvalue, tkey);
+ e.type = e.type.typeSemantic(e.loc, sc);
+
+ semanticTypeInfo(sc, e.type);
+
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ {
+ if (checkAssocArrayLiteralEscape(sc, e, false))
+ return setError();
+ }
+
+ result = e;
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("StructLiteralExp::semantic('%s')\n", e.toChars());
+ }
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+
+ e.sd.size(e.loc);
+ if (e.sd.sizeok != Sizeok.done)
+ return setError();
+
+ // run semantic() on each element
+ if (arrayExpressionSemantic(e.elements, sc))
+ return setError();
+
+ expandTuples(e.elements);
+
+ /* Fit elements[] to the corresponding type of field[].
+ */
+ if (!e.sd.fit(e.loc, sc, e.elements, e.stype))
+ return setError();
+
+ /* Fill out remainder of elements[] with default initializers for fields[]
+ */
+ if (!e.sd.fill(e.loc, e.elements, false))
+ {
+ /* An error in the initializer needs to be recorded as an error
+ * in the enclosing function or template, since the initializer
+ * will be part of the stuct declaration.
+ */
+ global.increaseErrorCount();
+ return setError();
+ }
+
+ if (checkFrameAccess(e.loc, sc, e.sd, e.elements.dim))
+ return setError();
+
+ e.type = e.stype ? e.stype : e.sd.type;
+ result = e;
+ }
+
+ override void visit(CompoundLiteralExp cle)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("CompoundLiteralExp::semantic('%s')\n", cle.toChars());
+ }
+ Type t = cle.type.typeSemantic(cle.loc, sc);
+ auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
+ auto e = initializerToExpression(init, t);
+ if (!e)
+ {
+ error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
+ return setError();
+ }
+ result = e;
+ return;
+ }
+
+ override void visit(TypeExp exp)
+ {
+ if (exp.type.ty == Terror)
+ return setError();
+
+ //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
+ Expression e;
+ Type t;
+ Dsymbol s;
+
+ dmd.typesem.resolve(exp.type, exp.loc, sc, e, t, s, true);
+ if (e)
+ {
+ // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
+ // then rewrite as `(this.var)` in case it would be followed by a DotVar
+ // to fix https://issues.dlang.org/show_bug.cgi?id=9490
+ VarExp ve = e.isVarExp();
+ if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) &&
+ sc.func && sc.func.needThis && ve.var.toParent2().isAggregateDeclaration())
+ {
+ // printf("apply fix for issue 9490: add `this.` to `%s`...\n", e.toChars());
+ e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false);
+ }
+ //printf("e = %s %s\n", Token::toChars(e.op), e.toChars());
+ e = e.expressionSemantic(sc);
+ }
+ else if (t)
+ {
+ //printf("t = %d %s\n", t.ty, t.toChars());
+ exp.type = t.typeSemantic(exp.loc, sc);
+ e = exp;
+ }
+ else if (s)
+ {
+ //printf("s = %s %s\n", s.kind(), s.toChars());
+ e = symbolToExp(s, exp.loc, sc, true);
+ }
+ else
+ assert(0);
+
+ if (global.params.vcomplex)
+ exp.type.checkComplexTransition(exp.loc, sc);
+
+ result = e;
+ }
+
+ override void visit(ScopeExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ ScopeDsymbol sds2 = exp.sds;
+ TemplateInstance ti = sds2.isTemplateInstance();
+ while (ti)
+ {
+ WithScopeSymbol withsym;
+ if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
+ return setError();
+ if (withsym && withsym.withstate.wthis)
+ {
+ Expression e = new VarExp(exp.loc, withsym.withstate.wthis);
+ e = new DotTemplateInstanceExp(exp.loc, e, ti);
+ result = e.expressionSemantic(sc);
+ return;
+ }
+ if (ti.needsTypeInference(sc))
+ {
+ if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
+ {
+ Dsymbol p = td.toParentLocal();
+ FuncDeclaration fdthis = hasThis(sc);
+ AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
+ if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
+ {
+ Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
+ result = e.expressionSemantic(sc);
+ return;
+ }
+ }
+ else if (OverloadSet os = ti.tempdecl.isOverloadSet())
+ {
+ FuncDeclaration fdthis = hasThis(sc);
+ AggregateDeclaration ad = os.parent.isAggregateDeclaration();
+ if (fdthis && ad && fdthis.isMemberLocal() == ad)
+ {
+ Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
+ result = e.expressionSemantic(sc);
+ return;
+ }
+ }
+ // ti is an instance which requires IFTI.
+ exp.sds = ti;
+ exp.type = Type.tvoid;
+ result = exp;
+ return;
+ }
+ ti.dsymbolSemantic(sc);
+ if (!ti.inst || ti.errors)
+ return setError();
+
+ Dsymbol s = ti.toAlias();
+ if (s == ti)
+ {
+ exp.sds = ti;
+ exp.type = Type.tvoid;
+ result = exp;
+ return;
+ }
+ sds2 = s.isScopeDsymbol();
+ if (sds2)
+ {
+ ti = sds2.isTemplateInstance();
+ //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
+ continue;
+ }
+
+ if (auto v = s.isVarDeclaration())
+ {
+ if (!v.type)
+ {
+ exp.error("forward reference of %s `%s`", v.kind(), v.toChars());
+ return setError();
+ }
+ if ((v.storage_class & STC.manifest) && v._init)
+ {
+ /* When an instance that will be converted to a constant exists,
+ * the instance representation "foo!tiargs" is treated like a
+ * variable name, and its recursive appearance check (note that
+ * it's equivalent with a recursive instantiation of foo) is done
+ * separately from the circular initialization check for the
+ * eponymous enum variable declaration.
+ *
+ * template foo(T) {
+ * enum bool foo = foo; // recursive definition check (v.inuse)
+ * }
+ * template bar(T) {
+ * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
+ * }
+ */
+ if (ti.inuse)
+ {
+ exp.error("recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars());
+ return setError();
+ }
+ v.checkDeprecated(exp.loc, sc);
+ auto e = v.expandInitializer(exp.loc);
+ ti.inuse++;
+ e = e.expressionSemantic(sc);
+ ti.inuse--;
+ result = e;
+ return;
+ }
+ }
+
+ //printf("s = %s, '%s'\n", s.kind(), s.toChars());
+ auto e = symbolToExp(s, exp.loc, sc, true);
+ //printf("-1ScopeExp::semantic()\n");
+ result = e;
+ return;
+ }
+
+ //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
+ //printf("\tparent = '%s'\n", sds2.parent.toChars());
+ sds2.dsymbolSemantic(sc);
+
+ // (Aggregate|Enum)Declaration
+ if (auto t = sds2.getType())
+ {
+ result = (new TypeExp(exp.loc, t)).expressionSemantic(sc);
+ return;
+ }
+
+ if (auto td = sds2.isTemplateDeclaration())
+ {
+ result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc);
+ return;
+ }
+
+ exp.sds = sds2;
+ exp.type = Type.tvoid;
+ //printf("-2ScopeExp::semantic() %s\n", toChars());
+ result = exp;
+ }
+
+ override void visit(NewExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("NewExp::semantic() %s\n", exp.toChars());
+ if (exp.thisexp)
+ printf("\tthisexp = %s\n", exp.thisexp.toChars());
+ printf("\tnewtype: %s\n", exp.newtype.toChars());
+ }
+ if (exp.type) // if semantic() already run
+ {
+ result = exp;
+ return;
+ }
+
+ //for error messages if the argument in [] is not convertible to size_t
+ const originalNewtype = exp.newtype;
+
+ // https://issues.dlang.org/show_bug.cgi?id=11581
+ // With the syntax `new T[edim]` or `thisexp.new T[edim]`,
+ // T should be analyzed first and edim should go into arguments iff it's
+ // not a tuple.
+ Expression edim = null;
+ if (!exp.arguments && exp.newtype.ty == Tsarray)
+ {
+ edim = (cast(TypeSArray)exp.newtype).dim;
+ exp.newtype = (cast(TypeNext)exp.newtype).next;
+ }
+
+ ClassDeclaration cdthis = null;
+ if (exp.thisexp)
+ {
+ exp.thisexp = exp.thisexp.expressionSemantic(sc);
+ if (exp.thisexp.op == TOK.error)
+ return setError();
+
+ cdthis = exp.thisexp.type.isClassHandle();
+ if (!cdthis)
+ {
+ exp.error("`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars());
+ return setError();
+ }
+
+ sc = sc.push(cdthis);
+ exp.type = exp.newtype.typeSemantic(exp.loc, sc);
+ sc = sc.pop();
+ }
+ else
+ {
+ exp.type = exp.newtype.typeSemantic(exp.loc, sc);
+ }
+ if (exp.type.ty == Terror)
+ return setError();
+
+ if (edim)
+ {
+ if (exp.type.toBasetype().ty == Ttuple)
+ {
+ // --> new T[edim]
+ exp.type = new TypeSArray(exp.type, edim);
+ exp.type = exp.type.typeSemantic(exp.loc, sc);
+ if (exp.type.ty == Terror)
+ return setError();
+ }
+ else
+ {
+ // --> new T[](edim)
+ exp.arguments = new Expressions();
+ exp.arguments.push(edim);
+ exp.type = exp.type.arrayOf();
+ }
+ }
+
+ exp.newtype = exp.type; // in case type gets cast to something else
+ Type tb = exp.type.toBasetype();
+ //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
+ if (arrayExpressionSemantic(exp.newargs, sc) ||
+ preFunctionParameters(sc, exp.newargs))
+ {
+ return setError();
+ }
+ if (arrayExpressionSemantic(exp.arguments, sc))
+ {
+ return setError();
+ }
+ //https://issues.dlang.org/show_bug.cgi?id=20547
+ //exp.arguments are the "parameters" to [], not to a real function
+ //so the errors that come from preFunctionParameters are misleading
+ if (originalNewtype.ty == Tsarray)
+ {
+ if (preFunctionParameters(sc, exp.arguments, false))
+ {
+ exp.error("cannot create a `%s` with `new`", originalNewtype.toChars());
+ return setError();
+ }
+ }
+ else if (preFunctionParameters(sc, exp.arguments))
+ {
+ return setError();
+ }
+
+ if (exp.thisexp && tb.ty != Tclass)
+ {
+ exp.error("`.new` is only for allocating nested classes, not `%s`", tb.toChars());
+ return setError();
+ }
+
+ const size_t nargs = exp.arguments ? exp.arguments.dim : 0;
+ Expression newprefix = null;
+
+ if (tb.ty == Tclass)
+ {
+ auto cd = (cast(TypeClass)tb).sym;
+ cd.size(exp.loc);
+ if (cd.sizeok != Sizeok.done)
+ return setError();
+ if (!cd.ctor)
+ cd.ctor = cd.searchCtor();
+ if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
+ {
+ exp.error("default construction is disabled for type `%s`", cd.type.toChars());
+ return setError();
+ }
+
+ if (cd.isInterfaceDeclaration())
+ {
+ exp.error("cannot create instance of interface `%s`", cd.toChars());
+ return setError();
+ }
+
+ if (cd.isAbstract())
+ {
+ exp.error("cannot create instance of abstract class `%s`", cd.toChars());
+ for (size_t i = 0; i < cd.vtbl.dim; i++)
+ {
+ FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
+ if (fd && fd.isAbstract())
+ {
+ errorSupplemental(exp.loc, "function `%s` is not implemented",
+ fd.toFullSignature());
+ }
+ }
+ return setError();
+ }
+ // checkDeprecated() is already done in newtype.typeSemantic().
+
+ if (cd.isNested())
+ {
+ /* We need a 'this' pointer for the nested class.
+ * Ensure we have the right one.
+ */
+ Dsymbol s = cd.toParentLocal();
+
+ //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
+ if (auto cdn = s.isClassDeclaration())
+ {
+ if (!cdthis)
+ {
+ // Supply an implicit 'this' and try again
+ exp.thisexp = new ThisExp(exp.loc);
+ for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal())
+ {
+ if (!sp)
+ {
+ exp.error("outer class `%s` `this` needed to `new` nested class `%s`",
+ cdn.toChars(), cd.toChars());
+ return setError();
+ }
+ ClassDeclaration cdp = sp.isClassDeclaration();
+ if (!cdp)
+ continue;
+ if (cdp == cdn || cdn.isBaseOf(cdp, null))
+ break;
+ // Add a '.outer' and try again
+ exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer);
+ }
+
+ exp.thisexp = exp.thisexp.expressionSemantic(sc);
+ if (exp.thisexp.op == TOK.error)
+ return setError();
+ cdthis = exp.thisexp.type.isClassHandle();
+ }
+ if (cdthis != cdn && !cdn.isBaseOf(cdthis, null))
+ {
+ //printf("cdthis = %s\n", cdthis.toChars());
+ exp.error("`this` for nested class must be of type `%s`, not `%s`",
+ cdn.toChars(), exp.thisexp.type.toChars());
+ return setError();
+ }
+ if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod))
+ {
+ exp.error("nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
+ exp.newtype.toChars(), exp.thisexp.type.toChars());
+ return setError();
+ }
+ }
+ else if (exp.thisexp)
+ {
+ exp.error("`.new` is only for allocating nested classes");
+ return setError();
+ }
+ else if (auto fdn = s.isFuncDeclaration())
+ {
+ // make sure the parent context fdn of cd is reachable from sc
+ if (!ensureStaticLinkTo(sc.parent, fdn))
+ {
+ exp.error("outer function context of `%s` is needed to `new` nested class `%s`",
+ fdn.toPrettyChars(), cd.toPrettyChars());
+ return setError();
+ }
+ }
+ else
+ assert(0);
+ }
+ else if (exp.thisexp)
+ {
+ exp.error("`.new` is only for allocating nested classes");
+ return setError();
+ }
+
+ if (cd.vthis2)
+ {
+ if (AggregateDeclaration ad2 = cd.isMember2())
+ {
+ Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
+ if (te.op != TOK.error)
+ te = getRightThis(exp.loc, sc, ad2, te, cd);
+ if (te.op == TOK.error)
+ {
+ exp.error("need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars());
+ return setError();
+ }
+ }
+ }
+
+ if (cd.disableNew)
+ {
+ exp.error("cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
+ originalNewtype.toChars());
+ return setError();
+ }
+ else
+ {
+ if (exp.newargs && exp.newargs.dim)
+ {
+ exp.error("no allocator for `%s`", cd.toChars());
+ return setError();
+ }
+ }
+
+ if (cd.ctor)
+ {
+ FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
+ if (!f || f.errors)
+ return setError();
+
+ checkFunctionAttributes(exp, sc, f);
+ checkAccess(cd, exp.loc, sc, f);
+
+ TypeFunction tf = cast(TypeFunction)f.type;
+ if (!exp.arguments)
+ exp.arguments = new Expressions();
+ if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix))
+ return setError();
+
+ exp.member = f.isCtorDeclaration();
+ assert(exp.member);
+ }
+ else
+ {
+ if (nargs)
+ {
+ exp.error("no constructor for `%s`", cd.toChars());
+ return setError();
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=19941
+ // Run semantic on all field initializers to resolve any forward
+ // references. This is the same as done for structs in sd.fill().
+ for (ClassDeclaration c = cd; c; c = c.baseClass)
+ {
+ foreach (v; c.fields)
+ {
+ if (v.inuse || v._scope is null || v._init is null ||
+ v._init.isVoidInitializer())
+ continue;
+ v.inuse++;
+ v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret);
+ v.inuse--;
+ }
+ }
+ }
+ }
+ else if (tb.ty == Tstruct)
+ {
+ auto sd = (cast(TypeStruct)tb).sym;
+ sd.size(exp.loc);
+ if (sd.sizeok != Sizeok.done)
+ return setError();
+ if (!sd.ctor)
+ sd.ctor = sd.searchCtor();
+ if (sd.noDefaultCtor && !nargs)
+ {
+ exp.error("default construction is disabled for type `%s`", sd.type.toChars());
+ return setError();
+ }
+ // checkDeprecated() is already done in newtype.typeSemantic().
+
+ if (sd.disableNew)
+ {
+ exp.error("cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
+ originalNewtype.toChars());
+ return setError();
+ }
+ else
+ {
+ if (exp.newargs && exp.newargs.dim)
+ {
+ exp.error("no allocator for `%s`", sd.toChars());
+ return setError();
+ }
+ }
+
+ if (sd.ctor && nargs)
+ {
+ FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
+ if (!f || f.errors)
+ return setError();
+
+ checkFunctionAttributes(exp, sc, f);
+ checkAccess(sd, exp.loc, sc, f);
+
+ TypeFunction tf = cast(TypeFunction)f.type;
+ if (!exp.arguments)
+ exp.arguments = new Expressions();
+ if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix))
+ return setError();
+
+ exp.member = f.isCtorDeclaration();
+ assert(exp.member);
+
+ if (checkFrameAccess(exp.loc, sc, sd, sd.fields.dim))
+ return setError();
+ }
+ else
+ {
+ if (!exp.arguments)
+ exp.arguments = new Expressions();
+
+ if (!sd.fit(exp.loc, sc, exp.arguments, tb))
+ return setError();
+
+ if (!sd.fill(exp.loc, exp.arguments, false))
+ return setError();
+
+ if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.dim : 0))
+ return setError();
+
+ /* Since a `new` allocation may escape, check each of the arguments for escaping
+ */
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ {
+ foreach (arg; *exp.arguments)
+ {
+ if (arg && checkNewEscape(sc, arg, false))
+ return setError();
+ }
+ }
+ }
+
+ exp.type = exp.type.pointerTo();
+ }
+ else if (tb.ty == Tarray)
+ {
+ if (!nargs)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=20422
+ // Without this check the compiler would give a misleading error
+ exp.error("missing length argument for array");
+ return setError();
+ }
+
+ Type tn = tb.nextOf().baseElemOf();
+ Dsymbol s = tn.toDsymbol(sc);
+ AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null;
+ if (ad && ad.noDefaultCtor)
+ {
+ exp.error("default construction is disabled for type `%s`", tb.nextOf().toChars());
+ return setError();
+ }
+ for (size_t i = 0; i < nargs; i++)
+ {
+ if (tb.ty != Tarray)
+ {
+ exp.error("too many arguments for array");
+ return setError();
+ }
+
+ Expression arg = (*exp.arguments)[i];
+ arg = resolveProperties(sc, arg);
+ arg = arg.implicitCastTo(sc, Type.tsize_t);
+ if (arg.op == TOK.error)
+ return setError();
+ arg = arg.optimize(WANTvalue);
+ if (arg.op == TOK.int64 && cast(sinteger_t)arg.toInteger() < 0)
+ {
+ exp.error("negative array index `%s`", arg.toChars());
+ return setError();
+ }
+ (*exp.arguments)[i] = arg;
+ tb = (cast(TypeDArray)tb).next.toBasetype();
+ }
+ }
+ else if (tb.isscalar())
+ {
+ if (!nargs)
+ {
+ }
+ else if (nargs == 1)
+ {
+ Expression e = (*exp.arguments)[0];
+ e = e.implicitCastTo(sc, tb);
+ (*exp.arguments)[0] = e;
+ }
+ else
+ {
+ exp.error("more than one argument for construction of `%s`", exp.type.toChars());
+ return setError();
+ }
+
+ exp.type = exp.type.pointerTo();
+ }
+ else
+ {
+ exp.error("cannot create a `%s` with `new`", exp.type.toChars());
+ return setError();
+ }
+
+ //printf("NewExp: '%s'\n", toChars());
+ //printf("NewExp:type '%s'\n", type.toChars());
+ semanticTypeInfo(sc, exp.type);
+
+ if (newprefix)
+ {
+ result = Expression.combine(newprefix, exp);
+ return;
+ }
+ result = exp;
+ }
+
+ override void visit(NewAnonClassExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("NewAnonClassExp::semantic() %s\n", e.toChars());
+ //printf("thisexp = %p\n", thisexp);
+ //printf("type: %s\n", type.toChars());
+ }
+
+ Expression d = new DeclarationExp(e.loc, e.cd);
+ sc = sc.push(); // just create new scope
+ sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
+ d = d.expressionSemantic(sc);
+ sc = sc.pop();
+
+ if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot())
+ {
+ ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module;
+ if (!sds.members)
+ sds.members = new Dsymbols();
+ sds.members.push(e.cd);
+ }
+
+ Expression n = new NewExp(e.loc, e.thisexp, e.newargs, e.cd.type, e.arguments);
+
+ Expression c = new CommaExp(e.loc, d, n);
+ result = c.expressionSemantic(sc);
+ }
+
+ override void visit(SymOffExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("SymOffExp::semantic('%s')\n", e.toChars());
+ }
+ //var.dsymbolSemantic(sc);
+ if (!e.type)
+ e.type = e.var.type.pointerTo();
+
+ if (auto v = e.var.isVarDeclaration())
+ {
+ if (v.checkNestedReference(sc, e.loc))
+ return setError();
+ }
+ else if (auto f = e.var.isFuncDeclaration())
+ {
+ if (f.checkNestedReference(sc, e.loc))
+ return setError();
+ }
+
+ result = e;
+ }
+
+ override void visit(VarExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("VarExp::semantic(%s)\n", e.toChars());
+ }
+
+ auto vd = e.var.isVarDeclaration();
+ auto fd = e.var.isFuncDeclaration();
+
+ if (fd)
+ {
+ //printf("L%d fd = %s\n", __LINE__, f.toChars());
+ if (!fd.functionSemantic())
+ return setError();
+ }
+
+ if (!e.type)
+ e.type = e.var.type;
+ if (e.type && !e.type.deco)
+ {
+ auto decl = e.var.isDeclaration();
+ if (decl)
+ decl.inuse++;
+ e.type = e.type.typeSemantic(e.loc, sc);
+ if (decl)
+ decl.inuse--;
+ }
+
+ /* Fix for 1161 doesn't work because it causes visibility
+ * problems when instantiating imported templates passing private
+ * variables as alias template parameters.
+ */
+ //checkAccess(loc, sc, NULL, var);
+
+ if (vd)
+ {
+ if (vd.checkNestedReference(sc, e.loc))
+ return setError();
+
+ // https://issues.dlang.org/show_bug.cgi?id=12025
+ // If the variable is not actually used in runtime code,
+ // the purity violation error is redundant.
+ //checkPurity(sc, vd);
+ }
+ else if (fd)
+ {
+ // TODO: If fd isn't yet resolved its overload, the checkNestedReference
+ // call would cause incorrect validation.
+ // Maybe here should be moved in CallExp, or AddrExp for functions.
+ if (fd.checkNestedReference(sc, e.loc))
+ return setError();
+ }
+ else if (auto od = e.var.isOverDeclaration())
+ {
+ e.type = Type.tvoid; // ambiguous type?
+ }
+
+ result = e;
+ }
+
+ override void visit(FuncExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("FuncExp::semantic(%s)\n", exp.toChars());
+ if (exp.fd.treq)
+ printf(" treq = %s\n", exp.fd.treq.toChars());
+ }
+
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ Expression e = exp;
+ uint olderrors;
+
+ sc = sc.push(); // just create new scope
+ sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
+ sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506
+
+ /* fd.treq might be incomplete type,
+ * so should not semantic it.
+ * void foo(T)(T delegate(int) dg){}
+ * foo(a=>a); // in IFTI, treq == T delegate(int)
+ */
+ //if (fd.treq)
+ // fd.treq = fd.treq.dsymbolSemantic(loc, sc);
+
+ exp.genIdent(sc);
+
+ // Set target of return type inference
+ if (exp.fd.treq && !exp.fd.type.nextOf())
+ {
+ TypeFunction tfv = null;
+ if (exp.fd.treq.ty == Tdelegate || exp.fd.treq.isPtrToFunction())
+ tfv = cast(TypeFunction)exp.fd.treq.nextOf();
+ if (tfv)
+ {
+ TypeFunction tfl = cast(TypeFunction)exp.fd.type;
+ tfl.next = tfv.nextOf();
+ }
+ }
+
+ //printf("td = %p, treq = %p\n", td, fd.treq);
+ if (exp.td)
+ {
+ assert(exp.td.parameters && exp.td.parameters.dim);
+ exp.td.dsymbolSemantic(sc);
+ exp.type = Type.tvoid; // temporary type
+
+ if (exp.fd.treq) // defer type determination
+ {
+ FuncExp fe;
+ if (exp.matchType(exp.fd.treq, sc, &fe) > MATCH.nomatch)
+ e = fe;
+ else
+ e = ErrorExp.get();
+ }
+ goto Ldone;
+ }
+
+ olderrors = global.errors;
+ exp.fd.dsymbolSemantic(sc);
+ if (olderrors == global.errors)
+ {
+ exp.fd.semantic2(sc);
+ if (olderrors == global.errors)
+ exp.fd.semantic3(sc);
+ }
+ if (olderrors != global.errors)
+ {
+ if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf())
+ (cast(TypeFunction)exp.fd.type).next = Type.terror;
+ e = ErrorExp.get();
+ goto Ldone;
+ }
+
+ // Type is a "delegate to" or "pointer to" the function literal
+ if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate))
+ {
+ exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
+ exp.type = exp.type.typeSemantic(exp.loc, sc);
+
+ exp.fd.tok = TOK.delegate_;
+ }
+ else
+ {
+ exp.type = new TypePointer(exp.fd.type);
+ exp.type = exp.type.typeSemantic(exp.loc, sc);
+ //type = fd.type.pointerTo();
+
+ /* A lambda expression deduced to function pointer might become
+ * to a delegate literal implicitly.
+ *
+ * auto foo(void function() fp) { return 1; }
+ * assert(foo({}) == 1);
+ *
+ * So, should keep fd.tok == TOKreserve if fd.treq == NULL.
+ */
+ if (exp.fd.treq && exp.fd.treq.ty == Tpointer)
+ {
+ // change to non-nested
+ exp.fd.tok = TOK.function_;
+ exp.fd.vthis = null;
+ }
+ }
+ exp.fd.tookAddressOf++;
+
+ Ldone:
+ sc = sc.pop();
+ result = e;
+ }
+
+ /**
+ * Perform semantic analysis on function literals
+ *
+ * Test the following construct:
+ * ---
+ * (x, y, z) { return x + y + z; }(42, 84, 1992);
+ * ---
+ */
+ Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments)
+ {
+ if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.dim)
+ {
+ for (size_t k = 0; k < arguments.dim; k++)
+ {
+ Expression checkarg = (*arguments)[k];
+ if (checkarg.op == TOK.error)
+ return checkarg;
+ }
+
+ exp.genIdent(sc);
+
+ assert(exp.td.parameters && exp.td.parameters.dim);
+ exp.td.dsymbolSemantic(sc);
+
+ TypeFunction tfl = cast(TypeFunction)exp.fd.type;
+ size_t dim = tfl.parameterList.length;
+ if (arguments.dim < dim)
+ {
+ // Default arguments are always typed, so they don't need inference.
+ Parameter p = tfl.parameterList[arguments.dim];
+ if (p.defaultArg)
+ dim = arguments.dim;
+ }
+
+ if ((tfl.parameterList.varargs == VarArg.none && arguments.dim > dim) ||
+ arguments.dim < dim)
+ {
+ OutBuffer buf;
+ foreach (idx, ref arg; *arguments)
+ buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars());
+ exp.error("function literal `%s%s` is not callable using argument types `(%s)`",
+ exp.fd.toChars(), parametersTypeToChars(tfl.parameterList),
+ buf.peekChars());
+ exp.errorSupplemental("too %s arguments, expected `%d`, got `%d`",
+ arguments.dim < dim ? "few".ptr : "many".ptr,
+ cast(int)dim, cast(int)arguments.dim);
+ return ErrorExp.get();
+ }
+
+ auto tiargs = new Objects();
+ tiargs.reserve(exp.td.parameters.dim);
+
+ for (size_t i = 0; i < exp.td.parameters.dim; i++)
+ {
+ TemplateParameter tp = (*exp.td.parameters)[i];
+ assert(dim <= tfl.parameterList.length);
+ foreach (u, p; tfl.parameterList)
+ {
+ if (u == dim)
+ break;
+
+ if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
+ {
+ Expression e = (*arguments)[u];
+ tiargs.push(e.type);
+ break;
+ }
+ }
+ }
+
+ auto ti = new TemplateInstance(exp.loc, exp.td, tiargs);
+ return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc);
+ }
+ return exp.expressionSemantic(sc);
+ }
+
+ override void visit(CallExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("CallExp::semantic() %s\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return; // semantic() already run
+ }
+
+ Objects* tiargs = null; // initial list of template arguments
+ Expression ethis = null;
+ Type tthis = null;
+ Expression e1org = exp.e1;
+
+ if (exp.e1.op == TOK.comma)
+ {
+ /* Rewrite (a,b)(args) as (a,(b(args)))
+ */
+ auto ce = cast(CommaExp)exp.e1;
+ exp.e1 = ce.e2;
+ ce.e2 = exp;
+ result = ce.expressionSemantic(sc);
+ return;
+ }
+ if (exp.e1.op == TOK.delegate_)
+ {
+ DelegateExp de = cast(DelegateExp)exp.e1;
+ exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
+ visit(exp);
+ return;
+ }
+ if (exp.e1.op == TOK.function_)
+ {
+ if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments))
+ return setError();
+
+ // Run e1 semantic even if arguments have any errors
+ FuncExp fe = cast(FuncExp)exp.e1;
+ exp.e1 = callExpSemantic(fe, sc, exp.arguments);
+ if (exp.e1.op == TOK.error)
+ {
+ result = exp.e1;
+ return;
+ }
+ }
+
+ if (Expression ex = resolveUFCS(sc, exp))
+ {
+ result = ex;
+ return;
+ }
+
+ /* This recognizes:
+ * foo!(tiargs)(funcargs)
+ */
+ if (exp.e1.op == TOK.scope_)
+ {
+ ScopeExp se = cast(ScopeExp)exp.e1;
+ TemplateInstance ti = se.sds.isTemplateInstance();
+ if (ti)
+ {
+ /* Attempt to instantiate ti. If that works, go with it.
+ * If not, go with partial explicit specialization.
+ */
+ WithScopeSymbol withsym;
+ if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
+ return setError();
+ if (withsym && withsym.withstate.wthis)
+ {
+ exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis);
+ exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti);
+ goto Ldotti;
+ }
+ if (ti.needsTypeInference(sc, 1))
+ {
+ /* Go with partial explicit specialization
+ */
+ tiargs = ti.tiargs;
+ assert(ti.tempdecl);
+ if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
+ exp.e1 = new TemplateExp(exp.loc, td);
+ else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
+ exp.e1 = new VarExp(exp.loc, od);
+ else
+ exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet());
+ }
+ else
+ {
+ Expression e1x = exp.e1.expressionSemantic(sc);
+ if (e1x.op == TOK.error)
+ {
+ result = e1x;
+ return;
+ }
+ exp.e1 = e1x;
+ }
+ }
+ }
+
+ /* This recognizes:
+ * expr.foo!(tiargs)(funcargs)
+ */
+ Ldotti:
+ if (exp.e1.op == TOK.dotTemplateInstance && !exp.e1.type)
+ {
+ DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)exp.e1;
+ TemplateInstance ti = se.ti;
+ {
+ /* Attempt to instantiate ti. If that works, go with it.
+ * If not, go with partial explicit specialization.
+ */
+ if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc))
+ return setError();
+ if (ti.needsTypeInference(sc, 1))
+ {
+ /* Go with partial explicit specialization
+ */
+ tiargs = ti.tiargs;
+ assert(ti.tempdecl);
+ if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
+ exp.e1 = new DotTemplateExp(exp.loc, se.e1, td);
+ else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
+ {
+ exp.e1 = new DotVarExp(exp.loc, se.e1, od, true);
+ }
+ else
+ exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet()));
+ }
+ else
+ {
+ Expression e1x = exp.e1.expressionSemantic(sc);
+ if (e1x.op == TOK.error)
+ {
+ result = e1x;
+ return;
+ }
+ exp.e1 = e1x;
+ }
+ }
+ }
+
+ Lagain:
+ //printf("Lagain: %s\n", toChars());
+ exp.f = null;
+ if (exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_)
+ {
+ // semantic() run later for these
+ }
+ else
+ {
+ if (exp.e1.op == TOK.dotIdentifier)
+ {
+ DotIdExp die = cast(DotIdExp)exp.e1;
+ exp.e1 = die.expressionSemantic(sc);
+ /* Look for e1 having been rewritten to expr.opDispatch!(string)
+ * We handle such earlier, so go back.
+ * Note that in the rewrite, we carefully did not run semantic() on e1
+ */
+ if (exp.e1.op == TOK.dotTemplateInstance && !exp.e1.type)
+ {
+ goto Ldotti;
+ }
+ }
+ else
+ {
+ __gshared int nest;
+ if (++nest > global.recursionLimit)
+ {
+ exp.error("recursive evaluation of `%s`", exp.toChars());
+ --nest;
+ return setError();
+ }
+ Expression ex = unaSemantic(exp, sc);
+ --nest;
+ if (ex)
+ {
+ result = ex;
+ return;
+ }
+ }
+
+ /* Look for e1 being a lazy parameter
+ */
+ if (exp.e1.op == TOK.variable)
+ {
+ VarExp ve = cast(VarExp)exp.e1;
+ if (ve.var.storage_class & STC.lazy_)
+ {
+ // lazy parameters can be called without violating purity and safety
+ Type tw = ve.var.type;
+ Type tc = ve.var.type.substWildTo(MODFlags.const_);
+ auto tf = new TypeFunction(ParameterList(), tc, LINK.d, STC.safe | STC.pure_);
+ (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757
+ auto t = new TypeDelegate(tf);
+ ve.type = t.typeSemantic(exp.loc, sc);
+ }
+ VarDeclaration v = ve.var.isVarDeclaration();
+ if (v && ve.checkPurity(sc, v))
+ return setError();
+ }
+
+ if (exp.e1.op == TOK.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
+ {
+ SymOffExp se = cast(SymOffExp)exp.e1;
+ exp.e1 = new VarExp(se.loc, se.var, true);
+ exp.e1 = exp.e1.expressionSemantic(sc);
+ }
+ else if (exp.e1.op == TOK.dot)
+ {
+ DotExp de = cast(DotExp)exp.e1;
+
+ if (de.e2.op == TOK.overloadSet)
+ {
+ ethis = de.e1;
+ tthis = de.e1.type;
+ exp.e1 = de.e2;
+ }
+ }
+ else if (exp.e1.op == TOK.star && exp.e1.type.ty == Tfunction)
+ {
+ // Rewrite (*fp)(arguments) to fp(arguments)
+ exp.e1 = (cast(PtrExp)exp.e1).e1;
+ }
+ else if (exp.e1.op == TOK.type && (sc && sc.flags & SCOPE.Cfile))
+ {
+ /* Ambiguous cases arise from CParser where there is not enough
+ * information to determine if we have a function call or declaration.
+ * type-name ( identifier ) ;
+ * identifier ( identifier ) ;
+ * If exp.e1 is a type-name, then this is a declaration. C11 does not
+ * have type construction syntax, so don't convert this to a cast().
+ */
+ if (exp.arguments && exp.arguments.dim == 1)
+ {
+ Expression arg = (*exp.arguments)[0];
+ if (auto ie = (*exp.arguments)[0].isIdentifierExp())
+ {
+ TypeExp te = cast(TypeExp)exp.e1;
+ auto initializer = new VoidInitializer(ie.loc);
+ Dsymbol s = new VarDeclaration(ie.loc, te.type, ie.ident, initializer);
+ auto decls = new Dsymbols(1);
+ (*decls)[0] = s;
+ s = new LinkDeclaration(s.loc, LINK.c, decls);
+ result = new DeclarationExp(exp.loc, s);
+ result = result.expressionSemantic(sc);
+ }
+ else
+ {
+ arg.error("identifier or `(` expected");
+ result = ErrorExp.get();
+ }
+ return;
+ }
+ exp.error("identifier or `(` expected before `)`");
+ result = ErrorExp.get();
+ return;
+ }
+ }
+
+ Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
+
+ if (exp.e1.op == TOK.error)
+ {
+ result = exp.e1;
+ return;
+ }
+ if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments))
+ return setError();
+
+ // Check for call operator overload
+ if (t1)
+ {
+ if (t1.ty == Tstruct)
+ {
+ auto sd = (cast(TypeStruct)t1).sym;
+ sd.size(exp.loc); // Resolve forward references to construct object
+ if (sd.sizeok != Sizeok.done)
+ return setError();
+ if (!sd.ctor)
+ sd.ctor = sd.searchCtor();
+ /* If `sd.ctor` is a generated copy constructor, this means that it
+ is the single constructor that this struct has. In order to not
+ disable default construction, the ctor is nullified. The side effect
+ of this is that the generated copy constructor cannot be called
+ explicitly, but that is ok, because when calling a constructor the
+ default constructor should have priority over the generated copy
+ constructor.
+ */
+ if (sd.ctor)
+ {
+ auto ctor = sd.ctor.isCtorDeclaration();
+ if (ctor && ctor.isCpCtor && ctor.generated)
+ sd.ctor = null;
+ }
+
+ // First look for constructor
+ if (exp.e1.op == TOK.type && sd.ctor)
+ {
+ if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.dim))
+ goto Lx;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=20695
+ If all constructors are copy constructors, then
+ try default construction.
+ */
+ if (!sd.hasRegularCtor)
+ goto Lx;
+
+ auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
+ if (!sd.fill(exp.loc, sle.elements, true))
+ return setError();
+ if (checkFrameAccess(exp.loc, sc, sd, sle.elements.dim))
+ return setError();
+
+ // https://issues.dlang.org/show_bug.cgi?id=14556
+ // Set concrete type to avoid further redundant semantic().
+ sle.type = exp.e1.type;
+
+ /* Constructor takes a mutable object, so don't use
+ * the immutable initializer symbol.
+ */
+ sle.useStaticInit = false;
+
+ Expression e = sle;
+ if (auto cf = sd.ctor.isCtorDeclaration())
+ {
+ e = new DotVarExp(exp.loc, e, cf, true);
+ }
+ else if (auto td = sd.ctor.isTemplateDeclaration())
+ {
+ e = new DotIdExp(exp.loc, e, td.ident);
+ }
+ else if (auto os = sd.ctor.isOverloadSet())
+ {
+ e = new DotExp(exp.loc, e, new OverExp(exp.loc, os));
+ }
+ else
+ assert(0);
+ e = new CallExp(exp.loc, e, exp.arguments);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ // No constructor, look for overload of opCall
+ if (search_function(sd, Id.call))
+ goto L1;
+ // overload of opCall, therefore it's a call
+ if (exp.e1.op != TOK.type)
+ {
+ if (sd.aliasthis && !isRecursiveAliasThis(exp.att1, exp.e1.type))
+ {
+ exp.e1 = resolveAliasThis(sc, exp.e1);
+ goto Lagain;
+ }
+ exp.error("%s `%s` does not overload ()", sd.kind(), sd.toChars());
+ return setError();
+ }
+
+ /* It's a struct literal
+ */
+ Lx:
+ Expression e = new StructLiteralExp(exp.loc, sd, exp.arguments, exp.e1.type);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ else if (t1.ty == Tclass)
+ {
+ L1:
+ // Rewrite as e1.call(arguments)
+ Expression e = new DotIdExp(exp.loc, exp.e1, Id.call);
+ e = new CallExp(exp.loc, e, exp.arguments);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ else if (exp.e1.op == TOK.type && t1.isscalar())
+ {
+ Expression e;
+
+ // Make sure to use the the enum type itself rather than its
+ // base type
+ // https://issues.dlang.org/show_bug.cgi?id=16346
+ if (exp.e1.type.ty == Tenum)
+ {
+ t1 = exp.e1.type;
+ }
+
+ if (!exp.arguments || exp.arguments.dim == 0)
+ {
+ e = t1.defaultInitLiteral(exp.loc);
+ }
+ else if (exp.arguments.dim == 1)
+ {
+ e = (*exp.arguments)[0];
+ e = e.implicitCastTo(sc, t1);
+ e = new CastExp(exp.loc, e, t1);
+ }
+ else
+ {
+ exp.error("more than one argument for construction of `%s`", t1.toChars());
+ return setError();
+ }
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ }
+
+ static FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc,
+ OverloadSet os, Objects* tiargs, Type tthis, Expressions* arguments)
+ {
+ FuncDeclaration f = null;
+ foreach (s; os.a)
+ {
+ if (tiargs && s.isFuncDeclaration())
+ continue;
+ if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, FuncResolveFlag.quiet))
+ {
+ if (f2.errors)
+ return null;
+ if (f)
+ {
+ /* Error if match in more than one overload set,
+ * even if one is a 'better' match than the other.
+ */
+ ScopeDsymbol.multiplyDefined(loc, f, f2);
+ }
+ else
+ f = f2;
+ }
+ }
+ if (!f)
+ .error(loc, "no overload matches for `%s`", os.toChars());
+ else if (f.errors)
+ f = null;
+ return f;
+ }
+
+ bool isSuper = false;
+ if (exp.e1.op == TOK.dotVariable && t1.ty == Tfunction || exp.e1.op == TOK.dotTemplateDeclaration)
+ {
+ UnaExp ue = cast(UnaExp)exp.e1;
+
+ Expression ue1 = ue.e1;
+ Expression ue1old = ue1; // need for 'right this' check
+ VarDeclaration v;
+ if (ue1.op == TOK.variable && (v = (cast(VarExp)ue1).var.isVarDeclaration()) !is null && v.needThis())
+ {
+ ue.e1 = new TypeExp(ue1.loc, ue1.type);
+ ue1 = null;
+ }
+
+ DotVarExp dve;
+ DotTemplateExp dte;
+ Dsymbol s;
+ if (exp.e1.op == TOK.dotVariable)
+ {
+ dve = cast(DotVarExp)exp.e1;
+ dte = null;
+ s = dve.var;
+ tiargs = null;
+ }
+ else
+ {
+ dve = null;
+ dte = cast(DotTemplateExp)exp.e1;
+ s = dte.td;
+ }
+
+ // Do overload resolution
+ exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue1 ? ue1.type : null, exp.arguments, FuncResolveFlag.standard);
+ if (!exp.f || exp.f.errors || exp.f.type.ty == Terror)
+ return setError();
+
+ if (exp.f.interfaceVirtual)
+ {
+ /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
+ */
+ auto b = exp.f.interfaceVirtual;
+ auto ad2 = b.sym;
+ ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
+ ue.e1 = ue.e1.expressionSemantic(sc);
+ ue1 = ue.e1;
+ auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.dim);
+ assert(vi >= 0);
+ exp.f = ad2.vtbl[vi].isFuncDeclaration();
+ assert(exp.f);
+ }
+ if (exp.f.needThis())
+ {
+ AggregateDeclaration ad = exp.f.toParentLocal().isAggregateDeclaration();
+ ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f);
+ if (ue.e1.op == TOK.error)
+ {
+ result = ue.e1;
+ return;
+ }
+ ethis = ue.e1;
+ tthis = ue.e1.type;
+ if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual))
+ {
+ if (global.params.useDIP1000 == FeatureState.enabled && checkParamArgumentEscape(sc, exp.f, null, ethis, false, false))
+ return setError();
+ }
+ }
+
+ /* Cannot call public functions from inside invariant
+ * (because then the invariant would have infinite recursion)
+ */
+ if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == TOK.this_ && exp.f.addPostInvariant())
+ {
+ exp.error("cannot call `public`/`export` function `%s` from invariant", exp.f.toChars());
+ return setError();
+ }
+
+ if (!exp.ignoreAttributes)
+ checkFunctionAttributes(exp, sc, exp.f);
+ checkAccess(exp.loc, sc, ue.e1, exp.f);
+ if (!exp.f.needThis())
+ {
+ exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false));
+ }
+ else
+ {
+ if (ue1old.checkRightThis(sc))
+ return setError();
+ if (exp.e1.op == TOK.dotVariable)
+ {
+ dve.var = exp.f;
+ exp.e1.type = exp.f.type;
+ }
+ else
+ {
+ exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false);
+ exp.e1 = exp.e1.expressionSemantic(sc);
+ if (exp.e1.op == TOK.error)
+ return setError();
+ ue = cast(UnaExp)exp.e1;
+ }
+ version (none)
+ {
+ printf("ue.e1 = %s\n", ue.e1.toChars());
+ printf("f = %s\n", exp.f.toChars());
+ printf("t1 = %s\n", t1.toChars());
+ printf("e1 = %s\n", exp.e1.toChars());
+ printf("e1.type = %s\n", exp.e1.type.toChars());
+ }
+
+ // See if we need to adjust the 'this' pointer
+ AggregateDeclaration ad = exp.f.isThis();
+ ClassDeclaration cd = ue.e1.type.isClassHandle();
+ if (ad && cd && ad.isClassDeclaration())
+ {
+ if (ue.e1.op == TOK.dotType)
+ {
+ ue.e1 = (cast(DotTypeExp)ue.e1).e1;
+ exp.directcall = true;
+ }
+ else if (ue.e1.op == TOK.super_)
+ exp.directcall = true;
+ else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
+ exp.directcall = true;
+
+ if (ad != cd)
+ {
+ ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod));
+ ue.e1 = ue.e1.expressionSemantic(sc);
+ }
+ }
+ }
+ // If we've got a pointer to a function then deference it
+ // https://issues.dlang.org/show_bug.cgi?id=16483
+ if (exp.e1.type.isPtrToFunction())
+ {
+ Expression e = new PtrExp(exp.loc, exp.e1);
+ e.type = exp.e1.type.nextOf();
+ exp.e1 = e;
+ }
+ t1 = exp.e1.type;
+ }
+ else if (exp.e1.op == TOK.super_ || exp.e1.op == TOK.this_)
+ {
+ auto ad = sc.func ? sc.func.isThis() : null;
+ auto cd = ad ? ad.isClassDeclaration() : null;
+
+ isSuper = exp.e1.op == TOK.super_;
+ if (isSuper)
+ {
+ // Base class constructor call
+ if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration())
+ {
+ exp.error("super class constructor call must be in a constructor");
+ return setError();
+ }
+ if (!cd.baseClass.ctor)
+ {
+ exp.error("no super class constructor for `%s`", cd.baseClass.toChars());
+ return setError();
+ }
+ }
+ else
+ {
+ // `this` call expression must be inside a
+ // constructor
+ if (!ad || !sc.func.isCtorDeclaration())
+ {
+ exp.error("constructor call must be in a constructor");
+ return setError();
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=18719
+ // If `exp` is a call expression to another constructor
+ // then it means that all struct/class fields will be
+ // initialized after this call.
+ foreach (ref field; sc.ctorflow.fieldinit)
+ {
+ field.csx |= CSX.this_ctor;
+ }
+ }
+
+ if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt))
+ {
+ if (sc.inLoop || sc.ctorflow.callSuper & CSX.label)
+ exp.error("constructor calls not allowed in loops or after labels");
+ if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor))
+ exp.error("multiple constructor calls");
+ if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor))
+ exp.error("an earlier `return` statement skips constructor");
+ sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor);
+ }
+
+ tthis = ad.type.addMod(sc.func.type.mod);
+ auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor;
+ if (auto os = ctor.isOverloadSet())
+ exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.arguments);
+ else
+ exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.arguments, FuncResolveFlag.standard);
+
+ if (!exp.f || exp.f.errors)
+ return setError();
+
+ checkFunctionAttributes(exp, sc, exp.f);
+ checkAccess(exp.loc, sc, null, exp.f);
+
+ exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false);
+ exp.e1 = exp.e1.expressionSemantic(sc);
+ // https://issues.dlang.org/show_bug.cgi?id=21095
+ if (exp.e1.op == TOK.error)
+ return setError();
+ t1 = exp.e1.type;
+
+ // BUG: this should really be done by checking the static
+ // call graph
+ if (exp.f == sc.func)
+ {
+ exp.error("cyclic constructor call");
+ return setError();
+ }
+ }
+ else if (exp.e1.op == TOK.overloadSet)
+ {
+ auto os = (cast(OverExp)exp.e1).vars;
+ exp.f = resolveOverloadSet(exp.loc, sc, os, tiargs, tthis, exp.arguments);
+ if (!exp.f)
+ return setError();
+ if (ethis)
+ exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false);
+ else
+ exp.e1 = new VarExp(exp.loc, exp.f, false);
+ goto Lagain;
+ }
+ else if (!t1)
+ {
+ exp.error("function expected before `()`, not `%s`", exp.e1.toChars());
+ return setError();
+ }
+ else if (t1.ty == Terror)
+ {
+ return setError();
+ }
+ else if (t1.ty != Tfunction)
+ {
+ TypeFunction tf;
+ const(char)* p;
+ Dsymbol s;
+ exp.f = null;
+ if (exp.e1.op == TOK.function_)
+ {
+ // function literal that direct called is always inferred.
+ assert((cast(FuncExp)exp.e1).fd);
+ exp.f = (cast(FuncExp)exp.e1).fd;
+ tf = cast(TypeFunction)exp.f.type;
+ p = "function literal";
+ }
+ else if (t1.ty == Tdelegate)
+ {
+ TypeDelegate td = cast(TypeDelegate)t1;
+ assert(td.next.ty == Tfunction);
+ tf = cast(TypeFunction)td.next;
+ p = "delegate";
+ }
+ else if (auto tfx = t1.isPtrToFunction())
+ {
+ tf = tfx;
+ p = "function pointer";
+ }
+ else if (exp.e1.op == TOK.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
+ {
+ DotVarExp dve = cast(DotVarExp)exp.e1;
+ exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.arguments, FuncResolveFlag.overloadOnly);
+ if (!exp.f)
+ return setError();
+ if (exp.f.needThis())
+ {
+ dve.var = exp.f;
+ dve.type = exp.f.type;
+ dve.hasOverloads = false;
+ goto Lagain;
+ }
+ exp.e1 = new VarExp(dve.loc, exp.f, false);
+ Expression e = new CommaExp(exp.loc, dve.e1, exp);
+ result = e.expressionSemantic(sc);
+ return;
+ }
+ else if (exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
+ {
+ s = (cast(VarExp)exp.e1).var;
+ goto L2;
+ }
+ else if (exp.e1.op == TOK.template_)
+ {
+ s = (cast(TemplateExp)exp.e1).td;
+ L2:
+ exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.arguments, FuncResolveFlag.standard);
+ if (!exp.f || exp.f.errors)
+ return setError();
+ if (exp.f.needThis())
+ {
+ if (hasThis(sc))
+ {
+ // Supply an implicit 'this', as in
+ // this.ident
+ exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false);
+ goto Lagain;
+ }
+ else if (isNeedThisScope(sc, exp.f))
+ {
+ exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars());
+ return setError();
+ }
+ }
+ exp.e1 = new VarExp(exp.e1.loc, exp.f, false);
+ goto Lagain;
+ }
+ else
+ {
+ exp.error("function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars());
+ return setError();
+ }
+
+ const(char)* failMessage;
+ Expression[] fargs = exp.arguments ? (*exp.arguments)[] : null;
+ if (!tf.callMatch(null, fargs, 0, &failMessage, sc))
+ {
+ OutBuffer buf;
+ buf.writeByte('(');
+ argExpTypesToCBuffer(&buf, exp.arguments);
+ buf.writeByte(')');
+ if (tthis)
+ tthis.modToBuffer(&buf);
+
+ //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
+ .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
+ p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
+ if (failMessage)
+ errorSupplemental(exp.loc, "%s", failMessage);
+ return setError();
+ }
+ // Purity and safety check should run after testing arguments matching
+ if (exp.f)
+ {
+ exp.checkPurity(sc, exp.f);
+ exp.checkSafety(sc, exp.f);
+ exp.checkNogc(sc, exp.f);
+ if (exp.f.checkNestedReference(sc, exp.loc))
+ return setError();
+ }
+ else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
+ {
+ bool err = false;
+ if (!tf.purity && sc.func.setImpure())
+ {
+ exp.error("`pure` %s `%s` cannot call impure %s `%s`",
+ sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
+ err = true;
+ }
+ if (!tf.isnogc && sc.func.setGC())
+ {
+ exp.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
+ sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
+ err = true;
+ }
+ if (tf.trust <= TRUST.system && sc.func.setUnsafe())
+ {
+ exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`",
+ sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
+ err = true;
+ }
+ if (err)
+ return setError();
+ }
+
+ if (t1.ty == Tpointer)
+ {
+ Expression e = new PtrExp(exp.loc, exp.e1);
+ e.type = tf;
+ exp.e1 = e;
+ }
+ t1 = tf;
+ }
+ else if (exp.e1.op == TOK.variable)
+ {
+ // Do overload resolution
+ VarExp ve = cast(VarExp)exp.e1;
+
+ exp.f = ve.var.isFuncDeclaration();
+ assert(exp.f);
+ tiargs = null;
+
+ if (exp.f.overnext)
+ exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, FuncResolveFlag.overloadOnly);
+ else
+ {
+ exp.f = exp.f.toAliasFunc();
+ TypeFunction tf = cast(TypeFunction)exp.f.type;
+ const(char)* failMessage;
+ Expression[] fargs = exp.arguments ? (*exp.arguments)[] : null;
+ if (!tf.callMatch(null, fargs, 0, &failMessage, sc))
+ {
+ OutBuffer buf;
+ buf.writeByte('(');
+ argExpTypesToCBuffer(&buf, exp.arguments);
+ buf.writeByte(')');
+
+ //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
+ .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
+ exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
+ if (failMessage)
+ errorSupplemental(exp.loc, "%s", failMessage);
+ exp.f = null;
+ }
+ }
+ if (!exp.f || exp.f.errors)
+ return setError();
+
+ if (exp.f.needThis())
+ {
+ // Change the ancestor lambdas to delegate before hasThis(sc) call.
+ if (exp.f.checkNestedReference(sc, exp.loc))
+ return setError();
+
+ if (hasThis(sc))
+ {
+ // Supply an implicit 'this', as in
+ // this.ident
+ exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var);
+ // Note: we cannot use f directly, because further overload resolution
+ // through the supplied 'this' may cause different result.
+ goto Lagain;
+ }
+ else if (isNeedThisScope(sc, exp.f))
+ {
+ // At this point it is possible that `exp.f` had an ambiguity error that was
+ // silenced because the previous call to `resolveFuncCall` was done using
+ // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
+ // is printed, redo the call with `FuncResolveFlag.standard`.
+ //
+ // https://issues.dlang.org/show_bug.cgi?id=22157
+ if (exp.f.overnext)
+ exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, FuncResolveFlag.standard);
+
+ if (!exp.f || exp.f.errors)
+ return setError();
+
+ // If no error is printed, it means that `f` is the single matching overload
+ // and it needs `this`.
+ exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars());
+ return setError();
+ }
+ }
+
+ checkFunctionAttributes(exp, sc, exp.f);
+ checkAccess(exp.loc, sc, null, exp.f);
+ if (exp.f.checkNestedReference(sc, exp.loc))
+ return setError();
+
+ ethis = null;
+ tthis = null;
+
+ if (ve.hasOverloads)
+ {
+ exp.e1 = new VarExp(ve.loc, exp.f, false);
+ exp.e1.type = exp.f.type;
+ }
+ t1 = exp.f.type;
+ }
+ assert(t1.ty == Tfunction);
+
+ Expression argprefix;
+ if (!exp.arguments)
+ exp.arguments = new Expressions();
+ if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.arguments, exp.f, &exp.type, &argprefix))
+ return setError();
+
+ if (!exp.type)
+ {
+ exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922
+ // avoid recursive expression printing
+ exp.error("forward reference to inferred return type of function call `%s`", exp.toChars());
+ return setError();
+ }
+
+ if (exp.f && exp.f.tintro)
+ {
+ Type t = exp.type;
+ int offset = 0;
+ TypeFunction tf = cast(TypeFunction)exp.f.tintro;
+ if (tf.next.isBaseOf(t, &offset) && offset)
+ {
+ exp.type = tf.next;
+ result = Expression.combine(argprefix, exp.castTo(sc, t));
+ return;
+ }
+ }
+
+ // Handle the case of a direct lambda call
+ if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof)
+ {
+ exp.f.tookAddressOf = 0;
+ }
+
+ result = Expression.combine(argprefix, exp);
+
+ if (isSuper)
+ {
+ auto ad = sc.func ? sc.func.isThis() : null;
+ auto cd = ad ? ad.isClassDeclaration() : null;
+ if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody)
+ {
+ // if super is defined in C++, it sets the vtable pointer to the base class
+ // so we have to restore it, but still return 'this' from super() call:
+ // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
+ Loc loc = exp.loc;
+
+ auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr);
+ auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr);
+ auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl);
+
+ auto superTmpDecl = copyToTemp(0, "__superTmp", result);
+ auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl);
+
+ auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp);
+
+ auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl));
+
+ Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl)));
+ result = e.expressionSemantic(sc);
+ }
+ }
+
+ // declare dual-context container
+ if (exp.f && exp.f.isThis2 && !sc.intypeof && sc.func)
+ {
+ // check access to second `this`
+ if (AggregateDeclaration ad2 = exp.f.isMember2())
+ {
+ Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
+ if (te.op != TOK.error)
+ te = getRightThis(exp.loc, sc, ad2, te, exp.f);
+ if (te.op == TOK.error)
+ {
+ exp.error("need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars());
+ return setError();
+ }
+ }
+ exp.vthis2 = makeThis2Argument(exp.loc, sc, exp.f);
+ Expression de = new DeclarationExp(exp.loc, exp.vthis2);
+ result = Expression.combine(de, result);
+ result = result.expressionSemantic(sc);
+ }
+ }
+
+ override void visit(DeclarationExp e)
+ {
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+ static if (LOGSEMANTIC)
+ {
+ printf("DeclarationExp::semantic() %s\n", e.toChars());
+ }
+
+ uint olderrors = global.errors;
+
+ /* This is here to support extern(linkage) declaration,
+ * where the extern(linkage) winds up being an AttribDeclaration
+ * wrapper.
+ */
+ Dsymbol s = e.declaration;
+
+ while (1)
+ {
+ AttribDeclaration ad = s.isAttribDeclaration();
+ if (ad)
+ {
+ if (ad.decl && ad.decl.dim == 1)
+ {
+ s = (*ad.decl)[0];
+ continue;
+ }
+ }
+ break;
+ }
+
+ VarDeclaration v = s.isVarDeclaration();
+ if (v)
+ {
+ // Do semantic() on initializer first, so:
+ // int a = a;
+ // will be illegal.
+ e.declaration.dsymbolSemantic(sc);
+ s.parent = sc.parent;
+ }
+
+ //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
+ // Insert into both local scope and function scope.
+ // Must be unique in both.
+ if (s.ident)
+ {
+ if (!sc.insert(s))
+ {
+ auto conflict = sc.search(Loc.initial, s.ident, null);
+ e.error("declaration `%s` is already defined", s.toPrettyChars());
+ errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
+ conflict.kind(), conflict.toChars());
+ return setError();
+ }
+ else if (sc.func)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=11720
+ if ((s.isFuncDeclaration() ||
+ s.isAggregateDeclaration() ||
+ s.isEnumDeclaration() ||
+ s.isTemplateDeclaration() ||
+ v
+ ) && !sc.func.localsymtab.insert(s))
+ {
+ // Get the previous symbol
+ Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident);
+
+ // Perturb the name mangling so that the symbols can co-exist
+ // instead of colliding
+ s.localNum = cast(ushort)(originalSymbol.localNum + 1);
+ assert(s.localNum); // 65535 should be enough for anyone
+
+ // Replace originalSymbol with s, which updates the localCount
+ sc.func.localsymtab.update(s);
+
+ // The mangling change only works for D mangling
+ }
+// else
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=21272
+ * If we are in a foreach body we need to extract the
+ * function containing the foreach
+ */
+ FuncDeclaration fes_enclosing_func;
+ if (sc.func && sc.func.fes)
+ fes_enclosing_func = sc.enclosing.enclosing.func;
+
+ // Disallow shadowing
+ for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing)
+ {
+ Dsymbol s2;
+ if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
+ {
+ // allow STC.local symbols to be shadowed
+ // TODO: not really an optimal design
+ auto decl = s2.isDeclaration();
+ if (!decl || !(decl.storage_class & STC.local))
+ {
+ if (sc.func.fes)
+ {
+ e.deprecation("%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
+ }
+ else
+ {
+ e.error("%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
+ return setError();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (!s.isVarDeclaration())
+ {
+ Scope* sc2 = sc;
+ if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc))
+ sc2 = sc.push();
+ sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc);
+ e.declaration.dsymbolSemantic(sc2);
+ if (sc2 != sc)
+ sc2.pop();
+ s.parent = sc.parent;
+ }
+ if (global.errors == olderrors)
+ {
+ e.declaration.semantic2(sc);
+ if (global.errors == olderrors)
+ {
+ e.declaration.semantic3(sc);
+ }
+ }
+ // todo: error in declaration should be propagated.
+
+ e.type = Type.tvoid;
+ result = e;
+ }
+
+ override void visit(TypeidExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("TypeidExp::semantic() %s\n", exp.toChars());
+ }
+ Type ta = isType(exp.obj);
+ Expression ea = isExpression(exp.obj);
+ Dsymbol sa = isDsymbol(exp.obj);
+ //printf("ta %p ea %p sa %p\n", ta, ea, sa);
+
+ if (ta)
+ {
+ dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true);
+ }
+
+ if (ea)
+ {
+ if (auto sym = getDsymbol(ea))
+ ea = symbolToExp(sym, exp.loc, sc, false);
+ else
+ ea = ea.expressionSemantic(sc);
+ ea = resolveProperties(sc, ea);
+ ta = ea.type;
+ if (ea.op == TOK.type)
+ ea = null;
+ }
+
+ if (!ta)
+ {
+ //printf("ta %p ea %p sa %p\n", ta, ea, sa);
+ exp.error("no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : ""));
+ return setError();
+ }
+
+ if (global.params.vcomplex)
+ ta.checkComplexTransition(exp.loc, sc);
+
+ Expression e;
+ auto tb = ta.toBasetype();
+ if (ea && tb.ty == Tclass)
+ {
+ if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp)
+ {
+ error(exp.loc, "Runtime type information is not supported for `extern(C++)` classes");
+ e = ErrorExp.get();
+ }
+ else if (!Type.typeinfoclass)
+ {
+ error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
+ e = ErrorExp.get();
+ }
+ else
+ {
+ /* Get the dynamic type, which is .classinfo
+ */
+ ea = ea.expressionSemantic(sc);
+ e = new TypeidExp(ea.loc, ea);
+ e.type = Type.typeinfoclass.type;
+ }
+ }
+ else if (ta.ty == Terror)
+ {
+ e = ErrorExp.get();
+ }
+ else
+ {
+ // Handle this in the glue layer
+ e = new TypeidExp(exp.loc, ta);
+ e.type = getTypeInfoType(exp.loc, ta, sc);
+
+ semanticTypeInfo(sc, ta);
+
+ if (ea)
+ {
+ e = new CommaExp(exp.loc, ea, e); // execute ea
+ e = e.expressionSemantic(sc);
+ }
+ }
+ result = e;
+ }
+
+ override void visit(TraitsExp e)
+ {
+ result = semanticTraits(e, sc);
+ }
+
+ override void visit(HaltExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("HaltExp::semantic()\n");
+ }
+ e.type = Type.tnoreturn;
+ result = e;
+ }
+
+ override void visit(IsExp e)
+ {
+ /* is(targ id tok tspec)
+ * is(targ id : tok2)
+ * is(targ id == tok2)
+ */
+ Type tded = null;
+
+ void yes()
+ {
+ //printf("yes\n");
+ if (!e.id)
+ {
+ result = IntegerExp.createBool(true);
+ return;
+ }
+
+ Dsymbol s;
+ Tuple tup = isTuple(tded);
+ if (tup)
+ s = new TupleDeclaration(e.loc, e.id, &tup.objects);
+ else
+ s = new AliasDeclaration(e.loc, e.id, tded);
+ s.dsymbolSemantic(sc);
+
+ /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
+ * More investigation is needed.
+ */
+ if (!tup && !sc.insert(s))
+ {
+ auto conflict = sc.search(Loc.initial, s.ident, null);
+ e.error("declaration `%s` is already defined", s.toPrettyChars());
+ errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
+ conflict.kind(), conflict.toChars());
+ }
+
+ unSpeculative(sc, s);
+
+ result = IntegerExp.createBool(true);
+ }
+ void no()
+ {
+ result = IntegerExp.createBool(false);
+ //printf("no\n");
+ }
+
+ static if (LOGSEMANTIC)
+ {
+ printf("IsExp::semantic(%s)\n", e.toChars());
+ }
+ if (e.id && !(sc.flags & SCOPE.condition))
+ {
+ e.error("can only declare type aliases within `static if` conditionals or `static assert`s");
+ return setError();
+ }
+
+ if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types.
+ {
+ const oldErrors = global.startGagging();
+ Dsymbol sym = e.targ.toDsymbol(sc);
+ global.endGagging(oldErrors);
+
+ if (sym is null)
+ return no();
+ Package p = resolveIsPackage(sym);
+ if (p is null)
+ return no();
+ if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
+ return no();
+ else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
+ return no();
+ tded = e.targ;
+ return yes();
+ }
+
+ {
+ Scope* sc2 = sc.copy(); // keep sc.flags
+ sc2.tinst = null;
+ sc2.minst = null;
+ sc2.flags |= SCOPE.fullinst;
+ Type t = e.targ.trySemantic(e.loc, sc2);
+ sc2.pop();
+ if (!t) // errors, so condition is false
+ return no();
+ e.targ = t;
+ }
+
+ if (e.tok2 != TOK.reserved)
+ {
+ switch (e.tok2)
+ {
+ case TOK.struct_:
+ if (e.targ.ty != Tstruct)
+ return no();
+ if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration())
+ return no();
+ tded = e.targ;
+ break;
+
+ case TOK.union_:
+ if (e.targ.ty != Tstruct)
+ return no();
+ if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration())
+ return no();
+ tded = e.targ;
+ break;
+
+ case TOK.class_:
+ if (e.targ.ty != Tclass)
+ return no();
+ if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
+ return no();
+ tded = e.targ;
+ break;
+
+ case TOK.interface_:
+ if (e.targ.ty != Tclass)
+ return no();
+ if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
+ return no();
+ tded = e.targ;
+ break;
+
+ case TOK.const_:
+ if (!e.targ.isConst())
+ return no();
+ tded = e.targ;
+ break;
+
+ case TOK.immutable_:
+ if (!e.targ.isImmutable())
+ return no();
+ tded = e.targ;
+ break;
+
+ case TOK.shared_:
+ if (!e.targ.isShared())
+ return no();
+ tded = e.targ;
+ break;
+
+ case TOK.inout_:
+ if (!e.targ.isWild())
+ return no();
+ tded = e.targ;
+ break;
+
+ case TOK.super_:
+ // If class or interface, get the base class and interfaces
+ if (e.targ.ty != Tclass)
+ return no();
+ else
+ {
+ ClassDeclaration cd = (cast(TypeClass)e.targ).sym;
+ auto args = new Parameters();
+ args.reserve(cd.baseclasses.dim);
+ if (cd.semanticRun < PASS.semanticdone)
+ cd.dsymbolSemantic(null);
+ for (size_t i = 0; i < cd.baseclasses.dim; i++)
+ {
+ BaseClass* b = (*cd.baseclasses)[i];
+ args.push(new Parameter(STC.in_, b.type, null, null, null));
+ }
+ tded = new TypeTuple(args);
+ }
+ break;
+
+ case TOK.enum_:
+ if (e.targ.ty != Tenum)
+ return no();
+ if (e.id)
+ tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc);
+ else
+ tded = e.targ;
+
+ if (tded.ty == Terror)
+ return setError();
+ break;
+
+ case TOK.delegate_:
+ if (e.targ.ty != Tdelegate)
+ return no();
+ tded = (cast(TypeDelegate)e.targ).next; // the underlying function type
+ break;
+
+ case TOK.function_:
+ case TOK.parameters:
+ {
+ if (e.targ.ty != Tfunction)
+ return no();
+ tded = e.targ;
+
+ /* Generate tuple from function parameter types.
+ */
+ assert(tded.ty == Tfunction);
+ auto tdedf = tded.isTypeFunction();
+ auto args = new Parameters();
+ foreach (i, arg; tdedf.parameterList)
+ {
+ assert(arg && arg.type);
+ /* If one of the default arguments was an error,
+ don't return an invalid tuple
+ */
+ if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == TOK.error)
+ return setError();
+ args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl));
+ }
+ tded = new TypeTuple(args);
+ break;
+ }
+ case TOK.return_:
+ /* Get the 'return type' for the function,
+ * delegate, or pointer to function.
+ */
+ if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
+ tded = tf.next;
+ else
+ return no();
+ break;
+
+ case TOK.argumentTypes:
+ /* Generate a type tuple of the equivalent types used to determine if a
+ * function argument of this type can be passed in registers.
+ * The results of this are highly platform dependent, and intended
+ * primarly for use in implementing va_arg().
+ */
+ tded = target.toArgTypes(e.targ);
+ if (!tded)
+ return no();
+ // not valid for a parameter
+ break;
+
+ case TOK.vector:
+ if (e.targ.ty != Tvector)
+ return no();
+ tded = (cast(TypeVector)e.targ).basetype;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=18753
+ if (tded)
+ return yes();
+ return no();
+ }
+ else if (e.tspec && !e.id && !(e.parameters && e.parameters.dim))
+ {
+ /* Evaluate to true if targ matches tspec
+ * is(targ == tspec)
+ * is(targ : tspec)
+ */
+ e.tspec = e.tspec.typeSemantic(e.loc, sc);
+ //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
+ //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
+
+ if (e.tok == TOK.colon)
+ {
+ // current scope is itself deprecated, or deprecations are not errors
+ const bool deprecationAllowed = sc.isDeprecated
+ || global.params.useDeprecated != DiagnosticReporting.error;
+ const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
+
+ // baseClass might not be set if either targ or tspec is forward referenced.
+ if (auto tc = e.targ.isTypeClass())
+ tc.sym.dsymbolSemantic(null);
+ if (auto tc = e.tspec.isTypeClass())
+ tc.sym.dsymbolSemantic(null);
+
+ if (preventAliasThis && e.targ.ty == Tstruct)
+ {
+ if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
+ return yes();
+ else
+ return no();
+ }
+ else if (preventAliasThis && e.targ.ty == Tclass)
+ {
+ if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
+ return yes();
+ else
+ return no();
+ }
+ else if (e.targ.implicitConvTo(e.tspec))
+ return yes();
+ else
+ return no();
+ }
+ else /* == */
+ {
+ if (e.targ.equals(e.tspec))
+ return yes();
+ else
+ return no();
+ }
+ }
+ else if (e.tspec)
+ {
+ /* Evaluate to true if targ matches tspec.
+ * If true, declare id as an alias for the specialized type.
+ * is(targ == tspec, tpl)
+ * is(targ : tspec, tpl)
+ * is(targ id == tspec)
+ * is(targ id : tspec)
+ * is(targ id == tspec, tpl)
+ * is(targ id : tspec, tpl)
+ */
+ Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id");
+ e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null));
+
+ Objects dedtypes = Objects(e.parameters.dim);
+ dedtypes.zero();
+
+ MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal);
+ //printf("targ: %s\n", targ.toChars());
+ //printf("tspec: %s\n", tspec.toChars());
+ if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
+ {
+ return no();
+ }
+ else
+ {
+ tded = cast(Type)dedtypes[0];
+ if (!tded)
+ tded = e.targ;
+ Objects tiargs = Objects(1);
+ tiargs[0] = e.targ;
+
+ /* Declare trailing parameters
+ */
+ for (size_t i = 1; i < e.parameters.dim; i++)
+ {
+ TemplateParameter tp = (*e.parameters)[i];
+ Declaration s = null;
+
+ m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s);
+ if (m == MATCH.nomatch)
+ return no();
+ s.dsymbolSemantic(sc);
+ if (!sc.insert(s))
+ {
+ auto conflict = sc.search(Loc.initial, s.ident, null);
+ e.error("declaration `%s` is already defined", s.toPrettyChars());
+ errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
+ conflict.kind(), conflict.toChars());
+ }
+
+ unSpeculative(sc, s);
+ }
+ return yes();
+ }
+ }
+ else if (e.id)
+ {
+ /* Declare id as an alias for type targ. Evaluate to true
+ * is(targ id)
+ */
+ tded = e.targ;
+ }
+ return yes();
+ }
+
+ override void visit(BinAssignExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp.e1.op == TOK.arrayLength)
+ {
+ // arr.length op= e2;
+ e = rewriteOpAssign(exp);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ if (exp.e1.op == TOK.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
+ {
+ if (checkNonAssignmentArrayOp(exp.e1))
+ return setError();
+
+ if (exp.e1.op == TOK.slice)
+ (cast(SliceExp)exp.e1).arrayop = true;
+
+ // T[] op= ...
+ if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
+ {
+ // T[] op= T
+ exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
+ }
+ else if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ exp.type = exp.e1.type;
+ result = arrayOp(exp, sc);
+ return;
+ }
+
+ exp.e1 = exp.e1.expressionSemantic(sc);
+ exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
+ exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
+ exp.type = exp.e1.type;
+
+ if (auto ad = isAggregate(exp.e1.type))
+ {
+ if (const s = search_function(ad, Id.opOpAssign))
+ {
+ error(exp.loc, "none of the `opOpAssign` overloads of `%s` are callable for `%s` of type `%s`", ad.toChars(), exp.e1.toChars(), exp.e1.type.toChars());
+ return setError();
+ }
+ }
+ if (exp.e1.checkScalar() ||
+ exp.e1.checkReadModifyWrite(exp.op, exp.e2) ||
+ exp.e1.checkSharedAccess(sc))
+ return setError();
+
+ int arith = (exp.op == TOK.addAssign || exp.op == TOK.minAssign || exp.op == TOK.mulAssign || exp.op == TOK.divAssign || exp.op == TOK.modAssign || exp.op == TOK.powAssign);
+ int bitwise = (exp.op == TOK.andAssign || exp.op == TOK.orAssign || exp.op == TOK.xorAssign);
+ int shift = (exp.op == TOK.leftShiftAssign || exp.op == TOK.rightShiftAssign || exp.op == TOK.unsignedRightShiftAssign);
+
+ if (bitwise && exp.type.toBasetype().ty == Tbool)
+ exp.e2 = exp.e2.implicitCastTo(sc, exp.type);
+ else if (exp.checkNoBool())
+ return setError();
+
+ if ((exp.op == TOK.addAssign || exp.op == TOK.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
+ {
+ result = scaleFactor(exp, sc);
+ return;
+ }
+
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)))
+ return setError();
+ if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)))
+ return setError();
+
+ if (shift)
+ {
+ if (exp.e2.type.toBasetype().ty != Tvector)
+ exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
+ }
+
+ if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+
+ if (exp.e1.op == TOK.error || exp.e2.op == TOK.error)
+ return setError();
+
+ e = exp.checkOpAssignTypes(sc);
+ if (e.op == TOK.error)
+ {
+ result = e;
+ return;
+ }
+
+ assert(e.op == TOK.assign || e == exp);
+ result = (cast(BinExp)e).reorderSettingAAElem(sc);
+ }
+
+ private Expression compileIt(MixinExp exp)
+ {
+ OutBuffer buf;
+ if (expressionsToString(buf, sc, exp.exps))
+ return null;
+
+ uint errors = global.errors;
+ const len = buf.length;
+ const str = buf.extractChars()[0 .. len];
+ scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false);
+ p.nextToken();
+ //printf("p.loc.linnum = %d\n", p.loc.linnum);
+
+ Expression e = p.parseExpression();
+ if (global.errors != errors)
+ return null;
+
+ if (p.token.value != TOK.endOfFile)
+ {
+ exp.error("incomplete mixin expression `%s`", str.ptr);
+ return null;
+ }
+ return e;
+ }
+
+ override void visit(MixinExp exp)
+ {
+ /* https://dlang.org/spec/expression.html#mixin_expressions
+ */
+
+ static if (LOGSEMANTIC)
+ {
+ printf("MixinExp::semantic('%s')\n", exp.toChars());
+ }
+
+ auto e = compileIt(exp);
+ if (!e)
+ return setError();
+ result = e.expressionSemantic(sc);
+ }
+
+ override void visit(ImportExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("ImportExp::semantic('%s')\n", e.toChars());
+ }
+
+ auto se = semanticString(sc, e.e1, "file name argument");
+ if (!se)
+ return setError();
+ se = se.toUTF8(sc);
+
+ auto namez = se.toStringz().ptr;
+ if (!global.filePath)
+ {
+ e.error("need `-J` switch to import text file `%s`", namez);
+ return setError();
+ }
+
+ /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
+ * ('Path Traversal') attacks.
+ * http://cwe.mitre.org/data/definitions/22.html
+ */
+
+ if (FileName.absolute(namez))
+ {
+ e.error("absolute path is not allowed in import expression: `%s`", se.toChars());
+ return setError();
+ }
+
+ auto idxReserved = FileName.findReservedChar(namez);
+ if (idxReserved != size_t.max)
+ {
+ e.error("`%s` is not a valid filename on this platform", se.toChars());
+ e.errorSupplemental("Character `'%c'` is reserved and cannot be used", namez[idxReserved]);
+ return setError();
+ }
+
+ if (FileName.refersToParentDir(namez))
+ {
+ e.error("path refers to parent (`..`) directory: `%s`", se.toChars());
+ return setError();
+ }
+
+ auto name = FileName.searchPath(global.filePath, namez, false);
+ if (!name)
+ {
+ e.error("file `%s` cannot be found or not in a path specified with `-J`", se.toChars());
+ e.errorSupplemental("Path(s) searched (as provided by `-J`):");
+ foreach (idx, path; *global.filePath)
+ {
+ const attr = FileName.exists(path);
+ const(char)* err = attr == 2 ? "" :
+ (attr == 1 ? " (not a directory)" : " (path not found)");
+ e.errorSupplemental("[%zu]: `%s`%s", idx, path, err);
+ }
+ return setError();
+ }
+
+ sc._module.contentImportedFiles.push(name);
+ if (global.params.verbose)
+ {
+ const slice = se.peekString();
+ message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, name);
+ }
+ if (global.params.moduleDeps !is null)
+ {
+ OutBuffer* ob = global.params.moduleDeps;
+ Module imod = sc._module;
+
+ if (!global.params.moduleDepsFile)
+ ob.writestring("depsFile ");
+ ob.writestring(imod.toPrettyChars());
+ ob.writestring(" (");
+ escapePath(ob, imod.srcfile.toChars());
+ ob.writestring(") : ");
+ if (global.params.moduleDepsFile)
+ ob.writestring("string : ");
+ ob.write(se.peekString());
+ ob.writestring(" (");
+ escapePath(ob, name);
+ ob.writestring(")");
+ ob.writenl();
+ }
+ if (global.params.emitMakeDeps)
+ {
+ global.params.makeDeps.push(name);
+ }
+
+ {
+ auto readResult = File.read(name);
+ if (!readResult.success)
+ {
+ e.error("cannot read file `%s`", name);
+ return setError();
+ }
+ else
+ {
+ // take ownership of buffer (probably leaking)
+ auto data = readResult.extractSlice();
+ se = new StringExp(e.loc, data);
+ }
+ }
+ result = se.expressionSemantic(sc);
+ }
+
+ override void visit(AssertExp exp)
+ {
+ // https://dlang.org/spec/expression.html#assert_expressions
+ static if (LOGSEMANTIC)
+ {
+ printf("AssertExp::semantic('%s')\n", exp.toChars());
+ }
+
+ const generateMsg = !exp.msg && global.params.checkAction == CHECKACTION.context && global.params.useAssert == CHECKENABLE.on;
+ Expression temporariesPrefix;
+
+ if (generateMsg)
+ // no message - use assert expression as msg
+ {
+ if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages"))
+ return setError();
+
+ /*
+ {
+ auto a = e1, b = e2;
+ assert(a == b, _d_assert_fail!"=="(a, b));
+ }()
+ */
+
+ /*
+ Stores the result of an operand expression into a temporary
+ if necessary, e.g. if it is an impure fuction call containing side
+ effects as in https://issues.dlang.org/show_bug.cgi?id=20114
+
+ Params:
+ op = an expression which may require a temporary (added to
+ `temporariesPrefix`: `auto tmp = op`) and will be replaced
+ by `tmp` if necessary
+
+ Returns: (possibly replaced) `op`
+ */
+ Expression maybePromoteToTmp(ref Expression op)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=20989
+ // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
+ // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
+ {
+ auto die = op.isDotIdExp();
+ if (die && die.ident == Id.ptr)
+ die.noderef = true;
+ }
+
+ op = op.expressionSemantic(sc);
+ op = resolveProperties(sc, op);
+
+ // Detect assert's using static operator overloads (e.g. `"var" in environment`)
+ if (auto te = op.isTypeExp())
+ {
+ // Replace the TypeExp with it's textual representation
+ // Including "..." in the error message isn't quite right but
+ // proper solutions require more drastic changes, e.g. directly
+ // using miniFormat and combine instead of calling _d_assert_fail
+ auto name = new StringExp(te.loc, te.toString());
+ return name.expressionSemantic(sc);
+ }
+
+ // Create a temporary for expressions with side effects
+ // Defensively assume that function calls may have side effects even
+ // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
+ // Rewriting CallExp's also avoids some issues with the inliner/debug generation
+ if (op.hasSideEffect(true))
+ {
+ // Don't create an invalid temporary for void-expressions
+ // Further semantic will issue an appropriate error
+ if (op.type.ty == Tvoid)
+ return op;
+
+ // https://issues.dlang.org/show_bug.cgi?id=21590
+ // Don't create unnecessary temporaries and detect `assert(a = b)`
+ if (op.isAssignExp() || op.isBinAssignExp())
+ {
+ auto left = (cast(BinExp) op).e1;
+
+ // Find leftmost expression to handle other rewrites,
+ // e.g. --(++a) => a += 1 -= 1
+ while (left.isAssignExp() || left.isBinAssignExp())
+ left = (cast(BinExp) left).e1;
+
+ // Only use the assignee if it's a variable and skip
+ // other lvalues (e.g. ref's returned by functions)
+ if (left.isVarExp())
+ return left;
+
+ // Sanity check that `op` can be converted to boolean
+ // But don't raise errors for assignments enclosed in another expression
+ if (op is exp.e1)
+ op.toBoolean(sc);
+ }
+
+ // Tuples with side-effects already receive a temporary during semantic
+ if (op.type.isTypeTuple())
+ {
+ auto te = op.isTupleExp();
+ assert(te);
+
+ // Create a new tuple without the associated temporary
+ auto res = new TupleExp(op.loc, te.exps);
+ return res.expressionSemantic(sc);
+ }
+
+ const stc = op.isLvalue() ? STC.ref_ : 0;
+ auto tmp = copyToTemp(stc, "__assertOp", op);
+ tmp.dsymbolSemantic(sc);
+
+ auto decl = new DeclarationExp(op.loc, tmp);
+ temporariesPrefix = Expression.combine(temporariesPrefix, decl);
+
+ op = new VarExp(op.loc, tmp);
+ op = op.expressionSemantic(sc);
+ }
+ return op;
+ }
+
+ // if the assert condition is a mixin expression, try to compile it
+ if (auto ce = exp.e1.isMixinExp())
+ {
+ if (auto e1 = compileIt(ce))
+ exp.e1 = e1;
+ }
+
+ Expressions* es;
+ Objects* tiargs;
+ Loc loc = exp.e1.loc;
+
+ const tok = exp.e1.op;
+ bool isEqualsCallExpression;
+ if (tok == TOK.call)
+ {
+ const callExp = cast(CallExp) exp.e1;
+
+ // https://issues.dlang.org/show_bug.cgi?id=20331
+ // callExp.f may be null if the assert contains a call to
+ // a function pointer or literal
+ if (const callExpFunc = callExp.f)
+ {
+ const callExpIdent = callExpFunc.ident;
+ isEqualsCallExpression = callExpIdent == Id.__equals ||
+ callExpIdent == Id.eq;
+ }
+ }
+ if (tok == TOK.equal || tok == TOK.notEqual ||
+ tok == TOK.lessThan || tok == TOK.greaterThan ||
+ tok == TOK.lessOrEqual || tok == TOK.greaterOrEqual ||
+ tok == TOK.identity || tok == TOK.notIdentity ||
+ tok == TOK.in_ ||
+ isEqualsCallExpression)
+ {
+ es = new Expressions(3);
+ tiargs = new Objects(1);
+
+ if (isEqualsCallExpression)
+ {
+ auto callExp = cast(CallExp) exp.e1;
+ auto args = callExp.arguments;
+
+ // structs with opEquals get rewritten to a DotVarExp:
+ // a.opEquals(b)
+ // https://issues.dlang.org/show_bug.cgi?id=20100
+ if (args.length == 1)
+ {
+ auto dv = callExp.e1.isDotVarExp();
+ assert(dv);
+
+ // runtime args
+ (*es)[1] = maybePromoteToTmp(dv.e1);
+ (*es)[2] = maybePromoteToTmp((*args)[0]);
+ }
+ else
+ {
+ // runtime args
+ (*es)[1] = maybePromoteToTmp((*args)[0]);
+ (*es)[2] = maybePromoteToTmp((*args)[1]);
+ }
+ }
+ else
+ {
+ auto binExp = cast(EqualExp) exp.e1;
+
+ // runtime args
+ (*es)[1] = maybePromoteToTmp(binExp.e1);
+ (*es)[2] = maybePromoteToTmp(binExp.e2);
+ }
+
+ // template args
+ Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : Token.toString(exp.e1.op));
+ comp = comp.expressionSemantic(sc);
+ (*es)[0] = comp;
+ (*tiargs)[0] = (*es)[1].type;
+ }
+
+ // Format exp.e1 before any additional boolean conversion
+ // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
+ else if (tok != TOK.andAnd && tok != TOK.orOr)
+ {
+ es = new Expressions(2);
+ tiargs = new Objects(1);
+
+ if (auto ne = exp.e1.isNotExp())
+ {
+ // Fetch the (potential non-bool) expression and fold
+ // (n) negations into (n % 2) negations, e.g. !!a => a
+ for (bool neg = true; ; neg = !neg)
+ {
+ if (auto ne2 = ne.e1.isNotExp())
+ ne = ne2;
+ else
+ {
+ (*es)[0] = new StringExp(loc, neg ? "!" : "");
+ (*es)[1] = maybePromoteToTmp(ne.e1);
+ break;
+ }
+ }
+ }
+ else
+ { // Simply format exp.e1
+ (*es)[0] = new StringExp(loc, "");
+ (*es)[1] = maybePromoteToTmp(exp.e1);
+ }
+
+ (*tiargs)[0] = (*es)[1].type;
+
+ // Passing __ctfe to auto ref infers ref and aborts compilation:
+ // "cannot modify compiler-generated variable __ctfe"
+ auto ve = (*es)[1].isVarExp();
+ if (ve && ve.var.ident == Id.ctfe)
+ {
+ exp.msg = new StringExp(loc, "assert(__ctfe) failed!");
+ goto LSkip;
+ }
+ }
+ else
+ {
+ OutBuffer buf;
+ buf.printf("%s failed", exp.toChars());
+ exp.msg = new StringExp(Loc.initial, buf.extractSlice());
+ goto LSkip;
+ }
+
+ Expression __assertFail = new IdentifierExp(exp.loc, Id.empty);
+ auto assertFail = new DotIdExp(loc, __assertFail, Id.object);
+
+ auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs);
+ auto ec = CallExp.create(loc, dt, es);
+ exp.msg = ec;
+ }
+
+ LSkip:
+ if (Expression ex = unaSemantic(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ exp.e1 = resolveProperties(sc, exp.e1);
+ // BUG: see if we can do compile time elimination of the Assert
+ exp.e1 = exp.e1.optimize(WANTvalue);
+ exp.e1 = exp.e1.toBoolean(sc);
+
+ if (exp.e1.op == TOK.error)
+ {
+ result = exp.e1;
+ return;
+ }
+
+ if (exp.msg)
+ {
+ exp.msg = expressionSemantic(exp.msg, sc);
+ exp.msg = resolveProperties(sc, exp.msg);
+ exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
+ exp.msg = exp.msg.optimize(WANTvalue);
+ checkParamArgumentEscape(sc, null, null, exp.msg, true, false);
+ }
+
+ if (exp.msg && exp.msg.op == TOK.error)
+ {
+ result = exp.msg;
+ return;
+ }
+
+ auto f1 = checkNonAssignmentArrayOp(exp.e1);
+ auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg);
+ if (f1 || f2)
+ return setError();
+
+ if (exp.e1.isBool(false))
+ {
+ /* This is an `assert(0)` which means halt program execution
+ */
+ FuncDeclaration fd = sc.parent.isFuncDeclaration();
+ if (fd)
+ fd.hasReturnExp |= 4;
+ sc.ctorflow.orCSX(CSX.halt);
+
+ if (global.params.useAssert == CHECKENABLE.off)
+ {
+ Expression e = new HaltExp(exp.loc);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ exp.type = Type.tnoreturn;
+ }
+ else
+ exp.type = Type.tvoid;
+
+ result = !temporariesPrefix
+ ? exp
+ : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc);
+ }
+
+ override void visit(DotIdExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
+ //printf("e1.op = %d, '%s'\n", e1.op, Token::toChars(e1.op));
+ }
+ Expression e = exp.semanticY(sc, 1);
+ if (e && isDotOpDispatch(e))
+ {
+ uint errors = global.startGagging();
+ e = resolvePropertiesX(sc, e);
+ if (global.endGagging(errors))
+ e = null; /* fall down to UFCS */
+ else
+ {
+ result = e;
+ return;
+ }
+ }
+ if (!e) // if failed to find the property
+ {
+ /* If ident is not a valid property, rewrite:
+ * e1.ident
+ * as:
+ * .ident(e1)
+ */
+ e = resolveUFCSProperties(sc, exp);
+ }
+ result = e;
+ }
+
+ override void visit(DotTemplateExp e)
+ {
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+ if (Expression ex = unaSemantic(e, sc))
+ {
+ result = ex;
+ return;
+ }
+ // 'void' like TemplateExp
+ e.type = Type.tvoid;
+ result = e;
+ }
+
+ override void visit(DotVarExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("DotVarExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ exp.var = exp.var.toAlias().isDeclaration();
+
+ exp.e1 = exp.e1.expressionSemantic(sc);
+
+ if (auto tup = exp.var.isTupleDeclaration())
+ {
+ /* Replace:
+ * e1.tuple(a, b, c)
+ * with:
+ * tuple(e1.a, e1.b, e1.c)
+ */
+ Expression e0;
+ Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1;
+
+ auto exps = new Expressions();
+ exps.reserve(tup.objects.dim);
+ for (size_t i = 0; i < tup.objects.dim; i++)
+ {
+ RootObject o = (*tup.objects)[i];
+ Expression e;
+ Declaration var;
+ if (o.dyncast() == DYNCAST.expression)
+ {
+ e = cast(Expression)o;
+ if (auto se = e.isDsymbolExp())
+ var = se.s.isDeclaration();
+ else if (auto ve = e.isVarExp())
+ if (!ve.var.isFuncDeclaration())
+ // Exempt functions for backwards compatibility reasons.
+ // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
+ var = ve.var;
+ }
+ else if (o.dyncast() == DYNCAST.dsymbol)
+ {
+ Dsymbol s = cast(Dsymbol) o;
+ Declaration d = s.isDeclaration();
+ if (!d || d.isFuncDeclaration())
+ // Exempt functions for backwards compatibility reasons.
+ // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
+ e = new DsymbolExp(exp.loc, s);
+ else
+ var = d;
+ }
+ else if (o.dyncast() == DYNCAST.type)
+ {
+ e = new TypeExp(exp.loc, cast(Type)o);
+ }
+ else
+ {
+ exp.error("`%s` is not an expression", o.toChars());
+ return setError();
+ }
+ if (var)
+ e = new DotVarExp(exp.loc, ev, var);
+ exps.push(e);
+ }
+
+ Expression e = new TupleExp(exp.loc, e0, exps);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+
+ exp.e1 = exp.e1.addDtorHook(sc);
+
+ Type t1 = exp.e1.type;
+
+ if (FuncDeclaration fd = exp.var.isFuncDeclaration())
+ {
+ // for functions, do checks after overload resolution
+ if (!fd.functionSemantic())
+ return setError();
+
+ /* https://issues.dlang.org/show_bug.cgi?id=13843
+ * If fd obviously has no overloads, we should
+ * normalize AST, and it will give a chance to wrap fd with FuncExp.
+ */
+ if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration())
+ {
+ // (e1, fd)
+ auto e = symbolToExp(fd, exp.loc, sc, false);
+ result = Expression.combine(exp.e1, e);
+ return;
+ }
+
+ exp.type = fd.type;
+ assert(exp.type);
+ }
+ else if (OverDeclaration od = exp.var.isOverDeclaration())
+ {
+ exp.type = Type.tvoid; // ambiguous type?
+ }
+ else
+ {
+ exp.type = exp.var.type;
+ if (!exp.type && global.errors) // var is goofed up, just return error.
+ return setError();
+ assert(exp.type);
+
+ if (t1.ty == Tpointer)
+ t1 = t1.nextOf();
+
+ exp.type = exp.type.addMod(t1.mod);
+
+ Dsymbol vparent = exp.var.toParent();
+ AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null;
+ if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1))
+ exp.e1 = e1x;
+ else
+ {
+ /* Later checkRightThis will report correct error for invalid field variable access.
+ */
+ Expression e = new VarExp(exp.loc, exp.var);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ checkAccess(exp.loc, sc, exp.e1, exp.var);
+
+ VarDeclaration v = exp.var.isVarDeclaration();
+ if (v && (v.isDataseg() || (v.storage_class & STC.manifest)))
+ {
+ Expression e = expandVar(WANTvalue, v);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+
+ if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
+ (!v.needThis() && v.semanticRun > PASS.init))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
+ {
+ // (e1, v)
+ checkAccess(exp.loc, sc, exp.e1, v);
+ Expression e = new VarExp(exp.loc, v);
+ e = new CommaExp(exp.loc, exp.e1, e);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ }
+ //printf("-DotVarExp::semantic('%s')\n", toChars());
+ result = exp;
+ }
+
+ override void visit(DotTemplateInstanceExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
+ }
+ // Indicate we need to resolve by UFCS.
+ Expression e = exp.semanticY(sc, 1);
+ if (!e)
+ e = resolveUFCSProperties(sc, exp);
+ result = e;
+ }
+
+ override void visit(DelegateExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("DelegateExp::semantic('%s')\n", e.toChars());
+ }
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+
+ e.e1 = e.e1.expressionSemantic(sc);
+
+ e.type = new TypeDelegate(e.func.type.isTypeFunction());
+ e.type = e.type.typeSemantic(e.loc, sc);
+
+ FuncDeclaration f = e.func.toAliasFunc();
+ AggregateDeclaration ad = f.toParentLocal().isAggregateDeclaration();
+ if (f.needThis())
+ e.e1 = getRightThis(e.loc, sc, ad, e.e1, f);
+ if (e.e1.op == TOK.error)
+ return setError();
+
+ /* A delegate takes the address of e.e1 in order to set the .ptr field
+ * https://issues.dlang.org/show_bug.cgi?id=18575
+ */
+ if (global.params.useDIP1000 == FeatureState.enabled && e.e1.type.toBasetype().ty == Tstruct)
+ {
+ if (auto v = expToVariable(e.e1))
+ {
+ if (!checkAddressVar(sc, e.e1, v))
+ return setError();
+ }
+ }
+
+ if (f.type.ty == Tfunction)
+ {
+ TypeFunction tf = cast(TypeFunction)f.type;
+ if (!MODmethodConv(e.e1.type.mod, f.type.mod))
+ {
+ OutBuffer thisBuf, funcBuf;
+ MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod);
+ MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod);
+ e.error("%smethod `%s` is not callable using a %s`%s`",
+ funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars());
+ return setError();
+ }
+ }
+ if (ad && ad.isClassDeclaration() && ad.type != e.e1.type)
+ {
+ // A downcast is required for interfaces
+ // https://issues.dlang.org/show_bug.cgi?id=3706
+ e.e1 = new CastExp(e.loc, e.e1, ad.type);
+ e.e1 = e.e1.expressionSemantic(sc);
+ }
+ result = e;
+ // declare dual-context container
+ if (f.isThis2 && !sc.intypeof && sc.func)
+ {
+ // check access to second `this`
+ if (AggregateDeclaration ad2 = f.isMember2())
+ {
+ Expression te = new ThisExp(e.loc).expressionSemantic(sc);
+ if (te.op != TOK.error)
+ te = getRightThis(e.loc, sc, ad2, te, f);
+ if (te.op == TOK.error)
+ {
+ e.error("need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars());
+ return setError();
+ }
+ }
+ VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f);
+ e.vthis2 = vthis2;
+ Expression de = new DeclarationExp(e.loc, vthis2);
+ result = Expression.combine(de, result);
+ result = result.expressionSemantic(sc);
+ }
+ }
+
+ override void visit(DotTypeExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("DotTypeExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (auto e = unaSemantic(exp, sc))
+ {
+ result = e;
+ return;
+ }
+
+ exp.type = exp.sym.getType().addMod(exp.e1.type.mod);
+ result = exp;
+ }
+
+ override void visit(AddrExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("AddrExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = unaSemantic(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ if (sc.flags & SCOPE.Cfile)
+ {
+ /* Special handling for &"string"
+ * since C regards a string literal as an lvalue
+ */
+ if (auto se = exp.e1.isStringExp())
+ {
+ if (auto tp = se.type.toBasetype().isTypePointer())
+ {
+ /* Switch from pointer-to-char to pointer-to-static-array-of-char
+ */
+ auto ts = new TypeSArray(tp.nextOf(), new IntegerExp(Loc.initial, se.len + 1, Type.tsize_t));
+ se.type = typeSemantic(ts, Loc.initial, sc).pointerTo();
+ result = se;
+ return;
+ }
+ }
+ }
+
+ int wasCond = exp.e1.op == TOK.question;
+
+ if (exp.e1.op == TOK.dotTemplateInstance)
+ {
+ DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1;
+ TemplateInstance ti = dti.ti;
+ {
+ //assert(ti.needsTypeInference(sc));
+ ti.dsymbolSemantic(sc);
+ if (!ti.inst || ti.errors) // if template failed to expand
+ return setError();
+
+ Dsymbol s = ti.toAlias();
+ FuncDeclaration f = s.isFuncDeclaration();
+ if (f)
+ {
+ exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f);
+ exp.e1 = exp.e1.expressionSemantic(sc);
+ }
+ }
+ }
+ else if (exp.e1.op == TOK.scope_)
+ {
+ TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance();
+ if (ti)
+ {
+ //assert(ti.needsTypeInference(sc));
+ ti.dsymbolSemantic(sc);
+ if (!ti.inst || ti.errors) // if template failed to expand
+ return setError();
+
+ Dsymbol s = ti.toAlias();
+ FuncDeclaration f = s.isFuncDeclaration();
+ if (f)
+ {
+ exp.e1 = new VarExp(exp.e1.loc, f);
+ exp.e1 = exp.e1.expressionSemantic(sc);
+ }
+ }
+ }
+ /* https://issues.dlang.org/show_bug.cgi?id=809
+ *
+ * If the address of a lazy variable is taken,
+ * the expression is rewritten so that the type
+ * of it is the delegate type. This means that
+ * the symbol is not going to represent a call
+ * to the delegate anymore, but rather, the
+ * actual symbol.
+ */
+ if (auto ve = exp.e1.isVarExp())
+ {
+ if (ve.var.storage_class & STC.lazy_)
+ {
+ exp.e1 = exp.e1.expressionSemantic(sc);
+ exp.e1 = resolveProperties(sc, exp.e1);
+ if (auto callExp = exp.e1.isCallExp())
+ {
+ if (callExp.e1.type.toBasetype().ty == Tdelegate)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=20551
+ *
+ * Cannot take address of lazy parameter in @safe code
+ * because it might end up being a pointer to undefined
+ * memory.
+ */
+ if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
+ {
+ exp.error("cannot take address of lazy parameter `%s` in `@safe` function `%s`",
+ ve.toChars(), sc.func.toChars());
+ setError();
+ }
+ else
+ {
+ VarExp ve2 = callExp.e1.isVarExp();
+ ve2.delegateWasExtracted = true;
+ ve2.var.storage_class |= STC.scope_;
+ result = ve2;
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ exp.e1 = exp.e1.toLvalue(sc, null);
+ if (exp.e1.op == TOK.error)
+ {
+ result = exp.e1;
+ return;
+ }
+ if (checkNonAssignmentArrayOp(exp.e1))
+ return setError();
+
+ if (!exp.e1.type)
+ {
+ exp.error("cannot take address of `%s`", exp.e1.toChars());
+ return setError();
+ }
+
+ bool hasOverloads;
+ if (auto f = isFuncAddress(exp, &hasOverloads))
+ {
+ if (!hasOverloads && f.checkForwardRef(exp.loc))
+ return setError();
+ }
+ else if (!exp.e1.type.deco)
+ {
+ if (exp.e1.op == TOK.variable)
+ {
+ VarExp ve = cast(VarExp)exp.e1;
+ Declaration d = ve.var;
+ exp.error("forward reference to %s `%s`", d.kind(), d.toChars());
+ }
+ else
+ exp.error("forward reference to `%s`", exp.e1.toChars());
+ return setError();
+ }
+
+ exp.type = exp.e1.type.pointerTo();
+
+ // See if this should really be a delegate
+ if (exp.e1.op == TOK.dotVariable)
+ {
+ DotVarExp dve = cast(DotVarExp)exp.e1;
+ FuncDeclaration f = dve.var.isFuncDeclaration();
+ if (f)
+ {
+ f = f.toAliasFunc(); // FIXME, should see overloads
+ // https://issues.dlang.org/show_bug.cgi?id=1983
+ if (!dve.hasOverloads)
+ f.tookAddressOf++;
+
+ Expression e;
+ if (f.needThis())
+ e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads);
+ else // It is a function pointer. Convert &v.f() --> (v, &V.f())
+ e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads)));
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+
+ // Look for misaligned pointer in @safe mode
+ if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true))
+ return setError();
+
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ {
+ if (VarDeclaration v = expToVariable(dve.e1))
+ {
+ if (!checkAddressVar(sc, exp.e1, v))
+ return setError();
+ }
+ }
+ }
+ else if (exp.e1.op == TOK.variable)
+ {
+ VarExp ve = cast(VarExp)exp.e1;
+ VarDeclaration v = ve.var.isVarDeclaration();
+ if (v)
+ {
+ if (!checkAddressVar(sc, exp.e1, v))
+ return setError();
+
+ ve.checkPurity(sc, v);
+ }
+ FuncDeclaration f = ve.var.isFuncDeclaration();
+ if (f)
+ {
+ /* Because nested functions cannot be overloaded,
+ * mark here that we took its address because castTo()
+ * may not be called with an exact match.
+ */
+ if (!ve.hasOverloads || (f.isNested() && !f.needThis()))
+ f.tookAddressOf++;
+ if (f.isNested() && !f.needThis())
+ {
+ if (f.isFuncLiteralDeclaration())
+ {
+ if (!f.FuncDeclaration.isNested())
+ {
+ /* Supply a 'null' for a this pointer if no this is available
+ */
+ Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ }
+ Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ if (f.needThis())
+ {
+ if (hasThis(sc))
+ {
+ /* Should probably supply 'this' after overload resolution,
+ * not before.
+ */
+ Expression ethis = new ThisExp(exp.loc);
+ Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ if (sc.func && !sc.intypeof)
+ {
+ if (!(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
+ {
+ exp.error("`this` reference necessary to take address of member `%s` in `@safe` function `%s`", f.toChars(), sc.func.toChars());
+ }
+ }
+ }
+ }
+ }
+ else if ((exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) && global.params.useDIP1000 == FeatureState.enabled)
+ {
+ if (VarDeclaration v = expToVariable(exp.e1))
+ {
+ if (!checkAddressVar(sc, exp.e1, v))
+ return setError();
+ }
+ }
+ else if (exp.e1.op == TOK.call)
+ {
+ CallExp ce = cast(CallExp)exp.e1;
+ if (ce.e1.type.ty == Tfunction)
+ {
+ TypeFunction tf = cast(TypeFunction)ce.e1.type;
+ if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
+ {
+ exp.error("cannot take address of `ref return` of `%s()` in `@safe` function `%s`",
+ ce.e1.toChars(), sc.func.toChars());
+ }
+ }
+ }
+ else if (exp.e1.op == TOK.index)
+ {
+ /* For:
+ * int[3] a;
+ * &a[i]
+ * check 'a' the same as for a regular variable
+ */
+ if (VarDeclaration v = expToVariable(exp.e1))
+ {
+ if (global.params.useDIP1000 == FeatureState.enabled && !checkAddressVar(sc, exp.e1, v))
+ return setError();
+
+ exp.e1.checkPurity(sc, v);
+ }
+ }
+ else if (wasCond)
+ {
+ /* a ? b : c was transformed to *(a ? &b : &c), but we still
+ * need to do safety checks
+ */
+ assert(exp.e1.op == TOK.star);
+ PtrExp pe = cast(PtrExp)exp.e1;
+ assert(pe.e1.op == TOK.question);
+ CondExp ce = cast(CondExp)pe.e1;
+ assert(ce.e1.op == TOK.address);
+ assert(ce.e2.op == TOK.address);
+
+ // Re-run semantic on the address expressions only
+ ce.e1.type = null;
+ ce.e1 = ce.e1.expressionSemantic(sc);
+ ce.e2.type = null;
+ ce.e2 = ce.e2.expressionSemantic(sc);
+ }
+ result = exp.optimize(WANTvalue);
+ }
+
+ override void visit(PtrExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("PtrExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ Type tb = exp.e1.type.toBasetype();
+ switch (tb.ty)
+ {
+ case Tpointer:
+ exp.type = (cast(TypePointer)tb).next;
+ break;
+
+ case Tsarray:
+ case Tarray:
+ if (isNonAssignmentArrayOp(exp.e1))
+ goto default;
+ exp.error("using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars());
+ exp.type = (cast(TypeArray)tb).next;
+ exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo());
+ break;
+
+ case Terror:
+ return setError();
+
+ case Tnull:
+ exp.type = Type.tnoreturn; // typeof(*null) is bottom type
+ break;
+
+ default:
+ exp.error("can only `*` a pointer, not a `%s`", exp.e1.type.toChars());
+ goto case Terror;
+ }
+
+ if (exp.checkValue())
+ return setError();
+
+ result = exp;
+ }
+
+ override void visit(NegExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("NegExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ fix16997(sc, exp);
+ exp.type = exp.e1.type;
+ Type tb = exp.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp.e1))
+ {
+ result = arrayOpInvalidError(exp);
+ return;
+ }
+ result = exp;
+ return;
+ }
+ if (!target.isVectorOpSupported(tb, exp.op))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ if (exp.e1.checkNoBool())
+ return setError();
+ if (exp.e1.checkArithmetic() ||
+ exp.e1.checkSharedAccess(sc))
+ return setError();
+
+ result = exp;
+ }
+
+ override void visit(UAddExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("UAddExp::semantic('%s')\n", exp.toChars());
+ }
+ assert(!exp.type);
+
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ fix16997(sc, exp);
+ if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ if (exp.e1.checkNoBool())
+ return setError();
+ if (exp.e1.checkArithmetic())
+ return setError();
+ if (exp.e1.checkSharedAccess(sc))
+ return setError();
+
+ result = exp.e1;
+ }
+
+ override void visit(ComExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ fix16997(sc, exp);
+ exp.type = exp.e1.type;
+ Type tb = exp.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp.e1))
+ {
+ result = arrayOpInvalidError(exp);
+ return;
+ }
+ result = exp;
+ return;
+ }
+ if (!target.isVectorOpSupported(tb, exp.op))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ if (exp.e1.checkNoBool())
+ return setError();
+ if (exp.e1.checkIntegral() ||
+ exp.e1.checkSharedAccess(sc))
+ return setError();
+
+ result = exp;
+ }
+
+ override void visit(NotExp e)
+ {
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+
+ e.setNoderefOperand();
+
+ // Note there is no operator overload
+ if (Expression ex = unaSemantic(e, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (e.e1.op == TOK.type)
+ e.e1 = resolveAliasThis(sc, e.e1);
+
+ e.e1 = resolveProperties(sc, e.e1);
+ e.e1 = e.e1.toBoolean(sc);
+ if (e.e1.type == Type.terror)
+ {
+ result = e.e1;
+ return;
+ }
+
+ if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op))
+ {
+ result = e.incompatibleTypes();
+ }
+ // https://issues.dlang.org/show_bug.cgi?id=13910
+ // Today NotExp can take an array as its operand.
+ if (checkNonAssignmentArrayOp(e.e1))
+ return setError();
+
+ e.type = Type.tbool;
+ result = e;
+ }
+
+ override void visit(DeleteExp exp)
+ {
+ if (!sc.isDeprecated)
+ {
+ // @@@DEPRECATED_2019-02@@@
+ // 1. Deprecation for 1 year
+ // 2. Error for 1 year
+ // 3. Removal of keyword, "delete" can be used for other identities
+ if (!exp.isRAII)
+ deprecation(exp.loc, "The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.");
+ }
+
+ if (Expression ex = unaSemantic(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ exp.e1 = resolveProperties(sc, exp.e1);
+ exp.e1 = exp.e1.modifiableLvalue(sc, null);
+ if (exp.e1.op == TOK.error)
+ {
+ result = exp.e1;
+ return;
+ }
+ exp.type = Type.tvoid;
+
+ AggregateDeclaration ad = null;
+ Type tb = exp.e1.type.toBasetype();
+ switch (tb.ty)
+ {
+ case Tclass:
+ {
+ auto cd = (cast(TypeClass)tb).sym;
+ if (cd.isCOMinterface())
+ {
+ /* Because COM classes are deleted by IUnknown.Release()
+ */
+ exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars());
+ return setError();
+ }
+ ad = cd;
+ break;
+ }
+ case Tpointer:
+ tb = (cast(TypePointer)tb).next.toBasetype();
+ if (tb.ty == Tstruct)
+ {
+ ad = (cast(TypeStruct)tb).sym;
+ semanticTypeInfo(sc, tb);
+ }
+ break;
+
+ case Tarray:
+ {
+ Type tv = tb.nextOf().baseElemOf();
+ if (tv.ty == Tstruct)
+ {
+ ad = (cast(TypeStruct)tv).sym;
+ if (ad.dtor)
+ semanticTypeInfo(sc, ad.type);
+ }
+ break;
+ }
+ default:
+ exp.error("cannot delete type `%s`", exp.e1.type.toChars());
+ return setError();
+ }
+
+ bool err = false;
+ if (ad)
+ {
+ if (ad.dtor)
+ {
+ err |= !ad.dtor.functionSemantic();
+ err |= exp.checkPurity(sc, ad.dtor);
+ err |= exp.checkSafety(sc, ad.dtor);
+ err |= exp.checkNogc(sc, ad.dtor);
+ }
+ if (err)
+ return setError();
+ }
+
+ if (!sc.intypeof && sc.func &&
+ !exp.isRAII &&
+ !(sc.flags & SCOPE.debug_) &&
+ sc.func.setUnsafe())
+ {
+ exp.error("`%s` is not `@safe` but is used in `@safe` function `%s`", exp.toChars(), sc.func.toChars());
+ err = true;
+ }
+ if (err)
+ return setError();
+
+ result = exp;
+ }
+
+ override void visit(CastExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("CastExp::semantic('%s')\n", exp.toChars());
+ }
+ //static int x; assert(++x < 10);
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if ((sc && sc.flags & SCOPE.Cfile) &&
+ exp.to && exp.to.ty == Tident &&
+ (exp.e1.op == TOK.address || exp.e1.op == TOK.star ||
+ exp.e1.op == TOK.uadd || exp.e1.op == TOK.negate))
+ {
+ /* Ambiguous cases arise from CParser if type-name is just an identifier.
+ * ( identifier ) cast-expression
+ * If we determine that `identifier` is a variable, and cast-expression
+ * is one of the unary operators (& * + -), then rewrite this cast
+ * as a binary expression.
+ */
+ Loc loc = exp.loc;
+ Type t;
+ Expression e;
+ Dsymbol s;
+ exp.to.resolve(loc, sc, e, t, s);
+ if (e !is null)
+ {
+ if (auto ex = exp.e1.isAddrExp()) // (ident) &exp -> (ident & exp)
+ result = new AndExp(loc, e, ex.e1);
+ else if (auto ex = exp.e1.isPtrExp()) // (ident) *exp -> (ident * exp)
+ result = new MulExp(loc, e, ex.e1);
+ else if (auto ex = exp.e1.isUAddExp()) // (ident) +exp -> (ident + exp)
+ result = new AddExp(loc, e, ex.e1);
+ else if (auto ex = exp.e1.isNegExp()) // (ident) -exp -> (ident - exp)
+ result = new MinExp(loc, e, ex.e1);
+
+ assert(result);
+ result = result.expressionSemantic(sc);
+ return;
+ }
+ }
+
+ if (exp.to)
+ {
+ exp.to = exp.to.typeSemantic(exp.loc, sc);
+ if (exp.to == Type.terror)
+ return setError();
+
+ if (!exp.to.hasPointers())
+ exp.setNoderefOperand();
+
+ // When e1 is a template lambda, this cast may instantiate it with
+ // the type 'to'.
+ exp.e1 = inferType(exp.e1, exp.to);
+ }
+
+ if (auto e = unaSemantic(exp, sc))
+ {
+ result = e;
+ return;
+ }
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (exp.e1.op == TOK.type)
+ exp.e1 = resolveAliasThis(sc, exp.e1);
+
+ auto e1x = resolveProperties(sc, exp.e1);
+ if (e1x.op == TOK.error)
+ {
+ result = e1x;
+ return;
+ }
+ if (e1x.checkType())
+ return setError();
+ exp.e1 = e1x;
+
+ if (!exp.e1.type)
+ {
+ exp.error("cannot cast `%s`", exp.e1.toChars());
+ return setError();
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=19954
+ if (exp.e1.type.ty == Ttuple)
+ {
+ TupleExp te = exp.e1.isTupleExp();
+ if (te.exps.dim == 1)
+ exp.e1 = (*te.exps)[0];
+ }
+
+ // only allow S(x) rewrite if cast specified S explicitly.
+ // See https://issues.dlang.org/show_bug.cgi?id=18545
+ const bool allowImplicitConstruction = exp.to !is null;
+
+ if (!exp.to) // Handle cast(const) and cast(immutable), etc.
+ {
+ exp.to = exp.e1.type.castMod(exp.mod);
+ exp.to = exp.to.typeSemantic(exp.loc, sc);
+
+ if (exp.to == Type.terror)
+ return setError();
+ }
+
+ if (exp.to.ty == Ttuple)
+ {
+ exp.error("cannot cast `%s` to tuple type `%s`", exp.e1.toChars(), exp.to.toChars());
+ return setError();
+ }
+
+ // cast(void) is used to mark e1 as unused, so it is safe
+ if (exp.to.ty == Tvoid)
+ {
+ exp.type = exp.to;
+ result = exp;
+ return;
+ }
+
+ if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0)
+ {
+ if (Expression e = exp.op_overload(sc))
+ {
+ result = e.implicitCastTo(sc, exp.to);
+ return;
+ }
+ }
+
+ Type t1b = exp.e1.type.toBasetype();
+ Type tob = exp.to.toBasetype();
+
+ if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b))
+ {
+ /* Look to replace:
+ * cast(S)t
+ * with:
+ * S(t)
+ */
+
+ // Rewrite as to.call(e1)
+ Expression e = new TypeExp(exp.loc, exp.to);
+ e = new CallExp(exp.loc, e, exp.e1);
+ e = e.trySemantic(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+
+ if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray))
+ {
+ if (checkNonAssignmentArrayOp(exp.e1))
+ return setError();
+ }
+
+ // Look for casting to a vector type
+ if (tob.ty == Tvector && t1b.ty != Tvector)
+ {
+ result = new VectorExp(exp.loc, exp.e1, exp.to);
+ result = result.expressionSemantic(sc);
+ return;
+ }
+
+ Expression ex = exp.e1.castTo(sc, exp.to);
+ if (ex.op == TOK.error)
+ {
+ result = ex;
+ return;
+ }
+
+ // Check for unsafe casts
+ if (!sc.intypeof &&
+ !(sc.flags & SCOPE.debug_) &&
+ !isSafeCast(ex, t1b, tob) &&
+ (!sc.func && sc.stc & STC.safe || sc.func && sc.func.setUnsafe()))
+ {
+ exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars());
+ return setError();
+ }
+
+ // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
+ // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
+ // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
+ // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
+ if (tob.ty == Tarray)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=19840
+ if (auto ad = isAggregate(t1b))
+ {
+ if (ad.aliasthis)
+ {
+ Expression e = resolveAliasThis(sc, exp.e1);
+ e = new CastExp(exp.loc, e, exp.to);
+ result = e.expressionSemantic(sc);
+ return;
+ }
+ }
+
+ if(t1b.ty == Tarray && exp.e1.op != TOK.arrayLiteral && (sc.flags & SCOPE.ctfe) == 0)
+ {
+ auto tFrom = t1b.nextOf();
+ auto tTo = tob.nextOf();
+
+ // https://issues.dlang.org/show_bug.cgi?id=20130
+ if (exp.e1.op != TOK.string_ || !ex.isStringExp)
+ {
+ const uint fromSize = cast(uint)tFrom.size();
+ const uint toSize = cast(uint)tTo.size();
+
+ // If array element sizes do not match, we must adjust the dimensions
+ if (fromSize != toSize)
+ {
+ if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs"))
+ return setError();
+
+ // A runtime check is needed in case arrays don't line up. That check should
+ // be done in the implementation of `object.__ArrayCast`
+ if (toSize == 0 || (fromSize % toSize) != 0)
+ {
+ // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
+
+ // fully qualify as `object.__ArrayCast`
+ Expression id = new IdentifierExp(exp.loc, Id.empty);
+ auto dotid = new DotIdExp(exp.loc, id, Id.object);
+
+ auto tiargs = new Objects();
+ tiargs.push(tFrom);
+ tiargs.push(tTo);
+ auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs);
+
+ auto arguments = new Expressions();
+ arguments.push(exp.e1);
+ Expression ce = new CallExp(exp.loc, dt, arguments);
+
+ result = expressionSemantic(ce, sc);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ if (sc && sc.flags & SCOPE.Cfile)
+ {
+ /* C11 6.5.4-5: A cast does not yield an lvalue.
+ * So ensure that castTo does not strip away the cast so that this
+ * can be enforced in other semantic visitor methods.
+ */
+ if (!ex.isCastExp())
+ {
+ ex = new CastExp(exp.loc, ex, exp.to);
+ ex.type = exp.to;
+ }
+ }
+ result = ex;
+ }
+
+ override void visit(VectorExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("VectorExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ exp.e1 = exp.e1.expressionSemantic(sc);
+ exp.type = exp.to.typeSemantic(exp.loc, sc);
+ if (exp.e1.op == TOK.error || exp.type.ty == Terror)
+ {
+ result = exp.e1;
+ return;
+ }
+
+ Type tb = exp.type.toBasetype();
+ assert(tb.ty == Tvector);
+ TypeVector tv = cast(TypeVector)tb;
+ Type te = tv.elementType();
+ exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc));
+
+ bool checkElem(Expression elem)
+ {
+ if (elem.isConst() == 1)
+ return false;
+
+ exp.error("constant expression expected, not `%s`", elem.toChars());
+ return true;
+ }
+
+ exp.e1 = exp.e1.optimize(WANTvalue);
+ bool res;
+ if (exp.e1.op == TOK.arrayLiteral)
+ {
+ foreach (i; 0 .. exp.dim)
+ {
+ // Do not stop on first error - check all AST nodes even if error found
+ res |= checkElem(exp.e1.isArrayLiteralExp()[i]);
+ }
+ }
+ else if (exp.e1.type.ty == Tvoid)
+ checkElem(exp.e1);
+
+ result = res ? ErrorExp.get() : exp;
+ }
+
+ override void visit(VectorArrayExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("VectorArrayExp::semantic('%s')\n", e.toChars());
+ }
+ if (!e.type)
+ {
+ unaSemantic(e, sc);
+ e.e1 = resolveProperties(sc, e.e1);
+
+ if (e.e1.op == TOK.error)
+ {
+ result = e.e1;
+ return;
+ }
+ assert(e.e1.type.ty == Tvector);
+ e.type = e.e1.type.isTypeVector().basetype;
+ }
+ result = e;
+ }
+
+ override void visit(SliceExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("SliceExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ // operator overloading should be handled in ArrayExp already.
+ if (Expression ex = unaSemantic(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ exp.e1 = resolveProperties(sc, exp.e1);
+ if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple)
+ {
+ if (exp.lwr || exp.upr)
+ {
+ exp.error("cannot slice type `%s`", exp.e1.toChars());
+ return setError();
+ }
+ Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf());
+ result = e.expressionSemantic(sc);
+ return;
+ }
+ if (!exp.lwr && !exp.upr)
+ {
+ if (exp.e1.op == TOK.arrayLiteral)
+ {
+ // Convert [a,b,c][] to [a,b,c]
+ Type t1b = exp.e1.type.toBasetype();
+ Expression e = exp.e1;
+ if (t1b.ty == Tsarray)
+ {
+ e = e.copy();
+ e.type = t1b.nextOf().arrayOf();
+ }
+ result = e;
+ return;
+ }
+ if (exp.e1.op == TOK.slice)
+ {
+ // Convert e[][] to e[]
+ SliceExp se = cast(SliceExp)exp.e1;
+ if (!se.lwr && !se.upr)
+ {
+ result = se;
+ return;
+ }
+ }
+ if (isArrayOpOperand(exp.e1))
+ {
+ // Convert (a[]+b[])[] to a[]+b[]
+ result = exp.e1;
+ return;
+ }
+ }
+ if (exp.e1.op == TOK.error)
+ {
+ result = exp.e1;
+ return;
+ }
+ if (exp.e1.type.ty == Terror)
+ return setError();
+
+ Type t1b = exp.e1.type.toBasetype();
+ if (t1b.ty == Tpointer)
+ {
+ if (t1b.isPtrToFunction())
+ {
+ exp.error("cannot slice function pointer `%s`", exp.e1.toChars());
+ return setError();
+ }
+ if (!exp.lwr || !exp.upr)
+ {
+ exp.error("need upper and lower bound to slice pointer");
+ return setError();
+ }
+ if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
+ {
+ exp.error("pointer slicing not allowed in safe functions");
+ return setError();
+ }
+ }
+ else if (t1b.ty == Tarray)
+ {
+ }
+ else if (t1b.ty == Tsarray)
+ {
+ if (!exp.arrayop && global.params.useDIP1000 == FeatureState.enabled)
+ {
+ /* Slicing a static array is like taking the address of it.
+ * Perform checks as if e[] was &e
+ */
+ if (VarDeclaration v = expToVariable(exp.e1))
+ {
+ if (exp.e1.op == TOK.dotVariable)
+ {
+ DotVarExp dve = cast(DotVarExp)exp.e1;
+ if ((dve.e1.op == TOK.this_ || dve.e1.op == TOK.super_) &&
+ !(v.storage_class & STC.ref_))
+ {
+ // because it's a class
+ v = null;
+ }
+ }
+
+ if (v && !checkAddressVar(sc, exp.e1, v))
+ return setError();
+ }
+ }
+ }
+ else if (t1b.ty == Ttuple)
+ {
+ if (!exp.lwr && !exp.upr)
+ {
+ result = exp.e1;
+ return;
+ }
+ if (!exp.lwr || !exp.upr)
+ {
+ exp.error("need upper and lower bound to slice tuple");
+ return setError();
+ }
+ }
+ else if (t1b.ty == Tvector)
+ {
+ // Convert e1 to corresponding static array
+ TypeVector tv1 = cast(TypeVector)t1b;
+ t1b = tv1.basetype;
+ t1b = t1b.castMod(tv1.mod);
+ exp.e1.type = t1b;
+ }
+ else
+ {
+ exp.error("`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars());
+ return setError();
+ }
+
+ /* Run semantic on lwr and upr.
+ */
+ Scope* scx = sc;
+ if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
+ {
+ // Create scope for 'length' variable
+ ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
+ sym.parent = sc.scopesym;
+ sc = sc.push(sym);
+ }
+ if (exp.lwr)
+ {
+ if (t1b.ty == Ttuple)
+ sc = sc.startCTFE();
+ exp.lwr = exp.lwr.expressionSemantic(sc);
+ exp.lwr = resolveProperties(sc, exp.lwr);
+ if (t1b.ty == Ttuple)
+ sc = sc.endCTFE();
+ exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t);
+ }
+ if (exp.upr)
+ {
+ if (t1b.ty == Ttuple)
+ sc = sc.startCTFE();
+ exp.upr = exp.upr.expressionSemantic(sc);
+ exp.upr = resolveProperties(sc, exp.upr);
+ if (t1b.ty == Ttuple)
+ sc = sc.endCTFE();
+ exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t);
+ }
+ if (sc != scx)
+ sc = sc.pop();
+ if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror)
+ return setError();
+
+ if (t1b.ty == Ttuple)
+ {
+ exp.lwr = exp.lwr.ctfeInterpret();
+ exp.upr = exp.upr.ctfeInterpret();
+ uinteger_t i1 = exp.lwr.toUInteger();
+ uinteger_t i2 = exp.upr.toUInteger();
+
+ TupleExp te;
+ TypeTuple tup;
+ size_t length;
+ if (exp.e1.op == TOK.tuple) // slicing an expression tuple
+ {
+ te = cast(TupleExp)exp.e1;
+ tup = null;
+ length = te.exps.dim;
+ }
+ else if (exp.e1.op == TOK.type) // slicing a type tuple
+ {
+ te = null;
+ tup = cast(TypeTuple)t1b;
+ length = Parameter.dim(tup.arguments);
+ }
+ else
+ assert(0);
+
+ if (i2 < i1 || length < i2)
+ {
+ exp.error("string slice `[%llu .. %llu]` is out of bounds", i1, i2);
+ return setError();
+ }
+
+ size_t j1 = cast(size_t)i1;
+ size_t j2 = cast(size_t)i2;
+ Expression e;
+ if (exp.e1.op == TOK.tuple)
+ {
+ auto exps = new Expressions(j2 - j1);
+ for (size_t i = 0; i < j2 - j1; i++)
+ {
+ (*exps)[i] = (*te.exps)[j1 + i];
+ }
+ e = new TupleExp(exp.loc, te.e0, exps);
+ }
+ else
+ {
+ auto args = new Parameters();
+ args.reserve(j2 - j1);
+ for (size_t i = j1; i < j2; i++)
+ {
+ Parameter arg = Parameter.getNth(tup.arguments, i);
+ args.push(arg);
+ }
+ e = new TypeExp(exp.e1.loc, new TypeTuple(args));
+ }
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+
+ exp.type = t1b.nextOf().arrayOf();
+ // Allow typedef[] -> typedef[]
+ if (exp.type.equals(t1b))
+ exp.type = exp.e1.type;
+
+ // We might know $ now
+ setLengthVarIfKnown(exp.lengthVar, t1b);
+
+ if (exp.lwr && exp.upr)
+ {
+ exp.lwr = exp.lwr.optimize(WANTvalue);
+ exp.upr = exp.upr.optimize(WANTvalue);
+
+ IntRange lwrRange = getIntRange(exp.lwr);
+ IntRange uprRange = getIntRange(exp.upr);
+
+ if (t1b.ty == Tsarray || t1b.ty == Tarray)
+ {
+ Expression el = new ArrayLengthExp(exp.loc, exp.e1);
+ el = el.expressionSemantic(sc);
+ el = el.optimize(WANTvalue);
+ if (el.op == TOK.int64)
+ {
+ // Array length is known at compile-time. Upper is in bounds if it fits length.
+ dinteger_t length = el.toInteger();
+ auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
+ exp.upperIsInBounds = bounds.contains(uprRange);
+ }
+ else if (exp.upr.op == TOK.int64 && exp.upr.toInteger() == 0)
+ {
+ // Upper slice expression is '0'. Value is always in bounds.
+ exp.upperIsInBounds = true;
+ }
+ else if (exp.upr.op == TOK.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
+ {
+ // Upper slice expression is '$'. Value is always in bounds.
+ exp.upperIsInBounds = true;
+ }
+ }
+ else if (t1b.ty == Tpointer)
+ {
+ exp.upperIsInBounds = true;
+ }
+ else
+ assert(0);
+
+ exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
+
+ //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
+ }
+
+ result = exp;
+ }
+
+ override void visit(ArrayLengthExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
+ }
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+
+ if (Expression ex = unaSemantic(e, sc))
+ {
+ result = ex;
+ return;
+ }
+ e.e1 = resolveProperties(sc, e.e1);
+
+ e.type = Type.tsize_t;
+ result = e;
+ }
+
+ override void visit(ArrayExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("ArrayExp::semantic('%s')\n", exp.toChars());
+ }
+ assert(!exp.type);
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (isAggregate(exp.e1.type))
+ exp.error("no `[]` operator overload for type `%s`", exp.e1.type.toChars());
+ else if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple)
+ exp.error("static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
+ else if (isIndexableNonAggregate(exp.e1.type))
+ exp.error("only one index allowed to index `%s`", exp.e1.type.toChars());
+ else
+ exp.error("cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars());
+
+ result = ErrorExp.get();
+ }
+
+ override void visit(DotExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("DotExp::semantic('%s')\n", exp.toChars());
+ if (exp.type)
+ printf("\ttype = %s\n", exp.type.toChars());
+ }
+ exp.e1 = exp.e1.expressionSemantic(sc);
+ exp.e2 = exp.e2.expressionSemantic(sc);
+
+ if (exp.e1.op == TOK.type)
+ {
+ result = exp.e2;
+ return;
+ }
+ if (exp.e2.op == TOK.type)
+ {
+ result = exp.e2;
+ return;
+ }
+ if (exp.e2.op == TOK.template_)
+ {
+ auto td = (cast(TemplateExp)exp.e2).td;
+ Expression e = new DotTemplateExp(exp.loc, exp.e1, td);
+ result = e.expressionSemantic(sc);
+ return;
+ }
+ if (!exp.type)
+ exp.type = exp.e2.type;
+ result = exp;
+ }
+
+ override void visit(CommaExp e)
+ {
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+
+ // Allow `((a,b),(x,y))`
+ if (e.allowCommaExp)
+ {
+ CommaExp.allow(e.e1);
+ CommaExp.allow(e.e2);
+ }
+
+ if (Expression ex = binSemanticProp(e, sc))
+ {
+ result = ex;
+ return;
+ }
+ e.e1 = e.e1.addDtorHook(sc);
+
+ if (checkNonAssignmentArrayOp(e.e1))
+ return setError();
+
+ e.type = e.e2.type;
+ if (e.type is Type.tvoid)
+ discardValue(e.e1);
+ else if (!e.allowCommaExp && !e.isGenerated)
+ e.error("Using the result of a comma expression is not allowed");
+ result = e;
+ }
+
+ override void visit(IntervalExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("IntervalExp::semantic('%s')\n", e.toChars());
+ }
+ if (e.type)
+ {
+ result = e;
+ return;
+ }
+
+ Expression le = e.lwr;
+ le = le.expressionSemantic(sc);
+ le = resolveProperties(sc, le);
+
+ Expression ue = e.upr;
+ ue = ue.expressionSemantic(sc);
+ ue = resolveProperties(sc, ue);
+
+ if (le.op == TOK.error)
+ {
+ result = le;
+ return;
+ }
+ if (ue.op == TOK.error)
+ {
+ result = ue;
+ return;
+ }
+
+ e.lwr = le;
+ e.upr = ue;
+
+ e.type = Type.tvoid;
+ result = e;
+ }
+
+ override void visit(DelegatePtrExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("DelegatePtrExp::semantic('%s')\n", e.toChars());
+ }
+ if (!e.type)
+ {
+ unaSemantic(e, sc);
+ e.e1 = resolveProperties(sc, e.e1);
+
+ if (e.e1.op == TOK.error)
+ {
+ result = e.e1;
+ return;
+ }
+ e.type = Type.tvoidptr;
+ }
+ result = e;
+ }
+
+ override void visit(DelegateFuncptrExp e)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars());
+ }
+ if (!e.type)
+ {
+ unaSemantic(e, sc);
+ e.e1 = resolveProperties(sc, e.e1);
+ if (e.e1.op == TOK.error)
+ {
+ result = e.e1;
+ return;
+ }
+ e.type = e.e1.type.nextOf().pointerTo();
+ }
+ result = e;
+ }
+
+ override void visit(IndexExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("IndexExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ // operator overloading should be handled in ArrayExp already.
+ if (!exp.e1.type)
+ exp.e1 = exp.e1.expressionSemantic(sc);
+ assert(exp.e1.type); // semantic() should already be run on it
+ if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple)
+ {
+ exp.e2 = exp.e2.expressionSemantic(sc);
+ exp.e2 = resolveProperties(sc, exp.e2);
+ Type nt;
+ if (exp.e2.op == TOK.type)
+ nt = new TypeAArray(exp.e1.type, exp.e2.type);
+ else
+ nt = new TypeSArray(exp.e1.type, exp.e2);
+ Expression e = new TypeExp(exp.loc, nt);
+ result = e.expressionSemantic(sc);
+ return;
+ }
+ if (exp.e1.op == TOK.error)
+ {
+ result = exp.e1;
+ return;
+ }
+ if (exp.e1.type.ty == Terror)
+ return setError();
+
+ // Note that unlike C we do not implement the int[ptr]
+
+ Type t1b = exp.e1.type.toBasetype();
+
+ if (t1b.ty == Tvector)
+ {
+ // Convert e1 to corresponding static array
+ TypeVector tv1 = cast(TypeVector)t1b;
+ t1b = tv1.basetype;
+ t1b = t1b.castMod(tv1.mod);
+ exp.e1.type = t1b;
+ }
+
+ /* Run semantic on e2
+ */
+ Scope* scx = sc;
+ if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
+ {
+ // Create scope for 'length' variable
+ ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
+ sym.parent = sc.scopesym;
+ sc = sc.push(sym);
+ }
+ if (t1b.ty == Ttuple)
+ sc = sc.startCTFE();
+ exp.e2 = exp.e2.expressionSemantic(sc);
+ exp.e2 = resolveProperties(sc, exp.e2);
+ if (t1b.ty == Ttuple)
+ sc = sc.endCTFE();
+ if (exp.e2.op == TOK.tuple)
+ {
+ TupleExp te = cast(TupleExp)exp.e2;
+ if (te.exps && te.exps.dim == 1)
+ exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix
+ }
+ if (sc != scx)
+ sc = sc.pop();
+ if (exp.e2.type == Type.terror)
+ return setError();
+
+ if (checkNonAssignmentArrayOp(exp.e1))
+ return setError();
+
+ switch (t1b.ty)
+ {
+ case Tpointer:
+ if (t1b.isPtrToFunction())
+ {
+ exp.error("cannot index function pointer `%s`", exp.e1.toChars());
+ return setError();
+ }
+ exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
+ if (exp.e2.type == Type.terror)
+ return setError();
+ exp.e2 = exp.e2.optimize(WANTvalue);
+ if (exp.e2.op == TOK.int64 && exp.e2.toInteger() == 0)
+ {
+ }
+ else if (sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
+ {
+ exp.error("safe function `%s` cannot index pointer `%s`", sc.func.toPrettyChars(), exp.e1.toChars());
+ return setError();
+ }
+ exp.type = (cast(TypeNext)t1b).next;
+ break;
+
+ case Tarray:
+ exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
+ if (exp.e2.type == Type.terror)
+ return setError();
+ exp.type = (cast(TypeNext)t1b).next;
+ break;
+
+ case Tsarray:
+ {
+ exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
+ if (exp.e2.type == Type.terror)
+ return setError();
+ exp.type = t1b.nextOf();
+ break;
+ }
+ case Taarray:
+ {
+ TypeAArray taa = cast(TypeAArray)t1b;
+ /* We can skip the implicit conversion if they differ only by
+ * constness
+ * https://issues.dlang.org/show_bug.cgi?id=2684
+ * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
+ */
+ if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index))
+ {
+ exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking
+ if (exp.e2.type == Type.terror)
+ return setError();
+ }
+
+ semanticTypeInfo(sc, taa);
+
+ exp.type = taa.next;
+ break;
+ }
+ case Ttuple:
+ {
+ exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
+ if (exp.e2.type == Type.terror)
+ return setError();
+
+ exp.e2 = exp.e2.ctfeInterpret();
+ uinteger_t index = exp.e2.toUInteger();
+
+ TupleExp te;
+ TypeTuple tup;
+ size_t length;
+ if (exp.e1.op == TOK.tuple)
+ {
+ te = cast(TupleExp)exp.e1;
+ tup = null;
+ length = te.exps.dim;
+ }
+ else if (exp.e1.op == TOK.type)
+ {
+ te = null;
+ tup = cast(TypeTuple)t1b;
+ length = Parameter.dim(tup.arguments);
+ }
+ else
+ assert(0);
+
+ if (length <= index)
+ {
+ exp.error("array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
+ return setError();
+ }
+ Expression e;
+ if (exp.e1.op == TOK.tuple)
+ {
+ e = (*te.exps)[cast(size_t)index];
+ e = Expression.combine(te.e0, e);
+ }
+ else
+ e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type);
+ result = e;
+ return;
+ }
+ default:
+ exp.error("`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars());
+ return setError();
+ }
+
+ // We might know $ now
+ setLengthVarIfKnown(exp.lengthVar, t1b);
+
+ if (t1b.ty == Tsarray || t1b.ty == Tarray)
+ {
+ Expression el = new ArrayLengthExp(exp.loc, exp.e1);
+ el = el.expressionSemantic(sc);
+ el = el.optimize(WANTvalue);
+ if (el.op == TOK.int64)
+ {
+ exp.e2 = exp.e2.optimize(WANTvalue);
+ dinteger_t length = el.toInteger();
+ if (length)
+ {
+ auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1));
+ exp.indexIsInBounds = bounds.contains(getIntRange(exp.e2));
+ }
+ }
+ }
+
+ result = exp;
+ }
+
+ override void visit(PostExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("PostExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemantic(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e1x = resolveProperties(sc, exp.e1);
+ if (e1x.op == TOK.error)
+ {
+ result = e1x;
+ return;
+ }
+ exp.e1 = e1x;
+
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp.e1.checkReadModifyWrite(exp.op))
+ return setError();
+
+ if (exp.e1.op == TOK.slice)
+ {
+ const(char)* s = exp.op == TOK.plusPlus ? "increment" : "decrement";
+ exp.error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
+ return setError();
+ }
+
+ Type t1 = exp.e1.type.toBasetype();
+ if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == TOK.arrayLength)
+ {
+ /* Check for operator overloading,
+ * but rewrite in terms of ++e instead of e++
+ */
+
+ /* If e1 is not trivial, take a reference to it
+ */
+ Expression de = null;
+ if (exp.e1.op != TOK.variable && exp.e1.op != TOK.arrayLength)
+ {
+ // ref v = e1;
+ auto v = copyToTemp(STC.ref_, "__postref", exp.e1);
+ de = new DeclarationExp(exp.loc, v);
+ exp.e1 = new VarExp(exp.e1.loc, v);
+ }
+
+ /* Rewrite as:
+ * auto tmp = e1; ++e1; tmp
+ */
+ auto tmp = copyToTemp(0, "__pitmp", exp.e1);
+ Expression ea = new DeclarationExp(exp.loc, tmp);
+
+ Expression eb = exp.e1.syntaxCopy();
+ eb = new PreExp(exp.op == TOK.plusPlus ? TOK.prePlusPlus : TOK.preMinusMinus, exp.loc, eb);
+
+ Expression ec = new VarExp(exp.loc, tmp);
+
+ // Combine de,ea,eb,ec
+ if (de)
+ ea = new CommaExp(exp.loc, de, ea);
+ e = new CommaExp(exp.loc, ea, eb);
+ e = new CommaExp(exp.loc, e, ec);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+
+ exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
+ exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
+
+ e = exp;
+ if (exp.e1.checkScalar() ||
+ exp.e1.checkSharedAccess(sc))
+ return setError();
+ if (exp.e1.checkNoBool())
+ return setError();
+
+ if (exp.e1.type.ty == Tpointer)
+ e = scaleFactor(exp, sc);
+ else
+ exp.e2 = exp.e2.castTo(sc, exp.e1.type);
+ e.type = exp.e1.type;
+ result = e;
+ }
+
+ override void visit(PreExp exp)
+ {
+ Expression e = exp.op_overload(sc);
+ // printf("PreExp::semantic('%s')\n", toChars());
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ // Rewrite as e1+=1 or e1-=1
+ if (exp.op == TOK.prePlusPlus)
+ e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
+ else
+ e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
+ result = e.expressionSemantic(sc);
+ }
+
+ /*
+ * Get the expression initializer for a specific struct
+ *
+ * Params:
+ * sd = the struct for which the expression initializer is needed
+ * loc = the location of the initializer
+ * sc = the scope where the expression is located
+ * t = the type of the expression
+ *
+ * Returns:
+ * The expression initializer or error expression if any errors occured
+ */
+ private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t)
+ {
+ if (sd.zeroInit && !sd.isNested())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=14606
+ // Always use BlitExp for the special expression: (struct = 0)
+ return IntegerExp.literal!0;
+ }
+
+ if (sd.isNested())
+ {
+ auto sle = new StructLiteralExp(loc, sd, null, t);
+ if (!sd.fill(loc, sle.elements, true))
+ return ErrorExp.get();
+ if (checkFrameAccess(loc, sc, sd, sle.elements.dim))
+ return ErrorExp.get();
+
+ sle.type = t;
+ return sle;
+ }
+
+ return t.defaultInit(loc);
+ }
+
+ override void visit(AssignExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("AssignExp::semantic('%s')\n", exp.toChars());
+ }
+ //printf("exp.e1.op = %d, '%s'\n", exp.e1.op, Token.toChars(exp.e1.op));
+ //printf("exp.e2.op = %d, '%s'\n", exp.e2.op, Token.toChars(exp.e2.op));
+
+ void setResult(Expression e, int line = __LINE__)
+ {
+ //printf("line %d\n", line);
+ result = e;
+ }
+
+ if (exp.type)
+ {
+ return setResult(exp);
+ }
+
+ Expression e1old = exp.e1;
+
+ if (auto e2comma = exp.e2.isCommaExp())
+ {
+ if (!e2comma.isGenerated)
+ exp.error("Using the result of a comma expression is not allowed");
+
+ /* Rewrite to get rid of the comma from rvalue
+ * e1=(e0,e2) => e0,(e1=e2)
+ */
+ Expression e0;
+ exp.e2 = Expression.extractLast(e2comma, e0);
+ Expression e = Expression.combine(e0, exp);
+ return setResult(e.expressionSemantic(sc));
+ }
+
+ /* Look for operator overloading of a[arguments] = e2.
+ * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
+ * converted to unary operator overloading already.
+ */
+ if (auto ae = exp.e1.isArrayExp())
+ {
+ Expression res;
+
+ ae.e1 = ae.e1.expressionSemantic(sc);
+ ae.e1 = resolveProperties(sc, ae.e1);
+ Expression ae1old = ae.e1;
+
+ const(bool) maybeSlice =
+ (ae.arguments.dim == 0 ||
+ ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval);
+
+ IntervalExp ie = null;
+ if (maybeSlice && ae.arguments.dim)
+ {
+ assert((*ae.arguments)[0].op == TOK.interval);
+ ie = cast(IntervalExp)(*ae.arguments)[0];
+ }
+ while (true)
+ {
+ if (ae.e1.op == TOK.error)
+ return setResult(ae.e1);
+
+ Expression e0 = null;
+ Expression ae1save = ae.e1;
+ ae.lengthVar = null;
+
+ Type t1b = ae.e1.type.toBasetype();
+ AggregateDeclaration ad = isAggregate(t1b);
+ if (!ad)
+ break;
+ if (search_function(ad, Id.indexass))
+ {
+ // Deal with $
+ res = resolveOpDollar(sc, ae, &e0);
+ if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
+ goto Lfallback;
+ if (res.op == TOK.error)
+ return setResult(res);
+
+ res = exp.e2.expressionSemantic(sc);
+ if (res.op == TOK.error)
+ return setResult(res);
+ exp.e2 = res;
+
+ /* Rewrite (a[arguments] = e2) as:
+ * a.opIndexAssign(e2, arguments)
+ */
+ Expressions* a = ae.arguments.copy();
+ a.insert(0, exp.e2);
+ res = new DotIdExp(exp.loc, ae.e1, Id.indexass);
+ res = new CallExp(exp.loc, res, a);
+ if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
+ res = res.trySemantic(sc);
+ else
+ res = res.expressionSemantic(sc);
+ if (res)
+ return setResult(Expression.combine(e0, res));
+ }
+
+ Lfallback:
+ if (maybeSlice && search_function(ad, Id.sliceass))
+ {
+ // Deal with $
+ res = resolveOpDollar(sc, ae, ie, &e0);
+ if (res.op == TOK.error)
+ return setResult(res);
+
+ res = exp.e2.expressionSemantic(sc);
+ if (res.op == TOK.error)
+ return setResult(res);
+
+ exp.e2 = res;
+
+ /* Rewrite (a[i..j] = e2) as:
+ * a.opSliceAssign(e2, i, j)
+ */
+ auto a = new Expressions();
+ a.push(exp.e2);
+ if (ie)
+ {
+ a.push(ie.lwr);
+ a.push(ie.upr);
+ }
+ res = new DotIdExp(exp.loc, ae.e1, Id.sliceass);
+ res = new CallExp(exp.loc, res, a);
+ res = res.expressionSemantic(sc);
+ return setResult(Expression.combine(e0, res));
+ }
+
+ // No operator overloading member function found yet, but
+ // there might be an alias this to try.
+ if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
+ {
+ /* Rewrite (a[arguments] op e2) as:
+ * a.aliasthis[arguments] op e2
+ */
+ ae.e1 = resolveAliasThis(sc, ae1save, true);
+ if (ae.e1)
+ continue;
+ }
+ break;
+ }
+ ae.e1 = ae1old; // recovery
+ ae.lengthVar = null;
+ }
+
+ /* Run this.e1 semantic.
+ */
+ {
+ Expression e1x = exp.e1;
+
+ /* With UFCS, e.f = value
+ * Could mean:
+ * .f(e, value)
+ * or:
+ * .f(e) = value
+ */
+ if (auto dti = e1x.isDotTemplateInstanceExp())
+ {
+ Expression e = dti.semanticY(sc, 1);
+ if (!e)
+ {
+ return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
+ }
+
+ e1x = e;
+ }
+ else if (auto die = e1x.isDotIdExp())
+ {
+ Expression e = die.semanticY(sc, 1);
+ if (e && isDotOpDispatch(e))
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=19687
+ *
+ * On this branch, e2 is semantically analyzed in resolvePropertiesX,
+ * but that call is done with gagged errors. That is the only time when
+ * semantic gets ran on e2, that is why the error never gets to be printed.
+ * In order to make sure that UFCS is tried with correct parameters, e2
+ * needs to have semantic ran on it.
+ */
+ exp.e2 = exp.e2.expressionSemantic(sc);
+ uint errors = global.startGagging();
+ e = resolvePropertiesX(sc, e, exp.e2);
+ if (global.endGagging(errors))
+ e = null; /* fall down to UFCS */
+ else
+ return setResult(e);
+ }
+ if (!e)
+ return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
+ e1x = e;
+ }
+ else
+ {
+ if (auto se = e1x.isSliceExp())
+ se.arrayop = true;
+
+ e1x = e1x.expressionSemantic(sc);
+ }
+
+ /* We have f = value.
+ * Could mean:
+ * f(value)
+ * or:
+ * f() = value
+ */
+ if (Expression e = resolvePropertiesX(sc, e1x, exp.e2))
+ return setResult(e);
+
+ if (e1x.checkRightThis(sc))
+ {
+ return setError();
+ }
+ exp.e1 = e1x;
+ assert(exp.e1.type);
+ }
+ Type t1 = exp.e1.type.toBasetype();
+
+ /* Run this.e2 semantic.
+ * Different from other binary expressions, the analysis of e2
+ * depends on the result of e1 in assignments.
+ */
+ {
+ Expression e2x = inferType(exp.e2, t1.baseElemOf());
+ e2x = e2x.expressionSemantic(sc);
+ e2x = resolveProperties(sc, e2x);
+ if (e2x.op == TOK.type)
+ e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
+ if (e2x.op == TOK.error)
+ return setResult(e2x);
+ // We skip checking the value for structs/classes as these might have
+ // an opAssign defined.
+ if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
+ e2x.checkSharedAccess(sc))
+ return setError();
+ exp.e2 = e2x;
+ }
+
+ /* Rewrite tuple assignment as a tuple of assignments.
+ */
+ {
+ Expression e2x = exp.e2;
+
+ Ltupleassign:
+ if (exp.e1.op == TOK.tuple && e2x.op == TOK.tuple)
+ {
+ TupleExp tup1 = cast(TupleExp)exp.e1;
+ TupleExp tup2 = cast(TupleExp)e2x;
+ size_t dim = tup1.exps.dim;
+ Expression e = null;
+ if (dim != tup2.exps.dim)
+ {
+ exp.error("mismatched tuple lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.dim);
+ return setError();
+ }
+ if (dim == 0)
+ {
+ e = IntegerExp.literal!0;
+ e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error
+ e = Expression.combine(tup1.e0, tup2.e0, e);
+ }
+ else
+ {
+ auto exps = new Expressions(dim);
+ for (size_t i = 0; i < dim; i++)
+ {
+ Expression ex1 = (*tup1.exps)[i];
+ Expression ex2 = (*tup2.exps)[i];
+ (*exps)[i] = new AssignExp(exp.loc, ex1, ex2);
+ }
+ e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps);
+ }
+ return setResult(e.expressionSemantic(sc));
+ }
+
+ /* Look for form: e1 = e2.aliasthis.
+ */
+ if (exp.e1.op == TOK.tuple)
+ {
+ TupleDeclaration td = isAliasThisTuple(e2x);
+ if (!td)
+ goto Lnomatch;
+
+ assert(exp.e1.type.ty == Ttuple);
+ TypeTuple tt = cast(TypeTuple)exp.e1.type;
+
+ Expression e0;
+ Expression ev = extractSideEffect(sc, "__tup", e0, e2x);
+
+ auto iexps = new Expressions();
+ iexps.push(ev);
+ for (size_t u = 0; u < iexps.dim; u++)
+ {
+ Lexpand:
+ Expression e = (*iexps)[u];
+
+ Parameter arg = Parameter.getNth(tt.arguments, u);
+ //printf("[%d] iexps.dim = %d, ", u, iexps.dim);
+ //printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars());
+ //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
+
+ if (!arg || !e.type.implicitConvTo(arg.type))
+ {
+ // expand initializer to tuple
+ if (expandAliasThisTuples(iexps, u) != -1)
+ {
+ if (iexps.dim <= u)
+ break;
+ goto Lexpand;
+ }
+ goto Lnomatch;
+ }
+ }
+ e2x = new TupleExp(e2x.loc, e0, iexps);
+ e2x = e2x.expressionSemantic(sc);
+ if (e2x.op == TOK.error)
+ {
+ result = e2x;
+ return;
+ }
+ // Do not need to overwrite this.e2
+ goto Ltupleassign;
+ }
+ Lnomatch:
+ }
+
+ /* Inside constructor, if this is the first assignment of object field,
+ * rewrite this to initializing the field.
+ */
+ if (exp.op == TOK.assign
+ && exp.e1.checkModifiable(sc) == Modifiable.initialization)
+ {
+ //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
+ auto t = exp.type;
+ exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
+ exp.type = t;
+
+ // https://issues.dlang.org/show_bug.cgi?id=13515
+ // set Index::modifiable flag for complex AA element initialization
+ if (auto ie1 = exp.e1.isIndexExp())
+ {
+ Expression e1x = ie1.markSettingAAElem();
+ if (e1x.op == TOK.error)
+ {
+ result = e1x;
+ return;
+ }
+ }
+ }
+ else if (exp.op == TOK.construct && exp.e1.op == TOK.variable &&
+ (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
+ {
+ exp.memset = MemorySet.referenceInit;
+ }
+
+ if (exp.op == TOK.assign) // skip TOK.blit and TOK.construct, which are initializations
+ {
+ exp.e1.checkSharedAccess(sc);
+ checkUnsafeAccess(sc, exp.e1, false, true);
+ }
+
+ checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked
+
+ /* If it is an assignment from a 'foreign' type,
+ * check for operator overloading.
+ */
+ if (exp.memset == MemorySet.referenceInit)
+ {
+ // If this is an initialization of a reference,
+ // do nothing
+ }
+ else if (t1.ty == Tstruct)
+ {
+ auto e1x = exp.e1;
+ auto e2x = exp.e2;
+ auto sd = (cast(TypeStruct)t1).sym;
+
+ if (exp.op == TOK.construct)
+ {
+ Type t2 = e2x.type.toBasetype();
+ if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
+ {
+ sd.size(exp.loc);
+ if (sd.sizeok != Sizeok.done)
+ return setError();
+ if (!sd.ctor)
+ sd.ctor = sd.searchCtor();
+
+ // https://issues.dlang.org/show_bug.cgi?id=15661
+ // Look for the form from last of comma chain.
+ auto e2y = lastComma(e2x);
+
+ CallExp ce = (e2y.op == TOK.call) ? cast(CallExp)e2y : null;
+ DotVarExp dve = (ce && ce.e1.op == TOK.dotVariable)
+ ? cast(DotVarExp)ce.e1 : null;
+ if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
+ // https://issues.dlang.org/show_bug.cgi?id=19389
+ dve.e1.op != TOK.dotVariable &&
+ e2y.type.implicitConvTo(t1))
+ {
+ /* Look for form of constructor call which is:
+ * __ctmp.ctor(arguments...)
+ */
+
+ /* Before calling the constructor, initialize
+ * variable with a bit copy of the default
+ * initializer
+ */
+ Expression einit = getInitExp(sd, exp.loc, sc, t1);
+ if (einit.op == TOK.error)
+ {
+ result = einit;
+ return;
+ }
+
+ auto ae = new BlitExp(exp.loc, exp.e1, einit);
+ ae.type = e1x.type;
+
+ /* Replace __ctmp being constructed with e1.
+ * We need to copy constructor call expression,
+ * because it may be used in other place.
+ */
+ auto dvx = cast(DotVarExp)dve.copy();
+ dvx.e1 = e1x;
+ auto cx = cast(CallExp)ce.copy();
+ cx.e1 = dvx;
+ if (checkConstructorEscape(sc, cx, false))
+ return setError();
+
+ Expression e0;
+ Expression.extractLast(e2x, e0);
+
+ auto e = Expression.combine(e0, ae, cx);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ // https://issues.dlang.org/show_bug.cgi?id=21586
+ // Rewrite CondExp or e1 will miss direct construction, e.g.
+ // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
+ // a temporary created and an extra destructor call.
+ // AST will be rewritten to:
+ // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
+ if (e2x.op == TOK.question)
+ {
+ /* Rewrite as:
+ * a ? e1 = b : e1 = c;
+ */
+ CondExp econd = cast(CondExp)e2x;
+ Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1);
+ Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2);
+ Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2);
+ result = e.expressionSemantic(sc);
+ return;
+ }
+ if (sd.postblit || sd.hasCopyCtor)
+ {
+ /* We have a copy constructor for this
+ */
+
+ if (e2x.isLvalue())
+ {
+ if (sd.hasCopyCtor)
+ {
+ /* Rewrite as:
+ * e1 = init, e1.copyCtor(e2);
+ */
+ Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1));
+ einit.type = e1x.type;
+
+ Expression e;
+ e = new DotIdExp(exp.loc, e1x, Id.ctor);
+ e = new CallExp(exp.loc, e, e2x);
+ e = new CommaExp(exp.loc, einit, e);
+
+ //printf("e: %s\n", e.toChars());
+
+ result = e.expressionSemantic(sc);
+ return;
+ }
+ else
+ {
+ if (!e2x.type.implicitConvTo(e1x.type))
+ {
+ exp.error("conversion error from `%s` to `%s`",
+ e2x.type.toChars(), e1x.type.toChars());
+ return setError();
+ }
+
+ /* Rewrite as:
+ * (e1 = e2).postblit();
+ *
+ * Blit assignment e1 = e2 returns a reference to the original e1,
+ * then call the postblit on it.
+ */
+ Expression e = e1x.copy();
+ e.type = e.type.mutableOf();
+ if (e.type.isShared && !sd.type.isShared)
+ e.type = e.type.unSharedOf();
+ e = new BlitExp(exp.loc, e, e2x);
+ e = new DotVarExp(exp.loc, e, sd.postblit, false);
+ e = new CallExp(exp.loc, e);
+ result = e.expressionSemantic(sc);
+ return;
+ }
+ }
+ else
+ {
+ /* The struct value returned from the function is transferred
+ * so should not call the destructor on it.
+ */
+ e2x = valueNoDtor(e2x);
+ }
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=19251
+ // if e2 cannot be converted to e1.type, maybe there is an alias this
+ if (!e2x.implicitConvTo(t1))
+ {
+ AggregateDeclaration ad2 = isAggregate(e2x.type);
+ if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
+ {
+ /* Rewrite (e1 op e2) as:
+ * (e1 op e2.aliasthis)
+ */
+ exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
+ result = exp.expressionSemantic(sc);
+ return;
+ }
+ }
+ }
+ else if (!e2x.implicitConvTo(t1))
+ {
+ sd.size(exp.loc);
+ if (sd.sizeok != Sizeok.done)
+ return setError();
+ if (!sd.ctor)
+ sd.ctor = sd.searchCtor();
+
+ if (sd.ctor)
+ {
+ /* Look for implicit constructor call
+ * Rewrite as:
+ * e1 = init, e1.ctor(e2)
+ */
+
+ /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
+ * Using `new` to initialize a struct object is a common mistake, but
+ * the error message from the compiler is not very helpful in that
+ * case. If exp.e2 is a NewExp and the type of new is the same as
+ * the type as exp.e1 (struct in this case), then we know for sure
+ * that the user wants to instantiate a struct. This is done to avoid
+ * issuing an error when the user actually wants to call a constructor
+ * which receives a class object.
+ *
+ * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
+ * which receives an instance of a Foo2 class
+ */
+ if (exp.e2.op == TOK.new_)
+ {
+ auto newExp = cast(NewExp)(exp.e2);
+ if (newExp.newtype && newExp.newtype == t1)
+ {
+ error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
+ newExp.toChars(), newExp.type.toChars(), t1.toChars());
+ errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?");
+ return setError();
+ }
+ }
+
+ Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1));
+ einit.type = e1x.type;
+
+ Expression e;
+ e = new DotIdExp(exp.loc, e1x, Id.ctor);
+ e = new CallExp(exp.loc, e, e2x);
+ e = new CommaExp(exp.loc, einit, e);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ if (search_function(sd, Id.call))
+ {
+ /* Look for static opCall
+ * https://issues.dlang.org/show_bug.cgi?id=2702
+ * Rewrite as:
+ * e1 = typeof(e1).opCall(arguments)
+ */
+ e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call);
+ e2x = new CallExp(exp.loc, e2x, exp.e2);
+
+ e2x = e2x.expressionSemantic(sc);
+ e2x = resolveProperties(sc, e2x);
+ if (e2x.op == TOK.error)
+ {
+ result = e2x;
+ return;
+ }
+ if (e2x.checkValue() || e2x.checkSharedAccess(sc))
+ return setError();
+ }
+ }
+ else // https://issues.dlang.org/show_bug.cgi?id=11355
+ {
+ AggregateDeclaration ad2 = isAggregate(e2x.type);
+ if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
+ {
+ /* Rewrite (e1 op e2) as:
+ * (e1 op e2.aliasthis)
+ */
+ exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
+ result = exp.expressionSemantic(sc);
+ return;
+ }
+ }
+ }
+ else if (exp.op == TOK.assign)
+ {
+ if (e1x.op == TOK.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
+ {
+ /*
+ * Rewrite:
+ * aa[key] = e2;
+ * as:
+ * ref __aatmp = aa;
+ * ref __aakey = key;
+ * ref __aaval = e2;
+ * (__aakey in __aatmp
+ * ? __aatmp[__aakey].opAssign(__aaval)
+ * : ConstructExp(__aatmp[__aakey], __aaval));
+ */
+ // ensure we keep the expr modifiable
+ Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
+ if (esetting.op == TOK.error)
+ {
+ result = esetting;
+ return;
+ }
+ assert(esetting.op == TOK.index);
+ IndexExp ie = cast(IndexExp) esetting;
+ Type t2 = e2x.type.toBasetype();
+
+ Expression e0 = null;
+ Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1);
+ Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2);
+ Expression ev = extractSideEffect(sc, "__aaval", e0, e2x);
+
+ AssignExp ae = cast(AssignExp)exp.copy();
+ ae.e1 = new IndexExp(exp.loc, ea, ek);
+ ae.e1 = ae.e1.expressionSemantic(sc);
+ ae.e1 = ae.e1.optimize(WANTvalue);
+ ae.e2 = ev;
+ Expression e = ae.op_overload(sc);
+ if (e)
+ {
+ Expression ey = null;
+ if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
+ {
+ ey = ev;
+ }
+ else if (!ev.implicitConvTo(ie.type) && sd.ctor)
+ {
+ // Look for implicit constructor call
+ // Rewrite as S().ctor(e2)
+ ey = new StructLiteralExp(exp.loc, sd, null);
+ ey = new DotIdExp(exp.loc, ey, Id.ctor);
+ ey = new CallExp(exp.loc, ey, ev);
+ ey = ey.trySemantic(sc);
+ }
+ if (ey)
+ {
+ Expression ex;
+ ex = new IndexExp(exp.loc, ea, ek);
+ ex = ex.expressionSemantic(sc);
+ ex = ex.modifiableLvalue(sc, ex); // allocate new slot
+ ex = ex.optimize(WANTvalue);
+
+ ey = new ConstructExp(exp.loc, ex, ey);
+ ey = ey.expressionSemantic(sc);
+ if (ey.op == TOK.error)
+ {
+ result = ey;
+ return;
+ }
+ ex = e;
+
+ // https://issues.dlang.org/show_bug.cgi?id=14144
+ // The whole expression should have the common type
+ // of opAssign() return and assigned AA entry.
+ // Even if there's no common type, expression should be typed as void.
+ if (!typeMerge(sc, TOK.question, ex, ey))
+ {
+ ex = new CastExp(ex.loc, ex, Type.tvoid);
+ ey = new CastExp(ey.loc, ey, Type.tvoid);
+ }
+ e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey);
+ }
+ e = Expression.combine(e0, e);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ }
+ else
+ {
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+ }
+ else
+ assert(exp.op == TOK.blit);
+
+ exp.e1 = e1x;
+ exp.e2 = e2x;
+ }
+ else if (t1.ty == Tclass)
+ {
+ // Disallow assignment operator overloads for same type
+ if (exp.op == TOK.assign && !exp.e2.implicitConvTo(exp.e1.type))
+ {
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+ }
+ }
+ else if (t1.ty == Tsarray)
+ {
+ // SliceExp cannot have static array type without context inference.
+ assert(exp.e1.op != TOK.slice);
+ Expression e1x = exp.e1;
+ Expression e2x = exp.e2;
+
+ if (e2x.implicitConvTo(e1x.type))
+ {
+ if (exp.op != TOK.blit && (e2x.op == TOK.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == TOK.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != TOK.slice && e2x.isLvalue()))
+ {
+ if (e1x.checkPostblit(sc, t1))
+ return setError();
+ }
+
+ // e2 matches to t1 because of the implicit length match, so
+ if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op))
+ {
+ // convert e1 to e1[]
+ // e.g. e1[] = a[] + b[];
+ auto sle = new SliceExp(e1x.loc, e1x, null, null);
+ sle.arrayop = true;
+ e1x = sle.expressionSemantic(sc);
+ }
+ else
+ {
+ // convert e2 to t1 later
+ // e.g. e1 = [1, 2, 3];
+ }
+ }
+ else
+ {
+ if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch)
+ {
+ uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger();
+ uinteger_t dim2 = dim1;
+ if (auto ale = e2x.isArrayLiteralExp())
+ {
+ dim2 = ale.elements ? ale.elements.dim : 0;
+ }
+ else if (auto se = e2x.isSliceExp())
+ {
+ Type tx = toStaticArrayType(se);
+ if (tx)
+ dim2 = (cast(TypeSArray)tx).dim.toInteger();
+ }
+ if (dim1 != dim2)
+ {
+ exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
+ return setError();
+ }
+ }
+
+ // May be block or element-wise assignment, so
+ // convert e1 to e1[]
+ if (exp.op != TOK.assign)
+ {
+ // If multidimensional static array, treat as one large array
+ //
+ // Find the appropriate array type depending on the assignment, e.g.
+ // int[3] = int => int[3]
+ // int[3][2] = int => int[6]
+ // int[3][2] = int[] => int[3][2]
+ // int[3][2][4] + int => int[24]
+ // int[3][2][4] + int[] => int[3][8]
+ ulong dim = t1.isTypeSArray().dim.toUInteger();
+ auto type = t1.nextOf();
+
+ for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; )
+ {
+ import core.checkedint : mulu;
+
+ // Accumulate skipped dimensions
+ bool overflow = false;
+ dim = mulu(dim, tsa.dim.toUInteger(), overflow);
+ if (overflow || dim >= uint.max)
+ {
+ // dym exceeds maximum array size
+ exp.error("static array `%s` size overflowed to %llu",
+ e1x.type.toChars(), cast(ulong) dim);
+ return setError();
+ }
+
+ // Move to the element type
+ type = tsa.nextOf().toBasetype();
+
+ // Rewrite ex1 as a static array if a matching type was found
+ if (e2x.implicitConvTo(type) > MATCH.nomatch)
+ {
+ e1x.type = type.sarrayOf(dim);
+ break;
+ }
+ }
+ }
+ auto sle = new SliceExp(e1x.loc, e1x, null, null);
+ sle.arrayop = true;
+ e1x = sle.expressionSemantic(sc);
+ }
+ if (e1x.op == TOK.error)
+ return setResult(e1x);
+ if (e2x.op == TOK.error)
+ return setResult(e2x);
+
+ exp.e1 = e1x;
+ exp.e2 = e2x;
+ t1 = e1x.type.toBasetype();
+ }
+ /* Check the mutability of e1.
+ */
+ if (auto ale = exp.e1.isArrayLengthExp())
+ {
+ // e1 is not an lvalue, but we let code generator handle it
+
+ auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1);
+ if (ale1x.op == TOK.error)
+ return setResult(ale1x);
+ ale.e1 = ale1x;
+
+ Type tn = ale.e1.type.toBasetype().nextOf();
+ checkDefCtor(ale.loc, tn);
+
+ Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT;
+ if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays"))
+ return setError();
+
+ exp.e2 = exp.e2.expressionSemantic(sc);
+ auto lc = lastComma(exp.e2);
+ lc = lc.optimize(WANTvalue);
+ // use slice expression when arr.length = 0 to avoid runtime call
+ if(lc.op == TOK.int64 && lc.toInteger() == 0)
+ {
+ Expression se = new SliceExp(ale.loc, ale.e1, lc, lc);
+ Expression as = new AssignExp(ale.loc, ale.e1, se);
+ as = as.expressionSemantic(sc);
+ auto res = Expression.combine(as, exp.e2);
+ res.type = ale.type;
+ return setResult(res);
+ }
+
+ // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
+ Expression id = new IdentifierExp(ale.loc, Id.empty);
+ id = new DotIdExp(ale.loc, id, Id.object);
+ auto tiargs = new Objects();
+ tiargs.push(ale.e1.type);
+ id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs);
+ id = new DotIdExp(ale.loc, id, hook);
+ id = id.expressionSemantic(sc);
+
+ auto arguments = new Expressions();
+ arguments.reserve(5);
+ if (global.params.tracegc)
+ {
+ auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
+ arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
+ arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
+ arguments.push(new StringExp(exp.loc, funcname.toDString()));
+ }
+ arguments.push(ale.e1);
+ arguments.push(exp.e2);
+
+ Expression ce = new CallExp(ale.loc, id, arguments);
+ auto res = ce.expressionSemantic(sc);
+ // if (global.params.verbose)
+ // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
+ return setResult(res);
+ }
+ else if (auto se = exp.e1.isSliceExp())
+ {
+ Type tn = se.type.nextOf();
+ const fun = sc.func;
+ if (exp.op == TOK.assign && !tn.isMutable() &&
+ // allow modifiation in module ctor, see
+ // https://issues.dlang.org/show_bug.cgi?id=9884
+ (!fun || (fun && !fun.isStaticCtorDeclaration())))
+ {
+ exp.error("slice `%s` is not mutable", se.toChars());
+ return setError();
+ }
+
+ if (exp.op == TOK.assign && !tn.baseElemOf().isAssignable())
+ {
+ exp.error("slice `%s` is not mutable, struct `%s` has immutable members",
+ exp.e1.toChars(), tn.baseElemOf().toChars());
+ result = ErrorExp.get();
+ return;
+ }
+
+ // For conditional operator, both branches need conversion.
+ while (se.e1.op == TOK.slice)
+ se = cast(SliceExp)se.e1;
+ if (se.e1.op == TOK.question && se.e1.type.toBasetype().ty == Tsarray)
+ {
+ se.e1 = se.e1.modifiableLvalue(sc, exp.e1);
+ if (se.e1.op == TOK.error)
+ return setResult(se.e1);
+ }
+ }
+ else
+ {
+ if (t1.ty == Tsarray && exp.op == TOK.assign)
+ {
+ Type tn = exp.e1.type.nextOf();
+ if (tn && !tn.baseElemOf().isAssignable())
+ {
+ exp.error("array `%s` is not mutable, struct `%s` has immutable members",
+ exp.e1.toChars(), tn.baseElemOf().toChars());
+ result = ErrorExp.get();
+ return;
+ }
+ }
+
+ Expression e1x = exp.e1;
+
+ // Try to do a decent error message with the expression
+ // before it gets constant folded
+ if (exp.op == TOK.assign)
+ e1x = e1x.modifiableLvalue(sc, e1old);
+
+ e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
+
+ if (e1x.op == TOK.error)
+ {
+ result = e1x;
+ return;
+ }
+ exp.e1 = e1x;
+ }
+
+ /* Tweak e2 based on the type of e1.
+ */
+ Expression e2x = exp.e2;
+ Type t2 = e2x.type.toBasetype();
+
+ // If it is a array, get the element type. Note that it may be
+ // multi-dimensional.
+ Type telem = t1;
+ while (telem.ty == Tarray)
+ telem = telem.nextOf();
+
+ if (exp.e1.op == TOK.slice && t1.nextOf() &&
+ (telem.ty != Tvoid || e2x.op == TOK.null_) &&
+ e2x.implicitConvTo(t1.nextOf()))
+ {
+ // Check for block assignment. If it is of type void[], void[][], etc,
+ // '= null' is the only allowable block assignment (Bug 7493)
+ exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is
+ e2x = e2x.implicitCastTo(sc, t1.nextOf());
+ if (exp.op != TOK.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf()))
+ return setError();
+ }
+ else if (exp.e1.op == TOK.slice &&
+ (t2.ty == Tarray || t2.ty == Tsarray) &&
+ t2.nextOf().implicitConvTo(t1.nextOf()))
+ {
+ // Check element-wise assignment.
+
+ /* If assigned elements number is known at compile time,
+ * check the mismatch.
+ */
+ SliceExp se1 = cast(SliceExp)exp.e1;
+ TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1);
+ TypeSArray tsa2 = null;
+ if (auto ale = e2x.isArrayLiteralExp())
+ tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.dim);
+ else if (auto se = e2x.isSliceExp())
+ tsa2 = cast(TypeSArray)toStaticArrayType(se);
+ else
+ tsa2 = t2.isTypeSArray();
+ if (tsa1 && tsa2)
+ {
+ uinteger_t dim1 = tsa1.dim.toInteger();
+ uinteger_t dim2 = tsa2.dim.toInteger();
+ if (dim1 != dim2)
+ {
+ exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
+ return setError();
+ }
+ }
+
+ if (exp.op != TOK.blit &&
+ (e2x.op == TOK.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
+ e2x.op == TOK.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
+ e2x.op != TOK.slice && e2x.isLvalue()))
+ {
+ if (exp.e1.checkPostblit(sc, t1.nextOf()))
+ return setError();
+ }
+
+ if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == TOK.assign &&
+ e2x.op != TOK.slice && e2x.op != TOK.assign &&
+ e2x.op != TOK.arrayLiteral && e2x.op != TOK.string_ &&
+ !(e2x.op == TOK.add || e2x.op == TOK.min ||
+ e2x.op == TOK.mul || e2x.op == TOK.div ||
+ e2x.op == TOK.mod || e2x.op == TOK.xor ||
+ e2x.op == TOK.and || e2x.op == TOK.or ||
+ e2x.op == TOK.pow ||
+ e2x.op == TOK.tilde || e2x.op == TOK.negate))
+ {
+ const(char)* e1str = exp.e1.toChars();
+ const(char)* e2str = e2x.toChars();
+ exp.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str, e2str, e1str, e2str);
+ }
+
+ Type t2n = t2.nextOf();
+ Type t1n = t1.nextOf();
+ int offset;
+ if (t2n.equivalent(t1n) ||
+ t1n.isBaseOf(t2n, &offset) && offset == 0)
+ {
+ /* Allow copy of distinct qualifier elements.
+ * eg.
+ * char[] dst; const(char)[] src;
+ * dst[] = src;
+ *
+ * class C {} class D : C {}
+ * C[2] ca; D[] da;
+ * ca[] = da;
+ */
+ if (isArrayOpValid(e2x))
+ {
+ // Don't add CastExp to keep AST for array operations
+ e2x = e2x.copy();
+ e2x.type = exp.e1.type.constOf();
+ }
+ else
+ e2x = e2x.castTo(sc, exp.e1.type.constOf());
+ }
+ else
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=15778
+ * A string literal has an array type of immutable
+ * elements by default, and normally it cannot be convertible to
+ * array type of mutable elements. But for element-wise assignment,
+ * elements need to be const at best. So we should give a chance
+ * to change code unit size for polysemous string literal.
+ */
+ if (e2x.op == TOK.string_)
+ e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf());
+ else
+ e2x = e2x.implicitCastTo(sc, exp.e1.type);
+ }
+ if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
+ {
+ if (!sc.intypeof && sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
+ {
+ exp.error("cannot copy `void[]` to `void[]` in `@safe` code");
+ return setError();
+ }
+ }
+ }
+ else
+ {
+ if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == TOK.assign &&
+ t1.ty == Tarray && t2.ty == Tsarray &&
+ e2x.op != TOK.slice &&
+ t2.implicitConvTo(t1))
+ {
+ // Disallow ar[] = sa (Converted to ar[] = sa[])
+ // Disallow da = sa (Converted to da = sa[])
+ const(char)* e1str = exp.e1.toChars();
+ const(char)* e2str = e2x.toChars();
+ const(char)* atypestr = exp.e1.op == TOK.slice ? "element-wise" : "slice";
+ exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str);
+ }
+ if (exp.op == TOK.blit)
+ e2x = e2x.castTo(sc, exp.e1.type);
+ else
+ {
+ e2x = e2x.implicitCastTo(sc, exp.e1.type);
+
+ // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
+
+ // If the implicit cast has failed and the assign expression is
+ // the initialization of a struct member field
+ if (e2x.op == TOK.error && exp.op == TOK.construct && t1.ty == Tstruct)
+ {
+ scope sd = (cast(TypeStruct)t1).sym;
+ Dsymbol opAssign = search_function(sd, Id.assign);
+
+ // and the struct defines an opAssign
+ if (opAssign)
+ {
+ // offer more information about the cause of the problem
+ errorSupplemental(exp.loc,
+ "`%s` is the first assignment of `%s` therefore it represents its initialization",
+ exp.toChars(), exp.e1.toChars());
+ errorSupplemental(exp.loc,
+ "`opAssign` methods are not used for initialization, but for subsequent assignments");
+ }
+ }
+ }
+ }
+ if (e2x.op == TOK.error)
+ {
+ result = e2x;
+ return;
+ }
+ exp.e2 = e2x;
+ t2 = exp.e2.type.toBasetype();
+
+ /* Look for array operations
+ */
+ if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2))
+ {
+ // Look for valid array operations
+ if (exp.memset != MemorySet.blockAssign &&
+ exp.e1.op == TOK.slice &&
+ (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op)))
+ {
+ exp.type = exp.e1.type;
+ if (exp.op == TOK.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
+ // tweak mutability of e1 element
+ exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf();
+ result = arrayOp(exp, sc);
+ return;
+ }
+
+ // Drop invalid array operations in e2
+ // d = a[] + b[], d = (a[] + b[])[0..2], etc
+ if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == TOK.assign))
+ return setError();
+
+ // Remains valid array assignments
+ // d = d[], d = [1,2,3], etc
+ }
+
+ /* Don't allow assignment to classes that were allocated on the stack with:
+ * scope Class c = new Class();
+ */
+ if (exp.e1.op == TOK.variable && exp.op == TOK.assign)
+ {
+ VarExp ve = cast(VarExp)exp.e1;
+ VarDeclaration vd = ve.var.isVarDeclaration();
+ if (vd && (vd.onstack || vd.mynew))
+ {
+ assert(t1.ty == Tclass);
+ exp.error("cannot rebind scope variables");
+ }
+ }
+
+ if (exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
+ {
+ exp.error("cannot modify compiler-generated variable `__ctfe`");
+ }
+
+ exp.type = exp.e1.type;
+ assert(exp.type);
+ auto res = exp.op == TOK.assign ? exp.reorderSettingAAElem(sc) : exp;
+ checkAssignEscape(sc, res, false);
+ return setResult(res);
+ }
+
+ override void visit(PowAssignExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp.e1.checkReadModifyWrite(exp.op, exp.e2))
+ return setError();
+
+ assert(exp.e1.type && exp.e2.type);
+ if (exp.e1.op == TOK.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
+ {
+ if (checkNonAssignmentArrayOp(exp.e1))
+ return setError();
+
+ // T[] ^^= ...
+ if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
+ {
+ // T[] ^^= T
+ exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
+ }
+ else if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ // Check element types are arithmetic
+ Type tb1 = exp.e1.type.nextOf().toBasetype();
+ Type tb2 = exp.e2.type.toBasetype();
+ if (tb2.ty == Tarray || tb2.ty == Tsarray)
+ tb2 = tb2.nextOf().toBasetype();
+ if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating()))
+ {
+ exp.type = exp.e1.type;
+ result = arrayOp(exp, sc);
+ return;
+ }
+ }
+ else
+ {
+ exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
+ }
+
+ if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating()))
+ {
+ Expression e0 = null;
+ e = exp.reorderSettingAAElem(sc);
+ e = Expression.extractLast(e, e0);
+ assert(e == exp);
+
+ if (exp.e1.op == TOK.variable)
+ {
+ // Rewrite: e1 = e1 ^^ e2
+ e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2);
+ e = new AssignExp(exp.loc, exp.e1, e);
+ }
+ else
+ {
+ // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
+ auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1);
+ auto de = new DeclarationExp(exp.e1.loc, v);
+ auto ve = new VarExp(exp.e1.loc, v);
+ e = new PowExp(exp.loc, ve, exp.e2);
+ e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e);
+ e = new CommaExp(exp.loc, de, e);
+ }
+ e = Expression.combine(e0, e);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ result = exp.incompatibleTypes();
+ }
+
+ override void visit(CatAssignExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ //printf("CatAssignExp::semantic() %s\n", exp.toChars());
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp.e1.op == TOK.slice)
+ {
+ SliceExp se = cast(SliceExp)exp.e1;
+ if (se.e1.type.toBasetype().ty == Tsarray)
+ {
+ exp.error("cannot append to static array `%s`", se.e1.type.toChars());
+ return setError();
+ }
+ }
+
+ exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
+ if (exp.e1.op == TOK.error)
+ {
+ result = exp.e1;
+ return;
+ }
+ if (exp.e2.op == TOK.error)
+ {
+ result = exp.e2;
+ return;
+ }
+
+ if (checkNonAssignmentArrayOp(exp.e2))
+ return setError();
+
+ Type tb1 = exp.e1.type.toBasetype();
+ Type tb1next = tb1.nextOf();
+ Type tb2 = exp.e2.type.toBasetype();
+
+ /* Possibilities:
+ * TOK.concatenateAssign: appending T[] to T[]
+ * TOK.concatenateElemAssign: appending T to T[]
+ * TOK.concatenateDcharAssign: appending dchar to T[]
+ */
+ if ((tb1.ty == Tarray) &&
+ (tb2.ty == Tarray || tb2.ty == Tsarray) &&
+ (exp.e2.implicitConvTo(exp.e1.type) ||
+ (tb2.nextOf().implicitConvTo(tb1next) &&
+ (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
+ {
+ // TOK.concatenateAssign
+ assert(exp.op == TOK.concatenateAssign);
+ if (exp.e1.checkPostblit(sc, tb1next))
+ return setError();
+
+ exp.e2 = exp.e2.castTo(sc, exp.e1.type);
+ }
+ else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next))
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=19782
+ *
+ * If e2 is implicitly convertible to tb1next, the conversion
+ * might be done through alias this, in which case, e2 needs to
+ * be modified accordingly (e2 => e2.aliasthis).
+ */
+ if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next))
+ goto Laliasthis;
+ if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next))
+ goto Laliasthis;
+ // Append element
+ if (exp.e2.checkPostblit(sc, tb2))
+ return setError();
+
+ if (checkNewEscape(sc, exp.e2, false))
+ return setError();
+
+ exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next));
+ exp.e2 = doCopyOrMove(sc, exp.e2);
+ }
+ else if (tb1.ty == Tarray &&
+ (tb1next.ty == Tchar || tb1next.ty == Twchar) &&
+ exp.e2.type.ty != tb1next.ty &&
+ exp.e2.implicitConvTo(Type.tdchar))
+ {
+ // Append dchar to char[] or wchar[]
+ exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar));
+
+ /* Do not allow appending wchar to char[] because if wchar happens
+ * to be a surrogate pair, nothing good can result.
+ */
+ }
+ else
+ {
+ // Try alias this on first operand
+ static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc)
+ {
+ AggregateDeclaration ad1 = isAggregate(exp.e1.type);
+ if (!ad1 || !ad1.aliasthis)
+ return null;
+
+ /* Rewrite (e1 op e2) as:
+ * (e1.aliasthis op e2)
+ */
+ if (isRecursiveAliasThis(exp.att1, exp.e1.type))
+ return null;
+ //printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
+ Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
+ BinExp be = cast(BinExp)exp.copy();
+ be.e1 = e1;
+ return be.trySemantic(sc);
+ }
+
+ // Try alias this on second operand
+ static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc)
+ {
+ AggregateDeclaration ad2 = isAggregate(exp.e2.type);
+ if (!ad2 || !ad2.aliasthis)
+ return null;
+ /* Rewrite (e1 op e2) as:
+ * (e1 op e2.aliasthis)
+ */
+ if (isRecursiveAliasThis(exp.att2, exp.e2.type))
+ return null;
+ //printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
+ Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
+ BinExp be = cast(BinExp)exp.copy();
+ be.e2 = e2;
+ return be.trySemantic(sc);
+ }
+
+ Laliasthis:
+ result = tryAliasThisForLhs(exp, sc);
+ if (result)
+ return;
+
+ result = tryAliasThisForRhs(exp, sc);
+ if (result)
+ return;
+
+ exp.error("cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars());
+ return setError();
+ }
+
+ if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc))
+ return setError();
+
+ exp.type = exp.e1.type;
+ auto res = exp.reorderSettingAAElem(sc);
+ if ((exp.op == TOK.concatenateElemAssign || exp.op == TOK.concatenateDcharAssign) &&
+ global.params.useDIP1000 == FeatureState.enabled)
+ checkAssignEscape(sc, res, false);
+ result = res;
+ }
+
+ override void visit(AddExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("AddExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ Type tb1 = exp.e1.type.toBasetype();
+ Type tb2 = exp.e2.type.toBasetype();
+
+ bool err = false;
+ if (tb1.ty == Tdelegate || tb1.isPtrToFunction())
+ {
+ err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc);
+ }
+ if (tb2.ty == Tdelegate || tb2.isPtrToFunction())
+ {
+ err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc);
+ }
+ if (err)
+ return setError();
+
+ if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral())
+ {
+ result = scaleFactor(exp, sc);
+ return;
+ }
+
+ if (tb1.ty == Tpointer && tb2.ty == Tpointer)
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type tb = exp.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ result = arrayOpInvalidError(exp);
+ return;
+ }
+ result = exp;
+ return;
+ }
+
+ tb1 = exp.e1.type.toBasetype();
+ if (!target.isVectorOpSupported(tb1, exp.op, tb2))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal()))
+ {
+ switch (exp.type.toBasetype().ty)
+ {
+ case Tfloat32:
+ case Timaginary32:
+ exp.type = Type.tcomplex32;
+ break;
+
+ case Tfloat64:
+ case Timaginary64:
+ exp.type = Type.tcomplex64;
+ break;
+
+ case Tfloat80:
+ case Timaginary80:
+ exp.type = Type.tcomplex80;
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ result = exp;
+ }
+
+ override void visit(MinExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("MinExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ Type t1 = exp.e1.type.toBasetype();
+ Type t2 = exp.e2.type.toBasetype();
+
+ bool err = false;
+ if (t1.ty == Tdelegate || t1.isPtrToFunction())
+ {
+ err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc);
+ }
+ if (t2.ty == Tdelegate || t2.isPtrToFunction())
+ {
+ err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc);
+ }
+ if (err)
+ return setError();
+
+ if (t1.ty == Tpointer)
+ {
+ if (t2.ty == Tpointer)
+ {
+ // https://dlang.org/spec/expression.html#add_expressions
+ // "If both operands are pointers, and the operator is -, the pointers are
+ // subtracted and the result is divided by the size of the type pointed to
+ // by the operands. It is an error if the pointers point to different types."
+ Type p1 = t1.nextOf();
+ Type p2 = t2.nextOf();
+
+ if (!p1.equivalent(p2))
+ {
+ // Deprecation to remain for at least a year, after which this should be
+ // changed to an error
+ // See https://github.com/dlang/dmd/pull/7332
+ deprecation(exp.loc,
+ "cannot subtract pointers to different types: `%s` and `%s`.",
+ t1.toChars(), t2.toChars());
+ }
+
+ // Need to divide the result by the stride
+ // Replace (ptr - ptr) with (ptr - ptr) / stride
+ d_int64 stride;
+
+ // make sure pointer types are compatible
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ exp.type = Type.tptrdiff_t;
+ stride = t2.nextOf().size();
+ if (stride == 0)
+ {
+ e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
+ }
+ else
+ {
+ e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t));
+ e.type = Type.tptrdiff_t;
+ }
+ }
+ else if (t2.isintegral())
+ e = scaleFactor(exp, sc);
+ else
+ {
+ exp.error("can't subtract `%s` from pointer", t2.toChars());
+ e = ErrorExp.get();
+ }
+ result = e;
+ return;
+ }
+ if (t2.ty == Tpointer)
+ {
+ exp.type = exp.e2.type;
+ exp.error("can't subtract pointer from `%s`", exp.e1.type.toChars());
+ return setError();
+ }
+
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type tb = exp.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ result = arrayOpInvalidError(exp);
+ return;
+ }
+ result = exp;
+ return;
+ }
+
+ t1 = exp.e1.type.toBasetype();
+ t2 = exp.e2.type.toBasetype();
+ if (!target.isVectorOpSupported(t1, exp.op, t2))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal()))
+ {
+ switch (exp.type.ty)
+ {
+ case Tfloat32:
+ case Timaginary32:
+ exp.type = Type.tcomplex32;
+ break;
+
+ case Tfloat64:
+ case Timaginary64:
+ exp.type = Type.tcomplex64;
+ break;
+
+ case Tfloat80:
+ case Timaginary80:
+ exp.type = Type.tcomplex80;
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ result = exp;
+ return;
+ }
+
+ override void visit(CatExp exp)
+ {
+ // https://dlang.org/spec/expression.html#cat_expressions
+ //printf("CatExp.semantic() %s\n", toChars());
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ Type tb1 = exp.e1.type.toBasetype();
+ Type tb2 = exp.e2.type.toBasetype();
+
+ auto f1 = checkNonAssignmentArrayOp(exp.e1);
+ auto f2 = checkNonAssignmentArrayOp(exp.e2);
+ if (f1 || f2)
+ return setError();
+
+ Type tb1next = tb1.nextOf();
+ Type tb2next = tb2.nextOf();
+
+ // Check for: array ~ array
+ if (tb1next && tb2next && (tb1next.implicitConvTo(tb2next) >= MATCH.constant || tb2next.implicitConvTo(tb1next) >= MATCH.constant || exp.e1.op == TOK.arrayLiteral && exp.e1.implicitConvTo(tb2) || exp.e2.op == TOK.arrayLiteral && exp.e2.implicitConvTo(tb1)))
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=9248
+ * Here to avoid the case of:
+ * void*[] a = [cast(void*)1];
+ * void*[] b = [cast(void*)2];
+ * a ~ b;
+ * becoming:
+ * a ~ [cast(void*)b];
+ */
+
+ /* https://issues.dlang.org/show_bug.cgi?id=14682
+ * Also to avoid the case of:
+ * int[][] a;
+ * a ~ [];
+ * becoming:
+ * a ~ cast(int[])[];
+ */
+ goto Lpeer;
+ }
+
+ // Check for: array ~ element
+ if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
+ {
+ if (exp.e1.op == TOK.arrayLiteral)
+ {
+ exp.e2 = doCopyOrMove(sc, exp.e2);
+ // https://issues.dlang.org/show_bug.cgi?id=14686
+ // Postblit call appears in AST, and this is
+ // finally translated to an ArrayLiteralExp in below optimize().
+ }
+ else if (exp.e1.op == TOK.string_)
+ {
+ // No postblit call exists on character (integer) value.
+ }
+ else
+ {
+ if (exp.e2.checkPostblit(sc, tb2))
+ return setError();
+ // Postblit call will be done in runtime helper function
+ }
+
+ if (exp.e1.op == TOK.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
+ {
+ exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf());
+ exp.type = tb2.arrayOf();
+ goto L2elem;
+ }
+ if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert)
+ {
+ exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
+ exp.type = tb1next.arrayOf();
+ L2elem:
+ if (tb2.ty == Tarray || tb2.ty == Tsarray)
+ {
+ // Make e2 into [e2]
+ exp.e2 = new ArrayLiteralExp(exp.e2.loc, exp.type, exp.e2);
+ }
+ else if (checkNewEscape(sc, exp.e2, false))
+ return setError();
+ result = exp.optimize(WANTvalue);
+ return;
+ }
+ }
+ // Check for: element ~ array
+ if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
+ {
+ if (exp.e2.op == TOK.arrayLiteral)
+ {
+ exp.e1 = doCopyOrMove(sc, exp.e1);
+ }
+ else if (exp.e2.op == TOK.string_)
+ {
+ }
+ else
+ {
+ if (exp.e1.checkPostblit(sc, tb1))
+ return setError();
+ }
+
+ if (exp.e2.op == TOK.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
+ {
+ exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf());
+ exp.type = tb1.arrayOf();
+ goto L1elem;
+ }
+ if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert)
+ {
+ exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
+ exp.type = tb2next.arrayOf();
+ L1elem:
+ if (tb1.ty == Tarray || tb1.ty == Tsarray)
+ {
+ // Make e1 into [e1]
+ exp.e1 = new ArrayLiteralExp(exp.e1.loc, exp.type, exp.e1);
+ }
+ else if (checkNewEscape(sc, exp.e1, false))
+ return setError();
+ result = exp.optimize(WANTvalue);
+ return;
+ }
+ }
+
+ Lpeer:
+ if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod))
+ {
+ Type t1 = tb1next.mutableOf().constOf().arrayOf();
+ Type t2 = tb2next.mutableOf().constOf().arrayOf();
+ if (exp.e1.op == TOK.string_ && !(cast(StringExp)exp.e1).committed)
+ exp.e1.type = t1;
+ else
+ exp.e1 = exp.e1.castTo(sc, t1);
+ if (exp.e2.op == TOK.string_ && !(cast(StringExp)exp.e2).committed)
+ exp.e2.type = t2;
+ else
+ exp.e2 = exp.e2.castTo(sc, t2);
+ }
+
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ exp.type = exp.type.toHeadMutable();
+
+ Type tb = exp.type.toBasetype();
+ if (tb.ty == Tsarray)
+ exp.type = tb.nextOf().arrayOf();
+ if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
+ {
+ exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
+ }
+ if (Type tbn = tb.nextOf())
+ {
+ if (exp.checkPostblit(sc, tbn))
+ return setError();
+ }
+ Type t1 = exp.e1.type.toBasetype();
+ Type t2 = exp.e2.type.toBasetype();
+ if ((t1.ty == Tarray || t1.ty == Tsarray) &&
+ (t2.ty == Tarray || t2.ty == Tsarray))
+ {
+ // Normalize to ArrayLiteralExp or StringExp as far as possible
+ e = exp.optimize(WANTvalue);
+ }
+ else
+ {
+ //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
+ result = exp.incompatibleTypes();
+ return;
+ }
+
+ result = e;
+ }
+
+ override void visit(MulExp exp)
+ {
+ version (none)
+ {
+ printf("MulExp::semantic() %s\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type tb = exp.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ result = arrayOpInvalidError(exp);
+ return;
+ }
+ result = exp;
+ return;
+ }
+
+ if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
+ return setError();
+
+ if (exp.type.isfloating())
+ {
+ Type t1 = exp.e1.type;
+ Type t2 = exp.e2.type;
+
+ if (t1.isreal())
+ {
+ exp.type = t2;
+ }
+ else if (t2.isreal())
+ {
+ exp.type = t1;
+ }
+ else if (t1.isimaginary())
+ {
+ if (t2.isimaginary())
+ {
+ switch (t1.toBasetype().ty)
+ {
+ case Timaginary32:
+ exp.type = Type.tfloat32;
+ break;
+
+ case Timaginary64:
+ exp.type = Type.tfloat64;
+ break;
+
+ case Timaginary80:
+ exp.type = Type.tfloat80;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ // iy * iv = -yv
+ exp.e1.type = exp.type;
+ exp.e2.type = exp.type;
+ e = new NegExp(exp.loc, exp);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ else
+ exp.type = t2; // t2 is complex
+ }
+ else if (t2.isimaginary())
+ {
+ exp.type = t1; // t1 is complex
+ }
+ }
+ else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ result = exp;
+ }
+
+ override void visit(DivExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type tb = exp.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ result = arrayOpInvalidError(exp);
+ return;
+ }
+ result = exp;
+ return;
+ }
+
+ if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
+ return setError();
+
+ if (exp.type.isfloating())
+ {
+ Type t1 = exp.e1.type;
+ Type t2 = exp.e2.type;
+
+ if (t1.isreal())
+ {
+ exp.type = t2;
+ if (t2.isimaginary())
+ {
+ // x/iv = i(-x/v)
+ exp.e2.type = t1;
+ e = new NegExp(exp.loc, exp);
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+ }
+ else if (t2.isreal())
+ {
+ exp.type = t1;
+ }
+ else if (t1.isimaginary())
+ {
+ if (t2.isimaginary())
+ {
+ switch (t1.toBasetype().ty)
+ {
+ case Timaginary32:
+ exp.type = Type.tfloat32;
+ break;
+
+ case Timaginary64:
+ exp.type = Type.tfloat64;
+ break;
+
+ case Timaginary80:
+ exp.type = Type.tfloat80;
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ else
+ exp.type = t2; // t2 is complex
+ }
+ else if (t2.isimaginary())
+ {
+ exp.type = t1; // t1 is complex
+ }
+ }
+ else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ result = exp;
+ }
+
+ override void visit(ModExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type tb = exp.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ result = arrayOpInvalidError(exp);
+ return;
+ }
+ result = exp;
+ return;
+ }
+ if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+
+ if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
+ return setError();
+
+ if (exp.type.isfloating())
+ {
+ exp.type = exp.e1.type;
+ if (exp.e2.type.iscomplex())
+ {
+ exp.error("cannot perform modulo complex arithmetic");
+ return setError();
+ }
+ }
+ result = exp;
+ }
+
+ override void visit(PowExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ //printf("PowExp::semantic() %s\n", toChars());
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type tb = exp.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ result = arrayOpInvalidError(exp);
+ return;
+ }
+ result = exp;
+ return;
+ }
+
+ if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
+ return setError();
+
+ if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+
+ // First, attempt to fold the expression.
+ e = exp.optimize(WANTvalue);
+ if (e.op != TOK.pow)
+ {
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+
+ Module mmath = loadStdMath();
+ if (!mmath)
+ {
+ e.error("`%s` requires `std.math` for `^^` operators", e.toChars());
+ return setError();
+ }
+ e = new ScopeExp(exp.loc, mmath);
+
+ if (exp.e2.op == TOK.float64 && exp.e2.toReal() == CTFloat.half)
+ {
+ // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
+ e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1);
+ }
+ else
+ {
+ // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
+ e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2);
+ }
+ e = e.expressionSemantic(sc);
+ result = e;
+ return;
+ }
+
+ override void visit(ShlExp exp)
+ {
+ //printf("ShlExp::semantic(), type = %p\n", type);
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
+ return setError();
+
+ if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ exp.e1 = integralPromotions(exp.e1, sc);
+ if (exp.e2.type.toBasetype().ty != Tvector)
+ exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
+
+ exp.type = exp.e1.type;
+ result = exp;
+ }
+
+ override void visit(ShrExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
+ return setError();
+
+ if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ exp.e1 = integralPromotions(exp.e1, sc);
+ if (exp.e2.type.toBasetype().ty != Tvector)
+ exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
+
+ exp.type = exp.e1.type;
+ result = exp;
+ }
+
+ override void visit(UshrExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
+ return setError();
+
+ if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ exp.e1 = integralPromotions(exp.e1, sc);
+ if (exp.e2.type.toBasetype().ty != Tvector)
+ exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
+
+ exp.type = exp.e1.type;
+ result = exp;
+ }
+
+ override void visit(AndExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
+ {
+ exp.type = exp.e1.type;
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type tb = exp.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ result = arrayOpInvalidError(exp);
+ return;
+ }
+ result = exp;
+ return;
+ }
+ if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
+ return setError();
+
+ result = exp;
+ }
+
+ override void visit(OrExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
+ {
+ exp.type = exp.e1.type;
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type tb = exp.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ result = arrayOpInvalidError(exp);
+ return;
+ }
+ result = exp;
+ return;
+ }
+ if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
+ return setError();
+
+ result = exp;
+ }
+
+ override void visit(XorExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
+ {
+ exp.type = exp.e1.type;
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ Type tb = exp.type.toBasetype();
+ if (tb.ty == Tarray || tb.ty == Tsarray)
+ {
+ if (!isArrayOpValid(exp))
+ {
+ result = arrayOpInvalidError(exp);
+ return;
+ }
+ result = exp;
+ return;
+ }
+ if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
+ return setError();
+
+ result = exp;
+ }
+
+ override void visit(LogicalExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("LogicalExp::semantic() %s\n", exp.toChars());
+ }
+
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ exp.setNoderefOperands();
+
+ Expression e1x = exp.e1.expressionSemantic(sc);
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (e1x.op == TOK.type)
+ e1x = resolveAliasThis(sc, e1x);
+
+ e1x = resolveProperties(sc, e1x);
+ e1x = e1x.toBoolean(sc);
+
+ if (sc.flags & SCOPE.condition)
+ {
+ /* If in static if, don't evaluate e2 if we don't have to.
+ */
+ e1x = e1x.optimize(WANTvalue);
+ if (e1x.isBool(exp.op == TOK.orOr))
+ {
+ result = IntegerExp.createBool(exp.op == TOK.orOr);
+ return;
+ }
+ }
+
+ CtorFlow ctorflow = sc.ctorflow.clone();
+ Expression e2x = exp.e2.expressionSemantic(sc);
+ sc.merge(exp.loc, ctorflow);
+ ctorflow.freeFieldinit();
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (e2x.op == TOK.type)
+ e2x = resolveAliasThis(sc, e2x);
+
+ e2x = resolveProperties(sc, e2x);
+
+ auto f1 = checkNonAssignmentArrayOp(e1x);
+ auto f2 = checkNonAssignmentArrayOp(e2x);
+ if (f1 || f2)
+ return setError();
+
+ // Unless the right operand is 'void', the expression is converted to 'bool'.
+ if (e2x.type.ty != Tvoid)
+ e2x = e2x.toBoolean(sc);
+
+ if (e2x.op == TOK.type || e2x.op == TOK.scope_)
+ {
+ exp.error("`%s` is not an expression", exp.e2.toChars());
+ return setError();
+ }
+ if (e1x.op == TOK.error || e1x.type.ty == Tnoreturn)
+ {
+ result = e1x;
+ return;
+ }
+ if (e2x.op == TOK.error)
+ {
+ result = e2x;
+ return;
+ }
+
+ // The result type is 'bool', unless the right operand has type 'void'.
+ if (e2x.type.ty == Tvoid)
+ exp.type = Type.tvoid;
+ else
+ exp.type = Type.tbool;
+
+ exp.e1 = e1x;
+ exp.e2 = e2x;
+ result = exp;
+ }
+
+
+ override void visit(CmpExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("CmpExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ exp.setNoderefOperands();
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Type t1 = exp.e1.type.toBasetype();
+ Type t2 = exp.e2.type.toBasetype();
+ if (t1.ty == Tclass && exp.e2.op == TOK.null_ || t2.ty == Tclass && exp.e1.op == TOK.null_)
+ {
+ exp.error("do not use `null` when comparing class types");
+ return setError();
+ }
+
+ TOK cmpop;
+ if (auto e = exp.op_overload(sc, &cmpop))
+ {
+ if (!e.type.isscalar() && e.type.equals(exp.e1.type))
+ {
+ exp.error("recursive `opCmp` expansion");
+ return setError();
+ }
+ if (e.op == TOK.call)
+ {
+ e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
+ e = e.expressionSemantic(sc);
+ }
+ result = e;
+ return;
+ }
+
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ auto f1 = checkNonAssignmentArrayOp(exp.e1);
+ auto f2 = checkNonAssignmentArrayOp(exp.e2);
+ if (f1 || f2)
+ return setError();
+
+ exp.type = Type.tbool;
+
+ // Special handling for array comparisons
+ Expression arrayLowering = null;
+ t1 = exp.e1.type.toBasetype();
+ t2 = exp.e2.type.toBasetype();
+ if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer))
+ {
+ Type t1next = t1.nextOf();
+ Type t2next = t2.nextOf();
+ if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid))
+ {
+ exp.error("array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars());
+ return setError();
+ }
+ if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray))
+ {
+ if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays"))
+ return setError();
+
+ // Lower to object.__cmp(e1, e2)
+ Expression al = new IdentifierExp(exp.loc, Id.empty);
+ al = new DotIdExp(exp.loc, al, Id.object);
+ al = new DotIdExp(exp.loc, al, Id.__cmp);
+ al = al.expressionSemantic(sc);
+
+ auto arguments = new Expressions(2);
+ (*arguments)[0] = exp.e1;
+ (*arguments)[1] = exp.e2;
+
+ al = new CallExp(exp.loc, al, arguments);
+ al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0);
+
+ arrayLowering = al;
+ }
+ }
+ else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass))
+ {
+ if (t2.ty == Tstruct)
+ exp.error("need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars());
+ else
+ exp.error("need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
+ return setError();
+ }
+ else if (t1.iscomplex() || t2.iscomplex())
+ {
+ exp.error("compare not defined for complex operands");
+ return setError();
+ }
+ else if (t1.ty == Taarray || t2.ty == Taarray)
+ {
+ exp.error("`%s` is not defined for associative arrays", Token.toChars(exp.op));
+ return setError();
+ }
+ else if (!target.isVectorOpSupported(t1, exp.op, t2))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+ else
+ {
+ bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc);
+ bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc);
+ if (r1 || r2)
+ return setError();
+ }
+
+ //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
+ if (arrayLowering)
+ {
+ arrayLowering = arrayLowering.expressionSemantic(sc);
+ result = arrayLowering;
+ return;
+ }
+ result = exp;
+ return;
+ }
+
+ override void visit(InExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (Expression ex = binSemanticProp(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+ Expression e = exp.op_overload(sc);
+ if (e)
+ {
+ result = e;
+ return;
+ }
+
+ Type t2b = exp.e2.type.toBasetype();
+ switch (t2b.ty)
+ {
+ case Taarray:
+ {
+ TypeAArray ta = cast(TypeAArray)t2b;
+
+ // Special handling for array keys
+ if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index))
+ {
+ // Convert key to type of key
+ exp.e1 = exp.e1.implicitCastTo(sc, ta.index);
+ }
+
+ semanticTypeInfo(sc, ta.index);
+
+ // Return type is pointer to value
+ exp.type = ta.nextOf().pointerTo();
+ break;
+ }
+
+ case Terror:
+ return setError();
+
+ default:
+ result = exp.incompatibleTypes();
+ return;
+ }
+ result = exp;
+ }
+
+ override void visit(RemoveExp e)
+ {
+ if (Expression ex = binSemantic(e, sc))
+ {
+ result = ex;
+ return;
+ }
+ result = e;
+ }
+
+ override void visit(EqualExp exp)
+ {
+ //printf("EqualExp::semantic('%s')\n", exp.toChars());
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ exp.setNoderefOperands();
+
+ if (auto e = binSemanticProp(exp, sc))
+ {
+ result = e;
+ return;
+ }
+ if (exp.e1.op == TOK.type || exp.e2.op == TOK.type)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=12520
+ * empty tuples are represented as types so special cases are added
+ * so that they can be compared for equality with tuples of values.
+ */
+ static auto extractTypeTupAndExpTup(Expression e)
+ {
+ static struct Result { bool ttEmpty; bool te; }
+ auto tt = e.op == TOK.type ? e.isTypeExp().type.isTypeTuple() : null;
+ return Result(tt && (!tt.arguments || !tt.arguments.dim), e.isTupleExp() !is null);
+ }
+ auto tups1 = extractTypeTupAndExpTup(exp.e1);
+ auto tups2 = extractTypeTupAndExpTup(exp.e2);
+ // AliasSeq!() == AliasSeq!(<at least a value>)
+ if (tups1.ttEmpty && tups2.te)
+ {
+ result = IntegerExp.createBool(exp.op != TOK.equal);
+ return;
+ }
+ // AliasSeq!(<at least a value>) == AliasSeq!()
+ else if (tups1.te && tups2.ttEmpty)
+ {
+ result = IntegerExp.createBool(exp.op != TOK.equal);
+ return;
+ }
+ // AliasSeq!() == AliasSeq!()
+ else if (tups1.ttEmpty && tups2.ttEmpty)
+ {
+ result = IntegerExp.createBool(exp.op == TOK.equal);
+ return;
+ }
+ // otherwise, two types are really not comparable
+ result = exp.incompatibleTypes();
+ return;
+ }
+
+ {
+ auto t1 = exp.e1.type;
+ auto t2 = exp.e2.type;
+ if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2))
+ exp.error("Comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
+ t1.toChars(), t2.toChars());
+ }
+
+ /* Before checking for operator overloading, check to see if we're
+ * comparing the addresses of two statics. If so, we can just see
+ * if they are the same symbol.
+ */
+ if (exp.e1.op == TOK.address && exp.e2.op == TOK.address)
+ {
+ AddrExp ae1 = cast(AddrExp)exp.e1;
+ AddrExp ae2 = cast(AddrExp)exp.e2;
+ if (ae1.e1.op == TOK.variable && ae2.e1.op == TOK.variable)
+ {
+ VarExp ve1 = cast(VarExp)ae1.e1;
+ VarExp ve2 = cast(VarExp)ae2.e1;
+ if (ve1.var == ve2.var)
+ {
+ // They are the same, result is 'true' for ==, 'false' for !=
+ result = IntegerExp.createBool(exp.op == TOK.equal);
+ return;
+ }
+ }
+ }
+
+ Type t1 = exp.e1.type.toBasetype();
+ Type t2 = exp.e2.type.toBasetype();
+
+ // Indicates whether the comparison of the 2 specified array types
+ // requires an object.__equals() lowering.
+ static bool needsDirectEq(Type t1, Type t2, Scope* sc)
+ {
+ Type t1n = t1.nextOf().toBasetype();
+ Type t2n = t2.nextOf().toBasetype();
+ if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) ||
+ (t1n.ty == Tvoid || t2n.ty == Tvoid))
+ {
+ return false;
+ }
+ if (t1n.constOf() != t2n.constOf())
+ return true;
+
+ Type t = t1n;
+ while (t.toBasetype().nextOf())
+ t = t.nextOf().toBasetype();
+ if (auto ts = t.isTypeStruct())
+ {
+ // semanticTypeInfo() makes sure hasIdentityEquals has been computed
+ if (global.params.useTypeInfo && Type.dtypeinfo)
+ semanticTypeInfo(sc, ts);
+
+ return ts.sym.hasIdentityEquals; // has custom opEquals
+ }
+
+ return false;
+ }
+
+ if (auto e = exp.op_overload(sc))
+ {
+ result = e;
+ return;
+ }
+
+
+ const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) &&
+ (t2.ty == Tarray || t2.ty == Tsarray);
+ const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc);
+
+ if (!needsArrayLowering)
+ {
+ if (auto e = typeCombine(exp, sc))
+ {
+ result = e;
+ return;
+ }
+ }
+
+ auto f1 = checkNonAssignmentArrayOp(exp.e1);
+ auto f2 = checkNonAssignmentArrayOp(exp.e2);
+ if (f1 || f2)
+ return setError();
+
+ exp.type = Type.tbool;
+
+ if (!isArrayComparison)
+ {
+ if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
+ {
+ // Cast both to complex
+ exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
+ exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
+ }
+ }
+
+ // lower some array comparisons to object.__equals(e1, e2)
+ if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray))
+ {
+ //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
+
+ if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
+ return setError();
+
+ Expression __equals = new IdentifierExp(exp.loc, Id.empty);
+ Identifier id = Identifier.idPool("__equals");
+ __equals = new DotIdExp(exp.loc, __equals, Id.object);
+ __equals = new DotIdExp(exp.loc, __equals, id);
+
+ auto arguments = new Expressions(2);
+ (*arguments)[0] = exp.e1;
+ (*arguments)[1] = exp.e2;
+
+ __equals = new CallExp(exp.loc, __equals, arguments);
+ if (exp.op == TOK.notEqual)
+ {
+ __equals = new NotExp(exp.loc, __equals);
+ }
+ __equals = __equals.trySemantic(sc); // for better error message
+ if (!__equals)
+ {
+ exp.error("incompatible types for array comparison: `%s` and `%s`",
+ exp.e1.type.toChars(), exp.e2.type.toChars());
+ __equals = ErrorExp.get();
+ }
+
+ result = __equals;
+ return;
+ }
+
+ if (exp.e1.type.toBasetype().ty == Taarray)
+ semanticTypeInfo(sc, exp.e1.type.toBasetype());
+
+
+ if (!target.isVectorOpSupported(t1, exp.op, t2))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+
+ result = exp;
+ }
+
+ override void visit(IdentityExp exp)
+ {
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ exp.setNoderefOperands();
+
+ if (auto e = binSemanticProp(exp, sc))
+ {
+ result = e;
+ return;
+ }
+
+ if (auto e = typeCombine(exp, sc))
+ {
+ result = e;
+ return;
+ }
+
+ auto f1 = checkNonAssignmentArrayOp(exp.e1);
+ auto f2 = checkNonAssignmentArrayOp(exp.e2);
+ if (f1 || f2)
+ return setError();
+
+ if (exp.e1.op == TOK.type || exp.e2.op == TOK.type)
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+
+ exp.type = Type.tbool;
+
+ if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
+ {
+ // Cast both to complex
+ exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
+ exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
+ }
+
+ auto tb1 = exp.e1.type.toBasetype();
+ auto tb2 = exp.e2.type.toBasetype();
+ if (!target.isVectorOpSupported(tb1, exp.op, tb2))
+ {
+ result = exp.incompatibleTypes();
+ return;
+ }
+
+ if (exp.e1.op == TOK.call)
+ exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc);
+ if (exp.e2.op == TOK.call)
+ exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
+
+ if (exp.e1.type.toBasetype().ty == Tsarray ||
+ exp.e2.type.toBasetype().ty == Tsarray)
+ exp.deprecation("identity comparison of static arrays "
+ ~ "implicitly coerces them to slices, "
+ ~ "which are compared by reference");
+
+ result = exp;
+ }
+
+ override void visit(CondExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("CondExp::semantic('%s')\n", exp.toChars());
+ }
+ if (exp.type)
+ {
+ result = exp;
+ return;
+ }
+
+ if (exp.econd.op == TOK.dotIdentifier)
+ (cast(DotIdExp)exp.econd).noderef = true;
+
+ Expression ec = exp.econd.expressionSemantic(sc);
+ ec = resolveProperties(sc, ec);
+ ec = ec.toBoolean(sc);
+
+ CtorFlow ctorflow_root = sc.ctorflow.clone();
+ Expression e1x = exp.e1.expressionSemantic(sc);
+ e1x = resolveProperties(sc, e1x);
+
+ CtorFlow ctorflow1 = sc.ctorflow;
+ sc.ctorflow = ctorflow_root;
+ Expression e2x = exp.e2.expressionSemantic(sc);
+ e2x = resolveProperties(sc, e2x);
+
+ sc.merge(exp.loc, ctorflow1);
+ ctorflow1.freeFieldinit();
+
+ if (ec.op == TOK.error)
+ {
+ result = ec;
+ return;
+ }
+ if (ec.type == Type.terror)
+ return setError();
+ exp.econd = ec;
+
+ if (e1x.op == TOK.error)
+ {
+ result = e1x;
+ return;
+ }
+ if (e1x.type == Type.terror)
+ return setError();
+ exp.e1 = e1x;
+
+ if (e2x.op == TOK.error)
+ {
+ result = e2x;
+ return;
+ }
+ if (e2x.type == Type.terror)
+ return setError();
+ exp.e2 = e2x;
+
+ auto f0 = checkNonAssignmentArrayOp(exp.econd);
+ auto f1 = checkNonAssignmentArrayOp(exp.e1);
+ auto f2 = checkNonAssignmentArrayOp(exp.e2);
+ if (f0 || f1 || f2)
+ return setError();
+
+ Type t1 = exp.e1.type;
+ Type t2 = exp.e2.type;
+ if (t1.ty == Tnoreturn)
+ {
+ exp.type = t2;
+ }
+ else if (t2.ty == Tnoreturn)
+ {
+ exp.type = t1;
+ }
+ // If either operand is void the result is void, we have to cast both
+ // the expression to void so that we explicitly discard the expression
+ // value if any
+ // https://issues.dlang.org/show_bug.cgi?id=16598
+ else if (t1.ty == Tvoid || t2.ty == Tvoid)
+ {
+ exp.type = Type.tvoid;
+ exp.e1 = exp.e1.castTo(sc, exp.type);
+ exp.e2 = exp.e2.castTo(sc, exp.type);
+ }
+ else if (t1 == t2)
+ exp.type = t1;
+ else
+ {
+ if (Expression ex = typeCombine(exp, sc))
+ {
+ result = ex;
+ return;
+ }
+
+ switch (exp.e1.type.toBasetype().ty)
+ {
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ exp.e2 = exp.e2.castTo(sc, exp.e1.type);
+ break;
+ default:
+ break;
+ }
+ switch (exp.e2.type.toBasetype().ty)
+ {
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ exp.e1 = exp.e1.castTo(sc, exp.e2.type);
+ break;
+ default:
+ break;
+ }
+ if (exp.type.toBasetype().ty == Tarray)
+ {
+ exp.e1 = exp.e1.castTo(sc, exp.type);
+ exp.e2 = exp.e2.castTo(sc, exp.type);
+ }
+ }
+ exp.type = exp.type.merge2();
+ version (none)
+ {
+ printf("res: %s\n", exp.type.toChars());
+ printf("e1 : %s\n", exp.e1.type.toChars());
+ printf("e2 : %s\n", exp.e2.type.toChars());
+ }
+
+ /* https://issues.dlang.org/show_bug.cgi?id=14696
+ * If either e1 or e2 contain temporaries which need dtor,
+ * make them conditional.
+ * Rewrite:
+ * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
+ * to:
+ * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
+ * and replace edtors of __tmp1 and __tmp2 with:
+ * __tmp1.edtor --> __cond && __tmp1.dtor()
+ * __tmp2.edtor --> __cond || __tmp2.dtor()
+ */
+ exp.hookDtors(sc);
+
+ result = exp;
+ }
+
+ override void visit(GenericExp exp)
+ {
+ static if (LOGSEMANTIC)
+ {
+ printf("GenericExp::semantic('%s')\n", exp.toChars());
+ }
+ // C11 6.5.1.1 Generic Selection
+
+ auto ec = exp.cntlExp.expressionSemantic(sc);
+ bool errors = ec.isErrorExp() !is null;
+ auto tc = ec.type;
+
+ auto types = (*exp.types)[];
+ foreach (i, ref t; types)
+ {
+ if (!t)
+ continue; // `default:` case
+ t = t.typeSemantic(ec.loc, sc);
+ if (t.isTypeError())
+ {
+ errors = true;
+ continue;
+ }
+
+ /* C11 6.5.1-2 duplicate check
+ */
+ /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
+ * C target, a long may have the same type as `int` in the D type system.
+ * So, skip checks when this may be the case. Later pick the first match
+ */
+ if (
+ (t.ty == Tint32 || t.ty == Tuns32) && target.c.longsize == 4 ||
+ (t.ty == Tint64 || t.ty == Tuns64) && target.c.longsize == 8 ||
+ (t.ty == Tfloat64 || t.ty == Timaginary64 || t.ty == Tcomplex64) && target.c.long_doublesize == 8
+ )
+ continue;
+
+ foreach (t2; types[0 .. i])
+ {
+ if (t2 && t2.equals(t))
+ {
+ error(ec.loc, "generic association type `%s` can only appear once", t.toChars());
+ errors = true;
+ break;
+ }
+ }
+ }
+
+ auto exps = (*exp.exps)[];
+ foreach (ref e; exps)
+ {
+ e = e.expressionSemantic(sc);
+ if (e.isErrorExp())
+ errors = true;
+ }
+
+ if (errors)
+ return setError();
+
+ enum size_t None = ~0;
+ size_t imatch = None;
+ size_t idefault = None;
+ foreach (const i, t; types)
+ {
+ if (t)
+ {
+ /* if tc is compatible with t, it's a match
+ * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
+ */
+ if (tc.equals(t))
+ {
+ assert(imatch == None);
+ imatch = i;
+ break; // pick first match
+ }
+ }
+ else
+ idefault = i; // multiple defaults are not allowed, and are caught by cparse
+ }
+
+ if (imatch == None)
+ imatch = idefault;
+ if (imatch == None)
+ {
+ error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars());
+ return setError();
+ }
+
+ result = exps[imatch];
+ }
+
+ override void visit(FileInitExp e)
+ {
+ //printf("FileInitExp::semantic()\n");
+ e.type = Type.tstring;
+ result = e;
+ }
+
+ override void visit(LineInitExp e)
+ {
+ e.type = Type.tint32;
+ result = e;
+ }
+
+ override void visit(ModuleInitExp e)
+ {
+ //printf("ModuleInitExp::semantic()\n");
+ e.type = Type.tstring;
+ result = e;
+ }
+
+ override void visit(FuncInitExp e)
+ {
+ //printf("FuncInitExp::semantic()\n");
+ e.type = Type.tstring;
+ if (sc.func)
+ {
+ result = e.resolveLoc(Loc.initial, sc);
+ return;
+ }
+ result = e;
+ }
+
+ override void visit(PrettyFuncInitExp e)
+ {
+ //printf("PrettyFuncInitExp::semantic()\n");
+ e.type = Type.tstring;
+ if (sc.func)
+ {
+ result = e.resolveLoc(Loc.initial, sc);
+ return;
+ }
+
+ result = e;
+ }
+}
+
+/**********************************
+ * Try to run semantic routines.
+ * If they fail, return NULL.
+ */
+Expression trySemantic(Expression exp, Scope* sc)
+{
+ //printf("+trySemantic(%s)\n", exp.toChars());
+ uint errors = global.startGagging();
+ Expression e = expressionSemantic(exp, sc);
+ if (global.endGagging(errors))
+ {
+ e = null;
+ }
+ //printf("-trySemantic(%s)\n", exp.toChars());
+ return e;
+}
+
+/**************************
+ * Helper function for easy error propagation.
+ * If error occurs, returns ErrorExp. Otherwise returns NULL.
+ */
+Expression unaSemantic(UnaExp e, Scope* sc)
+{
+ static if (LOGSEMANTIC)
+ {
+ printf("UnaExp::semantic('%s')\n", e.toChars());
+ }
+ Expression e1x = e.e1.expressionSemantic(sc);
+ if (e1x.op == TOK.error)
+ return e1x;
+ e.e1 = e1x;
+ return null;
+}
+
+/**************************
+ * Helper function for easy error propagation.
+ * If error occurs, returns ErrorExp. Otherwise returns NULL.
+ */
+Expression binSemantic(BinExp e, Scope* sc)
+{
+ static if (LOGSEMANTIC)
+ {
+ printf("BinExp::semantic('%s')\n", e.toChars());
+ }
+ Expression e1x = e.e1.expressionSemantic(sc);
+ Expression e2x = e.e2.expressionSemantic(sc);
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (e1x.op == TOK.type)
+ e1x = resolveAliasThis(sc, e1x);
+ if (e2x.op == TOK.type)
+ e2x = resolveAliasThis(sc, e2x);
+
+ if (e1x.op == TOK.error)
+ return e1x;
+ if (e2x.op == TOK.error)
+ return e2x;
+ e.e1 = e1x;
+ e.e2 = e2x;
+ return null;
+}
+
+Expression binSemanticProp(BinExp e, Scope* sc)
+{
+ if (Expression ex = binSemantic(e, sc))
+ return ex;
+ Expression e1x = resolveProperties(sc, e.e1);
+ Expression e2x = resolveProperties(sc, e.e2);
+ if (e1x.op == TOK.error)
+ return e1x;
+ if (e2x.op == TOK.error)
+ return e2x;
+ e.e1 = e1x;
+ e.e2 = e2x;
+ return null;
+}
+
+// entrypoint for semantic ExpressionSemanticVisitor
+extern (C++) Expression expressionSemantic(Expression e, Scope* sc)
+{
+ scope v = new ExpressionSemanticVisitor(sc);
+ e.accept(v);
+ return v.result;
+}
+
+Expression semanticX(DotIdExp exp, Scope* sc)
+{
+ //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
+ if (Expression ex = unaSemantic(exp, sc))
+ return ex;
+
+ if (exp.ident == Id._mangleof)
+ {
+ // symbol.mangleof
+ Dsymbol ds;
+ switch (exp.e1.op)
+ {
+ case TOK.scope_:
+ ds = (cast(ScopeExp)exp.e1).sds;
+ goto L1;
+ case TOK.variable:
+ ds = (cast(VarExp)exp.e1).var;
+ goto L1;
+ case TOK.dotVariable:
+ ds = (cast(DotVarExp)exp.e1).var;
+ goto L1;
+ case TOK.overloadSet:
+ ds = (cast(OverExp)exp.e1).vars;
+ goto L1;
+ case TOK.template_:
+ {
+ TemplateExp te = cast(TemplateExp)exp.e1;
+ ds = te.fd ? cast(Dsymbol)te.fd : te.td;
+ }
+ L1:
+ {
+ assert(ds);
+ if (auto f = ds.isFuncDeclaration())
+ {
+ if (f.checkForwardRef(exp.loc))
+ {
+ return ErrorExp.get();
+ }
+ if (f.flags & (FUNCFLAG.purityInprocess | FUNCFLAG.safetyInprocess |
+ FUNCFLAG.nothrowInprocess | FUNCFLAG.nogcInprocess))
+ {
+ f.error(exp.loc, "cannot retrieve its `.mangleof` while inferring attributes");
+ return ErrorExp.get();
+ }
+ }
+ OutBuffer buf;
+ mangleToBuffer(ds, &buf);
+ Expression e = new StringExp(exp.loc, buf.extractSlice());
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (exp.e1.op == TOK.variable && exp.e1.type.toBasetype().ty == Tsarray && exp.ident == Id.length)
+ {
+ // bypass checkPurity
+ return exp.e1.type.dotExp(sc, exp.e1, exp.ident, exp.noderef ? DotExpFlag.noDeref : 0);
+ }
+
+ if (exp.e1.op == TOK.dot)
+ {
+ }
+ else
+ {
+ exp.e1 = resolvePropertiesX(sc, exp.e1);
+ }
+ if (exp.e1.op == TOK.tuple && exp.ident == Id.offsetof)
+ {
+ /* 'distribute' the .offsetof to each of the tuple elements.
+ */
+ TupleExp te = cast(TupleExp)exp.e1;
+ auto exps = new Expressions(te.exps.dim);
+ for (size_t i = 0; i < exps.dim; i++)
+ {
+ Expression e = (*te.exps)[i];
+ e = e.expressionSemantic(sc);
+ e = new DotIdExp(e.loc, e, Id.offsetof);
+ (*exps)[i] = e;
+ }
+ // Don't evaluate te.e0 in runtime
+ Expression e = new TupleExp(exp.loc, null, exps);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ if (exp.e1.op == TOK.tuple && exp.ident == Id.length)
+ {
+ TupleExp te = cast(TupleExp)exp.e1;
+ // Don't evaluate te.e0 in runtime
+ Expression e = new IntegerExp(exp.loc, te.exps.dim, Type.tsize_t);
+ return e;
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=14416
+ // Template has no built-in properties except for 'stringof'.
+ if ((exp.e1.op == TOK.dotTemplateDeclaration || exp.e1.op == TOK.template_) && exp.ident != Id.stringof)
+ {
+ exp.error("template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
+ return ErrorExp.get();
+ }
+ if (!exp.e1.type)
+ {
+ exp.error("expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
+ return ErrorExp.get();
+ }
+
+ return exp;
+}
+
+// Resolve e1.ident without seeing UFCS.
+// If flag == 1, stop "not a property" error and return NULL.
+Expression semanticY(DotIdExp exp, Scope* sc, int flag)
+{
+ //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
+
+ //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
+
+ /* Special case: rewrite this.id and super.id
+ * to be classtype.id and baseclasstype.id
+ * if we have no this pointer.
+ */
+ if ((exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) && !hasThis(sc))
+ {
+ if (AggregateDeclaration ad = sc.getStructClassScope())
+ {
+ if (exp.e1.op == TOK.this_)
+ {
+ exp.e1 = new TypeExp(exp.e1.loc, ad.type);
+ }
+ else
+ {
+ ClassDeclaration cd = ad.isClassDeclaration();
+ if (cd && cd.baseClass)
+ exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
+ }
+ }
+ }
+
+ Expression e = semanticX(exp, sc);
+ if (e != exp)
+ return e;
+
+ Expression eleft;
+ Expression eright;
+ if (exp.e1.op == TOK.dot)
+ {
+ DotExp de = cast(DotExp)exp.e1;
+ eleft = de.e1;
+ eright = de.e2;
+ }
+ else
+ {
+ eleft = null;
+ eright = exp.e1;
+ }
+
+ Type t1b = exp.e1.type.toBasetype();
+
+ if (eright.op == TOK.scope_) // also used for template alias's
+ {
+ ScopeExp ie = cast(ScopeExp)eright;
+
+ int flags = SearchLocalsOnly;
+ /* Disable access to another module's private imports.
+ * The check for 'is sds our current module' is because
+ * the current module should have access to its own imports.
+ */
+ if (ie.sds.isModule() && ie.sds != sc._module)
+ flags |= IgnorePrivateImports;
+ if (sc.flags & SCOPE.ignoresymbolvisibility)
+ flags |= IgnoreSymbolVisibility;
+ Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
+ /* Check for visibility before resolving aliases because public
+ * aliases to private symbols are public.
+ */
+ if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s))
+ {
+ s = null;
+ }
+ if (s)
+ {
+ auto p = s.isPackage();
+ if (p && checkAccess(sc, p))
+ {
+ s = null;
+ }
+ }
+ if (s)
+ {
+ // if 's' is a tuple variable, the tuple is returned.
+ s = s.toAlias();
+
+ exp.checkDeprecated(sc, s);
+ exp.checkDisabled(sc, s);
+
+ EnumMember em = s.isEnumMember();
+ if (em)
+ {
+ return em.getVarExp(exp.loc, sc);
+ }
+ VarDeclaration v = s.isVarDeclaration();
+ if (v)
+ {
+ //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
+ if (!v.type ||
+ !v.type.deco && v.inuse)
+ {
+ if (v.inuse)
+ exp.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
+ else
+ exp.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
+ return ErrorExp.get();
+ }
+ if (v.type.ty == Terror)
+ return ErrorExp.get();
+
+ if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym)
+ {
+ /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
+ * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
+ * be reverted. `wantsym` is the hack to work around the problem.
+ */
+ if (v.inuse)
+ {
+ error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
+ return ErrorExp.get();
+ }
+ e = v.expandInitializer(exp.loc);
+ v.inuse++;
+ e = e.expressionSemantic(sc);
+ v.inuse--;
+ return e;
+ }
+
+ if (v.needThis())
+ {
+ if (!eleft)
+ eleft = new ThisExp(exp.loc);
+ e = new DotVarExp(exp.loc, eleft, v);
+ e = e.expressionSemantic(sc);
+ }
+ else
+ {
+ e = new VarExp(exp.loc, v);
+ if (eleft)
+ {
+ e = new CommaExp(exp.loc, eleft, e);
+ e.type = v.type;
+ }
+ }
+ e = e.deref();
+ return e.expressionSemantic(sc);
+ }
+
+ FuncDeclaration f = s.isFuncDeclaration();
+ if (f)
+ {
+ //printf("it's a function\n");
+ if (!f.functionSemantic())
+ return ErrorExp.get();
+ if (f.needThis())
+ {
+ if (!eleft)
+ eleft = new ThisExp(exp.loc);
+ e = new DotVarExp(exp.loc, eleft, f, true);
+ e = e.expressionSemantic(sc);
+ }
+ else
+ {
+ e = new VarExp(exp.loc, f, true);
+ if (eleft)
+ {
+ e = new CommaExp(exp.loc, eleft, e);
+ e.type = f.type;
+ }
+ }
+ return e;
+ }
+ if (auto td = s.isTemplateDeclaration())
+ {
+ if (eleft)
+ e = new DotTemplateExp(exp.loc, eleft, td);
+ else
+ e = new TemplateExp(exp.loc, td);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ if (OverDeclaration od = s.isOverDeclaration())
+ {
+ e = new VarExp(exp.loc, od, true);
+ if (eleft)
+ {
+ e = new CommaExp(exp.loc, eleft, e);
+ e.type = Type.tvoid; // ambiguous type?
+ }
+ return e;
+ }
+ OverloadSet o = s.isOverloadSet();
+ if (o)
+ {
+ //printf("'%s' is an overload set\n", o.toChars());
+ return new OverExp(exp.loc, o);
+ }
+
+ if (auto t = s.getType())
+ {
+ return (new TypeExp(exp.loc, t)).expressionSemantic(sc);
+ }
+
+ TupleDeclaration tup = s.isTupleDeclaration();
+ if (tup)
+ {
+ if (eleft)
+ {
+ e = new DotVarExp(exp.loc, eleft, tup);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ e = new TupleExp(exp.loc, tup);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ ScopeDsymbol sds = s.isScopeDsymbol();
+ if (sds)
+ {
+ //printf("it's a ScopeDsymbol %s\n", ident.toChars());
+ e = new ScopeExp(exp.loc, sds);
+ e = e.expressionSemantic(sc);
+ if (eleft)
+ e = new DotExp(exp.loc, eleft, e);
+ return e;
+ }
+
+ Import imp = s.isImport();
+ if (imp)
+ {
+ ie = new ScopeExp(exp.loc, imp.pkg);
+ return ie.expressionSemantic(sc);
+ }
+ // BUG: handle other cases like in IdentifierExp::semantic()
+ debug
+ {
+ printf("s = '%s', kind = '%s'\n", s.toChars(), s.kind());
+ }
+ assert(0);
+ }
+ else if (exp.ident == Id.stringof)
+ {
+ e = new StringExp(exp.loc, ie.toString());
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule())
+ {
+ flag = 0;
+ }
+ if (flag)
+ return null;
+ s = ie.sds.search_correct(exp.ident);
+ if (s && symbolIsVisible(sc, s))
+ {
+ if (s.isPackage())
+ exp.error("undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.toPrettyChars());
+ else
+ exp.error("undefined identifier `%s` in %s `%s`, did you mean %s `%s`?", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.kind(), s.toChars());
+ }
+ else
+ exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
+ return ErrorExp.get();
+ }
+ else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum && exp.ident != Id._init && exp.ident != Id.__sizeof && exp.ident != Id.__xalignof && exp.ident != Id.offsetof && exp.ident != Id._mangleof && exp.ident != Id.stringof)
+ {
+ Type t1bn = t1b.nextOf();
+ if (flag)
+ {
+ AggregateDeclaration ad = isAggregate(t1bn);
+ if (ad && !ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
+ return null;
+ }
+
+ /* Rewrite:
+ * p.ident
+ * as:
+ * (*p).ident
+ */
+ if (flag && t1bn.ty == Tvoid)
+ return null;
+ e = new PtrExp(exp.loc, exp.e1);
+ e = e.expressionSemantic(sc);
+ return e.type.dotExp(sc, e, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
+ }
+ else if (exp.ident == Id.__xalignof &&
+ exp.e1.isVarExp() &&
+ exp.e1.isVarExp().var.isVarDeclaration() &&
+ exp.e1.isVarExp().var.isVarDeclaration().alignment)
+ {
+ // For `x.alignof` get the alignment of the variable, not the alignment of its type
+ const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment;
+ const naturalAlignment = exp.e1.type.alignsize();
+ const actualAlignment = (explicitAlignment == STRUCTALIGN_DEFAULT ? naturalAlignment : explicitAlignment);
+ e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
+ return e;
+ }
+ else
+ {
+ if (exp.e1.op == TOK.type || exp.e1.op == TOK.template_)
+ flag = 0;
+ e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
+ if (e)
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+}
+
+// Resolve e1.ident!tiargs without seeing UFCS.
+// If flag == 1, stop "not a property" error and return NULL.
+Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
+{
+ static if (LOGSEMANTIC)
+ {
+ printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars());
+ }
+
+ static Expression errorExp()
+ {
+ return ErrorExp.get();
+ }
+
+ Expression e1 = exp.e1;
+
+ if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin())
+ {
+ // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
+ // and do the symbol search in that context (Issue: 19476)
+ auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent;
+ e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm));
+ }
+
+ auto die = new DotIdExp(exp.loc, e1, exp.ti.name);
+
+ Expression e = die.semanticX(sc);
+ if (e == die)
+ {
+ exp.e1 = die.e1; // take back
+ Type t1b = exp.e1.type.toBasetype();
+ if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid))
+ {
+ /* No built-in type has templatized properties, so do shortcut.
+ * It is necessary in: 1024.max!"a < b"
+ */
+ if (flag)
+ return null;
+ }
+ e = die.semanticY(sc, flag);
+ if (flag)
+ {
+ if (!e ||
+ isDotOpDispatch(e))
+ {
+ /* opDispatch!tiargs would be a function template that needs IFTI,
+ * so it's not a template
+ */
+ return null;
+ }
+ }
+ }
+ assert(e);
+
+ if (e.op == TOK.error)
+ return e;
+ if (e.op == TOK.dotVariable)
+ {
+ DotVarExp dve = cast(DotVarExp)e;
+ if (FuncDeclaration fd = dve.var.isFuncDeclaration())
+ {
+ if (TemplateDeclaration td = fd.findTemplateDeclRoot())
+ {
+ e = new DotTemplateExp(dve.loc, dve.e1, td);
+ e = e.expressionSemantic(sc);
+ }
+ }
+ else if (OverDeclaration od = dve.var.isOverDeclaration())
+ {
+ exp.e1 = dve.e1; // pull semantic() result
+
+ if (!exp.findTempDecl(sc))
+ goto Lerr;
+ if (exp.ti.needsTypeInference(sc))
+ return exp;
+ exp.ti.dsymbolSemantic(sc);
+ if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
+ return errorExp();
+
+ if (Declaration v = exp.ti.toAlias().isDeclaration())
+ {
+ if (v.type && !v.type.deco)
+ v.type = v.type.typeSemantic(v.loc, sc);
+ return new DotVarExp(exp.loc, exp.e1, v)
+ .expressionSemantic(sc);
+ }
+ return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
+ .expressionSemantic(sc);
+ }
+ }
+ else if (e.op == TOK.variable)
+ {
+ VarExp ve = cast(VarExp)e;
+ if (FuncDeclaration fd = ve.var.isFuncDeclaration())
+ {
+ if (TemplateDeclaration td = fd.findTemplateDeclRoot())
+ {
+ e = new TemplateExp(ve.loc, td)
+ .expressionSemantic(sc);
+ }
+ }
+ else if (OverDeclaration od = ve.var.isOverDeclaration())
+ {
+ exp.ti.tempdecl = od;
+ return new ScopeExp(exp.loc, exp.ti)
+ .expressionSemantic(sc);
+ }
+ }
+
+ if (e.op == TOK.dotTemplateDeclaration)
+ {
+ DotTemplateExp dte = cast(DotTemplateExp)e;
+ exp.e1 = dte.e1; // pull semantic() result
+
+ exp.ti.tempdecl = dte.td;
+ if (!exp.ti.semanticTiargs(sc))
+ return errorExp();
+ if (exp.ti.needsTypeInference(sc))
+ return exp;
+ exp.ti.dsymbolSemantic(sc);
+ if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
+ return errorExp();
+
+ if (Declaration v = exp.ti.toAlias().isDeclaration())
+ {
+ if (v.isFuncDeclaration() || v.isVarDeclaration())
+ {
+ return new DotVarExp(exp.loc, exp.e1, v)
+ .expressionSemantic(sc);
+ }
+ }
+ return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
+ .expressionSemantic(sc);
+ }
+ else if (e.op == TOK.template_)
+ {
+ exp.ti.tempdecl = (cast(TemplateExp)e).td;
+ return new ScopeExp(exp.loc, exp.ti)
+ .expressionSemantic(sc);
+ }
+ else if (e.op == TOK.dot)
+ {
+ DotExp de = cast(DotExp)e;
+
+ if (de.e2.op == TOK.overloadSet)
+ {
+ if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
+ {
+ return errorExp();
+ }
+ if (exp.ti.needsTypeInference(sc))
+ return exp;
+ exp.ti.dsymbolSemantic(sc);
+ if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
+ return errorExp();
+
+ if (Declaration v = exp.ti.toAlias().isDeclaration())
+ {
+ if (v.type && !v.type.deco)
+ v.type = v.type.typeSemantic(v.loc, sc);
+ return new DotVarExp(exp.loc, exp.e1, v)
+ .expressionSemantic(sc);
+ }
+ return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
+ .expressionSemantic(sc);
+ }
+ }
+ else if (e.op == TOK.overloadSet)
+ {
+ OverExp oe = cast(OverExp)e;
+ exp.ti.tempdecl = oe.vars;
+ return new ScopeExp(exp.loc, exp.ti)
+ .expressionSemantic(sc);
+ }
+
+Lerr:
+ exp.error("`%s` isn't a template", e.toChars());
+ return errorExp();
+}
+
+/***************************************
+ * If expression is shared, check that we can access it.
+ * Give error message if not.
+ *
+ * Params:
+ * e = expression to check
+ * sc = context
+ * returnRef = Whether this expression is for a `return` statement
+ * off a `ref` function, in which case a single level
+ * of dereference is allowed (e.g. `shared(int)*`).
+ * Returns:
+ * true on error
+ */
+bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
+{
+ if (!global.params.noSharedAccess ||
+ sc.intypeof ||
+ sc.flags & SCOPE.ctfe)
+ {
+ return false;
+ }
+
+ //printf("checkSharedAccess() %s\n", e.toChars());
+
+ static extern(C++) final class SharedCheckVisitor : SemanticTimeTransitiveVisitor
+ {
+ /// In case we don't know which expression triggered it,
+ /// e.g. for `visit(Type)` overload
+ Expression original;
+ /// Where the result is stored (`true` == error)
+ bool result;
+ /// Whether we should allow one level of dereferencing
+ bool allowRef;
+
+ /// Ctor
+ this(Expression oe, bool allowRef_)
+ {
+ this.original = oe;
+ this.allowRef = allowRef_;
+ }
+
+ void sharedError(Expression e)
+ {
+ // https://dlang.org/phobos/core_atomic.html
+ e.error("direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
+ this.result = true;
+ }
+
+ /// Introduce base class overrides
+ alias visit = SemanticTimeTransitiveVisitor.visit;
+
+ // Error by default
+ override void visit(Expression e)
+ {
+ if (e.type.isShared())
+ this.sharedError(e);
+ }
+
+ /// Ditto
+ override void visit(Type t)
+ {
+ // Note: This handles things like `new shared(Throwable).msg`,
+ // where accessing `msg` would violate `shared`.
+ if (t.isShared())
+ this.sharedError(this.original);
+ }
+
+ // Those have no indirections / can be ignored
+ override void visit(ErrorExp e) {}
+ override void visit(ComplexExp e) {}
+ override void visit(IntegerExp e) {}
+ override void visit(NullExp e) {}
+
+ override void visit(VarExp e)
+ {
+ if (!this.allowRef && e.var.type.isShared())
+ this.sharedError(e);
+ }
+
+ override void visit(AddrExp e)
+ {
+ this.allowRef = true;
+ e.e1.accept(this);
+ }
+
+ override void visit(PtrExp e)
+ {
+ if (!this.allowRef && e.type.isShared())
+ return this.sharedError(e);
+
+ if (e.e1.type.isShared())
+ return this.sharedError(e);
+
+ this.allowRef = false;
+ e.e1.accept(this);
+ }
+
+ override void visit(DotVarExp e)
+ {
+ auto fd = e.var.isFuncDeclaration();
+ const sharedFunc = fd && fd.type.isShared;
+
+ if (!this.allowRef && e.type.isShared() && !sharedFunc)
+ return this.sharedError(e);
+
+ // Allow to use `DotVarExp` within value types
+ if (e.e1.type.ty == Tsarray || e.e1.type.ty == Tstruct)
+ return e.e1.accept(this);
+
+ // If we end up with a single `VarExp`, it might be a `ref` param
+ // `shared ref T` param == `shared(T)*`.
+ if (auto ve = e.e1.isVarExp())
+ {
+ this.allowRef = this.allowRef && (ve.var.storage_class & STC.ref_);
+ return e.e1.accept(this);
+ }
+
+ this.allowRef = false;
+ return e.e1.accept(this);
+ }
+
+ override void visit(IndexExp e)
+ {
+ if (!this.allowRef && e.type.isShared())
+ return this.sharedError(e);
+
+ if (e.e1.type.isShared())
+ return this.sharedError(e);
+
+ this.allowRef = false;
+ e.e1.accept(this);
+ }
+
+ override void visit(CommaExp e)
+ {
+ // Cannot be `return ref` since we can't use the return,
+ // but it's better to show that error than an unrelated `shared` one
+ this.allowRef = true;
+ e.e2.accept(this);
+ }
+ }
+
+ scope visitor = new SharedCheckVisitor(e, returnRef);
+ e.accept(visitor);
+ return visitor.result;
+}
+
+
+
+/****************************************************
+ * Determine if `exp`, which gets its address taken, can do so safely.
+ * Params:
+ * sc = context
+ * exp = expression having its address taken
+ * v = the variable getting its address taken
+ * Returns:
+ * `true` if ok, `false` for error
+ */
+bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
+{
+ //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
+ if (v)
+ {
+ if (!v.canTakeAddressOf())
+ {
+ exp.error("cannot take address of `%s`", exp.toChars());
+ return false;
+ }
+ if (sc.func && !sc.intypeof && !v.isDataseg())
+ {
+ const(char)* p = v.isParameter() ? "parameter" : "local";
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ {
+ // Taking the address of v means it cannot be set to 'scope' later
+ v.storage_class &= ~STC.maybescope;
+ v.doNotInferScope = true;
+ if (exp.type.hasPointers() && v.storage_class & STC.scope_ &&
+ !(v.storage_class & STC.temp) &&
+ !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
+ {
+ exp.error("cannot take address of `scope` %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars());
+ return false;
+ }
+ }
+ else if (!(sc.flags & SCOPE.debug_) &&
+ !(v.storage_class & STC.temp) &&
+ sc.func.setUnsafe())
+ {
+ exp.error("cannot take address of %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars());
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/*******************************
+ * Checks the attributes of a function.
+ * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
+ * and usage of `deprecated` and `@disabled`-ed symbols are checked.
+ *
+ * Params:
+ * exp = expression to check attributes for
+ * sc = scope of the function
+ * f = function to be checked
+ * Returns: `true` if error occur.
+ */
+private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f)
+{
+ with(exp)
+ {
+ bool error = checkDisabled(sc, f);
+ error |= checkDeprecated(sc, f);
+ error |= checkPurity(sc, f);
+ error |= checkSafety(sc, f);
+ error |= checkNogc(sc, f);
+ return error;
+ }
+}
+
+/*******************************
+ * Helper function for `getRightThis()`.
+ * Gets `this` of the next outer aggregate.
+ * Params:
+ * loc = location to use for error messages
+ * sc = context
+ * s = the parent symbol of the existing `this`
+ * ad = struct or class we need the correct `this` for
+ * e1 = existing `this`
+ * t = type of the existing `this`
+ * var = the specific member of ad we're accessing
+ * flag = if true, return `null` instead of throwing an error
+ * Returns:
+ * Expression representing the `this` for the var
+ */
+Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false)
+{
+ int n = 0;
+ while (s && s.isFuncDeclaration())
+ {
+ FuncDeclaration f = s.isFuncDeclaration();
+ if (f.vthis)
+ {
+ n++;
+ e1 = new VarExp(loc, f.vthis);
+ if (f.isThis2)
+ {
+ // (*__this)[i]
+ if (n > 1)
+ e1 = e1.expressionSemantic(sc);
+ e1 = new PtrExp(loc, e1);
+ uint i = f.followInstantiationContext(ad);
+ e1 = new IndexExp(loc, e1, new IntegerExp(i));
+ s = f.toParentP(ad);
+ continue;
+ }
+ }
+ else
+ {
+ if (flag)
+ return null;
+ e1.error("need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars());
+ e1 = ErrorExp.get();
+ return e1;
+ }
+ s = s.toParent2();
+ }
+ if (n > 1 || e1.op == TOK.index)
+ e1 = e1.expressionSemantic(sc);
+ if (s && e1.type.equivalent(Type.tvoidptr))
+ {
+ if (auto sad = s.isAggregateDeclaration())
+ {
+ Type ta = sad.handleType();
+ if (ta.ty == Tstruct)
+ ta = ta.pointerTo();
+ e1.type = ta;
+ }
+ }
+ e1.type = e1.type.addMod(t.mod);
+ return e1;
+}
+
+/*******************************
+ * Make a dual-context container for use as a `this` argument.
+ * Params:
+ * loc = location to use for error messages
+ * sc = current scope
+ * fd = target function that will take the `this` argument
+ * Returns:
+ * Temporary closure variable.
+ * Note:
+ * The function `fd` is added to the nested references of the
+ * newly created variable such that a closure is made for the variable when
+ * the address of `fd` is taken.
+ */
+VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
+{
+ Type tthis2 = Type.tvoidptr.sarrayOf(2);
+ VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null);
+ vthis2.storage_class |= STC.temp;
+ vthis2.dsymbolSemantic(sc);
+ vthis2.parent = sc.parent;
+ // make it a closure var
+ assert(sc.func);
+ sc.func.closureVars.push(vthis2);
+ // add `fd` to the nested refs
+ vthis2.nestedrefs.push(fd);
+ return vthis2;
+}
+
+/*******************************
+ * Make sure that the runtime hook `id` exists.
+ * Params:
+ * loc = location to use for error messages
+ * sc = current scope
+ * id = the hook identifier
+ * description = what the hook does
+ * module_ = what module the hook is located in
+ * Returns:
+ * a `bool` indicating if the hook is present.
+ */
+bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
+{
+ auto rootSymbol = sc.search(loc, Id.empty, null);
+ if (auto moduleSymbol = rootSymbol.search(loc, module_))
+ if (moduleSymbol.search(loc, id))
+ return true;
+ error(loc, "`%s.%s` not found. The current runtime does not support %.*s, or the runtime is corrupt.", module_.toChars(), id.toChars(), cast(int)description.length, description.ptr);
+ return false;
+}
+
+/***************************************
+ * Fit elements[] to the corresponding types of the `sd`'s fields.
+ *
+ * Params:
+ * sd = the struct declaration
+ * loc = location to use for error messages
+ * sc = context
+ * elements = explicit arguments used to construct object
+ * stype = the constructed object type.
+ * Returns:
+ * false if any errors occur,
+ * otherwise true and elements[] are rewritten for the output.
+ */
+private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
+{
+ if (!elements)
+ return true;
+
+ const nfields = sd.nonHiddenFields();
+ size_t offset = 0;
+ for (size_t i = 0; i < elements.dim; i++)
+ {
+ Expression e = (*elements)[i];
+ if (!e)
+ continue;
+
+ e = resolveProperties(sc, e);
+ if (i >= nfields)
+ {
+ if (i <= sd.fields.dim && e.op == TOK.null_)
+ {
+ // CTFE sometimes creates null as hidden pointer; we'll allow this.
+ continue;
+ }
+ .error(loc, "more initializers than fields (%zu) of `%s`", nfields, sd.toChars());
+ return false;
+ }
+ VarDeclaration v = sd.fields[i];
+ if (v.offset < offset)
+ {
+ .error(loc, "overlapping initialization for `%s`", v.toChars());
+ if (!sd.isUnionDeclaration())
+ {
+ enum errorMsg = "`struct` initializers that contain anonymous unions" ~
+ " must initialize only the first member of a `union`. All subsequent" ~
+ " non-overlapping fields are default initialized";
+ .errorSupplemental(loc, errorMsg);
+ }
+ return false;
+ }
+ offset = cast(uint)(v.offset + v.type.size());
+
+ Type t = v.type;
+ if (stype)
+ t = t.addMod(stype.mod);
+ Type origType = t;
+ Type tb = t.toBasetype();
+
+ const hasPointers = tb.hasPointers();
+ if (hasPointers)
+ {
+ if ((stype.alignment() < target.ptrsize ||
+ (v.offset & (target.ptrsize - 1))) &&
+ (sc.func && sc.func.setUnsafe()))
+ {
+ .error(loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code",
+ sd.toChars(), v.toChars());
+ return false;
+ }
+ }
+
+ /* Look for case of initializing a static array with a too-short
+ * string literal, such as:
+ * char[5] foo = "abc";
+ * Allow this by doing an explicit cast, which will lengthen the string
+ * literal.
+ */
+ if (e.op == TOK.string_ && tb.ty == Tsarray)
+ {
+ StringExp se = cast(StringExp)e;
+ Type typeb = se.type.toBasetype();
+ TY tynto = tb.nextOf().ty;
+ if (!se.committed &&
+ (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
+ se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
+ {
+ e = se.castTo(sc, t);
+ goto L1;
+ }
+ }
+
+ while (!e.implicitConvTo(t) && tb.ty == Tsarray)
+ {
+ /* Static array initialization, as in:
+ * T[3][5] = e;
+ */
+ t = tb.nextOf();
+ tb = t.toBasetype();
+ }
+ if (!e.implicitConvTo(t))
+ t = origType; // restore type for better diagnostic
+
+ e = e.implicitCastTo(sc, t);
+ L1:
+ if (e.op == TOK.error)
+ return false;
+
+ (*elements)[i] = doCopyOrMove(sc, e);
+ }
+ return true;
+}
+
+
+/**
+ * Returns `em` as a VariableExp
+ * Params:
+ * em = the EnumMember to wrap
+ * loc = location of use of em
+ * sc = scope of use of em
+ * Returns:
+ * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
+ */
+Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
+{
+ dsymbolSemantic(em, sc);
+ if (em.errors)
+ return ErrorExp.get();
+ em.checkDisabled(loc, sc);
+
+ if (em.depdecl && !em.depdecl._scope)
+ em.depdecl._scope = sc;
+ em.checkDeprecated(loc, sc);
+
+ if (em.errors)
+ return ErrorExp.get();
+ Expression e = new VarExp(loc, em);
+ return e.expressionSemantic(sc);
+}
+
+
+/*****************************
+ * Try to treat `exp` as a boolean,
+ * Params:
+ * exp = the expression
+ * sc = scope to evalute `exp` in
+ * Returns:
+ * Modified expression on success, ErrorExp on error
+ */
+Expression toBoolean(Expression exp, Scope* sc)
+{
+ switch(exp.op)
+ {
+ case TOK.delete_:
+ exp.error("`delete` does not give a boolean result");
+ return ErrorExp.get();
+
+ case TOK.comma:
+ auto ce = exp.isCommaExp();
+ auto ex2 = ce.e2.toBoolean(sc);
+ if (ex2.op == TOK.error)
+ return ex2;
+ ce.e2 = ex2;
+ ce.type = ce.e2.type;
+ return ce;
+
+ case TOK.assign:
+ case TOK.construct:
+ case TOK.blit:
+ // Things like:
+ // if (a = b) ...
+ // are usually mistakes.
+ exp.error("assignment cannot be used as a condition, perhaps `==` was meant?");
+ return ErrorExp.get();
+
+ //LogicalExp
+ case TOK.andAnd:
+ case TOK.orOr:
+ auto le = exp.isLogicalExp();
+ auto ex2 = le.e2.toBoolean(sc);
+ if (ex2.op == TOK.error)
+ return ex2;
+ le.e2 = ex2;
+ return le;
+
+ case TOK.question:
+ auto ce = exp.isCondExp();
+ auto ex1 = ce.e1.toBoolean(sc);
+ auto ex2 = ce.e2.toBoolean(sc);
+ if (ex1.op == TOK.error)
+ return ex1;
+ if (ex2.op == TOK.error)
+ return ex2;
+ ce.e1 = ex1;
+ ce.e2 = ex2;
+ return ce;
+
+
+ default:
+ // Default is 'yes' - do nothing
+ Expression e = exp;
+ Type t = exp.type;
+ Type tb = t.toBasetype();
+ Type att = null;
+
+ while (1)
+ {
+ // Structs can be converted to bool using opCast(bool)()
+ if (auto ts = tb.isTypeStruct())
+ {
+ AggregateDeclaration ad = ts.sym;
+ /* Don't really need to check for opCast first, but by doing so we
+ * get better error messages if it isn't there.
+ */
+ if (Dsymbol fd = search_function(ad, Id._cast))
+ {
+ e = new CastExp(exp.loc, e, Type.tbool);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ // Forward to aliasthis.
+ if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
+ {
+ e = resolveAliasThis(sc, e);
+ t = e.type;
+ tb = e.type.toBasetype();
+ continue;
+ }
+ }
+ break;
+ }
+
+ if (!t.isBoolean())
+ {
+ if (tb != Type.terror)
+ exp.error("expression `%s` of type `%s` does not have a boolean value",
+ exp.toChars(), t.toChars());
+ return ErrorExp.get();
+ }
+ return e;
+ }
+}
diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d
new file mode 100644
index 0000000..9579ac7
--- /dev/null
+++ b/gcc/d/dmd/foreachvar.d
@@ -0,0 +1,323 @@
+/**
+ * Utility to visit every variable in an expression.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/foreachvar.d, _foreachvar.d)
+ * Documentation: https://dlang.org/phobos/dmd_foreachvar.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/foreachvar.d
+ */
+
+module dmd.foreachvar;
+
+import core.stdc.stdio;
+import core.stdc.stdlib;
+import core.stdc.string;
+
+import dmd.apply;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.func;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.initsem;
+import dmd.mtype;
+import dmd.printast;
+import dmd.root.array;
+import dmd.root.rootobject;
+import dmd.statement;
+import dmd.tokens;
+import dmd.visitor;
+
+/*********************************************
+ * Visit each Expression in e, and call dgVar() on each variable declared in it.
+ * Params:
+ * e = expression tree to visit
+ * dgVar = call when a variable is declared
+ */
+void foreachVar(Expression e, void delegate(VarDeclaration) dgVar)
+{
+ if (!e)
+ return;
+
+ extern (C++) final class VarWalker : StoppableVisitor
+ {
+ alias visit = typeof(super).visit;
+ extern (D) void delegate(VarDeclaration) dgVar;
+
+ extern (D) this(void delegate(VarDeclaration) dgVar)
+ {
+ this.dgVar = dgVar;
+ }
+
+ override void visit(Expression e)
+ {
+ }
+
+ override void visit(ErrorExp e)
+ {
+ }
+
+ override void visit(DeclarationExp e)
+ {
+ VarDeclaration v = e.declaration.isVarDeclaration();
+ if (!v)
+ return;
+ if (TupleDeclaration td = v.toAlias().isTupleDeclaration())
+ {
+ if (!td.objects)
+ return;
+ foreach (o; *td.objects)
+ {
+ Expression ex = isExpression(o);
+ DsymbolExp s = ex ? ex.isDsymbolExp() : null;
+ assert(s);
+ VarDeclaration v2 = s.s.isVarDeclaration();
+ assert(v2);
+ dgVar(v2);
+ }
+ }
+ else
+ dgVar(v);
+ Dsymbol s = v.toAlias();
+ if (s == v && !v.isStatic() && v._init)
+ {
+ if (auto ie = v._init.isExpInitializer())
+ ie.exp.foreachVar(dgVar);
+ }
+ }
+
+ override void visit(IndexExp e)
+ {
+ if (e.lengthVar)
+ dgVar(e.lengthVar);
+ }
+
+ override void visit(SliceExp e)
+ {
+ if (e.lengthVar)
+ dgVar(e.lengthVar);
+ }
+ }
+
+ scope VarWalker v = new VarWalker(dgVar);
+ walkPostorder(e, v);
+}
+
+/***************
+ * Transitively walk Statement s, pass Expressions to dgExp(), VarDeclarations to dgVar().
+ * Params:
+ * s = Statement to traverse
+ * dgExp = delegate to pass found Expressions to
+ * dgVar = delegate to pass found VarDeclarations to
+ */
+void foreachExpAndVar(Statement s,
+ void delegate(Expression) dgExp,
+ void delegate(VarDeclaration) dgVar)
+{
+ void visit(Statement s)
+ {
+ void visitExp(ExpStatement s)
+ {
+ if (s.exp)
+ dgExp(s.exp);
+ }
+
+ void visitDtorExp(DtorExpStatement s)
+ {
+ if (s.exp)
+ dgExp(s.exp);
+ }
+
+ void visitIf(IfStatement s)
+ {
+ dgExp(s.condition);
+ visit(s.ifbody);
+ visit(s.elsebody);
+ }
+
+ void visitDo(DoStatement s)
+ {
+ dgExp(s.condition);
+ visit(s._body);
+ }
+
+ void visitFor(ForStatement s)
+ {
+ visit(s._init);
+ if (s.condition)
+ dgExp(s.condition);
+ if (s.increment)
+ dgExp(s.increment);
+ visit(s._body);
+ }
+
+ void visitSwitch(SwitchStatement s)
+ {
+ dgExp(s.condition);
+ // Note that the body contains the Case and Default
+ // statements, so we only need to compile the expressions
+ foreach (cs; *s.cases)
+ {
+ dgExp(cs.exp);
+ }
+ visit(s._body);
+ }
+
+ void visitCase(CaseStatement s)
+ {
+ visit(s.statement);
+ }
+
+ void visitReturn(ReturnStatement s)
+ {
+ if (s.exp)
+ dgExp(s.exp);
+ }
+
+ void visitCompound(CompoundStatement s)
+ {
+ if (s.statements)
+ {
+ foreach (s2; *s.statements)
+ {
+ visit(s2);
+ }
+ }
+ }
+
+ void visitCompoundDeclaration(CompoundDeclarationStatement s)
+ {
+ visitCompound(s);
+ }
+
+ void visitUnrolledLoop(UnrolledLoopStatement s)
+ {
+ foreach (s2; *s.statements)
+ {
+ visit(s2);
+ }
+ }
+
+ void visitScope(ScopeStatement s)
+ {
+ visit(s.statement);
+ }
+
+ void visitDefault(DefaultStatement s)
+ {
+ visit(s.statement);
+ }
+
+ void visitWith(WithStatement s)
+ {
+ // If it is with(Enum) {...}, just execute the body.
+ if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type)
+ {
+ }
+ else
+ {
+ dgVar(s.wthis);
+ dgExp(s.exp);
+ }
+ visit(s._body);
+ }
+
+ void visitTryCatch(TryCatchStatement s)
+ {
+ visit(s._body);
+ foreach (ca; *s.catches)
+ {
+ if (ca.var)
+ dgVar(ca.var);
+ visit(ca.handler);
+ }
+ }
+
+ void visitTryFinally(TryFinallyStatement s)
+ {
+ visit(s._body);
+ visit(s.finalbody);
+ }
+
+ void visitThrow(ThrowStatement s)
+ {
+ dgExp(s.exp);
+ }
+
+ void visitLabel(LabelStatement s)
+ {
+ visit(s.statement);
+ }
+
+ if (!s)
+ return;
+
+ final switch (s.stmt)
+ {
+ case STMT.Exp: visitExp(s.isExpStatement()); break;
+ case STMT.DtorExp: visitDtorExp(s.isDtorExpStatement()); break;
+ case STMT.Compound: visitCompound(s.isCompoundStatement()); break;
+ case STMT.CompoundDeclaration: visitCompoundDeclaration(s.isCompoundDeclarationStatement()); break;
+ case STMT.UnrolledLoop: visitUnrolledLoop(s.isUnrolledLoopStatement()); break;
+ case STMT.Scope: visitScope(s.isScopeStatement()); break;
+ case STMT.Do: visitDo(s.isDoStatement()); break;
+ case STMT.For: visitFor(s.isForStatement()); break;
+ case STMT.If: visitIf(s.isIfStatement()); break;
+ case STMT.Switch: visitSwitch(s.isSwitchStatement()); break;
+ case STMT.Case: visitCase(s.isCaseStatement()); break;
+ case STMT.Default: visitDefault(s.isDefaultStatement()); break;
+ case STMT.Return: visitReturn(s.isReturnStatement()); break;
+ case STMT.With: visitWith(s.isWithStatement()); break;
+ case STMT.TryCatch: visitTryCatch(s.isTryCatchStatement()); break;
+ case STMT.TryFinally: visitTryFinally(s.isTryFinallyStatement()); break;
+ case STMT.Throw: visitThrow(s.isThrowStatement()); break;
+ case STMT.Label: visitLabel(s.isLabelStatement()); break;
+
+ case STMT.CompoundAsm:
+ case STMT.Asm:
+ case STMT.InlineAsm:
+ case STMT.GccAsm:
+
+ case STMT.Break:
+ case STMT.Continue:
+ case STMT.GotoDefault:
+ case STMT.GotoCase:
+ case STMT.SwitchError:
+ case STMT.Goto:
+ case STMT.Pragma:
+ case STMT.Import:
+ case STMT.Error:
+ break; // ignore these
+
+ case STMT.ScopeGuard:
+ case STMT.Foreach:
+ case STMT.ForeachRange:
+ case STMT.Debug:
+ case STMT.CaseRange:
+ case STMT.StaticForeach:
+ case STMT.StaticAssert:
+ case STMT.Conditional:
+ case STMT.While:
+ case STMT.Forwarding:
+ case STMT.Compile:
+ case STMT.Peel:
+ case STMT.Synchronized:
+ assert(0); // should have been rewritten
+ }
+ }
+
+ visit(s);
+}
+
diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c
deleted file mode 100644
index b8e1e31..0000000
--- a/gcc/d/dmd/func.c
+++ /dev/null
@@ -1,3161 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/func.c
- */
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "init.h"
-#include "declaration.h"
-#include "attrib.h"
-#include "expression.h"
-#include "scope.h"
-#include "mtype.h"
-#include "aggregate.h"
-#include "identifier.h"
-#include "id.h"
-#include "module.h"
-#include "statement.h"
-#include "statement_rewrite_walker.h"
-#include "template.h"
-#include "hdrgen.h"
-#include "target.h"
-#include "parse.h"
-#include "root/rmem.h"
-#include "visitor.h"
-
-bool checkNestedRef(Dsymbol *s, Dsymbol *p);
-int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow);
-TypeIdentifier *getThrowable();
-
-bool MODimplicitConv(MOD modfrom, MOD modto);
-MATCH MODmethodConv(MOD modfrom, MOD modto);
-
-/***********************************************************
- * Tuple of result identifier (possibly null) and statement.
- * This is used to store out contracts: out(id){ ensure }
- */
-Ensure::Ensure()
-{
- this->id = NULL;
- this->ensure = NULL;
-}
-
-Ensure::Ensure(Identifier *id, Statement *ensure)
-{
- this->id = id;
- this->ensure = ensure;
-}
-
-Ensure Ensure::syntaxCopy()
-{
- return Ensure(id, ensure->syntaxCopy());
-}
-
-/*****************************************
- * Do syntax copy of an array of Ensure's.
- */
-Ensures *Ensure::arraySyntaxCopy(Ensures *a)
-{
- Ensures *b = NULL;
- if (a)
- {
- b = a->copy();
- for (size_t i = 0; i < a->length; i++)
- (*b)[i] = (*a)[i].syntaxCopy();
- }
- return b;
-}
-
-/********************************* FuncDeclaration ****************************/
-
-FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type)
- : Declaration(id)
-{
- //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type);
- //printf("storage_class = x%x\n", storage_class);
- this->storage_class = storage_class;
- this->type = type;
- if (type)
- {
- // Normalize storage_class, because function-type related attributes
- // are already set in the 'type' in parsing phase.
- this->storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR);
- }
- this->loc = loc;
- this->endloc = endloc;
- fthrows = NULL;
- frequire = NULL;
- fdrequire = NULL;
- fdensure = NULL;
- mangleString = NULL;
- vresult = NULL;
- returnLabel = NULL;
- fensure = NULL;
- frequires = NULL;
- fensures = NULL;
- fbody = NULL;
- localsymtab = NULL;
- vthis = NULL;
- v_arguments = NULL;
- v_argptr = NULL;
- parameters = NULL;
- labtab = NULL;
- overnext = NULL;
- overnext0 = NULL;
- vtblIndex = -1;
- hasReturnExp = 0;
- naked = false;
- generated = false;
- inlineStatusExp = ILSuninitialized;
- inlineStatusStmt = ILSuninitialized;
- inlining = PINLINEdefault;
- inlineNest = 0;
- ctfeCode = NULL;
- isArrayOp = 0;
- semantic3Errors = false;
- fes = NULL;
- interfaceVirtual = NULL;
- introducing = 0;
- tintro = NULL;
- /* The type given for "infer the return type" is a TypeFunction with
- * NULL for the return type.
- */
- inferRetType = (type && type->nextOf() == NULL);
- storage_class2 = 0;
- hasReturnExp = 0;
- nrvo_can = 1;
- nrvo_var = NULL;
- shidden = NULL;
- builtin = BUILTINunknown;
- tookAddressOf = 0;
- requiresClosure = false;
- inlinedNestedCallees = NULL;
- flags = 0;
- returns = NULL;
- gotos = NULL;
- selector = NULL;
-}
-
-FuncDeclaration *FuncDeclaration::create(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type)
-{
- return new FuncDeclaration(loc, endloc, id, storage_class, type);
-}
-
-Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s)
-{
- //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
- FuncDeclaration *f =
- s ? (FuncDeclaration *)s
- : new FuncDeclaration(loc, endloc, ident, storage_class, type->syntaxCopy());
- f->frequires = frequires ? Statement::arraySyntaxCopy(frequires) : NULL;
- f->fensures = fensures ? Ensure::arraySyntaxCopy(fensures) : NULL;
- f->fbody = fbody ? fbody->syntaxCopy() : NULL;
- assert(!fthrows); // deprecated
- return f;
-}
-
-// Returns true if a contract can appear without a function body.
-bool allowsContractWithoutBody(FuncDeclaration *funcdecl)
-{
- assert(!funcdecl->fbody);
-
- /* Contracts can only appear without a body when they are virtual
- * interface functions or abstract.
- */
- Dsymbol *parent = funcdecl->toParent();
- InterfaceDeclaration *id = parent->isInterfaceDeclaration();
-
- if (!funcdecl->isAbstract() &&
- (funcdecl->fensures || funcdecl->frequires) &&
- !(id && funcdecl->isVirtual()))
- {
- ClassDeclaration *cd = parent->isClassDeclaration();
- if (!(cd && cd->isAbstract()))
- return false;
- }
- return true;
-}
-
-/****************************************************
- * Determine whether an 'out' contract is declared inside
- * the given function or any of its overrides.
- * Params:
- * fd = the function to search
- * Returns:
- * true found an 'out' contract
- * false didn't find one
- */
-bool FuncDeclaration::needsFensure(FuncDeclaration *fd)
-{
- if (fd->fensures)
- return true;
-
- for (size_t i = 0; i < fd->foverrides.length; i++)
- {
- FuncDeclaration *fdv = fd->foverrides[i];
-
- if (fdv->fensure)
- return true;
-
- if (needsFensure(fdv))
- return true;
- }
- return false;
-}
-
-/****************************************************
- * Check whether result variable can be built.
- * Returns:
- * `true` if the function has a return type that
- * is different from `void`.
- */
-static bool canBuildResultVar(FuncDeclaration *fd)
-{
- TypeFunction *f = (TypeFunction *)fd->type;
- return f && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid;
-}
-
-/****************************************************
- * Rewrite contracts as statements.
- */
-void FuncDeclaration::buildEnsureRequire()
-{
- if (frequires)
- {
- /* in { statements1... }
- * in { statements2... }
- * ...
- * becomes:
- * in { { statements1... } { statements2... } ... }
- */
- assert(frequires->length);
- Loc loc = (*frequires)[0]->loc;
- Statements *s = new Statements;
- for (size_t i = 0; i < frequires->length; i++)
- {
- Statement *r = (*frequires)[i];
- s->push(new ScopeStatement(r->loc, r, r->loc));
- }
- frequire = new CompoundStatement(loc, s);
- }
-
- if (fensures)
- {
- /* out(id1) { statements1... }
- * out(id2) { statements2... }
- * ...
- * becomes:
- * out(__result) { { ref id1 = __result; { statements1... } }
- * { ref id2 = __result; { statements2... } } ... }
- */
- assert(fensures->length);
- Loc loc = (*fensures)[0].ensure->loc;
- Statements *s = new Statements;
- for (size_t i = 0; i < fensures->length; i++)
- {
- Ensure r = (*fensures)[i];
- if (r.id && canBuildResultVar(this))
- {
- Loc rloc = r.ensure->loc;
- IdentifierExp *resultId = new IdentifierExp(rloc, Id::result);
- ExpInitializer *init = new ExpInitializer(rloc, resultId);
- StorageClass stc = STCref | STCtemp | STCresult;
- VarDeclaration *decl = new VarDeclaration(rloc, NULL, r.id, init);
- decl->storage_class = stc;
- ExpStatement *sdecl = new ExpStatement(rloc, decl);
- s->push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
- }
- else
- {
- s->push(r.ensure);
- }
- }
- fensure = new CompoundStatement(loc, s);
- }
-
- if (!isVirtual())
- return;
-
- /* Rewrite contracts as nested functions, then call them. Doing it as nested
- * functions means that overriding functions can call them.
- */
- TypeFunction *f = (TypeFunction *)type;
-
- if (frequire)
- {
- /* in { ... }
- * becomes:
- * void __require() { ... }
- * __require();
- */
- Loc loc = frequire->loc;
- TypeFunction *tf = new TypeFunction(ParameterList(), Type::tvoid, LINKd);
- tf->isnothrow = f->isnothrow;
- tf->isnogc = f->isnogc;
- tf->purity = f->purity;
- tf->trust = f->trust;
- FuncDeclaration *fd = new FuncDeclaration(loc, loc,
- Id::require, STCundefined, tf);
- fd->fbody = frequire;
- Statement *s1 = new ExpStatement(loc, fd);
- Expression *e = new CallExp(loc, new VarExp(loc, fd, false), (Expressions *)NULL);
- Statement *s2 = new ExpStatement(loc, e);
- frequire = new CompoundStatement(loc, s1, s2);
- fdrequire = fd;
- }
-
- if (fensure)
- {
- /* out (result) { ... }
- * becomes:
- * void __ensure(ref tret result) { ... }
- * __ensure(result);
- */
- Loc loc = fensure->loc;
- Parameters *fparams = new Parameters();
- Parameter *p = NULL;
- if (canBuildResultVar(this))
- {
- p = new Parameter(STCref | STCconst, f->nextOf(), Id::result, NULL, NULL);
- fparams->push(p);
- }
- TypeFunction *tf = new TypeFunction(ParameterList(fparams), Type::tvoid, LINKd);
- tf->isnothrow = f->isnothrow;
- tf->isnogc = f->isnogc;
- tf->purity = f->purity;
- tf->trust = f->trust;
- FuncDeclaration *fd = new FuncDeclaration(loc, loc,
- Id::ensure, STCundefined, tf);
- fd->fbody = fensure;
- Statement *s1 = new ExpStatement(loc, fd);
- Expression *eresult = NULL;
- if (canBuildResultVar(this))
- eresult = new IdentifierExp(loc, Id::result);
- Expression *e = new CallExp(loc, new VarExp(loc, fd, false), eresult);
- Statement *s2 = new ExpStatement(loc, e);
- fensure = new CompoundStatement(loc, s1, s2);
- fdensure = fd;
- }
-}
-
-/****************************************************
- * Resolve forward reference of function signature -
- * parameter types, return type, and attributes.
- * Returns false if any errors exist in the signature.
- */
-bool FuncDeclaration::functionSemantic()
-{
- if (!_scope)
- return !errors;
-
- if (!originalType) // semantic not yet run
- {
- TemplateInstance *spec = isSpeculative();
- unsigned olderrs = global.errors;
- unsigned oldgag = global.gag;
- if (global.gag && !spec)
- global.gag = 0;
- dsymbolSemantic(this, _scope);
- global.gag = oldgag;
- if (spec && global.errors != olderrs)
- spec->errors = (global.errors - olderrs != 0);
- if (olderrs != global.errors) // if errors compiling this function
- return false;
- }
-
- // if inferring return type, sematic3 needs to be run
- // - When the function body contains any errors, we cannot assume
- // the inferred return type is valid.
- // So, the body errors should become the function signature error.
- if (inferRetType && type && !type->nextOf())
- return functionSemantic3();
-
- TemplateInstance *ti;
- if (isInstantiated() && !isVirtualMethod() &&
- ((ti = parent->isTemplateInstance()) == NULL || ti->isTemplateMixin() || ti->tempdecl->ident == ident))
- {
- AggregateDeclaration *ad = isMember2();
- if (ad && ad->sizeok != SIZEOKdone)
- {
- /* Currently dmd cannot resolve forward references per methods,
- * then setting SIZOKfwd is too conservative and would break existing code.
- * So, just stop method attributes inference until ad->semantic() done.
- */
- //ad->sizeok = SIZEOKfwd;
- }
- else
- return functionSemantic3() || !errors;
- }
-
- if (storage_class & STCinference)
- return functionSemantic3() || !errors;
-
- return !errors;
-}
-
-/****************************************************
- * Resolve forward reference of function body.
- * Returns false if any errors exist in the body.
- */
-bool FuncDeclaration::functionSemantic3()
-{
- if (semanticRun < PASSsemantic3 && _scope)
- {
- /* Forward reference - we need to run semantic3 on this function.
- * If errors are gagged, and it's not part of a template instance,
- * we need to temporarily ungag errors.
- */
- TemplateInstance *spec = isSpeculative();
- unsigned olderrs = global.errors;
- unsigned oldgag = global.gag;
- if (global.gag && !spec)
- global.gag = 0;
- semantic3(this, _scope);
- global.gag = oldgag;
-
- // If it is a speculatively-instantiated template, and errors occur,
- // we need to mark the template as having errors.
- if (spec && global.errors != olderrs)
- spec->errors = (global.errors - olderrs != 0);
- if (olderrs != global.errors) // if errors compiling this function
- return false;
- }
-
- return !errors && !semantic3Errors;
-}
-
-/****************************************************
- * Check that this function type is properly resolved.
- * If not, report "forward reference error" and return true.
- */
-bool FuncDeclaration::checkForwardRef(Loc loc)
-{
- if (!functionSemantic())
- return true;
-
- /* No deco means the functionSemantic() call could not resolve
- * forward referenes in the type of this function.
- */
- if (!type->deco)
- {
- bool inSemantic3 = (inferRetType && semanticRun >= PASSsemantic3);
- ::error(loc, "forward reference to %s`%s`",
- (inSemantic3 ? "inferred return type of function " : ""),
- toChars());
- return true;
- }
- return false;
-}
-
-VarDeclaration *FuncDeclaration::declareThis(Scope *sc, AggregateDeclaration *ad)
-{
- if (ad)
- {
- VarDeclaration *v;
- {
- //printf("declareThis() %s\n", toChars());
- Type *thandle = ad->handleType();
- assert(thandle);
- thandle = thandle->addMod(type->mod);
- thandle = thandle->addStorageClass(storage_class);
- v = new ThisDeclaration(loc, thandle);
- v->storage_class |= STCparameter;
- if (thandle->ty == Tstruct)
- {
- v->storage_class |= STCref;
-
- // if member function is marked 'inout', then 'this' is 'return ref'
- if (type->ty == Tfunction && ((TypeFunction *)type)->iswild & 2)
- v->storage_class |= STCreturn;
- }
- if (type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)type;
- if (tf->isreturn)
- v->storage_class |= STCreturn;
- if (tf->isscope)
- v->storage_class |= STCscope;
- }
- if (flags & FUNCFLAGinferScope && !(v->storage_class & STCscope))
- v->storage_class |= STCmaybescope;
-
- dsymbolSemantic(v, sc);
- if (!sc->insert(v))
- assert(0);
- v->parent = this;
- return v;
- }
- }
- else if (isNested())
- {
- /* The 'this' for a nested function is the link to the
- * enclosing function's stack frame.
- * Note that nested functions and member functions are disjoint.
- */
- VarDeclaration *v = new ThisDeclaration(loc, Type::tvoid->pointerTo());
- v->storage_class |= STCparameter;
- if (type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)type;
- if (tf->isreturn)
- v->storage_class |= STCreturn;
- if (tf->isscope)
- v->storage_class |= STCscope;
- }
- if (flags & FUNCFLAGinferScope && !(v->storage_class & STCscope))
- v->storage_class |= STCmaybescope;
-
- dsymbolSemantic(v, sc);
- if (!sc->insert(v))
- assert(0);
- v->parent = this;
- return v;
- }
-
- return NULL;
-}
-
-bool FuncDeclaration::equals(RootObject *o)
-{
- if (this == o)
- return true;
-
- Dsymbol *s = isDsymbol(o);
- if (s)
- {
- FuncDeclaration *fd1 = this;
- FuncDeclaration *fd2 = s->isFuncDeclaration();
- if (!fd2)
- return false;
-
- FuncAliasDeclaration *fa1 = fd1->isFuncAliasDeclaration();
- FuncAliasDeclaration *fa2 = fd2->isFuncAliasDeclaration();
- if (fa1 && fa2)
- {
- return fa1->toAliasFunc()->equals(fa2->toAliasFunc()) &&
- fa1->hasOverloads == fa2->hasOverloads;
- }
-
- if (fa1 && (fd1 = fa1->toAliasFunc())->isUnique() && !fa1->hasOverloads)
- fa1 = NULL;
- if (fa2 && (fd2 = fa2->toAliasFunc())->isUnique() && !fa2->hasOverloads)
- fa2 = NULL;
- if ((fa1 != NULL) != (fa2 != NULL))
- return false;
-
- return fd1->toParent()->equals(fd2->toParent()) &&
- fd1->ident->equals(fd2->ident) && fd1->type->equals(fd2->type);
- }
- return false;
-}
-
-/****************************************************
- * Declare result variable lazily.
- */
-
-void FuncDeclaration::buildResultVar(Scope *sc, Type *tret)
-{
- if (!vresult)
- {
- Loc loc = fensure ? fensure->loc : this->loc;
-
- /* If inferRetType is true, tret may not be a correct return type yet.
- * So, in here it may be a temporary type for vresult, and after
- * fbody->semantic() running, vresult->type might be modified.
- */
- vresult = new VarDeclaration(loc, tret, Id::result, NULL);
- vresult->storage_class |= STCnodtor | STCtemp;
- if (!isVirtual())
- vresult->storage_class |= STCconst;
- vresult->storage_class |= STCresult;
-
- // set before the semantic() for checkNestedReference()
- vresult->parent = this;
- }
-
- if (sc && vresult->semanticRun == PASSinit)
- {
- TypeFunction *tf = type->toTypeFunction();
- if (tf->isref)
- vresult->storage_class |= STCref;
- vresult->type = tret;
-
- dsymbolSemantic(vresult, sc);
-
- if (!sc->insert(vresult))
- error("out result %s is already defined", vresult->toChars());
- assert(vresult->parent == this);
- }
-}
-
-/****************************************************
- * Merge into this function the 'in' contracts of all it overrides.
- * 'in's are OR'd together, i.e. only one of them needs to pass.
- */
-
-Statement *FuncDeclaration::mergeFrequire(Statement *sf)
-{
- /* If a base function and its override both have an IN contract, then
- * only one of them needs to succeed. This is done by generating:
- *
- * void derived.in() {
- * try {
- * base.in();
- * }
- * catch () {
- * ... body of derived.in() ...
- * }
- * }
- *
- * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
- * If base.in() throws, then derived.in()'s body is executed.
- */
-
- /* Implementing this is done by having the overriding function call
- * nested functions (the fdrequire functions) nested inside the overridden
- * function. This requires that the stack layout of the calling function's
- * parameters and 'this' pointer be in the same place (as the nested
- * function refers to them).
- * This is easy for the parameters, as they are all on the stack in the same
- * place by definition, since it's an overriding function. The problem is
- * getting the 'this' pointer in the same place, since it is a local variable.
- * We did some hacks in the code generator to make this happen:
- * 1. always generate exception handler frame, or at least leave space for it
- * in the frame (Windows 32 SEH only)
- * 2. always generate an EBP style frame
- * 3. since 'this' is passed in a register that is subsequently copied into
- * a stack local, allocate that local immediately following the exception
- * handler block, so it is always at the same offset from EBP.
- */
- for (size_t i = 0; i < foverrides.length; i++)
- {
- FuncDeclaration *fdv = foverrides[i];
-
- /* The semantic pass on the contracts of the overridden functions must
- * be completed before code generation occurs.
- * https://issues.dlang.org/show_bug.cgi?id=3602
- */
- if (fdv->frequires && fdv->semanticRun != PASSsemantic3done)
- {
- assert(fdv->_scope);
- Scope *sc = fdv->_scope->push();
- sc->stc &= ~STCoverride;
- semantic3(fdv, sc);
- sc->pop();
- }
-
- sf = fdv->mergeFrequire(sf);
- if (sf && fdv->fdrequire)
- {
- //printf("fdv->frequire: %s\n", fdv->frequire->toChars());
- /* Make the call:
- * try { __require(); }
- * catch (Throwable) { frequire; }
- */
- Expression *eresult = NULL;
- Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire, false), eresult);
- Statement *s2 = new ExpStatement(loc, e);
-
- Catch *c = new Catch(loc, getThrowable(), NULL, sf);
- c->internalCatch = true;
- Catches *catches = new Catches();
- catches->push(c);
- sf = new TryCatchStatement(loc, s2, catches);
- }
- else
- return NULL;
- }
- return sf;
-}
-
-/****************************************************
- * Merge into this function the 'out' contracts of all it overrides.
- * 'out's are AND'd together, i.e. all of them need to pass.
- */
-
-Statement *FuncDeclaration::mergeFensure(Statement *sf, Identifier *oid)
-{
- /* Same comments as for mergeFrequire(), except that we take care
- * of generating a consistent reference to the 'result' local by
- * explicitly passing 'result' to the nested function as a reference
- * argument.
- * This won't work for the 'this' parameter as it would require changing
- * the semantic code for the nested function so that it looks on the parameter
- * list for the 'this' pointer, something that would need an unknown amount
- * of tweaking of various parts of the compiler that I'd rather leave alone.
- */
- for (size_t i = 0; i < foverrides.length; i++)
- {
- FuncDeclaration *fdv = foverrides[i];
-
- /* The semantic pass on the contracts of the overridden functions must
- * be completed before code generation occurs.
- * https://issues.dlang.org/show_bug.cgi?id=3602 and
- * https://issues.dlang.org/show_bug.cgi?id=5230
- */
- if (needsFensure(fdv) && fdv->semanticRun != PASSsemantic3done)
- {
- assert(fdv->_scope);
- Scope *sc = fdv->_scope->push();
- sc->stc &= ~STCoverride;
- semantic3(fdv, sc);
- sc->pop();
- }
-
- sf = fdv->mergeFensure(sf, oid);
- if (fdv->fdensure)
- {
- //printf("fdv->fensure: %s\n", fdv->fensure->toChars());
- // Make the call: __ensure(result)
- Expression *eresult = NULL;
- if (canBuildResultVar(this))
- {
- eresult = new IdentifierExp(loc, oid);
-
- Type *t1 = fdv->type->nextOf()->toBasetype();
- Type *t2 = this->type->nextOf()->toBasetype();
- if (t1->isBaseOf(t2, NULL))
- {
- /* Making temporary reference variable is necessary
- * in covariant return.
- * See bugzilla 5204 and 10479.
- */
- ExpInitializer *ei = new ExpInitializer(Loc(), eresult);
- VarDeclaration *v = new VarDeclaration(Loc(), t1, Identifier::generateId("__covres"), ei);
- v->storage_class |= STCtemp;
- DeclarationExp *de = new DeclarationExp(Loc(), v);
- VarExp *ve = new VarExp(Loc(), v);
- eresult = new CommaExp(Loc(), de, ve);
- }
- }
- Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure, false), eresult);
- Statement *s2 = new ExpStatement(loc, e);
-
- if (sf)
- {
- sf = new CompoundStatement(sf->loc, s2, sf);
- }
- else
- sf = s2;
- }
- }
- return sf;
-}
-
-/****************************************************
- * Determine if 'this' overrides fd.
- * Return !=0 if it does.
- */
-
-int FuncDeclaration::overrides(FuncDeclaration *fd)
-{ int result = 0;
-
- if (fd->ident == ident)
- {
- int cov = type->covariant(fd->type);
- if (cov)
- { ClassDeclaration *cd1 = toParent()->isClassDeclaration();
- ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration();
-
- if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL))
- result = 1;
- }
- }
- return result;
-}
-
-/*************************************************
- * Find index of function in vtbl[0..length] that
- * this function overrides.
- * Prefer an exact match to a covariant one.
- * Params:
- * fix17349 = enable fix https://issues.dlang.org/show_bug.cgi?id=17349
- * Returns:
- * -1 didn't find one
- * -2 can't determine because of forward references
- */
-
-int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim, bool fix17349)
-{
- //printf("findVtblIndex() %s\n", toChars());
- FuncDeclaration *mismatch = NULL;
- StorageClass mismatchstc = 0;
- int mismatchvi = -1;
- int exactvi = -1;
- int bestvi = -1;
- for (int vi = 0; vi < dim; vi++)
- {
- FuncDeclaration *fdv = (*vtbl)[vi]->isFuncDeclaration();
- if (fdv && fdv->ident == ident)
- {
- if (type->equals(fdv->type)) // if exact match
- {
- if (fdv->parent->isClassDeclaration())
- {
- if (fdv->isFuture())
- {
- bestvi = vi;
- continue; // keep looking
- }
- return vi; // no need to look further
- }
-
- if (exactvi >= 0)
- {
- error("cannot determine overridden function");
- return exactvi;
- }
- exactvi = vi;
-
- bestvi = vi;
- continue;
- }
-
- StorageClass stc = 0;
- int cov = type->covariant(fdv->type, &stc, fix17349);
- //printf("\tbaseclass cov = %d\n", cov);
- switch (cov)
- {
- case 0: // types are distinct
- break;
-
- case 1:
- bestvi = vi; // covariant, but not identical
- break; // keep looking for an exact match
-
- case 2:
- mismatchvi = vi;
- mismatchstc = stc;
- mismatch = fdv; // overrides, but is not covariant
- break; // keep looking for an exact match
-
- case 3:
- return -2; // forward references
-
- default:
- assert(0);
- }
- }
- }
- if (bestvi == -1 && mismatch)
- {
- //type->print();
- //mismatch->type->print();
- //printf("%s %s\n", type->deco, mismatch->type->deco);
- //printf("stc = %llx\n", mismatchstc);
- if (mismatchstc)
- { // Fix it by modifying the type to add the storage classes
- type = type->addStorageClass(mismatchstc);
- bestvi = mismatchvi;
- }
- }
- return bestvi;
-}
-
-/*********************************
- * If function a function in a base class,
- * return that base class.
- * Params:
- * cd = class that function is in
- * Returns:
- * base class if overriding, NULL if not
- */
-BaseClass *FuncDeclaration::overrideInterface()
-{
- ClassDeclaration *cd = parent->isClassDeclaration();
- for (size_t i = 0; i < cd->interfaces.length; i++)
- {
- BaseClass *b = cd->interfaces.ptr[i];
- int v = findVtblIndex((Dsymbols *)&b->sym->vtbl, (int)b->sym->vtbl.length);
- if (v >= 0)
- return b;
- }
- return NULL;
-}
-
-/****************************************************
- * Overload this FuncDeclaration with the new one f.
- * Return true if successful; i.e. no conflict.
- */
-
-bool FuncDeclaration::overloadInsert(Dsymbol *s)
-{
- //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s->toChars(), toChars());
- assert(s != this);
-
- AliasDeclaration *ad = s->isAliasDeclaration();
- if (ad)
- {
- if (overnext)
- return overnext->overloadInsert(ad);
- if (!ad->aliassym && ad->type->ty != Tident && ad->type->ty != Tinstance)
- {
- //printf("\tad = '%s'\n", ad->type->toChars());
- return false;
- }
- overnext = ad;
- //printf("\ttrue: no conflict\n");
- return true;
- }
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (td)
- {
- if (!td->funcroot)
- td->funcroot = this;
- if (overnext)
- return overnext->overloadInsert(td);
- overnext = td;
- return true;
- }
- FuncDeclaration *fd = s->isFuncDeclaration();
- if (!fd)
- return false;
-
- if (overnext)
- {
- td = overnext->isTemplateDeclaration();
- if (td)
- fd->overloadInsert(td);
- else
- return overnext->overloadInsert(fd);
- }
- overnext = fd;
- //printf("\ttrue: no conflict\n");
- return true;
-}
-
-/***************************************************
- * Visit each overloaded function/template in turn, and call
- * (*fp)(param, s) on it.
- * Exit when no more, or (*fp)(param, f) returns nonzero.
- * Returns:
- * ==0 continue
- * !=0 done
- */
-
-int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *))
-{
- Dsymbol *d;
- Dsymbol *next;
- for (d = fstart; d; d = next)
- {
- if (OverDeclaration *od = d->isOverDeclaration())
- {
- if (od->hasOverloads)
- {
- if (int r = overloadApply(od->aliassym, param, fp))
- return r;
- }
- else
- {
- if (int r = (*fp)(param, od->aliassym))
- return r;
- }
- next = od->overnext;
- }
- else if (FuncAliasDeclaration *fa = d->isFuncAliasDeclaration())
- {
- if (fa->hasOverloads)
- {
- if (int r = overloadApply(fa->funcalias, param, fp))
- return r;
- }
- else
- {
- FuncDeclaration *fd = fa->toAliasFunc();
- if (!fd)
- {
- d->error("is aliased to a function");
- break;
- }
- if (int r = (*fp)(param, fd))
- return r;
- }
- next = fa->overnext;
- }
- else if (AliasDeclaration *ad = d->isAliasDeclaration())
- {
- next = ad->toAlias();
- if (next == ad)
- break;
- if (next == fstart)
- break;
- }
- else if (TemplateDeclaration *td = d->isTemplateDeclaration())
- {
- if (int r = (*fp)(param, td))
- return r;
- next = td->overnext;
- }
- else
- {
- FuncDeclaration *fd = d->isFuncDeclaration();
- if (!fd)
- {
- d->error("is aliased to a function");
- break; // BUG: should print error message?
- }
- if (int r = (*fp)(param, fd))
- return r;
- next = fd->overnext;
- }
- }
- return 0;
-}
-
-/********************************************
- * If there are no overloads of function f, return that function,
- * otherwise return NULL.
- */
-
-FuncDeclaration *FuncDeclaration::isUnique()
-{
- struct ParamUnique
- {
- static int fp(void *param, Dsymbol *s)
- {
- FuncDeclaration *f = s->isFuncDeclaration();
- if (!f)
- return 0;
- FuncDeclaration **pf = (FuncDeclaration **)param;
-
- if (*pf)
- {
- *pf = NULL;
- return 1; // ambiguous, done
- }
- else
- {
- *pf = f;
- return 0;
- }
- }
- };
- FuncDeclaration *result = NULL;
- overloadApply(this, &result, &ParamUnique::fp);
- return result;
-}
-
-/********************************************
- * Find function in overload list that exactly matches t.
- */
-
-FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t)
-{
- struct ParamExact
- {
- Type *t; // type to match
- FuncDeclaration *f; // return value
-
- static int fp(void *param, Dsymbol *s)
- {
- FuncDeclaration *f = s->isFuncDeclaration();
- if (!f)
- return 0;
- ParamExact *p = (ParamExact *)param;
- Type *t = p->t;
-
- if (t->equals(f->type))
- {
- p->f = f;
- return 1;
- }
-
- /* Allow covariant matches, as long as the return type
- * is just a const conversion.
- * This allows things like pure functions to match with an impure function type.
- */
- if (t->ty == Tfunction)
- { TypeFunction *tf = (TypeFunction *)f->type;
- if (tf->covariant(t) == 1 &&
- tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst)
- {
- p->f = f;
- return 1;
- }
- }
- return 0;
- }
- };
- ParamExact p;
- p.t = t;
- p.f = NULL;
- overloadApply(this, &p, &ParamExact::fp);
- return p.f;
-}
-
-void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod)
-{
- bool bothMutable = ((lhsMod & rhsMod) == 0);
- bool sharedMismatch = ((lhsMod ^ rhsMod) & MODshared) != 0;
- bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODshared);
-
- if (lhsMod & MODshared)
- buf->writestring("shared ");
- else if (sharedMismatch && !(lhsMod & MODimmutable))
- buf->writestring("non-shared ");
-
- if (bothMutable && sharedMismatchOnly)
- { }
- else if (lhsMod & MODimmutable)
- buf->writestring("immutable ");
- else if (lhsMod & MODconst)
- buf->writestring("const ");
- else if (lhsMod & MODwild)
- buf->writestring("inout ");
- else
- buf->writestring("mutable ");
-}
-
-/********************************************
- * Find function in overload list that matches to the 'this' modifier.
- * There's four result types.
- *
- * 1. If the 'tthis' matches only one candidate, it's an "exact match".
- * Returns the function and 'hasOverloads' is set to false.
- * eg. If 'tthis" is mutable and there's only one mutable method.
- * 2. If there's two or more match candidates, but a candidate function will be
- * a "better match".
- * Returns the better match function but 'hasOverloads' is set to true.
- * eg. If 'tthis' is mutable, and there's both mutable and const methods,
- * the mutable method will be a better match.
- * 3. If there's two or more match candidates, but there's no better match,
- * Returns NULL and 'hasOverloads' is set to true to represent "ambiguous match".
- * eg. If 'tthis' is mutable, and there's two or more mutable methods.
- * 4. If there's no candidates, it's "no match" and returns NULL with error report.
- * e.g. If 'tthis' is const but there's no const methods.
- */
-FuncDeclaration *FuncDeclaration::overloadModMatch(Loc loc, Type *tthis, bool &hasOverloads)
-{
- //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
- Match m;
- memset(&m, 0, sizeof(m));
- m.last = MATCHnomatch;
-
- struct ParamMod
- {
- Match *m;
- Type *tthis;
-
- static int fp(void *param, Dsymbol *s)
- {
- if (FuncDeclaration *fd = s->isFuncDeclaration())
- return ((ParamMod *)param)->fp(fd);
- return 0;
- }
- int fp(FuncDeclaration *f)
- {
- if (f == m->lastf) // skip duplicates
- return 0;
-
- m->anyf = f;
- TypeFunction *tf = f->type->toTypeFunction();
- //printf("tf = %s\n", tf->toChars());
-
- MATCH match;
- if (tthis) // non-static functions are preferred than static ones
- {
- if (f->needThis())
- match = f->isCtorDeclaration() ? MATCHexact : MODmethodConv(tthis->mod, tf->mod);
- else
- match = MATCHconst; // keep static funciton in overload candidates
- }
- else // static functions are preferred than non-static ones
- {
- if (f->needThis())
- match = MATCHconvert;
- else
- match = MATCHexact;
- }
- if (match != MATCHnomatch)
- {
- if (match > m->last) goto LfIsBetter;
- if (match < m->last) goto LlastIsBetter;
-
- /* See if one of the matches overrides the other.
- */
- if (m->lastf->overrides(f)) goto LlastIsBetter;
- if (f->overrides(m->lastf)) goto LfIsBetter;
-
- //printf("\tambiguous\n");
- m->nextf = f;
- m->count++;
- return 0;
-
- LlastIsBetter:
- //printf("\tlastbetter\n");
- m->count++; // count up
- return 0;
-
- LfIsBetter:
- //printf("\tisbetter\n");
- if (m->last <= MATCHconvert)
- {
- // clear last secondary matching
- m->nextf = NULL;
- m->count = 0;
- }
- m->last = match;
- m->lastf = f;
- m->count++; // count up
- return 0;
- }
- return 0;
- }
- };
- ParamMod p;
- p.m = &m;
- p.tthis = tthis;
- overloadApply(this, &p, &ParamMod::fp);
-
- if (m.count == 1) // exact match
- {
- hasOverloads = false;
- }
- else if (m.count > 1) // better or ambiguous match
- {
- hasOverloads = true;
- }
- else // no match
- {
- hasOverloads = true;
- TypeFunction *tf = this->type->toTypeFunction();
- assert(tthis);
- assert(!MODimplicitConv(tthis->mod, tf->mod)); // modifier mismatch
- {
- OutBuffer thisBuf, funcBuf;
- MODMatchToBuffer(&thisBuf, tthis->mod, tf->mod);
- MODMatchToBuffer(&funcBuf, tf->mod, tthis->mod);
- ::error(loc, "%smethod %s is not callable using a %sobject",
- funcBuf.peekChars(), this->toPrettyChars(), thisBuf.peekChars());
- }
- }
-
- return m.lastf;
-}
-
-/********************************************
- * Returns true if function was declared
- * directly or indirectly in a unittest block
- */
-bool FuncDeclaration::inUnittest()
-{
- Dsymbol *f = this;
- do
- {
- if (f->isUnitTestDeclaration())
- return true;
- f = f->toParent();
- } while (f);
-
- return false;
-}
-
-/********************************************
- * find function template root in overload list
- */
-
-TemplateDeclaration *FuncDeclaration::findTemplateDeclRoot()
-{
- FuncDeclaration *f = this;
- while (f && f->overnext)
- {
- //printf("f->overnext = %p %s\n", f->overnext, f->overnext->toChars());
- TemplateDeclaration *td = f->overnext->isTemplateDeclaration();
- if (td)
- return td;
- f = f->overnext->isFuncDeclaration();
- }
- return NULL;
-}
-
-/*************************************
- * Determine partial specialization order of 'this' vs g.
- * This is very similar to TemplateDeclaration::leastAsSpecialized().
- * Returns:
- * match 'this' is at least as specialized as g
- * 0 g is more specialized than 'this'
- */
-
-MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g)
-{
- /* This works by calling g() with f()'s parameters, and
- * if that is possible, then f() is at least as specialized
- * as g() is.
- */
-
- TypeFunction *tf = type->toTypeFunction();
- TypeFunction *tg = g->type->toTypeFunction();
- size_t nfparams = tf->parameterList.length();
-
- /* If both functions have a 'this' pointer, and the mods are not
- * the same and g's is not const, then this is less specialized.
- */
- if (needThis() && g->needThis() && tf->mod != tg->mod)
- {
- if (isCtorDeclaration())
- {
- if (!MODimplicitConv(tg->mod, tf->mod))
- return MATCHnomatch;
- }
- else
- {
- if (!MODimplicitConv(tf->mod, tg->mod))
- return MATCHnomatch;
- }
- }
-
- /* Create a dummy array of arguments out of the parameters to f()
- */
- Expressions args;
- args.setDim(nfparams);
- for (size_t u = 0; u < nfparams; u++)
- {
- Parameter *p = tf->parameterList[u];
- Expression *e;
- if (p->storageClass & (STCref | STCout))
- {
- e = new IdentifierExp(Loc(), p->ident);
- e->type = p->type;
- }
- else
- e = p->type->defaultInitLiteral(Loc());
- args[u] = e;
- }
-
- MATCH m = (MATCH) tg->callMatch(NULL, &args, 1);
- if (m > MATCHnomatch)
- {
- /* A variadic parameter list is less specialized than a
- * non-variadic one.
- */
- if (tf->parameterList.varargs && !tg->parameterList.varargs)
- goto L1; // less specialized
-
- return m;
- }
- L1:
- return MATCHnomatch;
-}
-
-/// Walk through candidate template overloads and print them in the diagnostics.
-struct TemplateCandidateWalker
-{
- Loc loc;
- int numToDisplay; // max num of overloads to print (-v overrides this).
-
- /// Count template overloads.
- struct CountWalker
- {
- int numOverloads;
-
- static int fp(void *param, Dsymbol *)
- {
- CountWalker *p = (CountWalker *)param;
- ++(p->numOverloads);
- return 0;
- }
- };
-
- static int fp(void *param, Dsymbol *s)
- {
- TemplateDeclaration *t = s->isTemplateDeclaration();
- if (!t) return 0;
-
- TemplateCandidateWalker *p = (TemplateCandidateWalker *)param;
-
- ::errorSupplemental(t->loc, "%s", t->toPrettyChars());
-
- if (!global.params.verbose && --(p->numToDisplay) == 0 && t->overnext)
- {
- // Too many overloads to sensibly display.
- // Just show count of remaining overloads.
- CountWalker cw;
- cw.numOverloads = 0;
- overloadApply(t->overnext, &cw, &CountWalker::fp);
-
- if (cw.numOverloads > 0)
- ::errorSupplemental(p->loc, "... (%d more, -v to show) ...", cw.numOverloads);
-
- return 1; // stop iterating
- }
-
- return 0;
- }
-};
-
-/// Walk through candidate template overloads and print them in the diagnostics.
-struct FuncCandidateWalker
-{
- Loc loc;
- int numToDisplay; // max num of overloads to print (-v overrides this).
-
- /// Count function overloads.
- struct CountWalker
- {
- int numOverloads;
-
- static int fp(void *param, Dsymbol *)
- {
- CountWalker *p = (CountWalker *)param;
- ++(p->numOverloads);
- return 0;
- }
- };
-
- static int fp(void *param, Dsymbol *s)
- {
- FuncDeclaration *fd = s->isFuncDeclaration();
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (fd)
- {
- if (fd->errors || fd->type->ty == Terror)
- return 0;
-
- TypeFunction *tf = (TypeFunction *)fd->type;
-
- ::errorSupplemental(fd->loc, "%s%s", fd->toPrettyChars(),
- parametersTypeToChars(tf->parameterList));
- }
- else
- {
- ::errorSupplemental(td->loc, "%s", td->toPrettyChars());
- }
-
- FuncCandidateWalker *p = (FuncCandidateWalker *)param;
- if (global.params.verbose || --(p->numToDisplay) != 0 || !fd)
- return 0;
-
- // Too many overloads to sensibly display.
- CountWalker cw;
- cw.numOverloads = 0;
- overloadApply(fd->overnext, &cw, &CountWalker::fp);
-
- if (cw.numOverloads > 0)
- ::errorSupplemental(p->loc, "... (%d more, -v to show) ...", cw.numOverloads);
-
- return 1; // stop iterating
- }
-};
-
-/*******************************************
- * Given a symbol that could be either a FuncDeclaration or
- * a function template, resolve it to a function symbol.
- * loc instantiation location
- * sc instantiation scope
- * tiargs initial list of template arguments
- * tthis if !NULL, the 'this' pointer argument
- * fargs arguments to function
- * flags 1: do not issue error message on no match, just return NULL
- * 2: overloadResolve only
- */
-
-FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
- Objects *tiargs, Type *tthis, Expressions *fargs, int flags)
-{
- if (!s)
- return NULL; // no match
-
- if ((tiargs && arrayObjectIsError(tiargs)) ||
- (fargs && arrayObjectIsError((Objects *)fargs)))
- {
- return NULL;
- }
-
- Match m;
- memset(&m, 0, sizeof(m));
- m.last = MATCHnomatch;
-
- const char *failMessage = NULL;
- functionResolve(&m, s, loc, sc, tiargs, tthis, fargs, &failMessage);
-
- if (m.last > MATCHnomatch && m.lastf)
- {
- if (m.count == 1) // exactly one match
- {
- if (!(flags & 1))
- m.lastf->functionSemantic();
- return m.lastf;
- }
- if ((flags & 2) && !tthis && m.lastf->needThis())
- {
- return m.lastf;
- }
- }
-
- /* Failed to find a best match.
- * Do nothing or print error.
- */
- if (m.last <= MATCHnomatch)
- {
- // error was caused on matched function
- if (m.count == 1)
- return m.lastf;
-
- // if do not print error messages
- if (flags & 1)
- return NULL; // no match
- }
-
- FuncDeclaration *fd = s->isFuncDeclaration();
- OverDeclaration *od = s->isOverDeclaration();
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (td && td->funcroot)
- s = fd = td->funcroot;
-
- OutBuffer tiargsBuf;
- arrayObjectsToBuffer(&tiargsBuf, tiargs);
-
- OutBuffer fargsBuf;
- fargsBuf.writeByte('(');
- argExpTypesToCBuffer(&fargsBuf, fargs);
- fargsBuf.writeByte(')');
- if (tthis)
- tthis->modToBuffer(&fargsBuf);
-
- const int numOverloadsDisplay = 5; // sensible number to display
-
- if (!m.lastf && !(flags & 1)) // no match
- {
- if (td && !fd) // all of overloads are templates
- {
- ::error(loc, "%s %s.%s cannot deduce function from argument types !(%s)%s, candidates are:",
- td->kind(), td->parent->toPrettyChars(), td->ident->toChars(),
- tiargsBuf.peekChars(), fargsBuf.peekChars());
-
- // Display candidate templates (even if there are no multiple overloads)
- TemplateCandidateWalker tcw;
- tcw.loc = loc;
- tcw.numToDisplay = numOverloadsDisplay;
- overloadApply(td, &tcw, &TemplateCandidateWalker::fp);
- }
- else if (od)
- {
- ::error(loc, "none of the overloads of `%s` are callable using argument types !(%s)%s",
- od->ident->toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
- }
- else
- {
- assert(fd);
-
- bool hasOverloads = fd->overnext != NULL;
- TypeFunction *tf = fd->type->toTypeFunction();
- if (tthis && !MODimplicitConv(tthis->mod, tf->mod)) // modifier mismatch
- {
- OutBuffer thisBuf, funcBuf;
- MODMatchToBuffer(&thisBuf, tthis->mod, tf->mod);
- MODMatchToBuffer(&funcBuf, tf->mod, tthis->mod);
- if (hasOverloads)
- ::error(loc, "none of the overloads of `%s` are callable using a %sobject, candidates are:",
- fd->ident->toChars(), thisBuf.peekChars());
- else
- ::error(loc, "%smethod `%s` is not callable using a %sobject",
- funcBuf.peekChars(), fd->toPrettyChars(), thisBuf.peekChars());
- }
- else
- {
- //printf("tf = %s, args = %s\n", tf->deco, (*fargs)[0]->type->deco);
- if (hasOverloads)
- ::error(loc, "none of the overloads of `%s` are callable using argument types `%s`, candidates are:",
- fd->ident->toChars(), fargsBuf.peekChars());
- else
- {
- fd->error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
- fd->kind(), fd->toPrettyChars(), parametersTypeToChars(tf->parameterList),
- tf->modToChars(), fargsBuf.peekChars());
- if (failMessage)
- errorSupplemental(loc, failMessage);
- }
- }
-
- // Display candidate functions
- if (hasOverloads)
- {
- FuncCandidateWalker fcw;
- fcw.loc = loc;
- fcw.numToDisplay = numOverloadsDisplay;
- overloadApply(fd, &fcw, &FuncCandidateWalker::fp);
- }
- }
- }
- else if (m.nextf)
- {
- TypeFunction *tf1 = m.lastf->type->toTypeFunction();
- TypeFunction *tf2 = m.nextf->type->toTypeFunction();
- const char *lastprms = parametersTypeToChars(tf1->parameterList);
- const char *nextprms = parametersTypeToChars(tf2->parameterList);
- ::error(loc, "%s.%s called with argument types %s matches both:\n"
- "%s: %s%s\nand:\n%s: %s%s",
- s->parent->toPrettyChars(), s->ident->toChars(),
- fargsBuf.peekChars(),
- m.lastf->loc.toChars(), m.lastf->toPrettyChars(), lastprms,
- m.nextf->loc.toChars(), m.nextf->toPrettyChars(), nextprms);
- }
- return NULL;
-}
-
-/********************************
- * Labels are in a separate scope, one per function.
- */
-
-LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident)
-{ Dsymbol *s;
-
- if (!labtab)
- labtab = new DsymbolTable(); // guess we need one
-
- s = labtab->lookup(ident);
- if (!s)
- {
- s = new LabelDsymbol(ident);
- labtab->insert(s);
- }
- return (LabelDsymbol *)s;
-}
-
-/*****************************************
- * Determine lexical level difference from 'this' to nested function 'fd'.
- * Error if this cannot call fd.
- * Returns:
- * 0 same level
- * >0 decrease nesting by number
- * -1 increase nesting by 1 (fd is nested within 'this')
- * -2 error
- */
-
-int FuncDeclaration::getLevel(Loc loc, Scope *sc, FuncDeclaration *fd)
-{
- int level;
- Dsymbol *s;
- Dsymbol *fdparent;
-
- //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars());
- fdparent = fd->toParent2();
- if (fdparent == this)
- return -1;
- s = this;
- level = 0;
- while (fd != s && fdparent != s->toParent2())
- {
- //printf("\ts = %s, '%s'\n", s->kind(), s->toChars());
- FuncDeclaration *thisfd = s->isFuncDeclaration();
- if (thisfd)
- {
- if (!thisfd->isNested() && !thisfd->vthis && !sc->intypeof)
- goto Lerr;
- }
- else
- {
- AggregateDeclaration *thiscd = s->isAggregateDeclaration();
- if (thiscd)
- {
- /* AggregateDeclaration::isNested returns true only when
- * it has a hidden pointer.
- * But, calling the function belongs unrelated lexical scope
- * is still allowed inside typeof.
- *
- * struct Map(alias fun) {
- * typeof({ return fun(); }) RetType;
- * // No member function makes Map struct 'not nested'.
- * }
- */
- if (!thiscd->isNested() && !sc->intypeof)
- goto Lerr;
- }
- else
- goto Lerr;
- }
-
- s = s->toParent2();
- assert(s);
- level++;
- }
- return level;
-
-Lerr:
- // Don't give error if in template constraint
- if (!(sc->flags & SCOPEconstraint))
- {
- const char *xstatic = isStatic() ? "static " : "";
- // better diagnostics for static functions
- ::error(loc, "%s%s %s cannot access frame of function %s",
- xstatic, kind(), toPrettyChars(), fd->toPrettyChars());
- return -2;
- }
- return 1;
-}
-
-const char *FuncDeclaration::toPrettyChars(bool QualifyTypes)
-{
- if (isMain())
- return "D main";
- else
- return Dsymbol::toPrettyChars(QualifyTypes);
-}
-
-/** for diagnostics, e.g. 'int foo(int x, int y) pure' */
-const char *FuncDeclaration::toFullSignature()
-{
- OutBuffer buf;
- functionToBufferWithIdent(type->toTypeFunction(), &buf, toChars());
- return buf.extractChars();
-}
-
-bool FuncDeclaration::isMain()
-{
- return ident == Id::main &&
- linkage != LINKc && !isMember() && !isNested();
-}
-
-bool FuncDeclaration::isCMain()
-{
- return ident == Id::main &&
- linkage == LINKc && !isMember() && !isNested();
-}
-
-bool FuncDeclaration::isWinMain()
-{
- //printf("FuncDeclaration::isWinMain() %s\n", toChars());
- return ident == Id::WinMain &&
- linkage != LINKc && !isMember();
-}
-
-bool FuncDeclaration::isDllMain()
-{
- return ident == Id::DllMain &&
- linkage != LINKc && !isMember();
-}
-
-bool FuncDeclaration::isExport() const
-{
- return protection.kind == Prot::export_;
-}
-
-bool FuncDeclaration::isImportedSymbol() const
-{
- //printf("isImportedSymbol()\n");
- //printf("protection = %d\n", protection);
- return (protection.kind == Prot::export_) && !fbody;
-}
-
-// Determine if function goes into virtual function pointer table
-
-bool FuncDeclaration::isVirtual()
-{
- if (toAliasFunc() != this)
- return toAliasFunc()->isVirtual();
-
- Dsymbol *p = toParent();
- return isMember() &&
- !(isStatic() || protection.kind == Prot::private_ || protection.kind == Prot::package_) &&
- p->isClassDeclaration() &&
- !(p->isInterfaceDeclaration() && isFinalFunc());
-}
-
-// Determine if a function is pedantically virtual
-
-bool FuncDeclaration::isVirtualMethod()
-{
- if (toAliasFunc() != this)
- return toAliasFunc()->isVirtualMethod();
-
- //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
- if (!isVirtual())
- return false;
- // If it's a final method, and does not override anything, then it is not virtual
- if (isFinalFunc() && foverrides.length == 0)
- {
- return false;
- }
- return true;
-}
-
-bool FuncDeclaration::isFinalFunc()
-{
- if (toAliasFunc() != this)
- return toAliasFunc()->isFinalFunc();
-
- ClassDeclaration *cd;
- return isMember() &&
- (Declaration::isFinal() ||
- ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal));
-}
-
-bool FuncDeclaration::isCodeseg() const
-{
- return true; // functions are always in the code segment
-}
-
-bool FuncDeclaration::isOverloadable()
-{
- return true; // functions can be overloaded
-}
-
-PURE FuncDeclaration::isPure()
-{
- //printf("FuncDeclaration::isPure() '%s'\n", toChars());
- TypeFunction *tf = type->toTypeFunction();
- if (flags & FUNCFLAGpurityInprocess)
- setImpure();
- if (tf->purity == PUREfwdref)
- tf->purityLevel();
- PURE purity = tf->purity;
- if (purity > PUREweak && isNested())
- purity = PUREweak;
- if (purity > PUREweak && needThis())
- {
- // The attribute of the 'this' reference affects purity strength
- if (type->mod & MODimmutable)
- ;
- else if (type->mod & (MODconst | MODwild) && purity >= PUREconst)
- purity = PUREconst;
- else
- purity = PUREweak;
- }
- tf->purity = purity;
- // ^ This rely on the current situation that every FuncDeclaration has a
- // unique TypeFunction.
- return purity;
-}
-
-PURE FuncDeclaration::isPureBypassingInference()
-{
- if (flags & FUNCFLAGpurityInprocess)
- return PUREfwdref;
- else
- return isPure();
-}
-
-/**************************************
- * The function is doing something impure,
- * so mark it as impure.
- * If there's a purity error, return true.
- */
-bool FuncDeclaration::setImpure()
-{
- if (flags & FUNCFLAGpurityInprocess)
- {
- flags &= ~FUNCFLAGpurityInprocess;
- if (fes)
- fes->func->setImpure();
- }
- else if (isPure())
- return true;
- return false;
-}
-
-bool FuncDeclaration::isSafe()
-{
- if (flags & FUNCFLAGsafetyInprocess)
- setUnsafe();
- return type->toTypeFunction()->trust == TRUSTsafe;
-}
-
-bool FuncDeclaration::isSafeBypassingInference()
-{
- return !(flags & FUNCFLAGsafetyInprocess) && isSafe();
-}
-
-bool FuncDeclaration::isTrusted()
-{
- if (flags & FUNCFLAGsafetyInprocess)
- setUnsafe();
- return type->toTypeFunction()->trust == TRUSTtrusted;
-}
-
-/**************************************
- * The function is doing something unsave,
- * so mark it as unsafe.
- * If there's a safe error, return true.
- */
-bool FuncDeclaration::setUnsafe()
-{
- if (flags & FUNCFLAGsafetyInprocess)
- {
- flags &= ~FUNCFLAGsafetyInprocess;
- type->toTypeFunction()->trust = TRUSTsystem;
- if (fes)
- fes->func->setUnsafe();
- }
- else if (isSafe())
- return true;
- return false;
-}
-
-bool FuncDeclaration::isNogc()
-{
- if (flags & FUNCFLAGnogcInprocess)
- setGC();
- return type->toTypeFunction()->isnogc;
-}
-
-bool FuncDeclaration::isNogcBypassingInference()
-{
- return !(flags & FUNCFLAGnogcInprocess) && isNogc();
-}
-
-/**************************************
- * The function is doing something that may allocate with the GC,
- * so mark it as not nogc (not no-how).
- * Returns:
- * true if function is marked as @nogc, meaning a user error occurred
- */
-bool FuncDeclaration::setGC()
-{
- if (flags & FUNCFLAGnogcInprocess)
- {
- flags &= ~FUNCFLAGnogcInprocess;
- type->toTypeFunction()->isnogc = false;
- if (fes)
- fes->func->setGC();
- }
- else if (isNogc())
- return true;
- return false;
-}
-
-/**************************************
- * Returns an indirect type one step from t.
- */
-
-Type *getIndirection(Type *t)
-{
- t = t->baseElemOf();
- if (t->ty == Tarray || t->ty == Tpointer)
- return t->nextOf()->toBasetype();
- if (t->ty == Taarray || t->ty == Tclass)
- return t;
- if (t->ty == Tstruct)
- return t->hasPointers() ? t : NULL; // TODO
-
- // should consider TypeDelegate?
- return NULL;
-}
-
-/**************************************
- * Returns true if memory reachable through a reference B to a value of type tb,
- * which has been constructed with a reference A to a value of type ta
- * available, can alias memory reachable from A based on the types involved
- * (either directly or via any number of indirections).
- *
- * Note that this relation is not symmetric in the two arguments. For example,
- * a const(int) reference can point to a pre-existing int, but not the other
- * way round.
- */
-bool traverseIndirections(Type *ta, Type *tb, void *p = NULL, bool reversePass = false)
-{
- Type *source = ta;
- Type *target = tb;
- if (reversePass)
- {
- source = tb;
- target = ta;
- }
-
- if (source->constConv(target))
- return true;
- else if (target->ty == Tvoid && MODimplicitConv(source->mod, target->mod))
- return true;
-
- // No direct match, so try breaking up one of the types (starting with tb).
- Type *tbb = tb->toBasetype()->baseElemOf();
- if (tbb != tb)
- return traverseIndirections(ta, tbb, p, reversePass);
-
- // context date to detect circular look up
- struct Ctxt
- {
- Ctxt *prev;
- Type *type;
- };
- Ctxt *ctxt = (Ctxt *)p;
-
- if (tb->ty == Tclass || tb->ty == Tstruct)
- {
- for (Ctxt *c = ctxt; c; c = c->prev)
- if (tb == c->type) return false;
- Ctxt c;
- c.prev = ctxt;
- c.type = tb;
-
- AggregateDeclaration *sym = tb->toDsymbol(NULL)->isAggregateDeclaration();
- for (size_t i = 0; i < sym->fields.length; i++)
- {
- VarDeclaration *v = sym->fields[i];
- Type *tprmi = v->type->addMod(tb->mod);
- //printf("\ttb = %s, tprmi = %s\n", tb->toChars(), tprmi->toChars());
- if (traverseIndirections(ta, tprmi, &c, reversePass))
- return true;
- }
- }
- else if (tb->ty == Tarray || tb->ty == Taarray || tb->ty == Tpointer)
- {
- Type *tind = tb->nextOf();
- if (traverseIndirections(ta, tind, ctxt, reversePass))
- return true;
- }
- else if (tb->hasPointers())
- {
- // FIXME: function pointer/delegate types should be considered.
- return true;
- }
-
- // Still no match, so try breaking up ta if we have note done so yet.
- if (!reversePass)
- return traverseIndirections(tb, ta, ctxt, true);
-
- return false;
-}
-
-/********************************************
- * Returns true if the function return value has no indirection
- * which comes from the parameters.
- */
-
-bool FuncDeclaration::isolateReturn()
-{
- TypeFunction *tf = type->toTypeFunction();
- assert(tf->next);
-
- Type *treti = tf->next;
- treti = tf->isref ? treti : getIndirection(treti);
- if (!treti)
- return true; // target has no mutable indirection
- return parametersIntersect(treti);
-}
-
-/********************************************
- * Returns true if an object typed t can have indirections
- * which come from the parameters.
- */
-
-bool FuncDeclaration::parametersIntersect(Type *t)
-{
- assert(t);
- if (!isPureBypassingInference() || isNested())
- return false;
-
- TypeFunction *tf = type->toTypeFunction();
-
- //printf("parametersIntersect(%s) t = %s\n", tf->toChars(), t->toChars());
-
- size_t dim = tf->parameterList.length();
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *fparam = tf->parameterList[i];
- if (!fparam->type)
- continue;
- Type *tprmi = (fparam->storageClass & (STClazy | STCout | STCref))
- ? fparam->type : getIndirection(fparam->type);
- if (!tprmi)
- continue; // there is no mutable indirection
-
- //printf("\t[%d] tprmi = %d %s\n", i, tprmi->ty, tprmi->toChars());
- if (traverseIndirections(tprmi, t))
- return false;
- }
- if (AggregateDeclaration *ad = isCtorDeclaration() ? NULL : isThis())
- {
- Type *tthis = ad->getType()->addMod(tf->mod);
- //printf("\ttthis = %s\n", tthis->toChars());
- if (traverseIndirections(tthis, t))
- return false;
- }
-
- return true;
-}
-
-/****************************************
- * Determine if function needs a static frame pointer.
- * Returns:
- * `true` if function is really nested within other function.
- * Contracts:
- * If isNested() returns true, isThis() should return false.
- */
-bool FuncDeclaration::isNested()
-{
- FuncDeclaration *f = toAliasFunc();
- //printf("\ttoParent2() = '%s'\n", f->toParent2()->toChars());
- return ((f->storage_class & STCstatic) == 0) &&
- (f->linkage == LINKd) &&
- (f->toParent2()->isFuncDeclaration() != NULL);
-}
-
-/****************************************
- * Determine if function is a non-static member function
- * that has an implicit 'this' expression.
- * Returns:
- * The aggregate it is a member of, or null.
- * Contracts:
- * If isThis() returns true, isNested() should return false.
- */
-AggregateDeclaration *FuncDeclaration::isThis()
-{
- //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
- AggregateDeclaration *ad = (storage_class & STCstatic) ? NULL : isMember2();
- //printf("-FuncDeclaration::isThis() %p\n", ad);
- return ad;
-}
-
-bool FuncDeclaration::needThis()
-{
- //printf("FuncDeclaration::needThis() '%s'\n", toChars());
- return toAliasFunc()->isThis() != NULL;
-}
-
-bool FuncDeclaration::addPreInvariant()
-{
- AggregateDeclaration *ad = isThis();
- ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL;
- return (ad && !(cd && cd->isCPPclass()) &&
- global.params.useInvariants == CHECKENABLEon &&
- (protection.kind == Prot::protected_ || protection.kind == Prot::public_ || protection.kind == Prot::export_) &&
- !naked);
-}
-
-bool FuncDeclaration::addPostInvariant()
-{
- AggregateDeclaration *ad = isThis();
- ClassDeclaration *cd = ad ? ad->isClassDeclaration() : NULL;
- return (ad && !(cd && cd->isCPPclass()) &&
- ad->inv &&
- global.params.useInvariants == CHECKENABLEon &&
- (protection.kind == Prot::protected_ || protection.kind == Prot::public_ || protection.kind == Prot::export_) &&
- !naked);
-}
-
-/**********************************
- * Generate a FuncDeclaration for a runtime library function.
- */
-
-FuncDeclaration *FuncDeclaration::genCfunc(Parameters *fparams, Type *treturn, const char *name, StorageClass stc)
-{
- return genCfunc(fparams, treturn, Identifier::idPool(name), stc);
-}
-
-FuncDeclaration *FuncDeclaration::genCfunc(Parameters *fparams, Type *treturn, Identifier *id, StorageClass stc)
-{
- FuncDeclaration *fd;
- TypeFunction *tf;
- Dsymbol *s;
- static DsymbolTable *st = NULL;
-
- //printf("genCfunc(name = '%s')\n", id->toChars());
- //printf("treturn\n\t"); treturn->print();
-
- // See if already in table
- if (!st)
- st = new DsymbolTable();
- s = st->lookup(id);
- if (s)
- {
- fd = s->isFuncDeclaration();
- assert(fd);
- assert(fd->type->nextOf()->equals(treturn));
- }
- else
- {
- tf = new TypeFunction(ParameterList(fparams), treturn, LINKc, stc);
- fd = new FuncDeclaration(Loc(), Loc(), id, STCstatic, tf);
- fd->protection = Prot(Prot::public_);
- fd->linkage = LINKc;
-
- st->insert(fd);
- }
- return fd;
-}
-
-/******************
- * Check parameters and return type of D main() function.
- * Issue error messages.
- */
-void FuncDeclaration::checkDmain()
-{
- TypeFunction *tf = type->toTypeFunction();
- const size_t nparams = tf->parameterList.length();
- bool argerr = false;
- if (nparams == 1)
- {
- Parameter *fparam0 = tf->parameterList[0];
- Type *t = fparam0->type->toBasetype();
- if (t->ty != Tarray ||
- t->nextOf()->ty != Tarray ||
- t->nextOf()->nextOf()->ty != Tchar ||
- fparam0->storageClass & (STCout | STCref | STClazy))
- {
- argerr = true;
- }
- }
-
- if (!tf->nextOf())
- error("must return int or void");
- else if (tf->nextOf()->ty != Tint32 && tf->nextOf()->ty != Tvoid)
- error("must return int or void, not %s", tf->nextOf()->toChars());
- else if (tf->parameterList.varargs || nparams >= 2 || argerr)
- error("parameters must be main() or main(string[] args)");
-}
-
-/***********************************************
- * Check all return statements for a function to verify that returning
- * using NRVO is possible.
- *
- * Returns:
- * `false` if the result cannot be returned by hidden reference.
- */
-bool FuncDeclaration::checkNRVO()
-{
- if (!nrvo_can || returns == NULL)
- return false;
-
- TypeFunction *tf = type->toTypeFunction();
- if (tf->isref)
- return false;
-
- for (size_t i = 0; i < returns->length; i++)
- {
- ReturnStatement *rs = (*returns)[i];
-
- if (VarExp *ve = rs->exp->isVarExp())
- {
- VarDeclaration *v = ve->var->isVarDeclaration();
- if (!v || v->isOut() || v->isRef())
- return false;
- else if (nrvo_var == NULL)
- {
- // Variables in the data segment (e.g. globals, TLS or not),
- // parameters and closure variables cannot be NRVOed.
- if (v->isDataseg() || v->isParameter() || v->toParent2() != this)
- return false;
- //printf("Setting nrvo to %s\n", v->toChars());
- nrvo_var = v;
- }
- else if (nrvo_var != v)
- return false;
- }
- else //if (!exp->isLvalue()) // keep NRVO-ability
- return false;
- }
- return true;
-}
-
-const char *FuncDeclaration::kind() const
-{
- return generated ? "generated function" : "function";
-}
-
-/*********************************************
- * In the current function, we are calling 'this' function.
- * 1. Check to see if the current function can call 'this' function, issue error if not.
- * 2. If the current function is not the parent of 'this' function, then add
- * the current function to the list of siblings of 'this' function.
- * 3. If the current function is a literal, and it's accessing an uplevel scope,
- * then mark it as a delegate.
- * Returns true if error occurs.
- */
-bool FuncDeclaration::checkNestedReference(Scope *sc, Loc loc)
-{
- //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
-
- if (FuncLiteralDeclaration *fld = this->isFuncLiteralDeclaration())
- {
- if (fld->tok == TOKreserved)
- {
- fld->tok = TOKfunction;
- fld->vthis = NULL;
- }
- }
-
- if (!parent || parent == sc->parent)
- return false;
- if (ident == Id::require || ident == Id::ensure)
- return false;
- if (!isThis() && !isNested())
- return false;
-
- // The current function
- FuncDeclaration *fdthis = sc->parent->isFuncDeclaration();
- if (!fdthis)
- return false; // out of function scope
-
- Dsymbol *p = toParent2();
-
- // Function literals from fdthis to p must be delegates
- checkNestedRef(fdthis, p);
-
- if (isNested())
- {
- // The function that this function is in
- FuncDeclaration *fdv = p->isFuncDeclaration();
- if (!fdv)
- return false;
- if (fdv == fdthis)
- return false;
-
- //printf("this = %s in [%s]\n", this->toChars(), this->loc.toChars());
- //printf("fdv = %s in [%s]\n", fdv->toChars(), fdv->loc.toChars());
- //printf("fdthis = %s in [%s]\n", fdthis->toChars(), fdthis->loc.toChars());
-
- // Add this function to the list of those which called us
- if (fdthis != this)
- {
- bool found = false;
- for (size_t i = 0; i < siblingCallers.length; ++i)
- {
- if (siblingCallers[i] == fdthis)
- found = true;
- }
- if (!found)
- {
- //printf("\tadding sibling %s\n", fdthis->toPrettyChars());
- if (!sc->intypeof && !(sc->flags & SCOPEcompile))
- siblingCallers.push(fdthis);
- }
- }
-
- int lv = fdthis->getLevel(loc, sc, fdv);
- if (lv == -2)
- return true; // error
- if (lv == -1)
- return false; // downlevel call
- if (lv == 0)
- return false; // same level call
- // Uplevel call
- }
- return false;
-}
-
-/* For all functions between outerFunc and f, mark them as needing
- * a closure.
- */
-void markAsNeedingClosure(Dsymbol *f, FuncDeclaration *outerFunc)
-{
- for (Dsymbol *sx = f; sx && sx != outerFunc; sx = sx->parent)
- {
- FuncDeclaration *fy = sx->isFuncDeclaration();
- if (fy && fy->closureVars.length)
- {
- /* fy needs a closure if it has closureVars[],
- * because the frame pointer in the closure will be accessed.
- */
- fy->requiresClosure = true;
- }
- }
-}
-
-
-/* Given a nested function f inside a function outerFunc, check
- * if any sibling callers of f have escaped. If so, mark
- * all the enclosing functions as needing closures.
- * Return true if any closures were detected.
- * This is recursive: we need to check the callers of our siblings.
- * Note that nested functions can only call lexically earlier nested
- * functions, so loops are impossible.
- */
-bool checkEscapingSiblings(FuncDeclaration *f, FuncDeclaration *outerFunc, void *p = NULL)
-{
- struct PrevSibling
- {
- PrevSibling *p;
- FuncDeclaration *f;
- };
-
- PrevSibling ps;
- ps.p = (PrevSibling *)p;
- ps.f = f;
-
- //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f->toChars(), outerFunc->toChars());
- bool bAnyClosures = false;
- for (size_t i = 0; i < f->siblingCallers.length; ++i)
- {
- FuncDeclaration *g = f->siblingCallers[i];
- if (g->isThis() || g->tookAddressOf)
- {
- markAsNeedingClosure(g, outerFunc);
- bAnyClosures = true;
- }
-
- PrevSibling *prev = (PrevSibling *)p;
- while (1)
- {
- if (!prev)
- {
- bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
- break;
- }
- if (prev->f == g)
- break;
- prev = prev->p;
- }
- }
- //printf("\t%d\n", bAnyClosures);
- return bAnyClosures;
-}
-
-
-/*******************************
- * Look at all the variables in this function that are referenced
- * by nested functions, and determine if a closure needs to be
- * created for them.
- */
-
-bool FuncDeclaration::needsClosure()
-{
- /* Need a closure for all the closureVars[] if any of the
- * closureVars[] are accessed by a
- * function that escapes the scope of this function.
- * We take the conservative approach and decide that a function needs
- * a closure if it:
- * 1) is a virtual function
- * 2) has its address taken
- * 3) has a parent that escapes
- * 4) calls another nested function that needs a closure
- *
- * Note that since a non-virtual function can be called by
- * a virtual one, if that non-virtual function accesses a closure
- * var, the closure still has to be taken. Hence, we check for isThis()
- * instead of isVirtual(). (thanks to David Friedman)
- *
- * When the function returns a local struct or class, `requiresClosure`
- * is already set to `true` upon entering this function when the
- * struct/class refers to a local variable and a closure is needed.
- */
-
- //printf("FuncDeclaration::needsClosure() %s\n", toChars());
-
- if (requiresClosure)
- goto Lyes;
-
- for (size_t i = 0; i < closureVars.length; i++)
- {
- VarDeclaration *v = closureVars[i];
- //printf("\tv = %s\n", v->toChars());
-
- for (size_t j = 0; j < v->nestedrefs.length; j++)
- {
- FuncDeclaration *f = v->nestedrefs[j];
- assert(f != this);
-
- //printf("\t\tf = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf);
-
- /* Look to see if f escapes. We consider all parents of f within
- * this, and also all siblings which call f; if any of them escape,
- * so does f.
- * Mark all affected functions as requiring closures.
- */
- for (Dsymbol *s = f; s && s != this; s = s->parent)
- {
- FuncDeclaration *fx = s->isFuncDeclaration();
- if (!fx)
- continue;
- if (fx->isThis() || fx->tookAddressOf)
- {
- //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx->toChars(), fx->isVirtual(), fx->isThis(), fx->tookAddressOf);
-
- /* Mark as needing closure any functions between this and f
- */
- markAsNeedingClosure( (fx == f) ? fx->parent : fx, this);
-
- requiresClosure = true;
- }
-
- /* We also need to check if any sibling functions that
- * called us, have escaped. This is recursive: we need
- * to check the callers of our siblings.
- */
- if (checkEscapingSiblings(fx, this))
- requiresClosure = true;
-
- /* Bugzilla 12406: Iterate all closureVars to mark all descendant
- * nested functions that access to the closing context of this funciton.
- */
- }
- }
- }
- if (requiresClosure)
- goto Lyes;
-
- return false;
-
-Lyes:
- //printf("\tneeds closure\n");
- return true;
-}
-
-/***********************************************
- * Check that the function contains any closure.
- * If it's @nogc, report suitable errors.
- * This is mostly consistent with FuncDeclaration::needsClosure().
- *
- * Returns:
- * true if any errors occur.
- */
-bool FuncDeclaration::checkClosure()
-{
- if (!needsClosure())
- return false;
-
- if (setGC())
- {
- error("is @nogc yet allocates closures with the GC");
- if (global.gag) // need not report supplemental errors
- return true;
- }
- else
- {
- printGCUsage(loc, "using closure causes GC allocation");
- return false;
- }
-
- FuncDeclarations a;
- for (size_t i = 0; i < closureVars.length; i++)
- {
- VarDeclaration *v = closureVars[i];
-
- for (size_t j = 0; j < v->nestedrefs.length; j++)
- {
- FuncDeclaration *f = v->nestedrefs[j];
- assert(f != this);
-
- for (Dsymbol *s = f; s && s != this; s = s->parent)
- {
- FuncDeclaration *fx = s->isFuncDeclaration();
- if (!fx)
- continue;
- if (fx->isThis() || fx->tookAddressOf)
- goto Lfound;
- if (checkEscapingSiblings(fx, this))
- goto Lfound;
- }
- continue;
-
- Lfound:
- for (size_t k = 0; ; k++)
- {
- if (k == a.length)
- {
- a.push(f);
- ::errorSupplemental(f->loc, "%s closes over variable %s at %s",
- f->toPrettyChars(), v->toChars(), v->loc.toChars());
- break;
- }
- if (a[k] == f)
- break;
- }
- continue;
- }
- }
-
- return true;
-}
-
-/***********************************************
- * Determine if function's variables are referenced by a function
- * nested within it.
- */
-
-bool FuncDeclaration::hasNestedFrameRefs()
-{
- if (closureVars.length)
- return true;
-
- /* If a virtual function has contracts, assume its variables are referenced
- * by those contracts, even if they aren't. Because they might be referenced
- * by the overridden or overriding function's contracts.
- * This can happen because frequire and fensure are implemented as nested functions,
- * and they can be called directly by an overriding function and the overriding function's
- * context had better match, or Bugzilla 7335 will bite.
- */
- if (fdrequire || fdensure)
- return true;
-
- if (foverrides.length && isVirtualMethod())
- {
- for (size_t i = 0; i < foverrides.length; i++)
- {
- FuncDeclaration *fdv = foverrides[i];
- if (fdv->hasNestedFrameRefs())
- return true;
- }
- }
-
- return false;
-}
-
-/*********************************************
- * Return the function's parameter list, and whether
- * it is variadic or not.
- */
-
-ParameterList FuncDeclaration::getParameterList()
-{
- if (type)
- {
- TypeFunction *fdtype = type->toTypeFunction();
- return fdtype->parameterList;
- }
-
- return ParameterList();
-}
-
-
-/****************************** FuncAliasDeclaration ************************/
-
-// Used as a way to import a set of functions from another scope into this one.
-
-FuncAliasDeclaration::FuncAliasDeclaration(Identifier *ident, FuncDeclaration *funcalias, bool hasOverloads)
- : FuncDeclaration(funcalias->loc, funcalias->endloc, ident,
- funcalias->storage_class, funcalias->type)
-{
- assert(funcalias != this);
- this->funcalias = funcalias;
-
- this->hasOverloads = hasOverloads;
- if (hasOverloads)
- {
- if (FuncAliasDeclaration *fad = funcalias->isFuncAliasDeclaration())
- this->hasOverloads = fad->hasOverloads;
- }
- else
- { // for internal use
- assert(!funcalias->isFuncAliasDeclaration());
- this->hasOverloads = false;
- }
- userAttribDecl = funcalias->userAttribDecl;
-}
-
-const char *FuncAliasDeclaration::kind() const
-{
- return "function alias";
-}
-
-FuncDeclaration *FuncAliasDeclaration::toAliasFunc()
-{
- return funcalias->toAliasFunc();
-}
-
-
-/****************************** FuncLiteralDeclaration ************************/
-
-FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type,
- TOK tok, ForeachStatement *fes, Identifier *id)
- : FuncDeclaration(loc, endloc, NULL, STCundefined, type)
-{
- this->ident = id ? id : Id::empty;
- this->tok = tok;
- this->fes = fes;
- this->treq = NULL;
- this->deferToObj = false;
- //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars());
-}
-
-Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s)
-{
- //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
- assert(!s);
- FuncLiteralDeclaration *f = new FuncLiteralDeclaration(loc, endloc,
- type->syntaxCopy(), tok, fes, ident);
- f->treq = treq; // don't need to copy
- return FuncDeclaration::syntaxCopy(f);
-}
-
-bool FuncLiteralDeclaration::isNested()
-{
- //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
- return (tok != TOKfunction) && !isThis();
-}
-
-AggregateDeclaration *FuncLiteralDeclaration::isThis()
-{
- //printf("FuncLiteralDeclaration::isThis() '%s'\n", toChars());
- return tok == TOKdelegate ? FuncDeclaration::isThis() : NULL;
-}
-
-bool FuncLiteralDeclaration::isVirtual()
-{
- return false;
-}
-
-bool FuncLiteralDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool FuncLiteralDeclaration::addPostInvariant()
-{
- return false;
-}
-
-/*******************************
- * Modify all expression type of return statements to tret.
- *
- * On function literals, return type may be modified based on the context type
- * after its semantic3 is done, in FuncExp::implicitCastTo.
- *
- * A function() dg = (){ return new B(); } // OK if is(B : A) == true
- *
- * If B to A conversion is convariant that requires offseet adjusting,
- * all return statements should be adjusted to return expressions typed A.
- */
-void FuncLiteralDeclaration::modifyReturns(Scope *sc, Type *tret)
-{
- class RetWalker : public StatementRewriteWalker
- {
- public:
- Scope *sc;
- Type *tret;
- FuncLiteralDeclaration *fld;
-
- void visit(ReturnStatement *s)
- {
- Expression *exp = s->exp;
- if (exp && !exp->type->equals(tret))
- {
- s->exp = exp->castTo(sc, tret);
- }
- }
- };
-
- if (semanticRun < PASSsemantic3done)
- return;
-
- if (fes)
- return;
-
- RetWalker w;
- w.sc = sc;
- w.tret = tret;
- w.fld = this;
- fbody->accept(&w);
-
- // Also update the inferred function type to match the new return type.
- // This is required so the code generator does not try to cast the
- // modified returns back to the original type.
- if (inferRetType && type->nextOf() != tret)
- type->toTypeFunction()->next = tret;
-}
-
-const char *FuncLiteralDeclaration::kind() const
-{
- return (tok != TOKfunction) ? "delegate" : "function";
-}
-
-const char *FuncLiteralDeclaration::toPrettyChars(bool QualifyTypes)
-{
- if (parent)
- {
- TemplateInstance *ti = parent->isTemplateInstance();
- if (ti)
- return ti->tempdecl->toPrettyChars(QualifyTypes);
- }
- return Dsymbol::toPrettyChars(QualifyTypes);
-}
-
-/********************************* CtorDeclaration ****************************/
-
-CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type)
- : FuncDeclaration(loc, endloc, Id::ctor, stc, type)
-{
- //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars());
-}
-
-Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- CtorDeclaration *f = new CtorDeclaration(loc, endloc, storage_class, type->syntaxCopy());
- return FuncDeclaration::syntaxCopy(f);
-}
-
-const char *CtorDeclaration::kind() const
-{
- return "constructor";
-}
-
-const char *CtorDeclaration::toChars()
-{
- return "this";
-}
-
-bool CtorDeclaration::isVirtual()
-{
- return false;
-}
-
-bool CtorDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool CtorDeclaration::addPostInvariant()
-{
- return (isThis() && vthis && global.params.useInvariants == CHECKENABLEon);
-}
-
-
-/********************************* PostBlitDeclaration ****************************/
-
-PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id)
- : FuncDeclaration(loc, endloc, id, stc, NULL)
-{
-}
-
-Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
- return FuncDeclaration::syntaxCopy(dd);
-}
-
-bool PostBlitDeclaration::overloadInsert(Dsymbol *)
-{
- return false; // cannot overload postblits
-}
-
-bool PostBlitDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool PostBlitDeclaration::addPostInvariant()
-{
- return (isThis() && vthis && global.params.useInvariants == CHECKENABLEon);
-}
-
-bool PostBlitDeclaration::isVirtual()
-{
- return false;
-}
-
-/********************************* DtorDeclaration ****************************/
-
-DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc)
- : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL)
-{
-}
-
-DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id)
- : FuncDeclaration(loc, endloc, id, stc, NULL)
-{
-}
-
-Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- DtorDeclaration *dd = new DtorDeclaration(loc, endloc, storage_class, ident);
- return FuncDeclaration::syntaxCopy(dd);
-}
-
-bool DtorDeclaration::overloadInsert(Dsymbol *)
-{
- return false; // cannot overload destructors
-}
-
-bool DtorDeclaration::addPreInvariant()
-{
- return (isThis() && vthis && global.params.useInvariants == CHECKENABLEon);
-}
-
-bool DtorDeclaration::addPostInvariant()
-{
- return false;
-}
-
-const char *DtorDeclaration::kind() const
-{
- return "destructor";
-}
-
-const char *DtorDeclaration::toChars()
-{
- return "~this";
-}
-
-bool DtorDeclaration::isVirtual()
-{
- // false so that dtor's don't get put into the vtbl[]
- return false;
-}
-
-/********************************* StaticCtorDeclaration ****************************/
-
-StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
- : FuncDeclaration(loc, endloc,
- Identifier::generateId("_staticCtor"), STCstatic | stc, NULL)
-{
-}
-
-StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc)
- : FuncDeclaration(loc, endloc,
- Identifier::generateId(name), STCstatic | stc, NULL)
-{
-}
-
-Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- StaticCtorDeclaration *scd = new StaticCtorDeclaration(loc, endloc, storage_class);
- return FuncDeclaration::syntaxCopy(scd);
-}
-
-AggregateDeclaration *StaticCtorDeclaration::isThis()
-{
- return NULL;
-}
-
-bool StaticCtorDeclaration::isVirtual()
-{
- return false;
-}
-
-bool StaticCtorDeclaration::hasStaticCtorOrDtor()
-{
- return true;
-}
-
-bool StaticCtorDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool StaticCtorDeclaration::addPostInvariant()
-{
- return false;
-}
-
-/********************************* SharedStaticCtorDeclaration ****************************/
-
-SharedStaticCtorDeclaration::SharedStaticCtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
- : StaticCtorDeclaration(loc, endloc, "_sharedStaticCtor", stc)
-{
-}
-
-Dsymbol *SharedStaticCtorDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- SharedStaticCtorDeclaration *scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
- return FuncDeclaration::syntaxCopy(scd);
-}
-
-/********************************* StaticDtorDeclaration ****************************/
-
-StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
- : FuncDeclaration(loc, endloc,
- Identifier::generateId("_staticDtor"), STCstatic | stc, NULL)
-{
- vgate = NULL;
-}
-
-StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, const char *name, StorageClass stc)
- : FuncDeclaration(loc, endloc,
- Identifier::generateId(name), STCstatic | stc, NULL)
-{
- vgate = NULL;
-}
-
-Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- StaticDtorDeclaration *sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
- return FuncDeclaration::syntaxCopy(sdd);
-}
-
-AggregateDeclaration *StaticDtorDeclaration::isThis()
-{
- return NULL;
-}
-
-bool StaticDtorDeclaration::isVirtual()
-{
- return false;
-}
-
-bool StaticDtorDeclaration::hasStaticCtorOrDtor()
-{
- return true;
-}
-
-bool StaticDtorDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool StaticDtorDeclaration::addPostInvariant()
-{
- return false;
-}
-
-/********************************* SharedStaticDtorDeclaration ****************************/
-
-SharedStaticDtorDeclaration::SharedStaticDtorDeclaration(Loc loc, Loc endloc, StorageClass stc)
- : StaticDtorDeclaration(loc, endloc, "_sharedStaticDtor", stc)
-{
-}
-
-Dsymbol *SharedStaticDtorDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- SharedStaticDtorDeclaration *sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
- return FuncDeclaration::syntaxCopy(sdd);
-}
-
-/********************************* InvariantDeclaration ****************************/
-
-InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc, StorageClass stc, Identifier *id)
- : FuncDeclaration(loc, endloc,
- id ? id : Identifier::generateId("__invariant"),
- stc, NULL)
-{
-}
-
-Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- InvariantDeclaration *id = new InvariantDeclaration(loc, endloc, storage_class);
- return FuncDeclaration::syntaxCopy(id);
-}
-
-bool InvariantDeclaration::isVirtual()
-{
- return false;
-}
-
-bool InvariantDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool InvariantDeclaration::addPostInvariant()
-{
- return false;
-}
-
-/********************************* UnitTestDeclaration ****************************/
-
-/*******************************
- * Generate unique unittest function Id so we can have multiple
- * instances per module.
- */
-
-static Identifier *unitTestId(Loc loc)
-{
- OutBuffer buf;
- buf.printf("__unittestL%u_", loc.linnum);
- return Identifier::generateId(buf.peekChars());
-}
-
-UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc, StorageClass stc, char *codedoc)
- : FuncDeclaration(loc, endloc, unitTestId(loc), stc, NULL)
-{
- this->codedoc = codedoc;
-}
-
-Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- UnitTestDeclaration *utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
- return FuncDeclaration::syntaxCopy(utd);
-}
-
-AggregateDeclaration *UnitTestDeclaration::isThis()
-{
- return NULL;
-}
-
-bool UnitTestDeclaration::isVirtual()
-{
- return false;
-}
-
-bool UnitTestDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool UnitTestDeclaration::addPostInvariant()
-{
- return false;
-}
-
-/********************************* NewDeclaration ****************************/
-
-NewDeclaration::NewDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *fparams, VarArg varargs)
- : FuncDeclaration(loc, endloc, Id::classNew, STCstatic | stc, NULL)
-{
- this->parameters = fparams;
- this->varargs = varargs;
-}
-
-Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- NewDeclaration *f = new NewDeclaration(loc, endloc,
- storage_class, Parameter::arraySyntaxCopy(parameters), varargs);
- return FuncDeclaration::syntaxCopy(f);
-}
-
-const char *NewDeclaration::kind() const
-{
- return "allocator";
-}
-
-bool NewDeclaration::isVirtual()
-{
- return false;
-}
-
-bool NewDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool NewDeclaration::addPostInvariant()
-{
- return false;
-}
-
-/********************************* DeleteDeclaration ****************************/
-
-DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, StorageClass stc, Parameters *fparams)
- : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic | stc, NULL)
-{
- this->parameters = fparams;
-}
-
-Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- DeleteDeclaration *f = new DeleteDeclaration(loc, endloc,
- storage_class, Parameter::arraySyntaxCopy(parameters));
- return FuncDeclaration::syntaxCopy(f);
-}
-
-const char *DeleteDeclaration::kind() const
-{
- return "deallocator";
-}
-
-bool DeleteDeclaration::isDelete()
-{
- return true;
-}
-
-bool DeleteDeclaration::isVirtual()
-{
- return false;
-}
-
-bool DeleteDeclaration::addPreInvariant()
-{
- return false;
-}
-
-bool DeleteDeclaration::addPostInvariant()
-{
- return false;
-}
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
new file mode 100644
index 0000000..7f0b0bb
--- /dev/null
+++ b/gcc/d/dmd/func.d
@@ -0,0 +1,4102 @@
+/**
+ * Defines a function declaration.
+ *
+ * Includes:
+ * - function/delegate literals
+ * - function aliases
+ * - (static/shared) constructors/destructors/post-blits
+ * - `invariant`
+ * - `unittest`
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/func.d, _func.d)
+ * Documentation: https://dlang.org/phobos/dmd_func.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/func.d
+ */
+
+module dmd.func;
+
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.blockexit;
+import dmd.gluelayer;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.delegatize;
+import dmd.dinterpret;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.escape;
+import dmd.expression;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.mtype;
+import dmd.objc;
+import dmd.root.outbuffer;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.root.stringtable;
+import dmd.semantic2;
+import dmd.semantic3;
+import dmd.statement_rewrite_walker;
+import dmd.statement;
+import dmd.statementsem;
+import dmd.tokens;
+import dmd.visitor;
+
+/// Inline Status
+enum ILS : ubyte
+{
+ uninitialized, /// not computed yet
+ no, /// cannot inline
+ yes, /// can inline
+}
+
+enum BUILTIN : ubyte
+{
+ unknown = 255, /// not known if this is a builtin
+ unimp = 0, /// this is not a builtin
+ gcc, /// this is a GCC builtin
+ llvm, /// this is an LLVM builtin
+ sin,
+ cos,
+ tan,
+ sqrt,
+ fabs,
+ ldexp,
+ log,
+ log2,
+ log10,
+ exp,
+ expm1,
+ exp2,
+ round,
+ floor,
+ ceil,
+ trunc,
+ copysign,
+ pow,
+ fmin,
+ fmax,
+ fma,
+ isnan,
+ isinfinity,
+ isfinite,
+ bsf,
+ bsr,
+ bswap,
+ popcnt,
+ yl2x,
+ yl2xp1,
+ toPrecFloat,
+ toPrecDouble,
+ toPrecReal
+}
+
+/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
+ */
+extern (C++) final class NrvoWalker : StatementRewriteWalker
+{
+ alias visit = typeof(super).visit;
+public:
+ FuncDeclaration fd;
+ Scope* sc;
+
+ override void visit(ReturnStatement s)
+ {
+ // See if all returns are instead to be replaced with a goto returnLabel;
+ if (fd.returnLabel)
+ {
+ /* Rewrite:
+ * return exp;
+ * as:
+ * vresult = exp; goto Lresult;
+ */
+ auto gs = new GotoStatement(s.loc, Id.returnLabel);
+ gs.label = fd.returnLabel;
+
+ Statement s1 = gs;
+ if (s.exp)
+ s1 = new CompoundStatement(s.loc, new ExpStatement(s.loc, s.exp), gs);
+
+ replaceCurrent(s1);
+ }
+ }
+
+ override void visit(TryFinallyStatement s)
+ {
+ DtorExpStatement des;
+ if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
+ fd.nrvo_var == des.var)
+ {
+ if (!(global.params.useExceptions && ClassDeclaration.throwable))
+ {
+ /* Don't need to call destructor at all, since it is nrvo
+ */
+ replaceCurrent(s._body);
+ s._body.accept(this);
+ return;
+ }
+
+ /* Normally local variable dtors are called regardless exceptions.
+ * But for nrvo_var, its dtor should be called only when exception is thrown.
+ *
+ * Rewrite:
+ * try { s.body; } finally { nrvo_var.edtor; }
+ * // equivalent with:
+ * // s.body; scope(exit) nrvo_var.edtor;
+ * as:
+ * try { s.body; } catch(Throwable __o) { nrvo_var.edtor; throw __o; }
+ * // equivalent with:
+ * // s.body; scope(failure) nrvo_var.edtor;
+ */
+ Statement sexception = new DtorExpStatement(Loc.initial, fd.nrvo_var.edtor, fd.nrvo_var);
+ Identifier id = Identifier.generateId("__o");
+
+ Statement handler = new PeelStatement(sexception);
+ if (sexception.blockExit(fd, false) & BE.fallthru)
+ {
+ auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
+ ts.internalThrow = true;
+ handler = new CompoundStatement(Loc.initial, handler, ts);
+ }
+
+ auto catches = new Catches();
+ auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
+ ctch.internalCatch = true;
+ ctch.catchSemantic(sc); // Run semantic to resolve identifier '__o'
+ catches.push(ctch);
+
+ Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
+ fd.eh_none = false;
+ replaceCurrent(s2);
+ s2.accept(this);
+ }
+ else
+ StatementRewriteWalker.visit(s);
+ }
+}
+
+enum FUNCFLAG : uint
+{
+ purityInprocess = 1, /// working on determining purity
+ safetyInprocess = 2, /// working on determining safety
+ nothrowInprocess = 4, /// working on determining nothrow
+ nogcInprocess = 8, /// working on determining @nogc
+ returnInprocess = 0x10, /// working on inferring 'return' for parameters
+ inlineScanned = 0x20, /// function has been scanned for inline possibilities
+ inferScope = 0x40, /// infer 'scope' for parameters
+ hasCatches = 0x80, /// function has try-catch statements
+ compileTimeOnly = 0x100, /// is a compile time only function; no code will be generated for it
+ printf = 0x200, /// is a printf-like function
+ scanf = 0x400, /// is a scanf-like function
+ noreturn = 0x800, /// the function does not return
+}
+
+/***********************************************************
+ * Tuple of result identifier (possibly null) and statement.
+ * This is used to store out contracts: out(id){ ensure }
+ */
+extern (C++) struct Ensure
+{
+ Identifier id;
+ Statement ensure;
+
+ Ensure syntaxCopy()
+ {
+ return Ensure(id, ensure.syntaxCopy());
+ }
+
+ /*****************************************
+ * Do syntax copy of an array of Ensure's.
+ */
+ static Ensures* arraySyntaxCopy(Ensures* a)
+ {
+ Ensures* b = null;
+ if (a)
+ {
+ b = a.copy();
+ foreach (i, e; *a)
+ {
+ (*b)[i] = e.syntaxCopy();
+ }
+ }
+ return b;
+ }
+
+}
+
+/***********************************************************
+ */
+extern (C++) class FuncDeclaration : Declaration
+{
+ Statements* frequires; /// in contracts
+ Ensures* fensures; /// out contracts
+ Statement frequire; /// lowered in contract
+ Statement fensure; /// lowered out contract
+ Statement fbody; /// function body
+
+ FuncDeclarations foverrides; /// functions this function overrides
+ FuncDeclaration fdrequire; /// function that does the in contract
+ FuncDeclaration fdensure; /// function that does the out contract
+
+ Expressions* fdrequireParams; /// argument list for __require
+ Expressions* fdensureParams; /// argument list for __ensure
+
+ const(char)* mangleString; /// mangled symbol created from mangleExact()
+
+ VarDeclaration vresult; /// result variable for out contracts
+ LabelDsymbol returnLabel; /// where the return goes
+
+ // used to prevent symbols in different
+ // scopes from having the same name
+ DsymbolTable localsymtab;
+ VarDeclaration vthis; /// 'this' parameter (member and nested)
+ bool isThis2; /// has a dual-context 'this' parameter
+ VarDeclaration v_arguments; /// '_arguments' parameter
+
+ VarDeclaration v_argptr; /// '_argptr' variable
+ VarDeclarations* parameters; /// Array of VarDeclaration's for parameters
+ DsymbolTable labtab; /// statement label symbol table
+ Dsymbol overnext; /// next in overload list
+ FuncDeclaration overnext0; /// next in overload list (only used during IFTI)
+ Loc endloc; /// location of closing curly bracket
+ int vtblIndex = -1; /// for member functions, index into vtbl[]
+ bool naked; /// true if naked
+ bool generated; /// true if function was generated by the compiler rather than
+ /// supplied by the user
+ bool hasAlwaysInlines; /// contains references to functions that must be inlined
+ ubyte isCrtCtorDtor; /// has attribute pragma(crt_constructor(1)/crt_destructor(2))
+ /// not set before the glue layer
+
+ ILS inlineStatusStmt = ILS.uninitialized;
+ ILS inlineStatusExp = ILS.uninitialized;
+ PINLINE inlining = PINLINE.default_;
+
+ int inlineNest; /// !=0 if nested inline
+ bool eh_none; /// true if no exception unwinding is needed
+
+ bool semantic3Errors; /// true if errors in semantic3 this function's frame ptr
+ ForeachStatement fes; /// if foreach body, this is the foreach
+ BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[]
+ bool introducing; /// true if 'introducing' function
+ /** if !=NULL, then this is the type
+ of the 'introducing' function
+ this one is overriding
+ */
+ Type tintro;
+
+ bool inferRetType; /// true if return type is to be inferred
+ StorageClass storage_class2; /// storage class for template onemember's
+
+ // Things that should really go into Scope
+
+ /// 1 if there's a return exp; statement
+ /// 2 if there's a throw statement
+ /// 4 if there's an assert(0)
+ /// 8 if there's inline asm
+ /// 16 if there are multiple return statements
+ int hasReturnExp;
+
+ // Support for NRVO (named return value optimization)
+ bool nrvo_can = true; /// true means we can do NRVO
+ VarDeclaration nrvo_var; /// variable to replace with shidden
+ Symbol* shidden; /// hidden pointer passed to function
+
+ ReturnStatements* returns;
+
+ GotoStatements* gotos; /// Gotos with forward references
+
+ /// set if this is a known, builtin function we can evaluate at compile time
+ BUILTIN builtin = BUILTIN.unknown;
+
+ /// set if someone took the address of this function
+ int tookAddressOf;
+
+ bool requiresClosure; // this function needs a closure
+
+ /** local variables in this function which are referenced by nested functions
+ * (They'll get put into the "closure" for this function.)
+ */
+ VarDeclarations closureVars;
+
+ /** Outer variables which are referenced by this nested function
+ * (the inverse of closureVars)
+ */
+ VarDeclarations outerVars;
+
+ /// Sibling nested functions which called this one
+ FuncDeclarations siblingCallers;
+
+ FuncDeclarations *inlinedNestedCallees;
+
+ uint flags; /// FUNCFLAG.xxxxx
+
+ /**
+ * Data for a function declaration that is needed for the Objective-C
+ * integration.
+ */
+ ObjcFuncDeclaration objc;
+
+ extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type, bool noreturn = false)
+ {
+ super(loc, ident);
+ //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type);
+ //printf("storage_class = x%x\n", storage_class);
+ this.storage_class = storage_class;
+ this.type = type;
+ if (type)
+ {
+ // Normalize storage_class, because function-type related attributes
+ // are already set in the 'type' in parsing phase.
+ this.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
+ }
+ this.endloc = endloc;
+ if (noreturn)
+ this.flags |= FUNCFLAG.noreturn;
+
+ /* The type given for "infer the return type" is a TypeFunction with
+ * NULL for the return type.
+ */
+ inferRetType = (type && type.nextOf() is null);
+ }
+
+ static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
+ {
+ return new FuncDeclaration(loc, endloc, id, storage_class, type, noreturn);
+ }
+
+ override FuncDeclaration syntaxCopy(Dsymbol s)
+ {
+ //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars());
+ FuncDeclaration f = s ? cast(FuncDeclaration)s
+ : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), (flags & FUNCFLAG.noreturn) != 0);
+ f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null;
+ f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null;
+ f.fbody = fbody ? fbody.syntaxCopy() : null;
+ return f;
+ }
+
+ /****************************************************
+ * Resolve forward reference of function signature -
+ * parameter types, return type, and attributes.
+ * Returns:
+ * false if any errors exist in the signature.
+ */
+ final bool functionSemantic()
+ {
+ //printf("functionSemantic() %p %s\n", this, toChars());
+ if (!_scope)
+ return !errors;
+
+ this.cppnamespace = _scope.namespace;
+
+ if (!originalType) // semantic not yet run
+ {
+ TemplateInstance spec = isSpeculative();
+ uint olderrs = global.errors;
+ uint oldgag = global.gag;
+ if (global.gag && !spec)
+ global.gag = 0;
+ dsymbolSemantic(this, _scope);
+ global.gag = oldgag;
+ if (spec && global.errors != olderrs)
+ spec.errors = (global.errors - olderrs != 0);
+ if (olderrs != global.errors) // if errors compiling this function
+ return false;
+ }
+
+ // if inferring return type, sematic3 needs to be run
+ // - When the function body contains any errors, we cannot assume
+ // the inferred return type is valid.
+ // So, the body errors should become the function signature error.
+ if (inferRetType && type && !type.nextOf())
+ return functionSemantic3();
+
+ TemplateInstance ti;
+ if (isInstantiated() && !isVirtualMethod() &&
+ ((ti = parent.isTemplateInstance()) is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident))
+ {
+ AggregateDeclaration ad = isMemberLocal();
+ if (ad && ad.sizeok != Sizeok.done)
+ {
+ /* Currently dmd cannot resolve forward references per methods,
+ * then setting SIZOKfwd is too conservative and would break existing code.
+ * So, just stop method attributes inference until ad.dsymbolSemantic() done.
+ */
+ //ad.sizeok = Sizeok.fwd;
+ }
+ else
+ return functionSemantic3() || !errors;
+ }
+
+ if (storage_class & STC.inference)
+ return functionSemantic3() || !errors;
+
+ return !errors;
+ }
+
+ /****************************************************
+ * Resolve forward reference of function body.
+ * Returns false if any errors exist in the body.
+ */
+ final bool functionSemantic3()
+ {
+ if (semanticRun < PASS.semantic3 && _scope)
+ {
+ /* Forward reference - we need to run semantic3 on this function.
+ * If errors are gagged, and it's not part of a template instance,
+ * we need to temporarily ungag errors.
+ */
+ TemplateInstance spec = isSpeculative();
+ uint olderrs = global.errors;
+ uint oldgag = global.gag;
+ if (global.gag && !spec)
+ global.gag = 0;
+ semantic3(this, _scope);
+ global.gag = oldgag;
+
+ // If it is a speculatively-instantiated template, and errors occur,
+ // we need to mark the template as having errors.
+ if (spec && global.errors != olderrs)
+ spec.errors = (global.errors - olderrs != 0);
+ if (olderrs != global.errors) // if errors compiling this function
+ return false;
+ }
+
+ return !errors && !semantic3Errors;
+ }
+
+ /****************************************************
+ * Check that this function type is properly resolved.
+ * If not, report "forward reference error" and return true.
+ */
+ extern (D) final bool checkForwardRef(const ref Loc loc)
+ {
+ if (!functionSemantic())
+ return true;
+
+ /* No deco means the functionSemantic() call could not resolve
+ * forward referenes in the type of this function.
+ */
+ if (!type.deco)
+ {
+ bool inSemantic3 = (inferRetType && semanticRun >= PASS.semantic3);
+ .error(loc, "forward reference to %s`%s`",
+ (inSemantic3 ? "inferred return type of function " : "").ptr,
+ toChars());
+ return true;
+ }
+ return false;
+ }
+
+ // called from semantic3
+ /**
+ * Creates and returns the hidden parameters for this function declaration.
+ *
+ * Hidden parameters include the `this` parameter of a class, struct or
+ * nested function and the selector parameter for Objective-C methods.
+ */
+ extern (D) final void declareThis(Scope* sc)
+ {
+ isThis2 = toParent2() != toParentLocal();
+ auto ad = isThis();
+ if (!isThis2 && !ad && !isNested())
+ {
+ vthis = null;
+ objc.selectorParameter = null;
+ return;
+ }
+
+ Type addModStc(Type t)
+ {
+ return t.addMod(type.mod).addStorageClass(storage_class);
+ }
+
+ if (isThis2 || isNested())
+ {
+ /* The 'this' for a nested function is the link to the
+ * enclosing function's stack frame.
+ * Note that nested functions and member functions are disjoint.
+ */
+ Type tthis = addModStc(isThis2 ?
+ Type.tvoidptr.sarrayOf(2).pointerTo() :
+ Type.tvoid.pointerTo());
+ vthis = new VarDeclaration(loc, tthis, isThis2 ? Id.this2 : Id.capture, null);
+ vthis.storage_class |= STC.parameter | STC.nodtor;
+ }
+ else if (ad)
+ {
+ Type thandle = addModStc(ad.handleType());
+ vthis = new ThisDeclaration(loc, thandle);
+ vthis.storage_class |= STC.parameter;
+ if (thandle.ty == Tstruct)
+ {
+ vthis.storage_class |= STC.ref_;
+ // if member function is marked 'inout', then 'this' is 'return ref'
+ if (type.ty == Tfunction && (cast(TypeFunction)type).isInOutQual())
+ vthis.storage_class |= STC.return_;
+ }
+ }
+
+ if (auto tf = type.isTypeFunction())
+ {
+ if (tf.isreturn)
+ vthis.storage_class |= STC.return_;
+ if (tf.isScopeQual)
+ vthis.storage_class |= STC.scope_;
+
+ /* Add STC.returnScope like typesem.d does for TypeFunction parameters,
+ * at least it should be the same. At the moment, we'll just
+ * do existing practice. But we should examine how TypeFunction does
+ * it, for consistency.
+ */
+ if (!tf.isref && isRefReturnScope(vthis.storage_class))
+ {
+ /* if `ref return scope`, evaluate to `ref` `return scope`
+ */
+ vthis.storage_class |= STC.returnScope;
+ }
+ }
+ if (flags & FUNCFLAG.inferScope && !(vthis.storage_class & STC.scope_))
+ vthis.storage_class |= STC.maybescope;
+
+ vthis.dsymbolSemantic(sc);
+ if (!sc.insert(vthis))
+ assert(0);
+ vthis.parent = this;
+ if (ad)
+ objc.selectorParameter = .objc.createSelectorParameter(this, sc);
+ }
+
+ override final bool equals(const RootObject o) const
+ {
+ if (this == o)
+ return true;
+
+ if (auto s = isDsymbol(o))
+ {
+ auto fd1 = this;
+ auto fd2 = s.isFuncDeclaration();
+ if (!fd2)
+ return false;
+
+ auto fa1 = fd1.isFuncAliasDeclaration();
+ auto faf1 = fa1 ? fa1.toAliasFunc() : fd1;
+
+ auto fa2 = fd2.isFuncAliasDeclaration();
+ auto faf2 = fa2 ? fa2.toAliasFunc() : fd2;
+
+ if (fa1 && fa2)
+ {
+ return faf1.equals(faf2) && fa1.hasOverloads == fa2.hasOverloads;
+ }
+
+ bool b1 = fa1 !is null;
+ if (b1 && faf1.isUnique() && !fa1.hasOverloads)
+ b1 = false;
+
+ bool b2 = fa2 !is null;
+ if (b2 && faf2.isUnique() && !fa2.hasOverloads)
+ b2 = false;
+
+ if (b1 != b2)
+ return false;
+
+ return faf1.toParent().equals(faf2.toParent()) &&
+ faf1.ident.equals(faf2.ident) &&
+ faf1.type.equals(faf2.type);
+ }
+ return false;
+ }
+
+ /****************************************************
+ * Determine if 'this' overrides fd.
+ * Return !=0 if it does.
+ */
+ final int overrides(FuncDeclaration fd)
+ {
+ int result = 0;
+ if (fd.ident == ident)
+ {
+ const cov = type.covariant(fd.type);
+ if (cov != Covariant.distinct)
+ {
+ ClassDeclaration cd1 = toParent().isClassDeclaration();
+ ClassDeclaration cd2 = fd.toParent().isClassDeclaration();
+ if (cd1 && cd2 && cd2.isBaseOf(cd1, null))
+ result = 1;
+ }
+ }
+ return result;
+ }
+
+ /*************************************************
+ * Find index of function in vtbl[0..dim] that
+ * this function overrides.
+ * Prefer an exact match to a covariant one.
+ * Params:
+ * vtbl = vtable to use
+ * dim = maximal vtable dimension
+ * Returns:
+ * -1 didn't find one
+ * -2 can't determine because of forward references
+ */
+ final int findVtblIndex(Dsymbols* vtbl, int dim)
+ {
+ //printf("findVtblIndex() %s\n", toChars());
+ FuncDeclaration mismatch = null;
+ StorageClass mismatchstc = 0;
+ int mismatchvi = -1;
+ int exactvi = -1;
+ int bestvi = -1;
+ for (int vi = 0; vi < dim; vi++)
+ {
+ FuncDeclaration fdv = (*vtbl)[vi].isFuncDeclaration();
+ if (fdv && fdv.ident == ident)
+ {
+ if (type.equals(fdv.type)) // if exact match
+ {
+ if (fdv.parent.isClassDeclaration())
+ {
+ if (fdv.isFuture())
+ {
+ bestvi = vi;
+ continue; // keep looking
+ }
+ return vi; // no need to look further
+ }
+
+ if (exactvi >= 0)
+ {
+ error("cannot determine overridden function");
+ return exactvi;
+ }
+ exactvi = vi;
+ bestvi = vi;
+ continue;
+ }
+
+ StorageClass stc = 0;
+ const cov = type.covariant(fdv.type, &stc);
+ //printf("\tbaseclass cov = %d\n", cov);
+ final switch (cov)
+ {
+ case Covariant.distinct:
+ // types are distinct
+ break;
+
+ case Covariant.yes:
+ bestvi = vi; // covariant, but not identical
+ break;
+ // keep looking for an exact match
+
+ case Covariant.no:
+ mismatchvi = vi;
+ mismatchstc = stc;
+ mismatch = fdv; // overrides, but is not covariant
+ break;
+ // keep looking for an exact match
+
+ case Covariant.fwdref:
+ return -2; // forward references
+ }
+ }
+ }
+ if (bestvi == -1 && mismatch)
+ {
+ //type.print();
+ //mismatch.type.print();
+ //printf("%s %s\n", type.deco, mismatch.type.deco);
+ //printf("stc = %llx\n", mismatchstc);
+ if (mismatchstc)
+ {
+ // Fix it by modifying the type to add the storage classes
+ type = type.addStorageClass(mismatchstc);
+ bestvi = mismatchvi;
+ }
+ }
+ return bestvi;
+ }
+
+ /*********************************
+ * If function a function in a base class,
+ * return that base class.
+ * Returns:
+ * base class if overriding, null if not
+ */
+ final BaseClass* overrideInterface()
+ {
+ if (ClassDeclaration cd = toParent2().isClassDeclaration())
+ {
+ foreach (b; cd.interfaces)
+ {
+ auto v = findVtblIndex(&b.sym.vtbl, cast(int)b.sym.vtbl.dim);
+ if (v >= 0)
+ return b;
+ }
+ }
+ return null;
+ }
+
+ /****************************************************
+ * Overload this FuncDeclaration with the new one f.
+ * Return true if successful; i.e. no conflict.
+ */
+ override bool overloadInsert(Dsymbol s)
+ {
+ //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
+ assert(s != this);
+ AliasDeclaration ad = s.isAliasDeclaration();
+ if (ad)
+ {
+ if (overnext)
+ return overnext.overloadInsert(ad);
+ if (!ad.aliassym && ad.type.ty != Tident && ad.type.ty != Tinstance && ad.type.ty != Ttypeof)
+ {
+ //printf("\tad = '%s'\n", ad.type.toChars());
+ return false;
+ }
+ overnext = ad;
+ //printf("\ttrue: no conflict\n");
+ return true;
+ }
+ TemplateDeclaration td = s.isTemplateDeclaration();
+ if (td)
+ {
+ if (!td.funcroot)
+ td.funcroot = this;
+ if (overnext)
+ return overnext.overloadInsert(td);
+ overnext = td;
+ return true;
+ }
+ FuncDeclaration fd = s.isFuncDeclaration();
+ if (!fd)
+ return false;
+
+ version (none)
+ {
+ /* Disable this check because:
+ * const void foo();
+ * semantic() isn't run yet on foo(), so the const hasn't been
+ * applied yet.
+ */
+ if (type)
+ {
+ printf("type = %s\n", type.toChars());
+ printf("fd.type = %s\n", fd.type.toChars());
+ }
+ // fd.type can be NULL for overloaded constructors
+ if (type && fd.type && fd.type.covariant(type) && fd.type.mod == type.mod && !isFuncAliasDeclaration())
+ {
+ //printf("\tfalse: conflict %s\n", kind());
+ return false;
+ }
+ }
+
+ if (overnext)
+ {
+ td = overnext.isTemplateDeclaration();
+ if (td)
+ fd.overloadInsert(td);
+ else
+ return overnext.overloadInsert(fd);
+ }
+ overnext = fd;
+ //printf("\ttrue: no conflict\n");
+ return true;
+ }
+
+ /********************************************
+ * Find function in overload list that exactly matches t.
+ */
+ extern (D) final FuncDeclaration overloadExactMatch(Type t)
+ {
+ FuncDeclaration fd;
+ overloadApply(this, (Dsymbol s)
+ {
+ auto f = s.isFuncDeclaration();
+ if (!f)
+ return 0;
+ if (t.equals(f.type))
+ {
+ fd = f;
+ return 1;
+ }
+
+ /* Allow covariant matches, as long as the return type
+ * is just a const conversion.
+ * This allows things like pure functions to match with an impure function type.
+ */
+ if (t.ty == Tfunction)
+ {
+ auto tf = cast(TypeFunction)f.type;
+ if (tf.covariant(t) == Covariant.yes &&
+ tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
+ {
+ fd = f;
+ return 1;
+ }
+ }
+ return 0;
+ });
+ return fd;
+ }
+
+ /********************************************
+ * Find function in overload list that matches to the 'this' modifier.
+ * There's four result types.
+ *
+ * 1. If the 'tthis' matches only one candidate, it's an "exact match".
+ * Returns the function and 'hasOverloads' is set to false.
+ * eg. If 'tthis" is mutable and there's only one mutable method.
+ * 2. If there's two or more match candidates, but a candidate function will be
+ * a "better match".
+ * Returns the better match function but 'hasOverloads' is set to true.
+ * eg. If 'tthis' is mutable, and there's both mutable and const methods,
+ * the mutable method will be a better match.
+ * 3. If there's two or more match candidates, but there's no better match,
+ * Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
+ * eg. If 'tthis' is mutable, and there's two or more mutable methods.
+ * 4. If there's no candidates, it's "no match" and returns null with error report.
+ * e.g. If 'tthis' is const but there's no const methods.
+ */
+ extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
+ {
+ //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
+ MatchAccumulator m;
+ overloadApply(this, (Dsymbol s)
+ {
+ auto f = s.isFuncDeclaration();
+ if (!f || f == m.lastf) // skip duplicates
+ return 0;
+
+ auto tf = f.type.toTypeFunction();
+ //printf("tf = %s\n", tf.toChars());
+
+ MATCH match;
+ if (tthis) // non-static functions are preferred than static ones
+ {
+ if (f.needThis())
+ match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
+ else
+ match = MATCH.constant; // keep static function in overload candidates
+ }
+ else // static functions are preferred than non-static ones
+ {
+ if (f.needThis())
+ match = MATCH.convert;
+ else
+ match = MATCH.exact;
+ }
+ if (match == MATCH.nomatch)
+ return 0;
+
+ if (match > m.last) goto LcurrIsBetter;
+ if (match < m.last) goto LlastIsBetter;
+
+ // See if one of the matches overrides the other.
+ if (m.lastf.overrides(f)) goto LlastIsBetter;
+ if (f.overrides(m.lastf)) goto LcurrIsBetter;
+
+ //printf("\tambiguous\n");
+ m.nextf = f;
+ m.count++;
+ return 0;
+
+ LlastIsBetter:
+ //printf("\tlastbetter\n");
+ m.count++; // count up
+ return 0;
+
+ LcurrIsBetter:
+ //printf("\tisbetter\n");
+ if (m.last <= MATCH.convert)
+ {
+ // clear last secondary matching
+ m.nextf = null;
+ m.count = 0;
+ }
+ m.last = match;
+ m.lastf = f;
+ m.count++; // count up
+ return 0;
+ });
+
+ if (m.count == 1) // exact match
+ {
+ hasOverloads = false;
+ }
+ else if (m.count > 1) // better or ambiguous match
+ {
+ hasOverloads = true;
+ }
+ else // no match
+ {
+ hasOverloads = true;
+ auto tf = this.type.toTypeFunction();
+ assert(tthis);
+ assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
+ {
+ OutBuffer thisBuf, funcBuf;
+ MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
+ MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
+ .error(loc, "%smethod %s is not callable using a %sobject",
+ funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
+ }
+ }
+ return m.lastf;
+ }
+
+ /********************************************
+ * find function template root in overload list
+ */
+ extern (D) final TemplateDeclaration findTemplateDeclRoot()
+ {
+ FuncDeclaration f = this;
+ while (f && f.overnext)
+ {
+ //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
+ TemplateDeclaration td = f.overnext.isTemplateDeclaration();
+ if (td)
+ return td;
+ f = f.overnext.isFuncDeclaration();
+ }
+ return null;
+ }
+
+ /********************************************
+ * Returns true if function was declared
+ * directly or indirectly in a unittest block
+ */
+ final bool inUnittest()
+ {
+ Dsymbol f = this;
+ do
+ {
+ if (f.isUnitTestDeclaration())
+ return true;
+ f = f.toParent();
+ }
+ while (f);
+ return false;
+ }
+
+ /*************************************
+ * Determine partial specialization order of 'this' vs g.
+ * This is very similar to TemplateDeclaration::leastAsSpecialized().
+ * Returns:
+ * match 'this' is at least as specialized as g
+ * 0 g is more specialized than 'this'
+ */
+ final MATCH leastAsSpecialized(FuncDeclaration g)
+ {
+ enum LOG_LEASTAS = 0;
+ static if (LOG_LEASTAS)
+ {
+ printf("%s.leastAsSpecialized(%s)\n", toChars(), g.toChars());
+ printf("%s, %s\n", type.toChars(), g.type.toChars());
+ }
+
+ /* This works by calling g() with f()'s parameters, and
+ * if that is possible, then f() is at least as specialized
+ * as g() is.
+ */
+
+ TypeFunction tf = type.toTypeFunction();
+ TypeFunction tg = g.type.toTypeFunction();
+
+ /* If both functions have a 'this' pointer, and the mods are not
+ * the same and g's is not const, then this is less specialized.
+ */
+ if (needThis() && g.needThis() && tf.mod != tg.mod)
+ {
+ if (isCtorDeclaration())
+ {
+ if (!MODimplicitConv(tg.mod, tf.mod))
+ return MATCH.nomatch;
+ }
+ else
+ {
+ if (!MODimplicitConv(tf.mod, tg.mod))
+ return MATCH.nomatch;
+ }
+ }
+
+ /* Create a dummy array of arguments out of the parameters to f()
+ */
+ Expressions args;
+ foreach (u, p; tf.parameterList)
+ {
+ Expression e;
+ if (p.isReference())
+ {
+ e = new IdentifierExp(Loc.initial, p.ident);
+ e.type = p.type;
+ }
+ else
+ e = p.type.defaultInitLiteral(Loc.initial);
+ args.push(e);
+ }
+
+ MATCH m = tg.callMatch(null, args[], 1);
+ if (m > MATCH.nomatch)
+ {
+ /* A variadic parameter list is less specialized than a
+ * non-variadic one.
+ */
+ if (tf.parameterList.varargs && !tg.parameterList.varargs)
+ goto L1; // less specialized
+
+ static if (LOG_LEASTAS)
+ {
+ printf(" matches %d, so is least as specialized\n", m);
+ }
+ return m;
+ }
+ L1:
+ static if (LOG_LEASTAS)
+ {
+ printf(" doesn't match, so is not as specialized\n");
+ }
+ return MATCH.nomatch;
+ }
+
+ /********************************
+ * Searches for a label with the given identifier. This function will insert a new
+ * `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`.
+ *
+ * Params:
+ * ident = identifier of the requested label
+ * loc = location used when creating a new `LabelDsymbol`
+ *
+ * Returns: the `LabelDsymbol` for `ident`
+ */
+ final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc = Loc.initial)
+ {
+ Dsymbol s;
+ if (!labtab)
+ labtab = new DsymbolTable(); // guess we need one
+
+ s = labtab.lookup(ident);
+ if (!s)
+ {
+ s = new LabelDsymbol(ident, loc);
+ labtab.insert(s);
+ }
+ return cast(LabelDsymbol)s;
+ }
+
+ /*****************************************
+ * Determine lexical level difference from `this` to nested function `fd`.
+ * Params:
+ * fd = target of call
+ * intypeof = !=0 if inside typeof
+ * Returns:
+ * 0 same level
+ * >0 decrease nesting by number
+ * -1 increase nesting by 1 (`fd` is nested within `this`)
+ * LevelError error, `this` cannot call `fd`
+ */
+ final int getLevel(FuncDeclaration fd, int intypeof)
+ {
+ //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd.toChars());
+ Dsymbol fdparent = fd.toParent2();
+ if (fdparent == this)
+ return -1;
+
+ Dsymbol s = this;
+ int level = 0;
+ while (fd != s && fdparent != s.toParent2())
+ {
+ //printf("\ts = %s, '%s'\n", s.kind(), s.toChars());
+ if (auto thisfd = s.isFuncDeclaration())
+ {
+ if (!thisfd.isNested() && !thisfd.vthis && !intypeof)
+ return LevelError;
+ }
+ else
+ {
+ if (auto thiscd = s.isAggregateDeclaration())
+ {
+ /* AggregateDeclaration::isNested returns true only when
+ * it has a hidden pointer.
+ * But, calling the function belongs unrelated lexical scope
+ * is still allowed inside typeof.
+ *
+ * struct Map(alias fun) {
+ * typeof({ return fun(); }) RetType;
+ * // No member function makes Map struct 'not nested'.
+ * }
+ */
+ if (!thiscd.isNested() && !intypeof)
+ return LevelError;
+ }
+ else
+ return LevelError;
+ }
+
+ s = s.toParentP(fd);
+ assert(s);
+ level++;
+ }
+ return level;
+ }
+
+ /***********************************
+ * Determine lexical level difference from `this` to nested function `fd`.
+ * Issue error if `this` cannot call `fd`.
+ *
+ * Params:
+ * loc = location for error messages
+ * sc = context
+ * fd = target of call
+ * decl = The `Declaration` that triggered this check.
+ * Used to provide a better error message only.
+ * Returns:
+ * 0 same level
+ * >0 decrease nesting by number
+ * -1 increase nesting by 1 (`fd` is nested within 'this')
+ * LevelError error
+ */
+ final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd,
+ Declaration decl)
+ {
+ int level = getLevel(fd, sc.intypeof);
+ if (level != LevelError)
+ return level;
+
+ // Don't give error if in template constraint
+ if (!(sc.flags & SCOPE.constraint))
+ {
+ const(char)* xstatic = isStatic() ? "`static` " : "";
+ // better diagnostics for static functions
+ .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
+ xstatic, kind(), toPrettyChars(), decl.kind(), decl.toChars(),
+ fd.toPrettyChars());
+ .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
+ return LevelError;
+ }
+ return 1;
+ }
+
+ enum LevelError = -2;
+
+ override const(char)* toPrettyChars(bool QualifyTypes = false)
+ {
+ if (isMain())
+ return "D main";
+ else
+ return Dsymbol.toPrettyChars(QualifyTypes);
+ }
+
+ /** for diagnostics, e.g. 'int foo(int x, int y) pure' */
+ final const(char)* toFullSignature()
+ {
+ OutBuffer buf;
+ functionToBufferWithIdent(type.toTypeFunction(), &buf, toChars(), isStatic);
+ return buf.extractChars();
+ }
+
+ final bool isMain() const
+ {
+ return ident == Id.main && linkage != LINK.c && !isMember() && !isNested();
+ }
+
+ final bool isCMain() const
+ {
+ return ident == Id.main && linkage == LINK.c && !isMember() && !isNested();
+ }
+
+ final bool isWinMain() const
+ {
+ //printf("FuncDeclaration::isWinMain() %s\n", toChars());
+ version (none)
+ {
+ bool x = ident == Id.WinMain && linkage != LINK.c && !isMember();
+ printf("%s\n", x ? "yes" : "no");
+ return x;
+ }
+ else
+ {
+ return ident == Id.WinMain && linkage != LINK.c && !isMember();
+ }
+ }
+
+ final bool isDllMain() const
+ {
+ return ident == Id.DllMain && linkage != LINK.c && !isMember();
+ }
+
+ final bool isRtInit() const
+ {
+ return ident == Id.rt_init && linkage == LINK.c && !isMember() && !isNested();
+ }
+
+ override final bool isExport() const
+ {
+ return visibility.kind == Visibility.Kind.export_;
+ }
+
+ override final bool isImportedSymbol() const
+ {
+ //printf("isImportedSymbol()\n");
+ //printf("protection = %d\n", visibility);
+ return (visibility.kind == Visibility.Kind.export_) && !fbody;
+ }
+
+ override final bool isCodeseg() const pure nothrow @nogc @safe
+ {
+ return true; // functions are always in the code segment
+ }
+
+ override final bool isOverloadable() const
+ {
+ return true; // functions can be overloaded
+ }
+
+ /***********************************
+ * Override so it can work even if semantic() hasn't yet
+ * been run.
+ */
+ override final bool isAbstract()
+ {
+ if (storage_class & STC.abstract_)
+ return true;
+ if (semanticRun >= PASS.semanticdone)
+ return false;
+
+ if (_scope)
+ {
+ if (_scope.stc & STC.abstract_)
+ return true;
+ parent = _scope.parent;
+ Dsymbol parent = toParent();
+ if (parent.isInterfaceDeclaration())
+ return true;
+ }
+ return false;
+ }
+
+ /**********************************
+ * Decide if attributes for this function can be inferred from examining
+ * the function body.
+ * Returns:
+ * true if can
+ */
+ final bool canInferAttributes(Scope* sc)
+ {
+ if (!fbody)
+ return false;
+
+ if (isVirtualMethod())
+ return false; // since they may be overridden
+
+ if (sc.func &&
+ /********** this is for backwards compatibility for the moment ********/
+ (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
+ return true;
+
+ if (isFuncLiteralDeclaration() || // externs are not possible with literals
+ (storage_class & STC.inference) || // do attribute inference
+ (inferRetType && !isCtorDeclaration()))
+ return true;
+
+ if (isInstantiated())
+ {
+ auto ti = parent.isTemplateInstance();
+ if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
+ return true;
+ }
+
+ return false;
+ }
+
+ /*****************************************
+ * Initialize for inferring the attributes of this function.
+ */
+ final void initInferAttributes()
+ {
+ //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars());
+ TypeFunction tf = type.toTypeFunction();
+ if (tf.purity == PURE.impure) // purity not specified
+ flags |= FUNCFLAG.purityInprocess;
+
+ if (tf.trust == TRUST.default_)
+ flags |= FUNCFLAG.safetyInprocess;
+
+ if (!tf.isnothrow)
+ flags |= FUNCFLAG.nothrowInprocess;
+
+ if (!tf.isnogc)
+ flags |= FUNCFLAG.nogcInprocess;
+
+ if (!isVirtual() || introducing)
+ flags |= FUNCFLAG.returnInprocess;
+
+ // Initialize for inferring STC.scope_
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ flags |= FUNCFLAG.inferScope;
+ }
+
+ final PURE isPure()
+ {
+ //printf("FuncDeclaration::isPure() '%s'\n", toChars());
+ TypeFunction tf = type.toTypeFunction();
+ if (flags & FUNCFLAG.purityInprocess)
+ setImpure();
+ if (tf.purity == PURE.fwdref)
+ tf.purityLevel();
+ PURE purity = tf.purity;
+ if (purity > PURE.weak && isNested())
+ purity = PURE.weak;
+ if (purity > PURE.weak && needThis())
+ {
+ // The attribute of the 'this' reference affects purity strength
+ if (type.mod & MODFlags.immutable_)
+ {
+ }
+ else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
+ purity = PURE.const_;
+ else
+ purity = PURE.weak;
+ }
+ tf.purity = purity;
+ // ^ This rely on the current situation that every FuncDeclaration has a
+ // unique TypeFunction.
+ return purity;
+ }
+
+ final PURE isPureBypassingInference()
+ {
+ if (flags & FUNCFLAG.purityInprocess)
+ return PURE.fwdref;
+ else
+ return isPure();
+ }
+
+ /**************************************
+ * The function is doing something impure,
+ * so mark it as impure.
+ * If there's a purity error, return true.
+ */
+ extern (D) final bool setImpure()
+ {
+ if (flags & FUNCFLAG.purityInprocess)
+ {
+ flags &= ~FUNCFLAG.purityInprocess;
+ if (fes)
+ fes.func.setImpure();
+ }
+ else if (isPure())
+ return true;
+ return false;
+ }
+
+ final bool isSafe()
+ {
+ if (flags & FUNCFLAG.safetyInprocess)
+ setUnsafe();
+ return type.toTypeFunction().trust == TRUST.safe;
+ }
+
+ final bool isSafeBypassingInference()
+ {
+ return !(flags & FUNCFLAG.safetyInprocess) && isSafe();
+ }
+
+ final bool isTrusted()
+ {
+ if (flags & FUNCFLAG.safetyInprocess)
+ setUnsafe();
+ return type.toTypeFunction().trust == TRUST.trusted;
+ }
+
+ /**************************************
+ * The function is doing something unsafe,
+ * so mark it as unsafe.
+ * If there's a safe error, return true.
+ */
+ extern (D) final bool setUnsafe()
+ {
+ if (flags & FUNCFLAG.safetyInprocess)
+ {
+ flags &= ~FUNCFLAG.safetyInprocess;
+ type.toTypeFunction().trust = TRUST.system;
+ if (fes)
+ fes.func.setUnsafe();
+ }
+ else if (isSafe())
+ return true;
+ return false;
+ }
+
+ final bool isNogc()
+ {
+ //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess));
+ if (flags & FUNCFLAG.nogcInprocess)
+ setGC();
+ return type.toTypeFunction().isnogc;
+ }
+
+ final bool isNogcBypassingInference()
+ {
+ return !(flags & FUNCFLAG.nogcInprocess) && isNogc();
+ }
+
+ /**************************************
+ * The function is doing something that may allocate with the GC,
+ * so mark it as not nogc (not no-how).
+ * Returns:
+ * true if function is marked as @nogc, meaning a user error occurred
+ */
+ extern (D) final bool setGC()
+ {
+ //printf("setGC() %s\n", toChars());
+ if (flags & FUNCFLAG.nogcInprocess && semanticRun < PASS.semantic3 && _scope)
+ {
+ this.semantic2(_scope);
+ this.semantic3(_scope);
+ }
+
+ if (flags & FUNCFLAG.nogcInprocess)
+ {
+ flags &= ~FUNCFLAG.nogcInprocess;
+ type.toTypeFunction().isnogc = false;
+ if (fes)
+ fes.func.setGC();
+ }
+ else if (isNogc())
+ return true;
+ return false;
+ }
+
+ extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn)
+ {
+ if (!global.params.vgc)
+ return;
+
+ Module m = getModule();
+ if (m && m.isRoot() && !inUnittest())
+ {
+ message(loc, "vgc: %s", warn);
+ }
+ }
+
+ /********************************************
+ * See if pointers from function parameters, mutable globals, or uplevel functions
+ * could leak into return value.
+ * Returns:
+ * true if the function return value is isolated from
+ * any inputs to the function
+ */
+ extern (D) final bool isReturnIsolated()
+ {
+ //printf("isReturnIsolated(this: %s)\n", this.toChars);
+ TypeFunction tf = type.toTypeFunction();
+ assert(tf.next);
+
+ Type treti = tf.next;
+ if (tf.isref)
+ return isTypeIsolatedIndirect(treti); // check influence from parameters
+
+ return isTypeIsolated(treti);
+ }
+
+ /********************
+ * See if pointers from function parameters, mutable globals, or uplevel functions
+ * could leak into type `t`.
+ * Params:
+ * t = type to check if it is isolated
+ * Returns:
+ * true if `t` is isolated from
+ * any inputs to the function
+ */
+ extern (D) final bool isTypeIsolated(Type t)
+ {
+ StringTable!Type parentTypes;
+ parentTypes._init();
+ return isTypeIsolated(t, parentTypes);
+ }
+
+ ///ditto
+ extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
+ {
+ //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
+
+ t = t.baseElemOf();
+ switch (t.ty)
+ {
+ case Tarray:
+ case Tpointer:
+ return isTypeIsolatedIndirect(t.nextOf()); // go down one level
+
+ case Taarray:
+ case Tclass:
+ return isTypeIsolatedIndirect(t);
+
+ case Tstruct:
+ /* Drill down and check the struct's fields
+ */
+ auto sym = t.toDsymbol(null).isStructDeclaration();
+ const tName = t.toChars.toDString;
+ const entry = parentTypes.insert(tName, t);
+ if (entry == null)
+ {
+ //we've already seen this type in a parent, not isolated
+ return false;
+ }
+ foreach (v; sym.fields)
+ {
+ Type tmi = v.type.addMod(t.mod);
+ //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
+ // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
+ if (!isTypeIsolated(tmi, parentTypes))
+ return false;
+ }
+ return true;
+
+ default:
+ return true;
+ }
+ }
+
+ /********************************************
+ * Params:
+ * t = type of object to test one level of indirection down
+ * Returns:
+ * true if an object typed `t` has no indirections
+ * which could have come from the function's parameters, mutable
+ * globals, or uplevel functions.
+ */
+ private bool isTypeIsolatedIndirect(Type t)
+ {
+ //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
+ assert(t);
+
+ /* Since `t` is one level down from an indirection, it could pick
+ * up a reference to a mutable global or an outer function, so
+ * return false.
+ */
+ if (!isPureBypassingInference() || isNested())
+ return false;
+
+ TypeFunction tf = type.toTypeFunction();
+
+ //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
+
+ foreach (i, fparam; tf.parameterList)
+ {
+ Type tp = fparam.type;
+ if (!tp)
+ continue;
+
+ if (fparam.storageClass & (STC.lazy_ | STC.out_ | STC.ref_))
+ {
+ if (!traverseIndirections(tp, t))
+ return false;
+ continue;
+ }
+
+ /* Goes down one level of indirection, then calls traverseIndirection() on
+ * the result.
+ * Returns:
+ * true if t is isolated from tp
+ */
+ static bool traverse(Type tp, Type t)
+ {
+ tp = tp.baseElemOf();
+ switch (tp.ty)
+ {
+ case Tarray:
+ case Tpointer:
+ return traverseIndirections(tp.nextOf(), t);
+
+ case Taarray:
+ case Tclass:
+ return traverseIndirections(tp, t);
+
+ case Tstruct:
+ /* Drill down and check the struct's fields
+ */
+ auto sym = tp.toDsymbol(null).isStructDeclaration();
+ foreach (v; sym.fields)
+ {
+ Type tprmi = v.type.addMod(tp.mod);
+ //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
+ if (!traverse(tprmi, t))
+ return false;
+ }
+ return true;
+
+ default:
+ return true;
+ }
+ }
+
+ if (!traverse(tp, t))
+ return false;
+ }
+ // The 'this' reference is a parameter, too
+ if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
+ {
+ Type tthis = ad.getType().addMod(tf.mod);
+ //printf("\ttthis = %s\n", tthis.toChars());
+ if (!traverseIndirections(tthis, t))
+ return false;
+ }
+
+ return true;
+ }
+
+ /****************************************
+ * Determine if function needs a static frame pointer.
+ * Returns:
+ * `true` if function is really nested within other function.
+ * Contracts:
+ * If isNested() returns true, isThis() should return false,
+ * unless the function needs a dual-context pointer.
+ */
+ bool isNested() const
+ {
+ auto f = toAliasFunc();
+ //printf("\ttoParent2() = '%s'\n", f.toParent2().toChars());
+ return ((f.storage_class & STC.static_) == 0) &&
+ (f.linkage == LINK.d) &&
+ (f.toParent2().isFuncDeclaration() !is null ||
+ f.toParent2() !is f.toParentLocal());
+ }
+
+ /****************************************
+ * Determine if function is a non-static member function
+ * that has an implicit 'this' expression.
+ * Returns:
+ * The aggregate it is a member of, or null.
+ * Contracts:
+ * Both isThis() and isNested() should return true if function needs a dual-context pointer,
+ * otherwise if isThis() returns true, isNested() should return false.
+ */
+ override inout(AggregateDeclaration) isThis() inout
+ {
+ //printf("+FuncDeclaration::isThis() '%s'\n", toChars());
+ auto ad = (storage_class & STC.static_) ? .objc.isThis(this) : isMemberLocal();
+ //printf("-FuncDeclaration::isThis() %p\n", ad);
+ return ad;
+ }
+
+ override final bool needThis()
+ {
+ //printf("FuncDeclaration::needThis() '%s'\n", toChars());
+ return toAliasFunc().isThis() !is null;
+ }
+
+ // Determine if a function is pedantically virtual
+ final bool isVirtualMethod()
+ {
+ if (toAliasFunc() != this)
+ return toAliasFunc().isVirtualMethod();
+
+ //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars());
+ if (!isVirtual())
+ return false;
+ // If it's a final method, and does not override anything, then it is not virtual
+ if (isFinalFunc() && foverrides.dim == 0)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ // Determine if function goes into virtual function pointer table
+ bool isVirtual() const
+ {
+ if (toAliasFunc() != this)
+ return toAliasFunc().isVirtual();
+
+ auto p = toParent();
+
+ if (!isMember || !p.isClassDeclaration)
+ return false;
+
+ if (p.isClassDeclaration.classKind == ClassKind.objc)
+ return .objc.isVirtual(this);
+
+ version (none)
+ {
+ printf("FuncDeclaration::isVirtual(%s)\n", toChars());
+ printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), visibility == Visibility.Kind.private_, isCtorDeclaration(), linkage != LINK.d);
+ printf("result is %d\n", isMember() && !(isStatic() || visibility == Visibility.Kind.private_ || visibility == Visibility.Kind.package_) && p.isClassDeclaration() && !(p.isInterfaceDeclaration() && isFinalFunc()));
+ }
+ return !(isStatic() || visibility.kind == Visibility.Kind.private_ || visibility.kind == Visibility.Kind.package_) && !(p.isInterfaceDeclaration() && isFinalFunc());
+ }
+
+ final bool isFinalFunc() const
+ {
+ if (toAliasFunc() != this)
+ return toAliasFunc().isFinalFunc();
+
+ version (none)
+ {{
+ auto cd = toParent().isClassDeclaration();
+ printf("FuncDeclaration::isFinalFunc(%s), %x\n", toChars(), Declaration.isFinal());
+ printf("%p %d %d %d\n", isMember(), isStatic(), Declaration.isFinal(), ((cd = toParent().isClassDeclaration()) !is null && cd.storage_class & STC.final_));
+ printf("result is %d\n", isMember() && (Declaration.isFinal() || (cd !is null && cd.storage_class & STC.final_)));
+ if (cd)
+ printf("\tmember of %s\n", cd.toChars());
+ }}
+ if (!isMember())
+ return false;
+ if (Declaration.isFinal())
+ return true;
+ auto cd = toParent().isClassDeclaration();
+ return (cd !is null) && (cd.storage_class & STC.final_);
+ }
+
+ bool addPreInvariant()
+ {
+ auto ad = isThis();
+ ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
+ return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !naked);
+ }
+
+ bool addPostInvariant()
+ {
+ auto ad = isThis();
+ ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
+ return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !naked);
+ }
+
+ override const(char)* kind() const
+ {
+ return generated ? "generated function" : "function";
+ }
+
+ /********************************************
+ * Returns:
+ * true if there are no overloads of this function
+ */
+ final bool isUnique() const
+ {
+ bool result = false;
+ overloadApply(cast() this, (Dsymbol s)
+ {
+ auto f = s.isFuncDeclaration();
+ if (!f)
+ return 0;
+ if (result)
+ {
+ result = false;
+ return 1; // ambiguous, done
+ }
+ else
+ {
+ result = true;
+ return 0;
+ }
+ });
+ return result;
+ }
+
+ /*********************************************
+ * In the current function, we are calling 'this' function.
+ * 1. Check to see if the current function can call 'this' function, issue error if not.
+ * 2. If the current function is not the parent of 'this' function, then add
+ * the current function to the list of siblings of 'this' function.
+ * 3. If the current function is a literal, and it's accessing an uplevel scope,
+ * then mark it as a delegate.
+ * Returns true if error occurs.
+ */
+ extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
+ {
+ //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
+
+ if (auto fld = this.isFuncLiteralDeclaration())
+ {
+ if (fld.tok == TOK.reserved)
+ {
+ fld.tok = TOK.function_;
+ fld.vthis = null;
+ }
+ }
+
+ if (!parent || parent == sc.parent)
+ return false;
+ if (ident == Id.require || ident == Id.ensure)
+ return false;
+ if (!isThis() && !isNested())
+ return false;
+
+ // The current function
+ FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
+ if (!fdthis)
+ return false; // out of function scope
+
+ Dsymbol p = toParentLocal();
+ Dsymbol p2 = toParent2();
+
+ // Function literals from fdthis to p must be delegates
+ ensureStaticLinkTo(fdthis, p);
+ if (p != p2)
+ ensureStaticLinkTo(fdthis, p2);
+
+ if (isNested())
+ {
+ // The function that this function is in
+ bool checkEnclosing(FuncDeclaration fdv)
+ {
+ if (!fdv)
+ return false;
+ if (fdv == fdthis)
+ return false;
+
+ //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
+ //printf("fdv = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
+ //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
+
+ // Add this function to the list of those which called us
+ if (fdthis != this)
+ {
+ bool found = false;
+ for (size_t i = 0; i < siblingCallers.dim; ++i)
+ {
+ if (siblingCallers[i] == fdthis)
+ found = true;
+ }
+ if (!found)
+ {
+ //printf("\tadding sibling %s\n", fdthis.toPrettyChars());
+ if (!sc.intypeof && !(sc.flags & SCOPE.compile))
+ siblingCallers.push(fdthis);
+ }
+ }
+
+ const lv = fdthis.getLevelAndCheck(loc, sc, fdv, this);
+ if (lv == LevelError)
+ return true; // error
+ if (lv == -1)
+ return false; // downlevel call
+ if (lv == 0)
+ return false; // same level call
+
+ return false; // Uplevel call
+ }
+
+ if (checkEnclosing(p.isFuncDeclaration()))
+ return true;
+ if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
+ return true;
+ }
+ return false;
+ }
+
+ /*******************************
+ * Look at all the variables in this function that are referenced
+ * by nested functions, and determine if a closure needs to be
+ * created for them.
+ */
+ final bool needsClosure()
+ {
+ /* Need a closure for all the closureVars[] if any of the
+ * closureVars[] are accessed by a
+ * function that escapes the scope of this function.
+ * We take the conservative approach and decide that a function needs
+ * a closure if it:
+ * 1) is a virtual function
+ * 2) has its address taken
+ * 3) has a parent that escapes
+ * 4) calls another nested function that needs a closure
+ *
+ * Note that since a non-virtual function can be called by
+ * a virtual one, if that non-virtual function accesses a closure
+ * var, the closure still has to be taken. Hence, we check for isThis()
+ * instead of isVirtual(). (thanks to David Friedman)
+ *
+ * When the function returns a local struct or class, `requiresClosure`
+ * is already set to `true` upon entering this function when the
+ * struct/class refers to a local variable and a closure is needed.
+ */
+
+ //printf("FuncDeclaration::needsClosure() %s\n", toChars());
+
+ if (requiresClosure)
+ goto Lyes;
+
+ for (size_t i = 0; i < closureVars.dim; i++)
+ {
+ VarDeclaration v = closureVars[i];
+ //printf("\tv = %s\n", v.toChars());
+
+ for (size_t j = 0; j < v.nestedrefs.dim; j++)
+ {
+ FuncDeclaration f = v.nestedrefs[j];
+ assert(f != this);
+
+ /* __require and __ensure will always get called directly,
+ * so they never make outer functions closure.
+ */
+ if (f.ident == Id.require || f.ident == Id.ensure)
+ continue;
+
+ //printf("\t\tf = %p, %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", f, f.toChars(), f.isVirtual(), f.isThis(), f.tookAddressOf);
+
+ /* Look to see if f escapes. We consider all parents of f within
+ * this, and also all siblings which call f; if any of them escape,
+ * so does f.
+ * Mark all affected functions as requiring closures.
+ */
+ for (Dsymbol s = f; s && s != this; s = s.toParentP(this))
+ {
+ FuncDeclaration fx = s.isFuncDeclaration();
+ if (!fx)
+ continue;
+ if (fx.isThis() || fx.tookAddressOf)
+ {
+ //printf("\t\tfx = %s, isVirtual=%d, isThis=%p, tookAddressOf=%d\n", fx.toChars(), fx.isVirtual(), fx.isThis(), fx.tookAddressOf);
+
+ /* Mark as needing closure any functions between this and f
+ */
+ markAsNeedingClosure((fx == f) ? fx.toParentP(this) : fx, this);
+
+ requiresClosure = true;
+ }
+
+ /* We also need to check if any sibling functions that
+ * called us, have escaped. This is recursive: we need
+ * to check the callers of our siblings.
+ */
+ if (checkEscapingSiblings(fx, this))
+ requiresClosure = true;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=12406
+ * Iterate all closureVars to mark all descendant
+ * nested functions that access to the closing context of this function.
+ */
+ }
+ }
+ }
+ if (requiresClosure)
+ goto Lyes;
+
+ return false;
+
+ Lyes:
+ //printf("\tneeds closure\n");
+ return true;
+ }
+
+ /***********************************************
+ * Check that the function contains any closure.
+ * If it's @nogc, report suitable errors.
+ * This is mostly consistent with FuncDeclaration::needsClosure().
+ *
+ * Returns:
+ * true if any errors occur.
+ */
+ extern (D) final bool checkClosure()
+ {
+ if (!needsClosure())
+ return false;
+
+ if (setGC())
+ {
+ error("is `@nogc` yet allocates closures with the GC");
+ if (global.gag) // need not report supplemental errors
+ return true;
+ }
+ else
+ {
+ printGCUsage(loc, "using closure causes GC allocation");
+ return false;
+ }
+
+ FuncDeclarations a;
+ foreach (v; closureVars)
+ {
+ foreach (f; v.nestedrefs)
+ {
+ assert(f !is this);
+
+ LcheckAncestorsOfANestedRef:
+ for (Dsymbol s = f; s && s !is this; s = s.toParentP(this))
+ {
+ auto fx = s.isFuncDeclaration();
+ if (!fx)
+ continue;
+ if (fx.isThis() ||
+ fx.tookAddressOf ||
+ checkEscapingSiblings(fx, this))
+ {
+ foreach (f2; a)
+ {
+ if (f2 == f)
+ break LcheckAncestorsOfANestedRef;
+ }
+ a.push(f);
+ .errorSupplemental(f.loc, "%s closes over variable %s at %s",
+ f.toPrettyChars(), v.toChars(), v.loc.toChars());
+ break LcheckAncestorsOfANestedRef;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /***********************************************
+ * Determine if function's variables are referenced by a function
+ * nested within it.
+ */
+ final bool hasNestedFrameRefs()
+ {
+ if (closureVars.dim)
+ return true;
+
+ /* If a virtual function has contracts, assume its variables are referenced
+ * by those contracts, even if they aren't. Because they might be referenced
+ * by the overridden or overriding function's contracts.
+ * This can happen because frequire and fensure are implemented as nested functions,
+ * and they can be called directly by an overriding function and the overriding function's
+ * context had better match, or
+ * https://issues.dlang.org/show_bug.cgi?id=7335 will bite.
+ */
+ if (fdrequire || fdensure)
+ return true;
+
+ if (foverrides.dim && isVirtualMethod())
+ {
+ for (size_t i = 0; i < foverrides.dim; i++)
+ {
+ FuncDeclaration fdv = foverrides[i];
+ if (fdv.hasNestedFrameRefs())
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /****************************************************
+ * Check whether result variable can be built.
+ * Returns:
+ * `true` if the function has a return type that
+ * is different from `void`.
+ */
+ extern (D) private bool canBuildResultVar()
+ {
+ auto f = cast(TypeFunction)type;
+ return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
+ }
+
+ /****************************************************
+ * Declare result variable lazily.
+ */
+ extern (D) final void buildResultVar(Scope* sc, Type tret)
+ {
+ if (!vresult)
+ {
+ Loc loc = fensure ? fensure.loc : this.loc;
+
+ /* If inferRetType is true, tret may not be a correct return type yet.
+ * So, in here it may be a temporary type for vresult, and after
+ * fbody.dsymbolSemantic() running, vresult.type might be modified.
+ */
+ vresult = new VarDeclaration(loc, tret, Id.result, null);
+ vresult.storage_class |= STC.nodtor | STC.temp;
+ if (!isVirtual())
+ vresult.storage_class |= STC.const_;
+ vresult.storage_class |= STC.result;
+
+ // set before the semantic() for checkNestedReference()
+ vresult.parent = this;
+ }
+
+ if (sc && vresult.semanticRun == PASS.init)
+ {
+ TypeFunction tf = type.toTypeFunction();
+ if (tf.isref)
+ vresult.storage_class |= STC.ref_;
+ vresult.type = tret;
+
+ vresult.dsymbolSemantic(sc);
+
+ if (!sc.insert(vresult))
+ error("out result %s is already defined", vresult.toChars());
+ assert(vresult.parent == this);
+ }
+ }
+
+ /****************************************************
+ * Merge into this function the 'in' contracts of all it overrides.
+ * 'in's are OR'd together, i.e. only one of them needs to pass.
+ */
+ extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
+ {
+ /* If a base function and its override both have an IN contract, then
+ * only one of them needs to succeed. This is done by generating:
+ *
+ * void derived.in() {
+ * try {
+ * base.in();
+ * }
+ * catch () {
+ * ... body of derived.in() ...
+ * }
+ * }
+ *
+ * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
+ * If base.in() throws, then derived.in()'s body is executed.
+ */
+
+ foreach (fdv; foverrides)
+ {
+ /* The semantic pass on the contracts of the overridden functions must
+ * be completed before code generation occurs.
+ * https://issues.dlang.org/show_bug.cgi?id=3602
+ */
+ if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
+ {
+ assert(fdv._scope);
+ Scope* sc = fdv._scope.push();
+ sc.stc &= ~STC.override_;
+ fdv.semantic3(sc);
+ sc.pop();
+ }
+
+ sf = fdv.mergeFrequire(sf, params);
+ if (!sf || !fdv.fdrequire)
+ return null;
+ //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
+ /* Make the call:
+ * try { __require(params); }
+ * catch (Throwable) { frequire; }
+ */
+ params = Expression.arraySyntaxCopy(params);
+ Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
+ Statement s2 = new ExpStatement(loc, e);
+
+ auto c = new Catch(loc, getThrowable(), null, sf);
+ c.internalCatch = true;
+ auto catches = new Catches();
+ catches.push(c);
+ sf = new TryCatchStatement(loc, s2, catches);
+ }
+ return sf;
+ }
+
+ /****************************************************
+ * Merge into this function the 'in' contracts of all it overrides.
+ */
+ extern (D) final Statement mergeFrequireInclusivePreview(Statement sf, Expressions* params)
+ {
+ /* If a base function and its override both have an IN contract, then
+ * the override in contract must widen the guarantee of the base contract.
+ * This is checked by generating:
+ *
+ * void derived.in() {
+ * try {
+ * ... body of derived.in() ...
+ * }
+ * catch () {
+ * // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
+ * base.in();
+ * assert(false, "Logic error: " ~ thr.msg);
+ * }
+ */
+
+ foreach (fdv; foverrides)
+ {
+ /* The semantic pass on the contracts of the overridden functions must
+ * be completed before code generation occurs.
+ * https://issues.dlang.org/show_bug.cgi?id=3602
+ */
+ if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
+ {
+ assert(fdv._scope);
+ Scope* sc = fdv._scope.push();
+ sc.stc &= ~STC.override_;
+ fdv.semantic3(sc);
+ sc.pop();
+ }
+
+ sf = fdv.mergeFrequireInclusivePreview(sf, params);
+ if (sf && fdv.fdrequire)
+ {
+ const loc = this.fdrequire.loc;
+
+ //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
+ /* Make the call:
+ * try { frequire; }
+ * catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
+ */
+ Identifier id = Identifier.generateId("thr");
+ params = Expression.arraySyntaxCopy(params);
+ Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
+ Statement s2 = new ExpStatement(loc, e);
+ // assert(false, ...)
+ // TODO make this a runtime helper to allow:
+ // - chaining the original expression
+ // - nogc concatenation
+ Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
+ Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
+
+ Statement s3 = new CompoundStatement(loc, s2, fail);
+
+ auto c = new Catch(loc, getThrowable(), id, s3);
+ c.internalCatch = true;
+ auto catches = new Catches();
+ catches.push(c);
+ sf = new TryCatchStatement(loc, sf, catches);
+ }
+ else
+ return null;
+ }
+ return sf;
+ }
+
+ /****************************************************
+ * Determine whether an 'out' contract is declared inside
+ * the given function or any of its overrides.
+ * Params:
+ * fd = the function to search
+ * Returns:
+ * true found an 'out' contract
+ */
+ static bool needsFensure(FuncDeclaration fd)
+ {
+ if (fd.fensures)
+ return true;
+
+ foreach (fdv; fd.foverrides)
+ {
+ if (needsFensure(fdv))
+ return true;
+ }
+ return false;
+ }
+
+ /****************************************************
+ * Rewrite contracts as statements.
+ */
+ final void buildEnsureRequire()
+ {
+
+ if (frequires)
+ {
+ /* in { statements1... }
+ * in { statements2... }
+ * ...
+ * becomes:
+ * in { { statements1... } { statements2... } ... }
+ */
+ assert(frequires.dim);
+ auto loc = (*frequires)[0].loc;
+ auto s = new Statements;
+ foreach (r; *frequires)
+ {
+ s.push(new ScopeStatement(r.loc, r, r.loc));
+ }
+ frequire = new CompoundStatement(loc, s);
+ }
+
+ if (fensures)
+ {
+ /* out(id1) { statements1... }
+ * out(id2) { statements2... }
+ * ...
+ * becomes:
+ * out(__result) { { ref id1 = __result; { statements1... } }
+ * { ref id2 = __result; { statements2... } } ... }
+ */
+ assert(fensures.dim);
+ auto loc = (*fensures)[0].ensure.loc;
+ auto s = new Statements;
+ foreach (r; *fensures)
+ {
+ if (r.id && canBuildResultVar())
+ {
+ auto rloc = r.ensure.loc;
+ auto resultId = new IdentifierExp(rloc, Id.result);
+ auto init = new ExpInitializer(rloc, resultId);
+ auto stc = STC.ref_ | STC.temp | STC.result;
+ auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
+ auto sdecl = new ExpStatement(rloc, decl);
+ s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
+ }
+ else
+ {
+ s.push(r.ensure);
+ }
+ }
+ fensure = new CompoundStatement(loc, s);
+ }
+
+ if (!isVirtual())
+ return;
+
+ /* Rewrite contracts as nested functions, then call them. Doing it as nested
+ * functions means that overriding functions can call them.
+ */
+ TypeFunction f = cast(TypeFunction) type;
+
+ /* Make a copy of the parameters and make them all ref */
+ static Parameters* toRefCopy(ParameterList parameterList)
+ {
+ auto result = new Parameters();
+
+ foreach (n, p; parameterList)
+ {
+ p = p.syntaxCopy();
+ if (!(p.storageClass & STC.lazy_))
+ p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
+ p.defaultArg = null; // won't be the same with ref
+ result.push(p);
+ }
+
+ return result;
+ }
+
+ if (frequire)
+ {
+ /* in { ... }
+ * becomes:
+ * void __require(ref params) { ... }
+ * __require(params);
+ */
+ Loc loc = frequire.loc;
+ fdrequireParams = new Expressions();
+ if (parameters)
+ {
+ foreach (vd; *parameters)
+ fdrequireParams.push(new VarExp(loc, vd));
+ }
+ auto fo = cast(TypeFunction)(originalType ? originalType : f);
+ auto fparams = toRefCopy(fo.parameterList);
+ auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
+ tf.isnothrow = f.isnothrow;
+ tf.isnogc = f.isnogc;
+ tf.purity = f.purity;
+ tf.trust = f.trust;
+ auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
+ fd.fbody = frequire;
+ Statement s1 = new ExpStatement(loc, fd);
+ Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
+ Statement s2 = new ExpStatement(loc, e);
+ frequire = new CompoundStatement(loc, s1, s2);
+ fdrequire = fd;
+ }
+
+ /* We need to set fdensureParams here and not in the block below to
+ * have the parameters available when calling a base class ensure(),
+ * even if this function doesn't have an out contract.
+ */
+ fdensureParams = new Expressions();
+ if (canBuildResultVar())
+ fdensureParams.push(new IdentifierExp(loc, Id.result));
+ if (parameters)
+ {
+ foreach (vd; *parameters)
+ fdensureParams.push(new VarExp(loc, vd));
+ }
+
+ if (fensure)
+ {
+ /* out (result) { ... }
+ * becomes:
+ * void __ensure(ref tret result, ref params) { ... }
+ * __ensure(result, params);
+ */
+ Loc loc = fensure.loc;
+ auto fparams = new Parameters();
+ if (canBuildResultVar())
+ {
+ Parameter p = new Parameter(STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
+ fparams.push(p);
+ }
+ auto fo = cast(TypeFunction)(originalType ? originalType : f);
+ fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
+ auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
+ tf.isnothrow = f.isnothrow;
+ tf.isnogc = f.isnogc;
+ tf.purity = f.purity;
+ tf.trust = f.trust;
+ auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
+ fd.fbody = fensure;
+ Statement s1 = new ExpStatement(loc, fd);
+ Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
+ Statement s2 = new ExpStatement(loc, e);
+ fensure = new CompoundStatement(loc, s1, s2);
+ fdensure = fd;
+ }
+ }
+
+ /****************************************************
+ * Merge into this function the 'out' contracts of all it overrides.
+ * 'out's are AND'd together, i.e. all of them need to pass.
+ */
+ extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
+ {
+ /* Same comments as for mergeFrequire(), except that we take care
+ * of generating a consistent reference to the 'result' local by
+ * explicitly passing 'result' to the nested function as a reference
+ * argument.
+ * This won't work for the 'this' parameter as it would require changing
+ * the semantic code for the nested function so that it looks on the parameter
+ * list for the 'this' pointer, something that would need an unknown amount
+ * of tweaking of various parts of the compiler that I'd rather leave alone.
+ */
+ foreach (fdv; foverrides)
+ {
+ /* The semantic pass on the contracts of the overridden functions must
+ * be completed before code generation occurs.
+ * https://issues.dlang.org/show_bug.cgi?id=3602 and
+ * https://issues.dlang.org/show_bug.cgi?id=5230
+ */
+ if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
+ {
+ assert(fdv._scope);
+ Scope* sc = fdv._scope.push();
+ sc.stc &= ~STC.override_;
+ fdv.semantic3(sc);
+ sc.pop();
+ }
+
+ sf = fdv.mergeFensure(sf, oid, params);
+ if (fdv.fdensure)
+ {
+ //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
+ // Make the call: __ensure(result, params)
+ params = Expression.arraySyntaxCopy(params);
+ if (canBuildResultVar())
+ {
+ Type t1 = fdv.type.nextOf().toBasetype();
+ Type t2 = this.type.nextOf().toBasetype();
+ if (t1.isBaseOf(t2, null))
+ {
+ /* Making temporary reference variable is necessary
+ * in covariant return.
+ * https://issues.dlang.org/show_bug.cgi?id=5204
+ * https://issues.dlang.org/show_bug.cgi?id=10479
+ */
+ Expression* eresult = &(*params)[0];
+ auto ei = new ExpInitializer(Loc.initial, *eresult);
+ auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
+ v.storage_class |= STC.temp;
+ auto de = new DeclarationExp(Loc.initial, v);
+ auto ve = new VarExp(Loc.initial, v);
+ *eresult = new CommaExp(Loc.initial, de, ve);
+ }
+ }
+ Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
+ Statement s2 = new ExpStatement(loc, e);
+
+ if (sf)
+ {
+ sf = new CompoundStatement(sf.loc, s2, sf);
+ }
+ else
+ sf = s2;
+ }
+ }
+ return sf;
+ }
+
+ /*********************************************
+ * Returns: the function's parameter list, and whether
+ * it is variadic or not.
+ */
+ final ParameterList getParameterList()
+ {
+ if (type)
+ {
+ TypeFunction fdtype = type.isTypeFunction();
+ if (fdtype) // Could also be TypeError
+ return fdtype.parameterList;
+ }
+
+ return ParameterList(null, VarArg.none);
+ }
+
+ /**********************************
+ * Generate a FuncDeclaration for a runtime library function.
+ */
+ static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, const(char)* name, StorageClass stc = 0)
+ {
+ return genCfunc(fparams, treturn, Identifier.idPool(name, cast(uint)strlen(name)), stc);
+ }
+
+ static FuncDeclaration genCfunc(Parameters* fparams, Type treturn, Identifier id, StorageClass stc = 0)
+ {
+ FuncDeclaration fd;
+ TypeFunction tf;
+ Dsymbol s;
+ __gshared DsymbolTable st = null;
+
+ //printf("genCfunc(name = '%s')\n", id.toChars());
+ //printf("treturn\n\t"); treturn.print();
+
+ // See if already in table
+ if (!st)
+ st = new DsymbolTable();
+ s = st.lookup(id);
+ if (s)
+ {
+ fd = s.isFuncDeclaration();
+ assert(fd);
+ assert(fd.type.nextOf().equals(treturn));
+ }
+ else
+ {
+ tf = new TypeFunction(ParameterList(fparams), treturn, LINK.c, stc);
+ fd = new FuncDeclaration(Loc.initial, Loc.initial, id, STC.static_, tf);
+ fd.visibility = Visibility(Visibility.Kind.public_);
+ fd.linkage = LINK.c;
+
+ st.insert(fd);
+ }
+ return fd;
+ }
+
+ /******************
+ * Check parameters and return type of D main() function.
+ * Issue error messages.
+ */
+ extern (D) final void checkDmain()
+ {
+ TypeFunction tf = type.toTypeFunction();
+ const nparams = tf.parameterList.length;
+ bool argerr;
+ if (nparams == 1)
+ {
+ auto fparam0 = tf.parameterList[0];
+ auto t = fparam0.type.toBasetype();
+ if (t.ty != Tarray ||
+ t.nextOf().ty != Tarray ||
+ t.nextOf().nextOf().ty != Tchar ||
+ fparam0.storageClass & (STC.out_ | STC.ref_ | STC.lazy_))
+ {
+ argerr = true;
+ }
+ }
+
+ if (!tf.nextOf())
+ error("must return `int` or `void`");
+ else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid)
+ error("must return `int` or `void`, not `%s`", tf.nextOf().toChars());
+ else if (tf.parameterList.varargs || nparams >= 2 || argerr)
+ error("parameters must be `main()` or `main(string[] args)`");
+ }
+
+ /***********************************************
+ * Check all return statements for a function to verify that returning
+ * using NRVO is possible.
+ *
+ * Returns:
+ * `false` if the result cannot be returned by hidden reference.
+ */
+ final bool checkNRVO()
+ {
+ if (!nrvo_can || returns is null)
+ return false;
+
+ auto tf = type.toTypeFunction();
+ if (tf.isref)
+ return false;
+
+ foreach (rs; *returns)
+ {
+ if (auto ve = rs.exp.isVarExp())
+ {
+ auto v = ve.var.isVarDeclaration();
+ if (!v || v.isOut() || v.isRef())
+ return false;
+ else if (nrvo_var is null)
+ {
+ // Variables in the data segment (e.g. globals, TLS or not),
+ // parameters and closure variables cannot be NRVOed.
+ if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
+ return false;
+ // The variable type needs to be equivalent to the return type.
+ if (!v.type.equivalent(tf.next))
+ return false;
+ //printf("Setting nrvo to %s\n", v.toChars());
+ nrvo_var = v;
+ }
+ else if (nrvo_var != v)
+ return false;
+ }
+ else //if (!exp.isLvalue()) // keep NRVO-ability
+ return false;
+ }
+ return true;
+ }
+
+ override final inout(FuncDeclaration) isFuncDeclaration() inout
+ {
+ return this;
+ }
+
+ inout(FuncDeclaration) toAliasFunc() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/********************************************************
+ * Generate Expression to call the invariant.
+ * Input:
+ * ad aggregate with the invariant
+ * vthis variable with 'this'
+ * Returns:
+ * void expression that calls the invariant
+ */
+Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
+{
+ Expression e = null;
+ // Call invariant directly only if it exists
+ FuncDeclaration inv = ad.inv;
+ ClassDeclaration cd = ad.isClassDeclaration();
+
+ while (!inv && cd)
+ {
+ cd = cd.baseClass;
+ if (!cd)
+ break;
+ inv = cd.inv;
+ }
+ if (inv)
+ {
+ version (all)
+ {
+ // Workaround for https://issues.dlang.org/show_bug.cgi?id=13394
+ // For the correct mangling,
+ // run attribute inference on inv if needed.
+ inv.functionSemantic();
+ }
+
+ //e = new DsymbolExp(Loc.initial, inv);
+ //e = new CallExp(Loc.initial, e);
+ //e = e.semantic(sc2);
+
+ /* https://issues.dlang.org/show_bug.cgi?id=13113
+ * Currently virtual invariant calls completely
+ * bypass attribute enforcement.
+ * Change the behavior of pre-invariant call by following it.
+ */
+ e = new ThisExp(Loc.initial);
+ e.type = ad.type.addMod(vthis.type.mod);
+ e = new DotVarExp(Loc.initial, e, inv, false);
+ e.type = inv.type;
+ e = new CallExp(Loc.initial, e);
+ e.type = Type.tvoid;
+ }
+ return e;
+}
+
+/***************************************************
+ * Visit each overloaded function/template in turn, and call dg(s) on it.
+ * Exit when no more, or dg(s) returns nonzero.
+ *
+ * Params:
+ * fstart = symbol to start from
+ * dg = the delegate to be called on the overload
+ * sc = context used to check if symbol is accessible (and therefore visible),
+ * can be null
+ *
+ * Returns:
+ * ==0 continue
+ * !=0 done (and the return value from the last dg() call)
+ */
+extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
+{
+ Dsymbol next;
+ for (auto d = fstart; d; d = next)
+ {
+ import dmd.access : checkSymbolAccess;
+ if (auto od = d.isOverDeclaration())
+ {
+ /* The scope is needed here to check whether a function in
+ an overload set was added by means of a private alias (or a
+ selective import). If the scope where the alias is created
+ is imported somewhere, the overload set is visible, but the private
+ alias is not.
+ */
+ if (sc)
+ {
+ if (checkSymbolAccess(sc, od))
+ {
+ if (int r = overloadApply(od.aliassym, dg, sc))
+ return r;
+ }
+ }
+ else if (int r = overloadApply(od.aliassym, dg, sc))
+ return r;
+ next = od.overnext;
+ }
+ else if (auto fa = d.isFuncAliasDeclaration())
+ {
+ if (fa.hasOverloads)
+ {
+ if (int r = overloadApply(fa.funcalias, dg, sc))
+ return r;
+ }
+ else if (auto fd = fa.toAliasFunc())
+ {
+ if (int r = dg(fd))
+ return r;
+ }
+ else
+ {
+ d.error("is aliased to a function");
+ break;
+ }
+ next = fa.overnext;
+ }
+ else if (auto ad = d.isAliasDeclaration())
+ {
+ if (sc)
+ {
+ if (checkSymbolAccess(sc, ad))
+ next = ad.toAlias();
+ }
+ else
+ next = ad.toAlias();
+ if (next == ad)
+ break;
+ if (next == fstart)
+ break;
+ }
+ else if (auto td = d.isTemplateDeclaration())
+ {
+ if (int r = dg(td))
+ return r;
+ next = td.overnext;
+ }
+ else if (auto fd = d.isFuncDeclaration())
+ {
+ if (int r = dg(fd))
+ return r;
+ next = fd.overnext;
+ }
+ else if (auto os = d.isOverloadSet())
+ {
+ foreach (ds; os.a)
+ if (int r = dg(ds))
+ return r;
+ }
+ else
+ {
+ d.error("is aliased to a function");
+ break;
+ // BUG: should print error message?
+ }
+ }
+ return 0;
+}
+
+/**
+Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
+mismatching modifiers to `buf`.
+
+The modifiers of the `lhsMod` mismatching the ones with the `rhsMod` are printed, i.e.
+lhs(shared) vs. rhs() prints "`shared`", wheras lhs() vs rhs(shared) prints "non-shared".
+
+Params:
+ buf = output buffer to write to
+ lhsMod = modifier on the left-hand side
+ lhsMod = modifier on the right-hand side
+
+Returns:
+
+A tuple with `isMutable` and `isNotShared` set
+if the `lhsMod` is missing those modifiers (compared to rhs).
+*/
+auto MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod)
+{
+ static struct Mismatches
+ {
+ bool isNotShared;
+ bool isMutable;
+ }
+
+ Mismatches mismatches;
+
+ bool bothMutable = ((lhsMod & rhsMod) == 0);
+ bool sharedMismatch = ((lhsMod ^ rhsMod) & MODFlags.shared_) != 0;
+ bool sharedMismatchOnly = ((lhsMod ^ rhsMod) == MODFlags.shared_);
+
+ if (lhsMod & MODFlags.shared_)
+ buf.writestring("`shared` ");
+ else if (sharedMismatch && !(lhsMod & MODFlags.immutable_))
+ {
+ buf.writestring("non-shared ");
+ mismatches.isNotShared = true;
+ }
+
+ if (bothMutable && sharedMismatchOnly)
+ {
+ }
+ else if (lhsMod & MODFlags.immutable_)
+ buf.writestring("`immutable` ");
+ else if (lhsMod & MODFlags.const_)
+ buf.writestring("`const` ");
+ else if (lhsMod & MODFlags.wild)
+ buf.writestring("`inout` ");
+ else
+ {
+ buf.writestring("mutable ");
+ mismatches.isMutable = true;
+ }
+
+ return mismatches;
+}
+
+///
+unittest
+{
+ OutBuffer buf;
+ auto mismatches = MODMatchToBuffer(&buf, MODFlags.shared_, 0);
+ assert(buf[] == "`shared` ");
+ assert(!mismatches.isNotShared);
+
+ buf.setsize(0);
+ mismatches = MODMatchToBuffer(&buf, 0, MODFlags.shared_);
+ assert(buf[] == "non-shared ");
+ assert(mismatches.isNotShared);
+
+ buf.setsize(0);
+ mismatches = MODMatchToBuffer(&buf, MODFlags.const_, 0);
+ assert(buf[] == "`const` ");
+ assert(!mismatches.isMutable);
+
+ buf.setsize(0);
+ mismatches = MODMatchToBuffer(&buf, 0, MODFlags.const_);
+ assert(buf[] == "mutable ");
+ assert(mismatches.isMutable);
+}
+
+private const(char)* prependSpace(const(char)* str)
+{
+ if (!str || !*str) return "";
+
+ return (" " ~ str.toDString() ~ "\0").ptr;
+}
+
+/// Flag used by $(LREF resolveFuncCall).
+enum FuncResolveFlag : ubyte
+{
+ standard = 0, /// issue error messages, solve the call.
+ quiet = 1, /// do not issue error message on no match, just return `null`.
+ overloadOnly = 2, /// only resolve overloads, i.e. do not issue error on ambiguous
+ /// matches and need explicit this.
+}
+
+/*******************************************
+ * Given a symbol that could be either a FuncDeclaration or
+ * a function template, resolve it to a function symbol.
+ * Params:
+ * loc = instantiation location
+ * sc = instantiation scope
+ * s = instantiation symbol
+ * tiargs = initial list of template arguments
+ * tthis = if !NULL, the `this` argument type
+ * fargs = arguments to function
+ * flags = see $(LREF FuncResolveFlag).
+ * Returns:
+ * if match is found, then function symbol, else null
+ */
+FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
+ Objects* tiargs, Type tthis, Expressions* fargs, FuncResolveFlag flags)
+{
+ if (!s)
+ return null; // no match
+
+ version (none)
+ {
+ printf("resolveFuncCall('%s')\n", s.toChars());
+ if (tthis)
+ printf("\tthis: %s\n", tthis.toChars());
+ if (fargs)
+ {
+ for (size_t i = 0; i < fargs.dim; i++)
+ {
+ Expression arg = (*fargs)[i];
+ assert(arg.type);
+ printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
+ }
+ }
+ }
+
+ if (tiargs && arrayObjectIsError(tiargs) ||
+ fargs && arrayObjectIsError(cast(Objects*)fargs))
+ {
+ return null;
+ }
+
+ MatchAccumulator m;
+ functionResolve(m, s, loc, sc, tiargs, tthis, fargs, null);
+ auto orig_s = s;
+
+ if (m.last > MATCH.nomatch && m.lastf)
+ {
+ if (m.count == 1) // exactly one match
+ {
+ if (!(flags & FuncResolveFlag.quiet))
+ m.lastf.functionSemantic();
+ return m.lastf;
+ }
+ if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
+ {
+ return m.lastf;
+ }
+ }
+
+ /* Failed to find a best match.
+ * Do nothing or print error.
+ */
+ if (m.last == MATCH.nomatch)
+ {
+ // error was caused on matched function, not on the matching itself,
+ // so return the function to produce a better diagnostic
+ if (m.count == 1)
+ return m.lastf;
+ }
+
+ // We are done at this point, as the rest of this function generate
+ // a diagnostic on invalid match
+ if (flags & FuncResolveFlag.quiet)
+ return null;
+
+ auto fd = s.isFuncDeclaration();
+ auto od = s.isOverDeclaration();
+ auto td = s.isTemplateDeclaration();
+ if (td && td.funcroot)
+ s = fd = td.funcroot;
+
+ OutBuffer tiargsBuf;
+ arrayObjectsToBuffer(&tiargsBuf, tiargs);
+
+ OutBuffer fargsBuf;
+ fargsBuf.writeByte('(');
+ argExpTypesToCBuffer(&fargsBuf, fargs);
+ fargsBuf.writeByte(')');
+ if (tthis)
+ tthis.modToBuffer(&fargsBuf);
+
+ // The call is ambiguous
+ if (m.lastf && m.nextf)
+ {
+ TypeFunction tf1 = m.lastf.type.toTypeFunction();
+ TypeFunction tf2 = m.nextf.type.toTypeFunction();
+ const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
+ const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
+
+ const(char)* mod1 = prependSpace(MODtoChars(tf1.mod));
+ const(char)* mod2 = prependSpace(MODtoChars(tf2.mod));
+
+ .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
+ s.parent.toPrettyChars(), s.ident.toChars(),
+ fargsBuf.peekChars(),
+ m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1,
+ m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2);
+ return null;
+ }
+
+ // no match, generate an error messages
+ if (!fd)
+ {
+ // all of overloads are templates
+ if (td)
+ {
+ .error(loc, "%s `%s.%s` cannot deduce function from argument types `!(%s)%s`",
+ td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
+ tiargsBuf.peekChars(), fargsBuf.peekChars());
+
+ printCandidates(loc, td, sc.isDeprecated());
+ return null;
+ }
+ /* This case used to happen when several ctors are mixed in an agregate.
+ A (bad) error message is already generated in overloadApply().
+ see https://issues.dlang.org/show_bug.cgi?id=19729
+ and https://issues.dlang.org/show_bug.cgi?id=17259
+ */
+ if (!od)
+ return null;
+ }
+
+ if (od)
+ {
+ .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
+ od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
+ return null;
+ }
+
+ // remove when deprecation period of class allocators and deallocators is over
+ if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
+ return null;
+
+ bool hasOverloads = fd.overnext !is null;
+ auto tf = fd.type.toTypeFunction();
+ if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch
+ {
+ OutBuffer thisBuf, funcBuf;
+ MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
+ auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
+ if (hasOverloads)
+ {
+ .error(loc, "none of the overloads of `%s` are callable using a %sobject",
+ fd.ident.toChars(), thisBuf.peekChars());
+ printCandidates(loc, fd, sc.isDeprecated());
+ return null;
+ }
+
+ const(char)* failMessage;
+ functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
+ if (failMessage)
+ {
+ .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
+ fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
+ tf.modToChars(), fargsBuf.peekChars());
+ errorSupplemental(loc, failMessage);
+ return null;
+ }
+
+ .error(loc, "%smethod `%s` is not callable using a %sobject",
+ funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
+
+ if (mismatches.isNotShared)
+ .errorSupplemental(fd.loc, "Consider adding `shared` here");
+ else if (mismatches.isMutable)
+ .errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
+ return null;
+ }
+
+ //printf("tf = %s, args = %s\n", tf.deco, (*fargs)[0].type.deco);
+ if (hasOverloads)
+ {
+ .error(loc, "none of the overloads of `%s` are callable using argument types `%s`",
+ fd.toChars(), fargsBuf.peekChars());
+ printCandidates(loc, fd, sc.isDeprecated());
+ return null;
+ }
+
+ .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
+ fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
+ tf.modToChars(), fargsBuf.peekChars());
+ // re-resolve to check for supplemental message
+ const(char)* failMessage;
+ functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
+ if (failMessage)
+ errorSupplemental(loc, failMessage);
+ return null;
+}
+
+/*******************************************
+ * Prints template and function overload candidates as supplemental errors.
+ * Params:
+ * loc = instantiation location
+ * declaration = the declaration to print overload candidates for
+ * showDeprecated = If `false`, `deprecated` function won't be shown
+ */
+private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
+if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
+{
+ // max num of overloads to print (-v overrides this).
+ enum int DisplayLimit = 5;
+ int displayed;
+ const(char)* constraintsTip;
+
+ // determine if the first candidate was printed
+ bool printed = false;
+
+ overloadApply(declaration, (Dsymbol s)
+ {
+ Dsymbol nextOverload;
+
+ if (auto fd = s.isFuncDeclaration())
+ {
+ // Don't print overloads which have errors.
+ // Not that if the whole overload set has errors, we'll never reach
+ // this point so there's no risk of printing no candidate
+ if (fd.errors || fd.type.ty == Terror)
+ return 0;
+ // Don't print disabled functions, or `deprecated` outside of deprecated scope
+ if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
+ return 0;
+
+ const single_candidate = fd.overnext is null;
+ auto tf = cast(TypeFunction) fd.type;
+ .errorSupplemental(fd.loc,
+ printed ? " `%s%s`" :
+ single_candidate ? "Candidate is: `%s%s`" : "Candidates are: `%s%s`",
+ fd.toPrettyChars(),
+ parametersTypeToChars(tf.parameterList));
+ printed = true;
+ nextOverload = fd.overnext;
+ }
+ else if (auto td = s.isTemplateDeclaration())
+ {
+ import dmd.staticcond;
+
+ const tmsg = td.toCharsNoConstraints();
+ const cmsg = td.getConstraintEvalError(constraintsTip);
+
+ const single_candidate = td.overnext is null;
+
+ // add blank space if there are multiple candidates
+ // the length of the blank space is `strlen("Candidates are: ")`
+
+ if (cmsg)
+ {
+ .errorSupplemental(td.loc,
+ printed ? " `%s`\n%s" :
+ single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
+ tmsg, cmsg);
+ printed = true;
+ }
+ else
+ {
+ .errorSupplemental(td.loc,
+ printed ? " `%s`" :
+ single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
+ tmsg);
+ printed = true;
+ }
+ nextOverload = td.overnext;
+ }
+
+ if (global.params.verbose || ++displayed < DisplayLimit)
+ return 0;
+
+ // Too many overloads to sensibly display.
+ // Just show count of remaining overloads.
+ int num = 0;
+ overloadApply(nextOverload, (s) { ++num; return 0; });
+
+ if (num > 0)
+ .errorSupplemental(loc, "... (%d more, -v to show) ...", num);
+ return 1; // stop iterating
+ });
+
+ // Nothing was displayed, all overloads are either disabled or deprecated
+ if (!displayed)
+ .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
+ // should be only in verbose mode
+ if (constraintsTip)
+ .tip(constraintsTip);
+}
+
+/**************************************
+ * Returns an indirect type one step from t.
+ */
+Type getIndirection(Type t)
+{
+ t = t.baseElemOf();
+ if (t.ty == Tarray || t.ty == Tpointer)
+ return t.nextOf().toBasetype();
+ if (t.ty == Taarray || t.ty == Tclass)
+ return t;
+ if (t.ty == Tstruct)
+ return t.hasPointers() ? t : null; // TODO
+
+ // should consider TypeDelegate?
+ return null;
+}
+
+/**************************************
+ * Performs type-based alias analysis between a newly created value and a pre-
+ * existing memory reference:
+ *
+ * Assuming that a reference A to a value of type `ta` was available to the code
+ * that created a reference B to a value of type `tb`, it returns whether B
+ * might alias memory reachable from A based on the types involved (either
+ * directly or via any number of indirections in either A or B).
+ *
+ * This relation is not symmetric in the two arguments. For example, a
+ * a `const(int)` reference can point to a pre-existing `int`, but not the other
+ * way round.
+ *
+ * Examples:
+ *
+ * ta, tb, result
+ * `const(int)`, `int`, `false`
+ * `int`, `const(int)`, `true`
+ * `int`, `immutable(int)`, `false`
+ * const(immutable(int)*), immutable(int)*, false // BUG: returns true
+ *
+ * Params:
+ * ta = value type being referred to
+ * tb = referred to value type that could be constructed from ta
+ *
+ * Returns:
+ * true if reference to `tb` is isolated from reference to `ta`
+ */
+private bool traverseIndirections(Type ta, Type tb)
+{
+ //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
+
+ /* Threaded list of aggregate types already examined,
+ * used to break cycles.
+ * Cycles in type graphs can only occur with aggregates.
+ */
+ static struct Ctxt
+ {
+ Ctxt* prev;
+ Type type; // an aggregate type
+ }
+
+ static bool traverse(Type ta, Type tb, Ctxt* ctxt, bool reversePass)
+ {
+ //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
+ ta = ta.baseElemOf();
+ tb = tb.baseElemOf();
+
+ // First, check if the pointed-to types are convertible to each other such
+ // that they might alias directly.
+ static bool mayAliasDirect(Type source, Type target)
+ {
+ return
+ // if source is the same as target or can be const-converted to target
+ source.constConv(target) != MATCH.nomatch ||
+ // if target is void and source can be const-converted to target
+ (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
+ }
+
+ if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
+ {
+ //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
+ return false;
+ }
+ if (ta.nextOf() && ta.nextOf() == tb.nextOf())
+ {
+ //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
+ return true;
+ }
+
+ if (tb.ty == Tclass || tb.ty == Tstruct)
+ {
+ for (Ctxt* c = ctxt; c; c = c.prev)
+ if (tb == c.type)
+ return true;
+ Ctxt c;
+ c.prev = ctxt;
+ c.type = tb;
+
+ /* Traverse the type of each field of the aggregate
+ */
+ AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
+ foreach (v; sym.fields)
+ {
+ Type tprmi = v.type.addMod(tb.mod);
+ //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
+ if (!traverse(ta, tprmi, &c, reversePass))
+ return false;
+ }
+ }
+ else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
+ {
+ Type tind = tb.nextOf();
+ if (!traverse(ta, tind, ctxt, reversePass))
+ return false;
+ }
+ else if (tb.hasPointers())
+ {
+ // BUG: consider the context pointer of delegate types
+ return false;
+ }
+
+ // Still no match, so try breaking up ta if we have not done so yet.
+ if (!reversePass)
+ return traverse(tb, ta, ctxt, true);
+
+ return true;
+ }
+
+ // To handle arbitrary levels of indirections in both parameters, we
+ // recursively descend into aggregate members/levels of indirection in both
+ // `ta` and `tb` while avoiding cycles. Start with the original types.
+ const result = traverse(ta, tb, null, false);
+ //printf(" returns %d\n", result);
+ return result;
+}
+
+/* For all functions between outerFunc and f, mark them as needing
+ * a closure.
+ */
+private void markAsNeedingClosure(Dsymbol f, FuncDeclaration outerFunc)
+{
+ for (Dsymbol sx = f; sx && sx != outerFunc; sx = sx.toParentP(outerFunc))
+ {
+ FuncDeclaration fy = sx.isFuncDeclaration();
+ if (fy && fy.closureVars.dim)
+ {
+ /* fy needs a closure if it has closureVars[],
+ * because the frame pointer in the closure will be accessed.
+ */
+ fy.requiresClosure = true;
+ }
+ }
+}
+
+/********
+ * Given a nested function f inside a function outerFunc, check
+ * if any sibling callers of f have escaped. If so, mark
+ * all the enclosing functions as needing closures.
+ * This is recursive: we need to check the callers of our siblings.
+ * Note that nested functions can only call lexically earlier nested
+ * functions, so loops are impossible.
+ * Params:
+ * f = inner function (nested within outerFunc)
+ * outerFunc = outer function
+ * p = for internal recursion use
+ * Returns:
+ * true if any closures were needed
+ */
+private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, void* p = null)
+{
+ static struct PrevSibling
+ {
+ PrevSibling* p;
+ FuncDeclaration f;
+ }
+
+ PrevSibling ps;
+ ps.p = cast(PrevSibling*)p;
+ ps.f = f;
+
+ //printf("checkEscapingSiblings(f = %s, outerfunc = %s)\n", f.toChars(), outerFunc.toChars());
+ bool bAnyClosures = false;
+ for (size_t i = 0; i < f.siblingCallers.dim; ++i)
+ {
+ FuncDeclaration g = f.siblingCallers[i];
+ if (g.isThis() || g.tookAddressOf)
+ {
+ markAsNeedingClosure(g, outerFunc);
+ bAnyClosures = true;
+ }
+
+ for (auto parent = g.toParentP(outerFunc); parent && parent !is outerFunc; parent = parent.toParentP(outerFunc))
+ {
+ // A parent of the sibling had its address taken.
+ // Assume escaping of parent affects its children, so needs propagating.
+ // see https://issues.dlang.org/show_bug.cgi?id=19679
+ FuncDeclaration parentFunc = parent.isFuncDeclaration;
+ if (parentFunc && parentFunc.tookAddressOf)
+ {
+ markAsNeedingClosure(parentFunc, outerFunc);
+ bAnyClosures = true;
+ }
+ }
+
+ PrevSibling* prev = cast(PrevSibling*)p;
+ while (1)
+ {
+ if (!prev)
+ {
+ bAnyClosures |= checkEscapingSiblings(g, outerFunc, &ps);
+ break;
+ }
+ if (prev.f == g)
+ break;
+ prev = prev.p;
+ }
+ }
+ //printf("\t%d\n", bAnyClosures);
+ return bAnyClosures;
+}
+
+/***********************************************************
+ * Used as a way to import a set of functions from another scope into this one.
+ */
+extern (C++) final class FuncAliasDeclaration : FuncDeclaration
+{
+ FuncDeclaration funcalias;
+ bool hasOverloads;
+
+ extern (D) this(Identifier ident, FuncDeclaration funcalias, bool hasOverloads = true)
+ {
+ super(funcalias.loc, funcalias.endloc, ident, funcalias.storage_class, funcalias.type);
+ assert(funcalias != this);
+ this.funcalias = funcalias;
+
+ this.hasOverloads = hasOverloads;
+ if (hasOverloads)
+ {
+ if (FuncAliasDeclaration fad = funcalias.isFuncAliasDeclaration())
+ this.hasOverloads = fad.hasOverloads;
+ }
+ else
+ {
+ // for internal use
+ assert(!funcalias.isFuncAliasDeclaration());
+ this.hasOverloads = false;
+ }
+ userAttribDecl = funcalias.userAttribDecl;
+ }
+
+ override inout(FuncAliasDeclaration) isFuncAliasDeclaration() inout
+ {
+ return this;
+ }
+
+ override const(char)* kind() const
+ {
+ return "function alias";
+ }
+
+ override inout(FuncDeclaration) toAliasFunc() inout
+ {
+ return funcalias.toAliasFunc();
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
+{
+ TOK tok; // TOK.function_ or TOK.delegate_
+ Type treq; // target of return type inference
+
+ // backend
+ bool deferToObj;
+
+ extern (D) this(const ref Loc loc, const ref Loc endloc, Type type, TOK tok, ForeachStatement fes, Identifier id = null)
+ {
+ super(loc, endloc, null, STC.undefined_, type);
+ this.ident = id ? id : Id.empty;
+ this.tok = tok;
+ this.fes = fes;
+ // Always infer scope for function literals
+ // See https://issues.dlang.org/show_bug.cgi?id=20362
+ this.flags |= FUNCFLAG.inferScope;
+ //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
+ }
+
+ override FuncLiteralDeclaration syntaxCopy(Dsymbol s)
+ {
+ //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars());
+ assert(!s);
+ auto f = new FuncLiteralDeclaration(loc, endloc, type.syntaxCopy(), tok, fes, ident);
+ f.treq = treq; // don't need to copy
+ FuncDeclaration.syntaxCopy(f);
+ return f;
+ }
+
+ override bool isNested() const
+ {
+ //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars());
+ return (tok != TOK.function_) && !isThis();
+ }
+
+ override inout(AggregateDeclaration) isThis() inout
+ {
+ return tok == TOK.delegate_ ? super.isThis() : null;
+ }
+
+ override bool isVirtual() const
+ {
+ return false;
+ }
+
+ override bool addPreInvariant()
+ {
+ return false;
+ }
+
+ override bool addPostInvariant()
+ {
+ return false;
+ }
+
+ /*******************************
+ * Modify all expression type of return statements to tret.
+ *
+ * On function literals, return type may be modified based on the context type
+ * after its semantic3 is done, in FuncExp::implicitCastTo.
+ *
+ * A function() dg = (){ return new B(); } // OK if is(B : A) == true
+ *
+ * If B to A conversion is convariant that requires offseet adjusting,
+ * all return statements should be adjusted to return expressions typed A.
+ */
+ void modifyReturns(Scope* sc, Type tret)
+ {
+ import dmd.statement_rewrite_walker;
+
+ extern (C++) final class RetWalker : StatementRewriteWalker
+ {
+ alias visit = typeof(super).visit;
+ public:
+ Scope* sc;
+ Type tret;
+ FuncLiteralDeclaration fld;
+
+ override void visit(ReturnStatement s)
+ {
+ Expression exp = s.exp;
+ if (exp && !exp.type.equals(tret))
+ {
+ s.exp = exp.castTo(sc, tret);
+ }
+ }
+ }
+
+ if (semanticRun < PASS.semantic3done)
+ return;
+
+ if (fes)
+ return;
+
+ scope RetWalker w = new RetWalker();
+ w.sc = sc;
+ w.tret = tret;
+ w.fld = this;
+ fbody.accept(w);
+
+ // Also update the inferred function type to match the new return type.
+ // This is required so the code generator does not try to cast the
+ // modified returns back to the original type.
+ if (inferRetType && type.nextOf() != tret)
+ type.toTypeFunction().next = tret;
+ }
+
+ override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
+ {
+ return this;
+ }
+
+ override const(char)* kind() const
+ {
+ // GCC requires the (char*) casts
+ return (tok != TOK.function_) ? "delegate" : "function";
+ }
+
+ override const(char)* toPrettyChars(bool QualifyTypes = false)
+ {
+ if (parent)
+ {
+ TemplateInstance ti = parent.isTemplateInstance();
+ if (ti)
+ return ti.tempdecl.toPrettyChars(QualifyTypes);
+ }
+ return Dsymbol.toPrettyChars(QualifyTypes);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class CtorDeclaration : FuncDeclaration
+{
+ bool isCpCtor;
+ extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false)
+ {
+ super(loc, endloc, Id.ctor, stc, type);
+ this.isCpCtor = isCpCtor;
+ //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars());
+ }
+
+ override CtorDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto f = new CtorDeclaration(loc, endloc, storage_class, type.syntaxCopy());
+ FuncDeclaration.syntaxCopy(f);
+ return f;
+ }
+
+ override const(char)* kind() const
+ {
+ return isCpCtor ? "copy constructor" : "constructor";
+ }
+
+ override const(char)* toChars() const
+ {
+ return "this";
+ }
+
+ override bool isVirtual() const
+ {
+ return false;
+ }
+
+ override bool addPreInvariant()
+ {
+ return false;
+ }
+
+ override bool addPostInvariant()
+ {
+ return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
+ }
+
+ override inout(CtorDeclaration) isCtorDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class PostBlitDeclaration : FuncDeclaration
+{
+ extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
+ {
+ super(loc, endloc, id, stc, null);
+ }
+
+ override PostBlitDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto dd = new PostBlitDeclaration(loc, endloc, storage_class, ident);
+ FuncDeclaration.syntaxCopy(dd);
+ return dd;
+ }
+
+ override bool isVirtual() const
+ {
+ return false;
+ }
+
+ override bool addPreInvariant()
+ {
+ return false;
+ }
+
+ override bool addPostInvariant()
+ {
+ return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
+ }
+
+ override bool overloadInsert(Dsymbol s)
+ {
+ return false; // cannot overload postblits
+ }
+
+ override inout(PostBlitDeclaration) isPostBlitDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DtorDeclaration : FuncDeclaration
+{
+ extern (D) this(const ref Loc loc, const ref Loc endloc)
+ {
+ super(loc, endloc, Id.dtor, STC.undefined_, null);
+ }
+
+ extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id)
+ {
+ super(loc, endloc, id, stc, null);
+ }
+
+ override DtorDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto dd = new DtorDeclaration(loc, endloc, storage_class, ident);
+ FuncDeclaration.syntaxCopy(dd);
+ return dd;
+ }
+
+ override const(char)* kind() const
+ {
+ return "destructor";
+ }
+
+ override const(char)* toChars() const
+ {
+ return "~this";
+ }
+
+ override bool isVirtual() const
+ {
+ // D dtor's don't get put into the vtbl[]
+ // this is a hack so that extern(C++) destructors report as virtual, which are manually added to the vtable
+ return vtblIndex != -1;
+ }
+
+ override bool addPreInvariant()
+ {
+ return (isThis() && vthis && global.params.useInvariants == CHECKENABLE.on);
+ }
+
+ override bool addPostInvariant()
+ {
+ return false;
+ }
+
+ override bool overloadInsert(Dsymbol s)
+ {
+ return false; // cannot overload destructors
+ }
+
+ override inout(DtorDeclaration) isDtorDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) class StaticCtorDeclaration : FuncDeclaration
+{
+ extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
+ {
+ super(loc, endloc, Identifier.generateIdWithLoc("_staticCtor", loc), STC.static_ | stc, null);
+ }
+
+ extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
+ {
+ super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
+ }
+
+ override StaticCtorDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto scd = new StaticCtorDeclaration(loc, endloc, storage_class);
+ FuncDeclaration.syntaxCopy(scd);
+ return scd;
+ }
+
+ override final inout(AggregateDeclaration) isThis() inout @nogc nothrow pure @safe
+ {
+ return null;
+ }
+
+ override final bool isVirtual() const @nogc nothrow pure @safe
+ {
+ return false;
+ }
+
+ override final bool addPreInvariant() @nogc nothrow pure @safe
+ {
+ return false;
+ }
+
+ override final bool addPostInvariant() @nogc nothrow pure @safe
+ {
+ return false;
+ }
+
+ override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
+ {
+ return true;
+ }
+
+ override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class SharedStaticCtorDeclaration : StaticCtorDeclaration
+{
+ extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
+ {
+ super(loc, endloc, "_sharedStaticCtor", stc);
+ }
+
+ override SharedStaticCtorDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto scd = new SharedStaticCtorDeclaration(loc, endloc, storage_class);
+ FuncDeclaration.syntaxCopy(scd);
+ return scd;
+ }
+
+ override inout(SharedStaticCtorDeclaration) isSharedStaticCtorDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) class StaticDtorDeclaration : FuncDeclaration
+{
+ VarDeclaration vgate; // 'gate' variable
+
+ extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
+ {
+ super(loc, endloc, Identifier.generateIdWithLoc("_staticDtor", loc), STC.static_ | stc, null);
+ }
+
+ extern (D) this(const ref Loc loc, const ref Loc endloc, string name, StorageClass stc)
+ {
+ super(loc, endloc, Identifier.generateIdWithLoc(name, loc), STC.static_ | stc, null);
+ }
+
+ override StaticDtorDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto sdd = new StaticDtorDeclaration(loc, endloc, storage_class);
+ FuncDeclaration.syntaxCopy(sdd);
+ return sdd;
+ }
+
+ override final inout(AggregateDeclaration) isThis() inout
+ {
+ return null;
+ }
+
+ override final bool isVirtual() const
+ {
+ return false;
+ }
+
+ override final bool hasStaticCtorOrDtor()
+ {
+ return true;
+ }
+
+ override final bool addPreInvariant()
+ {
+ return false;
+ }
+
+ override final bool addPostInvariant()
+ {
+ return false;
+ }
+
+ override final inout(StaticDtorDeclaration) isStaticDtorDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class SharedStaticDtorDeclaration : StaticDtorDeclaration
+{
+ extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc)
+ {
+ super(loc, endloc, "_sharedStaticDtor", stc);
+ }
+
+ override SharedStaticDtorDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto sdd = new SharedStaticDtorDeclaration(loc, endloc, storage_class);
+ FuncDeclaration.syntaxCopy(sdd);
+ return sdd;
+ }
+
+ override inout(SharedStaticDtorDeclaration) isSharedStaticDtorDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class InvariantDeclaration : FuncDeclaration
+{
+ extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
+ {
+ super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
+ this.fbody = fbody;
+ }
+
+ override InvariantDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto id = new InvariantDeclaration(loc, endloc, storage_class, null, null);
+ FuncDeclaration.syntaxCopy(id);
+ return id;
+ }
+
+ override bool isVirtual() const
+ {
+ return false;
+ }
+
+ override bool addPreInvariant()
+ {
+ return false;
+ }
+
+ override bool addPostInvariant()
+ {
+ return false;
+ }
+
+ override inout(InvariantDeclaration) isInvariantDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+
+/***********************************************************
+ */
+extern (C++) final class UnitTestDeclaration : FuncDeclaration
+{
+ char* codedoc; // for documented unittest
+
+ // toObjFile() these nested functions after this one
+ FuncDeclarations deferredNested;
+
+ extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, char* codedoc)
+ {
+ super(loc, endloc, Identifier.generateIdWithLoc("__unittest", loc), stc, null);
+ this.codedoc = codedoc;
+ }
+
+ override UnitTestDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto utd = new UnitTestDeclaration(loc, endloc, storage_class, codedoc);
+ FuncDeclaration.syntaxCopy(utd);
+ return utd;
+ }
+
+ override inout(AggregateDeclaration) isThis() inout
+ {
+ return null;
+ }
+
+ override bool isVirtual() const
+ {
+ return false;
+ }
+
+ override bool addPreInvariant()
+ {
+ return false;
+ }
+
+ override bool addPostInvariant()
+ {
+ return false;
+ }
+
+ override inout(UnitTestDeclaration) isUnitTestDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class NewDeclaration : FuncDeclaration
+{
+ extern (D) this(const ref Loc loc, StorageClass stc)
+ {
+ super(loc, Loc.initial, Id.classNew, STC.static_ | stc, null);
+ }
+
+ override NewDeclaration syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ auto f = new NewDeclaration(loc, storage_class);
+ FuncDeclaration.syntaxCopy(f);
+ return f;
+ }
+
+ override const(char)* kind() const
+ {
+ return "allocator";
+ }
+
+ override bool isVirtual() const
+ {
+ return false;
+ }
+
+ override bool addPreInvariant()
+ {
+ return false;
+ }
+
+ override bool addPostInvariant()
+ {
+ return false;
+ }
+
+ override inout(NewDeclaration) isNewDeclaration() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
new file mode 100644
index 0000000..9b65d02
--- /dev/null
+++ b/gcc/d/dmd/globals.d
@@ -0,0 +1,640 @@
+/**
+ * Stores command line options and contains other miscellaneous declarations.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/globals.d, _globals.d)
+ * Documentation: https://dlang.org/phobos/dmd_globals.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/globals.d
+ */
+
+module dmd.globals;
+
+import core.stdc.stdint;
+import dmd.root.array;
+import dmd.root.filename;
+import dmd.root.outbuffer;
+import dmd.identifier;
+
+/// Defines a setting for how compiler warnings and deprecations are handled
+enum DiagnosticReporting : ubyte
+{
+ error, /// generate an error
+ inform, /// generate a warning
+ off, /// disable diagnostic
+}
+
+/// How code locations are formatted for diagnostic reporting
+enum MessageStyle : ubyte
+{
+ digitalmars, /// filename.d(line): message
+ gnu, /// filename.d:line: message, see https://www.gnu.org/prep/standards/html_node/Errors.html
+}
+
+/// In which context checks for assertions, contracts, bounds checks etc. are enabled
+enum CHECKENABLE : ubyte
+{
+ _default, /// initial value
+ off, /// never do checking
+ on, /// always do checking
+ safeonly, /// do checking only in @safe functions
+}
+
+/// What should happend when an assertion fails
+enum CHECKACTION : ubyte
+{
+ D, /// call D assert on failure
+ C, /// call C assert on failure
+ halt, /// cause program halt on failure
+ context, /// call D assert with the error context on failure
+}
+
+/// Position Indepent Code setting
+enum PIC : ubyte
+{
+ fixed, /// located at a specific address
+ pic, /// Position Independent Code
+ pie, /// Position Independent Executable
+}
+
+/**
+Each flag represents a field that can be included in the JSON output.
+
+NOTE: set type to uint so its size matches C++ unsigned type
+*/
+enum JsonFieldFlags : uint
+{
+ none = 0,
+ compilerInfo = (1 << 0),
+ buildInfo = (1 << 1),
+ modules = (1 << 2),
+ semantics = (1 << 3),
+}
+
+/// Version of C++ standard to support
+enum CppStdRevision : uint
+{
+ cpp98 = 1997_11,
+ cpp11 = 2011_03,
+ cpp14 = 2014_02,
+ cpp17 = 2017_03,
+ cpp20 = 2020_02,
+}
+
+/// Configuration for the C++ header generator
+enum CxxHeaderMode : uint
+{
+ none, /// Don't generate headers
+ silent, /// Generate headers
+ verbose /// Generate headers and add comments for hidden declarations
+}
+
+/// Trivalent boolean to represent the state of a `revert`able change
+enum FeatureState : byte
+{
+ default_ = -1, /// Not specified by the user
+ disabled = 0, /// Specified as `-revert=`
+ enabled = 1 /// Specified as `-preview=`
+}
+
+/// Put command line switches in here
+extern (C++) struct Param
+{
+ bool obj = true; // write object file
+ bool link = true; // perform link
+ bool dll; // generate shared dynamic library
+ bool lib; // write library file instead of object file(s)
+ bool multiobj; // break one object file into multiple ones
+ bool oneobj; // write one object file instead of multiple ones
+ bool trace; // insert profiling hooks
+ bool tracegc; // instrument calls to 'new'
+ bool verbose; // verbose compile
+ bool vcg_ast; // write-out codegen-ast
+ bool showColumns; // print character (column) numbers in diagnostics
+ bool vtls; // identify thread local variables
+ bool vtemplates; // collect and list statistics on template instantiations
+ bool vtemplatesListInstances; // collect and list statistics on template instantiations origins. TODO: make this an enum when we want to list other kinds of instances
+ bool vgc; // identify gc usage
+ bool vfield; // identify non-mutable field variables
+ bool vcomplex = true; // identify complex/imaginary type usage
+ ubyte symdebug; // insert debug symbolic information
+ bool symdebugref; // insert debug information for all referenced types, too
+ bool optimize; // run optimizer
+ DiagnosticReporting useDeprecated = DiagnosticReporting.inform; // how use of deprecated features are handled
+ bool stackstomp; // add stack stomping code
+ bool useUnitTests; // generate unittest code
+ bool useInline = false; // inline expand functions
+ FeatureState useDIP25; // implement http://wiki.dlang.org/DIP25
+ FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params
+ bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md
+ bool release; // build release version
+ bool preservePaths; // true means don't strip path from source file
+ DiagnosticReporting warnings = DiagnosticReporting.off; // how compiler warnings are handled
+ PIC pic = PIC.fixed; // generate fixed, pic or pie code
+ bool color; // use ANSI colors in console output
+ bool cov; // generate code coverage data
+ ubyte covPercent; // 0..100 code coverage percentage required
+ bool ctfe_cov = false; // generate coverage data for ctfe
+ bool nofloat; // code should not pull in floating point support
+ bool ignoreUnsupportedPragmas; // rather than error on them
+ bool useModuleInfo = true; // generate runtime module information
+ bool useTypeInfo = true; // generate runtime type information
+ bool useExceptions = true; // support exception handling
+ bool noSharedAccess; // read/write access to shared memory objects
+ bool previewIn; // `in` means `[ref] scope const`, accepts rvalues
+ bool shortenedMethods; // allow => in normal function declarations
+ bool betterC; // be a "better C" compiler; no dependency on D runtime
+ bool addMain; // add a default main() function
+ bool allInst; // generate code for all template instantiations
+ bool fix16997; // fix integral promotions for unary + - ~ operators
+ // https://issues.dlang.org/show_bug.cgi?id=16997
+ bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes
+ bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract
+ /** The --transition=safe switch should only be used to show code with
+ * silent semantics changes related to @safe improvements. It should not be
+ * used to hide a feature that will have to go through deprecate-then-error
+ * before becoming default.
+ */
+ bool ehnogc; // use @nogc exception handling
+ FeatureState dtorFields; // destruct fields of partially constructed objects
+ // https://issues.dlang.org/show_bug.cgi?id=14246
+ bool fieldwise; // do struct equality testing field-wise rather than by memcmp()
+ bool rvalueRefParam; // allow rvalues to be arguments to ref parameters
+ // http://dconf.org/2019/talks/alexandrescu.html
+ // https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
+ // https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
+ // Implementation: https://github.com/dlang/dmd/pull/9817
+
+ CppStdRevision cplusplus = CppStdRevision.cpp11; // version of C++ standard to support
+
+ bool markdown = true; // enable Markdown replacements in Ddoc
+ bool vmarkdown; // list instances of Markdown replacements in Ddoc
+
+ bool showGaggedErrors; // print gagged errors anyway
+ bool printErrorContext; // print errors with the error context (the error line in the source file)
+ bool manual; // open browser on compiler manual
+ bool usage; // print usage and exit
+ bool mcpuUsage; // print help on -mcpu switch
+ bool transitionUsage; // print help on -transition switch
+ bool checkUsage; // print help on -check switch
+ bool checkActionUsage; // print help on -checkaction switch
+ bool revertUsage; // print help on -revert switch
+ bool previewUsage; // print help on -preview switch
+ bool externStdUsage; // print help on -extern-std switch
+ bool hcUsage; // print help on -HC switch
+ bool logo; // print compiler logo
+
+ CHECKENABLE useInvariants = CHECKENABLE._default; // generate class invariant checks
+ CHECKENABLE useIn = CHECKENABLE._default; // generate precondition checks
+ CHECKENABLE useOut = CHECKENABLE._default; // generate postcondition checks
+ CHECKENABLE useArrayBounds = CHECKENABLE._default; // when to generate code for array bounds checks
+ CHECKENABLE useAssert = CHECKENABLE._default; // when to generate code for assert()'s
+ CHECKENABLE useSwitchError = CHECKENABLE._default; // check for switches without a default
+ CHECKENABLE boundscheck = CHECKENABLE._default; // state of -boundscheck switch
+
+ CHECKACTION checkAction = CHECKACTION.D; // action to take when bounds, asserts or switch defaults are violated
+
+ uint errorLimit = 20;
+
+ const(char)[] argv0; // program name
+ Array!(const(char)*) modFileAliasStrings; // array of char*'s of -I module filename alias strings
+ Array!(const(char)*)* imppath; // array of char*'s of where to look for import modules
+ Array!(const(char)*)* fileImppath; // array of char*'s of where to look for file import modules
+ const(char)[] objdir; // .obj/.lib file output directory
+ const(char)[] objname; // .obj file output name
+ const(char)[] libname; // .lib file output name
+
+ bool doDocComments; // process embedded documentation comments
+ const(char)[] docdir; // write documentation file to docdir directory
+ const(char)[] docname; // write documentation file to docname
+ Array!(const(char)*) ddocfiles; // macro include files for Ddoc
+
+ bool doHdrGeneration; // process embedded documentation comments
+ const(char)[] hdrdir; // write 'header' file to docdir directory
+ const(char)[] hdrname; // write 'header' file to docname
+ bool hdrStripPlainFunctions = true; // strip the bodies of plain (non-template) functions
+
+ CxxHeaderMode doCxxHdrGeneration; /// Generate 'Cxx header' file
+ const(char)[] cxxhdrdir; // write 'header' file to docdir directory
+ const(char)[] cxxhdrname; // write 'header' file to docname
+
+ bool doJsonGeneration; // write JSON file
+ const(char)[] jsonfilename; // write JSON file to jsonfilename
+ JsonFieldFlags jsonFieldFlags; // JSON field flags to include
+
+ OutBuffer* mixinOut; // write expanded mixins for debugging
+ const(char)* mixinFile; // .mixin file output name
+ int mixinLines; // Number of lines in writeMixins
+
+ uint debuglevel; // debug level
+ Array!(const(char)*)* debugids; // debug identifiers
+
+ uint versionlevel; // version level
+ Array!(const(char)*)* versionids; // version identifiers
+
+ const(char)[] defaultlibname; // default library for non-debug builds
+ const(char)[] debuglibname; // default library for debug builds
+ const(char)[] mscrtlib; // MS C runtime library
+
+ const(char)[] moduleDepsFile; // filename for deps output
+ OutBuffer* moduleDeps; // contents to be written to deps file
+
+ bool emitMakeDeps; // whether to emit makedeps
+ const(char)[] makeDepsFile; // filename for makedeps output
+ Array!(const(char)*) makeDeps; // dependencies for makedeps
+
+ MessageStyle messageStyle = MessageStyle.digitalmars; // style of file/line annotations on messages
+
+ bool run; // run resulting executable
+ Strings runargs; // arguments for executable
+
+ // Linker stuff
+ Array!(const(char)*) objfiles;
+ Array!(const(char)*) linkswitches;
+ Array!bool linkswitchIsForCC;
+ Array!(const(char)*) libfiles;
+ Array!(const(char)*) dllfiles;
+ const(char)[] deffile;
+ const(char)[] resfile;
+ const(char)[] exefile;
+ const(char)[] mapfile;
+}
+
+alias structalign_t = uint;
+
+// magic value means "match whatever the underlying C compiler does"
+// other values are all powers of 2
+enum STRUCTALIGN_DEFAULT = (cast(structalign_t)~0);
+
+enum mars_ext = "d"; // for D source files
+enum doc_ext = "html"; // for Ddoc generated files
+enum ddoc_ext = "ddoc"; // for Ddoc macro include files
+enum dd_ext = "dd"; // for Ddoc source files
+enum hdr_ext = "di"; // for D 'header' import files
+enum json_ext = "json"; // for JSON files
+enum map_ext = "map"; // for .map files
+enum c_ext = "c"; // for C source files
+enum i_ext = "i"; // for preprocessed C source file
+
+/**
+ * Collection of global compiler settings and global state used by the frontend
+ */
+extern (C++) struct Global
+{
+ const(char)[] inifilename; /// filename of configuration file as given by `-conf=`, or default value
+
+ string copyright = "Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved";
+ string written = "written by Walter Bright";
+
+ Array!(const(char)*)* path; /// Array of char*'s which form the import lookup path
+ Array!(const(char)*)* filePath; /// Array of char*'s which form the file import lookup path
+
+ private enum string _version = import("VERSION");
+ private enum uint _versionNumber = parseVersionNumber(_version);
+
+ const(char)[] vendor; /// Compiler backend name
+
+ Param params; /// command line parameters
+ uint errors; /// number of errors reported so far
+ uint warnings; /// number of warnings reported so far
+ uint gag; /// !=0 means gag reporting of errors & warnings
+ uint gaggedErrors; /// number of errors reported while gagged
+ uint gaggedWarnings; /// number of warnings reported while gagged
+
+ void* console; /// opaque pointer to console for controlling text attributes
+
+ Array!Identifier* versionids; /// command line versions and predefined versions
+ Array!Identifier* debugids; /// command line debug versions and predefined versions
+
+ enum recursionLimit = 500; /// number of recursive template expansions before abort
+
+ nothrow:
+
+ /**
+ * Start ignoring compile errors instead of reporting them.
+ *
+ * Used for speculative compilation like `__traits(compiles, XXX)`, but also internally
+ * to e.g. try out an `alias this` rewrite without comitting to it.
+ *
+ * Works like a stack, so N calls to `startGagging` should be paired with N
+ * calls to `endGagging`.
+ *
+ * Returns: the current number of gagged errors, which should later be passed to `endGagging`
+ */
+ extern (C++) uint startGagging()
+ {
+ ++gag;
+ gaggedWarnings = 0;
+ return gaggedErrors;
+ }
+
+ /**
+ * Stop gagging, restoring the old gagged state before the most recent call to `startGagging`.
+ *
+ * Params:
+ * oldGagged = the previous number of errors, as returned by `startGagging`
+ * Returns: true if errors occurred while gagged.
+ */
+ extern (C++) bool endGagging(uint oldGagged)
+ {
+ bool anyErrs = (gaggedErrors != oldGagged);
+ --gag;
+ // Restore the original state of gagged errors; set total errors
+ // to be original errors + new ungagged errors.
+ errors -= (gaggedErrors - oldGagged);
+ gaggedErrors = oldGagged;
+ return anyErrs;
+ }
+
+ /**
+ * Increment the error count to record that an error has occurred in the current context.
+ *
+ * An error message may or may not have been printed.
+ */
+ extern (C++) void increaseErrorCount()
+ {
+ if (gag)
+ ++gaggedErrors;
+ ++errors;
+ }
+
+ extern (C++) void _init()
+ {
+ version (MARS)
+ {
+ vendor = "Digital Mars D";
+
+ // -color=auto is the default value
+ import dmd.console : detectTerminal;
+ params.color = detectTerminal();
+ }
+ else version (IN_GCC)
+ {
+ vendor = "GNU D";
+ }
+ }
+
+ /**
+ * Deinitializes the global state of the compiler.
+ *
+ * This can be used to restore the state set by `_init` to its original
+ * state.
+ */
+ extern (D) void deinitialize()
+ {
+ this = this.init;
+ }
+
+ /**
+ * Computes the version number __VERSION__ from the compiler version string.
+ */
+ extern (D) private static uint parseVersionNumber(string version_)
+ {
+ //
+ // parse _version
+ //
+ uint major = 0;
+ uint minor = 0;
+ bool point = false;
+ // skip initial 'v'
+ foreach (const c; version_[1..$])
+ {
+ if ('0' <= c && c <= '9') // isdigit
+ {
+ minor = minor * 10 + c - '0';
+ }
+ else if (c == '.')
+ {
+ if (point)
+ break; // ignore everything after second '.'
+ point = true;
+ major = minor;
+ minor = 0;
+ }
+ else
+ break;
+ }
+ return major * 1000 + minor;
+ }
+
+ /**
+ Returns: the version as the number that would be returned for __VERSION__
+ */
+ extern(C++) uint versionNumber()
+ {
+ return _versionNumber;
+ }
+
+ /**
+ Returns: compiler version string.
+ */
+ extern(D) string versionString()
+ {
+ return _version;
+ }
+
+ /**
+ Returns: compiler version as char string.
+ */
+ extern(C++) const(char*) versionChars()
+ {
+ return _version.ptr;
+ }
+
+ /**
+ Returns: the final defaultlibname based on the command-line parameters
+ */
+ extern (D) const(char)[] finalDefaultlibname() const
+ {
+ return params.betterC ? null :
+ params.symdebug ? params.debuglibname : params.defaultlibname;
+ }
+}
+
+// Because int64_t and friends may be any integral type of the
+// correct size, we have to explicitly ask for the correct
+// integer type to get the correct mangling with dmd
+
+// Be careful not to care about sign when using dinteger_t
+// use this instead of integer_t to
+// avoid conflicts with system #include's
+alias dinteger_t = ulong;
+// Signed and unsigned variants
+alias sinteger_t = long;
+alias uinteger_t = ulong;
+
+alias d_int8 = int8_t;
+alias d_uns8 = uint8_t;
+alias d_int16 = int16_t;
+alias d_uns16 = uint16_t;
+alias d_int32 = int32_t;
+alias d_uns32 = uint32_t;
+alias d_int64 = int64_t;
+alias d_uns64 = uint64_t;
+
+version (DMDLIB)
+{
+ version = LocOffset;
+}
+
+/**
+A source code location
+
+Used for error messages, `__FILE__` and `__LINE__` tokens, `__traits(getLocation, XXX)`,
+debug info etc.
+*/
+struct Loc
+{
+ /// zero-terminated filename string, either absolute or relative to cwd
+ const(char)* filename;
+ uint linnum; /// line number, starting from 1
+ uint charnum; /// utf8 code unit index relative to start of line, starting from 1
+ version (LocOffset)
+ uint fileOffset; /// utf8 code unit index relative to start of file, starting from 0
+
+ static immutable Loc initial; /// use for default initialization of const ref Loc's
+
+nothrow:
+ extern (D) this(const(char)* filename, uint linnum, uint charnum) pure
+ {
+ this.linnum = linnum;
+ this.charnum = charnum;
+ this.filename = filename;
+ }
+
+ extern (C++) const(char)* toChars(
+ bool showColumns = global.params.showColumns,
+ ubyte messageStyle = global.params.messageStyle) const pure nothrow
+ {
+ OutBuffer buf;
+ if (filename)
+ {
+ buf.writestring(filename);
+ }
+ if (linnum)
+ {
+ final switch (messageStyle)
+ {
+ case MessageStyle.digitalmars:
+ buf.writeByte('(');
+ buf.print(linnum);
+ if (showColumns && charnum)
+ {
+ buf.writeByte(',');
+ buf.print(charnum);
+ }
+ buf.writeByte(')');
+ break;
+ case MessageStyle.gnu: // https://www.gnu.org/prep/standards/html_node/Errors.html
+ buf.writeByte(':');
+ buf.print(linnum);
+ if (showColumns && charnum)
+ {
+ buf.writeByte(':');
+ buf.print(charnum);
+ }
+ break;
+ }
+ }
+ return buf.extractChars();
+ }
+
+ /**
+ * Checks for equivalence by comparing the filename contents (not the pointer) and character location.
+ *
+ * Note:
+ * - Uses case-insensitive comparison on Windows
+ * - Ignores `charnum` if `global.params.showColumns` is false.
+ */
+ extern (C++) bool equals(ref const(Loc) loc) const
+ {
+ return (!global.params.showColumns || charnum == loc.charnum) &&
+ linnum == loc.linnum &&
+ FileName.equals(filename, loc.filename);
+ }
+
+ /**
+ * `opEquals()` / `toHash()` for AA key usage
+ *
+ * Compare filename contents (case-sensitively on Windows too), not
+ * the pointer - a static foreach loop repeatedly mixing in a mixin
+ * may lead to multiple equivalent filenames (`foo.d-mixin-<line>`),
+ * e.g., for test/runnable/test18880.d.
+ */
+ extern (D) bool opEquals(ref const(Loc) loc) const @trusted pure nothrow @nogc
+ {
+ import core.stdc.string : strcmp;
+
+ return charnum == loc.charnum &&
+ linnum == loc.linnum &&
+ (filename == loc.filename ||
+ (filename && loc.filename && strcmp(filename, loc.filename) == 0));
+ }
+
+ /// ditto
+ extern (D) size_t toHash() const @trusted pure nothrow
+ {
+ import dmd.root.string : toDString;
+
+ auto hash = hashOf(linnum);
+ hash = hashOf(charnum, hash);
+ hash = hashOf(filename.toDString, hash);
+ return hash;
+ }
+
+ /******************
+ * Returns:
+ * true if Loc has been set to other than the default initialization
+ */
+ bool isValid() const pure
+ {
+ return filename !is null;
+ }
+}
+
+/// A linkage attribute as defined by `extern(XXX)`
+///
+/// https://dlang.org/spec/attribute.html#linkage
+enum LINK : ubyte
+{
+ default_,
+ d,
+ c,
+ cpp,
+ windows,
+ objc,
+ system,
+}
+
+/// Whether to mangle an external aggregate as a struct or class, as set by `extern(C++, struct)`
+enum CPPMANGLE : ubyte
+{
+ def, /// default
+ asStruct, /// `extern(C++, struct)`
+ asClass, /// `extern(C++, class)`
+}
+
+/// Function match levels
+///
+/// https://dlang.org/spec/function.html#function-overloading
+enum MATCH : int
+{
+ nomatch, /// no match
+ convert, /// match with conversions
+ constant, /// match with conversion to const
+ exact, /// exact match
+}
+
+/// Inline setting as defined by `pragma(inline, XXX)`
+enum PINLINE : ubyte
+{
+ default_, /// as specified on the command line
+ never, /// never inline
+ always, /// always inline
+}
+
+alias StorageClass = uinteger_t;
+
+/// Collection of global state
+extern (C++) __gshared Global global;
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index d9d59d6..6e79474 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -27,6 +27,13 @@ enum
DIAGNOSTICoff // disable diagnostic
};
+typedef unsigned char MessageStyle;
+enum
+{
+ MESSAGESTYLEdigitalmars, // file(line,column): message
+ MESSAGESTYLEgnu // file:line:column: message
+};
+
// The state of array bounds checking
typedef unsigned char CHECKENABLE;
enum
@@ -42,26 +49,17 @@ enum
{
CHECKACTION_D, // call D assert on failure
CHECKACTION_C, // call C assert on failure
- CHECKACTION_halt // cause program halt on failure
+ CHECKACTION_halt, // cause program halt on failure
+ CHECKACTION_context // call D assert with the error context on failure
};
-enum CPU
+enum JsonFieldFlags
{
- x87,
- mmx,
- sse,
- sse2,
- sse3,
- ssse3,
- sse4_1,
- sse4_2,
- avx, // AVX1 instruction set
- avx2, // AVX2 instruction set
- avx512, // AVX-512 instruction set
-
- // Special values that don't survive past the command line processing
- baseline, // (default) the minimum capability CPU
- native // the machine the compiler is being run on
+ none = 0,
+ compilerInfo = (1 << 0),
+ buildInfo = (1 << 1),
+ modules = (1 << 2),
+ semantics = (1 << 3)
};
enum CppStdRevision
@@ -69,7 +67,24 @@ enum CppStdRevision
CppStdRevisionCpp98 = 199711,
CppStdRevisionCpp11 = 201103,
CppStdRevisionCpp14 = 201402,
- CppStdRevisionCpp17 = 201703
+ CppStdRevisionCpp17 = 201703,
+ CppStdRevisionCpp20 = 202002
+};
+
+/// Configuration for the C++ header generator
+enum class CxxHeaderMode
+{
+ none, /// Don't generate headers
+ silent, /// Generate headers
+ verbose /// Generate headers and add comments for hidden declarations
+};
+
+/// Trivalent boolean to represent the state of a `revert`able change
+enum class FeatureState : signed char
+{
+ default_ = -1, /// Not specified by the user
+ disabled = 0, /// Specified as `-revert=`
+ enabled = 1 /// Specified as `-preview=`
};
// Put command line switches in here
@@ -87,50 +102,65 @@ struct Param
bool vcg_ast; // write-out codegen-ast
bool showColumns; // print character (column) numbers in diagnostics
bool vtls; // identify thread local variables
- char vgc; // identify gc usage
+ bool vtemplates; // collect and list statistics on template instantiations
+ bool vtemplatesListInstances; // collect and list statistics on template instantiations origins
+ bool vgc; // identify gc usage
bool vfield; // identify non-mutable field variables
bool vcomplex; // identify complex/imaginary type usage
- char symdebug; // insert debug symbolic information
+ unsigned char symdebug; // insert debug symbolic information
bool symdebugref; // insert debug information for all referenced types, too
- bool alwaysframe; // always emit standard stack frame
bool optimize; // run optimizer
- bool map; // generate linker .map file
- bool is64bit; // generate 64 bit code
- bool isLP64; // generate code for LP64
- bool isLinux; // generate code for linux
- bool isOSX; // generate code for Mac OSX
- bool isWindows; // generate code for Windows
- bool isFreeBSD; // generate code for FreeBSD
- bool isOpenBSD; // generate code for OpenBSD
- bool isSolaris; // generate code for Solaris
- bool hasObjectiveC; // target supports Objective-C
- bool mscoff; // for Win32: write COFF object files instead of OMF
Diagnostic useDeprecated;
bool stackstomp; // add stack stomping code
bool useUnitTests; // generate unittest code
bool useInline; // inline expand functions
- bool useDIP25; // implement http://wiki.dlang.org/DIP25
+ FeatureState useDIP25; // implement http://wiki.dlang.org/DIP25
+ FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params
+ bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md
bool release; // build release version
bool preservePaths; // true means don't strip path from source file
Diagnostic warnings;
- bool pic; // generate position-independent-code for shared libs
+ unsigned char pic; // generate position-independent-code for shared libs
bool color; // use ANSI colors in console output
bool cov; // generate code coverage data
unsigned char covPercent; // 0..100 code coverage percentage required
+ bool ctfe_cov; // generate coverage data for ctfe
bool nofloat; // code should not pull in floating point support
bool ignoreUnsupportedPragmas; // rather than error on them
- bool enforcePropertySyntax;
bool useModuleInfo; // generate runtime module information
bool useTypeInfo; // generate runtime type information
bool useExceptions; // support exception handling
+ bool noSharedAccess; // read/write access to shared memory objects
+ bool previewIn; // `in` means `scope const`, perhaps `ref`, accepts rvalues
+ bool shortenedMethods; // allow => in normal function declarations
bool betterC; // be a "better C" compiler; no dependency on D runtime
bool addMain; // add a default main() function
bool allInst; // generate code for all template instantiations
- bool vsafe; // use enhanced @safe checking
- unsigned cplusplus; // version of C++ name mangling to support
+ bool fix16997; // fix integral promotions for unary + - ~ operators
+ // https://issues.dlang.org/show_bug.cgi?id=16997
+ bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes
+ bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract
+ bool ehnogc; // use @nogc exception handling
+ FeatureState dtorFields; // destruct fields of partially constructed objects
+ // https://issues.dlang.org/show_bug.cgi?id=14246
+ bool fieldwise; // do struct equality testing field-wise rather than by memcmp()
+ bool rvalueRefParam; // allow rvalues to be arguments to ref parameters
+ CppStdRevision cplusplus; // version of C++ name mangling to support
+ bool markdown; // enable Markdown replacements in Ddoc
+ bool vmarkdown; // list instances of Markdown replacements in Ddoc
bool showGaggedErrors; // print gagged errors anyway
-
- CPU cpu; // CPU instruction set to target
+ bool printErrorContext; // print errors with the error context (the error line in the source file)
+ bool manual; // open browser on compiler manual
+ bool usage; // print usage and exit
+ bool mcpuUsage; // print help on -mcpu switch
+ bool transitionUsage; // print help on -transition switch
+ bool checkUsage; // print help on -check switch
+ bool checkActionUsage; // print help on -checkaction switch
+ bool revertUsage; // print help on -revert switch
+ bool previewUsage; // print help on -preview switch
+ bool externStdUsage; // print help on -extern-std switch
+ bool hcUsage; // print help on -HC switch
+ bool logo; // print logo;
CHECKENABLE useInvariants; // generate class invariant checks
CHECKENABLE useIn; // generate precondition checks
@@ -162,8 +192,17 @@ struct Param
DString hdrname; // write 'header' file to docname
bool hdrStripPlainFunctions; // strip the bodies of plain (non-template) functions
+ CxxHeaderMode doCxxHdrGeneration; // write 'Cxx header' file
+ DString cxxhdrdir; // write 'header' file to docdir directory
+ DString cxxhdrname; // write 'header' file to docname
+
bool doJsonGeneration; // write JSON file
DString jsonfilename; // write JSON file to jsonfilename
+ unsigned jsonFieldFlags; // JSON field flags to include
+
+ OutBuffer *mixinOut; // write expanded mixins for debugging
+ const char *mixinFile; // .mixin file output name
+ int mixinLines; // Number of lines in writeMixins
unsigned debuglevel; // debug level
Array<const char *> *debugids; // debug identifiers
@@ -178,13 +217,11 @@ struct Param
DString moduleDepsFile; // filename for deps output
OutBuffer *moduleDeps; // contents to be written to deps file
- // Hidden debug switches
- bool debugb;
- bool debugc;
- bool debugf;
- bool debugr;
- bool debugx;
- bool debugy;
+ bool emitMakeDeps; // whether to emit makedeps
+ DString makeDepsFile; // filename for makedeps output
+ Array<const char *> makeDeps; // dependencies for makedeps
+
+ MessageStyle messageStyle; // style of file/line annotations on messages
bool run; // run resulting executable
Strings runargs; // arguments for executable
@@ -192,6 +229,7 @@ struct Param
// Linker stuff
Array<const char *> objfiles;
Array<const char *> linkswitches;
+ Array<bool> linkswitchIsForCC;
Array<const char *> libfiles;
Array<const char *> dllfiles;
DString deffile;
@@ -205,36 +243,30 @@ typedef unsigned structalign_t;
// other values are all powers of 2
#define STRUCTALIGN_DEFAULT ((structalign_t) ~0)
+const DString mars_ext = "d";
+const DString doc_ext = "html"; // for Ddoc generated files
+const DString ddoc_ext = "ddoc"; // for Ddoc macro include files
+const DString dd_ext = "dd"; // for Ddoc source files
+const DString hdr_ext = "di"; // for D 'header' import files
+const DString json_ext = "json"; // for JSON files
+const DString map_ext = "map"; // for .map files
+
struct Global
{
DString inifilename;
- DString mars_ext;
- DString obj_ext;
- DString lib_ext;
- DString dll_ext;
- DString doc_ext; // for Ddoc generated files
- DString ddoc_ext; // for Ddoc macro include files
- DString hdr_ext; // for D 'header' import files
- DString cxxhdr_ext; // for C/C++ 'header' files
- DString json_ext; // for JSON files
- DString map_ext; // for .map files
- bool run_noext; // allow -run sources without extensions.
-
- DString copyright;
- DString written;
- const char *main_d; // dummy filename for dummy main()
+
+ const DString copyright;
+ const DString written;
Array<const char *> *path; // Array of char*'s which form the import lookup path
Array<const char *> *filePath; // Array of char*'s which form the file import lookup path
- DString version; // Compiler version string
DString vendor; // Compiler backend name
Param params;
- unsigned errors; // number of errors reported so far
- unsigned warnings; // number of warnings reported so far
- FILE *stdmsg; // where to send verbose messages
- unsigned gag; // !=0 means gag reporting of errors & warnings
- unsigned gaggedErrors; // number of errors reported while gagged
+ unsigned errors; // number of errors reported so far
+ unsigned warnings; // number of warnings reported so far
+ unsigned gag; // !=0 means gag reporting of errors & warnings
+ unsigned gaggedErrors; // number of errors reported while gagged
unsigned gaggedWarnings; // number of warnings reported while gagged
void* console; // opaque pointer to console for controlling text attributes
@@ -242,8 +274,6 @@ struct Global
Array<class Identifier*>* versionids; // command line versions and predefined versions
Array<class Identifier*>* debugids; // command line debug versions and predefined versions
- enum { recursionLimit = 500 }; // number of recursive template expansions before abort
-
/* Start gagging. Return the current number of gagged errors
*/
unsigned startGagging();
@@ -260,17 +290,43 @@ struct Global
void increaseErrorCount();
void _init();
+
+ /**
+ Returns: the version as the number that would be returned for __VERSION__
+ */
+ unsigned versionNumber();
+
+ /**
+ Returns: the compiler version string.
+ */
+ const char * versionChars();
};
extern Global global;
+// Because int64_t and friends may be any integral type of the correct size,
+// we have to explicitly ask for the correct integer type to get the correct
+// mangling with dmd. The #if logic here should match the mangling of
+// Tint64 and Tuns64 in cppmangle.d.
+#if MARS && DMD_VERSION >= 2079 && DMD_VERSION <= 2081 && \
+ __APPLE__ && __SIZEOF_LONG__ == 8
+// DMD versions between 2.079 and 2.081 mapped D long to int64_t on OS X.
+typedef uint64_t dinteger_t;
+typedef int64_t sinteger_t;
+typedef uint64_t uinteger_t;
+#elif __SIZEOF_LONG__ == 8
// Be careful not to care about sign when using dinteger_t
// use this instead of integer_t to
// avoid conflicts with system #include's
-typedef uint64_t dinteger_t;
+typedef unsigned long dinteger_t;
// Signed and unsigned variants
-typedef int64_t sinteger_t;
-typedef uint64_t uinteger_t;
+typedef long sinteger_t;
+typedef unsigned long uinteger_t;
+#else
+typedef unsigned long long dinteger_t;
+typedef long long sinteger_t;
+typedef unsigned long long uinteger_t;
+#endif
typedef int8_t d_int8;
typedef uint8_t d_uns8;
@@ -295,43 +351,50 @@ struct Loc
filename = NULL;
}
- Loc(const char *filename, unsigned linnum, unsigned charnum);
+ Loc(const char *filename, unsigned linnum, unsigned charnum)
+ {
+ this->linnum = linnum;
+ this->charnum = charnum;
+ this->filename = filename;
+ }
- const char *toChars() const;
- bool equals(const Loc& loc);
+ const char *toChars(
+ bool showColumns = global.params.showColumns,
+ MessageStyle messageStyle = global.params.messageStyle) const;
+ bool equals(const Loc& loc) const;
};
-enum LINK
+enum class LINK : uint8_t
{
- LINKdefault,
- LINKd,
- LINKc,
- LINKcpp,
- LINKwindows,
- LINKobjc,
- LINKsystem
+ default_,
+ d,
+ c,
+ cpp,
+ windows,
+ objc,
+ system
};
-enum CPPMANGLE
+enum class CPPMANGLE : uint8_t
{
- CPPMANGLEdefault,
- CPPMANGLEstruct,
- CPPMANGLEclass
+ def,
+ asStruct,
+ asClass
};
-enum MATCH
+enum class MATCH : int
{
- MATCHnomatch, // no match
- MATCHconvert, // match with conversions
- MATCHconst, // match with conversion to const
- MATCHexact // exact match
+ nomatch, // no match
+ convert, // match with conversions
+ constant, // match with conversion to const
+ exact // exact match
};
-enum PINLINE
+enum class PINLINE : uint8_t
{
- PINLINEdefault, // as specified on the command line
- PINLINEnever, // never inline
- PINLINEalways // always inline
+ default_, // as specified on the command line
+ never, // never inline
+ always // always inline
};
typedef uinteger_t StorageClass;
diff --git a/gcc/d/dmd/gluelayer.d b/gcc/d/dmd/gluelayer.d
new file mode 100644
index 0000000..debb9ca
--- /dev/null
+++ b/gcc/d/dmd/gluelayer.d
@@ -0,0 +1,90 @@
+/**
+ * Declarations for back-end functions that the front-end invokes.
+ *
+ * This 'glues' either the DMC or GCC back-end to the front-end.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/gluelayer.d, _gluelayer.d)
+ * Documentation: https://dlang.org/phobos/dmd_gluelayer.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/gluelayer.d
+ */
+
+module dmd.gluelayer;
+
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.mtype;
+import dmd.statement;
+import dmd.root.file;
+
+version (NoBackend)
+{
+ struct Symbol;
+ struct code;
+ struct block;
+ struct Blockx;
+ struct elem;
+ struct TYPE;
+ alias type = TYPE;
+
+ extern (C++)
+ {
+ // iasm
+ Statement asmSemantic(AsmStatement s, Scope* sc)
+ {
+ sc.func.hasReturnExp = 8;
+ return null;
+ }
+
+ // toir
+ void toObjFile(Dsymbol ds, bool multiobj) {}
+
+ extern(C++) abstract class ObjcGlue
+ {
+ static void initialize() {}
+ }
+ }
+}
+else version (MARS)
+{
+ public import dmd.backend.cc : block, Blockx, Symbol;
+ public import dmd.backend.type : type;
+ public import dmd.backend.el : elem;
+ public import dmd.backend.code_x86 : code;
+
+ extern (C++)
+ {
+ Statement asmSemantic(AsmStatement s, Scope* sc);
+
+ void toObjFile(Dsymbol ds, bool multiobj);
+
+ extern(C++) abstract class ObjcGlue
+ {
+ static void initialize();
+ }
+ }
+}
+else version (IN_GCC)
+{
+ extern (C++) union tree_node;
+
+ alias Symbol = tree_node;
+ alias code = tree_node;
+ alias type = tree_node;
+
+ extern (C++)
+ {
+ Statement asmSemantic(AsmStatement s, Scope* sc);
+ }
+
+ // stubs
+ extern(C++) abstract class ObjcGlue
+ {
+ static void initialize() {}
+ }
+}
+else
+ static assert(false, "Unsupported compiler backend");
diff --git a/gcc/d/dmd/hdrgen.c b/gcc/d/dmd/hdrgen.c
deleted file mode 100644
index 9397b1e..0000000
--- a/gcc/d/dmd/hdrgen.c
+++ /dev/null
@@ -1,3591 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Dave Fladebo
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/hdrgen.c
- */
-
-// Routines to emit header files
-
-#include "root/dsystem.h"
-#include "root/rmem.h"
-
-#include "mars.h"
-#include "id.h"
-#include "init.h"
-
-#include "attrib.h"
-#include "cond.h"
-#include "doc.h"
-#include "enum.h"
-#include "import.h"
-#include "module.h"
-#include "mtype.h"
-#include "parse.h"
-#include "scope.h"
-#include "staticassert.h"
-#include "target.h"
-#include "template.h"
-#include "utf.h"
-#include "version.h"
-
-#include "declaration.h"
-#include "aggregate.h"
-#include "expression.h"
-#include "ctfe.h"
-#include "statement.h"
-#include "aliasthis.h"
-#include "nspace.h"
-#include "hdrgen.h"
-
-void linkageToBuffer(OutBuffer *buf, LINK linkage);
-void MODtoBuffer(OutBuffer *buf, MOD mod);
-
-void genhdrfile(Module *m)
-{
- OutBuffer buf;
- buf.doindent = 1;
-
- buf.printf("// D import file generated from '%s'", m->srcfile->toChars());
- buf.writenl();
-
- HdrGenState hgs;
- hgs.hdrgen = true;
-
- toCBuffer(m, &buf, &hgs);
-
- // Transfer image to file
- m->hdrfile->setbuffer(buf.slice().ptr, buf.length());
- buf.extractData();
-
- ensurePathToNameExists(Loc(), m->hdrfile->toChars());
- writeFile(m->loc, m->hdrfile);
-}
-
-/**
- * Dumps the full contents of module `m` to `buf`.
- * Params:
- * buf = buffer to write to.
- * m = module to visit all members of.
- */
-void moduleToBuffer(OutBuffer *buf, Module *m)
-{
- HdrGenState hgs;
- hgs.fullDump = true;
- toCBuffer(m, buf, &hgs);
-}
-
-class PrettyPrintVisitor : public Visitor
-{
-public:
- OutBuffer *buf;
- HdrGenState *hgs;
- bool declstring; // set while declaring alias for string,wstring or dstring
- EnumDeclaration *inEnumDecl;
-
- PrettyPrintVisitor(OutBuffer *buf, HdrGenState *hgs)
- : buf(buf), hgs(hgs), declstring(false), inEnumDecl(NULL)
- {
- }
-
- void visit(Statement *)
- {
- buf->printf("Statement::toCBuffer()");
- buf->writenl();
- assert(0);
- }
-
- void visit(ErrorStatement *)
- {
- buf->printf("__error__");
- buf->writenl();
- }
-
- void visit(ExpStatement *s)
- {
- if (s->exp && s->exp->op == TOKdeclaration)
- {
- // bypass visit(DeclarationExp)
- ((DeclarationExp *)s->exp)->declaration->accept(this);
- return;
- }
- if (s->exp)
- s->exp->accept(this);
- buf->writeByte(';');
- if (!hgs->forStmtInit)
- buf->writenl();
- }
-
- void visit(CompileStatement *s)
- {
- buf->writestring("mixin(");
- argsToBuffer(s->exps);
- buf->writestring(");");
- if (!hgs->forStmtInit)
- buf->writenl();
- }
-
- void visit(CompoundStatement *s)
- {
- for (size_t i = 0; i < s->statements->length; i++)
- {
- Statement *sx = (*s->statements)[i];
- if (sx)
- sx->accept(this);
- }
- }
-
- void visit(CompoundDeclarationStatement *s)
- {
- bool anywritten = false;
- for (size_t i = 0; i < s->statements->length; i++)
- {
- Statement *sx = (*s->statements)[i];
- ExpStatement *ds = sx ? sx->isExpStatement() : NULL;
- if (ds && ds->exp->op == TOKdeclaration)
- {
- Dsymbol *d = ((DeclarationExp *)ds->exp)->declaration;
- assert(d->isDeclaration());
- if (VarDeclaration *v = d->isVarDeclaration())
- visitVarDecl(v, anywritten);
- else
- d->accept(this);
- anywritten = true;
- }
- }
- buf->writeByte(';');
- if (!hgs->forStmtInit)
- buf->writenl();
- }
-
- void visit(UnrolledLoopStatement *s)
- {
- buf->writestring("unrolled {");
- buf->writenl();
- buf->level++;
-
- for (size_t i = 0; i < s->statements->length; i++)
- {
- Statement *sx = (*s->statements)[i];
- if (sx)
- sx->accept(this);
- }
-
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- }
-
- void visit(ScopeStatement *s)
- {
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
-
- if (s->statement)
- s->statement->accept(this);
-
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- }
-
- void visit(WhileStatement *s)
- {
- buf->writestring("while (");
- s->condition->accept(this);
- buf->writeByte(')');
- buf->writenl();
- if (s->_body)
- s->_body->accept(this);
- }
-
- void visit(DoStatement *s)
- {
- buf->writestring("do");
- buf->writenl();
- if (s->_body)
- s->_body->accept(this);
- buf->writestring("while (");
- s->condition->accept(this);
- buf->writestring(");");
- buf->writenl();
- }
-
- void visit(ForStatement *s)
- {
- buf->writestring("for (");
- if (s->_init)
- {
- hgs->forStmtInit++;
- s->_init->accept(this);
- hgs->forStmtInit--;
- }
- else
- buf->writeByte(';');
- if (s->condition)
- {
- buf->writeByte(' ');
- s->condition->accept(this);
- }
- buf->writeByte(';');
- if (s->increment)
- {
- buf->writeByte(' ');
- s->increment->accept(this);
- }
- buf->writeByte(')');
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- if (s->_body)
- s->_body->accept(this);
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- }
-
- void foreachWithoutBody(ForeachStatement *s)
- {
- buf->writestring(Token::toChars(s->op));
- buf->writestring(" (");
- for (size_t i = 0; i < s->parameters->length; i++)
- {
- Parameter *p = (*s->parameters)[i];
- if (i)
- buf->writestring(", ");
- if (stcToBuffer(buf, p->storageClass))
- buf->writeByte(' ');
- if (p->type)
- typeToBuffer(p->type, p->ident);
- else
- buf->writestring(p->ident->toChars());
- }
- buf->writestring("; ");
- s->aggr->accept(this);
- buf->writeByte(')');
- buf->writenl();
- }
-
- void visit(ForeachStatement *s)
- {
- foreachWithoutBody(s);
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- if (s->_body)
- s->_body->accept(this);
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- }
-
- void foreachRangeWithoutBody(ForeachRangeStatement *s)
- {
- buf->writestring(Token::toChars(s->op));
- buf->writestring(" (");
-
- if (s->prm->type)
- typeToBuffer(s->prm->type, s->prm->ident);
- else
- buf->writestring(s->prm->ident->toChars());
-
- buf->writestring("; ");
- s->lwr->accept(this);
- buf->writestring(" .. ");
- s->upr->accept(this);
- buf->writeByte(')');
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- }
-
- void visit(ForeachRangeStatement *s)
- {
- foreachRangeWithoutBody(s);
- buf->level++;
- if (s->_body)
- s->_body->accept(this);
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- }
-
- void visit(StaticForeachStatement *s)
- {
- buf->writestring("static ");
- if (s->sfe->aggrfe)
- {
- visit(s->sfe->aggrfe);
- }
- else
- {
- assert(s->sfe->rangefe);
- visit(s->sfe->rangefe);
- }
- }
-
- void visit(IfStatement *s)
- {
- buf->writestring("if (");
- if (Parameter *p = s->prm)
- {
- StorageClass stc = p->storageClass;
- if (!p->type && !stc)
- stc = STCauto;
- if (stcToBuffer(buf, stc))
- buf->writeByte(' ');
- if (p->type)
- typeToBuffer(p->type, p->ident);
- else
- buf->writestring(p->ident->toChars());
- buf->writestring(" = ");
- }
- s->condition->accept(this);
- buf->writeByte(')');
- buf->writenl();
- if (s->ifbody->isScopeStatement())
- {
- s->ifbody->accept(this);
- }
- else
- {
- buf->level++;
- s->ifbody->accept(this);
- buf->level--;
- }
- if (s->elsebody)
- {
- buf->writestring("else");
- if (!s->elsebody->isIfStatement())
- {
- buf->writenl();
- }
- else
- {
- buf->writeByte(' ');
- }
- if (s->elsebody->isScopeStatement() || s->elsebody->isIfStatement())
- {
- s->elsebody->accept(this);
- }
- else
- {
- buf->level++;
- s->elsebody->accept(this);
- buf->level--;
- }
- }
- }
-
- void visit(ConditionalStatement *s)
- {
- s->condition->accept(this);
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- if (s->ifbody)
- s->ifbody->accept(this);
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- if (s->elsebody)
- {
- buf->writestring("else");
- buf->writenl();
- buf->writeByte('{');
- buf->level++;
- buf->writenl();
- s->elsebody->accept(this);
- buf->level--;
- buf->writeByte('}');
- }
- buf->writenl();
- }
-
- void visit(PragmaStatement *s)
- {
- buf->writestring("pragma (");
- buf->writestring(s->ident->toChars());
- if (s->args && s->args->length)
- {
- buf->writestring(", ");
- argsToBuffer(s->args);
- }
- buf->writeByte(')');
- if (s->_body)
- {
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
-
- s->_body->accept(this);
-
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- }
- else
- {
- buf->writeByte(';');
- buf->writenl();
- }
- }
-
- void visit(StaticAssertStatement *s)
- {
- s->sa->accept(this);
- }
-
- void visit(SwitchStatement *s)
- {
- buf->writestring(s->isFinal ? "final switch (" : "switch (");
- s->condition->accept(this);
- buf->writeByte(')');
- buf->writenl();
- if (s->_body)
- {
- if (!s->_body->isScopeStatement())
- {
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- s->_body->accept(this);
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- }
- else
- {
- s->_body->accept(this);
- }
- }
- }
-
- void visit(CaseStatement *s)
- {
- buf->writestring("case ");
- s->exp->accept(this);
- buf->writeByte(':');
- buf->writenl();
- s->statement->accept(this);
- }
-
- void visit(CaseRangeStatement *s)
- {
- buf->writestring("case ");
- s->first->accept(this);
- buf->writestring(": .. case ");
- s->last->accept(this);
- buf->writeByte(':');
- buf->writenl();
- s->statement->accept(this);
- }
-
- void visit(DefaultStatement *s)
- {
- buf->writestring("default:");
- buf->writenl();
- s->statement->accept(this);
- }
-
- void visit(GotoDefaultStatement *)
- {
- buf->writestring("goto default;");
- buf->writenl();
- }
-
- void visit(GotoCaseStatement *s)
- {
- buf->writestring("goto case");
- if (s->exp)
- {
- buf->writeByte(' ');
- s->exp->accept(this);
- }
- buf->writeByte(';');
- buf->writenl();
- }
-
- void visit(SwitchErrorStatement *)
- {
- buf->writestring("SwitchErrorStatement::toCBuffer()");
- buf->writenl();
- }
-
- void visit(ReturnStatement *s)
- {
- buf->printf("return ");
- if (s->exp)
- s->exp->accept(this);
- buf->writeByte(';');
- buf->writenl();
- }
-
- void visit(BreakStatement *s)
- {
- buf->writestring("break");
- if (s->ident)
- {
- buf->writeByte(' ');
- buf->writestring(s->ident->toChars());
- }
- buf->writeByte(';');
- buf->writenl();
- }
-
- void visit(ContinueStatement *s)
- {
- buf->writestring("continue");
- if (s->ident)
- {
- buf->writeByte(' ');
- buf->writestring(s->ident->toChars());
- }
- buf->writeByte(';');
- buf->writenl();
- }
-
- void visit(SynchronizedStatement *s)
- {
- buf->writestring("synchronized");
- if (s->exp)
- {
- buf->writeByte('(');
- s->exp->accept(this);
- buf->writeByte(')');
- }
- if (s->_body)
- {
- buf->writeByte(' ');
- s->_body->accept(this);
- }
- }
-
- void visit(WithStatement *s)
- {
- buf->writestring("with (");
- s->exp->accept(this);
- buf->writestring(")");
- buf->writenl();
- if (s->_body)
- s->_body->accept(this);
- }
-
- void visit(TryCatchStatement *s)
- {
- buf->writestring("try");
- buf->writenl();
- if (s->_body)
- s->_body->accept(this);
- for (size_t i = 0; i < s->catches->length; i++)
- {
- Catch *c = (*s->catches)[i];
- visit(c);
- }
- }
-
- void visit(TryFinallyStatement *s)
- {
- buf->writestring("try");
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- s->_body->accept(this);
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- buf->writestring("finally");
- buf->writenl();
- if (s->finalbody->isScopeStatement())
- {
- s->finalbody->accept(this);
- }
- else
- {
- buf->level++;
- s->finalbody->accept(this);
- buf->level--;
- }
- buf->writeByte('}');
- buf->writenl();
- }
-
- void visit(ScopeGuardStatement *s)
- {
- buf->writestring(Token::toChars(s->tok));
- buf->writeByte(' ');
- s->statement->accept(this);
- }
-
- void visit(ThrowStatement *s)
- {
- buf->printf("throw ");
- s->exp->accept(this);
- buf->writeByte(';');
- buf->writenl();
- }
-
- void visit(DebugStatement *s)
- {
- if (s->statement)
- {
- s->statement->accept(this);
- }
- }
-
- void visit(GotoStatement *s)
- {
- buf->writestring("goto ");
- buf->writestring(s->ident->toChars());
- buf->writeByte(';');
- buf->writenl();
- }
-
- void visit(LabelStatement *s)
- {
- buf->writestring(s->ident->toChars());
- buf->writeByte(':');
- buf->writenl();
- if (s->statement)
- s->statement->accept(this);
- }
-
- void visit(AsmStatement *s)
- {
- buf->writestring("asm { ");
- Token *t = s->tokens;
- buf->level++;
- while (t)
- {
- buf->writestring(t->toChars());
- if (t->next &&
- t->value != TOKmin &&
- t->value != TOKcomma && t->next->value != TOKcomma &&
- t->value != TOKlbracket && t->next->value != TOKlbracket &&
- t->next->value != TOKrbracket &&
- t->value != TOKlparen && t->next->value != TOKlparen &&
- t->next->value != TOKrparen &&
- t->value != TOKdot && t->next->value != TOKdot)
- {
- buf->writeByte(' ');
- }
- t = t->next;
- }
- buf->level--;
- buf->writestring("; }");
- buf->writenl();
- }
-
- void visit(ImportStatement *s)
- {
- for (size_t i = 0; i < s->imports->length; i++)
- {
- Dsymbol *imp = (*s->imports)[i];
- imp->accept(this);
- }
- }
-
- void visit(Catch *c)
- {
- buf->writestring("catch");
- if (c->type)
- {
- buf->writeByte('(');
- typeToBuffer(c->type, c->ident);
- buf->writeByte(')');
- }
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- if (c->handler)
- c->handler->accept(this);
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- /**************************************************
- * An entry point to pretty-print type.
- */
- void typeToBuffer(Type *t, Identifier *ident)
- {
- if (t->ty == Tfunction)
- {
- visitFuncIdentWithPrefix((TypeFunction *)t, ident, NULL);
- return;
- }
-
- visitWithMask(t, 0);
-
- if (ident)
- {
- buf->writeByte(' ');
- buf->writestring(ident->toChars());
- }
- }
-
- void visitWithMask(Type *t, unsigned char modMask)
- {
- // Tuples and functions don't use the type constructor syntax
- if (modMask == t->mod ||
- t->ty == Tfunction ||
- t->ty == Ttuple)
- {
- t->accept(this);
- }
- else
- {
- unsigned char m = t->mod & ~(t->mod & modMask);
- if (m & MODshared)
- {
- MODtoBuffer(buf, MODshared);
- buf->writeByte('(');
- }
- if (m & MODwild)
- {
- MODtoBuffer(buf, MODwild);
- buf->writeByte('(');
- }
- if (m & (MODconst | MODimmutable))
- {
- MODtoBuffer(buf, m & (MODconst | MODimmutable));
- buf->writeByte('(');
- }
-
- t->accept(this);
-
- if (m & (MODconst | MODimmutable))
- buf->writeByte(')');
- if (m & MODwild)
- buf->writeByte(')');
- if (m & MODshared)
- buf->writeByte(')');
- }
- }
-
- void visit(Type *t)
- {
- printf("t = %p, ty = %d\n", t, t->ty);
- assert(0);
- }
-
- void visit(TypeError *)
- {
- buf->writestring("_error_");
- }
-
- void visit(TypeBasic *t)
- {
- //printf("TypeBasic::toCBuffer2(t->mod = %d)\n", t->mod);
- buf->writestring(t->dstring);
- }
-
- void visit(TypeTraits *t)
- {
- //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod);
- t->exp->accept(this);
- }
-
- void visit(TypeVector *t)
- {
- //printf("TypeVector::toCBuffer2(t->mod = %d)\n", t->mod);
- buf->writestring("__vector(");
- visitWithMask(t->basetype, t->mod);
- buf->writestring(")");
- }
-
- void visit(TypeSArray *t)
- {
- visitWithMask(t->next, t->mod);
- buf->writeByte('[');
- sizeToBuffer(t->dim);
- buf->writeByte(']');
- }
-
- void visit(TypeDArray *t)
- {
- Type *ut = t->castMod(0);
- if (declstring)
- goto L1;
- if (ut->equals(Type::tstring))
- buf->writestring("string");
- else if (ut->equals(Type::twstring))
- buf->writestring("wstring");
- else if (ut->equals(Type::tdstring))
- buf->writestring("dstring");
- else
- {
- L1:
- visitWithMask(t->next, t->mod);
- buf->writestring("[]");
- }
- }
-
- void visit(TypeAArray *t)
- {
- visitWithMask(t->next, t->mod);
- buf->writeByte('[');
- visitWithMask(t->index, 0);
- buf->writeByte(']');
- }
-
- void visit(TypePointer *t)
- {
- //printf("TypePointer::toCBuffer2() next = %d\n", t->next->ty);
- if (t->next->ty == Tfunction)
- visitFuncIdentWithPostfix((TypeFunction *)t->next, "function");
- else
- {
- visitWithMask(t->next, t->mod);
- buf->writeByte('*');
- }
- }
-
- void visit(TypeReference *t)
- {
- visitWithMask(t->next, t->mod);
- buf->writeByte('&');
- }
-
- void visit(TypeFunction *t)
- {
- //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t->isref);
- visitFuncIdentWithPostfix(t, NULL);
- }
-
- // callback for TypeFunction::attributesApply
- struct PrePostAppendStrings
- {
- OutBuffer *buf;
- bool isPostfixStyle;
- bool isCtor;
-
- static int fp(void *param, const char *str)
- {
- PrePostAppendStrings *p = (PrePostAppendStrings *)param;
-
- // don't write 'ref' for ctors
- if (p->isCtor && strcmp(str, "ref") == 0)
- return 0;
-
- if ( p->isPostfixStyle) p->buf->writeByte(' ');
- p->buf->writestring(str);
- if (!p->isPostfixStyle) p->buf->writeByte(' ');
- return 0;
- }
- };
-
- void visitFuncIdentWithPostfix(TypeFunction *t, const char *ident)
- {
- if (t->inuse)
- {
- t->inuse = 2; // flag error to caller
- return;
- }
- t->inuse++;
-
- PrePostAppendStrings pas;
- pas.buf = buf;
- pas.isCtor = false;
- pas.isPostfixStyle = true;
-
- if (t->linkage > LINKd && hgs->ddoc != 1 && !hgs->hdrgen)
- {
- linkageToBuffer(buf, t->linkage);
- buf->writeByte(' ');
- }
-
- if (t->next)
- {
- typeToBuffer(t->next, NULL);
- if (ident)
- buf->writeByte(' ');
- }
- else if (hgs->ddoc)
- buf->writestring("auto ");
-
- if (ident)
- buf->writestring(ident);
-
- parametersToBuffer(t->parameterList.parameters, t->parameterList.varargs);
-
- /* Use postfix style for attributes
- */
- if (t->mod)
- {
- buf->writeByte(' ');
- MODtoBuffer(buf, t->mod);
- }
- t->attributesApply(&pas, &PrePostAppendStrings::fp);
-
- t->inuse--;
- }
- void visitFuncIdentWithPrefix(TypeFunction *t, Identifier *ident, TemplateDeclaration *td)
- {
- if (t->inuse)
- {
- t->inuse = 2; // flag error to caller
- return;
- }
- t->inuse++;
-
- PrePostAppendStrings pas;
- pas.buf = buf;
- pas.isCtor = (ident == Id::ctor);
- pas.isPostfixStyle = false;
-
- /* Use 'storage class' (prefix) style for attributes
- */
- if (t->mod)
- {
- MODtoBuffer(buf, t->mod);
- buf->writeByte(' ');
- }
- t->attributesApply(&pas, &PrePostAppendStrings::fp);
-
- if (t->linkage > LINKd && hgs->ddoc != 1 && !hgs->hdrgen)
- {
- linkageToBuffer(buf, t->linkage);
- buf->writeByte(' ');
- }
-
- if (ident && ident->toHChars2() != ident->toChars())
- {
- // Don't print return type for ctor, dtor, unittest, etc
- }
- else if (t->next)
- {
- typeToBuffer(t->next, NULL);
- if (ident)
- buf->writeByte(' ');
- }
- else if (hgs->ddoc)
- buf->writestring("auto ");
-
- if (ident)
- buf->writestring(ident->toHChars2());
-
- if (td)
- {
- buf->writeByte('(');
- for (size_t i = 0; i < td->origParameters->length; i++)
- {
- TemplateParameter *p = (*td->origParameters)[i];
- if (i)
- buf->writestring(", ");
- p->accept(this);
- }
- buf->writeByte(')');
- }
- parametersToBuffer(t->parameterList.parameters, t->parameterList.varargs);
-
- t->inuse--;
- }
-
- void visit(TypeDelegate *t)
- {
- visitFuncIdentWithPostfix((TypeFunction *)t->next, "delegate");
- }
-
- void visitTypeQualifiedHelper(TypeQualified *t)
- {
- for (size_t i = 0; i < t->idents.length; i++)
- {
- RootObject *id = t->idents[i];
-
- if (id->dyncast() == DYNCAST_DSYMBOL)
- {
- buf->writeByte('.');
- TemplateInstance *ti = (TemplateInstance *)id;
- ti->accept(this);
- }
- else if (id->dyncast() == DYNCAST_EXPRESSION)
- {
- buf->writeByte('[');
- ((Expression *)id)->accept(this);
- buf->writeByte(']');
- }
- else if (id->dyncast() == DYNCAST_TYPE)
- {
- buf->writeByte('[');
- ((Type *)id)->accept(this);
- buf->writeByte(']');
- }
- else
- {
- buf->writeByte('.');
- buf->writestring(id->toChars());
- }
- }
- }
-
- void visit(TypeIdentifier *t)
- {
- buf->writestring(t->ident->toChars());
- visitTypeQualifiedHelper(t);
- }
-
- void visit(TypeInstance *t)
- {
- t->tempinst->accept(this);
- visitTypeQualifiedHelper(t);
- }
-
- void visit(TypeTypeof *t)
- {
- buf->writestring("typeof(");
- t->exp->accept(this);
- buf->writeByte(')');
- visitTypeQualifiedHelper(t);
- }
-
- void visit(TypeReturn *t)
- {
- buf->writestring("typeof(return)");
- visitTypeQualifiedHelper(t);
- }
-
- void visit(TypeEnum *t)
- {
- buf->writestring(t->sym->toChars());
- }
-
- void visit(TypeStruct *t)
- {
- // Bugzilla 13776: Don't use ti->toAlias() to avoid forward reference error
- // while printing messages.
- TemplateInstance *ti = t->sym->parent ? t->sym->parent->isTemplateInstance() : NULL;
- if (ti && ti->aliasdecl == t->sym)
- buf->writestring(hgs->fullQual ? ti->toPrettyChars() : ti->toChars());
- else
- buf->writestring(hgs->fullQual ? t->sym->toPrettyChars() : t->sym->toChars());
- }
-
- void visit(TypeClass *t)
- {
- // Bugzilla 13776: Don't use ti->toAlias() to avoid forward reference error
- // while printing messages.
- TemplateInstance *ti = t->sym->parent->isTemplateInstance();
- if (ti && ti->aliasdecl == t->sym)
- buf->writestring(hgs->fullQual ? ti->toPrettyChars() : ti->toChars());
- else
- buf->writestring(hgs->fullQual ? t->sym->toPrettyChars() : t->sym->toChars());
- }
-
- void visit(TypeTuple *t)
- {
- parametersToBuffer(t->arguments, 0);
- }
-
- void visit(TypeSlice *t)
- {
- visitWithMask(t->next, t->mod);
-
- buf->writeByte('[');
- sizeToBuffer(t->lwr);
- buf->writestring(" .. ");
- sizeToBuffer(t->upr);
- buf->writeByte(']');
- }
-
- void visit(TypeNull *)
- {
- buf->writestring("typeof(null)");
- }
-
- void visit(TypeMixin *t)
- {
- buf->writestring("mixin(");
- argsToBuffer(t->exps);
- buf->writeByte(')');
- }
-
- void visit(TypeNoreturn *)
- {
- buf->writestring("noreturn");
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- void visit(Dsymbol *s)
- {
- buf->writestring(s->toChars());
- }
-
- void visit(StaticAssert *s)
- {
- buf->writestring(s->kind());
- buf->writeByte('(');
- s->exp->accept(this);
- if (s->msg)
- {
- buf->writestring(", ");
- s->msg->accept(this);
- }
- buf->writestring(");");
- buf->writenl();
- }
-
- void visit(DebugSymbol *s)
- {
- buf->writestring("debug = ");
- if (s->ident)
- buf->writestring(s->ident->toChars());
- else
- buf->printf("%u", s->level);
- buf->writestring(";");
- buf->writenl();
- }
-
- void visit(VersionSymbol *s)
- {
- buf->writestring("version = ");
- if (s->ident)
- buf->writestring(s->ident->toChars());
- else
- buf->printf("%u", s->level);
- buf->writestring(";");
- buf->writenl();
- }
-
- void visit(EnumMember *em)
- {
- if (em->type)
- typeToBuffer(em->type, em->ident);
- else
- buf->writestring(em->ident->toChars());
- if (em->value())
- {
- buf->writestring(" = ");
- em->value()->accept(this);
- }
- }
-
- void visit(Import *imp)
- {
- if (hgs->hdrgen && imp->id == Id::object)
- return; // object is imported by default
-
- if (imp->isstatic)
- buf->writestring("static ");
- buf->writestring("import ");
- if (imp->aliasId)
- {
- buf->printf("%s = ", imp->aliasId->toChars());
- }
- if (imp->packages && imp->packages->length)
- {
- for (size_t i = 0; i < imp->packages->length; i++)
- {
- Identifier *pid = (*imp->packages)[i];
- buf->printf("%s.", pid->toChars());
- }
- }
- buf->printf("%s", imp->id->toChars());
- if (imp->names.length)
- {
- buf->writestring(" : ");
- for (size_t i = 0; i < imp->names.length; i++)
- {
- if (i)
- buf->writestring(", ");
-
- Identifier *name = imp->names[i];
- Identifier *alias = imp->aliases[i];
- if (alias)
- buf->printf("%s = %s", alias->toChars(), name->toChars());
- else
- buf->printf("%s", name->toChars());
- }
- }
- buf->printf(";");
- buf->writenl();
- }
-
- void visit(AliasThis *d)
- {
- buf->writestring("alias ");
- buf->writestring(d->ident->toChars());
- buf->writestring(" this;\n");
- }
-
- void visit(AttribDeclaration *d)
- {
- if (!d->decl)
- {
- buf->writeByte(';');
- buf->writenl();
- return;
- }
-
- if (d->decl->length == 0)
- buf->writestring("{}");
- else if (hgs->hdrgen && d->decl->length == 1 && (*d->decl)[0]->isUnitTestDeclaration())
- {
- // hack for bugzilla 8081
- buf->writestring("{}");
- }
- else if (d->decl->length == 1)
- {
- ((*d->decl)[0])->accept(this);
- return;
- }
- else
- {
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- for (size_t i = 0; i < d->decl->length; i++)
- {
- Dsymbol *de = (*d->decl)[i];
- de->accept(this);
- }
- buf->level--;
- buf->writeByte('}');
- }
- buf->writenl();
- }
-
- void visit(StorageClassDeclaration *d)
- {
- if (stcToBuffer(buf, d->stc))
- buf->writeByte(' ');
- visit((AttribDeclaration *)d);
- }
-
- void visit(DeprecatedDeclaration *d)
- {
- buf->writestring("deprecated(");
- d->msg->accept(this);
- buf->writestring(") ");
- visit((AttribDeclaration *)d);
- }
-
- void visit(LinkDeclaration *d)
- {
- const char *p;
-
- switch (d->linkage)
- {
- case LINKd: p = "D"; break;
- case LINKc: p = "C"; break;
- case LINKcpp: p = "C++"; break;
- case LINKwindows: p = "Windows"; break;
- case LINKobjc: p = "Objective-C"; break;
- default:
- assert(0);
- break;
- }
- buf->writestring("extern (");
- buf->writestring(p);
- buf->writestring(") ");
- visit((AttribDeclaration *)d);
- }
-
- void visit(CPPMangleDeclaration *d)
- {
- const char *p;
-
- switch (d->cppmangle)
- {
- case CPPMANGLEclass: p = "class"; break;
- case CPPMANGLEstruct: p = "struct"; break;
- default:
- assert(0);
- break;
- }
- buf->writestring("extern (C++, ");
- buf->writestring(p);
- buf->writestring(") ");
- visit((AttribDeclaration *)d);
- }
-
- void visit(ProtDeclaration *d)
- {
- protectionToBuffer(buf, d->protection);
- buf->writeByte(' ');
- visit((AttribDeclaration *)d);
- }
-
- void visit(AlignDeclaration *d)
- {
- if (!d->ealign)
- buf->printf("align ");
- else
- buf->printf("align (%s)", d->ealign->toChars());
- visit((AttribDeclaration *)d);
- }
-
- void visit(AnonDeclaration *d)
- {
- buf->printf(d->isunion ? "union" : "struct");
- buf->writenl();
- buf->writestring("{");
- buf->writenl();
- buf->level++;
- if (d->decl)
- {
- for (size_t i = 0; i < d->decl->length; i++)
- {
- Dsymbol *de = (*d->decl)[i];
- de->accept(this);
- }
- }
- buf->level--;
- buf->writestring("}");
- buf->writenl();
- }
-
- void visit(PragmaDeclaration *d)
- {
- buf->printf("pragma (%s", d->ident->toChars());
- if (d->args && d->args->length)
- {
- buf->writestring(", ");
- argsToBuffer(d->args);
- }
- buf->writeByte(')');
- visit((AttribDeclaration *)d);
- }
-
- void visit(ConditionalDeclaration *d)
- {
- d->condition->accept(this);
- if (d->decl || d->elsedecl)
- {
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- if (d->decl)
- {
- for (size_t i = 0; i < d->decl->length; i++)
- {
- Dsymbol *de = (*d->decl)[i];
- de->accept(this);
- }
- }
- buf->level--;
- buf->writeByte('}');
- if (d->elsedecl)
- {
- buf->writenl();
- buf->writestring("else");
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- for (size_t i = 0; i < d->elsedecl->length; i++)
- {
- Dsymbol *de = (*d->elsedecl)[i];
- de->accept(this);
- }
- buf->level--;
- buf->writeByte('}');
- }
- }
- else
- buf->writeByte(':');
- buf->writenl();
- }
-
- void visit(ForwardingStatement *s)
- {
- s->statement->accept(this);
- }
-
- void visit(StaticForeachDeclaration *s)
- {
- buf->writestring("static ");
- if (s->sfe->aggrfe)
- {
- foreachWithoutBody(s->sfe->aggrfe);
- }
- else
- {
- assert(s->sfe->rangefe);
- foreachRangeWithoutBody(s->sfe->rangefe);
- }
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- visit((AttribDeclaration *)s);
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- }
-
- void visit(CompileDeclaration *d)
- {
- buf->writestring("mixin(");
- argsToBuffer(d->exps);
- buf->writestring(");");
- buf->writenl();
- }
-
- void visit(UserAttributeDeclaration *d)
- {
- buf->writestring("@(");
- argsToBuffer(d->atts);
- buf->writeByte(')');
- visit((AttribDeclaration *)d);
- }
-
- void visit(TemplateDeclaration *d)
- {
- if ((hgs->hdrgen || hgs->fullDump) && visitEponymousMember(d))
- return;
-
- if (hgs->ddoc)
- buf->writestring(d->kind());
- else
- buf->writestring("template");
- buf->writeByte(' ');
- buf->writestring(d->ident->toChars());
- buf->writeByte('(');
- visitTemplateParameters(hgs->ddoc ? d->origParameters : d->parameters);
- buf->writeByte(')');
- visitTemplateConstraint(d->constraint);
-
- if (hgs->hdrgen || hgs->fullDump)
- {
- hgs->tpltMember++;
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- for (size_t i = 0; i < d->members->length; i++)
- {
- Dsymbol *s = (*d->members)[i];
- s->accept(this);
- }
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- hgs->tpltMember--;
- }
- }
-
- bool visitEponymousMember(TemplateDeclaration *d)
- {
- if (!d->members || d->members->length != 1)
- return false;
-
- Dsymbol *onemember = (*d->members)[0];
- if (onemember->ident != d->ident)
- return false;
-
- if (FuncDeclaration *fd = onemember->isFuncDeclaration())
- {
- assert(fd->type);
- if (stcToBuffer(buf, fd->storage_class))
- buf->writeByte(' ');
- functionToBufferFull((TypeFunction *)fd->type, buf, d->ident, hgs, d);
- visitTemplateConstraint(d->constraint);
-
- hgs->tpltMember++;
- bodyToBuffer(fd);
- hgs->tpltMember--;
- return true;
- }
- if (AggregateDeclaration *ad = onemember->isAggregateDeclaration())
- {
- buf->writestring(ad->kind());
- buf->writeByte(' ');
- buf->writestring(ad->ident->toChars());
- buf->writeByte('(');
- visitTemplateParameters(hgs->ddoc ? d->origParameters : d->parameters);
- buf->writeByte(')');
- visitTemplateConstraint(d->constraint);
- visitBaseClasses(ad->isClassDeclaration());
-
- hgs->tpltMember++;
- if (ad->members)
- {
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- for (size_t i = 0; i < ad->members->length; i++)
- {
- Dsymbol *s = (*ad->members)[i];
- s->accept(this);
- }
- buf->level--;
- buf->writeByte('}');
- }
- else
- buf->writeByte(';');
- buf->writenl();
- hgs->tpltMember--;
- return true;
- }
- if (VarDeclaration *vd = onemember->isVarDeclaration())
- {
- if (d->constraint)
- return false;
-
- if (stcToBuffer(buf, vd->storage_class))
- buf->writeByte(' ');
- if (vd->type)
- typeToBuffer(vd->type, vd->ident);
- else
- buf->writestring(vd->ident->toChars());
-
- buf->writeByte('(');
- visitTemplateParameters(hgs->ddoc ? d->origParameters : d->parameters);
- buf->writeByte(')');
-
- if (vd->_init)
- {
- buf->writestring(" = ");
- ExpInitializer *ie = vd->_init->isExpInitializer();
- if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit))
- ((AssignExp *)ie->exp)->e2->accept(this);
- else
- vd->_init->accept(this);
- }
- buf->writeByte(';');
- buf->writenl();
- return true;
- }
-
- return false;
- }
- void visitTemplateParameters(TemplateParameters *parameters)
- {
- if (!parameters || !parameters->length)
- return;
- for (size_t i = 0; i < parameters->length; i++)
- {
- TemplateParameter *p = (*parameters)[i];
- if (i)
- buf->writestring(", ");
- p->accept(this);
- }
- }
- void visitTemplateConstraint(Expression *constraint)
- {
- if (!constraint)
- return;
- buf->writestring(" if (");
- constraint->accept(this);
- buf->writeByte(')');
- }
-
- void visit(TemplateInstance *ti)
- {
- buf->writestring(ti->name->toChars());
- tiargsToBuffer(ti);
-
- if (hgs->fullDump)
- {
- buf->writenl();
- if (ti->aliasdecl)
- {
- // the ti.aliasDecl is the instantiated body
- // if we have it, print it.
- ti->aliasdecl->accept(this);
- }
- }
- }
-
- void visit(TemplateMixin *tm)
- {
- buf->writestring("mixin ");
-
- typeToBuffer(tm->tqual, NULL);
- tiargsToBuffer(tm);
-
- if (tm->ident && memcmp(tm->ident->toChars(), "__mixin", 7) != 0)
- {
- buf->writeByte(' ');
- buf->writestring(tm->ident->toChars());
- }
- buf->writeByte(';');
- buf->writenl();
- }
-
- void tiargsToBuffer(TemplateInstance *ti)
- {
- buf->writeByte('!');
- if (ti->nest)
- {
- buf->writestring("(...)");
- return;
- }
- if (!ti->tiargs)
- {
- buf->writestring("()");
- return;
- }
-
- if (ti->tiargs->length == 1)
- {
- RootObject *oarg = (*ti->tiargs)[0];
- if (Type *t = isType(oarg))
- {
- if (t->equals(Type::tstring) ||
- t->equals(Type::twstring) ||
- t->equals(Type::tdstring) ||
- (t->mod == 0 &&
- (t->isTypeBasic() ||
- (t->ty == Tident && ((TypeIdentifier *)t)->idents.length == 0))))
- {
- buf->writestring(t->toChars());
- return;
- }
- }
- else if (Expression *e = isExpression(oarg))
- {
- if (e->op == TOKint64 ||
- e->op == TOKfloat64 ||
- e->op == TOKnull ||
- e->op == TOKstring ||
- e->op == TOKthis)
- {
- buf->writestring(e->toChars());
- return;
- }
- }
- }
- buf->writeByte('(');
- ti->nest++;
- for (size_t i = 0; i < ti->tiargs->length; i++)
- {
- RootObject *arg = (*ti->tiargs)[i];
- if (i)
- buf->writestring(", ");
- objectToBuffer(arg);
- }
- ti->nest--;
- buf->writeByte(')');
- }
-
- /****************************************
- * This makes a 'pretty' version of the template arguments.
- * It's analogous to genIdent() which makes a mangled version.
- */
- void objectToBuffer(RootObject *oarg)
- {
- //printf("objectToBuffer()\n");
-
- /* The logic of this should match what genIdent() does. The _dynamic_cast()
- * function relies on all the pretty strings to be unique for different classes
- * (see Bugzilla 7375).
- * Perhaps it would be better to demangle what genIdent() does.
- */
- if (Type *t = isType(oarg))
- {
- //printf("\tt: %s ty = %d\n", t->toChars(), t->ty);
- typeToBuffer(t, NULL);
- }
- else if (Expression *e = isExpression(oarg))
- {
- if (e->op == TOKvar)
- e = e->optimize(WANTvalue); // added to fix Bugzilla 7375
- e->accept(this);
- }
- else if (Dsymbol *s = isDsymbol(oarg))
- {
- const char *p = s->ident ? s->ident->toChars() : s->toChars();
- buf->writestring(p);
- }
- else if (Tuple *v = isTuple(oarg))
- {
- Objects *args = &v->objects;
- for (size_t i = 0; i < args->length; i++)
- {
- RootObject *arg = (*args)[i];
- if (i)
- buf->writestring(", ");
- objectToBuffer(arg);
- }
- }
- else if (Parameter *p = isParameter(oarg))
- {
- p->accept(this);
- }
- else if (!oarg)
- {
- buf->writestring("NULL");
- }
- else
- {
- assert(0);
- }
- }
-
- void visit(EnumDeclaration *d)
- {
- EnumDeclaration *oldInEnumDecl = inEnumDecl;
- inEnumDecl = d;
- buf->writestring("enum ");
- if (d->ident)
- {
- buf->writestring(d->ident->toChars());
- buf->writeByte(' ');
- }
- if (d->memtype)
- {
- buf->writestring(": ");
- typeToBuffer(d->memtype, NULL);
- }
- if (!d->members)
- {
- buf->writeByte(';');
- buf->writenl();
- inEnumDecl = oldInEnumDecl;
- return;
- }
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- for (size_t i = 0; i < d->members->length; i++)
- {
- EnumMember *em = (*d->members)[i]->isEnumMember();
- if (!em)
- continue;
- em->accept(this);
- buf->writeByte(',');
- buf->writenl();
- }
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- inEnumDecl = oldInEnumDecl;
- }
-
- void visit(Nspace *d)
- {
- buf->writestring("extern (C++, ");
- buf->writestring(d->ident->toChars());
- buf->writeByte(')');
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- for (size_t i = 0; i < d->members->length; i++)
- {
- Dsymbol *s = (*d->members)[i];
- s->accept(this);
- }
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- }
-
- void visit(StructDeclaration *d)
- {
- buf->printf("%s ", d->kind());
- if (!d->isAnonymous())
- buf->writestring(d->toChars());
- if (!d->members)
- {
- buf->writeByte(';');
- buf->writenl();
- return;
- }
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- for (size_t i = 0; i < d->members->length; i++)
- {
- Dsymbol *s = (*d->members)[i];
- s->accept(this);
- }
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
- }
-
- void visit(ClassDeclaration *d)
- {
- if (!d->isAnonymous())
- {
- buf->writestring(d->kind());
- buf->writeByte(' ');
- buf->writestring(d->ident->toChars());
- }
- visitBaseClasses(d);
- if (d->members)
- {
- buf->writenl();
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- for (size_t i = 0; i < d->members->length; i++)
- {
- Dsymbol *s = (*d->members)[i];
- s->accept(this);
- }
- buf->level--;
- buf->writeByte('}');
- }
- else
- buf->writeByte(';');
- buf->writenl();
- }
-
- void visitBaseClasses(ClassDeclaration *d)
- {
- if (!d || !d->baseclasses->length)
- return;
-
- buf->writestring(" : ");
- for (size_t i = 0; i < d->baseclasses->length; i++)
- {
- if (i)
- buf->writestring(", ");
- BaseClass *b = (*d->baseclasses)[i];
- typeToBuffer(b->type, NULL);
- }
- }
-
- void visit(AliasDeclaration *d)
- {
- if (d->storage_class & STClocal)
- return;
- buf->writestring("alias ");
- if (d->aliassym)
- {
- buf->writestring(d->ident->toChars());
- buf->writestring(" = ");
- if (stcToBuffer(buf, d->storage_class))
- buf->writeByte(' ');
- d->aliassym->accept(this);
- }
- else if (d->type->ty == Tfunction)
- {
- if (stcToBuffer(buf, d->storage_class))
- buf->writeByte(' ');
- typeToBuffer(d->type, d->ident);
- }
- else
- {
- declstring = (d->ident == Id::string || d->ident == Id::wstring || d->ident == Id::dstring);
- buf->writestring(d->ident->toChars());
- buf->writestring(" = ");
- if (stcToBuffer(buf, d->storage_class))
- buf->writeByte(' ');
- typeToBuffer(d->type, NULL);
- declstring = false;
- }
- buf->writeByte(';');
- buf->writenl();
- }
-
- void visit(VarDeclaration *d)
- {
- if (d->storage_class & STClocal)
- return;
- visitVarDecl(d, false);
- buf->writeByte(';');
- buf->writenl();
- }
- void visitVarDecl(VarDeclaration *v, bool anywritten)
- {
- if (anywritten)
- {
- buf->writestring(", ");
- buf->writestring(v->ident->toChars());
- }
- else
- {
- if (stcToBuffer(buf, v->storage_class))
- buf->writeByte(' ');
- if (v->type)
- typeToBuffer(v->type, v->ident);
- else
- buf->writestring(v->ident->toChars());
- }
- if (v->_init)
- {
- buf->writestring(" = ");
- ExpInitializer *ie = v->_init->isExpInitializer();
- if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit))
- ((AssignExp *)ie->exp)->e2->accept(this);
- else
- v->_init->accept(this);
- }
- }
-
- void visit(FuncDeclaration *f)
- {
- //printf("FuncDeclaration::toCBuffer() '%s'\n", f->toChars());
-
- if (stcToBuffer(buf, f->storage_class))
- buf->writeByte(' ');
- TypeFunction *tf = (TypeFunction *)f->type;
- typeToBuffer(tf, f->ident);
- if (hgs->hdrgen)
- {
- // if the return type is missing (e.g. ref functions or auto)
- if (!tf->next || f->storage_class & STCauto)
- {
- hgs->autoMember++;
- bodyToBuffer(f);
- hgs->autoMember--;
- }
- else if (hgs->tpltMember == 0 && global.params.hdrStripPlainFunctions)
- {
- buf->writeByte(';');
- buf->writenl();
- }
- else
- bodyToBuffer(f);
- }
- else
- bodyToBuffer(f);
- }
-
- void bodyToBuffer(FuncDeclaration *f)
- {
- if (!f->fbody || (hgs->hdrgen && global.params.hdrStripPlainFunctions && !hgs->autoMember && !hgs->tpltMember))
- {
- buf->writeByte(';');
- buf->writenl();
- return;
- }
-
- int savetlpt = hgs->tpltMember;
- int saveauto = hgs->autoMember;
- hgs->tpltMember = 0;
- hgs->autoMember = 0;
- buf->writenl();
- bool requireDo = false;
- // in{}
- if (f->frequires)
- {
- for (size_t i = 0; i < f->frequires->length; i++)
- {
- Statement *frequire = (*f->frequires)[i];
- buf->writestring("in");
- if (ExpStatement *es = frequire->isExpStatement())
- {
- assert(es->exp && es->exp->op == TOKassert);
- buf->writestring(" (");
- ((AssertExp *)es->exp)->e1->accept(this);
- buf->writeByte(')');
- buf->writenl();
- requireDo = false;
- }
- else
- {
- buf->writenl();
- frequire->accept(this);
- requireDo = true;
- }
- }
- }
-
- // out{}
- if (f->fensures)
- {
- for (size_t i = 0; i < f->fensures->length; i++)
- {
- Ensure fensure = (*f->fensures)[i];
- buf->writestring("out");
- if (ExpStatement *es = fensure.ensure->isExpStatement())
- {
- assert(es->exp && es->exp->op == TOKassert);
- buf->writestring(" (");
- if (fensure.id)
- {
- buf->writestring(fensure.id->toChars());
- }
- buf->writestring("; ");
- ((AssertExp *)es->exp)->e1->accept(this);
- buf->writeByte(')');
- buf->writenl();
- requireDo = false;
- }
- else
- {
- if (fensure.id)
- {
- buf->writeByte('(');
- buf->writestring(fensure.id->toChars());
- buf->writeByte(')');
- }
- buf->writenl();
- fensure.ensure->accept(this);
- requireDo = true;
- }
- }
- }
-
- if (requireDo)
- {
- buf->writestring("body");
- buf->writenl();
- }
-
- buf->writeByte('{');
- buf->writenl();
- buf->level++;
- f->fbody->accept(this);
- buf->level--;
- buf->writeByte('}');
- buf->writenl();
-
- hgs->tpltMember = savetlpt;
- hgs->autoMember = saveauto;
- }
-
- void visit(FuncLiteralDeclaration *f)
- {
- if (f->type->ty == Terror)
- {
- buf->writestring("__error");
- return;
- }
-
- if (f->tok != TOKreserved)
- {
- buf->writestring(f->kind());
- buf->writeByte(' ');
- }
-
- TypeFunction *tf = (TypeFunction *)f->type;
- // Don't print tf->mod, tf->trust, and tf->linkage
- if (!f->inferRetType && tf->next)
- typeToBuffer(tf->next, NULL);
- parametersToBuffer(tf->parameterList.parameters, tf->parameterList.varargs);
-
- CompoundStatement *cs = f->fbody->isCompoundStatement();
- Statement *s1;
- if (f->semanticRun >= PASSsemantic3done && cs)
- {
- s1 = (*cs->statements)[cs->statements->length - 1];
- }
- else
- s1 = !cs ? f->fbody : NULL;
- ReturnStatement *rs = s1 ? s1->isReturnStatement() : NULL;
- if (rs && rs->exp)
- {
- buf->writestring(" => ");
- rs->exp->accept(this);
- }
- else
- {
- hgs->tpltMember++;
- bodyToBuffer(f);
- hgs->tpltMember--;
- }
- }
-
- void visit(PostBlitDeclaration *d)
- {
- if (stcToBuffer(buf, d->storage_class))
- buf->writeByte(' ');
- buf->writestring("this(this)");
- bodyToBuffer(d);
- }
-
- void visit(DtorDeclaration *d)
- {
- if (d->storage_class & STCtrusted)
- buf->writestring("@trusted ");
- if (d->storage_class & STCsafe)
- buf->writestring("@safe ");
- if (d->storage_class & STCnogc)
- buf->writestring("@nogc ");
- if (d->storage_class & STCdisable)
- buf->writestring("@disable ");
-
- buf->writestring("~this()");
- bodyToBuffer(d);
- }
-
- void visit(StaticCtorDeclaration *d)
- {
- if (stcToBuffer(buf, d->storage_class & ~STCstatic))
- buf->writeByte(' ');
- if (d->isSharedStaticCtorDeclaration())
- buf->writestring("shared ");
- buf->writestring("static this()");
- if (hgs->hdrgen && !hgs->tpltMember)
- {
- buf->writeByte(';');
- buf->writenl();
- }
- else
- bodyToBuffer(d);
- }
-
- void visit(StaticDtorDeclaration *d)
- {
- if (hgs->hdrgen)
- return;
- if (stcToBuffer(buf, d->storage_class & ~STCstatic))
- buf->writeByte(' ');
- if (d->isSharedStaticDtorDeclaration())
- buf->writestring("shared ");
- buf->writestring("static ~this()");
- bodyToBuffer(d);
- }
-
- void visit(InvariantDeclaration *d)
- {
- if (hgs->hdrgen)
- return;
- if (stcToBuffer(buf, d->storage_class))
- buf->writeByte(' ');
- buf->writestring("invariant");
- if (ExpStatement *es = d->fbody->isExpStatement())
- {
- assert(es->exp && es->exp->op == TOKassert);
- buf->writestring(" (");
- ((AssertExp *)es->exp)->e1->accept(this);
- buf->writestring(");");
- buf->writenl();
- }
- else
- {
- bodyToBuffer(d);
- }
- }
-
- void visit(UnitTestDeclaration *d)
- {
- if (hgs->hdrgen)
- return;
- if (stcToBuffer(buf, d->storage_class))
- buf->writeByte(' ');
- buf->writestring("unittest");
- bodyToBuffer(d);
- }
-
- void visit(NewDeclaration *d)
- {
- if (stcToBuffer(buf, d->storage_class & ~STCstatic))
- buf->writeByte(' ');
- buf->writestring("new");
- parametersToBuffer(d->parameters, d->varargs);
- bodyToBuffer(d);
- }
-
- void visit(DeleteDeclaration *d)
- {
- if (stcToBuffer(buf, d->storage_class & ~STCstatic))
- buf->writeByte(' ');
- buf->writestring("delete");
- parametersToBuffer(d->parameters, 0);
- bodyToBuffer(d);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- void visit(ErrorInitializer *)
- {
- buf->writestring("__error__");
- }
-
- void visit(VoidInitializer *)
- {
- buf->writestring("void");
- }
-
- void visit(StructInitializer *si)
- {
- //printf("StructInitializer::toCBuffer()\n");
- buf->writeByte('{');
- for (size_t i = 0; i < si->field.length; i++)
- {
- if (i)
- buf->writestring(", ");
- if (Identifier *id = si->field[i])
- {
- buf->writestring(id->toChars());
- buf->writeByte(':');
- }
- if (Initializer *iz = si->value[i])
- iz->accept(this);
- }
- buf->writeByte('}');
- }
-
- void visit(ArrayInitializer *ai)
- {
- buf->writeByte('[');
- for (size_t i = 0; i < ai->index.length; i++)
- {
- if (i)
- buf->writestring(", ");
- if (Expression *ex = ai->index[i])
- {
- ex->accept(this);
- buf->writeByte(':');
- }
- if (Initializer *iz = ai->value[i])
- iz->accept(this);
- }
- buf->writeByte(']');
- }
-
- void visit(ExpInitializer *ei)
- {
- ei->exp->accept(this);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- /**************************************************
- * Write out argument list to buf.
- */
- void argsToBuffer(Expressions *expressions, Expression *basis = NULL)
- {
- if (!expressions || !expressions->length)
- return;
-
- for (size_t i = 0; i < expressions->length; i++)
- {
- Expression *el = (*expressions)[i];
- if (i)
- buf->writestring(", ");
- if (!el)
- el = basis;
- if (el)
- expToBuffer(el, PREC_assign);
- }
- }
-
- void sizeToBuffer(Expression *e)
- {
- if (e->type == Type::tsize_t)
- {
- Expression *ex = (e->op == TOKcast ? ((CastExp *)e)->e1 : e);
- ex = ex->optimize(WANTvalue);
-
- dinteger_t uval = ex->op == TOKint64 ? ex->toInteger() : (dinteger_t)-1;
- if ((sinteger_t)uval >= 0)
- {
- dinteger_t sizemax;
- if (target.ptrsize == 8)
- sizemax = 0xFFFFFFFFFFFFFFFFULL;
- else if (target.ptrsize == 4)
- sizemax = 0xFFFFFFFFUL;
- else if (target.ptrsize == 2)
- sizemax = 0xFFFFUL;
- else
- assert(0);
- if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFULL)
- {
- buf->printf("%llu", uval);
- return;
- }
- }
- }
- expToBuffer(e, PREC_assign);
- }
-
- /**************************************************
- * Write expression out to buf, but wrap it
- * in ( ) if its precedence is less than pr.
- */
- void expToBuffer(Expression *e, PREC pr)
- {
- assert(precedence[e->op] != PREC_zero);
- assert(pr != PREC_zero);
-
- //if (precedence[e->op] == 0) e->print();
- /* Despite precedence, we don't allow a<b<c expressions.
- * They must be parenthesized.
- */
- if (precedence[e->op] < pr ||
- (pr == PREC_rel && precedence[e->op] == pr))
- {
- buf->writeByte('(');
- e->accept(this);
- buf->writeByte(')');
- }
- else
- e->accept(this);
- }
-
- void visit(Expression *e)
- {
- buf->writestring(Token::toChars(e->op));
- }
-
- void visit(IntegerExp *e)
- {
- dinteger_t v = e->toInteger();
-
- if (e->type)
- {
- Type *t = e->type;
- L1:
- switch (t->ty)
- {
- case Tenum:
- {
- TypeEnum *te = (TypeEnum *)t;
- if (hgs->fullDump)
- {
- EnumDeclaration *sym = te->sym;
- if (inEnumDecl != sym)
- {
- for (size_t i = 0; i < sym->members->length; i++)
- {
- EnumMember *em = (EnumMember *)(*sym->members)[i];
- if (em->value()->toInteger() == v)
- {
- buf->printf("%s.%s", sym->toChars(), em->ident->toChars());
- return;
- }
- }
- }
- }
- buf->printf("cast(%s)", te->sym->toChars());
- t = te->sym->memtype;
- goto L1;
- }
-
- case Twchar: // BUG: need to cast(wchar)
- case Tdchar: // BUG: need to cast(dchar)
- if ((uinteger_t)v > 0xFF)
- {
- buf->printf("'\\U%08x'", v);
- break;
- }
- /* fall through */
- case Tchar:
- {
- size_t o = buf->length();
- if (v == '\'')
- buf->writestring("'\\''");
- else if (isprint((int)v) && v != '\\')
- buf->printf("'%c'", (int)v);
- else
- buf->printf("'\\x%02x'", (int)v);
- if (hgs->ddoc)
- escapeDdocString(buf, o);
- break;
- }
-
- case Tint8:
- buf->writestring("cast(byte)");
- goto L2;
-
- case Tint16:
- buf->writestring("cast(short)");
- goto L2;
-
- case Tint32:
- L2:
- buf->printf("%d", (int)v);
- break;
-
- case Tuns8:
- buf->writestring("cast(ubyte)");
- goto L3;
-
- case Tuns16:
- buf->writestring("cast(ushort)");
- goto L3;
-
- case Tuns32:
- L3:
- buf->printf("%uu", (unsigned)v);
- break;
-
- case Tint64:
- buf->printf("%lldL", v);
- break;
-
- case Tuns64:
- L4:
- buf->printf("%lluLU", v);
- break;
-
- case Tbool:
- buf->writestring(v ? "true" : "false");
- break;
-
- case Tpointer:
- buf->writestring("cast(");
- buf->writestring(t->toChars());
- buf->writeByte(')');
- if (target.ptrsize == 8)
- goto L4;
- else if (target.ptrsize == 4 ||
- target.ptrsize == 2)
- goto L3;
- else
- assert(0);
-
- case Tvoid:
- buf->writestring("cast(void)0");
- break;
-
- default:
- /* This can happen if errors, such as
- * the type is painted on like in fromConstInitializer().
- */
- if (!global.errors)
- {
- assert(0);
- }
- break;
- }
- }
- else if (v & 0x8000000000000000LL)
- buf->printf("0x%llx", v);
- else
- buf->printf("%lld", v);
- }
-
- void visit(ErrorExp *)
- {
- buf->writestring("__error");
- }
-
- void floatToBuffer(Type *type, real_t value)
- {
- /** sizeof(value)*3 is because each byte of mantissa is max
- of 256 (3 characters). The string will be "-M.MMMMe-4932".
- (ie, 8 chars more than mantissa). Plus one for trailing \0.
- Plus one for rounding. */
- const size_t BUFFER_LEN = sizeof(value) * 3 + 8 + 1 + 1;
- char buffer[BUFFER_LEN];
- memset(buffer, 0, BUFFER_LEN);
- CTFloat::sprint(buffer, 'g', value);
- assert(strlen(buffer) < BUFFER_LEN);
-
- if (hgs->hdrgen)
- {
- real_t r = CTFloat::parse(buffer);
- if (r != value) // if exact duplication
- CTFloat::sprint(buffer, 'a', value);
- }
- buf->writestring(buffer);
-
- if (type)
- {
- Type *t = type->toBasetype();
- switch (t->ty)
- {
- case Tfloat32:
- case Timaginary32:
- case Tcomplex32:
- buf->writeByte('F');
- break;
-
- case Tfloat80:
- case Timaginary80:
- case Tcomplex80:
- buf->writeByte('L');
- break;
-
- default:
- break;
- }
- if (t->isimaginary())
- buf->writeByte('i');
- }
- }
-
- void visit(RealExp *e)
- {
- floatToBuffer(e->type, e->value);
- }
-
- void visit(ComplexExp *e)
- {
- /* Print as:
- * (re+imi)
- */
- buf->writeByte('(');
- floatToBuffer(e->type, creall(e->value));
- buf->writeByte('+');
- floatToBuffer(e->type, cimagl(e->value));
- buf->writestring("i)");
- }
-
- void visit(IdentifierExp *e)
- {
- if (hgs->hdrgen || hgs->ddoc)
- buf->writestring(e->ident->toHChars2());
- else
- buf->writestring(e->ident->toChars());
- }
-
- void visit(DsymbolExp *e)
- {
- buf->writestring(e->s->toChars());
- }
-
- void visit(ThisExp *)
- {
- buf->writestring("this");
- }
-
- void visit(SuperExp *)
- {
- buf->writestring("super");
- }
-
- void visit(NullExp *)
- {
- buf->writestring("null");
- }
-
- void visit(StringExp *e)
- {
- buf->writeByte('"');
- size_t o = buf->length();
- for (size_t i = 0; i < e->len; i++)
- {
- unsigned c = e->charAt(i);
- switch (c)
- {
- case '"':
- case '\\':
- buf->writeByte('\\');
- /* fall through */
- default:
- if (c <= 0xFF)
- {
- if (c <= 0x7F && isprint(c))
- buf->writeByte(c);
- else
- buf->printf("\\x%02x", c);
- }
- else if (c <= 0xFFFF)
- buf->printf("\\x%02x\\x%02x", c & 0xFF, c >> 8);
- else
- buf->printf("\\x%02x\\x%02x\\x%02x\\x%02x",
- c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24);
- break;
- }
- }
- if (hgs->ddoc)
- escapeDdocString(buf, o);
- buf->writeByte('"');
- if (e->postfix)
- buf->writeByte(e->postfix);
- }
-
- void visit(ArrayLiteralExp *e)
- {
- buf->writeByte('[');
- argsToBuffer(e->elements, e->basis);
- buf->writeByte(']');
- }
-
- void visit(AssocArrayLiteralExp *e)
- {
- buf->writeByte('[');
- for (size_t i = 0; i < e->keys->length; i++)
- {
- Expression *key = (*e->keys)[i];
- Expression *value = (*e->values)[i];
-
- if (i)
- buf->writestring(", ");
- expToBuffer(key, PREC_assign);
- buf->writeByte(':');
- expToBuffer(value, PREC_assign);
- }
- buf->writeByte(']');
- }
-
- void visit(StructLiteralExp *e)
- {
- buf->writestring(e->sd->toChars());
- buf->writeByte('(');
-
- // CTFE can generate struct literals that contain an AddrExp pointing
- // to themselves, need to avoid infinite recursion:
- // struct S { this(int){ this.s = &this; } S* s; }
- // const foo = new S(0);
- if (e->stageflags & stageToCBuffer)
- buf->writestring("<recursion>");
- else
- {
- int old = e->stageflags;
- e->stageflags |= stageToCBuffer;
- argsToBuffer(e->elements);
- e->stageflags = old;
- }
-
- buf->writeByte(')');
- }
-
- void visit(TypeExp *e)
- {
- typeToBuffer(e->type, NULL);
- }
-
- void visit(ScopeExp *e)
- {
- if (e->sds->isTemplateInstance())
- {
- e->sds->accept(this);
- }
- else if (hgs != NULL && hgs->ddoc)
- {
- // fixes bug 6491
- Module *m = e->sds->isModule();
- if (m)
- buf->writestring(m->md->toChars());
- else
- buf->writestring(e->sds->toChars());
- }
- else
- {
- buf->writestring(e->sds->kind());
- buf->writeByte(' ');
- buf->writestring(e->sds->toChars());
- }
- }
-
- void visit(TemplateExp *e)
- {
- buf->writestring(e->td->toChars());
- }
-
- void visit(NewExp *e)
- {
- if (e->thisexp)
- {
- expToBuffer(e->thisexp, PREC_primary);
- buf->writeByte('.');
- }
- buf->writestring("new ");
- if (e->newargs && e->newargs->length)
- {
- buf->writeByte('(');
- argsToBuffer(e->newargs);
- buf->writeByte(')');
- }
- typeToBuffer(e->newtype, NULL);
- if (e->arguments && e->arguments->length)
- {
- buf->writeByte('(');
- argsToBuffer(e->arguments);
- buf->writeByte(')');
- }
- }
-
- void visit(NewAnonClassExp *e)
- {
- if (e->thisexp)
- {
- expToBuffer(e->thisexp, PREC_primary);
- buf->writeByte('.');
- }
- buf->writestring("new");
- if (e->newargs && e->newargs->length)
- {
- buf->writeByte('(');
- argsToBuffer(e->newargs);
- buf->writeByte(')');
- }
- buf->writestring(" class ");
- if (e->arguments && e->arguments->length)
- {
- buf->writeByte('(');
- argsToBuffer(e->arguments);
- buf->writeByte(')');
- }
- if (e->cd)
- e->cd->accept(this);
- }
-
- void visit(SymOffExp *e)
- {
- if (e->offset)
- buf->printf("(& %s+%u)", e->var->toChars(), e->offset);
- else if (e->var->isTypeInfoDeclaration())
- buf->printf("%s", e->var->toChars());
- else
- buf->printf("& %s", e->var->toChars());
- }
-
- void visit(VarExp *e)
- {
- buf->writestring(e->var->toChars());
- }
-
- void visit(OverExp *e)
- {
- buf->writestring(e->vars->ident->toChars());
- }
-
- void visit(TupleExp *e)
- {
- if (e->e0)
- {
- buf->writeByte('(');
- e->e0->accept(this);
- buf->writestring(", tuple(");
- argsToBuffer(e->exps);
- buf->writestring("))");
- }
- else
- {
- buf->writestring("tuple(");
- argsToBuffer(e->exps);
- buf->writeByte(')');
- }
- }
-
- void visit(FuncExp *e)
- {
- e->fd->accept(this);
- //buf->writestring(e->fd->toChars());
- }
-
- void visit(DeclarationExp *e)
- {
- /* Normal dmd execution won't reach here - regular variable declarations
- * are handled in visit(ExpStatement), so here would be used only when
- * we'll directly call Expression::toChars() for debugging.
- */
- if (VarDeclaration *v = e->declaration->isVarDeclaration())
- {
- // For debugging use:
- // - Avoid printing newline.
- // - Intentionally use the format (Type var;)
- // which isn't correct as regular D code.
- buf->writeByte('(');
- visitVarDecl(v, false);
- buf->writeByte(';');
- buf->writeByte(')');
- }
- else
- e->declaration->accept(this);
- }
-
- void visit(TypeidExp *e)
- {
- buf->writestring("typeid(");
- objectToBuffer(e->obj);
- buf->writeByte(')');
- }
-
- void visit(TraitsExp *e)
- {
- buf->writestring("__traits(");
- if (e->ident)
- buf->writestring(e->ident->toChars());
- if (e->args)
- {
- for (size_t i = 0; i < e->args->length; i++)
- {
- RootObject *arg = (*e->args)[i];
- buf->writestring(", ");
- objectToBuffer(arg);
- }
- }
- buf->writeByte(')');
- }
-
- void visit(HaltExp *)
- {
- buf->writestring("halt");
- }
-
- void visit(IsExp *e)
- {
- buf->writestring("is(");
- typeToBuffer(e->targ, e->id);
- if (e->tok2 != TOKreserved)
- {
- buf->printf(" %s %s", Token::toChars(e->tok), Token::toChars(e->tok2));
- }
- else if (e->tspec)
- {
- if (e->tok == TOKcolon)
- buf->writestring(" : ");
- else
- buf->writestring(" == ");
- typeToBuffer(e->tspec, NULL);
- }
- if (e->parameters && e->parameters->length)
- {
- buf->writestring(", ");
- visitTemplateParameters(e->parameters);
- }
- buf->writeByte(')');
- }
-
- void visit(UnaExp *e)
- {
- buf->writestring(Token::toChars(e->op));
- expToBuffer(e->e1, precedence[e->op]);
- }
-
- void visit(BinExp *e)
- {
- expToBuffer(e->e1, precedence[e->op]);
- buf->writeByte(' ');
- buf->writestring(Token::toChars(e->op));
- buf->writeByte(' ');
- expToBuffer(e->e2, (PREC)(precedence[e->op] + 1));
- }
-
- void visit(CompileExp *e)
- {
- buf->writestring("mixin(");
- argsToBuffer(e->exps);
- buf->writeByte(')');
- }
-
- void visit(ImportExp *e)
- {
- buf->writestring("import(");
- expToBuffer(e->e1, PREC_assign);
- buf->writeByte(')');
- }
-
- void visit(AssertExp *e)
- {
- buf->writestring("assert(");
- expToBuffer(e->e1, PREC_assign);
- if (e->msg)
- {
- buf->writestring(", ");
- expToBuffer(e->msg, PREC_assign);
- }
- buf->writeByte(')');
- }
-
- void visit(DotIdExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writeByte('.');
- buf->writestring(e->ident->toChars());
- }
-
- void visit(DotTemplateExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writeByte('.');
- buf->writestring(e->td->toChars());
- }
-
- void visit(DotVarExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writeByte('.');
- buf->writestring(e->var->toChars());
- }
-
- void visit(DotTemplateInstanceExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writeByte('.');
- e->ti->accept(this);
- }
-
- void visit(DelegateExp *e)
- {
- buf->writeByte('&');
- if (!e->func->isNested())
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writeByte('.');
- }
- buf->writestring(e->func->toChars());
- }
-
- void visit(DotTypeExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writeByte('.');
- buf->writestring(e->sym->toChars());
- }
-
- void visit(CallExp *e)
- {
- if (e->e1->op == TOKtype)
- {
- /* Avoid parens around type to prevent forbidden cast syntax:
- * (sometype)(arg1)
- * This is ok since types in constructor calls
- * can never depend on parens anyway
- */
- e->e1->accept(this);
- }
- else
- expToBuffer(e->e1, precedence[e->op]);
- buf->writeByte('(');
- argsToBuffer(e->arguments);
- buf->writeByte(')');
- }
-
- void visit(PtrExp *e)
- {
- buf->writeByte('*');
- expToBuffer(e->e1, precedence[e->op]);
- }
-
- void visit(DeleteExp *e)
- {
- buf->writestring("delete ");
- expToBuffer(e->e1, precedence[e->op]);
- }
-
- void visit(CastExp *e)
- {
- buf->writestring("cast(");
- if (e->to)
- typeToBuffer(e->to, NULL);
- else
- {
- MODtoBuffer(buf, e->mod);
- }
- buf->writeByte(')');
- expToBuffer(e->e1, precedence[e->op]);
- }
-
- void visit(VectorExp *e)
- {
- buf->writestring("cast(");
- typeToBuffer(e->to, NULL);
- buf->writeByte(')');
- expToBuffer(e->e1, precedence[e->op]);
- }
-
- void visit(VectorArrayExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writestring(".array");
- }
-
- void visit(SliceExp *e)
- {
- expToBuffer(e->e1, precedence[e->op]);
- buf->writeByte('[');
- if (e->upr || e->lwr)
- {
- if (e->lwr)
- sizeToBuffer(e->lwr);
- else
- buf->writeByte('0');
- buf->writestring("..");
- if (e->upr)
- sizeToBuffer(e->upr);
- else
- buf->writeByte('$');
- }
- buf->writeByte(']');
- }
-
- void visit(ArrayLengthExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writestring(".length");
- }
-
- void visit(IntervalExp *e)
- {
- expToBuffer(e->lwr, PREC_assign);
- buf->writestring("..");
- expToBuffer(e->upr, PREC_assign);
- }
-
- void visit(DelegatePtrExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writestring(".ptr");
- }
-
- void visit(DelegateFuncptrExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writestring(".funcptr");
- }
-
- void visit(ArrayExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writeByte('[');
- argsToBuffer(e->arguments);
- buf->writeByte(']');
- }
-
- void visit(DotExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writeByte('.');
- expToBuffer(e->e2, PREC_primary);
- }
-
- void visit(IndexExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writeByte('[');
- sizeToBuffer(e->e2);
- buf->writeByte(']');
- }
-
- void visit(PostExp *e)
- {
- expToBuffer(e->e1, precedence[e->op]);
- buf->writestring(Token::toChars(e->op));
- }
-
- void visit(PreExp *e)
- {
- buf->writestring(Token::toChars(e->op));
- expToBuffer(e->e1, precedence[e->op]);
- }
-
- void visit(RemoveExp *e)
- {
- expToBuffer(e->e1, PREC_primary);
- buf->writestring(".remove(");
- expToBuffer(e->e2, PREC_assign);
- buf->writeByte(')');
- }
-
- void visit(CondExp *e)
- {
- expToBuffer(e->econd, PREC_oror);
- buf->writestring(" ? ");
- expToBuffer(e->e1, PREC_expr);
- buf->writestring(" : ");
- expToBuffer(e->e2, PREC_cond);
- }
-
- void visit(DefaultInitExp *e)
- {
- buf->writestring(Token::toChars(e->subop));
- }
-
- void visit(ClassReferenceExp *e)
- {
- buf->writestring(e->value->toChars());
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- void visit(TemplateTypeParameter *tp)
- {
- buf->writestring(tp->ident->toChars());
- if (tp->specType)
- {
- buf->writestring(" : ");
- typeToBuffer(tp->specType, NULL);
- }
- if (tp->defaultType)
- {
- buf->writestring(" = ");
- typeToBuffer(tp->defaultType, NULL);
- }
- }
-
- void visit(TemplateThisParameter *tp)
- {
- buf->writestring("this ");
- visit((TemplateTypeParameter *)tp);
- }
-
- void visit(TemplateAliasParameter *tp)
- {
- buf->writestring("alias ");
- if (tp->specType)
- typeToBuffer(tp->specType, tp->ident);
- else
- buf->writestring(tp->ident->toChars());
- if (tp->specAlias)
- {
- buf->writestring(" : ");
- objectToBuffer(tp->specAlias);
- }
- if (tp->defaultAlias)
- {
- buf->writestring(" = ");
- objectToBuffer(tp->defaultAlias);
- }
- }
-
- void visit(TemplateValueParameter *tp)
- {
- typeToBuffer(tp->valType, tp->ident);
- if (tp->specValue)
- {
- buf->writestring(" : ");
- tp->specValue->accept(this);
- }
- if (tp->defaultValue)
- {
- buf->writestring(" = ");
- tp->defaultValue->accept(this);
- }
- }
-
- void visit(TemplateTupleParameter *tp)
- {
- buf->writestring(tp->ident->toChars());
- buf->writestring("...");
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- void visit(DebugCondition *c)
- {
- if (c->ident)
- buf->printf("debug (%s)", c->ident->toChars());
- else
- buf->printf("debug (%u)", c->level);
- }
-
- void visit(VersionCondition *c)
- {
- if (c->ident)
- buf->printf("version (%s)", c->ident->toChars());
- else
- buf->printf("version (%u)", c->level);
- }
-
- void visit(StaticIfCondition *c)
- {
- buf->writestring("static if (");
- c->exp->accept(this);
- buf->writeByte(')');
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- void visit(Parameter *p)
- {
- if (p->userAttribDecl)
- {
- buf->writestring("@");
- bool isAnonymous = p->userAttribDecl->atts->length > 0
- && (*p->userAttribDecl->atts)[0]->op != TOKcall;
- if (isAnonymous)
- buf->writestring("(");
- argsToBuffer(p->userAttribDecl->atts);
- if (isAnonymous)
- buf->writestring(")");
- buf->writestring(" ");
- }
- if (p->storageClass & STCauto)
- buf->writestring("auto ");
-
- if (p->storageClass & STCreturn)
- buf->writestring("return ");
-
- if (p->storageClass & STCout)
- buf->writestring("out ");
- else if (p->storageClass & STCref)
- buf->writestring("ref ");
- else if (p->storageClass & STCin)
- buf->writestring("in ");
- else if (p->storageClass & STClazy)
- buf->writestring("lazy ");
- else if (p->storageClass & STCalias)
- buf->writestring("alias ");
-
- StorageClass stc = p->storageClass;
- if (p->type && p->type->mod & MODshared)
- stc &= ~STCshared;
-
- if (stcToBuffer(buf, stc & (STCconst | STCimmutable | STCwild | STCshared | STCscope | STCscopeinferred)))
- buf->writeByte(' ');
-
- if (p->storageClass & STCalias)
- {
- if (p->ident)
- buf->writestring(p->ident->toChars());
- }
- else if (p->type->ty == Tident &&
- strlen(((TypeIdentifier *)p->type)->ident->toChars()) > 3 &&
- strncmp(((TypeIdentifier *)p->type)->ident->toChars(), "__T", 3) == 0)
- {
- // print parameter name, instead of undetermined type parameter
- buf->writestring(p->ident->toChars());
- }
- else
- typeToBuffer(p->type, p->ident);
- if (p->defaultArg)
- {
- buf->writestring(" = ");
- p->defaultArg->accept(this);
- }
- }
-
- void parametersToBuffer(Parameters *parameters, int varargs)
- {
- buf->writeByte('(');
- if (parameters)
- {
- size_t dim = Parameter::dim(parameters);
- for (size_t i = 0; i < dim; i++)
- {
- if (i)
- buf->writestring(", ");
- Parameter *fparam = Parameter::getNth(parameters, i);
- fparam->accept(this);
- }
- if (varargs)
- {
- if (parameters->length && varargs == 1)
- buf->writestring(", ");
- buf->writestring("...");
- }
- }
- buf->writeByte(')');
- }
-
- void visit(Module *m)
- {
- if (m->md)
- {
- if (m->userAttribDecl)
- {
- buf->writestring("@(");
- argsToBuffer(m->userAttribDecl->atts);
- buf->writeByte(')');
- buf->writenl();
- }
- if (m->md->isdeprecated)
- {
- if (m->md->msg)
- {
- buf->writestring("deprecated(");
- m->md->msg->accept(this);
- buf->writestring(") ");
- }
- else
- buf->writestring("deprecated ");
- }
-
- buf->writestring("module ");
- buf->writestring(m->md->toChars());
- buf->writeByte(';');
- buf->writenl();
- }
- for (size_t i = 0; i < m->members->length; i++)
- {
- Dsymbol *s = (*m->members)[i];
- s->accept(this);
- }
- }
-};
-
-void toCBuffer(Statement *s, OutBuffer *buf, HdrGenState *hgs)
-{
- PrettyPrintVisitor v(buf, hgs);
- s->accept(&v);
-}
-
-void toCBuffer(Type *t, OutBuffer *buf, Identifier *ident, HdrGenState *hgs)
-{
- PrettyPrintVisitor v(buf, hgs);
- v.typeToBuffer(t, ident);
-}
-
-void toCBuffer(Dsymbol *s, OutBuffer *buf, HdrGenState *hgs)
-{
- PrettyPrintVisitor v(buf, hgs);
- s->accept(&v);
-}
-
-// used from TemplateInstance::toChars() and TemplateMixin::toChars()
-void toCBufferInstance(TemplateInstance *ti, OutBuffer *buf, bool qualifyTypes)
-{
- HdrGenState hgs;
- hgs.fullQual = qualifyTypes;
- PrettyPrintVisitor v(buf, &hgs);
- v.visit(ti);
-}
-
-void toCBuffer(Initializer *iz, OutBuffer *buf, HdrGenState *hgs)
-{
- PrettyPrintVisitor v(buf, hgs);
- iz->accept(&v);
-}
-
-bool stcToBuffer(OutBuffer *buf, StorageClass stc)
-{
- bool result = false;
- if ((stc & (STCreturn | STCscope)) == (STCreturn | STCscope))
- stc &= ~STCscope;
- if (stc & STCscopeinferred)
- stc &= ~(STCscope | STCscopeinferred);
- while (stc)
- {
- const char *p = stcToChars(stc);
- if (!p)
- break;
- if (!result)
- result = true;
- else
- buf->writeByte(' ');
- buf->writestring(p);
- }
- return result;
-}
-
-/*************************************************
- * Pick off one of the storage classes from stc,
- * and return a pointer to a string representation of it.
- * stc is reduced by the one picked.
- */
-const char *stcToChars(StorageClass& stc)
-{
- struct SCstring
- {
- StorageClass stc;
- TOK tok;
- const char *id;
- };
-
- static SCstring table[] =
- {
- { STCauto, TOKauto, NULL },
- { STCscope, TOKscope, NULL },
- { STCstatic, TOKstatic, NULL },
- { STCextern, TOKextern, NULL },
- { STCconst, TOKconst, NULL },
- { STCfinal, TOKfinal, NULL },
- { STCabstract, TOKabstract, NULL },
- { STCsynchronized, TOKsynchronized, NULL },
- { STCdeprecated, TOKdeprecated, NULL },
- { STCoverride, TOKoverride, NULL },
- { STClazy, TOKlazy, NULL },
- { STCalias, TOKalias, NULL },
- { STCout, TOKout, NULL },
- { STCin, TOKin, NULL },
- { STCmanifest, TOKenum, NULL },
- { STCimmutable, TOKimmutable, NULL },
- { STCshared, TOKshared, NULL },
- { STCnothrow, TOKnothrow, NULL },
- { STCwild, TOKwild, NULL },
- { STCpure, TOKpure, NULL },
- { STCref, TOKref, NULL },
- { STCtls, TOKreserved, NULL },
- { STCgshared, TOKgshared, NULL },
- { STCnogc, TOKat, "@nogc" },
- { STCproperty, TOKat, "@property" },
- { STCsafe, TOKat, "@safe" },
- { STCtrusted, TOKat, "@trusted" },
- { STCsystem, TOKat, "@system" },
- { STCdisable, TOKat, "@disable" },
- { STCfuture, TOKat, "@__future" },
- { STClocal, TOKat, "__local" },
- { 0, TOKreserved, NULL }
- };
-
- for (int i = 0; table[i].stc; i++)
- {
- StorageClass tbl = table[i].stc;
- assert(tbl & STCStorageClass);
- if (stc & tbl)
- {
- stc &= ~tbl;
- if (tbl == STCtls) // TOKtls was removed
- return "__thread";
-
- TOK tok = table[i].tok;
- if (tok == TOKat)
- return table[i].id;
- else
- return Token::toChars(tok);
- }
- }
- //printf("stc = %llx\n", stc);
- return NULL;
-}
-
-void trustToBuffer(OutBuffer *buf, TRUST trust)
-{
- const char *p = trustToChars(trust);
- if (p)
- buf->writestring(p);
-}
-
-const char *trustToChars(TRUST trust)
-{
- switch (trust)
- {
- case TRUSTdefault: return NULL;
- case TRUSTsystem: return "@system";
- case TRUSTtrusted: return "@trusted";
- case TRUSTsafe: return "@safe";
- default: assert(0);
- }
- return NULL; // never reached
-}
-
-void linkageToBuffer(OutBuffer *buf, LINK linkage)
-{
- const char *p = linkageToChars(linkage);
- if (p)
- {
- buf->writestring("extern (");
- buf->writestring(p);
- buf->writeByte(')');
- }
-}
-
-const char *linkageToChars(LINK linkage)
-{
- switch (linkage)
- {
- case LINKdefault: return NULL;
- case LINKd: return "D";
- case LINKc: return "C";
- case LINKcpp: return "C++";
- case LINKwindows: return "Windows";
- case LINKobjc: return "Objective-C";
- case LINKsystem: return "System";
- default: assert(0);
- }
- return NULL; // never reached
-}
-
-void protectionToBuffer(OutBuffer *buf, Prot prot)
-{
- const char *p = protectionToChars(prot.kind);
- if (p)
- buf->writestring(p);
-
- if (prot.kind == Prot::package_ && prot.pkg)
- {
- buf->writeByte('(');
- buf->writestring(prot.pkg->toPrettyChars(true));
- buf->writeByte(')');
- }
-}
-
-const char *protectionToChars(Prot::Kind kind)
-{
- switch (kind)
- {
- case Prot::undefined: return NULL;
- case Prot::none: return "none";
- case Prot::private_: return "private";
- case Prot::package_: return "package";
- case Prot::protected_: return "protected";
- case Prot::public_: return "public";
- case Prot::export_: return "export";
- default: assert(0);
- }
- return NULL; // never reached
-}
-
-// Print the full function signature with correct ident, attributes and template args
-void functionToBufferFull(TypeFunction *tf, OutBuffer *buf, Identifier *ident,
- HdrGenState* hgs, TemplateDeclaration *td)
-{
- //printf("TypeFunction::toCBuffer() this = %p\n", this);
- PrettyPrintVisitor v(buf, hgs);
- v.visitFuncIdentWithPrefix(tf, ident, td);
-}
-
-// ident is inserted before the argument list and will be "function" or "delegate" for a type
-void functionToBufferWithIdent(TypeFunction *tf, OutBuffer *buf, const char *ident)
-{
- HdrGenState hgs;
- PrettyPrintVisitor v(buf, &hgs);
- v.visitFuncIdentWithPostfix(tf, ident);
-}
-
-void toCBuffer(Expression *e, OutBuffer *buf, HdrGenState *hgs)
-{
- PrettyPrintVisitor v(buf, hgs);
- e->accept(&v);
-}
-
-/**************************************************
- * Write out argument types to buf.
- */
-void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments)
-{
- if (!arguments || !arguments->length)
- return;
-
- HdrGenState hgs;
- PrettyPrintVisitor v(buf, &hgs);
- for (size_t i = 0; i < arguments->length; i++)
- {
- Expression *arg = (*arguments)[i];
- if (i)
- buf->writestring(", ");
- v.typeToBuffer(arg->type, NULL);
- }
-}
-
-void toCBuffer(TemplateParameter *tp, OutBuffer *buf, HdrGenState *hgs)
-{
- PrettyPrintVisitor v(buf, hgs);
- tp->accept(&v);
-}
-
-void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects)
-{
- if (!objects || !objects->length)
- return;
-
- HdrGenState hgs;
- PrettyPrintVisitor v(buf, &hgs);
- for (size_t i = 0; i < objects->length; i++)
- {
- RootObject *o = (*objects)[i];
- if (i)
- buf->writestring(", ");
- v.objectToBuffer(o);
- }
-}
-
-/*************************************************************
- * Pretty print function parameters.
- * Params:
- * parameters = parameters to print, such as TypeFunction.parameters.
- * varargs = kind of varargs, see TypeFunction.varargs.
- * Returns: Null-terminated string representing parameters.
- */
-const char *parametersTypeToChars(ParameterList pl)
-{
- OutBuffer buf;
- HdrGenState hgs;
- PrettyPrintVisitor v(&buf, &hgs);
- v.parametersToBuffer(pl.parameters, pl.varargs);
- return buf.extractChars();
-}
-
-/*************************************************************
- * Pretty print function parameter.
- * Params:
- * parameter = parameter to print.
- * tf = TypeFunction which holds parameter.
- * fullQual = whether to fully qualify types.
- * Returns: Null-terminated string representing parameters.
- */
-const char *parameterToChars(Parameter *parameter, TypeFunction *tf, bool fullQual)
-{
- OutBuffer buf;
- HdrGenState hgs;
- hgs.fullQual = fullQual;
- PrettyPrintVisitor v(&buf, &hgs);
-
- parameter->accept(&v);
- if (tf->parameterList.varargs == 2 && parameter == tf->parameterList[tf->parameterList.parameters->length - 1])
- {
- buf.writestring("...");
- }
- return buf.extractChars();
-}
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
new file mode 100644
index 0000000..8c31590
--- /dev/null
+++ b/gcc/d/dmd/hdrgen.d
@@ -0,0 +1,3956 @@
+/**
+ * Generate $(LINK2 https://dlang.org/dmd-windows.html#interface-files, D interface files).
+ *
+ * Also used to convert AST nodes to D code in general, e.g. for error messages or `printf` debugging.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/hdrgen.d, _hdrgen.d)
+ * Documentation: https://dlang.org/phobos/dmd_hdrgen.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/hdrgen.d
+ */
+
+module dmd.hdrgen;
+
+import core.stdc.ctype;
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.complex;
+import dmd.cond;
+import dmd.ctfeexpr;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dimport;
+import dmd.dmodule;
+import dmd.doc;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dtemplate;
+import dmd.dversion;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.mtype;
+import dmd.nspace;
+import dmd.parse;
+import dmd.root.ctfloat;
+import dmd.root.outbuffer;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.statement;
+import dmd.staticassert;
+import dmd.target;
+import dmd.tokens;
+import dmd.utils;
+import dmd.visitor;
+
+struct HdrGenState
+{
+ bool hdrgen; /// true if generating header file
+ bool ddoc; /// true if generating Ddoc file
+ bool fullDump; /// true if generating a full AST dump file
+
+ bool fullQual; /// fully qualify types when printing
+ int tpltMember;
+ int autoMember;
+ int forStmtInit;
+
+ bool declstring; // set while declaring alias for string,wstring or dstring
+ EnumDeclaration inEnumDecl;
+}
+
+enum TEST_EMIT_ALL = 0;
+
+extern (C++) void genhdrfile(Module m)
+{
+ OutBuffer buf;
+ buf.doindent = 1;
+ buf.printf("// D import file generated from '%s'", m.srcfile.toChars());
+ buf.writenl();
+ HdrGenState hgs;
+ hgs.hdrgen = true;
+ toCBuffer(m, &buf, &hgs);
+ writeFile(m.loc, m.hdrfile.toString(), buf[]);
+}
+
+/**
+ * Dumps the full contents of module `m` to `buf`.
+ * Params:
+ * buf = buffer to write to.
+ * m = module to visit all members of.
+ */
+extern (C++) void moduleToBuffer(OutBuffer* buf, Module m)
+{
+ HdrGenState hgs;
+ hgs.fullDump = true;
+ toCBuffer(m, buf, &hgs);
+}
+
+void moduleToBuffer2(Module m, OutBuffer* buf, HdrGenState* hgs)
+{
+ if (m.md)
+ {
+ if (m.userAttribDecl)
+ {
+ buf.writestring("@(");
+ argsToBuffer(m.userAttribDecl.atts, buf, hgs);
+ buf.writeByte(')');
+ buf.writenl();
+ }
+ if (m.md.isdeprecated)
+ {
+ if (m.md.msg)
+ {
+ buf.writestring("deprecated(");
+ m.md.msg.expressionToBuffer(buf, hgs);
+ buf.writestring(") ");
+ }
+ else
+ buf.writestring("deprecated ");
+ }
+ buf.writestring("module ");
+ buf.writestring(m.md.toChars());
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ foreach (s; *m.members)
+ {
+ s.dsymbolToBuffer(buf, hgs);
+ }
+}
+
+private void statementToBuffer(Statement s, OutBuffer* buf, HdrGenState* hgs)
+{
+ scope v = new StatementPrettyPrintVisitor(buf, hgs);
+ s.accept(v);
+}
+
+private extern (C++) final class StatementPrettyPrintVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+public:
+ OutBuffer* buf;
+ HdrGenState* hgs;
+
+ extern (D) this(OutBuffer* buf, HdrGenState* hgs)
+ {
+ this.buf = buf;
+ this.hgs = hgs;
+ }
+
+ override void visit(Statement s)
+ {
+ buf.writestring("Statement::toCBuffer()");
+ buf.writenl();
+ assert(0);
+ }
+
+ override void visit(ErrorStatement s)
+ {
+ buf.writestring("__error__");
+ buf.writenl();
+ }
+
+ override void visit(ExpStatement s)
+ {
+ if (s.exp && s.exp.op == TOK.declaration &&
+ (cast(DeclarationExp)s.exp).declaration)
+ {
+ // bypass visit(DeclarationExp)
+ (cast(DeclarationExp)s.exp).declaration.dsymbolToBuffer(buf, hgs);
+ return;
+ }
+ if (s.exp)
+ s.exp.expressionToBuffer(buf, hgs);
+ buf.writeByte(';');
+ if (!hgs.forStmtInit)
+ buf.writenl();
+ }
+
+ override void visit(CompileStatement s)
+ {
+ buf.writestring("mixin(");
+ argsToBuffer(s.exps, buf, hgs, null);
+ buf.writestring(");");
+ if (!hgs.forStmtInit)
+ buf.writenl();
+ }
+
+ override void visit(CompoundStatement s)
+ {
+ foreach (sx; *s.statements)
+ {
+ if (sx)
+ sx.accept(this);
+ }
+ }
+
+ override void visit(CompoundDeclarationStatement s)
+ {
+ bool anywritten = false;
+ foreach (sx; *s.statements)
+ {
+ auto ds = sx ? sx.isExpStatement() : null;
+ if (ds && ds.exp.op == TOK.declaration)
+ {
+ auto d = (cast(DeclarationExp)ds.exp).declaration;
+ assert(d.isDeclaration());
+ if (auto v = d.isVarDeclaration())
+ {
+ scope ppv = new DsymbolPrettyPrintVisitor(buf, hgs);
+ ppv.visitVarDecl(v, anywritten);
+ }
+ else
+ d.dsymbolToBuffer(buf, hgs);
+ anywritten = true;
+ }
+ }
+ buf.writeByte(';');
+ if (!hgs.forStmtInit)
+ buf.writenl();
+ }
+
+ override void visit(UnrolledLoopStatement s)
+ {
+ buf.writestring("/*unrolled*/ {");
+ buf.writenl();
+ buf.level++;
+ foreach (sx; *s.statements)
+ {
+ if (sx)
+ sx.accept(this);
+ }
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ }
+
+ override void visit(ScopeStatement s)
+ {
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ if (s.statement)
+ s.statement.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ }
+
+ override void visit(WhileStatement s)
+ {
+ buf.writestring("while (");
+ if (auto p = s.param)
+ {
+ // Print condition assignment
+ StorageClass stc = p.storageClass;
+ if (!p.type && !stc)
+ stc = STC.auto_;
+ if (stcToBuffer(buf, stc))
+ buf.writeByte(' ');
+ if (p.type)
+ typeToBuffer(p.type, p.ident, buf, hgs);
+ else
+ buf.writestring(p.ident.toString());
+ buf.writestring(" = ");
+ }
+ s.condition.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ buf.writenl();
+ if (s._body)
+ s._body.accept(this);
+ }
+
+ override void visit(DoStatement s)
+ {
+ buf.writestring("do");
+ buf.writenl();
+ if (s._body)
+ s._body.accept(this);
+ buf.writestring("while (");
+ s.condition.expressionToBuffer(buf, hgs);
+ buf.writestring(");");
+ buf.writenl();
+ }
+
+ override void visit(ForStatement s)
+ {
+ buf.writestring("for (");
+ if (s._init)
+ {
+ hgs.forStmtInit++;
+ s._init.accept(this);
+ hgs.forStmtInit--;
+ }
+ else
+ buf.writeByte(';');
+ if (s.condition)
+ {
+ buf.writeByte(' ');
+ s.condition.expressionToBuffer(buf, hgs);
+ }
+ buf.writeByte(';');
+ if (s.increment)
+ {
+ buf.writeByte(' ');
+ s.increment.expressionToBuffer(buf, hgs);
+ }
+ buf.writeByte(')');
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ if (s._body)
+ s._body.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ }
+
+ private void foreachWithoutBody(ForeachStatement s)
+ {
+ buf.writestring(Token.toString(s.op));
+ buf.writestring(" (");
+ foreach (i, p; *s.parameters)
+ {
+ if (i)
+ buf.writestring(", ");
+ if (stcToBuffer(buf, p.storageClass))
+ buf.writeByte(' ');
+ if (p.type)
+ typeToBuffer(p.type, p.ident, buf, hgs);
+ else
+ buf.writestring(p.ident.toString());
+ }
+ buf.writestring("; ");
+ s.aggr.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ buf.writenl();
+ }
+
+ override void visit(ForeachStatement s)
+ {
+ foreachWithoutBody(s);
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ if (s._body)
+ s._body.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ }
+
+ private void foreachRangeWithoutBody(ForeachRangeStatement s)
+ {
+ buf.writestring(Token.toString(s.op));
+ buf.writestring(" (");
+ if (s.prm.type)
+ typeToBuffer(s.prm.type, s.prm.ident, buf, hgs);
+ else
+ buf.writestring(s.prm.ident.toString());
+ buf.writestring("; ");
+ s.lwr.expressionToBuffer(buf, hgs);
+ buf.writestring(" .. ");
+ s.upr.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ buf.writenl();
+ }
+
+ override void visit(ForeachRangeStatement s)
+ {
+ foreachRangeWithoutBody(s);
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ if (s._body)
+ s._body.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ }
+
+ override void visit(StaticForeachStatement s)
+ {
+ buf.writestring("static ");
+ if (s.sfe.aggrfe)
+ {
+ visit(s.sfe.aggrfe);
+ }
+ else
+ {
+ assert(s.sfe.rangefe);
+ visit(s.sfe.rangefe);
+ }
+ }
+
+ override void visit(ForwardingStatement s)
+ {
+ s.statement.accept(this);
+ }
+
+ override void visit(IfStatement s)
+ {
+ buf.writestring("if (");
+ if (Parameter p = s.prm)
+ {
+ StorageClass stc = p.storageClass;
+ if (!p.type && !stc)
+ stc = STC.auto_;
+ if (stcToBuffer(buf, stc))
+ buf.writeByte(' ');
+ if (p.type)
+ typeToBuffer(p.type, p.ident, buf, hgs);
+ else
+ buf.writestring(p.ident.toString());
+ buf.writestring(" = ");
+ }
+ s.condition.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ buf.writenl();
+ if (s.ifbody.isScopeStatement())
+ {
+ s.ifbody.accept(this);
+ }
+ else
+ {
+ buf.level++;
+ s.ifbody.accept(this);
+ buf.level--;
+ }
+ if (s.elsebody)
+ {
+ buf.writestring("else");
+ if (!s.elsebody.isIfStatement())
+ {
+ buf.writenl();
+ }
+ else
+ {
+ buf.writeByte(' ');
+ }
+ if (s.elsebody.isScopeStatement() || s.elsebody.isIfStatement())
+ {
+ s.elsebody.accept(this);
+ }
+ else
+ {
+ buf.level++;
+ s.elsebody.accept(this);
+ buf.level--;
+ }
+ }
+ }
+
+ override void visit(ConditionalStatement s)
+ {
+ s.condition.conditionToBuffer(buf, hgs);
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ if (s.ifbody)
+ s.ifbody.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ if (s.elsebody)
+ {
+ buf.writestring("else");
+ buf.writenl();
+ buf.writeByte('{');
+ buf.level++;
+ buf.writenl();
+ s.elsebody.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ }
+ buf.writenl();
+ }
+
+ override void visit(PragmaStatement s)
+ {
+ buf.writestring("pragma (");
+ buf.writestring(s.ident.toString());
+ if (s.args && s.args.dim)
+ {
+ buf.writestring(", ");
+ argsToBuffer(s.args, buf, hgs);
+ }
+ buf.writeByte(')');
+ if (s._body)
+ {
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ s._body.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ }
+ else
+ {
+ buf.writeByte(';');
+ buf.writenl();
+ }
+ }
+
+ override void visit(StaticAssertStatement s)
+ {
+ s.sa.dsymbolToBuffer(buf, hgs);
+ }
+
+ override void visit(SwitchStatement s)
+ {
+ buf.writestring(s.isFinal ? "final switch (" : "switch (");
+ s.condition.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ buf.writenl();
+ if (s._body)
+ {
+ if (!s._body.isScopeStatement())
+ {
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ s._body.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ }
+ else
+ {
+ s._body.accept(this);
+ }
+ }
+ }
+
+ override void visit(CaseStatement s)
+ {
+ buf.writestring("case ");
+ s.exp.expressionToBuffer(buf, hgs);
+ buf.writeByte(':');
+ buf.writenl();
+ s.statement.accept(this);
+ }
+
+ override void visit(CaseRangeStatement s)
+ {
+ buf.writestring("case ");
+ s.first.expressionToBuffer(buf, hgs);
+ buf.writestring(": .. case ");
+ s.last.expressionToBuffer(buf, hgs);
+ buf.writeByte(':');
+ buf.writenl();
+ s.statement.accept(this);
+ }
+
+ override void visit(DefaultStatement s)
+ {
+ buf.writestring("default:");
+ buf.writenl();
+ s.statement.accept(this);
+ }
+
+ override void visit(GotoDefaultStatement s)
+ {
+ buf.writestring("goto default;");
+ buf.writenl();
+ }
+
+ override void visit(GotoCaseStatement s)
+ {
+ buf.writestring("goto case");
+ if (s.exp)
+ {
+ buf.writeByte(' ');
+ s.exp.expressionToBuffer(buf, hgs);
+ }
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ override void visit(SwitchErrorStatement s)
+ {
+ buf.writestring("SwitchErrorStatement::toCBuffer()");
+ buf.writenl();
+ }
+
+ override void visit(ReturnStatement s)
+ {
+ buf.writestring("return ");
+ if (s.exp)
+ s.exp.expressionToBuffer(buf, hgs);
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ override void visit(BreakStatement s)
+ {
+ buf.writestring("break");
+ if (s.ident)
+ {
+ buf.writeByte(' ');
+ buf.writestring(s.ident.toString());
+ }
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ override void visit(ContinueStatement s)
+ {
+ buf.writestring("continue");
+ if (s.ident)
+ {
+ buf.writeByte(' ');
+ buf.writestring(s.ident.toString());
+ }
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ override void visit(SynchronizedStatement s)
+ {
+ buf.writestring("synchronized");
+ if (s.exp)
+ {
+ buf.writeByte('(');
+ s.exp.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ }
+ if (s._body)
+ {
+ buf.writeByte(' ');
+ s._body.accept(this);
+ }
+ }
+
+ override void visit(WithStatement s)
+ {
+ buf.writestring("with (");
+ s.exp.expressionToBuffer(buf, hgs);
+ buf.writestring(")");
+ buf.writenl();
+ if (s._body)
+ s._body.accept(this);
+ }
+
+ override void visit(TryCatchStatement s)
+ {
+ buf.writestring("try");
+ buf.writenl();
+ if (s._body)
+ {
+ if (s._body.isScopeStatement())
+ {
+ s._body.accept(this);
+ }
+ else
+ {
+ buf.level++;
+ s._body.accept(this);
+ buf.level--;
+ }
+ }
+ foreach (c; *s.catches)
+ {
+ visit(c);
+ }
+ }
+
+ override void visit(TryFinallyStatement s)
+ {
+ buf.writestring("try");
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ s._body.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ buf.writestring("finally");
+ buf.writenl();
+ if (s.finalbody.isScopeStatement())
+ {
+ s.finalbody.accept(this);
+ }
+ else
+ {
+ buf.level++;
+ s.finalbody.accept(this);
+ buf.level--;
+ }
+ }
+
+ override void visit(ScopeGuardStatement s)
+ {
+ buf.writestring(Token.toString(s.tok));
+ buf.writeByte(' ');
+ if (s.statement)
+ s.statement.accept(this);
+ }
+
+ override void visit(ThrowStatement s)
+ {
+ buf.writestring("throw ");
+ s.exp.expressionToBuffer(buf, hgs);
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ override void visit(DebugStatement s)
+ {
+ if (s.statement)
+ {
+ s.statement.accept(this);
+ }
+ }
+
+ override void visit(GotoStatement s)
+ {
+ buf.writestring("goto ");
+ buf.writestring(s.ident.toString());
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ override void visit(LabelStatement s)
+ {
+ buf.writestring(s.ident.toString());
+ buf.writeByte(':');
+ buf.writenl();
+ if (s.statement)
+ s.statement.accept(this);
+ }
+
+ override void visit(AsmStatement s)
+ {
+ buf.writestring("asm { ");
+ Token* t = s.tokens;
+ buf.level++;
+ while (t)
+ {
+ buf.writestring(t.toChars());
+ if (t.next &&
+ t.value != TOK.min &&
+ t.value != TOK.comma && t.next.value != TOK.comma &&
+ t.value != TOK.leftBracket && t.next.value != TOK.leftBracket &&
+ t.next.value != TOK.rightBracket &&
+ t.value != TOK.leftParenthesis && t.next.value != TOK.leftParenthesis &&
+ t.next.value != TOK.rightParenthesis &&
+ t.value != TOK.dot && t.next.value != TOK.dot)
+ {
+ buf.writeByte(' ');
+ }
+ t = t.next;
+ }
+ buf.level--;
+ buf.writestring("; }");
+ buf.writenl();
+ }
+
+ override void visit(ImportStatement s)
+ {
+ foreach (imp; *s.imports)
+ {
+ imp.dsymbolToBuffer(buf, hgs);
+ }
+ }
+
+ void visit(Catch c)
+ {
+ buf.writestring("catch");
+ if (c.type)
+ {
+ buf.writeByte('(');
+ typeToBuffer(c.type, c.ident, buf, hgs);
+ buf.writeByte(')');
+ }
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ if (c.handler)
+ c.handler.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ }
+}
+
+private void dsymbolToBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs)
+{
+ scope v = new DsymbolPrettyPrintVisitor(buf, hgs);
+ s.accept(v);
+}
+
+private extern (C++) final class DsymbolPrettyPrintVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+public:
+ OutBuffer* buf;
+ HdrGenState* hgs;
+
+ extern (D) this(OutBuffer* buf, HdrGenState* hgs)
+ {
+ this.buf = buf;
+ this.hgs = hgs;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+
+ override void visit(Dsymbol s)
+ {
+ buf.writestring(s.toChars());
+ }
+
+ override void visit(StaticAssert s)
+ {
+ buf.writestring(s.kind());
+ buf.writeByte('(');
+ s.exp.expressionToBuffer(buf, hgs);
+ if (s.msg)
+ {
+ buf.writestring(", ");
+ s.msg.expressionToBuffer(buf, hgs);
+ }
+ buf.writestring(");");
+ buf.writenl();
+ }
+
+ override void visit(DebugSymbol s)
+ {
+ buf.writestring("debug = ");
+ if (s.ident)
+ buf.writestring(s.ident.toString());
+ else
+ buf.print(s.level);
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ override void visit(VersionSymbol s)
+ {
+ buf.writestring("version = ");
+ if (s.ident)
+ buf.writestring(s.ident.toString());
+ else
+ buf.print(s.level);
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ override void visit(EnumMember em)
+ {
+ if (em.type)
+ typeToBuffer(em.type, em.ident, buf, hgs);
+ else
+ buf.writestring(em.ident.toString());
+ if (em.value)
+ {
+ buf.writestring(" = ");
+ em.value.expressionToBuffer(buf, hgs);
+ }
+ }
+
+ override void visit(Import imp)
+ {
+ if (hgs.hdrgen && imp.id == Id.object)
+ return; // object is imported by default
+ if (imp.isstatic)
+ buf.writestring("static ");
+ buf.writestring("import ");
+ if (imp.aliasId)
+ {
+ buf.printf("%s = ", imp.aliasId.toChars());
+ }
+ foreach (const pid; imp.packages)
+ {
+ buf.printf("%s.", pid.toChars());
+ }
+ buf.writestring(imp.id.toString());
+ if (imp.names.dim)
+ {
+ buf.writestring(" : ");
+ foreach (const i, const name; imp.names)
+ {
+ if (i)
+ buf.writestring(", ");
+ const _alias = imp.aliases[i];
+ if (_alias)
+ buf.printf("%s = %s", _alias.toChars(), name.toChars());
+ else
+ buf.writestring(name.toChars());
+ }
+ }
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ override void visit(AliasThis d)
+ {
+ buf.writestring("alias ");
+ buf.writestring(d.ident.toString());
+ buf.writestring(" this;\n");
+ }
+
+ override void visit(AttribDeclaration d)
+ {
+ if (!d.decl)
+ {
+ buf.writeByte(';');
+ buf.writenl();
+ return;
+ }
+ if (d.decl.dim == 0 || (hgs.hdrgen && d.decl.dim == 1 && (*d.decl)[0].isUnitTestDeclaration()))
+ {
+ // hack for bugzilla 8081
+ buf.writestring("{}");
+ }
+ else if (d.decl.dim == 1)
+ {
+ (*d.decl)[0].accept(this);
+ return;
+ }
+ else
+ {
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ foreach (de; *d.decl)
+ de.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ }
+ buf.writenl();
+ }
+
+ override void visit(StorageClassDeclaration d)
+ {
+ if (stcToBuffer(buf, d.stc))
+ buf.writeByte(' ');
+ visit(cast(AttribDeclaration)d);
+ }
+
+ override void visit(DeprecatedDeclaration d)
+ {
+ buf.writestring("deprecated(");
+ d.msg.expressionToBuffer(buf, hgs);
+ buf.writestring(") ");
+ visit(cast(AttribDeclaration)d);
+ }
+
+ override void visit(LinkDeclaration d)
+ {
+ buf.writestring("extern (");
+ buf.writestring(linkageToString(d.linkage));
+ buf.writestring(") ");
+ visit(cast(AttribDeclaration)d);
+ }
+
+ override void visit(CPPMangleDeclaration d)
+ {
+ string s;
+ final switch (d.cppmangle)
+ {
+ case CPPMANGLE.asClass:
+ s = "class";
+ break;
+ case CPPMANGLE.asStruct:
+ s = "struct";
+ break;
+ case CPPMANGLE.def:
+ break;
+ }
+ buf.writestring("extern (C++, ");
+ buf.writestring(s);
+ buf.writestring(") ");
+ visit(cast(AttribDeclaration)d);
+ }
+
+ override void visit(VisibilityDeclaration d)
+ {
+ visibilityToBuffer(buf, d.visibility);
+ buf.writeByte(' ');
+ AttribDeclaration ad = cast(AttribDeclaration)d;
+ if (ad.decl.dim == 1 && (*ad.decl)[0].isVisibilityDeclaration)
+ visit(cast(AttribDeclaration)(*ad.decl)[0]);
+ else
+ visit(cast(AttribDeclaration)d);
+ }
+
+ override void visit(AlignDeclaration d)
+ {
+ if (d.exps)
+ {
+ foreach (i, exp; (*d.exps)[])
+ {
+ if (i)
+ buf.writeByte(' ');
+ buf.printf("align (%s)", exp.toChars());
+ }
+ if (d.decl && d.decl.dim < 2)
+ buf.writeByte(' ');
+ }
+ else
+ buf.writestring("align ");
+
+ visit(d.isAttribDeclaration());
+ }
+
+ override void visit(AnonDeclaration d)
+ {
+ buf.writestring(d.isunion ? "union" : "struct");
+ buf.writenl();
+ buf.writestring("{");
+ buf.writenl();
+ buf.level++;
+ if (d.decl)
+ {
+ foreach (de; *d.decl)
+ de.accept(this);
+ }
+ buf.level--;
+ buf.writestring("}");
+ buf.writenl();
+ }
+
+ override void visit(PragmaDeclaration d)
+ {
+ buf.writestring("pragma (");
+ buf.writestring(d.ident.toString());
+ if (d.args && d.args.dim)
+ {
+ buf.writestring(", ");
+ argsToBuffer(d.args, buf, hgs);
+ }
+ buf.writeByte(')');
+ visit(cast(AttribDeclaration)d);
+ }
+
+ override void visit(ConditionalDeclaration d)
+ {
+ d.condition.conditionToBuffer(buf, hgs);
+ if (d.decl || d.elsedecl)
+ {
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ if (d.decl)
+ {
+ foreach (de; *d.decl)
+ de.accept(this);
+ }
+ buf.level--;
+ buf.writeByte('}');
+ if (d.elsedecl)
+ {
+ buf.writenl();
+ buf.writestring("else");
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ foreach (de; *d.elsedecl)
+ de.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ }
+ }
+ else
+ buf.writeByte(':');
+ buf.writenl();
+ }
+
+ override void visit(StaticForeachDeclaration s)
+ {
+ void foreachWithoutBody(ForeachStatement s)
+ {
+ buf.writestring(Token.toString(s.op));
+ buf.writestring(" (");
+ foreach (i, p; *s.parameters)
+ {
+ if (i)
+ buf.writestring(", ");
+ if (stcToBuffer(buf, p.storageClass))
+ buf.writeByte(' ');
+ if (p.type)
+ typeToBuffer(p.type, p.ident, buf, hgs);
+ else
+ buf.writestring(p.ident.toString());
+ }
+ buf.writestring("; ");
+ s.aggr.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ buf.writenl();
+ }
+
+ void foreachRangeWithoutBody(ForeachRangeStatement s)
+ {
+ /* s.op ( prm ; lwr .. upr )
+ */
+ buf.writestring(Token.toString(s.op));
+ buf.writestring(" (");
+ if (s.prm.type)
+ typeToBuffer(s.prm.type, s.prm.ident, buf, hgs);
+ else
+ buf.writestring(s.prm.ident.toString());
+ buf.writestring("; ");
+ s.lwr.expressionToBuffer(buf, hgs);
+ buf.writestring(" .. ");
+ s.upr.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ buf.writenl();
+ }
+
+ buf.writestring("static ");
+ if (s.sfe.aggrfe)
+ {
+ foreachWithoutBody(s.sfe.aggrfe);
+ }
+ else
+ {
+ assert(s.sfe.rangefe);
+ foreachRangeWithoutBody(s.sfe.rangefe);
+ }
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ visit(cast(AttribDeclaration)s);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+
+ }
+
+ override void visit(CompileDeclaration d)
+ {
+ buf.writestring("mixin(");
+ argsToBuffer(d.exps, buf, hgs, null);
+ buf.writestring(");");
+ buf.writenl();
+ }
+
+ override void visit(UserAttributeDeclaration d)
+ {
+ buf.writestring("@(");
+ argsToBuffer(d.atts, buf, hgs);
+ buf.writeByte(')');
+ visit(cast(AttribDeclaration)d);
+ }
+
+ override void visit(TemplateDeclaration d)
+ {
+ version (none)
+ {
+ // Should handle template functions for doc generation
+ if (onemember && onemember.isFuncDeclaration())
+ buf.writestring("foo ");
+ }
+ if ((hgs.hdrgen || hgs.fullDump) && visitEponymousMember(d))
+ return;
+ if (hgs.ddoc)
+ buf.writestring(d.kind());
+ else
+ buf.writestring("template");
+ buf.writeByte(' ');
+ buf.writestring(d.ident.toString());
+ buf.writeByte('(');
+ visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
+ buf.writeByte(')');
+ visitTemplateConstraint(d.constraint);
+ if (hgs.hdrgen || hgs.fullDump)
+ {
+ hgs.tpltMember++;
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ foreach (s; *d.members)
+ s.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ hgs.tpltMember--;
+ }
+ }
+
+ bool visitEponymousMember(TemplateDeclaration d)
+ {
+ if (!d.members || d.members.dim != 1)
+ return false;
+ Dsymbol onemember = (*d.members)[0];
+ if (onemember.ident != d.ident)
+ return false;
+ if (FuncDeclaration fd = onemember.isFuncDeclaration())
+ {
+ assert(fd.type);
+ if (stcToBuffer(buf, fd.storage_class))
+ buf.writeByte(' ');
+ functionToBufferFull(cast(TypeFunction)fd.type, buf, d.ident, hgs, d);
+ visitTemplateConstraint(d.constraint);
+ hgs.tpltMember++;
+ bodyToBuffer(fd);
+ hgs.tpltMember--;
+ return true;
+ }
+ if (AggregateDeclaration ad = onemember.isAggregateDeclaration())
+ {
+ buf.writestring(ad.kind());
+ buf.writeByte(' ');
+ buf.writestring(ad.ident.toString());
+ buf.writeByte('(');
+ visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
+ buf.writeByte(')');
+ visitTemplateConstraint(d.constraint);
+ visitBaseClasses(ad.isClassDeclaration());
+ hgs.tpltMember++;
+ if (ad.members)
+ {
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ foreach (s; *ad.members)
+ s.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ }
+ else
+ buf.writeByte(';');
+ buf.writenl();
+ hgs.tpltMember--;
+ return true;
+ }
+ if (VarDeclaration vd = onemember.isVarDeclaration())
+ {
+ if (d.constraint)
+ return false;
+ if (stcToBuffer(buf, vd.storage_class))
+ buf.writeByte(' ');
+ if (vd.type)
+ typeToBuffer(vd.type, vd.ident, buf, hgs);
+ else
+ buf.writestring(vd.ident.toString());
+ buf.writeByte('(');
+ visitTemplateParameters(hgs.ddoc ? d.origParameters : d.parameters);
+ buf.writeByte(')');
+ if (vd._init)
+ {
+ buf.writestring(" = ");
+ ExpInitializer ie = vd._init.isExpInitializer();
+ if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit))
+ (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs);
+ else
+ vd._init.initializerToBuffer(buf, hgs);
+ }
+ buf.writeByte(';');
+ buf.writenl();
+ return true;
+ }
+ return false;
+ }
+
+ void visitTemplateParameters(TemplateParameters* parameters)
+ {
+ if (!parameters || !parameters.dim)
+ return;
+ foreach (i, p; *parameters)
+ {
+ if (i)
+ buf.writestring(", ");
+ p.templateParameterToBuffer(buf, hgs);
+ }
+ }
+
+ void visitTemplateConstraint(Expression constraint)
+ {
+ if (!constraint)
+ return;
+ buf.writestring(" if (");
+ constraint.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ }
+
+ override void visit(TemplateInstance ti)
+ {
+ buf.writestring(ti.name.toChars());
+ tiargsToBuffer(ti, buf, hgs);
+
+ if (hgs.fullDump)
+ {
+ buf.writenl();
+ dumpTemplateInstance(ti, buf, hgs);
+ }
+ }
+
+ override void visit(TemplateMixin tm)
+ {
+ buf.writestring("mixin ");
+ typeToBuffer(tm.tqual, null, buf, hgs);
+ tiargsToBuffer(tm, buf, hgs);
+ if (tm.ident && memcmp(tm.ident.toChars(), cast(const(char)*)"__mixin", 7) != 0)
+ {
+ buf.writeByte(' ');
+ buf.writestring(tm.ident.toString());
+ }
+ buf.writeByte(';');
+ buf.writenl();
+ if (hgs.fullDump)
+ dumpTemplateInstance(tm, buf, hgs);
+ }
+
+ override void visit(EnumDeclaration d)
+ {
+ auto oldInEnumDecl = hgs.inEnumDecl;
+ scope(exit) hgs.inEnumDecl = oldInEnumDecl;
+ hgs.inEnumDecl = d;
+ buf.writestring("enum ");
+ if (d.ident)
+ {
+ buf.writestring(d.ident.toString());
+ buf.writeByte(' ');
+ }
+ if (d.memtype)
+ {
+ buf.writestring(": ");
+ typeToBuffer(d.memtype, null, buf, hgs);
+ }
+ if (!d.members)
+ {
+ buf.writeByte(';');
+ buf.writenl();
+ return;
+ }
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ foreach (em; *d.members)
+ {
+ if (!em)
+ continue;
+ em.accept(this);
+ buf.writeByte(',');
+ buf.writenl();
+ }
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ }
+
+ override void visit(Nspace d)
+ {
+ buf.writestring("extern (C++, ");
+ buf.writestring(d.ident.toString());
+ buf.writeByte(')');
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ foreach (s; *d.members)
+ s.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ }
+
+ override void visit(StructDeclaration d)
+ {
+ buf.writestring(d.kind());
+ buf.writeByte(' ');
+ if (!d.isAnonymous())
+ buf.writestring(d.toChars());
+ if (!d.members)
+ {
+ buf.writeByte(';');
+ buf.writenl();
+ return;
+ }
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ foreach (s; *d.members)
+ s.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ }
+
+ override void visit(ClassDeclaration d)
+ {
+ if (!d.isAnonymous())
+ {
+ buf.writestring(d.kind());
+ buf.writeByte(' ');
+ buf.writestring(d.ident.toString());
+ }
+ visitBaseClasses(d);
+ if (d.members)
+ {
+ buf.writenl();
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ foreach (s; *d.members)
+ s.accept(this);
+ buf.level--;
+ buf.writeByte('}');
+ }
+ else
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ void visitBaseClasses(ClassDeclaration d)
+ {
+ if (!d || !d.baseclasses.dim)
+ return;
+ if (!d.isAnonymous())
+ buf.writestring(" : ");
+ foreach (i, b; *d.baseclasses)
+ {
+ if (i)
+ buf.writestring(", ");
+ typeToBuffer(b.type, null, buf, hgs);
+ }
+ }
+
+ override void visit(AliasDeclaration d)
+ {
+ if (d.storage_class & STC.local)
+ return;
+ buf.writestring("alias ");
+ if (d.aliassym)
+ {
+ buf.writestring(d.ident.toString());
+ buf.writestring(" = ");
+ if (stcToBuffer(buf, d.storage_class))
+ buf.writeByte(' ');
+ d.aliassym.accept(this);
+ }
+ else if (d.type.ty == Tfunction)
+ {
+ if (stcToBuffer(buf, d.storage_class))
+ buf.writeByte(' ');
+ typeToBuffer(d.type, d.ident, buf, hgs);
+ }
+ else if (d.ident)
+ {
+ hgs.declstring = (d.ident == Id.string || d.ident == Id.wstring || d.ident == Id.dstring);
+ buf.writestring(d.ident.toString());
+ buf.writestring(" = ");
+ if (stcToBuffer(buf, d.storage_class))
+ buf.writeByte(' ');
+ typeToBuffer(d.type, null, buf, hgs);
+ hgs.declstring = false;
+ }
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ override void visit(AliasAssign d)
+ {
+ buf.writestring(d.ident.toString());
+ buf.writestring(" = ");
+ if (d.aliassym)
+ d.aliassym.accept(this);
+ else // d.type
+ typeToBuffer(d.type, null, buf, hgs);
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ override void visit(VarDeclaration d)
+ {
+ if (d.storage_class & STC.local)
+ return;
+ visitVarDecl(d, false);
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ void visitVarDecl(VarDeclaration v, bool anywritten)
+ {
+ if (anywritten)
+ {
+ buf.writestring(", ");
+ buf.writestring(v.ident.toString());
+ }
+ else
+ {
+ if (stcToBuffer(buf, v.storage_class))
+ buf.writeByte(' ');
+ if (v.type)
+ typeToBuffer(v.type, v.ident, buf, hgs);
+ else
+ buf.writestring(v.ident.toString());
+ }
+ if (v._init)
+ {
+ buf.writestring(" = ");
+ auto ie = v._init.isExpInitializer();
+ if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit))
+ (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs);
+ else
+ v._init.initializerToBuffer(buf, hgs);
+ }
+ }
+
+ override void visit(FuncDeclaration f)
+ {
+ //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars());
+ if (stcToBuffer(buf, f.storage_class))
+ buf.writeByte(' ');
+ auto tf = cast(TypeFunction)f.type;
+ typeToBuffer(tf, f.ident, buf, hgs);
+
+ if (hgs.hdrgen)
+ {
+ // if the return type is missing (e.g. ref functions or auto)
+ if (!tf.next || f.storage_class & STC.auto_)
+ {
+ hgs.autoMember++;
+ bodyToBuffer(f);
+ hgs.autoMember--;
+ }
+ else if (hgs.tpltMember == 0 && global.params.hdrStripPlainFunctions)
+ {
+ buf.writeByte(';');
+ buf.writenl();
+ }
+ else
+ bodyToBuffer(f);
+ }
+ else
+ bodyToBuffer(f);
+ }
+
+ void bodyToBuffer(FuncDeclaration f)
+ {
+ if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember))
+ {
+ buf.writeByte(';');
+ buf.writenl();
+ return;
+ }
+ const savetlpt = hgs.tpltMember;
+ const saveauto = hgs.autoMember;
+ hgs.tpltMember = 0;
+ hgs.autoMember = 0;
+ buf.writenl();
+ bool requireDo = false;
+ // in{}
+ if (f.frequires)
+ {
+ foreach (frequire; *f.frequires)
+ {
+ buf.writestring("in");
+ if (auto es = frequire.isExpStatement())
+ {
+ assert(es.exp && es.exp.op == TOK.assert_);
+ buf.writestring(" (");
+ (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ buf.writenl();
+ requireDo = false;
+ }
+ else
+ {
+ buf.writenl();
+ frequire.statementToBuffer(buf, hgs);
+ requireDo = true;
+ }
+ }
+ }
+ // out{}
+ if (f.fensures)
+ {
+ foreach (fensure; *f.fensures)
+ {
+ buf.writestring("out");
+ if (auto es = fensure.ensure.isExpStatement())
+ {
+ assert(es.exp && es.exp.op == TOK.assert_);
+ buf.writestring(" (");
+ if (fensure.id)
+ {
+ buf.writestring(fensure.id.toString());
+ }
+ buf.writestring("; ");
+ (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ buf.writenl();
+ requireDo = false;
+ }
+ else
+ {
+ if (fensure.id)
+ {
+ buf.writeByte('(');
+ buf.writestring(fensure.id.toString());
+ buf.writeByte(')');
+ }
+ buf.writenl();
+ fensure.ensure.statementToBuffer(buf, hgs);
+ requireDo = true;
+ }
+ }
+ }
+ if (requireDo)
+ {
+ buf.writestring("do");
+ buf.writenl();
+ }
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+ f.fbody.statementToBuffer(buf, hgs);
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+ hgs.tpltMember = savetlpt;
+ hgs.autoMember = saveauto;
+ }
+
+ override void visit(FuncLiteralDeclaration f)
+ {
+ if (f.type.ty == Terror)
+ {
+ buf.writestring("__error");
+ return;
+ }
+ if (f.tok != TOK.reserved)
+ {
+ buf.writestring(f.kind());
+ buf.writeByte(' ');
+ }
+ TypeFunction tf = cast(TypeFunction)f.type;
+
+ if (!f.inferRetType && tf.next)
+ typeToBuffer(tf.next, null, buf, hgs);
+ parametersToBuffer(tf.parameterList, buf, hgs);
+
+ // https://issues.dlang.org/show_bug.cgi?id=20074
+ void printAttribute(string str)
+ {
+ buf.writeByte(' ');
+ buf.writestring(str);
+ }
+ tf.attributesApply(&printAttribute);
+
+
+ CompoundStatement cs = f.fbody.isCompoundStatement();
+ Statement s1;
+ if (f.semanticRun >= PASS.semantic3done && cs)
+ {
+ s1 = (*cs.statements)[cs.statements.dim - 1];
+ }
+ else
+ s1 = !cs ? f.fbody : null;
+ ReturnStatement rs = s1 ? s1.endsWithReturnStatement() : null;
+ if (rs && rs.exp)
+ {
+ buf.writestring(" => ");
+ rs.exp.expressionToBuffer(buf, hgs);
+ }
+ else
+ {
+ hgs.tpltMember++;
+ bodyToBuffer(f);
+ hgs.tpltMember--;
+ }
+ }
+
+ override void visit(PostBlitDeclaration d)
+ {
+ if (stcToBuffer(buf, d.storage_class))
+ buf.writeByte(' ');
+ buf.writestring("this(this)");
+ bodyToBuffer(d);
+ }
+
+ override void visit(DtorDeclaration d)
+ {
+ if (d.storage_class & STC.trusted)
+ buf.writestring("@trusted ");
+ if (d.storage_class & STC.safe)
+ buf.writestring("@safe ");
+ if (d.storage_class & STC.nogc)
+ buf.writestring("@nogc ");
+ if (d.storage_class & STC.live)
+ buf.writestring("@live ");
+ if (d.storage_class & STC.disable)
+ buf.writestring("@disable ");
+
+ buf.writestring("~this()");
+ bodyToBuffer(d);
+ }
+
+ override void visit(StaticCtorDeclaration d)
+ {
+ if (stcToBuffer(buf, d.storage_class & ~STC.static_))
+ buf.writeByte(' ');
+ if (d.isSharedStaticCtorDeclaration())
+ buf.writestring("shared ");
+ buf.writestring("static this()");
+ if (hgs.hdrgen && !hgs.tpltMember)
+ {
+ buf.writeByte(';');
+ buf.writenl();
+ }
+ else
+ bodyToBuffer(d);
+ }
+
+ override void visit(StaticDtorDeclaration d)
+ {
+ if (stcToBuffer(buf, d.storage_class & ~STC.static_))
+ buf.writeByte(' ');
+ if (d.isSharedStaticDtorDeclaration())
+ buf.writestring("shared ");
+ buf.writestring("static ~this()");
+ if (hgs.hdrgen && !hgs.tpltMember)
+ {
+ buf.writeByte(';');
+ buf.writenl();
+ }
+ else
+ bodyToBuffer(d);
+ }
+
+ override void visit(InvariantDeclaration d)
+ {
+ if (hgs.hdrgen)
+ return;
+ if (stcToBuffer(buf, d.storage_class))
+ buf.writeByte(' ');
+ buf.writestring("invariant");
+ if(auto es = d.fbody.isExpStatement())
+ {
+ assert(es.exp && es.exp.op == TOK.assert_);
+ buf.writestring(" (");
+ (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
+ buf.writestring(");");
+ buf.writenl();
+ }
+ else
+ {
+ bodyToBuffer(d);
+ }
+ }
+
+ override void visit(UnitTestDeclaration d)
+ {
+ if (hgs.hdrgen)
+ return;
+ if (stcToBuffer(buf, d.storage_class))
+ buf.writeByte(' ');
+ buf.writestring("unittest");
+ bodyToBuffer(d);
+ }
+
+ override void visit(BitFieldDeclaration d)
+ {
+ if (stcToBuffer(buf, d.storage_class))
+ buf.writeByte(' ');
+ Identifier id = d.isAnonymous() ? null : d.ident;
+ typeToBuffer(d.type, id, buf, hgs);
+ buf.writestring(" : ");
+ d.width.expressionToBuffer(buf, hgs);
+ buf.writeByte(';');
+ buf.writenl();
+ }
+
+ override void visit(NewDeclaration d)
+ {
+ if (stcToBuffer(buf, d.storage_class & ~STC.static_))
+ buf.writeByte(' ');
+ buf.writestring("new();");
+ }
+
+ override void visit(Module m)
+ {
+ moduleToBuffer2(m, buf, hgs);
+ }
+}
+
+private extern (C++) final class ExpressionPrettyPrintVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+public:
+ OutBuffer* buf;
+ HdrGenState* hgs;
+
+ extern (D) this(OutBuffer* buf, HdrGenState* hgs)
+ {
+ this.buf = buf;
+ this.hgs = hgs;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ override void visit(Expression e)
+ {
+ buf.writestring(Token.toString(e.op));
+ }
+
+ override void visit(IntegerExp e)
+ {
+ const dinteger_t v = e.toInteger();
+ if (e.type)
+ {
+ Type t = e.type;
+ L1:
+ switch (t.ty)
+ {
+ case Tenum:
+ {
+ TypeEnum te = cast(TypeEnum)t;
+ auto sym = te.sym;
+ if (sym && sym.members && (!hgs.inEnumDecl || hgs.inEnumDecl != sym))
+ {
+ foreach (em; *sym.members)
+ {
+ if ((cast(EnumMember)em).value.toInteger == v)
+ {
+ buf.printf("%s.%s", sym.toChars(), em.ident.toChars());
+ return ;
+ }
+ }
+ }
+
+ buf.printf("cast(%s)", te.sym.toChars());
+ t = te.sym.memtype;
+ goto L1;
+ }
+ case Twchar:
+ // BUG: need to cast(wchar)
+ case Tdchar:
+ // BUG: need to cast(dchar)
+ if (cast(uinteger_t)v > 0xFF)
+ {
+ buf.printf("'\\U%08llx'", cast(long)v);
+ break;
+ }
+ goto case;
+ case Tchar:
+ {
+ size_t o = buf.length;
+ if (v == '\'')
+ buf.writestring("'\\''");
+ else if (isprint(cast(int)v) && v != '\\')
+ buf.printf("'%c'", cast(int)v);
+ else
+ buf.printf("'\\x%02x'", cast(int)v);
+ if (hgs.ddoc)
+ escapeDdocString(buf, o);
+ break;
+ }
+ case Tint8:
+ buf.writestring("cast(byte)");
+ goto L2;
+ case Tint16:
+ buf.writestring("cast(short)");
+ goto L2;
+ case Tint32:
+ L2:
+ buf.printf("%d", cast(int)v);
+ break;
+ case Tuns8:
+ buf.writestring("cast(ubyte)");
+ goto case Tuns32;
+ case Tuns16:
+ buf.writestring("cast(ushort)");
+ goto case Tuns32;
+ case Tuns32:
+ buf.printf("%uu", cast(uint)v);
+ break;
+ case Tint64:
+ buf.printf("%lldL", v);
+ break;
+ case Tuns64:
+ buf.printf("%lluLU", v);
+ break;
+ case Tbool:
+ buf.writestring(v ? "true" : "false");
+ break;
+ case Tpointer:
+ buf.writestring("cast(");
+ buf.writestring(t.toChars());
+ buf.writeByte(')');
+ if (target.ptrsize == 8)
+ goto case Tuns64;
+ else if (target.ptrsize == 4 ||
+ target.ptrsize == 2)
+ goto case Tuns32;
+ else
+ assert(0);
+
+ case Tvoid:
+ buf.writestring("cast(void)0");
+ break;
+
+ default:
+ /* This can happen if errors, such as
+ * the type is painted on like in fromConstInitializer().
+ */
+ if (!global.errors)
+ {
+ assert(0);
+ }
+ break;
+ }
+ }
+ else if (v & 0x8000000000000000L)
+ buf.printf("0x%llx", v);
+ else
+ buf.print(v);
+ }
+
+ override void visit(ErrorExp e)
+ {
+ buf.writestring("__error");
+ }
+
+ override void visit(VoidInitExp e)
+ {
+ buf.writestring("__void");
+ }
+
+ void floatToBuffer(Type type, real_t value)
+ {
+ .floatToBuffer(type, value, buf, hgs.hdrgen);
+ }
+
+ override void visit(RealExp e)
+ {
+ floatToBuffer(e.type, e.value);
+ }
+
+ override void visit(ComplexExp e)
+ {
+ /* Print as:
+ * (re+imi)
+ */
+ buf.writeByte('(');
+ floatToBuffer(e.type, creall(e.value));
+ buf.writeByte('+');
+ floatToBuffer(e.type, cimagl(e.value));
+ buf.writestring("i)");
+ }
+
+ override void visit(IdentifierExp e)
+ {
+ if (hgs.hdrgen || hgs.ddoc)
+ buf.writestring(e.ident.toHChars2());
+ else
+ buf.writestring(e.ident.toString());
+ }
+
+ override void visit(DsymbolExp e)
+ {
+ buf.writestring(e.s.toChars());
+ }
+
+ override void visit(ThisExp e)
+ {
+ buf.writestring("this");
+ }
+
+ override void visit(SuperExp e)
+ {
+ buf.writestring("super");
+ }
+
+ override void visit(NullExp e)
+ {
+ buf.writestring("null");
+ }
+
+ override void visit(StringExp e)
+ {
+ buf.writeByte('"');
+ const o = buf.length;
+ for (size_t i = 0; i < e.len; i++)
+ {
+ const c = e.charAt(i);
+ switch (c)
+ {
+ case '"':
+ case '\\':
+ buf.writeByte('\\');
+ goto default;
+ default:
+ if (c <= 0xFF)
+ {
+ if (c <= 0x7F && isprint(c))
+ buf.writeByte(c);
+ else
+ buf.printf("\\x%02x", c);
+ }
+ else if (c <= 0xFFFF)
+ buf.printf("\\x%02x\\x%02x", c & 0xFF, c >> 8);
+ else
+ buf.printf("\\x%02x\\x%02x\\x%02x\\x%02x", c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24);
+ break;
+ }
+ }
+ if (hgs.ddoc)
+ escapeDdocString(buf, o);
+ buf.writeByte('"');
+ if (e.postfix)
+ buf.writeByte(e.postfix);
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ buf.writeByte('[');
+ argsToBuffer(e.elements, buf, hgs, e.basis);
+ buf.writeByte(']');
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ buf.writeByte('[');
+ foreach (i, key; *e.keys)
+ {
+ if (i)
+ buf.writestring(", ");
+ expToBuffer(key, PREC.assign, buf, hgs);
+ buf.writeByte(':');
+ auto value = (*e.values)[i];
+ expToBuffer(value, PREC.assign, buf, hgs);
+ }
+ buf.writeByte(']');
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ buf.writestring(e.sd.toChars());
+ buf.writeByte('(');
+ // CTFE can generate struct literals that contain an AddrExp pointing
+ // to themselves, need to avoid infinite recursion:
+ // struct S { this(int){ this.s = &this; } S* s; }
+ // const foo = new S(0);
+ if (e.stageflags & stageToCBuffer)
+ buf.writestring("<recursion>");
+ else
+ {
+ const old = e.stageflags;
+ e.stageflags |= stageToCBuffer;
+ argsToBuffer(e.elements, buf, hgs);
+ e.stageflags = old;
+ }
+ buf.writeByte(')');
+ }
+
+ override void visit(CompoundLiteralExp e)
+ {
+ buf.writeByte('(');
+ typeToBuffer(e.type, null, buf, hgs);
+ buf.writeByte(')');
+ e.initializer.initializerToBuffer(buf, hgs);
+ }
+
+ override void visit(TypeExp e)
+ {
+ typeToBuffer(e.type, null, buf, hgs);
+ }
+
+ override void visit(ScopeExp e)
+ {
+ if (e.sds.isTemplateInstance())
+ {
+ e.sds.dsymbolToBuffer(buf, hgs);
+ }
+ else if (hgs !is null && hgs.ddoc)
+ {
+ // fixes bug 6491
+ if (auto m = e.sds.isModule())
+ buf.writestring(m.md.toChars());
+ else
+ buf.writestring(e.sds.toChars());
+ }
+ else
+ {
+ buf.writestring(e.sds.kind());
+ buf.writeByte(' ');
+ buf.writestring(e.sds.toChars());
+ }
+ }
+
+ override void visit(TemplateExp e)
+ {
+ buf.writestring(e.td.toChars());
+ }
+
+ override void visit(NewExp e)
+ {
+ if (e.thisexp)
+ {
+ expToBuffer(e.thisexp, PREC.primary, buf, hgs);
+ buf.writeByte('.');
+ }
+ buf.writestring("new ");
+ if (e.newargs && e.newargs.dim)
+ {
+ buf.writeByte('(');
+ argsToBuffer(e.newargs, buf, hgs);
+ buf.writeByte(')');
+ }
+ typeToBuffer(e.newtype, null, buf, hgs);
+ if (e.arguments && e.arguments.dim)
+ {
+ buf.writeByte('(');
+ argsToBuffer(e.arguments, buf, hgs);
+ buf.writeByte(')');
+ }
+ }
+
+ override void visit(NewAnonClassExp e)
+ {
+ if (e.thisexp)
+ {
+ expToBuffer(e.thisexp, PREC.primary, buf, hgs);
+ buf.writeByte('.');
+ }
+ buf.writestring("new");
+ if (e.newargs && e.newargs.dim)
+ {
+ buf.writeByte('(');
+ argsToBuffer(e.newargs, buf, hgs);
+ buf.writeByte(')');
+ }
+ buf.writestring(" class ");
+ if (e.arguments && e.arguments.dim)
+ {
+ buf.writeByte('(');
+ argsToBuffer(e.arguments, buf, hgs);
+ buf.writeByte(')');
+ }
+ if (e.cd)
+ e.cd.dsymbolToBuffer(buf, hgs);
+ }
+
+ override void visit(SymOffExp e)
+ {
+ if (e.offset)
+ buf.printf("(& %s%+lld)", e.var.toChars(), e.offset);
+ else if (e.var.isTypeInfoDeclaration())
+ buf.writestring(e.var.toChars());
+ else
+ buf.printf("& %s", e.var.toChars());
+ }
+
+ override void visit(VarExp e)
+ {
+ buf.writestring(e.var.toChars());
+ }
+
+ override void visit(OverExp e)
+ {
+ buf.writestring(e.vars.ident.toString());
+ }
+
+ override void visit(TupleExp e)
+ {
+ if (e.e0)
+ {
+ buf.writeByte('(');
+ e.e0.accept(this);
+ buf.writestring(", tuple(");
+ argsToBuffer(e.exps, buf, hgs);
+ buf.writestring("))");
+ }
+ else
+ {
+ buf.writestring("tuple(");
+ argsToBuffer(e.exps, buf, hgs);
+ buf.writeByte(')');
+ }
+ }
+
+ override void visit(FuncExp e)
+ {
+ e.fd.dsymbolToBuffer(buf, hgs);
+ //buf.writestring(e.fd.toChars());
+ }
+
+ override void visit(DeclarationExp e)
+ {
+ /* Normal dmd execution won't reach here - regular variable declarations
+ * are handled in visit(ExpStatement), so here would be used only when
+ * we'll directly call Expression.toChars() for debugging.
+ */
+ if (e.declaration)
+ {
+ if (auto var = e.declaration.isVarDeclaration())
+ {
+ // For debugging use:
+ // - Avoid printing newline.
+ // - Intentionally use the format (Type var;)
+ // which isn't correct as regular D code.
+ buf.writeByte('(');
+
+ scope v = new DsymbolPrettyPrintVisitor(buf, hgs);
+ v.visitVarDecl(var, false);
+
+ buf.writeByte(';');
+ buf.writeByte(')');
+ }
+ else e.declaration.dsymbolToBuffer(buf, hgs);
+ }
+ }
+
+ override void visit(TypeidExp e)
+ {
+ buf.writestring("typeid(");
+ objectToBuffer(e.obj, buf, hgs);
+ buf.writeByte(')');
+ }
+
+ override void visit(TraitsExp e)
+ {
+ buf.writestring("__traits(");
+ if (e.ident)
+ buf.writestring(e.ident.toString());
+ if (e.args)
+ {
+ foreach (arg; *e.args)
+ {
+ buf.writestring(", ");
+ objectToBuffer(arg, buf, hgs);
+ }
+ }
+ buf.writeByte(')');
+ }
+
+ override void visit(HaltExp e)
+ {
+ buf.writestring("halt");
+ }
+
+ override void visit(IsExp e)
+ {
+ buf.writestring("is(");
+ typeToBuffer(e.targ, e.id, buf, hgs);
+ if (e.tok2 != TOK.reserved)
+ {
+ buf.printf(" %s %s", Token.toChars(e.tok), Token.toChars(e.tok2));
+ }
+ else if (e.tspec)
+ {
+ if (e.tok == TOK.colon)
+ buf.writestring(" : ");
+ else
+ buf.writestring(" == ");
+ typeToBuffer(e.tspec, null, buf, hgs);
+ }
+ if (e.parameters && e.parameters.dim)
+ {
+ buf.writestring(", ");
+ scope v = new DsymbolPrettyPrintVisitor(buf, hgs);
+ v.visitTemplateParameters(e.parameters);
+ }
+ buf.writeByte(')');
+ }
+
+ override void visit(UnaExp e)
+ {
+ buf.writestring(Token.toString(e.op));
+ expToBuffer(e.e1, precedence[e.op], buf, hgs);
+ }
+
+ override void visit(BinExp e)
+ {
+ expToBuffer(e.e1, precedence[e.op], buf, hgs);
+ buf.writeByte(' ');
+ buf.writestring(Token.toString(e.op));
+ buf.writeByte(' ');
+ expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf, hgs);
+ }
+
+ override void visit(CommaExp e)
+ {
+ // CommaExp is generated by the compiler so it shouldn't
+ // appear in error messages or header files.
+ // For now, this treats the case where the compiler
+ // generates CommaExp for temporaries by calling
+ // the `sideeffect.copyToTemp` function.
+ auto ve = e.e2.isVarExp();
+
+ // not a CommaExp introduced for temporaries, go on
+ // the old path
+ if (!ve || !(ve.var.storage_class & STC.temp))
+ {
+ visit(cast(BinExp)e);
+ return;
+ }
+
+ // CommaExp that contain temporaries inserted via
+ // `copyToTemp` are usually of the form
+ // ((T __temp = exp), __tmp).
+ // Asserts are here to easily spot
+ // missing cases where CommaExp
+ // are used for other constructs
+ auto vd = ve.var.isVarDeclaration();
+ assert(vd && vd._init);
+
+ if (auto ei = vd._init.isExpInitializer())
+ {
+ Expression commaExtract;
+ auto exp = ei.exp;
+ if (auto ce = exp.isConstructExp())
+ commaExtract = ce.e2;
+ else if (auto se = exp.isStructLiteralExp())
+ commaExtract = se;
+
+ if (commaExtract)
+ {
+ expToBuffer(commaExtract, precedence[exp.op], buf, hgs);
+ return;
+ }
+ }
+
+ // not one of the known cases, go on the old path
+ visit(cast(BinExp)e);
+ return;
+ }
+
+ override void visit(MixinExp e)
+ {
+ buf.writestring("mixin(");
+ argsToBuffer(e.exps, buf, hgs, null);
+ buf.writeByte(')');
+ }
+
+ override void visit(ImportExp e)
+ {
+ buf.writestring("import(");
+ expToBuffer(e.e1, PREC.assign, buf, hgs);
+ buf.writeByte(')');
+ }
+
+ override void visit(AssertExp e)
+ {
+ buf.writestring("assert(");
+ expToBuffer(e.e1, PREC.assign, buf, hgs);
+ if (e.msg)
+ {
+ buf.writestring(", ");
+ expToBuffer(e.msg, PREC.assign, buf, hgs);
+ }
+ buf.writeByte(')');
+ }
+
+ override void visit(DotIdExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writeByte('.');
+ buf.writestring(e.ident.toString());
+ }
+
+ override void visit(DotTemplateExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writeByte('.');
+ buf.writestring(e.td.toChars());
+ }
+
+ override void visit(DotVarExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writeByte('.');
+ buf.writestring(e.var.toChars());
+ }
+
+ override void visit(DotTemplateInstanceExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writeByte('.');
+ e.ti.dsymbolToBuffer(buf, hgs);
+ }
+
+ override void visit(DelegateExp e)
+ {
+ buf.writeByte('&');
+ if (!e.func.isNested() || e.func.needThis())
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writeByte('.');
+ }
+ buf.writestring(e.func.toChars());
+ }
+
+ override void visit(DotTypeExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writeByte('.');
+ buf.writestring(e.sym.toChars());
+ }
+
+ override void visit(CallExp e)
+ {
+ if (e.e1.op == TOK.type)
+ {
+ /* Avoid parens around type to prevent forbidden cast syntax:
+ * (sometype)(arg1)
+ * This is ok since types in constructor calls
+ * can never depend on parens anyway
+ */
+ e.e1.accept(this);
+ }
+ else
+ expToBuffer(e.e1, precedence[e.op], buf, hgs);
+ buf.writeByte('(');
+ argsToBuffer(e.arguments, buf, hgs);
+ buf.writeByte(')');
+ }
+
+ override void visit(PtrExp e)
+ {
+ buf.writeByte('*');
+ expToBuffer(e.e1, precedence[e.op], buf, hgs);
+ }
+
+ override void visit(DeleteExp e)
+ {
+ buf.writestring("delete ");
+ expToBuffer(e.e1, precedence[e.op], buf, hgs);
+ }
+
+ override void visit(CastExp e)
+ {
+ buf.writestring("cast(");
+ if (e.to)
+ typeToBuffer(e.to, null, buf, hgs);
+ else
+ {
+ MODtoBuffer(buf, e.mod);
+ }
+ buf.writeByte(')');
+ expToBuffer(e.e1, precedence[e.op], buf, hgs);
+ }
+
+ override void visit(VectorExp e)
+ {
+ buf.writestring("cast(");
+ typeToBuffer(e.to, null, buf, hgs);
+ buf.writeByte(')');
+ expToBuffer(e.e1, precedence[e.op], buf, hgs);
+ }
+
+ override void visit(VectorArrayExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writestring(".array");
+ }
+
+ override void visit(SliceExp e)
+ {
+ expToBuffer(e.e1, precedence[e.op], buf, hgs);
+ buf.writeByte('[');
+ if (e.upr || e.lwr)
+ {
+ if (e.lwr)
+ sizeToBuffer(e.lwr, buf, hgs);
+ else
+ buf.writeByte('0');
+ buf.writestring("..");
+ if (e.upr)
+ sizeToBuffer(e.upr, buf, hgs);
+ else
+ buf.writeByte('$');
+ }
+ buf.writeByte(']');
+ }
+
+ override void visit(ArrayLengthExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writestring(".length");
+ }
+
+ override void visit(IntervalExp e)
+ {
+ expToBuffer(e.lwr, PREC.assign, buf, hgs);
+ buf.writestring("..");
+ expToBuffer(e.upr, PREC.assign, buf, hgs);
+ }
+
+ override void visit(DelegatePtrExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writestring(".ptr");
+ }
+
+ override void visit(DelegateFuncptrExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writestring(".funcptr");
+ }
+
+ override void visit(ArrayExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writeByte('[');
+ argsToBuffer(e.arguments, buf, hgs);
+ buf.writeByte(']');
+ }
+
+ override void visit(DotExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writeByte('.');
+ expToBuffer(e.e2, PREC.primary, buf, hgs);
+ }
+
+ override void visit(IndexExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writeByte('[');
+ sizeToBuffer(e.e2, buf, hgs);
+ buf.writeByte(']');
+ }
+
+ override void visit(PostExp e)
+ {
+ expToBuffer(e.e1, precedence[e.op], buf, hgs);
+ buf.writestring(Token.toString(e.op));
+ }
+
+ override void visit(PreExp e)
+ {
+ buf.writestring(Token.toString(e.op));
+ expToBuffer(e.e1, precedence[e.op], buf, hgs);
+ }
+
+ override void visit(RemoveExp e)
+ {
+ expToBuffer(e.e1, PREC.primary, buf, hgs);
+ buf.writestring(".remove(");
+ expToBuffer(e.e2, PREC.assign, buf, hgs);
+ buf.writeByte(')');
+ }
+
+ override void visit(CondExp e)
+ {
+ expToBuffer(e.econd, PREC.oror, buf, hgs);
+ buf.writestring(" ? ");
+ expToBuffer(e.e1, PREC.expr, buf, hgs);
+ buf.writestring(" : ");
+ expToBuffer(e.e2, PREC.cond, buf, hgs);
+ }
+
+ override void visit(DefaultInitExp e)
+ {
+ buf.writestring(Token.toString(e.op));
+ }
+
+ override void visit(ClassReferenceExp e)
+ {
+ buf.writestring(e.value.toChars());
+ }
+}
+
+/**
+ * Formats `value` as a literal of type `type` into `buf`.
+ *
+ * Params:
+ * type = literal type (e.g. Tfloat)
+ * value = value to print
+ * buf = target buffer
+ * allowHex = whether hex floating point literals may be used
+ * for greater accuracy
+ */
+void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool allowHex)
+{
+ /** sizeof(value)*3 is because each byte of mantissa is max
+ of 256 (3 characters). The string will be "-M.MMMMe-4932".
+ (ie, 8 chars more than mantissa). Plus one for trailing \0.
+ Plus one for rounding. */
+ const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1;
+ char[BUFFER_LEN] buffer;
+ CTFloat.sprint(buffer.ptr, 'g', value);
+ assert(strlen(buffer.ptr) < BUFFER_LEN);
+ if (allowHex)
+ {
+ real_t r = CTFloat.parse(buffer.ptr);
+ if (r != value) // if exact duplication
+ CTFloat.sprint(buffer.ptr, 'a', value);
+ }
+ buf.writestring(buffer.ptr);
+ if (buffer.ptr[strlen(buffer.ptr) - 1] == '.')
+ buf.remove(buf.length() - 1, 1);
+
+ if (type)
+ {
+ Type t = type.toBasetype();
+ switch (t.ty)
+ {
+ case Tfloat32:
+ case Timaginary32:
+ case Tcomplex32:
+ buf.writeByte('F');
+ break;
+ case Tfloat80:
+ case Timaginary80:
+ case Tcomplex80:
+ buf.writeByte('L');
+ break;
+ default:
+ break;
+ }
+ if (t.isimaginary())
+ buf.writeByte('i');
+ }
+}
+
+private void templateParameterToBuffer(TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs)
+{
+ scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs);
+ tp.accept(v);
+}
+
+private extern (C++) final class TemplateParameterPrettyPrintVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+public:
+ OutBuffer* buf;
+ HdrGenState* hgs;
+
+ extern (D) this(OutBuffer* buf, HdrGenState* hgs)
+ {
+ this.buf = buf;
+ this.hgs = hgs;
+ }
+
+ override void visit(TemplateTypeParameter tp)
+ {
+ buf.writestring(tp.ident.toString());
+ if (tp.specType)
+ {
+ buf.writestring(" : ");
+ typeToBuffer(tp.specType, null, buf, hgs);
+ }
+ if (tp.defaultType)
+ {
+ buf.writestring(" = ");
+ typeToBuffer(tp.defaultType, null, buf, hgs);
+ }
+ }
+
+ override void visit(TemplateThisParameter tp)
+ {
+ buf.writestring("this ");
+ visit(cast(TemplateTypeParameter)tp);
+ }
+
+ override void visit(TemplateAliasParameter tp)
+ {
+ buf.writestring("alias ");
+ if (tp.specType)
+ typeToBuffer(tp.specType, tp.ident, buf, hgs);
+ else
+ buf.writestring(tp.ident.toString());
+ if (tp.specAlias)
+ {
+ buf.writestring(" : ");
+ objectToBuffer(tp.specAlias, buf, hgs);
+ }
+ if (tp.defaultAlias)
+ {
+ buf.writestring(" = ");
+ objectToBuffer(tp.defaultAlias, buf, hgs);
+ }
+ }
+
+ override void visit(TemplateValueParameter tp)
+ {
+ typeToBuffer(tp.valType, tp.ident, buf, hgs);
+ if (tp.specValue)
+ {
+ buf.writestring(" : ");
+ tp.specValue.expressionToBuffer(buf, hgs);
+ }
+ if (tp.defaultValue)
+ {
+ buf.writestring(" = ");
+ tp.defaultValue.expressionToBuffer(buf, hgs);
+ }
+ }
+
+ override void visit(TemplateTupleParameter tp)
+ {
+ buf.writestring(tp.ident.toString());
+ buf.writestring("...");
+ }
+}
+
+private void conditionToBuffer(Condition c, OutBuffer* buf, HdrGenState* hgs)
+{
+ scope v = new ConditionPrettyPrintVisitor(buf, hgs);
+ c.accept(v);
+}
+
+private extern (C++) final class ConditionPrettyPrintVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+public:
+ OutBuffer* buf;
+ HdrGenState* hgs;
+
+ extern (D) this(OutBuffer* buf, HdrGenState* hgs)
+ {
+ this.buf = buf;
+ this.hgs = hgs;
+ }
+
+ override void visit(DebugCondition c)
+ {
+ buf.writestring("debug (");
+ if (c.ident)
+ buf.writestring(c.ident.toString());
+ else
+ buf.print(c.level);
+ buf.writeByte(')');
+ }
+
+ override void visit(VersionCondition c)
+ {
+ buf.writestring("version (");
+ if (c.ident)
+ buf.writestring(c.ident.toString());
+ else
+ buf.print(c.level);
+ buf.writeByte(')');
+ }
+
+ override void visit(StaticIfCondition c)
+ {
+ buf.writestring("static if (");
+ c.exp.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ }
+}
+
+void toCBuffer(const Statement s, OutBuffer* buf, HdrGenState* hgs)
+{
+ scope v = new StatementPrettyPrintVisitor(buf, hgs);
+ (cast() s).accept(v);
+}
+
+void toCBuffer(const Type t, OutBuffer* buf, const Identifier ident, HdrGenState* hgs)
+{
+ typeToBuffer(cast() t, ident, buf, hgs);
+}
+
+void toCBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs)
+{
+ scope v = new DsymbolPrettyPrintVisitor(buf, hgs);
+ s.accept(v);
+}
+
+// used from TemplateInstance::toChars() and TemplateMixin::toChars()
+void toCBufferInstance(const TemplateInstance ti, OutBuffer* buf, bool qualifyTypes = false)
+{
+ HdrGenState hgs;
+ hgs.fullQual = qualifyTypes;
+ scope v = new DsymbolPrettyPrintVisitor(buf, &hgs);
+ v.visit(cast() ti);
+}
+
+void toCBuffer(const Initializer iz, OutBuffer* buf, HdrGenState* hgs)
+{
+ initializerToBuffer(cast() iz, buf, hgs);
+}
+
+bool stcToBuffer(OutBuffer* buf, StorageClass stc)
+{
+ //printf("stc: %llx\n", stc);
+ bool result = false;
+
+ if (stc & STC.scopeinferred)
+ stc &= ~(STC.scope_ | STC.scopeinferred);
+ if (stc & STC.returninferred)
+ stc &= ~(STC.return_ | STC.returninferred);
+
+ /* Put scope ref return into a standard order
+ */
+ string rrs;
+ const isout = (stc & STC.out_) != 0;
+ //printf("bsr = %d %llx\n", buildScopeRef(stc), stc);
+ final switch (buildScopeRef(stc))
+ {
+ case ScopeRef.None:
+ case ScopeRef.Scope:
+ case ScopeRef.Ref:
+ case ScopeRef.Return:
+ break;
+
+ case ScopeRef.ReturnScope: rrs = "return scope"; goto L1;
+ case ScopeRef.ReturnRef: rrs = isout ? "return out" : "return ref"; goto L1;
+ case ScopeRef.RefScope: rrs = isout ? "out scope" : "ref scope"; goto L1;
+ case ScopeRef.ReturnRef_Scope: rrs = isout ? "return out scope" : "return ref scope"; goto L1;
+ case ScopeRef.Ref_ReturnScope: rrs = isout ? "out return scope" : "ref return scope"; goto L1;
+ L1:
+ buf.writestring(rrs);
+ result = true;
+ stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_);
+ break;
+ }
+
+ while (stc)
+ {
+ const s = stcToString(stc);
+ if (!s.length)
+ break;
+ if (result)
+ buf.writeByte(' ');
+ result = true;
+ buf.writestring(s);
+ }
+
+ return result;
+}
+
+/*************************************************
+ * Pick off one of the storage classes from stc,
+ * and return a string representation of it.
+ * stc is reduced by the one picked.
+ */
+string stcToString(ref StorageClass stc)
+{
+ static struct SCstring
+ {
+ StorageClass stc;
+ string id;
+ }
+
+ // Note: The identifier needs to be `\0` terminated
+ // as some code assumes it (e.g. when printing error messages)
+ static immutable SCstring[] table =
+ [
+ SCstring(STC.auto_, Token.toString(TOK.auto_)),
+ SCstring(STC.scope_, Token.toString(TOK.scope_)),
+ SCstring(STC.static_, Token.toString(TOK.static_)),
+ SCstring(STC.extern_, Token.toString(TOK.extern_)),
+ SCstring(STC.const_, Token.toString(TOK.const_)),
+ SCstring(STC.final_, Token.toString(TOK.final_)),
+ SCstring(STC.abstract_, Token.toString(TOK.abstract_)),
+ SCstring(STC.synchronized_, Token.toString(TOK.synchronized_)),
+ SCstring(STC.deprecated_, Token.toString(TOK.deprecated_)),
+ SCstring(STC.override_, Token.toString(TOK.override_)),
+ SCstring(STC.lazy_, Token.toString(TOK.lazy_)),
+ SCstring(STC.alias_, Token.toString(TOK.alias_)),
+ SCstring(STC.out_, Token.toString(TOK.out_)),
+ SCstring(STC.in_, Token.toString(TOK.in_)),
+ SCstring(STC.manifest, Token.toString(TOK.enum_)),
+ SCstring(STC.immutable_, Token.toString(TOK.immutable_)),
+ SCstring(STC.shared_, Token.toString(TOK.shared_)),
+ SCstring(STC.nothrow_, Token.toString(TOK.nothrow_)),
+ SCstring(STC.wild, Token.toString(TOK.inout_)),
+ SCstring(STC.pure_, Token.toString(TOK.pure_)),
+ SCstring(STC.ref_, Token.toString(TOK.ref_)),
+ SCstring(STC.return_, Token.toString(TOK.return_)),
+ SCstring(STC.tls, "__thread"),
+ SCstring(STC.gshared, Token.toString(TOK.gshared)),
+ SCstring(STC.nogc, "@nogc"),
+ SCstring(STC.live, "@live"),
+ SCstring(STC.property, "@property"),
+ SCstring(STC.safe, "@safe"),
+ SCstring(STC.trusted, "@trusted"),
+ SCstring(STC.system, "@system"),
+ SCstring(STC.disable, "@disable"),
+ SCstring(STC.future, "@__future"),
+ SCstring(STC.local, "__local"),
+ ];
+ foreach (ref entry; table)
+ {
+ const StorageClass tbl = entry.stc;
+ assert(tbl & STC.visibleStorageClasses);
+ if (stc & tbl)
+ {
+ stc &= ~tbl;
+ return entry.id;
+ }
+ }
+ //printf("stc = %llx\n", stc);
+ return null;
+}
+
+/// Ditto
+extern (D) string trustToString(TRUST trust) pure nothrow
+{
+ final switch (trust)
+ {
+ case TRUST.default_:
+ return null;
+ case TRUST.system:
+ return "@system";
+ case TRUST.trusted:
+ return "@trusted";
+ case TRUST.safe:
+ return "@safe";
+ }
+}
+
+private void linkageToBuffer(OutBuffer* buf, LINK linkage)
+{
+ const s = linkageToString(linkage);
+ if (s.length)
+ {
+ buf.writestring("extern (");
+ buf.writestring(s);
+ buf.writeByte(')');
+ }
+}
+
+const(char)* linkageToChars(LINK linkage)
+{
+ /// Works because we return a literal
+ return linkageToString(linkage).ptr;
+}
+
+string linkageToString(LINK linkage) pure nothrow
+{
+ final switch (linkage)
+ {
+ case LINK.default_:
+ return null;
+ case LINK.d:
+ return "D";
+ case LINK.c:
+ return "C";
+ case LINK.cpp:
+ return "C++";
+ case LINK.windows:
+ return "Windows";
+ case LINK.objc:
+ return "Objective-C";
+ case LINK.system:
+ return "System";
+ }
+}
+
+void visibilityToBuffer(OutBuffer* buf, Visibility vis)
+{
+ buf.writestring(visibilityToString(vis.kind));
+ if (vis.kind == Visibility.Kind.package_ && vis.pkg)
+ {
+ buf.writeByte('(');
+ buf.writestring(vis.pkg.toPrettyChars(true));
+ buf.writeByte(')');
+ }
+}
+
+/**
+ * Returns:
+ * a human readable representation of `kind`
+ */
+const(char)* visibilityToChars(Visibility.Kind kind)
+{
+ // Null terminated because we return a literal
+ return visibilityToString(kind).ptr;
+}
+
+/// Ditto
+extern (D) string visibilityToString(Visibility.Kind kind) nothrow pure
+{
+ final switch (kind)
+ {
+ case Visibility.Kind.undefined:
+ return null;
+ case Visibility.Kind.none:
+ return "none";
+ case Visibility.Kind.private_:
+ return "private";
+ case Visibility.Kind.package_:
+ return "package";
+ case Visibility.Kind.protected_:
+ return "protected";
+ case Visibility.Kind.public_:
+ return "public";
+ case Visibility.Kind.export_:
+ return "export";
+ }
+}
+
+// Print the full function signature with correct ident, attributes and template args
+void functionToBufferFull(TypeFunction tf, OutBuffer* buf, const Identifier ident, HdrGenState* hgs, TemplateDeclaration td)
+{
+ //printf("TypeFunction::toCBuffer() this = %p\n", this);
+ visitFuncIdentWithPrefix(tf, ident, td, buf, hgs);
+}
+
+// ident is inserted before the argument list and will be "function" or "delegate" for a type
+void functionToBufferWithIdent(TypeFunction tf, OutBuffer* buf, const(char)* ident, bool isStatic)
+{
+ HdrGenState hgs;
+ visitFuncIdentWithPostfix(tf, ident.toDString(), buf, &hgs, isStatic);
+}
+
+void toCBuffer(const Expression e, OutBuffer* buf, HdrGenState* hgs)
+{
+ scope v = new ExpressionPrettyPrintVisitor(buf, hgs);
+ (cast() e).accept(v);
+}
+
+/**************************************************
+ * Write out argument types to buf.
+ */
+void argExpTypesToCBuffer(OutBuffer* buf, Expressions* arguments)
+{
+ if (!arguments || !arguments.dim)
+ return;
+ HdrGenState hgs;
+ foreach (i, arg; *arguments)
+ {
+ if (i)
+ buf.writestring(", ");
+ typeToBuffer(arg.type, null, buf, &hgs);
+ }
+}
+
+void toCBuffer(const TemplateParameter tp, OutBuffer* buf, HdrGenState* hgs)
+{
+ scope v = new TemplateParameterPrettyPrintVisitor(buf, hgs);
+ (cast() tp).accept(v);
+}
+
+void arrayObjectsToBuffer(OutBuffer* buf, Objects* objects)
+{
+ if (!objects || !objects.dim)
+ return;
+ HdrGenState hgs;
+ foreach (i, o; *objects)
+ {
+ if (i)
+ buf.writestring(", ");
+ objectToBuffer(o, buf, &hgs);
+ }
+}
+
+/*************************************************************
+ * Pretty print function parameters.
+ * Params:
+ * pl = parameter list to print
+ * Returns: Null-terminated string representing parameters.
+ */
+extern (C++) const(char)* parametersTypeToChars(ParameterList pl)
+{
+ OutBuffer buf;
+ HdrGenState hgs;
+ parametersToBuffer(pl, &buf, &hgs);
+ return buf.extractChars();
+}
+
+/*************************************************************
+ * Pretty print function parameter.
+ * Params:
+ * parameter = parameter to print.
+ * tf = TypeFunction which holds parameter.
+ * fullQual = whether to fully qualify types.
+ * Returns: Null-terminated string representing parameters.
+ */
+const(char)* parameterToChars(Parameter parameter, TypeFunction tf, bool fullQual)
+{
+ OutBuffer buf;
+ HdrGenState hgs;
+ hgs.fullQual = fullQual;
+
+ parameterToBuffer(parameter, &buf, &hgs);
+
+ if (tf.parameterList.varargs == VarArg.typesafe && parameter == tf.parameterList[tf.parameterList.parameters.dim - 1])
+ {
+ buf.writestring("...");
+ }
+ return buf.extractChars();
+}
+
+
+/*************************************************
+ * Write ParameterList to buffer.
+ * Params:
+ * pl = parameter list to serialize
+ * buf = buffer to write it to
+ * hgs = context
+ */
+
+private void parametersToBuffer(ParameterList pl, OutBuffer* buf, HdrGenState* hgs)
+{
+ buf.writeByte('(');
+ foreach (i; 0 .. pl.length)
+ {
+ if (i)
+ buf.writestring(", ");
+ pl[i].parameterToBuffer(buf, hgs);
+ }
+ final switch (pl.varargs)
+ {
+ case VarArg.none:
+ break;
+
+ case VarArg.variadic:
+ if (pl.length)
+ buf.writestring(", ");
+
+ if (stcToBuffer(buf, pl.stc))
+ buf.writeByte(' ');
+ goto case VarArg.typesafe;
+
+ case VarArg.typesafe:
+ buf.writestring("...");
+ break;
+ }
+ buf.writeByte(')');
+}
+
+
+/***********************************************************
+ * Write parameter `p` to buffer `buf`.
+ * Params:
+ * p = parameter to serialize
+ * buf = buffer to write it to
+ * hgs = context
+ */
+private void parameterToBuffer(Parameter p, OutBuffer* buf, HdrGenState* hgs)
+{
+ if (p.userAttribDecl)
+ {
+ buf.writeByte('@');
+
+ bool isAnonymous = p.userAttribDecl.atts.dim > 0 && (*p.userAttribDecl.atts)[0].op != TOK.call;
+ if (isAnonymous)
+ buf.writeByte('(');
+
+ argsToBuffer(p.userAttribDecl.atts, buf, hgs);
+
+ if (isAnonymous)
+ buf.writeByte(')');
+ buf.writeByte(' ');
+ }
+ if (p.storageClass & STC.auto_)
+ buf.writestring("auto ");
+
+ StorageClass stc = p.storageClass;
+ if (p.storageClass & STC.in_)
+ {
+ buf.writestring("in ");
+ if (global.params.previewIn && p.storageClass & STC.ref_)
+ stc &= ~STC.ref_;
+ }
+ else if (p.storageClass & STC.lazy_)
+ buf.writestring("lazy ");
+ else if (p.storageClass & STC.alias_)
+ buf.writestring("alias ");
+
+ if (p.type && p.type.mod & MODFlags.shared_)
+ stc &= ~STC.shared_;
+
+ if (stcToBuffer(buf, stc & (STC.const_ | STC.immutable_ | STC.wild | STC.shared_ |
+ STC.return_ | STC.returninferred | STC.scope_ | STC.scopeinferred | STC.out_ | STC.ref_ | STC.returnScope)))
+ buf.writeByte(' ');
+
+ if (p.storageClass & STC.alias_)
+ {
+ if (p.ident)
+ buf.writestring(p.ident.toString());
+ }
+ else if (p.type.ty == Tident &&
+ (cast(TypeIdentifier)p.type).ident.toString().length > 3 &&
+ strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0)
+ {
+ // print parameter name, instead of undetermined type parameter
+ buf.writestring(p.ident.toString());
+ }
+ else
+ {
+ typeToBuffer(p.type, p.ident, buf, hgs, (stc & STC.in_) ? MODFlags.const_ : 0);
+ }
+
+ if (p.defaultArg)
+ {
+ buf.writestring(" = ");
+ p.defaultArg.expToBuffer(PREC.assign, buf, hgs);
+ }
+}
+
+
+/**************************************************
+ * Write out argument list to buf.
+ */
+private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* hgs, Expression basis = null)
+{
+ if (!expressions || !expressions.dim)
+ return;
+ version (all)
+ {
+ foreach (i, el; *expressions)
+ {
+ if (i)
+ buf.writestring(", ");
+ if (!el)
+ el = basis;
+ if (el)
+ expToBuffer(el, PREC.assign, buf, hgs);
+ }
+ }
+ else
+ {
+ // Sparse style formatting, for debug use only
+ // [0..dim: basis, 1: e1, 5: e5]
+ if (basis)
+ {
+ buf.writestring("0..");
+ buf.print(expressions.dim);
+ buf.writestring(": ");
+ expToBuffer(basis, PREC.assign, buf, hgs);
+ }
+ foreach (i, el; *expressions)
+ {
+ if (el)
+ {
+ if (basis)
+ {
+ buf.writestring(", ");
+ buf.print(i);
+ buf.writestring(": ");
+ }
+ else if (i)
+ buf.writestring(", ");
+ expToBuffer(el, PREC.assign, buf, hgs);
+ }
+ }
+ }
+}
+
+private void sizeToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
+{
+ if (e.type == Type.tsize_t)
+ {
+ Expression ex = (e.op == TOK.cast_ ? (cast(CastExp)e).e1 : e);
+ ex = ex.optimize(WANTvalue);
+ const dinteger_t uval = ex.op == TOK.int64 ? ex.toInteger() : cast(dinteger_t)-1;
+ if (cast(sinteger_t)uval >= 0)
+ {
+ dinteger_t sizemax = void;
+ if (target.ptrsize == 8)
+ sizemax = 0xFFFFFFFFFFFFFFFFUL;
+ else if (target.ptrsize == 4)
+ sizemax = 0xFFFFFFFFU;
+ else if (target.ptrsize == 2)
+ sizemax = 0xFFFFU;
+ else
+ assert(0);
+ if (uval <= sizemax && uval <= 0x7FFFFFFFFFFFFFFFUL)
+ {
+ buf.print(uval);
+ return;
+ }
+ }
+ }
+ expToBuffer(e, PREC.assign, buf, hgs);
+}
+
+private void expressionToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
+{
+ scope v = new ExpressionPrettyPrintVisitor(buf, hgs);
+ e.accept(v);
+}
+
+/**************************************************
+ * Write expression out to buf, but wrap it
+ * in ( ) if its precedence is less than pr.
+ */
+private void expToBuffer(Expression e, PREC pr, OutBuffer* buf, HdrGenState* hgs)
+{
+ debug
+ {
+ if (precedence[e.op] == PREC.zero)
+ printf("precedence not defined for token '%s'\n", Token.toChars(e.op));
+ }
+ if (e.op == 0xFF)
+ {
+ buf.writestring("<FF>");
+ return;
+ }
+ assert(precedence[e.op] != PREC.zero);
+ assert(pr != PREC.zero);
+ /* Despite precedence, we don't allow a<b<c expressions.
+ * They must be parenthesized.
+ */
+ if (precedence[e.op] < pr || (pr == PREC.rel && precedence[e.op] == pr)
+ || (pr >= PREC.or && pr <= PREC.and && precedence[e.op] == PREC.rel))
+ {
+ buf.writeByte('(');
+ e.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ }
+ else
+ {
+ e.expressionToBuffer(buf, hgs);
+ }
+}
+
+
+/**************************************************
+ * An entry point to pretty-print type.
+ */
+private void typeToBuffer(Type t, const Identifier ident, OutBuffer* buf, HdrGenState* hgs,
+ ubyte modMask = 0)
+{
+ if (auto tf = t.isTypeFunction())
+ {
+ visitFuncIdentWithPrefix(tf, ident, null, buf, hgs);
+ return;
+ }
+ visitWithMask(t, modMask, buf, hgs);
+ if (ident)
+ {
+ buf.writeByte(' ');
+ buf.writestring(ident.toString());
+ }
+}
+
+private void visitWithMask(Type t, ubyte modMask, OutBuffer* buf, HdrGenState* hgs)
+{
+ // Tuples and functions don't use the type constructor syntax
+ if (modMask == t.mod || t.ty == Tfunction || t.ty == Ttuple)
+ {
+ typeToBufferx(t, buf, hgs);
+ }
+ else
+ {
+ ubyte m = t.mod & ~(t.mod & modMask);
+ if (m & MODFlags.shared_)
+ {
+ MODtoBuffer(buf, MODFlags.shared_);
+ buf.writeByte('(');
+ }
+ if (m & MODFlags.wild)
+ {
+ MODtoBuffer(buf, MODFlags.wild);
+ buf.writeByte('(');
+ }
+ if (m & (MODFlags.const_ | MODFlags.immutable_))
+ {
+ MODtoBuffer(buf, m & (MODFlags.const_ | MODFlags.immutable_));
+ buf.writeByte('(');
+ }
+ typeToBufferx(t, buf, hgs);
+ if (m & (MODFlags.const_ | MODFlags.immutable_))
+ buf.writeByte(')');
+ if (m & MODFlags.wild)
+ buf.writeByte(')');
+ if (m & MODFlags.shared_)
+ buf.writeByte(')');
+ }
+}
+
+
+private void dumpTemplateInstance(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs)
+{
+ buf.writeByte('{');
+ buf.writenl();
+ buf.level++;
+
+ if (ti.aliasdecl)
+ {
+ ti.aliasdecl.dsymbolToBuffer(buf, hgs);
+ buf.writenl();
+ }
+ else if (ti.members)
+ {
+ foreach(m;*ti.members)
+ m.dsymbolToBuffer(buf, hgs);
+ }
+
+ buf.level--;
+ buf.writeByte('}');
+ buf.writenl();
+
+}
+
+private void tiargsToBuffer(TemplateInstance ti, OutBuffer* buf, HdrGenState* hgs)
+{
+ buf.writeByte('!');
+ if (ti.nest)
+ {
+ buf.writestring("(...)");
+ return;
+ }
+ if (!ti.tiargs)
+ {
+ buf.writestring("()");
+ return;
+ }
+ if (ti.tiargs.dim == 1)
+ {
+ RootObject oarg = (*ti.tiargs)[0];
+ if (Type t = isType(oarg))
+ {
+ if (t.equals(Type.tstring) || t.equals(Type.twstring) || t.equals(Type.tdstring) || t.mod == 0 && (t.isTypeBasic() || t.ty == Tident && (cast(TypeIdentifier)t).idents.dim == 0))
+ {
+ buf.writestring(t.toChars());
+ return;
+ }
+ }
+ else if (Expression e = isExpression(oarg))
+ {
+ if (e.op == TOK.int64 || e.op == TOK.float64 || e.op == TOK.null_ || e.op == TOK.string_ || e.op == TOK.this_)
+ {
+ buf.writestring(e.toChars());
+ return;
+ }
+ }
+ }
+ buf.writeByte('(');
+ ti.nestUp();
+ foreach (i, arg; *ti.tiargs)
+ {
+ if (i)
+ buf.writestring(", ");
+ objectToBuffer(arg, buf, hgs);
+ }
+ ti.nestDown();
+ buf.writeByte(')');
+}
+
+/****************************************
+ * This makes a 'pretty' version of the template arguments.
+ * It's analogous to genIdent() which makes a mangled version.
+ */
+private void objectToBuffer(RootObject oarg, OutBuffer* buf, HdrGenState* hgs)
+{
+ //printf("objectToBuffer()\n");
+ /* The logic of this should match what genIdent() does. The _dynamic_cast()
+ * function relies on all the pretty strings to be unique for different classes
+ * See https://issues.dlang.org/show_bug.cgi?id=7375
+ * Perhaps it would be better to demangle what genIdent() does.
+ */
+ if (auto t = isType(oarg))
+ {
+ //printf("\tt: %s ty = %d\n", t.toChars(), t.ty);
+ typeToBuffer(t, null, buf, hgs);
+ }
+ else if (auto e = isExpression(oarg))
+ {
+ if (e.op == TOK.variable)
+ e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375
+ expToBuffer(e, PREC.assign, buf, hgs);
+ }
+ else if (Dsymbol s = isDsymbol(oarg))
+ {
+ const p = s.ident ? s.ident.toChars() : s.toChars();
+ buf.writestring(p);
+ }
+ else if (auto v = isTuple(oarg))
+ {
+ auto args = &v.objects;
+ foreach (i, arg; *args)
+ {
+ if (i)
+ buf.writestring(", ");
+ objectToBuffer(arg, buf, hgs);
+ }
+ }
+ else if (auto p = isParameter(oarg))
+ {
+ parameterToBuffer(p, buf, hgs);
+ }
+ else if (!oarg)
+ {
+ buf.writestring("NULL");
+ }
+ else
+ {
+ debug
+ {
+ printf("bad Object = %p\n", oarg);
+ }
+ assert(0);
+ }
+}
+
+
+private void visitFuncIdentWithPostfix(TypeFunction t, const char[] ident, OutBuffer* buf, HdrGenState* hgs, bool isStatic)
+{
+ if (t.inuse)
+ {
+ t.inuse = 2; // flag error to caller
+ return;
+ }
+ t.inuse++;
+ if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen)
+ {
+ linkageToBuffer(buf, t.linkage);
+ buf.writeByte(' ');
+ }
+ if (t.linkage == LINK.objc && isStatic)
+ buf.write("static ");
+ if (t.next)
+ {
+ typeToBuffer(t.next, null, buf, hgs);
+ if (ident)
+ buf.writeByte(' ');
+ }
+ else if (hgs.ddoc)
+ buf.writestring("auto ");
+ if (ident)
+ buf.writestring(ident);
+ parametersToBuffer(t.parameterList, buf, hgs);
+ /* Use postfix style for attributes
+ */
+ if (t.mod)
+ {
+ buf.writeByte(' ');
+ MODtoBuffer(buf, t.mod);
+ }
+
+ void dg(string str)
+ {
+ buf.writeByte(' ');
+ buf.writestring(str);
+ }
+ t.attributesApply(&dg);
+
+ t.inuse--;
+}
+
+private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, TemplateDeclaration td,
+ OutBuffer* buf, HdrGenState* hgs)
+{
+ if (t.inuse)
+ {
+ t.inuse = 2; // flag error to caller
+ return;
+ }
+ t.inuse++;
+
+ /* Use 'storage class' (prefix) style for attributes
+ */
+ if (t.mod)
+ {
+ MODtoBuffer(buf, t.mod);
+ buf.writeByte(' ');
+ }
+
+ void ignoreReturn(string str)
+ {
+ if (str != "return")
+ {
+ // don't write 'ref' for ctors
+ if ((ident == Id.ctor) && str == "ref")
+ return;
+ buf.writestring(str);
+ buf.writeByte(' ');
+ }
+ }
+ t.attributesApply(&ignoreReturn);
+
+ if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen)
+ {
+ linkageToBuffer(buf, t.linkage);
+ buf.writeByte(' ');
+ }
+ if (ident && ident.toHChars2() != ident.toChars())
+ {
+ // Don't print return type for ctor, dtor, unittest, etc
+ }
+ else if (t.next)
+ {
+ typeToBuffer(t.next, null, buf, hgs);
+ if (ident)
+ buf.writeByte(' ');
+ }
+ else if (hgs.ddoc)
+ buf.writestring("auto ");
+ if (ident)
+ buf.writestring(ident.toHChars2());
+ if (td)
+ {
+ buf.writeByte('(');
+ foreach (i, p; *td.origParameters)
+ {
+ if (i)
+ buf.writestring(", ");
+ p.templateParameterToBuffer(buf, hgs);
+ }
+ buf.writeByte(')');
+ }
+ parametersToBuffer(t.parameterList, buf, hgs);
+ if (t.isreturn)
+ {
+ buf.writestring(" return");
+ }
+ t.inuse--;
+}
+
+
+private void initializerToBuffer(Initializer inx, OutBuffer* buf, HdrGenState* hgs)
+{
+ void visitError(ErrorInitializer iz)
+ {
+ buf.writestring("__error__");
+ }
+
+ void visitVoid(VoidInitializer iz)
+ {
+ buf.writestring("void");
+ }
+
+ void visitStruct(StructInitializer si)
+ {
+ //printf("StructInitializer::toCBuffer()\n");
+ buf.writeByte('{');
+ foreach (i, const id; si.field)
+ {
+ if (i)
+ buf.writestring(", ");
+ if (id)
+ {
+ buf.writestring(id.toString());
+ buf.writeByte(':');
+ }
+ if (auto iz = si.value[i])
+ initializerToBuffer(iz, buf, hgs);
+ }
+ buf.writeByte('}');
+ }
+
+ void visitArray(ArrayInitializer ai)
+ {
+ buf.writeByte('[');
+ foreach (i, ex; ai.index)
+ {
+ if (i)
+ buf.writestring(", ");
+ if (ex)
+ {
+ ex.expressionToBuffer(buf, hgs);
+ buf.writeByte(':');
+ }
+ if (auto iz = ai.value[i])
+ initializerToBuffer(iz, buf, hgs);
+ }
+ buf.writeByte(']');
+ }
+
+ void visitExp(ExpInitializer ei)
+ {
+ ei.exp.expressionToBuffer(buf, hgs);
+ }
+
+ void visitC(CInitializer ci)
+ {
+ buf.writeByte('{');
+ foreach (i, ref DesigInit di; ci.initializerList)
+ {
+ if (i)
+ buf.writestring(", ");
+ if (di.designatorList)
+ {
+ foreach (ref Designator d; (*di.designatorList)[])
+ {
+ if (d.exp)
+ {
+ buf.writeByte('[');
+ toCBuffer(d.exp, buf, hgs);
+ buf.writeByte(']');
+ }
+ else
+ {
+ buf.writeByte('.');
+ buf.writestring(d.ident.toString());
+ }
+ }
+ buf.writeByte('=');
+ }
+ initializerToBuffer(di.initializer, buf, hgs);
+ }
+ buf.writeByte('}');
+ }
+
+ final switch (inx.kind)
+ {
+ case InitKind.error: return visitError (inx.isErrorInitializer ());
+ case InitKind.void_: return visitVoid (inx.isVoidInitializer ());
+ case InitKind.struct_: return visitStruct(inx.isStructInitializer());
+ case InitKind.array: return visitArray (inx.isArrayInitializer ());
+ case InitKind.exp: return visitExp (inx.isExpInitializer ());
+ case InitKind.C_: return visitC (inx.isCInitializer ());
+ }
+}
+
+
+private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs)
+{
+ void visitType(Type t)
+ {
+ printf("t = %p, ty = %d\n", t, t.ty);
+ assert(0);
+ }
+
+ void visitError(TypeError t)
+ {
+ buf.writestring("_error_");
+ }
+
+ void visitBasic(TypeBasic t)
+ {
+ //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod);
+ buf.writestring(t.dstring);
+ }
+
+ void visitTraits(TypeTraits t)
+ {
+ //printf("TypeBasic::toCBuffer2(t.mod = %d)\n", t.mod);
+ t.exp.expressionToBuffer(buf, hgs);
+ }
+
+ void visitVector(TypeVector t)
+ {
+ //printf("TypeVector::toCBuffer2(t.mod = %d)\n", t.mod);
+ buf.writestring("__vector(");
+ visitWithMask(t.basetype, t.mod, buf, hgs);
+ buf.writestring(")");
+ }
+
+ void visitSArray(TypeSArray t)
+ {
+ visitWithMask(t.next, t.mod, buf, hgs);
+ buf.writeByte('[');
+ sizeToBuffer(t.dim, buf, hgs);
+ buf.writeByte(']');
+ }
+
+ void visitDArray(TypeDArray t)
+ {
+ Type ut = t.castMod(0);
+ if (hgs.declstring)
+ goto L1;
+ if (ut.equals(Type.tstring))
+ buf.writestring("string");
+ else if (ut.equals(Type.twstring))
+ buf.writestring("wstring");
+ else if (ut.equals(Type.tdstring))
+ buf.writestring("dstring");
+ else
+ {
+ L1:
+ visitWithMask(t.next, t.mod, buf, hgs);
+ buf.writestring("[]");
+ }
+ }
+
+ void visitAArray(TypeAArray t)
+ {
+ visitWithMask(t.next, t.mod, buf, hgs);
+ buf.writeByte('[');
+ visitWithMask(t.index, 0, buf, hgs);
+ buf.writeByte(']');
+ }
+
+ void visitPointer(TypePointer t)
+ {
+ //printf("TypePointer::toCBuffer2() next = %d\n", t.next.ty);
+ if (t.next.ty == Tfunction)
+ visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "function", buf, hgs, false);
+ else
+ {
+ visitWithMask(t.next, t.mod, buf, hgs);
+ buf.writeByte('*');
+ }
+ }
+
+ void visitReference(TypeReference t)
+ {
+ visitWithMask(t.next, t.mod, buf, hgs);
+ buf.writeByte('&');
+ }
+
+ void visitFunction(TypeFunction t)
+ {
+ //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t.isref);
+ visitFuncIdentWithPostfix(t, null, buf, hgs, false);
+ }
+
+ void visitDelegate(TypeDelegate t)
+ {
+ visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "delegate", buf, hgs, false);
+ }
+
+ void visitTypeQualifiedHelper(TypeQualified t)
+ {
+ foreach (id; t.idents)
+ {
+ if (id.dyncast() == DYNCAST.dsymbol)
+ {
+ buf.writeByte('.');
+ TemplateInstance ti = cast(TemplateInstance)id;
+ ti.dsymbolToBuffer(buf, hgs);
+ }
+ else if (id.dyncast() == DYNCAST.expression)
+ {
+ buf.writeByte('[');
+ (cast(Expression)id).expressionToBuffer(buf, hgs);
+ buf.writeByte(']');
+ }
+ else if (id.dyncast() == DYNCAST.type)
+ {
+ buf.writeByte('[');
+ typeToBufferx(cast(Type)id, buf, hgs);
+ buf.writeByte(']');
+ }
+ else
+ {
+ buf.writeByte('.');
+ buf.writestring(id.toString());
+ }
+ }
+ }
+
+ void visitIdentifier(TypeIdentifier t)
+ {
+ buf.writestring(t.ident.toString());
+ visitTypeQualifiedHelper(t);
+ }
+
+ void visitInstance(TypeInstance t)
+ {
+ t.tempinst.dsymbolToBuffer(buf, hgs);
+ visitTypeQualifiedHelper(t);
+ }
+
+ void visitTypeof(TypeTypeof t)
+ {
+ buf.writestring("typeof(");
+ t.exp.expressionToBuffer(buf, hgs);
+ buf.writeByte(')');
+ visitTypeQualifiedHelper(t);
+ }
+
+ void visitReturn(TypeReturn t)
+ {
+ buf.writestring("typeof(return)");
+ visitTypeQualifiedHelper(t);
+ }
+
+ void visitEnum(TypeEnum t)
+ {
+ buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
+ }
+
+ void visitStruct(TypeStruct t)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=13776
+ // Don't use ti.toAlias() to avoid forward reference error
+ // while printing messages.
+ TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null;
+ if (ti && ti.aliasdecl == t.sym)
+ buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars());
+ else
+ buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
+ }
+
+ void visitClass(TypeClass t)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=13776
+ // Don't use ti.toAlias() to avoid forward reference error
+ // while printing messages.
+ TemplateInstance ti = t.sym.parent ? t.sym.parent.isTemplateInstance() : null;
+ if (ti && ti.aliasdecl == t.sym)
+ buf.writestring(hgs.fullQual ? ti.toPrettyChars() : ti.toChars());
+ else
+ buf.writestring(hgs.fullQual ? t.sym.toPrettyChars() : t.sym.toChars());
+ }
+
+ void visitTag(TypeTag t)
+ {
+ buf.writestring(Token.toChars(t.tok));
+ buf.writeByte(' ');
+ if (t.id)
+ buf.writestring(t.id.toChars());
+ }
+
+ void visitTuple(TypeTuple t)
+ {
+ parametersToBuffer(ParameterList(t.arguments, VarArg.none), buf, hgs);
+ }
+
+ void visitSlice(TypeSlice t)
+ {
+ visitWithMask(t.next, t.mod, buf, hgs);
+ buf.writeByte('[');
+ sizeToBuffer(t.lwr, buf, hgs);
+ buf.writestring(" .. ");
+ sizeToBuffer(t.upr, buf, hgs);
+ buf.writeByte(']');
+ }
+
+ void visitNull(TypeNull t)
+ {
+ buf.writestring("typeof(null)");
+ }
+
+ void visitMixin(TypeMixin t)
+ {
+ buf.writestring("mixin(");
+ argsToBuffer(t.exps, buf, hgs, null);
+ buf.writeByte(')');
+ }
+
+ void visitNoreturn(TypeNoreturn t)
+ {
+ buf.writestring("noreturn");
+ }
+
+
+ switch (t.ty)
+ {
+ default: return t.isTypeBasic() ?
+ visitBasic(cast(TypeBasic)t) :
+ visitType(t);
+
+ case Terror: return visitError(cast(TypeError)t);
+ case Ttraits: return visitTraits(cast(TypeTraits)t);
+ case Tvector: return visitVector(cast(TypeVector)t);
+ case Tsarray: return visitSArray(cast(TypeSArray)t);
+ case Tarray: return visitDArray(cast(TypeDArray)t);
+ case Taarray: return visitAArray(cast(TypeAArray)t);
+ case Tpointer: return visitPointer(cast(TypePointer)t);
+ case Treference: return visitReference(cast(TypeReference)t);
+ case Tfunction: return visitFunction(cast(TypeFunction)t);
+ case Tdelegate: return visitDelegate(cast(TypeDelegate)t);
+ case Tident: return visitIdentifier(cast(TypeIdentifier)t);
+ case Tinstance: return visitInstance(cast(TypeInstance)t);
+ case Ttypeof: return visitTypeof(cast(TypeTypeof)t);
+ case Treturn: return visitReturn(cast(TypeReturn)t);
+ case Tenum: return visitEnum(cast(TypeEnum)t);
+ case Tstruct: return visitStruct(cast(TypeStruct)t);
+ case Tclass: return visitClass(cast(TypeClass)t);
+ case Ttuple: return visitTuple (cast(TypeTuple)t);
+ case Tslice: return visitSlice(cast(TypeSlice)t);
+ case Tnull: return visitNull(cast(TypeNull)t);
+ case Tmixin: return visitMixin(cast(TypeMixin)t);
+ case Tnoreturn: return visitNoreturn(cast(TypeNoreturn)t);
+ case Ttag: return visitTag(cast(TypeTag)t);
+ }
+}
diff --git a/gcc/d/dmd/hdrgen.h b/gcc/d/dmd/hdrgen.h
index 6822aaf4..531d5d8 100644
--- a/gcc/d/dmd/hdrgen.h
+++ b/gcc/d/dmd/hdrgen.h
@@ -10,45 +10,12 @@
#pragma once
-#include "root/dsystem.h" // memset()
-#include "dsymbol.h"
+#include "globals.h"
+#include "mtype.h"
-void genhdrfile(Module *m);
-
-struct HdrGenState
-{
- bool hdrgen; // true if generating header file
- bool ddoc; // true if generating Ddoc file
- bool fullDump; // true if generating a full AST dump file
- bool fullQual; // fully qualify types when printing
- int tpltMember;
- int autoMember;
- int forStmtInit;
-
- HdrGenState() { memset(this, 0, sizeof(HdrGenState)); }
-};
-
-void toCBuffer(Statement *s, OutBuffer *buf, HdrGenState *hgs);
-void toCBuffer(Type *t, OutBuffer *buf, Identifier *ident, HdrGenState *hgs);
-void toCBuffer(Dsymbol *s, OutBuffer *buf, HdrGenState *hgs);
-void toCBuffer(Initializer *iz, OutBuffer *buf, HdrGenState *hgs);
-void toCBuffer(Expression *e, OutBuffer *buf, HdrGenState *hgs);
-void toCBuffer(TemplateParameter *tp, OutBuffer *buf, HdrGenState *hgs);
-
-void toCBufferInstance(TemplateInstance *ti, OutBuffer *buf, bool qualifyTypes = false);
-
-void functionToBufferFull(TypeFunction *tf, OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TemplateDeclaration *td);
-void functionToBufferWithIdent(TypeFunction *t, OutBuffer *buf, const char *ident);
-
-void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments);
-
-void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects);
+class Module;
+void genhdrfile(Module *m);
+void genCppHdrFiles(Modules &ms);
void moduleToBuffer(OutBuffer *buf, Module *m);
-
const char *parametersTypeToChars(ParameterList pl);
-const char *parameterToChars(Parameter *parameter, TypeFunction *tf, bool fullQual);
-
-bool stcToBuffer(OutBuffer *buf, StorageClass stc);
-const char *stcToChars(StorageClass& stc);
-const char *linkageToChars(LINK linkage);
diff --git a/gcc/d/dmd/iasm.c b/gcc/d/dmd/iasm.c
deleted file mode 100644
index fc58a3c..0000000
--- a/gcc/d/dmd/iasm.c
+++ /dev/null
@@ -1,44 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 2018-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/iasm.c
- */
-
-/* Inline assembler for the D programming language compiler
- */
-
-#include "scope.h"
-#include "declaration.h"
-#include "statement.h"
-
-#ifdef IN_GCC
-Statement *gccAsmSemantic(GccAsmStatement *s, Scope *sc);
-#else
-Statement *inlineAsmSemantic(InlineAsmStatement *s, Scope *sc);
-#endif
-
-Statement *asmSemantic(AsmStatement *s, Scope *sc)
-{
- //printf("AsmStatement::semantic()\n");
-
- FuncDeclaration *fd = sc->parent->isFuncDeclaration();
- assert(fd);
-
- if (!s->tokens)
- return NULL;
-
- // Assume assembler code takes care of setting the return value
- sc->func->hasReturnExp |= 8;
-
-#ifdef IN_GCC
- GccAsmStatement *eas = new GccAsmStatement(s->loc, s->tokens);
- return gccAsmSemantic(eas, sc);
-#else
- InlineAsmStatement *ias = new InlineAsmStatement(s->loc, s->tokens);
- return inlineAsmSemantic(ias, sc);
-#endif
-}
diff --git a/gcc/d/dmd/iasm.d b/gcc/d/dmd/iasm.d
new file mode 100644
index 0000000..df8d1c9
--- /dev/null
+++ b/gcc/d/dmd/iasm.d
@@ -0,0 +1,59 @@
+/**
+ * Inline assembler for the D programming language compiler.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/iasm.html, Inline Assembler)
+ *
+ * Copyright (C) 2018-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/iasm.d, _iasm.d)
+ * Documentation: https://dlang.org/phobos/dmd_iasm.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/iasm.d
+ */
+
+module dmd.iasm;
+
+import dmd.dscope;
+import dmd.func;
+import dmd.statement;
+
+version (MARS)
+{
+ import dmd.iasmdmd;
+}
+else version (IN_GCC)
+{
+ import dmd.iasmgcc;
+}
+
+/************************ AsmStatement ***************************************/
+
+extern(C++) Statement asmSemantic(AsmStatement s, Scope *sc)
+{
+ //printf("AsmStatement.semantic()\n");
+
+ FuncDeclaration fd = sc.parent.isFuncDeclaration();
+ assert(fd);
+
+ if (!s.tokens)
+ return null;
+
+ // Assume assembler code takes care of setting the return value
+ sc.func.hasReturnExp |= 8;
+
+ version (MARS)
+ {
+ auto ias = new InlineAsmStatement(s.loc, s.tokens);
+ return inlineAsmSemantic(ias, sc);
+ }
+ else version (IN_GCC)
+ {
+ auto eas = new GccAsmStatement(s.loc, s.tokens);
+ return gccAsmSemantic(eas, sc);
+ }
+ else
+ {
+ s.error("D inline assembler statements are not supported");
+ return new ErrorStatement();
+ }
+}
diff --git a/gcc/d/dmd/iasmgcc.c b/gcc/d/dmd/iasmgcc.c
deleted file mode 100644
index e3940a8..0000000
--- a/gcc/d/dmd/iasmgcc.c
+++ /dev/null
@@ -1,379 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 2018-2021 by The D Language Foundation, All Rights Reserved
- * written by Iain Buclaw
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/iasmgcc.c
- */
-
-/* Inline assembler for the GCC D compiler.
- */
-
-#include "scope.h"
-#include "expression.h"
-#include "declaration.h"
-#include "errors.h"
-#include "parse.h"
-#include "statement.h"
-
-/***********************************
- * Parse list of extended asm input or output operands.
- * Grammar:
- * | Operands:
- * | SymbolicName(opt) StringLiteral ( AssignExpression )
- * | SymbolicName(opt) StringLiteral ( AssignExpression ), Operands
- * |
- * | SymbolicName:
- * | [ Identifier ]
- * Params:
- * p = parser state
- * s = asm statement to parse
- * Returns:
- * number of operands added to the gcc asm statement
- */
-static int parseExtAsmOperands(Parser *p, GccAsmStatement *s)
-{
- int numargs = 0;
-
- while (1)
- {
- Expression *arg = NULL;
- Identifier *name = NULL;
- Expression *constraint = NULL;
-
- switch (p->token.value)
- {
- case TOKsemicolon:
- case TOKcolon:
- case TOKeof:
- return numargs;
-
- case TOKlbracket:
- if (p->peekNext() == TOKidentifier)
- {
- // Skip over openings `[`
- p->nextToken();
- // Store the symbolic name
- name = p->token.ident;
- p->nextToken();
- }
- else
- {
- p->error(s->loc, "expected identifier after `[`");
- goto Lerror;
- }
- // Look for closing `]`
- p->check(TOKrbracket);
- // Look for the string literal and fall through
- if (p->token.value != TOKstring)
- goto Ldefault;
- // fall through
-
- case TOKstring:
- constraint = p->parsePrimaryExp();
- // @@@DEPRECATED@@@
- // Old parser allowed omitting parentheses around the expression.
- // Deprecated in 2.091. Can be made permanent error after 2.100
- if (p->token.value != TOKlparen)
- {
- arg = p->parseAssignExp();
- deprecation(arg->loc, "`%s` must be surrounded by parentheses", arg->toChars());
- }
- else
- {
- // Look for the opening `(`
- p->check(TOKlparen);
- // Parse the assign expression
- arg = p->parseAssignExp();
- // Look for the closing `)`
- p->check(TOKrparen);
- }
-
- if (!s->args)
- {
- s->names = new Identifiers();
- s->constraints = new Expressions();
- s->args = new Expressions();
- }
- s->names->push(name);
- s->args->push(arg);
- s->constraints->push(constraint);
- numargs++;
-
- if (p->token.value == TOKcomma)
- p->nextToken();
- break;
-
- default:
- Ldefault:
- p->error("expected constant string constraint for operand, not `%s`",
- p->token.toChars());
- goto Lerror;
- }
- }
-Lerror:
- while (p->token.value != TOKrcurly &&
- p->token.value != TOKsemicolon &&
- p->token.value != TOKeof)
- p->nextToken();
-
- return numargs;
-}
-
-/***********************************
- * Parse list of extended asm clobbers.
- * Grammar:
- * | Clobbers:
- * | StringLiteral
- * | StringLiteral , Clobbers
- * Params:
- * p = parser state
- * Returns:
- * array of parsed clobber expressions
- */
-static Expressions *parseExtAsmClobbers(Parser *p)
-{
- Expressions *clobbers = NULL;
-
- while (1)
- {
- Expression *clobber;
-
- switch (p->token.value)
- {
- case TOKsemicolon:
- case TOKcolon:
- case TOKeof:
- return clobbers;
-
- case TOKstring:
- clobber = p->parsePrimaryExp();
- if (!clobbers)
- clobbers = new Expressions();
- clobbers->push(clobber);
-
- if (p->token.value == TOKcomma)
- p->nextToken();
- break;
-
- default:
- p->error("expected constant string constraint for clobber name, not `%s`",
- p->token.toChars());
- goto Lerror;
- }
- }
-Lerror:
- while (p->token.value != TOKrcurly &&
- p->token.value != TOKsemicolon &&
- p->token.value != TOKeof)
- p->nextToken();
-
- return clobbers;
-}
-
-/***********************************
- * Parse list of extended asm goto labels.
- * Grammar:
- * | GotoLabels:
- * | Identifier
- * | Identifier , GotoLabels
- * Params:
- * p = parser state
- * Returns:
- * array of parsed goto labels
- */
-static Identifiers *parseExtAsmGotoLabels(Parser *p)
-{
- Identifiers *labels = NULL;
-
- while (1)
- {
- switch (p->token.value)
- {
- case TOKsemicolon:
- case TOKeof:
- return labels;
-
- case TOKidentifier:
- if (!labels)
- labels = new Identifiers();
- labels->push(p->token.ident);
-
- if (p->nextToken() == TOKcomma)
- p->nextToken();
- break;
-
- default:
- p->error("expected identifier for goto label name, not `%s`",
- p->token.toChars());
- goto Lerror;
- }
- }
-Lerror:
- while (p->token.value != TOKrcurly &&
- p->token.value != TOKsemicolon &&
- p->token.value != TOKeof)
- p->nextToken();
-
- return labels;
-}
-
-/***********************************
- * Parse a gcc asm statement.
- * There are three forms of inline asm statements, basic, extended, and goto.
- * Grammar:
- * | AsmInstruction:
- * | BasicAsmInstruction
- * | ExtAsmInstruction
- * | GotoAsmInstruction
- * |
- * | BasicAsmInstruction:
- * | Expression
- * |
- * | ExtAsmInstruction:
- * | Expression : Operands(opt) : Operands(opt) : Clobbers(opt)
- * |
- * | GotoAsmInstruction:
- * | Expression : : Operands(opt) : Clobbers(opt) : GotoLabels(opt)
- * Params:
- * p = parser state
- * s = asm statement to parse
- * Returns:
- * the parsed gcc asm statement
- */
-static GccAsmStatement *parseGccAsm(Parser *p, GccAsmStatement *s)
-{
- s->insn = p->parseExpression();
- if (p->token.value == TOKsemicolon || p->token.value == TOKeof)
- goto Ldone;
-
- // No semicolon followed after instruction template, treat as extended asm.
- for (int section = 0; section < 4; ++section)
- {
- p->check(TOKcolon);
-
- switch (section)
- {
- case 0:
- s->outputargs = parseExtAsmOperands(p, s);
- break;
-
- case 1:
- parseExtAsmOperands(p, s);
- break;
-
- case 2:
- s->clobbers = parseExtAsmClobbers(p);
- break;
-
- case 3:
- s->labels = parseExtAsmGotoLabels(p);
- break;
-
- default:
- assert(0);
- }
-
- if (p->token.value == TOKsemicolon || p->token.value == TOKeof)
- goto Ldone;
- }
-Ldone:
- p->check(TOKsemicolon);
-
- return s;
-}
-
-/***********************************
- * Parse and run semantic analysis on a GccAsmStatement.
- * Params:
- * s = gcc asm statement being parsed
- * sc = the scope where the asm statement is located
- * Returns:
- * the completed gcc asm statement, or null if errors occurred
- */
-Statement *gccAsmSemantic(GccAsmStatement *s, Scope *sc)
-{
- //printf("GccAsmStatement::semantic()\n");
- Parser p(sc->_module, (const utf8_t *)";", 1, false);
-
- // Make a safe copy of the token list before parsing.
- Token *toklist = NULL;
- Token **ptoklist = &toklist;
-
- for (Token *token = s->tokens; token; token = token->next)
- {
- *ptoklist = Token::alloc();
- memcpy(*ptoklist, token, sizeof(Token));
- ptoklist = &(*ptoklist)->next;
- *ptoklist = NULL;
- }
- p.token = *toklist;
- p.scanloc = s->loc;
-
- // Parse the gcc asm statement.
- s = parseGccAsm(&p, s);
- if (p.errors)
- return NULL;
- s->stc = sc->stc;
-
- // Fold the instruction template string.
- s->insn = expressionSemantic(s->insn, sc);
- s->insn = s->insn->ctfeInterpret();
-
- if (s->insn->op != TOKstring || ((StringExp *) s->insn)->sz != 1)
- s->insn->error("asm instruction template must be a constant char string");
-
- if (s->labels && s->outputargs)
- s->error("extended asm statements with labels cannot have output constraints");
-
- // Analyse all input and output operands.
- if (s->args)
- {
- for (size_t i = 0; i < s->args->length; i++)
- {
- Expression *e = (*s->args)[i];
- e = expressionSemantic(e, sc);
- // Check argument is a valid lvalue/rvalue.
- if (i < s->outputargs)
- e = e->modifiableLvalue(sc, NULL);
- else if (e->checkValue())
- e = new ErrorExp();
- (*s->args)[i] = e;
-
- e = (*s->constraints)[i];
- e = expressionSemantic(e, sc);
- assert(e->op == TOKstring && ((StringExp *) e)->sz == 1);
- (*s->constraints)[i] = e;
- }
- }
-
- // Analyse all clobbers.
- if (s->clobbers)
- {
- for (size_t i = 0; i < s->clobbers->length; i++)
- {
- Expression *e = (*s->clobbers)[i];
- e = expressionSemantic(e, sc);
- assert(e->op == TOKstring && ((StringExp *) e)->sz == 1);
- (*s->clobbers)[i] = e;
- }
- }
-
- // Analyse all goto labels.
- if (s->labels)
- {
- for (size_t i = 0; i < s->labels->length; i++)
- {
- Identifier *ident = (*s->labels)[i];
- GotoStatement *gs = new GotoStatement(s->loc, ident);
- if (!s->gotos)
- s->gotos = new GotoStatements();
- s->gotos->push(gs);
- statementSemantic(gs, sc);
- }
- }
-
- return s;
-}
diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d
new file mode 100644
index 0000000..e61fb23
--- /dev/null
+++ b/gcc/d/dmd/iasmgcc.d
@@ -0,0 +1,537 @@
+/**
+ * Inline assembler for the GCC D compiler.
+ *
+ * Copyright (C) 2018-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Iain Buclaw
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/iasmgcc.d, _iasmgcc.d)
+ * Documentation: https://dlang.org/phobos/dmd_iasmgcc.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/iasmgcc.d
+ */
+
+module dmd.iasmgcc;
+
+import core.stdc.string;
+
+import dmd.arraytypes;
+import dmd.astcodegen;
+import dmd.dscope;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.identifier;
+import dmd.globals;
+import dmd.parse;
+import dmd.tokens;
+import dmd.statement;
+import dmd.statementsem;
+
+private:
+
+/***********************************
+ * Parse list of extended asm input or output operands.
+ * Grammar:
+ * | Operands:
+ * | SymbolicName(opt) StringLiteral ( AssignExpression )
+ * | SymbolicName(opt) StringLiteral ( AssignExpression ), Operands
+ * |
+ * | SymbolicName:
+ * | [ Identifier ]
+ * Params:
+ * p = parser state
+ * s = asm statement to parse
+ * Returns:
+ * number of operands added to the gcc asm statement
+ */
+int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s)
+{
+ int numargs = 0;
+
+ while (1)
+ {
+ Expression arg;
+ Identifier name;
+ Expression constraint;
+
+ switch (p.token.value)
+ {
+ case TOK.semicolon:
+ case TOK.colon:
+ case TOK.endOfFile:
+ return numargs;
+
+ case TOK.leftBracket:
+ if (p.peekNext() == TOK.identifier)
+ {
+ // Skip over opening `[`
+ p.nextToken();
+ // Store the symbolic name
+ name = p.token.ident;
+ p.nextToken();
+ }
+ else
+ {
+ p.error(s.loc, "expected identifier after `[`");
+ goto Lerror;
+ }
+ // Look for closing `]`
+ p.check(TOK.rightBracket);
+ // Look for the string literal and fall through
+ if (p.token.value == TOK.string_)
+ goto case;
+ else
+ goto default;
+
+ case TOK.string_:
+ constraint = p.parsePrimaryExp();
+ // @@@DEPRECATED@@@
+ // Old parser allowed omitting parentheses around the expression.
+ // Deprecated in 2.091. Can be made permanent error after 2.100
+ if (p.token.value != TOK.leftParenthesis)
+ {
+ arg = p.parseAssignExp();
+ deprecation(arg.loc, "`%s` must be surrounded by parentheses", arg.toChars());
+ }
+ else
+ {
+ // Look for the opening `(`
+ p.check(TOK.leftParenthesis);
+ // Parse the assign expression
+ arg = p.parseAssignExp();
+ // Look for the closing `)`
+ p.check(TOK.rightParenthesis);
+ }
+
+ if (!s.args)
+ {
+ s.names = new Identifiers();
+ s.constraints = new Expressions();
+ s.args = new Expressions();
+ }
+ s.names.push(name);
+ s.args.push(arg);
+ s.constraints.push(constraint);
+ numargs++;
+
+ if (p.token.value == TOK.comma)
+ p.nextToken();
+ break;
+
+ default:
+ p.error("expected constant string constraint for operand, not `%s`",
+ p.token.toChars());
+ goto Lerror;
+ }
+ }
+Lerror:
+ while (p.token.value != TOK.rightCurly &&
+ p.token.value != TOK.semicolon &&
+ p.token.value != TOK.endOfFile)
+ p.nextToken();
+
+ return numargs;
+}
+
+/***********************************
+ * Parse list of extended asm clobbers.
+ * Grammar:
+ * | Clobbers:
+ * | StringLiteral
+ * | StringLiteral , Clobbers
+ * Params:
+ * p = parser state
+ * Returns:
+ * array of parsed clobber expressions
+ */
+Expressions *parseExtAsmClobbers(Parser)(Parser p)
+{
+ Expressions *clobbers;
+
+ while (1)
+ {
+ Expression clobber;
+
+ switch (p.token.value)
+ {
+ case TOK.semicolon:
+ case TOK.colon:
+ case TOK.endOfFile:
+ return clobbers;
+
+ case TOK.string_:
+ clobber = p.parsePrimaryExp();
+ if (!clobbers)
+ clobbers = new Expressions();
+ clobbers.push(clobber);
+
+ if (p.token.value == TOK.comma)
+ p.nextToken();
+ break;
+
+ default:
+ p.error("expected constant string constraint for clobber name, not `%s`",
+ p.token.toChars());
+ goto Lerror;
+ }
+ }
+Lerror:
+ while (p.token.value != TOK.rightCurly &&
+ p.token.value != TOK.semicolon &&
+ p.token.value != TOK.endOfFile)
+ p.nextToken();
+
+ return clobbers;
+}
+
+/***********************************
+ * Parse list of extended asm goto labels.
+ * Grammar:
+ * | GotoLabels:
+ * | Identifier
+ * | Identifier , GotoLabels
+ * Params:
+ * p = parser state
+ * Returns:
+ * array of parsed goto labels
+ */
+Identifiers *parseExtAsmGotoLabels(Parser)(Parser p)
+{
+ Identifiers *labels;
+
+ while (1)
+ {
+ switch (p.token.value)
+ {
+ case TOK.semicolon:
+ case TOK.endOfFile:
+ return labels;
+
+ case TOK.identifier:
+ if (!labels)
+ labels = new Identifiers();
+ labels.push(p.token.ident);
+
+ if (p.nextToken() == TOK.comma)
+ p.nextToken();
+ break;
+
+ default:
+ p.error("expected identifier for goto label name, not `%s`",
+ p.token.toChars());
+ goto Lerror;
+ }
+ }
+Lerror:
+ while (p.token.value != TOK.rightCurly &&
+ p.token.value != TOK.semicolon &&
+ p.token.value != TOK.endOfFile)
+ p.nextToken();
+
+ return labels;
+}
+
+/***********************************
+ * Parse a gcc asm statement.
+ * There are three forms of inline asm statements, basic, extended, and goto.
+ * Grammar:
+ * | AsmInstruction:
+ * | BasicAsmInstruction
+ * | ExtAsmInstruction
+ * | GotoAsmInstruction
+ * |
+ * | BasicAsmInstruction:
+ * | AssignExpression
+ * |
+ * | ExtAsmInstruction:
+ * | AssignExpression : Operands(opt) : Operands(opt) : Clobbers(opt)
+ * |
+ * | GotoAsmInstruction:
+ * | AssignExpression : : Operands(opt) : Clobbers(opt) : GotoLabels(opt)
+ * Params:
+ * p = parser state
+ * s = asm statement to parse
+ * Returns:
+ * the parsed gcc asm statement
+ */
+GccAsmStatement parseGccAsm(Parser)(Parser p, GccAsmStatement s)
+{
+ s.insn = p.parseAssignExp();
+ if (p.token.value == TOK.semicolon || p.token.value == TOK.endOfFile)
+ goto Ldone;
+
+ // No semicolon followed after instruction template, treat as extended asm.
+ foreach (section; 0 .. 4)
+ {
+ p.check(TOK.colon);
+
+ final switch (section)
+ {
+ case 0:
+ s.outputargs = p.parseExtAsmOperands(s);
+ break;
+
+ case 1:
+ p.parseExtAsmOperands(s);
+ break;
+
+ case 2:
+ s.clobbers = p.parseExtAsmClobbers();
+ break;
+
+ case 3:
+ s.labels = p.parseExtAsmGotoLabels();
+ break;
+ }
+
+ if (p.token.value == TOK.semicolon || p.token.value == TOK.endOfFile)
+ goto Ldone;
+ }
+Ldone:
+ p.check(TOK.semicolon);
+
+ return s;
+}
+
+/***********************************
+ * Parse and run semantic analysis on a GccAsmStatement.
+ * Params:
+ * s = gcc asm statement being parsed
+ * sc = the scope where the asm statement is located
+ * Returns:
+ * the completed gcc asm statement, or null if errors occurred
+ */
+public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
+{
+ //printf("GccAsmStatement.semantic()\n");
+ scope p = new Parser!ASTCodegen(sc._module, ";", false);
+
+ // Make a safe copy of the token list before parsing.
+ Token *toklist = null;
+ Token **ptoklist = &toklist;
+
+ for (Token *token = s.tokens; token; token = token.next)
+ {
+ *ptoklist = p.allocateToken();
+ memcpy(*ptoklist, token, Token.sizeof);
+ ptoklist = &(*ptoklist).next;
+ *ptoklist = null;
+ }
+ p.token = *toklist;
+ p.scanloc = s.loc;
+
+ // Parse the gcc asm statement.
+ const errors = global.errors;
+ s = p.parseGccAsm(s);
+ if (errors != global.errors)
+ return null;
+ s.stc = sc.stc;
+
+ // Fold the instruction template string.
+ s.insn = semanticString(sc, s.insn, "asm instruction template");
+
+ if (s.labels && s.outputargs)
+ s.error("extended asm statements with labels cannot have output constraints");
+
+ // Analyse all input and output operands.
+ if (s.args)
+ {
+ foreach (i; 0 .. s.args.dim)
+ {
+ Expression e = (*s.args)[i];
+ e = e.expressionSemantic(sc);
+ // Check argument is a valid lvalue/rvalue.
+ if (i < s.outputargs)
+ e = e.modifiableLvalue(sc, null);
+ else if (e.checkValue())
+ e = ErrorExp.get();
+ (*s.args)[i] = e;
+
+ e = (*s.constraints)[i];
+ e = e.expressionSemantic(sc);
+ assert(e.op == TOK.string_ && (cast(StringExp) e).sz == 1);
+ (*s.constraints)[i] = e;
+ }
+ }
+
+ // Analyse all clobbers.
+ if (s.clobbers)
+ {
+ foreach (i; 0 .. s.clobbers.dim)
+ {
+ Expression e = (*s.clobbers)[i];
+ e = e.expressionSemantic(sc);
+ assert(e.op == TOK.string_ && (cast(StringExp) e).sz == 1);
+ (*s.clobbers)[i] = e;
+ }
+ }
+
+ // Analyse all goto labels.
+ if (s.labels)
+ {
+ foreach (i; 0 .. s.labels.dim)
+ {
+ Identifier ident = (*s.labels)[i];
+ GotoStatement gs = new GotoStatement(s.loc, ident);
+ if (!s.gotos)
+ s.gotos = new GotoStatements();
+ s.gotos.push(gs);
+ gs.statementSemantic(sc);
+ }
+ }
+
+ return s;
+}
+
+unittest
+{
+ import dmd.mtype : TypeBasic;
+
+ uint errors = global.startGagging();
+ scope(exit) global.endGagging(errors);
+
+ // If this check fails, then Type._init() was called before reaching here,
+ // and the entire chunk of code that follows can be removed.
+ assert(ASTCodegen.Type.tint32 is null);
+ // Minimally initialize the cached types in ASTCodegen.Type, as they are
+ // dependencies for some fail asm tests to succeed.
+ ASTCodegen.Type.stringtable._init();
+ scope(exit)
+ {
+ ASTCodegen.Type.deinitialize();
+ ASTCodegen.Type.tint32 = null;
+ }
+ scope tint32 = new TypeBasic(ASTCodegen.Tint32);
+ ASTCodegen.Type.tint32 = tint32;
+
+ // Imitates asmSemantic if version = IN_GCC.
+ static int semanticAsm(Token* tokens)
+ {
+ const errors = global.errors;
+ scope gas = new GccAsmStatement(Loc.initial, tokens);
+ scope p = new Parser!ASTCodegen(null, ";", false);
+ p.token = *tokens;
+ p.parseGccAsm(gas);
+ return global.errors - errors;
+ }
+
+ // Imitates parseStatement for asm statements.
+ static void parseAsm(string input, bool expectError)
+ {
+ // Generate tokens from input test.
+ scope p = new Parser!ASTCodegen(null, input, false);
+ p.nextToken();
+
+ Token* toklist = null;
+ Token** ptoklist = &toklist;
+ p.check(TOK.asm_);
+ p.check(TOK.leftCurly);
+ while (1)
+ {
+ if (p.token.value == TOK.rightCurly || p.token.value == TOK.endOfFile)
+ break;
+ if (p.token.value == TOK.colonColon)
+ {
+ *ptoklist = p.allocateToken();
+ memcpy(*ptoklist, &p.token, Token.sizeof);
+ (*ptoklist).value = TOK.colon;
+ ptoklist = &(*ptoklist).next;
+
+ *ptoklist = p.allocateToken();
+ memcpy(*ptoklist, &p.token, Token.sizeof);
+ (*ptoklist).value = TOK.colon;
+ ptoklist = &(*ptoklist).next;
+ }
+ else
+ {
+ *ptoklist = p.allocateToken();
+ memcpy(*ptoklist, &p.token, Token.sizeof);
+ ptoklist = &(*ptoklist).next;
+ }
+ *ptoklist = null;
+ p.nextToken();
+ }
+ p.check(TOK.rightCurly);
+
+ auto res = semanticAsm(toklist);
+ // Checks for both unexpected passes and failures.
+ assert((res == 0) != expectError);
+ }
+
+ /// Assembly Tests, all should pass.
+ /// Note: Frontend is not initialized, use only strings and identifiers.
+ immutable string[] passAsmTests = [
+ // Basic asm statement
+ q{ asm { "nop";
+ } },
+
+ // Extended asm statement
+ q{ asm { "cpuid"
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d)
+ : "a" (input);
+ } },
+
+ // Assembly with symbolic names
+ q{ asm { "bts %[base], %[offset]"
+ : [base] "+rm" (*ptr),
+ : [offset] "Ir" (bitnum);
+ } },
+
+ // Assembly with clobbers
+ q{ asm { "cpuid"
+ : "=a" (a)
+ : "a" (input)
+ : "ebx", "ecx", "edx";
+ } },
+
+ // Goto asm statement
+ q{ asm { "jmp %l0"
+ :
+ :
+ :
+ : Ljmplabel;
+ } },
+
+ // Any CTFE-able string allowed as instruction template.
+ q{ asm { generateAsm();
+ } },
+
+ // Likewise mixins, permissible so long as the result is a string.
+ q{ asm { mixin(`"repne"`, `~ "scasb"`);
+ } },
+
+ // :: token tests
+ q{ asm { "" : : : "memory"; } },
+ q{ asm { "" :: : "memory"; } },
+ q{ asm { "" : :: "memory"; } },
+ q{ asm { "" ::: "memory"; } },
+ ];
+
+ immutable string[] failAsmTests = [
+ // Found 'h' when expecting ';'
+ q{ asm { ""h;
+ } },
+
+ // https://issues.dlang.org/show_bug.cgi?id=20592
+ q{ asm { "nop" : [name] string (expr); } },
+
+ // Expression expected, not ';'
+ q{ asm { ""[;
+ } },
+
+ // Expression expected, not ':'
+ q{ asm { ""
+ :
+ : "g" (a ? b : : c);
+ } },
+
+ // Found ',' when expecting ':'
+ q{ asm { "", "";
+ } },
+ ];
+
+ foreach (test; passAsmTests)
+ parseAsm(test, false);
+
+ foreach (test; failAsmTests)
+ parseAsm(test, true);
+}
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
new file mode 100644
index 0000000..1f04dcf
--- /dev/null
+++ b/gcc/d/dmd/id.d
@@ -0,0 +1,568 @@
+/**
+ * Contains the `Id` struct with a list of predefined symbols the compiler knows about.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/id.d, _id.d)
+ * Documentation: https://dlang.org/phobos/dmd_id.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/id.d
+ */
+
+module dmd.id;
+
+import dmd.identifier;
+import dmd.tokens;
+
+/**
+ * Represents a list of predefined symbols the compiler knows about.
+ *
+ * All static fields in this struct represents a specific predefined symbol.
+ */
+extern (C++) struct Id
+{
+ static __gshared:
+
+ mixin(msgtable.generate(&identifier));
+
+ /**
+ * Populates the identifier pool with all predefined symbols.
+ *
+ * An identifier that corresponds to each static field in this struct will
+ * be placed in the identifier pool.
+ */
+ extern(C++) void initialize()
+ {
+ mixin(msgtable.generate(&initializer));
+ }
+
+ /**
+ * Deinitializes the global state of the compiler.
+ *
+ * This can be used to restore the state set by `initialize` to its original
+ * state.
+ */
+ extern (D) void deinitialize()
+ {
+ mixin(msgtable.generate(&deinitializer));
+ }
+}
+
+private:
+
+
+/**
+ * Each element in this array will generate one static field in the `Id` struct
+ * and a call to `Identifier.idPool` to populate the identifier pool in the
+ * `Id.initialize` method.
+ */
+immutable Msgtable[] msgtable =
+[
+ { "IUnknown" },
+ { "Object" },
+ { "object" },
+ { "string" },
+ { "wstring" },
+ { "dstring" },
+ { "max" },
+ { "min" },
+ { "This", "this" },
+ { "_super", "super" },
+ { "ctor", "__ctor" },
+ { "dtor", "__dtor" },
+ { "__xdtor", "__xdtor" },
+ { "__fieldDtor", "__fieldDtor" },
+ { "__aggrDtor", "__aggrDtor" },
+ { "cppdtor", "__cppdtor" },
+ { "ticppdtor", "__ticppdtor" },
+ { "postblit", "__postblit" },
+ { "__xpostblit", "__xpostblit" },
+ { "__fieldPostblit", "__fieldPostblit" },
+ { "__aggrPostblit", "__aggrPostblit" },
+ { "classInvariant", "__invariant" },
+ { "unitTest", "__unitTest" },
+ { "require", "__require" },
+ { "ensure", "__ensure" },
+ { "capture", "__capture" },
+ { "this2", "__this" },
+ { "_init", "init" },
+ { "__sizeof", "sizeof" },
+ { "__xalignof", "alignof" },
+ { "_mangleof", "mangleof" },
+ { "stringof" },
+ { "_tupleof", "tupleof" },
+ { "length" },
+ { "remove" },
+ { "ptr" },
+ { "array" },
+ { "funcptr" },
+ { "dollar", "__dollar" },
+ { "ctfe", "__ctfe" },
+ { "offset" },
+ { "offsetof" },
+ { "ModuleInfo" },
+ { "ClassInfo" },
+ { "classinfo" },
+ { "typeinfo" },
+ { "outer" },
+ { "Exception" },
+ { "RTInfo" },
+ { "Throwable" },
+ { "Error" },
+ { "withSym", "__withSym" },
+ { "result", "__result" },
+ { "returnLabel", "__returnLabel" },
+ { "line" },
+ { "empty", "" },
+ { "p" },
+ { "q" },
+ { "__vptr" },
+ { "__monitor" },
+ { "gate", "__gate" },
+ { "__c_long" },
+ { "__c_ulong" },
+ { "__c_longlong" },
+ { "__c_ulonglong" },
+ { "__c_long_double" },
+ { "__c_wchar_t" },
+ { "__c_complex_float" },
+ { "__c_complex_double" },
+ { "__c_complex_real" },
+ { "cpp_type_info_ptr", "__cpp_type_info_ptr" },
+ { "_assert", "assert" },
+ { "_unittest", "unittest" },
+ { "_body", "body" },
+ { "printf" },
+ { "scanf" },
+
+ { "TypeInfo" },
+ { "TypeInfo_Class" },
+ { "TypeInfo_Interface" },
+ { "TypeInfo_Struct" },
+ { "TypeInfo_Enum" },
+ { "TypeInfo_Pointer" },
+ { "TypeInfo_Vector" },
+ { "TypeInfo_Array" },
+ { "TypeInfo_StaticArray" },
+ { "TypeInfo_AssociativeArray" },
+ { "TypeInfo_Function" },
+ { "TypeInfo_Delegate" },
+ { "TypeInfo_Tuple" },
+ { "TypeInfo_Const" },
+ { "TypeInfo_Invariant" },
+ { "TypeInfo_Shared" },
+ { "TypeInfo_Wild", "TypeInfo_Inout" },
+ { "elements" },
+ { "_arguments_typeinfo" },
+ { "_arguments" },
+ { "_argptr" },
+ { "destroy" },
+ { "xopEquals", "__xopEquals" },
+ { "xopCmp", "__xopCmp" },
+ { "xtoHash", "__xtoHash" },
+
+ { "LINE", "__LINE__" },
+ { "FILE", "__FILE__" },
+ { "MODULE", "__MODULE__" },
+ { "FUNCTION", "__FUNCTION__" },
+ { "PRETTY_FUNCTION", "__PRETTY_FUNCTION__" },
+ { "DATE", "__DATE__" },
+ { "TIME", "__TIME__" },
+ { "TIMESTAMP", "__TIMESTAMP__" },
+ { "VENDOR", "__VENDOR__" },
+ { "VERSIONX", "__VERSION__" },
+ { "EOFX", "__EOF__" },
+
+ { "nan" },
+ { "infinity" },
+ { "dig" },
+ { "epsilon" },
+ { "mant_dig" },
+ { "max_10_exp" },
+ { "max_exp" },
+ { "min_10_exp" },
+ { "min_exp" },
+ { "min_normal" },
+ { "re" },
+ { "im" },
+
+ { "C" },
+ { "D" },
+ { "Windows" },
+ { "System" },
+ { "Objective" },
+
+ { "exit" },
+ { "success" },
+ { "failure" },
+
+ { "keys" },
+ { "values" },
+ { "rehash" },
+
+ { "future", "__future" },
+ { "property" },
+ { "nogc" },
+ { "live" },
+ { "safe" },
+ { "trusted" },
+ { "system" },
+ { "disable" },
+
+ // For inline assembler
+ { "___out", "out" },
+ { "___in", "in" },
+ { "__int", "int" },
+ { "_dollar", "$" },
+ { "__LOCAL_SIZE" },
+
+ // For operator overloads
+ { "uadd", "opPos" },
+ { "neg", "opNeg" },
+ { "com", "opCom" },
+ { "add", "opAdd" },
+ { "add_r", "opAdd_r" },
+ { "sub", "opSub" },
+ { "sub_r", "opSub_r" },
+ { "mul", "opMul" },
+ { "mul_r", "opMul_r" },
+ { "div", "opDiv" },
+ { "div_r", "opDiv_r" },
+ { "mod", "opMod" },
+ { "mod_r", "opMod_r" },
+ { "eq", "opEquals" },
+ { "cmp", "opCmp" },
+ { "iand", "opAnd" },
+ { "iand_r", "opAnd_r" },
+ { "ior", "opOr" },
+ { "ior_r", "opOr_r" },
+ { "ixor", "opXor" },
+ { "ixor_r", "opXor_r" },
+ { "shl", "opShl" },
+ { "shl_r", "opShl_r" },
+ { "shr", "opShr" },
+ { "shr_r", "opShr_r" },
+ { "ushr", "opUShr" },
+ { "ushr_r", "opUShr_r" },
+ { "cat", "opCat" },
+ { "cat_r", "opCat_r" },
+ { "assign", "opAssign" },
+ { "addass", "opAddAssign" },
+ { "subass", "opSubAssign" },
+ { "mulass", "opMulAssign" },
+ { "divass", "opDivAssign" },
+ { "modass", "opModAssign" },
+ { "andass", "opAndAssign" },
+ { "orass", "opOrAssign" },
+ { "xorass", "opXorAssign" },
+ { "shlass", "opShlAssign" },
+ { "shrass", "opShrAssign" },
+ { "ushrass", "opUShrAssign" },
+ { "catass", "opCatAssign" },
+ { "postinc", "opPostInc" },
+ { "postdec", "opPostDec" },
+ { "index", "opIndex" },
+ { "indexass", "opIndexAssign" },
+ { "slice", "opSlice" },
+ { "sliceass", "opSliceAssign" },
+ { "call", "opCall" },
+ { "_cast", "opCast" },
+ { "opIn" },
+ { "opIn_r" },
+ { "opStar" },
+ { "opDot" },
+ { "opDispatch" },
+ { "opDollar" },
+ { "opUnary" },
+ { "opIndexUnary" },
+ { "opSliceUnary" },
+ { "opBinary" },
+ { "opBinaryRight" },
+ { "opOpAssign" },
+ { "opIndexOpAssign" },
+ { "opSliceOpAssign" },
+ { "pow", "opPow" },
+ { "pow_r", "opPow_r" },
+ { "powass", "opPowAssign" },
+
+ { "classNew", "new" },
+ { "classDelete", "delete" },
+
+ // For foreach
+ { "apply", "opApply" },
+ { "applyReverse", "opApplyReverse" },
+
+ // Ranges
+ { "Fempty", "empty" },
+ { "Ffront", "front" },
+ { "Fback", "back" },
+ { "FpopFront", "popFront" },
+ { "FpopBack", "popBack" },
+
+ // For internal functions
+ { "aaLen", "_aaLen" },
+ { "aaKeys", "_aaKeys" },
+ { "aaValues", "_aaValues" },
+ { "aaRehash", "_aaRehash" },
+ { "monitorenter", "_d_monitorenter" },
+ { "monitorexit", "_d_monitorexit" },
+ { "criticalenter", "_d_criticalenter2" },
+ { "criticalexit", "_d_criticalexit" },
+ { "__ArrayPostblit" },
+ { "__ArrayDtor" },
+ { "_d_delThrowable" },
+ { "_d_assert_fail" },
+ { "dup" },
+ { "_aaApply" },
+ { "_aaApply2" },
+
+ // For pragma's
+ { "Pinline", "inline" },
+ { "lib" },
+ { "linkerDirective" },
+ { "mangle" },
+ { "msg" },
+ { "startaddress" },
+ { "crt_constructor" },
+ { "crt_destructor" },
+
+ // For special functions
+ { "tohash", "toHash" },
+ { "tostring", "toString" },
+ { "getmembers", "getMembers" },
+
+ // Special functions
+ { "__alloca", "alloca" },
+ { "main" },
+ { "WinMain" },
+ { "DllMain" },
+ { "CMain", "_d_cmain" },
+ { "rt_init" },
+ { "__cmp" },
+ { "__equals"},
+ { "__switch"},
+ { "__switch_error"},
+ { "__ArrayCast"},
+ { "_d_HookTraceImpl" },
+ { "_d_arraysetlengthTImpl"},
+ { "_d_arraysetlengthT"},
+ { "_d_arraysetlengthTTrace"},
+
+ // varargs implementation
+ { "stdc" },
+ { "stdarg" },
+ { "va_start" },
+
+ // Builtin functions
+ { "std" },
+ { "core" },
+ { "etc" },
+ { "attribute" },
+ { "math" },
+ { "sin" },
+ { "cos" },
+ { "tan" },
+ { "_sqrt", "sqrt" },
+ { "_pow", "pow" },
+ { "atan2" },
+ { "rint" },
+ { "ldexp" },
+ { "rndtol" },
+ { "exp" },
+ { "expm1" },
+ { "exp2" },
+ { "yl2x" },
+ { "yl2xp1" },
+ { "log" },
+ { "log2" },
+ { "log10" },
+ { "round" },
+ { "floor" },
+ { "trunc" },
+ { "fmax" },
+ { "fmin" },
+ { "fma" },
+ { "isnan" },
+ { "isInfinity" },
+ { "isfinite" },
+ { "ceil" },
+ { "copysign" },
+ { "fabs" },
+ { "toPrec" },
+ { "simd" },
+ { "__prefetch"},
+ { "__simd_sto"},
+ { "__simd"},
+ { "__simd_ib"},
+ { "bitop" },
+ { "bsf" },
+ { "bsr" },
+ { "btc" },
+ { "btr" },
+ { "bts" },
+ { "bswap" },
+ { "volatile"},
+ { "volatileLoad"},
+ { "volatileStore"},
+ { "_popcnt"},
+ { "inp"},
+ { "inpl"},
+ { "inpw"},
+ { "outp"},
+ { "outpl"},
+ { "outpw"},
+
+ // Traits
+ { "isAbstractClass" },
+ { "isArithmetic" },
+ { "isAssociativeArray" },
+ { "isFinalClass" },
+ { "isTemplate" },
+ { "isPOD" },
+ { "isDeprecated" },
+ { "isDisabled" },
+ { "isFuture" },
+ { "isNested" },
+ { "isFloating" },
+ { "isIntegral" },
+ { "isScalar" },
+ { "isStaticArray" },
+ { "isUnsigned" },
+ { "isVirtualFunction" },
+ { "isVirtualMethod" },
+ { "isAbstractFunction" },
+ { "isFinalFunction" },
+ { "isOverrideFunction" },
+ { "isStaticFunction" },
+ { "isModule" },
+ { "isPackage" },
+ { "isRef" },
+ { "isOut" },
+ { "isLazy" },
+ { "hasMember" },
+ { "identifier" },
+ { "getProtection" },
+ { "getVisibility" },
+ { "parent" },
+ { "child" },
+ { "getMember" },
+ { "getOverloads" },
+ { "getVirtualFunctions" },
+ { "getVirtualMethods" },
+ { "classInstanceSize" },
+ { "allMembers" },
+ { "derivedMembers" },
+ { "isSame" },
+ { "compiles" },
+ { "getAliasThis" },
+ { "getAttributes" },
+ { "getFunctionAttributes" },
+ { "getFunctionVariadicStyle" },
+ { "getParameterStorageClasses" },
+ { "getLinkage" },
+ { "getUnitTests" },
+ { "getVirtualIndex" },
+ { "getPointerBitmap" },
+ { "getCppNamespaces" },
+ { "isReturnOnStack" },
+ { "isZeroInit" },
+ { "getTargetInfo" },
+ { "getLocation" },
+ { "hasPostblit" },
+ { "hasCopyConstructor" },
+ { "isCopyable" },
+ { "toType" },
+
+ // For C++ mangling
+ { "allocator" },
+ { "basic_string" },
+ { "basic_istream" },
+ { "basic_ostream" },
+ { "basic_iostream" },
+ { "char_traits" },
+
+ // Compiler recognized UDA's
+ { "udaGNUAbiTag", "gnuAbiTag" },
+ { "udaSelector", "selector" },
+ { "udaOptional", "optional"},
+
+ // C names, for undefined identifier error messages
+ { "NULL" },
+ { "TRUE" },
+ { "FALSE" },
+ { "unsigned" },
+ { "wchar_t" },
+
+ // for C compiler
+ { "__tag" },
+ { "dllimport" },
+ { "dllexport" },
+ { "vector_size" },
+ { "__func__" },
+ { "noreturn" },
+];
+
+
+/*
+ * Tuple of DMD source code identifier and symbol in the D executable.
+ *
+ * The first element of the tuple is the identifier to use in the DMD source
+ * code and the second element, if present, is the name to use in the D
+ * executable. If second element, `name`, is not present the identifier,
+ * `ident`, will be used instead
+ */
+struct Msgtable
+{
+ // The identifier to use in the DMD source.
+ string ident;
+
+ // The name to use in the D executable
+ private string name_;
+
+ /*
+ * Returns: the name to use in the D executable, `name_` if non-empty,
+ * otherwise `ident`
+ */
+ string name()
+ {
+ return name_ ? name_ : ident;
+ }
+}
+
+/*
+ * Iterates the given Msgtable array, passes each element to the given lambda
+ * and accumulates a string from each return value of calling the lambda.
+ * Appends a newline character after each call to the lambda.
+ */
+string generate(immutable(Msgtable)[] msgtable, string function(Msgtable) dg)
+{
+ string code;
+
+ foreach (i, m ; msgtable)
+ {
+ if (i != 0)
+ code ~= '\n';
+
+ code ~= dg(m);
+ }
+
+ return code;
+}
+
+// Used to generate the code for each identifier.
+string identifier(Msgtable m)
+{
+ return "Identifier " ~ m.ident ~ ";";
+}
+
+// Used to generate the code for each initializer.
+string initializer(Msgtable m)
+{
+ return m.ident ~ ` = Identifier.idPool("` ~ m.name ~ `");`;
+}
+
+// Used to generate the code for each deinitializer.
+string deinitializer(Msgtable m)
+{
+ return m.ident ~ " = Identifier.init;";
+}
diff --git a/gcc/d/dmd/id.h b/gcc/d/dmd/id.h
new file mode 100644
index 0000000..8066747
--- /dev/null
+++ b/gcc/d/dmd/id.h
@@ -0,0 +1,16 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 2017-2021 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/id.h
+ */
+
+#pragma once
+
+struct Id
+{
+ static void initialize();
+};
diff --git a/gcc/d/dmd/identifier.c b/gcc/d/dmd/identifier.c
deleted file mode 100644
index 197d288..0000000
--- a/gcc/d/dmd/identifier.c
+++ /dev/null
@@ -1,188 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/identifier.c
- */
-
-#include "root/dsystem.h"
-#include "root/root.h"
-
-#include "identifier.h"
-#include "mars.h"
-#include "id.h"
-#include "tokens.h"
-#include "utf.h"
-
-Identifier::Identifier(const char *string, size_t length, int value)
-{
- //printf("Identifier('%s', %d)\n", string, value);
- this->string = string;
- this->value = value;
- this->len = length;
-}
-
-Identifier::Identifier(const char *string)
-{
- //printf("Identifier('%s')\n", string);
- this->string = string;
- this->value = TOKidentifier;
- this->len = strlen(string);
-}
-
-Identifier *Identifier::create(const char *string)
-{
- return new Identifier(string);
-}
-
-bool Identifier::equals(RootObject *o)
-{
- return this == o || strncmp(string,o->toChars(),len+1) == 0;
-}
-
-int Identifier::compare(RootObject *o)
-{
- return strncmp(string, o->toChars(), len + 1);
-}
-
-const char *Identifier::toChars()
-{
- return string;
-}
-
-int Identifier::getValue() const
-{
- return value;
-}
-
-const char *Identifier::toHChars2()
-{
- const char *p = NULL;
-
- if (this == Id::ctor) p = "this";
- else if (this == Id::dtor) p = "~this";
- else if (this == Id::unitTest) p = "unittest";
- else if (this == Id::dollar) p = "$";
- else if (this == Id::withSym) p = "with";
- else if (this == Id::result) p = "result";
- else if (this == Id::returnLabel) p = "return";
- else
- { p = toChars();
- if (*p == '_')
- {
- if (strncmp(p, "_staticCtor", 11) == 0)
- p = "static this";
- else if (strncmp(p, "_staticDtor", 11) == 0)
- p = "static ~this";
- else if (strncmp(p, "__invariant", 11) == 0)
- p = "invariant";
- }
- }
-
- return p;
-}
-
-void Identifier::print()
-{
- fprintf(stderr, "%s",string);
-}
-
-int Identifier::dyncast() const
-{
- return DYNCAST_IDENTIFIER;
-}
-
-StringTable Identifier::stringtable;
-
-Identifier *Identifier::generateId(const char *prefix)
-{
- static size_t i;
-
- return generateId(prefix, ++i);
-}
-
-Identifier *Identifier::generateId(const char *prefix, size_t i)
-{ OutBuffer buf;
-
- buf.writestring(prefix);
- buf.printf("%llu", (ulonglong)i);
-
- char *id = buf.peekChars();
- return idPool(id);
-}
-
-/********************************************
- * Create an identifier in the string table.
- */
-
-Identifier *Identifier::idPool(const char *s, size_t len)
-{
- StringValue *sv = stringtable.update(s, len);
- Identifier *id = (Identifier *) sv->ptrvalue;
- if (!id)
- {
- id = new Identifier(sv->toDchars(), len, TOKidentifier);
- sv->ptrvalue = (char *)id;
- }
- return id;
-}
-
-Identifier *Identifier::idPool(const char *s, size_t len, int value)
-{
- StringValue *sv = stringtable.insert(s, len, NULL);
- assert(sv);
- Identifier *id = new Identifier(sv->toDchars(), len, value);
- sv->ptrvalue = (char *)id;
- return id;
-}
-
-/**********************************
- * Determine if string is a valid Identifier.
- * Returns:
- * 0 invalid
- */
-
-bool Identifier::isValidIdentifier(const char *p)
-{
- size_t len;
- size_t idx;
-
- if (!p || !*p)
- goto Linvalid;
-
- if (*p >= '0' && *p <= '9') // beware of isdigit() on signed chars
- goto Linvalid;
-
- len = strlen(p);
- idx = 0;
- while (p[idx])
- {
- dchar_t dc;
- const char *q = utf_decodeChar((const utf8_t *)p, len, &idx, &dc);
- if (q)
- goto Linvalid;
-
- if (!((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_'))
- goto Linvalid;
- }
- return true;
-
-Linvalid:
- return false;
-}
-
-Identifier *Identifier::lookup(const char *s, size_t len)
-{
- StringValue *sv = stringtable.lookup(s, len);
- if (!sv)
- return NULL;
- return (Identifier *)sv->ptrvalue;
-}
-
-void Identifier::initTable()
-{
- stringtable._init(28000);
-}
diff --git a/gcc/d/dmd/identifier.d b/gcc/d/dmd/identifier.d
new file mode 100644
index 0000000..43a1435
--- /dev/null
+++ b/gcc/d/dmd/identifier.d
@@ -0,0 +1,362 @@
+/**
+ * Defines an identifier, which is the name of a `Dsymbol`.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/identifier.d, _identifier.d)
+ * Documentation: https://dlang.org/phobos/dmd_identifier.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/identifier.d
+ */
+
+module dmd.identifier;
+
+import core.stdc.ctype;
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.globals;
+import dmd.id;
+import dmd.root.outbuffer;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.root.stringtable;
+import dmd.tokens;
+import dmd.utf;
+
+
+/***********************************************************
+ */
+extern (C++) final class Identifier : RootObject
+{
+ private const int value;
+
+ // Indicates if this is an identifier used for an anonymous symbol.
+ private const bool isAnonymous_ = false;
+
+ private const char[] name;
+
+nothrow:
+
+ /// Construct an identifier from the given name.
+ extern (D) this(const(char)* name)
+ {
+ //printf("Identifier('%s', %d)\n", name, value);
+ this(name.toDString(), TOK.identifier);
+ }
+
+ /**
+ Construct an identifier from the given name.
+
+ Params:
+ name = the identifier name. There must be `'\0'` at `name[length]`.
+ length = the length of `name`, excluding the terminating `'\0'`
+ value = Identifier value (e.g. `Id.unitTest`) or `TOK.identifier`
+ */
+ extern (D) this(const(char)* name, size_t length, int value)
+ in
+ {
+ assert(name[length] == '\0');
+ }
+ do
+ {
+ //printf("Identifier('%s', %d)\n", name, value);
+ this(name[0 .. length], value);
+ }
+
+ /// ditto
+ extern (D) this(const(char)[] name, int value)
+ {
+ //printf("Identifier('%.*s', %d)\n", cast(int)name.length, name.ptr, value);
+ this(name, value, false);
+ }
+
+ extern (D) private this(const(char)[] name, int value, bool isAnonymous)
+ {
+ //printf("Identifier('%.*s', %d, %d)\n", cast(int)name.length, name.ptr, value, isAnonymous);
+ this.name = name;
+ this.value = value;
+ isAnonymous_ = isAnonymous;
+ }
+
+ static Identifier create(const(char)* name)
+ {
+ return new Identifier(name);
+ }
+
+ override const(char)* toChars() const pure
+ {
+ return name.ptr;
+ }
+
+ extern (D) override const(char)[] toString() const pure
+ {
+ return name;
+ }
+
+ int getValue() const pure
+ {
+ return value;
+ }
+
+ bool isAnonymous() const pure @nogc @safe
+ {
+ return isAnonymous_;
+ }
+
+ const(char)* toHChars2() const
+ {
+ const(char)* p = null;
+ if (this == Id.ctor)
+ p = "this";
+ else if (this == Id.dtor)
+ p = "~this";
+ else if (this == Id.unitTest)
+ p = "unittest";
+ else if (this == Id.dollar)
+ p = "$";
+ else if (this == Id.withSym)
+ p = "with";
+ else if (this == Id.result)
+ p = "result";
+ else if (this == Id.returnLabel)
+ p = "return";
+ else
+ {
+ p = toChars();
+ if (*p == '_')
+ {
+ if (strncmp(p, "_staticCtor", 11) == 0)
+ p = "static this";
+ else if (strncmp(p, "_staticDtor", 11) == 0)
+ p = "static ~this";
+ else if (strncmp(p, "__invariant", 11) == 0)
+ p = "invariant";
+ }
+ }
+ return p;
+ }
+
+ override DYNCAST dyncast() const
+ {
+ return DYNCAST.identifier;
+ }
+
+ private extern (D) __gshared StringTable!Identifier stringtable;
+
+ /**
+ * Generates a new identifier.
+ *
+ * Params:
+ * prefix = this will be the prefix of the name of the identifier. For debugging
+ * purpose.
+ */
+ extern(D) static Identifier generateId(const(char)[] prefix)
+ {
+ return generateId(prefix, newSuffix, false);
+ }
+
+ /**
+ * Generates a new anonymous identifier.
+ *
+ * Params:
+ * name = this will be part of the name of the identifier. For debugging
+ * purpose.
+ */
+ extern(D) static Identifier generateAnonymousId(const(char)[] name)
+ {
+ return generateId("__anon" ~ name, newSuffix, true);
+ }
+
+ /**
+ * Generates a new identifier.
+ *
+ * Params:
+ * prefix = this will be the prefix of the name of the identifier. For debugging
+ * purpose.
+ * suffix = this will be the suffix of the name of the identifier. This is
+ * what makes the identifier unique
+ */
+ extern(D) static Identifier generateId(const(char)[] prefix, size_t suffix)
+ {
+ return generateId(prefix, suffix, false);
+ }
+
+ /// ditto
+ static Identifier generateId(const(char)* prefix, size_t length, size_t suffix)
+ {
+ return generateId(prefix[0 .. length], suffix);
+ }
+
+ // Generates a new, unique, suffix for an identifier.
+ extern (D) private static size_t newSuffix()
+ {
+ __gshared size_t i;
+ return ++i;
+ }
+
+ extern(D) private static Identifier generateId(const(char)[] prefix, size_t suffix, bool isAnonymous)
+ {
+ OutBuffer buf;
+ buf.write(prefix);
+ buf.print(suffix);
+ return idPool(buf[], isAnonymous);
+ }
+
+ /***************************************
+ * Generate deterministic named identifier based on a source location,
+ * such that the name is consistent across multiple compilations.
+ * A new unique name is generated. If the prefix+location is already in
+ * the stringtable, an extra suffix is added (starting the count at "_1").
+ *
+ * Params:
+ * prefix = first part of the identifier name.
+ * loc = source location to use in the identifier name.
+ * Returns:
+ * Identifier (inside Identifier.idPool) with deterministic name based
+ * on the source location.
+ */
+ extern (D) static Identifier generateIdWithLoc(string prefix, const ref Loc loc)
+ {
+ // generate `<prefix>_L<line>_C<col>`
+ OutBuffer idBuf;
+ idBuf.writestring(prefix);
+ idBuf.writestring("_L");
+ idBuf.print(loc.linnum);
+ idBuf.writestring("_C");
+ idBuf.print(loc.charnum);
+
+ /**
+ * Make sure the identifiers are unique per filename, i.e., per module/mixin
+ * (`path/to/foo.d` and `path/to/foo.d-mixin-<line>`). See issues
+ * https://issues.dlang.org/show_bug.cgi?id=16995
+ * https://issues.dlang.org/show_bug.cgi?id=18097
+ * https://issues.dlang.org/show_bug.cgi?id=18111
+ * https://issues.dlang.org/show_bug.cgi?id=18880
+ * https://issues.dlang.org/show_bug.cgi?id=18868
+ * https://issues.dlang.org/show_bug.cgi?id=19058
+ */
+ static struct Key { Loc loc; string prefix; }
+ __gshared uint[Key] counters;
+
+ static if (__traits(compiles, counters.update(Key.init, () => 0u, (ref uint a) => 0u)))
+ {
+ // 2.082+
+ counters.update(Key(loc, prefix),
+ () => 1u, // insertion
+ (ref uint counter) // update
+ {
+ idBuf.writestring("_");
+ idBuf.print(counter);
+ return counter + 1;
+ }
+ );
+ }
+ else
+ {
+ const key = Key(loc, prefix);
+ if (auto pCounter = key in counters)
+ {
+ idBuf.writestring("_");
+ idBuf.print((*pCounter)++);
+ }
+ else
+ counters[key] = 1;
+ }
+
+ return idPool(idBuf[]);
+ }
+
+ /********************************************
+ * Create an identifier in the string table.
+ */
+ static Identifier idPool(const(char)* s, uint len)
+ {
+ return idPool(s[0 .. len]);
+ }
+
+ extern (D) static Identifier idPool(const(char)[] s)
+ {
+ return idPool(s, false);
+ }
+
+ extern (D) private static Identifier idPool(const(char)[] s, bool isAnonymous)
+ {
+ auto sv = stringtable.update(s);
+ auto id = sv.value;
+ if (!id)
+ {
+ id = new Identifier(sv.toString(), TOK.identifier, isAnonymous);
+ sv.value = id;
+ }
+ return id;
+ }
+
+ extern (D) static Identifier idPool(const(char)* s, size_t len, int value)
+ {
+ return idPool(s[0 .. len], value);
+ }
+
+ extern (D) static Identifier idPool(const(char)[] s, int value)
+ {
+ auto sv = stringtable.insert(s, null);
+ assert(sv);
+ auto id = new Identifier(sv.toString(), value);
+ sv.value = id;
+ return id;
+ }
+
+ /**********************************
+ * Determine if string is a valid Identifier.
+ * Params:
+ * str = string to check
+ * Returns:
+ * false for invalid
+ */
+ static bool isValidIdentifier(const(char)* str)
+ {
+ return str && isValidIdentifier(str.toDString);
+ }
+
+ /**********************************
+ * ditto
+ */
+ extern (D) static bool isValidIdentifier(const(char)[] str)
+ {
+ if (str.length == 0 ||
+ (str[0] >= '0' && str[0] <= '9')) // beware of isdigit() on signed chars
+ {
+ return false;
+ }
+
+ size_t idx = 0;
+ while (idx < str.length)
+ {
+ dchar dc;
+ const s = utf_decodeChar(str, idx, dc);
+ if (s ||
+ !((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_'))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ extern (D) static Identifier lookup(const(char)* s, size_t len)
+ {
+ return lookup(s[0 .. len]);
+ }
+
+ extern (D) static Identifier lookup(const(char)[] s)
+ {
+ auto sv = stringtable.lookup(s);
+ if (!sv)
+ return null;
+ return sv.value;
+ }
+
+ extern (D) static void initTable()
+ {
+ stringtable._init(28_000);
+ }
+}
diff --git a/gcc/d/dmd/identifier.h b/gcc/d/dmd/identifier.h
index 278ce9b..790d5a0 100644
--- a/gcc/d/dmd/identifier.h
+++ b/gcc/d/dmd/identifier.h
@@ -10,40 +10,32 @@
#pragma once
-#include "root/root.h"
-#include "root/stringtable.h"
+#include "root/dcompat.h"
+#include "root/object.h"
class Identifier : public RootObject
{
private:
int value;
- const char *string;
- size_t len;
+ bool isAnonymous_;
+ DString string;
public:
- Identifier(const char *string, size_t length, int value);
- Identifier(const char *string);
static Identifier* create(const char *string);
- bool equals(RootObject *o);
- int compare(RootObject *o);
- void print();
- const char *toChars();
+ bool equals(const RootObject *o) const;
+ const char *toChars() const;
int getValue() const;
- const char *toHChars2();
- int dyncast() const;
+ bool isAnonymous() const;
+ const char *toHChars2() const;
+ DYNCAST dyncast() const;
- static StringTable stringtable;
- static Identifier *generateId(const char *prefix);
- static Identifier *generateId(const char *prefix, size_t i);
- static Identifier *idPool(const char *s, size_t len);
- static Identifier *idPool(const char *s, size_t len, int value);
+ static Identifier *generateId(const char *prefix, size_t length, size_t suffix);
+ static Identifier *idPool(const char *s, unsigned len);
static inline Identifier *idPool(const char *s)
{
- return idPool(s, strlen(s));
+ return idPool(s, static_cast<unsigned>(strlen(s)));
}
static bool isValidIdentifier(const char *p);
- static Identifier *lookup(const char *s, size_t len);
- static void initTable();
};
diff --git a/gcc/d/dmd/idgen.c b/gcc/d/dmd/idgen.c
deleted file mode 100644
index 0740653..0000000
--- a/gcc/d/dmd/idgen.c
+++ /dev/null
@@ -1,560 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/idgen.c
- */
-
-// Program to generate string files in d data structures.
-// Saves much tedious typing, and eliminates typo problems.
-// Generates:
-// id.h
-// id.c
-
-#include "root/dsystem.h"
-
-struct Msgtable
-{
- const char* ident; // name to use in DMD source
- const char* name; // name in D executable
-};
-
-Msgtable msgtable[] =
-{
- { "IUnknown", NULL },
- { "Object", NULL },
- { "object", NULL },
- { "string", NULL },
- { "wstring", NULL },
- { "dstring", NULL },
- { "max", NULL },
- { "min", NULL },
- { "This", "this" },
- { "_super", "super" },
- { "ctor", "__ctor" },
- { "dtor", "__dtor" },
- { "__xdtor", "__xdtor" },
- { "__fieldDtor", "__fieldDtor" },
- { "__aggrDtor", "__aggrDtor" },
- { "postblit", "__postblit" },
- { "__xpostblit", "__xpostblit" },
- { "__fieldPostblit", "__fieldPostblit" },
- { "__aggrPostblit", "__aggrPostblit" },
- { "classInvariant", "__invariant" },
- { "unitTest", "__unitTest" },
- { "require", "__require" },
- { "ensure", "__ensure" },
- { "_init", "init" },
- { "__sizeof", "sizeof" },
- { "__xalignof", "alignof" },
- { "_mangleof", "mangleof" },
- { "stringof", NULL },
- { "_tupleof", "tupleof" },
- { "length", NULL },
- { "remove", NULL },
- { "ptr", NULL },
- { "array", NULL },
- { "funcptr", NULL },
- { "dollar", "__dollar" },
- { "ctfe", "__ctfe" },
- { "offset", NULL },
- { "offsetof", NULL },
- { "ModuleInfo", NULL },
- { "ClassInfo", NULL },
- { "classinfo", NULL },
- { "typeinfo", NULL },
- { "outer", NULL },
- { "Exception", NULL },
- { "RTInfo", NULL },
- { "Throwable", NULL },
- { "Error", NULL },
- { "withSym", "__withSym" },
- { "result", "__result" },
- { "returnLabel", "__returnLabel" },
- { "line", NULL },
- { "empty", "" },
- { "p", NULL },
- { "q", NULL },
- { "__vptr", NULL },
- { "__monitor", NULL },
- { "gate", "__gate" },
- { "__c_long", NULL },
- { "__c_ulong", NULL },
- { "__c_longlong", NULL },
- { "__c_ulonglong", NULL },
- { "__c_long_double", NULL },
- { "__c_wchar_t", NULL },
- { "__c_complex_float", NULL },
- { "__c_complex_double", NULL },
- { "__c_complex_real", NULL },
- { "cpp_type_info_ptr", "__cpp_type_info_ptr" },
- { "_assert", "assert" },
- { "_unittest", "unittest" },
- { "_body", "body" },
- { "printf", NULL },
- { "scanf", NULL },
-
- { "TypeInfo", NULL },
- { "TypeInfo_Class", NULL },
- { "TypeInfo_Interface", NULL },
- { "TypeInfo_Struct", NULL },
- { "TypeInfo_Enum", NULL },
- { "TypeInfo_Pointer", NULL },
- { "TypeInfo_Vector", NULL },
- { "TypeInfo_Array", NULL },
- { "TypeInfo_StaticArray", NULL },
- { "TypeInfo_AssociativeArray", NULL },
- { "TypeInfo_Function", NULL },
- { "TypeInfo_Delegate", NULL },
- { "TypeInfo_Tuple", NULL },
- { "TypeInfo_Const", NULL },
- { "TypeInfo_Invariant", NULL },
- { "TypeInfo_Shared", NULL },
- { "TypeInfo_Wild", "TypeInfo_Inout" },
- { "elements", NULL },
- { "_arguments_typeinfo", NULL },
- { "_arguments", NULL },
- { "_argptr", NULL },
- { "destroy", NULL },
- { "xopEquals", "__xopEquals" },
- { "xopCmp", "__xopCmp" },
- { "xtoHash", "__xtoHash" },
-
- { "LINE", "__LINE__" },
- { "FILE", "__FILE__" },
- { "MODULE", "__MODULE__" },
- { "FUNCTION", "__FUNCTION__" },
- { "PRETTY_FUNCTION", "__PRETTY_FUNCTION__" },
- { "DATE", "__DATE__" },
- { "TIME", "__TIME__" },
- { "TIMESTAMP", "__TIMESTAMP__" },
- { "VENDOR", "__VENDOR__" },
- { "VERSIONX", "__VERSION__" },
- { "EOFX", "__EOF__" },
-
- { "nan", NULL },
- { "infinity", NULL },
- { "dig", NULL },
- { "epsilon", NULL },
- { "mant_dig", NULL },
- { "max_10_exp", NULL },
- { "max_exp", NULL },
- { "min_10_exp", NULL },
- { "min_exp", NULL },
- { "min_normal", NULL },
- { "re", NULL },
- { "im", NULL },
-
- { "C", NULL },
- { "D", NULL },
- { "Windows", NULL },
- { "System", NULL },
- { "Objective", NULL },
-
- { "exit", NULL },
- { "success", NULL },
- { "failure", NULL },
-
- { "keys", NULL },
- { "values", NULL },
- { "rehash", NULL },
-
- { "future", "__future" },
- { "property", NULL },
- { "nogc", NULL },
- { "safe", NULL },
- { "trusted", NULL },
- { "system", NULL },
- { "disable", NULL },
-
- // For inline assembler
- { "___out", "out" },
- { "___in", "in" },
- { "__int", "int" },
- { "_dollar", "$" },
- { "__LOCAL_SIZE", NULL },
-
- // For operator overloads
- { "uadd", "opPos" },
- { "neg", "opNeg" },
- { "com", "opCom" },
- { "add", "opAdd" },
- { "add_r", "opAdd_r" },
- { "sub", "opSub" },
- { "sub_r", "opSub_r" },
- { "mul", "opMul" },
- { "mul_r", "opMul_r" },
- { "div", "opDiv" },
- { "div_r", "opDiv_r" },
- { "mod", "opMod" },
- { "mod_r", "opMod_r" },
- { "eq", "opEquals" },
- { "cmp", "opCmp" },
- { "iand", "opAnd" },
- { "iand_r", "opAnd_r" },
- { "ior", "opOr" },
- { "ior_r", "opOr_r" },
- { "ixor", "opXor" },
- { "ixor_r", "opXor_r" },
- { "shl", "opShl" },
- { "shl_r", "opShl_r" },
- { "shr", "opShr" },
- { "shr_r", "opShr_r" },
- { "ushr", "opUShr" },
- { "ushr_r", "opUShr_r" },
- { "cat", "opCat" },
- { "cat_r", "opCat_r" },
- { "assign", "opAssign" },
- { "addass", "opAddAssign" },
- { "subass", "opSubAssign" },
- { "mulass", "opMulAssign" },
- { "divass", "opDivAssign" },
- { "modass", "opModAssign" },
- { "andass", "opAndAssign" },
- { "orass", "opOrAssign" },
- { "xorass", "opXorAssign" },
- { "shlass", "opShlAssign" },
- { "shrass", "opShrAssign" },
- { "ushrass", "opUShrAssign" },
- { "catass", "opCatAssign" },
- { "postinc", "opPostInc" },
- { "postdec", "opPostDec" },
- { "index", "opIndex" },
- { "indexass", "opIndexAssign" },
- { "slice", "opSlice" },
- { "sliceass", "opSliceAssign" },
- { "call", "opCall" },
- { "_cast", "opCast" },
- { "opIn", NULL },
- { "opIn_r", NULL },
- { "opStar", NULL },
- { "opDot", NULL },
- { "opDispatch", NULL },
- { "opDollar", NULL },
- { "opUnary", NULL },
- { "opIndexUnary", NULL },
- { "opSliceUnary", NULL },
- { "opBinary", NULL },
- { "opBinaryRight", NULL },
- { "opOpAssign", NULL },
- { "opIndexOpAssign", NULL },
- { "opSliceOpAssign", NULL },
- { "pow", "opPow" },
- { "pow_r", "opPow_r" },
- { "powass", "opPowAssign" },
-
- { "classNew", "new" },
- { "classDelete", "delete" },
-
- // For foreach
- { "apply", "opApply" },
- { "applyReverse", "opApplyReverse" },
-
- // Ranges
- { "Fempty", "empty" },
- { "Ffront", "front" },
- { "Fback", "back" },
- { "FpopFront", "popFront" },
- { "FpopBack", "popBack" },
-
- // For internal functions
- { "aaLen", "_aaLen" },
- { "aaKeys", "_aaKeys" },
- { "aaValues", "_aaValues" },
- { "aaRehash", "_aaRehash" },
- { "monitorenter", "_d_monitorenter" },
- { "monitorexit", "_d_monitorexit" },
- { "criticalenter", "_d_criticalenter2" },
- { "criticalexit", "_d_criticalexit" },
- { "__ArrayEq", NULL },
- { "__ArrayPostblit", NULL },
- { "__ArrayDtor", NULL },
- { "dup", NULL },
- { "_aaApply", NULL },
- { "_aaApply2", NULL },
-
- // For pragma's
- { "Pinline", "inline" },
- { "lib", NULL },
- { "mangle", NULL },
- { "msg", NULL },
- { "startaddress", NULL },
-
- // For special functions
- { "tohash", "toHash" },
- { "tostring", "toString" },
- { "getmembers", "getMembers" },
-
- // Special functions
- { "__alloca", "alloca" },
- { "main", NULL },
- { "WinMain", NULL },
- { "DllMain", NULL },
- { "tls_get_addr", "___tls_get_addr" },
- { "entrypoint", "__entrypoint" },
-
- // varargs implementation
- { "stdc", NULL },
- { "stdarg", NULL },
- { "va_start", NULL },
-
- // Builtin functions
- { "std", NULL },
- { "core", NULL },
- { "attribute", NULL },
- { "math", NULL },
- { "sin", NULL },
- { "cos", NULL },
- { "tan", NULL },
- { "_sqrt", "sqrt" },
- { "_pow", "pow" },
- { "atan2", NULL },
- { "rint", NULL },
- { "ldexp", NULL },
- { "rndtol", NULL },
- { "exp", NULL },
- { "expm1", NULL },
- { "exp2", NULL },
- { "yl2x", NULL },
- { "yl2xp1", NULL },
- { "log", NULL },
- { "log2", NULL },
- { "log10", NULL },
- { "round", NULL },
- { "floor", NULL },
- { "trunc", NULL },
- { "fmax", NULL },
- { "fmin", NULL },
- { "fma", NULL },
- { "isnan", NULL },
- { "isInfinity", NULL },
- { "isfinite", NULL },
- { "ceil", NULL },
- { "copysign", NULL },
- { "fabs", NULL },
- { "toPrec", NULL },
- { "simd", NULL },
- { "__prefetch", NULL },
- { "__simd_sto", NULL },
- { "__simd", NULL },
- { "__simd_ib", NULL },
- { "bitop", NULL },
- { "bsf", NULL },
- { "bsr", NULL },
- { "btc", NULL },
- { "btr", NULL },
- { "bts", NULL },
- { "bswap", NULL },
- { "_volatile", "volatile" },
- { "volatileLoad", NULL },
- { "volatileStore", NULL },
- { "_popcnt", NULL },
- { "inp", NULL },
- { "inpl", NULL },
- { "inpw", NULL },
- { "outp", NULL },
- { "outpl", NULL },
- { "outpw", NULL },
-
- // Traits
- { "isAbstractClass", NULL },
- { "isArithmetic", NULL },
- { "isAssociativeArray", NULL },
- { "isFinalClass", NULL },
- { "isTemplate", NULL },
- { "isPOD", NULL },
- { "isDeprecated", NULL },
- { "isDisabled", NULL },
- { "isFuture" , NULL },
- { "isNested", NULL },
- { "isFloating", NULL },
- { "isIntegral", NULL },
- { "isScalar", NULL },
- { "isStaticArray", NULL },
- { "isUnsigned", NULL },
- { "isVirtualFunction", NULL },
- { "isVirtualMethod", NULL },
- { "isAbstractFunction", NULL },
- { "isFinalFunction", NULL },
- { "isOverrideFunction", NULL },
- { "isStaticFunction", NULL },
- { "isModule", NULL },
- { "isPackage", NULL },
- { "isRef", NULL },
- { "isOut", NULL },
- { "isLazy", NULL },
- { "hasMember", NULL },
- { "identifier", NULL },
- { "getProtection", NULL },
- { "getVisibility", NULL },
- { "parent", NULL },
- { "child", NULL },
- { "getMember", NULL },
- { "getOverloads", NULL },
- { "getVirtualFunctions", NULL },
- { "getVirtualMethods", NULL },
- { "classInstanceSize", NULL },
- { "allMembers", NULL },
- { "derivedMembers", NULL },
- { "isSame", NULL },
- { "compiles", NULL },
- { "getAliasThis", NULL },
- { "getAttributes", NULL },
- { "getFunctionAttributes", NULL },
- { "getFunctionVariadicStyle", NULL },
- { "getParameterStorageClasses", NULL },
- { "getLinkage", NULL },
- { "getUnitTests", NULL },
- { "getVirtualIndex", NULL },
- { "getPointerBitmap", NULL },
- { "isReturnOnStack", NULL },
- { "isZeroInit", NULL },
- { "getTargetInfo", NULL },
- { "getLocation", NULL },
- { "hasPostblit", NULL },
- { "isCopyable", NULL },
- { "toType", NULL },
-
- // For C++ mangling
- { "allocator", NULL },
- { "basic_string", NULL },
- { "basic_istream", NULL },
- { "basic_ostream", NULL },
- { "basic_iostream", NULL },
- { "char_traits", NULL },
-
- // Compiler recognized UDA's
- { "udaSelector", "selector" },
-
- // C names, for undefined identifier error messages
- { "C_NULL", "NULL" },
- { "C_TRUE", "TRUE" },
- { "C_FALSE", "FALSE" },
- { "C_unsigned", "unsigned" },
- { "C_wchar_t", "wchar_t" },
-};
-
-
-int main()
-{
- {
- FILE *fp = fopen("id.h","wb");
- if (!fp)
- {
- printf("can't open id.h\n");
- exit(EXIT_FAILURE);
- }
-
- fprintf(fp, "// File generated by idgen.c\n");
- fprintf(fp, "#ifndef DMD_ID_H\n");
- fprintf(fp, "#define DMD_ID_H 1\n");
- fprintf(fp, "class Identifier;\n");
- fprintf(fp, "struct Id\n");
- fprintf(fp, "{\n");
-
- for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
- {
- const char *id = msgtable[i].ident;
- fprintf(fp," static Identifier *%s;\n", id);
- }
-
- fprintf(fp, " static void initialize();\n");
- fprintf(fp, "};\n");
- fprintf(fp, "#endif\n");
-
- fclose(fp);
- }
-
- {
- FILE *fp = fopen("id.c","wb");
- if (!fp)
- {
- printf("can't open id.c\n");
- exit(EXIT_FAILURE);
- }
-
- fprintf(fp, "// File generated by idgen.c\n");
- fprintf(fp, "#include \"identifier.h\"\n");
- fprintf(fp, "#include \"id.h\"\n");
- fprintf(fp, "#include \"mars.h\"\n");
-
- for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
- {
- const char *id = msgtable[i].ident;
- const char *p = msgtable[i].name;
-
- if (!p)
- p = id;
- fprintf(fp,"Identifier *Id::%s;\n", id);
- }
-
- fprintf(fp, "void Id::initialize()\n");
- fprintf(fp, "{\n");
-
- for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
- {
- const char *id = msgtable[i].ident;
- const char *p = msgtable[i].name;
-
- if (!p)
- p = id;
- fprintf(fp," %s = Identifier::idPool(\"%s\");\n", id, p);
- }
-
- fprintf(fp, "}\n");
-
- fclose(fp);
- }
-
- {
- FILE *fp = fopen("id.d","wb");
- if (!fp)
- {
- printf("can't open id.d\n");
- exit(EXIT_FAILURE);
- }
-
- fprintf(fp, "// File generated by idgen.c\n");
- fprintf(fp, "\n");
- fprintf(fp, "module ddmd.id;\n");
- fprintf(fp, "\n");
- fprintf(fp, "import ddmd.identifier, ddmd.tokens;\n");
- fprintf(fp, "\n");
- fprintf(fp, "struct Id\n");
- fprintf(fp, "{\n");
-
- for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
- {
- const char *id = msgtable[i].ident;
- const char *p = msgtable[i].name;
-
- if (!p)
- p = id;
- fprintf(fp, " extern (C++) static __gshared Identifier %s;\n", id);
- }
-
- fprintf(fp, "\n");
- fprintf(fp, " extern (C++) static void initialize()\n");
- fprintf(fp, " {\n");
-
- for (unsigned i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++)
- {
- const char *id = msgtable[i].ident;
- const char *p = msgtable[i].name;
-
- if (!p)
- p = id;
- fprintf(fp," %s = Identifier.idPool(\"%s\");\n", id, p);
- }
-
- fprintf(fp, " }\n");
- fprintf(fp, "}\n");
-
- fclose(fp);
- }
-
- return EXIT_SUCCESS;
-}
diff --git a/gcc/d/dmd/impcnvgen.c b/gcc/d/dmd/impcnvgen.c
deleted file mode 100644
index d7c27ea..0000000
--- a/gcc/d/dmd/impcnvgen.c
+++ /dev/null
@@ -1,598 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/impcnvgen.c
- */
-
-#include "root/dsystem.h"
-
-#include "mtype.h"
-
-TY impcnvResultTab[TMAX][TMAX];
-TY impcnvType1Tab[TMAX][TMAX];
-TY impcnvType2Tab[TMAX][TMAX];
-int impcnvWarnTab[TMAX][TMAX];
-
-int integral_promotion(int t)
-{
- switch (t)
- {
- case Tchar:
- case Twchar:
- case Tbool:
- case Tint8:
- case Tuns8:
- case Tint16:
- case Tuns16: return Tint32;
- case Tdchar: return Tuns32;
- default: return t;
- }
-}
-
-void init()
-{ int i, j;
-
- // Set conversion tables
- for (i = 0; i < TMAX; i++)
- for (j = 0; j < TMAX; j++)
- { impcnvResultTab[i][j] = Terror;
- impcnvType1Tab[i][j] = Terror;
- impcnvType2Tab[i][j] = Terror;
- impcnvWarnTab[i][j] = 0;
- }
-
-#define X(t1,t2, nt1,nt2, rt) \
- impcnvResultTab[t1][t2] = rt; \
- impcnvType1Tab[t1][t2] = nt1; \
- impcnvType2Tab[t1][t2] = nt2;
-
-
- /* ======================= */
-
- X(Tbool,Tbool, Tbool,Tbool, Tbool)
- X(Tbool,Tint8, Tint32,Tint32, Tint32)
- X(Tbool,Tuns8, Tint32,Tint32, Tint32)
- X(Tbool,Tint16, Tint32,Tint32, Tint32)
- X(Tbool,Tuns16, Tint32,Tint32, Tint32)
- X(Tbool,Tint32, Tint32,Tint32, Tint32)
- X(Tbool,Tuns32, Tuns32,Tuns32, Tuns32)
- X(Tbool,Tint64, Tint64,Tint64, Tint64)
- X(Tbool,Tuns64, Tuns64,Tuns64, Tuns64)
- X(Tbool,Tint128, Tint128,Tint128, Tint128)
- X(Tbool,Tuns128, Tuns128,Tuns128, Tuns128)
-
- X(Tbool,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tbool,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tbool,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
- X(Tbool,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tbool,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tbool,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
- X(Tbool,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tbool,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tbool,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tint8,Tint8, Tint32,Tint32, Tint32)
- X(Tint8,Tuns8, Tint32,Tint32, Tint32)
- X(Tint8,Tint16, Tint32,Tint32, Tint32)
- X(Tint8,Tuns16, Tint32,Tint32, Tint32)
- X(Tint8,Tint32, Tint32,Tint32, Tint32)
- X(Tint8,Tuns32, Tuns32,Tuns32, Tuns32)
- X(Tint8,Tint64, Tint64,Tint64, Tint64)
- X(Tint8,Tuns64, Tuns64,Tuns64, Tuns64)
- X(Tint8,Tint128, Tint128,Tint128, Tint128)
- X(Tint8,Tuns128, Tuns128,Tuns128, Tuns128)
-
- X(Tint8,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tint8,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tint8,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
- X(Tint8,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tint8,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tint8,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
- X(Tint8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tint8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tint8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tuns8,Tuns8, Tint32,Tint32, Tint32)
- X(Tuns8,Tint16, Tint32,Tint32, Tint32)
- X(Tuns8,Tuns16, Tint32,Tint32, Tint32)
- X(Tuns8,Tint32, Tint32,Tint32, Tint32)
- X(Tuns8,Tuns32, Tuns32,Tuns32, Tuns32)
- X(Tuns8,Tint64, Tint64,Tint64, Tint64)
- X(Tuns8,Tuns64, Tuns64,Tuns64, Tuns64)
- X(Tuns8,Tint128, Tint128,Tint128, Tint128)
- X(Tuns8,Tuns128, Tuns128,Tuns128, Tuns128)
-
- X(Tuns8,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tuns8,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tuns8,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
- X(Tuns8,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tuns8,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tuns8,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
- X(Tuns8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tuns8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tuns8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tint16,Tint16, Tint32,Tint32, Tint32)
- X(Tint16,Tuns16, Tint32,Tint32, Tint32)
- X(Tint16,Tint32, Tint32,Tint32, Tint32)
- X(Tint16,Tuns32, Tuns32,Tuns32, Tuns32)
- X(Tint16,Tint64, Tint64,Tint64, Tint64)
- X(Tint16,Tuns64, Tuns64,Tuns64, Tuns64)
- X(Tint16,Tint128, Tint128,Tint128, Tint128)
- X(Tint16,Tuns128, Tuns128,Tuns128, Tuns128)
-
- X(Tint16,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tint16,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tint16,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
- X(Tint16,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tint16,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tint16,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
- X(Tint16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tint16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tint16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tuns16,Tuns16, Tint32,Tint32, Tint32)
- X(Tuns16,Tint32, Tint32,Tint32, Tint32)
- X(Tuns16,Tuns32, Tuns32,Tuns32, Tuns32)
- X(Tuns16,Tint64, Tint64,Tint64, Tint64)
- X(Tuns16,Tuns64, Tuns64,Tuns64, Tuns64)
- X(Tuns16,Tint128, Tint128,Tint128, Tint128)
- X(Tuns16,Tuns128, Tuns128,Tuns128, Tuns128)
-
- X(Tuns16,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tuns16,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tuns16,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
- X(Tuns16,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tuns16,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tuns16,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
- X(Tuns16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tuns16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tuns16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tint32,Tint32, Tint32,Tint32, Tint32)
- X(Tint32,Tuns32, Tuns32,Tuns32, Tuns32)
- X(Tint32,Tint64, Tint64,Tint64, Tint64)
- X(Tint32,Tuns64, Tuns64,Tuns64, Tuns64)
- X(Tint32,Tint128, Tint128,Tint128, Tint128)
- X(Tint32,Tuns128, Tuns128,Tuns128, Tuns128)
-
- X(Tint32,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tint32,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tint32,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
- X(Tint32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tint32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tint32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
- X(Tint32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tint32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tint32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tuns32,Tuns32, Tuns32,Tuns32, Tuns32)
- X(Tuns32,Tint64, Tint64,Tint64, Tint64)
- X(Tuns32,Tuns64, Tuns64,Tuns64, Tuns64)
- X(Tuns32,Tint128, Tint128,Tint128, Tint128)
- X(Tuns32,Tuns128, Tuns128,Tuns128, Tuns128)
-
- X(Tuns32,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tuns32,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tuns32,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
- X(Tuns32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tuns32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tuns32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
- X(Tuns32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tuns32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tuns32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tint64,Tint64, Tint64,Tint64, Tint64)
- X(Tint64,Tuns64, Tuns64,Tuns64, Tuns64)
- X(Tint64,Tint128, Tint128,Tint128, Tint128)
- X(Tint64,Tuns128, Tuns128,Tuns128, Tuns128)
-
- X(Tint64,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tint64,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tint64,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
- X(Tint64,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tint64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tint64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
- X(Tint64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tint64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tint64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tuns64,Tuns64, Tuns64,Tuns64, Tuns64)
- X(Tuns64,Tint128, Tint128,Tint128, Tint128)
- X(Tuns64,Tuns128, Tuns128,Tuns128, Tuns128)
-
- X(Tuns64,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tuns64,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tuns64,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
- X(Tuns64,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tuns64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tuns64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
- X(Tuns64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tuns64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tuns64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tint128,Tint128, Tint128,Tint128, Tint128)
- X(Tint128,Tuns128, Tuns128,Tuns128, Tuns128)
-
- X(Tint128,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tint128,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tint128,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
- X(Tint128,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tint128,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tint128,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
- X(Tint128,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tint128,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tint128,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tuns128,Tuns128, Tuns128,Tuns128, Tuns128)
-
- X(Tuns128,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tuns128,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tuns128,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
- X(Tuns128,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tuns128,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tuns128,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
- X(Tuns128,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tuns128,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tuns128,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tfloat32,Tfloat32, Tfloat32,Tfloat32, Tfloat32)
- X(Tfloat32,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tfloat32,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
-
- X(Tfloat32,Timaginary32, Tfloat32,Timaginary32, Tfloat32)
- X(Tfloat32,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tfloat32,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
-
- X(Tfloat32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32)
- X(Tfloat32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tfloat32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tfloat64,Tfloat64, Tfloat64,Tfloat64, Tfloat64)
- X(Tfloat64,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
-
- X(Tfloat64,Timaginary32, Tfloat64,Timaginary64, Tfloat64)
- X(Tfloat64,Timaginary64, Tfloat64,Timaginary64, Tfloat64)
- X(Tfloat64,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
-
- X(Tfloat64,Tcomplex32, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tfloat64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64)
- X(Tfloat64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tfloat80,Tfloat80, Tfloat80,Tfloat80, Tfloat80)
-
- X(Tfloat80,Timaginary32, Tfloat80,Timaginary80, Tfloat80)
- X(Tfloat80,Timaginary64, Tfloat80,Timaginary80, Tfloat80)
- X(Tfloat80,Timaginary80, Tfloat80,Timaginary80, Tfloat80)
-
- X(Tfloat80,Tcomplex32, Tfloat80,Tcomplex80, Tcomplex80)
- X(Tfloat80,Tcomplex64, Tfloat80,Tcomplex80, Tcomplex80)
- X(Tfloat80,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Timaginary32,Timaginary32, Timaginary32,Timaginary32, Timaginary32)
- X(Timaginary32,Timaginary64, Timaginary64,Timaginary64, Timaginary64)
- X(Timaginary32,Timaginary80, Timaginary80,Timaginary80, Timaginary80)
-
- X(Timaginary32,Tcomplex32, Timaginary32,Tcomplex32, Tcomplex32)
- X(Timaginary32,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64)
- X(Timaginary32,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Timaginary64,Timaginary64, Timaginary64,Timaginary64, Timaginary64)
- X(Timaginary64,Timaginary80, Timaginary80,Timaginary80, Timaginary80)
-
- X(Timaginary64,Tcomplex32, Timaginary64,Tcomplex64, Tcomplex64)
- X(Timaginary64,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64)
- X(Timaginary64,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Timaginary80,Timaginary80, Timaginary80,Timaginary80, Timaginary80)
-
- X(Timaginary80,Tcomplex32, Timaginary80,Tcomplex80, Tcomplex80)
- X(Timaginary80,Tcomplex64, Timaginary80,Tcomplex80, Tcomplex80)
- X(Timaginary80,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tcomplex32,Tcomplex32, Tcomplex32,Tcomplex32, Tcomplex32)
- X(Tcomplex32,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64)
- X(Tcomplex32,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tcomplex64,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64)
- X(Tcomplex64,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80)
-
- /* ======================= */
-
- X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80)
-
-#undef X
-
-#define Y(t1,t2) impcnvWarnTab[t1][t2] = 1;
-
- Y(Tuns8, Tint8)
- Y(Tint16, Tint8)
- Y(Tuns16, Tint8)
- Y(Tint32, Tint8)
- Y(Tuns32, Tint8)
- Y(Tint64, Tint8)
- Y(Tuns64, Tint8)
- Y(Tint128, Tint8)
- Y(Tuns128, Tint8)
-
- Y(Tint8, Tuns8)
- Y(Tint16, Tuns8)
- Y(Tuns16, Tuns8)
- Y(Tint32, Tuns8)
- Y(Tuns32, Tuns8)
- Y(Tint64, Tuns8)
- Y(Tuns64, Tuns8)
- Y(Tint128, Tuns8)
- Y(Tuns128, Tuns8)
-
- Y(Tint8, Tchar)
- Y(Tint16, Tchar)
- Y(Tuns16, Tchar)
- Y(Tint32, Tchar)
- Y(Tuns32, Tchar)
- Y(Tint64, Tchar)
- Y(Tuns64, Tchar)
- Y(Tint128, Tchar)
- Y(Tuns128, Tchar)
-
- Y(Tuns16, Tint16)
- Y(Tint32, Tint16)
- Y(Tuns32, Tint16)
- Y(Tint64, Tint16)
- Y(Tuns64, Tint16)
- Y(Tint128, Tint16)
- Y(Tuns128, Tint16)
-
- Y(Tint16, Tuns16)
- Y(Tint32, Tuns16)
- Y(Tuns32, Tuns16)
- Y(Tint64, Tuns16)
- Y(Tuns64, Tuns16)
- Y(Tint128, Tuns16)
- Y(Tuns128, Tuns16)
-
- Y(Tint16, Twchar)
- Y(Tint32, Twchar)
- Y(Tuns32, Twchar)
- Y(Tint64, Twchar)
- Y(Tuns64, Twchar)
- Y(Tint128, Twchar)
- Y(Tuns128, Twchar)
-
-// Y(Tuns32, Tint32)
- Y(Tint64, Tint32)
- Y(Tuns64, Tint32)
- Y(Tint128, Tint32)
- Y(Tuns128, Tint32)
-
-// Y(Tint32, Tuns32)
- Y(Tint64, Tuns32)
- Y(Tuns64, Tuns32)
- Y(Tint128, Tuns32)
- Y(Tuns128, Tuns32)
-
- Y(Tint64, Tdchar)
- Y(Tuns64, Tdchar)
- Y(Tint128, Tdchar)
- Y(Tuns128, Tdchar)
-
-// Y(Tint64, Tuns64)
-// Y(Tuns64, Tint64)
- Y(Tint128, Tint64)
- Y(Tuns128, Tint64)
- Y(Tint128, Tuns64)
- Y(Tuns128, Tuns64)
-
-// Y(Tint128, Tuns128)
-// Y(Tuns128, Tint128)
-
- for (i = 0; i < TMAX; i++)
- for (j = 0; j < TMAX; j++)
- {
- if (impcnvResultTab[i][j] == Terror)
- {
- impcnvResultTab[i][j] = impcnvResultTab[j][i];
- impcnvType1Tab[i][j] = impcnvType2Tab[j][i];
- impcnvType2Tab[i][j] = impcnvType1Tab[j][i];
- }
- }
-}
-
-int main()
-{
- int i;
- int j;
-
- init();
-
- {
- FILE *fp = fopen("impcnvtab.c","wb");
-
- fprintf(fp,"// This file is generated by impcnvgen.c\n");
- fprintf(fp,"#include \"mtype.h\"\n");
-
- fprintf(fp,"unsigned char impcnvResult[TMAX][TMAX] =\n{\n");
- for (i = 0; i < TMAX; i++)
- {
- if (i)
- fprintf(fp, ",");
- fprintf(fp, "{");
- for (j = 0; j < TMAX; j++)
- {
- if (j)
- fprintf(fp, ",");
- fprintf(fp, "%d",impcnvResultTab[i][j]);
- }
- fprintf(fp, "}\n");
- }
- fprintf(fp,"};\n");
-
- fprintf(fp,"unsigned char impcnvType1[TMAX][TMAX] =\n{\n");
- for (i = 0; i < TMAX; i++)
- {
- if (i)
- fprintf(fp, ",");
- fprintf(fp, "{");
- for (j = 0; j < TMAX; j++)
- {
- if (j)
- fprintf(fp, ",");
- fprintf(fp, "%d",impcnvType1Tab[i][j]);
- }
- fprintf(fp, "}\n");
- }
- fprintf(fp,"};\n");
-
- fprintf(fp,"unsigned char impcnvType2[TMAX][TMAX] =\n{\n");
- for (i = 0; i < TMAX; i++)
- {
- if (i)
- fprintf(fp, ",");
- fprintf(fp, "{");
- for (j = 0; j < TMAX; j++)
- {
- if (j)
- fprintf(fp, ",");
- fprintf(fp, "%d",impcnvType2Tab[i][j]);
- }
- fprintf(fp, "}\n");
- }
- fprintf(fp,"};\n");
-
- fprintf(fp,"unsigned char impcnvWarn[TMAX][TMAX] =\n{\n");
- for (i = 0; i < TMAX; i++)
- {
- if (i)
- fprintf(fp, ",");
- fprintf(fp, "{");
- for (j = 0; j < TMAX; j++)
- {
- if (j)
- fprintf(fp, ",");
- fprintf(fp, "%d",impcnvWarnTab[i][j]);
- }
- fprintf(fp, "}\n");
- }
- fprintf(fp,"};\n");
-
- fclose(fp);
- }
-
- {
- FILE *fp = fopen("impcnvtab.d", "wb");
-
- fprintf(fp, "// This file is generated by impcnvgen.c\n");
- fprintf(fp, "module ddmd.impcnvtab;\n");
- fprintf(fp, "\n");
- fprintf(fp, "import ddmd.mtype;\n");
- fprintf(fp, "\n");
-
- fprintf(fp, "extern (C++) __gshared ubyte[TMAX][TMAX] impcnvResult =\n[\n");
- for (i = 0; i < TMAX; i++)
- {
- if (i)
- fprintf(fp, ",\n");
- fprintf(fp, " [");
- for (j = 0; j < TMAX; j++)
- {
- if (j)
- fprintf(fp, ",");
- fprintf(fp, "%d", impcnvResultTab[i][j]);
- }
- fprintf(fp, "]");
- }
- fprintf(fp, "\n];\n");
-
- fprintf(fp, "extern (C++) __gshared ubyte[TMAX][TMAX] impcnvType1 =\n[\n");
- for (i = 0; i < TMAX; i++)
- {
- if (i)
- fprintf(fp, ",\n");
- fprintf(fp, " [");
- for (j = 0; j < TMAX; j++)
- {
- if (j)
- fprintf(fp, ",");
- fprintf(fp, "%d", impcnvType1Tab[i][j]);
- }
- fprintf(fp, "]");
- }
- fprintf(fp, "\n];\n");
-
- fprintf(fp, "extern (C++) __gshared ubyte[TMAX][TMAX] impcnvType2 =\n[\n");
- for (i = 0; i < TMAX; i++)
- {
- if (i)
- fprintf(fp, ",\n");
- fprintf(fp, " [");
- for (j = 0; j < TMAX; j++)
- {
- if (j)
- fprintf(fp, ",");
- fprintf(fp, "%d",impcnvType2Tab[i][j]);
- }
- fprintf(fp, "]");
- }
- fprintf(fp,"\n];\n");
-
- fprintf(fp,"extern (C++) __gshared ubyte[TMAX][TMAX] impcnvWarn =\n[\n");
- for (i = 0; i < TMAX; i++)
- {
- if (i)
- fprintf(fp, ",\n");
- fprintf(fp, " [");
- for (j = 0; j < TMAX; j++)
- {
- if (j)
- fprintf(fp, ",");
- fprintf(fp, "%d", impcnvWarnTab[i][j]);
- }
- fprintf(fp, "]");
- }
- fprintf(fp, "\n];\n");
-
- fclose(fp);
- }
-
- return EXIT_SUCCESS;
-}
diff --git a/gcc/d/dmd/impcnvtab.d b/gcc/d/dmd/impcnvtab.d
new file mode 100644
index 0000000..db09f0c
--- /dev/null
+++ b/gcc/d/dmd/impcnvtab.d
@@ -0,0 +1,379 @@
+/**
+ * Provides an implicit conversion table for basic types.
+ *
+ * Used to determine integer promotions and common types.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/type.html#integer-promotions, Integer Promotions),
+ * $(LINK2 https://dlang.org/spec/type.html#usual-arithmetic-conversions, Usual Arithmetic Conversions).
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d, _impcnvtab.d)
+ * Documentation: https://dlang.org/phobos/dmd_impcnvtab.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/impcnvtab.d
+ */
+
+module dmd.impcnvtab;
+
+import dmd.astenums;
+import dmd.mtype;
+
+pure @nogc nothrow @safe:
+
+/*************************************************
+ * If ty1 and ty2 are basic types, return the TY that both can
+ * be implicitly converted to.
+ * Params:
+ * ty1 = first operand type
+ * ty2 = second operand type
+ * Returns:
+ * ty = common type, else Terror
+ */
+TY implicitConvCommonTy(TY ty1, TY ty2)
+{
+ return impCnvTab.impcnvResultTab[ty1][ty2];
+}
+
+/*************************************************
+ * If ty1 and ty2 are basic types, return the TY that ty1 can
+ * be implicitly converted to to bring them to a common ty.
+ * It's symmetric, i.e. the operands can be swapped.
+ * Params:
+ * ty1 = first operand type
+ * ty2 = second operand type
+ * Returns:
+ * ty = what ty1 should be converted to, else Terror
+ */
+TY implicitConvTy1(TY ty1, TY ty2)
+{
+ return impCnvTab.impcnvType1Tab[ty1][ty2];
+}
+
+/******************************************************************************/
+
+private:
+
+struct ImpCnvTab
+{
+ TY[TMAX][TMAX] impcnvResultTab;
+ TY[TMAX][TMAX] impcnvType1Tab;
+}
+
+enum ImpCnvTab impCnvTab = generateImpCnvTab();
+
+ImpCnvTab generateImpCnvTab()
+{
+ ImpCnvTab impCnvTab;
+
+ // Set conversion tables
+ foreach (i; 0 .. cast(size_t)TMAX)
+ {
+ foreach (j; 0 .. cast(size_t)TMAX)
+ {
+ impCnvTab.impcnvResultTab[i][j] = Terror;
+ impCnvTab.impcnvType1Tab[i][j] = Terror;
+ }
+ }
+
+ void X(TY t1, TY t2, TY nt1, TY nt2, TY rt)
+ {
+ impCnvTab.impcnvResultTab[t1][t2] = rt;
+ impCnvTab.impcnvResultTab[t2][t1] = rt;
+
+ impCnvTab.impcnvType1Tab[t1][t2] = nt1;
+ impCnvTab.impcnvType1Tab[t2][t1] = nt2;
+ }
+
+ /* ======================= */
+
+ X(Tbool,Tbool, Tbool,Tbool, Tbool);
+ X(Tbool,Tint8, Tint32,Tint32, Tint32);
+ X(Tbool,Tuns8, Tint32,Tint32, Tint32);
+ X(Tbool,Tint16, Tint32,Tint32, Tint32);
+ X(Tbool,Tuns16, Tint32,Tint32, Tint32);
+ X(Tbool,Tint32, Tint32,Tint32, Tint32);
+ X(Tbool,Tuns32, Tuns32,Tuns32, Tuns32);
+ X(Tbool,Tint64, Tint64,Tint64, Tint64);
+ X(Tbool,Tuns64, Tuns64,Tuns64, Tuns64);
+ X(Tbool,Tint128, Tint128,Tint128, Tint128);
+ X(Tbool,Tuns128, Tuns128,Tuns128, Tuns128);
+
+ X(Tbool,Tfloat32, Tfloat32,Tfloat32, Tfloat32);
+ X(Tbool,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tbool,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+ X(Tbool,Timaginary32, Tfloat32,Timaginary32, Tfloat32);
+ X(Tbool,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tbool,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+ X(Tbool,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32);
+ X(Tbool,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tbool,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tint8,Tint8, Tint32,Tint32, Tint32);
+ X(Tint8,Tuns8, Tint32,Tint32, Tint32);
+ X(Tint8,Tint16, Tint32,Tint32, Tint32);
+ X(Tint8,Tuns16, Tint32,Tint32, Tint32);
+ X(Tint8,Tint32, Tint32,Tint32, Tint32);
+ X(Tint8,Tuns32, Tuns32,Tuns32, Tuns32);
+ X(Tint8,Tint64, Tint64,Tint64, Tint64);
+ X(Tint8,Tuns64, Tuns64,Tuns64, Tuns64);
+ X(Tint8,Tint128, Tint128,Tint128, Tint128);
+ X(Tint8,Tuns128, Tuns128,Tuns128, Tuns128);
+
+ X(Tint8,Tfloat32, Tfloat32,Tfloat32, Tfloat32);
+ X(Tint8,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tint8,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+ X(Tint8,Timaginary32, Tfloat32,Timaginary32, Tfloat32);
+ X(Tint8,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tint8,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+ X(Tint8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32);
+ X(Tint8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tint8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tuns8,Tuns8, Tint32,Tint32, Tint32);
+ X(Tuns8,Tint16, Tint32,Tint32, Tint32);
+ X(Tuns8,Tuns16, Tint32,Tint32, Tint32);
+ X(Tuns8,Tint32, Tint32,Tint32, Tint32);
+ X(Tuns8,Tuns32, Tuns32,Tuns32, Tuns32);
+ X(Tuns8,Tint64, Tint64,Tint64, Tint64);
+ X(Tuns8,Tuns64, Tuns64,Tuns64, Tuns64);
+ X(Tuns8,Tint128, Tint128,Tint128, Tint128);
+ X(Tuns8,Tuns128, Tuns128,Tuns128, Tuns128);
+
+ X(Tuns8,Tfloat32, Tfloat32,Tfloat32, Tfloat32);
+ X(Tuns8,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tuns8,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+ X(Tuns8,Timaginary32, Tfloat32,Timaginary32, Tfloat32);
+ X(Tuns8,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tuns8,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+ X(Tuns8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32);
+ X(Tuns8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tuns8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tint16,Tint16, Tint32,Tint32, Tint32);
+ X(Tint16,Tuns16, Tint32,Tint32, Tint32);
+ X(Tint16,Tint32, Tint32,Tint32, Tint32);
+ X(Tint16,Tuns32, Tuns32,Tuns32, Tuns32);
+ X(Tint16,Tint64, Tint64,Tint64, Tint64);
+ X(Tint16,Tuns64, Tuns64,Tuns64, Tuns64);
+ X(Tint16,Tint128, Tint128,Tint128, Tint128);
+ X(Tint16,Tuns128, Tuns128,Tuns128, Tuns128);
+
+ X(Tint16,Tfloat32, Tfloat32,Tfloat32, Tfloat32);
+ X(Tint16,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tint16,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+ X(Tint16,Timaginary32, Tfloat32,Timaginary32, Tfloat32);
+ X(Tint16,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tint16,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+ X(Tint16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32);
+ X(Tint16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tint16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tuns16,Tuns16, Tint32,Tint32, Tint32);
+ X(Tuns16,Tint32, Tint32,Tint32, Tint32);
+ X(Tuns16,Tuns32, Tuns32,Tuns32, Tuns32);
+ X(Tuns16,Tint64, Tint64,Tint64, Tint64);
+ X(Tuns16,Tuns64, Tuns64,Tuns64, Tuns64);
+ X(Tuns16,Tint128, Tint128,Tint128, Tint128);
+ X(Tuns16,Tuns128, Tuns128,Tuns128, Tuns128);
+
+ X(Tuns16,Tfloat32, Tfloat32,Tfloat32, Tfloat32);
+ X(Tuns16,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tuns16,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+ X(Tuns16,Timaginary32, Tfloat32,Timaginary32, Tfloat32);
+ X(Tuns16,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tuns16,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+ X(Tuns16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32);
+ X(Tuns16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tuns16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tint32,Tint32, Tint32,Tint32, Tint32);
+ X(Tint32,Tuns32, Tuns32,Tuns32, Tuns32);
+ X(Tint32,Tint64, Tint64,Tint64, Tint64);
+ X(Tint32,Tuns64, Tuns64,Tuns64, Tuns64);
+ X(Tint32,Tint128, Tint128,Tint128, Tint128);
+ X(Tint32,Tuns128, Tuns128,Tuns128, Tuns128);
+
+ X(Tint32,Tfloat32, Tfloat32,Tfloat32, Tfloat32);
+ X(Tint32,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tint32,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+ X(Tint32,Timaginary32, Tfloat32,Timaginary32, Tfloat32);
+ X(Tint32,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tint32,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+ X(Tint32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32);
+ X(Tint32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tint32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tuns32,Tuns32, Tuns32,Tuns32, Tuns32);
+ X(Tuns32,Tint64, Tint64,Tint64, Tint64);
+ X(Tuns32,Tuns64, Tuns64,Tuns64, Tuns64);
+ X(Tuns32,Tint128, Tint128,Tint128, Tint128);
+ X(Tuns32,Tuns128, Tuns128,Tuns128, Tuns128);
+
+ X(Tuns32,Tfloat32, Tfloat32,Tfloat32, Tfloat32);
+ X(Tuns32,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tuns32,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+ X(Tuns32,Timaginary32, Tfloat32,Timaginary32, Tfloat32);
+ X(Tuns32,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tuns32,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+ X(Tuns32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32);
+ X(Tuns32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tuns32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tint64,Tint64, Tint64,Tint64, Tint64);
+ X(Tint64,Tuns64, Tuns64,Tuns64, Tuns64);
+ X(Tint64,Tint128, Tint128,Tint128, Tint128);
+ X(Tint64,Tuns128, Tuns128,Tuns128, Tuns128);
+
+ X(Tint64,Tfloat32, Tfloat32,Tfloat32, Tfloat32);
+ X(Tint64,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tint64,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+ X(Tint64,Timaginary32, Tfloat32,Timaginary32, Tfloat32);
+ X(Tint64,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tint64,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+ X(Tint64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32);
+ X(Tint64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tint64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tuns64,Tuns64, Tuns64,Tuns64, Tuns64);
+ X(Tuns64,Tint128, Tint128,Tint128, Tint128);
+ X(Tuns64,Tuns128, Tuns128,Tuns128, Tuns128);
+
+ X(Tuns64,Tfloat32, Tfloat32,Tfloat32, Tfloat32);
+ X(Tuns64,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tuns64,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+ X(Tuns64,Timaginary32, Tfloat32,Timaginary32, Tfloat32);
+ X(Tuns64,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tuns64,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+ X(Tuns64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32);
+ X(Tuns64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tuns64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tint128,Tint128, Tint128,Tint128, Tint128);
+ X(Tint128,Tuns128, Tuns128,Tuns128, Tuns128);
+
+ X(Tint128,Tfloat32, Tfloat32,Tfloat32, Tfloat32);
+ X(Tint128,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tint128,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+ X(Tint128,Timaginary32, Tfloat32,Timaginary32, Tfloat32);
+ X(Tint128,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tint128,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+ X(Tint128,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32);
+ X(Tint128,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tint128,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tuns128,Tuns128, Tuns128,Tuns128, Tuns128);
+
+ X(Tuns128,Tfloat32, Tfloat32,Tfloat32, Tfloat32);
+ X(Tuns128,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tuns128,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+ X(Tuns128,Timaginary32, Tfloat32,Timaginary32, Tfloat32);
+ X(Tuns128,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tuns128,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+ X(Tuns128,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32);
+ X(Tuns128,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tuns128,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tfloat32,Tfloat32, Tfloat32,Tfloat32, Tfloat32);
+ X(Tfloat32,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tfloat32,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+
+ X(Tfloat32,Timaginary32, Tfloat32,Timaginary32, Tfloat32);
+ X(Tfloat32,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tfloat32,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+
+ X(Tfloat32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32);
+ X(Tfloat32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tfloat32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tfloat64,Tfloat64, Tfloat64,Tfloat64, Tfloat64);
+ X(Tfloat64,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+
+ X(Tfloat64,Timaginary32, Tfloat64,Timaginary64, Tfloat64);
+ X(Tfloat64,Timaginary64, Tfloat64,Timaginary64, Tfloat64);
+ X(Tfloat64,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+
+ X(Tfloat64,Tcomplex32, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tfloat64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64);
+ X(Tfloat64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tfloat80,Tfloat80, Tfloat80,Tfloat80, Tfloat80);
+
+ X(Tfloat80,Timaginary32, Tfloat80,Timaginary80, Tfloat80);
+ X(Tfloat80,Timaginary64, Tfloat80,Timaginary80, Tfloat80);
+ X(Tfloat80,Timaginary80, Tfloat80,Timaginary80, Tfloat80);
+
+ X(Tfloat80,Tcomplex32, Tfloat80,Tcomplex80, Tcomplex80);
+ X(Tfloat80,Tcomplex64, Tfloat80,Tcomplex80, Tcomplex80);
+ X(Tfloat80,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Timaginary32,Timaginary32, Timaginary32,Timaginary32, Timaginary32);
+ X(Timaginary32,Timaginary64, Timaginary64,Timaginary64, Timaginary64);
+ X(Timaginary32,Timaginary80, Timaginary80,Timaginary80, Timaginary80);
+
+ X(Timaginary32,Tcomplex32, Timaginary32,Tcomplex32, Tcomplex32);
+ X(Timaginary32,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64);
+ X(Timaginary32,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Timaginary64,Timaginary64, Timaginary64,Timaginary64, Timaginary64);
+ X(Timaginary64,Timaginary80, Timaginary80,Timaginary80, Timaginary80);
+
+ X(Timaginary64,Tcomplex32, Timaginary64,Tcomplex64, Tcomplex64);
+ X(Timaginary64,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64);
+ X(Timaginary64,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Timaginary80,Timaginary80, Timaginary80,Timaginary80, Timaginary80);
+
+ X(Timaginary80,Tcomplex32, Timaginary80,Tcomplex80, Tcomplex80);
+ X(Timaginary80,Tcomplex64, Timaginary80,Tcomplex80, Tcomplex80);
+ X(Timaginary80,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tcomplex32,Tcomplex32, Tcomplex32,Tcomplex32, Tcomplex32);
+ X(Tcomplex32,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64);
+ X(Tcomplex32,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tcomplex64,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64);
+ X(Tcomplex64,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80);
+
+ /* ======================= */
+
+ X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80);
+
+ return impCnvTab;
+}
diff --git a/gcc/d/dmd/imphint.c b/gcc/d/dmd/imphint.c
deleted file mode 100644
index 239cb07..0000000
--- a/gcc/d/dmd/imphint.c
+++ /dev/null
@@ -1,52 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 2010-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/imphint.c
- */
-
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-
-/******************************************
- * Looks for undefined identifier s to see
- * if it might be undefined because an import
- * was not specified.
- * Not meant to be a comprehensive list of names in each module,
- * just the most common ones.
- */
-
-const char *importHint(const char *s)
-{
- static const char *modules[] =
- { "core.stdc.stdio",
- "std.stdio",
- "std.math",
- NULL
- };
- static const char *names[] =
- {
- "printf", NULL,
- "writeln", NULL,
- "sin", "cos", "sqrt", "fabs", NULL,
- };
- int m = 0;
- for (int n = 0; modules[m]; n++)
- {
- const char *p = names[n];
- if (p == NULL)
- {
- m++;
- continue;
- }
- assert(modules[m]);
- if (strcmp(s, p) == 0)
- return modules[m];
- }
- return NULL; // didn't find it
-}
diff --git a/gcc/d/dmd/imphint.d b/gcc/d/dmd/imphint.d
new file mode 100644
index 0000000..e1919a6
--- /dev/null
+++ b/gcc/d/dmd/imphint.d
@@ -0,0 +1,91 @@
+/**
+ * Give import hints for common symbol names that couldn't be resolved.
+ *
+ * For example, prompt to `import std.stdio` when using `writeln`.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/imphint.d, _imphint.d)
+ * Documentation: https://dlang.org/phobos/dmd_imphint.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/imphint.d
+ */
+
+module dmd.imphint;
+
+/******************************************
+ * Looks for undefined identifier s to see
+ * if it might be undefined because an import
+ * was not specified.
+ * Not meant to be a comprehensive list of names in each module,
+ * just the most common ones.
+ */
+const(char)[] importHint(const(char)[] s)
+{
+ if (auto entry = s in hints)
+ return *entry;
+ return null;
+}
+
+private immutable string[string] hints;
+
+shared static this()
+{
+ // in alphabetic order
+ hints = [
+ "AliasSeq": "std.meta",
+ "appender": "std.array",
+ "array": "std.array",
+ "calloc": "core.stdc.stdlib",
+ "chdir": "std.file",
+ "cos": "std.math",
+ "dirEntries": "std.file",
+ "drop": "std.range",
+ "each": "std.algorithm",
+ "empty": "std.range",
+ "endsWith": "std.algorithm",
+ "enforce": "std.exception",
+ "enumerate": "std.range",
+ "equal": "std.algorithm",
+ "exists": "std.file",
+ "fabs": "std.math",
+ "filter": "std.algorithm",
+ "format": "std.format",
+ "free": "core.stdc.stdlib",
+ "front": "std.range",
+ "iota": "std.range",
+ "isDir": "std.file",
+ "isFile": "std.file",
+ "join": "std.array",
+ "joiner": "std.algorithm",
+ "malloc": "core.stdc.stdlib",
+ "map": "std.algorithm",
+ "max": "std.algorithm",
+ "min": "std.algorithm",
+ "mkdir": "std.file",
+ "popFront": "std.range",
+ "printf": "core.stdc.stdio",
+ "realloc": "core.stdc.stdlib",
+ "replace": "std.array",
+ "rmdir": "std.file",
+ "sin": "std.math",
+ "sort": "std.algorithm",
+ "split": "std.array",
+ "sqrt": "std.math",
+ "startsWith": "std.algorithm",
+ "take": "std.range",
+ "text": "std.conv",
+ "to": "std.conv",
+ "writefln": "std.stdio",
+ "writeln": "std.stdio",
+ "__va_argsave_t": "core.stdc.stdarg",
+ "__va_list_tag": "core.stdc.stdarg",
+ ];
+}
+
+unittest
+{
+ assert(importHint("printf") !is null);
+ assert(importHint("fabs") !is null);
+ assert(importHint("xxxxx") is null);
+}
diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h
index 07fb32a..34c5a05 100644
--- a/gcc/d/dmd/import.h
+++ b/gcc/d/dmd/import.h
@@ -16,7 +16,6 @@ class Identifier;
struct Scope;
class Module;
class Package;
-class AliasDeclaration;
class Import : public Dsymbol
{
@@ -24,11 +23,11 @@ public:
/* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2;
*/
- Identifiers *packages; // array of Identifier's representing packages
+ DArray<Identifier*> packages; // array of Identifier's representing packages
Identifier *id; // module Identifier
Identifier *aliasId;
int isstatic; // !=0 if static import
- Prot protection;
+ Visibility visibility;
// Pairs of alias=name to bind into current namespace
Identifiers names;
@@ -39,15 +38,11 @@ public:
AliasDeclarations aliasdecls; // corresponding AliasDeclarations for alias=name pairs
- Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId,
- int isstatic);
- void addAlias(Identifier *name, Identifier *alias);
const char *kind() const;
- Prot prot();
- Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
+ Visibility visible();
+ Import *syntaxCopy(Dsymbol *s); // copy only syntax trees
void load(Scope *sc);
void importAll(Scope *sc);
- void addPackageAccess(ScopeDsymbol *scopesym);
Dsymbol *toAlias();
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope* sc);
diff --git a/gcc/d/dmd/init.c b/gcc/d/dmd/init.c
deleted file mode 100644
index d18e054..0000000
--- a/gcc/d/dmd/init.c
+++ /dev/null
@@ -1,282 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/init.c
- */
-
-#include "root/dsystem.h"
-#include "root/checkedint.h"
-
-#include "mars.h"
-#include "init.h"
-#include "expression.h"
-#include "statement.h"
-#include "identifier.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "scope.h"
-#include "mtype.h"
-#include "hdrgen.h"
-#include "template.h"
-#include "id.h"
-#include "tokens.h"
-
-/********************************** Initializer *******************************/
-
-Initializer::Initializer(Loc loc)
-{
- this->loc = loc;
-}
-
-Initializers *Initializer::arraySyntaxCopy(Initializers *ai)
-{
- Initializers *a = NULL;
- if (ai)
- {
- a = new Initializers();
- a->setDim(ai->length);
- for (size_t i = 0; i < a->length; i++)
- (*a)[i] = (*ai)[i]->syntaxCopy();
- }
- return a;
-}
-
-const char *Initializer::toChars()
-{
- OutBuffer buf;
- HdrGenState hgs;
- ::toCBuffer(this, &buf, &hgs);
- return buf.extractChars();
-}
-
-/********************************** ErrorInitializer ***************************/
-
-ErrorInitializer::ErrorInitializer()
- : Initializer(Loc())
-{
-}
-
-Initializer *ErrorInitializer::syntaxCopy()
-{
- return this;
-}
-
-/********************************** VoidInitializer ***************************/
-
-VoidInitializer::VoidInitializer(Loc loc)
- : Initializer(loc)
-{
- type = NULL;
-}
-
-Initializer *VoidInitializer::syntaxCopy()
-{
- return new VoidInitializer(loc);
-}
-
-/********************************** StructInitializer *************************/
-
-StructInitializer::StructInitializer(Loc loc)
- : Initializer(loc)
-{
-}
-
-Initializer *StructInitializer::syntaxCopy()
-{
- StructInitializer *ai = new StructInitializer(loc);
- assert(field.length == value.length);
- ai->field.setDim(field.length);
- ai->value.setDim(value.length);
- for (size_t i = 0; i < field.length; i++)
- {
- ai->field[i] = field[i];
- ai->value[i] = value[i]->syntaxCopy();
- }
- return ai;
-}
-
-void StructInitializer::addInit(Identifier *field, Initializer *value)
-{
- //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
- this->field.push(field);
- this->value.push(value);
-}
-
-/********************************** ArrayInitializer ************************************/
-
-ArrayInitializer::ArrayInitializer(Loc loc)
- : Initializer(loc)
-{
- dim = 0;
- type = NULL;
- sem = false;
-}
-
-Initializer *ArrayInitializer::syntaxCopy()
-{
- //printf("ArrayInitializer::syntaxCopy()\n");
- ArrayInitializer *ai = new ArrayInitializer(loc);
- assert(index.length == value.length);
- ai->index.setDim(index.length);
- ai->value.setDim(value.length);
- for (size_t i = 0; i < ai->value.length; i++)
- {
- ai->index[i] = index[i] ? index[i]->syntaxCopy() : NULL;
- ai->value[i] = value[i]->syntaxCopy();
- }
- return ai;
-}
-
-void ArrayInitializer::addInit(Expression *index, Initializer *value)
-{
- this->index.push(index);
- this->value.push(value);
- dim = 0;
- type = NULL;
-}
-
-bool ArrayInitializer::isAssociativeArray()
-{
- for (size_t i = 0; i < value.length; i++)
- {
- if (index[i])
- return true;
- }
- return false;
-}
-
-/********************************
- * If possible, convert array initializer to associative array initializer.
- */
-
-Expression *ArrayInitializer::toAssocArrayLiteral()
-{
- Expression *e;
-
- //printf("ArrayInitializer::toAssocArrayInitializer()\n");
- //static int i; if (++i == 2) halt();
- Expressions *keys = new Expressions();
- keys->setDim(value.length);
- Expressions *values = new Expressions();
- values->setDim(value.length);
-
- for (size_t i = 0; i < value.length; i++)
- {
- e = index[i];
- if (!e)
- goto Lno;
- (*keys)[i] = e;
-
- Initializer *iz = value[i];
- if (!iz)
- goto Lno;
- e = initializerToExpression(iz);
- if (!e)
- goto Lno;
- (*values)[i] = e;
- }
- e = new AssocArrayLiteralExp(loc, keys, values);
- return e;
-
-Lno:
- delete keys;
- delete values;
- error(loc, "not an associative array initializer");
- return new ErrorExp();
-}
-
-/********************************** ExpInitializer ************************************/
-
-ExpInitializer::ExpInitializer(Loc loc, Expression *exp)
- : Initializer(loc)
-{
- this->exp = exp;
- this->expandTuples = false;
-}
-
-Initializer *ExpInitializer::syntaxCopy()
-{
- return new ExpInitializer(loc, exp->syntaxCopy());
-}
-
-#if 1 // should be removed and rely on ctfeInterpreter()
-bool arrayHasNonConstPointers(Expressions *elems);
-
-bool hasNonConstPointers(Expression *e)
-{
- if (e->type->ty == Terror)
- return false;
-
- if (e->op == TOKnull)
- return false;
- if (e->op == TOKstructliteral)
- {
- StructLiteralExp *se = (StructLiteralExp *)e;
- return arrayHasNonConstPointers(se->elements);
- }
- if (e->op == TOKarrayliteral)
- {
- if (!e->type->nextOf()->hasPointers())
- return false;
- ArrayLiteralExp *ae = (ArrayLiteralExp *)e;
- return arrayHasNonConstPointers(ae->elements);
- }
- if (e->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
- if (ae->type->nextOf()->hasPointers() &&
- arrayHasNonConstPointers(ae->values))
- return true;
- if (((TypeAArray *)ae->type)->index->hasPointers())
- return arrayHasNonConstPointers(ae->keys);
- return false;
- }
- if (e->op == TOKaddress)
- {
- AddrExp *ae = (AddrExp *)e;
- if (ae->e1->op == TOKstructliteral)
- {
- StructLiteralExp *se = (StructLiteralExp *)ae->e1;
- if (!(se->stageflags & stageSearchPointers))
- {
- int old = se->stageflags;
- se->stageflags |= stageSearchPointers;
- bool ret = arrayHasNonConstPointers(se->elements);
- se->stageflags = old;
- return ret;
- }
- else
- {
- return false;
- }
- }
- return true;
- }
- if (e->type->ty== Tpointer && e->type->nextOf()->ty != Tfunction)
- {
- if (e->op == TOKsymoff) // address of a global is OK
- return false;
- if (e->op == TOKint64) // cast(void *)int is OK
- return false;
- if (e->op == TOKstring) // "abc".ptr is OK
- return false;
- return true;
- }
- return false;
-}
-
-bool arrayHasNonConstPointers(Expressions *elems)
-{
- for (size_t i = 0; i < elems->length; i++)
- {
- Expression *e = (*elems)[i];
- if (e && hasNonConstPointers(e))
- return true;
- }
- return false;
-}
-#endif
diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d
new file mode 100644
index 0000000..45e101b
--- /dev/null
+++ b/gcc/d/dmd/init.d
@@ -0,0 +1,332 @@
+/**
+ * Defines initializers of variables, e.g. the array literal in `int[3] x = [0, 1, 2]`.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/init.d, _init.d)
+ * Documentation: https://dlang.org/phobos/dmd_init.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/init.d
+ */
+
+module dmd.init;
+
+import core.stdc.stdio;
+import core.checkedint;
+
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.ast_node;
+import dmd.dsymbol;
+import dmd.expression;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.root.outbuffer;
+import dmd.root.rootobject;
+import dmd.tokens;
+import dmd.visitor;
+
+enum NeedInterpret : int
+{
+ INITnointerpret,
+ INITinterpret,
+}
+
+alias INITnointerpret = NeedInterpret.INITnointerpret;
+alias INITinterpret = NeedInterpret.INITinterpret;
+
+/***********************************************************
+ */
+extern (C++) class Initializer : ASTNode
+{
+ Loc loc;
+ InitKind kind;
+
+ override DYNCAST dyncast() const nothrow pure
+ {
+ return DYNCAST.initializer;
+ }
+
+
+ extern (D) this(const ref Loc loc, InitKind kind)
+ {
+ this.loc = loc;
+ this.kind = kind;
+ }
+
+ override final const(char)* toChars() const
+ {
+ OutBuffer buf;
+ HdrGenState hgs;
+ .toCBuffer(this, &buf, &hgs);
+ return buf.extractChars();
+ }
+
+ final inout(ErrorInitializer) isErrorInitializer() inout @nogc nothrow pure
+ {
+ // Use void* cast to skip dynamic casting call
+ return kind == InitKind.error ? cast(inout ErrorInitializer)cast(void*)this : null;
+ }
+
+ final inout(VoidInitializer) isVoidInitializer() inout @nogc nothrow pure
+ {
+ return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null;
+ }
+
+ final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure
+ {
+ return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null;
+ }
+
+ final inout(ArrayInitializer) isArrayInitializer() inout @nogc nothrow pure
+ {
+ return kind == InitKind.array ? cast(inout ArrayInitializer)cast(void*)this : null;
+ }
+
+ final inout(ExpInitializer) isExpInitializer() inout @nogc nothrow pure
+ {
+ return kind == InitKind.exp ? cast(inout ExpInitializer)cast(void*)this : null;
+ }
+
+ final inout(CInitializer) isCInitializer() inout @nogc nothrow pure
+ {
+ return kind == InitKind.C_ ? cast(inout CInitializer)cast(void*)this : null;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class VoidInitializer : Initializer
+{
+ Type type; // type that this will initialize to
+
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, InitKind.void_);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ErrorInitializer : Initializer
+{
+ extern (D) this()
+ {
+ super(Loc.initial, InitKind.error);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class StructInitializer : Initializer
+{
+ Identifiers field; // of Identifier *'s
+ Initializers value; // parallel array of Initializer *'s
+
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, InitKind.struct_);
+ }
+
+ extern (D) void addInit(Identifier field, Initializer value)
+ {
+ //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value);
+ this.field.push(field);
+ this.value.push(value);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ArrayInitializer : Initializer
+{
+ Expressions index; // indices
+ Initializers value; // of Initializer *'s
+ uint dim; // length of array being initialized
+ Type type; // type that array will be used to initialize
+ bool sem; // true if semantic() is run
+
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, InitKind.array);
+ }
+
+ extern (D) void addInit(Expression index, Initializer value)
+ {
+ this.index.push(index);
+ this.value.push(value);
+ dim = 0;
+ type = null;
+ }
+
+ bool isAssociativeArray() const pure
+ {
+ foreach (idx; index)
+ {
+ if (idx)
+ return true;
+ }
+ return false;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class ExpInitializer : Initializer
+{
+ bool expandTuples;
+ Expression exp;
+
+ extern (D) this(const ref Loc loc, Expression exp)
+ {
+ super(loc, InitKind.exp);
+ this.exp = exp;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/*********************************************
+ * Holds the `designator` for C initializers
+ */
+struct Designator
+{
+ Expression exp; /// [ constant-expression ]
+ Identifier ident; /// . identifier
+
+ this(Expression exp) { this.exp = exp; }
+ this(Identifier ident) { this.ident = ident; }
+}
+
+/*********************************************
+ * Holds the `designation (opt) initializer` for C initializers
+ */
+struct DesigInit
+{
+ Designators* designatorList; /// designation (opt)
+ Initializer initializer; /// initializer
+}
+
+/********************************
+ * C11 6.7.9 Initialization
+ * Represents the C initializer-list
+ */
+extern (C++) final class CInitializer : Initializer
+{
+ DesigInits initializerList; /// initializer-list
+ Type type; /// type that array will be used to initialize
+ bool sem; /// true if semantic() is run
+
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, InitKind.C_);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/****************************************
+ * Copy the AST for Initializer.
+ * Params:
+ * inx = Initializer AST to copy
+ * Returns:
+ * the copy
+ */
+Initializer syntaxCopy(Initializer inx)
+{
+ static Initializer copyStruct(StructInitializer vi)
+ {
+ auto si = new StructInitializer(vi.loc);
+ assert(vi.field.dim == vi.value.dim);
+ si.field.setDim(vi.field.dim);
+ si.value.setDim(vi.value.dim);
+ foreach (const i; 0 .. vi.field.dim)
+ {
+ si.field[i] = vi.field[i];
+ si.value[i] = vi.value[i].syntaxCopy();
+ }
+ return si;
+ }
+
+ static Initializer copyArray(ArrayInitializer vi)
+ {
+ auto ai = new ArrayInitializer(vi.loc);
+ assert(vi.index.dim == vi.value.dim);
+ ai.index.setDim(vi.index.dim);
+ ai.value.setDim(vi.value.dim);
+ foreach (const i; 0 .. vi.value.dim)
+ {
+ ai.index[i] = vi.index[i] ? vi.index[i].syntaxCopy() : null;
+ ai.value[i] = vi.value[i].syntaxCopy();
+ }
+ return ai;
+ }
+
+ static Initializer copyC(CInitializer vi)
+ {
+ auto ci = new CInitializer(vi.loc);
+ ci.initializerList.setDim(vi.initializerList.length);
+ foreach (const i; 0 .. vi.initializerList.length)
+ {
+ DesigInit* cdi = &ci.initializerList[i];
+ DesigInit* vdi = &ci.initializerList[i];
+ cdi.initializer = vdi.initializer.syntaxCopy();
+ if (vdi.designatorList)
+ {
+ cdi.designatorList = new Designators();
+ cdi.designatorList.setDim(vdi.designatorList.length);
+ foreach (const j; 0 .. vdi.designatorList.length)
+ {
+ Designator* cdid = &(*cdi.designatorList)[j];
+ Designator* vdid = &(*vdi.designatorList)[j];
+ cdid.exp = vdid.exp ? vdid.exp.syntaxCopy() : null;
+ cdid.ident = vdid.ident;
+ }
+ }
+ }
+ return ci;
+ }
+
+ final switch (inx.kind)
+ {
+ case InitKind.void_: return new VoidInitializer(inx.loc);
+ case InitKind.error: return inx;
+ case InitKind.struct_: return copyStruct(cast(StructInitializer)inx);
+ case InitKind.array: return copyArray(cast(ArrayInitializer)inx);
+ case InitKind.exp: return new ExpInitializer(inx.loc, (cast(ExpInitializer)inx).exp.syntaxCopy());
+ case InitKind.C_: return copyC(cast(CInitializer)inx);
+ }
+}
diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h
index 4ba18d6..23204b8 100644
--- a/gcc/d/dmd/init.h
+++ b/gcc/d/dmd/init.h
@@ -10,7 +10,6 @@
#pragma once
-#include "root/root.h"
#include "ast_node.h"
#include "globals.h"
#include "arraytypes.h"
@@ -18,36 +17,31 @@
class Identifier;
class Expression;
-struct Scope;
class Type;
-class AggregateDeclaration;
-class Initializer;
class ErrorInitializer;
class VoidInitializer;
class StructInitializer;
class ArrayInitializer;
class ExpInitializer;
+class CInitializer;
enum NeedInterpret { INITnointerpret, INITinterpret };
-Initializer *initializerSemantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret);
-
class Initializer : public ASTNode
{
public:
Loc loc;
+ unsigned char kind;
- Initializer(Loc loc);
- virtual Initializer *syntaxCopy() = 0;
- static Initializers *arraySyntaxCopy(Initializers *ai);
+ const char *toChars() const;
- const char *toChars();
+ ErrorInitializer *isErrorInitializer();
+ VoidInitializer *isVoidInitializer();
+ StructInitializer *isStructInitializer();
+ ArrayInitializer *isArrayInitializer();
+ ExpInitializer *isExpInitializer();
+ CInitializer *isCInitializer();
- virtual ErrorInitializer *isErrorInitializer() { return NULL; }
- virtual VoidInitializer *isVoidInitializer() { return NULL; }
- virtual StructInitializer *isStructInitializer() { return NULL; }
- virtual ArrayInitializer *isArrayInitializer() { return NULL; }
- virtual ExpInitializer *isExpInitializer() { return NULL; }
void accept(Visitor *v) { v->visit(this); }
};
@@ -56,20 +50,12 @@ class VoidInitializer : public Initializer
public:
Type *type; // type that this will initialize to
- VoidInitializer(Loc loc);
- Initializer *syntaxCopy();
-
- virtual VoidInitializer *isVoidInitializer() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
class ErrorInitializer : public Initializer
{
public:
- ErrorInitializer();
- Initializer *syntaxCopy();
-
- virtual ErrorInitializer *isErrorInitializer() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
@@ -79,11 +65,6 @@ public:
Identifiers field; // of Identifier *'s
Initializers value; // parallel array of Initializer *'s
- StructInitializer(Loc loc);
- Initializer *syntaxCopy();
- void addInit(Identifier *field, Initializer *value);
-
- StructInitializer *isStructInitializer() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
@@ -96,26 +77,40 @@ public:
Type *type; // type that array will be used to initialize
bool sem; // true if semantic() is run
- ArrayInitializer(Loc loc);
- Initializer *syntaxCopy();
- void addInit(Expression *index, Initializer *value);
- bool isAssociativeArray();
+ bool isAssociativeArray() const;
Expression *toAssocArrayLiteral();
- ArrayInitializer *isArrayInitializer() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
class ExpInitializer : public Initializer
{
public:
- Expression *exp;
bool expandTuples;
+ Expression *exp;
+
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+struct Designator
+{
+ Expression *exp;
+ Identifier *ident;
+};
+
+struct DesigInit
+{
+ Designators *designatorList;
+ Initializer *initializer;
+};
- ExpInitializer(Loc loc, Expression *exp);
- Initializer *syntaxCopy();
+class CInitializer : public Initializer
+{
+public:
+ DesigInits initializerList;
+ Type *type; // type that array will be used to initialize
+ bool sem; // true if semantic() is run
- ExpInitializer *isExpInitializer() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
diff --git a/gcc/d/dmd/initsem.c b/gcc/d/dmd/initsem.c
deleted file mode 100644
index c7d1dfe..0000000
--- a/gcc/d/dmd/initsem.c
+++ /dev/null
@@ -1,914 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- */
-
-#include "root/checkedint.h"
-#include "mars.h"
-#include "init.h"
-#include "expression.h"
-#include "statement.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "scope.h"
-#include "mtype.h"
-#include "template.h"
-#include "id.h"
-
-FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
-Initializer *inferType(Initializer *init, Scope *sc);
-bool hasNonConstPointers(Expression *e);
-
-class InitializerSemanticVisitor : public Visitor
-{
-public:
- Initializer *result;
- Scope *sc;
- Type *t;
- NeedInterpret needInterpret;
-
- InitializerSemanticVisitor(Scope *sc, Type *t, NeedInterpret needInterpret)
- {
- this->result = NULL;
- this->sc = sc;
- this->t = t;
- this->needInterpret = needInterpret;
- }
-
- void visit(ErrorInitializer *i)
- {
- //printf("ErrorInitializer::semantic(t = %p)\n", t);
- result = i;
- }
-
- void visit(VoidInitializer *i)
- {
- //printf("VoidInitializer::semantic(t = %p)\n", t);
- i->type = t;
- result = i;
- }
-
- void visit(StructInitializer *i)
- {
- //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars());
- t = t->toBasetype();
- if (t->ty == Tsarray && t->nextOf()->toBasetype()->ty == Tstruct)
- t = t->nextOf()->toBasetype();
- if (t->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)t)->sym;
- if (sd->ctor)
- {
- error(i->loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead",
- sd->kind(), sd->toChars(), sd->toChars());
- result = new ErrorInitializer();
- return;
- }
- sd->size(i->loc);
- if (sd->sizeok != SIZEOKdone)
- {
- result = new ErrorInitializer();
- return;
- }
- size_t nfields = sd->fields.length - sd->isNested();
-
- //expandTuples for non-identity arguments?
-
- Expressions *elements = new Expressions();
- elements->setDim(nfields);
- for (size_t j = 0; j < elements->length; j++)
- (*elements)[j] = NULL;
-
- // Run semantic for explicitly given initializers
- // TODO: this part is slightly different from StructLiteralExp::semantic.
- bool errors = false;
- for (size_t fieldi = 0, j = 0; j < i->field.length; j++)
- {
- if (Identifier *id = i->field[j])
- {
- Dsymbol *s = sd->search(i->loc, id);
- if (!s)
- {
- s = sd->search_correct(id);
- if (s)
- error(i->loc, "`%s` is not a member of `%s`, did you mean %s `%s`?",
- id->toChars(), sd->toChars(), s->kind(), s->toChars());
- else
- error(i->loc, "`%s` is not a member of `%s`", id->toChars(), sd->toChars());
- result = new ErrorInitializer();
- return;
- }
- s = s->toAlias();
-
- // Find out which field index it is
- for (fieldi = 0; 1; fieldi++)
- {
- if (fieldi >= nfields)
- {
- error(i->loc, "%s.%s is not a per-instance initializable field",
- sd->toChars(), s->toChars());
- result = new ErrorInitializer();
- return;
- }
- if (s == sd->fields[fieldi])
- break;
- }
- }
- else if (fieldi >= nfields)
- {
- error(i->loc, "too many initializers for %s", sd->toChars());
- result = new ErrorInitializer();
- return;
- }
-
- VarDeclaration *vd = sd->fields[fieldi];
- if ((*elements)[fieldi])
- {
- error(i->loc, "duplicate initializer for field `%s`", vd->toChars());
- errors = true;
- continue;
- }
- for (size_t k = 0; k < nfields; k++)
- {
- VarDeclaration *v2 = sd->fields[k];
- if (vd->isOverlappedWith(v2) && (*elements)[k])
- {
- error(i->loc, "overlapping initialization for field %s and %s",
- v2->toChars(), vd->toChars());
- errors = true;
- continue;
- }
- }
-
- assert(sc);
- Initializer *iz = i->value[j];
- iz = initializerSemantic(iz, sc, vd->type->addMod(t->mod), needInterpret);
- Expression *ex = initializerToExpression(iz);
- if (ex->op == TOKerror)
- {
- errors = true;
- continue;
- }
- i->value[j] = iz;
- (*elements)[fieldi] = doCopyOrMove(sc, ex);
- ++fieldi;
- }
- if (errors)
- {
- result = new ErrorInitializer();
- return;
- }
-
- StructLiteralExp *sle = new StructLiteralExp(i->loc, sd, elements, t);
- if (!sd->fill(i->loc, elements, false))
- {
- result = new ErrorInitializer();
- return;
- }
- sle->type = t;
-
- ExpInitializer *ie = new ExpInitializer(i->loc, sle);
- result = initializerSemantic(ie, sc, t, needInterpret);
- return;
- }
- else if ((t->ty == Tdelegate || (t->ty == Tpointer && t->nextOf()->ty == Tfunction)) && i->value.length == 0)
- {
- TOK tok = (t->ty == Tdelegate) ? TOKdelegate : TOKfunction;
- /* Rewrite as empty delegate literal { }
- */
- Type *tf = new TypeFunction(ParameterList(), NULL, LINKd);
- FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(i->loc, Loc(), tf, tok, NULL);
- fd->fbody = new CompoundStatement(i->loc, new Statements());
- fd->endloc = i->loc;
- Expression *e = new FuncExp(i->loc, fd);
- ExpInitializer *ie = new ExpInitializer(i->loc, e);
- result = initializerSemantic(ie, sc, t, needInterpret);
- return;
- }
-
- error(i->loc, "a struct is not a valid initializer for a %s", t->toChars());
- result = new ErrorInitializer();
- }
-
- void visit(ArrayInitializer *i)
- {
- unsigned length;
- const unsigned amax = 0x80000000;
- bool errors = false;
-
- //printf("ArrayInitializer::semantic(%s)\n", t->toChars());
- if (i->sem) // if semantic() already run
- {
- result = i;
- return;
- }
- i->sem = true;
- t = t->toBasetype();
- switch (t->ty)
- {
- case Tsarray:
- case Tarray:
- break;
-
- case Tvector:
- t = ((TypeVector *)t)->basetype;
- break;
-
- case Taarray:
- case Tstruct: // consider implicit constructor call
- {
- Expression *e;
- // note: MyStruct foo = [1:2, 3:4] is correct code if MyStruct has a this(int[int])
- if (t->ty == Taarray || i->isAssociativeArray())
- e = i->toAssocArrayLiteral();
- else
- e = initializerToExpression(i);
- if (!e) // Bugzilla 13987
- {
- error(i->loc, "cannot use array to initialize %s", t->toChars());
- goto Lerr;
- }
- ExpInitializer *ei = new ExpInitializer(e->loc, e);
- result = initializerSemantic(ei, sc, t, needInterpret);
- return;
- }
- case Tpointer:
- if (t->nextOf()->ty != Tfunction)
- break;
- /* fall through */
-
- default:
- error(i->loc, "cannot use array to initialize %s", t->toChars());
- goto Lerr;
- }
-
- i->type = t;
-
- length = 0;
- for (size_t j = 0; j < i->index.length; j++)
- {
- Expression *idx = i->index[j];
- if (idx)
- {
- sc = sc->startCTFE();
- idx = expressionSemantic(idx, sc);
- sc = sc->endCTFE();
- idx = idx->ctfeInterpret();
- i->index[j] = idx;
- const uinteger_t idxvalue = idx->toInteger();
- if (idxvalue >= amax)
- {
- error(i->loc, "array index %llu overflow", (ulonglong)idxvalue);
- errors = true;
- }
- length = (unsigned)idx->toInteger();
- if (idx->op == TOKerror)
- errors = true;
- }
-
- Initializer *val = i->value[j];
- ExpInitializer *ei = val->isExpInitializer();
- if (ei && !idx)
- ei->expandTuples = true;
- val = initializerSemantic(val, sc, t->nextOf(), needInterpret);
- if (val->isErrorInitializer())
- errors = true;
-
- ei = val->isExpInitializer();
- // found a tuple, expand it
- if (ei && ei->exp->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)ei->exp;
- i->index.remove(j);
- i->value.remove(j);
-
- for (size_t k = 0; k < te->exps->length; ++k)
- {
- Expression *e = (*te->exps)[k];
- i->index.insert(j + k, (Expression *)NULL);
- i->value.insert(j + k, new ExpInitializer(e->loc, e));
- }
- j--;
- continue;
- }
- else
- {
- i->value[j] = val;
- }
-
- length++;
- if (length == 0)
- {
- error(i->loc, "array dimension overflow");
- goto Lerr;
- }
- if (length > i->dim)
- i->dim = length;
- }
- if (t->ty == Tsarray)
- {
- uinteger_t edim = ((TypeSArray *)t)->dim->toInteger();
- if (i->dim > edim)
- {
- error(i->loc, "array initializer has %u elements, but array length is %llu", i->dim, (ulonglong)edim);
- goto Lerr;
- }
- }
- if (errors)
- goto Lerr;
- else
- {
- d_uns64 sz = t->nextOf()->size();
- bool overflow = false;
- const d_uns64 max = mulu((d_uns64)i->dim, sz, overflow);
- if (overflow || max > amax)
- {
- error(i->loc, "array dimension %llu exceeds max of %llu", (ulonglong)i->dim, (ulonglong)(amax / sz));
- goto Lerr;
- }
- result = i;
- return;
- }
-
- Lerr:
- result = new ErrorInitializer();
- }
-
- void visit(ExpInitializer *i)
- {
- //printf("ExpInitializer::semantic(%s), type = %s\n", i->exp->toChars(), t->toChars());
- if (needInterpret) sc = sc->startCTFE();
- i->exp = expressionSemantic(i->exp, sc);
- i->exp = resolveProperties(sc, i->exp);
- if (needInterpret) sc = sc->endCTFE();
- if (i->exp->op == TOKerror)
- {
- result = new ErrorInitializer();
- return;
- }
-
- unsigned int olderrors = global.errors;
- if (needInterpret)
- {
- // If the result will be implicitly cast, move the cast into CTFE
- // to avoid premature truncation of polysemous types.
- // eg real [] x = [1.1, 2.2]; should use real precision.
- if (i->exp->implicitConvTo(t))
- {
- i->exp = i->exp->implicitCastTo(sc, t);
- }
- if (!global.gag && olderrors != global.errors)
- {
- result = i;
- return;
- }
- i->exp = i->exp->ctfeInterpret();
- }
- else
- {
- i->exp = i->exp->optimize(WANTvalue);
- }
- if (!global.gag && olderrors != global.errors)
- {
- result = i; // Failed, suppress duplicate error messages
- return;
- }
-
- if (i->exp->type->ty == Ttuple && ((TypeTuple *)i->exp->type)->arguments->length == 0)
- {
- Type *et = i->exp->type;
- i->exp = new TupleExp(i->exp->loc, new Expressions());
- i->exp->type = et;
- }
- if (i->exp->op == TOKtype)
- {
- i->exp->error("initializer must be an expression, not `%s`", i->exp->toChars());
- result = new ErrorInitializer();
- return;
- }
-
- // Make sure all pointers are constants
- if (needInterpret && hasNonConstPointers(i->exp))
- {
- i->exp->error("cannot use non-constant CTFE pointer in an initializer `%s`", i->exp->toChars());
- result = new ErrorInitializer();
- return;
- }
-
- Type *tb = t->toBasetype();
- Type *ti = i->exp->type->toBasetype();
-
- if (i->exp->op == TOKtuple && i->expandTuples && !i->exp->implicitConvTo(t))
- {
- result = new ExpInitializer(i->loc, i->exp);
- return;
- }
-
- /* Look for case of initializing a static array with a too-short
- * string literal, such as:
- * char[5] foo = "abc";
- * Allow this by doing an explicit cast, which will lengthen the string
- * literal.
- */
- if (i->exp->op == TOKstring && tb->ty == Tsarray)
- {
- StringExp *se = (StringExp *)i->exp;
- Type *typeb = se->type->toBasetype();
- TY tynto = tb->nextOf()->ty;
- if (!se->committed &&
- (typeb->ty == Tarray || typeb->ty == Tsarray) &&
- (tynto == Tchar || tynto == Twchar || tynto == Tdchar) &&
- se->numberOfCodeUnits(tynto) < ((TypeSArray *)tb)->dim->toInteger())
- {
- i->exp = se->castTo(sc, t);
- goto L1;
- }
- }
-
- // Look for implicit constructor call
- if (tb->ty == Tstruct &&
- !(ti->ty == Tstruct && tb->toDsymbol(sc) == ti->toDsymbol(sc)) &&
- !i->exp->implicitConvTo(t))
- {
- StructDeclaration *sd = ((TypeStruct *)tb)->sym;
- if (sd->ctor)
- {
- // Rewrite as S().ctor(exp)
- Expression *e;
- e = new StructLiteralExp(i->loc, sd, NULL);
- e = new DotIdExp(i->loc, e, Id::ctor);
- e = new CallExp(i->loc, e, i->exp);
- e = expressionSemantic(e, sc);
- if (needInterpret)
- i->exp = e->ctfeInterpret();
- else
- i->exp = e->optimize(WANTvalue);
- }
- }
-
- // Look for the case of statically initializing an array
- // with a single member.
- if (tb->ty == Tsarray &&
- !tb->nextOf()->equals(ti->toBasetype()->nextOf()) &&
- i->exp->implicitConvTo(tb->nextOf())
- )
- {
- /* If the variable is not actually used in compile time, array creation is
- * redundant. So delay it until invocation of toExpression() or toDt().
- */
- t = tb->nextOf();
- }
-
- if (i->exp->implicitConvTo(t))
- {
- i->exp = i->exp->implicitCastTo(sc, t);
- }
- else
- {
- // Look for mismatch of compile-time known length to emit
- // better diagnostic message, as same as AssignExp::semantic.
- if (tb->ty == Tsarray &&
- i->exp->implicitConvTo(tb->nextOf()->arrayOf()) > MATCHnomatch)
- {
- uinteger_t dim1 = ((TypeSArray *)tb)->dim->toInteger();
- uinteger_t dim2 = dim1;
- if (i->exp->op == TOKarrayliteral)
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)i->exp;
- dim2 = ale->elements ? ale->elements->length : 0;
- }
- else if (i->exp->op == TOKslice)
- {
- Type *tx = toStaticArrayType((SliceExp *)i->exp);
- if (tx)
- dim2 = ((TypeSArray *)tx)->dim->toInteger();
- }
- if (dim1 != dim2)
- {
- i->exp->error("mismatched array lengths, %d and %d", (int)dim1, (int)dim2);
- i->exp = new ErrorExp();
- }
- }
- i->exp = i->exp->implicitCastTo(sc, t);
- }
- L1:
- if (i->exp->op == TOKerror)
- {
- result = i;
- return;
- }
- if (needInterpret)
- i->exp = i->exp->ctfeInterpret();
- else
- i->exp = i->exp->optimize(WANTvalue);
- //printf("-ExpInitializer::semantic(): "); i->exp->print();
- result = i;
- }
-};
-
-// Performs semantic analisys on Initializer AST nodes
-Initializer *initializerSemantic(Initializer *init, Scope *sc, Type *t, NeedInterpret needInterpret)
-{
- InitializerSemanticVisitor v = InitializerSemanticVisitor(sc, t, needInterpret);
- init->accept(&v);
- return v.result;
-}
-
-class InferTypeVisitor : public Visitor
-{
-public:
- Initializer *result;
- Scope *sc;
-
- InferTypeVisitor(Scope *sc)
- {
- this->result = NULL;
- this->sc = sc;
- }
-
- void visit(ErrorInitializer *i)
- {
- result = i;
- }
-
- void visit(VoidInitializer *i)
- {
- error(i->loc, "cannot infer type from void initializer");
- result = new ErrorInitializer();
- }
-
- void visit(StructInitializer *i)
- {
- error(i->loc, "cannot infer type from struct initializer");
- result = new ErrorInitializer();
- }
-
- void visit(ArrayInitializer *init)
- {
- //printf("ArrayInitializer::inferType() %s\n", init->toChars());
- Expressions *keys = NULL;
- Expressions *values;
- if (init->isAssociativeArray())
- {
- keys = new Expressions();
- keys->setDim(init->value.length);
- values = new Expressions();
- values->setDim(init->value.length);
-
- for (size_t i = 0; i < init->value.length; i++)
- {
- Expression *e = init->index[i];
- if (!e)
- goto Lno;
- (*keys)[i] = e;
-
- Initializer *iz = init->value[i];
- if (!iz)
- goto Lno;
- iz = inferType(iz, sc);
- if (iz->isErrorInitializer())
- {
- result = iz;
- return;
- }
- assert(iz->isExpInitializer());
- (*values)[i] = ((ExpInitializer *)iz)->exp;
- assert((*values)[i]->op != TOKerror);
- }
-
- Expression *e = new AssocArrayLiteralExp(init->loc, keys, values);
- ExpInitializer *ei = new ExpInitializer(init->loc, e);
- result = inferType(ei, sc);
- return;
- }
- else
- {
- Expressions *elements = new Expressions();
- elements->setDim(init->value.length);
- elements->zero();
-
- for (size_t i = 0; i < init->value.length; i++)
- {
- assert(!init->index[i]); // already asserted by isAssociativeArray()
-
- Initializer *iz = init->value[i];
- if (!iz)
- goto Lno;
- iz = inferType(iz, sc);
- if (iz->isErrorInitializer())
- {
- result = iz;
- return;
- }
- assert(iz->isExpInitializer());
- (*elements)[i] = ((ExpInitializer *)iz)->exp;
- assert((*elements)[i]->op != TOKerror);
- }
-
- Expression *e = new ArrayLiteralExp(init->loc, NULL, elements);
- ExpInitializer *ei = new ExpInitializer(init->loc, e);
- result = inferType(ei, sc);
- return;
- }
- Lno:
- if (keys)
- {
- delete keys;
- delete values;
- error(init->loc, "not an associative array initializer");
- }
- else
- {
- error(init->loc, "cannot infer type from array initializer");
- }
- result = new ErrorInitializer();
- }
-
- void visit(ExpInitializer *init)
- {
- //printf("ExpInitializer::inferType() %s\n", init->toChars());
- init->exp = expressionSemantic(init->exp, sc);
- init->exp = resolveProperties(sc, init->exp);
-
- if (init->exp->op == TOKscope)
- {
- ScopeExp *se = (ScopeExp *)init->exp;
- TemplateInstance *ti = se->sds->isTemplateInstance();
- if (ti && ti->semanticRun == PASSsemantic && !ti->aliasdecl)
- se->error("cannot infer type from %s %s, possible circular dependency", se->sds->kind(), se->toChars());
- else
- se->error("cannot infer type from %s %s", se->sds->kind(), se->toChars());
- result = new ErrorInitializer();
- return;
- }
-
- // Give error for overloaded function addresses
- bool hasOverloads = false;
- if (FuncDeclaration *f = isFuncAddress(init->exp, &hasOverloads))
- {
- if (f->checkForwardRef(init->loc))
- {
- result = new ErrorInitializer();
- return;
- }
-
- if (hasOverloads && !f->isUnique())
- {
- init->exp->error("cannot infer type from overloaded function symbol %s", init->exp->toChars());
- result = new ErrorInitializer();
- return;
- }
- }
- if (init->exp->op == TOKaddress)
- {
- AddrExp *ae = (AddrExp *)init->exp;
- if (ae->e1->op == TOKoverloadset)
- {
- init->exp->error("cannot infer type from overloaded function symbol %s", init->exp->toChars());
- result = new ErrorInitializer();
- return;
- }
- }
-
- if (init->exp->op == TOKerror)
- {
- result = new ErrorInitializer();
- return;
- }
- if (!init->exp->type)
- {
- result = new ErrorInitializer();
- return;
- }
- result = init;
- }
-};
-
-/* Translates to an expression to infer type.
- * Returns ExpInitializer or ErrorInitializer.
- */
-Initializer *inferType(Initializer *init, Scope *sc)
-{
- InferTypeVisitor v = InferTypeVisitor(sc);
- init->accept(&v);
- return v.result;
-}
-
-class InitToExpressionVisitor : public Visitor
-{
-public:
- Expression *result;
- Type *itype;
-
- InitToExpressionVisitor(Type *itype)
- {
- this->result = NULL;
- this->itype = itype;
- }
-
- void visit(ErrorInitializer *)
- {
- result = new ErrorExp();
- }
-
- void visit(VoidInitializer *)
- {
- result = NULL;
- }
-
- /***************************************
- * This works by transforming a struct initializer into
- * a struct literal. In the future, the two should be the
- * same thing.
- */
- void visit(StructInitializer *)
- {
- // cannot convert to an expression without target 'ad'
- result = NULL;
- }
-
- /********************************
- * If possible, convert array initializer to array literal.
- * Otherwise return NULL.
- */
-
- void visit(ArrayInitializer *init)
- {
- //printf("ArrayInitializer::toExpression(), dim = %d\n", init->length);
- //static int i; if (++i == 2) halt();
-
- Expressions *elements;
- unsigned edim;
- const unsigned amax = 0x80000000;
- Type *t = NULL;
- if (init->type)
- {
- if (init->type == Type::terror)
- {
- result = new ErrorExp();
- return;
- }
-
- t = init->type->toBasetype();
- switch (t->ty)
- {
- case Tvector:
- t = ((TypeVector *)t)->basetype;
- /* fall through */
-
- case Tsarray:
- {
- uinteger_t adim = ((TypeSArray *)t)->dim->toInteger();
- if (adim >= amax)
- goto Lno;
- edim = (unsigned)adim;
- break;
- }
-
- case Tpointer:
- case Tarray:
- edim = init->dim;
- break;
-
- default:
- assert(0);
- }
- }
- else
- {
- edim = (unsigned)init->value.length;
- for (size_t i = 0, j = 0; i < init->value.length; i++, j++)
- {
- if (init->index[i])
- {
- if (init->index[i]->op == TOKint64)
- {
- const uinteger_t idxval = init->index[i]->toInteger();
- if (idxval >= amax)
- goto Lno;
- j = (size_t)idxval;
- }
- else
- goto Lno;
- }
- if (j >= edim)
- edim = (unsigned)(j + 1);
- }
- }
-
- elements = new Expressions();
- elements->setDim(edim);
- elements->zero();
- for (size_t i = 0, j = 0; i < init->value.length; i++, j++)
- {
- if (init->index[i])
- j = (size_t)(init->index[i])->toInteger();
- assert(j < edim);
- Initializer *iz = init->value[i];
- if (!iz)
- goto Lno;
- Expression *ex = initializerToExpression(iz);
- if (!ex)
- {
- goto Lno;
- }
- (*elements)[j] = ex;
- }
-
- /* Fill in any missing elements with the default initializer
- */
- {
- Expression *_init = NULL;
- for (size_t i = 0; i < edim; i++)
- {
- if (!(*elements)[i])
- {
- if (!init->type)
- goto Lno;
- if (!_init)
- _init = ((TypeNext *)t)->next->defaultInit();
- (*elements)[i] = _init;
- }
- }
-
- /* Expand any static array initializers that are a single expression
- * into an array of them
- */
- if (t)
- {
- Type *tn = t->nextOf()->toBasetype();
- if (tn->ty == Tsarray)
- {
- size_t dim = ((TypeSArray *)tn)->dim->toInteger();
- Type *te = tn->nextOf()->toBasetype();
- for (size_t i = 0; i < elements->length; i++)
- {
- Expression *e = (*elements)[i];
- if (te->equals(e->type))
- {
- Expressions *elements2 = new Expressions();
- elements2->setDim(dim);
- for (size_t j = 0; j < dim; j++)
- (*elements2)[j] = e;
- e = new ArrayLiteralExp(e->loc, tn, elements2);
- (*elements)[i] = e;
- }
- }
- }
- }
-
- /* If any elements are errors, then the whole thing is an error
- */
- for (size_t i = 0; i < edim; i++)
- {
- Expression *e = (*elements)[i];
- if (e->op == TOKerror)
- {
- result = e;
- return;
- }
- }
-
- Expression *e = new ArrayLiteralExp(init->loc, init->type, elements);
- result = e;
- return;
- }
-
- Lno:
- result = NULL;
- }
-
- void visit(ExpInitializer *i)
- {
- if (itype)
- {
- //printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype->toChars(), i->exp->toChars());
- Type *tb = itype->toBasetype();
- Expression *e = (i->exp->op == TOKconstruct || i->exp->op == TOKblit) ? ((AssignExp *)i->exp)->e2 : i->exp;
- if (tb->ty == Tsarray && e->implicitConvTo(tb->nextOf()))
- {
- TypeSArray *tsa = (TypeSArray *)tb;
- size_t d = (size_t)tsa->dim->toInteger();
- Expressions *elements = new Expressions();
- elements->setDim(d);
- for (size_t j = 0; j < d; j++)
- (*elements)[j] = e;
- ArrayLiteralExp *ae = new ArrayLiteralExp(e->loc, itype, elements);
- result = ae;
- return;
- }
- }
- result = i->exp;
- }
-};
-
-Expression *initializerToExpression(Initializer *i, Type *t)
-{
- InitToExpressionVisitor v = InitToExpressionVisitor(t);
- i->accept(&v);
- return v.result;
-}
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
new file mode 100644
index 0000000..ae8bde2
--- /dev/null
+++ b/gcc/d/dmd/initsem.d
@@ -0,0 +1,1268 @@
+/**
+ * Semantic analysis of initializers.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/initsem.d, _initsem.d)
+ * Documentation: https://dlang.org/phobos/dmd_initsem.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/initsem.d
+ */
+
+module dmd.initsem;
+
+import core.stdc.stdio;
+import core.checkedint;
+
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.dcast;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.mtype;
+import dmd.opover;
+import dmd.statement;
+import dmd.target;
+import dmd.tokens;
+import dmd.typesem;
+
+/********************************
+ * If possible, convert array initializer to associative array initializer.
+ *
+ * Params:
+ * ai = array initializer to be converted
+ *
+ * Returns:
+ * The converted associative array initializer or ErrorExp if `ai`
+ * is not an associative array initializer.
+ */
+Expression toAssocArrayLiteral(ArrayInitializer ai)
+{
+ Expression e;
+ //printf("ArrayInitializer::toAssocArrayInitializer()\n");
+ //static int i; if (++i == 2) assert(0);
+ const dim = ai.value.dim;
+ auto keys = new Expressions(dim);
+ auto values = new Expressions(dim);
+ for (size_t i = 0; i < dim; i++)
+ {
+ e = ai.index[i];
+ if (!e)
+ goto Lno;
+ (*keys)[i] = e;
+ Initializer iz = ai.value[i];
+ if (!iz)
+ goto Lno;
+ e = iz.initializerToExpression();
+ if (!e)
+ goto Lno;
+ (*values)[i] = e;
+ }
+ e = new AssocArrayLiteralExp(ai.loc, keys, values);
+ return e;
+Lno:
+ error(ai.loc, "not an associative array initializer");
+ return ErrorExp.get();
+}
+
+/******************************************
+ * Perform semantic analysis on init.
+ * Params:
+ * init = Initializer AST node
+ * sc = context
+ * tx = type that the initializer needs to become. If tx is an incomplete
+ * type and the initializer completes it, it is updated to be the
+ * complete type. ImportC has incomplete types
+ * needInterpret = if CTFE needs to be run on this,
+ * such as if it is the initializer for a const declaration
+ * Returns:
+ * `Initializer` with completed semantic analysis, `ErrorInitializer` if errors
+ * were encountered
+ */
+extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedInterpret needInterpret)
+{
+ Type t = tx;
+
+ static Initializer err()
+ {
+ return new ErrorInitializer();
+ }
+
+ Initializer visitVoid(VoidInitializer i)
+ {
+ i.type = t;
+ return i;
+ }
+
+ Initializer visitError(ErrorInitializer i)
+ {
+ return i;
+ }
+
+ Initializer visitStruct(StructInitializer i)
+ {
+ //printf("StructInitializer::semantic(t = %s) %s\n", t.toChars(), i.toChars());
+ /* This works by replacing the StructInitializer with an ExpInitializer.
+ */
+ t = t.toBasetype();
+ if (t.ty == Tsarray && t.nextOf().toBasetype().ty == Tstruct)
+ t = t.nextOf().toBasetype();
+ if (auto ts = t.isTypeStruct())
+ {
+ StructDeclaration sd = ts.sym;
+ // check if the sd has a regular ctor (user defined non-copy ctor)
+ // that is not disabled.
+ if (sd.hasRegularCtor(true))
+ {
+ error(i.loc, "%s `%s` has constructors, cannot use `{ initializers }`, use `%s( initializers )` instead", sd.kind(), sd.toChars(), sd.toChars());
+ return err();
+ }
+ sd.size(i.loc);
+ if (sd.sizeok != Sizeok.done)
+ return err();
+ const nfields = sd.nonHiddenFields();
+ //expandTuples for non-identity arguments?
+ auto elements = new Expressions(nfields);
+ auto elems = (*elements)[];
+ foreach (ref elem; elems)
+ elem = null;
+
+ // Run semantic for explicitly given initializers
+ // TODO: this part is slightly different from StructLiteralExp::semantic.
+ bool errors = false;
+ size_t fieldi = 0;
+ foreach (j, id; i.field[])
+ {
+ if (id)
+ {
+ /* Determine `fieldi` that `id` matches
+ */
+ Dsymbol s = sd.search(i.loc, id);
+ if (!s)
+ {
+ s = sd.search_correct(id);
+ const initLoc = i.value[j].loc;
+ if (s)
+ error(initLoc, "`%s` is not a member of `%s`, did you mean %s `%s`?", id.toChars(), sd.toChars(), s.kind(), s.toChars());
+ else
+ error(initLoc, "`%s` is not a member of `%s`", id.toChars(), sd.toChars());
+ return err();
+ }
+ s.checkDeprecated(i.loc, sc);
+ s = s.toAlias();
+
+ // Find out which field index `s` is
+ for (fieldi = 0; 1; fieldi++)
+ {
+ if (fieldi >= nfields)
+ {
+ error(i.loc, "`%s.%s` is not a per-instance initializable field", sd.toChars(), s.toChars());
+ return err();
+ }
+ if (s == sd.fields[fieldi])
+ break;
+ }
+ }
+ else if (fieldi >= nfields)
+ {
+ error(i.loc, "too many initializers for `%s`", sd.toChars());
+ return err();
+ }
+
+ VarDeclaration vd = sd.fields[fieldi];
+ if (elems[fieldi])
+ {
+ error(i.loc, "duplicate initializer for field `%s`", vd.toChars());
+ errors = true;
+ continue;
+ }
+
+ // Check for @safe violations
+ if (vd.type.hasPointers)
+ {
+ if ((t.alignment() < target.ptrsize ||
+ (vd.offset & (target.ptrsize - 1))) &&
+ sc.func && sc.func.setUnsafe())
+ {
+ error(i.loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code",
+ sd.toChars(), vd.toChars());
+ errors = true;
+ }
+ }
+
+ // Check for overlapping initializations (can happen with unions)
+ foreach (k, v2; sd.fields[0 .. nfields])
+ {
+ if (vd.isOverlappedWith(v2) && elems[k])
+ {
+ error(i.loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
+ errors = true;
+ continue;
+ }
+ }
+
+ // Convert initializer to Expression `ex`
+ assert(sc);
+ auto tm = vd.type.addMod(t.mod);
+ auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret);
+ auto ex = iz.initializerToExpression();
+ if (ex.op == TOK.error)
+ {
+ errors = true;
+ continue;
+ }
+
+ i.value[j] = iz;
+ elems[fieldi] = doCopyOrMove(sc, ex);
+ ++fieldi;
+ }
+ if (errors)
+ return err();
+
+ // Make a StructLiteralExp out of elements[]
+ auto sle = new StructLiteralExp(i.loc, sd, elements, t);
+ if (!sd.fill(i.loc, elements, false))
+ return err();
+ sle.type = t;
+ auto ie = new ExpInitializer(i.loc, sle);
+ return ie.initializerSemantic(sc, t, needInterpret);
+ }
+ else if ((t.ty == Tdelegate || t.isPtrToFunction()) && i.value.dim == 0)
+ {
+ const tok = (t.ty == Tdelegate) ? TOK.delegate_ : TOK.function_;
+ /* Rewrite as empty delegate literal { }
+ */
+ Type tf = new TypeFunction(ParameterList(), null, LINK.d);
+ auto fd = new FuncLiteralDeclaration(i.loc, Loc.initial, tf, tok, null);
+ fd.fbody = new CompoundStatement(i.loc, new Statements());
+ fd.endloc = i.loc;
+ Expression e = new FuncExp(i.loc, fd);
+ auto ie = new ExpInitializer(i.loc, e);
+ return ie.initializerSemantic(sc, t, needInterpret);
+ }
+ if (t.ty != Terror)
+ error(i.loc, "a struct is not a valid initializer for a `%s`", t.toChars());
+ return err();
+ }
+
+ Initializer visitArray(ArrayInitializer i)
+ {
+ uint length;
+ const(uint) amax = 0x80000000;
+ bool errors = false;
+ //printf("ArrayInitializer::semantic(%s)\n", t.toChars());
+ if (i.sem) // if semantic() already run
+ {
+ return i;
+ }
+ i.sem = true;
+ t = t.toBasetype();
+ switch (t.ty)
+ {
+ case Tsarray:
+ case Tarray:
+ break;
+ case Tvector:
+ t = (cast(TypeVector)t).basetype;
+ break;
+ case Taarray:
+ case Tstruct: // consider implicit constructor call
+ {
+ Expression e;
+ // note: MyStruct foo = [1:2, 3:4] is correct code if MyStruct has a this(int[int])
+ if (t.ty == Taarray || i.isAssociativeArray())
+ e = i.toAssocArrayLiteral();
+ else
+ e = i.initializerToExpression();
+ // Bugzilla 13987
+ if (!e)
+ {
+ error(i.loc, "cannot use array to initialize `%s`", t.toChars());
+ return err();
+ }
+ auto ei = new ExpInitializer(e.loc, e);
+ return ei.initializerSemantic(sc, t, needInterpret);
+ }
+ case Tpointer:
+ if (t.nextOf().ty != Tfunction)
+ break;
+ goto default;
+ default:
+ error(i.loc, "cannot use array to initialize `%s`", t.toChars());
+ return err();
+ }
+ i.type = t;
+ length = 0;
+ for (size_t j = 0; j < i.index.dim; j++)
+ {
+ Expression idx = i.index[j];
+ if (idx)
+ {
+ sc = sc.startCTFE();
+ idx = idx.expressionSemantic(sc);
+ sc = sc.endCTFE();
+ idx = idx.ctfeInterpret();
+ i.index[j] = idx;
+ const uinteger_t idxvalue = idx.toInteger();
+ if (idxvalue >= amax)
+ {
+ error(i.loc, "array index %llu overflow", idxvalue);
+ errors = true;
+ }
+ length = cast(uint)idxvalue;
+ if (idx.op == TOK.error)
+ errors = true;
+ }
+ Initializer val = i.value[j];
+ ExpInitializer ei = val.isExpInitializer();
+ if (ei && !idx)
+ ei.expandTuples = true;
+ auto tn = t.nextOf();
+ val = val.initializerSemantic(sc, tn, needInterpret);
+ if (val.isErrorInitializer())
+ errors = true;
+ ei = val.isExpInitializer();
+ // found a tuple, expand it
+ if (ei && ei.exp.op == TOK.tuple)
+ {
+ TupleExp te = cast(TupleExp)ei.exp;
+ i.index.remove(j);
+ i.value.remove(j);
+ for (size_t k = 0; k < te.exps.dim; ++k)
+ {
+ Expression e = (*te.exps)[k];
+ i.index.insert(j + k, cast(Expression)null);
+ i.value.insert(j + k, new ExpInitializer(e.loc, e));
+ }
+ j--;
+ continue;
+ }
+ else
+ {
+ i.value[j] = val;
+ }
+ length++;
+ if (length == 0)
+ {
+ error(i.loc, "array dimension overflow");
+ return err();
+ }
+ if (length > i.dim)
+ i.dim = length;
+ }
+ if (t.ty == Tsarray)
+ {
+ uinteger_t edim = (cast(TypeSArray)t).dim.toInteger();
+ if (i.dim > edim)
+ {
+ error(i.loc, "array initializer has %u elements, but array length is %llu", i.dim, edim);
+ return err();
+ }
+ }
+ if (errors)
+ return err();
+
+ const sz = t.nextOf().size();
+ bool overflow;
+ const max = mulu(i.dim, sz, overflow);
+ if (overflow || max >= amax)
+ {
+ error(i.loc, "array dimension %llu exceeds max of %llu", ulong(i.dim), ulong(amax / sz));
+ return err();
+ }
+ return i;
+ }
+
+ Initializer visitExp(ExpInitializer i)
+ {
+ //printf("ExpInitializer::semantic(%s), type = %s\n", i.exp.toChars(), t.toChars());
+ if (needInterpret)
+ sc = sc.startCTFE();
+ i.exp = i.exp.expressionSemantic(sc);
+ i.exp = resolveProperties(sc, i.exp);
+ if (needInterpret)
+ sc = sc.endCTFE();
+ if (i.exp.op == TOK.error)
+ return err();
+ uint olderrors = global.errors;
+ /* Save the expression before ctfe
+ * Otherwise the error message would contain for example "&[0][0]" instead of "new int"
+ * Regression: https://issues.dlang.org/show_bug.cgi?id=21687
+ */
+ Expression currExp = i.exp;
+ if (needInterpret)
+ {
+ // If the result will be implicitly cast, move the cast into CTFE
+ // to avoid premature truncation of polysemous types.
+ // eg real [] x = [1.1, 2.2]; should use real precision.
+ if (i.exp.implicitConvTo(t))
+ {
+ i.exp = i.exp.implicitCastTo(sc, t);
+ }
+ if (!global.gag && olderrors != global.errors)
+ {
+ return i;
+ }
+ i.exp = i.exp.ctfeInterpret();
+ if (i.exp.op == TOK.voidExpression)
+ error(i.loc, "variables cannot be initialized with an expression of type `void`. Use `void` initialization instead.");
+ }
+ else
+ {
+ i.exp = i.exp.optimize(WANTvalue);
+ }
+ if (!global.gag && olderrors != global.errors)
+ {
+ return i; // Failed, suppress duplicate error messages
+ }
+ if (i.exp.type.ty == Ttuple && (cast(TypeTuple)i.exp.type).arguments.dim == 0)
+ {
+ Type et = i.exp.type;
+ i.exp = new TupleExp(i.exp.loc, new Expressions());
+ i.exp.type = et;
+ }
+ if (i.exp.op == TOK.type)
+ {
+ i.exp.error("initializer must be an expression, not `%s`", i.exp.toChars());
+ return err();
+ }
+ // Make sure all pointers are constants
+ if (needInterpret && hasNonConstPointers(i.exp))
+ {
+ i.exp.error("cannot use non-constant CTFE pointer in an initializer `%s`", currExp.toChars());
+ return err();
+ }
+ Type tb = t.toBasetype();
+ Type ti = i.exp.type.toBasetype();
+ if (i.exp.op == TOK.tuple && i.expandTuples && !i.exp.implicitConvTo(t))
+ {
+ return new ExpInitializer(i.loc, i.exp);
+ }
+ /* Look for case of initializing a static array with a too-short
+ * string literal, such as:
+ * char[5] foo = "abc";
+ * Allow this by doing an explicit cast, which will lengthen the string
+ * literal.
+ */
+ if (i.exp.op == TOK.string_ && tb.ty == Tsarray)
+ {
+ StringExp se = cast(StringExp)i.exp;
+ Type typeb = se.type.toBasetype();
+ TY tynto = tb.nextOf().ty;
+ if (!se.committed &&
+ (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
+ se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
+ {
+ i.exp = se.castTo(sc, t);
+ goto L1;
+ }
+ }
+
+ /* C11 6.7.9-14..15
+ * Initialize an array of unknown size with a string.
+ * ImportC regards Tarray as an array of unknown size.
+ * Change to static array of known size
+ */
+ if (sc.flags & SCOPE.Cfile && i.exp.op == TOK.string_ && tb.ty == Tarray)
+ {
+ StringExp se = i.exp.isStringExp();
+ auto ts = new TypeSArray(tb.nextOf(), new IntegerExp(Loc.initial, se.len + 1, Type.tsize_t));
+ t = typeSemantic(ts, Loc.initial, sc);
+ i.exp.type = t;
+ tx = t;
+ }
+
+ // Look for implicit constructor call
+ if (tb.ty == Tstruct && !(ti.ty == Tstruct && tb.toDsymbol(sc) == ti.toDsymbol(sc)) && !i.exp.implicitConvTo(t))
+ {
+ StructDeclaration sd = (cast(TypeStruct)tb).sym;
+ if (sd.ctor)
+ {
+ // Rewrite as S().ctor(exp)
+ Expression e;
+ e = new StructLiteralExp(i.loc, sd, null);
+ e = new DotIdExp(i.loc, e, Id.ctor);
+ e = new CallExp(i.loc, e, i.exp);
+ e = e.expressionSemantic(sc);
+ if (needInterpret)
+ i.exp = e.ctfeInterpret();
+ else
+ i.exp = e.optimize(WANTvalue);
+ }
+ else if (search_function(sd, Id.call))
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=1547
+ *
+ * Look for static opCall
+ *
+ * Rewrite as:
+ * i.exp = typeof(sd).opCall(arguments)
+ */
+
+ Expression e = typeDotIdExp(i.loc, sd.type, Id.call);
+ e = new CallExp(i.loc, e, i.exp);
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ if (needInterpret)
+ i.exp = e.ctfeInterpret();
+ else
+ i.exp = e.optimize(WANTvalue);
+ }
+ }
+ // Look for the case of statically initializing an array
+ // with a single member.
+ if (tb.ty == Tsarray && !tb.nextOf().equals(ti.toBasetype().nextOf()) && i.exp.implicitConvTo(tb.nextOf()))
+ {
+ /* If the variable is not actually used in compile time, array creation is
+ * redundant. So delay it until invocation of toExpression() or toDt().
+ */
+ t = tb.nextOf();
+ }
+ if (i.exp.implicitConvTo(t))
+ {
+ i.exp = i.exp.implicitCastTo(sc, t);
+ }
+ else
+ {
+ // Look for mismatch of compile-time known length to emit
+ // better diagnostic message, as same as AssignExp::semantic.
+ if (tb.ty == Tsarray && i.exp.implicitConvTo(tb.nextOf().arrayOf()) > MATCH.nomatch)
+ {
+ uinteger_t dim1 = (cast(TypeSArray)tb).dim.toInteger();
+ uinteger_t dim2 = dim1;
+ if (i.exp.op == TOK.arrayLiteral)
+ {
+ ArrayLiteralExp ale = cast(ArrayLiteralExp)i.exp;
+ dim2 = ale.elements ? ale.elements.dim : 0;
+ }
+ else if (i.exp.op == TOK.slice)
+ {
+ Type tx = toStaticArrayType(cast(SliceExp)i.exp);
+ if (tx)
+ dim2 = (cast(TypeSArray)tx).dim.toInteger();
+ }
+ if (dim1 != dim2)
+ {
+ i.exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
+ i.exp = ErrorExp.get();
+ }
+ }
+ i.exp = i.exp.implicitCastTo(sc, t);
+ }
+ L1:
+ if (i.exp.op == TOK.error)
+ {
+ return i;
+ }
+ if (needInterpret)
+ i.exp = i.exp.ctfeInterpret();
+ else
+ i.exp = i.exp.optimize(WANTvalue);
+ //printf("-ExpInitializer::semantic(): "); i.exp.print();
+ return i;
+ }
+
+ Initializer visitC(CInitializer ci)
+ {
+ if (ci.sem) // if semantic() already run
+ return ci;
+ //printf("CInitializer::semantic() (%s) %s\n", t.toChars(), ci.toChars());
+ ci.sem = true;
+ t = t.toBasetype();
+ ci.type = t; // later passes will need this
+
+ auto dil = ci.initializerList[];
+ size_t i = 0; // index into dil[]
+ const uint amax = 0x8000_0000;
+ bool errors;
+
+ /* If `{ expression }` return the expression initializer
+ */
+ ExpInitializer isBraceExpression()
+ {
+ return (dil.length == 1 && !dil[0].designatorList)
+ ? dil[0].initializer.isExpInitializer()
+ : null;
+ }
+
+ /* Convert struct initializer into ExpInitializer
+ */
+ Initializer structs(TypeStruct ts)
+ {
+ //printf("structs %s\n", ts.toChars());
+ StructDeclaration sd = ts.sym;
+ sd.size(ci.loc);
+ if (sd.sizeok != Sizeok.done)
+ {
+ errors = true;
+ return err();
+ }
+ const nfields = sd.nonHiddenFields();
+ auto elements = new Expressions(nfields);
+ auto elems = (*elements)[];
+ foreach (ref elem; elems)
+ elem = null;
+
+ FieldLoop:
+ for (size_t fieldi = 0; fieldi < nfields; ++fieldi)
+ {
+ if (i == dil.length)
+ break;
+
+ auto di = dil[i];
+ if (di.designatorList)
+ {
+ error(ci.loc, "C designator-list not supported yet");
+ errors = true;
+ break;
+ }
+
+ VarDeclaration vd = sd.fields[fieldi];
+
+ // Check for overlapping initializations (can happen with unions)
+ foreach (k, v2; sd.fields[0 .. nfields])
+ {
+ if (vd.isOverlappedWith(v2) && elems[k])
+ {
+ continue FieldLoop; // skip it
+ }
+ }
+
+ ++i;
+
+ // Convert initializer to Expression `ex`
+ assert(sc);
+ auto tm = vd.type.addMod(ts.mod);
+ auto iz = di.initializer.initializerSemantic(sc, tm, needInterpret);
+ auto ex = iz.initializerToExpression();
+ if (ex.op == TOK.error)
+ {
+ errors = true;
+ continue;
+ }
+
+ elems[fieldi] = ex;
+ }
+ if (errors)
+ return err();
+
+ // Make a StructLiteralExp out of elements[]
+ Type tx = ts;
+ auto sle = new StructLiteralExp(ci.loc, sd, elements, tx);
+ if (!sd.fill(ci.loc, elements, false))
+ return err();
+ sle.type = tx;
+ auto ie = new ExpInitializer(ci.loc, sle);
+ return ie.initializerSemantic(sc, tx, needInterpret);
+ }
+
+ if (auto ts = t.isTypeStruct())
+ {
+ auto ei = structs(ts);
+ if (errors)
+ return err();
+ if (i < dil.length)
+ {
+ error(ci.loc, "%d extra initializer(s) for `struct %s`", cast(int)(dil.length - i), ts.toChars());
+ return err();
+ }
+ return ei;
+ }
+
+ auto tsa = t.isTypeSArray();
+ auto ta = t.isTypeDArray();
+ if (!(tsa || ta))
+ {
+ /* Not an array. See if it is `{ exp }` which can be
+ * converted to an ExpInitializer
+ */
+ if (ExpInitializer ei = isBraceExpression())
+ {
+ return ei.initializerSemantic(sc, t, needInterpret);
+ }
+
+ error(ci.loc, "C non-array initializer (%s) %s not supported yet", t.toChars(), ci.toChars());
+ return err();
+ }
+
+ /* If it's an array of integral being initialized by `{ string }`
+ * replace with `string`
+ */
+ auto tn = t.nextOf();
+ if (tn.isintegral())
+ {
+ if (ExpInitializer ei = isBraceExpression())
+ {
+ if (ei.exp.isStringExp())
+ return ei.initializerSemantic(sc, t, needInterpret);
+ }
+ }
+
+ /* Support recursion to handle un-braced array initializers
+ * Params:
+ * t = element type
+ * dim = max number of elements
+ * Returns:
+ * # of elements in array
+ */
+ size_t array(Type t, size_t dim)
+ {
+ //printf(" type %s i %d dim %d dil.length = %d\n", t.toChars(), cast(int)i, cast(int)dim, cast(int)dil.length);
+ auto tn = t.nextOf().toBasetype();
+ if (auto tna = tn.isTypeDArray())
+ {
+ // C11 6.2.5-20 "element type shall be complete whenever the array type is specified"
+ error(ci.loc, "incomplete element type `%s` not allowed", tna.toChars());
+ errors = true;
+ return 1;
+ }
+ if (i == dil.length)
+ return 0;
+ size_t n;
+ auto tnsa = tn.isTypeSArray();
+ const nelems = tnsa ? cast(size_t)tnsa.dim.toInteger() : 0;
+
+ foreach (j; 0 .. dim)
+ {
+ auto di = dil[i];
+ if (di.designatorList)
+ {
+ error(ci.loc, "C designator-list not supported yet");
+ errors = true;
+ break;
+ }
+ if (tnsa && di.initializer.isExpInitializer())
+ {
+ // no braces enclosing array initializer, so recurse
+ array(tnsa, nelems);
+ }
+ else if (auto tns = tn.isTypeStruct())
+ {
+ dil[n].initializer = structs(tns);
+ }
+ else
+ {
+ ++i;
+ auto tnx = tn; // in case initializerSemantic tries to change it
+ di.initializer = di.initializer.initializerSemantic(sc, tnx, needInterpret);
+ if (di.initializer.isErrorInitializer())
+ errors = true;
+ assert(tnx == tn); // sub-types should not be modified
+ }
+ ++n;
+ if (i == dil.length)
+ break;
+ }
+ //printf(" n: %d i: %d\n", cast(int)n, cast(int)i);
+ return n;
+ }
+
+ size_t dim = ta ? dil.length : cast(size_t)tsa.dim.toInteger();
+ auto n = array(t, dim);
+
+ if (errors)
+ return err();
+
+ if (ta) // array of unknown length
+ {
+ // Change to array of known length
+ tsa = new TypeSArray(tn, new IntegerExp(Loc.initial, n, Type.tsize_t));
+ tx = tsa; // rewrite caller's type
+ ci.type = tsa; // remember for later passes
+ }
+ const uinteger_t edim = tsa.dim.toInteger();
+ if (i < dil.length)
+ {
+ error(ci.loc, "%d extra initializer(s) for static array length of %d", cast(int)(dil.length - i), cast(int)edim);
+ return err();
+ }
+
+ const sz = tn.size(); // element size
+ bool overflow;
+ const max = mulu(edim, sz, overflow);
+ if (overflow || max >= amax)
+ {
+ error(ci.loc, "array dimension %llu exceeds max of %llu", ulong(edim), ulong(amax / sz));
+ return err();
+ }
+
+ return ci;
+ }
+
+ final switch (init.kind)
+ {
+ case InitKind.void_: return visitVoid (cast( VoidInitializer)init);
+ case InitKind.error: return visitError (cast( ErrorInitializer)init);
+ case InitKind.struct_: return visitStruct(cast(StructInitializer)init);
+ case InitKind.array: return visitArray (cast( ArrayInitializer)init);
+ case InitKind.exp: return visitExp (cast( ExpInitializer)init);
+ case InitKind.C_: return visitC (cast( CInitializer)init);
+ }
+}
+
+/***********************
+ * Translate init to an `Expression` in order to infer the type.
+ * Params:
+ * init = `Initializer` AST node
+ * sc = context
+ * Returns:
+ * an equivalent `ExpInitializer` if successful, or `ErrorInitializer` if it cannot be translated
+ */
+Initializer inferType(Initializer init, Scope* sc)
+{
+ Initializer visitVoid(VoidInitializer i)
+ {
+ error(i.loc, "cannot infer type from void initializer");
+ return new ErrorInitializer();
+ }
+
+ Initializer visitError(ErrorInitializer i)
+ {
+ return i;
+ }
+
+ Initializer visitStruct(StructInitializer i)
+ {
+ error(i.loc, "cannot infer type from struct initializer");
+ return new ErrorInitializer();
+ }
+
+ Initializer visitArray(ArrayInitializer init)
+ {
+ //printf("ArrayInitializer::inferType() %s\n", toChars());
+ Expressions* keys = null;
+ Expressions* values;
+ if (init.isAssociativeArray())
+ {
+ keys = new Expressions(init.value.dim);
+ values = new Expressions(init.value.dim);
+ for (size_t i = 0; i < init.value.dim; i++)
+ {
+ Expression e = init.index[i];
+ if (!e)
+ goto Lno;
+ (*keys)[i] = e;
+ Initializer iz = init.value[i];
+ if (!iz)
+ goto Lno;
+ iz = iz.inferType(sc);
+ if (iz.isErrorInitializer())
+ {
+ return iz;
+ }
+ assert(iz.isExpInitializer());
+ (*values)[i] = (cast(ExpInitializer)iz).exp;
+ assert((*values)[i].op != TOK.error);
+ }
+ Expression e = new AssocArrayLiteralExp(init.loc, keys, values);
+ auto ei = new ExpInitializer(init.loc, e);
+ return ei.inferType(sc);
+ }
+ else
+ {
+ auto elements = new Expressions(init.value.dim);
+ elements.zero();
+ for (size_t i = 0; i < init.value.dim; i++)
+ {
+ assert(!init.index[i]); // already asserted by isAssociativeArray()
+ Initializer iz = init.value[i];
+ if (!iz)
+ goto Lno;
+ iz = iz.inferType(sc);
+ if (iz.isErrorInitializer())
+ {
+ return iz;
+ }
+ assert(iz.isExpInitializer());
+ (*elements)[i] = (cast(ExpInitializer)iz).exp;
+ assert((*elements)[i].op != TOK.error);
+ }
+ Expression e = new ArrayLiteralExp(init.loc, null, elements);
+ auto ei = new ExpInitializer(init.loc, e);
+ return ei.inferType(sc);
+ }
+ Lno:
+ if (keys)
+ {
+ error(init.loc, "not an associative array initializer");
+ }
+ else
+ {
+ error(init.loc, "cannot infer type from array initializer");
+ }
+ return new ErrorInitializer();
+ }
+
+ Initializer visitExp(ExpInitializer init)
+ {
+ //printf("ExpInitializer::inferType() %s\n", init.toChars());
+ init.exp = init.exp.expressionSemantic(sc);
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (init.exp.op == TOK.type)
+ init.exp = resolveAliasThis(sc, init.exp);
+
+ init.exp = resolveProperties(sc, init.exp);
+ if (init.exp.op == TOK.scope_)
+ {
+ ScopeExp se = cast(ScopeExp)init.exp;
+ TemplateInstance ti = se.sds.isTemplateInstance();
+ if (ti && ti.semanticRun == PASS.semantic && !ti.aliasdecl)
+ se.error("cannot infer type from %s `%s`, possible circular dependency", se.sds.kind(), se.toChars());
+ else
+ se.error("cannot infer type from %s `%s`", se.sds.kind(), se.toChars());
+ return new ErrorInitializer();
+ }
+
+ // Give error for overloaded function addresses
+ bool hasOverloads;
+ if (auto f = isFuncAddress(init.exp, &hasOverloads))
+ {
+ if (f.checkForwardRef(init.loc))
+ {
+ return new ErrorInitializer();
+ }
+ if (hasOverloads && !f.isUnique())
+ {
+ init.exp.error("cannot infer type from overloaded function symbol `%s`", init.exp.toChars());
+ return new ErrorInitializer();
+ }
+ }
+ if (init.exp.op == TOK.address)
+ {
+ AddrExp ae = cast(AddrExp)init.exp;
+ if (ae.e1.op == TOK.overloadSet)
+ {
+ init.exp.error("cannot infer type from overloaded function symbol `%s`", init.exp.toChars());
+ return new ErrorInitializer();
+ }
+ }
+ if (init.exp.op == TOK.error)
+ {
+ return new ErrorInitializer();
+ }
+ if (!init.exp.type)
+ {
+ return new ErrorInitializer();
+ }
+ return init;
+ }
+
+ Initializer visitC(CInitializer i)
+ {
+ //printf(CInitializer::inferType()\n");
+ error(i.loc, "TODO C inferType initializers not supported yet");
+ return new ErrorInitializer();
+ }
+
+ final switch (init.kind)
+ {
+ case InitKind.void_: return visitVoid (cast( VoidInitializer)init);
+ case InitKind.error: return visitError (cast( ErrorInitializer)init);
+ case InitKind.struct_: return visitStruct(cast(StructInitializer)init);
+ case InitKind.array: return visitArray (cast( ArrayInitializer)init);
+ case InitKind.exp: return visitExp (cast( ExpInitializer)init);
+ case InitKind.C_: return visitC (cast( CInitializer)init);
+ }
+}
+
+/***********************
+ * Translate init to an `Expression`.
+ * Params:
+ * init = `Initializer` AST node
+ * itype = if not `null`, type to coerce expression to
+ * Returns:
+ * `Expression` created, `null` if cannot, `ErrorExp` for other errors
+ */
+extern (C++) Expression initializerToExpression(Initializer init, Type itype = null)
+{
+ Expression visitVoid(VoidInitializer)
+ {
+ return null;
+ }
+
+ Expression visitError(ErrorInitializer)
+ {
+ return ErrorExp.get();
+ }
+
+ /***************************************
+ * This works by transforming a struct initializer into
+ * a struct literal. In the future, the two should be the
+ * same thing.
+ */
+ Expression visitStruct(StructInitializer)
+ {
+ // cannot convert to an expression without target 'ad'
+ return null;
+ }
+
+ /********************************
+ * If possible, convert array initializer to array literal.
+ * Otherwise return NULL.
+ */
+ Expression visitArray(ArrayInitializer init)
+ {
+ //printf("ArrayInitializer::toExpression(), dim = %d\n", dim);
+ //static int i; if (++i == 2) assert(0);
+ uint edim; // the length of the resulting array literal
+ const(uint) amax = 0x80000000;
+ Type t = null; // type of the array literal being initialized
+ if (init.type)
+ {
+ if (init.type == Type.terror)
+ {
+ return ErrorExp.get();
+ }
+ t = init.type.toBasetype();
+ switch (t.ty)
+ {
+ case Tvector:
+ t = t.isTypeVector().basetype;
+ goto case Tsarray;
+
+ case Tsarray:
+ uinteger_t adim = t.isTypeSArray().dim.toInteger();
+ if (adim >= amax)
+ return null;
+ edim = cast(uint)adim;
+ break;
+
+ case Tpointer:
+ case Tarray:
+ edim = init.dim;
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ else
+ {
+ /* Calculate the length of the array literal
+ */
+ edim = cast(uint)init.value.dim;
+ size_t j = 0;
+ foreach (i; 0 .. init.value.dim)
+ {
+ if (auto e = init.index[i])
+ {
+ if (e.op == TOK.int64)
+ {
+ const uinteger_t idxval = e.toInteger();
+ if (idxval >= amax)
+ return null;
+ j = cast(size_t)idxval;
+ }
+ else
+ return null;
+ }
+ ++j;
+ if (j > edim)
+ edim = cast(uint)j;
+ }
+ }
+
+ auto elements = new Expressions(edim);
+ elements.zero();
+ size_t j = 0;
+ foreach (i; 0 .. init.value.dim)
+ {
+ if (auto e = init.index[i])
+ j = cast(size_t)e.toInteger();
+ assert(j < edim);
+ if (Initializer iz = init.value[i])
+ {
+ if (Expression ex = iz.initializerToExpression())
+ {
+ (*elements)[j] = ex;
+ ++j;
+ }
+ else
+ return null;
+ }
+ else
+ return null;
+ }
+
+ /* Fill in any missing elements with the default initializer
+ */
+ Expression defaultInit = null; // lazily create it
+ foreach (ref element; (*elements)[0 .. edim])
+ {
+ if (!element)
+ {
+ if (!init.type) // don't know what type to use
+ return null;
+ if (!defaultInit)
+ defaultInit = (cast(TypeNext)t).next.defaultInit(Loc.initial);
+ element = defaultInit;
+ }
+ }
+
+ /* Expand any static array initializers that are a single expression
+ * into an array of them
+ * e => [e, e, ..., e, e]
+ */
+ if (t)
+ {
+ Type tn = t.nextOf().toBasetype();
+ if (tn.ty == Tsarray)
+ {
+ const dim = cast(size_t)(cast(TypeSArray)tn).dim.toInteger();
+ Type te = tn.nextOf().toBasetype();
+ foreach (ref e; *elements)
+ {
+ if (te.equals(e.type))
+ {
+ auto elements2 = new Expressions(dim);
+ foreach (ref e2; *elements2)
+ e2 = e;
+ e = new ArrayLiteralExp(e.loc, tn, elements2);
+ }
+ }
+ }
+ }
+
+ /* If any elements are errors, then the whole thing is an error
+ */
+ foreach (e; (*elements)[0 .. edim])
+ {
+ if (e.op == TOK.error)
+ {
+ return e;
+ }
+ }
+
+ Expression e = new ArrayLiteralExp(init.loc, init.type, elements);
+ return e;
+ }
+
+ Expression visitExp(ExpInitializer i)
+ {
+ if (itype)
+ {
+ //printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype.toChars(), i.exp.toChars());
+ Type tb = itype.toBasetype();
+ Expression e = (i.exp.op == TOK.construct || i.exp.op == TOK.blit) ? (cast(AssignExp)i.exp).e2 : i.exp;
+ if (tb.ty == Tsarray && e.implicitConvTo(tb.nextOf()))
+ {
+ TypeSArray tsa = cast(TypeSArray)tb;
+ size_t d = cast(size_t)tsa.dim.toInteger();
+ auto elements = new Expressions(d);
+ for (size_t j = 0; j < d; j++)
+ (*elements)[j] = e;
+ auto ae = new ArrayLiteralExp(e.loc, itype, elements);
+ return ae;
+ }
+ }
+ return i.exp;
+ }
+
+ Expression visitC(CInitializer i)
+ {
+ //printf("CInitializer.initializerToExpression()\n");
+ return null;
+ }
+
+ final switch (init.kind)
+ {
+ case InitKind.void_: return visitVoid (cast( VoidInitializer)init);
+ case InitKind.error: return visitError (cast( ErrorInitializer)init);
+ case InitKind.struct_: return visitStruct(cast(StructInitializer)init);
+ case InitKind.array: return visitArray (cast( ArrayInitializer)init);
+ case InitKind.exp: return visitExp (cast( ExpInitializer)init);
+ case InitKind.C_: return visitC (cast( CInitializer)init);
+ }
+}
+
+
+/**************************************
+ * Determine if expression has non-constant pointers, or more precisely,
+ * a pointer that CTFE cannot handle.
+ * Params:
+ * e = expression to check
+ * Returns:
+ * true if it has non-constant pointers
+ */
+private bool hasNonConstPointers(Expression e)
+{
+ static bool checkArray(Expressions* elems)
+ {
+ foreach (e; *elems)
+ {
+ if (e && hasNonConstPointers(e))
+ return true;
+ }
+ return false;
+ }
+
+ if (e.type.ty == Terror)
+ return false;
+ if (e.op == TOK.null_)
+ return false;
+ if (auto se = e.isStructLiteralExp())
+ {
+ return checkArray(se.elements);
+ }
+ if (auto ae = e.isArrayLiteralExp())
+ {
+ if (!ae.type.nextOf().hasPointers())
+ return false;
+ return checkArray(ae.elements);
+ }
+ if (auto ae = e.isAssocArrayLiteralExp())
+ {
+ if (ae.type.nextOf().hasPointers() && checkArray(ae.values))
+ return true;
+ if ((cast(TypeAArray)ae.type).index.hasPointers())
+ return checkArray(ae.keys);
+ return false;
+ }
+ if (auto ae = e.isAddrExp())
+ {
+ if (auto se = ae.e1.isStructLiteralExp())
+ {
+ if (!(se.stageflags & stageSearchPointers))
+ {
+ const old = se.stageflags;
+ se.stageflags |= stageSearchPointers;
+ bool ret = checkArray(se.elements);
+ se.stageflags = old;
+ return ret;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ if (e.type.ty == Tpointer && !e.type.isPtrToFunction())
+ {
+ if (e.op == TOK.symbolOffset) // address of a global is OK
+ return false;
+ if (e.op == TOK.int64) // cast(void *)int is OK
+ return false;
+ if (e.op == TOK.string_) // "abc".ptr is OK
+ return false;
+ return true;
+ }
+ return false;
+}
+
+
+
diff --git a/gcc/d/dmd/inline.d b/gcc/d/dmd/inline.d
new file mode 100644
index 0000000..cfd619a
--- /dev/null
+++ b/gcc/d/dmd/inline.d
@@ -0,0 +1,30 @@
+/**
+ * Performs inlining, which is an optimization pass enabled with the `-inline` flag.
+ *
+ * The AST is traversed, and every function call is considered for inlining using `inlinecost.d`.
+ * The function call is then inlined if this cost is below a threshold.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/inline.d, _inline.d)
+ * Documentation: https://dlang.org/phobos/dmd_inline.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/inline.d
+ */
+
+module dmd.inline;
+
+import dmd.dscope;
+import dmd.expression;
+
+/***********************************************************
+ * Perform the "inline copying" of a default argument for a function parameter.
+ *
+ * Todo:
+ * The hack for bugzilla 4820 case is still questionable. Perhaps would have to
+ * handle a delegate expression with 'null' context properly in front-end.
+ */
+public Expression inlineCopy(Expression e, Scope* sc)
+{
+ return e.copy();
+}
diff --git a/gcc/d/dmd/intrange.c b/gcc/d/dmd/intrange.c
deleted file mode 100644
index 36af8da..0000000
--- a/gcc/d/dmd/intrange.c
+++ /dev/null
@@ -1,839 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by KennyTM
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/intrange.c
- */
-
-#include "root/dsystem.h"
-
-#include "intrange.h"
-#include "mars.h"
-#include "mtype.h"
-#include "expression.h"
-
-// Copy the sign to the value *x*. Equivalent to `sign ? -x : x`.
-static uinteger_t copySign(uinteger_t x, bool sign)
-{
- // return sign ? -x : x;
- return (x - (uinteger_t)sign) ^ -(uinteger_t)sign;
-}
-
-#ifndef UINT64_MAX
-#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL
-#endif
-
-//==================== SignExtendedNumber ======================================
-
-SignExtendedNumber SignExtendedNumber::fromInteger(uinteger_t value_)
-{
- return SignExtendedNumber(value_, value_ >> 63);
-}
-
-bool SignExtendedNumber::operator==(const SignExtendedNumber& a) const
-{
- return value == a.value && negative == a.negative;
-}
-
-bool SignExtendedNumber::operator<(const SignExtendedNumber& a) const
-{
- return (negative && !a.negative)
- || (negative == a.negative && value < a.value);
-}
-
-SignExtendedNumber SignExtendedNumber::extreme(bool minimum)
-{
- return SignExtendedNumber(minimum-1, minimum);
-}
-
-SignExtendedNumber SignExtendedNumber::max()
-{
- return SignExtendedNumber(UINT64_MAX, false);
-}
-
-SignExtendedNumber& SignExtendedNumber::operator++()
-{
- if (value != UINT64_MAX)
- ++value;
- else if (negative)
- {
- value = 0;
- negative = false;
- }
- return *this;
-}
-
-SignExtendedNumber SignExtendedNumber::operator~() const
-{
- if (~value == 0)
- return SignExtendedNumber(~value);
- else
- return SignExtendedNumber(~value, !negative);
-}
-
-SignExtendedNumber SignExtendedNumber::operator-() const
-{
- if (value == 0)
- return SignExtendedNumber(-negative);
- else
- return SignExtendedNumber(-value, !negative);
-}
-
-SignExtendedNumber SignExtendedNumber::operator&(const SignExtendedNumber& rhs) const
-{
- return SignExtendedNumber(value & rhs.value);
-}
-
-SignExtendedNumber SignExtendedNumber::operator|(const SignExtendedNumber& rhs) const
-{
- return SignExtendedNumber(value | rhs.value);
-}
-
-SignExtendedNumber SignExtendedNumber::operator^(const SignExtendedNumber& rhs) const
-{
- return SignExtendedNumber(value ^ rhs.value);
-}
-
-SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& rhs) const
-{
- uinteger_t sum = value + rhs.value;
- bool carry = sum < value && sum < rhs.value;
- if (negative != rhs.negative)
- return SignExtendedNumber(sum, !carry);
- else if (negative)
- return SignExtendedNumber(carry ? sum : 0, true);
- else
- return SignExtendedNumber(carry ? UINT64_MAX : sum, false);
-}
-
-SignExtendedNumber SignExtendedNumber::operator-(const SignExtendedNumber& rhs) const
-{
- if (rhs.isMinimum())
- return negative ? SignExtendedNumber(value, false) : max();
- else
- return *this + (-rhs);
-}
-
-SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& rhs) const
-{
- // perform *saturated* multiplication, otherwise we may get bogus ranges
- // like 0x10 * 0x10 == 0x100 == 0.
-
- /* Special handling for zeros:
- INT65_MIN * 0 = 0
- INT65_MIN * + = INT65_MIN
- INT65_MIN * - = INT65_MAX
- 0 * anything = 0
- */
- if (value == 0)
- {
- if (!negative)
- return *this;
- else if (rhs.negative)
- return max();
- else
- return rhs.value == 0 ? rhs : *this;
- }
- else if (rhs.value == 0)
- return rhs * *this; // don't duplicate the symmetric case.
-
- SignExtendedNumber rv;
- // these are != 0 now surely.
- uinteger_t tAbs = copySign(value, negative);
- uinteger_t aAbs = copySign(rhs.value, rhs.negative);
- rv.negative = negative != rhs.negative;
- if (UINT64_MAX / tAbs < aAbs)
- rv.value = rv.negative-1;
- else
- rv.value = copySign(tAbs * aAbs, rv.negative);
- return rv;
-}
-
-SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& rhs) const
-{
- /* special handling for zeros:
- INT65_MIN / INT65_MIN = 1
- anything / INT65_MIN = 0
- + / 0 = INT65_MAX (eh?)
- - / 0 = INT65_MIN (eh?)
- */
- if (rhs.value == 0)
- {
- if (rhs.negative)
- return SignExtendedNumber(value == 0 && negative);
- else
- return extreme(negative);
- }
-
- uinteger_t aAbs = copySign(rhs.value, rhs.negative);
- uinteger_t rvVal;
-
- if (!isMinimum())
- rvVal = copySign(value, negative) / aAbs;
- // Special handling for INT65_MIN
- // if the denominator is not a power of 2, it is same as UINT64_MAX / x.
- else if (aAbs & (aAbs-1))
- rvVal = UINT64_MAX / aAbs;
- // otherwise, it's the same as reversing the bits of x.
- else
- {
- if (aAbs == 1)
- return extreme(!rhs.negative);
- rvVal = 1ULL << 63;
- aAbs >>= 1;
- if (aAbs & 0xAAAAAAAAAAAAAAAAULL) rvVal >>= 1;
- if (aAbs & 0xCCCCCCCCCCCCCCCCULL) rvVal >>= 2;
- if (aAbs & 0xF0F0F0F0F0F0F0F0ULL) rvVal >>= 4;
- if (aAbs & 0xFF00FF00FF00FF00ULL) rvVal >>= 8;
- if (aAbs & 0xFFFF0000FFFF0000ULL) rvVal >>= 16;
- if (aAbs & 0xFFFFFFFF00000000ULL) rvVal >>= 32;
- }
- bool rvNeg = negative != rhs.negative;
- rvVal = copySign(rvVal, rvNeg);
-
- return SignExtendedNumber(rvVal, rvVal != 0 && rvNeg);
-}
-
-SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& rhs) const
-{
- if (rhs.value == 0)
- return !rhs.negative ? rhs : isMinimum() ? SignExtendedNumber(0) : *this;
-
- uinteger_t aAbs = copySign(rhs.value, rhs.negative);
- uinteger_t rvVal;
-
- // a % b == sgn(a) * abs(a) % abs(b).
- if (!isMinimum())
- rvVal = copySign(value, negative) % aAbs;
- // Special handling for INT65_MIN
- // if the denominator is not a power of 2, it is same as UINT64_MAX%x + 1.
- else if (aAbs & (aAbs - 1))
- rvVal = UINT64_MAX % aAbs + 1;
- // otherwise, the modulus is trivially zero.
- else
- rvVal = 0;
-
- rvVal = copySign(rvVal, negative);
- return SignExtendedNumber(rvVal, rvVal != 0 && negative);
-}
-
-SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& rhs) const
-{
- // assume left-shift the shift-amount is always unsigned. Thus negative
- // shifts will give huge result.
- if (value == 0)
- return *this;
- else if (rhs.negative)
- return extreme(negative);
-
- uinteger_t v = copySign(value, negative);
-
- // compute base-2 log of 'v' to determine the maximum allowed bits to shift.
- // Ref: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
-
- // Why is this a size_t? Looks like a bug.
- size_t r, s;
-
- r = (v > 0xFFFFFFFFULL) << 5; v >>= r;
- s = (v > 0xFFFFULL ) << 4; v >>= s; r |= s;
- s = (v > 0xFFULL ) << 3; v >>= s; r |= s;
- s = (v > 0xFULL ) << 2; v >>= s; r |= s;
- s = (v > 0x3ULL ) << 1; v >>= s; r |= s;
- r |= (v >> 1);
-
- uinteger_t allowableShift = 63 - r;
- if (rhs.value > allowableShift)
- return extreme(negative);
- else
- return SignExtendedNumber(value << rhs.value, negative);
-}
-
-SignExtendedNumber SignExtendedNumber::operator>>(const SignExtendedNumber& rhs) const
-{
- if (rhs.negative || rhs.value > 63)
- return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
- else if (isMinimum())
- return rhs.value == 0 ? *this : SignExtendedNumber(-1ULL << (64 - rhs.value), true);
-
- uinteger_t x = value ^ -negative;
- x >>= rhs.value;
- return SignExtendedNumber(x ^ -negative, negative);
-}
-
-
-//==================== IntRange ================================================
-
-IntRange IntRange::widest()
-{
- return IntRange(SignExtendedNumber::min(), SignExtendedNumber::max());
-}
-
-IntRange IntRange::fromType(Type *type)
-{
- return fromType(type, type->isunsigned());
-}
-
-IntRange IntRange::fromType(Type *type, bool isUnsigned)
-{
- if (!type->isintegral() || type->toBasetype()->ty == Tvector)
- return widest();
-
- uinteger_t mask = type->sizemask();
- SignExtendedNumber lower(0), upper(mask);
- if (type->toBasetype()->ty == Tdchar)
- upper.value = 0x10FFFFULL;
- else if (!isUnsigned)
- {
- lower.value = ~(mask >> 1);
- lower.negative = true;
- upper.value = (mask >> 1);
- }
- return IntRange(lower, upper);
-}
-
-IntRange IntRange::fromNumbers2(const SignExtendedNumber numbers[2])
-{
- if (numbers[0] < numbers[1])
- return IntRange(numbers[0], numbers[1]);
- else
- return IntRange(numbers[1], numbers[0]);
-}
-IntRange IntRange::fromNumbers4(const SignExtendedNumber numbers[4])
-{
- IntRange ab = fromNumbers2(numbers);
- IntRange cd = fromNumbers2(numbers + 2);
- if (cd.imin < ab.imin)
- ab.imin = cd.imin;
- if (cd.imax > ab.imax)
- ab.imax = cd.imax;
- return ab;
-}
-
-bool IntRange::contains(const IntRange& a) const
-{
- return imin <= a.imin && imax >= a.imax;
-}
-
-bool IntRange::containsZero() const
-{
- return (imin.negative && !imax.negative)
- || (!imin.negative && imin.value == 0);
-}
-
-IntRange& IntRange::castUnsigned(uinteger_t mask)
-{
- // .... 0x1eff ] [0x1f00 .. 0x1fff] [0 .. 0xff] [0x100 .. 0x1ff] [0x200 ....
- //
- // regular unsigned type. We just need to see if ir steps across the
- // boundary of validRange. If yes, ir will represent the whole validRange,
- // otherwise, we just take the modulus.
- // e.g. [0x105, 0x107] & 0xff == [5, 7]
- // [0x105, 0x207] & 0xff == [0, 0xff]
- uinteger_t minChunk = imin.value & ~mask;
- uinteger_t maxChunk = imax.value & ~mask;
- if (minChunk == maxChunk && imin.negative == imax.negative)
- {
- imin.value &= mask;
- imax.value &= mask;
- }
- else
- {
- imin.value = 0;
- imax.value = mask;
- }
- imin.negative = imax.negative = false;
- return *this;
-}
-
-IntRange& IntRange::castSigned(uinteger_t mask)
-{
- // .... 0x1e7f ] [0x1e80 .. 0x1f7f] [0x1f80 .. 0x7f] [0x80 .. 0x17f] [0x180 ....
- //
- // regular signed type. We use a technique similar to the unsigned version,
- // but the chunk has to be offset by 1/2 of the range.
- uinteger_t halfChunkMask = mask >> 1;
- uinteger_t minHalfChunk = imin.value & ~halfChunkMask;
- uinteger_t maxHalfChunk = imax.value & ~halfChunkMask;
- int minHalfChunkNegativity = imin.negative; // 1 = neg, 0 = nonneg, -1 = chunk containing ::max
- int maxHalfChunkNegativity = imax.negative;
- if (minHalfChunk & mask)
- {
- minHalfChunk += halfChunkMask+1;
- if (minHalfChunk == 0)
- -- minHalfChunkNegativity;
- }
- if (maxHalfChunk & mask)
- {
- maxHalfChunk += halfChunkMask+1;
- if (maxHalfChunk == 0)
- -- maxHalfChunkNegativity;
- }
- if (minHalfChunk == maxHalfChunk && minHalfChunkNegativity == maxHalfChunkNegativity)
- {
- imin.value &= mask;
- imax.value &= mask;
- // sign extend if necessary.
- imin.negative = imin.value & ~halfChunkMask;
- imax.negative = imax.value & ~halfChunkMask;
- halfChunkMask += 1;
- imin.value = (imin.value ^ halfChunkMask) - halfChunkMask;
- imax.value = (imax.value ^ halfChunkMask) - halfChunkMask;
- }
- else
- {
- imin = SignExtendedNumber(~halfChunkMask, true);
- imax = SignExtendedNumber(halfChunkMask, false);
- }
- return *this;
-}
-
-IntRange& IntRange::castDchar()
-{
- // special case for dchar. Casting to dchar means "I'll ignore all
- // invalid characters."
- castUnsigned(0xFFFFFFFFULL);
- if (imin.value > 0x10FFFFULL) // ??
- imin.value = 0x10FFFFULL; // ??
- if (imax.value > 0x10FFFFULL)
- imax.value = 0x10FFFFULL;
- return *this;
-}
-
-IntRange& IntRange::cast(Type *type)
-{
- if (!type->isintegral() || type->toBasetype()->ty == Tvector)
- return *this;
- else if (!type->isunsigned())
- return castSigned(type->sizemask());
- else if (type->toBasetype()->ty == Tdchar)
- return castDchar();
- else
- return castUnsigned(type->sizemask());
-}
-
-IntRange& IntRange::castUnsigned(Type *type)
-{
- if (!type->isintegral() || type->toBasetype()->ty == Tvector)
- return castUnsigned(UINT64_MAX);
- else if (type->toBasetype()->ty == Tdchar)
- return castDchar();
- else
- return castUnsigned(type->sizemask());
-}
-
-IntRange IntRange::absNeg() const
-{
- if (imax.negative)
- return *this;
- else if (!imin.negative)
- return IntRange(-imax, -imin);
- else
- {
- SignExtendedNumber imaxAbsNeg = -imax;
- return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin,
- SignExtendedNumber(0));
- }
-}
-
-IntRange IntRange::unionWith(const IntRange& other) const
-{
- return IntRange(imin < other.imin ? imin : other.imin,
- imax > other.imax ? imax : other.imax);
-}
-
-void IntRange::unionOrAssign(const IntRange& other, bool& union_)
-{
- if (!union_ || imin > other.imin)
- imin = other.imin;
- if (!union_ || imax < other.imax)
- imax = other.imax;
- union_ = true;
-}
-
-void IntRange::splitBySign(IntRange& negRange, bool& hasNegRange,
- IntRange& nonNegRange, bool& hasNonNegRange) const
-{
- hasNegRange = imin.negative;
- if (hasNegRange)
- {
- negRange.imin = imin;
- negRange.imax = imax.negative ? imax : SignExtendedNumber(-1, true);
- }
- hasNonNegRange = !imax.negative;
- if (hasNonNegRange)
- {
- nonNegRange.imin = imin.negative ? SignExtendedNumber(0) : imin;
- nonNegRange.imax = imax;
- }
-}
-
-IntRange IntRange::operator~() const
-{
- return IntRange(~imax, ~imin);
-}
-
-IntRange IntRange::operator-() const
-{
- return IntRange(-imax, -imin);
-}
-
-IntRange IntRange::operator&(const IntRange& rhs) const
-{
- // unsigned or identical sign bits
- if ((imin.negative ^ imax.negative) != 1 && (rhs.imin.negative ^ rhs.imax.negative) != 1)
- {
- return IntRange(minAnd(*this, rhs), maxAnd(*this, rhs));
- }
-
- IntRange l = IntRange(*this);
- IntRange r = IntRange(rhs);
-
- // both intervals span [-1,0]
- if ((l.imin.negative ^ l.imax.negative) == 1 && (r.imin.negative ^ r.imax.negative) == 1)
- {
- // cannot be larger than either l.max or r.max, set the other one to -1
- SignExtendedNumber max = l.imax.value > r.imax.value ? l.imax : r.imax;
-
- // only negative numbers for minimum
- l.imax.value = -1;
- l.imax.negative = true;
- r.imax.value = -1;
- r.imax.negative = true;
-
- return IntRange(minAnd(l, r), max);
- }
- else
- {
- // only one interval spans [-1,0]
- if ((l.imin.negative ^ l.imax.negative) == 1)
- {
- swap(l, r); // r spans [-1,0]
- }
-
- SignExtendedNumber minAndNeg = minAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
- SignExtendedNumber minAndPos = minAnd(l, IntRange(SignExtendedNumber(0), r.imax));
- SignExtendedNumber maxAndNeg = maxAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
- SignExtendedNumber maxAndPos = maxAnd(l, IntRange(SignExtendedNumber(0), r.imax));
-
- SignExtendedNumber min = minAndNeg < minAndPos ? minAndNeg : minAndPos;
- SignExtendedNumber max = maxAndNeg > maxAndPos ? maxAndNeg : maxAndPos;
-
- return IntRange(min, max);
- }
-}
-
-IntRange IntRange::operator|(const IntRange& rhs) const
-{
- // unsigned or identical sign bits:
- if ((imin.negative ^ imax.negative) == 0 && (rhs.imin.negative ^ rhs.imax.negative) == 0)
- {
- return IntRange(minOr(*this, rhs), maxOr(*this, rhs));
- }
-
- IntRange l = IntRange(*this);
- IntRange r = IntRange(rhs);
-
- // both intervals span [-1,0]
- if ((l.imin.negative ^ l.imax.negative) == 1 && (r.imin.negative ^ r.imax.negative) == 1)
- {
- // cannot be smaller than either l.min or r.min, set the other one to 0
- SignExtendedNumber min = l.imin.value < r.imin.value ? l.imin : r.imin;
-
- // only negative numbers for minimum
- l.imin.value = 0;
- l.imin.negative = false;
- r.imin.value = 0;
- r.imin.negative = false;
-
- return IntRange(min, maxOr(l, r));
- }
- else
- {
- // only one interval spans [-1,0]
- if ((imin.negative ^ imax.negative) == 1)
- {
- swap(l, r); // r spans [-1,0]
- }
-
- SignExtendedNumber minOrNeg = minOr(l, IntRange(r.imin, SignExtendedNumber(-1)));
- SignExtendedNumber minOrPos = minOr(l, IntRange(SignExtendedNumber(0), r.imax));
- SignExtendedNumber maxOrNeg = maxOr(l, IntRange(r.imin, SignExtendedNumber(-1)));
- SignExtendedNumber maxOrPos = maxOr(l, IntRange(SignExtendedNumber(0), r.imax));
-
- SignExtendedNumber min = minOrNeg < minOrPos ? minOrNeg : minOrPos;
- SignExtendedNumber max = maxOrNeg > maxOrPos ? maxOrNeg : maxOrPos;
-
- return IntRange(min, max);
- }
-}
-
-IntRange IntRange::operator^(const IntRange& rhs) const
-{
- return (*this & (~rhs)) | (~(*this) & rhs);
-}
-
-IntRange IntRange::operator+(const IntRange& rhs) const
-{
- return IntRange(imin + rhs.imin, imax + rhs.imax);
-}
-
-IntRange IntRange::operator-(const IntRange& rhs) const
-{
- return IntRange(imin - rhs.imax, imax - rhs.imin);
-}
-
-IntRange IntRange::operator*(const IntRange& rhs) const
-{
- // [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)]
- SignExtendedNumber bdy[4];
- bdy[0] = imin * rhs.imin;
- bdy[1] = imin * rhs.imax;
- bdy[2] = imax * rhs.imin;
- bdy[3] = imax * rhs.imax;
- return IntRange::fromNumbers4(bdy);
-}
-
-IntRange IntRange::operator/(const IntRange& rhs) const
-{
- // Handle divide by 0
- if (rhs.imax.value == 0 && rhs.imin.value == 0)
- return widest();
-
- IntRange r = IntRange(rhs);
-
- // Don't treat the whole range as divide by 0 if only one end of a range is 0.
- // Issue 15289
- if (r.imax.value == 0)
- {
- r.imax.value--;
- }
- else if (r.imin.value == 0)
- {
- r.imin.value++;
- }
-
- if (!imin.negative && !imax.negative && !r.imin.negative && !r.imax.negative)
- {
- return IntRange(imin / r.imax, imax / r.imin);
- }
- else
- {
- // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
- SignExtendedNumber bdy[4];
- bdy[0] = imin / r.imin;
- bdy[1] = imin / r.imax;
- bdy[2] = imax / r.imin;
- bdy[3] = imax / r.imax;
-
- return IntRange::fromNumbers4(bdy);
- }
-}
-
-IntRange IntRange::operator%(const IntRange& rhs) const
-{
- IntRange irNum = *this;
- IntRange irDen = rhs.absNeg();
-
- /*
- due to the rules of D (C)'s % operator, we need to consider the cases
- separately in different range of signs.
-
- case 1. [500, 1700] % [7, 23] (numerator is always positive)
- = [0, 22]
- case 2. [-500, 1700] % [7, 23] (numerator can be negative)
- = [-22, 22]
- case 3. [-1700, -500] % [7, 23] (numerator is always negative)
- = [-22, 0]
-
- the number 22 is the maximum absolute value in the denomator's range. We
- don't care about divide by zero.
- */
-
- irDen.imin = irDen.imin + SignExtendedNumber(1);
- irDen.imax = -irDen.imin;
-
- if (!irNum.imin.negative)
- {
- irNum.imin.value = 0;
- }
- else if (irNum.imin < irDen.imin)
- {
- irNum.imin = irDen.imin;
- }
-
- if (irNum.imax.negative)
- {
- irNum.imax.negative = false;
- irNum.imax.value = 0;
- }
- else if (irNum.imax > irDen.imax)
- {
- irNum.imax = irDen.imax;
- }
-
- return irNum;
-}
-
-IntRange IntRange::operator<<(const IntRange& rhs) const
-{
- IntRange r = IntRange(rhs);
- if (r.imin.negative)
- {
- r = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
- }
-
- SignExtendedNumber lower = imin << (imin.negative ? r.imax : r.imin);
- SignExtendedNumber upper = imax << (imax.negative ? r.imin : r.imax);
-
- return IntRange(lower, upper);
-}
-
-IntRange IntRange::operator>>(const IntRange& rhs) const
-{
- IntRange r = IntRange(rhs);
- if (r.imin.negative)
- {
- r = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
- }
-
- SignExtendedNumber lower = imin >> (imin.negative ? r.imin : r.imax);
- SignExtendedNumber upper = imax >> (imax.negative ? r.imax : r.imin);
-
- return IntRange(lower, upper);
-}
-
-SignExtendedNumber IntRange::maxOr(const IntRange& lhs, const IntRange& rhs)
-{
- uinteger_t x = 0;
- bool sign = false;
- uinteger_t xorvalue = lhs.imax.value ^ rhs.imax.value;
- uinteger_t andvalue = lhs.imax.value & rhs.imax.value;
- IntRange lhsc = IntRange(lhs);
- IntRange rhsc = IntRange(rhs);
-
- // Sign bit not part of the .value so we need an extra iteration
- if (lhsc.imax.negative ^ rhsc.imax.negative)
- {
- sign = true;
- if (lhsc.imax.negative)
- {
- if (!lhsc.imin.negative)
- {
- lhsc.imin.value = 0;
- }
- if (!rhsc.imin.negative)
- {
- rhsc.imin.value = 0;
- }
- }
- }
- else if (lhsc.imin.negative & rhsc.imin.negative)
- {
- sign = true;
- }
- else if (lhsc.imax.negative & rhsc.imax.negative)
- {
- return SignExtendedNumber(-1, false);
- }
-
- for (uinteger_t d = 1ULL << (8 * sizeof(uinteger_t) - 1); d; d >>= 1)
- {
- if (xorvalue & d)
- {
- x |= d;
- if (lhsc.imax.value & d)
- {
- if (~lhsc.imin.value & d)
- {
- lhsc.imin.value = 0;
- }
- }
- else
- {
- if (~rhsc.imin.value & d)
- {
- rhsc.imin.value = 0;
- }
- }
- }
- else if (lhsc.imin.value & rhsc.imin.value & d)
- {
- x |= d;
- }
- else if (andvalue & d)
- {
- x |= (d << 1) - 1;
- break;
- }
- }
-
- return SignExtendedNumber(x, sign);
-}
-
-SignExtendedNumber IntRange::minOr(const IntRange& lhs, const IntRange& rhs)
-{
- return ~maxAnd(~lhs, ~rhs);
-}
-
-SignExtendedNumber IntRange::maxAnd(const IntRange& lhs, const IntRange& rhs)
-{
- uinteger_t x = 0;
- bool sign = false;
- IntRange lhsc = IntRange(lhs);
- IntRange rhsc = IntRange(rhs);
-
- if (lhsc.imax.negative & rhsc.imax.negative)
- {
- sign = true;
- }
-
- for (uinteger_t d = 1ULL << (8 * sizeof(uinteger_t) - 1); d; d >>= 1)
- {
- if (lhsc.imax.value & rhsc.imax.value & d)
- {
- x |= d;
- if (~lhsc.imin.value & d)
- {
- lhsc.imin.value = 0;
- }
- if (~rhsc.imin.value & d)
- {
- rhsc.imin.value = 0;
- }
- }
- else if (~lhsc.imin.value & d && lhsc.imax.value & d)
- {
- lhsc.imax.value |= d - 1;
- }
- else if (~rhsc.imin.value & d && rhsc.imax.value & d)
- {
- rhsc.imax.value |= d - 1;
- }
- }
-
- return SignExtendedNumber(x, sign);
-}
-
-SignExtendedNumber IntRange::minAnd(const IntRange& lhs, const IntRange& rhs)
-{
- return ~maxOr(~lhs, ~rhs);
-}
-
-void IntRange::swap(IntRange& a, IntRange& b)
-{
- IntRange aux = a;
- a = b;
- b = aux;
-}
-
-const IntRange& IntRange::dump(const char* funcName, Expression *e) const
-{
- printf("[(%c)%#018llx, (%c)%#018llx] @ %s ::: %s\n",
- imin.negative?'-':'+', (unsigned long long)imin.value,
- imax.negative?'-':'+', (unsigned long long)imax.value,
- funcName, e->toChars());
- return *this;
-}
diff --git a/gcc/d/dmd/intrange.d b/gcc/d/dmd/intrange.d
new file mode 100644
index 0000000..9b70f49
--- /dev/null
+++ b/gcc/d/dmd/intrange.d
@@ -0,0 +1,919 @@
+/**
+ * Implement $(LINK2 https://digitalmars.com/articles/b62.html, Value Range Propagation).
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/intrange.d, _intrange.d)
+ * Documentation: https://dlang.org/phobos/dmd_intrange.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/intrange.d
+ */
+
+module dmd.intrange;
+
+import core.stdc.stdio;
+
+import dmd.astenums;
+import dmd.mtype;
+import dmd.expression;
+import dmd.globals;
+
+private uinteger_t copySign(uinteger_t x, bool sign)
+{
+ // return sign ? -x : x;
+ return (x - cast(uinteger_t)sign) ^ -cast(uinteger_t)sign;
+}
+
+struct SignExtendedNumber
+{
+ uinteger_t value;
+ bool negative;
+
+ static SignExtendedNumber fromInteger(uinteger_t value_)
+ {
+ return SignExtendedNumber(value_, value_ >> 63);
+ }
+
+ static SignExtendedNumber extreme(bool minimum)
+ {
+ return SignExtendedNumber(minimum - 1, minimum);
+ }
+
+ static SignExtendedNumber max()
+ {
+ return SignExtendedNumber(ulong.max, false);
+ }
+
+ static SignExtendedNumber min()
+ {
+ return SignExtendedNumber(0, true);
+ }
+
+ bool isMinimum() const
+ {
+ return negative && value == 0;
+ }
+
+ bool opEquals(const ref SignExtendedNumber a) const
+ {
+ return value == a.value && negative == a.negative;
+ }
+
+ int opCmp(const ref SignExtendedNumber a) const
+ {
+ if (negative != a.negative)
+ {
+ if (negative)
+ return -1;
+ else
+ return 1;
+ }
+ if (value < a.value)
+ return -1;
+ else if (value > a.value)
+ return 1;
+ else
+ return 0;
+ }
+
+ SignExtendedNumber opUnary(string op : "++")()
+ {
+ if (value != ulong.max)
+ ++value;
+ else if (negative)
+ {
+ value = 0;
+ negative = false;
+ }
+ return this;
+ }
+
+ SignExtendedNumber opUnary(string op : "~")() const
+ {
+ if (~value == 0)
+ return SignExtendedNumber(~value);
+ else
+ return SignExtendedNumber(~value, !negative);
+ }
+
+ SignExtendedNumber opUnary(string op : "-")() const
+ {
+ if (value == 0)
+ return SignExtendedNumber(-cast(ulong)negative);
+ else
+ return SignExtendedNumber(-value, !negative);
+ }
+
+ SignExtendedNumber opBinary(string op : "&")(SignExtendedNumber rhs) const
+ {
+ return SignExtendedNumber(value & rhs.value);
+ }
+
+ SignExtendedNumber opBinary(string op : "|")(SignExtendedNumber rhs)
+ {
+ return SignExtendedNumber(value | rhs.value);
+ }
+
+ SignExtendedNumber opBinary(string op : "^")(SignExtendedNumber rhs)
+ {
+ return SignExtendedNumber(value ^ rhs.value);
+ }
+
+ SignExtendedNumber opBinary(string op : "+")(SignExtendedNumber rhs)
+ {
+ uinteger_t sum = value + rhs.value;
+ bool carry = sum < value && sum < rhs.value;
+ if (negative != rhs.negative)
+ return SignExtendedNumber(sum, !carry);
+ else if (negative)
+ return SignExtendedNumber(carry ? sum : 0, true);
+ else
+ return SignExtendedNumber(carry ? ulong.max : sum, false);
+ }
+
+
+ SignExtendedNumber opBinary(string op : "-")(SignExtendedNumber rhs)
+ {
+ if (rhs.isMinimum())
+ return negative ? SignExtendedNumber(value, false) : max();
+ else
+ return this + (-rhs);
+ }
+
+ SignExtendedNumber opBinary(string op : "*")(SignExtendedNumber rhs)
+ {
+ // perform *saturated* multiplication, otherwise we may get bogus ranges
+ // like 0x10 * 0x10 == 0x100 == 0.
+
+ /* Special handling for zeros:
+ INT65_MIN * 0 = 0
+ INT65_MIN * + = INT65_MIN
+ INT65_MIN * - = INT65_MAX
+ 0 * anything = 0
+ */
+ if (value == 0)
+ {
+ if (!negative)
+ return this;
+ else if (rhs.negative)
+ return max();
+ else
+ return rhs.value == 0 ? rhs : this;
+ }
+ else if (rhs.value == 0)
+ return rhs * this; // don't duplicate the symmetric case.
+
+ SignExtendedNumber rv;
+ // these are != 0 now surely.
+ uinteger_t tAbs = copySign(value, negative);
+ uinteger_t aAbs = copySign(rhs.value, rhs.negative);
+ rv.negative = negative != rhs.negative;
+ if (ulong.max / tAbs < aAbs)
+ rv.value = rv.negative - 1;
+ else
+ rv.value = copySign(tAbs * aAbs, rv.negative);
+ return rv;
+ }
+
+ SignExtendedNumber opBinary(string op : "/")(SignExtendedNumber rhs)
+ {
+ /* special handling for zeros:
+ INT65_MIN / INT65_MIN = 1
+ anything / INT65_MIN = 0
+ + / 0 = INT65_MAX (eh?)
+ - / 0 = INT65_MIN (eh?)
+ */
+ if (rhs.value == 0)
+ {
+ if (rhs.negative)
+ return SignExtendedNumber(value == 0 && negative);
+ else
+ return extreme(negative);
+ }
+
+ uinteger_t aAbs = copySign(rhs.value, rhs.negative);
+ uinteger_t rvVal;
+
+ if (!isMinimum())
+ rvVal = copySign(value, negative) / aAbs;
+ // Special handling for INT65_MIN
+ // if the denominator is not a power of 2, it is same as ulong.max / x.
+ else if (aAbs & (aAbs - 1))
+ rvVal = ulong.max / aAbs;
+ // otherwise, it's the same as reversing the bits of x.
+ else
+ {
+ if (aAbs == 1)
+ return extreme(!rhs.negative);
+ rvVal = 1UL << 63;
+ aAbs >>= 1;
+ if (aAbs & 0xAAAAAAAAAAAAAAAAUL) rvVal >>= 1;
+ if (aAbs & 0xCCCCCCCCCCCCCCCCUL) rvVal >>= 2;
+ if (aAbs & 0xF0F0F0F0F0F0F0F0UL) rvVal >>= 4;
+ if (aAbs & 0xFF00FF00FF00FF00UL) rvVal >>= 8;
+ if (aAbs & 0xFFFF0000FFFF0000UL) rvVal >>= 16;
+ if (aAbs & 0xFFFFFFFF00000000UL) rvVal >>= 32;
+ }
+ bool rvNeg = negative != rhs.negative;
+ rvVal = copySign(rvVal, rvNeg);
+
+ return SignExtendedNumber(rvVal, rvVal != 0 && rvNeg);
+ }
+
+ SignExtendedNumber opBinary(string op : "%")(SignExtendedNumber rhs)
+ {
+ if (rhs.value == 0)
+ return !rhs.negative ? rhs : isMinimum() ? SignExtendedNumber(0) : this;
+
+ uinteger_t aAbs = copySign(rhs.value, rhs.negative);
+ uinteger_t rvVal;
+
+ // a % b == sgn(a) * abs(a) % abs(b).
+ if (!isMinimum())
+ rvVal = copySign(value, negative) % aAbs;
+ // Special handling for INT65_MIN
+ // if the denominator is not a power of 2, it is same as ulong.max % x + 1.
+ else if (aAbs & (aAbs - 1))
+ rvVal = ulong.max % aAbs + 1;
+ // otherwise, the modulus is trivially zero.
+ else
+ rvVal = 0;
+
+ rvVal = copySign(rvVal, negative);
+ return SignExtendedNumber(rvVal, rvVal != 0 && negative);
+ }
+
+ SignExtendedNumber opBinary(string op : "<<")(SignExtendedNumber rhs)
+ {
+ // assume left-shift the shift-amount is always unsigned. Thus negative
+ // shifts will give huge result.
+ if (value == 0)
+ return this;
+ else if (rhs.negative)
+ return extreme(negative);
+
+ uinteger_t v = copySign(value, negative);
+
+ // compute base-2 log of 'v' to determine the maximum allowed bits to shift.
+ // Ref: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
+
+ // Why is this a size_t? Looks like a bug.
+ size_t r, s;
+
+ r = (v > 0xFFFFFFFFUL) << 5; v >>= r;
+ s = (v > 0xFFFFUL ) << 4; v >>= s; r |= s;
+ s = (v > 0xFFUL ) << 3; v >>= s; r |= s;
+ s = (v > 0xFUL ) << 2; v >>= s; r |= s;
+ s = (v > 0x3UL ) << 1; v >>= s; r |= s;
+ r |= (v >> 1);
+
+ uinteger_t allowableShift = 63 - r;
+ if (rhs.value > allowableShift)
+ return extreme(negative);
+ else
+ return SignExtendedNumber(value << rhs.value, negative);
+ }
+
+ SignExtendedNumber opBinary(string op : ">>")(SignExtendedNumber rhs)
+ {
+ if (rhs.negative || rhs.value > 63)
+ return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
+ else if (isMinimum())
+ return rhs.value == 0 ? this : SignExtendedNumber(-1UL << (64 - rhs.value), true);
+
+ uinteger_t x = value ^ -cast(int)negative;
+ x >>= rhs.value;
+ return SignExtendedNumber(x ^ -cast(int)negative, negative);
+ }
+
+ SignExtendedNumber opBinary(string op : "^^")(SignExtendedNumber rhs)
+ {
+ // Not yet implemented
+ assert(0);
+ }
+}
+
+struct IntRange
+{
+ SignExtendedNumber imin, imax;
+
+ this(IntRange another)
+ {
+ imin = another.imin;
+ imax = another.imax;
+ }
+
+ this(SignExtendedNumber a)
+ {
+ imin = a;
+ imax = a;
+ }
+
+ this(SignExtendedNumber lower, SignExtendedNumber upper)
+ {
+ imin = lower;
+ imax = upper;
+ }
+
+ static IntRange fromType(Type type)
+ {
+ return fromType(type, type.isunsigned());
+ }
+
+ static IntRange fromType(Type type, bool isUnsigned)
+ {
+ if (!type.isintegral() || type.toBasetype().ty == Tvector)
+ return widest();
+
+ uinteger_t mask = type.sizemask();
+ auto lower = SignExtendedNumber(0);
+ auto upper = SignExtendedNumber(mask);
+ if (type.toBasetype().ty == Tdchar)
+ upper.value = 0x10FFFFUL;
+ else if (!isUnsigned)
+ {
+ lower.value = ~(mask >> 1);
+ lower.negative = true;
+ upper.value = (mask >> 1);
+ }
+ return IntRange(lower, upper);
+ }
+
+ static IntRange fromNumbers2(SignExtendedNumber* numbers)
+ {
+ if (numbers[0] < numbers[1])
+ return IntRange(numbers[0], numbers[1]);
+ else
+ return IntRange(numbers[1], numbers[0]);
+ }
+
+ static IntRange fromNumbers4(SignExtendedNumber* numbers)
+ {
+ IntRange ab = fromNumbers2(numbers);
+ IntRange cd = fromNumbers2(numbers + 2);
+ if (cd.imin < ab.imin)
+ ab.imin = cd.imin;
+ if (cd.imax > ab.imax)
+ ab.imax = cd.imax;
+ return ab;
+ }
+
+ static IntRange widest()
+ {
+ return IntRange(SignExtendedNumber.min(), SignExtendedNumber.max());
+ }
+
+ IntRange castSigned(uinteger_t mask)
+ {
+ // .... 0x1e7f ] [0x1e80 .. 0x1f7f] [0x1f80 .. 0x7f] [0x80 .. 0x17f] [0x180 ....
+ //
+ // regular signed type. We use a technique similar to the unsigned version,
+ // but the chunk has to be offset by 1/2 of the range.
+ uinteger_t halfChunkMask = mask >> 1;
+ uinteger_t minHalfChunk = imin.value & ~halfChunkMask;
+ uinteger_t maxHalfChunk = imax.value & ~halfChunkMask;
+ int minHalfChunkNegativity = imin.negative; // 1 = neg, 0 = nonneg, -1 = chunk containing ::max
+ int maxHalfChunkNegativity = imax.negative;
+ if (minHalfChunk & mask)
+ {
+ minHalfChunk += halfChunkMask + 1;
+ if (minHalfChunk == 0)
+ --minHalfChunkNegativity;
+ }
+ if (maxHalfChunk & mask)
+ {
+ maxHalfChunk += halfChunkMask + 1;
+ if (maxHalfChunk == 0)
+ --maxHalfChunkNegativity;
+ }
+ if (minHalfChunk == maxHalfChunk && minHalfChunkNegativity == maxHalfChunkNegativity)
+ {
+ imin.value &= mask;
+ imax.value &= mask;
+ // sign extend if necessary.
+ imin.negative = (imin.value & ~halfChunkMask) != 0;
+ imax.negative = (imax.value & ~halfChunkMask) != 0;
+ halfChunkMask += 1;
+ imin.value = (imin.value ^ halfChunkMask) - halfChunkMask;
+ imax.value = (imax.value ^ halfChunkMask) - halfChunkMask;
+ }
+ else
+ {
+ imin = SignExtendedNumber(~halfChunkMask, true);
+ imax = SignExtendedNumber(halfChunkMask, false);
+ }
+ return this;
+ }
+
+ IntRange castUnsigned(uinteger_t mask)
+ {
+ // .... 0x1eff ] [0x1f00 .. 0x1fff] [0 .. 0xff] [0x100 .. 0x1ff] [0x200 ....
+ //
+ // regular unsigned type. We just need to see if ir steps across the
+ // boundary of validRange. If yes, ir will represent the whole validRange,
+ // otherwise, we just take the modulus.
+ // e.g. [0x105, 0x107] & 0xff == [5, 7]
+ // [0x105, 0x207] & 0xff == [0, 0xff]
+ uinteger_t minChunk = imin.value & ~mask;
+ uinteger_t maxChunk = imax.value & ~mask;
+ if (minChunk == maxChunk && imin.negative == imax.negative)
+ {
+ imin.value &= mask;
+ imax.value &= mask;
+ }
+ else
+ {
+ imin.value = 0;
+ imax.value = mask;
+ }
+ imin.negative = imax.negative = false;
+ return this;
+ }
+
+ IntRange castDchar()
+ {
+ // special case for dchar. Casting to dchar means "I'll ignore all
+ // invalid characters."
+ castUnsigned(0xFFFFFFFFUL);
+ if (imin.value > 0x10FFFFUL) // ??
+ imin.value = 0x10FFFFUL; // ??
+ if (imax.value > 0x10FFFFUL)
+ imax.value = 0x10FFFFUL;
+ return this;
+ }
+
+ IntRange _cast(Type type)
+ {
+ if (!type.isintegral() || type.toBasetype().ty == Tvector)
+ return this;
+ else if (!type.isunsigned())
+ return castSigned(type.sizemask());
+ else if (type.toBasetype().ty == Tdchar)
+ return castDchar();
+ else
+ return castUnsigned(type.sizemask());
+ }
+
+ IntRange castUnsigned(Type type)
+ {
+ if (!type.isintegral() || type.toBasetype().ty == Tvector)
+ return castUnsigned(ulong.max);
+ else if (type.toBasetype().ty == Tdchar)
+ return castDchar();
+ else
+ return castUnsigned(type.sizemask());
+ }
+
+ bool contains(IntRange a)
+ {
+ return imin <= a.imin && imax >= a.imax;
+ }
+
+ bool containsZero() const
+ {
+ return (imin.negative && !imax.negative)
+ || (!imin.negative && imin.value == 0);
+ }
+
+ IntRange absNeg() const
+ {
+ if (imax.negative)
+ return this;
+ else if (!imin.negative)
+ return IntRange(-imax, -imin);
+ else
+ {
+ SignExtendedNumber imaxAbsNeg = -imax;
+ return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin,
+ SignExtendedNumber(0));
+ }
+ }
+
+ IntRange unionWith(const ref IntRange other) const
+ {
+ return IntRange(imin < other.imin ? imin : other.imin,
+ imax > other.imax ? imax : other.imax);
+ }
+
+ void unionOrAssign(IntRange other, ref bool union_)
+ {
+ if (!union_ || imin > other.imin)
+ imin = other.imin;
+ if (!union_ || imax < other.imax)
+ imax = other.imax;
+ union_ = true;
+ }
+
+ ref const(IntRange) dump(const(char)* funcName, Expression e) const return
+ {
+ printf("[(%c)%#018llx, (%c)%#018llx] @ %s ::: %s\n",
+ imin.negative?'-':'+', cast(ulong)imin.value,
+ imax.negative?'-':'+', cast(ulong)imax.value,
+ funcName, e.toChars());
+ return this;
+ }
+
+ void splitBySign(ref IntRange negRange, ref bool hasNegRange, ref IntRange nonNegRange, ref bool hasNonNegRange) const
+ {
+ hasNegRange = imin.negative;
+ if (hasNegRange)
+ {
+ negRange.imin = imin;
+ negRange.imax = imax.negative ? imax : SignExtendedNumber(-1, true);
+ }
+ hasNonNegRange = !imax.negative;
+ if (hasNonNegRange)
+ {
+ nonNegRange.imin = imin.negative ? SignExtendedNumber(0) : imin;
+ nonNegRange.imax = imax;
+ }
+ }
+
+ IntRange opUnary(string op:"~")() const
+ {
+ return IntRange(~imax, ~imin);
+ }
+
+ IntRange opUnary(string op : "-")()
+ {
+ return IntRange(-imax, -imin);
+ }
+
+ // Credits to Timon Gehr for the algorithms for &, |
+ // https://github.com/tgehr/d-compiler/blob/master/vrange.d
+ IntRange opBinary(string op : "&")(IntRange rhs) const
+ {
+ // unsigned or identical sign bits
+ if ((imin.negative ^ imax.negative) != 1 && (rhs.imin.negative ^ rhs.imax.negative) != 1)
+ {
+ return IntRange(minAnd(this, rhs), maxAnd(this, rhs));
+ }
+
+ IntRange l = IntRange(this);
+ IntRange r = IntRange(rhs);
+
+ // both intervals span [-1,0]
+ if ((imin.negative ^ imax.negative) == 1 && (rhs.imin.negative ^ rhs.imax.negative) == 1)
+ {
+ // cannot be larger than either l.max or r.max, set the other one to -1
+ SignExtendedNumber max = l.imax.value > r.imax.value ? l.imax : r.imax;
+
+ // only negative numbers for minimum
+ l.imax.value = -1;
+ l.imax.negative = true;
+ r.imax.value = -1;
+ r.imax.negative = true;
+
+ return IntRange(minAnd(l, r), max);
+ }
+ else
+ {
+ // only one interval spans [-1,0]
+ if ((l.imin.negative ^ l.imax.negative) == 1)
+ {
+ swap(l, r); // r spans [-1,0]
+ }
+
+ auto minAndNeg = minAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
+ auto minAndPos = minAnd(l, IntRange(SignExtendedNumber(0), r.imax));
+ auto maxAndNeg = maxAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
+ auto maxAndPos = maxAnd(l, IntRange(SignExtendedNumber(0), r.imax));
+
+ auto min = minAndNeg < minAndPos ? minAndNeg : minAndPos;
+ auto max = maxAndNeg > maxAndPos ? maxAndNeg : maxAndPos;
+
+ auto range = IntRange(min, max);
+ return range;
+ }
+ }
+
+ // Credits to Timon Gehr for the algorithms for &, |
+ // https://github.com/tgehr/d-compiler/blob/master/vrange.d
+ IntRange opBinary(string op : "|")(IntRange rhs) const
+ {
+ // unsigned or identical sign bits:
+ if ((imin.negative ^ imax.negative) == 0 && (rhs.imin.negative ^ rhs.imax.negative) == 0)
+ {
+ return IntRange(minOr(this, rhs), maxOr(this, rhs));
+ }
+
+ IntRange l = IntRange(this);
+ IntRange r = IntRange(rhs);
+
+ // both intervals span [-1,0]
+ if ((imin.negative ^ imax.negative) == 1 && (rhs.imin.negative ^ rhs.imax.negative) == 1)
+ {
+ // cannot be smaller than either l.min or r.min, set the other one to 0
+ SignExtendedNumber min = l.imin.value < r.imin.value ? l.imin : r.imin;
+
+ // only negative numbers for minimum
+ l.imin.value = 0;
+ l.imin.negative = false;
+ r.imin.value = 0;
+ r.imin.negative = false;
+
+ return IntRange(min, maxOr(l, r));
+ }
+ else
+ {
+ // only one interval spans [-1,0]
+ if ((imin.negative ^ imax.negative) == 1)
+ {
+ swap(l, r); // r spans [-1,0]
+ }
+
+ auto minOrNeg = minOr(l, IntRange(r.imin, SignExtendedNumber(-1)));
+ auto minOrPos = minOr(l, IntRange(SignExtendedNumber(0), r.imax));
+ auto maxOrNeg = maxOr(l, IntRange(r.imin, SignExtendedNumber(-1)));
+ auto maxOrPos = maxOr(l, IntRange(SignExtendedNumber(0), r.imax));
+
+ auto min = minOrNeg < minOrPos ? minOrNeg : minOrPos;
+ auto max = maxOrNeg > maxOrPos ? maxOrNeg : maxOrPos;
+
+ auto range = IntRange(min, max);
+ return range;
+ }
+ }
+
+ IntRange opBinary(string op : "^")(IntRange rhs) const
+ {
+ return this & ~rhs | ~this & rhs;
+ }
+
+ IntRange opBinary(string op : "+")(IntRange rhs)
+ {
+ return IntRange(imin + rhs.imin, imax + rhs.imax);
+ }
+
+ IntRange opBinary(string op : "-")(IntRange rhs)
+ {
+ return IntRange(imin - rhs.imax, imax - rhs.imin);
+ }
+
+ IntRange opBinary(string op : "*")(IntRange rhs)
+ {
+ // [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)]
+ SignExtendedNumber[4] bdy;
+ bdy[0] = imin * rhs.imin;
+ bdy[1] = imin * rhs.imax;
+ bdy[2] = imax * rhs.imin;
+ bdy[3] = imax * rhs.imax;
+ return IntRange.fromNumbers4(bdy.ptr);
+ }
+
+ IntRange opBinary(string op : "/")(IntRange rhs)
+ {
+ // Handle divide by 0
+ if (rhs.imax.value == 0 && rhs.imin.value == 0)
+ return widest();
+
+ // Don't treat the whole range as divide by 0 if only one end of a range is 0.
+ // Issue 15289
+ if (rhs.imax.value == 0)
+ {
+ rhs.imax.value--;
+ }
+ else if(rhs.imin.value == 0)
+ {
+ rhs.imin.value++;
+ }
+
+ if (!imin.negative && !imax.negative && !rhs.imin.negative && !rhs.imax.negative)
+ {
+ return IntRange(imin / rhs.imax, imax / rhs.imin);
+ }
+ else
+ {
+ // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
+ SignExtendedNumber[4] bdy;
+ bdy[0] = imin / rhs.imin;
+ bdy[1] = imin / rhs.imax;
+ bdy[2] = imax / rhs.imin;
+ bdy[3] = imax / rhs.imax;
+
+ return IntRange.fromNumbers4(bdy.ptr);
+ }
+ }
+
+ IntRange opBinary(string op : "%")(IntRange rhs)
+ {
+ IntRange irNum = this;
+ IntRange irDen = rhs.absNeg();
+
+ /*
+ due to the rules of D (C)'s % operator, we need to consider the cases
+ separately in different range of signs.
+
+ case 1. [500, 1700] % [7, 23] (numerator is always positive)
+ = [0, 22]
+ case 2. [-500, 1700] % [7, 23] (numerator can be negative)
+ = [-22, 22]
+ case 3. [-1700, -500] % [7, 23] (numerator is always negative)
+ = [-22, 0]
+
+ the number 22 is the maximum absolute value in the denomator's range. We
+ don't care about divide by zero.
+ */
+
+ irDen.imin = irDen.imin + SignExtendedNumber(1);
+ irDen.imax = -irDen.imin;
+
+ if (!irNum.imin.negative)
+ {
+ irNum.imin.value = 0;
+ }
+ else if (irNum.imin < irDen.imin)
+ {
+ irNum.imin = irDen.imin;
+ }
+
+ if (irNum.imax.negative)
+ {
+ irNum.imax.negative = false;
+ irNum.imax.value = 0;
+ }
+ else if (irNum.imax > irDen.imax)
+ {
+ irNum.imax = irDen.imax;
+ }
+
+ return irNum;
+ }
+
+ IntRange opBinary(string op : "<<")(IntRange rhs)
+ {
+ if (rhs.imin.negative)
+ {
+ rhs = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
+ }
+
+ SignExtendedNumber lower = imin << (imin.negative ? rhs.imax : rhs.imin);
+ SignExtendedNumber upper = imax << (imax.negative ? rhs.imin : rhs.imax);
+
+ return IntRange(lower, upper);
+ }
+
+ IntRange opBinary(string op : ">>")(IntRange rhs)
+ {
+ if (rhs.imin.negative)
+ {
+ rhs = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
+ }
+
+ SignExtendedNumber lower = imin >> (imin.negative ? rhs.imin : rhs.imax);
+ SignExtendedNumber upper = imax >> (imax.negative ? rhs.imax : rhs.imin);
+
+ return IntRange(lower, upper);
+ }
+
+ IntRange opBinary(string op : ">>>")(IntRange rhs)
+ {
+ if (rhs.imin.negative)
+ {
+ rhs = IntRange(SignExtendedNumber(0), SignExtendedNumber(64));
+ }
+
+ return IntRange(imin >> rhs.imax, imax >> rhs.imin);
+ }
+
+ IntRange opBinary(string op : "^^")(IntRange rhs)
+ {
+ // Not yet implemented
+ assert(0);
+ }
+
+private:
+ // Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd
+ // https://github.com/tgehr/d-compiler/blob/master/vrange.d
+ static SignExtendedNumber maxOr(const IntRange lhs, const IntRange rhs)
+ {
+ uinteger_t x = 0;
+ auto sign = false;
+ auto xor = lhs.imax.value ^ rhs.imax.value;
+ auto and = lhs.imax.value & rhs.imax.value;
+ auto lhsc = IntRange(lhs);
+ auto rhsc = IntRange(rhs);
+
+ // Sign bit not part of the .value so we need an extra iteration
+ if (lhsc.imax.negative ^ rhsc.imax.negative)
+ {
+ sign = true;
+ if (lhsc.imax.negative)
+ {
+ if (!lhsc.imin.negative)
+ {
+ lhsc.imin.value = 0;
+ }
+ if (!rhsc.imin.negative)
+ {
+ rhsc.imin.value = 0;
+ }
+ }
+ }
+ else if (lhsc.imin.negative & rhsc.imin.negative)
+ {
+ sign = true;
+ }
+ else if (lhsc.imax.negative & rhsc.imax.negative)
+ {
+ return SignExtendedNumber(-1, false);
+ }
+
+ for (uinteger_t d = 1LU << (8 * uinteger_t.sizeof - 1); d; d >>= 1)
+ {
+ if (xor & d)
+ {
+ x |= d;
+ if (lhsc.imax.value & d)
+ {
+ if (~lhsc.imin.value & d)
+ {
+ lhsc.imin.value = 0;
+ }
+ }
+ else
+ {
+ if (~rhsc.imin.value & d)
+ {
+ rhsc.imin.value = 0;
+ }
+ }
+ }
+ else if (lhsc.imin.value & rhsc.imin.value & d)
+ {
+ x |= d;
+ }
+ else if (and & d)
+ {
+ x |= (d << 1) - 1;
+ break;
+ }
+ }
+
+ auto range = SignExtendedNumber(x, sign);
+ return range;
+ }
+
+ // Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd
+ // https://github.com/tgehr/d-compiler/blob/master/vrange.d
+ static SignExtendedNumber minOr(const IntRange lhs, const IntRange rhs)
+ {
+ return ~maxAnd(~lhs, ~rhs);
+ }
+
+ // Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd
+ // https://github.com/tgehr/d-compiler/blob/master/vrange.d
+ static SignExtendedNumber maxAnd(const IntRange lhs, const IntRange rhs)
+ {
+ uinteger_t x = 0;
+ bool sign = false;
+ auto lhsc = IntRange(lhs);
+ auto rhsc = IntRange(rhs);
+
+ if (lhsc.imax.negative & rhsc.imax.negative)
+ {
+ sign = true;
+ }
+
+ for (uinteger_t d = 1LU << (8 * uinteger_t.sizeof - 1); d; d >>= 1)
+ {
+ if (lhsc.imax.value & rhsc.imax.value & d)
+ {
+ x |= d;
+ if (~lhsc.imin.value & d)
+ {
+ lhsc.imin.value = 0;
+ }
+ if (~rhsc.imin.value & d)
+ {
+ rhsc.imin.value = 0;
+ }
+ }
+ else if (~lhsc.imin.value & d && lhsc.imax.value & d)
+ {
+ lhsc.imax.value |= d - 1;
+ }
+ else if (~rhsc.imin.value & d && rhsc.imax.value & d)
+ {
+ rhsc.imax.value |= d - 1;
+ }
+ }
+
+ auto range = SignExtendedNumber(x, sign);
+ return range;
+ }
+
+ // Credits to Timon Gehr maxOr, minOr, maxAnd, minAnd
+ // https://github.com/tgehr/d-compiler/blob/master/vrange.d
+ static SignExtendedNumber minAnd(const IntRange lhs, const IntRange rhs)
+ {
+ return ~maxOr(~lhs, ~rhs);
+ }
+
+ static swap(ref IntRange a, ref IntRange b)
+ {
+ auto aux = a;
+ a = b;
+ b = aux;
+ }
+}
diff --git a/gcc/d/dmd/json.c b/gcc/d/dmd/json.c
deleted file mode 100644
index 832e559..0000000
--- a/gcc/d/dmd/json.c
+++ /dev/null
@@ -1,888 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/json.c
- */
-
-// This implements the JSON capability.
-
-#include "root/dsystem.h"
-#include "root/rmem.h"
-
-#include "mars.h"
-#include "dsymbol.h"
-#include "template.h"
-#include "aggregate.h"
-#include "declaration.h"
-#include "enum.h"
-#include "module.h"
-#include "json.h"
-#include "mtype.h"
-#include "attrib.h"
-#include "cond.h"
-#include "init.h"
-#include "import.h"
-#include "id.h"
-#include "hdrgen.h"
-
-class ToJsonVisitor : public Visitor
-{
-public:
- OutBuffer *buf;
- int indentLevel;
- const char *filename;
-
- ToJsonVisitor(OutBuffer *buf)
- : buf(buf), indentLevel(0), filename(NULL)
- {
- }
-
- void indent()
- {
- if (buf->length() >= 1 &&
- buf->slice().ptr[buf->length() - 1] == '\n')
- for (int i = 0; i < indentLevel; i++)
- buf->writeByte(' ');
- }
-
- void removeComma()
- {
- if (buf->length() >= 2 &&
- buf->slice().ptr[buf->length() - 2] == ',' &&
- (buf->slice().ptr[buf->length() - 1] == '\n' || buf->slice().ptr[buf->length() - 1] == ' '))
- buf->setsize(buf->length() - 2);
- }
-
- void comma()
- {
- if (indentLevel > 0)
- buf->writestring(",\n");
- }
-
- void stringStart()
- {
- buf->writeByte('\"');
- }
-
- void stringEnd()
- {
- buf->writeByte('\"');
- }
-
- void stringPart(const char *s)
- {
- for (; *s; s++)
- {
- utf8_t c = (utf8_t) *s;
- switch (c)
- {
- case '\n':
- buf->writestring("\\n");
- break;
-
- case '\r':
- buf->writestring("\\r");
- break;
-
- case '\t':
- buf->writestring("\\t");
- break;
-
- case '\"':
- buf->writestring("\\\"");
- break;
-
- case '\\':
- buf->writestring("\\\\");
- break;
-
- case '\b':
- buf->writestring("\\b");
- break;
-
- case '\f':
- buf->writestring("\\f");
- break;
-
- default:
- if (c < 0x20)
- buf->printf("\\u%04x", c);
- else
- {
- // Note that UTF-8 chars pass through here just fine
- buf->writeByte(c);
- }
- break;
- }
- }
- }
-
- // Json value functions
-
- /*********************************
- * Encode string into buf, and wrap it in double quotes.
- */
- void value(const char *s)
- {
- stringStart();
- stringPart(s);
- stringEnd();
- }
-
- void value(int value)
- {
- buf->printf("%d", value);
- }
-
- void valueBool(bool value)
- {
- buf->writestring(value ? "true" : "false");
- }
-
- /*********************************
- * Item is an intented value and a comma, for use in arrays
- */
- void item(const char *s)
- {
- indent();
- value(s);
- comma();
- }
-
- void item(int i)
- {
- indent();
- value(i);
- comma();
- }
-
- void itemBool(bool b)
- {
- indent();
- valueBool(b);
- comma();
- }
-
-
- // Json array functions
-
- void arrayStart()
- {
- indent();
- buf->writestring("[\n");
- indentLevel++;
- }
-
- void arrayEnd()
- {
- indentLevel--;
- removeComma();
- if (buf->length() >= 2 &&
- buf->slice().ptr[buf->length() - 2] == '[' &&
- buf->slice().ptr[buf->length() - 1] == '\n')
- buf->setsize(buf->length() - 1);
- else if (!(buf->length() >= 1 &&
- buf->slice().ptr[buf->length() - 1] == '['))
- {
- buf->writestring("\n");
- indent();
- }
- buf->writestring("]");
- comma();
- }
-
-
- // Json object functions
-
- void objectStart()
- {
- indent();
- buf->writestring("{\n");
- indentLevel++;
- }
-
- void objectEnd()
- {
- indentLevel--;
- removeComma();
- if (buf->length() >= 2 &&
- buf->slice().ptr[buf->length() - 2] == '{' &&
- buf->slice().ptr[buf->length() - 1] == '\n')
- buf->setsize(buf->length() - 1);
- else
- {
- buf->writestring("\n");
- indent();
- }
- buf->writestring("}");
- comma();
- }
-
- // Json object property functions
-
- void propertyStart(const char *name)
- {
- indent();
- value(name);
- buf->writestring(" : ");
- }
-
- void property(const char *name, const char *s)
- {
- if (s == NULL) return;
-
- propertyStart(name);
- value(s);
- comma();
- }
-
- void property(const char *name, int i)
- {
- propertyStart(name);
- value(i);
- comma();
- }
-
- void propertyBool(const char *name, bool b)
- {
- propertyStart(name);
- valueBool(b);
- comma();
- }
-
-
- void property(const char *name, TRUST trust)
- {
- switch (trust)
- {
- case TRUSTdefault:
- // Should not be printed
- //property(name, "default");
- break;
- case TRUSTsystem:
- property(name, "system");
- break;
- case TRUSTtrusted:
- property(name, "trusted");
- break;
- case TRUSTsafe:
- property(name, "safe");
- break;
- default:
- assert(false);
- }
- }
-
- void property(const char *name, PURE purity)
- {
- switch (purity)
- {
- case PUREimpure:
- // Should not be printed
- //property(name, "impure");
- break;
- case PUREweak:
- property(name, "weak");
- break;
- case PUREconst:
- property(name, "const");
- break;
- case PUREstrong:
- property(name, "strong");
- break;
- case PUREfwdref:
- property(name, "fwdref");
- break;
- default:
- assert(false);
- }
- }
-
- void property(const char *name, LINK linkage)
- {
- switch (linkage)
- {
- case LINKdefault:
- // Should not be printed
- //property(name, "default");
- break;
- case LINKd:
- // Should not be printed
- //property(name, "d");
- break;
- case LINKc:
- property(name, "c");
- break;
- case LINKcpp:
- property(name, "cpp");
- break;
- case LINKwindows:
- property(name, "windows");
- break;
- default:
- assert(false);
- }
- }
-
- void propertyStorageClass(const char *name, StorageClass stc)
- {
- stc &= STCStorageClass;
- if (stc)
- {
- propertyStart(name);
- arrayStart();
-
- while (stc)
- {
- const char *p = stcToChars(stc);
- assert(p);
- item(p);
- }
-
- arrayEnd();
- }
- }
-
- void property(const char *linename, const char *charname, Loc *loc)
- {
- if (loc)
- {
- const char *filename = loc->filename;
- if (filename)
- {
- if (!this->filename || strcmp(filename, this->filename))
- {
- this->filename = filename;
- property("file", filename);
- }
- }
-
- if (loc->linnum)
- {
- property(linename, loc->linnum);
- if (loc->charnum)
- property(charname, loc->charnum);
- }
- }
- }
-
- void property(const char *name, Type *type)
- {
- if (type)
- {
- property(name, type->toChars());
- }
- }
-
- void property(const char *name, const char *deconame, Type *type)
- {
- if (type)
- {
- if (type->deco)
- property(deconame, type->deco);
- else
- property(name, type->toChars());
- }
- }
-
- void property(const char *name, Parameters *parameters)
- {
- if (parameters == NULL || parameters->length == 0)
- return;
-
- propertyStart(name);
- arrayStart();
-
- if (parameters)
- {
- for (size_t i = 0; i < parameters->length; i++)
- {
- Parameter *p = (*parameters)[i];
- objectStart();
-
- if (p->ident)
- property("name", p->ident->toChars());
-
- property("type", "deco", p->type);
-
- propertyStorageClass("storageClass", p->storageClass);
-
- if (p->defaultArg)
- property("default", p->defaultArg->toChars());
-
-
- objectEnd();
- }
- }
-
- arrayEnd();
- }
-
- /* ========================================================================== */
-
- void jsonProperties(Dsymbol *s)
- {
- if (s->isModule())
- return;
-
- if (!s->isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes
- {
- property("name", s->toChars());
- property("kind", s->kind());
- }
-
- if (s->prot().kind != Prot::public_) // TODO: How about package(names)?
- property("protection", protectionToChars(s->prot().kind));
-
- if (EnumMember *em = s->isEnumMember())
- {
- if (em->origValue)
- property("value", em->origValue->toChars());
- }
-
- property("comment", (const char *)s->comment);
-
- property("line", "char", &s->loc);
- }
-
- void jsonProperties(Declaration *d)
- {
- if (d->storage_class & STClocal)
- return;
- jsonProperties((Dsymbol *)d);
-
- propertyStorageClass("storageClass", d->storage_class);
-
- property("type", "deco", d->type);
-
- // Emit originalType if it differs from type
- if (d->type != d->originalType && d->originalType)
- {
- const char *ostr = d->originalType->toChars();
- if (d->type)
- {
- const char *tstr = d->type->toChars();
- if (strcmp(tstr, ostr))
- {
- //printf("tstr = %s, ostr = %s\n", tstr, ostr);
- property("originalType", ostr);
- }
- }
- else
- property("originalType", ostr);
- }
- }
-
- void jsonProperties(TemplateDeclaration *td)
- {
- jsonProperties((Dsymbol *)td);
-
- if (td->onemember && td->onemember->isCtorDeclaration())
- property("name", "this"); // __ctor -> this
- else
- property("name", td->ident->toChars()); // Foo(T) -> Foo
- }
-
- /* ========================================================================== */
-
- void visit(Dsymbol *)
- {
- }
-
- void visit(Module *s)
- {
- objectStart();
-
- if (s->md)
- property("name", s->md->toChars());
-
- property("kind", s->kind());
-
- filename = s->srcfile->toChars();
- property("file", filename);
-
- property("comment", (const char *)s->comment);
-
- propertyStart("members");
- arrayStart();
- for (size_t i = 0; i < s->members->length; i++)
- {
- (*s->members)[i]->accept(this);
- }
- arrayEnd();
-
- objectEnd();
- }
-
- void visit(Import *s)
- {
- if (s->id == Id::object)
- return;
-
- objectStart();
-
- propertyStart("name");
- stringStart();
- if (s->packages && s->packages->length)
- {
- for (size_t i = 0; i < s->packages->length; i++)
- {
- Identifier *pid = (*s->packages)[i];
- stringPart(pid->toChars());
- buf->writeByte('.');
- }
- }
- stringPart(s->id->toChars());
- stringEnd();
- comma();
-
- property("kind", s->kind());
- property("comment", (const char *)s->comment);
- property("line", "char", &s->loc);
- if (s->prot().kind != Prot::public_)
- property("protection", protectionToChars(s->prot().kind));
- if (s->aliasId)
- property("alias", s->aliasId->toChars());
-
- bool hasRenamed = false;
- bool hasSelective = false;
- for (size_t i = 0; i < s->aliases.length; i++)
- {
- // avoid empty "renamed" and "selective" sections
- if (hasRenamed && hasSelective)
- break;
- else if (s->aliases[i])
- hasRenamed = true;
- else
- hasSelective = true;
- }
-
- if (hasRenamed)
- {
- // import foo : alias1 = target1;
- propertyStart("renamed");
- objectStart();
- for (size_t i = 0; i < s->aliases.length; i++)
- {
- Identifier *name = s->names[i];
- Identifier *alias = s->aliases[i];
- if (alias) property(alias->toChars(), name->toChars());
- }
- objectEnd();
- }
-
- if (hasSelective)
- {
- // import foo : target1;
- propertyStart("selective");
- arrayStart();
- for (size_t i = 0; i < s->names.length; i++)
- {
- Identifier *name = s->names[i];
- if (!s->aliases[i]) item(name->toChars());
- }
- arrayEnd();
- }
-
- objectEnd();
- }
-
- void visit(AttribDeclaration *d)
- {
- Dsymbols *ds = d->include(NULL);
-
- if (ds)
- {
- for (size_t i = 0; i < ds->length; i++)
- {
- Dsymbol *s = (*ds)[i];
- s->accept(this);
- }
- }
- }
-
- void visit(ConditionalDeclaration *d)
- {
- if (d->condition->inc)
- {
- visit((AttribDeclaration *)d);
- }
- }
-
- void visit(TypeInfoDeclaration *) {}
- void visit(PostBlitDeclaration *) {}
-
- void visit(Declaration *d)
- {
- objectStart();
-
- //property("unknown", "declaration");
-
- jsonProperties(d);
-
- objectEnd();
- }
-
- void visit(AggregateDeclaration *d)
- {
- objectStart();
-
- jsonProperties(d);
-
- ClassDeclaration *cd = d->isClassDeclaration();
- if (cd)
- {
- if (cd->baseClass && cd->baseClass->ident != Id::Object)
- {
- property("base", cd->baseClass->toPrettyChars(true));
- }
- if (cd->interfaces.length)
- {
- propertyStart("interfaces");
- arrayStart();
- for (size_t i = 0; i < cd->interfaces.length; i++)
- {
- BaseClass *b = cd->interfaces.ptr[i];
- item(b->sym->toPrettyChars(true));
- }
- arrayEnd();
- }
- }
-
- if (d->members)
- {
- propertyStart("members");
- arrayStart();
- for (size_t i = 0; i < d->members->length; i++)
- {
- Dsymbol *s = (*d->members)[i];
- s->accept(this);
- }
- arrayEnd();
- }
-
- objectEnd();
- }
-
- void visit(FuncDeclaration *d)
- {
- objectStart();
-
- jsonProperties(d);
-
- TypeFunction *tf = (TypeFunction *)d->type;
- if (tf && tf->ty == Tfunction)
- property("parameters", tf->parameterList.parameters);
-
- property("endline", "endchar", &d->endloc);
-
- if (d->foverrides.length)
- {
- propertyStart("overrides");
- arrayStart();
- for (size_t i = 0; i < d->foverrides.length; i++)
- {
- FuncDeclaration *fd = d->foverrides[i];
- item(fd->toPrettyChars());
- }
- arrayEnd();
- }
-
- if (d->fdrequire)
- {
- propertyStart("in");
- d->fdrequire->accept(this);
- }
-
- if (d->fdensure)
- {
- propertyStart("out");
- d->fdensure->accept(this);
- }
-
- objectEnd();
- }
-
- void visit(TemplateDeclaration *d)
- {
- objectStart();
-
- // TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one
- property("kind", "template");
-
- jsonProperties(d);
-
- propertyStart("parameters");
- arrayStart();
- for (size_t i = 0; i < d->parameters->length; i++)
- {
- TemplateParameter *s = (*d->parameters)[i];
- objectStart();
-
- property("name", s->ident->toChars());
-
- TemplateTypeParameter *type = s->isTemplateTypeParameter();
- if (type)
- {
- if (s->isTemplateThisParameter())
- property("kind", "this");
- else
- property("kind", "type");
- property("type", "deco", type->specType);
-
- property("default", "defaultDeco", type->defaultType);
- }
-
- TemplateValueParameter *value = s->isTemplateValueParameter();
- if (value)
- {
- property("kind", "value");
-
- property("type", "deco", value->valType);
-
- if (value->specValue)
- property("specValue", value->specValue->toChars());
-
- if (value->defaultValue)
- property("defaultValue", value->defaultValue->toChars());
- }
-
- TemplateAliasParameter *alias = s->isTemplateAliasParameter();
- if (alias)
- {
- property("kind", "alias");
-
- property("type", "deco", alias->specType);
-
- if (alias->specAlias)
- property("specAlias", alias->specAlias->toChars());
-
- if (alias->defaultAlias)
- property("defaultAlias", alias->defaultAlias->toChars());
- }
-
- TemplateTupleParameter *tuple = s->isTemplateTupleParameter();
- if (tuple)
- {
- property("kind", "tuple");
- }
-
- objectEnd();
- }
- arrayEnd();
-
- Expression *expression = d->constraint;
- if (expression)
- {
- property("constraint", expression->toChars());
- }
-
- propertyStart("members");
- arrayStart();
- for (size_t i = 0; i < d->members->length; i++)
- {
- Dsymbol *s = (*d->members)[i];
- s->accept(this);
- }
- arrayEnd();
-
- objectEnd();
- }
-
- void visit(EnumDeclaration *d)
- {
- if (d->isAnonymous())
- {
- if (d->members)
- {
- for (size_t i = 0; i < d->members->length; i++)
- {
- Dsymbol *s = (*d->members)[i];
- s->accept(this);
- }
- }
- return;
- }
-
- objectStart();
-
- jsonProperties(d);
-
- property("base", "baseDeco", d->memtype);
-
- if (d->members)
- {
- propertyStart("members");
- arrayStart();
- for (size_t i = 0; i < d->members->length; i++)
- {
- Dsymbol *s = (*d->members)[i];
- s->accept(this);
- }
- arrayEnd();
- }
-
- objectEnd();
- }
-
- void visit(EnumMember *s)
- {
- objectStart();
-
- jsonProperties((Dsymbol*)s);
-
- property("type", "deco", s->origType);
-
- objectEnd();
- }
-
- void visit(VarDeclaration *d)
- {
- if (d->storage_class & STClocal)
- return;
- objectStart();
-
- jsonProperties(d);
-
- if (d->_init)
- property("init", d->_init->toChars());
-
- if (d->isField())
- property("offset", d->offset);
-
- if (d->alignment && d->alignment != STRUCTALIGN_DEFAULT)
- property("align", d->alignment);
-
- objectEnd();
- }
-
- void visit(TemplateMixin *d)
- {
- objectStart();
-
- jsonProperties(d);
-
- objectEnd();
- }
-};
-
-
-void json_generate(OutBuffer *buf, Modules *modules)
-{
- ToJsonVisitor json(buf);
-
- json.arrayStart();
- for (size_t i = 0; i < modules->length; i++)
- {
- Module *m = (*modules)[i];
- if (global.params.verbose)
- message("json gen %s", m->toChars());
- m->accept(&json);
- }
- json.arrayEnd();
- json.removeComma();
-}
diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d
new file mode 100644
index 0000000..bfd31bc
--- /dev/null
+++ b/gcc/d/dmd/json.d
@@ -0,0 +1,1085 @@
+/**
+ * Code for generating .json descriptions of the module when passing the `-X` flag to dmd.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/json.d, _json.d)
+ * Documentation: https://dlang.org/phobos/dmd_json.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/json.d
+ */
+
+module dmd.json;
+
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.cond;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dimport;
+import dmd.dmodule;
+import dmd.dsymbol;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.root.outbuffer;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.target;
+import dmd.visitor;
+
+version(Windows) {
+ extern (C) char* getcwd(char* buffer, size_t maxlen);
+} else {
+ import core.sys.posix.unistd : getcwd;
+}
+
+private extern (C++) final class ToJsonVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+public:
+ OutBuffer* buf;
+ int indentLevel;
+ const(char)[] filename;
+
+ extern (D) this(OutBuffer* buf)
+ {
+ this.buf = buf;
+ }
+
+
+ void indent()
+ {
+ if (buf.length >= 1 && (*buf)[buf.length - 1] == '\n')
+ for (int i = 0; i < indentLevel; i++)
+ buf.writeByte(' ');
+ }
+
+ void removeComma()
+ {
+ if (buf.length >= 2 && (*buf)[buf.length - 2] == ',' && ((*buf)[buf.length - 1] == '\n' || (*buf)[buf.length - 1] == ' '))
+ buf.setsize(buf.length - 2);
+ }
+
+ void comma()
+ {
+ if (indentLevel > 0)
+ buf.writestring(",\n");
+ }
+
+ void stringStart()
+ {
+ buf.writeByte('\"');
+ }
+
+ void stringEnd()
+ {
+ buf.writeByte('\"');
+ }
+
+ extern(D) void stringPart(const char[] s)
+ {
+ foreach (char c; s)
+ {
+ switch (c)
+ {
+ case '\n':
+ buf.writestring("\\n");
+ break;
+ case '\r':
+ buf.writestring("\\r");
+ break;
+ case '\t':
+ buf.writestring("\\t");
+ break;
+ case '\"':
+ buf.writestring("\\\"");
+ break;
+ case '\\':
+ buf.writestring("\\\\");
+ break;
+ case '\b':
+ buf.writestring("\\b");
+ break;
+ case '\f':
+ buf.writestring("\\f");
+ break;
+ default:
+ if (c < 0x20)
+ buf.printf("\\u%04x", c);
+ else
+ {
+ // Note that UTF-8 chars pass through here just fine
+ buf.writeByte(c);
+ }
+ break;
+ }
+ }
+ }
+
+ // Json value functions
+ /*********************************
+ * Encode string into buf, and wrap it in double quotes.
+ */
+ extern(D) void value(const char[] s)
+ {
+ stringStart();
+ stringPart(s);
+ stringEnd();
+ }
+
+ void value(int value)
+ {
+ if (value < 0)
+ {
+ buf.writeByte('-');
+ value = -value;
+ }
+ buf.print(value);
+ }
+
+ void valueBool(bool value)
+ {
+ buf.writestring(value ? "true" : "false");
+ }
+
+ /*********************************
+ * Item is an intented value and a comma, for use in arrays
+ */
+ extern(D) void item(const char[] s)
+ {
+ indent();
+ value(s);
+ comma();
+ }
+
+ void item(int i)
+ {
+ indent();
+ value(i);
+ comma();
+ }
+
+ void itemBool(const bool b)
+ {
+ indent();
+ valueBool(b);
+ comma();
+ }
+
+ // Json array functions
+ void arrayStart()
+ {
+ indent();
+ buf.writestring("[\n");
+ indentLevel++;
+ }
+
+ void arrayEnd()
+ {
+ indentLevel--;
+ removeComma();
+ if (buf.length >= 2 && (*buf)[buf.length - 2] == '[' && (*buf)[buf.length - 1] == '\n')
+ buf.setsize(buf.length - 1);
+ else if (!(buf.length >= 1 && (*buf)[buf.length - 1] == '['))
+ {
+ buf.writestring("\n");
+ indent();
+ }
+ buf.writestring("]");
+ comma();
+ }
+
+ // Json object functions
+ void objectStart()
+ {
+ indent();
+ buf.writestring("{\n");
+ indentLevel++;
+ }
+
+ void objectEnd()
+ {
+ indentLevel--;
+ removeComma();
+ if (buf.length >= 2 && (*buf)[buf.length - 2] == '{' && (*buf)[buf.length - 1] == '\n')
+ buf.setsize(buf.length - 1);
+ else
+ {
+ buf.writestring("\n");
+ indent();
+ }
+ buf.writestring("}");
+ comma();
+ }
+
+ // Json object property functions
+ extern(D) void propertyStart(const char[] name)
+ {
+ indent();
+ value(name);
+ buf.writestring(" : ");
+ }
+
+ /**
+ Write the given string object property only if `s` is not null.
+
+ Params:
+ name = the name of the object property
+ s = the string value of the object property
+ */
+ extern(D) void property(const char[] name, const char[] s)
+ {
+ if (s is null)
+ return;
+ propertyStart(name);
+ value(s);
+ comma();
+ }
+
+ /**
+ Write the given string object property.
+
+ Params:
+ name = the name of the object property
+ s = the string value of the object property
+ */
+ extern(D) void requiredProperty(const char[] name, const char[] s)
+ {
+ propertyStart(name);
+ if (s is null)
+ buf.writestring("null");
+ else
+ value(s);
+ comma();
+ }
+
+ extern(D) void property(const char[] name, int i)
+ {
+ propertyStart(name);
+ value(i);
+ comma();
+ }
+
+ extern(D) void propertyBool(const char[] name, const bool b)
+ {
+ propertyStart(name);
+ valueBool(b);
+ comma();
+ }
+
+ extern(D) void property(const char[] name, TRUST trust)
+ {
+ final switch (trust)
+ {
+ case TRUST.default_:
+ // Should not be printed
+ //property(name, "default");
+ break;
+ case TRUST.system: return property(name, "system");
+ case TRUST.trusted: return property(name, "trusted");
+ case TRUST.safe: return property(name, "safe");
+ }
+ }
+
+ extern(D) void property(const char[] name, PURE purity)
+ {
+ final switch (purity)
+ {
+ case PURE.impure:
+ // Should not be printed
+ //property(name, "impure");
+ break;
+ case PURE.weak: return property(name, "weak");
+ case PURE.const_: return property(name, "const");
+ case PURE.strong: return property(name, "strong");
+ case PURE.fwdref: return property(name, "fwdref");
+ }
+ }
+
+ extern(D) void property(const char[] name, const LINK linkage)
+ {
+ final switch (linkage)
+ {
+ case LINK.default_:
+ // Should not be printed
+ //property(name, "default");
+ break;
+ case LINK.d:
+ // Should not be printed
+ //property(name, "d");
+ break;
+ case LINK.system:
+ // Should not be printed
+ //property(name, "system");
+ break;
+ case LINK.c: return property(name, "c");
+ case LINK.cpp: return property(name, "cpp");
+ case LINK.windows: return property(name, "windows");
+ case LINK.objc: return property(name, "objc");
+ }
+ }
+
+ extern(D) void propertyStorageClass(const char[] name, StorageClass stc)
+ {
+ stc &= STC.visibleStorageClasses;
+ if (stc)
+ {
+ propertyStart(name);
+ arrayStart();
+ while (stc)
+ {
+ auto p = stcToString(stc);
+ assert(p.length);
+ item(p);
+ }
+ arrayEnd();
+ }
+ }
+
+ extern(D) void property(const char[] linename, const char[] charname, const ref Loc loc)
+ {
+ if (loc.isValid())
+ {
+ if (auto filename = loc.filename.toDString)
+ {
+ if (filename != this.filename)
+ {
+ this.filename = filename;
+ property("file", filename);
+ }
+ }
+ if (loc.linnum)
+ {
+ property(linename, loc.linnum);
+ if (loc.charnum)
+ property(charname, loc.charnum);
+ }
+ }
+ }
+
+ extern(D) void property(const char[] name, Type type)
+ {
+ if (type)
+ {
+ property(name, type.toString());
+ }
+ }
+
+ extern(D) void property(const char[] name, const char[] deconame, Type type)
+ {
+ if (type)
+ {
+ if (type.deco)
+ property(deconame, type.deco.toDString);
+ else
+ property(name, type.toString());
+ }
+ }
+
+ extern(D) void property(const char[] name, Parameters* parameters)
+ {
+ if (parameters is null || parameters.dim == 0)
+ return;
+ propertyStart(name);
+ arrayStart();
+ if (parameters)
+ {
+ for (size_t i = 0; i < parameters.dim; i++)
+ {
+ Parameter p = (*parameters)[i];
+ objectStart();
+ if (p.ident)
+ property("name", p.ident.toString());
+ property("type", "deco", p.type);
+ propertyStorageClass("storageClass", p.storageClass);
+ if (p.defaultArg)
+ property("default", p.defaultArg.toString());
+ objectEnd();
+ }
+ }
+ arrayEnd();
+ }
+
+ /* ========================================================================== */
+ void jsonProperties(Dsymbol s)
+ {
+ if (s.isModule())
+ return;
+ if (!s.isTemplateDeclaration()) // TemplateDeclaration::kind() acts weird sometimes
+ {
+ property("name", s.toString());
+ if (s.isStaticCtorDeclaration())
+ {
+ property("kind", s.isSharedStaticCtorDeclaration()
+ ? "shared static constructor" : "static constructor");
+ }
+ else if (s.isStaticDtorDeclaration())
+ {
+ property("kind", s.isSharedStaticDtorDeclaration()
+ ? "shared static destructor" : "static destructor");
+ }
+ else
+ property("kind", s.kind.toDString);
+ }
+ // TODO: How about package(names)?
+ property("protection", visibilityToString(s.visible().kind));
+ if (EnumMember em = s.isEnumMember())
+ {
+ if (em.origValue)
+ property("value", em.origValue.toString());
+ }
+ property("comment", s.comment.toDString);
+ property("line", "char", s.loc);
+ }
+
+ void jsonProperties(Declaration d)
+ {
+ if (d.storage_class & STC.local)
+ return;
+ jsonProperties(cast(Dsymbol)d);
+ propertyStorageClass("storageClass", d.storage_class);
+ property("linkage", d.linkage);
+ property("type", "deco", d.type);
+ // Emit originalType if it differs from type
+ if (d.type != d.originalType && d.originalType)
+ {
+ auto ostr = d.originalType.toString();
+ if (d.type)
+ {
+ auto tstr = d.type.toString();
+ if (ostr != tstr)
+ {
+ //printf("tstr = %s, ostr = %s\n", tstr, ostr);
+ property("originalType", ostr);
+ }
+ }
+ else
+ property("originalType", ostr);
+ }
+ }
+
+ void jsonProperties(TemplateDeclaration td)
+ {
+ jsonProperties(cast(Dsymbol)td);
+ if (td.onemember && td.onemember.isCtorDeclaration())
+ property("name", "this"); // __ctor -> this
+ else
+ property("name", td.ident.toString()); // Foo(T) -> Foo
+ }
+
+ /* ========================================================================== */
+ override void visit(Dsymbol s)
+ {
+ }
+
+ override void visit(Module s)
+ {
+ objectStart();
+ if (s.md)
+ property("name", s.md.toString());
+ property("kind", s.kind.toDString);
+ filename = s.srcfile.toString();
+ property("file", filename);
+ property("comment", s.comment.toDString);
+ propertyStart("members");
+ arrayStart();
+ for (size_t i = 0; i < s.members.dim; i++)
+ {
+ (*s.members)[i].accept(this);
+ }
+ arrayEnd();
+ objectEnd();
+ }
+
+ override void visit(Import s)
+ {
+ if (s.id == Id.object)
+ return;
+ objectStart();
+ propertyStart("name");
+ stringStart();
+ foreach (const pid; s.packages){
+ stringPart(pid.toString());
+ buf.writeByte('.');
+ }
+ stringPart(s.id.toString());
+ stringEnd();
+ comma();
+ property("kind", s.kind.toDString);
+ property("comment", s.comment.toDString);
+ property("line", "char", s.loc);
+ if (s.visible().kind != Visibility.Kind.public_)
+ property("protection", visibilityToString(s.visible().kind));
+ if (s.aliasId)
+ property("alias", s.aliasId.toString());
+ bool hasRenamed = false;
+ bool hasSelective = false;
+ for (size_t i = 0; i < s.aliases.dim; i++)
+ {
+ // avoid empty "renamed" and "selective" sections
+ if (hasRenamed && hasSelective)
+ break;
+ else if (s.aliases[i])
+ hasRenamed = true;
+ else
+ hasSelective = true;
+ }
+ if (hasRenamed)
+ {
+ // import foo : alias1 = target1;
+ propertyStart("renamed");
+ objectStart();
+ for (size_t i = 0; i < s.aliases.dim; i++)
+ {
+ const name = s.names[i];
+ const _alias = s.aliases[i];
+ if (_alias)
+ property(_alias.toString(), name.toString());
+ }
+ objectEnd();
+ }
+ if (hasSelective)
+ {
+ // import foo : target1;
+ propertyStart("selective");
+ arrayStart();
+ foreach (i, name; s.names)
+ {
+ if (!s.aliases[i])
+ item(name.toString());
+ }
+ arrayEnd();
+ }
+ objectEnd();
+ }
+
+ override void visit(AttribDeclaration d)
+ {
+ Dsymbols* ds = d.include(null);
+ if (ds)
+ {
+ for (size_t i = 0; i < ds.dim; i++)
+ {
+ Dsymbol s = (*ds)[i];
+ s.accept(this);
+ }
+ }
+ }
+
+ override void visit(ConditionalDeclaration d)
+ {
+ if (d.condition.inc != Include.notComputed)
+ {
+ visit(cast(AttribDeclaration)d);
+ return; // Don't visit the if/else bodies again below
+ }
+ Dsymbols* ds = d.decl ? d.decl : d.elsedecl;
+ for (size_t i = 0; i < ds.dim; i++)
+ {
+ Dsymbol s = (*ds)[i];
+ s.accept(this);
+ }
+ }
+
+ override void visit(TypeInfoDeclaration d)
+ {
+ }
+
+ override void visit(PostBlitDeclaration d)
+ {
+ }
+
+ override void visit(Declaration d)
+ {
+ objectStart();
+ //property("unknown", "declaration");
+ jsonProperties(d);
+ objectEnd();
+ }
+
+ override void visit(AggregateDeclaration d)
+ {
+ objectStart();
+ jsonProperties(d);
+ ClassDeclaration cd = d.isClassDeclaration();
+ if (cd)
+ {
+ if (cd.baseClass && cd.baseClass.ident != Id.Object)
+ {
+ property("base", cd.baseClass.toPrettyChars(true).toDString);
+ }
+ if (cd.interfaces.length)
+ {
+ propertyStart("interfaces");
+ arrayStart();
+ foreach (b; cd.interfaces)
+ {
+ item(b.sym.toPrettyChars(true).toDString);
+ }
+ arrayEnd();
+ }
+ }
+ if (d.members)
+ {
+ propertyStart("members");
+ arrayStart();
+ for (size_t i = 0; i < d.members.dim; i++)
+ {
+ Dsymbol s = (*d.members)[i];
+ s.accept(this);
+ }
+ arrayEnd();
+ }
+ objectEnd();
+ }
+
+ override void visit(FuncDeclaration d)
+ {
+ objectStart();
+ jsonProperties(d);
+ TypeFunction tf = cast(TypeFunction)d.type;
+ if (tf && tf.ty == Tfunction)
+ property("parameters", tf.parameterList.parameters);
+ property("endline", "endchar", d.endloc);
+ if (d.foverrides.dim)
+ {
+ propertyStart("overrides");
+ arrayStart();
+ for (size_t i = 0; i < d.foverrides.dim; i++)
+ {
+ FuncDeclaration fd = d.foverrides[i];
+ item(fd.toPrettyChars().toDString);
+ }
+ arrayEnd();
+ }
+ if (d.fdrequire)
+ {
+ propertyStart("in");
+ d.fdrequire.accept(this);
+ }
+ if (d.fdensure)
+ {
+ propertyStart("out");
+ d.fdensure.accept(this);
+ }
+ objectEnd();
+ }
+
+ override void visit(TemplateDeclaration d)
+ {
+ objectStart();
+ // TemplateDeclaration::kind returns the kind of its Aggregate onemember, if it is one
+ property("kind", "template");
+ jsonProperties(d);
+ propertyStart("parameters");
+ arrayStart();
+ for (size_t i = 0; i < d.parameters.dim; i++)
+ {
+ TemplateParameter s = (*d.parameters)[i];
+ objectStart();
+ property("name", s.ident.toString());
+
+ if (auto type = s.isTemplateTypeParameter())
+ {
+ if (s.isTemplateThisParameter())
+ property("kind", "this");
+ else
+ property("kind", "type");
+ property("type", "deco", type.specType);
+ property("default", "defaultDeco", type.defaultType);
+ }
+
+ if (auto value = s.isTemplateValueParameter())
+ {
+ property("kind", "value");
+ property("type", "deco", value.valType);
+ if (value.specValue)
+ property("specValue", value.specValue.toString());
+ if (value.defaultValue)
+ property("defaultValue", value.defaultValue.toString());
+ }
+
+ if (auto _alias = s.isTemplateAliasParameter())
+ {
+ property("kind", "alias");
+ property("type", "deco", _alias.specType);
+ if (_alias.specAlias)
+ property("specAlias", _alias.specAlias.toString());
+ if (_alias.defaultAlias)
+ property("defaultAlias", _alias.defaultAlias.toString());
+ }
+
+ if (auto tuple = s.isTemplateTupleParameter())
+ {
+ property("kind", "tuple");
+ }
+
+ objectEnd();
+ }
+ arrayEnd();
+ Expression expression = d.constraint;
+ if (expression)
+ {
+ property("constraint", expression.toString());
+ }
+ propertyStart("members");
+ arrayStart();
+ for (size_t i = 0; i < d.members.dim; i++)
+ {
+ Dsymbol s = (*d.members)[i];
+ s.accept(this);
+ }
+ arrayEnd();
+ objectEnd();
+ }
+
+ override void visit(EnumDeclaration d)
+ {
+ if (d.isAnonymous())
+ {
+ if (d.members)
+ {
+ for (size_t i = 0; i < d.members.dim; i++)
+ {
+ Dsymbol s = (*d.members)[i];
+ s.accept(this);
+ }
+ }
+ return;
+ }
+ objectStart();
+ jsonProperties(d);
+ property("base", "baseDeco", d.memtype);
+ if (d.members)
+ {
+ propertyStart("members");
+ arrayStart();
+ for (size_t i = 0; i < d.members.dim; i++)
+ {
+ Dsymbol s = (*d.members)[i];
+ s.accept(this);
+ }
+ arrayEnd();
+ }
+ objectEnd();
+ }
+
+ override void visit(EnumMember s)
+ {
+ objectStart();
+ jsonProperties(cast(Dsymbol)s);
+ property("type", "deco", s.origType);
+ objectEnd();
+ }
+
+ override void visit(VarDeclaration d)
+ {
+ if (d.storage_class & STC.local)
+ return;
+ objectStart();
+ jsonProperties(d);
+ if (d._init)
+ property("init", d._init.toString());
+ if (d.isField())
+ property("offset", d.offset);
+ if (d.alignment && d.alignment != STRUCTALIGN_DEFAULT)
+ property("align", d.alignment);
+ objectEnd();
+ }
+
+ override void visit(TemplateMixin d)
+ {
+ objectStart();
+ jsonProperties(d);
+ objectEnd();
+ }
+
+ /**
+ Generate an array of module objects that represent the syntax of each
+ "root module".
+
+ Params:
+ modules = array of the "root modules"
+ */
+ private void generateModules(Modules* modules)
+ {
+ arrayStart();
+ if (modules)
+ {
+ foreach (m; *modules)
+ {
+ if (global.params.verbose)
+ message("json gen %s", m.toChars());
+ m.accept(this);
+ }
+ }
+ arrayEnd();
+ }
+
+ /**
+ Generate the "compilerInfo" object which contains information about the compiler
+ such as the filename, version, supported features, etc.
+ */
+ private void generateCompilerInfo()
+ {
+ import dmd.target : target;
+ objectStart();
+ requiredProperty("vendor", global.vendor);
+ requiredProperty("version", global.versionString());
+ property("__VERSION__", global.versionNumber());
+ requiredProperty("interface", determineCompilerInterface());
+ property("size_t", size_t.sizeof);
+ propertyStart("platforms");
+ arrayStart();
+ if (target.os == Target.OS.Windows)
+ {
+ item("windows");
+ }
+ else
+ {
+ item("posix");
+ if (target.os == Target.OS.linux)
+ item("linux");
+ else if (target.os == Target.OS.OSX)
+ item("osx");
+ else if (target.os == Target.OS.FreeBSD)
+ {
+ item("freebsd");
+ item("bsd");
+ }
+ else if (target.os == Target.OS.OpenBSD)
+ {
+ item("openbsd");
+ item("bsd");
+ }
+ else if (target.os == Target.OS.Solaris)
+ {
+ item("solaris");
+ item("bsd");
+ }
+ }
+ arrayEnd();
+
+ propertyStart("architectures");
+ arrayStart();
+ item(target.architectureName);
+ arrayEnd();
+
+ propertyStart("predefinedVersions");
+ arrayStart();
+ if (global.versionids)
+ {
+ foreach (const versionid; *global.versionids)
+ {
+ item(versionid.toString());
+ }
+ }
+ arrayEnd();
+
+ propertyStart("supportedFeatures");
+ {
+ objectStart();
+ scope(exit) objectEnd();
+ propertyBool("includeImports", true);
+ }
+ objectEnd();
+ }
+
+ /**
+ Generate the "buildInfo" object which contains information specific to the
+ current build such as CWD, importPaths, configFile, etc.
+ */
+ private void generateBuildInfo()
+ {
+ objectStart();
+ requiredProperty("cwd", getcwd(null, 0).toDString);
+ requiredProperty("argv0", global.params.argv0);
+ requiredProperty("config", global.inifilename);
+ requiredProperty("libName", global.params.libname);
+
+ propertyStart("importPaths");
+ arrayStart();
+ if (global.params.imppath)
+ {
+ foreach (importPath; *global.params.imppath)
+ {
+ item(importPath.toDString);
+ }
+ }
+ arrayEnd();
+
+ propertyStart("objectFiles");
+ arrayStart();
+ foreach (objfile; global.params.objfiles)
+ {
+ item(objfile.toDString);
+ }
+ arrayEnd();
+
+ propertyStart("libraryFiles");
+ arrayStart();
+ foreach (lib; global.params.libfiles)
+ {
+ item(lib.toDString);
+ }
+ arrayEnd();
+
+ propertyStart("ddocFiles");
+ arrayStart();
+ foreach (ddocFile; global.params.ddocfiles)
+ {
+ item(ddocFile.toDString);
+ }
+ arrayEnd();
+
+ requiredProperty("mapFile", global.params.mapfile);
+ requiredProperty("resourceFile", global.params.resfile);
+ requiredProperty("defFile", global.params.deffile);
+
+ objectEnd();
+ }
+
+ /**
+ Generate the "semantics" object which contains a 'modules' field representing
+ semantic information about all the modules used in the compilation such as
+ module name, isRoot, contentImportedFiles, etc.
+ */
+ private void generateSemantics()
+ {
+ objectStart();
+ propertyStart("modules");
+ arrayStart();
+ foreach (m; Module.amodules)
+ {
+ objectStart();
+ requiredProperty("name", m.md ? m.md.toString() : null);
+ requiredProperty("file", m.srcfile.toString());
+ propertyBool("isRoot", m.isRoot());
+ if(m.contentImportedFiles.dim > 0)
+ {
+ propertyStart("contentImports");
+ arrayStart();
+ foreach (file; m.contentImportedFiles)
+ {
+ item(file.toDString);
+ }
+ arrayEnd();
+ }
+ objectEnd();
+ }
+ arrayEnd();
+ objectEnd();
+ }
+}
+
+extern (C++) void json_generate(OutBuffer* buf, Modules* modules)
+{
+ scope ToJsonVisitor json = new ToJsonVisitor(buf);
+ // write trailing newline
+ scope(exit) buf.writeByte('\n');
+
+ if (global.params.jsonFieldFlags == 0)
+ {
+ // Generate the original format, which is just an array
+ // of modules representing their syntax.
+ json.generateModules(modules);
+ json.removeComma();
+ }
+ else
+ {
+ // Generate the new format which is an object where each
+ // output option is its own field.
+
+ json.objectStart();
+ if (global.params.jsonFieldFlags & JsonFieldFlags.compilerInfo)
+ {
+ json.propertyStart("compilerInfo");
+ json.generateCompilerInfo();
+ }
+ if (global.params.jsonFieldFlags & JsonFieldFlags.buildInfo)
+ {
+ json.propertyStart("buildInfo");
+ json.generateBuildInfo();
+ }
+ if (global.params.jsonFieldFlags & JsonFieldFlags.modules)
+ {
+ json.propertyStart("modules");
+ json.generateModules(modules);
+ }
+ if (global.params.jsonFieldFlags & JsonFieldFlags.semantics)
+ {
+ json.propertyStart("semantics");
+ json.generateSemantics();
+ }
+ json.objectEnd();
+ }
+}
+
+/**
+A string listing the name of each JSON field. Useful for errors messages.
+*/
+enum jsonFieldNames = () {
+ string s;
+ string prefix = "";
+ foreach (idx, enumName; __traits(allMembers, JsonFieldFlags))
+ {
+ static if (idx > 0)
+ {
+ s ~= prefix ~ "`" ~ enumName ~ "`";
+ prefix = ", ";
+ }
+ }
+ return s;
+}();
+
+/**
+Parse the given `fieldName` and return its corresponding JsonFieldFlags value.
+
+Params:
+ fieldName = the field name to parse
+
+Returns: JsonFieldFlags.none on error, otherwise the JsonFieldFlags value
+ corresponding to the given fieldName.
+*/
+extern (C++) JsonFieldFlags tryParseJsonField(const(char)* fieldName)
+{
+ auto fieldNameString = fieldName.toDString();
+ foreach (idx, enumName; __traits(allMembers, JsonFieldFlags))
+ {
+ static if (idx > 0)
+ {
+ if (fieldNameString == enumName)
+ return __traits(getMember, JsonFieldFlags, enumName);
+ }
+ }
+ return JsonFieldFlags.none;
+}
+
+/**
+Determines and returns the compiler interface which is one of `dmd`, `ldc`,
+`gdc` or `sdc`. Returns `null` if no interface can be determined.
+*/
+private extern(D) string determineCompilerInterface()
+{
+ if (global.vendor == "Digital Mars D")
+ return "dmd";
+ if (global.vendor == "LDC")
+ return "ldc";
+ if (global.vendor == "GNU D")
+ return "gdc";
+ if (global.vendor == "SDC")
+ return "sdc";
+ return null;
+}
diff --git a/gcc/d/dmd/json.h b/gcc/d/dmd/json.h
index d680001..1311fb3 100644
--- a/gcc/d/dmd/json.h
+++ b/gcc/d/dmd/json.h
@@ -11,7 +11,9 @@
#pragma once
#include "arraytypes.h"
+#include "globals.h"
struct OutBuffer;
void json_generate(OutBuffer *, Modules *);
+JsonFieldFlags tryParseJsonField(const char *fieldName);
diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d
new file mode 100644
index 0000000..d29bdc1
--- /dev/null
+++ b/gcc/d/dmd/lambdacomp.d
@@ -0,0 +1,495 @@
+/**
+ * Implements the serialization of a lambda function.
+ *
+ * The serializationis computed by visiting the abstract syntax subtree of the given lambda function.
+ * The serialization is a string which contains the type of the parameters and the string
+ * represantation of the lambda expression.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lamdbacomp.d, _lambdacomp.d)
+ * Documentation: https://dlang.org/phobos/dmd_lambdacomp.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/lambdacomp.d
+ */
+
+module dmd.lambdacomp;
+
+import core.stdc.stdio;
+import core.stdc.string;
+
+import dmd.astenums;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dsymbol;
+import dmd.dtemplate;
+import dmd.expression;
+import dmd.func;
+import dmd.dmangle;
+import dmd.mtype;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+import dmd.root.stringtable;
+import dmd.dscope;
+import dmd.statement;
+import dmd.tokens;
+import dmd.visitor;
+
+enum LOG = false;
+
+/**
+ * The type of the visited expression.
+ */
+private enum ExpType
+{
+ None,
+ EnumDecl,
+ Arg
+}
+
+/**
+ * Compares 2 lambda functions described by their serialization.
+ *
+ * Params:
+ * l1 = first lambda to be compared
+ * l2 = second lambda to be compared
+ * sc = the scope where the lambdas are compared
+ *
+ * Returns:
+ * `true` if the 2 lambda functions are equal, `false` otherwise
+ */
+bool isSameFuncLiteral(FuncLiteralDeclaration l1, FuncLiteralDeclaration l2, Scope* sc)
+{
+ bool result;
+ if (auto ser1 = getSerialization(l1, sc))
+ {
+ //printf("l1 serialization: %.*s\n", cast(int)ser1.length, &ser1[0]);
+ if (auto ser2 = getSerialization(l2, sc))
+ {
+ //printf("l2 serialization: %.*s\n", cast(int)ser2.length, &ser2[0]);
+ if (ser1 == ser2)
+ result = true;
+ mem.xfree(cast(void*)ser2.ptr);
+ }
+ mem.xfree(cast(void*)ser1.ptr);
+ }
+ return result;
+}
+
+/**
+ * Computes the string representation of a
+ * lambda function described by the subtree starting from a
+ * $(REF dmd, func, FuncLiteralDeclaration).
+ *
+ * Limitations: only IntegerExps, Enums and function
+ * arguments are supported in the lambda function body. The
+ * arguments may be of any type (basic types, user defined types),
+ * except template instantiations. If a function call, a local
+ * variable or a template instance is encountered, the
+ * serialization is dropped and the function is considered
+ * uncomparable.
+ *
+ * Params:
+ * fld = the starting AST node for the lambda function
+ * sc = the scope in which the lambda function is located
+ *
+ * Returns:
+ * The serialization of `fld` allocated with mem.
+ */
+private string getSerialization(FuncLiteralDeclaration fld, Scope* sc)
+{
+ scope serVisitor = new SerializeVisitor(fld.parent._scope);
+ fld.accept(serVisitor);
+ const len = serVisitor.buf.length;
+ if (len == 0)
+ return null;
+
+ return cast(string)serVisitor.buf.extractSlice();
+}
+
+private extern (C++) class SerializeVisitor : SemanticTimeTransitiveVisitor
+{
+private:
+ StringTable!(const(char)[]) arg_hash;
+ Scope* sc;
+ ExpType et;
+ Dsymbol d;
+
+public:
+ OutBuffer buf;
+ alias visit = SemanticTimeTransitiveVisitor.visit;
+
+ this(Scope* sc)
+ {
+ this.sc = sc;
+ }
+
+ /**
+ * Entrypoint of the SerializeVisitor.
+ *
+ * Params:
+ * fld = the lambda function for which the serialization is computed
+ */
+ override void visit(FuncLiteralDeclaration fld)
+ {
+ assert(fld.type.ty != Terror);
+ static if (LOG)
+ printf("FuncLiteralDeclaration: %s\n", fld.toChars());
+
+ TypeFunction tf = cast(TypeFunction) fld.type;
+ const dim = cast(uint) tf.parameterList.length;
+ // Start the serialization by printing the number of
+ // arguments the lambda has.
+ buf.printf("%d:", dim);
+
+ arg_hash._init(dim + 1);
+ // For each argument
+ foreach (i, fparam; tf.parameterList)
+ {
+ if (fparam.ident !is null)
+ {
+ // the variable name is introduced into a hashtable
+ // where the key is the user defined name and the
+ // value is the cannonically name (arg0, arg1 ...)
+ auto key = fparam.ident.toString();
+ OutBuffer value;
+ value.writestring("arg");
+ value.print(i);
+ arg_hash.insert(key, value.extractSlice());
+ // and the type of the variable is serialized.
+ fparam.accept(this);
+ }
+ }
+
+ // Now the function body can be serialized.
+ ReturnStatement rs = fld.fbody.endsWithReturnStatement();
+ if (rs && rs.exp)
+ {
+ rs.exp.accept(this);
+ }
+ else
+ {
+ buf.setsize(0);
+ }
+ }
+
+ override void visit(DotIdExp exp)
+ {
+ static if (LOG)
+ printf("DotIdExp: %s\n", exp.toChars());
+ if (buf.length == 0)
+ return;
+
+ // First we need to see what kind of expression e1 is.
+ // It might an enum member (enum.value) or the field of
+ // an argument (argX.value) if the argument is an aggregate
+ // type. This is reported through the et variable.
+ exp.e1.accept(this);
+ if (buf.length == 0)
+ return;
+
+ if (et == ExpType.EnumDecl)
+ {
+ Dsymbol s = d.search(exp.loc, exp.ident);
+ if (s)
+ {
+ if (auto em = s.isEnumMember())
+ {
+ em.value.accept(this);
+ }
+ et = ExpType.None;
+ d = null;
+ }
+ }
+
+ else if (et == ExpType.Arg)
+ {
+ buf.setsize(buf.length -1);
+ buf.writeByte('.');
+ buf.writestring(exp.ident.toString());
+ buf.writeByte('_');
+ }
+ }
+
+ bool checkArgument(const(char)* id)
+ {
+ // The identifier may be an argument
+ auto stringtable_value = arg_hash.lookup(id, strlen(id));
+ if (stringtable_value)
+ {
+ // In which case we need to update the serialization accordingly
+ const(char)[] gen_id = stringtable_value.value;
+ buf.write(gen_id);
+ buf.writeByte('_');
+ et = ExpType.Arg;
+ return true;
+ }
+ return false;
+ }
+
+ override void visit(IdentifierExp exp)
+ {
+ static if (LOG)
+ printf("IdentifierExp: %s\n", exp.toChars());
+
+ if (buf.length == 0)
+ return;
+
+ auto id = exp.ident.toChars();
+
+ // If it's not an argument
+ if (!checkArgument(id))
+ {
+ // we must check what the identifier expression is.
+ Dsymbol scopesym;
+ Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
+ if (s)
+ {
+ auto v = s.isVarDeclaration();
+ // If it's a VarDeclaration, it must be a manifest constant
+ if (v && (v.storage_class & STC.manifest))
+ {
+ v.getConstInitializer.accept(this);
+ }
+ else if (auto em = s.isEnumDeclaration())
+ {
+ d = em;
+ et = ExpType.EnumDecl;
+ }
+ else if (auto fd = s.isFuncDeclaration())
+ {
+ writeMangledName(fd);
+ }
+ // For anything else, the function is deemed uncomparable
+ else
+ {
+ buf.setsize(0);
+ }
+ }
+ // If it's an unknown symbol, consider the function incomparable
+ else
+ {
+ buf.setsize(0);
+ }
+ }
+ }
+
+ override void visit(DotVarExp exp)
+ {
+ static if (LOG)
+ printf("DotVarExp: %s, var: %s, e1: %s\n", exp.toChars(),
+ exp.var.toChars(), exp.e1.toChars());
+
+ exp.e1.accept(this);
+ if (buf.length == 0)
+ return;
+
+ buf.setsize(buf.length -1);
+ buf.writeByte('.');
+ buf.writestring(exp.var.toChars());
+ buf.writeByte('_');
+ }
+
+ override void visit(VarExp exp)
+ {
+ static if (LOG)
+ printf("VarExp: %s, var: %s\n", exp.toChars(), exp.var.toChars());
+
+ if (buf.length == 0)
+ return;
+
+ auto id = exp.var.ident.toChars();
+ if (!checkArgument(id))
+ {
+ buf.setsize(0);
+ }
+ }
+
+ // serialize function calls
+ override void visit(CallExp exp)
+ {
+ static if (LOG)
+ printf("CallExp: %s\n", exp.toChars());
+
+ if (buf.length == 0)
+ return;
+
+ if (!exp.f)
+ {
+ exp.e1.accept(this);
+ }
+ else
+ {
+ writeMangledName(exp.f);
+ }
+
+ buf.writeByte('(');
+ foreach (arg; *(exp.arguments))
+ {
+ arg.accept(this);
+ }
+ buf.writeByte(')');
+ }
+
+ override void visit(UnaExp exp)
+ {
+ if (buf.length == 0)
+ return;
+
+ buf.writeByte('(');
+ buf.writestring(Token.toString(exp.op));
+ exp.e1.accept(this);
+ if (buf.length != 0)
+ buf.writestring(")_");
+ }
+
+ override void visit(IntegerExp exp)
+ {
+ if (buf.length == 0)
+ return;
+
+ buf.print(exp.toInteger());
+ buf.writeByte('_');
+ }
+
+ override void visit(RealExp exp)
+ {
+ if (buf.length == 0)
+ return;
+
+ buf.writestring(exp.toChars());
+ buf.writeByte('_');
+ }
+
+ override void visit(BinExp exp)
+ {
+ static if (LOG)
+ printf("BinExp: %s\n", exp.toChars());
+
+ if (buf.length == 0)
+ return;
+
+ buf.writeByte('(');
+ buf.writestring(Token.toChars(exp.op));
+
+ exp.e1.accept(this);
+ if (buf.length == 0)
+ return;
+
+ exp.e2.accept(this);
+ if (buf.length == 0)
+ return;
+
+ buf.writeByte(')');
+ }
+
+ override void visit(TypeBasic t)
+ {
+ buf.writestring(t.dstring);
+ buf.writeByte('_');
+ }
+
+ void writeMangledName(Dsymbol s)
+ {
+ if (s)
+ {
+ OutBuffer mangledName;
+ mangleToBuffer(s, &mangledName);
+ buf.writestring(mangledName[]);
+ buf.writeByte('_');
+ }
+ else
+ buf.setsize(0);
+ }
+
+ private bool checkTemplateInstance(T)(T t)
+ if (is(T == TypeStruct) || is(T == TypeClass))
+ {
+ if (t.sym.parent && t.sym.parent.isTemplateInstance())
+ {
+ buf.setsize(0);
+ return true;
+ }
+ return false;
+ }
+
+ override void visit(TypeStruct t)
+ {
+ static if (LOG)
+ printf("TypeStruct: %s\n", t.toChars);
+
+ if (!checkTemplateInstance!TypeStruct(t))
+ writeMangledName(t.sym);
+ }
+
+ override void visit(TypeClass t)
+ {
+ static if (LOG)
+ printf("TypeClass: %s\n", t.toChars());
+
+ if (!checkTemplateInstance!TypeClass(t))
+ writeMangledName(t.sym);
+ }
+
+ override void visit(Parameter p)
+ {
+ if (p.type.ty == Tident
+ && (cast(TypeIdentifier)p.type).ident.toString().length > 3
+ && strncmp((cast(TypeIdentifier)p.type).ident.toChars(), "__T", 3) == 0)
+ {
+ buf.writestring("none_");
+ }
+ else
+ visitType(p.type);
+ }
+
+ override void visit(StructLiteralExp e) {
+ static if (LOG)
+ printf("StructLiteralExp: %s\n", e.toChars);
+
+ auto ty = cast(TypeStruct)e.stype;
+ if (ty)
+ {
+ writeMangledName(ty.sym);
+ auto dim = e.elements.dim;
+ foreach (i; 0..dim)
+ {
+ auto elem = (*e.elements)[i];
+ if (elem)
+ elem.accept(this);
+ else
+ buf.writestring("null_");
+ }
+ }
+ else
+ buf.setsize(0);
+ }
+
+ override void visit(ArrayLiteralExp) { buf.setsize(0); }
+ override void visit(AssocArrayLiteralExp) { buf.setsize(0); }
+ override void visit(MixinExp) { buf.setsize(0); }
+ override void visit(ComplexExp) { buf.setsize(0); }
+ override void visit(DeclarationExp) { buf.setsize(0); }
+ override void visit(DefaultInitExp) { buf.setsize(0); }
+ override void visit(DsymbolExp) { buf.setsize(0); }
+ override void visit(ErrorExp) { buf.setsize(0); }
+ override void visit(FuncExp) { buf.setsize(0); }
+ override void visit(HaltExp) { buf.setsize(0); }
+ override void visit(IntervalExp) { buf.setsize(0); }
+ override void visit(IsExp) { buf.setsize(0); }
+ override void visit(NewAnonClassExp) { buf.setsize(0); }
+ override void visit(NewExp) { buf.setsize(0); }
+ override void visit(NullExp) { buf.setsize(0); }
+ override void visit(ObjcClassReferenceExp) { buf.setsize(0); }
+ override void visit(OverExp) { buf.setsize(0); }
+ override void visit(ScopeExp) { buf.setsize(0); }
+ override void visit(StringExp) { buf.setsize(0); }
+ override void visit(SymbolExp) { buf.setsize(0); }
+ override void visit(TemplateExp) { buf.setsize(0); }
+ override void visit(ThisExp) { buf.setsize(0); }
+ override void visit(TraitsExp) { buf.setsize(0); }
+ override void visit(TupleExp) { buf.setsize(0); }
+ override void visit(TypeExp) { buf.setsize(0); }
+ override void visit(TypeidExp) { buf.setsize(0); }
+ override void visit(VoidInitExp) { buf.setsize(0); }
+}
diff --git a/gcc/d/dmd/lexer.c b/gcc/d/dmd/lexer.c
deleted file mode 100644
index 3ea932c..0000000
--- a/gcc/d/dmd/lexer.c
+++ /dev/null
@@ -1,2405 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/lexer.c
- */
-
-/* Lexical Analyzer */
-
-#include "root/dsystem.h" // for time() and ctime()
-#include "root/rmem.h"
-
-#include "mars.h"
-#include "lexer.h"
-#include "utf.h"
-#include "identifier.h"
-#include "id.h"
-
-extern int HtmlNamedEntity(const utf8_t *p, size_t length);
-
-#define LS 0x2028 // UTF line separator
-#define PS 0x2029 // UTF paragraph separator
-
-/********************************************
- * Do our own char maps
- */
-
-static unsigned char cmtable[256];
-
-const int CMoctal = 0x1;
-const int CMhex = 0x2;
-const int CMidchar = 0x4;
-
-inline bool isoctal (utf8_t c) { return (cmtable[c] & CMoctal) != 0; }
-inline bool ishex (utf8_t c) { return (cmtable[c] & CMhex) != 0; }
-inline bool isidchar(utf8_t c) { return (cmtable[c] & CMidchar) != 0; }
-
-struct CMTableInitializer
-{
- CMTableInitializer();
-};
-
-static CMTableInitializer cmtableinitializer;
-
-CMTableInitializer::CMTableInitializer()
-{
- for (unsigned c = 0; c < 256; c++)
- {
- if ('0' <= c && c <= '7')
- cmtable[c] |= CMoctal;
- if (isxdigit(c))
- cmtable[c] |= CMhex;
- if (isalnum(c) || c == '_')
- cmtable[c] |= CMidchar;
- }
-}
-
-/*************************** Lexer ********************************************/
-
-OutBuffer Lexer::stringbuffer;
-
-Lexer::Lexer(const char *filename,
- const utf8_t *base, size_t begoffset, size_t endoffset,
- bool doDocComment, bool commentToken)
-{
- scanloc = Loc(filename, 1, 1);
- //printf("Lexer::Lexer(%p,%d)\n",base,length);
- //printf("lexer.filename = %s\n", filename);
- this->token = Token();
- this->token.ptr = NULL;
- this->token.value = TOKreserved;
- this->token.blockComment = NULL;
- this->token.lineComment = NULL;
- this->base = base;
- this->end = base + endoffset;
- p = base + begoffset;
- line = p;
- this->doDocComment = doDocComment;
- this->anyToken = 0;
- this->commentToken = commentToken;
- this->errors = false;
- //initKeywords();
-
- /* If first line starts with '#!', ignore the line
- */
-
- if (p[0] == '#' && p[1] =='!')
- {
- p += 2;
- while (1)
- {
- utf8_t c = *p++;
- switch (c)
- {
- case 0:
- case 0x1A:
- p--;
- /* fall through */
-
- case '\n':
- break;
-
- default:
- continue;
- }
- break;
- }
- endOfLine();
- }
-}
-
-
-void Lexer::endOfLine()
-{
- scanloc.linnum++;
- line = p;
-}
-
-
-void Lexer::error(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- ::verror(token.loc, format, ap);
- va_end(ap);
- errors = true;
-}
-
-void Lexer::error(Loc loc, const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- ::verror(loc, format, ap);
- va_end(ap);
- errors = true;
-}
-
-void Lexer::deprecation(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- ::vdeprecation(token.loc, format, ap);
- va_end(ap);
- if (global.params.useDeprecated == DIAGNOSTICerror)
- errors = true;
-}
-
-TOK Lexer::nextToken()
-{
- if (token.next)
- {
- Token *t = token.next;
- memcpy(&token,t,sizeof(Token));
- t->free();
- }
- else
- {
- scan(&token);
- }
- //token.print();
- return token.value;
-}
-
-Token *Lexer::peek(Token *ct)
-{
- Token *t;
- if (ct->next)
- t = ct->next;
- else
- {
- t = Token::alloc();
- scan(t);
- ct->next = t;
- }
- return t;
-}
-
-/***********************
- * Look ahead at next token's value.
- */
-
-TOK Lexer::peekNext()
-{
- return peek(&token)->value;
-}
-
-/***********************
- * Look 2 tokens ahead at value.
- */
-
-TOK Lexer::peekNext2()
-{
- Token *t = peek(&token);
- return peek(t)->value;
-}
-
-/*********************************
- * tk is on the opening (.
- * Look ahead and return token that is past the closing ).
- */
-
-Token *Lexer::peekPastParen(Token *tk)
-{
- //printf("peekPastParen()\n");
- int parens = 1;
- int curlynest = 0;
- while (1)
- {
- tk = peek(tk);
- //tk->print();
- switch (tk->value)
- {
- case TOKlparen:
- parens++;
- continue;
-
- case TOKrparen:
- --parens;
- if (parens)
- continue;
- tk = peek(tk);
- break;
-
- case TOKlcurly:
- curlynest++;
- continue;
-
- case TOKrcurly:
- if (--curlynest >= 0)
- continue;
- break;
-
- case TOKsemicolon:
- if (curlynest)
- continue;
- break;
-
- case TOKeof:
- break;
-
- default:
- continue;
- }
- return tk;
- }
-}
-
-/****************************
- * Turn next token in buffer into a token.
- */
-
-void Lexer::scan(Token *t)
-{
- unsigned lastLine = scanloc.linnum;
- Loc startLoc;
-
- t->blockComment = NULL;
- t->lineComment = NULL;
- while (1)
- {
- t->ptr = p;
- //printf("p = %p, *p = '%c'\n",p,*p);
- t->loc = loc();
- switch (*p)
- {
- case 0:
- case 0x1A:
- t->value = TOKeof; // end of file
- return;
-
- case ' ':
- case '\t':
- case '\v':
- case '\f':
- p++;
- continue; // skip white space
-
- case '\r':
- p++;
- if (*p != '\n') // if CR stands by itself
- endOfLine();
- continue; // skip white space
-
- case '\n':
- p++;
- endOfLine();
- continue; // skip white space
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- t->value = number(t);
- return;
-
- case '\'':
- t->value = charConstant(t);
- return;
-
- case 'r':
- if (p[1] != '"')
- goto case_ident;
- p++;
- /* fall through */
- case '`':
- t->value = wysiwygStringConstant(t, *p);
- return;
-
- case 'x':
- if (p[1] != '"')
- goto case_ident;
- p++;
- t->value = hexStringConstant(t);
- return;
-
- case 'q':
- if (p[1] == '"')
- {
- p++;
- t->value = delimitedStringConstant(t);
- return;
- }
- else if (p[1] == '{')
- {
- p++;
- t->value = tokenStringConstant(t);
- return;
- }
- else
- goto case_ident;
-
- case '"':
- t->value = escapeStringConstant(t);
- return;
-
- case 'a': case 'b': case 'c': case 'd': case 'e':
- case 'f': case 'g': case 'h': case 'i': case 'j':
- case 'k': case 'l': case 'm': case 'n': case 'o':
- case 'p': /*case 'q': case 'r':*/ case 's': case 't':
- case 'u': case 'v': case 'w': /*case 'x':*/ case 'y':
- case 'z':
- case 'A': case 'B': case 'C': case 'D': case 'E':
- case 'F': case 'G': case 'H': case 'I': case 'J':
- case 'K': case 'L': case 'M': case 'N': case 'O':
- case 'P': case 'Q': case 'R': case 'S': case 'T':
- case 'U': case 'V': case 'W': case 'X': case 'Y':
- case 'Z':
- case '_':
- case_ident:
- { utf8_t c;
-
- while (1)
- {
- c = *++p;
- if (isidchar(c))
- continue;
- else if (c & 0x80)
- { const utf8_t *s = p;
- unsigned u = decodeUTF();
- if (isUniAlpha(u))
- continue;
- error("char 0x%04x not allowed in identifier", u);
- p = s;
- }
- break;
- }
-
- Identifier *id = Identifier::idPool((const char *)t->ptr, p - t->ptr);
- t->ident = id;
- t->value = (TOK) id->getValue();
- anyToken = 1;
- if (*t->ptr == '_') // if special identifier token
- {
- static bool initdone = false;
- static char date[11+1];
- static char time[8+1];
- static char timestamp[24+1];
-
- if (!initdone) // lazy evaluation
- {
- initdone = true;
- time_t ct;
- ::time(&ct);
- char *p = ctime(&ct);
- assert(p);
- sprintf(&date[0], "%.6s %.4s", p + 4, p + 20);
- sprintf(&time[0], "%.8s", p + 11);
- sprintf(&timestamp[0], "%.24s", p);
- }
-
- if (id == Id::DATE)
- {
- t->ustring = (utf8_t *)date;
- goto Lstr;
- }
- else if (id == Id::TIME)
- {
- t->ustring = (utf8_t *)time;
- goto Lstr;
- }
- else if (id == Id::VENDOR)
- {
- t->ustring = (utf8_t *)const_cast<char *>(global.vendor.ptr);
- goto Lstr;
- }
- else if (id == Id::TIMESTAMP)
- {
- t->ustring = (utf8_t *)timestamp;
- Lstr:
- t->value = TOKstring;
- t->postfix = 0;
- t->len = (unsigned)strlen((char *)t->ustring);
- }
- else if (id == Id::VERSIONX)
- { unsigned major = 0;
- unsigned minor = 0;
- bool point = false;
-
- for (const char *p = global.version.ptr + 1; 1; p++)
- {
- c = *p;
- if (isdigit((utf8_t)c))
- minor = minor * 10 + c - '0';
- else if (c == '.')
- {
- if (point)
- break; // ignore everything after second '.'
- point = true;
- major = minor;
- minor = 0;
- }
- else
- break;
- }
- t->value = TOKint64v;
- t->uns64value = major * 1000 + minor;
- }
- else if (id == Id::EOFX)
- {
- t->value = TOKeof;
- // Advance scanner to end of file
- while (!(*p == 0 || *p == 0x1A))
- p++;
- }
- }
- //printf("t->value = %d\n",t->value);
- return;
- }
-
- case '/':
- p++;
- switch (*p)
- {
- case '=':
- p++;
- t->value = TOKdivass;
- return;
-
- case '*':
- p++;
- startLoc = loc();
- while (1)
- {
- while (1)
- { utf8_t c = *p;
- switch (c)
- {
- case '/':
- break;
-
- case '\n':
- endOfLine();
- p++;
- continue;
-
- case '\r':
- p++;
- if (*p != '\n')
- endOfLine();
- continue;
-
- case 0:
- case 0x1A:
- error("unterminated /* */ comment");
- p = end;
- t->loc = loc();
- t->value = TOKeof;
- return;
-
- default:
- if (c & 0x80)
- { unsigned u = decodeUTF();
- if (u == PS || u == LS)
- endOfLine();
- }
- p++;
- continue;
- }
- break;
- }
- p++;
- if (p[-2] == '*' && p - 3 != t->ptr)
- break;
- }
- if (commentToken)
- {
- t->loc = startLoc;
- t->value = TOKcomment;
- return;
- }
- else if (doDocComment && t->ptr[2] == '*' && p - 4 != t->ptr)
- { // if /** but not /**/
- getDocComment(t, lastLine == startLoc.linnum);
- }
- continue;
-
- case '/': // do // style comments
- startLoc = loc();
- while (1)
- { utf8_t c = *++p;
- switch (c)
- {
- case '\n':
- break;
-
- case '\r':
- if (p[1] == '\n')
- p++;
- break;
-
- case 0:
- case 0x1A:
- if (commentToken)
- {
- p = end;
- t->loc = startLoc;
- t->value = TOKcomment;
- return;
- }
- if (doDocComment && t->ptr[2] == '/')
- getDocComment(t, lastLine == startLoc.linnum);
- p = end;
- t->loc = loc();
- t->value = TOKeof;
- return;
-
- default:
- if (c & 0x80)
- { unsigned u = decodeUTF();
- if (u == PS || u == LS)
- break;
- }
- continue;
- }
- break;
- }
-
- if (commentToken)
- {
- p++;
- endOfLine();
- t->loc = startLoc;
- t->value = TOKcomment;
- return;
- }
- if (doDocComment && t->ptr[2] == '/')
- getDocComment(t, lastLine == startLoc.linnum);
-
- p++;
- endOfLine();
- continue;
-
- case '+':
- { int nest;
-
- startLoc = loc();
- p++;
- nest = 1;
- while (1)
- { utf8_t c = *p;
- switch (c)
- {
- case '/':
- p++;
- if (*p == '+')
- {
- p++;
- nest++;
- }
- continue;
-
- case '+':
- p++;
- if (*p == '/')
- {
- p++;
- if (--nest == 0)
- break;
- }
- continue;
-
- case '\r':
- p++;
- if (*p != '\n')
- endOfLine();
- continue;
-
- case '\n':
- endOfLine();
- p++;
- continue;
-
- case 0:
- case 0x1A:
- error("unterminated /+ +/ comment");
- p = end;
- t->loc = loc();
- t->value = TOKeof;
- return;
-
- default:
- if (c & 0x80)
- { unsigned u = decodeUTF();
- if (u == PS || u == LS)
- endOfLine();
- }
- p++;
- continue;
- }
- break;
- }
- if (commentToken)
- {
- t->loc = startLoc;
- t->value = TOKcomment;
- return;
- }
- if (doDocComment && t->ptr[2] == '+' && p - 4 != t->ptr)
- { // if /++ but not /++/
- getDocComment(t, lastLine == startLoc.linnum);
- }
- continue;
- }
- default:
- break;
- }
- t->value = TOKdiv;
- return;
-
- case '.':
- p++;
- if (isdigit(*p))
- { /* Note that we don't allow ._1 and ._ as being
- * valid floating point numbers.
- */
- p--;
- t->value = inreal(t);
- }
- else if (p[0] == '.')
- {
- if (p[1] == '.')
- { p += 2;
- t->value = TOKdotdotdot;
- }
- else
- { p++;
- t->value = TOKslice;
- }
- }
- else
- t->value = TOKdot;
- return;
-
- case '&':
- p++;
- if (*p == '=')
- { p++;
- t->value = TOKandass;
- }
- else if (*p == '&')
- { p++;
- t->value = TOKandand;
- }
- else
- t->value = TOKand;
- return;
-
- case '|':
- p++;
- if (*p == '=')
- { p++;
- t->value = TOKorass;
- }
- else if (*p == '|')
- { p++;
- t->value = TOKoror;
- }
- else
- t->value = TOKor;
- return;
-
- case '-':
- p++;
- if (*p == '=')
- { p++;
- t->value = TOKminass;
- }
- else if (*p == '-')
- { p++;
- t->value = TOKminusminus;
- }
- else
- t->value = TOKmin;
- return;
-
- case '+':
- p++;
- if (*p == '=')
- { p++;
- t->value = TOKaddass;
- }
- else if (*p == '+')
- { p++;
- t->value = TOKplusplus;
- }
- else
- t->value = TOKadd;
- return;
-
- case '<':
- p++;
- if (*p == '=')
- { p++;
- t->value = TOKle; // <=
- }
- else if (*p == '<')
- { p++;
- if (*p == '=')
- { p++;
- t->value = TOKshlass; // <<=
- }
- else
- t->value = TOKshl; // <<
- }
- else if (*p == '>')
- { p++;
- if (*p == '=')
- { p++;
- t->value = TOKleg; // <>=
- }
- else
- t->value = TOKlg; // <>
- }
- else
- t->value = TOKlt; // <
- return;
-
- case '>':
- p++;
- if (*p == '=')
- { p++;
- t->value = TOKge; // >=
- }
- else if (*p == '>')
- { p++;
- if (*p == '=')
- { p++;
- t->value = TOKshrass; // >>=
- }
- else if (*p == '>')
- { p++;
- if (*p == '=')
- { p++;
- t->value = TOKushrass; // >>>=
- }
- else
- t->value = TOKushr; // >>>
- }
- else
- t->value = TOKshr; // >>
- }
- else
- t->value = TOKgt; // >
- return;
-
- case '!':
- p++;
- if (*p == '=')
- { p++;
- t->value = TOKnotequal; // !=
- }
- else if (*p == '<')
- { p++;
- if (*p == '>')
- { p++;
- if (*p == '=')
- { p++;
- t->value = TOKunord; // !<>=
- }
- else
- t->value = TOKue; // !<>
- }
- else if (*p == '=')
- { p++;
- t->value = TOKug; // !<=
- }
- else
- t->value = TOKuge; // !<
- }
- else if (*p == '>')
- { p++;
- if (*p == '=')
- { p++;
- t->value = TOKul; // !>=
- }
- else
- t->value = TOKule; // !>
- }
- else
- t->value = TOKnot; // !
- return;
-
- case '=':
- p++;
- if (*p == '=')
- { p++;
- t->value = TOKequal; // ==
- }
- else if (*p == '>')
- { p++;
- t->value = TOKgoesto; // =>
- }
- else
- t->value = TOKassign; // =
- return;
-
- case '~':
- p++;
- if (*p == '=')
- { p++;
- t->value = TOKcatass; // ~=
- }
- else
- t->value = TOKtilde; // ~
- return;
-
- case '^':
- p++;
- if (*p == '^')
- { p++;
- if (*p == '=')
- { p++;
- t->value = TOKpowass; // ^^=
- }
- else
- t->value = TOKpow; // ^^
- }
- else if (*p == '=')
- { p++;
- t->value = TOKxorass; // ^=
- }
- else
- t->value = TOKxor; // ^
- return;
-
- case '(': p++; t->value = TOKlparen; return;
- case ')': p++; t->value = TOKrparen; return;
- case '[': p++; t->value = TOKlbracket; return;
- case ']': p++; t->value = TOKrbracket; return;
- case '{': p++; t->value = TOKlcurly; return;
- case '}': p++; t->value = TOKrcurly; return;
- case '?': p++; t->value = TOKquestion; return;
- case ',': p++; t->value = TOKcomma; return;
- case ';': p++; t->value = TOKsemicolon; return;
- case ':': p++; t->value = TOKcolon; return;
- case '$': p++; t->value = TOKdollar; return;
- case '@': p++; t->value = TOKat; return;
-
- case '*':
- p++;
- if (*p == '=')
- { p++;
- t->value = TOKmulass;
- }
- else
- t->value = TOKmul;
- return;
- case '%':
- p++;
- if (*p == '=')
- { p++;
- t->value = TOKmodass;
- }
- else
- t->value = TOKmod;
- return;
-
- case '#':
- {
- p++;
- Token n;
- scan(&n);
- if (n.value == TOKidentifier)
- {
- if (n.ident == Id::line)
- {
- poundLine();
- continue;
- }
- else
- {
- const Loc locx = loc();
- warning(locx, "C preprocessor directive `#%s` is not supported", n.ident->toChars());
- }
- }
- else if (n.value == TOKif)
- {
- error("C preprocessor directive `#if` is not supported, use `version` or `static if`");
- }
- t->value = TOKpound;
- return;
- }
-
- default:
- { unsigned c = *p;
-
- if (c & 0x80)
- { c = decodeUTF();
-
- // Check for start of unicode identifier
- if (isUniAlpha(c))
- goto case_ident;
-
- if (c == PS || c == LS)
- {
- endOfLine();
- p++;
- continue;
- }
- }
- if (c < 0x80 && isprint(c))
- error("character '%c' is not a valid token", c);
- else
- error("character 0x%02x is not a valid token", c);
- p++;
- continue;
- }
- }
- }
-}
-
-/*******************************************
- * Parse escape sequence.
- */
-
-unsigned Lexer::escapeSequence()
-{ unsigned c = *p;
-
- int n;
- int ndigits;
-
- switch (c)
- {
- case '\'':
- case '"':
- case '?':
- case '\\':
- Lconsume:
- p++;
- break;
-
- case 'a': c = 7; goto Lconsume;
- case 'b': c = 8; goto Lconsume;
- case 'f': c = 12; goto Lconsume;
- case 'n': c = 10; goto Lconsume;
- case 'r': c = 13; goto Lconsume;
- case 't': c = 9; goto Lconsume;
- case 'v': c = 11; goto Lconsume;
-
- case 'u':
- ndigits = 4;
- goto Lhex;
- case 'U':
- ndigits = 8;
- goto Lhex;
- case 'x':
- ndigits = 2;
- Lhex:
- p++;
- c = *p;
- if (ishex((utf8_t)c))
- { unsigned v;
-
- n = 0;
- v = 0;
- while (1)
- {
- if (isdigit((utf8_t)c))
- c -= '0';
- else if (islower(c))
- c -= 'a' - 10;
- else
- c -= 'A' - 10;
- v = v * 16 + c;
- c = *++p;
- if (++n == ndigits)
- break;
- if (!ishex((utf8_t)c))
- { error("escape hex sequence has %d hex digits instead of %d", n, ndigits);
- break;
- }
- }
- if (ndigits != 2 && !utf_isValidDchar(v))
- { error("invalid UTF character \\U%08x", v);
- v = '?'; // recover with valid UTF character
- }
- c = v;
- }
- else
- error("undefined escape hex sequence \\%c",c);
- break;
-
- case '&': // named character entity
- for (const utf8_t *idstart = ++p; 1; p++)
- {
- switch (*p)
- {
- case ';':
- c = HtmlNamedEntity(idstart, p - idstart);
- if (c == ~0U)
- { error("unnamed character entity &%.*s;", (int)(p - idstart), idstart);
- c = ' ';
- }
- p++;
- break;
-
- default:
- if (isalpha(*p) ||
- (p != idstart && isdigit(*p)))
- continue;
- error("unterminated named entity &%.*s;", (int)(p - idstart + 1), idstart);
- break;
- }
- break;
- }
- break;
-
- case 0:
- case 0x1A: // end of file
- c = '\\';
- break;
-
- default:
- if (isoctal((utf8_t)c))
- { unsigned v;
-
- n = 0;
- v = 0;
- do
- {
- v = v * 8 + (c - '0');
- c = *++p;
- } while (++n < 3 && isoctal((utf8_t)c));
- c = v;
- if (c > 0xFF)
- error("escape octal sequence \\%03o is larger than \\377", c);
- }
- else
- error("undefined escape sequence \\%c",c);
- break;
- }
- return c;
-}
-
-/**************************************
- */
-
-TOK Lexer::wysiwygStringConstant(Token *t, int tc)
-{
- int c;
- Loc start = loc();
-
- p++;
- stringbuffer.reset();
- while (1)
- {
- c = *p++;
- switch (c)
- {
- case '\n':
- endOfLine();
- break;
-
- case '\r':
- if (*p == '\n')
- continue; // ignore
- c = '\n'; // treat EndOfLine as \n character
- endOfLine();
- break;
-
- case 0:
- case 0x1A:
- error("unterminated string constant starting at %s", start.toChars());
- t->ustring = (utf8_t *)const_cast<char *>("");
- t->len = 0;
- t->postfix = 0;
- return TOKstring;
-
- case '"':
- case '`':
- if (c == tc)
- {
- t->len = (unsigned)stringbuffer.length();
- stringbuffer.writeByte(0);
- t->ustring = (utf8_t *)mem.xmalloc(stringbuffer.length());
- memcpy(t->ustring, stringbuffer.slice().ptr, stringbuffer.length());
- stringPostfix(t);
- return TOKstring;
- }
- break;
-
- default:
- if (c & 0x80)
- { p--;
- unsigned u = decodeUTF();
- p++;
- if (u == PS || u == LS)
- endOfLine();
- stringbuffer.writeUTF8(u);
- continue;
- }
- break;
- }
- stringbuffer.writeByte(c);
- }
-}
-
-/**************************************
- * Lex hex strings:
- * x"0A ae 34FE BD"
- */
-
-TOK Lexer::hexStringConstant(Token *t)
-{
- unsigned c;
- Loc start = loc();
- unsigned n = 0;
- unsigned v = ~0; // dead assignment, needed to suppress warning
-
- p++;
- stringbuffer.reset();
- while (1)
- {
- c = *p++;
- switch (c)
- {
- case ' ':
- case '\t':
- case '\v':
- case '\f':
- continue; // skip white space
-
- case '\r':
- if (*p == '\n')
- continue; // ignore
- // Treat isolated '\r' as if it were a '\n'
- /* fall through */
- case '\n':
- endOfLine();
- continue;
-
- case 0:
- case 0x1A:
- error("unterminated string constant starting at %s", start.toChars());
- t->ustring = (utf8_t *)const_cast<char *>("");
- t->len = 0;
- t->postfix = 0;
- return TOKxstring;
-
- case '"':
- if (n & 1)
- { error("odd number (%d) of hex characters in hex string", n);
- stringbuffer.writeByte(v);
- }
- t->len = (unsigned)stringbuffer.length();
- stringbuffer.writeByte(0);
- t->ustring = (utf8_t *)mem.xmalloc(stringbuffer.length());
- memcpy(t->ustring, stringbuffer.slice().ptr, stringbuffer.length());
- stringPostfix(t);
- return TOKxstring;
-
- default:
- if (c >= '0' && c <= '9')
- c -= '0';
- else if (c >= 'a' && c <= 'f')
- c -= 'a' - 10;
- else if (c >= 'A' && c <= 'F')
- c -= 'A' - 10;
- else if (c & 0x80)
- { p--;
- unsigned u = decodeUTF();
- p++;
- if (u == PS || u == LS)
- endOfLine();
- else
- error("non-hex character \\u%04x in hex string", u);
- }
- else
- error("non-hex character '%c' in hex string", c);
- if (n & 1)
- { v = (v << 4) | c;
- stringbuffer.writeByte(v);
- }
- else
- v = c;
- n++;
- break;
- }
- }
-}
-
-
-/**************************************
- * Lex delimited strings:
- * q"(foo(xxx))" // "foo(xxx)"
- * q"[foo(]" // "foo("
- * q"/foo]/" // "foo]"
- * q"HERE
- * foo
- * HERE" // "foo\n"
- * Input:
- * p is on the "
- */
-
-TOK Lexer::delimitedStringConstant(Token *t)
-{
- unsigned c;
- Loc start = loc();
- unsigned delimleft = 0;
- unsigned delimright = 0;
- unsigned nest = 1;
- unsigned nestcount = ~0; // dead assignment, needed to suppress warning
- Identifier *hereid = NULL;
- unsigned blankrol = 0;
- unsigned startline = 0;
-
- p++;
- stringbuffer.reset();
- while (1)
- {
- c = *p++;
- //printf("c = '%c'\n", c);
- switch (c)
- {
- case '\n':
- Lnextline:
- endOfLine();
- startline = 1;
- if (blankrol)
- { blankrol = 0;
- continue;
- }
- if (hereid)
- {
- stringbuffer.writeUTF8(c);
- continue;
- }
- break;
-
- case '\r':
- if (*p == '\n')
- continue; // ignore
- c = '\n'; // treat EndOfLine as \n character
- goto Lnextline;
-
- case 0:
- case 0x1A:
- error("unterminated delimited string constant starting at %s", start.toChars());
- t->ustring = (utf8_t *)const_cast<char *>("");
- t->len = 0;
- t->postfix = 0;
- return TOKstring;
-
- default:
- if (c & 0x80)
- { p--;
- c = decodeUTF();
- p++;
- if (c == PS || c == LS)
- goto Lnextline;
- }
- break;
- }
- if (delimleft == 0)
- { delimleft = c;
- nest = 1;
- nestcount = 1;
- if (c == '(')
- delimright = ')';
- else if (c == '{')
- delimright = '}';
- else if (c == '[')
- delimright = ']';
- else if (c == '<')
- delimright = '>';
- else if (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c)))
- { // Start of identifier; must be a heredoc
- Token tok;
- p--;
- scan(&tok); // read in heredoc identifier
- if (tok.value != TOKidentifier)
- { error("identifier expected for heredoc, not %s", tok.toChars());
- delimright = c;
- }
- else
- { hereid = tok.ident;
- //printf("hereid = '%s'\n", hereid->toChars());
- blankrol = 1;
- }
- nest = 0;
- }
- else
- { delimright = c;
- nest = 0;
- if (isspace(c))
- error("delimiter cannot be whitespace");
- }
- }
- else
- {
- if (blankrol)
- { error("heredoc rest of line should be blank");
- blankrol = 0;
- continue;
- }
- if (nest == 1)
- {
- if (c == delimleft)
- nestcount++;
- else if (c == delimright)
- { nestcount--;
- if (nestcount == 0)
- goto Ldone;
- }
- }
- else if (c == delimright)
- goto Ldone;
- if (startline && isalpha(c) && hereid)
- { Token tok;
- const utf8_t *psave = p;
- p--;
- scan(&tok); // read in possible heredoc identifier
- //printf("endid = '%s'\n", tok.ident->toChars());
- if (tok.value == TOKidentifier && tok.ident->equals(hereid))
- { /* should check that rest of line is blank
- */
- goto Ldone;
- }
- p = psave;
- }
- stringbuffer.writeUTF8(c);
- startline = 0;
- }
- }
-
-Ldone:
- if (*p == '"')
- p++;
- else if (hereid)
- error("delimited string must end in %s\"", hereid->toChars());
- else
- error("delimited string must end in %c\"", delimright);
- t->len = (unsigned)stringbuffer.length();
- stringbuffer.writeByte(0);
- t->ustring = (utf8_t *)mem.xmalloc(stringbuffer.length());
- memcpy(t->ustring, stringbuffer.slice().ptr, stringbuffer.length());
- stringPostfix(t);
- return TOKstring;
-}
-
-/**************************************
- * Lex delimited strings:
- * q{ foo(xxx) } // " foo(xxx) "
- * q{foo(} // "foo("
- * q{{foo}"}"} // "{foo}"}""
- * Input:
- * p is on the q
- */
-
-TOK Lexer::tokenStringConstant(Token *t)
-{
- unsigned nest = 1;
- Loc start = loc();
- const utf8_t *pstart = ++p;
-
- while (1)
- { Token tok;
-
- scan(&tok);
- switch (tok.value)
- {
- case TOKlcurly:
- nest++;
- continue;
-
- case TOKrcurly:
- if (--nest == 0)
- {
- t->len = (unsigned)(p - 1 - pstart);
- t->ustring = (utf8_t *)mem.xmalloc(t->len + 1);
- memcpy(t->ustring, pstart, t->len);
- t->ustring[t->len] = 0;
- stringPostfix(t);
- return TOKstring;
- }
- continue;
-
- case TOKeof:
- error("unterminated token string constant starting at %s", start.toChars());
- t->ustring = (utf8_t *)const_cast<char *>("");
- t->len = 0;
- t->postfix = 0;
- return TOKstring;
-
- default:
- continue;
- }
- }
-}
-
-
-
-/**************************************
- */
-
-TOK Lexer::escapeStringConstant(Token *t)
-{
- unsigned c;
- Loc start = loc();
-
- p++;
- stringbuffer.reset();
- while (1)
- {
- c = *p++;
- switch (c)
- {
- case '\\':
- switch (*p)
- {
- case 'u':
- case 'U':
- case '&':
- c = escapeSequence();
- stringbuffer.writeUTF8(c);
- continue;
-
- default:
- c = escapeSequence();
- break;
- }
- break;
- case '\n':
- endOfLine();
- break;
-
- case '\r':
- if (*p == '\n')
- continue; // ignore
- c = '\n'; // treat EndOfLine as \n character
- endOfLine();
- break;
-
- case '"':
- t->len = (unsigned)stringbuffer.length();
- stringbuffer.writeByte(0);
- t->ustring = (utf8_t *)mem.xmalloc(stringbuffer.length());
- memcpy(t->ustring, stringbuffer.slice().ptr, stringbuffer.length());
- stringPostfix(t);
- return TOKstring;
-
- case 0:
- case 0x1A:
- p--;
- error("unterminated string constant starting at %s", start.toChars());
- t->ustring = (utf8_t *)const_cast<char *>("");
- t->len = 0;
- t->postfix = 0;
- return TOKstring;
-
- default:
- if (c & 0x80)
- {
- p--;
- c = decodeUTF();
- if (c == LS || c == PS)
- { c = '\n';
- endOfLine();
- }
- p++;
- stringbuffer.writeUTF8(c);
- continue;
- }
- break;
- }
- stringbuffer.writeByte(c);
- }
-}
-
-/**************************************
- */
-
-TOK Lexer::charConstant(Token *t)
-{
- unsigned c;
- TOK tk = TOKcharv;
-
- //printf("Lexer::charConstant\n");
- p++;
- c = *p++;
- switch (c)
- {
- case '\\':
- switch (*p)
- {
- case 'u':
- t->uns64value = escapeSequence();
- tk = TOKwcharv;
- break;
-
- case 'U':
- case '&':
- t->uns64value = escapeSequence();
- tk = TOKdcharv;
- break;
-
- default:
- t->uns64value = escapeSequence();
- break;
- }
- break;
- case '\n':
- L1:
- endOfLine();
- /* fall through */
- case '\r':
- case 0:
- case 0x1A:
- case '\'':
- error("unterminated character constant");
- t->uns64value = '?';
- return tk;
-
- default:
- if (c & 0x80)
- {
- p--;
- c = decodeUTF();
- p++;
- if (c == LS || c == PS)
- goto L1;
- if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE))
- tk = TOKwcharv;
- else
- tk = TOKdcharv;
- }
- t->uns64value = c;
- break;
- }
-
- if (*p != '\'')
- {
- error("unterminated character constant");
- t->uns64value = '?';
- return tk;
- }
- p++;
- return tk;
-}
-
-/***************************************
- * Get postfix of string literal.
- */
-
-void Lexer::stringPostfix(Token *t)
-{
- switch (*p)
- {
- case 'c':
- case 'w':
- case 'd':
- t->postfix = *p;
- p++;
- break;
-
- default:
- t->postfix = 0;
- break;
- }
-}
-
-/**************************************
- * Read in a number.
- * If it's an integer, store it in tok.TKutok.Vlong.
- * integers can be decimal, octal or hex
- * Handle the suffixes U, UL, LU, L, etc.
- * If it's double, store it in tok.TKutok.Vdouble.
- * Returns:
- * TKnum
- * TKdouble,...
- */
-
-TOK Lexer::number(Token *t)
-{
- int base = 10;
- const utf8_t *start = p;
- unsigned c;
- uinteger_t n = 0; // unsigned >=64 bit integer type
- int d;
- bool err = false;
- bool overflow = false;
-
- c = *p;
- if (c == '0')
- {
- ++p;
- c = *p;
- switch (c)
- {
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- n = c - '0';
- ++p;
- base = 8;
- break;
-
- case 'x':
- case 'X':
- ++p;
- base = 16;
- break;
-
- case 'b':
- case 'B':
- ++p;
- base = 2;
- break;
-
- case '.':
- if (p[1] == '.')
- goto Ldone; // if ".."
- if (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80)
- goto Ldone; // if ".identifier" or ".unicode"
- goto Lreal; // '.' is part of current token
-
- case 'i':
- case 'f':
- case 'F':
- goto Lreal;
-
- case '_':
- ++p;
- base = 8;
- break;
-
- case 'L':
- if (p[1] == 'i')
- goto Lreal;
- break;
-
- default:
- break;
- }
- }
-
- while (1)
- {
- c = *p;
- switch (c)
- {
- case '0': case '1':
- ++p;
- d = c - '0';
- break;
-
- case '2': case '3':
- case '4': case '5': case '6': case '7':
- if (base == 2 && !err)
- {
- error("binary digit expected");
- err = true;
- }
- ++p;
- d = c - '0';
- break;
-
- case '8': case '9':
- ++p;
- if (base < 10 && !err)
- {
- error("radix %d digit expected, not `%c`", base, c);
- err = true;
- }
- d = c - '0';
- break;
-
- case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
- case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
- ++p;
- if (base != 16)
- {
- if (c == 'e' || c == 'E' || c == 'f' || c == 'F')
- goto Lreal;
- if (!err)
- {
- error("radix %d digit expected, not `%c`", base, c);
- err = true;
- }
- }
- if (c >= 'a')
- d = c + 10 - 'a';
- else
- d = c + 10 - 'A';
- break;
-
- case 'L':
- if (p[1] == 'i')
- goto Lreal;
- goto Ldone;
-
- case '.':
- if (p[1] == '.')
- goto Ldone; // if ".."
- if (base == 10 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80))
- goto Ldone; // if ".identifier" or ".unicode"
- goto Lreal; // otherwise as part of a floating point literal
-
- case 'p':
- case 'P':
- case 'i':
- Lreal:
- p = start;
- return inreal(t);
-
- case '_':
- ++p;
- continue;
-
- default:
- goto Ldone;
- }
-
- uinteger_t n2 = n * base;
- if ((n2 / base != n || n2 + d < n))
- {
- overflow = true;
- }
- n = n2 + d;
-
- // if n needs more than 64 bits
- if (sizeof(n) > 8 &&
- n > 0xFFFFFFFFFFFFFFFFULL)
- {
- overflow = true;
- }
- }
-
-Ldone:
-
- if (overflow && !err)
- {
- error("integer overflow");
- err = true;
- }
-
- enum FLAGS
- {
- FLAGS_none = 0,
- FLAGS_decimal = 1, // decimal
- FLAGS_unsigned = 2, // u or U suffix
- FLAGS_long = 4, // L suffix
- };
-
- unsigned flags = (base == 10) ? FLAGS_decimal : FLAGS_none;
-
- // Parse trailing 'u', 'U', 'l' or 'L' in any combination
- const utf8_t *psuffix = p;
- while (1)
- {
- utf8_t f;
- switch (*p)
- {
- case 'U':
- case 'u':
- f = FLAGS_unsigned;
- goto L1;
-
- case 'l':
- f = FLAGS_long;
- error("lower case integer suffix 'l' is not allowed. Please use 'L' instead");
- goto L1;
-
- case 'L':
- f = FLAGS_long;
- L1:
- p++;
- if ((flags & f) && !err)
- {
- error("unrecognized token");
- err = true;
- }
- flags = (FLAGS) (flags | f);
- continue;
- default:
- break;
- }
- break;
- }
-
- if (base == 8 && n >= 8)
- error("octal literals 0%llo%.*s are no longer supported, use std.conv.octal!%llo%.*s instead",
- n, p - psuffix, psuffix, n, p - psuffix, psuffix);
-
- TOK result;
- switch (flags)
- {
- case FLAGS_none:
- /* Octal or Hexadecimal constant.
- * First that fits: int, uint, long, ulong
- */
- if (n & 0x8000000000000000LL)
- result = TOKuns64v;
- else if (n & 0xFFFFFFFF00000000LL)
- result = TOKint64v;
- else if (n & 0x80000000)
- result = TOKuns32v;
- else
- result = TOKint32v;
- break;
-
- case FLAGS_decimal:
- /* First that fits: int, long, long long
- */
- if (n & 0x8000000000000000LL)
- {
- if (!err)
- {
- error("signed integer overflow");
- err = true;
- }
- result = TOKuns64v;
- }
- else if (n & 0xFFFFFFFF80000000LL)
- result = TOKint64v;
- else
- result = TOKint32v;
- break;
-
- case FLAGS_unsigned:
- case FLAGS_decimal | FLAGS_unsigned:
- /* First that fits: uint, ulong
- */
- if (n & 0xFFFFFFFF00000000LL)
- result = TOKuns64v;
- else
- result = TOKuns32v;
- break;
-
- case FLAGS_decimal | FLAGS_long:
- if (n & 0x8000000000000000LL)
- {
- if (!err)
- {
- error("signed integer overflow");
- err = true;
- }
- result = TOKuns64v;
- }
- else
- result = TOKint64v;
- break;
-
- case FLAGS_long:
- if (n & 0x8000000000000000LL)
- result = TOKuns64v;
- else
- result = TOKint64v;
- break;
-
- case FLAGS_unsigned | FLAGS_long:
- case FLAGS_decimal | FLAGS_unsigned | FLAGS_long:
- result = TOKuns64v;
- break;
-
- default:
- assert(0);
- }
- t->uns64value = n;
- return result;
-}
-
-/**************************************
- * Read in characters, converting them to real.
- * Bugs:
- * Exponent overflow not detected.
- * Too much requested precision is not detected.
- */
-
-TOK Lexer::inreal(Token *t)
-{
- //printf("Lexer::inreal()\n");
- bool isWellformedString = true;
- stringbuffer.reset();
- const utf8_t *pstart = p;
- char hex = 0;
- unsigned c = *p++;
-
- // Leading '0x'
- if (c == '0')
- {
- c = *p++;
- if (c == 'x' || c == 'X')
- {
- hex = true;
- c = *p++;
- }
- }
-
- // Digits to left of '.'
- while (1)
- {
- if (c == '.')
- {
- c = *p++;
- break;
- }
- if (isdigit(c) || (hex && isxdigit(c)) || c == '_')
- {
- c = *p++;
- continue;
- }
- break;
- }
-
- // Digits to right of '.'
- while (1)
- {
- if (isdigit(c) || (hex && isxdigit(c)) || c == '_')
- {
- c = *p++;
- continue;
- }
- break;
- }
-
- if (c == 'e' || c == 'E' || (hex && (c == 'p' || c == 'P')))
- {
- c = *p++;
- if (c == '-' || c == '+')
- {
- c = *p++;
- }
- bool anyexp = false;
- while (1)
- {
- if (isdigit(c))
- {
- anyexp = true;
- c = *p++;
- continue;
- }
- if (c == '_')
- {
- c = *p++;
- continue;
- }
- if (!anyexp)
- {
- error("missing exponent");
- isWellformedString = false;
- }
- break;
- }
- }
- else if (hex)
- {
- error("exponent required for hex float");
- isWellformedString = false;
- }
- --p;
- while (pstart < p)
- {
- if (*pstart != '_')
- stringbuffer.writeByte(*pstart);
- ++pstart;
- }
-
- stringbuffer.writeByte(0);
- const char *sbufptr = (char *)stringbuffer.slice().ptr;
- TOK result;
- bool isOutOfRange = false;
- t->floatvalue = (isWellformedString ? CTFloat::parse(sbufptr, &isOutOfRange) : CTFloat::zero);
- errno = 0;
- switch (*p)
- {
- case 'F':
- case 'f':
- if (isWellformedString && !isOutOfRange)
- isOutOfRange = Port::isFloat32LiteralOutOfRange(sbufptr);
- result = TOKfloat32v;
- p++;
- break;
-
- default:
- if (isWellformedString && !isOutOfRange)
- isOutOfRange = Port::isFloat64LiteralOutOfRange(sbufptr);
- result = TOKfloat64v;
- break;
-
- case 'l':
- error("use 'L' suffix instead of 'l'");
- /* fall through */
- case 'L':
- result = TOKfloat80v;
- p++;
- break;
- }
- if (*p == 'i' || *p == 'I')
- {
- if (*p == 'I')
- error("use 'i' suffix instead of 'I'");
- p++;
- switch (result)
- {
- case TOKfloat32v:
- result = TOKimaginary32v;
- break;
- case TOKfloat64v:
- result = TOKimaginary64v;
- break;
- case TOKfloat80v:
- result = TOKimaginary80v;
- break;
- default: break;
- }
- }
- const bool isLong = (result == TOKfloat80v || result == TOKimaginary80v);
- if (isOutOfRange && !isLong)
- {
- const char *suffix = (result == TOKfloat32v || result == TOKimaginary32v) ? "f" : "";
- error(scanloc, "number `%s%s` is not representable", (char *)stringbuffer.slice().ptr, suffix);
- }
- return result;
-}
-
-/*********************************************
- * parse:
- * #line linnum [filespec]
- * also allow __LINE__ for linnum, and __FILE__ for filespec
- */
-
-void Lexer::poundLine()
-{
- Token tok;
- int linnum = this->scanloc.linnum;
- char *filespec = NULL;
- Loc loc = this->loc();
-
- scan(&tok);
- if (tok.value == TOKint32v || tok.value == TOKint64v)
- {
- int lin = (int)(tok.uns64value - 1);
- if ((unsigned)lin != tok.uns64value - 1)
- error("line number %lld out of range", (unsigned long long)tok.uns64value);
- else
- linnum = lin;
- }
- else if (tok.value == TOKline)
- {
- }
- else
- goto Lerr;
-
- while (1)
- {
- switch (*p)
- {
- case 0:
- case 0x1A:
- case '\n':
- Lnewline:
- this->scanloc.linnum = linnum;
- if (filespec)
- this->scanloc.filename = filespec;
- return;
-
- case '\r':
- p++;
- if (*p != '\n')
- { p--;
- goto Lnewline;
- }
- continue;
-
- case ' ':
- case '\t':
- case '\v':
- case '\f':
- p++;
- continue; // skip white space
-
- case '_':
- if (memcmp(p, "__FILE__", 8) == 0)
- {
- p += 8;
- filespec = mem.xstrdup(scanloc.filename);
- continue;
- }
- goto Lerr;
-
- case '"':
- if (filespec)
- goto Lerr;
- stringbuffer.reset();
- p++;
- while (1)
- { unsigned c;
-
- c = *p;
- switch (c)
- {
- case '\n':
- case '\r':
- case 0:
- case 0x1A:
- goto Lerr;
-
- case '"':
- stringbuffer.writeByte(0);
- filespec = mem.xstrdup((char *)stringbuffer.slice().ptr);
- p++;
- break;
-
- default:
- if (c & 0x80)
- { unsigned u = decodeUTF();
- if (u == PS || u == LS)
- goto Lerr;
- }
- stringbuffer.writeByte(c);
- p++;
- continue;
- }
- break;
- }
- continue;
-
- default:
- if (*p & 0x80)
- { unsigned u = decodeUTF();
- if (u == PS || u == LS)
- goto Lnewline;
- }
- goto Lerr;
- }
- }
-
-Lerr:
- error(loc, "#line integer [\"filespec\"]\\n expected");
-}
-
-
-/********************************************
- * Decode UTF character.
- * Issue error messages for invalid sequences.
- * Return decoded character, advance p to last character in UTF sequence.
- */
-
-unsigned Lexer::decodeUTF()
-{
- dchar_t u;
- utf8_t c;
- const utf8_t *s = p;
- size_t len;
- size_t idx;
- const char *msg;
-
- c = *s;
- assert(c & 0x80);
-
- // Check length of remaining string up to 6 UTF-8 characters
- for (len = 1; len < 6 && s[len]; len++)
- ;
-
- idx = 0;
- msg = utf_decodeChar(s, len, &idx, &u);
- p += idx - 1;
- if (msg)
- {
- error("%s", msg);
- }
- return u;
-}
-
-static void trimTrailingWhitespace(OutBuffer &buf)
-{
- const unsigned char *s = buf.slice().ptr;
- size_t len = buf.length();
- while (len && (s[len - 1] == ' ' || s[len - 1] == '\t'))
- --len;
- buf.setsize(len);
-}
-
-/***************************************************
- * Parse doc comment embedded between t->ptr and p.
- * Remove trailing blanks and tabs from lines.
- * Replace all newlines with \n.
- * Remove leading comment character from each line.
- * Decide if it's a lineComment or a blockComment.
- * Append to previous one for this token.
- */
-
-void Lexer::getDocComment(Token *t, unsigned lineComment)
-{
- /* ct tells us which kind of comment it is: '/', '*', or '+'
- */
- utf8_t ct = t->ptr[2];
-
- /* Start of comment text skips over / * *, / + +, or / / /
- */
- const utf8_t *q = t->ptr + 3; // start of comment text
-
- const utf8_t *qend = p;
- if (ct == '*' || ct == '+')
- qend -= 2;
-
- /* Scan over initial row of ****'s or ++++'s or ////'s
- */
- for (; q < qend; q++)
- {
- if (*q != ct)
- break;
- }
-
- /* Remove leading spaces until start of the comment
- */
- int linestart = 0;
- if (ct == '/')
- {
- while (q < qend && (*q == ' ' || *q == '\t'))
- ++q;
- }
- else if (q < qend)
- {
- if (*q == '\r')
- {
- ++q;
- if (q < qend && *q == '\n')
- ++q;
- linestart = 1;
- }
- else if (*q == '\n')
- {
- ++q;
- linestart = 1;
- }
- }
-
- /* Remove trailing row of ****'s or ++++'s
- */
- if (ct != '/')
- {
- for (; q < qend; qend--)
- {
- if (qend[-1] != ct)
- break;
- }
- }
-
- /* Comment is now [q .. qend].
- * Canonicalize it into buf[].
- */
- OutBuffer buf;
-
- for (; q < qend; q++)
- {
- utf8_t c = *q;
-
- switch (c)
- {
- case '*':
- case '+':
- if (linestart && c == ct)
- { linestart = 0;
- /* Trim preceding whitespace up to preceding \n
- */
- trimTrailingWhitespace(buf);
- continue;
- }
- break;
-
- case ' ':
- case '\t':
- break;
-
- case '\r':
- if (q[1] == '\n')
- continue; // skip the \r
- goto Lnewline;
-
- default:
- if (c == 226)
- {
- // If LS or PS
- if (q[1] == 128 &&
- (q[2] == 168 || q[2] == 169))
- {
- q += 2;
- goto Lnewline;
- }
- }
- linestart = 0;
- break;
-
- Lnewline:
- c = '\n'; // replace all newlines with \n
- /* fall through */
- case '\n':
- linestart = 1;
-
- /* Trim trailing whitespace
- */
- trimTrailingWhitespace(buf);
- break;
- }
- buf.writeByte(c);
- }
-
- /* Trim trailing whitespace (if the last line does not have newline)
- */
- if (buf.length() && (buf.slice().ptr[buf.length() - 1] == ' ' || buf.slice().ptr[buf.length() - 1] == '\t'))
- {
- trimTrailingWhitespace(buf);
- }
-
- // Always end with a newline
- if (!buf.length() || buf.slice().ptr[buf.length() - 1] != '\n')
- buf.writeByte('\n');
-
- buf.writeByte(0);
-
- // It's a line comment if the start of the doc comment comes
- // after other non-whitespace on the same line.
- const utf8_t** dc = (lineComment && anyToken)
- ? &t->lineComment
- : &t->blockComment;
-
- // Combine with previous doc comment, if any
- if (*dc)
- *dc = combineComments(*dc, (utf8_t *)buf.slice().ptr);
- else
- *dc = (utf8_t *)buf.extractData();
-}
-
-/********************************************
- * Combine two document comments into one,
- * separated by a newline.
- */
-
-const utf8_t *Lexer::combineComments(const utf8_t *c1, const utf8_t *c2)
-{
- //printf("Lexer::combineComments('%s', '%s')\n", c1, c2);
-
- const utf8_t *c = c2;
-
- if (c1)
- {
- c = c1;
- if (c2)
- {
- size_t len1 = strlen((const char *)c1);
- size_t len2 = strlen((const char *)c2);
-
- int insertNewLine = 0;
- if (len1 && c1[len1 - 1] != '\n')
- {
- ++len1;
- insertNewLine = 1;
- }
-
- utf8_t *p = (utf8_t *)mem.xmalloc(len1 + 1 + len2 + 1);
- memcpy(p, c1, len1 - insertNewLine);
- if (insertNewLine)
- p[len1 - 1] = '\n';
-
- p[len1] = '\n';
-
- memcpy(p + len1 + 1, c2, len2);
- p[len1 + 1 + len2] = 0;
- c = p;
- }
- }
- return c;
-}
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
new file mode 100644
index 0000000..afffc2d
--- /dev/null
+++ b/gcc/d/dmd/lexer.d
@@ -0,0 +1,3273 @@
+/**
+ * Implements the lexical analyzer, which converts source code into lexical tokens.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/lex.html, Lexical)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/lexer.d, _lexer.d)
+ * Documentation: https://dlang.org/phobos/dmd_lexer.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/lexer.d
+ */
+
+module dmd.lexer;
+
+import core.stdc.ctype;
+import core.stdc.errno;
+import core.stdc.stdarg;
+import core.stdc.stdio;
+import core.stdc.stdlib : getenv;
+import core.stdc.string;
+import core.stdc.time;
+
+import dmd.entity;
+import dmd.errors;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.root.ctfloat;
+import dmd.root.outbuffer;
+import dmd.root.port;
+import dmd.root.rmem;
+import dmd.root.string;
+import dmd.tokens;
+import dmd.utf;
+import dmd.utils;
+
+nothrow:
+
+private enum LS = 0x2028; // UTF line separator
+private enum PS = 0x2029; // UTF paragraph separator
+
+/********************************************
+ * Do our own char maps
+ */
+private static immutable cmtable = () {
+ ubyte[256] table;
+ foreach (const c; 0 .. table.length)
+ {
+ if ('0' <= c && c <= '7')
+ table[c] |= CMoctal;
+ if (c_isxdigit(c))
+ table[c] |= CMhex;
+ if (c_isalnum(c) || c == '_')
+ table[c] |= CMidchar;
+
+ switch (c)
+ {
+ case 'x': case 'X':
+ case 'b': case 'B':
+ table[c] |= CMzerosecond;
+ break;
+
+ case '0': .. case '9':
+ case 'e': case 'E':
+ case 'f': case 'F':
+ case 'l': case 'L':
+ case 'p': case 'P':
+ case 'u': case 'U':
+ case 'i':
+ case '.':
+ case '_':
+ table[c] |= CMzerosecond | CMdigitsecond;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (c)
+ {
+ case '\\':
+ case '\n':
+ case '\r':
+ case 0:
+ case 0x1A:
+ case '\'':
+ break;
+ default:
+ if (!(c & 0x80))
+ table[c] |= CMsinglechar;
+ break;
+ }
+ }
+ return table;
+}();
+
+private
+{
+ enum CMoctal = 0x1;
+ enum CMhex = 0x2;
+ enum CMidchar = 0x4;
+ enum CMzerosecond = 0x8;
+ enum CMdigitsecond = 0x10;
+ enum CMsinglechar = 0x20;
+}
+
+private bool isoctal(const char c) pure @nogc @safe
+{
+ return (cmtable[c] & CMoctal) != 0;
+}
+
+private bool ishex(const char c) pure @nogc @safe
+{
+ return (cmtable[c] & CMhex) != 0;
+}
+
+private bool isidchar(const char c) pure @nogc @safe
+{
+ return (cmtable[c] & CMidchar) != 0;
+}
+
+private bool isZeroSecond(const char c) pure @nogc @safe
+{
+ return (cmtable[c] & CMzerosecond) != 0;
+}
+
+private bool isDigitSecond(const char c) pure @nogc @safe
+{
+ return (cmtable[c] & CMdigitsecond) != 0;
+}
+
+private bool issinglechar(const char c) pure @nogc @safe
+{
+ return (cmtable[c] & CMsinglechar) != 0;
+}
+
+private bool c_isxdigit(const int c) pure @nogc @safe
+{
+ return (( c >= '0' && c <= '9') ||
+ ( c >= 'a' && c <= 'f') ||
+ ( c >= 'A' && c <= 'F'));
+}
+
+private bool c_isalnum(const int c) pure @nogc @safe
+{
+ return (( c >= '0' && c <= '9') ||
+ ( c >= 'a' && c <= 'z') ||
+ ( c >= 'A' && c <= 'Z'));
+}
+
+unittest
+{
+ //printf("lexer.unittest\n");
+ /* Not much here, just trying things out.
+ */
+ string text = "int"; // We rely on the implicit null-terminator
+ scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0);
+ TOK tok;
+ tok = lex1.nextToken();
+ //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32);
+ assert(tok == TOK.int32);
+ tok = lex1.nextToken();
+ assert(tok == TOK.endOfFile);
+ tok = lex1.nextToken();
+ assert(tok == TOK.endOfFile);
+ tok = lex1.nextToken();
+ assert(tok == TOK.endOfFile);
+}
+
+unittest
+{
+ // We don't want to see Lexer error output during these tests.
+ uint errors = global.startGagging();
+ scope(exit) global.endGagging(errors);
+
+ // Test malformed input: even malformed input should end in a TOK.endOfFile.
+ static immutable char[][] testcases =
+ [ // Testcase must end with 0 or 0x1A.
+ [0], // not malformed, but pathological
+ ['\'', 0],
+ ['\'', 0x1A],
+ ['{', '{', 'q', '{', 0],
+ [0xFF, 0],
+ [0xFF, 0x80, 0],
+ [0xFF, 0xFF, 0],
+ [0xFF, 0xFF, 0],
+ ['x', '"', 0x1A],
+ ];
+
+ foreach (testcase; testcases)
+ {
+ scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0);
+ TOK tok = lex2.nextToken();
+ size_t iterations = 1;
+ while ((tok != TOK.endOfFile) && (iterations++ < testcase.length))
+ {
+ tok = lex2.nextToken();
+ }
+ assert(tok == TOK.endOfFile);
+ tok = lex2.nextToken();
+ assert(tok == TOK.endOfFile);
+ }
+}
+
+version (DMDLIB)
+{
+ version = LocOffset;
+}
+
+/***********************************************************
+ */
+class Lexer
+{
+ private __gshared OutBuffer stringbuffer;
+
+ Loc scanloc; // for error messages
+ Loc prevloc; // location of token before current
+
+ const(char)* p; // current character
+
+ Token token;
+
+ // For ImportC
+ bool Ccompile; /// true if compiling ImportC
+
+ // The following are valid only if (Ccompile == true)
+ ubyte longsize; /// size of C long, 4 or 8
+ ubyte long_doublesize; /// size of C long double, 8 or D real.sizeof
+ ubyte wchar_tsize; /// size of C wchar_t, 2 or 4
+
+ private
+ {
+ const(char)* base; // pointer to start of buffer
+ const(char)* end; // pointer to last element of buffer
+ const(char)* line; // start of current line
+
+ bool doDocComment; // collect doc comment information
+ bool anyToken; // seen at least one token
+ bool commentToken; // comments are TOK.comment's
+ int inTokenStringConstant; // can be larger than 1 when in nested q{} strings
+ int lastDocLine; // last line of previous doc comment
+
+ Token* tokenFreelist;
+ }
+
+ nothrow:
+
+ /*********************
+ * Creates a Lexer for the source code base[begoffset..endoffset+1].
+ * The last character, base[endoffset], must be null (0) or EOF (0x1A).
+ *
+ * Params:
+ * filename = used for error messages
+ * base = source code, must be terminated by a null (0) or EOF (0x1A) character
+ * begoffset = starting offset into base[]
+ * endoffset = the last offset to read into base[]
+ * doDocComment = handle documentation comments
+ * commentToken = comments become TOK.comment's
+ */
+ this(const(char)* filename, const(char)* base, size_t begoffset,
+ size_t endoffset, bool doDocComment, bool commentToken) pure
+ {
+ scanloc = Loc(filename, 1, 1);
+ //printf("Lexer::Lexer(%p,%d)\n",base,length);
+ //printf("lexer.filename = %s\n", filename);
+ token = Token.init;
+ this.base = base;
+ this.end = base + endoffset;
+ p = base + begoffset;
+ line = p;
+ this.doDocComment = doDocComment;
+ this.commentToken = commentToken;
+ this.inTokenStringConstant = 0;
+ this.lastDocLine = 0;
+ //initKeywords();
+ /* If first line starts with '#!', ignore the line
+ */
+ if (p && p[0] == '#' && p[1] == '!')
+ {
+ p += 2;
+ while (1)
+ {
+ char c = *p++;
+ switch (c)
+ {
+ case 0:
+ case 0x1A:
+ p--;
+ goto case;
+ case '\n':
+ break;
+ default:
+ continue;
+ }
+ break;
+ }
+ endOfLine();
+ }
+ }
+
+ /// Returns: a newly allocated `Token`.
+ Token* allocateToken() pure nothrow @safe
+ {
+ if (tokenFreelist)
+ {
+ Token* t = tokenFreelist;
+ tokenFreelist = t.next;
+ t.next = null;
+ return t;
+ }
+ return new Token();
+ }
+
+ /// Frees the given token by returning it to the freelist.
+ private void releaseToken(Token* token) pure nothrow @nogc @safe
+ {
+ if (mem.isGCEnabled)
+ *token = Token.init;
+ token.next = tokenFreelist;
+ tokenFreelist = token;
+ }
+
+ final TOK nextToken()
+ {
+ prevloc = token.loc;
+ if (token.next)
+ {
+ Token* t = token.next;
+ memcpy(&token, t, Token.sizeof);
+ releaseToken(t);
+ }
+ else
+ {
+ scan(&token);
+ }
+ //printf(token.toChars());
+ return token.value;
+ }
+
+ /***********************
+ * Look ahead at next token's value.
+ */
+ final TOK peekNext()
+ {
+ return peek(&token).value;
+ }
+
+ /***********************
+ * Look 2 tokens ahead at value.
+ */
+ final TOK peekNext2()
+ {
+ Token* t = peek(&token);
+ return peek(t).value;
+ }
+
+ /****************************
+ * Turn next token in buffer into a token.
+ */
+ final void scan(Token* t)
+ {
+ const lastLine = scanloc.linnum;
+ Loc startLoc;
+ t.blockComment = null;
+ t.lineComment = null;
+
+ while (1)
+ {
+ t.ptr = p;
+ //printf("p = %p, *p = '%c'\n",p,*p);
+ t.loc = loc();
+ switch (*p)
+ {
+ case 0:
+ case 0x1A:
+ t.value = TOK.endOfFile; // end of file
+ // Intentionally not advancing `p`, such that subsequent calls keep returning TOK.endOfFile.
+ return;
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ p++;
+ continue; // skip white space
+ case '\r':
+ p++;
+ if (*p != '\n') // if CR stands by itself
+ {
+ endOfLine();
+ goto skipFourSpaces;
+ }
+ continue; // skip white space
+ case '\n':
+ p++;
+ endOfLine();
+ skipFourSpaces:
+ while (*(cast(uint*)p) == 0x20202020) //' ' == 0x20
+ {
+ p+=4;
+ }
+ continue; // skip white space
+ case '0':
+ if (!isZeroSecond(p[1])) // if numeric literal does not continue
+ {
+ ++p;
+ t.unsvalue = 0;
+ t.value = TOK.int32Literal;
+ return;
+ }
+ goto Lnumber;
+
+ case '1': .. case '9':
+ if (!isDigitSecond(p[1])) // if numeric literal does not continue
+ {
+ t.unsvalue = *p - '0';
+ ++p;
+ t.value = TOK.int32Literal;
+ return;
+ }
+ Lnumber:
+ t.value = number(t);
+ return;
+
+ case '\'':
+ if (issinglechar(p[1]) && p[2] == '\'')
+ {
+ t.unsvalue = p[1]; // simple one character literal
+ t.value = Ccompile ? TOK.int32Literal : TOK.charLiteral;
+ p += 3;
+ }
+ else if (Ccompile)
+ {
+ clexerCharConstant(*t, 0);
+ }
+ else
+ {
+ t.value = charConstant(t);
+ }
+ return;
+
+ case 'u':
+ case 'U':
+ case 'L':
+ if (!Ccompile)
+ goto case_ident;
+ if (p[1] == '\'') // C wide character constant
+ {
+ char c = *p;
+ if (c == 'L') // convert L to u or U
+ c = (wchar_tsize == 4) ? 'u' : 'U';
+ ++p;
+ clexerCharConstant(*t, c);
+ return;
+ }
+ else if (p[1] == '\"') // C wide string literal
+ {
+ const c = *p;
+ ++p;
+ escapeStringConstant(t);
+ t.postfix = c == 'L' ? (wchar_tsize == 2 ? 'w' : 'd') :
+ c == 'u' ? 'w' :
+ 'd';
+ return;
+ }
+ goto case_ident;
+
+ case 'r':
+ if (p[1] != '"')
+ goto case_ident;
+ p++;
+ goto case '`';
+ case '`':
+ wysiwygStringConstant(t);
+ return;
+ case 'x':
+ if (p[1] != '"')
+ goto case_ident;
+ p++;
+ auto start = p;
+ OutBuffer hexString;
+ t.value = hexStringConstant(t);
+ hexString.write(start[0 .. p - start]);
+ error("Built-in hex string literals are obsolete, use `std.conv.hexString!%s` instead.", hexString.extractChars());
+ return;
+ case 'q':
+ if (p[1] == '"')
+ {
+ p++;
+ delimitedStringConstant(t);
+ return;
+ }
+ else if (p[1] == '{')
+ {
+ p++;
+ tokenStringConstant(t);
+ return;
+ }
+ else
+ goto case_ident;
+ case '"':
+ escapeStringConstant(t);
+ return;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'g':
+ case 'h':
+ case 'i':
+ case 'j':
+ case 'k':
+ case 'l':
+ case 'm':
+ case 'n':
+ case 'o':
+ case 'p':
+ /*case 'q': case 'r':*/
+ case 's':
+ case 't':
+ //case 'u':
+ case 'v':
+ case 'w':
+ /*case 'x':*/
+ case 'y':
+ case 'z':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ case 'G':
+ case 'H':
+ case 'I':
+ case 'J':
+ case 'K':
+ //case 'L':
+ case 'M':
+ case 'N':
+ case 'O':
+ case 'P':
+ case 'Q':
+ case 'R':
+ case 'S':
+ case 'T':
+ //case 'U':
+ case 'V':
+ case 'W':
+ case 'X':
+ case 'Y':
+ case 'Z':
+ case '_':
+ case_ident:
+ {
+ while (1)
+ {
+ const c = *++p;
+ if (isidchar(c))
+ continue;
+ else if (c & 0x80)
+ {
+ const s = p;
+ const u = decodeUTF();
+ if (isUniAlpha(u))
+ continue;
+ error("char 0x%04x not allowed in identifier", u);
+ p = s;
+ }
+ break;
+ }
+ Identifier id = Identifier.idPool(cast(char*)t.ptr, cast(uint)(p - t.ptr));
+ t.ident = id;
+ t.value = cast(TOK)id.getValue();
+
+ anyToken = 1;
+
+ /* Different keywords for C and D
+ */
+ if (Ccompile)
+ {
+ if (t.value != TOK.identifier)
+ {
+ t.value = Ckeywords[t.value]; // filter out D keywords
+ }
+ }
+ else if (t.value >= FirstCKeyword)
+ t.value = TOK.identifier; // filter out C keywords
+
+ else if (*t.ptr == '_') // if special identifier token
+ {
+ // Lazy initialization
+ TimeStampInfo.initialize(t.loc);
+
+ if (id == Id.DATE)
+ {
+ t.ustring = TimeStampInfo.date.ptr;
+ goto Lstr;
+ }
+ else if (id == Id.TIME)
+ {
+ t.ustring = TimeStampInfo.time.ptr;
+ goto Lstr;
+ }
+ else if (id == Id.VENDOR)
+ {
+ t.ustring = global.vendor.xarraydup.ptr;
+ goto Lstr;
+ }
+ else if (id == Id.TIMESTAMP)
+ {
+ t.ustring = TimeStampInfo.timestamp.ptr;
+ Lstr:
+ t.value = TOK.string_;
+ t.postfix = 0;
+ t.len = cast(uint)strlen(t.ustring);
+ }
+ else if (id == Id.VERSIONX)
+ {
+ t.value = TOK.int64Literal;
+ t.unsvalue = global.versionNumber();
+ }
+ else if (id == Id.EOFX)
+ {
+ t.value = TOK.endOfFile;
+ // Advance scanner to end of file
+ while (!(*p == 0 || *p == 0x1A))
+ p++;
+ }
+ }
+ //printf("t.value = %d\n",t.value);
+ return;
+ }
+ case '/':
+ p++;
+ switch (*p)
+ {
+ case '=':
+ p++;
+ t.value = TOK.divAssign;
+ return;
+ case '*':
+ p++;
+ startLoc = loc();
+ while (1)
+ {
+ while (1)
+ {
+ const c = *p;
+ switch (c)
+ {
+ case '/':
+ break;
+ case '\n':
+ endOfLine();
+ p++;
+ continue;
+ case '\r':
+ p++;
+ if (*p != '\n')
+ endOfLine();
+ continue;
+ case 0:
+ case 0x1A:
+ error("unterminated /* */ comment");
+ p = end;
+ t.loc = loc();
+ t.value = TOK.endOfFile;
+ return;
+ default:
+ if (c & 0x80)
+ {
+ const u = decodeUTF();
+ if (u == PS || u == LS)
+ endOfLine();
+ }
+ p++;
+ continue;
+ }
+ break;
+ }
+ p++;
+ if (p[-2] == '*' && p - 3 != t.ptr)
+ break;
+ }
+ if (commentToken)
+ {
+ t.loc = startLoc;
+ t.value = TOK.comment;
+ return;
+ }
+ else if (doDocComment && t.ptr[2] == '*' && p - 4 != t.ptr)
+ {
+ // if /** but not /**/
+ getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1);
+ lastDocLine = scanloc.linnum;
+ }
+ continue;
+ case '/': // do // style comments
+ startLoc = loc();
+ while (1)
+ {
+ const c = *++p;
+ switch (c)
+ {
+ case '\n':
+ break;
+ case '\r':
+ if (p[1] == '\n')
+ p++;
+ break;
+ case 0:
+ case 0x1A:
+ if (commentToken)
+ {
+ p = end;
+ t.loc = startLoc;
+ t.value = TOK.comment;
+ return;
+ }
+ if (doDocComment && t.ptr[2] == '/')
+ {
+ getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1);
+ lastDocLine = scanloc.linnum;
+ }
+ p = end;
+ t.loc = loc();
+ t.value = TOK.endOfFile;
+ return;
+ default:
+ if (c & 0x80)
+ {
+ const u = decodeUTF();
+ if (u == PS || u == LS)
+ break;
+ }
+ continue;
+ }
+ break;
+ }
+ if (commentToken)
+ {
+ p++;
+ endOfLine();
+ t.loc = startLoc;
+ t.value = TOK.comment;
+ return;
+ }
+ if (doDocComment && t.ptr[2] == '/')
+ {
+ getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1);
+ lastDocLine = scanloc.linnum;
+ }
+ p++;
+ endOfLine();
+ continue;
+ case '+':
+ {
+ int nest;
+ startLoc = loc();
+ p++;
+ nest = 1;
+ while (1)
+ {
+ char c = *p;
+ switch (c)
+ {
+ case '/':
+ p++;
+ if (*p == '+')
+ {
+ p++;
+ nest++;
+ }
+ continue;
+ case '+':
+ p++;
+ if (*p == '/')
+ {
+ p++;
+ if (--nest == 0)
+ break;
+ }
+ continue;
+ case '\r':
+ p++;
+ if (*p != '\n')
+ endOfLine();
+ continue;
+ case '\n':
+ endOfLine();
+ p++;
+ continue;
+ case 0:
+ case 0x1A:
+ error("unterminated /+ +/ comment");
+ p = end;
+ t.loc = loc();
+ t.value = TOK.endOfFile;
+ return;
+ default:
+ if (c & 0x80)
+ {
+ uint u = decodeUTF();
+ if (u == PS || u == LS)
+ endOfLine();
+ }
+ p++;
+ continue;
+ }
+ break;
+ }
+ if (commentToken)
+ {
+ t.loc = startLoc;
+ t.value = TOK.comment;
+ return;
+ }
+ if (doDocComment && t.ptr[2] == '+' && p - 4 != t.ptr)
+ {
+ // if /++ but not /++/
+ getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1);
+ lastDocLine = scanloc.linnum;
+ }
+ continue;
+ }
+ default:
+ break;
+ }
+ t.value = TOK.div;
+ return;
+ case '.':
+ p++;
+ if (isdigit(*p))
+ {
+ /* Note that we don't allow ._1 and ._ as being
+ * valid floating point numbers.
+ */
+ p--;
+ t.value = inreal(t);
+ }
+ else if (p[0] == '.')
+ {
+ if (p[1] == '.')
+ {
+ p += 2;
+ t.value = TOK.dotDotDot;
+ }
+ else
+ {
+ p++;
+ t.value = TOK.slice;
+ }
+ }
+ else
+ t.value = TOK.dot;
+ return;
+ case '&':
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.andAssign;
+ }
+ else if (*p == '&')
+ {
+ p++;
+ t.value = TOK.andAnd;
+ }
+ else
+ t.value = TOK.and;
+ return;
+ case '|':
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.orAssign;
+ }
+ else if (*p == '|')
+ {
+ p++;
+ t.value = TOK.orOr;
+ }
+ else
+ t.value = TOK.or;
+ return;
+ case '-':
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.minAssign;
+ }
+ else if (*p == '-')
+ {
+ p++;
+ t.value = TOK.minusMinus;
+ }
+ else if (*p == '>')
+ {
+ ++p;
+ t.value = TOK.arrow;
+ }
+ else
+ t.value = TOK.min;
+ return;
+ case '+':
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.addAssign;
+ }
+ else if (*p == '+')
+ {
+ p++;
+ t.value = TOK.plusPlus;
+ }
+ else
+ t.value = TOK.add;
+ return;
+ case '<':
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.lessOrEqual; // <=
+ }
+ else if (*p == '<')
+ {
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.leftShiftAssign; // <<=
+ }
+ else
+ t.value = TOK.leftShift; // <<
+ }
+ else if (*p == ':' && Ccompile)
+ {
+ ++p;
+ t.value = TOK.leftBracket; // <:
+ }
+ else if (*p == '%' && Ccompile)
+ {
+ ++p;
+ t.value = TOK.leftCurly; // <%
+ }
+ else
+ t.value = TOK.lessThan; // <
+ return;
+ case '>':
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.greaterOrEqual; // >=
+ }
+ else if (*p == '>')
+ {
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.rightShiftAssign; // >>=
+ }
+ else if (*p == '>')
+ {
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.unsignedRightShiftAssign; // >>>=
+ }
+ else
+ t.value = TOK.unsignedRightShift; // >>>
+ }
+ else
+ t.value = TOK.rightShift; // >>
+ }
+ else
+ t.value = TOK.greaterThan; // >
+ return;
+ case '!':
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.notEqual; // !=
+ }
+ else
+ t.value = TOK.not; // !
+ return;
+ case '=':
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.equal; // ==
+ }
+ else if (*p == '>')
+ {
+ p++;
+ t.value = TOK.goesTo; // =>
+ }
+ else
+ t.value = TOK.assign; // =
+ return;
+ case '~':
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.concatenateAssign; // ~=
+ }
+ else
+ t.value = TOK.tilde; // ~
+ return;
+ case '^':
+ p++;
+ if (*p == '^')
+ {
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.powAssign; // ^^=
+ }
+ else
+ t.value = TOK.pow; // ^^
+ }
+ else if (*p == '=')
+ {
+ p++;
+ t.value = TOK.xorAssign; // ^=
+ }
+ else
+ t.value = TOK.xor; // ^
+ return;
+ case '(':
+ p++;
+ t.value = TOK.leftParenthesis;
+ return;
+ case ')':
+ p++;
+ t.value = TOK.rightParenthesis;
+ return;
+ case '[':
+ p++;
+ t.value = TOK.leftBracket;
+ return;
+ case ']':
+ p++;
+ t.value = TOK.rightBracket;
+ return;
+ case '{':
+ p++;
+ t.value = TOK.leftCurly;
+ return;
+ case '}':
+ p++;
+ t.value = TOK.rightCurly;
+ return;
+ case '?':
+ p++;
+ t.value = TOK.question;
+ return;
+ case ',':
+ p++;
+ t.value = TOK.comma;
+ return;
+ case ';':
+ p++;
+ t.value = TOK.semicolon;
+ return;
+ case ':':
+ p++;
+ if (*p == ':')
+ {
+ ++p;
+ t.value = TOK.colonColon;
+ }
+ else if (*p == '>' && Ccompile)
+ {
+ ++p;
+ t.value = TOK.rightBracket;
+ }
+ else
+ t.value = TOK.colon;
+ return;
+ case '$':
+ p++;
+ t.value = TOK.dollar;
+ return;
+ case '@':
+ p++;
+ t.value = TOK.at;
+ return;
+ case '*':
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.mulAssign;
+ }
+ else
+ t.value = TOK.mul;
+ return;
+ case '%':
+ p++;
+ if (*p == '=')
+ {
+ p++;
+ t.value = TOK.modAssign;
+ }
+ else if (*p == '>' && Ccompile)
+ {
+ ++p;
+ t.value = TOK.rightCurly;
+ }
+ else if (*p == ':' && Ccompile)
+ {
+ goto case '#'; // %: means #
+ }
+ else
+ t.value = TOK.mod;
+ return;
+ case '#':
+ {
+ p++;
+ Token n;
+ scan(&n);
+ if (Ccompile && n.value == TOK.int32Literal)
+ {
+ poundLine(n, true);
+ continue;
+ }
+ if (n.value == TOK.identifier)
+ {
+ if (n.ident == Id.line)
+ {
+ poundLine(n, false);
+ continue;
+ }
+ else
+ {
+ const locx = loc();
+ warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars());
+ }
+ }
+ else if (n.value == TOK.if_)
+ {
+ error("C preprocessor directive `#if` is not supported, use `version` or `static if`");
+ }
+ t.value = TOK.pound;
+ return;
+ }
+ default:
+ {
+ dchar c = *p;
+ if (c & 0x80)
+ {
+ c = decodeUTF();
+ // Check for start of unicode identifier
+ if (isUniAlpha(c))
+ goto case_ident;
+ if (c == PS || c == LS)
+ {
+ endOfLine();
+ p++;
+ continue;
+ }
+ }
+ if (c < 0x80 && isprint(c))
+ error("character '%c' is not a valid token", c);
+ else
+ error("character 0x%02x is not a valid token", c);
+ p++;
+ continue;
+ }
+ }
+ }
+ }
+
+ final Token* peek(Token* ct)
+ {
+ Token* t;
+ if (ct.next)
+ t = ct.next;
+ else
+ {
+ t = allocateToken();
+ scan(t);
+ ct.next = t;
+ }
+ return t;
+ }
+
+ /*********************************
+ * tk is on the opening (.
+ * Look ahead and return token that is past the closing ).
+ */
+ final Token* peekPastParen(Token* tk)
+ {
+ //printf("peekPastParen()\n");
+ int parens = 1;
+ int curlynest = 0;
+ while (1)
+ {
+ tk = peek(tk);
+ //tk.print();
+ switch (tk.value)
+ {
+ case TOK.leftParenthesis:
+ parens++;
+ continue;
+ case TOK.rightParenthesis:
+ --parens;
+ if (parens)
+ continue;
+ tk = peek(tk);
+ break;
+ case TOK.leftCurly:
+ curlynest++;
+ continue;
+ case TOK.rightCurly:
+ if (--curlynest >= 0)
+ continue;
+ break;
+ case TOK.semicolon:
+ if (curlynest)
+ continue;
+ break;
+ case TOK.endOfFile:
+ break;
+ default:
+ continue;
+ }
+ return tk;
+ }
+ }
+
+ /*******************************************
+ * Parse escape sequence.
+ */
+ private uint escapeSequence()
+ {
+ return Lexer.escapeSequence(token.loc, p, Ccompile);
+ }
+
+ /********
+ * Parse the given string literal escape sequence into a single character.
+ * D https://dlang.org/spec/lex.html#escape_sequences
+ * C11 6.4.4.4
+ * Params:
+ * loc = location to use for error messages
+ * sequence = pointer to string with escape sequence to parse. Updated to
+ * point past the end of the escape sequence
+ * Ccompile = true for compile C11 escape sequences
+ * Returns:
+ * the escape sequence as a single character
+ */
+ private static dchar escapeSequence(const ref Loc loc, ref const(char)* sequence, bool Ccompile)
+ {
+ const(char)* p = sequence; // cache sequence reference on stack
+ scope(exit) sequence = p;
+
+ uint c = *p;
+ int ndigits;
+ switch (c)
+ {
+ case '\'':
+ case '"':
+ case '?':
+ case '\\':
+ Lconsume:
+ p++;
+ break;
+ case 'a':
+ c = 7;
+ goto Lconsume;
+ case 'b':
+ c = 8;
+ goto Lconsume;
+ case 'f':
+ c = 12;
+ goto Lconsume;
+ case 'n':
+ c = 10;
+ goto Lconsume;
+ case 'r':
+ c = 13;
+ goto Lconsume;
+ case 't':
+ c = 9;
+ goto Lconsume;
+ case 'v':
+ c = 11;
+ goto Lconsume;
+ case 'u':
+ ndigits = 4;
+ goto Lhex;
+ case 'U':
+ ndigits = 8;
+ goto Lhex;
+ case 'x':
+ ndigits = 2;
+ Lhex:
+ p++;
+ c = *p;
+ if (ishex(cast(char)c))
+ {
+ uint v = 0;
+ int n = 0;
+ while (1)
+ {
+ if (isdigit(cast(char)c))
+ c -= '0';
+ else if (islower(c))
+ c -= 'a' - 10;
+ else
+ c -= 'A' - 10;
+ v = v * 16 + c;
+ c = *++p;
+ if (++n == ndigits)
+ break;
+ if (!ishex(cast(char)c))
+ {
+ .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits);
+ break;
+ }
+ }
+ if (ndigits != 2 && !utf_isValidDchar(v))
+ {
+ .error(loc, "invalid UTF character \\U%08x", v);
+ v = '?'; // recover with valid UTF character
+ }
+ c = v;
+ }
+ else
+ {
+ .error(loc, "undefined escape hex sequence \\%c%c", sequence[0], c);
+ p++;
+ }
+ break;
+ case '&':
+ if (Ccompile)
+ goto default;
+
+ // named character entity
+ for (const idstart = ++p; 1; p++)
+ {
+ switch (*p)
+ {
+ case ';':
+ c = HtmlNamedEntity(idstart, p - idstart);
+ if (c == ~0)
+ {
+ .error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart);
+ c = '?';
+ }
+ p++;
+ break;
+ default:
+ if (isalpha(*p) || (p != idstart && isdigit(*p)))
+ continue;
+ .error(loc, "unterminated named entity &%.*s;", cast(int)(p - idstart + 1), idstart);
+ c = '?';
+ break;
+ }
+ break;
+ }
+ break;
+ case 0:
+ case 0x1A:
+ // end of file
+ c = '\\';
+ break;
+ default:
+ if (isoctal(cast(char)c))
+ {
+ uint v = 0;
+ int n = 0;
+ do
+ {
+ v = v * 8 + (c - '0');
+ c = *++p;
+ }
+ while (++n < 3 && isoctal(cast(char)c));
+ c = v;
+ if (c > 0xFF)
+ .error(loc, "escape octal sequence \\%03o is larger than \\377", c);
+ }
+ else
+ {
+ .error(loc, "undefined escape sequence \\%c", c);
+ p++;
+ }
+ break;
+ }
+ return c;
+ }
+
+ /**
+ Lex a wysiwyg string. `p` must be pointing to the first character before the
+ contents of the string literal. The character pointed to by `p` will be used as
+ the terminating character (i.e. backtick or double-quote).
+ Params:
+ result = pointer to the token that accepts the result
+ */
+ private void wysiwygStringConstant(Token* result)
+ {
+ result.value = TOK.string_;
+ Loc start = loc();
+ auto terminator = p[0];
+ p++;
+ stringbuffer.setsize(0);
+ while (1)
+ {
+ dchar c = p[0];
+ p++;
+ switch (c)
+ {
+ case '\n':
+ endOfLine();
+ break;
+ case '\r':
+ if (p[0] == '\n')
+ continue; // ignore
+ c = '\n'; // treat EndOfLine as \n character
+ endOfLine();
+ break;
+ case 0:
+ case 0x1A:
+ error("unterminated string constant starting at %s", start.toChars());
+ result.setString();
+ // rewind `p` so it points to the EOF character
+ p--;
+ return;
+ default:
+ if (c == terminator)
+ {
+ result.setString(stringbuffer);
+ stringPostfix(result);
+ return;
+ }
+ else if (c & 0x80)
+ {
+ p--;
+ const u = decodeUTF();
+ p++;
+ if (u == PS || u == LS)
+ endOfLine();
+ stringbuffer.writeUTF8(u);
+ continue;
+ }
+ break;
+ }
+ stringbuffer.writeByte(c);
+ }
+ }
+
+ /**************************************
+ * Lex hex strings:
+ * x"0A ae 34FE BD"
+ */
+ private TOK hexStringConstant(Token* t)
+ {
+ Loc start = loc();
+ uint n = 0;
+ uint v = ~0; // dead assignment, needed to suppress warning
+ p++;
+ stringbuffer.setsize(0);
+ while (1)
+ {
+ dchar c = *p++;
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ continue; // skip white space
+ case '\r':
+ if (*p == '\n')
+ continue; // ignore '\r' if followed by '\n'
+ // Treat isolated '\r' as if it were a '\n'
+ goto case '\n';
+ case '\n':
+ endOfLine();
+ continue;
+ case 0:
+ case 0x1A:
+ error("unterminated string constant starting at %s", start.toChars());
+ t.setString();
+ // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token).
+ p--;
+ return TOK.hexadecimalString;
+ case '"':
+ if (n & 1)
+ {
+ error("odd number (%d) of hex characters in hex string", n);
+ stringbuffer.writeByte(v);
+ }
+ t.setString(stringbuffer);
+ stringPostfix(t);
+ return TOK.hexadecimalString;
+ default:
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'a' && c <= 'f')
+ c -= 'a' - 10;
+ else if (c >= 'A' && c <= 'F')
+ c -= 'A' - 10;
+ else if (c & 0x80)
+ {
+ p--;
+ const u = decodeUTF();
+ p++;
+ if (u == PS || u == LS)
+ endOfLine();
+ else
+ error("non-hex character \\u%04x in hex string", u);
+ }
+ else
+ error("non-hex character '%c' in hex string", c);
+ if (n & 1)
+ {
+ v = (v << 4) | c;
+ stringbuffer.writeByte(v);
+ }
+ else
+ v = c;
+ n++;
+ break;
+ }
+ }
+ assert(0); // see bug 15731
+ }
+
+ /**
+ Lex a delimited string. Some examples of delimited strings are:
+ ---
+ q"(foo(xxx))" // "foo(xxx)"
+ q"[foo$(LPAREN)]" // "foo$(LPAREN)"
+ q"/foo]/" // "foo]"
+ q"HERE
+ foo
+ HERE" // "foo\n"
+ ---
+ It is assumed that `p` points to the opening double-quote '"'.
+ Params:
+ result = pointer to the token that accepts the result
+ */
+ private void delimitedStringConstant(Token* result)
+ {
+ result.value = TOK.string_;
+ Loc start = loc();
+ dchar delimleft = 0;
+ dchar delimright = 0;
+ uint nest = 1;
+ uint nestcount = ~0; // dead assignment, needed to suppress warning
+ Identifier hereid = null;
+ uint blankrol = 0;
+ uint startline = 0;
+ p++;
+ stringbuffer.setsize(0);
+ while (1)
+ {
+ dchar c = *p++;
+ //printf("c = '%c'\n", c);
+ switch (c)
+ {
+ case '\n':
+ Lnextline:
+ endOfLine();
+ startline = 1;
+ if (blankrol)
+ {
+ blankrol = 0;
+ continue;
+ }
+ if (hereid)
+ {
+ stringbuffer.writeUTF8(c);
+ continue;
+ }
+ break;
+ case '\r':
+ if (*p == '\n')
+ continue; // ignore
+ c = '\n'; // treat EndOfLine as \n character
+ goto Lnextline;
+ case 0:
+ case 0x1A:
+ error("unterminated delimited string constant starting at %s", start.toChars());
+ result.setString();
+ // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token).
+ p--;
+ return;
+ default:
+ if (c & 0x80)
+ {
+ p--;
+ c = decodeUTF();
+ p++;
+ if (c == PS || c == LS)
+ goto Lnextline;
+ }
+ break;
+ }
+ if (delimleft == 0)
+ {
+ delimleft = c;
+ nest = 1;
+ nestcount = 1;
+ if (c == '(')
+ delimright = ')';
+ else if (c == '{')
+ delimright = '}';
+ else if (c == '[')
+ delimright = ']';
+ else if (c == '<')
+ delimright = '>';
+ else if (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c)))
+ {
+ // Start of identifier; must be a heredoc
+ Token tok;
+ p--;
+ scan(&tok); // read in heredoc identifier
+ if (tok.value != TOK.identifier)
+ {
+ error("identifier expected for heredoc, not %s", tok.toChars());
+ delimright = c;
+ }
+ else
+ {
+ hereid = tok.ident;
+ //printf("hereid = '%s'\n", hereid.toChars());
+ blankrol = 1;
+ }
+ nest = 0;
+ }
+ else
+ {
+ delimright = c;
+ nest = 0;
+ if (isspace(c))
+ error("delimiter cannot be whitespace");
+ }
+ }
+ else
+ {
+ if (blankrol)
+ {
+ error("heredoc rest of line should be blank");
+ blankrol = 0;
+ continue;
+ }
+ if (nest == 1)
+ {
+ if (c == delimleft)
+ nestcount++;
+ else if (c == delimright)
+ {
+ nestcount--;
+ if (nestcount == 0)
+ goto Ldone;
+ }
+ }
+ else if (c == delimright)
+ goto Ldone;
+ if (startline && (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c))) && hereid)
+ {
+ Token tok;
+ auto psave = p;
+ p--;
+ scan(&tok); // read in possible heredoc identifier
+ //printf("endid = '%s'\n", tok.ident.toChars());
+ if (tok.value == TOK.identifier && tok.ident is hereid)
+ {
+ /* should check that rest of line is blank
+ */
+ goto Ldone;
+ }
+ p = psave;
+ }
+ stringbuffer.writeUTF8(c);
+ startline = 0;
+ }
+ }
+ Ldone:
+ if (*p == '"')
+ p++;
+ else if (hereid)
+ error("delimited string must end in %s\"", hereid.toChars());
+ else
+ error("delimited string must end in %c\"", delimright);
+ result.setString(stringbuffer);
+ stringPostfix(result);
+ }
+
+ /**
+ Lex a token string. Some examples of token strings are:
+ ---
+ q{ foo(xxx) } // " foo(xxx) "
+ q{foo$(LPAREN)} // "foo$(LPAREN)"
+ q{{foo}"}"} // "{foo}"}""
+ ---
+ It is assumed that `p` points to the opening curly-brace.
+ Params:
+ result = pointer to the token that accepts the result
+ */
+ private void tokenStringConstant(Token* result)
+ {
+ result.value = TOK.string_;
+
+ uint nest = 1;
+ const start = loc();
+ const pstart = ++p;
+ inTokenStringConstant++;
+ scope(exit) inTokenStringConstant--;
+ while (1)
+ {
+ Token tok;
+ scan(&tok);
+ switch (tok.value)
+ {
+ case TOK.leftCurly:
+ nest++;
+ continue;
+ case TOK.rightCurly:
+ if (--nest == 0)
+ {
+ result.setString(pstart, p - 1 - pstart);
+ stringPostfix(result);
+ return;
+ }
+ continue;
+ case TOK.endOfFile:
+ error("unterminated token string constant starting at %s", start.toChars());
+ result.setString();
+ return;
+ default:
+ continue;
+ }
+ }
+ }
+
+ /**
+ Scan a quoted string while building the processed string value by
+ handling escape sequences. The result is returned in the given `t` token.
+ This function assumes that `p` currently points to the opening quote
+ of the string.
+ Params:
+ t = the token to set the resulting string to
+ * References:
+ * D https://dlang.org/spec/lex.html#double_quoted_strings
+ * ImportC C11 6.4.5
+ */
+ private void escapeStringConstant(Token* t)
+ {
+ t.value = TOK.string_;
+
+ const start = loc();
+ const tc = *p++; // opening quote
+ stringbuffer.setsize(0);
+ while (1)
+ {
+ dchar c = *p++;
+ switch (c)
+ {
+ case '\\':
+ switch (*p)
+ {
+ case '&':
+ if (Ccompile)
+ goto default;
+ goto case;
+
+ case 'u':
+ case 'U':
+ c = escapeSequence();
+ stringbuffer.writeUTF8(c);
+ continue;
+ default:
+ c = escapeSequence();
+ break;
+ }
+ break;
+ case '\n':
+ endOfLine();
+ if (Ccompile)
+ goto Lunterminated;
+ break;
+ case '\r':
+ if (*p == '\n')
+ continue; // ignore
+ c = '\n'; // treat EndOfLine as \n character
+ endOfLine();
+ if (Ccompile)
+ goto Lunterminated;
+ break;
+ case '\'':
+ case '"':
+ if (c != tc)
+ goto default;
+ t.setString(stringbuffer);
+ if (!Ccompile)
+ stringPostfix(t);
+ return;
+ case 0:
+ case 0x1A:
+ // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token).
+ p--;
+ Lunterminated:
+ error("unterminated string constant starting at %s", start.toChars());
+ t.setString();
+ return;
+ default:
+ if (c & 0x80)
+ {
+ p--;
+ c = decodeUTF();
+ if (c == LS || c == PS)
+ {
+ c = '\n';
+ endOfLine();
+ if (Ccompile)
+ goto Lunterminated;
+ }
+ p++;
+ stringbuffer.writeUTF8(c);
+ continue;
+ }
+ break;
+ }
+ stringbuffer.writeByte(c);
+ }
+ }
+
+ /**************************************
+ * Reference:
+ * https://dlang.org/spec/lex.html#characterliteral
+ */
+ private TOK charConstant(Token* t)
+ {
+ TOK tk = TOK.charLiteral;
+ //printf("Lexer::charConstant\n");
+ p++;
+ dchar c = *p++;
+ switch (c)
+ {
+ case '\\':
+ switch (*p)
+ {
+ case 'u':
+ t.unsvalue = escapeSequence();
+ tk = TOK.wcharLiteral;
+ break;
+ case 'U':
+ case '&':
+ t.unsvalue = escapeSequence();
+ tk = TOK.dcharLiteral;
+ break;
+ default:
+ t.unsvalue = escapeSequence();
+ break;
+ }
+ break;
+ case '\n':
+ L1:
+ endOfLine();
+ goto case;
+ case '\r':
+ goto case '\'';
+ case 0:
+ case 0x1A:
+ // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token).
+ p--;
+ goto case;
+ case '\'':
+ error("unterminated character constant");
+ t.unsvalue = '?';
+ return tk;
+ default:
+ if (c & 0x80)
+ {
+ p--;
+ c = decodeUTF();
+ p++;
+ if (c == LS || c == PS)
+ goto L1;
+ if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE))
+ tk = TOK.wcharLiteral;
+ else
+ tk = TOK.dcharLiteral;
+ }
+ t.unsvalue = c;
+ break;
+ }
+ if (*p != '\'')
+ {
+ while (*p != '\'' && *p != 0x1A && *p != 0 && *p != '\n' &&
+ *p != '\r' && *p != ';' && *p != ')' && *p != ']' && *p != '}')
+ {
+ if (*p & 0x80)
+ {
+ const s = p;
+ c = decodeUTF();
+ if (c == LS || c == PS)
+ {
+ p = s;
+ break;
+ }
+ }
+ p++;
+ }
+
+ if (*p == '\'')
+ {
+ error("character constant has multiple characters");
+ p++;
+ }
+ else
+ error("unterminated character constant");
+ t.unsvalue = '?';
+ return tk;
+ }
+ p++;
+ return tk;
+ }
+
+ /***************************************
+ * Lex C character constant.
+ * Parser is on the opening quote.
+ * Params:
+ * t = token to fill in
+ * prefix = one of `u`, `U` or 0.
+ * Reference:
+ * C11 6.4.4.4
+ */
+ private void clexerCharConstant(ref Token t, char prefix)
+ {
+ escapeStringConstant(&t);
+ const(char)[] str = t.ustring[0 .. t.len];
+ const n = str.length;
+ const loc = t.loc;
+ if (n == 0)
+ {
+ error(loc, "empty character constant");
+ t.value = TOK.semicolon;
+ return;
+ }
+
+ uint u;
+ switch (prefix)
+ {
+ case 0:
+ if (n == 1) // fast case
+ {
+ u = str[0];
+ }
+ else if (n > 4)
+ error(loc, "max number of chars in character literal is 4, had %d",
+ cast(int)n);
+ else
+ {
+ foreach (i, c; str)
+ (cast(char*)&u)[n - 1 - i] = c;
+ }
+ break;
+
+ case 'u':
+ dchar d1;
+ size_t idx;
+ auto msg = utf_decodeChar(str, idx, d1);
+ dchar d2 = 0;
+ if (idx < n && !msg)
+ msg = utf_decodeChar(str, idx, d2);
+ if (msg)
+ error(loc, "%s", msg);
+ else if (idx < n)
+ error(loc, "max number of chars in 16 bit character literal is 2, had %d",
+ (n + 1) >> 1);
+ else if (d1 > 0x1_0000)
+ error(loc, "%d does not fit in 16 bits", d1);
+ else if (d2 > 0x1_0000)
+ error(loc, "%d does not fit in 16 bits", d2);
+ u = d1;
+ if (d2)
+ u = (d1 << 16) | d2;
+ break;
+
+ case 'U':
+ dchar d;
+ size_t idx;
+ auto msg = utf_decodeChar(str, idx, d);
+ if (msg)
+ error(loc, "%s", msg);
+ else if (idx < n)
+ error(loc, "max number of chars in 32 bit character literal is 1, had %d",
+ (n + 3) >> 2);
+ u = d;
+ break;
+
+ default:
+ assert(0);
+ }
+ t.value = TOK.int32Literal;
+ t.unsvalue = u;
+ }
+
+ /***************************************
+ * Get postfix of string literal.
+ */
+ private void stringPostfix(Token* t) pure @nogc
+ {
+ switch (*p)
+ {
+ case 'c':
+ case 'w':
+ case 'd':
+ t.postfix = *p;
+ p++;
+ break;
+ default:
+ t.postfix = 0;
+ break;
+ }
+ }
+
+ /**************************************
+ * Read in a number.
+ * If it's an integer, store it in tok.TKutok.Vlong.
+ * integers can be decimal, octal or hex
+ * Handle the suffixes U, UL, LU, L, etc.
+ * If it's double, store it in tok.TKutok.Vdouble.
+ * Returns:
+ * TKnum
+ * TKdouble,...
+ */
+ private TOK number(Token* t)
+ {
+ int base = 10;
+ const start = p;
+ uinteger_t n = 0; // unsigned >=64 bit integer type
+ int d;
+ bool err = false;
+ bool overflow = false;
+ bool anyBinaryDigitsNoSingleUS = false;
+ bool anyHexDigitsNoSingleUS = false;
+ dchar c = *p;
+ if (c == '0')
+ {
+ ++p;
+ c = *p;
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ base = 8;
+ break;
+
+ case '8':
+ case '9':
+ if (Ccompile)
+ error("octal digit expected, not `%c`", c);
+ base = 8;
+ break;
+ case 'x':
+ case 'X':
+ ++p;
+ base = 16;
+ break;
+ case 'b':
+ case 'B':
+ if (Ccompile)
+ error("binary constants not allowed");
+ ++p;
+ base = 2;
+ break;
+ case '.':
+ if (p[1] == '.')
+ goto Ldone; // if ".."
+ if (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80)
+ goto Ldone; // if ".identifier" or ".unicode"
+ goto Lreal; // '.' is part of current token
+ case 'i':
+ case 'f':
+ case 'F':
+ goto Lreal;
+ case '_':
+ if (Ccompile)
+ error("embedded `_` not allowed");
+ ++p;
+ base = 8;
+ break;
+ case 'L':
+ if (p[1] == 'i')
+ goto Lreal;
+ break;
+ default:
+ break;
+ }
+ }
+ while (1)
+ {
+ c = *p;
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ ++p;
+ d = c - '0';
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ ++p;
+ if (base != 16)
+ {
+ if (c == 'e' || c == 'E' || c == 'f' || c == 'F')
+ goto Lreal;
+ }
+ if (c >= 'a')
+ d = c + 10 - 'a';
+ else
+ d = c + 10 - 'A';
+ break;
+ case 'L':
+ if (p[1] == 'i')
+ goto Lreal;
+ goto Ldone;
+ case '.':
+ if (p[1] == '.')
+ goto Ldone; // if ".."
+ if (base == 10 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80))
+ goto Ldone; // if ".identifier" or ".unicode"
+ if (base == 16 && (!ishex(p[1]) || p[1] == '_' || p[1] & 0x80))
+ goto Ldone; // if ".identifier" or ".unicode"
+ if (base == 2)
+ goto Ldone; // if ".identifier" or ".unicode"
+ goto Lreal; // otherwise as part of a floating point literal
+ case 'p':
+ case 'P':
+ case 'i':
+ Lreal:
+ p = start;
+ return inreal(t);
+ case '_':
+ if (Ccompile)
+ goto default;
+ ++p;
+ continue;
+ default:
+ goto Ldone;
+ }
+ // got a digit here, set any necessary flags, check for errors
+ anyHexDigitsNoSingleUS = true;
+ anyBinaryDigitsNoSingleUS = true;
+ if (!err && d >= base)
+ {
+ error("%s digit expected, not `%c`", base == 2 ? "binary".ptr :
+ base == 8 ? "octal".ptr :
+ "decimal".ptr, c);
+ err = true;
+ }
+ // Avoid expensive overflow check if we aren't at risk of overflow
+ if (n <= 0x0FFF_FFFF_FFFF_FFFFUL)
+ n = n * base + d;
+ else
+ {
+ import core.checkedint : mulu, addu;
+
+ n = mulu(n, base, overflow);
+ n = addu(n, d, overflow);
+ }
+ }
+ Ldone:
+ if (overflow && !err)
+ {
+ error("integer overflow");
+ err = true;
+ }
+ if ((base == 2 && !anyBinaryDigitsNoSingleUS) ||
+ (base == 16 && !anyHexDigitsNoSingleUS))
+ error("`%.*s` isn't a valid integer literal, use `%.*s0` instead", cast(int)(p - start), start, 2, start);
+
+ t.unsvalue = n;
+
+ if (Ccompile)
+ return cnumber(base, n);
+
+ enum FLAGS : int
+ {
+ none = 0,
+ decimal = 1, // decimal
+ unsigned = 2, // u or U suffix
+ long_ = 4, // L suffix
+ }
+
+ FLAGS flags = (base == 10) ? FLAGS.decimal : FLAGS.none;
+ // Parse trailing 'u', 'U', 'l' or 'L' in any combination
+ const psuffix = p;
+ while (1)
+ {
+ FLAGS f;
+ switch (*p)
+ {
+ case 'U':
+ case 'u':
+ f = FLAGS.unsigned;
+ goto L1;
+ case 'l':
+ f = FLAGS.long_;
+ error("lower case integer suffix 'l' is not allowed. Please use 'L' instead");
+ goto L1;
+ case 'L':
+ f = FLAGS.long_;
+ L1:
+ p++;
+ if ((flags & f) && !err)
+ {
+ error("unrecognized token");
+ err = true;
+ }
+ flags = cast(FLAGS)(flags | f);
+ continue;
+ default:
+ break;
+ }
+ break;
+ }
+ if (base == 8 && n >= 8)
+ {
+ if (err)
+ // can't translate invalid octal value, just show a generic message
+ error("octal literals larger than 7 are no longer supported");
+ else
+ error("octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!%llo%.*s` instead",
+ n, cast(int)(p - psuffix), psuffix, n, cast(int)(p - psuffix), psuffix);
+ }
+ TOK result;
+ switch (flags)
+ {
+ case FLAGS.none:
+ /* Octal or Hexadecimal constant.
+ * First that fits: int, uint, long, ulong
+ */
+ if (n & 0x8000000000000000L)
+ result = TOK.uns64Literal;
+ else if (n & 0xFFFFFFFF00000000L)
+ result = TOK.int64Literal;
+ else if (n & 0x80000000)
+ result = TOK.uns32Literal;
+ else
+ result = TOK.int32Literal;
+ break;
+ case FLAGS.decimal:
+ /* First that fits: int, long, long long
+ */
+ if (n & 0x8000000000000000L)
+ {
+ result = TOK.uns64Literal;
+ }
+ else if (n & 0xFFFFFFFF80000000L)
+ result = TOK.int64Literal;
+ else
+ result = TOK.int32Literal;
+ break;
+ case FLAGS.unsigned:
+ case FLAGS.decimal | FLAGS.unsigned:
+ /* First that fits: uint, ulong
+ */
+ if (n & 0xFFFFFFFF00000000L)
+ result = TOK.uns64Literal;
+ else
+ result = TOK.uns32Literal;
+ break;
+ case FLAGS.decimal | FLAGS.long_:
+ if (n & 0x8000000000000000L)
+ {
+ if (!err)
+ {
+ error("signed integer overflow");
+ err = true;
+ }
+ result = TOK.uns64Literal;
+ }
+ else
+ result = TOK.int64Literal;
+ break;
+ case FLAGS.long_:
+ if (n & 0x8000000000000000L)
+ result = TOK.uns64Literal;
+ else
+ result = TOK.int64Literal;
+ break;
+ case FLAGS.unsigned | FLAGS.long_:
+ case FLAGS.decimal | FLAGS.unsigned | FLAGS.long_:
+ result = TOK.uns64Literal;
+ break;
+ default:
+ debug
+ {
+ printf("%x\n", flags);
+ }
+ assert(0);
+ }
+ return result;
+ }
+
+ /**************************************
+ * Lex C integer-suffix
+ * Params:
+ * base = number base
+ * n = raw integer value
+ * Returns:
+ * token value
+ */
+ private TOK cnumber(int base, uinteger_t n)
+ {
+ /* C11 6.4.4.1
+ * Parse trailing suffixes:
+ * u or U
+ * l or L
+ * ll or LL
+ */
+ enum FLAGS : uint
+ {
+ octalhex = 1, // octal or hexadecimal
+ decimal = 2, // decimal
+ unsigned = 4, // u or U suffix
+ long_ = 8, // l or L suffix
+ llong = 0x10 // ll or LL
+ }
+ FLAGS flags = (base == 10) ? FLAGS.decimal : FLAGS.octalhex;
+ bool err;
+ Lsuffixes:
+ while (1)
+ {
+ FLAGS f;
+ const cs = *p;
+ switch (cs)
+ {
+ case 'U':
+ case 'u':
+ f = FLAGS.unsigned;
+ break;
+
+ case 'l':
+ case 'L':
+ f = FLAGS.long_;
+ if (cs == p[1])
+ {
+ f = FLAGS.long_ | FLAGS.llong;
+ ++p;
+ }
+ break;
+
+ default:
+ break Lsuffixes;
+ }
+ ++p;
+ if ((flags & f) && !err)
+ {
+ error("duplicate integer suffixes");
+ err = true;
+ }
+ flags = cast(FLAGS)(flags | f);
+ }
+
+ void overflow()
+ {
+ error("integer overflow");
+ }
+
+ TOK result = TOK.int32Literal; // default
+ switch (flags)
+ {
+ /* Since D doesn't have a variable sized `long` or `unsigned long` type,
+ * this code deviates from C by picking D int, uint, long, or ulong instead
+ */
+
+ case FLAGS.octalhex:
+ /* Octal or Hexadecimal constant.
+ * First that fits: int, unsigned, long, unsigned long,
+ * long long, unsigned long long
+ */
+ if (longsize == 4)
+ {
+ if (n & 0x8000000000000000L)
+ result = TOK.uns64Literal;
+ else if (n & 0xFFFFFFFF00000000L)
+ result = TOK.int64Literal;
+ else if (n & 0x80000000)
+ result = TOK.uns32Literal;
+ else
+ result = TOK.int32Literal;
+ }
+ else
+ {
+ if (n & 0x8000000000000000L)
+ result = TOK.uns64Literal; // unsigned long
+ else if (n & 0xFFFFFFFF00000000L)
+ result = TOK.int64Literal; // long
+ else if (n & 0x80000000)
+ result = TOK.uns32Literal;
+ else
+ result = TOK.int32Literal;
+ }
+ break;
+
+ case FLAGS.decimal:
+ /* First that fits: int, long, long long
+ */
+ if (longsize == 4)
+ {
+ if (n & 0x8000000000000000L)
+ result = TOK.uns64Literal;
+ else if (n & 0xFFFFFFFF80000000L)
+ result = TOK.int64Literal;
+ else
+ result = TOK.int32Literal;
+ }
+ else
+ {
+ if (n & 0x8000000000000000L)
+ result = TOK.uns64Literal; // unsigned long
+ else if (n & 0xFFFFFFFF80000000L)
+ result = TOK.int64Literal; // long
+ else
+ result = TOK.int32Literal;
+ }
+ break;
+
+ case FLAGS.octalhex | FLAGS.unsigned:
+ case FLAGS.decimal | FLAGS.unsigned:
+ /* First that fits: unsigned, unsigned long, unsigned long long
+ */
+ if (longsize == 4)
+ {
+ if (n & 0xFFFFFFFF00000000L)
+ result = TOK.uns64Literal;
+ else
+ result = TOK.uns32Literal;
+ }
+ else
+ {
+ if (n & 0xFFFFFFFF00000000L)
+ result = TOK.uns64Literal; // unsigned long
+ else
+ result = TOK.uns32Literal;
+ }
+ break;
+
+ case FLAGS.decimal | FLAGS.long_:
+ /* First that fits: long, long long
+ */
+ if (longsize == 4)
+ {
+ if (n & 0x8000000000000000L)
+ overflow();
+ else if (n & 0xFFFFFFFF_80000000L)
+ result = TOK.int64Literal;
+ else
+ result = TOK.int32Literal; // long
+ }
+ else
+ {
+ if (n & 0x8000000000000000L)
+ overflow();
+ else
+ result = TOK.int64Literal; // long
+ }
+ break;
+
+ case FLAGS.octalhex | FLAGS.long_:
+ /* First that fits: long, unsigned long, long long,
+ * unsigned long long
+ */
+ if (longsize == 4)
+ {
+ if (n & 0x8000000000000000L)
+ result = TOK.uns64Literal;
+ else if (n & 0xFFFFFFFF00000000L)
+ result = TOK.int64Literal;
+ else if (n & 0x80000000)
+ result = TOK.uns32Literal; // unsigned long
+ else
+ result = TOK.int32Literal; // long
+ }
+ else
+ {
+ if (n & 0x80000000_00000000L)
+ result = TOK.uns64Literal; // unsigned long
+ else
+ result = TOK.int64Literal; // long
+ }
+ break;
+
+ case FLAGS.octalhex | FLAGS.unsigned | FLAGS.long_:
+ case FLAGS.decimal | FLAGS.unsigned | FLAGS.long_:
+ /* First that fits: unsigned long, unsigned long long
+ */
+ if (longsize == 4)
+ {
+ if (n & 0xFFFFFFFF00000000L)
+ result = TOK.uns64Literal;
+ else
+ result = TOK.uns32Literal; // unsigned long
+ }
+ else
+ {
+ result = TOK.uns64Literal; // unsigned long
+ }
+ break;
+
+ case FLAGS.octalhex | FLAGS.long_ | FLAGS.llong:
+ /* First that fits: long long, unsigned long long
+ */
+ if (n & 0x8000000000000000L)
+ result = TOK.uns64Literal;
+ else
+ result = TOK.int64Literal;
+ break;
+
+ case FLAGS.decimal | FLAGS.long_ | FLAGS.llong:
+ /* long long
+ */
+ result = TOK.int64Literal;
+ break;
+
+ case FLAGS.octalhex | FLAGS.long_ | FLAGS.unsigned | FLAGS.llong:
+ case FLAGS.decimal | FLAGS.long_ | FLAGS.unsigned | FLAGS.llong:
+ result = TOK.uns64Literal;
+ break;
+
+ default:
+ debug printf("%x\n",flags);
+ assert(0);
+ }
+ return result;
+ }
+
+ /**************************************
+ * Read in characters, converting them to real.
+ * Bugs:
+ * Exponent overflow not detected.
+ * Too much requested precision is not detected.
+ */
+ private TOK inreal(Token* t)
+ {
+ //printf("Lexer::inreal()\n");
+ debug
+ {
+ assert(*p == '.' || isdigit(*p));
+ }
+ bool isWellformedString = true;
+ stringbuffer.setsize(0);
+ auto pstart = p;
+ bool hex = false;
+ dchar c = *p++;
+ // Leading '0x'
+ if (c == '0')
+ {
+ c = *p++;
+ if (c == 'x' || c == 'X')
+ {
+ hex = true;
+ c = *p++;
+ }
+ }
+ // Digits to left of '.'
+ while (1)
+ {
+ if (c == '.')
+ {
+ c = *p++;
+ break;
+ }
+ if (isdigit(c) || (hex && isxdigit(c)) || c == '_')
+ {
+ c = *p++;
+ continue;
+ }
+ break;
+ }
+ // Digits to right of '.'
+ while (1)
+ {
+ if (isdigit(c) || (hex && isxdigit(c)) || c == '_')
+ {
+ c = *p++;
+ continue;
+ }
+ break;
+ }
+ if (c == 'e' || c == 'E' || (hex && (c == 'p' || c == 'P')))
+ {
+ c = *p++;
+ if (c == '-' || c == '+')
+ {
+ c = *p++;
+ }
+ bool anyexp = false;
+ while (1)
+ {
+ if (isdigit(c))
+ {
+ anyexp = true;
+ c = *p++;
+ continue;
+ }
+ if (c == '_')
+ {
+ if (Ccompile)
+ error("embedded `_` in numeric literals not allowed");
+ c = *p++;
+ continue;
+ }
+ if (!anyexp)
+ {
+ error("missing exponent");
+ isWellformedString = false;
+ }
+ break;
+ }
+ }
+ else if (hex)
+ {
+ error("exponent required for hex float");
+ isWellformedString = false;
+ }
+ --p;
+ while (pstart < p)
+ {
+ if (*pstart != '_')
+ stringbuffer.writeByte(*pstart);
+ ++pstart;
+ }
+ stringbuffer.writeByte(0);
+ auto sbufptr = cast(const(char)*)stringbuffer[].ptr;
+ TOK result;
+ bool isOutOfRange = false;
+ t.floatvalue = (isWellformedString ? CTFloat.parse(sbufptr, &isOutOfRange) : CTFloat.zero);
+ switch (*p)
+ {
+ case 'F':
+ case 'f':
+ if (isWellformedString && !isOutOfRange)
+ isOutOfRange = Port.isFloat32LiteralOutOfRange(sbufptr);
+ result = TOK.float32Literal;
+ p++;
+ break;
+ default:
+ if (isWellformedString && !isOutOfRange)
+ isOutOfRange = Port.isFloat64LiteralOutOfRange(sbufptr);
+ result = TOK.float64Literal;
+ break;
+ case 'l':
+ if (!Ccompile)
+ error("use 'L' suffix instead of 'l'");
+ goto case 'L';
+ case 'L':
+ ++p;
+ if (Ccompile && long_doublesize == 8)
+ goto default;
+ result = TOK.float80Literal;
+ break;
+ }
+ if ((*p == 'i' || *p == 'I') && !Ccompile)
+ {
+ if (*p == 'I')
+ error("use 'i' suffix instead of 'I'");
+ p++;
+ switch (result)
+ {
+ case TOK.float32Literal:
+ result = TOK.imaginary32Literal;
+ break;
+ case TOK.float64Literal:
+ result = TOK.imaginary64Literal;
+ break;
+ case TOK.float80Literal:
+ result = TOK.imaginary80Literal;
+ break;
+ default:
+ break;
+ }
+ }
+ const isLong = (result == TOK.float80Literal || result == TOK.imaginary80Literal);
+ if (isOutOfRange && !isLong)
+ {
+ const char* suffix = (result == TOK.float32Literal || result == TOK.imaginary32Literal) ? "f" : "";
+ error(scanloc, "number `%s%s` is not representable", sbufptr, suffix);
+ }
+ debug
+ {
+ switch (result)
+ {
+ case TOK.float32Literal:
+ case TOK.float64Literal:
+ case TOK.float80Literal:
+ case TOK.imaginary32Literal:
+ case TOK.imaginary64Literal:
+ case TOK.imaginary80Literal:
+ break;
+ default:
+ assert(0);
+ }
+ }
+ return result;
+ }
+
+ final Loc loc() pure @nogc
+ {
+ scanloc.charnum = cast(uint)(1 + p - line);
+ version (LocOffset)
+ scanloc.fileOffset = cast(uint)(p - base);
+ return scanloc;
+ }
+
+ final void error(const(char)* format, ...)
+ {
+ va_list args;
+ va_start(args, format);
+ .verror(token.loc, format, args);
+ va_end(args);
+ }
+
+ final void error(const ref Loc loc, const(char)* format, ...)
+ {
+ va_list args;
+ va_start(args, format);
+ .verror(loc, format, args);
+ va_end(args);
+ }
+
+ final void deprecation(const(char)* format, ...)
+ {
+ va_list args;
+ va_start(args, format);
+ .vdeprecation(token.loc, format, args);
+ va_end(args);
+ }
+
+ /*********************************************
+ * Parse line/file preprocessor directive:
+ * #line linnum [filespec]
+ * Allow __LINE__ for linnum, and __FILE__ for filespec.
+ * Accept linemarker format:
+ * # linnum [filespec] {flags}
+ * There can be zero or more flags, which are one of the digits 1..4, and
+ * must be in ascending order. The flags are ignored.
+ * Params:
+ * tok = token we're on, which is linnum of linemarker
+ * linemarker = true if line marker format and lexer is on linnum
+ * References:
+ * linemarker https://gcc.gnu.org/onlinedocs/gcc-11.1.0/cpp/Preprocessor-Output.html
+ */
+ private void poundLine(ref Token tok, bool linemarker)
+ {
+ auto linnum = this.scanloc.linnum;
+ const(char)* filespec = null;
+ const loc = this.loc();
+ bool flags;
+
+ if (!linemarker)
+ scan(&tok);
+ if (tok.value == TOK.int32Literal || tok.value == TOK.int64Literal)
+ {
+ const lin = cast(int)(tok.unsvalue - 1);
+ if (lin != tok.unsvalue - 1)
+ error("line number `%lld` out of range", cast(ulong)tok.unsvalue);
+ else
+ linnum = lin;
+ }
+ else if (tok.value == TOK.line) // #line __LINE__
+ {
+ }
+ else
+ goto Lerr;
+ while (1)
+ {
+ switch (*p)
+ {
+ case 0:
+ case 0x1A:
+ case '\n':
+ Lnewline:
+ if (!inTokenStringConstant)
+ {
+ this.scanloc.linnum = linnum;
+ if (filespec)
+ this.scanloc.filename = filespec;
+ }
+ return;
+ case '\r':
+ p++;
+ if (*p != '\n')
+ {
+ p--;
+ goto Lnewline;
+ }
+ continue;
+ case ' ':
+ case '\t':
+ case '\v':
+ case '\f':
+ p++;
+ continue; // skip white space
+ case '_':
+ if (filespec || flags)
+ goto Lerr;
+ if (memcmp(p, "__FILE__".ptr, 8) == 0)
+ {
+ p += 8;
+ filespec = mem.xstrdup(scanloc.filename);
+ continue;
+ }
+ goto Lerr;
+ case '"':
+ if (filespec || flags)
+ goto Lerr;
+ stringbuffer.setsize(0);
+ p++;
+ while (1)
+ {
+ uint c;
+ c = *p;
+ switch (c)
+ {
+ case '\n':
+ case '\r':
+ case 0:
+ case 0x1A:
+ goto Lerr;
+ case '"':
+ stringbuffer.writeByte(0);
+ filespec = mem.xstrdup(cast(const(char)*)stringbuffer[].ptr);
+ p++;
+ break;
+ default:
+ if (c & 0x80)
+ {
+ uint u = decodeUTF();
+ if (u == PS || u == LS)
+ goto Lerr;
+ }
+ stringbuffer.writeByte(c);
+ p++;
+ continue;
+ }
+ break;
+ }
+ continue;
+
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ flags = true; // linemarker flags seen
+ ++p;
+ if ('0' <= *p && *p <= '9')
+ goto Lerr; // only one digit allowed
+ continue;
+
+ default:
+ if (*p & 0x80)
+ {
+ uint u = decodeUTF();
+ if (u == PS || u == LS)
+ goto Lnewline;
+ }
+ goto Lerr;
+ }
+ }
+ Lerr:
+ if (linemarker)
+ error(loc, "# integer [\"filespec\"] { 1 | 2 | 3 | 4 }\\n expected");
+ else
+ error(loc, "#line integer [\"filespec\"]\\n expected");
+ }
+
+ /********************************************
+ * Decode UTF character.
+ * Issue error messages for invalid sequences.
+ * Return decoded character, advance p to last character in UTF sequence.
+ */
+ private uint decodeUTF()
+ {
+ const s = p;
+ assert(*s & 0x80);
+ // Check length of remaining string up to 4 UTF-8 characters
+ size_t len;
+ for (len = 1; len < 4 && s[len]; len++)
+ {
+ }
+ size_t idx = 0;
+ dchar u;
+ const msg = utf_decodeChar(s[0 .. len], idx, u);
+ p += idx - 1;
+ if (msg)
+ {
+ error("%.*s", cast(int)msg.length, msg.ptr);
+ }
+ return u;
+ }
+
+ /***************************************************
+ * Parse doc comment embedded between t.ptr and p.
+ * Remove trailing blanks and tabs from lines.
+ * Replace all newlines with \n.
+ * Remove leading comment character from each line.
+ * Decide if it's a lineComment or a blockComment.
+ * Append to previous one for this token.
+ *
+ * If newParagraph is true, an extra newline will be
+ * added between adjoining doc comments.
+ */
+ private void getDocComment(Token* t, uint lineComment, bool newParagraph) pure
+ {
+ /* ct tells us which kind of comment it is: '/', '*', or '+'
+ */
+ const ct = t.ptr[2];
+ /* Start of comment text skips over / * *, / + +, or / / /
+ */
+ const(char)* q = t.ptr + 3; // start of comment text
+ const(char)* qend = p;
+ if (ct == '*' || ct == '+')
+ qend -= 2;
+ /* Scan over initial row of ****'s or ++++'s or ////'s
+ */
+ for (; q < qend; q++)
+ {
+ if (*q != ct)
+ break;
+ }
+ /* Remove leading spaces until start of the comment
+ */
+ int linestart = 0;
+ if (ct == '/')
+ {
+ while (q < qend && (*q == ' ' || *q == '\t'))
+ ++q;
+ }
+ else if (q < qend)
+ {
+ if (*q == '\r')
+ {
+ ++q;
+ if (q < qend && *q == '\n')
+ ++q;
+ linestart = 1;
+ }
+ else if (*q == '\n')
+ {
+ ++q;
+ linestart = 1;
+ }
+ }
+ /* Remove trailing row of ****'s or ++++'s
+ */
+ if (ct != '/')
+ {
+ for (; q < qend; qend--)
+ {
+ if (qend[-1] != ct)
+ break;
+ }
+ }
+ /* Comment is now [q .. qend].
+ * Canonicalize it into buf[].
+ */
+ OutBuffer buf;
+
+ void trimTrailingWhitespace()
+ {
+ const s = buf[];
+ auto len = s.length;
+ while (len && (s[len - 1] == ' ' || s[len - 1] == '\t'))
+ --len;
+ buf.setsize(len);
+ }
+
+ for (; q < qend; q++)
+ {
+ char c = *q;
+ switch (c)
+ {
+ case '*':
+ case '+':
+ if (linestart && c == ct)
+ {
+ linestart = 0;
+ /* Trim preceding whitespace up to preceding \n
+ */
+ trimTrailingWhitespace();
+ continue;
+ }
+ break;
+ case ' ':
+ case '\t':
+ break;
+ case '\r':
+ if (q[1] == '\n')
+ continue; // skip the \r
+ goto Lnewline;
+ default:
+ if (c == 226)
+ {
+ // If LS or PS
+ if (q[1] == 128 && (q[2] == 168 || q[2] == 169))
+ {
+ q += 2;
+ goto Lnewline;
+ }
+ }
+ linestart = 0;
+ break;
+ Lnewline:
+ c = '\n'; // replace all newlines with \n
+ goto case;
+ case '\n':
+ linestart = 1;
+ /* Trim trailing whitespace
+ */
+ trimTrailingWhitespace();
+ break;
+ }
+ buf.writeByte(c);
+ }
+ /* Trim trailing whitespace (if the last line does not have newline)
+ */
+ trimTrailingWhitespace();
+
+ // Always end with a newline
+ const s = buf[];
+ if (s.length == 0 || s[$ - 1] != '\n')
+ buf.writeByte('\n');
+
+ // It's a line comment if the start of the doc comment comes
+ // after other non-whitespace on the same line.
+ auto dc = (lineComment && anyToken) ? &t.lineComment : &t.blockComment;
+ // Combine with previous doc comment, if any
+ if (*dc)
+ *dc = combineComments(*dc, buf[], newParagraph).toDString();
+ else
+ *dc = buf.extractSlice(true);
+ }
+
+ /********************************************
+ * Combine two document comments into one,
+ * separated by an extra newline if newParagraph is true.
+ */
+ static const(char)* combineComments(const(char)[] c1, const(char)[] c2, bool newParagraph) pure
+ {
+ //printf("Lexer::combineComments('%s', '%s', '%i')\n", c1, c2, newParagraph);
+ const(int) newParagraphSize = newParagraph ? 1 : 0; // Size of the combining '\n'
+ if (!c1)
+ return c2.ptr;
+ if (!c2)
+ return c1.ptr;
+
+ int insertNewLine = 0;
+ if (c1.length && c1[$ - 1] != '\n')
+ insertNewLine = 1;
+ const retSize = c1.length + insertNewLine + newParagraphSize + c2.length;
+ auto p = cast(char*)mem.xmalloc_noscan(retSize + 1);
+ p[0 .. c1.length] = c1[];
+ if (insertNewLine)
+ p[c1.length] = '\n';
+ if (newParagraph)
+ p[c1.length + insertNewLine] = '\n';
+ p[retSize - c2.length .. retSize] = c2[];
+ p[retSize] = 0;
+ return p;
+ }
+
+private:
+ void endOfLine() pure @nogc @safe
+ {
+ scanloc.linnum++;
+ line = p;
+ }
+}
+
+/// Support for `__DATE__`, `__TIME__`, and `__TIMESTAMP__`
+private struct TimeStampInfo
+{
+ private __gshared bool initdone = false;
+
+ // Note: Those properties need to be guarded by a call to `init`
+ // The API isn't safe, and quite brittle, but it was left this way
+ // over performance concerns.
+ // This is currently only called once, from the lexer.
+ __gshared char[11 + 1] date;
+ __gshared char[8 + 1] time;
+ __gshared char[24 + 1] timestamp;
+
+ public static void initialize(const ref Loc loc) nothrow
+ {
+ if (initdone)
+ return;
+
+ initdone = true;
+ time_t ct;
+ // https://issues.dlang.org/show_bug.cgi?id=20444
+ if (auto p = getenv("SOURCE_DATE_EPOCH"))
+ {
+ if (!ct.parseDigits(p.toDString()))
+ error(loc, "Value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p);
+ }
+ else
+ .time(&ct);
+ const p = ctime(&ct);
+ assert(p);
+ sprintf(&date[0], "%.6s %.4s", p + 4, p + 20);
+ sprintf(&time[0], "%.8s", p + 11);
+ sprintf(&timestamp[0], "%.24s", p);
+ }
+}
+
+unittest
+{
+ import dmd.console;
+ nothrow bool assertDiagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header,
+ const(char)* format, va_list ap, const(char)* p1, const(char)* p2)
+ {
+ assert(0);
+ }
+ diagnosticHandler = &assertDiagnosticHandler;
+
+ static void test(T)(string sequence, T expected, bool Ccompile = false)
+ {
+ auto p = cast(const(char)*)sequence.ptr;
+ assert(expected == Lexer.escapeSequence(Loc.initial, p, Ccompile));
+ assert(p == sequence.ptr + sequence.length);
+ }
+
+ test(`'`, '\'');
+ test(`"`, '"');
+ test(`?`, '?');
+ test(`\`, '\\');
+ test(`0`, '\0');
+ test(`a`, '\a');
+ test(`b`, '\b');
+ test(`f`, '\f');
+ test(`n`, '\n');
+ test(`r`, '\r');
+ test(`t`, '\t');
+ test(`v`, '\v');
+
+ test(`x00`, 0x00);
+ test(`xff`, 0xff);
+ test(`xFF`, 0xff);
+ test(`xa7`, 0xa7);
+ test(`x3c`, 0x3c);
+ test(`xe2`, 0xe2);
+
+ test(`1`, '\1');
+ test(`42`, '\42');
+ test(`357`, '\357');
+
+ test(`u1234`, '\u1234');
+ test(`uf0e4`, '\uf0e4');
+
+ test(`U0001f603`, '\U0001f603');
+
+ test(`&quot;`, '"');
+ test(`&lt;`, '<');
+ test(`&gt;`, '>');
+
+ diagnosticHandler = null;
+}
+unittest
+{
+ import dmd.console;
+ string expected;
+ bool gotError;
+
+ nothrow bool expectDiagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header,
+ const(char)* format, va_list ap, const(char)* p1, const(char)* p2)
+ {
+ assert(cast(Classification)headerColor == Classification.error);
+
+ gotError = true;
+ char[100] buffer = void;
+ auto actual = buffer[0 .. vsprintf(buffer.ptr, format, ap)];
+ assert(expected == actual);
+ return true;
+ }
+
+ diagnosticHandler = &expectDiagnosticHandler;
+
+ void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength, bool Ccompile = false)
+ {
+ uint errors = global.errors;
+ gotError = false;
+ expected = expectedError;
+ auto p = cast(const(char)*)sequence.ptr;
+ auto actualReturnValue = Lexer.escapeSequence(Loc.initial, p, Ccompile);
+ assert(gotError);
+ assert(expectedReturnValue == actualReturnValue);
+
+ auto actualScanLength = p - sequence.ptr;
+ assert(expectedScanLength == actualScanLength);
+ global.errors = errors;
+ }
+
+ test("c", `undefined escape sequence \c`, 'c', 1);
+ test("!", `undefined escape sequence \!`, '!', 1);
+ test("&quot;", `undefined escape sequence \&`, '&', 1, true);
+
+ test("x1", `escape hex sequence has 1 hex digits instead of 2`, '\x01', 2);
+
+ test("u1" , `escape hex sequence has 1 hex digits instead of 4`, 0x1, 2);
+ test("u12" , `escape hex sequence has 2 hex digits instead of 4`, 0x12, 3);
+ test("u123", `escape hex sequence has 3 hex digits instead of 4`, 0x123, 4);
+
+ test("U0" , `escape hex sequence has 1 hex digits instead of 8`, 0x0, 2);
+ test("U00" , `escape hex sequence has 2 hex digits instead of 8`, 0x00, 3);
+ test("U000" , `escape hex sequence has 3 hex digits instead of 8`, 0x000, 4);
+ test("U0000" , `escape hex sequence has 4 hex digits instead of 8`, 0x0000, 5);
+ test("U0001f" , `escape hex sequence has 5 hex digits instead of 8`, 0x0001f, 6);
+ test("U0001f6" , `escape hex sequence has 6 hex digits instead of 8`, 0x0001f6, 7);
+ test("U0001f60", `escape hex sequence has 7 hex digits instead of 8`, 0x0001f60, 8);
+
+ test("ud800" , `invalid UTF character \U0000d800`, '?', 5);
+ test("udfff" , `invalid UTF character \U0000dfff`, '?', 5);
+ test("U00110000", `invalid UTF character \U00110000`, '?', 9);
+
+ test("xg0" , `undefined escape hex sequence \xg`, 'g', 2);
+ test("ug000" , `undefined escape hex sequence \ug`, 'g', 2);
+ test("Ug0000000", `undefined escape hex sequence \Ug`, 'g', 2);
+
+ test("&BAD;", `unnamed character entity &BAD;` , '?', 5);
+ test("&quot", `unterminated named entity &quot;`, '?', 5);
+ test("&quot", `unterminated named entity &quot;`, '?', 5);
+
+ test("400", `escape octal sequence \400 is larger than \377`, 0x100, 3);
+
+ diagnosticHandler = null;
+}
diff --git a/gcc/d/dmd/mangle.h b/gcc/d/dmd/mangle.h
index 544f77b..670cf4d 100644
--- a/gcc/d/dmd/mangle.h
+++ b/gcc/d/dmd/mangle.h
@@ -17,16 +17,16 @@ class TemplateInstance;
class Type;
struct OutBuffer;
-// In cppmangle.c
+// In cppmangle.d
const char *toCppMangleItanium(Dsymbol *s);
const char *cppTypeInfoMangleItanium(Dsymbol *s);
const char *cppThunkMangleItanium(FuncDeclaration *fd, int offset);
-// In cppmanglewin.c
+// In cppmanglewin.d
const char *toCppMangleMSVC(Dsymbol *s);
const char *cppTypeInfoMangleMSVC(Dsymbol *s);
-// In dmangle.c
+// In dmangle.d
const char *mangleExact(FuncDeclaration *fd);
void mangleToBuffer(Type *s, OutBuffer *buf);
void mangleToBuffer(Expression *s, OutBuffer *buf);
diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h
index 1664492..969290c 100644
--- a/gcc/d/dmd/module.h
+++ b/gcc/d/dmd/module.h
@@ -10,15 +10,16 @@
#pragma once
-#include "root/root.h"
#include "dsymbol.h"
-class ClassDeclaration;
struct ModuleDeclaration;
-struct Macro;
struct Escape;
-class VarDeclaration;
-class Library;
+struct FileBuffer;
+
+struct MacroTable
+{
+ void* internal; // PIMPL
+};
enum PKG
{
@@ -34,10 +35,9 @@ public:
unsigned tag; // auto incremented tag, used to mask package tree in scopes
Module *mod; // != NULL if isPkgMod == PKGmodule
- Package(Identifier *ident);
const char *kind() const;
- static DsymbolTable *resolve(Identifiers *packages, Dsymbol **pparent, Package **ppkg);
+ bool equals(const RootObject *o) const;
Package *isPackage() { return this; }
@@ -47,7 +47,6 @@ public:
void accept(Visitor *v) { v->visit(this); }
Module *isPackageMod();
- void resolvePKGunknown();
};
class Module : public Package
@@ -60,26 +59,31 @@ public:
static Dsymbols deferred2; // deferred Dsymbol's needing semantic2() run on them
static Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them
static unsigned dprogress; // progress resolving the deferred list
+
static void _init();
static AggregateDeclaration *moduleinfo;
- const char *arg; // original argument name
+ DString arg; // original argument name
ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration
- File *srcfile; // input source file
- File *objfile; // output .obj file
- File *hdrfile; // 'header' file
- File *docfile; // output documentation file
+ FileName srcfile; // input source file
+ FileName objfile; // output .obj file
+ FileName hdrfile; // 'header' file
+ FileName docfile; // output documentation file
+ FileBuffer *srcBuffer; // set during load(), free'd in parse()
unsigned errors; // if any errors in file
unsigned numlines; // number of lines in source file
- int isDocFile; // if it is a documentation input file, not D source
+ bool isHdrFile; // if it is a header (.di) file
+ bool isCFile; // if it is a C (.c) file
+ bool isDocFile; // if it is a documentation input file, not D source
+ bool hasAlwaysInlines; // contains references to functions that must be inlined
bool isPackageFile; // if it is a package.d
Package *pkg; // if isPackageFile is true, the Package that contains this package.d
Strings contentImportedFiles; // array of files whose content was imported
int needmoduleinfo;
-
int selfimports; // 0: don't know, 1: does not, 2: does
+ void* tagSymTab; // ImportC: tag symbols that conflict with other symbols used as the index
bool selfImports(); // returns true if module imports itself
int rootimports; // 0: don't know, 1: does not, 2: does
@@ -101,41 +105,34 @@ public:
unsigned debuglevel; // debug level
Identifiers *debugids; // debug identifiers
- Identifiers *debugidsNot; // forward referenced debug identifiers
+ Identifiers *debugidsNot; // forward referenced debug identifiers
unsigned versionlevel; // version level
Identifiers *versionids; // version identifiers
- Identifiers *versionidsNot; // forward referenced version identifiers
+ Identifiers *versionidsNot; // forward referenced version identifiers
- Macro *macrotable; // document comment macros
+ MacroTable macrotable; // document comment macros
Escape *escapetable; // document comment escapes
size_t nameoffset; // offset of module name from start of ModuleInfo
size_t namelen; // length of module name in characters
- Module(const char *arg, Identifier *ident, int doDocComment, int doHdrGen);
static Module* create(const char *arg, Identifier *ident, int doDocComment, int doHdrGen);
static Module *load(Loc loc, Identifiers *packages, Identifier *ident);
const char *kind() const;
- File *setOutfile(const char *name, const char *dir, const char *arg, const char *ext);
- void setDocfile();
- bool read(Loc loc); // read file, returns 'true' if succeed, 'false' otherwise.
+ bool read(const Loc &loc); // read file, returns 'true' if succeed, 'false' otherwise.
Module *parse(); // syntactic parse
void importAll(Scope *sc);
int needModuleInfo();
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
- bool isPackageAccessible(Package *p, Prot protection, int flags = 0);
+ bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0);
Dsymbol *symtabInsert(Dsymbol *s);
void deleteObjFile();
- static void addDeferredSemantic(Dsymbol *s);
- static void addDeferredSemantic2(Dsymbol *s);
- static void addDeferredSemantic3(Dsymbol *s);
static void runDeferredSemantic();
static void runDeferredSemantic2();
static void runDeferredSemantic3();
- static void clearCache();
int imports(Module *m);
bool isRoot() { return this->importedFrom == this; }
@@ -158,6 +155,8 @@ public:
Symbol *sfilename; // symbol for filename
+ void *ctfe_cov; // stores coverage information from ctfe
+
Module *isModule() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
@@ -167,11 +166,9 @@ struct ModuleDeclaration
{
Loc loc;
Identifier *id;
- Identifiers *packages; // array of Identifier's representing packages
+ DArray<Identifier*> packages; // array of Identifier's representing packages
bool isdeprecated; // if it is a deprecated module
Expression *msg;
- ModuleDeclaration(Loc loc, Identifiers *packages, Identifier *id);
-
- const char *toChars();
+ const char *toChars() const;
};
diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c
deleted file mode 100644
index 6cccf40..0000000
--- a/gcc/d/dmd/mtype.c
+++ /dev/null
@@ -1,8722 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/mtype.c
- */
-
-#include "root/dsystem.h"
-#include "root/checkedint.h"
-#include "root/rmem.h"
-
-#include "mars.h"
-#include "mangle.h"
-#include "dsymbol.h"
-#include "mtype.h"
-#include "scope.h"
-#include "init.h"
-#include "expression.h"
-#include "statement.h"
-#include "attrib.h"
-#include "declaration.h"
-#include "template.h"
-#include "id.h"
-#include "enum.h"
-#include "module.h"
-#include "import.h"
-#include "aggregate.h"
-#include "hdrgen.h"
-#include "target.h"
-
-bool symbolIsVisible(Scope *sc, Dsymbol *s);
-typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param);
-int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL);
-FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
-Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
-Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-Expression *typeToExpression(Type *t);
-Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
-RootObject *compileTypeMixin(TypeMixin *tm, Loc loc, Scope *sc);
-
-/***************************** Type *****************************/
-
-ClassDeclaration *Type::dtypeinfo;
-ClassDeclaration *Type::typeinfoclass;
-ClassDeclaration *Type::typeinfointerface;
-ClassDeclaration *Type::typeinfostruct;
-ClassDeclaration *Type::typeinfopointer;
-ClassDeclaration *Type::typeinfoarray;
-ClassDeclaration *Type::typeinfostaticarray;
-ClassDeclaration *Type::typeinfoassociativearray;
-ClassDeclaration *Type::typeinfovector;
-ClassDeclaration *Type::typeinfoenum;
-ClassDeclaration *Type::typeinfofunction;
-ClassDeclaration *Type::typeinfodelegate;
-ClassDeclaration *Type::typeinfotypelist;
-ClassDeclaration *Type::typeinfoconst;
-ClassDeclaration *Type::typeinfoinvariant;
-ClassDeclaration *Type::typeinfoshared;
-ClassDeclaration *Type::typeinfowild;
-
-TemplateDeclaration *Type::rtinfo;
-
-Type *Type::tvoid;
-Type *Type::tint8;
-Type *Type::tuns8;
-Type *Type::tint16;
-Type *Type::tuns16;
-Type *Type::tint32;
-Type *Type::tuns32;
-Type *Type::tint64;
-Type *Type::tuns64;
-Type *Type::tint128;
-Type *Type::tuns128;
-Type *Type::tfloat32;
-Type *Type::tfloat64;
-Type *Type::tfloat80;
-
-Type *Type::timaginary32;
-Type *Type::timaginary64;
-Type *Type::timaginary80;
-
-Type *Type::tcomplex32;
-Type *Type::tcomplex64;
-Type *Type::tcomplex80;
-
-Type *Type::tbool;
-Type *Type::tchar;
-Type *Type::twchar;
-Type *Type::tdchar;
-
-Type *Type::tshiftcnt;
-Type *Type::terror;
-Type *Type::tnull;
-Type *Type::tnoreturn;
-
-Type *Type::tsize_t;
-Type *Type::tptrdiff_t;
-Type *Type::thash_t;
-
-Type *Type::tvoidptr;
-Type *Type::tstring;
-Type *Type::twstring;
-Type *Type::tdstring;
-Type *Type::basic[TMAX];
-unsigned char Type::sizeTy[TMAX];
-StringTable Type::stringtable;
-
-void initTypeMangle();
-
-Type::Type(TY ty)
-{
- this->ty = ty;
- this->mod = 0;
- this->deco = NULL;
- this->cto = NULL;
- this->ito = NULL;
- this->sto = NULL;
- this->scto = NULL;
- this->wto = NULL;
- this->wcto = NULL;
- this->swto = NULL;
- this->swcto = NULL;
- this->pto = NULL;
- this->rto = NULL;
- this->arrayof = NULL;
- this->vtinfo = NULL;
- this->ctype = NULL;
-}
-
-const char *Type::kind()
-{
- assert(false); // should be overridden
- return NULL;
-}
-
-Type *Type::copy()
-{
- void *pt = mem.xmalloc(sizeTy[ty]);
- Type *t = (Type *)memcpy(pt, (void *)this, sizeTy[ty]);
- return t;
-}
-
-Type *Type::syntaxCopy()
-{
- print();
- fprintf(stderr, "ty = %d\n", ty);
- assert(0);
- return this;
-}
-
-bool Type::equals(RootObject *o)
-{
- Type *t = (Type *)o;
- //printf("Type::equals(%s, %s)\n", toChars(), t->toChars());
- // deco strings are unique
- // and semantic() has been run
- if (this == o || ((t && deco == t->deco) && deco != NULL))
- {
- //printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
- return true;
- }
- //if (deco && t && t->deco) printf("deco = '%s', t->deco = '%s'\n", deco, t->deco);
- return false;
-}
-
-bool Type::equivalent(Type *t)
-{
- return immutableOf()->equals(t->immutableOf());
-}
-
-void Type::_init()
-{
- stringtable._init(14000);
-
- for (size_t i = 0; i < TMAX; i++)
- sizeTy[i] = sizeof(TypeBasic);
- sizeTy[Tsarray] = sizeof(TypeSArray);
- sizeTy[Tarray] = sizeof(TypeDArray);
- sizeTy[Taarray] = sizeof(TypeAArray);
- sizeTy[Tpointer] = sizeof(TypePointer);
- sizeTy[Treference] = sizeof(TypeReference);
- sizeTy[Tfunction] = sizeof(TypeFunction);
- sizeTy[Tdelegate] = sizeof(TypeDelegate);
- sizeTy[Tident] = sizeof(TypeIdentifier);
- sizeTy[Tinstance] = sizeof(TypeInstance);
- sizeTy[Ttypeof] = sizeof(TypeTypeof);
- sizeTy[Tenum] = sizeof(TypeEnum);
- sizeTy[Tstruct] = sizeof(TypeStruct);
- sizeTy[Tclass] = sizeof(TypeClass);
- sizeTy[Ttuple] = sizeof(TypeTuple);
- sizeTy[Tslice] = sizeof(TypeSlice);
- sizeTy[Treturn] = sizeof(TypeReturn);
- sizeTy[Terror] = sizeof(TypeError);
- sizeTy[Tnull] = sizeof(TypeNull);
- sizeTy[Tvector] = sizeof(TypeVector);
- sizeTy[Ttraits] = sizeof(TypeTraits);
- sizeTy[Tmixin] = sizeof(TypeMixin);
- sizeTy[Tnoreturn] = sizeof(TypeNoreturn);
-
- initTypeMangle();
-
- // Set basic types
- static TY basetab[] =
- { Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64,
- Tint128, Tuns128,
- Tfloat32, Tfloat64, Tfloat80,
- Timaginary32, Timaginary64, Timaginary80,
- Tcomplex32, Tcomplex64, Tcomplex80,
- Tbool,
- Tchar, Twchar, Tdchar, Terror };
-
- for (size_t i = 0; basetab[i] != Terror; i++)
- {
- Type *t = new TypeBasic(basetab[i]);
- t = t->merge();
- basic[basetab[i]] = t;
- }
- basic[Terror] = new TypeError();
-
- tnoreturn = new TypeNoreturn();
- tnoreturn->deco = tnoreturn->merge()->deco;
- basic[Tnoreturn] = tnoreturn;
-
- tvoid = basic[Tvoid];
- tint8 = basic[Tint8];
- tuns8 = basic[Tuns8];
- tint16 = basic[Tint16];
- tuns16 = basic[Tuns16];
- tint32 = basic[Tint32];
- tuns32 = basic[Tuns32];
- tint64 = basic[Tint64];
- tuns64 = basic[Tuns64];
- tint128 = basic[Tint128];
- tuns128 = basic[Tuns128];
- tfloat32 = basic[Tfloat32];
- tfloat64 = basic[Tfloat64];
- tfloat80 = basic[Tfloat80];
-
- timaginary32 = basic[Timaginary32];
- timaginary64 = basic[Timaginary64];
- timaginary80 = basic[Timaginary80];
-
- tcomplex32 = basic[Tcomplex32];
- tcomplex64 = basic[Tcomplex64];
- tcomplex80 = basic[Tcomplex80];
-
- tbool = basic[Tbool];
- tchar = basic[Tchar];
- twchar = basic[Twchar];
- tdchar = basic[Tdchar];
-
- tshiftcnt = tint32;
- terror = basic[Terror];
- tnoreturn = basic[Tnoreturn];
- tnull = new TypeNull();
- tnull->deco = tnull->merge()->deco;
-
- tvoidptr = tvoid->pointerTo();
- tstring = tchar->immutableOf()->arrayOf();
- twstring = twchar->immutableOf()->arrayOf();
- tdstring = tdchar->immutableOf()->arrayOf();
-
- const bool isLP64 = global.params.isLP64;
-
- tsize_t = basic[isLP64 ? Tuns64 : Tuns32];
- tptrdiff_t = basic[isLP64 ? Tint64 : Tint32];
- thash_t = tsize_t;
-}
-
-d_uns64 Type::size()
-{
- return size(Loc());
-}
-
-d_uns64 Type::size(Loc loc)
-{
- error(loc, "no size for type %s", toChars());
- return SIZE_INVALID;
-}
-
-unsigned Type::alignsize()
-{
- return (unsigned)size(Loc());
-}
-
-Type *Type::trySemantic(Loc loc, Scope *sc)
-{
- //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
- unsigned errors = global.startGagging();
- Type *t = typeSemantic(this, loc, sc);
- if (global.endGagging(errors) || t->ty == Terror) // if any errors happened
- {
- t = NULL;
- }
- //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
- return t;
-}
-
-/********************************
- * Return a copy of this type with all attributes null-initialized.
- * Useful for creating a type with different modifiers.
- */
-
-Type *Type::nullAttributes()
-{
- unsigned sz = sizeTy[ty];
- void *pt = mem.xmalloc(sz);
- Type *t = (Type *)memcpy(pt, (void *)this, sz);
- t->deco = NULL;
- t->arrayof = NULL;
- t->pto = NULL;
- t->rto = NULL;
- t->cto = NULL;
- t->ito = NULL;
- t->sto = NULL;
- t->scto = NULL;
- t->wto = NULL;
- t->wcto = NULL;
- t->swto = NULL;
- t->swcto = NULL;
- t->vtinfo = NULL;
- t->ctype = NULL;
- if (t->ty == Tstruct) ((TypeStruct *)t)->att = RECfwdref;
- if (t->ty == Tclass) ((TypeClass *)t)->att = RECfwdref;
- return t;
-}
-
-/********************************
- * Convert to 'const'.
- */
-
-Type *Type::constOf()
-{
- //printf("Type::constOf() %p %s\n", this, toChars());
- if (mod == MODconst)
- return this;
- if (cto)
- {
- assert(cto->mod == MODconst);
- return cto;
- }
- Type *t = makeConst();
- t = t->merge();
- t->fixTo(this);
- //printf("-Type::constOf() %p %s\n", t, t->toChars());
- return t;
-}
-
-/********************************
- * Convert to 'immutable'.
- */
-
-Type *Type::immutableOf()
-{
- //printf("Type::immutableOf() %p %s\n", this, toChars());
- if (isImmutable())
- return this;
- if (ito)
- {
- assert(ito->isImmutable());
- return ito;
- }
- Type *t = makeImmutable();
- t = t->merge();
- t->fixTo(this);
- //printf("\t%p\n", t);
- return t;
-}
-
-/********************************
- * Make type mutable.
- */
-
-Type *Type::mutableOf()
-{
- //printf("Type::mutableOf() %p, %s\n", this, toChars());
- Type *t = this;
- if (isImmutable())
- {
- t = ito; // immutable => naked
- assert(!t || (t->isMutable() && !t->isShared()));
- }
- else if (isConst())
- {
- if (isShared())
- {
- if (isWild())
- t = swcto; // shared wild const -> shared
- else
- t = sto; // shared const => shared
- }
- else
- {
- if (isWild())
- t = wcto; // wild const -> naked
- else
- t = cto; // const => naked
- }
- assert(!t || t->isMutable());
- }
- else if (isWild())
- {
- if (isShared())
- t = sto; // shared wild => shared
- else
- t = wto; // wild => naked
- assert(!t || t->isMutable());
- }
- if (!t)
- {
- t = makeMutable();
- t = t->merge();
- t->fixTo(this);
- }
- else
- t = t->merge();
- assert(t->isMutable());
- return t;
-}
-
-Type *Type::sharedOf()
-{
- //printf("Type::sharedOf() %p, %s\n", this, toChars());
- if (mod == MODshared)
- return this;
- if (sto)
- {
- assert(sto->mod == MODshared);
- return sto;
- }
- Type *t = makeShared();
- t = t->merge();
- t->fixTo(this);
- //printf("\t%p\n", t);
- return t;
-}
-
-Type *Type::sharedConstOf()
-{
- //printf("Type::sharedConstOf() %p, %s\n", this, toChars());
- if (mod == (MODshared | MODconst))
- return this;
- if (scto)
- {
- assert(scto->mod == (MODshared | MODconst));
- return scto;
- }
- Type *t = makeSharedConst();
- t = t->merge();
- t->fixTo(this);
- //printf("\t%p\n", t);
- return t;
-}
-
-
-/********************************
- * Make type unshared.
- * 0 => 0
- * const => const
- * immutable => immutable
- * shared => 0
- * shared const => const
- * wild => wild
- * wild const => wild const
- * shared wild => wild
- * shared wild const => wild const
- */
-
-Type *Type::unSharedOf()
-{
- //printf("Type::unSharedOf() %p, %s\n", this, toChars());
- Type *t = this;
-
- if (isShared())
- {
- if (isWild())
- {
- if (isConst())
- t = wcto; // shared wild const => wild const
- else
- t = wto; // shared wild => wild
- }
- else
- {
- if (isConst())
- t = cto; // shared const => const
- else
- t = sto; // shared => naked
- }
- assert(!t || !t->isShared());
- }
-
- if (!t)
- {
- t = this->nullAttributes();
- t->mod = mod & ~MODshared;
- t->ctype = ctype;
- t = t->merge();
-
- t->fixTo(this);
- }
- else
- t = t->merge();
- assert(!t->isShared());
- return t;
-}
-
-/********************************
- * Convert to 'wild'.
- */
-
-Type *Type::wildOf()
-{
- //printf("Type::wildOf() %p %s\n", this, toChars());
- if (mod == MODwild)
- return this;
- if (wto)
- {
- assert(wto->mod == MODwild);
- return wto;
- }
- Type *t = makeWild();
- t = t->merge();
- t->fixTo(this);
- //printf("\t%p %s\n", t, t->toChars());
- return t;
-}
-
-Type *Type::wildConstOf()
-{
- //printf("Type::wildConstOf() %p %s\n", this, toChars());
- if (mod == MODwildconst)
- return this;
- if (wcto)
- {
- assert(wcto->mod == MODwildconst);
- return wcto;
- }
- Type *t = makeWildConst();
- t = t->merge();
- t->fixTo(this);
- //printf("\t%p %s\n", t, t->toChars());
- return t;
-}
-
-Type *Type::sharedWildOf()
-{
- //printf("Type::sharedWildOf() %p, %s\n", this, toChars());
- if (mod == (MODshared | MODwild))
- return this;
- if (swto)
- {
- assert(swto->mod == (MODshared | MODwild));
- return swto;
- }
- Type *t = makeSharedWild();
- t = t->merge();
- t->fixTo(this);
- //printf("\t%p %s\n", t, t->toChars());
- return t;
-}
-
-Type *Type::sharedWildConstOf()
-{
- //printf("Type::sharedWildConstOf() %p, %s\n", this, toChars());
- if (mod == (MODshared | MODwildconst))
- return this;
- if (swcto)
- {
- assert(swcto->mod == (MODshared | MODwildconst));
- return swcto;
- }
- Type *t = makeSharedWildConst();
- t = t->merge();
- t->fixTo(this);
- //printf("\t%p %s\n", t, t->toChars());
- return t;
-}
-
-/**********************************
- * For our new type 'this', which is type-constructed from t,
- * fill in the cto, ito, sto, scto, wto shortcuts.
- */
-
-void Type::fixTo(Type *t)
-{
- // If fixing this: immutable(T*) by t: immutable(T)*,
- // cache t to this->xto won't break transitivity.
- Type *mto = NULL;
- Type *tn = nextOf();
- if (!tn || (ty != Tsarray && tn->mod == t->nextOf()->mod))
- {
- switch (t->mod)
- {
- case 0: mto = t; break;
- case MODconst: cto = t; break;
- case MODwild: wto = t; break;
- case MODwildconst: wcto = t; break;
- case MODshared: sto = t; break;
- case MODshared | MODconst: scto = t; break;
- case MODshared | MODwild: swto = t; break;
- case MODshared | MODwildconst: swcto = t; break;
- case MODimmutable: ito = t; break;
- }
- }
-
- assert(mod != t->mod);
-#define X(m, n) (((m) << 4) | (n))
- switch (mod)
- {
- case 0:
- break;
-
- case MODconst:
- cto = mto;
- t->cto = this;
- break;
-
- case MODwild:
- wto = mto;
- t->wto = this;
- break;
-
- case MODwildconst:
- wcto = mto;
- t->wcto = this;
- break;
-
- case MODshared:
- sto = mto;
- t->sto = this;
- break;
-
- case MODshared | MODconst:
- scto = mto;
- t->scto = this;
- break;
-
- case MODshared | MODwild:
- swto = mto;
- t->swto = this;
- break;
-
- case MODshared | MODwildconst:
- swcto = mto;
- t->swcto = this;
- break;
-
- case MODimmutable:
- t->ito = this;
- if (t-> cto) t-> cto->ito = this;
- if (t-> sto) t-> sto->ito = this;
- if (t-> scto) t-> scto->ito = this;
- if (t-> wto) t-> wto->ito = this;
- if (t-> wcto) t-> wcto->ito = this;
- if (t-> swto) t-> swto->ito = this;
- if (t->swcto) t->swcto->ito = this;
- break;
-
- default:
- assert(0);
- }
-#undef X
-
- check();
- t->check();
- //printf("fixTo: %s, %s\n", toChars(), t->toChars());
-}
-
-/***************************
- * Look for bugs in constructing types.
- */
-
-void Type::check()
-{
- switch (mod)
- {
- case 0:
- if (cto) assert(cto->mod == MODconst);
- if (ito) assert(ito->mod == MODimmutable);
- if (sto) assert(sto->mod == MODshared);
- if (scto) assert(scto->mod == (MODshared | MODconst));
- if (wto) assert(wto->mod == MODwild);
- if (wcto) assert(wcto->mod == MODwildconst);
- if (swto) assert(swto->mod == (MODshared | MODwild));
- if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
- break;
-
- case MODconst:
- if (cto) assert(cto->mod == 0);
- if (ito) assert(ito->mod == MODimmutable);
- if (sto) assert(sto->mod == MODshared);
- if (scto) assert(scto->mod == (MODshared | MODconst));
- if (wto) assert(wto->mod == MODwild);
- if (wcto) assert(wcto->mod == MODwildconst);
- if (swto) assert(swto->mod == (MODshared | MODwild));
- if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
- break;
-
- case MODwild:
- if (cto) assert(cto->mod == MODconst);
- if (ito) assert(ito->mod == MODimmutable);
- if (sto) assert(sto->mod == MODshared);
- if (scto) assert(scto->mod == (MODshared | MODconst));
- if (wto) assert(wto->mod == 0);
- if (wcto) assert(wcto->mod == MODwildconst);
- if (swto) assert(swto->mod == (MODshared | MODwild));
- if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
- break;
-
- case MODwildconst:
- assert(! cto || cto->mod == MODconst);
- assert(! ito || ito->mod == MODimmutable);
- assert(! sto || sto->mod == MODshared);
- assert(! scto || scto->mod == (MODshared | MODconst));
- assert(! wto || wto->mod == MODwild);
- assert(! wcto || wcto->mod == 0);
- assert(! swto || swto->mod == (MODshared | MODwild));
- assert(!swcto || swcto->mod == (MODshared | MODwildconst));
- break;
-
- case MODshared:
- if (cto) assert(cto->mod == MODconst);
- if (ito) assert(ito->mod == MODimmutable);
- if (sto) assert(sto->mod == 0);
- if (scto) assert(scto->mod == (MODshared | MODconst));
- if (wto) assert(wto->mod == MODwild);
- if (wcto) assert(wcto->mod == MODwildconst);
- if (swto) assert(swto->mod == (MODshared | MODwild));
- if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
- break;
-
- case MODshared | MODconst:
- if (cto) assert(cto->mod == MODconst);
- if (ito) assert(ito->mod == MODimmutable);
- if (sto) assert(sto->mod == MODshared);
- if (scto) assert(scto->mod == 0);
- if (wto) assert(wto->mod == MODwild);
- if (wcto) assert(wcto->mod == MODwildconst);
- if (swto) assert(swto->mod == (MODshared | MODwild));
- if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
- break;
-
- case MODshared | MODwild:
- if (cto) assert(cto->mod == MODconst);
- if (ito) assert(ito->mod == MODimmutable);
- if (sto) assert(sto->mod == MODshared);
- if (scto) assert(scto->mod == (MODshared | MODconst));
- if (wto) assert(wto->mod == MODwild);
- if (wcto) assert(wcto->mod == MODwildconst);
- if (swto) assert(swto->mod == 0);
- if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
- break;
-
- case MODshared | MODwildconst:
- assert(! cto || cto->mod == MODconst);
- assert(! ito || ito->mod == MODimmutable);
- assert(! sto || sto->mod == MODshared);
- assert(! scto || scto->mod == (MODshared | MODconst));
- assert(! wto || wto->mod == MODwild);
- assert(! wcto || wcto->mod == MODwildconst);
- assert(! swto || swto->mod == (MODshared | MODwild));
- assert(!swcto || swcto->mod == 0);
- break;
-
- case MODimmutable:
- if (cto) assert(cto->mod == MODconst);
- if (ito) assert(ito->mod == 0);
- if (sto) assert(sto->mod == MODshared);
- if (scto) assert(scto->mod == (MODshared | MODconst));
- if (wto) assert(wto->mod == MODwild);
- if (wcto) assert(wcto->mod == MODwildconst);
- if (swto) assert(swto->mod == (MODshared | MODwild));
- if (swcto) assert(swcto->mod == (MODshared | MODwildconst));
- break;
-
- default:
- assert(0);
- }
-
- Type *tn = nextOf();
- if (tn && ty != Tfunction && tn->ty != Tfunction && ty != Tenum)
- {
- // Verify transitivity
- switch (mod)
- {
- case 0:
- case MODconst:
- case MODwild:
- case MODwildconst:
- case MODshared:
- case MODshared | MODconst:
- case MODshared | MODwild:
- case MODshared | MODwildconst:
- case MODimmutable:
- assert(tn->mod == MODimmutable || (tn->mod & mod) == mod);
- break;
-
- default:
- assert(0);
- }
- tn->check();
- }
-}
-
-Type *Type::makeConst()
-{
- //printf("Type::makeConst() %p, %s\n", this, toChars());
- if (cto) return cto;
- Type *t = this->nullAttributes();
- t->mod = MODconst;
- //printf("-Type::makeConst() %p, %s\n", t, toChars());
- return t;
-}
-
-Type *Type::makeImmutable()
-{
- if (ito) return ito;
- Type *t = this->nullAttributes();
- t->mod = MODimmutable;
- return t;
-}
-
-Type *Type::makeShared()
-{
- if (sto) return sto;
- Type *t = this->nullAttributes();
- t->mod = MODshared;
- return t;
-}
-
-Type *Type::makeSharedConst()
-{
- if (scto) return scto;
- Type *t = this->nullAttributes();
- t->mod = MODshared | MODconst;
- return t;
-}
-
-Type *Type::makeWild()
-{
- if (wto) return wto;
- Type *t = this->nullAttributes();
- t->mod = MODwild;
- return t;
-}
-
-Type *Type::makeWildConst()
-{
- if (wcto) return wcto;
- Type *t = this->nullAttributes();
- t->mod = MODwildconst;
- return t;
-}
-
-Type *Type::makeSharedWild()
-{
- if (swto) return swto;
- Type *t = this->nullAttributes();
- t->mod = MODshared | MODwild;
- return t;
-}
-
-Type *Type::makeSharedWildConst()
-{
- if (swcto) return swcto;
- Type *t = this->nullAttributes();
- t->mod = MODshared | MODwildconst;
- return t;
-}
-
-Type *Type::makeMutable()
-{
- Type *t = this->nullAttributes();
- t->mod = mod & MODshared;
- return t;
-}
-
-/*************************************
- * Apply STCxxxx bits to existing type.
- * Use *before* semantic analysis is run.
- */
-
-Type *Type::addSTC(StorageClass stc)
-{
- Type *t = this;
- if (t->isImmutable())
- ;
- else if (stc & STCimmutable)
- {
- t = t->makeImmutable();
- }
- else
- {
- if ((stc & STCshared) && !t->isShared())
- {
- if (t->isWild())
- {
- if (t->isConst())
- t = t->makeSharedWildConst();
- else
- t = t->makeSharedWild();
- }
- else
- {
- if (t->isConst())
- t = t->makeSharedConst();
- else
- t = t->makeShared();
- }
- }
- if ((stc & STCconst) && !t->isConst())
- {
- if (t->isShared())
- {
- if (t->isWild())
- t = t->makeSharedWildConst();
- else
- t = t->makeSharedConst();
- }
- else
- {
- if (t->isWild())
- t = t->makeWildConst();
- else
- t = t->makeConst();
- }
- }
- if ((stc & STCwild) && !t->isWild())
- {
- if (t->isShared())
- {
- if (t->isConst())
- t = t->makeSharedWildConst();
- else
- t = t->makeSharedWild();
- }
- else
- {
- if (t->isConst())
- t = t->makeWildConst();
- else
- t = t->makeWild();
- }
- }
- }
- return t;
-}
-
-/************************************
- * Convert MODxxxx to STCxxx
- */
-
-StorageClass ModToStc(unsigned mod)
-{
- StorageClass stc = 0;
- if (mod & MODimmutable) stc |= STCimmutable;
- if (mod & MODconst) stc |= STCconst;
- if (mod & MODwild) stc |= STCwild;
- if (mod & MODshared) stc |= STCshared;
- return stc;
-}
-
-/************************************
- * Apply MODxxxx bits to existing type.
- */
-
-Type *Type::castMod(MOD mod)
-{ Type *t;
-
- switch (mod)
- {
- case 0:
- t = unSharedOf()->mutableOf();
- break;
-
- case MODconst:
- t = unSharedOf()->constOf();
- break;
-
- case MODwild:
- t = unSharedOf()->wildOf();
- break;
-
- case MODwildconst:
- t = unSharedOf()->wildConstOf();
- break;
-
- case MODshared:
- t = mutableOf()->sharedOf();
- break;
-
- case MODshared | MODconst:
- t = sharedConstOf();
- break;
-
- case MODshared | MODwild:
- t = sharedWildOf();
- break;
-
- case MODshared | MODwildconst:
- t = sharedWildConstOf();
- break;
-
- case MODimmutable:
- t = immutableOf();
- break;
-
- default:
- assert(0);
- }
- return t;
-}
-
-/************************************
- * Add MODxxxx bits to existing type.
- * We're adding, not replacing, so adding const to
- * a shared type => "shared const"
- */
-
-Type *Type::addMod(MOD mod)
-{
- /* Add anything to immutable, and it remains immutable
- */
- Type *t = this;
- if (!t->isImmutable())
- {
- //printf("addMod(%x) %s\n", mod, toChars());
- switch (mod)
- {
- case 0:
- break;
-
- case MODconst:
- if (isShared())
- {
- if (isWild())
- t = sharedWildConstOf();
- else
- t = sharedConstOf();
- }
- else
- {
- if (isWild())
- t = wildConstOf();
- else
- t = constOf();
- }
- break;
-
- case MODwild:
- if (isShared())
- {
- if (isConst())
- t = sharedWildConstOf();
- else
- t = sharedWildOf();
- }
- else
- {
- if (isConst())
- t = wildConstOf();
- else
- t = wildOf();
- }
- break;
-
- case MODwildconst:
- if (isShared())
- t = sharedWildConstOf();
- else
- t = wildConstOf();
- break;
-
- case MODshared:
- if (isWild())
- {
- if (isConst())
- t = sharedWildConstOf();
- else
- t = sharedWildOf();
- }
- else
- {
- if (isConst())
- t = sharedConstOf();
- else
- t = sharedOf();
- }
- break;
-
- case MODshared | MODconst:
- if (isWild())
- t = sharedWildConstOf();
- else
- t = sharedConstOf();
- break;
-
- case MODshared | MODwild:
- if (isConst())
- t = sharedWildConstOf();
- else
- t = sharedWildOf();
- break;
-
- case MODshared | MODwildconst:
- t = sharedWildConstOf();
- break;
-
- case MODimmutable:
- t = immutableOf();
- break;
-
- default:
- assert(0);
- }
- }
- return t;
-}
-
-/************************************
- * Add storage class modifiers to type.
- */
-
-Type *Type::addStorageClass(StorageClass stc)
-{
- /* Just translate to MOD bits and let addMod() do the work
- */
- MOD mod = 0;
-
- if (stc & STCimmutable)
- mod = MODimmutable;
- else
- {
- if (stc & (STCconst | STCin))
- mod |= MODconst;
- if (stc & STCwild)
- mod |= MODwild;
- if (stc & STCshared)
- mod |= MODshared;
- }
- return addMod(mod);
-}
-
-Type *Type::pointerTo()
-{
- if (ty == Terror)
- return this;
- if (!pto)
- {
- Type *t = new TypePointer(this);
- if (ty == Tfunction)
- {
- t->deco = t->merge()->deco;
- pto = t;
- }
- else
- pto = t->merge();
- }
- return pto;
-}
-
-Type *Type::referenceTo()
-{
- if (ty == Terror)
- return this;
- if (!rto)
- {
- Type *t = new TypeReference(this);
- rto = t->merge();
- }
- return rto;
-}
-
-Type *Type::arrayOf()
-{
- if (ty == Terror)
- return this;
- if (!arrayof)
- {
- Type *t = new TypeDArray(this);
- arrayof = t->merge();
- }
- return arrayof;
-}
-
-// Make corresponding static array type without semantic
-Type *Type::sarrayOf(dinteger_t dim)
-{
- assert(deco);
- Type *t = new TypeSArray(this, new IntegerExp(Loc(), dim, Type::tsize_t));
-
- // according to TypeSArray::semantic()
- t = t->addMod(mod);
- t = t->merge();
-
- return t;
-}
-
-Type *Type::aliasthisOf()
-{
- AggregateDeclaration *ad = isAggregate(this);
- if (ad && ad->aliasthis)
- {
- Dsymbol *s = ad->aliasthis;
- if (s->isAliasDeclaration())
- s = s->toAlias();
- Declaration *d = s->isDeclaration();
- if (d && !d->isTupleDeclaration())
- {
- assert(d->type);
- Type *t = d->type;
- if (d->isVarDeclaration() && d->needThis())
- {
- t = t->addMod(this->mod);
- }
- else if (d->isFuncDeclaration())
- {
- FuncDeclaration *fd = resolveFuncCall(Loc(), NULL, d, NULL, this, NULL, 1);
- if (fd && fd->errors)
- return Type::terror;
- if (fd && !fd->type->nextOf() && !fd->functionSemantic())
- fd = NULL;
- if (fd)
- {
- t = fd->type->nextOf();
- if (!t) // issue 14185
- return Type::terror;
- t = t->substWildTo(mod == 0 ? MODmutable : (MODFlags)mod);
- }
- else
- return Type::terror;
- }
- return t;
- }
- EnumDeclaration *ed = s->isEnumDeclaration();
- if (ed)
- {
- Type *t = ed->type;
- return t;
- }
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (td)
- {
- assert(td->_scope);
- FuncDeclaration *fd = resolveFuncCall(Loc(), NULL, td, NULL, this, NULL, 1);
- if (fd && fd->errors)
- return Type::terror;
- if (fd && fd->functionSemantic())
- {
- Type *t = fd->type->nextOf();
- t = t->substWildTo(mod == 0 ? MODmutable : (MODFlags)mod);
- return t;
- }
- else
- return Type::terror;
- }
- //printf("%s\n", s->kind());
- }
- return NULL;
-}
-
-bool Type::checkAliasThisRec()
-{
- Type *tb = toBasetype();
- AliasThisRec* pflag;
- if (tb->ty == Tstruct)
- pflag = &((TypeStruct *)tb)->att;
- else if (tb->ty == Tclass)
- pflag = &((TypeClass *)tb)->att;
- else
- return false;
-
- AliasThisRec flag = (AliasThisRec)(*pflag & RECtypeMask);
- if (flag == RECfwdref)
- {
- Type *att = aliasthisOf();
- flag = att && att->implicitConvTo(this) ? RECyes : RECno;
- }
- *pflag = (AliasThisRec)(flag | (*pflag & ~RECtypeMask));
- return flag == RECyes;
-}
-
-Dsymbol *Type::toDsymbol(Scope *)
-{
- return NULL;
-}
-
-/*******************************
- * If this is a shell around another type,
- * get that other type.
- */
-
-Type *Type::toBasetype()
-{
- return this;
-}
-
-/***************************
- * Return !=0 if modfrom can be implicitly converted to modto
- */
-bool MODimplicitConv(MOD modfrom, MOD modto)
-{
- if (modfrom == modto)
- return true;
-
- //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto);
- #define X(m, n) (((m) << 4) | (n))
- switch (X(modfrom & ~MODshared, modto & ~MODshared))
- {
- case X(0, MODconst):
- case X(MODwild, MODconst):
- case X(MODwild, MODwildconst):
- case X(MODwildconst, MODconst):
- return (modfrom & MODshared) == (modto & MODshared);
-
- case X(MODimmutable, MODconst):
- case X(MODimmutable, MODwildconst):
- return true;
-
- default:
- return false;
- }
- #undef X
-}
-
-/***************************
- * Return MATCHexact or MATCHconst if a method of type '() modfrom' can call a method of type '() modto'.
- */
-MATCH MODmethodConv(MOD modfrom, MOD modto)
-{
- if (modfrom == modto)
- return MATCHexact;
- if (MODimplicitConv(modfrom, modto))
- return MATCHconst;
-
- #define X(m, n) (((m) << 4) | (n))
- switch (X(modfrom, modto))
- {
- case X(0, MODwild):
- case X(MODimmutable, MODwild):
- case X(MODconst, MODwild):
- case X(MODwildconst, MODwild):
- case X(MODshared, MODshared|MODwild):
- case X(MODshared|MODimmutable, MODshared|MODwild):
- case X(MODshared|MODconst, MODshared|MODwild):
- case X(MODshared|MODwildconst, MODshared|MODwild):
- return MATCHconst;
-
- default:
- return MATCHnomatch;
- }
- #undef X
-}
-
-/***************************
- * Merge mod bits to form common mod.
- */
-MOD MODmerge(MOD mod1, MOD mod2)
-{
- if (mod1 == mod2)
- return mod1;
-
- //printf("MODmerge(1 = %x, 2 = %x)\n", mod1, mod2);
- MOD result = 0;
- if ((mod1 | mod2) & MODshared)
- {
- // If either type is shared, the result will be shared
- result |= MODshared;
- mod1 &= ~MODshared;
- mod2 &= ~MODshared;
- }
- if (mod1 == 0 || mod1 == MODmutable || mod1 == MODconst ||
- mod2 == 0 || mod2 == MODmutable || mod2 == MODconst)
- {
- // If either type is mutable or const, the result will be const.
- result |= MODconst;
- }
- else
- {
- // MODimmutable vs MODwild
- // MODimmutable vs MODwildconst
- // MODwild vs MODwildconst
- assert(mod1 & MODwild || mod2 & MODwild);
- result |= MODwildconst;
- }
- return result;
-}
-
-/*********************************
- * Store modifier name into buf.
- */
-void MODtoBuffer(OutBuffer *buf, MOD mod)
-{
- switch (mod)
- {
- case 0:
- break;
-
- case MODimmutable:
- buf->writestring(Token::tochars[TOKimmutable]);
- break;
-
- case MODshared:
- buf->writestring(Token::tochars[TOKshared]);
- break;
-
- case MODshared | MODconst:
- buf->writestring(Token::tochars[TOKshared]);
- buf->writeByte(' ');
- /* fall through */
- case MODconst:
- buf->writestring(Token::tochars[TOKconst]);
- break;
-
- case MODshared | MODwild:
- buf->writestring(Token::tochars[TOKshared]);
- buf->writeByte(' ');
- /* fall through */
- case MODwild:
- buf->writestring(Token::tochars[TOKwild]);
- break;
-
- case MODshared | MODwildconst:
- buf->writestring(Token::tochars[TOKshared]);
- buf->writeByte(' ');
- /* fall through */
- case MODwildconst:
- buf->writestring(Token::tochars[TOKwild]);
- buf->writeByte(' ');
- buf->writestring(Token::tochars[TOKconst]);
- break;
-
- default:
- assert(0);
- }
-}
-
-
-/*********************************
- * Return modifier name.
- */
-char *MODtoChars(MOD mod)
-{
- OutBuffer buf;
- buf.reserve(16);
- MODtoBuffer(&buf, mod);
- return buf.extractChars();
-}
-
-/********************************
- * For pretty-printing a type.
- */
-
-const char *Type::toChars()
-{
- OutBuffer buf;
- buf.reserve(16);
- HdrGenState hgs;
- hgs.fullQual = (ty == Tclass && !mod);
-
- ::toCBuffer(this, &buf, NULL, &hgs);
- return buf.extractChars();
-}
-
-char *Type::toPrettyChars(bool QualifyTypes)
-{
- OutBuffer buf;
- buf.reserve(16);
- HdrGenState hgs;
- hgs.fullQual = QualifyTypes;
-
- ::toCBuffer(this, &buf, NULL, &hgs);
- return buf.extractChars();
-}
-
-/*********************************
- * Store this type's modifier name into buf.
- */
-void Type::modToBuffer(OutBuffer *buf)
-{
- if (mod)
- {
- buf->writeByte(' ');
- MODtoBuffer(buf, mod);
- }
-}
-
-/*********************************
- * Return this type's modifier name.
- */
-char *Type::modToChars()
-{
- OutBuffer buf;
- buf.reserve(16);
- modToBuffer(&buf);
- return buf.extractChars();
-}
-
-/** For each active modifier (MODconst, MODimmutable, etc) call fp with a
-void* for the work param and a string representation of the attribute. */
-int Type::modifiersApply(void *param, int (*fp)(void *, const char *))
-{
- static unsigned char modsArr[] = { MODconst, MODimmutable, MODwild, MODshared };
-
- for (size_t idx = 0; idx < 4; ++idx)
- {
- if (mod & modsArr[idx])
- {
- if (int res = fp(param, MODtoChars(modsArr[idx])))
- return res;
- }
- }
- return 0;
-}
-
-/************************************
- * Strip all parameter's idenfiers and their default arguments for merging types.
- * If some of parameter types or return type are function pointer, delegate, or
- * the types which contains either, then strip also from them.
- */
-
-Type *stripDefaultArgs(Type *t)
-{
- struct N
- {
- static Parameters *stripParams(Parameters *parameters)
- {
- Parameters *params = parameters;
- if (params && params->length > 0)
- {
- for (size_t i = 0; i < params->length; i++)
- {
- Parameter *p = (*params)[i];
- Type *ta = stripDefaultArgs(p->type);
- if (ta != p->type || p->defaultArg || p->ident || p->userAttribDecl)
- {
- if (params == parameters)
- {
- params = new Parameters();
- params->setDim(parameters->length);
- for (size_t j = 0; j < params->length; j++)
- (*params)[j] = (*parameters)[j];
- }
- (*params)[i] = new Parameter(p->storageClass, ta, NULL, NULL, NULL);
- }
- }
- }
- return params;
- }
- };
-
- if (t == NULL)
- return t;
-
- if (t->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)t;
- Type *tret = stripDefaultArgs(tf->next);
- Parameters *params = N::stripParams(tf->parameterList.parameters);
- if (tret == tf->next && params == tf->parameterList.parameters)
- goto Lnot;
- tf = (TypeFunction *)tf->copy();
- tf->parameterList.parameters = params;
- tf->next = tret;
- //printf("strip %s\n <- %s\n", tf->toChars(), t->toChars());
- t = tf;
- }
- else if (t->ty == Ttuple)
- {
- TypeTuple *tt = (TypeTuple *)t;
- Parameters *args = N::stripParams(tt->arguments);
- if (args == tt->arguments)
- goto Lnot;
- t = t->copy();
- ((TypeTuple *)t)->arguments = args;
- }
- else if (t->ty == Tenum)
- {
- // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
- goto Lnot;
- }
- else
- {
- Type *tn = t->nextOf();
- Type *n = stripDefaultArgs(tn);
- if (n == tn)
- goto Lnot;
- t = t->copy();
- ((TypeNext *)t)->next = n;
- }
- //printf("strip %s\n", t->toChars());
-Lnot:
- return t;
-}
-
-/************************************
- */
-
-Type *Type::merge()
-{
- if (ty == Terror) return this;
- if (ty == Ttypeof) return this;
- if (ty == Tident) return this;
- if (ty == Tinstance) return this;
- if (ty == Taarray && !((TypeAArray *)this)->index->merge()->deco)
- return this;
- if (ty != Tenum && nextOf() && !nextOf()->deco)
- return this;
-
- //printf("merge(%s)\n", toChars());
- Type *t = this;
- assert(t);
- if (!deco)
- {
- OutBuffer buf;
- buf.reserve(32);
-
- mangleToBuffer(this, &buf);
-
- StringValue *sv = stringtable.update((char *)buf.slice().ptr, buf.length());
- if (sv->ptrvalue)
- {
- t = (Type *) sv->ptrvalue;
- assert(t->deco);
- //printf("old value, deco = '%s' %p\n", t->deco, t->deco);
- }
- else
- {
- sv->ptrvalue = (char *)(t = stripDefaultArgs(t));
- deco = t->deco = const_cast<char *>(sv->toDchars());
- //printf("new value, deco = '%s' %p\n", t->deco, t->deco);
- }
- }
- return t;
-}
-
-/*************************************
- * This version does a merge even if the deco is already computed.
- * Necessary for types that have a deco, but are not merged.
- */
-Type *Type::merge2()
-{
- //printf("merge2(%s)\n", toChars());
- Type *t = this;
- assert(t);
- if (!t->deco)
- return t->merge();
-
- StringValue *sv = stringtable.lookup((char *)t->deco, strlen(t->deco));
- if (sv && sv->ptrvalue)
- { t = (Type *) sv->ptrvalue;
- assert(t->deco);
- }
- else
- assert(0);
- return t;
-}
-
-bool Type::isintegral()
-{
- return false;
-}
-
-bool Type::isfloating()
-{
- return false;
-}
-
-bool Type::isreal()
-{
- return false;
-}
-
-bool Type::isimaginary()
-{
- return false;
-}
-
-bool Type::iscomplex()
-{
- return false;
-}
-
-bool Type::isscalar()
-{
- return false;
-}
-
-bool Type::isunsigned()
-{
- return false;
-}
-
-ClassDeclaration *Type::isClassHandle()
-{
- return NULL;
-}
-
-bool Type::isscope()
-{
- return false;
-}
-
-bool Type::isString()
-{
- return false;
-}
-
-/**************************
- * When T is mutable,
- * Given:
- * T a, b;
- * Can we bitwise assign:
- * a = b;
- * ?
- */
-bool Type::isAssignable()
-{
- return true;
-}
-
-/**************************
- * Returns true if T can be converted to boolean value.
- */
-bool Type::isBoolean()
-{
- return isscalar();
-}
-
-/********************************
- * true if when type goes out of scope, it needs a destructor applied.
- * Only applies to value types, not ref types.
- */
-bool Type::needsDestruction()
-{
- return false;
-}
-
-/*********************************
- *
- */
-
-bool Type::needsNested()
-{
- return false;
-}
-
-/*********************************
- * Check type to see if it is based on a deprecated symbol.
- */
-
-void Type::checkDeprecated(Loc loc, Scope *sc)
-{
- if (Dsymbol *s = toDsymbol(sc))
- {
- s->checkDeprecated(loc, sc);
- }
-}
-
-
-Expression *Type::defaultInit(Loc)
-{
- return NULL;
-}
-
-/***************************************
- * Use when we prefer the default initializer to be a literal,
- * rather than a global immutable variable.
- */
-Expression *Type::defaultInitLiteral(Loc loc)
-{
- return defaultInit(loc);
-}
-
-bool Type::isZeroInit(Loc)
-{
- return false; // assume not
-}
-
-bool Type::isBaseOf(Type *, int *)
-{
- return 0; // assume not
-}
-
-/********************************
- * Determine if 'this' can be implicitly converted
- * to type 'to'.
- * Returns:
- * MATCHnomatch, MATCHconvert, MATCHconst, MATCHexact
- */
-
-MATCH Type::implicitConvTo(Type *to)
-{
- //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
- //printf("from: %s\n", toChars());
- //printf("to : %s\n", to->toChars());
- if (this->equals(to))
- return MATCHexact;
- return MATCHnomatch;
-}
-
-/*******************************
- * Determine if converting 'this' to 'to' is an identity operation,
- * a conversion to const operation, or the types aren't the same.
- * Returns:
- * MATCHexact 'this' == 'to'
- * MATCHconst 'to' is const
- * MATCHnomatch conversion to mutable or invariant
- */
-
-MATCH Type::constConv(Type *to)
-{
- //printf("Type::constConv(this = %s, to = %s)\n", toChars(), to->toChars());
- if (equals(to))
- return MATCHexact;
- if (ty == to->ty && MODimplicitConv(mod, to->mod))
- return MATCHconst;
- return MATCHnomatch;
-}
-
-/***************************************
- * Return MOD bits matching this type to wild parameter type (tprm).
- */
-
-unsigned char Type::deduceWild(Type *t, bool)
-{
- //printf("Type::deduceWild this = '%s', tprm = '%s'\n", toChars(), tprm->toChars());
-
- if (t->isWild())
- {
- if (isImmutable())
- return MODimmutable;
- else if (isWildConst())
- {
- if (t->isWildConst())
- return MODwild;
- else
- return MODwildconst;
- }
- else if (isWild())
- return MODwild;
- else if (isConst())
- return MODconst;
- else if (isMutable())
- return MODmutable;
- else
- assert(0);
- }
- return 0;
-}
-
-Type *Type::unqualify(unsigned m)
-{
- Type *t = mutableOf()->unSharedOf();
-
- Type *tn = ty == Tenum ? NULL : nextOf();
- if (tn && tn->ty != Tfunction)
- {
- Type *utn = tn->unqualify(m);
- if (utn != tn)
- {
- if (ty == Tpointer)
- t = utn->pointerTo();
- else if (ty == Tarray)
- t = utn->arrayOf();
- else if (ty == Tsarray)
- t = new TypeSArray(utn, ((TypeSArray *)this)->dim);
- else if (ty == Taarray)
- {
- t = new TypeAArray(utn, ((TypeAArray *)this)->index);
- ((TypeAArray *)t)->sc = ((TypeAArray *)this)->sc; // duplicate scope
- }
- else
- assert(0);
-
- t = t->merge();
- }
- }
- t = t->addMod(mod & ~m);
- return t;
-}
-
-Type *Type::substWildTo(unsigned mod)
-{
- //printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod);
- Type *t;
-
- if (Type *tn = nextOf())
- {
- // substitution has no effect on function pointer type.
- if (ty == Tpointer && tn->ty == Tfunction)
- {
- t = this;
- goto L1;
- }
-
- t = tn->substWildTo(mod);
- if (t == tn)
- t = this;
- else
- {
- if (ty == Tpointer)
- t = t->pointerTo();
- else if (ty == Tarray)
- t = t->arrayOf();
- else if (ty == Tsarray)
- t = new TypeSArray(t, ((TypeSArray *)this)->dim->syntaxCopy());
- else if (ty == Taarray)
- {
- t = new TypeAArray(t, ((TypeAArray *)this)->index->syntaxCopy());
- ((TypeAArray *)t)->sc = ((TypeAArray *)this)->sc; // duplicate scope
- }
- else if (ty == Tdelegate)
- {
- t = new TypeDelegate(t);
- }
- else
- assert(0);
-
- t = t->merge();
- }
- }
- else
- t = this;
-
-L1:
- if (isWild())
- {
- if (mod == MODimmutable)
- {
- t = t->immutableOf();
- }
- else if (mod == MODwildconst)
- {
- t = t->wildConstOf();
- }
- else if (mod == MODwild)
- {
- if (isWildConst())
- t = t->wildConstOf();
- else
- t = t->wildOf();
- }
- else if (mod == MODconst)
- {
- t = t->constOf();
- }
- else
- {
- if (isWildConst())
- t = t->constOf();
- else
- t = t->mutableOf();
- }
- }
- if (isConst())
- t = t->addMod(MODconst);
- if (isShared())
- t = t->addMod(MODshared);
-
- //printf("-Type::substWildTo t = %s\n", t->toChars());
- return t;
-}
-
-Type *TypeFunction::substWildTo(unsigned)
-{
- if (!iswild && !(mod & MODwild))
- return this;
-
- // Substitude inout qualifier of function type to mutable or immutable
- // would break type system. Instead substitude inout to the most weak
- // qualifer - const.
- unsigned m = MODconst;
-
- assert(next);
- Type *tret = next->substWildTo(m);
- Parameters *params = parameterList.parameters;
- if (mod & MODwild)
- params = parameterList.parameters->copy();
- for (size_t i = 0; i < params->length; i++)
- {
- Parameter *p = (*params)[i];
- Type *t = p->type->substWildTo(m);
- if (t == p->type)
- continue;
- if (params == parameterList.parameters)
- params = parameterList.parameters->copy();
- (*params)[i] = new Parameter(p->storageClass, t, NULL, NULL, NULL);
- }
- if (next == tret && params == parameterList.parameters)
- return this;
-
- // Similar to TypeFunction::syntaxCopy;
- TypeFunction *t = new TypeFunction(ParameterList(params, parameterList.varargs),
- tret, linkage);
- t->mod = ((mod & MODwild) ? (mod & ~MODwild) | MODconst : mod);
- t->isnothrow = isnothrow;
- t->isnogc = isnogc;
- t->purity = purity;
- t->isproperty = isproperty;
- t->isref = isref;
- t->isreturn = isreturn;
- t->isscope = isscope;
- t->isscopeinferred = isscopeinferred;
- t->iswild = 0;
- t->trust = trust;
- t->fargs = fargs;
- return t->merge();
-}
-
-/**************************
- * Return type with the top level of it being mutable.
- */
-Type *Type::toHeadMutable()
-{
- if (!mod)
- return this;
- return mutableOf();
-}
-
-/***************************************
- * Calculate built-in properties which just the type is necessary.
- *
- * If flag & 1, don't report "not a property" error and just return NULL.
- */
-Expression *Type::getProperty(Loc loc, Identifier *ident, int flag)
-{
- Expression *e;
-
- if (ident == Id::__sizeof)
- {
- d_uns64 sz = size(loc);
- if (sz == SIZE_INVALID)
- return new ErrorExp();
- e = new IntegerExp(loc, sz, Type::tsize_t);
- }
- else if (ident == Id::__xalignof)
- {
- unsigned explicitAlignment = alignment();
- unsigned naturalAlignment = alignsize();
- unsigned actualAlignment = (explicitAlignment == STRUCTALIGN_DEFAULT ? naturalAlignment : explicitAlignment);
- e = new IntegerExp(loc, actualAlignment, Type::tsize_t);
- }
- else if (ident == Id::_init)
- {
- Type *tb = toBasetype();
- e = defaultInitLiteral(loc);
- if (tb->ty == Tstruct && tb->needsNested())
- {
- StructLiteralExp *se = (StructLiteralExp *)e;
- se->useStaticInit = true;
- }
- }
- else if (ident == Id::_mangleof)
- {
- if (!deco)
- {
- error(loc, "forward reference of type %s.mangleof", toChars());
- e = new ErrorExp();
- }
- else
- {
- e = new StringExp(loc, (char *)deco, strlen(deco));
- Scope sc;
- e = expressionSemantic(e, &sc);
- }
- }
- else if (ident == Id::stringof)
- {
- const char *s = toChars();
- e = new StringExp(loc, const_cast<char *>(s), strlen(s));
- Scope sc;
- e = expressionSemantic(e, &sc);
- }
- else if (flag && this != Type::terror)
- {
- return NULL;
- }
- else
- {
- Dsymbol *s = NULL;
- if (ty == Tstruct || ty == Tclass || ty == Tenum)
- s = toDsymbol(NULL);
- if (s)
- s = s->search_correct(ident);
- if (this != Type::terror)
- {
- if (s)
- error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident->toChars(), toChars(), s->toPrettyChars());
- else
- error(loc, "no property `%s` for type `%s`", ident->toChars(), toChars());
- }
- e = new ErrorExp();
- }
- return e;
-}
-
-/***************************************
- * Access the members of the object e. This type is same as e->type.
- *
- * If flag & 1, don't report "not a property" error and just return NULL.
- */
-Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- VarDeclaration *v = NULL;
-
- Expression *ex = e;
- while (ex->op == TOKcomma)
- ex = ((CommaExp *)ex)->e2;
- if (ex->op == TOKdotvar)
- {
- DotVarExp *dv = (DotVarExp *)ex;
- v = dv->var->isVarDeclaration();
- }
- else if (ex->op == TOKvar)
- {
- VarExp *ve = (VarExp *)ex;
- v = ve->var->isVarDeclaration();
- }
- if (v)
- {
- if (ident == Id::offsetof)
- {
- if (v->isField())
- {
- AggregateDeclaration *ad = v->toParent()->isAggregateDeclaration();
- ad->size(e->loc);
- if (ad->sizeok != SIZEOKdone)
- return new ErrorExp();
- e = new IntegerExp(e->loc, v->offset, Type::tsize_t);
- return e;
- }
- }
- else if (ident == Id::_init)
- {
- Type *tb = toBasetype();
- e = defaultInitLiteral(e->loc);
- if (tb->ty == Tstruct && tb->needsNested())
- {
- StructLiteralExp *se = (StructLiteralExp *)e;
- se->useStaticInit = true;
- }
- goto Lreturn;
- }
- }
- if (ident == Id::stringof)
- {
- /* Bugzilla 3796: this should demangle e->type->deco rather than
- * pretty-printing the type.
- */
- const char *s = e->toChars();
- e = new StringExp(e->loc, const_cast<char *>(s), strlen(s));
- }
- else
- e = getProperty(e->loc, ident, flag & 1);
-
-Lreturn:
- if (e)
- e = expressionSemantic(e, sc);
- return e;
-}
-
-/************************************
- * Return alignment to use for this type.
- */
-
-structalign_t Type::alignment()
-{
- return STRUCTALIGN_DEFAULT;
-}
-
-/***************************************
- * Figures out what to do with an undefined member reference
- * for classes and structs.
- *
- * If flag & 1, don't report "not a property" error and just return NULL.
- */
-Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- //printf("Type::noMember(e: %s ident: %s flag: %d)\n", e->toChars(), ident->toChars(), flag);
-
- static int nest; // https://issues.dlang.org/show_bug.cgi?id=17380
-
- if (++nest > global.recursionLimit)
- {
- ::error(e->loc, "cannot resolve identifier `%s`", ident->toChars());
- --nest;
- return (flag & 1) ? NULL : new ErrorExp();
- }
-
- assert(ty == Tstruct || ty == Tclass);
- AggregateDeclaration *sym = toDsymbol(sc)->isAggregateDeclaration();
- assert(sym);
-
- if (ident != Id::__sizeof &&
- ident != Id::__xalignof &&
- ident != Id::_init &&
- ident != Id::_mangleof &&
- ident != Id::stringof &&
- ident != Id::offsetof &&
- // Bugzilla 15045: Don't forward special built-in member functions.
- ident != Id::ctor &&
- ident != Id::dtor &&
- ident != Id::__xdtor &&
- ident != Id::postblit &&
- ident != Id::__xpostblit)
- {
- /* Look for overloaded opDot() to see if we should forward request
- * to it.
- */
- if (Dsymbol *fd = search_function(sym, Id::opDot))
- {
- /* Rewrite e.ident as:
- * e.opDot().ident
- */
- e = build_overload(e->loc, sc, e, NULL, fd);
- e = new DotIdExp(e->loc, e, ident);
- e = expressionSemantic(e, sc);
- --nest;
- return e;
- }
-
- /* Look for overloaded opDispatch to see if we should forward request
- * to it.
- */
- if (Dsymbol *fd = search_function(sym, Id::opDispatch))
- {
- /* Rewrite e.ident as:
- * e.opDispatch!("ident")
- */
- TemplateDeclaration *td = fd->isTemplateDeclaration();
- if (!td)
- {
- fd->error("must be a template opDispatch(string s), not a %s", fd->kind());
- --nest;
- return new ErrorExp();
- }
- StringExp *se = new StringExp(e->loc, const_cast<char *>(ident->toChars()));
- Objects *tiargs = new Objects();
- tiargs->push(se);
- DotTemplateInstanceExp *dti = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs);
- dti->ti->tempdecl = td;
-
- /* opDispatch, which doesn't need IFTI, may occur instantiate error.
- * It should be gagged if flag & 1.
- * e.g.
- * template opDispatch(name) if (isValid!name) { ... }
- */
- unsigned errors = flag & 1 ? global.startGagging() : 0;
- e = semanticY(dti, sc, 0);
- if (flag & 1 && global.endGagging(errors))
- e = NULL;
- --nest;
- return e;
- }
-
- /* See if we should forward to the alias this.
- */
- if (sym->aliasthis)
- { /* Rewrite e.ident as:
- * e.aliasthis.ident
- */
- e = resolveAliasThis(sc, e);
- DotIdExp *die = new DotIdExp(e->loc, e, ident);
- e = semanticY(die, sc, flag & 1);
- --nest;
- return e;
- }
- }
-
- e = Type::dotExp(sc, e, ident, flag);
- --nest;
- return e;
-}
-
-void Type::error(Loc loc, const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- ::verror(loc, format, ap);
- va_end( ap );
-}
-
-void Type::warning(Loc loc, const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- ::vwarning(loc, format, ap);
- va_end( ap );
-}
-
-Identifier *Type::getTypeInfoIdent()
-{
- // _init_10TypeInfo_%s
- OutBuffer buf;
- buf.reserve(32);
- mangleToBuffer(this, &buf);
-
- size_t len = buf.length();
- buf.writeByte(0);
-
- // Allocate buffer on stack, fail over to using malloc()
- char namebuf[128];
- size_t namelen = 19 + sizeof(len) * 3 + len + 1;
- char *name = namelen <= sizeof(namebuf) ? namebuf : (char *)mem.xmalloc(namelen);
-
- int length = sprintf(name, "_D%lluTypeInfo_%s6__initZ", (unsigned long long) 9 + len, buf.slice().ptr);
- //printf("%p, deco = %s, name = %s\n", this, deco, name);
- assert(0 < length && (size_t)length < namelen); // don't overflow the buffer
-
- Identifier *id = Identifier::idPool(name, length);
-
- if (name != namebuf)
- free(name);
- return id;
-}
-
-TypeBasic *Type::isTypeBasic()
-{
- return NULL;
-}
-
-TypeError *Type::isTypeError()
-{
- return ty == Terror ? (TypeError *)this : NULL;
-}
-
-TypeVector *Type::isTypeVector()
-{
- return ty == Tvector ? (TypeVector *)this : NULL;
-}
-
-TypeSArray *Type::isTypeSArray()
-{
- return ty == Tsarray ? (TypeSArray *)this : NULL;
-}
-
-TypeDArray *Type::isTypeDArray()
-{
- return ty == Tarray ? (TypeDArray *)this : NULL;
-}
-
-TypeAArray *Type::isTypeAArray()
-{
- return ty == Taarray ? (TypeAArray *)this : NULL;
-}
-
-TypePointer *Type::isTypePointer()
-{
- return ty == Tpointer ? (TypePointer *)this : NULL;
-}
-
-TypeReference *Type::isTypeReference()
-{
- return ty == Treference ? (TypeReference *)this : NULL;
-}
-
-TypeFunction *Type::isTypeFunction()
-{
- return ty == Tfunction ? (TypeFunction *)this : NULL;
-}
-
-TypeDelegate *Type::isTypeDelegate()
-{
- return ty == Tdelegate ? (TypeDelegate *)this : NULL;
-}
-
-TypeIdentifier *Type::isTypeIdentifier()
-{
- return ty == Tident ? (TypeIdentifier *)this : NULL;
-}
-
-TypeInstance *Type::isTypeInstance()
-{
- return ty == Tinstance ? (TypeInstance *)this : NULL;
-}
-
-TypeTypeof *Type::isTypeTypeof()
-{
- return ty == Ttypeof ? (TypeTypeof *)this : NULL;
-}
-
-TypeReturn *Type::isTypeReturn()
-{
- return ty == Treturn ? (TypeReturn *)this : NULL;
-}
-
-TypeStruct *Type::isTypeStruct()
-{
- return ty == Tstruct ? (TypeStruct *)this : NULL;
-}
-
-TypeEnum *Type::isTypeEnum()
-{
- return ty == Tenum ? (TypeEnum *)this : NULL;
-}
-
-TypeClass *Type::isTypeClass()
-{
- return ty == Tclass ? (TypeClass *)this : NULL;
-}
-
-TypeTuple *Type::isTypeTuple()
-{
- return ty == Ttuple ? (TypeTuple *)this : NULL;
-}
-
-TypeSlice *Type::isTypeSlice()
-{
- return ty == Tslice ? (TypeSlice *)this : NULL;
-}
-
-TypeNull *Type::isTypeNull()
-{
- return ty == Tnull ? (TypeNull *)this : NULL;
-}
-
-TypeTraits *Type::isTypeTraits()
-{
- return ty == Ttraits ? (TypeTraits *)this : NULL;
-}
-
-TypeMixin *Type::isTypeMixin()
-{
- return ty == Tmixin ? (TypeMixin *)this : NULL;
-}
-
-TypeNoreturn *Type::isTypeNoreturn()
-{
- return ty == Tnoreturn ? (TypeNoreturn *)this : NULL;
-}
-
-TypeFunction *Type::toTypeFunction()
-{
- if (ty != Tfunction)
- assert(0);
- return (TypeFunction *)this;
-}
-
-/***************************************
- * Resolve 'this' type to either type, symbol, or expression.
- * If errors happened, resolved to Type.terror.
- */
-void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool)
-{
- //printf("Type::resolve() %s, %d\n", toChars(), ty);
- Type *t = typeSemantic(this, loc, sc);
- *pt = t;
- *pe = NULL;
- *ps = NULL;
-}
-
-/***************************************
- * Normalize `e` as the result of Type::resolve() process.
- */
-void Type::resolveExp(Expression *e, Type **pt, Expression **pe, Dsymbol **ps)
-{
- *pt = NULL;
- *pe = NULL;
- *ps = NULL;
-
- Dsymbol *s;
- switch (e->op)
- {
- case TOKerror:
- *pt = Type::terror;
- return;
-
- case TOKtype:
- *pt = e->type;
- return;
-
- case TOKvar:
- s = ((VarExp *)e)->var;
- if (s->isVarDeclaration())
- goto Ldefault;
- //if (s->isOverDeclaration())
- // todo;
- break;
-
- case TOKtemplate:
- // TemplateDeclaration
- s = ((TemplateExp *)e)->td;
- break;
-
- case TOKimport:
- s = ((ScopeExp *)e)->sds;
- // TemplateDeclaration, TemplateInstance, Import, Package, Module
- break;
-
- case TOKfunction:
- s = getDsymbol(e);
- break;
-
- //case TOKthis:
- //case TOKsuper:
-
- //case TOKtuple:
-
- //case TOKoverloadset:
-
- //case TOKdotvar:
- //case TOKdottd:
- //case TOKdotti:
- //case TOKdottype:
- //case TOKdot:
-
- default:
- Ldefault:
- *pe = e;
- return;
- }
-
- *ps = s;
-}
-
-/***************************************
- * Return !=0 if the type or any of its subtypes is wild.
- */
-
-int Type::hasWild() const
-{
- return mod & MODwild;
-}
-
-/***************************************
- * Return !=0 if type has pointers that need to
- * be scanned by the GC during a collection cycle.
- */
-bool Type::hasPointers()
-{
- //printf("Type::hasPointers() %s, %d\n", toChars(), ty);
- return false;
-}
-
-/*************************************
- * Detect if type has pointer fields that are initialized to void.
- * Local stack variables with such void fields can remain uninitialized,
- * leading to pointer bugs.
- * Returns:
- * true if so
- */
-bool Type::hasVoidInitPointers()
-{
- return false;
-}
-
-/*************************************
- * If this is a type of something, return that something.
- */
-
-Type *Type::nextOf()
-{
- return NULL;
-}
-
-/*************************************
- * If this is a type of static array, return its base element type.
- */
-
-Type *Type::baseElemOf()
-{
- Type *t = toBasetype();
- while (t->ty == Tsarray)
- t = ((TypeSArray *)t)->next->toBasetype();
- return t;
-}
-
-/*************************************
- * Bugzilla 14488: Check if the inner most base type is complex or imaginary.
- * Should only give alerts when set to emit transitional messages.
- */
-
-void Type::checkComplexTransition(Loc loc)
-{
- Type *t = baseElemOf();
- while (t->ty == Tpointer || t->ty == Tarray)
- t = t->nextOf()->baseElemOf();
-
- if (t->isimaginary() || t->iscomplex())
- {
- Type *rt;
- switch (t->ty)
- {
- case Tcomplex32:
- case Timaginary32:
- rt = Type::tfloat32; break;
- case Tcomplex64:
- case Timaginary64:
- rt = Type::tfloat64; break;
- case Tcomplex80:
- case Timaginary80:
- rt = Type::tfloat80; break;
- default:
- assert(0);
- }
- if (t->iscomplex())
- {
- message(loc, "use of complex type `%s` is scheduled for deprecation, "
- "use `std.complex.Complex!(%s)` instead", toChars(), rt->toChars());
- }
- else
- {
- message(loc, "use of imaginary type `%s` is scheduled for deprecation, "
- "use `%s` instead\n", toChars(), rt->toChars());
- }
- }
-}
-
-/*******************************************
- * Compute number of elements for a (possibly multidimensional) static array,
- * or 1 for other types.
- * Params:
- * loc = for error message
- * Returns:
- * number of elements, uint.max on overflow
- */
-unsigned Type::numberOfElems(const Loc &loc)
-{
- //printf("Type::numberOfElems()\n");
- uinteger_t n = 1;
- Type *tb = this;
- while ((tb = tb->toBasetype())->ty == Tsarray)
- {
- bool overflow = false;
- n = mulu(n, ((TypeSArray *)tb)->dim->toUInteger(), overflow);
- if (overflow || n >= UINT32_MAX)
- {
- error(loc, "static array `%s` size overflowed to %llu", toChars(), (unsigned long long)n);
- return UINT32_MAX;
- }
- tb = ((TypeSArray *)tb)->next;
- }
- return (unsigned)n;
-}
-
-/****************************************
- * Return the mask that an integral type will
- * fit into.
- */
-uinteger_t Type::sizemask()
-{ uinteger_t m;
-
- switch (toBasetype()->ty)
- {
- case Tbool: m = 1; break;
- case Tchar:
- case Tint8:
- case Tuns8: m = 0xFF; break;
- case Twchar:
- case Tint16:
- case Tuns16: m = 0xFFFFUL; break;
- case Tdchar:
- case Tint32:
- case Tuns32: m = 0xFFFFFFFFUL; break;
- case Tint64:
- case Tuns64: m = 0xFFFFFFFFFFFFFFFFULL; break;
- default:
- assert(0);
- }
- return m;
-}
-
-/* ============================= TypeError =========================== */
-
-TypeError::TypeError()
- : Type(Terror)
-{
-}
-
-Type *TypeError::syntaxCopy()
-{
- // No semantic analysis done, no need to copy
- return this;
-}
-
-d_uns64 TypeError::size(Loc) { return SIZE_INVALID; }
-Expression *TypeError::getProperty(Loc, Identifier *, int) { return new ErrorExp(); }
-Expression *TypeError::dotExp(Scope *, Expression *, Identifier *, int) { return new ErrorExp(); }
-Expression *TypeError::defaultInit(Loc) { return new ErrorExp(); }
-Expression *TypeError::defaultInitLiteral(Loc) { return new ErrorExp(); }
-
-/* ============================= TypeNext =========================== */
-
-TypeNext::TypeNext(TY ty, Type *next)
- : Type(ty)
-{
- this->next = next;
-}
-
-void TypeNext::checkDeprecated(Loc loc, Scope *sc)
-{
- Type::checkDeprecated(loc, sc);
- if (next) // next can be NULL if TypeFunction and auto return type
- next->checkDeprecated(loc, sc);
-}
-
-int TypeNext::hasWild() const
-{
- if (ty == Tfunction)
- return 0;
- if (ty == Tdelegate)
- return Type::hasWild();
- return mod & MODwild || (next && next->hasWild());
-}
-
-
-/*******************************
- * For TypeFunction, nextOf() can return NULL if the function return
- * type is meant to be inferred, and semantic() hasn't yet ben run
- * on the function. After semantic(), it must no longer be NULL.
- */
-
-Type *TypeNext::nextOf()
-{
- return next;
-}
-
-Type *TypeNext::makeConst()
-{
- //printf("TypeNext::makeConst() %p, %s\n", this, toChars());
- if (cto)
- {
- assert(cto->mod == MODconst);
- return cto;
- }
- TypeNext *t = (TypeNext *)Type::makeConst();
- if (ty != Tfunction && next->ty != Tfunction &&
- !next->isImmutable())
- {
- if (next->isShared())
- {
- if (next->isWild())
- t->next = next->sharedWildConstOf();
- else
- t->next = next->sharedConstOf();
- }
- else
- {
- if (next->isWild())
- t->next = next->wildConstOf();
- else
- t->next = next->constOf();
- }
- }
- //printf("TypeNext::makeConst() returns %p, %s\n", t, t->toChars());
- return t;
-}
-
-Type *TypeNext::makeImmutable()
-{
- //printf("TypeNext::makeImmutable() %s\n", toChars());
- if (ito)
- {
- assert(ito->isImmutable());
- return ito;
- }
- TypeNext *t = (TypeNext *)Type::makeImmutable();
- if (ty != Tfunction && next->ty != Tfunction &&
- !next->isImmutable())
- {
- t->next = next->immutableOf();
- }
- return t;
-}
-
-Type *TypeNext::makeShared()
-{
- //printf("TypeNext::makeShared() %s\n", toChars());
- if (sto)
- {
- assert(sto->mod == MODshared);
- return sto;
- }
- TypeNext *t = (TypeNext *)Type::makeShared();
- if (ty != Tfunction && next->ty != Tfunction &&
- !next->isImmutable())
- {
- if (next->isWild())
- {
- if (next->isConst())
- t->next = next->sharedWildConstOf();
- else
- t->next = next->sharedWildOf();
- }
- else
- {
- if (next->isConst())
- t->next = next->sharedConstOf();
- else
- t->next = next->sharedOf();
- }
- }
- //printf("TypeNext::makeShared() returns %p, %s\n", t, t->toChars());
- return t;
-}
-
-Type *TypeNext::makeSharedConst()
-{
- //printf("TypeNext::makeSharedConst() %s\n", toChars());
- if (scto)
- {
- assert(scto->mod == (MODshared | MODconst));
- return scto;
- }
- TypeNext *t = (TypeNext *)Type::makeSharedConst();
- if (ty != Tfunction && next->ty != Tfunction &&
- !next->isImmutable())
- {
- if (next->isWild())
- t->next = next->sharedWildConstOf();
- else
- t->next = next->sharedConstOf();
- }
- //printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t->toChars());
- return t;
-}
-
-Type *TypeNext::makeWild()
-{
- //printf("TypeNext::makeWild() %s\n", toChars());
- if (wto)
- {
- assert(wto->mod == MODwild);
- return wto;
- }
- TypeNext *t = (TypeNext *)Type::makeWild();
- if (ty != Tfunction && next->ty != Tfunction &&
- !next->isImmutable())
- {
- if (next->isShared())
- {
- if (next->isConst())
- t->next = next->sharedWildConstOf();
- else
- t->next = next->sharedWildOf();
- }
- else
- {
- if (next->isConst())
- t->next = next->wildConstOf();
- else
- t->next = next->wildOf();
- }
- }
- //printf("TypeNext::makeWild() returns %p, %s\n", t, t->toChars());
- return t;
-}
-
-Type *TypeNext::makeWildConst()
-{
- //printf("TypeNext::makeWildConst() %s\n", toChars());
- if (wcto)
- {
- assert(wcto->mod == MODwildconst);
- return wcto;
- }
- TypeNext *t = (TypeNext *)Type::makeWildConst();
- if (ty != Tfunction && next->ty != Tfunction &&
- !next->isImmutable())
- {
- if (next->isShared())
- t->next = next->sharedWildConstOf();
- else
- t->next = next->wildConstOf();
- }
- //printf("TypeNext::makeWildConst() returns %p, %s\n", t, t->toChars());
- return t;
-}
-
-Type *TypeNext::makeSharedWild()
-{
- //printf("TypeNext::makeSharedWild() %s\n", toChars());
- if (swto)
- {
- assert(swto->isSharedWild());
- return swto;
- }
- TypeNext *t = (TypeNext *)Type::makeSharedWild();
- if (ty != Tfunction && next->ty != Tfunction &&
- !next->isImmutable())
- {
- if (next->isConst())
- t->next = next->sharedWildConstOf();
- else
- t->next = next->sharedWildOf();
- }
- //printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t->toChars());
- return t;
-}
-
-Type *TypeNext::makeSharedWildConst()
-{
- //printf("TypeNext::makeSharedWildConst() %s\n", toChars());
- if (swcto)
- {
- assert(swcto->mod == (MODshared | MODwildconst));
- return swcto;
- }
- TypeNext *t = (TypeNext *)Type::makeSharedWildConst();
- if (ty != Tfunction && next->ty != Tfunction &&
- !next->isImmutable())
- {
- t->next = next->sharedWildConstOf();
- }
- //printf("TypeNext::makeSharedWildConst() returns %p, %s\n", t, t->toChars());
- return t;
-}
-
-Type *TypeNext::makeMutable()
-{
- //printf("TypeNext::makeMutable() %p, %s\n", this, toChars());
- TypeNext *t = (TypeNext *)Type::makeMutable();
- if (ty == Tsarray)
- {
- t->next = next->mutableOf();
- }
- //printf("TypeNext::makeMutable() returns %p, %s\n", t, t->toChars());
- return t;
-}
-
-MATCH TypeNext::constConv(Type *to)
-{
- //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to->toChars());
- if (equals(to))
- return MATCHexact;
-
- if (!(ty == to->ty && MODimplicitConv(mod, to->mod)))
- return MATCHnomatch;
-
- Type *tn = to->nextOf();
- if (!(tn && next->ty == tn->ty))
- return MATCHnomatch;
-
- MATCH m;
- if (to->isConst()) // whole tail const conversion
- { // Recursive shared level check
- m = next->constConv(tn);
- if (m == MATCHexact)
- m = MATCHconst;
- }
- else
- { //printf("\tnext => %s, to->next => %s\n", next->toChars(), tn->toChars());
- m = next->equals(tn) ? MATCHconst : MATCHnomatch;
- }
- return m;
-}
-
-unsigned char TypeNext::deduceWild(Type *t, bool isRef)
-{
- if (ty == Tfunction)
- return 0;
-
- unsigned char wm;
-
- Type *tn = t->nextOf();
- if (!isRef && (ty == Tarray || ty == Tpointer) && tn)
- {
- wm = next->deduceWild(tn, true);
- if (!wm)
- wm = Type::deduceWild(t, true);
- }
- else
- {
- wm = Type::deduceWild(t, isRef);
- if (!wm && tn)
- wm = next->deduceWild(tn, true);
- }
-
- return wm;
-}
-
-
-void TypeNext::transitive()
-{
- /* Invoke transitivity of type attributes
- */
- next = next->addMod(mod);
-}
-
-/* ============================= TypeBasic =========================== */
-
-#define TFLAGSintegral 1
-#define TFLAGSfloating 2
-#define TFLAGSunsigned 4
-#define TFLAGSreal 8
-#define TFLAGSimaginary 0x10
-#define TFLAGScomplex 0x20
-
-TypeBasic::TypeBasic(TY ty)
- : Type(ty)
-{ const char *d;
- unsigned flags;
-
- flags = 0;
- switch (ty)
- {
- case Tvoid: d = Token::toChars(TOKvoid);
- break;
-
- case Tint8: d = Token::toChars(TOKint8);
- flags |= TFLAGSintegral;
- break;
-
- case Tuns8: d = Token::toChars(TOKuns8);
- flags |= TFLAGSintegral | TFLAGSunsigned;
- break;
-
- case Tint16: d = Token::toChars(TOKint16);
- flags |= TFLAGSintegral;
- break;
-
- case Tuns16: d = Token::toChars(TOKuns16);
- flags |= TFLAGSintegral | TFLAGSunsigned;
- break;
-
- case Tint32: d = Token::toChars(TOKint32);
- flags |= TFLAGSintegral;
- break;
-
- case Tuns32: d = Token::toChars(TOKuns32);
- flags |= TFLAGSintegral | TFLAGSunsigned;
- break;
-
- case Tfloat32: d = Token::toChars(TOKfloat32);
- flags |= TFLAGSfloating | TFLAGSreal;
- break;
-
- case Tint64: d = Token::toChars(TOKint64);
- flags |= TFLAGSintegral;
- break;
-
- case Tuns64: d = Token::toChars(TOKuns64);
- flags |= TFLAGSintegral | TFLAGSunsigned;
- break;
-
- case Tint128: d = Token::toChars(TOKint128);
- flags |= TFLAGSintegral;
- break;
-
- case Tuns128: d = Token::toChars(TOKuns128);
- flags |= TFLAGSintegral | TFLAGSunsigned;
- break;
-
- case Tfloat64: d = Token::toChars(TOKfloat64);
- flags |= TFLAGSfloating | TFLAGSreal;
- break;
-
- case Tfloat80: d = Token::toChars(TOKfloat80);
- flags |= TFLAGSfloating | TFLAGSreal;
- break;
-
- case Timaginary32: d = Token::toChars(TOKimaginary32);
- flags |= TFLAGSfloating | TFLAGSimaginary;
- break;
-
- case Timaginary64: d = Token::toChars(TOKimaginary64);
- flags |= TFLAGSfloating | TFLAGSimaginary;
- break;
-
- case Timaginary80: d = Token::toChars(TOKimaginary80);
- flags |= TFLAGSfloating | TFLAGSimaginary;
- break;
-
- case Tcomplex32: d = Token::toChars(TOKcomplex32);
- flags |= TFLAGSfloating | TFLAGScomplex;
- break;
-
- case Tcomplex64: d = Token::toChars(TOKcomplex64);
- flags |= TFLAGSfloating | TFLAGScomplex;
- break;
-
- case Tcomplex80: d = Token::toChars(TOKcomplex80);
- flags |= TFLAGSfloating | TFLAGScomplex;
- break;
-
- case Tbool: d = "bool";
- flags |= TFLAGSintegral | TFLAGSunsigned;
- break;
-
- case Tchar: d = Token::toChars(TOKchar);
- flags |= TFLAGSintegral | TFLAGSunsigned;
- break;
-
- case Twchar: d = Token::toChars(TOKwchar);
- flags |= TFLAGSintegral | TFLAGSunsigned;
- break;
-
- case Tdchar: d = Token::toChars(TOKdchar);
- flags |= TFLAGSintegral | TFLAGSunsigned;
- break;
-
- default: assert(0);
- }
- this->dstring = d;
- this->flags = flags;
- merge();
-}
-
-const char *TypeBasic::kind()
-{
- return dstring;
-}
-
-Type *TypeBasic::syntaxCopy()
-{
- // No semantic analysis done on basic types, no need to copy
- return this;
-}
-
-d_uns64 TypeBasic::size(Loc)
-{ unsigned size;
-
- //printf("TypeBasic::size()\n");
- switch (ty)
- {
- case Tint8:
- case Tuns8: size = 1; break;
- case Tint16:
- case Tuns16: size = 2; break;
- case Tint32:
- case Tuns32:
- case Tfloat32:
- case Timaginary32:
- size = 4; break;
- case Tint64:
- case Tuns64:
- case Tfloat64:
- case Timaginary64:
- size = 8; break;
- case Tfloat80:
- case Timaginary80:
- size = target.realsize; break;
- case Tcomplex32:
- size = 8; break;
- case Tcomplex64:
- case Tint128:
- case Tuns128:
- size = 16; break;
- case Tcomplex80:
- size = target.realsize * 2; break;
-
- case Tvoid:
- //size = Type::size(); // error message
- size = 1;
- break;
-
- case Tbool: size = 1; break;
- case Tchar: size = 1; break;
- case Twchar: size = 2; break;
- case Tdchar: size = 4; break;
-
- default:
- assert(0);
- break;
- }
- //printf("TypeBasic::size() = %d\n", size);
- return size;
-}
-
-unsigned TypeBasic::alignsize()
-{
- return target.alignsize(this);
-}
-
-
-Expression *TypeBasic::getProperty(Loc loc, Identifier *ident, int flag)
-{
- Expression *e;
- dinteger_t ivalue;
- real_t fvalue;
-
- //printf("TypeBasic::getProperty('%s')\n", ident->toChars());
- if (ident == Id::max)
- {
- switch (ty)
- {
- case Tint8:
- ivalue = 0x7F;
- goto Livalue;
- case Tuns8:
- ivalue = 0xFF;
- goto Livalue;
- case Tint16:
- ivalue = 0x7FFFUL;
- goto Livalue;
- case Tuns16:
- ivalue = 0xFFFFUL;
- goto Livalue;
- case Tint32:
- ivalue = 0x7FFFFFFFUL;
- goto Livalue;
- case Tuns32:
- ivalue = 0xFFFFFFFFUL;
- goto Livalue;
- case Tint64:
- ivalue = 0x7FFFFFFFFFFFFFFFLL;
- goto Livalue;
- case Tuns64:
- ivalue = 0xFFFFFFFFFFFFFFFFULL;
- goto Livalue;
- case Tbool:
- ivalue = 1;
- goto Livalue;
- case Tchar:
- ivalue = 0xFF;
- goto Livalue;
- case Twchar:
- ivalue = 0xFFFFUL;
- goto Livalue;
- case Tdchar:
- ivalue = 0x10FFFFUL;
- goto Livalue;
- case Tcomplex32:
- case Timaginary32:
- case Tfloat32:
- fvalue = target.FloatProperties.max;
- goto Lfvalue;
- case Tcomplex64:
- case Timaginary64:
- case Tfloat64:
- fvalue = target.DoubleProperties.max;
- goto Lfvalue;
- case Tcomplex80:
- case Timaginary80:
- case Tfloat80:
- fvalue = target.RealProperties.max;
- goto Lfvalue;
- }
- }
- else if (ident == Id::min)
- {
- switch (ty)
- {
- case Tint8:
- ivalue = -128;
- goto Livalue;
- case Tuns8:
- ivalue = 0;
- goto Livalue;
- case Tint16:
- ivalue = -32768;
- goto Livalue;
- case Tuns16:
- ivalue = 0;
- goto Livalue;
- case Tint32:
- ivalue = -2147483647L - 1;
- goto Livalue;
- case Tuns32:
- ivalue = 0;
- goto Livalue;
- case Tint64:
- ivalue = (-9223372036854775807LL-1LL);
- goto Livalue;
- case Tuns64:
- ivalue = 0;
- goto Livalue;
- case Tbool:
- ivalue = 0;
- goto Livalue;
- case Tchar:
- ivalue = 0;
- goto Livalue;
- case Twchar:
- ivalue = 0;
- goto Livalue;
- case Tdchar:
- ivalue = 0;
- goto Livalue;
-
- case Tcomplex32:
- case Timaginary32:
- case Tfloat32:
- case Tcomplex64:
- case Timaginary64:
- case Tfloat64:
- case Tcomplex80:
- case Timaginary80:
- case Tfloat80:
- error(loc, "use .min_normal property instead of .min");
- return new ErrorExp();
- }
- }
- else if (ident == Id::min_normal)
- {
- switch (ty)
- {
- case Tcomplex32:
- case Timaginary32:
- case Tfloat32:
- fvalue = target.FloatProperties.min_normal;
- goto Lfvalue;
- case Tcomplex64:
- case Timaginary64:
- case Tfloat64:
- fvalue = target.DoubleProperties.min_normal;
- goto Lfvalue;
- case Tcomplex80:
- case Timaginary80:
- case Tfloat80:
- fvalue = target.RealProperties.min_normal;
- goto Lfvalue;
- }
- }
- else if (ident == Id::nan)
- {
- switch (ty)
- {
- case Tcomplex32:
- case Tcomplex64:
- case Tcomplex80:
- case Timaginary32:
- case Timaginary64:
- case Timaginary80:
- case Tfloat32:
- case Tfloat64:
- case Tfloat80:
- fvalue = target.RealProperties.nan;
- goto Lfvalue;
- }
- }
- else if (ident == Id::infinity)
- {
- switch (ty)
- {
- case Tcomplex32:
- case Tcomplex64:
- case Tcomplex80:
- case Timaginary32:
- case Timaginary64:
- case Timaginary80:
- case Tfloat32:
- case Tfloat64:
- case Tfloat80:
- fvalue = target.RealProperties.infinity;
- goto Lfvalue;
- }
- }
- else if (ident == Id::dig)
- {
- switch (ty)
- {
- case Tcomplex32:
- case Timaginary32:
- case Tfloat32:
- ivalue = target.FloatProperties.dig;
- goto Lint;
- case Tcomplex64:
- case Timaginary64:
- case Tfloat64:
- ivalue = target.DoubleProperties.dig;
- goto Lint;
- case Tcomplex80:
- case Timaginary80:
- case Tfloat80:
- ivalue = target.RealProperties.dig;
- goto Lint;
- }
- }
- else if (ident == Id::epsilon)
- {
- switch (ty)
- {
- case Tcomplex32:
- case Timaginary32:
- case Tfloat32:
- fvalue = target.FloatProperties.epsilon;
- goto Lfvalue;
- case Tcomplex64:
- case Timaginary64:
- case Tfloat64:
- fvalue = target.DoubleProperties.epsilon;
- goto Lfvalue;
- case Tcomplex80:
- case Timaginary80:
- case Tfloat80:
- fvalue = target.RealProperties.epsilon;
- goto Lfvalue;
- }
- }
- else if (ident == Id::mant_dig)
- {
- switch (ty)
- {
- case Tcomplex32:
- case Timaginary32:
- case Tfloat32:
- ivalue = target.FloatProperties.mant_dig;
- goto Lint;
- case Tcomplex64:
- case Timaginary64:
- case Tfloat64:
- ivalue = target.DoubleProperties.mant_dig;
- goto Lint;
- case Tcomplex80:
- case Timaginary80:
- case Tfloat80:
- ivalue = target.RealProperties.mant_dig;
- goto Lint;
- }
- }
- else if (ident == Id::max_10_exp)
- {
- switch (ty)
- {
- case Tcomplex32:
- case Timaginary32:
- case Tfloat32:
- ivalue = target.FloatProperties.max_10_exp;
- goto Lint;
- case Tcomplex64:
- case Timaginary64:
- case Tfloat64:
- ivalue = target.DoubleProperties.max_10_exp;
- goto Lint;
- case Tcomplex80:
- case Timaginary80:
- case Tfloat80:
- ivalue = target.RealProperties.max_10_exp;
- goto Lint;
- }
- }
- else if (ident == Id::max_exp)
- {
- switch (ty)
- {
- case Tcomplex32:
- case Timaginary32:
- case Tfloat32:
- ivalue = target.FloatProperties.max_exp;
- goto Lint;
- case Tcomplex64:
- case Timaginary64:
- case Tfloat64:
- ivalue = target.DoubleProperties.max_exp;
- goto Lint;
- case Tcomplex80:
- case Timaginary80:
- case Tfloat80:
- ivalue = target.RealProperties.max_exp;
- goto Lint;
- }
- }
- else if (ident == Id::min_10_exp)
- {
- switch (ty)
- {
- case Tcomplex32:
- case Timaginary32:
- case Tfloat32:
- ivalue = target.FloatProperties.min_10_exp;
- goto Lint;
- case Tcomplex64:
- case Timaginary64:
- case Tfloat64:
- ivalue = target.DoubleProperties.min_10_exp;
- goto Lint;
- case Tcomplex80:
- case Timaginary80:
- case Tfloat80:
- ivalue = target.RealProperties.min_10_exp;
- goto Lint;
- }
- }
- else if (ident == Id::min_exp)
- {
- switch (ty)
- {
- case Tcomplex32:
- case Timaginary32:
- case Tfloat32:
- ivalue = target.FloatProperties.min_exp;
- goto Lint;
- case Tcomplex64:
- case Timaginary64:
- case Tfloat64:
- ivalue = target.DoubleProperties.min_exp;
- goto Lint;
- case Tcomplex80:
- case Timaginary80:
- case Tfloat80:
- ivalue = target.RealProperties.min_exp;
- goto Lint;
- }
- }
-
- return Type::getProperty(loc, ident, flag);
-
-Livalue:
- e = new IntegerExp(loc, ivalue, this);
- return e;
-
-Lfvalue:
- if (isreal() || isimaginary())
- e = new RealExp(loc, fvalue, this);
- else
- {
- complex_t cvalue = complex_t(fvalue, fvalue);
- //for (int i = 0; i < 20; i++)
- // printf("%02x ", ((unsigned char *)&cvalue)[i]);
- //printf("\n");
- e = new ComplexExp(loc, cvalue, this);
- }
- return e;
-
-Lint:
- e = new IntegerExp(loc, ivalue, Type::tint32);
- return e;
-}
-
-Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- Type *t;
-
- if (ident == Id::re)
- {
- switch (ty)
- {
- case Tcomplex32: t = tfloat32; goto L1;
- case Tcomplex64: t = tfloat64; goto L1;
- case Tcomplex80: t = tfloat80; goto L1;
- L1:
- e = e->castTo(sc, t);
- break;
-
- case Tfloat32:
- case Tfloat64:
- case Tfloat80:
- break;
-
- case Timaginary32: t = tfloat32; goto L2;
- case Timaginary64: t = tfloat64; goto L2;
- case Timaginary80: t = tfloat80; goto L2;
- L2:
- e = new RealExp(e->loc, CTFloat::zero, t);
- break;
-
- default:
- e = Type::getProperty(e->loc, ident, flag);
- break;
- }
- }
- else if (ident == Id::im)
- { Type *t2;
-
- switch (ty)
- {
- case Tcomplex32: t = timaginary32; t2 = tfloat32; goto L3;
- case Tcomplex64: t = timaginary64; t2 = tfloat64; goto L3;
- case Tcomplex80: t = timaginary80; t2 = tfloat80; goto L3;
- L3:
- e = e->castTo(sc, t);
- e->type = t2;
- break;
-
- case Timaginary32: t = tfloat32; goto L4;
- case Timaginary64: t = tfloat64; goto L4;
- case Timaginary80: t = tfloat80; goto L4;
- L4:
- e = e->copy();
- e->type = t;
- break;
-
- case Tfloat32:
- case Tfloat64:
- case Tfloat80:
- e = new RealExp(e->loc, CTFloat::zero, this);
- break;
-
- default:
- e = Type::getProperty(e->loc, ident, flag);
- break;
- }
- }
- else
- {
- return Type::dotExp(sc, e, ident, flag);
- }
- if (!(flag & 1) || e)
- e = expressionSemantic(e, sc);
- return e;
-}
-
-Expression *TypeBasic::defaultInit(Loc loc)
-{
- dinteger_t value = 0;
-
- switch (ty)
- {
- case Tchar:
- value = 0xFF;
- break;
-
- case Twchar:
- case Tdchar:
- value = 0xFFFF;
- break;
-
- case Timaginary32:
- case Timaginary64:
- case Timaginary80:
- case Tfloat32:
- case Tfloat64:
- case Tfloat80:
- return new RealExp(loc, target.RealProperties.snan, this);
-
- case Tcomplex32:
- case Tcomplex64:
- case Tcomplex80:
- { // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
- complex_t cvalue = complex_t(target.RealProperties.snan, target.RealProperties.snan);
- return new ComplexExp(loc, cvalue, this);
- }
-
- case Tvoid:
- error(loc, "void does not have a default initializer");
- return new ErrorExp();
- }
- return new IntegerExp(loc, value, this);
-}
-
-bool TypeBasic::isZeroInit(Loc)
-{
- switch (ty)
- {
- case Tchar:
- case Twchar:
- case Tdchar:
- case Timaginary32:
- case Timaginary64:
- case Timaginary80:
- case Tfloat32:
- case Tfloat64:
- case Tfloat80:
- case Tcomplex32:
- case Tcomplex64:
- case Tcomplex80:
- return false; // no
- default:
- return true; // yes
- }
-}
-
-bool TypeBasic::isintegral()
-{
- //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags);
- return (flags & TFLAGSintegral) != 0;
-}
-
-bool TypeBasic::isfloating()
-{
- return (flags & TFLAGSfloating) != 0;
-}
-
-bool TypeBasic::isreal()
-{
- return (flags & TFLAGSreal) != 0;
-}
-
-bool TypeBasic::isimaginary()
-{
- return (flags & TFLAGSimaginary) != 0;
-}
-
-bool TypeBasic::iscomplex()
-{
- return (flags & TFLAGScomplex) != 0;
-}
-
-bool TypeBasic::isunsigned()
-{
- return (flags & TFLAGSunsigned) != 0;
-}
-
-bool TypeBasic::isscalar()
-{
- return (flags & (TFLAGSintegral | TFLAGSfloating)) != 0;
-}
-
-MATCH TypeBasic::implicitConvTo(Type *to)
-{
- //printf("TypeBasic::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
- if (this == to)
- return MATCHexact;
-
- if (ty == to->ty)
- {
- if (mod == to->mod)
- return MATCHexact;
- else if (MODimplicitConv(mod, to->mod))
- return MATCHconst;
- else if (!((mod ^ to->mod) & MODshared)) // for wild matching
- return MATCHconst;
- else
- return MATCHconvert;
- }
-
- if (ty == Tvoid || to->ty == Tvoid)
- return MATCHnomatch;
- if (to->ty == Tbool)
- return MATCHnomatch;
-
- TypeBasic *tob;
- if (to->ty == Tvector && to->deco)
- {
- TypeVector *tv = (TypeVector *)to;
- tob = tv->elementType();
- }
- else if (to->ty == Tenum)
- {
- EnumDeclaration *ed = ((TypeEnum *)to)->sym;
- if (ed->isSpecial())
- {
- /* Special enums that allow implicit conversions to them. */
- tob = to->toBasetype()->isTypeBasic();
- if (tob)
- return implicitConvTo(tob);
- }
- else
- return MATCHnomatch;
- }
- else
- tob = to->isTypeBasic();
- if (!tob)
- return MATCHnomatch;
-
- if (flags & TFLAGSintegral)
- {
- // Disallow implicit conversion of integers to imaginary or complex
- if (tob->flags & (TFLAGSimaginary | TFLAGScomplex))
- return MATCHnomatch;
-
- // If converting from integral to integral
- if (tob->flags & TFLAGSintegral)
- { d_uns64 sz = size(Loc());
- d_uns64 tosz = tob->size(Loc());
-
- /* Can't convert to smaller size
- */
- if (sz > tosz)
- return MATCHnomatch;
-
- /* Can't change sign if same size
- */
- /*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned)
- return MATCHnomatch;*/
- }
- }
- else if (flags & TFLAGSfloating)
- {
- // Disallow implicit conversion of floating point to integer
- if (tob->flags & TFLAGSintegral)
- return MATCHnomatch;
-
- assert(tob->flags & TFLAGSfloating || to->ty == Tvector);
-
- // Disallow implicit conversion from complex to non-complex
- if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex))
- return MATCHnomatch;
-
- // Disallow implicit conversion of real or imaginary to complex
- if (flags & (TFLAGSreal | TFLAGSimaginary) &&
- tob->flags & TFLAGScomplex)
- return MATCHnomatch;
-
- // Disallow implicit conversion to-from real and imaginary
- if ((flags & (TFLAGSreal | TFLAGSimaginary)) !=
- (tob->flags & (TFLAGSreal | TFLAGSimaginary)))
- return MATCHnomatch;
- }
- return MATCHconvert;
-}
-
-TypeBasic *TypeBasic::isTypeBasic()
-{
- return (TypeBasic *)this;
-}
-
-/* ============================= TypeVector =========================== */
-
-/* The basetype must be one of:
- * byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2]
- * For AVX:
- * byte[32],ubyte[32],short[16],ushort[16],int[8],uint[8],long[4],ulong[4],float[8],double[4]
- */
-TypeVector::TypeVector(Type *basetype)
- : Type(Tvector)
-{
- this->basetype = basetype;
-}
-
-TypeVector *TypeVector::create(Type *basetype)
-{
- return new TypeVector(basetype);
-}
-
-const char *TypeVector::kind()
-{
- return "vector";
-}
-
-Type *TypeVector::syntaxCopy()
-{
- return new TypeVector(basetype->syntaxCopy());
-}
-
-TypeBasic *TypeVector::elementType()
-{
- assert(basetype->ty == Tsarray);
- TypeSArray *t = (TypeSArray *)basetype;
- TypeBasic *tb = t->nextOf()->isTypeBasic();
- assert(tb);
- return tb;
-}
-
-bool TypeVector::isBoolean()
-{
- return false;
-}
-
-d_uns64 TypeVector::size(Loc)
-{
- return basetype->size();
-}
-
-unsigned TypeVector::alignsize()
-{
- return (unsigned)basetype->size();
-}
-
-Expression *TypeVector::getProperty(Loc loc, Identifier *ident, int flag)
-{
- return Type::getProperty(loc, ident, flag);
-}
-
-Expression *TypeVector::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- if (ident == Id::ptr && e->op == TOKcall)
- {
- /* The trouble with TOKcall is the return ABI for float[4] is different from
- * __vector(float[4]), and a type paint won't do.
- */
- e = new AddrExp(e->loc, e);
- e = expressionSemantic(e, sc);
- e = e->castTo(sc, basetype->nextOf()->pointerTo());
- return e;
- }
- if (ident == Id::array)
- {
- //e = e->castTo(sc, basetype);
- // Keep lvalue-ness
- e = new VectorArrayExp(e->loc, e);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (ident == Id::_init || ident == Id::offsetof || ident == Id::stringof || ident == Id::__xalignof)
- {
- // init should return a new VectorExp (Bugzilla 12776)
- // offsetof does not work on a cast expression, so use e directly
- // stringof should not add a cast to the output
- return Type::dotExp(sc, e, ident, flag);
- }
- return basetype->dotExp(sc, e->castTo(sc, basetype), ident, flag);
-}
-
-Expression *TypeVector::defaultInit(Loc loc)
-{
- //printf("TypeVector::defaultInit()\n");
- assert(basetype->ty == Tsarray);
- Expression *e = basetype->defaultInit(loc);
- VectorExp *ve = new VectorExp(loc, e, this);
- ve->type = this;
- ve->dim = (int)(basetype->size(loc) / elementType()->size(loc));
- return ve;
-}
-
-Expression *TypeVector::defaultInitLiteral(Loc loc)
-{
- //printf("TypeVector::defaultInitLiteral()\n");
- assert(basetype->ty == Tsarray);
- Expression *e = basetype->defaultInitLiteral(loc);
- VectorExp *ve = new VectorExp(loc, e, this);
- ve->type = this;
- ve->dim = (int)(basetype->size(loc) / elementType()->size(loc));
- return ve;
-}
-
-bool TypeVector::isZeroInit(Loc loc)
-{
- return basetype->isZeroInit(loc);
-}
-
-bool TypeVector::isintegral()
-{
- //printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags);
- return basetype->nextOf()->isintegral();
-}
-
-bool TypeVector::isfloating()
-{
- return basetype->nextOf()->isfloating();
-}
-
-bool TypeVector::isunsigned()
-{
- return basetype->nextOf()->isunsigned();
-}
-
-bool TypeVector::isscalar()
-{
- return basetype->nextOf()->isscalar();
-}
-
-MATCH TypeVector::implicitConvTo(Type *to)
-{
- //printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars());
- if (this == to)
- return MATCHexact;
-#ifdef IN_GCC
- if (to->ty == Tvector)
- {
- TypeVector *tv = (TypeVector *)to;
- assert(basetype->ty == Tsarray && tv->basetype->ty == Tsarray);
-
- // Can't convert to a vector which has different size.
- if (basetype->size() != tv->basetype->size())
- return MATCHnomatch;
-
- // Allow conversion to void[]
- if (tv->basetype->nextOf()->ty == Tvoid)
- return MATCHconvert;
-
- // Otherwise implicitly convertible only if basetypes are.
- return basetype->implicitConvTo(tv->basetype);
- }
-#else
- if (ty == to->ty)
- return MATCHconvert;
-#endif
- return MATCHnomatch;
-}
-
-/***************************** TypeArray *****************************/
-
-TypeArray::TypeArray(TY ty, Type *next)
- : TypeNext(ty, next)
-{
-}
-
-Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- e = Type::dotExp(sc, e, ident, flag);
-
- if (!(flag & 1) || e)
- e = expressionSemantic(e, sc);
- return e;
-}
-
-
-/***************************** TypeSArray *****************************/
-
-TypeSArray::TypeSArray(Type *t, Expression *dim)
- : TypeArray(Tsarray, t)
-{
- //printf("TypeSArray(%s)\n", dim->toChars());
- this->dim = dim;
-}
-
-const char *TypeSArray::kind()
-{
- return "sarray";
-}
-
-Type *TypeSArray::syntaxCopy()
-{
- Type *t = next->syntaxCopy();
- Expression *e = dim->syntaxCopy();
- t = new TypeSArray(t, e);
- t->mod = mod;
- return t;
-}
-
-d_uns64 TypeSArray::size(Loc loc)
-{
- //printf("TypeSArray::size()\n");
- uinteger_t n = numberOfElems(loc);
- uinteger_t elemsize = baseElemOf()->size();
- bool overflow = false;
- uinteger_t sz = mulu(n, elemsize, overflow);
- if (overflow || sz >= UINT32_MAX)
- {
- if (elemsize != SIZE_INVALID && n != UINT32_MAX)
- error(loc, "static array `%s` size overflowed to %lld", toChars(), (long long)sz);
- return SIZE_INVALID;
- }
- return sz;
-}
-
-unsigned TypeSArray::alignsize()
-{
- return next->alignsize();
-}
-
-void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
-{
- //printf("TypeSArray::resolve() %s\n", toChars());
- next->resolve(loc, sc, pe, pt, ps, intypeid);
- //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
- if (*pe)
- {
- // It's really an index expression
- if (Dsymbol *s = getDsymbol(*pe))
- *pe = new DsymbolExp(loc, s);
- *pe = new ArrayExp(loc, *pe, dim);
- }
- else if (*ps)
- {
- Dsymbol *s = *ps;
- TupleDeclaration *td = s->isTupleDeclaration();
- if (td)
- {
- ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
- sc = sc->startCTFE();
- dim = expressionSemantic(dim, sc);
- sc = sc->endCTFE();
- sc = sc->pop();
-
- dim = dim->ctfeInterpret();
- uinteger_t d = dim->toUInteger();
-
- if (d >= td->objects->length)
- {
- error(loc, "tuple index %llu exceeds length %u", d, td->objects->length);
- *ps = NULL;
- *pt = Type::terror;
- return;
- }
- RootObject *o = (*td->objects)[(size_t)d];
- if (o->dyncast() == DYNCAST_DSYMBOL)
- {
- *ps = (Dsymbol *)o;
- return;
- }
- if (o->dyncast() == DYNCAST_EXPRESSION)
- {
- Expression *e = (Expression *)o;
- if (e->op == TOKdsymbol)
- {
- *ps = ((DsymbolExp *)e)->s;
- *pe = NULL;
- }
- else
- {
- *ps = NULL;
- *pe = e;
- }
- return;
- }
- if (o->dyncast() == DYNCAST_TYPE)
- {
- *ps = NULL;
- *pt = ((Type *)o)->addMod(this->mod);
- return;
- }
-
- /* Create a new TupleDeclaration which
- * is a slice [d..d+1] out of the old one.
- * Do it this way because TemplateInstance::semanticTiargs()
- * can handle unresolved Objects this way.
- */
- Objects *objects = new Objects;
- objects->setDim(1);
- (*objects)[0] = o;
-
- TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
- *ps = tds;
- }
- else
- goto Ldefault;
- }
- else
- {
- if ((*pt)->ty != Terror)
- next = *pt; // prevent re-running semantic() on 'next'
- Ldefault:
- Type::resolve(loc, sc, pe, pt, ps, intypeid);
- }
-}
-
-Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- if (ident == Id::length)
- {
- Loc oldLoc = e->loc;
- e = dim->copy();
- e->loc = oldLoc;
- }
- else if (ident == Id::ptr)
- {
- if (e->op == TOKtype)
- {
- e->error("%s is not an expression", e->toChars());
- return new ErrorExp();
- }
- else if (!(flag & 2) && sc->func && !sc->intypeof && sc->func->setUnsafe())
- {
- e->deprecation("%s.ptr cannot be used in @safe code, use &%s[0] instead", e->toChars(), e->toChars());
- // return new ErrorExp();
- }
- e = e->castTo(sc, e->type->nextOf()->pointerTo());
- }
- else
- {
- e = TypeArray::dotExp(sc, e, ident, flag);
- }
- if (!(flag & 1) || e)
- e = expressionSemantic(e, sc);
- return e;
-}
-
-structalign_t TypeSArray::alignment()
-{
- return next->alignment();
-}
-
-bool TypeSArray::isString()
-{
- TY nty = next->toBasetype()->ty;
- return nty == Tchar || nty == Twchar || nty == Tdchar;
-}
-
-MATCH TypeSArray::constConv(Type *to)
-{
- if (to->ty == Tsarray)
- {
- TypeSArray *tsa = (TypeSArray *)to;
- if (!dim->equals(tsa->dim))
- return MATCHnomatch;
- }
- return TypeNext::constConv(to);
-}
-
-MATCH TypeSArray::implicitConvTo(Type *to)
-{
- //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
-
- if (to->ty == Tarray)
- {
- TypeDArray *ta = (TypeDArray *)to;
-
- if (!MODimplicitConv(next->mod, ta->next->mod))
- return MATCHnomatch;
-
- /* Allow conversion to void[]
- */
- if (ta->next->ty == Tvoid)
- {
- return MATCHconvert;
- }
-
- MATCH m = next->constConv(ta->next);
- if (m > MATCHnomatch)
- {
- return MATCHconvert;
- }
- return MATCHnomatch;
- }
-
- if (to->ty == Tsarray)
- {
- if (this == to)
- return MATCHexact;
-
- TypeSArray *tsa = (TypeSArray *)to;
-
- if (dim->equals(tsa->dim))
- {
- /* Since static arrays are value types, allow
- * conversions from const elements to non-const
- * ones, just like we allow conversion from const int
- * to int.
- */
- MATCH m = next->implicitConvTo(tsa->next);
- if (m >= MATCHconst)
- {
- if (mod != to->mod)
- m = MATCHconst;
- return m;
- }
- }
- }
- return MATCHnomatch;
-}
-
-Expression *TypeSArray::defaultInit(Loc loc)
-{
- if (next->ty == Tvoid)
- return tuns8->defaultInit(loc);
- else
- return next->defaultInit(loc);
-}
-
-bool TypeSArray::isZeroInit(Loc loc)
-{
- return next->isZeroInit(loc);
-}
-
-bool TypeSArray::needsDestruction()
-{
- return next->needsDestruction();
-}
-
-/*********************************
- *
- */
-
-bool TypeSArray::needsNested()
-{
- return next->needsNested();
-}
-
-Expression *TypeSArray::defaultInitLiteral(Loc loc)
-{
- size_t d = (size_t)dim->toInteger();
- Expression *elementinit;
- if (next->ty == Tvoid)
- elementinit = tuns8->defaultInitLiteral(loc);
- else
- elementinit = next->defaultInitLiteral(loc);
- Expressions *elements = new Expressions();
- elements->setDim(d);
- for (size_t i = 0; i < d; i++)
- (*elements)[i] = NULL;
- ArrayLiteralExp *ae = new ArrayLiteralExp(Loc(), this, elementinit, elements);
- return ae;
-}
-
-bool TypeSArray::hasPointers()
-{
- /* Don't want to do this, because:
- * struct S { T* array[0]; }
- * may be a variable length struct.
- */
- //if (dim->toInteger() == 0)
- // return false;
-
- if (next->ty == Tvoid)
- {
- // Arrays of void contain arbitrary data, which may include pointers
- return true;
- }
- else
- return next->hasPointers();
-}
-
-/***************************** TypeDArray *****************************/
-
-TypeDArray::TypeDArray(Type *t)
- : TypeArray(Tarray, t)
-{
- //printf("TypeDArray(t = %p)\n", t);
-}
-
-const char *TypeDArray::kind()
-{
- return "darray";
-}
-
-Type *TypeDArray::syntaxCopy()
-{
- Type *t = next->syntaxCopy();
- if (t == next)
- t = this;
- else
- {
- t = new TypeDArray(t);
- t->mod = mod;
- }
- return t;
-}
-
-d_uns64 TypeDArray::size(Loc)
-{
- //printf("TypeDArray::size()\n");
- return target.ptrsize * 2;
-}
-
-unsigned TypeDArray::alignsize()
-{
- // A DArray consists of two ptr-sized values, so align it on pointer size
- // boundary
- return target.ptrsize;
-}
-
-void TypeDArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
-{
- //printf("TypeDArray::resolve() %s\n", toChars());
- next->resolve(loc, sc, pe, pt, ps, intypeid);
- //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt);
- if (*pe)
- {
- // It's really a slice expression
- if (Dsymbol *s = getDsymbol(*pe))
- *pe = new DsymbolExp(loc, s);
- *pe = new ArrayExp(loc, *pe);
- }
- else if (*ps)
- {
- TupleDeclaration *td = (*ps)->isTupleDeclaration();
- if (td)
- ; // keep *ps
- else
- goto Ldefault;
- }
- else
- {
- if ((*pt)->ty != Terror)
- next = *pt; // prevent re-running semantic() on 'next'
- Ldefault:
- Type::resolve(loc, sc, pe, pt, ps, intypeid);
- }
-}
-
-Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- if (e->op == TOKtype &&
- (ident == Id::length || ident == Id::ptr))
- {
- e->error("%s is not an expression", e->toChars());
- return new ErrorExp();
- }
- if (ident == Id::length)
- {
- if (e->op == TOKstring)
- {
- StringExp *se = (StringExp *)e;
- return new IntegerExp(se->loc, se->len, Type::tsize_t);
- }
- if (e->op == TOKnull)
- return new IntegerExp(e->loc, 0, Type::tsize_t);
- if (checkNonAssignmentArrayOp(e))
- return new ErrorExp();
- e = new ArrayLengthExp(e->loc, e);
- e->type = Type::tsize_t;
- return e;
- }
- else if (ident == Id::ptr)
- {
- if (!(flag & 2) && sc->func && !sc->intypeof && sc->func->setUnsafe())
- {
- e->deprecation("%s.ptr cannot be used in @safe code, use &%s[0] instead", e->toChars(), e->toChars());
- // return new ErrorExp();
- }
- e = e->castTo(sc, next->pointerTo());
- return e;
- }
- else
- {
- e = TypeArray::dotExp(sc, e, ident, flag);
- }
- return e;
-}
-
-bool TypeDArray::isString()
-{
- TY nty = next->toBasetype()->ty;
- return nty == Tchar || nty == Twchar || nty == Tdchar;
-}
-
-MATCH TypeDArray::implicitConvTo(Type *to)
-{
- //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
- if (equals(to))
- return MATCHexact;
-
- if (to->ty == Tarray)
- {
- TypeDArray *ta = (TypeDArray *)to;
-
- if (!MODimplicitConv(next->mod, ta->next->mod))
- return MATCHnomatch; // not const-compatible
-
- /* Allow conversion to void[]
- */
- if (next->ty != Tvoid && ta->next->ty == Tvoid)
- {
- return MATCHconvert;
- }
-
- MATCH m = next->constConv(ta->next);
- if (m > MATCHnomatch)
- {
- if (m == MATCHexact && mod != to->mod)
- m = MATCHconst;
- return m;
- }
- }
- return Type::implicitConvTo(to);
-}
-
-Expression *TypeDArray::defaultInit(Loc loc)
-{
- return new NullExp(loc, this);
-}
-
-bool TypeDArray::isZeroInit(Loc)
-{
- return true;
-}
-
-bool TypeDArray::isBoolean()
-{
- return true;
-}
-
-bool TypeDArray::hasPointers()
-{
- return true;
-}
-
-
-/***************************** TypeAArray *****************************/
-
-TypeAArray::TypeAArray(Type *t, Type *index)
- : TypeArray(Taarray, t)
-{
- this->index = index;
- this->loc = Loc();
- this->sc = NULL;
-}
-
-TypeAArray *TypeAArray::create(Type *t, Type *index)
-{
- return new TypeAArray(t, index);
-}
-
-const char *TypeAArray::kind()
-{
- return "aarray";
-}
-
-Type *TypeAArray::syntaxCopy()
-{
- Type *t = next->syntaxCopy();
- Type *ti = index->syntaxCopy();
- if (t == next && ti == index)
- t = this;
- else
- {
- t = new TypeAArray(t, ti);
- t->mod = mod;
- }
- return t;
-}
-
-d_uns64 TypeAArray::size(Loc)
-{
- return target.ptrsize;
-}
-
-void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
-{
- //printf("TypeAArray::resolve() %s\n", toChars());
-
- // Deal with the case where we thought the index was a type, but
- // in reality it was an expression.
- if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray)
- {
- Expression *e;
- Type *t;
- Dsymbol *s;
-
- index->resolve(loc, sc, &e, &t, &s, intypeid);
- if (e)
- {
- // It was an expression -
- // Rewrite as a static array
- TypeSArray *tsa = new TypeSArray(next, e);
- tsa->mod = this->mod; // just copy mod field so tsa's semantic is not yet done
- return tsa->resolve(loc, sc, pe, pt, ps, intypeid);
- }
- else if (t)
- index = t;
- else
- index->error(loc, "index is not a type or an expression");
- }
- Type::resolve(loc, sc, pe, pt, ps, intypeid);
-}
-
-
-Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- if (ident == Id::length)
- {
- static FuncDeclaration *fd_aaLen = NULL;
- if (fd_aaLen == NULL)
- {
- Parameters *fparams = new Parameters();
- fparams->push(new Parameter(STCin, this, NULL, NULL, NULL));
- fd_aaLen = FuncDeclaration::genCfunc(fparams, Type::tsize_t, Id::aaLen);
- TypeFunction *tf = fd_aaLen->type->toTypeFunction();
- tf->purity = PUREconst;
- tf->isnothrow = true;
- tf->isnogc = false;
- }
- Expression *ev = new VarExp(e->loc, fd_aaLen, false);
- e = new CallExp(e->loc, ev, e);
- e->type = fd_aaLen->type->toTypeFunction()->next;
- }
- else
- e = Type::dotExp(sc, e, ident, flag);
- return e;
-}
-
-Expression *TypeAArray::defaultInit(Loc loc)
-{
- return new NullExp(loc, this);
-}
-
-bool TypeAArray::isZeroInit(Loc)
-{
- return true;
-}
-
-bool TypeAArray::isBoolean()
-{
- return true;
-}
-
-bool TypeAArray::hasPointers()
-{
- return true;
-}
-
-MATCH TypeAArray::implicitConvTo(Type *to)
-{
- //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars());
- if (equals(to))
- return MATCHexact;
-
- if (to->ty == Taarray)
- { TypeAArray *ta = (TypeAArray *)to;
-
- if (!MODimplicitConv(next->mod, ta->next->mod))
- return MATCHnomatch; // not const-compatible
-
- if (!MODimplicitConv(index->mod, ta->index->mod))
- return MATCHnomatch; // not const-compatible
-
- MATCH m = next->constConv(ta->next);
- MATCH mi = index->constConv(ta->index);
- if (m > MATCHnomatch && mi > MATCHnomatch)
- {
- return MODimplicitConv(mod, to->mod) ? MATCHconst : MATCHnomatch;
- }
- }
- return Type::implicitConvTo(to);
-}
-
-MATCH TypeAArray::constConv(Type *to)
-{
- if (to->ty == Taarray)
- {
- TypeAArray *taa = (TypeAArray *)to;
- MATCH mindex = index->constConv(taa->index);
- MATCH mkey = next->constConv(taa->next);
- // Pick the worst match
- return mkey < mindex ? mkey : mindex;
- }
- return Type::constConv(to);
-}
-
-/***************************** TypePointer *****************************/
-
-TypePointer::TypePointer(Type *t)
- : TypeNext(Tpointer, t)
-{
-}
-
-TypePointer *TypePointer::create(Type *t)
-{
- return new TypePointer(t);
-}
-
-const char *TypePointer::kind()
-{
- return "pointer";
-}
-
-Type *TypePointer::syntaxCopy()
-{
- Type *t = next->syntaxCopy();
- if (t == next)
- t = this;
- else
- {
- t = new TypePointer(t);
- t->mod = mod;
- }
- return t;
-}
-
-d_uns64 TypePointer::size(Loc)
-{
- return target.ptrsize;
-}
-
-MATCH TypePointer::implicitConvTo(Type *to)
-{
- //printf("TypePointer::implicitConvTo(to = %s) %s\n", to->toChars(), toChars());
-
- if (equals(to))
- return MATCHexact;
- if (next->ty == Tfunction)
- {
- if (to->ty == Tpointer)
- {
- TypePointer *tp = (TypePointer *)to;
- if (tp->next->ty == Tfunction)
- {
- if (next->equals(tp->next))
- return MATCHconst;
-
- if (next->covariant(tp->next) == 1)
- {
- Type *tret = this->next->nextOf();
- Type *toret = tp->next->nextOf();
- if (tret->ty == Tclass && toret->ty == Tclass)
- {
- /* Bugzilla 10219: Check covariant interface return with offset tweaking.
- * interface I {}
- * class C : Object, I {}
- * I function() dg = function C() {} // should be error
- */
- int offset = 0;
- if (toret->isBaseOf(tret, &offset) && offset != 0)
- return MATCHnomatch;
- }
- return MATCHconvert;
- }
- }
- else if (tp->next->ty == Tvoid)
- {
- // Allow conversions to void*
- return MATCHconvert;
- }
- }
- return MATCHnomatch;
- }
- else if (to->ty == Tpointer)
- {
- TypePointer *tp = (TypePointer *)to;
- assert(tp->next);
-
- if (!MODimplicitConv(next->mod, tp->next->mod))
- return MATCHnomatch; // not const-compatible
-
- /* Alloc conversion to void*
- */
- if (next->ty != Tvoid && tp->next->ty == Tvoid)
- {
- return MATCHconvert;
- }
-
- MATCH m = next->constConv(tp->next);
- if (m > MATCHnomatch)
- {
- if (m == MATCHexact && mod != to->mod)
- m = MATCHconst;
- return m;
- }
- }
- return MATCHnomatch;
-}
-
-MATCH TypePointer::constConv(Type *to)
-{
- if (next->ty == Tfunction)
- {
- if (to->nextOf() && next->equals(((TypeNext *)to)->next))
- return Type::constConv(to);
- else
- return MATCHnomatch;
- }
- return TypeNext::constConv(to);
-}
-
-bool TypePointer::isscalar()
-{
- return true;
-}
-
-Expression *TypePointer::defaultInit(Loc loc)
-{
- return new NullExp(loc, this);
-}
-
-bool TypePointer::isZeroInit(Loc)
-{
- return true;
-}
-
-bool TypePointer::hasPointers()
-{
- return true;
-}
-
-
-/***************************** TypeReference *****************************/
-
-TypeReference::TypeReference(Type *t)
- : TypeNext(Treference, t)
-{
- // BUG: what about references to static arrays?
-}
-
-const char *TypeReference::kind()
-{
- return "reference";
-}
-
-Type *TypeReference::syntaxCopy()
-{
- Type *t = next->syntaxCopy();
- if (t == next)
- t = this;
- else
- {
- t = new TypeReference(t);
- t->mod = mod;
- }
- return t;
-}
-
-d_uns64 TypeReference::size(Loc)
-{
- return target.ptrsize;
-}
-
-Expression *TypeReference::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- // References just forward things along
- return next->dotExp(sc, e, ident, flag);
-}
-
-Expression *TypeReference::defaultInit(Loc loc)
-{
- return new NullExp(loc, this);
-}
-
-bool TypeReference::isZeroInit(Loc)
-{
- return true;
-}
-
-
-/***************************** TypeFunction *****************************/
-
-TypeFunction::TypeFunction(const ParameterList &pl, Type *treturn, LINK linkage, StorageClass stc)
- : TypeNext(Tfunction, treturn)
-{
-//if (!treturn) *(char*)0=0;
-// assert(treturn);
- assert(VARARGnone <= pl.varargs && pl.varargs <= VARARGtypesafe);
- this->parameterList = pl;
- this->linkage = linkage;
- this->inuse = 0;
- this->isnothrow = false;
- this->isnogc = false;
- this->purity = PUREimpure;
- this->isproperty = false;
- this->isref = false;
- this->isreturn = false;
- this->isscope = false;
- this->isscopeinferred = false;
- this->iswild = 0;
- this->fargs = NULL;
-
- if (stc & STCpure)
- this->purity = PUREfwdref;
- if (stc & STCnothrow)
- this->isnothrow = true;
- if (stc & STCnogc)
- this->isnogc = true;
- if (stc & STCproperty)
- this->isproperty = true;
-
- if (stc & STCref)
- this->isref = true;
- if (stc & STCreturn)
- this->isreturn = true;
- if (stc & STCscope)
- this->isscope = true;
- if (stc & STCscopeinferred)
- this->isscopeinferred = true;
-
- this->trust = TRUSTdefault;
- if (stc & STCsafe)
- this->trust = TRUSTsafe;
- if (stc & STCsystem)
- this->trust = TRUSTsystem;
- if (stc & STCtrusted)
- this->trust = TRUSTtrusted;
-}
-
-TypeFunction *TypeFunction::create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc)
-{
- return new TypeFunction(ParameterList(parameters, varargs), treturn, linkage, stc);
-}
-
-const char *TypeFunction::kind()
-{
- return "function";
-}
-
-Type *TypeFunction::syntaxCopy()
-{
- Type *treturn = next ? next->syntaxCopy() : NULL;
- Parameters *parameters = Parameter::arraySyntaxCopy(parameterList.parameters);
- TypeFunction *t = new TypeFunction(ParameterList(parameters, parameterList.varargs),
- treturn, linkage);
- t->mod = mod;
- t->isnothrow = isnothrow;
- t->isnogc = isnogc;
- t->purity = purity;
- t->isproperty = isproperty;
- t->isref = isref;
- t->isreturn = isreturn;
- t->isscope = isscope;
- t->isscopeinferred = isscopeinferred;
- t->iswild = iswild;
- t->trust = trust;
- t->fargs = fargs;
- return t;
-}
-
-/*******************************
- * Covariant means that 'this' can substitute for 't',
- * i.e. a pure function is a match for an impure type.
- * Params:
- * t = type 'this' is covariant with
- * pstc = if not null, store STCxxxx which would make it covariant
- * fix17349 = enable fix https://issues.dlang.org/show_bug.cgi?id=17349
- * Returns:
- * 0 types are distinct
- * 1 this is covariant with t
- * 2 arguments match as far as overloading goes,
- * but types are not covariant
- * 3 cannot determine covariance because of forward references
- * *pstc STCxxxx which would make it covariant
- */
-
-int Type::covariant(Type *t, StorageClass *pstc, bool fix17349)
-{
- if (pstc)
- *pstc = 0;
- StorageClass stc = 0;
-
- bool notcovariant = false;
-
- TypeFunction *t1;
- TypeFunction *t2;
-
- if (equals(t))
- return 1; // covariant
-
- if (ty != Tfunction || t->ty != Tfunction)
- goto Ldistinct;
-
- t1 = (TypeFunction *)this;
- t2 = (TypeFunction *)t;
-
- if (t1->parameterList.varargs != t2->parameterList.varargs)
- goto Ldistinct;
-
- if (t1->parameterList.parameters && t2->parameterList.parameters)
- {
- size_t dim = t1->parameterList.length();
- if (dim != t2->parameterList.length())
- goto Ldistinct;
-
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *fparam1 = t1->parameterList[i];
- Parameter *fparam2 = t2->parameterList[i];
-
- if (!fparam1->type->equals(fparam2->type))
- {
- if (!fix17349)
- goto Ldistinct;
- Type *tp1 = fparam1->type;
- Type *tp2 = fparam2->type;
- if (tp1->ty == tp2->ty)
- {
- if (tp1->ty == Tclass)
- {
- if (((TypeClass *)tp1)->sym == ((TypeClass *)tp2)->sym && MODimplicitConv(tp2->mod, tp1->mod))
- goto Lcov;
- }
- else if (tp1->ty == Tstruct)
- {
- if (((TypeStruct *)tp1)->sym == ((TypeStruct *)tp2)->sym && MODimplicitConv(tp2->mod, tp1->mod))
- goto Lcov;
- }
- else if (tp1->ty == Tpointer)
- {
- if (tp2->implicitConvTo(tp1))
- goto Lcov;
- }
- else if (tp1->ty == Tarray)
- {
- if (tp2->implicitConvTo(tp1))
- goto Lcov;
- }
- else if (tp1->ty == Tdelegate)
- {
- if (tp1->implicitConvTo(tp2))
- goto Lcov;
- }
- }
- goto Ldistinct;
- }
- Lcov:
- notcovariant |= !fparam1->isCovariant(t1->isref, fparam2);
- }
- }
- else if (t1->parameterList.parameters != t2->parameterList.parameters)
- {
- size_t dim1 = t1->parameterList.length();
- size_t dim2 = t2->parameterList.length();
- if (dim1 || dim2)
- goto Ldistinct;
- }
-
- // The argument lists match
- if (notcovariant)
- goto Lnotcovariant;
- if (t1->linkage != t2->linkage)
- goto Lnotcovariant;
-
- {
- // Return types
- Type *t1n = t1->next;
- Type *t2n = t2->next;
-
- if (!t1n || !t2n) // happens with return type inference
- goto Lnotcovariant;
-
- if (t1n->equals(t2n))
- goto Lcovariant;
- if (t1n->ty == Tclass && t2n->ty == Tclass)
- {
- /* If same class type, but t2n is const, then it's
- * covariant. Do this test first because it can work on
- * forward references.
- */
- if (((TypeClass *)t1n)->sym == ((TypeClass *)t2n)->sym &&
- MODimplicitConv(t1n->mod, t2n->mod))
- goto Lcovariant;
-
- // If t1n is forward referenced:
- ClassDeclaration *cd = ((TypeClass *)t1n)->sym;
- if (cd->semanticRun < PASSsemanticdone && !cd->isBaseInfoComplete())
- dsymbolSemantic(cd, NULL);
- if (!cd->isBaseInfoComplete())
- {
- return 3; // forward references
- }
- }
- if (t1n->ty == Tstruct && t2n->ty == Tstruct)
- {
- if (((TypeStruct *)t1n)->sym == ((TypeStruct *)t2n)->sym &&
- MODimplicitConv(t1n->mod, t2n->mod))
- goto Lcovariant;
- }
- else if (t1n->ty == t2n->ty && t1n->implicitConvTo(t2n))
- goto Lcovariant;
- else if (t1n->ty == Tnull)
- {
- // NULL is covariant with any pointer type, but not with any
- // dynamic arrays, associative arrays or delegates.
- // https://issues.dlang.org/show_bug.cgi?id=8589
- // https://issues.dlang.org/show_bug.cgi?id=19618
- Type *t2bn = t2n->toBasetype();
- if (t2bn->ty == Tnull || t2bn->ty == Tpointer || t2bn->ty == Tclass)
- goto Lcovariant;
- }
- }
- goto Lnotcovariant;
-
-Lcovariant:
- if (t1->isref != t2->isref)
- goto Lnotcovariant;
-
- if (!t1->isref && (t1->isscope || t2->isscope))
- {
- StorageClass stc1 = t1->isscope ? STCscope : 0;
- StorageClass stc2 = t2->isscope ? STCscope : 0;
- if (t1->isreturn)
- {
- stc1 |= STCreturn;
- if (!t1->isscope)
- stc1 |= STCref;
- }
- if (t2->isreturn)
- {
- stc2 |= STCreturn;
- if (!t2->isscope)
- stc2 |= STCref;
- }
- if (!Parameter::isCovariantScope(t1->isref, stc1, stc2))
- goto Lnotcovariant;
- }
-
- // We can subtract 'return ref' from 'this', but cannot add it
- else if (t1->isreturn && !t2->isreturn)
- goto Lnotcovariant;
-
- /* Can convert mutable to const
- */
- if (!MODimplicitConv(t2->mod, t1->mod))
- {
- goto Ldistinct;
- }
-
- /* Can convert pure to impure, nothrow to throw, and nogc to gc
- */
- if (!t1->purity && t2->purity)
- stc |= STCpure;
-
- if (!t1->isnothrow && t2->isnothrow)
- stc |= STCnothrow;
-
- if (!t1->isnogc && t2->isnogc)
- stc |= STCnogc;
-
- /* Can convert safe/trusted to system
- */
- if (t1->trust <= TRUSTsystem && t2->trust >= TRUSTtrusted)
- {
- // Should we infer trusted or safe? Go with safe.
- stc |= STCsafe;
- }
-
- if (stc)
- { if (pstc)
- *pstc = stc;
- goto Lnotcovariant;
- }
-
- //printf("\tcovaraint: 1\n");
- return 1;
-
-Ldistinct:
- //printf("\tcovaraint: 0\n");
- return 0;
-
-Lnotcovariant:
- //printf("\tcovaraint: 2\n");
- return 2;
-}
-
-bool TypeFunction::checkRetType(Loc loc)
-{
- Type *tb = next->toBasetype();
- if (tb->ty == Tfunction)
- {
- error(loc, "functions cannot return a function");
- next = Type::terror;
- }
- if (tb->ty == Ttuple)
- {
- error(loc, "functions cannot return a tuple");
- next = Type::terror;
- }
- if (!isref && (tb->ty == Tstruct || tb->ty == Tsarray))
- {
- Type *tb2 = tb->baseElemOf();
- if (tb2->ty == Tstruct && !((TypeStruct *)tb2)->sym->members)
- {
- error(loc, "functions cannot return opaque type %s by value", tb->toChars());
- next = Type::terror;
- }
- }
- if (tb->ty == Terror)
- return true;
-
- return false;
-}
-
-/* Determine purity level based on mutability of t
- * and whether it is a 'ref' type or not.
- */
-static PURE purityOfType(bool isref, Type *t)
-{
- if (isref)
- {
- if (t->mod & MODimmutable)
- return PUREstrong;
- if (t->mod & (MODconst | MODwild))
- return PUREconst;
- return PUREweak;
- }
-
- t = t->baseElemOf();
-
- if (!t->hasPointers() || t->mod & MODimmutable)
- return PUREstrong;
-
- /* Accept immutable(T)[] and immutable(T)* as being strongly pure
- */
- if (t->ty == Tarray || t->ty == Tpointer)
- {
- Type *tn = t->nextOf()->toBasetype();
- if (tn->mod & MODimmutable)
- return PUREstrong;
- if (tn->mod & (MODconst | MODwild))
- return PUREconst;
- }
-
- /* The rest of this is too strict; fix later.
- * For example, the only pointer members of a struct may be immutable,
- * which would maintain strong purity.
- * (Just like for dynamic arrays and pointers above.)
- */
- if (t->mod & (MODconst | MODwild))
- return PUREconst;
-
- /* Should catch delegates and function pointers, and fold in their purity
- */
- return PUREweak;
-}
-
-/********************************************
- * Set 'purity' field of 'this'.
- * Do this lazily, as the parameter types might be forward referenced.
- */
-void TypeFunction::purityLevel()
-{
- TypeFunction *tf = this;
- if (tf->purity != PUREfwdref)
- return;
-
- purity = PUREstrong; // assume strong until something weakens it
-
- /* Evaluate what kind of purity based on the modifiers for the parameters
- */
- const size_t dim = tf->parameterList.length();
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *fparam = tf->parameterList[i];
- Type *t = fparam->type;
- if (!t)
- continue;
-
- if (fparam->storageClass & (STClazy | STCout))
- {
- purity = PUREweak;
- break;
- }
- switch (purityOfType((fparam->storageClass & STCref) != 0, t))
- {
- case PUREweak:
- purity = PUREweak;
- break;
-
- case PUREconst:
- purity = PUREconst;
- continue;
-
- case PUREstrong:
- continue;
-
- default:
- assert(0);
- }
- break; // since PUREweak, no need to check further
- }
-
- if (purity > PUREweak && tf->nextOf())
- {
- /* Adjust purity based on mutability of return type.
- * https://issues.dlang.org/show_bug.cgi?id=15862
- */
- const PURE purity2 = purityOfType(tf->isref, tf->nextOf());
- if (purity2 < purity)
- purity = purity2;
- }
- tf->purity = purity;
-}
-
-// arguments get specially formatted
-static const char *getParamError(TypeFunction *tf, Expression *arg, Parameter *par)
-{
- if (global.gag && !global.params.showGaggedErrors)
- return NULL;
- // show qualification when toChars() is the same but types are different
- const char *at = arg->type->toChars();
- bool qual = !arg->type->equals(par->type) && strcmp(at, par->type->toChars()) == 0;
- if (qual)
- at = arg->type->toPrettyChars(true);
- OutBuffer buf;
- // only mention rvalue if it's relevant
- const bool rv = !arg->isLvalue() && (par->storageClass & (STCref | STCout)) != 0;
- buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
- rv ? "rvalue " : "", arg->toChars(), at,
- parameterToChars(par, tf, qual));
- return buf.extractChars();
-}
-
-static const char *getMatchError(const char *format, ...)
-{
- if (global.gag && !global.params.showGaggedErrors)
- return NULL;
- OutBuffer buf;
- va_list ap;
- va_start(ap, format);
- buf.vprintf(format, ap);
- va_end(ap);
- return buf.extractChars();
-}
-
-/********************************
- * 'args' are being matched to function 'this'
- * Determine match level.
- * Input:
- * flag 1 performing a partial ordering match
- * pMessage address to store error message, or null
- * Returns:
- * MATCHxxxx
- */
-
-MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag, const char **pMessage)
-{
- //printf("TypeFunction::callMatch() %s\n", toChars());
- MATCH match = MATCHexact; // assume exact match
- unsigned char wildmatch = 0;
-
- if (tthis)
- {
- Type *t = tthis;
- if (t->toBasetype()->ty == Tpointer)
- t = t->toBasetype()->nextOf(); // change struct* to struct
- if (t->mod != mod)
- {
- if (MODimplicitConv(t->mod, mod))
- match = MATCHconst;
- else if ((mod & MODwild) && MODimplicitConv(t->mod, (mod & ~MODwild) | MODconst))
- {
- match = MATCHconst;
- }
- else
- return MATCHnomatch;
- }
- if (isWild())
- {
- if (t->isWild())
- wildmatch |= MODwild;
- else if (t->isConst())
- wildmatch |= MODconst;
- else if (t->isImmutable())
- wildmatch |= MODimmutable;
- else
- wildmatch |= MODmutable;
- }
- }
-
- size_t nparams = parameterList.length();
- size_t nargs = args ? args->length : 0;
- if (nargs > nparams)
- {
- if (parameterList.varargs == VARARGnone)
- {
- // suppress early exit if an error message is wanted,
- // so we can check any matching args are valid
- if (!pMessage)
- goto Nomatch; // too many args; no match
- }
- match = MATCHconvert; // match ... with a "conversion" match level
- }
-
- for (size_t u = 0; u < nargs; u++)
- {
- if (u >= nparams)
- break;
- Parameter *p = parameterList[u];
- Expression *arg = (*args)[u];
- assert(arg);
- Type *tprm = p->type;
- Type *targ = arg->type;
-
- if (!(p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid))
- {
- bool isRef = (p->storageClass & (STCref | STCout)) != 0;
- wildmatch |= targ->deduceWild(tprm, isRef);
- }
- }
- if (wildmatch)
- {
- /* Calculate wild matching modifier
- */
- if (wildmatch & MODconst || wildmatch & (wildmatch - 1))
- wildmatch = MODconst;
- else if (wildmatch & MODimmutable)
- wildmatch = MODimmutable;
- else if (wildmatch & MODwild)
- wildmatch = MODwild;
- else
- {
- assert(wildmatch & MODmutable);
- wildmatch = MODmutable;
- }
- }
-
- for (size_t u = 0; u < nparams; u++)
- {
- MATCH m;
-
- Parameter *p = parameterList[u];
- assert(p);
- if (u >= nargs)
- {
- if (p->defaultArg)
- continue;
- goto L1; // try typesafe variadics
- }
- {
- Expression *arg = (*args)[u];
- assert(arg);
- //printf("arg: %s, type: %s\n", arg->toChars(), arg->type->toChars());
-
- Type *targ = arg->type;
- Type *tprm = wildmatch ? p->type->substWildTo(wildmatch) : p->type;
-
- if (p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid)
- m = MATCHconvert;
- else
- {
- //printf("%s of type %s implicitConvTo %s\n", arg->toChars(), targ->toChars(), tprm->toChars());
- if (flag)
- {
- // for partial ordering, value is an irrelevant mockup, just look at the type
- m = targ->implicitConvTo(tprm);
- }
- else
- m = arg->implicitConvTo(tprm);
- //printf("match %d\n", m);
- }
-
- // Non-lvalues do not match ref or out parameters
- if (p->storageClass & (STCref | STCout))
- {
- // Bugzilla 13783: Don't use toBasetype() to handle enum types.
- Type *ta = targ;
- Type *tp = tprm;
- //printf("fparam[%d] ta = %s, tp = %s\n", u, ta->toChars(), tp->toChars());
-
- if (m && !arg->isLvalue())
- {
- if (p->storageClass & STCout)
- {
- if (pMessage) *pMessage = getParamError(this, arg, p);
- goto Nomatch;
- }
-
- if (arg->op == TOKstring && tp->ty == Tsarray)
- {
- if (ta->ty != Tsarray)
- {
- Type *tn = tp->nextOf()->castMod(ta->nextOf()->mod);
- dinteger_t dim = ((StringExp *)arg)->len;
- ta = tn->sarrayOf(dim);
- }
- }
- else if (arg->op == TOKslice && tp->ty == Tsarray)
- {
- // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
- if (ta->ty != Tsarray)
- {
- Type *tn = ta->nextOf();
- dinteger_t dim = ((TypeSArray *)tp)->dim->toUInteger();
- ta = tn->sarrayOf(dim);
- }
- }
- else
- {
- if (pMessage) *pMessage = getParamError(this, arg, p);
- goto Nomatch;
- }
- }
-
- /* Find most derived alias this type being matched.
- * Bugzilla 15674: Allow on both ref and out parameters.
- */
- while (1)
- {
- Type *tat = ta->toBasetype()->aliasthisOf();
- if (!tat || !tat->implicitConvTo(tprm))
- break;
- ta = tat;
- }
-
- /* A ref variable should work like a head-const reference.
- * e.g. disallows:
- * ref T <- an lvalue of const(T) argument
- * ref T[dim] <- an lvalue of const(T[dim]) argument
- */
- if (!ta->constConv(tp))
- {
- if (pMessage) *pMessage = getParamError(this, arg, p);
- goto Nomatch;
- }
- }
- }
-
- /* prefer matching the element type rather than the array
- * type when more arguments are present with T[]...
- */
- if (parameterList.varargs == VARARGtypesafe && u + 1 == nparams && nargs > nparams)
- goto L1;
-
- //printf("\tm = %d\n", m);
- if (m == MATCHnomatch) // if no match
- {
- L1:
- if (parameterList.varargs == VARARGtypesafe && u + 1 == nparams) // if last varargs param
- {
- Type *tb = p->type->toBasetype();
- TypeSArray *tsa;
- dinteger_t sz;
-
- switch (tb->ty)
- {
- case Tsarray:
- tsa = (TypeSArray *)tb;
- sz = tsa->dim->toInteger();
- if (sz != nargs - u)
- {
- if (pMessage)
- *pMessage = getMatchError("expected %llu variadic argument(s), not %zu", sz, nargs - u);
- goto Nomatch;
- }
- /* fall through */
- case Tarray:
- {
- TypeArray *ta = (TypeArray *)tb;
- for (; u < nargs; u++)
- {
- Expression *arg = (*args)[u];
- assert(arg);
-
- /* If lazy array of delegates,
- * convert arg(s) to delegate(s)
- */
- Type *tret = p->isLazyArray();
- if (tret)
- {
- if (ta->next->equals(arg->type))
- m = MATCHexact;
- else if (tret->toBasetype()->ty == Tvoid)
- m = MATCHconvert;
- else
- {
- m = arg->implicitConvTo(tret);
- if (m == MATCHnomatch)
- m = arg->implicitConvTo(ta->next);
- }
- }
- else
- m = arg->implicitConvTo(ta->next);
-
- if (m == MATCHnomatch)
- {
- if (pMessage) *pMessage = getParamError(this, arg, p);
- goto Nomatch;
- }
- if (m < match)
- match = m;
- }
- goto Ldone;
- }
- case Tclass:
- // Should see if there's a constructor match?
- // Or just leave it ambiguous?
- goto Ldone;
-
- default:
- break;
- }
- }
- if (pMessage && u < nargs)
- *pMessage = getParamError(this, (*args)[u], p);
- else if (pMessage)
- *pMessage = getMatchError("missing argument for parameter #%d: `%s`",
- u + 1, parameterToChars(p, this, false));
- goto Nomatch;
- }
- if (m < match)
- match = m; // pick worst match
- }
-
-Ldone:
- if (pMessage && !parameterList.varargs && nargs > nparams)
- {
- // all parameters had a match, but there are surplus args
- *pMessage = getMatchError("expected %d argument(s), not %d", nparams, nargs);
- goto Nomatch;
- }
- //printf("match = %d\n", match);
- return match;
-
-Nomatch:
- //printf("no match\n");
- return MATCHnomatch;
-}
-
-/********************************************
- * Return true if there are lazy parameters.
- */
-bool TypeFunction::hasLazyParameters()
-{
- size_t dim = parameterList.length();
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *fparam = parameterList[i];
- if (fparam->storageClass & STClazy)
- return true;
- }
- return false;
-}
-
-/*******************************
- * Check for `extern (D) U func(T t, ...)` variadic function type,
- * which has `_arguments[]` added as the first argument.
- * Returns:
- * true if D-style variadic
- */
-bool TypeFunction::isDstyleVariadic() const
-{
- return linkage == LINKd && parameterList.varargs == VARARGvariadic;
-}
-
-/***************************
- * Examine function signature for parameter p and see if
- * the value of p can 'escape' the scope of the function.
- * This is useful to minimize the needed annotations for the parameters.
- * Params:
- * p = parameter to this function
- * Returns:
- * true if escapes via assignment to global or through a parameter
- */
-
-bool TypeFunction::parameterEscapes(Parameter *p)
-{
- /* Scope parameters do not escape.
- * Allow 'lazy' to imply 'scope' -
- * lazy parameters can be passed along
- * as lazy parameters to the next function, but that isn't
- * escaping.
- */
- if (parameterStorageClass(p) & (STCscope | STClazy))
- return false;
- return true;
-}
-
-/************************************
- * Take the specified storage class for p,
- * and use the function signature to infer whether
- * STCscope and STCreturn should be OR'd in.
- * (This will not affect the name mangling.)
- * Params:
- * p = one of the parameters to 'this'
- * Returns:
- * storage class with STCscope or STCreturn OR'd in
- */
-StorageClass TypeFunction::parameterStorageClass(Parameter *p)
-{
- StorageClass stc = p->storageClass;
- if (!global.params.vsafe)
- return stc;
-
- if (stc & (STCscope | STCreturn | STClazy) || purity == PUREimpure)
- return stc;
-
- /* If haven't inferred the return type yet, can't infer storage classes
- */
- if (!nextOf())
- return stc;
-
- purityLevel();
-
- // See if p can escape via any of the other parameters
- if (purity == PUREweak)
- {
- const size_t dim = parameterList.length();
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *fparam = parameterList[i];
- Type *t = fparam->type;
- if (!t)
- continue;
- t = t->baseElemOf();
- if (t->isMutable() && t->hasPointers())
- {
- if (fparam->storageClass & (STCref | STCout))
- {
- }
- else if (t->ty == Tarray || t->ty == Tpointer)
- {
- Type *tn = t->nextOf()->toBasetype();
- if (!(tn->isMutable() && tn->hasPointers()))
- continue;
- }
- return stc;
- }
- }
- }
-
- stc |= STCscope;
-
- /* Inferring STCreturn here has false positives
- * for pure functions, producing spurious error messages
- * about escaping references.
- * Give up on it for now.
- */
- return stc;
-}
-
-Expression *TypeFunction::defaultInit(Loc loc)
-{
- error(loc, "function does not have a default initializer");
- return new ErrorExp();
-}
-
-Type *TypeFunction::addStorageClass(StorageClass stc)
-{
- //printf("addStorageClass(%llx) %d\n", stc, (stc & STCscope) != 0);
- TypeFunction *t = Type::addStorageClass(stc)->toTypeFunction();
- if ((stc & STCpure && !t->purity) ||
- (stc & STCnothrow && !t->isnothrow) ||
- (stc & STCnogc && !t->isnogc) ||
- (stc & STCscope && !t->isscope) ||
- (stc & STCsafe && t->trust < TRUSTtrusted))
- {
- // Klunky to change these
- TypeFunction *tf = new TypeFunction(t->parameterList, t->next, t->linkage, 0);
- tf->mod = t->mod;
- tf->fargs = fargs;
- tf->purity = t->purity;
- tf->isnothrow = t->isnothrow;
- tf->isnogc = t->isnogc;
- tf->isproperty = t->isproperty;
- tf->isref = t->isref;
- tf->isreturn = t->isreturn;
- tf->isscope = t->isscope;
- tf->isscopeinferred = t->isscopeinferred;
- tf->trust = t->trust;
- tf->iswild = t->iswild;
-
- if (stc & STCpure)
- tf->purity = PUREfwdref;
- if (stc & STCnothrow)
- tf->isnothrow = true;
- if (stc & STCnogc)
- tf->isnogc = true;
- if (stc & STCsafe)
- tf->trust = TRUSTsafe;
- if (stc & STCscope)
- {
- tf->isscope = true;
- if (stc & STCscopeinferred)
- tf->isscopeinferred = true;
- }
-
- tf->deco = tf->merge()->deco;
- t = tf;
- }
- return t;
-}
-
-/** For each active attribute (ref/const/nogc/etc) call fp with a void* for the
-work param and a string representation of the attribute. */
-int TypeFunction::attributesApply(void *param, int (*fp)(void *, const char *), TRUSTformat trustFormat)
-{
- int res = 0;
-
- if (purity) res = fp(param, "pure");
- if (res) return res;
-
- if (isnothrow) res = fp(param, "nothrow");
- if (res) return res;
-
- if (isnogc) res = fp(param, "@nogc");
- if (res) return res;
-
- if (isproperty) res = fp(param, "@property");
- if (res) return res;
-
- if (isref) res = fp(param, "ref");
- if (res) return res;
-
- if (isreturn) res = fp(param, "return");
- if (res) return res;
-
- if (isscope && !isscopeinferred) res = fp(param, "scope");
- if (res) return res;
-
- TRUST trustAttrib = trust;
-
- if (trustAttrib == TRUSTdefault)
- {
- // Print out "@system" when trust equals TRUSTdefault (if desired).
- if (trustFormat == TRUSTformatSystem)
- trustAttrib = TRUSTsystem;
- else
- return res; // avoid calling with an empty string
- }
-
- return fp(param, trustToChars(trustAttrib));
-}
-
-/***************************** TypeDelegate *****************************/
-
-TypeDelegate::TypeDelegate(Type *t)
- : TypeNext(Tfunction, t)
-{
- ty = Tdelegate;
-}
-
-TypeDelegate *TypeDelegate::create(Type *t)
-{
- return new TypeDelegate(t);
-}
-
-const char *TypeDelegate::kind()
-{
- return "delegate";
-}
-
-Type *TypeDelegate::syntaxCopy()
-{
- Type *t = next->syntaxCopy();
- if (t == next)
- t = this;
- else
- {
- t = new TypeDelegate(t);
- t->mod = mod;
- }
- return t;
-}
-
-Type *TypeDelegate::addStorageClass(StorageClass stc)
-{
- TypeDelegate *t = (TypeDelegate*)Type::addStorageClass(stc);
- if (!global.params.vsafe)
- return t;
-
- /* The rest is meant to add 'scope' to a delegate declaration if it is of the form:
- * alias dg_t = void* delegate();
- * scope dg_t dg = ...;
- */
- if (stc & STCscope)
- {
- Type *n = t->next->addStorageClass(STCscope | STCscopeinferred);
- if (n != t->next)
- {
- t->next = n;
- t->deco = t->merge()->deco; // mangling supposed to not be changed due to STCscopeinferrred
- }
- }
- return t;
-}
-
-d_uns64 TypeDelegate::size(Loc)
-{
- return target.ptrsize * 2;
-}
-
-unsigned TypeDelegate::alignsize()
-{
- return target.ptrsize;
-}
-
-MATCH TypeDelegate::implicitConvTo(Type *to)
-{
- //printf("TypeDelegate::implicitConvTo(this=%p, to=%p)\n", this, to);
- //printf("from: %s\n", toChars());
- //printf("to : %s\n", to->toChars());
- if (this == to)
- return MATCHexact;
-#if 1 // not allowing covariant conversions because it interferes with overriding
- if (to->ty == Tdelegate && this->nextOf()->covariant(to->nextOf()) == 1)
- {
- Type *tret = this->next->nextOf();
- Type *toret = ((TypeDelegate *)to)->next->nextOf();
- if (tret->ty == Tclass && toret->ty == Tclass)
- {
- /* Bugzilla 10219: Check covariant interface return with offset tweaking.
- * interface I {}
- * class C : Object, I {}
- * I delegate() dg = delegate C() {} // should be error
- */
- int offset = 0;
- if (toret->isBaseOf(tret, &offset) && offset != 0)
- return MATCHnomatch;
- }
- return MATCHconvert;
- }
-#endif
- return MATCHnomatch;
-}
-
-Expression *TypeDelegate::defaultInit(Loc loc)
-{
- return new NullExp(loc, this);
-}
-
-bool TypeDelegate::isZeroInit(Loc)
-{
- return true;
-}
-
-bool TypeDelegate::isBoolean()
-{
- return true;
-}
-
-Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- if (ident == Id::ptr)
- {
- e = new DelegatePtrExp(e->loc, e);
- e = expressionSemantic(e, sc);
- }
- else if (ident == Id::funcptr)
- {
- if (!(flag & 2) && sc->func && !sc->intypeof && sc->func->setUnsafe())
- {
- e->error("%s.funcptr cannot be used in @safe code", e->toChars());
- return new ErrorExp();
- }
- e = new DelegateFuncptrExp(e->loc, e);
- e = expressionSemantic(e, sc);
- }
- else
- {
- e = Type::dotExp(sc, e, ident, flag);
- }
- return e;
-}
-
-bool TypeDelegate::hasPointers()
-{
- return true;
-}
-
-/***************************** TypeTraits ********************************/
-
-TypeTraits::TypeTraits(const Loc &loc, TraitsExp *exp)
- : Type(Ttraits)
-{
- this->loc = loc;
- this->exp = exp;
- this->sym = NULL;
-}
-
-Type *TypeTraits::syntaxCopy()
-{
- TraitsExp *te = (TraitsExp *) exp->syntaxCopy();
- TypeTraits *tt = new TypeTraits(loc, te);
- tt->mod = mod;
- return tt;
-}
-
-Dsymbol *TypeTraits::toDsymbol(Scope *sc)
-{
- Type *t = NULL;
- Expression *e = NULL;
- Dsymbol *s = NULL;
- resolve(loc, sc, &e, &t, &s);
- if (t && t->ty != Terror)
- s = t->toDsymbol(sc);
- else if (e)
- s = getDsymbol(e);
-
- return s;
-}
-
-void TypeTraits::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool)
-{
- *pt = NULL;
- *pe = NULL;
- *ps = NULL;
-
- if (Type *t = typeSemantic(this, loc, sc))
- *pt = t;
- else if (sym)
- *ps = sym;
- else
- *pt = Type::terror;
-}
-
-d_uns64 TypeTraits::size(Loc)
-{
- return SIZE_INVALID;
-}
-
-/***************************** TypeMixin *****************************/
-
-/******
- * Implements mixin types.
- *
- * Semantic analysis will convert it to a real type.
- */
-TypeMixin::TypeMixin(const Loc &loc, Expressions *exps)
- : Type(Tmixin)
-{
- this->loc = loc;
- this->exps = exps;
- this->obj = NULL; // cached result of semantic analysis.
-}
-
-const char *TypeMixin::kind()
-{
- return "mixin";
-}
-
-Type *TypeMixin::syntaxCopy()
-{
- return new TypeMixin(loc, Expression::arraySyntaxCopy(exps));
-}
-
-Dsymbol *TypeMixin::toDsymbol(Scope *sc)
-{
- Type *t = NULL;
- Expression *e = NULL;
- Dsymbol *s = NULL;
- resolve(loc, sc, &e, &t, &s);
- if (t)
- s = t->toDsymbol(sc);
- else if (e)
- s = getDsymbol(e);
-
- return s;
-}
-
-void TypeMixin::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
-{
- // if already resolved just set pe/pt/ps and return.
- if (obj)
- {
- *pe = isExpression(obj);
- *pt = isType(obj);
- *ps = isDsymbol(obj);
- return;
- }
-
- RootObject *o = compileTypeMixin(this, loc, sc);
- if (Type *t = isType(o))
- {
- t->resolve(loc, sc, pe, pt, ps, intypeid);
- if (*pt)
- (*pt) = (*pt)->addMod(mod);
- }
- else if (Expression *e = isExpression(o))
- {
- e = expressionSemantic(e, sc);
- if (TypeExp *et = e->isTypeExp())
- {
- *pe = NULL;
- *pt = et->type->addMod(mod);
- *ps = NULL;
- }
- else
- {
- *pe = e;
- *pt = NULL;
- *ps = NULL;
- }
- }
- else
- {
- *pe = NULL;
- *pt = Type::terror;
- *ps = NULL;
- }
-
- // save the result
- obj = *pe ? (RootObject *)*pe : (*pt ? (RootObject *)*pt : (RootObject *)*ps);
-}
-
-/***************************** TypeQualified *****************************/
-
-TypeQualified::TypeQualified(TY ty, Loc loc)
- : Type(ty)
-{
- this->loc = loc;
-}
-
-void TypeQualified::syntaxCopyHelper(TypeQualified *t)
-{
- //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t->toChars(), toChars());
- idents.setDim(t->idents.length);
- for (size_t i = 0; i < idents.length; i++)
- {
- RootObject *id = t->idents[i];
- if (id->dyncast() == DYNCAST_DSYMBOL)
- {
- TemplateInstance *ti = (TemplateInstance *)id;
-
- ti = (TemplateInstance *)ti->syntaxCopy(NULL);
- id = ti;
- }
- else if (id->dyncast() == DYNCAST_EXPRESSION)
- {
- Expression *e = (Expression *)id;
- e = e->syntaxCopy();
- id = e;
- }
- else if (id->dyncast() == DYNCAST_TYPE)
- {
- Type *tx = (Type *)id;
- tx = tx->syntaxCopy();
- id = tx;
- }
- idents[i] = id;
- }
-}
-
-void TypeQualified::addIdent(Identifier *ident)
-{
- idents.push(ident);
-}
-
-void TypeQualified::addInst(TemplateInstance *inst)
-{
- idents.push(inst);
-}
-
-void TypeQualified::addIndex(RootObject *e)
-{
- idents.push(e);
-}
-
-d_uns64 TypeQualified::size(Loc)
-{
- error(this->loc, "size of type %s is not known", toChars());
- return SIZE_INVALID;
-}
-
-/*************************************
- * Resolve a tuple index.
- */
-void TypeQualified::resolveTupleIndex(Loc loc, Scope *sc, Dsymbol *s,
- Expression **pe, Type **pt, Dsymbol **ps, RootObject *oindex)
-{
- *pt = NULL;
- *ps = NULL;
- *pe = NULL;
-
- TupleDeclaration *td = s->isTupleDeclaration();
-
- Expression *eindex = isExpression(oindex);
- Type *tindex = isType(oindex);
- Dsymbol *sindex = isDsymbol(oindex);
-
- if (!td)
- {
- // It's really an index expression
- if (tindex)
- eindex = new TypeExp(loc, tindex);
- else if (sindex)
- eindex = ::resolve(loc, sc, sindex, false);
- Expression *e = new IndexExp(loc, ::resolve(loc, sc, s, false), eindex);
- e = expressionSemantic(e, sc);
- resolveExp(e, pt, pe, ps);
- return;
- }
-
- // Convert oindex to Expression, then try to resolve to constant.
- if (tindex)
- tindex->resolve(loc, sc, &eindex, &tindex, &sindex);
- if (sindex)
- eindex = ::resolve(loc, sc, sindex, false);
- if (!eindex)
- {
- ::error(loc, "index is %s not an expression", oindex->toChars());
- *pt = Type::terror;
- return;
- }
- sc = sc->startCTFE();
- eindex = expressionSemantic(eindex, sc);
- sc = sc->endCTFE();
-
- eindex = eindex->ctfeInterpret();
- if (eindex->op == TOKerror)
- {
- *pt = Type::terror;
- return;
- }
-
- const uinteger_t d = eindex->toUInteger();
- if (d >= td->objects->length)
- {
- ::error(loc, "tuple index %llu exceeds length %u", (ulonglong)d, (unsigned)td->objects->length);
- *pt = Type::terror;
- return;
- }
-
- RootObject *o = (*td->objects)[(size_t)d];
- *pt = isType(o);
- *ps = isDsymbol(o);
- *pe = isExpression(o);
-
- if (*pt)
- *pt = typeSemantic(*pt, loc, sc);
- if (*pe)
- resolveExp(*pe, pt, pe, ps);
-}
-
-/*************************************
- * Takes an array of Identifiers and figures out if
- * it represents a Type or an Expression.
- * Output:
- * if expression, *pe is set
- * if type, *pt is set
- */
-void TypeQualified::resolveHelper(Loc loc, Scope *sc,
- Dsymbol *s, Dsymbol *,
- Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
-{
- *pe = NULL;
- *pt = NULL;
- *ps = NULL;
- if (s)
- {
- //printf("\t1: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
- Declaration *d = s->isDeclaration();
- if (d && (d->storage_class & STCtemplateparameter))
- s = s->toAlias();
- else
- {
- // check for deprecated aliases
- s->checkDeprecated(loc, sc);
- if (d)
- d->checkDisabled(loc, sc, true);
- }
-
- s = s->toAlias();
- //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind());
- for (size_t i = 0; i < idents.length; i++)
- {
- RootObject *id = idents[i];
-
- if (id->dyncast() == DYNCAST_EXPRESSION ||
- id->dyncast() == DYNCAST_TYPE)
- {
- Type *tx;
- Expression *ex;
- Dsymbol *sx;
- resolveTupleIndex(loc, sc, s, &ex, &tx, &sx, id);
- if (sx)
- {
- s = sx->toAlias();
- continue;
- }
- if (tx)
- ex = new TypeExp(loc, tx);
- assert(ex);
-
- ex = typeToExpressionHelper(this, ex, i + 1);
- ex = expressionSemantic(ex, sc);
- resolveExp(ex, pt, pe, ps);
- return;
- }
-
- Type *t = s->getType(); // type symbol, type alias, or type tuple?
- unsigned errorsave = global.errors;
- int flags = t == NULL ? SearchLocalsOnly : IgnorePrivateImports;
- Dsymbol *sm = s->searchX(loc, sc, id, flags);
- if (sm)
- {
- if (!(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, sm))
- {
- ::error(loc, "`%s` is not visible from module `%s`", sm->toPrettyChars(), sc->_module->toChars());
- sm = NULL;
- }
- // Same check as in Expression::semanticY(DotIdExp)
- else if (sm->isPackage() && checkAccess(sc, (Package *)sm))
- {
- // @@@DEPRECATED_2.096@@@
- // Should be an error in 2.106. Just remove the deprecation call
- // and uncomment the null assignment
- ::deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'",
- sm->kind(), sm->toPrettyChars(), sm->toPrettyChars());
- //sm = null;
- }
- }
- if (global.errors != errorsave)
- {
- *pt = Type::terror;
- return;
- }
- //printf("\t3: s = %p %s %s, sm = %p\n", s, s->kind(), s->toChars(), sm);
- if (intypeid && !t && sm && sm->needThis())
- goto L3;
- if (VarDeclaration *v = s->isVarDeclaration())
- {
- // https://issues.dlang.org/show_bug.cgi?id=19913
- // v->type would be null if it is a forward referenced member.
- if (v->type == NULL)
- dsymbolSemantic(v, sc);
- if (v->storage_class & (STCconst | STCimmutable | STCmanifest) ||
- v->type->isConst() || v->type->isImmutable())
- {
- // Bugzilla 13087: this.field is not constant always
- if (!v->isThisDeclaration())
- goto L3;
- }
- }
- if (!sm)
- {
- if (!t)
- {
- if (s->isDeclaration()) // var, func, or tuple declaration?
- {
- t = s->isDeclaration()->type;
- if (!t && s->isTupleDeclaration()) // expression tuple?
- goto L3;
- }
- else if (s->isTemplateInstance() ||
- s->isImport() || s->isPackage() || s->isModule())
- {
- goto L3;
- }
- }
- if (t)
- {
- sm = t->toDsymbol(sc);
- if (sm && id->dyncast() == DYNCAST_IDENTIFIER)
- {
- sm = sm->search(loc, (Identifier *)id, IgnorePrivateImports);
- if (sm)
- goto L2;
- }
- L3:
- Expression *e;
- VarDeclaration *v = s->isVarDeclaration();
- FuncDeclaration *f = s->isFuncDeclaration();
- if (intypeid || (!v && !f))
- e = ::resolve(loc, sc, s, true);
- else
- e = new VarExp(loc, s->isDeclaration(), true);
-
- e = typeToExpressionHelper(this, e, i);
- e = expressionSemantic(e, sc);
- resolveExp(e, pt, pe, ps);
- return;
- }
- else
- {
- if (id->dyncast() == DYNCAST_DSYMBOL)
- {
- // searchX already handles errors for template instances
- assert(global.errors);
- }
- else
- {
- assert(id->dyncast() == DYNCAST_IDENTIFIER);
- sm = s->search_correct((Identifier *)id);
- if (sm)
- error(loc, "identifier `%s` of `%s` is not defined, did you mean %s `%s`?",
- id->toChars(), toChars(), sm->kind(), sm->toChars());
- else
- error(loc, "identifier `%s` of `%s` is not defined", id->toChars(), toChars());
- }
- *pe = new ErrorExp();
- }
- return;
- }
- L2:
- s = sm->toAlias();
- }
-
- if (EnumMember *em = s->isEnumMember())
- {
- // It's not a type, it's an expression
- *pe = em->getVarExp(loc, sc);
- return;
- }
- if (VarDeclaration *v = s->isVarDeclaration())
- {
- /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
- * because some variables used in type context need to prevent lowering
- * to a literal or contextful expression. For example:
- *
- * enum a = 1; alias b = a;
- * template X(alias e){ alias v = e; } alias x = X!(1);
- * struct S { int v; alias w = v; }
- * // TypeIdentifier 'a', 'e', and 'v' should be TOKvar,
- * // because getDsymbol() need to work in AliasDeclaration::semantic().
- */
- if (!v->type ||
- (!v->type->deco && v->inuse))
- {
- if (v->inuse) // Bugzilla 9494
- error(loc, "circular reference to %s `%s`", v->kind(), v->toPrettyChars());
- else
- error(loc, "forward reference to %s `%s`", v->kind(), v->toPrettyChars());
- *pt = Type::terror;
- return;
- }
- if (v->type->ty == Terror)
- *pt = Type::terror;
- else
- *pe = new VarExp(loc, v);
- return;
- }
- if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration())
- {
- //printf("'%s' is a function literal\n", fld->toChars());
- *pe = new FuncExp(loc, fld);
- *pe = expressionSemantic(*pe, sc);
- return;
- }
-L1:
- Type *t = s->getType();
- if (!t)
- {
- // If the symbol is an import, try looking inside the import
- if (Import *si = s->isImport())
- {
- s = si->search(loc, s->ident);
- if (s && s != si)
- goto L1;
- s = si;
- }
- *ps = s;
- return;
- }
- if (t->ty == Tinstance && t != this && !t->deco)
- {
- if (!((TypeInstance *)t)->tempinst->errors)
- error(loc, "forward reference to `%s`", t->toChars());
- *pt = Type::terror;
- return;
- }
-
- if (t->ty == Ttuple)
- *pt = t;
- else
- *pt = t->merge();
- }
- if (!s)
- {
- /* Look for what user might have intended
- */
- const char *p = mutableOf()->unSharedOf()->toChars();
- Identifier *id = Identifier::idPool(p, strlen(p));
- if (const char *n = importHint(p))
- error(loc, "`%s` is not defined, perhaps `import %s;` ?", p, n);
- else if (Dsymbol *s2 = sc->search_correct(id))
- error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2->kind(), s2->toChars());
- else if (const char *q = Scope::search_correct_C(id))
- error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q);
- else
- error(loc, "undefined identifier `%s`", p);
-
- *pt = Type::terror;
- }
-}
-
-/***************************** TypeIdentifier *****************************/
-
-TypeIdentifier::TypeIdentifier(Loc loc, Identifier *ident)
- : TypeQualified(Tident, loc)
-{
- this->ident = ident;
-}
-
-const char *TypeIdentifier::kind()
-{
- return "identifier";
-}
-
-Type *TypeIdentifier::syntaxCopy()
-{
- TypeIdentifier *t = new TypeIdentifier(loc, ident);
- t->syntaxCopyHelper(this);
- t->mod = mod;
- return t;
-}
-
-/*************************************
- * Takes an array of Identifiers and figures out if
- * it represents a Type or an Expression.
- * Output:
- * if expression, *pe is set
- * if type, *pt is set
- */
-
-void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
-{
- //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, toChars());
-
- if ((ident->equals(Id::_super) || ident->equals(Id::This)) && !hasThis(sc))
- {
- AggregateDeclaration *ad = sc->getStructClassScope();
- if (ad)
- {
- ClassDeclaration *cd = ad->isClassDeclaration();
- if (cd)
- {
- if (ident->equals(Id::This))
- ident = cd->ident;
- else if (cd->baseClass && ident->equals(Id::_super))
- ident = cd->baseClass->ident;
- }
- else
- {
- StructDeclaration *sd = ad->isStructDeclaration();
- if (sd && ident->equals(Id::This))
- ident = sd->ident;
- }
- }
- }
- if (ident == Id::ctfe)
- {
- error(loc, "variable __ctfe cannot be read at compile time");
- *pe = NULL;
- *ps = NULL;
- *pt = Type::terror;
- return;
- }
-
- Dsymbol *scopesym;
- Dsymbol *s = sc->search(loc, ident, &scopesym);
- resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid);
- if (*pt)
- (*pt) = (*pt)->addMod(mod);
-}
-
-/*****************************************
- * See if type resolves to a symbol, if so,
- * return that symbol.
- */
-
-Dsymbol *TypeIdentifier::toDsymbol(Scope *sc)
-{
- //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
- if (!sc)
- return NULL;
-
- Type *t;
- Expression *e;
- Dsymbol *s;
-
- resolve(loc, sc, &e, &t, &s);
- if (t && t->ty != Tident)
- s = t->toDsymbol(sc);
- if (e)
- s = getDsymbol(e);
-
- return s;
-}
-
-/***************************** TypeInstance *****************************/
-
-TypeInstance::TypeInstance(Loc loc, TemplateInstance *tempinst)
- : TypeQualified(Tinstance, loc)
-{
- this->tempinst = tempinst;
-}
-
-const char *TypeInstance::kind()
-{
- return "instance";
-}
-
-Type *TypeInstance::syntaxCopy()
-{
- //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.length);
- TypeInstance *t = new TypeInstance(loc, (TemplateInstance *)tempinst->syntaxCopy(NULL));
- t->syntaxCopyHelper(this);
- t->mod = mod;
- return t;
-}
-
-void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
-{
- // Note close similarity to TypeIdentifier::resolve()
- *pe = NULL;
- *pt = NULL;
- *ps = NULL;
- //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, tempinst->toChars());
- dsymbolSemantic(tempinst, sc);
- if (!global.gag && tempinst->errors)
- {
- *pt = terror;
- return;
- }
-
- resolveHelper(loc, sc, tempinst, NULL, pe, pt, ps, intypeid);
- if (*pt)
- *pt = (*pt)->addMod(mod);
- //if (*pt) printf("pt = '%s'\n", (*pt)->toChars());
-}
-
-Dsymbol *TypeInstance::toDsymbol(Scope *sc)
-{
- Type *t;
- Expression *e;
- Dsymbol *s;
-
- //printf("TypeInstance::semantic(%s)\n", toChars());
- resolve(loc, sc, &e, &t, &s);
- if (t && t->ty != Tinstance)
- s = t->toDsymbol(sc);
-
- return s;
-}
-
-
-/***************************** TypeTypeof *****************************/
-
-TypeTypeof::TypeTypeof(Loc loc, Expression *exp)
- : TypeQualified(Ttypeof, loc)
-{
- this->exp = exp;
- inuse = 0;
-}
-
-const char *TypeTypeof::kind()
-{
- return "typeof";
-}
-
-Type *TypeTypeof::syntaxCopy()
-{
- //printf("TypeTypeof::syntaxCopy() %s\n", toChars());
- TypeTypeof *t = new TypeTypeof(loc, exp->syntaxCopy());
- t->syntaxCopyHelper(this);
- t->mod = mod;
- return t;
-}
-
-Dsymbol *TypeTypeof::toDsymbol(Scope *sc)
-{
- //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
- Expression *e;
- Type *t;
- Dsymbol *s;
- resolve(loc, sc, &e, &t, &s);
-
- return s;
-}
-
-void TypeTypeof::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
-{
- *pe = NULL;
- *pt = NULL;
- *ps = NULL;
-
- //printf("TypeTypeof::resolve(sc = %p, idents = '%s')\n", sc, toChars());
- //static int nest; if (++nest == 50) *(char*)0=0;
- if (sc == NULL)
- {
- *pt = Type::terror;
- error(loc, "Invalid scope.");
- return;
- }
- if (inuse)
- {
- inuse = 2;
- error(loc, "circular typeof definition");
- Lerr:
- *pt = Type::terror;
- inuse--;
- return;
- }
- inuse++;
-
- Type *t;
- {
- /* Currently we cannot evalute 'exp' in speculative context, because
- * the type implementation may leak to the final execution. Consider:
- *
- * struct S(T) {
- * string toString() const { return "x"; }
- * }
- * void main() {
- * alias X = typeof(S!int());
- * assert(typeid(X).xtoString(null) == "x");
- * }
- */
- Scope *sc2 = sc->push();
- sc2->intypeof = 1;
- Expression *exp2 = expressionSemantic(exp, sc2);
- exp2 = resolvePropertiesOnly(sc2, exp2);
- sc2->pop();
-
- if (exp2->op == TOKerror)
- {
- if (!global.gag)
- exp = exp2;
- goto Lerr;
- }
- exp = exp2;
-
- if (exp->op == TOKtype ||
- exp->op == TOKscope)
- {
- if (exp->checkType())
- goto Lerr;
-
- /* Today, 'typeof(func)' returns void if func is a
- * function template (TemplateExp), or
- * template lambda (FuncExp).
- * It's actually used in Phobos as an idiom, to branch code for
- * template functions.
- */
- }
- if (FuncDeclaration *f = exp->op == TOKvar ? (( VarExp *)exp)->var->isFuncDeclaration()
- : exp->op == TOKdotvar ? ((DotVarExp *)exp)->var->isFuncDeclaration() : NULL)
- {
- if (f->checkForwardRef(loc))
- goto Lerr;
- }
- if (FuncDeclaration *f = isFuncAddress(exp))
- {
- if (f->checkForwardRef(loc))
- goto Lerr;
- }
-
- t = exp->type;
- if (!t)
- {
- error(loc, "expression (%s) has no type", exp->toChars());
- goto Lerr;
- }
- if (t->ty == Ttypeof)
- {
- error(loc, "forward reference to %s", toChars());
- goto Lerr;
- }
- }
- if (idents.length == 0)
- *pt = t;
- else
- {
- if (Dsymbol *s = t->toDsymbol(sc))
- resolveHelper(loc, sc, s, NULL, pe, pt, ps, intypeid);
- else
- {
- Expression *e = typeToExpressionHelper(this, new TypeExp(loc, t));
- e = expressionSemantic(e, sc);
- resolveExp(e, pt, pe, ps);
- }
- }
- if (*pt)
- (*pt) = (*pt)->addMod(mod);
- inuse--;
- return;
-}
-
-d_uns64 TypeTypeof::size(Loc loc)
-{
- if (exp->type)
- return exp->type->size(loc);
- else
- return TypeQualified::size(loc);
-}
-
-
-
-/***************************** TypeReturn *****************************/
-
-TypeReturn::TypeReturn(Loc loc)
- : TypeQualified(Treturn, loc)
-{
-}
-
-const char *TypeReturn::kind()
-{
- return "return";
-}
-
-Type *TypeReturn::syntaxCopy()
-{
- TypeReturn *t = new TypeReturn(loc);
- t->syntaxCopyHelper(this);
- t->mod = mod;
- return t;
-}
-
-Dsymbol *TypeReturn::toDsymbol(Scope *sc)
-{
- Expression *e;
- Type *t;
- Dsymbol *s;
- resolve(loc, sc, &e, &t, &s);
-
- return s;
-}
-
-void TypeReturn::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
-{
- *pe = NULL;
- *pt = NULL;
- *ps = NULL;
-
- //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, toChars());
- Type *t;
- {
- FuncDeclaration *func = sc->func;
- if (!func)
- {
- error(loc, "typeof(return) must be inside function");
- goto Lerr;
- }
- if (func->fes)
- func = func->fes->func;
-
- t = func->type->nextOf();
- if (!t)
- {
- error(loc, "cannot use typeof(return) inside function %s with inferred return type", sc->func->toChars());
- goto Lerr;
- }
- }
- if (idents.length == 0)
- *pt = t;
- else
- {
- if (Dsymbol *s = t->toDsymbol(sc))
- resolveHelper(loc, sc, s, NULL, pe, pt, ps, intypeid);
- else
- {
- Expression *e = typeToExpressionHelper(this, new TypeExp(loc, t));
- e = expressionSemantic(e, sc);
- resolveExp(e, pt, pe, ps);
- }
- }
- if (*pt)
- (*pt) = (*pt)->addMod(mod);
- return;
-
-Lerr:
- *pt = Type::terror;
- return;
-}
-
-/***************************** TypeEnum *****************************/
-
-TypeEnum::TypeEnum(EnumDeclaration *sym)
- : Type(Tenum)
-{
- this->sym = sym;
-}
-
-const char *TypeEnum::kind()
-{
- return "enum";
-}
-
-Type *TypeEnum::syntaxCopy()
-{
- return this;
-}
-
-d_uns64 TypeEnum::size(Loc loc)
-{
- return sym->getMemtype(loc)->size(loc);
-}
-
-unsigned TypeEnum::alignsize()
-{
- Type *t = sym->getMemtype(Loc());
- if (t->ty == Terror)
- return 4;
- return t->alignsize();
-}
-
-Dsymbol *TypeEnum::toDsymbol(Scope *)
-{
- return sym;
-}
-
-Type *TypeEnum::toBasetype()
-{
- if (!sym->members && !sym->memtype)
- return this;
- Type *tb = sym->getMemtype(Loc())->toBasetype();
- return tb->castMod(mod); // retain modifier bits from 'this'
-}
-
-Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- // Bugzilla 14010
- if (ident == Id::_mangleof)
- return getProperty(e->loc, ident, flag & 1);
-
- if (sym->semanticRun < PASSsemanticdone)
- dsymbolSemantic(sym, NULL);
-
- Dsymbol *s = sym->search(e->loc, ident);
- if (!s)
- {
- if (ident == Id::max ||
- ident == Id::min ||
- ident == Id::_init)
- {
- return getProperty(e->loc, ident, flag & 1);
- }
- Expression *res = sym->getMemtype(Loc())->dotExp(sc, e, ident, 1);
- if (!(flag & 1) && !res)
- {
- if (Dsymbol *ns = sym->search_correct(ident))
- e->error("no property `%s` for type `%s`. Did you mean `%s.%s` ?",
- ident->toChars(), toChars(), toChars(), ns->toChars());
- else
- e->error("no property `%s` for type `%s`",
- ident->toChars(), toChars());
-
- return new ErrorExp();
- }
- return res;
- }
- EnumMember *m = s->isEnumMember();
- return m->getVarExp(e->loc, sc);
-}
-
-Expression *TypeEnum::getProperty(Loc loc, Identifier *ident, int flag)
-{
- Expression *e;
- if (ident == Id::max || ident == Id::min)
- {
- return sym->getMaxMinValue(loc, ident);
- }
- else if (ident == Id::_init)
- {
- e = defaultInitLiteral(loc);
- }
- else if (ident == Id::stringof)
- {
- const char *s = toChars();
- e = new StringExp(loc, const_cast<char *>(s), strlen(s));
- Scope sc;
- e = expressionSemantic(e, &sc);
- }
- else if (ident == Id::_mangleof)
- {
- e = Type::getProperty(loc, ident, flag);
- }
- else
- {
- e = toBasetype()->getProperty(loc, ident, flag);
- }
- return e;
-}
-
-bool TypeEnum::isintegral()
-{
- return sym->getMemtype(Loc())->isintegral();
-}
-
-bool TypeEnum::isfloating()
-{
- return sym->getMemtype(Loc())->isfloating();
-}
-
-bool TypeEnum::isreal()
-{
- return sym->getMemtype(Loc())->isreal();
-}
-
-bool TypeEnum::isimaginary()
-{
- return sym->getMemtype(Loc())->isimaginary();
-}
-
-bool TypeEnum::iscomplex()
-{
- return sym->getMemtype(Loc())->iscomplex();
-}
-
-bool TypeEnum::isunsigned()
-{
- return sym->getMemtype(Loc())->isunsigned();
-}
-
-bool TypeEnum::isscalar()
-{
- return sym->getMemtype(Loc())->isscalar();
-}
-
-bool TypeEnum::isString()
-{
- return sym->getMemtype(Loc())->isString();
-}
-
-bool TypeEnum::isAssignable()
-{
- return sym->getMemtype(Loc())->isAssignable();
-}
-
-bool TypeEnum::isBoolean()
-{
- return sym->getMemtype(Loc())->isBoolean();
-}
-
-bool TypeEnum::needsDestruction()
-{
- return sym->getMemtype(Loc())->needsDestruction();
-}
-
-bool TypeEnum::needsNested()
-{
- return sym->getMemtype(Loc())->needsNested();
-}
-
-MATCH TypeEnum::implicitConvTo(Type *to)
-{
- MATCH m;
-
- //printf("TypeEnum::implicitConvTo()\n");
- if (ty == to->ty && sym == ((TypeEnum *)to)->sym)
- m = (mod == to->mod) ? MATCHexact : MATCHconst;
- else if (sym->getMemtype(Loc())->implicitConvTo(to))
- m = MATCHconvert; // match with conversions
- else
- m = MATCHnomatch; // no match
- return m;
-}
-
-MATCH TypeEnum::constConv(Type *to)
-{
- if (equals(to))
- return MATCHexact;
- if (ty == to->ty && sym == ((TypeEnum *)to)->sym &&
- MODimplicitConv(mod, to->mod))
- return MATCHconst;
- return MATCHnomatch;
-}
-
-
-Expression *TypeEnum::defaultInit(Loc loc)
-{
- // Initialize to first member of enum
- Expression *e = sym->getDefaultValue(loc);
- e = e->copy();
- e->loc = loc;
- e->type = this; // to deal with const, immutable, etc., variants
- return e;
-}
-
-bool TypeEnum::isZeroInit(Loc loc)
-{
- return sym->getDefaultValue(loc)->isBool(false);
-}
-
-bool TypeEnum::hasPointers()
-{
- return sym->getMemtype(Loc())->hasPointers();
-}
-
-bool TypeEnum::hasVoidInitPointers()
-{
- return sym->getMemtype(Loc())->hasVoidInitPointers();
-}
-
-Type *TypeEnum::nextOf()
-{
- return sym->getMemtype(Loc())->nextOf();
-}
-
-/***************************** TypeStruct *****************************/
-
-TypeStruct::TypeStruct(StructDeclaration *sym)
- : Type(Tstruct)
-{
- this->sym = sym;
- this->att = RECfwdref;
- this->cppmangle = CPPMANGLEdefault;
-}
-
-TypeStruct *TypeStruct::create(StructDeclaration *sym)
-{
- return new TypeStruct(sym);
-}
-
-const char *TypeStruct::kind()
-{
- return "struct";
-}
-
-Type *TypeStruct::syntaxCopy()
-{
- return this;
-}
-
-d_uns64 TypeStruct::size(Loc loc)
-{
- return sym->size(loc);
-}
-
-unsigned TypeStruct::alignsize()
-{
- sym->size(Loc()); // give error for forward references
- return sym->alignsize;
-}
-
-Dsymbol *TypeStruct::toDsymbol(Scope *)
-{
- return sym;
-}
-
-Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- Dsymbol *s;
-
- assert(e->op != TOKdot);
-
- // Bugzilla 14010
- if (ident == Id::_mangleof)
- return getProperty(e->loc, ident, flag & 1);
-
- /* If e.tupleof
- */
- if (ident == Id::_tupleof)
- {
- /* Create a TupleExp out of the fields of the struct e:
- * (e.field0, e.field1, e.field2, ...)
- */
- e = expressionSemantic(e, sc); // do this before turning on noaccesscheck
-
- if (!sym->determineFields())
- {
- error(e->loc, "unable to determine fields of `%s` because of forward references", toChars());
- }
-
- Expression *e0 = NULL;
- Expression *ev = e->op == TOKtype ? NULL : e;
- if (ev)
- ev = extractSideEffect(sc, "__tup", &e0, ev);
-
- Expressions *exps = new Expressions;
- exps->reserve(sym->fields.length);
- for (size_t i = 0; i < sym->fields.length; i++)
- {
- VarDeclaration *v = sym->fields[i];
- Expression *ex;
- if (ev)
- ex = new DotVarExp(e->loc, ev, v);
- else
- {
- ex = new VarExp(e->loc, v);
- ex->type = ex->type->addMod(e->type->mod);
- }
- exps->push(ex);
- }
-
- e = new TupleExp(e->loc, e0, exps);
- Scope *sc2 = sc->push();
- sc2->flags = sc->flags | SCOPEnoaccesscheck;
- e = expressionSemantic(e, sc2);
- sc2->pop();
- return e;
- }
-
- const int flags = sc->flags & SCOPEignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
- s = sym->search(e->loc, ident, flags | IgnorePrivateImports);
-L1:
- if (!s)
- {
- return noMember(sc, e, ident, flag);
- }
- if (!(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, s))
- {
- return noMember(sc, e, ident, flag);
- }
- if (!s->isFuncDeclaration()) // because of overloading
- {
- s->checkDeprecated(e->loc, sc);
- if (Declaration *d = s->isDeclaration())
- d->checkDisabled(e->loc, sc);
- }
- s = s->toAlias();
-
- EnumMember *em = s->isEnumMember();
- if (em)
- {
- return em->getVarExp(e->loc, sc);
- }
-
- if (VarDeclaration *v = s->isVarDeclaration())
- {
- if (!v->type ||
- (!v->type->deco && v->inuse))
- {
- if (v->inuse) // Bugzilla 9494
- e->error("circular reference to %s `%s`", v->kind(), v->toPrettyChars());
- else
- e->error("forward reference to %s `%s`", v->kind(), v->toPrettyChars());
- return new ErrorExp();
- }
- if (v->type->ty == Terror)
- return new ErrorExp();
-
- if ((v->storage_class & STCmanifest) && v->_init)
- {
- if (v->inuse)
- {
- e->error("circular initialization of %s `%s`", v->kind(), v->toPrettyChars());
- return new ErrorExp();
- }
- checkAccess(e->loc, sc, NULL, v);
- Expression *ve = new VarExp(e->loc, v);
- ve = expressionSemantic(ve, sc);
- return ve;
- }
- }
-
- if (Type *t = s->getType())
- {
- return expressionSemantic(new TypeExp(e->loc, t), sc);
- }
-
- TemplateMixin *tm = s->isTemplateMixin();
- if (tm)
- {
- Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
- de->type = e->type;
- return de;
- }
-
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (td)
- {
- if (e->op == TOKtype)
- e = new TemplateExp(e->loc, td);
- else
- e = new DotTemplateExp(e->loc, e, td);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- TemplateInstance *ti = s->isTemplateInstance();
- if (ti)
- {
- if (!ti->semanticRun)
- {
- dsymbolSemantic(ti, sc);
- if (!ti->inst || ti->errors) // if template failed to expand
- return new ErrorExp();
- }
- s = ti->inst->toAlias();
- if (!s->isTemplateInstance())
- goto L1;
- if (e->op == TOKtype)
- e = new ScopeExp(e->loc, ti);
- else
- e = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
- return expressionSemantic(e, sc);
- }
-
- if (s->isImport() || s->isModule() || s->isPackage())
- {
- e = ::resolve(e->loc, sc, s, false);
- return e;
- }
-
- OverloadSet *o = s->isOverloadSet();
- if (o)
- {
- OverExp *oe = new OverExp(e->loc, o);
- if (e->op == TOKtype)
- return oe;
- return new DotExp(e->loc, e, oe);
- }
-
- Declaration *d = s->isDeclaration();
- if (!d)
- {
- e->error("%s.%s is not a declaration", e->toChars(), ident->toChars());
- return new ErrorExp();
- }
-
- if (e->op == TOKtype)
- {
- /* It's:
- * Struct.d
- */
- if (TupleDeclaration *tup = d->isTupleDeclaration())
- {
- e = new TupleExp(e->loc, tup);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (d->needThis() && sc->intypeof != 1)
- {
- /* Rewrite as:
- * this.d
- */
- if (hasThis(sc))
- {
- e = new DotVarExp(e->loc, new ThisExp(e->loc), d);
- e = expressionSemantic(e, sc);
- return e;
- }
- }
- if (d->semanticRun == PASSinit)
- dsymbolSemantic(d, NULL);
- checkAccess(e->loc, sc, e, d);
- VarExp *ve = new VarExp(e->loc, d);
- if (d->isVarDeclaration() && d->needThis())
- ve->type = d->type->addMod(e->type->mod);
- return ve;
- }
-
- bool unreal = e->op == TOKvar && ((VarExp *)e)->var->isField();
- if (d->isDataseg() || (unreal && d->isField()))
- {
- // (e, d)
- checkAccess(e->loc, sc, e, d);
- Expression *ve = new VarExp(e->loc, d);
- e = unreal ? ve : new CommaExp(e->loc, e, ve);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- e = new DotVarExp(e->loc, e, d);
- e = expressionSemantic(e, sc);
- return e;
-}
-
-structalign_t TypeStruct::alignment()
-{
- if (sym->alignment == 0)
- sym->size(sym->loc);
- return sym->alignment;
-}
-
-Expression *TypeStruct::defaultInit(Loc)
-{
- Declaration *d = new SymbolDeclaration(sym->loc, sym);
- assert(d);
- d->type = this;
- d->storage_class |= STCrvalue; // Bugzilla 14398
- return new VarExp(sym->loc, d);
-}
-
-/***************************************
- * Use when we prefer the default initializer to be a literal,
- * rather than a global immutable variable.
- */
-Expression *TypeStruct::defaultInitLiteral(Loc loc)
-{
- sym->size(loc);
- if (sym->sizeok != SIZEOKdone)
- return new ErrorExp();
- Expressions *structelems = new Expressions();
- structelems->setDim(sym->fields.length - sym->isNested());
- unsigned offset = 0;
- for (size_t j = 0; j < structelems->length; j++)
- {
- VarDeclaration *vd = sym->fields[j];
- Expression *e;
- if (vd->inuse)
- {
- error(loc, "circular reference to `%s`", vd->toPrettyChars());
- return new ErrorExp();
- }
- if (vd->offset < offset || vd->type->size() == 0)
- e = NULL;
- else if (vd->_init)
- {
- if (vd->_init->isVoidInitializer())
- e = NULL;
- else
- e = vd->getConstInitializer(false);
- }
- else
- e = vd->type->defaultInitLiteral(loc);
- if (e && e->op == TOKerror)
- return e;
- if (e)
- offset = vd->offset + (unsigned)vd->type->size();
- (*structelems)[j] = e;
- }
- StructLiteralExp *structinit = new StructLiteralExp(loc, (StructDeclaration *)sym, structelems);
-
- /* Copy from the initializer symbol for larger symbols,
- * otherwise the literals expressed as code get excessively large.
- */
- if (size(loc) > target.ptrsize * 4U && !needsNested())
- structinit->useStaticInit = true;
-
- structinit->type = this;
- return structinit;
-}
-
-
-bool TypeStruct::isZeroInit(Loc)
-{
- return sym->zeroInit != 0;
-}
-
-bool TypeStruct::isBoolean()
-{
- return false;
-}
-
-bool TypeStruct::needsDestruction()
-{
- return sym->dtor != NULL;
-}
-
-bool TypeStruct::needsNested()
-{
- if (sym->isNested())
- return true;
-
- for (size_t i = 0; i < sym->fields.length; i++)
- {
- VarDeclaration *v = sym->fields[i];
- if (!v->isDataseg() && v->type->needsNested())
- return true;
- }
- return false;
-}
-
-bool TypeStruct::isAssignable()
-{
- bool assignable = true;
- unsigned offset = ~0; // dead-store initialize to prevent spurious warning
-
- /* If any of the fields are const or immutable,
- * then one cannot assign this struct.
- */
- for (size_t i = 0; i < sym->fields.length; i++)
- {
- VarDeclaration *v = sym->fields[i];
- //printf("%s [%d] v = (%s) %s, v->offset = %d, v->parent = %s", sym->toChars(), i, v->kind(), v->toChars(), v->offset, v->parent->kind());
- if (i == 0)
- ;
- else if (v->offset == offset)
- {
- /* If any fields of anonymous union are assignable,
- * then regard union as assignable.
- * This is to support unsafe things like Rebindable templates.
- */
- if (assignable)
- continue;
- }
- else
- {
- if (!assignable)
- return false;
- }
- assignable = v->type->isMutable() && v->type->isAssignable();
- offset = v->offset;
- //printf(" -> assignable = %d\n", assignable);
- }
-
- return assignable;
-}
-
-bool TypeStruct::hasPointers()
-{
- // Probably should cache this information in sym rather than recompute
- StructDeclaration *s = sym;
-
- if (sym->members && !sym->determineFields() && sym->type != Type::terror)
- error(sym->loc, "no size because of forward references");
-
- for (size_t i = 0; i < s->fields.length; i++)
- {
- Declaration *d = s->fields[i];
- if (d->storage_class & STCref || d->hasPointers())
- return true;
- }
- return false;
-}
-
-bool TypeStruct::hasVoidInitPointers()
-{
- // Probably should cache this information in sym rather than recompute
- StructDeclaration *s = sym;
-
- sym->size(Loc()); // give error for forward references
- for (size_t i = 0; i < s->fields.length; i++)
- {
- VarDeclaration *v = s->fields[i];
- if (v->_init && v->_init->isVoidInitializer() && v->type->hasPointers())
- return true;
- if (!v->_init && v->type->hasVoidInitPointers())
- return true;
- }
- return false;
-}
-
-MATCH TypeStruct::implicitConvTo(Type *to)
-{ MATCH m;
-
- //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to->toChars());
-
- if (ty == to->ty && sym == ((TypeStruct *)to)->sym)
- {
- m = MATCHexact; // exact match
- if (mod != to->mod)
- {
- m = MATCHconst;
- if (MODimplicitConv(mod, to->mod))
- ;
- else
- {
- /* Check all the fields. If they can all be converted,
- * allow the conversion.
- */
- unsigned offset = ~0; // dead-store to prevent spurious warning
- for (size_t i = 0; i < sym->fields.length; i++)
- {
- VarDeclaration *v = sym->fields[i];
- if (i == 0)
- ;
- else if (v->offset == offset)
- {
- if (m > MATCHnomatch)
- continue;
- }
- else
- {
- if (m <= MATCHnomatch)
- return m;
- }
-
- // 'from' type
- Type *tvf = v->type->addMod(mod);
-
- // 'to' type
- Type *tv = v->type->addMod(to->mod);
-
- // field match
- MATCH mf = tvf->implicitConvTo(tv);
- //printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), mf);
-
- if (mf <= MATCHnomatch)
- return mf;
- if (mf < m) // if field match is worse
- m = mf;
- offset = v->offset;
- }
- }
- }
- }
- else if (sym->aliasthis && !(att & RECtracing))
- {
- att = (AliasThisRec)(att | RECtracing);
- m = aliasthisOf()->implicitConvTo(to);
- att = (AliasThisRec)(att & ~RECtracing);
- }
- else
- m = MATCHnomatch; // no match
- return m;
-}
-
-MATCH TypeStruct::constConv(Type *to)
-{
- if (equals(to))
- return MATCHexact;
- if (ty == to->ty && sym == ((TypeStruct *)to)->sym &&
- MODimplicitConv(mod, to->mod))
- return MATCHconst;
- return MATCHnomatch;
-}
-
-unsigned char TypeStruct::deduceWild(Type *t, bool isRef)
-{
- if (ty == t->ty && sym == ((TypeStruct *)t)->sym)
- return Type::deduceWild(t, isRef);
-
- unsigned char wm = 0;
-
- if (t->hasWild() && sym->aliasthis && !(att & RECtracing))
- {
- att = (AliasThisRec)(att | RECtracing);
- wm = aliasthisOf()->deduceWild(t, isRef);
- att = (AliasThisRec)(att & ~RECtracing);
- }
-
- return wm;
-}
-
-Type *TypeStruct::toHeadMutable()
-{
- return this;
-}
-
-
-/***************************** TypeClass *****************************/
-
-TypeClass::TypeClass(ClassDeclaration *sym)
- : Type(Tclass)
-{
- this->sym = sym;
- this->att = RECfwdref;
- this->cppmangle = CPPMANGLEdefault;
-}
-
-const char *TypeClass::kind()
-{
- return "class";
-}
-
-Type *TypeClass::syntaxCopy()
-{
- return this;
-}
-
-d_uns64 TypeClass::size(Loc)
-{
- return target.ptrsize;
-}
-
-Dsymbol *TypeClass::toDsymbol(Scope *)
-{
- return sym;
-}
-
-Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident, int flag)
-{
- Dsymbol *s;
- assert(e->op != TOKdot);
-
- // Bugzilla 12543
- if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::_mangleof)
- {
- return Type::getProperty(e->loc, ident, 0);
- }
-
- /* If e.tupleof
- */
- if (ident == Id::_tupleof)
- {
- /* Create a TupleExp
- */
- e = expressionSemantic(e, sc); // do this before turning on noaccesscheck
-
- sym->size(e->loc); // do semantic of type
-
- Expression *e0 = NULL;
- Expression *ev = e->op == TOKtype ? NULL : e;
- if (ev)
- ev = extractSideEffect(sc, "__tup", &e0, ev);
-
- Expressions *exps = new Expressions;
- exps->reserve(sym->fields.length);
- for (size_t i = 0; i < sym->fields.length; i++)
- {
- VarDeclaration *v = sym->fields[i];
- // Don't include hidden 'this' pointer
- if (v->isThisDeclaration())
- continue;
- Expression *ex;
- if (ev)
- ex = new DotVarExp(e->loc, ev, v);
- else
- {
- ex = new VarExp(e->loc, v);
- ex->type = ex->type->addMod(e->type->mod);
- }
- exps->push(ex);
- }
-
- e = new TupleExp(e->loc, e0, exps);
- Scope *sc2 = sc->push();
- sc2->flags = sc->flags | SCOPEnoaccesscheck;
- e = expressionSemantic(e, sc2);
- sc2->pop();
- return e;
- }
-
- int flags = sc->flags & SCOPEignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
- s = sym->search(e->loc, ident, flags | IgnorePrivateImports);
-
-L1:
- if (!s)
- {
- // See if it's 'this' class or a base class
- if (sym->ident == ident)
- {
- if (e->op == TOKtype)
- return Type::getProperty(e->loc, ident, 0);
- e = new DotTypeExp(e->loc, e, sym);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (ClassDeclaration *cbase = sym->searchBase(ident))
- {
- if (e->op == TOKtype)
- return Type::getProperty(e->loc, ident, 0);
- if (InterfaceDeclaration *ifbase = cbase->isInterfaceDeclaration())
- e = new CastExp(e->loc, e, ifbase->type);
- else
- e = new DotTypeExp(e->loc, e, cbase);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- if (ident == Id::classinfo)
- {
- if (!Type::typeinfoclass)
- {
- error(e->loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
- return new ErrorExp();
- }
-
- Type *t = Type::typeinfoclass->type;
- if (e->op == TOKtype || e->op == TOKdottype)
- {
- /* For type.classinfo, we know the classinfo
- * at compile time.
- */
- if (!sym->vclassinfo)
- sym->vclassinfo = new TypeInfoClassDeclaration(sym->type);
- e = new VarExp(e->loc, sym->vclassinfo);
- e = e->addressOf();
- e->type = t; // do this so we don't get redundant dereference
- }
- else
- {
- /* For class objects, the classinfo reference is the first
- * entry in the vtbl[]
- */
- e = new PtrExp(e->loc, e);
- e->type = t->pointerTo();
- if (sym->isInterfaceDeclaration())
- {
- if (sym->isCPPinterface())
- {
- /* C++ interface vtbl[]s are different in that the
- * first entry is always pointer to the first virtual
- * function, not classinfo.
- * We can't get a .classinfo for it.
- */
- error(e->loc, "no .classinfo for C++ interface objects");
- }
- /* For an interface, the first entry in the vtbl[]
- * is actually a pointer to an instance of struct Interface.
- * The first member of Interface is the .classinfo,
- * so add an extra pointer indirection.
- */
- e->type = e->type->pointerTo();
- e = new PtrExp(e->loc, e);
- e->type = t->pointerTo();
- }
- e = new PtrExp(e->loc, e, t);
- }
- return e;
- }
-
- if (ident == Id::__vptr)
- {
- /* The pointer to the vtbl[]
- * *cast(immutable(void*)**)e
- */
- e = e->castTo(sc, tvoidptr->immutableOf()->pointerTo()->pointerTo());
- e = new PtrExp(e->loc, e);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- if (ident == Id::__monitor && sym->hasMonitor())
- {
- /* The handle to the monitor (call it a void*)
- * *(cast(void**)e + 1)
- */
- e = e->castTo(sc, tvoidptr->pointerTo());
- e = new AddExp(e->loc, e, new IntegerExp(1));
- e = new PtrExp(e->loc, e);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- if (ident == Id::outer && sym->vthis)
- {
- if (sym->vthis->semanticRun == PASSinit)
- dsymbolSemantic(sym->vthis, NULL);
-
- if (ClassDeclaration *cdp = sym->toParent2()->isClassDeclaration())
- {
- DotVarExp *dve = new DotVarExp(e->loc, e, sym->vthis);
- dve->type = cdp->type->addMod(e->type->mod);
- return dve;
- }
-
- /* Bugzilla 15839: Find closest parent class through nested functions.
- */
- for (Dsymbol *p = sym->toParent2(); p; p = p->toParent2())
- {
- FuncDeclaration *fd = p->isFuncDeclaration();
- if (!fd)
- break;
- if (fd->isNested())
- continue;
- AggregateDeclaration *ad = fd->isThis();
- if (!ad)
- break;
- if (ad->isClassDeclaration())
- {
- ThisExp *ve = new ThisExp(e->loc);
-
- ve->var = fd->vthis;
- const bool nestedError = fd->vthis->checkNestedReference(sc, e->loc);
- assert(!nestedError);
-
- ve->type = fd->vthis->type->addMod(e->type->mod);
- return ve;
- }
- break;
- }
-
- // Continue to show enclosing function's frame (stack or closure).
- DotVarExp *dve = new DotVarExp(e->loc, e, sym->vthis);
- dve->type = sym->vthis->type->addMod(e->type->mod);
- return dve;
- }
-
- return noMember(sc, e, ident, flag & 1);
- }
- if (!(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, s))
- {
- return noMember(sc, e, ident, flag);
- }
- if (!s->isFuncDeclaration()) // because of overloading
- {
- s->checkDeprecated(e->loc, sc);
- if (Declaration *d = s->isDeclaration())
- d->checkDisabled(e->loc, sc);
- }
- s = s->toAlias();
-
- EnumMember *em = s->isEnumMember();
- if (em)
- {
- return em->getVarExp(e->loc, sc);
- }
-
- if (VarDeclaration *v = s->isVarDeclaration())
- {
- if (!v->type ||
- (!v->type->deco && v->inuse))
- {
- if (v->inuse) // Bugzilla 9494
- e->error("circular reference to %s `%s`", v->kind(), v->toPrettyChars());
- else
- e->error("forward reference to %s `%s`", v->kind(), v->toPrettyChars());
- return new ErrorExp();
- }
- if (v->type->ty == Terror)
- return new ErrorExp();
-
- if ((v->storage_class & STCmanifest) && v->_init)
- {
- if (v->inuse)
- {
- e->error("circular initialization of %s `%s`", v->kind(), v->toPrettyChars());
- return new ErrorExp();
- }
- checkAccess(e->loc, sc, NULL, v);
- Expression *ve = new VarExp(e->loc, v);
- ve = expressionSemantic(ve, sc);
- return ve;
- }
- }
-
- if (Type *t = s->getType())
- {
- return expressionSemantic(new TypeExp(e->loc, t), sc);
- }
-
- TemplateMixin *tm = s->isTemplateMixin();
- if (tm)
- {
- Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm));
- de->type = e->type;
- return de;
- }
-
- TemplateDeclaration *td = s->isTemplateDeclaration();
- if (td)
- {
- if (e->op == TOKtype)
- e = new TemplateExp(e->loc, td);
- else
- e = new DotTemplateExp(e->loc, e, td);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- TemplateInstance *ti = s->isTemplateInstance();
- if (ti)
- {
- if (!ti->semanticRun)
- {
- dsymbolSemantic(ti, sc);
- if (!ti->inst || ti->errors) // if template failed to expand
- return new ErrorExp();
- }
- s = ti->inst->toAlias();
- if (!s->isTemplateInstance())
- goto L1;
- if (e->op == TOKtype)
- e = new ScopeExp(e->loc, ti);
- else
- e = new DotExp(e->loc, e, new ScopeExp(e->loc, ti));
- return expressionSemantic(e, sc);
- }
-
- if (s->isImport() || s->isModule() || s->isPackage())
- {
- e = ::resolve(e->loc, sc, s, false);
- return e;
- }
-
- OverloadSet *o = s->isOverloadSet();
- if (o)
- {
- OverExp *oe = new OverExp(e->loc, o);
- if (e->op == TOKtype)
- return oe;
- return new DotExp(e->loc, e, oe);
- }
-
- Declaration *d = s->isDeclaration();
- if (!d)
- {
- e->error("%s.%s is not a declaration", e->toChars(), ident->toChars());
- return new ErrorExp();
- }
-
- if (e->op == TOKtype)
- {
- /* It's:
- * Class.d
- */
- if (TupleDeclaration *tup = d->isTupleDeclaration())
- {
- e = new TupleExp(e->loc, tup);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (d->needThis() && sc->intypeof != 1)
- {
- /* Rewrite as:
- * this.d
- */
- if (hasThis(sc))
- {
- // This is almost same as getRightThis() in expression.c
- Expression *e1 = new ThisExp(e->loc);
- e1 = expressionSemantic(e1, sc);
- L2:
- Type *t = e1->type->toBasetype();
- ClassDeclaration *cd = e->type->isClassHandle();
- ClassDeclaration *tcd = t->isClassHandle();
- if (cd && tcd && (tcd == cd || cd->isBaseOf(tcd, NULL)))
- {
- e = new DotTypeExp(e1->loc, e1, cd);
- e = new DotVarExp(e->loc, e, d);
- e = expressionSemantic(e, sc);
- return e;
- }
- if (tcd && tcd->isNested())
- { /* e1 is the 'this' pointer for an inner class: tcd.
- * Rewrite it as the 'this' pointer for the outer class.
- */
-
- e1 = new DotVarExp(e->loc, e1, tcd->vthis);
- e1->type = tcd->vthis->type;
- e1->type = e1->type->addMod(t->mod);
- // Do not call checkNestedRef()
- //e1 = expressionSemantic(e1, sc);
-
- // Skip up over nested functions, and get the enclosing
- // class type.
- int n = 0;
- for (s = tcd->toParent();
- s && s->isFuncDeclaration();
- s = s->toParent())
- { FuncDeclaration *f = s->isFuncDeclaration();
- if (f->vthis)
- {
- //printf("rewriting e1 to %s's this\n", f->toChars());
- n++;
- e1 = new VarExp(e->loc, f->vthis);
- }
- else
- {
- e = new VarExp(e->loc, d);
- return e;
- }
- }
- if (s && s->isClassDeclaration())
- { e1->type = s->isClassDeclaration()->type;
- e1->type = e1->type->addMod(t->mod);
- if (n > 1)
- e1 = expressionSemantic(e1, sc);
- }
- else
- e1 = expressionSemantic(e1, sc);
- goto L2;
- }
- }
- }
- //printf("e = %s, d = %s\n", e->toChars(), d->toChars());
- if (d->semanticRun == PASSinit)
- dsymbolSemantic(d, NULL);
- checkAccess(e->loc, sc, e, d);
- VarExp *ve = new VarExp(e->loc, d);
- if (d->isVarDeclaration() && d->needThis())
- ve->type = d->type->addMod(e->type->mod);
- return ve;
- }
-
- bool unreal = e->op == TOKvar && ((VarExp *)e)->var->isField();
- if (d->isDataseg() || (unreal && d->isField()))
- {
- // (e, d)
- checkAccess(e->loc, sc, e, d);
- Expression *ve = new VarExp(e->loc, d);
- e = unreal ? ve : new CommaExp(e->loc, e, ve);
- e = expressionSemantic(e, sc);
- return e;
- }
-
- e = new DotVarExp(e->loc, e, d);
- e = expressionSemantic(e, sc);
- return e;
-}
-
-ClassDeclaration *TypeClass::isClassHandle()
-{
- return sym;
-}
-
-bool TypeClass::isscope()
-{
- return sym->isscope;
-}
-
-bool TypeClass::isBaseOf(Type *t, int *poffset)
-{
- if (t && t->ty == Tclass)
- {
- ClassDeclaration *cd = ((TypeClass *)t)->sym;
- if (sym->isBaseOf(cd, poffset))
- return true;
- }
- return false;
-}
-
-MATCH TypeClass::implicitConvTo(Type *to)
-{
- //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to->toChars(), toChars());
- MATCH m = constConv(to);
- if (m > MATCHnomatch)
- return m;
-
- ClassDeclaration *cdto = to->isClassHandle();
- if (cdto)
- {
- //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to->toChars(), toChars(), cdto->isBaseInfoComplete(), sym->isBaseInfoComplete());
- if (cdto->semanticRun < PASSsemanticdone && !cdto->isBaseInfoComplete())
- dsymbolSemantic(cdto, NULL);
- if (sym->semanticRun < PASSsemanticdone && !sym->isBaseInfoComplete())
- dsymbolSemantic(sym, NULL);
- if (cdto->isBaseOf(sym, NULL) && MODimplicitConv(mod, to->mod))
- {
- //printf("'to' is base\n");
- return MATCHconvert;
- }
- }
-
- m = MATCHnomatch;
- if (sym->aliasthis && !(att & RECtracing))
- {
- att = (AliasThisRec)(att | RECtracing);
- m = aliasthisOf()->implicitConvTo(to);
- att = (AliasThisRec)(att & ~RECtracing);
- }
-
- return m;
-}
-
-MATCH TypeClass::constConv(Type *to)
-{
- if (equals(to))
- return MATCHexact;
- if (ty == to->ty && sym == ((TypeClass *)to)->sym &&
- MODimplicitConv(mod, to->mod))
- return MATCHconst;
-
- /* Conversion derived to const(base)
- */
- int offset = 0;
- if (to->isBaseOf(this, &offset) && offset == 0 &&
- MODimplicitConv(mod, to->mod))
- {
- // Disallow:
- // derived to base
- // inout(derived) to inout(base)
- if (!to->isMutable() && !to->isWild())
- return MATCHconvert;
- }
-
- return MATCHnomatch;
-}
-
-unsigned char TypeClass::deduceWild(Type *t, bool isRef)
-{
- ClassDeclaration *cd = t->isClassHandle();
- if (cd && (sym == cd || cd->isBaseOf(sym, NULL)))
- return Type::deduceWild(t, isRef);
-
- unsigned char wm = 0;
-
- if (t->hasWild() && sym->aliasthis && !(att & RECtracing))
- {
- att = (AliasThisRec)(att | RECtracing);
- wm = aliasthisOf()->deduceWild(t, isRef);
- att = (AliasThisRec)(att & ~RECtracing);
- }
-
- return wm;
-}
-
-Type *TypeClass::toHeadMutable()
-{
- return this;
-}
-
-Expression *TypeClass::defaultInit(Loc loc)
-{
- return new NullExp(loc, this);
-}
-
-bool TypeClass::isZeroInit(Loc)
-{
- return true;
-}
-
-bool TypeClass::isBoolean()
-{
- return true;
-}
-
-bool TypeClass::hasPointers()
-{
- return true;
-}
-
-/***************************** TypeTuple *****************************/
-
-TypeTuple::TypeTuple(Parameters *arguments)
- : Type(Ttuple)
-{
- //printf("TypeTuple(this = %p)\n", this);
- this->arguments = arguments;
- //printf("TypeTuple() %p, %s\n", this, toChars());
-}
-
-/****************
- * Form TypeTuple from the types of the expressions.
- * Assume exps[] is already tuple expanded.
- */
-
-TypeTuple::TypeTuple(Expressions *exps)
- : Type(Ttuple)
-{
- Parameters *arguments = new Parameters;
- if (exps)
- {
- arguments->setDim(exps->length);
- for (size_t i = 0; i < exps->length; i++)
- { Expression *e = (*exps)[i];
- if (e->type->ty == Ttuple)
- e->error("cannot form tuple of tuples");
- Parameter *arg = new Parameter(STCundefined, e->type, NULL, NULL, NULL);
- (*arguments)[i] = arg;
- }
- }
- this->arguments = arguments;
- //printf("TypeTuple() %p, %s\n", this, toChars());
-}
-
-TypeTuple *TypeTuple::create(Parameters *arguments)
-{
- return new TypeTuple(arguments);
-}
-
-/*******************************************
- * Type tuple with 0, 1 or 2 types in it.
- */
-TypeTuple::TypeTuple()
- : Type(Ttuple)
-{
- arguments = new Parameters();
-}
-
-TypeTuple::TypeTuple(Type *t1)
- : Type(Ttuple)
-{
- arguments = new Parameters();
- arguments->push(new Parameter(0, t1, NULL, NULL, NULL));
-}
-
-TypeTuple::TypeTuple(Type *t1, Type *t2)
- : Type(Ttuple)
-{
- arguments = new Parameters();
- arguments->push(new Parameter(0, t1, NULL, NULL, NULL));
- arguments->push(new Parameter(0, t2, NULL, NULL, NULL));
-}
-
-const char *TypeTuple::kind()
-{
- return "tuple";
-}
-
-Type *TypeTuple::syntaxCopy()
-{
- Parameters *args = Parameter::arraySyntaxCopy(arguments);
- Type *t = new TypeTuple(args);
- t->mod = mod;
- return t;
-}
-
-bool TypeTuple::equals(RootObject *o)
-{
- Type *t = (Type *)o;
- //printf("TypeTuple::equals(%s, %s)\n", toChars(), t->toChars());
- if (this == t)
- return true;
- if (t->ty == Ttuple)
- {
- TypeTuple *tt = (TypeTuple *)t;
- if (arguments->length == tt->arguments->length)
- {
- for (size_t i = 0; i < tt->arguments->length; i++)
- {
- Parameter *arg1 = (*arguments)[i];
- Parameter *arg2 = (*tt->arguments)[i];
- if (!arg1->type->equals(arg2->type))
- return false;
- }
- return true;
- }
- }
- return false;
-}
-
-Expression *TypeTuple::getProperty(Loc loc, Identifier *ident, int flag)
-{
- Expression *e;
-
- if (ident == Id::length)
- {
- e = new IntegerExp(loc, arguments->length, Type::tsize_t);
- }
- else if (ident == Id::_init)
- {
- e = defaultInitLiteral(loc);
- }
- else if (flag)
- {
- e = NULL;
- }
- else
- {
- error(loc, "no property `%s` for tuple `%s`", ident->toChars(), toChars());
- e = new ErrorExp();
- }
- return e;
-}
-
-Expression *TypeTuple::defaultInit(Loc loc)
-{
- Expressions *exps = new Expressions();
- exps->setDim(arguments->length);
- for (size_t i = 0; i < arguments->length; i++)
- {
- Parameter *p = (*arguments)[i];
- assert(p->type);
- Expression *e = p->type->defaultInitLiteral(loc);
- if (e->op == TOKerror)
- return e;
- (*exps)[i] = e;
- }
- return new TupleExp(loc, exps);
-}
-
-/***************************** TypeSlice *****************************/
-
-/* This is so we can slice a TypeTuple */
-
-TypeSlice::TypeSlice(Type *next, Expression *lwr, Expression *upr)
- : TypeNext(Tslice, next)
-{
- //printf("TypeSlice[%s .. %s]\n", lwr->toChars(), upr->toChars());
- this->lwr = lwr;
- this->upr = upr;
-}
-
-const char *TypeSlice::kind()
-{
- return "slice";
-}
-
-Type *TypeSlice::syntaxCopy()
-{
- Type *t = new TypeSlice(next->syntaxCopy(), lwr->syntaxCopy(), upr->syntaxCopy());
- t->mod = mod;
- return t;
-}
-
-void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
-{
- next->resolve(loc, sc, pe, pt, ps, intypeid);
- if (*pe)
- {
- // It's really a slice expression
- if (Dsymbol *s = getDsymbol(*pe))
- *pe = new DsymbolExp(loc, s);
- *pe = new ArrayExp(loc, *pe, new IntervalExp(loc, lwr, upr));
- }
- else if (*ps)
- {
- Dsymbol *s = *ps;
- TupleDeclaration *td = s->isTupleDeclaration();
- if (td)
- {
- /* It's a slice of a TupleDeclaration
- */
- ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td);
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
- sc = sc->startCTFE();
- lwr = expressionSemantic(lwr, sc);
- upr = expressionSemantic(upr, sc);
- sc = sc->endCTFE();
- sc = sc->pop();
-
- lwr = lwr->ctfeInterpret();
- upr = upr->ctfeInterpret();
- uinteger_t i1 = lwr->toUInteger();
- uinteger_t i2 = upr->toUInteger();
-
- if (!(i1 <= i2 && i2 <= td->objects->length))
- {
- error(loc, "slice [%llu..%llu] is out of range of [0..%u]", i1, i2, td->objects->length);
- *ps = NULL;
- *pt = Type::terror;
- return;
- }
-
- if (i1 == 0 && i2 == td->objects->length)
- {
- *ps = td;
- return;
- }
-
- /* Create a new TupleDeclaration which
- * is a slice [i1..i2] out of the old one.
- */
- Objects *objects = new Objects;
- objects->setDim((size_t)(i2 - i1));
- for (size_t i = 0; i < objects->length; i++)
- {
- (*objects)[i] = (*td->objects)[(size_t)i1 + i];
- }
-
- TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects);
- *ps = tds;
- }
- else
- goto Ldefault;
- }
- else
- {
- if ((*pt)->ty != Terror)
- next = *pt; // prevent re-running semantic() on 'next'
- Ldefault:
- Type::resolve(loc, sc, pe, pt, ps, intypeid);
- }
-}
-
-/***************************** TypeNull *****************************/
-
-TypeNull::TypeNull()
- : Type(Tnull)
-{
-}
-
-const char *TypeNull::kind()
-{
- return "null";
-}
-
-Type *TypeNull::syntaxCopy()
-{
- // No semantic analysis done, no need to copy
- return this;
-}
-
-MATCH TypeNull::implicitConvTo(Type *to)
-{
- //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to);
- //printf("from: %s\n", toChars());
- //printf("to : %s\n", to->toChars());
- MATCH m = Type::implicitConvTo(to);
- if (m != MATCHnomatch)
- return m;
-
- // NULL implicitly converts to any pointer type or dynamic array
- //if (type->ty == Tpointer && type->nextOf()->ty == Tvoid)
- {
- Type *tb = to->toBasetype();
- if (tb->ty == Tnull ||
- tb->ty == Tpointer || tb->ty == Tarray ||
- tb->ty == Taarray || tb->ty == Tclass ||
- tb->ty == Tdelegate)
- return MATCHconst;
- }
-
- return MATCHnomatch;
-}
-
-bool TypeNull::isBoolean()
-{
- return true;
-}
-
-d_uns64 TypeNull::size(Loc loc)
-{
- return tvoidptr->size(loc);
-}
-
-Expression *TypeNull::defaultInit(Loc)
-{
- return new NullExp(Loc(), Type::tnull);
-}
-
-/***************************** TypeNoreturn *****************************/
-
-TypeNoreturn::TypeNoreturn()
- : Type(Tnoreturn)
-{
- //printf("TypeNoreturn %p\n", this);
-}
-
-const char *TypeNoreturn::kind()
-{
- return "noreturn";
-}
-
-Type *TypeNoreturn::syntaxCopy()
-{
- // No semantic analysis done, no need to copy
- return this;
-}
-
-MATCH TypeNoreturn::implicitConvTo(Type *to)
-{
- //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to);
- //printf("from: %s\n", toChars());
- //printf("to : %s\n", to.toChars());
- MATCH m = Type::implicitConvTo(to);
- return (m == MATCHexact) ? MATCHexact : MATCHconvert;
-}
-
-bool TypeNoreturn::isBoolean()
-{
- return true; // bottom type can be implicitly converted to any other type
-}
-
-d_uns64 TypeNoreturn::size(Loc)
-{
- return 0;
-}
-
-unsigned TypeNoreturn::alignsize()
-{
- return 0;
-}
-
-/***********************************************************
- * Encapsulate Parameters* so .length and [i] can be used on it.
- * https://dlang.org/spec/function.html#ParameterList
- */
-
-ParameterList::ParameterList(Parameters *parameters, VarArg varargs)
-{
- this->parameters = parameters;
- this->varargs = varargs;
-}
-
-size_t ParameterList::length()
-{
- return Parameter::dim(parameters);
-}
-
-/***************************** Parameter *****************************/
-
-Parameter::Parameter(StorageClass storageClass, Type *type, Identifier *ident,
- Expression *defaultArg, UserAttributeDeclaration *userAttribDecl)
-{
- this->type = type;
- this->ident = ident;
- this->storageClass = storageClass;
- this->defaultArg = defaultArg;
- this->userAttribDecl = userAttribDecl;
-}
-
-Parameter *Parameter::create(StorageClass storageClass, Type *type, Identifier *ident,
- Expression *defaultArg, UserAttributeDeclaration *userAttribDecl)
-{
- return new Parameter(storageClass, type, ident, defaultArg, userAttribDecl);
-}
-
-Parameter *Parameter::syntaxCopy()
-{
- return new Parameter(storageClass,
- type ? type->syntaxCopy() : NULL,
- ident,
- defaultArg ? defaultArg->syntaxCopy() : NULL,
- userAttribDecl ? (UserAttributeDeclaration *) userAttribDecl->syntaxCopy(NULL) : NULL);
-}
-
-Parameters *Parameter::arraySyntaxCopy(Parameters *parameters)
-{
- Parameters *params = NULL;
- if (parameters)
- {
- params = new Parameters();
- params->setDim(parameters->length);
- for (size_t i = 0; i < params->length; i++)
- (*params)[i] = (*parameters)[i]->syntaxCopy();
- }
- return params;
-}
-
-/****************************************************
- * Determine if parameter is a lazy array of delegates.
- * If so, return the return type of those delegates.
- * If not, return NULL.
- *
- * Returns T if the type is one of the following forms:
- * T delegate()[]
- * T delegate()[dim]
- */
-
-Type *Parameter::isLazyArray()
-{
- Type *tb = type->toBasetype();
- if (tb->ty == Tsarray || tb->ty == Tarray)
- {
- Type *tel = ((TypeArray *)tb)->next->toBasetype();
- if (tel->ty == Tdelegate)
- {
- TypeDelegate *td = (TypeDelegate *)tel;
- TypeFunction *tf = td->next->toTypeFunction();
-
- if (tf->parameterList.varargs == VARARGnone && tf->parameterList.length() == 0)
- {
- return tf->next; // return type of delegate
- }
- }
- }
- return NULL;
-}
-
-/***************************************
- * Determine number of arguments, folding in tuples.
- */
-
-static int dimDg(void *ctx, size_t, Parameter *)
-{
- ++*(size_t *)ctx;
- return 0;
-}
-
-size_t Parameter::dim(Parameters *parameters)
-{
- size_t n = 0;
- Parameter_foreach(parameters, &dimDg, &n);
- return n;
-}
-
-/***************************************
- * Get nth Parameter, folding in tuples.
- * Returns:
- * Parameter* nth Parameter
- * NULL not found, *pn gets incremented by the number
- * of Parameters
- */
-
-struct GetNthParamCtx
-{
- size_t nth;
- Parameter *param;
-};
-
-static int getNthParamDg(void *ctx, size_t n, Parameter *p)
-{
- GetNthParamCtx *c = (GetNthParamCtx *)ctx;
- if (n == c->nth)
- {
- c->param = p;
- return 1;
- }
- return 0;
-}
-
-Parameter *Parameter::getNth(Parameters *parameters, size_t nth, size_t *)
-{
- GetNthParamCtx ctx = { nth, NULL };
- int res = Parameter_foreach(parameters, &getNthParamDg, &ctx);
- return res ? ctx.param : NULL;
-}
-
-/***************************************
- * Expands tuples in args in depth first order. Calls
- * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter.
- * If dg returns !=0, stops and returns that value else returns 0.
- * Use this function to avoid the O(N + N^2/2) complexity of
- * calculating dim and calling N times getNth.
- */
-
-int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn)
-{
- assert(dg);
- if (!parameters)
- return 0;
-
- size_t n = pn ? *pn : 0; // take over index
- int result = 0;
- for (size_t i = 0; i < parameters->length; i++)
- {
- Parameter *p = (*parameters)[i];
- Type *t = p->type->toBasetype();
-
- if (t->ty == Ttuple)
- {
- TypeTuple *tu = (TypeTuple *)t;
- result = Parameter_foreach(tu->arguments, dg, ctx, &n);
- }
- else
- result = dg(ctx, n++, p);
-
- if (result)
- break;
- }
-
- if (pn)
- *pn = n; // update index
- return result;
-}
-
-
-const char *Parameter::toChars()
-{
- return ident ? ident->toChars() : "__anonymous_param";
-}
-
-/*********************************
- * Compute covariance of parameters `this` and `p`
- * as determined by the storage classes of both.
- * Params:
- * p = Parameter to compare with
- * Returns:
- * true = `this` can be used in place of `p`
- * false = nope
- */
-bool Parameter::isCovariant(bool returnByRef, const Parameter *p) const
-{
- const StorageClass stc = STCref | STCin | STCout | STClazy;
- if ((this->storageClass & stc) != (p->storageClass & stc))
- return false;
-
- return isCovariantScope(returnByRef, this->storageClass, p->storageClass);
-}
-
-bool Parameter::isCovariantScope(bool returnByRef, StorageClass from, StorageClass to)
-{
- if (from == to)
- return true;
-
- struct SR
- {
- /* Classification of 'scope-return-ref' possibilities
- */
- enum
- {
- SRNone,
- SRScope,
- SRReturnScope,
- SRRef,
- SRReturnRef,
- SRRefScope,
- SRReturnRef_Scope,
- SRRef_ReturnScope,
- SRMAX,
- };
-
- /* Shrinking the representation is necessary because StorageClass is so wide
- * Params:
- * returnByRef = true if the function returns by ref
- * stc = storage class of parameter
- */
- static unsigned buildSR(bool returnByRef, StorageClass stc)
- {
- unsigned result;
- StorageClass stc2 = stc & (STCref | STCscope | STCreturn);
- if (stc2 == 0)
- result = SRNone;
- else if (stc2 == STCref)
- result = SRRef;
- else if (stc2 == STCscope)
- result = SRScope;
- else if (stc2 == (STCscope | STCreturn))
- result = SRReturnScope;
- else if (stc2 == (STCref | STCreturn))
- result = SRReturnRef;
- else if (stc2 == (STCscope | STCref))
- result = SRRefScope;
- else if (stc2 == (STCscope | STCref | STCreturn))
- result = returnByRef ? SRReturnRef_Scope : SRRef_ReturnScope;
- else
- assert(0);
- return result;
- }
-
- static void covariantInit(bool covariant[SRMAX][SRMAX])
- {
- /* Initialize covariant[][] with this:
-
- From\To n rs s
- None X
- ReturnScope X X
- Scope X X X
-
- From\To r rr rs rr-s r-rs
- Ref X X
- ReturnRef X
- RefScope X X X X X
- ReturnRef-Scope X X
- Ref-ReturnScope X X X
- */
- for (int i = 0; i < SRMAX; i++)
- {
- covariant[i][i] = true;
- covariant[SRRefScope][i] = true;
- }
- covariant[SRReturnScope][SRNone] = true;
- covariant[SRScope ][SRNone] = true;
- covariant[SRScope ][SRReturnScope] = true;
-
- covariant[SRRef ][SRReturnRef] = true;
- covariant[SRReturnRef_Scope][SRReturnRef] = true;
- covariant[SRRef_ReturnScope][SRRef ] = true;
- covariant[SRRef_ReturnScope][SRReturnRef] = true;
- }
- };
-
- /* result is true if the 'from' can be used as a 'to'
- */
-
- if ((from ^ to) & STCref) // differing in 'ref' means no covariance
- return false;
-
- static bool covariant[SR::SRMAX][SR::SRMAX];
- static bool init = false;
- if (!init)
- {
- SR::covariantInit(covariant);
- init = true;
- }
-
- return covariant[SR::buildSR(returnByRef, from)][SR::buildSR(returnByRef, to)];
-}
-
-/**
- * For printing two types with qualification when necessary.
- * Params:
- * t1 = The first type to receive the type name for
- * t2 = The second type to receive the type name for
- * Returns:
- * The fully-qualified names of both types if the two type names are not the same,
- * or the unqualified names of both types if the two type names are the same.
- */
-void toAutoQualChars(const char **result, Type *t1, Type *t2)
-{
- const char *s1 = t1->toChars();
- const char *s2 = t2->toChars();
- if (strcmp(s1, s2) == 0)
- {
- s1 = t1->toPrettyChars(true);
- s2 = t2->toPrettyChars(true);
- }
- result[0] = s1;
- result[1] = s2;
-}
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
new file mode 100644
index 0000000..80e4791
--- /dev/null
+++ b/gcc/d/dmd/mtype.d
@@ -0,0 +1,7355 @@
+/**
+ * Defines a D type.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mtype.d, _mtype.d)
+ * Documentation: https://dlang.org/phobos/dmd_mtype.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mtype.d
+ */
+
+module dmd.mtype;
+
+import core.checkedint;
+import core.stdc.stdarg;
+import core.stdc.stdio;
+import core.stdc.stdlib;
+import core.stdc.string;
+
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.attrib;
+import dmd.astenums;
+import dmd.ast_node;
+import dmd.gluelayer;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dmangle;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.opover;
+import dmd.root.ctfloat;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+import dmd.root.rootobject;
+import dmd.root.stringtable;
+import dmd.target;
+import dmd.tokens;
+import dmd.typesem;
+import dmd.visitor;
+
+enum LOGDOTEXP = 0; // log ::dotExp()
+enum LOGDEFAULTINIT = 0; // log ::defaultInit()
+
+enum SIZE_INVALID = (~cast(d_uns64)0); // error return from size() functions
+
+
+/***************************
+ * Return !=0 if modfrom can be implicitly converted to modto
+ */
+bool MODimplicitConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe
+{
+ if (modfrom == modto)
+ return true;
+
+ //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto);
+ auto X(T, U)(T m, U n)
+ {
+ return ((m << 4) | n);
+ }
+
+ switch (X(modfrom & ~MODFlags.shared_, modto & ~MODFlags.shared_))
+ {
+ case X(0, MODFlags.const_):
+ case X(MODFlags.wild, MODFlags.const_):
+ case X(MODFlags.wild, MODFlags.wildconst):
+ case X(MODFlags.wildconst, MODFlags.const_):
+ return (modfrom & MODFlags.shared_) == (modto & MODFlags.shared_);
+
+ case X(MODFlags.immutable_, MODFlags.const_):
+ case X(MODFlags.immutable_, MODFlags.wildconst):
+ return true;
+ default:
+ return false;
+ }
+}
+
+/***************************
+ * Return MATCH.exact or MATCH.constant if a method of type '() modfrom' can call a method of type '() modto'.
+ */
+MATCH MODmethodConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe
+{
+ if (modfrom == modto)
+ return MATCH.exact;
+ if (MODimplicitConv(modfrom, modto))
+ return MATCH.constant;
+
+ auto X(T, U)(T m, U n)
+ {
+ return ((m << 4) | n);
+ }
+
+ switch (X(modfrom, modto))
+ {
+ case X(0, MODFlags.wild):
+ case X(MODFlags.immutable_, MODFlags.wild):
+ case X(MODFlags.const_, MODFlags.wild):
+ case X(MODFlags.wildconst, MODFlags.wild):
+ case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.shared_ | MODFlags.immutable_, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
+ case X(MODFlags.shared_ | MODFlags.wildconst, MODFlags.shared_ | MODFlags.wild):
+ return MATCH.constant;
+
+ default:
+ return MATCH.nomatch;
+ }
+}
+
+/***************************
+ * Merge mod bits to form common mod.
+ */
+MOD MODmerge(MOD mod1, MOD mod2) pure nothrow @nogc @safe
+{
+ if (mod1 == mod2)
+ return mod1;
+
+ //printf("MODmerge(1 = %x, 2 = %x)\n", mod1, mod2);
+ MOD result = 0;
+ if ((mod1 | mod2) & MODFlags.shared_)
+ {
+ // If either type is shared, the result will be shared
+ result |= MODFlags.shared_;
+ mod1 &= ~MODFlags.shared_;
+ mod2 &= ~MODFlags.shared_;
+ }
+ if (mod1 == 0 || mod1 == MODFlags.mutable || mod1 == MODFlags.const_ || mod2 == 0 || mod2 == MODFlags.mutable || mod2 == MODFlags.const_)
+ {
+ // If either type is mutable or const, the result will be const.
+ result |= MODFlags.const_;
+ }
+ else
+ {
+ // MODFlags.immutable_ vs MODFlags.wild
+ // MODFlags.immutable_ vs MODFlags.wildconst
+ // MODFlags.wild vs MODFlags.wildconst
+ assert(mod1 & MODFlags.wild || mod2 & MODFlags.wild);
+ result |= MODFlags.wildconst;
+ }
+ return result;
+}
+
+/*********************************
+ * Store modifier name into buf.
+ */
+void MODtoBuffer(OutBuffer* buf, MOD mod) nothrow
+{
+ buf.writestring(MODtoString(mod));
+}
+
+/*********************************
+ * Returns:
+ * a human readable representation of `mod`,
+ * which is the token `mod` corresponds to
+ */
+const(char)* MODtoChars(MOD mod) nothrow pure
+{
+ /// Works because we return a literal
+ return MODtoString(mod).ptr;
+}
+
+/// Ditto
+string MODtoString(MOD mod) nothrow pure
+{
+ final switch (mod)
+ {
+ case 0:
+ return "";
+
+ case MODFlags.immutable_:
+ return "immutable";
+
+ case MODFlags.shared_:
+ return "shared";
+
+ case MODFlags.shared_ | MODFlags.const_:
+ return "shared const";
+
+ case MODFlags.const_:
+ return "const";
+
+ case MODFlags.shared_ | MODFlags.wild:
+ return "shared inout";
+
+ case MODFlags.wild:
+ return "inout";
+
+ case MODFlags.shared_ | MODFlags.wildconst:
+ return "shared inout const";
+
+ case MODFlags.wildconst:
+ return "inout const";
+ }
+}
+
+
+/************************************
+ * Convert MODxxxx to STCxxx
+ */
+StorageClass ModToStc(uint mod) pure nothrow @nogc @safe
+{
+ StorageClass stc = 0;
+ if (mod & MODFlags.immutable_)
+ stc |= STC.immutable_;
+ if (mod & MODFlags.const_)
+ stc |= STC.const_;
+ if (mod & MODFlags.wild)
+ stc |= STC.wild;
+ if (mod & MODFlags.shared_)
+ stc |= STC.shared_;
+ return stc;
+}
+
+///Returns true if ty is char, wchar, or dchar
+bool isSomeChar(TY ty) pure nothrow @nogc @safe
+{
+ return ty == Tchar || ty == Twchar || ty == Tdchar;
+}
+
+/****************
+ * dotExp() bit flags
+ */
+enum DotExpFlag
+{
+ gag = 1, // don't report "not a property" error and just return null
+ noDeref = 2, // the use of the expression will not attempt a dereference
+}
+
+/// Result of a check whether two types are covariant
+enum Covariant
+{
+ distinct = 0, /// types are distinct
+ yes = 1, /// types are covariant
+ no = 2, /// arguments match as far as overloading goes, but types are not covariant
+ fwdref = 3, /// cannot determine covariance because of forward references
+}
+
+/***********************************************************
+ */
+extern (C++) abstract class Type : ASTNode
+{
+ TY ty;
+ MOD mod; // modifiers MODxxxx
+ char* deco;
+
+ static struct Mcache
+ {
+ /* These are cached values that are lazily evaluated by constOf(), immutableOf(), etc.
+ * They should not be referenced by anybody but mtype.d.
+ * They can be null if not lazily evaluated yet.
+ * Note that there is no "shared immutable", because that is just immutable
+ * The point of this is to reduce the size of each Type instance as
+ * we bank on the idea that usually only one of variants exist.
+ * It will also speed up code because these are rarely referenced and
+ * so need not be in the cache.
+ */
+ Type cto; // MODFlags.const_
+ Type ito; // MODFlags.immutable_
+ Type sto; // MODFlags.shared_
+ Type scto; // MODFlags.shared_ | MODFlags.const_
+ Type wto; // MODFlags.wild
+ Type wcto; // MODFlags.wildconst
+ Type swto; // MODFlags.shared_ | MODFlags.wild
+ Type swcto; // MODFlags.shared_ | MODFlags.wildconst
+ }
+ private Mcache* mcache;
+
+ Type pto; // merged pointer to this type
+ Type rto; // reference to this type
+ Type arrayof; // array of this type
+
+ TypeInfoDeclaration vtinfo; // TypeInfo object for this Type
+
+ type* ctype; // for back end
+
+ extern (C++) __gshared Type tvoid;
+ extern (C++) __gshared Type tint8;
+ extern (C++) __gshared Type tuns8;
+ extern (C++) __gshared Type tint16;
+ extern (C++) __gshared Type tuns16;
+ extern (C++) __gshared Type tint32;
+ extern (C++) __gshared Type tuns32;
+ extern (C++) __gshared Type tint64;
+ extern (C++) __gshared Type tuns64;
+ extern (C++) __gshared Type tint128;
+ extern (C++) __gshared Type tuns128;
+ extern (C++) __gshared Type tfloat32;
+ extern (C++) __gshared Type tfloat64;
+ extern (C++) __gshared Type tfloat80;
+ extern (C++) __gshared Type timaginary32;
+ extern (C++) __gshared Type timaginary64;
+ extern (C++) __gshared Type timaginary80;
+ extern (C++) __gshared Type tcomplex32;
+ extern (C++) __gshared Type tcomplex64;
+ extern (C++) __gshared Type tcomplex80;
+ extern (C++) __gshared Type tbool;
+ extern (C++) __gshared Type tchar;
+ extern (C++) __gshared Type twchar;
+ extern (C++) __gshared Type tdchar;
+
+ // Some special types
+ extern (C++) __gshared Type tshiftcnt;
+ extern (C++) __gshared Type tvoidptr; // void*
+ extern (C++) __gshared Type tstring; // immutable(char)[]
+ extern (C++) __gshared Type twstring; // immutable(wchar)[]
+ extern (C++) __gshared Type tdstring; // immutable(dchar)[]
+ extern (C++) __gshared Type terror; // for error recovery
+ extern (C++) __gshared Type tnull; // for null type
+ extern (C++) __gshared Type tnoreturn; // for bottom type typeof(*null)
+
+ extern (C++) __gshared Type tsize_t; // matches size_t alias
+ extern (C++) __gshared Type tptrdiff_t; // matches ptrdiff_t alias
+ extern (C++) __gshared Type thash_t; // matches hash_t alias
+
+ extern (C++) __gshared ClassDeclaration dtypeinfo;
+ extern (C++) __gshared ClassDeclaration typeinfoclass;
+ extern (C++) __gshared ClassDeclaration typeinfointerface;
+ extern (C++) __gshared ClassDeclaration typeinfostruct;
+ extern (C++) __gshared ClassDeclaration typeinfopointer;
+ extern (C++) __gshared ClassDeclaration typeinfoarray;
+ extern (C++) __gshared ClassDeclaration typeinfostaticarray;
+ extern (C++) __gshared ClassDeclaration typeinfoassociativearray;
+ extern (C++) __gshared ClassDeclaration typeinfovector;
+ extern (C++) __gshared ClassDeclaration typeinfoenum;
+ extern (C++) __gshared ClassDeclaration typeinfofunction;
+ extern (C++) __gshared ClassDeclaration typeinfodelegate;
+ extern (C++) __gshared ClassDeclaration typeinfotypelist;
+ extern (C++) __gshared ClassDeclaration typeinfoconst;
+ extern (C++) __gshared ClassDeclaration typeinfoinvariant;
+ extern (C++) __gshared ClassDeclaration typeinfoshared;
+ extern (C++) __gshared ClassDeclaration typeinfowild;
+
+ extern (C++) __gshared TemplateDeclaration rtinfo;
+
+ extern (C++) __gshared Type[TMAX] basic;
+
+ extern (D) __gshared StringTable!Type stringtable;
+ extern (D) private __gshared ubyte[TMAX] sizeTy = ()
+ {
+ ubyte[TMAX] sizeTy = __traits(classInstanceSize, TypeBasic);
+ sizeTy[Tsarray] = __traits(classInstanceSize, TypeSArray);
+ sizeTy[Tarray] = __traits(classInstanceSize, TypeDArray);
+ sizeTy[Taarray] = __traits(classInstanceSize, TypeAArray);
+ sizeTy[Tpointer] = __traits(classInstanceSize, TypePointer);
+ sizeTy[Treference] = __traits(classInstanceSize, TypeReference);
+ sizeTy[Tfunction] = __traits(classInstanceSize, TypeFunction);
+ sizeTy[Tdelegate] = __traits(classInstanceSize, TypeDelegate);
+ sizeTy[Tident] = __traits(classInstanceSize, TypeIdentifier);
+ sizeTy[Tinstance] = __traits(classInstanceSize, TypeInstance);
+ sizeTy[Ttypeof] = __traits(classInstanceSize, TypeTypeof);
+ sizeTy[Tenum] = __traits(classInstanceSize, TypeEnum);
+ sizeTy[Tstruct] = __traits(classInstanceSize, TypeStruct);
+ sizeTy[Tclass] = __traits(classInstanceSize, TypeClass);
+ sizeTy[Ttuple] = __traits(classInstanceSize, TypeTuple);
+ sizeTy[Tslice] = __traits(classInstanceSize, TypeSlice);
+ sizeTy[Treturn] = __traits(classInstanceSize, TypeReturn);
+ sizeTy[Terror] = __traits(classInstanceSize, TypeError);
+ sizeTy[Tnull] = __traits(classInstanceSize, TypeNull);
+ sizeTy[Tvector] = __traits(classInstanceSize, TypeVector);
+ sizeTy[Ttraits] = __traits(classInstanceSize, TypeTraits);
+ sizeTy[Tmixin] = __traits(classInstanceSize, TypeMixin);
+ sizeTy[Tnoreturn] = __traits(classInstanceSize, TypeNoreturn);
+ sizeTy[Ttag] = __traits(classInstanceSize, TypeTag);
+ return sizeTy;
+ }();
+
+ final extern (D) this(TY ty)
+ {
+ this.ty = ty;
+ }
+
+ const(char)* kind() const nothrow pure @nogc @safe
+ {
+ assert(false); // should be overridden
+ }
+
+ final Type copy() nothrow const
+ {
+ Type t = cast(Type)mem.xmalloc(sizeTy[ty]);
+ memcpy(cast(void*)t, cast(void*)this, sizeTy[ty]);
+ return t;
+ }
+
+ Type syntaxCopy()
+ {
+ fprintf(stderr, "this = %s, ty = %d\n", toChars(), ty);
+ assert(0);
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ Type t = cast(Type)o;
+ //printf("Type::equals(%s, %s)\n", toChars(), t.toChars());
+ // deco strings are unique
+ // and semantic() has been run
+ if (this == o || ((t && deco == t.deco) && deco !is null))
+ {
+ //printf("deco = '%s', t.deco = '%s'\n", deco, t.deco);
+ return true;
+ }
+ //if (deco && t && t.deco) printf("deco = '%s', t.deco = '%s'\n", deco, t.deco);
+ return false;
+ }
+
+ final bool equivalent(Type t)
+ {
+ return immutableOf().equals(t.immutableOf());
+ }
+
+ // kludge for template.isType()
+ override final DYNCAST dyncast() const
+ {
+ return DYNCAST.type;
+ }
+
+ extern (D)
+ final Mcache* getMcache()
+ {
+ if (!mcache)
+ mcache = cast(Mcache*) mem.xcalloc(Mcache.sizeof, 1);
+ return mcache;
+ }
+
+ /*******************************
+ * Covariant means that 'this' can substitute for 't',
+ * i.e. a pure function is a match for an impure type.
+ * Params:
+ * t = type 'this' is covariant with
+ * pstc = if not null, store STCxxxx which would make it covariant
+ * Returns:
+ * An enum value of either `Covariant.yes` or a reason it's not covariant.
+ */
+ final Covariant covariant(Type t, StorageClass* pstc = null)
+ {
+ version (none)
+ {
+ printf("Type::covariant(t = %s) %s\n", t.toChars(), toChars());
+ printf("deco = %p, %p\n", deco, t.deco);
+ // printf("ty = %d\n", next.ty);
+ printf("mod = %x, %x\n", mod, t.mod);
+ }
+ if (pstc)
+ *pstc = 0;
+ StorageClass stc = 0;
+
+ bool notcovariant = false;
+
+ if (equals(t))
+ return Covariant.yes;
+
+ TypeFunction t1 = this.isTypeFunction();
+ TypeFunction t2 = t.isTypeFunction();
+
+ if (!t1 || !t2)
+ goto Ldistinct;
+
+ if (t1.parameterList.varargs != t2.parameterList.varargs)
+ goto Ldistinct;
+
+ if (t1.parameterList.parameters && t2.parameterList.parameters)
+ {
+ if (t1.parameterList.length != t2.parameterList.length)
+ goto Ldistinct;
+
+ foreach (i, fparam1; t1.parameterList)
+ {
+ Parameter fparam2 = t2.parameterList[i];
+
+ if (!fparam1.type.equals(fparam2.type))
+ {
+ Type tp1 = fparam1.type;
+ Type tp2 = fparam2.type;
+ if (tp1.ty == tp2.ty)
+ {
+ if (auto tc1 = tp1.isTypeClass())
+ {
+ if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
+ goto Lcov;
+ }
+ else if (auto ts1 = tp1.isTypeStruct())
+ {
+ if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
+ goto Lcov;
+ }
+ else if (tp1.ty == Tpointer)
+ {
+ if (tp2.implicitConvTo(tp1))
+ goto Lcov;
+ }
+ else if (tp1.ty == Tarray)
+ {
+ if (tp2.implicitConvTo(tp1))
+ goto Lcov;
+ }
+ else if (tp1.ty == Tdelegate)
+ {
+ if (tp1.implicitConvTo(tp2))
+ goto Lcov;
+ }
+ }
+ goto Ldistinct;
+ }
+ Lcov:
+ notcovariant |= !fparam1.isCovariant(t1.isref, fparam2);
+ }
+ }
+ else if (t1.parameterList.parameters != t2.parameterList.parameters)
+ {
+ if (t1.parameterList.length || t2.parameterList.length)
+ goto Ldistinct;
+ }
+
+ // The argument lists match
+ if (notcovariant)
+ goto Lnotcovariant;
+ if (t1.linkage != t2.linkage)
+ goto Lnotcovariant;
+
+ {
+ // Return types
+ Type t1n = t1.next;
+ Type t2n = t2.next;
+
+ if (!t1n || !t2n) // happens with return type inference
+ goto Lnotcovariant;
+
+ if (t1n.equals(t2n))
+ goto Lcovariant;
+ if (t1n.ty == Tclass && t2n.ty == Tclass)
+ {
+ /* If same class type, but t2n is const, then it's
+ * covariant. Do this test first because it can work on
+ * forward references.
+ */
+ if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
+ goto Lcovariant;
+
+ // If t1n is forward referenced:
+ ClassDeclaration cd = (cast(TypeClass)t1n).sym;
+ if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
+ cd.dsymbolSemantic(null);
+ if (!cd.isBaseInfoComplete())
+ {
+ return Covariant.fwdref;
+ }
+ }
+ if (t1n.ty == Tstruct && t2n.ty == Tstruct)
+ {
+ if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
+ goto Lcovariant;
+ }
+ else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n))
+ goto Lcovariant;
+ else if (t1n.ty == Tnull)
+ {
+ // NULL is covariant with any pointer type, but not with any
+ // dynamic arrays, associative arrays or delegates.
+ // https://issues.dlang.org/show_bug.cgi?id=8589
+ // https://issues.dlang.org/show_bug.cgi?id=19618
+ Type t2bn = t2n.toBasetype();
+ if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass)
+ goto Lcovariant;
+ }
+ // bottom type is covariant to any type
+ else if (t1n.ty == Tnoreturn)
+ goto Lcovariant;
+ }
+ goto Lnotcovariant;
+
+ Lcovariant:
+ if (t1.isref != t2.isref)
+ goto Lnotcovariant;
+
+ if (!t1.isref && (t1.isScopeQual || t2.isScopeQual))
+ {
+ StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0;
+ StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0;
+ if (t1.isreturn)
+ {
+ stc1 |= STC.return_;
+ if (!t1.isScopeQual)
+ stc1 |= STC.ref_;
+ }
+ if (t2.isreturn)
+ {
+ stc2 |= STC.return_;
+ if (!t2.isScopeQual)
+ stc2 |= STC.ref_;
+ }
+ if (!Parameter.isCovariantScope(t1.isref, stc1, stc2))
+ goto Lnotcovariant;
+ }
+
+ // We can subtract 'return ref' from 'this', but cannot add it
+ else if (t1.isreturn && !t2.isreturn)
+ goto Lnotcovariant;
+
+ /* Can convert mutable to const
+ */
+ if (!MODimplicitConv(t2.mod, t1.mod))
+ {
+ version (none)
+ {
+ //stop attribute inference with const
+ // If adding 'const' will make it covariant
+ if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_)))
+ stc |= STC.const_;
+ else
+ goto Lnotcovariant;
+ }
+ else
+ {
+ goto Ldistinct;
+ }
+ }
+
+ /* Can convert pure to impure, nothrow to throw, and nogc to gc
+ */
+ if (!t1.purity && t2.purity)
+ stc |= STC.pure_;
+
+ if (!t1.isnothrow && t2.isnothrow)
+ stc |= STC.nothrow_;
+
+ if (!t1.isnogc && t2.isnogc)
+ stc |= STC.nogc;
+
+ /* Can convert safe/trusted to system
+ */
+ if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted)
+ {
+ // Should we infer trusted or safe? Go with safe.
+ stc |= STC.safe;
+ }
+
+ if (stc)
+ {
+ if (pstc)
+ *pstc = stc;
+ goto Lnotcovariant;
+ }
+
+ //printf("\tcovaraint: 1\n");
+ return Covariant.yes;
+
+ Ldistinct:
+ //printf("\tcovaraint: 0\n");
+ return Covariant.distinct;
+
+ Lnotcovariant:
+ //printf("\tcovaraint: 2\n");
+ return Covariant.no;
+ }
+
+ /********************************
+ * For pretty-printing a type.
+ */
+ final override const(char)* toChars() const
+ {
+ OutBuffer buf;
+ buf.reserve(16);
+ HdrGenState hgs;
+ hgs.fullQual = (ty == Tclass && !mod);
+
+ .toCBuffer(this, &buf, null, &hgs);
+ return buf.extractChars();
+ }
+
+ /// ditto
+ final char* toPrettyChars(bool QualifyTypes = false)
+ {
+ OutBuffer buf;
+ buf.reserve(16);
+ HdrGenState hgs;
+ hgs.fullQual = QualifyTypes;
+
+ .toCBuffer(this, &buf, null, &hgs);
+ return buf.extractChars();
+ }
+
+ static void _init()
+ {
+ stringtable._init(14_000);
+
+ // Set basic types
+ __gshared TY* basetab =
+ [
+ Tvoid,
+ Tint8,
+ Tuns8,
+ Tint16,
+ Tuns16,
+ Tint32,
+ Tuns32,
+ Tint64,
+ Tuns64,
+ Tint128,
+ Tuns128,
+ Tfloat32,
+ Tfloat64,
+ Tfloat80,
+ Timaginary32,
+ Timaginary64,
+ Timaginary80,
+ Tcomplex32,
+ Tcomplex64,
+ Tcomplex80,
+ Tbool,
+ Tchar,
+ Twchar,
+ Tdchar,
+ Terror
+ ];
+
+ for (size_t i = 0; basetab[i] != Terror; i++)
+ {
+ Type t = new TypeBasic(basetab[i]);
+ t = t.merge();
+ basic[basetab[i]] = t;
+ }
+ basic[Terror] = new TypeError();
+
+ tnoreturn = new TypeNoreturn();
+ tnoreturn.deco = tnoreturn.merge().deco;
+ basic[Tnoreturn] = tnoreturn;
+
+ tvoid = basic[Tvoid];
+ tint8 = basic[Tint8];
+ tuns8 = basic[Tuns8];
+ tint16 = basic[Tint16];
+ tuns16 = basic[Tuns16];
+ tint32 = basic[Tint32];
+ tuns32 = basic[Tuns32];
+ tint64 = basic[Tint64];
+ tuns64 = basic[Tuns64];
+ tint128 = basic[Tint128];
+ tuns128 = basic[Tuns128];
+ tfloat32 = basic[Tfloat32];
+ tfloat64 = basic[Tfloat64];
+ tfloat80 = basic[Tfloat80];
+
+ timaginary32 = basic[Timaginary32];
+ timaginary64 = basic[Timaginary64];
+ timaginary80 = basic[Timaginary80];
+
+ tcomplex32 = basic[Tcomplex32];
+ tcomplex64 = basic[Tcomplex64];
+ tcomplex80 = basic[Tcomplex80];
+
+ tbool = basic[Tbool];
+ tchar = basic[Tchar];
+ twchar = basic[Twchar];
+ tdchar = basic[Tdchar];
+
+ tshiftcnt = tint32;
+ terror = basic[Terror];
+ tnoreturn = basic[Tnoreturn];
+ tnull = new TypeNull();
+ tnull.deco = tnull.merge().deco;
+
+ tvoidptr = tvoid.pointerTo();
+ tstring = tchar.immutableOf().arrayOf();
+ twstring = twchar.immutableOf().arrayOf();
+ tdstring = tdchar.immutableOf().arrayOf();
+
+ const isLP64 = target.isLP64;
+
+ tsize_t = basic[isLP64 ? Tuns64 : Tuns32];
+ tptrdiff_t = basic[isLP64 ? Tint64 : Tint32];
+ thash_t = tsize_t;
+ }
+
+ /**
+ * Deinitializes the global state of the compiler.
+ *
+ * This can be used to restore the state set by `_init` to its original
+ * state.
+ */
+ static void deinitialize()
+ {
+ stringtable = stringtable.init;
+ }
+
+ final d_uns64 size()
+ {
+ return size(Loc.initial);
+ }
+
+ d_uns64 size(const ref Loc loc)
+ {
+ error(loc, "no size for type `%s`", toChars());
+ return SIZE_INVALID;
+ }
+
+ uint alignsize()
+ {
+ return cast(uint)size(Loc.initial);
+ }
+
+ final Type trySemantic(const ref Loc loc, Scope* sc)
+ {
+ //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
+
+ // Needed to display any deprecations that were gagged
+ auto tcopy = this.syntaxCopy();
+
+ const errors = global.startGagging();
+ Type t = typeSemantic(this, loc, sc);
+ if (global.endGagging(errors) || t.ty == Terror) // if any errors happened
+ {
+ t = null;
+ }
+ else
+ {
+ // If `typeSemantic` succeeded, there may have been deprecations that
+ // were gagged due the the `startGagging` above. Run again to display
+ // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107
+ if (global.gaggedWarnings > 0)
+ typeSemantic(tcopy, loc, sc);
+ }
+ //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
+ return t;
+ }
+
+ /*************************************
+ * This version does a merge even if the deco is already computed.
+ * Necessary for types that have a deco, but are not merged.
+ */
+ final Type merge2()
+ {
+ //printf("merge2(%s)\n", toChars());
+ Type t = this;
+ assert(t);
+ if (!t.deco)
+ return t.merge();
+
+ auto sv = stringtable.lookup(t.deco, strlen(t.deco));
+ if (sv && sv.value)
+ {
+ t = sv.value;
+ assert(t.deco);
+ }
+ else
+ assert(0);
+ return t;
+ }
+
+ /*********************************
+ * Store this type's modifier name into buf.
+ */
+ final void modToBuffer(OutBuffer* buf) nothrow const
+ {
+ if (mod)
+ {
+ buf.writeByte(' ');
+ MODtoBuffer(buf, mod);
+ }
+ }
+
+ /*********************************
+ * Return this type's modifier name.
+ */
+ final char* modToChars() nothrow const
+ {
+ OutBuffer buf;
+ buf.reserve(16);
+ modToBuffer(&buf);
+ return buf.extractChars();
+ }
+
+ bool isintegral()
+ {
+ return false;
+ }
+
+ // real, imaginary, or complex
+ bool isfloating()
+ {
+ return false;
+ }
+
+ bool isreal()
+ {
+ return false;
+ }
+
+ bool isimaginary()
+ {
+ return false;
+ }
+
+ bool iscomplex()
+ {
+ return false;
+ }
+
+ bool isscalar()
+ {
+ return false;
+ }
+
+ bool isunsigned()
+ {
+ return false;
+ }
+
+ bool isscope()
+ {
+ return false;
+ }
+
+ bool isString()
+ {
+ return false;
+ }
+
+ /**************************
+ * When T is mutable,
+ * Given:
+ * T a, b;
+ * Can we bitwise assign:
+ * a = b;
+ * ?
+ */
+ bool isAssignable()
+ {
+ return true;
+ }
+
+ /**************************
+ * Returns true if T can be converted to boolean value.
+ */
+ bool isBoolean()
+ {
+ return isscalar();
+ }
+
+ /*********************************
+ * Check type to see if it is based on a deprecated symbol.
+ */
+ void checkDeprecated(const ref Loc loc, Scope* sc)
+ {
+ if (Dsymbol s = toDsymbol(sc))
+ {
+ s.checkDeprecated(loc, sc);
+ }
+ }
+
+ final bool isConst() const nothrow pure @nogc @safe
+ {
+ return (mod & MODFlags.const_) != 0;
+ }
+
+ final bool isImmutable() const nothrow pure @nogc @safe
+ {
+ return (mod & MODFlags.immutable_) != 0;
+ }
+
+ final bool isMutable() const nothrow pure @nogc @safe
+ {
+ return (mod & (MODFlags.const_ | MODFlags.immutable_ | MODFlags.wild)) == 0;
+ }
+
+ final bool isShared() const nothrow pure @nogc @safe
+ {
+ return (mod & MODFlags.shared_) != 0;
+ }
+
+ final bool isSharedConst() const nothrow pure @nogc @safe
+ {
+ return (mod & (MODFlags.shared_ | MODFlags.const_)) == (MODFlags.shared_ | MODFlags.const_);
+ }
+
+ final bool isWild() const nothrow pure @nogc @safe
+ {
+ return (mod & MODFlags.wild) != 0;
+ }
+
+ final bool isWildConst() const nothrow pure @nogc @safe
+ {
+ return (mod & MODFlags.wildconst) == MODFlags.wildconst;
+ }
+
+ final bool isSharedWild() const nothrow pure @nogc @safe
+ {
+ return (mod & (MODFlags.shared_ | MODFlags.wild)) == (MODFlags.shared_ | MODFlags.wild);
+ }
+
+ final bool isNaked() const nothrow pure @nogc @safe
+ {
+ return mod == 0;
+ }
+
+ /********************************
+ * Return a copy of this type with all attributes null-initialized.
+ * Useful for creating a type with different modifiers.
+ */
+ final Type nullAttributes() nothrow const
+ {
+ uint sz = sizeTy[ty];
+ Type t = cast(Type)mem.xmalloc(sz);
+ memcpy(cast(void*)t, cast(void*)this, sz);
+ // t.mod = NULL; // leave mod unchanged
+ t.deco = null;
+ t.arrayof = null;
+ t.pto = null;
+ t.rto = null;
+ t.vtinfo = null;
+ t.ctype = null;
+ t.mcache = null;
+ if (t.ty == Tstruct)
+ (cast(TypeStruct)t).att = AliasThisRec.fwdref;
+ if (t.ty == Tclass)
+ (cast(TypeClass)t).att = AliasThisRec.fwdref;
+ return t;
+ }
+
+ /********************************
+ * Convert to 'const'.
+ */
+ final Type constOf()
+ {
+ //printf("Type::constOf() %p %s\n", this, toChars());
+ if (mod == MODFlags.const_)
+ return this;
+ if (mcache && mcache.cto)
+ {
+ assert(mcache.cto.mod == MODFlags.const_);
+ return mcache.cto;
+ }
+ Type t = makeConst();
+ t = t.merge();
+ t.fixTo(this);
+ //printf("-Type::constOf() %p %s\n", t, t.toChars());
+ return t;
+ }
+
+ /********************************
+ * Convert to 'immutable'.
+ */
+ final Type immutableOf()
+ {
+ //printf("Type::immutableOf() %p %s\n", this, toChars());
+ if (isImmutable())
+ return this;
+ if (mcache && mcache.ito)
+ {
+ assert(mcache.ito.isImmutable());
+ return mcache.ito;
+ }
+ Type t = makeImmutable();
+ t = t.merge();
+ t.fixTo(this);
+ //printf("\t%p\n", t);
+ return t;
+ }
+
+ /********************************
+ * Make type mutable.
+ */
+ final Type mutableOf()
+ {
+ //printf("Type::mutableOf() %p, %s\n", this, toChars());
+ Type t = this;
+ if (isImmutable())
+ {
+ getMcache();
+ t = mcache.ito; // immutable => naked
+ assert(!t || (t.isMutable() && !t.isShared()));
+ }
+ else if (isConst())
+ {
+ getMcache();
+ if (isShared())
+ {
+ if (isWild())
+ t = mcache.swcto; // shared wild const -> shared
+ else
+ t = mcache.sto; // shared const => shared
+ }
+ else
+ {
+ if (isWild())
+ t = mcache.wcto; // wild const -> naked
+ else
+ t = mcache.cto; // const => naked
+ }
+ assert(!t || t.isMutable());
+ }
+ else if (isWild())
+ {
+ getMcache();
+ if (isShared())
+ t = mcache.sto; // shared wild => shared
+ else
+ t = mcache.wto; // wild => naked
+ assert(!t || t.isMutable());
+ }
+ if (!t)
+ {
+ t = makeMutable();
+ t = t.merge();
+ t.fixTo(this);
+ }
+ else
+ t = t.merge();
+ assert(t.isMutable());
+ return t;
+ }
+
+ final Type sharedOf()
+ {
+ //printf("Type::sharedOf() %p, %s\n", this, toChars());
+ if (mod == MODFlags.shared_)
+ return this;
+ if (mcache && mcache.sto)
+ {
+ assert(mcache.sto.mod == MODFlags.shared_);
+ return mcache.sto;
+ }
+ Type t = makeShared();
+ t = t.merge();
+ t.fixTo(this);
+ //printf("\t%p\n", t);
+ return t;
+ }
+
+ final Type sharedConstOf()
+ {
+ //printf("Type::sharedConstOf() %p, %s\n", this, toChars());
+ if (mod == (MODFlags.shared_ | MODFlags.const_))
+ return this;
+ if (mcache && mcache.scto)
+ {
+ assert(mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_));
+ return mcache.scto;
+ }
+ Type t = makeSharedConst();
+ t = t.merge();
+ t.fixTo(this);
+ //printf("\t%p\n", t);
+ return t;
+ }
+
+ /********************************
+ * Make type unshared.
+ * 0 => 0
+ * const => const
+ * immutable => immutable
+ * shared => 0
+ * shared const => const
+ * wild => wild
+ * wild const => wild const
+ * shared wild => wild
+ * shared wild const => wild const
+ */
+ final Type unSharedOf()
+ {
+ //printf("Type::unSharedOf() %p, %s\n", this, toChars());
+ Type t = this;
+
+ if (isShared())
+ {
+ getMcache();
+ if (isWild())
+ {
+ if (isConst())
+ t = mcache.wcto; // shared wild const => wild const
+ else
+ t = mcache.wto; // shared wild => wild
+ }
+ else
+ {
+ if (isConst())
+ t = mcache.cto; // shared const => const
+ else
+ t = mcache.sto; // shared => naked
+ }
+ assert(!t || !t.isShared());
+ }
+
+ if (!t)
+ {
+ t = this.nullAttributes();
+ t.mod = mod & ~MODFlags.shared_;
+ t.ctype = ctype;
+ t = t.merge();
+ t.fixTo(this);
+ }
+ else
+ t = t.merge();
+ assert(!t.isShared());
+ return t;
+ }
+
+ /********************************
+ * Convert to 'wild'.
+ */
+ final Type wildOf()
+ {
+ //printf("Type::wildOf() %p %s\n", this, toChars());
+ if (mod == MODFlags.wild)
+ return this;
+ if (mcache && mcache.wto)
+ {
+ assert(mcache.wto.mod == MODFlags.wild);
+ return mcache.wto;
+ }
+ Type t = makeWild();
+ t = t.merge();
+ t.fixTo(this);
+ //printf("\t%p %s\n", t, t.toChars());
+ return t;
+ }
+
+ final Type wildConstOf()
+ {
+ //printf("Type::wildConstOf() %p %s\n", this, toChars());
+ if (mod == MODFlags.wildconst)
+ return this;
+ if (mcache && mcache.wcto)
+ {
+ assert(mcache.wcto.mod == MODFlags.wildconst);
+ return mcache.wcto;
+ }
+ Type t = makeWildConst();
+ t = t.merge();
+ t.fixTo(this);
+ //printf("\t%p %s\n", t, t.toChars());
+ return t;
+ }
+
+ final Type sharedWildOf()
+ {
+ //printf("Type::sharedWildOf() %p, %s\n", this, toChars());
+ if (mod == (MODFlags.shared_ | MODFlags.wild))
+ return this;
+ if (mcache && mcache.swto)
+ {
+ assert(mcache.swto.mod == (MODFlags.shared_ | MODFlags.wild));
+ return mcache.swto;
+ }
+ Type t = makeSharedWild();
+ t = t.merge();
+ t.fixTo(this);
+ //printf("\t%p %s\n", t, t.toChars());
+ return t;
+ }
+
+ final Type sharedWildConstOf()
+ {
+ //printf("Type::sharedWildConstOf() %p, %s\n", this, toChars());
+ if (mod == (MODFlags.shared_ | MODFlags.wildconst))
+ return this;
+ if (mcache && mcache.swcto)
+ {
+ assert(mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
+ return mcache.swcto;
+ }
+ Type t = makeSharedWildConst();
+ t = t.merge();
+ t.fixTo(this);
+ //printf("\t%p %s\n", t, t.toChars());
+ return t;
+ }
+
+ /**********************************
+ * For our new type 'this', which is type-constructed from t,
+ * fill in the cto, ito, sto, scto, wto shortcuts.
+ */
+ final void fixTo(Type t)
+ {
+ // If fixing this: immutable(T*) by t: immutable(T)*,
+ // cache t to this.xto won't break transitivity.
+ Type mto = null;
+ Type tn = nextOf();
+ if (!tn || ty != Tsarray && tn.mod == t.nextOf().mod)
+ {
+ switch (t.mod)
+ {
+ case 0:
+ mto = t;
+ break;
+
+ case MODFlags.const_:
+ getMcache();
+ mcache.cto = t;
+ break;
+
+ case MODFlags.wild:
+ getMcache();
+ mcache.wto = t;
+ break;
+
+ case MODFlags.wildconst:
+ getMcache();
+ mcache.wcto = t;
+ break;
+
+ case MODFlags.shared_:
+ getMcache();
+ mcache.sto = t;
+ break;
+
+ case MODFlags.shared_ | MODFlags.const_:
+ getMcache();
+ mcache.scto = t;
+ break;
+
+ case MODFlags.shared_ | MODFlags.wild:
+ getMcache();
+ mcache.swto = t;
+ break;
+
+ case MODFlags.shared_ | MODFlags.wildconst:
+ getMcache();
+ mcache.swcto = t;
+ break;
+
+ case MODFlags.immutable_:
+ getMcache();
+ mcache.ito = t;
+ break;
+
+ default:
+ break;
+ }
+ }
+ assert(mod != t.mod);
+
+ if (mod)
+ {
+ getMcache();
+ t.getMcache();
+ }
+ switch (mod)
+ {
+ case 0:
+ break;
+
+ case MODFlags.const_:
+ mcache.cto = mto;
+ t.mcache.cto = this;
+ break;
+
+ case MODFlags.wild:
+ mcache.wto = mto;
+ t.mcache.wto = this;
+ break;
+
+ case MODFlags.wildconst:
+ mcache.wcto = mto;
+ t.mcache.wcto = this;
+ break;
+
+ case MODFlags.shared_:
+ mcache.sto = mto;
+ t.mcache.sto = this;
+ break;
+
+ case MODFlags.shared_ | MODFlags.const_:
+ mcache.scto = mto;
+ t.mcache.scto = this;
+ break;
+
+ case MODFlags.shared_ | MODFlags.wild:
+ mcache.swto = mto;
+ t.mcache.swto = this;
+ break;
+
+ case MODFlags.shared_ | MODFlags.wildconst:
+ mcache.swcto = mto;
+ t.mcache.swcto = this;
+ break;
+
+ case MODFlags.immutable_:
+ t.mcache.ito = this;
+ if (t.mcache.cto)
+ t.mcache.cto.getMcache().ito = this;
+ if (t.mcache.sto)
+ t.mcache.sto.getMcache().ito = this;
+ if (t.mcache.scto)
+ t.mcache.scto.getMcache().ito = this;
+ if (t.mcache.wto)
+ t.mcache.wto.getMcache().ito = this;
+ if (t.mcache.wcto)
+ t.mcache.wcto.getMcache().ito = this;
+ if (t.mcache.swto)
+ t.mcache.swto.getMcache().ito = this;
+ if (t.mcache.swcto)
+ t.mcache.swcto.getMcache().ito = this;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ check();
+ t.check();
+ //printf("fixTo: %s, %s\n", toChars(), t.toChars());
+ }
+
+ /***************************
+ * Look for bugs in constructing types.
+ */
+ final void check()
+ {
+ if (mcache)
+ with (mcache)
+ switch (mod)
+ {
+ case 0:
+ if (cto)
+ assert(cto.mod == MODFlags.const_);
+ if (ito)
+ assert(ito.mod == MODFlags.immutable_);
+ if (sto)
+ assert(sto.mod == MODFlags.shared_);
+ if (scto)
+ assert(scto.mod == (MODFlags.shared_ | MODFlags.const_));
+ if (wto)
+ assert(wto.mod == MODFlags.wild);
+ if (wcto)
+ assert(wcto.mod == MODFlags.wildconst);
+ if (swto)
+ assert(swto.mod == (MODFlags.shared_ | MODFlags.wild));
+ if (swcto)
+ assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
+ break;
+
+ case MODFlags.const_:
+ if (cto)
+ assert(cto.mod == 0);
+ if (ito)
+ assert(ito.mod == MODFlags.immutable_);
+ if (sto)
+ assert(sto.mod == MODFlags.shared_);
+ if (scto)
+ assert(scto.mod == (MODFlags.shared_ | MODFlags.const_));
+ if (wto)
+ assert(wto.mod == MODFlags.wild);
+ if (wcto)
+ assert(wcto.mod == MODFlags.wildconst);
+ if (swto)
+ assert(swto.mod == (MODFlags.shared_ | MODFlags.wild));
+ if (swcto)
+ assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
+ break;
+
+ case MODFlags.wild:
+ if (cto)
+ assert(cto.mod == MODFlags.const_);
+ if (ito)
+ assert(ito.mod == MODFlags.immutable_);
+ if (sto)
+ assert(sto.mod == MODFlags.shared_);
+ if (scto)
+ assert(scto.mod == (MODFlags.shared_ | MODFlags.const_));
+ if (wto)
+ assert(wto.mod == 0);
+ if (wcto)
+ assert(wcto.mod == MODFlags.wildconst);
+ if (swto)
+ assert(swto.mod == (MODFlags.shared_ | MODFlags.wild));
+ if (swcto)
+ assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
+ break;
+
+ case MODFlags.wildconst:
+ assert(!cto || cto.mod == MODFlags.const_);
+ assert(!ito || ito.mod == MODFlags.immutable_);
+ assert(!sto || sto.mod == MODFlags.shared_);
+ assert(!scto || scto.mod == (MODFlags.shared_ | MODFlags.const_));
+ assert(!wto || wto.mod == MODFlags.wild);
+ assert(!wcto || wcto.mod == 0);
+ assert(!swto || swto.mod == (MODFlags.shared_ | MODFlags.wild));
+ assert(!swcto || swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
+ break;
+
+ case MODFlags.shared_:
+ if (cto)
+ assert(cto.mod == MODFlags.const_);
+ if (ito)
+ assert(ito.mod == MODFlags.immutable_);
+ if (sto)
+ assert(sto.mod == 0);
+ if (scto)
+ assert(scto.mod == (MODFlags.shared_ | MODFlags.const_));
+ if (wto)
+ assert(wto.mod == MODFlags.wild);
+ if (wcto)
+ assert(wcto.mod == MODFlags.wildconst);
+ if (swto)
+ assert(swto.mod == (MODFlags.shared_ | MODFlags.wild));
+ if (swcto)
+ assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
+ break;
+
+ case MODFlags.shared_ | MODFlags.const_:
+ if (cto)
+ assert(cto.mod == MODFlags.const_);
+ if (ito)
+ assert(ito.mod == MODFlags.immutable_);
+ if (sto)
+ assert(sto.mod == MODFlags.shared_);
+ if (scto)
+ assert(scto.mod == 0);
+ if (wto)
+ assert(wto.mod == MODFlags.wild);
+ if (wcto)
+ assert(wcto.mod == MODFlags.wildconst);
+ if (swto)
+ assert(swto.mod == (MODFlags.shared_ | MODFlags.wild));
+ if (swcto)
+ assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
+ break;
+
+ case MODFlags.shared_ | MODFlags.wild:
+ if (cto)
+ assert(cto.mod == MODFlags.const_);
+ if (ito)
+ assert(ito.mod == MODFlags.immutable_);
+ if (sto)
+ assert(sto.mod == MODFlags.shared_);
+ if (scto)
+ assert(scto.mod == (MODFlags.shared_ | MODFlags.const_));
+ if (wto)
+ assert(wto.mod == MODFlags.wild);
+ if (wcto)
+ assert(wcto.mod == MODFlags.wildconst);
+ if (swto)
+ assert(swto.mod == 0);
+ if (swcto)
+ assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
+ break;
+
+ case MODFlags.shared_ | MODFlags.wildconst:
+ assert(!cto || cto.mod == MODFlags.const_);
+ assert(!ito || ito.mod == MODFlags.immutable_);
+ assert(!sto || sto.mod == MODFlags.shared_);
+ assert(!scto || scto.mod == (MODFlags.shared_ | MODFlags.const_));
+ assert(!wto || wto.mod == MODFlags.wild);
+ assert(!wcto || wcto.mod == MODFlags.wildconst);
+ assert(!swto || swto.mod == (MODFlags.shared_ | MODFlags.wild));
+ assert(!swcto || swcto.mod == 0);
+ break;
+
+ case MODFlags.immutable_:
+ if (cto)
+ assert(cto.mod == MODFlags.const_);
+ if (ito)
+ assert(ito.mod == 0);
+ if (sto)
+ assert(sto.mod == MODFlags.shared_);
+ if (scto)
+ assert(scto.mod == (MODFlags.shared_ | MODFlags.const_));
+ if (wto)
+ assert(wto.mod == MODFlags.wild);
+ if (wcto)
+ assert(wcto.mod == MODFlags.wildconst);
+ if (swto)
+ assert(swto.mod == (MODFlags.shared_ | MODFlags.wild));
+ if (swcto)
+ assert(swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
+ break;
+
+ default:
+ assert(0);
+ }
+
+ Type tn = nextOf();
+ if (tn && ty != Tfunction && tn.ty != Tfunction && ty != Tenum)
+ {
+ // Verify transitivity
+ switch (mod)
+ {
+ case 0:
+ case MODFlags.const_:
+ case MODFlags.wild:
+ case MODFlags.wildconst:
+ case MODFlags.shared_:
+ case MODFlags.shared_ | MODFlags.const_:
+ case MODFlags.shared_ | MODFlags.wild:
+ case MODFlags.shared_ | MODFlags.wildconst:
+ case MODFlags.immutable_:
+ assert(tn.mod == MODFlags.immutable_ || (tn.mod & mod) == mod);
+ break;
+
+ default:
+ assert(0);
+ }
+ tn.check();
+ }
+ }
+
+ /*************************************
+ * Apply STCxxxx bits to existing type.
+ * Use *before* semantic analysis is run.
+ */
+ final Type addSTC(StorageClass stc)
+ {
+ Type t = this;
+ if (t.isImmutable())
+ {
+ }
+ else if (stc & STC.immutable_)
+ {
+ t = t.makeImmutable();
+ }
+ else
+ {
+ if ((stc & STC.shared_) && !t.isShared())
+ {
+ if (t.isWild())
+ {
+ if (t.isConst())
+ t = t.makeSharedWildConst();
+ else
+ t = t.makeSharedWild();
+ }
+ else
+ {
+ if (t.isConst())
+ t = t.makeSharedConst();
+ else
+ t = t.makeShared();
+ }
+ }
+ if ((stc & STC.const_) && !t.isConst())
+ {
+ if (t.isShared())
+ {
+ if (t.isWild())
+ t = t.makeSharedWildConst();
+ else
+ t = t.makeSharedConst();
+ }
+ else
+ {
+ if (t.isWild())
+ t = t.makeWildConst();
+ else
+ t = t.makeConst();
+ }
+ }
+ if ((stc & STC.wild) && !t.isWild())
+ {
+ if (t.isShared())
+ {
+ if (t.isConst())
+ t = t.makeSharedWildConst();
+ else
+ t = t.makeSharedWild();
+ }
+ else
+ {
+ if (t.isConst())
+ t = t.makeWildConst();
+ else
+ t = t.makeWild();
+ }
+ }
+ }
+ return t;
+ }
+
+ /************************************
+ * Apply MODxxxx bits to existing type.
+ */
+ final Type castMod(MOD mod)
+ {
+ Type t;
+ switch (mod)
+ {
+ case 0:
+ t = unSharedOf().mutableOf();
+ break;
+
+ case MODFlags.const_:
+ t = unSharedOf().constOf();
+ break;
+
+ case MODFlags.wild:
+ t = unSharedOf().wildOf();
+ break;
+
+ case MODFlags.wildconst:
+ t = unSharedOf().wildConstOf();
+ break;
+
+ case MODFlags.shared_:
+ t = mutableOf().sharedOf();
+ break;
+
+ case MODFlags.shared_ | MODFlags.const_:
+ t = sharedConstOf();
+ break;
+
+ case MODFlags.shared_ | MODFlags.wild:
+ t = sharedWildOf();
+ break;
+
+ case MODFlags.shared_ | MODFlags.wildconst:
+ t = sharedWildConstOf();
+ break;
+
+ case MODFlags.immutable_:
+ t = immutableOf();
+ break;
+
+ default:
+ assert(0);
+ }
+ return t;
+ }
+
+ /************************************
+ * Add MODxxxx bits to existing type.
+ * We're adding, not replacing, so adding const to
+ * a shared type => "shared const"
+ */
+ final Type addMod(MOD mod)
+ {
+ /* Add anything to immutable, and it remains immutable
+ */
+ Type t = this;
+ if (!t.isImmutable())
+ {
+ //printf("addMod(%x) %s\n", mod, toChars());
+ switch (mod)
+ {
+ case 0:
+ break;
+
+ case MODFlags.const_:
+ if (isShared())
+ {
+ if (isWild())
+ t = sharedWildConstOf();
+ else
+ t = sharedConstOf();
+ }
+ else
+ {
+ if (isWild())
+ t = wildConstOf();
+ else
+ t = constOf();
+ }
+ break;
+
+ case MODFlags.wild:
+ if (isShared())
+ {
+ if (isConst())
+ t = sharedWildConstOf();
+ else
+ t = sharedWildOf();
+ }
+ else
+ {
+ if (isConst())
+ t = wildConstOf();
+ else
+ t = wildOf();
+ }
+ break;
+
+ case MODFlags.wildconst:
+ if (isShared())
+ t = sharedWildConstOf();
+ else
+ t = wildConstOf();
+ break;
+
+ case MODFlags.shared_:
+ if (isWild())
+ {
+ if (isConst())
+ t = sharedWildConstOf();
+ else
+ t = sharedWildOf();
+ }
+ else
+ {
+ if (isConst())
+ t = sharedConstOf();
+ else
+ t = sharedOf();
+ }
+ break;
+
+ case MODFlags.shared_ | MODFlags.const_:
+ if (isWild())
+ t = sharedWildConstOf();
+ else
+ t = sharedConstOf();
+ break;
+
+ case MODFlags.shared_ | MODFlags.wild:
+ if (isConst())
+ t = sharedWildConstOf();
+ else
+ t = sharedWildOf();
+ break;
+
+ case MODFlags.shared_ | MODFlags.wildconst:
+ t = sharedWildConstOf();
+ break;
+
+ case MODFlags.immutable_:
+ t = immutableOf();
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ return t;
+ }
+
+ /************************************
+ * Add storage class modifiers to type.
+ */
+ Type addStorageClass(StorageClass stc)
+ {
+ /* Just translate to MOD bits and let addMod() do the work
+ */
+ MOD mod = 0;
+ if (stc & STC.immutable_)
+ mod = MODFlags.immutable_;
+ else
+ {
+ if (stc & (STC.const_ | STC.in_))
+ mod |= MODFlags.const_;
+ if (stc & STC.wild)
+ mod |= MODFlags.wild;
+ if (stc & STC.shared_)
+ mod |= MODFlags.shared_;
+ }
+ return addMod(mod);
+ }
+
+ final Type pointerTo()
+ {
+ if (ty == Terror)
+ return this;
+ if (!pto)
+ {
+ Type t = new TypePointer(this);
+ if (ty == Tfunction)
+ {
+ t.deco = t.merge().deco;
+ pto = t;
+ }
+ else
+ pto = t.merge();
+ }
+ return pto;
+ }
+
+ final Type referenceTo()
+ {
+ if (ty == Terror)
+ return this;
+ if (!rto)
+ {
+ Type t = new TypeReference(this);
+ rto = t.merge();
+ }
+ return rto;
+ }
+
+ final Type arrayOf()
+ {
+ if (ty == Terror)
+ return this;
+ if (!arrayof)
+ {
+ Type t = new TypeDArray(this);
+ arrayof = t.merge();
+ }
+ return arrayof;
+ }
+
+ // Make corresponding static array type without semantic
+ final Type sarrayOf(dinteger_t dim)
+ {
+ assert(deco);
+ Type t = new TypeSArray(this, new IntegerExp(Loc.initial, dim, Type.tsize_t));
+ // according to TypeSArray::semantic()
+ t = t.addMod(mod);
+ t = t.merge();
+ return t;
+ }
+
+ final bool hasDeprecatedAliasThis()
+ {
+ auto ad = isAggregate(this);
+ return ad && ad.aliasthis && (ad.aliasthis.isDeprecated || ad.aliasthis.sym.isDeprecated);
+ }
+
+ final Type aliasthisOf()
+ {
+ auto ad = isAggregate(this);
+ if (!ad || !ad.aliasthis)
+ return null;
+
+ auto s = ad.aliasthis.sym;
+ if (s.isAliasDeclaration())
+ s = s.toAlias();
+
+ if (s.isTupleDeclaration())
+ return null;
+
+ if (auto vd = s.isVarDeclaration())
+ {
+ auto t = vd.type;
+ if (vd.needThis())
+ t = t.addMod(this.mod);
+ return t;
+ }
+ if (auto fd = s.isFuncDeclaration())
+ {
+ fd = resolveFuncCall(Loc.initial, null, fd, null, this, null, FuncResolveFlag.quiet);
+ if (!fd || fd.errors || !fd.functionSemantic())
+ return Type.terror;
+
+ auto t = fd.type.nextOf();
+ if (!t) // issue 14185
+ return Type.terror;
+ t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod);
+ return t;
+ }
+ if (auto d = s.isDeclaration())
+ {
+ assert(d.type);
+ return d.type;
+ }
+ if (auto ed = s.isEnumDeclaration())
+ {
+ return ed.type;
+ }
+ if (auto td = s.isTemplateDeclaration())
+ {
+ assert(td._scope);
+ auto fd = resolveFuncCall(Loc.initial, null, td, null, this, null, FuncResolveFlag.quiet);
+ if (!fd || fd.errors || !fd.functionSemantic())
+ return Type.terror;
+
+ auto t = fd.type.nextOf();
+ if (!t)
+ return Type.terror;
+ t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod);
+ return t;
+ }
+
+ //printf("%s\n", s.kind());
+ return null;
+ }
+
+ extern (D) final bool checkAliasThisRec()
+ {
+ Type tb = toBasetype();
+ AliasThisRec* pflag;
+ if (tb.ty == Tstruct)
+ pflag = &(cast(TypeStruct)tb).att;
+ else if (tb.ty == Tclass)
+ pflag = &(cast(TypeClass)tb).att;
+ else
+ return false;
+
+ AliasThisRec flag = cast(AliasThisRec)(*pflag & AliasThisRec.typeMask);
+ if (flag == AliasThisRec.fwdref)
+ {
+ Type att = aliasthisOf();
+ flag = att && att.implicitConvTo(this) ? AliasThisRec.yes : AliasThisRec.no;
+ }
+ *pflag = cast(AliasThisRec)(flag | (*pflag & ~AliasThisRec.typeMask));
+ return flag == AliasThisRec.yes;
+ }
+
+ Type makeConst()
+ {
+ //printf("Type::makeConst() %p, %s\n", this, toChars());
+ if (mcache && mcache.cto)
+ return mcache.cto;
+ Type t = this.nullAttributes();
+ t.mod = MODFlags.const_;
+ //printf("-Type::makeConst() %p, %s\n", t, toChars());
+ return t;
+ }
+
+ Type makeImmutable()
+ {
+ if (mcache && mcache.ito)
+ return mcache.ito;
+ Type t = this.nullAttributes();
+ t.mod = MODFlags.immutable_;
+ return t;
+ }
+
+ Type makeShared()
+ {
+ if (mcache && mcache.sto)
+ return mcache.sto;
+ Type t = this.nullAttributes();
+ t.mod = MODFlags.shared_;
+ return t;
+ }
+
+ Type makeSharedConst()
+ {
+ if (mcache && mcache.scto)
+ return mcache.scto;
+ Type t = this.nullAttributes();
+ t.mod = MODFlags.shared_ | MODFlags.const_;
+ return t;
+ }
+
+ Type makeWild()
+ {
+ if (mcache && mcache.wto)
+ return mcache.wto;
+ Type t = this.nullAttributes();
+ t.mod = MODFlags.wild;
+ return t;
+ }
+
+ Type makeWildConst()
+ {
+ if (mcache && mcache.wcto)
+ return mcache.wcto;
+ Type t = this.nullAttributes();
+ t.mod = MODFlags.wildconst;
+ return t;
+ }
+
+ Type makeSharedWild()
+ {
+ if (mcache && mcache.swto)
+ return mcache.swto;
+ Type t = this.nullAttributes();
+ t.mod = MODFlags.shared_ | MODFlags.wild;
+ return t;
+ }
+
+ Type makeSharedWildConst()
+ {
+ if (mcache && mcache.swcto)
+ return mcache.swcto;
+ Type t = this.nullAttributes();
+ t.mod = MODFlags.shared_ | MODFlags.wildconst;
+ return t;
+ }
+
+ Type makeMutable()
+ {
+ Type t = this.nullAttributes();
+ t.mod = mod & MODFlags.shared_;
+ return t;
+ }
+
+ Dsymbol toDsymbol(Scope* sc)
+ {
+ return null;
+ }
+
+ /*******************************
+ * If this is a shell around another type,
+ * get that other type.
+ */
+ final Type toBasetype()
+ {
+ /* This function is used heavily.
+ * De-virtualize it so it can be easily inlined.
+ */
+ TypeEnum te;
+ return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this;
+ }
+
+ bool isBaseOf(Type t, int* poffset)
+ {
+ return 0; // assume not
+ }
+
+ /********************************
+ * Determine if 'this' can be implicitly converted
+ * to type 'to'.
+ * Returns:
+ * MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact
+ */
+ MATCH implicitConvTo(Type to)
+ {
+ //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
+ //printf("from: %s\n", toChars());
+ //printf("to : %s\n", to.toChars());
+ if (this.equals(to))
+ return MATCH.exact;
+ return MATCH.nomatch;
+ }
+
+ /*******************************
+ * Determine if converting 'this' to 'to' is an identity operation,
+ * a conversion to const operation, or the types aren't the same.
+ * Returns:
+ * MATCH.exact 'this' == 'to'
+ * MATCH.constant 'to' is const
+ * MATCH.nomatch conversion to mutable or invariant
+ */
+ MATCH constConv(Type to)
+ {
+ //printf("Type::constConv(this = %s, to = %s)\n", toChars(), to.toChars());
+ if (equals(to))
+ return MATCH.exact;
+ if (ty == to.ty && MODimplicitConv(mod, to.mod))
+ return MATCH.constant;
+ return MATCH.nomatch;
+ }
+
+ /***************************************
+ * Compute MOD bits matching `this` argument type to wild parameter type.
+ * Params:
+ * t = corresponding parameter type
+ * isRef = parameter is `ref` or `out`
+ * Returns:
+ * MOD bits
+ */
+ MOD deduceWild(Type t, bool isRef)
+ {
+ //printf("Type::deduceWild this = '%s', tprm = '%s'\n", toChars(), tprm.toChars());
+ if (t.isWild())
+ {
+ if (isImmutable())
+ return MODFlags.immutable_;
+ else if (isWildConst())
+ {
+ if (t.isWildConst())
+ return MODFlags.wild;
+ else
+ return MODFlags.wildconst;
+ }
+ else if (isWild())
+ return MODFlags.wild;
+ else if (isConst())
+ return MODFlags.const_;
+ else if (isMutable())
+ return MODFlags.mutable;
+ else
+ assert(0);
+ }
+ return 0;
+ }
+
+ Type substWildTo(uint mod)
+ {
+ //printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod);
+ Type t;
+
+ if (Type tn = nextOf())
+ {
+ // substitution has no effect on function pointer type.
+ if (ty == Tpointer && tn.ty == Tfunction)
+ {
+ t = this;
+ goto L1;
+ }
+
+ t = tn.substWildTo(mod);
+ if (t == tn)
+ t = this;
+ else
+ {
+ if (ty == Tpointer)
+ t = t.pointerTo();
+ else if (ty == Tarray)
+ t = t.arrayOf();
+ else if (ty == Tsarray)
+ t = new TypeSArray(t, (cast(TypeSArray)this).dim.syntaxCopy());
+ else if (ty == Taarray)
+ {
+ t = new TypeAArray(t, (cast(TypeAArray)this).index.syntaxCopy());
+ }
+ else if (ty == Tdelegate)
+ {
+ t = new TypeDelegate(t.isTypeFunction());
+ }
+ else
+ assert(0);
+
+ t = t.merge();
+ }
+ }
+ else
+ t = this;
+
+ L1:
+ if (isWild())
+ {
+ if (mod == MODFlags.immutable_)
+ {
+ t = t.immutableOf();
+ }
+ else if (mod == MODFlags.wildconst)
+ {
+ t = t.wildConstOf();
+ }
+ else if (mod == MODFlags.wild)
+ {
+ if (isWildConst())
+ t = t.wildConstOf();
+ else
+ t = t.wildOf();
+ }
+ else if (mod == MODFlags.const_)
+ {
+ t = t.constOf();
+ }
+ else
+ {
+ if (isWildConst())
+ t = t.constOf();
+ else
+ t = t.mutableOf();
+ }
+ }
+ if (isConst())
+ t = t.addMod(MODFlags.const_);
+ if (isShared())
+ t = t.addMod(MODFlags.shared_);
+
+ //printf("-Type::substWildTo t = %s\n", t.toChars());
+ return t;
+ }
+
+ final Type unqualify(uint m)
+ {
+ Type t = mutableOf().unSharedOf();
+
+ Type tn = ty == Tenum ? null : nextOf();
+ if (tn && tn.ty != Tfunction)
+ {
+ Type utn = tn.unqualify(m);
+ if (utn != tn)
+ {
+ if (ty == Tpointer)
+ t = utn.pointerTo();
+ else if (ty == Tarray)
+ t = utn.arrayOf();
+ else if (ty == Tsarray)
+ t = new TypeSArray(utn, (cast(TypeSArray)this).dim);
+ else if (ty == Taarray)
+ {
+ t = new TypeAArray(utn, (cast(TypeAArray)this).index);
+ }
+ else
+ assert(0);
+
+ t = t.merge();
+ }
+ }
+ t = t.addMod(mod & ~m);
+ return t;
+ }
+
+ /**************************
+ * Return type with the top level of it being mutable.
+ */
+ inout(Type) toHeadMutable() inout
+ {
+ if (!mod)
+ return this;
+ Type unqualThis = cast(Type) this;
+ // `mutableOf` needs a mutable `this` only for caching
+ return cast(inout(Type)) unqualThis.mutableOf();
+ }
+
+ inout(ClassDeclaration) isClassHandle() inout
+ {
+ return null;
+ }
+
+ /************************************
+ * Return alignment to use for this type.
+ */
+ structalign_t alignment()
+ {
+ return STRUCTALIGN_DEFAULT;
+ }
+
+ /***************************************
+ * Use when we prefer the default initializer to be a literal,
+ * rather than a global immutable variable.
+ */
+ Expression defaultInitLiteral(const ref Loc loc)
+ {
+ static if (LOGDEFAULTINIT)
+ {
+ printf("Type::defaultInitLiteral() '%s'\n", toChars());
+ }
+ return defaultInit(this, loc);
+ }
+
+ // if initializer is 0
+ bool isZeroInit(const ref Loc loc)
+ {
+ return false; // assume not
+ }
+
+ final Identifier getTypeInfoIdent()
+ {
+ // _init_10TypeInfo_%s
+ OutBuffer buf;
+ buf.reserve(32);
+ mangleToBuffer(this, &buf);
+
+ const slice = buf[];
+
+ // Allocate buffer on stack, fail over to using malloc()
+ char[128] namebuf;
+ const namelen = 19 + size_t.sizeof * 3 + slice.length + 1;
+ auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen));
+
+ const length = sprintf(name, "_D%lluTypeInfo_%.*s6__initZ",
+ cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr);
+ //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name);
+ assert(0 < length && length < namelen); // don't overflow the buffer
+
+ auto id = Identifier.idPool(name, length);
+
+ if (name != namebuf.ptr)
+ free(name);
+ return id;
+ }
+
+ /***************************************
+ * Return !=0 if the type or any of its subtypes is wild.
+ */
+ int hasWild() const
+ {
+ return mod & MODFlags.wild;
+ }
+
+ /***************************************
+ * Return !=0 if type has pointers that need to
+ * be scanned by the GC during a collection cycle.
+ */
+ bool hasPointers()
+ {
+ //printf("Type::hasPointers() %s, %d\n", toChars(), ty);
+ return false;
+ }
+
+ /*************************************
+ * Detect if type has pointer fields that are initialized to void.
+ * Local stack variables with such void fields can remain uninitialized,
+ * leading to pointer bugs.
+ * Returns:
+ * true if so
+ */
+ bool hasVoidInitPointers()
+ {
+ return false;
+ }
+
+ /***************************************
+ * Returns: true if type has any invariants
+ */
+ bool hasInvariant()
+ {
+ //printf("Type::hasInvariant() %s, %d\n", toChars(), ty);
+ return false;
+ }
+
+ /*************************************
+ * If this is a type of something, return that something.
+ */
+ Type nextOf()
+ {
+ return null;
+ }
+
+ /*************************************
+ * If this is a type of static array, return its base element type.
+ */
+ final Type baseElemOf()
+ {
+ Type t = toBasetype();
+ TypeSArray tsa;
+ while ((tsa = t.isTypeSArray()) !is null)
+ t = tsa.next.toBasetype();
+ return t;
+ }
+
+ /*******************************************
+ * Compute number of elements for a (possibly multidimensional) static array,
+ * or 1 for other types.
+ * Params:
+ * loc = for error message
+ * Returns:
+ * number of elements, uint.max on overflow
+ */
+ final uint numberOfElems(const ref Loc loc)
+ {
+ //printf("Type::numberOfElems()\n");
+ uinteger_t n = 1;
+ Type tb = this;
+ while ((tb = tb.toBasetype()).ty == Tsarray)
+ {
+ bool overflow = false;
+ n = mulu(n, (cast(TypeSArray)tb).dim.toUInteger(), overflow);
+ if (overflow || n >= uint.max)
+ {
+ error(loc, "static array `%s` size overflowed to %llu", toChars(), cast(ulong)n);
+ return uint.max;
+ }
+ tb = (cast(TypeSArray)tb).next;
+ }
+ return cast(uint)n;
+ }
+
+ /****************************************
+ * Return the mask that an integral type will
+ * fit into.
+ */
+ final uinteger_t sizemask()
+ {
+ uinteger_t m;
+ switch (toBasetype().ty)
+ {
+ case Tbool:
+ m = 1;
+ break;
+ case Tchar:
+ case Tint8:
+ case Tuns8:
+ m = 0xFF;
+ break;
+ case Twchar:
+ case Tint16:
+ case Tuns16:
+ m = 0xFFFFU;
+ break;
+ case Tdchar:
+ case Tint32:
+ case Tuns32:
+ m = 0xFFFFFFFFU;
+ break;
+ case Tint64:
+ case Tuns64:
+ m = 0xFFFFFFFFFFFFFFFFUL;
+ break;
+ default:
+ assert(0);
+ }
+ return m;
+ }
+
+ /********************************
+ * true if when type goes out of scope, it needs a destructor applied.
+ * Only applies to value types, not ref types.
+ */
+ bool needsDestruction()
+ {
+ return false;
+ }
+
+ /********************************
+ * true if when type is copied, it needs a copy constructor or postblit
+ * applied. Only applies to value types, not ref types.
+ */
+ bool needsCopyOrPostblit()
+ {
+ return false;
+ }
+
+ /*********************************
+ *
+ */
+ bool needsNested()
+ {
+ return false;
+ }
+
+ /*************************************
+ * https://issues.dlang.org/show_bug.cgi?id=14488
+ * Check if the inner most base type is complex or imaginary.
+ * Should only give alerts when set to emit transitional messages.
+ * Params:
+ * loc = The source location.
+ * sc = scope of the type
+ */
+ extern (D) final bool checkComplexTransition(const ref Loc loc, Scope* sc)
+ {
+ if (sc.isDeprecated())
+ return false;
+ // Don't complain if we're inside a template constraint
+ // https://issues.dlang.org/show_bug.cgi?id=21831
+ if (sc.flags & SCOPE.constraint)
+ return false;
+
+ Type t = baseElemOf();
+ while (t.ty == Tpointer || t.ty == Tarray)
+ t = t.nextOf().baseElemOf();
+
+ // Basetype is an opaque enum, nothing to check.
+ if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype)
+ return false;
+
+ if (t.isimaginary() || t.iscomplex())
+ {
+ Type rt;
+ switch (t.ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ rt = Type.tfloat32;
+ break;
+
+ case Tcomplex64:
+ case Timaginary64:
+ rt = Type.tfloat64;
+ break;
+
+ case Tcomplex80:
+ case Timaginary80:
+ rt = Type.tfloat80;
+ break;
+
+ default:
+ assert(0);
+ }
+ if (t.iscomplex())
+ {
+ deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
+ toChars(), rt.toChars());
+ return true;
+ }
+ else
+ {
+ deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead",
+ toChars(), rt.toChars());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // For eliminating dynamic_cast
+ TypeBasic isTypeBasic()
+ {
+ return null;
+ }
+
+ final pure inout nothrow @nogc
+ {
+ /****************
+ * Is this type a pointer to a function?
+ * Returns:
+ * the function type if it is
+ */
+ inout(TypeFunction) isPtrToFunction()
+ {
+ return (ty == Tpointer && (cast(TypePointer)this).next.ty == Tfunction)
+ ? cast(typeof(return))(cast(TypePointer)this).next
+ : null;
+ }
+
+ /*****************
+ * Is this type a function, delegate, or pointer to a function?
+ * Returns:
+ * the function type if it is
+ */
+ inout(TypeFunction) isFunction_Delegate_PtrToFunction()
+ {
+ return ty == Tfunction ? cast(typeof(return))this :
+
+ ty == Tdelegate ? cast(typeof(return))(cast(TypePointer)this).next :
+
+ ty == Tpointer && (cast(TypePointer)this).next.ty == Tfunction ?
+ cast(typeof(return))(cast(TypePointer)this).next :
+
+ null;
+ }
+ }
+
+ final pure inout nothrow @nogc @safe
+ {
+ inout(TypeError) isTypeError() { return ty == Terror ? cast(typeof(return))this : null; }
+ inout(TypeVector) isTypeVector() { return ty == Tvector ? cast(typeof(return))this : null; }
+ inout(TypeSArray) isTypeSArray() { return ty == Tsarray ? cast(typeof(return))this : null; }
+ inout(TypeDArray) isTypeDArray() { return ty == Tarray ? cast(typeof(return))this : null; }
+ inout(TypeAArray) isTypeAArray() { return ty == Taarray ? cast(typeof(return))this : null; }
+ inout(TypePointer) isTypePointer() { return ty == Tpointer ? cast(typeof(return))this : null; }
+ inout(TypeReference) isTypeReference() { return ty == Treference ? cast(typeof(return))this : null; }
+ inout(TypeFunction) isTypeFunction() { return ty == Tfunction ? cast(typeof(return))this : null; }
+ inout(TypeDelegate) isTypeDelegate() { return ty == Tdelegate ? cast(typeof(return))this : null; }
+ inout(TypeIdentifier) isTypeIdentifier() { return ty == Tident ? cast(typeof(return))this : null; }
+ inout(TypeInstance) isTypeInstance() { return ty == Tinstance ? cast(typeof(return))this : null; }
+ inout(TypeTypeof) isTypeTypeof() { return ty == Ttypeof ? cast(typeof(return))this : null; }
+ inout(TypeReturn) isTypeReturn() { return ty == Treturn ? cast(typeof(return))this : null; }
+ inout(TypeStruct) isTypeStruct() { return ty == Tstruct ? cast(typeof(return))this : null; }
+ inout(TypeEnum) isTypeEnum() { return ty == Tenum ? cast(typeof(return))this : null; }
+ inout(TypeClass) isTypeClass() { return ty == Tclass ? cast(typeof(return))this : null; }
+ inout(TypeTuple) isTypeTuple() { return ty == Ttuple ? cast(typeof(return))this : null; }
+ inout(TypeSlice) isTypeSlice() { return ty == Tslice ? cast(typeof(return))this : null; }
+ inout(TypeNull) isTypeNull() { return ty == Tnull ? cast(typeof(return))this : null; }
+ inout(TypeMixin) isTypeMixin() { return ty == Tmixin ? cast(typeof(return))this : null; }
+ inout(TypeTraits) isTypeTraits() { return ty == Ttraits ? cast(typeof(return))this : null; }
+ inout(TypeNoreturn) isTypeNoreturn() { return ty == Tnoreturn ? cast(typeof(return))this : null; }
+ inout(TypeTag) isTypeTag() { return ty == Ttag ? cast(typeof(return))this : null; }
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ final TypeFunction toTypeFunction()
+ {
+ if (ty != Tfunction)
+ assert(0);
+ return cast(TypeFunction)this;
+ }
+
+ extern (D) static Types* arraySyntaxCopy(Types* types)
+ {
+ Types* a = null;
+ if (types)
+ {
+ a = new Types(types.length);
+ foreach (i, t; *types)
+ {
+ (*a)[i] = t ? t.syntaxCopy() : null;
+ }
+ }
+ return a;
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeError : Type
+{
+ extern (D) this()
+ {
+ super(Terror);
+ }
+
+ override const(char)* kind() const
+ {
+ return "error";
+ }
+
+ override TypeError syntaxCopy()
+ {
+ // No semantic analysis done, no need to copy
+ return this;
+ }
+
+ override d_uns64 size(const ref Loc loc)
+ {
+ return SIZE_INVALID;
+ }
+
+ override Expression defaultInitLiteral(const ref Loc loc)
+ {
+ return ErrorExp.get();
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) abstract class TypeNext : Type
+{
+ Type next;
+
+ final extern (D) this(TY ty, Type next)
+ {
+ super(ty);
+ this.next = next;
+ }
+
+ override final void checkDeprecated(const ref Loc loc, Scope* sc)
+ {
+ Type.checkDeprecated(loc, sc);
+ if (next) // next can be NULL if TypeFunction and auto return type
+ next.checkDeprecated(loc, sc);
+ }
+
+ override final int hasWild() const
+ {
+ if (ty == Tfunction)
+ return 0;
+ if (ty == Tdelegate)
+ return Type.hasWild();
+ return mod & MODFlags.wild || (next && next.hasWild());
+ }
+
+ /*******************************
+ * For TypeFunction, nextOf() can return NULL if the function return
+ * type is meant to be inferred, and semantic() hasn't yet ben run
+ * on the function. After semantic(), it must no longer be NULL.
+ */
+ override final Type nextOf()
+ {
+ return next;
+ }
+
+ override final Type makeConst()
+ {
+ //printf("TypeNext::makeConst() %p, %s\n", this, toChars());
+ if (mcache && mcache.cto)
+ {
+ assert(mcache.cto.mod == MODFlags.const_);
+ return mcache.cto;
+ }
+ TypeNext t = cast(TypeNext)Type.makeConst();
+ if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
+ {
+ if (next.isShared())
+ {
+ if (next.isWild())
+ t.next = next.sharedWildConstOf();
+ else
+ t.next = next.sharedConstOf();
+ }
+ else
+ {
+ if (next.isWild())
+ t.next = next.wildConstOf();
+ else
+ t.next = next.constOf();
+ }
+ }
+ //printf("TypeNext::makeConst() returns %p, %s\n", t, t.toChars());
+ return t;
+ }
+
+ override final Type makeImmutable()
+ {
+ //printf("TypeNext::makeImmutable() %s\n", toChars());
+ if (mcache && mcache.ito)
+ {
+ assert(mcache.ito.isImmutable());
+ return mcache.ito;
+ }
+ TypeNext t = cast(TypeNext)Type.makeImmutable();
+ if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
+ {
+ t.next = next.immutableOf();
+ }
+ return t;
+ }
+
+ override final Type makeShared()
+ {
+ //printf("TypeNext::makeShared() %s\n", toChars());
+ if (mcache && mcache.sto)
+ {
+ assert(mcache.sto.mod == MODFlags.shared_);
+ return mcache.sto;
+ }
+ TypeNext t = cast(TypeNext)Type.makeShared();
+ if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
+ {
+ if (next.isWild())
+ {
+ if (next.isConst())
+ t.next = next.sharedWildConstOf();
+ else
+ t.next = next.sharedWildOf();
+ }
+ else
+ {
+ if (next.isConst())
+ t.next = next.sharedConstOf();
+ else
+ t.next = next.sharedOf();
+ }
+ }
+ //printf("TypeNext::makeShared() returns %p, %s\n", t, t.toChars());
+ return t;
+ }
+
+ override final Type makeSharedConst()
+ {
+ //printf("TypeNext::makeSharedConst() %s\n", toChars());
+ if (mcache && mcache.scto)
+ {
+ assert(mcache.scto.mod == (MODFlags.shared_ | MODFlags.const_));
+ return mcache.scto;
+ }
+ TypeNext t = cast(TypeNext)Type.makeSharedConst();
+ if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
+ {
+ if (next.isWild())
+ t.next = next.sharedWildConstOf();
+ else
+ t.next = next.sharedConstOf();
+ }
+ //printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t.toChars());
+ return t;
+ }
+
+ override final Type makeWild()
+ {
+ //printf("TypeNext::makeWild() %s\n", toChars());
+ if (mcache && mcache.wto)
+ {
+ assert(mcache.wto.mod == MODFlags.wild);
+ return mcache.wto;
+ }
+ TypeNext t = cast(TypeNext)Type.makeWild();
+ if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
+ {
+ if (next.isShared())
+ {
+ if (next.isConst())
+ t.next = next.sharedWildConstOf();
+ else
+ t.next = next.sharedWildOf();
+ }
+ else
+ {
+ if (next.isConst())
+ t.next = next.wildConstOf();
+ else
+ t.next = next.wildOf();
+ }
+ }
+ //printf("TypeNext::makeWild() returns %p, %s\n", t, t.toChars());
+ return t;
+ }
+
+ override final Type makeWildConst()
+ {
+ //printf("TypeNext::makeWildConst() %s\n", toChars());
+ if (mcache && mcache.wcto)
+ {
+ assert(mcache.wcto.mod == MODFlags.wildconst);
+ return mcache.wcto;
+ }
+ TypeNext t = cast(TypeNext)Type.makeWildConst();
+ if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
+ {
+ if (next.isShared())
+ t.next = next.sharedWildConstOf();
+ else
+ t.next = next.wildConstOf();
+ }
+ //printf("TypeNext::makeWildConst() returns %p, %s\n", t, t.toChars());
+ return t;
+ }
+
+ override final Type makeSharedWild()
+ {
+ //printf("TypeNext::makeSharedWild() %s\n", toChars());
+ if (mcache && mcache.swto)
+ {
+ assert(mcache.swto.isSharedWild());
+ return mcache.swto;
+ }
+ TypeNext t = cast(TypeNext)Type.makeSharedWild();
+ if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
+ {
+ if (next.isConst())
+ t.next = next.sharedWildConstOf();
+ else
+ t.next = next.sharedWildOf();
+ }
+ //printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t.toChars());
+ return t;
+ }
+
+ override final Type makeSharedWildConst()
+ {
+ //printf("TypeNext::makeSharedWildConst() %s\n", toChars());
+ if (mcache && mcache.swcto)
+ {
+ assert(mcache.swcto.mod == (MODFlags.shared_ | MODFlags.wildconst));
+ return mcache.swcto;
+ }
+ TypeNext t = cast(TypeNext)Type.makeSharedWildConst();
+ if (ty != Tfunction && next.ty != Tfunction && !next.isImmutable())
+ {
+ t.next = next.sharedWildConstOf();
+ }
+ //printf("TypeNext::makeSharedWildConst() returns %p, %s\n", t, t.toChars());
+ return t;
+ }
+
+ override final Type makeMutable()
+ {
+ //printf("TypeNext::makeMutable() %p, %s\n", this, toChars());
+ TypeNext t = cast(TypeNext)Type.makeMutable();
+ if (ty == Tsarray)
+ {
+ t.next = next.mutableOf();
+ }
+ //printf("TypeNext::makeMutable() returns %p, %s\n", t, t.toChars());
+ return t;
+ }
+
+ override MATCH constConv(Type to)
+ {
+ //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to.toChars());
+ if (equals(to))
+ return MATCH.exact;
+
+ if (!(ty == to.ty && MODimplicitConv(mod, to.mod)))
+ return MATCH.nomatch;
+
+ Type tn = to.nextOf();
+ if (!(tn && next.ty == tn.ty))
+ return MATCH.nomatch;
+
+ MATCH m;
+ if (to.isConst()) // whole tail const conversion
+ {
+ // Recursive shared level check
+ m = next.constConv(tn);
+ if (m == MATCH.exact)
+ m = MATCH.constant;
+ }
+ else
+ {
+ //printf("\tnext => %s, to.next => %s\n", next.toChars(), tn.toChars());
+ m = next.equals(tn) ? MATCH.constant : MATCH.nomatch;
+ }
+ return m;
+ }
+
+ override final MOD deduceWild(Type t, bool isRef)
+ {
+ if (ty == Tfunction)
+ return 0;
+
+ ubyte wm;
+
+ Type tn = t.nextOf();
+ if (!isRef && (ty == Tarray || ty == Tpointer) && tn)
+ {
+ wm = next.deduceWild(tn, true);
+ if (!wm)
+ wm = Type.deduceWild(t, true);
+ }
+ else
+ {
+ wm = Type.deduceWild(t, isRef);
+ if (!wm && tn)
+ wm = next.deduceWild(tn, true);
+ }
+
+ return wm;
+ }
+
+ final void transitive()
+ {
+ /* Invoke transitivity of type attributes
+ */
+ next = next.addMod(mod);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeBasic : Type
+{
+ const(char)* dstring;
+ uint flags;
+
+ extern (D) this(TY ty)
+ {
+ super(ty);
+ const(char)* d;
+ uint flags = 0;
+ switch (ty)
+ {
+ case Tvoid:
+ d = Token.toChars(TOK.void_);
+ break;
+
+ case Tint8:
+ d = Token.toChars(TOK.int8);
+ flags |= TFlags.integral;
+ break;
+
+ case Tuns8:
+ d = Token.toChars(TOK.uns8);
+ flags |= TFlags.integral | TFlags.unsigned;
+ break;
+
+ case Tint16:
+ d = Token.toChars(TOK.int16);
+ flags |= TFlags.integral;
+ break;
+
+ case Tuns16:
+ d = Token.toChars(TOK.uns16);
+ flags |= TFlags.integral | TFlags.unsigned;
+ break;
+
+ case Tint32:
+ d = Token.toChars(TOK.int32);
+ flags |= TFlags.integral;
+ break;
+
+ case Tuns32:
+ d = Token.toChars(TOK.uns32);
+ flags |= TFlags.integral | TFlags.unsigned;
+ break;
+
+ case Tfloat32:
+ d = Token.toChars(TOK.float32);
+ flags |= TFlags.floating | TFlags.real_;
+ break;
+
+ case Tint64:
+ d = Token.toChars(TOK.int64);
+ flags |= TFlags.integral;
+ break;
+
+ case Tuns64:
+ d = Token.toChars(TOK.uns64);
+ flags |= TFlags.integral | TFlags.unsigned;
+ break;
+
+ case Tint128:
+ d = Token.toChars(TOK.int128);
+ flags |= TFlags.integral;
+ break;
+
+ case Tuns128:
+ d = Token.toChars(TOK.uns128);
+ flags |= TFlags.integral | TFlags.unsigned;
+ break;
+
+ case Tfloat64:
+ d = Token.toChars(TOK.float64);
+ flags |= TFlags.floating | TFlags.real_;
+ break;
+
+ case Tfloat80:
+ d = Token.toChars(TOK.float80);
+ flags |= TFlags.floating | TFlags.real_;
+ break;
+
+ case Timaginary32:
+ d = Token.toChars(TOK.imaginary32);
+ flags |= TFlags.floating | TFlags.imaginary;
+ break;
+
+ case Timaginary64:
+ d = Token.toChars(TOK.imaginary64);
+ flags |= TFlags.floating | TFlags.imaginary;
+ break;
+
+ case Timaginary80:
+ d = Token.toChars(TOK.imaginary80);
+ flags |= TFlags.floating | TFlags.imaginary;
+ break;
+
+ case Tcomplex32:
+ d = Token.toChars(TOK.complex32);
+ flags |= TFlags.floating | TFlags.complex;
+ break;
+
+ case Tcomplex64:
+ d = Token.toChars(TOK.complex64);
+ flags |= TFlags.floating | TFlags.complex;
+ break;
+
+ case Tcomplex80:
+ d = Token.toChars(TOK.complex80);
+ flags |= TFlags.floating | TFlags.complex;
+ break;
+
+ case Tbool:
+ d = "bool";
+ flags |= TFlags.integral | TFlags.unsigned;
+ break;
+
+ case Tchar:
+ d = Token.toChars(TOK.char_);
+ flags |= TFlags.integral | TFlags.unsigned;
+ break;
+
+ case Twchar:
+ d = Token.toChars(TOK.wchar_);
+ flags |= TFlags.integral | TFlags.unsigned;
+ break;
+
+ case Tdchar:
+ d = Token.toChars(TOK.dchar_);
+ flags |= TFlags.integral | TFlags.unsigned;
+ break;
+
+ default:
+ assert(0);
+ }
+ this.dstring = d;
+ this.flags = flags;
+ merge(this);
+ }
+
+ override const(char)* kind() const
+ {
+ return dstring;
+ }
+
+ override TypeBasic syntaxCopy()
+ {
+ // No semantic analysis done on basic types, no need to copy
+ return this;
+ }
+
+ override d_uns64 size(const ref Loc loc) const
+ {
+ uint size;
+ //printf("TypeBasic::size()\n");
+ switch (ty)
+ {
+ case Tint8:
+ case Tuns8:
+ size = 1;
+ break;
+
+ case Tint16:
+ case Tuns16:
+ size = 2;
+ break;
+
+ case Tint32:
+ case Tuns32:
+ case Tfloat32:
+ case Timaginary32:
+ size = 4;
+ break;
+
+ case Tint64:
+ case Tuns64:
+ case Tfloat64:
+ case Timaginary64:
+ size = 8;
+ break;
+
+ case Tfloat80:
+ case Timaginary80:
+ size = target.realsize;
+ break;
+
+ case Tcomplex32:
+ size = 8;
+ break;
+
+ case Tcomplex64:
+ case Tint128:
+ case Tuns128:
+ size = 16;
+ break;
+
+ case Tcomplex80:
+ size = target.realsize * 2;
+ break;
+
+ case Tvoid:
+ //size = Type::size(); // error message
+ size = 1;
+ break;
+
+ case Tbool:
+ size = 1;
+ break;
+
+ case Tchar:
+ size = 1;
+ break;
+
+ case Twchar:
+ size = 2;
+ break;
+
+ case Tdchar:
+ size = 4;
+ break;
+
+ default:
+ assert(0);
+ }
+ //printf("TypeBasic::size() = %d\n", size);
+ return size;
+ }
+
+ override uint alignsize()
+ {
+ return target.alignsize(this);
+ }
+
+ override bool isintegral()
+ {
+ //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags);
+ return (flags & TFlags.integral) != 0;
+ }
+
+ override bool isfloating() const
+ {
+ return (flags & TFlags.floating) != 0;
+ }
+
+ override bool isreal() const
+ {
+ return (flags & TFlags.real_) != 0;
+ }
+
+ override bool isimaginary() const
+ {
+ return (flags & TFlags.imaginary) != 0;
+ }
+
+ override bool iscomplex() const
+ {
+ return (flags & TFlags.complex) != 0;
+ }
+
+ override bool isscalar() const
+ {
+ return (flags & (TFlags.integral | TFlags.floating)) != 0;
+ }
+
+ override bool isunsigned() const
+ {
+ return (flags & TFlags.unsigned) != 0;
+ }
+
+ override MATCH implicitConvTo(Type to)
+ {
+ //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), toChars());
+ if (this == to)
+ return MATCH.exact;
+
+ if (ty == to.ty)
+ {
+ if (mod == to.mod)
+ return MATCH.exact;
+ else if (MODimplicitConv(mod, to.mod))
+ return MATCH.constant;
+ else if (!((mod ^ to.mod) & MODFlags.shared_)) // for wild matching
+ return MATCH.constant;
+ else
+ return MATCH.convert;
+ }
+
+ if (ty == Tvoid || to.ty == Tvoid)
+ return MATCH.nomatch;
+ if (to.ty == Tbool)
+ return MATCH.nomatch;
+
+ TypeBasic tob;
+ if (to.ty == Tvector && to.deco)
+ {
+ TypeVector tv = cast(TypeVector)to;
+ tob = tv.elementType();
+ }
+ else if (auto te = to.isTypeEnum())
+ {
+ EnumDeclaration ed = te.sym;
+ if (ed.isSpecial())
+ {
+ /* Special enums that allow implicit conversions to them
+ * with a MATCH.convert
+ */
+ tob = to.toBasetype().isTypeBasic();
+ }
+ else
+ return MATCH.nomatch;
+ }
+ else
+ tob = to.isTypeBasic();
+ if (!tob)
+ return MATCH.nomatch;
+
+ if (flags & TFlags.integral)
+ {
+ // Disallow implicit conversion of integers to imaginary or complex
+ if (tob.flags & (TFlags.imaginary | TFlags.complex))
+ return MATCH.nomatch;
+
+ // If converting from integral to integral
+ if (tob.flags & TFlags.integral)
+ {
+ d_uns64 sz = size(Loc.initial);
+ d_uns64 tosz = tob.size(Loc.initial);
+
+ /* Can't convert to smaller size
+ */
+ if (sz > tosz)
+ return MATCH.nomatch;
+ /* Can't change sign if same size
+ */
+ //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned)
+ // return MATCH.nomatch;
+ }
+ }
+ else if (flags & TFlags.floating)
+ {
+ // Disallow implicit conversion of floating point to integer
+ if (tob.flags & TFlags.integral)
+ return MATCH.nomatch;
+
+ assert(tob.flags & TFlags.floating || to.ty == Tvector);
+
+ // Disallow implicit conversion from complex to non-complex
+ if (flags & TFlags.complex && !(tob.flags & TFlags.complex))
+ return MATCH.nomatch;
+
+ // Disallow implicit conversion of real or imaginary to complex
+ if (flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex)
+ return MATCH.nomatch;
+
+ // Disallow implicit conversion to-from real and imaginary
+ if ((flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary)))
+ return MATCH.nomatch;
+ }
+ return MATCH.convert;
+ }
+
+ override bool isZeroInit(const ref Loc loc) const
+ {
+ switch (ty)
+ {
+ case Tchar:
+ case Twchar:
+ case Tdchar:
+ case Timaginary32:
+ case Timaginary64:
+ case Timaginary80:
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80:
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ return false; // no
+ default:
+ return true; // yes
+ }
+ }
+
+ // For eliminating dynamic_cast
+ override TypeBasic isTypeBasic()
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * The basetype must be one of:
+ * byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2]
+ * For AVX:
+ * byte[32],ubyte[32],short[16],ushort[16],int[8],uint[8],long[4],ulong[4],float[8],double[4]
+ */
+extern (C++) final class TypeVector : Type
+{
+ Type basetype;
+
+ extern (D) this(Type basetype)
+ {
+ super(Tvector);
+ this.basetype = basetype;
+ }
+
+ static TypeVector create(Type basetype)
+ {
+ return new TypeVector(basetype);
+ }
+
+ override const(char)* kind() const
+ {
+ return "vector";
+ }
+
+ override TypeVector syntaxCopy()
+ {
+ return new TypeVector(basetype.syntaxCopy());
+ }
+
+ override d_uns64 size(const ref Loc loc)
+ {
+ return basetype.size();
+ }
+
+ override uint alignsize()
+ {
+ return cast(uint)basetype.size();
+ }
+
+ override bool isintegral()
+ {
+ //printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags);
+ return basetype.nextOf().isintegral();
+ }
+
+ override bool isfloating()
+ {
+ return basetype.nextOf().isfloating();
+ }
+
+ override bool isscalar()
+ {
+ return basetype.nextOf().isscalar();
+ }
+
+ override bool isunsigned()
+ {
+ return basetype.nextOf().isunsigned();
+ }
+
+ override bool isBoolean() const
+ {
+ return false;
+ }
+
+ override MATCH implicitConvTo(Type to)
+ {
+ //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), toChars());
+ if (this == to)
+ return MATCH.exact;
+ if (to.ty != Tvector)
+ return MATCH.nomatch;
+
+ TypeVector tv = cast(TypeVector)to;
+ assert(basetype.ty == Tsarray && tv.basetype.ty == Tsarray);
+
+ // Can't convert to a vector which has different size.
+ if (basetype.size() != tv.basetype.size())
+ return MATCH.nomatch;
+
+ // Allow conversion to void[]
+ if (tv.basetype.nextOf().ty == Tvoid)
+ return MATCH.convert;
+
+ // Otherwise implicitly convertible only if basetypes are.
+ return basetype.implicitConvTo(tv.basetype);
+ }
+
+ override Expression defaultInitLiteral(const ref Loc loc)
+ {
+ //printf("TypeVector::defaultInitLiteral()\n");
+ assert(basetype.ty == Tsarray);
+ Expression e = basetype.defaultInitLiteral(loc);
+ auto ve = new VectorExp(loc, e, this);
+ ve.type = this;
+ ve.dim = cast(int)(basetype.size(loc) / elementType().size(loc));
+ return ve;
+ }
+
+ TypeBasic elementType()
+ {
+ assert(basetype.ty == Tsarray);
+ TypeSArray t = cast(TypeSArray)basetype;
+ TypeBasic tb = t.nextOf().isTypeBasic();
+ assert(tb);
+ return tb;
+ }
+
+ override bool isZeroInit(const ref Loc loc)
+ {
+ return basetype.isZeroInit(loc);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) abstract class TypeArray : TypeNext
+{
+ final extern (D) this(TY ty, Type next)
+ {
+ super(ty, next);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Static array, one with a fixed dimension
+ */
+extern (C++) final class TypeSArray : TypeArray
+{
+ Expression dim;
+
+ extern (D) this(Type t, Expression dim)
+ {
+ super(Tsarray, t);
+ //printf("TypeSArray(%s)\n", dim.toChars());
+ this.dim = dim;
+ }
+
+ override const(char)* kind() const
+ {
+ return "sarray";
+ }
+
+ override TypeSArray syntaxCopy()
+ {
+ Type t = next.syntaxCopy();
+ Expression e = dim.syntaxCopy();
+ auto result = new TypeSArray(t, e);
+ result.mod = mod;
+ return result;
+ }
+
+ override d_uns64 size(const ref Loc loc)
+ {
+ //printf("TypeSArray::size()\n");
+ const n = numberOfElems(loc);
+ const elemsize = baseElemOf().size(loc);
+ bool overflow = false;
+ const sz = mulu(n, elemsize, overflow);
+ if (overflow || sz >= uint.max)
+ {
+ if (elemsize != SIZE_INVALID && n != uint.max)
+ error(loc, "static array `%s` size overflowed to %lld", toChars(), cast(long)sz);
+ return SIZE_INVALID;
+ }
+ return sz;
+ }
+
+ override uint alignsize()
+ {
+ return next.alignsize();
+ }
+
+ override bool isString()
+ {
+ TY nty = next.toBasetype().ty;
+ return nty.isSomeChar;
+ }
+
+ override bool isZeroInit(const ref Loc loc)
+ {
+ return next.isZeroInit(loc);
+ }
+
+ override structalign_t alignment()
+ {
+ return next.alignment();
+ }
+
+ override MATCH constConv(Type to)
+ {
+ if (auto tsa = to.isTypeSArray())
+ {
+ if (!dim.equals(tsa.dim))
+ return MATCH.nomatch;
+ }
+ return TypeNext.constConv(to);
+ }
+
+ override MATCH implicitConvTo(Type to)
+ {
+ //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
+ if (auto ta = to.isTypeDArray())
+ {
+ if (!MODimplicitConv(next.mod, ta.next.mod))
+ return MATCH.nomatch;
+
+ /* Allow conversion to void[]
+ */
+ if (ta.next.ty == Tvoid)
+ {
+ return MATCH.convert;
+ }
+
+ MATCH m = next.constConv(ta.next);
+ if (m > MATCH.nomatch)
+ {
+ return MATCH.convert;
+ }
+ return MATCH.nomatch;
+ }
+ if (auto tsa = to.isTypeSArray())
+ {
+ if (this == to)
+ return MATCH.exact;
+
+ if (dim.equals(tsa.dim))
+ {
+ MATCH m = next.implicitConvTo(tsa.next);
+
+ /* Allow conversion to non-interface base class.
+ */
+ if (m == MATCH.convert &&
+ next.ty == Tclass)
+ {
+ if (auto toc = tsa.next.isTypeClass)
+ {
+ if (!toc.sym.isInterfaceDeclaration)
+ return MATCH.convert;
+ }
+ }
+
+ /* Since static arrays are value types, allow
+ * conversions from const elements to non-const
+ * ones, just like we allow conversion from const int
+ * to int.
+ */
+ if (m >= MATCH.constant)
+ {
+ if (mod != to.mod)
+ m = MATCH.constant;
+ return m;
+ }
+ }
+ }
+ return MATCH.nomatch;
+ }
+
+ override Expression defaultInitLiteral(const ref Loc loc)
+ {
+ static if (LOGDEFAULTINIT)
+ {
+ printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars());
+ }
+ size_t d = cast(size_t)dim.toInteger();
+ Expression elementinit;
+ if (next.ty == Tvoid)
+ elementinit = tuns8.defaultInitLiteral(loc);
+ else
+ elementinit = next.defaultInitLiteral(loc);
+ auto elements = new Expressions(d);
+ foreach (ref e; *elements)
+ e = null;
+ auto ae = new ArrayLiteralExp(Loc.initial, this, elementinit, elements);
+ return ae;
+ }
+
+ override bool hasPointers()
+ {
+ /* Don't want to do this, because:
+ * struct S { T* array[0]; }
+ * may be a variable length struct.
+ */
+ //if (dim.toInteger() == 0)
+ // return false;
+
+ if (next.ty == Tvoid)
+ {
+ // Arrays of void contain arbitrary data, which may include pointers
+ return true;
+ }
+ else
+ return next.hasPointers();
+ }
+
+ override bool hasInvariant()
+ {
+ return next.hasInvariant();
+ }
+
+ override bool needsDestruction()
+ {
+ return next.needsDestruction();
+ }
+
+ override bool needsCopyOrPostblit()
+ {
+ return next.needsCopyOrPostblit();
+ }
+
+ /*********************************
+ *
+ */
+ override bool needsNested()
+ {
+ return next.needsNested();
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Dynamic array, no dimension
+ */
+extern (C++) final class TypeDArray : TypeArray
+{
+ extern (D) this(Type t)
+ {
+ super(Tarray, t);
+ //printf("TypeDArray(t = %p)\n", t);
+ }
+
+ override const(char)* kind() const
+ {
+ return "darray";
+ }
+
+ override TypeDArray syntaxCopy()
+ {
+ Type t = next.syntaxCopy();
+ if (t == next)
+ return this;
+
+ auto result = new TypeDArray(t);
+ result.mod = mod;
+ return result;
+ }
+
+ override d_uns64 size(const ref Loc loc) const
+ {
+ //printf("TypeDArray::size()\n");
+ return target.ptrsize * 2;
+ }
+
+ override uint alignsize() const
+ {
+ // A DArray consists of two ptr-sized values, so align it on pointer size
+ // boundary
+ return target.ptrsize;
+ }
+
+ override bool isString()
+ {
+ TY nty = next.toBasetype().ty;
+ return nty.isSomeChar;
+ }
+
+ override bool isZeroInit(const ref Loc loc) const
+ {
+ return true;
+ }
+
+ override bool isBoolean() const
+ {
+ return true;
+ }
+
+ override MATCH implicitConvTo(Type to)
+ {
+ //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
+ if (equals(to))
+ return MATCH.exact;
+
+ if (auto ta = to.isTypeDArray())
+ {
+ if (!MODimplicitConv(next.mod, ta.next.mod))
+ return MATCH.nomatch; // not const-compatible
+
+ /* Allow conversion to void[]
+ */
+ if (next.ty != Tvoid && ta.next.ty == Tvoid)
+ {
+ return MATCH.convert;
+ }
+
+ MATCH m = next.constConv(ta.next);
+ if (m > MATCH.nomatch)
+ {
+ if (m == MATCH.exact && mod != to.mod)
+ m = MATCH.constant;
+ return m;
+ }
+ }
+ return Type.implicitConvTo(to);
+ }
+
+ override bool hasPointers() const
+ {
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeAArray : TypeArray
+{
+ Type index; // key type
+ Loc loc;
+
+ extern (D) this(Type t, Type index)
+ {
+ super(Taarray, t);
+ this.index = index;
+ }
+
+ static TypeAArray create(Type t, Type index)
+ {
+ return new TypeAArray(t, index);
+ }
+
+ override const(char)* kind() const
+ {
+ return "aarray";
+ }
+
+ override TypeAArray syntaxCopy()
+ {
+ Type t = next.syntaxCopy();
+ Type ti = index.syntaxCopy();
+ if (t == next && ti == index)
+ return this;
+
+ auto result = new TypeAArray(t, ti);
+ result.mod = mod;
+ return result;
+ }
+
+ override d_uns64 size(const ref Loc loc) const
+ {
+ return target.ptrsize;
+ }
+
+ override bool isZeroInit(const ref Loc loc) const
+ {
+ return true;
+ }
+
+ override bool isBoolean() const
+ {
+ return true;
+ }
+
+ override bool hasPointers() const
+ {
+ return true;
+ }
+
+ override MATCH implicitConvTo(Type to)
+ {
+ //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
+ if (equals(to))
+ return MATCH.exact;
+
+ if (auto ta = to.isTypeAArray())
+ {
+ if (!MODimplicitConv(next.mod, ta.next.mod))
+ return MATCH.nomatch; // not const-compatible
+
+ if (!MODimplicitConv(index.mod, ta.index.mod))
+ return MATCH.nomatch; // not const-compatible
+
+ MATCH m = next.constConv(ta.next);
+ MATCH mi = index.constConv(ta.index);
+ if (m > MATCH.nomatch && mi > MATCH.nomatch)
+ {
+ return MODimplicitConv(mod, to.mod) ? MATCH.constant : MATCH.nomatch;
+ }
+ }
+ return Type.implicitConvTo(to);
+ }
+
+ override MATCH constConv(Type to)
+ {
+ if (auto taa = to.isTypeAArray())
+ {
+ MATCH mindex = index.constConv(taa.index);
+ MATCH mkey = next.constConv(taa.next);
+ // Pick the worst match
+ return mkey < mindex ? mkey : mindex;
+ }
+ return Type.constConv(to);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypePointer : TypeNext
+{
+ extern (D) this(Type t)
+ {
+ super(Tpointer, t);
+ }
+
+ static TypePointer create(Type t)
+ {
+ return new TypePointer(t);
+ }
+
+ override const(char)* kind() const
+ {
+ return "pointer";
+ }
+
+ override TypePointer syntaxCopy()
+ {
+ Type t = next.syntaxCopy();
+ if (t == next)
+ return this;
+
+ auto result = new TypePointer(t);
+ result.mod = mod;
+ return result;
+ }
+
+ override d_uns64 size(const ref Loc loc) const
+ {
+ return target.ptrsize;
+ }
+
+ override MATCH implicitConvTo(Type to)
+ {
+ //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), toChars());
+ if (equals(to))
+ return MATCH.exact;
+
+ if (next.ty == Tfunction)
+ {
+ if (auto tp = to.isTypePointer())
+ {
+ if (tp.next.ty == Tfunction)
+ {
+ if (next.equals(tp.next))
+ return MATCH.constant;
+
+ if (next.covariant(tp.next) == Covariant.yes)
+ {
+ Type tret = this.next.nextOf();
+ Type toret = tp.next.nextOf();
+ if (tret.ty == Tclass && toret.ty == Tclass)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=10219
+ * Check covariant interface return with offset tweaking.
+ * interface I {}
+ * class C : Object, I {}
+ * I function() dg = function C() {} // should be error
+ */
+ int offset = 0;
+ if (toret.isBaseOf(tret, &offset) && offset != 0)
+ return MATCH.nomatch;
+ }
+ return MATCH.convert;
+ }
+ }
+ else if (tp.next.ty == Tvoid)
+ {
+ // Allow conversions to void*
+ return MATCH.convert;
+ }
+ }
+ return MATCH.nomatch;
+ }
+ else if (auto tp = to.isTypePointer())
+ {
+ assert(tp.next);
+
+ if (!MODimplicitConv(next.mod, tp.next.mod))
+ return MATCH.nomatch; // not const-compatible
+
+ /* Alloc conversion to void*
+ */
+ if (next.ty != Tvoid && tp.next.ty == Tvoid)
+ {
+ return MATCH.convert;
+ }
+
+ MATCH m = next.constConv(tp.next);
+ if (m > MATCH.nomatch)
+ {
+ if (m == MATCH.exact && mod != to.mod)
+ m = MATCH.constant;
+ return m;
+ }
+ }
+ return MATCH.nomatch;
+ }
+
+ override MATCH constConv(Type to)
+ {
+ if (next.ty == Tfunction)
+ {
+ if (to.nextOf() && next.equals((cast(TypeNext)to).next))
+ return Type.constConv(to);
+ else
+ return MATCH.nomatch;
+ }
+ return TypeNext.constConv(to);
+ }
+
+ override bool isscalar() const
+ {
+ return true;
+ }
+
+ override bool isZeroInit(const ref Loc loc) const
+ {
+ return true;
+ }
+
+ override bool hasPointers() const
+ {
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeReference : TypeNext
+{
+ extern (D) this(Type t)
+ {
+ super(Treference, t);
+ // BUG: what about references to static arrays?
+ }
+
+ override const(char)* kind() const
+ {
+ return "reference";
+ }
+
+ override TypeReference syntaxCopy()
+ {
+ Type t = next.syntaxCopy();
+ if (t == next)
+ return this;
+
+ auto result = new TypeReference(t);
+ result.mod = mod;
+ return result;
+ }
+
+ override d_uns64 size(const ref Loc loc) const
+ {
+ return target.ptrsize;
+ }
+
+ override bool isZeroInit(const ref Loc loc) const
+ {
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+enum RET : int
+{
+ regs = 1, // returned in registers
+ stack = 2, // returned on stack
+}
+
+enum TRUSTformat : int
+{
+ TRUSTformatDefault, // do not emit @system when trust == TRUST.default_
+ TRUSTformatSystem, // emit @system when trust == TRUST.default_
+}
+
+alias TRUSTformatDefault = TRUSTformat.TRUSTformatDefault;
+alias TRUSTformatSystem = TRUSTformat.TRUSTformatSystem;
+
+/***********************************************************
+ */
+extern (C++) final class TypeFunction : TypeNext
+{
+ // .next is the return type
+
+ ParameterList parameterList; // function parameters
+
+ private enum FunctionFlag : uint
+ {
+ none = 0,
+ isnothrow = 0x0001, // nothrow
+ isnogc = 0x0002, // is @nogc
+ isproperty = 0x0004, // can be called without parentheses
+ isref = 0x0008, // returns a reference
+ isreturn = 0x0010, // 'this' is returned by ref
+ isscope = 0x0020, // 'this' is scope
+ isreturninferred= 0x0040, // 'this' is return from inference
+ isscopeinferred = 0x0080, // 'this' is scope from inference
+ islive = 0x0100, // is @live
+ incomplete = 0x0200, // return type or default arguments removed
+ inoutParam = 0x0400, // inout on the parameters
+ inoutQual = 0x0800, // inout on the qualifier
+ isctor = 0x1000, // the function is a constructor
+ }
+
+ LINK linkage; // calling convention
+ FunctionFlag funcFlags;
+ TRUST trust; // level of trust
+ PURE purity = PURE.impure;
+ byte inuse;
+ Expressions* fargs; // function arguments
+
+ extern (D) this(ParameterList pl, Type treturn, LINK linkage, StorageClass stc = 0)
+ {
+ super(Tfunction, treturn);
+ //if (!treturn) *(char*)0=0;
+ // assert(treturn);
+ assert(VarArg.none <= pl.varargs && pl.varargs <= VarArg.typesafe);
+ this.parameterList = pl;
+ this.linkage = linkage;
+
+ if (stc & STC.pure_)
+ this.purity = PURE.fwdref;
+ if (stc & STC.nothrow_)
+ this.isnothrow = true;
+ if (stc & STC.nogc)
+ this.isnogc = true;
+ if (stc & STC.property)
+ this.isproperty = true;
+ if (stc & STC.live)
+ this.islive = true;
+
+ if (stc & STC.ref_)
+ this.isref = true;
+ if (stc & STC.return_)
+ this.isreturn = true;
+ if (stc & STC.returninferred)
+ this.isreturninferred = true;
+ if (stc & STC.scope_)
+ this.isScopeQual = true;
+ if (stc & STC.scopeinferred)
+ this.isscopeinferred = true;
+
+ this.trust = TRUST.default_;
+ if (stc & STC.safe)
+ this.trust = TRUST.safe;
+ if (stc & STC.system)
+ this.trust = TRUST.system;
+ if (stc & STC.trusted)
+ this.trust = TRUST.trusted;
+ }
+
+ static TypeFunction create(Parameters* parameters, Type treturn, ubyte varargs, LINK linkage, StorageClass stc = 0)
+ {
+ return new TypeFunction(ParameterList(parameters, cast(VarArg)varargs), treturn, linkage, stc);
+ }
+
+ override const(char)* kind() const
+ {
+ return "function";
+ }
+
+ override TypeFunction syntaxCopy()
+ {
+ Type treturn = next ? next.syntaxCopy() : null;
+ auto t = new TypeFunction(parameterList.syntaxCopy(), treturn, linkage);
+ t.mod = mod;
+ t.isnothrow = isnothrow;
+ t.isnogc = isnogc;
+ t.islive = islive;
+ t.purity = purity;
+ t.isproperty = isproperty;
+ t.isref = isref;
+ t.isreturn = isreturn;
+ t.isScopeQual = isScopeQual;
+ t.isreturninferred = isreturninferred;
+ t.isscopeinferred = isscopeinferred;
+ t.isInOutParam = isInOutParam;
+ t.isInOutQual = isInOutQual;
+ t.trust = trust;
+ t.fargs = fargs;
+ t.isctor = isctor;
+ return t;
+ }
+
+ /********************************************
+ * Set 'purity' field of 'this'.
+ * Do this lazily, as the parameter types might be forward referenced.
+ */
+ void purityLevel()
+ {
+ TypeFunction tf = this;
+ if (tf.purity != PURE.fwdref)
+ return;
+
+ /* Determine purity level based on mutability of t
+ * and whether it is a 'ref' type or not.
+ */
+ static PURE purityOfType(bool isref, Type t)
+ {
+ if (isref)
+ {
+ if (t.mod & MODFlags.immutable_)
+ return PURE.strong;
+ if (t.mod & (MODFlags.const_ | MODFlags.wild))
+ return PURE.const_;
+ return PURE.weak;
+ }
+
+ t = t.baseElemOf();
+
+ if (!t.hasPointers() || t.mod & MODFlags.immutable_)
+ return PURE.strong;
+
+ /* Accept immutable(T)[] and immutable(T)* as being strongly pure
+ */
+ if (t.ty == Tarray || t.ty == Tpointer)
+ {
+ Type tn = t.nextOf().toBasetype();
+ if (tn.mod & MODFlags.immutable_)
+ return PURE.strong;
+ if (tn.mod & (MODFlags.const_ | MODFlags.wild))
+ return PURE.const_;
+ }
+
+ /* The rest of this is too strict; fix later.
+ * For example, the only pointer members of a struct may be immutable,
+ * which would maintain strong purity.
+ * (Just like for dynamic arrays and pointers above.)
+ */
+ if (t.mod & (MODFlags.const_ | MODFlags.wild))
+ return PURE.const_;
+
+ /* Should catch delegates and function pointers, and fold in their purity
+ */
+ return PURE.weak;
+ }
+
+ purity = PURE.strong; // assume strong until something weakens it
+
+ /* Evaluate what kind of purity based on the modifiers for the parameters
+ */
+ Lloop: foreach (i, fparam; tf.parameterList)
+ {
+ Type t = fparam.type;
+ if (!t)
+ continue;
+
+ if (fparam.storageClass & (STC.lazy_ | STC.out_))
+ {
+ purity = PURE.weak;
+ break;
+ }
+ switch (purityOfType((fparam.storageClass & STC.ref_) != 0, t))
+ {
+ case PURE.weak:
+ purity = PURE.weak;
+ break Lloop; // since PURE.weak, no need to check further
+
+ case PURE.const_:
+ purity = PURE.const_;
+ continue;
+
+ case PURE.strong:
+ continue;
+
+ default:
+ assert(0);
+ }
+ }
+
+ if (purity > PURE.weak && tf.nextOf())
+ {
+ /* Adjust purity based on mutability of return type.
+ * https://issues.dlang.org/show_bug.cgi?id=15862
+ */
+ const purity2 = purityOfType(tf.isref, tf.nextOf());
+ if (purity2 < purity)
+ purity = purity2;
+ }
+ tf.purity = purity;
+ }
+
+ /********************************************
+ * Return true if there are lazy parameters.
+ */
+ bool hasLazyParameters()
+ {
+ foreach (i, fparam; parameterList)
+ {
+ if (fparam.storageClass & STC.lazy_)
+ return true;
+ }
+ return false;
+ }
+
+ /*******************************
+ * Check for `extern (D) U func(T t, ...)` variadic function type,
+ * which has `_arguments[]` added as the first argument.
+ * Returns:
+ * true if D-style variadic
+ */
+ bool isDstyleVariadic() const pure nothrow
+ {
+ return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
+ }
+
+ /***************************
+ * Examine function signature for parameter p and see if
+ * the value of p can 'escape' the scope of the function.
+ * This is useful to minimize the needed annotations for the parameters.
+ * Params:
+ * tthis = type of `this` parameter, null if none
+ * p = parameter to this function
+ * Returns:
+ * true if escapes via assignment to global or through a parameter
+ */
+ bool parameterEscapes(Type tthis, Parameter p)
+ {
+ /* Scope parameters do not escape.
+ * Allow 'lazy' to imply 'scope' -
+ * lazy parameters can be passed along
+ * as lazy parameters to the next function, but that isn't
+ * escaping.
+ */
+ if (parameterStorageClass(tthis, p) & (STC.scope_ | STC.lazy_))
+ return false;
+ return true;
+ }
+
+ /************************************
+ * Take the specified storage class for p,
+ * and use the function signature to infer whether
+ * STC.scope_ and STC.return_ should be OR'd in.
+ * (This will not affect the name mangling.)
+ * Params:
+ * tthis = type of `this` parameter, null if none
+ * p = parameter to this function
+ * Returns:
+ * storage class with STC.scope_ or STC.return_ OR'd in
+ */
+ StorageClass parameterStorageClass(Type tthis, Parameter p)
+ {
+ //printf("parameterStorageClass(p: %s)\n", p.toChars());
+ auto stc = p.storageClass;
+ if (global.params.useDIP1000 != FeatureState.enabled)
+ return stc;
+
+ // When the preview switch is enable, `in` parameters are `scope`
+ if (stc & STC.in_ && global.params.previewIn)
+ return stc | STC.scope_;
+
+ if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure)
+ return stc;
+
+ /* If haven't inferred the return type yet, can't infer storage classes
+ */
+ if (!nextOf())
+ return stc;
+
+ purityLevel();
+
+ // See if p can escape via any of the other parameters
+ if (purity == PURE.weak)
+ {
+ // Check escaping through parameters
+ foreach (i, fparam; parameterList)
+ {
+ if (fparam == p)
+ continue;
+ Type t = fparam.type;
+ if (!t)
+ continue;
+ t = t.baseElemOf();
+ if (t.isMutable() && t.hasPointers())
+ {
+ if (fparam.isReference())
+ {
+ }
+ else if (t.ty == Tarray || t.ty == Tpointer)
+ {
+ Type tn = t.nextOf().toBasetype();
+ if (!(tn.isMutable() && tn.hasPointers()))
+ continue;
+ }
+ return stc;
+ }
+ }
+
+ // Check escaping through `this`
+ if (tthis && tthis.isMutable())
+ {
+ auto tb = tthis.toBasetype();
+ AggregateDeclaration ad;
+ if (auto tc = tb.isTypeClass())
+ ad = tc.sym;
+ else if (auto ts = tb.isTypeStruct())
+ ad = ts.sym;
+ else
+ assert(0);
+ foreach (VarDeclaration v; ad.fields)
+ {
+ if (v.hasPointers())
+ return stc;
+ }
+ }
+ }
+
+ /* Inferring STC.return_ here has false positives
+ * for pure functions, producing spurious error messages
+ * about escaping references.
+ * Give up on it for now.
+ */
+ version (none)
+ {
+ stc |= STC.scope_;
+
+ Type tret = nextOf().toBasetype();
+ if (isref || tret.hasPointers())
+ {
+ /* The result has references, so p could be escaping
+ * that way.
+ */
+ stc |= STC.return_;
+ }
+ }
+ else
+ {
+ // Check escaping through return value
+ Type tret = nextOf().toBasetype();
+ if (isref || tret.hasPointers())
+ {
+ return stc;
+ }
+
+ stc |= STC.scope_;
+ }
+
+ return stc;
+ }
+
+ override Type addStorageClass(StorageClass stc)
+ {
+ //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0);
+ TypeFunction t = Type.addStorageClass(stc).toTypeFunction();
+ if ((stc & STC.pure_ && !t.purity) ||
+ (stc & STC.nothrow_ && !t.isnothrow) ||
+ (stc & STC.nogc && !t.isnogc) ||
+ (stc & STC.scope_ && !t.isScopeQual) ||
+ (stc & STC.safe && t.trust < TRUST.trusted))
+ {
+ // Klunky to change these
+ auto tf = new TypeFunction(t.parameterList, t.next, t.linkage, 0);
+ tf.mod = t.mod;
+ tf.fargs = fargs;
+ tf.purity = t.purity;
+ tf.isnothrow = t.isnothrow;
+ tf.isnogc = t.isnogc;
+ tf.isproperty = t.isproperty;
+ tf.isref = t.isref;
+ tf.isreturn = t.isreturn;
+ tf.isScopeQual = t.isScopeQual;
+ tf.isreturninferred = t.isreturninferred;
+ tf.isscopeinferred = t.isscopeinferred;
+ tf.trust = t.trust;
+ tf.isInOutParam = t.isInOutParam;
+ tf.isInOutQual = t.isInOutQual;
+ tf.isctor = t.isctor;
+
+ if (stc & STC.pure_)
+ tf.purity = PURE.fwdref;
+ if (stc & STC.nothrow_)
+ tf.isnothrow = true;
+ if (stc & STC.nogc)
+ tf.isnogc = true;
+ if (stc & STC.safe)
+ tf.trust = TRUST.safe;
+ if (stc & STC.scope_)
+ {
+ tf.isScopeQual = true;
+ if (stc & STC.scopeinferred)
+ tf.isscopeinferred = true;
+ }
+
+ tf.deco = tf.merge().deco;
+ t = tf;
+ }
+ return t;
+ }
+
+ override Type substWildTo(uint)
+ {
+ if (!iswild && !(mod & MODFlags.wild))
+ return this;
+
+ // Substitude inout qualifier of function type to mutable or immutable
+ // would break type system. Instead substitude inout to the most weak
+ // qualifer - const.
+ uint m = MODFlags.const_;
+
+ assert(next);
+ Type tret = next.substWildTo(m);
+ Parameters* params = parameterList.parameters;
+ if (mod & MODFlags.wild)
+ params = parameterList.parameters.copy();
+ for (size_t i = 0; i < params.dim; i++)
+ {
+ Parameter p = (*params)[i];
+ Type t = p.type.substWildTo(m);
+ if (t == p.type)
+ continue;
+ if (params == parameterList.parameters)
+ params = parameterList.parameters.copy();
+ (*params)[i] = new Parameter(p.storageClass, t, null, null, null);
+ }
+ if (next == tret && params == parameterList.parameters)
+ return this;
+
+ // Similar to TypeFunction::syntaxCopy;
+ auto t = new TypeFunction(ParameterList(params, parameterList.varargs), tret, linkage);
+ t.mod = ((mod & MODFlags.wild) ? (mod & ~MODFlags.wild) | MODFlags.const_ : mod);
+ t.isnothrow = isnothrow;
+ t.isnogc = isnogc;
+ t.purity = purity;
+ t.isproperty = isproperty;
+ t.isref = isref;
+ t.isreturn = isreturn;
+ t.isScopeQual = isScopeQual;
+ t.isreturninferred = isreturninferred;
+ t.isscopeinferred = isscopeinferred;
+ t.isInOutParam = false;
+ t.isInOutQual = false;
+ t.trust = trust;
+ t.fargs = fargs;
+ t.isctor = isctor;
+ return t.merge();
+ }
+
+ // arguments get specially formatted
+ private const(char)* getParamError(Expression arg, Parameter par)
+ {
+ if (global.gag && !global.params.showGaggedErrors)
+ return null;
+ // show qualification when toChars() is the same but types are different
+ auto at = arg.type.toChars();
+ bool qual = !arg.type.equals(par.type) && strcmp(at, par.type.toChars()) == 0;
+ if (qual)
+ at = arg.type.toPrettyChars(true);
+ OutBuffer buf;
+ // only mention rvalue if it's relevant
+ const rv = !arg.isLvalue() && par.isReference();
+ buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
+ rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at,
+ parameterToChars(par, this, qual));
+ return buf.extractChars();
+ }
+
+ private extern(D) const(char)* getMatchError(A...)(const(char)* format, A args)
+ {
+ if (global.gag && !global.params.showGaggedErrors)
+ return null;
+ OutBuffer buf;
+ buf.printf(format, args);
+ return buf.extractChars();
+ }
+
+ /********************************
+ * 'args' are being matched to function 'this'
+ * Determine match level.
+ * Params:
+ * tthis = type of `this` pointer, null if not member function
+ * args = array of function arguments
+ * flag = 1: performing a partial ordering match
+ * pMessage = address to store error message, or null
+ * sc = context
+ * Returns:
+ * MATCHxxxx
+ */
+ extern (D) MATCH callMatch(Type tthis, Expression[] args, int flag = 0, const(char)** pMessage = null, Scope* sc = null)
+ {
+ //printf("TypeFunction::callMatch() %s\n", toChars());
+ MATCH match = MATCH.exact; // assume exact match
+ ubyte wildmatch = 0;
+
+ if (tthis)
+ {
+ Type t = tthis;
+ if (t.toBasetype().ty == Tpointer)
+ t = t.toBasetype().nextOf(); // change struct* to struct
+ if (t.mod != mod)
+ {
+ if (MODimplicitConv(t.mod, mod))
+ match = MATCH.constant;
+ else if ((mod & MODFlags.wild) && MODimplicitConv(t.mod, (mod & ~MODFlags.wild) | MODFlags.const_))
+ {
+ match = MATCH.constant;
+ }
+ else
+ return MATCH.nomatch;
+ }
+ if (isWild())
+ {
+ if (t.isWild())
+ wildmatch |= MODFlags.wild;
+ else if (t.isConst())
+ wildmatch |= MODFlags.const_;
+ else if (t.isImmutable())
+ wildmatch |= MODFlags.immutable_;
+ else
+ wildmatch |= MODFlags.mutable;
+ }
+ }
+
+ const nparams = parameterList.length;
+ const nargs = args.length;
+ if (nargs > nparams)
+ {
+ if (parameterList.varargs == VarArg.none)
+ {
+ // suppress early exit if an error message is wanted,
+ // so we can check any matching args are valid
+ if (!pMessage)
+ goto Nomatch;
+ }
+ // too many args; no match
+ match = MATCH.convert; // match ... with a "conversion" match level
+ }
+
+ foreach (u, p; parameterList)
+ {
+ if (u == nargs)
+ break;
+
+ Expression arg = args[u];
+ assert(arg);
+ Type tprm = p.type;
+ Type targ = arg.type;
+
+ if (!(p.storageClass & STC.lazy_ && tprm.ty == Tvoid && targ.ty != Tvoid))
+ {
+ const isRef = p.isReference();
+ wildmatch |= targ.deduceWild(tprm, isRef);
+ }
+ }
+ if (wildmatch)
+ {
+ /* Calculate wild matching modifier
+ */
+ if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1))
+ wildmatch = MODFlags.const_;
+ else if (wildmatch & MODFlags.immutable_)
+ wildmatch = MODFlags.immutable_;
+ else if (wildmatch & MODFlags.wild)
+ wildmatch = MODFlags.wild;
+ else
+ {
+ assert(wildmatch & MODFlags.mutable);
+ wildmatch = MODFlags.mutable;
+ }
+ }
+
+ foreach (u, p; parameterList)
+ {
+ MATCH m;
+
+ assert(p);
+ if (u >= nargs)
+ {
+ if (p.defaultArg)
+ continue;
+ // try typesafe variadics
+ goto L1;
+ }
+ {
+ Expression arg = args[u];
+ assert(arg);
+ //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
+
+ Type targ = arg.type;
+ Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type;
+
+ if (p.storageClass & STC.lazy_ && tprm.ty == Tvoid && targ.ty != Tvoid)
+ m = MATCH.convert;
+ else
+ {
+ //printf("%s of type %s implicitConvTo %s\n", arg.toChars(), targ.toChars(), tprm.toChars());
+ if (flag)
+ {
+ // for partial ordering, value is an irrelevant mockup, just look at the type
+ m = targ.implicitConvTo(tprm);
+ }
+ else
+ {
+ const isRef = p.isReference();
+
+ StructDeclaration argStruct, prmStruct;
+
+ // first look for a copy constructor
+ if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct)
+ {
+ // if the argument and the parameter are of the same unqualified struct type
+ argStruct = (cast(TypeStruct)targ).sym;
+ prmStruct = (cast(TypeStruct)tprm).sym;
+ }
+
+ // check if the copy constructor may be called to copy the argument
+ if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
+ {
+ /* this is done by seeing if a call to the copy constructor can be made:
+ *
+ * typeof(tprm) __copytmp;
+ * copytmp.__copyCtor(arg);
+ */
+ auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null);
+ tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe;
+ tmp.dsymbolSemantic(sc);
+ Expression ve = new VarExp(arg.loc, tmp);
+ Expression e = new DotIdExp(arg.loc, ve, Id.ctor);
+ e = new CallExp(arg.loc, e, arg);
+ //printf("e = %s\n", e.toChars());
+ if(.trySemantic(e, sc))
+ m = MATCH.exact;
+ else
+ {
+ m = MATCH.nomatch;
+ if (pMessage)
+ {
+ OutBuffer buf;
+ buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
+ argStruct.toChars(), targ.toChars(), tprm.toChars());
+ *pMessage = buf.extractChars();
+ }
+ goto Nomatch;
+ }
+ }
+ else
+ m = arg.implicitConvTo(tprm);
+ }
+ //printf("match %d\n", m);
+ }
+
+ // Non-lvalues do not match ref or out parameters
+ if (p.isReference())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=13783
+ // Don't use toBasetype() to handle enum types.
+ Type ta = targ;
+ Type tp = tprm;
+ //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
+
+ if (m && !arg.isLvalue())
+ {
+ if (p.storageClass & STC.out_)
+ {
+ if (pMessage) *pMessage = getParamError(arg, p);
+ goto Nomatch;
+ }
+
+ if (arg.op == TOK.string_ && tp.ty == Tsarray)
+ {
+ if (ta.ty != Tsarray)
+ {
+ Type tn = tp.nextOf().castMod(ta.nextOf().mod);
+ dinteger_t dim = (cast(StringExp)arg).len;
+ ta = tn.sarrayOf(dim);
+ }
+ }
+ else if (arg.op == TOK.slice && tp.ty == Tsarray)
+ {
+ // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
+ if (ta.ty != Tsarray)
+ {
+ Type tn = ta.nextOf();
+ dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
+ ta = tn.sarrayOf(dim);
+ }
+ }
+ else if ((p.storageClass & STC.in_) && global.params.previewIn)
+ {
+ // Allow converting a literal to an `in` which is `ref`
+ if (arg.op == TOK.arrayLiteral && tp.ty == Tsarray)
+ {
+ Type tn = tp.nextOf();
+ dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
+ ta = tn.sarrayOf(dim);
+ }
+
+ // Need to make this a rvalue through a temporary
+ m = MATCH.convert;
+ }
+ else if (!global.params.rvalueRefParam ||
+ p.storageClass & STC.out_ ||
+ !arg.type.isCopyable()) // can't copy to temp for ref parameter
+ {
+ if (pMessage) *pMessage = getParamError(arg, p);
+ goto Nomatch;
+ }
+ else
+ {
+ /* in functionParameters() we'll convert this
+ * rvalue into a temporary
+ */
+ m = MATCH.convert;
+ }
+ }
+
+ /* If the match is not already perfect or if the arg
+ is not a lvalue then try the `alias this` chain
+ see https://issues.dlang.org/show_bug.cgi?id=15674
+ and https://issues.dlang.org/show_bug.cgi?id=21905
+ */
+ if (ta != tp || !arg.isLvalue())
+ {
+ Type firsttab = ta.toBasetype();
+ while (1)
+ {
+ Type tab = ta.toBasetype();
+ Type tat = tab.aliasthisOf();
+ if (!tat || !tat.implicitConvTo(tprm))
+ break;
+ if (tat == tab || tat == firsttab)
+ break;
+ ta = tat;
+ }
+ }
+
+ /* A ref variable should work like a head-const reference.
+ * e.g. disallows:
+ * ref T <- an lvalue of const(T) argument
+ * ref T[dim] <- an lvalue of const(T[dim]) argument
+ */
+ if (!ta.constConv(tp))
+ {
+ if (pMessage) *pMessage = getParamError(arg, p);
+ goto Nomatch;
+ }
+ }
+ }
+
+ /* prefer matching the element type rather than the array
+ * type when more arguments are present with T[]...
+ */
+ if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && nargs > nparams)
+ goto L1;
+
+ //printf("\tm = %d\n", m);
+ if (m == MATCH.nomatch) // if no match
+ {
+ L1:
+ if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param
+ {
+ Type tb = p.type.toBasetype();
+ TypeSArray tsa;
+ dinteger_t sz;
+
+ switch (tb.ty)
+ {
+ case Tsarray:
+ tsa = cast(TypeSArray)tb;
+ sz = tsa.dim.toInteger();
+ if (sz != nargs - u)
+ {
+ if (pMessage)
+ // Windows (Vista) OutBuffer.vprintf issue? 2nd argument always zero
+ //*pMessage = getMatchError("expected %d variadic argument(s), not %d", sz, nargs - u);
+ if (!global.gag || global.params.showGaggedErrors)
+ {
+ OutBuffer buf;
+ buf.printf("expected %llu variadic argument(s)", sz);
+ buf.printf(", not %zu", nargs - u);
+ *pMessage = buf.extractChars();
+ }
+ goto Nomatch;
+ }
+ goto case Tarray;
+ case Tarray:
+ {
+ TypeArray ta = cast(TypeArray)tb;
+ foreach (arg; args[u .. nargs])
+ {
+ assert(arg);
+
+ /* If lazy array of delegates,
+ * convert arg(s) to delegate(s)
+ */
+ Type tret = p.isLazyArray();
+ if (tret)
+ {
+ if (ta.next.equals(arg.type))
+ m = MATCH.exact;
+ else if (tret.toBasetype().ty == Tvoid)
+ m = MATCH.convert;
+ else
+ {
+ m = arg.implicitConvTo(tret);
+ if (m == MATCH.nomatch)
+ m = arg.implicitConvTo(ta.next);
+ }
+ }
+ else
+ m = arg.implicitConvTo(ta.next);
+
+ if (m == MATCH.nomatch)
+ {
+ if (pMessage) *pMessage = getParamError(arg, p);
+ goto Nomatch;
+ }
+ if (m < match)
+ match = m;
+ }
+ goto Ldone;
+ }
+ case Tclass:
+ // Should see if there's a constructor match?
+ // Or just leave it ambiguous?
+ goto Ldone;
+
+ default:
+ break;
+ }
+ }
+ if (pMessage && u < nargs)
+ *pMessage = getParamError(args[u], p);
+ else if (pMessage)
+ *pMessage = getMatchError("missing argument for parameter #%d: `%s`",
+ u + 1, parameterToChars(p, this, false));
+ goto Nomatch;
+ }
+ if (m < match)
+ match = m; // pick worst match
+ }
+
+ Ldone:
+ if (pMessage && !parameterList.varargs && nargs > nparams)
+ {
+ // all parameters had a match, but there are surplus args
+ *pMessage = getMatchError("expected %d argument(s), not %d", nparams, nargs);
+ goto Nomatch;
+ }
+ //printf("match = %d\n", match);
+ return match;
+
+ Nomatch:
+ //printf("no match\n");
+ return MATCH.nomatch;
+ }
+
+ /** Extends TypeNext.constConv by also checking for matching attributes **/
+ override MATCH constConv(Type to)
+ {
+ // Attributes need to match exactly, otherwise it's an implicit conversion
+ if (this.ty != to.ty || !this.attributesEqual(cast(TypeFunction) to))
+ return MATCH.nomatch;
+
+ return super.constConv(to);
+ }
+
+ extern (D) bool checkRetType(const ref Loc loc)
+ {
+ Type tb = next.toBasetype();
+ if (tb.ty == Tfunction)
+ {
+ error(loc, "functions cannot return a function");
+ next = Type.terror;
+ }
+ if (tb.ty == Ttuple)
+ {
+ error(loc, "functions cannot return a tuple");
+ next = Type.terror;
+ }
+ if (!isref && (tb.ty == Tstruct || tb.ty == Tsarray))
+ {
+ if (auto ts = tb.baseElemOf().isTypeStruct())
+ {
+ if (!ts.sym.members)
+ {
+ error(loc, "functions cannot return opaque type `%s` by value", tb.toChars());
+ next = Type.terror;
+ }
+ }
+ }
+ if (tb.ty == Terror)
+ return true;
+ return false;
+ }
+
+ /// set or get if the function has the `nothrow` attribute
+ bool isnothrow() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.isnothrow) != 0;
+ }
+ /// ditto
+ void isnothrow(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.isnothrow;
+ else funcFlags &= ~FunctionFlag.isnothrow;
+ }
+
+ /// set or get if the function has the `@nogc` attribute
+ bool isnogc() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.isnogc) != 0;
+ }
+ /// ditto
+ void isnogc(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.isnogc;
+ else funcFlags &= ~FunctionFlag.isnogc;
+ }
+
+ /// set or get if the function has the `@property` attribute
+ bool isproperty() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.isproperty) != 0;
+ }
+ /// ditto
+ void isproperty(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.isproperty;
+ else funcFlags &= ~FunctionFlag.isproperty;
+ }
+
+ /// set or get if the function has the `ref` attribute
+ bool isref() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.isref) != 0;
+ }
+ /// ditto
+ void isref(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.isref;
+ else funcFlags &= ~FunctionFlag.isref;
+ }
+
+ /// set or get if the function has the `return` attribute
+ bool isreturn() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.isreturn) != 0;
+ }
+ /// ditto
+ void isreturn(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.isreturn;
+ else funcFlags &= ~FunctionFlag.isreturn;
+ }
+
+ /// set or get if the function has the `scope` attribute
+ bool isScopeQual() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.isscope) != 0;
+ }
+ /// ditto
+ void isScopeQual(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.isscope;
+ else funcFlags &= ~FunctionFlag.isscope;
+ }
+
+ /// set or get if the function has the `return` attribute inferred
+ bool isreturninferred() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.isreturninferred) != 0;
+ }
+ /// ditto
+ void isreturninferred(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.isreturninferred;
+ else funcFlags &= ~FunctionFlag.isreturninferred;
+ }
+
+ /// set or get if the function has the `scope` attribute inferred
+ bool isscopeinferred() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.isscopeinferred) != 0;
+ }
+ /// ditoo
+ void isscopeinferred(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.isscopeinferred;
+ else funcFlags &= ~FunctionFlag.isscopeinferred;
+ }
+
+ /// set or get if the function has the `@live` attribute
+ bool islive() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.islive) != 0;
+ }
+ /// ditto
+ void islive(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.islive;
+ else funcFlags &= ~FunctionFlag.islive;
+ }
+
+ /// set or get if the return type or the default arguments are removed
+ bool incomplete() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.incomplete) != 0;
+ }
+ /// ditto
+ void incomplete(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.incomplete;
+ else funcFlags &= ~FunctionFlag.incomplete;
+ }
+
+ /// set or get if the function has the `inout` on the parameters
+ bool isInOutParam() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.inoutParam) != 0;
+ }
+ /// ditto
+ void isInOutParam(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.inoutParam;
+ else funcFlags &= ~FunctionFlag.inoutParam;
+ }
+
+ /// set or get if the function has the `inout` on the parameters
+ bool isInOutQual() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.inoutQual) != 0;
+ }
+ /// ditto
+ void isInOutQual(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.inoutQual;
+ else funcFlags &= ~FunctionFlag.inoutQual;
+ }
+ /// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise.
+ bool iswild() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & (FunctionFlag.inoutParam | FunctionFlag.inoutQual)) != 0;
+ }
+
+ /// set or get if the function is a constructor
+ bool isctor() const pure nothrow @safe @nogc
+ {
+ return (funcFlags & FunctionFlag.isctor) != 0;
+ }
+ /// ditto
+ void isctor(bool v) pure nothrow @safe @nogc
+ {
+ if (v) funcFlags |= FunctionFlag.isctor;
+ else funcFlags &= ~FunctionFlag.isctor;
+ }
+
+ /// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other`
+ bool attributesEqual(const scope TypeFunction other) const pure nothrow @safe @nogc
+ {
+ enum attributes = FunctionFlag.isnothrow
+ | FunctionFlag.isnogc
+ | FunctionFlag.islive;
+
+ return this.trust == other.trust &&
+ this.purity == other.purity &&
+ (this.funcFlags & attributes) == (other.funcFlags & attributes);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeDelegate : TypeNext
+{
+ // .next is a TypeFunction
+
+ extern (D) this(TypeFunction t)
+ {
+ super(Tfunction, t);
+ ty = Tdelegate;
+ }
+
+ static TypeDelegate create(TypeFunction t)
+ {
+ return new TypeDelegate(t);
+ }
+
+ override const(char)* kind() const
+ {
+ return "delegate";
+ }
+
+ override TypeDelegate syntaxCopy()
+ {
+ auto tf = next.syntaxCopy().isTypeFunction();
+ if (tf == next)
+ return this;
+
+ auto result = new TypeDelegate(tf);
+ result.mod = mod;
+ return result;
+ }
+
+ override Type addStorageClass(StorageClass stc)
+ {
+ TypeDelegate t = cast(TypeDelegate)Type.addStorageClass(stc);
+ if (global.params.useDIP1000 != FeatureState.enabled)
+ return t;
+
+ /* The rest is meant to add 'scope' to a delegate declaration if it is of the form:
+ * alias dg_t = void* delegate();
+ * scope dg_t dg = ...;
+ */
+ if(stc & STC.scope_)
+ {
+ auto n = t.next.addStorageClass(STC.scope_ | STC.scopeinferred);
+ if (n != t.next)
+ {
+ t.next = n;
+ t.deco = t.merge().deco; // mangling supposed to not be changed due to STC.scope_inferrred
+ }
+ }
+ return t;
+ }
+
+ override d_uns64 size(const ref Loc loc) const
+ {
+ return target.ptrsize * 2;
+ }
+
+ override uint alignsize() const
+ {
+ return target.ptrsize;
+ }
+
+ override MATCH implicitConvTo(Type to)
+ {
+ //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to);
+ //printf("from: %s\n", toChars());
+ //printf("to : %s\n", to.toChars());
+ if (this == to)
+ return MATCH.exact;
+
+ version (all)
+ {
+ // not allowing covariant conversions because it interferes with overriding
+ if (to.ty == Tdelegate && this.nextOf().covariant(to.nextOf()) == Covariant.yes)
+ {
+ Type tret = this.next.nextOf();
+ Type toret = (cast(TypeDelegate)to).next.nextOf();
+ if (tret.ty == Tclass && toret.ty == Tclass)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=10219
+ * Check covariant interface return with offset tweaking.
+ * interface I {}
+ * class C : Object, I {}
+ * I delegate() dg = delegate C() {} // should be error
+ */
+ int offset = 0;
+ if (toret.isBaseOf(tret, &offset) && offset != 0)
+ return MATCH.nomatch;
+ }
+ return MATCH.convert;
+ }
+ }
+
+ return MATCH.nomatch;
+ }
+
+ override bool isZeroInit(const ref Loc loc) const
+ {
+ return true;
+ }
+
+ override bool isBoolean() const
+ {
+ return true;
+ }
+
+ override bool hasPointers() const
+ {
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/**
+ * This is a shell containing a TraitsExp that can be
+ * either resolved to a type or to a symbol.
+ *
+ * The point is to allow AliasDeclarationY to use `__traits()`, see issue 7804.
+ */
+extern (C++) final class TypeTraits : Type
+{
+ Loc loc;
+ /// The expression to resolve as type or symbol.
+ TraitsExp exp;
+ /// After `typeSemantic` the symbol when `exp` doesn't represent a type.
+ Dsymbol sym;
+
+ final extern (D) this(const ref Loc loc, TraitsExp exp)
+ {
+ super(Ttraits);
+ this.loc = loc;
+ this.exp = exp;
+ }
+
+ override const(char)* kind() const
+ {
+ return "traits";
+ }
+
+ override TypeTraits syntaxCopy()
+ {
+ TraitsExp te = exp.syntaxCopy();
+ TypeTraits tt = new TypeTraits(loc, te);
+ tt.mod = mod;
+ return tt;
+ }
+
+ override Dsymbol toDsymbol(Scope* sc)
+ {
+ Type t;
+ Expression e;
+ Dsymbol s;
+ resolve(this, loc, sc, e, t, s);
+ if (t && t.ty != Terror)
+ s = t.toDsymbol(sc);
+ else if (e)
+ s = getDsymbol(e);
+
+ return s;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ override d_uns64 size(const ref Loc loc)
+ {
+ return SIZE_INVALID;
+ }
+}
+
+/******
+ * Implements mixin types.
+ *
+ * Semantic analysis will convert it to a real type.
+ */
+extern (C++) final class TypeMixin : Type
+{
+ Loc loc;
+ Expressions* exps;
+ RootObject obj; // cached result of semantic analysis.
+
+ extern (D) this(const ref Loc loc, Expressions* exps)
+ {
+ super(Tmixin);
+ this.loc = loc;
+ this.exps = exps;
+ }
+
+ override const(char)* kind() const
+ {
+ return "mixin";
+ }
+
+ override TypeMixin syntaxCopy()
+ {
+ return new TypeMixin(loc, Expression.arraySyntaxCopy(exps));
+ }
+
+ override Dsymbol toDsymbol(Scope* sc)
+ {
+ Type t;
+ Expression e;
+ Dsymbol s;
+ resolve(this, loc, sc, e, t, s);
+ if (t)
+ s = t.toDsymbol(sc);
+ else if (e)
+ s = getDsymbol(e);
+
+ return s;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) abstract class TypeQualified : Type
+{
+ Loc loc;
+
+ // array of Identifier and TypeInstance,
+ // representing ident.ident!tiargs.ident. ... etc.
+ Objects idents;
+
+ final extern (D) this(TY ty, Loc loc)
+ {
+ super(ty);
+ this.loc = loc;
+ }
+
+ // abstract override so that using `TypeQualified.syntaxCopy` gets
+ // us a `TypeQualified`
+ abstract override TypeQualified syntaxCopy();
+
+ final void syntaxCopyHelper(TypeQualified t)
+ {
+ //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t.toChars(), toChars());
+ idents.setDim(t.idents.dim);
+ for (size_t i = 0; i < idents.dim; i++)
+ {
+ RootObject id = t.idents[i];
+ with (DYNCAST) final switch (id.dyncast())
+ {
+ case object:
+ break;
+ case expression:
+ Expression e = cast(Expression)id;
+ e = e.syntaxCopy();
+ id = e;
+ break;
+ case dsymbol:
+ TemplateInstance ti = cast(TemplateInstance)id;
+ ti = ti.syntaxCopy(null);
+ id = ti;
+ break;
+ case type:
+ Type tx = cast(Type)id;
+ tx = tx.syntaxCopy();
+ id = tx;
+ break;
+ case identifier:
+ case tuple:
+ case parameter:
+ case statement:
+ case condition:
+ case templateparameter:
+ case initializer:
+ }
+ idents[i] = id;
+ }
+ }
+
+ final void addIdent(Identifier ident)
+ {
+ idents.push(ident);
+ }
+
+ final void addInst(TemplateInstance inst)
+ {
+ idents.push(inst);
+ }
+
+ final void addIndex(RootObject e)
+ {
+ idents.push(e);
+ }
+
+ override d_uns64 size(const ref Loc loc)
+ {
+ error(this.loc, "size of type `%s` is not known", toChars());
+ return SIZE_INVALID;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeIdentifier : TypeQualified
+{
+ Identifier ident;
+
+ // The symbol representing this identifier, before alias resolution
+ Dsymbol originalSymbol;
+
+ extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ super(Tident, loc);
+ this.ident = ident;
+ }
+
+ override const(char)* kind() const
+ {
+ return "identifier";
+ }
+
+ override TypeIdentifier syntaxCopy()
+ {
+ auto t = new TypeIdentifier(loc, ident);
+ t.syntaxCopyHelper(this);
+ t.mod = mod;
+ return t;
+ }
+
+ /*****************************************
+ * See if type resolves to a symbol, if so,
+ * return that symbol.
+ */
+ override Dsymbol toDsymbol(Scope* sc)
+ {
+ //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
+ if (!sc)
+ return null;
+
+ Type t;
+ Expression e;
+ Dsymbol s;
+ resolve(this, loc, sc, e, t, s);
+ if (t && t.ty != Tident)
+ s = t.toDsymbol(sc);
+ if (e)
+ s = getDsymbol(e);
+
+ return s;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Similar to TypeIdentifier, but with a TemplateInstance as the root
+ */
+extern (C++) final class TypeInstance : TypeQualified
+{
+ TemplateInstance tempinst;
+
+ extern (D) this(const ref Loc loc, TemplateInstance tempinst)
+ {
+ super(Tinstance, loc);
+ this.tempinst = tempinst;
+ }
+
+ override const(char)* kind() const
+ {
+ return "instance";
+ }
+
+ override TypeInstance syntaxCopy()
+ {
+ //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim);
+ auto t = new TypeInstance(loc, tempinst.syntaxCopy(null));
+ t.syntaxCopyHelper(this);
+ t.mod = mod;
+ return t;
+ }
+
+ override Dsymbol toDsymbol(Scope* sc)
+ {
+ Type t;
+ Expression e;
+ Dsymbol s;
+ //printf("TypeInstance::semantic(%s)\n", toChars());
+ resolve(this, loc, sc, e, t, s);
+ if (t && t.ty != Tinstance)
+ s = t.toDsymbol(sc);
+ return s;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeTypeof : TypeQualified
+{
+ Expression exp;
+ int inuse;
+
+ extern (D) this(const ref Loc loc, Expression exp)
+ {
+ super(Ttypeof, loc);
+ this.exp = exp;
+ }
+
+ override const(char)* kind() const
+ {
+ return "typeof";
+ }
+
+ override TypeTypeof syntaxCopy()
+ {
+ //printf("TypeTypeof::syntaxCopy() %s\n", toChars());
+ auto t = new TypeTypeof(loc, exp.syntaxCopy());
+ t.syntaxCopyHelper(this);
+ t.mod = mod;
+ return t;
+ }
+
+ override Dsymbol toDsymbol(Scope* sc)
+ {
+ //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
+ Expression e;
+ Type t;
+ Dsymbol s;
+ resolve(this, loc, sc, e, t, s);
+ return s;
+ }
+
+ override d_uns64 size(const ref Loc loc)
+ {
+ if (exp.type)
+ return exp.type.size(loc);
+ else
+ return TypeQualified.size(loc);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeReturn : TypeQualified
+{
+ extern (D) this(const ref Loc loc)
+ {
+ super(Treturn, loc);
+ }
+
+ override const(char)* kind() const
+ {
+ return "return";
+ }
+
+ override TypeReturn syntaxCopy()
+ {
+ auto t = new TypeReturn(loc);
+ t.syntaxCopyHelper(this);
+ t.mod = mod;
+ return t;
+ }
+
+ override Dsymbol toDsymbol(Scope* sc)
+ {
+ Expression e;
+ Type t;
+ Dsymbol s;
+ resolve(this, loc, sc, e, t, s);
+ return s;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeStruct : Type
+{
+ StructDeclaration sym;
+ AliasThisRec att = AliasThisRec.fwdref;
+ bool inuse = false; // struct currently subject of recursive method call
+
+ extern (D) this(StructDeclaration sym)
+ {
+ super(Tstruct);
+ this.sym = sym;
+ }
+
+ static TypeStruct create(StructDeclaration sym)
+ {
+ return new TypeStruct(sym);
+ }
+
+ override const(char)* kind() const
+ {
+ return "struct";
+ }
+
+ override d_uns64 size(const ref Loc loc)
+ {
+ return sym.size(loc);
+ }
+
+ override uint alignsize()
+ {
+ sym.size(Loc.initial); // give error for forward references
+ return sym.alignsize;
+ }
+
+ override TypeStruct syntaxCopy()
+ {
+ return this;
+ }
+
+ override Dsymbol toDsymbol(Scope* sc)
+ {
+ return sym;
+ }
+
+ override structalign_t alignment()
+ {
+ if (sym.alignment == 0)
+ sym.size(sym.loc);
+ return sym.alignment;
+ }
+
+ /***************************************
+ * Use when we prefer the default initializer to be a literal,
+ * rather than a global immutable variable.
+ */
+ override Expression defaultInitLiteral(const ref Loc loc)
+ {
+ static if (LOGDEFAULTINIT)
+ {
+ printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars());
+ }
+ sym.size(loc);
+ if (sym.sizeok != Sizeok.done)
+ return ErrorExp.get();
+
+ auto structelems = new Expressions(sym.nonHiddenFields());
+ uint offset = 0;
+ foreach (j; 0 .. structelems.dim)
+ {
+ VarDeclaration vd = sym.fields[j];
+ Expression e;
+ if (vd.inuse)
+ {
+ error(loc, "circular reference to `%s`", vd.toPrettyChars());
+ return ErrorExp.get();
+ }
+ if (vd.offset < offset || vd.type.size() == 0)
+ e = null;
+ else if (vd._init)
+ {
+ if (vd._init.isVoidInitializer())
+ e = null;
+ else
+ e = vd.getConstInitializer(false);
+ }
+ else
+ e = vd.type.defaultInitLiteral(loc);
+ if (e && e.op == TOK.error)
+ return e;
+ if (e)
+ offset = vd.offset + cast(uint)vd.type.size();
+ (*structelems)[j] = e;
+ }
+ auto structinit = new StructLiteralExp(loc, sym, structelems);
+
+ /* Copy from the initializer symbol for larger symbols,
+ * otherwise the literals expressed as code get excessively large.
+ */
+ if (size(loc) > target.ptrsize * 4 && !needsNested())
+ structinit.useStaticInit = true;
+
+ structinit.type = this;
+ return structinit;
+ }
+
+ override bool isZeroInit(const ref Loc loc)
+ {
+ // Determine zeroInit here, as this can be called before semantic2
+ sym.determineSize(sym.loc);
+ return sym.zeroInit;
+ }
+
+ override bool isAssignable()
+ {
+ bool assignable = true;
+ uint offset = ~0; // dead-store initialize to prevent spurious warning
+
+ sym.determineSize(sym.loc);
+
+ /* If any of the fields are const or immutable,
+ * then one cannot assign this struct.
+ */
+ for (size_t i = 0; i < sym.fields.dim; i++)
+ {
+ VarDeclaration v = sym.fields[i];
+ //printf("%s [%d] v = (%s) %s, v.offset = %d, v.parent = %s\n", sym.toChars(), i, v.kind(), v.toChars(), v.offset, v.parent.kind());
+ if (i == 0)
+ {
+ }
+ else if (v.offset == offset)
+ {
+ /* If any fields of anonymous union are assignable,
+ * then regard union as assignable.
+ * This is to support unsafe things like Rebindable templates.
+ */
+ if (assignable)
+ continue;
+ }
+ else
+ {
+ if (!assignable)
+ return false;
+ }
+ assignable = v.type.isMutable() && v.type.isAssignable();
+ offset = v.offset;
+ //printf(" -> assignable = %d\n", assignable);
+ }
+
+ return assignable;
+ }
+
+ override bool isBoolean() const
+ {
+ return false;
+ }
+
+ override bool needsDestruction() const
+ {
+ return sym.dtor !is null;
+ }
+
+ override bool needsCopyOrPostblit()
+ {
+ return sym.hasCopyCtor || sym.postblit;
+ }
+
+ override bool needsNested()
+ {
+ if (inuse) return false; // circular type, error instead of crashing
+
+ inuse = true;
+ scope(exit) inuse = false;
+
+ if (sym.isNested())
+ return true;
+
+ for (size_t i = 0; i < sym.fields.dim; i++)
+ {
+ VarDeclaration v = sym.fields[i];
+ if (!v.isDataseg() && v.type.needsNested())
+ return true;
+ }
+ return false;
+ }
+
+ override bool hasPointers()
+ {
+ // Probably should cache this information in sym rather than recompute
+ StructDeclaration s = sym;
+
+ if (sym.members && !sym.determineFields() && sym.type != Type.terror)
+ error(sym.loc, "no size because of forward references");
+
+ foreach (VarDeclaration v; s.fields)
+ {
+ if (v.storage_class & STC.ref_ || v.hasPointers())
+ return true;
+ }
+ return false;
+ }
+
+ override bool hasVoidInitPointers()
+ {
+ // Probably should cache this information in sym rather than recompute
+ StructDeclaration s = sym;
+
+ sym.size(Loc.initial); // give error for forward references
+ foreach (VarDeclaration v; s.fields)
+ {
+ if (v._init && v._init.isVoidInitializer() && v.type.hasPointers())
+ return true;
+ if (!v._init && v.type.hasVoidInitPointers())
+ return true;
+ }
+ return false;
+ }
+
+ override bool hasInvariant()
+ {
+ // Probably should cache this information in sym rather than recompute
+ StructDeclaration s = sym;
+
+ sym.size(Loc.initial); // give error for forward references
+
+ if (s.hasInvariant())
+ return true;
+
+ foreach (VarDeclaration v; s.fields)
+ {
+ if (v.type.hasInvariant())
+ return true;
+ }
+ return false;
+ }
+
+ extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
+ {
+ MATCH m;
+
+ if (ty == to.ty && sym == (cast(TypeStruct)to).sym)
+ {
+ m = MATCH.exact; // exact match
+ if (mod != to.mod)
+ {
+ m = MATCH.constant;
+ if (MODimplicitConv(mod, to.mod))
+ {
+ }
+ else
+ {
+ /* Check all the fields. If they can all be converted,
+ * allow the conversion.
+ */
+ uint offset = ~0; // dead-store to prevent spurious warning
+ for (size_t i = 0; i < sym.fields.dim; i++)
+ {
+ VarDeclaration v = sym.fields[i];
+ if (i == 0)
+ {
+ }
+ else if (v.offset == offset)
+ {
+ if (m > MATCH.nomatch)
+ continue;
+ }
+ else
+ {
+ if (m == MATCH.nomatch)
+ return m;
+ }
+
+ // 'from' type
+ Type tvf = v.type.addMod(mod);
+
+ // 'to' type
+ Type tv = v.type.addMod(to.mod);
+
+ // field match
+ MATCH mf = tvf.implicitConvTo(tv);
+ //printf("\t%s => %s, match = %d\n", v.type.toChars(), tv.toChars(), mf);
+
+ if (mf == MATCH.nomatch)
+ return mf;
+ if (mf < m) // if field match is worse
+ m = mf;
+ offset = v.offset;
+ }
+ }
+ }
+ }
+ return m;
+ }
+
+ extern (D) MATCH implicitConvToThroughAliasThis(Type to)
+ {
+ MATCH m;
+ if (!(ty == to.ty && sym == (cast(TypeStruct)to).sym) && sym.aliasthis && !(att & AliasThisRec.tracing))
+ {
+ if (auto ato = aliasthisOf())
+ {
+ att = cast(AliasThisRec)(att | AliasThisRec.tracing);
+ m = ato.implicitConvTo(to);
+ att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
+ }
+ else
+ m = MATCH.nomatch; // no match
+ }
+ return m;
+ }
+
+ override MATCH implicitConvTo(Type to)
+ {
+ //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to.toChars());
+ MATCH m = implicitConvToWithoutAliasThis(to);
+ return m ? m : implicitConvToThroughAliasThis(to);
+ }
+
+ override MATCH constConv(Type to)
+ {
+ if (equals(to))
+ return MATCH.exact;
+ if (ty == to.ty && sym == (cast(TypeStruct)to).sym && MODimplicitConv(mod, to.mod))
+ return MATCH.constant;
+ return MATCH.nomatch;
+ }
+
+ override MOD deduceWild(Type t, bool isRef)
+ {
+ if (ty == t.ty && sym == (cast(TypeStruct)t).sym)
+ return Type.deduceWild(t, isRef);
+
+ ubyte wm = 0;
+
+ if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing))
+ {
+ if (auto ato = aliasthisOf())
+ {
+ att = cast(AliasThisRec)(att | AliasThisRec.tracing);
+ wm = ato.deduceWild(t, isRef);
+ att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
+ }
+ }
+
+ return wm;
+ }
+
+ override inout(Type) toHeadMutable() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeEnum : Type
+{
+ EnumDeclaration sym;
+
+ extern (D) this(EnumDeclaration sym)
+ {
+ super(Tenum);
+ this.sym = sym;
+ }
+
+ override const(char)* kind() const
+ {
+ return "enum";
+ }
+
+ override TypeEnum syntaxCopy()
+ {
+ return this;
+ }
+
+ override d_uns64 size(const ref Loc loc)
+ {
+ return sym.getMemtype(loc).size(loc);
+ }
+
+ Type memType(const ref Loc loc = Loc.initial)
+ {
+ return sym.getMemtype(loc);
+ }
+ override uint alignsize()
+ {
+ Type t = memType();
+ if (t.ty == Terror)
+ return 4;
+ return t.alignsize();
+ }
+
+ override Dsymbol toDsymbol(Scope* sc)
+ {
+ return sym;
+ }
+
+ override bool isintegral()
+ {
+ return memType().isintegral();
+ }
+
+ override bool isfloating()
+ {
+ return memType().isfloating();
+ }
+
+ override bool isreal()
+ {
+ return memType().isreal();
+ }
+
+ override bool isimaginary()
+ {
+ return memType().isimaginary();
+ }
+
+ override bool iscomplex()
+ {
+ return memType().iscomplex();
+ }
+
+ override bool isscalar()
+ {
+ return memType().isscalar();
+ }
+
+ override bool isunsigned()
+ {
+ return memType().isunsigned();
+ }
+
+ override bool isBoolean()
+ {
+ return memType().isBoolean();
+ }
+
+ override bool isString()
+ {
+ return memType().isString();
+ }
+
+ override bool isAssignable()
+ {
+ return memType().isAssignable();
+ }
+
+ override bool needsDestruction()
+ {
+ return memType().needsDestruction();
+ }
+
+ override bool needsCopyOrPostblit()
+ {
+ return memType().needsCopyOrPostblit();
+ }
+
+ override bool needsNested()
+ {
+ return memType().needsNested();
+ }
+
+ override MATCH implicitConvTo(Type to)
+ {
+ MATCH m;
+ //printf("TypeEnum::implicitConvTo() %s to %s\n", toChars(), to.toChars());
+ if (ty == to.ty && sym == (cast(TypeEnum)to).sym)
+ m = (mod == to.mod) ? MATCH.exact : MATCH.constant;
+ else if (sym.getMemtype(Loc.initial).implicitConvTo(to))
+ m = MATCH.convert; // match with conversions
+ else
+ m = MATCH.nomatch; // no match
+ return m;
+ }
+
+ override MATCH constConv(Type to)
+ {
+ if (equals(to))
+ return MATCH.exact;
+ if (ty == to.ty && sym == (cast(TypeEnum)to).sym && MODimplicitConv(mod, to.mod))
+ return MATCH.constant;
+ return MATCH.nomatch;
+ }
+
+ extern (D) Type toBasetype2()
+ {
+ if (!sym.members && !sym.memtype)
+ return this;
+ auto tb = sym.getMemtype(Loc.initial).toBasetype();
+ return tb.castMod(mod); // retain modifier bits from 'this'
+ }
+
+ override bool isZeroInit(const ref Loc loc)
+ {
+ return sym.getDefaultValue(loc).isBool(false);
+ }
+
+ override bool hasPointers()
+ {
+ return memType().hasPointers();
+ }
+
+ override bool hasVoidInitPointers()
+ {
+ return memType().hasVoidInitPointers();
+ }
+
+ override bool hasInvariant()
+ {
+ return memType().hasInvariant();
+ }
+
+ override Type nextOf()
+ {
+ return memType().nextOf();
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeClass : Type
+{
+ ClassDeclaration sym;
+ AliasThisRec att = AliasThisRec.fwdref;
+ CPPMANGLE cppmangle = CPPMANGLE.def;
+
+ extern (D) this(ClassDeclaration sym)
+ {
+ super(Tclass);
+ this.sym = sym;
+ }
+
+ override const(char)* kind() const
+ {
+ return "class";
+ }
+
+ override d_uns64 size(const ref Loc loc) const
+ {
+ return target.ptrsize;
+ }
+
+ override TypeClass syntaxCopy()
+ {
+ return this;
+ }
+
+ override Dsymbol toDsymbol(Scope* sc)
+ {
+ return sym;
+ }
+
+ override inout(ClassDeclaration) isClassHandle() inout
+ {
+ return sym;
+ }
+
+ override bool isBaseOf(Type t, int* poffset)
+ {
+ if (t && t.ty == Tclass)
+ {
+ ClassDeclaration cd = (cast(TypeClass)t).sym;
+ if (sym.isBaseOf(cd, poffset))
+ return true;
+ }
+ return false;
+ }
+
+ extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
+ {
+ MATCH m = constConv(to);
+ if (m > MATCH.nomatch)
+ return m;
+
+ ClassDeclaration cdto = to.isClassHandle();
+ if (cdto)
+ {
+ //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to.toChars(), toChars(), cdto.isBaseInfoComplete(), sym.isBaseInfoComplete());
+ if (cdto.semanticRun < PASS.semanticdone && !cdto.isBaseInfoComplete())
+ cdto.dsymbolSemantic(null);
+ if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
+ sym.dsymbolSemantic(null);
+ if (cdto.isBaseOf(sym, null) && MODimplicitConv(mod, to.mod))
+ {
+ //printf("'to' is base\n");
+ return MATCH.convert;
+ }
+ }
+ return MATCH.nomatch;
+ }
+
+ extern (D) MATCH implicitConvToThroughAliasThis(Type to)
+ {
+ MATCH m;
+ if (sym.aliasthis && !(att & AliasThisRec.tracing))
+ {
+ if (auto ato = aliasthisOf())
+ {
+ att = cast(AliasThisRec)(att | AliasThisRec.tracing);
+ m = ato.implicitConvTo(to);
+ att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
+ }
+ }
+ return m;
+ }
+
+ override MATCH implicitConvTo(Type to)
+ {
+ //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), toChars());
+ MATCH m = implicitConvToWithoutAliasThis(to);
+ return m ? m : implicitConvToThroughAliasThis(to);
+ }
+
+ override MATCH constConv(Type to)
+ {
+ if (equals(to))
+ return MATCH.exact;
+ if (ty == to.ty && sym == (cast(TypeClass)to).sym && MODimplicitConv(mod, to.mod))
+ return MATCH.constant;
+
+ /* Conversion derived to const(base)
+ */
+ int offset = 0;
+ if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod))
+ {
+ // Disallow:
+ // derived to base
+ // inout(derived) to inout(base)
+ if (!to.isMutable() && !to.isWild())
+ return MATCH.convert;
+ }
+
+ return MATCH.nomatch;
+ }
+
+ override MOD deduceWild(Type t, bool isRef)
+ {
+ ClassDeclaration cd = t.isClassHandle();
+ if (cd && (sym == cd || cd.isBaseOf(sym, null)))
+ return Type.deduceWild(t, isRef);
+
+ ubyte wm = 0;
+
+ if (t.hasWild() && sym.aliasthis && !(att & AliasThisRec.tracing))
+ {
+ if (auto ato = aliasthisOf())
+ {
+ att = cast(AliasThisRec)(att | AliasThisRec.tracing);
+ wm = ato.deduceWild(t, isRef);
+ att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
+ }
+ }
+
+ return wm;
+ }
+
+ override inout(Type) toHeadMutable() inout
+ {
+ return this;
+ }
+
+ override bool isZeroInit(const ref Loc loc) const
+ {
+ return true;
+ }
+
+ override bool isscope() const
+ {
+ return sym.stack;
+ }
+
+ override bool isBoolean() const
+ {
+ return true;
+ }
+
+ override bool hasPointers() const
+ {
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeTuple : Type
+{
+ // 'logically immutable' cached global - don't modify!
+ __gshared TypeTuple empty = new TypeTuple();
+
+ Parameters* arguments; // types making up the tuple
+
+ extern (D) this(Parameters* arguments)
+ {
+ super(Ttuple);
+ //printf("TypeTuple(this = %p)\n", this);
+ this.arguments = arguments;
+ //printf("TypeTuple() %p, %s\n", this, toChars());
+ debug
+ {
+ if (arguments)
+ {
+ for (size_t i = 0; i < arguments.dim; i++)
+ {
+ Parameter arg = (*arguments)[i];
+ assert(arg && arg.type);
+ }
+ }
+ }
+ }
+
+ /****************
+ * Form TypeTuple from the types of the expressions.
+ * Assume exps[] is already tuple expanded.
+ */
+ extern (D) this(Expressions* exps)
+ {
+ super(Ttuple);
+ auto arguments = new Parameters();
+ if (exps)
+ {
+ arguments.setDim(exps.dim);
+ for (size_t i = 0; i < exps.dim; i++)
+ {
+ Expression e = (*exps)[i];
+ if (e.type.ty == Ttuple)
+ e.error("cannot form tuple of tuples");
+ auto arg = new Parameter(STC.undefined_, e.type, null, null, null);
+ (*arguments)[i] = arg;
+ }
+ }
+ this.arguments = arguments;
+ //printf("TypeTuple() %p, %s\n", this, toChars());
+ }
+
+ static TypeTuple create(Parameters* arguments)
+ {
+ return new TypeTuple(arguments);
+ }
+
+ /*******************************************
+ * Type tuple with 0, 1 or 2 types in it.
+ */
+ extern (D) this()
+ {
+ super(Ttuple);
+ arguments = new Parameters();
+ }
+
+ extern (D) this(Type t1)
+ {
+ super(Ttuple);
+ arguments = new Parameters();
+ arguments.push(new Parameter(0, t1, null, null, null));
+ }
+
+ extern (D) this(Type t1, Type t2)
+ {
+ super(Ttuple);
+ arguments = new Parameters();
+ arguments.push(new Parameter(0, t1, null, null, null));
+ arguments.push(new Parameter(0, t2, null, null, null));
+ }
+
+ static TypeTuple create()
+ {
+ return new TypeTuple();
+ }
+
+ static TypeTuple create(Type t1)
+ {
+ return new TypeTuple(t1);
+ }
+
+ static TypeTuple create(Type t1, Type t2)
+ {
+ return new TypeTuple(t1, t2);
+ }
+
+ override const(char)* kind() const
+ {
+ return "tuple";
+ }
+
+ override TypeTuple syntaxCopy()
+ {
+ Parameters* args = Parameter.arraySyntaxCopy(arguments);
+ auto t = new TypeTuple(args);
+ t.mod = mod;
+ return t;
+ }
+
+ override bool equals(const RootObject o) const
+ {
+ Type t = cast(Type)o;
+ //printf("TypeTuple::equals(%s, %s)\n", toChars(), t.toChars());
+ if (this == t)
+ return true;
+ if (auto tt = t.isTypeTuple())
+ {
+ if (arguments.dim == tt.arguments.dim)
+ {
+ for (size_t i = 0; i < tt.arguments.dim; i++)
+ {
+ const Parameter arg1 = (*arguments)[i];
+ Parameter arg2 = (*tt.arguments)[i];
+ if (!arg1.type.equals(arg2.type))
+ return false;
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * This is so we can slice a TypeTuple
+ */
+extern (C++) final class TypeSlice : TypeNext
+{
+ Expression lwr;
+ Expression upr;
+
+ extern (D) this(Type next, Expression lwr, Expression upr)
+ {
+ super(Tslice, next);
+ //printf("TypeSlice[%s .. %s]\n", lwr.toChars(), upr.toChars());
+ this.lwr = lwr;
+ this.upr = upr;
+ }
+
+ override const(char)* kind() const
+ {
+ return "slice";
+ }
+
+ override TypeSlice syntaxCopy()
+ {
+ auto t = new TypeSlice(next.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy());
+ t.mod = mod;
+ return t;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeNull : Type
+{
+ extern (D) this()
+ {
+ //printf("TypeNull %p\n", this);
+ super(Tnull);
+ }
+
+ override const(char)* kind() const
+ {
+ return "null";
+ }
+
+ override TypeNull syntaxCopy()
+ {
+ // No semantic analysis done, no need to copy
+ return this;
+ }
+
+ override MATCH implicitConvTo(Type to)
+ {
+ //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to);
+ //printf("from: %s\n", toChars());
+ //printf("to : %s\n", to.toChars());
+ MATCH m = Type.implicitConvTo(to);
+ if (m != MATCH.nomatch)
+ return m;
+
+ // NULL implicitly converts to any pointer type or dynamic array
+ //if (type.ty == Tpointer && type.nextOf().ty == Tvoid)
+ {
+ Type tb = to.toBasetype();
+ if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate)
+ return MATCH.constant;
+ }
+
+ return MATCH.nomatch;
+ }
+
+ override bool hasPointers()
+ {
+ /* Although null isn't dereferencable, treat it as a pointer type for
+ * attribute inference, generic code, etc.
+ */
+ return true;
+ }
+
+ override bool isBoolean() const
+ {
+ return true;
+ }
+
+ override d_uns64 size(const ref Loc loc) const
+ {
+ return tvoidptr.size(loc);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class TypeNoreturn : Type
+{
+ extern (D) this()
+ {
+ //printf("TypeNoreturn %p\n", this);
+ super(Tnoreturn);
+ }
+
+ override const(char)* kind() const
+ {
+ return "noreturn";
+ }
+
+ override TypeNoreturn syntaxCopy()
+ {
+ // No semantic analysis done, no need to copy
+ return this;
+ }
+
+ override MATCH implicitConvTo(Type to)
+ {
+ //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to);
+ //printf("from: %s\n", toChars());
+ //printf("to : %s\n", to.toChars());
+ if (this.equals(to))
+ return MATCH.exact;
+
+ // Different qualifiers?
+ if (to.ty == Tnoreturn)
+ return MATCH.constant;
+
+ // Implicitly convertible to any type
+ return MATCH.convert;
+ }
+
+ override MATCH constConv(Type to)
+ {
+ // Either another noreturn or conversion to any type
+ return this.implicitConvTo(to);
+ }
+
+ override bool isBoolean() const
+ {
+ return true; // bottom type can be implicitly converted to any other type
+ }
+
+ override d_uns64 size(const ref Loc loc) const
+ {
+ return 0;
+ }
+
+ override uint alignsize()
+ {
+ return 0;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Unlike D, C can declare/define struct/union/enum tag names
+ * inside Declarators, instead of separately as in D.
+ * The order these appear in the symbol table must be in lexical
+ * order. There isn't enough info at the parsing stage to determine if
+ * it's a declaration or a reference to an existing name, so this Type
+ * collects the necessary info and defers it to semantic().
+ */
+extern (C++) final class TypeTag : Type
+{
+ Loc loc; /// location of declaration
+ TOK tok; /// TOK.struct_, TOK.union_, TOK.enum_
+ Identifier id; /// tag name identifier
+ Dsymbols* members; /// members of struct, null if none
+
+ Type resolved; /// type after semantic() in case there are more others
+ /// pointing to this instance, which can happen with
+ /// struct S { int a; } s1, *s2;
+
+ extern (D) this(const ref Loc loc, TOK tok, Identifier id, Dsymbols* members)
+ {
+ //printf("TypeTag %p\n", this);
+ super(Ttag);
+ this.loc = loc;
+ this.tok = tok;
+ this.id = id;
+ this.members = members;
+ }
+
+ override const(char)* kind() const
+ {
+ return "tag";
+ }
+
+ override TypeTag syntaxCopy()
+ {
+ // No semantic analysis done, no need to copy
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Represents a function's formal parameters + variadics info.
+ * Length, indexing and iteration are based on a depth-first tuple expansion.
+ * https://dlang.org/spec/function.html#ParameterList
+ */
+extern (C++) struct ParameterList
+{
+ /// The raw (unexpanded) formal parameters, possibly containing tuples.
+ Parameters* parameters;
+ StorageClass stc; // storage class of ...
+ VarArg varargs = VarArg.none;
+ bool hasIdentifierList; // true if C identifier-list style
+
+ this(Parameters* parameters, VarArg varargs = VarArg.none, StorageClass stc = 0)
+ {
+ this.parameters = parameters;
+ this.varargs = varargs;
+ this.stc = stc;
+ }
+
+ /// Returns the number of expanded parameters. Complexity: O(N).
+ size_t length()
+ {
+ return Parameter.dim(parameters);
+ }
+
+ /// Returns the expanded parameter at the given index, or null if out of
+ /// bounds. Complexity: O(i).
+ Parameter opIndex(size_t i)
+ {
+ return Parameter.getNth(parameters, i);
+ }
+
+ /// Iterates over the expanded parameters. Complexity: O(N).
+ /// Prefer this to avoid the O(N + N^2/2) complexity of calculating length
+ /// and calling N times opIndex.
+ extern (D) int opApply(scope Parameter.ForeachDg dg)
+ {
+ return Parameter._foreach(parameters, dg);
+ }
+
+ /// Iterates over the expanded parameters, matching them with the unexpanded
+ /// ones, for semantic processing
+ extern (D) int opApply(scope Parameter.SemanticForeachDg dg)
+ {
+ return Parameter._foreach(this.parameters, dg);
+ }
+
+ extern (D) ParameterList syntaxCopy()
+ {
+ return ParameterList(Parameter.arraySyntaxCopy(parameters), varargs);
+ }
+
+ /// Compares this to another ParameterList (and expands tuples if necessary)
+ extern (D) bool opEquals(scope ref ParameterList other) const
+ {
+ if (stc != other.stc || varargs != other.varargs || (!parameters != !other.parameters))
+ return false;
+
+ if (this.parameters is other.parameters)
+ return true;
+
+ size_t idx;
+ bool diff;
+
+ // Pairwise compare each parameter
+ // Can this avoid the O(n) indexing for the second list?
+ foreach (_, p1; cast() this)
+ {
+ auto p2 = other[idx++];
+ if (!p2 || p1 != p2) {
+ diff = true;
+ break;
+ }
+ }
+
+ // Ensure no remaining parameters in `other`
+ return !diff && other[idx] is null;
+ }
+}
+
+
+/***********************************************************
+ */
+extern (C++) final class Parameter : ASTNode
+{
+ import dmd.attrib : UserAttributeDeclaration;
+
+ StorageClass storageClass;
+ Type type;
+ Identifier ident;
+ Expression defaultArg;
+ UserAttributeDeclaration userAttribDecl; // user defined attributes
+
+ extern (D) this(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl)
+ {
+ this.type = type;
+ this.ident = ident;
+ this.storageClass = storageClass;
+ this.defaultArg = defaultArg;
+ this.userAttribDecl = userAttribDecl;
+ }
+
+ static Parameter create(StorageClass storageClass, Type type, Identifier ident, Expression defaultArg, UserAttributeDeclaration userAttribDecl)
+ {
+ return new Parameter(storageClass, type, ident, defaultArg, userAttribDecl);
+ }
+
+ Parameter syntaxCopy()
+ {
+ return new Parameter(storageClass, type ? type.syntaxCopy() : null, ident, defaultArg ? defaultArg.syntaxCopy() : null, userAttribDecl ? userAttribDecl.syntaxCopy(null) : null);
+ }
+
+ /****************************************************
+ * Determine if parameter is a lazy array of delegates.
+ * If so, return the return type of those delegates.
+ * If not, return NULL.
+ *
+ * Returns T if the type is one of the following forms:
+ * T delegate()[]
+ * T delegate()[dim]
+ */
+ Type isLazyArray()
+ {
+ Type tb = type.toBasetype();
+ if (tb.ty == Tsarray || tb.ty == Tarray)
+ {
+ Type tel = (cast(TypeArray)tb).next.toBasetype();
+ if (auto td = tel.isTypeDelegate())
+ {
+ TypeFunction tf = td.next.toTypeFunction();
+ if (tf.parameterList.varargs == VarArg.none && tf.parameterList.length == 0)
+ {
+ return tf.next; // return type of delegate
+ }
+ }
+ }
+ return null;
+ }
+
+ /// Returns: Whether the function parameter is a reference (out / ref)
+ bool isReference() const @safe pure nothrow @nogc
+ {
+ return (this.storageClass & (STC.ref_ | STC.out_)) != 0;
+ }
+
+ // kludge for template.isType()
+ override DYNCAST dyncast() const
+ {
+ return DYNCAST.parameter;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ extern (D) static Parameters* arraySyntaxCopy(Parameters* parameters)
+ {
+ Parameters* params = null;
+ if (parameters)
+ {
+ params = new Parameters(parameters.dim);
+ for (size_t i = 0; i < params.dim; i++)
+ (*params)[i] = (*parameters)[i].syntaxCopy();
+ }
+ return params;
+ }
+
+ /***************************************
+ * Determine number of arguments, folding in tuples.
+ */
+ static size_t dim(Parameters* parameters)
+ {
+ size_t nargs = 0;
+
+ int dimDg(size_t n, Parameter p)
+ {
+ ++nargs;
+ return 0;
+ }
+
+ _foreach(parameters, &dimDg);
+ return nargs;
+ }
+
+ /**
+ * Get nth `Parameter`, folding in tuples.
+ *
+ * Since `parameters` can include tuples, which would increase its
+ * length, this function allows to get the `nth` parameter as if
+ * all tuples transitively contained in `parameters` were flattened.
+ *
+ * Params:
+ * parameters = Array of `Parameter` to iterate over
+ * nth = Index of the desired parameter.
+ *
+ * Returns:
+ * The parameter at index `nth` (taking tuples into account),
+ * or `null` if out of bound.
+ */
+ static Parameter getNth(Parameters* parameters, size_t nth)
+ {
+ Parameter param;
+
+ int getNthParamDg(size_t n, Parameter p)
+ {
+ if (n == nth)
+ {
+ param = p;
+ return 1;
+ }
+ return 0;
+ }
+
+ int res = _foreach(parameters, &getNthParamDg);
+ return res ? param : null;
+ }
+
+ /// Type of delegate when iterating solely on the parameters
+ alias ForeachDg = extern (D) int delegate(size_t paramidx, Parameter param);
+ /// Type of delegate when iterating on both the original set of parameters,
+ /// and the type tuple. Useful for semantic analysis.
+ /// 'o' stands for 'original' and 'e' stands for 'expanded'.
+ alias SemanticForeachDg = extern (D) int delegate(
+ size_t oidx, Parameter oparam, size_t eidx, Parameter eparam);
+
+ /***************************************
+ * Expands tuples in args in depth first order. Calls
+ * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter.
+ * If dg returns !=0, stops and returns that value else returns 0.
+ * Use this function to avoid the O(N + N^2/2) complexity of
+ * calculating dim and calling N times getNth.
+ */
+ extern (D) static int _foreach(Parameters* parameters, scope ForeachDg dg)
+ {
+ assert(dg !is null);
+ return _foreach(parameters, (_oidx, _oparam, idx, param) => dg(idx, param));
+ }
+
+ /// Ditto
+ extern (D) static int _foreach(
+ Parameters* parameters, scope SemanticForeachDg dg)
+ {
+ assert(dg !is null);
+ if (parameters is null)
+ return 0;
+
+ size_t eidx;
+ foreach (oidx; 0 .. parameters.length)
+ {
+ Parameter oparam = (*parameters)[oidx];
+ if (auto r = _foreachImpl(dg, oidx, oparam, eidx, /* eparam */ oparam))
+ return r;
+ }
+ return 0;
+ }
+
+ /// Implementation of the iteration process, which recurses in itself
+ /// and just forwards `oidx` and `oparam`.
+ extern (D) private static int _foreachImpl(scope SemanticForeachDg dg,
+ size_t oidx, Parameter oparam, ref size_t eidx, Parameter eparam)
+ {
+ if (eparam is null)
+ return 0;
+
+ Type t = eparam.type.toBasetype();
+ if (auto tu = t.isTypeTuple())
+ {
+ // Check for empty tuples
+ if (tu.arguments is null)
+ return 0;
+
+ foreach (nidx; 0 .. tu.arguments.length)
+ {
+ Parameter nextep = (*tu.arguments)[nidx];
+ if (auto r = _foreachImpl(dg, oidx, oparam, eidx, nextep))
+ return r;
+ }
+ }
+ else
+ {
+ if (auto r = dg(oidx, oparam, eidx, eparam))
+ return r;
+ // The only place where we should increment eidx is here,
+ // as a TypeTuple doesn't count as a parameter (for arity)
+ // it it is empty.
+ eidx++;
+ }
+ return 0;
+ }
+
+ override const(char)* toChars() const
+ {
+ return ident ? ident.toChars() : "__anonymous_param";
+ }
+
+ /*********************************
+ * Compute covariance of parameters `this` and `p`
+ * as determined by the storage classes of both.
+ *
+ * Params:
+ * returnByRef = true if the function returns by ref
+ * p = Parameter to compare with
+ * previewIn = Whether `-preview=in` is being used, and thus if
+ * `in` means `scope [ref]`.
+ *
+ * Returns:
+ * true = `this` can be used in place of `p`
+ * false = nope
+ */
+ bool isCovariant(bool returnByRef, const Parameter p, bool previewIn = global.params.previewIn)
+ const pure nothrow @nogc @safe
+ {
+ ulong thisSTC = this.storageClass;
+ ulong otherSTC = p.storageClass;
+
+ if (previewIn)
+ {
+ if (thisSTC & STC.in_)
+ thisSTC |= STC.scope_;
+ if (otherSTC & STC.in_)
+ otherSTC |= STC.scope_;
+ }
+
+ const mask = STC.ref_ | STC.out_ | STC.lazy_ | (previewIn ? STC.in_ : 0);
+ if ((thisSTC & mask) != (otherSTC & mask))
+ return false;
+ return isCovariantScope(returnByRef, thisSTC, otherSTC);
+ }
+
+ extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
+ {
+ if (from == to)
+ return true;
+
+ /* result is true if the 'from' can be used as a 'to'
+ */
+
+ if ((from ^ to) & STC.ref_) // differing in 'ref' means no covariance
+ return false;
+
+ /* workaround until we get STC.returnScope reliably set correctly
+ */
+ if (returnByRef)
+ {
+ from &= ~STC.returnScope;
+ to &= ~STC.returnScope;
+ }
+ else
+ {
+ from |= STC.returnScope;
+ to |= STC.returnScope;
+ }
+ return covariant[buildScopeRef(from)][buildScopeRef(to)];
+ }
+
+ extern (D) private static bool[ScopeRef.max + 1][ScopeRef.max + 1] covariantInit() pure nothrow @nogc @safe
+ {
+ /* Initialize covariant[][] with this:
+
+ From\To n rs s
+ None X
+ ReturnScope X X
+ Scope X X X
+
+ From\To r rr rs rr-s r-rs
+ Ref X X
+ ReturnRef X
+ RefScope X X X X X
+ ReturnRef-Scope X X
+ Ref-ReturnScope X X X
+ */
+ bool[ScopeRef.max + 1][ScopeRef.max + 1] covariant;
+
+ foreach (i; 0 .. ScopeRef.max + 1)
+ {
+ covariant[i][i] = true;
+ covariant[ScopeRef.RefScope][i] = true;
+ }
+ covariant[ScopeRef.ReturnScope][ScopeRef.None] = true;
+ covariant[ScopeRef.Scope ][ScopeRef.None] = true;
+ covariant[ScopeRef.Scope ][ScopeRef.ReturnScope] = true;
+
+ covariant[ScopeRef.Ref ][ScopeRef.ReturnRef] = true;
+ covariant[ScopeRef.ReturnRef_Scope][ScopeRef.ReturnRef] = true;
+ covariant[ScopeRef.Ref_ReturnScope][ScopeRef.Ref ] = true;
+ covariant[ScopeRef.Ref_ReturnScope][ScopeRef.ReturnRef] = true;
+
+ return covariant;
+ }
+
+ extern (D) private static immutable bool[ScopeRef.max + 1][ScopeRef.max + 1] covariant = covariantInit();
+
+ extern (D) bool opEquals(const Parameter other) const
+ {
+ return this.storageClass == other.storageClass
+ && this.type == other.type;
+ }
+}
+
+/*************************************************************
+ * For printing two types with qualification when necessary.
+ * Params:
+ * t1 = The first type to receive the type name for
+ * t2 = The second type to receive the type name for
+ * Returns:
+ * The fully-qualified names of both types if the two type names are not the same,
+ * or the unqualified names of both types if the two type names are the same.
+ */
+const(char*)[2] toAutoQualChars(Type t1, Type t2)
+{
+ auto s1 = t1.toChars();
+ auto s2 = t2.toChars();
+ // show qualification only if it's different
+ if (!t1.equals(t2) && strcmp(s1, s2) == 0)
+ {
+ s1 = t1.toPrettyChars(true);
+ s2 = t2.toPrettyChars(true);
+ }
+ return [s1, s2];
+}
+
+
+/**
+ * For each active modifier (MODFlags.const_, MODFlags.immutable_, etc) call `fp` with a
+ * void* for the work param and a string representation of the attribute.
+ */
+void modifiersApply(const TypeFunction tf, void delegate(string) dg)
+{
+ immutable ubyte[4] modsArr = [MODFlags.const_, MODFlags.immutable_, MODFlags.wild, MODFlags.shared_];
+
+ foreach (modsarr; modsArr)
+ {
+ if (tf.mod & modsarr)
+ {
+ dg(MODtoString(modsarr));
+ }
+ }
+}
+
+/**
+ * For each active attribute (ref/const/nogc/etc) call `fp` with a void* for the
+ * work param and a string representation of the attribute.
+ */
+void attributesApply(const TypeFunction tf, void delegate(string) dg, TRUSTformat trustFormat = TRUSTformatDefault)
+{
+ if (tf.purity)
+ dg("pure");
+ if (tf.isnothrow)
+ dg("nothrow");
+ if (tf.isnogc)
+ dg("@nogc");
+ if (tf.isproperty)
+ dg("@property");
+ if (tf.isref)
+ dg("ref");
+ if (tf.isreturn && !tf.isreturninferred)
+ dg("return");
+ if (tf.isScopeQual && !tf.isscopeinferred)
+ dg("scope");
+ if (tf.islive)
+ dg("@live");
+
+ TRUST trustAttrib = tf.trust;
+
+ if (trustAttrib == TRUST.default_)
+ {
+ if (trustFormat == TRUSTformatSystem)
+ trustAttrib = TRUST.system;
+ else
+ return; // avoid calling with an empty string
+ }
+
+ dg(trustToString(trustAttrib));
+}
+
+/**
+ * If the type is a class or struct, returns the symbol for it,
+ * else null.
+ */
+extern (C++) AggregateDeclaration isAggregate(Type t)
+{
+ t = t.toBasetype();
+ if (t.ty == Tclass)
+ return (cast(TypeClass)t).sym;
+ if (t.ty == Tstruct)
+ return (cast(TypeStruct)t).sym;
+ return null;
+}
+
+/***************************************************
+ * Determine if type t can be indexed or sliced given that it is not an
+ * aggregate with operator overloads.
+ * Params:
+ * t = type to check
+ * Returns:
+ * true if an expression of type t can be e1 in an array expression
+ */
+bool isIndexableNonAggregate(Type t)
+{
+ t = t.toBasetype();
+ return (t.ty == Tpointer || t.ty == Tsarray || t.ty == Tarray || t.ty == Taarray ||
+ t.ty == Ttuple || t.ty == Tvector);
+}
+
+/***************************************************
+ * Determine if type t is copyable.
+ * Params:
+ * t = type to check
+ * Returns:
+ * true if we can copy it
+ */
+bool isCopyable(Type t)
+{
+ //printf("isCopyable() %s\n", t.toChars());
+ if (auto ts = t.isTypeStruct())
+ {
+ if (ts.sym.postblit &&
+ ts.sym.postblit.storage_class & STC.disable)
+ return false;
+ if (ts.sym.hasCopyCtor)
+ {
+ // check if there is a matching overload of the copy constructor and whether it is disabled or not
+ // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575
+ Dsymbol ctor = search_function(ts.sym, Id.ctor);
+ assert(ctor);
+ scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue
+ el.type = cast() ts;
+ Expressions args;
+ args.push(el);
+ FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, &args, FuncResolveFlag.quiet);
+ if (!f || f.storage_class & STC.disable)
+ return false;
+ }
+ }
+ return true;
+}
+
+/***************************************
+ * Computes how a parameter may be returned.
+ * Shrinking the representation is necessary because StorageClass is so wide
+ * Params:
+ * stc = storage class of parameter
+ * Returns:
+ * value from enum ScopeRef
+ */
+ScopeRef buildScopeRef(StorageClass stc) pure nothrow @nogc @safe
+{
+ if (stc & STC.out_)
+ stc |= STC.ref_; // treat `out` and `ref` the same
+
+ ScopeRef result;
+ final switch (stc & (STC.ref_ | STC.scope_ | STC.return_))
+ {
+ case 0: result = ScopeRef.None; break;
+
+ /* can occur in case test/compilable/testsctreturn.d
+ * related to https://issues.dlang.org/show_bug.cgi?id=20149
+ * where inout adds `return` without `scope` or `ref`
+ */
+ case STC.return_: result = ScopeRef.Return; break;
+
+ case STC.ref_: result = ScopeRef.Ref; break;
+ case STC.scope_: result = ScopeRef.Scope; break;
+ case STC.return_ | STC.ref_: result = ScopeRef.ReturnRef; break;
+ case STC.return_ | STC.scope_: result = ScopeRef.ReturnScope; break;
+ case STC.ref_ | STC.scope_: result = ScopeRef.RefScope; break;
+
+ case STC.return_ | STC.ref_ | STC.scope_:
+ result = stc & STC.returnScope ? ScopeRef.Ref_ReturnScope
+ : ScopeRef.ReturnRef_Scope;
+ break;
+ }
+ return result;
+}
+
+/**
+ * Classification of 'scope-return-ref' possibilities
+ */
+enum ScopeRef
+{
+ None,
+ Scope,
+ ReturnScope,
+ Ref,
+ ReturnRef,
+ RefScope,
+ ReturnRef_Scope,
+ Ref_ReturnScope,
+ Return,
+}
+
+/*********************************
+ * Give us a nice string for debugging purposes.
+ * Params:
+ * sr = value
+ * Returns:
+ * corresponding string
+ */
+const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe
+{
+ with (ScopeRef)
+ {
+ static immutable char*[ScopeRef.max + 1] names =
+ [
+ None: "None",
+ Scope: "Scope",
+ ReturnScope: "ReturnScope",
+ Ref: "Ref",
+ ReturnRef: "ReturnRef",
+ RefScope: "RefScope",
+ ReturnRef_Scope: "ReturnRef_Scope",
+ Ref_ReturnScope: "Ref_ReturnScope",
+ Return: "Return",
+ ];
+ return names[sr];
+ }
+}
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index 3687053..cdf221f 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -10,15 +10,15 @@
#pragma once
-#include "root/root.h"
-#include "root/stringtable.h"
+#include "root/dcompat.h" // for d_size_t
#include "arraytypes.h"
#include "ast_node.h"
-#include "expression.h"
+#include "globals.h"
#include "visitor.h"
struct Scope;
+class AggregateDeclaration;
class Identifier;
class Expression;
class StructDeclaration;
@@ -28,7 +28,6 @@ class TypeInfoDeclaration;
class Dsymbol;
class TemplateInstance;
class TemplateDeclaration;
-enum LINK;
class TypeBasic;
class Parameter;
@@ -40,12 +39,12 @@ typedef union tree_node type;
typedef struct TYPE type;
#endif
-Type *typeSemantic(Type *type, const Loc &loc, Scope *sc);
void semanticTypeInfo(Scope *sc, Type *t);
-MATCH deduceType(RootObject *o, Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wm = NULL, size_t inferStart = 0);
-StorageClass ModToStc(unsigned mod);
-enum ENUMTY
+Type *typeSemantic(Type *t, const Loc &loc, Scope *sc);
+Type *merge(Type *type);
+
+enum class TY : uint8_t
{
Tarray, // slice array, aka T[]
Tsarray, // static array, aka T[dimension]
@@ -100,7 +99,6 @@ enum ENUMTY
Tnoreturn,
TMAX
};
-typedef unsigned char TY; // ENUMTY
#define SIZE_INVALID (~(d_uns64)0) // error return from size() functions
@@ -120,22 +118,22 @@ enum MODFlags
};
typedef unsigned char MOD;
-// These tables are for implicit conversion of binary ops;
-// the indices are the type of operand one, followed by operand two.
-extern unsigned char impcnvResult[TMAX][TMAX];
-extern unsigned char impcnvType1[TMAX][TMAX];
-extern unsigned char impcnvType2[TMAX][TMAX];
-
-// If !=0, give warning on implicit conversion
-extern unsigned char impcnvWarn[TMAX][TMAX];
+enum class Covariant
+{
+ distinct = 0,
+ yes = 1,
+ no = 2,
+ fwdref = 3,
+};
-enum VarArg
+enum VarArgValues
{
VARARGnone = 0, /// fixed number of arguments
VARARGvariadic = 1, /// T t, ...) can be C-style (core.stdc.stdarg) or D-style (core.vararg)
VARARGtypesafe = 2 /// T t ...) typesafe https://dlang.org/spec/function.html#typesafe_variadic_functions
/// or https://dlang.org/spec/function.html#typesafe_variadic_functions
};
+typedef unsigned char VarArg;
class Type : public ASTNode
{
@@ -144,22 +142,10 @@ public:
MOD mod; // modifiers MODxxxx
char *deco;
- /* These are cached values that are lazily evaluated by constOf(), immutableOf(), etc.
- * They should not be referenced by anybody but mtype.c.
- * They can be NULL if not lazily evaluated yet.
- * Note that there is no "shared immutable", because that is just immutable
- * Naked == no MOD bits
- */
-
- Type *cto; // MODconst ? naked version of this type : const version
- Type *ito; // MODimmutable ? naked version of this type : immutable version
- Type *sto; // MODshared ? naked version of this type : shared mutable version
- Type *scto; // MODshared | MODconst ? naked version of this type : shared const version
- Type *wto; // MODwild ? naked version of this type : wild version
- Type *wcto; // MODwildconst ? naked version of this type : wild const version
- Type *swto; // MODshared | MODwild ? naked version of this type : shared wild version
- Type *swcto; // MODshared | MODwildconst ? naked version of this type : shared wild const version
+private:
+ void* mcache;
+public:
Type *pto; // merged pointer to this type
Type *rto; // reference to this type
Type *arrayof; // array of this type
@@ -229,35 +215,27 @@ public:
static TemplateDeclaration *rtinfo;
- static Type *basic[TMAX];
- static unsigned char sizeTy[TMAX];
- static StringTable stringtable;
+ static Type *basic[(int)TY::TMAX];
- Type(TY ty);
virtual const char *kind();
- Type *copy();
+ Type *copy() const;
virtual Type *syntaxCopy();
- bool equals(RootObject *o);
+ bool equals(const RootObject *o) const;
bool equivalent(Type *t);
// kludge for template.isType()
- int dyncast() const { return DYNCAST_TYPE; }
- int covariant(Type *t, StorageClass *pstc = NULL, bool fix17349 = true);
- const char *toChars();
+ DYNCAST dyncast() const { return DYNCAST_TYPE; }
+ Covariant covariant(Type *t, StorageClass *pstc = NULL);
+ const char *toChars() const;
char *toPrettyChars(bool QualifyTypes = false);
static void _init();
d_uns64 size();
- virtual d_uns64 size(Loc loc);
+ virtual d_uns64 size(const Loc &loc);
virtual unsigned alignsize();
- Type *trySemantic(Loc loc, Scope *sc);
- Type *merge();
+ Type *trySemantic(const Loc &loc, Scope *sc);
Type *merge2();
- void modToBuffer(OutBuffer *buf);
- char *modToChars();
-
- /** For each active modifier (MODconst, MODimmutable, etc) call fp with a
- void* for the work param and a string representation of the attribute. */
- int modifiersApply(void *param, int (*fp)(void *, const char *));
+ void modToBuffer(OutBuffer *buf) const;
+ char *modToChars() const;
virtual bool isintegral();
virtual bool isfloating(); // real, imaginary, or complex
@@ -270,7 +248,7 @@ public:
virtual bool isString();
virtual bool isAssignable();
virtual bool isBoolean();
- virtual void checkDeprecated(Loc loc, Scope *sc);
+ virtual void checkDeprecated(const Loc &loc, Scope *sc);
bool isConst() const { return (mod & MODconst) != 0; }
bool isImmutable() const { return (mod & MODimmutable) != 0; }
bool isMutable() const { return (mod & (MODconst | MODimmutable | MODwild)) == 0; }
@@ -280,7 +258,7 @@ public:
bool isWildConst() const { return (mod & MODwildconst) == MODwildconst; }
bool isSharedWild() const { return (mod & (MODshared | MODwild)) == (MODshared | MODwild); }
bool isNaked() const { return mod == 0; }
- Type *nullAttributes();
+ Type *nullAttributes() const;
Type *constOf();
Type *immutableOf();
Type *mutableOf();
@@ -301,8 +279,8 @@ public:
Type *referenceTo();
Type *arrayOf();
Type *sarrayOf(dinteger_t dim);
+ bool hasDeprecatedAliasThis();
Type *aliasthisOf();
- bool checkAliasThisRec();
virtual Type *makeConst();
virtual Type *makeImmutable();
virtual Type *makeShared();
@@ -313,7 +291,7 @@ public:
virtual Type *makeSharedWildConst();
virtual Type *makeMutable();
virtual Dsymbol *toDsymbol(Scope *sc);
- virtual Type *toBasetype();
+ Type *toBasetype();
virtual bool isBaseOf(Type *t, int *poffset);
virtual MATCH implicitConvTo(Type *to);
virtual MATCH constConv(Type *to);
@@ -324,33 +302,27 @@ public:
virtual Type *toHeadMutable();
virtual ClassDeclaration *isClassHandle();
- virtual Expression *getProperty(Loc loc, Identifier *ident, int flag);
- virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
virtual structalign_t alignment();
- Expression *noMember(Scope *sc, Expression *e, Identifier *ident, int flag);
- virtual Expression *defaultInit(Loc loc = Loc());
- virtual Expression *defaultInitLiteral(Loc loc);
- virtual bool isZeroInit(Loc loc = Loc()); // if initializer is 0
+ virtual Expression *defaultInitLiteral(const Loc &loc);
+ virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0
Identifier *getTypeInfoIdent();
- virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
- void resolveExp(Expression *e, Type **pt, Expression **pe, Dsymbol **ps);
virtual int hasWild() const;
virtual bool hasPointers();
virtual bool hasVoidInitPointers();
+ virtual bool hasInvariant();
virtual Type *nextOf();
Type *baseElemOf();
uinteger_t sizemask();
- unsigned numberOfElems(const Loc &loc);
virtual bool needsDestruction();
+ virtual bool needsCopyOrPostblit();
virtual bool needsNested();
- void checkComplexTransition(Loc loc);
- TypeFunction *toTypeFunction();
- static void error(Loc loc, const char *format, ...);
- static void warning(Loc loc, const char *format, ...);
+ TypeFunction *toTypeFunction();
// For eliminating dynamic_cast
virtual TypeBasic *isTypeBasic();
+ TypeFunction *isPtrToFunction();
+ TypeFunction *isFunction_Delegate_PtrToFunction();
TypeError *isTypeError();
TypeVector *isTypeVector();
TypeSArray *isTypeSArray();
@@ -373,6 +345,7 @@ public:
TypeMixin *isTypeMixin();
TypeTraits *isTypeTraits();
TypeNoreturn *isTypeNoreturn();
+ TypeTag *isTypeTag();
void accept(Visitor *v) { v->visit(this); }
};
@@ -380,14 +353,11 @@ public:
class TypeError : public Type
{
public:
- TypeError();
- Type *syntaxCopy();
-
- d_uns64 size(Loc loc);
- Expression *getProperty(Loc loc, Identifier *ident, int flag);
- Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
- Expression *defaultInit(Loc loc);
- Expression *defaultInitLiteral(Loc loc);
+ const char *kind();
+ TypeError *syntaxCopy();
+
+ d_uns64 size(const Loc &loc);
+ Expression *defaultInitLiteral(const Loc &loc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -396,8 +366,7 @@ class TypeNext : public Type
public:
Type *next;
- TypeNext(TY ty, Type *next);
- void checkDeprecated(Loc loc, Scope *sc);
+ void checkDeprecated(const Loc &loc, Scope *sc);
int hasWild() const;
Type *nextOf();
Type *makeConst();
@@ -421,13 +390,10 @@ public:
const char *dstring;
unsigned flags;
- TypeBasic(TY ty);
const char *kind();
- Type *syntaxCopy();
- d_uns64 size(Loc loc) /*const*/;
+ TypeBasic *syntaxCopy();
+ d_uns64 size(const Loc &loc) /*const*/;
unsigned alignsize();
- Expression *getProperty(Loc loc, Identifier *ident, int flag);
- Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
bool isintegral();
bool isfloating() /*const*/;
bool isreal() /*const*/;
@@ -436,8 +402,7 @@ public:
bool isscalar() /*const*/;
bool isunsigned() /*const*/;
MATCH implicitConvTo(Type *to);
- Expression *defaultInit(Loc loc);
- bool isZeroInit(Loc loc) /*const*/;
+ bool isZeroInit(const Loc &loc) /*const*/;
// For eliminating dynamic_cast
TypeBasic *isTypeBasic();
@@ -449,24 +414,20 @@ class TypeVector : public Type
public:
Type *basetype;
- TypeVector(Type *basetype);
static TypeVector *create(Type *basetype);
const char *kind();
- Type *syntaxCopy();
- d_uns64 size(Loc loc);
+ TypeVector *syntaxCopy();
+ d_uns64 size(const Loc &loc);
unsigned alignsize();
- Expression *getProperty(Loc loc, Identifier *ident, int flag);
- Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
bool isintegral();
bool isfloating();
bool isscalar();
bool isunsigned();
bool isBoolean() /*const*/;
MATCH implicitConvTo(Type *to);
- Expression *defaultInit(Loc loc);
- Expression *defaultInitLiteral(Loc loc);
+ Expression *defaultInitLiteral(const Loc &loc);
TypeBasic *elementType();
- bool isZeroInit(Loc loc);
+ bool isZeroInit(const Loc &loc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -474,8 +435,6 @@ public:
class TypeArray : public TypeNext
{
public:
- TypeArray(TY ty, Type *next);
- Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
void accept(Visitor *v) { v->visit(this); }
};
@@ -485,22 +444,20 @@ class TypeSArray : public TypeArray
public:
Expression *dim;
- TypeSArray(Type *t, Expression *dim);
const char *kind();
- Type *syntaxCopy();
- d_uns64 size(Loc loc);
+ TypeSArray *syntaxCopy();
+ d_uns64 size(const Loc &loc);
unsigned alignsize();
- void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
- Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
bool isString();
- bool isZeroInit(Loc loc);
+ bool isZeroInit(const Loc &loc);
structalign_t alignment();
MATCH constConv(Type *to);
MATCH implicitConvTo(Type *to);
- Expression *defaultInit(Loc loc);
- Expression *defaultInitLiteral(Loc loc);
+ Expression *defaultInitLiteral(const Loc &loc);
bool hasPointers();
+ bool hasInvariant();
bool needsDestruction();
+ bool needsCopyOrPostblit();
bool needsNested();
void accept(Visitor *v) { v->visit(this); }
@@ -510,18 +467,14 @@ public:
class TypeDArray : public TypeArray
{
public:
- TypeDArray(Type *t);
const char *kind();
- Type *syntaxCopy();
- d_uns64 size(Loc loc) /*const*/;
+ TypeDArray *syntaxCopy();
+ d_uns64 size(const Loc &loc) /*const*/;
unsigned alignsize() /*const*/;
- void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
- Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
bool isString();
- bool isZeroInit(Loc loc) /*const*/;
+ bool isZeroInit(const Loc &loc) /*const*/;
bool isBoolean() /*const*/;
MATCH implicitConvTo(Type *to);
- Expression *defaultInit(Loc loc);
bool hasPointers() /*const*/;
void accept(Visitor *v) { v->visit(this); }
@@ -532,17 +485,12 @@ class TypeAArray : public TypeArray
public:
Type *index; // key type
Loc loc;
- Scope *sc;
- TypeAArray(Type *t, Type *index);
static TypeAArray *create(Type *t, Type *index);
const char *kind();
- Type *syntaxCopy();
- d_uns64 size(Loc loc);
- void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
- Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
- Expression *defaultInit(Loc loc);
- bool isZeroInit(Loc loc) /*const*/;
+ TypeAArray *syntaxCopy();
+ d_uns64 size(const Loc &loc);
+ bool isZeroInit(const Loc &loc) /*const*/;
bool isBoolean() /*const*/;
bool hasPointers() /*const*/;
MATCH implicitConvTo(Type *to);
@@ -554,16 +502,14 @@ public:
class TypePointer : public TypeNext
{
public:
- TypePointer(Type *t);
static TypePointer *create(Type *t);
const char *kind();
- Type *syntaxCopy();
- d_uns64 size(Loc loc) /*const*/;
+ TypePointer *syntaxCopy();
+ d_uns64 size(const Loc &loc) /*const*/;
MATCH implicitConvTo(Type *to);
MATCH constConv(Type *to);
bool isscalar() /*const*/;
- Expression *defaultInit(Loc loc);
- bool isZeroInit(Loc loc) /*const*/;
+ bool isZeroInit(const Loc &loc) /*const*/;
bool hasPointers() /*const*/;
void accept(Visitor *v) { v->visit(this); }
@@ -572,13 +518,10 @@ public:
class TypeReference : public TypeNext
{
public:
- TypeReference(Type *t);
const char *kind();
- Type *syntaxCopy();
- d_uns64 size(Loc loc) /*const*/;
- Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
- Expression *defaultInit(Loc loc);
- bool isZeroInit(Loc loc) /*const*/;
+ TypeReference *syntaxCopy();
+ d_uns64 size(const Loc &loc) /*const*/;
+ bool isZeroInit(const Loc &loc) /*const*/;
void accept(Visitor *v) { v->visit(this); }
};
@@ -588,31 +531,27 @@ enum RET
RETstack = 2 // returned on stack
};
-enum TRUST
+enum class TRUST : unsigned char
{
- TRUSTdefault = 0,
- TRUSTsystem = 1, // @system (same as TRUSTdefault)
- TRUSTtrusted = 2, // @trusted
- TRUSTsafe = 3 // @safe
+ default_ = 0,
+ system = 1, // @system (same as TRUSTdefault)
+ trusted = 2, // @trusted
+ safe = 3 // @safe
};
-// in hdrgen.c
-void trustToBuffer(OutBuffer *buf, TRUST trust);
-const char *trustToChars(TRUST trust);
-
enum TRUSTformat
{
TRUSTformatDefault, // do not emit @system when trust == TRUSTdefault
TRUSTformatSystem // emit @system when trust == TRUSTdefault
};
-enum PURE
+enum class PURE : unsigned char
{
- PUREimpure = 0, // not pure at all
- PUREfwdref = 1, // it's pure, but not known which level yet
- PUREweak = 2, // no mutable globals are read or written
- PUREconst = 3, // parameters are values or const
- PUREstrong = 4 // parameters are values or immutable
+ impure = 0, // not pure at all
+ fwdref = 1, // it's pure, but not known which level yet
+ weak = 2, // no mutable globals are read or written
+ const_ = 3, // parameters are values or const
+ strong = 4 // parameters are values or immutable
};
class Parameter : public ASTNode
@@ -624,31 +563,26 @@ public:
Expression *defaultArg;
UserAttributeDeclaration *userAttribDecl; // user defined attributes
- Parameter(StorageClass storageClass, Type *type, Identifier *ident,
- Expression *defaultArg, UserAttributeDeclaration *userAttribDecl);
static Parameter *create(StorageClass storageClass, Type *type, Identifier *ident,
Expression *defaultArg, UserAttributeDeclaration *userAttribDecl);
Parameter *syntaxCopy();
Type *isLazyArray();
// kludge for template.isType()
- int dyncast() const { return DYNCAST_PARAMETER; }
+ DYNCAST dyncast() const { return DYNCAST_PARAMETER; }
void accept(Visitor *v) { v->visit(this); }
- static Parameters *arraySyntaxCopy(Parameters *parameters);
static size_t dim(Parameters *parameters);
- static Parameter *getNth(Parameters *parameters, size_t nth, size_t *pn = NULL);
- const char *toChars();
- bool isCovariant(bool returnByRef, const Parameter *p) const;
- static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to);
+ static Parameter *getNth(Parameters *parameters, d_size_t nth);
+ const char *toChars() const;
+ bool isCovariant(bool returnByRef, const Parameter *p, bool previewIn) const;
};
struct ParameterList
{
- Parameters *parameters;
+ Parameters* parameters;
+ StorageClass stc;
VarArg varargs;
- ParameterList(Parameters *parameters = NULL, VarArg varargs = VARARGnone);
-
size_t length();
Parameter *operator[](size_t i) { return Parameter::getNth(parameters, i); }
};
@@ -658,27 +592,17 @@ class TypeFunction : public TypeNext
public:
// .next is the return type
- ParameterList parameterList; // function parameters
-
- bool isnothrow; // true: nothrow
- bool isnogc; // true: is @nogc
- bool isproperty; // can be called without parentheses
- bool isref; // true: returns a reference
- bool isreturn; // true: 'this' is returned by ref
- bool isscope; // true: 'this' is scope
- bool isscopeinferred; // true: 'this' is scope from inference
- LINK linkage; // calling convention
- TRUST trust; // level of trust
- PURE purity; // PURExxxx
- unsigned char iswild; // bit0: inout on params, bit1: inout on qualifier
- Expressions *fargs; // function arguments
+ ParameterList parameterList; // function parameters
+ LINK linkage; // calling convention
+ unsigned funcFlags;
+ TRUST trust; // level of trust
+ PURE purity; // PURExxxx
+ char inuse;
+ Expressions *fargs; // function arguments
- int inuse;
-
- TypeFunction(const ParameterList &pl, Type *treturn, LINK linkage, StorageClass stc = 0);
static TypeFunction *create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc = 0);
const char *kind();
- Type *syntaxCopy();
+ TypeFunction *syntaxCopy();
void purityLevel();
bool hasLazyParameters();
bool isDstyleVariadic() const;
@@ -686,15 +610,35 @@ public:
StorageClass parameterStorageClass(Parameter *p);
Type *addStorageClass(StorageClass stc);
- /** For each active attribute (ref/const/nogc/etc) call fp with a void* for the
- work param and a string representation of the attribute. */
- int attributesApply(void *param, int (*fp)(void *, const char *), TRUSTformat trustFormat = TRUSTformatDefault);
-
Type *substWildTo(unsigned mod);
- MATCH callMatch(Type *tthis, Expressions *toargs, int flag = 0, const char **pMessage = NULL);
- bool checkRetType(Loc loc);
+ MATCH constConv(Type *to);
+
+ bool isnothrow() const;
+ void isnothrow(bool v);
+ bool isnogc() const;
+ void isnogc(bool v);
+ bool isproperty() const;
+ void isproperty(bool v);
+ bool isref() const;
+ void isref(bool v);
+ bool isreturn() const;
+ void isreturn(bool v);
+ bool isScopeQual() const;
+ void isScopeQual(bool v);
+ bool isreturninferred() const;
+ void isreturninferred(bool v);
+ bool isscopeinferred() const;
+ void isscopeinferred(bool v);
+ bool islive() const;
+ void islive(bool v);
+ bool incomplete() const;
+ void incomplete(bool v);
+ bool isInOutParam() const;
+ void isInOutParam(bool v);
+ bool isInOutQual() const;
+ void isInOutQual(bool v);
+ bool iswild() const;
- Expression *defaultInit(Loc loc) /*const*/;
void accept(Visitor *v) { v->visit(this); }
};
@@ -703,18 +647,15 @@ class TypeDelegate : public TypeNext
public:
// .next is a TypeFunction
- TypeDelegate(Type *t);
- static TypeDelegate *create(Type *t);
+ static TypeDelegate *create(TypeFunction *t);
const char *kind();
- Type *syntaxCopy();
+ TypeDelegate *syntaxCopy();
Type *addStorageClass(StorageClass stc);
- d_uns64 size(Loc loc) /*const*/;
+ d_uns64 size(const Loc &loc) /*const*/;
unsigned alignsize() /*const*/;
MATCH implicitConvTo(Type *to);
- Expression *defaultInit(Loc loc);
- bool isZeroInit(Loc loc) /*const*/;
+ bool isZeroInit(const Loc &loc) /*const*/;
bool isBoolean() /*const*/;
- Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
bool hasPointers() /*const*/;
void accept(Visitor *v) { v->visit(this); }
@@ -722,33 +663,28 @@ public:
class TypeTraits : public Type
{
-public:
Loc loc;
/// The expression to resolve as type or symbol.
TraitsExp *exp;
/// The symbol when exp doesn't represent a type.
Dsymbol *sym;
- TypeTraits(const Loc &loc, TraitsExp *exp);
- Type *syntaxCopy();
+ const char *kind();
+ TypeTraits *syntaxCopy();
+ d_uns64 size(const Loc &loc);
Dsymbol *toDsymbol(Scope *sc);
- void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
- d_uns64 size(Loc loc);
void accept(Visitor *v) { v->visit(this); }
};
class TypeMixin : public Type
{
-public:
Loc loc;
Expressions *exps;
RootObject *obj;
- TypeMixin(const Loc &loc, Expressions *exps);
const char *kind();
- Type *syntaxCopy();
+ TypeMixin *syntaxCopy();
Dsymbol *toDsymbol(Scope *sc);
- void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
void accept(Visitor *v) { v->visit(this); }
};
@@ -760,17 +696,11 @@ public:
// representing ident.ident!tiargs.ident. ... etc.
Objects idents;
- TypeQualified(TY ty, Loc loc);
void syntaxCopyHelper(TypeQualified *t);
void addIdent(Identifier *ident);
void addInst(TemplateInstance *inst);
void addIndex(RootObject *expr);
- d_uns64 size(Loc loc);
-
- void resolveTupleIndex(Loc loc, Scope *sc, Dsymbol *s,
- Expression **pe, Type **pt, Dsymbol **ps, RootObject *oindex);
- void resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym,
- Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ d_uns64 size(const Loc &loc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -781,10 +711,8 @@ public:
Identifier *ident;
Dsymbol *originalSymbol; // The symbol representing this identifier, before alias resolution
- TypeIdentifier(Loc loc, Identifier *ident);
const char *kind();
- Type *syntaxCopy();
- void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ TypeIdentifier *syntaxCopy();
Dsymbol *toDsymbol(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -796,10 +724,8 @@ class TypeInstance : public TypeQualified
public:
TemplateInstance *tempinst;
- TypeInstance(Loc loc, TemplateInstance *tempinst);
const char *kind();
- Type *syntaxCopy();
- void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ TypeInstance *syntaxCopy();
Dsymbol *toDsymbol(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -810,23 +736,19 @@ public:
Expression *exp;
int inuse;
- TypeTypeof(Loc loc, Expression *exp);
const char *kind();
- Type *syntaxCopy();
+ TypeTypeof *syntaxCopy();
Dsymbol *toDsymbol(Scope *sc);
- void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
- d_uns64 size(Loc loc);
+ d_uns64 size(const Loc &loc);
void accept(Visitor *v) { v->visit(this); }
};
class TypeReturn : public TypeQualified
{
public:
- TypeReturn(Loc loc);
const char *kind();
- Type *syntaxCopy();
+ TypeReturn *syntaxCopy();
Dsymbol *toDsymbol(Scope *sc);
- void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
void accept(Visitor *v) { v->visit(this); }
};
@@ -847,26 +769,25 @@ class TypeStruct : public Type
public:
StructDeclaration *sym;
AliasThisRec att;
- CPPMANGLE cppmangle;
+ bool inuse;
- TypeStruct(StructDeclaration *sym);
static TypeStruct *create(StructDeclaration *sym);
const char *kind();
- d_uns64 size(Loc loc);
+ d_uns64 size(const Loc &loc);
unsigned alignsize();
- Type *syntaxCopy();
+ TypeStruct *syntaxCopy();
Dsymbol *toDsymbol(Scope *sc);
- Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
structalign_t alignment();
- Expression *defaultInit(Loc loc);
- Expression *defaultInitLiteral(Loc loc);
- bool isZeroInit(Loc loc) /*const*/;
+ Expression *defaultInitLiteral(const Loc &loc);
+ bool isZeroInit(const Loc &loc);
bool isAssignable();
bool isBoolean() /*const*/;
bool needsDestruction() /*const*/;
+ bool needsCopyOrPostblit();
bool needsNested();
bool hasPointers();
bool hasVoidInitPointers();
+ bool hasInvariant();
MATCH implicitConvTo(Type *to);
MATCH constConv(Type *to);
unsigned char deduceWild(Type *t, bool isRef);
@@ -880,14 +801,12 @@ class TypeEnum : public Type
public:
EnumDeclaration *sym;
- TypeEnum(EnumDeclaration *sym);
const char *kind();
- Type *syntaxCopy();
- d_uns64 size(Loc loc);
+ TypeEnum *syntaxCopy();
+ d_uns64 size(const Loc &loc);
unsigned alignsize();
+ Type *memType(const Loc &loc = Loc());
Dsymbol *toDsymbol(Scope *sc);
- Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
- Expression *getProperty(Loc loc, Identifier *ident, int flag);
bool isintegral();
bool isfloating();
bool isreal();
@@ -899,14 +818,14 @@ public:
bool isString();
bool isAssignable();
bool needsDestruction();
+ bool needsCopyOrPostblit();
bool needsNested();
MATCH implicitConvTo(Type *to);
MATCH constConv(Type *to);
- Type *toBasetype();
- Expression *defaultInit(Loc loc);
- bool isZeroInit(Loc loc);
+ bool isZeroInit(const Loc &loc);
bool hasPointers();
bool hasVoidInitPointers();
+ bool hasInvariant();
Type *nextOf();
void accept(Visitor *v) { v->visit(this); }
@@ -919,20 +838,17 @@ public:
AliasThisRec att;
CPPMANGLE cppmangle;
- TypeClass(ClassDeclaration *sym);
const char *kind();
- d_uns64 size(Loc loc) /*const*/;
- Type *syntaxCopy();
+ d_uns64 size(const Loc &loc) /*const*/;
+ TypeClass *syntaxCopy();
Dsymbol *toDsymbol(Scope *sc);
- Expression *dotExp(Scope *sc, Expression *e, Identifier *ident, int flag);
ClassDeclaration *isClassHandle();
bool isBaseOf(Type *t, int *poffset);
MATCH implicitConvTo(Type *to);
MATCH constConv(Type *to);
unsigned char deduceWild(Type *t, bool isRef);
Type *toHeadMutable();
- Expression *defaultInit(Loc loc);
- bool isZeroInit(Loc loc) /*const*/;
+ bool isZeroInit(const Loc &loc) /*const*/;
bool isscope() /*const*/;
bool isBoolean() /*const*/;
bool hasPointers() /*const*/;
@@ -943,19 +859,18 @@ public:
class TypeTuple : public Type
{
public:
+ // 'logically immutable' cached global - don't modify (neither pointer nor pointee)!
+ static TypeTuple *empty;
+
Parameters *arguments; // types making up the tuple
- TypeTuple(Parameters *arguments);
- TypeTuple(Expressions *exps);
static TypeTuple *create(Parameters *arguments);
- TypeTuple();
- TypeTuple(Type *t1);
- TypeTuple(Type *t1, Type *t2);
+ static TypeTuple *create();
+ static TypeTuple *create(Type *t1);
+ static TypeTuple *create(Type *t1, Type *t2);
const char *kind();
- Type *syntaxCopy();
- bool equals(RootObject *o);
- Expression *getProperty(Loc loc, Identifier *ident, int flag);
- Expression *defaultInit(Loc loc);
+ TypeTuple *syntaxCopy();
+ bool equals(const RootObject *o) const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -965,44 +880,49 @@ public:
Expression *lwr;
Expression *upr;
- TypeSlice(Type *next, Expression *lwr, Expression *upr);
const char *kind();
- Type *syntaxCopy();
- void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+ TypeSlice *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class TypeNull : public Type
{
public:
- TypeNull();
const char *kind();
- Type *syntaxCopy();
+ TypeNull *syntaxCopy();
MATCH implicitConvTo(Type *to);
bool isBoolean() /*const*/;
- d_uns64 size(Loc loc) /*const*/;
- Expression *defaultInit(Loc loc) /*const*/;
+ d_uns64 size(const Loc &loc) /*const*/;
void accept(Visitor *v) { v->visit(this); }
};
-class TypeNoreturn : public Type
+class TypeNoreturn final : public Type
{
public:
- TypeNoreturn();
const char *kind();
+ TypeNoreturn *syntaxCopy();
+ MATCH implicitConvTo(Type* to);
+ MATCH constConv(Type* to);
+ bool isBoolean() /* const */;
+ d_uns64 size(const Loc& loc) /* const */;
+ unsigned alignsize();
- Type *syntaxCopy();
- MATCH implicitConvTo(Type *to);
- bool isBoolean() /*const*/;
+ void accept(Visitor *v) { v->visit(this); }
+};
+
+class TypeTag final : public Type
+{
+public:
+ TypeTag *syntaxCopy();
- d_uns64 size(Loc loc) /*const*/;
- unsigned alignsize();
void accept(Visitor *v) { v->visit(this); }
};
/**************************************************************/
-bool arrayTypeCompatible(Loc loc, Type *t1, Type *t2);
bool arrayTypeCompatibleWithoutCasting(Type *t1, Type *t2);
+
+// If the type is a class or struct, returns the symbol for it, else null.
+AggregateDeclaration *isAggregate(Type *t);
diff --git a/gcc/d/dmd/nogc.c b/gcc/d/dmd/nogc.c
deleted file mode 100644
index 12c8b49..0000000
--- a/gcc/d/dmd/nogc.c
+++ /dev/null
@@ -1,241 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/nogc.c
- */
-
-#include "mars.h"
-#include "init.h"
-#include "visitor.h"
-#include "expression.h"
-#include "statement.h"
-#include "declaration.h"
-#include "id.h"
-#include "module.h"
-#include "scope.h"
-#include "tokens.h"
-#include "aggregate.h"
-
-bool walkPostorder(Expression *e, StoppableVisitor *v);
-
-void FuncDeclaration::printGCUsage(Loc loc, const char* warn)
-{
- if (!global.params.vgc)
- return;
-
- Module *m = getModule();
- if (m && m->isRoot() && !inUnittest())
- {
- message(loc, "vgc: %s", warn);
- }
-}
-
-/**************************************
- * Look for GC-allocations
- */
-class NOGCVisitor : public StoppableVisitor
-{
-public:
- FuncDeclaration *f;
- bool err;
-
- NOGCVisitor(FuncDeclaration *f)
- {
- this->f = f;
- this->err = false;
- }
-
- void doCond(Expression *exp)
- {
- if (exp)
- walkPostorder(exp, this);
- }
-
- void visit(Expression *)
- {
- }
-
- void visit(DeclarationExp *e)
- {
- // Note that, walkPostorder does not support DeclarationExp today.
- VarDeclaration *v = e->declaration->isVarDeclaration();
- if (v && !(v->storage_class & STCmanifest) && !v->isDataseg() && v->_init)
- {
- if (ExpInitializer *ei = v->_init->isExpInitializer())
- {
- doCond(ei->exp);
- }
- }
- }
-
- void visit(CallExp *)
- {
- }
-
- void visit(ArrayLiteralExp *e)
- {
- if (e->type->ty != Tarray || !e->elements || !e->elements->length)
- return;
-
- if (f->setGC())
- {
- e->error("array literal in @nogc %s `%s` may cause GC allocation",
- f->kind(), f->toPrettyChars());
- err = true;
- return;
- }
- f->printGCUsage(e->loc, "array literal may cause GC allocation");
- }
-
- void visit(AssocArrayLiteralExp *e)
- {
- if (!e->keys->length)
- return;
-
- if (f->setGC())
- {
- e->error("associative array literal in @nogc %s `%s` may cause GC allocation",
- f->kind(), f->toPrettyChars());
- err = true;
- return;
- }
- f->printGCUsage(e->loc, "associative array literal may cause GC allocation");
- }
-
- void visit(NewExp *e)
- {
- if (e->member && !e->member->isNogc() && f->setGC())
- {
- // @nogc-ness is already checked in NewExp::semantic
- return;
- }
- if (e->onstack)
- return;
- if (e->allocator)
- return;
-
- if (f->setGC())
- {
- e->error("cannot use `new` in @nogc %s `%s`",
- f->kind(), f->toPrettyChars());
- err = true;
- return;
- }
- f->printGCUsage(e->loc, "`new` causes GC allocation");
- }
-
- void visit(DeleteExp *e)
- {
- if (e->e1->op == TOKvar)
- {
- VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
- if (v && v->onstack)
- return; // delete for scope allocated class object
- }
-
- Type *tb = e->e1->type->toBasetype();
- AggregateDeclaration *ad = NULL;
- switch (tb->ty)
- {
- case Tclass:
- ad = ((TypeClass *)tb)->sym;
- break;
-
- case Tpointer:
- tb = ((TypePointer *)tb)->next->toBasetype();
- if (tb->ty == Tstruct)
- ad = ((TypeStruct *)tb)->sym;
- break;
-
- default:
- break;
- }
- if (ad && ad->aggDelete)
- return;
-
- if (f->setGC())
- {
- e->error("cannot use `delete` in @nogc %s `%s`",
- f->kind(), f->toPrettyChars());
- err = true;
- return;
- }
- f->printGCUsage(e->loc, "`delete` requires GC");
- }
-
- void visit(IndexExp* e)
- {
- Type *t1b = e->e1->type->toBasetype();
- if (t1b->ty == Taarray)
- {
- if (f->setGC())
- {
- e->error("indexing an associative array in @nogc %s `%s` may cause GC allocation",
- f->kind(), f->toPrettyChars());
- err = true;
- return;
- }
- f->printGCUsage(e->loc, "indexing an associative array may cause GC allocation");
- }
- }
-
- void visit(AssignExp *e)
- {
- if (e->e1->op == TOKarraylength)
- {
- if (f->setGC())
- {
- e->error("setting `length` in @nogc %s `%s` may cause GC allocation",
- f->kind(), f->toPrettyChars());
- err = true;
- return;
- }
- f->printGCUsage(e->loc, "setting `length` may cause GC allocation");
- }
- }
-
- void visit(CatAssignExp *e)
- {
- if (f->setGC())
- {
- e->error("cannot use operator ~= in @nogc %s `%s`",
- f->kind(), f->toPrettyChars());
- err = true;
- return;
- }
- f->printGCUsage(e->loc, "operator ~= may cause GC allocation");
- }
-
- void visit(CatExp *e)
- {
- if (f->setGC())
- {
- e->error("cannot use operator ~ in @nogc %s `%s`",
- f->kind(), f->toPrettyChars());
- err = true;
- return;
- }
- f->printGCUsage(e->loc, "operator ~ may cause GC allocation");
- }
-};
-
-Expression *checkGC(Scope *sc, Expression *e)
-{
- FuncDeclaration *f = sc->func;
- if (e && e->op != TOKerror &&
- f && sc->intypeof != 1 && !(sc->flags & SCOPEctfe) &&
- ((f->type->ty == Tfunction && ((TypeFunction *)f->type)->isnogc) ||
- (f->flags & FUNCFLAGnogcInprocess) ||
- global.params.vgc))
- {
- NOGCVisitor gcv(f);
- walkPostorder(e, &gcv);
- if (gcv.err)
- return new ErrorExp();
- }
- return e;
-}
diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d
new file mode 100644
index 0000000..4bb2907
--- /dev/null
+++ b/gcc/d/dmd/nogc.d
@@ -0,0 +1,266 @@
+/**
+ * Checks that a function marked `@nogc` does not invoke the Garbage Collector.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/function.html#nogc-functions, No-GC Functions)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nogc.d, _nogc.d)
+ * Documentation: https://dlang.org/phobos/dmd_nogc.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/nogc.d
+ */
+
+module dmd.nogc;
+
+import dmd.aggregate;
+import dmd.apply;
+import dmd.astenums;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.init;
+import dmd.mtype;
+import dmd.tokens;
+import dmd.visitor;
+
+/**************************************
+ * Look for GC-allocations
+ */
+extern (C++) final class NOGCVisitor : StoppableVisitor
+{
+ alias visit = typeof(super).visit;
+public:
+ FuncDeclaration f;
+ bool err;
+
+ extern (D) this(FuncDeclaration f)
+ {
+ this.f = f;
+ }
+
+ void doCond(Expression exp)
+ {
+ if (exp)
+ walkPostorder(exp, this);
+ }
+
+ override void visit(Expression e)
+ {
+ }
+
+ override void visit(DeclarationExp e)
+ {
+ // Note that, walkPostorder does not support DeclarationExp today.
+ VarDeclaration v = e.declaration.isVarDeclaration();
+ if (v && !(v.storage_class & STC.manifest) && !v.isDataseg() && v._init)
+ {
+ if (ExpInitializer ei = v._init.isExpInitializer())
+ {
+ doCond(ei.exp);
+ }
+ }
+ }
+
+ override void visit(CallExp e)
+ {
+ import dmd.id : Id;
+ import core.stdc.stdio : printf;
+ if (!e.f)
+ return;
+
+ auto fd = stripHookTraceImpl(e.f);
+ if (fd.ident == Id._d_arraysetlengthT)
+ {
+ if (f.setGC())
+ {
+ e.error("setting `length` in `@nogc` %s `%s` may cause a GC allocation",
+ f.kind(), f.toPrettyChars());
+ err = true;
+ return;
+ }
+ f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
+ }
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ if (e.type.ty != Tarray || !e.elements || !e.elements.dim)
+ return;
+ if (f.setGC())
+ {
+ e.error("array literal in `@nogc` %s `%s` may cause a GC allocation",
+ f.kind(), f.toPrettyChars());
+ err = true;
+ return;
+ }
+ f.printGCUsage(e.loc, "array literal may cause a GC allocation");
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ if (!e.keys.dim)
+ return;
+ if (f.setGC())
+ {
+ e.error("associative array literal in `@nogc` %s `%s` may cause a GC allocation",
+ f.kind(), f.toPrettyChars());
+ err = true;
+ return;
+ }
+ f.printGCUsage(e.loc, "associative array literal may cause a GC allocation");
+ }
+
+ override void visit(NewExp e)
+ {
+ if (e.member && !e.member.isNogc() && f.setGC())
+ {
+ // @nogc-ness is already checked in NewExp::semantic
+ return;
+ }
+ if (e.onstack)
+ return;
+ if (global.params.ehnogc && e.thrownew)
+ return; // separate allocator is called for this, not the GC
+ if (f.setGC())
+ {
+ e.error("cannot use `new` in `@nogc` %s `%s`",
+ f.kind(), f.toPrettyChars());
+ err = true;
+ return;
+ }
+ f.printGCUsage(e.loc, "`new` causes a GC allocation");
+ }
+
+ override void visit(DeleteExp e)
+ {
+ if (e.e1.op == TOK.variable)
+ {
+ VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration();
+ if (v && v.onstack)
+ return; // delete for scope allocated class object
+ }
+
+ Type tb = e.e1.type.toBasetype();
+ AggregateDeclaration ad = null;
+ switch (tb.ty)
+ {
+ case Tclass:
+ ad = (cast(TypeClass)tb).sym;
+ break;
+
+ case Tpointer:
+ tb = (cast(TypePointer)tb).next.toBasetype();
+ if (tb.ty == Tstruct)
+ ad = (cast(TypeStruct)tb).sym;
+ break;
+
+ default:
+ break;
+ }
+
+ if (f.setGC())
+ {
+ e.error("cannot use `delete` in `@nogc` %s `%s`",
+ f.kind(), f.toPrettyChars());
+ err = true;
+ return;
+ }
+ f.printGCUsage(e.loc, "`delete` requires the GC");
+ }
+
+ override void visit(IndexExp e)
+ {
+ Type t1b = e.e1.type.toBasetype();
+ if (t1b.ty == Taarray)
+ {
+ if (f.setGC())
+ {
+ e.error("indexing an associative array in `@nogc` %s `%s` may cause a GC allocation",
+ f.kind(), f.toPrettyChars());
+ err = true;
+ return;
+ }
+ f.printGCUsage(e.loc, "indexing an associative array may cause a GC allocation");
+ }
+ }
+
+ override void visit(AssignExp e)
+ {
+ if (e.e1.op == TOK.arrayLength)
+ {
+ if (f.setGC())
+ {
+ e.error("setting `length` in `@nogc` %s `%s` may cause a GC allocation",
+ f.kind(), f.toPrettyChars());
+ err = true;
+ return;
+ }
+ f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
+ }
+ }
+
+ override void visit(CatAssignExp e)
+ {
+ if (f.setGC())
+ {
+ e.error("cannot use operator `~=` in `@nogc` %s `%s`",
+ f.kind(), f.toPrettyChars());
+ err = true;
+ return;
+ }
+ f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation");
+ }
+
+ override void visit(CatExp e)
+ {
+ if (f.setGC())
+ {
+ e.error("cannot use operator `~` in `@nogc` %s `%s`",
+ f.kind(), f.toPrettyChars());
+ err = true;
+ return;
+ }
+ f.printGCUsage(e.loc, "operator `~` may cause a GC allocation");
+ }
+}
+
+Expression checkGC(Scope* sc, Expression e)
+{
+ FuncDeclaration f = sc.func;
+ if (e && e.op != TOK.error && f && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe) &&
+ (f.type.ty == Tfunction &&
+ (cast(TypeFunction)f.type).isnogc || (f.flags & FUNCFLAG.nogcInprocess) || global.params.vgc) &&
+ !(sc.flags & SCOPE.debug_))
+ {
+ scope NOGCVisitor gcv = new NOGCVisitor(f);
+ walkPostorder(e, gcv);
+ if (gcv.err)
+ return ErrorExp.get();
+ }
+ return e;
+}
+
+/**
+ * Removes `_d_HookTraceImpl` if found from `fd`.
+ * This is needed to be able to find hooks that are called though the hook's `*Trace` wrapper.
+ * Parameters:
+ * fd = The function declaration to remove `_d_HookTraceImpl` from
+ */
+private FuncDeclaration stripHookTraceImpl(FuncDeclaration fd)
+{
+ import dmd.id : Id;
+ import dmd.dsymbol : Dsymbol;
+ import dmd.root.rootobject : RootObject, DYNCAST;
+
+ if (fd.ident != Id._d_HookTraceImpl)
+ return fd;
+
+ // Get the Hook from the second template parameter
+ auto templateInstance = fd.parent.isTemplateInstance;
+ RootObject hook = (*templateInstance.tiargs)[1];
+ assert(hook.dyncast() == DYNCAST.dsymbol, "Expected _d_HookTraceImpl's second template parameter to be an alias to the hook!");
+ return (cast(Dsymbol)hook).isFuncDeclaration;
+}
diff --git a/gcc/d/dmd/nspace.c b/gcc/d/dmd/nspace.c
deleted file mode 100644
index 95cfb6f..0000000
--- a/gcc/d/dmd/nspace.c
+++ /dev/null
@@ -1,164 +0,0 @@
-
-// Compiler implementation of the D programming language
-// Copyright: Copyright (C) 2014-2021 by The D Language Foundation, All Rights Reserved
-// Authors: Walter Bright, http://www.digitalmars.com
-// License: http://boost.org/LICENSE_1_0.txt
-// Source: https://github.com/D-Programming-Language/dmd/blob/master/src/nspace.c
-
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "dsymbol.h"
-#include "nspace.h"
-#include "identifier.h"
-#include "scope.h"
-
-/* This implements namespaces.
- */
-
-Nspace::Nspace(Loc loc, Identifier *ident, Dsymbols *members, bool mangleOnly)
- : ScopeDsymbol(ident)
-{
- //printf("Nspace::Nspace(ident = %s)\n", ident->toChars());
- this->loc = loc;
- this->members = members;
- // Determines whether the symbol for this namespace should be included in
- // the symbol table.
- this->mangleOnly = mangleOnly;
-}
-
-Dsymbol *Nspace::syntaxCopy(Dsymbol *)
-{
- Nspace *ns = new Nspace(loc, ident, NULL, mangleOnly);
- return ScopeDsymbol::syntaxCopy(ns);
-}
-
-void Nspace::addMember(Scope *sc, ScopeDsymbol *sds)
-{
- if (mangleOnly)
- parent = sds;
- else
- ScopeDsymbol::addMember(sc, sds);
- if (members)
- {
- if (!symtab)
- symtab = new DsymbolTable();
- // The namespace becomes 'imported' into the enclosing scope
- for (Scope *sce = sc; 1; sce = sce->enclosing)
- {
- ScopeDsymbol *sds2 = sce->scopesym;
- if (sds2)
- {
- sds2->importScope(this, Prot(Prot::public_));
- break;
- }
- }
- assert(sc);
- sc = sc->push(this);
- sc->linkage = LINKcpp; // namespaces default to C++ linkage
- sc->parent = this;
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- //printf("add %s to scope %s\n", s->toChars(), toChars());
- s->addMember(sc, this);
- }
- sc->pop();
- }
-}
-
-void Nspace::setScope(Scope *sc)
-{
- ScopeDsymbol::setScope(sc);
- if (members)
- {
- assert(sc);
- sc = sc->push(this);
- sc->linkage = LINKcpp; // namespaces default to C++ linkage
- sc->parent = this;
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- s->setScope(sc);
- }
- sc->pop();
- }
-}
-
-const char *Nspace::kind() const
-{
- return "namespace";
-}
-
-bool Nspace::oneMember(Dsymbol **ps, Identifier *ident)
-{
- return Dsymbol::oneMember(ps, ident);
-}
-
-Dsymbol *Nspace::search(const Loc &loc, Identifier *ident, int flags)
-{
- //printf("%s::Nspace::search('%s')\n", toChars(), ident->toChars());
- if (_scope && !symtab)
- dsymbolSemantic(this, _scope);
-
- if (!members || !symtab) // opaque or semantic() is not yet called
- {
- error("is forward referenced when looking for `%s`", ident->toChars());
- return NULL;
- }
-
- return ScopeDsymbol::search(loc, ident, flags);
-}
-
-int Nspace::apply(Dsymbol_apply_ft_t fp, void *param)
-{
- if (members)
- {
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- if (s)
- {
- if (s->apply(fp, param))
- return 1;
- }
- }
- }
- return 0;
-}
-
-bool Nspace::hasPointers()
-{
- //printf("Nspace::hasPointers() %s\n", toChars());
-
- if (members)
- {
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- //printf(" s = %s %s\n", s->kind(), s->toChars());
- if (s->hasPointers())
- {
- return true;
- }
- }
- }
- return false;
-}
-
-void Nspace::setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion)
-{
- //printf("Nspace::setFieldOffset() %s\n", toChars());
- if (_scope) // if fwd reference
- dsymbolSemantic(this, NULL); // try to resolve it
- if (members)
- {
- for (size_t i = 0; i < members->length; i++)
- {
- Dsymbol *s = (*members)[i];
- //printf("\t%s\n", s->toChars());
- s->setFieldOffset(ad, poffset, isunion);
- }
- }
-}
diff --git a/gcc/d/dmd/nspace.d b/gcc/d/dmd/nspace.d
new file mode 100644
index 0000000..215f259
--- /dev/null
+++ b/gcc/d/dmd/nspace.d
@@ -0,0 +1,170 @@
+/**
+ * A scoped C++ namespace symbol
+ *
+ * D supports the following syntax to declare symbol(s) as being part of a
+ * C++ namespace:
+ * ---
+ * extern (C++, "myNamespace") { /+ Symbols +/ } // String variant
+ * extern (C++, SomeNamespace) { /+ Other symbols +/ } // Identifier variant
+ * ---
+ * The first form is an attribute and only affects mangling, and is implemented
+ * in `dmd.attrib`.
+ * The second form introduces a named scope and allows symbols to be refered
+ * to with or without the namespace name, much like a named template mixin,
+ * and is implemented in this module.
+ * ---
+ * extern (C++, Basket)
+ * {
+ * struct StrawBerry;
+ * void swapFood (Strawberry* f1, Strawberry* f2);
+ * }
+ * void main ()
+ * {
+ * Basket.StrawBerry fruit1;
+ * StrawBerry fruit2;
+ * Basket.swapFood(fruit1, fruit2);
+ * swapFood(fruit1, fruit2);
+ * }
+ * ---
+ * Hence the `Nspace` symbol implements the usual `ScopeDsymbol` semantics.
+ *
+ * Note that it implies `extern(C++)` so it cannot be used as a generic
+ * named scope. Additionally, `Nspace` with the same `Identifier` can be
+ * defined in different module (as C++ allows a namespace to be spread accross
+ * translation units), but symbols in it should be considered
+ * part of the same scope. Lastly, not all possible C++ namespace names
+ * are valid D identifier.
+ *
+ * See_Also: https://github.com/dlang/dmd/pull/10031
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/nspace.d, _nspace.d)
+ * Documentation: https://dlang.org/phobos/dmd_nspace.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/nspace.d
+ */
+
+module dmd.nspace;
+
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.expression;
+import dmd.globals;
+import dmd.identifier;
+import dmd.visitor;
+import core.stdc.stdio;
+
+private enum LOG = false;
+
+/// Ditto
+extern (C++) final class Nspace : ScopeDsymbol
+{
+ /**
+ * Namespace identifier resolved during semantic.
+ */
+ Expression identExp;
+
+ extern (D) this(const ref Loc loc, Identifier ident, Expression identExp, Dsymbols* members)
+ {
+ super(loc, ident);
+ //printf("Nspace::Nspace(ident = %s)\n", ident.toChars());
+ this.members = members;
+ this.identExp = identExp;
+ }
+
+ override Nspace syntaxCopy(Dsymbol s)
+ {
+ auto ns = new Nspace(loc, ident, identExp, null);
+ ScopeDsymbol.syntaxCopy(ns);
+ return ns;
+ }
+
+ override void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ ScopeDsymbol.addMember(sc, sds);
+
+ if (members)
+ {
+ if (!symtab)
+ symtab = new DsymbolTable();
+ // The namespace becomes 'imported' into the enclosing scope
+ for (Scope* sce = sc; 1; sce = sce.enclosing)
+ {
+ ScopeDsymbol sds2 = sce.scopesym;
+ if (sds2)
+ {
+ sds2.importScope(this, Visibility(Visibility.Kind.public_));
+ break;
+ }
+ }
+ assert(sc);
+ sc = sc.push(this);
+ sc.linkage = LINK.cpp; // namespaces default to C++ linkage
+ sc.parent = this;
+ members.foreachDsymbol(s => s.addMember(sc, this));
+ sc.pop();
+ }
+ }
+
+ override void setScope(Scope* sc)
+ {
+ ScopeDsymbol.setScope(sc);
+ if (members)
+ {
+ assert(sc);
+ sc = sc.push(this);
+ sc.linkage = LINK.cpp; // namespaces default to C++ linkage
+ sc.parent = this;
+ members.foreachDsymbol(s => s.setScope(sc));
+ sc.pop();
+ }
+ }
+
+ override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
+ {
+ //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars());
+ if (_scope && !symtab)
+ dsymbolSemantic(this, _scope);
+
+ if (!members || !symtab) // opaque or semantic() is not yet called
+ {
+ if (!(flags & IgnoreErrors))
+ error("is forward referenced when looking for `%s`", ident.toChars());
+ return null;
+ }
+
+ return ScopeDsymbol.search(loc, ident, flags);
+ }
+
+ override bool hasPointers()
+ {
+ //printf("Nspace::hasPointers() %s\n", toChars());
+ return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
+ }
+
+ override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
+ {
+ //printf("Nspace::setFieldOffset() %s\n", toChars());
+ if (_scope) // if fwd reference
+ dsymbolSemantic(this, null); // try to resolve it
+ members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
+ }
+
+ override const(char)* kind() const
+ {
+ return "namespace";
+ }
+
+ override inout(Nspace) isNspace() inout
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h
index 71dafb2..43d36e9 100644
--- a/gcc/d/dmd/nspace.h
+++ b/gcc/d/dmd/nspace.h
@@ -19,17 +19,13 @@
class Nspace : public ScopeDsymbol
{
public:
- bool mangleOnly;
- Nspace(Loc loc, Identifier *ident, Dsymbols *members, bool mangleOnly);
-
- Dsymbol *syntaxCopy(Dsymbol *s);
+ Expression *identExp;
+ Nspace *syntaxCopy(Dsymbol *s);
void addMember(Scope *sc, ScopeDsymbol *sds);
void setScope(Scope *sc);
- bool oneMember(Dsymbol **ps, Identifier *ident);
Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
- int apply(Dsymbol_apply_ft_t fp, void *param);
bool hasPointers();
- void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
+ void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
const char *kind() const;
Nspace *isNspace() { return this; }
void accept(Visitor *v) { v->visit(this); }
diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d
new file mode 100644
index 0000000..7719ccf
--- /dev/null
+++ b/gcc/d/dmd/ob.d
@@ -0,0 +1,2680 @@
+/**
+ * Flow analysis for Ownership/Borrowing
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ob.d, _ob.d)
+ * Documentation: https://dlang.org/phobos/dmd_escape.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ob.d
+ */
+
+module dmd.ob;
+
+import core.stdc.stdio : printf;
+import core.stdc.stdlib;
+import core.stdc.string;
+
+import dmd.root.array;
+import dmd.root.rootobject;
+import dmd.root.rmem;
+
+import dmd.aggregate;
+import dmd.apply;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.escape;
+import dmd.expression;
+import dmd.foreachvar;
+import dmd.func;
+import dmd.globals;
+import dmd.identifier;
+import dmd.init;
+import dmd.mtype;
+import dmd.printast;
+import dmd.statement;
+import dmd.stmtstate;
+import dmd.tokens;
+import dmd.visitor;
+
+import dmd.root.bitarray;
+import dmd.root.outbuffer;
+
+/**********************************
+ * Perform ownership/borrowing checks for funcdecl.
+ * Does not modify the AST, just checks for errors.
+ */
+
+void oblive(FuncDeclaration funcdecl)
+{
+ //printf("oblive() %s\n", funcdecl.toChars());
+ //printf("fbody: %s\n", funcdecl.fbody.toChars());
+ ObState obstate;
+
+ /* Build the flow graph
+ */
+ setLabelStatementExtraFields(funcdecl.labtab);
+ toObNodes(obstate.nodes, funcdecl.fbody);
+ insertFinallyBlockCalls(obstate.nodes);
+ insertFinallyBlockGotos(obstate.nodes);
+ removeUnreachable(obstate.nodes);
+ computePreds(obstate.nodes);
+
+ numberNodes(obstate.nodes);
+ //foreach (ob; obstate.nodes) ob.print();
+
+ collectVars(funcdecl, obstate.vars);
+ allocStates(obstate);
+ doDataFlowAnalysis(obstate);
+
+ checkObErrors(obstate);
+}
+
+alias ObNodes = Array!(ObNode*);
+
+alias StmtState = dmd.stmtstate.StmtState!ObNode;
+
+/*******************************************
+ * Collect the state information.
+ */
+struct ObState
+{
+ ObNodes nodes;
+ VarDeclarations vars;
+
+ Array!size_t varStack; /// temporary storage
+ Array!bool mutableStack; /// parallel to varStack[], is type mutable?
+
+ PtrVarState[] varPool; /// memory pool
+
+ ~this()
+ {
+ mem.xfree(varPool.ptr);
+ }
+}
+
+/***********************************************
+ * A node in the function's expression graph, and its edges to predecessors and successors.
+ */
+struct ObNode
+{
+ Expression exp; /// expression for the node
+ ObNodes preds; /// predecessors
+ ObNodes succs; /// successors
+ ObNode* tryBlock; /// try-finally block we're inside
+ ObType obtype;
+ uint index; /// index of this in obnodes
+
+ PtrVarState[] gen; /// new states generated for this node
+ PtrVarState[] input; /// variable states on entry to exp
+ PtrVarState[] output; /// variable states on exit to exp
+
+ this(ObNode* tryBlock)
+ {
+ this.tryBlock = tryBlock;
+ }
+
+ void print()
+ {
+ printf("%d: %s %s\n", index, obtype.toString.ptr, exp ? exp.toChars() : "-");
+ printf(" preds: ");
+ foreach (ob; preds)
+ printf(" %d", ob.index);
+ printf("\n succs: ");
+ foreach (ob; succs)
+ printf(" %d", ob.index);
+ printf("\n\n");
+ }
+}
+
+
+enum ObType : ubyte
+{
+ goto_, /// goto one of the succs[]
+ return_, /// returns from function
+ retexp, /// returns expression from function
+ throw_, /// exits with throw
+ exit, /// exits program
+ try_,
+ finally_,
+ fend,
+}
+
+string toString(ObType obtype)
+{
+ return obtype == ObType.goto_ ? "goto " :
+ obtype == ObType.return_ ? "ret " :
+ obtype == ObType.retexp ? "retexp" :
+ obtype == ObType.throw_ ? "throw" :
+ obtype == ObType.exit ? "exit" :
+ obtype == ObType.try_ ? "try" :
+ obtype == ObType.finally_ ? "finally" :
+ obtype == ObType.fend ? "fend" :
+ "---";
+}
+
+/***********
+ Pointer variable states:
+
+ Initial state is not known; ignore for now
+
+ Undefined not in a usable state
+
+ T* p = void;
+
+ Owner mutable pointer
+
+ T* p = initializer;
+
+ Borrowed scope mutable pointer, borrowed from [p]
+
+ T* p = initializer;
+ scope T* b = p;
+
+ Readonly scope const pointer, copied from [p]
+
+ T* p = initializer;
+ scope const(T)* cp = p;
+
+ Examples:
+
+ T* p = initializer; // p is owner
+ T** pp = &p; // pp borrows from p
+
+ T* p = initialize; // p is owner
+ T* q = p; // transfer: q is owner, p is undefined
+ */
+
+enum PtrState : ubyte
+{
+ Initial, Undefined, Owner, Borrowed, Readonly
+}
+
+/************
+ */
+const(char)* toChars(PtrState state)
+{
+ return toString(state).ptr;
+}
+
+string toString(PtrState state)
+{
+ return ["Initial", "Undefined", "Owner", "Borrowed", "Readonly"][state];
+}
+
+/******
+ * Carries the state of a pointer variable.
+ */
+struct PtrVarState
+{
+ BitArray deps; /// dependencies
+ PtrState state; /// state the pointer variable is in
+
+ void opAssign(const ref PtrVarState pvs)
+ {
+ state = pvs.state;
+ deps = pvs.deps;
+ }
+
+ /* Combine `this` and `pvs` into `this`,
+ * on the idea that the `this` and the `pvs` paths
+ * are being merged
+ * Params:
+ * pvs = path to be merged with `this`
+ */
+ void combine(ref PtrVarState pvs, size_t vi, PtrVarState[] gen)
+ {
+ static uint X(PtrState x1, PtrState x2) { return x1 * (PtrState.max + 1) + x2; }
+
+ with (PtrState)
+ {
+ switch (X(state, pvs.state))
+ {
+ case X(Initial, Initial):
+ break;
+
+ case X(Initial, Owner ):
+ case X(Initial, Borrowed ):
+ case X(Initial, Readonly ):
+ // Transfer state to `this`
+ state = pvs.state;
+ deps = pvs.deps;
+ break;
+
+ case X(Owner, Initial):
+ case X(Borrowed, Initial):
+ case X(Readonly, Initial):
+ break;
+
+ case X(Undefined, Initial):
+ case X(Undefined, Undefined):
+ case X(Undefined, Owner ):
+ case X(Undefined, Borrowed ):
+ case X(Undefined, Readonly ):
+ break;
+
+ case X(Owner , Owner ):
+ break;
+
+ case X(Borrowed , Borrowed):
+ case X(Readonly , Readonly):
+ deps.or(pvs.deps);
+ break;
+
+ default:
+ makeUndefined(vi, gen);
+ break;
+ }
+ }
+ }
+
+ bool opEquals(const ref PtrVarState pvs) const
+ {
+ return state == pvs.state &&
+ deps == pvs.deps;
+ }
+
+ /***********************
+ */
+ void print(VarDeclaration[] vars)
+ {
+ string s = toString(state);
+ printf("%.*s [", cast(int)s.length, s.ptr);
+ assert(vars.length == deps.length);
+ OutBuffer buf;
+ depsToBuf(buf, vars);
+ auto t = buf[];
+ printf("%.*s]\n", cast(int)t.length, t.ptr);
+ }
+
+ /*****************************
+ * Produce a user-readable comma separated string of the
+ * dependencies.
+ * Params:
+ * buf = write resulting string here
+ * vars = array from which to get the variable names
+ */
+ void depsToBuf(ref OutBuffer buf, const VarDeclaration[] vars)
+ {
+ bool any = false;
+ foreach (i; 0 .. deps.length)
+ {
+ if (deps[i])
+ {
+ if (any)
+ buf.writestring(", ");
+ buf.writestring(vars[i].toString());
+ any = true;
+ }
+ }
+ }
+}
+
+
+/*****************************************
+ * Set the `.extra` field for LabelStatements in labtab[].
+ */
+void setLabelStatementExtraFields(DsymbolTable labtab)
+{
+ if (labtab)
+ foreach (keyValue; labtab.tab.asRange)
+ {
+ //printf(" KV: %s = %s\n", keyValue.key.toChars(), keyValue.value.toChars());
+ auto label = cast(LabelDsymbol)keyValue.value;
+ if (label.statement)
+ label.statement.extra = cast(void*) new ObNode(null);
+ }
+}
+
+/*****************************************
+ * Convert statement into ObNodes.
+ */
+
+void toObNodes(ref ObNodes obnodes, Statement s)
+{
+ ObNode* curblock = new ObNode(null);
+ obnodes.push(curblock);
+
+ void visit(Statement s, StmtState* stmtstate)
+ {
+ if (!s)
+ return;
+
+ ObNode* newNode()
+ {
+ return new ObNode(stmtstate.tryBlock);
+ }
+
+ ObNode* nextNodeIs(ObNode* ob)
+ {
+ obnodes.push(ob);
+ curblock = ob;
+ return ob;
+ }
+
+ ObNode* nextNode()
+ {
+ return nextNodeIs(newNode());
+ }
+
+ ObNode* gotoNextNodeIs(ObNode* ob)
+ {
+ obnodes.push(ob);
+ curblock.succs.push(ob);
+ curblock = ob;
+ return ob;
+ }
+
+ // block_goto(blx, BCgoto, null)
+ ObNode* gotoNextNode()
+ {
+ return gotoNextNodeIs(newNode());
+ }
+
+ /***
+ * Doing a goto to dest
+ */
+ ObNode* gotoDest(ObNode* dest)
+ {
+ curblock.succs.push(dest);
+ return nextNode();
+ }
+
+ void visitExp(ExpStatement s)
+ {
+ curblock.obtype = ObType.goto_;
+ curblock.exp = s.exp;
+ gotoNextNode();
+ }
+
+ void visitDtorExp(DtorExpStatement s)
+ {
+ visitExp(s);
+ }
+
+ void visitCompound(CompoundStatement s)
+ {
+ if (s.statements)
+ {
+ foreach (s2; *s.statements)
+ {
+ visit(s2, stmtstate);
+ }
+ }
+ }
+
+ void visitCompoundDeclaration(CompoundDeclarationStatement s)
+ {
+ visitCompound(s);
+ }
+
+ void visitUnrolledLoop(UnrolledLoopStatement s)
+ {
+ StmtState mystate = StmtState(stmtstate, s);
+ mystate.breakBlock = newNode();
+
+ gotoNextNode();
+
+ foreach (s2; *s.statements)
+ {
+ if (s2)
+ {
+ mystate.contBlock = newNode();
+
+ visit(s2, &mystate);
+
+ gotoNextNodeIs(mystate.contBlock);
+ }
+ }
+
+ gotoNextNodeIs(mystate.breakBlock);
+ }
+
+ void visitScope(ScopeStatement s)
+ {
+ if (s.statement)
+ {
+ StmtState mystate = StmtState(stmtstate, s);
+
+ if (mystate.prev.ident)
+ mystate.ident = mystate.prev.ident;
+
+ visit(s.statement, &mystate);
+
+ if (mystate.breakBlock)
+ gotoNextNodeIs(mystate.breakBlock);
+ }
+ }
+
+ void visitDo(DoStatement s)
+ {
+ StmtState mystate = StmtState(stmtstate, s);
+ mystate.breakBlock = newNode();
+ mystate.contBlock = newNode();
+
+ auto bpre = curblock;
+
+ auto ob = newNode();
+ obnodes.push(ob);
+ curblock.succs.push(ob);
+ curblock = ob;
+ bpre.succs.push(curblock);
+
+ mystate.contBlock.succs.push(curblock);
+ mystate.contBlock.succs.push(mystate.breakBlock);
+
+ visit(s._body, &mystate);
+
+ gotoNextNodeIs(mystate.contBlock);
+ mystate.contBlock.exp = s.condition;
+ nextNodeIs(mystate.breakBlock);
+ }
+
+ void visitFor(ForStatement s)
+ {
+ //printf("visit(ForStatement)) %u..%u\n", s.loc.linnum, s.endloc.linnum);
+ StmtState mystate = StmtState(stmtstate, s);
+ mystate.breakBlock = newNode();
+ mystate.contBlock = newNode();
+
+ visit(s._init, &mystate);
+
+ auto bcond = gotoNextNode();
+ mystate.contBlock.succs.push(bcond);
+
+ if (s.condition)
+ {
+ bcond.exp = s.condition;
+ auto ob = newNode();
+ obnodes.push(ob);
+ bcond.succs.push(ob);
+ bcond.succs.push(mystate.breakBlock);
+ curblock = ob;
+ }
+ else
+ { /* No conditional, it's a straight goto
+ */
+ bcond.exp = s.condition;
+ bcond.succs.push(nextNode());
+ }
+
+ visit(s._body, &mystate);
+ /* End of the body goes to the continue block
+ */
+ curblock.succs.push(mystate.contBlock);
+ nextNodeIs(mystate.contBlock);
+
+ if (s.increment)
+ curblock.exp = s.increment;
+
+ /* The 'break' block follows the for statement.
+ */
+ nextNodeIs(mystate.breakBlock);
+ }
+
+ void visitIf(IfStatement s)
+ {
+ StmtState mystate = StmtState(stmtstate, s);
+
+ // bexit is the block that gets control after this IfStatement is done
+ auto bexit = mystate.breakBlock ? mystate.breakBlock : newNode();
+
+ curblock.exp = s.condition;
+
+ auto bcond = curblock;
+ gotoNextNode();
+
+ visit(s.ifbody, &mystate);
+ curblock.succs.push(bexit);
+
+ if (s.elsebody)
+ {
+ bcond.succs.push(nextNode());
+
+ visit(s.elsebody, &mystate);
+
+ gotoNextNodeIs(bexit);
+ }
+ else
+ {
+ bcond.succs.push(bexit);
+ nextNodeIs(bexit);
+ }
+ }
+
+ void visitSwitch(SwitchStatement s)
+ {
+ StmtState mystate = StmtState(stmtstate, s);
+
+ mystate.switchBlock = curblock;
+
+ /* Block for where "break" goes to
+ */
+ mystate.breakBlock = newNode();
+
+ /* Block for where "default" goes to.
+ * If there is a default statement, then that is where default goes.
+ * If not, then do:
+ * default: break;
+ * by making the default block the same as the break block.
+ */
+ mystate.defaultBlock = s.sdefault ? newNode() : mystate.breakBlock;
+
+ const numcases = s.cases ? s.cases.dim : 0;
+
+ /* allocate a block for each case
+ */
+ if (numcases)
+ foreach (cs; *s.cases)
+ {
+ cs.extra = cast(void*)newNode();
+ }
+
+ curblock.exp = s.condition;
+
+ if (s.hasVars)
+ { /* Generate a sequence of if-then-else blocks for the cases.
+ */
+ if (numcases)
+ foreach (cs; *s.cases)
+ {
+ auto ecase = newNode();
+ obnodes.push(ecase);
+ ecase.exp = cs.exp;
+ curblock.succs.push(ecase);
+
+ auto cn = cast(ObNode*)cs.extra;
+ ecase.succs.push(cn);
+ ecase.succs.push(nextNode());
+ }
+
+ /* The final 'else' clause goes to the default
+ */
+ curblock.succs.push(mystate.defaultBlock);
+ nextNode();
+
+ visit(s._body, &mystate);
+
+ /* Have the end of the switch body fall through to the block
+ * following the switch statement.
+ */
+ gotoNextNodeIs(mystate.breakBlock);
+ return;
+ }
+
+ auto ob = newNode();
+ obnodes.push(ob);
+ curblock = ob;
+
+ mystate.switchBlock.succs.push(mystate.defaultBlock);
+
+ visit(s._body, &mystate);
+
+ /* Have the end of the switch body fall through to the block
+ * following the switch statement.
+ */
+ gotoNextNodeIs(mystate.breakBlock);
+ }
+
+ void visitCase(CaseStatement s)
+ {
+ auto cb = cast(ObNode*)s.extra;
+ cb.tryBlock = stmtstate.tryBlock;
+ auto bsw = stmtstate.getSwitchBlock();
+ bsw.succs.push(cb);
+ gotoNextNodeIs(cb);
+
+ visit(s.statement, stmtstate);
+ }
+
+ void visitDefault(DefaultStatement s)
+ {
+ auto bdefault = stmtstate.getDefaultBlock;
+ bdefault.tryBlock = stmtstate.tryBlock;
+ gotoNextNodeIs(bdefault);
+ visit(s.statement, stmtstate);
+ }
+
+ void visitGotoDefault(GotoDefaultStatement s)
+ {
+ gotoDest(stmtstate.getDefaultBlock);
+ }
+
+ void visitGotoCase(GotoCaseStatement s)
+ {
+ gotoDest(cast(ObNode*)s.cs.extra);
+ }
+
+ void visitSwitchError(SwitchErrorStatement s)
+ {
+ curblock.obtype = ObType.throw_;
+ curblock.exp = s.exp;
+
+ nextNode();
+ }
+
+ void visitReturn(ReturnStatement s)
+ {
+ //printf("visitReturn() %s\n", s.toChars());
+ curblock.obtype = s.exp && s.exp.type.toBasetype().ty != Tvoid
+ ? ObType.retexp
+ : ObType.return_;
+ curblock.exp = s.exp;
+
+ nextNode();
+ }
+
+ void visitBreak(BreakStatement s)
+ {
+ gotoDest(stmtstate.getBreakBlock(s.ident));
+ }
+
+ void visitContinue(ContinueStatement s)
+ {
+ gotoDest(stmtstate.getContBlock(s.ident));
+ }
+
+ void visitWith(WithStatement s)
+ {
+ visit(s._body, stmtstate);
+ }
+
+ void visitTryCatch(TryCatchStatement s)
+ {
+ /* tryblock
+ * body
+ * breakBlock
+ * catches
+ * breakBlock2
+ */
+
+ StmtState mystate = StmtState(stmtstate, s);
+ mystate.breakBlock = newNode();
+
+ auto tryblock = gotoNextNode();
+
+ visit(s._body, &mystate);
+
+ gotoNextNodeIs(mystate.breakBlock);
+
+ // create new break block that follows all the catches
+ auto breakBlock2 = newNode();
+
+ gotoDest(breakBlock2);
+
+ foreach (cs; *s.catches)
+ {
+ /* Each catch block is a successor to tryblock
+ * and the last block of try body
+ */
+ StmtState catchState = StmtState(stmtstate, s);
+
+ auto bcatch = curblock;
+ tryblock.succs.push(bcatch);
+ mystate.breakBlock.succs.push(bcatch);
+
+ nextNode();
+
+ visit(cs.handler, &catchState);
+
+ gotoDest(breakBlock2);
+ }
+
+ curblock.succs.push(breakBlock2);
+ obnodes.push(breakBlock2);
+ curblock = breakBlock2;
+ }
+
+ void visitTryFinally(TryFinallyStatement s)
+ {
+ /* Build this:
+ * 1 goto [2]
+ * 2 try_ [3] [5] [7]
+ * 3 body
+ * 4 goto [8]
+ * 5 finally_ [6]
+ * 6 finalbody
+ * 7 fend [8]
+ * 8 lastblock
+ */
+
+ StmtState bodyState = StmtState(stmtstate, s);
+
+ auto b2 = gotoNextNode();
+ b2.obtype = ObType.try_;
+ bodyState.tryBlock = b2;
+
+ gotoNextNode();
+
+ visit(s._body, &bodyState);
+
+ auto b4 = gotoNextNode();
+
+ auto b5 = newNode();
+ b5.obtype = ObType.finally_;
+ nextNodeIs(b5);
+ gotoNextNode();
+
+ StmtState finallyState = StmtState(stmtstate, s);
+ visit(s.finalbody, &finallyState);
+
+ auto b7 = gotoNextNode();
+ b7.obtype = ObType.fend;
+
+ auto b8 = gotoNextNode();
+
+ b2.succs.push(b5);
+ b2.succs.push(b7);
+
+ b4.succs.push(b8);
+ }
+
+ void visitThrow(ThrowStatement s)
+ {
+ curblock.obtype = ObType.throw_;
+ curblock.exp = s.exp;
+ nextNode();
+ }
+
+ void visitGoto(GotoStatement s)
+ {
+ gotoDest(cast(ObNode*)s.label.statement.extra);
+ }
+
+ void visitLabel(LabelStatement s)
+ {
+ StmtState mystate = StmtState(stmtstate, s);
+ mystate.ident = s.ident;
+
+ auto ob = cast(ObNode*)s.extra;
+ ob.tryBlock = mystate.tryBlock;
+ visit(s.statement, &mystate);
+ }
+
+ final switch (s.stmt)
+ {
+ case STMT.Exp: visitExp(s.isExpStatement()); break;
+ case STMT.DtorExp: visitDtorExp(s.isDtorExpStatement()); break;
+ case STMT.Compound: visitCompound(s.isCompoundStatement()); break;
+ case STMT.CompoundDeclaration: visitCompoundDeclaration(s.isCompoundDeclarationStatement()); break;
+ case STMT.UnrolledLoop: visitUnrolledLoop(s.isUnrolledLoopStatement()); break;
+ case STMT.Scope: visitScope(s.isScopeStatement()); break;
+ case STMT.Do: visitDo(s.isDoStatement()); break;
+ case STMT.For: visitFor(s.isForStatement()); break;
+ case STMT.If: visitIf(s.isIfStatement()); break;
+ case STMT.Switch: visitSwitch(s.isSwitchStatement()); break;
+ case STMT.Case: visitCase(s.isCaseStatement()); break;
+ case STMT.Default: visitDefault(s.isDefaultStatement()); break;
+ case STMT.GotoDefault: visitGotoDefault(s.isGotoDefaultStatement()); break;
+ case STMT.GotoCase: visitGotoCase(s.isGotoCaseStatement()); break;
+ case STMT.SwitchError: visitSwitchError(s.isSwitchErrorStatement()); break;
+ case STMT.Return: visitReturn(s.isReturnStatement()); break;
+ case STMT.Break: visitBreak(s.isBreakStatement()); break;
+ case STMT.Continue: visitContinue(s.isContinueStatement()); break;
+ case STMT.With: visitWith(s.isWithStatement()); break;
+ case STMT.TryCatch: visitTryCatch(s.isTryCatchStatement()); break;
+ case STMT.TryFinally: visitTryFinally(s.isTryFinallyStatement()); break;
+ case STMT.Throw: visitThrow(s.isThrowStatement()); break;
+ case STMT.Goto: visitGoto(s.isGotoStatement()); break;
+ case STMT.Label: visitLabel(s.isLabelStatement()); break;
+
+ case STMT.CompoundAsm:
+ case STMT.Asm:
+ case STMT.InlineAsm:
+ case STMT.GccAsm:
+
+ case STMT.Pragma:
+ case STMT.Import:
+ case STMT.ScopeGuard:
+ case STMT.Error:
+ break; // ignore these
+
+ case STMT.Foreach:
+ case STMT.ForeachRange:
+ case STMT.Debug:
+ case STMT.CaseRange:
+ case STMT.StaticForeach:
+ case STMT.StaticAssert:
+ case STMT.Conditional:
+ case STMT.While:
+ case STMT.Forwarding:
+ case STMT.Compile:
+ case STMT.Peel:
+ case STMT.Synchronized:
+ debug printf("s: %s\n", s.toChars());
+ assert(0); // should have been rewritten
+ }
+ }
+
+ StmtState stmtstate;
+ visit(s, &stmtstate);
+ curblock.obtype = ObType.return_;
+
+ static if (0)
+ {
+ printf("toObNodes()\n");
+ printf("------- before ----------\n");
+ numberNodes(obnodes);
+ foreach (ob; obnodes) ob.print();
+ printf("-------------------------\n");
+ }
+
+ assert(stmtstate.breakBlock is null);
+ assert(stmtstate.contBlock is null);
+ assert(stmtstate.switchBlock is null);
+ assert(stmtstate.defaultBlock is null);
+ assert(stmtstate.tryBlock is null);
+}
+
+/***************************************************
+ * Insert finally block calls when doing a goto from
+ * inside a try block to outside.
+ * Done after blocks are generated because then we know all
+ * the edges of the graph, but before the pred's are computed.
+ * Params:
+ * obnodes = graph of the function
+ */
+
+void insertFinallyBlockCalls(ref ObNodes obnodes)
+{
+ ObNode* bcret = null;
+ ObNode* bcretexp = null;
+
+ enum log = false;
+
+ static if (log)
+ {
+ printf("insertFinallyBlockCalls()\n");
+ printf("------- before ----------\n");
+ numberNodes(obnodes);
+ foreach (ob; obnodes) ob.print();
+ printf("-------------------------\n");
+ }
+
+ foreach (ob; obnodes)
+ {
+ if (!ob.tryBlock)
+ continue;
+
+ switch (ob.obtype)
+ {
+ case ObType.return_:
+ // Rewrite into a ObType.goto_ => ObType.return_
+ if (!bcret)
+ {
+ bcret = new ObNode();
+ bcret.obtype = ob.obtype;
+ }
+ ob.obtype = ObType.goto_;
+ ob.succs.push(bcret);
+ goto case_goto;
+
+ case ObType.retexp:
+ // Rewrite into a ObType.goto_ => ObType.retexp
+ if (!bcretexp)
+ {
+ bcretexp = new ObNode();
+ bcretexp.obtype = ob.obtype;
+ }
+ ob.obtype = ObType.goto_;
+ ob.succs.push(bcretexp);
+ goto case_goto;
+
+ case ObType.goto_:
+ if (ob.succs.length != 1)
+ break;
+
+ case_goto:
+ {
+ auto target = ob.succs[0]; // destination of goto
+ ob.succs.setDim(0);
+ auto lasttry = target.tryBlock;
+ auto blast = ob;
+ for (auto bt = ob.tryBlock; bt != lasttry; bt = bt.tryBlock)
+ {
+ assert(bt.obtype == ObType.try_);
+ auto bf = bt.succs[1];
+ assert(bf.obtype == ObType.finally_);
+ auto bfend = bt.succs[2];
+ assert(bfend.obtype == ObType.fend);
+
+ if (!blast.succs.contains(bf.succs[0]))
+ blast.succs.push(bf.succs[0]);
+
+ blast = bfend;
+ }
+ if (!blast.succs.contains(target))
+ blast.succs.push(target);
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ if (bcret)
+ obnodes.push(bcret);
+ if (bcretexp)
+ obnodes.push(bcretexp);
+
+ static if (log)
+ {
+ printf("------- after ----------\n");
+ numberNodes(obnodes);
+ foreach (ob; obnodes) ob.print();
+ printf("-------------------------\n");
+ }
+}
+
+/***************************************************
+ * Remove try-finally scaffolding.
+ * Params:
+ * obnodes = nodes for the function
+ */
+
+void insertFinallyBlockGotos(ref ObNodes obnodes)
+{
+ /* Remove all the try_, finally_, lpad and ret nodes.
+ * Actually, just make them into no-ops.
+ */
+ foreach (ob; obnodes)
+ {
+ ob.tryBlock = null;
+ switch (ob.obtype)
+ {
+ case ObType.try_:
+ ob.obtype = ObType.goto_;
+ ob.succs.remove(2); // remove fend
+ ob.succs.remove(1); // remove finally_
+ break;
+
+ case ObType.finally_:
+ ob.obtype = ObType.goto_;
+ break;
+
+ case ObType.fend:
+ ob.obtype = ObType.goto_;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/*********************************
+ * Set the `index` field of each ObNode
+ * to its index in the `obnodes[]` array.
+ */
+void numberNodes(ref ObNodes obnodes)
+{
+ //printf("numberNodes()\n");
+ foreach (i, ob; obnodes)
+ {
+ //printf("ob = %d, %p\n", i, ob);
+ ob.index = cast(uint)i;
+ }
+
+ // Verify that nodes do not appear more than once in obnodes[]
+ debug
+ foreach (i, ob; obnodes)
+ {
+ assert(ob.index == cast(uint)i);
+ }
+}
+
+
+/*********************************
+ * Remove unreachable nodes and compress
+ * them out of obnodes[].
+ * Params:
+ * obnodes = array of nodes
+ */
+void removeUnreachable(ref ObNodes obnodes)
+{
+ if (!obnodes.length)
+ return;
+
+ /* Mark all nodes as unreachable,
+ * temporarilly reusing ObNode.index
+ */
+ foreach (ob; obnodes)
+ ob.index = 0;
+
+ /* Recursively mark ob and all its successors as reachable
+ */
+ static void mark(ObNode* ob)
+ {
+ ob.index = 1;
+ foreach (succ; ob.succs)
+ {
+ if (!succ.index)
+ mark(succ);
+ }
+ }
+
+ mark(obnodes[0]); // first node is entry point
+
+ /* Remove unreachable nodes by shifting the remainder left
+ */
+ size_t j = 1;
+ foreach (i; 1 .. obnodes.length)
+ {
+ if (obnodes[i].index)
+ {
+ if (i != j)
+ obnodes[j] = obnodes[i];
+ ++j;
+ }
+ else
+ {
+ obnodes[i].destroy();
+ }
+ }
+ obnodes.setDim(j);
+}
+
+
+
+/*************************************
+ * Compute predecessors.
+ */
+void computePreds(ref ObNodes obnodes)
+{
+ foreach (ob; obnodes)
+ {
+ foreach (succ; ob.succs)
+ {
+ succ.preds.push(ob);
+ }
+ }
+}
+
+/*******************************
+ * Are we interested in tracking variable `v`?
+ */
+bool isTrackableVar(VarDeclaration v)
+{
+ //printf("isTrackableVar() %s\n", v.toChars());
+ auto tb = v.type.toBasetype();
+
+ /* Assume class references are managed by the GC,
+ * don't need to track them
+ */
+ if (tb.ty == Tclass)
+ return false;
+
+ /* Assume types with a destructor are doing their own tracking,
+ * such as being a ref counted type
+ */
+ if (v.needsScopeDtor())
+ return false;
+
+ /* Not tracking function parameters that are not mutable
+ */
+ if (v.storage_class & STC.parameter && !tb.hasPointersToMutableFields())
+ return false;
+
+ /* Not tracking global variables
+ */
+ return !v.isDataseg();
+}
+
+/*******************************
+ * Are we interested in tracking this expression?
+ * Returns:
+ * variable if so, null if not
+ */
+VarDeclaration isTrackableVarExp(Expression e)
+{
+ if (auto ve = e.isVarExp())
+ {
+ if (auto v = ve.var.isVarDeclaration())
+ if (isTrackableVar(v))
+ return v;
+ }
+ return null;
+}
+
+
+/**************
+ * Find the pointer variable declarations in this function,
+ * and fill `vars` with them.
+ * Params:
+ * funcdecl = function we are in
+ * vars = array to fill in
+ */
+void collectVars(FuncDeclaration funcdecl, out VarDeclarations vars)
+{
+ enum log = false;
+ if (log)
+ printf("----------------collectVars()---------------\n");
+
+ if (funcdecl.parameters)
+ foreach (v; (*funcdecl.parameters)[])
+ {
+ if (isTrackableVar(v))
+ vars.push(v);
+ }
+
+ void dgVar(VarDeclaration v)
+ {
+ if (isTrackableVar(v))
+ vars.push(v);
+ }
+
+ void dgExp(Expression e)
+ {
+ foreachVar(e, &dgVar);
+ }
+
+ foreachExpAndVar(funcdecl.fbody, &dgExp, &dgVar);
+
+ static if (log)
+ {
+ foreach (i, v; vars[])
+ {
+ printf("vars[%d] = %s\n", cast(int)i, v.toChars());
+ }
+ }
+}
+
+/***********************************
+ * Allocate BitArrays in PtrVarState.
+ * Can be allocated much more efficiently by subdividing a single
+ * large array of bits
+ */
+void allocDeps(PtrVarState[] pvss)
+{
+ //printf("allocDeps()\n");
+ foreach (ref pvs; pvss)
+ {
+ pvs.deps.length = pvss.length;
+ }
+}
+
+
+/**************************************
+ * Allocate state variables foreach node.
+ */
+void allocStates(ref ObState obstate)
+{
+ //printf("---------------allocStates()------------------\n");
+ const vlen = obstate.vars.length;
+ PtrVarState* p = cast(PtrVarState*) mem.xcalloc(obstate.nodes.length * 3 * vlen, PtrVarState.sizeof);
+ obstate.varPool = p[0 .. obstate.nodes.length * 3 * vlen];
+ foreach (i, ob; obstate.nodes)
+ {
+ //printf(" [%d]\n", cast(int)i);
+// ob.kill.length = obstate.vars.length;
+// ob.comb.length = obstate.vars.length;
+ ob.gen = p[0 .. vlen]; p += vlen;
+ ob.input = p[0 .. vlen]; p += vlen;
+ ob.output = p[0 .. vlen]; p += vlen;
+
+ allocDeps(ob.gen);
+ allocDeps(ob.input);
+ allocDeps(ob.output);
+ }
+}
+
+/******************************
+ * Does v meet the definiton of a `Borrowed` pointer?
+ * Returns:
+ * true if it does
+ */
+bool isBorrowedPtr(VarDeclaration v)
+{
+ return v.isScope() && !v.isowner && v.type.nextOf().isMutable();
+}
+
+/******************************
+ * Does v meet the definiton of a `Readonly` pointer?
+ * Returns:
+ * true if it does
+ */
+bool isReadonlyPtr(VarDeclaration v)
+{
+ return v.isScope() && !v.type.nextOf().isMutable();
+}
+
+/***************************************
+ * Compute the gen vector for ob.
+ */
+void genKill(ref ObState obstate, ObNode* ob)
+{
+ enum log = false;
+ if (log)
+ printf("-----------computeGenKill()-----------\n");
+
+ /***************
+ * Assigning result of expression `e` to variable `v`.
+ */
+ void dgWriteVar(ObNode* ob, VarDeclaration v, Expression e, bool initializer)
+ {
+ if (log)
+ printf("dgWriteVar() %s := %s %d\n", v.toChars(), e.toChars(), initializer);
+ const vi = obstate.vars.find(v);
+ assert(vi != size_t.max);
+ PtrVarState* pvs = &ob.gen[vi];
+ readVar(ob, vi, true, ob.gen);
+ if (e)
+ {
+ if (isBorrowedPtr(v))
+ pvs.state = PtrState.Borrowed;
+ else if (isReadonlyPtr(v))
+ pvs.state = PtrState.Readonly;
+ else
+ pvs.state = PtrState.Owner;
+ pvs.deps.zero();
+
+ EscapeByResults er;
+ escapeByValue(e, &er, true);
+ bool any = false; // if any variables are assigned to v
+
+ void by(VarDeclaration r)
+ {
+ const ri = obstate.vars.find(r);
+ if (ri != size_t.max && ri != vi)
+ {
+ pvs.deps[ri] = true; // v took from r
+ auto pvsr = &ob.gen[ri];
+ any = true;
+
+ if (isBorrowedPtr(v))
+ {
+ // v is borrowing from r
+ pvs.state = PtrState.Borrowed;
+ }
+ else if (isReadonlyPtr(v))
+ {
+ pvs.state = PtrState.Readonly;
+ }
+ else
+ {
+ // move r to v, which "consumes" r
+ pvsr.state = PtrState.Undefined;
+ pvsr.deps.zero();
+ }
+ }
+ }
+
+ foreach (VarDeclaration v2; er.byvalue)
+ by(v2);
+ foreach (VarDeclaration v2; er.byref)
+ by(v2);
+
+ /* Make v an Owner for initializations like:
+ * scope v = malloc();
+ */
+ if (initializer && !any && isBorrowedPtr(v))
+ {
+ v.isowner = true;
+ pvs.state = PtrState.Owner;
+ }
+ }
+ else
+ {
+ if (isBorrowedPtr(v))
+ pvs.state = PtrState.Borrowed;
+ else if (isReadonlyPtr(v))
+ pvs.state = PtrState.Readonly;
+ else
+ pvs.state = PtrState.Owner;
+ pvs.deps.zero();
+ }
+ }
+
+ void dgReadVar(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable)
+ {
+ if (log)
+ printf("dgReadVar() %s %d\n", v.toChars(), mutable);
+ const vi = obstate.vars.find(v);
+ assert(vi != size_t.max);
+ readVar(ob, vi, mutable, ob.gen);
+ }
+
+ void foreachExp(ObNode* ob, Expression e)
+ {
+ extern (C++) final class ExpWalker : Visitor
+ {
+ alias visit = typeof(super).visit;
+ extern (D) void delegate(ObNode*, VarDeclaration, Expression, bool) dgWriteVar;
+ extern (D) void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable) dgReadVar;
+ ObNode* ob;
+ ObState* obstate;
+
+ extern (D) this(void delegate(ObNode*, VarDeclaration, Expression, bool) dgWriteVar,
+ void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable) dgReadVar,
+ ObNode* ob, ref ObState obstate)
+ {
+ this.dgWriteVar = dgWriteVar;
+ this.dgReadVar = dgReadVar;
+ this.ob = ob;
+ this.obstate = &obstate;
+ }
+
+ override void visit(Expression e)
+ {
+ //printf("[%s] %s: %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars());
+ //assert(0);
+ }
+
+ void visitAssign(AssignExp ae, bool initializer)
+ {
+ ae.e2.accept(this);
+ if (auto ve = ae.e1.isVarExp())
+ {
+ if (auto v = ve.var.isVarDeclaration())
+ if (isTrackableVar(v))
+ dgWriteVar(ob, v, ae.e2, initializer);
+ }
+ else
+ ae.e1.accept(this);
+ }
+
+ override void visit(AssignExp ae)
+ {
+ visitAssign(ae, false);
+ }
+
+ override void visit(DeclarationExp e)
+ {
+ void Dsymbol_visit(Dsymbol s)
+ {
+ if (auto vd = s.isVarDeclaration())
+ {
+ s = s.toAlias();
+ if (s != vd)
+ return Dsymbol_visit(s);
+ if (!isTrackableVar(vd))
+ return;
+
+ if (!(vd._init && vd._init.isVoidInitializer()))
+ {
+ auto ei = vd._init ? vd._init.isExpInitializer() : null;
+ if (ei)
+ visitAssign(cast(AssignExp)ei.exp, true);
+ else
+ dgWriteVar(ob, vd, null, false);
+ }
+ }
+ else if (auto td = s.isTupleDeclaration())
+ {
+ foreach (o; *td.objects)
+ {
+ if (auto eo = o.isExpression())
+ {
+ if (auto se = eo.isDsymbolExp())
+ {
+ Dsymbol_visit(se.s);
+ }
+ }
+ }
+ }
+ }
+
+ Dsymbol_visit(e.declaration);
+ }
+
+ override void visit(VarExp ve)
+ {
+ //printf("VarExp: %s\n", ve.toChars());
+ if (auto v = ve.var.isVarDeclaration())
+ if (isTrackableVar(v))
+ {
+ dgReadVar(ve.loc, ob, v, isMutableRef(ve.type));
+ }
+ }
+
+ override void visit(CallExp ce)
+ {
+ //printf("CallExp() %s\n", ce.toChars());
+ ce.e1.accept(this);
+ auto t = ce.e1.type.toBasetype();
+ auto tf = t.isTypeFunction();
+ if (!tf)
+ {
+ assert(t.ty == Tdelegate);
+ tf = t.nextOf().isTypeFunction();
+ assert(tf);
+ }
+
+ // j=1 if _arguments[] is first argument
+ const int j = tf.isDstyleVariadic();
+ bool hasOut;
+ const varStackSave = obstate.varStack.length;
+
+ foreach (const i, arg; (*ce.arguments)[])
+ {
+ if (i - j < tf.parameterList.length &&
+ i >= j)
+ {
+ Parameter p = tf.parameterList[i - j];
+ auto pt = p.type.toBasetype();
+
+ EscapeByResults er;
+ escapeByValue(arg, &er, true);
+
+ if (!(p.storageClass & STC.out_ && arg.isVarExp()))
+ arg.accept(this);
+
+ void by(VarDeclaration v)
+ {
+ if (!isTrackableVar(v))
+ return;
+
+ const vi = obstate.vars.find(v);
+ if (vi == size_t.max)
+ return;
+
+ if (p.storageClass & STC.out_)
+ {
+ /// initialize
+ hasOut = true;
+ makeUndefined(vi, ob.gen);
+ }
+ else if (p.storageClass & STC.scope_)
+ {
+ // borrow
+ obstate.varStack.push(vi);
+ obstate.mutableStack.push(isMutableRef(pt));
+ }
+ else
+ {
+ // move (i.e. consume arg)
+ makeUndefined(vi, ob.gen);
+ }
+ }
+
+ foreach (VarDeclaration v2; er.byvalue)
+ by(v2);
+ foreach (VarDeclaration v2; er.byref)
+ by(v2);
+ }
+ else // variadic args
+ {
+ arg.accept(this);
+
+ EscapeByResults er;
+ escapeByValue(arg, &er, true);
+
+ void byv(VarDeclaration v)
+ {
+ if (!isTrackableVar(v))
+ return;
+
+ const vi = obstate.vars.find(v);
+ if (vi == size_t.max)
+ return;
+
+ if (tf.parameterList.stc & STC.scope_)
+ {
+ // borrow
+ obstate.varStack.push(vi);
+ obstate.mutableStack.push(isMutableRef(arg.type) &&
+ !(tf.parameterList.stc & (STC.const_ | STC.immutable_)));
+ }
+ else
+ // move (i.e. consume arg)
+ makeUndefined(vi, ob.gen);
+ }
+
+ foreach (VarDeclaration v2; er.byvalue)
+ byv(v2);
+ foreach (VarDeclaration v2; er.byref)
+ byv(v2);
+ }
+ }
+
+ /* Do a dummy 'read' of each variable passed to the function,
+ * to detect O/B errors
+ */
+ assert(obstate.varStack.length == obstate.mutableStack.length);
+ foreach (i; varStackSave .. obstate.varStack.length)
+ {
+ const vi = obstate.varStack[i];
+ // auto pvs = &ob.gen[vi];
+ auto v = obstate.vars[vi];
+ //if (pvs.state == PtrState.Undefined)
+ //v.error(ce.loc, "is Undefined, cannot pass to function");
+
+ dgReadVar(ce.loc, ob, v, obstate.mutableStack[i]);
+ }
+
+ /* Pop off stack all variables for this function call
+ */
+ obstate.varStack.setDim(varStackSave);
+ obstate.mutableStack.setDim(varStackSave);
+
+ if (hasOut)
+ // Initialization of out's only happens after the function call
+ foreach (const i, arg; (*ce.arguments)[])
+ {
+ if (i - j < tf.parameterList.length &&
+ i >= j)
+ {
+ Parameter p = tf.parameterList[i - j];
+ if (p.storageClass & STC.out_)
+ {
+ if (auto v = isTrackableVarExp(arg))
+ dgWriteVar(ob, v, null, true);
+ }
+ }
+ }
+ }
+
+ override void visit(SymOffExp e)
+ {
+ if (auto v = e.var.isVarDeclaration())
+ if (isTrackableVar(v))
+ {
+ dgReadVar(e.loc, ob, v, isMutableRef(e.type));
+ }
+ }
+
+ override void visit(LogicalExp e)
+ {
+ e.e1.accept(this);
+
+ const vlen = obstate.vars.length;
+ auto p = cast(PtrVarState*)mem.xcalloc(vlen, PtrVarState.sizeof);
+ PtrVarState[] gen1 = p[0 .. vlen];
+ foreach (i, ref pvs; gen1)
+ {
+ pvs = ob.gen[i];
+ }
+
+ e.e2.accept(this);
+
+ // Merge gen1 into ob.gen
+ foreach (i; 0 .. vlen)
+ {
+ ob.gen[i].combine(gen1[i], i, ob.gen);
+ }
+
+ mem.xfree(p); // should free .deps too
+ }
+
+ override void visit(CondExp e)
+ {
+ e.econd.accept(this);
+
+ const vlen = obstate.vars.length;
+ auto p = cast(PtrVarState*)mem.xcalloc(vlen, PtrVarState.sizeof);
+ PtrVarState[] gen1 = p[0 .. vlen];
+ foreach (i, ref pvs; gen1)
+ {
+ pvs = ob.gen[i];
+ }
+
+ e.e1.accept(this);
+
+ // Swap gen1 with ob.gen
+ foreach (i; 0 .. vlen)
+ {
+ gen1[i].deps.swap(ob.gen[i].deps);
+ const state = gen1[i].state;
+ gen1[i].state = ob.gen[i].state;
+ ob.gen[i].state = state;
+ }
+
+ e.e2.accept(this);
+
+ /* xxx1 is the state from expression e1, ob.xxx is the state from e2.
+ * Merge xxx1 into ob.xxx to get the state from `e`.
+ */
+ foreach (i; 0 .. vlen)
+ {
+ ob.gen[i].combine(gen1[i], i, ob.gen);
+ }
+
+ mem.xfree(p); // should free .deps too
+ }
+
+ override void visit(AddrExp e)
+ {
+ /* Taking the address of struct literal is normally not
+ * allowed, but CTFE can generate one out of a new expression,
+ * but it'll be placed in static data so no need to check it.
+ */
+ if (e.e1.op != TOK.structLiteral)
+ e.e1.accept(this);
+ }
+
+ override void visit(UnaExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(BinExp e)
+ {
+ e.e1.accept(this);
+ e.e2.accept(this);
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ Type tb = e.type.toBasetype();
+ if (tb.ty == Tsarray || tb.ty == Tarray)
+ {
+ if (e.basis)
+ e.basis.accept(this);
+ foreach (el; *e.elements)
+ {
+ if (el)
+ el.accept(this);
+ }
+ }
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ if (e.elements)
+ {
+ foreach (ex; *e.elements)
+ {
+ if (ex)
+ ex.accept(this);
+ }
+ }
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ if (e.keys)
+ {
+ foreach (i, key; *e.keys)
+ {
+ if (key)
+ key.accept(this);
+ if (auto value = (*e.values)[i])
+ value.accept(this);
+ }
+ }
+ }
+
+ override void visit(NewExp e)
+ {
+ if (e.arguments)
+ {
+ foreach (ex; *e.arguments)
+ {
+ if (ex)
+ ex.accept(this);
+ }
+ }
+ }
+
+ override void visit(SliceExp e)
+ {
+ e.e1.accept(this);
+ if (e.lwr)
+ e.lwr.accept(this);
+ if (e.upr)
+ e.upr.accept(this);
+ }
+ }
+
+ if (e)
+ {
+ scope ExpWalker ew = new ExpWalker(&dgWriteVar, &dgReadVar, ob, obstate);
+ e.accept(ew);
+ }
+ }
+
+ foreachExp(ob, ob.exp);
+}
+
+/***************************************
+ * Determine the state of a variable based on
+ * its type and storage class.
+ */
+PtrState toPtrState(VarDeclaration v)
+{
+ /* pointer to mutable: Owner
+ * pointer to mutable, scope: Borrowed
+ * pointer to const: Owner
+ * pointer to const, scope: Readonly
+ * ref: Borrowed
+ * const ref: Readonly
+ */
+
+ auto t = v.type;
+ if (v.isRef())
+ {
+ return t.hasMutableFields() ? PtrState.Borrowed : PtrState.Readonly;
+ }
+ if (v.isScope())
+ {
+ return t.hasPointersToMutableFields() ? PtrState.Borrowed : PtrState.Readonly;
+ }
+ else
+ return PtrState.Owner;
+}
+
+/**********************************
+ * Does type `t` contain any pointers to mutable?
+ */
+bool hasPointersToMutableFields(Type t)
+{
+ auto tb = t.toBasetype();
+ if (!tb.isMutable())
+ return false;
+ if (auto tsa = tb.isTypeSArray())
+ {
+ return tsa.nextOf().hasPointersToMutableFields();
+ }
+ if (auto ts = tb.isTypeStruct())
+ {
+ foreach (v; ts.sym.fields)
+ {
+ if (v.isRef())
+ {
+ if (v.type.hasMutableFields())
+ return true;
+ }
+ else if (v.type.hasPointersToMutableFields())
+ return true;
+ }
+ return false;
+ }
+ auto tbn = tb.nextOf();
+ return tbn && tbn.hasMutableFields();
+}
+
+/********************************
+ * Does type `t` have any mutable fields?
+ */
+bool hasMutableFields(Type t)
+{
+ auto tb = t.toBasetype();
+ if (!tb.isMutable())
+ return false;
+ if (auto tsa = tb.isTypeSArray())
+ {
+ return tsa.nextOf().hasMutableFields();
+ }
+ if (auto ts = tb.isTypeStruct())
+ {
+ foreach (v; ts.sym.fields)
+ {
+ if (v.type.hasMutableFields())
+ return true;
+ }
+ return false;
+ }
+ return true;
+}
+
+
+
+/***************************************
+ * Do the data flow analysis (i.e. compute the input[]
+ * and output[] vectors for each ObNode).
+ */
+void doDataFlowAnalysis(ref ObState obstate)
+{
+ enum log = false;
+ if (log)
+ {
+ printf("-----------------doDataFlowAnalysis()-------------------------\n");
+ foreach (ob; obstate.nodes) ob.print();
+ printf("------------------------------------------\n");
+ }
+
+ if (!obstate.nodes.length)
+ return;
+
+ auto startnode = obstate.nodes[0];
+ assert(startnode.preds.length == 0);
+
+ /* Set opening state `input[]` for first node
+ */
+ foreach (i, ref ps; startnode.input)
+ {
+ auto v = obstate.vars[i];
+ auto state = toPtrState(v);
+ if (v.isParameter())
+ {
+ if (v.isOut())
+ state = PtrState.Undefined;
+ else if (v.isBorrowedPtr())
+ state = PtrState.Borrowed;
+ else
+ state = PtrState.Owner;
+ }
+ else
+ state = PtrState.Undefined;
+ ps.state = state;
+ ps.deps.zero();
+ startnode.gen[i] = ps;
+ }
+
+ /* Set all output[]s to Initial
+ */
+ foreach (ob; obstate.nodes[])
+ {
+ foreach (ref ps; ob.output)
+ {
+ ps.state = PtrState.Initial;
+ ps.deps.zero();
+ }
+ }
+
+ const vlen = obstate.vars.length;
+ PtrVarState pvs;
+ pvs.deps.length = vlen;
+ int counter = 0;
+ bool changes;
+ do
+ {
+ changes = false;
+ assert(++counter <= 1000); // should converge, but don't hang if it doesn't
+ foreach (ob; obstate.nodes[])
+ {
+ /* Construct ob.gen[] by combining the .output[]s of each ob.preds[]
+ * and set ob.input[] to the same state
+ */
+ if (ob != startnode)
+ {
+ assert(ob.preds.length);
+
+ foreach (i; 0 .. vlen)
+ {
+ ob.gen[i] = ob.preds[0].output[i];
+ }
+
+ foreach (j; 1 .. ob.preds.length)
+ {
+ foreach (i; 0 .. vlen)
+ {
+ ob.gen[i].combine(ob.preds[j].output[i], i, ob.gen);
+ }
+ }
+
+ /* Set ob.input[] to ob.gen[],
+ * if any changes were made we'll have to do another iteration
+ */
+ foreach (i; 0 .. vlen)
+ {
+ if (ob.gen[i] != ob.input[i])
+ {
+ ob.input[i] = ob.gen[i];
+ changes = true;
+ }
+ }
+ }
+
+ /* Compute gen[] for node ob
+ */
+ genKill(obstate, ob);
+
+ foreach (i; 0 .. vlen)
+ {
+ if (ob.gen[i] != ob.output[i])
+ {
+ ob.output[i] = ob.gen[i];
+ changes = true;
+ }
+ }
+ }
+ } while (changes);
+
+ static if (log)
+ {
+ foreach (obi, ob; obstate.nodes)
+ {
+ printf("%d: %s\n", obi, ob.exp ? ob.exp.toChars() : "".ptr);
+ printf(" input:\n");
+ foreach (i, ref pvs2; ob.input[])
+ {
+ printf(" %s: ", obstate.vars[i].toChars()); pvs2.print(obstate.vars[]);
+ }
+
+ printf(" gen:\n");
+ foreach (i, ref pvs2; ob.gen[])
+ {
+ printf(" %s: ", obstate.vars[i].toChars()); pvs2.print(obstate.vars[]);
+ }
+ printf(" output:\n");
+ foreach (i, ref pvs2; ob.output[])
+ {
+ printf(" %s: ", obstate.vars[i].toChars()); pvs2.print(obstate.vars[]);
+ }
+ }
+ printf("\n");
+ }
+}
+
+
+/***************************************
+ * Check for Ownership/Borrowing errors.
+ */
+void checkObErrors(ref ObState obstate)
+{
+ enum log = false;
+ if (log)
+ printf("------------checkObErrors()----------\n");
+
+ void dgWriteVar(ObNode* ob, PtrVarState[] cpvs, VarDeclaration v, Expression e)
+ {
+ if (log) printf("dgWriteVar(v:%s, e:%s)\n", v.toChars(), e ? e.toChars() : "null");
+ const vi = obstate.vars.find(v);
+ assert(vi != size_t.max);
+ PtrVarState* pvs = &cpvs[vi];
+ readVar(ob, vi, true, cpvs);
+ if (e)
+ {
+ if (isBorrowedPtr(v))
+ pvs.state = PtrState.Borrowed;
+ else if (isReadonlyPtr(v))
+ pvs.state = PtrState.Readonly;
+ else
+ pvs.state = PtrState.Owner;
+ pvs.deps.zero();
+
+ EscapeByResults er;
+ escapeByValue(e, &er, true);
+
+ void by(VarDeclaration r) // `v` = `r`
+ {
+ //printf(" by(%s)\n", r.toChars());
+ const ri = obstate.vars.find(r);
+ if (ri == size_t.max)
+ return;
+
+ with (PtrState)
+ {
+ pvs.deps[ri] = true; // v took from r
+ auto pvsr = &cpvs[ri];
+
+ if (pvsr.state == Undefined)
+ {
+ v.error(e.loc, "is reading from `%s` which is Undefined", r.toChars());
+ }
+ else if (isBorrowedPtr(v)) // v is going to borrow from r
+ {
+ if (pvsr.state == Readonly)
+ v.error(e.loc, "is borrowing from `%s` which is Readonly", r.toChars());
+
+ pvs.state = Borrowed;
+ }
+ else if (isReadonlyPtr(v))
+ {
+ pvs.state = Readonly;
+ }
+ else
+ {
+ // move from r to v
+ pvsr.state = Undefined;
+ pvsr.deps.zero();
+ }
+ }
+ }
+
+ foreach (VarDeclaration v2; er.byvalue)
+ by(v2);
+ foreach (VarDeclaration v2; er.byref)
+ by(v2);
+ }
+ else
+ {
+ if (isBorrowedPtr(v))
+ pvs.state = PtrState.Borrowed;
+ else if (isReadonlyPtr(v))
+ pvs.state = PtrState.Readonly;
+ else
+ pvs.state = PtrState.Owner;
+ pvs.deps.zero();
+ }
+ }
+
+ void dgReadVar(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[] gen)
+ {
+ if (log) printf("dgReadVar() %s\n", v.toChars());
+ const vi = obstate.vars.find(v);
+ assert(vi != size_t.max);
+ auto pvs = &gen[vi];
+ if (pvs.state == PtrState.Undefined)
+ v.error(loc, "has undefined state and cannot be read");
+
+ readVar(ob, vi, mutable, gen);
+ }
+
+ void foreachExp(ObNode* ob, Expression e, PtrVarState[] cpvs)
+ {
+ extern (C++) final class ExpWalker : Visitor
+ {
+ alias visit = typeof(super).visit;
+ extern (D) void delegate(ObNode*, PtrVarState[], VarDeclaration, Expression) dgWriteVar;
+ extern (D) void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[]) dgReadVar;
+ PtrVarState[] cpvs;
+ ObNode* ob;
+ ObState* obstate;
+
+ extern (D) this(void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[]) dgReadVar,
+ void delegate(ObNode*, PtrVarState[], VarDeclaration, Expression) dgWriteVar,
+ PtrVarState[] cpvs, ObNode* ob, ref ObState obstate)
+ {
+ this.dgReadVar = dgReadVar;
+ this.dgWriteVar = dgWriteVar;
+ this.cpvs = cpvs;
+ this.ob = ob;
+ this.obstate = &obstate;
+ }
+
+ override void visit(Expression)
+ {
+ }
+
+ override void visit(DeclarationExp e)
+ {
+ void Dsymbol_visit(Dsymbol s)
+ {
+ if (auto vd = s.isVarDeclaration())
+ {
+ s = s.toAlias();
+ if (s != vd)
+ return Dsymbol_visit(s);
+ if (!isTrackableVar(vd))
+ return;
+
+ if (vd._init && vd._init.isVoidInitializer())
+ return;
+
+ auto ei = vd._init ? vd._init.isExpInitializer() : null;
+ if (ei)
+ {
+ auto e = ei.exp;
+ if (auto ae = e.isConstructExp())
+ e = ae.e2;
+ dgWriteVar(ob, cpvs, vd, e);
+ }
+ else
+ dgWriteVar(ob, cpvs, vd, null);
+ }
+ else if (auto td = s.isTupleDeclaration())
+ {
+ foreach (o; *td.objects)
+ {
+ if (auto eo = o.isExpression())
+ {
+ if (auto se = eo.isDsymbolExp())
+ {
+ Dsymbol_visit(se.s);
+ }
+ }
+ }
+ }
+ }
+
+ Dsymbol_visit(e.declaration);
+ }
+
+ override void visit(AssignExp ae)
+ {
+ ae.e2.accept(this);
+ if (auto ve = ae.e1.isVarExp())
+ {
+ if (auto v = ve.var.isVarDeclaration())
+ if (isTrackableVar(v))
+ dgWriteVar(ob, cpvs, v, ae.e2);
+ }
+ else
+ ae.e1.accept(this);
+ }
+
+ override void visit(VarExp ve)
+ {
+ //printf("VarExp: %s\n", ve.toChars());
+ if (auto v = ve.var.isVarDeclaration())
+ if (isTrackableVar(v))
+ {
+ dgReadVar(ve.loc, ob, v, isMutableRef(ve.type), cpvs);
+ }
+ }
+
+ override void visit(CallExp ce)
+ {
+ //printf("CallExp(%s)\n", ce.toChars());
+ ce.e1.accept(this);
+ auto t = ce.e1.type.toBasetype();
+ auto tf = t.isTypeFunction();
+ if (!tf)
+ {
+ assert(t.ty == Tdelegate);
+ tf = t.nextOf().isTypeFunction();
+ assert(tf);
+ }
+
+ // j=1 if _arguments[] is first argument
+ const int j = tf.isDstyleVariadic();
+ bool hasOut;
+ const varStackSave = obstate.varStack.length;
+
+ foreach (const i, arg; (*ce.arguments)[])
+ {
+ if (i - j < tf.parameterList.length &&
+ i >= j)
+ {
+ Parameter p = tf.parameterList[i - j];
+ auto pt = p.type.toBasetype();
+
+ if (!(p.storageClass & STC.out_ && arg.isVarExp()))
+ arg.accept(this);
+
+ EscapeByResults er;
+ escapeByValue(arg, &er, true);
+
+ void by(VarDeclaration v)
+ {
+ if (!isTrackableVar(v))
+ return;
+
+ const vi = obstate.vars.find(v);
+ if (vi == size_t.max)
+ return;
+
+ auto pvs = &cpvs[vi];
+
+ if (p.storageClass & STC.out_)
+ {
+ /// initialize
+ hasOut = true;
+ makeUndefined(vi, cpvs);
+ }
+ else if (p.storageClass & STC.scope_)
+ {
+ // borrow
+ obstate.varStack.push(vi);
+ obstate.mutableStack.push(isMutableRef(pt));
+ }
+ else
+ {
+ // move (i.e. consume arg)
+ if (pvs.state != PtrState.Owner)
+ v.error(arg.loc, "is not Owner, cannot consume its value");
+ makeUndefined(vi, cpvs);
+ }
+ }
+
+ foreach (VarDeclaration v2; er.byvalue)
+ by(v2);
+ foreach (VarDeclaration v2; er.byref)
+ by(v2);
+ }
+ else // variadic args
+ {
+ arg.accept(this);
+
+ EscapeByResults er;
+ escapeByValue(arg, &er, true);
+
+ void byv(VarDeclaration v)
+ {
+ if (!isTrackableVar(v))
+ return;
+
+ const vi = obstate.vars.find(v);
+ if (vi == size_t.max)
+ return;
+
+ auto pvs = &cpvs[vi];
+
+ if (tf.parameterList.stc & STC.scope_)
+ {
+ // borrow
+ obstate.varStack.push(vi);
+ obstate.mutableStack.push(isMutableRef(arg.type) &&
+ !(tf.parameterList.stc & (STC.const_ | STC.immutable_)));
+ }
+ else
+ {
+ // move (i.e. consume arg)
+ if (pvs.state != PtrState.Owner)
+ v.error(arg.loc, "is not Owner, cannot consume its value");
+ makeUndefined(vi, cpvs);
+ }
+ }
+
+ foreach (VarDeclaration v2; er.byvalue)
+ byv(v2);
+ foreach (VarDeclaration v2; er.byref)
+ byv(v2);
+ }
+ }
+
+ /* Do a dummy 'read' of each variable passed to the function,
+ * to detect O/B errors
+ */
+ assert(obstate.varStack.length == obstate.mutableStack.length);
+ foreach (i; varStackSave .. obstate.varStack.length)
+ {
+ const vi = obstate.varStack[i];
+ auto pvs = &cpvs[vi];
+ auto v = obstate.vars[vi];
+ //if (pvs.state == PtrState.Undefined)
+ //v.error(ce.loc, "is Undefined, cannot pass to function");
+
+ dgReadVar(ce.loc, ob, v, obstate.mutableStack[i], cpvs);
+
+ if (pvs.state == PtrState.Owner)
+ {
+ for (size_t k = i + 1; k < obstate.varStack.length;++k)
+ {
+ const vk = obstate.varStack[k];
+ if (vk == vi)
+ {
+ if (obstate.mutableStack[vi] || obstate.mutableStack[vk])
+ {
+ v.error(ce.loc, "is passed as Owner more than once");
+ break; // no need to continue
+ }
+ }
+ }
+ }
+ }
+
+ /* Pop off stack all variables for this function call
+ */
+ obstate.varStack.setDim(varStackSave);
+ obstate.mutableStack.setDim(varStackSave);
+
+ if (hasOut)
+ // Initialization of out's only happens after the function call
+ foreach (const i, arg; (*ce.arguments)[])
+ {
+ if (i - j < tf.parameterList.length &&
+ i >= j)
+ {
+ Parameter p = tf.parameterList[i - j];
+ if (p.storageClass & STC.out_)
+ {
+ if (auto v = isTrackableVarExp(arg))
+ {
+ dgWriteVar(ob, cpvs, v, null);
+ }
+ }
+ }
+ }
+ }
+
+ override void visit(SymOffExp e)
+ {
+ if (auto v = e.var.isVarDeclaration())
+ if (isTrackableVar(v))
+ {
+ dgReadVar(e.loc, ob, v, isMutableRef(e.type), cpvs);
+ }
+ }
+
+ override void visit(LogicalExp e)
+ {
+ e.e1.accept(this);
+
+ const vlen = obstate.vars.length;
+ auto p = cast(PtrVarState*)mem.xcalloc(vlen, PtrVarState.sizeof);
+ PtrVarState[] out1 = p[0 .. vlen];
+ foreach (i, ref pvs; out1)
+ {
+ pvs = cpvs[i];
+ }
+
+ e.e2.accept(this);
+
+ // Merge out1 into cpvs
+ foreach (i; 0 .. vlen)
+ {
+ cpvs[i].combine(out1[i], i, cpvs);
+ }
+
+ mem.xfree(p); // should free .deps too
+ }
+
+ override void visit(CondExp e)
+ {
+ e.econd.accept(this);
+
+ const vlen = obstate.vars.length;
+ auto p = cast(PtrVarState*)mem.xcalloc(vlen, PtrVarState.sizeof);
+ PtrVarState[] out1 = p[0 .. vlen];
+ foreach (i, ref pvs; out1)
+ {
+ pvs = cpvs[i];
+ }
+
+ e.e1.accept(this);
+
+ // Swap out1 with cpvs
+ foreach (i; 0 .. vlen)
+ {
+ out1[i].deps.swap(cpvs[i].deps);
+ const state = out1[i].state;
+ out1[i].state = cpvs[i].state;
+ cpvs[i].state = state;
+ }
+
+ e.e2.accept(this);
+
+ // Merge out1 into cpvs
+ foreach (i; 0 .. vlen)
+ {
+ cpvs[i].combine(out1[i], i, cpvs);
+ }
+
+ mem.xfree(p); // should free .deps too
+ }
+
+ override void visit(AddrExp e)
+ {
+ /* Taking the address of struct literal is normally not
+ * allowed, but CTFE can generate one out of a new expression,
+ * but it'll be placed in static data so no need to check it.
+ */
+ if (e.e1.op != TOK.structLiteral)
+ e.e1.accept(this);
+ }
+
+ override void visit(UnaExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(BinExp e)
+ {
+ e.e1.accept(this);
+ e.e2.accept(this);
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ Type tb = e.type.toBasetype();
+ if (tb.ty == Tsarray || tb.ty == Tarray)
+ {
+ if (e.basis)
+ e.basis.accept(this);
+ foreach (el; *e.elements)
+ {
+ if (el)
+ el.accept(this);
+ }
+ }
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ if (e.elements)
+ {
+ foreach (ex; *e.elements)
+ {
+ if (ex)
+ ex.accept(this);
+ }
+ }
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ if (e.keys)
+ {
+ foreach (i, key; *e.keys)
+ {
+ if (key)
+ key.accept(this);
+ if (auto value = (*e.values)[i])
+ value.accept(this);
+ }
+ }
+ }
+
+ override void visit(NewExp e)
+ {
+ if (e.arguments)
+ {
+ foreach (ex; *e.arguments)
+ {
+ if (ex)
+ ex.accept(this);
+ }
+ }
+ }
+
+ override void visit(SliceExp e)
+ {
+ e.e1.accept(this);
+ if (e.lwr)
+ e.lwr.accept(this);
+ if (e.upr)
+ e.upr.accept(this);
+ }
+ }
+
+ if (e)
+ {
+ scope ExpWalker ew = new ExpWalker(&dgReadVar, &dgWriteVar, cpvs, ob, obstate);
+ e.accept(ew);
+ }
+ }
+
+ const vlen = obstate.vars.length;
+ auto p = cast(PtrVarState*)mem.xcalloc(vlen, PtrVarState.sizeof);
+ PtrVarState[] cpvs = p[0 .. vlen];
+ foreach (ref pvs; cpvs)
+ pvs.deps.length = vlen;
+
+ foreach (obi, ob; obstate.nodes)
+ {
+ static if (log)
+ {
+ printf("%d: %s\n", obi, ob.exp ? ob.exp.toChars() : "".ptr);
+ printf(" input:\n");
+ foreach (i, ref pvs; ob.input[])
+ {
+ printf(" %s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]);
+ }
+ }
+
+ /* Combine the .output[]s of each ob.preds[] looking for errors
+ */
+ if (obi) // skip startnode
+ {
+ assert(ob.preds.length);
+
+ foreach (i; 0 .. vlen)
+ {
+ ob.gen[i] = ob.preds[0].output[i];
+ }
+
+ foreach (j; 1 .. ob.preds.length)
+ {
+ foreach (i; 0 .. vlen)
+ {
+ auto pvs1 = &ob.gen[i];
+ auto pvs2 = &ob.preds[j].output[i];
+ const s1 = pvs1.state;
+ const s2 = pvs2.state;
+ if (s1 != s2 && (s1 == PtrState.Owner || s2 == PtrState.Owner))
+ {
+ auto v = obstate.vars[i];
+ v.error(ob.exp ? ob.exp.loc : v.loc, "is both %s and %s", s1.toChars(), s2.toChars());
+ }
+ pvs1.combine(*pvs2, i, ob.gen);
+ }
+ }
+ }
+
+ /* Prolly should use gen[] instead of cpvs[], or vice versa
+ */
+ foreach (i, ref pvs; ob.input)
+ {
+ cpvs[i] = pvs;
+ }
+
+ foreachExp(ob, ob.exp, cpvs);
+
+ static if (log)
+ {
+ printf(" cpvs:\n");
+ foreach (i, ref pvs; cpvs[])
+ {
+ printf(" %s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]);
+ }
+ printf(" output:\n");
+ foreach (i, ref pvs; ob.output[])
+ {
+ printf(" %s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]);
+ }
+ }
+
+ if (ob.obtype == ObType.retexp)
+ {
+ EscapeByResults er;
+ escapeByValue(ob.exp, &er, true);
+
+ void by(VarDeclaration r) // `r` is the rvalue
+ {
+ const ri = obstate.vars.find(r);
+ if (ri == size_t.max)
+ return;
+ with (PtrState)
+ {
+ auto pvsr = &ob.output[ri];
+ switch (pvsr.state)
+ {
+ case Undefined:
+ r.error(ob.exp.loc, "is returned but is Undefined");
+ break;
+
+ case Owner:
+ pvsr.state = Undefined; // returning a pointer "consumes" it
+ break;
+
+ case Borrowed:
+ case Readonly:
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+ }
+
+ foreach (VarDeclaration v2; er.byvalue)
+ by(v2);
+ foreach (VarDeclaration v2; er.byref)
+ by(v2);
+ }
+
+ if (ob.obtype == ObType.return_ || ob.obtype == ObType.retexp)
+ {
+ foreach (i, ref pvs; ob.output[])
+ {
+ //printf("%s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]);
+ if (pvs.state == PtrState.Owner)
+ {
+ auto v = obstate.vars[i];
+ if (v.type.hasPointers())
+ v.error(v.loc, "is left dangling at return");
+ }
+ }
+ }
+ }
+}
+
+
+/***************************************************
+ * Read from variable vi.
+ * The beginning of the 'scope' of a variable is when it is first read.
+ * Hence, when a read is done, instead of when assignment to the variable is done, the O/B rules are enforced.
+ * (Also called "non-lexical scoping".)
+ */
+void readVar(ObNode* ob, const size_t vi, bool mutable, PtrVarState[] gen)
+{
+ //printf("readVar(v%d)\n", cast(int)vi);
+ auto pvso = &gen[vi];
+ switch (pvso.state)
+ {
+ case PtrState.Owner:
+ //printf("t: %s\n", t.toChars());
+ if (mutable) // if mutable read
+ {
+ makeChildrenUndefined(vi, gen);
+ }
+ else // const read
+ {
+ // If there's a Borrow child, set that to Undefined
+ foreach (di; 0 .. gen.length)
+ {
+ auto pvsd = &gen[di];
+ if (pvsd.deps[vi] && pvsd.state == PtrState.Borrowed) // if di borrowed vi
+ {
+ makeUndefined(di, gen);
+ }
+ }
+ }
+ break;
+
+ case PtrState.Borrowed:
+ /* All children become Undefined
+ */
+ makeChildrenUndefined(vi, gen);
+ break;
+
+ case PtrState.Readonly:
+ break;
+
+ case PtrState.Undefined:
+ break;
+
+ default:
+ break;
+ }
+}
+
+/********************
+ * Recursively make Undefined all who list vi as a dependency
+ */
+void makeChildrenUndefined(size_t vi, PtrVarState[] gen)
+{
+ //printf("makeChildrenUndefined(%d)\n", vi);
+ foreach (di; 0 .. gen.length)
+ {
+ if (gen[di].deps[vi]) // if di depends on vi
+ {
+ if (gen[di].state != PtrState.Undefined)
+ {
+ gen[di].state = PtrState.Undefined; // set this first to avoid infinite recursion
+ makeChildrenUndefined(di, gen);
+ gen[di].deps.zero();
+ }
+ }
+ }
+}
+
+
+/********************
+ * Recursively make Undefined vi undefined and all who list vi as a dependency
+ */
+void makeUndefined(size_t vi, PtrVarState[] gen)
+{
+ auto pvs = &gen[vi];
+ pvs.state = PtrState.Undefined; // set this first to avoid infinite recursion
+ makeChildrenUndefined(vi, gen);
+ pvs.deps.zero();
+}
+
+/*************************
+ * Is type `t` a reference to a const or a reference to a mutable?
+ */
+bool isMutableRef(Type t)
+{
+ auto tb = t.toBasetype();
+ return (tb.nextOf() ? tb.nextOf() : tb).isMutable();
+}
diff --git a/gcc/d/dmd/objc.c b/gcc/d/dmd/objc.c
deleted file mode 100644
index 3199a01..0000000
--- a/gcc/d/dmd/objc.c
+++ /dev/null
@@ -1,84 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 2015-2021 by The D Language Foundation, All Rights Reserved
- * written by Michel Fortin
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/objc_stubs.c
- */
-
-#include "objc.h"
-#include "aggregate.h"
-#include "scope.h"
-
-class FuncDeclaration;
-
-// MARK: ObjcSelector
-
-ObjcSelector::ObjcSelector(const char *, size_t, size_t)
-{
- printf("Should never be called when D_OBJC is false\n");
- assert(0);
-}
-
-ObjcSelector *ObjcSelector::lookup(const char *)
-{
- printf("Should never be called when D_OBJC is false\n");
- assert(0);
- return NULL;
-}
-
-ObjcSelector *ObjcSelector::lookup(const char *, size_t, size_t)
-{
- printf("Should never be called when D_OBJC is false\n");
- assert(0);
- return NULL;
-}
-
-ObjcSelector *ObjcSelector::create(FuncDeclaration *)
-{
- printf("Should never be called when D_OBJC is false\n");
- assert(0);
- return NULL;
-}
-
-class UnsupportedObjc : public Objc
-{
- void setObjc(ClassDeclaration *cd)
- {
- cd->error("Objective-C classes not supported");
- }
-
- void setObjc(InterfaceDeclaration *id)
- {
- id->error("Objective-C interfaces not supported");
- }
-
- void setSelector(FuncDeclaration *, Scope *)
- {
- // noop
- }
-
- void validateSelector(FuncDeclaration *)
- {
- // noop
- }
-
- void checkLinkage(FuncDeclaration *)
- {
- // noop
- }
-};
-
-static Objc *_objc;
-
-Objc *objc()
-{
- return _objc;
-}
-
-void Objc::_init()
-{
- _objc = new UnsupportedObjc();
-}
diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d
new file mode 100644
index 0000000..85e371e
--- /dev/null
+++ b/gcc/d/dmd/objc.d
@@ -0,0 +1,953 @@
+/**
+ * Interfacing with Objective-C.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/objc_interface.html, Interfacing to Objective-C)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/objc.d, _objc.d)
+ * Documentation: https://dlang.org/phobos/dmd_objc.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/objc.d
+ */
+
+module dmd.objc;
+
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.cond;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dmangle;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.gluelayer;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.root.array;
+import dmd.root.outbuffer;
+import dmd.root.stringtable;
+import dmd.target;
+import dmd.tokens;
+
+struct ObjcSelector
+{
+ // MARK: Selector
+ private __gshared StringTable!(ObjcSelector*) stringtable;
+ private __gshared int incnum = 0;
+ const(char)* stringvalue;
+ size_t stringlen;
+ size_t paramCount;
+
+ extern (C++) static void _init()
+ {
+ stringtable._init();
+ }
+
+ extern (D) this(const(char)* sv, size_t len, size_t pcount)
+ {
+ stringvalue = sv;
+ stringlen = len;
+ paramCount = pcount;
+ }
+
+ extern (D) static ObjcSelector* lookup(const(char)* s)
+ {
+ size_t len = 0;
+ size_t pcount = 0;
+ const(char)* i = s;
+ while (*i != 0)
+ {
+ ++len;
+ if (*i == ':')
+ ++pcount;
+ ++i;
+ }
+ return lookup(s, len, pcount);
+ }
+
+ extern (D) static ObjcSelector* lookup(const(char)* s, size_t len, size_t pcount)
+ {
+ auto sv = stringtable.update(s, len);
+ ObjcSelector* sel = sv.value;
+ if (!sel)
+ {
+ sel = new ObjcSelector(sv.toDchars(), len, pcount);
+ sv.value = sel;
+ }
+ return sel;
+ }
+
+ extern (C++) static ObjcSelector* create(FuncDeclaration fdecl)
+ {
+ OutBuffer buf;
+ TypeFunction ftype = cast(TypeFunction)fdecl.type;
+ const id = fdecl.ident.toString();
+ const nparams = ftype.parameterList.length;
+ // Special case: property setter
+ if (ftype.isproperty && nparams == 1)
+ {
+ // rewrite "identifier" as "setIdentifier"
+ char firstChar = id[0];
+ if (firstChar >= 'a' && firstChar <= 'z')
+ firstChar = cast(char)(firstChar - 'a' + 'A');
+ buf.writestring("set");
+ buf.writeByte(firstChar);
+ buf.write(id[1 .. id.length - 1]);
+ buf.writeByte(':');
+ goto Lcomplete;
+ }
+ // write identifier in selector
+ buf.write(id[]);
+ // add mangled type and colon for each parameter
+ if (nparams)
+ {
+ buf.writeByte('_');
+ foreach (i, fparam; ftype.parameterList)
+ {
+ mangleToBuffer(fparam.type, &buf);
+ buf.writeByte(':');
+ }
+ }
+ Lcomplete:
+ buf.writeByte('\0');
+ // the slice is not expected to include a terminating 0
+ return lookup(cast(const(char)*)buf[].ptr, buf.length - 1, nparams);
+ }
+
+ extern (D) const(char)[] toString() const pure
+ {
+ return stringvalue[0 .. stringlen];
+ }
+}
+
+private __gshared Objc _objc;
+
+Objc objc()
+{
+ return _objc;
+}
+
+
+/**
+ * Contains all data for a class declaration that is needed for the Objective-C
+ * integration.
+ */
+extern (C++) struct ObjcClassDeclaration
+{
+ /// `true` if this class is a metaclass.
+ bool isMeta = false;
+
+ /// `true` if this class is externally defined.
+ bool isExtern = false;
+
+ /// Name of this class.
+ Identifier identifier;
+
+ /// The class declaration this belongs to.
+ ClassDeclaration classDeclaration;
+
+ /// The metaclass of this class.
+ ClassDeclaration metaclass;
+
+ /// List of non-inherited methods.
+ FuncDeclaration[] methodList;
+
+ extern (D) this(ClassDeclaration classDeclaration)
+ {
+ this.classDeclaration = classDeclaration;
+ }
+
+ bool isRootClass() const
+ {
+ return classDeclaration.classKind == ClassKind.objc &&
+ !metaclass &&
+ !classDeclaration.baseClass;
+ }
+}
+
+/**
+ * Contains all data for a function declaration that is needed for the
+ * Objective-C integration.
+ */
+extern (C++) struct ObjcFuncDeclaration
+{
+ /// The method selector (member functions only).
+ ObjcSelector* selector;
+
+ /// The implicit selector parameter.
+ VarDeclaration selectorParameter;
+
+ /// `true` if this function declaration is declared optional.
+ bool isOptional;
+}
+
+// Should be an interface
+extern(C++) abstract class Objc
+{
+ static void _init()
+ {
+ if (target.objc.supported)
+ _objc = new Supported;
+ else
+ _objc = new Unsupported;
+ }
+
+ /**
+ * Deinitializes the global state of the compiler.
+ *
+ * This can be used to restore the state set by `_init` to its original
+ * state.
+ */
+ static void deinitialize()
+ {
+ _objc = _objc.init;
+ }
+
+ abstract void setObjc(ClassDeclaration cd);
+ abstract void setObjc(InterfaceDeclaration);
+
+ /**
+ * Returns a pretty textual representation of the given class declaration.
+ *
+ * Params:
+ * classDeclaration = the class declaration to return the textual representation for
+ * qualifyTypes = `true` if types should be qualified in the result
+ *
+ * Returns: the textual representation
+ */
+ abstract const(char)* toPrettyChars(ClassDeclaration classDeclaration, bool qualifyTypes) const;
+
+ abstract void setSelector(FuncDeclaration, Scope* sc);
+ abstract void validateSelector(FuncDeclaration fd);
+ abstract void checkLinkage(FuncDeclaration fd);
+
+ /**
+ * Returns `true` if the given function declaration is virtual.
+ *
+ * Function declarations with Objective-C linkage and which are static or
+ * final are considered virtual.
+ *
+ * Params:
+ * fd = the function declaration to check if it's virtual
+ *
+ * Returns: `true` if the given function declaration is virtual
+ */
+ abstract bool isVirtual(const FuncDeclaration fd) const;
+
+ /**
+ * Marks the given function declaration as optional.
+ *
+ * A function declaration is considered optional if it's annotated with the
+ * UDA: `@(core.attribute.optional)`. Only function declarations inside
+ * interface declarations and with Objective-C linkage can be declared as
+ * optional.
+ *
+ * Params:
+ * functionDeclaration = the function declaration to be set as optional
+ * sc = the scope from the semantic phase
+ */
+ abstract void setAsOptional(FuncDeclaration functionDeclaration, Scope* sc) const;
+
+ /**
+ * Validates function declarations declared optional.
+ *
+ * Params:
+ * functionDeclaration = the function declaration to validate
+ */
+ abstract void validateOptional(FuncDeclaration functionDeclaration) const;
+
+ /**
+ * Gets the parent of the given function declaration.
+ *
+ * Handles Objective-C static member functions, which are virtual functions
+ * of the metaclass, by returning the parent class declaration to the
+ * metaclass.
+ *
+ * Params:
+ * fd = the function declaration to get the parent of
+ * cd = the current parent, i.e. the class declaration the given function
+ * declaration belongs to
+ *
+ * Returns: the parent
+ */
+ abstract ClassDeclaration getParent(FuncDeclaration fd,
+ ClassDeclaration cd) const;
+
+ /**
+ * Adds the given function to the list of Objective-C methods.
+ *
+ * This list will later be used output the necessary Objective-C module info.
+ *
+ * Params:
+ * fd = the function declaration to be added to the list
+ * cd = the class declaration the function belongs to
+ */
+ abstract void addToClassMethodList(FuncDeclaration fd,
+ ClassDeclaration cd) const;
+
+ /**
+ * Returns the `this` pointer of the given function declaration.
+ *
+ * This is only used for class/static methods. For instance methods, no
+ * Objective-C specialization is necessary.
+ *
+ * Params:
+ * funcDeclaration = the function declaration to get the `this` pointer for
+ *
+ * Returns: the `this` pointer of the given function declaration, or `null`
+ * if the given function declaration is not an Objective-C method.
+ */
+ abstract inout(AggregateDeclaration) isThis(inout FuncDeclaration funcDeclaration) const;
+
+ /**
+ * Creates the selector parameter for the given function declaration.
+ *
+ * Objective-C methods has an extra hidden parameter that comes after the
+ * `this` parameter. The selector parameter is of the Objective-C type `SEL`
+ * and contains the selector which this method was called with.
+ *
+ * Params:
+ * fd = the function declaration to create the parameter for
+ * sc = the scope from the semantic phase
+ *
+ * Returns: the newly created selector parameter or `null` for
+ * non-Objective-C functions
+ */
+ abstract VarDeclaration createSelectorParameter(FuncDeclaration fd, Scope* sc) const;
+
+ /**
+ * Creates and sets the metaclass on the given class/interface declaration.
+ *
+ * Will only be performed on regular Objective-C classes, not on metaclasses.
+ *
+ * Params:
+ * classDeclaration = the class/interface declaration to set the metaclass on
+ */
+ abstract void setMetaclass(InterfaceDeclaration interfaceDeclaration, Scope* sc) const;
+
+ /// ditto
+ abstract void setMetaclass(ClassDeclaration classDeclaration, Scope* sc) const;
+
+ /**
+ * Returns Objective-C runtime metaclass of the given class declaration.
+ *
+ * `ClassDeclaration.ObjcClassDeclaration.metaclass` contains the metaclass
+ * from the semantic point of view. This function returns the metaclass from
+ * the Objective-C runtime's point of view. Here, the metaclass of a
+ * metaclass is the root metaclass, not `null`. The root metaclass's
+ * metaclass is itself.
+ *
+ * Params:
+ * classDeclaration = The class declaration to return the metaclass of
+ *
+ * Returns: the Objective-C runtime metaclass of the given class declaration
+ */
+ abstract ClassDeclaration getRuntimeMetaclass(ClassDeclaration classDeclaration) const;
+
+ ///
+ abstract void addSymbols(AttribDeclaration attribDeclaration,
+ ClassDeclarations* classes, ClassDeclarations* categories) const;
+
+ ///
+ abstract void addSymbols(ClassDeclaration classDeclaration,
+ ClassDeclarations* classes, ClassDeclarations* categories) const;
+
+ /**
+ * Issues a compile time error if the `.offsetof`/`.tupleof` property is
+ * used on a field of an Objective-C class.
+ *
+ * To solve the fragile base class problem in Objective-C, fields have a
+ * dynamic offset instead of a static offset. The compiler outputs a
+ * statically known offset which later the dynamic loader can update, if
+ * necessary, when the application is loaded. Due to this behavior it
+ * doesn't make sense to be able to get the offset of a field at compile
+ * time, because this offset might not actually be the same at runtime.
+ *
+ * To get the offset of a field that is correct at runtime, functionality
+ * from the Objective-C runtime can be used instead.
+ *
+ * Params:
+ * expression = the `.offsetof`/`.tupleof` expression
+ * aggregateDeclaration = the aggregate declaration the field of the
+ * `.offsetof`/`.tupleof` expression belongs to
+ * type = the type of the receiver of the `.tupleof` expression
+ *
+ * See_Also:
+ * $(LINK2 https://en.wikipedia.org/wiki/Fragile_binary_interface_problem,
+ * Fragile Binary Interface Problem)
+ *
+ * See_Also:
+ * $(LINK2 https://developer.apple.com/documentation/objectivec/objective_c_runtime,
+ * Objective-C Runtime)
+ */
+ abstract void checkOffsetof(Expression expression, AggregateDeclaration aggregateDeclaration) const;
+
+ /// ditto
+ abstract void checkTupleof(Expression expression, TypeClass type) const;
+}
+
+extern(C++) private final class Unsupported : Objc
+{
+ extern(D) final this()
+ {
+ ObjcGlue.initialize();
+ }
+
+ override void setObjc(ClassDeclaration cd)
+ {
+ cd.error("Objective-C classes not supported");
+ }
+
+ override void setObjc(InterfaceDeclaration id)
+ {
+ id.error("Objective-C interfaces not supported");
+ }
+
+ override const(char)* toPrettyChars(ClassDeclaration, bool qualifyTypes) const
+ {
+ assert(0, "Should never be called when Objective-C is not supported");
+ }
+
+ override void setSelector(FuncDeclaration, Scope*)
+ {
+ // noop
+ }
+
+ override void validateSelector(FuncDeclaration)
+ {
+ // noop
+ }
+
+ override void checkLinkage(FuncDeclaration)
+ {
+ // noop
+ }
+
+ override bool isVirtual(const FuncDeclaration) const
+ {
+ assert(0, "Should never be called when Objective-C is not supported");
+ }
+
+ override void setAsOptional(FuncDeclaration, Scope*) const
+ {
+ // noop
+ }
+
+ override void validateOptional(FuncDeclaration) const
+ {
+ // noop
+ }
+
+ override ClassDeclaration getParent(FuncDeclaration, ClassDeclaration cd) const
+ {
+ return cd;
+ }
+
+ override void addToClassMethodList(FuncDeclaration, ClassDeclaration) const
+ {
+ // noop
+ }
+
+ override inout(AggregateDeclaration) isThis(inout FuncDeclaration funcDeclaration) const
+ {
+ return null;
+ }
+
+ override VarDeclaration createSelectorParameter(FuncDeclaration, Scope*) const
+ {
+ return null;
+ }
+
+ override void setMetaclass(InterfaceDeclaration, Scope*) const
+ {
+ // noop
+ }
+
+ override void setMetaclass(ClassDeclaration, Scope*) const
+ {
+ // noop
+ }
+
+ override ClassDeclaration getRuntimeMetaclass(ClassDeclaration classDeclaration) const
+ {
+ assert(0, "Should never be called when Objective-C is not supported");
+ }
+
+ override void addSymbols(AttribDeclaration attribDeclaration,
+ ClassDeclarations* classes, ClassDeclarations* categories) const
+ {
+ // noop
+ }
+
+ override void addSymbols(ClassDeclaration classDeclaration,
+ ClassDeclarations* classes, ClassDeclarations* categories) const
+ {
+ // noop
+ }
+
+ override void checkOffsetof(Expression expression, AggregateDeclaration aggregateDeclaration) const
+ {
+ // noop
+ }
+
+ override void checkTupleof(Expression expression, TypeClass type) const
+ {
+ // noop
+ }
+}
+
+extern(C++) private final class Supported : Objc
+{
+ extern(D) final this()
+ {
+ VersionCondition.addPredefinedGlobalIdent("D_ObjectiveC");
+
+ ObjcGlue.initialize();
+ ObjcSelector._init();
+ }
+
+ override void setObjc(ClassDeclaration cd)
+ {
+ cd.classKind = ClassKind.objc;
+ cd.objc.isExtern = (cd.storage_class & STC.extern_) > 0;
+ }
+
+ override void setObjc(InterfaceDeclaration id)
+ {
+ id.classKind = ClassKind.objc;
+ id.objc.isExtern = true;
+ }
+
+ override const(char)* toPrettyChars(ClassDeclaration cd, bool qualifyTypes) const
+ {
+ return cd.parent.toPrettyChars(qualifyTypes);
+ }
+
+ override void setSelector(FuncDeclaration fd, Scope* sc)
+ {
+ foreachUda(fd, sc, (e) {
+ if (e.op != TOK.structLiteral)
+ return 0;
+
+ auto literal = cast(StructLiteralExp) e;
+ assert(literal.sd);
+
+ if (!isCoreUda(literal.sd, Id.udaSelector))
+ return 0;
+
+ if (fd.objc.selector)
+ {
+ fd.error("can only have one Objective-C selector per method");
+ return 1;
+ }
+
+ assert(literal.elements.dim == 1);
+ auto se = (*literal.elements)[0].toStringExp();
+ assert(se);
+
+ fd.objc.selector = ObjcSelector.lookup(se.toUTF8(sc).peekString().ptr);
+
+ return 0;
+ });
+ }
+
+ override void validateSelector(FuncDeclaration fd)
+ {
+ if (!fd.objc.selector)
+ return;
+ TypeFunction tf = cast(TypeFunction)fd.type;
+ if (fd.objc.selector.paramCount != tf.parameterList.parameters.dim)
+ fd.error("number of colons in Objective-C selector must match number of parameters");
+ if (fd.parent && fd.parent.isTemplateInstance())
+ fd.error("template cannot have an Objective-C selector attached");
+ }
+
+ override void checkLinkage(FuncDeclaration fd)
+ {
+ if (fd.linkage != LINK.objc && fd.objc.selector)
+ fd.error("must have Objective-C linkage to attach a selector");
+ }
+
+ override bool isVirtual(const FuncDeclaration fd) const
+ in
+ {
+ assert(fd.selector);
+ assert(fd.isMember);
+ }
+ do
+ {
+ if (fd.toParent.isInterfaceDeclaration && fd.isFinal)
+ return false;
+
+ // * final member functions are kept virtual with Objective-C linkage
+ // because the Objective-C runtime always use dynamic dispatch.
+ // * static member functions are kept virtual too, as they represent
+ // methods of the metaclass.
+ with (fd.visibility)
+ return !(kind == Visibility.Kind.private_ || kind == Visibility.Kind.package_);
+ }
+
+ override void setAsOptional(FuncDeclaration fd, Scope* sc) const
+ {
+ const count = declaredAsOptionalCount(fd, sc);
+ fd.objc.isOptional = count > 0;
+
+ if (count > 1)
+ fd.error("can only declare a function as optional once");
+ }
+
+ /// Returns: the number of times `fd` has been declared as optional.
+ private int declaredAsOptionalCount(FuncDeclaration fd , Scope* sc) const
+ {
+ int count;
+
+ foreachUda(fd, sc, (e) {
+ if (e.op != TOK.type)
+ return 0;
+
+ auto typeExp = cast(TypeExp) e;
+
+ if (typeExp.type.ty != Tenum)
+ return 0;
+
+ auto typeEnum = cast(TypeEnum) typeExp.type;
+
+ if (isCoreUda(typeEnum.sym, Id.udaOptional))
+ count++;
+
+ return 0;
+ });
+
+ return count;
+ }
+
+ override void validateOptional(FuncDeclaration fd) const
+ {
+ if (!fd.objc.isOptional)
+ return;
+
+ if (fd.linkage != LINK.objc)
+ {
+ fd.error("only functions with Objective-C linkage can be declared as optional");
+
+ const linkage = linkageToString(fd.linkage);
+
+ errorSupplemental(fd.loc, "function is declared with %.*s linkage",
+ cast(uint) linkage.length, linkage.ptr);
+ }
+
+ auto parent = fd.parent;
+
+ if (parent && parent.isTemplateInstance())
+ {
+ fd.error("template cannot be optional");
+ parent = parent.parent;
+ assert(parent);
+ }
+
+ if (parent && !parent.isInterfaceDeclaration())
+ {
+ fd.error("only functions declared inside interfaces can be optional");
+ errorSupplemental(fd.loc, "function is declared inside %s", fd.parent.kind);
+ }
+ }
+
+ override ClassDeclaration getParent(FuncDeclaration fd, ClassDeclaration cd) const
+ out(metaclass)
+ {
+ assert(metaclass);
+ }
+ do
+ {
+ if (cd.classKind == ClassKind.objc && fd.isStatic && !cd.objc.isMeta)
+ return cd.objc.metaclass;
+ else
+ return cd;
+ }
+
+ override void addToClassMethodList(FuncDeclaration fd, ClassDeclaration cd) const
+ in
+ {
+ assert(fd.parent.isClassDeclaration);
+ }
+ do
+ {
+ if (cd.classKind != ClassKind.objc)
+ return;
+
+ if (!fd.objc.selector)
+ return;
+
+ assert(fd.isStatic ? cd.objc.isMeta : !cd.objc.isMeta);
+
+ cd.objc.methodList ~= fd;
+ }
+
+ override inout(AggregateDeclaration) isThis(inout FuncDeclaration funcDeclaration) const
+ {
+ with(funcDeclaration)
+ {
+ if (!objc.selector)
+ return null;
+
+ // Use Objective-C class object as 'this'
+ auto cd = isMember2().isClassDeclaration();
+
+ if (cd.classKind == ClassKind.objc)
+ {
+ if (!cd.objc.isMeta)
+ return cd.objc.metaclass;
+ }
+
+ return null;
+ }
+ }
+
+ override VarDeclaration createSelectorParameter(FuncDeclaration fd, Scope* sc) const
+ in
+ {
+ assert(fd.selectorParameter is null);
+ }
+ do
+ {
+ if (!fd.objc.selector)
+ return null;
+
+ auto ident = Identifier.generateAnonymousId("_cmd");
+ auto var = new VarDeclaration(fd.loc, Type.tvoidptr, ident, null);
+ var.storage_class |= STC.parameter;
+ var.dsymbolSemantic(sc);
+ if (!sc.insert(var))
+ assert(false);
+ var.parent = fd;
+
+ return var;
+ }
+
+ override void setMetaclass(InterfaceDeclaration interfaceDeclaration, Scope* sc) const
+ {
+ auto newMetaclass(Loc loc, BaseClasses* metaBases)
+ {
+ auto ident = createMetaclassIdentifier(interfaceDeclaration);
+ return new InterfaceDeclaration(loc, ident, metaBases);
+ }
+
+ .setMetaclass!newMetaclass(interfaceDeclaration, sc);
+ }
+
+ override void setMetaclass(ClassDeclaration classDeclaration, Scope* sc) const
+ {
+ auto newMetaclass(Loc loc, BaseClasses* metaBases)
+ {
+ auto ident = createMetaclassIdentifier(classDeclaration);
+ return new ClassDeclaration(loc, ident, metaBases, new Dsymbols(), 0);
+ }
+
+ .setMetaclass!newMetaclass(classDeclaration, sc);
+ }
+
+ override ClassDeclaration getRuntimeMetaclass(ClassDeclaration classDeclaration) const
+ {
+ if (!classDeclaration.objc.metaclass && classDeclaration.objc.isMeta)
+ {
+ if (classDeclaration.baseClass)
+ return getRuntimeMetaclass(classDeclaration.baseClass);
+ else
+ return classDeclaration;
+ }
+ else
+ return classDeclaration.objc.metaclass;
+ }
+
+ override void addSymbols(AttribDeclaration attribDeclaration,
+ ClassDeclarations* classes, ClassDeclarations* categories) const
+ {
+ auto symbols = attribDeclaration.include(null);
+
+ if (!symbols)
+ return;
+
+ foreach (symbol; *symbols)
+ symbol.addObjcSymbols(classes, categories);
+ }
+
+ override void addSymbols(ClassDeclaration classDeclaration,
+ ClassDeclarations* classes, ClassDeclarations* categories) const
+ {
+ with (classDeclaration)
+ if (classKind == ClassKind.objc && !objc.isExtern && !objc.isMeta)
+ classes.push(classDeclaration);
+ }
+
+ override void checkOffsetof(Expression expression, AggregateDeclaration aggregateDeclaration) const
+ {
+ if (aggregateDeclaration.classKind != ClassKind.objc)
+ return;
+
+ enum errorMessage = "no property `offsetof` for member `%s` of type " ~
+ "`%s`";
+
+ enum supplementalMessage = "`offsetof` is not available for members " ~
+ "of Objective-C classes. Please use the Objective-C runtime instead";
+
+ expression.error(errorMessage, expression.toChars(),
+ expression.type.toChars());
+ expression.errorSupplemental(supplementalMessage);
+ }
+
+ override void checkTupleof(Expression expression, TypeClass type) const
+ {
+ if (type.sym.classKind != ClassKind.objc)
+ return;
+
+ expression.error("no property `tupleof` for type `%s`", type.toChars());
+ expression.errorSupplemental("`tupleof` is not available for members " ~
+ "of Objective-C classes. Please use the Objective-C runtime instead");
+ }
+
+extern(D) private:
+
+ /**
+ * Returns `true` if the given symbol is a symbol declared in
+ * `core.attribute` and has the given identifier.
+ *
+ * This is used to determine if a symbol is a UDA declared in
+ * `core.attribute`.
+ *
+ * Params:
+ * sd = the symbol to check
+ * ident = the name of the expected UDA
+ */
+ bool isCoreUda(ScopeDsymbol sd, Identifier ident) const
+ {
+ if (sd.ident != ident || !sd.parent)
+ return false;
+
+ auto _module = sd.parent.isModule();
+ return _module && _module.isCoreModule(Id.attribute);
+ }
+
+ /**
+ * Iterates the UDAs attached to the given function declaration.
+ *
+ * If `dg` returns `!= 0`, it will stop the iteration and return that
+ * value, otherwise it will return 0.
+ *
+ * Params:
+ * fd = the function declaration to get the UDAs from
+ * dg = called once for each UDA. If `dg` returns `!= 0`, it will stop the
+ * iteration and return that value, otherwise it will return `0`.
+ */
+ int foreachUda(FuncDeclaration fd, Scope* sc, int delegate(Expression) dg) const
+ {
+ if (!fd.userAttribDecl)
+ return 0;
+
+ auto udas = fd.userAttribDecl.getAttributes();
+ arrayExpressionSemantic(udas, sc, true);
+
+ return udas.each!((uda) {
+ if (uda.op != TOK.tuple)
+ return 0;
+
+ auto exps = (cast(TupleExp) uda).exps;
+
+ return exps.each!((e) {
+ assert(e);
+
+ if (auto result = dg(e))
+ return result;
+
+ return 0;
+ });
+ });
+ }
+}
+
+/*
+ * Creates and sets the metaclass on the given class/interface declaration.
+ *
+ * Will only be performed on regular Objective-C classes, not on metaclasses.
+ *
+ * Params:
+ * newMetaclass = a function that returns the metaclass to set. This should
+ * return the same type as `T`.
+ * classDeclaration = the class/interface declaration to set the metaclass on
+ */
+private void setMetaclass(alias newMetaclass, T)(T classDeclaration, Scope* sc)
+if (is(T == ClassDeclaration) || is(T == InterfaceDeclaration))
+{
+ static if (is(T == ClassDeclaration))
+ enum errorType = "class";
+ else
+ enum errorType = "interface";
+
+ with (classDeclaration)
+ {
+ if (classKind != ClassKind.objc || objc.isMeta || objc.metaclass)
+ return;
+
+ if (!objc.identifier)
+ objc.identifier = classDeclaration.ident;
+
+ auto metaBases = new BaseClasses();
+
+ foreach (base ; baseclasses.opSlice)
+ {
+ auto baseCd = base.sym;
+ assert(baseCd);
+
+ if (baseCd.classKind == ClassKind.objc)
+ {
+ assert(baseCd.objc.metaclass);
+ assert(baseCd.objc.metaclass.objc.isMeta);
+ assert(baseCd.objc.metaclass.type.ty == Tclass);
+
+ auto metaBase = new BaseClass(baseCd.objc.metaclass.type);
+ metaBase.sym = baseCd.objc.metaclass;
+ metaBases.push(metaBase);
+ }
+ else
+ {
+ error("base " ~ errorType ~ " for an Objective-C " ~
+ errorType ~ " must be `extern (Objective-C)`");
+ }
+ }
+
+ objc.metaclass = newMetaclass(loc, metaBases);
+ objc.metaclass.storage_class |= STC.static_;
+ objc.metaclass.classKind = ClassKind.objc;
+ objc.metaclass.objc.isMeta = true;
+ objc.metaclass.objc.isExtern = objc.isExtern;
+ objc.metaclass.objc.identifier = objc.identifier;
+
+ if (baseClass)
+ objc.metaclass.baseClass = baseClass.objc.metaclass;
+
+ members.push(objc.metaclass);
+ objc.metaclass.addMember(sc, classDeclaration);
+
+ objc.metaclass.members = new Dsymbols();
+ objc.metaclass.dsymbolSemantic(sc);
+ }
+}
+
+private Identifier createMetaclassIdentifier(ClassDeclaration classDeclaration)
+{
+ const name = "class_" ~ classDeclaration.ident.toString ~ "_Meta";
+ return Identifier.generateAnonymousId(name);
+}
diff --git a/gcc/d/dmd/objc.h b/gcc/d/dmd/objc.h
index f3da5a3..483e501 100644
--- a/gcc/d/dmd/objc.h
+++ b/gcc/d/dmd/objc.h
@@ -10,22 +10,20 @@
#pragma once
-#include "root/root.h"
-#include "root/stringtable.h"
+#include "root/dsystem.h"
+#include "arraytypes.h"
-class Identifier;
-class FuncDeclaration;
+class AggregateDeclaration;
+class AttribDeclaration;
class ClassDeclaration;
+class FuncDeclaration;
+class Identifier;
class InterfaceDeclaration;
+
struct Scope;
-class StructDeclaration;
struct ObjcSelector
{
- static StringTable stringtable;
- static StringTable vTableDispatchSelectors;
- static int incnum;
-
const char *stringvalue;
size_t stringlen;
size_t paramCount;
@@ -34,12 +32,29 @@ struct ObjcSelector
ObjcSelector(const char *sv, size_t len, size_t pcount);
- static ObjcSelector *lookup(const char *s);
- static ObjcSelector *lookup(const char *s, size_t len, size_t pcount);
-
static ObjcSelector *create(FuncDeclaration *fdecl);
};
+struct ObjcClassDeclaration
+{
+ bool isMeta;
+ bool isExtern;
+
+ Identifier* identifier;
+ ClassDeclaration* classDeclaration;
+ ClassDeclaration* metaclass;
+ DArray<FuncDeclaration*> methodList;
+
+ bool isRootClass() const;
+};
+
+struct ObjcFuncDeclaration
+{
+ ObjcSelector* selector;
+ VarDeclaration* selectorParameter;
+ bool isOptional;
+};
+
class Objc
{
public:
@@ -47,7 +62,23 @@ public:
virtual void setObjc(ClassDeclaration* cd) = 0;
virtual void setObjc(InterfaceDeclaration*) = 0;
+ virtual const char *toPrettyChars(ClassDeclaration *cd, bool qualifyTypes) const = 0;
+
virtual void setSelector(FuncDeclaration*, Scope* sc) = 0;
virtual void validateSelector(FuncDeclaration* fd) = 0;
virtual void checkLinkage(FuncDeclaration* fd) = 0;
+ virtual bool isVirtual(const FuncDeclaration*) const = 0;
+ virtual void setAsOptional(FuncDeclaration *fd, Scope *sc) const = 0;
+ virtual void validateOptional(FuncDeclaration *fd) const = 0;
+ virtual ClassDeclaration* getParent(FuncDeclaration*, ClassDeclaration*) const = 0;
+ virtual void addToClassMethodList(FuncDeclaration*, ClassDeclaration*) const = 0;
+ virtual AggregateDeclaration* isThis(FuncDeclaration* fd) = 0;
+ virtual VarDeclaration* createSelectorParameter(FuncDeclaration*, Scope*) const = 0;
+
+ virtual void setMetaclass(InterfaceDeclaration* id, Scope*) const = 0;
+ virtual void setMetaclass(ClassDeclaration* id, Scope*) const = 0;
+ virtual ClassDeclaration* getRuntimeMetaclass(ClassDeclaration* cd) = 0;
+
+ virtual void addSymbols(AttribDeclaration*, ClassDeclarations*, ClassDeclarations*) const = 0;
+ virtual void addSymbols(ClassDeclaration*, ClassDeclarations*, ClassDeclarations*) const = 0;
};
diff --git a/gcc/d/dmd/opover.c b/gcc/d/dmd/opover.c
deleted file mode 100644
index 0aff8b4..0000000
--- a/gcc/d/dmd/opover.c
+++ /dev/null
@@ -1,1960 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/opover.c
- */
-
-#include "root/dsystem.h" // memset()
-#include "root/rmem.h"
-
-#include "mars.h"
-#include "mtype.h"
-#include "init.h"
-#include "expression.h"
-#include "statement.h"
-#include "scope.h"
-#include "id.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "template.h"
-#include "tokens.h"
-
-static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *parameters);
-static int inferApplyArgTypesY(TypeFunction *tf, Parameters *parameters, int flags = 0);
-Expression *compare_overload(BinExp *e, Scope *sc, Identifier *id);
-bool MODimplicitConv(MOD modfrom, MOD modto);
-
-/******************************** Expression **************************/
-
-
-/***********************************
- * Determine if operands of binary op can be reversed
- * to fit operator overload.
- */
-
-bool isCommutative(TOK op)
-{
- switch (op)
- {
- case TOKadd:
- case TOKmul:
- case TOKand:
- case TOKor:
- case TOKxor:
-
- // EqualExp
- case TOKequal:
- case TOKnotequal:
-
- // CmpExp
- case TOKlt:
- case TOKle:
- case TOKgt:
- case TOKge:
- return true;
-
- default:
- break;
- }
- return false;
-}
-
-/***********************************
- * Get Identifier for operator overload.
- */
-
-static Identifier *opId(Expression *e)
-{
- class OpIdVisitor : public Visitor
- {
- public:
- Identifier *id;
- void visit(Expression *) { assert(0); }
- void visit(UAddExp *) { id = Id::uadd; }
- void visit(NegExp *) { id = Id::neg; }
- void visit(ComExp *) { id = Id::com; }
- void visit(CastExp *) { id = Id::_cast; }
- void visit(InExp *) { id = Id::opIn; }
- void visit(PostExp *e) { id = (e->op == TOKplusplus) ? Id::postinc : Id::postdec; }
- void visit(AddExp *) { id = Id::add; }
- void visit(MinExp *) { id = Id::sub; }
- void visit(MulExp *) { id = Id::mul; }
- void visit(DivExp *) { id = Id::div; }
- void visit(ModExp *) { id = Id::mod; }
- void visit(PowExp *) { id = Id::pow; }
- void visit(ShlExp *) { id = Id::shl; }
- void visit(ShrExp *) { id = Id::shr; }
- void visit(UshrExp *) { id = Id::ushr; }
- void visit(AndExp *) { id = Id::iand; }
- void visit(OrExp *) { id = Id::ior; }
- void visit(XorExp *) { id = Id::ixor; }
- void visit(CatExp *) { id = Id::cat; }
- void visit(AssignExp *) { id = Id::assign; }
- void visit(AddAssignExp *) { id = Id::addass; }
- void visit(MinAssignExp *) { id = Id::subass; }
- void visit(MulAssignExp *) { id = Id::mulass; }
- void visit(DivAssignExp *) { id = Id::divass; }
- void visit(ModAssignExp *) { id = Id::modass; }
- void visit(AndAssignExp *) { id = Id::andass; }
- void visit(OrAssignExp *) { id = Id::orass; }
- void visit(XorAssignExp *) { id = Id::xorass; }
- void visit(ShlAssignExp *) { id = Id::shlass; }
- void visit(ShrAssignExp *) { id = Id::shrass; }
- void visit(UshrAssignExp *) { id = Id::ushrass; }
- void visit(CatAssignExp *) { id = Id::catass; }
- void visit(PowAssignExp *) { id = Id::powass; }
- void visit(EqualExp *) { id = Id::eq; }
- void visit(CmpExp *) { id = Id::cmp; }
- void visit(ArrayExp *) { id = Id::index; }
- void visit(PtrExp *) { id = Id::opStar; }
- };
- OpIdVisitor v;
- e->accept(&v);
- return v.id;
-}
-
-/***********************************
- * Get Identifier for reverse operator overload,
- * NULL if not supported for this operator.
- */
-
-static Identifier *opId_r(Expression *e)
-{
- class OpIdRVisitor : public Visitor
- {
- public:
- Identifier *id;
- void visit(Expression *) { id = NULL; }
- void visit(InExp *) { id = Id::opIn_r; }
- void visit(AddExp *) { id = Id::add_r; }
- void visit(MinExp *) { id = Id::sub_r; }
- void visit(MulExp *) { id = Id::mul_r; }
- void visit(DivExp *) { id = Id::div_r; }
- void visit(ModExp *) { id = Id::mod_r; }
- void visit(PowExp *) { id = Id::pow_r; }
- void visit(ShlExp *) { id = Id::shl_r; }
- void visit(ShrExp *) { id = Id::shr_r; }
- void visit(UshrExp *) { id = Id::ushr_r; }
- void visit(AndExp *) { id = Id::iand_r; }
- void visit(OrExp *) { id = Id::ior_r; }
- void visit(XorExp *) { id = Id::ixor_r; }
- void visit(CatExp *) { id = Id::cat_r; }
- };
- OpIdRVisitor v;
- e->accept(&v);
- return v.id;
-}
-
-/************************************
- * If type is a class or struct, return the symbol for it,
- * else NULL
- */
-AggregateDeclaration *isAggregate(Type *t)
-{
- t = t->toBasetype();
- if (t->ty == Tclass)
- {
- return ((TypeClass *)t)->sym;
- }
- else if (t->ty == Tstruct)
- {
- return ((TypeStruct *)t)->sym;
- }
- return NULL;
-}
-
-/*******************************************
- * Helper function to turn operator into template argument list
- */
-Objects *opToArg(Scope *sc, TOK op)
-{
- /* Remove the = from op=
- */
- switch (op)
- {
- case TOKaddass: op = TOKadd; break;
- case TOKminass: op = TOKmin; break;
- case TOKmulass: op = TOKmul; break;
- case TOKdivass: op = TOKdiv; break;
- case TOKmodass: op = TOKmod; break;
- case TOKandass: op = TOKand; break;
- case TOKorass: op = TOKor; break;
- case TOKxorass: op = TOKxor; break;
- case TOKshlass: op = TOKshl; break;
- case TOKshrass: op = TOKshr; break;
- case TOKushrass: op = TOKushr; break;
- case TOKcatass: op = TOKcat; break;
- case TOKpowass: op = TOKpow; break;
- default: break;
- }
- Expression *e = new StringExp(Loc(), const_cast<char *>(Token::toChars(op)));
- e = expressionSemantic(e, sc);
- Objects *tiargs = new Objects();
- tiargs->push(e);
- return tiargs;
-}
-
-/************************************
- * Operator overload.
- * Check for operator overload, if so, replace
- * with function call.
- * Return NULL if not an operator overload.
- */
-
-Expression *op_overload(Expression *e, Scope *sc)
-{
- class OpOverload : public Visitor
- {
- public:
- Scope *sc;
- Expression *result;
-
- OpOverload(Scope *sc)
- : sc(sc)
- {
- result = NULL;
- }
-
- void visit(Expression *)
- {
- assert(0);
- }
-
- void visit(UnaExp *e)
- {
- //printf("UnaExp::op_overload() (%s)\n", e->toChars());
-
- if (e->e1->op == TOKarray)
- {
- ArrayExp *ae = (ArrayExp *)e->e1;
- ae->e1 = expressionSemantic(ae->e1, sc);
- ae->e1 = resolveProperties(sc, ae->e1);
- Expression *ae1old = ae->e1;
-
- const bool maybeSlice =
- (ae->arguments->length == 0 ||
- (ae->arguments->length == 1 && (*ae->arguments)[0]->op == TOKinterval));
- IntervalExp *ie = NULL;
- if (maybeSlice && ae->arguments->length)
- {
- assert((*ae->arguments)[0]->op == TOKinterval);
- ie = (IntervalExp *)(*ae->arguments)[0];
- }
-
- while (true)
- {
- if (ae->e1->op == TOKerror)
- {
- result = ae->e1;
- return;
- }
- Expression *e0 = NULL;
- Expression *ae1save = ae->e1;
- ae->lengthVar = NULL;
-
- Type *t1b = ae->e1->type->toBasetype();
- AggregateDeclaration *ad = isAggregate(t1b);
- if (!ad)
- break;
- if (search_function(ad, Id::opIndexUnary))
- {
- // Deal with $
- result = resolveOpDollar(sc, ae, &e0);
- if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j)
- goto Lfallback;
- if (result->op == TOKerror)
- return;
-
- /* Rewrite op(a[arguments]) as:
- * a.opIndexUnary!(op)(arguments)
- */
- Expressions *a = (Expressions *)ae->arguments->copy();
- Objects *tiargs = opToArg(sc, e->op);
- result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opIndexUnary, tiargs);
- result = new CallExp(e->loc, result, a);
- if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)()
- result = trySemantic(result, sc);
- else
- result = expressionSemantic(result, sc);
- if (result)
- {
- result = Expression::combine(e0, result);
- return;
- }
- }
- Lfallback:
- if (maybeSlice && search_function(ad, Id::opSliceUnary))
- {
- // Deal with $
- result = resolveOpDollar(sc, ae, ie, &e0);
- if (result->op == TOKerror)
- return;
-
- /* Rewrite op(a[i..j]) as:
- * a.opSliceUnary!(op)(i, j)
- */
- Expressions *a = new Expressions();
- if (ie)
- {
- a->push(ie->lwr);
- a->push(ie->upr);
- }
- Objects *tiargs = opToArg(sc, e->op);
- result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opSliceUnary, tiargs);
- result = new CallExp(e->loc, result, a);
- result = expressionSemantic(result, sc);
- result = Expression::combine(e0, result);
- return;
- }
-
- // Didn't find it. Forward to aliasthis
- if (ad->aliasthis && t1b != ae->att1)
- {
- if (!ae->att1 && t1b->checkAliasThisRec())
- ae->att1 = t1b;
-
- /* Rewrite op(a[arguments]) as:
- * op(a.aliasthis[arguments])
- */
- ae->e1 = resolveAliasThis(sc, ae1save, true);
- if (ae->e1)
- continue;
- }
- break;
- }
- ae->e1 = ae1old; // recovery
- ae->lengthVar = NULL;
- }
-
- e->e1 = expressionSemantic(e->e1, sc);
- e->e1 = resolveProperties(sc, e->e1);
- if (e->e1->op == TOKerror)
- {
- result = e->e1;
- return;
- }
-
- AggregateDeclaration *ad = isAggregate(e->e1->type);
- if (ad)
- {
- Dsymbol *fd = NULL;
- #if 1 // Old way, kept for compatibility with D1
- if (e->op != TOKpreplusplus && e->op != TOKpreminusminus)
- {
- fd = search_function(ad, opId(e));
- if (fd)
- {
- // Rewrite +e1 as e1.add()
- result = build_overload(e->loc, sc, e->e1, NULL, fd);
- return;
- }
- }
- #endif
-
- /* Rewrite as:
- * e1.opUnary!(op)()
- */
- fd = search_function(ad, Id::opUnary);
- if (fd)
- {
- Objects *tiargs = opToArg(sc, e->op);
- result = new DotTemplateInstanceExp(e->loc, e->e1, fd->ident, tiargs);
- result = new CallExp(e->loc, result);
- result = expressionSemantic(result, sc);
- return;
- }
-
- // Didn't find it. Forward to aliasthis
- if (ad->aliasthis && e->e1->type != e->att1)
- {
- /* Rewrite op(e1) as:
- * op(e1.aliasthis)
- */
- //printf("att una %s e1 = %s\n", Token::toChars(op), this->e1->type->toChars());
- Expression *e1 = new DotIdExp(e->loc, e->e1, ad->aliasthis->ident);
- UnaExp *ue = (UnaExp *)e->copy();
- if (!ue->att1 && e->e1->type->checkAliasThisRec())
- ue->att1 = e->e1->type;
- ue->e1 = e1;
- result = trySemantic(ue, sc);
- return;
- }
- }
- }
-
- void visit(ArrayExp *ae)
- {
- //printf("ArrayExp::op_overload() (%s)\n", ae->toChars());
- ae->e1 = expressionSemantic(ae->e1, sc);
- ae->e1 = resolveProperties(sc, ae->e1);
- Expression *ae1old = ae->e1;
-
- const bool maybeSlice =
- (ae->arguments->length == 0 ||
- (ae->arguments->length == 1 && (*ae->arguments)[0]->op == TOKinterval));
- IntervalExp *ie = NULL;
- if (maybeSlice && ae->arguments->length)
- {
- assert((*ae->arguments)[0]->op == TOKinterval);
- ie = (IntervalExp *)(*ae->arguments)[0];
- }
-
- while (true)
- {
- if (ae->e1->op == TOKerror)
- {
- result = ae->e1;
- return;
- }
- Expression *e0 = NULL;
- Expression *ae1save = ae->e1;
- ae->lengthVar = NULL;
-
- Type *t1b = ae->e1->type->toBasetype();
- AggregateDeclaration *ad = isAggregate(t1b);
- if (!ad)
- {
- // If the non-aggregate expression ae->e1 is indexable or sliceable,
- // convert it to the corresponding concrete expression.
- if (t1b->ty == Tpointer ||
- t1b->ty == Tsarray ||
- t1b->ty == Tarray ||
- t1b->ty == Taarray ||
- t1b->ty == Ttuple ||
- t1b->ty == Tvector ||
- ae->e1->op == TOKtype)
- {
- // Convert to SliceExp
- if (maybeSlice)
- {
- result = new SliceExp(ae->loc, ae->e1, ie);
- result = expressionSemantic(result, sc);
- return;
- }
- // Convert to IndexExp
- if (ae->arguments->length == 1)
- {
- result = new IndexExp(ae->loc, ae->e1, (*ae->arguments)[0]);
- result = expressionSemantic(result, sc);
- return;
- }
- }
- break;
- }
- if (search_function(ad, Id::index))
- {
- // Deal with $
- result = resolveOpDollar(sc, ae, &e0);
- if (!result) // a[i..j] might be: a.opSlice(i, j)
- goto Lfallback;
- if (result->op == TOKerror)
- return;
-
- /* Rewrite e1[arguments] as:
- * e1.opIndex(arguments)
- */
- Expressions *a = (Expressions *)ae->arguments->copy();
- result = new DotIdExp(ae->loc, ae->e1, Id::index);
- result = new CallExp(ae->loc, result, a);
- if (maybeSlice) // a[] might be: a.opSlice()
- result = trySemantic(result, sc);
- else
- result = expressionSemantic(result, sc);
- if (result)
- {
- result = Expression::combine(e0, result);
- return;
- }
- }
- Lfallback:
- if (maybeSlice && ae->e1->op == TOKtype)
- {
- result = new SliceExp(ae->loc, ae->e1, ie);
- result = expressionSemantic(result, sc);
- result = Expression::combine(e0, result);
- return;
- }
- if (maybeSlice && search_function(ad, Id::slice))
- {
- // Deal with $
- result = resolveOpDollar(sc, ae, ie, &e0);
- if (result->op == TOKerror)
- return;
-
- /* Rewrite a[i..j] as:
- * a.opSlice(i, j)
- */
- Expressions *a = new Expressions();
- if (ie)
- {
- a->push(ie->lwr);
- a->push(ie->upr);
- }
- result = new DotIdExp(ae->loc, ae->e1, Id::slice);
- result = new CallExp(ae->loc, result, a);
- result = expressionSemantic(result, sc);
- result = Expression::combine(e0, result);
- return;
- }
-
- // Didn't find it. Forward to aliasthis
- if (ad->aliasthis && t1b != ae->att1)
- {
- if (!ae->att1 && t1b->checkAliasThisRec())
- ae->att1 = t1b;
- //printf("att arr e1 = %s\n", this->e1->type->toChars());
-
- /* Rewrite op(a[arguments]) as:
- * op(a.aliasthis[arguments])
- */
- ae->e1 = resolveAliasThis(sc, ae1save, true);
- if (ae->e1)
- continue;
- }
- break;
- }
- ae->e1 = ae1old; // recovery
- ae->lengthVar = NULL;
- }
-
- /***********************************************
- * This is mostly the same as UnaryExp::op_overload(), but has
- * a different rewrite.
- */
- void visit(CastExp *e)
- {
- //printf("CastExp::op_overload() (%s)\n", e->toChars());
- AggregateDeclaration *ad = isAggregate(e->e1->type);
- if (ad)
- {
- Dsymbol *fd = NULL;
- /* Rewrite as:
- * e1.opCast!(T)()
- */
- fd = search_function(ad, Id::_cast);
- if (fd)
- {
- #if 1 // Backwards compatibility with D1 if opCast is a function, not a template
- if (fd->isFuncDeclaration())
- {
- // Rewrite as: e1.opCast()
- result = build_overload(e->loc, sc, e->e1, NULL, fd);
- return;
- }
- #endif
- Objects *tiargs = new Objects();
- tiargs->push(e->to);
- result = new DotTemplateInstanceExp(e->loc, e->e1, fd->ident, tiargs);
- result = new CallExp(e->loc, result);
- result = expressionSemantic(result, sc);
- return;
- }
-
- // Didn't find it. Forward to aliasthis
- if (ad->aliasthis)
- {
- /* Rewrite op(e1) as:
- * op(e1.aliasthis)
- */
- Expression *e1 = new DotIdExp(e->loc, e->e1, ad->aliasthis->ident);
- result = e->copy();
- ((UnaExp *)result)->e1 = e1;
- result = trySemantic(result, sc);
- return;
- }
- }
- }
-
- void visit(BinExp *e)
- {
- //printf("BinExp::op_overload() (%s)\n", e->toChars());
-
- Identifier *id = opId(e);
- Identifier *id_r = opId_r(e);
-
- Expressions args1;
- Expressions args2;
- int argsset = 0;
-
- AggregateDeclaration *ad1 = isAggregate(e->e1->type);
- AggregateDeclaration *ad2 = isAggregate(e->e2->type);
-
- if (e->op == TOKassign && ad1 == ad2)
- {
- StructDeclaration *sd = ad1->isStructDeclaration();
- if (sd && !sd->hasIdentityAssign)
- {
- /* This is bitwise struct assignment. */
- return;
- }
- }
-
- Dsymbol *s = NULL;
- Dsymbol *s_r = NULL;
-
- #if 1 // the old D1 scheme
- if (ad1 && id)
- {
- s = search_function(ad1, id);
- }
- if (ad2 && id_r)
- {
- s_r = search_function(ad2, id_r);
-
- // Bugzilla 12778: If both x.opBinary(y) and y.opBinaryRight(x) found,
- // and they are exactly same symbol, x.opBinary(y) should be preferred.
- if (s_r && s_r == s)
- s_r = NULL;
- }
- #endif
-
- Objects *tiargs = NULL;
- if (e->op == TOKplusplus || e->op == TOKminusminus)
- {
- // Bug4099 fix
- if (ad1 && search_function(ad1, Id::opUnary))
- return;
- }
- if (!s && !s_r && e->op != TOKequal && e->op != TOKnotequal && e->op != TOKassign &&
- e->op != TOKplusplus && e->op != TOKminusminus)
- {
- /* Try the new D2 scheme, opBinary and opBinaryRight
- */
- if (ad1)
- {
- s = search_function(ad1, Id::opBinary);
- if (s && !s->isTemplateDeclaration())
- {
- e->e1->error("%s.opBinary isn't a template", e->e1->toChars());
- result = new ErrorExp();
- return;
- }
- }
- if (ad2)
- {
- s_r = search_function(ad2, Id::opBinaryRight);
- if (s_r && !s_r->isTemplateDeclaration())
- {
- e->e2->error("%s.opBinaryRight isn't a template", e->e2->toChars());
- result = new ErrorExp();
- return;
- }
- if (s_r && s_r == s) // Bugzilla 12778
- s_r = NULL;
- }
-
- // Set tiargs, the template argument list, which will be the operator string
- if (s || s_r)
- {
- id = Id::opBinary;
- id_r = Id::opBinaryRight;
- tiargs = opToArg(sc, e->op);
- }
- }
-
- if (s || s_r)
- {
- /* Try:
- * a.opfunc(b)
- * b.opfunc_r(a)
- * and see which is better.
- */
-
- args1.setDim(1);
- args1[0] = e->e1;
- expandTuples(&args1);
- args2.setDim(1);
- args2[0] = e->e2;
- expandTuples(&args2);
- argsset = 1;
-
- Match m;
- memset(&m, 0, sizeof(m));
- m.last = MATCHnomatch;
-
- if (s)
- {
- functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2);
- if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
- {
- result = new ErrorExp();
- return;
- }
- }
-
- FuncDeclaration *lastf = m.lastf;
-
- if (s_r)
- {
- functionResolve(&m, s_r, e->loc, sc, tiargs, e->e2->type, &args1);
- if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
- {
- result = new ErrorExp();
- return;
- }
- }
-
- if (m.count > 1)
- {
- // Error, ambiguous
- e->error("overloads %s and %s both match argument list for %s",
- m.lastf->type->toChars(),
- m.nextf->type->toChars(),
- m.lastf->toChars());
- }
- else if (m.last <= MATCHnomatch)
- {
- m.lastf = m.anyf;
- if (tiargs)
- goto L1;
- }
-
- if (e->op == TOKplusplus || e->op == TOKminusminus)
- {
- // Kludge because operator overloading regards e++ and e--
- // as unary, but it's implemented as a binary.
- // Rewrite (e1 ++ e2) as e1.postinc()
- // Rewrite (e1 -- e2) as e1.postdec()
- result = build_overload(e->loc, sc, e->e1, NULL, m.lastf ? m.lastf : s);
- }
- else if ((lastf && m.lastf == lastf) || (!s_r && m.last <= MATCHnomatch))
- {
- // Rewrite (e1 op e2) as e1.opfunc(e2)
- result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s);
- }
- else
- {
- // Rewrite (e1 op e2) as e2.opfunc_r(e1)
- result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s_r);
- }
- return;
- }
-
- L1:
- #if 1 // Retained for D1 compatibility
- if (isCommutative(e->op) && !tiargs)
- {
- s = NULL;
- s_r = NULL;
- if (ad1 && id_r)
- {
- s_r = search_function(ad1, id_r);
- }
- if (ad2 && id)
- {
- s = search_function(ad2, id);
- if (s && s == s_r) // Bugzilla 12778
- s = NULL;
- }
-
- if (s || s_r)
- {
- /* Try:
- * a.opfunc_r(b)
- * b.opfunc(a)
- * and see which is better.
- */
-
- if (!argsset)
- {
- args1.setDim(1);
- args1[0] = e->e1;
- expandTuples(&args1);
- args2.setDim(1);
- args2[0] = e->e2;
- expandTuples(&args2);
- }
-
- Match m;
- memset(&m, 0, sizeof(m));
- m.last = MATCHnomatch;
-
- if (s_r)
- {
- functionResolve(&m, s_r, e->loc, sc, tiargs, e->e1->type, &args2);
- if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
- {
- result = new ErrorExp();
- return;
- }
- }
-
- FuncDeclaration *lastf = m.lastf;
-
- if (s)
- {
- functionResolve(&m, s, e->loc, sc, tiargs, e->e2->type, &args1);
- if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
- {
- result = new ErrorExp();
- return;
- }
- }
-
- if (m.count > 1)
- {
- // Error, ambiguous
- e->error("overloads %s and %s both match argument list for %s",
- m.lastf->type->toChars(),
- m.nextf->type->toChars(),
- m.lastf->toChars());
- }
- else if (m.last <= MATCHnomatch)
- {
- m.lastf = m.anyf;
- }
-
- if ((lastf && m.lastf == lastf) || (!s && m.last <= MATCHnomatch))
- {
- // Rewrite (e1 op e2) as e1.opfunc_r(e2)
- result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s_r);
- }
- else
- {
- // Rewrite (e1 op e2) as e2.opfunc(e1)
- result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s);
- }
-
- // When reversing operands of comparison operators,
- // need to reverse the sense of the op
- switch (e->op)
- {
- case TOKlt: e->op = TOKgt; break;
- case TOKgt: e->op = TOKlt; break;
- case TOKle: e->op = TOKge; break;
- case TOKge: e->op = TOKle; break;
- default: break;
- }
-
- return;
- }
- }
- #endif
-
- // Try alias this on first operand
- if (ad1 && ad1->aliasthis &&
- !(e->op == TOKassign && ad2 && ad1 == ad2)) // See Bugzilla 2943
- {
- /* Rewrite (e1 op e2) as:
- * (e1.aliasthis op e2)
- */
- if (e->att1 && e->e1->type == e->att1)
- return;
- //printf("att bin e1 = %s\n", this->e1->type->toChars());
- Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident);
- BinExp *be = (BinExp *)e->copy();
- if (!be->att1 && e->e1->type->checkAliasThisRec())
- be->att1 = e->e1->type;
- be->e1 = e1;
- result = trySemantic(be, sc);
- return;
- }
-
- // Try alias this on second operand
- /* Bugzilla 2943: make sure that when we're copying the struct, we don't
- * just copy the alias this member
- */
- if (ad2 && ad2->aliasthis &&
- !(e->op == TOKassign && ad1 && ad1 == ad2))
- {
- /* Rewrite (e1 op e2) as:
- * (e1 op e2.aliasthis)
- */
- if (e->att2 && e->e2->type == e->att2)
- return;
- //printf("att bin e2 = %s\n", e->e2->type->toChars());
- Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident);
- BinExp *be = (BinExp *)e->copy();
- if (!be->att2 && e->e2->type->checkAliasThisRec())
- be->att2 = e->e2->type;
- be->e2 = e2;
- result = trySemantic(be, sc);
- return;
- }
- return;
- }
-
- static bool needsDirectEq(Type *t1, Type *t2, Scope *sc)
- {
- Type *t1n = t1->nextOf()->toBasetype();
- Type *t2n = t2->nextOf()->toBasetype();
- if (((t1n->ty == Tchar || t1n->ty == Twchar || t1n->ty == Tdchar) &&
- (t2n->ty == Tchar || t2n->ty == Twchar || t2n->ty == Tdchar)) ||
- (t1n->ty == Tvoid || t2n->ty == Tvoid))
- {
- return false;
- }
- if (t1n->constOf() != t2n->constOf())
- return true;
-
- Type *t = t1n;
- while (t->toBasetype()->nextOf())
- t = t->nextOf()->toBasetype();
- if (t->ty != Tstruct)
- return false;
-
- if (global.params.useTypeInfo && Type::dtypeinfo)
- semanticTypeInfo(sc, t);
-
- return ((TypeStruct *)t)->sym->hasIdentityEquals;
- }
-
- void visit(EqualExp *e)
- {
- //printf("EqualExp::op_overload() (%s)\n", e->toChars());
-
- Type *t1 = e->e1->type->toBasetype();
- Type *t2 = e->e2->type->toBasetype();
-
- /* Check for array equality.
- */
- if ((t1->ty == Tarray || t1->ty == Tsarray) &&
- (t2->ty == Tarray || t2->ty == Tsarray))
- {
- if (needsDirectEq(t1, t2, sc))
- {
- /* Rewrite as:
- * __ArrayEq(e1, e2)
- */
- Expression *eeq = new IdentifierExp(e->loc, Id::__ArrayEq);
- result = new CallExp(e->loc, eeq, e->e1, e->e2);
- if (e->op == TOKnotequal)
- result = new NotExp(e->loc, result);
- result = trySemantic(result, sc); // for better error message
- if (!result)
- {
- e->error("cannot compare %s and %s", t1->toChars(), t2->toChars());
- result = new ErrorExp();
- }
- return;
- }
- }
-
- /* Check for class equality with null literal or typeof(null).
- */
- if ((t1->ty == Tclass && e->e2->op == TOKnull) ||
- (t2->ty == Tclass && e->e1->op == TOKnull))
- {
- e->error("use `%s` instead of `%s` when comparing with null",
- Token::toChars(e->op == TOKequal ? TOKidentity : TOKnotidentity),
- Token::toChars(e->op));
- result = new ErrorExp();
- return;
- }
- if ((t1->ty == Tclass && t2->ty == Tnull) ||
- (t1->ty == Tnull && t2->ty == Tclass))
- {
- // Comparing a class with typeof(null) should not call opEquals
- return;
- }
-
- /* Check for class equality.
- */
- if (t1->ty == Tclass && t2->ty == Tclass)
- {
- ClassDeclaration *cd1 = t1->isClassHandle();
- ClassDeclaration *cd2 = t2->isClassHandle();
-
- if (!(cd1->isCPPclass() || cd2->isCPPclass()))
- {
- /* Rewrite as:
- * .object.opEquals(e1, e2)
- */
- Expression *e1x = e->e1;
- Expression *e2x = e->e2;
-
- /* The explicit cast is necessary for interfaces,
- * see Bugzilla 4088.
- */
- Type *to = ClassDeclaration::object->getType();
- if (cd1->isInterfaceDeclaration())
- e1x = new CastExp(e->loc, e->e1, t1->isMutable() ? to : to->constOf());
- if (cd2->isInterfaceDeclaration())
- e2x = new CastExp(e->loc, e->e2, t2->isMutable() ? to : to->constOf());
-
- result = new IdentifierExp(e->loc, Id::empty);
- result = new DotIdExp(e->loc, result, Id::object);
- result = new DotIdExp(e->loc, result, Id::eq);
- result = new CallExp(e->loc, result, e1x, e2x);
- if (e->op == TOKnotequal)
- result = new NotExp(e->loc, result);
- result = expressionSemantic(result, sc);
- return;
- }
- }
-
- result = compare_overload(e, sc, Id::eq);
- if (result)
- {
- if (result->op == TOKcall && e->op == TOKnotequal)
- {
- result = new NotExp(result->loc, result);
- result = expressionSemantic(result, sc);
- }
- return;
- }
-
- /* Check for pointer equality.
- */
- if (t1->ty == Tpointer || t2->ty == Tpointer)
- {
- /* Rewrite:
- * ptr1 == ptr2
- * as:
- * ptr1 is ptr2
- *
- * This is just a rewriting for deterministic AST representation
- * as the backend input.
- */
- TOK op2 = e->op == TOKequal ? TOKidentity : TOKnotidentity;
- result = new IdentityExp(op2, e->loc, e->e1, e->e2);
- result = expressionSemantic(result, sc);
- return;
- }
-
- /* Check for struct equality without opEquals.
- */
- if (t1->ty == Tstruct && t2->ty == Tstruct)
- {
- StructDeclaration *sd = ((TypeStruct *)t1)->sym;
- if (sd != ((TypeStruct *)t2)->sym)
- return;
-
- if (!needOpEquals(sd))
- {
- // Use bitwise equality.
- TOK op2 = e->op == TOKequal ? TOKidentity : TOKnotidentity;
- result = new IdentityExp(op2, e->loc, e->e1, e->e2);
- result = expressionSemantic(result, sc);
- return;
- }
-
- /* Do memberwise equality.
- * Rewrite:
- * e1 == e2
- * as:
- * e1.tupleof == e2.tupleof
- *
- * If sd is a nested struct, and if it's nested in a class, it will
- * also compare the parent class's equality. Otherwise, compares
- * the identity of parent context through void*.
- */
- if (e->att1 && t1 == e->att1)
- return;
- if (e->att2 && t2 == e->att2)
- return;
-
- e = (EqualExp *)e->copy();
- if (!e->att1)
- e->att1 = t1;
- if (!e->att2)
- e->att2 = t2;
- e->e1 = new DotIdExp(e->loc, e->e1, Id::_tupleof);
- e->e2 = new DotIdExp(e->loc, e->e2, Id::_tupleof);
- result = expressionSemantic(e, sc);
-
- /* Bugzilla 15292, if the rewrite result is same with the original,
- * the equality is unresolvable because it has recursive definition.
- */
- if (result->op == e->op &&
- ((EqualExp *)result)->e1->type->toBasetype() == t1)
- {
- e->error("cannot compare %s because its auto generated member-wise equality has recursive definition",
- t1->toChars());
- result = new ErrorExp();
- }
- return;
- }
-
- /* Check for tuple equality.
- */
- if (e->e1->op == TOKtuple && e->e2->op == TOKtuple)
- {
- TupleExp *tup1 = (TupleExp *)e->e1;
- TupleExp *tup2 = (TupleExp *)e->e2;
- size_t dim = tup1->exps->length;
- if (dim != tup2->exps->length)
- {
- e->error("mismatched tuple lengths, %d and %d",
- (int)dim, (int)tup2->exps->length);
- result = new ErrorExp();
- return;
- }
-
- if (dim == 0)
- {
- // zero-length tuple comparison should always return true or false.
- result = new IntegerExp(e->loc, (e->op == TOKequal), Type::tbool);
- }
- else
- {
- for (size_t i = 0; i < dim; i++)
- {
- Expression *ex1 = (*tup1->exps)[i];
- Expression *ex2 = (*tup2->exps)[i];
- EqualExp *eeq = new EqualExp(e->op, e->loc, ex1, ex2);
- eeq->att1 = e->att1;
- eeq->att2 = e->att2;
-
- if (!result)
- result = eeq;
- else if (e->op == TOKequal)
- result = new LogicalExp(e->loc, TOKandand, result, eeq);
- else
- result = new LogicalExp(e->loc, TOKoror, result, eeq);
- }
- assert(result);
- }
- result = Expression::combine(Expression::combine(tup1->e0, tup2->e0), result);
- result = expressionSemantic(result, sc);
- return;
- }
- }
-
- void visit(CmpExp *e)
- {
- //printf("CmpExp::op_overload() (%s)\n", e->toChars());
-
- result = compare_overload(e, sc, Id::cmp);
- }
-
- /*********************************
- * Operator overloading for op=
- */
- void visit(BinAssignExp *e)
- {
- //printf("BinAssignExp::op_overload() (%s)\n", e->toChars());
-
- if (e->e1->op == TOKarray)
- {
- ArrayExp *ae = (ArrayExp *)e->e1;
- ae->e1 = expressionSemantic(ae->e1, sc);
- ae->e1 = resolveProperties(sc, ae->e1);
- Expression *ae1old = ae->e1;
-
- const bool maybeSlice =
- (ae->arguments->length == 0 ||
- (ae->arguments->length == 1 && (*ae->arguments)[0]->op == TOKinterval));
- IntervalExp *ie = NULL;
- if (maybeSlice && ae->arguments->length)
- {
- assert((*ae->arguments)[0]->op == TOKinterval);
- ie = (IntervalExp *)(*ae->arguments)[0];
- }
-
- while (true)
- {
- if (ae->e1->op == TOKerror)
- {
- result = ae->e1;
- return;
- }
- Expression *e0 = NULL;
- Expression *ae1save = ae->e1;
- ae->lengthVar = NULL;
-
- Type *t1b = ae->e1->type->toBasetype();
- AggregateDeclaration *ad = isAggregate(t1b);
- if (!ad)
- break;
- if (search_function(ad, Id::opIndexOpAssign))
- {
- // Deal with $
- result = resolveOpDollar(sc, ae, &e0);
- if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j)
- goto Lfallback;
- if (result->op == TOKerror)
- return;
-
- result = expressionSemantic(e->e2, sc);
- if (result->op == TOKerror)
- return;
- e->e2 = result;
-
- /* Rewrite a[arguments] op= e2 as:
- * a.opIndexOpAssign!(op)(e2, arguments)
- */
- Expressions *a = (Expressions *)ae->arguments->copy();
- a->insert(0, e->e2);
- Objects *tiargs = opToArg(sc, e->op);
- result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opIndexOpAssign, tiargs);
- result = new CallExp(e->loc, result, a);
- if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2)
- result = trySemantic(result, sc);
- else
- result = expressionSemantic(result, sc);
- if (result)
- {
- result = Expression::combine(e0, result);
- return;
- }
- }
- Lfallback:
- if (maybeSlice && search_function(ad, Id::opSliceOpAssign))
- {
- // Deal with $
- result = resolveOpDollar(sc, ae, ie, &e0);
- if (result->op == TOKerror)
- return;
-
- result = expressionSemantic(e->e2, sc);
- if (result->op == TOKerror)
- return;
- e->e2 = result;
-
- /* Rewrite (a[i..j] op= e2) as:
- * a.opSliceOpAssign!(op)(e2, i, j)
- */
- Expressions *a = new Expressions();
- a->push(e->e2);
- if (ie)
- {
- a->push(ie->lwr);
- a->push(ie->upr);
- }
- Objects *tiargs = opToArg(sc, e->op);
- result = new DotTemplateInstanceExp(e->loc, ae->e1, Id::opSliceOpAssign, tiargs);
- result = new CallExp(e->loc, result, a);
- result = expressionSemantic(result, sc);
- result = Expression::combine(e0, result);
- return;
- }
-
- // Didn't find it. Forward to aliasthis
- if (ad->aliasthis && t1b != ae->att1)
- {
- if (!ae->att1 && t1b->checkAliasThisRec())
- ae->att1 = t1b;
-
- /* Rewrite (a[arguments] op= e2) as:
- * a.aliasthis[arguments] op= e2
- */
- ae->e1 = resolveAliasThis(sc, ae1save, true);
- if (ae->e1)
- continue;
- }
- break;
- }
- ae->e1 = ae1old; // recovery
- ae->lengthVar = NULL;
- }
-
- result = binSemanticProp(e, sc);
- if (result)
- return;
-
- // Don't attempt 'alias this' if an error occured
- if (e->e1->type->ty == Terror || e->e2->type->ty == Terror)
- {
- result = new ErrorExp();
- return;
- }
-
- Identifier *id = opId(e);
-
- Expressions args2;
-
- AggregateDeclaration *ad1 = isAggregate(e->e1->type);
-
- Dsymbol *s = NULL;
-
- #if 1 // the old D1 scheme
- if (ad1 && id)
- {
- s = search_function(ad1, id);
- }
- #endif
-
- Objects *tiargs = NULL;
- if (!s)
- {
- /* Try the new D2 scheme, opOpAssign
- */
- if (ad1)
- {
- s = search_function(ad1, Id::opOpAssign);
- if (s && !s->isTemplateDeclaration())
- {
- e->error("%s.opOpAssign isn't a template", e->e1->toChars());
- result = new ErrorExp();
- return;
- }
- }
-
- // Set tiargs, the template argument list, which will be the operator string
- if (s)
- {
- id = Id::opOpAssign;
- tiargs = opToArg(sc, e->op);
- }
- }
-
- if (s)
- {
- /* Try:
- * a.opOpAssign(b)
- */
-
- args2.setDim(1);
- args2[0] = e->e2;
- expandTuples(&args2);
-
- Match m;
- memset(&m, 0, sizeof(m));
- m.last = MATCHnomatch;
-
- if (s)
- {
- functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2);
- if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
- {
- result = new ErrorExp();
- return;
- }
- }
-
- if (m.count > 1)
- {
- // Error, ambiguous
- e->error("overloads %s and %s both match argument list for %s",
- m.lastf->type->toChars(),
- m.nextf->type->toChars(),
- m.lastf->toChars());
- }
- else if (m.last <= MATCHnomatch)
- {
- m.lastf = m.anyf;
- if (tiargs)
- goto L1;
- }
-
- // Rewrite (e1 op e2) as e1.opOpAssign(e2)
- result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s);
- return;
- }
-
- L1:
-
- // Try alias this on first operand
- if (ad1 && ad1->aliasthis)
- {
- /* Rewrite (e1 op e2) as:
- * (e1.aliasthis op e2)
- */
- if (e->att1 && e->e1->type == e->att1)
- return;
- //printf("att %s e1 = %s\n", Token::toChars(e->op), e->e1->type->toChars());
- Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident);
- BinExp *be = (BinExp *)e->copy();
- if (!be->att1 && e->e1->type->checkAliasThisRec())
- be->att1 = e->e1->type;
- be->e1 = e1;
- result = trySemantic(be, sc);
- return;
- }
-
- // Try alias this on second operand
- AggregateDeclaration *ad2 = isAggregate(e->e2->type);
- if (ad2 && ad2->aliasthis)
- {
- /* Rewrite (e1 op e2) as:
- * (e1 op e2.aliasthis)
- */
- if (e->att2 && e->e2->type == e->att2)
- return;
- //printf("att %s e2 = %s\n", Token::toChars(e->op), e->e2->type->toChars());
- Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident);
- BinExp *be = (BinExp *)e->copy();
- if (!be->att2 && e->e2->type->checkAliasThisRec())
- be->att2 = e->e2->type;
- be->e2 = e2;
- result = trySemantic(be, sc);
- return;
- }
- }
- };
-
- OpOverload v(sc);
- e->accept(&v);
- return v.result;
-}
-
-/******************************************
- * Common code for overloading of EqualExp and CmpExp
- */
-Expression *compare_overload(BinExp *e, Scope *sc, Identifier *id)
-{
- //printf("BinExp::compare_overload(id = %s) %s\n", id->toChars(), e->toChars());
-
- AggregateDeclaration *ad1 = isAggregate(e->e1->type);
- AggregateDeclaration *ad2 = isAggregate(e->e2->type);
-
- Dsymbol *s = NULL;
- Dsymbol *s_r = NULL;
-
- if (ad1)
- {
- s = search_function(ad1, id);
- }
- if (ad2)
- {
- s_r = search_function(ad2, id);
- if (s == s_r)
- s_r = NULL;
- }
-
- Objects *tiargs = NULL;
-
- if (s || s_r)
- {
- /* Try:
- * a.opEquals(b)
- * b.opEquals(a)
- * and see which is better.
- */
-
- Expressions args1;
- Expressions args2;
-
- args1.setDim(1);
- args1[0] = e->e1;
- expandTuples(&args1);
- args2.setDim(1);
- args2[0] = e->e2;
- expandTuples(&args2);
-
- Match m;
- memset(&m, 0, sizeof(m));
- m.last = MATCHnomatch;
-
- if (0 && s && s_r)
- {
- printf("s : %s\n", s->toPrettyChars());
- printf("s_r: %s\n", s_r->toPrettyChars());
- }
-
- if (s)
- {
- functionResolve(&m, s, e->loc, sc, tiargs, e->e1->type, &args2);
- if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
- return new ErrorExp();
- }
-
- FuncDeclaration *lastf = m.lastf;
- int count = m.count;
-
- if (s_r)
- {
- functionResolve(&m, s_r, e->loc, sc, tiargs, e->e2->type, &args1);
- if (m.lastf && (m.lastf->errors || m.lastf->semantic3Errors))
- return new ErrorExp();
- }
-
- if (m.count > 1)
- {
- /* The following if says "not ambiguous" if there's one match
- * from s and one from s_r, in which case we pick s.
- * This doesn't follow the spec, but is a workaround for the case
- * where opEquals was generated from templates and we cannot figure
- * out if both s and s_r came from the same declaration or not.
- * The test case is:
- * import std.typecons;
- * void main() {
- * assert(tuple("has a", 2u) == tuple("has a", 1));
- * }
- */
- if (!(m.lastf == lastf && m.count == 2 && count == 1))
- {
- // Error, ambiguous
- e->error("overloads %s and %s both match argument list for %s",
- m.lastf->type->toChars(),
- m.nextf->type->toChars(),
- m.lastf->toChars());
- }
- }
- else if (m.last <= MATCHnomatch)
- {
- m.lastf = m.anyf;
- }
-
- Expression *result;
- if ((lastf && m.lastf == lastf) || (!s_r && m.last <= MATCHnomatch))
- {
- // Rewrite (e1 op e2) as e1.opfunc(e2)
- result = build_overload(e->loc, sc, e->e1, e->e2, m.lastf ? m.lastf : s);
- }
- else
- {
- // Rewrite (e1 op e2) as e2.opfunc_r(e1)
- result = build_overload(e->loc, sc, e->e2, e->e1, m.lastf ? m.lastf : s_r);
-
- // When reversing operands of comparison operators,
- // need to reverse the sense of the op
- switch (e->op)
- {
- case TOKlt: e->op = TOKgt; break;
- case TOKgt: e->op = TOKlt; break;
- case TOKle: e->op = TOKge; break;
- case TOKge: e->op = TOKle; break;
-
- // The rest are symmetric
- default:
- break;
- }
- }
-
- return result;
- }
-
- // Try alias this on first operand
- if (ad1 && ad1->aliasthis)
- {
- /* Rewrite (e1 op e2) as:
- * (e1.aliasthis op e2)
- */
- if (e->att1 && e->e1->type == e->att1)
- return NULL;
- //printf("att cmp_bin e1 = %s\n", e->e1->type->toChars());
- Expression *e1 = new DotIdExp(e->loc, e->e1, ad1->aliasthis->ident);
- BinExp *be = (BinExp *)e->copy();
- if (!be->att1 && e->e1->type->checkAliasThisRec())
- be->att1 = e->e1->type;
- be->e1 = e1;
- return trySemantic(be, sc);
- }
-
- // Try alias this on second operand
- if (ad2 && ad2->aliasthis)
- {
- /* Rewrite (e1 op e2) as:
- * (e1 op e2.aliasthis)
- */
- if (e->att2 && e->e2->type == e->att2)
- return NULL;
- //printf("att cmp_bin e2 = %s\n", e->e2->type->toChars());
- Expression *e2 = new DotIdExp(e->loc, e->e2, ad2->aliasthis->ident);
- BinExp *be = (BinExp *)e->copy();
- if (!be->att2 && e->e2->type->checkAliasThisRec())
- be->att2 = e->e2->type;
- be->e2 = e2;
- return trySemantic(be, sc);
- }
-
- return NULL;
-}
-
-/***********************************
- * Utility to build a function call out of this reference and argument.
- */
-
-Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg,
- Dsymbol *d)
-{
- assert(d);
- Expression *e;
-
- //printf("build_overload(id = '%s')\n", id->toChars());
- //earg->print();
- //earg->type->print();
- Declaration *decl = d->isDeclaration();
- if (decl)
- e = new DotVarExp(loc, ethis, decl, false);
- else
- e = new DotIdExp(loc, ethis, d->ident);
- e = new CallExp(loc, e, earg);
-
- e = expressionSemantic(e, sc);
- return e;
-}
-
-/***************************************
- * Search for function funcid in aggregate ad.
- */
-
-Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid)
-{
- Dsymbol *s = ad->search(Loc(), funcid);
- if (s)
- {
- //printf("search_function: s = '%s'\n", s->kind());
- Dsymbol *s2 = s->toAlias();
- //printf("search_function: s2 = '%s'\n", s2->kind());
- FuncDeclaration *fd = s2->isFuncDeclaration();
- if (fd && fd->type->ty == Tfunction)
- return fd;
-
- TemplateDeclaration *td = s2->isTemplateDeclaration();
- if (td)
- return td;
- }
- return NULL;
-}
-
-
-bool inferAggregate(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply)
-{
- //printf("inferAggregate(%s)\n", fes->aggr->toChars());
- Identifier *idapply = (fes->op == TOKforeach) ? Id::apply : Id::applyReverse;
- Identifier *idfront = (fes->op == TOKforeach) ? Id::Ffront : Id::Fback;
- int sliced = 0;
- Type *tab;
- Type *att = NULL;
- Expression *aggr = fes->aggr;
- AggregateDeclaration *ad;
-
- while (1)
- {
- aggr = expressionSemantic(aggr, sc);
- aggr = resolveProperties(sc, aggr);
- aggr = aggr->optimize(WANTvalue);
- if (!aggr->type || aggr->op == TOKerror)
- goto Lerr;
-
- tab = aggr->type->toBasetype();
- switch (tab->ty)
- {
- case Tarray:
- case Tsarray:
- case Ttuple:
- case Taarray:
- break;
-
- case Tclass:
- ad = ((TypeClass *)tab)->sym;
- goto Laggr;
-
- case Tstruct:
- ad = ((TypeStruct *)tab)->sym;
- goto Laggr;
-
- Laggr:
- if (!sliced)
- {
- sapply = search_function(ad, idapply);
- if (sapply)
- {
- // opApply aggregate
- break;
- }
-
- if (fes->aggr->op != TOKtype)
- {
- Expression *rinit = new ArrayExp(fes->aggr->loc, fes->aggr);
- rinit = trySemantic(rinit, sc);
- if (rinit) // if application of [] succeeded
- {
- aggr = rinit;
- sliced = 1;
- continue;
- }
- }
- }
-
- if (ad->search(Loc(), idfront))
- {
- // range aggregate
- break;
- }
-
- if (ad->aliasthis)
- {
- if (att == tab)
- goto Lerr;
- if (!att && tab->checkAliasThisRec())
- att = tab;
- aggr = resolveAliasThis(sc, aggr);
- continue;
- }
- goto Lerr;
-
- case Tdelegate:
- if (aggr->op == TOKdelegate)
- {
- sapply = ((DelegateExp *)aggr)->func;
- }
- break;
-
- case Terror:
- break;
-
- default:
- goto Lerr;
- }
- break;
- }
- fes->aggr = aggr;
- return true;
-
-Lerr:
- return false;
-}
-
-/*****************************************
- * Given array of parameters and an aggregate type,
- * if any of the parameter types are missing, attempt to infer
- * them from the aggregate type.
- */
-
-bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply)
-{
- if (!fes->parameters || !fes->parameters->length)
- return false;
-
- if (sapply) // prefer opApply
- {
- for (size_t u = 0; u < fes->parameters->length; u++)
- {
- Parameter *p = (*fes->parameters)[u];
- if (p->type)
- {
- p->type = typeSemantic(p->type, fes->loc, sc);
- p->type = p->type->addStorageClass(p->storageClass);
- }
- }
-
- Expression *ethis;
- Type *tab = fes->aggr->type->toBasetype();
- if (tab->ty == Tclass || tab->ty == Tstruct)
- ethis = fes->aggr;
- else
- { assert(tab->ty == Tdelegate && fes->aggr->op == TOKdelegate);
- ethis = ((DelegateExp *)fes->aggr)->e1;
- }
-
- /* Look for like an
- * int opApply(int delegate(ref Type [, ...]) dg);
- * overload
- */
- FuncDeclaration *fd = sapply->isFuncDeclaration();
- if (fd)
- {
- sapply = inferApplyArgTypesX(ethis, fd, fes->parameters);
- }
- return sapply != NULL;
- }
-
- /* Return if no parameters need types.
- */
- for (size_t u = 0; u < fes->parameters->length; u++)
- {
- Parameter *p = (*fes->parameters)[u];
- if (!p->type)
- break;
- }
-
- AggregateDeclaration *ad;
-
- Parameter *p = (*fes->parameters)[0];
- Type *taggr = fes->aggr->type;
- assert(taggr);
- Type *tab = taggr->toBasetype();
- switch (tab->ty)
- {
- case Tarray:
- case Tsarray:
- case Ttuple:
- if (fes->parameters->length == 2)
- {
- if (!p->type)
- {
- p->type = Type::tsize_t; // key type
- p->type = p->type->addStorageClass(p->storageClass);
- }
- p = (*fes->parameters)[1];
- }
- if (!p->type && tab->ty != Ttuple)
- {
- p->type = tab->nextOf(); // value type
- p->type = p->type->addStorageClass(p->storageClass);
- }
- break;
-
- case Taarray:
- {
- TypeAArray *taa = (TypeAArray *)tab;
-
- if (fes->parameters->length == 2)
- {
- if (!p->type)
- {
- p->type = taa->index; // key type
- p->type = p->type->addStorageClass(p->storageClass);
- if (p->storageClass & STCref) // key must not be mutated via ref
- p->type = p->type->addMod(MODconst);
- }
- p = (*fes->parameters)[1];
- }
- if (!p->type)
- {
- p->type = taa->next; // value type
- p->type = p->type->addStorageClass(p->storageClass);
- }
- break;
- }
-
- case Tclass:
- ad = ((TypeClass *)tab)->sym;
- goto Laggr;
-
- case Tstruct:
- ad = ((TypeStruct *)tab)->sym;
- goto Laggr;
-
- Laggr:
- if (fes->parameters->length == 1)
- {
- if (!p->type)
- {
- /* Look for a front() or back() overload
- */
- Identifier *id = (fes->op == TOKforeach) ? Id::Ffront : Id::Fback;
- Dsymbol *s = ad->search(Loc(), id);
- FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
- if (fd)
- {
- // Resolve inout qualifier of front type
- p->type = fd->type->nextOf();
- if (p->type)
- {
- p->type = p->type->substWildTo(tab->mod);
- p->type = p->type->addStorageClass(p->storageClass);
- }
- }
- else if (s && s->isTemplateDeclaration())
- ;
- else if (s && s->isDeclaration())
- p->type = ((Declaration *)s)->type;
- else
- break;
- }
- break;
- }
- break;
-
- case Tdelegate:
- {
- if (!inferApplyArgTypesY((TypeFunction *)tab->nextOf(), fes->parameters))
- return false;
- break;
- }
-
- default:
- break; // ignore error, caught later
- }
- return true;
-}
-
-static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *parameters)
-{
- struct ParamOpOver
- {
- Parameters *parameters;
- MOD mod;
- MATCH match;
- FuncDeclaration *fd_best;
- FuncDeclaration *fd_ambig;
-
- static int fp(void *param, Dsymbol *s)
- {
- FuncDeclaration *f = s->isFuncDeclaration();
- if (!f)
- return 0;
- ParamOpOver *p = (ParamOpOver *)param;
- TypeFunction *tf = (TypeFunction *)f->type;
- MATCH m = MATCHexact;
-
- if (f->isThis())
- {
- if (!MODimplicitConv(p->mod, tf->mod))
- m = MATCHnomatch;
- else if (p->mod != tf->mod)
- m = MATCHconst;
- }
- if (!inferApplyArgTypesY(tf, p->parameters, 1))
- m = MATCHnomatch;
-
- if (m > p->match)
- {
- p->fd_best = f;
- p->fd_ambig = NULL;
- p->match = m;
- }
- else if (m == p->match)
- p->fd_ambig = f;
- return 0;
- }
- };
- ParamOpOver p;
- p.parameters = parameters;
- p.mod = ethis->type->mod;
- p.match = MATCHnomatch;
- p.fd_best = NULL;
- p.fd_ambig = NULL;
- overloadApply(fstart, &p, &ParamOpOver::fp);
- if (p.fd_best)
- {
- inferApplyArgTypesY((TypeFunction *)p.fd_best->type, parameters);
- if (p.fd_ambig)
- { ::error(ethis->loc, "%s.%s matches more than one declaration:\n%s: %s\nand:\n%s: %s",
- ethis->toChars(), fstart->ident->toChars(),
- p.fd_best ->loc.toChars(), p.fd_best ->type->toChars(),
- p.fd_ambig->loc.toChars(), p.fd_ambig->type->toChars());
- p.fd_best = NULL;
- }
- }
- return p.fd_best;
-}
-
-/******************************
- * Infer parameters from type of function.
- * Returns:
- * 1 match for this function
- * 0 no match for this function
- */
-
-static int inferApplyArgTypesY(TypeFunction *tf, Parameters *parameters, int flags)
-{ size_t nparams;
- Parameter *p;
-
- if (tf->parameterList.length() != 1)
- goto Lnomatch;
- p = tf->parameterList[0];
- if (p->type->ty != Tdelegate)
- goto Lnomatch;
- tf = (TypeFunction *)p->type->nextOf();
- assert(tf->ty == Tfunction);
-
- /* We now have tf, the type of the delegate. Match it against
- * the parameters, filling in missing parameter types.
- */
- nparams = tf->parameterList.length();
- if (nparams == 0 || tf->parameterList.varargs != VARARGnone)
- goto Lnomatch; // not enough parameters
- if (parameters->length != nparams)
- goto Lnomatch; // not enough parameters
-
- for (size_t u = 0; u < nparams; u++)
- {
- p = (*parameters)[u];
- Parameter *param = tf->parameterList[u];
- if (p->type)
- {
- if (!p->type->equals(param->type))
- goto Lnomatch;
- }
- else if (!flags)
- {
- p->type = param->type;
- p->type = p->type->addStorageClass(p->storageClass);
- }
- }
- return 1;
-
-Lnomatch:
- return 0;
-}
-
diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d
new file mode 100644
index 0000000..4ef55f3
--- /dev/null
+++ b/gcc/d/dmd/opover.d
@@ -0,0 +1,1843 @@
+/**
+ * Handles operator overloading.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/operatoroverloading.html, Operator Overloading)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/opover.d, _opover.d)
+ * Documentation: https://dlang.org/phobos/dmd_opover.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/opover.d
+ */
+
+module dmd.opover;
+
+import core.stdc.stdio;
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.statement;
+import dmd.tokens;
+import dmd.typesem;
+import dmd.visitor;
+
+/***********************************
+ * Determine if operands of binary op can be reversed
+ * to fit operator overload.
+ */
+bool isCommutative(TOK op)
+{
+ switch (op)
+ {
+ case TOK.add:
+ case TOK.mul:
+ case TOK.and:
+ case TOK.or:
+ case TOK.xor:
+ // EqualExp
+ case TOK.equal:
+ case TOK.notEqual:
+ // CmpExp
+ case TOK.lessThan:
+ case TOK.lessOrEqual:
+ case TOK.greaterThan:
+ case TOK.greaterOrEqual:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+/***********************************
+ * Get Identifier for operator overload.
+ */
+private Identifier opId(Expression e)
+{
+ switch (e.op)
+ {
+ case TOK.uadd: return Id.uadd;
+ case TOK.negate: return Id.neg;
+ case TOK.tilde: return Id.com;
+ case TOK.cast_: return Id._cast;
+ case TOK.in_: return Id.opIn;
+ case TOK.plusPlus: return Id.postinc;
+ case TOK.minusMinus: return Id.postdec;
+ case TOK.add: return Id.add;
+ case TOK.min: return Id.sub;
+ case TOK.mul: return Id.mul;
+ case TOK.div: return Id.div;
+ case TOK.mod: return Id.mod;
+ case TOK.pow: return Id.pow;
+ case TOK.leftShift: return Id.shl;
+ case TOK.rightShift: return Id.shr;
+ case TOK.unsignedRightShift: return Id.ushr;
+ case TOK.and: return Id.iand;
+ case TOK.or: return Id.ior;
+ case TOK.xor: return Id.ixor;
+ case TOK.concatenate: return Id.cat;
+ case TOK.assign: return Id.assign;
+ case TOK.addAssign: return Id.addass;
+ case TOK.minAssign: return Id.subass;
+ case TOK.mulAssign: return Id.mulass;
+ case TOK.divAssign: return Id.divass;
+ case TOK.modAssign: return Id.modass;
+ case TOK.powAssign: return Id.powass;
+ case TOK.leftShiftAssign: return Id.shlass;
+ case TOK.rightShiftAssign: return Id.shrass;
+ case TOK.unsignedRightShiftAssign: return Id.ushrass;
+ case TOK.andAssign: return Id.andass;
+ case TOK.orAssign: return Id.orass;
+ case TOK.xorAssign: return Id.xorass;
+ case TOK.concatenateAssign: return Id.catass;
+ case TOK.equal: return Id.eq;
+ case TOK.lessThan:
+ case TOK.lessOrEqual:
+ case TOK.greaterThan:
+ case TOK.greaterOrEqual: return Id.cmp;
+ case TOK.array: return Id.index;
+ case TOK.star: return Id.opStar;
+ default: assert(0);
+ }
+}
+
+/***********************************
+ * Get Identifier for reverse operator overload,
+ * `null` if not supported for this operator.
+ */
+private Identifier opId_r(Expression e)
+{
+ switch (e.op)
+ {
+ case TOK.in_: return Id.opIn_r;
+ case TOK.add: return Id.add_r;
+ case TOK.min: return Id.sub_r;
+ case TOK.mul: return Id.mul_r;
+ case TOK.div: return Id.div_r;
+ case TOK.mod: return Id.mod_r;
+ case TOK.pow: return Id.pow_r;
+ case TOK.leftShift: return Id.shl_r;
+ case TOK.rightShift: return Id.shr_r;
+ case TOK.unsignedRightShift:return Id.ushr_r;
+ case TOK.and: return Id.iand_r;
+ case TOK.or: return Id.ior_r;
+ case TOK.xor: return Id.ixor_r;
+ case TOK.concatenate: return Id.cat_r;
+ default: return null;
+ }
+}
+
+/*******************************************
+ * Helper function to turn operator into template argument list
+ */
+Objects* opToArg(Scope* sc, TOK op)
+{
+ /* Remove the = from op=
+ */
+ switch (op)
+ {
+ case TOK.addAssign:
+ op = TOK.add;
+ break;
+ case TOK.minAssign:
+ op = TOK.min;
+ break;
+ case TOK.mulAssign:
+ op = TOK.mul;
+ break;
+ case TOK.divAssign:
+ op = TOK.div;
+ break;
+ case TOK.modAssign:
+ op = TOK.mod;
+ break;
+ case TOK.andAssign:
+ op = TOK.and;
+ break;
+ case TOK.orAssign:
+ op = TOK.or;
+ break;
+ case TOK.xorAssign:
+ op = TOK.xor;
+ break;
+ case TOK.leftShiftAssign:
+ op = TOK.leftShift;
+ break;
+ case TOK.rightShiftAssign:
+ op = TOK.rightShift;
+ break;
+ case TOK.unsignedRightShiftAssign:
+ op = TOK.unsignedRightShift;
+ break;
+ case TOK.concatenateAssign:
+ op = TOK.concatenate;
+ break;
+ case TOK.powAssign:
+ op = TOK.pow;
+ break;
+ default:
+ break;
+ }
+ Expression e = new StringExp(Loc.initial, Token.toString(op));
+ e = e.expressionSemantic(sc);
+ auto tiargs = new Objects();
+ tiargs.push(e);
+ return tiargs;
+}
+
+// Try alias this on first operand
+private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinExp e)
+{
+ if (!ad || !ad.aliasthis)
+ return null;
+
+ /* Rewrite (e1 op e2) as:
+ * (e1.aliasthis op e2)
+ */
+ if (isRecursiveAliasThis(e.att1, e.e1.type))
+ return null;
+ //printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
+ Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident);
+ BinExp be = cast(BinExp)e.copy();
+ be.e1 = e1;
+
+ Expression result;
+ if (be.op == TOK.concatenateAssign)
+ result = be.op_overload(sc);
+ else
+ result = be.trySemantic(sc);
+
+ return result;
+}
+
+// Try alias this on second operand
+private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinExp e)
+{
+ if (!ad || !ad.aliasthis)
+ return null;
+ /* Rewrite (e1 op e2) as:
+ * (e1 op e2.aliasthis)
+ */
+ if (isRecursiveAliasThis(e.att2, e.e2.type))
+ return null;
+ //printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
+ Expression e2 = new DotIdExp(e.loc, e.e2, ad.aliasthis.ident);
+ BinExp be = cast(BinExp)e.copy();
+ be.e2 = e2;
+
+ Expression result;
+ if (be.op == TOK.concatenateAssign)
+ result = be.op_overload(sc);
+ else
+ result = be.trySemantic(sc);
+
+ return result;
+}
+
+/************************************
+ * Operator overload.
+ * Check for operator overload, if so, replace
+ * with function call.
+ * Params:
+ * e = expression with operator
+ * sc = context
+ * pop = if not null, is set to the operator that was actually overloaded,
+ * which may not be `e.op`. Happens when operands are reversed to
+ * match an overload
+ * Returns:
+ * `null` if not an operator overload,
+ * otherwise the lowered expression
+ */
+Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
+{
+ extern (C++) final class OpOverload : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ Scope* sc;
+ TOK* pop;
+ Expression result;
+
+ extern (D) this(Scope* sc, TOK* pop)
+ {
+ this.sc = sc;
+ this.pop = pop;
+ }
+
+ override void visit(Expression e)
+ {
+ assert(0);
+ }
+
+ override void visit(UnaExp e)
+ {
+ //printf("UnaExp::op_overload() (%s)\n", e.toChars());
+ if (e.e1.op == TOK.array)
+ {
+ ArrayExp ae = cast(ArrayExp)e.e1;
+ ae.e1 = ae.e1.expressionSemantic(sc);
+ ae.e1 = resolveProperties(sc, ae.e1);
+ Expression ae1old = ae.e1;
+ const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval);
+ IntervalExp ie = null;
+ if (maybeSlice && ae.arguments.dim)
+ {
+ assert((*ae.arguments)[0].op == TOK.interval);
+ ie = cast(IntervalExp)(*ae.arguments)[0];
+ }
+ while (true)
+ {
+ if (ae.e1.op == TOK.error)
+ {
+ result = ae.e1;
+ return;
+ }
+ Expression e0 = null;
+ Expression ae1save = ae.e1;
+ ae.lengthVar = null;
+ Type t1b = ae.e1.type.toBasetype();
+ AggregateDeclaration ad = isAggregate(t1b);
+ if (!ad)
+ break;
+ if (search_function(ad, Id.opIndexUnary))
+ {
+ // Deal with $
+ result = resolveOpDollar(sc, ae, &e0);
+ if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j)
+ goto Lfallback;
+ if (result.op == TOK.error)
+ return;
+ /* Rewrite op(a[arguments]) as:
+ * a.opIndexUnary!(op)(arguments)
+ */
+ Expressions* a = ae.arguments.copy();
+ Objects* tiargs = opToArg(sc, e.op);
+ result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opIndexUnary, tiargs);
+ result = new CallExp(e.loc, result, a);
+ if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)()
+ result = result.trySemantic(sc);
+ else
+ result = result.expressionSemantic(sc);
+ if (result)
+ {
+ result = Expression.combine(e0, result);
+ return;
+ }
+ }
+ Lfallback:
+ if (maybeSlice && search_function(ad, Id.opSliceUnary))
+ {
+ // Deal with $
+ result = resolveOpDollar(sc, ae, ie, &e0);
+ if (result.op == TOK.error)
+ return;
+ /* Rewrite op(a[i..j]) as:
+ * a.opSliceUnary!(op)(i, j)
+ */
+ auto a = new Expressions();
+ if (ie)
+ {
+ a.push(ie.lwr);
+ a.push(ie.upr);
+ }
+ Objects* tiargs = opToArg(sc, e.op);
+ result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opSliceUnary, tiargs);
+ result = new CallExp(e.loc, result, a);
+ result = result.expressionSemantic(sc);
+ result = Expression.combine(e0, result);
+ return;
+ }
+ // Didn't find it. Forward to aliasthis
+ if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
+ {
+ /* Rewrite op(a[arguments]) as:
+ * op(a.aliasthis[arguments])
+ */
+ ae.e1 = resolveAliasThis(sc, ae1save, true);
+ if (ae.e1)
+ continue;
+ }
+ break;
+ }
+ ae.e1 = ae1old; // recovery
+ ae.lengthVar = null;
+ }
+ e.e1 = e.e1.expressionSemantic(sc);
+ e.e1 = resolveProperties(sc, e.e1);
+ if (e.e1.op == TOK.error)
+ {
+ result = e.e1;
+ return;
+ }
+ AggregateDeclaration ad = isAggregate(e.e1.type);
+ if (ad)
+ {
+ Dsymbol fd = null;
+ /* Rewrite as:
+ * e1.opUnary!(op)()
+ */
+ fd = search_function(ad, Id.opUnary);
+ if (fd)
+ {
+ Objects* tiargs = opToArg(sc, e.op);
+ result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs);
+ result = new CallExp(e.loc, result);
+ result = result.expressionSemantic(sc);
+ return;
+ }
+ // D1-style operator overloads, deprecated
+ if (e.op != TOK.prePlusPlus && e.op != TOK.preMinusMinus)
+ {
+ auto id = opId(e);
+ fd = search_function(ad, id);
+ if (fd)
+ {
+ // @@@DEPRECATED_2.098@@@.
+ // Deprecated in 2.088
+ // Make an error in 2.098
+ e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), Token.toChars(e.op));
+ // Rewrite +e1 as e1.add()
+ result = build_overload(e.loc, sc, e.e1, null, fd);
+ return;
+ }
+ }
+ // Didn't find it. Forward to aliasthis
+ if (ad.aliasthis && !isRecursiveAliasThis(e.att1, e.e1.type))
+ {
+ /* Rewrite op(e1) as:
+ * op(e1.aliasthis)
+ */
+ //printf("att una %s e1 = %s\n", Token::toChars(op), this.e1.type.toChars());
+ Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident);
+ UnaExp ue = cast(UnaExp)e.copy();
+ ue.e1 = e1;
+ result = ue.trySemantic(sc);
+ return;
+ }
+ }
+ }
+
+ override void visit(ArrayExp ae)
+ {
+ //printf("ArrayExp::op_overload() (%s)\n", ae.toChars());
+ ae.e1 = ae.e1.expressionSemantic(sc);
+ ae.e1 = resolveProperties(sc, ae.e1);
+ Expression ae1old = ae.e1;
+ const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval);
+ IntervalExp ie = null;
+ if (maybeSlice && ae.arguments.dim)
+ {
+ assert((*ae.arguments)[0].op == TOK.interval);
+ ie = cast(IntervalExp)(*ae.arguments)[0];
+ }
+ while (true)
+ {
+ if (ae.e1.op == TOK.error)
+ {
+ result = ae.e1;
+ return;
+ }
+ Expression e0 = null;
+ Expression ae1save = ae.e1;
+ ae.lengthVar = null;
+ Type t1b = ae.e1.type.toBasetype();
+ AggregateDeclaration ad = isAggregate(t1b);
+ if (!ad)
+ {
+ // If the non-aggregate expression ae.e1 is indexable or sliceable,
+ // convert it to the corresponding concrete expression.
+ if (isIndexableNonAggregate(t1b) || ae.e1.op == TOK.type)
+ {
+ // Convert to SliceExp
+ if (maybeSlice)
+ {
+ result = new SliceExp(ae.loc, ae.e1, ie);
+ result = result.expressionSemantic(sc);
+ return;
+ }
+ // Convert to IndexExp
+ if (ae.arguments.dim == 1)
+ {
+ result = new IndexExp(ae.loc, ae.e1, (*ae.arguments)[0]);
+ result = result.expressionSemantic(sc);
+ return;
+ }
+ }
+ break;
+ }
+ if (search_function(ad, Id.index))
+ {
+ // Deal with $
+ result = resolveOpDollar(sc, ae, &e0);
+ if (!result) // a[i..j] might be: a.opSlice(i, j)
+ goto Lfallback;
+ if (result.op == TOK.error)
+ return;
+ /* Rewrite e1[arguments] as:
+ * e1.opIndex(arguments)
+ */
+ Expressions* a = ae.arguments.copy();
+ result = new DotIdExp(ae.loc, ae.e1, Id.index);
+ result = new CallExp(ae.loc, result, a);
+ if (maybeSlice) // a[] might be: a.opSlice()
+ result = result.trySemantic(sc);
+ else
+ result = result.expressionSemantic(sc);
+ if (result)
+ {
+ result = Expression.combine(e0, result);
+ return;
+ }
+ }
+ Lfallback:
+ if (maybeSlice && ae.e1.op == TOK.type)
+ {
+ result = new SliceExp(ae.loc, ae.e1, ie);
+ result = result.expressionSemantic(sc);
+ result = Expression.combine(e0, result);
+ return;
+ }
+ if (maybeSlice && search_function(ad, Id.slice))
+ {
+ // Deal with $
+ result = resolveOpDollar(sc, ae, ie, &e0);
+ if (result.op == TOK.error)
+ return;
+ /* Rewrite a[i..j] as:
+ * a.opSlice(i, j)
+ */
+ auto a = new Expressions();
+ if (ie)
+ {
+ a.push(ie.lwr);
+ a.push(ie.upr);
+ }
+ result = new DotIdExp(ae.loc, ae.e1, Id.slice);
+ result = new CallExp(ae.loc, result, a);
+ result = result.expressionSemantic(sc);
+ result = Expression.combine(e0, result);
+ return;
+ }
+ // Didn't find it. Forward to aliasthis
+ if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
+ {
+ //printf("att arr e1 = %s\n", this.e1.type.toChars());
+ /* Rewrite op(a[arguments]) as:
+ * op(a.aliasthis[arguments])
+ */
+ ae.e1 = resolveAliasThis(sc, ae1save, true);
+ if (ae.e1)
+ continue;
+ }
+ break;
+ }
+ ae.e1 = ae1old; // recovery
+ ae.lengthVar = null;
+ }
+
+ /***********************************************
+ * This is mostly the same as UnaryExp::op_overload(), but has
+ * a different rewrite.
+ */
+ override void visit(CastExp e)
+ {
+ //printf("CastExp::op_overload() (%s)\n", e.toChars());
+ AggregateDeclaration ad = isAggregate(e.e1.type);
+ if (ad)
+ {
+ Dsymbol fd = null;
+ /* Rewrite as:
+ * e1.opCast!(T)()
+ */
+ fd = search_function(ad, Id._cast);
+ if (fd)
+ {
+ version (all)
+ {
+ // Backwards compatibility with D1 if opCast is a function, not a template
+ if (fd.isFuncDeclaration())
+ {
+ // Rewrite as: e1.opCast()
+ result = build_overload(e.loc, sc, e.e1, null, fd);
+ return;
+ }
+ }
+ auto tiargs = new Objects();
+ tiargs.push(e.to);
+ result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs);
+ result = new CallExp(e.loc, result);
+ result = result.expressionSemantic(sc);
+ return;
+ }
+ // Didn't find it. Forward to aliasthis
+ if (ad.aliasthis && !isRecursiveAliasThis(e.att1, e.e1.type))
+ {
+ /* Rewrite op(e1) as:
+ * op(e1.aliasthis)
+ */
+ Expression e1 = resolveAliasThis(sc, e.e1);
+ result = e.copy();
+ (cast(UnaExp)result).e1 = e1;
+ result = result.op_overload(sc);
+ return;
+ }
+ }
+ }
+
+ override void visit(BinExp e)
+ {
+ //printf("BinExp::op_overload() (%s)\n", e.toChars());
+ Identifier id = opId(e);
+ Identifier id_r = opId_r(e);
+ Expressions args1;
+ Expressions args2;
+ int argsset = 0;
+ AggregateDeclaration ad1 = isAggregate(e.e1.type);
+ AggregateDeclaration ad2 = isAggregate(e.e2.type);
+ if (e.op == TOK.assign && ad1 == ad2)
+ {
+ StructDeclaration sd = ad1.isStructDeclaration();
+ if (sd &&
+ (!sd.hasIdentityAssign ||
+ /* Do a blit if we can and the rvalue is something like .init,
+ * where a postblit is not necessary.
+ */
+ (sd.hasBlitAssign && !e.e2.isLvalue())))
+ {
+ /* This is bitwise struct assignment. */
+ return;
+ }
+ }
+ Dsymbol s = null;
+ Dsymbol s_r = null;
+ Objects* tiargs = null;
+ if (e.op == TOK.plusPlus || e.op == TOK.minusMinus)
+ {
+ // Bug4099 fix
+ if (ad1 && search_function(ad1, Id.opUnary))
+ return;
+ }
+ if (e.op != TOK.equal && e.op != TOK.notEqual && e.op != TOK.assign && e.op != TOK.plusPlus && e.op != TOK.minusMinus)
+ {
+ /* Try opBinary and opBinaryRight
+ */
+ if (ad1)
+ {
+ s = search_function(ad1, Id.opBinary);
+ if (s && !s.isTemplateDeclaration())
+ {
+ e.e1.error("`%s.opBinary` isn't a template", e.e1.toChars());
+ result = ErrorExp.get();
+ return;
+ }
+ }
+ if (ad2)
+ {
+ s_r = search_function(ad2, Id.opBinaryRight);
+ if (s_r && !s_r.isTemplateDeclaration())
+ {
+ e.e2.error("`%s.opBinaryRight` isn't a template", e.e2.toChars());
+ result = ErrorExp.get();
+ return;
+ }
+ if (s_r && s_r == s) // https://issues.dlang.org/show_bug.cgi?id=12778
+ s_r = null;
+ }
+ // Set tiargs, the template argument list, which will be the operator string
+ if (s || s_r)
+ {
+ id = Id.opBinary;
+ id_r = Id.opBinaryRight;
+ tiargs = opToArg(sc, e.op);
+ }
+ }
+ if (!s && !s_r)
+ {
+ // Try the D1-style operators, deprecated
+ if (ad1 && id)
+ {
+ s = search_function(ad1, id);
+ if (s && id != Id.assign)
+ {
+ // @@@DEPRECATED_2.098@@@.
+ // Deprecated in 2.088
+ // Make an error in 2.098
+ if (id == Id.postinc || id == Id.postdec)
+ e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), Token.toChars(e.op));
+ else
+ e.deprecation("`%s` is deprecated. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), Token.toChars(e.op));
+ }
+ }
+ if (ad2 && id_r)
+ {
+ s_r = search_function(ad2, id_r);
+ // https://issues.dlang.org/show_bug.cgi?id=12778
+ // If both x.opBinary(y) and y.opBinaryRight(x) found,
+ // and they are exactly same symbol, x.opBinary(y) should be preferred.
+ if (s_r && s_r == s)
+ s_r = null;
+ if (s_r)
+ {
+ // @@@DEPRECATED_2.098@@@.
+ // Deprecated in 2.088
+ // Make an error in 2.098
+ e.deprecation("`%s` is deprecated. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), Token.toChars(e.op));
+ }
+ }
+ }
+ if (s || s_r)
+ {
+ /* Try:
+ * a.opfunc(b)
+ * b.opfunc_r(a)
+ * and see which is better.
+ */
+ args1.setDim(1);
+ args1[0] = e.e1;
+ expandTuples(&args1);
+ args2.setDim(1);
+ args2[0] = e.e2;
+ expandTuples(&args2);
+ argsset = 1;
+ MatchAccumulator m;
+ if (s)
+ {
+ functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
+ if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ }
+ FuncDeclaration lastf = m.lastf;
+ if (s_r)
+ {
+ functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1);
+ if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ }
+ if (m.count > 1)
+ {
+ // Error, ambiguous
+ e.error("overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars());
+ }
+ else if (m.last == MATCH.nomatch)
+ {
+ if (tiargs)
+ goto L1;
+ m.lastf = null;
+ }
+ if (e.op == TOK.plusPlus || e.op == TOK.minusMinus)
+ {
+ // Kludge because operator overloading regards e++ and e--
+ // as unary, but it's implemented as a binary.
+ // Rewrite (e1 ++ e2) as e1.postinc()
+ // Rewrite (e1 -- e2) as e1.postdec()
+ result = build_overload(e.loc, sc, e.e1, null, m.lastf ? m.lastf : s);
+ }
+ else if (lastf && m.lastf == lastf || !s_r && m.last == MATCH.nomatch)
+ {
+ // Rewrite (e1 op e2) as e1.opfunc(e2)
+ result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
+ }
+ else
+ {
+ // Rewrite (e1 op e2) as e2.opfunc_r(e1)
+ result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r);
+ }
+ return;
+ }
+ L1:
+ version (all)
+ {
+ // Retained for D1 compatibility
+ if (isCommutative(e.op) && !tiargs)
+ {
+ s = null;
+ s_r = null;
+ if (ad1 && id_r)
+ {
+ s_r = search_function(ad1, id_r);
+ }
+ if (ad2 && id)
+ {
+ s = search_function(ad2, id);
+ if (s && s == s_r) // https://issues.dlang.org/show_bug.cgi?id=12778
+ s = null;
+ }
+ if (s || s_r)
+ {
+ /* Try:
+ * a.opfunc_r(b)
+ * b.opfunc(a)
+ * and see which is better.
+ */
+ if (!argsset)
+ {
+ args1.setDim(1);
+ args1[0] = e.e1;
+ expandTuples(&args1);
+ args2.setDim(1);
+ args2[0] = e.e2;
+ expandTuples(&args2);
+ }
+ MatchAccumulator m;
+ if (s_r)
+ {
+ functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, &args2);
+ if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ }
+ FuncDeclaration lastf = m.lastf;
+ if (s)
+ {
+ functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, &args1);
+ if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ }
+ if (m.count > 1)
+ {
+ // Error, ambiguous
+ e.error("overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars());
+ }
+ else if (m.last == MATCH.nomatch)
+ {
+ m.lastf = null;
+ }
+
+ if (lastf && m.lastf == lastf || !s && m.last == MATCH.nomatch)
+ {
+ // Rewrite (e1 op e2) as e1.opfunc_r(e2)
+ result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s_r);
+ }
+ else
+ {
+ // Rewrite (e1 op e2) as e2.opfunc(e1)
+ result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s);
+ }
+ // When reversing operands of comparison operators,
+ // need to reverse the sense of the op
+ if (pop)
+ *pop = reverseRelation(e.op);
+ return;
+ }
+ }
+ }
+
+ Expression tempResult;
+ if (!(e.op == TOK.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
+ {
+ result = checkAliasThisForLhs(ad1, sc, e);
+ if (result)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=19441
+ *
+ * alias this may not be used for partial assignment.
+ * If a struct has a single member which is aliased this
+ * directly or aliased to a ref getter function that returns
+ * the mentioned member, then alias this may be
+ * used since the object will be fully initialised.
+ * If the struct is nested, the context pointer is considered
+ * one of the members, hence the `ad1.fields.dim == 2 && ad1.vthis`
+ * condition.
+ */
+ if (e.op != TOK.assign || e.e1.op == TOK.type)
+ return;
+
+ if (ad1.fields.dim == 1 || (ad1.fields.dim == 2 && ad1.vthis))
+ {
+ auto var = ad1.aliasthis.sym.isVarDeclaration();
+ if (var && var.type == ad1.fields[0].type)
+ return;
+
+ auto func = ad1.aliasthis.sym.isFuncDeclaration();
+ auto tf = cast(TypeFunction)(func.type);
+ if (tf.isref && ad1.fields[0].type == tf.next)
+ return;
+ }
+ tempResult = result;
+ }
+ }
+ if (!(e.op == TOK.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
+ {
+ result = checkAliasThisForRhs(ad2, sc, e);
+ if (result)
+ return;
+ }
+
+ // @@@DEPRECATED_2019-02@@@
+ // 1. Deprecation for 1 year
+ // 2. Turn to error after
+ if (tempResult)
+ {
+ // move this line where tempResult is assigned to result and turn to error when derecation period is over
+ e.deprecation("Cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`", e.e1.toChars(), ad1.toChars(), (cast(BinExp)tempResult).e1.toChars());
+ // delete this line when deprecation period is over
+ result = tempResult;
+ }
+ }
+
+ override void visit(EqualExp e)
+ {
+ //printf("EqualExp::op_overload() (%s)\n", e.toChars());
+ Type t1 = e.e1.type.toBasetype();
+ Type t2 = e.e2.type.toBasetype();
+
+ /* Array equality is handled by expressionSemantic() potentially
+ * lowering to object.__equals(), which takes care of overloaded
+ * operators for the element types.
+ */
+ if ((t1.ty == Tarray || t1.ty == Tsarray) &&
+ (t2.ty == Tarray || t2.ty == Tsarray))
+ {
+ return;
+ }
+
+ /* Check for class equality with null literal or typeof(null).
+ */
+ if (t1.ty == Tclass && e.e2.op == TOK.null_ ||
+ t2.ty == Tclass && e.e1.op == TOK.null_)
+ {
+ e.error("use `%s` instead of `%s` when comparing with `null`",
+ Token.toChars(e.op == TOK.equal ? TOK.identity : TOK.notIdentity),
+ Token.toChars(e.op));
+ result = ErrorExp.get();
+ return;
+ }
+ if (t1.ty == Tclass && t2.ty == Tnull ||
+ t1.ty == Tnull && t2.ty == Tclass)
+ {
+ // Comparing a class with typeof(null) should not call opEquals
+ return;
+ }
+
+ /* Check for class equality.
+ */
+ if (t1.ty == Tclass && t2.ty == Tclass)
+ {
+ ClassDeclaration cd1 = t1.isClassHandle();
+ ClassDeclaration cd2 = t2.isClassHandle();
+ if (!(cd1.classKind == ClassKind.cpp || cd2.classKind == ClassKind.cpp))
+ {
+ /* Rewrite as:
+ * .object.opEquals(e1, e2)
+ */
+ Expression e1x = e.e1;
+ Expression e2x = e.e2;
+
+ /* The explicit cast is necessary for interfaces
+ * https://issues.dlang.org/show_bug.cgi?id=4088
+ */
+ Type to = ClassDeclaration.object.getType();
+ if (cd1.isInterfaceDeclaration())
+ e1x = new CastExp(e.loc, e.e1, t1.isMutable() ? to : to.constOf());
+ if (cd2.isInterfaceDeclaration())
+ e2x = new CastExp(e.loc, e.e2, t2.isMutable() ? to : to.constOf());
+
+ result = new IdentifierExp(e.loc, Id.empty);
+ result = new DotIdExp(e.loc, result, Id.object);
+ result = new DotIdExp(e.loc, result, Id.eq);
+ result = new CallExp(e.loc, result, e1x, e2x);
+ if (e.op == TOK.notEqual)
+ result = new NotExp(e.loc, result);
+ result = result.expressionSemantic(sc);
+ return;
+ }
+ }
+
+ result = compare_overload(e, sc, Id.eq, null);
+ if (result)
+ {
+ if (lastComma(result).op == TOK.call && e.op == TOK.notEqual)
+ {
+ result = new NotExp(result.loc, result);
+ result = result.expressionSemantic(sc);
+ }
+ return;
+ }
+
+ /* Check for pointer equality.
+ */
+ if (t1.ty == Tpointer || t2.ty == Tpointer)
+ {
+ /* Rewrite:
+ * ptr1 == ptr2
+ * as:
+ * ptr1 is ptr2
+ *
+ * This is just a rewriting for deterministic AST representation
+ * as the backend input.
+ */
+ auto op2 = e.op == TOK.equal ? TOK.identity : TOK.notIdentity;
+ result = new IdentityExp(op2, e.loc, e.e1, e.e2);
+ result = result.expressionSemantic(sc);
+ return;
+ }
+
+ /* Check for struct equality without opEquals.
+ */
+ if (t1.ty == Tstruct && t2.ty == Tstruct)
+ {
+ auto sd = (cast(TypeStruct)t1).sym;
+ if (sd != (cast(TypeStruct)t2).sym)
+ return;
+
+ import dmd.clone : needOpEquals;
+ if (!global.params.fieldwise && !needOpEquals(sd))
+ {
+ // Use bitwise equality.
+ auto op2 = e.op == TOK.equal ? TOK.identity : TOK.notIdentity;
+ result = new IdentityExp(op2, e.loc, e.e1, e.e2);
+ result = result.expressionSemantic(sc);
+ return;
+ }
+
+ /* Do memberwise equality.
+ * https://dlang.org/spec/expression.html#equality_expressions
+ * Rewrite:
+ * e1 == e2
+ * as:
+ * e1.tupleof == e2.tupleof
+ *
+ * If sd is a nested struct, and if it's nested in a class, it will
+ * also compare the parent class's equality. Otherwise, compares
+ * the identity of parent context through void*.
+ */
+ if (e.att1 && t1.equivalent(e.att1)) return;
+ if (e.att2 && t2.equivalent(e.att2)) return;
+
+ e = cast(EqualExp)e.copy();
+ if (!e.att1) e.att1 = t1;
+ if (!e.att2) e.att2 = t2;
+ e.e1 = new DotIdExp(e.loc, e.e1, Id._tupleof);
+ e.e2 = new DotIdExp(e.loc, e.e2, Id._tupleof);
+
+ auto sc2 = sc.push();
+ sc2.flags = (sc2.flags & ~SCOPE.onlysafeaccess) | SCOPE.noaccesscheck;
+ result = e.expressionSemantic(sc2);
+ sc2.pop();
+
+ /* https://issues.dlang.org/show_bug.cgi?id=15292
+ * if the rewrite result is same with the original,
+ * the equality is unresolvable because it has recursive definition.
+ */
+ if (result.op == e.op &&
+ (cast(EqualExp)result).e1.type.toBasetype() == t1)
+ {
+ e.error("cannot compare `%s` because its auto generated member-wise equality has recursive definition",
+ t1.toChars());
+ result = ErrorExp.get();
+ }
+ return;
+ }
+
+ /* Check for tuple equality.
+ */
+ if (e.e1.op == TOK.tuple && e.e2.op == TOK.tuple)
+ {
+ auto tup1 = cast(TupleExp)e.e1;
+ auto tup2 = cast(TupleExp)e.e2;
+ size_t dim = tup1.exps.dim;
+ if (dim != tup2.exps.dim)
+ {
+ e.error("mismatched tuple lengths, `%d` and `%d`",
+ cast(int)dim, cast(int)tup2.exps.dim);
+ result = ErrorExp.get();
+ return;
+ }
+
+ if (dim == 0)
+ {
+ // zero-length tuple comparison should always return true or false.
+ result = IntegerExp.createBool(e.op == TOK.equal);
+ }
+ else
+ {
+ for (size_t i = 0; i < dim; i++)
+ {
+ auto ex1 = (*tup1.exps)[i];
+ auto ex2 = (*tup2.exps)[i];
+ auto eeq = new EqualExp(e.op, e.loc, ex1, ex2);
+ eeq.att1 = e.att1;
+ eeq.att2 = e.att2;
+
+ if (!result)
+ result = eeq;
+ else if (e.op == TOK.equal)
+ result = new LogicalExp(e.loc, TOK.andAnd, result, eeq);
+ else
+ result = new LogicalExp(e.loc, TOK.orOr, result, eeq);
+ }
+ assert(result);
+ }
+ result = Expression.combine(tup1.e0, tup2.e0, result);
+ result = result.expressionSemantic(sc);
+
+ return;
+ }
+ }
+
+ override void visit(CmpExp e)
+ {
+ //printf("CmpExp:: () (%s)\n", e.toChars());
+ result = compare_overload(e, sc, Id.cmp, pop);
+ }
+
+ /*********************************
+ * Operator overloading for op=
+ */
+ override void visit(BinAssignExp e)
+ {
+ //printf("BinAssignExp::op_overload() (%s)\n", e.toChars());
+ if (e.e1.op == TOK.array)
+ {
+ ArrayExp ae = cast(ArrayExp)e.e1;
+ ae.e1 = ae.e1.expressionSemantic(sc);
+ ae.e1 = resolveProperties(sc, ae.e1);
+ Expression ae1old = ae.e1;
+ const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval);
+ IntervalExp ie = null;
+ if (maybeSlice && ae.arguments.dim)
+ {
+ assert((*ae.arguments)[0].op == TOK.interval);
+ ie = cast(IntervalExp)(*ae.arguments)[0];
+ }
+ while (true)
+ {
+ if (ae.e1.op == TOK.error)
+ {
+ result = ae.e1;
+ return;
+ }
+ Expression e0 = null;
+ Expression ae1save = ae.e1;
+ ae.lengthVar = null;
+ Type t1b = ae.e1.type.toBasetype();
+ AggregateDeclaration ad = isAggregate(t1b);
+ if (!ad)
+ break;
+ if (search_function(ad, Id.opIndexOpAssign))
+ {
+ // Deal with $
+ result = resolveOpDollar(sc, ae, &e0);
+ if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j)
+ goto Lfallback;
+ if (result.op == TOK.error)
+ return;
+ result = e.e2.expressionSemantic(sc);
+ if (result.op == TOK.error)
+ return;
+ e.e2 = result;
+ /* Rewrite a[arguments] op= e2 as:
+ * a.opIndexOpAssign!(op)(e2, arguments)
+ */
+ Expressions* a = ae.arguments.copy();
+ a.insert(0, e.e2);
+ Objects* tiargs = opToArg(sc, e.op);
+ result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opIndexOpAssign, tiargs);
+ result = new CallExp(e.loc, result, a);
+ if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2)
+ result = result.trySemantic(sc);
+ else
+ result = result.expressionSemantic(sc);
+ if (result)
+ {
+ result = Expression.combine(e0, result);
+ return;
+ }
+ }
+ Lfallback:
+ if (maybeSlice && search_function(ad, Id.opSliceOpAssign))
+ {
+ // Deal with $
+ result = resolveOpDollar(sc, ae, ie, &e0);
+ if (result.op == TOK.error)
+ return;
+ result = e.e2.expressionSemantic(sc);
+ if (result.op == TOK.error)
+ return;
+ e.e2 = result;
+ /* Rewrite (a[i..j] op= e2) as:
+ * a.opSliceOpAssign!(op)(e2, i, j)
+ */
+ auto a = new Expressions();
+ a.push(e.e2);
+ if (ie)
+ {
+ a.push(ie.lwr);
+ a.push(ie.upr);
+ }
+ Objects* tiargs = opToArg(sc, e.op);
+ result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opSliceOpAssign, tiargs);
+ result = new CallExp(e.loc, result, a);
+ result = result.expressionSemantic(sc);
+ result = Expression.combine(e0, result);
+ return;
+ }
+ // Didn't find it. Forward to aliasthis
+ if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
+ {
+ /* Rewrite (a[arguments] op= e2) as:
+ * a.aliasthis[arguments] op= e2
+ */
+ ae.e1 = resolveAliasThis(sc, ae1save, true);
+ if (ae.e1)
+ continue;
+ }
+ break;
+ }
+ ae.e1 = ae1old; // recovery
+ ae.lengthVar = null;
+ }
+ result = e.binSemanticProp(sc);
+ if (result)
+ return;
+ // Don't attempt 'alias this' if an error occurred
+ if (e.e1.type.ty == Terror || e.e2.type.ty == Terror)
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ Identifier id = opId(e);
+ Expressions args2;
+ AggregateDeclaration ad1 = isAggregate(e.e1.type);
+ Dsymbol s = null;
+ Objects* tiargs = null;
+ /* Try opOpAssign
+ */
+ if (ad1)
+ {
+ s = search_function(ad1, Id.opOpAssign);
+ if (s && !s.isTemplateDeclaration())
+ {
+ e.error("`%s.opOpAssign` isn't a template", e.e1.toChars());
+ result = ErrorExp.get();
+ return;
+ }
+ }
+ // Set tiargs, the template argument list, which will be the operator string
+ if (s)
+ {
+ id = Id.opOpAssign;
+ tiargs = opToArg(sc, e.op);
+ }
+
+ // Try D1-style operator overload, deprecated
+ if (!s && ad1 && id)
+ {
+ s = search_function(ad1, id);
+ if (s)
+ {
+ // @@@DEPRECATED_2.098@@@.
+ // Deprecated in 2.088
+ // Make an error in 2.098
+ scope char[] op = Token.toString(e.op).dup;
+ op[$-1] = '\0'; // remove trailing `=`
+ e.deprecation("`%s` is deprecated. Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr);
+ }
+ }
+
+ if (s)
+ {
+ /* Try:
+ * a.opOpAssign(b)
+ */
+ args2.setDim(1);
+ args2[0] = e.e2;
+ expandTuples(&args2);
+ MatchAccumulator m;
+ if (s)
+ {
+ functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
+ if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ }
+ if (m.count > 1)
+ {
+ // Error, ambiguous
+ e.error("overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars());
+ }
+ else if (m.last == MATCH.nomatch)
+ {
+ if (tiargs)
+ goto L1;
+ m.lastf = null;
+ }
+ // Rewrite (e1 op e2) as e1.opOpAssign(e2)
+ result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
+ return;
+ }
+ L1:
+ result = checkAliasThisForLhs(ad1, sc, e);
+ if (result || !s) // no point in trying Rhs alias-this if there's no overload of any kind in lhs
+ return;
+
+ result = checkAliasThisForRhs(isAggregate(e.e2.type), sc, e);
+ }
+ }
+
+ if (pop)
+ *pop = e.op;
+ scope OpOverload v = new OpOverload(sc, pop);
+ e.accept(v);
+ return v.result;
+}
+
+/******************************************
+ * Common code for overloading of EqualExp and CmpExp
+ */
+private Expression compare_overload(BinExp e, Scope* sc, Identifier id, TOK* pop)
+{
+ //printf("BinExp::compare_overload(id = %s) %s\n", id.toChars(), e.toChars());
+ AggregateDeclaration ad1 = isAggregate(e.e1.type);
+ AggregateDeclaration ad2 = isAggregate(e.e2.type);
+ Dsymbol s = null;
+ Dsymbol s_r = null;
+ if (ad1)
+ {
+ s = search_function(ad1, id);
+ }
+ if (ad2)
+ {
+ s_r = search_function(ad2, id);
+ if (s == s_r)
+ s_r = null;
+ }
+ Objects* tiargs = null;
+ if (s || s_r)
+ {
+ /* Try:
+ * a.opEquals(b)
+ * b.opEquals(a)
+ * and see which is better.
+ */
+ Expressions args1 = Expressions(1);
+ args1[0] = e.e1;
+ expandTuples(&args1);
+ Expressions args2 = Expressions(1);
+ args2[0] = e.e2;
+ expandTuples(&args2);
+ MatchAccumulator m;
+ if (0 && s && s_r)
+ {
+ printf("s : %s\n", s.toPrettyChars());
+ printf("s_r: %s\n", s_r.toPrettyChars());
+ }
+ if (s)
+ {
+ functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
+ if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ return ErrorExp.get();
+ }
+ FuncDeclaration lastf = m.lastf;
+ int count = m.count;
+ if (s_r)
+ {
+ functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1);
+ if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ return ErrorExp.get();
+ }
+ if (m.count > 1)
+ {
+ /* The following if says "not ambiguous" if there's one match
+ * from s and one from s_r, in which case we pick s.
+ * This doesn't follow the spec, but is a workaround for the case
+ * where opEquals was generated from templates and we cannot figure
+ * out if both s and s_r came from the same declaration or not.
+ * The test case is:
+ * import std.typecons;
+ * void main() {
+ * assert(tuple("has a", 2u) == tuple("has a", 1));
+ * }
+ */
+ if (!(m.lastf == lastf && m.count == 2 && count == 1))
+ {
+ // Error, ambiguous
+ e.error("overloads `%s` and `%s` both match argument list for `%s`", m.lastf.type.toChars(), m.nextf.type.toChars(), m.lastf.toChars());
+ }
+ }
+ else if (m.last == MATCH.nomatch)
+ {
+ m.lastf = null;
+ }
+ Expression result;
+ if (lastf && m.lastf == lastf || !s_r && m.last == MATCH.nomatch)
+ {
+ // Rewrite (e1 op e2) as e1.opfunc(e2)
+ result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
+ }
+ else
+ {
+ // Rewrite (e1 op e2) as e2.opfunc_r(e1)
+ result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r);
+ // When reversing operands of comparison operators,
+ // need to reverse the sense of the op
+ if (pop)
+ *pop = reverseRelation(e.op);
+ }
+ return result;
+ }
+ /*
+ * https://issues.dlang.org/show_bug.cgi?id=16657
+ * at this point, no matching opEquals was found for structs,
+ * so we should not follow the alias this comparison code.
+ */
+ if ((e.op == TOK.equal || e.op == TOK.notEqual) && ad1 == ad2)
+ return null;
+ Expression result = checkAliasThisForLhs(ad1, sc, e);
+ return result ? result : checkAliasThisForRhs(isAggregate(e.e2.type), sc, e);
+}
+
+/***********************************
+ * Utility to build a function call out of this reference and argument.
+ */
+Expression build_overload(const ref Loc loc, Scope* sc, Expression ethis, Expression earg, Dsymbol d)
+{
+ assert(d);
+ Expression e;
+ Declaration decl = d.isDeclaration();
+ if (decl)
+ e = new DotVarExp(loc, ethis, decl, false);
+ else
+ e = new DotIdExp(loc, ethis, d.ident);
+ e = new CallExp(loc, e, earg);
+ e = e.expressionSemantic(sc);
+ return e;
+}
+
+/***************************************
+ * Search for function funcid in aggregate ad.
+ */
+Dsymbol search_function(ScopeDsymbol ad, Identifier funcid)
+{
+ Dsymbol s = ad.search(Loc.initial, funcid);
+ if (s)
+ {
+ //printf("search_function: s = '%s'\n", s.kind());
+ Dsymbol s2 = s.toAlias();
+ //printf("search_function: s2 = '%s'\n", s2.kind());
+ FuncDeclaration fd = s2.isFuncDeclaration();
+ if (fd && fd.type.ty == Tfunction)
+ return fd;
+ TemplateDeclaration td = s2.isTemplateDeclaration();
+ if (td)
+ return td;
+ }
+ return null;
+}
+
+/**************************************
+ * Figure out what is being foreach'd over by looking at the ForeachAggregate.
+ * Params:
+ * sc = context
+ * isForeach = true for foreach, false for foreach_reverse
+ * feaggr = ForeachAggregate
+ * sapply = set to function opApply/opApplyReverse, or delegate, or null.
+ * Overload resolution is not done.
+ * Returns:
+ * true if successfully figured it out; feaggr updated with semantic analysis.
+ * false for failed, which is an error.
+ */
+bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out Dsymbol sapply)
+{
+ //printf("inferForeachAggregate(%s)\n", feaggr.toChars());
+ bool sliced;
+ Type att = null;
+ auto aggr = feaggr;
+ while (1)
+ {
+ aggr = aggr.expressionSemantic(sc);
+ aggr = resolveProperties(sc, aggr);
+ aggr = aggr.optimize(WANTvalue);
+ if (!aggr.type || aggr.op == TOK.error)
+ return false;
+ Type tab = aggr.type.toBasetype();
+ switch (tab.ty)
+ {
+ case Tarray: // https://dlang.org/spec/statement.html#foreach_over_arrays
+ case Tsarray: // https://dlang.org/spec/statement.html#foreach_over_arrays
+ case Ttuple: // https://dlang.org/spec/statement.html#foreach_over_tuples
+ case Taarray: // https://dlang.org/spec/statement.html#foreach_over_associative_arrays
+ break;
+
+ case Tclass:
+ case Tstruct:
+ {
+ AggregateDeclaration ad = (tab.ty == Tclass) ? (cast(TypeClass)tab).sym
+ : (cast(TypeStruct)tab).sym;
+ if (!sliced)
+ {
+ sapply = search_function(ad, isForeach ? Id.apply : Id.applyReverse);
+ if (sapply)
+ {
+ // https://dlang.org/spec/statement.html#foreach_over_struct_and_classes
+ // opApply aggregate
+ break;
+ }
+ if (feaggr.op != TOK.type)
+ {
+ /* See if rewriting `aggr` to `aggr[]` will work
+ */
+ Expression rinit = new ArrayExp(aggr.loc, feaggr);
+ rinit = rinit.trySemantic(sc);
+ if (rinit) // if it worked
+ {
+ aggr = rinit;
+ sliced = true; // only try it once
+ continue;
+ }
+ }
+ }
+ if (ad.search(Loc.initial, isForeach ? Id.Ffront : Id.Fback))
+ {
+ // https://dlang.org/spec/statement.html#foreach-with-ranges
+ // range aggregate
+ break;
+ }
+ if (ad.aliasthis)
+ {
+ if (isRecursiveAliasThis(att, tab)) // error, circular alias this
+ return false;
+ aggr = resolveAliasThis(sc, aggr);
+ continue;
+ }
+ return false;
+ }
+
+ case Tdelegate: // https://dlang.org/spec/statement.html#foreach_over_delegates
+ if (aggr.op == TOK.delegate_)
+ {
+ sapply = (cast(DelegateExp)aggr).func;
+ }
+ break;
+
+ case Terror:
+ break;
+
+ default:
+ return false;
+ }
+ feaggr = aggr;
+ return true;
+ }
+ assert(0);
+}
+
+/*****************************************
+ * Given array of foreach parameters and an aggregate type,
+ * find best opApply overload,
+ * if any of the parameter types are missing, attempt to infer
+ * them from the aggregate type.
+ * Params:
+ * fes = the foreach statement
+ * sc = context
+ * sapply = null or opApply or delegate
+ * Returns:
+ * false for errors
+ */
+bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
+{
+ if (!fes.parameters || !fes.parameters.dim)
+ return false;
+ if (sapply) // prefer opApply
+ {
+ foreach (Parameter p; *fes.parameters)
+ {
+ if (p.type)
+ {
+ p.type = p.type.typeSemantic(fes.loc, sc);
+ p.type = p.type.addStorageClass(p.storageClass);
+ }
+ }
+
+ // Determine ethis for sapply
+ Expression ethis;
+ Type tab = fes.aggr.type.toBasetype();
+ if (tab.ty == Tclass || tab.ty == Tstruct)
+ ethis = fes.aggr;
+ else
+ {
+ assert(tab.ty == Tdelegate && fes.aggr.op == TOK.delegate_);
+ ethis = (cast(DelegateExp)fes.aggr).e1;
+ }
+
+ /* Look for like an
+ * int opApply(int delegate(ref Type [, ...]) dg);
+ * overload
+ */
+ if (FuncDeclaration fd = sapply.isFuncDeclaration())
+ {
+ auto fdapply = findBestOpApplyMatch(ethis, fd, fes.parameters);
+ if (fdapply)
+ {
+ // Fill in any missing types on foreach parameters[]
+ matchParamsToOpApply(cast(TypeFunction)fdapply.type, fes.parameters, true);
+ sapply = fdapply;
+ return true;
+ }
+ return false;
+ }
+ return sapply !is null;
+ }
+
+ Parameter p = (*fes.parameters)[0];
+ Type taggr = fes.aggr.type;
+ assert(taggr);
+ Type tab = taggr.toBasetype();
+ switch (tab.ty)
+ {
+ case Tarray:
+ case Tsarray:
+ case Ttuple:
+ if (fes.parameters.dim == 2)
+ {
+ if (!p.type)
+ {
+ p.type = Type.tsize_t; // key type
+ p.type = p.type.addStorageClass(p.storageClass);
+ }
+ p = (*fes.parameters)[1];
+ }
+ if (!p.type && tab.ty != Ttuple)
+ {
+ p.type = tab.nextOf(); // value type
+ p.type = p.type.addStorageClass(p.storageClass);
+ }
+ break;
+
+ case Taarray:
+ {
+ TypeAArray taa = cast(TypeAArray)tab;
+ if (fes.parameters.dim == 2)
+ {
+ if (!p.type)
+ {
+ p.type = taa.index; // key type
+ p.type = p.type.addStorageClass(p.storageClass);
+ if (p.storageClass & STC.ref_) // key must not be mutated via ref
+ p.type = p.type.addMod(MODFlags.const_);
+ }
+ p = (*fes.parameters)[1];
+ }
+ if (!p.type)
+ {
+ p.type = taa.next; // value type
+ p.type = p.type.addStorageClass(p.storageClass);
+ }
+ break;
+ }
+
+ case Tclass:
+ case Tstruct:
+ {
+ AggregateDeclaration ad = (tab.ty == Tclass) ? (cast(TypeClass)tab).sym
+ : (cast(TypeStruct)tab).sym;
+ if (fes.parameters.dim == 1)
+ {
+ if (!p.type)
+ {
+ /* Look for a front() or back() overload
+ */
+ Identifier id = (fes.op == TOK.foreach_) ? Id.Ffront : Id.Fback;
+ Dsymbol s = ad.search(Loc.initial, id);
+ FuncDeclaration fd = s ? s.isFuncDeclaration() : null;
+ if (fd)
+ {
+ // Resolve inout qualifier of front type
+ p.type = fd.type.nextOf();
+ if (p.type)
+ {
+ p.type = p.type.substWildTo(tab.mod);
+ p.type = p.type.addStorageClass(p.storageClass);
+ }
+ }
+ else if (s && s.isTemplateDeclaration())
+ {
+ }
+ else if (s && s.isDeclaration())
+ p.type = (cast(Declaration)s).type;
+ else
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ case Tdelegate:
+ if (!matchParamsToOpApply(cast(TypeFunction)tab.nextOf(), fes.parameters, true))
+ return false;
+ break;
+
+ default:
+ break; // ignore error, caught later
+ }
+ return true;
+}
+
+/*********************************************
+ * Find best overload match on fstart given ethis and parameters[].
+ * Params:
+ * ethis = expression to use for `this`
+ * fstart = opApply or foreach delegate
+ * parameters = ForeachTypeList (i.e. foreach parameters)
+ * Returns:
+ * best match if there is one, null if error
+ */
+private FuncDeclaration findBestOpApplyMatch(Expression ethis, FuncDeclaration fstart, Parameters* parameters)
+{
+ MOD mod = ethis.type.mod;
+ MATCH match = MATCH.nomatch;
+ FuncDeclaration fd_best;
+ FuncDeclaration fd_ambig;
+
+ overloadApply(fstart, (Dsymbol s)
+ {
+ auto f = s.isFuncDeclaration();
+ if (!f)
+ return 0; // continue
+ auto tf = cast(TypeFunction)f.type;
+ MATCH m = MATCH.exact;
+ if (f.isThis())
+ {
+ if (!MODimplicitConv(mod, tf.mod))
+ m = MATCH.nomatch;
+ else if (mod != tf.mod)
+ m = MATCH.constant;
+ }
+ if (!matchParamsToOpApply(tf, parameters, false))
+ m = MATCH.nomatch;
+ if (m > match)
+ {
+ fd_best = f;
+ fd_ambig = null;
+ match = m;
+ }
+ else if (m == match && m > MATCH.nomatch)
+ {
+ assert(fd_best);
+ /* Ignore covariant matches, as later on it can be redone
+ * after the opApply delegate has its attributes inferred.
+ */
+ if (tf.covariant(fd_best.type) != Covariant.yes &&
+ fd_best.type.covariant(tf) != Covariant.yes)
+ fd_ambig = f; // not covariant, so ambiguous
+ }
+ return 0; // continue
+ });
+
+ if (fd_ambig)
+ {
+ .error(ethis.loc, "`%s.%s` matches more than one declaration:\n`%s`: `%s`\nand:\n`%s`: `%s`",
+ ethis.toChars(), fstart.ident.toChars(),
+ fd_best.loc.toChars(), fd_best.type.toChars(),
+ fd_ambig.loc.toChars(), fd_ambig.type.toChars());
+ return null;
+ }
+
+ return fd_best;
+}
+
+/******************************
+ * Determine if foreach parameters match opApply parameters.
+ * Infer missing foreach parameter types from type of opApply delegate.
+ * Params:
+ * tf = type of opApply or delegate
+ * parameters = foreach parameters
+ * infer = infer missing parameter types
+ * Returns:
+ * true for match for this function
+ * false for no match for this function
+ */
+private bool matchParamsToOpApply(TypeFunction tf, Parameters* parameters, bool infer)
+{
+ enum nomatch = false;
+
+ /* opApply/delegate has exactly one parameter, and that parameter
+ * is a delegate that looks like:
+ * int opApply(int delegate(ref Type [, ...]) dg);
+ */
+ if (tf.parameterList.length != 1)
+ return nomatch;
+
+ /* Get the type of opApply's dg parameter
+ */
+ Parameter p0 = tf.parameterList[0];
+ if (p0.type.ty != Tdelegate)
+ return nomatch;
+ TypeFunction tdg = cast(TypeFunction)p0.type.nextOf();
+ assert(tdg.ty == Tfunction);
+
+ /* We now have tdg, the type of the delegate.
+ * tdg's parameters must match that of the foreach arglist (i.e. parameters).
+ * Fill in missing types in parameters.
+ */
+ const nparams = tdg.parameterList.length;
+ if (nparams == 0 || nparams != parameters.dim || tdg.parameterList.varargs != VarArg.none)
+ return nomatch; // parameter mismatch
+
+ foreach (u, p; *parameters)
+ {
+ Parameter param = tdg.parameterList[u];
+ if (p.type)
+ {
+ if (!p.type.equals(param.type))
+ return nomatch;
+ }
+ else if (infer)
+ {
+ p.type = param.type;
+ p.type = p.type.addStorageClass(p.storageClass);
+ }
+ }
+ return true;
+}
+
+/**
+ * Reverse relational operator, eg >= becomes <=
+ * Note this is not negation.
+ * Params:
+ * op = comparison operator to reverse
+ * Returns:
+ * reverse of op
+ */
+private TOK reverseRelation(TOK op) pure
+{
+ switch (op)
+ {
+ case TOK.greaterOrEqual: op = TOK.lessOrEqual; break;
+ case TOK.greaterThan: op = TOK.lessThan; break;
+ case TOK.lessOrEqual: op = TOK.greaterOrEqual; break;
+ case TOK.lessThan: op = TOK.greaterThan; break;
+ default: break;
+ }
+ return op;
+}
diff --git a/gcc/d/dmd/optimize.c b/gcc/d/dmd/optimize.c
deleted file mode 100644
index 44dedd8..0000000
--- a/gcc/d/dmd/optimize.c
+++ /dev/null
@@ -1,1230 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/optimize.c
- */
-
-#include "root/dsystem.h"
-
-#include "root/checkedint.h"
-#include "lexer.h"
-#include "mtype.h"
-#include "expression.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "init.h"
-#include "enum.h"
-#include "ctfe.h"
-#include "errors.h"
-
-/*************************************
- * If variable has a const initializer,
- * return that initializer.
- */
-
-Expression *expandVar(int result, VarDeclaration *v)
-{
- //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v->toChars() : "null");
-
- Expression *e = NULL;
- if (!v)
- return e;
- if (!v->originalType && v->semanticRun < PASSsemanticdone) // semantic() not yet run
- dsymbolSemantic(v, NULL);
-
- if (v->isConst() || v->isImmutable() || v->storage_class & STCmanifest)
- {
- if (!v->type)
- {
- return e;
- }
- Type *tb = v->type->toBasetype();
- if (v->storage_class & STCmanifest ||
- v->type->toBasetype()->isscalar() ||
- ((result & WANTexpand) && (tb->ty != Tsarray && tb->ty != Tstruct))
- )
- {
- if (v->_init)
- {
- if (v->inuse)
- {
- if (v->storage_class & STCmanifest)
- {
- v->error("recursive initialization of constant");
- goto Lerror;
- }
- goto L1;
- }
- Expression *ei = v->getConstInitializer();
- if (!ei)
- {
- if (v->storage_class & STCmanifest)
- {
- v->error("enum cannot be initialized with %s", v->_init->toChars());
- goto Lerror;
- }
- goto L1;
- }
- if (ei->op == TOKconstruct || ei->op == TOKblit)
- {
- AssignExp *ae = (AssignExp *)ei;
- ei = ae->e2;
- if (ei->isConst() == 1)
- {
- }
- else if (ei->op == TOKstring)
- {
- // Bugzilla 14459: We should not constfold the string literal
- // if it's typed as a C string, because the value expansion
- // will drop the pointer identity.
- if (!(result & WANTexpand) && ei->type->toBasetype()->ty == Tpointer)
- goto L1;
- }
- else
- goto L1;
-
- if (ei->type == v->type)
- {
- // const variable initialized with const expression
- }
- else if (ei->implicitConvTo(v->type) >= MATCHconst)
- {
- // const var initialized with non-const expression
- ei = ei->implicitCastTo(NULL, v->type);
- ei = expressionSemantic(ei, NULL);
- }
- else
- goto L1;
- }
- else if (!(v->storage_class & STCmanifest) &&
- ei->isConst() != 1 && ei->op != TOKstring &&
- ei->op != TOKaddress)
- {
- goto L1;
- }
- if (!ei->type)
- {
- goto L1;
- }
- else
- {
- // Should remove the copy() operation by
- // making all mods to expressions copy-on-write
- e = ei->copy();
- }
- }
- else
- {
- goto L1;
- }
- if (e->type != v->type)
- {
- e = e->castTo(NULL, v->type);
- }
- v->inuse++;
- e = e->optimize(result);
- v->inuse--;
- }
- }
-L1:
- //if (e) printf("\te = %p, %s, e->type = %d, %s\n", e, e->toChars(), e->type->ty, e->type->toChars());
- return e;
-
-Lerror:
- return new ErrorExp();
-}
-
-
-Expression *fromConstInitializer(int result, Expression *e1)
-{
- //printf("fromConstInitializer(result = %x, %s)\n", result, e1->toChars());
- //static int xx; if (xx++ == 10) assert(0);
- Expression *e = e1;
- if (e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e1;
- VarDeclaration *v = ve->var->isVarDeclaration();
- e = expandVar(result, v);
- if (e)
- {
- // If it is a comma expression involving a declaration, we mustn't
- // perform a copy -- we'd get two declarations of the same variable.
- // See bugzilla 4465.
- if (e->op == TOKcomma && ((CommaExp *)e)->e1->op == TOKdeclaration)
- e = e1;
- else
-
- if (e->type != e1->type && e1->type && e1->type->ty != Tident)
- {
- // Type 'paint' operation
- e = e->copy();
- e->type = e1->type;
- }
- e->loc = e1->loc;
- }
- else
- {
- e = e1;
- }
- }
- return e;
-}
-
-Expression *Expression_optimize(Expression *e, int result, bool keepLvalue)
-{
- class OptimizeVisitor : public Visitor
- {
- public:
- int result;
- bool keepLvalue;
- Expression *ret;
-
- OptimizeVisitor(int result, bool keepLvalue)
- : result(result), keepLvalue(keepLvalue)
- {
- }
-
- void error()
- {
- ret = new ErrorExp();
- }
-
- bool expOptimize(Expression *&e, int flags, bool keepLvalue = false)
- {
- if (!e)
- return false;
- Expression *ex = e->optimize(flags, keepLvalue);
- if (ex->op == TOKerror)
- {
- ret = ex; // store error result
- return true;
- }
- else
- {
- e = ex; // modify original
- return false;
- }
- }
-
- bool unaOptimize(UnaExp *e, int flags)
- {
- return expOptimize(e->e1, flags);
- }
-
- bool binOptimize(BinExp *e, int flags)
- {
- expOptimize(e->e1, flags);
- expOptimize(e->e2, flags);
- return ret->op == TOKerror;
- }
-
- void visit(Expression *)
- {
- //printf("Expression::optimize(result = x%x) %s\n", result, e->toChars());
- }
-
- void visit(VarExp *e)
- {
- if (keepLvalue)
- {
- VarDeclaration *v = e->var->isVarDeclaration();
- if (v && !(v->storage_class & STCmanifest))
- return;
- }
- ret = fromConstInitializer(result, e);
- }
-
- void visit(TupleExp *e)
- {
- expOptimize(e->e0, WANTvalue);
- for (size_t i = 0; i < e->exps->length; i++)
- {
- expOptimize((*e->exps)[i], WANTvalue);
- }
- }
-
- void visit(ArrayLiteralExp *e)
- {
- if (e->elements)
- {
- expOptimize(e->basis, result & WANTexpand);
- for (size_t i = 0; i < e->elements->length; i++)
- {
- expOptimize((*e->elements)[i], result & WANTexpand);
- }
- }
- }
-
- void visit(AssocArrayLiteralExp *e)
- {
- assert(e->keys->length == e->values->length);
- for (size_t i = 0; i < e->keys->length; i++)
- {
- expOptimize((*e->keys)[i], result & WANTexpand);
- expOptimize((*e->values)[i], result & WANTexpand);
- }
- }
-
- void visit(StructLiteralExp *e)
- {
- if (e->stageflags & stageOptimize) return;
- int old = e->stageflags;
- e->stageflags |= stageOptimize;
- if (e->elements)
- {
- for (size_t i = 0; i < e->elements->length; i++)
- {
- expOptimize((*e->elements)[i], result & WANTexpand);
- }
- }
- e->stageflags = old;
- }
-
- void visit(UnaExp *e)
- {
- //printf("UnaExp::optimize() %s\n", e->toChars());
- if (unaOptimize(e, result))
- return;
- }
-
- void visit(NegExp *e)
- {
- if (unaOptimize(e, result))
- return;
-
- if (e->e1->isConst() == 1)
- {
- ret = Neg(e->type, e->e1).copy();
- }
- }
-
- void visit(ComExp *e)
- {
- if (unaOptimize(e, result))
- return;
-
- if (e->e1->isConst() == 1)
- {
- ret = Com(e->type, e->e1).copy();
- }
- }
-
- void visit(NotExp *e)
- {
- if (unaOptimize(e, result))
- return;
-
- if (e->e1->isConst() == 1)
- {
- ret = Not(e->type, e->e1).copy();
- }
- }
-
- void visit(SymOffExp *e)
- {
- assert(e->var);
- }
-
- void visit(AddrExp *e)
- {
- //printf("AddrExp::optimize(result = %d) %s\n", result, e->toChars());
-
- /* Rewrite &(a,b) as (a,&b)
- */
- if (e->e1->op == TOKcomma)
- {
- CommaExp *ce = (CommaExp *)e->e1;
- AddrExp *ae = new AddrExp(e->loc, ce->e2, e->type);
- ret = new CommaExp(ce->loc, ce->e1, ae);
- ret->type = e->type;
- return;
- }
-
- // Keep lvalue-ness
- if (expOptimize(e->e1, result, true))
- return;
-
- // Convert &*ex to ex
- if (e->e1->op == TOKstar)
- {
- Expression *ex = ((PtrExp *)e->e1)->e1;
- if (e->type->equals(ex->type))
- ret = ex;
- else if (e->type->toBasetype()->equivalent(ex->type->toBasetype()))
- {
- ret = ex->copy();
- ret->type = e->type;
- }
- return;
- }
- if (e->e1->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e->e1;
- if (!ve->var->isOut() && !ve->var->isRef() &&
- !ve->var->isImportedSymbol())
- {
- ret = new SymOffExp(e->loc, ve->var, 0, ve->hasOverloads);
- ret->type = e->type;
- return;
- }
- }
- if (e->e1->op == TOKindex)
- {
- // Convert &array[n] to &array+n
- IndexExp *ae = (IndexExp *)e->e1;
-
- if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar)
- {
- sinteger_t index = ae->e2->toInteger();
- VarExp *ve = (VarExp *)ae->e1;
- if (ve->type->ty == Tsarray
- && !ve->var->isImportedSymbol())
- {
- TypeSArray *ts = (TypeSArray *)ve->type;
- sinteger_t dim = ts->dim->toInteger();
- if (index < 0 || index >= dim)
- {
- e->error("array index %lld is out of bounds [0..%lld]", index, dim);
- return error();
- }
-
- bool overflow = false;
- const d_uns64 offset = mulu(index, ts->nextOf()->size(e->loc), overflow);
- if (overflow)
- {
- e->error("array offset overflow");
- return error();
- }
-
- ret = new SymOffExp(e->loc, ve->var, offset);
- ret->type = e->type;
- return;
- }
- }
- }
- }
-
- void visit(PtrExp *e)
- {
- //printf("PtrExp::optimize(result = x%x) %s\n", result, e->toChars());
- if (expOptimize(e->e1, result))
- return;
- // Convert *&ex to ex
- // But only if there is no type punning involved
- if (e->e1->op == TOKaddress)
- {
- Expression *ex = ((AddrExp *)e->e1)->e1;
- if (e->type->equals(ex->type))
- ret = ex;
- else if (e->type->toBasetype()->equivalent(ex->type->toBasetype()))
- {
- ret = ex->copy();
- ret->type = e->type;
- }
- }
- if (keepLvalue)
- return;
-
- // Constant fold *(&structliteral + offset)
- if (e->e1->op == TOKadd)
- {
- Expression *ex = Ptr(e->type, e->e1).copy();
- if (!CTFEExp::isCantExp(ex))
- {
- ret = ex;
- return;
- }
- }
-
- if (e->e1->op == TOKsymoff)
- {
- SymOffExp *se = (SymOffExp *)e->e1;
- VarDeclaration *v = se->var->isVarDeclaration();
- Expression *ex = expandVar(result, v);
- if (ex && ex->op == TOKstructliteral)
- {
- StructLiteralExp *sle = (StructLiteralExp *)ex;
- ex = sle->getField(e->type, (unsigned)se->offset);
- if (ex && !CTFEExp::isCantExp(ex))
- {
- ret = ex;
- return;
- }
- }
- }
- }
-
- void visit(DotVarExp *e)
- {
- //printf("DotVarExp::optimize(result = x%x) %s\n", result, e->toChars());
- if (expOptimize(e->e1, result))
- return;
- if (keepLvalue)
- return;
-
- Expression *ex = e->e1;
-
- if (ex->op == TOKvar)
- {
- VarExp *ve = (VarExp *)ex;
- VarDeclaration *v = ve->var->isVarDeclaration();
- ex = expandVar(result, v);
- }
-
- if (ex && ex->op == TOKstructliteral)
- {
- StructLiteralExp *sle = (StructLiteralExp *)ex;
- VarDeclaration *vf = e->var->isVarDeclaration();
- if (vf && !vf->overlapped)
- {
- /* Bugzilla 13021: Prevent optimization if vf has overlapped fields.
- */
- ex = sle->getField(e->type, vf->offset);
- if (ex && !CTFEExp::isCantExp(ex))
- {
- ret = ex;
- return;
- }
- }
- }
- }
-
- void visit(NewExp *e)
- {
- expOptimize(e->thisexp, WANTvalue);
-
- // Optimize parameters
- if (e->newargs)
- {
- for (size_t i = 0; i < e->newargs->length; i++)
- {
- expOptimize((*e->newargs)[i], WANTvalue);
- }
- }
-
- if (e->arguments)
- {
- for (size_t i = 0; i < e->arguments->length; i++)
- {
- expOptimize((*e->arguments)[i], WANTvalue);
- }
- }
- }
-
- void visit(CallExp *e)
- {
- //printf("CallExp::optimize(result = %d) %s\n", result, e->toChars());
-
- // Optimize parameters with keeping lvalue-ness
- if (expOptimize(e->e1, result))
- return;
- if (e->arguments)
- {
- Type *t1 = e->e1->type->toBasetype();
- if (t1->ty == Tdelegate) t1 = t1->nextOf();
- assert(t1->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)t1;
- for (size_t i = 0; i < e->arguments->length; i++)
- {
- Parameter *p = tf->parameterList[i];
- bool keep = p && (p->storageClass & (STCref | STCout)) != 0;
- expOptimize((*e->arguments)[i], WANTvalue, keep);
- }
- }
- }
-
- void visit(CastExp *e)
- {
- //printf("CastExp::optimize(result = %d) %s\n", result, e->toChars());
- //printf("from %s to %s\n", e->type->toChars(), e->to->toChars());
- //printf("from %s\n", e->type->toChars());
- //printf("e1->type %s\n", e->e1->type->toChars());
- //printf("type = %p\n", e->type);
- assert(e->type);
- TOK op1 = e->e1->op;
-
- Expression *e1old = e->e1;
- if (expOptimize(e->e1, result))
- return;
- e->e1 = fromConstInitializer(result, e->e1);
-
- if (e->e1 == e1old &&
- e->e1->op == TOKarrayliteral &&
- e->type->toBasetype()->ty == Tpointer &&
- e->e1->type->toBasetype()->ty != Tsarray)
- {
- // Casting this will result in the same expression, and
- // infinite loop because of Expression::implicitCastTo()
- return; // no change
- }
-
- if ((e->e1->op == TOKstring || e->e1->op == TOKarrayliteral) &&
- (e->type->ty == Tpointer || e->type->ty == Tarray))
- {
- const d_uns64 esz = e->type->nextOf()->size(e->loc);
- const d_uns64 e1sz = e->e1->type->toBasetype()->nextOf()->size(e->e1->loc);
- if (esz == SIZE_INVALID || e1sz == SIZE_INVALID)
- return error();
-
- if (e1sz == esz)
- {
- // Bugzilla 12937: If target type is void array, trying to paint
- // e->e1 with that type will cause infinite recursive optimization.
- if (e->type->nextOf()->ty == Tvoid)
- return;
-
- ret = e->e1->castTo(NULL, e->type);
- //printf(" returning1 %s\n", ret->toChars());
- return;
- }
- }
-
- if (e->e1->op == TOKstructliteral &&
- e->e1->type->implicitConvTo(e->type) >= MATCHconst)
- {
- //printf(" returning2 %s\n", e->e1->toChars());
- L1: // Returning e1 with changing its type
- ret = (e1old == e->e1 ? e->e1->copy() : e->e1);
- ret->type = e->type;
- return;
- }
-
- /* The first test here is to prevent infinite loops
- */
- if (op1 != TOKarrayliteral && e->e1->op == TOKarrayliteral)
- {
- ret = e->e1->castTo(NULL, e->to);
- return;
- }
- if (e->e1->op == TOKnull &&
- (e->type->ty == Tpointer || e->type->ty == Tclass || e->type->ty == Tarray))
- {
- //printf(" returning3 %s\n", e->e1->toChars());
- goto L1;
- }
-
- if (e->type->ty == Tclass && e->e1->type->ty == Tclass)
- {
- // See if we can remove an unnecessary cast
- ClassDeclaration *cdfrom = e->e1->type->isClassHandle();
- ClassDeclaration *cdto = e->type->isClassHandle();
- if (cdto == ClassDeclaration::object && !cdfrom->isInterfaceDeclaration())
- goto L1; // can always convert a class to Object
- // Need to determine correct offset before optimizing away the cast.
- // https://issues.dlang.org/show_bug.cgi?id=16980
- cdfrom->size(e->loc);
- assert(cdfrom->sizeok == SIZEOKdone);
- assert(cdto->sizeok == SIZEOKdone || !cdto->isBaseOf(cdfrom, NULL));
- int offset;
- if (cdto->isBaseOf(cdfrom, &offset) && offset == 0)
- {
- //printf(" returning4 %s\n", e->e1->toChars());
- goto L1;
- }
- }
-
- // We can convert 'head const' to mutable
- if (e->to->mutableOf()->constOf()->equals(e->e1->type->mutableOf()->constOf()))
- {
- //printf(" returning5 %s\n", e->e1->toChars());
- goto L1;
- }
-
- if (e->e1->isConst())
- {
- if (e->e1->op == TOKsymoff)
- {
- if (e->type->toBasetype()->ty != Tsarray)
- {
- const d_uns64 esz = e->type->size(e->loc);
- const d_uns64 e1sz = e->e1->type->size(e->e1->loc);
- if (esz == SIZE_INVALID ||
- e1sz == SIZE_INVALID)
- return error();
-
- if (esz == e1sz)
- goto L1;
- }
- return;
- }
- if (e->to->toBasetype()->ty != Tvoid)
- {
- if (e->e1->type->equals(e->type) && e->type->equals(e->to))
- ret = e->e1;
- else
- ret = Cast(e->loc, e->type, e->to, e->e1).copy();
- }
- }
- //printf(" returning6 %s\n", ret->toChars());
- }
-
- void visit(BinExp *e)
- {
- //printf("BinExp::optimize(result = %d) %s\n", result, e->toChars());
- // don't replace const variable with its initializer in e1
- bool e2only = (e->op == TOKconstruct || e->op == TOKblit);
- if (e2only ? expOptimize(e->e2, result) : binOptimize(e, result))
- return;
-
- if (e->op == TOKshlass || e->op == TOKshrass || e->op == TOKushrass)
- {
- if (e->e2->isConst() == 1)
- {
- sinteger_t i2 = e->e2->toInteger();
- d_uns64 sz = e->e1->type->size(e->e1->loc);
- assert(sz != SIZE_INVALID);
- sz *= 8;
- if (i2 < 0 || (d_uns64)i2 >= sz)
- {
- e->error("shift assign by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1);
- return error();
- }
- }
- }
- }
-
- void visit(AddExp *e)
- {
- //printf("AddExp::optimize(%s)\n", e->toChars());
-
- if (binOptimize(e, result))
- return;
-
- if (e->e1->isConst() && e->e2->isConst())
- {
- if (e->e1->op == TOKsymoff && e->e2->op == TOKsymoff)
- return;
- ret = Add(e->loc, e->type, e->e1, e->e2).copy();
- }
- }
-
- void visit(MinExp *e)
- {
- if (binOptimize(e, result))
- return;
-
- if (e->e1->isConst() && e->e2->isConst())
- {
- if (e->e2->op == TOKsymoff)
- return;
- ret = Min(e->loc, e->type, e->e1, e->e2).copy();
- }
- }
-
- void visit(MulExp *e)
- {
- //printf("MulExp::optimize(result = %d) %s\n", result, e->toChars());
-
- if (binOptimize(e, result))
- return;
-
- if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
- {
- ret = Mul(e->loc, e->type, e->e1, e->e2).copy();
- }
- }
-
- void visit(DivExp *e)
- {
- //printf("DivExp::optimize(%s)\n", e->toChars());
-
- if (binOptimize(e, result))
- return;
-
- if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
- {
- ret = Div(e->loc, e->type, e->e1, e->e2).copy();
- }
- }
-
- void visit(ModExp *e)
- {
- if (binOptimize(e, result))
- return;
-
- if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
- {
- ret = Mod(e->loc, e->type, e->e1, e->e2).copy();
- }
- }
-
- void shift_optimize(BinExp *e, UnionExp (*shift)(Loc, Type *, Expression *, Expression *))
- {
- if (binOptimize(e, result))
- return;
-
- if (e->e2->isConst() == 1)
- {
- sinteger_t i2 = e->e2->toInteger();
- d_uns64 sz = e->e1->type->size();
- assert(sz != SIZE_INVALID);
- sz *= 8;
- if (i2 < 0 || (d_uns64)i2 >= sz)
- {
- e->error("shift by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1);
- return error();
- }
- if (e->e1->isConst() == 1)
- ret = (*shift)(e->loc, e->type, e->e1, e->e2).copy();
- }
- }
-
- void visit(ShlExp *e)
- {
- //printf("ShlExp::optimize(result = %d) %s\n", result, e->toChars());
- shift_optimize(e, &Shl);
- }
-
- void visit(ShrExp *e)
- {
- //printf("ShrExp::optimize(result = %d) %s\n", result, e->toChars());
- shift_optimize(e, &Shr);
- }
-
- void visit(UshrExp *e)
- {
- //printf("UshrExp::optimize(result = %d) %s\n", result, toChars());
- shift_optimize(e, &Ushr);
- }
-
- void visit(AndExp *e)
- {
- if (binOptimize(e, result))
- return;
-
- if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
- ret = And(e->loc, e->type, e->e1, e->e2).copy();
- }
-
- void visit(OrExp *e)
- {
- if (binOptimize(e, result))
- return;
-
- if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
- ret = Or(e->loc, e->type, e->e1, e->e2).copy();
- }
-
- void visit(XorExp *e)
- {
- if (binOptimize(e, result))
- return;
-
- if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
- ret = Xor(e->loc, e->type, e->e1, e->e2).copy();
- }
-
- void visit(PowExp *e)
- {
- if (binOptimize(e, result))
- return;
-
- // Replace 1 ^^ x or 1.0^^x by (x, 1)
- if ((e->e1->op == TOKint64 && e->e1->toInteger() == 1) ||
- (e->e1->op == TOKfloat64 && e->e1->toReal() == CTFloat::one))
- {
- ret = new CommaExp(e->loc, e->e2, e->e1);
- ret->type = e->type;
- return;
- }
-
- // Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral
- if (e->e2->type->isintegral() && e->e1->op == TOKint64 && (sinteger_t)e->e1->toInteger() == -1L)
- {
- ret = new AndExp(e->loc, e->e2, new IntegerExp(e->loc, 1, e->e2->type));
- ret->type = e->e2->type;
- ret = new CondExp(e->loc, ret, new IntegerExp(e->loc, -1L, e->type), new IntegerExp(e->loc, 1L, e->type));
- ret->type = e->type;
- return;
- }
-
- // Replace x ^^ 0 or x^^0.0 by (x, 1)
- if ((e->e2->op == TOKint64 && e->e2->toInteger() == 0) ||
- (e->e2->op == TOKfloat64 && e->e2->toReal() == CTFloat::zero))
- {
- if (e->e1->type->isintegral())
- ret = new IntegerExp(e->loc, 1, e->e1->type);
- else
- ret = new RealExp(e->loc, CTFloat::one, e->e1->type);
-
- ret = new CommaExp(e->loc, e->e1, ret);
- ret->type = e->type;
- return;
- }
-
- // Replace x ^^ 1 or x^^1.0 by (x)
- if ((e->e2->op == TOKint64 && e->e2->toInteger() == 1) ||
- (e->e2->op == TOKfloat64 && e->e2->toReal() == CTFloat::one))
- {
- ret = e->e1;
- return;
- }
-
- // Replace x ^^ -1.0 by (1.0 / x)
- if ((e->e2->op == TOKfloat64 && e->e2->toReal() == CTFloat::minusone))
- {
- ret = new DivExp(e->loc, new RealExp(e->loc, CTFloat::one, e->e2->type), e->e1);
- ret->type = e->type;
- return;
- }
-
- // All other negative integral powers are illegal
- if ((e->e1->type->isintegral()) && (e->e2->op == TOKint64) && (sinteger_t)e->e2->toInteger() < 0)
- {
- e->error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?",
- e->e1->type->toBasetype()->toChars(), e->e1->toChars(), e->e2->toChars());
- return error();
- }
-
- // If e2 *could* have been an integer, make it one.
- if (e->e2->op == TOKfloat64 && (e->e2->toReal() == ldouble((sinteger_t)e->e2->toReal())))
- e->e2 = new IntegerExp(e->loc, e->e2->toInteger(), Type::tint64);
-
- if (e->e1->isConst() == 1 && e->e2->isConst() == 1)
- {
- Expression *ex = Pow(e->loc, e->type, e->e1, e->e2).copy();
- if (!CTFEExp::isCantExp(ex))
- {
- ret = ex;
- return;
- }
- }
-
- // (2 ^^ n) ^^ p -> 1 << n * p
- if (e->e1->op == TOKint64 && e->e1->toInteger() > 0 &&
- !((e->e1->toInteger() - 1) & e->e1->toInteger()) &&
- e->e2->type->isintegral() && e->e2->type->isunsigned())
- {
- dinteger_t i = e->e1->toInteger();
- dinteger_t mul = 1;
- while ((i >>= 1) > 1)
- mul++;
- Expression *shift = new MulExp(e->loc, e->e2, new IntegerExp(e->loc, mul, e->e2->type));
- shift->type = e->e2->type;
- shift = shift->castTo(NULL, Type::tshiftcnt);
- ret = new ShlExp(e->loc, new IntegerExp(e->loc, 1, e->e1->type), shift);
- ret->type = e->type;
- return;
- }
- }
-
- void visit(CommaExp *e)
- {
- //printf("CommaExp::optimize(result = %d) %s\n", result, e->toChars());
- // Comma needs special treatment, because it may
- // contain compiler-generated declarations. We can interpret them, but
- // otherwise we must NOT attempt to constant-fold them.
- // In particular, if the comma returns a temporary variable, it needs
- // to be an lvalue (this is particularly important for struct constructors)
-
- expOptimize(e->e1, WANTvalue);
- expOptimize(e->e2, result, keepLvalue);
- if (ret->op == TOKerror)
- return;
-
- if (!e->e1 || e->e1->op == TOKint64 || e->e1->op == TOKfloat64 || !hasSideEffect(e->e1))
- {
- ret = e->e2;
- if (ret)
- ret->type = e->type;
- }
-
- //printf("-CommaExp::optimize(result = %d) %s\n", result, e->e->toChars());
- }
-
- void visit(ArrayLengthExp *e)
- {
- //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, e->toChars());
-
- if (unaOptimize(e, WANTexpand))
- return;
-
- // CTFE interpret static immutable arrays (to get better diagnostics)
- if (e->e1->op == TOKvar)
- {
- VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration();
- if (v && (v->storage_class & STCstatic) && (v->storage_class & STCimmutable) && v->_init)
- {
- if (Expression *ci = v->getConstInitializer())
- e->e1 = ci;
- }
- }
-
- if (e->e1->op == TOKstring || e->e1->op == TOKarrayliteral || e->e1->op == TOKassocarrayliteral ||
- e->e1->type->toBasetype()->ty == Tsarray)
- {
- ret = ArrayLength(e->type, e->e1).copy();
- }
- }
-
- void visit(EqualExp *e)
- {
- //printf("EqualExp::optimize(result = %x) %s\n", result, e->toChars());
- if (binOptimize(e, WANTvalue))
- return;
-
- Expression *e1 = fromConstInitializer(result, e->e1);
- Expression *e2 = fromConstInitializer(result, e->e2);
- if (e1->op == TOKerror)
- {
- ret = e1;
- return;
- }
- if (e2->op == TOKerror)
- {
- ret = e2;
- return;
- }
-
- ret = Equal(e->op, e->loc, e->type, e1, e2).copy();
- if (CTFEExp::isCantExp(ret))
- ret = e;
- }
-
- void visit(IdentityExp *e)
- {
- //printf("IdentityExp::optimize(result = %d) %s\n", result, e->toChars());
-
- if (binOptimize(e, WANTvalue))
- return;
-
- if ((e->e1->isConst() && e->e2->isConst()) ||
- (e->e1->op == TOKnull && e->e2->op == TOKnull)
- )
- {
- ret = Identity(e->op, e->loc, e->type, e->e1, e->e2).copy();
- if (CTFEExp::isCantExp(ret))
- ret = e;
- }
- }
-
- /* It is possible for constant folding to change an array expression of
- * unknown length, into one where the length is known.
- * If the expression 'arr' is a literal, set lengthVar to be its length.
- */
- static void setLengthVarIfKnown(VarDeclaration *lengthVar, Expression *arr)
- {
- if (!lengthVar)
- return;
- if (lengthVar->_init && !lengthVar->_init->isVoidInitializer())
- return; // we have previously calculated the length
- size_t len;
- if (arr->op == TOKstring)
- len = ((StringExp *)arr)->len;
- else if (arr->op == TOKarrayliteral)
- len = ((ArrayLiteralExp *)arr)->elements->length;
- else
- {
- Type *t = arr->type->toBasetype();
- if (t->ty == Tsarray)
- len = (size_t)((TypeSArray *)t)->dim->toInteger();
- else
- return; // we don't know the length yet
- }
-
- Expression *dollar = new IntegerExp(Loc(), len, Type::tsize_t);
- lengthVar->_init = new ExpInitializer(Loc(), dollar);
- lengthVar->storage_class |= STCstatic | STCconst;
- }
-
- void visit(IndexExp *e)
- {
- //printf("IndexExp::optimize(result = %d) %s\n", result, e->toChars());
- if (expOptimize(e->e1, result & WANTexpand))
- return;
-
- Expression *ex = fromConstInitializer(result, e->e1);
-
- // We might know $ now
- setLengthVarIfKnown(e->lengthVar, ex);
-
- if (expOptimize(e->e2, WANTvalue))
- return;
- if (keepLvalue)
- return;
- ret = Index(e->type, ex, e->e2).copy();
- if (CTFEExp::isCantExp(ret))
- ret = e;
- }
-
- void visit(SliceExp *e)
- {
- //printf("SliceExp::optimize(result = %d) %s\n", result, e->toChars());
- if (expOptimize(e->e1, result & WANTexpand))
- return;
- if (!e->lwr)
- {
- if (e->e1->op == TOKstring)
- {
- // Convert slice of string literal into dynamic array
- Type *t = e->e1->type->toBasetype();
- if (Type *tn = t->nextOf())
- ret = e->e1->castTo(NULL, tn->arrayOf());
- }
- }
- else
- {
- e->e1 = fromConstInitializer(result, e->e1);
- // We might know $ now
- setLengthVarIfKnown(e->lengthVar, e->e1);
- expOptimize(e->lwr, WANTvalue);
- expOptimize(e->upr, WANTvalue);
- if (ret->op == TOKerror)
- return;
- ret = Slice(e->type, e->e1, e->lwr, e->upr).copy();
- if (CTFEExp::isCantExp(ret))
- ret = e;
- }
-
- // Bugzilla 14649: We need to leave the slice form so it might be
- // a part of array operation.
- // Assume that the backend codegen will handle the form `e[]`
- // as an equal to `e` itself.
- if (ret->op == TOKstring)
- {
- e->e1 = ret;
- e->lwr = NULL;
- e->upr = NULL;
- ret = e;
- }
- //printf("-SliceExp::optimize() %s\n", ret->toChars());
- }
-
- void visit(LogicalExp *e)
- {
- //printf("LogicalExp::optimize(%d) %s\n", result, e->toChars());
- if (expOptimize(e->e1, WANTvalue))
- return;
- const bool oror = e->op == TOKoror;
- if (e->e1->isBool(oror))
- {
- // Replace with (e1, oror)
- ret = new IntegerExp(e->loc, oror, Type::tbool);
- ret = Expression::combine(e->e1, ret);
- if (e->type->toBasetype()->ty == Tvoid)
- {
- ret = new CastExp(e->loc, ret, Type::tvoid);
- ret->type = e->type;
- }
- ret = ret->optimize(result);
- return;
- }
-
- if (expOptimize(e->e2, WANTvalue))
- return;
-
- if (e->e1->isConst())
- {
- if (e->e2->isConst())
- {
- bool n1 = e->e1->isBool(true);
- bool n2 = e->e2->isBool(true);
- ret = new IntegerExp(e->loc, oror ? (n1 || n2) : (n1 && n2), e->type);
- }
- else if (e->e1->isBool(!oror))
- {
- if (e->type->toBasetype()->ty == Tvoid)
- ret = e->e2;
- else
- {
- ret = new CastExp(e->loc, e->e2, e->type);
- ret->type = e->type;
- }
- }
- }
- }
-
- void visit(CmpExp *e)
- {
- //printf("CmpExp::optimize() %s\n", e->toChars());
- if (binOptimize(e, WANTvalue))
- return;
-
- Expression *e1 = fromConstInitializer(result, e->e1);
- Expression *e2 = fromConstInitializer(result, e->e2);
-
- ret = Cmp(e->op, e->loc, e->type, e1, e2).copy();
- if (CTFEExp::isCantExp(ret))
- ret = e;
- }
-
- void visit(CatExp *e)
- {
- //printf("CatExp::optimize(%d) %s\n", result, e->toChars());
-
- if (binOptimize(e, result))
- return;
-
- if (e->e1->op == TOKcat)
- {
- // Bugzilla 12798: optimize ((expr ~ str1) ~ str2)
- CatExp *ce1 = (CatExp *)e->e1;
- CatExp cex(e->loc, ce1->e2, e->e2);
- cex.type = e->type;
- Expression *ex = cex.optimize(result);
- if (ex != &cex)
- {
- e->e1 = ce1->e1;
- e->e2 = ex;
- }
- }
-
- // optimize "str"[] -> "str"
- if (e->e1->op == TOKslice)
- {
- SliceExp *se1 = (SliceExp *)e->e1;
- if (se1->e1->op == TOKstring && !se1->lwr)
- e->e1 = se1->e1;
- }
- if (e->e2->op == TOKslice)
- {
- SliceExp *se2 = (SliceExp *)e->e2;
- if (se2->e1->op == TOKstring && !se2->lwr)
- e->e2 = se2->e1;
- }
-
- ret = Cat(e->type, e->e1, e->e2).copy();
- if (CTFEExp::isCantExp(ret))
- ret = e;
- }
-
- void visit(CondExp *e)
- {
- if (expOptimize(e->econd, WANTvalue))
- return;
- if (e->econd->isBool(true))
- ret = e->e1->optimize(result, keepLvalue);
- else if (e->econd->isBool(false))
- ret = e->e2->optimize(result, keepLvalue);
- else
- {
- expOptimize(e->e1, result, keepLvalue);
- expOptimize(e->e2, result, keepLvalue);
- }
- }
- };
-
- OptimizeVisitor v(result, keepLvalue);
- Expression *ex = NULL;
- v.ret = e;
-
- // Optimize the expression until it can no longer be simplified.
- size_t b = 0;
- while (1)
- {
- if (b++ == global.recursionLimit)
- {
- e->error("infinite loop while optimizing expression");
- fatal();
- }
- ex = v.ret;
- ex->accept(&v);
- if (ex == v.ret)
- break;
- }
- return ex;
-}
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
new file mode 100644
index 0000000..3ae3061
--- /dev/null
+++ b/gcc/d/dmd/optimize.d
@@ -0,0 +1,1186 @@
+/**
+ * Perform constant folding.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/optimize.d, _optimize.d)
+ * Documentation: https://dlang.org/phobos/dmd_optimize.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/optimize.d
+ */
+
+module dmd.optimize;
+
+import core.stdc.stdio;
+
+import dmd.astenums;
+import dmd.constfold;
+import dmd.ctfeexpr;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.globals;
+import dmd.init;
+import dmd.mtype;
+import dmd.root.ctfloat;
+import dmd.sideeffect;
+import dmd.tokens;
+import dmd.visitor;
+
+/*************************************
+ * If variable has a const initializer,
+ * return that initializer.
+ * Returns:
+ * initializer if there is one,
+ * null if not,
+ * ErrorExp if error
+ */
+Expression expandVar(int result, VarDeclaration v)
+{
+ //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v.toChars() : "null");
+
+ /********
+ * Params:
+ * e = initializer expression
+ */
+ Expression initializerReturn(Expression e)
+ {
+ if (e.type != v.type)
+ {
+ e = e.castTo(null, v.type);
+ }
+ v.inuse++;
+ e = e.optimize(result);
+ v.inuse--;
+ //if (e) printf("\te = %p, %s, e.type = %d, %s\n", e, e.toChars(), e.type.ty, e.type.toChars());
+ return e;
+ }
+
+ static Expression nullReturn()
+ {
+ return null;
+ }
+
+ static Expression errorReturn()
+ {
+ return ErrorExp.get();
+ }
+
+ if (!v)
+ return nullReturn();
+ if (!v.originalType && v.semanticRun < PASS.semanticdone) // semantic() not yet run
+ v.dsymbolSemantic(null);
+ if (v.type &&
+ (v.isConst() || v.isImmutable() || v.storage_class & STC.manifest))
+ {
+ Type tb = v.type.toBasetype();
+ if (v.storage_class & STC.manifest ||
+ tb.isscalar() ||
+ ((result & WANTexpand) && (tb.ty != Tsarray && tb.ty != Tstruct)))
+ {
+ if (v._init)
+ {
+ if (v.inuse)
+ {
+ if (v.storage_class & STC.manifest)
+ {
+ v.error("recursive initialization of constant");
+ return errorReturn();
+ }
+ return nullReturn();
+ }
+ Expression ei = v.getConstInitializer();
+ if (!ei)
+ {
+ if (v.storage_class & STC.manifest)
+ {
+ v.error("enum cannot be initialized with `%s`", v._init.toChars());
+ return errorReturn();
+ }
+ return nullReturn();
+ }
+ if (ei.op == TOK.construct || ei.op == TOK.blit)
+ {
+ AssignExp ae = cast(AssignExp)ei;
+ ei = ae.e2;
+ if (ei.isConst() == 1)
+ {
+ }
+ else if (ei.op == TOK.string_)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=14459
+ // Do not constfold the string literal
+ // if it's typed as a C string, because the value expansion
+ // will drop the pointer identity.
+ if (!(result & WANTexpand) && ei.type.toBasetype().ty == Tpointer)
+ return nullReturn();
+ }
+ else
+ return nullReturn();
+ if (ei.type == v.type)
+ {
+ // const variable initialized with const expression
+ }
+ else if (ei.implicitConvTo(v.type) >= MATCH.constant)
+ {
+ // const var initialized with non-const expression
+ ei = ei.implicitCastTo(null, v.type);
+ ei = ei.expressionSemantic(null);
+ }
+ else
+ return nullReturn();
+ }
+ else if (!(v.storage_class & STC.manifest) &&
+ ei.isConst() != 1 &&
+ ei.op != TOK.string_ &&
+ ei.op != TOK.address)
+ {
+ return nullReturn();
+ }
+
+ if (!ei.type)
+ {
+ return nullReturn();
+ }
+ else
+ {
+ // Should remove the copy() operation by
+ // making all mods to expressions copy-on-write
+ return initializerReturn(ei.copy());
+ }
+ }
+ else
+ {
+ // v does not have an initializer
+ version (all)
+ {
+ return nullReturn();
+ }
+ else
+ {
+ // BUG: what if const is initialized in constructor?
+ auto e = v.type.defaultInit();
+ e.loc = e1.loc;
+ return initializerReturn(e);
+ }
+ }
+ assert(0);
+ }
+ }
+ return nullReturn();
+}
+
+private Expression fromConstInitializer(int result, Expression e1)
+{
+ //printf("fromConstInitializer(result = %x, %s)\n", result, e1.toChars());
+ //static int xx; if (xx++ == 10) assert(0);
+ Expression e = e1;
+ if (e1.op == TOK.variable)
+ {
+ VarExp ve = cast(VarExp)e1;
+ VarDeclaration v = ve.var.isVarDeclaration();
+ e = expandVar(result, v);
+ if (e)
+ {
+ // If it is a comma expression involving a declaration, we mustn't
+ // perform a copy -- we'd get two declarations of the same variable.
+ // See bugzilla 4465.
+ if (e.op == TOK.comma && (cast(CommaExp)e).e1.op == TOK.declaration)
+ e = e1;
+ else if (e.type != e1.type && e1.type && e1.type.ty != Tident)
+ {
+ // Type 'paint' operation
+ e = e.copy();
+ e.type = e1.type;
+ }
+ e.loc = e1.loc;
+ }
+ else
+ {
+ e = e1;
+ }
+ }
+ return e;
+}
+
+/* It is possible for constant folding to change an array expression of
+ * unknown length, into one where the length is known.
+ * If the expression 'arr' is a literal, set lengthVar to be its length.
+ */
+package void setLengthVarIfKnown(VarDeclaration lengthVar, Expression arr)
+{
+ if (!lengthVar)
+ return;
+ if (lengthVar._init && !lengthVar._init.isVoidInitializer())
+ return; // we have previously calculated the length
+ size_t len;
+ if (arr.op == TOK.string_)
+ len = (cast(StringExp)arr).len;
+ else if (arr.op == TOK.arrayLiteral)
+ len = (cast(ArrayLiteralExp)arr).elements.dim;
+ else
+ {
+ Type t = arr.type.toBasetype();
+ if (t.ty == Tsarray)
+ len = cast(size_t)(cast(TypeSArray)t).dim.toInteger();
+ else
+ return; // we don't know the length yet
+ }
+ Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t);
+ lengthVar._init = new ExpInitializer(Loc.initial, dollar);
+ lengthVar.storage_class |= STC.static_ | STC.const_;
+}
+
+/* Same as above, but determines the length from 'type'. */
+package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type)
+{
+ if (!lengthVar)
+ return;
+ if (lengthVar._init && !lengthVar._init.isVoidInitializer())
+ return; // we have previously calculated the length
+ size_t len;
+ Type t = type.toBasetype();
+ if (t.ty == Tsarray)
+ len = cast(size_t)(cast(TypeSArray)t).dim.toInteger();
+ else
+ return; // we don't know the length yet
+ Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t);
+ lengthVar._init = new ExpInitializer(Loc.initial, dollar);
+ lengthVar.storage_class |= STC.static_ | STC.const_;
+}
+
+/*********************************
+ * Constant fold an Expression.
+ * Params:
+ * e = expression to const fold; this may get modified in-place
+ * result = WANTvalue, WANTexpand, or both
+ * keepLvalue = `e` is an lvalue, and keep it as an lvalue since it is
+ * an argument to a `ref` or `out` parameter, or the operand of `&` operator
+ * Returns:
+ * Constant folded version of `e`
+ */
+Expression Expression_optimize(Expression e, int result, bool keepLvalue)
+{
+ extern (C++) final class OptimizeVisitor : Visitor
+ {
+ alias visit = Visitor.visit;
+
+ Expression ret;
+ private const int result;
+ private const bool keepLvalue;
+
+ extern (D) this(Expression e, int result, bool keepLvalue)
+ {
+ this.ret = e; // default result is original expression
+ this.result = result;
+ this.keepLvalue = keepLvalue;
+ }
+
+ void error()
+ {
+ ret = ErrorExp.get();
+ }
+
+ bool expOptimize(ref Expression e, int flags, bool keepLvalue = false)
+ {
+ if (!e)
+ return false;
+ Expression ex = Expression_optimize(e, flags, keepLvalue);
+ if (ex.op == TOK.error)
+ {
+ ret = ex; // store error result
+ return true;
+ }
+ else
+ {
+ e = ex; // modify original
+ return false;
+ }
+ }
+
+ bool unaOptimize(UnaExp e, int flags)
+ {
+ return expOptimize(e.e1, flags);
+ }
+
+ bool binOptimize(BinExp e, int flags, bool keepLhsLvalue = false)
+ {
+ expOptimize(e.e1, flags, keepLhsLvalue);
+ expOptimize(e.e2, flags);
+ return ret.op == TOK.error;
+ }
+
+ override void visit(Expression e)
+ {
+ //printf("Expression::optimize(result = x%x) %s\n", result, e.toChars());
+ }
+
+ override void visit(VarExp e)
+ {
+ VarDeclaration v = e.var.isVarDeclaration();
+
+ if (!(keepLvalue && v && !(v.storage_class & STC.manifest)))
+ ret = fromConstInitializer(result, e);
+
+ // if unoptimized, try to optimize the dtor expression
+ // (e.g., might be a LogicalExp with constant lhs)
+ if (ret == e && v && v.edtor)
+ {
+ // prevent infinite recursion (`<var>.~this()`)
+ if (!v.inuse)
+ {
+ v.inuse++;
+ expOptimize(v.edtor, WANTvalue);
+ v.inuse--;
+ }
+ }
+ }
+
+ override void visit(TupleExp e)
+ {
+ expOptimize(e.e0, WANTvalue);
+ for (size_t i = 0; i < e.exps.dim; i++)
+ {
+ expOptimize((*e.exps)[i], WANTvalue);
+ }
+ }
+
+ override void visit(ArrayLiteralExp e)
+ {
+ if (e.elements)
+ {
+ expOptimize(e.basis, result & WANTexpand);
+ for (size_t i = 0; i < e.elements.dim; i++)
+ {
+ expOptimize((*e.elements)[i], result & WANTexpand);
+ }
+ }
+ }
+
+ override void visit(AssocArrayLiteralExp e)
+ {
+ assert(e.keys.dim == e.values.dim);
+ for (size_t i = 0; i < e.keys.dim; i++)
+ {
+ expOptimize((*e.keys)[i], result & WANTexpand);
+ expOptimize((*e.values)[i], result & WANTexpand);
+ }
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ if (e.stageflags & stageOptimize)
+ return;
+ int old = e.stageflags;
+ e.stageflags |= stageOptimize;
+ if (e.elements)
+ {
+ for (size_t i = 0; i < e.elements.dim; i++)
+ {
+ expOptimize((*e.elements)[i], result & WANTexpand);
+ }
+ }
+ e.stageflags = old;
+ }
+
+ override void visit(UnaExp e)
+ {
+ //printf("UnaExp::optimize() %s\n", e.toChars());
+ if (unaOptimize(e, result))
+ return;
+ }
+
+ override void visit(NegExp e)
+ {
+ if (unaOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1)
+ {
+ ret = Neg(e.type, e.e1).copy();
+ }
+ }
+
+ override void visit(ComExp e)
+ {
+ if (unaOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1)
+ {
+ ret = Com(e.type, e.e1).copy();
+ }
+ }
+
+ override void visit(NotExp e)
+ {
+ if (unaOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1)
+ {
+ ret = Not(e.type, e.e1).copy();
+ }
+ }
+
+ override void visit(SymOffExp e)
+ {
+ assert(e.var);
+ }
+
+ override void visit(AddrExp e)
+ {
+ //printf("AddrExp::optimize(result = %d) %s\n", result, e.toChars());
+ /* Rewrite &(a,b) as (a,&b)
+ */
+ if (e.e1.op == TOK.comma)
+ {
+ CommaExp ce = cast(CommaExp)e.e1;
+ auto ae = new AddrExp(e.loc, ce.e2, e.type);
+ ret = new CommaExp(ce.loc, ce.e1, ae);
+ ret.type = e.type;
+ return;
+ }
+ // Keep lvalue-ness
+ if (expOptimize(e.e1, result, true))
+ return;
+ // Convert &*ex to ex
+ if (e.e1.op == TOK.star)
+ {
+ Expression ex = (cast(PtrExp)e.e1).e1;
+ if (e.type.equals(ex.type))
+ ret = ex;
+ else if (e.type.toBasetype().equivalent(ex.type.toBasetype()))
+ {
+ ret = ex.copy();
+ ret.type = e.type;
+ }
+ return;
+ }
+ if (e.e1.op == TOK.variable)
+ {
+ VarExp ve = cast(VarExp)e.e1;
+ if (!ve.var.isReference() && !ve.var.isImportedSymbol())
+ {
+ ret = new SymOffExp(e.loc, ve.var, 0, ve.hasOverloads);
+ ret.type = e.type;
+ return;
+ }
+ }
+ if (e.e1.op == TOK.index)
+ {
+ // Convert &array[n] to &array+n
+ IndexExp ae = cast(IndexExp)e.e1;
+ if (ae.e2.op == TOK.int64 && ae.e1.op == TOK.variable)
+ {
+ sinteger_t index = ae.e2.toInteger();
+ VarExp ve = cast(VarExp)ae.e1;
+ if (ve.type.ty == Tsarray && !ve.var.isImportedSymbol())
+ {
+ TypeSArray ts = cast(TypeSArray)ve.type;
+ sinteger_t dim = ts.dim.toInteger();
+ if (index < 0 || index >= dim)
+ {
+ e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
+ return error();
+ }
+
+ import core.checkedint : mulu;
+ bool overflow;
+ const offset = mulu(index, ts.nextOf().size(e.loc), overflow);
+ if (overflow)
+ {
+ e.error("array offset overflow");
+ return error();
+ }
+
+ ret = new SymOffExp(e.loc, ve.var, offset);
+ ret.type = e.type;
+ return;
+ }
+ }
+ }
+ }
+
+ override void visit(PtrExp e)
+ {
+ //printf("PtrExp::optimize(result = x%x) %s\n", result, e.toChars());
+ if (expOptimize(e.e1, result))
+ return;
+ // Convert *&ex to ex
+ // But only if there is no type punning involved
+ if (e.e1.op == TOK.address)
+ {
+ Expression ex = (cast(AddrExp)e.e1).e1;
+ if (e.type.equals(ex.type))
+ ret = ex;
+ else if (e.type.toBasetype().equivalent(ex.type.toBasetype()))
+ {
+ ret = ex.copy();
+ ret.type = e.type;
+ }
+ }
+ if (keepLvalue)
+ return;
+ // Constant fold *(&structliteral + offset)
+ if (e.e1.op == TOK.add)
+ {
+ Expression ex = Ptr(e.type, e.e1).copy();
+ if (!CTFEExp.isCantExp(ex))
+ {
+ ret = ex;
+ return;
+ }
+ }
+ if (e.e1.op == TOK.symbolOffset)
+ {
+ SymOffExp se = cast(SymOffExp)e.e1;
+ VarDeclaration v = se.var.isVarDeclaration();
+ Expression ex = expandVar(result, v);
+ if (ex && ex.op == TOK.structLiteral)
+ {
+ StructLiteralExp sle = cast(StructLiteralExp)ex;
+ ex = sle.getField(e.type, cast(uint)se.offset);
+ if (ex && !CTFEExp.isCantExp(ex))
+ {
+ ret = ex;
+ return;
+ }
+ }
+ }
+ }
+
+ override void visit(DotVarExp e)
+ {
+ //printf("DotVarExp::optimize(result = x%x) %s\n", result, e.toChars());
+ if (expOptimize(e.e1, result))
+ return;
+ if (keepLvalue)
+ return;
+ Expression ex = e.e1;
+ if (ex.op == TOK.variable)
+ {
+ VarExp ve = cast(VarExp)ex;
+ VarDeclaration v = ve.var.isVarDeclaration();
+ ex = expandVar(result, v);
+ }
+ if (ex && ex.op == TOK.structLiteral)
+ {
+ StructLiteralExp sle = cast(StructLiteralExp)ex;
+ VarDeclaration vf = e.var.isVarDeclaration();
+ if (vf && !vf.overlapped)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=13021
+ * Prevent optimization if vf has overlapped fields.
+ */
+ ex = sle.getField(e.type, vf.offset);
+ if (ex && !CTFEExp.isCantExp(ex))
+ {
+ ret = ex;
+ return;
+ }
+ }
+ }
+ }
+
+ override void visit(NewExp e)
+ {
+ expOptimize(e.thisexp, WANTvalue);
+ // Optimize parameters
+ if (e.newargs)
+ {
+ for (size_t i = 0; i < e.newargs.dim; i++)
+ {
+ expOptimize((*e.newargs)[i], WANTvalue);
+ }
+ }
+ if (e.arguments)
+ {
+ for (size_t i = 0; i < e.arguments.dim; i++)
+ {
+ expOptimize((*e.arguments)[i], WANTvalue);
+ }
+ }
+ }
+
+ override void visit(CallExp e)
+ {
+ //printf("CallExp::optimize(result = %d) %s\n", result, e.toChars());
+ // Optimize parameters with keeping lvalue-ness
+ if (expOptimize(e.e1, result))
+ return;
+ if (e.arguments)
+ {
+ Type t1 = e.e1.type.toBasetype();
+ if (t1.ty == Tdelegate)
+ t1 = t1.nextOf();
+ // t1 can apparently be void for __ArrayDtor(T) calls
+ if (auto tf = t1.isTypeFunction())
+ {
+ for (size_t i = 0; i < e.arguments.dim; i++)
+ {
+ Parameter p = tf.parameterList[i];
+ bool keep = p && p.isReference();
+ expOptimize((*e.arguments)[i], WANTvalue, keep);
+ }
+ }
+ }
+ }
+
+ override void visit(CastExp e)
+ {
+ //printf("CastExp::optimize(result = %d) %s\n", result, e.toChars());
+ //printf("from %s to %s\n", e.type.toChars(), e.to.toChars());
+ //printf("from %s\n", e.type.toChars());
+ //printf("e1.type %s\n", e.e1.type.toChars());
+ //printf("type = %p\n", e.type);
+ assert(e.type);
+ TOK op1 = e.e1.op;
+ Expression e1old = e.e1;
+ if (expOptimize(e.e1, result, keepLvalue))
+ return;
+ if (!keepLvalue)
+ e.e1 = fromConstInitializer(result, e.e1);
+ if (e.e1 == e1old && e.e1.op == TOK.arrayLiteral && e.type.toBasetype().ty == Tpointer && e.e1.type.toBasetype().ty != Tsarray)
+ {
+ // Casting this will result in the same expression, and
+ // infinite loop because of Expression::implicitCastTo()
+ return; // no change
+ }
+ if ((e.e1.op == TOK.string_ || e.e1.op == TOK.arrayLiteral) &&
+ (e.type.ty == Tpointer || e.type.ty == Tarray))
+ {
+ const esz = e.type.nextOf().size(e.loc);
+ const e1sz = e.e1.type.toBasetype().nextOf().size(e.e1.loc);
+ if (esz == SIZE_INVALID || e1sz == SIZE_INVALID)
+ return error();
+
+ if (e1sz == esz)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=12937
+ // If target type is void array, trying to paint
+ // e.e1 with that type will cause infinite recursive optimization.
+ if (e.type.nextOf().ty == Tvoid)
+ return;
+ ret = e.e1.castTo(null, e.type);
+ //printf(" returning1 %s\n", ret.toChars());
+ return;
+ }
+ }
+
+ if (e.e1.op == TOK.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant)
+ {
+ //printf(" returning2 %s\n", e.e1.toChars());
+ L1:
+ // Returning e1 with changing its type
+ ret = (e1old == e.e1 ? e.e1.copy() : e.e1);
+ ret.type = e.type;
+ return;
+ }
+ /* The first test here is to prevent infinite loops
+ */
+ if (op1 != TOK.arrayLiteral && e.e1.op == TOK.arrayLiteral)
+ {
+ ret = e.e1.castTo(null, e.to);
+ return;
+ }
+ if (e.e1.op == TOK.null_ && (e.type.ty == Tpointer || e.type.ty == Tclass || e.type.ty == Tarray))
+ {
+ //printf(" returning3 %s\n", e.e1.toChars());
+ goto L1;
+ }
+ if (e.type.ty == Tclass && e.e1.type.ty == Tclass)
+ {
+ import dmd.astenums : Sizeok;
+
+ // See if we can remove an unnecessary cast
+ ClassDeclaration cdfrom = e.e1.type.isClassHandle();
+ ClassDeclaration cdto = e.type.isClassHandle();
+ if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration())
+ goto L1; // can always convert a class to Object
+ // Need to determine correct offset before optimizing away the cast.
+ // https://issues.dlang.org/show_bug.cgi?id=16980
+ cdfrom.size(e.loc);
+ assert(cdfrom.sizeok == Sizeok.done);
+ assert(cdto.sizeok == Sizeok.done || !cdto.isBaseOf(cdfrom, null));
+ int offset;
+ if (cdto.isBaseOf(cdfrom, &offset) && offset == 0)
+ {
+ //printf(" returning4 %s\n", e.e1.toChars());
+ goto L1;
+ }
+ }
+ if (e.e1.type.mutableOf().unSharedOf().equals(e.to.mutableOf().unSharedOf()))
+ {
+ //printf(" returning5 %s\n", e.e1.toChars());
+ goto L1;
+ }
+ if (e.e1.isConst())
+ {
+ if (e.e1.op == TOK.symbolOffset)
+ {
+ if (e.type.toBasetype().ty != Tsarray)
+ {
+ const esz = e.type.size(e.loc);
+ const e1sz = e.e1.type.size(e.e1.loc);
+ if (esz == SIZE_INVALID ||
+ e1sz == SIZE_INVALID)
+ return error();
+
+ if (esz == e1sz)
+ goto L1;
+ }
+ return;
+ }
+ if (e.to.toBasetype().ty != Tvoid)
+ {
+ if (e.e1.type.equals(e.type) && e.type.equals(e.to))
+ ret = e.e1;
+ else
+ ret = Cast(e.loc, e.type, e.to, e.e1).copy();
+ }
+ }
+ //printf(" returning6 %s\n", ret.toChars());
+ }
+
+ override void visit(BinAssignExp e)
+ {
+ //printf("BinAssignExp::optimize(result = %d) %s\n", result, e.toChars());
+ if (binOptimize(e, result, /*keepLhsLvalue*/ true))
+ return;
+ if (e.op == TOK.leftShiftAssign || e.op == TOK.rightShiftAssign || e.op == TOK.unsignedRightShiftAssign)
+ {
+ if (e.e2.isConst() == 1)
+ {
+ sinteger_t i2 = e.e2.toInteger();
+ d_uns64 sz = e.e1.type.size(e.e1.loc);
+ assert(sz != SIZE_INVALID);
+ sz *= 8;
+ if (i2 < 0 || i2 >= sz)
+ {
+ e.error("shift assign by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1);
+ return error();
+ }
+ }
+ }
+ }
+
+ override void visit(BinExp e)
+ {
+ //printf("BinExp::optimize(result = %d) %s\n", result, e.toChars());
+ const keepLhsLvalue = e.op == TOK.construct || e.op == TOK.blit || e.op == TOK.assign
+ || e.op == TOK.plusPlus || e.op == TOK.minusMinus
+ || e.op == TOK.prePlusPlus || e.op == TOK.preMinusMinus;
+ binOptimize(e, result, keepLhsLvalue);
+ }
+
+ override void visit(AddExp e)
+ {
+ //printf("AddExp::optimize(%s)\n", e.toChars());
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() && e.e2.isConst())
+ {
+ if (e.e1.op == TOK.symbolOffset && e.e2.op == TOK.symbolOffset)
+ return;
+ ret = Add(e.loc, e.type, e.e1, e.e2).copy();
+ }
+ }
+
+ override void visit(MinExp e)
+ {
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() && e.e2.isConst())
+ {
+ if (e.e2.op == TOK.symbolOffset)
+ return;
+ ret = Min(e.loc, e.type, e.e1, e.e2).copy();
+ }
+ }
+
+ override void visit(MulExp e)
+ {
+ //printf("MulExp::optimize(result = %d) %s\n", result, e.toChars());
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+ {
+ ret = Mul(e.loc, e.type, e.e1, e.e2).copy();
+ }
+ }
+
+ override void visit(DivExp e)
+ {
+ //printf("DivExp::optimize(%s)\n", e.toChars());
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+ {
+ ret = Div(e.loc, e.type, e.e1, e.e2).copy();
+ }
+ }
+
+ override void visit(ModExp e)
+ {
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+ {
+ ret = Mod(e.loc, e.type, e.e1, e.e2).copy();
+ }
+ }
+
+ extern (D) void shift_optimize(BinExp e, UnionExp function(const ref Loc, Type, Expression, Expression) shift)
+ {
+ if (binOptimize(e, result))
+ return;
+ if (e.e2.isConst() == 1)
+ {
+ sinteger_t i2 = e.e2.toInteger();
+ d_uns64 sz = e.e1.type.size(e.e1.loc);
+ assert(sz != SIZE_INVALID);
+ sz *= 8;
+ if (i2 < 0 || i2 >= sz)
+ {
+ e.error("shift by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1);
+ return error();
+ }
+ if (e.e1.isConst() == 1)
+ ret = (*shift)(e.loc, e.type, e.e1, e.e2).copy();
+ }
+ }
+
+ override void visit(ShlExp e)
+ {
+ //printf("ShlExp::optimize(result = %d) %s\n", result, e.toChars());
+ shift_optimize(e, &Shl);
+ }
+
+ override void visit(ShrExp e)
+ {
+ //printf("ShrExp::optimize(result = %d) %s\n", result, e.toChars());
+ shift_optimize(e, &Shr);
+ }
+
+ override void visit(UshrExp e)
+ {
+ //printf("UshrExp::optimize(result = %d) %s\n", result, toChars());
+ shift_optimize(e, &Ushr);
+ }
+
+ override void visit(AndExp e)
+ {
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+ ret = And(e.loc, e.type, e.e1, e.e2).copy();
+ }
+
+ override void visit(OrExp e)
+ {
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+ ret = Or(e.loc, e.type, e.e1, e.e2).copy();
+ }
+
+ override void visit(XorExp e)
+ {
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+ ret = Xor(e.loc, e.type, e.e1, e.e2).copy();
+ }
+
+ override void visit(PowExp e)
+ {
+ if (binOptimize(e, result))
+ return;
+ // All negative integral powers are illegal.
+ if (e.e1.type.isintegral() && (e.e2.op == TOK.int64) && cast(sinteger_t)e.e2.toInteger() < 0)
+ {
+ e.error("cannot raise `%s` to a negative integer power. Did you mean `(cast(real)%s)^^%s` ?", e.e1.type.toBasetype().toChars(), e.e1.toChars(), e.e2.toChars());
+ return error();
+ }
+ // If e2 *could* have been an integer, make it one.
+ if (e.e2.op == TOK.float64 && e.e2.toReal() == real_t(cast(sinteger_t)e.e2.toReal()))
+ {
+ // This only applies to floating point, or positive integral powers.
+ if (e.e1.type.isfloating() || cast(sinteger_t)e.e2.toInteger() >= 0)
+ e.e2 = new IntegerExp(e.loc, e.e2.toInteger(), Type.tint64);
+ }
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+ {
+ Expression ex = Pow(e.loc, e.type, e.e1, e.e2).copy();
+ if (!CTFEExp.isCantExp(ex))
+ {
+ ret = ex;
+ return;
+ }
+ }
+ }
+
+ override void visit(CommaExp e)
+ {
+ //printf("CommaExp::optimize(result = %d) %s\n", result, e.toChars());
+ // Comma needs special treatment, because it may
+ // contain compiler-generated declarations. We can interpret them, but
+ // otherwise we must NOT attempt to constant-fold them.
+ // In particular, if the comma returns a temporary variable, it needs
+ // to be an lvalue (this is particularly important for struct constructors)
+ expOptimize(e.e1, WANTvalue);
+ expOptimize(e.e2, result, keepLvalue);
+ if (ret.op == TOK.error)
+ return;
+ if (!e.e1 || e.e1.op == TOK.int64 || e.e1.op == TOK.float64 || !hasSideEffect(e.e1))
+ {
+ ret = e.e2;
+ if (ret)
+ ret.type = e.type;
+ }
+ //printf("-CommaExp::optimize(result = %d) %s\n", result, e.e.toChars());
+ }
+
+ override void visit(ArrayLengthExp e)
+ {
+ //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, e.toChars());
+ if (unaOptimize(e, WANTexpand))
+ return;
+ // CTFE interpret static immutable arrays (to get better diagnostics)
+ if (e.e1.op == TOK.variable)
+ {
+ VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration();
+ if (v && (v.storage_class & STC.static_) && (v.storage_class & STC.immutable_) && v._init)
+ {
+ if (Expression ci = v.getConstInitializer())
+ e.e1 = ci;
+ }
+ }
+ if (e.e1.op == TOK.string_ || e.e1.op == TOK.arrayLiteral || e.e1.op == TOK.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray)
+ {
+ ret = ArrayLength(e.type, e.e1).copy();
+ }
+ }
+
+ override void visit(EqualExp e)
+ {
+ //printf("EqualExp::optimize(result = %x) %s\n", result, e.toChars());
+ if (binOptimize(e, WANTvalue))
+ return;
+ Expression e1 = fromConstInitializer(result, e.e1);
+ Expression e2 = fromConstInitializer(result, e.e2);
+ if (e1.op == TOK.error)
+ {
+ ret = e1;
+ return;
+ }
+ if (e2.op == TOK.error)
+ {
+ ret = e2;
+ return;
+ }
+ ret = Equal(e.op, e.loc, e.type, e1, e2).copy();
+ if (CTFEExp.isCantExp(ret))
+ ret = e;
+ }
+
+ override void visit(IdentityExp e)
+ {
+ //printf("IdentityExp::optimize(result = %d) %s\n", result, e.toChars());
+ if (binOptimize(e, WANTvalue))
+ return;
+ if ((e.e1.isConst() && e.e2.isConst()) || (e.e1.op == TOK.null_ && e.e2.op == TOK.null_))
+ {
+ ret = Identity(e.op, e.loc, e.type, e.e1, e.e2).copy();
+ if (CTFEExp.isCantExp(ret))
+ ret = e;
+ }
+ }
+
+ override void visit(IndexExp e)
+ {
+ //printf("IndexExp::optimize(result = %d) %s\n", result, e.toChars());
+ if (expOptimize(e.e1, result & WANTexpand))
+ return;
+ Expression ex = fromConstInitializer(result, e.e1);
+ // We might know $ now
+ setLengthVarIfKnown(e.lengthVar, ex);
+ if (expOptimize(e.e2, WANTvalue))
+ return;
+ // Don't optimize to an array literal element directly in case an lvalue is requested
+ if (keepLvalue && ex.op == TOK.arrayLiteral)
+ return;
+ ret = Index(e.type, ex, e.e2).copy();
+ if (CTFEExp.isCantExp(ret) || (!ret.isErrorExp() && keepLvalue && !ret.isLvalue()))
+ ret = e;
+ }
+
+ override void visit(SliceExp e)
+ {
+ //printf("SliceExp::optimize(result = %d) %s\n", result, e.toChars());
+ if (expOptimize(e.e1, result & WANTexpand))
+ return;
+ if (!e.lwr)
+ {
+ if (e.e1.op == TOK.string_)
+ {
+ // Convert slice of string literal into dynamic array
+ Type t = e.e1.type.toBasetype();
+ if (Type tn = t.nextOf())
+ ret = e.e1.castTo(null, tn.arrayOf());
+ }
+ }
+ else
+ {
+ e.e1 = fromConstInitializer(result, e.e1);
+ // We might know $ now
+ setLengthVarIfKnown(e.lengthVar, e.e1);
+ expOptimize(e.lwr, WANTvalue);
+ expOptimize(e.upr, WANTvalue);
+ if (ret.op == TOK.error)
+ return;
+ ret = Slice(e.type, e.e1, e.lwr, e.upr).copy();
+ if (CTFEExp.isCantExp(ret))
+ ret = e;
+ }
+ // https://issues.dlang.org/show_bug.cgi?id=14649
+ // Leave the slice form so it might be
+ // a part of array operation.
+ // Assume that the backend codegen will handle the form `e[]`
+ // as an equal to `e` itself.
+ if (ret.op == TOK.string_)
+ {
+ e.e1 = ret;
+ e.lwr = null;
+ e.upr = null;
+ ret = e;
+ }
+ //printf("-SliceExp::optimize() %s\n", ret.toChars());
+ }
+
+ override void visit(LogicalExp e)
+ {
+ //printf("LogicalExp::optimize(%d) %s\n", result, e.toChars());
+ if (expOptimize(e.e1, WANTvalue))
+ return;
+ const oror = e.op == TOK.orOr;
+ if (e.e1.isBool(oror))
+ {
+ // Replace with (e1, oror)
+ ret = IntegerExp.createBool(oror);
+ ret = Expression.combine(e.e1, ret);
+ if (e.type.toBasetype().ty == Tvoid)
+ {
+ ret = new CastExp(e.loc, ret, Type.tvoid);
+ ret.type = e.type;
+ }
+ ret = Expression_optimize(ret, result, false);
+ return;
+ }
+ expOptimize(e.e2, WANTvalue);
+ if (e.e1.isConst())
+ {
+ if (e.e2.isConst())
+ {
+ bool n1 = e.e1.isBool(true);
+ bool n2 = e.e2.isBool(true);
+ ret = new IntegerExp(e.loc, oror ? (n1 || n2) : (n1 && n2), e.type);
+ }
+ else if (e.e1.isBool(!oror))
+ {
+ if (e.type.toBasetype().ty == Tvoid)
+ ret = e.e2;
+ else
+ {
+ ret = new CastExp(e.loc, e.e2, e.type);
+ ret.type = e.type;
+ }
+ }
+ }
+ }
+
+ override void visit(CmpExp e)
+ {
+ //printf("CmpExp::optimize() %s\n", e.toChars());
+ if (binOptimize(e, WANTvalue))
+ return;
+ Expression e1 = fromConstInitializer(result, e.e1);
+ Expression e2 = fromConstInitializer(result, e.e2);
+ ret = Cmp(e.op, e.loc, e.type, e1, e2).copy();
+ if (CTFEExp.isCantExp(ret))
+ ret = e;
+ }
+
+ override void visit(CatExp e)
+ {
+ //printf("CatExp::optimize(%d) %s\n", result, e.toChars());
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.op == TOK.concatenate)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=12798
+ // optimize ((expr ~ str1) ~ str2)
+ CatExp ce1 = cast(CatExp)e.e1;
+ scope CatExp cex = new CatExp(e.loc, ce1.e2, e.e2);
+ cex.type = e.type;
+ Expression ex = Expression_optimize(cex, result, false);
+ if (ex != cex)
+ {
+ e.e1 = ce1.e1;
+ e.e2 = ex;
+ }
+ }
+ // optimize "str"[] -> "str"
+ if (e.e1.op == TOK.slice)
+ {
+ SliceExp se1 = cast(SliceExp)e.e1;
+ if (se1.e1.op == TOK.string_ && !se1.lwr)
+ e.e1 = se1.e1;
+ }
+ if (e.e2.op == TOK.slice)
+ {
+ SliceExp se2 = cast(SliceExp)e.e2;
+ if (se2.e1.op == TOK.string_ && !se2.lwr)
+ e.e2 = se2.e1;
+ }
+ ret = Cat(e.loc, e.type, e.e1, e.e2).copy();
+ if (CTFEExp.isCantExp(ret))
+ ret = e;
+ }
+
+ override void visit(CondExp e)
+ {
+ if (expOptimize(e.econd, WANTvalue))
+ return;
+ if (e.econd.isBool(true))
+ ret = Expression_optimize(e.e1, result, keepLvalue);
+ else if (e.econd.isBool(false))
+ ret = Expression_optimize(e.e2, result, keepLvalue);
+ else
+ {
+ expOptimize(e.e1, result, keepLvalue);
+ expOptimize(e.e2, result, keepLvalue);
+ }
+ }
+ }
+
+ scope OptimizeVisitor v = new OptimizeVisitor(e, result, keepLvalue);
+
+ // Optimize the expression until it can no longer be simplified.
+ size_t b;
+ while (1)
+ {
+ if (b++ == global.recursionLimit)
+ {
+ e.error("infinite loop while optimizing expression");
+ fatal();
+ }
+ auto ex = v.ret;
+ ex.accept(v);
+ if (ex == v.ret)
+ break;
+ }
+ return v.ret;
+}
diff --git a/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c
deleted file mode 100644
index e1f1321..0000000
--- a/gcc/d/dmd/parse.c
+++ /dev/null
@@ -1,8492 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/parse.c
- */
-
-// This is the D parser
-
-#include "root/dsystem.h" // strlen(),memcpy()
-#include "root/rmem.h"
-
-#include "mars.h"
-#include "lexer.h"
-#include "parse.h"
-#include "init.h"
-#include "attrib.h"
-#include "cond.h"
-#include "mtype.h"
-#include "template.h"
-#include "staticassert.h"
-#include "expression.h"
-#include "statement.h"
-#include "module.h"
-#include "dsymbol.h"
-#include "import.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "enum.h"
-#include "id.h"
-#include "version.h"
-#include "aliasthis.h"
-#include "nspace.h"
-#include "hdrgen.h"
-
-Expression *typeToExpression(Type *t);
-
-// Support C cast syntax:
-// (type)(expression)
-#define CCASTSYNTAX 1
-
-// Support postfix C array declarations, such as
-// int a[3][4];
-#define CARRAYDECL 1
-
-Parser::Parser(Module *module, const utf8_t *base, size_t length, bool doDocComment)
- : Lexer(module ? module->srcfile->toChars() : NULL, base, 0, length, doDocComment, false)
-{
- //printf("Parser::Parser()\n");
- mod = module;
- md = NULL;
- linkage = LINKd;
- endloc = Loc();
- inBrackets = 0;
- lookingForElse = Loc();
- //nextToken(); // start up the scanner
-}
-
-/*********************
- * Use this constructor for string mixins.
- * Input:
- * loc location in source file of mixin
- */
-Parser::Parser(Loc loc, Module *module, const utf8_t *base, size_t length, bool doDocComment)
- : Lexer(module ? module->srcfile->toChars() : NULL, base, 0, length, doDocComment, false)
-{
- //printf("Parser::Parser()\n");
- scanloc = loc;
-
- if (loc.filename)
- {
- /* Create a pseudo-filename for the mixin string, as it may not even exist
- * in the source file.
- */
- char *filename = (char *)mem.xmalloc(strlen(loc.filename) + 7 + sizeof(loc.linnum) * 3 + 1);
- sprintf(filename, "%s-mixin-%d", loc.filename, (int)loc.linnum);
- scanloc.filename = filename;
- }
-
- mod = module;
- md = NULL;
- linkage = LINKd;
- endloc = Loc();
- inBrackets = 0;
- lookingForElse = Loc();
- //nextToken(); // start up the scanner
-}
-
-Dsymbols *Parser::parseModule()
-{
- const utf8_t *comment = token.blockComment;
- bool isdeprecated = false;
- Expression *msg = NULL;
- Expressions *udas = NULL;
- Dsymbols *decldefs;
-
- Token *tk;
- if (skipAttributes(&token, &tk) && tk->value == TOKmodule)
- {
- while (token.value != TOKmodule)
- {
- switch (token.value)
- {
- case TOKdeprecated:
- {
- // deprecated (...) module ...
- if (isdeprecated)
- {
- error("there is only one deprecation attribute allowed for module declaration");
- }
- else
- {
- isdeprecated = true;
- }
- nextToken();
- if (token.value == TOKlparen)
- {
- check(TOKlparen);
- msg = parseAssignExp();
- check(TOKrparen);
- }
- break;
- }
- case TOKat:
- {
- Expressions *exps = NULL;
- StorageClass stc = parseAttribute(&exps);
-
- if (stc == STCproperty || stc == STCnogc || stc == STCdisable ||
- stc == STCsafe || stc == STCtrusted || stc == STCsystem)
- {
- error("@%s attribute for module declaration is not supported", token.toChars());
- }
- else
- {
- udas = UserAttributeDeclaration::concat(udas, exps);
- }
- if (stc)
- nextToken();
- break;
- }
- default:
- {
- error("`module` expected instead of %s", token.toChars());
- nextToken();
- break;
- }
- }
- }
- }
-
- if (udas)
- {
- Dsymbols *a = new Dsymbols();
- UserAttributeDeclaration *udad = new UserAttributeDeclaration(udas, a);
- mod->userAttribDecl = udad;
- }
-
- // ModuleDeclation leads off
- if (token.value == TOKmodule)
- {
- Loc loc = token.loc;
-
- nextToken();
- if (token.value != TOKidentifier)
- {
- error("identifier expected following module");
- goto Lerr;
- }
- else
- {
- Identifiers *a = NULL;
- Identifier *id;
-
- id = token.ident;
- while (nextToken() == TOKdot)
- {
- if (!a)
- a = new Identifiers();
- a->push(id);
- nextToken();
- if (token.value != TOKidentifier)
- {
- error("identifier expected following package");
- goto Lerr;
- }
- id = token.ident;
- }
-
- md = new ModuleDeclaration(loc, a, id);
- md->isdeprecated = isdeprecated;
- md->msg = msg;
-
- if (token.value != TOKsemicolon)
- error("`;` expected following module declaration instead of %s", token.toChars());
- nextToken();
- addComment(mod, comment);
- }
- }
-
- decldefs = parseDeclDefs(0);
- if (token.value != TOKeof)
- {
- error(token.loc, "unrecognized declaration");
- goto Lerr;
- }
- return decldefs;
-
-Lerr:
- while (token.value != TOKsemicolon && token.value != TOKeof)
- nextToken();
- nextToken();
- return new Dsymbols();
-}
-
-static StorageClass parseDeprecatedAttribute(Parser *p, Expression **msg)
-{
- if (p->peekNext() != TOKlparen)
- return STCdeprecated;
-
- p->nextToken();
- p->check(TOKlparen);
- Expression *e = p->parseAssignExp();
- p->check(TOKrparen);
- if (*msg)
- {
- p->error("conflicting storage class `deprecated(%s)` and `deprecated(%s)`",
- (*msg)->toChars(), e->toChars());
- }
- *msg = e;
- return STCundefined;
-}
-
-struct PrefixAttributes
-{
- StorageClass storageClass;
- Expression *depmsg;
- LINK link;
- Prot protection;
- bool setAlignment;
- Expression *ealign;
- Expressions *udas;
- const utf8_t *comment;
-
- PrefixAttributes()
- : storageClass(STCundefined),
- depmsg(NULL),
- link(LINKdefault),
- protection(Prot::undefined),
- setAlignment(false),
- ealign(NULL),
- udas(NULL),
- comment(NULL)
- {
- }
-};
-
-Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes *pAttrs)
-{
- Dsymbol *lastDecl = NULL; // used to link unittest to its previous declaration
- if (!pLastDecl)
- pLastDecl = &lastDecl;
-
- LINK linksave = linkage; // save global state
-
- //printf("Parser::parseDeclDefs()\n");
- Dsymbols *decldefs = new Dsymbols();
- do
- {
- // parse result
- Dsymbol *s = NULL;
- Dsymbols *a = NULL;
-
- PrefixAttributes attrs;
- if (!once || !pAttrs)
- {
- pAttrs = &attrs;
- pAttrs->comment = token.blockComment;
- }
- Prot::Kind prot;
- StorageClass stc;
- Condition *condition;
-
- linkage = linksave;
-
- switch (token.value)
- {
- case TOKenum:
- {
- /* Determine if this is a manifest constant declaration,
- * or a conventional enum.
- */
- Token *t = peek(&token);
- if (t->value == TOKlcurly || t->value == TOKcolon)
- s = parseEnum();
- else if (t->value != TOKidentifier)
- goto Ldeclaration;
- else
- {
- t = peek(t);
- if (t->value == TOKlcurly || t->value == TOKcolon ||
- t->value == TOKsemicolon)
- s = parseEnum();
- else
- goto Ldeclaration;
- }
- break;
- }
-
- case TOKimport:
- a = parseImport();
- // keep pLastDecl
- break;
-
- case TOKtemplate:
- s = (Dsymbol *)parseTemplateDeclaration();
- break;
-
- case TOKmixin:
- {
- Loc loc = token.loc;
- switch (peekNext())
- {
- case TOKlparen:
- {
- // mixin(string)
- nextToken();
- Expressions *exps = parseArguments();
- check(TOKsemicolon);
- s = new CompileDeclaration(loc, exps);
- break;
- }
- case TOKtemplate:
- // mixin template
- nextToken();
- s = (Dsymbol *)parseTemplateDeclaration(true);
- break;
-
- default:
- s = parseMixin();
- break;
- }
- break;
- }
-
- case TOKwchar: case TOKdchar:
- case TOKbool: case TOKchar:
- case TOKint8: case TOKuns8:
- case TOKint16: case TOKuns16:
- case TOKint32: case TOKuns32:
- case TOKint64: case TOKuns64:
- case TOKint128: case TOKuns128:
- case TOKfloat32: case TOKfloat64: case TOKfloat80:
- case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
- case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
- case TOKvoid:
- case TOKalias:
- case TOKidentifier:
- case TOKsuper:
- case TOKtypeof:
- case TOKdot:
- case TOKvector:
- case TOKstruct:
- case TOKunion:
- case TOKclass:
- case TOKinterface:
- case TOKtraits:
- Ldeclaration:
- a = parseDeclarations(false, pAttrs, pAttrs->comment);
- if (a && a->length)
- *pLastDecl = (*a)[a->length-1];
- break;
-
- case TOKthis:
- if (peekNext() == TOKdot)
- goto Ldeclaration;
- else
- s = parseCtor(pAttrs);
- break;
-
- case TOKtilde:
- s = parseDtor(pAttrs);
- break;
-
- case TOKinvariant:
- {
- Token *t = peek(&token);
- if (t->value == TOKlparen || t->value == TOKlcurly)
- {
- // invariant { statements... }
- // invariant() { statements... }
- // invariant (expression);
- s = parseInvariant(pAttrs);
- }
- else
- {
- error("invariant body expected, not `%s`", token.toChars());
- goto Lerror;
- }
- break;
- }
-
- case TOKunittest:
- if (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration)
- {
- s = parseUnitTest(pAttrs);
- if (*pLastDecl)
- (*pLastDecl)->ddocUnittest = (UnitTestDeclaration *)s;
- }
- else
- {
- // Skip over unittest block by counting { }
- Loc loc = token.loc;
- int braces = 0;
- while (1)
- {
- nextToken();
- switch (token.value)
- {
- case TOKlcurly:
- ++braces;
- continue;
-
- case TOKrcurly:
- if (--braces)
- continue;
- nextToken();
- break;
-
- case TOKeof:
- /* { */
- error(loc, "closing } of unittest not found before end of file");
- goto Lerror;
-
- default:
- continue;
- }
- break;
- }
- // Workaround 14894. Add an empty unittest declaration to keep
- // the number of symbols in this scope independent of -unittest.
- s = new UnitTestDeclaration(loc, token.loc, STCundefined, NULL);
- }
- break;
-
- case TOKnew:
- s = parseNew(pAttrs);
- break;
-
- case TOKdelete:
- s = parseDelete(pAttrs);
- break;
-
- case TOKcolon:
- case TOKlcurly:
- error("declaration expected, not `%s`",token.toChars());
- goto Lerror;
-
- case TOKrcurly:
- case TOKeof:
- if (once)
- error("declaration expected, not `%s`", token.toChars());
- return decldefs;
-
- case TOKstatic:
- {
- TOK next = peekNext();
- if (next == TOKthis)
- s = parseStaticCtor(pAttrs);
- else if (next == TOKtilde)
- s = parseStaticDtor(pAttrs);
- else if (next == TOKassert)
- s = parseStaticAssert();
- else if (next == TOKif)
- {
- condition = parseStaticIfCondition();
- Dsymbols *athen;
- if (token.value == TOKcolon)
- athen = parseBlock(pLastDecl);
- else
- {
- Loc lookingForElseSave = lookingForElse;
- lookingForElse = token.loc;
- athen = parseBlock(pLastDecl);
- lookingForElse = lookingForElseSave;
- }
- Dsymbols *aelse = NULL;
- if (token.value == TOKelse)
- {
- Loc elseloc = token.loc;
- nextToken();
- aelse = parseBlock(pLastDecl);
- checkDanglingElse(elseloc);
- }
- s = new StaticIfDeclaration(condition, athen, aelse);
- }
- else if (next == TOKimport)
- {
- a = parseImport();
- // keep pLastDecl
- }
- else if (next == TOKforeach || next == TOKforeach_reverse)
- {
- s = parseForeachStaticDecl(token.loc, pLastDecl);
- }
- else
- {
- stc = STCstatic;
- goto Lstc;
- }
- break;
- }
-
- case TOKconst:
- if (peekNext() == TOKlparen)
- goto Ldeclaration;
- stc = STCconst;
- goto Lstc;
-
- case TOKimmutable:
- if (peekNext() == TOKlparen)
- goto Ldeclaration;
- stc = STCimmutable;
- goto Lstc;
-
- case TOKshared:
- {
- TOK next = peekNext();
- if (next == TOKlparen)
- goto Ldeclaration;
- if (next == TOKstatic)
- {
- TOK next2 = peekNext2();
- if (next2 == TOKthis)
- {
- s = parseSharedStaticCtor(pAttrs);
- break;
- }
- if (next2 == TOKtilde)
- {
- s = parseSharedStaticDtor(pAttrs);
- break;
- }
- }
- stc = STCshared;
- goto Lstc;
- }
-
- case TOKwild:
- if (peekNext() == TOKlparen)
- goto Ldeclaration;
- stc = STCwild;
- goto Lstc;
-
- case TOKfinal: stc = STCfinal; goto Lstc;
- case TOKauto: stc = STCauto; goto Lstc;
- case TOKscope: stc = STCscope; goto Lstc;
- case TOKoverride: stc = STCoverride; goto Lstc;
- case TOKabstract: stc = STCabstract; goto Lstc;
- case TOKsynchronized: stc = STCsynchronized; goto Lstc;
- case TOKnothrow: stc = STCnothrow; goto Lstc;
- case TOKpure: stc = STCpure; goto Lstc;
- case TOKref: stc = STCref; goto Lstc;
- case TOKgshared: stc = STCgshared; goto Lstc;
- //case TOKmanifest: stc = STCmanifest; goto Lstc;
- case TOKat:
- {
- Expressions *exps = NULL;
- stc = parseAttribute(&exps);
- if (stc)
- goto Lstc; // it's a predefined attribute
- // no redundant/conflicting check for UDAs
- pAttrs->udas = UserAttributeDeclaration::concat(pAttrs->udas, exps);
- goto Lautodecl;
- }
- Lstc:
- pAttrs->storageClass = appendStorageClass(pAttrs->storageClass, stc);
- nextToken();
-
- Lautodecl:
- Token *tk;
-
- /* Look for auto initializers:
- * storage_class identifier = initializer;
- * storage_class identifier(...) = initializer;
- */
- if (token.value == TOKidentifier &&
- skipParensIf(peek(&token), &tk) &&
- tk->value == TOKassign)
- {
- a = parseAutoDeclarations(pAttrs->storageClass, pAttrs->comment);
- pAttrs->storageClass = STCundefined;
- if (a && a->length)
- *pLastDecl = (*a)[a->length-1];
- if (pAttrs->udas)
- {
- s = new UserAttributeDeclaration(pAttrs->udas, a);
- pAttrs->udas = NULL;
- }
- break;
- }
-
- /* Look for return type inference for template functions.
- */
- if (token.value == TOKidentifier && skipParens(peek(&token), &tk) && skipAttributes(tk, &tk) &&
- (tk->value == TOKlparen || tk->value == TOKlcurly || tk->value == TOKin ||
- tk->value == TOKout || tk->value == TOKdo ||
- (tk->value == TOKidentifier && tk->ident == Id::_body))
- )
- {
- a = parseDeclarations(true, pAttrs, pAttrs->comment);
- if (a && a->length)
- *pLastDecl = (*a)[a->length-1];
- if (pAttrs->udas)
- {
- s = new UserAttributeDeclaration(pAttrs->udas, a);
- pAttrs->udas = NULL;
- }
- break;
- }
-
- a = parseBlock(pLastDecl, pAttrs);
- if (pAttrs->storageClass != STCundefined)
- {
- s = new StorageClassDeclaration(pAttrs->storageClass, a);
- pAttrs->storageClass = STCundefined;
- }
- if (pAttrs->udas)
- {
- if (s)
- {
- a = new Dsymbols();
- a->push(s);
- }
- s = new UserAttributeDeclaration(pAttrs->udas, a);
- pAttrs->udas = NULL;
- }
- break;
-
- case TOKdeprecated:
- {
- if (StorageClass _stc = parseDeprecatedAttribute(this, &pAttrs->depmsg))
- {
- stc = _stc;
- goto Lstc;
- }
- a = parseBlock(pLastDecl, pAttrs);
- if (pAttrs->depmsg)
- {
- s = new DeprecatedDeclaration(pAttrs->depmsg, a);
- pAttrs->depmsg = NULL;
- }
- break;
- }
-
- case TOKlbracket:
- {
- if (peekNext() == TOKrbracket)
- error("empty attribute list is not allowed");
- error("use @(attributes) instead of [attributes]");
- Expressions *exps = parseArguments();
- // no redundant/conflicting check for UDAs
-
- pAttrs->udas = UserAttributeDeclaration::concat(pAttrs->udas, exps);
- a = parseBlock(pLastDecl, pAttrs);
- if (pAttrs->udas)
- {
- s = new UserAttributeDeclaration(pAttrs->udas, a);
- pAttrs->udas = NULL;
- }
- break;
- }
-
- case TOKextern:
- {
- if (peek(&token)->value != TOKlparen)
- {
- stc = STCextern;
- goto Lstc;
- }
-
- Loc linkLoc = token.loc;
- Identifiers *idents = NULL;
- CPPMANGLE cppmangle = CPPMANGLEdefault;
- bool cppMangleOnly = false;
- LINK link = parseLinkage(&idents, &cppmangle, &cppMangleOnly);
- if (pAttrs->link != LINKdefault)
- {
- if (pAttrs->link != link)
- {
- error("conflicting linkage extern (%s) and extern (%s)",
- linkageToChars(pAttrs->link), linkageToChars(link));
- }
- else if (idents)
- {
- // Allow:
- // extern(C++, foo) extern(C++, bar) void foo();
- // to be equivalent with:
- // extern(C++, foo.bar) void foo();
- }
- else
- error("redundant linkage extern (%s)", linkageToChars(pAttrs->link));
- }
- pAttrs->link = link;
- this->linkage = link;
- a = parseBlock(pLastDecl, pAttrs);
- if (idents)
- {
- assert(link == LINKcpp);
- assert(idents->length);
- for (size_t i = idents->length; i;)
- {
- Identifier *id = (*idents)[--i];
- if (s)
- {
- a = new Dsymbols();
- a->push(s);
- }
- s = new Nspace(linkLoc, id, a, cppMangleOnly);
- }
- delete idents;
- pAttrs->link = LINKdefault;
- }
- else if (pAttrs->link != LINKdefault)
- {
- s = new LinkDeclaration(pAttrs->link, a);
- pAttrs->link = LINKdefault;
- }
- else if (cppmangle != CPPMANGLEdefault)
- {
- assert(link == LINKcpp);
- s = new CPPMangleDeclaration(cppmangle, a);
- }
- break;
- }
-
- case TOKprivate: prot = Prot::private_; goto Lprot;
- case TOKpackage: prot = Prot::package_; goto Lprot;
- case TOKprotected: prot = Prot::protected_; goto Lprot;
- case TOKpublic: prot = Prot::public_; goto Lprot;
- case TOKexport: prot = Prot::export_; goto Lprot;
- Lprot:
- {
- if (pAttrs->protection.kind != Prot::undefined)
- {
- if (pAttrs->protection.kind != prot)
- error("conflicting protection attribute `%s` and `%s`",
- protectionToChars(pAttrs->protection.kind), protectionToChars(prot));
- else
- error("redundant protection attribute `%s`", protectionToChars(prot));
- }
- pAttrs->protection.kind = prot;
-
- nextToken();
-
- // optional qualified package identifier to bind
- // protection to
- Identifiers *pkg_prot_idents = NULL;
- if (pAttrs->protection.kind == Prot::package_ && token.value == TOKlparen)
- {
- pkg_prot_idents = parseQualifiedIdentifier("protection package");
-
- if (pkg_prot_idents)
- check(TOKrparen);
- else
- {
- while (token.value != TOKsemicolon && token.value != TOKeof)
- nextToken();
- nextToken();
- break;
- }
- }
-
- Loc attrloc = token.loc;
- a = parseBlock(pLastDecl, pAttrs);
- if (pAttrs->protection.kind != Prot::undefined)
- {
- if (pAttrs->protection.kind == Prot::package_ && pkg_prot_idents)
- s = new ProtDeclaration(attrloc, pkg_prot_idents, a);
- else
- s = new ProtDeclaration(attrloc, pAttrs->protection, a);
-
- pAttrs->protection = Prot(Prot::undefined);
- }
- break;
- }
-
- case TOKalign:
- {
- const Loc attrLoc = token.loc;
-
- nextToken();
-
- Expression *e = NULL; // default
- if (token.value == TOKlparen)
- {
- nextToken();
- e = parseAssignExp();
- check(TOKrparen);
- }
-
- if (pAttrs->setAlignment)
- {
- const char *s1 = "";
- OutBuffer buf1;
- if (e)
- {
- buf1.printf("(%s)", e->toChars());
- s1 = buf1.peekChars();
- }
- error("redundant alignment attribute align%s", s1);
- }
-
- pAttrs->setAlignment = true;
- pAttrs->ealign = e;
- a = parseBlock(pLastDecl, pAttrs);
- if (pAttrs->setAlignment)
- {
- s = new AlignDeclaration(attrLoc, pAttrs->ealign, a);
- pAttrs->setAlignment = false;
- pAttrs->ealign = NULL;
- }
- break;
- }
-
- case TOKpragma:
- {
- Expressions *args = NULL;
- Loc loc = token.loc;
-
- nextToken();
- check(TOKlparen);
- if (token.value != TOKidentifier)
- {
- error("pragma(identifier) expected");
- goto Lerror;
- }
- Identifier *ident = token.ident;
- nextToken();
- if (token.value == TOKcomma && peekNext() != TOKrparen)
- args = parseArguments(); // pragma(identifier, args...)
- else
- check(TOKrparen); // pragma(identifier)
-
- Dsymbols *a2 = NULL;
- if (token.value == TOKsemicolon)
- {
- /* Bugzilla 2354: Accept single semicolon as an empty
- * DeclarationBlock following attribute.
- *
- * Attribute DeclarationBlock
- * Pragma DeclDef
- * ;
- */
- nextToken();
- }
- else
- a2 = parseBlock(pLastDecl);
- s = new PragmaDeclaration(loc, ident, args, a2);
- break;
- }
-
- case TOKdebug:
- nextToken();
- if (token.value == TOKassign)
- {
- nextToken();
- if (token.value == TOKidentifier)
- s = new DebugSymbol(token.loc, token.ident);
- else if (token.value == TOKint32v || token.value == TOKint64v)
- s = new DebugSymbol(token.loc, (unsigned)token.uns64value);
- else
- {
- error("identifier or integer expected, not %s", token.toChars());
- s = NULL;
- }
- nextToken();
- if (token.value != TOKsemicolon)
- error("semicolon expected");
- nextToken();
- break;
- }
-
- condition = parseDebugCondition();
- goto Lcondition;
-
- case TOKversion:
- nextToken();
- if (token.value == TOKassign)
- {
- nextToken();
- if (token.value == TOKidentifier)
- s = new VersionSymbol(token.loc, token.ident);
- else if (token.value == TOKint32v || token.value == TOKint64v)
- s = new VersionSymbol(token.loc, (unsigned)token.uns64value);
- else
- {
- error("identifier or integer expected, not %s", token.toChars());
- s = NULL;
- }
- nextToken();
- if (token.value != TOKsemicolon)
- error("semicolon expected");
- nextToken();
- break;
- }
- condition = parseVersionCondition();
- goto Lcondition;
-
- Lcondition:
- {
- Dsymbols *athen;
- if (token.value == TOKcolon)
- athen = parseBlock(pLastDecl);
- else
- {
- Loc lookingForElseSave = lookingForElse;
- lookingForElse = token.loc;
- athen = parseBlock(pLastDecl);
- lookingForElse = lookingForElseSave;
- }
- Dsymbols *aelse = NULL;
- if (token.value == TOKelse)
- {
- Loc elseloc = token.loc;
- nextToken();
- aelse = parseBlock(pLastDecl);
- checkDanglingElse(elseloc);
- }
- s = new ConditionalDeclaration(condition, athen, aelse);
- break;
- }
-
- case TOKsemicolon: // empty declaration
- //error("empty declaration");
- nextToken();
- continue;
-
- default:
- error("declaration expected, not `%s`",token.toChars());
- Lerror:
- while (token.value != TOKsemicolon && token.value != TOKeof)
- nextToken();
- nextToken();
- s = NULL;
- continue;
- }
-
- if (s)
- {
- if (!s->isAttribDeclaration())
- *pLastDecl = s;
- decldefs->push(s);
- addComment(s, pAttrs->comment);
- }
- else if (a && a->length)
- {
- decldefs->append(a);
- }
- } while (!once);
-
- linkage = linksave;
-
- return decldefs;
-}
-
-/*********************************************
- * Give error on redundant/conflicting storage class.
- *
- * TODO: remove deprecation in 2.068 and keep only error
- */
-
-StorageClass Parser::appendStorageClass(StorageClass storageClass, StorageClass stc,
- bool deprec)
-{
- if ((storageClass & stc) ||
- (storageClass & STCin && stc & (STCconst | STCscope)) ||
- (stc & STCin && storageClass & (STCconst | STCscope)))
- {
- OutBuffer buf;
- stcToBuffer(&buf, stc);
- if (deprec)
- deprecation("redundant attribute `%s`", buf.peekChars());
- else
- error("redundant attribute `%s`", buf.peekChars());
- return storageClass | stc;
- }
-
- storageClass |= stc;
-
- if (stc & (STCconst | STCimmutable | STCmanifest))
- {
- StorageClass u = storageClass & (STCconst | STCimmutable | STCmanifest);
- if (u & (u - 1))
- error("conflicting attribute `%s`", Token::toChars(token.value));
- }
- if (stc & (STCgshared | STCshared | STCtls))
- {
- StorageClass u = storageClass & (STCgshared | STCshared | STCtls);
- if (u & (u - 1))
- error("conflicting attribute `%s`", Token::toChars(token.value));
- }
- if (stc & (STCsafe | STCsystem | STCtrusted))
- {
- StorageClass u = storageClass & (STCsafe | STCsystem | STCtrusted);
- if (u & (u - 1))
- error("conflicting attribute `@%s`", token.toChars());
- }
-
- return storageClass;
-}
-
-/***********************************************
- * Parse attribute, lexer is on '@'.
- * Input:
- * pudas array of UDAs to append to
- * Returns:
- * storage class if a predefined attribute; also scanner remains on identifier.
- * 0 if not a predefined attribute
- * *pudas set if user defined attribute, scanner is past UDA
- * *pudas NULL if not a user defined attribute
- */
-
-StorageClass Parser::parseAttribute(Expressions **pudas)
-{
- nextToken();
- Expressions *udas = NULL;
- StorageClass stc = 0;
- if (token.value == TOKidentifier)
- {
- if (token.ident == Id::property)
- stc = STCproperty;
- else if (token.ident == Id::nogc)
- stc = STCnogc;
- else if (token.ident == Id::safe)
- stc = STCsafe;
- else if (token.ident == Id::trusted)
- stc = STCtrusted;
- else if (token.ident == Id::system)
- stc = STCsystem;
- else if (token.ident == Id::disable)
- stc = STCdisable;
- else if (token.ident == Id::future)
- stc = STCfuture;
- else
- {
- // Allow identifier, template instantiation, or function call
- Expression *exp = parsePrimaryExp();
- if (token.value == TOKlparen)
- {
- Loc loc = token.loc;
- exp = new CallExp(loc, exp, parseArguments());
- }
-
- udas = new Expressions();
- udas->push(exp);
- }
- }
- else if (token.value == TOKlparen)
- {
- // @( ArgumentList )
- // Concatenate with existing
- if (peekNext() == TOKrparen)
- error("empty attribute list is not allowed");
- udas = parseArguments();
- }
- else
- {
- error("@identifier or @(ArgumentList) expected, not @%s", token.toChars());
- }
-
- if (stc)
- {
- }
- else if (udas)
- {
- *pudas = UserAttributeDeclaration::concat(*pudas, udas);
- }
- else
- error("valid attributes are @property, @safe, @trusted, @system, @disable");
- return stc;
-}
-
-/***********************************************
- * Parse const/immutable/shared/inout/nothrow/pure postfix
- */
-
-StorageClass Parser::parsePostfix(StorageClass storageClass, Expressions **pudas)
-{
- while (1)
- {
- StorageClass stc;
- switch (token.value)
- {
- case TOKconst: stc = STCconst; break;
- case TOKimmutable: stc = STCimmutable; break;
- case TOKshared: stc = STCshared; break;
- case TOKwild: stc = STCwild; break;
- case TOKnothrow: stc = STCnothrow; break;
- case TOKpure: stc = STCpure; break;
- case TOKreturn: stc = STCreturn; break;
- case TOKscope: stc = STCscope; break;
- case TOKat:
- {
- Expressions *udas = NULL;
- stc = parseAttribute(&udas);
- if (udas)
- {
- if (pudas)
- *pudas = UserAttributeDeclaration::concat(*pudas, udas);
- else
- {
- // Disallow:
- // void function() @uda fp;
- // () @uda { return 1; }
- error("user-defined attributes cannot appear as postfixes");
- }
- continue;
- }
- break;
- }
-
- default:
- return storageClass;
- }
- storageClass = appendStorageClass(storageClass, stc, true);
- nextToken();
- }
-}
-
-StorageClass Parser::parseTypeCtor()
-{
- StorageClass storageClass = STCundefined;
-
- while (1)
- {
- if (peek(&token)->value == TOKlparen)
- return storageClass;
-
- StorageClass stc;
- switch (token.value)
- {
- case TOKconst: stc = STCconst; break;
- case TOKimmutable: stc = STCimmutable; break;
- case TOKshared: stc = STCshared; break;
- case TOKwild: stc = STCwild; break;
-
- default:
- return storageClass;
- }
- storageClass = appendStorageClass(storageClass, stc);
- nextToken();
- }
-}
-
-/********************************************
- * Parse declarations after an align, protection, or extern decl.
- */
-
-Dsymbols *Parser::parseBlock(Dsymbol **pLastDecl, PrefixAttributes *pAttrs)
-{
- Dsymbols *a = NULL;
-
- //printf("parseBlock()\n");
- switch (token.value)
- {
- case TOKsemicolon:
- error("declaration expected following attribute, not `;`");
- nextToken();
- break;
-
- case TOKeof:
- error("declaration expected following attribute, not EOF");
- break;
-
- case TOKlcurly:
- {
- Loc lookingForElseSave = lookingForElse;
- lookingForElse = Loc();
-
- nextToken();
- a = parseDeclDefs(0, pLastDecl);
- if (token.value != TOKrcurly)
- {
- /* { */
- error("matching `}` expected, not %s", token.toChars());
- }
- else
- nextToken();
- lookingForElse = lookingForElseSave;
- break;
- }
-
- case TOKcolon:
- nextToken();
- a = parseDeclDefs(0, pLastDecl); // grab declarations up to closing curly bracket
- break;
-
- default:
- a = parseDeclDefs(1, pLastDecl, pAttrs);
- break;
- }
- return a;
-}
-
-/**********************************
- * Parse a static assertion.
- * Current token is 'static'.
- */
-
-StaticAssert *Parser::parseStaticAssert()
-{
- Loc loc = token.loc;
- Expression *exp;
- Expression *msg = NULL;
-
- //printf("parseStaticAssert()\n");
- nextToken();
- nextToken();
- check(TOKlparen);
- exp = parseAssignExp();
- if (token.value == TOKcomma)
- {
- nextToken();
- if (token.value != TOKrparen)
- {
- msg = parseAssignExp();
- if (token.value == TOKcomma)
- nextToken();
- }
- }
- check(TOKrparen);
- check(TOKsemicolon);
- return new StaticAssert(loc, exp, msg);
-}
-
-/***********************************
- * Parse typeof(expression).
- * Current token is on the 'typeof'.
- */
-
-TypeQualified *Parser::parseTypeof()
-{
- TypeQualified *t;
- Loc loc = token.loc;
-
- nextToken();
- check(TOKlparen);
- if (token.value == TOKreturn) // typeof(return)
- {
- nextToken();
- t = new TypeReturn(loc);
- }
- else
- {
- Expression *exp = parseExpression(); // typeof(expression)
- t = new TypeTypeof(loc, exp);
- }
- check(TOKrparen);
- return t;
-}
-
-/***********************************
- * Parse __vector(type).
- * Current token is on the '__vector'.
- */
-
-Type *Parser::parseVector()
-{
- nextToken();
- check(TOKlparen);
- Type *tb = parseType();
- check(TOKrparen);
- return new TypeVector(tb);
-}
-
-/***********************************
- * Parse:
- * extern (linkage)
- * extern (C++, namespaces)
- * extern (C++, "namespace", "namespaces", ...)
- * The parser is on the 'extern' token.
- */
-
-LINK Parser::parseLinkage(Identifiers **pidents, CPPMANGLE *pcppmangle, bool *pcppMangleOnly)
-{
- Identifiers *idents = NULL;
- CPPMANGLE cppmangle = CPPMANGLEdefault;
- bool cppMangleOnly = false;
- LINK link = LINKdefault;
- nextToken();
- assert(token.value == TOKlparen);
- nextToken();
- if (token.value == TOKidentifier)
- { Identifier *id = token.ident;
-
- nextToken();
- if (id == Id::Windows)
- link = LINKwindows;
- else if (id == Id::D)
- link = LINKd;
- else if (id == Id::C)
- {
- link = LINKc;
- if (token.value == TOKplusplus)
- {
- link = LINKcpp;
- nextToken();
- if (token.value == TOKcomma) // , namespaces or class or struct
- {
- nextToken();
- if (token.value == TOKclass || token.value == TOKstruct)
- {
- cppmangle = token.value == TOKclass ? CPPMANGLEclass : CPPMANGLEstruct;
- nextToken();
- }
- else if (token.value == TOKstring) // extern(C++, "namespace", "namespaces")
- {
- cppMangleOnly = true;
- idents = new Identifiers();
-
- while (1)
- {
- StringExp *stringExp = (StringExp *)parsePrimaryExp();
- const char *name = stringExp->toPtr();
- if (stringExp->len == 0)
- {
- error("invalid zero length C++ namespace");
- idents = NULL;
- break;
- }
- else if (!Identifier::isValidIdentifier(name))
- {
- error("expected valid identifier for C++ namespace but got `%s`", name);
- idents = NULL;
- break;
- }
- idents->push(Identifier::idPool(name));
- if (token.value == TOKcomma)
- {
- nextToken();
- if (token.value != TOKstring)
- {
- error("string expected following `,` for C++ namespace, not `%s`", token.toChars());
- idents = NULL;
- break;
- }
- }
- else
- break;
- }
- }
- else
- {
- idents = new Identifiers();
- while (1)
- {
- if (token.value == TOKidentifier)
- {
- Identifier *idn = token.ident;
- idents->push(idn);
- nextToken();
- if (token.value == TOKdot)
- {
- nextToken();
- continue;
- }
- }
- else
- {
- error("identifier expected for C++ namespace");
- idents = NULL; // error occurred, invalidate list of elements.
- }
- break;
- }
- }
- }
- }
- }
- else if (id == Id::Objective) // Looking for tokens "Objective-C"
- {
- if (token.value == TOKmin)
- {
- nextToken();
- if (token.ident == Id::C)
- {
- link = LINKobjc;
- nextToken();
- }
- else
- goto LinvalidLinkage;
- }
- else
- goto LinvalidLinkage;
- }
- else if (id == Id::System)
- {
- link = LINKsystem;
- }
- else
- {
- LinvalidLinkage:
- error("valid linkage identifiers are D, C, C++, Objective-C, Windows, System");
- link = LINKd;
- }
- }
- else
- {
- link = LINKd; // default
- }
- check(TOKrparen);
- *pidents = idents;
- *pcppmangle = cppmangle;
- *pcppMangleOnly = cppMangleOnly;
- return link;
-}
-
-/***********************************
- * Parse ident1.ident2.ident3
- *
- * Params:
- * entity = what qualified identifier is expected to resolve into.
- * Used only for better error message
- *
- * Returns:
- * array of identifiers with actual qualified one stored last
- */
-Identifiers *Parser::parseQualifiedIdentifier(const char *entity)
-{
- Identifiers *qualified = NULL;
-
- do
- {
- nextToken();
- if (token.value != TOKidentifier)
- {
- error("%s expected as dot-separated identifiers, got `%s`",
- entity, token.toChars());
- return NULL;
- }
-
- Identifier *id = token.ident;
- if (!qualified)
- qualified = new Identifiers();
- qualified->push(id);
-
- nextToken();
- } while (token.value == TOKdot);
-
- return qualified;
-}
-
-/**************************************
- * Parse a debug conditional
- */
-
-Condition *Parser::parseDebugCondition()
-{
- Condition *c;
-
- if (token.value == TOKlparen)
- {
- nextToken();
- unsigned level = 1;
- Identifier *id = NULL;
-
- if (token.value == TOKidentifier)
- id = token.ident;
- else if (token.value == TOKint32v || token.value == TOKint64v)
- level = (unsigned)token.uns64value;
- else
- error("identifier or integer expected, not %s", token.toChars());
- nextToken();
- check(TOKrparen);
- c = new DebugCondition(mod, level, id);
- }
- else
- c = new DebugCondition(mod, 1, NULL);
- return c;
-
-}
-
-/**************************************
- * Parse a version conditional
- */
-
-Condition *Parser::parseVersionCondition()
-{
- Condition *c;
- unsigned level = 1;
- Identifier *id = NULL;
-
- if (token.value == TOKlparen)
- {
- nextToken();
- /* Allow:
- * version (unittest)
- * version (assert)
- * even though they are keywords
- */
- if (token.value == TOKidentifier)
- id = token.ident;
- else if (token.value == TOKint32v || token.value == TOKint64v)
- level = (unsigned)token.uns64value;
- else if (token.value == TOKunittest)
- id = Identifier::idPool(Token::toChars(TOKunittest));
- else if (token.value == TOKassert)
- id = Identifier::idPool(Token::toChars(TOKassert));
- else
- error("identifier or integer expected, not %s", token.toChars());
- nextToken();
- check(TOKrparen);
-
- }
- else
- error("(condition) expected following version");
- c = new VersionCondition(mod, level, id);
- return c;
-
-}
-
-/***********************************************
- * static if (expression)
- * body
- * else
- * body
- * Current token is 'static'.
- */
-
-Condition *Parser::parseStaticIfCondition()
-{
- Expression *exp;
- Condition *condition;
- Loc loc = token.loc;
-
- nextToken();
- nextToken();
- if (token.value == TOKlparen)
- {
- nextToken();
- exp = parseAssignExp();
- check(TOKrparen);
- }
- else
- {
- error("(expression) expected following static if");
- exp = NULL;
- }
- condition = new StaticIfCondition(loc, exp);
- return condition;
-}
-
-
-/*****************************************
- * Parse a constructor definition:
- * this(parameters) { body }
- * or postblit:
- * this(this) { body }
- * or constructor template:
- * this(templateparameters)(parameters) { body }
- * Current token is 'this'.
- */
-
-Dsymbol *Parser::parseCtor(PrefixAttributes *pAttrs)
-{
- Expressions *udas = NULL;
- Loc loc = token.loc;
- StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
-
- nextToken();
- if (token.value == TOKlparen && peekNext() == TOKthis && peekNext2() == TOKrparen)
- {
- // this(this) { ... }
- nextToken();
- nextToken();
- check(TOKrparen);
-
- stc = parsePostfix(stc, &udas);
- if (stc & STCstatic)
- error(loc, "postblit cannot be static");
-
- PostBlitDeclaration *f = new PostBlitDeclaration(loc, Loc(), stc, Id::postblit);
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
- Dsymbol *s = parseContracts(f);
- if (udas)
- {
- Dsymbols *a = new Dsymbols();
- a->push(f);
- s = new UserAttributeDeclaration(udas, a);
- }
- return s;
- }
-
- /* Look ahead to see if:
- * this(...)(...)
- * which is a constructor template
- */
- TemplateParameters *tpl = NULL;
- if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen)
- {
- tpl = parseTemplateParameterList();
- }
-
- /* Just a regular constructor
- */
- VarArg varargs;
- Parameters *parameters = parseParameters(&varargs);
- stc = parsePostfix(stc, &udas);
- if (varargs != VARARGnone || Parameter::dim(parameters) != 0)
- {
- if (stc & STCstatic)
- error(loc, "constructor cannot be static");
- }
- else if (StorageClass ss = stc & (STCshared | STCstatic)) // this()
- {
- if (ss == STCstatic)
- error(loc, "use `static this()` to declare a static constructor");
- else if (ss == (STCshared | STCstatic))
- error(loc, "use `shared static this()` to declare a shared static constructor");
- }
-
- Expression *constraint = tpl ? parseConstraint() : NULL;
-
- Type *tf = new TypeFunction(ParameterList(parameters, varargs),
- NULL, linkage, stc); // ReturnType -> auto
- tf = tf->addSTC(stc);
-
- CtorDeclaration *f = new CtorDeclaration(loc, Loc(), stc, tf);
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
- Dsymbol *s = parseContracts(f);
- if (udas)
- {
- Dsymbols *a = new Dsymbols();
- a->push(f);
- s = new UserAttributeDeclaration(udas, a);
- }
-
- if (tpl)
- {
- // Wrap a template around it
- Dsymbols *decldefs = new Dsymbols();
- decldefs->push(s);
- s = new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs);
- }
-
- return s;
-}
-
-/*****************************************
- * Parse a destructor definition:
- * ~this() { body }
- * Current token is '~'.
- */
-
-Dsymbol *Parser::parseDtor(PrefixAttributes *pAttrs)
-{
- Expressions *udas = NULL;
- Loc loc = token.loc;
- StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
-
- nextToken();
- check(TOKthis);
- check(TOKlparen);
- check(TOKrparen);
-
- stc = parsePostfix(stc, &udas);
- if (StorageClass ss = stc & (STCshared | STCstatic))
- {
- if (ss == STCstatic)
- error(loc, "use `static ~this()` to declare a static destructor");
- else if (ss == (STCshared | STCstatic))
- error(loc, "use `shared static ~this()` to declare a shared static destructor");
- }
-
- DtorDeclaration *f = new DtorDeclaration(loc, Loc(), stc, Id::dtor);
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
- Dsymbol *s = parseContracts(f);
- if (udas)
- {
- Dsymbols *a = new Dsymbols();
- a->push(f);
- s = new UserAttributeDeclaration(udas, a);
- }
- return s;
-}
-
-/*****************************************
- * Parse a static constructor definition:
- * static this() { body }
- * Current token is 'static'.
- */
-
-Dsymbol *Parser::parseStaticCtor(PrefixAttributes *pAttrs)
-{
- //Expressions *udas = NULL;
- Loc loc = token.loc;
- StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
-
- nextToken();
- nextToken();
- check(TOKlparen);
- check(TOKrparen);
-
- stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
- if (stc & STCshared)
- error(loc, "use `shared static this()` to declare a shared static constructor");
- else if (stc & STCstatic)
- appendStorageClass(stc, STCstatic); // complaint for the redundancy
- else if (StorageClass modStc = stc & STC_TYPECTOR)
- {
- OutBuffer buf;
- stcToBuffer(&buf, modStc);
- error(loc, "static constructor cannot be %s", buf.peekChars());
- }
- stc &= ~(STCstatic | STC_TYPECTOR);
-
- StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, Loc(), stc);
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
- Dsymbol *s = parseContracts(f);
- return s;
-}
-
-/*****************************************
- * Parse a static destructor definition:
- * static ~this() { body }
- * Current token is 'static'.
- */
-
-Dsymbol *Parser::parseStaticDtor(PrefixAttributes *pAttrs)
-{
- Expressions *udas = NULL;
- Loc loc = token.loc;
- StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
-
- nextToken();
- nextToken();
- check(TOKthis);
- check(TOKlparen);
- check(TOKrparen);
-
- stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
- if (stc & STCshared)
- error(loc, "use `shared static ~this()` to declare a shared static destructor");
- else if (stc & STCstatic)
- appendStorageClass(stc, STCstatic); // complaint for the redundancy
- else if (StorageClass modStc = stc & STC_TYPECTOR)
- {
- OutBuffer buf;
- stcToBuffer(&buf, modStc);
- error(loc, "static destructor cannot be %s", buf.peekChars());
- }
- stc &= ~(STCstatic | STC_TYPECTOR);
-
- StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, Loc(), stc);
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
- Dsymbol *s = parseContracts(f);
- if (udas)
- {
- Dsymbols *a = new Dsymbols();
- a->push(f);
- s = new UserAttributeDeclaration(udas, a);
- }
- return s;
-}
-
-/*****************************************
- * Parse a shared static constructor definition:
- * shared static this() { body }
- * Current token is 'shared'.
- */
-
-Dsymbol *Parser::parseSharedStaticCtor(PrefixAttributes *pAttrs)
-{
- //Expressions *udas = NULL;
- Loc loc = token.loc;
- StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
-
- nextToken();
- nextToken();
- nextToken();
- check(TOKlparen);
- check(TOKrparen);
-
- stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
- if (StorageClass ss = stc & (STCshared | STCstatic))
- appendStorageClass(stc, ss); // complaint for the redundancy
- else if (StorageClass modStc = stc & STC_TYPECTOR)
- {
- OutBuffer buf;
- stcToBuffer(&buf, modStc);
- error(loc, "shared static constructor cannot be %s", buf.peekChars());
- }
- stc &= ~(STCstatic | STC_TYPECTOR);
-
- SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, Loc(), stc);
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
- Dsymbol *s = parseContracts(f);
- return s;
-}
-
-/*****************************************
- * Parse a shared static destructor definition:
- * shared static ~this() { body }
- * Current token is 'shared'.
- */
-
-Dsymbol *Parser::parseSharedStaticDtor(PrefixAttributes *pAttrs)
-{
- Expressions *udas = NULL;
- Loc loc = token.loc;
- StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
-
- nextToken();
- nextToken();
- nextToken();
- check(TOKthis);
- check(TOKlparen);
- check(TOKrparen);
-
- stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
- if (StorageClass ss = stc & (STCshared | STCstatic))
- appendStorageClass(stc, ss); // complaint for the redundancy
- else if (StorageClass modStc = stc & STC_TYPECTOR)
- {
- OutBuffer buf;
- stcToBuffer(&buf, modStc);
- error(loc, "shared static destructor cannot be %s", buf.peekChars());
- }
- stc &= ~(STCstatic | STC_TYPECTOR);
-
- SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, Loc(), stc);
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
- Dsymbol *s = parseContracts(f);
- if (udas)
- {
- Dsymbols *a = new Dsymbols();
- a->push(f);
- s = new UserAttributeDeclaration(udas, a);
- }
- return s;
-}
-
-/*****************************************
- * Parse an invariant definition:
- * invariant { statements... }
- * invariant() { statements... }
- * invariant (expression);
- * Current token is 'invariant'.
- */
-
-Dsymbol *Parser::parseInvariant(PrefixAttributes *pAttrs)
-{
- Loc loc = token.loc;
- StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
-
- nextToken();
- if (token.value == TOKlparen) // optional () or invariant (expression);
- {
- nextToken();
- if (token.value != TOKrparen) // invariant (expression);
- {
- Expression *e = parseAssignExp();
- Expression *msg = NULL;
- if (token.value == TOKcomma)
- {
- nextToken();
- if (token.value != TOKrparen)
- {
- msg = parseAssignExp();
- if (token.value == TOKcomma)
- nextToken();
- }
- }
- check(TOKrparen);
- check(TOKsemicolon);
- e = new AssertExp(loc, e, msg);
- ExpStatement *fbody = new ExpStatement(loc, e);
- InvariantDeclaration *f = new InvariantDeclaration(loc, token.loc, stc);
- f->fbody = fbody;
- return f;
- }
- else
- {
- nextToken();
- }
- }
-
- InvariantDeclaration *f = new InvariantDeclaration(loc, Loc(), stc);
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
- f->fbody = parseStatement(PScurly);
- return f;
-}
-
-/*****************************************
- * Parse a unittest definition:
- * unittest { body }
- * Current token is 'unittest'.
- */
-
-Dsymbol *Parser::parseUnitTest(PrefixAttributes *pAttrs)
-{
- Loc loc = token.loc;
- StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
-
- nextToken();
-
- const utf8_t *begPtr = token.ptr + 1; // skip '{'
- const utf8_t *endPtr = NULL;
- Statement *sbody = parseStatement(PScurly, &endPtr);
-
- /** Extract unittest body as a string. Must be done eagerly since memory
- will be released by the lexer before doc gen. */
- char *docline = NULL;
- if (global.params.doDocComments && endPtr > begPtr)
- {
- /* Remove trailing whitespaces */
- for (const utf8_t *p = endPtr - 1;
- begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p)
- {
- endPtr = p;
- }
-
- size_t len = endPtr - begPtr;
- if (len > 0)
- {
- docline = (char *)mem.xmalloc(len + 2);
- memcpy(docline, begPtr, len);
- docline[len ] = '\n'; // Terminate all lines by LF
- docline[len+1] = '\0';
- }
- }
-
- UnitTestDeclaration *f = new UnitTestDeclaration(loc, token.loc, stc, docline);
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
- f->fbody = sbody;
- return f;
-}
-
-/*****************************************
- * Parse a new definition:
- * new(parameters) { body }
- * Current token is 'new'.
- */
-
-Dsymbol *Parser::parseNew(PrefixAttributes *pAttrs)
-{
- Loc loc = token.loc;
- StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
-
- nextToken();
-
- VarArg varargs;
- Parameters *parameters = parseParameters(&varargs);
- NewDeclaration *f = new NewDeclaration(loc, Loc(), stc, parameters, varargs);
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
- Dsymbol *s = parseContracts(f);
- return s;
-}
-
-/*****************************************
- * Parse a delete definition:
- * delete(parameters) { body }
- * Current token is 'delete'.
- */
-
-Dsymbol *Parser::parseDelete(PrefixAttributes *pAttrs)
-{
- Loc loc = token.loc;
- StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
-
- nextToken();
-
- VarArg varargs;
- Parameters *parameters = parseParameters(&varargs);
- if (varargs != VARARGnone)
- error("... not allowed in delete function parameter list");
- DeleteDeclaration *f = new DeleteDeclaration(loc, Loc(), stc, parameters);
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
- Dsymbol *s = parseContracts(f);
- return s;
-}
-
-/**********************************************
- * Parse parameter list.
- */
-
-Parameters *Parser::parseParameters(VarArg *pvarargs, TemplateParameters **tpl)
-{
- Parameters *parameters = new Parameters();
- VarArg varargs = VARARGnone;
- int hasdefault = 0;
-
- check(TOKlparen);
- while (1)
- {
- Identifier *ai = NULL;
- Type *at;
- StorageClass storageClass = 0;
- StorageClass stc;
- Expression *ae;
- Expressions *udas = NULL;
-
- for (;1; nextToken())
- {
- L3:
- switch (token.value)
- {
- case TOKrparen:
- break;
-
- case TOKdotdotdot:
- varargs = VARARGvariadic;
- nextToken();
- break;
-
- case TOKconst:
- if (peek(&token)->value == TOKlparen)
- goto Ldefault;
- stc = STCconst;
- goto L2;
-
- case TOKimmutable:
- if (peek(&token)->value == TOKlparen)
- goto Ldefault;
- stc = STCimmutable;
- goto L2;
-
- case TOKshared:
- if (peek(&token)->value == TOKlparen)
- goto Ldefault;
- stc = STCshared;
- goto L2;
-
- case TOKwild:
- if (peek(&token)->value == TOKlparen)
- goto Ldefault;
- stc = STCwild;
- goto L2;
-
- case TOKat:
- {
- Expressions *exps = NULL;
- StorageClass stc2 = parseAttribute(&exps);
- if (stc2 == STCproperty || stc2 == STCnogc ||
- stc2 == STCdisable || stc2 == STCsafe ||
- stc2 == STCtrusted || stc2 == STCsystem)
- {
- error("`@%s` attribute for function parameter is not supported", token.toChars());
- }
- else
- {
- udas = UserAttributeDeclaration::concat(udas, exps);
- }
- if (token.value == TOKdotdotdot)
- error("variadic parameter cannot have user-defined attributes");
- if (stc2)
- nextToken();
- goto L3;
- // Don't call nextToken again.
- }
-
- case TOKin: stc = STCin; goto L2;
- case TOKout: stc = STCout; goto L2;
- case TOKref: stc = STCref; goto L2;
- case TOKlazy: stc = STClazy; goto L2;
- case TOKscope: stc = STCscope; goto L2;
- case TOKfinal: stc = STCfinal; goto L2;
- case TOKauto: stc = STCauto; goto L2;
- case TOKreturn: stc = STCreturn; goto L2;
- L2:
- storageClass = appendStorageClass(storageClass, stc);
- continue;
-
- default:
- Ldefault:
- { stc = storageClass & (STCin | STCout | STCref | STClazy);
- // if stc is not a power of 2
- if (stc & (stc - 1) &&
- !(stc == (STCin | STCref)))
- error("incompatible parameter storage classes");
- //if ((storageClass & STCscope) && (storageClass & (STCref | STCout)))
- //error("scope cannot be ref or out");
-
- Token *t;
- if (tpl && token.value == TOKidentifier &&
- (t = peek(&token), (t->value == TOKcomma ||
- t->value == TOKrparen ||
- t->value == TOKdotdotdot)))
- {
- Identifier *id = Identifier::generateId("__T");
- Loc loc = token.loc;
- at = new TypeIdentifier(loc, id);
- if (!*tpl)
- *tpl = new TemplateParameters();
- TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
- (*tpl)->push(tp);
-
- ai = token.ident;
- nextToken();
- }
- else
- at = parseType(&ai);
- ae = NULL;
- if (token.value == TOKassign) // = defaultArg
- { nextToken();
- ae = parseDefaultInitExp();
- hasdefault = 1;
- }
- else
- { if (hasdefault)
- error("default argument expected for %s",
- ai ? ai->toChars() : at->toChars());
- }
- Parameter *param = new Parameter(storageClass, at, ai, ae, NULL);
- if (udas)
- {
- Dsymbols *a = new Dsymbols();
- UserAttributeDeclaration *udad = new UserAttributeDeclaration(udas, a);
- param->userAttribDecl = udad;
- }
- if (token.value == TOKat)
- {
- Expressions *exps = NULL;
- StorageClass stc2 = parseAttribute(&exps);
- if (stc2 == STCproperty || stc2 == STCnogc ||
- stc2 == STCdisable || stc2 == STCsafe ||
- stc2 == STCtrusted || stc2 == STCsystem)
- {
- error("`@%s` attribute for function parameter is not supported", token.toChars());
- }
- else
- {
- error("user-defined attributes cannot appear as postfixes", token.toChars());
- }
- if (stc2)
- nextToken();
- }
- if (token.value == TOKdotdotdot)
- { /* This is:
- * at ai ...
- */
-
- if (storageClass & (STCout | STCref))
- error("variadic argument cannot be out or ref");
- varargs = VARARGtypesafe;
- parameters->push(param);
- nextToken();
- break;
- }
- parameters->push(param);
- if (token.value == TOKcomma)
- { nextToken();
- goto L1;
- }
- break;
- }
- }
- break;
- }
- break;
-
- L1: ;
- }
- check(TOKrparen);
- *pvarargs = varargs;
- return parameters;
-}
-
-
-/*************************************
- */
-
-EnumDeclaration *Parser::parseEnum()
-{
- EnumDeclaration *e;
- Identifier *id;
- Type *memtype;
- Loc loc = token.loc;
-
- // printf("Parser::parseEnum()\n");
- nextToken();
- if (token.value == TOKidentifier)
- {
- id = token.ident;
- nextToken();
- }
- else
- id = NULL;
-
- if (token.value == TOKcolon)
- {
- nextToken();
-
- int alt = 0;
- Loc typeLoc = token.loc;
- memtype = parseBasicType();
- memtype = parseDeclarator(memtype, &alt, NULL);
- checkCstyleTypeSyntax(typeLoc, memtype, alt, NULL);
- }
- else
- memtype = NULL;
-
- e = new EnumDeclaration(loc, id, memtype);
- if (token.value == TOKsemicolon && id)
- nextToken();
- else if (token.value == TOKlcurly)
- {
- bool isAnonymousEnum = !id;
-
- //printf("enum definition\n");
- e->members = new Dsymbols();
- nextToken();
- const utf8_t *comment = token.blockComment;
- while (token.value != TOKrcurly)
- {
- /* Can take the following forms...
- * 1. ident
- * 2. ident = value
- * 3. type ident = value
- * ... prefixed by valid attributes
- */
- loc = token.loc;
-
- Type *type = NULL;
- Identifier *ident = NULL;
-
- Expressions *udas = NULL;
- StorageClass stc = STCundefined;
- Expression *deprecationMessage = NULL;
-
- while (token.value != TOKrcurly &&
- token.value != TOKcomma &&
- token.value != TOKassign)
- {
- switch (token.value)
- {
- case TOKat:
- if (StorageClass _stc = parseAttribute(&udas))
- {
- if (_stc == STCdisable)
- stc |= _stc;
- else
- {
- OutBuffer buf;
- stcToBuffer(&buf, _stc);
- error("`%s` is not a valid attribute for enum members", buf.peekChars());
- }
- nextToken();
- }
- break;
- case TOKdeprecated:
- if (StorageClass _stc = parseDeprecatedAttribute(this, &deprecationMessage))
- {
- stc |= _stc;
- nextToken();
- }
- break;
- case TOKidentifier:
- {
- Token *tp = peek(&token);
- if (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly)
- {
- ident = token.ident;
- type = NULL;
- nextToken();
- }
- else
- {
- goto Ldefault;
- }
- break;
- }
- default:
- Ldefault:
- if (isAnonymousEnum)
- {
- type = parseType(&ident, NULL);
- if (type == Type::terror)
- {
- type = NULL;
- nextToken();
- }
- }
- else
- {
- error("`%s` is not a valid attribute for enum members", token.toChars());
- nextToken();
- }
- break;
- }
- }
-
- if (type && type != Type::terror)
- {
- if (!ident)
- error("no identifier for declarator %s", type->toChars());
- if (!isAnonymousEnum)
- error("type only allowed if anonymous enum and no enum type");
- }
-
- Expression *value;
- if (token.value == TOKassign)
- {
- nextToken();
- value = parseAssignExp();
- }
- else
- {
- value = NULL;
- if (type && type != Type::terror && isAnonymousEnum)
- error("if type, there must be an initializer");
- }
-
- UserAttributeDeclaration *uad = NULL;
- if (udas)
- uad = new UserAttributeDeclaration(udas, NULL);
-
- DeprecatedDeclaration *dd = NULL;
- if (deprecationMessage)
- {
- dd = new DeprecatedDeclaration(deprecationMessage, NULL);
- stc |= STCdeprecated;
- }
-
- EnumMember *em = new EnumMember(loc, ident, value, type, stc, uad, dd);
- e->members->push(em);
-
- if (token.value == TOKrcurly)
- ;
- else
- {
- addComment(em, comment);
- comment = NULL;
- check(TOKcomma);
- }
- addComment(em, comment);
- comment = token.blockComment;
-
- if (token.value == TOKeof)
- {
- error("premature end of file");
- break;
- }
- }
- nextToken();
- }
- else
- error("enum declaration is invalid");
-
- //printf("-parseEnum() %s\n", e->toChars());
- return e;
-}
-
-/********************************
- * Parse struct, union, interface, class.
- */
-
-Dsymbol *Parser::parseAggregate()
-{
- AggregateDeclaration *a = NULL;
- int anon = 0;
- Identifier *id;
- TemplateParameters *tpl = NULL;
- Expression *constraint = NULL;
- Loc loc = token.loc;
- TOK tok = token.value;
-
- //printf("Parser::parseAggregate()\n");
- nextToken();
- if (token.value != TOKidentifier)
- {
- id = NULL;
- }
- else
- {
- id = token.ident;
- nextToken();
-
- if (token.value == TOKlparen)
- {
- // Class template declaration.
- // Gather template parameter list
- tpl = parseTemplateParameterList();
- constraint = parseConstraint();
- }
- }
-
- switch (tok)
- {
- case TOKclass:
- case TOKinterface:
- {
- if (!id)
- error(loc, "anonymous classes not allowed");
-
- // Collect base class(es)
- BaseClasses *baseclasses = NULL;
- if (token.value == TOKcolon)
- {
- nextToken();
- baseclasses = parseBaseClasses();
-
- if (tpl)
- {
- Expression *tempCons = parseConstraint();
- if (tempCons)
- {
- if (constraint)
- error("members expected");
- else
- constraint = tempCons;
- }
- }
-
- if (token.value != TOKlcurly)
- error("members expected");
- }
-
- if (tok == TOKclass)
- {
- bool inObject = md && !md->packages && md->id == Id::object;
- a = new ClassDeclaration(loc, id, baseclasses, NULL, inObject);
- }
- else
- a = new InterfaceDeclaration(loc, id, baseclasses);
- break;
- }
-
- case TOKstruct:
- if (id)
- {
- bool inObject = md && !md->packages && md->id == Id::object;
- a = new StructDeclaration(loc, id, inObject);
- }
- else
- anon = 1;
- break;
-
- case TOKunion:
- if (id)
- a = new UnionDeclaration(loc, id);
- else
- anon = 2;
- break;
-
- default:
- assert(0);
- break;
- }
- if (a && token.value == TOKsemicolon)
- {
- nextToken();
- }
- else if (token.value == TOKlcurly)
- {
- const Loc lookingForElseSave = lookingForElse;
- lookingForElse = Loc();
- //printf("aggregate definition\n");
- nextToken();
- Dsymbols *decl = parseDeclDefs(0);
- lookingForElse = lookingForElseSave;
- if (token.value != TOKrcurly)
- error("} expected following members in %s declaration at %s",
- Token::toChars(tok), loc.toChars());
- nextToken();
- if (anon)
- {
- /* Anonymous structs/unions are more like attributes.
- */
- return new AnonDeclaration(loc, anon == 2, decl);
- }
- else
- a->members = decl;
- }
- else
- {
- error("{ } expected following %s declaration", Token::toChars(tok));
- a = new StructDeclaration(loc, NULL, false);
- }
-
- if (tpl)
- {
- // Wrap a template around the aggregate declaration
- Dsymbols *decldefs = new Dsymbols();
- decldefs->push(a);
- TemplateDeclaration *tempdecl =
- new TemplateDeclaration(loc, id, tpl, constraint, decldefs);
- return tempdecl;
- }
-
- return a;
-}
-
-/*******************************************
- */
-
-BaseClasses *Parser::parseBaseClasses()
-{
- BaseClasses *baseclasses = new BaseClasses();
-
- for (; 1; nextToken())
- {
- bool prot = false;
- Prot protection = Prot(Prot::public_);
- switch (token.value)
- {
- case TOKprivate:
- prot = true;
- protection = Prot(Prot::private_);
- nextToken();
- break;
- case TOKpackage:
- prot = true;
- protection = Prot(Prot::package_);
- nextToken();
- break;
- case TOKprotected:
- prot = true;
- protection = Prot(Prot::protected_);
- nextToken();
- break;
- case TOKpublic:
- prot = true;
- protection = Prot(Prot::public_);
- nextToken();
- break;
- default: break;
- }
- if (prot)
- error("use of base class protection is no longer supported");
- BaseClass *b = new BaseClass(parseBasicType());
- baseclasses->push(b);
- if (token.value != TOKcomma)
- break;
- }
- return baseclasses;
-}
-
-/**************************************
- * Parse constraint.
- * Constraint is of the form:
- * if ( ConstraintExpression )
- */
-
-Expression *Parser::parseConstraint()
-{ Expression *e = NULL;
-
- if (token.value == TOKif)
- {
- nextToken(); // skip over 'if'
- check(TOKlparen);
- e = parseExpression();
- check(TOKrparen);
- }
- return e;
-}
-
-/**************************************
- * Parse a TemplateDeclaration.
- */
-
-TemplateDeclaration *Parser::parseTemplateDeclaration(bool ismixin)
-{
- TemplateDeclaration *tempdecl;
- Identifier *id;
- TemplateParameters *tpl;
- Dsymbols *decldefs;
- Expression *constraint = NULL;
- Loc loc = token.loc;
-
- nextToken();
- if (token.value != TOKidentifier)
- {
- error("identifier expected following template");
- goto Lerr;
- }
- id = token.ident;
- nextToken();
- tpl = parseTemplateParameterList();
- if (!tpl)
- goto Lerr;
-
- constraint = parseConstraint();
-
- if (token.value != TOKlcurly)
- {
- error("members of template declaration expected");
- goto Lerr;
- }
- else
- decldefs = parseBlock(NULL);
-
- tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
- return tempdecl;
-
-Lerr:
- return NULL;
-}
-
-/******************************************
- * Parse template parameter list.
- * Input:
- * flag 0: parsing "( list )"
- * 1: parsing non-empty "list )"
- */
-
-TemplateParameters *Parser::parseTemplateParameterList(int flag)
-{
- TemplateParameters *tpl = new TemplateParameters();
-
- if (!flag && token.value != TOKlparen)
- { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
- goto Lerr;
- }
- nextToken();
-
- // Get array of TemplateParameters
- if (flag || token.value != TOKrparen)
- {
- int isvariadic = 0;
- while (token.value != TOKrparen)
- {
- TemplateParameter *tp;
- Loc loc;
- Identifier *tp_ident = NULL;
- Type *tp_spectype = NULL;
- Type *tp_valtype = NULL;
- Type *tp_defaulttype = NULL;
- Expression *tp_specvalue = NULL;
- Expression *tp_defaultvalue = NULL;
- Token *t;
-
- // Get TemplateParameter
-
- // First, look ahead to see if it is a TypeParameter or a ValueParameter
- t = peek(&token);
- if (token.value == TOKalias)
- { // AliasParameter
- nextToken();
- loc = token.loc; // todo
- Type *spectype = NULL;
- if (isDeclaration(&token, 2, TOKreserved, NULL))
- {
- spectype = parseType(&tp_ident);
- }
- else
- {
- if (token.value != TOKidentifier)
- {
- error("identifier expected for template alias parameter");
- goto Lerr;
- }
- tp_ident = token.ident;
- nextToken();
- }
- RootObject *spec = NULL;
- if (token.value == TOKcolon) // : Type
- {
- nextToken();
- if (isDeclaration(&token, 0, TOKreserved, NULL))
- spec = parseType();
- else
- spec = parseCondExp();
- }
- RootObject *def = NULL;
- if (token.value == TOKassign) // = Type
- {
- nextToken();
- if (isDeclaration(&token, 0, TOKreserved, NULL))
- def = parseType();
- else
- def = parseCondExp();
- }
- tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
- }
- else if (t->value == TOKcolon || t->value == TOKassign ||
- t->value == TOKcomma || t->value == TOKrparen)
- {
- // TypeParameter
- if (token.value != TOKidentifier)
- {
- error("identifier expected for template type parameter");
- goto Lerr;
- }
- loc = token.loc;
- tp_ident = token.ident;
- nextToken();
- if (token.value == TOKcolon) // : Type
- {
- nextToken();
- tp_spectype = parseType();
- }
- if (token.value == TOKassign) // = Type
- {
- nextToken();
- tp_defaulttype = parseType();
- }
- tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
- }
- else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
- {
- // ident...
- if (isvariadic)
- error("variadic template parameter must be last");
- isvariadic = 1;
- loc = token.loc;
- tp_ident = token.ident;
- nextToken();
- nextToken();
- tp = new TemplateTupleParameter(loc, tp_ident);
- }
- else if (token.value == TOKthis)
- {
- // ThisParameter
- nextToken();
- if (token.value != TOKidentifier)
- {
- error("identifier expected for template this parameter");
- goto Lerr;
- }
- loc = token.loc;
- tp_ident = token.ident;
- nextToken();
- if (token.value == TOKcolon) // : Type
- {
- nextToken();
- tp_spectype = parseType();
- }
- if (token.value == TOKassign) // = Type
- {
- nextToken();
- tp_defaulttype = parseType();
- }
- tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
- }
- else
- {
- // ValueParameter
- loc = token.loc; // todo
- tp_valtype = parseType(&tp_ident);
- if (!tp_ident)
- {
- error("identifier expected for template value parameter");
- tp_ident = Identifier::idPool("error");
- }
- if (token.value == TOKcolon) // : CondExpression
- {
- nextToken();
- tp_specvalue = parseCondExp();
- }
- if (token.value == TOKassign) // = CondExpression
- {
- nextToken();
- tp_defaultvalue = parseDefaultInitExp();
- }
- tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
- }
- tpl->push(tp);
- if (token.value != TOKcomma)
- break;
- nextToken();
- }
- }
- check(TOKrparen);
-Lerr:
- return tpl;
-}
-
-/******************************************
- * Parse template mixin.
- * mixin Foo;
- * mixin Foo!(args);
- * mixin a.b.c!(args).Foo!(args);
- * mixin Foo!(args) identifier;
- * mixin typeof(expr).identifier!(args);
- */
-
-Dsymbol *Parser::parseMixin()
-{
- TemplateMixin *tm;
- Identifier *id;
- Objects *tiargs;
-
- //printf("parseMixin()\n");
- Loc locMixin = token.loc;
- nextToken(); // skip 'mixin'
-
- Loc loc = token.loc;
- TypeQualified *tqual = NULL;
- if (token.value == TOKdot)
- {
- id = Id::empty;
- }
- else
- {
- if (token.value == TOKtypeof)
- {
- tqual = parseTypeof();
- check(TOKdot);
- }
- if (token.value != TOKidentifier)
- {
- error("identifier expected, not %s", token.toChars());
- id = Id::empty;
- }
- else
- id = token.ident;
- nextToken();
- }
-
- while (1)
- {
- tiargs = NULL;
- if (token.value == TOKnot)
- {
- tiargs = parseTemplateArguments();
- }
-
- if (tiargs && token.value == TOKdot)
- {
- TemplateInstance *tempinst = new TemplateInstance(loc, id);
- tempinst->tiargs = tiargs;
- if (!tqual)
- tqual = new TypeInstance(loc, tempinst);
- else
- tqual->addInst(tempinst);
- tiargs = NULL;
- }
- else
- {
- if (!tqual)
- tqual = new TypeIdentifier(loc, id);
- else
- tqual->addIdent(id);
- }
-
- if (token.value != TOKdot)
- break;
-
- nextToken();
- if (token.value != TOKidentifier)
- {
- error("identifier expected following `.` instead of `%s`", token.toChars());
- break;
- }
- loc = token.loc;
- id = token.ident;
- nextToken();
- }
-
- if (token.value == TOKidentifier)
- {
- id = token.ident;
- nextToken();
- }
- else
- id = NULL;
-
- tm = new TemplateMixin(locMixin, id, tqual, tiargs);
- if (token.value != TOKsemicolon)
- error("`;` expected after mixin");
- nextToken();
-
- return tm;
-}
-
-/******************************************
- * Parse template arguments.
- * Input:
- * current token is opening '!'
- * Output:
- * current token is one after closing ')'
- */
-
-Objects *Parser::parseTemplateArguments()
-{
- Objects *tiargs;
-
- nextToken();
- if (token.value == TOKlparen)
- {
- // ident!(template_arguments)
- tiargs = parseTemplateArgumentList();
- }
- else
- {
- // ident!template_argument
- tiargs = parseTemplateSingleArgument();
- }
- if (token.value == TOKnot)
- {
- TOK tok = peekNext();
- if (tok != TOKis && tok != TOKin)
- {
- error("multiple ! arguments are not allowed");
- Lagain:
- nextToken();
- if (token.value == TOKlparen)
- parseTemplateArgumentList();
- else
- parseTemplateSingleArgument();
- if (token.value == TOKnot && (tok = peekNext()) != TOKis && tok != TOKin)
- goto Lagain;
- }
- }
- return tiargs;
-}
-
-/***************************************
- * Parse a Type or an Expression
- * Returns:
- * RootObject representing the AST
- */
-RootObject *Parser::parseTypeOrAssignExp(TOK endtoken)
-{
- return isDeclaration(&token, 0, endtoken, NULL)
- ? (RootObject *)parseType() // argument is a type
- : (RootObject *)parseAssignExp(); // argument is an expression
-}
-
-/******************************************
- * Parse template argument list.
- * Input:
- * current token is opening '(',
- * or ',' for __traits
- * Output:
- * current token is one after closing ')'
- */
-
-Objects *Parser::parseTemplateArgumentList()
-{
- //printf("Parser::parseTemplateArgumentList()\n");
- Objects *tiargs = new Objects();
- TOK endtok = TOKrparen;
- assert(token.value == TOKlparen || token.value == TOKcomma);
- nextToken();
-
- // Get TemplateArgumentList
- while (token.value != endtok)
- {
- tiargs->push(parseTypeOrAssignExp());
- if (token.value != TOKcomma)
- break;
- nextToken();
- }
- check(endtok, "template argument list");
- return tiargs;
-}
-
-/*****************************
- * Parse single template argument, to support the syntax:
- * foo!arg
- * Input:
- * current token is the arg
- */
-
-Objects *Parser::parseTemplateSingleArgument()
-{
- //printf("parseTemplateSingleArgument()\n");
- Objects *tiargs = new Objects();
- Type *ta;
- switch (token.value)
- {
- case TOKidentifier:
- ta = new TypeIdentifier(token.loc, token.ident);
- goto LabelX;
-
- case TOKvector:
- ta = parseVector();
- goto LabelX;
-
- case TOKvoid: ta = Type::tvoid; goto LabelX;
- case TOKint8: ta = Type::tint8; goto LabelX;
- case TOKuns8: ta = Type::tuns8; goto LabelX;
- case TOKint16: ta = Type::tint16; goto LabelX;
- case TOKuns16: ta = Type::tuns16; goto LabelX;
- case TOKint32: ta = Type::tint32; goto LabelX;
- case TOKuns32: ta = Type::tuns32; goto LabelX;
- case TOKint64: ta = Type::tint64; goto LabelX;
- case TOKuns64: ta = Type::tuns64; goto LabelX;
- case TOKint128: ta = Type::tint128; goto LabelX;
- case TOKuns128: ta = Type::tuns128; goto LabelX;
- case TOKfloat32: ta = Type::tfloat32; goto LabelX;
- case TOKfloat64: ta = Type::tfloat64; goto LabelX;
- case TOKfloat80: ta = Type::tfloat80; goto LabelX;
- case TOKimaginary32: ta = Type::timaginary32; goto LabelX;
- case TOKimaginary64: ta = Type::timaginary64; goto LabelX;
- case TOKimaginary80: ta = Type::timaginary80; goto LabelX;
- case TOKcomplex32: ta = Type::tcomplex32; goto LabelX;
- case TOKcomplex64: ta = Type::tcomplex64; goto LabelX;
- case TOKcomplex80: ta = Type::tcomplex80; goto LabelX;
- case TOKbool: ta = Type::tbool; goto LabelX;
- case TOKchar: ta = Type::tchar; goto LabelX;
- case TOKwchar: ta = Type::twchar; goto LabelX;
- case TOKdchar: ta = Type::tdchar; goto LabelX;
- LabelX:
- tiargs->push(ta);
- nextToken();
- break;
-
- case TOKint32v:
- case TOKuns32v:
- case TOKint64v:
- case TOKuns64v:
- case TOKint128v:
- case TOKuns128v:
- case TOKfloat32v:
- case TOKfloat64v:
- case TOKfloat80v:
- case TOKimaginary32v:
- case TOKimaginary64v:
- case TOKimaginary80v:
- case TOKnull:
- case TOKtrue:
- case TOKfalse:
- case TOKcharv:
- case TOKwcharv:
- case TOKdcharv:
- case TOKstring:
- case TOKxstring:
- case TOKfile:
- case TOKfilefullpath:
- case TOKline:
- case TOKmodulestring:
- case TOKfuncstring:
- case TOKprettyfunc:
- case TOKthis:
- { // Template argument is an expression
- Expression *ea = parsePrimaryExp();
- tiargs->push(ea);
- break;
- }
-
- default:
- error("template argument expected following !");
- break;
- }
- return tiargs;
-}
-
-Dsymbols *Parser::parseImport()
-{
- Dsymbols *decldefs = new Dsymbols();
- Identifier *aliasid = NULL;
-
- int isstatic = token.value == TOKstatic;
- if (isstatic)
- nextToken();
-
- //printf("Parser::parseImport()\n");
- do
- {
- L1:
- nextToken();
- if (token.value != TOKidentifier)
- {
- error("identifier expected following import");
- break;
- }
-
- Loc loc = token.loc;
- Identifier *id = token.ident;
- Identifiers *a = NULL;
- nextToken();
- if (!aliasid && token.value == TOKassign)
- {
- aliasid = id;
- goto L1;
- }
- while (token.value == TOKdot)
- {
- if (!a)
- a = new Identifiers();
- a->push(id);
- nextToken();
- if (token.value != TOKidentifier)
- {
- error("identifier expected following package");
- break;
- }
- id = token.ident;
- nextToken();
- }
-
- Import *s = new Import(loc, a, id, aliasid, isstatic);
- decldefs->push(s);
-
- /* Look for
- * : alias=name, alias=name;
- * syntax.
- */
- if (token.value == TOKcolon)
- {
- do
- {
- nextToken();
- if (token.value != TOKidentifier)
- {
- error("identifier expected following :");
- break;
- }
- Identifier *alias = token.ident;
- Identifier *name;
- nextToken();
- if (token.value == TOKassign)
- {
- nextToken();
- if (token.value != TOKidentifier)
- {
- error("identifier expected following %s=", alias->toChars());
- break;
- }
- name = token.ident;
- nextToken();
- }
- else
- {
- name = alias;
- alias = NULL;
- }
- s->addAlias(name, alias);
- } while (token.value == TOKcomma);
- break; // no comma-separated imports of this form
- }
-
- aliasid = NULL;
- } while (token.value == TOKcomma);
-
- if (token.value == TOKsemicolon)
- nextToken();
- else
- {
- error("`;` expected");
- nextToken();
- }
-
- return decldefs;
-}
-
-Type *Parser::parseType(Identifier **pident, TemplateParameters **ptpl)
-{
- /* Take care of the storage class prefixes that
- * serve as type attributes:
- * const type
- * immutable type
- * shared type
- * inout type
- * inout const type
- * shared const type
- * shared inout type
- * shared inout const type
- */
- StorageClass stc = 0;
- while (1)
- {
- switch (token.value)
- {
- case TOKconst:
- if (peekNext() == TOKlparen)
- break; // const as type constructor
- stc |= STCconst; // const as storage class
- nextToken();
- continue;
-
- case TOKimmutable:
- if (peekNext() == TOKlparen)
- break;
- stc |= STCimmutable;
- nextToken();
- continue;
-
- case TOKshared:
- if (peekNext() == TOKlparen)
- break;
- stc |= STCshared;
- nextToken();
- continue;
-
- case TOKwild:
- if (peekNext() == TOKlparen)
- break;
- stc |= STCwild;
- nextToken();
- continue;
-
- default:
- break;
- }
- break;
- }
-
- Loc typeLoc = token.loc;
-
- Type *t;
- t = parseBasicType();
-
- int alt = 0;
- t = parseDeclarator(t, &alt, pident, ptpl);
- checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : NULL);
-
- t = t->addSTC(stc);
- return t;
-}
-
-Type *Parser::parseBasicType(bool dontLookDotIdents)
-{
- Type *t;
- Loc loc;
- Identifier *id;
-
- //printf("parseBasicType()\n");
- switch (token.value)
- {
- case TOKvoid: t = Type::tvoid; goto LabelX;
- case TOKint8: t = Type::tint8; goto LabelX;
- case TOKuns8: t = Type::tuns8; goto LabelX;
- case TOKint16: t = Type::tint16; goto LabelX;
- case TOKuns16: t = Type::tuns16; goto LabelX;
- case TOKint32: t = Type::tint32; goto LabelX;
- case TOKuns32: t = Type::tuns32; goto LabelX;
- case TOKint64:
- t = Type::tint64;
- nextToken();
- if (token.value == TOKint64) // if `long long`
- {
- error("use `long` for a 64 bit integer instead of `long long`");
- nextToken();
- }
- else if (token.value == TOKfloat64) // if `long double`
- {
- error("use `real` instead of `long double`");
- t = Type::tfloat80;
- nextToken();
-
- }
- break;
-
- case TOKuns64: t = Type::tuns64; goto LabelX;
- case TOKint128: t = Type::tint128; goto LabelX;
- case TOKuns128: t = Type::tuns128; goto LabelX;
- case TOKfloat32: t = Type::tfloat32; goto LabelX;
- case TOKfloat64: t = Type::tfloat64; goto LabelX;
- case TOKfloat80: t = Type::tfloat80; goto LabelX;
- case TOKimaginary32: t = Type::timaginary32; goto LabelX;
- case TOKimaginary64: t = Type::timaginary64; goto LabelX;
- case TOKimaginary80: t = Type::timaginary80; goto LabelX;
- case TOKcomplex32: t = Type::tcomplex32; goto LabelX;
- case TOKcomplex64: t = Type::tcomplex64; goto LabelX;
- case TOKcomplex80: t = Type::tcomplex80; goto LabelX;
- case TOKbool: t = Type::tbool; goto LabelX;
- case TOKchar: t = Type::tchar; goto LabelX;
- case TOKwchar: t = Type::twchar; goto LabelX;
- case TOKdchar: t = Type::tdchar; goto LabelX;
- LabelX:
- nextToken();
- break;
-
- case TOKthis:
- case TOKsuper:
- case TOKidentifier:
- loc = token.loc;
- id = token.ident;
- nextToken();
- if (token.value == TOKnot)
- {
- // ident!(template_arguments)
- TemplateInstance *tempinst = new TemplateInstance(loc, id);
- tempinst->tiargs = parseTemplateArguments();
- t = parseBasicTypeStartingAt(new TypeInstance(loc, tempinst), dontLookDotIdents);
- }
- else
- {
- t = parseBasicTypeStartingAt(new TypeIdentifier(loc, id), dontLookDotIdents);
- }
- break;
-
- case TOKmixin:
- // https://dlang.org/spec/expression.html#mixin_types
- loc = token.loc;
- nextToken();
- if (token.value != TOKlparen)
- error("found `%s` when expecting `%s` following %s", token.toChars(), Token::toChars(TOKlparen), "`mixin`");
- t = new TypeMixin(loc, parseArguments());
- break;
-
- case TOKdot:
- // Leading . as in .foo
- t = parseBasicTypeStartingAt(new TypeIdentifier(token.loc, Id::empty), dontLookDotIdents);
- break;
-
- case TOKtypeof:
- // typeof(expression)
- t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents);
- break;
-
- case TOKvector:
- t = parseVector();
- break;
-
- case TOKtraits:
- if (TraitsExp *te = (TraitsExp *) parsePrimaryExp())
- {
- if (te->ident && te->args)
- {
- t = new TypeTraits(token.loc, te);
- break;
- }
- }
- t = new TypeError();
- break;
-
- case TOKconst:
- // const(type)
- nextToken();
- check(TOKlparen);
- t = parseType()->addSTC(STCconst);
- check(TOKrparen);
- break;
-
- case TOKimmutable:
- // immutable(type)
- nextToken();
- check(TOKlparen);
- t = parseType()->addSTC(STCimmutable);
- check(TOKrparen);
- break;
-
- case TOKshared:
- // shared(type)
- nextToken();
- check(TOKlparen);
- t = parseType()->addSTC(STCshared);
- check(TOKrparen);
- break;
-
- case TOKwild:
- // wild(type)
- nextToken();
- check(TOKlparen);
- t = parseType()->addSTC(STCwild);
- check(TOKrparen);
- break;
-
- default:
- error("basic type expected, not %s", token.toChars());
- t = Type::terror;
- break;
- }
- return t;
-}
-
-Type *Parser::parseBasicTypeStartingAt(TypeQualified *tid, bool dontLookDotIdents)
-{
- Type *maybeArray = NULL;
- // See https://issues.dlang.org/show_bug.cgi?id=1215
- // A basic type can look like MyType (typical case), but also:
- // MyType.T -> A type
- // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
- // MyType[expr].T -> A type.
- // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type
- // (iif MyType[expr].T is a Ttuple)
- while (1)
- {
- switch (token.value)
- {
- case TOKdot:
- {
- nextToken();
- if (token.value != TOKidentifier)
- {
- error("identifier expected following `.` instead of `%s`", token.toChars());
- break;
- }
- if (maybeArray)
- {
- // This is actually a TypeTuple index, not an {a/s}array.
- // We need to have a while loop to unwind all index taking:
- // T[e1][e2].U -> T, addIndex(e1), addIndex(e2)
- Objects dimStack;
- Type *t = maybeArray;
- while (true)
- {
- if (t->ty == Tsarray)
- {
- // The index expression is an Expression.
- TypeSArray *a = (TypeSArray *)t;
- dimStack.push(a->dim->syntaxCopy());
- t = a->next->syntaxCopy();
- }
- else if (t->ty == Taarray)
- {
- // The index expression is a Type. It will be interpreted as an expression at semantic time.
- TypeAArray *a = (TypeAArray *)t;
- dimStack.push(a->index->syntaxCopy());
- t = a->next->syntaxCopy();
- }
- else
- {
- break;
- }
- }
- assert(dimStack.length > 0);
- // We're good. Replay indices in the reverse order.
- tid = (TypeQualified *)t;
- while (dimStack.length)
- {
- tid->addIndex(dimStack.pop());
- }
- maybeArray = NULL;
- }
- Loc loc = token.loc;
- Identifier *id = token.ident;
- nextToken();
- if (token.value == TOKnot)
- {
- TemplateInstance *tempinst = new TemplateInstance(loc, id);
- tempinst->tiargs = parseTemplateArguments();
- tid->addInst(tempinst);
- }
- else
- tid->addIdent(id);
- continue;
- }
- case TOKlbracket:
- {
- if (dontLookDotIdents) // workaround for Bugzilla 14911
- goto Lend;
-
- nextToken();
- Type *t = maybeArray ? maybeArray : (Type *)tid;
- if (token.value == TOKrbracket)
- {
- // It's a dynamic array, and we're done:
- // T[].U does not make sense.
- t = new TypeDArray(t);
- nextToken();
- return t;
- }
- else if (isDeclaration(&token, 0, TOKrbracket, NULL))
- {
- // This can be one of two things:
- // 1 - an associative array declaration, T[type]
- // 2 - an associative array declaration, T[expr]
- // These can only be disambiguated later.
- Type *index = parseType(); // [ type ]
- maybeArray = new TypeAArray(t, index);
- check(TOKrbracket);
- }
- else
- {
- // This can be one of three things:
- // 1 - an static array declaration, T[expr]
- // 2 - a slice, T[expr .. expr]
- // 3 - a template parameter pack index expression, T[expr].U
- // 1 and 3 can only be disambiguated later.
- //printf("it's type[expression]\n");
- inBrackets++;
- Expression *e = parseAssignExp(); // [ expression ]
- if (token.value == TOKslice)
- {
- // It's a slice, and we're done.
- nextToken();
- Expression *e2 = parseAssignExp(); // [ exp .. exp ]
- t = new TypeSlice(t, e, e2);
- inBrackets--;
- check(TOKrbracket);
- return t;
- }
- else
- {
- maybeArray = new TypeSArray(t, e);
- inBrackets--;
- check(TOKrbracket);
- continue;
- }
- }
- break;
- }
- default:
- goto Lend;
- }
- }
-Lend:
- return maybeArray ? maybeArray : (Type *)tid;
-}
-
-/******************************************
- * Parse things that follow the initial type t.
- * t *
- * t []
- * t [type]
- * t [expression]
- * t [expression .. expression]
- * t function
- * t delegate
- */
-
-Type *Parser::parseBasicType2(Type *t)
-{
- //printf("parseBasicType2()\n");
- while (1)
- {
- switch (token.value)
- {
- case TOKmul:
- t = new TypePointer(t);
- nextToken();
- continue;
-
- case TOKlbracket:
- // Handle []. Make sure things like
- // int[3][1] a;
- // is (array[1] of array[3] of int)
- nextToken();
- if (token.value == TOKrbracket)
- {
- t = new TypeDArray(t); // []
- nextToken();
- }
- else if (isDeclaration(&token, 0, TOKrbracket, NULL))
- {
- // It's an associative array declaration
- //printf("it's an associative array\n");
- Type *index = parseType(); // [ type ]
- t = new TypeAArray(t, index);
- check(TOKrbracket);
- }
- else
- {
- //printf("it's type[expression]\n");
- inBrackets++;
- Expression *e = parseAssignExp(); // [ expression ]
- if (token.value == TOKslice)
- {
- nextToken();
- Expression *e2 = parseAssignExp(); // [ exp .. exp ]
- t = new TypeSlice(t, e, e2);
- }
- else
- {
- t = new TypeSArray(t,e);
- }
- inBrackets--;
- check(TOKrbracket);
- }
- continue;
-
- case TOKdelegate:
- case TOKfunction:
- {
- // Handle delegate declaration:
- // t delegate(parameter list) nothrow pure
- // t function(parameter list) nothrow pure
- TOK save = token.value;
- nextToken();
-
- VarArg varargs;
- Parameters *parameters = parseParameters(&varargs);
-
- StorageClass stc = parsePostfix(STCundefined, NULL);
- TypeFunction *tf = new TypeFunction(ParameterList(parameters, varargs),
- t, linkage, stc);
- if (stc & (STCconst | STCimmutable | STCshared | STCwild | STCreturn))
- {
- if (save == TOKfunction)
- error("const/immutable/shared/inout/return attributes are only valid for non-static member functions");
- else
- tf = (TypeFunction *)tf->addSTC(stc);
- }
-
- if (save == TOKdelegate)
- t = new TypeDelegate(tf);
- else
- t = new TypePointer(tf); // pointer to function
- continue;
- }
-
- default:
- return t;
- }
- assert(0);
- }
- assert(0);
- return NULL;
-}
-
-Type *Parser::parseDeclarator(Type *t, int *palt, Identifier **pident,
- TemplateParameters **tpl, StorageClass storageClass, int *pdisable, Expressions **pudas)
-{
- //printf("parseDeclarator(tpl = %p)\n", tpl);
- t = parseBasicType2(t);
-
- Type *ts;
- switch (token.value)
- {
- case TOKidentifier:
- if (pident)
- *pident = token.ident;
- else
- error("unexpected identifier `%s` in declarator", token.ident->toChars());
- ts = t;
- nextToken();
- break;
-
- case TOKlparen:
- {
- // like: T (*fp)();
- // like: T ((*fp))();
- if (peekNext() == TOKmul ||
- peekNext() == TOKlparen)
- {
- /* Parse things with parentheses around the identifier, like:
- * int (*ident[3])[]
- * although the D style would be:
- * int[]*[3] ident
- */
- *palt |= 1;
- nextToken();
- ts = parseDeclarator(t, palt, pident);
- check(TOKrparen);
- break;
- }
- ts = t;
-
- Token *peekt = &token;
- /* Completely disallow C-style things like:
- * T (a);
- * Improve error messages for the common bug of a missing return type
- * by looking to see if (a) looks like a parameter list.
- */
- if (isParameters(&peekt))
- {
- error("function declaration without return type. (Note that constructors are always named `this`)");
- }
- else
- error("unexpected ( in declarator");
- break;
- }
-
- default:
- ts = t;
- break;
- }
-
- // parse DeclaratorSuffixes
- while (1)
- {
- switch (token.value)
- {
-#if CARRAYDECL
- /* Support C style array syntax:
- * int ident[]
- * as opposed to D-style:
- * int[] ident
- */
- case TOKlbracket:
- {
- // This is the old C-style post [] syntax.
- TypeNext *ta;
- nextToken();
- if (token.value == TOKrbracket)
- {
- // It's a dynamic array
- ta = new TypeDArray(t); // []
- nextToken();
- *palt |= 2;
- }
- else if (isDeclaration(&token, 0, TOKrbracket, NULL))
- {
- // It's an associative array
- //printf("it's an associative array\n");
- Type *index = parseType(); // [ type ]
- check(TOKrbracket);
- ta = new TypeAArray(t, index);
- *palt |= 2;
- }
- else
- {
- //printf("It's a static array\n");
- Expression *e = parseAssignExp(); // [ expression ]
- ta = new TypeSArray(t, e);
- check(TOKrbracket);
- *palt |= 2;
- }
-
- /* Insert ta into
- * ts -> ... -> t
- * so that
- * ts -> ... -> ta -> t
- */
- Type **pt;
- for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next)
- ;
- *pt = ta;
- continue;
- }
-#endif
- case TOKlparen:
- {
- if (tpl)
- {
- Token *tk = peekPastParen(&token);
- if (tk->value == TOKlparen)
- {
- /* Look ahead to see if this is (...)(...),
- * i.e. a function template declaration
- */
- //printf("function template declaration\n");
-
- // Gather template parameter list
- *tpl = parseTemplateParameterList();
- }
- else if (tk->value == TOKassign)
- {
- /* or (...) =,
- * i.e. a variable template declaration
- */
- //printf("variable template declaration\n");
- *tpl = parseTemplateParameterList();
- break;
- }
- }
-
- VarArg varargs;
- Parameters *parameters = parseParameters(&varargs);
-
- /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
- */
- StorageClass stc = parsePostfix(storageClass, pudas);
- // merge prefix storage classes
- Type *tf = new TypeFunction(ParameterList(parameters, varargs),
- t, linkage, stc);
- tf = tf->addSTC(stc);
- if (pdisable)
- *pdisable = stc & STCdisable ? 1 : 0;
-
- /* Insert tf into
- * ts -> ... -> t
- * so that
- * ts -> ... -> tf -> t
- */
- Type **pt;
- for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next)
- ;
- *pt = tf;
- break;
- }
- default: break;
- }
- break;
- }
-
- return ts;
-}
-
-void Parser::parseStorageClasses(StorageClass &storage_class, LINK &link,
- bool &setAlignment, Expression *&ealign, Expressions *&udas)
-{
- StorageClass stc;
- bool sawLinkage = false; // seen a linkage declaration
-
- while (1)
- {
- switch (token.value)
- {
- case TOKconst:
- if (peek(&token)->value == TOKlparen)
- break; // const as type constructor
- stc = STCconst; // const as storage class
- goto L1;
-
- case TOKimmutable:
- if (peek(&token)->value == TOKlparen)
- break;
- stc = STCimmutable;
- goto L1;
-
- case TOKshared:
- if (peek(&token)->value == TOKlparen)
- break;
- stc = STCshared;
- goto L1;
-
- case TOKwild:
- if (peek(&token)->value == TOKlparen)
- break;
- stc = STCwild;
- goto L1;
-
- case TOKstatic: stc = STCstatic; goto L1;
- case TOKfinal: stc = STCfinal; goto L1;
- case TOKauto: stc = STCauto; goto L1;
- case TOKscope: stc = STCscope; goto L1;
- case TOKoverride: stc = STCoverride; goto L1;
- case TOKabstract: stc = STCabstract; goto L1;
- case TOKsynchronized: stc = STCsynchronized; goto L1;
- case TOKdeprecated: stc = STCdeprecated; goto L1;
- case TOKnothrow: stc = STCnothrow; goto L1;
- case TOKpure: stc = STCpure; goto L1;
- case TOKref: stc = STCref; goto L1;
- case TOKgshared: stc = STCgshared; goto L1;
- case TOKenum: stc = STCmanifest; goto L1;
- case TOKat:
- {
- stc = parseAttribute(&udas);
- if (stc)
- goto L1;
- continue;
- }
- L1:
- storage_class = appendStorageClass(storage_class, stc);
- nextToken();
- continue;
-
- case TOKextern:
- {
- if (peek(&token)->value != TOKlparen)
- {
- stc = STCextern;
- goto L1;
- }
-
- if (sawLinkage)
- error("redundant linkage declaration");
- sawLinkage = true;
- Identifiers *idents = NULL;
- CPPMANGLE cppmangle = CPPMANGLEdefault;
- bool cppMangleOnly = false;
- link = parseLinkage(&idents, &cppmangle, &cppMangleOnly);
- if (idents)
- {
- error("C++ name spaces not allowed here");
- delete idents;
- }
- if (cppmangle != CPPMANGLEdefault)
- {
- error("C++ mangle declaration not allowed here");
- }
- continue;
- }
-
- case TOKalign:
- {
- nextToken();
- setAlignment = true;
- if (token.value == TOKlparen)
- {
- nextToken();
- ealign = parseExpression();
- check(TOKrparen);
- }
- continue;
- }
- default:
- break;
- }
- break;
- }
-}
-
-static void parseAttributes(Parser *p, bool &hasParsedAttributes,
- StorageClass &storage_class, LINK &link, bool &setAlignment,
- Expression *&ealign, Expressions *&udas)
-{
- if (hasParsedAttributes) // only parse once
- return;
- hasParsedAttributes = true;
- udas = NULL;
- storage_class = STCundefined;
- link = p->linkage;
- setAlignment = false;
- ealign = NULL;
- p->parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
-}
-
-/**********************************
- * Parse Declarations.
- * These can be:
- * 1. declarations at global/class level
- * 2. declarations at statement level
- * Return array of Declaration *'s.
- */
-
-Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, const utf8_t *comment)
-{
- StorageClass storage_class = STCundefined;
- Type *ts;
- Type *t;
- Type *tfirst;
- Identifier *ident;
- TOK tok = TOKreserved;
- LINK link = linkage;
- bool setAlignment = false;
- Expression *ealign = NULL;
- Loc loc = token.loc;
- Expressions *udas = NULL;
- Token *tk;
-
- //printf("parseDeclarations() %s\n", token.toChars());
- if (!comment)
- comment = token.blockComment;
-
- if (autodecl)
- {
- ts = NULL; // infer type
- goto L2;
- }
-
- if (token.value == TOKalias)
- {
- tok = token.value;
- nextToken();
-
- /* Look for:
- * alias identifier this;
- */
- if (token.value == TOKidentifier && peekNext() == TOKthis)
- {
- AliasThis *s = new AliasThis(loc, token.ident);
- nextToken();
- check(TOKthis);
- check(TOKsemicolon);
- Dsymbols *a = new Dsymbols();
- a->push(s);
- addComment(s, comment);
- return a;
- }
- /* Look for:
- * alias identifier = type;
- * alias identifier(...) = type;
- */
- if (token.value == TOKidentifier &&
- skipParensIf(peek(&token), &tk) &&
- tk->value == TOKassign)
- {
- Dsymbols *a = new Dsymbols();
- while (1)
- {
- ident = token.ident;
- nextToken();
- TemplateParameters *tpl = NULL;
- if (token.value == TOKlparen)
- tpl = parseTemplateParameterList();
- check(TOKassign);
-
- bool hasParsedAttributes = false;
- if (token.value == TOKat)
- {
- parseAttributes(this, hasParsedAttributes,
- storage_class, link, setAlignment, ealign, udas);
- }
-
- Declaration *v;
- Dsymbol *s;
-
- // try to parse function type:
- // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
- bool attributesAppended = false;
- const StorageClass funcStc = parseTypeCtor();
- Token *tlu = &token;
- if (token.value != TOKfunction &&
- token.value != TOKdelegate &&
- isBasicType(&tlu) && tlu &&
- tlu->value == TOKlparen)
- {
- VarArg vargs;
- Type *tret = parseBasicType();
- Parameters *prms = parseParameters(&vargs);
- ParameterList pl = ParameterList(prms, vargs);
-
- parseAttributes(this, hasParsedAttributes,
- storage_class, link, setAlignment, ealign, udas);
- if (udas)
- error("user-defined attributes not allowed for `alias` declarations");
-
- attributesAppended = true;
- storage_class = appendStorageClass(storage_class, funcStc);
- Type *tf = new TypeFunction(pl, tret, link, storage_class);
- v = new AliasDeclaration(loc, ident, tf);
- }
- else if (token.value == TOKfunction ||
- token.value == TOKdelegate ||
- (token.value == TOKlparen &&
- skipAttributes(peekPastParen(&token), &tk) &&
- (tk->value == TOKgoesto || tk->value == TOKlcurly)) ||
- token.value == TOKlcurly ||
- (token.value == TOKidentifier && peekNext() == TOKgoesto) ||
- (token.value == TOKref && peekNext() == TOKlparen &&
- skipAttributes(peekPastParen(peek(&token)), &tk) &&
- (tk->value == TOKgoesto || tk->value == TOKlcurly)))
- {
- // function (parameters) { statements... }
- // delegate (parameters) { statements... }
- // (parameters) { statements... }
- // (parameters) => expression
- // { statements... }
- // identifier => expression
- // ref (parameters) { statements... }
- // ref (parameters) => expression
-
- s = parseFunctionLiteral();
-
- if (udas != NULL)
- {
- if (storage_class != 0)
- error("Cannot put a storage-class in an alias declaration.");
- // shouldn't have set these variables
- assert(link == linkage && !setAlignment && ealign == NULL);
- TemplateDeclaration *tpl_ = (TemplateDeclaration *) s;
- assert(tpl_ != NULL && tpl_->members->length == 1);
- FuncLiteralDeclaration *fd = (FuncLiteralDeclaration *) (*tpl_->members)[0];
- TypeFunction *tf = (TypeFunction *) fd->type;
- assert(tf->parameterList.length() > 0);
- Dsymbols *as = new Dsymbols();
- (*tf->parameterList.parameters)[0]->userAttribDecl = new UserAttributeDeclaration(udas, as);
- }
- v = new AliasDeclaration(loc, ident, s);
- }
- else
- {
- // StorageClasses type
- parseAttributes(this, hasParsedAttributes,
- storage_class, link, setAlignment, ealign, udas);
- if (udas)
- error("user-defined attributes not allowed for %s declarations", Token::toChars(tok));
-
- t = parseType();
- v = new AliasDeclaration(loc, ident, t);
- }
- if (!attributesAppended)
- storage_class = appendStorageClass(storage_class, funcStc);
- v->storage_class = storage_class;
-
- s = v;
- if (tpl)
- {
- Dsymbols *a2 = new Dsymbols();
- a2->push(s);
- TemplateDeclaration *tempdecl =
- new TemplateDeclaration(loc, ident, tpl, NULL, a2);
- s = tempdecl;
- }
- if (setAlignment)
- {
- Dsymbols *ax = new Dsymbols();
- ax->push(s);
- s = new AlignDeclaration(v->loc, ealign, ax);
- }
- if (link != linkage)
- {
- Dsymbols *a2 = new Dsymbols();
- a2->push(s);
- s = new LinkDeclaration(link, a2);
- }
- a->push(s);
-
- switch (token.value)
- {
- case TOKsemicolon:
- nextToken();
- addComment(s, comment);
- break;
- case TOKcomma:
- nextToken();
- addComment(s, comment);
- if (token.value != TOKidentifier)
- {
- error("identifier expected following comma, not %s", token.toChars());
- break;
- }
- if (peekNext() != TOKassign && peekNext() != TOKlparen)
- {
- error("= expected following identifier");
- nextToken();
- break;
- }
- continue;
- default:
- error("semicolon expected to close %s declaration", Token::toChars(tok));
- break;
- }
- break;
- }
- return a;
- }
-
- // alias StorageClasses type ident;
- }
-
- parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
-
- if (token.value == TOKstruct ||
- token.value == TOKunion ||
- token.value == TOKclass ||
- token.value == TOKinterface)
- {
- Dsymbol *s = parseAggregate();
- Dsymbols *a = new Dsymbols();
- a->push(s);
-
- if (storage_class)
- {
- s = new StorageClassDeclaration(storage_class, a);
- a = new Dsymbols();
- a->push(s);
- }
- if (setAlignment)
- {
- s = new AlignDeclaration(s->loc, ealign, a);
- a = new Dsymbols();
- a->push(s);
- }
- if (link != linkage)
- {
- s = new LinkDeclaration(link, a);
- a = new Dsymbols();
- a->push(s);
- }
- if (udas)
- {
- s = new UserAttributeDeclaration(udas, a);
- a = new Dsymbols();
- a->push(s);
- }
-
- addComment(s, comment);
- return a;
- }
-
- /* Look for auto initializers:
- * storage_class identifier = initializer;
- * storage_class identifier(...) = initializer;
- */
- if ((storage_class || udas) &&
- token.value == TOKidentifier &&
- skipParensIf(peek(&token), &tk) &&
- tk->value == TOKassign)
- {
- Dsymbols *a = parseAutoDeclarations(storage_class, comment);
- if (udas)
- {
- Dsymbol *s = new UserAttributeDeclaration(udas, a);
- a = new Dsymbols();
- a->push(s);
- }
- return a;
- }
-
- /* Look for return type inference for template functions.
- */
- if ((storage_class || udas) && token.value == TOKidentifier && skipParens(peek(&token), &tk) &&
- skipAttributes(tk, &tk) &&
- (tk->value == TOKlparen || tk->value == TOKlcurly || tk->value == TOKin || tk->value == TOKout ||
- tk->value == TOKdo || (tk->value == TOKidentifier && tk->ident == Id::_body)))
- {
- ts = NULL;
- }
- else
- {
- ts = parseBasicType();
- ts = parseBasicType2(ts);
- }
-
-L2:
- tfirst = NULL;
- Dsymbols *a = new Dsymbols();
-
- if (pAttrs)
- {
- storage_class |= pAttrs->storageClass;
- //pAttrs->storageClass = STCundefined;
- }
-
- while (1)
- {
- TemplateParameters *tpl = NULL;
- int disable;
- int alt = 0;
-
- loc = token.loc;
- ident = NULL;
- t = parseDeclarator(ts, &alt, &ident, &tpl, storage_class, &disable, &udas);
- assert(t);
- if (!tfirst)
- tfirst = t;
- else if (t != tfirst)
- error("multiple declarations must have the same type, not %s and %s",
- tfirst->toChars(), t->toChars());
- bool isThis = (t->ty == Tident && ((TypeIdentifier *)t)->ident == Id::This && token.value == TOKassign);
- if (ident)
- checkCstyleTypeSyntax(loc, t, alt, ident);
- else if (!isThis)
- error("no identifier for declarator %s", t->toChars());
-
- if (tok == TOKalias)
- {
- Declaration *v;
- Initializer *init = NULL;
-
- /* Aliases can no longer have multiple declarators, storage classes,
- * linkages, or auto declarations.
- * These never made any sense, anyway.
- * The code below needs to be fixed to reject them.
- * The grammar has already been fixed to preclude them.
- */
-
- if (udas)
- error("user-defined attributes not allowed for %s declarations", Token::toChars(tok));
-
- if (token.value == TOKassign)
- {
- nextToken();
- init = parseInitializer();
- }
- if (init)
- {
- if (isThis)
- error("cannot use syntax `alias this = %s`, use `alias %s this` instead",
- init->toChars(), init->toChars());
- else
- error("alias cannot have initializer");
- }
- v = new AliasDeclaration(loc, ident, t);
-
- v->storage_class = storage_class;
- if (pAttrs)
- {
- /* AliasDeclaration distinguish @safe, @system, @trusted atttributes
- * on prefix and postfix.
- * @safe alias void function() FP1;
- * alias @safe void function() FP2; // FP2 is not @safe
- * alias void function() @safe FP3;
- */
- pAttrs->storageClass &= (STCsafe | STCsystem | STCtrusted);
- }
- Dsymbol *s = v;
-
- if (link != linkage)
- {
- Dsymbols *ax = new Dsymbols();
- ax->push(v);
- s = new LinkDeclaration(link, ax);
- }
- a->push(s);
- switch (token.value)
- {
- case TOKsemicolon:
- nextToken();
- addComment(s, comment);
- break;
-
- case TOKcomma:
- nextToken();
- addComment(s, comment);
- continue;
-
- default:
- error("semicolon expected to close %s declaration", Token::toChars(tok));
- break;
- }
- }
- else if (t->ty == Tfunction)
- {
- Expression *constraint = NULL;
-
- //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class);
- FuncDeclaration *f =
- new FuncDeclaration(loc, Loc(), ident, storage_class | (disable ? STCdisable : 0), t);
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
- if (tpl)
- constraint = parseConstraint();
- Dsymbol *s = parseContracts(f);
- Identifier *tplIdent = s->ident;
- if (link != linkage)
- {
- Dsymbols *ax = new Dsymbols();
- ax->push(s);
- s = new LinkDeclaration(link, ax);
- }
- if (udas)
- {
- Dsymbols *ax = new Dsymbols();
- ax->push(s);
- s = new UserAttributeDeclaration(udas, ax);
- }
-
- /* A template parameter list means it's a function template
- */
- if (tpl)
- {
- // Wrap a template around the function declaration
- Dsymbols *decldefs = new Dsymbols();
- decldefs->push(s);
- TemplateDeclaration *tempdecl =
- new TemplateDeclaration(loc, tplIdent, tpl, constraint, decldefs);
- s = tempdecl;
-
- if (storage_class & STCstatic)
- {
- assert(f->storage_class & STCstatic);
- f->storage_class &= ~STCstatic;
-
- Dsymbols *ax = new Dsymbols();
- ax->push(s);
- s = new StorageClassDeclaration(STCstatic, ax);
- }
- }
- a->push(s);
- addComment(s, comment);
- }
- else if (ident)
- {
- Initializer *init = NULL;
- if (token.value == TOKassign)
- {
- nextToken();
- init = parseInitializer();
- }
-
- VarDeclaration *v = new VarDeclaration(loc, t, ident, init);
- v->storage_class = storage_class;
- if (pAttrs)
- pAttrs->storageClass = STCundefined;
-
- Dsymbol *s = v;
-
- if (tpl && init)
- {
- Dsymbols *a2 = new Dsymbols();
- a2->push(s);
- TemplateDeclaration *tempdecl =
- new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0);
- s = tempdecl;
- }
- if (link != linkage)
- {
- Dsymbols *ax = new Dsymbols();
- ax->push(s);
- s = new LinkDeclaration(link, ax);
- }
- if (udas)
- {
- Dsymbols *ax = new Dsymbols();
- ax->push(s);
- s = new UserAttributeDeclaration(udas, ax);
- }
- a->push(s);
- switch (token.value)
- {
- case TOKsemicolon:
- nextToken();
- addComment(s, comment);
- break;
-
- case TOKcomma:
- nextToken();
- addComment(s, comment);
- continue;
-
- default:
- error("semicolon expected, not `%s`", token.toChars());
- break;
- }
- }
- break;
- }
- return a;
-}
-
-Dsymbol *Parser::parseFunctionLiteral()
-{
- Loc loc = token.loc;
-
- TemplateParameters *tpl = NULL;
- Parameters *parameters = NULL;
- VarArg varargs = VARARGnone;
- Type *tret = NULL;
- StorageClass stc = 0;
- TOK save = TOKreserved;
-
- switch (token.value)
- {
- case TOKfunction:
- case TOKdelegate:
- save = token.value;
- nextToken();
- if (token.value == TOKref)
- {
- // function ref (parameters) { statements... }
- // delegate ref (parameters) { statements... }
- stc = STCref;
- nextToken();
- }
- if (token.value != TOKlparen && token.value != TOKlcurly)
- {
- // function type (parameters) { statements... }
- // delegate type (parameters) { statements... }
- tret = parseBasicType();
- tret = parseBasicType2(tret); // function return type
- }
-
- if (token.value == TOKlparen)
- {
- // function (parameters) { statements... }
- // delegate (parameters) { statements... }
- }
- else
- {
- // function { statements... }
- // delegate { statements... }
- break;
- }
- goto LTOKlparen;
-
- case TOKref:
- // ref (parameters) => expression
- // ref (parameters) { statements... }
- stc = STCref;
- nextToken();
- goto LTOKlparen;
-
- case TOKlparen:
- LTOKlparen:
- {
- // (parameters) => expression
- // (parameters) { statements... }
- parameters = parseParameters(&varargs, &tpl);
- stc = parsePostfix(stc, NULL);
- if (StorageClass modStc = stc & STC_TYPECTOR)
- {
- if (save == TOKfunction)
- {
- OutBuffer buf;
- stcToBuffer(&buf, modStc);
- error("function literal cannot be %s", buf.peekChars());
- }
- else
- save = TOKdelegate;
- }
- break;
- }
- case TOKlcurly:
- // { statements... }
- break;
-
- case TOKidentifier:
- {
- // identifier => expression
- parameters = new Parameters();
- Identifier *id = Identifier::generateId("__T");
- Type *t = new TypeIdentifier(loc, id);
- parameters->push(new Parameter(0, t, token.ident, NULL, NULL));
-
- tpl = new TemplateParameters();
- TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
- tpl->push(tp);
-
- nextToken();
- break;
- }
- default:
- assert(0);
- }
-
- if (!parameters)
- parameters = new Parameters();
- TypeFunction *tf = new TypeFunction(ParameterList(parameters, varargs),
- tret, linkage, stc);
- tf = (TypeFunction *)tf->addSTC(stc);
- FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, Loc(), tf, save, NULL);
-
- if (token.value == TOKgoesto)
- {
- check(TOKgoesto);
- Loc returnloc = token.loc;
- Expression *ae = parseAssignExp();
- fd->fbody = new ReturnStatement(returnloc, ae);
- fd->endloc = token.loc;
- }
- else
- {
- parseContracts(fd);
- }
-
- if (tpl)
- {
- // Wrap a template around function fd
- Dsymbols *decldefs = new Dsymbols();
- decldefs->push(fd);
- return new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, false, true);
- }
- else
- return fd;
-}
-
-/*****************************************
- * Parse auto declarations of the form:
- * storageClass ident = init, ident = init, ... ;
- * and return the array of them.
- * Starts with token on the first ident.
- * Ends with scanner past closing ';'
- */
-
-Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, const utf8_t *comment)
-{
- //printf("parseAutoDeclarations\n");
- Token *tk;
- Dsymbols *a = new Dsymbols;
-
- while (1)
- {
- Loc loc = token.loc;
- Identifier *ident = token.ident;
- nextToken(); // skip over ident
-
- TemplateParameters *tpl = NULL;
- if (token.value == TOKlparen)
- tpl = parseTemplateParameterList();
-
- check(TOKassign); // skip over '='
- Initializer *init = parseInitializer();
- VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
- v->storage_class = storageClass;
-
- Dsymbol *s = v;
- if (tpl)
- {
- Dsymbols *a2 = new Dsymbols();
- a2->push(v);
- TemplateDeclaration *tempdecl =
- new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0);
- s = tempdecl;
- }
- a->push(s);
- switch (token.value)
- {
- case TOKsemicolon:
- nextToken();
- addComment(s, comment);
- break;
-
- case TOKcomma:
- nextToken();
- if (!(token.value == TOKidentifier &&
- skipParensIf(peek(&token), &tk) &&
- tk->value == TOKassign))
- {
- error("identifier expected following comma");
- break;
- }
- addComment(s, comment);
- continue;
-
- default:
- error("semicolon expected following auto declaration, not `%s`", token.toChars());
- break;
- }
- break;
- }
- return a;
-}
-
-/*****************************************
- * Parse contracts following function declaration.
- */
-
-FuncDeclaration *Parser::parseContracts(FuncDeclaration *f)
-{
- LINK linksave = linkage;
-
- bool literal = f->isFuncLiteralDeclaration() != NULL;
-
- // The following is irrelevant, as it is overridden by sc->linkage in
- // TypeFunction::semantic
- linkage = LINKd; // nested functions have D linkage
- bool requireDo = false;
-L1:
- switch (token.value)
- {
- case TOKlcurly:
- if (requireDo)
- error("missing body { ... } after in or out");
- f->fbody = parseStatement(PSsemi);
- f->endloc = endloc;
- break;
-
- case TOKidentifier:
- if (token.ident != Id::_body)
- goto Ldefault;
- /* fall through */
-
- case TOKdo:
- nextToken();
- f->fbody = parseStatement(PScurly);
- f->endloc = endloc;
- break;
-
- case TOKin:
- {
- // in { statements... }
- // in (expression)
- Loc loc = token.loc;
- nextToken();
- if (!f->frequires)
- {
- f->frequires = new Statements();
- }
- if (token.value == TOKlparen)
- {
- nextToken();
- Expression *e = parseAssignExp();
- Expression *msg = NULL;
- if (token.value == TOKcomma)
- {
- nextToken();
- if (token.value != TOKrparen)
- {
- msg = parseAssignExp();
- if (token.value == TOKcomma)
- nextToken();
- }
- }
- check(TOKrparen);
- e = new AssertExp(loc, e, msg);
- f->frequires->push(new ExpStatement(loc, e));
- requireDo = false;
- }
- else
- {
- f->frequires->push(parseStatement(PScurly | PSscope));
- requireDo = true;
- }
- goto L1;
- }
-
- case TOKout:
- {
- // out { statements... }
- // out (; expression)
- // out (identifier) { statements... }
- // out (identifier; expression)
- Loc loc = token.loc;
- nextToken();
- if (!f->fensures)
- {
- f->fensures = new Ensures();
- }
- Identifier *id = NULL;
- if (token.value != TOKlcurly)
- {
- check(TOKlparen);
- if (token.value != TOKidentifier && token.value != TOKsemicolon)
- error("`(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `%s`", token.toChars());
- if (token.value != TOKsemicolon)
- {
- id = token.ident;
- nextToken();
- }
- if (token.value == TOKsemicolon)
- {
- nextToken();
- Expression *e = parseAssignExp();
- Expression *msg = NULL;
- if (token.value == TOKcomma)
- {
- nextToken();
- if (token.value != TOKrparen)
- {
- msg = parseAssignExp();
- if (token.value == TOKcomma)
- nextToken();
- }
- }
- check(TOKrparen);
- e = new AssertExp(loc, e, msg);
- f->fensures->push(Ensure(id, new ExpStatement(loc, e)));
- requireDo = false;
- goto L1;
- }
- check(TOKrparen);
- }
- f->fensures->push(Ensure(id, parseStatement(PScurly | PSscope)));
- requireDo = true;
- goto L1;
- }
-
- case TOKsemicolon:
- if (!literal)
- {
- // Bugzilla 15799: Semicolon becomes a part of function declaration
- // only when 'do' is not required
- if (!requireDo)
- nextToken();
- break;
- }
- /* fall through */
-
- default:
- Ldefault:
- if (literal)
- {
- const char *sbody = requireDo ? "do " : "";
- error("missing %s{ ... } for function literal", sbody);
- }
- else if (!requireDo) // allow these even with no body
- {
- error("semicolon expected following function declaration");
- }
- break;
- }
- if (literal && !f->fbody)
- {
- // Set empty function body for error recovery
- f->fbody = new CompoundStatement(Loc(), (Statement *)NULL);
- }
-
- linkage = linksave;
-
- return f;
-}
-
-/*****************************************
- * Parse initializer for variable declaration.
- */
-
-Initializer *Parser::parseInitializer()
-{
- StructInitializer *is;
- ArrayInitializer *ia;
- ExpInitializer *ie;
- Expression *e;
- Identifier *id;
- Initializer *value;
- int comma;
- Loc loc = token.loc;
- Token *t;
- int braces;
- int brackets;
-
- switch (token.value)
- {
- case TOKlcurly:
- /* Scan ahead to see if it is a struct initializer or
- * a function literal.
- * If it contains a ';', it is a function literal.
- * Treat { } as a struct initializer.
- */
- braces = 1;
- for (t = peek(&token); 1; t = peek(t))
- {
- switch (t->value)
- {
- case TOKsemicolon:
- case TOKreturn:
- goto Lexpression;
-
- case TOKlcurly:
- braces++;
- continue;
-
- case TOKrcurly:
- if (--braces == 0)
- break;
- continue;
-
- case TOKeof:
- break;
-
- default:
- continue;
- }
- break;
- }
-
- is = new StructInitializer(loc);
- nextToken();
- comma = 2;
- while (1)
- {
- switch (token.value)
- {
- case TOKidentifier:
- if (comma == 1)
- error("comma expected separating field initializers");
- t = peek(&token);
- if (t->value == TOKcolon)
- {
- id = token.ident;
- nextToken();
- nextToken(); // skip over ':'
- }
- else
- { id = NULL;
- }
- value = parseInitializer();
- is->addInit(id, value);
- comma = 1;
- continue;
-
- case TOKcomma:
- if (comma == 2)
- error("expression expected, not `,`");
- nextToken();
- comma = 2;
- continue;
-
- case TOKrcurly: // allow trailing comma's
- nextToken();
- break;
-
- case TOKeof:
- error("found EOF instead of initializer");
- break;
-
- default:
- if (comma == 1)
- error("comma expected separating field initializers");
- value = parseInitializer();
- is->addInit(NULL, value);
- comma = 1;
- continue;
- //error("found `%s` instead of field initializer", token.toChars());
- //break;
- }
- break;
- }
- return is;
-
- case TOKlbracket:
- /* Scan ahead to see if it is an array initializer or
- * an expression.
- * If it ends with a ';' ',' or '}', it is an array initializer.
- */
- brackets = 1;
- for (t = peek(&token); 1; t = peek(t))
- {
- switch (t->value)
- {
- case TOKlbracket:
- brackets++;
- continue;
-
- case TOKrbracket:
- if (--brackets == 0)
- { t = peek(t);
- if (t->value != TOKsemicolon &&
- t->value != TOKcomma &&
- t->value != TOKrbracket &&
- t->value != TOKrcurly)
- goto Lexpression;
- break;
- }
- continue;
-
- case TOKeof:
- break;
-
- default:
- continue;
- }
- break;
- }
-
- ia = new ArrayInitializer(loc);
- nextToken();
- comma = 2;
- while (1)
- {
- switch (token.value)
- {
- default:
- if (comma == 1)
- { error("comma expected separating array initializers, not %s", token.toChars());
- nextToken();
- break;
- }
- e = parseAssignExp();
- if (!e)
- break;
- if (token.value == TOKcolon)
- {
- nextToken();
- value = parseInitializer();
- }
- else
- { value = new ExpInitializer(e->loc, e);
- e = NULL;
- }
- ia->addInit(e, value);
- comma = 1;
- continue;
-
- case TOKlcurly:
- case TOKlbracket:
- if (comma == 1)
- error("comma expected separating array initializers, not %s", token.toChars());
- value = parseInitializer();
- if (token.value == TOKcolon)
- {
- nextToken();
- e = initializerToExpression(value);
- value = parseInitializer();
- }
- else
- e = NULL;
- ia->addInit(e, value);
- comma = 1;
- continue;
-
- case TOKcomma:
- if (comma == 2)
- error("expression expected, not `,`");
- nextToken();
- comma = 2;
- continue;
-
- case TOKrbracket: // allow trailing comma's
- nextToken();
- break;
-
- case TOKeof:
- error("found `%s` instead of array initializer", token.toChars());
- break;
- }
- break;
- }
- return ia;
-
- case TOKvoid:
- t = peek(&token);
- if (t->value == TOKsemicolon || t->value == TOKcomma)
- {
- nextToken();
- return new VoidInitializer(loc);
- }
- goto Lexpression;
-
- default:
- Lexpression:
- e = parseAssignExp();
- ie = new ExpInitializer(loc, e);
- return ie;
- }
-}
-
-/*****************************************
- * Parses default argument initializer expression that is an assign expression,
- * with special handling for __FILE__, __FILE_FULL_PATH__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
- */
-
-Expression *Parser::parseDefaultInitExp()
-{
- if (token.value == TOKfile ||
- token.value == TOKfilefullpath ||
- token.value == TOKline ||
- token.value == TOKmodulestring ||
- token.value == TOKfuncstring ||
- token.value == TOKprettyfunc)
- {
- Token *t = peek(&token);
- if (t->value == TOKcomma || t->value == TOKrparen)
- {
- Expression *e = NULL;
- if (token.value == TOKfile)
- e = new FileInitExp(token.loc, TOKfile);
- else if (token.value == TOKfilefullpath)
- e = new FileInitExp(token.loc, TOKfilefullpath);
- else if (token.value == TOKline)
- e = new LineInitExp(token.loc);
- else if (token.value == TOKmodulestring)
- e = new ModuleInitExp(token.loc);
- else if (token.value == TOKfuncstring)
- e = new FuncInitExp(token.loc);
- else if (token.value == TOKprettyfunc)
- e = new PrettyFuncInitExp(token.loc);
- else
- assert(0);
- nextToken();
- return e;
- }
- }
-
- Expression *e = parseAssignExp();
- return e;
-}
-
-/*****************************************
- */
-
-void Parser::checkDanglingElse(Loc elseloc)
-{
- if (token.value != TOKelse &&
- token.value != TOKcatch &&
- token.value != TOKfinally &&
- lookingForElse.linnum != 0)
- {
- warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
- }
-}
-
-void Parser::checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident)
-{
- if (!alt)
- return;
-
- const char *sp = !ident ? "" : " ";
- const char *s = !ident ? "" : ident->toChars();
- if (alt & 1) // contains C-style function pointer syntax
- error(loc, "instead of C-style syntax, use D-style `%s%s%s`", t->toChars(), sp, s);
- else
- ::warning(loc, "instead of C-style syntax, use D-style syntax `%s%s%s`", t->toChars(), sp, s);
-
-}
-
-/*****************************************
- * Parses `foreach` statements, `static foreach` statements and
- * `static foreach` declarations. The template parameter
- * `isStatic` is true, iff a `static foreach` should be parsed.
- * If `isStatic` is true, `isDecl` can be true to indicate that a
- * `static foreach` declaration should be parsed.
- */
-Statement *Parser::parseForeach(Loc loc, bool *isRange, bool isDecl)
-{
- TOK op = token.value;
-
- nextToken();
- check(TOKlparen);
-
- Parameters *parameters = new Parameters();
-
- while (1)
- {
- Identifier *ai = NULL;
- Type *at;
-
- StorageClass storageClass = 0;
- StorageClass stc = 0;
- Lagain:
- if (stc)
- {
- storageClass = appendStorageClass(storageClass, stc);
- nextToken();
- }
- switch (token.value)
- {
- case TOKref:
- stc = STCref;
- goto Lagain;
-
- case TOKenum:
- stc = STCmanifest;
- goto Lagain;
-
- case TOKalias:
- storageClass = appendStorageClass(storageClass, STCalias);
- nextToken();
- break;
-
- case TOKconst:
- if (peekNext() != TOKlparen)
- {
- stc = STCconst;
- goto Lagain;
- }
- break;
-
- case TOKimmutable:
- if (peekNext() != TOKlparen)
- {
- stc = STCimmutable;
- goto Lagain;
- }
- break;
-
- case TOKshared:
- if (peekNext() != TOKlparen)
- {
- stc = STCshared;
- goto Lagain;
- }
- break;
-
- case TOKwild:
- if (peekNext() != TOKlparen)
- {
- stc = STCwild;
- goto Lagain;
- }
- break;
-
- default:
- break;
- }
- if (token.value == TOKidentifier)
- {
- Token *t = peek(&token);
- if (t->value == TOKcomma || t->value == TOKsemicolon)
- { ai = token.ident;
- at = NULL; // infer argument type
- nextToken();
- goto Larg;
- }
- }
- at = parseType(&ai);
- if (!ai)
- error("no identifier for declarator %s", at->toChars());
- Larg:
- Parameter *p = new Parameter(storageClass, at, ai, NULL, NULL);
- parameters->push(p);
- if (token.value == TOKcomma)
- { nextToken();
- continue;
- }
- break;
- }
- check(TOKsemicolon);
-
- Expression *aggr = parseExpression();
- if (token.value == TOKslice && parameters->length == 1)
- {
- Parameter *p = (*parameters)[0];
- delete parameters;
- nextToken();
- Expression *upr = parseExpression();
- check(TOKrparen);
- Loc endloc;
- Statement *body = (!isDecl) ? parseStatement(0, NULL, &endloc) : NULL;
- if (isRange)
- *isRange = true;
- return new ForeachRangeStatement(loc, op, p, aggr, upr, body, endloc);
- }
- else
- {
- check(TOKrparen);
- Loc endloc;
- Statement *body = (!isDecl) ? parseStatement(0, NULL, &endloc) : NULL;
- if (isRange)
- *isRange = false;
- return new ForeachStatement(loc, op, parameters, aggr, body, endloc);
- }
-}
-
-Dsymbol *Parser::parseForeachStaticDecl(Loc loc, Dsymbol **pLastDecl)
-{
- nextToken();
-
- bool isRange = false;
- Statement *s = parseForeach(loc, &isRange, true);
-
- return new StaticForeachDeclaration(
- new StaticForeach(loc, isRange ? NULL : (ForeachStatement *)s,
- isRange ? (ForeachRangeStatement *)s : NULL),
- parseBlock(pLastDecl)
- );
-}
-
-Statement *Parser::parseForeachStatic(Loc loc)
-{
- nextToken();
-
- bool isRange = false;
- Statement *s = parseForeach(loc, &isRange, false);
-
- return new StaticForeachStatement(loc,
- new StaticForeach(loc, isRange ? NULL : (ForeachStatement *)s,
- isRange ? (ForeachRangeStatement *)s : NULL)
- );
-}
-
-/*****************************************
- * Input:
- * flags PSxxxx
- * Output:
- * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of first token of next statement
- */
-
-Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc)
-{
- Statement *s = NULL;
- Condition *cond;
- Statement *ifbody;
- Statement *elsebody;
- bool isfinal;
- Loc loc = token.loc;
-
- //printf("parseStatement()\n");
-
- if (flags & PScurly && token.value != TOKlcurly)
- error("statement expected to be { }, not %s", token.toChars());
-
- switch (token.value)
- {
- case TOKidentifier:
- { /* A leading identifier can be a declaration, label, or expression.
- * The easiest case to check first is label:
- */
- Token *t = peek(&token);
- if (t->value == TOKcolon)
- {
- Token *nt = peek(t);
- if (nt->value == TOKcolon)
- {
- // skip ident::
- nextToken();
- nextToken();
- nextToken();
- error("use `.` for member lookup, not `::`");
- break;
- }
- // It's a label
- Identifier *ident = token.ident;
- nextToken();
- nextToken();
- if (token.value == TOKrcurly)
- s = NULL;
- else if (token.value == TOKlcurly)
- s = parseStatement(PScurly | PSscope);
- else
- s = parseStatement(PSsemi_ok);
- s = new LabelStatement(loc, ident, s);
- break;
- }
- }
- /* fall through */
- case TOKdot:
- case TOKtypeof:
- case TOKvector:
- case TOKtraits:
- /* Bugzilla 15163: If tokens can be handled as
- * old C-style declaration or D expression, prefer the latter.
- */
- if (isDeclaration(&token, 3, TOKreserved, NULL))
- goto Ldeclaration;
- else
- goto Lexp;
- break;
-
- case TOKassert:
- case TOKthis:
- case TOKsuper:
- case TOKint32v:
- case TOKuns32v:
- case TOKint64v:
- case TOKuns64v:
- case TOKint128v:
- case TOKuns128v:
- case TOKfloat32v:
- case TOKfloat64v:
- case TOKfloat80v:
- case TOKimaginary32v:
- case TOKimaginary64v:
- case TOKimaginary80v:
- case TOKcharv:
- case TOKwcharv:
- case TOKdcharv:
- case TOKnull:
- case TOKtrue:
- case TOKfalse:
- case TOKstring:
- case TOKxstring:
- case TOKlparen:
- case TOKcast:
- case TOKmul:
- case TOKmin:
- case TOKadd:
- case TOKtilde:
- case TOKnot:
- case TOKplusplus:
- case TOKminusminus:
- case TOKnew:
- case TOKdelete:
- case TOKdelegate:
- case TOKfunction:
- case TOKtypeid:
- case TOKis:
- case TOKlbracket:
- case TOKfile:
- case TOKfilefullpath:
- case TOKline:
- case TOKmodulestring:
- case TOKfuncstring:
- case TOKprettyfunc:
- Lexp:
- {
- Expression *exp = parseExpression();
- check(TOKsemicolon, "statement");
- s = new ExpStatement(loc, exp);
- break;
- }
-
- case TOKstatic:
- { // Look ahead to see if it's static assert() or static if()
-
- Token *t = peek(&token);
- if (t->value == TOKassert)
- {
- s = new StaticAssertStatement(parseStaticAssert());
- break;
- }
- if (t->value == TOKif)
- {
- cond = parseStaticIfCondition();
- goto Lcondition;
- }
- else if (t->value == TOKforeach || t->value == TOKforeach_reverse)
- {
- s = parseForeachStatic(loc);
- if (flags & PSscope)
- s = new ScopeStatement(loc, s, token.loc);
- break;
- }
- if (t->value == TOKimport)
- {
- Dsymbols *imports = parseImport();
- s = new ImportStatement(loc, imports);
- if (flags & PSscope)
- s = new ScopeStatement(loc, s, token.loc);
- break;
- }
- goto Ldeclaration;
- }
-
- case TOKfinal:
- if (peekNext() == TOKswitch)
- {
- nextToken();
- isfinal = true;
- goto Lswitch;
- }
- goto Ldeclaration;
-
- case TOKwchar: case TOKdchar:
- case TOKbool: case TOKchar:
- case TOKint8: case TOKuns8:
- case TOKint16: case TOKuns16:
- case TOKint32: case TOKuns32:
- case TOKint64: case TOKuns64:
- case TOKint128: case TOKuns128:
- case TOKfloat32: case TOKfloat64: case TOKfloat80:
- case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
- case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
- case TOKvoid:
- // bug 7773: int.max is always a part of expression
- if (peekNext() == TOKdot)
- goto Lexp;
- if (peekNext() == TOKlparen)
- goto Lexp;
- /* fall through */
-
- case TOKalias:
- case TOKconst:
- case TOKauto:
- case TOKabstract:
- case TOKextern:
- case TOKalign:
- case TOKimmutable:
- case TOKshared:
- case TOKwild:
- case TOKdeprecated:
- case TOKnothrow:
- case TOKpure:
- case TOKref:
- case TOKgshared:
- case TOKat:
- case TOKstruct:
- case TOKunion:
- case TOKclass:
- case TOKinterface:
- Ldeclaration:
- {
- Dsymbols *a = parseDeclarations(false, NULL, NULL);
- if (a->length > 1)
- {
- Statements *as = new Statements();
- as->reserve(a->length);
- for (size_t i = 0; i < a->length; i++)
- {
- Dsymbol *d = (*a)[i];
- s = new ExpStatement(loc, d);
- as->push(s);
- }
- s = new CompoundDeclarationStatement(loc, as);
- }
- else if (a->length == 1)
- {
- Dsymbol *d = (*a)[0];
- s = new ExpStatement(loc, d);
- }
- else
- s = new ExpStatement(loc, (Expression *)NULL);
- if (flags & PSscope)
- s = new ScopeStatement(loc, s, token.loc);
- break;
- }
-
- case TOKenum:
- { /* Determine if this is a manifest constant declaration,
- * or a conventional enum.
- */
- Dsymbol *d;
- Token *t = peek(&token);
- if (t->value == TOKlcurly || t->value == TOKcolon)
- d = parseEnum();
- else if (t->value != TOKidentifier)
- goto Ldeclaration;
- else
- {
- t = peek(t);
- if (t->value == TOKlcurly || t->value == TOKcolon ||
- t->value == TOKsemicolon)
- d = parseEnum();
- else
- goto Ldeclaration;
- }
- s = new ExpStatement(loc, d);
- if (flags & PSscope)
- s = new ScopeStatement(loc, s, token.loc);
- break;
- }
-
- case TOKmixin:
- {
- if (isDeclaration(&token, 3, TOKreserved, NULL))
- goto Ldeclaration;
- Token *t = peek(&token);
- if (t->value == TOKlparen)
- {
- // mixin(string)
- Expression *e = parseAssignExp();
- check(TOKsemicolon);
- if (e->op == TOKmixin)
- {
- CompileExp *cpe = (CompileExp *)e;
- s = new CompileStatement(loc, cpe->exps);
- }
- else
- {
- s = new ExpStatement(loc, e);
- }
- break;
- }
- Dsymbol *d = parseMixin();
- s = new ExpStatement(loc, d);
- if (flags & PSscope)
- s = new ScopeStatement(loc, s, token.loc);
- break;
- }
-
- case TOKlcurly:
- {
- Loc lookingForElseSave = lookingForElse;
- lookingForElse = Loc();
-
- nextToken();
- //if (token.value == TOKsemicolon)
- //error("use `{ }` for an empty statement, not a `;`");
- Statements *statements = new Statements();
- while (token.value != TOKrcurly && token.value != TOKeof)
- {
- statements->push(parseStatement(PSsemi | PScurlyscope));
- }
- if (endPtr) *endPtr = token.ptr;
- endloc = token.loc;
- if (pEndloc)
- {
- *pEndloc = token.loc;
- pEndloc = NULL; // don't set it again
- }
- s = new CompoundStatement(loc, statements);
- if (flags & (PSscope | PScurlyscope))
- s = new ScopeStatement(loc, s, token.loc);
- check(TOKrcurly, "compound statement");
- lookingForElse = lookingForElseSave;
- break;
- }
-
- case TOKwhile:
- {
- nextToken();
- check(TOKlparen);
- Expression *condition = parseExpression();
- check(TOKrparen);
- Loc endloc;
- Statement *body = parseStatement(PSscope, NULL, &endloc);
- s = new WhileStatement(loc, condition, body, endloc);
- break;
- }
-
- case TOKsemicolon:
- if (!(flags & PSsemi_ok))
- {
- if (flags & PSsemi)
- deprecation("use `{ }` for an empty statement, not a `;`");
- else
- error("use `{ }` for an empty statement, not a `;`");
- }
- nextToken();
- s = new ExpStatement(loc, (Expression *)NULL);
- break;
-
- case TOKdo:
- { Statement *body;
- Expression *condition;
-
- nextToken();
- Loc lookingForElseSave = lookingForElse;
- lookingForElse = Loc();
- body = parseStatement(PSscope);
- lookingForElse = lookingForElseSave;
- check(TOKwhile);
- check(TOKlparen);
- condition = parseExpression();
- check(TOKrparen);
- if (token.value == TOKsemicolon)
- nextToken();
- else
- error("terminating `;` required after do-while statement");
- s = new DoStatement(loc, body, condition, token.loc);
- break;
- }
-
- case TOKfor:
- {
- Statement *init;
- Expression *condition;
- Expression *increment;
-
- nextToken();
- check(TOKlparen);
- if (token.value == TOKsemicolon)
- { init = NULL;
- nextToken();
- }
- else
- {
- Loc lookingForElseSave = lookingForElse;
- lookingForElse = Loc();
- init = parseStatement(0);
- lookingForElse = lookingForElseSave;
- }
- if (token.value == TOKsemicolon)
- {
- condition = NULL;
- nextToken();
- }
- else
- {
- condition = parseExpression();
- check(TOKsemicolon, "for condition");
- }
- if (token.value == TOKrparen)
- { increment = NULL;
- nextToken();
- }
- else
- { increment = parseExpression();
- check(TOKrparen);
- }
- Loc endloc;
- Statement *body = parseStatement(PSscope, NULL, &endloc);
- s = new ForStatement(loc, init, condition, increment, body, endloc);
- break;
- }
-
- case TOKforeach:
- case TOKforeach_reverse:
- {
- s = parseForeach(loc, NULL, false);
- break;
- }
-
- case TOKif:
- {
- Parameter *param = NULL;
- Expression *condition;
-
- nextToken();
- check(TOKlparen);
-
- StorageClass storageClass = 0;
- StorageClass stc = 0;
- LagainStc:
- if (stc)
- {
- storageClass = appendStorageClass(storageClass, stc);
- nextToken();
- }
- switch (token.value)
- {
- case TOKref:
- stc = STCref;
- goto LagainStc;
- case TOKauto:
- stc = STCauto;
- goto LagainStc;
- case TOKconst:
- if (peekNext() != TOKlparen)
- {
- stc = STCconst;
- goto LagainStc;
- }
- break;
- case TOKimmutable:
- if (peekNext() != TOKlparen)
- {
- stc = STCimmutable;
- goto LagainStc;
- }
- break;
- case TOKshared:
- if (peekNext() != TOKlparen)
- {
- stc = STCshared;
- goto LagainStc;
- }
- break;
- case TOKwild:
- if (peekNext() != TOKlparen)
- {
- stc = STCwild;
- goto LagainStc;
- }
- break;
- default:
- break;
- }
-
- if (storageClass != 0 &&
- token.value == TOKidentifier &&
- peek(&token)->value == TOKassign)
- {
- Identifier *ai = token.ident;
- Type *at = NULL; // infer parameter type
- nextToken();
- check(TOKassign);
- param = new Parameter(storageClass, at, ai, NULL, NULL);
- }
- else if (isDeclaration(&token, 2, TOKassign, NULL))
- {
- Identifier *ai;
- Type *at = parseType(&ai);
- check(TOKassign);
- param = new Parameter(storageClass, at, ai, NULL, NULL);
- }
-
- condition = parseExpression();
- check(TOKrparen);
- {
- Loc lookingForElseSave = lookingForElse;
- lookingForElse = loc;
- ifbody = parseStatement(PSscope);
- lookingForElse = lookingForElseSave;
- }
- if (token.value == TOKelse)
- {
- Loc elseloc = token.loc;
- nextToken();
- elsebody = parseStatement(PSscope);
- checkDanglingElse(elseloc);
- }
- else
- elsebody = NULL;
- if (condition && ifbody)
- s = new IfStatement(loc, param, condition, ifbody, elsebody, token.loc);
- else
- s = NULL; // don't propagate parsing errors
- break;
- }
-
- case TOKscope:
- if (peek(&token)->value != TOKlparen)
- goto Ldeclaration; // scope used as storage class
- nextToken();
- check(TOKlparen);
- if (token.value != TOKidentifier)
- { error("scope identifier expected");
- goto Lerror;
- }
- else
- { TOK t = TOKon_scope_exit;
- Identifier *id = token.ident;
-
- if (id == Id::exit)
- t = TOKon_scope_exit;
- else if (id == Id::failure)
- t = TOKon_scope_failure;
- else if (id == Id::success)
- t = TOKon_scope_success;
- else
- error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
- nextToken();
- check(TOKrparen);
- Statement *st = parseStatement(PSscope);
- s = new ScopeGuardStatement(loc, t, st);
- break;
- }
-
- case TOKdebug:
- nextToken();
- if (token.value == TOKassign)
- {
- error("debug conditions can only be declared at module scope");
- nextToken();
- nextToken();
- goto Lerror;
- }
- cond = parseDebugCondition();
- goto Lcondition;
-
- case TOKversion:
- nextToken();
- if (token.value == TOKassign)
- {
- error("version conditions can only be declared at module scope");
- nextToken();
- nextToken();
- goto Lerror;
- }
- cond = parseVersionCondition();
- goto Lcondition;
-
- Lcondition:
- {
- Loc lookingForElseSave = lookingForElse;
- lookingForElse = loc;
- ifbody = parseStatement(0);
- lookingForElse = lookingForElseSave;
- }
- elsebody = NULL;
- if (token.value == TOKelse)
- {
- Loc elseloc = token.loc;
- nextToken();
- elsebody = parseStatement(0);
- checkDanglingElse(elseloc);
- }
- s = new ConditionalStatement(loc, cond, ifbody, elsebody);
- if (flags & PSscope)
- s = new ScopeStatement(loc, s, token.loc);
- break;
-
- case TOKpragma:
- { Identifier *ident;
- Expressions *args = NULL;
- Statement *body;
-
- nextToken();
- check(TOKlparen);
- if (token.value != TOKidentifier)
- { error("pragma(identifier expected");
- goto Lerror;
- }
- ident = token.ident;
- nextToken();
- if (token.value == TOKcomma && peekNext() != TOKrparen)
- args = parseArguments(); // pragma(identifier, args...);
- else
- check(TOKrparen); // pragma(identifier);
- if (token.value == TOKsemicolon)
- { nextToken();
- body = NULL;
- }
- else
- body = parseStatement(PSsemi);
- s = new PragmaStatement(loc, ident, args, body);
- break;
- }
-
- case TOKswitch:
- isfinal = false;
- goto Lswitch;
-
- Lswitch:
- {
- nextToken();
- check(TOKlparen);
- Expression *condition = parseExpression();
- check(TOKrparen);
- Statement *body = parseStatement(PSscope);
- s = new SwitchStatement(loc, condition, body, isfinal);
- break;
- }
-
- case TOKcase:
- { Expression *exp;
- Expressions cases; // array of Expression's
- Expression *last = NULL;
-
- while (1)
- {
- nextToken();
- exp = parseAssignExp();
- cases.push(exp);
- if (token.value != TOKcomma)
- break;
- }
- check(TOKcolon);
-
- /* case exp: .. case last:
- */
- if (token.value == TOKslice)
- {
- if (cases.length > 1)
- error("only one case allowed for start of case range");
- nextToken();
- check(TOKcase);
- last = parseAssignExp();
- check(TOKcolon);
- }
-
- if (flags & PScurlyscope)
- {
- Statements *statements = new Statements();
- while (token.value != TOKcase &&
- token.value != TOKdefault &&
- token.value != TOKeof &&
- token.value != TOKrcurly)
- {
- statements->push(parseStatement(PSsemi | PScurlyscope));
- }
- s = new CompoundStatement(loc, statements);
- }
- else
- s = parseStatement(PSsemi | PScurlyscope);
- s = new ScopeStatement(loc, s, token.loc);
-
- if (last)
- {
- s = new CaseRangeStatement(loc, exp, last, s);
- }
- else
- {
- // Keep cases in order by building the case statements backwards
- for (size_t i = cases.length; i; i--)
- {
- exp = cases[i - 1];
- s = new CaseStatement(loc, exp, s);
- }
- }
- break;
- }
-
- case TOKdefault:
- {
- nextToken();
- check(TOKcolon);
-
- if (flags & PScurlyscope)
- {
- Statements *statements = new Statements();
- while (token.value != TOKcase &&
- token.value != TOKdefault &&
- token.value != TOKeof &&
- token.value != TOKrcurly)
- {
- statements->push(parseStatement(PSsemi | PScurlyscope));
- }
- s = new CompoundStatement(loc, statements);
- }
- else
- s = parseStatement(PSsemi | PScurlyscope);
- s = new ScopeStatement(loc, s, token.loc);
- s = new DefaultStatement(loc, s);
- break;
- }
-
- case TOKreturn:
- { Expression *exp;
-
- nextToken();
- if (token.value == TOKsemicolon)
- exp = NULL;
- else
- exp = parseExpression();
- check(TOKsemicolon, "return statement");
- s = new ReturnStatement(loc, exp);
- break;
- }
-
- case TOKbreak:
- { Identifier *ident;
-
- nextToken();
- if (token.value == TOKidentifier)
- { ident = token.ident;
- nextToken();
- }
- else
- ident = NULL;
- check(TOKsemicolon, "break statement");
- s = new BreakStatement(loc, ident);
- break;
- }
-
- case TOKcontinue:
- { Identifier *ident;
-
- nextToken();
- if (token.value == TOKidentifier)
- { ident = token.ident;
- nextToken();
- }
- else
- ident = NULL;
- check(TOKsemicolon, "continue statement");
- s = new ContinueStatement(loc, ident);
- break;
- }
-
- case TOKgoto:
- { Identifier *ident;
-
- nextToken();
- if (token.value == TOKdefault)
- {
- nextToken();
- s = new GotoDefaultStatement(loc);
- }
- else if (token.value == TOKcase)
- {
- Expression *exp = NULL;
-
- nextToken();
- if (token.value != TOKsemicolon)
- exp = parseExpression();
- s = new GotoCaseStatement(loc, exp);
- }
- else
- {
- if (token.value != TOKidentifier)
- {
- error("identifier expected following goto");
- ident = NULL;
- }
- else
- {
- ident = token.ident;
- nextToken();
- }
- s = new GotoStatement(loc, ident);
- }
- check(TOKsemicolon, "goto statement");
- break;
- }
-
- case TOKsynchronized:
- { Expression *exp;
- Statement *body;
-
- Token *t = peek(&token);
- if (skipAttributes(t, &t) && t->value == TOKclass)
- goto Ldeclaration;
-
- nextToken();
- if (token.value == TOKlparen)
- {
- nextToken();
- exp = parseExpression();
- check(TOKrparen);
- }
- else
- exp = NULL;
- body = parseStatement(PSscope);
- s = new SynchronizedStatement(loc, exp, body);
- break;
- }
-
- case TOKwith:
- { Expression *exp;
- Statement *body;
-
- nextToken();
- check(TOKlparen);
- exp = parseExpression();
- check(TOKrparen);
- body = parseStatement(PSscope);
- s = new WithStatement(loc, exp, body, token.loc);
- break;
- }
-
- case TOKtry:
- { Statement *body;
- Catches *catches = NULL;
- Statement *finalbody = NULL;
-
- nextToken();
- Loc lookingForElseSave = lookingForElse;
- lookingForElse = Loc();
- body = parseStatement(PSscope);
- lookingForElse = lookingForElseSave;
- while (token.value == TOKcatch)
- {
- Statement *handler;
- Catch *c;
- Type *t;
- Identifier *id;
- Loc catchloc = token.loc;
-
- nextToken();
- if (token.value == TOKlcurly || token.value != TOKlparen)
- {
- t = NULL;
- id = NULL;
- }
- else
- {
- check(TOKlparen);
- id = NULL;
- t = parseType(&id);
- check(TOKrparen);
- }
- handler = parseStatement(0);
- c = new Catch(catchloc, t, id, handler);
- if (!catches)
- catches = new Catches();
- catches->push(c);
- }
-
- if (token.value == TOKfinally)
- {
- nextToken();
- finalbody = parseStatement(PSscope);
- }
-
- s = body;
- if (!catches && !finalbody)
- error("catch or finally expected following try");
- else
- { if (catches)
- s = new TryCatchStatement(loc, body, catches);
- if (finalbody)
- s = new TryFinallyStatement(loc, s, finalbody);
- }
- break;
- }
-
- case TOKthrow:
- { Expression *exp;
-
- nextToken();
- exp = parseExpression();
- check(TOKsemicolon, "throw statement");
- s = new ThrowStatement(loc, exp);
- break;
- }
-
- case TOKasm:
- {
- // Parse the asm block into a sequence of AsmStatements,
- // each AsmStatement is one instruction.
- // Separate out labels.
- // Defer parsing of AsmStatements until semantic processing.
-
- Loc labelloc;
-
- nextToken();
- StorageClass stc = parsePostfix(STCundefined, NULL);
- if (stc & (STCconst | STCimmutable | STCshared | STCwild))
- error("const/immutable/shared/inout attributes are not allowed on asm blocks");
-
- check(TOKlcurly);
- Token *toklist = NULL;
- Token **ptoklist = &toklist;
- Identifier *label = NULL;
- Statements *statements = new Statements();
- size_t nestlevel = 0;
- while (1)
- {
- switch (token.value)
- {
- case TOKidentifier:
- if (!toklist)
- {
- // Look ahead to see if it is a label
- Token *t = peek(&token);
- if (t->value == TOKcolon)
- { // It's a label
- label = token.ident;
- labelloc = token.loc;
- nextToken();
- nextToken();
- continue;
- }
- }
- goto Ldefault;
-
- case TOKlcurly:
- ++nestlevel;
- goto Ldefault;
-
- case TOKrcurly:
- if (nestlevel > 0)
- {
- --nestlevel;
- goto Ldefault;
- }
-
- if (toklist || label)
- {
- error("asm statements must end in `;`");
- }
- break;
-
- case TOKsemicolon:
- if (nestlevel != 0)
- error("mismatched number of curly brackets");
-
- s = NULL;
- if (toklist || label)
- {
- // Create AsmStatement from list of tokens we've saved
- s = new AsmStatement(token.loc, toklist);
- toklist = NULL;
- ptoklist = &toklist;
- if (label)
- { s = new LabelStatement(labelloc, label, s);
- label = NULL;
- }
- statements->push(s);
- }
- nextToken();
- continue;
-
- case TOKeof:
- /* { */
- error("matching `}` expected, not end of file");
- goto Lerror;
- /* fall through */
-
- default:
- Ldefault:
- *ptoklist = Token::alloc();
- memcpy(*ptoklist, &token, sizeof(Token));
- ptoklist = &(*ptoklist)->next;
- *ptoklist = NULL;
-
- nextToken();
- continue;
- }
- break;
- }
- s = new CompoundAsmStatement(loc, statements, stc);
- nextToken();
- break;
- }
-
- case TOKimport:
- {
- Dsymbols *imports = parseImport();
- s = new ImportStatement(loc, imports);
- if (flags & PSscope)
- s = new ScopeStatement(loc, s, token.loc);
- break;
- }
-
- case TOKtemplate:
- {
- Dsymbol *d = parseTemplateDeclaration();
- s = new ExpStatement(loc, d);
- break;
- }
-
- default:
- error("found `%s` instead of statement", token.toChars());
- goto Lerror;
-
- Lerror:
- while (token.value != TOKrcurly &&
- token.value != TOKsemicolon &&
- token.value != TOKeof)
- nextToken();
- if (token.value == TOKsemicolon)
- nextToken();
- s = NULL;
- break;
- }
- if (pEndloc)
- *pEndloc = token.loc;
- return s;
-}
-
-void Parser::check(TOK value)
-{
- check(token.loc, value);
-}
-
-void Parser::check(Loc loc, TOK value)
-{
- if (token.value != value)
- error(loc, "found `%s` when expecting `%s`", token.toChars(), Token::toChars(value));
- nextToken();
-}
-
-void Parser::check(TOK value, const char *string)
-{
- if (token.value != value)
- error("found `%s` when expecting `%s` following %s",
- token.toChars(), Token::toChars(value), string);
- nextToken();
-}
-
-void Parser::checkParens(TOK value, Expression *e)
-{
- if (precedence[e->op] == PREC_rel && !e->parens)
- error(e->loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value));
-}
-
-/************************************
- * Determine if the scanner is sitting on the start of a declaration.
- * Input:
- * needId 0 no identifier
- * 1 identifier optional
- * 2 must have identifier
- * 3 must have identifier, but don't recognize old C-style syntax.
- * Output:
- * if *pt is not NULL, it is set to the ending token, which would be endtok
- */
-
-bool Parser::isDeclaration(Token *t, int needId, TOK endtok, Token **pt)
-{
- //printf("isDeclaration(needId = %d)\n", needId);
- int haveId = 0;
- int haveTpl = 0;
-
- while (1)
- {
- if ((t->value == TOKconst ||
- t->value == TOKimmutable ||
- t->value == TOKwild ||
- t->value == TOKshared) &&
- peek(t)->value != TOKlparen)
- {
- /* const type
- * immutable type
- * shared type
- * wild type
- */
- t = peek(t);
- continue;
- }
- break;
- }
-
- if (!isBasicType(&t))
- {
- goto Lisnot;
- }
- if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != 3))
- goto Lisnot;
- if ((needId == 0 && !haveId) ||
- (needId == 1) ||
- (needId == 2 && haveId) ||
- (needId == 3 && haveId))
- {
- if (pt)
- *pt = t;
- goto Lis;
- }
- else
- goto Lisnot;
-
-Lis:
- //printf("\tis declaration, t = %s\n", t->toChars());
- return true;
-
-Lisnot:
- //printf("\tis not declaration\n");
- return false;
-}
-
-bool Parser::isBasicType(Token **pt)
-{
- // This code parallels parseBasicType()
- Token *t = *pt;
-
- switch (t->value)
- {
- case TOKwchar: case TOKdchar:
- case TOKbool: case TOKchar:
- case TOKint8: case TOKuns8:
- case TOKint16: case TOKuns16:
- case TOKint32: case TOKuns32:
- case TOKint64: case TOKuns64:
- case TOKint128: case TOKuns128:
- case TOKfloat32: case TOKfloat64: case TOKfloat80:
- case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
- case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
- case TOKvoid:
- t = peek(t);
- break;
-
- case TOKidentifier:
- L5:
- t = peek(t);
- if (t->value == TOKnot)
- {
- goto L4;
- }
- goto L3;
- while (1)
- {
- L2:
- t = peek(t);
- L3:
- if (t->value == TOKdot)
- {
- Ldot:
- t = peek(t);
- if (t->value != TOKidentifier)
- goto Lfalse;
- t = peek(t);
- if (t->value != TOKnot)
- goto L3;
- L4:
- /* Seen a !
- * Look for:
- * !( args ), !identifier, etc.
- */
- t = peek(t);
- switch (t->value)
- {
- case TOKidentifier:
- goto L5;
- case TOKlparen:
- if (!skipParens(t, &t))
- goto Lfalse;
- goto L3;
- case TOKwchar: case TOKdchar:
- case TOKbool: case TOKchar:
- case TOKint8: case TOKuns8:
- case TOKint16: case TOKuns16:
- case TOKint32: case TOKuns32:
- case TOKint64: case TOKuns64:
- case TOKint128: case TOKuns128:
- case TOKfloat32: case TOKfloat64: case TOKfloat80:
- case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
- case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
- case TOKvoid:
- case TOKint32v:
- case TOKuns32v:
- case TOKint64v:
- case TOKuns64v:
- case TOKint128v:
- case TOKuns128v:
- case TOKfloat32v:
- case TOKfloat64v:
- case TOKfloat80v:
- case TOKimaginary32v:
- case TOKimaginary64v:
- case TOKimaginary80v:
- case TOKnull:
- case TOKtrue:
- case TOKfalse:
- case TOKcharv:
- case TOKwcharv:
- case TOKdcharv:
- case TOKstring:
- case TOKxstring:
- case TOKfile:
- case TOKfilefullpath:
- case TOKline:
- case TOKmodulestring:
- case TOKfuncstring:
- case TOKprettyfunc:
- goto L2;
- default:
- goto Lfalse;
- }
- }
- else
- break;
- }
- break;
-
- case TOKdot:
- goto Ldot;
-
- case TOKtypeof:
- case TOKvector:
- case TOKmixin:
- /* typeof(exp).identifier...
- */
- t = peek(t);
- if (!skipParens(t, &t))
- goto Lfalse;
- goto L3;
-
- case TOKtraits:
- {
- // __traits(getMember
- t = peek(t);
- if (t->value != TOKlparen)
- goto Lfalse;
- Token *lp = t;
- t = peek(t);
- if (t->value != TOKidentifier || t->ident != Id::getMember)
- goto Lfalse;
- if (!skipParens(lp, &lp))
- goto Lfalse;
- // we are in a lookup for decl VS statement
- // so we expect a declarator following __trait if it's a type.
- // other usages wont be ambiguous (alias, template instance, type qual, etc.)
- if (lp->value != TOKidentifier)
- goto Lfalse;
-
- break;
- }
-
- case TOKconst:
- case TOKimmutable:
- case TOKshared:
- case TOKwild:
- // const(type) or immutable(type) or shared(type) or wild(type)
- t = peek(t);
- if (t->value != TOKlparen)
- goto Lfalse;
- t = peek(t);
- if (!isDeclaration(t, 0, TOKrparen, &t))
- {
- goto Lfalse;
- }
- t = peek(t);
- break;
-
- default:
- goto Lfalse;
- }
- *pt = t;
- //printf("is\n");
- return true;
-
-Lfalse:
- //printf("is not\n");
- return false;
-}
-
-bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, bool allowAltSyntax)
-{ // This code parallels parseDeclarator()
- Token *t = *pt;
- int parens;
-
- //printf("Parser::isDeclarator() %s\n", t->toChars());
- if (t->value == TOKassign)
- return false;
-
- while (1)
- {
- parens = false;
- switch (t->value)
- {
- case TOKmul:
- //case TOKand:
- t = peek(t);
- continue;
-
- case TOKlbracket:
- t = peek(t);
- if (t->value == TOKrbracket)
- {
- t = peek(t);
- }
- else if (isDeclaration(t, 0, TOKrbracket, &t))
- {
- // It's an associative array declaration
- t = peek(t);
-
- // ...[type].ident
- if (t->value == TOKdot && peek(t)->value == TOKidentifier)
- {
- t = peek(t);
- t = peek(t);
- }
- }
- else
- {
- // [ expression ]
- // [ expression .. expression ]
- if (!isExpression(&t))
- return false;
- if (t->value == TOKslice)
- {
- t = peek(t);
- if (!isExpression(&t))
- return false;
- if (t->value != TOKrbracket)
- return false;
- t = peek(t);
- }
- else
- {
- if (t->value != TOKrbracket)
- return false;
- t = peek(t);
-
- // ...[index].ident
- if (t->value == TOKdot && peek(t)->value == TOKidentifier)
- {
- t = peek(t);
- t = peek(t);
- }
- }
- }
- continue;
-
- case TOKidentifier:
- if (*haveId)
- return false;
- *haveId = true;
- t = peek(t);
- break;
-
- case TOKlparen:
- if (!allowAltSyntax)
- return false; // Do not recognize C-style declarations.
-
- t = peek(t);
-
- if (t->value == TOKrparen)
- return false; // () is not a declarator
-
- /* Regard ( identifier ) as not a declarator
- * BUG: what about ( *identifier ) in
- * f(*p)(x);
- * where f is a class instance with overloaded () ?
- * Should we just disallow C-style function pointer declarations?
- */
- if (t->value == TOKidentifier)
- { Token *t2 = peek(t);
- if (t2->value == TOKrparen)
- return false;
- }
-
-
- if (!isDeclarator(&t, haveId, NULL, TOKrparen))
- return false;
- t = peek(t);
- parens = true;
- break;
-
- case TOKdelegate:
- case TOKfunction:
- t = peek(t);
- if (!isParameters(&t))
- return false;
- skipAttributes(t, &t);
- continue;
- default: break;
- }
- break;
- }
-
- while (1)
- {
- switch (t->value)
- {
-#if CARRAYDECL
- case TOKlbracket:
- parens = false;
- t = peek(t);
- if (t->value == TOKrbracket)
- {
- t = peek(t);
- }
- else if (isDeclaration(t, 0, TOKrbracket, &t))
- { // It's an associative array declaration
- t = peek(t);
- }
- else
- {
- // [ expression ]
- if (!isExpression(&t))
- return false;
- if (t->value != TOKrbracket)
- return false;
- t = peek(t);
- }
- continue;
-#endif
-
- case TOKlparen:
- parens = false;
- if (Token *tk = peekPastParen(t))
- {
- if (tk->value == TOKlparen)
- {
- if (!haveTpl) return false;
- *haveTpl = 1;
- t = tk;
- }
- else if (tk->value == TOKassign)
- {
- if (!haveTpl) return false;
- *haveTpl = 1;
- *pt = tk;
- return true;
- }
- }
- if (!isParameters(&t))
- return false;
- while (1)
- {
- switch (t->value)
- {
- case TOKconst:
- case TOKimmutable:
- case TOKshared:
- case TOKwild:
- case TOKpure:
- case TOKnothrow:
- case TOKreturn:
- case TOKscope:
- t = peek(t);
- continue;
- case TOKat:
- t = peek(t); // skip '@'
- t = peek(t); // skip identifier
- continue;
- default:
- break;
- }
- break;
- }
- continue;
-
- case TOKidentifier:
- if (t->ident != Id::_body)
- goto Ldefault;
- /* fall through */
-
- // Valid tokens that follow a declaration
- case TOKrparen:
- case TOKrbracket:
- case TOKassign:
- case TOKcomma:
- case TOKdotdotdot:
- case TOKsemicolon:
- case TOKlcurly:
- case TOKin:
- case TOKout:
- case TOKdo:
- LTOKdo:
- // The !parens is to disallow unnecessary parentheses
- if (!parens && (endtok == TOKreserved || endtok == t->value))
- {
- *pt = t;
- return true;
- }
- return false;
-
- case TOKif:
- return haveTpl ? true : false;
-
- // Used for mixin type parsing
- case TOKeof:
- if (endtok == TOKeof)
- goto LTOKdo;
- return false;
-
- default:
- Ldefault:
- return false;
- }
- }
- assert(0);
-}
-
-
-bool Parser::isParameters(Token **pt)
-{ // This code parallels parseParameters()
- Token *t = *pt;
-
- //printf("isParameters()\n");
- if (t->value != TOKlparen)
- return false;
-
- t = peek(t);
- for (;1; t = peek(t))
- {
- L1:
- switch (t->value)
- {
- case TOKrparen:
- break;
-
- case TOKdotdotdot:
- t = peek(t);
- break;
-
- case TOKin:
- case TOKout:
- case TOKref:
- case TOKlazy:
- case TOKscope:
- case TOKfinal:
- case TOKauto:
- case TOKreturn:
- continue;
-
- case TOKconst:
- case TOKimmutable:
- case TOKshared:
- case TOKwild:
- t = peek(t);
- if (t->value == TOKlparen)
- {
- t = peek(t);
- if (!isDeclaration(t, 0, TOKrparen, &t))
- return false;
- t = peek(t); // skip past closing ')'
- goto L2;
- }
- goto L1;
-
- default:
- { if (!isBasicType(&t))
- return false;
- L2:
- int tmp = false;
- if (t->value != TOKdotdotdot &&
- !isDeclarator(&t, &tmp, NULL, TOKreserved))
- return false;
- if (t->value == TOKassign)
- { t = peek(t);
- if (!isExpression(&t))
- return false;
- }
- if (t->value == TOKdotdotdot)
- {
- t = peek(t);
- break;
- }
- }
- if (t->value == TOKcomma)
- {
- continue;
- }
- break;
- }
- break;
- }
- if (t->value != TOKrparen)
- return false;
- t = peek(t);
- *pt = t;
- return true;
-}
-
-bool Parser::isExpression(Token **pt)
-{
- // This is supposed to determine if something is an expression.
- // What it actually does is scan until a closing right bracket
- // is found.
-
- Token *t = *pt;
- int brnest = 0;
- int panest = 0;
- int curlynest = 0;
-
- for (;; t = peek(t))
- {
- switch (t->value)
- {
- case TOKlbracket:
- brnest++;
- continue;
-
- case TOKrbracket:
- if (--brnest >= 0)
- continue;
- break;
-
- case TOKlparen:
- panest++;
- continue;
-
- case TOKcomma:
- if (brnest || panest)
- continue;
- break;
-
- case TOKrparen:
- if (--panest >= 0)
- continue;
- break;
-
- case TOKlcurly:
- curlynest++;
- continue;
-
- case TOKrcurly:
- if (--curlynest >= 0)
- continue;
- return false;
-
- case TOKslice:
- if (brnest)
- continue;
- break;
-
- case TOKsemicolon:
- if (curlynest)
- continue;
- return false;
-
- case TOKeof:
- return false;
-
- default:
- continue;
- }
- break;
- }
-
- *pt = t;
- return true;
-}
-
-/*******************************************
- * Skip parens, brackets.
- * Input:
- * t is on opening (
- * Output:
- * *pt is set to closing token, which is ')' on success
- * Returns:
- * true successful
- * false some parsing error
- */
-
-bool Parser::skipParens(Token *t, Token **pt)
-{
- if (t->value != TOKlparen)
- return false;
-
- int parens = 0;
-
- while (1)
- {
- switch (t->value)
- {
- case TOKlparen:
- parens++;
- break;
-
- case TOKrparen:
- parens--;
- if (parens < 0)
- goto Lfalse;
- if (parens == 0)
- goto Ldone;
- break;
-
- case TOKeof:
- goto Lfalse;
-
- default:
- break;
- }
- t = peek(t);
- }
-
- Ldone:
- if (pt)
- *pt = peek(t); // skip found rparen
- return true;
-
- Lfalse:
- return false;
-}
-
-bool Parser::skipParensIf(Token *t, Token **pt)
-{
- if (t->value != TOKlparen)
- {
- if (pt)
- *pt = t;
- return true;
- }
- return skipParens(t, pt);
-}
-
-/*******************************************
- * Skip attributes.
- * Input:
- * t is on a candidate attribute
- * Output:
- * *pt is set to first non-attribute token on success
- * Returns:
- * true successful
- * false some parsing error
- */
-
-bool Parser::skipAttributes(Token *t, Token **pt)
-{
- while (1)
- {
- switch (t->value)
- {
- case TOKconst:
- case TOKimmutable:
- case TOKshared:
- case TOKwild:
- case TOKfinal:
- case TOKauto:
- case TOKscope:
- case TOKoverride:
- case TOKabstract:
- case TOKsynchronized:
- break;
- case TOKdeprecated:
- if (peek(t)->value == TOKlparen)
- {
- t = peek(t);
- if (!skipParens(t, &t))
- goto Lerror;
- // t is on the next of closing parenthesis
- continue;
- }
- break;
- case TOKnothrow:
- case TOKpure:
- case TOKref:
- case TOKgshared:
- case TOKreturn:
- //case TOKmanifest:
- break;
- case TOKat:
- t = peek(t);
- if (t->value == TOKidentifier)
- {
- /* @identifier
- * @identifier!arg
- * @identifier!(arglist)
- * any of the above followed by (arglist)
- * @predefined_attribute
- */
- if (t->ident == Id::property ||
- t->ident == Id::nogc ||
- t->ident == Id::safe ||
- t->ident == Id::trusted ||
- t->ident == Id::system ||
- t->ident == Id::disable)
- break;
- t = peek(t);
- if (t->value == TOKnot)
- {
- t = peek(t);
- if (t->value == TOKlparen)
- {
- // @identifier!(arglist)
- if (!skipParens(t, &t))
- goto Lerror;
- // t is on the next of closing parenthesis
- }
- else
- {
- // @identifier!arg
- // Do low rent skipTemplateArgument
- if (t->value == TOKvector)
- {
- // identifier!__vector(type)
- t = peek(t);
- if (!skipParens(t, &t))
- goto Lerror;
- }
- else
- t = peek(t);
- }
- }
- if (t->value == TOKlparen)
- {
- if (!skipParens(t, &t))
- goto Lerror;
- // t is on the next of closing parenthesis
- continue;
- }
- continue;
- }
- if (t->value == TOKlparen)
- {
- // @( ArgumentList )
- if (!skipParens(t, &t))
- goto Lerror;
- // t is on the next of closing parenthesis
- continue;
- }
- goto Lerror;
- default:
- goto Ldone;
- }
- t = peek(t);
- }
-
- Ldone:
- if (pt)
- *pt = t;
- return true;
-
- Lerror:
- return false;
-}
-
-/********************************* Expression Parser ***************************/
-
-Expression *Parser::parsePrimaryExp()
-{
- Expression *e;
- Type *t;
- Identifier *id;
- Loc loc = token.loc;
-
- //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
- switch (token.value)
- {
- case TOKidentifier:
- {
- Token *t1 = peek(&token);
- Token *t2 = peek(t1);
- if (t1->value == TOKmin && t2->value == TOKgt)
- {
- // skip ident.
- nextToken();
- nextToken();
- nextToken();
- error("use `.` for member lookup, not `->`");
- goto Lerr;
- }
-
- if (peekNext() == TOKgoesto)
- goto case_delegate;
-
- id = token.ident;
- nextToken();
- TOK save;
- if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin)
- {
- // identifier!(template-argument-list)
- TemplateInstance *tempinst;
- tempinst = new TemplateInstance(loc, id);
- tempinst->tiargs = parseTemplateArguments();
- e = new ScopeExp(loc, tempinst);
- }
- else
- e = new IdentifierExp(loc, id);
- break;
- }
-
- case TOKdollar:
- if (!inBrackets)
- error("`$` is valid only inside [] of index or slice");
- e = new DollarExp(loc);
- nextToken();
- break;
-
- case TOKdot:
- // Signal global scope '.' operator with "" identifier
- e = new IdentifierExp(loc, Id::empty);
- break;
-
- case TOKthis:
- e = new ThisExp(loc);
- nextToken();
- break;
-
- case TOKsuper:
- e = new SuperExp(loc);
- nextToken();
- break;
-
- case TOKint32v:
- e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32);
- nextToken();
- break;
-
- case TOKuns32v:
- e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32);
- nextToken();
- break;
-
- case TOKint64v:
- e = new IntegerExp(loc, token.int64value, Type::tint64);
- nextToken();
- break;
-
- case TOKuns64v:
- e = new IntegerExp(loc, token.uns64value, Type::tuns64);
- nextToken();
- break;
-
- case TOKfloat32v:
- e = new RealExp(loc, token.floatvalue, Type::tfloat32);
- nextToken();
- break;
-
- case TOKfloat64v:
- e = new RealExp(loc, token.floatvalue, Type::tfloat64);
- nextToken();
- break;
-
- case TOKfloat80v:
- e = new RealExp(loc, token.floatvalue, Type::tfloat80);
- nextToken();
- break;
-
- case TOKimaginary32v:
- e = new RealExp(loc, token.floatvalue, Type::timaginary32);
- nextToken();
- break;
-
- case TOKimaginary64v:
- e = new RealExp(loc, token.floatvalue, Type::timaginary64);
- nextToken();
- break;
-
- case TOKimaginary80v:
- e = new RealExp(loc, token.floatvalue, Type::timaginary80);
- nextToken();
- break;
-
- case TOKnull:
- e = new NullExp(loc);
- nextToken();
- break;
-
- case TOKfile:
- {
- const char *s = loc.filename ? loc.filename : mod->ident->toChars();
- e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
- nextToken();
- break;
- }
-
- case TOKfilefullpath:
- {
- assert(loc.filename); // __FILE_FULL_PATH__ does not work with an invalid location
- const char *s = FileName::toAbsolute(loc.filename);
- e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
- nextToken();
- break;
- }
-
- case TOKline:
- e = new IntegerExp(loc, loc.linnum, Type::tint32);
- nextToken();
- break;
-
- case TOKmodulestring:
- {
- const char *s = md ? md->toChars() : mod->toChars();
- e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
- nextToken();
- break;
- }
-
- case TOKfuncstring:
- e = new FuncInitExp(loc);
- nextToken();
- break;
-
- case TOKprettyfunc:
- e = new PrettyFuncInitExp(loc);
- nextToken();
- break;
-
- case TOKtrue:
- e = new IntegerExp(loc, 1, Type::tbool);
- nextToken();
- break;
-
- case TOKfalse:
- e = new IntegerExp(loc, 0, Type::tbool);
- nextToken();
- break;
-
- case TOKcharv:
- e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar);
- nextToken();
- break;
-
- case TOKwcharv:
- e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar);
- nextToken();
- break;
-
- case TOKdcharv:
- e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar);
- nextToken();
- break;
-
- case TOKstring:
- case TOKxstring:
- {
- // cat adjacent strings
- utf8_t *s = token.ustring;
- size_t len = token.len;
- unsigned char postfix = token.postfix;
- while (1)
- {
- const Token prev = token;
- nextToken();
- if (token.value == TOKstring ||
- token.value == TOKxstring)
- {
- if (token.postfix)
- { if (token.postfix != postfix)
- error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
- postfix = token.postfix;
- }
-
- deprecation("Implicit string concatenation is deprecated, use %s ~ %s instead",
- prev.toChars(), token.toChars());
-
- size_t len1 = len;
- size_t len2 = token.len;
- len = len1 + len2;
- utf8_t *s2 = (utf8_t *)mem.xmalloc((len + 1) * sizeof(utf8_t));
- memcpy(s2, s, len1 * sizeof(utf8_t));
- memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(utf8_t));
- s = s2;
- }
- else
- break;
- }
- e = new StringExp(loc, s, len, postfix);
- break;
- }
-
- case TOKvoid: t = Type::tvoid; goto LabelX;
- case TOKint8: t = Type::tint8; goto LabelX;
- case TOKuns8: t = Type::tuns8; goto LabelX;
- case TOKint16: t = Type::tint16; goto LabelX;
- case TOKuns16: t = Type::tuns16; goto LabelX;
- case TOKint32: t = Type::tint32; goto LabelX;
- case TOKuns32: t = Type::tuns32; goto LabelX;
- case TOKint64: t = Type::tint64; goto LabelX;
- case TOKuns64: t = Type::tuns64; goto LabelX;
- case TOKint128: t = Type::tint128; goto LabelX;
- case TOKuns128: t = Type::tuns128; goto LabelX;
- case TOKfloat32: t = Type::tfloat32; goto LabelX;
- case TOKfloat64: t = Type::tfloat64; goto LabelX;
- case TOKfloat80: t = Type::tfloat80; goto LabelX;
- case TOKimaginary32: t = Type::timaginary32; goto LabelX;
- case TOKimaginary64: t = Type::timaginary64; goto LabelX;
- case TOKimaginary80: t = Type::timaginary80; goto LabelX;
- case TOKcomplex32: t = Type::tcomplex32; goto LabelX;
- case TOKcomplex64: t = Type::tcomplex64; goto LabelX;
- case TOKcomplex80: t = Type::tcomplex80; goto LabelX;
- case TOKbool: t = Type::tbool; goto LabelX;
- case TOKchar: t = Type::tchar; goto LabelX;
- case TOKwchar: t = Type::twchar; goto LabelX;
- case TOKdchar: t = Type::tdchar; goto LabelX;
- LabelX:
- nextToken();
- if (token.value == TOKlparen)
- {
- e = new TypeExp(loc, t);
- e = new CallExp(loc, e, parseArguments());
- break;
- }
- check(TOKdot, t->toChars());
- if (token.value != TOKidentifier)
- { error("found `%s` when expecting identifier following `%s.`", token.toChars(), t->toChars());
- goto Lerr;
- }
- e = typeDotIdExp(loc, t, token.ident);
- nextToken();
- break;
-
- case TOKtypeof:
- {
- t = parseTypeof();
- e = new TypeExp(loc, t);
- break;
- }
-
- case TOKvector:
- {
- t = parseVector();
- e = new TypeExp(loc, t);
- break;
- }
-
- case TOKtypeid:
- {
- nextToken();
- check(TOKlparen, "typeid");
- RootObject *o = parseTypeOrAssignExp();
- check(TOKrparen);
- e = new TypeidExp(loc, o);
- break;
- }
-
- case TOKtraits:
- { /* __traits(identifier, args...)
- */
- Identifier *ident;
- Objects *args = NULL;
-
- nextToken();
- check(TOKlparen);
- if (token.value != TOKidentifier)
- { error("__traits(identifier, args...) expected");
- goto Lerr;
- }
- ident = token.ident;
- nextToken();
- if (token.value == TOKcomma)
- args = parseTemplateArgumentList(); // __traits(identifier, args...)
- else
- check(TOKrparen); // __traits(identifier)
-
- e = new TraitsExp(loc, ident, args);
- break;
- }
-
- case TOKis:
- {
- Type *targ;
- Identifier *ident = NULL;
- Type *tspec = NULL;
- TOK tok = TOKreserved;
- TOK tok2 = TOKreserved;
- TemplateParameters *tpl = NULL;
-
- nextToken();
- if (token.value == TOKlparen)
- {
- nextToken();
- if (token.value == TOKidentifier && peekNext() == TOKlparen)
- {
- error(loc, "unexpected `(` after `%s`, inside `is` expression. Try enclosing the contents of `is` with a `typeof` expression", token.toChars());
- nextToken();
- Token *tempTok = peekPastParen(&token);
- memcpy(&token, tempTok, sizeof(Token));
- goto Lerr;
- }
- targ = parseType(&ident);
- if (token.value == TOKcolon || token.value == TOKequal)
- {
- tok = token.value;
- nextToken();
- if (tok == TOKequal &&
- (token.value == TOKstruct ||
- token.value == TOKunion ||
- token.value == TOKclass ||
- token.value == TOKsuper ||
- token.value == TOKenum ||
- token.value == TOKinterface ||
- token.value == TOKmodule ||
- token.value == TOKpackage ||
- token.value == TOKargTypes ||
- token.value == TOKparameters ||
- (token.value == TOKconst && peek(&token)->value == TOKrparen) ||
- (token.value == TOKimmutable && peek(&token)->value == TOKrparen) ||
- (token.value == TOKshared && peek(&token)->value == TOKrparen) ||
- (token.value == TOKwild && peek(&token)->value == TOKrparen) ||
- token.value == TOKfunction ||
- token.value == TOKdelegate ||
- token.value == TOKreturn ||
- (token.value == TOKvector && peek(&token)->value == TOKrparen)))
- {
- tok2 = token.value;
- nextToken();
- }
- else
- {
- tspec = parseType();
- }
- }
- if (tspec)
- {
- if (token.value == TOKcomma)
- tpl = parseTemplateParameterList(1);
- else
- {
- tpl = new TemplateParameters();
- check(TOKrparen);
- }
- }
- else
- check(TOKrparen);
- }
- else
- {
- error("(type identifier : specialization) expected following is");
- goto Lerr;
- }
- e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
- break;
- }
-
- case TOKassert:
- { Expression *msg = NULL;
-
- nextToken();
- check(TOKlparen, "assert");
- e = parseAssignExp();
- if (token.value == TOKcomma)
- {
- nextToken();
- if (token.value != TOKrparen)
- {
- msg = parseAssignExp();
- if (token.value == TOKcomma)
- nextToken();
- }
- }
- check(TOKrparen);
- e = new AssertExp(loc, e, msg);
- break;
- }
-
- case TOKmixin:
- {
- // https://dlang.org/spec/expression.html#mixin_expressions
- nextToken();
- if (token.value != TOKlparen)
- error("found `%s` when expecting `%s` following %s", token.toChars(), Token::toChars(TOKlparen), "`mixin`");
- e = new CompileExp(loc, parseArguments());
- break;
- }
-
- case TOKimport:
- {
- nextToken();
- check(TOKlparen, "import");
- e = parseAssignExp();
- check(TOKrparen);
- e = new ImportExp(loc, e);
- break;
- }
-
- case TOKnew:
- e = parseNewExp(NULL);
- break;
-
- case TOKref:
- {
- if (peekNext() == TOKlparen)
- {
- Token *tk = peekPastParen(peek(&token));
- if (skipAttributes(tk, &tk) &&
- (tk->value == TOKgoesto || tk->value == TOKlcurly))
- {
- // ref (arguments) => expression
- // ref (arguments) { statements... }
- goto case_delegate;
- }
- }
- nextToken();
- error("found `%s` when expecting function literal following `ref`", token.toChars());
- goto Lerr;
- }
-
- case TOKlparen:
- {
- Token *tk = peekPastParen(&token);
- if (skipAttributes(tk, &tk) &&
- (tk->value == TOKgoesto || tk->value == TOKlcurly))
- {
- // (arguments) => expression
- // (arguments) { statements... }
- goto case_delegate;
- }
-
- // ( expression )
- nextToken();
- e = parseExpression();
- e->parens = 1;
- check(loc, TOKrparen);
- break;
- }
-
- case TOKlbracket:
- { /* Parse array literals and associative array literals:
- * [ value, value, value ... ]
- * [ key:value, key:value, key:value ... ]
- */
- Expressions *values = new Expressions();
- Expressions *keys = NULL;
-
- nextToken();
- while (token.value != TOKrbracket && token.value != TOKeof)
- {
- e = parseAssignExp();
- if (token.value == TOKcolon && (keys || values->length == 0))
- { nextToken();
- if (!keys)
- keys = new Expressions();
- keys->push(e);
- e = parseAssignExp();
- }
- else if (keys)
- { error("`key:value` expected for associative array literal");
- delete keys;
- keys = NULL;
- }
- values->push(e);
- if (token.value == TOKrbracket)
- break;
- check(TOKcomma);
- }
- check(loc, TOKrbracket);
-
- if (keys)
- e = new AssocArrayLiteralExp(loc, keys, values);
- else
- e = new ArrayLiteralExp(loc, NULL, values);
- break;
- }
-
- case TOKlcurly:
- case TOKfunction:
- case TOKdelegate:
- case_delegate:
- {
- Dsymbol *s = parseFunctionLiteral();
- e = new FuncExp(loc, s);
- break;
- }
-
- default:
- error("expression expected, not `%s`", token.toChars());
- Lerr:
- // Anything for e, as long as it's not NULL
- e = new IntegerExp(loc, 0, Type::tint32);
- nextToken();
- break;
- }
- return e;
-}
-
-Expression *Parser::parsePostExp(Expression *e)
-{
- Loc loc;
-
- while (1)
- {
- loc = token.loc;
- switch (token.value)
- {
- case TOKdot:
- nextToken();
- if (token.value == TOKidentifier)
- { Identifier *id = token.ident;
-
- nextToken();
- if (token.value == TOKnot && peekNext() != TOKis && peekNext() != TOKin)
- {
- Objects *tiargs = parseTemplateArguments();
- e = new DotTemplateInstanceExp(loc, e, id, tiargs);
- }
- else
- e = new DotIdExp(loc, e, id);
- continue;
- }
- else if (token.value == TOKnew)
- {
- e = parseNewExp(e);
- continue;
- }
- else
- error("identifier expected following `.`, not `%s`", token.toChars());
- break;
-
- case TOKplusplus:
- e = new PostExp(TOKplusplus, loc, e);
- break;
-
- case TOKminusminus:
- e = new PostExp(TOKminusminus, loc, e);
- break;
-
- case TOKlparen:
- e = new CallExp(loc, e, parseArguments());
- continue;
-
- case TOKlbracket:
- { // array dereferences:
- // array[index]
- // array[]
- // array[lwr .. upr]
- Expression *index;
- Expression *upr;
- Expressions *arguments = new Expressions();
-
- inBrackets++;
- nextToken();
- while (token.value != TOKrbracket && token.value != TOKeof)
- {
- index = parseAssignExp();
- if (token.value == TOKslice)
- {
- // array[..., lwr..upr, ...]
- nextToken();
- upr = parseAssignExp();
- arguments->push(new IntervalExp(loc, index, upr));
- }
- else
- arguments->push(index);
- if (token.value == TOKrbracket)
- break;
- check(TOKcomma);
- }
- check(TOKrbracket);
- inBrackets--;
- e = new ArrayExp(loc, e, arguments);
- continue;
- }
-
- default:
- return e;
- }
- nextToken();
- }
-}
-
-Expression *Parser::parseUnaryExp()
-{
- Expression *e;
- Loc loc = token.loc;
-
- switch (token.value)
- {
- case TOKand:
- nextToken();
- e = parseUnaryExp();
- e = new AddrExp(loc, e);
- break;
-
- case TOKplusplus:
- nextToken();
- e = parseUnaryExp();
- //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
- e = new PreExp(TOKpreplusplus, loc, e);
- break;
-
- case TOKminusminus:
- nextToken();
- e = parseUnaryExp();
- //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
- e = new PreExp(TOKpreminusminus, loc, e);
- break;
-
- case TOKmul:
- nextToken();
- e = parseUnaryExp();
- e = new PtrExp(loc, e);
- break;
-
- case TOKmin:
- nextToken();
- e = parseUnaryExp();
- e = new NegExp(loc, e);
- break;
-
- case TOKadd:
- nextToken();
- e = parseUnaryExp();
- e = new UAddExp(loc, e);
- break;
-
- case TOKnot:
- nextToken();
- e = parseUnaryExp();
- e = new NotExp(loc, e);
- break;
-
- case TOKtilde:
- nextToken();
- e = parseUnaryExp();
- e = new ComExp(loc, e);
- break;
-
- case TOKdelete:
- nextToken();
- e = parseUnaryExp();
- e = new DeleteExp(loc, e, false);
- break;
-
- case TOKcast: // cast(type) expression
- {
- nextToken();
- check(TOKlparen);
- /* Look for cast(), cast(const), cast(immutable),
- * cast(shared), cast(shared const), cast(wild), cast(shared wild)
- */
- unsigned char m = 0;
- while (1)
- {
- switch (token.value)
- {
- case TOKconst:
- if (peekNext() == TOKlparen)
- break; // const as type constructor
- m |= MODconst; // const as storage class
- nextToken();
- continue;
-
- case TOKimmutable:
- if (peekNext() == TOKlparen)
- break;
- m |= MODimmutable;
- nextToken();
- continue;
-
- case TOKshared:
- if (peekNext() == TOKlparen)
- break;
- m |= MODshared;
- nextToken();
- continue;
-
- case TOKwild:
- if (peekNext() == TOKlparen)
- break;
- m |= MODwild;
- nextToken();
- continue;
-
- default:
- break;
- }
- break;
- }
- if (token.value == TOKrparen)
- {
- nextToken();
- e = parseUnaryExp();
- e = new CastExp(loc, e, m);
- }
- else
- {
- Type *t = parseType(); // cast( type )
- t = t->addMod(m); // cast( const type )
- check(TOKrparen);
- e = parseUnaryExp();
- e = new CastExp(loc, e, t);
- }
- break;
- }
-
- case TOKwild:
- case TOKshared:
- case TOKconst:
- case TOKimmutable: // immutable(type)(arguments) / immutable(type).init
- {
- StorageClass stc = parseTypeCtor();
- Type *t = parseBasicType();
- t = t->addSTC(stc);
- e = new TypeExp(loc, t);
- if (stc == 0 && token.value == TOKdot)
- {
- nextToken();
- if (token.value != TOKidentifier)
- {
- error("identifier expected following (type).");
- return NULL;
- }
- e = typeDotIdExp(loc, t, token.ident);
- nextToken();
- e = parsePostExp(e);
- break;
- }
- else if (token.value != TOKlparen)
- {
- error("(arguments) expected following %s", t->toChars());
- return e;
- }
- e = new CallExp(loc, e, parseArguments());
- break;
- }
-
-
- case TOKlparen:
- { Token *tk;
-
- tk = peek(&token);
-#if CCASTSYNTAX
- // If cast
- if (isDeclaration(tk, 0, TOKrparen, &tk))
- {
- tk = peek(tk); // skip over right parenthesis
- switch (tk->value)
- {
- case TOKnot:
- tk = peek(tk);
- if (tk->value == TOKis || tk->value == TOKin) // !is or !in
- break;
- /* fall through */
-
- case TOKdot:
- case TOKplusplus:
- case TOKminusminus:
- case TOKdelete:
- case TOKnew:
- case TOKlparen:
- case TOKidentifier:
- case TOKthis:
- case TOKsuper:
- case TOKint32v:
- case TOKuns32v:
- case TOKint64v:
- case TOKuns64v:
- case TOKint128v:
- case TOKuns128v:
- case TOKfloat32v:
- case TOKfloat64v:
- case TOKfloat80v:
- case TOKimaginary32v:
- case TOKimaginary64v:
- case TOKimaginary80v:
- case TOKnull:
- case TOKtrue:
- case TOKfalse:
- case TOKcharv:
- case TOKwcharv:
- case TOKdcharv:
- case TOKstring:
- case TOKfunction:
- case TOKdelegate:
- case TOKtypeof:
- case TOKtraits:
- case TOKvector:
- case TOKfile:
- case TOKfilefullpath:
- case TOKline:
- case TOKmodulestring:
- case TOKfuncstring:
- case TOKprettyfunc:
- case TOKwchar: case TOKdchar:
- case TOKbool: case TOKchar:
- case TOKint8: case TOKuns8:
- case TOKint16: case TOKuns16:
- case TOKint32: case TOKuns32:
- case TOKint64: case TOKuns64:
- case TOKint128: case TOKuns128:
- case TOKfloat32: case TOKfloat64: case TOKfloat80:
- case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
- case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
- case TOKvoid:
- { // (type) una_exp
- Type *t;
-
- nextToken();
- t = parseType();
- check(TOKrparen);
-
- // if .identifier
- // or .identifier!( ... )
- if (token.value == TOKdot)
- {
- if (peekNext() != TOKidentifier && peekNext() != TOKnew)
- {
- error("identifier or new keyword expected following (...).");
- return NULL;
- }
- e = new TypeExp(loc, t);
- e->parens = 1;
- e = parsePostExp(e);
- }
- else
- {
- e = parseUnaryExp();
- e = new CastExp(loc, e, t);
- error("C style cast illegal, use %s", e->toChars());
- }
- return e;
- }
- default:
- break;
- }
- }
-#endif
- e = parsePrimaryExp();
- e = parsePostExp(e);
- break;
- }
- default:
- e = parsePrimaryExp();
- e = parsePostExp(e);
- break;
- }
- assert(e);
-
- // ^^ is right associative and has higher precedence than the unary operators
- while (token.value == TOKpow)
- {
- nextToken();
- Expression *e2 = parseUnaryExp();
- e = new PowExp(loc, e, e2);
- }
-
- return e;
-}
-
-Expression *Parser::parseMulExp()
-{
- Expression *e;
- Expression *e2;
- Loc loc = token.loc;
-
- e = parseUnaryExp();
- while (1)
- {
- switch (token.value)
- {
- case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
- case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
- case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
-
- default:
- break;
- }
- break;
- }
- return e;
-}
-
-Expression *Parser::parseAddExp()
-{
- Expression *e;
- Expression *e2;
- Loc loc = token.loc;
-
- e = parseMulExp();
- while (1)
- {
- switch (token.value)
- {
- case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
- case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
- case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
-
- default:
- break;
- }
- break;
- }
- return e;
-}
-
-Expression *Parser::parseShiftExp()
-{
- Expression *e;
- Expression *e2;
- Loc loc = token.loc;
-
- e = parseAddExp();
- while (1)
- {
- switch (token.value)
- {
- case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue;
- case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue;
- case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
-
- default:
- break;
- }
- break;
- }
- return e;
-}
-
-Expression *Parser::parseCmpExp()
-{
- Expression *e;
- Expression *e2;
- Token *t;
- Loc loc = token.loc;
-
- e = parseShiftExp();
- TOK op = token.value;
-
- switch (op)
- {
- case TOKequal:
- case TOKnotequal:
- nextToken();
- e2 = parseShiftExp();
- e = new EqualExp(op, loc, e, e2);
- break;
-
- case TOKis:
- op = TOKidentity;
- goto L1;
-
- case TOKnot:
- // Attempt to identify '!is'
- t = peek(&token);
- if (t->value == TOKin)
- {
- nextToken();
- nextToken();
- e2 = parseShiftExp();
- e = new InExp(loc, e, e2);
- e = new NotExp(loc, e);
- break;
- }
- if (t->value != TOKis)
- break;
- nextToken();
- op = TOKnotidentity;
- goto L1;
-
- L1:
- nextToken();
- e2 = parseShiftExp();
- e = new IdentityExp(op, loc, e, e2);
- break;
-
- case TOKlt:
- case TOKle:
- case TOKgt:
- case TOKge:
- case TOKunord:
- case TOKlg:
- case TOKleg:
- case TOKule:
- case TOKul:
- case TOKuge:
- case TOKug:
- case TOKue:
- nextToken();
- e2 = parseShiftExp();
- e = new CmpExp(op, loc, e, e2);
- break;
-
- case TOKin:
- nextToken();
- e2 = parseShiftExp();
- e = new InExp(loc, e, e2);
- break;
-
- default:
- break;
- }
- return e;
-}
-
-Expression *Parser::parseAndExp()
-{
- Loc loc = token.loc;
-
- Expression *e = parseCmpExp();
- while (token.value == TOKand)
- {
- checkParens(TOKand, e);
- nextToken();
- Expression *e2 = parseCmpExp();
- checkParens(TOKand, e2);
- e = new AndExp(loc,e,e2);
- loc = token.loc;
- }
- return e;
-}
-
-Expression *Parser::parseXorExp()
-{
- Loc loc = token.loc;
-
- Expression *e = parseAndExp();
- while (token.value == TOKxor)
- {
- checkParens(TOKxor, e);
- nextToken();
- Expression *e2 = parseAndExp();
- checkParens(TOKxor, e2);
- e = new XorExp(loc, e, e2);
- }
- return e;
-}
-
-Expression *Parser::parseOrExp()
-{
- Loc loc = token.loc;
-
- Expression *e = parseXorExp();
- while (token.value == TOKor)
- {
- checkParens(TOKor, e);
- nextToken();
- Expression *e2 = parseXorExp();
- checkParens(TOKor, e2);
- e = new OrExp(loc, e, e2);
- }
- return e;
-}
-
-Expression *Parser::parseAndAndExp()
-{
- Expression *e;
- Expression *e2;
- Loc loc = token.loc;
-
- e = parseOrExp();
- while (token.value == TOKandand)
- {
- nextToken();
- e2 = parseOrExp();
- e = new LogicalExp(loc, TOKandand, e, e2);
- }
- return e;
-}
-
-Expression *Parser::parseOrOrExp()
-{
- Expression *e;
- Expression *e2;
- Loc loc = token.loc;
-
- e = parseAndAndExp();
- while (token.value == TOKoror)
- {
- nextToken();
- e2 = parseAndAndExp();
- e = new LogicalExp(loc, TOKoror, e, e2);
- }
- return e;
-}
-
-Expression *Parser::parseCondExp()
-{
- Expression *e;
- Expression *e1;
- Expression *e2;
- Loc loc = token.loc;
-
- e = parseOrOrExp();
- if (token.value == TOKquestion)
- {
- nextToken();
- e1 = parseExpression();
- check(TOKcolon);
- e2 = parseCondExp();
- e = new CondExp(loc, e, e1, e2);
- }
- return e;
-}
-
-Expression *Parser::parseAssignExp()
-{
- Expression *e;
- Expression *e2;
- Loc loc;
-
- e = parseCondExp();
- while (1)
- {
- loc = token.loc;
- switch (token.value)
- {
- case TOKassign: nextToken(); e2 = parseAssignExp(); e = new AssignExp(loc,e,e2); continue;
- case TOKaddass: nextToken(); e2 = parseAssignExp(); e = new AddAssignExp(loc,e,e2); continue;
- case TOKminass: nextToken(); e2 = parseAssignExp(); e = new MinAssignExp(loc,e,e2); continue;
- case TOKmulass: nextToken(); e2 = parseAssignExp(); e = new MulAssignExp(loc,e,e2); continue;
- case TOKdivass: nextToken(); e2 = parseAssignExp(); e = new DivAssignExp(loc,e,e2); continue;
- case TOKmodass: nextToken(); e2 = parseAssignExp(); e = new ModAssignExp(loc,e,e2); continue;
- case TOKpowass: nextToken(); e2 = parseAssignExp(); e = new PowAssignExp(loc,e,e2); continue;
- case TOKandass: nextToken(); e2 = parseAssignExp(); e = new AndAssignExp(loc,e,e2); continue;
- case TOKorass: nextToken(); e2 = parseAssignExp(); e = new OrAssignExp(loc,e,e2); continue;
- case TOKxorass: nextToken(); e2 = parseAssignExp(); e = new XorAssignExp(loc,e,e2); continue;
- case TOKshlass: nextToken(); e2 = parseAssignExp(); e = new ShlAssignExp(loc,e,e2); continue;
- case TOKshrass: nextToken(); e2 = parseAssignExp(); e = new ShrAssignExp(loc,e,e2); continue;
- case TOKushrass: nextToken(); e2 = parseAssignExp(); e = new UshrAssignExp(loc,e,e2); continue;
- case TOKcatass: nextToken(); e2 = parseAssignExp(); e = new CatAssignExp(loc,e,e2); continue;
- default:
- break;
- }
- break;
- }
- return e;
-}
-
-Expression *Parser::parseExpression()
-{
- Expression *e;
- Expression *e2;
- Loc loc = token.loc;
-
- //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
- e = parseAssignExp();
- while (token.value == TOKcomma)
- {
- nextToken();
- e2 = parseAssignExp();
- e = new CommaExp(loc, e, e2, false);
- loc = token.loc;
- }
- return e;
-}
-
-
-/*************************
- * Collect argument list.
- * Assume current token is ',', '(' or '['.
- */
-
-Expressions *Parser::parseArguments()
-{ // function call
- Expressions *arguments;
- Expression *arg;
- TOK endtok;
-
- arguments = new Expressions();
- if (token.value == TOKlbracket)
- endtok = TOKrbracket;
- else
- endtok = TOKrparen;
-
- {
- nextToken();
- while (token.value != endtok && token.value != TOKeof)
- {
- arg = parseAssignExp();
- arguments->push(arg);
- if (token.value == endtok)
- break;
- check(TOKcomma);
- }
- check(endtok);
- }
- return arguments;
-}
-
-/*******************************************
- */
-
-Expression *Parser::parseNewExp(Expression *thisexp)
-{
- Type *t;
- Expressions *newargs;
- Expressions *arguments = NULL;
- Loc loc = token.loc;
-
- nextToken();
- newargs = NULL;
- if (token.value == TOKlparen)
- {
- newargs = parseArguments();
- }
-
- // An anonymous nested class starts with "class"
- if (token.value == TOKclass)
- {
- nextToken();
- if (token.value == TOKlparen)
- arguments = parseArguments();
-
- BaseClasses *baseclasses = NULL;
- if (token.value != TOKlcurly)
- baseclasses = parseBaseClasses();
-
- Identifier *id = NULL;
- Dsymbols *members = NULL;
-
- if (token.value != TOKlcurly)
- {
- error("{ members } expected for anonymous class");
- }
- else
- {
- nextToken();
- members = parseDeclDefs(0);
- if (token.value != TOKrcurly)
- error("class member expected");
- nextToken();
- }
-
- ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses, members, false);
- Expression *e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
-
- return e;
- }
-
- StorageClass stc = parseTypeCtor();
- t = parseBasicType(true);
- t = parseBasicType2(t);
- t = t->addSTC(stc);
- if (t->ty == Taarray)
- {
- TypeAArray *taa = (TypeAArray *)t;
- Type *index = taa->index;
-
- Expression *edim = typeToExpression(index);
- if (!edim)
- {
- error("need size of rightmost array, not type %s", index->toChars());
- return new NullExp(loc);
- }
- t = new TypeSArray(taa->next, edim);
- }
- else if (t->ty == Tsarray)
- {
- }
- else if (token.value == TOKlparen)
- {
- arguments = parseArguments();
- }
- Expression *e = new NewExp(loc, thisexp, newargs, t, arguments);
- return e;
-}
-
-/**********************************************
- */
-
-void Parser::addComment(Dsymbol *s, const utf8_t *blockComment)
-{
- s->addComment(combineComments(blockComment, token.lineComment));
- token.lineComment = NULL;
-}
-
-
-/**********************************
- * Set operator precedence for each operator.
- */
-
-PREC precedence[TOKMAX];
-
-struct PrecedenceInitializer
-{
- PrecedenceInitializer();
-};
-
-static PrecedenceInitializer precedenceinitializer;
-
-PrecedenceInitializer::PrecedenceInitializer()
-{
- for (size_t i = 0; i < TOKMAX; i++)
- precedence[i] = PREC_zero;
-
- precedence[TOKtype] = PREC_expr;
- precedence[TOKerror] = PREC_expr;
-
- precedence[TOKtypeof] = PREC_primary;
- precedence[TOKmixin] = PREC_primary;
- precedence[TOKimport] = PREC_primary;
-
- precedence[TOKdotvar] = PREC_primary;
- precedence[TOKscope] = PREC_primary;
- precedence[TOKidentifier] = PREC_primary;
- precedence[TOKthis] = PREC_primary;
- precedence[TOKsuper] = PREC_primary;
- precedence[TOKint64] = PREC_primary;
- precedence[TOKfloat64] = PREC_primary;
- precedence[TOKcomplex80] = PREC_primary;
- precedence[TOKnull] = PREC_primary;
- precedence[TOKstring] = PREC_primary;
- precedence[TOKarrayliteral] = PREC_primary;
- precedence[TOKassocarrayliteral] = PREC_primary;
- precedence[TOKclassreference] = PREC_primary;
- precedence[TOKfile] = PREC_primary;
- precedence[TOKfilefullpath] = PREC_primary;
- precedence[TOKline] = PREC_primary;
- precedence[TOKmodulestring] = PREC_primary;
- precedence[TOKfuncstring] = PREC_primary;
- precedence[TOKprettyfunc] = PREC_primary;
- precedence[TOKtypeid] = PREC_primary;
- precedence[TOKis] = PREC_primary;
- precedence[TOKassert] = PREC_primary;
- precedence[TOKhalt] = PREC_primary;
- precedence[TOKtemplate] = PREC_primary;
- precedence[TOKdsymbol] = PREC_primary;
- precedence[TOKfunction] = PREC_primary;
- precedence[TOKvar] = PREC_primary;
- precedence[TOKsymoff] = PREC_primary;
- precedence[TOKstructliteral] = PREC_primary;
- precedence[TOKarraylength] = PREC_primary;
- precedence[TOKdelegateptr] = PREC_primary;
- precedence[TOKdelegatefuncptr] = PREC_primary;
- precedence[TOKremove] = PREC_primary;
- precedence[TOKtuple] = PREC_primary;
- precedence[TOKtraits] = PREC_primary;
- precedence[TOKdefault] = PREC_primary;
- precedence[TOKoverloadset] = PREC_primary;
- precedence[TOKvoid] = PREC_primary;
- precedence[TOKvectorarray] = PREC_primary;
-
- // post
- precedence[TOKdotti] = PREC_primary;
- precedence[TOKdotid] = PREC_primary;
- precedence[TOKdottd] = PREC_primary;
- precedence[TOKdot] = PREC_primary;
- precedence[TOKdottype] = PREC_primary;
-// precedence[TOKarrow] = PREC_primary;
- precedence[TOKplusplus] = PREC_primary;
- precedence[TOKminusminus] = PREC_primary;
- precedence[TOKpreplusplus] = PREC_primary;
- precedence[TOKpreminusminus] = PREC_primary;
- precedence[TOKcall] = PREC_primary;
- precedence[TOKslice] = PREC_primary;
- precedence[TOKarray] = PREC_primary;
- precedence[TOKindex] = PREC_primary;
-
- precedence[TOKdelegate] = PREC_unary;
- precedence[TOKaddress] = PREC_unary;
- precedence[TOKstar] = PREC_unary;
- precedence[TOKneg] = PREC_unary;
- precedence[TOKuadd] = PREC_unary;
- precedence[TOKnot] = PREC_unary;
- precedence[TOKtilde] = PREC_unary;
- precedence[TOKdelete] = PREC_unary;
- precedence[TOKnew] = PREC_unary;
- precedence[TOKnewanonclass] = PREC_unary;
- precedence[TOKcast] = PREC_unary;
-
- precedence[TOKvector] = PREC_unary;
- precedence[TOKpow] = PREC_pow;
-
- precedence[TOKmul] = PREC_mul;
- precedence[TOKdiv] = PREC_mul;
- precedence[TOKmod] = PREC_mul;
-
- precedence[TOKadd] = PREC_add;
- precedence[TOKmin] = PREC_add;
- precedence[TOKcat] = PREC_add;
-
- precedence[TOKshl] = PREC_shift;
- precedence[TOKshr] = PREC_shift;
- precedence[TOKushr] = PREC_shift;
-
- precedence[TOKlt] = PREC_rel;
- precedence[TOKle] = PREC_rel;
- precedence[TOKgt] = PREC_rel;
- precedence[TOKge] = PREC_rel;
- precedence[TOKunord] = PREC_rel;
- precedence[TOKlg] = PREC_rel;
- precedence[TOKleg] = PREC_rel;
- precedence[TOKule] = PREC_rel;
- precedence[TOKul] = PREC_rel;
- precedence[TOKuge] = PREC_rel;
- precedence[TOKug] = PREC_rel;
- precedence[TOKue] = PREC_rel;
- precedence[TOKin] = PREC_rel;
-
- /* Note that we changed precedence, so that < and != have the same
- * precedence. This change is in the parser, too.
- */
- precedence[TOKequal] = PREC_rel;
- precedence[TOKnotequal] = PREC_rel;
- precedence[TOKidentity] = PREC_rel;
- precedence[TOKnotidentity] = PREC_rel;
-
- precedence[TOKand] = PREC_and;
-
- precedence[TOKxor] = PREC_xor;
-
- precedence[TOKor] = PREC_or;
-
- precedence[TOKandand] = PREC_andand;
-
- precedence[TOKoror] = PREC_oror;
-
- precedence[TOKquestion] = PREC_cond;
-
- precedence[TOKassign] = PREC_assign;
- precedence[TOKconstruct] = PREC_assign;
- precedence[TOKblit] = PREC_assign;
- precedence[TOKaddass] = PREC_assign;
- precedence[TOKminass] = PREC_assign;
- precedence[TOKcatass] = PREC_assign;
- precedence[TOKmulass] = PREC_assign;
- precedence[TOKdivass] = PREC_assign;
- precedence[TOKmodass] = PREC_assign;
- precedence[TOKpowass] = PREC_assign;
- precedence[TOKshlass] = PREC_assign;
- precedence[TOKshrass] = PREC_assign;
- precedence[TOKushrass] = PREC_assign;
- precedence[TOKandass] = PREC_assign;
- precedence[TOKorass] = PREC_assign;
- precedence[TOKxorass] = PREC_assign;
-
- precedence[TOKcomma] = PREC_expr;
- precedence[TOKdeclaration] = PREC_expr;
-
- precedence[TOKinterval] = PREC_assign;
-}
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
new file mode 100644
index 0000000..21042dd
--- /dev/null
+++ b/gcc/d/dmd/parse.d
@@ -0,0 +1,9365 @@
+/**
+ * Takes a token stream from the lexer, and parses it into an abstract syntax tree.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/grammar.html, D Grammar)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/parse.d, _parse.d)
+ * Documentation: https://dlang.org/phobos/dmd_parse.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/parse.d
+ */
+
+module dmd.parse;
+
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.astenums;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.lexer;
+import dmd.errors;
+import dmd.root.filename;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.tokens;
+
+// How multiple declarations are parsed.
+// If 1, treat as C.
+// If 0, treat:
+// int *p, i;
+// as:
+// int* p;
+// int* i;
+private enum CDECLSYNTAX = 0;
+
+// Support C cast syntax:
+// (type)(expression)
+private enum CCASTSYNTAX = 1;
+
+// Support postfix C array declarations, such as
+// int a[3][4];
+private enum CARRAYDECL = 1;
+
+/**********************************
+ * Set operator precedence for each operator.
+ *
+ * Used by hdrgen
+ */
+immutable PREC[TOK.max + 1] precedence =
+[
+ TOK.type : PREC.expr,
+ TOK.error : PREC.expr,
+ TOK.objcClassReference : PREC.expr, // Objective-C class reference, same as TOK.type
+
+ TOK.typeof_ : PREC.primary,
+ TOK.mixin_ : PREC.primary,
+
+ TOK.import_ : PREC.primary,
+ TOK.dotVariable : PREC.primary,
+ TOK.scope_ : PREC.primary,
+ TOK.identifier : PREC.primary,
+ TOK.this_ : PREC.primary,
+ TOK.super_ : PREC.primary,
+ TOK.int64 : PREC.primary,
+ TOK.float64 : PREC.primary,
+ TOK.complex80 : PREC.primary,
+ TOK.null_ : PREC.primary,
+ TOK.string_ : PREC.primary,
+ TOK.arrayLiteral : PREC.primary,
+ TOK.assocArrayLiteral : PREC.primary,
+ TOK.classReference : PREC.primary,
+ TOK.file : PREC.primary,
+ TOK.fileFullPath : PREC.primary,
+ TOK.line : PREC.primary,
+ TOK.moduleString : PREC.primary,
+ TOK.functionString : PREC.primary,
+ TOK.prettyFunction : PREC.primary,
+ TOK.typeid_ : PREC.primary,
+ TOK.is_ : PREC.primary,
+ TOK.assert_ : PREC.primary,
+ TOK.halt : PREC.primary,
+ TOK.template_ : PREC.primary,
+ TOK.dSymbol : PREC.primary,
+ TOK.function_ : PREC.primary,
+ TOK.variable : PREC.primary,
+ TOK.symbolOffset : PREC.primary,
+ TOK.structLiteral : PREC.primary,
+ TOK.compoundLiteral : PREC.primary,
+ TOK.arrayLength : PREC.primary,
+ TOK.delegatePointer : PREC.primary,
+ TOK.delegateFunctionPointer : PREC.primary,
+ TOK.remove : PREC.primary,
+ TOK.tuple : PREC.primary,
+ TOK.traits : PREC.primary,
+ TOK.default_ : PREC.primary,
+ TOK.overloadSet : PREC.primary,
+ TOK.void_ : PREC.primary,
+ TOK.vectorArray : PREC.primary,
+ TOK._Generic : PREC.primary,
+
+ // post
+ TOK.dotTemplateInstance : PREC.primary,
+ TOK.dotIdentifier : PREC.primary,
+ TOK.dotTemplateDeclaration : PREC.primary,
+ TOK.dot : PREC.primary,
+ TOK.dotType : PREC.primary,
+ TOK.plusPlus : PREC.primary,
+ TOK.minusMinus : PREC.primary,
+ TOK.prePlusPlus : PREC.primary,
+ TOK.preMinusMinus : PREC.primary,
+ TOK.call : PREC.primary,
+ TOK.slice : PREC.primary,
+ TOK.array : PREC.primary,
+ TOK.index : PREC.primary,
+
+ TOK.delegate_ : PREC.unary,
+ TOK.address : PREC.unary,
+ TOK.star : PREC.unary,
+ TOK.negate : PREC.unary,
+ TOK.uadd : PREC.unary,
+ TOK.not : PREC.unary,
+ TOK.tilde : PREC.unary,
+ TOK.delete_ : PREC.unary,
+ TOK.new_ : PREC.unary,
+ TOK.newAnonymousClass : PREC.unary,
+ TOK.cast_ : PREC.unary,
+
+ TOK.vector : PREC.unary,
+ TOK.pow : PREC.pow,
+
+ TOK.mul : PREC.mul,
+ TOK.div : PREC.mul,
+ TOK.mod : PREC.mul,
+
+ TOK.add : PREC.add,
+ TOK.min : PREC.add,
+ TOK.concatenate : PREC.add,
+
+ TOK.leftShift : PREC.shift,
+ TOK.rightShift : PREC.shift,
+ TOK.unsignedRightShift : PREC.shift,
+
+ TOK.lessThan : PREC.rel,
+ TOK.lessOrEqual : PREC.rel,
+ TOK.greaterThan : PREC.rel,
+ TOK.greaterOrEqual : PREC.rel,
+ TOK.in_ : PREC.rel,
+
+ /* Note that we changed precedence, so that < and != have the same
+ * precedence. This change is in the parser, too.
+ */
+ TOK.equal : PREC.rel,
+ TOK.notEqual : PREC.rel,
+ TOK.identity : PREC.rel,
+ TOK.notIdentity : PREC.rel,
+
+ TOK.and : PREC.and,
+ TOK.xor : PREC.xor,
+ TOK.or : PREC.or,
+
+ TOK.andAnd : PREC.andand,
+ TOK.orOr : PREC.oror,
+
+ TOK.question : PREC.cond,
+
+ TOK.assign : PREC.assign,
+ TOK.construct : PREC.assign,
+ TOK.blit : PREC.assign,
+ TOK.addAssign : PREC.assign,
+ TOK.minAssign : PREC.assign,
+ TOK.concatenateAssign : PREC.assign,
+ TOK.concatenateElemAssign : PREC.assign,
+ TOK.concatenateDcharAssign : PREC.assign,
+ TOK.mulAssign : PREC.assign,
+ TOK.divAssign : PREC.assign,
+ TOK.modAssign : PREC.assign,
+ TOK.powAssign : PREC.assign,
+ TOK.leftShiftAssign : PREC.assign,
+ TOK.rightShiftAssign : PREC.assign,
+ TOK.unsignedRightShiftAssign : PREC.assign,
+ TOK.andAssign : PREC.assign,
+ TOK.orAssign : PREC.assign,
+ TOK.xorAssign : PREC.assign,
+
+ TOK.comma : PREC.expr,
+ TOK.declaration : PREC.expr,
+
+ TOK.interval : PREC.assign,
+];
+
+enum ParseStatementFlags : int
+{
+ semi = 1, // empty ';' statements are allowed, but deprecated
+ scope_ = 2, // start a new scope
+ curly = 4, // { } statement is required
+ curlyScope = 8, // { } starts a new scope
+ semiOk = 0x10, // empty ';' are really ok
+}
+
+struct PrefixAttributes(AST)
+{
+ StorageClass storageClass;
+ AST.Expression depmsg;
+ LINK link;
+ AST.Visibility visibility;
+ bool setAlignment;
+ AST.Expression ealign;
+ AST.Expressions* udas;
+ const(char)* comment;
+}
+
+/// The result of the `ParseLinkage` function
+struct ParsedLinkage(AST)
+{
+ /// What linkage was specified
+ LINK link;
+ /// If `extern(C++, class|struct)`, contains the `class|struct`
+ CPPMANGLE cppmangle;
+ /// If `extern(C++, some.identifier)`, will be the identifiers
+ AST.Identifiers* idents;
+ /// If `extern(C++, (some_tuple_expression)|"string"), will be the expressions
+ AST.Expressions* identExps;
+}
+
+/*****************************
+ * Destructively extract storage class from pAttrs.
+ */
+private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs)
+{
+ StorageClass stc = STC.undefined_;
+ if (pAttrs)
+ {
+ stc = pAttrs.storageClass;
+ pAttrs.storageClass = STC.undefined_;
+ }
+ return stc;
+}
+
+/**************************************
+ * dump mixin expansion to file for better debugging
+ */
+private bool writeMixin(const(char)[] s, ref Loc loc)
+{
+ if (!global.params.mixinOut)
+ return false;
+
+ OutBuffer* ob = global.params.mixinOut;
+
+ ob.writestring("// expansion at ");
+ ob.writestring(loc.toChars());
+ ob.writenl();
+
+ global.params.mixinLines++;
+
+ loc = Loc(global.params.mixinFile, global.params.mixinLines + 1, loc.charnum);
+
+ // write by line to create consistent line endings
+ size_t lastpos = 0;
+ for (size_t i = 0; i < s.length; ++i)
+ {
+ // detect LF and CRLF
+ const c = s[i];
+ if (c == '\n' || (c == '\r' && i+1 < s.length && s[i+1] == '\n'))
+ {
+ ob.writestring(s[lastpos .. i]);
+ ob.writenl();
+ global.params.mixinLines++;
+ if (c == '\r')
+ ++i;
+ lastpos = i + 1;
+ }
+ }
+
+ if(lastpos < s.length)
+ ob.writestring(s[lastpos .. $]);
+
+ if (s.length == 0 || s[$-1] != '\n')
+ {
+ ob.writenl(); // ensure empty line after expansion
+ global.params.mixinLines++;
+ }
+ ob.writenl();
+ global.params.mixinLines++;
+
+ return true;
+}
+
+/***********************************************************
+ */
+class Parser(AST) : Lexer
+{
+ AST.ModuleDeclaration* md;
+
+ protected
+ {
+ AST.Module mod;
+ LINK linkage;
+ Loc linkLoc;
+ CPPMANGLE cppmangle;
+ Loc endloc; // set to location of last right curly
+ int inBrackets; // inside [] of array index or slice
+ Loc lookingForElse; // location of lonely if looking for an else
+ }
+
+ /*********************
+ * Use this constructor for string mixins.
+ * Input:
+ * loc location in source file of mixin
+ */
+ extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment)
+ {
+ super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false);
+
+ //printf("Parser::Parser()\n");
+ scanloc = loc;
+
+ if (!writeMixin(input, scanloc) && loc.filename)
+ {
+ /* Create a pseudo-filename for the mixin string, as it may not even exist
+ * in the source file.
+ */
+ char* filename = cast(char*)mem.xmalloc(strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1);
+ sprintf(filename, "%s-mixin-%d", loc.filename, cast(int)loc.linnum);
+ scanloc.filename = filename;
+ }
+
+ mod = _module;
+ linkage = LINK.d;
+ //nextToken(); // start up the scanner
+ }
+
+ extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment)
+ {
+ super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false);
+
+ //printf("Parser::Parser()\n");
+ mod = _module;
+ linkage = LINK.d;
+ //nextToken(); // start up the scanner
+ }
+
+ AST.Dsymbols* parseModule()
+ {
+ const comment = token.blockComment;
+ bool isdeprecated = false;
+ AST.Expression msg = null;
+ AST.Expressions* udas = null;
+ AST.Dsymbols* decldefs;
+ AST.Dsymbol lastDecl = mod; // for attaching ddoc unittests to module decl
+
+ Token* tk;
+ if (skipAttributes(&token, &tk) && tk.value == TOK.module_)
+ {
+ while (token.value != TOK.module_)
+ {
+ switch (token.value)
+ {
+ case TOK.deprecated_:
+ {
+ // deprecated (...) module ...
+ if (isdeprecated)
+ error("there is only one deprecation attribute allowed for module declaration");
+ isdeprecated = true;
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ {
+ check(TOK.leftParenthesis);
+ msg = parseAssignExp();
+ check(TOK.rightParenthesis);
+ }
+ break;
+ }
+ case TOK.at:
+ {
+ AST.Expressions* exps = null;
+ const stc = parseAttribute(exps);
+ if (stc & atAttrGroup)
+ {
+ error("`@%s` attribute for module declaration is not supported", token.toChars());
+ }
+ else
+ {
+ udas = AST.UserAttributeDeclaration.concat(udas, exps);
+ }
+ if (stc)
+ nextToken();
+ break;
+ }
+ default:
+ {
+ error("`module` expected instead of `%s`", token.toChars());
+ nextToken();
+ break;
+ }
+ }
+ }
+ }
+
+ if (udas)
+ {
+ auto a = new AST.Dsymbols();
+ auto udad = new AST.UserAttributeDeclaration(udas, a);
+ mod.userAttribDecl = udad;
+ }
+
+ // ModuleDeclation leads off
+ if (token.value == TOK.module_)
+ {
+ const loc = token.loc;
+
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `module`");
+ goto Lerr;
+ }
+
+ Identifier[] a;
+ Identifier id = token.ident;
+
+ while (nextToken() == TOK.dot)
+ {
+ a ~= id;
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `package`");
+ goto Lerr;
+ }
+ id = token.ident;
+ }
+
+ md = new AST.ModuleDeclaration(loc, a, id, msg, isdeprecated);
+
+ if (token.value != TOK.semicolon)
+ error("`;` expected following module declaration instead of `%s`", token.toChars());
+ nextToken();
+ addComment(mod, comment);
+ }
+
+ decldefs = parseDeclDefs(0, &lastDecl);
+ if (token.value != TOK.endOfFile)
+ {
+ error(token.loc, "unrecognized declaration");
+ goto Lerr;
+ }
+ return decldefs;
+
+ Lerr:
+ while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
+ nextToken();
+ nextToken();
+ return new AST.Dsymbols();
+ }
+
+ final:
+
+ /**
+ * Parses a `deprecated` declaration
+ *
+ * Params:
+ * msg = Deprecated message, if any.
+ * Used to support overriding a deprecated storage class with
+ * a deprecated declaration with a message, but to error
+ * if both declaration have a message.
+ *
+ * Returns:
+ * Whether the deprecated declaration has a message
+ */
+ private bool parseDeprecatedAttribute(ref AST.Expression msg)
+ {
+ if (peekNext() != TOK.leftParenthesis)
+ return false;
+
+ nextToken();
+ check(TOK.leftParenthesis);
+ AST.Expression e = parseAssignExp();
+ check(TOK.rightParenthesis);
+ if (msg)
+ {
+ error("conflicting storage class `deprecated(%s)` and `deprecated(%s)`", msg.toChars(), e.toChars());
+ }
+ msg = e;
+ return true;
+ }
+
+ AST.Dsymbols* parseDeclDefs(int once, AST.Dsymbol* pLastDecl = null, PrefixAttributes!AST* pAttrs = null)
+ {
+ AST.Dsymbol lastDecl = null; // used to link unittest to its previous declaration
+ if (!pLastDecl)
+ pLastDecl = &lastDecl;
+
+ const linksave = linkage; // save global state
+
+ //printf("Parser::parseDeclDefs()\n");
+ auto decldefs = new AST.Dsymbols();
+ do
+ {
+ // parse result
+ AST.Dsymbol s = null;
+ AST.Dsymbols* a = null;
+
+ PrefixAttributes!AST attrs;
+ if (!once || !pAttrs)
+ {
+ pAttrs = &attrs;
+ pAttrs.comment = token.blockComment.ptr;
+ }
+ AST.Visibility.Kind prot;
+ StorageClass stc;
+ AST.Condition condition;
+
+ linkage = linksave;
+
+ Loc startloc;
+
+ switch (token.value)
+ {
+ case TOK.enum_:
+ {
+ /* Determine if this is a manifest constant declaration,
+ * or a conventional enum.
+ */
+ const tv = peekNext();
+ if (tv == TOK.leftCurly || tv == TOK.colon)
+ s = parseEnum();
+ else if (tv != TOK.identifier)
+ goto Ldeclaration;
+ else
+ {
+ const nextv = peekNext2();
+ if (nextv == TOK.leftCurly || nextv == TOK.colon || nextv == TOK.semicolon)
+ s = parseEnum();
+ else
+ goto Ldeclaration;
+ }
+ break;
+ }
+ case TOK.import_:
+ a = parseImport();
+ // keep pLastDecl
+ break;
+
+ case TOK.template_:
+ s = cast(AST.Dsymbol)parseTemplateDeclaration();
+ break;
+
+ case TOK.mixin_:
+ {
+ const loc = token.loc;
+ switch (peekNext())
+ {
+ case TOK.leftParenthesis:
+ {
+ // mixin(string)
+ nextToken();
+ auto exps = parseArguments();
+ check(TOK.semicolon);
+ s = new AST.CompileDeclaration(loc, exps);
+ break;
+ }
+ case TOK.template_:
+ // mixin template
+ nextToken();
+ s = cast(AST.Dsymbol)parseTemplateDeclaration(true);
+ break;
+
+ default:
+ s = parseMixin();
+ break;
+ }
+ break;
+ }
+ case TOK.wchar_:
+ case TOK.dchar_:
+ case TOK.bool_:
+ case TOK.char_:
+ case TOK.int8:
+ case TOK.uns8:
+ case TOK.int16:
+ case TOK.uns16:
+ case TOK.int32:
+ case TOK.uns32:
+ case TOK.int64:
+ case TOK.uns64:
+ case TOK.int128:
+ case TOK.uns128:
+ case TOK.float32:
+ case TOK.float64:
+ case TOK.float80:
+ case TOK.imaginary32:
+ case TOK.imaginary64:
+ case TOK.imaginary80:
+ case TOK.complex32:
+ case TOK.complex64:
+ case TOK.complex80:
+ case TOK.void_:
+ case TOK.alias_:
+ case TOK.identifier:
+ case TOK.super_:
+ case TOK.typeof_:
+ case TOK.dot:
+ case TOK.vector:
+ case TOK.struct_:
+ case TOK.union_:
+ case TOK.class_:
+ case TOK.interface_:
+ case TOK.traits:
+ Ldeclaration:
+ a = parseDeclarations(false, pAttrs, pAttrs.comment);
+ if (a && a.dim)
+ *pLastDecl = (*a)[a.dim - 1];
+ break;
+
+ case TOK.this_:
+ if (peekNext() == TOK.dot)
+ goto Ldeclaration;
+ s = parseCtor(pAttrs);
+ break;
+
+ case TOK.tilde:
+ s = parseDtor(pAttrs);
+ break;
+
+ case TOK.invariant_:
+ const tv = peekNext();
+ if (tv == TOK.leftParenthesis || tv == TOK.leftCurly)
+ {
+ // invariant { statements... }
+ // invariant() { statements... }
+ // invariant (expression);
+ s = parseInvariant(pAttrs);
+ break;
+ }
+ error("invariant body expected, not `%s`", token.toChars());
+ goto Lerror;
+
+ case TOK.unittest_:
+ if (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration)
+ {
+ s = parseUnitTest(pAttrs);
+ if (*pLastDecl)
+ (*pLastDecl).ddocUnittest = cast(AST.UnitTestDeclaration)s;
+ }
+ else
+ {
+ // Skip over unittest block by counting { }
+ Loc loc = token.loc;
+ int braces = 0;
+ while (1)
+ {
+ nextToken();
+ switch (token.value)
+ {
+ case TOK.leftCurly:
+ ++braces;
+ continue;
+
+ case TOK.rightCurly:
+ if (--braces)
+ continue;
+ nextToken();
+ break;
+
+ case TOK.endOfFile:
+ /* { */
+ error(loc, "closing `}` of unittest not found before end of file");
+ goto Lerror;
+
+ default:
+ continue;
+ }
+ break;
+ }
+ // Workaround 14894. Add an empty unittest declaration to keep
+ // the number of symbols in this scope independent of -unittest.
+ s = new AST.UnitTestDeclaration(loc, token.loc, STC.undefined_, null);
+ }
+ break;
+
+ case TOK.new_:
+ s = parseNew(pAttrs);
+ break;
+
+ case TOK.colon:
+ case TOK.leftCurly:
+ error("declaration expected, not `%s`", token.toChars());
+ goto Lerror;
+
+ case TOK.rightCurly:
+ case TOK.endOfFile:
+ if (once)
+ error("declaration expected, not `%s`", token.toChars());
+ return decldefs;
+
+ case TOK.static_:
+ {
+ const next = peekNext();
+ if (next == TOK.this_)
+ s = parseStaticCtor(pAttrs);
+ else if (next == TOK.tilde)
+ s = parseStaticDtor(pAttrs);
+ else if (next == TOK.assert_)
+ s = parseStaticAssert();
+ else if (next == TOK.if_)
+ {
+ const Loc loc = token.loc;
+ condition = parseStaticIfCondition();
+ AST.Dsymbols* athen;
+ if (token.value == TOK.colon)
+ athen = parseBlock(pLastDecl);
+ else
+ {
+ const lookingForElseSave = lookingForElse;
+ lookingForElse = token.loc;
+ athen = parseBlock(pLastDecl);
+ lookingForElse = lookingForElseSave;
+ }
+ AST.Dsymbols* aelse = null;
+ if (token.value == TOK.else_)
+ {
+ const elseloc = token.loc;
+ nextToken();
+ aelse = parseBlock(pLastDecl);
+ checkDanglingElse(elseloc);
+ }
+ s = new AST.StaticIfDeclaration(loc, condition, athen, aelse);
+ }
+ else if (next == TOK.import_)
+ {
+ a = parseImport();
+ // keep pLastDecl
+ }
+ else if (next == TOK.foreach_ || next == TOK.foreach_reverse_)
+ {
+ s = parseForeach!(AST.StaticForeachDeclaration)(token.loc, pLastDecl);
+ }
+ else
+ {
+ stc = STC.static_;
+ goto Lstc;
+ }
+ break;
+ }
+ case TOK.const_:
+ if (peekNext() == TOK.leftParenthesis)
+ goto Ldeclaration;
+ stc = STC.const_;
+ goto Lstc;
+
+ case TOK.immutable_:
+ if (peekNext() == TOK.leftParenthesis)
+ goto Ldeclaration;
+ stc = STC.immutable_;
+ goto Lstc;
+
+ case TOK.shared_:
+ {
+ const next = peekNext();
+ if (next == TOK.leftParenthesis)
+ goto Ldeclaration;
+ if (next == TOK.static_)
+ {
+ TOK next2 = peekNext2();
+ if (next2 == TOK.this_)
+ {
+ s = parseSharedStaticCtor(pAttrs);
+ break;
+ }
+ if (next2 == TOK.tilde)
+ {
+ s = parseSharedStaticDtor(pAttrs);
+ break;
+ }
+ }
+ stc = STC.shared_;
+ goto Lstc;
+ }
+ case TOK.inout_:
+ if (peekNext() == TOK.leftParenthesis)
+ goto Ldeclaration;
+ stc = STC.wild;
+ goto Lstc;
+
+ case TOK.final_:
+ stc = STC.final_;
+ goto Lstc;
+
+ case TOK.auto_:
+ stc = STC.auto_;
+ goto Lstc;
+
+ case TOK.scope_:
+ stc = STC.scope_;
+ goto Lstc;
+
+ case TOK.override_:
+ stc = STC.override_;
+ goto Lstc;
+
+ case TOK.abstract_:
+ stc = STC.abstract_;
+ goto Lstc;
+
+ case TOK.synchronized_:
+ stc = STC.synchronized_;
+ goto Lstc;
+
+ case TOK.nothrow_:
+ stc = STC.nothrow_;
+ goto Lstc;
+
+ case TOK.pure_:
+ stc = STC.pure_;
+ goto Lstc;
+
+ case TOK.ref_:
+ stc = STC.ref_;
+ goto Lstc;
+
+ case TOK.gshared:
+ stc = STC.gshared;
+ goto Lstc;
+
+ case TOK.at:
+ {
+ AST.Expressions* exps = null;
+ stc = parseAttribute(exps);
+ if (stc)
+ goto Lstc; // it's a predefined attribute
+ // no redundant/conflicting check for UDAs
+ pAttrs.udas = AST.UserAttributeDeclaration.concat(pAttrs.udas, exps);
+ goto Lautodecl;
+ }
+ Lstc:
+ pAttrs.storageClass = appendStorageClass(pAttrs.storageClass, stc);
+ nextToken();
+
+ Lautodecl:
+
+ /* Look for auto initializers:
+ * storage_class identifier = initializer;
+ * storage_class identifier(...) = initializer;
+ */
+ if (token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign))
+ {
+ a = parseAutoDeclarations(getStorageClass!AST(pAttrs), pAttrs.comment);
+ if (a && a.dim)
+ *pLastDecl = (*a)[a.dim - 1];
+ if (pAttrs.udas)
+ {
+ s = new AST.UserAttributeDeclaration(pAttrs.udas, a);
+ pAttrs.udas = null;
+ }
+ break;
+ }
+
+ /* Look for return type inference for template functions.
+ */
+ Token* tk;
+ if (token.value == TOK.identifier && skipParens(peek(&token), &tk) && skipAttributes(tk, &tk) &&
+ (tk.value == TOK.leftParenthesis || tk.value == TOK.leftCurly || tk.value == TOK.in_ ||
+ tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.goesTo ||
+ tk.value == TOK.identifier && tk.ident == Id._body))
+ {
+ // @@@DEPRECATED@@@
+ // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
+ // Deprecated in 2.097 - Can be removed from 2.117
+ // The deprecation period is longer than usual as `body`
+ // was quite widely used.
+ if (tk.value == TOK.identifier && tk.ident == Id._body)
+ deprecation("Usage of the `body` keyword is deprecated. Use `do` instead.");
+
+ a = parseDeclarations(true, pAttrs, pAttrs.comment);
+ if (a && a.dim)
+ *pLastDecl = (*a)[a.dim - 1];
+ if (pAttrs.udas)
+ {
+ s = new AST.UserAttributeDeclaration(pAttrs.udas, a);
+ pAttrs.udas = null;
+ }
+ break;
+ }
+
+ a = parseBlock(pLastDecl, pAttrs);
+ auto stc2 = getStorageClass!AST(pAttrs);
+ if (stc2 != STC.undefined_)
+ {
+ s = new AST.StorageClassDeclaration(stc2, a);
+ }
+ if (pAttrs.udas)
+ {
+ if (s)
+ {
+ a = new AST.Dsymbols();
+ a.push(s);
+ }
+ s = new AST.UserAttributeDeclaration(pAttrs.udas, a);
+ pAttrs.udas = null;
+ }
+ break;
+
+ case TOK.deprecated_:
+ {
+ stc |= STC.deprecated_;
+ if (!parseDeprecatedAttribute(pAttrs.depmsg))
+ goto Lstc;
+
+ a = parseBlock(pLastDecl, pAttrs);
+ s = new AST.DeprecatedDeclaration(pAttrs.depmsg, a);
+ pAttrs.depmsg = null;
+ break;
+ }
+ case TOK.leftBracket:
+ {
+ if (peekNext() == TOK.rightBracket)
+ error("empty attribute list is not allowed");
+ error("use `@(attributes)` instead of `[attributes]`");
+ AST.Expressions* exps = parseArguments();
+ // no redundant/conflicting check for UDAs
+
+ pAttrs.udas = AST.UserAttributeDeclaration.concat(pAttrs.udas, exps);
+ a = parseBlock(pLastDecl, pAttrs);
+ if (pAttrs.udas)
+ {
+ s = new AST.UserAttributeDeclaration(pAttrs.udas, a);
+ pAttrs.udas = null;
+ }
+ break;
+ }
+ case TOK.extern_:
+ {
+ if (peekNext() != TOK.leftParenthesis)
+ {
+ stc = STC.extern_;
+ goto Lstc;
+ }
+
+ const linkLoc = token.loc;
+ auto res = parseLinkage();
+ if (pAttrs.link != LINK.default_)
+ {
+ if (pAttrs.link != res.link)
+ {
+ error("conflicting linkage `extern (%s)` and `extern (%s)`", AST.linkageToChars(pAttrs.link), AST.linkageToChars(res.link));
+ }
+ else if (res.idents || res.identExps || res.cppmangle != CPPMANGLE.def)
+ {
+ // Allow:
+ // extern(C++, foo) extern(C++, bar) void foo();
+ // to be equivalent with:
+ // extern(C++, foo.bar) void foo();
+ // Allow also:
+ // extern(C++, "ns") extern(C++, class) struct test {}
+ // extern(C++, class) extern(C++, "ns") struct test {}
+ }
+ else
+ error("redundant linkage `extern (%s)`", AST.linkageToChars(pAttrs.link));
+ }
+ pAttrs.link = res.link;
+ this.linkage = res.link;
+ this.linkLoc = linkLoc;
+ a = parseBlock(pLastDecl, pAttrs);
+ if (res.idents)
+ {
+ assert(res.link == LINK.cpp);
+ assert(res.idents.dim);
+ for (size_t i = res.idents.dim; i;)
+ {
+ Identifier id = (*res.idents)[--i];
+ if (s)
+ {
+ a = new AST.Dsymbols();
+ a.push(s);
+ }
+ s = new AST.Nspace(linkLoc, id, null, a);
+ }
+ pAttrs.link = LINK.default_;
+ }
+ else if (res.identExps)
+ {
+ assert(res.link == LINK.cpp);
+ assert(res.identExps.dim);
+ for (size_t i = res.identExps.dim; i;)
+ {
+ AST.Expression exp = (*res.identExps)[--i];
+ if (s)
+ {
+ a = new AST.Dsymbols();
+ a.push(s);
+ }
+ s = new AST.CPPNamespaceDeclaration(linkLoc, exp, a);
+ }
+ pAttrs.link = LINK.default_;
+ }
+ else if (res.cppmangle != CPPMANGLE.def)
+ {
+ assert(res.link == LINK.cpp);
+ s = new AST.CPPMangleDeclaration(linkLoc, res.cppmangle, a);
+ }
+ else if (pAttrs.link != LINK.default_)
+ {
+ s = new AST.LinkDeclaration(linkLoc, pAttrs.link, a);
+ pAttrs.link = LINK.default_;
+ }
+ break;
+ }
+
+ case TOK.private_:
+ prot = AST.Visibility.Kind.private_;
+ goto Lprot;
+
+ case TOK.package_:
+ prot = AST.Visibility.Kind.package_;
+ goto Lprot;
+
+ case TOK.protected_:
+ prot = AST.Visibility.Kind.protected_;
+ goto Lprot;
+
+ case TOK.public_:
+ prot = AST.Visibility.Kind.public_;
+ goto Lprot;
+
+ case TOK.export_:
+ prot = AST.Visibility.Kind.export_;
+ goto Lprot;
+ Lprot:
+ {
+ if (pAttrs.visibility.kind != AST.Visibility.Kind.undefined)
+ {
+ if (pAttrs.visibility.kind != prot)
+ error("conflicting visibility attribute `%s` and `%s`", AST.visibilityToChars(pAttrs.visibility.kind), AST.visibilityToChars(prot));
+ else
+ error("redundant visibility attribute `%s`", AST.visibilityToChars(prot));
+ }
+ pAttrs.visibility.kind = prot;
+
+ nextToken();
+
+ // optional qualified package identifier to bind
+ // visibility to
+ Identifier[] pkg_prot_idents;
+ if (pAttrs.visibility.kind == AST.Visibility.Kind.package_ && token.value == TOK.leftParenthesis)
+ {
+ pkg_prot_idents = parseQualifiedIdentifier("protection package");
+ if (pkg_prot_idents)
+ check(TOK.rightParenthesis);
+ else
+ {
+ while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
+ nextToken();
+ nextToken();
+ break;
+ }
+ }
+
+ const attrloc = token.loc;
+ a = parseBlock(pLastDecl, pAttrs);
+ if (pAttrs.visibility.kind != AST.Visibility.Kind.undefined)
+ {
+ if (pAttrs.visibility.kind == AST.Visibility.Kind.package_ && pkg_prot_idents)
+ s = new AST.VisibilityDeclaration(attrloc, pkg_prot_idents, a);
+ else
+ s = new AST.VisibilityDeclaration(attrloc, pAttrs.visibility, a);
+
+ pAttrs.visibility = AST.Visibility(AST.Visibility.Kind.undefined);
+ }
+ break;
+ }
+ case TOK.align_:
+ {
+ const attrLoc = token.loc;
+
+ nextToken();
+
+ AST.Expression e = null; // default
+ if (token.value == TOK.leftParenthesis)
+ {
+ nextToken();
+ e = parseAssignExp();
+ check(TOK.rightParenthesis);
+ }
+
+ if (pAttrs.setAlignment)
+ {
+ if (e)
+ error("redundant alignment attribute `align(%s)`", e.toChars());
+ else
+ error("redundant alignment attribute `align`");
+ }
+
+ pAttrs.setAlignment = true;
+ pAttrs.ealign = e;
+ a = parseBlock(pLastDecl, pAttrs);
+ if (pAttrs.setAlignment)
+ {
+ s = new AST.AlignDeclaration(attrLoc, pAttrs.ealign, a);
+ pAttrs.setAlignment = false;
+ pAttrs.ealign = null;
+ }
+ break;
+ }
+ case TOK.pragma_:
+ {
+ AST.Expressions* args = null;
+ const loc = token.loc;
+
+ nextToken();
+ check(TOK.leftParenthesis);
+ if (token.value != TOK.identifier)
+ {
+ error("`pragma(identifier)` expected");
+ goto Lerror;
+ }
+ Identifier ident = token.ident;
+ nextToken();
+ if (token.value == TOK.comma && peekNext() != TOK.rightParenthesis)
+ args = parseArguments(); // pragma(identifier, args...)
+ else
+ check(TOK.rightParenthesis); // pragma(identifier)
+
+ AST.Dsymbols* a2 = null;
+ if (token.value == TOK.semicolon)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=2354
+ * Accept single semicolon as an empty
+ * DeclarationBlock following attribute.
+ *
+ * Attribute DeclarationBlock
+ * Pragma DeclDef
+ * ;
+ */
+ nextToken();
+ }
+ else
+ a2 = parseBlock(pLastDecl);
+ s = new AST.PragmaDeclaration(loc, ident, args, a2);
+ break;
+ }
+ case TOK.debug_:
+ startloc = token.loc;
+ nextToken();
+ if (token.value == TOK.assign)
+ {
+ nextToken();
+ if (token.value == TOK.identifier)
+ s = new AST.DebugSymbol(token.loc, token.ident);
+ else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+ s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
+ else
+ {
+ error("identifier or integer expected, not `%s`", token.toChars());
+ s = null;
+ }
+ nextToken();
+ if (token.value != TOK.semicolon)
+ error("semicolon expected");
+ nextToken();
+ break;
+ }
+
+ condition = parseDebugCondition();
+ goto Lcondition;
+
+ case TOK.version_:
+ startloc = token.loc;
+ nextToken();
+ if (token.value == TOK.assign)
+ {
+ nextToken();
+ if (token.value == TOK.identifier)
+ s = new AST.VersionSymbol(token.loc, token.ident);
+ else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+ s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
+ else
+ {
+ error("identifier or integer expected, not `%s`", token.toChars());
+ s = null;
+ }
+ nextToken();
+ if (token.value != TOK.semicolon)
+ error("semicolon expected");
+ nextToken();
+ break;
+ }
+ condition = parseVersionCondition();
+ goto Lcondition;
+
+ Lcondition:
+ {
+ AST.Dsymbols* athen;
+ if (token.value == TOK.colon)
+ athen = parseBlock(pLastDecl);
+ else
+ {
+ const lookingForElseSave = lookingForElse;
+ lookingForElse = token.loc;
+ athen = parseBlock(pLastDecl);
+ lookingForElse = lookingForElseSave;
+ }
+ AST.Dsymbols* aelse = null;
+ if (token.value == TOK.else_)
+ {
+ const elseloc = token.loc;
+ nextToken();
+ aelse = parseBlock(pLastDecl);
+ checkDanglingElse(elseloc);
+ }
+ s = new AST.ConditionalDeclaration(startloc, condition, athen, aelse);
+ break;
+ }
+ case TOK.semicolon:
+ // empty declaration
+ //error("empty declaration");
+ nextToken();
+ continue;
+
+ default:
+ error("declaration expected, not `%s`", token.toChars());
+ Lerror:
+ while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
+ nextToken();
+ nextToken();
+ s = null;
+ continue;
+ }
+
+ if (s)
+ {
+ if (!s.isAttribDeclaration())
+ *pLastDecl = s;
+ decldefs.push(s);
+ addComment(s, pAttrs.comment);
+ }
+ else if (a && a.dim)
+ {
+ decldefs.append(a);
+ }
+ }
+ while (!once);
+
+ linkage = linksave;
+
+ return decldefs;
+ }
+
+ /*****************************************
+ * Parse auto declarations of the form:
+ * storageClass ident = init, ident = init, ... ;
+ * and return the array of them.
+ * Starts with token on the first ident.
+ * Ends with scanner past closing ';'
+ */
+ private AST.Dsymbols* parseAutoDeclarations(StorageClass storageClass, const(char)* comment)
+ {
+ //printf("parseAutoDeclarations\n");
+ auto a = new AST.Dsymbols();
+
+ while (1)
+ {
+ const loc = token.loc;
+ Identifier ident = token.ident;
+ nextToken(); // skip over ident
+
+ AST.TemplateParameters* tpl = null;
+ if (token.value == TOK.leftParenthesis)
+ tpl = parseTemplateParameterList();
+
+ check(TOK.assign); // skip over '='
+ AST.Initializer _init = parseInitializer();
+ auto v = new AST.VarDeclaration(loc, null, ident, _init, storageClass);
+
+ AST.Dsymbol s = v;
+ if (tpl)
+ {
+ auto a2 = new AST.Dsymbols();
+ a2.push(v);
+ auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2, 0);
+ s = tempdecl;
+ }
+ a.push(s);
+ switch (token.value)
+ {
+ case TOK.semicolon:
+ nextToken();
+ addComment(s, comment);
+ break;
+
+ case TOK.comma:
+ nextToken();
+ if (!(token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign)))
+ {
+ error("identifier expected following comma");
+ break;
+ }
+ addComment(s, comment);
+ continue;
+
+ default:
+ error("semicolon expected following auto declaration, not `%s`", token.toChars());
+ break;
+ }
+ break;
+ }
+ return a;
+ }
+
+ /********************************************
+ * Parse declarations after an align, visibility, or extern decl.
+ */
+ private AST.Dsymbols* parseBlock(AST.Dsymbol* pLastDecl, PrefixAttributes!AST* pAttrs = null)
+ {
+ AST.Dsymbols* a = null;
+
+ //printf("parseBlock()\n");
+ switch (token.value)
+ {
+ case TOK.semicolon:
+ error("declaration expected following attribute, not `;`");
+ nextToken();
+ break;
+
+ case TOK.endOfFile:
+ error("declaration expected following attribute, not end of file");
+ break;
+
+ case TOK.leftCurly:
+ {
+ const lookingForElseSave = lookingForElse;
+ lookingForElse = Loc();
+
+ nextToken();
+ a = parseDeclDefs(0, pLastDecl);
+ if (token.value != TOK.rightCurly)
+ {
+ /* { */
+ error("matching `}` expected, not `%s`", token.toChars());
+ }
+ else
+ nextToken();
+ lookingForElse = lookingForElseSave;
+ break;
+ }
+ case TOK.colon:
+ nextToken();
+ a = parseDeclDefs(0, pLastDecl); // grab declarations up to closing curly bracket
+ break;
+
+ default:
+ a = parseDeclDefs(1, pLastDecl, pAttrs);
+ break;
+ }
+ return a;
+ }
+
+ /**
+ * Provide an error message if `added` contains storage classes which are
+ * redundant with those in `orig`; otherwise, return the combination.
+ *
+ * Params:
+ * orig = The already applied storage class.
+ * added = The new storage class to add to `orig`.
+ *
+ * Returns:
+ * The combination of both storage classes (`orig | added`).
+ */
+ private StorageClass appendStorageClass(StorageClass orig, StorageClass added)
+ {
+ if (orig & added)
+ {
+ OutBuffer buf;
+ AST.stcToBuffer(&buf, added);
+ error("redundant attribute `%s`", buf.peekChars());
+ return orig | added;
+ }
+
+ const Redundant = (STC.const_ | STC.scope_ |
+ (global.params.previewIn ? STC.ref_ : 0));
+ orig |= added;
+
+ if ((orig & STC.in_) && (added & Redundant))
+ {
+ if (added & STC.const_)
+ error("attribute `const` is redundant with previously-applied `in`");
+ else if (global.params.previewIn)
+ {
+ error("attribute `%s` is redundant with previously-applied `in`",
+ (orig & STC.scope_) ? "scope".ptr : "ref".ptr);
+ }
+ else
+ error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead");
+ return orig;
+ }
+
+ if ((added & STC.in_) && (orig & Redundant))
+ {
+ if (orig & STC.const_)
+ error("attribute `in` cannot be added after `const`: remove `const`");
+ else if (global.params.previewIn)
+ {
+ // Windows `printf` does not support `%1$s`
+ const(char*) stc_str = (orig & STC.scope_) ? "scope".ptr : "ref".ptr;
+ error("attribute `in` cannot be added after `%s`: remove `%s`",
+ stc_str, stc_str);
+ }
+ else
+ error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`");
+ return orig;
+ }
+
+ if (added & (STC.const_ | STC.immutable_ | STC.manifest))
+ {
+ StorageClass u = orig & (STC.const_ | STC.immutable_ | STC.manifest);
+ if (u & (u - 1))
+ error("conflicting attribute `%s`", Token.toChars(token.value));
+ }
+ if (added & (STC.gshared | STC.shared_ | STC.tls))
+ {
+ StorageClass u = orig & (STC.gshared | STC.shared_ | STC.tls);
+ if (u & (u - 1))
+ error("conflicting attribute `%s`", Token.toChars(token.value));
+ }
+ if (added & STC.safeGroup)
+ {
+ StorageClass u = orig & STC.safeGroup;
+ if (u & (u - 1))
+ error("conflicting attribute `@%s`", token.toChars());
+ }
+
+ return orig;
+ }
+
+ /***********************************************
+ * Parse attribute(s), lexer is on '@'.
+ *
+ * Attributes can be builtin (e.g. `@safe`, `@nogc`, etc...),
+ * or be user-defined (UDAs). In the former case, we return the storage
+ * class via the return value, while in thelater case we return `0`
+ * and set `pudas`.
+ *
+ * Params:
+ * pudas = An array of UDAs to append to
+ *
+ * Returns:
+ * If the attribute is builtin, the return value will be non-zero.
+ * Otherwise, 0 is returned, and `pudas` will be appended to.
+ */
+ private StorageClass parseAttribute(ref AST.Expressions* udas)
+ {
+ nextToken();
+ if (token.value == TOK.identifier)
+ {
+ // If we find a builtin attribute, we're done, return immediately.
+ if (StorageClass stc = isBuiltinAtAttribute(token.ident))
+ return stc;
+
+ // Allow identifier, template instantiation, or function call
+ // for `@Argument` (single UDA) form.
+ AST.Expression exp = parsePrimaryExp();
+ if (token.value == TOK.leftParenthesis)
+ {
+ const loc = token.loc;
+ exp = new AST.CallExp(loc, exp, parseArguments());
+ }
+
+ if (udas is null)
+ udas = new AST.Expressions();
+ udas.push(exp);
+ return 0;
+ }
+
+ if (token.value == TOK.leftParenthesis)
+ {
+ // Multi-UDAs ( `@( ArgumentList )`) form, concatenate with existing
+ if (peekNext() == TOK.rightParenthesis)
+ error("empty attribute list is not allowed");
+ udas = AST.UserAttributeDeclaration.concat(udas, parseArguments());
+ return 0;
+ }
+
+ if (token.isKeyword())
+ error("`%s` is a keyword, not an `@` attribute", token.toChars());
+ else
+ error("`@identifier` or `@(ArgumentList)` expected, not `@%s`", token.toChars());
+
+ return 0;
+ }
+
+ /***********************************************
+ * Parse const/immutable/shared/inout/nothrow/pure postfix
+ */
+ private StorageClass parsePostfix(StorageClass storageClass, AST.Expressions** pudas)
+ {
+ while (1)
+ {
+ StorageClass stc;
+ switch (token.value)
+ {
+ case TOK.const_:
+ stc = STC.const_;
+ break;
+
+ case TOK.immutable_:
+ stc = STC.immutable_;
+ break;
+
+ case TOK.shared_:
+ stc = STC.shared_;
+ break;
+
+ case TOK.inout_:
+ stc = STC.wild;
+ break;
+
+ case TOK.nothrow_:
+ stc = STC.nothrow_;
+ break;
+
+ case TOK.pure_:
+ stc = STC.pure_;
+ break;
+
+ case TOK.return_:
+ stc = STC.return_;
+ break;
+
+ case TOK.scope_:
+ stc = STC.scope_;
+ break;
+
+ case TOK.at:
+ {
+ AST.Expressions* udas = null;
+ stc = parseAttribute(udas);
+ if (udas)
+ {
+ if (pudas)
+ *pudas = AST.UserAttributeDeclaration.concat(*pudas, udas);
+ else
+ {
+ // Disallow:
+ // void function() @uda fp;
+ // () @uda { return 1; }
+ error("user-defined attributes cannot appear as postfixes");
+ }
+ continue;
+ }
+ break;
+ }
+ default:
+ return storageClass;
+ }
+ storageClass = appendStorageClass(storageClass, stc);
+ nextToken();
+ }
+ }
+
+ private StorageClass parseTypeCtor()
+ {
+ StorageClass storageClass = STC.undefined_;
+
+ while (1)
+ {
+ if (peekNext() == TOK.leftParenthesis)
+ return storageClass;
+
+ StorageClass stc;
+ switch (token.value)
+ {
+ case TOK.const_:
+ stc = STC.const_;
+ break;
+
+ case TOK.immutable_:
+ stc = STC.immutable_;
+ break;
+
+ case TOK.shared_:
+ stc = STC.shared_;
+ break;
+
+ case TOK.inout_:
+ stc = STC.wild;
+ break;
+
+ default:
+ return storageClass;
+ }
+ storageClass = appendStorageClass(storageClass, stc);
+ nextToken();
+ }
+ }
+
+ /**************************************
+ * Parse constraint.
+ * Constraint is of the form:
+ * if ( ConstraintExpression )
+ */
+ private AST.Expression parseConstraint()
+ {
+ AST.Expression e = null;
+ if (token.value == TOK.if_)
+ {
+ nextToken(); // skip over 'if'
+ check(TOK.leftParenthesis);
+ e = parseExpression();
+ check(TOK.rightParenthesis);
+ }
+ return e;
+ }
+
+ /**************************************
+ * Parse a TemplateDeclaration.
+ */
+ private AST.TemplateDeclaration parseTemplateDeclaration(bool ismixin = false)
+ {
+ AST.TemplateDeclaration tempdecl;
+ Identifier id;
+ AST.TemplateParameters* tpl;
+ AST.Dsymbols* decldefs;
+ AST.Expression constraint = null;
+ const loc = token.loc;
+
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `template`");
+ goto Lerr;
+ }
+ id = token.ident;
+ nextToken();
+ tpl = parseTemplateParameterList();
+ if (!tpl)
+ goto Lerr;
+
+ constraint = parseConstraint();
+
+ if (token.value != TOK.leftCurly)
+ {
+ error("members of template declaration expected");
+ goto Lerr;
+ }
+ decldefs = parseBlock(null);
+
+ tempdecl = new AST.TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
+ return tempdecl;
+
+ Lerr:
+ return null;
+ }
+
+ /******************************************
+ * Parse template parameter list.
+ * Input:
+ * flag 0: parsing "( list )"
+ * 1: parsing non-empty "list $(RPAREN)"
+ */
+ private AST.TemplateParameters* parseTemplateParameterList(int flag = 0)
+ {
+ auto tpl = new AST.TemplateParameters();
+
+ if (!flag && token.value != TOK.leftParenthesis)
+ {
+ error("parenthesized template parameter list expected following template identifier");
+ goto Lerr;
+ }
+ nextToken();
+
+ // Get array of TemplateParameters
+ if (flag || token.value != TOK.rightParenthesis)
+ {
+ while (token.value != TOK.rightParenthesis)
+ {
+ AST.TemplateParameter tp;
+ Loc loc;
+ Identifier tp_ident = null;
+ AST.Type tp_spectype = null;
+ AST.Type tp_valtype = null;
+ AST.Type tp_defaulttype = null;
+ AST.Expression tp_specvalue = null;
+ AST.Expression tp_defaultvalue = null;
+
+ // Get TemplateParameter
+
+ // First, look ahead to see if it is a TypeParameter or a ValueParameter
+ const tv = peekNext();
+ if (token.value == TOK.alias_)
+ {
+ // AliasParameter
+ nextToken();
+ loc = token.loc; // todo
+ AST.Type spectype = null;
+ if (isDeclaration(&token, NeedDeclaratorId.must, TOK.reserved, null))
+ {
+ spectype = parseType(&tp_ident);
+ }
+ else
+ {
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected for template `alias` parameter");
+ goto Lerr;
+ }
+ tp_ident = token.ident;
+ nextToken();
+ }
+ RootObject spec = null;
+ if (token.value == TOK.colon) // : Type
+ {
+ nextToken();
+ if (isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null))
+ spec = parseType();
+ else
+ spec = parseCondExp();
+ }
+ RootObject def = null;
+ if (token.value == TOK.assign) // = Type
+ {
+ nextToken();
+ if (isDeclaration(&token, NeedDeclaratorId.no, TOK.reserved, null))
+ def = parseType();
+ else
+ def = parseCondExp();
+ }
+ tp = new AST.TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
+ }
+ else if (tv == TOK.colon || tv == TOK.assign || tv == TOK.comma || tv == TOK.rightParenthesis)
+ {
+ // TypeParameter
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected for template type parameter");
+ goto Lerr;
+ }
+ loc = token.loc;
+ tp_ident = token.ident;
+ nextToken();
+ if (token.value == TOK.colon) // : Type
+ {
+ nextToken();
+ tp_spectype = parseType();
+ }
+ if (token.value == TOK.assign) // = Type
+ {
+ nextToken();
+ tp_defaulttype = parseType();
+ }
+ tp = new AST.TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+ }
+ else if (token.value == TOK.identifier && tv == TOK.dotDotDot)
+ {
+ // ident...
+ loc = token.loc;
+ tp_ident = token.ident;
+ nextToken();
+ nextToken();
+ tp = new AST.TemplateTupleParameter(loc, tp_ident);
+ }
+ else if (token.value == TOK.this_)
+ {
+ // ThisParameter
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected for template `this` parameter");
+ goto Lerr;
+ }
+ loc = token.loc;
+ tp_ident = token.ident;
+ nextToken();
+ if (token.value == TOK.colon) // : Type
+ {
+ nextToken();
+ tp_spectype = parseType();
+ }
+ if (token.value == TOK.assign) // = Type
+ {
+ nextToken();
+ tp_defaulttype = parseType();
+ }
+ tp = new AST.TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
+ }
+ else
+ {
+ // ValueParameter
+ loc = token.loc; // todo
+ tp_valtype = parseType(&tp_ident);
+ if (!tp_ident)
+ {
+ error("identifier expected for template value parameter");
+ tp_ident = Identifier.idPool("error");
+ }
+ if (token.value == TOK.colon) // : CondExpression
+ {
+ nextToken();
+ tp_specvalue = parseCondExp();
+ }
+ if (token.value == TOK.assign) // = CondExpression
+ {
+ nextToken();
+ tp_defaultvalue = parseDefaultInitExp();
+ }
+ tp = new AST.TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
+ }
+ tpl.push(tp);
+ if (token.value != TOK.comma)
+ break;
+ nextToken();
+ }
+ }
+ check(TOK.rightParenthesis);
+
+ Lerr:
+ return tpl;
+ }
+
+ /******************************************
+ * Parse template mixin.
+ * mixin Foo;
+ * mixin Foo!(args);
+ * mixin a.b.c!(args).Foo!(args);
+ * mixin Foo!(args) identifier;
+ * mixin typeof(expr).identifier!(args);
+ */
+ private AST.Dsymbol parseMixin()
+ {
+ AST.TemplateMixin tm;
+ Identifier id;
+ AST.Objects* tiargs;
+
+ //printf("parseMixin()\n");
+ const locMixin = token.loc;
+ nextToken(); // skip 'mixin'
+
+ auto loc = token.loc;
+ AST.TypeQualified tqual = null;
+ if (token.value == TOK.dot)
+ {
+ id = Id.empty;
+ }
+ else
+ {
+ if (token.value == TOK.typeof_)
+ {
+ tqual = parseTypeof();
+ check(TOK.dot);
+ }
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected, not `%s`", token.toChars());
+ id = Id.empty;
+ }
+ else
+ id = token.ident;
+ nextToken();
+ }
+
+ while (1)
+ {
+ tiargs = null;
+ if (token.value == TOK.not)
+ {
+ tiargs = parseTemplateArguments();
+ }
+
+ if (tiargs && token.value == TOK.dot)
+ {
+ auto tempinst = new AST.TemplateInstance(loc, id, tiargs);
+ if (!tqual)
+ tqual = new AST.TypeInstance(loc, tempinst);
+ else
+ tqual.addInst(tempinst);
+ tiargs = null;
+ }
+ else
+ {
+ if (!tqual)
+ tqual = new AST.TypeIdentifier(loc, id);
+ else
+ tqual.addIdent(id);
+ }
+
+ if (token.value != TOK.dot)
+ break;
+
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `.` instead of `%s`", token.toChars());
+ break;
+ }
+ loc = token.loc;
+ id = token.ident;
+ nextToken();
+ }
+
+ id = null;
+ if (token.value == TOK.identifier)
+ {
+ id = token.ident;
+ nextToken();
+ }
+
+ tm = new AST.TemplateMixin(locMixin, id, tqual, tiargs);
+ if (token.value != TOK.semicolon)
+ error("`;` expected after `mixin`");
+ nextToken();
+
+ return tm;
+ }
+
+ /******************************************
+ * Parse template arguments.
+ * Input:
+ * current token is opening '!'
+ * Output:
+ * current token is one after closing '$(RPAREN)'
+ */
+ private AST.Objects* parseTemplateArguments()
+ {
+ AST.Objects* tiargs;
+
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ {
+ // ident!(template_arguments)
+ tiargs = parseTemplateArgumentList();
+ }
+ else
+ {
+ // ident!template_argument
+ tiargs = parseTemplateSingleArgument();
+ }
+ if (token.value == TOK.not)
+ {
+ TOK tok = peekNext();
+ if (tok != TOK.is_ && tok != TOK.in_)
+ {
+ error("multiple ! arguments are not allowed");
+ Lagain:
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ parseTemplateArgumentList();
+ else
+ parseTemplateSingleArgument();
+ if (token.value == TOK.not && (tok = peekNext()) != TOK.is_ && tok != TOK.in_)
+ goto Lagain;
+ }
+ }
+ return tiargs;
+ }
+
+ /******************************************
+ * Parse template argument list.
+ * Input:
+ * current token is opening '$(LPAREN)',
+ * or ',' for __traits
+ * Output:
+ * current token is one after closing '$(RPAREN)'
+ */
+ private AST.Objects* parseTemplateArgumentList()
+ {
+ //printf("Parser::parseTemplateArgumentList()\n");
+ auto tiargs = new AST.Objects();
+ TOK endtok = TOK.rightParenthesis;
+ assert(token.value == TOK.leftParenthesis || token.value == TOK.comma);
+ nextToken();
+
+ // Get TemplateArgumentList
+ while (token.value != endtok)
+ {
+ tiargs.push(parseTypeOrAssignExp());
+ if (token.value != TOK.comma)
+ break;
+ nextToken();
+ }
+ check(endtok, "template argument list");
+ return tiargs;
+ }
+
+ /***************************************
+ * Parse a Type or an Expression
+ * Returns:
+ * RootObject representing the AST
+ */
+ RootObject parseTypeOrAssignExp(TOK endtoken = TOK.reserved)
+ {
+ return isDeclaration(&token, NeedDeclaratorId.no, endtoken, null)
+ ? parseType() // argument is a type
+ : parseAssignExp(); // argument is an expression
+ }
+
+ /*****************************
+ * Parse single template argument, to support the syntax:
+ * foo!arg
+ * Input:
+ * current token is the arg
+ */
+ private AST.Objects* parseTemplateSingleArgument()
+ {
+ //printf("parseTemplateSingleArgument()\n");
+ auto tiargs = new AST.Objects();
+ AST.Type ta;
+ switch (token.value)
+ {
+ case TOK.identifier:
+ ta = new AST.TypeIdentifier(token.loc, token.ident);
+ goto LabelX;
+
+ case TOK.vector:
+ ta = parseVector();
+ goto LabelX;
+
+ case TOK.void_:
+ ta = AST.Type.tvoid;
+ goto LabelX;
+
+ case TOK.int8:
+ ta = AST.Type.tint8;
+ goto LabelX;
+
+ case TOK.uns8:
+ ta = AST.Type.tuns8;
+ goto LabelX;
+
+ case TOK.int16:
+ ta = AST.Type.tint16;
+ goto LabelX;
+
+ case TOK.uns16:
+ ta = AST.Type.tuns16;
+ goto LabelX;
+
+ case TOK.int32:
+ ta = AST.Type.tint32;
+ goto LabelX;
+
+ case TOK.uns32:
+ ta = AST.Type.tuns32;
+ goto LabelX;
+
+ case TOK.int64:
+ ta = AST.Type.tint64;
+ goto LabelX;
+
+ case TOK.uns64:
+ ta = AST.Type.tuns64;
+ goto LabelX;
+
+ case TOK.int128:
+ ta = AST.Type.tint128;
+ goto LabelX;
+
+ case TOK.uns128:
+ ta = AST.Type.tuns128;
+ goto LabelX;
+
+ case TOK.float32:
+ ta = AST.Type.tfloat32;
+ goto LabelX;
+
+ case TOK.float64:
+ ta = AST.Type.tfloat64;
+ goto LabelX;
+
+ case TOK.float80:
+ ta = AST.Type.tfloat80;
+ goto LabelX;
+
+ case TOK.imaginary32:
+ ta = AST.Type.timaginary32;
+ goto LabelX;
+
+ case TOK.imaginary64:
+ ta = AST.Type.timaginary64;
+ goto LabelX;
+
+ case TOK.imaginary80:
+ ta = AST.Type.timaginary80;
+ goto LabelX;
+
+ case TOK.complex32:
+ ta = AST.Type.tcomplex32;
+ goto LabelX;
+
+ case TOK.complex64:
+ ta = AST.Type.tcomplex64;
+ goto LabelX;
+
+ case TOK.complex80:
+ ta = AST.Type.tcomplex80;
+ goto LabelX;
+
+ case TOK.bool_:
+ ta = AST.Type.tbool;
+ goto LabelX;
+
+ case TOK.char_:
+ ta = AST.Type.tchar;
+ goto LabelX;
+
+ case TOK.wchar_:
+ ta = AST.Type.twchar;
+ goto LabelX;
+
+ case TOK.dchar_:
+ ta = AST.Type.tdchar;
+ goto LabelX;
+ LabelX:
+ tiargs.push(ta);
+ nextToken();
+ break;
+
+ case TOK.int32Literal:
+ case TOK.uns32Literal:
+ case TOK.int64Literal:
+ case TOK.uns64Literal:
+ case TOK.int128Literal:
+ case TOK.uns128Literal:
+ case TOK.float32Literal:
+ case TOK.float64Literal:
+ case TOK.float80Literal:
+ case TOK.imaginary32Literal:
+ case TOK.imaginary64Literal:
+ case TOK.imaginary80Literal:
+ case TOK.null_:
+ case TOK.true_:
+ case TOK.false_:
+ case TOK.charLiteral:
+ case TOK.wcharLiteral:
+ case TOK.dcharLiteral:
+ case TOK.string_:
+ case TOK.hexadecimalString:
+ case TOK.file:
+ case TOK.fileFullPath:
+ case TOK.line:
+ case TOK.moduleString:
+ case TOK.functionString:
+ case TOK.prettyFunction:
+ case TOK.this_:
+ {
+ // Template argument is an expression
+ AST.Expression ea = parsePrimaryExp();
+ tiargs.push(ea);
+ break;
+ }
+ default:
+ error("template argument expected following `!`");
+ break;
+ }
+ return tiargs;
+ }
+
+ /**********************************
+ * Parse a static assertion.
+ * Current token is 'static'.
+ */
+ private AST.StaticAssert parseStaticAssert()
+ {
+ const loc = token.loc;
+ AST.Expression exp;
+ AST.Expression msg = null;
+
+ //printf("parseStaticAssert()\n");
+ nextToken();
+ nextToken();
+ check(TOK.leftParenthesis);
+ exp = parseAssignExp();
+ if (token.value == TOK.comma)
+ {
+ nextToken();
+ if (token.value != TOK.rightParenthesis)
+ {
+ msg = parseAssignExp();
+ if (token.value == TOK.comma)
+ nextToken();
+ }
+ }
+ check(TOK.rightParenthesis);
+ check(TOK.semicolon);
+ return new AST.StaticAssert(loc, exp, msg);
+ }
+
+ /***********************************
+ * Parse typeof(expression).
+ * Current token is on the 'typeof'.
+ */
+ private AST.TypeQualified parseTypeof()
+ {
+ AST.TypeQualified t;
+ const loc = token.loc;
+
+ nextToken();
+ check(TOK.leftParenthesis);
+ if (token.value == TOK.return_) // typeof(return)
+ {
+ nextToken();
+ t = new AST.TypeReturn(loc);
+ }
+ else
+ {
+ AST.Expression exp = parseExpression(); // typeof(expression)
+ t = new AST.TypeTypeof(loc, exp);
+ }
+ check(TOK.rightParenthesis);
+ return t;
+ }
+
+ /***********************************
+ * Parse __vector(type).
+ * Current token is on the '__vector'.
+ */
+ private AST.Type parseVector()
+ {
+ nextToken();
+ check(TOK.leftParenthesis);
+ AST.Type tb = parseType();
+ check(TOK.rightParenthesis);
+ return new AST.TypeVector(tb);
+ }
+
+ /***********************************
+ * Parse:
+ * extern (linkage)
+ * extern (C++, namespaces)
+ * extern (C++, "namespace", "namespaces", ...)
+ * extern (C++, (StringExp))
+ * The parser is on the 'extern' token.
+ */
+ private ParsedLinkage!(AST) parseLinkage()
+ {
+ ParsedLinkage!(AST) result;
+ nextToken();
+ assert(token.value == TOK.leftParenthesis);
+ nextToken();
+ ParsedLinkage!(AST) returnLinkage(LINK link)
+ {
+ check(TOK.rightParenthesis);
+ result.link = link;
+ return result;
+ }
+ ParsedLinkage!(AST) invalidLinkage()
+ {
+ error("valid linkage identifiers are `D`, `C`, `C++`, `Objective-C`, `Windows`, `System`");
+ return returnLinkage(LINK.d);
+ }
+
+ if (token.value != TOK.identifier)
+ return returnLinkage(LINK.d);
+
+ Identifier id = token.ident;
+ nextToken();
+ if (id == Id.Windows)
+ return returnLinkage(LINK.windows);
+ else if (id == Id.D)
+ return returnLinkage(LINK.d);
+ else if (id == Id.System)
+ return returnLinkage(LINK.system);
+ else if (id == Id.Objective) // Looking for tokens "Objective-C"
+ {
+ if (token.value != TOK.min)
+ return invalidLinkage();
+
+ nextToken();
+ if (token.ident != Id.C)
+ return invalidLinkage();
+
+ nextToken();
+ return returnLinkage(LINK.objc);
+ }
+ else if (id != Id.C)
+ return invalidLinkage();
+
+ if (token.value != TOK.plusPlus)
+ return returnLinkage(LINK.c);
+
+ nextToken();
+ if (token.value != TOK.comma) // , namespaces or class or struct
+ return returnLinkage(LINK.cpp);
+
+ nextToken();
+
+ if (token.value == TOK.rightParenthesis)
+ return returnLinkage(LINK.cpp); // extern(C++,)
+
+ if (token.value == TOK.class_ || token.value == TOK.struct_)
+ {
+ result.cppmangle = token.value == TOK.class_ ? CPPMANGLE.asClass : CPPMANGLE.asStruct;
+ nextToken();
+ }
+ else if (token.value == TOK.identifier) // named scope namespace
+ {
+ result.idents = new AST.Identifiers();
+ while (1)
+ {
+ Identifier idn = token.ident;
+ result.idents.push(idn);
+ nextToken();
+ if (token.value == TOK.dot)
+ {
+ nextToken();
+ if (token.value == TOK.identifier)
+ continue;
+ error("identifier expected for C++ namespace");
+ result.idents = null; // error occurred, invalidate list of elements.
+ }
+ break;
+ }
+ }
+ else // non-scoped StringExp namespace
+ {
+ result.identExps = new AST.Expressions();
+ while (1)
+ {
+ result.identExps.push(parseCondExp());
+ if (token.value != TOK.comma)
+ break;
+ nextToken();
+ // Allow trailing commas as done for argument lists, arrays, ...
+ if (token.value == TOK.rightParenthesis)
+ break;
+ }
+ }
+ return returnLinkage(LINK.cpp);
+ }
+
+ /***********************************
+ * Parse ident1.ident2.ident3
+ *
+ * Params:
+ * entity = what qualified identifier is expected to resolve into.
+ * Used only for better error message
+ *
+ * Returns:
+ * array of identifiers with actual qualified one stored last
+ */
+ private Identifier[] parseQualifiedIdentifier(const(char)* entity)
+ {
+ Identifier[] qualified;
+
+ do
+ {
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("`%s` expected as dot-separated identifiers, got `%s`", entity, token.toChars());
+ return qualified;
+ }
+
+ Identifier id = token.ident;
+ qualified ~= id;
+
+ nextToken();
+ }
+ while (token.value == TOK.dot);
+
+ return qualified;
+ }
+
+ /**************************************
+ * Parse a debug conditional
+ */
+ private AST.Condition parseDebugCondition()
+ {
+ uint level = 1;
+ Identifier id = null;
+ Loc loc = token.loc;
+
+ if (token.value == TOK.leftParenthesis)
+ {
+ nextToken();
+
+ if (token.value == TOK.identifier)
+ id = token.ident;
+ else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+ level = cast(uint)token.unsvalue;
+ else
+ error("identifier or integer expected inside `debug(...)`, not `%s`", token.toChars());
+ loc = token.loc;
+ nextToken();
+ check(TOK.rightParenthesis);
+ }
+ return new AST.DebugCondition(loc, mod, level, id);
+ }
+
+ /**************************************
+ * Parse a version conditional
+ */
+ private AST.Condition parseVersionCondition()
+ {
+ uint level = 1;
+ Identifier id = null;
+ Loc loc;
+
+ if (token.value == TOK.leftParenthesis)
+ {
+ nextToken();
+ /* Allow:
+ * version (unittest)
+ * version (assert)
+ * even though they are keywords
+ */
+ loc = token.loc;
+ if (token.value == TOK.identifier)
+ id = token.ident;
+ else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+ level = cast(uint)token.unsvalue;
+ else if (token.value == TOK.unittest_)
+ id = Identifier.idPool(Token.toString(TOK.unittest_));
+ else if (token.value == TOK.assert_)
+ id = Identifier.idPool(Token.toString(TOK.assert_));
+ else
+ error("identifier or integer expected inside `version(...)`, not `%s`", token.toChars());
+ nextToken();
+ check(TOK.rightParenthesis);
+ }
+ else
+ error("(condition) expected following `version`");
+ return new AST.VersionCondition(loc, mod, level, id);
+ }
+
+ /***********************************************
+ * static if (expression)
+ * body
+ * else
+ * body
+ * Current token is 'static'.
+ */
+ private AST.Condition parseStaticIfCondition()
+ {
+ AST.Expression exp;
+ AST.Condition condition;
+ const loc = token.loc;
+
+ nextToken();
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ {
+ nextToken();
+ exp = parseAssignExp();
+ check(TOK.rightParenthesis);
+ }
+ else
+ {
+ error("(expression) expected following `static if`");
+ exp = null;
+ }
+ condition = new AST.StaticIfCondition(loc, exp);
+ return condition;
+ }
+
+ /*****************************************
+ * Parse a constructor definition:
+ * this(parameters) { body }
+ * or postblit:
+ * this(this) { body }
+ * or constructor template:
+ * this(templateparameters)(parameters) { body }
+ * Current token is 'this'.
+ */
+ private AST.Dsymbol parseCtor(PrefixAttributes!AST* pAttrs)
+ {
+ AST.Expressions* udas = null;
+ const loc = token.loc;
+ StorageClass stc = getStorageClass!AST(pAttrs);
+
+ nextToken();
+ if (token.value == TOK.leftParenthesis && peekNext() == TOK.this_ && peekNext2() == TOK.rightParenthesis)
+ {
+ // this(this) { ... }
+ nextToken();
+ nextToken();
+ check(TOK.rightParenthesis);
+
+ stc = parsePostfix(stc, &udas);
+ if (stc & STC.immutable_)
+ deprecation("`immutable` postblit is deprecated. Please use an unqualified postblit.");
+ if (stc & STC.shared_)
+ deprecation("`shared` postblit is deprecated. Please use an unqualified postblit.");
+ if (stc & STC.const_)
+ deprecation("`const` postblit is deprecated. Please use an unqualified postblit.");
+ if (stc & STC.static_)
+ error(loc, "postblit cannot be `static`");
+
+ auto f = new AST.PostBlitDeclaration(loc, Loc.initial, stc, Id.postblit);
+ AST.Dsymbol s = parseContracts(f);
+ if (udas)
+ {
+ auto a = new AST.Dsymbols();
+ a.push(f);
+ s = new AST.UserAttributeDeclaration(udas, a);
+ }
+ return s;
+ }
+
+ /* Look ahead to see if:
+ * this(...)(...)
+ * which is a constructor template
+ */
+ AST.TemplateParameters* tpl = null;
+ if (token.value == TOK.leftParenthesis && peekPastParen(&token).value == TOK.leftParenthesis)
+ {
+ tpl = parseTemplateParameterList();
+ }
+
+ /* Just a regular constructor
+ */
+ auto parameterList = parseParameterList(null);
+ stc = parsePostfix(stc, &udas);
+
+ if (parameterList.varargs != VarArg.none || AST.Parameter.dim(parameterList.parameters) != 0)
+ {
+ if (stc & STC.static_)
+ error(loc, "constructor cannot be static");
+ }
+ else if (StorageClass ss = stc & (STC.shared_ | STC.static_)) // this()
+ {
+ if (ss == STC.static_)
+ error(loc, "use `static this()` to declare a static constructor");
+ else if (ss == (STC.shared_ | STC.static_))
+ error(loc, "use `shared static this()` to declare a shared static constructor");
+ }
+
+ AST.Expression constraint = tpl ? parseConstraint() : null;
+
+ AST.Type tf = new AST.TypeFunction(parameterList, null, linkage, stc); // RetrunType -> auto
+ tf = tf.addSTC(stc);
+
+ auto f = new AST.CtorDeclaration(loc, Loc.initial, stc, tf);
+ AST.Dsymbol s = parseContracts(f);
+ if (udas)
+ {
+ auto a = new AST.Dsymbols();
+ a.push(f);
+ s = new AST.UserAttributeDeclaration(udas, a);
+ }
+
+ if (tpl)
+ {
+ // Wrap a template around it
+ auto decldefs = new AST.Dsymbols();
+ decldefs.push(s);
+ s = new AST.TemplateDeclaration(loc, f.ident, tpl, constraint, decldefs);
+ }
+
+ return s;
+ }
+
+ /*****************************************
+ * Parse a destructor definition:
+ * ~this() { body }
+ * Current token is '~'.
+ */
+ private AST.Dsymbol parseDtor(PrefixAttributes!AST* pAttrs)
+ {
+ AST.Expressions* udas = null;
+ const loc = token.loc;
+ StorageClass stc = getStorageClass!AST(pAttrs);
+
+ nextToken();
+ check(TOK.this_);
+ check(TOK.leftParenthesis);
+ check(TOK.rightParenthesis);
+
+ stc = parsePostfix(stc, &udas);
+ if (StorageClass ss = stc & (STC.shared_ | STC.static_))
+ {
+ if (ss == STC.static_)
+ error(loc, "use `static ~this()` to declare a static destructor");
+ else if (ss == (STC.shared_ | STC.static_))
+ error(loc, "use `shared static ~this()` to declare a shared static destructor");
+ }
+
+ auto f = new AST.DtorDeclaration(loc, Loc.initial, stc, Id.dtor);
+ AST.Dsymbol s = parseContracts(f);
+ if (udas)
+ {
+ auto a = new AST.Dsymbols();
+ a.push(f);
+ s = new AST.UserAttributeDeclaration(udas, a);
+ }
+ return s;
+ }
+
+ /*****************************************
+ * Parse a static constructor definition:
+ * static this() { body }
+ * Current token is 'static'.
+ */
+ private AST.Dsymbol parseStaticCtor(PrefixAttributes!AST* pAttrs)
+ {
+ //Expressions *udas = NULL;
+ const loc = token.loc;
+ StorageClass stc = getStorageClass!AST(pAttrs);
+
+ nextToken();
+ nextToken();
+ check(TOK.leftParenthesis);
+ check(TOK.rightParenthesis);
+
+ stc = parsePostfix(stc & ~STC.TYPECTOR, null) | stc;
+ if (stc & STC.shared_)
+ error(loc, "use `shared static this()` to declare a shared static constructor");
+ else if (stc & STC.static_)
+ appendStorageClass(stc, STC.static_); // complaint for the redundancy
+ else if (StorageClass modStc = stc & STC.TYPECTOR)
+ {
+ OutBuffer buf;
+ AST.stcToBuffer(&buf, modStc);
+ error(loc, "static constructor cannot be `%s`", buf.peekChars());
+ }
+ stc &= ~(STC.static_ | STC.TYPECTOR);
+
+ auto f = new AST.StaticCtorDeclaration(loc, Loc.initial, stc);
+ AST.Dsymbol s = parseContracts(f);
+ return s;
+ }
+
+ /*****************************************
+ * Parse a static destructor definition:
+ * static ~this() { body }
+ * Current token is 'static'.
+ */
+ private AST.Dsymbol parseStaticDtor(PrefixAttributes!AST* pAttrs)
+ {
+ AST.Expressions* udas = null;
+ const loc = token.loc;
+ StorageClass stc = getStorageClass!AST(pAttrs);
+
+ nextToken();
+ nextToken();
+ check(TOK.this_);
+ check(TOK.leftParenthesis);
+ check(TOK.rightParenthesis);
+
+ stc = parsePostfix(stc & ~STC.TYPECTOR, &udas) | stc;
+ if (stc & STC.shared_)
+ error(loc, "use `shared static ~this()` to declare a shared static destructor");
+ else if (stc & STC.static_)
+ appendStorageClass(stc, STC.static_); // complaint for the redundancy
+ else if (StorageClass modStc = stc & STC.TYPECTOR)
+ {
+ OutBuffer buf;
+ AST.stcToBuffer(&buf, modStc);
+ error(loc, "static destructor cannot be `%s`", buf.peekChars());
+ }
+ stc &= ~(STC.static_ | STC.TYPECTOR);
+
+ auto f = new AST.StaticDtorDeclaration(loc, Loc.initial, stc);
+ AST.Dsymbol s = parseContracts(f);
+ if (udas)
+ {
+ auto a = new AST.Dsymbols();
+ a.push(f);
+ s = new AST.UserAttributeDeclaration(udas, a);
+ }
+ return s;
+ }
+
+ /*****************************************
+ * Parse a shared static constructor definition:
+ * shared static this() { body }
+ * Current token is 'shared'.
+ */
+ private AST.Dsymbol parseSharedStaticCtor(PrefixAttributes!AST* pAttrs)
+ {
+ //Expressions *udas = NULL;
+ const loc = token.loc;
+ StorageClass stc = getStorageClass!AST(pAttrs);
+
+ nextToken();
+ nextToken();
+ nextToken();
+ check(TOK.leftParenthesis);
+ check(TOK.rightParenthesis);
+
+ stc = parsePostfix(stc & ~STC.TYPECTOR, null) | stc;
+ if (StorageClass ss = stc & (STC.shared_ | STC.static_))
+ appendStorageClass(stc, ss); // complaint for the redundancy
+ else if (StorageClass modStc = stc & STC.TYPECTOR)
+ {
+ OutBuffer buf;
+ AST.stcToBuffer(&buf, modStc);
+ error(loc, "shared static constructor cannot be `%s`", buf.peekChars());
+ }
+ stc &= ~(STC.static_ | STC.TYPECTOR);
+
+ auto f = new AST.SharedStaticCtorDeclaration(loc, Loc.initial, stc);
+ AST.Dsymbol s = parseContracts(f);
+ return s;
+ }
+
+ /*****************************************
+ * Parse a shared static destructor definition:
+ * shared static ~this() { body }
+ * Current token is 'shared'.
+ */
+ private AST.Dsymbol parseSharedStaticDtor(PrefixAttributes!AST* pAttrs)
+ {
+ AST.Expressions* udas = null;
+ const loc = token.loc;
+ StorageClass stc = getStorageClass!AST(pAttrs);
+
+ nextToken();
+ nextToken();
+ nextToken();
+ check(TOK.this_);
+ check(TOK.leftParenthesis);
+ check(TOK.rightParenthesis);
+
+ stc = parsePostfix(stc & ~STC.TYPECTOR, &udas) | stc;
+ if (StorageClass ss = stc & (STC.shared_ | STC.static_))
+ appendStorageClass(stc, ss); // complaint for the redundancy
+ else if (StorageClass modStc = stc & STC.TYPECTOR)
+ {
+ OutBuffer buf;
+ AST.stcToBuffer(&buf, modStc);
+ error(loc, "shared static destructor cannot be `%s`", buf.peekChars());
+ }
+ stc &= ~(STC.static_ | STC.TYPECTOR);
+
+ auto f = new AST.SharedStaticDtorDeclaration(loc, Loc.initial, stc);
+ AST.Dsymbol s = parseContracts(f);
+ if (udas)
+ {
+ auto a = new AST.Dsymbols();
+ a.push(f);
+ s = new AST.UserAttributeDeclaration(udas, a);
+ }
+ return s;
+ }
+
+ /*****************************************
+ * Parse an invariant definition:
+ * invariant { statements... }
+ * invariant() { statements... }
+ * invariant (expression);
+ * Current token is 'invariant'.
+ */
+ private AST.Dsymbol parseInvariant(PrefixAttributes!AST* pAttrs)
+ {
+ const loc = token.loc;
+ StorageClass stc = getStorageClass!AST(pAttrs);
+
+ nextToken();
+ if (token.value == TOK.leftParenthesis) // optional () or invariant (expression);
+ {
+ nextToken();
+ if (token.value != TOK.rightParenthesis) // invariant (expression);
+ {
+ AST.Expression e = parseAssignExp(), msg = null;
+ if (token.value == TOK.comma)
+ {
+ nextToken();
+ if (token.value != TOK.rightParenthesis)
+ {
+ msg = parseAssignExp();
+ if (token.value == TOK.comma)
+ nextToken();
+ }
+ }
+ check(TOK.rightParenthesis);
+ check(TOK.semicolon);
+ e = new AST.AssertExp(loc, e, msg);
+ auto fbody = new AST.ExpStatement(loc, e);
+ auto f = new AST.InvariantDeclaration(loc, token.loc, stc, null, fbody);
+ return f;
+ }
+ nextToken();
+ }
+
+ auto fbody = parseStatement(ParseStatementFlags.curly);
+ auto f = new AST.InvariantDeclaration(loc, token.loc, stc, null, fbody);
+ return f;
+ }
+
+ /*****************************************
+ * Parse a unittest definition:
+ * unittest { body }
+ * Current token is 'unittest'.
+ */
+ private AST.Dsymbol parseUnitTest(PrefixAttributes!AST* pAttrs)
+ {
+ const loc = token.loc;
+ StorageClass stc = getStorageClass!AST(pAttrs);
+
+ nextToken();
+
+ const(char)* begPtr = token.ptr + 1; // skip '{'
+ const(char)* endPtr = null;
+ AST.Statement sbody = parseStatement(ParseStatementFlags.curly, &endPtr);
+
+ /** Extract unittest body as a string. Must be done eagerly since memory
+ will be released by the lexer before doc gen. */
+ char* docline = null;
+ if (global.params.doDocComments && endPtr > begPtr)
+ {
+ /* Remove trailing whitespaces */
+ for (const(char)* p = endPtr - 1; begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p)
+ {
+ endPtr = p;
+ }
+
+ size_t len = endPtr - begPtr;
+ if (len > 0)
+ {
+ docline = cast(char*)mem.xmalloc_noscan(len + 2);
+ memcpy(docline, begPtr, len);
+ docline[len] = '\n'; // Terminate all lines by LF
+ docline[len + 1] = '\0';
+ }
+ }
+
+ auto f = new AST.UnitTestDeclaration(loc, token.loc, stc, docline);
+ f.fbody = sbody;
+ return f;
+ }
+
+ /*****************************************
+ * Parse a new definition:
+ * @disable new();
+ * Current token is 'new'.
+ */
+ private AST.Dsymbol parseNew(PrefixAttributes!AST* pAttrs)
+ {
+ const loc = token.loc;
+ StorageClass stc = getStorageClass!AST(pAttrs);
+ if (!(stc & STC.disable))
+ {
+ error("`new` allocator must be annotated with `@disabled`");
+ }
+ nextToken();
+
+ /* @@@DEPRECATED_2.098@@@
+ * After deprecation period (2.108), remove all code in the version(all) block.
+ */
+ version (all)
+ {
+ auto parameterList = parseParameterList(null); // parameterList ignored
+ if (parameterList.parameters.length > 0 || parameterList.varargs != VarArg.none)
+ deprecation("`new` allocator with non-empty parameter list is deprecated");
+ auto f = new AST.NewDeclaration(loc, stc);
+ if (token.value != TOK.semicolon)
+ {
+ deprecation("`new` allocator with function definition is deprecated");
+ parseContracts(f); // body ignored
+ f.fbody = null;
+ f.fensures = null;
+ f.frequires = null;
+ }
+ else
+ nextToken();
+ return f;
+ }
+ else
+ {
+ check(TOK.leftParenthesis);
+ check(TOK.rightParenthesis);
+ check(TOK.semicolon);
+ return new AST.NewDeclaration(loc, stc);
+ }
+ }
+
+ /**********************************************
+ * Parse parameter list.
+ */
+ private AST.ParameterList parseParameterList(AST.TemplateParameters** tpl)
+ {
+ auto parameters = new AST.Parameters();
+ VarArg varargs = VarArg.none;
+ int hasdefault = 0;
+ StorageClass varargsStc;
+
+ // Attributes allowed for ...
+ enum VarArgsStc = STC.const_ | STC.immutable_ | STC.shared_ | STC.scope_ | STC.return_;
+
+ check(TOK.leftParenthesis);
+ while (1)
+ {
+ Identifier ai = null;
+ AST.Type at;
+ StorageClass storageClass = 0;
+ StorageClass stc;
+ AST.Expression ae;
+ AST.Expressions* udas = null;
+ for (; 1; nextToken())
+ {
+ L3:
+ switch (token.value)
+ {
+ case TOK.rightParenthesis:
+ if (storageClass != 0 || udas !is null)
+ error("basic type expected, not `)`");
+ break;
+
+ case TOK.dotDotDot:
+ varargs = VarArg.variadic;
+ varargsStc = storageClass;
+ if (varargsStc & ~VarArgsStc)
+ {
+ OutBuffer buf;
+ AST.stcToBuffer(&buf, varargsStc & ~VarArgsStc);
+ error("variadic parameter cannot have attributes `%s`", buf.peekChars());
+ varargsStc &= VarArgsStc;
+ }
+ nextToken();
+ break;
+
+ case TOK.const_:
+ if (peekNext() == TOK.leftParenthesis)
+ goto default;
+ stc = STC.const_;
+ goto L2;
+
+ case TOK.immutable_:
+ if (peekNext() == TOK.leftParenthesis)
+ goto default;
+ stc = STC.immutable_;
+ goto L2;
+
+ case TOK.shared_:
+ if (peekNext() == TOK.leftParenthesis)
+ goto default;
+ stc = STC.shared_;
+ goto L2;
+
+ case TOK.inout_:
+ if (peekNext() == TOK.leftParenthesis)
+ goto default;
+ stc = STC.wild;
+ goto L2;
+ case TOK.at:
+ {
+ AST.Expressions* exps = null;
+ StorageClass stc2 = parseAttribute(exps);
+ if (stc2 & atAttrGroup)
+ {
+ error("`@%s` attribute for function parameter is not supported", token.toChars());
+ }
+ else
+ {
+ udas = AST.UserAttributeDeclaration.concat(udas, exps);
+ }
+ if (token.value == TOK.dotDotDot)
+ error("variadic parameter cannot have user-defined attributes");
+ if (stc2)
+ nextToken();
+ goto L3;
+ // Don't call nextToken again.
+ }
+ case TOK.in_:
+ stc = STC.in_;
+ goto L2;
+
+ case TOK.out_:
+ stc = STC.out_;
+ goto L2;
+
+ case TOK.ref_:
+ stc = STC.ref_;
+ goto L2;
+
+ case TOK.lazy_:
+ stc = STC.lazy_;
+ goto L2;
+
+ case TOK.scope_:
+ stc = STC.scope_;
+ goto L2;
+
+ case TOK.final_:
+ stc = STC.final_;
+ goto L2;
+
+ case TOK.auto_:
+ stc = STC.auto_;
+ goto L2;
+
+ case TOK.return_:
+ stc = STC.return_;
+ goto L2;
+ L2:
+ storageClass = appendStorageClass(storageClass, stc);
+ continue;
+
+ version (none)
+ {
+ case TOK.static_:
+ stc = STC.static_;
+ goto L2;
+
+ case TOK.auto_:
+ storageClass = STC.auto_;
+ goto L4;
+
+ case TOK.alias_:
+ storageClass = STC.alias_;
+ goto L4;
+ L4:
+ nextToken();
+ ai = null;
+ if (token.value == TOK.identifier)
+ {
+ ai = token.ident;
+ nextToken();
+ }
+
+ at = null; // no type
+ ae = null; // no default argument
+ if (token.value == TOK.assign) // = defaultArg
+ {
+ nextToken();
+ ae = parseDefaultInitExp();
+ hasdefault = 1;
+ }
+ else
+ {
+ if (hasdefault)
+ error("default argument expected for `alias %s`", ai ? ai.toChars() : "");
+ }
+ goto L3;
+ }
+ default:
+ {
+ stc = storageClass & (STC.IOR | STC.lazy_);
+ // if stc is not a power of 2
+ if (stc & (stc - 1) && !(stc == (STC.in_ | STC.ref_)))
+ error("incompatible parameter storage classes");
+ //if ((storageClass & STC.scope_) && (storageClass & (STC.ref_ | STC.out_)))
+ //error("scope cannot be ref or out");
+
+ if (tpl && token.value == TOK.identifier)
+ {
+ const tv = peekNext();
+ if (tv == TOK.comma || tv == TOK.rightParenthesis || tv == TOK.dotDotDot)
+ {
+ Identifier id = Identifier.generateId("__T");
+ const loc = token.loc;
+ at = new AST.TypeIdentifier(loc, id);
+ if (!*tpl)
+ *tpl = new AST.TemplateParameters();
+ AST.TemplateParameter tp = new AST.TemplateTypeParameter(loc, id, null, null);
+ (*tpl).push(tp);
+
+ ai = token.ident;
+ nextToken();
+ }
+ else goto _else;
+ }
+ else
+ {
+ _else:
+ at = parseType(&ai);
+ }
+ ae = null;
+ if (token.value == TOK.assign) // = defaultArg
+ {
+ nextToken();
+ ae = parseDefaultInitExp();
+ hasdefault = 1;
+ }
+ else
+ {
+ if (hasdefault)
+ error("default argument expected for `%s`", ai ? ai.toChars() : at.toChars());
+ }
+ auto param = new AST.Parameter(storageClass | STC.parameter, at, ai, ae, null);
+ if (udas)
+ {
+ auto a = new AST.Dsymbols();
+ auto udad = new AST.UserAttributeDeclaration(udas, a);
+ param.userAttribDecl = udad;
+ }
+ if (token.value == TOK.at)
+ {
+ AST.Expressions* exps = null;
+ StorageClass stc2 = parseAttribute(exps);
+ if (stc2 & atAttrGroup)
+ {
+ error("`@%s` attribute for function parameter is not supported", token.toChars());
+ }
+ else
+ {
+ error("user-defined attributes cannot appear as postfixes", token.toChars());
+ }
+ if (stc2)
+ nextToken();
+ }
+ if (token.value == TOK.dotDotDot)
+ {
+ /* This is:
+ * at ai ...
+ */
+ if (storageClass & (STC.out_ | STC.ref_))
+ error("variadic argument cannot be `out` or `ref`");
+ varargs = VarArg.typesafe;
+ parameters.push(param);
+ nextToken();
+ break;
+ }
+ parameters.push(param);
+ if (token.value == TOK.comma)
+ {
+ nextToken();
+ goto L1;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ break;
+
+ L1:
+ }
+ check(TOK.rightParenthesis);
+ return AST.ParameterList(parameters, varargs, varargsStc);
+ }
+
+ /*************************************
+ */
+ private AST.EnumDeclaration parseEnum()
+ {
+ AST.EnumDeclaration e;
+ Identifier id;
+ AST.Type memtype;
+ auto loc = token.loc;
+
+ // printf("Parser::parseEnum()\n");
+ nextToken();
+ id = null;
+ if (token.value == TOK.identifier)
+ {
+ id = token.ident;
+ nextToken();
+ }
+
+ memtype = null;
+ if (token.value == TOK.colon)
+ {
+ nextToken();
+ int alt = 0;
+ const typeLoc = token.loc;
+ memtype = parseBasicType();
+ memtype = parseDeclarator(memtype, alt, null);
+ checkCstyleTypeSyntax(typeLoc, memtype, alt, null);
+ }
+
+ e = new AST.EnumDeclaration(loc, id, memtype);
+ if (token.value == TOK.semicolon && id)
+ nextToken();
+ else if (token.value == TOK.leftCurly)
+ {
+ bool isAnonymousEnum = !id;
+ TOK prevTOK;
+
+ //printf("enum definition\n");
+ e.members = new AST.Dsymbols();
+ nextToken();
+ const(char)[] comment = token.blockComment;
+ while (token.value != TOK.rightCurly)
+ {
+ /* Can take the following forms...
+ * 1. ident
+ * 2. ident = value
+ * 3. type ident = value
+ * ... prefixed by valid attributes
+ */
+ loc = token.loc;
+
+ AST.Type type = null;
+ Identifier ident = null;
+
+ AST.Expressions* udas;
+ StorageClass stc;
+ AST.Expression deprecationMessage;
+ enum attributeErrorMessage = "`%s` is not a valid attribute for enum members";
+ while(token.value != TOK.rightCurly
+ && token.value != TOK.comma
+ && token.value != TOK.assign)
+ {
+ switch(token.value)
+ {
+ case TOK.at:
+ if (StorageClass _stc = parseAttribute(udas))
+ {
+ if (_stc == STC.disable)
+ stc |= _stc;
+ else
+ {
+ OutBuffer buf;
+ AST.stcToBuffer(&buf, _stc);
+ error(attributeErrorMessage, buf.peekChars());
+ }
+ prevTOK = token.value;
+ nextToken();
+ }
+ break;
+ case TOK.deprecated_:
+ stc |= STC.deprecated_;
+ if (!parseDeprecatedAttribute(deprecationMessage))
+ {
+ prevTOK = token.value;
+ nextToken();
+ }
+ break;
+ case TOK.identifier:
+ const tv = peekNext();
+ if (tv == TOK.assign || tv == TOK.comma || tv == TOK.rightCurly)
+ {
+ ident = token.ident;
+ type = null;
+ prevTOK = token.value;
+ nextToken();
+ }
+ else
+ {
+ goto default;
+ }
+ break;
+ default:
+ if (isAnonymousEnum)
+ {
+ type = parseType(&ident, null);
+ if (type == AST.Type.terror)
+ {
+ type = null;
+ prevTOK = token.value;
+ nextToken();
+ }
+ else
+ {
+ prevTOK = TOK.identifier;
+ }
+ }
+ else
+ {
+ error(attributeErrorMessage, token.toChars());
+ prevTOK = token.value;
+ nextToken();
+ }
+ break;
+ }
+ if (token.value == TOK.comma)
+ {
+ prevTOK = token.value;
+ }
+ }
+
+ if (type && type != AST.Type.terror)
+ {
+ if (!ident)
+ error("no identifier for declarator `%s`", type.toChars());
+ if (!isAnonymousEnum)
+ error("type only allowed if anonymous enum and no enum type");
+ }
+ AST.Expression value;
+ if (token.value == TOK.assign)
+ {
+ if (prevTOK == TOK.identifier)
+ {
+ nextToken();
+ value = parseAssignExp();
+ }
+ else
+ {
+ error("assignment must be preceded by an identifier");
+ nextToken();
+ }
+ }
+ else
+ {
+ value = null;
+ if (type && type != AST.Type.terror && isAnonymousEnum)
+ error("if type, there must be an initializer");
+ }
+
+ AST.DeprecatedDeclaration dd;
+ if (deprecationMessage)
+ {
+ dd = new AST.DeprecatedDeclaration(deprecationMessage, null);
+ stc |= STC.deprecated_;
+ }
+
+ auto em = new AST.EnumMember(loc, ident, value, type, stc, null, dd);
+ e.members.push(em);
+
+ if (udas)
+ {
+ auto s = new AST.Dsymbols();
+ s.push(em);
+ auto uad = new AST.UserAttributeDeclaration(udas, s);
+ em.userAttribDecl = uad;
+ }
+
+ if (token.value == TOK.rightCurly)
+ {
+ }
+ else
+ {
+ addComment(em, comment);
+ comment = null;
+ check(TOK.comma);
+ }
+ addComment(em, comment);
+ comment = token.blockComment;
+
+ if (token.value == TOK.endOfFile)
+ {
+ error("premature end of file");
+ break;
+ }
+ }
+ nextToken();
+ }
+ else
+ error("enum declaration is invalid");
+
+ //printf("-parseEnum() %s\n", e.toChars());
+ return e;
+ }
+
+ /********************************
+ * Parse struct, union, interface, class.
+ */
+ private AST.Dsymbol parseAggregate()
+ {
+ AST.TemplateParameters* tpl = null;
+ AST.Expression constraint;
+ const loc = token.loc;
+ TOK tok = token.value;
+
+ //printf("Parser::parseAggregate()\n");
+ nextToken();
+ Identifier id;
+ if (token.value != TOK.identifier)
+ {
+ id = null;
+ }
+ else
+ {
+ id = token.ident;
+ nextToken();
+
+ if (token.value == TOK.leftParenthesis)
+ {
+ // struct/class template declaration.
+ tpl = parseTemplateParameterList();
+ constraint = parseConstraint();
+ }
+ }
+
+ // Collect base class(es)
+ AST.BaseClasses* baseclasses = null;
+ if (token.value == TOK.colon)
+ {
+ if (tok != TOK.interface_ && tok != TOK.class_)
+ error("base classes are not allowed for `%s`, did you mean `;`?", Token.toChars(tok));
+ nextToken();
+ baseclasses = parseBaseClasses();
+ }
+
+ if (token.value == TOK.if_)
+ {
+ if (constraint)
+ error("template constraints appear both before and after BaseClassList, put them before");
+ constraint = parseConstraint();
+ }
+ if (constraint)
+ {
+ if (!id)
+ error("template constraints not allowed for anonymous `%s`", Token.toChars(tok));
+ if (!tpl)
+ error("template constraints only allowed for templates");
+ }
+
+ AST.Dsymbols* members = null;
+ if (token.value == TOK.leftCurly)
+ {
+ //printf("aggregate definition\n");
+ const lookingForElseSave = lookingForElse;
+ lookingForElse = Loc();
+ nextToken();
+ members = parseDeclDefs(0);
+ lookingForElse = lookingForElseSave;
+ if (token.value != TOK.rightCurly)
+ {
+ /* { */
+ error("`}` expected following members in `%s` declaration at %s",
+ Token.toChars(tok), loc.toChars());
+ }
+ nextToken();
+ }
+ else if (token.value == TOK.semicolon && id)
+ {
+ if (baseclasses || constraint)
+ error("members expected");
+ nextToken();
+ }
+ else
+ {
+ error("{ } expected following `%s` declaration", Token.toChars(tok));
+ }
+
+ AST.AggregateDeclaration a;
+ switch (tok)
+ {
+ case TOK.interface_:
+ if (!id)
+ error(loc, "anonymous interfaces not allowed");
+ a = new AST.InterfaceDeclaration(loc, id, baseclasses);
+ a.members = members;
+ break;
+
+ case TOK.class_:
+ if (!id)
+ error(loc, "anonymous classes not allowed");
+ bool inObject = md && !md.packages && md.id == Id.object;
+ a = new AST.ClassDeclaration(loc, id, baseclasses, members, inObject);
+ break;
+
+ case TOK.struct_:
+ if (id)
+ {
+ bool inObject = md && !md.packages && md.id == Id.object;
+ a = new AST.StructDeclaration(loc, id, inObject);
+ a.members = members;
+ }
+ else
+ {
+ /* Anonymous structs/unions are more like attributes.
+ */
+ assert(!tpl);
+ return new AST.AnonDeclaration(loc, false, members);
+ }
+ break;
+
+ case TOK.union_:
+ if (id)
+ {
+ a = new AST.UnionDeclaration(loc, id);
+ a.members = members;
+ }
+ else
+ {
+ /* Anonymous structs/unions are more like attributes.
+ */
+ assert(!tpl);
+ return new AST.AnonDeclaration(loc, true, members);
+ }
+ break;
+
+ default:
+ assert(0);
+ }
+
+ if (tpl)
+ {
+ // Wrap a template around the aggregate declaration
+ auto decldefs = new AST.Dsymbols();
+ decldefs.push(a);
+ auto tempdecl = new AST.TemplateDeclaration(loc, id, tpl, constraint, decldefs);
+ return tempdecl;
+ }
+ return a;
+ }
+
+ /*******************************************
+ */
+ private AST.BaseClasses* parseBaseClasses()
+ {
+ auto baseclasses = new AST.BaseClasses();
+
+ for (; 1; nextToken())
+ {
+ auto b = new AST.BaseClass(parseBasicType());
+ baseclasses.push(b);
+ if (token.value != TOK.comma)
+ break;
+ }
+ return baseclasses;
+ }
+
+ private AST.Dsymbols* parseImport()
+ {
+ auto decldefs = new AST.Dsymbols();
+ Identifier aliasid = null;
+
+ int isstatic = token.value == TOK.static_;
+ if (isstatic)
+ nextToken();
+
+ //printf("Parser::parseImport()\n");
+ do
+ {
+ L1:
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `import`");
+ break;
+ }
+
+ const loc = token.loc;
+ Identifier id = token.ident;
+ Identifier[] a;
+ nextToken();
+ if (!aliasid && token.value == TOK.assign)
+ {
+ aliasid = id;
+ goto L1;
+ }
+ while (token.value == TOK.dot)
+ {
+ a ~= id;
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `package`");
+ break;
+ }
+ id = token.ident;
+ nextToken();
+ }
+
+ auto s = new AST.Import(loc, a, id, aliasid, isstatic);
+ decldefs.push(s);
+
+ /* Look for
+ * : alias=name, alias=name;
+ * syntax.
+ */
+ if (token.value == TOK.colon)
+ {
+ do
+ {
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `:`");
+ break;
+ }
+ Identifier _alias = token.ident;
+ Identifier name;
+ nextToken();
+ if (token.value == TOK.assign)
+ {
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `%s=`", _alias.toChars());
+ break;
+ }
+ name = token.ident;
+ nextToken();
+ }
+ else
+ {
+ name = _alias;
+ _alias = null;
+ }
+ s.addAlias(name, _alias);
+ }
+ while (token.value == TOK.comma);
+ break; // no comma-separated imports of this form
+ }
+ aliasid = null;
+ }
+ while (token.value == TOK.comma);
+
+ if (token.value == TOK.semicolon)
+ nextToken();
+ else
+ {
+ error("`;` expected");
+ nextToken();
+ }
+
+ return decldefs;
+ }
+
+ AST.Type parseType(Identifier* pident = null, AST.TemplateParameters** ptpl = null)
+ {
+ /* Take care of the storage class prefixes that
+ * serve as type attributes:
+ * const type
+ * immutable type
+ * shared type
+ * inout type
+ * inout const type
+ * shared const type
+ * shared inout type
+ * shared inout const type
+ */
+ StorageClass stc = 0;
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.const_:
+ if (peekNext() == TOK.leftParenthesis)
+ break; // const as type constructor
+ stc |= STC.const_; // const as storage class
+ nextToken();
+ continue;
+
+ case TOK.immutable_:
+ if (peekNext() == TOK.leftParenthesis)
+ break;
+ stc |= STC.immutable_;
+ nextToken();
+ continue;
+
+ case TOK.shared_:
+ if (peekNext() == TOK.leftParenthesis)
+ break;
+ stc |= STC.shared_;
+ nextToken();
+ continue;
+
+ case TOK.inout_:
+ if (peekNext() == TOK.leftParenthesis)
+ break;
+ stc |= STC.wild;
+ nextToken();
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ const typeLoc = token.loc;
+
+ AST.Type t;
+ t = parseBasicType();
+
+ int alt = 0;
+ t = parseDeclarator(t, alt, pident, ptpl);
+ checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : null);
+
+ t = t.addSTC(stc);
+ return t;
+ }
+
+ private AST.Type parseBasicType(bool dontLookDotIdents = false)
+ {
+ AST.Type t;
+ Loc loc;
+ Identifier id;
+ //printf("parseBasicType()\n");
+ switch (token.value)
+ {
+ case TOK.void_:
+ t = AST.Type.tvoid;
+ goto LabelX;
+
+ case TOK.int8:
+ t = AST.Type.tint8;
+ goto LabelX;
+
+ case TOK.uns8:
+ t = AST.Type.tuns8;
+ goto LabelX;
+
+ case TOK.int16:
+ t = AST.Type.tint16;
+ goto LabelX;
+
+ case TOK.uns16:
+ t = AST.Type.tuns16;
+ goto LabelX;
+
+ case TOK.int32:
+ t = AST.Type.tint32;
+ goto LabelX;
+
+ case TOK.uns32:
+ t = AST.Type.tuns32;
+ goto LabelX;
+
+ case TOK.int64:
+ t = AST.Type.tint64;
+ nextToken();
+ if (token.value == TOK.int64) // if `long long`
+ {
+ error("use `long` for a 64 bit integer instead of `long long`");
+ nextToken();
+ }
+ else if (token.value == TOK.float64) // if `long double`
+ {
+ error("use `real` instead of `long double`");
+ t = AST.Type.tfloat80;
+ nextToken();
+ }
+ break;
+
+ case TOK.uns64:
+ t = AST.Type.tuns64;
+ goto LabelX;
+
+ case TOK.int128:
+ t = AST.Type.tint128;
+ goto LabelX;
+
+ case TOK.uns128:
+ t = AST.Type.tuns128;
+ goto LabelX;
+
+ case TOK.float32:
+ t = AST.Type.tfloat32;
+ goto LabelX;
+
+ case TOK.float64:
+ t = AST.Type.tfloat64;
+ goto LabelX;
+
+ case TOK.float80:
+ t = AST.Type.tfloat80;
+ goto LabelX;
+
+ case TOK.imaginary32:
+ t = AST.Type.timaginary32;
+ goto LabelX;
+
+ case TOK.imaginary64:
+ t = AST.Type.timaginary64;
+ goto LabelX;
+
+ case TOK.imaginary80:
+ t = AST.Type.timaginary80;
+ goto LabelX;
+
+ case TOK.complex32:
+ t = AST.Type.tcomplex32;
+ goto LabelX;
+
+ case TOK.complex64:
+ t = AST.Type.tcomplex64;
+ goto LabelX;
+
+ case TOK.complex80:
+ t = AST.Type.tcomplex80;
+ goto LabelX;
+
+ case TOK.bool_:
+ t = AST.Type.tbool;
+ goto LabelX;
+
+ case TOK.char_:
+ t = AST.Type.tchar;
+ goto LabelX;
+
+ case TOK.wchar_:
+ t = AST.Type.twchar;
+ goto LabelX;
+
+ case TOK.dchar_:
+ t = AST.Type.tdchar;
+ goto LabelX;
+ LabelX:
+ nextToken();
+ break;
+
+ case TOK.this_:
+ case TOK.super_:
+ case TOK.identifier:
+ loc = token.loc;
+ id = token.ident;
+ nextToken();
+ if (token.value == TOK.not)
+ {
+ // ident!(template_arguments)
+ auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments());
+ t = parseBasicTypeStartingAt(new AST.TypeInstance(loc, tempinst), dontLookDotIdents);
+ }
+ else
+ {
+ t = parseBasicTypeStartingAt(new AST.TypeIdentifier(loc, id), dontLookDotIdents);
+ }
+ break;
+
+ case TOK.mixin_:
+ // https://dlang.org/spec/expression.html#mixin_types
+ loc = token.loc;
+ nextToken();
+ if (token.value != TOK.leftParenthesis)
+ error("found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis));
+ auto exps = parseArguments();
+ t = new AST.TypeMixin(loc, exps);
+ break;
+
+ case TOK.dot:
+ // Leading . as in .foo
+ t = parseBasicTypeStartingAt(new AST.TypeIdentifier(token.loc, Id.empty), dontLookDotIdents);
+ break;
+
+ case TOK.typeof_:
+ // typeof(expression)
+ t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents);
+ break;
+
+ case TOK.vector:
+ t = parseVector();
+ break;
+
+ case TOK.traits:
+ if (AST.TraitsExp te = cast(AST.TraitsExp) parsePrimaryExp())
+ if (te.ident && te.args)
+ {
+ t = new AST.TypeTraits(token.loc, te);
+ break;
+ }
+ t = new AST.TypeError;
+ break;
+
+ case TOK.const_:
+ // const(type)
+ nextToken();
+ check(TOK.leftParenthesis);
+ t = parseType().addSTC(STC.const_);
+ check(TOK.rightParenthesis);
+ break;
+
+ case TOK.immutable_:
+ // immutable(type)
+ nextToken();
+ check(TOK.leftParenthesis);
+ t = parseType().addSTC(STC.immutable_);
+ check(TOK.rightParenthesis);
+ break;
+
+ case TOK.shared_:
+ // shared(type)
+ nextToken();
+ check(TOK.leftParenthesis);
+ t = parseType().addSTC(STC.shared_);
+ check(TOK.rightParenthesis);
+ break;
+
+ case TOK.inout_:
+ // wild(type)
+ nextToken();
+ check(TOK.leftParenthesis);
+ t = parseType().addSTC(STC.wild);
+ check(TOK.rightParenthesis);
+ break;
+
+ default:
+ error("basic type expected, not `%s`", token.toChars());
+ if (token.value == TOK.else_)
+ errorSupplemental(token.loc, "There's no `static else`, use `else` instead.");
+ t = AST.Type.terror;
+ break;
+ }
+ return t;
+ }
+
+ private AST.Type parseBasicTypeStartingAt(AST.TypeQualified tid, bool dontLookDotIdents)
+ {
+ AST.Type maybeArray = null;
+ // See https://issues.dlang.org/show_bug.cgi?id=1215
+ // A basic type can look like MyType (typical case), but also:
+ // MyType.T -> A type
+ // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
+ // MyType[expr].T -> A type.
+ // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type
+ // (iif MyType[expr].T is a Ttuple)
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.dot:
+ {
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `.` instead of `%s`", token.toChars());
+ break;
+ }
+ if (maybeArray)
+ {
+ // This is actually a TypeTuple index, not an {a/s}array.
+ // We need to have a while loop to unwind all index taking:
+ // T[e1][e2].U -> T, addIndex(e1), addIndex(e2)
+ AST.Objects dimStack;
+ AST.Type t = maybeArray;
+ while (true)
+ {
+ if (t.ty == Tsarray)
+ {
+ // The index expression is an Expression.
+ AST.TypeSArray a = cast(AST.TypeSArray)t;
+ dimStack.push(a.dim.syntaxCopy());
+ t = a.next.syntaxCopy();
+ }
+ else if (t.ty == Taarray)
+ {
+ // The index expression is a Type. It will be interpreted as an expression at semantic time.
+ AST.TypeAArray a = cast(AST.TypeAArray)t;
+ dimStack.push(a.index.syntaxCopy());
+ t = a.next.syntaxCopy();
+ }
+ else
+ {
+ break;
+ }
+ }
+ assert(dimStack.dim > 0);
+ // We're good. Replay indices in the reverse order.
+ tid = cast(AST.TypeQualified)t;
+ while (dimStack.dim)
+ {
+ tid.addIndex(dimStack.pop());
+ }
+ maybeArray = null;
+ }
+ const loc = token.loc;
+ Identifier id = token.ident;
+ nextToken();
+ if (token.value == TOK.not)
+ {
+ auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments());
+ tid.addInst(tempinst);
+ }
+ else
+ tid.addIdent(id);
+ continue;
+ }
+ case TOK.leftBracket:
+ {
+ if (dontLookDotIdents) // workaround for https://issues.dlang.org/show_bug.cgi?id=14911
+ goto Lend;
+
+ nextToken();
+ AST.Type t = maybeArray ? maybeArray : cast(AST.Type)tid;
+ if (token.value == TOK.rightBracket)
+ {
+ // It's a dynamic array, and we're done:
+ // T[].U does not make sense.
+ t = new AST.TypeDArray(t);
+ nextToken();
+ return t;
+ }
+ else if (isDeclaration(&token, NeedDeclaratorId.no, TOK.rightBracket, null))
+ {
+ // This can be one of two things:
+ // 1 - an associative array declaration, T[type]
+ // 2 - an associative array declaration, T[expr]
+ // These can only be disambiguated later.
+ AST.Type index = parseType(); // [ type ]
+ maybeArray = new AST.TypeAArray(t, index);
+ check(TOK.rightBracket);
+ }
+ else
+ {
+ // This can be one of three things:
+ // 1 - an static array declaration, T[expr]
+ // 2 - a slice, T[expr .. expr]
+ // 3 - a template parameter pack index expression, T[expr].U
+ // 1 and 3 can only be disambiguated later.
+ //printf("it's type[expression]\n");
+ inBrackets++;
+ AST.Expression e = parseAssignExp(); // [ expression ]
+ if (token.value == TOK.slice)
+ {
+ // It's a slice, and we're done.
+ nextToken();
+ AST.Expression e2 = parseAssignExp(); // [ exp .. exp ]
+ t = new AST.TypeSlice(t, e, e2);
+ inBrackets--;
+ check(TOK.rightBracket);
+ return t;
+ }
+ else
+ {
+ maybeArray = new AST.TypeSArray(t, e);
+ inBrackets--;
+ check(TOK.rightBracket);
+ continue;
+ }
+ }
+ break;
+ }
+ default:
+ goto Lend;
+ }
+ }
+ Lend:
+ return maybeArray ? maybeArray : cast(AST.Type)tid;
+ }
+
+ /******************************************
+ * Parse suffixes to type t.
+ * *
+ * []
+ * [AssignExpression]
+ * [AssignExpression .. AssignExpression]
+ * [Type]
+ * delegate Parameters MemberFunctionAttributes(opt)
+ * function Parameters FunctionAttributes(opt)
+ * Params:
+ * t = the already parsed type
+ * Returns:
+ * t with the suffixes added
+ * See_Also:
+ * https://dlang.org/spec/declaration.html#TypeSuffixes
+ */
+ private AST.Type parseTypeSuffixes(AST.Type t)
+ {
+ //printf("parseTypeSuffixes()\n");
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.mul:
+ t = new AST.TypePointer(t);
+ nextToken();
+ continue;
+
+ case TOK.leftBracket:
+ // Handle []. Make sure things like
+ // int[3][1] a;
+ // is (array[1] of array[3] of int)
+ nextToken();
+ if (token.value == TOK.rightBracket)
+ {
+ t = new AST.TypeDArray(t); // []
+ nextToken();
+ }
+ else if (isDeclaration(&token, NeedDeclaratorId.no, TOK.rightBracket, null))
+ {
+ // It's an associative array declaration
+ //printf("it's an associative array\n");
+ AST.Type index = parseType(); // [ type ]
+ t = new AST.TypeAArray(t, index);
+ check(TOK.rightBracket);
+ }
+ else
+ {
+ //printf("it's type[expression]\n");
+ inBrackets++;
+ AST.Expression e = parseAssignExp(); // [ expression ]
+ if (!e)
+ {
+ inBrackets--;
+ check(TOK.rightBracket);
+ continue;
+ }
+ if (token.value == TOK.slice)
+ {
+ nextToken();
+ AST.Expression e2 = parseAssignExp(); // [ exp .. exp ]
+ t = new AST.TypeSlice(t, e, e2);
+ }
+ else
+ {
+ t = new AST.TypeSArray(t, e);
+ }
+ inBrackets--;
+ check(TOK.rightBracket);
+ }
+ continue;
+
+ case TOK.delegate_:
+ case TOK.function_:
+ {
+ // Handle delegate declaration:
+ // t delegate(parameter list) nothrow pure
+ // t function(parameter list) nothrow pure
+ TOK save = token.value;
+ nextToken();
+
+ auto parameterList = parseParameterList(null);
+
+ StorageClass stc = parsePostfix(STC.undefined_, null);
+ auto tf = new AST.TypeFunction(parameterList, t, linkage, stc);
+ if (stc & (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild | STC.return_))
+ {
+ if (save == TOK.function_)
+ error("`const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions");
+ else
+ tf = cast(AST.TypeFunction)tf.addSTC(stc);
+ }
+ t = save == TOK.delegate_ ? new AST.TypeDelegate(tf) : new AST.TypePointer(tf); // pointer to function
+ continue;
+ }
+ default:
+ return t;
+ }
+ assert(0);
+ }
+ assert(0);
+ }
+
+ /**********************
+ * Parse Declarator
+ * Params:
+ * t = base type to start with
+ * palt = OR in 1 for C-style function pointer declaration syntax,
+ * 2 for C-style array declaration syntax, otherwise don't modify
+ * pident = set to Identifier if there is one, null if not
+ * tpl = if !null, then set to TemplateParameterList
+ * storageClass = any storage classes seen so far
+ * pdisable = set to true if @disable seen
+ * pudas = any user defined attributes seen so far. Merged with any more found
+ * Returns:
+ * type declared
+ * Reference: https://dlang.org/spec/declaration.html#Declarator
+ */
+ private AST.Type parseDeclarator(AST.Type t, ref int palt, Identifier* pident,
+ AST.TemplateParameters** tpl = null, StorageClass storageClass = 0,
+ bool* pdisable = null, AST.Expressions** pudas = null)
+ {
+ //printf("parseDeclarator(tpl = %p)\n", tpl);
+ t = parseTypeSuffixes(t);
+ AST.Type ts;
+ switch (token.value)
+ {
+ case TOK.identifier:
+ if (pident)
+ *pident = token.ident;
+ else
+ error("unexpected identifier `%s` in declarator", token.ident.toChars());
+ ts = t;
+ nextToken();
+ break;
+
+ case TOK.leftParenthesis:
+ {
+ // like: T (*fp)();
+ // like: T ((*fp))();
+ if (peekNext() == TOK.mul || peekNext() == TOK.leftParenthesis)
+ {
+ /* Parse things with parentheses around the identifier, like:
+ * int (*ident[3])[]
+ * although the D style would be:
+ * int[]*[3] ident
+ */
+ palt |= 1;
+ nextToken();
+ ts = parseDeclarator(t, palt, pident);
+ check(TOK.rightParenthesis);
+ break;
+ }
+ ts = t;
+
+ Token* peekt = &token;
+ /* Completely disallow C-style things like:
+ * T (a);
+ * Improve error messages for the common bug of a missing return type
+ * by looking to see if (a) looks like a parameter list.
+ */
+ if (isParameters(&peekt))
+ {
+ error("function declaration without return type. (Note that constructors are always named `this`)");
+ }
+ else
+ error("unexpected `(` in declarator");
+ break;
+ }
+ default:
+ ts = t;
+ break;
+ }
+
+ // parse DeclaratorSuffixes
+ while (1)
+ {
+ switch (token.value)
+ {
+ static if (CARRAYDECL)
+ {
+ /* Support C style array syntax:
+ * int ident[]
+ * as opposed to D-style:
+ * int[] ident
+ */
+ case TOK.leftBracket:
+ {
+ // This is the old C-style post [] syntax.
+ AST.TypeNext ta;
+ nextToken();
+ if (token.value == TOK.rightBracket)
+ {
+ // It's a dynamic array
+ ta = new AST.TypeDArray(t); // []
+ nextToken();
+ palt |= 2;
+ }
+ else if (isDeclaration(&token, NeedDeclaratorId.no, TOK.rightBracket, null))
+ {
+ // It's an associative array
+ //printf("it's an associative array\n");
+ AST.Type index = parseType(); // [ type ]
+ check(TOK.rightBracket);
+ ta = new AST.TypeAArray(t, index);
+ palt |= 2;
+ }
+ else
+ {
+ //printf("It's a static array\n");
+ AST.Expression e = parseAssignExp(); // [ expression ]
+ ta = new AST.TypeSArray(t, e);
+ check(TOK.rightBracket);
+ palt |= 2;
+ }
+
+ /* Insert ta into
+ * ts -> ... -> t
+ * so that
+ * ts -> ... -> ta -> t
+ */
+ AST.Type* pt;
+ for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next)
+ {
+ }
+ *pt = ta;
+ continue;
+ }
+ }
+ case TOK.leftParenthesis:
+ {
+ if (tpl)
+ {
+ Token* tk = peekPastParen(&token);
+ if (tk.value == TOK.leftParenthesis)
+ {
+ /* Look ahead to see if this is (...)(...),
+ * i.e. a function template declaration
+ */
+ //printf("function template declaration\n");
+
+ // Gather template parameter list
+ *tpl = parseTemplateParameterList();
+ }
+ else if (tk.value == TOK.assign)
+ {
+ /* or (...) =,
+ * i.e. a variable template declaration
+ */
+ //printf("variable template declaration\n");
+ *tpl = parseTemplateParameterList();
+ break;
+ }
+ }
+
+ auto parameterList = parseParameterList(null);
+
+ /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
+ */
+ // merge prefix storage classes
+ StorageClass stc = parsePostfix(storageClass, pudas);
+
+ AST.Type tf = new AST.TypeFunction(parameterList, t, linkage, stc);
+ tf = tf.addSTC(stc);
+ if (pdisable)
+ *pdisable = stc & STC.disable ? true : false;
+
+ /* Insert tf into
+ * ts -> ... -> t
+ * so that
+ * ts -> ... -> tf -> t
+ */
+ AST.Type* pt;
+ for (pt = &ts; *pt != t; pt = &(cast(AST.TypeNext)*pt).next)
+ {
+ }
+ *pt = tf;
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ return ts;
+ }
+
+ private void parseStorageClasses(ref StorageClass storage_class, ref LINK link,
+ ref bool setAlignment, ref AST.Expression ealign, ref AST.Expressions* udas,
+ out Loc linkloc)
+ {
+ StorageClass stc;
+ bool sawLinkage = false; // seen a linkage declaration
+
+ linkloc = Loc.initial;
+
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.const_:
+ if (peekNext() == TOK.leftParenthesis)
+ break; // const as type constructor
+ stc = STC.const_; // const as storage class
+ goto L1;
+
+ case TOK.immutable_:
+ if (peekNext() == TOK.leftParenthesis)
+ break;
+ stc = STC.immutable_;
+ goto L1;
+
+ case TOK.shared_:
+ if (peekNext() == TOK.leftParenthesis)
+ break;
+ stc = STC.shared_;
+ goto L1;
+
+ case TOK.inout_:
+ if (peekNext() == TOK.leftParenthesis)
+ break;
+ stc = STC.wild;
+ goto L1;
+
+ case TOK.static_:
+ stc = STC.static_;
+ goto L1;
+
+ case TOK.final_:
+ stc = STC.final_;
+ goto L1;
+
+ case TOK.auto_:
+ stc = STC.auto_;
+ goto L1;
+
+ case TOK.scope_:
+ stc = STC.scope_;
+ goto L1;
+
+ case TOK.override_:
+ stc = STC.override_;
+ goto L1;
+
+ case TOK.abstract_:
+ stc = STC.abstract_;
+ goto L1;
+
+ case TOK.synchronized_:
+ stc = STC.synchronized_;
+ goto L1;
+
+ case TOK.deprecated_:
+ stc = STC.deprecated_;
+ goto L1;
+
+ case TOK.nothrow_:
+ stc = STC.nothrow_;
+ goto L1;
+
+ case TOK.pure_:
+ stc = STC.pure_;
+ goto L1;
+
+ case TOK.ref_:
+ stc = STC.ref_;
+ goto L1;
+
+ case TOK.gshared:
+ stc = STC.gshared;
+ goto L1;
+
+ case TOK.enum_:
+ {
+ const tv = peekNext();
+ if (tv == TOK.leftCurly || tv == TOK.colon)
+ break;
+ if (tv == TOK.identifier)
+ {
+ const nextv = peekNext2();
+ if (nextv == TOK.leftCurly || nextv == TOK.colon || nextv == TOK.semicolon)
+ break;
+ }
+ stc = STC.manifest;
+ goto L1;
+ }
+
+ case TOK.at:
+ {
+ stc = parseAttribute(udas);
+ if (stc)
+ goto L1;
+ continue;
+ }
+ L1:
+ storage_class = appendStorageClass(storage_class, stc);
+ nextToken();
+ continue;
+
+ case TOK.extern_:
+ {
+ if (peekNext() != TOK.leftParenthesis)
+ {
+ stc = STC.extern_;
+ goto L1;
+ }
+
+ if (sawLinkage)
+ error("redundant linkage declaration");
+ sawLinkage = true;
+ linkloc = token.loc;
+ auto res = parseLinkage();
+ link = res.link;
+ if (res.idents || res.identExps)
+ {
+ error("C++ name spaces not allowed here");
+ }
+ if (res.cppmangle != CPPMANGLE.def)
+ {
+ error("C++ mangle declaration not allowed here");
+ }
+ continue;
+ }
+ case TOK.align_:
+ {
+ nextToken();
+ setAlignment = true;
+ if (token.value == TOK.leftParenthesis)
+ {
+ nextToken();
+ ealign = parseExpression();
+ check(TOK.rightParenthesis);
+ }
+ continue;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ }
+
+ /**********************************
+ * Parse Declarations.
+ * These can be:
+ * 1. declarations at global/class level
+ * 2. declarations at statement level
+ * Return array of Declaration *'s.
+ */
+ private AST.Dsymbols* parseDeclarations(bool autodecl, PrefixAttributes!AST* pAttrs, const(char)* comment)
+ {
+ StorageClass storage_class = STC.undefined_;
+ TOK tok = TOK.reserved;
+ LINK link = linkage;
+ Loc linkloc = this.linkLoc;
+ bool setAlignment = false;
+ AST.Expression ealign;
+ AST.Expressions* udas = null;
+
+ //printf("parseDeclarations() %s\n", token.toChars());
+ if (!comment)
+ comment = token.blockComment.ptr;
+
+ /* Look for AliasAssignment:
+ * identifier = type;
+ */
+ if (token.value == TOK.identifier && peekNext() == TOK.assign)
+ {
+ const loc = token.loc;
+ auto ident = token.ident;
+ nextToken();
+ nextToken(); // advance past =
+ auto t = parseType();
+ AST.Dsymbol s = new AST.AliasAssign(loc, ident, t, null);
+ check(TOK.semicolon);
+ addComment(s, comment);
+ auto a = new AST.Dsymbols();
+ a.push(s);
+ return a;
+ }
+
+ if (token.value == TOK.alias_)
+ {
+ const loc = token.loc;
+ tok = token.value;
+ nextToken();
+
+ /* Look for:
+ * alias identifier this;
+ */
+ if (token.value == TOK.identifier && peekNext() == TOK.this_)
+ {
+ auto s = new AST.AliasThis(loc, token.ident);
+ nextToken();
+ check(TOK.this_);
+ check(TOK.semicolon);
+ auto a = new AST.Dsymbols();
+ a.push(s);
+ addComment(s, comment);
+ return a;
+ }
+ version (none)
+ {
+ /* Look for:
+ * alias this = identifier;
+ */
+ if (token.value == TOK.this_ && peekNext() == TOK.assign && peekNext2() == TOK.identifier)
+ {
+ check(TOK.this_);
+ check(TOK.assign);
+ auto s = new AliasThis(loc, token.ident);
+ nextToken();
+ check(TOK.semicolon);
+ auto a = new Dsymbols();
+ a.push(s);
+ addComment(s, comment);
+ return a;
+ }
+ }
+ /* Look for:
+ * alias identifier = type;
+ * alias identifier(...) = type;
+ */
+ if (token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign))
+ {
+ auto a = new AST.Dsymbols();
+ while (1)
+ {
+ auto ident = token.ident;
+ nextToken();
+ AST.TemplateParameters* tpl = null;
+ if (token.value == TOK.leftParenthesis)
+ tpl = parseTemplateParameterList();
+ check(TOK.assign);
+
+ bool hasParsedAttributes;
+ void parseAttributes()
+ {
+ if (hasParsedAttributes) // only parse once
+ return;
+ hasParsedAttributes = true;
+ udas = null;
+ storage_class = STC.undefined_;
+ link = linkage;
+ linkloc = this.linkLoc;
+ setAlignment = false;
+ ealign = null;
+ parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc);
+ }
+
+ if (token.value == TOK.at)
+ parseAttributes;
+
+ AST.Declaration v;
+ AST.Dsymbol s;
+
+ // try to parse function type:
+ // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
+ bool attributesAppended;
+ const StorageClass funcStc = parseTypeCtor();
+ Token* tlu = &token;
+ Token* tk;
+ if (token.value != TOK.function_ &&
+ token.value != TOK.delegate_ &&
+ isBasicType(&tlu) && tlu &&
+ tlu.value == TOK.leftParenthesis)
+ {
+ AST.Type tret = parseBasicType();
+ auto parameterList = parseParameterList(null);
+
+ parseAttributes();
+ if (udas)
+ error("user-defined attributes not allowed for `alias` declarations");
+
+ attributesAppended = true;
+ storage_class = appendStorageClass(storage_class, funcStc);
+ AST.Type tf = new AST.TypeFunction(parameterList, tret, link, storage_class);
+ v = new AST.AliasDeclaration(loc, ident, tf);
+ }
+ else if (token.value == TOK.function_ ||
+ token.value == TOK.delegate_ ||
+ token.value == TOK.leftParenthesis &&
+ skipAttributes(peekPastParen(&token), &tk) &&
+ (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) ||
+ token.value == TOK.leftCurly ||
+ token.value == TOK.identifier && peekNext() == TOK.goesTo ||
+ token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis &&
+ skipAttributes(peekPastParen(peek(&token)), &tk) &&
+ (tk.value == TOK.goesTo || tk.value == TOK.leftCurly)
+ )
+ {
+ // function (parameters) { statements... }
+ // delegate (parameters) { statements... }
+ // (parameters) { statements... }
+ // (parameters) => expression
+ // { statements... }
+ // identifier => expression
+ // ref (parameters) { statements... }
+ // ref (parameters) => expression
+
+ s = parseFunctionLiteral();
+
+ if (udas !is null)
+ {
+ if (storage_class != 0)
+ error("Cannot put a storage-class in an alias declaration.");
+ // parseAttributes shouldn't have set these variables
+ assert(link == linkage && !setAlignment && ealign is null);
+ auto tpl_ = cast(AST.TemplateDeclaration) s;
+ assert(tpl_ !is null && tpl_.members.dim == 1);
+ auto fd = cast(AST.FuncLiteralDeclaration) (*tpl_.members)[0];
+ auto tf = cast(AST.TypeFunction) fd.type;
+ assert(tf.parameterList.parameters.dim > 0);
+ auto as = new AST.Dsymbols();
+ (*tf.parameterList.parameters)[0].userAttribDecl = new AST.UserAttributeDeclaration(udas, as);
+ }
+
+ v = new AST.AliasDeclaration(loc, ident, s);
+ }
+ else
+ {
+ parseAttributes();
+ // type
+ if (udas)
+ error("user-defined attributes not allowed for `%s` declarations", Token.toChars(tok));
+
+ auto t = parseType();
+
+ // Disallow meaningless storage classes on type aliases
+ if (storage_class)
+ {
+ // Don't raise errors for STC that are part of a function/delegate type, e.g.
+ // `alias F = ref pure nothrow @nogc @safe int function();`
+ auto tp = t.isTypePointer;
+ const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate;
+ const remStc = isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class;
+
+ if (remStc)
+ {
+ OutBuffer buf;
+ AST.stcToBuffer(&buf, remStc);
+ // @@@DEPRECATED_2.093@@@
+ // Deprecated in 2020-07, can be made an error in 2.103
+ deprecation("storage class `%s` has no effect in type aliases", buf.peekChars());
+ }
+ }
+
+ v = new AST.AliasDeclaration(loc, ident, t);
+ }
+ if (!attributesAppended)
+ storage_class = appendStorageClass(storage_class, funcStc);
+ v.storage_class = storage_class;
+
+ s = v;
+ if (tpl)
+ {
+ auto a2 = new AST.Dsymbols();
+ a2.push(s);
+ auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2);
+ s = tempdecl;
+ }
+ if (link != linkage)
+ {
+ auto a2 = new AST.Dsymbols();
+ a2.push(s);
+ s = new AST.LinkDeclaration(linkloc, link, a2);
+ }
+ a.push(s);
+
+ switch (token.value)
+ {
+ case TOK.semicolon:
+ nextToken();
+ addComment(s, comment);
+ break;
+
+ case TOK.comma:
+ nextToken();
+ addComment(s, comment);
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following comma, not `%s`", token.toChars());
+ break;
+ }
+ if (peekNext() != TOK.assign && peekNext() != TOK.leftParenthesis)
+ {
+ error("`=` expected following identifier");
+ nextToken();
+ break;
+ }
+ continue;
+
+ default:
+ error("semicolon expected to close `%s` declaration", Token.toChars(tok));
+ break;
+ }
+ break;
+ }
+ return a;
+ }
+
+ // alias StorageClasses type ident;
+ }
+
+ AST.Type ts;
+
+ if (!autodecl)
+ {
+ parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc);
+
+ if (token.value == TOK.enum_)
+ {
+ AST.Dsymbol d = parseEnum();
+ auto a = new AST.Dsymbols();
+ a.push(d);
+
+ if (udas)
+ {
+ d = new AST.UserAttributeDeclaration(udas, a);
+ a = new AST.Dsymbols();
+ a.push(d);
+ }
+
+ addComment(d, comment);
+ return a;
+ }
+ if (token.value == TOK.struct_ ||
+ token.value == TOK.union_ ||
+ token.value == TOK.class_ ||
+ token.value == TOK.interface_)
+ {
+ AST.Dsymbol s = parseAggregate();
+ auto a = new AST.Dsymbols();
+ a.push(s);
+
+ if (storage_class)
+ {
+ s = new AST.StorageClassDeclaration(storage_class, a);
+ a = new AST.Dsymbols();
+ a.push(s);
+ }
+ if (setAlignment)
+ {
+ s = new AST.AlignDeclaration(s.loc, ealign, a);
+ a = new AST.Dsymbols();
+ a.push(s);
+ }
+ if (link != linkage)
+ {
+ s = new AST.LinkDeclaration(linkloc, link, a);
+ a = new AST.Dsymbols();
+ a.push(s);
+ }
+ if (udas)
+ {
+ s = new AST.UserAttributeDeclaration(udas, a);
+ a = new AST.Dsymbols();
+ a.push(s);
+ }
+
+ addComment(s, comment);
+ return a;
+ }
+
+ /* Look for auto initializers:
+ * storage_class identifier = initializer;
+ * storage_class identifier(...) = initializer;
+ */
+ if ((storage_class || udas) && token.value == TOK.identifier && hasOptionalParensThen(peek(&token), TOK.assign))
+ {
+ AST.Dsymbols* a = parseAutoDeclarations(storage_class, comment);
+ if (udas)
+ {
+ AST.Dsymbol s = new AST.UserAttributeDeclaration(udas, a);
+ a = new AST.Dsymbols();
+ a.push(s);
+ }
+ return a;
+ }
+
+ /* Look for return type inference for template functions.
+ */
+ {
+ Token* tk;
+ if ((storage_class || udas) && token.value == TOK.identifier && skipParens(peek(&token), &tk) &&
+ skipAttributes(tk, &tk) &&
+ (tk.value == TOK.leftParenthesis || tk.value == TOK.leftCurly || tk.value == TOK.in_ || tk.value == TOK.out_ || tk.value == TOK.goesTo ||
+ tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body))
+ {
+ // @@@DEPRECATED@@@
+ // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
+ // Deprecated in 2.097 - Can be removed from 2.117
+ // The deprecation period is longer than usual as `body`
+ // was quite widely used.
+ if (tk.value == TOK.identifier && tk.ident == Id._body)
+ deprecation("Usage of the `body` keyword is deprecated. Use `do` instead.");
+
+ ts = null;
+ }
+ else
+ {
+ ts = parseBasicType();
+ ts = parseTypeSuffixes(ts);
+ }
+ }
+ }
+
+ if (pAttrs)
+ {
+ storage_class |= pAttrs.storageClass;
+ //pAttrs.storageClass = STC.undefined_;
+ }
+
+ AST.Type tfirst = null;
+ auto a = new AST.Dsymbols();
+
+ while (1)
+ {
+ AST.TemplateParameters* tpl = null;
+ bool disable;
+ int alt = 0;
+
+ const loc = token.loc;
+ Identifier ident;
+
+ auto t = parseDeclarator(ts, alt, &ident, &tpl, storage_class, &disable, &udas);
+ assert(t);
+ if (!tfirst)
+ tfirst = t;
+ else if (t != tfirst)
+ error("multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars());
+
+ bool isThis = (t.ty == Tident && (cast(AST.TypeIdentifier)t).ident == Id.This && token.value == TOK.assign);
+ if (ident)
+ checkCstyleTypeSyntax(loc, t, alt, ident);
+ else if (!isThis && (t != AST.Type.terror))
+ error("no identifier for declarator `%s`", t.toChars());
+
+ if (tok == TOK.alias_)
+ {
+ AST.Declaration v;
+ AST.Initializer _init = null;
+
+ /* Aliases can no longer have multiple declarators, storage classes,
+ * linkages, or auto declarations.
+ * These never made any sense, anyway.
+ * The code below needs to be fixed to reject them.
+ * The grammar has already been fixed to preclude them.
+ */
+
+ if (udas)
+ error("user-defined attributes not allowed for `%s` declarations", Token.toChars(tok));
+
+ if (token.value == TOK.assign)
+ {
+ nextToken();
+ _init = parseInitializer();
+ }
+ if (_init)
+ {
+ if (isThis)
+ error("cannot use syntax `alias this = %s`, use `alias %s this` instead", _init.toChars(), _init.toChars());
+ else
+ error("alias cannot have initializer");
+ }
+ v = new AST.AliasDeclaration(loc, ident, t);
+
+ v.storage_class = storage_class;
+ if (pAttrs)
+ {
+ /* AliasDeclaration distinguish @safe, @system, @trusted attributes
+ * on prefix and postfix.
+ * @safe alias void function() FP1;
+ * alias @safe void function() FP2; // FP2 is not @safe
+ * alias void function() @safe FP3;
+ */
+ pAttrs.storageClass &= STC.safeGroup;
+ }
+ AST.Dsymbol s = v;
+
+ if (link != linkage)
+ {
+ auto ax = new AST.Dsymbols();
+ ax.push(v);
+ s = new AST.LinkDeclaration(linkloc, link, ax);
+ }
+ a.push(s);
+ switch (token.value)
+ {
+ case TOK.semicolon:
+ nextToken();
+ addComment(s, comment);
+ break;
+
+ case TOK.comma:
+ nextToken();
+ addComment(s, comment);
+ continue;
+
+ default:
+ error("semicolon expected to close `%s` declaration", Token.toChars(tok));
+ break;
+ }
+ }
+ else if (t.ty == Tfunction)
+ {
+ AST.Expression constraint = null;
+ //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t.toChars(), storage_class);
+ auto f = new AST.FuncDeclaration(loc, Loc.initial, ident, storage_class | (disable ? STC.disable : 0), t);
+ if (pAttrs)
+ pAttrs.storageClass = STC.undefined_;
+ if (tpl)
+ constraint = parseConstraint();
+ AST.Dsymbol s = parseContracts(f);
+ auto tplIdent = s.ident;
+
+ if (link != linkage)
+ {
+ auto ax = new AST.Dsymbols();
+ ax.push(s);
+ s = new AST.LinkDeclaration(linkloc, link, ax);
+ }
+ if (udas)
+ {
+ auto ax = new AST.Dsymbols();
+ ax.push(s);
+ s = new AST.UserAttributeDeclaration(udas, ax);
+ }
+
+ /* A template parameter list means it's a function template
+ */
+ if (tpl)
+ {
+ // Wrap a template around the function declaration
+ auto decldefs = new AST.Dsymbols();
+ decldefs.push(s);
+ auto tempdecl = new AST.TemplateDeclaration(loc, tplIdent, tpl, constraint, decldefs);
+ s = tempdecl;
+
+ StorageClass stc2 = STC.undefined_;
+ if (storage_class & STC.static_)
+ {
+ assert(f.storage_class & STC.static_);
+ f.storage_class &= ~STC.static_;
+ stc2 |= STC.static_;
+ }
+ if (storage_class & STC.deprecated_)
+ {
+ assert(f.storage_class & STC.deprecated_);
+ f.storage_class &= ~STC.deprecated_;
+ stc2 |= STC.deprecated_;
+ }
+ if (stc2 != STC.undefined_)
+ {
+ auto ax = new AST.Dsymbols();
+ ax.push(s);
+ s = new AST.StorageClassDeclaration(stc2, ax);
+ }
+ }
+ a.push(s);
+ addComment(s, comment);
+ }
+ else if (ident)
+ {
+ AST.Initializer _init = null;
+ if (token.value == TOK.assign)
+ {
+ nextToken();
+ _init = parseInitializer();
+ }
+
+ auto v = new AST.VarDeclaration(loc, t, ident, _init);
+ v.storage_class = storage_class;
+ if (pAttrs)
+ pAttrs.storageClass = STC.undefined_;
+
+ AST.Dsymbol s = v;
+
+ if (tpl && _init)
+ {
+ auto a2 = new AST.Dsymbols();
+ a2.push(s);
+ auto tempdecl = new AST.TemplateDeclaration(loc, ident, tpl, null, a2, 0);
+ s = tempdecl;
+ }
+ if (setAlignment)
+ {
+ auto ax = new AST.Dsymbols();
+ ax.push(s);
+ s = new AST.AlignDeclaration(v.loc, ealign, ax);
+ }
+ if (link != linkage)
+ {
+ auto ax = new AST.Dsymbols();
+ ax.push(s);
+ s = new AST.LinkDeclaration(linkloc, link, ax);
+ }
+ if (udas)
+ {
+ auto ax = new AST.Dsymbols();
+ ax.push(s);
+ s = new AST.UserAttributeDeclaration(udas, ax);
+ }
+ a.push(s);
+ switch (token.value)
+ {
+ case TOK.semicolon:
+ nextToken();
+ addComment(s, comment);
+ break;
+
+ case TOK.comma:
+ nextToken();
+ addComment(s, comment);
+ continue;
+
+ default:
+ error("semicolon expected, not `%s`", token.toChars());
+ break;
+ }
+ }
+ break;
+ }
+ return a;
+ }
+
+ private AST.Dsymbol parseFunctionLiteral()
+ {
+ const loc = token.loc;
+ AST.TemplateParameters* tpl = null;
+ AST.ParameterList parameterList;
+ AST.Type tret = null;
+ StorageClass stc = 0;
+ TOK save = TOK.reserved;
+
+ switch (token.value)
+ {
+ case TOK.function_:
+ case TOK.delegate_:
+ save = token.value;
+ nextToken();
+ if (token.value == TOK.ref_)
+ {
+ // function ref (parameters) { statements... }
+ // delegate ref (parameters) { statements... }
+ stc = STC.ref_;
+ nextToken();
+ }
+ if (token.value != TOK.leftParenthesis && token.value != TOK.leftCurly)
+ {
+ // function type (parameters) { statements... }
+ // delegate type (parameters) { statements... }
+ tret = parseBasicType();
+ tret = parseTypeSuffixes(tret); // function return type
+ }
+
+ if (token.value == TOK.leftParenthesis)
+ {
+ // function (parameters) { statements... }
+ // delegate (parameters) { statements... }
+ }
+ else
+ {
+ // function { statements... }
+ // delegate { statements... }
+ break;
+ }
+ goto case TOK.leftParenthesis;
+
+ case TOK.ref_:
+ {
+ // ref (parameters) => expression
+ // ref (parameters) { statements... }
+ stc = STC.ref_;
+ nextToken();
+ goto case TOK.leftParenthesis;
+ }
+ case TOK.leftParenthesis:
+ {
+ // (parameters) => expression
+ // (parameters) { statements... }
+ parameterList = parseParameterList(&tpl);
+ stc = parsePostfix(stc, null);
+ if (StorageClass modStc = stc & STC.TYPECTOR)
+ {
+ if (save == TOK.function_)
+ {
+ OutBuffer buf;
+ AST.stcToBuffer(&buf, modStc);
+ error("function literal cannot be `%s`", buf.peekChars());
+ }
+ else
+ save = TOK.delegate_;
+ }
+ break;
+ }
+ case TOK.leftCurly:
+ // { statements... }
+ break;
+
+ case TOK.identifier:
+ {
+ // identifier => expression
+ parameterList.parameters = new AST.Parameters();
+ Identifier id = Identifier.generateId("__T");
+ AST.Type t = new AST.TypeIdentifier(loc, id);
+ parameterList.parameters.push(new AST.Parameter(STC.parameter, t, token.ident, null, null));
+
+ tpl = new AST.TemplateParameters();
+ AST.TemplateParameter tp = new AST.TemplateTypeParameter(loc, id, null, null);
+ tpl.push(tp);
+
+ nextToken();
+ break;
+ }
+ default:
+ assert(0);
+ }
+
+ auto tf = new AST.TypeFunction(parameterList, tret, linkage, stc);
+ tf = cast(AST.TypeFunction)tf.addSTC(stc);
+ auto fd = new AST.FuncLiteralDeclaration(loc, Loc.initial, tf, save, null);
+
+ if (token.value == TOK.goesTo)
+ {
+ check(TOK.goesTo);
+ if (token.value == TOK.leftCurly)
+ {
+ deprecation("Using `(args) => { ... }` to create a delegate that returns a delegate is error-prone.");
+ deprecationSupplemental(token.loc, "Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate.");
+ }
+ const returnloc = token.loc;
+ AST.Expression ae = parseAssignExp();
+ fd.fbody = new AST.ReturnStatement(returnloc, ae);
+ fd.endloc = token.loc;
+ }
+ else
+ {
+ parseContracts(fd);
+ }
+
+ if (tpl)
+ {
+ // Wrap a template around function fd
+ auto decldefs = new AST.Dsymbols();
+ decldefs.push(fd);
+ return new AST.TemplateDeclaration(fd.loc, fd.ident, tpl, null, decldefs, false, true);
+ }
+ return fd;
+ }
+
+ /*****************************************
+ * Parse contracts following function declaration.
+ */
+ private AST.FuncDeclaration parseContracts(AST.FuncDeclaration f)
+ {
+ LINK linksave = linkage;
+
+ bool literal = f.isFuncLiteralDeclaration() !is null;
+
+ // The following is irrelevant, as it is overridden by sc.linkage in
+ // TypeFunction::semantic
+ linkage = LINK.d; // nested functions have D linkage
+ bool requireDo = false;
+ L1:
+ switch (token.value)
+ {
+ case TOK.goesTo:
+ if (requireDo)
+ error("missing `do { ... }` after `in` or `out`");
+ if (!global.params.shortenedMethods)
+ error("=> shortened method not enabled, compile with compiler switch `-preview=shortenedMethods`");
+ const returnloc = token.loc;
+ nextToken();
+ f.fbody = new AST.ReturnStatement(returnloc, parseExpression());
+ f.endloc = token.loc;
+ check(TOK.semicolon);
+ break;
+
+ case TOK.leftCurly:
+ if (requireDo)
+ error("missing `do { ... }` after `in` or `out`");
+ f.fbody = parseStatement(ParseStatementFlags.semi);
+ f.endloc = endloc;
+ break;
+
+ case TOK.identifier:
+ if (token.ident == Id._body)
+ {
+ // @@@DEPRECATED@@@
+ // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
+ // Deprecated in 2.097 - Can be removed from 2.117
+ // The deprecation period is longer than usual as `body`
+ // was quite widely used.
+ deprecation("Usage of the `body` keyword is deprecated. Use `do` instead.");
+ goto case TOK.do_;
+ }
+ goto default;
+
+ case TOK.do_:
+ nextToken();
+ f.fbody = parseStatement(ParseStatementFlags.curly);
+ f.endloc = endloc;
+ break;
+
+ version (none)
+ {
+ // Do we want this for function declarations, so we can do:
+ // int x, y, foo(), z;
+ case TOK.comma:
+ nextToken();
+ continue;
+ }
+
+ case TOK.in_:
+ // in { statements... }
+ // in (expression)
+ auto loc = token.loc;
+ nextToken();
+ if (!f.frequires)
+ {
+ f.frequires = new AST.Statements;
+ }
+ if (token.value == TOK.leftParenthesis)
+ {
+ nextToken();
+ AST.Expression e = parseAssignExp(), msg = null;
+ if (token.value == TOK.comma)
+ {
+ nextToken();
+ if (token.value != TOK.rightParenthesis)
+ {
+ msg = parseAssignExp();
+ if (token.value == TOK.comma)
+ nextToken();
+ }
+ }
+ check(TOK.rightParenthesis);
+ e = new AST.AssertExp(loc, e, msg);
+ f.frequires.push(new AST.ExpStatement(loc, e));
+ requireDo = false;
+ }
+ else
+ {
+ f.frequires.push(parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_));
+ requireDo = true;
+ }
+ goto L1;
+
+ case TOK.out_:
+ // out { statements... }
+ // out (; expression)
+ // out (identifier) { statements... }
+ // out (identifier; expression)
+ auto loc = token.loc;
+ nextToken();
+ if (!f.fensures)
+ {
+ f.fensures = new AST.Ensures;
+ }
+ Identifier id = null;
+ if (token.value != TOK.leftCurly)
+ {
+ check(TOK.leftParenthesis);
+ if (token.value != TOK.identifier && token.value != TOK.semicolon)
+ error("`(identifier) { ... }` or `(identifier; expression)` following `out` expected, not `%s`", token.toChars());
+ if (token.value != TOK.semicolon)
+ {
+ id = token.ident;
+ nextToken();
+ }
+ if (token.value == TOK.semicolon)
+ {
+ nextToken();
+ AST.Expression e = parseAssignExp(), msg = null;
+ if (token.value == TOK.comma)
+ {
+ nextToken();
+ if (token.value != TOK.rightParenthesis)
+ {
+ msg = parseAssignExp();
+ if (token.value == TOK.comma)
+ nextToken();
+ }
+ }
+ check(TOK.rightParenthesis);
+ e = new AST.AssertExp(loc, e, msg);
+ f.fensures.push(AST.Ensure(id, new AST.ExpStatement(loc, e)));
+ requireDo = false;
+ goto L1;
+ }
+ check(TOK.rightParenthesis);
+ }
+ f.fensures.push(AST.Ensure(id, parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_)));
+ requireDo = true;
+ goto L1;
+
+ case TOK.semicolon:
+ if (!literal)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=15799
+ // Semicolon becomes a part of function declaration
+ // only when 'do' is not required
+ if (!requireDo)
+ nextToken();
+ break;
+ }
+ goto default;
+
+ default:
+ if (literal)
+ {
+ const(char)* sbody = requireDo ? "do " : "";
+ error("missing `%s{ ... }` for function literal", sbody);
+ }
+ else if (!requireDo) // allow contracts even with no body
+ {
+ TOK t = token.value;
+ if (t == TOK.const_ || t == TOK.immutable_ || t == TOK.inout_ || t == TOK.return_ ||
+ t == TOK.shared_ || t == TOK.nothrow_ || t == TOK.pure_)
+ error("'%s' cannot be placed after a template constraint", token.toChars);
+ else if (t == TOK.at)
+ error("attributes cannot be placed after a template constraint");
+ else if (t == TOK.if_)
+ error("cannot use function constraints for non-template functions. Use `static if` instead");
+ else
+ error("semicolon expected following function declaration");
+ }
+ break;
+ }
+ if (literal && !f.fbody)
+ {
+ // Set empty function body for error recovery
+ f.fbody = new AST.CompoundStatement(Loc.initial, cast(AST.Statement)null);
+ }
+
+ linkage = linksave;
+
+ return f;
+ }
+
+ /*****************************************
+ */
+ private void checkDanglingElse(Loc elseloc)
+ {
+ if (token.value != TOK.else_ && token.value != TOK.catch_ && token.value != TOK.finally_ && lookingForElse.linnum != 0)
+ {
+ warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
+ }
+ }
+
+ /* *************************
+ * Issue errors if C-style syntax
+ * Params:
+ * alt = !=0 for C-style syntax
+ */
+ private void checkCstyleTypeSyntax(Loc loc, AST.Type t, int alt, Identifier ident)
+ {
+ if (!alt)
+ return;
+
+ const(char)* sp = !ident ? "" : " ";
+ const(char)* s = !ident ? "" : ident.toChars();
+ error(loc, "instead of C-style syntax, use D-style `%s%s%s`", t.toChars(), sp, s);
+ }
+
+ /*****************************************
+ * Parses `foreach` statements, `static foreach` statements and
+ * `static foreach` declarations.
+ * Params:
+ * Foreach = one of Statement, StaticForeachStatement, StaticForeachDeclaration
+ * loc = location of foreach
+ * pLastDecl = non-null for StaticForeachDeclaration
+ * Returns:
+ * the Foreach generated
+ */
+ private Foreach parseForeach(alias Foreach)(Loc loc, AST.Dsymbol* pLastDecl)
+ {
+ static if (is(Foreach == AST.StaticForeachStatement) || is(Foreach == AST.StaticForeachDeclaration))
+ {
+ nextToken();
+ }
+
+ TOK op = token.value;
+
+ nextToken();
+ check(TOK.leftParenthesis);
+
+ auto parameters = new AST.Parameters();
+ while (1)
+ {
+ Identifier ai = null;
+ AST.Type at;
+
+ StorageClass storageClass = 0;
+ StorageClass stc = 0;
+ Lagain:
+ if (stc)
+ {
+ storageClass = appendStorageClass(storageClass, stc);
+ nextToken();
+ }
+ switch (token.value)
+ {
+ case TOK.ref_:
+ stc = STC.ref_;
+ goto Lagain;
+
+ case TOK.scope_:
+ stc = STC.scope_;
+ goto Lagain;
+
+ case TOK.enum_:
+ stc = STC.manifest;
+ goto Lagain;
+
+ case TOK.alias_:
+ storageClass = appendStorageClass(storageClass, STC.alias_);
+ nextToken();
+ break;
+
+ case TOK.const_:
+ if (peekNext() != TOK.leftParenthesis)
+ {
+ stc = STC.const_;
+ goto Lagain;
+ }
+ break;
+
+ case TOK.immutable_:
+ if (peekNext() != TOK.leftParenthesis)
+ {
+ stc = STC.immutable_;
+ goto Lagain;
+ }
+ break;
+
+ case TOK.shared_:
+ if (peekNext() != TOK.leftParenthesis)
+ {
+ stc = STC.shared_;
+ goto Lagain;
+ }
+ break;
+
+ case TOK.inout_:
+ if (peekNext() != TOK.leftParenthesis)
+ {
+ stc = STC.wild;
+ goto Lagain;
+ }
+ break;
+
+ default:
+ break;
+ }
+ if (token.value == TOK.identifier)
+ {
+ const tv = peekNext();
+ if (tv == TOK.comma || tv == TOK.semicolon)
+ {
+ ai = token.ident;
+ at = null; // infer argument type
+ nextToken();
+ goto Larg;
+ }
+ }
+ at = parseType(&ai);
+ if (!ai)
+ error("no identifier for declarator `%s`", at.toChars());
+ Larg:
+ auto p = new AST.Parameter(storageClass, at, ai, null, null);
+ parameters.push(p);
+ if (token.value == TOK.comma)
+ {
+ nextToken();
+ continue;
+ }
+ break;
+ }
+ check(TOK.semicolon);
+
+ AST.Expression aggr = parseExpression();
+ if (token.value == TOK.slice && parameters.dim == 1)
+ {
+ AST.Parameter p = (*parameters)[0];
+ nextToken();
+ AST.Expression upr = parseExpression();
+ check(TOK.rightParenthesis);
+ Loc endloc;
+ static if (is(Foreach == AST.Statement) || is(Foreach == AST.StaticForeachStatement))
+ {
+ AST.Statement _body = parseStatement(0, null, &endloc);
+ }
+ else
+ {
+ AST.Statement _body = null;
+ }
+ auto rangefe = new AST.ForeachRangeStatement(loc, op, p, aggr, upr, _body, endloc);
+ static if (is(Foreach == AST.Statement))
+ {
+ return rangefe;
+ }
+ else static if(is(Foreach == AST.StaticForeachDeclaration))
+ {
+ return new AST.StaticForeachDeclaration(new AST.StaticForeach(loc, null, rangefe), parseBlock(pLastDecl));
+ }
+ else static if (is(Foreach == AST.StaticForeachStatement))
+ {
+ return new AST.StaticForeachStatement(loc, new AST.StaticForeach(loc, null, rangefe));
+ }
+ }
+ else
+ {
+ check(TOK.rightParenthesis);
+ Loc endloc;
+ static if (is(Foreach == AST.Statement) || is(Foreach == AST.StaticForeachStatement))
+ {
+ AST.Statement _body = parseStatement(0, null, &endloc);
+ }
+ else
+ {
+ AST.Statement _body = null;
+ }
+ auto aggrfe = new AST.ForeachStatement(loc, op, parameters, aggr, _body, endloc);
+ static if (is(Foreach == AST.Statement))
+ {
+ return aggrfe;
+ }
+ else static if(is(Foreach == AST.StaticForeachDeclaration))
+ {
+ return new AST.StaticForeachDeclaration(new AST.StaticForeach(loc, aggrfe, null), parseBlock(pLastDecl));
+ }
+ else static if (is(Foreach == AST.StaticForeachStatement))
+ {
+ return new AST.StaticForeachStatement(loc, new AST.StaticForeach(loc, aggrfe, null));
+ }
+ }
+
+ }
+
+ /***
+ * Parse an assignment condition for if or while statements.
+ *
+ * Returns:
+ * The variable that is declared inside the condition
+ */
+ AST.Parameter parseAssignCondition()
+ {
+ AST.Parameter param = null;
+ StorageClass storageClass = 0;
+ StorageClass stc = 0;
+LagainStc:
+ if (stc)
+ {
+ storageClass = appendStorageClass(storageClass, stc);
+ nextToken();
+ }
+ switch (token.value)
+ {
+ case TOK.ref_:
+ stc = STC.ref_;
+ goto LagainStc;
+
+ case TOK.scope_:
+ stc = STC.scope_;
+ goto LagainStc;
+
+ case TOK.auto_:
+ stc = STC.auto_;
+ goto LagainStc;
+
+ case TOK.const_:
+ if (peekNext() != TOK.leftParenthesis)
+ {
+ stc = STC.const_;
+ goto LagainStc;
+ }
+ break;
+
+ case TOK.immutable_:
+ if (peekNext() != TOK.leftParenthesis)
+ {
+ stc = STC.immutable_;
+ goto LagainStc;
+ }
+ break;
+
+ case TOK.shared_:
+ if (peekNext() != TOK.leftParenthesis)
+ {
+ stc = STC.shared_;
+ goto LagainStc;
+ }
+ break;
+
+ case TOK.inout_:
+ if (peekNext() != TOK.leftParenthesis)
+ {
+ stc = STC.wild;
+ goto LagainStc;
+ }
+ break;
+
+ default:
+ break;
+ }
+ auto n = peek(&token);
+ if (storageClass != 0 && token.value == TOK.identifier && n.value == TOK.assign)
+ {
+ Identifier ai = token.ident;
+ AST.Type at = null; // infer parameter type
+ nextToken();
+ check(TOK.assign);
+ param = new AST.Parameter(storageClass, at, ai, null, null);
+ }
+ else if (isDeclaration(&token, NeedDeclaratorId.must, TOK.assign, null))
+ {
+ Identifier ai;
+ AST.Type at = parseType(&ai);
+ check(TOK.assign);
+ param = new AST.Parameter(storageClass, at, ai, null, null);
+ }
+ else if (storageClass != 0)
+ error("found `%s` while expecting `=` or identifier", n.toChars());
+
+ return param;
+ }
+
+ /*****************************************
+ * Input:
+ * flags PSxxxx
+ * Output:
+ * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of last token of statement
+ */
+ AST.Statement parseStatement(int flags, const(char)** endPtr = null, Loc* pEndloc = null)
+ {
+ AST.Statement s;
+ AST.Condition cond;
+ AST.Statement ifbody;
+ AST.Statement elsebody;
+ bool isfinal;
+ const loc = token.loc;
+
+ //printf("parseStatement()\n");
+ if (flags & ParseStatementFlags.curly && token.value != TOK.leftCurly)
+ error("statement expected to be `{ }`, not `%s`", token.toChars());
+
+ switch (token.value)
+ {
+ case TOK.identifier:
+ {
+ /* A leading identifier can be a declaration, label, or expression.
+ * The easiest case to check first is label:
+ */
+ if (peekNext() == TOK.colonColon)
+ {
+ // skip ident::
+ nextToken();
+ nextToken();
+ error("use `.` for member lookup, not `::`");
+ break;
+ }
+
+ if (peekNext() == TOK.colon)
+ {
+ // It's a label
+ Identifier ident = token.ident;
+ nextToken();
+ nextToken();
+ if (token.value == TOK.rightCurly)
+ s = null;
+ else if (token.value == TOK.leftCurly)
+ s = parseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_);
+ else
+ s = parseStatement(ParseStatementFlags.semiOk);
+ s = new AST.LabelStatement(loc, ident, s);
+ break;
+ }
+ goto case TOK.dot;
+ }
+ case TOK.dot:
+ case TOK.typeof_:
+ case TOK.vector:
+ case TOK.traits:
+ /* https://issues.dlang.org/show_bug.cgi?id=15163
+ * If tokens can be handled as
+ * old C-style declaration or D expression, prefer the latter.
+ */
+ if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null))
+ goto Ldeclaration;
+ goto Lexp;
+
+ case TOK.assert_:
+ case TOK.this_:
+ case TOK.super_:
+ case TOK.int32Literal:
+ case TOK.uns32Literal:
+ case TOK.int64Literal:
+ case TOK.uns64Literal:
+ case TOK.int128Literal:
+ case TOK.uns128Literal:
+ case TOK.float32Literal:
+ case TOK.float64Literal:
+ case TOK.float80Literal:
+ case TOK.imaginary32Literal:
+ case TOK.imaginary64Literal:
+ case TOK.imaginary80Literal:
+ case TOK.charLiteral:
+ case TOK.wcharLiteral:
+ case TOK.dcharLiteral:
+ case TOK.null_:
+ case TOK.true_:
+ case TOK.false_:
+ case TOK.string_:
+ case TOK.hexadecimalString:
+ case TOK.leftParenthesis:
+ case TOK.cast_:
+ case TOK.mul:
+ case TOK.min:
+ case TOK.add:
+ case TOK.tilde:
+ case TOK.not:
+ case TOK.plusPlus:
+ case TOK.minusMinus:
+ case TOK.new_:
+ case TOK.delete_:
+ case TOK.delegate_:
+ case TOK.function_:
+ case TOK.typeid_:
+ case TOK.is_:
+ case TOK.leftBracket:
+ case TOK.file:
+ case TOK.fileFullPath:
+ case TOK.line:
+ case TOK.moduleString:
+ case TOK.functionString:
+ case TOK.prettyFunction:
+ Lexp:
+ {
+ AST.Expression exp = parseExpression();
+ /* https://issues.dlang.org/show_bug.cgi?id=15103
+ * Improve declaration / initialization syntax error message
+ * Error: found 'foo' when expecting ';' following statement
+ * becomes Error: found `(` when expecting `;` or `=`, did you mean `Foo foo = 42`?
+ */
+ if (token.value == TOK.identifier && exp.op == TOK.identifier)
+ {
+ error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
+ nextToken();
+ }
+ else
+ check(TOK.semicolon, "statement");
+ s = new AST.ExpStatement(loc, exp);
+ break;
+ }
+ case TOK.static_:
+ {
+ // Look ahead to see if it's static assert() or static if()
+ const tv = peekNext();
+ if (tv == TOK.assert_)
+ {
+ s = new AST.StaticAssertStatement(parseStaticAssert());
+ break;
+ }
+ if (tv == TOK.if_)
+ {
+ cond = parseStaticIfCondition();
+ goto Lcondition;
+ }
+ if (tv == TOK.foreach_ || tv == TOK.foreach_reverse_)
+ {
+ s = parseForeach!(AST.StaticForeachStatement)(loc, null);
+ if (flags & ParseStatementFlags.scope_)
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ break;
+ }
+ if (tv == TOK.import_)
+ {
+ AST.Dsymbols* imports = parseImport();
+ s = new AST.ImportStatement(loc, imports);
+ if (flags & ParseStatementFlags.scope_)
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ break;
+ }
+ goto Ldeclaration;
+ }
+ case TOK.final_:
+ if (peekNext() == TOK.switch_)
+ {
+ nextToken();
+ isfinal = true;
+ goto Lswitch;
+ }
+ goto Ldeclaration;
+
+ case TOK.wchar_:
+ case TOK.dchar_:
+ case TOK.bool_:
+ case TOK.char_:
+ case TOK.int8:
+ case TOK.uns8:
+ case TOK.int16:
+ case TOK.uns16:
+ case TOK.int32:
+ case TOK.uns32:
+ case TOK.int64:
+ case TOK.uns64:
+ case TOK.int128:
+ case TOK.uns128:
+ case TOK.float32:
+ case TOK.float64:
+ case TOK.float80:
+ case TOK.imaginary32:
+ case TOK.imaginary64:
+ case TOK.imaginary80:
+ case TOK.complex32:
+ case TOK.complex64:
+ case TOK.complex80:
+ case TOK.void_:
+ // bug 7773: int.max is always a part of expression
+ if (peekNext() == TOK.dot)
+ goto Lexp;
+ if (peekNext() == TOK.leftParenthesis)
+ goto Lexp;
+ goto case;
+
+ case TOK.alias_:
+ case TOK.const_:
+ case TOK.auto_:
+ case TOK.abstract_:
+ case TOK.extern_:
+ case TOK.align_:
+ case TOK.immutable_:
+ case TOK.shared_:
+ case TOK.inout_:
+ case TOK.deprecated_:
+ case TOK.nothrow_:
+ case TOK.pure_:
+ case TOK.ref_:
+ case TOK.gshared:
+ case TOK.at:
+ case TOK.struct_:
+ case TOK.union_:
+ case TOK.class_:
+ case TOK.interface_:
+ Ldeclaration:
+ {
+ AST.Dsymbols* a = parseDeclarations(false, null, null);
+ if (a.dim > 1)
+ {
+ auto as = new AST.Statements();
+ as.reserve(a.dim);
+ foreach (i; 0 .. a.dim)
+ {
+ AST.Dsymbol d = (*a)[i];
+ s = new AST.ExpStatement(loc, d);
+ as.push(s);
+ }
+ s = new AST.CompoundDeclarationStatement(loc, as);
+ }
+ else if (a.dim == 1)
+ {
+ AST.Dsymbol d = (*a)[0];
+ s = new AST.ExpStatement(loc, d);
+ }
+ else
+ s = new AST.ExpStatement(loc, cast(AST.Expression)null);
+ if (flags & ParseStatementFlags.scope_)
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ break;
+ }
+ case TOK.enum_:
+ {
+ /* Determine if this is a manifest constant declaration,
+ * or a conventional enum.
+ */
+ AST.Dsymbol d;
+ const tv = peekNext();
+ if (tv == TOK.leftCurly || tv == TOK.colon)
+ d = parseEnum();
+ else if (tv != TOK.identifier)
+ goto Ldeclaration;
+ else
+ {
+ const nextv = peekNext2();
+ if (nextv == TOK.leftCurly || nextv == TOK.colon || nextv == TOK.semicolon)
+ d = parseEnum();
+ else
+ goto Ldeclaration;
+ }
+ s = new AST.ExpStatement(loc, d);
+ if (flags & ParseStatementFlags.scope_)
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ break;
+ }
+ case TOK.mixin_:
+ {
+ if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null))
+ goto Ldeclaration;
+ if (peekNext() == TOK.leftParenthesis)
+ {
+ // mixin(string)
+ AST.Expression e = parseAssignExp();
+ check(TOK.semicolon);
+ if (e.op == TOK.mixin_)
+ {
+ AST.MixinExp cpe = cast(AST.MixinExp)e;
+ s = new AST.CompileStatement(loc, cpe.exps);
+ }
+ else
+ {
+ s = new AST.ExpStatement(loc, e);
+ }
+ break;
+ }
+ AST.Dsymbol d = parseMixin();
+ s = new AST.ExpStatement(loc, d);
+ if (flags & ParseStatementFlags.scope_)
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ break;
+ }
+ case TOK.leftCurly:
+ {
+ const lookingForElseSave = lookingForElse;
+ lookingForElse = Loc.initial;
+
+ nextToken();
+ //if (token.value == TOK.semicolon)
+ // error("use `{ }` for an empty statement, not `;`");
+ auto statements = new AST.Statements();
+ while (token.value != TOK.rightCurly && token.value != TOK.endOfFile)
+ {
+ statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
+ }
+ if (endPtr)
+ *endPtr = token.ptr;
+ endloc = token.loc;
+ if (pEndloc)
+ {
+ *pEndloc = token.loc;
+ pEndloc = null; // don't set it again
+ }
+ s = new AST.CompoundStatement(loc, statements);
+ if (flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope))
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ check(TOK.rightCurly, "compound statement");
+ lookingForElse = lookingForElseSave;
+ break;
+ }
+ case TOK.while_:
+ {
+ AST.Parameter param = null;
+ nextToken();
+ check(TOK.leftParenthesis);
+ param = parseAssignCondition();
+ AST.Expression condition = parseExpression();
+ check(TOK.rightParenthesis);
+ Loc endloc;
+ AST.Statement _body = parseStatement(ParseStatementFlags.scope_, null, &endloc);
+ s = new AST.WhileStatement(loc, condition, _body, endloc, param);
+ break;
+ }
+ case TOK.semicolon:
+ if (!(flags & ParseStatementFlags.semiOk))
+ {
+ if (flags & ParseStatementFlags.semi)
+ deprecation("use `{ }` for an empty statement, not `;`");
+ else
+ error("use `{ }` for an empty statement, not `;`");
+ }
+ nextToken();
+ s = new AST.ExpStatement(loc, cast(AST.Expression)null);
+ break;
+
+ case TOK.do_:
+ {
+ AST.Statement _body;
+ AST.Expression condition;
+
+ nextToken();
+ const lookingForElseSave = lookingForElse;
+ lookingForElse = Loc.initial;
+ _body = parseStatement(ParseStatementFlags.scope_);
+ lookingForElse = lookingForElseSave;
+ check(TOK.while_);
+ check(TOK.leftParenthesis);
+ condition = parseExpression();
+ check(TOK.rightParenthesis);
+ if (token.value == TOK.semicolon)
+ nextToken();
+ else
+ error("terminating `;` required after do-while statement");
+ s = new AST.DoStatement(loc, _body, condition, token.loc);
+ break;
+ }
+ case TOK.for_:
+ {
+ AST.Statement _init;
+ AST.Expression condition;
+ AST.Expression increment;
+
+ nextToken();
+ check(TOK.leftParenthesis);
+ if (token.value == TOK.semicolon)
+ {
+ _init = null;
+ nextToken();
+ }
+ else
+ {
+ const lookingForElseSave = lookingForElse;
+ lookingForElse = Loc.initial;
+ _init = parseStatement(0);
+ lookingForElse = lookingForElseSave;
+ }
+ if (token.value == TOK.semicolon)
+ {
+ condition = null;
+ nextToken();
+ }
+ else
+ {
+ condition = parseExpression();
+ check(TOK.semicolon, "`for` condition");
+ }
+ if (token.value == TOK.rightParenthesis)
+ {
+ increment = null;
+ nextToken();
+ }
+ else
+ {
+ increment = parseExpression();
+ check(TOK.rightParenthesis);
+ }
+ Loc endloc;
+ AST.Statement _body = parseStatement(ParseStatementFlags.scope_, null, &endloc);
+ s = new AST.ForStatement(loc, _init, condition, increment, _body, endloc);
+ break;
+ }
+ case TOK.foreach_:
+ case TOK.foreach_reverse_:
+ {
+ s = parseForeach!(AST.Statement)(loc, null);
+ break;
+ }
+ case TOK.if_:
+ {
+ AST.Parameter param = null;
+ AST.Expression condition;
+
+ nextToken();
+ check(TOK.leftParenthesis);
+ param = parseAssignCondition();
+ condition = parseExpression();
+ check(TOK.rightParenthesis);
+ {
+ const lookingForElseSave = lookingForElse;
+ lookingForElse = loc;
+ ifbody = parseStatement(ParseStatementFlags.scope_);
+ lookingForElse = lookingForElseSave;
+ }
+ if (token.value == TOK.else_)
+ {
+ const elseloc = token.loc;
+ nextToken();
+ elsebody = parseStatement(ParseStatementFlags.scope_);
+ checkDanglingElse(elseloc);
+ }
+ else
+ elsebody = null;
+ if (condition && ifbody)
+ s = new AST.IfStatement(loc, param, condition, ifbody, elsebody, token.loc);
+ else
+ s = null; // don't propagate parsing errors
+ break;
+ }
+
+ case TOK.else_:
+ error("found `else` without a corresponding `if`, `version` or `debug` statement");
+ goto Lerror;
+
+ case TOK.scope_:
+ if (peekNext() != TOK.leftParenthesis)
+ goto Ldeclaration; // scope used as storage class
+ nextToken();
+ check(TOK.leftParenthesis);
+ if (token.value != TOK.identifier)
+ {
+ error("scope identifier expected");
+ goto Lerror;
+ }
+ else
+ {
+ TOK t = TOK.onScopeExit;
+ Identifier id = token.ident;
+ if (id == Id.exit)
+ t = TOK.onScopeExit;
+ else if (id == Id.failure)
+ t = TOK.onScopeFailure;
+ else if (id == Id.success)
+ t = TOK.onScopeSuccess;
+ else
+ error("valid scope identifiers are `exit`, `failure`, or `success`, not `%s`", id.toChars());
+ nextToken();
+ check(TOK.rightParenthesis);
+ AST.Statement st = parseStatement(ParseStatementFlags.scope_);
+ s = new AST.ScopeGuardStatement(loc, t, st);
+ break;
+ }
+
+ case TOK.debug_:
+ nextToken();
+ if (token.value == TOK.assign)
+ {
+ error("debug conditions can only be declared at module scope");
+ nextToken();
+ nextToken();
+ goto Lerror;
+ }
+ cond = parseDebugCondition();
+ goto Lcondition;
+
+ case TOK.version_:
+ nextToken();
+ if (token.value == TOK.assign)
+ {
+ error("version conditions can only be declared at module scope");
+ nextToken();
+ nextToken();
+ goto Lerror;
+ }
+ cond = parseVersionCondition();
+ goto Lcondition;
+
+ Lcondition:
+ {
+ const lookingForElseSave = lookingForElse;
+ lookingForElse = loc;
+ ifbody = parseStatement(0);
+ lookingForElse = lookingForElseSave;
+ }
+ elsebody = null;
+ if (token.value == TOK.else_)
+ {
+ const elseloc = token.loc;
+ nextToken();
+ elsebody = parseStatement(0);
+ checkDanglingElse(elseloc);
+ }
+ s = new AST.ConditionalStatement(loc, cond, ifbody, elsebody);
+ if (flags & ParseStatementFlags.scope_)
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ break;
+
+ case TOK.pragma_:
+ {
+ Identifier ident;
+ AST.Expressions* args = null;
+ AST.Statement _body;
+
+ nextToken();
+ check(TOK.leftParenthesis);
+ if (token.value != TOK.identifier)
+ {
+ error("`pragma(identifier)` expected");
+ goto Lerror;
+ }
+ ident = token.ident;
+ nextToken();
+ if (token.value == TOK.comma && peekNext() != TOK.rightParenthesis)
+ args = parseArguments(); // pragma(identifier, args...);
+ else
+ check(TOK.rightParenthesis); // pragma(identifier);
+ if (token.value == TOK.semicolon)
+ {
+ nextToken();
+ _body = null;
+ }
+ else
+ _body = parseStatement(ParseStatementFlags.semi);
+ s = new AST.PragmaStatement(loc, ident, args, _body);
+ break;
+ }
+ case TOK.switch_:
+ isfinal = false;
+ goto Lswitch;
+
+ Lswitch:
+ {
+ nextToken();
+ check(TOK.leftParenthesis);
+ AST.Expression condition = parseExpression();
+ check(TOK.rightParenthesis);
+ AST.Statement _body = parseStatement(ParseStatementFlags.scope_);
+ s = new AST.SwitchStatement(loc, condition, _body, isfinal);
+ break;
+ }
+ case TOK.case_:
+ {
+ AST.Expression exp;
+ AST.Expressions cases; // array of Expression's
+ AST.Expression last = null;
+
+ nextToken();
+ do
+ {
+ exp = parseAssignExp();
+ cases.push(exp);
+ if (token.value != TOK.comma)
+ break;
+ nextToken(); //comma
+ }
+ while (token.value != TOK.colon && token.value != TOK.endOfFile);
+ check(TOK.colon);
+
+ /* case exp: .. case last:
+ */
+ if (token.value == TOK.slice)
+ {
+ if (cases.dim > 1)
+ error("only one `case` allowed for start of case range");
+ nextToken();
+ check(TOK.case_);
+ last = parseAssignExp();
+ check(TOK.colon);
+ }
+
+ if (flags & ParseStatementFlags.curlyScope)
+ {
+ auto statements = new AST.Statements();
+ while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
+ {
+ auto cur = parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
+ statements.push(cur);
+
+ // https://issues.dlang.org/show_bug.cgi?id=21739
+ // Stop at the last break s.t. the following non-case statements are
+ // not merged into the current case. This can happen for
+ // case 1: ... break;
+ // debug { case 2: ... }
+ if (cur && cur.isBreakStatement())
+ break;
+ }
+ s = new AST.CompoundStatement(loc, statements);
+ }
+ else
+ {
+ s = parseStatement(ParseStatementFlags.semi);
+ }
+ s = new AST.ScopeStatement(loc, s, token.loc);
+
+ if (last)
+ {
+ s = new AST.CaseRangeStatement(loc, exp, last, s);
+ }
+ else
+ {
+ // Keep cases in order by building the case statements backwards
+ for (size_t i = cases.dim; i; i--)
+ {
+ exp = cases[i - 1];
+ s = new AST.CaseStatement(loc, exp, s);
+ }
+ }
+ break;
+ }
+ case TOK.default_:
+ {
+ nextToken();
+ check(TOK.colon);
+
+ if (flags & ParseStatementFlags.curlyScope)
+ {
+ auto statements = new AST.Statements();
+ while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly)
+ {
+ statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope));
+ }
+ s = new AST.CompoundStatement(loc, statements);
+ }
+ else
+ s = parseStatement(ParseStatementFlags.semi);
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ s = new AST.DefaultStatement(loc, s);
+ break;
+ }
+ case TOK.return_:
+ {
+ AST.Expression exp;
+ nextToken();
+ exp = token.value == TOK.semicolon ? null : parseExpression();
+ check(TOK.semicolon, "`return` statement");
+ s = new AST.ReturnStatement(loc, exp);
+ break;
+ }
+ case TOK.break_:
+ {
+ Identifier ident;
+ nextToken();
+ ident = null;
+ if (token.value == TOK.identifier)
+ {
+ ident = token.ident;
+ nextToken();
+ }
+ check(TOK.semicolon, "`break` statement");
+ s = new AST.BreakStatement(loc, ident);
+ break;
+ }
+ case TOK.continue_:
+ {
+ Identifier ident;
+ nextToken();
+ ident = null;
+ if (token.value == TOK.identifier)
+ {
+ ident = token.ident;
+ nextToken();
+ }
+ check(TOK.semicolon, "`continue` statement");
+ s = new AST.ContinueStatement(loc, ident);
+ break;
+ }
+ case TOK.goto_:
+ {
+ Identifier ident;
+ nextToken();
+ if (token.value == TOK.default_)
+ {
+ nextToken();
+ s = new AST.GotoDefaultStatement(loc);
+ }
+ else if (token.value == TOK.case_)
+ {
+ AST.Expression exp = null;
+ nextToken();
+ if (token.value != TOK.semicolon)
+ exp = parseExpression();
+ s = new AST.GotoCaseStatement(loc, exp);
+ }
+ else
+ {
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `goto`");
+ ident = null;
+ }
+ else
+ {
+ ident = token.ident;
+ nextToken();
+ }
+ s = new AST.GotoStatement(loc, ident);
+ }
+ check(TOK.semicolon, "`goto` statement");
+ break;
+ }
+ case TOK.synchronized_:
+ {
+ AST.Expression exp;
+ AST.Statement _body;
+
+ Token* t = peek(&token);
+ if (skipAttributes(t, &t) && t.value == TOK.class_)
+ goto Ldeclaration;
+
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ {
+ nextToken();
+ exp = parseExpression();
+ check(TOK.rightParenthesis);
+ }
+ else
+ exp = null;
+ _body = parseStatement(ParseStatementFlags.scope_);
+ s = new AST.SynchronizedStatement(loc, exp, _body);
+ break;
+ }
+ case TOK.with_:
+ {
+ AST.Expression exp;
+ AST.Statement _body;
+ Loc endloc = loc;
+
+ nextToken();
+ check(TOK.leftParenthesis);
+ exp = parseExpression();
+ check(TOK.rightParenthesis);
+ _body = parseStatement(ParseStatementFlags.scope_, null, &endloc);
+ s = new AST.WithStatement(loc, exp, _body, endloc);
+ break;
+ }
+ case TOK.try_:
+ {
+ AST.Statement _body;
+ AST.Catches* catches = null;
+ AST.Statement finalbody = null;
+
+ nextToken();
+ const lookingForElseSave = lookingForElse;
+ lookingForElse = Loc.initial;
+ _body = parseStatement(ParseStatementFlags.scope_);
+ lookingForElse = lookingForElseSave;
+ while (token.value == TOK.catch_)
+ {
+ AST.Statement handler;
+ AST.Catch c;
+ AST.Type t;
+ Identifier id;
+ const catchloc = token.loc;
+
+ nextToken();
+ if (token.value != TOK.leftParenthesis)
+ {
+ deprecation("`catch` statement without an exception specification is deprecated");
+ deprecationSupplemental(token.loc, "use `catch(Throwable)` for old behavior");
+ t = null;
+ id = null;
+ }
+ else
+ {
+ check(TOK.leftParenthesis);
+ id = null;
+ t = parseType(&id);
+ check(TOK.rightParenthesis);
+ }
+ handler = parseStatement(0);
+ c = new AST.Catch(catchloc, t, id, handler);
+ if (!catches)
+ catches = new AST.Catches();
+ catches.push(c);
+ }
+
+ if (token.value == TOK.finally_)
+ {
+ nextToken();
+ finalbody = parseStatement(ParseStatementFlags.scope_);
+ }
+
+ s = _body;
+ if (!catches && !finalbody)
+ error("`catch` or `finally` expected following `try`");
+ else
+ {
+ if (catches)
+ s = new AST.TryCatchStatement(loc, _body, catches);
+ if (finalbody)
+ s = new AST.TryFinallyStatement(loc, s, finalbody);
+ }
+ break;
+ }
+ case TOK.throw_:
+ {
+ AST.Expression exp;
+ nextToken();
+ exp = parseExpression();
+ check(TOK.semicolon, "`throw` statement");
+ s = new AST.ThrowStatement(loc, exp);
+ break;
+ }
+
+ case TOK.asm_:
+ s = parseAsm();
+ break;
+
+ case TOK.import_:
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=16088
+ *
+ * At this point it can either be an
+ * https://dlang.org/spec/grammar.html#ImportExpression
+ * or an
+ * https://dlang.org/spec/grammar.html#ImportDeclaration.
+ * See if the next token after `import` is a `(`; if so,
+ * then it is an import expression.
+ */
+ if (peekNext() == TOK.leftParenthesis)
+ {
+ AST.Expression e = parseExpression();
+ check(TOK.semicolon);
+ s = new AST.ExpStatement(loc, e);
+ }
+ else
+ {
+ AST.Dsymbols* imports = parseImport();
+ s = new AST.ImportStatement(loc, imports);
+ if (flags & ParseStatementFlags.scope_)
+ s = new AST.ScopeStatement(loc, s, token.loc);
+ }
+ break;
+ }
+ case TOK.template_:
+ {
+ AST.Dsymbol d = parseTemplateDeclaration();
+ s = new AST.ExpStatement(loc, d);
+ break;
+ }
+ default:
+ error("found `%s` instead of statement", token.toChars());
+ goto Lerror;
+
+ Lerror:
+ while (token.value != TOK.rightCurly && token.value != TOK.semicolon && token.value != TOK.endOfFile)
+ nextToken();
+ if (token.value == TOK.semicolon)
+ nextToken();
+ s = null;
+ break;
+ }
+ if (pEndloc)
+ *pEndloc = prevloc;
+ return s;
+ }
+
+
+ private AST.ExpInitializer parseExpInitializer(Loc loc)
+ {
+ auto ae = parseAssignExp();
+ return new AST.ExpInitializer(loc, ae);
+ }
+
+ private AST.Initializer parseStructInitializer(Loc loc)
+ {
+ /* Scan ahead to discern between a struct initializer and
+ * parameterless function literal.
+ *
+ * We'll scan the topmost curly bracket level for statement-related
+ * tokens, thereby ruling out a struct initializer. (A struct
+ * initializer which itself contains function literals may have
+ * statements at nested curly bracket levels.)
+ *
+ * It's important that this function literal check not be
+ * pendantic, otherwise a function having the slightest syntax
+ * error would emit confusing errors when we proceed to parse it
+ * as a struct initializer.
+ *
+ * The following two ambiguous cases will be treated as a struct
+ * initializer (best we can do without type info):
+ * {}
+ * {{statements...}} - i.e. it could be struct initializer
+ * with one function literal, or function literal having an
+ * extra level of curly brackets
+ * If a function literal is intended in these cases (unlikely),
+ * source can use a more explicit function literal syntax
+ * (e.g. prefix with "()" for empty parameter list).
+ */
+ int braces = 1;
+ int parens = 0;
+ for (auto t = peek(&token); 1; t = peek(t))
+ {
+ switch (t.value)
+ {
+ case TOK.leftParenthesis:
+ parens++;
+ continue;
+ case TOK.rightParenthesis:
+ parens--;
+ continue;
+ // https://issues.dlang.org/show_bug.cgi?id=21163
+ // lambda params can have the `scope` storage class, e.g
+ // `S s = { (scope Type Id){} }`
+ case TOK.scope_:
+ if (!parens) goto case;
+ continue;
+ /* Look for a semicolon or keyword of statements which don't
+ * require a semicolon (typically containing BlockStatement).
+ * Tokens like "else", "catch", etc. are omitted where the
+ * leading token of the statement is sufficient.
+ */
+ case TOK.asm_:
+ case TOK.class_:
+ case TOK.debug_:
+ case TOK.enum_:
+ case TOK.if_:
+ case TOK.interface_:
+ case TOK.pragma_:
+ case TOK.semicolon:
+ case TOK.struct_:
+ case TOK.switch_:
+ case TOK.synchronized_:
+ case TOK.try_:
+ case TOK.union_:
+ case TOK.version_:
+ case TOK.while_:
+ case TOK.with_:
+ if (braces == 1)
+ return parseExpInitializer(loc);
+ continue;
+
+ case TOK.leftCurly:
+ braces++;
+ continue;
+
+ case TOK.rightCurly:
+ if (--braces == 0)
+ break;
+ continue;
+
+ case TOK.endOfFile:
+ break;
+
+ default:
+ continue;
+ }
+ break;
+ }
+
+ auto _is = new AST.StructInitializer(loc);
+ bool commaExpected = false;
+ nextToken();
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.identifier:
+ {
+
+ if (commaExpected)
+ error("comma expected separating field initializers");
+ const t = peek(&token);
+ Identifier id;
+ if (t.value == TOK.colon)
+ {
+ id = token.ident;
+ nextToken();
+ nextToken(); // skip over ':'
+ }
+ auto value = parseInitializer();
+ _is.addInit(id, value);
+ commaExpected = true;
+ continue;
+ }
+ case TOK.comma:
+ if (!commaExpected)
+ error("expression expected, not `,`");
+ nextToken();
+ commaExpected = false;
+ continue;
+
+ case TOK.rightCurly: // allow trailing comma's
+ nextToken();
+ break;
+
+ case TOK.endOfFile:
+ error("found end of file instead of initializer");
+ break;
+
+ default:
+ if (commaExpected)
+ error("comma expected separating field initializers");
+ auto value = parseInitializer();
+ _is.addInit(null, value);
+ commaExpected = true;
+ continue;
+ }
+ break;
+ }
+ return _is;
+
+ }
+
+ /*****************************************
+ * Parse initializer for variable declaration.
+ */
+ private AST.Initializer parseInitializer()
+ {
+ const loc = token.loc;
+
+ switch (token.value)
+ {
+ case TOK.leftCurly:
+ return parseStructInitializer(loc);
+
+ case TOK.leftBracket:
+ /* Scan ahead to see if it is an array initializer or
+ * an expression.
+ * If it ends with a ';' ',' or '}', it is an array initializer.
+ */
+ int brackets = 1;
+ for (auto t = peek(&token); 1; t = peek(t))
+ {
+ switch (t.value)
+ {
+ case TOK.leftBracket:
+ brackets++;
+ continue;
+
+ case TOK.rightBracket:
+ if (--brackets == 0)
+ {
+ t = peek(t);
+ if (t.value != TOK.semicolon && t.value != TOK.comma && t.value != TOK.rightBracket && t.value != TOK.rightCurly)
+ return parseExpInitializer(loc);
+ break;
+ }
+ continue;
+
+ case TOK.endOfFile:
+ break;
+
+ default:
+ continue;
+ }
+ break;
+ }
+
+ auto ia = new AST.ArrayInitializer(loc);
+ bool commaExpected = false;
+
+ nextToken();
+ while (1)
+ {
+ switch (token.value)
+ {
+ default:
+ if (commaExpected)
+ {
+ error("comma expected separating array initializers, not `%s`", token.toChars());
+ nextToken();
+ break;
+ }
+ auto e = parseAssignExp();
+ if (!e)
+ break;
+
+ AST.Initializer value;
+ if (token.value == TOK.colon)
+ {
+ nextToken();
+ value = parseInitializer();
+ }
+ else
+ {
+ value = new AST.ExpInitializer(e.loc, e);
+ e = null;
+ }
+ ia.addInit(e, value);
+ commaExpected = true;
+ continue;
+
+ case TOK.leftCurly:
+ case TOK.leftBracket:
+ if (commaExpected)
+ error("comma expected separating array initializers, not `%s`", token.toChars());
+ auto value = parseInitializer();
+ AST.Expression e;
+
+ if (token.value == TOK.colon)
+ {
+ nextToken();
+ if (auto ei = value.isExpInitializer())
+ {
+ e = ei.exp;
+ value = parseInitializer();
+ }
+ else
+ error("initializer expression expected following colon, not `%s`", token.toChars());
+ }
+ ia.addInit(e, value);
+ commaExpected = true;
+ continue;
+
+ case TOK.comma:
+ if (!commaExpected)
+ error("expression expected, not `,`");
+ nextToken();
+ commaExpected = false;
+ continue;
+
+ case TOK.rightBracket: // allow trailing comma's
+ nextToken();
+ break;
+
+ case TOK.endOfFile:
+ error("found `%s` instead of array initializer", token.toChars());
+ break;
+ }
+ break;
+ }
+ return ia;
+
+ case TOK.void_:
+ const tv = peekNext();
+ if (tv == TOK.semicolon || tv == TOK.comma)
+ {
+ nextToken();
+ return new AST.VoidInitializer(loc);
+ }
+ return parseExpInitializer(loc);
+
+ default:
+ return parseExpInitializer(loc);
+ }
+ }
+
+ /*****************************************
+ * Parses default argument initializer expression that is an assign expression,
+ * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
+ */
+ private AST.Expression parseDefaultInitExp()
+ {
+ AST.Expression e = null;
+ const tv = peekNext();
+ if (tv == TOK.comma || tv == TOK.rightParenthesis)
+ {
+ switch (token.value)
+ {
+ case TOK.file: e = new AST.FileInitExp(token.loc, TOK.file); break;
+ case TOK.fileFullPath: e = new AST.FileInitExp(token.loc, TOK.fileFullPath); break;
+ case TOK.line: e = new AST.LineInitExp(token.loc); break;
+ case TOK.moduleString: e = new AST.ModuleInitExp(token.loc); break;
+ case TOK.functionString: e = new AST.FuncInitExp(token.loc); break;
+ case TOK.prettyFunction: e = new AST.PrettyFuncInitExp(token.loc); break;
+ default: goto LExp;
+ }
+ nextToken();
+ return e;
+ }
+ LExp:
+ return parseAssignExp();
+ }
+
+ /********************
+ * Parse inline assembler block.
+ * Returns:
+ * inline assembler block as a Statement
+ */
+ AST.Statement parseAsm()
+ {
+ // Parse the asm block into a sequence of AsmStatements,
+ // each AsmStatement is one instruction.
+ // Separate out labels.
+ // Defer parsing of AsmStatements until semantic processing.
+
+ const loc = token.loc;
+ Loc labelloc;
+
+ nextToken();
+ StorageClass stc = parsePostfix(STC.undefined_, null);
+ if (stc & (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild))
+ error("`const`/`immutable`/`shared`/`inout` attributes are not allowed on `asm` blocks");
+
+ check(TOK.leftCurly);
+ Token* toklist = null;
+ Token** ptoklist = &toklist;
+ Identifier label = null;
+ auto statements = new AST.Statements();
+ size_t nestlevel = 0;
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.identifier:
+ if (!toklist)
+ {
+ // Look ahead to see if it is a label
+ if (peekNext() == TOK.colon)
+ {
+ // It's a label
+ label = token.ident;
+ labelloc = token.loc;
+ nextToken();
+ nextToken();
+ continue;
+ }
+ }
+ goto default;
+
+ case TOK.leftCurly:
+ ++nestlevel;
+ goto default;
+
+ case TOK.rightCurly:
+ if (nestlevel > 0)
+ {
+ --nestlevel;
+ goto default;
+ }
+ if (toklist || label)
+ {
+ error("`asm` statements must end in `;`");
+ }
+ break;
+
+ case TOK.semicolon:
+ if (nestlevel != 0)
+ error("mismatched number of curly brackets");
+
+ if (toklist || label)
+ {
+ // Create AsmStatement from list of tokens we've saved
+ AST.Statement s = new AST.AsmStatement(token.loc, toklist);
+ toklist = null;
+ ptoklist = &toklist;
+ if (label)
+ {
+ s = new AST.LabelStatement(labelloc, label, s);
+ label = null;
+ }
+ statements.push(s);
+ }
+ nextToken();
+ continue;
+
+ case TOK.endOfFile:
+ /* { */
+ error("matching `}` expected, not end of file");
+ break;
+
+ case TOK.colonColon: // treat as two separate : tokens for iasmgcc
+ *ptoklist = allocateToken();
+ memcpy(*ptoklist, &token, Token.sizeof);
+ (*ptoklist).value = TOK.colon;
+ ptoklist = &(*ptoklist).next;
+
+ *ptoklist = allocateToken();
+ memcpy(*ptoklist, &token, Token.sizeof);
+ (*ptoklist).value = TOK.colon;
+ ptoklist = &(*ptoklist).next;
+
+ *ptoklist = null;
+ nextToken();
+ continue;
+
+ default:
+ *ptoklist = allocateToken();
+ memcpy(*ptoklist, &token, Token.sizeof);
+ ptoklist = &(*ptoklist).next;
+ *ptoklist = null;
+ nextToken();
+ continue;
+ }
+ break;
+ }
+ nextToken();
+ auto s = new AST.CompoundAsmStatement(loc, statements, stc);
+ return s;
+ }
+
+ /**********************************
+ * Issue error if the current token is not `value`,
+ * advance to next token.
+ * Params:
+ * loc = location for error message
+ * value = token value to compare with
+ */
+ void check(Loc loc, TOK value)
+ {
+ if (token.value != value)
+ error(loc, "found `%s` when expecting `%s`", token.toChars(), Token.toChars(value));
+ nextToken();
+ }
+
+ /**********************************
+ * Issue error if the current token is not `value`,
+ * advance to next token.
+ * Params:
+ * value = token value to compare with
+ */
+ void check(TOK value)
+ {
+ check(token.loc, value);
+ }
+
+ /**********************************
+ * Issue error if the current token is not `value`,
+ * advance to next token.
+ * Params:
+ * value = token value to compare with
+ * string = for error message
+ */
+ void check(TOK value, const(char)* string)
+ {
+ if (token.value != value)
+ error("found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(value), string);
+ nextToken();
+ }
+
+ private void checkParens(TOK value, AST.Expression e)
+ {
+ if (precedence[e.op] == PREC.rel && !e.parens)
+ error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(value));
+ }
+
+ ///
+ enum NeedDeclaratorId
+ {
+ no, // Declarator part must have no identifier
+ opt, // Declarator part identifier is optional
+ must, // Declarator part must have identifier
+ mustIfDstyle, // Declarator part must have identifier, but don't recognize old C-style syntax
+ }
+
+ /************************************
+ * Determine if the scanner is sitting on the start of a declaration.
+ * Params:
+ * t = current token of the scanner
+ * needId = flag with additional requirements for a declaration
+ * endtok = ending token
+ * pt = will be set ending token (if not null)
+ * Output:
+ * true if the token `t` is a declaration, false otherwise
+ */
+ private bool isDeclaration(Token* t, NeedDeclaratorId needId, TOK endtok, Token** pt)
+ {
+ //printf("isDeclaration(needId = %d)\n", needId);
+ int haveId = 0;
+ int haveTpl = 0;
+
+ while (1)
+ {
+ if ((t.value == TOK.const_ || t.value == TOK.immutable_ || t.value == TOK.inout_ || t.value == TOK.shared_) && peek(t).value != TOK.leftParenthesis)
+ {
+ /* const type
+ * immutable type
+ * shared type
+ * wild type
+ */
+ t = peek(t);
+ continue;
+ }
+ break;
+ }
+
+ if (!isBasicType(&t))
+ {
+ goto Lisnot;
+ }
+ if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != NeedDeclaratorId.mustIfDstyle))
+ goto Lisnot;
+ if ((needId == NeedDeclaratorId.no && !haveId) ||
+ (needId == NeedDeclaratorId.opt) ||
+ (needId == NeedDeclaratorId.must && haveId) ||
+ (needId == NeedDeclaratorId.mustIfDstyle && haveId))
+ {
+ if (pt)
+ *pt = t;
+ goto Lis;
+ }
+ goto Lisnot;
+
+ Lis:
+ //printf("\tis declaration, t = %s\n", t.toChars());
+ return true;
+
+ Lisnot:
+ //printf("\tis not declaration\n");
+ return false;
+ }
+
+ private bool isBasicType(Token** pt)
+ {
+ // This code parallels parseBasicType()
+ Token* t = *pt;
+ switch (t.value)
+ {
+ case TOK.wchar_:
+ case TOK.dchar_:
+ case TOK.bool_:
+ case TOK.char_:
+ case TOK.int8:
+ case TOK.uns8:
+ case TOK.int16:
+ case TOK.uns16:
+ case TOK.int32:
+ case TOK.uns32:
+ case TOK.int64:
+ case TOK.uns64:
+ case TOK.int128:
+ case TOK.uns128:
+ case TOK.float32:
+ case TOK.float64:
+ case TOK.float80:
+ case TOK.imaginary32:
+ case TOK.imaginary64:
+ case TOK.imaginary80:
+ case TOK.complex32:
+ case TOK.complex64:
+ case TOK.complex80:
+ case TOK.void_:
+ t = peek(t);
+ break;
+
+ case TOK.identifier:
+ L5:
+ t = peek(t);
+ if (t.value == TOK.not)
+ {
+ goto L4;
+ }
+ goto L3;
+ while (1)
+ {
+ L2:
+ t = peek(t);
+ L3:
+ if (t.value == TOK.dot)
+ {
+ Ldot:
+ t = peek(t);
+ if (t.value != TOK.identifier)
+ goto Lfalse;
+ t = peek(t);
+ if (t.value != TOK.not)
+ goto L3;
+ L4:
+ /* Seen a !
+ * Look for:
+ * !( args ), !identifier, etc.
+ */
+ t = peek(t);
+ switch (t.value)
+ {
+ case TOK.identifier:
+ goto L5;
+
+ case TOK.leftParenthesis:
+ if (!skipParens(t, &t))
+ goto Lfalse;
+ goto L3;
+
+ case TOK.wchar_:
+ case TOK.dchar_:
+ case TOK.bool_:
+ case TOK.char_:
+ case TOK.int8:
+ case TOK.uns8:
+ case TOK.int16:
+ case TOK.uns16:
+ case TOK.int32:
+ case TOK.uns32:
+ case TOK.int64:
+ case TOK.uns64:
+ case TOK.int128:
+ case TOK.uns128:
+ case TOK.float32:
+ case TOK.float64:
+ case TOK.float80:
+ case TOK.imaginary32:
+ case TOK.imaginary64:
+ case TOK.imaginary80:
+ case TOK.complex32:
+ case TOK.complex64:
+ case TOK.complex80:
+ case TOK.void_:
+ case TOK.int32Literal:
+ case TOK.uns32Literal:
+ case TOK.int64Literal:
+ case TOK.uns64Literal:
+ case TOK.int128Literal:
+ case TOK.uns128Literal:
+ case TOK.float32Literal:
+ case TOK.float64Literal:
+ case TOK.float80Literal:
+ case TOK.imaginary32Literal:
+ case TOK.imaginary64Literal:
+ case TOK.imaginary80Literal:
+ case TOK.null_:
+ case TOK.true_:
+ case TOK.false_:
+ case TOK.charLiteral:
+ case TOK.wcharLiteral:
+ case TOK.dcharLiteral:
+ case TOK.string_:
+ case TOK.hexadecimalString:
+ case TOK.file:
+ case TOK.fileFullPath:
+ case TOK.line:
+ case TOK.moduleString:
+ case TOK.functionString:
+ case TOK.prettyFunction:
+ goto L2;
+
+ default:
+ goto Lfalse;
+ }
+ }
+ break;
+ }
+ break;
+
+ case TOK.dot:
+ goto Ldot;
+
+ case TOK.typeof_:
+ case TOK.vector:
+ case TOK.mixin_:
+ /* typeof(exp).identifier...
+ */
+ t = peek(t);
+ if (!skipParens(t, &t))
+ goto Lfalse;
+ goto L3;
+
+ case TOK.traits:
+ // __traits(getMember
+ t = peek(t);
+ if (t.value != TOK.leftParenthesis)
+ goto Lfalse;
+ auto lp = t;
+ t = peek(t);
+ if (t.value != TOK.identifier || t.ident != Id.getMember)
+ goto Lfalse;
+ if (!skipParens(lp, &lp))
+ goto Lfalse;
+ // we are in a lookup for decl VS statement
+ // so we expect a declarator following __trait if it's a type.
+ // other usages wont be ambiguous (alias, template instance, type qual, etc.)
+ if (lp.value != TOK.identifier)
+ goto Lfalse;
+
+ break;
+
+ case TOK.const_:
+ case TOK.immutable_:
+ case TOK.shared_:
+ case TOK.inout_:
+ // const(type) or immutable(type) or shared(type) or wild(type)
+ t = peek(t);
+ if (t.value != TOK.leftParenthesis)
+ goto Lfalse;
+ t = peek(t);
+ if (!isDeclaration(t, NeedDeclaratorId.no, TOK.rightParenthesis, &t))
+ {
+ goto Lfalse;
+ }
+ t = peek(t);
+ break;
+
+ default:
+ goto Lfalse;
+ }
+ *pt = t;
+ //printf("is\n");
+ return true;
+
+ Lfalse:
+ //printf("is not\n");
+ return false;
+ }
+
+ private bool isDeclarator(Token** pt, int* haveId, int* haveTpl, TOK endtok, bool allowAltSyntax = true)
+ {
+ // This code parallels parseDeclarator()
+ Token* t = *pt;
+ int parens;
+
+ //printf("Parser::isDeclarator() %s\n", t.toChars());
+ if (t.value == TOK.assign)
+ return false;
+
+ while (1)
+ {
+ parens = false;
+ switch (t.value)
+ {
+ case TOK.mul:
+ //case TOK.and:
+ t = peek(t);
+ continue;
+
+ case TOK.leftBracket:
+ t = peek(t);
+ if (t.value == TOK.rightBracket)
+ {
+ t = peek(t);
+ }
+ else if (isDeclaration(t, NeedDeclaratorId.no, TOK.rightBracket, &t))
+ {
+ // It's an associative array declaration
+ t = peek(t);
+
+ // ...[type].ident
+ if (t.value == TOK.dot && peek(t).value == TOK.identifier)
+ {
+ t = peek(t);
+ t = peek(t);
+ }
+ }
+ else
+ {
+ // [ expression ]
+ // [ expression .. expression ]
+ if (!isExpression(&t))
+ return false;
+ if (t.value == TOK.slice)
+ {
+ t = peek(t);
+ if (!isExpression(&t))
+ return false;
+ if (t.value != TOK.rightBracket)
+ return false;
+ t = peek(t);
+ }
+ else
+ {
+ if (t.value != TOK.rightBracket)
+ return false;
+ t = peek(t);
+ // ...[index].ident
+ if (t.value == TOK.dot && peek(t).value == TOK.identifier)
+ {
+ t = peek(t);
+ t = peek(t);
+ }
+ }
+ }
+ continue;
+
+ case TOK.identifier:
+ if (*haveId)
+ return false;
+ *haveId = true;
+ t = peek(t);
+ break;
+
+ case TOK.leftParenthesis:
+ if (!allowAltSyntax)
+ return false; // Do not recognize C-style declarations.
+
+ t = peek(t);
+ if (t.value == TOK.rightParenthesis)
+ return false; // () is not a declarator
+
+ /* Regard ( identifier ) as not a declarator
+ * BUG: what about ( *identifier ) in
+ * f(*p)(x);
+ * where f is a class instance with overloaded () ?
+ * Should we just disallow C-style function pointer declarations?
+ */
+ if (t.value == TOK.identifier)
+ {
+ Token* t2 = peek(t);
+ if (t2.value == TOK.rightParenthesis)
+ return false;
+ }
+
+ if (!isDeclarator(&t, haveId, null, TOK.rightParenthesis))
+ return false;
+ t = peek(t);
+ parens = true;
+ break;
+
+ case TOK.delegate_:
+ case TOK.function_:
+ t = peek(t);
+ if (!isParameters(&t))
+ return false;
+ skipAttributes(t, &t);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ while (1)
+ {
+ switch (t.value)
+ {
+ static if (CARRAYDECL)
+ {
+ case TOK.leftBracket:
+ parens = false;
+ t = peek(t);
+ if (t.value == TOK.rightBracket)
+ {
+ t = peek(t);
+ }
+ else if (isDeclaration(t, NeedDeclaratorId.no, TOK.rightBracket, &t))
+ {
+ // It's an associative array declaration
+ t = peek(t);
+ }
+ else
+ {
+ // [ expression ]
+ if (!isExpression(&t))
+ return false;
+ if (t.value != TOK.rightBracket)
+ return false;
+ t = peek(t);
+ }
+ continue;
+ }
+
+ case TOK.leftParenthesis:
+ parens = false;
+ if (Token* tk = peekPastParen(t))
+ {
+ if (tk.value == TOK.leftParenthesis)
+ {
+ if (!haveTpl)
+ return false;
+ *haveTpl = 1;
+ t = tk;
+ }
+ else if (tk.value == TOK.assign)
+ {
+ if (!haveTpl)
+ return false;
+ *haveTpl = 1;
+ *pt = tk;
+ return true;
+ }
+ }
+ if (!isParameters(&t))
+ return false;
+ while (1)
+ {
+ switch (t.value)
+ {
+ case TOK.const_:
+ case TOK.immutable_:
+ case TOK.shared_:
+ case TOK.inout_:
+ case TOK.pure_:
+ case TOK.nothrow_:
+ case TOK.return_:
+ case TOK.scope_:
+ t = peek(t);
+ continue;
+
+ case TOK.at:
+ t = peek(t); // skip '@'
+ t = peek(t); // skip identifier
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ continue;
+
+ // Valid tokens that follow a declaration
+ case TOK.rightParenthesis:
+ case TOK.rightBracket:
+ case TOK.assign:
+ case TOK.comma:
+ case TOK.dotDotDot:
+ case TOK.semicolon:
+ case TOK.leftCurly:
+ case TOK.in_:
+ case TOK.out_:
+ case TOK.do_:
+ // The !parens is to disallow unnecessary parentheses
+ if (!parens && (endtok == TOK.reserved || endtok == t.value))
+ {
+ *pt = t;
+ return true;
+ }
+ return false;
+
+ case TOK.identifier:
+ if (t.ident == Id._body)
+ {
+ // @@@DEPRECATED@@@
+ // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
+ // Deprecated in 2.097 - Can be removed from 2.117
+ // The deprecation period is longer than usual as `body`
+ // was quite widely used.
+ deprecation("Usage of the `body` keyword is deprecated. Use `do` instead.");
+ goto case TOK.do_;
+ }
+ goto default;
+
+ case TOK.if_:
+ return haveTpl ? true : false;
+
+ // Used for mixin type parsing
+ case TOK.endOfFile:
+ if (endtok == TOK.endOfFile)
+ goto case TOK.do_;
+ return false;
+
+ default:
+ return false;
+ }
+ }
+ assert(0);
+ }
+
+ private bool isParameters(Token** pt)
+ {
+ // This code parallels parseParameterList()
+ Token* t = *pt;
+
+ //printf("isParameters()\n");
+ if (t.value != TOK.leftParenthesis)
+ return false;
+
+ t = peek(t);
+ for (; 1; t = peek(t))
+ {
+ L1:
+ switch (t.value)
+ {
+ case TOK.rightParenthesis:
+ break;
+
+ case TOK.at:
+ Token* pastAttr;
+ if (skipAttributes(t, &pastAttr))
+ {
+ t = pastAttr;
+ goto default;
+ }
+ break;
+
+ case TOK.dotDotDot:
+ t = peek(t);
+ break;
+
+ case TOK.in_:
+ case TOK.out_:
+ case TOK.ref_:
+ case TOK.lazy_:
+ case TOK.scope_:
+ case TOK.final_:
+ case TOK.auto_:
+ case TOK.return_:
+ continue;
+
+ case TOK.const_:
+ case TOK.immutable_:
+ case TOK.shared_:
+ case TOK.inout_:
+ t = peek(t);
+ if (t.value == TOK.leftParenthesis)
+ {
+ t = peek(t);
+ if (!isDeclaration(t, NeedDeclaratorId.no, TOK.rightParenthesis, &t))
+ return false;
+ t = peek(t); // skip past closing ')'
+ goto L2;
+ }
+ goto L1;
+
+ version (none)
+ {
+ case TOK.static_:
+ continue;
+ case TOK.auto_:
+ case TOK.alias_:
+ t = peek(t);
+ if (t.value == TOK.identifier)
+ t = peek(t);
+ if (t.value == TOK.assign)
+ {
+ t = peek(t);
+ if (!isExpression(&t))
+ return false;
+ }
+ goto L3;
+ }
+
+ default:
+ {
+ if (!isBasicType(&t))
+ return false;
+ L2:
+ int tmp = false;
+ if (t.value != TOK.dotDotDot && !isDeclarator(&t, &tmp, null, TOK.reserved))
+ return false;
+ if (t.value == TOK.assign)
+ {
+ t = peek(t);
+ if (!isExpression(&t))
+ return false;
+ }
+ if (t.value == TOK.dotDotDot)
+ {
+ t = peek(t);
+ break;
+ }
+ }
+ if (t.value == TOK.comma)
+ {
+ continue;
+ }
+ break;
+ }
+ break;
+ }
+ if (t.value != TOK.rightParenthesis)
+ return false;
+ t = peek(t);
+ *pt = t;
+ return true;
+ }
+
+ private bool isExpression(Token** pt)
+ {
+ // This is supposed to determine if something is an expression.
+ // What it actually does is scan until a closing right bracket
+ // is found.
+
+ Token* t = *pt;
+ int brnest = 0;
+ int panest = 0;
+ int curlynest = 0;
+
+ for (;; t = peek(t))
+ {
+ switch (t.value)
+ {
+ case TOK.leftBracket:
+ brnest++;
+ continue;
+
+ case TOK.rightBracket:
+ if (--brnest >= 0)
+ continue;
+ break;
+
+ case TOK.leftParenthesis:
+ panest++;
+ continue;
+
+ case TOK.comma:
+ if (brnest || panest)
+ continue;
+ break;
+
+ case TOK.rightParenthesis:
+ if (--panest >= 0)
+ continue;
+ break;
+
+ case TOK.leftCurly:
+ curlynest++;
+ continue;
+
+ case TOK.rightCurly:
+ if (--curlynest >= 0)
+ continue;
+ return false;
+
+ case TOK.slice:
+ if (brnest)
+ continue;
+ break;
+
+ case TOK.semicolon:
+ if (curlynest)
+ continue;
+ return false;
+
+ case TOK.endOfFile:
+ return false;
+
+ default:
+ continue;
+ }
+ break;
+ }
+
+ *pt = t;
+ return true;
+ }
+
+ /*******************************************
+ * Skip parentheses.
+ * Params:
+ * t = on opening $(LPAREN)
+ * pt = *pt is set to token past '$(RPAREN)' on true
+ * Returns:
+ * true successful
+ * false some parsing error
+ */
+ bool skipParens(Token* t, Token** pt)
+ {
+ if (t.value != TOK.leftParenthesis)
+ return false;
+
+ int parens = 0;
+
+ while (1)
+ {
+ switch (t.value)
+ {
+ case TOK.leftParenthesis:
+ parens++;
+ break;
+
+ case TOK.rightParenthesis:
+ parens--;
+ if (parens < 0)
+ goto Lfalse;
+ if (parens == 0)
+ goto Ldone;
+ break;
+
+ case TOK.endOfFile:
+ goto Lfalse;
+
+ default:
+ break;
+ }
+ t = peek(t);
+ }
+ Ldone:
+ if (pt)
+ *pt = peek(t); // skip found rparen
+ return true;
+
+ Lfalse:
+ return false;
+ }
+
+ private bool skipParensIf(Token* t, Token** pt)
+ {
+ if (t.value != TOK.leftParenthesis)
+ {
+ if (pt)
+ *pt = t;
+ return true;
+ }
+ return skipParens(t, pt);
+ }
+
+ //returns true if the next value (after optional matching parens) is expected
+ private bool hasOptionalParensThen(Token* t, TOK expected)
+ {
+ Token* tk;
+ if (!skipParensIf(t, &tk))
+ return false;
+ return tk.value == expected;
+ }
+
+ /*******************************************
+ * Skip attributes.
+ * Input:
+ * t is on a candidate attribute
+ * Output:
+ * *pt is set to first non-attribute token on success
+ * Returns:
+ * true successful
+ * false some parsing error
+ */
+ private bool skipAttributes(Token* t, Token** pt)
+ {
+ while (1)
+ {
+ switch (t.value)
+ {
+ case TOK.const_:
+ case TOK.immutable_:
+ case TOK.shared_:
+ case TOK.inout_:
+ case TOK.final_:
+ case TOK.auto_:
+ case TOK.scope_:
+ case TOK.override_:
+ case TOK.abstract_:
+ case TOK.synchronized_:
+ break;
+
+ case TOK.deprecated_:
+ if (peek(t).value == TOK.leftParenthesis)
+ {
+ t = peek(t);
+ if (!skipParens(t, &t))
+ goto Lerror;
+ // t is on the next of closing parenthesis
+ continue;
+ }
+ break;
+
+ case TOK.nothrow_:
+ case TOK.pure_:
+ case TOK.ref_:
+ case TOK.gshared:
+ case TOK.return_:
+ break;
+
+ case TOK.at:
+ t = peek(t);
+ if (t.value == TOK.identifier)
+ {
+ /* @identifier
+ * @identifier!arg
+ * @identifier!(arglist)
+ * any of the above followed by (arglist)
+ * @predefined_attribute
+ */
+ if (isBuiltinAtAttribute(t.ident))
+ break;
+ t = peek(t);
+ if (t.value == TOK.not)
+ {
+ t = peek(t);
+ if (t.value == TOK.leftParenthesis)
+ {
+ // @identifier!(arglist)
+ if (!skipParens(t, &t))
+ goto Lerror;
+ // t is on the next of closing parenthesis
+ }
+ else
+ {
+ // @identifier!arg
+ // Do low rent skipTemplateArgument
+ if (t.value == TOK.vector)
+ {
+ // identifier!__vector(type)
+ t = peek(t);
+ if (!skipParens(t, &t))
+ goto Lerror;
+ }
+ else
+ t = peek(t);
+ }
+ }
+ if (t.value == TOK.leftParenthesis)
+ {
+ if (!skipParens(t, &t))
+ goto Lerror;
+ // t is on the next of closing parenthesis
+ continue;
+ }
+ continue;
+ }
+ if (t.value == TOK.leftParenthesis)
+ {
+ // @( ArgumentList )
+ if (!skipParens(t, &t))
+ goto Lerror;
+ // t is on the next of closing parenthesis
+ continue;
+ }
+ goto Lerror;
+
+ default:
+ goto Ldone;
+ }
+ t = peek(t);
+ }
+ Ldone:
+ if (pt)
+ *pt = t;
+ return true;
+
+ Lerror:
+ return false;
+ }
+
+ AST.Expression parseExpression()
+ {
+ auto loc = token.loc;
+
+ //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
+ auto e = parseAssignExp();
+ while (token.value == TOK.comma)
+ {
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.CommaExp(loc, e, e2, false);
+ loc = token.loc;
+ }
+ return e;
+ }
+
+ /********************************* Expression Parser ***************************/
+
+ AST.Expression parsePrimaryExp()
+ {
+ AST.Expression e;
+ AST.Type t;
+ Identifier id;
+ const loc = token.loc;
+
+ //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
+ switch (token.value)
+ {
+ case TOK.identifier:
+ {
+ if (peekNext() == TOK.arrow)
+ {
+ // skip `identifier ->`
+ nextToken();
+ nextToken();
+ error("use `.` for member lookup, not `->`");
+ goto Lerr;
+ }
+
+ if (peekNext() == TOK.goesTo)
+ goto case_delegate;
+
+ id = token.ident;
+ nextToken();
+ TOK save;
+ if (token.value == TOK.not && (save = peekNext()) != TOK.is_ && save != TOK.in_)
+ {
+ // identifier!(template-argument-list)
+ auto tempinst = new AST.TemplateInstance(loc, id, parseTemplateArguments());
+ e = new AST.ScopeExp(loc, tempinst);
+ }
+ else
+ e = new AST.IdentifierExp(loc, id);
+ break;
+ }
+ case TOK.dollar:
+ if (!inBrackets)
+ error("`$` is valid only inside [] of index or slice");
+ e = new AST.DollarExp(loc);
+ nextToken();
+ break;
+
+ case TOK.dot:
+ // Signal global scope '.' operator with "" identifier
+ e = new AST.IdentifierExp(loc, Id.empty);
+ break;
+
+ case TOK.this_:
+ e = new AST.ThisExp(loc);
+ nextToken();
+ break;
+
+ case TOK.super_:
+ e = new AST.SuperExp(loc);
+ nextToken();
+ break;
+
+ case TOK.int32Literal:
+ e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint32);
+ nextToken();
+ break;
+
+ case TOK.uns32Literal:
+ e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32);
+ nextToken();
+ break;
+
+ case TOK.int64Literal:
+ e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint64);
+ nextToken();
+ break;
+
+ case TOK.uns64Literal:
+ e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns64);
+ nextToken();
+ break;
+
+ case TOK.float32Literal:
+ e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat32);
+ nextToken();
+ break;
+
+ case TOK.float64Literal:
+ e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat64);
+ nextToken();
+ break;
+
+ case TOK.float80Literal:
+ e = new AST.RealExp(loc, token.floatvalue, AST.Type.tfloat80);
+ nextToken();
+ break;
+
+ case TOK.imaginary32Literal:
+ e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary32);
+ nextToken();
+ break;
+
+ case TOK.imaginary64Literal:
+ e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary64);
+ nextToken();
+ break;
+
+ case TOK.imaginary80Literal:
+ e = new AST.RealExp(loc, token.floatvalue, AST.Type.timaginary80);
+ nextToken();
+ break;
+
+ case TOK.null_:
+ e = new AST.NullExp(loc);
+ nextToken();
+ break;
+
+ case TOK.file:
+ {
+ const(char)* s = loc.filename ? loc.filename : mod.ident.toChars();
+ e = new AST.StringExp(loc, s.toDString());
+ nextToken();
+ break;
+ }
+ case TOK.fileFullPath:
+ {
+ assert(loc.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location");
+ const s = FileName.toAbsolute(loc.filename);
+ e = new AST.StringExp(loc, s.toDString());
+ nextToken();
+ break;
+ }
+
+ case TOK.line:
+ e = new AST.IntegerExp(loc, loc.linnum, AST.Type.tint32);
+ nextToken();
+ break;
+
+ case TOK.moduleString:
+ {
+ const(char)* s = md ? md.toChars() : mod.toChars();
+ e = new AST.StringExp(loc, s.toDString());
+ nextToken();
+ break;
+ }
+ case TOK.functionString:
+ e = new AST.FuncInitExp(loc);
+ nextToken();
+ break;
+
+ case TOK.prettyFunction:
+ e = new AST.PrettyFuncInitExp(loc);
+ nextToken();
+ break;
+
+ case TOK.true_:
+ e = new AST.IntegerExp(loc, 1, AST.Type.tbool);
+ nextToken();
+ break;
+
+ case TOK.false_:
+ e = new AST.IntegerExp(loc, 0, AST.Type.tbool);
+ nextToken();
+ break;
+
+ case TOK.charLiteral:
+ e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tchar);
+ nextToken();
+ break;
+
+ case TOK.wcharLiteral:
+ e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.twchar);
+ nextToken();
+ break;
+
+ case TOK.dcharLiteral:
+ e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tdchar);
+ nextToken();
+ break;
+
+ case TOK.string_:
+ case TOK.hexadecimalString:
+ {
+ // cat adjacent strings
+ auto s = token.ustring;
+ auto len = token.len;
+ auto postfix = token.postfix;
+ while (1)
+ {
+ const prev = token;
+ nextToken();
+ if (token.value == TOK.string_ || token.value == TOK.hexadecimalString)
+ {
+ if (token.postfix)
+ {
+ if (token.postfix != postfix)
+ error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix);
+ postfix = token.postfix;
+ }
+
+ error("Implicit string concatenation is error-prone and disallowed in D");
+ errorSupplemental(token.loc, "Use the explicit syntax instead " ~
+ "(concatenating literals is `@nogc`): %s ~ %s",
+ prev.toChars(), token.toChars());
+
+ const len1 = len;
+ const len2 = token.len;
+ len = len1 + len2;
+ auto s2 = cast(char*)mem.xmalloc_noscan(len * char.sizeof);
+ memcpy(s2, s, len1 * char.sizeof);
+ memcpy(s2 + len1, token.ustring, len2 * char.sizeof);
+ s = s2;
+ }
+ else
+ break;
+ }
+ e = new AST.StringExp(loc, s[0 .. len], len, 1, postfix);
+ break;
+ }
+ case TOK.void_:
+ t = AST.Type.tvoid;
+ goto LabelX;
+
+ case TOK.int8:
+ t = AST.Type.tint8;
+ goto LabelX;
+
+ case TOK.uns8:
+ t = AST.Type.tuns8;
+ goto LabelX;
+
+ case TOK.int16:
+ t = AST.Type.tint16;
+ goto LabelX;
+
+ case TOK.uns16:
+ t = AST.Type.tuns16;
+ goto LabelX;
+
+ case TOK.int32:
+ t = AST.Type.tint32;
+ goto LabelX;
+
+ case TOK.uns32:
+ t = AST.Type.tuns32;
+ goto LabelX;
+
+ case TOK.int64:
+ t = AST.Type.tint64;
+ goto LabelX;
+
+ case TOK.uns64:
+ t = AST.Type.tuns64;
+ goto LabelX;
+
+ case TOK.int128:
+ t = AST.Type.tint128;
+ goto LabelX;
+
+ case TOK.uns128:
+ t = AST.Type.tuns128;
+ goto LabelX;
+
+ case TOK.float32:
+ t = AST.Type.tfloat32;
+ goto LabelX;
+
+ case TOK.float64:
+ t = AST.Type.tfloat64;
+ goto LabelX;
+
+ case TOK.float80:
+ t = AST.Type.tfloat80;
+ goto LabelX;
+
+ case TOK.imaginary32:
+ t = AST.Type.timaginary32;
+ goto LabelX;
+
+ case TOK.imaginary64:
+ t = AST.Type.timaginary64;
+ goto LabelX;
+
+ case TOK.imaginary80:
+ t = AST.Type.timaginary80;
+ goto LabelX;
+
+ case TOK.complex32:
+ t = AST.Type.tcomplex32;
+ goto LabelX;
+
+ case TOK.complex64:
+ t = AST.Type.tcomplex64;
+ goto LabelX;
+
+ case TOK.complex80:
+ t = AST.Type.tcomplex80;
+ goto LabelX;
+
+ case TOK.bool_:
+ t = AST.Type.tbool;
+ goto LabelX;
+
+ case TOK.char_:
+ t = AST.Type.tchar;
+ goto LabelX;
+
+ case TOK.wchar_:
+ t = AST.Type.twchar;
+ goto LabelX;
+
+ case TOK.dchar_:
+ t = AST.Type.tdchar;
+ goto LabelX;
+ LabelX:
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ {
+ e = new AST.TypeExp(loc, t);
+ e = new AST.CallExp(loc, e, parseArguments());
+ break;
+ }
+ check(TOK.dot, t.toChars());
+ if (token.value != TOK.identifier)
+ {
+ error("found `%s` when expecting identifier following `%s`.", token.toChars(), t.toChars());
+ goto Lerr;
+ }
+ e = new AST.DotIdExp(loc, new AST.TypeExp(loc, t), token.ident);
+ nextToken();
+ break;
+
+ case TOK.typeof_:
+ {
+ t = parseTypeof();
+ e = new AST.TypeExp(loc, t);
+ break;
+ }
+ case TOK.vector:
+ {
+ t = parseVector();
+ e = new AST.TypeExp(loc, t);
+ break;
+ }
+ case TOK.typeid_:
+ {
+ nextToken();
+ check(TOK.leftParenthesis, "`typeid`");
+ RootObject o = parseTypeOrAssignExp();
+ check(TOK.rightParenthesis);
+ e = new AST.TypeidExp(loc, o);
+ break;
+ }
+ case TOK.traits:
+ {
+ /* __traits(identifier, args...)
+ */
+ Identifier ident;
+ AST.Objects* args = null;
+
+ nextToken();
+ check(TOK.leftParenthesis);
+ if (token.value != TOK.identifier)
+ {
+ error("`__traits(identifier, args...)` expected");
+ goto Lerr;
+ }
+ ident = token.ident;
+ nextToken();
+ if (token.value == TOK.comma)
+ args = parseTemplateArgumentList(); // __traits(identifier, args...)
+ else
+ check(TOK.rightParenthesis); // __traits(identifier)
+
+ e = new AST.TraitsExp(loc, ident, args);
+ break;
+ }
+ case TOK.is_:
+ {
+ AST.Type targ;
+ Identifier ident = null;
+ AST.Type tspec = null;
+ TOK tok = TOK.reserved;
+ TOK tok2 = TOK.reserved;
+ AST.TemplateParameters* tpl = null;
+
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ {
+ nextToken();
+ if (token.value == TOK.identifier && peekNext() == TOK.leftParenthesis)
+ {
+ error(loc, "unexpected `(` after `%s`, inside `is` expression. Try enclosing the contents of `is` with a `typeof` expression", token.toChars());
+ nextToken();
+ Token* tempTok = peekPastParen(&token);
+ memcpy(&token, tempTok, Token.sizeof);
+ goto Lerr;
+ }
+ targ = parseType(&ident);
+ if (token.value == TOK.colon || token.value == TOK.equal)
+ {
+ tok = token.value;
+ nextToken();
+ if (tok == TOK.equal && (token.value == TOK.struct_ || token.value == TOK.union_
+ || token.value == TOK.class_ || token.value == TOK.super_ || token.value == TOK.enum_
+ || token.value == TOK.interface_ || token.value == TOK.package_ || token.value == TOK.module_
+ || token.value == TOK.argumentTypes || token.value == TOK.parameters
+ || token.value == TOK.const_ && peekNext() == TOK.rightParenthesis
+ || token.value == TOK.immutable_ && peekNext() == TOK.rightParenthesis
+ || token.value == TOK.shared_ && peekNext() == TOK.rightParenthesis
+ || token.value == TOK.inout_ && peekNext() == TOK.rightParenthesis || token.value == TOK.function_
+ || token.value == TOK.delegate_ || token.value == TOK.return_
+ || (token.value == TOK.vector && peekNext() == TOK.rightParenthesis)))
+ {
+ tok2 = token.value;
+ nextToken();
+ }
+ else
+ {
+ tspec = parseType();
+ }
+ }
+ if (tspec)
+ {
+ if (token.value == TOK.comma)
+ tpl = parseTemplateParameterList(1);
+ else
+ {
+ tpl = new AST.TemplateParameters();
+ check(TOK.rightParenthesis);
+ }
+ }
+ else
+ check(TOK.rightParenthesis);
+ }
+ else
+ {
+ error("`type identifier : specialization` expected following `is`");
+ goto Lerr;
+ }
+ e = new AST.IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
+ break;
+ }
+ case TOK.assert_:
+ {
+ // https://dlang.org/spec/expression.html#assert_expressions
+ AST.Expression msg = null;
+
+ nextToken();
+ check(TOK.leftParenthesis, "`assert`");
+ e = parseAssignExp();
+ if (token.value == TOK.comma)
+ {
+ nextToken();
+ if (token.value != TOK.rightParenthesis)
+ {
+ msg = parseAssignExp();
+ if (token.value == TOK.comma)
+ nextToken();
+ }
+ }
+ check(TOK.rightParenthesis);
+ e = new AST.AssertExp(loc, e, msg);
+ break;
+ }
+ case TOK.mixin_:
+ {
+ // https://dlang.org/spec/expression.html#mixin_expressions
+ nextToken();
+ if (token.value != TOK.leftParenthesis)
+ error("found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis));
+ auto exps = parseArguments();
+ e = new AST.MixinExp(loc, exps);
+ break;
+ }
+ case TOK.import_:
+ {
+ nextToken();
+ check(TOK.leftParenthesis, "`import`");
+ e = parseAssignExp();
+ check(TOK.rightParenthesis);
+ e = new AST.ImportExp(loc, e);
+ break;
+ }
+ case TOK.new_:
+ e = parseNewExp(null);
+ break;
+
+ case TOK.ref_:
+ {
+ if (peekNext() == TOK.leftParenthesis)
+ {
+ Token* tk = peekPastParen(peek(&token));
+ if (skipAttributes(tk, &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly))
+ {
+ // ref (arguments) => expression
+ // ref (arguments) { statements... }
+ goto case_delegate;
+ }
+ }
+ nextToken();
+ error("found `%s` when expecting function literal following `ref`", token.toChars());
+ goto Lerr;
+ }
+ case TOK.leftParenthesis:
+ {
+ Token* tk = peekPastParen(&token);
+ if (skipAttributes(tk, &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly))
+ {
+ // (arguments) => expression
+ // (arguments) { statements... }
+ goto case_delegate;
+ }
+
+ // ( expression )
+ nextToken();
+ e = parseExpression();
+ e.parens = 1;
+ check(loc, TOK.rightParenthesis);
+ break;
+ }
+ case TOK.leftBracket:
+ {
+ /* Parse array literals and associative array literals:
+ * [ value, value, value ... ]
+ * [ key:value, key:value, key:value ... ]
+ */
+ auto values = new AST.Expressions();
+ AST.Expressions* keys = null;
+
+ nextToken();
+ while (token.value != TOK.rightBracket && token.value != TOK.endOfFile)
+ {
+ e = parseAssignExp();
+ if (token.value == TOK.colon && (keys || values.dim == 0))
+ {
+ nextToken();
+ if (!keys)
+ keys = new AST.Expressions();
+ keys.push(e);
+ e = parseAssignExp();
+ }
+ else if (keys)
+ {
+ error("`key:value` expected for associative array literal");
+ keys = null;
+ }
+ values.push(e);
+ if (token.value == TOK.rightBracket)
+ break;
+ check(TOK.comma);
+ }
+ check(loc, TOK.rightBracket);
+
+ if (keys)
+ e = new AST.AssocArrayLiteralExp(loc, keys, values);
+ else
+ e = new AST.ArrayLiteralExp(loc, null, values);
+ break;
+ }
+ case TOK.leftCurly:
+ case TOK.function_:
+ case TOK.delegate_:
+ case_delegate:
+ {
+ AST.Dsymbol s = parseFunctionLiteral();
+ e = new AST.FuncExp(loc, s);
+ break;
+ }
+ default:
+ error("expression expected, not `%s`", token.toChars());
+ Lerr:
+ // Anything for e, as long as it's not NULL
+ e = new AST.IntegerExp(loc, 0, AST.Type.tint32);
+ nextToken();
+ break;
+ }
+ return e;
+ }
+
+ private AST.Expression parseUnaryExp()
+ {
+ AST.Expression e;
+ const loc = token.loc;
+
+ switch (token.value)
+ {
+ case TOK.and:
+ nextToken();
+ e = parseUnaryExp();
+ e = new AST.AddrExp(loc, e);
+ break;
+
+ case TOK.plusPlus:
+ nextToken();
+ e = parseUnaryExp();
+ //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
+ e = new AST.PreExp(TOK.prePlusPlus, loc, e);
+ break;
+
+ case TOK.minusMinus:
+ nextToken();
+ e = parseUnaryExp();
+ //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
+ e = new AST.PreExp(TOK.preMinusMinus, loc, e);
+ break;
+
+ case TOK.mul:
+ nextToken();
+ e = parseUnaryExp();
+ e = new AST.PtrExp(loc, e);
+ break;
+
+ case TOK.min:
+ nextToken();
+ e = parseUnaryExp();
+ e = new AST.NegExp(loc, e);
+ break;
+
+ case TOK.add:
+ nextToken();
+ e = parseUnaryExp();
+ e = new AST.UAddExp(loc, e);
+ break;
+
+ case TOK.not:
+ nextToken();
+ e = parseUnaryExp();
+ e = new AST.NotExp(loc, e);
+ break;
+
+ case TOK.tilde:
+ nextToken();
+ e = parseUnaryExp();
+ e = new AST.ComExp(loc, e);
+ break;
+
+ case TOK.delete_:
+ nextToken();
+ e = parseUnaryExp();
+ e = new AST.DeleteExp(loc, e, false);
+ break;
+
+ case TOK.cast_: // cast(type) expression
+ {
+ nextToken();
+ check(TOK.leftParenthesis);
+ /* Look for cast(), cast(const), cast(immutable),
+ * cast(shared), cast(shared const), cast(wild), cast(shared wild)
+ */
+ ubyte m = 0;
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.const_:
+ if (peekNext() == TOK.leftParenthesis)
+ break; // const as type constructor
+ m |= MODFlags.const_; // const as storage class
+ nextToken();
+ continue;
+
+ case TOK.immutable_:
+ if (peekNext() == TOK.leftParenthesis)
+ break;
+ m |= MODFlags.immutable_;
+ nextToken();
+ continue;
+
+ case TOK.shared_:
+ if (peekNext() == TOK.leftParenthesis)
+ break;
+ m |= MODFlags.shared_;
+ nextToken();
+ continue;
+
+ case TOK.inout_:
+ if (peekNext() == TOK.leftParenthesis)
+ break;
+ m |= MODFlags.wild;
+ nextToken();
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ if (token.value == TOK.rightParenthesis)
+ {
+ nextToken();
+ e = parseUnaryExp();
+ e = new AST.CastExp(loc, e, m);
+ }
+ else
+ {
+ AST.Type t = parseType(); // cast( type )
+ t = t.addMod(m); // cast( const type )
+ check(TOK.rightParenthesis);
+ e = parseUnaryExp();
+ e = new AST.CastExp(loc, e, t);
+ }
+ break;
+ }
+ case TOK.inout_:
+ case TOK.shared_:
+ case TOK.const_:
+ case TOK.immutable_: // immutable(type)(arguments) / immutable(type).init
+ {
+ StorageClass stc = parseTypeCtor();
+
+ AST.Type t = parseBasicType();
+ t = t.addSTC(stc);
+
+ if (stc == 0 && token.value == TOK.dot)
+ {
+ nextToken();
+ if (token.value != TOK.identifier)
+ {
+ error("identifier expected following `(type)`.");
+ return null;
+ }
+ e = new AST.DotIdExp(loc, new AST.TypeExp(loc, t), token.ident);
+ nextToken();
+ e = parsePostExp(e);
+ }
+ else
+ {
+ e = new AST.TypeExp(loc, t);
+ if (token.value != TOK.leftParenthesis)
+ {
+ error("`(arguments)` expected following `%s`", t.toChars());
+ return e;
+ }
+ e = new AST.CallExp(loc, e, parseArguments());
+ }
+ break;
+ }
+ case TOK.leftParenthesis:
+ {
+ auto tk = peek(&token);
+ static if (CCASTSYNTAX)
+ {
+ // If cast
+ if (isDeclaration(tk, NeedDeclaratorId.no, TOK.rightParenthesis, &tk))
+ {
+ tk = peek(tk); // skip over right parenthesis
+ switch (tk.value)
+ {
+ case TOK.not:
+ tk = peek(tk);
+ if (tk.value == TOK.is_ || tk.value == TOK.in_) // !is or !in
+ break;
+ goto case;
+
+ case TOK.dot:
+ case TOK.plusPlus:
+ case TOK.minusMinus:
+ case TOK.delete_:
+ case TOK.new_:
+ case TOK.leftParenthesis:
+ case TOK.identifier:
+ case TOK.this_:
+ case TOK.super_:
+ case TOK.int32Literal:
+ case TOK.uns32Literal:
+ case TOK.int64Literal:
+ case TOK.uns64Literal:
+ case TOK.int128Literal:
+ case TOK.uns128Literal:
+ case TOK.float32Literal:
+ case TOK.float64Literal:
+ case TOK.float80Literal:
+ case TOK.imaginary32Literal:
+ case TOK.imaginary64Literal:
+ case TOK.imaginary80Literal:
+ case TOK.null_:
+ case TOK.true_:
+ case TOK.false_:
+ case TOK.charLiteral:
+ case TOK.wcharLiteral:
+ case TOK.dcharLiteral:
+ case TOK.string_:
+ version (none)
+ {
+ case TOK.tilde:
+ case TOK.and:
+ case TOK.mul:
+ case TOK.min:
+ case TOK.add:
+ }
+ case TOK.function_:
+ case TOK.delegate_:
+ case TOK.typeof_:
+ case TOK.traits:
+ case TOK.vector:
+ case TOK.file:
+ case TOK.fileFullPath:
+ case TOK.line:
+ case TOK.moduleString:
+ case TOK.functionString:
+ case TOK.prettyFunction:
+ case TOK.wchar_:
+ case TOK.dchar_:
+ case TOK.bool_:
+ case TOK.char_:
+ case TOK.int8:
+ case TOK.uns8:
+ case TOK.int16:
+ case TOK.uns16:
+ case TOK.int32:
+ case TOK.uns32:
+ case TOK.int64:
+ case TOK.uns64:
+ case TOK.int128:
+ case TOK.uns128:
+ case TOK.float32:
+ case TOK.float64:
+ case TOK.float80:
+ case TOK.imaginary32:
+ case TOK.imaginary64:
+ case TOK.imaginary80:
+ case TOK.complex32:
+ case TOK.complex64:
+ case TOK.complex80:
+ case TOK.void_:
+ {
+ // (type) una_exp
+ nextToken();
+ auto t = parseType();
+ check(TOK.rightParenthesis);
+
+ // if .identifier
+ // or .identifier!( ... )
+ if (token.value == TOK.dot)
+ {
+ if (peekNext() != TOK.identifier && peekNext() != TOK.new_)
+ {
+ error("identifier or new keyword expected following `(...)`.");
+ return null;
+ }
+ e = new AST.TypeExp(loc, t);
+ e.parens = true;
+ e = parsePostExp(e);
+ }
+ else
+ {
+ e = parseUnaryExp();
+ e = new AST.CastExp(loc, e, t);
+ error("C style cast illegal, use `%s`", e.toChars());
+ }
+ return e;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ e = parsePrimaryExp();
+ e = parsePostExp(e);
+ break;
+ }
+ default:
+ e = parsePrimaryExp();
+ e = parsePostExp(e);
+ break;
+ }
+ assert(e);
+
+ // ^^ is right associative and has higher precedence than the unary operators
+ while (token.value == TOK.pow)
+ {
+ nextToken();
+ AST.Expression e2 = parseUnaryExp();
+ e = new AST.PowExp(loc, e, e2);
+ }
+
+ return e;
+ }
+
+ private AST.Expression parsePostExp(AST.Expression e)
+ {
+ while (1)
+ {
+ const loc = token.loc;
+ switch (token.value)
+ {
+ case TOK.dot:
+ nextToken();
+ if (token.value == TOK.identifier)
+ {
+ Identifier id = token.ident;
+
+ nextToken();
+ if (token.value == TOK.not && peekNext() != TOK.is_ && peekNext() != TOK.in_)
+ {
+ AST.Objects* tiargs = parseTemplateArguments();
+ e = new AST.DotTemplateInstanceExp(loc, e, id, tiargs);
+ }
+ else
+ e = new AST.DotIdExp(loc, e, id);
+ continue;
+ }
+ if (token.value == TOK.new_)
+ {
+ e = parseNewExp(e);
+ continue;
+ }
+ error("identifier or `new` expected following `.`, not `%s`", token.toChars());
+ break;
+
+ case TOK.plusPlus:
+ e = new AST.PostExp(TOK.plusPlus, loc, e);
+ break;
+
+ case TOK.minusMinus:
+ e = new AST.PostExp(TOK.minusMinus, loc, e);
+ break;
+
+ case TOK.leftParenthesis:
+ e = new AST.CallExp(loc, e, parseArguments());
+ continue;
+
+ case TOK.leftBracket:
+ {
+ // array dereferences:
+ // array[index]
+ // array[]
+ // array[lwr .. upr]
+ AST.Expression index;
+ AST.Expression upr;
+ auto arguments = new AST.Expressions();
+
+ inBrackets++;
+ nextToken();
+ while (token.value != TOK.rightBracket && token.value != TOK.endOfFile)
+ {
+ index = parseAssignExp();
+ if (token.value == TOK.slice)
+ {
+ // array[..., lwr..upr, ...]
+ nextToken();
+ upr = parseAssignExp();
+ arguments.push(new AST.IntervalExp(loc, index, upr));
+ }
+ else
+ arguments.push(index);
+ if (token.value == TOK.rightBracket)
+ break;
+ check(TOK.comma);
+ }
+ check(TOK.rightBracket);
+ inBrackets--;
+ e = new AST.ArrayExp(loc, e, arguments);
+ continue;
+ }
+ default:
+ return e;
+ }
+ nextToken();
+ }
+ }
+
+ private AST.Expression parseMulExp()
+ {
+ const loc = token.loc;
+ auto e = parseUnaryExp();
+
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.mul:
+ nextToken();
+ auto e2 = parseUnaryExp();
+ e = new AST.MulExp(loc, e, e2);
+ continue;
+
+ case TOK.div:
+ nextToken();
+ auto e2 = parseUnaryExp();
+ e = new AST.DivExp(loc, e, e2);
+ continue;
+
+ case TOK.mod:
+ nextToken();
+ auto e2 = parseUnaryExp();
+ e = new AST.ModExp(loc, e, e2);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ return e;
+ }
+
+ private AST.Expression parseAddExp()
+ {
+ const loc = token.loc;
+ auto e = parseMulExp();
+
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.add:
+ nextToken();
+ auto e2 = parseMulExp();
+ e = new AST.AddExp(loc, e, e2);
+ continue;
+
+ case TOK.min:
+ nextToken();
+ auto e2 = parseMulExp();
+ e = new AST.MinExp(loc, e, e2);
+ continue;
+
+ case TOK.tilde:
+ nextToken();
+ auto e2 = parseMulExp();
+ e = new AST.CatExp(loc, e, e2);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ return e;
+ }
+
+ private AST.Expression parseShiftExp()
+ {
+ const loc = token.loc;
+ auto e = parseAddExp();
+
+ while (1)
+ {
+ switch (token.value)
+ {
+ case TOK.leftShift:
+ nextToken();
+ auto e2 = parseAddExp();
+ e = new AST.ShlExp(loc, e, e2);
+ continue;
+
+ case TOK.rightShift:
+ nextToken();
+ auto e2 = parseAddExp();
+ e = new AST.ShrExp(loc, e, e2);
+ continue;
+
+ case TOK.unsignedRightShift:
+ nextToken();
+ auto e2 = parseAddExp();
+ e = new AST.UshrExp(loc, e, e2);
+ continue;
+
+ default:
+ break;
+ }
+ break;
+ }
+ return e;
+ }
+
+ private AST.Expression parseCmpExp()
+ {
+ const loc = token.loc;
+
+ auto e = parseShiftExp();
+ TOK op = token.value;
+
+ switch (op)
+ {
+ case TOK.equal:
+ case TOK.notEqual:
+ nextToken();
+ auto e2 = parseShiftExp();
+ e = new AST.EqualExp(op, loc, e, e2);
+ break;
+
+ case TOK.is_:
+ op = TOK.identity;
+ goto L1;
+
+ case TOK.not:
+ {
+ // Attempt to identify '!is'
+ const tv = peekNext();
+ if (tv == TOK.in_)
+ {
+ nextToken();
+ nextToken();
+ auto e2 = parseShiftExp();
+ e = new AST.InExp(loc, e, e2);
+ e = new AST.NotExp(loc, e);
+ break;
+ }
+ if (tv != TOK.is_)
+ break;
+ nextToken();
+ op = TOK.notIdentity;
+ goto L1;
+ }
+ L1:
+ nextToken();
+ auto e2 = parseShiftExp();
+ e = new AST.IdentityExp(op, loc, e, e2);
+ break;
+
+ case TOK.lessThan:
+ case TOK.lessOrEqual:
+ case TOK.greaterThan:
+ case TOK.greaterOrEqual:
+ nextToken();
+ auto e2 = parseShiftExp();
+ e = new AST.CmpExp(op, loc, e, e2);
+ break;
+
+ case TOK.in_:
+ nextToken();
+ auto e2 = parseShiftExp();
+ e = new AST.InExp(loc, e, e2);
+ break;
+
+ default:
+ break;
+ }
+ return e;
+ }
+
+ private AST.Expression parseAndExp()
+ {
+ Loc loc = token.loc;
+ auto e = parseCmpExp();
+ while (token.value == TOK.and)
+ {
+ checkParens(TOK.and, e);
+ nextToken();
+ auto e2 = parseCmpExp();
+ checkParens(TOK.and, e2);
+ e = new AST.AndExp(loc, e, e2);
+ loc = token.loc;
+ }
+ return e;
+ }
+
+ private AST.Expression parseXorExp()
+ {
+ const loc = token.loc;
+
+ auto e = parseAndExp();
+ while (token.value == TOK.xor)
+ {
+ checkParens(TOK.xor, e);
+ nextToken();
+ auto e2 = parseAndExp();
+ checkParens(TOK.xor, e2);
+ e = new AST.XorExp(loc, e, e2);
+ }
+ return e;
+ }
+
+ private AST.Expression parseOrExp()
+ {
+ const loc = token.loc;
+
+ auto e = parseXorExp();
+ while (token.value == TOK.or)
+ {
+ checkParens(TOK.or, e);
+ nextToken();
+ auto e2 = parseXorExp();
+ checkParens(TOK.or, e2);
+ e = new AST.OrExp(loc, e, e2);
+ }
+ return e;
+ }
+
+ private AST.Expression parseAndAndExp()
+ {
+ const loc = token.loc;
+
+ auto e = parseOrExp();
+ while (token.value == TOK.andAnd)
+ {
+ nextToken();
+ auto e2 = parseOrExp();
+ e = new AST.LogicalExp(loc, TOK.andAnd, e, e2);
+ }
+ return e;
+ }
+
+ private AST.Expression parseOrOrExp()
+ {
+ const loc = token.loc;
+
+ auto e = parseAndAndExp();
+ while (token.value == TOK.orOr)
+ {
+ nextToken();
+ auto e2 = parseAndAndExp();
+ e = new AST.LogicalExp(loc, TOK.orOr, e, e2);
+ }
+ return e;
+ }
+
+ private AST.Expression parseCondExp()
+ {
+ const loc = token.loc;
+
+ auto e = parseOrOrExp();
+ if (token.value == TOK.question)
+ {
+ nextToken();
+ auto e1 = parseExpression();
+ check(TOK.colon);
+ auto e2 = parseCondExp();
+ e = new AST.CondExp(loc, e, e1, e2);
+ }
+ return e;
+ }
+
+ AST.Expression parseAssignExp()
+ {
+ AST.Expression e;
+ e = parseCondExp();
+ if (e is null)
+ return e;
+
+ // require parens for e.g. `t ? a = 1 : b = 2`
+ if (e.op == TOK.question && !e.parens && precedence[token.value] == PREC.assign)
+ dmd.errors.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`",
+ e.toChars(), Token.toChars(token.value));
+
+ const loc = token.loc;
+ switch (token.value)
+ {
+ case TOK.assign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.AssignExp(loc, e, e2);
+ break;
+
+ case TOK.addAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.AddAssignExp(loc, e, e2);
+ break;
+
+ case TOK.minAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.MinAssignExp(loc, e, e2);
+ break;
+
+ case TOK.mulAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.MulAssignExp(loc, e, e2);
+ break;
+
+ case TOK.divAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.DivAssignExp(loc, e, e2);
+ break;
+
+ case TOK.modAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.ModAssignExp(loc, e, e2);
+ break;
+
+ case TOK.powAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.PowAssignExp(loc, e, e2);
+ break;
+
+ case TOK.andAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.AndAssignExp(loc, e, e2);
+ break;
+
+ case TOK.orAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.OrAssignExp(loc, e, e2);
+ break;
+
+ case TOK.xorAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.XorAssignExp(loc, e, e2);
+ break;
+
+ case TOK.leftShiftAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.ShlAssignExp(loc, e, e2);
+ break;
+
+ case TOK.rightShiftAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.ShrAssignExp(loc, e, e2);
+ break;
+
+ case TOK.unsignedRightShiftAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.UshrAssignExp(loc, e, e2);
+ break;
+
+ case TOK.concatenateAssign:
+ nextToken();
+ auto e2 = parseAssignExp();
+ e = new AST.CatAssignExp(loc, e, e2);
+ break;
+
+ default:
+ break;
+ }
+
+ return e;
+ }
+
+ /*************************
+ * Collect argument list.
+ * Assume current token is ',', '$(LPAREN)' or '['.
+ */
+ private AST.Expressions* parseArguments()
+ {
+ // function call
+ AST.Expressions* arguments;
+
+ arguments = new AST.Expressions();
+ const endtok = token.value == TOK.leftBracket ? TOK.rightBracket : TOK.rightParenthesis;
+
+ nextToken();
+
+ while (token.value != endtok && token.value != TOK.endOfFile)
+ {
+ auto arg = parseAssignExp();
+ arguments.push(arg);
+ if (token.value != TOK.comma)
+ break;
+
+ nextToken(); //comma
+ }
+
+ check(endtok);
+
+ return arguments;
+ }
+
+ /*******************************************
+ */
+ private AST.Expression parseNewExp(AST.Expression thisexp)
+ {
+ const loc = token.loc;
+
+ nextToken();
+ AST.Expressions* newargs = null;
+ AST.Expressions* arguments = null;
+ if (token.value == TOK.leftParenthesis)
+ {
+ newargs = parseArguments();
+ }
+
+ // An anonymous nested class starts with "class"
+ if (token.value == TOK.class_)
+ {
+ nextToken();
+ if (token.value == TOK.leftParenthesis)
+ arguments = parseArguments();
+
+ AST.BaseClasses* baseclasses = null;
+ if (token.value != TOK.leftCurly)
+ baseclasses = parseBaseClasses();
+
+ Identifier id = null;
+ AST.Dsymbols* members = null;
+
+ if (token.value != TOK.leftCurly)
+ {
+ error("`{ members }` expected for anonymous class");
+ }
+ else
+ {
+ nextToken();
+ members = parseDeclDefs(0);
+ if (token.value != TOK.rightCurly)
+ error("class member expected");
+ nextToken();
+ }
+
+ auto cd = new AST.ClassDeclaration(loc, id, baseclasses, members, false);
+ auto e = new AST.NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
+ return e;
+ }
+
+ const stc = parseTypeCtor();
+ auto t = parseBasicType(true);
+ t = parseTypeSuffixes(t);
+ t = t.addSTC(stc);
+ if (t.ty == Taarray)
+ {
+ AST.TypeAArray taa = cast(AST.TypeAArray)t;
+ AST.Type index = taa.index;
+ auto edim = AST.typeToExpression(index);
+ if (!edim)
+ {
+ error("cannot create a `%s` with `new`", t.toChars);
+ return new AST.NullExp(loc);
+ }
+ t = new AST.TypeSArray(taa.next, edim);
+ }
+ else if (token.value == TOK.leftParenthesis && t.ty != Tsarray)
+ {
+ arguments = parseArguments();
+ }
+
+ auto e = new AST.NewExp(loc, thisexp, newargs, t, arguments);
+ return e;
+ }
+
+ /**********************************************
+ */
+ private void addComment(AST.Dsymbol s, const(char)* blockComment)
+ {
+ if (s !is null)
+ this.addComment(s, blockComment.toDString());
+ }
+
+ private void addComment(AST.Dsymbol s, const(char)[] blockComment)
+ {
+ if (s !is null)
+ {
+ s.addComment(combineComments(blockComment, token.lineComment, true));
+ token.lineComment = null;
+ }
+ }
+
+ /**********************************************
+ * Recognize builtin @ attributes
+ * Params:
+ * ident = identifier
+ * Returns:
+ * storage class for attribute, 0 if not
+ */
+ static StorageClass isBuiltinAtAttribute(Identifier ident)
+ {
+ return (ident == Id.property) ? STC.property :
+ (ident == Id.nogc) ? STC.nogc :
+ (ident == Id.safe) ? STC.safe :
+ (ident == Id.trusted) ? STC.trusted :
+ (ident == Id.system) ? STC.system :
+ (ident == Id.live) ? STC.live :
+ (ident == Id.future) ? STC.future :
+ (ident == Id.disable) ? STC.disable :
+ 0;
+ }
+
+ enum StorageClass atAttrGroup =
+ STC.property |
+ STC.nogc |
+ STC.safe |
+ STC.trusted |
+ STC.system |
+ STC.live |
+ /*STC.future |*/ // probably should be included
+ STC.disable;
+ }
+
+enum PREC : int
+{
+ zero,
+ expr,
+ assign,
+ cond,
+ oror,
+ andand,
+ or,
+ xor,
+ and,
+ equal,
+ rel,
+ shift,
+ add,
+ mul,
+ pow,
+ unary,
+ primary,
+}
diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d
new file mode 100644
index 0000000..d3e3086
--- /dev/null
+++ b/gcc/d/dmd/parsetimevisitor.d
@@ -0,0 +1,297 @@
+/**
+ * Defines a visitor for the AST.
+ *
+ * Other visitors derive from this class.
+ *
+ * Documentation: https://dlang.org/phobos/dmd_parsetimevisitor.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/parsetimevisitor.d
+ */
+
+module dmd.parsetimevisitor;
+
+/** Basic and dumm visitor which implements a visit method for each AST node
+ * implemented in AST. This visitor is the parent of strict, transitive
+ * and permissive visitors.
+ */
+extern (C++) class ParseTimeVisitor(AST)
+{
+public:
+ void visit(AST.Dsymbol) { assert(0); }
+ void visit(AST.Parameter) { assert(0); }
+ void visit(AST.Statement) { assert(0); }
+ void visit(AST.Type) { assert(0); }
+ void visit(AST.Expression) { assert(0); }
+ void visit(AST.TemplateParameter) { assert(0); }
+ void visit(AST.Condition) { assert(0); }
+ void visit(AST.Initializer) { assert(0); }
+
+ //=======================================================================================
+ // Dsymbols
+ void visit(AST.AliasThis s) { visit(cast(AST.Dsymbol)s); }
+ void visit(AST.Declaration s) { visit(cast(AST.Dsymbol)s); }
+ void visit(AST.ScopeDsymbol s) { visit(cast(AST.Dsymbol)s); }
+ void visit(AST.Import s) { visit(cast(AST.Dsymbol)s); }
+ void visit(AST.AttribDeclaration s) { visit(cast(AST.Dsymbol)s); }
+ void visit(AST.StaticAssert s) { visit(cast(AST.Dsymbol)s); }
+ void visit(AST.DebugSymbol s) { visit(cast(AST.Dsymbol)s); }
+ void visit(AST.VersionSymbol s) { visit(cast(AST.Dsymbol)s); }
+ void visit(AST.AliasAssign s) { visit(cast(AST.Dsymbol)s); }
+
+ // ScopeDsymbols
+ void visit(AST.Package s) { visit(cast(AST.ScopeDsymbol)s); }
+ void visit(AST.EnumDeclaration s) { visit(cast(AST.ScopeDsymbol)s); }
+ void visit(AST.AggregateDeclaration s) { visit(cast(AST.ScopeDsymbol)s); }
+ void visit(AST.TemplateDeclaration s) { visit(cast(AST.ScopeDsymbol)s); }
+ void visit(AST.TemplateInstance s) { visit(cast(AST.ScopeDsymbol)s); }
+ void visit(AST.Nspace s) { visit(cast(AST.ScopeDsymbol)s); }
+
+ //=========================================================================================
+ // Declarations
+ void visit(AST.VarDeclaration s) { visit(cast(AST.Declaration)s); }
+ void visit(AST.FuncDeclaration s) { visit(cast(AST.Declaration)s); }
+ void visit(AST.AliasDeclaration s) { visit(cast(AST.Declaration)s); }
+ void visit(AST.TupleDeclaration s) { visit(cast(AST.Declaration)s); }
+
+ // FuncDeclarations
+ void visit(AST.FuncLiteralDeclaration s) { visit(cast(AST.FuncDeclaration)s); }
+ void visit(AST.PostBlitDeclaration s) { visit(cast(AST.FuncDeclaration)s); }
+ void visit(AST.CtorDeclaration s) { visit(cast(AST.FuncDeclaration)s); }
+ void visit(AST.DtorDeclaration s) { visit(cast(AST.FuncDeclaration)s); }
+ void visit(AST.InvariantDeclaration s) { visit(cast(AST.FuncDeclaration)s); }
+ void visit(AST.UnitTestDeclaration s) { visit(cast(AST.FuncDeclaration)s); }
+ void visit(AST.NewDeclaration s) { visit(cast(AST.FuncDeclaration)s); }
+ void visit(AST.StaticCtorDeclaration s) { visit(cast(AST.FuncDeclaration)s); }
+ void visit(AST.StaticDtorDeclaration s) { visit(cast(AST.FuncDeclaration)s); }
+ void visit(AST.SharedStaticCtorDeclaration s) { visit(cast(AST.StaticCtorDeclaration)s); }
+ void visit(AST.SharedStaticDtorDeclaration s) { visit(cast(AST.StaticDtorDeclaration)s); }
+
+ // AttribDeclarations
+ void visit(AST.CompileDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+ void visit(AST.UserAttributeDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+ void visit(AST.LinkDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+ void visit(AST.AnonDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+ void visit(AST.AlignDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+ void visit(AST.CPPMangleDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+ void visit(AST.CPPNamespaceDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+ void visit(AST.VisibilityDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+ void visit(AST.PragmaDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+ void visit(AST.StorageClassDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+ void visit(AST.ConditionalDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+ void visit(AST.StaticForeachDeclaration s) { visit(cast(AST.AttribDeclaration)s); }
+
+ //==============================================================================================
+ // Miscellaneous
+ void visit(AST.DeprecatedDeclaration s) { visit(cast(AST.StorageClassDeclaration)s); }
+ void visit(AST.StaticIfDeclaration s) { visit(cast(AST.ConditionalDeclaration)s); }
+ void visit(AST.EnumMember s) { visit(cast(AST.VarDeclaration)s); }
+ void visit(AST.Module s) { visit(cast(AST.Package)s); }
+ void visit(AST.StructDeclaration s) { visit(cast(AST.AggregateDeclaration)s); }
+ void visit(AST.UnionDeclaration s) { visit(cast(AST.StructDeclaration)s); }
+ void visit(AST.ClassDeclaration s) { visit(cast(AST.AggregateDeclaration)s); }
+ void visit(AST.InterfaceDeclaration s) { visit(cast(AST.ClassDeclaration)s); }
+ void visit(AST.TemplateMixin s) { visit(cast(AST.TemplateInstance)s); }
+ void visit(AST.BitFieldDeclaration s) { visit(cast(AST.VarDeclaration)s); }
+
+ //============================================================================================
+ // Statements
+ void visit(AST.ImportStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.ScopeStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.ReturnStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.LabelStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.StaticAssertStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.CompileStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.WhileStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.ForStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.DoStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.ForeachRangeStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.ForeachStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.IfStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.ScopeGuardStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.ConditionalStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.StaticForeachStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.PragmaStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.SwitchStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.CaseRangeStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.CaseStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.DefaultStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.BreakStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.ContinueStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.GotoDefaultStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.GotoCaseStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.GotoStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.SynchronizedStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.WithStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.TryCatchStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.TryFinallyStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.ThrowStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.AsmStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.ExpStatement s) { visit(cast(AST.Statement)s); }
+ void visit(AST.CompoundStatement s) { visit(cast(AST.Statement)s); }
+
+ // CompoundStatements
+ void visit(AST.CompoundDeclarationStatement s) { visit(cast(AST.CompoundStatement)s); }
+ void visit(AST.CompoundAsmStatement s) { visit(cast(AST.CompoundStatement)s); }
+
+ // AsmStatements
+ void visit(AST.InlineAsmStatement s) { visit(cast(AST.AsmStatement)s); }
+ void visit(AST.GccAsmStatement s) { visit(cast(AST.AsmStatement)s); }
+
+ //=========================================================================================
+ // Types
+ void visit(AST.TypeBasic t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeError t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeNull t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeNoreturn t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeVector t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeEnum t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeTuple t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeClass t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeStruct t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeNext t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeQualified t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeTraits t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeMixin t) { visit(cast(AST.Type)t); }
+ void visit(AST.TypeTag t) { visit(cast(AST.Type)t); }
+
+ // TypeNext
+ void visit(AST.TypeReference t) { visit(cast(AST.TypeNext)t); }
+ void visit(AST.TypeSlice t) { visit(cast(AST.TypeNext)t); }
+ void visit(AST.TypeDelegate t) { visit(cast(AST.TypeNext)t); }
+ void visit(AST.TypePointer t) { visit(cast(AST.TypeNext)t); }
+ void visit(AST.TypeFunction t) { visit(cast(AST.TypeNext)t); }
+ void visit(AST.TypeArray t) { visit(cast(AST.TypeNext)t); }
+
+ // TypeArray
+ void visit(AST.TypeDArray t) { visit(cast(AST.TypeArray)t); }
+ void visit(AST.TypeAArray t) { visit(cast(AST.TypeArray)t); }
+ void visit(AST.TypeSArray t) { visit(cast(AST.TypeArray)t); }
+
+ // TypeQualified
+ void visit(AST.TypeIdentifier t) { visit(cast(AST.TypeQualified)t); }
+ void visit(AST.TypeReturn t) { visit(cast(AST.TypeQualified)t); }
+ void visit(AST.TypeTypeof t) { visit(cast(AST.TypeQualified)t); }
+ void visit(AST.TypeInstance t) { visit(cast(AST.TypeQualified)t); }
+
+ //=================================================================================
+ // Expressions
+ void visit(AST.DeclarationExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.IntegerExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.NewAnonClassExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.IsExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.RealExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.NullExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.TypeidExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.TraitsExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.StringExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.NewExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.AssocArrayLiteralExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.ArrayLiteralExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.MixinExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.FuncExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.IntervalExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.TypeExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.ScopeExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.IdentifierExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.UnaExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.DefaultInitExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.BinExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.DsymbolExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.TemplateExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.SymbolExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.TupleExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.ThisExp e) { visit(cast(AST.Expression)e); }
+ void visit(AST.GenericExp e) { visit(cast(AST.Expression)e); }
+
+ // Miscellaneous
+ void visit(AST.VarExp e) { visit(cast(AST.SymbolExp)e); }
+ void visit(AST.DollarExp e) { visit(cast(AST.IdentifierExp)e); }
+ void visit(AST.SuperExp e) { visit(cast(AST.ThisExp)e); }
+
+ // UnaExp
+ void visit(AST.AddrExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.PreExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.PtrExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.NegExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.UAddExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.NotExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.ComExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.DeleteExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.CastExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.CallExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.DotIdExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.AssertExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.ImportExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.DotTemplateInstanceExp e) { visit(cast(AST.UnaExp)e); }
+ void visit(AST.ArrayExp e) { visit(cast(AST.UnaExp)e); }
+
+ // DefaultInitExp
+ void visit(AST.FuncInitExp e) { visit(cast(AST.DefaultInitExp)e); }
+ void visit(AST.PrettyFuncInitExp e) { visit(cast(AST.DefaultInitExp)e); }
+ void visit(AST.FileInitExp e) { visit(cast(AST.DefaultInitExp)e); }
+ void visit(AST.LineInitExp e) { visit(cast(AST.DefaultInitExp)e); }
+ void visit(AST.ModuleInitExp e) { visit(cast(AST.DefaultInitExp)e); }
+
+ // BinExp
+ void visit(AST.CommaExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.PostExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.PowExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.MulExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.DivExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.ModExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.AddExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.MinExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.CatExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.ShlExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.ShrExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.UshrExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.EqualExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.InExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.IdentityExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.CmpExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.AndExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.XorExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.OrExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.LogicalExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.CondExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.AssignExp e) { visit(cast(AST.BinExp)e); }
+ void visit(AST.BinAssignExp e) { visit(cast(AST.BinExp)e); }
+
+ // BinAssignExp
+ void visit(AST.AddAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+ void visit(AST.MinAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+ void visit(AST.MulAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+ void visit(AST.DivAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+ void visit(AST.ModAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+ void visit(AST.PowAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+ void visit(AST.AndAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+ void visit(AST.OrAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+ void visit(AST.XorAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+ void visit(AST.ShlAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+ void visit(AST.ShrAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+ void visit(AST.UshrAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+ void visit(AST.CatAssignExp e) { visit(cast(AST.BinAssignExp)e); }
+
+ //===============================================================================
+ // TemplateParameter
+ void visit(AST.TemplateAliasParameter tp) { visit(cast(AST.TemplateParameter)tp); }
+ void visit(AST.TemplateTypeParameter tp) { visit(cast(AST.TemplateParameter)tp); }
+ void visit(AST.TemplateTupleParameter tp) { visit(cast(AST.TemplateParameter)tp); }
+ void visit(AST.TemplateValueParameter tp) { visit(cast(AST.TemplateParameter)tp); }
+
+ void visit(AST.TemplateThisParameter tp) { visit(cast(AST.TemplateTypeParameter)tp); }
+
+ //===============================================================================
+ // Condition
+ void visit(AST.StaticIfCondition c) { visit(cast(AST.Condition)c); }
+ void visit(AST.DVCondition c) { visit(cast(AST.Condition)c); }
+ void visit(AST.DebugCondition c) { visit(cast(AST.DVCondition)c); }
+ void visit(AST.VersionCondition c) { visit(cast(AST.DVCondition)c); }
+
+ //===============================================================================
+ // Initializer
+ void visit(AST.ExpInitializer i) { visit(cast(AST.Initializer)i); }
+ void visit(AST.StructInitializer i) { visit(cast(AST.Initializer)i); }
+ void visit(AST.ArrayInitializer i) { visit(cast(AST.Initializer)i); }
+ void visit(AST.VoidInitializer i) { visit(cast(AST.Initializer)i); }
+ void visit(AST.CInitializer i) { visit(cast(AST.CInitializer)i); }
+}
diff --git a/gcc/d/dmd/permissivevisitor.d b/gcc/d/dmd/permissivevisitor.d
new file mode 100644
index 0000000..5d7f3fc
--- /dev/null
+++ b/gcc/d/dmd/permissivevisitor.d
@@ -0,0 +1,28 @@
+/**
+ * A visitor that facilitates the traversal of subsets of the AST.
+ *
+ * Documentation: https://dlang.org/phobos/dmd_permissivevisitor.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/permissivevisitor.d
+ */
+
+module dmd.permissivevisitor;
+
+import dmd.parsetimevisitor;
+
+/** PermissiveVisitor overrides all the visit methods in the parent class
+ * that assert(0) in order to facilitate the traversal of subsets of the AST.
+ * It does not implement any visiting logic.
+ */
+extern(C++) class PermissiveVisitor(AST): ParseTimeVisitor!AST
+{
+ alias visit = ParseTimeVisitor!AST.visit;
+
+ override void visit(AST.Dsymbol){}
+ override void visit(AST.Parameter){}
+ override void visit(AST.Statement){}
+ override void visit(AST.Type){}
+ override void visit(AST.Expression){}
+ override void visit(AST.TemplateParameter){}
+ override void visit(AST.Condition){}
+ override void visit(AST.Initializer){}
+}
diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d
new file mode 100644
index 0000000..3f12b17
--- /dev/null
+++ b/gcc/d/dmd/printast.d
@@ -0,0 +1,173 @@
+/**
+ * Provides an AST printer for debugging.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/printast.d, _printast.d)
+ * Documentation: https://dlang.org/phobos/dmd_printast.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/printast.d
+ */
+
+module dmd.printast;
+
+import core.stdc.stdio;
+
+import dmd.expression;
+import dmd.tokens;
+import dmd.visitor;
+
+/********************
+ * Print AST data structure in a nice format.
+ * Params:
+ * e = expression AST to print
+ * indent = indentation level
+ */
+void printAST(Expression e, int indent = 0)
+{
+ scope PrintASTVisitor pav = new PrintASTVisitor(indent);
+ e.accept(pav);
+}
+
+private:
+
+extern (C++) final class PrintASTVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+
+ int indent;
+
+ extern (D) this(int indent)
+ {
+ this.indent = indent;
+ }
+
+ override void visit(Expression e)
+ {
+ printIndent(indent);
+ printf("%s %s\n", Token.toChars(e.op), e.type ? e.type.toChars() : "");
+ }
+
+ override void visit(IntegerExp e)
+ {
+ printIndent(indent);
+ printf("Integer %lld %s\n", e.toInteger(), e.type ? e.type.toChars() : "");
+ }
+
+ override void visit(RealExp e)
+ {
+ printIndent(indent);
+
+ import dmd.hdrgen : floatToBuffer;
+ import dmd.root.outbuffer : OutBuffer;
+ OutBuffer buf;
+ floatToBuffer(e.type, e.value, &buf, false);
+ printf("Real %s %s\n", buf.peekChars(), e.type ? e.type.toChars() : "");
+ }
+
+ override void visit(StructLiteralExp e)
+ {
+ printIndent(indent);
+ printf("%s %s, %s\n", Token.toChars(e.op), e.type ? e.type.toChars() : "", e.toChars());
+ }
+
+ override void visit(SymbolExp e)
+ {
+ printIndent(indent);
+ printf("Symbol %s\n", e.type ? e.type.toChars() : "");
+ printIndent(indent + 2);
+ printf(".var: %s\n", e.var ? e.var.toChars() : "");
+ }
+
+ override void visit(DsymbolExp e)
+ {
+ visit(cast(Expression)e);
+ printIndent(indent + 2);
+ printf(".s: %s\n", e.s ? e.s.toChars() : "");
+ }
+
+ override void visit(DotIdExp e)
+ {
+ printIndent(indent);
+ printf("DotId %s\n", e.type ? e.type.toChars() : "");
+ printIndent(indent + 2);
+ printf(".ident: %s\n", e.ident.toChars());
+ printAST(e.e1, indent + 2);
+ }
+
+ override void visit(UnaExp e)
+ {
+ visit(cast(Expression)e);
+ printAST(e.e1, indent + 2);
+ }
+
+ override void visit(VectorExp e)
+ {
+ printIndent(indent);
+ printf("Vector %s\n", e.type ? e.type.toChars() : "");
+ printIndent(indent + 2);
+ printf(".to: %s\n", e.to.toChars());
+ printAST(e.e1, indent + 2);
+ }
+
+ override void visit(VectorArrayExp e)
+ {
+ printIndent(indent);
+ printf("VectorArray %s\n", e.type ? e.type.toChars() : "");
+ printAST(e.e1, indent + 2);
+ }
+
+ override void visit(BinExp e)
+ {
+ visit(cast(Expression)e);
+ printAST(e.e1, indent + 2);
+ printAST(e.e2, indent + 2);
+ }
+
+ override void visit(AssignExp e)
+ {
+ printIndent(indent);
+ printf("Assign %s\n", e.type ? e.type.toChars() : "");
+ printAST(e.e1, indent + 2);
+ printAST(e.e2, indent + 2);
+ }
+
+ override void visit(ConstructExp e)
+ {
+ printIndent(indent);
+ printf("Construct %s\n", e.type ? e.type.toChars() : "");
+ printAST(e.e1, indent + 2);
+ printAST(e.e2, indent + 2);
+ }
+
+ override void visit(BlitExp e)
+ {
+ printIndent(indent);
+ printf("Blit %s\n", e.type ? e.type.toChars() : "");
+ printAST(e.e1, indent + 2);
+ printAST(e.e2, indent + 2);
+ }
+
+ override void visit(IndexExp e)
+ {
+ printIndent(indent);
+ printf("Index %s\n", e.type ? e.type.toChars() : "");
+ printAST(e.e1, indent + 2);
+ printAST(e.e2, indent + 2);
+ }
+
+ override void visit(DelegateExp e)
+ {
+ visit(cast(Expression)e);
+ printIndent(indent + 2);
+ printf(".func: %s\n", e.func ? e.func.toChars() : "");
+ }
+
+ static void printIndent(int indent)
+ {
+ foreach (i; 0 .. indent)
+ putc(' ', stdout);
+ }
+}
+
+
diff --git a/gcc/d/dmd/readme.txt b/gcc/d/dmd/readme.txt
deleted file mode 100644
index a9a31af..0000000
--- a/gcc/d/dmd/readme.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-This is the source code to the DMD compiler
-for the D Programming Language defined in the documents at
-http://dlang.org/
-
-These sources are free, they are redistributable and modifiable
-under the terms of the Boost Software License, Version 1.0.
-The terms of this license are in the file boostlicense.txt,
-or see http://www.boost.org/LICENSE_1_0.txt.
-
-If a particular file has a different license in it, that overrides
-this license for that file.
-
--Walter Bright
diff --git a/gcc/d/dmd/res/default_ddoc_theme.ddoc b/gcc/d/dmd/res/default_ddoc_theme.ddoc
new file mode 100644
index 0000000..7ae0db8
--- /dev/null
+++ b/gcc/d/dmd/res/default_ddoc_theme.ddoc
@@ -0,0 +1,825 @@
+LPAREN = (
+RPAREN = )
+BACKTICK = `
+DOLLAR = $
+COMMA = ,
+QUOTE = &quot;
+LF =
+$(LF)
+
+ESCAPES =
+ /</&lt;/
+ />/&gt;/
+ /&/&amp;/
+
+H1 = <h1>$0</h1>
+H2 = <h2>$0</h2>
+H3 = <h3>$0</h3>
+H4 = <h4>$0</h4>
+H5 = <h5>$0</h5>
+H6 = <h6>$0</h6>
+B = <b>$0</b>
+I = <i>$0</i>
+EM = <em>$0</em>
+STRONG = <strong>$0</strong>
+U = <u>$0</u>
+P = <p>$0</p>
+DL = <dl>$0</dl>
+DT = <dt>$0</dt>
+DD = <dd>$0</dd>
+TABLE = <table>$0</table>
+THEAD = <thead>$0</thead>
+TBODY = <tbody>$0</tbody>
+TR = <tr>$0</tr>
+TH = <th>$0</th>
+TD = <td>$0</td>
+TH_ALIGN = <th align="$1">$+</th>
+TD_ALIGN = <td align="$1">$+</td>
+OL = <ol>$0</ol>
+OL_START = <ol start="$1">$2</ol>
+UL = <ul>$0</ul>
+LI = <li>$0</li>
+BIG = <span class="font_big">$0</span>
+SMALL = <small>$0</small>
+BR = <br>
+HR = <hr />
+LINK = <a href="$0">$0</a>
+LINK2 = <a href="$1">$+</a>
+LINK_TITLE = <a href="$1" title="$2">$3</a>
+SYMBOL_LINK = <a href="$1">$(DDOC_PSYMBOL $+)</a>
+PHOBOS_PATH = https://dlang.org/phobos/
+DOC_ROOT_std = $(PHOBOS_PATH)
+DOC_ROOT_core = $(PHOBOS_PATH)
+DOC_ROOT_etc = $(PHOBOS_PATH)
+DOC_ROOT_object = $(PHOBOS_PATH)
+DOC_EXTENSION = .html
+IMAGE = <img src="$1" alt="$+" />
+IMAGE_TITLE = <img src="$1" alt="$3" title="$2" />
+BLOCKQUOTE = <blockquote>$0</blockquote>
+DEPRECATED = $0
+
+RED = <span class="color_red">$0</span>
+BLUE = <span class="color_blue">$0</span>
+GREEN = <span class="color_green">$0</span>
+YELLOW = <span class="color_yellow">$0</span>
+BLACK = <span class="color_black">$0</span>
+WHITE = <span class="color_white">$0</span>
+
+D_CODE =
+<section class="code_listing">
+ <div class="code_sample">
+ <div class="dlang">
+ <ol class="code_lines">
+ <li><code class="code">$0</code></li>
+ </ol>
+ </div>
+ </div>
+</section>
+
+OTHER_CODE =
+<section class="code_listing">
+ <div class="code_sample">
+ <div class="dlang">
+ <ol class="code_lines">
+ <li><code class="code language-$1">$+</code></li>
+ </ol>
+ </div>
+ </div>
+</section>
+
+D_INLINECODE = <code class="code">$0</code>
+DDOC_BACKQUOTED = $(D_INLINECODE $0)
+D_COMMENT = <span class="comment">$0</span>
+D_STRING = <span class="string_literal">$0</span>
+D_KEYWORD = <span class="keyword">$0</span>
+D_PSYMBOL = <span class="psymbol">$0</span>
+D_PARAM = <span class="param">$0</span>
+
+DDOC_BLANKLINE = <br><br>
+DDOC_COMMENT = <!-- $0 -->
+
+DDOC =
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+ <title>$(TITLE)</title>
+ <style type="text/css" media="screen">
+ html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p,
+ blockquote, pre, a, abbr, address, cite, code, del, dfn, em, figure,
+ img, ins, kbd, q, s, samp, small, strong, sub, sup, var, b, u, i, dl,
+ dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption,
+ tbody, tfoot, thead, tr, th, td {
+ background: transparent none repeat scroll 0 0;
+ border: 0 none;
+ font-size: 100%;
+ margin: 0;
+ outline: 0 none;
+ padding: 0;
+ vertical-align: baseline;
+ }
+
+ h1 { font-size: 200%; }
+ h2 { font-size: 160%; }
+ h3 { font-size: 120%; }
+ h4 { font-size: 100%; }
+ h5 { font-size: 80%; }
+ h6 { font-size: 80%; font-weight: normal; }
+
+ ul, ol {
+ margin: 1.4em 0;
+ }
+ ul ul, ol ol, ul ol, ol ul {
+ margin-top: 0;
+ margin-bottom: 0;
+ }
+ ul, ol {
+ margin-left: 2.8em;
+ }
+
+ ol {
+ list-style: decimal;
+ }
+ ol ol {
+ list-style: lower-alpha;
+ }
+ ol ol ol {
+ list-style: lower-roman;
+ }
+ ol ol ol ol {
+ list-style: decimal;
+ }
+
+ blockquote {
+ margin: 0.1em;
+ margin-left: 1em;
+ border-left: 2px solid #cccccc;
+ padding-left: 0.7em;
+ }
+
+ .color_red { color: #dc322f; }
+ .color_blue { color: #268bd2; }
+ .color_green { color: #859901; }
+ .color_yellow { color: #b58901; }
+ .color_black { color: black; }
+ .color_white { color: white; }
+
+ .font_big {
+ font-size: 1.2em;
+ }
+
+ .ddoc_section_h {
+ font-weight: bold;
+ font-size: 13px;
+ line-height: 19.5px;
+ margin-top: 11px;
+ display: block;
+ }
+
+ body.dlang .dlang {
+ display: inline-block;
+ }
+
+ body.dlang .declaration .dlang {
+ display: block;
+ }
+
+ body.dlang .ddoc_header_anchor a.dlang {
+ display: block;
+ color: rgba(0, 136, 204, 1);
+ text-decoration: none;
+ }
+
+ body.dlang .ddoc_header_anchor .code {
+ color: rgba(0, 136, 204, 1);
+ }
+
+ #ddoc_main .module {
+ border-color: currentColor rgba(233, 233, 233, 1) rgba(233, 233, 233, 1);
+ border-style: none solid solid;
+ border-width: 0 1px 1px;
+ overflow-x: hidden;
+ padding: 15px;
+ }
+
+ #ddoc_main .section .section {
+ margin-top: 0;
+ }
+
+ #ddoc_main .ddoc_module_members_section {
+ padding: 1px 0 0;
+ transition: transform 0.3s ease 0s;
+ }
+
+ #ddoc_main .ddoc_member, #ddoc_main .ddoc_module_members section.intro {
+ background: #fff none repeat scroll 0 0;
+ list-style-type: none;
+ width: 100%;
+ }
+
+ #ddoc_main .ddoc_header_anchor {
+ font-size: 1.4em;
+ transition: transform 0.3s ease 0s;
+ }
+
+ #ddoc_main .ddoc_header_anchor > .code {
+ display: inline-block;
+
+ }
+
+ #ddoc_main .ddoc_decl {
+ background-color: transparent;
+ height: 100%;
+ left: 0;
+ top: 0;
+ padding: 0;
+ padding-left: 15px;
+ }
+
+ #ddoc_main .ddoc_decl .section, #ddoc_main .section.ddoc_sections {
+ background: white none repeat scroll 0 0;
+ margin: 0;
+ padding: 5px;
+ position: relative;
+ border-radius: 5px;
+ }
+
+ #ddoc_main .ddoc_decl .section h4:first-of-type, #ddoc_main .section.ddoc_sections h4:first-of-type {
+ font-size: 13px;
+ line-height: 1.5;
+ margin-top: 21px;
+ }
+
+ #ddoc_main .section .declaration {
+ margin-top: 21px;
+ }
+
+ #ddoc_main .section .declaration .code {
+ color: rgba(0, 0, 0, 1);
+ margin-bottom: 15px;
+ padding-bottom: 6px;
+ }
+
+ #ddoc_main .declaration div .para {
+ margin-bottom: 0;
+ }
+
+ #ddoc_main .ddoc_params .graybox tr td:first-of-type {
+ padding: 7px;
+ text-align: right;
+ vertical-align: top;
+ word-break: normal;
+ white-space: nowrap;
+ }
+
+ #ddoc_main .ddoc_params .graybox {
+ border: 0 none;
+ }
+
+ #ddoc_main .ddoc_params .graybox td {
+ border-color: rgba(214, 214, 214, 1);
+ }
+
+ #ddoc_main .ddoc_params .graybox tr:first-child > td {
+ border-top: 0 none;
+ }
+
+ #ddoc_main .ddoc_params .graybox tr:last-child > td {
+ border-bottom: 0 none;
+ }
+
+ #ddoc_main .ddoc_params .graybox tr > td:first-child {
+ border-left: 0 none;
+ }
+
+ #ddoc_main .ddoc_params .graybox tr > td:last-child {
+ border-right: 0 none;
+ width: 100%;
+ }
+
+ #ddoc_main em.term, #ddoc_main em.term .code {
+ color: rgba(65, 65, 65, 1);
+ font-size: 12px;
+ font-style: italic;
+ line-height: 1.5;
+ }
+
+ #ddoc_main .see-also {
+ cursor: pointer;
+ font-family: Menlo,monospace;
+ }
+
+ #ddoc_main .ddoc_decl .section > div:last-of-type {
+ margin-bottom: 15px;
+ }
+
+ #ddoc_main .ddoc_member, #ddoc_main .ddoc_module_members {
+ transition: transform 0.3s ease 0s;
+ }
+
+ #ddoc_main .code_sample {
+ background: inherit;
+ }
+
+ #ddoc_main .declaration .code-line {
+ display: block;
+ font: 1em Menlo,monospace;
+ }
+
+ #ddoc_main a[name] {
+ margin: -112px 0 0;
+ padding-top: 112px;
+ }
+
+ #ddoc_main .ddoc_decl td {
+ max-width: inherit;
+ }
+
+ #ddoc_main .declaration a {
+ color: inherit;
+ }
+
+ #ddoc_main .declaration a:hover {
+ color: rgba(0, 136, 204, 1);
+ text-decoration: underline;
+ }
+
+ body.ddoc {
+ background-color: transparent;
+ color: rgba(0, 0, 0, 1);
+ font-family: Helvetica,Arial,sans-serif;
+ font-size: 62.5%;
+ margin: 0;
+ border: 0;
+ left: 0;
+ top: 0;
+ padding: 0;
+ }
+
+ .ddoc a[name] {
+ display: block;
+ height: 0;
+ margin: -85px 0 0;
+ padding-top: 85px;
+ width: 0;
+ }
+
+ .ddoc .module {
+ border-color: transparent;
+ background-color: rgba(255, 255, 255, 1);
+ border-color: currentColor rgba(233, 233, 233, 1) rgba(233, 233, 233, 1);
+ border-image: none;
+ border-style: none solid solid;
+ border-width: 0 1px 1px;
+ box-shadow: 0 0 1px rgba(0, 0, 0, 0.07);
+ display: block;
+ margin-left: 0;
+ min-height: calc(100% - 173px);
+ overflow: auto;
+ padding-bottom: 100px;
+ }
+
+ .ddoc .content_wrapper {
+ background-color: rgba(242, 242, 242, 1);
+ margin: 0 auto;
+ max-width: 980px;
+ }
+
+ .ddoc .section {
+ padding: 15px 25px 30px;
+ }
+
+ .ddoc .section .section {
+ margin: 30px 0 0;
+ padding: 0;
+ }
+
+ .ddoc .para {
+ color: rgba(65, 65, 65, 1);
+ font-size: 1.4em;
+ line-height: 145%;
+ margin-bottom: 15px;
+ }
+
+ .ddoc .ddoc_examples .para {
+ margin-bottom: 0;
+ }
+
+ .ddoc .module_name {
+ color: rgba(0, 0, 0, 1);
+ display: block;
+ font-family: Helvetica;
+ font-size: 2.8em;
+ font-weight: 100;
+ margin-bottom: 0;
+ padding: 15px 0;
+ }
+
+ .ddoc .module a {
+ color: rgba(0, 136, 204, 1);
+ text-decoration: none;
+ }
+
+ .ddoc .code {
+ color: rgba(128, 128, 128, 1);
+ font-family: Menlo,monospace;
+ font-size: 0.85em;
+ word-wrap: break-word;
+ }
+
+ .ddoc .code i {
+ font-style: normal;
+ }
+
+ .ddoc .code .code {
+ font-size: 1em;
+ }
+
+ .ddoc .code_sample {
+ background-clip: padding-box;
+ margin: 1px 0;
+ text-align: left;
+ }
+
+ .ddoc .code_sample {
+ display: block;
+ font-size: 1.4em;
+ margin-left: 21px;
+ }
+
+ .ddoc ol .code_sample {
+ font-size: 1em;
+ }
+
+ .ddoc .code_lines {
+ counter-reset: li;
+ line-height: 1.6em;
+ list-style: outside none none;
+ margin: 0;
+ padding: 0;
+ }
+
+ .ddoc .code_listing .code_sample div {
+ margin-left: 13px;
+ width: 93%;
+ }
+
+ .ddoc .code_listing .code_sample div .code_lines li {
+ list-style-type: none;
+ margin: 0;
+ padding-right: 10px;
+ }
+
+ .ddoc .code_sample div .code_lines li::before {
+ margin-left: -33px;
+ margin-right: 25px;
+ }
+
+ .ddoc .code_sample div .code_lines li:nth-child(n+10)::before {
+ margin-left: -39px;
+ margin-right: 25px;
+ }
+
+ .ddoc .code_sample div .code_lines li:nth-child(n+100)::before {
+ margin-left: -46px;
+ margin-right: 25px;
+ }
+
+ .ddoc .code_sample .code_lines .code {
+ color: #000;
+ }
+
+ .ddoc div.dlang {
+ margin: 10px 0 21px;
+ padding: 4px 0 2px 10px;
+ }
+
+ .ddoc div.dlang {
+ margin: 10px 0 21px;
+ padding: 4px 0 2px 10px;
+ }
+
+ .ddoc div.dlang {
+ border-left: 5px solid rgba(0, 155, 51, 0.2);
+ }
+
+ .ddoc .code_lines li::before {
+ color: rgba(128, 128, 128, 1);
+ content: counter(li, decimal);
+ counter-increment: li;
+ font-family: Menlo,monospace;
+ font-size: 0.9em;
+ margin-right: 16px;
+ }
+
+ .ddoc .code_lines li {
+ padding-left: 0;
+ white-space: pre-wrap;
+ }
+
+ .ddoc .code_lines li:only-of-type::before {
+ color: rgba(255, 255, 255, 1);
+ content: " ";
+ }
+
+ .ddoc .code_lines li:only-of-type {
+ color: rgba(255, 255, 255, 1);
+ content: " ";
+ }
+
+ .ddoc .code_lines li:nth-child(n+10) {
+ text-indent: -17px;
+ }
+
+ .ddoc .code_lines li:nth-child(n+10)::before {
+ margin-right: 12px;
+ }
+
+ .ddoc .graybox {
+ border: 1px solid rgba(233, 233, 233, 1);
+ border-collapse: collapse;
+ border-spacing: 0;
+ empty-cells: hide;
+ margin: 20px 0 36px;
+ text-align: left;
+ }
+
+ .ddoc .graybox p {
+ margin: 0;
+ min-width: 50px;
+ }
+
+ .ddoc th {
+ margin: 0;
+ max-width: 260px;
+ padding: 5px 10px 5px 10px;
+ vertical-align: bottom;
+ }
+
+ .ddoc td {
+ border: 1px solid rgba(233, 233, 233, 1);
+ margin: 0;
+ max-width: 260px;
+ padding: 5px 10px 5px 10px;
+ vertical-align: middle;
+ }
+
+ .punctuation {
+ color: rgba(0, 0, 0, 1);
+ }
+
+ .comment {
+ color: rgba(0, 131, 18, 1);
+ }
+
+ .operator {
+ color: #000;
+ }
+
+ .keyword {
+ color: rgba(170, 13, 145, 1);
+ }
+
+ .keyword_type {
+ color: rgba(170, 51, 145, 1);
+ }
+
+ .string_literal {
+ color: rgba(196, 26, 22, 1);
+ }
+
+ .ddoc_psuper_symbol {
+ color: rgba(92, 38, 153, 1);
+ }
+
+ .param {
+ color: rgba(0, 0, 0, 1);
+ }
+
+ .psymbol {
+ color: rgba(0, 0, 0, 1);
+ }
+
+ .ddoc_member_header .ddoc_header_anchor .code {
+ font-size: 1em;
+ }
+ </style>
+ </head>
+ <body id="ddoc_main" class="ddoc dlang">
+ <div class="content_wrapper">
+ <article class="module">
+ <h1 class="module_name">$(TITLE)</h1>
+ <section id="module_content">$(BODY)</section>
+ </article>
+ </div>
+ </body>
+</html>$(LF)
+
+DDOC_MODULE_MEMBERS = <section class="section ddoc_module_members_section">
+ <div class="ddoc_module_members">
+ $(DDOC_MEMBERS $0)
+ </div>
+</section>$(LF)
+
+DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)$(LF)
+DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)$(LF)
+DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)$(LF)
+DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)$(LF)
+
+DDOC_MEMBERS = <ul class="ddoc_members">
+ $0
+</ul>
+
+DDOC_MEMBER = <li class="ddoc_member">
+ $0
+</li>
+
+DDOC_MEMBER_HEADER = <div class="ddoc_member_header">
+ $0
+</div>
+
+DDOC_HEADER_ANCHOR = <div class="ddoc_header_anchor">
+ <a href="#$1" id="$1"><code class="code">$2</code></a>
+</div>
+
+DDOC_DECL = <div class="ddoc_decl">
+ <section class="section">
+ <div class="declaration">
+ <h4>Declaration</h4>
+ <div class="dlang">
+ <p class="para">
+ <code class="code">
+ $0
+ </code>
+ </p>
+ </div>
+ </div>
+ </section>
+</div>
+
+DDOC_ANCHOR = <span class="ddoc_anchor" id="$1"></span>
+
+DDOC_DECL_DD = <div class="ddoc_decl">
+ $0
+</div>
+
+DDOC_SECTIONS = <section class="section ddoc_sections">
+ $0
+</section>$(LF)
+
+DDOC_SUMMARY = <div class="ddoc_summary">
+ <p class="para">
+ $0
+ </p>
+</div>$(LF)
+
+DDOC_DESCRIPTION = <div class="ddoc_description">
+ <h4>Discussion</h4>
+ <p class="para">
+ $0
+ </p>
+</div>$(LF)
+
+DDOC_EXAMPLES = <div class="ddoc_examples">
+ <h4>Examples</h4>
+ <p class="para">
+ $0
+ </p>
+</div>
+
+DDOC_RETURNS = <div class="ddoc_returns">
+ <h4>Return Value</h4>
+ <p class="para">
+ $0
+ </p>
+</div>$(LF)
+
+DDOC_PARAMS = <div class="ddoc_params">
+ <h4>Parameters</h4>
+ <table cellspacing="0" cellpadding="5" border="0" class="graybox">
+ <tbody>
+ $0
+ </tbody>
+ </table>
+</div>$(LF)
+
+DDOC_PARAM_ROW = <tr class="ddoc_param_row">
+ $0
+</tr>$(LF)
+
+DDOC_PARAM_ID = <td scope="ddoc_param_id">
+ <code class="code">
+ <em class="term">$0</em>
+ </code>
+</td>$(LF)
+
+DDOC_PARAM_DESC = <td>
+ <div class="ddoc_param_desc">
+ <p class="para">
+ $0
+ </p>
+ </div>
+</td>
+
+DDOC_LICENSE = <div class="ddoc_license">
+ <h4>License</h4>
+ <p class="para">
+ $0
+ </p>
+</div>$(LF)
+
+DDOC_AUTHORS = <div class="ddoc_authors">
+ <h4>Authors</h4>
+ <p class="para">
+ $0
+ </p>
+</div>$(LF)
+
+DDOC_BUGS = <div class="ddoc_bugs">
+ <h4>Bugs</h4>
+ <p class="para">
+ $0
+ </p>
+</div>$(LF)
+
+DDOC_COPYRIGHT = <div class="ddoc_copyright">
+ <h4>Copyright</h4>
+ <p class="para">
+ $0
+ </p>
+</div>$(LF)
+
+DDOC_DATE = <div class="ddoc_date">
+ <h4>Date</h4>
+ <p class="para">
+ $0
+ </p>
+</div>$(LF)
+
+DDOC_DEPRECATED = <div class="ddoc_deprecated">
+ <h4>Deprecated</h4>
+ <p class="para">
+ $0
+ </p>
+</div>$(LF)
+
+DDOC_HISTORY = <div class="ddoc_history">
+ <h4>History</h4>
+ <p class="para">
+ $0
+ </p>
+</div>$(LF)
+
+DDOC_SEE_ALSO = <div class="ddoc_see_also">
+ <h4>See Also</h4>
+ <p class="para">
+ $0
+ </p>
+</div>$(LF)
+
+DDOC_STANDARDS = <div class="ddoc_standards">
+ <h4>Standards</h4>
+ <p class="para">
+ $0
+ </p>
+</div>
+
+DDOC_THROWS = <div class="ddoc_throws">
+ <h4>Throws</h4>
+ <p class="para">
+ $0
+ </p>
+</div>
+
+DDOC_VERSION = <div class="ddoc_version">
+ <h4>Version</h4>
+ <p class="para">
+ $0
+ </p>
+</div>
+
+DDOC_SECTION = <div class="ddoc_section">
+ <p class="para">
+ $0
+ </p>
+</div>$(LF)
+
+DDOC_SECTION_H = <span class="ddoc_section_h">$0:</span>$(LF)
+
+DDOC_DITTO = <br>
+$0
+
+DDOC_PSYMBOL = <code class="code">$0</code>
+DDOC_ENUM_BASETYPE = $0
+DDOC_PSUPER_SYMBOL = <span class="ddoc_psuper_symbol">$0</span>
+DDOC_KEYWORD = <code class="code">$0</code>
+DDOC_PARAM = <code class="code">$0</code>
+DDOC_CONSTRAINT = $(DDOC_CONSTRAINT) if ($0)
+DDOC_OVERLOAD_SEPARATOR = $0
+DDOC_TEMPLATE_PARAM_LIST = $0
+DDOC_TEMPLATE_PARAM = $0
+DDOC_LINK_AUTODETECT = $(LINK $0)
+DDOC_AUTO_PSYMBOL = $(DDOC_PSYMBOL $0)
+DDOC_AUTO_KEYWORD = $(DDOC_KEYWORD $0)
+DDOC_AUTO_PARAM = $(DDOC_PARAM $0)
+DDOC_AUTO_PSYMBOL_SUPPRESS = $0
diff --git a/gcc/d/dmd/root/README.md b/gcc/d/dmd/root/README.md
new file mode 100644
index 0000000..539b940
--- /dev/null
+++ b/gcc/d/dmd/root/README.md
@@ -0,0 +1,23 @@
+# Table of contents
+
+| File | Purpose |
+|--------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
+| [aav.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/aav.d) | An associative array implementation |
+| [array.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/array.d) | A dynamic array implementation |
+| [bitarray.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/bitarray.d) | A compact array of bits |
+| [ctfloat.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/ctfloat.d) | A floating point type for compile-time calculations |
+| [file.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/file.d) | Read a file from disk and store it in memory |
+| [filename.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/filename.d) | Encapsulate path and file names |
+| [hash.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/hash.d) | Calculate a hash for a byte array |
+| [longdouble.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/longdouble.d) | 80-bit floating point number implementation in case they are not natively supported |
+| [man.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/man.d) | Opens an online manual page |
+| [outbuffer.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.d) | An expandable buffer in which you can write text or binary data. |
+| [port.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/port.d) | Portable routines for functions that have different implementations on different platforms |
+| [region.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/region.d) | A region allocator |
+| [response.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/response.d) | Parse command line arguments from response files |
+| [rmem.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/rmem.d) | Allocate memory using `malloc` or the GC depending on the configuration |
+| [rootobject.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/rootobject.d) | A root object that classes in dmd inherit from |
+| [speller.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/speller.d) | Try to detect typos in identifiers |
+| [string.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/string.d) | Various string related functions |
+| [stringtable.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/stringtable.d) | Specialized associative array with string keys stored in a variable length structure |
+| [strtold.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/strtold.d) | D implementation of the standard C function `strtold` (String to long double) |
diff --git a/gcc/d/dmd/root/aav.c b/gcc/d/dmd/root/aav.c
deleted file mode 100644
index 992a117..0000000
--- a/gcc/d/dmd/root/aav.c
+++ /dev/null
@@ -1,171 +0,0 @@
-
-/* Copyright (C) 2010-2021 by The D Language Foundation, All Rights Reserved
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
- * https://github.com/D-Programming-Language/dmd/blob/master/src/root/aav.c
- */
-
-/**
- * Implementation of associative arrays.
- *
- */
-
-#include "dsystem.h"
-#include "aav.h"
-#include "rmem.h"
-
-
-inline size_t hash(size_t a)
-{
- a ^= (a >> 20) ^ (a >> 12);
- return a ^ (a >> 7) ^ (a >> 4);
-}
-
-struct aaA
-{
- aaA *next;
- Key key;
- Value value;
-};
-
-struct AA
-{
- aaA* *b;
- size_t b_length;
- size_t nodes; // total number of aaA nodes
- aaA* binit[4]; // initial value of b[]
-
- aaA aafirst; // a lot of these AA's have only one entry
-};
-
-/****************************************************
- * Determine number of entries in associative array.
- */
-
-size_t dmd_aaLen(AA* aa)
-{
- return aa ? aa->nodes : 0;
-}
-
-
-/*************************************************
- * Get pointer to value in associative array indexed by key.
- * Add entry for key if it is not already there, returning a pointer to a null Value.
- * Create the associative array if it does not already exist.
- */
-
-Value* dmd_aaGet(AA** paa, Key key)
-{
- //printf("paa = %p\n", paa);
-
- if (!*paa)
- { AA *a = (AA *)mem.xmalloc(sizeof(AA));
- a->b = (aaA**)a->binit;
- a->b_length = 4;
- a->nodes = 0;
- a->binit[0] = NULL;
- a->binit[1] = NULL;
- a->binit[2] = NULL;
- a->binit[3] = NULL;
- *paa = a;
- assert((*paa)->b_length == 4);
- }
- //printf("paa = %p, *paa = %p\n", paa, *paa);
-
- assert((*paa)->b_length);
- size_t i = hash((size_t)key) & ((*paa)->b_length - 1);
- aaA** pe = &(*paa)->b[i];
- aaA *e;
- while ((e = *pe) != NULL)
- {
- if (key == e->key)
- return &e->value;
- pe = &e->next;
- }
-
- // Not found, create new elem
- //printf("create new one\n");
-
- size_t nodes = ++(*paa)->nodes;
- e = (nodes != 1) ? (aaA *)mem.xmalloc(sizeof(aaA)) : &(*paa)->aafirst;
- //e = new aaA();
- e->next = NULL;
- e->key = key;
- e->value = NULL;
- *pe = e;
-
- //printf("length = %d, nodes = %d\n", (*paa)->b_length, nodes);
- if (nodes > (*paa)->b_length * 2)
- {
- //printf("rehash\n");
- dmd_aaRehash(paa);
- }
-
- return &e->value;
-}
-
-
-/*************************************************
- * Get value in associative array indexed by key.
- * Returns NULL if it is not already there.
- */
-
-Value dmd_aaGetRvalue(AA* aa, Key key)
-{
- //printf("_aaGetRvalue(key = %p)\n", key);
- if (aa)
- {
- size_t i;
- size_t len = aa->b_length;
- i = hash((size_t)key) & (len-1);
- aaA* e = aa->b[i];
- while (e)
- {
- if (key == e->key)
- return e->value;
- e = e->next;
- }
- }
- return NULL; // not found
-}
-
-
-/********************************************
- * Rehash an array.
- */
-
-void dmd_aaRehash(AA** paa)
-{
- //printf("Rehash\n");
- if (*paa)
- {
- AA *aa = *paa;
- if (aa)
- {
- size_t len = aa->b_length;
- if (len == 4)
- len = 32;
- else
- len *= 4;
- aaA** newb = (aaA**)mem.xmalloc(sizeof(aaA)*len);
- memset(newb, 0, len * sizeof(aaA*));
-
- for (size_t k = 0; k < aa->b_length; k++)
- { aaA *e = aa->b[k];
- while (e)
- { aaA* enext = e->next;
- size_t j = hash((size_t)e->key) & (len-1);
- e->next = newb[j];
- newb[j] = e;
- e = enext;
- }
- }
- if (aa->b != (aaA**)aa->binit)
- mem.xfree(aa->b);
-
- aa->b = newb;
- aa->b_length = len;
- }
- }
-}
diff --git a/gcc/d/dmd/root/aav.d b/gcc/d/dmd/root/aav.d
new file mode 100644
index 0000000..92b58ba
--- /dev/null
+++ b/gcc/d/dmd/root/aav.d
@@ -0,0 +1,339 @@
+/**
+ * Associative array implementation.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/aav.d, root/_aav.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_aav.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/aav.d
+ */
+
+module dmd.root.aav;
+
+import core.stdc.string;
+import dmd.root.rmem;
+
+private size_t hash(size_t a) pure nothrow @nogc @safe
+{
+ a ^= (a >> 20) ^ (a >> 12);
+ return a ^ (a >> 7) ^ (a >> 4);
+}
+
+struct KeyValueTemplate(K,V)
+{
+ K key;
+ V value;
+}
+
+alias Key = void*;
+alias Value = void*;
+
+alias KeyValue = KeyValueTemplate!(Key, Value);
+
+struct aaA
+{
+ aaA* next;
+ KeyValue keyValue;
+ alias keyValue this;
+}
+
+struct AA
+{
+ aaA** b;
+ size_t b_length;
+ size_t nodes; // total number of aaA nodes
+ aaA*[4] binit; // initial value of b[]
+ aaA aafirst; // a lot of these AA's have only one entry
+}
+
+/****************************************************
+ * Determine number of entries in associative array.
+ */
+private size_t dmd_aaLen(const AA* aa) pure nothrow @nogc @safe
+{
+ return aa ? aa.nodes : 0;
+}
+
+/*************************************************
+ * Get pointer to value in associative array indexed by key.
+ * Add entry for key if it is not already there, returning a pointer to a null Value.
+ * Create the associative array if it does not already exist.
+ */
+private Value* dmd_aaGet(AA** paa, Key key) pure nothrow
+{
+ //printf("paa = %p\n", paa);
+ if (!*paa)
+ {
+ AA* a = cast(AA*)mem.xmalloc(AA.sizeof);
+ a.b = cast(aaA**)a.binit;
+ a.b_length = 4;
+ a.nodes = 0;
+ a.binit[0] = null;
+ a.binit[1] = null;
+ a.binit[2] = null;
+ a.binit[3] = null;
+ *paa = a;
+ assert((*paa).b_length == 4);
+ }
+ //printf("paa = %p, *paa = %p\n", paa, *paa);
+ assert((*paa).b_length);
+ size_t i = hash(cast(size_t)key) & ((*paa).b_length - 1);
+ aaA** pe = &(*paa).b[i];
+ aaA* e;
+ while ((e = *pe) !is null)
+ {
+ if (key == e.key)
+ return &e.value;
+ pe = &e.next;
+ }
+ // Not found, create new elem
+ //printf("create new one\n");
+ size_t nodes = ++(*paa).nodes;
+ e = (nodes != 1) ? cast(aaA*)mem.xmalloc(aaA.sizeof) : &(*paa).aafirst;
+ //e = new aaA();
+ e.next = null;
+ e.key = key;
+ e.value = null;
+ *pe = e;
+ //printf("length = %d, nodes = %d\n", (*paa)->b_length, nodes);
+ if (nodes > (*paa).b_length * 2)
+ {
+ //printf("rehash\n");
+ dmd_aaRehash(paa);
+ }
+ return &e.value;
+}
+
+/*************************************************
+ * Get value in associative array indexed by key.
+ * Returns NULL if it is not already there.
+ */
+private Value dmd_aaGetRvalue(AA* aa, Key key) pure nothrow @nogc
+{
+ //printf("_aaGetRvalue(key = %p)\n", key);
+ if (aa)
+ {
+ size_t i;
+ size_t len = aa.b_length;
+ i = hash(cast(size_t)key) & (len - 1);
+ aaA* e = aa.b[i];
+ while (e)
+ {
+ if (key == e.key)
+ return e.value;
+ e = e.next;
+ }
+ }
+ return null; // not found
+}
+
+/**
+Gets a range of key/values for `aa`.
+
+Returns: a range of key/values for `aa`.
+*/
+@property auto asRange(AA* aa) pure nothrow @nogc
+{
+ return AARange!(Key, Value)(aa);
+}
+
+private struct AARange(K,V)
+{
+ AA* aa;
+ // current index into bucket array `aa.b`
+ size_t bIndex;
+ aaA* current;
+
+ this(AA* aa) pure nothrow @nogc
+ {
+ if (aa)
+ {
+ this.aa = aa;
+ toNext();
+ }
+ }
+
+ @property bool empty() const pure nothrow @nogc @safe
+ {
+ return current is null;
+ }
+
+ @property auto front() const pure nothrow @nogc
+ {
+ return cast(KeyValueTemplate!(K,V))current.keyValue;
+ }
+
+ void popFront() pure nothrow @nogc
+ {
+ if (current.next)
+ current = current.next;
+ else
+ {
+ bIndex++;
+ toNext();
+ }
+ }
+
+ private void toNext() pure nothrow @nogc
+ {
+ for (; bIndex < aa.b_length; bIndex++)
+ {
+ if (auto next = aa.b[bIndex])
+ {
+ current = next;
+ return;
+ }
+ }
+ current = null;
+ }
+}
+
+unittest
+{
+ AA* aa = null;
+ foreach(keyValue; aa.asRange)
+ assert(0);
+
+ enum totalKeyLength = 50;
+ foreach (i; 1 .. totalKeyLength + 1)
+ {
+ auto key = cast(void*)i;
+ {
+ auto valuePtr = dmd_aaGet(&aa, key);
+ assert(valuePtr);
+ *valuePtr = key;
+ }
+ bool[totalKeyLength] found;
+ size_t rangeCount = 0;
+ foreach (keyValue; aa.asRange)
+ {
+ assert(keyValue.key <= key);
+ assert(keyValue.key == keyValue.value);
+ rangeCount++;
+ assert(!found[cast(size_t)keyValue.key - 1]);
+ found[cast(size_t)keyValue.key - 1] = true;
+ }
+ assert(rangeCount == i);
+ }
+}
+
+/********************************************
+ * Rehash an array.
+ */
+private void dmd_aaRehash(AA** paa) pure nothrow
+{
+ //printf("Rehash\n");
+ if (*paa)
+ {
+ AA* aa = *paa;
+ if (aa)
+ {
+ size_t len = aa.b_length;
+ if (len == 4)
+ len = 32;
+ else
+ len *= 4;
+ aaA** newb = cast(aaA**)mem.xmalloc(aaA.sizeof * len);
+ memset(newb, 0, len * (aaA*).sizeof);
+ for (size_t k = 0; k < aa.b_length; k++)
+ {
+ aaA* e = aa.b[k];
+ while (e)
+ {
+ aaA* enext = e.next;
+ size_t j = hash(cast(size_t)e.key) & (len - 1);
+ e.next = newb[j];
+ newb[j] = e;
+ e = enext;
+ }
+ }
+ if (aa.b != cast(aaA**)aa.binit)
+ mem.xfree(aa.b);
+ aa.b = newb;
+ aa.b_length = len;
+ }
+ }
+}
+
+unittest
+{
+ AA* aa = null;
+ Value v = dmd_aaGetRvalue(aa, null);
+ assert(!v);
+ Value* pv = dmd_aaGet(&aa, null);
+ assert(pv);
+ *pv = cast(void*)3;
+ v = dmd_aaGetRvalue(aa, null);
+ assert(v == cast(void*)3);
+}
+
+struct AssocArray(K,V)
+{
+ private AA* aa;
+
+ /**
+ Returns: The number of key/value pairs.
+ */
+ @property size_t length() const pure nothrow @nogc @safe
+ {
+ return dmd_aaLen(aa);
+ }
+
+ /**
+ Lookup value associated with `key` and return the address to it. If the `key`
+ has not been added, it adds it and returns the address to the new value.
+
+ Params:
+ key = key to lookup the value for
+
+ Returns: the address to the value associated with `key`. If `key` does not exist, it
+ is added and the address to the new value is returned.
+ */
+ V* getLvalue(const(K) key) pure nothrow
+ {
+ return cast(V*)dmd_aaGet(&aa, cast(void*)key);
+ }
+
+ /**
+ Lookup and return the value associated with `key`, if the `key` has not been
+ added, it returns null.
+
+ Params:
+ key = key to lookup the value for
+
+ Returns: the value associated with `key` if present, otherwise, null.
+ */
+ V opIndex(const(K) key) pure nothrow @nogc
+ {
+ return cast(V)dmd_aaGetRvalue(aa, cast(void*)key);
+ }
+
+ /**
+ Gets a range of key/values for `aa`.
+
+ Returns: a range of key/values for `aa`.
+ */
+ @property auto asRange() pure nothrow @nogc
+ {
+ return AARange!(K,V)(aa);
+ }
+}
+
+///
+unittest
+{
+ auto foo = new Object();
+ auto bar = new Object();
+
+ AssocArray!(Object, Object) aa;
+
+ assert(aa[foo] is null);
+ assert(aa.length == 0);
+
+ auto fooValuePtr = aa.getLvalue(foo);
+ *fooValuePtr = bar;
+
+ assert(aa[foo] is bar);
+ assert(aa.length == 1);
+}
diff --git a/gcc/d/dmd/root/array.d b/gcc/d/dmd/root/array.d
new file mode 100644
index 0000000..ed925c8
--- /dev/null
+++ b/gcc/d/dmd/root/array.d
@@ -0,0 +1,1121 @@
+
+/**
+ * Dynamic array implementation.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/array.d, root/_array.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_array.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/array.d
+ */
+
+module dmd.root.array;
+
+import core.stdc.stdlib : _compare_fp_t;
+import core.stdc.string;
+
+import dmd.root.rmem;
+import dmd.root.string;
+
+// `qsort` is only `nothrow` since 2.081.0
+private extern(C) void qsort(scope void* base, size_t nmemb, size_t size, _compare_fp_t compar) nothrow @nogc;
+
+
+debug
+{
+ debug = stomp; // flush out dangling pointer problems by stomping on unused memory
+}
+
+extern (C++) struct Array(T)
+{
+ size_t length;
+
+private:
+ T[] data;
+ enum SMALLARRAYCAP = 1;
+ T[SMALLARRAYCAP] smallarray; // inline storage for small arrays
+
+public:
+ /*******************
+ * Params:
+ * dim = initial length of array
+ */
+ this(size_t dim) pure nothrow
+ {
+ reserve(dim);
+ this.length = dim;
+ }
+
+ @disable this(this);
+
+ ~this() pure nothrow
+ {
+ debug (stomp) memset(data.ptr, 0xFF, data.length);
+ if (data.ptr != &smallarray[0])
+ mem.xfree(data.ptr);
+ }
+ ///returns elements comma separated in []
+ extern(D) const(char)[] toString() const
+ {
+ static const(char)[] toStringImpl(alias toStringFunc, Array)(Array* a, bool quoted = false)
+ {
+ const(char)[][] buf = (cast(const(char)[]*)mem.xcalloc((char[]).sizeof, a.length))[0 .. a.length];
+ size_t len = 2; // [ and ]
+ const seplen = quoted ? 3 : 1; // ',' or null terminator and optionally '"'
+ if (a.length == 0)
+ len += 1; // null terminator
+ else
+ {
+ foreach (u; 0 .. a.length)
+ {
+ buf[u] = toStringFunc(a.data[u]);
+ len += buf[u].length + seplen;
+ }
+ }
+ char[] str = (cast(char*)mem.xmalloc_noscan(len))[0..len];
+
+ str[0] = '[';
+ char* p = str.ptr + 1;
+ foreach (u; 0 .. a.length)
+ {
+ if (u)
+ *p++ = ',';
+ if (quoted)
+ *p++ = '"';
+ memcpy(p, buf[u].ptr, buf[u].length);
+ p += buf[u].length;
+ if (quoted)
+ *p++ = '"';
+ }
+ *p++ = ']';
+ *p = 0;
+ assert(p - str.ptr == str.length - 1); // null terminator
+ mem.xfree(buf.ptr);
+ return str[0 .. $-1];
+ }
+
+ static if (is(typeof(T.init.toString())))
+ {
+ return toStringImpl!(a => a.toString)(&this);
+ }
+ else static if (is(typeof(T.init.toDString())))
+ {
+ return toStringImpl!(a => a.toDString)(&this, true);
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+ ///ditto
+ const(char)* toChars() const
+ {
+ return toString.ptr;
+ }
+
+ ref Array push(T ptr) return pure nothrow
+ {
+ reserve(1);
+ data[length++] = ptr;
+ return this;
+ }
+
+ extern (D) ref Array pushSlice(T[] a) return pure nothrow
+ {
+ const oldLength = length;
+ setDim(oldLength + a.length);
+ memcpy(data.ptr + oldLength, a.ptr, a.length * T.sizeof);
+ return this;
+ }
+
+ ref Array append(typeof(this)* a) return pure nothrow
+ {
+ insert(length, a);
+ return this;
+ }
+
+ void reserve(size_t nentries) pure nothrow
+ {
+ //printf("Array::reserve: length = %d, data.length = %d, nentries = %d\n", (int)length, (int)data.length, (int)nentries);
+
+ // Cold path
+ void enlarge(size_t nentries)
+ {
+ pragma(inline, false); // never inline cold path
+ if (data.length == 0)
+ {
+ // Not properly initialized, someone memset it to zero
+ if (nentries <= SMALLARRAYCAP)
+ {
+ data = SMALLARRAYCAP ? smallarray[] : null;
+ }
+ else
+ {
+ auto p = cast(T*)mem.xmalloc(nentries * T.sizeof);
+ data = p[0 .. nentries];
+ }
+ }
+ else if (data.length == SMALLARRAYCAP)
+ {
+ const allocdim = length + nentries;
+ auto p = cast(T*)mem.xmalloc(allocdim * T.sizeof);
+ memcpy(p, smallarray.ptr, length * T.sizeof);
+ data = p[0 .. allocdim];
+ }
+ else
+ {
+ /* Increase size by 1.5x to avoid excessive memory fragmentation
+ */
+ auto increment = length / 2;
+ if (nentries > increment) // if 1.5 is not enough
+ increment = nentries;
+ const allocdim = length + increment;
+ debug (stomp)
+ {
+ // always move using allocate-copy-stomp-free
+ auto p = cast(T*)mem.xmalloc(allocdim * T.sizeof);
+ memcpy(p, data.ptr, length * T.sizeof);
+ memset(data.ptr, 0xFF, data.length * T.sizeof);
+ mem.xfree(data.ptr);
+ }
+ else
+ auto p = cast(T*)mem.xrealloc(data.ptr, allocdim * T.sizeof);
+ data = p[0 .. allocdim];
+ }
+
+ debug (stomp)
+ {
+ if (length < data.length)
+ memset(data.ptr + length, 0xFF, (data.length - length) * T.sizeof);
+ }
+ else
+ {
+ if (mem.isGCEnabled)
+ if (length < data.length)
+ memset(data.ptr + length, 0xFF, (data.length - length) * T.sizeof);
+ }
+ }
+
+ if (data.length - length < nentries) // false means hot path
+ enlarge(nentries);
+ }
+
+ void remove(size_t i) pure nothrow @nogc
+ {
+ if (length - i - 1)
+ memmove(data.ptr + i, data.ptr + i + 1, (length - i - 1) * T.sizeof);
+ length--;
+ debug (stomp) memset(data.ptr + length, 0xFF, T.sizeof);
+ }
+
+ void insert(size_t index, typeof(this)* a) pure nothrow
+ {
+ if (a)
+ {
+ size_t d = a.length;
+ reserve(d);
+ if (length != index)
+ memmove(data.ptr + index + d, data.ptr + index, (length - index) * T.sizeof);
+ memcpy(data.ptr + index, a.data.ptr, d * T.sizeof);
+ length += d;
+ }
+ }
+
+ void insert(size_t index, T ptr) pure nothrow
+ {
+ reserve(1);
+ memmove(data.ptr + index + 1, data.ptr + index, (length - index) * T.sizeof);
+ data[index] = ptr;
+ length++;
+ }
+
+ void setDim(size_t newdim) pure nothrow
+ {
+ if (length < newdim)
+ {
+ reserve(newdim - length);
+ }
+ length = newdim;
+ }
+
+ size_t find(T ptr) const nothrow pure
+ {
+ foreach (i; 0 .. length)
+ if (data[i] is ptr)
+ return i;
+ return size_t.max;
+ }
+
+ bool contains(T ptr) const nothrow pure
+ {
+ return find(ptr) != size_t.max;
+ }
+
+ ref inout(T) opIndex(size_t i) inout nothrow pure
+ {
+ debug
+ // This is called so often the array bounds become expensive
+ return data[i];
+ else
+ return data.ptr[i];
+ }
+
+ inout(T)* tdata() inout pure nothrow @nogc @trusted
+ {
+ return data.ptr;
+ }
+
+ Array!T* copy() const pure nothrow
+ {
+ auto a = new Array!T();
+ a.setDim(length);
+ memcpy(a.data.ptr, data.ptr, length * T.sizeof);
+ return a;
+ }
+
+ void shift(T ptr) pure nothrow
+ {
+ reserve(1);
+ memmove(data.ptr + 1, data.ptr, length * T.sizeof);
+ data[0] = ptr;
+ length++;
+ }
+
+ void zero() nothrow pure @nogc
+ {
+ data[0 .. length] = T.init;
+ }
+
+ T pop() nothrow pure @nogc
+ {
+ debug (stomp)
+ {
+ assert(length);
+ auto result = data[length - 1];
+ remove(length - 1);
+ return result;
+ }
+ else
+ return data[--length];
+ }
+
+ extern (D) inout(T)[] opSlice() inout nothrow pure @nogc
+ {
+ return data[0 .. length];
+ }
+
+ extern (D) inout(T)[] opSlice(size_t a, size_t b) inout nothrow pure @nogc
+ {
+ assert(a <= b && b <= length);
+ return data[a .. b];
+ }
+
+ /**
+ * Sort the elements of an array
+ *
+ * This function relies on `qsort`.
+ *
+ * Params:
+ * pred = Predicate to use. Should be a function of type
+ * `int function(scope const T* e1, scope const T* e2) nothrow`.
+ * The return value of this function should follow the
+ * usual C rule: `e1 >= e2 ? (e1 > e2) : -1`.
+ * The function can have D linkage.
+ *
+ * Returns:
+ * A reference to this, for easy chaining.
+ */
+ extern(D) ref typeof(this) sort (alias pred) () nothrow
+ {
+ if (this.length < 2)
+ return this;
+ qsort(this.data.ptr, this.length, T.sizeof, &arraySortWrapper!(T, pred));
+ return this;
+ }
+
+ /// Ditto, but use `opCmp` by default
+ extern(D) ref typeof(this) sort () () nothrow
+ if (is(typeof(this.data[0].opCmp(this.data[1])) : int))
+ {
+ return this.sort!(function (scope const(T)* pe1, scope const(T)* pe2) => pe1.opCmp(*pe2));
+ }
+
+ alias opDollar = length;
+ alias dim = length;
+}
+
+unittest
+{
+ // Test for objects implementing toString()
+ static struct S
+ {
+ int s = -1;
+ string toString() const
+ {
+ return "S";
+ }
+ }
+ auto array = Array!S(4);
+ assert(array.toString() == "[S,S,S,S]");
+ array.setDim(0);
+ assert(array.toString() == "[]");
+
+ // Test for toDString()
+ auto strarray = Array!(const(char)*)(2);
+ strarray[0] = "hello";
+ strarray[1] = "world";
+ auto str = strarray.toString();
+ assert(str == `["hello","world"]`);
+ // Test presence of null terminator.
+ assert(str.ptr[str.length] == '\0');
+}
+
+unittest
+{
+ auto array = Array!double(4);
+ array.shift(10);
+ array.push(20);
+ array[2] = 15;
+ assert(array[0] == 10);
+ assert(array.find(10) == 0);
+ assert(array.find(20) == 5);
+ assert(!array.contains(99));
+ array.remove(1);
+ assert(array.length == 5);
+ assert(array[1] == 15);
+ assert(array.pop() == 20);
+ assert(array.length == 4);
+ array.insert(1, 30);
+ assert(array[1] == 30);
+ assert(array[2] == 15);
+}
+
+unittest
+{
+ auto arrayA = Array!int(0);
+ int[3] buf = [10, 15, 20];
+ arrayA.pushSlice(buf);
+ assert(arrayA[] == buf[]);
+ auto arrayPtr = arrayA.copy();
+ assert(arrayPtr);
+ assert((*arrayPtr)[] == arrayA[]);
+ assert(arrayPtr.tdata != arrayA.tdata);
+
+ arrayPtr.setDim(0);
+ int[2] buf2 = [100, 200];
+ arrayPtr.pushSlice(buf2);
+
+ arrayA.append(arrayPtr);
+ assert(arrayA[3..$] == buf2[]);
+ arrayA.insert(0, arrayPtr);
+ assert(arrayA[] == [100, 200, 10, 15, 20, 100, 200]);
+
+ arrayA.zero();
+ foreach(e; arrayA)
+ assert(e == 0);
+}
+
+/**
+ * Exposes the given root Array as a standard D array.
+ * Params:
+ * array = the array to expose.
+ * Returns:
+ * The given array exposed to a standard D array.
+ */
+@property inout(T)[] peekSlice(T)(inout(Array!T)* array) pure nothrow @nogc
+{
+ return array ? (*array)[] : null;
+}
+
+/**
+ * Splits the array at $(D index) and expands it to make room for $(D length)
+ * elements by shifting everything past $(D index) to the right.
+ * Params:
+ * array = the array to split.
+ * index = the index to split the array from.
+ * length = the number of elements to make room for starting at $(D index).
+ */
+void split(T)(ref Array!T array, size_t index, size_t length) pure nothrow
+{
+ if (length > 0)
+ {
+ auto previousDim = array.length;
+ array.setDim(array.length + length);
+ for (size_t i = previousDim; i > index;)
+ {
+ i--;
+ array[i + length] = array[i];
+ }
+ }
+}
+unittest
+{
+ auto array = Array!int();
+ array.split(0, 0);
+ assert([] == array[]);
+ array.push(1).push(3);
+ array.split(1, 1);
+ array[1] = 2;
+ assert([1, 2, 3] == array[]);
+ array.split(2, 3);
+ array[2] = 8;
+ array[3] = 20;
+ array[4] = 4;
+ assert([1, 2, 8, 20, 4, 3] == array[]);
+ array.split(0, 0);
+ assert([1, 2, 8, 20, 4, 3] == array[]);
+ array.split(0, 1);
+ array[0] = 123;
+ assert([123, 1, 2, 8, 20, 4, 3] == array[]);
+ array.split(0, 3);
+ array[0] = 123;
+ array[1] = 421;
+ array[2] = 910;
+ assert([123, 421, 910, 123, 1, 2, 8, 20, 4, 3] == (&array).peekSlice());
+}
+
+/**
+ * Reverse an array in-place.
+ * Params:
+ * a = array
+ * Returns:
+ * reversed a[]
+ */
+T[] reverse(T)(T[] a) pure nothrow @nogc @safe
+{
+ if (a.length > 1)
+ {
+ const mid = (a.length + 1) >> 1;
+ foreach (i; 0 .. mid)
+ {
+ T e = a[i];
+ a[i] = a[$ - 1 - i];
+ a[$ - 1 - i] = e;
+ }
+ }
+ return a;
+}
+
+unittest
+{
+ int[] a1 = [];
+ assert(reverse(a1) == []);
+ int[] a2 = [2];
+ assert(reverse(a2) == [2]);
+ int[] a3 = [2,3];
+ assert(reverse(a3) == [3,2]);
+ int[] a4 = [2,3,4];
+ assert(reverse(a4) == [4,3,2]);
+ int[] a5 = [2,3,4,5];
+ assert(reverse(a5) == [5,4,3,2]);
+}
+
+unittest
+{
+ //test toString/toChars. Identifier is a simple object that has a usable .toString
+ import dmd.identifier : Identifier;
+ import core.stdc.string : strcmp;
+
+ auto array = Array!Identifier();
+ array.push(new Identifier("id1"));
+ array.push(new Identifier("id2"));
+
+ string expected = "[id1,id2]";
+ assert(array.toString == expected);
+ assert(strcmp(array.toChars, expected.ptr) == 0);
+}
+
+/// Predicate to wrap a D function passed to `qsort`
+private template arraySortWrapper(T, alias fn)
+{
+ pragma(mangle, "arraySortWrapper_" ~ T.mangleof ~ "_" ~ fn.mangleof)
+ extern(C) int arraySortWrapper(scope const void* e1, scope const void* e2) nothrow
+ {
+ return fn(cast(const(T*))e1, cast(const(T*))e2);
+ }
+}
+
+// Test sorting
+unittest
+{
+ Array!(const(char)*) strings;
+ strings.push("World");
+ strings.push("Foo");
+ strings.push("baguette");
+ strings.push("Avocado");
+ strings.push("Hello");
+ // Newer frontend versions will work with (e1, e2) and infer the type
+ strings.sort!(function (scope const char** e1, scope const char** e2) => strcmp(*e1, *e2));
+ assert(strings[0] == "Avocado");
+ assert(strings[1] == "Foo");
+ assert(strings[2] == "Hello");
+ assert(strings[3] == "World");
+ assert(strings[4] == "baguette");
+
+ /// opCmp automatically supported
+ static struct MyStruct
+ {
+ int a;
+
+ int opCmp(const ref MyStruct other) const nothrow
+ {
+ // Reverse order
+ return other.a - this.a;
+ }
+ }
+
+ Array!MyStruct arr1;
+ arr1.push(MyStruct(2));
+ arr1.push(MyStruct(4));
+ arr1.push(MyStruct(256));
+ arr1.push(MyStruct(42));
+ arr1.sort();
+ assert(arr1[0].a == 256);
+ assert(arr1[1].a == 42);
+ assert(arr1[2].a == 4);
+ assert(arr1[3].a == 2);
+
+ /// But only if user defined
+ static struct OtherStruct
+ {
+ int a;
+
+ static int pred (scope const OtherStruct* pe1, scope const OtherStruct* pe2)
+ nothrow @nogc pure @safe
+ {
+ return pe1.a - pe2.a;
+ }
+ }
+
+ static assert (!is(typeof(Array!(OtherStruct).init.sort())));
+ static assert (!is(typeof(Array!(OtherStruct).init.sort!pred)));
+}
+
+/**
+ * Iterates the given array and calls the given callable for each element.
+ *
+ * Use this instead of `foreach` when the array may expand during iteration.
+ *
+ * Params:
+ * callable = the callable to call for each element
+ * array = the array to iterate
+ *
+ * See_Also: $(REF foreachDsymbol, dmd, dsymbol)
+ */
+template each(alias callable, T)
+if (is(ReturnType!(typeof((T t) => callable(t))) == void))
+{
+ void each(ref Array!T array)
+ {
+ // Do not use foreach, as the size of the array may expand during iteration
+ for (size_t i = 0; i < array.length; ++i)
+ callable(array[i]);
+ }
+
+ void each(Array!T* array)
+ {
+ if (array)
+ each!callable(*array);
+ }
+}
+
+///
+@("iterate over an Array") unittest
+{
+ static immutable expected = [2, 3, 4, 5];
+
+ Array!int array;
+
+ foreach (e ; expected)
+ array.push(e);
+
+ int[] result;
+ array.each!((e) {
+ result ~= e;
+ });
+
+ assert(result == expected);
+}
+
+@("iterate over a pointer to an Array") unittest
+{
+ static immutable expected = [2, 3, 4, 5];
+
+ auto array = new Array!int;
+
+ foreach (e ; expected)
+ array.push(e);
+
+ int[] result;
+ array.each!((e) {
+ result ~= e;
+ });
+
+ assert(result == expected);
+}
+
+@("iterate while appending to the array being iterated") unittest
+{
+ static immutable expected = [2, 3, 4, 5];
+
+ Array!int array;
+
+ foreach (e ; expected[0 .. $ - 1])
+ array.push(e);
+
+ int[] result;
+
+ array.each!((e) {
+ if (e == 2)
+ array.push(5);
+
+ result ~= e;
+ });
+
+ assert(array[] == expected);
+ assert(result == expected);
+}
+
+/**
+ * Iterates the given array and calls the given callable for each element.
+ *
+ * If `callable` returns `!= 0`, it will stop the iteration and return that
+ * value, otherwise it will return 0.
+ *
+ * Use this instead of `foreach` when the array may expand during iteration.
+ *
+ * Params:
+ * callable = the callable to call for each element
+ * array = the array to iterate
+ *
+ * Returns: the last value returned by `callable`
+ * See_Also: $(REF foreachDsymbol, dmd, dsymbol)
+ */
+template each(alias callable, T)
+if (is(ReturnType!(typeof((T t) => callable(t))) == int))
+{
+ int each(ref Array!T array)
+ {
+ // Do not use foreach, as the size of the array may expand during iteration
+ for (size_t i = 0; i < array.length; ++i)
+ {
+ if (const result = callable(array[i]))
+ return result;
+ }
+
+ return 0;
+ }
+
+ int each(Array!T* array)
+ {
+ return array ? each!callable(*array) : 0;
+ }
+}
+
+///
+@("iterate over an Array and stop the iteration") unittest
+{
+ Array!int array;
+
+ foreach (e ; [2, 3, 4, 5])
+ array.push(e);
+
+ int[] result;
+ const returnValue = array.each!((e) {
+ result ~= e;
+
+ if (e == 3)
+ return 8;
+
+ return 0;
+ });
+
+ assert(result == [2, 3]);
+ assert(returnValue == 8);
+}
+
+@("iterate over an Array") unittest
+{
+ static immutable expected = [2, 3, 4, 5];
+
+ Array!int array;
+
+ foreach (e ; expected)
+ array.push(e);
+
+ int[] result;
+ const returnValue = array.each!((e) {
+ result ~= e;
+ return 0;
+ });
+
+ assert(result == expected);
+ assert(returnValue == 0);
+}
+
+@("iterate over a pointer to an Array and stop the iteration") unittest
+{
+ auto array = new Array!int;
+
+ foreach (e ; [2, 3, 4, 5])
+ array.push(e);
+
+ int[] result;
+ const returnValue = array.each!((e) {
+ result ~= e;
+
+ if (e == 3)
+ return 9;
+
+ return 0;
+ });
+
+ assert(result == [2, 3]);
+ assert(returnValue == 9);
+}
+
+@("iterate while appending to the array being iterated and stop the iteration") unittest
+{
+ Array!int array;
+
+ foreach (e ; [2, 3])
+ array.push(e);
+
+ int[] result;
+
+ const returnValue = array.each!((e) {
+ if (e == 2)
+ array.push(1);
+
+ result ~= e;
+
+ if (e == 1)
+ return 7;
+
+ return 0;
+ });
+
+ static immutable expected = [2, 3, 1];
+
+ assert(array[] == expected);
+ assert(result == expected);
+ assert(returnValue == 7);
+}
+
+/// Returns: A static array constructed from `array`.
+pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] array)
+{
+ return array;
+}
+
+///
+pure nothrow @safe @nogc unittest
+{
+ enum a = [0, 1].staticArray;
+ static assert(is(typeof(a) == int[2]));
+ static assert(a == [0, 1]);
+}
+
+/// Returns: `true` if the two given ranges are equal
+bool equal(Range1, Range2)(Range1 range1, Range2 range2)
+{
+ template isArray(T)
+ {
+ static if (is(T U : U[]))
+ enum isArray = true;
+
+ else
+ enum isArray = false;
+ }
+
+ static if (isArray!Range1 && isArray!Range2 && is(typeof(range1 == range2)))
+ return range1 == range2;
+
+ else
+ {
+ static if (hasLength!Range1 && hasLength!Range2 && is(typeof(r1.length == r2.length)))
+ {
+ if (range1.length != range2.length)
+ return false;
+ }
+
+ for (; !range1.empty; range1.popFront(), range2.popFront())
+ {
+ if (range2.empty)
+ return false;
+
+ if (range1.front != range2.front)
+ return false;
+ }
+
+ return range2.empty;
+ }
+}
+
+///
+pure nothrow @nogc @safe unittest
+{
+ enum a = [ 1, 2, 4, 3 ].staticArray;
+ static assert(!equal(a[], a[1..$]));
+ static assert(equal(a[], a[]));
+
+ // different types
+ enum b = [ 1.0, 2, 4, 3].staticArray;
+ static assert(!equal(a[], b[1..$]));
+ static assert(equal(a[], b[]));
+}
+
+pure nothrow @safe unittest
+{
+ static assert(equal([1, 2, 3].map!(x => x * 2), [1, 2, 3].map!(x => x * 2)));
+
+ static assert(!equal([1, 2].map!(x => x * 2), [1, 2, 3].map!(x => x * 2)));
+}
+
+/**
+ * Lazily filters the given range based on the given predicate.
+ *
+ * Returns: a range containing only elements for which the predicate returns
+ * `true`
+ */
+auto filter(alias predicate, Range)(Range range)
+if (isInputRange!(Unqual!Range) && isPredicateOf!(predicate, ElementType!Range))
+{
+ return Filter!(predicate, Range)(range);
+}
+
+///
+pure nothrow @safe @nogc unittest
+{
+ enum a = [1, 2, 3, 4].staticArray;
+ enum result = a[].filter!(e => e > 2);
+
+ enum expected = [3, 4].staticArray;
+ static assert(result.equal(expected[]));
+}
+
+private struct Filter(alias predicate, Range)
+{
+ private Range range;
+ private bool primed;
+
+ private void prime()
+ {
+ if (primed)
+ return;
+
+ while (!range.empty && !predicate(range.front))
+ range.popFront();
+
+ primed = true;
+ }
+
+ @property bool empty()
+ {
+ prime();
+ return range.empty;
+ }
+
+ @property auto front()
+ {
+ assert(!range.empty);
+ prime();
+ return range.front;
+ }
+
+ void popFront()
+ {
+ assert(!range.empty);
+ prime();
+
+ do
+ {
+ range.popFront();
+ } while (!range.empty && !predicate(range.front));
+ }
+
+ auto opSlice()
+ {
+ return this;
+ }
+}
+
+/**
+ * Lazily iterates the given range and calls the given callable for each element.
+ *
+ * Returns: a range containing the result of each call to `callable`
+ */
+auto map(alias callable, Range)(Range range)
+if (isInputRange!(Unqual!Range) && isCallableWith!(callable, ElementType!Range))
+{
+ return Map!(callable, Range)(range);
+}
+
+///
+pure nothrow @safe @nogc unittest
+{
+ enum a = [1, 2, 3, 4].staticArray;
+ enum expected = [2, 4, 6, 8].staticArray;
+
+ enum result = a[].map!(e => e * 2);
+ static assert(result.equal(expected[]));
+}
+
+private struct Map(alias callable, Range)
+{
+ private Range range;
+
+ @property bool empty()
+ {
+ return range.empty;
+ }
+
+ @property auto front()
+ {
+ assert(!range.empty);
+ return callable(range.front);
+ }
+
+ void popFront()
+ {
+ assert(!range.empty);
+ range.popFront();
+ }
+
+ static if (hasLength!Range)
+ {
+ @property auto length()
+ {
+ return range.length;
+ }
+
+ alias opDollar = length;
+ }
+}
+
+/// Returns: the length of the given range.
+auto walkLength(Range)(Range range)
+if (isInputRange!Range )
+{
+ static if (hasLength!Range)
+ return range.length;
+ else
+ {
+ size_t result;
+ for (; !range.empty; range.popFront())
+ ++result;
+ return result;
+ }
+}
+
+///
+pure nothrow @safe @nogc unittest
+{
+ enum a = [1, 2, 3, 4].staticArray;
+ static assert(a[].walkLength == 4);
+
+ enum c = a[].filter!(e => e > 2);
+ static assert(c.walkLength == 2);
+}
+
+/// Evaluates to the element type of `R`.
+template ElementType(R)
+{
+ static if (is(typeof(R.init.front.init) T))
+ alias ElementType = T;
+ else
+ alias ElementType = void;
+}
+
+/// Evaluates to `true` if the given type satisfy the input range interface.
+enum isInputRange(R) =
+ is(typeof(R.init) == R)
+ && is(ReturnType!(typeof((R r) => r.empty)) == bool)
+ && is(typeof((return ref R r) => r.front))
+ && !is(ReturnType!(typeof((R r) => r.front)) == void)
+ && is(typeof((R r) => r.popFront));
+
+/// Evaluates to `true` if `func` can be called with a value of `T` and returns
+/// a value that is convertible to `bool`.
+enum isPredicateOf(alias func, T) = is(typeof((T t) => !func(t)));
+
+/// Evaluates to `true` if `func` be called withl a value of `T`.
+enum isCallableWith(alias func, T) =
+ __traits(compiles, { auto _ = (T t) => func(t); });
+
+private:
+
+template ReturnType(T)
+{
+ static if (is(T R == return))
+ alias ReturnType = R;
+ else
+ static assert(false, "argument is not a function");
+}
+
+alias Unqual(T) = ReturnType!(typeof((T t) => cast() t));
+
+template hasLength(Range)
+{
+ static if (is(typeof(((Range* r) => r.length)(null)) Length))
+ enum hasLength = is(Length == size_t);
+ else
+ enum hasLength = false;
+}
+
+/// Implements the range interface primitive `front` for built-in arrays.
+@property ref inout(T) front(T)(return scope inout(T)[] a) pure nothrow @nogc @safe
+{
+ assert(a.length, "Attempting to fetch the front of an empty array of " ~ T.stringof);
+ return a[0];
+}
+
+///
+pure nothrow @nogc @safe unittest
+{
+ enum a = [1, 2, 3].staticArray;
+ static assert(a[].front == 1);
+}
+
+/// Implements the range interface primitive `empty` for types that obey $(LREF hasLength) property
+@property bool empty(T)(auto ref scope T a)
+if (is(typeof(a.length) : size_t))
+{
+ return !a.length;
+}
+
+///
+pure nothrow @nogc @safe unittest
+{
+ enum a = [1, 2, 3].staticArray;
+
+ static assert(!a.empty);
+ static assert(a[3 .. $].empty);
+}
+
+pure nothrow @safe unittest
+{
+ int[string] b;
+ assert(b.empty);
+ b["zero"] = 0;
+ assert(!b.empty);
+}
+
+/// Implements the range interface primitive `popFront` for built-in arrays.
+void popFront(T)(/*scope*/ ref inout(T)[] array) pure nothrow @nogc @safe
+{ // does not compile with GDC 9 if this is `scope`
+ assert(array.length, "Attempting to popFront() past the end of an array of " ~ T.stringof);
+ array = array[1 .. $];
+}
+
+///
+pure nothrow @nogc @safe unittest
+{
+ auto a = [1, 2, 3].staticArray;
+ auto b = a[];
+ auto expected = [2, 3].staticArray;
+
+ b.popFront();
+ assert(b == expected[]);
+}
diff --git a/gcc/d/dmd/root/array.h b/gcc/d/dmd/root/array.h
index f7cb0c7..f573dca 100644
--- a/gcc/d/dmd/root/array.h
+++ b/gcc/d/dmd/root/array.h
@@ -9,14 +9,13 @@
#pragma once
#include "dsystem.h"
-#include "dcompat.h"
#include "object.h"
#include "rmem.h"
template <typename TYPE>
struct Array
{
- size_t length;
+ d_size_t length;
private:
DArray<TYPE> data;
@@ -42,8 +41,8 @@ struct Array
char *toChars() const
{
const char **buf = (const char **)mem.xmalloc(length * sizeof(const char *));
- size_t len = 2;
- for (size_t u = 0; u < length; u++)
+ d_size_t len = 2;
+ for (d_size_t u = 0; u < length; u++)
{
buf[u] = ((RootObject *)data.ptr[u])->toChars();
len += strlen(buf[u]) + 1;
@@ -52,7 +51,7 @@ struct Array
str[0] = '[';
char *p = str + 1;
- for (size_t u = 0; u < length; u++)
+ for (d_size_t u = 0; u < length; u++)
{
if (u)
*p++ = ',';
@@ -77,7 +76,7 @@ struct Array
insert(length, a);
}
- void reserve(size_t nentries)
+ void reserve(d_size_t nentries)
{
//printf("Array::reserve: length = %d, data.length = %d, nentries = %d\n", (int)length, (int)data.length, (int)nentries);
if (data.length - length < nentries)
@@ -106,7 +105,7 @@ struct Array
{
/* Increase size by 1.5x to avoid excessive memory fragmentation
*/
- size_t increment = length / 2;
+ d_size_t increment = length / 2;
if (nentries > increment) // if 1.5 is not enough
increment = nentries;
data.length = length + increment;
@@ -115,18 +114,18 @@ struct Array
}
}
- void remove(size_t i)
+ void remove(d_size_t i)
{
if (length - i - 1)
memmove(data.ptr + i, data.ptr + i + 1, (length - i - 1) * sizeof(TYPE));
length--;
}
- void insert(size_t index, Array *a)
+ void insert(d_size_t index, Array *a)
{
if (a)
{
- size_t d = a->length;
+ d_size_t d = a->length;
reserve(d);
if (length != index)
memmove(data.ptr + index + d, data.ptr + index, (length - index) * sizeof(TYPE));
@@ -135,7 +134,7 @@ struct Array
}
}
- void insert(size_t index, TYPE ptr)
+ void insert(d_size_t index, TYPE ptr)
{
reserve(1);
memmove(data.ptr + index + 1, data.ptr + index, (length - index) * sizeof(TYPE));
@@ -143,7 +142,7 @@ struct Array
length++;
}
- void setDim(size_t newdim)
+ void setDim(d_size_t newdim)
{
if (length < newdim)
{
@@ -152,9 +151,9 @@ struct Array
length = newdim;
}
- size_t find(TYPE ptr) const
+ d_size_t find(TYPE ptr) const
{
- for (size_t i = 0; i < length; i++)
+ for (d_size_t i = 0; i < length; i++)
{
if (data.ptr[i] == ptr)
return i;
@@ -167,7 +166,7 @@ struct Array
return find(ptr) != SIZE_MAX;
}
- TYPE& operator[] (size_t index)
+ TYPE& operator[] (d_size_t index)
{
#ifdef DEBUG
assert(index < length);
@@ -205,28 +204,5 @@ struct Array
{
return data.ptr[--length];
}
-
- void sort()
- {
- struct ArraySort
- {
- static int
- #if _WIN32
- __cdecl
- #endif
- Array_sort_compare(const void *x, const void *y)
- {
- RootObject *ox = *(RootObject **)const_cast<void *>(x);
- RootObject *oy = *(RootObject **)const_cast<void *>(y);
-
- return ox->compare(oy);
- }
- };
-
- if (length)
- {
- qsort(data.ptr, length, sizeof(RootObject *), &ArraySort::Array_sort_compare);
- }
- }
};
diff --git a/gcc/d/dmd/root/bitarray.d b/gcc/d/dmd/root/bitarray.d
new file mode 100644
index 0000000..f912961
--- /dev/null
+++ b/gcc/d/dmd/root/bitarray.d
@@ -0,0 +1,192 @@
+/**
+ * Implementation of a bit array.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/bitarray.d, root/_bitarray.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_array.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/bitarray.d
+ */
+
+module dmd.root.bitarray;
+
+import core.stdc.stdio;
+import core.stdc.string;
+
+import dmd.root.rmem;
+
+struct BitArray
+{
+
+ alias Chunk_t = size_t;
+ enum ChunkSize = Chunk_t.sizeof;
+ enum BitsPerChunk = ChunkSize * 8;
+
+ size_t length() const @nogc nothrow pure @safe
+ {
+ return len;
+ }
+
+ void length(size_t nlen) nothrow pure
+ {
+ immutable ochunks = chunks(len);
+ immutable nchunks = chunks(nlen);
+ if (ochunks != nchunks)
+ {
+ ptr = cast(size_t*)mem.xrealloc_noscan(ptr, nchunks * ChunkSize);
+ }
+ if (nchunks > ochunks)
+ ptr[ochunks .. nchunks] = 0;
+ if (nlen & (BitsPerChunk - 1))
+ ptr[nchunks - 1] &= (cast(Chunk_t)1 << (nlen & (BitsPerChunk - 1))) - 1;
+ len = nlen;
+ }
+
+ void opAssign(const ref BitArray b) nothrow pure
+ {
+ if (!len)
+ length(b.len);
+ assert(len == b.len);
+ memcpy(ptr, b.ptr, bytes(len));
+ }
+
+ bool opIndex(size_t idx) const @nogc nothrow pure
+ {
+ import core.bitop : bt;
+
+ assert(idx < len);
+ return !!bt(ptr, idx);
+ }
+
+ void opIndexAssign(bool val, size_t idx) @nogc nothrow pure
+ {
+ import core.bitop : btc, bts;
+
+ assert(idx < len);
+ if (val)
+ bts(ptr, idx);
+ else
+ btc(ptr, idx);
+ }
+
+ bool opEquals(const ref BitArray b) const @nogc nothrow pure
+ {
+ return len == b.len && memcmp(ptr, b.ptr, bytes(len)) == 0;
+ }
+
+ void zero() @nogc nothrow pure
+ {
+ memset(ptr, 0, bytes(len));
+ }
+
+ /******
+ * Returns:
+ * true if no bits are set
+ */
+ bool isZero() @nogc nothrow pure
+ {
+ const nchunks = chunks(len);
+ foreach (i; 0 .. nchunks)
+ {
+ if (ptr[i])
+ return false;
+ }
+ return true;
+ }
+
+ void or(const ref BitArray b) @nogc nothrow pure
+ {
+ assert(len == b.len);
+ const nchunks = chunks(len);
+ foreach (i; 0 .. nchunks)
+ ptr[i] |= b.ptr[i];
+ }
+
+ /* Swap contents of `this` with `b`
+ */
+ void swap(ref BitArray b) @nogc nothrow pure
+ {
+ assert(len == b.len);
+ const nchunks = chunks(len);
+ foreach (i; 0 .. nchunks)
+ {
+ const chunk = ptr[i];
+ ptr[i] = b.ptr[i];
+ b.ptr[i] = chunk;
+ }
+ }
+
+ ~this() nothrow pure
+ {
+ debug
+ {
+ // Stomp the allocated memory
+ const nchunks = chunks(len);
+ foreach (i; 0 .. nchunks)
+ {
+ ptr[i] = cast(Chunk_t)0xFEFEFEFE_FEFEFEFE;
+ }
+ }
+ mem.xfree(ptr);
+ debug
+ {
+ // Set to implausible values
+ len = cast(size_t)0xFEFEFEFE_FEFEFEFE;
+ ptr = cast(size_t*)cast(size_t)0xFEFEFEFE_FEFEFEFE;
+ }
+ }
+
+private:
+ size_t len; // length in bits
+ size_t *ptr;
+
+ /// Returns: The amount of chunks used to store len bits
+ static size_t chunks(const size_t len) @nogc nothrow pure @safe
+ {
+ return (len + BitsPerChunk - 1) / BitsPerChunk;
+ }
+
+ /// Returns: The amount of bytes used to store len bits
+ static size_t bytes(const size_t len) @nogc nothrow pure @safe
+ {
+ return chunks(len) * ChunkSize;
+ }
+}
+
+nothrow pure unittest
+{
+ BitArray array;
+ array.length = 20;
+ assert(array[19] == 0);
+ array[10] = 1;
+ assert(array[10] == 1);
+ array[10] = 0;
+ assert(array[10] == 0);
+ assert(array.length == 20);
+
+ BitArray a,b;
+ assert(a != array);
+ a.length = 200;
+ assert(a != array);
+ assert(a.isZero());
+ a[100] = true;
+ b.length = 200;
+ b[100] = true;
+ assert(a == b);
+
+ a.length = 300;
+ b.length = 300;
+ assert(a == b);
+ b[299] = true;
+ assert(a != b);
+ assert(!a.isZero());
+ a.swap(b);
+ assert(a[299] == true);
+ assert(b[299] == false);
+ a = b;
+ assert(a == b);
+}
+
+
+
diff --git a/gcc/d/dmd/root/bitarray.h b/gcc/d/dmd/root/bitarray.h
index 004c43c..e773711 100644
--- a/gcc/d/dmd/root/bitarray.h
+++ b/gcc/d/dmd/root/bitarray.h
@@ -24,8 +24,8 @@ struct BitArray
mem.xfree(ptr);
}
- size_t len;
- size_t *ptr;
+ d_size_t len;
+ d_size_t *ptr;
private:
BitArray(const BitArray&);
diff --git a/gcc/d/dmd/root/checkedint.c b/gcc/d/dmd/root/checkedint.c
deleted file mode 100644
index af7b56f..0000000
--- a/gcc/d/dmd/root/checkedint.c
+++ /dev/null
@@ -1,238 +0,0 @@
-
-/**********************************************
- * This module implements integral arithmetic primitives that check
- * for out-of-range results.
- * This is a translation to C++ of D's core.checkedint
- *
- * Integral arithmetic operators operate on fixed width types.
- * Results that are not representable in those fixed widths are silently
- * truncated to fit.
- * This module offers integral arithmetic primitives that produce the
- * same results, but set an 'overflow' flag when such truncation occurs.
- * The setting is sticky, meaning that numerous operations can be cascaded
- * and then the flag need only be checked at the end.
- * Whether the operation is signed or unsigned is indicated by an 's' or 'u'
- * suffix, respectively. While this could be achieved without such suffixes by
- * using overloading on the signedness of the types, the suffix makes it clear
- * which is happening without needing to examine the types.
- *
- * While the generic versions of these functions are computationally expensive
- * relative to the cost of the operation itself, compiler implementations are free
- * to recognize them and generate equivalent and faster code.
- *
- * References: $(LINK2 http://blog.regehr.org/archives/1139, Fast Integer Overflow Checks)
- * Copyright: Copyright (C) 2014-2021 by The D Language Foundation, All Rights Reserved
- * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Authors: Walter Bright
- * Source: https://github.com/D-Programming-Language/dmd/blob/master/src/root/checkedint.c
- */
-
-#include "dsystem.h"
-#include "checkedint.h"
-
-
-/*******************************
- * Add two signed integers, checking for overflow.
- *
- * The overflow is sticky, meaning a sequence of operations can
- * be done and overflow need only be checked at the end.
- * Params:
- * x = left operand
- * y = right operand
- * overflow = set if an overflow occurs, is not affected otherwise
- * Returns:
- * the sum
- */
-
-int adds(int x, int y, bool& overflow)
-{
- int64_t r = (int64_t)x + (int64_t)y;
- if (r < INT32_MIN || r > INT32_MAX)
- overflow = true;
- return (int)r;
-}
-
-/// ditto
-int64_t adds(int64_t x, int64_t y, bool& overflow)
-{
- int64_t r = (uint64_t)x + (uint64_t)y;
- if ((x < 0 && y < 0 && r >= 0) ||
- (x >= 0 && y >= 0 && r < 0))
- overflow = true;
- return r;
-}
-
-/*******************************
- * Add two unsigned integers, checking for overflow (aka carry).
- *
- * The overflow is sticky, meaning a sequence of operations can
- * be done and overflow need only be checked at the end.
- * Params:
- * x = left operand
- * y = right operand
- * overflow = set if an overflow occurs, is not affected otherwise
- * Returns:
- * the sum
- */
-
-unsigned addu(unsigned x, unsigned y, bool& overflow)
-{
- unsigned r = x + y;
- if (r < x || r < y)
- overflow = true;
- return r;
-}
-
-/// ditto
-uint64_t addu(uint64_t x, uint64_t y, bool& overflow)
-{
- uint64_t r = x + y;
- if (r < x || r < y)
- overflow = true;
- return r;
-}
-
-/*******************************
- * Subtract two signed integers, checking for overflow.
- *
- * The overflow is sticky, meaning a sequence of operations can
- * be done and overflow need only be checked at the end.
- * Params:
- * x = left operand
- * y = right operand
- * overflow = set if an overflow occurs, is not affected otherwise
- * Returns:
- * the sum
- */
-
-int subs(int x, int y, bool& overflow)
-{
- int64_t r = (int64_t)x - (int64_t)y;
- if (r < INT32_MIN || r > INT32_MAX)
- overflow = true;
- return (int)r;
-}
-
-/// ditto
-int64_t subs(int64_t x, int64_t y, bool& overflow)
-{
- int64_t r = (uint64_t)x - (uint64_t)y;
- if ((x < 0 && y >= 0 && r >= 0) ||
- (x >= 0 && y < 0 && (r < 0 || y == INT64_MIN)))
- overflow = true;
- return r;
-}
-
-/*******************************
- * Subtract two unsigned integers, checking for overflow (aka borrow).
- *
- * The overflow is sticky, meaning a sequence of operations can
- * be done and overflow need only be checked at the end.
- * Params:
- * x = left operand
- * y = right operand
- * overflow = set if an overflow occurs, is not affected otherwise
- * Returns:
- * the sum
- */
-
-unsigned subu(unsigned x, unsigned y, bool& overflow)
-{
- if (x < y)
- overflow = true;
- return x - y;
-}
-
-/// ditto
-uint64_t subu(uint64_t x, uint64_t y, bool& overflow)
-{
- if (x < y)
- overflow = true;
- return x - y;
-}
-
-/***********************************************
- * Negate an integer.
- *
- * Params:
- * x = operand
- * overflow = set if x cannot be negated, is not affected otherwise
- * Returns:
- * the negation of x
- */
-
-int negs(int x, bool& overflow)
-{
- if (x == (int)INT32_MIN)
- overflow = true;
- return -x;
-}
-
-/// ditto
-int64_t negs(int64_t x, bool& overflow)
-{
- if (x == INT64_MIN)
- overflow = true;
- return -x;
-}
-
-/*******************************
- * Multiply two signed integers, checking for overflow.
- *
- * The overflow is sticky, meaning a sequence of operations can
- * be done and overflow need only be checked at the end.
- * Params:
- * x = left operand
- * y = right operand
- * overflow = set if an overflow occurs, is not affected otherwise
- * Returns:
- * the sum
- */
-
-int muls(int x, int y, bool& overflow)
-{
- int64_t r = (int64_t)x * (int64_t)y;
- if (r < INT32_MIN || r > INT32_MAX)
- overflow = true;
- return (int)r;
-}
-
-/// ditto
-int64_t muls(int64_t x, int64_t y, bool& overflow)
-{
- int64_t r = (uint64_t)x * (uint64_t)y;
- int64_t not0or1 = ~(int64_t)1;
- if ((x & not0or1) && ((r == y) ? r : (r / x) != y))
- overflow = true;
- return r;
-}
-
-/*******************************
- * Multiply two unsigned integers, checking for overflow (aka carry).
- *
- * The overflow is sticky, meaning a sequence of operations can
- * be done and overflow need only be checked at the end.
- * Params:
- * x = left operand
- * y = right operand
- * overflow = set if an overflow occurs, is not affected otherwise
- * Returns:
- * the sum
- */
-
-unsigned mulu(unsigned x, unsigned y, bool& overflow)
-{
- uint64_t r = (uint64_t)x * (uint64_t)y;
- if (r > UINT32_MAX)
- overflow = true;
- return (unsigned)r;
-}
-
-/// ditto
-uint64_t mulu(uint64_t x, uint64_t y, bool& overflow)
-{
- uint64_t r = x * y;
- if (x && (r / x) != y)
- overflow = true;
- return r;
-}
diff --git a/gcc/d/dmd/root/ctfloat.d b/gcc/d/dmd/root/ctfloat.d
new file mode 100644
index 0000000..9b98742
--- /dev/null
+++ b/gcc/d/dmd/root/ctfloat.d
@@ -0,0 +1,63 @@
+/**
+ * Collects functions for compile-time floating-point calculations.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/ctfloat.d, root/_ctfloat.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_ctfloat.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/ctfloat.d
+ */
+
+module dmd.root.ctfloat;
+
+nothrow:
+
+// Type used by the front-end for compile-time reals
+public import dmd.root.longdouble : real_t = longdouble;
+
+// Compile-time floating-point helper
+extern (C++) struct CTFloat
+{
+ nothrow:
+ @nogc:
+ @safe:
+
+ version (GNU)
+ enum yl2x_supported = false;
+ else
+ enum yl2x_supported = __traits(compiles, core.math.yl2x(1.0L, 2.0L));
+ enum yl2xp1_supported = yl2x_supported;
+
+ pure static real_t fabs(real_t x);
+ pure static real_t ldexp(real_t n, int exp);
+
+ pure @trusted
+ static bool isIdentical(real_t a, real_t b);
+
+ pure @trusted
+ static size_t hash(real_t a);
+
+ pure
+ static bool isNaN(real_t r);
+
+ pure @trusted
+ static bool isSNaN(real_t r);
+
+ static bool isInfinity(real_t r) pure;
+
+ @system
+ static real_t parse(const(char)* literal, bool* isOutOfRange = null);
+
+ @system
+ static int sprint(char* str, char fmt, real_t x);
+
+ // Constant real values 0, 1, -1 and 0.5.
+ __gshared real_t zero;
+ __gshared real_t one;
+ __gshared real_t minusone;
+ __gshared real_t half;
+
+ @trusted
+ static void initialize();
+}
diff --git a/gcc/d/dmd/root/ctfloat.h b/gcc/d/dmd/root/ctfloat.h
index 0a829f3..1221b82 100644
--- a/gcc/d/dmd/root/ctfloat.h
+++ b/gcc/d/dmd/root/ctfloat.h
@@ -1,5 +1,6 @@
/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
@@ -16,9 +17,6 @@ typedef longdouble real_t;
// Compile-time floating-point helper
struct CTFloat
{
- static bool yl2x_supported;
- static bool yl2xp1_supported;
-
static void yl2x(const real_t *x, const real_t *y, real_t *res);
static void yl2xp1(const real_t *x, const real_t *y, real_t *res);
@@ -62,4 +60,6 @@ struct CTFloat
static real_t one;
static real_t minusone;
static real_t half;
+
+ static void initialize();
};
diff --git a/gcc/d/dmd/root/dcompat.h b/gcc/d/dmd/root/dcompat.h
index 9fd176e..88f2095 100644
--- a/gcc/d/dmd/root/dcompat.h
+++ b/gcc/d/dmd/root/dcompat.h
@@ -34,3 +34,15 @@ struct DString : public DArray<const char>
DString(size_t length, const char *ptr)
: DArray<const char>(length, ptr) { }
};
+
+/// Corresponding C++ type that maps to D size_t
+#if __APPLE__ && __i386__
+// size_t is 'unsigned long', which makes it mangle differently than D's 'uint'
+typedef unsigned d_size_t;
+#elif MARS && DMD_VERSION >= 2079 && DMD_VERSION <= 2081 && \
+ __APPLE__ && __SIZEOF_SIZE_T__ == 8
+// DMD versions between 2.079 and 2.081 mapped D ulong to uint64_t on OS X.
+typedef uint64_t d_size_t;
+#else
+typedef size_t d_size_t;
+#endif
diff --git a/gcc/d/dmd/root/file.c b/gcc/d/dmd/root/file.c
deleted file mode 100644
index 314b5b5..0000000
--- a/gcc/d/dmd/root/file.c
+++ /dev/null
@@ -1,258 +0,0 @@
-
-/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
- * https://github.com/D-Programming-Language/dmd/blob/master/src/root/file.c
- */
-
-#include "dsystem.h"
-#include "file.h"
-
-#if _WIN32
-#include <windows.h>
-#endif
-
-#if POSIX
-#include <utime.h>
-#endif
-
-#include "filename.h"
-#include "array.h"
-#include "rmem.h"
-
-/****************************** File ********************************/
-
-File::File(const FileName *n)
-{
- ref = 0;
- buffer = NULL;
- len = 0;
- name = const_cast<FileName *>(n);
-}
-
-File *File::create(const char *n)
-{
- return new File(n);
-}
-
-File::File(const char *n)
-{
- ref = 0;
- buffer = NULL;
- len = 0;
- name = new FileName(n);
-}
-
-File::~File()
-{
- if (buffer)
- {
- if (ref == 0)
- mem.xfree(buffer);
-#if _WIN32
- if (ref == 2)
- UnmapViewOfFile(buffer);
-#endif
- }
-}
-
-/*************************************
- */
-
-bool File::read()
-{
- if (len)
- return false; // already read the file
-#if POSIX
- size_t size;
- struct stat buf;
- ssize_t numread;
-
- const char *name = this->name->toChars();
- //printf("File::read('%s')\n",name);
- int fd = open(name, O_RDONLY);
- if (fd == -1)
- {
- //printf("\topen error, errno = %d\n",errno);
- goto err1;
- }
-
- if (!ref)
- ::free(buffer);
- ref = 0; // we own the buffer now
-
- //printf("\tfile opened\n");
- if (fstat(fd, &buf))
- {
- printf("\tfstat error, errno = %d\n",errno);
- goto err2;
- }
- size = (size_t)buf.st_size;
-#ifdef IN_GCC
- buffer = (unsigned char *) ::xmalloc(size + 2);
-#else
- buffer = (unsigned char *) ::malloc(size + 2);
-#endif
- if (!buffer)
- {
- printf("\tmalloc error, errno = %d\n",errno);
- goto err2;
- }
-
- numread = ::read(fd, buffer, size);
- if (numread != (ssize_t)size)
- {
- printf("\tread error, errno = %d\n",errno);
- goto err2;
- }
-
- if (close(fd) == -1)
- {
- printf("\tclose error, errno = %d\n",errno);
- goto err;
- }
-
- len = size;
-
- // Always store a wchar ^Z past end of buffer so scanner has a sentinel
- buffer[size] = 0; // ^Z is obsolete, use 0
- buffer[size + 1] = 0;
- return false;
-
-err2:
- close(fd);
-err:
- ::free(buffer);
- buffer = NULL;
- len = 0;
-
-err1:
- return true;
-#elif _WIN32
- DWORD size;
- DWORD numread;
-
- const char *name = this->name->toChars();
- HANDLE h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
- if (h == INVALID_HANDLE_VALUE)
- goto err1;
-
- if (!ref)
- ::free(buffer);
- ref = 0;
-
- size = GetFileSize(h,NULL);
-#ifdef IN_GCC
- buffer = (unsigned char *) ::xmalloc(size + 2);
-#else
- buffer = (unsigned char *) ::malloc(size + 2);
-#endif
- if (!buffer)
- goto err2;
-
- if (ReadFile(h,buffer,size,&numread,NULL) != TRUE)
- goto err2;
-
- if (numread != size)
- goto err2;
-
- if (!CloseHandle(h))
- goto err;
-
- len = size;
-
- // Always store a wchar ^Z past end of buffer so scanner has a sentinel
- buffer[size] = 0; // ^Z is obsolete, use 0
- buffer[size + 1] = 0;
- return 0;
-
-err2:
- CloseHandle(h);
-err:
- ::free(buffer);
- buffer = NULL;
- len = 0;
-
-err1:
- return true;
-#else
- assert(0);
-#endif
-}
-
-/*********************************************
- * Write a file.
- * Returns:
- * false success
- */
-
-bool File::write()
-{
-#if POSIX
- ssize_t numwritten;
-
- const char *name = this->name->toChars();
- int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4);
- if (fd == -1)
- goto err;
-
- numwritten = ::write(fd, buffer, len);
- if ((ssize_t)len != numwritten)
- goto err2;
-
- if (close(fd) == -1)
- goto err;
-
- return false;
-
-err2:
- close(fd);
- ::remove(name);
-err:
- return true;
-#elif _WIN32
- DWORD numwritten;
-
- const char *name = this->name->toChars();
- HANDLE h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
- if (h == INVALID_HANDLE_VALUE)
- goto err;
-
- if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE)
- goto err2;
-
- if (len != numwritten)
- goto err2;
-
- if (!CloseHandle(h))
- goto err;
- return false;
-
-err2:
- CloseHandle(h);
- DeleteFileA(name);
-err:
- return true;
-#else
- assert(0);
-#endif
-}
-
-void File::remove()
-{
-#if POSIX
- ::remove(this->name->toChars());
-#elif _WIN32
- DeleteFileA(this->name->toChars());
-#else
- assert(0);
-#endif
-}
-
-const char *File::toChars()
-{
- return name->toChars();
-}
diff --git a/gcc/d/dmd/root/file.d b/gcc/d/dmd/root/file.d
new file mode 100644
index 0000000..ef6056c
--- /dev/null
+++ b/gcc/d/dmd/root/file.d
@@ -0,0 +1,814 @@
+/**
+ * Read a file from disk and store it in memory.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/file.d, root/_file.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_file.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/file.d
+ */
+
+module dmd.root.file;
+
+import core.stdc.errno;
+import core.stdc.stdio;
+import core.stdc.stdlib;
+import core.stdc.string : strerror;
+import core.sys.posix.fcntl;
+import core.sys.posix.unistd;
+import core.sys.windows.winbase;
+import core.sys.windows.winnt;
+import dmd.root.filename;
+import dmd.root.rmem;
+import dmd.root.string;
+
+/**
+Encapsulated management of a memory-mapped file.
+
+Params:
+Datum = the mapped data type: Use a POD of size 1 for read/write mapping
+and a `const` version thereof for read-only mapping. Other primitive types
+should work, but have not been yet tested.
+*/
+struct FileMapping(Datum)
+{
+ static assert(__traits(isPOD, Datum) && Datum.sizeof == 1,
+ "Not tested with other data types yet. Add new types with care.");
+
+ version(Posix) enum invalidHandle = -1;
+ else version(Windows) enum invalidHandle = INVALID_HANDLE_VALUE;
+
+ // state {
+ /// Handle of underlying file
+ private auto handle = invalidHandle;
+ /// File mapping object needed on Windows
+ version(Windows) private HANDLE fileMappingObject = invalidHandle;
+ /// Memory-mapped array
+ private Datum[] data;
+ /// Name of underlying file, zero-terminated
+ private const(char)* name;
+ // state }
+
+ /**
+ Open `filename` and map it in memory. If `Datum` is `const`, opens for
+ read-only and maps the content in memory; no error is issued if the file
+ does not exist. This makes it easy to treat a non-existing file as empty.
+
+ If `Datum` is mutable, opens for read/write (creates file if it does not
+ exist) and fails fatally on any error.
+
+ Due to quirks in `mmap`, if the file is empty, `handle` is valid but `data`
+ is `null`. This state is valid and accounted for.
+
+ Params:
+ filename = the name of the file to be mapped in memory
+ */
+ this(const char* filename)
+ {
+ version (Posix)
+ {
+ import core.sys.posix.sys.mman;
+ import core.sys.posix.fcntl;
+
+ handle = .open(filename, is(Datum == const) ? O_RDONLY : (O_CREAT | O_RDWR),
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ if (handle == invalidHandle)
+ {
+ static if (is(Datum == const))
+ {
+ // No error, nonexisting file in read mode behaves like an empty file.
+ return;
+ }
+ else
+ {
+ fprintf(stderr, "open(\"%s\") failed: %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ }
+
+ const size = File.size(handle);
+
+ if (size > 0 && size != ulong.max && size <= size_t.max)
+ {
+ auto p = mmap(null, cast(size_t) size, is(Datum == const) ? PROT_READ : PROT_WRITE, MAP_SHARED, handle, 0);
+ if (p == MAP_FAILED)
+ {
+ fprintf(stderr, "mmap(null, %zu) for \"%s\" failed: %s\n", cast(size_t) size, filename, strerror(errno));
+ exit(1);
+ }
+ // The cast below will always work because it's gated by the `size <= size_t.max` condition.
+ data = cast(Datum[]) p[0 .. cast(size_t) size];
+ }
+ }
+ else version(Windows)
+ {
+ static if (is(Datum == const))
+ {
+ enum createFileMode = GENERIC_READ;
+ enum openFlags = OPEN_EXISTING;
+ }
+ else
+ {
+ enum createFileMode = GENERIC_READ | GENERIC_WRITE;
+ enum openFlags = CREATE_ALWAYS;
+ }
+
+ handle = CreateFileA(filename, createFileMode, 0, null, openFlags, FILE_ATTRIBUTE_NORMAL, null);
+ if (handle == invalidHandle)
+ {
+ static if (is(Datum == const))
+ {
+ return;
+ }
+ else
+ {
+ fprintf(stderr, "CreateFileA() failed for \"%s\": %d\n", filename, GetLastError());
+ exit(1);
+ }
+ }
+ createMapping(filename, File.size(handle));
+ }
+ else static assert(0);
+
+ // Save the name for later. Technically there's no need: on Linux one can use readlink on /proc/self/fd/NNN.
+ // On BSD and OSX one can use fcntl with F_GETPATH. On Windows one can use GetFileInformationByHandleEx.
+ // But just saving the name is simplest, fastest, and most portable...
+ import core.stdc.string : strlen;
+ name = filename[0 .. filename.strlen() + 1].idup.ptr;
+ }
+
+ /**
+ Common code factored opportunistically. Windows only. Assumes `handle` is
+ already pointing to an opened file. Initializes the `fileMappingObject`
+ and `data` members.
+
+ Params:
+ filename = the file to be mapped
+ size = the size of the file in bytes
+ */
+ version(Windows) private void createMapping(const char* filename, ulong size)
+ {
+ assert(size <= size_t.max || size == ulong.max);
+ assert(handle != invalidHandle);
+ assert(data is null);
+ assert(fileMappingObject == invalidHandle);
+
+ if (size == 0 || size == ulong.max)
+ return;
+
+ static if (is(Datum == const))
+ {
+ enum fileMappingFlags = PAGE_READONLY;
+ enum mapViewFlags = FILE_MAP_READ;
+ }
+ else
+ {
+ enum fileMappingFlags = PAGE_READWRITE;
+ enum mapViewFlags = FILE_MAP_WRITE;
+ }
+
+ fileMappingObject = CreateFileMappingA(handle, null, fileMappingFlags, 0, 0, null);
+ if (!fileMappingObject)
+ {
+ fprintf(stderr, "CreateFileMappingA(%p) failed for %llu bytes of \"%s\": %d\n",
+ handle, size, filename, GetLastError());
+ fileMappingObject = invalidHandle; // by convention always use invalidHandle, not null
+ exit(1);
+ }
+ auto p = MapViewOfFile(fileMappingObject, mapViewFlags, 0, 0, 0);
+ if (!p)
+ {
+ fprintf(stderr, "MapViewOfFile() failed for \"%s\": %d\n", filename, GetLastError());
+ exit(1);
+ }
+ data = cast(Datum[]) p[0 .. cast(size_t) size];
+ }
+
+ // Not copyable or assignable (for now).
+ @disable this(const FileMapping!Datum rhs);
+ @disable void opAssign(const ref FileMapping!Datum rhs);
+
+ /**
+ Frees resources associated with this mapping. However, it does not deallocate the name.
+ */
+ ~this() pure nothrow
+ {
+ if (!active)
+ return;
+ fakePure({
+ version (Posix)
+ {
+ import core.sys.posix.sys.mman : munmap;
+
+ // Cannot call fprintf from inside a destructor, so exiting silently.
+
+ if (data.ptr && munmap(cast(void*) data.ptr, data.length) != 0)
+ {
+ exit(1);
+ }
+ data = null;
+ if (handle != invalidHandle && .close(handle) != 0)
+ {
+ exit(1);
+ }
+ handle = invalidHandle;
+ }
+ else version(Windows)
+ {
+ if (data.ptr !is null && UnmapViewOfFile(cast(void*) data.ptr) == 0)
+ {
+ exit(1);
+ }
+ data = null;
+ if (fileMappingObject != invalidHandle && CloseHandle(fileMappingObject) == 0)
+ {
+ exit(1);
+ }
+ fileMappingObject = invalidHandle;
+ if (handle != invalidHandle && CloseHandle(handle) == 0)
+ {
+ exit(1);
+ }
+ handle = invalidHandle;
+ }
+ else static assert(0);
+ });
+ }
+
+ /**
+ Returns the zero-terminated file name associated with the mapping. Can
+ be saved beyond the lifetime of `this`.
+ */
+ const(char)* filename() const pure @nogc @safe nothrow { return name; }
+
+ /**
+ Frees resources associated with this mapping. However, it does not deallocate the name.
+ Reinitializes `this` as a fresh object that can be reused.
+ */
+ void close()
+ {
+ __dtor();
+ handle = invalidHandle;
+ version(Windows) fileMappingObject = invalidHandle;
+ data = null;
+ name = null;
+ }
+
+ /**
+ Deletes the underlying file and frees all resources associated.
+ Reinitializes `this` as a fresh object that can be reused.
+
+ This function does not abort if the file cannot be deleted, but does print
+ a message on `stderr` and returns `false` to the caller. The underlying
+ rationale is to give the caller the option to continue execution if
+ deleting the file is not important.
+
+ Returns: `true` iff the file was successfully deleted. If the file was not
+ deleted, prints a message to `stderr` and returns `false`.
+ */
+ static if (!is(Datum == const))
+ bool discard()
+ {
+ // Truncate file to zero so unflushed buffers are not flushed unnecessarily.
+ resize(0);
+ auto deleteme = name;
+ close();
+ // In-memory resource freed, now get rid of the underlying temp file.
+ version(Posix)
+ {
+ import core.sys.posix.unistd;
+ if (unlink(deleteme) != 0)
+ {
+ fprintf(stderr, "unlink(\"%s\") failed: %s\n", filename, strerror(errno));
+ return false;
+ }
+ }
+ else version(Windows)
+ {
+ import core.sys.windows.winbase;
+ if (DeleteFileA(deleteme) == 0)
+ {
+ fprintf(stderr, "DeleteFileA error %d\n", GetLastError());
+ return false;
+ }
+ }
+ else static assert(0);
+ return true;
+ }
+
+ /**
+ Queries whether `this` is currently associated with a file.
+
+ Returns: `true` iff there is an active mapping.
+ */
+ bool active() const pure @nogc nothrow
+ {
+ return handle !is invalidHandle;
+ }
+
+ /**
+ Queries the length of the file associated with this mapping. If not
+ active, returns 0.
+
+ Returns: the length of the file, or 0 if no file associated.
+ */
+ size_t length() const pure @nogc @safe nothrow { return data.length; }
+
+ /**
+ Get a slice to the contents of the entire file.
+
+ Returns: the contents of the file. If not active, returns the `null` slice.
+ */
+ auto opSlice() pure @nogc @safe nothrow { return data; }
+
+ /**
+ Resizes the file and mapping to the specified `size`.
+
+ Params:
+ size = new length requested
+ */
+ static if (!is(Datum == const))
+ void resize(size_t size) pure
+ {
+ assert(handle != invalidHandle);
+ fakePure({
+ version(Posix)
+ {
+ import core.sys.posix.unistd : ftruncate;
+ import core.sys.posix.sys.mman;
+
+ if (data.length)
+ {
+ assert(data.ptr, "Corrupt memory mapping");
+ // assert(0) here because it would indicate an internal error
+ munmap(cast(void*) data.ptr, data.length) == 0 || assert(0);
+ data = null;
+ }
+ if (ftruncate(handle, size) != 0)
+ {
+ fprintf(stderr, "ftruncate() failed for \"%s\": %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ if (size > 0)
+ {
+ auto p = mmap(null, size, PROT_WRITE, MAP_SHARED, handle, 0);
+ if (cast(ssize_t) p == -1)
+ {
+ fprintf(stderr, "mmap() failed for \"%s\": %s\n", filename, strerror(errno));
+ exit(1);
+ }
+ data = cast(Datum[]) p[0 .. size];
+ }
+ }
+ else version(Windows)
+ {
+ // Per documentation, must unmap first.
+ if (data.length > 0 && UnmapViewOfFile(cast(void*) data.ptr) == 0)
+ {
+ fprintf(stderr, "UnmapViewOfFile(%p) failed for memory mapping of \"%s\": %d\n",
+ data.ptr, filename, GetLastError());
+ exit(1);
+ }
+ data = null;
+ if (fileMappingObject != invalidHandle && CloseHandle(fileMappingObject) == 0)
+ {
+ fprintf(stderr, "CloseHandle() failed for memory mapping of \"%s\": %d\n", filename, GetLastError());
+ exit(1);
+ }
+ fileMappingObject = invalidHandle;
+ LARGE_INTEGER biggie;
+ biggie.QuadPart = size;
+ if (SetFilePointerEx(handle, biggie, null, FILE_BEGIN) == 0 || SetEndOfFile(handle) == 0)
+ {
+ fprintf(stderr, "SetFilePointer() failed for \"%s\": %d\n", filename, GetLastError());
+ exit(1);
+ }
+ createMapping(name, size);
+ }
+ else static assert(0);
+ });
+ }
+
+ /**
+ Unconditionally and destructively moves the underlying file to `filename`.
+ If the operation succeds, returns true. Upon failure, prints a message to
+ `stderr` and returns `false`.
+
+ Params: filename = zero-terminated name of the file to move to.
+
+ Returns: `true` iff the operation was successful.
+ */
+ bool moveToFile(const char* filename)
+ {
+ auto oldname = name;
+
+ close();
+ // Rename the underlying file to the target, no copy necessary.
+ version(Posix)
+ {
+ if (.rename(oldname, filename) != 0)
+ {
+ fprintf(stderr, "rename(\"%s\", \"%s\") failed: %s\n", oldname, filename, strerror(errno));
+ return false;
+ }
+ }
+ else version(Windows)
+ {
+ import core.sys.windows.winbase;
+ if (MoveFileExA(oldname, filename, MOVEFILE_REPLACE_EXISTING) == 0)
+ {
+ fprintf(stderr, "MoveFileExA(\"%s\", \"%s\") failed: %d\n", oldname, filename, GetLastError());
+ return false;
+ }
+ }
+ else static assert(0);
+ return true;
+ }
+}
+
+/// Owns a (rmem-managed) file buffer.
+struct FileBuffer
+{
+ ubyte[] data;
+
+ this(this) @disable;
+
+ ~this() pure nothrow
+ {
+ mem.xfree(data.ptr);
+ }
+
+ /// Transfers ownership of the buffer to the caller.
+ ubyte[] extractSlice() pure nothrow @nogc @safe
+ {
+ auto result = data;
+ data = null;
+ return result;
+ }
+
+ extern (C++) static FileBuffer* create() pure nothrow @safe
+ {
+ return new FileBuffer();
+ }
+}
+
+///
+struct File
+{
+ ///
+ static struct ReadResult
+ {
+ bool success;
+ FileBuffer buffer;
+
+ /// Transfers ownership of the buffer to the caller.
+ ubyte[] extractSlice() pure nothrow @nogc @safe
+ {
+ return buffer.extractSlice();
+ }
+
+ /// ditto
+ /// Include the null-terminator at the end of the buffer in the returned array.
+ ubyte[] extractDataZ() @nogc nothrow pure
+ {
+ auto result = buffer.extractSlice();
+ return result.ptr[0 .. result.length + 1];
+ }
+ }
+
+nothrow:
+ /// Read the full content of a file.
+ extern (C++) static ReadResult read(const(char)* name)
+ {
+ return read(name.toDString());
+ }
+
+ /// Ditto
+ static ReadResult read(const(char)[] name)
+ {
+ ReadResult result;
+
+ version (Posix)
+ {
+ size_t size;
+ stat_t buf;
+ ssize_t numread;
+ //printf("File::read('%s')\n",name);
+ int fd = name.toCStringThen!(slice => open(slice.ptr, O_RDONLY));
+ if (fd == -1)
+ {
+ //printf("\topen error, errno = %d\n",errno);
+ return result;
+ }
+ //printf("\tfile opened\n");
+ if (fstat(fd, &buf))
+ {
+ perror("\tfstat error");
+ close(fd);
+ return result;
+ }
+ size = cast(size_t)buf.st_size;
+ ubyte* buffer = cast(ubyte*)mem.xmalloc_noscan(size + 4);
+ numread = .read(fd, buffer, size);
+ if (numread != size)
+ {
+ perror("\tread error");
+ goto err2;
+ }
+ if (close(fd) == -1)
+ {
+ perror("\tclose error");
+ goto err;
+ }
+ // Always store a wchar ^Z past end of buffer so scanner has a sentinel
+ buffer[size] = 0; // ^Z is obsolete, use 0
+ buffer[size + 1] = 0;
+ buffer[size + 2] = 0; //add two more so lexer doesnt read pass the buffer
+ buffer[size + 3] = 0;
+
+ result.success = true;
+ result.buffer.data = buffer[0 .. size];
+ return result;
+ err2:
+ close(fd);
+ err:
+ mem.xfree(buffer);
+ return result;
+ }
+ else version (Windows)
+ {
+ DWORD size;
+ DWORD numread;
+
+ // work around Windows file path length limitation
+ // (see documentation for extendedPathThen).
+ HANDLE h = name.extendedPathThen!
+ (p => CreateFileW(p.ptr,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ null,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+ null));
+ if (h == INVALID_HANDLE_VALUE)
+ return result;
+ size = GetFileSize(h, null);
+ ubyte* buffer = cast(ubyte*)mem.xmalloc_noscan(size + 4);
+ if (ReadFile(h, buffer, size, &numread, null) != TRUE)
+ goto err2;
+ if (numread != size)
+ goto err2;
+ if (!CloseHandle(h))
+ goto err;
+ // Always store a wchar ^Z past end of buffer so scanner has a sentinel
+ buffer[size] = 0; // ^Z is obsolete, use 0
+ buffer[size + 1] = 0;
+ buffer[size + 2] = 0; //add two more so lexer doesnt read pass the buffer
+ buffer[size + 3] = 0;
+ result.success = true;
+ result.buffer.data = buffer[0 .. size];
+ return result;
+ err2:
+ CloseHandle(h);
+ err:
+ mem.xfree(buffer);
+ return result;
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+
+ /// Write a file, returning `true` on success.
+ extern (D) static bool write(const(char)* name, const void[] data)
+ {
+ version (Posix)
+ {
+ ssize_t numwritten;
+ int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4);
+ if (fd == -1)
+ goto err;
+ numwritten = .write(fd, data.ptr, data.length);
+ if (numwritten != data.length)
+ goto err2;
+ if (close(fd) == -1)
+ goto err;
+ return true;
+ err2:
+ close(fd);
+ .remove(name);
+ err:
+ return false;
+ }
+ else version (Windows)
+ {
+ DWORD numwritten; // here because of the gotos
+ const nameStr = name.toDString;
+ // work around Windows file path length limitation
+ // (see documentation for extendedPathThen).
+ HANDLE h = nameStr.extendedPathThen!
+ (p => CreateFileW(p.ptr,
+ GENERIC_WRITE,
+ 0,
+ null,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+ null));
+ if (h == INVALID_HANDLE_VALUE)
+ goto err;
+
+ if (WriteFile(h, data.ptr, cast(DWORD)data.length, &numwritten, null) != TRUE)
+ goto err2;
+ if (numwritten != data.length)
+ goto err2;
+ if (!CloseHandle(h))
+ goto err;
+ return true;
+ err2:
+ CloseHandle(h);
+ nameStr.extendedPathThen!(p => DeleteFileW(p.ptr));
+ err:
+ return false;
+ }
+ else
+ {
+ static assert(0);
+ }
+ }
+
+ ///ditto
+ extern(D) static bool write(const(char)[] name, const void[] data)
+ {
+ return name.toCStringThen!((fname) => write(fname.ptr, data));
+ }
+
+ /// ditto
+ extern (C++) static bool write(const(char)* name, const(void)* data, size_t size)
+ {
+ return write(name, data[0 .. size]);
+ }
+
+ /// Delete a file.
+ extern (C++) static void remove(const(char)* name)
+ {
+ version (Posix)
+ {
+ .remove(name);
+ }
+ else version (Windows)
+ {
+ name.toDString.extendedPathThen!(p => DeleteFileW(p.ptr));
+ }
+ else
+ {
+ static assert(0);
+ }
+ }
+
+ /***************************************************
+ * Update file
+ *
+ * If the file exists and is identical to what is to be written,
+ * merely update the timestamp on the file.
+ * Otherwise, write the file.
+ *
+ * The idea is writes are much slower than reads, and build systems
+ * often wind up generating identical files.
+ * Params:
+ * name = name of file to update
+ * data = updated contents of file
+ * Returns:
+ * `true` on success
+ */
+ extern (D) static bool update(const(char)* namez, const void[] data)
+ {
+ enum log = false;
+ if (log) printf("update %s\n", namez);
+
+ if (data.length != File.size(namez))
+ return write(namez, data); // write new file
+
+ if (log) printf("same size\n");
+
+ /* The file already exists, and is the same size.
+ * Read it in, and compare for equality.
+ */
+ //if (FileMapping!(const ubyte)(namez)[] != data[])
+ return write(namez, data); // contents not same, so write new file
+ //if (log) printf("same contents\n");
+
+ /* Contents are identical, so set timestamp of existing file to current time
+ */
+ //return touch(namez);
+ }
+
+ ///ditto
+ extern(D) static bool update(const(char)[] name, const void[] data)
+ {
+ return name.toCStringThen!(fname => update(fname.ptr, data));
+ }
+
+ /// ditto
+ extern (C++) static bool update(const(char)* name, const(void)* data, size_t size)
+ {
+ return update(name, data[0 .. size]);
+ }
+
+ /// Touch a file to current date
+ static bool touch(const char* namez)
+ {
+ version (Windows)
+ {
+ FILETIME ft = void;
+ SYSTEMTIME st = void;
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+
+ import core.stdc.string : strlen;
+
+ // get handle to file
+ HANDLE h = namez[0 .. namez.strlen()].extendedPathThen!(p => CreateFile(p.ptr,
+ FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ null, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, null));
+ if (h == INVALID_HANDLE_VALUE)
+ return false;
+
+ const f = SetFileTime(h, null, null, &ft); // set last write time
+
+ if (!CloseHandle(h))
+ return false;
+
+ return f != 0;
+ }
+ else version (Posix)
+ {
+ import core.sys.posix.utime;
+ return utime(namez, null) == 0;
+ }
+ else
+ static assert(0);
+ }
+
+ /// Size of a file in bytes.
+ /// Params: namez = null-terminated filename
+ /// Returns: `ulong.max` on any error, the length otherwise.
+ static ulong size(const char* namez)
+ {
+ version (Posix)
+ {
+ stat_t buf;
+ if (stat(namez, &buf) == 0)
+ return buf.st_size;
+ }
+ else version (Windows)
+ {
+ const nameStr = namez.toDString();
+ import core.sys.windows.windows;
+ WIN32_FILE_ATTRIBUTE_DATA fad = void;
+ // Doesn't exist, not a regular file, different size
+ if (nameStr.extendedPathThen!(p => GetFileAttributesExW(p.ptr, GET_FILEEX_INFO_LEVELS.GetFileExInfoStandard, &fad)) != 0)
+ return (ulong(fad.nFileSizeHigh) << 32UL) | fad.nFileSizeLow;
+ }
+ else static assert(0);
+ // Error cases go here.
+ return ulong.max;
+ }
+
+ /// Ditto
+ version (Posix)
+ static ulong size(int fd)
+ {
+ stat_t buf;
+ if (fstat(fd, &buf) == 0)
+ return buf.st_size;
+ return ulong.max;
+ }
+
+ /// Ditto
+ version (Windows)
+ static ulong size(HANDLE fd)
+ {
+ ulong result;
+ if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0)
+ return result;
+ return ulong.max;
+ }
+}
+
+/**
+Runs a non-pure function or delegate as pure code. Use with caution.
+
+Params:
+fun = the delegate to run, usually inlined: `fakePure({ ... });`
+
+Returns: whatever `fun` returns.
+*/
+private auto ref fakePure(F)(scope F fun) pure
+{
+ mixin("alias PureFun = " ~ F.stringof ~ " pure;");
+ return (cast(PureFun) fun)();
+}
diff --git a/gcc/d/dmd/root/file.h b/gcc/d/dmd/root/file.h
index 5135818..ee0d51e 100644
--- a/gcc/d/dmd/root/file.h
+++ b/gcc/d/dmd/root/file.h
@@ -1,5 +1,6 @@
/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
@@ -8,46 +9,33 @@
#pragma once
-#include "dsystem.h"
#include "array.h"
+#include "filename.h"
-typedef Array<struct File *> Files;
-
-struct FileName;
-
-struct File
+struct FileBuffer
{
- int ref; // != 0 if this is a reference to someone else's buffer
- unsigned char *buffer; // data for our file
- size_t len; // amount of data in buffer[]
-
- FileName *name; // name of our file
-
- File(const char *);
- static File *create(const char *);
- File(const FileName *);
- ~File();
-
- const char *toChars();
+ DArray<unsigned char> data;
- /* Read file, return true if error
- */
+ FileBuffer(const FileBuffer &) /* = delete */;
+ ~FileBuffer() { mem.xfree(data.ptr); }
- bool read();
-
- /* Write file, return true if error
- */
+ static FileBuffer *create();
+};
- bool write();
+struct File
+{
+ struct ReadResult
+ {
+ bool success;
+ FileBuffer buffer;
+ };
- /* Set buffer
- */
+ // Read the full content of a file.
+ static ReadResult read(const char *name);
- void setbuffer(void *buffer, size_t len)
- {
- this->buffer = (unsigned char *)buffer;
- this->len = len;
- }
+ // Write a file, returning `true` on success.
+ static bool write(const char *name, const void *data, d_size_t size);
- void remove(); // delete file
+ // Delete a file.
+ static void remove(const char *name);
};
diff --git a/gcc/d/dmd/root/filename.c b/gcc/d/dmd/root/filename.c
deleted file mode 100644
index 0c5138b..0000000
--- a/gcc/d/dmd/root/filename.c
+++ /dev/null
@@ -1,671 +0,0 @@
-
-/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
- * https://github.com/D-Programming-Language/dmd/blob/master/src/root/filename.c
- */
-
-#include "dsystem.h"
-#include "filename.h"
-#include "port.h"
-#include "outbuffer.h"
-#include "array.h"
-#include "file.h"
-#include "rmem.h"
-
-#if _WIN32
-#include <windows.h>
-#endif
-
-#if POSIX
-#include <utime.h>
-#endif
-
-/****************************** FileName ********************************/
-
-FileName::FileName(const char *str)
- : str(mem.xstrdup(str))
-{
-}
-
-const char *FileName::combine(const char *path, const char *name)
-{ char *f;
- size_t pathlen;
- size_t namelen;
-
- if (!path || !*path)
- return name;
- pathlen = strlen(path);
- namelen = strlen(name);
- f = (char *)mem.xmalloc(pathlen + 1 + namelen + 1);
- memcpy(f, path, pathlen);
-#if POSIX
- if (path[pathlen - 1] != '/')
- { f[pathlen] = '/';
- pathlen++;
- }
-#elif _WIN32
- if (path[pathlen - 1] != '\\' &&
- path[pathlen - 1] != '/' &&
- path[pathlen - 1] != ':')
- { f[pathlen] = '\\';
- pathlen++;
- }
-#else
- assert(0);
-#endif
- memcpy(f + pathlen, name, namelen + 1);
- return f;
-}
-
-// Split a path into an Array of paths
-Strings *FileName::splitPath(const char *path)
-{
- char c = 0; // unnecessary initializer is for VC /W4
- const char *p;
- OutBuffer buf;
- Strings *array;
-
- array = new Strings();
- if (path)
- {
- p = path;
- do
- { char instring = 0;
-
- while (isspace((utf8_t)*p)) // skip leading whitespace
- p++;
- buf.reserve(strlen(p) + 1); // guess size of path
- for (; ; p++)
- {
- c = *p;
- switch (c)
- {
- case '"':
- instring ^= 1; // toggle inside/outside of string
- continue;
-
-#if MACINTOSH
- case ',':
-#endif
-#if _WIN32
- case ';':
-#endif
-#if POSIX
- case ':':
-#endif
- p++;
- break; // note that ; cannot appear as part
- // of a path, quotes won't protect it
-
- case 0x1A: // ^Z means end of file
- case 0:
- break;
-
- case '\r':
- continue; // ignore carriage returns
-
-#if POSIX
- case '~':
- {
- char *home = getenv("HOME");
- // Expand ~ only if it is prefixing the rest of the path.
- if (!buf.length() && p[1] == '/' && home)
- buf.writestring(home);
- else
- buf.writestring("~");
- continue;
- }
-#endif
-
- default:
- buf.writeByte(c);
- continue;
- }
- break;
- }
- if (buf.length()) // if path is not empty
- {
- array->push(buf.extractChars());
- }
- } while (c);
- }
- return array;
-}
-
-int FileName::compare(RootObject *obj)
-{
- return compare(str, ((FileName *)obj)->str);
-}
-
-int FileName::compare(const char *name1, const char *name2)
-{
-#if _WIN32
- return stricmp(name1, name2);
-#else
- return strcmp(name1, name2);
-#endif
-}
-
-bool FileName::equals(RootObject *obj)
-{
- return compare(obj) == 0;
-}
-
-bool FileName::equals(const char *name1, const char *name2)
-{
- return compare(name1, name2) == 0;
-}
-
-/************************************
- * Return !=0 if absolute path name.
- */
-
-bool FileName::absolute(const char *name)
-{
-#if _WIN32
- return (*name == '\\') ||
- (*name == '/') ||
- (*name && name[1] == ':');
-#elif POSIX
- return (*name == '/');
-#else
- assert(0);
-#endif
-}
-
-/**
-Return the given name as an absolute path
-
-Params:
- name = path
- base = the absolute base to prefix name with if it is relative
-
-Returns: name as an absolute path relative to base
-*/
-const char *FileName::toAbsolute(const char *name, const char *base)
-{
- return absolute(name) ? name : combine(base ? base : getcwd(NULL, 0), name);
-}
-
-/********************************
- * Return filename extension (read-only).
- * Points past '.' of extension.
- * If there isn't one, return NULL.
- */
-
-const char *FileName::ext(const char *str)
-{
- size_t len = strlen(str);
-
- const char *e = str + len;
- for (;;)
- {
- switch (*e)
- { case '.':
- return e + 1;
-#if POSIX
- case '/':
- break;
-#endif
-#if _WIN32
- case '\\':
- case ':':
- case '/':
- break;
-#endif
- default:
- if (e == str)
- break;
- e--;
- continue;
- }
- return NULL;
- }
-}
-
-const char *FileName::ext()
-{
- return ext(str);
-}
-
-/********************************
- * Return mem.xmalloc'd filename with extension removed.
- */
-
-const char *FileName::removeExt(const char *str)
-{
- const char *e = ext(str);
- if (e)
- { size_t len = (e - str) - 1;
- char *n = (char *)mem.xmalloc(len + 1);
- memcpy(n, str, len);
- n[len] = 0;
- return n;
- }
- return mem.xstrdup(str);
-}
-
-/********************************
- * Return filename name excluding path (read-only).
- */
-
-const char *FileName::name(const char *str)
-{
- size_t len = strlen(str);
-
- const char *e = str + len;
- for (;;)
- {
- switch (*e)
- {
-#if POSIX
- case '/':
- return e + 1;
-#endif
-#if _WIN32
- case '/':
- case '\\':
- return e + 1;
- case ':':
- /* The ':' is a drive letter only if it is the second
- * character or the last character,
- * otherwise it is an ADS (Alternate Data Stream) separator.
- * Consider ADS separators as part of the file name.
- */
- if (e == str + 1 || e == str + len - 1)
- return e + 1;
-#endif
- /* falls through */
- default:
- if (e == str)
- break;
- e--;
- continue;
- }
- return e;
- }
-}
-
-const char *FileName::name()
-{
- return name(str);
-}
-
-/**************************************
- * Return path portion of str.
- * Path will does not include trailing path separator.
- */
-
-const char *FileName::path(const char *str)
-{
- const char *n = name(str);
- size_t pathlen;
-
- if (n > str)
- {
-#if POSIX
- if (n[-1] == '/')
- n--;
-#elif _WIN32
- if (n[-1] == '\\' || n[-1] == '/')
- n--;
-#else
- assert(0);
-#endif
- }
- pathlen = n - str;
- char *path = (char *)mem.xmalloc(pathlen + 1);
- memcpy(path, str, pathlen);
- path[pathlen] = 0;
- return path;
-}
-
-/**************************************
- * Replace filename portion of path.
- */
-
-const char *FileName::replaceName(const char *path, const char *name)
-{
- size_t pathlen;
- size_t namelen;
-
- if (absolute(name))
- return name;
-
- const char *n = FileName::name(path);
- if (n == path)
- return name;
- pathlen = n - path;
- namelen = strlen(name);
- char *f = (char *)mem.xmalloc(pathlen + 1 + namelen + 1);
- memcpy(f, path, pathlen);
-#if POSIX
- if (path[pathlen - 1] != '/')
- { f[pathlen] = '/';
- pathlen++;
- }
-#elif _WIN32
- if (path[pathlen - 1] != '\\' &&
- path[pathlen - 1] != '/' &&
- path[pathlen - 1] != ':')
- { f[pathlen] = '\\';
- pathlen++;
- }
-#else
- assert(0);
-#endif
- memcpy(f + pathlen, name, namelen + 1);
- return f;
-}
-
-/***************************
- * Free returned value with FileName::free()
- */
-
-const char *FileName::defaultExt(const char *name, const char *ext)
-{
- const char *e = FileName::ext(name);
- if (e) // if already has an extension
- return mem.xstrdup(name);
-
- size_t len = strlen(name);
- size_t extlen = strlen(ext);
- char *s = (char *)mem.xmalloc(len + 1 + extlen + 1);
- memcpy(s,name,len);
- s[len] = '.';
- memcpy(s + len + 1, ext, extlen + 1);
- return s;
-}
-
-/***************************
- * Free returned value with FileName::free()
- */
-
-const char *FileName::forceExt(const char *name, const char *ext)
-{
- const char *e = FileName::ext(name);
- if (e) // if already has an extension
- {
- size_t len = e - name;
- size_t extlen = strlen(ext);
-
- char *s = (char *)mem.xmalloc(len + extlen + 1);
- memcpy(s,name,len);
- memcpy(s + len, ext, extlen + 1);
- return s;
- }
- else
- return defaultExt(name, ext); // doesn't have one
-}
-
-/******************************
- * Return !=0 if extensions match.
- */
-
-bool FileName::equalsExt(const char *ext)
-{
- return equalsExt(str, ext);
-}
-
-bool FileName::equalsExt(const char *name, const char *ext)
-{
- const char *e = FileName::ext(name);
- if (!e && !ext)
- return true;
- if (!e || !ext)
- return false;
- return FileName::compare(e, ext) == 0;
-}
-
-/*************************************
- * Search Path for file.
- * Input:
- * cwd if true, search current directory before searching path
- */
-
-const char *FileName::searchPath(Strings *path, const char *name, bool cwd)
-{
- if (absolute(name))
- {
- return exists(name) ? name : NULL;
- }
- if (cwd)
- {
- if (exists(name))
- return name;
- }
- if (path)
- {
-
- for (size_t i = 0; i < path->length; i++)
- {
- const char *p = (*path)[i];
- const char *n = combine(p, name);
-
- if (exists(n))
- return n;
- }
- }
- return NULL;
-}
-
-
-/*************************************
- * Search Path for file in a safe manner.
- *
- * Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
- * ('Path Traversal') attacks.
- * http://cwe.mitre.org/data/definitions/22.html
- * More info:
- * https://www.securecoding.cert.org/confluence/display/c/FIO02-C.+Canonicalize+path+names+originating+from+tainted+sources
- * Returns:
- * NULL file not found
- * !=NULL mem.xmalloc'd file name
- */
-
-const char *FileName::safeSearchPath(Strings *path, const char *name)
-{
-#if _WIN32
- // don't allow leading / because it might be an absolute
- // path or UNC path or something we'd prefer to just not deal with
- if (*name == '/')
- {
- return NULL;
- }
- /* Disallow % \ : and .. in name characters
- * We allow / for compatibility with subdirectories which is allowed
- * on dmd/posix. With the leading / blocked above and the rest of these
- * conservative restrictions, we should be OK.
- */
- for (const char *p = name; *p; p++)
- {
- char c = *p;
- if (c == '\\' || c == ':' || c == '%' || (c == '.' && p[1] == '.'))
- {
- return NULL;
- }
- }
-
- return FileName::searchPath(path, name, false);
-#elif POSIX
- /* Even with realpath(), we must check for // and disallow it
- */
- for (const char *p = name; *p; p++)
- {
- char c = *p;
- if (c == '/' && p[1] == '/')
- {
- return NULL;
- }
- }
-
- if (path)
- {
- /* Each path is converted to a cannonical name and then a check is done to see
- * that the searched name is really a child one of the the paths searched.
- */
- for (size_t i = 0; i < path->length; i++)
- {
- const char *cname = NULL;
- const char *cpath = canonicalName((*path)[i]);
- //printf("FileName::safeSearchPath(): name=%s; path=%s; cpath=%s\n",
- // name, (char *)path->data[i], cpath);
- if (cpath == NULL)
- goto cont;
- cname = canonicalName(combine(cpath, name));
- //printf("FileName::safeSearchPath(): cname=%s\n", cname);
- if (cname == NULL)
- goto cont;
- //printf("FileName::safeSearchPath(): exists=%i "
- // "strncmp(cpath, cname, %i)=%i\n", exists(cname),
- // strlen(cpath), strncmp(cpath, cname, strlen(cpath)));
- // exists and name is *really* a "child" of path
- if (exists(cname) && strncmp(cpath, cname, strlen(cpath)) == 0)
- {
- ::free(const_cast<char *>(cpath));
- const char *p = mem.xstrdup(cname);
- ::free(const_cast<char *>(cname));
- return p;
- }
-cont:
- if (cpath)
- ::free(const_cast<char *>(cpath));
- if (cname)
- ::free(const_cast<char *>(cname));
- }
- }
- return NULL;
-#else
- assert(0);
-#endif
-}
-
-
-int FileName::exists(const char *name)
-{
-#if POSIX
- struct stat st;
-
- if (stat(name, &st) < 0)
- return 0;
- if (S_ISDIR(st.st_mode))
- return 2;
- return 1;
-#elif _WIN32
- DWORD dw;
- int result;
-
- dw = GetFileAttributesA(name);
- if (dw == INVALID_FILE_ATTRIBUTES)
- result = 0;
- else if (dw & FILE_ATTRIBUTE_DIRECTORY)
- result = 2;
- else
- result = 1;
- return result;
-#else
- assert(0);
-#endif
-}
-
-bool FileName::ensurePathExists(const char *path)
-{
- //printf("FileName::ensurePathExists(%s)\n", path ? path : "");
- if (path && *path)
- {
- if (!exists(path))
- {
- const char *p = FileName::path(path);
- if (*p)
- {
-#if _WIN32
- size_t len = strlen(path);
- if ((len > 2 && p[-1] == ':' && strcmp(path + 2, p) == 0) ||
- len == strlen(p))
- { mem.xfree(const_cast<char *>(p));
- return 0;
- }
-#endif
- bool r = ensurePathExists(p);
- mem.xfree(const_cast<char *>(p));
- if (r)
- return r;
- }
-#if _WIN32
- char sep = '\\';
-#elif POSIX
- char sep = '/';
-#endif
- if (path[strlen(path) - 1] != sep)
- {
- //printf("mkdir(%s)\n", path);
-#if _WIN32
- int r = _mkdir(path);
-#endif
-#if POSIX
- int r = mkdir(path, (7 << 6) | (7 << 3) | 7);
-#endif
- if (r)
- {
- /* Don't error out if another instance of dmd just created
- * this directory
- */
- if (errno != EEXIST)
- return true;
- }
- }
- }
- }
- return false;
-}
-
-/******************************************
- * Return canonical version of name in a malloc'd buffer.
- * This code is high risk.
- */
-const char *FileName::canonicalName(const char *name)
-{
-#if POSIX
- // NULL destination buffer is allowed and preferred
- return realpath(name, NULL);
-#elif _WIN32
- /* Apparently, there is no good way to do this on Windows.
- * GetFullPathName isn't it, but use it anyway.
- */
- DWORD result = GetFullPathNameA(name, 0, NULL, NULL);
- if (result)
- {
- char *buf = (char *)mem.xmalloc(result);
- result = GetFullPathNameA(name, result, buf, NULL);
- if (result == 0)
- {
- ::free(buf);
- return NULL;
- }
- return buf;
- }
- return NULL;
-#else
- assert(0);
- return NULL;
-#endif
-}
-
-/********************************
- * Free memory allocated by FileName routines
- */
-void FileName::free(const char *str)
-{
- if (str)
- { assert(str[0] != (char)0xAB);
- memset(const_cast<char *>(str), 0xAB, strlen(str) + 1); // stomp
- }
- mem.xfree(const_cast<char *>(str));
-}
-
-const char *FileName::toChars() const
-{
- return str;
-}
diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d
new file mode 100644
index 0000000..1e4ccb5
--- /dev/null
+++ b/gcc/d/dmd/root/filename.d
@@ -0,0 +1,1273 @@
+/**
+ * Encapsulate path and file names.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/filename.d, root/_filename.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_filename.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/filename.d
+ */
+
+module dmd.root.filename;
+
+import core.stdc.ctype;
+import core.stdc.errno;
+import core.stdc.string;
+import dmd.root.array;
+import dmd.root.file;
+import dmd.root.outbuffer;
+import dmd.root.port;
+import dmd.root.rmem;
+import dmd.root.rootobject;
+import dmd.root.string;
+
+version (Posix)
+{
+ import core.sys.posix.stdlib;
+ import core.sys.posix.sys.stat;
+ import core.sys.posix.unistd : getcwd;
+}
+
+version (Windows)
+{
+ import core.sys.windows.winbase;
+ import core.sys.windows.windef;
+ import core.sys.windows.winnls;
+
+ extern (Windows) DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*) nothrow @nogc;
+ extern (Windows) void SetLastError(DWORD) nothrow @nogc;
+ extern (C) char* getcwd(char* buffer, size_t maxlen) nothrow;
+
+ // assume filenames encoded in system default Windows ANSI code page
+ private enum CodePage = CP_ACP;
+}
+
+version (CRuntime_Glibc)
+{
+ extern (C) char* canonicalize_file_name(const char*) nothrow;
+}
+
+alias Strings = Array!(const(char)*);
+
+
+// Check whether character is a directory separator
+private bool isDirSeparator(char c) pure nothrow @nogc @safe
+{
+ version (Windows)
+ {
+ return c == '\\' || c == '/';
+ }
+ else version (Posix)
+ {
+ return c == '/';
+ }
+ else
+ {
+ assert(0);
+ }
+}
+
+/***********************************************************
+ * Encapsulate path and file names.
+ */
+struct FileName
+{
+nothrow:
+ private const(char)[] str;
+
+ ///
+ extern (D) this(const(char)[] str) pure
+ {
+ this.str = str.xarraydup;
+ }
+
+ /// Compare two name according to the platform's rules (case sensitive or not)
+ extern (C++) static bool equals(const(char)* name1, const(char)* name2) pure @nogc
+ {
+ return equals(name1.toDString, name2.toDString);
+ }
+
+ /// Ditto
+ extern (D) static bool equals(const(char)[] name1, const(char)[] name2) pure @nogc
+ {
+ if (name1.length != name2.length)
+ return false;
+
+ version (Windows)
+ {
+ return name1.ptr == name2.ptr ||
+ Port.memicmp(name1.ptr, name2.ptr, name1.length) == 0;
+ }
+ else
+ {
+ return name1 == name2;
+ }
+ }
+
+ /************************************
+ * Determine if path is absolute.
+ * Params:
+ * name = path
+ * Returns:
+ * true if absolute path name.
+ */
+ extern (C++) static bool absolute(const(char)* name) pure @nogc
+ {
+ return absolute(name.toDString);
+ }
+
+ /// Ditto
+ extern (D) static bool absolute(const(char)[] name) pure @nogc
+ {
+ if (!name.length)
+ return false;
+
+ version (Windows)
+ {
+ return isDirSeparator(name[0])
+ || (name.length >= 2 && name[1] == ':');
+ }
+ else version (Posix)
+ {
+ return isDirSeparator(name[0]);
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+
+ unittest
+ {
+ assert(absolute("/"[]) == true);
+ assert(absolute(""[]) == false);
+
+ version (Windows)
+ {
+ assert(absolute(r"\"[]) == true);
+ assert(absolute(r"\\"[]) == true);
+ assert(absolute(r"c:"[]) == true);
+ }
+ }
+
+ /**
+ Return the given name as an absolute path
+
+ Params:
+ name = path
+ base = the absolute base to prefix name with if it is relative
+
+ Returns: name as an absolute path relative to base
+ */
+ extern (C++) static const(char)* toAbsolute(const(char)* name, const(char)* base = null)
+ {
+ const name_ = name.toDString();
+ const base_ = base ? base.toDString() : getcwd(null, 0).toDString();
+ return absolute(name_) ? name : combine(base_, name_).ptr;
+ }
+
+ /********************************
+ * Determine file name extension as slice of input.
+ * Params:
+ * str = file name
+ * Returns:
+ * filename extension (read-only).
+ * Points past '.' of extension.
+ * If there isn't one, return null.
+ */
+ extern (C++) static const(char)* ext(const(char)* str) pure @nogc
+ {
+ return ext(str.toDString).ptr;
+ }
+
+ /// Ditto
+ extern (D) static const(char)[] ext(const(char)[] str) nothrow pure @safe @nogc
+ {
+ foreach_reverse (idx, char e; str)
+ {
+ switch (e)
+ {
+ case '.':
+ return str[idx + 1 .. $];
+ version (Posix)
+ {
+ case '/':
+ return null;
+ }
+ version (Windows)
+ {
+ case '\\':
+ case ':':
+ case '/':
+ return null;
+ }
+ default:
+ continue;
+ }
+ }
+ return null;
+ }
+
+ unittest
+ {
+ assert(ext("/foo/bar/dmd.conf"[]) == "conf");
+ assert(ext("object.o"[]) == "o");
+ assert(ext("/foo/bar/dmd"[]) == null);
+ assert(ext(".objdir.o/object"[]) == null);
+ assert(ext([]) == null);
+ }
+
+ extern (C++) const(char)* ext() const pure @nogc
+ {
+ return ext(str).ptr;
+ }
+
+ /********************************
+ * Return file name without extension.
+ *
+ * TODO:
+ * Once slice are used everywhere and `\0` is not assumed,
+ * this can be turned into a simple slicing.
+ *
+ * Params:
+ * str = file name
+ *
+ * Returns:
+ * mem.xmalloc'd filename with extension removed.
+ */
+ extern (C++) static const(char)* removeExt(const(char)* str)
+ {
+ return removeExt(str.toDString).ptr;
+ }
+
+ /// Ditto
+ extern (D) static const(char)[] removeExt(const(char)[] str)
+ {
+ auto e = ext(str);
+ if (e.length)
+ {
+ const len = (str.length - e.length) - 1; // -1 for the dot
+ char* n = cast(char*)mem.xmalloc(len + 1);
+ memcpy(n, str.ptr, len);
+ n[len] = 0;
+ return n[0 .. len];
+ }
+ return mem.xstrdup(str.ptr)[0 .. str.length];
+ }
+
+ unittest
+ {
+ assert(removeExt("/foo/bar/object.d"[]) == "/foo/bar/object");
+ assert(removeExt("/foo/bar/frontend.di"[]) == "/foo/bar/frontend");
+ }
+
+ /********************************
+ * Return filename name excluding path (read-only).
+ */
+ extern (C++) static const(char)* name(const(char)* str) pure @nogc
+ {
+ return name(str.toDString).ptr;
+ }
+
+ /// Ditto
+ extern (D) static const(char)[] name(const(char)[] str) pure @nogc
+ {
+ foreach_reverse (idx, char e; str)
+ {
+ switch (e)
+ {
+ version (Posix)
+ {
+ case '/':
+ return str[idx + 1 .. $];
+ }
+ version (Windows)
+ {
+ case '/':
+ case '\\':
+ return str[idx + 1 .. $];
+ case ':':
+ /* The ':' is a drive letter only if it is the second
+ * character or the last character,
+ * otherwise it is an ADS (Alternate Data Stream) separator.
+ * Consider ADS separators as part of the file name.
+ */
+ if (idx == 1 || idx == str.length - 1)
+ return str[idx + 1 .. $];
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ return str;
+ }
+
+ extern (C++) const(char)* name() const pure @nogc
+ {
+ return name(str).ptr;
+ }
+
+ unittest
+ {
+ assert(name("/foo/bar/object.d"[]) == "object.d");
+ assert(name("/foo/bar/frontend.di"[]) == "frontend.di");
+ }
+
+ /**************************************
+ * Return path portion of str.
+ * returned string is newly allocated
+ * Path does not include trailing path separator.
+ */
+ extern (C++) static const(char)* path(const(char)* str)
+ {
+ return path(str.toDString).ptr;
+ }
+
+ /// Ditto
+ extern (D) static const(char)[] path(const(char)[] str)
+ {
+ const n = name(str);
+ bool hasTrailingSlash;
+ if (n.length < str.length)
+ {
+ if (isDirSeparator(str[$ - n.length - 1]))
+ hasTrailingSlash = true;
+ }
+ const pathlen = str.length - n.length - (hasTrailingSlash ? 1 : 0);
+ char* path = cast(char*)mem.xmalloc(pathlen + 1);
+ memcpy(path, str.ptr, pathlen);
+ path[pathlen] = 0;
+ return path[0 .. pathlen];
+ }
+
+ unittest
+ {
+ assert(path("/foo/bar"[]) == "/foo");
+ assert(path("foo"[]) == "");
+ }
+
+ /**************************************
+ * Replace filename portion of path.
+ */
+ extern (D) static const(char)[] replaceName(const(char)[] path, const(char)[] name)
+ {
+ if (absolute(name))
+ return name;
+ auto n = FileName.name(path);
+ if (n == path)
+ return name;
+ return combine(path[0 .. $ - n.length], name);
+ }
+
+ /**
+ Combine a `path` and a file `name`
+
+ Params:
+ path = Path to append to
+ name = Name to append to path
+
+ Returns:
+ The `\0` terminated string which is the combination of `path` and `name`
+ and a valid path.
+ */
+ extern (C++) static const(char)* combine(const(char)* path, const(char)* name)
+ {
+ if (!path)
+ return name;
+ return combine(path.toDString, name.toDString).ptr;
+ }
+
+ /// Ditto
+ extern(D) static const(char)[] combine(const(char)[] path, const(char)[] name)
+ {
+ return !path.length ? name : buildPath(path, name);
+ }
+
+ unittest
+ {
+ version (Windows)
+ assert(combine("foo"[], "bar"[]) == "foo\\bar");
+ else
+ assert(combine("foo"[], "bar"[]) == "foo/bar");
+ assert(combine("foo/"[], "bar"[]) == "foo/bar");
+ }
+
+ static const(char)[] buildPath(const(char)[][] fragments...)
+ {
+ size_t size;
+ foreach (f; fragments)
+ size += f.length ? f.length + 1 : 0;
+ if (size == 0)
+ size = 1;
+
+ char* p = cast(char*) mem.xmalloc_noscan(size);
+ size_t length;
+ foreach (f; fragments)
+ {
+ if (!f.length)
+ continue;
+
+ p[length .. length + f.length] = f;
+ length += f.length;
+
+ const last = p[length - 1];
+ version (Posix)
+ {
+ if (!isDirSeparator(last))
+ p[length++] = '/';
+ }
+ else version (Windows)
+ {
+ if (!isDirSeparator(last) && last != ':')
+ p[length++] = '\\';
+ }
+ else
+ assert(0);
+ }
+
+ // overwrite last slash with null terminator
+ p[length ? --length : 0] = 0;
+
+ return p[0 .. length];
+ }
+
+ unittest
+ {
+ assert(buildPath() == "");
+ assert(buildPath("foo") == "foo");
+ assert(buildPath("foo", null) == "foo");
+ assert(buildPath(null, "foo") == "foo");
+ version (Windows)
+ assert(buildPath("C:", r"a\", "bb/", "ccc", "d") == r"C:a\bb/ccc\d");
+ else
+ assert(buildPath("a/", "bb", "ccc") == "a/bb/ccc");
+ }
+
+ // Split a path into an Array of paths
+ extern (C++) static Strings* splitPath(const(char)* path)
+ {
+ auto array = new Strings();
+ int sink(const(char)* p) nothrow
+ {
+ array.push(p);
+ return 0;
+ }
+ splitPath(&sink, path);
+ return array;
+ }
+
+ /****
+ * Split path (such as that returned by `getenv("PATH")`) into pieces, each piece is mem.xmalloc'd
+ * Handle double quotes and ~.
+ * Pass the pieces to sink()
+ * Params:
+ * sink = send the path pieces here, end when sink() returns !=0
+ * path = the path to split up.
+ */
+ static void splitPath(int delegate(const(char)*) nothrow sink, const(char)* path)
+ {
+ if (!path)
+ return;
+
+ auto p = path;
+ OutBuffer buf;
+ char c;
+ do
+ {
+ const(char)* home;
+ bool instring = false;
+ while (isspace(*p)) // skip leading whitespace
+ ++p;
+ buf.reserve(8); // guess size of piece
+ for (;; ++p)
+ {
+ c = *p;
+ switch (c)
+ {
+ case '"':
+ instring ^= false; // toggle inside/outside of string
+ continue;
+
+ version (OSX)
+ {
+ case ',':
+ }
+ version (Windows)
+ {
+ case ';':
+ }
+ version (Posix)
+ {
+ case ':':
+ }
+ p++; // ; cannot appear as part of a
+ break; // path, quotes won't protect it
+
+ case 0x1A: // ^Z means end of file
+ case 0:
+ break;
+
+ case '\r':
+ continue; // ignore carriage returns
+
+ version (Posix)
+ {
+ case '~':
+ if (!home)
+ home = getenv("HOME");
+ // Expand ~ only if it is prefixing the rest of the path.
+ if (!buf.length && p[1] == '/' && home)
+ buf.writestring(home);
+ else
+ buf.writeByte('~');
+ continue;
+ }
+
+ version (none)
+ {
+ case ' ':
+ case '\t': // tabs in filenames?
+ if (!instring) // if not in string
+ break; // treat as end of path
+ }
+ default:
+ buf.writeByte(c);
+ continue;
+ }
+ break;
+ }
+ if (buf.length) // if path is not empty
+ {
+ if (sink(buf.extractChars()))
+ break;
+ }
+ } while (c);
+ }
+
+ /**
+ * Add the extension `ext` to `name`, regardless of the content of `name`
+ *
+ * Params:
+ * name = Path to append the extension to
+ * ext = Extension to add (should not include '.')
+ *
+ * Returns:
+ * A newly allocated string (free with `FileName.free`)
+ */
+ extern(D) static char[] addExt(const(char)[] name, const(char)[] ext) pure
+ {
+ const len = name.length + ext.length + 2;
+ auto s = cast(char*)mem.xmalloc(len);
+ s[0 .. name.length] = name[];
+ s[name.length] = '.';
+ s[name.length + 1 .. len - 1] = ext[];
+ s[len - 1] = '\0';
+ return s[0 .. len - 1];
+ }
+
+
+ /***************************
+ * Free returned value with FileName::free()
+ */
+ extern (C++) static const(char)* defaultExt(const(char)* name, const(char)* ext)
+ {
+ return defaultExt(name.toDString, ext.toDString).ptr;
+ }
+
+ /// Ditto
+ extern (D) static const(char)[] defaultExt(const(char)[] name, const(char)[] ext)
+ {
+ auto e = FileName.ext(name);
+ if (e.length) // it already has an extension
+ return name.xarraydup;
+ return addExt(name, ext);
+ }
+
+ unittest
+ {
+ assert(defaultExt("/foo/object.d"[], "d") == "/foo/object.d");
+ assert(defaultExt("/foo/object"[], "d") == "/foo/object.d");
+ assert(defaultExt("/foo/bar.d"[], "o") == "/foo/bar.d");
+ }
+
+ /***************************
+ * Free returned value with FileName::free()
+ */
+ extern (C++) static const(char)* forceExt(const(char)* name, const(char)* ext)
+ {
+ return forceExt(name.toDString, ext.toDString).ptr;
+ }
+
+ /// Ditto
+ extern (D) static const(char)[] forceExt(const(char)[] name, const(char)[] ext)
+ {
+ if (auto e = FileName.ext(name))
+ return addExt(name[0 .. $ - e.length - 1], ext);
+ return defaultExt(name, ext); // doesn't have one
+ }
+
+ unittest
+ {
+ assert(forceExt("/foo/object.d"[], "d") == "/foo/object.d");
+ assert(forceExt("/foo/object"[], "d") == "/foo/object.d");
+ assert(forceExt("/foo/bar.d"[], "o") == "/foo/bar.o");
+ }
+
+ /// Returns:
+ /// `true` if `name`'s extension is `ext`
+ extern (C++) static bool equalsExt(const(char)* name, const(char)* ext) pure @nogc
+ {
+ return equalsExt(name.toDString, ext.toDString);
+ }
+
+ /// Ditto
+ extern (D) static bool equalsExt(const(char)[] name, const(char)[] ext) pure @nogc
+ {
+ auto e = FileName.ext(name);
+ if (!e.length && !ext.length)
+ return true;
+ if (!e.length || !ext.length)
+ return false;
+ return FileName.equals(e, ext);
+ }
+
+ unittest
+ {
+ assert(!equalsExt("foo.bar"[], "d"));
+ assert(equalsExt("foo.bar"[], "bar"));
+ assert(equalsExt("object.d"[], "d"));
+ assert(!equalsExt("object"[], "d"));
+ }
+
+ /******************************
+ * Return !=0 if extensions match.
+ */
+ extern (C++) bool equalsExt(const(char)* ext) const pure @nogc
+ {
+ return equalsExt(str, ext.toDString());
+ }
+
+ /*************************************
+ * Search paths for file.
+ * Params:
+ * path = array of path strings
+ * name = file to look for
+ * cwd = true means search current directory before searching path
+ * Returns:
+ * if found, filename combined with path, otherwise null
+ */
+ extern (C++) static const(char)* searchPath(Strings* path, const(char)* name, bool cwd)
+ {
+ return searchPath(path, name.toDString, cwd).ptr;
+ }
+
+ extern (D) static const(char)[] searchPath(Strings* path, const(char)[] name, bool cwd)
+ {
+ if (absolute(name))
+ {
+ return exists(name) ? name : null;
+ }
+ if (cwd)
+ {
+ if (exists(name))
+ return name;
+ }
+ if (path)
+ {
+ foreach (p; *path)
+ {
+ auto n = combine(p.toDString, name);
+ if (exists(n))
+ return n;
+ //combine might return name
+ if (n.ptr != name.ptr)
+ {
+ mem.xfree(cast(void*)n.ptr);
+ }
+ }
+ }
+ return null;
+ }
+
+ extern (D) static const(char)[] searchPath(const(char)* path, const(char)[] name, bool cwd)
+ {
+ if (absolute(name))
+ {
+ return exists(name) ? name : null;
+ }
+ if (cwd)
+ {
+ if (exists(name))
+ return name;
+ }
+ if (path && *path)
+ {
+ const(char)[] result;
+
+ int sink(const(char)* p) nothrow
+ {
+ auto n = combine(p.toDString, name);
+ mem.xfree(cast(void*)p);
+ if (exists(n))
+ {
+ result = n;
+ return 1; // done with splitPath() call
+ }
+ return 0;
+ }
+
+ splitPath(&sink, path);
+ return result;
+ }
+ return null;
+ }
+
+ /************************************
+ * Determine if path contains reserved character.
+ * Params:
+ * name = path
+ * Returns:
+ * index of the first reserved character in path if found, size_t.max otherwise
+ */
+ extern (D) static size_t findReservedChar(const(char)* name) pure @nogc
+ {
+ version (Windows)
+ {
+ size_t idx = 0;
+ // According to https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions
+ // the following characters are not allowed in path: < > : " | ? *
+ for (const(char)* p = name; *p; p++, idx++)
+ {
+ char c = *p;
+ if (c == '<' || c == '>' || c == ':' || c == '"' || c == '|' || c == '?' || c == '*')
+ {
+ return idx;
+ }
+ }
+ return size_t.max;
+ }
+ else
+ {
+ return size_t.max;
+ }
+ }
+ unittest
+ {
+ assert(findReservedChar(r"") == size_t.max);
+ assert(findReservedChar(r" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.-_=+()") == size_t.max);
+
+ version (Windows)
+ {
+ assert(findReservedChar(` < `) == 1);
+ assert(findReservedChar(` >`) == 1);
+ assert(findReservedChar(`: `) == 0);
+ assert(findReservedChar(`"`) == 0);
+ assert(findReservedChar(`|`) == 0);
+ assert(findReservedChar(`?`) == 0);
+ assert(findReservedChar(`*`) == 0);
+ }
+ else
+ {
+ assert(findReservedChar(`<>:"|?*`) == size_t.max);
+ }
+ }
+
+ /************************************
+ * Determine if path has a reference to parent directory.
+ * Params:
+ * name = path
+ * Returns:
+ * true if path contains '..' reference to parent directory
+ */
+ extern (D) static bool refersToParentDir(const(char)* name) pure @nogc
+ {
+ if (name[0] == '.' && name[1] == '.' && (!name[2] || isDirSeparator(name[2])))
+ {
+ return true;
+ }
+
+ for (const(char)* p = name; *p; p++)
+ {
+ char c = *p;
+ if (isDirSeparator(c) && p[1] == '.' && p[2] == '.' && (!p[3] || isDirSeparator(p[3])))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ unittest
+ {
+ assert(!refersToParentDir(r""));
+ assert(!refersToParentDir(r"foo"));
+ assert(!refersToParentDir(r"foo.."));
+ assert(!refersToParentDir(r"foo..boo"));
+ assert(!refersToParentDir(r"foo/..boo"));
+ assert(!refersToParentDir(r"foo../boo"));
+ assert(refersToParentDir(r".."));
+ assert(refersToParentDir(r"../"));
+ assert(refersToParentDir(r"foo/.."));
+ assert(refersToParentDir(r"foo/../"));
+ assert(refersToParentDir(r"foo/../../boo"));
+
+ version (Windows)
+ {
+ // Backslash as directory separator
+ assert(!refersToParentDir(r"foo\..boo"));
+ assert(!refersToParentDir(r"foo..\boo"));
+ assert(refersToParentDir(r"..\"));
+ assert(refersToParentDir(r"foo\.."));
+ assert(refersToParentDir(r"foo\..\"));
+ assert(refersToParentDir(r"foo\..\..\boo"));
+ }
+ }
+
+
+ /**
+ Check if the file the `path` points to exists
+
+ Returns:
+ 0 if it does not exists
+ 1 if it exists and is not a directory
+ 2 if it exists and is a directory
+ */
+ extern (C++) static int exists(const(char)* name)
+ {
+ return exists(name.toDString);
+ }
+
+ /// Ditto
+ extern (D) static int exists(const(char)[] name)
+ {
+ if (!name.length)
+ return 0;
+ version (Posix)
+ {
+ stat_t st;
+ if (name.toCStringThen!((v) => stat(v.ptr, &st)) < 0)
+ return 0;
+ if (S_ISDIR(st.st_mode))
+ return 2;
+ return 1;
+ }
+ else version (Windows)
+ {
+ return name.toWStringzThen!((wname)
+ {
+ const dw = GetFileAttributesW(&wname[0]);
+ if (dw == -1)
+ return 0;
+ else if (dw & FILE_ATTRIBUTE_DIRECTORY)
+ return 2;
+ else
+ return 1;
+ });
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+
+ /**
+ Ensure that the provided path exists
+
+ Accepts a path to either a file or a directory.
+ In the former case, the basepath (path to the containing directory)
+ will be checked for existence, and created if it does not exists.
+ In the later case, the directory pointed to will be checked for existence
+ and created if needed.
+
+ Params:
+ path = a path to a file or a directory
+
+ Returns:
+ `true` if the directory exists or was successfully created
+ */
+ extern (D) static bool ensurePathExists(const(char)[] path)
+ {
+ //printf("FileName::ensurePathExists(%s)\n", path ? path : "");
+ if (!path.length)
+ return true;
+ if (exists(path))
+ return true;
+
+ // We were provided with a file name
+ // We need to call ourselves recursively to ensure parent dir exist
+ const char[] p = FileName.path(path);
+ if (p.length)
+ {
+ version (Windows)
+ {
+ // Note: Windows filename comparison should be case-insensitive,
+ // however p is a subslice of path so we don't need it
+ if (path.length == p.length ||
+ (path.length > 2 && path[1] == ':' && path[2 .. $] == p))
+ {
+ mem.xfree(cast(void*)p.ptr);
+ return true;
+ }
+ }
+ const r = ensurePathExists(p);
+ mem.xfree(cast(void*)p);
+
+ if (!r)
+ return r;
+ }
+
+ version (Windows)
+ const r = _mkdir(path);
+ version (Posix)
+ {
+ errno = 0;
+ const r = path.toCStringThen!((pathCS) => mkdir(pathCS.ptr, (7 << 6) | (7 << 3) | 7));
+ }
+
+ if (r == 0)
+ return true;
+
+ // Don't error out if another instance of dmd just created
+ // this directory
+ version (Windows)
+ {
+ import core.sys.windows.winerror : ERROR_ALREADY_EXISTS;
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ return true;
+ }
+ version (Posix)
+ {
+ if (errno == EEXIST)
+ return true;
+ }
+
+ return false;
+ }
+
+ ///ditto
+ extern (C++) static bool ensurePathExists(const(char)* path)
+ {
+ return ensurePathExists(path.toDString);
+ }
+
+ /******************************************
+ * Return canonical version of name.
+ * This code is high risk.
+ */
+ extern (C++) static const(char)* canonicalName(const(char)* name)
+ {
+ return canonicalName(name.toDString).ptr;
+ }
+
+ /// Ditto
+ extern (D) static const(char)[] canonicalName(const(char)[] name)
+ {
+ version (Posix)
+ {
+ import core.stdc.limits; // PATH_MAX
+ import core.sys.posix.unistd; // _PC_PATH_MAX
+
+ // Older versions of druntime don't have PATH_MAX defined.
+ // i.e: dmd __VERSION__ < 2085, gdc __VERSION__ < 2076.
+ static if (!__traits(compiles, PATH_MAX))
+ {
+ version (DragonFlyBSD)
+ enum PATH_MAX = 1024;
+ else version (FreeBSD)
+ enum PATH_MAX = 1024;
+ else version (linux)
+ enum PATH_MAX = 4096;
+ else version (NetBSD)
+ enum PATH_MAX = 1024;
+ else version (OpenBSD)
+ enum PATH_MAX = 1024;
+ else version (OSX)
+ enum PATH_MAX = 1024;
+ else version (Solaris)
+ enum PATH_MAX = 1024;
+ }
+
+ // Have realpath(), passing a NULL destination pointer may return an
+ // internally malloc'd buffer, however it is implementation defined
+ // as to what happens, so cannot rely on it.
+ static if (__traits(compiles, PATH_MAX))
+ {
+ // Have compile time limit on filesystem path, use it with realpath.
+ char[PATH_MAX] buf = void;
+ auto path = name.toCStringThen!((n) => realpath(n.ptr, buf.ptr));
+ if (path !is null)
+ return xarraydup(path.toDString);
+ }
+ else static if (__traits(compiles, canonicalize_file_name))
+ {
+ // Have canonicalize_file_name, which malloc's memory.
+ // We need a dmd.root.rmem allocation though.
+ auto path = name.toCStringThen!((n) => canonicalize_file_name(n.ptr));
+ scope(exit) .free(path.ptr);
+ if (path !is null)
+ return xarraydup(path.toDString);
+ }
+ else static if (__traits(compiles, _PC_PATH_MAX))
+ {
+ // Panic! Query the OS for the buffer limit.
+ auto path_max = pathconf("/", _PC_PATH_MAX);
+ if (path_max > 0)
+ {
+ char *buf = cast(char*)mem.xmalloc(path_max);
+ scope(exit) mem.xfree(buf);
+ auto path = name.toCStringThen!((n) => realpath(n.ptr, buf));
+ if (path !is null)
+ return xarraydup(path.toDString);
+ }
+ }
+ // Give up trying to support this platform, just duplicate the filename
+ // unless there is nothing to copy from.
+ if (!name.length)
+ return null;
+ return xarraydup(name);
+ }
+ else version (Windows)
+ {
+ // Convert to wstring first since otherwise the Win32 APIs have a character limit
+ return name.toWStringzThen!((wname)
+ {
+ /* Apparently, there is no good way to do this on Windows.
+ * GetFullPathName isn't it, but use it anyway.
+ */
+ // First find out how long the buffer has to be, incl. terminating null.
+ const capacity = GetFullPathNameW(&wname[0], 0, null, null);
+ if (!capacity) return null;
+ auto buffer = cast(wchar*) mem.xmalloc_noscan(capacity * wchar.sizeof);
+ scope(exit) mem.xfree(buffer);
+
+ // Actually get the full path name. If the buffer is large enough,
+ // the returned length does NOT include the terminating null...
+ const length = GetFullPathNameW(&wname[0], capacity, buffer, null /*filePart*/);
+ assert(length == capacity - 1);
+
+ return toNarrowStringz(buffer[0 .. length]);
+ });
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+
+ unittest
+ {
+ string filename = "foo.bar";
+ const path = canonicalName(filename);
+ scope(exit) free(path.ptr);
+ assert(path.length >= filename.length);
+ assert(path[$ - filename.length .. $] == filename);
+ }
+
+ /********************************
+ * Free memory allocated by FileName routines
+ */
+ extern (C++) static void free(const(char)* str) pure
+ {
+ if (str)
+ {
+ assert(str[0] != cast(char)0xAB);
+ memset(cast(void*)str, 0xAB, strlen(str) + 1); // stomp
+ }
+ mem.xfree(cast(void*)str);
+ }
+
+ extern (C++) const(char)* toChars() const pure nothrow @nogc @trusted
+ {
+ // Since we can return an empty slice (but '\0' terminated),
+ // we don't do bounds check (as `&str[0]` does)
+ return str.ptr;
+ }
+
+ const(char)[] toString() const pure nothrow @nogc @trusted
+ {
+ return str;
+ }
+
+ bool opCast(T)() const pure nothrow @nogc @safe
+ if (is(T == bool))
+ {
+ return str.ptr !is null;
+ }
+}
+
+version(Windows)
+{
+ /****************************************************************
+ * The code before used the POSIX function `mkdir` on Windows. That
+ * function is now deprecated and fails with long paths, so instead
+ * we use the newer `CreateDirectoryW`.
+ *
+ * `CreateDirectoryW` is the unicode version of the generic macro
+ * `CreateDirectory`. `CreateDirectoryA` has a file path
+ * limitation of 248 characters, `mkdir` fails with less and might
+ * fail due to the number of consecutive `..`s in the
+ * path. `CreateDirectoryW` also normally has a 248 character
+ * limit, unless the path is absolute and starts with `\\?\`. Note
+ * that this is different from starting with the almost identical
+ * `\\?`.
+ *
+ * Params:
+ * path = The path to create.
+ *
+ * Returns:
+ * 0 on success, 1 on failure.
+ *
+ * References:
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa363855(v=vs.85).aspx
+ */
+ private int _mkdir(const(char)[] path) nothrow
+ {
+ const createRet = path.extendedPathThen!(
+ p => CreateDirectoryW(&p[0], null /*securityAttributes*/));
+ // different conventions for CreateDirectory and mkdir
+ return createRet == 0 ? 1 : 0;
+ }
+
+ /**************************************
+ * Converts a path to one suitable to be passed to Win32 API
+ * functions that can deal with paths longer than 248
+ * characters then calls the supplied function on it.
+ *
+ * Params:
+ * path = The Path to call F on.
+ *
+ * Returns:
+ * The result of calling F on path.
+ *
+ * References:
+ * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+ */
+ package auto extendedPathThen(alias F)(const(char)[] path)
+ {
+ if (!path.length)
+ return F((wchar[]).init);
+ return path.toWStringzThen!((wpath)
+ {
+ // GetFullPathNameW expects a sized buffer to store the result in. Since we don't
+ // know how large it has to be, we pass in null and get the needed buffer length
+ // as the return code.
+ const pathLength = GetFullPathNameW(&wpath[0],
+ 0 /*length8*/,
+ null /*output buffer*/,
+ null /*filePartBuffer*/);
+ if (pathLength == 0)
+ {
+ return F((wchar[]).init);
+ }
+
+ // wpath is the UTF16 version of path, but to be able to use
+ // extended paths, we need to prefix with `\\?\` and the absolute
+ // path.
+ static immutable prefix = `\\?\`w;
+
+ // prefix only needed for long names and non-UNC names
+ const needsPrefix = pathLength >= MAX_PATH && (wpath[0] != '\\' || wpath[1] != '\\');
+ const prefixLength = needsPrefix ? prefix.length : 0;
+
+ // +1 for the null terminator
+ const bufferLength = pathLength + prefixLength + 1;
+
+ wchar[1024] absBuf = void;
+ wchar[] absPath = bufferLength > absBuf.length
+ ? new wchar[bufferLength] : absBuf[0 .. bufferLength];
+
+ absPath[0 .. prefixLength] = prefix[0 .. prefixLength];
+
+ const absPathRet = GetFullPathNameW(&wpath[0],
+ cast(uint)(absPath.length - prefixLength - 1),
+ &absPath[prefixLength],
+ null /*filePartBuffer*/);
+
+ if (absPathRet == 0 || absPathRet > absPath.length - prefixLength)
+ {
+ return F((wchar[]).init);
+ }
+
+ absPath[$ - 1] = '\0';
+ // Strip null terminator from the slice
+ return F(absPath[0 .. $ - 1]);
+ });
+ }
+
+ /**********************************
+ * Converts a UTF-16 string to a (null-terminated) narrow string.
+ * Returns:
+ * If `buffer` is specified and the result fits, a slice of that buffer,
+ * otherwise a new buffer which can be released via `mem.xfree()`.
+ * Nulls are propagated, i.e., if `wide` is null, the returned slice is
+ * null too.
+ */
+ char[] toNarrowStringz(const(wchar)[] wide, char[] buffer = null) nothrow
+ {
+ if (wide is null)
+ return null;
+
+ const requiredLength = WideCharToMultiByte(CodePage, 0, wide.ptr, cast(int) wide.length, buffer.ptr, cast(int) buffer.length, null, null);
+ if (requiredLength < buffer.length)
+ {
+ buffer[requiredLength] = 0;
+ return buffer[0 .. requiredLength];
+ }
+
+ char* newBuffer = cast(char*) mem.xmalloc_noscan(requiredLength + 1);
+ const length = WideCharToMultiByte(CodePage, 0, wide.ptr, cast(int) wide.length, newBuffer, requiredLength, null, null);
+ assert(length == requiredLength);
+ newBuffer[length] = 0;
+ return newBuffer[0 .. length];
+ }
+
+ /**********************************
+ * Converts a narrow string to a (null-terminated) UTF-16 string.
+ * Returns:
+ * If `buffer` is specified and the result fits, a slice of that buffer,
+ * otherwise a new buffer which can be released via `mem.xfree()`.
+ * Nulls are propagated, i.e., if `narrow` is null, the returned slice is
+ * null too.
+ */
+ wchar[] toWStringz(const(char)[] narrow, wchar[] buffer = null) nothrow
+ {
+ if (narrow is null)
+ return null;
+
+ const requiredLength = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length);
+ if (requiredLength < buffer.length)
+ {
+ buffer[requiredLength] = 0;
+ return buffer[0 .. requiredLength];
+ }
+
+ wchar* newBuffer = cast(wchar*) mem.xmalloc_noscan((requiredLength + 1) * wchar.sizeof);
+ const length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, newBuffer, requiredLength);
+ assert(length == requiredLength);
+ newBuffer[length] = 0;
+ return newBuffer[0 .. length];
+ }
+
+ /**********************************
+ * Converts a slice of UTF-8 characters to an array of wchar that's null
+ * terminated so it can be passed to Win32 APIs then calls the supplied
+ * function on it.
+ *
+ * Params:
+ * str = The string to convert.
+ *
+ * Returns:
+ * The result of calling F on the UTF16 version of str.
+ */
+ private auto toWStringzThen(alias F)(const(char)[] str) nothrow
+ {
+ if (!str.length) return F(""w.ptr);
+
+ wchar[1024] buf = void;
+ wchar[] wide = toWStringz(str, buf);
+ scope(exit) wide.ptr != buf.ptr && mem.xfree(wide.ptr);
+
+ return F(wide);
+ }
+}
diff --git a/gcc/d/dmd/root/filename.h b/gcc/d/dmd/root/filename.h
index 52cd963..9f773b5 100644
--- a/gcc/d/dmd/root/filename.h
+++ b/gcc/d/dmd/root/filename.h
@@ -1,5 +1,6 @@
/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
@@ -9,20 +10,16 @@
#pragma once
#include "array.h"
+#include "dcompat.h"
-class RootObject;
-
-template <typename TYPE> struct Array;
typedef Array<const char *> Strings;
struct FileName
{
- const char *str;
- FileName(const char *str);
- bool equals(RootObject *obj);
+private:
+ DString str;
+public:
static bool equals(const char *name1, const char *name2);
- int compare(RootObject *obj);
- static int compare(const char *name1, const char *name2);
static bool absolute(const char *name);
static const char *toAbsolute(const char *name, const char *base = NULL);
static const char *ext(const char *);
@@ -31,7 +28,6 @@ struct FileName
static const char *name(const char *);
const char *name();
static const char *path(const char *);
- static const char *replaceName(const char *path, const char *name);
static const char *combine(const char *path, const char *name);
static Strings *splitPath(const char *path);
@@ -42,7 +38,6 @@ struct FileName
bool equalsExt(const char *ext);
static const char *searchPath(Strings *path, const char *name, bool cwd);
- static const char *safeSearchPath(Strings *path, const char *name);
static int exists(const char *name);
static bool ensurePathExists(const char *path);
static const char *canonicalName(const char *name);
diff --git a/gcc/d/dmd/root/hash.d b/gcc/d/dmd/root/hash.d
new file mode 100644
index 0000000..f484819
--- /dev/null
+++ b/gcc/d/dmd/root/hash.d
@@ -0,0 +1,83 @@
+/**
+ * Hash functions for arbitrary binary data.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Martin Nowak, Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/hash.d, root/_hash.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_hash.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/hash.d
+ */
+
+module dmd.root.hash;
+
+// MurmurHash2 was written by Austin Appleby, and is placed in the public
+// domain. The author hereby disclaims copyright to this source code.
+// https://sites.google.com/site/murmurhash/
+uint calcHash(scope const(char)[] data) @nogc nothrow pure @safe
+{
+ return calcHash(cast(const(ubyte)[])data);
+}
+
+/// ditto
+uint calcHash(scope const(ubyte)[] data) @nogc nothrow pure @safe
+{
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+ enum uint m = 0x5bd1e995;
+ enum int r = 24;
+ // Initialize the hash to a 'random' value
+ uint h = cast(uint) data.length;
+ // Mix 4 bytes at a time into the hash
+ while (data.length >= 4)
+ {
+ uint k = data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0];
+ k *= m;
+ k ^= k >> r;
+ h = (h * m) ^ (k * m);
+ data = data[4..$];
+ }
+ // Handle the last few bytes of the input array
+ switch (data.length & 3)
+ {
+ case 3:
+ h ^= data[2] << 16;
+ goto case;
+ case 2:
+ h ^= data[1] << 8;
+ goto case;
+ case 1:
+ h ^= data[0];
+ h *= m;
+ goto default;
+ default:
+ break;
+ }
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+ return h;
+}
+
+unittest
+{
+ char[10] data = "0123456789";
+ assert(calcHash(data[0..$]) == 439_272_720);
+ assert(calcHash(data[1..$]) == 3_704_291_687);
+ assert(calcHash(data[2..$]) == 2_125_368_748);
+ assert(calcHash(data[3..$]) == 3_631_432_225);
+}
+
+// combine and mix two words (boost::hash_combine)
+size_t mixHash(size_t h, size_t k) @nogc nothrow pure @safe
+{
+ return h ^ (k + 0x9e3779b9 + (h << 6) + (h >> 2));
+}
+
+unittest
+{
+ // & uint.max because mixHash output is truncated on 32-bit targets
+ assert((mixHash(0xDE00_1540, 0xF571_1A47) & uint.max) == 0x952D_FC10);
+}
diff --git a/gcc/d/dmd/root/longdouble.d b/gcc/d/dmd/root/longdouble.d
new file mode 100644
index 0000000..a845c97
--- /dev/null
+++ b/gcc/d/dmd/root/longdouble.d
@@ -0,0 +1,140 @@
+/**
+ * 80-bit floating point value implementation if the C/D compiler does not support them natively.
+ * Copyright (C) 2021 Free Software Foundation, Inc.
+ *
+ * GCC 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, or (at your option)
+ * any later version.
+ *
+ * GCC 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/>.
+ */
+
+module dmd.root.longdouble;
+
+import core.stdc.config;
+import core.stdc.stdint;
+
+extern(C++):
+nothrow:
+@nogc:
+
+// Type used by the front-end for compile-time reals
+struct longdouble
+{
+ extern (D) this(T)(T r)
+ {
+ this.set(cast(SetType!T)r);
+ }
+
+ // No constructor to be able to use this class in a union.
+ extern (D) longdouble opAssign(T)(T r)
+ if (is (T : longdouble))
+ {
+ this.realvalue = r.realvalue;
+ return this;
+ }
+
+ extern (D) longdouble opAssign(T)(T r)
+ if (!is (T : longdouble))
+ {
+ this.set(cast(SetType!T)r);
+ return this;
+ }
+
+ // Arithmetic operators.
+ extern (D) longdouble opBinary(string op, T)(T r) const
+ if ((op == "+" || op == "-" || op == "*" || op == "/" || op == "%")
+ && is (T : longdouble))
+ {
+ static if (op == "+")
+ return this.add(r);
+ else static if (op == "-")
+ return this.sub(r);
+ else static if (op == "*")
+ return this.mul(r);
+ else static if (op == "/")
+ return this.div(r);
+ else static if (op == "%")
+ return this.mod(r);
+ }
+
+ extern (D) longdouble opUnary(string op)() const
+ if (op == "-")
+ {
+ return this.neg();
+ }
+
+ extern (D) int opCmp(longdouble r) const
+ {
+ return this.cmp(r);
+ }
+
+ extern (D) int opEquals(longdouble r) const
+ {
+ return this.equals(r);
+ }
+
+ extern (D) bool opCast(T : bool)() const
+ {
+ return this.to_bool();
+ }
+
+ extern (D) T opCast(T)() const
+ {
+ static if (__traits(isUnsigned, T))
+ return cast (T) this.to_uint();
+ else
+ return cast(T) this.to_int();
+ }
+
+ void set(int8_t d);
+ void set(int16_t d);
+ void set(int32_t d);
+ void set(int64_t d);
+ void set(uint8_t d);
+ void set(uint16_t d);
+ void set(uint32_t d);
+ void set(uint64_t d);
+ void set(bool d);
+
+ int64_t to_int() const;
+ uint64_t to_uint() const;
+ bool to_bool() const;
+
+ longdouble add(const ref longdouble r) const;
+ longdouble sub(const ref longdouble r) const;
+ longdouble mul(const ref longdouble r) const;
+ longdouble div(const ref longdouble r) const;
+ longdouble mod(const ref longdouble r) const;
+ longdouble neg() const;
+ int cmp(const ref longdouble t) const;
+ int equals(const ref longdouble t) const;
+
+private:
+ // Statically allocate enough space for REAL_VALUE_TYPE.
+ enum REALVALUE_SIZE = (2 + (16 + c_long.sizeof) / c_long.sizeof);
+ c_long [REALVALUE_SIZE] realvalue;
+}
+
+// Pick the corresponding (u)int64_t type for T, as int64_t may be
+// a special enum that requires casting to explicitly.
+private template SetType(T)
+{
+ static if (__traits(isIntegral, T) && T.sizeof == 8)
+ {
+ static if (__traits(isUnsigned, T))
+ alias SetType = uint64_t;
+ else
+ alias SetType = int64_t;
+ }
+ else
+ alias SetType = T;
+}
diff --git a/gcc/d/dmd/root/object.h b/gcc/d/dmd/root/object.h
index d5e3b2b..fb367bc 100644
--- a/gcc/d/dmd/root/object.h
+++ b/gcc/d/dmd/root/object.h
@@ -1,14 +1,16 @@
/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
- * https://github.com/dlang/dmd/blob/master/src/root/object.h
+ * http://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/root/object.h
*/
#pragma once
#include "dsystem.h"
+#include "dcompat.h"
typedef size_t hash_t;
@@ -23,7 +25,8 @@ enum DYNCAST
DYNCAST_IDENTIFIER,
DYNCAST_TUPLE,
DYNCAST_PARAMETER,
- DYNCAST_STATEMENT
+ DYNCAST_STATEMENT,
+ DYNCAST_TEMPLATEPARAMETER
};
/*
@@ -34,25 +37,19 @@ class RootObject
public:
RootObject() { }
- virtual bool equals(RootObject *o);
-
- /**
- * Return <0, ==0, or >0 if this is less than, equal to, or greater than obj.
- * Useful for sorting Objects.
- */
- virtual int compare(RootObject *obj);
+ virtual bool equals(const RootObject *o) const;
/**
* Pretty-print an Object. Useful for debugging the old-fashioned way.
*/
- virtual void print();
-
- virtual const char *toChars();
- virtual void toBuffer(OutBuffer *buf);
+ virtual const char *toChars() const;
+ /// This function is `extern(D)` and should not be called from C++,
+ /// as the ABI does not match on some platforms
+ virtual DString toString();
/**
* Used as a replacement for dynamic_cast. Returns a unique number
* defined by the library user. For Object, the return value is 0.
*/
- virtual int dyncast() const;
+ virtual DYNCAST dyncast() const;
};
diff --git a/gcc/d/dmd/root/outbuffer.c b/gcc/d/dmd/root/outbuffer.c
deleted file mode 100644
index 7fbbfe5..0000000
--- a/gcc/d/dmd/root/outbuffer.c
+++ /dev/null
@@ -1,417 +0,0 @@
-
-/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
- * https://github.com/D-Programming-Language/dmd/blob/master/src/root/outbuffer.c
- */
-
-#include "dsystem.h"
-#include "outbuffer.h"
-#include "object.h"
-
-char *OutBuffer::extractData()
-{
- char *p;
-
- p = (char *)data.ptr;
- data = DArray<unsigned char>();
- offset = 0;
- return p;
-}
-
-void OutBuffer::reserve(size_t nbytes)
-{
- //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", data.length, offset, nbytes);
- if (data.length - offset < nbytes)
- {
- data.length = (offset + nbytes) * 2;
- data.length = (data.length + 15) & ~15;
- data.ptr = (unsigned char *)mem.xrealloc(data.ptr, data.length);
- }
-}
-
-void OutBuffer::reset()
-{
- offset = 0;
-}
-
-void OutBuffer::setsize(size_t size)
-{
- offset = size;
-}
-
-void OutBuffer::write(const void *data, size_t nbytes)
-{
- if (doindent && !notlinehead)
- {
- if (level)
- {
- reserve(level);
- for (int i = 0; i < level; i++)
- {
- this->data.ptr[offset] = '\t';
- offset++;
- }
- }
- notlinehead = 1;
- }
- reserve(nbytes);
- memcpy(this->data.ptr + offset, data, nbytes);
- offset += nbytes;
-}
-
-void OutBuffer::writestring(const char *string)
-{
- write(string,strlen(string));
-}
-
-void OutBuffer::prependstring(const char *string)
-{
- size_t len = strlen(string);
- reserve(len);
- memmove(data.ptr + len, data.ptr, offset);
- memcpy(data.ptr, string, len);
- offset += len;
-}
-
-void OutBuffer::writenl()
-{
-#if _WIN32
- writeword(0x0A0D); // newline is CR,LF on Microsoft OS's
-#else
- writeByte('\n');
-#endif
- if (doindent)
- notlinehead = 0;
-}
-
-void OutBuffer::writeByte(unsigned b)
-{
- if (doindent && !notlinehead
- && b != '\n')
- {
- if (level)
- {
- reserve(level);
- for (int i = 0; i < level; i++)
- {
- this->data.ptr[offset] = '\t';
- offset++;
- }
- }
- notlinehead = 1;
- }
- reserve(1);
- this->data.ptr[offset] = (unsigned char)b;
- offset++;
-}
-
-void OutBuffer::writeUTF8(unsigned b)
-{
- reserve(6);
- if (b <= 0x7F)
- {
- this->data.ptr[offset] = (unsigned char)b;
- offset++;
- }
- else if (b <= 0x7FF)
- {
- this->data.ptr[offset + 0] = (unsigned char)((b >> 6) | 0xC0);
- this->data.ptr[offset + 1] = (unsigned char)((b & 0x3F) | 0x80);
- offset += 2;
- }
- else if (b <= 0xFFFF)
- {
- this->data.ptr[offset + 0] = (unsigned char)((b >> 12) | 0xE0);
- this->data.ptr[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
- this->data.ptr[offset + 2] = (unsigned char)((b & 0x3F) | 0x80);
- offset += 3;
- }
- else if (b <= 0x1FFFFF)
- {
- this->data.ptr[offset + 0] = (unsigned char)((b >> 18) | 0xF0);
- this->data.ptr[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
- this->data.ptr[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
- this->data.ptr[offset + 3] = (unsigned char)((b & 0x3F) | 0x80);
- offset += 4;
- }
- else if (b <= 0x3FFFFFF)
- {
- this->data.ptr[offset + 0] = (unsigned char)((b >> 24) | 0xF8);
- this->data.ptr[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
- this->data.ptr[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
- this->data.ptr[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
- this->data.ptr[offset + 4] = (unsigned char)((b & 0x3F) | 0x80);
- offset += 5;
- }
- else if (b <= 0x7FFFFFFF)
- {
- this->data.ptr[offset + 0] = (unsigned char)((b >> 30) | 0xFC);
- this->data.ptr[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80);
- this->data.ptr[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80);
- this->data.ptr[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80);
- this->data.ptr[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80);
- this->data.ptr[offset + 5] = (unsigned char)((b & 0x3F) | 0x80);
- offset += 6;
- }
- else
- assert(0);
-}
-
-void OutBuffer::prependbyte(unsigned b)
-{
- reserve(1);
- memmove(data.ptr + 1, data.ptr, offset);
- data.ptr[0] = (unsigned char)b;
- offset++;
-}
-
-void OutBuffer::writewchar(unsigned w)
-{
-#if _WIN32
- writeword(w);
-#else
- write4(w);
-#endif
-}
-
-void OutBuffer::writeword(unsigned w)
-{
-#if _WIN32
- unsigned newline = 0x0A0D;
-#else
- unsigned newline = '\n';
-#endif
- if (doindent && !notlinehead
- && w != newline)
- {
- if (level)
- {
- reserve(level);
- for (int i = 0; i < level; i++)
- {
- this->data.ptr[offset] = '\t';
- offset++;
- }
- }
- notlinehead = 1;
- }
- reserve(2);
- *(unsigned short *)(this->data.ptr + offset) = (unsigned short)w;
- offset += 2;
-}
-
-void OutBuffer::writeUTF16(unsigned w)
-{
- reserve(4);
- if (w <= 0xFFFF)
- {
- *(unsigned short *)(this->data.ptr + offset) = (unsigned short)w;
- offset += 2;
- }
- else if (w <= 0x10FFFF)
- {
- *(unsigned short *)(this->data.ptr + offset) = (unsigned short)((w >> 10) + 0xD7C0);
- *(unsigned short *)(this->data.ptr + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00);
- offset += 4;
- }
- else
- assert(0);
-}
-
-void OutBuffer::write4(unsigned w)
-{
-#if _WIN32
- bool notnewline = w != 0x000A000D;
-#else
- bool notnewline = true;
-#endif
- if (doindent && !notlinehead && notnewline)
- {
- if (level)
- {
- reserve(level);
- for (int i = 0; i < level; i++)
- {
- this->data.ptr[offset] = '\t';
- offset++;
- }
- }
- notlinehead = 1;
- }
- reserve(4);
- *(unsigned *)(this->data.ptr + offset) = w;
- offset += 4;
-}
-
-void OutBuffer::write(OutBuffer *buf)
-{
- if (buf)
- { reserve(buf->offset);
- memcpy(data.ptr + offset, buf->data.ptr, buf->offset);
- offset += buf->offset;
- }
-}
-
-void OutBuffer::write(RootObject *obj)
-{
- if (obj)
- {
- writestring(obj->toChars());
- }
-}
-
-void OutBuffer::fill0(size_t nbytes)
-{
- reserve(nbytes);
- memset(data.ptr + offset,0,nbytes);
- offset += nbytes;
-}
-
-void OutBuffer::vprintf(const char *format, va_list args)
-{
- int count;
-
- if (doindent)
- write(NULL, 0); // perform indent
- int psize = 128;
- for (;;)
- {
- reserve(psize);
-#if _WIN32
- count = _vsnprintf((char *)data.ptr + offset,psize,format,args);
- if (count != -1)
- break;
- psize *= 2;
-#elif POSIX
- va_list va;
- va_copy(va, args);
-/*
- The functions vprintf(), vfprintf(), vsprintf(), vsnprintf()
- are equivalent to the functions printf(), fprintf(), sprintf(),
- snprintf(), respectively, except that they are called with a
- va_list instead of a variable number of arguments. These
- functions do not call the va_end macro. Consequently, the value
- of ap is undefined after the call. The application should call
- va_end(ap) itself afterwards.
- */
- count = vsnprintf((char *)data.ptr + offset,psize,format,va);
- va_end(va);
- if (count == -1)
- psize *= 2;
- else if (count >= psize)
- psize = count + 1;
- else
- break;
-#else
- assert(0);
-#endif
- }
- offset += count;
-}
-
-void OutBuffer::printf(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- vprintf(format,ap);
- va_end(ap);
-}
-
-/**************************************
- * Convert `u` to a string and append it to the buffer.
- * Params:
- * u = integral value to append
- */
-void OutBuffer::print(unsigned long long u)
-{
- unsigned long long value = u;
- char buf[20];
- const unsigned radix = 10;
-
- size_t i = sizeof(buf);
- do
- {
- if (value < radix)
- {
- unsigned char x = (unsigned char)value;
- buf[--i] = (char)(x + '0');
- break;
- }
- else
- {
- unsigned char x = (unsigned char)(value % radix);
- value = value / radix;
- buf[--i] = (char)(x + '0');
- }
- } while (value);
-
- write(buf + i, sizeof(buf) - i);
-}
-
-void OutBuffer::bracket(char left, char right)
-{
- reserve(2);
- memmove(data.ptr + 1, data.ptr, offset);
- data.ptr[0] = left;
- data.ptr[offset + 1] = right;
- offset += 2;
-}
-
-/******************
- * Insert left at i, and right at j.
- * Return index just past right.
- */
-
-size_t OutBuffer::bracket(size_t i, const char *left, size_t j, const char *right)
-{
- size_t leftlen = strlen(left);
- size_t rightlen = strlen(right);
- reserve(leftlen + rightlen);
- insert(i, left, leftlen);
- insert(j + leftlen, right, rightlen);
- return j + leftlen + rightlen;
-}
-
-void OutBuffer::spread(size_t offset, size_t nbytes)
-{
- reserve(nbytes);
- memmove(data.ptr + offset + nbytes, data.ptr + offset,
- this->offset - offset);
- this->offset += nbytes;
-}
-
-/****************************************
- * Returns: offset + nbytes
- */
-
-size_t OutBuffer::insert(size_t offset, const void *p, size_t nbytes)
-{
- spread(offset, nbytes);
- memmove(data.ptr + offset, p, nbytes);
- return offset + nbytes;
-}
-
-void OutBuffer::remove(size_t offset, size_t nbytes)
-{
- memmove(data.ptr + offset, data.ptr + offset + nbytes, this->offset - (offset + nbytes));
- this->offset -= nbytes;
-}
-
-char *OutBuffer::peekChars()
-{
- if (!offset || data.ptr[offset-1] != '\0')
- {
- writeByte(0);
- offset--; // allow appending more
- }
- return (char *)data.ptr;
-}
-
-char *OutBuffer::extractChars()
-{
- if (!offset || data.ptr[offset-1] != '\0')
- writeByte(0);
- return extractData();
-}
diff --git a/gcc/d/dmd/root/outbuffer.d b/gcc/d/dmd/root/outbuffer.d
new file mode 100644
index 0000000..e756917
--- /dev/null
+++ b/gcc/d/dmd/root/outbuffer.d
@@ -0,0 +1,720 @@
+/**
+ * An expandable buffer in which you can write text or binary data.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.d, root/_outbuffer.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_outbuffer.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/outbuffer.d
+ */
+
+module dmd.root.outbuffer;
+
+import core.stdc.stdarg;
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.root.rmem;
+import dmd.root.rootobject;
+import dmd.root.string;
+
+debug
+{
+ debug = stomp; // flush out dangling pointer problems by stomping on unused memory
+}
+
+/**
+`OutBuffer` is a write-only output stream of untyped data. It is backed up by
+a contiguous array or a memory-mapped file.
+*/
+struct OutBuffer
+{
+ import dmd.root.file : FileMapping;
+
+ // IMPORTANT: PLEASE KEEP STATE AND DESTRUCTOR IN SYNC WITH DEFINITION IN ./outbuffer.h.
+ // state {
+ private ubyte[] data;
+ private size_t offset;
+ private bool notlinehead;
+ /// File mapping, if any. Use a pointer for ABI compatibility with the C++ counterpart.
+ /// If the pointer is non-null the store is a memory-mapped file, otherwise the store is RAM.
+ private FileMapping!ubyte* fileMapping;
+ /// Whether to indent
+ bool doindent;
+ /// Whether to indent by 4 spaces or by tabs;
+ bool spaces;
+ /// Current indent level
+ int level;
+ // state }
+
+ /**
+ Construct from filename. Will map the file into memory (or create it anew
+ if necessary) and start writing at the beginning of it.
+
+ Params:
+ filename = zero-terminated name of file to map into memory
+ */
+ @trusted this(const(char)* filename)
+ {
+ fileMapping = new FileMapping!ubyte(filename);
+ data = (*fileMapping)[];
+ }
+
+ /**
+ Frees resources associated automatically.
+ */
+ extern (C++) ~this() pure nothrow
+ {
+ if (fileMapping)
+ {
+ if (fileMapping.active)
+ fileMapping.close();
+ fileMapping = null;
+ }
+ else
+ {
+ debug (stomp) memset(data.ptr, 0xFF, data.length);
+ mem.xfree(data.ptr);
+ }
+ }
+
+ extern (C++) size_t length() const pure @nogc @safe nothrow { return offset; }
+
+ /**********************
+ * Transfer ownership of the allocated data to the caller.
+ * Returns:
+ * pointer to the allocated data
+ */
+ extern (C++) char* extractData() pure nothrow @nogc @trusted
+ {
+ char* p = cast(char*)data.ptr;
+ data = null;
+ offset = 0;
+ return p;
+ }
+
+ /**
+ Releases all resources associated with `this` and resets it as an empty
+ memory buffer. The config variables `notlinehead`, `doindent` etc. are
+ not changed.
+ */
+ extern (C++) void destroy() pure nothrow @trusted
+ {
+ if (fileMapping && fileMapping.active)
+ {
+ fileMapping.close();
+ data = null;
+ offset = 0;
+ }
+ else
+ {
+ debug (stomp) memset(data.ptr, 0xFF, data.length);
+ mem.xfree(extractData());
+ }
+ }
+
+ /**
+ Reserves `nbytes` bytes of additional memory (or file space) in advance.
+ The resulting capacity is at least the previous length plus `nbytes`.
+
+ Params:
+ nbytes = the number of additional bytes to reserve
+ */
+ extern (C++) void reserve(size_t nbytes) pure nothrow
+ {
+ //debug (stomp) printf("OutBuffer::reserve: size = %lld, offset = %lld, nbytes = %lld\n", data.length, offset, nbytes);
+ const minSize = offset + nbytes;
+ if (data.length >= minSize)
+ return;
+
+ /* Increase by factor of 1.5; round up to 16 bytes.
+ * The odd formulation is so it will map onto single x86 LEA instruction.
+ */
+ const size = ((minSize * 3 + 30) / 2) & ~15;
+
+ if (fileMapping && fileMapping.active)
+ {
+ fileMapping.resize(size);
+ data = (*fileMapping)[];
+ }
+ else
+ {
+ debug (stomp)
+ {
+ auto p = cast(ubyte*)mem.xmalloc(size);
+ memcpy(p, data.ptr, offset);
+ memset(data.ptr, 0xFF, data.length); // stomp old location
+ mem.xfree(data.ptr);
+ memset(p + offset, 0xff, size - offset); // stomp unused data
+ }
+ else
+ {
+ auto p = cast(ubyte*)mem.xrealloc(data.ptr, size);
+ if (mem.isGCEnabled) // clear currently unused data to avoid false pointers
+ memset(p + offset + nbytes, 0xff, size - offset - nbytes);
+ }
+ data = p[0 .. size];
+ }
+ }
+
+ /************************
+ * Shrink the size of the data to `size`.
+ * Params:
+ * size = new size of data, must be <= `.length`
+ */
+ extern (C++) void setsize(size_t size) pure nothrow @nogc @safe
+ {
+ assert(size <= offset);
+ offset = size;
+ }
+
+ extern (C++) void reset() pure nothrow @nogc @safe
+ {
+ offset = 0;
+ }
+
+ private void indent() pure nothrow
+ {
+ if (level)
+ {
+ const indentLevel = spaces ? level * 4 : level;
+ reserve(indentLevel);
+ data[offset .. offset + indentLevel] = (spaces ? ' ' : '\t');
+ offset += indentLevel;
+ }
+ notlinehead = true;
+ }
+
+ extern (C++) void write(const(void)* data, size_t nbytes) pure nothrow
+ {
+ write(data[0 .. nbytes]);
+ }
+
+ void write(const(void)[] buf) pure nothrow
+ {
+ if (doindent && !notlinehead)
+ indent();
+ reserve(buf.length);
+ memcpy(this.data.ptr + offset, buf.ptr, buf.length);
+ offset += buf.length;
+ }
+
+ extern (C++) void writestring(const(char)* string) pure nothrow
+ {
+ write(string.toDString);
+ }
+
+ void writestring(const(char)[] s) pure nothrow
+ {
+ write(s);
+ }
+
+ void writestring(string s) pure nothrow
+ {
+ write(s);
+ }
+
+ void writestringln(const(char)[] s) pure nothrow
+ {
+ writestring(s);
+ writenl();
+ }
+
+ extern (C++) void prependstring(const(char)* string) pure nothrow
+ {
+ size_t len = strlen(string);
+ reserve(len);
+ memmove(data.ptr + len, data.ptr, offset);
+ memcpy(data.ptr, string, len);
+ offset += len;
+ }
+
+ /// write newline
+ extern (C++) void writenl() pure nothrow
+ {
+ version (Windows)
+ {
+ writeword(0x0A0D); // newline is CR,LF on Microsoft OS's
+ }
+ else
+ {
+ writeByte('\n');
+ }
+ if (doindent)
+ notlinehead = false;
+ }
+
+ extern (C++) void writeByte(uint b) pure nothrow
+ {
+ if (doindent && !notlinehead && b != '\n')
+ indent();
+ reserve(1);
+ this.data[offset] = cast(ubyte)b;
+ offset++;
+ }
+
+ extern (C++) void writeUTF8(uint b) pure nothrow
+ {
+ reserve(6);
+ if (b <= 0x7F)
+ {
+ this.data[offset] = cast(ubyte)b;
+ offset++;
+ }
+ else if (b <= 0x7FF)
+ {
+ this.data[offset + 0] = cast(ubyte)((b >> 6) | 0xC0);
+ this.data[offset + 1] = cast(ubyte)((b & 0x3F) | 0x80);
+ offset += 2;
+ }
+ else if (b <= 0xFFFF)
+ {
+ this.data[offset + 0] = cast(ubyte)((b >> 12) | 0xE0);
+ this.data[offset + 1] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80);
+ this.data[offset + 2] = cast(ubyte)((b & 0x3F) | 0x80);
+ offset += 3;
+ }
+ else if (b <= 0x1FFFFF)
+ {
+ this.data[offset + 0] = cast(ubyte)((b >> 18) | 0xF0);
+ this.data[offset + 1] = cast(ubyte)(((b >> 12) & 0x3F) | 0x80);
+ this.data[offset + 2] = cast(ubyte)(((b >> 6) & 0x3F) | 0x80);
+ this.data[offset + 3] = cast(ubyte)((b & 0x3F) | 0x80);
+ offset += 4;
+ }
+ else
+ assert(0);
+ }
+
+ extern (C++) void prependbyte(uint b) pure nothrow
+ {
+ reserve(1);
+ memmove(data.ptr + 1, data.ptr, offset);
+ data[0] = cast(ubyte)b;
+ offset++;
+ }
+
+ extern (C++) void writewchar(uint w) pure nothrow
+ {
+ version (Windows)
+ {
+ writeword(w);
+ }
+ else
+ {
+ write4(w);
+ }
+ }
+
+ extern (C++) void writeword(uint w) pure nothrow
+ {
+ version (Windows)
+ {
+ uint newline = 0x0A0D;
+ }
+ else
+ {
+ uint newline = '\n';
+ }
+ if (doindent && !notlinehead && w != newline)
+ indent();
+
+ reserve(2);
+ *cast(ushort*)(this.data.ptr + offset) = cast(ushort)w;
+ offset += 2;
+ }
+
+ extern (C++) void writeUTF16(uint w) pure nothrow
+ {
+ reserve(4);
+ if (w <= 0xFFFF)
+ {
+ *cast(ushort*)(this.data.ptr + offset) = cast(ushort)w;
+ offset += 2;
+ }
+ else if (w <= 0x10FFFF)
+ {
+ *cast(ushort*)(this.data.ptr + offset) = cast(ushort)((w >> 10) + 0xD7C0);
+ *cast(ushort*)(this.data.ptr + offset + 2) = cast(ushort)((w & 0x3FF) | 0xDC00);
+ offset += 4;
+ }
+ else
+ assert(0);
+ }
+
+ extern (C++) void write4(uint w) pure nothrow
+ {
+ version (Windows)
+ {
+ bool notnewline = w != 0x000A000D;
+ }
+ else
+ {
+ bool notnewline = true;
+ }
+ if (doindent && !notlinehead && notnewline)
+ indent();
+ reserve(4);
+ *cast(uint*)(this.data.ptr + offset) = w;
+ offset += 4;
+ }
+
+ extern (C++) void write(const OutBuffer* buf) pure nothrow
+ {
+ if (buf)
+ {
+ reserve(buf.offset);
+ memcpy(data.ptr + offset, buf.data.ptr, buf.offset);
+ offset += buf.offset;
+ }
+ }
+
+ extern (C++) void write(RootObject obj) /*nothrow*/
+ {
+ if (obj)
+ {
+ writestring(obj.toChars());
+ }
+ }
+
+ extern (C++) void fill0(size_t nbytes) pure nothrow
+ {
+ reserve(nbytes);
+ memset(data.ptr + offset, 0, nbytes);
+ offset += nbytes;
+ }
+
+ /**
+ * Allocate space, but leave it uninitialized.
+ * Params:
+ * nbytes = amount to allocate
+ * Returns:
+ * slice of the allocated space to be filled in
+ */
+ extern (D) char[] allocate(size_t nbytes) pure nothrow
+ {
+ reserve(nbytes);
+ offset += nbytes;
+ return cast(char[])data[offset - nbytes .. offset];
+ }
+
+ extern (C++) void vprintf(const(char)* format, va_list args) nothrow
+ {
+ int count;
+ if (doindent && !notlinehead)
+ indent();
+ uint psize = 128;
+ for (;;)
+ {
+ reserve(psize);
+ va_list va;
+ va_copy(va, args);
+ /*
+ The functions vprintf(), vfprintf(), vsprintf(), vsnprintf()
+ are equivalent to the functions printf(), fprintf(), sprintf(),
+ snprintf(), respectively, except that they are called with a
+ va_list instead of a variable number of arguments. These
+ functions do not call the va_end macro. Consequently, the value
+ of ap is undefined after the call. The application should call
+ va_end(ap) itself afterwards.
+ */
+ count = vsnprintf(cast(char*)data.ptr + offset, psize, format, va);
+ va_end(va);
+ if (count == -1) // snn.lib and older libcmt.lib return -1 if buffer too small
+ psize *= 2;
+ else if (count >= psize)
+ psize = count + 1;
+ else
+ break;
+ }
+ offset += count;
+ if (mem.isGCEnabled)
+ memset(data.ptr + offset, 0xff, psize - count);
+ }
+
+ static if (__VERSION__ < 2092)
+ {
+ extern (C++) void printf(const(char)* format, ...) nothrow
+ {
+ va_list ap;
+ va_start(ap, format);
+ vprintf(format, ap);
+ va_end(ap);
+ }
+ }
+ else
+ {
+ pragma(printf) extern (C++) void printf(const(char)* format, ...) nothrow
+ {
+ va_list ap;
+ va_start(ap, format);
+ vprintf(format, ap);
+ va_end(ap);
+ }
+ }
+
+ /**************************************
+ * Convert `u` to a string and append it to the buffer.
+ * Params:
+ * u = integral value to append
+ */
+ extern (C++) void print(ulong u) pure nothrow
+ {
+ //import core.internal.string; // not available
+ UnsignedStringBuf buf = void;
+ writestring(unsignedToTempString(u, buf));
+ }
+
+ extern (C++) void bracket(char left, char right) pure nothrow
+ {
+ reserve(2);
+ memmove(data.ptr + 1, data.ptr, offset);
+ data[0] = left;
+ data[offset + 1] = right;
+ offset += 2;
+ }
+
+ /******************
+ * Insert left at i, and right at j.
+ * Return index just past right.
+ */
+ extern (C++) size_t bracket(size_t i, const(char)* left, size_t j, const(char)* right) pure nothrow
+ {
+ size_t leftlen = strlen(left);
+ size_t rightlen = strlen(right);
+ reserve(leftlen + rightlen);
+ insert(i, left, leftlen);
+ insert(j + leftlen, right, rightlen);
+ return j + leftlen + rightlen;
+ }
+
+ extern (C++) void spread(size_t offset, size_t nbytes) pure nothrow
+ {
+ reserve(nbytes);
+ memmove(data.ptr + offset + nbytes, data.ptr + offset, this.offset - offset);
+ this.offset += nbytes;
+ }
+
+ /****************************************
+ * Returns: offset + nbytes
+ */
+ extern (C++) size_t insert(size_t offset, const(void)* p, size_t nbytes) pure nothrow
+ {
+ spread(offset, nbytes);
+ memmove(data.ptr + offset, p, nbytes);
+ return offset + nbytes;
+ }
+
+ size_t insert(size_t offset, const(char)[] s) pure nothrow
+ {
+ return insert(offset, s.ptr, s.length);
+ }
+
+ extern (C++) void remove(size_t offset, size_t nbytes) pure nothrow @nogc
+ {
+ memmove(data.ptr + offset, data.ptr + offset + nbytes, this.offset - (offset + nbytes));
+ this.offset -= nbytes;
+ }
+
+ /**
+ * Returns:
+ * a non-owning const slice of the buffer contents
+ */
+ extern (D) const(char)[] opSlice() const pure nothrow @nogc @safe
+ {
+ return cast(const(char)[])data[0 .. offset];
+ }
+
+ extern (D) const(char)[] opSlice(size_t lwr, size_t upr) const pure nothrow @nogc @safe
+ {
+ return cast(const(char)[])data[lwr .. upr];
+ }
+
+ extern (D) char opIndex(size_t i) const pure nothrow @nogc @safe
+ {
+ return cast(char)data[i];
+ }
+
+ /***********************************
+ * Extract the data as a slice and take ownership of it.
+ *
+ * When `true` is passed as an argument, this function behaves
+ * like `dmd.utils.toDString(thisbuffer.extractChars())`.
+ *
+ * Params:
+ * nullTerminate = When `true`, the data will be `null` terminated.
+ * This is useful to call C functions or store
+ * the result in `Strings`. Defaults to `false`.
+ */
+ extern (D) char[] extractSlice(bool nullTerminate = false) pure nothrow
+ {
+ const length = offset;
+ if (!nullTerminate)
+ return extractData()[0 .. length];
+ // There's already a terminating `'\0'`
+ if (length && data[length - 1] == '\0')
+ return extractData()[0 .. length - 1];
+ writeByte(0);
+ return extractData()[0 .. length];
+ }
+
+ // Append terminating null if necessary and get view of internal buffer
+ extern (C++) char* peekChars() pure nothrow
+ {
+ if (!offset || data[offset - 1] != '\0')
+ {
+ writeByte(0);
+ offset--; // allow appending more
+ }
+ return cast(char*)data.ptr;
+ }
+
+ // Append terminating null if necessary and take ownership of data
+ extern (C++) char* extractChars() pure nothrow
+ {
+ if (!offset || data[offset - 1] != '\0')
+ writeByte(0);
+ return extractData();
+ }
+
+ /**
+ Destructively saves the contents of `this` to `filename`. As an
+ optimization, if the file already has identical contents with the buffer,
+ no copying is done. This is because on SSD drives reading is often much
+ faster than writing and because there's a high likelihood an identical
+ file is written during the build process.
+
+ Params:
+ filename = the name of the file to receive the contents
+
+ Returns: `true` iff the operation succeeded.
+ */
+ extern(D) bool moveToFile(const char* filename)
+ {
+ import dmd.root.file;
+ bool result = true;
+ const bool identical = this[] == FileMapping!(const ubyte)(filename)[];
+
+ if (fileMapping && fileMapping.active)
+ {
+ // Defer to corresponding functions in FileMapping.
+ if (identical)
+ {
+ result = fileMapping.discard();
+ }
+ else
+ {
+ // Resize to fit to get rid of the slack bytes at the end
+ fileMapping.resize(offset);
+ result = fileMapping.moveToFile(filename);
+ }
+ // Can't call destroy() here because the file mapping is already closed.
+ data = null;
+ offset = 0;
+ }
+ else
+ {
+ if (!identical)
+ File.write(filename, this[]);
+ destroy();
+ }
+
+ return identical
+ ? result && File.touch(filename)
+ : result;
+ }
+}
+
+/****** copied from core.internal.string *************/
+
+private:
+
+alias UnsignedStringBuf = char[20];
+
+char[] unsignedToTempString(ulong value, char[] buf, uint radix = 10) @safe pure nothrow @nogc
+{
+ size_t i = buf.length;
+ do
+ {
+ if (value < radix)
+ {
+ ubyte x = cast(ubyte)value;
+ buf[--i] = cast(char)((x < 10) ? x + '0' : x - 10 + 'a');
+ break;
+ }
+ else
+ {
+ ubyte x = cast(ubyte)(value % radix);
+ value = value / radix;
+ buf[--i] = cast(char)((x < 10) ? x + '0' : x - 10 + 'a');
+ }
+ } while (value);
+ return buf[i .. $];
+}
+
+/************* unit tests **************************************************/
+
+unittest
+{
+ OutBuffer buf;
+ buf.printf("betty");
+ buf.insert(1, "xx".ptr, 2);
+ buf.insert(3, "yy");
+ buf.remove(4, 1);
+ buf.bracket('(', ')');
+ const char[] s = buf[];
+ assert(s == "(bxxyetty)");
+ buf.destroy();
+}
+
+unittest
+{
+ OutBuffer buf;
+ buf.writestring("abc".ptr);
+ buf.prependstring("def");
+ buf.prependbyte('x');
+ OutBuffer buf2;
+ buf2.writestring("mmm");
+ buf.write(&buf2);
+ char[] s = buf.extractSlice();
+ assert(s == "xdefabcmmm");
+}
+
+unittest
+{
+ OutBuffer buf;
+ buf.writeByte('a');
+ char[] s = buf.extractSlice();
+ assert(s == "a");
+
+ buf.writeByte('b');
+ char[] t = buf.extractSlice();
+ assert(t == "b");
+}
+
+unittest
+{
+ OutBuffer buf;
+ char* p = buf.peekChars();
+ assert(*p == 0);
+
+ buf.writeByte('s');
+ char* q = buf.peekChars();
+ assert(strcmp(q, "s") == 0);
+}
+
+unittest
+{
+ char[10] buf;
+ char[] s = unsignedToTempString(278, buf[], 10);
+ assert(s == "278");
+
+ s = unsignedToTempString(1, buf[], 10);
+ assert(s == "1");
+
+ s = unsignedToTempString(8, buf[], 2);
+ assert(s == "1000");
+
+ s = unsignedToTempString(29, buf[], 16);
+ assert(s == "1d");
+}
diff --git a/gcc/d/dmd/root/outbuffer.h b/gcc/d/dmd/root/outbuffer.h
index 186fbb7..b635373 100644
--- a/gcc/d/dmd/root/outbuffer.h
+++ b/gcc/d/dmd/root/outbuffer.h
@@ -1,5 +1,6 @@
/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
@@ -16,14 +17,16 @@ class RootObject;
struct OutBuffer
{
+ // IMPORTANT: PLEASE KEEP STATE AND DESTRUCTOR IN SYNC WITH DEFINITION IN ./outbuffer.d.
private:
DArray<unsigned char> data;
- size_t offset;
+ d_size_t offset;
bool notlinehead;
+ void* fileMapping; // pointer to a file mapping object not used on the C++ side
public:
-
- int level;
bool doindent;
+ bool spaces;
+ int level;
OutBuffer()
{
@@ -33,17 +36,18 @@ public:
doindent = 0;
level = 0;
notlinehead = 0;
+ fileMapping = 0;
}
~OutBuffer()
{
mem.xfree(data.ptr);
}
- const DArray<unsigned char> slice() const { return data; }
- size_t length() const { return offset; }
+ d_size_t length() const { return offset; }
char *extractData();
+ void destroy();
- void reserve(size_t nbytes);
- void setsize(size_t size);
+ void reserve(d_size_t nbytes);
+ void setsize(d_size_t size);
void reset();
void write(const void *data, size_t nbytes);
void writestring(const char *string);
@@ -56,17 +60,16 @@ public:
void writeword(unsigned w);
void writeUTF16(unsigned w);
void write4(unsigned w);
- void write(OutBuffer *buf);
+ void write(const OutBuffer *buf);
void write(RootObject *obj);
- void fill0(size_t nbytes);
+ void fill0(d_size_t nbytes);
void vprintf(const char *format, va_list args);
void printf(const char *format, ...);
- void print(unsigned long long u);
void bracket(char left, char right);
- size_t bracket(size_t i, const char *left, size_t j, const char *right);
- void spread(size_t offset, size_t nbytes);
- size_t insert(size_t offset, const void *data, size_t nbytes);
- void remove(size_t offset, size_t nbytes);
+ d_size_t bracket(d_size_t i, const char *left, d_size_t j, const char *right);
+ void spread(d_size_t offset, d_size_t nbytes);
+ d_size_t insert(d_size_t offset, const void *data, d_size_t nbytes);
+ void remove(d_size_t offset, d_size_t nbytes);
// Append terminating null if necessary and get view of internal buffer
char *peekChars();
// Append terminating null if necessary and take ownership of data
diff --git a/gcc/d/dmd/root/port.d b/gcc/d/dmd/root/port.d
new file mode 100644
index 0000000..1bafa20
--- /dev/null
+++ b/gcc/d/dmd/root/port.d
@@ -0,0 +1,49 @@
+/**
+ * Portable routines for functions that have different implementations on different platforms.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/port.d, root/_port.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_port.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/port.d
+ */
+
+module dmd.root.port;
+
+import core.stdc.stdint;
+
+nothrow @nogc:
+
+extern (C++) struct Port
+{
+ nothrow @nogc:
+
+ static int memicmp(scope const char* s1, scope const char* s2, size_t n) pure;
+
+ static char* strupr(char* s) pure;
+
+ static bool isFloat32LiteralOutOfRange(scope const(char)* s);
+
+ static bool isFloat64LiteralOutOfRange(scope const(char)* s);
+
+ // Little endian
+ static void writelongLE(uint value, scope void* buffer) pure;
+
+ // Little endian
+ static uint readlongLE(scope const void* buffer) pure;
+
+ // Big endian
+ static void writelongBE(uint value, scope void* buffer) pure;
+
+ // Big endian
+ static uint readlongBE(scope const void* buffer) pure;
+
+ // Little endian
+ static uint readwordLE(scope const void* buffer) pure;
+
+ // Big endian
+ static uint readwordBE(scope const void* buffer) pure;
+
+ static void valcpy(scope void *dst, uint64_t val, size_t size) pure;
+}
diff --git a/gcc/d/dmd/root/port.h b/gcc/d/dmd/root/port.h
index 94651cd..08cf66c 100644
--- a/gcc/d/dmd/root/port.h
+++ b/gcc/d/dmd/root/port.h
@@ -1,5 +1,6 @@
/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
@@ -11,15 +12,7 @@
// Portable wrapper around compiler/system specific things.
// The idea is to minimize #ifdef's in the app code.
-#include "dsystem.h" // for alloca
-
-#if _MSC_VER
-typedef __int64 longlong;
-typedef unsigned __int64 ulonglong;
-#else
-typedef long long longlong;
-typedef unsigned long long ulonglong;
-#endif
+#include "dsystem.h"
typedef unsigned char utf8_t;
diff --git a/gcc/d/dmd/root/region.d b/gcc/d/dmd/root/region.d
new file mode 100644
index 0000000..50689fe
--- /dev/null
+++ b/gcc/d/dmd/root/region.d
@@ -0,0 +1,161 @@
+/**
+ * Region storage allocator implementation.
+ *
+ * Copyright: Copyright (C) 2019-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/region.d, root/_region.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_region.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/region.d
+ */
+
+module dmd.root.region;
+
+import core.stdc.stdio;
+import core.stdc.string;
+import core.stdc.stdlib;
+
+import dmd.root.rmem;
+import dmd.root.array;
+
+/*****
+ * Simple region storage allocator.
+ */
+struct Region
+{
+ nothrow:
+ private:
+
+ Array!(void*) array; // array of chunks
+ int used; // number of chunks used in array[]
+ void[] available; // slice of chunk that's available to allocate
+
+ enum ChunkSize = 4096 * 1024;
+ enum MaxAllocSize = ChunkSize;
+
+ struct RegionPos
+ {
+ int used;
+ void[] available;
+ }
+
+public:
+
+ /******
+ * Allocate nbytes. Aborts on failure.
+ * Params:
+ * nbytes = number of bytes to allocate, can be 0, must be <= than MaxAllocSize
+ * Returns:
+ * allocated data, null for nbytes==0
+ */
+ void* malloc(size_t nbytes)
+ {
+ if (!nbytes)
+ return null;
+
+ nbytes = (nbytes + 15) & ~15;
+ if (nbytes > available.length)
+ {
+ assert(nbytes <= MaxAllocSize);
+ if (used == array.length)
+ {
+ auto h = Mem.check(.malloc(ChunkSize));
+ array.push(h);
+ }
+
+ available = array[used][0 .. MaxAllocSize];
+ ++used;
+ }
+
+ auto p = available.ptr;
+ available = (p + nbytes)[0 .. available.length - nbytes];
+ return p;
+ }
+
+ /****************************
+ * Return stack position for allocations in this region.
+ * Returns:
+ * an opaque struct to be passed to `release()`
+ */
+ RegionPos savePos() pure @nogc @safe
+ {
+ return RegionPos(used, available);
+ }
+
+ /********************
+ * Release the memory that was allocated after the respective call to `savePos()`.
+ * Params:
+ * pos = position returned by `savePos()`
+ */
+ void release(RegionPos pos) pure @nogc @safe
+ {
+ version (all)
+ {
+ /* Recycle the memory. There better not be
+ * any live pointers to it.
+ */
+ used = pos.used;
+ available = pos.available;
+ }
+ else
+ {
+ /* Instead of recycling the memory, stomp on it
+ * to flush out any remaining live pointers to it.
+ */
+ (cast(ubyte[])pos.available)[] = 0xFF;
+ foreach (h; array[pos.used .. used])
+ (cast(ubyte*)h)[0 .. ChunkSize] = 0xFF;
+ }
+ }
+
+ /****************************
+ * If pointer points into Region.
+ * Params:
+ * p = pointer to check
+ * Returns:
+ * true if it points into the region
+ */
+ bool contains(void* p) pure @nogc
+ {
+ foreach (h; array[0 .. used])
+ {
+ if (h <= p && p < h + ChunkSize)
+ return true;
+ }
+ return false;
+ }
+
+ /*********************
+ * Returns: size of Region
+ */
+ size_t size() pure @nogc @safe
+ {
+ return used * MaxAllocSize - available.length;
+ }
+}
+
+
+unittest
+{
+ Region reg;
+ auto rgnpos = reg.savePos();
+
+ void* p = reg.malloc(0);
+ assert(p == null);
+ assert(!reg.contains(p));
+
+ p = reg.malloc(100);
+ assert(p !is null);
+ assert(reg.contains(p));
+ memset(p, 0, 100);
+
+ p = reg.malloc(100);
+ assert(p !is null);
+ assert(reg.contains(p));
+ memset(p, 0, 100);
+
+ assert(reg.size() > 0);
+ assert(!reg.contains(&reg));
+
+ reg.release(rgnpos);
+}
diff --git a/gcc/d/dmd/root/rmem.c b/gcc/d/dmd/root/rmem.c
deleted file mode 100644
index 768b75d..0000000
--- a/gcc/d/dmd/root/rmem.c
+++ /dev/null
@@ -1,191 +0,0 @@
-
-/* Copyright (C) 2000-2021 by The D Language Foundation, All Rights Reserved
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
- * https://github.com/D-Programming-Language/dmd/blob/master/src/root/rmem.c
- */
-
-#include "dsystem.h"
-#include "rmem.h"
-
-/* This implementation of the storage allocator uses the standard C allocation package.
- */
-
-Mem mem;
-
-char *Mem::xstrdup(const char *s)
-{
- char *p;
-
- if (s)
- {
-#ifdef IN_GCC
- p = ::xstrdup(s);
-#else
- p = strdup(s);
-#endif
- if (p)
- return p;
- error();
- }
- return NULL;
-}
-
-void *Mem::xmalloc(size_t size)
-{ void *p;
-
- if (!size)
- p = NULL;
- else
- {
-#ifdef IN_GCC
- p = ::xmalloc(size);
-#else
- p = malloc(size);
-#endif
- if (!p)
- error();
- }
- return p;
-}
-
-void *Mem::xcalloc(size_t size, size_t n)
-{ void *p;
-
- if (!size || !n)
- p = NULL;
- else
- {
-#ifdef IN_GCC
- p = ::xcalloc(size, n);
-#else
- p = calloc(size, n);
-#endif
- if (!p)
- error();
- }
- return p;
-}
-
-void *Mem::xrealloc(void *p, size_t size)
-{
- if (!size)
- { if (p)
- {
- free(p);
- p = NULL;
- }
- }
- else if (!p)
- {
-#ifdef IN_GCC
- p = ::xmalloc(size);
-#else
- p = malloc(size);
-#endif
- if (!p)
- error();
- }
- else
- {
- void *psave = p;
-#ifdef IN_GCC
- p = ::xrealloc(psave, size);
-#else
- p = realloc(psave, size);
-#endif
- if (!p)
- { xfree(psave);
- error();
- }
- }
- return p;
-}
-
-void Mem::xfree(void *p)
-{
- if (p)
- free(p);
-}
-
-void *Mem::xmallocdup(void *o, size_t size)
-{ void *p;
-
- if (!size)
- p = NULL;
- else
- {
-#ifdef IN_GCC
- p = ::xmalloc(size);
-#else
- p = malloc(size);
-#endif
- if (!p)
- error();
- else
- memcpy(p,o,size);
- }
- return p;
-}
-
-void Mem::error()
-{
- printf("Error: out of memory\n");
- exit(EXIT_FAILURE);
-}
-
-/* =================================================== */
-
-/* Allocate, but never release
- */
-
-// Allocate a little less than 1Mb because the C runtime adds some overhead that
-// causes the actual memory block to be larger than 1Mb otherwise.
-#define CHUNK_SIZE (256 * 4096 - 64)
-
-static size_t heapleft = 0;
-static void *heapp;
-
-extern "C" void *allocmemory(size_t m_size)
-{
- // 16 byte alignment is better (and sometimes needed) for doubles
- m_size = (m_size + 15) & ~15;
-
- // The layout of the code is selected so the most common case is straight through
- if (m_size <= heapleft)
- {
- L1:
- heapleft -= m_size;
- void *p = heapp;
- heapp = (void *)((char *)heapp + m_size);
- return p;
- }
-
- if (m_size > CHUNK_SIZE)
- {
-#ifdef IN_GCC
- void *p = xmalloc(m_size);
-#else
- void *p = malloc(m_size);
-#endif
- if (p)
- return p;
- printf("Error: out of memory\n");
- exit(EXIT_FAILURE);
- return p;
- }
-
- heapleft = CHUNK_SIZE;
-#ifdef IN_GCC
- heapp = xmalloc(CHUNK_SIZE);
-#else
- heapp = malloc(CHUNK_SIZE);
-#endif
- if (!heapp)
- {
- printf("Error: out of memory\n");
- exit(EXIT_FAILURE);
- }
- goto L1;
-}
diff --git a/gcc/d/dmd/root/rmem.d b/gcc/d/dmd/root/rmem.d
new file mode 100644
index 0000000..198f3d0
--- /dev/null
+++ b/gcc/d/dmd/root/rmem.d
@@ -0,0 +1,375 @@
+/**
+ * Allocate memory using `malloc` or the GC depending on the configuration.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/rmem.d, root/_rmem.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_rmem.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/rmem.d
+ */
+
+module dmd.root.rmem;
+
+import core.exception : onOutOfMemoryError;
+import core.stdc.stdio;
+import core.stdc.stdlib;
+import core.stdc.string;
+
+import core.memory : GC;
+
+extern (C++) struct Mem
+{
+ static char* xstrdup(const(char)* s) nothrow
+ {
+ if (isGCEnabled)
+ return s ? s[0 .. strlen(s) + 1].dup.ptr : null;
+
+ return s ? cast(char*)check(.strdup(s)) : null;
+ }
+
+ static void xfree(void* p) pure nothrow
+ {
+ if (isGCEnabled)
+ return GC.free(p);
+
+ pureFree(p);
+ }
+
+ static void* xmalloc(size_t size) pure nothrow
+ {
+ if (isGCEnabled)
+ return size ? GC.malloc(size) : null;
+
+ return size ? check(pureMalloc(size)) : null;
+ }
+
+ static void* xmalloc_noscan(size_t size) pure nothrow
+ {
+ if (isGCEnabled)
+ return size ? GC.malloc(size, GC.BlkAttr.NO_SCAN) : null;
+
+ return size ? check(pureMalloc(size)) : null;
+ }
+
+ static void* xcalloc(size_t size, size_t n) pure nothrow
+ {
+ if (isGCEnabled)
+ return size * n ? GC.calloc(size * n) : null;
+
+ return (size && n) ? check(pureCalloc(size, n)) : null;
+ }
+
+ static void* xcalloc_noscan(size_t size, size_t n) pure nothrow
+ {
+ if (isGCEnabled)
+ return size * n ? GC.calloc(size * n, GC.BlkAttr.NO_SCAN) : null;
+
+ return (size && n) ? check(pureCalloc(size, n)) : null;
+ }
+
+ static void* xrealloc(void* p, size_t size) pure nothrow
+ {
+ if (isGCEnabled)
+ return GC.realloc(p, size);
+
+ if (!size)
+ {
+ pureFree(p);
+ return null;
+ }
+
+ return check(pureRealloc(p, size));
+ }
+
+ static void* xrealloc_noscan(void* p, size_t size) pure nothrow
+ {
+ if (isGCEnabled)
+ return GC.realloc(p, size, GC.BlkAttr.NO_SCAN);
+
+ if (!size)
+ {
+ pureFree(p);
+ return null;
+ }
+
+ return check(pureRealloc(p, size));
+ }
+
+ static void* error() pure nothrow @nogc @safe
+ {
+ onOutOfMemoryError();
+ assert(0);
+ }
+
+ /**
+ * Check p for null. If it is, issue out of memory error
+ * and exit program.
+ * Params:
+ * p = pointer to check for null
+ * Returns:
+ * p if not null
+ */
+ static void* check(void* p) pure nothrow @nogc
+ {
+ return p ? p : error();
+ }
+
+ __gshared bool _isGCEnabled = true;
+
+ // fake purity by making global variable immutable (_isGCEnabled only modified before startup)
+ enum _pIsGCEnabled = cast(immutable bool*) &_isGCEnabled;
+
+ static bool isGCEnabled() pure nothrow @nogc @safe
+ {
+ return *_pIsGCEnabled;
+ }
+
+ static void disableGC() nothrow @nogc
+ {
+ _isGCEnabled = false;
+ }
+
+ static void addRange(const(void)* p, size_t size) nothrow @nogc
+ {
+ if (isGCEnabled)
+ GC.addRange(p, size);
+ }
+
+ static void removeRange(const(void)* p) nothrow @nogc
+ {
+ if (isGCEnabled)
+ GC.removeRange(p);
+ }
+}
+
+extern (C++) const __gshared Mem mem;
+
+enum CHUNK_SIZE = (256 * 4096 - 64);
+
+__gshared size_t heapleft = 0;
+__gshared void* heapp;
+
+extern (D) void* allocmemoryNoFree(size_t m_size) nothrow @nogc
+{
+ // 16 byte alignment is better (and sometimes needed) for doubles
+ m_size = (m_size + 15) & ~15;
+
+ // The layout of the code is selected so the most common case is straight through
+ if (m_size <= heapleft)
+ {
+ L1:
+ heapleft -= m_size;
+ auto p = heapp;
+ heapp = cast(void*)(cast(char*)heapp + m_size);
+ return p;
+ }
+
+ if (m_size > CHUNK_SIZE)
+ {
+ return Mem.check(malloc(m_size));
+ }
+
+ heapleft = CHUNK_SIZE;
+ heapp = Mem.check(malloc(CHUNK_SIZE));
+ goto L1;
+}
+
+extern (D) void* allocmemory(size_t m_size) nothrow
+{
+ if (mem.isGCEnabled)
+ return GC.malloc(m_size);
+
+ return allocmemoryNoFree(m_size);
+}
+
+version (DigitalMars)
+{
+ enum OVERRIDE_MEMALLOC = true;
+}
+else version (LDC)
+{
+ // Memory allocation functions gained weak linkage when the @weak attribute was introduced.
+ import ldc.attributes;
+ enum OVERRIDE_MEMALLOC = is(typeof(ldc.attributes.weak));
+}
+else version (GNU)
+{
+ version (IN_GCC)
+ enum OVERRIDE_MEMALLOC = false;
+ else
+ enum OVERRIDE_MEMALLOC = true;
+}
+else
+{
+ enum OVERRIDE_MEMALLOC = false;
+}
+
+static if (OVERRIDE_MEMALLOC)
+{
+ // Override the host druntime allocation functions in order to use the bump-
+ // pointer allocation scheme (`allocmemoryNoFree()` above) if the GC is disabled.
+ // That scheme is faster and comes with less memory overhead than using a
+ // disabled GC alone.
+
+ extern (C) void* _d_allocmemory(size_t m_size) nothrow
+ {
+ return allocmemory(m_size);
+ }
+
+ private void* allocClass(const ClassInfo ci) nothrow pure
+ {
+ alias BlkAttr = GC.BlkAttr;
+
+ assert(!(ci.m_flags & TypeInfo_Class.ClassFlags.isCOMclass));
+
+ BlkAttr attr = BlkAttr.NONE;
+ if (ci.m_flags & TypeInfo_Class.ClassFlags.hasDtor
+ && !(ci.m_flags & TypeInfo_Class.ClassFlags.isCPPclass))
+ attr |= BlkAttr.FINALIZE;
+ if (ci.m_flags & TypeInfo_Class.ClassFlags.noPointers)
+ attr |= BlkAttr.NO_SCAN;
+ return GC.malloc(ci.initializer.length, attr, ci);
+ }
+
+ extern (C) void* _d_newitemU(const TypeInfo ti) nothrow;
+
+ extern (C) Object _d_newclass(const ClassInfo ci) nothrow
+ {
+ const initializer = ci.initializer;
+
+ auto p = mem.isGCEnabled ? allocClass(ci) : allocmemoryNoFree(initializer.length);
+ memcpy(p, initializer.ptr, initializer.length);
+ return cast(Object) p;
+ }
+
+ version (LDC)
+ {
+ extern (C) Object _d_allocclass(const ClassInfo ci) nothrow
+ {
+ if (mem.isGCEnabled)
+ return cast(Object) allocClass(ci);
+
+ return cast(Object) allocmemoryNoFree(ci.initializer.length);
+ }
+ }
+
+ extern (C) void* _d_newitemT(TypeInfo ti) nothrow
+ {
+ auto p = mem.isGCEnabled ? _d_newitemU(ti) : allocmemoryNoFree(ti.tsize);
+ memset(p, 0, ti.tsize);
+ return p;
+ }
+
+ extern (C) void* _d_newitemiT(TypeInfo ti) nothrow
+ {
+ auto p = mem.isGCEnabled ? _d_newitemU(ti) : allocmemoryNoFree(ti.tsize);
+ const initializer = ti.initializer;
+ memcpy(p, initializer.ptr, initializer.length);
+ return p;
+ }
+
+ // TypeInfo.initializer for compilers older than 2.070
+ static if(!__traits(hasMember, TypeInfo, "initializer"))
+ private const(void[]) initializer(T : TypeInfo)(const T t)
+ nothrow pure @safe @nogc
+ {
+ return t.init;
+ }
+}
+
+extern (C) pure @nogc nothrow
+{
+ /**
+ * Pure variants of C's memory allocation functions `malloc`, `calloc`, and
+ * `realloc` and deallocation function `free`.
+ *
+ * UNIX 98 requires that errno be set to ENOMEM upon failure.
+ * https://linux.die.net/man/3/malloc
+ * However, this is irrelevant for DMD's purposes, and best practice
+ * protocol for using errno is to treat it as an `out` parameter, and not
+ * something with state that can be relied on across function calls.
+ * So, we'll ignore it.
+ *
+ * See_Also:
+ * $(LINK2 https://dlang.org/spec/function.html#pure-functions, D's rules for purity),
+ * which allow for memory allocation under specific circumstances.
+ */
+ pragma(mangle, "malloc") void* pureMalloc(size_t size) @trusted;
+
+ /// ditto
+ pragma(mangle, "calloc") void* pureCalloc(size_t nmemb, size_t size) @trusted;
+
+ /// ditto
+ pragma(mangle, "realloc") void* pureRealloc(void* ptr, size_t size) @system;
+
+ /// ditto
+ pragma(mangle, "free") void pureFree(void* ptr) @system;
+
+}
+
+/**
+Makes a null-terminated copy of the given string on newly allocated memory.
+The null-terminator won't be part of the returned string slice. It will be
+at position `n` where `n` is the length of the input string.
+
+Params:
+ s = string to copy
+
+Returns: A null-terminated copy of the input array.
+*/
+extern (D) char[] xarraydup(const(char)[] s) pure nothrow
+{
+ if (!s)
+ return null;
+
+ auto p = cast(char*)mem.xmalloc_noscan(s.length + 1);
+ char[] a = p[0 .. s.length];
+ a[] = s[0 .. s.length];
+ p[s.length] = 0; // preserve 0 terminator semantics
+ return a;
+}
+
+///
+pure nothrow unittest
+{
+ auto s1 = "foo";
+ auto s2 = s1.xarraydup;
+ s2[0] = 'b';
+ assert(s1 == "foo");
+ assert(s2 == "boo");
+ assert(*(s2.ptr + s2.length) == '\0');
+ string sEmpty;
+ assert(sEmpty.xarraydup is null);
+}
+
+/**
+Makes a copy of the given array on newly allocated memory.
+
+Params:
+ s = array to copy
+
+Returns: A copy of the input array.
+*/
+extern (D) T[] arraydup(T)(const scope T[] s) pure nothrow
+{
+ if (!s)
+ return null;
+
+ const dim = s.length;
+ auto p = (cast(T*)mem.xmalloc(T.sizeof * dim))[0 .. dim];
+ p[] = s;
+ return p;
+}
+
+///
+pure nothrow unittest
+{
+ auto s1 = [0, 1, 2];
+ auto s2 = s1.arraydup;
+ s2[0] = 4;
+ assert(s1 == [0, 1, 2]);
+ assert(s2 == [4, 1, 2]);
+ string sEmpty;
+ assert(sEmpty.arraydup is null);
+}
diff --git a/gcc/d/dmd/root/rmem.h b/gcc/d/dmd/root/rmem.h
index 1f603b8..04d9e3f 100644
--- a/gcc/d/dmd/root/rmem.h
+++ b/gcc/d/dmd/root/rmem.h
@@ -1,5 +1,6 @@
/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
@@ -8,19 +9,25 @@
#pragma once
-#include "dsystem.h" // for size_t
+#include "dcompat.h" // for d_size_t
struct Mem
{
Mem() { }
static char *xstrdup(const char *s);
- static void *xmalloc(size_t size);
- static void *xcalloc(size_t size, size_t n);
- static void *xrealloc(void *p, size_t size);
static void xfree(void *p);
- static void *xmallocdup(void *o, size_t size);
+ static void *xmalloc(d_size_t size);
+ static void *xcalloc(d_size_t size, d_size_t n);
+ static void *xrealloc(void *p, d_size_t size);
static void error();
+
+ static bool _isGCEnabled;
+
+ static bool isGCEnabled();
+ static void disableGC();
+ static void addRange(const void *p, d_size_t size);
+ static void removeRange(const void *p);
};
extern Mem mem;
diff --git a/gcc/d/dmd/root/root.h b/gcc/d/dmd/root/root.h
index d998d95..667ce67 100644
--- a/gcc/d/dmd/root/root.h
+++ b/gcc/d/dmd/root/root.h
@@ -1,5 +1,6 @@
/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
diff --git a/gcc/d/dmd/root/rootobject.c b/gcc/d/dmd/root/rootobject.c
deleted file mode 100644
index 7fee0d7..0000000
--- a/gcc/d/dmd/root/rootobject.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
- * https://github.com/D-Programming-Language/dmd/blob/master/src/root/object.c
- */
-
-#include "dsystem.h"
-#include "object.h"
-#include "outbuffer.h"
-
-/****************************** Object ********************************/
-
-bool RootObject::equals(RootObject *o)
-{
- return o == this;
-}
-
-int RootObject::compare(RootObject *obj)
-{
- size_t lhs = (size_t)this;
- size_t rhs = (size_t)obj;
- if (lhs < rhs)
- return -1;
- else if (lhs > rhs)
- return 1;
- return 0;
-}
-
-void RootObject::print()
-{
- printf("%s %p\n", toChars(), this);
-}
-
-const char *RootObject::toChars()
-{
- return "Object";
-}
-
-int RootObject::dyncast() const
-{
- return DYNCAST_OBJECT;
-}
-
-void RootObject::toBuffer(OutBuffer *b)
-{
- b->writestring("Object");
-}
diff --git a/gcc/d/dmd/root/rootobject.d b/gcc/d/dmd/root/rootobject.d
new file mode 100644
index 0000000..854ec1a
--- /dev/null
+++ b/gcc/d/dmd/root/rootobject.d
@@ -0,0 +1,67 @@
+/**
+ * Provide the root object that classes in dmd inherit from.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/rootobject.d, root/_rootobject.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_rootobject.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/rootobject.d
+ */
+
+module dmd.root.rootobject;
+
+import core.stdc.stdio;
+
+import dmd.root.outbuffer;
+
+/***********************************************************
+ */
+
+enum DYNCAST : int
+{
+ object,
+ expression,
+ dsymbol,
+ type,
+ identifier,
+ tuple,
+ parameter,
+ statement,
+ condition,
+ templateparameter,
+ initializer,
+}
+
+/***********************************************************
+ */
+
+extern (C++) class RootObject
+{
+ this() nothrow pure @nogc @safe
+ {
+ }
+
+ bool equals(const RootObject o) const
+ {
+ return o is this;
+ }
+
+ const(char)* toChars() const
+ {
+ assert(0);
+ }
+
+ ///
+ extern(D) const(char)[] toString() const
+ {
+ import core.stdc.string : strlen;
+ auto p = this.toChars();
+ return p[0 .. strlen(p)];
+ }
+
+ DYNCAST dyncast() const nothrow pure @nogc @safe
+ {
+ return DYNCAST.object;
+ }
+}
diff --git a/gcc/d/dmd/root/speller.c b/gcc/d/dmd/root/speller.c
deleted file mode 100644
index 3957c11..0000000
--- a/gcc/d/dmd/root/speller.c
+++ /dev/null
@@ -1,231 +0,0 @@
-
-/* Copyright (C) 2010-2021 by The D Language Foundation, All Rights Reserved
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
- * https://github.com/D-Programming-Language/dmd/blob/master/src/root/speller.c
- */
-
-#include "dsystem.h"
-#include "speller.h"
-
-const char idchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
-
-/**************************************************
- * combine a new result from the spell checker to
- * find the one with the closest symbol with
- * respect to the cost defined by the search function
- * Input/Output:
- * p best found spelling (NULL if none found yet)
- * cost cost of p (INT_MAX if none found yet)
- * Input:
- * np new found spelling (NULL if none found)
- * ncost cost of np if non-NULL
- * Returns:
- * true if the cost is less or equal 0
- * false otherwise
- */
-bool combineSpellerResult(void*& p, int& cost, void* np, int ncost)
-{
- if (np && ncost < cost)
- {
- p = np;
- cost = ncost;
- if (cost <= 0)
- return true;
- }
- return false;
-}
-
-void *spellerY(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg,
- const char *charset, size_t index, int* cost)
-{
- if (!seedlen)
- return NULL;
- assert(seed[seedlen] == 0);
-
- char tmp[30];
- char *buf;
- if (seedlen <= sizeof(tmp) - 2)
- buf = tmp;
- else
- {
- buf = (char *)alloca(seedlen + 2); // leave space for extra char
- if (!buf)
- return NULL; // no matches
- }
-
- memcpy(buf, seed, index);
- *cost = INT_MAX;
- void* p = NULL;
- int ncost = 0;
-
- /* Delete at seed[index] */
- if (index < seedlen)
- {
- memcpy(buf + index, seed + index + 1, seedlen - index);
- assert(buf[seedlen - 1] == 0);
- void* np = (*fp)(fparg, buf, &ncost);
- if (combineSpellerResult(p, *cost, np, ncost))
- return p;
- }
-
- if (charset && *charset)
- {
- /* Substitutions */
- if (index < seedlen)
- {
- memcpy(buf, seed, seedlen + 1);
- for (const char *s = charset; *s; s++)
- {
- buf[index] = *s;
-
- //printf("sub buf = '%s'\n", buf);
- void* np = (*fp)(fparg, buf, &ncost);
- if (combineSpellerResult(p, *cost, np, ncost))
- return p;
- }
- assert(buf[seedlen] == 0);
- }
-
- /* Insertions */
- memcpy (buf + index + 1, seed + index, seedlen + 1 - index);
-
- for (const char *s = charset; *s; s++)
- {
- buf[index] = *s;
-
- //printf("ins buf = '%s'\n", buf);
- void* np = (*fp)(fparg, buf, &ncost);
- if (combineSpellerResult(p, *cost, np, ncost))
- return p;
- }
- assert(buf[seedlen + 1] == 0);
- }
-
- return p; // return "best" result
-}
-
-void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg,
- const char *charset, int flag)
-{
- if (!seedlen)
- return NULL;
-
- char tmp[30];
- char *buf;
- if (seedlen <= sizeof(tmp) - 2)
- buf = tmp;
- else
- {
- buf = (char *)alloca(seedlen + 2); // leave space for extra char
- if (!buf)
- return NULL; // no matches
- }
- int cost = INT_MAX, ncost = 0;
- void *p = NULL, *np;
-
- /* Deletions */
- memcpy(buf, seed + 1, seedlen);
- for (size_t i = 0; i < seedlen; i++)
- {
- //printf("del buf = '%s'\n", buf);
- if (flag)
- np = spellerY(buf, seedlen - 1, fp, fparg, charset, i, &ncost);
- else
- np = (*fp)(fparg, buf, &ncost);
- if (combineSpellerResult(p, cost, np, ncost))
- return p;
-
- buf[i] = seed[i];
- }
-
- /* Transpositions */
- if (!flag)
- {
- memcpy(buf, seed, seedlen + 1);
- for (size_t i = 0; i + 1 < seedlen; i++)
- {
- // swap [i] and [i + 1]
- buf[i] = seed[i + 1];
- buf[i + 1] = seed[i];
-
- //printf("tra buf = '%s'\n", buf);
- if (combineSpellerResult(p, cost, (*fp)(fparg, buf, &ncost), ncost))
- return p;
-
- buf[i] = seed[i];
- }
- }
-
- if (charset && *charset)
- {
- /* Substitutions */
- memcpy(buf, seed, seedlen + 1);
- for (size_t i = 0; i < seedlen; i++)
- {
- for (const char *s = charset; *s; s++)
- {
- buf[i] = *s;
-
- //printf("sub buf = '%s'\n", buf);
- if (flag)
- np = spellerY(buf, seedlen, fp, fparg, charset, i + 1, &ncost);
- else
- np = (*fp)(fparg, buf, &ncost);
- if (combineSpellerResult(p, cost, np, ncost))
- return p;
- }
- buf[i] = seed[i];
- }
-
- /* Insertions */
- memcpy(buf + 1, seed, seedlen + 1);
- for (size_t i = 0; i <= seedlen; i++) // yes, do seedlen+1 iterations
- {
- for (const char *s = charset; *s; s++)
- {
- buf[i] = *s;
-
- //printf("ins buf = '%s'\n", buf);
- if (flag)
- np = spellerY(buf, seedlen + 1, fp, fparg, charset, i + 1, &ncost);
- else
- np = (*fp)(fparg, buf, &ncost);
- if (combineSpellerResult(p, cost, np, ncost))
- return p;
- }
- buf[i] = seed[i]; // going past end of seed[] is ok, as we hit the 0
- }
- }
-
- return p; // return "best" result
-}
-
-/**************************************************
- * Looks for correct spelling.
- * Currently only looks a 'distance' of one from the seed[].
- * This does an exhaustive search, so can potentially be very slow.
- * Input:
- * seed wrongly spelled word
- * fp search function
- * fparg argument to search function
- * charset character set
- * Returns:
- * NULL no correct spellings found
- * void* value returned by fp() for first possible correct spelling
- */
-
-void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset)
-{
- size_t seedlen = strlen(seed);
- size_t maxdist = seedlen < 4 ? seedlen / 2 : 2;
- for (size_t distance = 0; distance < maxdist; distance++)
- { void *p = spellerX(seed, seedlen, fp, fparg, charset, distance);
- if (p)
- return p;
-// if (seedlen > 10)
-// break;
- }
- return NULL; // didn't find it
-}
diff --git a/gcc/d/dmd/root/speller.d b/gcc/d/dmd/root/speller.d
new file mode 100644
index 0000000..543005b
--- /dev/null
+++ b/gcc/d/dmd/root/speller.d
@@ -0,0 +1,303 @@
+/**
+ * Spell checker
+ *
+ * Does not have any dependencies on the rest of DMD.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/speller.d, root/_speller.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_speller.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/speller.d
+ */
+
+module dmd.root.speller;
+
+/**************************************************
+ * Looks for correct spelling.
+ * Looks a distance of up to two.
+ * This does an exhaustive search, so can potentially be very slow.
+ * Params:
+ * seed = wrongly spelled word
+ * dg = search delegate of the form `T delegate(const(char)[] p, out int cost)`
+ * Returns:
+ * T.init = no correct spellings found,
+ * otherwise the value returned by dg() for first possible correct spelling
+ */
+auto speller(alias dg)(const(char)[] seed)
+if (isSearchFunction!dg)
+{
+ const size_t maxdist = seed.length < 4 ? seed.length / 2 : 2;
+ foreach (distance; 0 .. maxdist)
+ {
+ if (auto p = spellerX!dg(seed, distance != 0))
+ return p;
+ // if (seedlen > 10)
+ // break;
+ }
+ return null; // didn't find it
+}
+
+private:
+
+import core.stdc.stdlib;
+import core.stdc.string;
+
+enum isSearchFunction(alias fun) = is(searchFunctionType!fun);
+alias searchFunctionType(alias fun) = typeof(() {int x; return fun("", x);}());
+
+/*************************************
+ * Spell check level 1.
+ * Params:
+ * dg = delegate that looks up string in dictionary AA and returns value found
+ * seed = starting string
+ * flag = if true, do 2 level lookup otherwise 1 level
+ * Returns:
+ * whatever dg returns, null if no match
+ */
+auto spellerX(alias dg)(const(char)[] seed, bool flag)
+{
+ if (!seed.length)
+ return null;
+
+ /* Need buffer to store trial strings in
+ */
+ char[30] tmp = void;
+ char[] buf;
+ if (seed.length <= tmp.sizeof - 1)
+ buf = tmp;
+ else
+ {
+ buf = (cast(char*)alloca(seed.length + 1))[0 .. seed.length + 1]; // leave space for extra char
+ if (!buf.ptr)
+ return null; // no matches
+ }
+
+ int cost = int.max;
+ searchFunctionType!dg p = null;
+
+ /* Deletions */
+ buf[0 .. seed.length - 1] = seed[1 .. $];
+ foreach (i; 0 .. seed.length)
+ {
+ //printf("del buf = '%s'\n", buf);
+ int ncost;
+ auto np = flag ? spellerY!dg(buf[0 .. seed.length - 1], i, ncost)
+ : dg(buf[0 .. seed.length - 1], ncost);
+ if (combineSpellerResult(p, cost, np, ncost))
+ return p;
+ buf[i] = seed[i];
+ }
+
+ /* Transpositions */
+ if (!flag)
+ {
+ buf[0 .. seed.length] = seed;
+ for (size_t i = 0; i + 1 < seed.length; i++)
+ {
+ // swap [i] and [i + 1]
+ buf[i] = seed[i + 1];
+ buf[i + 1] = seed[i];
+ //printf("tra buf = '%s'\n", buf);
+ int ncost;
+ auto np = dg(buf[0 .. seed.length], ncost);
+ if (combineSpellerResult(p, cost, np, ncost))
+ return p;
+ buf[i] = seed[i];
+ }
+ }
+
+ /* Substitutions */
+ buf[0 .. seed.length] = seed;
+ foreach (i; 0 .. seed.length)
+ {
+ foreach (s; idchars)
+ {
+ buf[i] = s;
+ //printf("sub buf = '%s'\n", buf);
+ int ncost;
+ auto np = flag ? spellerY!dg(buf[0 .. seed.length], i + 1, ncost)
+ : dg(buf[0 .. seed.length], ncost);
+ if (combineSpellerResult(p, cost, np, ncost))
+ return p;
+ }
+ buf[i] = seed[i];
+ }
+
+ /* Insertions */
+ buf[1 .. seed.length + 1] = seed;
+ foreach (i; 0 .. seed.length + 1) // yes, do seed.length+1 iterations
+ {
+ foreach (s; idchars)
+ {
+ buf[i] = s;
+ //printf("ins buf = '%s'\n", buf);
+ int ncost;
+ auto np = flag ? spellerY!dg(buf[0 .. seed.length + 1], i + 1, ncost)
+ : dg(buf[0 .. seed.length + 1], ncost);
+ if (combineSpellerResult(p, cost, np, ncost))
+ return p;
+ }
+ if (i < seed.length)
+ buf[i] = seed[i];
+ }
+
+ return p; // return "best" result
+}
+
+/**********************************************
+ * Do second level of spell matching.
+ * Params:
+ * dg = delegate that looks up string in dictionary AA and returns value found
+ * seed = starting string
+ * index = index into seed[] that is where we will mutate it
+ * cost = set to cost of match
+ * Returns:
+ * whatever dg returns, null if no match
+ */
+auto spellerY(alias dg)(const(char)[] seed, size_t index, out int cost)
+{
+ if (!seed.length)
+ return null;
+
+ /* Allocate a buf to store the new string to play with, needs
+ * space for an extra char for insertions
+ */
+ char[30] tmp = void; // stack allocations are fastest
+ char[] buf;
+ if (seed.length <= tmp.sizeof - 1)
+ buf = tmp;
+ else
+ {
+ buf = (cast(char*)alloca(seed.length + 1))[0 .. seed.length + 1]; // leave space for extra char
+ if (!buf.ptr)
+ return null; // no matches
+ }
+ buf[0 .. index] = seed[0 .. index];
+
+ cost = int.max; // start with worst possible match
+ searchFunctionType!dg p = null;
+
+ /* Delete character at seed[index] */
+ if (index < seed.length)
+ {
+ buf[index .. seed.length - 1] = seed[index + 1 .. $]; // seed[] with deleted character
+ int ncost;
+ auto np = dg(buf[0 .. seed.length - 1], ncost); // look it up
+ if (combineSpellerResult(p, cost, np, ncost)) // compare with prev match
+ return p; // cannot get any better
+ }
+
+ /* Substitute character at seed[index] */
+ if (index < seed.length)
+ {
+ buf[0 .. seed.length] = seed;
+ foreach (s; idchars)
+ {
+ buf[index] = s; // seed[] with substituted character
+ //printf("sub buf = '%s'\n", buf);
+ int ncost;
+ auto np = dg(buf[0 .. seed.length], ncost);
+ if (combineSpellerResult(p, cost, np, ncost))
+ return p;
+ }
+ }
+
+ /* Insert character at seed[index] */
+ buf[index + 1 .. seed.length + 1] = seed[index .. $];
+ foreach (s; idchars)
+ {
+ buf[index] = s;
+ //printf("ins buf = '%s'\n", buf);
+ int ncost;
+ auto np = dg(buf[0 .. seed.length + 1], ncost);
+ if (combineSpellerResult(p, cost, np, ncost))
+ return p;
+ }
+ return p; // return "best" result
+}
+
+
+/* Characters used to substitute ones in the string we're checking
+ * the spelling on.
+ */
+immutable string idchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
+
+/**************************************************
+ * Combine a new result from the spell checker to
+ * find the one with the closest symbol with
+ * respect to the cost defined by the search function
+ * Params:
+ * p = best found spelling so far, T.init if none found yet.
+ * If np is better, p is replaced with np
+ * cost = cost of p (int.max if none found yet).
+ * If np is better, cost is replaced with ncost
+ * np = current spelling to check against p, T.init if none
+ * ncost = cost of np if np is not T.init
+ * Returns:
+ * true if the cost is less or equal 0, meaning we can stop looking
+ * false otherwise
+ */
+bool combineSpellerResult(T)(ref T p, ref int cost, T np, int ncost)
+{
+ if (np && ncost < cost) // if np is better
+ {
+ p = np; // np is new best match
+ cost = ncost;
+ if (cost <= 0)
+ return true; // meaning we can stop looking
+ }
+ return false;
+}
+
+/************************************* Tests ***********************/
+
+unittest
+{
+ static immutable string[][] cases =
+ [
+ ["hello", "hell", "y"],
+ ["hello", "hel", "y"],
+ ["hello", "ello", "y"],
+ ["hello", "llo", "y"],
+ ["hello", "hellox", "y"],
+ ["hello", "helloxy", "y"],
+ ["hello", "xhello", "y"],
+ ["hello", "xyhello", "y"],
+ ["hello", "ehllo", "y"],
+ ["hello", "helol", "y"],
+ ["hello", "abcd", "n"],
+ ["hello", "helxxlo", "y"],
+ ["hello", "ehlxxlo", "n"],
+ ["hello", "heaao", "y"],
+ ["_123456789_123456789_123456789_123456789", "_123456789_123456789_123456789_12345678", "y"],
+ ];
+ //printf("unittest_speller()\n");
+
+ string dgarg;
+
+ string speller_test(const(char)[] s, ref int cost)
+ {
+ assert(s[$-1] != '\0');
+ //printf("speller_test(%s, %s)\n", dgarg, s);
+ cost = 0;
+ if (dgarg == s)
+ return dgarg;
+ return null;
+ }
+
+ dgarg = "hell";
+ auto p = speller!speller_test("hello");
+ assert(p !is null);
+ foreach (testCase; cases)
+ {
+ //printf("case [%d]\n", i);
+ dgarg = testCase[1];
+ auto p2 = speller!speller_test(testCase[0]);
+ if (p2)
+ assert(testCase[2][0] == 'y');
+ else
+ assert(testCase[2][0] == 'n');
+ }
+ //printf("unittest_speller() success\n");
+}
diff --git a/gcc/d/dmd/root/string.d b/gcc/d/dmd/root/string.d
new file mode 100644
index 0000000..73fe562
--- /dev/null
+++ b/gcc/d/dmd/root/string.d
@@ -0,0 +1,293 @@
+/**
+ * Contains various string related functions.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/string.d, root/_string.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_string.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/string.d
+ */
+module dmd.root.string;
+
+/// Slices a `\0`-terminated C-string, excluding the terminator
+inout(char)[] toDString (inout(char)* s) pure nothrow @nogc
+{
+ import core.stdc.string : strlen;
+ return s ? s[0 .. strlen(s)] : null;
+}
+
+/**
+Compare two slices for equality, in a case-insensitive way
+
+Comparison is based on `char` and does not do decoding.
+As a result, it's only really accurate for plain ASCII strings.
+
+Params:
+s1 = string to compare
+s2 = string to compare
+
+Returns:
+`true` if `s1 == s2` regardless of case
+*/
+extern(D) static bool iequals(const(char)[] s1, const(char)[] s2) pure nothrow @nogc
+{
+ import core.stdc.ctype : toupper;
+
+ if (s1.length != s2.length)
+ return false;
+
+ foreach (idx, c1; s1)
+ {
+ // Since we did a length check, it is safe to bypass bounds checking
+ const c2 = s2.ptr[idx];
+ if (c1 != c2)
+ if (toupper(c1) != toupper(c2))
+ return false;
+ }
+ return true;
+}
+
+/**
+Copy the content of `src` into a C-string ('\0' terminated) then call `dg`
+
+The intent of this function is to provide an allocation-less
+way to call a C function using a D slice.
+The function internally allocates a buffer if needed, but frees it on exit.
+
+Note:
+The argument to `dg` is `scope`. To keep the data around after `dg` exits,
+one has to copy it.
+
+Params:
+src = Slice to use to call the C function
+dg = Delegate to call afterwards
+
+Returns:
+The return value of `T`
+*/
+auto toCStringThen(alias dg)(const(char)[] src) nothrow
+{
+ import dmd.root.rmem : mem;
+
+ const len = src.length + 1;
+ char[512] small = void;
+ scope ptr = (src.length < (small.length - 1))
+ ? small[0 .. len]
+ : (cast(char*)mem.xmalloc(len))[0 .. len];
+ scope (exit)
+ {
+ if (&ptr[0] != &small[0])
+ mem.xfree(&ptr[0]);
+ }
+ ptr[0 .. src.length] = src[];
+ ptr[src.length] = '\0';
+ return dg(ptr);
+}
+
+unittest
+{
+ assert("Hello world".toCStringThen!((v) => v == "Hello world\0"));
+ assert("Hello world\0".toCStringThen!((v) => v == "Hello world\0\0"));
+ assert(null.toCStringThen!((v) => v == "\0"));
+}
+
+/**
+ * Strips one leading line terminator of the given string.
+ *
+ * The following are what the Unicode standard considers as line terminators:
+ *
+ * | Name | D Escape Sequence | Unicode Code Point |
+ * |---------------------|-------------------|--------------------|
+ * | Line feed | `\n` | `U+000A` |
+ * | Line tabulation | `\v` | `U+000B` |
+ * | Form feed | `\f` | `U+000C` |
+ * | Carriage return | `\r` | `U+000D` |
+ * | Next line | | `U+0085` |
+ * | Line separator | | `U+2028` |
+ * | Paragraph separator | | `U+2029` |
+ *
+ * This function will also strip `\r\n`.
+ */
+string stripLeadingLineTerminator(string str) pure nothrow @nogc @safe
+{
+ enum nextLine = "\xC2\x85";
+ enum lineSeparator = "\xE2\x80\xA8";
+ enum paragraphSeparator = "\xE2\x80\xA9";
+
+ static assert(lineSeparator.length == paragraphSeparator.length);
+
+ if (str.length == 0)
+ return str;
+
+ switch (str[0])
+ {
+ case '\r':
+ {
+ if (str.length >= 2 && str[1] == '\n')
+ return str[2 .. $];
+ goto case;
+ }
+ case '\v', '\f', '\n': return str[1 .. $];
+
+ case nextLine[0]:
+ {
+ if (str.length >= 2 && str[0 .. 2] == nextLine)
+ return str[2 .. $];
+
+ return str;
+ }
+
+ case lineSeparator[0]:
+ {
+ if (str.length >= lineSeparator.length)
+ {
+ const prefix = str[0 .. lineSeparator.length];
+
+ if (prefix == lineSeparator || prefix == paragraphSeparator)
+ return str[lineSeparator.length .. $];
+ }
+
+ return str;
+ }
+
+ default: return str;
+ }
+}
+
+unittest
+{
+ assert("".stripLeadingLineTerminator == "");
+ assert("foo".stripLeadingLineTerminator == "foo");
+ assert("\xC2foo".stripLeadingLineTerminator == "\xC2foo");
+ assert("\xE2foo".stripLeadingLineTerminator == "\xE2foo");
+ assert("\nfoo".stripLeadingLineTerminator == "foo");
+ assert("\vfoo".stripLeadingLineTerminator == "foo");
+ assert("\ffoo".stripLeadingLineTerminator == "foo");
+ assert("\rfoo".stripLeadingLineTerminator == "foo");
+ assert("\u0085foo".stripLeadingLineTerminator == "foo");
+ assert("\u2028foo".stripLeadingLineTerminator == "foo");
+ assert("\u2029foo".stripLeadingLineTerminator == "foo");
+ assert("\n\rfoo".stripLeadingLineTerminator == "\rfoo");
+ assert("\r\nfoo".stripLeadingLineTerminator == "foo");
+}
+
+/**
+ * A string comparison functions that returns the same result as strcmp
+ *
+ * Note: Strings are compared based on their ASCII values, no UTF-8 decoding.
+ *
+ * Some C functions (e.g. `qsort`) require a `int` result for comparison.
+ * See_Also: Druntime's `core.internal.string`
+ */
+int dstrcmp()( scope const char[] s1, scope const char[] s2 ) @trusted
+{
+ immutable len = s1.length <= s2.length ? s1.length : s2.length;
+ if (__ctfe)
+ {
+ foreach (const u; 0 .. len)
+ {
+ if (s1[u] != s2[u])
+ return s1[u] > s2[u] ? 1 : -1;
+ }
+ }
+ else
+ {
+ import core.stdc.string : memcmp;
+
+ const ret = memcmp( s1.ptr, s2.ptr, len );
+ if ( ret )
+ return ret;
+ }
+ return s1.length < s2.length ? -1 : (s1.length > s2.length);
+}
+
+//
+unittest
+{
+ assert(dstrcmp("Fraise", "Fraise") == 0);
+ assert(dstrcmp("Baguette", "Croissant") == -1);
+ assert(dstrcmp("Croissant", "Baguette") == 1);
+
+ static assert(dstrcmp("Baguette", "Croissant") == -1);
+
+ // UTF-8 decoding for the CT variant
+ assert(dstrcmp("안녕하세요!", "안녕하세요!") == 0);
+ static assert(dstrcmp("안녕하세요!", "안녕하세요!") == 0);
+}
+
+/**
+ * Infers the length `N` of a string literal and coerces its type to a static
+ * array with length `N + 1`. Returns the string with a null character appended
+ * to the end.
+ *
+ * Params:
+ * literal = string literal
+ *
+ * Notes:
+ * - LDC produces quite optimal code for short strings:
+ * - https://d.godbolt.org/z/M69Z1g
+ * - https://gist.github.com/PetarKirov/338e4ab9292b6b2b311a3070572a07fb (backup URL)
+*/
+char[N + 1] toStaticArray(size_t N)(scope const(char)[N] literal)
+{
+ char[N+1] result = void;
+ result[0..N] = literal[0..N];
+ result[N] = 0;
+ return result;
+}
+
+///
+@safe pure nothrow @nogc
+unittest
+{
+ auto m = "123".toStaticArray;
+ const c = "123".toStaticArray;
+ immutable i = "123".toStaticArray;
+ enum e = "123".toStaticArray;
+
+ assert(m == "123\0");
+ assert(c == "123\0");
+ assert(i == "123\0");
+ static assert(e == "123\0");
+
+ const empty = "".toStaticArray;
+ static assert(empty.length == 1);
+ static assert(empty[0] == '\0');
+}
+
+/**
+ * Checks if C string `p` starts with `needle`.
+ * Params:
+ * p = the C string to check
+ * needle = the string to look for
+ * Returns:
+ * `true` if `p` starts with `needle`
+ */
+@system pure nothrow @nogc
+bool startsWith(scope const(char)* p, scope const(char)[] needle)
+in { assert(p && needle.ptr); }
+do
+{
+ foreach (const c; needle)
+ {
+ assert(c);
+ if (c != *p)
+ return false;
+ ++p;
+ }
+ return true;
+}
+
+///
+@system pure nothrow @nogc
+unittest
+{
+ const buf = "123".toStaticArray;
+ const ptr = &buf[0];
+ assert(ptr.startsWith(""));
+ assert(ptr.startsWith("1"));
+ assert(ptr.startsWith("12"));
+ assert(ptr.startsWith("123"));
+ assert(!ptr.startsWith("1234"));
+}
diff --git a/gcc/d/dmd/root/stringtable.c b/gcc/d/dmd/root/stringtable.c
deleted file mode 100644
index fe14807..0000000
--- a/gcc/d/dmd/root/stringtable.c
+++ /dev/null
@@ -1,196 +0,0 @@
-
-/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
- * https://github.com/D-Programming-Language/dmd/blob/master/src/root/stringtable.c
- */
-
-#include "dsystem.h" // uint{8|16|32}_t, memcpy()
-#include "root.h"
-#include "rmem.h" // mem
-#include "stringtable.h"
-#include "hash.h"
-
-#define POOL_BITS 12
-#define POOL_SIZE (1U << POOL_BITS)
-
-struct StringEntry
-{
- uint32_t hash;
- uint32_t vptr;
-};
-
-uint32_t StringTable::allocValue(const char *s, size_t length, void *ptrvalue)
-{
- const size_t nbytes = sizeof(StringValue) + length + 1;
-
- if (!npools || nfill + nbytes > POOL_SIZE)
- {
- pools = (uint8_t **)mem.xrealloc(pools, ++npools * sizeof(pools[0]));
- pools[npools - 1] = (uint8_t *)mem.xmalloc(nbytes > POOL_SIZE ? nbytes : POOL_SIZE);
- nfill = 0;
- }
-
- StringValue *sv = (StringValue *)&pools[npools - 1][nfill];
- sv->ptrvalue = ptrvalue;
- sv->length = length;
- ::memcpy(sv->lstring(), s, length);
- sv->lstring()[length] = 0;
-
- const uint32_t vptr = (uint32_t)(npools << POOL_BITS | nfill);
- nfill += nbytes + (-nbytes & 7); // align to 8 bytes
- return vptr;
-}
-
-StringValue *StringTable::getValue(uint32_t vptr)
-{
- if (!vptr) return NULL;
-
- const size_t idx = (vptr >> POOL_BITS) - 1;
- const size_t off = vptr & (POOL_SIZE - 1);
- return (StringValue *)&pools[idx][off];
-}
-
-static size_t nextpow2(size_t val)
-{
- size_t res = 1;
- while (res < val)
- res <<= 1;
- return res;
-}
-
-static const double loadFactor = 0.8;
-
-void StringTable::_init(size_t size)
-{
- size = nextpow2((size_t)(size / loadFactor));
- if (size < 32) size = 32;
- table = (StringEntry *)mem.xcalloc(size, sizeof(table[0]));
- tabledim = size;
- pools = NULL;
- npools = nfill = 0;
- count = 0;
-}
-
-void StringTable::reset(size_t size)
-{
- for (size_t i = 0; i < npools; ++i)
- mem.xfree(pools[i]);
-
- mem.xfree(table);
- mem.xfree(pools);
- table = NULL;
- pools = NULL;
- _init(size);
-}
-
-StringTable::~StringTable()
-{
- for (size_t i = 0; i < npools; ++i)
- mem.xfree(pools[i]);
-
- mem.xfree(table);
- mem.xfree(pools);
- table = NULL;
- pools = NULL;
-}
-
-size_t StringTable::findSlot(hash_t hash, const char *s, size_t length)
-{
- // quadratic probing using triangular numbers
- // http://stackoverflow.com/questions/2348187/moving-from-linear-probing-to-quadratic-probing-hash-collisons/2349774#2349774
- for (size_t i = hash & (tabledim - 1), j = 1; ;++j)
- {
- StringValue *sv;
- if (!table[i].vptr ||
- (table[i].hash == hash &&
- (sv = getValue(table[i].vptr))->length == length &&
- ::memcmp(s, sv->lstring(), length) == 0))
- return i;
- i = (i + j) & (tabledim - 1);
- }
-}
-
-StringValue *StringTable::lookup(const char *s, size_t length)
-{
- const hash_t hash = calcHash(s, length);
- const size_t i = findSlot(hash, s, length);
- // printf("lookup %.*s %p\n", (int)length, s, table[i].value ?: NULL);
- return getValue(table[i].vptr);
-}
-
-StringValue *StringTable::update(const char *s, size_t length)
-{
- const hash_t hash = calcHash(s, length);
- size_t i = findSlot(hash, s, length);
- if (!table[i].vptr)
- {
- if (++count > tabledim * loadFactor)
- {
- grow();
- i = findSlot(hash, s, length);
- }
- table[i].hash = hash;
- table[i].vptr = allocValue(s, length, NULL);
- }
- // printf("update %.*s %p\n", (int)length, s, table[i].value ?: NULL);
- return getValue(table[i].vptr);
-}
-
-StringValue *StringTable::insert(const char *s, size_t length, void *ptrvalue)
-{
- const hash_t hash = calcHash(s, length);
- size_t i = findSlot(hash, s, length);
- if (table[i].vptr)
- return NULL; // already in table
- if (++count > tabledim * loadFactor)
- {
- grow();
- i = findSlot(hash, s, length);
- }
- table[i].hash = hash;
- table[i].vptr = allocValue(s, length, ptrvalue);
- // printf("insert %.*s %p\n", (int)length, s, table[i].value ?: NULL);
- return getValue(table[i].vptr);
-}
-
-void StringTable::grow()
-{
- const size_t odim = tabledim;
- StringEntry *otab = table;
- tabledim *= 2;
- table = (StringEntry *)mem.xcalloc(tabledim, sizeof(table[0]));
-
- for (size_t i = 0; i < odim; ++i)
- {
- StringEntry *se = &otab[i];
- if (!se->vptr) continue;
- StringValue *sv = getValue(se->vptr);
- table[findSlot(se->hash, sv->lstring(), sv->length)] = *se;
- }
- mem.xfree(otab);
-}
-
-/********************************
- * Walk the contents of the string table,
- * calling fp for each entry.
- * Params:
- * fp = function to call. Returns !=0 to stop
- * Returns:
- * last return value of fp call
- */
-int StringTable::apply(int (*fp)(StringValue *))
-{
- for (size_t i = 0; i < tabledim; ++i)
- {
- StringEntry *se = &table[i];
- if (!se->vptr) continue;
- StringValue *sv = getValue(se->vptr);
- int result = (*fp)(sv);
- if (result)
- return result;
- }
- return 0;
-}
-
diff --git a/gcc/d/dmd/root/stringtable.d b/gcc/d/dmd/root/stringtable.d
new file mode 100644
index 0000000..42b26e2
--- /dev/null
+++ b/gcc/d/dmd/root/stringtable.d
@@ -0,0 +1,411 @@
+/**
+ * A specialized associative array with string keys stored in a variable length structure.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: Walter Bright, http://www.digitalmars.com
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/stringtable.d, root/_stringtable.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_stringtable.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/stringtable.d
+ */
+
+module dmd.root.stringtable;
+
+import core.stdc.string;
+import dmd.root.rmem, dmd.root.hash;
+
+private enum POOL_BITS = 12;
+private enum POOL_SIZE = (1U << POOL_BITS);
+
+/*
+Returns the smallest integer power of 2 larger than val.
+if val > 2^^63 on 64-bit targets or val > 2^^31 on 32-bit targets it enters an
+endless loop because of overflow.
+*/
+private size_t nextpow2(size_t val) @nogc nothrow pure @safe
+{
+ size_t res = 1;
+ while (res < val)
+ res <<= 1;
+ return res;
+}
+
+unittest
+{
+ assert(nextpow2(0) == 1);
+ assert(nextpow2(0xFFFF) == (1 << 16));
+ assert(nextpow2(size_t.max / 2) == size_t.max / 2 + 1);
+ // note: nextpow2((1UL << 63) + 1) results in an endless loop
+}
+
+private enum loadFactorNumerator = 8;
+private enum loadFactorDenominator = 10; // for a load factor of 0.8
+
+private struct StringEntry
+{
+ uint hash;
+ uint vptr;
+}
+
+/********************************
+ * StringValue is a variable-length structure. It has neither proper c'tors nor a
+ * factory method because the only thing which should be creating these is StringTable.
+ * The string characters are stored in memory immediately after the StringValue struct.
+ */
+struct StringValue(T)
+{
+ T value; //T is/should typically be a pointer or a slice
+ private size_t length;
+ /+
+ char[length] chars; // the string characters are stored here
+ +/
+
+ char* lstring() @nogc nothrow pure return
+ {
+ return cast(char*)(&this + 1);
+ }
+
+ size_t len() const @nogc nothrow pure @safe
+ {
+ return length;
+ }
+
+ const(char)* toDchars() const @nogc nothrow pure return
+ {
+ return cast(const(char)*)(&this + 1);
+ }
+
+ /// Returns: The content of this entry as a D slice
+ const(char)[] toString() const @nogc nothrow pure
+ {
+ return (cast(inout(char)*)(&this + 1))[0 .. length];
+ }
+}
+
+struct StringTable(T)
+{
+private:
+ StringEntry[] table;
+ ubyte*[] pools;
+ size_t nfill;
+ size_t count;
+ size_t countTrigger; // amount which will trigger growing the table
+
+public:
+ void _init(size_t size = 0) nothrow pure
+ {
+ size = nextpow2((size * loadFactorDenominator) / loadFactorNumerator);
+ if (size < 32)
+ size = 32;
+ table = (cast(StringEntry*)mem.xcalloc(size, (table[0]).sizeof))[0 .. size];
+ countTrigger = (table.length * loadFactorNumerator) / loadFactorDenominator;
+ pools = null;
+ nfill = 0;
+ count = 0;
+ }
+
+ void reset(size_t size = 0) nothrow pure
+ {
+ freeMem();
+ _init(size);
+ }
+
+ ~this() nothrow pure
+ {
+ freeMem();
+ }
+
+ /**
+ Looks up the given string in the string table and returns its associated
+ value.
+
+ Params:
+ s = the string to look up
+ length = the length of $(D_PARAM s)
+ str = the string to look up
+
+ Returns: the string's associated value, or `null` if the string doesn't
+ exist in the string table
+ */
+ inout(StringValue!T)* lookup(scope const(char)[] str) inout @nogc nothrow pure
+ {
+ const(size_t) hash = calcHash(str);
+ const(size_t) i = findSlot(hash, str);
+ // printf("lookup %.*s %p\n", cast(int)str.length, str.ptr, table[i].value ?: null);
+ return getValue(table[i].vptr);
+ }
+
+ /// ditto
+ inout(StringValue!T)* lookup(scope const(char)* s, size_t length) inout @nogc nothrow pure
+ {
+ return lookup(s[0 .. length]);
+ }
+
+ /**
+ Inserts the given string and the given associated value into the string
+ table.
+
+ Params:
+ s = the string to insert
+ length = the length of $(D_PARAM s)
+ ptrvalue = the value to associate with the inserted string
+ str = the string to insert
+ value = the value to associate with the inserted string
+
+ Returns: the newly inserted value, or `null` if the string table already
+ contains the string
+ */
+ StringValue!(T)* insert(scope const(char)[] str, T value) nothrow pure
+ {
+ const(size_t) hash = calcHash(str);
+ size_t i = findSlot(hash, str);
+ if (table[i].vptr)
+ return null; // already in table
+ if (++count > countTrigger)
+ {
+ grow();
+ i = findSlot(hash, str);
+ }
+ table[i].hash = hash;
+ table[i].vptr = allocValue(str, value);
+ // printf("insert %.*s %p\n", cast(int)str.length, str.ptr, table[i].value ?: NULL);
+ return getValue(table[i].vptr);
+ }
+
+ /// ditto
+ StringValue!(T)* insert(scope const(char)* s, size_t length, T value) nothrow pure
+ {
+ return insert(s[0 .. length], value);
+ }
+
+ StringValue!(T)* update(scope const(char)[] str) nothrow pure
+ {
+ const(size_t) hash = calcHash(str);
+ size_t i = findSlot(hash, str);
+ if (!table[i].vptr)
+ {
+ if (++count > countTrigger)
+ {
+ grow();
+ i = findSlot(hash, str);
+ }
+ table[i].hash = hash;
+ table[i].vptr = allocValue(str, T.init);
+ }
+ // printf("update %.*s %p\n", cast(int)str.length, str.ptr, table[i].value ?: NULL);
+ return getValue(table[i].vptr);
+ }
+
+ StringValue!(T)* update(scope const(char)* s, size_t length) nothrow pure
+ {
+ return update(s[0 .. length]);
+ }
+
+ /********************************
+ * Walk the contents of the string table,
+ * calling fp for each entry.
+ * Params:
+ * fp = function to call. Returns !=0 to stop
+ * Returns:
+ * last return value of fp call
+ */
+ int apply(int function(const(StringValue!T)*) nothrow fp) nothrow
+ {
+ foreach (const se; table)
+ {
+ if (!se.vptr)
+ continue;
+ const sv = getValue(se.vptr);
+ int result = (*fp)(sv);
+ if (result)
+ return result;
+ }
+ return 0;
+ }
+
+ /// ditto
+ extern(D) int opApply(scope int delegate(const(StringValue!T)*) nothrow dg) nothrow
+ {
+ foreach (const se; table)
+ {
+ if (!se.vptr)
+ continue;
+ const sv = getValue(se.vptr);
+ int result = dg(sv);
+ if (result)
+ return result;
+ }
+ return 0;
+ }
+
+private:
+ /// Free all memory in use by this StringTable
+ void freeMem() nothrow pure
+ {
+ foreach (pool; pools)
+ mem.xfree(pool);
+ mem.xfree(table.ptr);
+ mem.xfree(pools.ptr);
+ table = null;
+ pools = null;
+ }
+
+ // Note that a copy is made of str
+ uint allocValue(scope const(char)[] str, T value) nothrow pure
+ {
+ const(size_t) nbytes = (StringValue!T).sizeof + str.length + 1;
+ if (!pools.length || nfill + nbytes > POOL_SIZE)
+ {
+ pools = (cast(ubyte**) mem.xrealloc(pools.ptr, (pools.length + 1) * (pools[0]).sizeof))[0 .. pools.length + 1];
+ pools[$-1] = cast(ubyte*) mem.xmalloc(nbytes > POOL_SIZE ? nbytes : POOL_SIZE);
+ if (mem.isGCEnabled)
+ memset(pools[$ - 1], 0xff, POOL_SIZE); // 0xff less likely to produce GC pointer
+ nfill = 0;
+ }
+ StringValue!(T)* sv = cast(StringValue!(T)*)&pools[$ - 1][nfill];
+ sv.value = value;
+ sv.length = str.length;
+ .memcpy(sv.lstring(), str.ptr, str.length);
+ sv.lstring()[str.length] = 0;
+ const(uint) vptr = cast(uint)(pools.length << POOL_BITS | nfill);
+ nfill += nbytes + (-nbytes & 7); // align to 8 bytes
+ return vptr;
+ }
+
+ inout(StringValue!T)* getValue(uint vptr) inout @nogc nothrow pure
+ {
+ if (!vptr)
+ return null;
+ const(size_t) idx = (vptr >> POOL_BITS) - 1;
+ const(size_t) off = vptr & POOL_SIZE - 1;
+ return cast(inout(StringValue!T)*)&pools[idx][off];
+ }
+
+ size_t findSlot(hash_t hash, scope const(char)[] str) const @nogc nothrow pure
+ {
+ // quadratic probing using triangular numbers
+ // http://stackoverflow.com/questions/2348187/moving-from-linear-probing-to-quadratic-probing-hash-collisons/2349774#2349774
+ for (size_t i = hash & (table.length - 1), j = 1;; ++j)
+ {
+ const(StringValue!T)* sv;
+ auto vptr = table[i].vptr;
+ if (!vptr || table[i].hash == hash && (sv = getValue(vptr)).length == str.length && .memcmp(str.ptr, sv.toDchars(), str.length) == 0)
+ return i;
+ i = (i + j) & (table.length - 1);
+ }
+ }
+
+ void grow() nothrow pure
+ {
+ const odim = table.length;
+ auto otab = table;
+ const ndim = table.length * 2;
+ countTrigger = (ndim * loadFactorNumerator) / loadFactorDenominator;
+ table = (cast(StringEntry*)mem.xcalloc_noscan(ndim, (table[0]).sizeof))[0 .. ndim];
+ foreach (const se; otab[0 .. odim])
+ {
+ if (!se.vptr)
+ continue;
+ const sv = getValue(se.vptr);
+ table[findSlot(se.hash, sv.toString())] = se;
+ }
+ mem.xfree(otab.ptr);
+ }
+}
+
+nothrow unittest
+{
+ StringTable!(const(char)*) tab;
+ tab._init(10);
+
+ // construct two strings with the same text, but a different pointer
+ const(char)[6] fooBuffer = "foofoo";
+ const(char)[] foo = fooBuffer[0 .. 3];
+ const(char)[] fooAltPtr = fooBuffer[3 .. 6];
+
+ assert(foo.ptr != fooAltPtr.ptr);
+
+ // first insertion returns value
+ assert(tab.insert(foo, foo.ptr).value == foo.ptr);
+
+ // subsequent insertion of same string return null
+ assert(tab.insert(foo.ptr, foo.length, foo.ptr) == null);
+ assert(tab.insert(fooAltPtr, foo.ptr) == null);
+
+ const lookup = tab.lookup("foo");
+ assert(lookup.value == foo.ptr);
+ assert(lookup.len == 3);
+ assert(lookup.toString() == "foo");
+
+ assert(tab.lookup("bar") == null);
+ tab.update("bar".ptr, "bar".length);
+ assert(tab.lookup("bar").value == null);
+
+ tab.reset(0);
+ assert(tab.lookup("foo".ptr, "foo".length) == null);
+ //tab.insert("bar");
+}
+
+nothrow unittest
+{
+ StringTable!(void*) tab;
+ tab._init(100);
+
+ enum testCount = 2000;
+
+ char[2 * testCount] buf;
+
+ foreach(i; 0 .. testCount)
+ {
+ buf[i * 2 + 0] = cast(char) (i % 256);
+ buf[i * 2 + 1] = cast(char) (i / 256);
+ auto toInsert = cast(const(char)[]) buf[i * 2 .. i * 2 + 2];
+ tab.insert(toInsert, cast(void*) i);
+ }
+
+ foreach(i; 0 .. testCount)
+ {
+ auto toLookup = cast(const(char)[]) buf[i * 2 .. i * 2 + 2];
+ assert(tab.lookup(toLookup).value == cast(void*) i);
+ }
+}
+
+nothrow unittest
+{
+ StringTable!(int) tab;
+ tab._init(10);
+ tab.insert("foo", 4);
+ tab.insert("bar", 6);
+
+ static int resultFp = 0;
+ int resultDg = 0;
+ static bool returnImmediately = false;
+
+ int function(const(StringValue!int)*) nothrow applyFunc = (const(StringValue!int)* s)
+ {
+ resultFp += s.value;
+ return returnImmediately;
+ };
+
+ scope int delegate(const(StringValue!int)*) nothrow applyDeleg = (const(StringValue!int)* s)
+ {
+ resultDg += s.value;
+ return returnImmediately;
+ };
+
+ tab.apply(applyFunc);
+ tab.opApply(applyDeleg);
+
+ assert(resultDg == 10);
+ assert(resultFp == 10);
+
+ returnImmediately = true;
+
+ tab.apply(applyFunc);
+ tab.opApply(applyDeleg);
+
+ // Order of string table iteration is not specified, either foo or bar could
+ // have been visited first.
+ assert(resultDg == 14 || resultDg == 16);
+ assert(resultFp == 14 || resultFp == 16);
+}
diff --git a/gcc/d/dmd/safe.c b/gcc/d/dmd/safe.c
deleted file mode 100644
index 7d83dd1..0000000
--- a/gcc/d/dmd/safe.c
+++ /dev/null
@@ -1,168 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/safe.c
- */
-
-#include "mars.h"
-#include "expression.h"
-#include "scope.h"
-#include "aggregate.h"
-#include "target.h"
-
-bool MODimplicitConv(MOD modfrom, MOD modto);
-
-/*************************************************************
- * Check for unsafe access in @safe code:
- * 1. read overlapped pointers
- * 2. write misaligned pointers
- * 3. write overlapped storage classes
- * Print error if unsafe.
- * Params:
- * sc = scope
- * e = expression to check
- * readonly = if access is read-only
- * printmsg = print error message if true
- * Returns:
- * true if error
- */
-
-bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg)
-{
- if (e->op != TOKdotvar)
- return false;
- DotVarExp *dve = (DotVarExp *)e;
- if (VarDeclaration *v = dve->var->isVarDeclaration())
- {
- if (sc->intypeof || !sc->func || !sc->func->isSafeBypassingInference())
- return false;
-
- AggregateDeclaration *ad = v->toParent2()->isAggregateDeclaration();
- if (!ad)
- return false;
-
- if (v->overlapped && v->type->hasPointers() && sc->func->setUnsafe())
- {
- if (printmsg)
- e->error("field %s.%s cannot access pointers in @safe code that overlap other fields",
- ad->toChars(), v->toChars());
- return true;
- }
-
- if (readonly || !e->type->isMutable())
- return false;
-
- if (v->type->hasPointers() && v->type->toBasetype()->ty != Tstruct)
- {
- if ((ad->type->alignment() < target.ptrsize ||
- (v->offset & (target.ptrsize - 1))) &&
- sc->func->setUnsafe())
- {
- if (printmsg)
- e->error("field %s.%s cannot modify misaligned pointers in @safe code",
- ad->toChars(), v->toChars());
- return true;
- }
- }
-
- if (v->overlapUnsafe && sc->func->setUnsafe())
- {
- if (printmsg)
- e->error("field %s.%s cannot modify fields in @safe code that overlap fields with other storage classes",
- ad->toChars(), v->toChars());
- return true;
- }
- }
- return false;
-}
-
-
-/**********************************************
- * Determine if it is @safe to cast e from tfrom to tto.
- * Params:
- * e = expression to be cast
- * tfrom = type of e
- * tto = type to cast e to
- * Returns:
- * true if @safe
- */
-bool isSafeCast(Expression *e, Type *tfrom, Type *tto)
-{
- // Implicit conversions are always safe
- if (tfrom->implicitConvTo(tto))
- return true;
-
- if (!tto->hasPointers())
- return true;
-
- Type *ttob = tto->toBasetype();
-
- if (ttob->ty == Tclass && tfrom->ty == Tclass)
- {
- ClassDeclaration *cdfrom = tfrom->isClassHandle();
- ClassDeclaration *cdto = ttob->isClassHandle();
-
- int offset;
- if (!cdfrom->isBaseOf(cdto, &offset))
- return false;
-
- if (cdfrom->isCPPinterface() || cdto->isCPPinterface())
- return false;
-
- if (!MODimplicitConv(tfrom->mod, ttob->mod))
- return false;
- return true;
- }
-
- if (ttob->ty == Tarray && tfrom->ty == Tsarray) // Bugzilla 12502
- tfrom = tfrom->nextOf()->arrayOf();
-
- if ((ttob->ty == Tarray && tfrom->ty == Tarray) ||
- (ttob->ty == Tpointer && tfrom->ty == Tpointer))
- {
- Type *ttobn = ttob->nextOf()->toBasetype();
- Type *tfromn = tfrom->nextOf()->toBasetype();
-
- /* From void[] to anything mutable is unsafe because:
- * int*[] api;
- * void[] av = api;
- * int[] ai = cast(int[]) av;
- * ai[0] = 7;
- * *api[0] crash!
- */
- if (tfromn->ty == Tvoid && ttobn->isMutable())
- {
- if (ttob->ty == Tarray && e->op == TOKarrayliteral)
- return true;
- return false;
- }
-
- // If the struct is opaque we don't know about the struct members then the cast becomes unsafe
- if ((ttobn->ty == Tstruct && !((TypeStruct *)ttobn)->sym->members) ||
- (tfromn->ty == Tstruct && !((TypeStruct *)tfromn)->sym->members))
- return false;
-
- const bool frompointers = tfromn->hasPointers();
- const bool topointers = ttobn->hasPointers();
-
- if (frompointers && !topointers && ttobn->isMutable())
- return false;
-
- if (!frompointers && topointers)
- return false;
-
- if (!topointers &&
- ttobn->ty != Tfunction && tfromn->ty != Tfunction &&
- (ttob->ty == Tarray || ttobn->size() <= tfromn->size()) &&
- MODimplicitConv(tfromn->mod, ttobn->mod))
- {
- return true;
- }
- }
- return false;
-}
-
diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d
new file mode 100644
index 0000000..35734b2
--- /dev/null
+++ b/gcc/d/dmd/safe.d
@@ -0,0 +1,228 @@
+/**
+ * Checks whether member access or array casting is allowed in `@safe` code.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/function.html#function-safety, Function Safety)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/safe.d, _safe.d)
+ * Documentation: https://dlang.org/phobos/dmd_safe.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/safe.d
+ */
+
+module dmd.safe;
+
+import core.stdc.stdio;
+
+import dmd.aggregate;
+import dmd.astenums;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.expression;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.target;
+import dmd.tokens;
+
+
+/*************************************************************
+ * Check for unsafe access in @safe code:
+ * 1. read overlapped pointers
+ * 2. write misaligned pointers
+ * 3. write overlapped storage classes
+ * Print error if unsafe.
+ * Params:
+ * sc = scope
+ * e = expression to check
+ * readonly = if access is read-only
+ * printmsg = print error message if true
+ * Returns:
+ * true if error
+ */
+
+bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
+{
+ //printf("checkUnsafeAccess(e: '%s', readonly: %d, printmsg: %d)\n", e.toChars(), readonly, printmsg);
+ if (e.op != TOK.dotVariable)
+ return false;
+ DotVarExp dve = cast(DotVarExp)e;
+ if (VarDeclaration v = dve.var.isVarDeclaration())
+ {
+ if (sc.intypeof || !sc.func || !sc.func.isSafeBypassingInference())
+ return false;
+ auto ad = v.toParent2().isAggregateDeclaration();
+ if (!ad)
+ return false;
+
+ // needed to set v.overlapped and v.overlapUnsafe
+ if (ad.sizeok != Sizeok.done)
+ ad.determineSize(ad.loc);
+
+ const hasPointers = v.type.hasPointers();
+ if (hasPointers)
+ {
+ if (v.overlapped && sc.func.setUnsafe())
+ {
+ if (printmsg)
+ e.error("field `%s.%s` cannot access pointers in `@safe` code that overlap other fields",
+ ad.toChars(), v.toChars());
+ return true;
+ }
+ }
+
+ if (v.type.hasInvariant())
+ {
+ if (v.overlapped && sc.func.setUnsafe())
+ {
+ if (printmsg)
+ e.error("field `%s.%s` cannot access structs with invariants in `@safe` code that overlap other fields",
+ ad.toChars(), v.toChars());
+ return true;
+ }
+ }
+
+ if (readonly || !e.type.isMutable())
+ return false;
+
+ if (hasPointers && v.type.toBasetype().ty != Tstruct)
+ {
+ if ((ad.type.alignment() < target.ptrsize ||
+ (v.offset & (target.ptrsize - 1))) &&
+ sc.func.setUnsafe())
+ {
+ if (printmsg)
+ e.error("field `%s.%s` cannot modify misaligned pointers in `@safe` code",
+ ad.toChars(), v.toChars());
+ return true;
+ }
+ }
+
+ if (v.overlapUnsafe && sc.func.setUnsafe())
+ {
+ if (printmsg)
+ e.error("field `%s.%s` cannot modify fields in `@safe` code that overlap fields with other storage classes",
+ ad.toChars(), v.toChars());
+ return true;
+ }
+ }
+ return false;
+}
+
+
+/**********************************************
+ * Determine if it is @safe to cast e from tfrom to tto.
+ * Params:
+ * e = expression to be cast
+ * tfrom = type of e
+ * tto = type to cast e to
+ * Returns:
+ * true if @safe
+ */
+bool isSafeCast(Expression e, Type tfrom, Type tto)
+{
+ // Implicit conversions are always safe
+ if (tfrom.implicitConvTo(tto))
+ return true;
+
+ if (!tto.hasPointers())
+ return true;
+
+ auto tfromb = tfrom.toBasetype();
+ auto ttob = tto.toBasetype();
+
+ if (ttob.ty == Tclass && tfromb.ty == Tclass)
+ {
+ ClassDeclaration cdfrom = tfromb.isClassHandle();
+ ClassDeclaration cdto = ttob.isClassHandle();
+
+ int offset;
+ if (!cdfrom.isBaseOf(cdto, &offset) &&
+ !((cdfrom.isInterfaceDeclaration() || cdto.isInterfaceDeclaration())
+ && cdfrom.classKind == ClassKind.d && cdto.classKind == ClassKind.d))
+ return false;
+
+ if (cdfrom.isCPPinterface() || cdto.isCPPinterface())
+ return false;
+
+ if (!MODimplicitConv(tfromb.mod, ttob.mod))
+ return false;
+ return true;
+ }
+
+ if (ttob.ty == Tarray && tfromb.ty == Tsarray) // https://issues.dlang.org/show_bug.cgi?id=12502
+ tfromb = tfromb.nextOf().arrayOf();
+
+ if (ttob.ty == Tarray && tfromb.ty == Tarray ||
+ ttob.ty == Tpointer && tfromb.ty == Tpointer)
+ {
+ Type ttobn = ttob.nextOf().toBasetype();
+ Type tfromn = tfromb.nextOf().toBasetype();
+
+ /* From void[] to anything mutable is unsafe because:
+ * int*[] api;
+ * void[] av = api;
+ * int[] ai = cast(int[]) av;
+ * ai[0] = 7;
+ * *api[0] crash!
+ */
+ if (tfromn.ty == Tvoid && ttobn.isMutable())
+ {
+ if (ttob.ty == Tarray && e.op == TOK.arrayLiteral)
+ return true;
+ return false;
+ }
+
+ // If the struct is opaque we don't know about the struct members then the cast becomes unsafe
+ if (ttobn.ty == Tstruct && !(cast(TypeStruct)ttobn).sym.members ||
+ tfromn.ty == Tstruct && !(cast(TypeStruct)tfromn).sym.members)
+ return false;
+
+ const frompointers = tfromn.hasPointers();
+ const topointers = ttobn.hasPointers();
+
+ if (frompointers && !topointers && ttobn.isMutable())
+ return false;
+
+ if (!frompointers && topointers)
+ return false;
+
+ if (!topointers &&
+ ttobn.ty != Tfunction && tfromn.ty != Tfunction &&
+ (ttob.ty == Tarray || ttobn.size() <= tfromn.size()) &&
+ MODimplicitConv(tfromn.mod, ttobn.mod))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+/*************************************************
+ * Check for unsafe use of `.ptr` or `.funcptr`
+ * Params:
+ * sc = context
+ * e = expression for error messages
+ * id = `ptr` or `funcptr`
+ * flag = DotExpFlag
+ * Returns:
+ * true if error
+ */
+bool checkUnsafeDotExp(Scope* sc, Expression e, Identifier id, int flag)
+{
+ if (!(flag & DotExpFlag.noDeref) && // this use is attempting a dereference
+ sc.func && // inside a function
+ !sc.intypeof && // allow unsafe code in typeof expressions
+ !(sc.flags & SCOPE.debug_) && // allow unsafe code in debug statements
+ sc.func.setUnsafe()) // infer this function to be unsafe
+ {
+ if (id == Id.ptr)
+ e.error("`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e.toChars(), e.toChars());
+ else
+ e.error("`%s.%s` cannot be used in `@safe` code", e.toChars(), id.toChars());
+ return true;
+ }
+ return false;
+}
diff --git a/gcc/d/dmd/sapply.c b/gcc/d/dmd/sapply.c
deleted file mode 100644
index ce08926..0000000
--- a/gcc/d/dmd/sapply.c
+++ /dev/null
@@ -1,155 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/sapply.c
- */
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "statement.h"
-#include "visitor.h"
-
-
-/**************************************
- * A Statement tree walker that will visit each Statement s in the tree,
- * in depth-first evaluation order, and call fp(s,param) on it.
- * fp() signals whether the walking continues with its return value:
- * Returns:
- * 0 continue
- * 1 done
- * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
- * Creating an iterator for this would be much more complex.
- */
-
-class PostorderStatementVisitor : public StoppableVisitor
-{
-public:
- StoppableVisitor *v;
- PostorderStatementVisitor(StoppableVisitor *v) : v(v) {}
-
- bool doCond(Statement *s)
- {
- if (!stop && s)
- s->accept(this);
- return stop;
- }
- bool applyTo(Statement *s)
- {
- s->accept(v);
- stop = v->stop;
- return true;
- }
-
- void visit(Statement *s)
- {
- applyTo(s);
- }
- void visit(PeelStatement *s)
- {
- doCond(s->s) || applyTo(s);
- }
- void visit(CompoundStatement *s)
- {
- for (size_t i = 0; i < s->statements->length; i++)
- if (doCond((*s->statements)[i]))
- return;
- applyTo(s);
- }
- void visit(UnrolledLoopStatement *s)
- {
- for (size_t i = 0; i < s->statements->length; i++)
- if (doCond((*s->statements)[i]))
- return;
- applyTo(s);
- }
- void visit(ScopeStatement *s)
- {
- doCond(s->statement) || applyTo(s);
- }
- void visit(WhileStatement *s)
- {
- doCond(s->_body) || applyTo(s);
- }
- void visit(DoStatement *s)
- {
- doCond(s->_body) || applyTo(s);
- }
- void visit(ForStatement *s)
- {
- doCond(s->_init) || doCond(s->_body) || applyTo(s);
- }
- void visit(ForeachStatement *s)
- {
- doCond(s->_body) || applyTo(s);
- }
- void visit(ForeachRangeStatement *s)
- {
- doCond(s->_body) || applyTo(s);
- }
- void visit(IfStatement *s)
- {
- doCond(s->ifbody) || doCond(s->elsebody) || applyTo(s);
- }
- void visit(PragmaStatement *s)
- {
- doCond(s->_body) || applyTo(s);
- }
- void visit(SwitchStatement *s)
- {
- doCond(s->_body) || applyTo(s);
- }
- void visit(CaseStatement *s)
- {
- doCond(s->statement) || applyTo(s);
- }
- void visit(DefaultStatement *s)
- {
- doCond(s->statement) || applyTo(s);
- }
- void visit(SynchronizedStatement *s)
- {
- doCond(s->_body) || applyTo(s);
- }
- void visit(WithStatement *s)
- {
- doCond(s->_body) || applyTo(s);
- }
- void visit(TryCatchStatement *s)
- {
- if (doCond(s->_body))
- return;
-
- for (size_t i = 0; i < s->catches->length; i++)
- if (doCond((*s->catches)[i]->handler))
- return;
- applyTo(s);
- }
- void visit(TryFinallyStatement *s)
- {
- doCond(s->_body) || doCond(s->finalbody) || applyTo(s);
- }
- void visit(ScopeGuardStatement *s)
- {
- doCond(s->statement) || applyTo(s);
- }
- void visit(DebugStatement *s)
- {
- doCond(s->statement) || applyTo(s);
- }
- void visit(LabelStatement *s)
- {
- doCond(s->statement) || applyTo(s);
- }
-};
-
-bool walkPostorder(Statement *s, StoppableVisitor *v)
-{
- PostorderStatementVisitor pv(v);
- s->accept(&pv);
- return v->stop;
-}
diff --git a/gcc/d/dmd/sapply.d b/gcc/d/dmd/sapply.d
new file mode 100644
index 0000000..018b046
--- /dev/null
+++ b/gcc/d/dmd/sapply.d
@@ -0,0 +1,180 @@
+/**
+ * Provides a depth-first statement visitor.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/sparse.d, _sparse.d)
+ * Documentation: https://dlang.org/phobos/dmd_sapply.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/sapply.d
+ */
+
+module dmd.sapply;
+
+import dmd.statement;
+import dmd.visitor;
+
+bool walkPostorder(Statement s, StoppableVisitor v)
+{
+ scope PostorderStatementVisitor pv = new PostorderStatementVisitor(v);
+ s.accept(pv);
+ return v.stop;
+}
+
+/**************************************
+ * A Statement tree walker that will visit each Statement s in the tree,
+ * in depth-first evaluation order, and call fp(s,param) on it.
+ * fp() signals whether the walking continues with its return value:
+ * Returns:
+ * 0 continue
+ * 1 done
+ * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
+ * Creating an iterator for this would be much more complex.
+ */
+private extern (C++) final class PostorderStatementVisitor : StoppableVisitor
+{
+ alias visit = typeof(super).visit;
+public:
+ StoppableVisitor v;
+
+ extern (D) this(StoppableVisitor v)
+ {
+ this.v = v;
+ }
+
+ bool doCond(Statement s)
+ {
+ if (!stop && s)
+ s.accept(this);
+ return stop;
+ }
+
+ bool applyTo(Statement s)
+ {
+ s.accept(v);
+ stop = v.stop;
+ return true;
+ }
+
+ override void visit(Statement s)
+ {
+ applyTo(s);
+ }
+
+ override void visit(PeelStatement s)
+ {
+ doCond(s.s) || applyTo(s);
+ }
+
+ override void visit(CompoundStatement s)
+ {
+ for (size_t i = 0; i < s.statements.dim; i++)
+ if (doCond((*s.statements)[i]))
+ return;
+ applyTo(s);
+ }
+
+ override void visit(UnrolledLoopStatement s)
+ {
+ for (size_t i = 0; i < s.statements.dim; i++)
+ if (doCond((*s.statements)[i]))
+ return;
+ applyTo(s);
+ }
+
+ override void visit(ScopeStatement s)
+ {
+ doCond(s.statement) || applyTo(s);
+ }
+
+ override void visit(WhileStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(DoStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(ForStatement s)
+ {
+ doCond(s._init) || doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(ForeachStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(ForeachRangeStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(IfStatement s)
+ {
+ doCond(s.ifbody) || doCond(s.elsebody) || applyTo(s);
+ }
+
+ override void visit(PragmaStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(SwitchStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(CaseStatement s)
+ {
+ doCond(s.statement) || applyTo(s);
+ }
+
+ override void visit(DefaultStatement s)
+ {
+ doCond(s.statement) || applyTo(s);
+ }
+
+ override void visit(SynchronizedStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(WithStatement s)
+ {
+ doCond(s._body) || applyTo(s);
+ }
+
+ override void visit(TryCatchStatement s)
+ {
+ if (doCond(s._body))
+ return;
+ for (size_t i = 0; i < s.catches.dim; i++)
+ if (doCond((*s.catches)[i].handler))
+ return;
+ applyTo(s);
+ }
+
+ override void visit(TryFinallyStatement s)
+ {
+ doCond(s._body) || doCond(s.finalbody) || applyTo(s);
+ }
+
+ override void visit(ScopeGuardStatement s)
+ {
+ doCond(s.statement) || applyTo(s);
+ }
+
+ override void visit(DebugStatement s)
+ {
+ doCond(s.statement) || applyTo(s);
+ }
+
+ override void visit(LabelStatement s)
+ {
+ doCond(s.statement) || applyTo(s);
+ }
+}
+
diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h
index ea3061b..4d8c0bb 100644
--- a/gcc/d/dmd/scope.h
+++ b/gcc/d/dmd/scope.h
@@ -10,8 +10,6 @@
#pragma once
-class Dsymbol;
-class ScopeDsymbol;
class Identifier;
class Module;
class Statement;
@@ -26,49 +24,48 @@ class UserAttributeDeclaration;
struct DocComment;
struct AA;
class TemplateInstance;
+class CPPNamespaceDeclaration;
#include "dsymbol.h"
-#if __GNUC__
-// Requires a full definition for LINK
-#include "globals.h"
-#else
-enum LINK;
-enum PINLINE;
-#endif
-
-#define CSXthis_ctor 1 // called this()
-#define CSXsuper_ctor 2 // called super()
-#define CSXthis 4 // referenced this
-#define CSXsuper 8 // referenced super
-#define CSXlabel 0x10 // seen a label
-#define CSXreturn 0x20 // seen a return statement
-#define CSXany_ctor 0x40 // either this() or super() was called
-#define CSXhalt 0x80 // assert(0)
-
-// Flags that would not be inherited beyond scope nesting
-#define SCOPEctor 0x0001 // constructor type
-#define SCOPEcondition 0x0004 // inside static if/assert condition
-#define SCOPEdebug 0x0008 // inside debug conditional
-
-// Flags that would be inherited beyond scope nesting
-#define SCOPEnoaccesscheck 0x0002 // don't do access checks
-#define SCOPEconstraint 0x0010 // inside template constraint
-#define SCOPEinvariant 0x0020 // inside invariant code
-#define SCOPErequire 0x0040 // inside in contract code
-#define SCOPEensure 0x0060 // inside out contract code
-#define SCOPEcontract 0x0060 // [mask] we're inside contract code
-#define SCOPEctfe 0x0080 // inside a ctfe-only expression
-#define SCOPEcompile 0x0100 // inside __traits(compile)
-#define SCOPEignoresymbolvisibility 0x0200 // ignore symbol visibility (Bugzilla 15907)
-
-#define SCOPEfree 0x8000 // is on free list
-#define SCOPEfullinst 0x10000 // fully instantiate templates
-#define SCOPEalias 0x20000 // inside alias declaration
-
-// The following are mutually exclusive
-#define SCOPEprintf 0x40000 // printf-style function
-#define SCOPEscanf 0x80000 // scanf-style function
+enum
+{
+ CSXthis_ctor = 1, // called this()
+ CSXsuper_ctor = 2, // called super()
+ CSXthis = 4, // referenced this
+ CSXsuper = 8, // referenced super
+ CSXlabel = 0x10, // seen a label
+ CSXreturn = 0x20, // seen a return statement
+ CSXany_ctor = 0x40, // either this() or super() was called
+ CSXhalt = 0x80, // assert(0)
+};
+
+enum
+{
+ // Flags that would not be inherited beyond scope nesting
+ SCOPEctor = 0x0001, // constructor type
+ SCOPEcondition = 0x0004, // inside static if/assert condition
+ SCOPEdebug = 0x0008, // inside debug conditional
+
+ // Flags that would be inherited beyond scope nesting
+ SCOPEnoaccesscheck = 0x0002, // don't do access checks
+ SCOPEconstraint = 0x0010, // inside template constraint
+ SCOPEinvariant = 0x0020, // inside invariant code
+ SCOPErequire = 0x0040, // inside in contract code
+ SCOPEensure = 0x0060, // inside out contract code
+ SCOPEcontract = 0x0060, // [mask] we're inside contract code
+ SCOPEctfe = 0x0080, // inside a ctfe-only expression
+ SCOPEcompile = 0x0100, // inside __traits(compile)
+ SCOPEignoresymbolvisibility = 0x0200, // ignore symbol visibility (Bugzilla 15907)
+
+ SCOPEfree = 0x8000, // is on free list
+ SCOPEfullinst = 0x10000, // fully instantiate templates
+ SCOPEalias = 0x20000, // inside alias declaration
+
+ // The following are mutually exclusive
+ SCOPEprintf = 0x40000, // printf-style function
+ SCOPEscanf = 0x80000, // scanf-style function
+};
struct Scope
{
@@ -80,15 +77,16 @@ struct Scope
Dsymbol *parent; // parent to use
LabelStatement *slabel; // enclosing labelled statement
SwitchStatement *sw; // enclosing switch statement
+ Statement *tryBody; // enclosing _body of TryCatchStatement or TryFinallyStatement
TryFinallyStatement *tf; // enclosing try finally statement
ScopeGuardStatement *os; // enclosing scope(xxx) statement
Statement *sbreak; // enclosing statement that supports "break"
Statement *scontinue; // enclosing statement that supports "continue"
ForeachStatement *fes; // if nested function for ForeachStatement, this is it
Scope *callsc; // used for __FUNCTION__, __PRETTY_FUNCTION__ and __MODULE__
- int inunion; // we're processing members of a union
- int nofree; // set if shouldn't free it
- int noctor; // set if constructor calls aren't allowed
+ Dsymbol *inunion; // !=null if processing members of a union
+ bool nofree; // true if shouldn't free it
+ bool inLoop; // true if inside a loop (where constructor calls aren't allowed)
int intypeof; // in typeof(exp)
VarDeclaration *lastVar; // Previous symbol used to prevent goto-skips-init
@@ -100,18 +98,21 @@ struct Scope
Module *minst; // root module where the instantiated templates should belong to
TemplateInstance *tinst; // enclosing template instance
- unsigned callSuper; // primitive flow analysis for constructors
- unsigned *fieldinit;
+ unsigned char callSuper; // primitive flow analysis for constructors
+ unsigned char *fieldinit;
size_t fieldinit_dim;
AlignDeclaration *aligndecl; // alignment for struct members
+ /// C++ namespace this symbol belongs to
+ CPPNamespaceDeclaration *namespace_;
+
LINK linkage; // linkage for external functions
CPPMANGLE cppmangle; // C++ mangle type
- PINLINE inlining; // inlining strategy for functions
+ PragmaDeclaration *inlining; // inlining strategy for functions
- Prot protection; // protection for class members
- int explicitProtection; // set if in an explicit protection attribute
+ Visibility visibility; // visibility for class members
+ int explicitVisibility; // set if in an explicit visibility attribute
StorageClass stc; // storage class
@@ -125,10 +126,8 @@ struct Scope
AA *anchorCounts; // lookup duplicate anchor name count
Identifier *prevAnchor; // qualified symbol name of last doc anchor
- static Scope *freelist;
- static Scope *alloc();
- static Scope *createGlobal(Module *module);
-
+ AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value,
+ // do not set wasRead for it
Scope();
Scope *copy();
@@ -140,21 +139,12 @@ struct Scope
Scope *startCTFE();
Scope *endCTFE();
- void mergeCallSuper(Loc loc, unsigned cs);
-
- unsigned *saveFieldInit();
- void mergeFieldInit(Loc loc, unsigned *cses);
-
- Module *instantiatingModule();
-
- Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone);
- Dsymbol *search_correct(Identifier *ident);
- static const char *search_correct_C(Identifier *ident);
- Dsymbol *insert(Dsymbol *s);
+ Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone);
ClassDeclaration *getClassScope();
AggregateDeclaration *getStructClassScope();
- void setNoFree();
structalign_t alignment();
+
+ bool isDeprecated() const;
};
diff --git a/gcc/d/dmd/semantic2.c b/gcc/d/dmd/semantic2.c
deleted file mode 100644
index 194a3fb..0000000
--- a/gcc/d/dmd/semantic2.c
+++ /dev/null
@@ -1,430 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- */
-
-#include "dsymbol.h"
-#include "aggregate.h"
-#include "attrib.h"
-#include "declaration.h"
-#include "errors.h"
-#include "import.h"
-#include "init.h"
-#include "module.h"
-#include "nspace.h"
-#include "objc.h"
-#include "scope.h"
-#include "staticassert.h"
-#include "template.h"
-#include "visitor.h"
-
-bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
-void udaExpressionEval(Scope *sc, Expressions *exps);
-Objc *objc();
-
-class Semantic2Visitor : public Visitor
-{
-public:
- Scope *sc;
-
- Semantic2Visitor(Scope *sc)
- {
- this->sc = sc;
- }
-
- void visit(Dsymbol *)
- {
- // Most Dsymbols have no further semantic analysis needed
- }
-
- void visit(StaticAssert *sa)
- {
- //printf("StaticAssert::semantic2() %s\n", toChars());
- ScopeDsymbol *sds = new ScopeDsymbol();
- sc = sc->push(sds);
- sc->tinst = NULL;
- sc->minst = NULL;
-
- bool errors = false;
- bool result = evalStaticCondition(sc, sa->exp, sa->exp, errors);
- sc = sc->pop();
- if (errors)
- {
- errorSupplemental(sa->loc, "while evaluating: static assert(%s)", sa->exp->toChars());
- }
- else if (!result)
- {
- if (sa->msg)
- {
- sc = sc->startCTFE();
- sa->msg = expressionSemantic(sa->msg, sc);
- sa->msg = resolveProperties(sc, sa->msg);
- sc = sc->endCTFE();
- sa->msg = sa->msg->ctfeInterpret();
- if (StringExp * se = sa->msg->toStringExp())
- {
- // same with pragma(msg)
- se = se->toUTF8(sc);
- sa->error("\"%.*s\"", (int)se->len, (char *)se->string);
- }
- else
- sa->error("%s", sa->msg->toChars());
- }
- else
- sa->error("(%s) is false", sa->exp->toChars());
- if (sc->tinst)
- sc->tinst->printInstantiationTrace();
- if (!global.gag)
- fatal();
- }
- }
-
- void visit(TemplateInstance *tempinst)
- {
- if (tempinst->semanticRun >= PASSsemantic2)
- return;
- tempinst->semanticRun = PASSsemantic2;
- if (!tempinst->errors && tempinst->members)
- {
- TemplateDeclaration *tempdecl = tempinst->tempdecl->isTemplateDeclaration();
- assert(tempdecl);
-
- sc = tempdecl->_scope;
- assert(sc);
- sc = sc->push(tempinst->argsym);
- sc = sc->push(tempinst);
- sc->tinst = tempinst;
- sc->minst = tempinst->minst;
-
- int needGagging = (tempinst->gagged && !global.gag);
- unsigned int olderrors = global.errors;
- int oldGaggedErrors = -1; // dead-store to prevent spurious warning
- if (needGagging)
- oldGaggedErrors = global.startGagging();
-
- for (size_t i = 0; i < tempinst->members->length; i++)
- {
- Dsymbol *s = (*tempinst->members)[i];
- semantic2(s, sc);
- if (tempinst->gagged && global.errors != olderrors)
- break;
- }
-
- if (global.errors != olderrors)
- {
- if (!tempinst->errors)
- {
- if (!tempdecl->literal)
- tempinst->error(tempinst->loc, "error instantiating");
- if (tempinst->tinst)
- tempinst->tinst->printInstantiationTrace();
- }
- tempinst->errors = true;
- }
- if (needGagging)
- global.endGagging(oldGaggedErrors);
-
- sc = sc->pop();
- sc->pop();
- }
- }
-
- void visit(TemplateMixin *tmix)
- {
- if (tmix->semanticRun >= PASSsemantic2)
- return;
- tmix->semanticRun = PASSsemantic2;
- if (tmix->members)
- {
- assert(sc);
- sc = sc->push(tmix->argsym);
- sc = sc->push(tmix);
- for (size_t i = 0; i < tmix->members->length; i++)
- {
- Dsymbol *s = (*tmix->members)[i];
- semantic2(s, sc);
- }
- sc = sc->pop();
- sc->pop();
- }
- }
-
- void visit(VarDeclaration *vd)
- {
- if (vd->semanticRun < PASSsemanticdone && vd->inuse)
- return;
-
- //printf("VarDeclaration::semantic2('%s')\n", toChars());
-
- if (vd->_init && !vd->toParent()->isFuncDeclaration())
- {
- vd->inuse++;
-
- /* https://issues.dlang.org/show_bug.cgi?id=20280
- *
- * Template instances may import modules that have not
- * finished semantic1.
- */
- if (!vd->type)
- dsymbolSemantic(vd, sc);
-
- // Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof
- vd->_init = initializerSemantic(vd->_init, sc, vd->type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
- vd->inuse--;
- }
- if (vd->_init && (vd->storage_class & STCmanifest))
- {
- /* Cannot initializer enums with CTFE classreferences and addresses of struct literals.
- * Scan initializer looking for them. Issue error if found.
- */
- if (ExpInitializer *ei = vd->_init->isExpInitializer())
- {
- struct EnumInitializer
- {
- static bool arrayHasInvalidEnumInitializer(Expressions *elems)
- {
- for (size_t i = 0; i < elems->length; i++)
- {
- Expression *e = (*elems)[i];
- if (e && hasInvalidEnumInitializer(e))
- return true;
- }
- return false;
- }
-
- static bool hasInvalidEnumInitializer(Expression *e)
- {
- if (e->op == TOKclassreference)
- return true;
- if (e->op == TOKaddress && ((AddrExp *)e)->e1->op == TOKstructliteral)
- return true;
- if (e->op == TOKarrayliteral)
- return arrayHasInvalidEnumInitializer(((ArrayLiteralExp *)e)->elements);
- if (e->op == TOKstructliteral)
- return arrayHasInvalidEnumInitializer(((StructLiteralExp *)e)->elements);
- if (e->op == TOKassocarrayliteral)
- {
- AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e;
- return arrayHasInvalidEnumInitializer(ae->values) ||
- arrayHasInvalidEnumInitializer(ae->keys);
- }
- return false;
- }
- };
- if (EnumInitializer::hasInvalidEnumInitializer(ei->exp))
- vd->error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead.");
- }
- }
- else if (vd->_init && vd->isThreadlocal())
- {
- if ((vd->type->ty == Tclass) && vd->type->isMutable() && !vd->type->isShared())
- {
- ExpInitializer *ei = vd->_init->isExpInitializer();
- if (ei && ei->exp->op == TOKclassreference)
- vd->error("is mutable. Only const or immutable class thread local variable are allowed, not %s", vd->type->toChars());
- }
- else if (vd->type->ty == Tpointer && vd->type->nextOf()->ty == Tstruct && vd->type->nextOf()->isMutable() && !vd->type->nextOf()->isShared())
- {
- ExpInitializer *ei = vd->_init->isExpInitializer();
- if (ei && ei->exp->op == TOKaddress && ((AddrExp *)ei->exp)->e1->op == TOKstructliteral)
- {
- vd->error("is a pointer to mutable struct. Only pointers to const, immutable or shared struct thread local variable are allowed, not %s", vd->type->toChars());
- }
- }
- }
- vd->semanticRun = PASSsemantic2done;
- }
-
- void visit(Module *mod)
- {
- //printf("Module::semantic2('%s'): parent = %p\n", toChars(), mod->parent);
- if (mod->semanticRun != PASSsemanticdone) // semantic() not completed yet - could be recursive call
- return;
- mod->semanticRun = PASSsemantic2;
-
- // Note that modules get their own scope, from scratch.
- // This is so regardless of where in the syntax a module
- // gets imported, it is unaffected by context.
- Scope *sc = Scope::createGlobal(mod); // create root scope
- //printf("Module = %p\n", sc.scopesym);
-
- // Pass 2 semantic routines: do initializers and function bodies
- for (size_t i = 0; i < mod->members->length; i++)
- {
- Dsymbol *s = (*mod->members)[i];
- semantic2(s, sc);
- }
-
- if (mod->userAttribDecl)
- {
- semantic2(mod->userAttribDecl, sc);
- }
-
- sc = sc->pop();
- sc->pop();
- mod->semanticRun = PASSsemantic2done;
- //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), mod->parent);
- }
-
- void visit(FuncDeclaration *fd)
- {
- if (fd->semanticRun >= PASSsemantic2done)
- return;
-
- if (fd->semanticRun < PASSsemanticdone && !fd->errors)
- {
- /* https://issues.dlang.org/show_bug.cgi?id=21614
- *
- * Template instances may import modules that have not
- * finished semantic1.
- */
- dsymbolSemantic(fd, sc);
- }
-
- assert(fd->semanticRun <= PASSsemantic2);
- fd->semanticRun = PASSsemantic2;
-
- objc()->setSelector(fd, sc);
- objc()->validateSelector(fd);
-
- if (fd->parent->isClassDeclaration())
- {
- objc()->checkLinkage(fd);
- }
- if (!fd->type || fd->type->ty != Tfunction)
- return;
- TypeFunction *f = fd->type->toTypeFunction();
- const size_t nparams = f->parameterList.length();
- // semantic for parameters' UDAs
- for (size_t i = 0; i < nparams; i++)
- {
- Parameter *param = f->parameterList[i];
- if (param && param->userAttribDecl)
- semantic2(param->userAttribDecl, sc);
- }
- }
-
- void visit(Import *i)
- {
- //printf("Import::semantic2('%s')\n", toChars());
- if (i->mod)
- {
- semantic2(i->mod, NULL);
- if (i->mod->needmoduleinfo)
- {
- //printf("module5 %s because of %s\n", sc->_module->toChars(), i->mod->toChars());
- if (sc)
- sc->_module->needmoduleinfo = 1;
- }
- }
- }
-
- void visit(Nspace *ns)
- {
- if (ns->semanticRun >= PASSsemantic2)
- return;
- ns->semanticRun = PASSsemantic2;
- if (ns->members)
- {
- assert(sc);
- sc = sc->push(ns);
- sc->linkage = LINKcpp;
- for (size_t i = 0; i < ns->members->length; i++)
- {
- Dsymbol *s = (*ns->members)[i];
- semantic2(s, sc);
- }
- sc->pop();
- }
- }
-
- void visit(AttribDeclaration *ad)
- {
- Dsymbols *d = ad->include(sc);
-
- if (d)
- {
- Scope *sc2 = ad->newScope(sc);
-
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- semantic2(s, sc2);
- }
-
- if (sc2 != sc)
- sc2->pop();
- }
- }
-
- /**
- * Run the DeprecatedDeclaration's semantic2 phase then its members.
- *
- * The message set via a `DeprecatedDeclaration` can be either of:
- * - a string literal
- * - an enum
- * - a static immutable
- * So we need to call ctfe to resolve it.
- * Afterward forwards to the members' semantic2.
- */
- void visit(DeprecatedDeclaration *dd)
- {
- dd->getMessage();
- visit((AttribDeclaration *)dd);
- }
-
- void visit(AlignDeclaration *ad)
- {
- ad->getAlignment(sc);
- visit((AttribDeclaration *)ad);
- }
-
- void visit(UserAttributeDeclaration *uad)
- {
- if (uad->decl && uad->atts && uad->atts->length && uad->_scope)
- {
- uad->_scope = NULL;
- udaExpressionEval(sc, uad->atts);
- }
- visit((AttribDeclaration *)uad);
- }
-
- void visit(AggregateDeclaration *ad)
- {
- //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", toChars(), ad->type->toChars(), ad->errors);
- if (!ad->members)
- return;
-
- if (ad->_scope)
- {
- ad->error("has forward references");
- return;
- }
-
- Scope *sc2 = ad->newScope(sc);
-
- ad->determineSize(ad->loc);
-
- for (size_t i = 0; i < ad->members->length; i++)
- {
- Dsymbol *s = (*ad->members)[i];
- //printf("\t[%d] %s\n", i, s->toChars());
- semantic2(s, sc2);
- }
-
- sc2->pop();
- }
-};
-
-/*************************************
- * Does semantic analysis on initializers and members of aggregates.
- */
-void semantic2(Dsymbol *dsym, Scope *sc)
-{
- Semantic2Visitor v(sc);
- dsym->accept(&v);
-}
diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d
new file mode 100644
index 0000000..7b2fa5e
--- /dev/null
+++ b/gcc/d/dmd/semantic2.d
@@ -0,0 +1,774 @@
+/**
+ * Performs the semantic2 stage, which deals with initializer expressions.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic2.d, _semantic2.d)
+ * Documentation: https://dlang.org/phobos/dmd_semantic2.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/semantic2.d
+ */
+
+module dmd.semantic2;
+
+import core.stdc.stdio;
+import core.stdc.string;
+
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arraytypes;
+import dmd.astcodegen;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.blockexit;
+import dmd.clone;
+import dmd.dcast;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dimport;
+import dmd.dinterpret;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.dversion;
+import dmd.errors;
+import dmd.escape;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.initsem;
+import dmd.hdrgen;
+import dmd.mtype;
+import dmd.nogc;
+import dmd.nspace;
+import dmd.objc;
+import dmd.opover;
+import dmd.parse;
+import dmd.root.filename;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+import dmd.root.rootobject;
+import dmd.sideeffect;
+import dmd.statementsem;
+import dmd.staticassert;
+import dmd.tokens;
+import dmd.utf;
+import dmd.statement;
+import dmd.target;
+import dmd.templateparamsem;
+import dmd.typesem;
+import dmd.visitor;
+
+enum LOG = false;
+
+
+/*************************************
+ * Does semantic analysis on initializers and members of aggregates.
+ */
+extern(C++) void semantic2(Dsymbol dsym, Scope* sc)
+{
+ scope v = new Semantic2Visitor(sc);
+ dsym.accept(v);
+}
+
+private extern(C++) final class Semantic2Visitor : Visitor
+{
+ alias visit = Visitor.visit;
+ Scope* sc;
+ this(Scope* sc)
+ {
+ this.sc = sc;
+ }
+
+ override void visit(Dsymbol) {}
+
+ override void visit(StaticAssert sa)
+ {
+ //printf("StaticAssert::semantic2() %s\n", sa.toChars());
+ auto sds = new ScopeDsymbol();
+ sc = sc.push(sds);
+ sc.tinst = null;
+ sc.minst = null;
+
+ import dmd.staticcond;
+ bool errors;
+ bool result = evalStaticCondition(sc, sa.exp, sa.exp, errors);
+ sc = sc.pop();
+ if (errors)
+ {
+ errorSupplemental(sa.loc, "while evaluating: `static assert(%s)`", sa.exp.toChars());
+ return;
+ }
+ else if (result)
+ return;
+
+ if (sa.msg)
+ {
+ sc = sc.startCTFE();
+ sa.msg = sa.msg.expressionSemantic(sc);
+ sa.msg = resolveProperties(sc, sa.msg);
+ sc = sc.endCTFE();
+ sa.msg = sa.msg.ctfeInterpret();
+ if (StringExp se = sa.msg.toStringExp())
+ {
+ // same with pragma(msg)
+ const slice = se.toUTF8(sc).peekString();
+ error(sa.loc, "static assert: \"%.*s\"", cast(int)slice.length, slice.ptr);
+ }
+ else
+ error(sa.loc, "static assert: %s", sa.msg.toChars());
+ }
+ else
+ error(sa.loc, "static assert: `%s` is false", sa.exp.toChars());
+ if (sc.tinst)
+ sc.tinst.printInstantiationTrace();
+ if (!global.gag)
+ fatal();
+ }
+
+ override void visit(TemplateInstance tempinst)
+ {
+ if (tempinst.semanticRun >= PASS.semantic2)
+ return;
+ tempinst.semanticRun = PASS.semantic2;
+ static if (LOG)
+ {
+ printf("+TemplateInstance.semantic2('%s')\n", tempinst.toChars());
+ scope(exit) printf("-TemplateInstance.semantic2('%s')\n", tempinst.toChars());
+ }
+ if (tempinst.errors || !tempinst.members)
+ return;
+
+ TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration();
+ assert(tempdecl);
+
+ sc = tempdecl._scope;
+ assert(sc);
+ sc = sc.push(tempinst.argsym);
+ sc = sc.push(tempinst);
+ sc.tinst = tempinst;
+ sc.minst = tempinst.minst;
+
+ int needGagging = (tempinst.gagged && !global.gag);
+ uint olderrors = global.errors;
+ int oldGaggedErrors = -1; // dead-store to prevent spurious warning
+ if (needGagging)
+ oldGaggedErrors = global.startGagging();
+
+ for (size_t i = 0; i < tempinst.members.dim; i++)
+ {
+ Dsymbol s = (*tempinst.members)[i];
+ static if (LOG)
+ {
+ printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
+ }
+ s.semantic2(sc);
+ if (tempinst.gagged && global.errors != olderrors)
+ break;
+ }
+
+ if (global.errors != olderrors)
+ {
+ if (!tempinst.errors)
+ {
+ if (!tempdecl.literal)
+ tempinst.error(tempinst.loc, "error instantiating");
+ if (tempinst.tinst)
+ tempinst.tinst.printInstantiationTrace();
+ }
+ tempinst.errors = true;
+ }
+ if (needGagging)
+ global.endGagging(oldGaggedErrors);
+
+ sc = sc.pop();
+ sc.pop();
+ }
+
+ override void visit(TemplateMixin tmix)
+ {
+ if (tmix.semanticRun >= PASS.semantic2)
+ return;
+ tmix.semanticRun = PASS.semantic2;
+ static if (LOG)
+ {
+ printf("+TemplateMixin.semantic2('%s')\n", tmix.toChars());
+ scope(exit) printf("-TemplateMixin.semantic2('%s')\n", tmix.toChars());
+ }
+ if (!tmix.members)
+ return;
+
+ assert(sc);
+ sc = sc.push(tmix.argsym);
+ sc = sc.push(tmix);
+ sc.tinst = tmix;
+ sc.minst = tmix.minst;
+ for (size_t i = 0; i < tmix.members.dim; i++)
+ {
+ Dsymbol s = (*tmix.members)[i];
+ static if (LOG)
+ {
+ printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
+ }
+ s.semantic2(sc);
+ }
+ sc = sc.pop();
+ sc.pop();
+ }
+
+ override void visit(VarDeclaration vd)
+ {
+ if (vd.semanticRun < PASS.semanticdone && vd.inuse)
+ return;
+
+ //printf("VarDeclaration::semantic2('%s')\n", toChars());
+
+ if (vd.aliassym) // if it's a tuple
+ {
+ vd.aliassym.accept(this);
+ vd.semanticRun = PASS.semantic2done;
+ return;
+ }
+
+ UserAttributeDeclaration.checkGNUABITag(vd, vd.linkage);
+
+ if (vd._init && !vd.toParent().isFuncDeclaration())
+ {
+ vd.inuse++;
+
+ /* https://issues.dlang.org/show_bug.cgi?id=20280
+ *
+ * Template instances may import modules that have not
+ * finished semantic1.
+ */
+ if (!vd.type)
+ vd.dsymbolSemantic(sc);
+
+
+ // https://issues.dlang.org/show_bug.cgi?id=14166
+ // https://issues.dlang.org/show_bug.cgi?id=20417
+ // Don't run CTFE for the temporary variables inside typeof or __traits(compiles)
+ vd._init = vd._init.initializerSemantic(sc, vd.type, sc.intypeof == 1 || sc.flags & SCOPE.compile ? INITnointerpret : INITinterpret);
+ vd.inuse--;
+ }
+ if (vd._init && vd.storage_class & STC.manifest)
+ {
+ /* Cannot initializer enums with CTFE classreferences and addresses of struct literals.
+ * Scan initializer looking for them. Issue error if found.
+ */
+ if (ExpInitializer ei = vd._init.isExpInitializer())
+ {
+ static bool hasInvalidEnumInitializer(Expression e)
+ {
+ static bool arrayHasInvalidEnumInitializer(Expressions* elems)
+ {
+ foreach (e; *elems)
+ {
+ if (e && hasInvalidEnumInitializer(e))
+ return true;
+ }
+ return false;
+ }
+
+ if (e.op == TOK.classReference)
+ return true;
+ if (e.op == TOK.address && (cast(AddrExp)e).e1.op == TOK.structLiteral)
+ return true;
+ if (e.op == TOK.arrayLiteral)
+ return arrayHasInvalidEnumInitializer((cast(ArrayLiteralExp)e).elements);
+ if (e.op == TOK.structLiteral)
+ return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements);
+ if (e.op == TOK.assocArrayLiteral)
+ {
+ AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e;
+ return arrayHasInvalidEnumInitializer(ae.values) ||
+ arrayHasInvalidEnumInitializer(ae.keys);
+ }
+ return false;
+ }
+
+ if (hasInvalidEnumInitializer(ei.exp))
+ vd.error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead.");
+ }
+ }
+ else if (vd._init && vd.isThreadlocal())
+ {
+ // Cannot initialize a thread-local class or pointer to struct variable with a literal
+ // that itself is a thread-local reference and would need dynamic initialization also.
+ if ((vd.type.ty == Tclass) && vd.type.isMutable() && !vd.type.isShared())
+ {
+ ExpInitializer ei = vd._init.isExpInitializer();
+ if (ei && ei.exp.op == TOK.classReference)
+ vd.error("is a thread-local class and cannot have a static initializer. Use `static this()` to initialize instead.");
+ }
+ else if (vd.type.ty == Tpointer && vd.type.nextOf().ty == Tstruct && vd.type.nextOf().isMutable() && !vd.type.nextOf().isShared())
+ {
+ ExpInitializer ei = vd._init.isExpInitializer();
+ if (ei && ei.exp.op == TOK.address && (cast(AddrExp)ei.exp).e1.op == TOK.structLiteral)
+ vd.error("is a thread-local pointer to struct and cannot have a static initializer. Use `static this()` to initialize instead.");
+ }
+ }
+ vd.semanticRun = PASS.semantic2done;
+ }
+
+ override void visit(Module mod)
+ {
+ //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent);
+ if (mod.semanticRun != PASS.semanticdone) // semantic() not completed yet - could be recursive call
+ return;
+ mod.semanticRun = PASS.semantic2;
+ // Note that modules get their own scope, from scratch.
+ // This is so regardless of where in the syntax a module
+ // gets imported, it is unaffected by context.
+ Scope* sc = Scope.createGlobal(mod); // create root scope
+ //printf("Module = %p\n", sc.scopesym);
+ // Pass 2 semantic routines: do initializers and function bodies
+ for (size_t i = 0; i < mod.members.dim; i++)
+ {
+ Dsymbol s = (*mod.members)[i];
+ s.semantic2(sc);
+ }
+ if (mod.userAttribDecl)
+ {
+ mod.userAttribDecl.semantic2(sc);
+ }
+ sc = sc.pop();
+ sc.pop();
+ mod.semanticRun = PASS.semantic2done;
+ //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent);
+ }
+
+ override void visit(FuncDeclaration fd)
+ {
+ if (fd.semanticRun >= PASS.semantic2done)
+ return;
+
+ if (fd.semanticRun < PASS.semanticdone && !fd.errors)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=21614
+ *
+ * Template instances may import modules that have not
+ * finished semantic1.
+ */
+ fd.dsymbolSemantic(sc);
+ }
+ assert(fd.semanticRun <= PASS.semantic2);
+ fd.semanticRun = PASS.semantic2;
+
+ //printf("FuncDeclaration::semantic2 [%s] fd0 = %s %s\n", loc.toChars(), toChars(), type.toChars());
+
+ // Only check valid functions which have a body to avoid errors
+ // for multiple declarations, e.g.
+ // void foo();
+ // void foo();
+ if (fd.fbody && fd.overnext && !fd.errors)
+ {
+ // Always starts the lookup from 'this', because the conflicts with
+ // previous overloads are already reported.
+ alias f1 = fd;
+ auto tf1 = cast(TypeFunction) f1.type;
+ auto parent1 = f1.toParent2();
+
+ overloadApply(f1, (Dsymbol s)
+ {
+ auto f2 = s.isFuncDeclaration();
+ if (!f2 || f1 == f2 || f2.errors)
+ return 0;
+
+ // Don't have to check conflict between declaration and definition.
+ if (f2.fbody is null)
+ return 0;
+
+ // Functions with different manglings can never conflict
+ if (f1.linkage != f2.linkage)
+ return 0;
+
+ // Functions with different names never conflict
+ // (they can form overloads sets introduced by an alias)
+ if (f1.ident != f2.ident)
+ return 0;
+
+ // Functions with different parents never conflict
+ // (E.g. when aliasing a free function into a struct)
+ if (parent1 != f2.toParent2())
+ return 0;
+
+ /* Check for overload merging with base class member functions.
+ *
+ * class B { void foo() {} }
+ * class D : B {
+ * override void foo() {} // B.foo appears as f2
+ * alias foo = B.foo;
+ * }
+ */
+ if (f1.overrides(f2))
+ return 0;
+
+ auto tf2 = cast(TypeFunction) f2.type;
+
+ // Overloading based on storage classes
+ if (tf1.mod != tf2.mod || ((f1.storage_class ^ f2.storage_class) & STC.static_))
+ return 0;
+
+ const sameAttr = tf1.attributesEqual(tf2);
+ const sameParams = tf1.parameterList == tf2.parameterList;
+
+ // Allow the hack to declare overloads with different parameters/STC's
+ // @@@DEPRECATED_2.094@@@
+ // Deprecated in 2020-08, make this an error in 2.104
+ if (parent1.isModule() &&
+ f1.linkage != LINK.d && f1.linkage != LINK.cpp &&
+ (!sameAttr || !sameParams)
+ )
+ {
+ f2.deprecation("cannot overload `extern(%s)` function at %s",
+ linkageToChars(f1.linkage),
+ f1.loc.toChars());
+ return 0;
+ }
+
+ // Different parameters don't conflict in extern(C++/D)
+ if (!sameParams)
+ return 0;
+
+ // Different attributes don't conflict in extern(D)
+ if (!sameAttr && f1.linkage == LINK.d)
+ return 0;
+
+ error(f2.loc, "%s `%s%s` conflicts with previous declaration at %s",
+ f2.kind(),
+ f2.toPrettyChars(),
+ parametersTypeToChars(tf2.parameterList),
+ f1.loc.toChars());
+ f2.type = Type.terror;
+ f2.errors = true;
+ return 0;
+ });
+ }
+ if (!fd.type || fd.type.ty != Tfunction)
+ return;
+ TypeFunction f = cast(TypeFunction) fd.type;
+
+ UserAttributeDeclaration.checkGNUABITag(fd, fd.linkage);
+ //semantic for parameters' UDAs
+ foreach (i, param; f.parameterList)
+ {
+ if (param && param.userAttribDecl)
+ param.userAttribDecl.semantic2(sc);
+ }
+ }
+
+ override void visit(Import i)
+ {
+ //printf("Import::semantic2('%s')\n", toChars());
+ if (!i.mod)
+ return;
+
+ i.mod.semantic2(null);
+ if (i.mod.needmoduleinfo)
+ {
+ //printf("module5 %s because of %s\n", sc.module.toChars(), mod.toChars());
+ if (sc)
+ sc._module.needmoduleinfo = 1;
+ }
+ }
+
+ override void visit(Nspace ns)
+ {
+ if (ns.semanticRun >= PASS.semantic2)
+ return;
+ ns.semanticRun = PASS.semantic2;
+ static if (LOG)
+ {
+ printf("+Nspace::semantic2('%s')\n", ns.toChars());
+ scope(exit) printf("-Nspace::semantic2('%s')\n", ns.toChars());
+ }
+ UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp);
+ if (!ns.members)
+ return;
+
+ assert(sc);
+ sc = sc.push(ns);
+ sc.linkage = LINK.cpp;
+ foreach (s; *ns.members)
+ {
+ static if (LOG)
+ {
+ printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
+ }
+ s.semantic2(sc);
+ }
+ sc.pop();
+ }
+
+ override void visit(AttribDeclaration ad)
+ {
+ Dsymbols* d = ad.include(sc);
+ if (!d)
+ return;
+
+ Scope* sc2 = ad.newScope(sc);
+ for (size_t i = 0; i < d.dim; i++)
+ {
+ Dsymbol s = (*d)[i];
+ s.semantic2(sc2);
+ }
+ if (sc2 != sc)
+ sc2.pop();
+ }
+
+ /**
+ * Run the DeprecatedDeclaration's semantic2 phase then its members.
+ *
+ * The message set via a `DeprecatedDeclaration` can be either of:
+ * - a string literal
+ * - an enum
+ * - a static immutable
+ * So we need to call ctfe to resolve it.
+ * Afterward forwards to the members' semantic2.
+ */
+ override void visit(DeprecatedDeclaration dd)
+ {
+ getMessage(dd);
+ visit(cast(AttribDeclaration)dd);
+ }
+
+ override void visit(AlignDeclaration ad)
+ {
+ ad.getAlignment(sc);
+ visit(cast(AttribDeclaration)ad);
+ }
+
+ override void visit(CPPNamespaceDeclaration decl)
+ {
+ UserAttributeDeclaration.checkGNUABITag(decl, LINK.cpp);
+ visit(cast(AttribDeclaration)decl);
+ }
+
+ override void visit(UserAttributeDeclaration uad)
+ {
+ if (!uad.decl || !uad.atts || !uad.atts.dim || !uad._scope)
+ return visit(cast(AttribDeclaration)uad);
+
+ Expression* lastTag;
+ static void eval(Scope* sc, Expressions* exps, ref Expression* lastTag)
+ {
+ foreach (ref Expression e; *exps)
+ {
+ if (!e)
+ continue;
+
+ e = e.expressionSemantic(sc);
+ if (definitelyValueParameter(e))
+ e = e.ctfeInterpret();
+ if (e.op == TOK.tuple)
+ {
+ TupleExp te = cast(TupleExp)e;
+ eval(sc, te.exps, lastTag);
+ }
+
+ // Handles compiler-recognized `core.attribute.gnuAbiTag`
+ if (UserAttributeDeclaration.isGNUABITag(e))
+ doGNUABITagSemantic(e, lastTag);
+ }
+ }
+
+ uad._scope = null;
+ eval(sc, uad.atts, lastTag);
+ visit(cast(AttribDeclaration)uad);
+ }
+
+ override void visit(AggregateDeclaration ad)
+ {
+ //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", ad.toChars(), ad.type.toChars(), ad.errors);
+ if (!ad.members)
+ return;
+
+ if (ad._scope)
+ {
+ ad.error("has forward references");
+ return;
+ }
+
+ UserAttributeDeclaration.checkGNUABITag(
+ ad, ad.classKind == ClassKind.cpp ? LINK.cpp : LINK.d);
+
+ auto sc2 = ad.newScope(sc);
+
+ ad.determineSize(ad.loc);
+
+ for (size_t i = 0; i < ad.members.dim; i++)
+ {
+ Dsymbol s = (*ad.members)[i];
+ //printf("\t[%d] %s\n", i, s.toChars());
+ s.semantic2(sc2);
+ }
+
+ sc2.pop();
+ }
+
+ override void visit(ClassDeclaration cd)
+ {
+ /// Checks that the given class implements all methods of its interfaces.
+ static void checkInterfaceImplementations(ClassDeclaration cd)
+ {
+ foreach (base; cd.interfaces)
+ {
+ // first entry is ClassInfo reference
+ auto methods = base.sym.vtbl[base.sym.vtblOffset .. $];
+
+ foreach (m; methods)
+ {
+ auto ifd = m.isFuncDeclaration;
+ assert(ifd);
+
+ if (ifd.objc.isOptional)
+ continue;
+
+ auto type = ifd.type.toTypeFunction();
+ auto fd = cd.findFunc(ifd.ident, type);
+
+ if (fd && !fd.isAbstract)
+ {
+ //printf(" found\n");
+ // Check that calling conventions match
+ if (fd.linkage != ifd.linkage)
+ fd.error("linkage doesn't match interface function");
+
+ // Check that it is current
+ //printf("newinstance = %d fd.toParent() = %s ifd.toParent() = %s\n",
+ //newinstance, fd.toParent().toChars(), ifd.toParent().toChars());
+ if (fd.toParent() != cd && ifd.toParent() == base.sym)
+ cd.error("interface function `%s` is not implemented", ifd.toFullSignature());
+ }
+ else
+ {
+ //printf(" not found %p\n", fd);
+ // BUG: should mark this class as abstract?
+ if (!cd.isAbstract())
+ cd.error("interface function `%s` is not implemented", ifd.toFullSignature());
+ }
+ }
+ }
+ }
+
+ if (cd.semanticRun >= PASS.semantic2done)
+ return;
+ assert(cd.semanticRun <= PASS.semantic2);
+ cd.semanticRun = PASS.semantic2;
+
+ checkInterfaceImplementations(cd);
+ visit(cast(AggregateDeclaration) cd);
+ }
+
+ override void visit(InterfaceDeclaration cd)
+ {
+ visit(cast(AggregateDeclaration) cd);
+ }
+}
+
+/**
+ * Perform semantic analysis specific to the GNU ABI tags
+ *
+ * The GNU ABI tags are a feature introduced in C++11, specific to g++
+ * and the Itanium ABI.
+ * They are mandatory for C++ interfacing, simply because the templated struct
+ *`std::basic_string`, of which the ubiquitous `std::string` is a instantiation
+ * of, uses them.
+ *
+ * Params:
+ * e = Expression to perform semantic on
+ * See `Semantic2Visitor.visit(UserAttributeDeclaration)`
+ * lastTag = When `!is null`, we already saw an ABI tag.
+ * To simplify implementation and reflection code,
+ * only one ABI tag object is allowed per symbol
+ * (but it can have multiple tags as it's an array exp).
+ */
+private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag)
+{
+ import dmd.dmangle;
+
+ // When `@gnuAbiTag` is used, the type will be the UDA, not the struct literal
+ if (e.op == TOK.type)
+ {
+ e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars());
+ return;
+ }
+
+ // Definition is in `core.attributes`. If it's not a struct literal,
+ // it shouldn't have passed semantic, hence the `assert`.
+ auto sle = e.isStructLiteralExp();
+ if (sle is null)
+ {
+ assert(global.errors);
+ return;
+ }
+ // The definition of `gnuAttributes` only have 1 member, `string[] tags`
+ assert(sle.elements && sle.elements.length == 1);
+ // `gnuAbiTag`'s constructor is defined as `this(string[] tags...)`
+ auto ale = (*sle.elements)[0].isArrayLiteralExp();
+ if (ale is null)
+ {
+ e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars());
+ return;
+ }
+
+ // Check that it's the only tag on the symbol
+ if (lastTag !is null)
+ {
+ const str1 = (*lastTag.isStructLiteralExp().elements)[0].toString();
+ const str2 = ale.toString();
+ e.error("only one `@%s` allowed per symbol", Id.udaGNUAbiTag.toChars());
+ e.errorSupplemental("instead of `@%s @%s`, use `@%s(%.*s, %.*s)`",
+ lastTag.toChars(), e.toChars(), Id.udaGNUAbiTag.toChars(),
+ // Avoid [ ... ]
+ cast(int)str1.length - 2, str1.ptr + 1,
+ cast(int)str2.length - 2, str2.ptr + 1);
+ return;
+ }
+ lastTag = &e;
+
+ // We already know we have a valid array literal of strings.
+ // Now checks that elements are valid.
+ foreach (idx, elem; *ale.elements)
+ {
+ const str = elem.toStringExp().peekString();
+ if (!str.length)
+ {
+ e.error("argument `%d` to `@%s` cannot be %s", cast(int)(idx + 1),
+ Id.udaGNUAbiTag.toChars(),
+ elem.isNullExp() ? "`null`".ptr : "empty".ptr);
+ continue;
+ }
+
+ foreach (c; str)
+ {
+ if (!c.isValidMangling())
+ {
+ e.error("`@%s` char `0x%02x` not allowed in mangling",
+ Id.udaGNUAbiTag.toChars(), c);
+ break;
+ }
+ }
+ // Valid element
+ }
+ // Since ABI tags need to be sorted, we sort them in place
+ // It might be surprising for users that inspects the UDAs,
+ // but it's a concession to practicality.
+ // Casts are unfortunately necessary as `implicitConvTo` is not
+ // `const` (and nor is `StringExp`, by extension).
+ static int predicate(const scope Expression* e1, const scope Expression* e2) nothrow
+ {
+ scope(failure) assert(0, "An exception was thrown");
+ return (cast(Expression*)e1).toStringExp().compare((cast(Expression*)e2).toStringExp());
+ }
+ ale.elements.sort!predicate;
+}
diff --git a/gcc/d/dmd/semantic3.c b/gcc/d/dmd/semantic3.c
deleted file mode 100644
index 6bd9a6d..0000000
--- a/gcc/d/dmd/semantic3.c
+++ /dev/null
@@ -1,1399 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- */
-
-#include "dsymbol.h"
-#include "aggregate.h"
-#include "attrib.h"
-#include "declaration.h"
-#include "errors.h"
-#include "id.h"
-#include "init.h"
-#include "module.h"
-#include "nspace.h"
-#include "scope.h"
-#include "statement.h"
-#include "statement_rewrite_walker.h"
-#include "target.h"
-#include "template.h"
-#include "visitor.h"
-
-bool allowsContractWithoutBody(FuncDeclaration *funcdecl);
-int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow);
-bool checkReturnEscape(Scope *sc, Expression *e, bool gag);
-bool checkReturnEscapeRef(Scope *sc, Expression *e, bool gag);
-TypeIdentifier *getThrowable();
-char *MODtoChars(MOD mod);
-Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-void allocFieldinit(Scope *sc, size_t dim);
-void freeFieldinit(Scope *sc);
-
-/* Determine if function should add `return 0;`
- */
-static bool addReturn0(FuncDeclaration *funcdecl)
-{
- TypeFunction *f = (TypeFunction *)funcdecl->type;
-
- return f->next->ty == Tvoid &&
- (funcdecl->isMain() || (global.params.betterC && funcdecl->isCMain()));
-}
-
-/********************************************************
- * Generate Expression to call the invariant.
- * Input:
- * ad aggregate with the invariant
- * vthis variable with 'this'
- * Returns:
- * void expression that calls the invariant
- */
-static Expression *addInvariant(AggregateDeclaration *ad, VarDeclaration *vthis)
-{
- Expression *e = NULL;
-
- // Call invariant directly only if it exists
- FuncDeclaration *inv = ad->inv;
- ClassDeclaration *cd = ad->isClassDeclaration();
-
- while (!inv && cd)
- {
- cd = cd->baseClass;
- if (!cd)
- break;
- inv = cd->inv;
- }
- if (inv)
- {
- #if 1
- // Workaround for bugzilla 13394: For the correct mangling,
- // run attribute inference on inv if needed.
- inv->functionSemantic();
- #endif
-
- //e = new DsymbolExp(Loc(), inv);
- //e = new CallExp(Loc(), e);
- //dsymbolSemantic(e, sc2);
-
- /* https://issues.dlang.org/show_bug.cgi?id=13113
- * Currently virtual invariant calls completely
- * bypass attribute enforcement.
- * Change the behavior of pre-invariant call by following it.
- */
- e = new ThisExp(Loc());
- e->type = vthis->type;
- e = new DotVarExp(Loc(), e, inv, false);
- e->type = inv->type;
- e = new CallExp(Loc(), e);
- e->type = Type::tvoid;
- }
- return e;
-}
-
-/* Tweak all return statements and dtor call for nrvo_var, for correct NRVO.
- */
-class NrvoWalker : public StatementRewriteWalker
-{
-public:
- FuncDeclaration *fd;
- Scope *sc;
-
- void visit(ReturnStatement *s)
- {
- // See if all returns are instead to be replaced with a goto returnLabel;
- if (fd->returnLabel)
- {
- /* Rewrite:
- * return exp;
- * as:
- * vresult = exp; goto Lresult;
- */
- GotoStatement *gs = new GotoStatement(s->loc, Id::returnLabel);
- gs->label = fd->returnLabel;
-
- Statement *s1 = gs;
- if (s->exp)
- s1 = new CompoundStatement(s->loc, new ExpStatement(s->loc, s->exp), gs);
-
- replaceCurrent(s1);
- }
- }
- void visit(TryFinallyStatement *s)
- {
- DtorExpStatement *des;
- if (fd->nrvo_can &&
- s->finalbody && (des = s->finalbody->isDtorExpStatement()) != NULL &&
- fd->nrvo_var == des->var)
- {
- if (!(global.params.useExceptions && ClassDeclaration::throwable))
- {
- /* Don't need to call destructor at all, since it is nrvo
- */
- replaceCurrent(s->_body);
- s->_body->accept(this);
- return;
- }
-
- /* Normally local variable dtors are called regardless exceptions.
- * But for nrvo_var, its dtor should be called only when exception is thrown.
- *
- * Rewrite:
- * try { s->body; } finally { nrvo_var->edtor; }
- * // equivalent with:
- * // s->body; scope(exit) nrvo_var->edtor;
- * as:
- * try { s->body; } catch(Throwable __o) { nrvo_var->edtor; throw __o; }
- * // equivalent with:
- * // s->body; scope(failure) nrvo_var->edtor;
- */
- Statement *sexception = new DtorExpStatement(Loc(), fd->nrvo_var->edtor, fd->nrvo_var);
- Identifier *id = Identifier::generateId("__o");
-
- Statement *handler = new PeelStatement(sexception);
- if (blockExit(sexception, fd, false) & BEfallthru)
- {
- ThrowStatement *ts = new ThrowStatement(Loc(), new IdentifierExp(Loc(), id));
- ts->internalThrow = true;
- handler = new CompoundStatement(Loc(), handler, ts);
- }
-
- Catches *catches = new Catches();
- Catch *ctch = new Catch(Loc(), getThrowable(), id, handler);
- ctch->internalCatch = true;
- catchSemantic(ctch, sc); // Run semantic to resolve identifier '__o'
- catches->push(ctch);
-
- Statement *s2 = new TryCatchStatement(Loc(), s->_body, catches);
- replaceCurrent(s2);
- s2->accept(this);
- }
- else
- StatementRewriteWalker::visit(s);
- }
-};
-
-class Semantic3Visitor : public Visitor
-{
-public:
- Scope *sc;
-
- Semantic3Visitor(Scope *sc)
- {
- this->sc = sc;
- }
-
- void visit(Dsymbol *)
- {
- // Most Dsymbols have no further semantic analysis needed
- }
-
- void visit(TemplateInstance *tempinst)
- {
- //if (tempinst->toChars()[0] == 'D') *(char*)0=0;
- if (tempinst->semanticRun >= PASSsemantic3)
- return;
- tempinst->semanticRun = PASSsemantic3;
- if (!tempinst->errors && tempinst->members)
- {
- TemplateDeclaration *tempdecl = tempinst->tempdecl->isTemplateDeclaration();
- assert(tempdecl);
-
- sc = tempdecl->_scope;
- sc = sc->push(tempinst->argsym);
- sc = sc->push(tempinst);
- sc->tinst = tempinst;
- sc->minst = tempinst->minst;
-
- int needGagging = (tempinst->gagged && !global.gag);
- unsigned int olderrors = global.errors;
- int oldGaggedErrors = -1; // dead-store to prevent spurious warning
- /* If this is a gagged instantiation, gag errors.
- * Future optimisation: If the results are actually needed, errors
- * would already be gagged, so we don't really need to run semantic
- * on the members.
- */
- if (needGagging)
- oldGaggedErrors = global.startGagging();
-
- for (size_t i = 0; i < tempinst->members->length; i++)
- {
- Dsymbol *s = (*tempinst->members)[i];
- semantic3(s, sc);
- if (tempinst->gagged && global.errors != olderrors)
- break;
- }
-
- if (global.errors != olderrors)
- {
- if (!tempinst->errors)
- {
- if (!tempdecl->literal)
- tempinst->error(tempinst->loc, "error instantiating");
- if (tempinst->tinst)
- tempinst->tinst->printInstantiationTrace();
- }
- tempinst->errors = true;
- }
- if (needGagging)
- global.endGagging(oldGaggedErrors);
-
- sc = sc->pop();
- sc->pop();
- }
- }
-
- void visit(TemplateMixin *tmix)
- {
- if (tmix->semanticRun >= PASSsemantic3)
- return;
- tmix->semanticRun = PASSsemantic3;
- if (tmix->members)
- {
- sc = sc->push(tmix->argsym);
- sc = sc->push(tmix);
- for (size_t i = 0; i < tmix->members->length; i++)
- {
- Dsymbol *s = (*tmix->members)[i];
- semantic3(s, sc);
- }
- sc = sc->pop();
- sc->pop();
- }
- }
-
- void visit(Module *mod)
- {
- //printf("Module::semantic3('%s'): parent = %p\n", mod->toChars(), mod->parent);
- if (mod->semanticRun != PASSsemantic2done)
- return;
- mod->semanticRun = PASSsemantic3;
-
- // Note that modules get their own scope, from scratch.
- // This is so regardless of where in the syntax a module
- // gets imported, it is unaffected by context.
- Scope *sc = Scope::createGlobal(mod); // create root scope
- //printf("Module = %p\n", sc.scopesym);
-
- // Pass 3 semantic routines: do initializers and function bodies
- for (size_t i = 0; i < mod->members->length; i++)
- {
- Dsymbol *s = (*mod->members)[i];
- //printf("Module %s: %s.semantic3()\n", mod->toChars(), s->toChars());
- semantic3(s, sc);
-
- mod->runDeferredSemantic2();
- }
-
- if (mod->userAttribDecl)
- {
- semantic3(mod->userAttribDecl, sc);
- }
-
- sc = sc->pop();
- sc->pop();
- mod->semanticRun = PASSsemantic3done;
- }
-
- void visit(FuncDeclaration *funcdecl)
- {
- VarDeclaration *_arguments = NULL;
-
- if (!funcdecl->parent)
- {
- if (global.errors)
- return;
- //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", funcdecl->kind(), funcdecl->toChars(), sc);
- assert(0);
- }
- if (funcdecl->errors || isError(funcdecl->parent))
- {
- funcdecl->errors = true;
- return;
- }
- //printf("FuncDeclaration::semantic3('%s.%s', %p, sc = %p, loc = %s)\n", funcdecl->parent->toChars(), funcdecl->toChars(), funcdecl, sc, funcdecl->loc.toChars());
- //fflush(stdout);
- //printf("storage class = x%x %x\n", sc->stc, funcdecl->storage_class);
- //{ static int x; if (++x == 2) *(char*)0=0; }
- //printf("\tlinkage = %d\n", sc->linkage);
-
- if (funcdecl->ident == Id::assign && !funcdecl->inuse)
- {
- if (funcdecl->storage_class & STCinference)
- {
- /* Bugzilla 15044: For generated opAssign function, any errors
- * from its body need to be gagged.
- */
- unsigned oldErrors = global.startGagging();
- funcdecl->inuse++;
- semantic3(funcdecl, sc);
- funcdecl->inuse--;
- if (global.endGagging(oldErrors)) // if errors happened
- {
- // Disable generated opAssign, because some members forbid identity assignment.
- funcdecl->storage_class |= STCdisable;
- funcdecl->fbody = NULL; // remove fbody which contains the error
- funcdecl->semantic3Errors = false;
- }
- return;
- }
- }
-
- //printf(" sc->incontract = %d\n", (sc->flags & SCOPEcontract));
- if (funcdecl->semanticRun >= PASSsemantic3)
- return;
- funcdecl->semanticRun = PASSsemantic3;
- funcdecl->semantic3Errors = false;
-
- if (!funcdecl->type || funcdecl->type->ty != Tfunction)
- return;
- TypeFunction *f = (TypeFunction *)funcdecl->type;
- if (!funcdecl->inferRetType && f->next->ty == Terror)
- return;
-
- if (!funcdecl->fbody && funcdecl->inferRetType && !f->next)
- {
- funcdecl->error("has no function body with return type inference");
- return;
- }
-
- unsigned oldErrors = global.errors;
-
- if (funcdecl->frequires)
- {
- for (size_t i = 0; i < funcdecl->foverrides.length; i++)
- {
- FuncDeclaration *fdv = funcdecl->foverrides[i];
-
- if (fdv->fbody && !fdv->frequires)
- {
- funcdecl->error("cannot have an in contract when overriden function %s does not have an in contract", fdv->toPrettyChars());
- break;
- }
- }
- }
-
- // Remember whether we need to generate an 'out' contract.
- const bool needEnsure = FuncDeclaration::needsFensure(funcdecl);
-
- if (funcdecl->fbody || funcdecl->frequires || needEnsure)
- {
- /* Symbol table into which we place parameters and nested functions,
- * solely to diagnose name collisions.
- */
- funcdecl->localsymtab = new DsymbolTable();
-
- // Establish function scope
- ScopeDsymbol *ss = new ScopeDsymbol();
- // find enclosing scope symbol, might skip symbol-less CTFE and/or FuncExp scopes
- for (Scope *scx = sc; ; scx = scx->enclosing)
- {
- if (scx->scopesym)
- {
- ss->parent = scx->scopesym;
- break;
- }
- }
- ss->loc = funcdecl->loc;
- ss->endlinnum = funcdecl->endloc.linnum;
- Scope *sc2 = sc->push(ss);
- sc2->func = funcdecl;
- sc2->parent = funcdecl;
- sc2->callSuper = 0;
- sc2->sbreak = NULL;
- sc2->scontinue = NULL;
- sc2->sw = NULL;
- sc2->fes = funcdecl->fes;
- sc2->linkage = LINKd;
- sc2->stc &= ~(STCauto | STCscope | STCstatic | STCextern | STCabstract |
- STCdeprecated | STCoverride |
- STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref | STCreturn |
- STCproperty | STCnothrow | STCpure | STCsafe | STCtrusted | STCsystem);
- sc2->protection = Prot(Prot::public_);
- sc2->explicitProtection = 0;
- sc2->aligndecl = NULL;
- if (funcdecl->ident != Id::require && funcdecl->ident != Id::ensure)
- sc2->flags = sc->flags & ~SCOPEcontract;
- sc2->flags &= ~SCOPEcompile;
- sc2->tf = NULL;
- sc2->os = NULL;
- sc2->noctor = 0;
- sc2->userAttribDecl = NULL;
- if (sc2->intypeof == 1) sc2->intypeof = 2;
- sc2->fieldinit = NULL;
- sc2->fieldinit_dim = 0;
-
- /* Note: When a lambda is defined immediately under aggregate member
- * scope, it should be contextless due to prevent interior pointers.
- * e.g.
- * // dg points 'this' - it's interior pointer
- * class C { int x; void delegate() dg = (){ this.x = 1; }; }
- *
- * However, lambdas could be used inside typeof, in order to check
- * some expressions varidity at compile time. For such case the lambda
- * body can access aggregate instance members.
- * e.g.
- * class C { int x; static assert(is(typeof({ this.x = 1; }))); }
- *
- * To properly accept it, mark these lambdas as member functions.
- */
- if (FuncLiteralDeclaration *fld = funcdecl->isFuncLiteralDeclaration())
- {
- if (AggregateDeclaration *ad = funcdecl->isMember2())
- {
- if (!sc->intypeof)
- {
- if (fld->tok == TOKdelegate)
- funcdecl->error("cannot be %s members", ad->kind());
- else
- fld->tok = TOKfunction;
- }
- else
- {
- if (fld->tok != TOKfunction)
- fld->tok = TOKdelegate;
- }
- }
- }
-
- // Declare 'this'
- AggregateDeclaration *ad = funcdecl->isThis();
- funcdecl->vthis = funcdecl->declareThis(sc2, ad);
- //printf("[%s] ad = %p vthis = %p\n", funcdecl->loc.toChars(), ad, funcdecl->vthis);
- //if (funcdecl->vthis) printf("\tvthis->type = %s\n", funcdecl->vthis->type->toChars());
-
- // Declare hidden variable _arguments[] and _argptr
- if (f->parameterList.varargs == VARARGvariadic)
- {
- if (f->linkage == LINKd)
- {
- // Variadic arguments depend on Typeinfo being defined
- if (!global.params.useTypeInfo || !Type::dtypeinfo || !Type::typeinfotypelist)
- {
- if (!global.params.useTypeInfo)
- funcdecl->error("D-style variadic functions cannot be used with -betterC");
- else if (!Type::typeinfotypelist)
- funcdecl->error("`object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions");
- else
- funcdecl->error("`object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions");
- fatal();
- }
-
- // Declare _arguments[]
- funcdecl->v_arguments = new VarDeclaration(Loc(), Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL);
- funcdecl->v_arguments->storage_class |= STCtemp | STCparameter;
- dsymbolSemantic(funcdecl->v_arguments, sc2);
- sc2->insert(funcdecl->v_arguments);
- funcdecl->v_arguments->parent = funcdecl;
-
- //Type *t = Type::typeinfo->type->constOf()->arrayOf();
- Type *t = Type::dtypeinfo->type->arrayOf();
- _arguments = new VarDeclaration(Loc(), t, Id::_arguments, NULL);
- _arguments->storage_class |= STCtemp;
- dsymbolSemantic(_arguments, sc2);
- sc2->insert(_arguments);
- _arguments->parent = funcdecl;
- }
- if (f->linkage == LINKd || f->parameterList.length())
- {
- // Declare _argptr
- Type *t = target.va_listType(funcdecl->loc, sc);
- funcdecl->v_argptr = new VarDeclaration(Loc(), t, Id::_argptr, NULL);
- funcdecl->v_argptr->storage_class |= STCtemp;
- dsymbolSemantic(funcdecl->v_argptr, sc2);
- sc2->insert(funcdecl->v_argptr);
- funcdecl->v_argptr->parent = funcdecl;
- }
- }
-
- /* Declare all the function parameters as variables
- * and install them in parameters[]
- */
- size_t nparams = f->parameterList.length();
- if (nparams)
- {
- /* parameters[] has all the tuples removed, as the back end
- * doesn't know about tuples
- */
- funcdecl->parameters = new VarDeclarations();
- funcdecl->parameters->reserve(nparams);
- for (size_t i = 0; i < nparams; i++)
- {
- Parameter *fparam = f->parameterList[i];
- Identifier *id = fparam->ident;
- StorageClass stc = 0;
- if (!id)
- {
- /* Generate identifier for un-named parameter,
- * because we need it later on.
- */
- fparam->ident = id = Identifier::generateId("_param_", i);
- stc |= STCtemp;
- }
- Type *vtype = fparam->type;
- VarDeclaration *v = new VarDeclaration(funcdecl->loc, vtype, id, NULL);
- //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars());
- stc |= STCparameter;
- if (f->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
- stc |= STCvariadic;
- if (funcdecl->flags & FUNCFLAGinferScope && !(fparam->storageClass & STCscope))
- stc |= STCmaybescope;
- stc |= fparam->storageClass & (STCin | STCout | STCref | STCreturn | STCscope | STClazy | STCfinal | STC_TYPECTOR | STCnodtor);
- v->storage_class = stc;
- dsymbolSemantic(v, sc2);
- if (!sc2->insert(v))
- funcdecl->error("parameter %s.%s is already defined", funcdecl->toChars(), v->toChars());
- else
- funcdecl->parameters->push(v);
- funcdecl->localsymtab->insert(v);
- v->parent = funcdecl;
- if (fparam->userAttribDecl)
- v->userAttribDecl = fparam->userAttribDecl;
- }
- }
-
- // Declare the tuple symbols and put them in the symbol table,
- // but not in parameters[].
- if (f->parameterList.parameters)
- {
- for (size_t i = 0; i < f->parameterList.parameters->length; i++)
- {
- Parameter *fparam = (*f->parameterList.parameters)[i];
-
- if (!fparam->ident)
- continue; // never used, so ignore
- if (fparam->type->ty == Ttuple)
- {
- TypeTuple *t = (TypeTuple *)fparam->type;
- size_t dim = Parameter::dim(t->arguments);
- Objects *exps = new Objects();
- exps->setDim(dim);
- for (size_t j = 0; j < dim; j++)
- {
- Parameter *narg = Parameter::getNth(t->arguments, j);
- assert(narg->ident);
- VarDeclaration *v = sc2->search(Loc(), narg->ident, NULL)->isVarDeclaration();
- assert(v);
- Expression *e = new VarExp(v->loc, v);
- (*exps)[j] = e;
- }
- assert(fparam->ident);
- TupleDeclaration *v = new TupleDeclaration(funcdecl->loc, fparam->ident, exps);
- //printf("declaring tuple %s\n", v->toChars());
- v->isexp = true;
- if (!sc2->insert(v))
- funcdecl->error("parameter %s.%s is already defined", funcdecl->toChars(), v->toChars());
- funcdecl->localsymtab->insert(v);
- v->parent = funcdecl;
- }
- }
- }
-
- // Precondition invariant
- Statement *fpreinv = NULL;
- if (funcdecl->addPreInvariant())
- {
- Expression *e = addInvariant(ad, funcdecl->vthis);
- if (e)
- fpreinv = new ExpStatement(Loc(), e);
- }
-
- // Postcondition invariant
- Statement *fpostinv = NULL;
- if (funcdecl->addPostInvariant())
- {
- Expression *e = addInvariant(ad, funcdecl->vthis);
- if (e)
- fpostinv = new ExpStatement(Loc(), e);
- }
-
- // Pre/Postcondition contract
- if (!funcdecl->fbody)
- funcdecl->buildEnsureRequire();
-
- Scope *scout = NULL;
- if (needEnsure || funcdecl->addPostInvariant())
- {
- if ((needEnsure && global.params.useOut == CHECKENABLEon) || fpostinv)
- {
- funcdecl->returnLabel = new LabelDsymbol(Id::returnLabel);
- }
-
- // scope of out contract (need for vresult->semantic)
- ScopeDsymbol *sym = new ScopeDsymbol();
- sym->parent = sc2->scopesym;
- sym->loc = funcdecl->loc;
- sym->endlinnum = funcdecl->endloc.linnum;
- scout = sc2->push(sym);
- }
-
- if (funcdecl->fbody)
- {
- ScopeDsymbol *sym = new ScopeDsymbol();
- sym->parent = sc2->scopesym;
- sym->loc = funcdecl->loc;
- sym->endlinnum = funcdecl->endloc.linnum;
- sc2 = sc2->push(sym);
-
- AggregateDeclaration *ad2 = funcdecl->isMember2();
-
- /* If this is a class constructor
- */
- if (ad2 && funcdecl->isCtorDeclaration())
- {
- allocFieldinit(sc2, ad2->fields.length);
- for (size_t i = 0; i < ad2->fields.length; i++)
- {
- VarDeclaration *v = ad2->fields[i];
- v->ctorinit = 0;
- }
- }
-
- bool inferRef = (f->isref && (funcdecl->storage_class & STCauto));
-
- funcdecl->fbody = statementSemantic(funcdecl->fbody, sc2);
- if (!funcdecl->fbody)
- funcdecl->fbody = new CompoundStatement(Loc(), new Statements());
-
- if (funcdecl->naked)
- {
- fpreinv = NULL; // can't accommodate with no stack frame
- fpostinv = NULL;
- }
-
- assert(funcdecl->type == f ||
- (funcdecl->type->ty == Tfunction &&
- f->purity == PUREimpure &&
- ((TypeFunction *)funcdecl->type)->purity >= PUREfwdref));
- f = (TypeFunction *)funcdecl->type;
-
- if (funcdecl->inferRetType)
- {
- // If no return type inferred yet, then infer a void
- if (!f->next)
- f->next = Type::tvoid;
- if (f->checkRetType(funcdecl->loc))
- funcdecl->fbody = new ErrorStatement();
- }
- if (global.params.vcomplex && f->next != NULL)
- f->next->checkComplexTransition(funcdecl->loc);
-
- if (funcdecl->returns && !funcdecl->fbody->isErrorStatement())
- {
- for (size_t i = 0; i < funcdecl->returns->length; )
- {
- Expression *exp = (*funcdecl->returns)[i]->exp;
- if (exp->op == TOKvar && ((VarExp *)exp)->var == funcdecl->vresult)
- {
- if (addReturn0(funcdecl))
- exp->type = Type::tint32;
- else
- exp->type = f->next;
- // Remove `return vresult;` from returns
- funcdecl->returns->remove(i);
- continue;
- }
- if (inferRef && f->isref && !exp->type->constConv(f->next)) // Bugzilla 13336
- f->isref = false;
- i++;
- }
- }
- if (f->isref) // Function returns a reference
- {
- if (funcdecl->storage_class & STCauto)
- funcdecl->storage_class &= ~STCauto;
- }
- if (!target.isReturnOnStack(f, funcdecl->needThis()) || !funcdecl->checkNRVO())
- funcdecl->nrvo_can = 0;
-
- if (funcdecl->fbody->isErrorStatement())
- ;
- else if (funcdecl->isStaticCtorDeclaration())
- {
- /* It's a static constructor. Ensure that all
- * ctor consts were initialized.
- */
- ScopeDsymbol *pd = funcdecl->toParent()->isScopeDsymbol();
- for (size_t i = 0; i < pd->members->length; i++)
- {
- Dsymbol *s = (*pd->members)[i];
- s->checkCtorConstInit();
- }
- }
- else if (ad2 && funcdecl->isCtorDeclaration())
- {
- ClassDeclaration *cd = ad2->isClassDeclaration();
-
- // Verify that all the ctorinit fields got initialized
- if (!(sc2->callSuper & CSXthis_ctor))
- {
- for (size_t i = 0; i < ad2->fields.length; i++)
- {
- VarDeclaration *v = ad2->fields[i];
- if (v->isThisDeclaration())
- continue;
- if (v->ctorinit == 0)
- {
- /* Current bugs in the flow analysis:
- * 1. union members should not produce error messages even if
- * not assigned to
- * 2. structs should recognize delegating opAssign calls as well
- * as delegating calls to other constructors
- */
- if (v->isCtorinit() && !v->type->isMutable() && cd)
- funcdecl->error("missing initializer for %s field %s", MODtoChars(v->type->mod), v->toChars());
- else if (v->storage_class & STCnodefaultctor)
- error(funcdecl->loc, "field %s must be initialized in constructor", v->toChars());
- else if (v->type->needsNested())
- error(funcdecl->loc, "field %s must be initialized in constructor, because it is nested struct", v->toChars());
- }
- else
- {
- bool mustInit = (v->storage_class & STCnodefaultctor ||
- v->type->needsNested());
- if (mustInit && !(sc2->fieldinit[i] & CSXthis_ctor))
- {
- funcdecl->error("field %s must be initialized but skipped", v->toChars());
- }
- }
- }
- }
- freeFieldinit(sc2);
-
- if (cd &&
- !(sc2->callSuper & CSXany_ctor) &&
- cd->baseClass && cd->baseClass->ctor)
- {
- sc2->callSuper = 0;
-
- // Insert implicit super() at start of fbody
- FuncDeclaration *fd = resolveFuncCall(Loc(), sc2, cd->baseClass->ctor, NULL, funcdecl->vthis->type, NULL, 1);
- if (!fd)
- {
- funcdecl->error("no match for implicit super() call in constructor");
- }
- else if (fd->storage_class & STCdisable)
- {
- funcdecl->error("cannot call super() implicitly because it is annotated with @disable");
- }
- else
- {
- Expression *e1 = new SuperExp(Loc());
- Expression *e = new CallExp(Loc(), e1);
- e = expressionSemantic(e, sc2);
-
- Statement *s = new ExpStatement(Loc(), e);
- funcdecl->fbody = new CompoundStatement(Loc(), s, funcdecl->fbody);
- }
- }
- //printf("callSuper = x%x\n", sc2->callSuper);
- }
-
- /* https://issues.dlang.org/show_bug.cgi?id=17502
- * Wait until after the return type has been inferred before
- * generating the contracts for this function, and merging contracts
- * from overrides.
- *
- * https://issues.dlang.org/show_bug.cgi?id=17893
- * However should take care to generate this before inferered
- * function attributes are applied, such as 'nothrow'.
- *
- * This was originally at the end of the first semantic pass, but
- * required a fix-up to be done here for the '__result' variable
- * type of __ensure() inside auto functions, but this didn't work
- * if the out parameter was implicit.
- */
- funcdecl->buildEnsureRequire();
-
- int blockexit = BEnone;
- if (!funcdecl->fbody->isErrorStatement())
- {
- // Check for errors related to 'nothrow'.
- unsigned int nothrowErrors = global.errors;
- blockexit = blockExit(funcdecl->fbody, funcdecl, f->isnothrow);
- if (f->isnothrow && (global.errors != nothrowErrors))
- error(funcdecl->loc, "nothrow %s `%s` may throw", funcdecl->kind(), funcdecl->toPrettyChars());
- if (funcdecl->flags & FUNCFLAGnothrowInprocess)
- {
- if (funcdecl->type == f) f = (TypeFunction *)f->copy();
- f->isnothrow = !(blockexit & BEthrow);
- }
- }
-
- if (funcdecl->fbody->isErrorStatement())
- ;
- else if (ad2 && funcdecl->isCtorDeclaration())
- {
- /* Append:
- * return this;
- * to function body
- */
- if (blockexit & BEfallthru)
- {
- Statement *s = new ReturnStatement(funcdecl->loc, NULL);
- s = statementSemantic(s, sc2);
- funcdecl->fbody = new CompoundStatement(funcdecl->loc, funcdecl->fbody, s);
- funcdecl->hasReturnExp |= (funcdecl->hasReturnExp & 1 ? 16 : 1);
- }
- }
- else if (funcdecl->fes)
- {
- // For foreach(){} body, append a return 0;
- if (blockexit & BEfallthru)
- {
- Expression *e = new IntegerExp(0);
- Statement *s = new ReturnStatement(Loc(), e);
- funcdecl->fbody = new CompoundStatement(Loc(), funcdecl->fbody, s);
- funcdecl->hasReturnExp |= (funcdecl->hasReturnExp & 1 ? 16 : 1);
- }
- assert(!funcdecl->returnLabel);
- }
- else if (f->next->ty == Tnoreturn)
- {
- }
- else
- {
- const bool inlineAsm = (funcdecl->hasReturnExp & 8) != 0;
- if ((blockexit & BEfallthru) && f->next->ty != Tvoid && !inlineAsm)
- {
- if (!funcdecl->hasReturnExp)
- funcdecl->error("has no `return` statement, but is expected to return a value of type `%s`", f->next->toChars());
- else
- funcdecl->error("no `return exp;` or `assert(0);` at end of function");
- }
- }
-
- if (funcdecl->returns)
- {
- bool implicit0 = addReturn0(funcdecl);
- Type *tret = implicit0 ? Type::tint32 : f->next;
- assert(tret->ty != Tvoid);
- if (funcdecl->vresult || funcdecl->returnLabel)
- funcdecl->buildResultVar(scout ? scout : sc2, tret);
-
- /* Cannot move this loop into NrvoWalker, because
- * returns[i] may be in the nested delegate for foreach-body.
- */
- for (size_t i = 0; i < funcdecl->returns->length; i++)
- {
- ReturnStatement *rs = (*funcdecl->returns)[i];
- Expression *exp = rs->exp;
- if (exp->op == TOKerror)
- continue;
- if (tret->ty == Terror)
- {
- // Bugzilla 13702
- exp = checkGC(sc2, exp);
- continue;
- }
-
- if (!exp->implicitConvTo(tret) &&
- funcdecl->parametersIntersect(exp->type))
- {
- if (exp->type->immutableOf()->implicitConvTo(tret))
- exp = exp->castTo(sc2, exp->type->immutableOf());
- else if (exp->type->wildOf()->implicitConvTo(tret))
- exp = exp->castTo(sc2, exp->type->wildOf());
- }
- exp = exp->implicitCastTo(sc2, tret);
-
- if (f->isref)
- {
- // Function returns a reference
- exp = exp->toLvalue(sc2, exp);
- checkReturnEscapeRef(sc2, exp, false);
- }
- else
- {
- exp = exp->optimize(WANTvalue);
-
- /* Bugzilla 10789:
- * If NRVO is not possible, all returned lvalues should call their postblits.
- */
- if (!funcdecl->nrvo_can)
- exp = doCopyOrMove(sc2, exp);
-
- if (tret->hasPointers())
- checkReturnEscape(sc2, exp, false);
- }
-
- exp = checkGC(sc2, exp);
-
- if (funcdecl->vresult)
- {
- // Create: return vresult = exp;
- exp = new BlitExp(rs->loc, funcdecl->vresult, exp);
- exp->type = funcdecl->vresult->type;
-
- if (rs->caseDim)
- exp = Expression::combine(exp, new IntegerExp(rs->caseDim));
- }
- else if (funcdecl->tintro && !tret->equals(funcdecl->tintro->nextOf()))
- {
- exp = exp->implicitCastTo(sc2, funcdecl->tintro->nextOf());
- }
- rs->exp = exp;
- }
- }
- if (funcdecl->nrvo_var || funcdecl->returnLabel)
- {
- NrvoWalker nw;
- nw.fd = funcdecl;
- nw.sc = sc2;
- nw.visitStmt(funcdecl->fbody);
- }
-
- sc2 = sc2->pop();
- }
-
- funcdecl->frequire = funcdecl->mergeFrequire(funcdecl->frequire);
- funcdecl->fensure = funcdecl->mergeFensure(funcdecl->fensure, Id::result);
-
- Statement *freq = funcdecl->frequire;
- Statement *fens = funcdecl->fensure;
-
- /* Do the semantic analysis on the [in] preconditions and
- * [out] postconditions.
- */
- if (freq)
- {
- /* frequire is composed of the [in] contracts
- */
- ScopeDsymbol *sym = new ScopeDsymbol();
- sym->parent = sc2->scopesym;
- sym->loc = funcdecl->loc;
- sym->endlinnum = funcdecl->endloc.linnum;
- sc2 = sc2->push(sym);
- sc2->flags = (sc2->flags & ~SCOPEcontract) | SCOPErequire;
-
- // BUG: need to error if accessing out parameters
- // BUG: need to disallow returns and throws
- // BUG: verify that all in and ref parameters are read
- freq = statementSemantic(freq, sc2);
- blockExit(freq, funcdecl, false);
-
- sc2 = sc2->pop();
-
- if (global.params.useIn == CHECKENABLEoff)
- freq = NULL;
- }
-
- if (fens)
- {
- /* fensure is composed of the [out] contracts
- */
- if (f->next->ty == Tvoid && funcdecl->fensures)
- {
- for (size_t i = 0; i < funcdecl->fensures->length; i++)
- {
- Ensure e = (*funcdecl->fensures)[i];
- if (e.id)
- {
- funcdecl->error(e.ensure->loc, "`void` functions have no result");
- //fens = NULL;
- }
- }
- }
-
- sc2 = scout; //push
- sc2->flags = (sc2->flags & ~SCOPEcontract) | SCOPEensure;
-
- // BUG: need to disallow returns and throws
- if (funcdecl->fensure && f->next->ty != Tvoid)
- funcdecl->buildResultVar(scout, f->next);
-
- fens = statementSemantic(fens, sc2);
- blockExit(fens, funcdecl, false);
-
- sc2 = sc2->pop();
-
- if (global.params.useOut == CHECKENABLEoff)
- fens = NULL;
- }
-
- if (funcdecl->fbody && funcdecl->fbody->isErrorStatement())
- ;
- else
- {
- Statements *a = new Statements();
-
- // Merge in initialization of 'out' parameters
- if (funcdecl->parameters)
- {
- for (size_t i = 0; i < funcdecl->parameters->length; i++)
- {
- VarDeclaration *v = (*funcdecl->parameters)[i];
- if (v->storage_class & STCout)
- {
- assert(v->_init);
- ExpInitializer *ie = v->_init->isExpInitializer();
- assert(ie);
- if (ie->exp->op == TOKconstruct)
- ie->exp->op = TOKassign; // construction occured in parameter processing
- a->push(new ExpStatement(Loc(), ie->exp));
- }
- }
- }
-
- if (funcdecl->v_argptr)
- {
- // Handled in FuncDeclaration::toObjFile
- funcdecl->v_argptr->_init = new VoidInitializer(funcdecl->loc);
- }
-
- if (_arguments)
- {
- /* Advance to elements[] member of TypeInfo_Tuple with:
- * _arguments = v_arguments.elements;
- */
- Expression *e = new VarExp(Loc(), funcdecl->v_arguments);
- e = new DotIdExp(Loc(), e, Id::elements);
- e = new ConstructExp(Loc(), _arguments, e);
- e = expressionSemantic(e, sc2);
-
- _arguments->_init = new ExpInitializer(Loc(), e);
- DeclarationExp *de = new DeclarationExp(Loc(), _arguments);
- a->push(new ExpStatement(Loc(), de));
- }
-
- // Merge contracts together with body into one compound statement
-
- if (freq || fpreinv)
- {
- if (!freq)
- freq = fpreinv;
- else if (fpreinv)
- freq = new CompoundStatement(Loc(), freq, fpreinv);
-
- a->push(freq);
- }
-
- if (funcdecl->fbody)
- a->push(funcdecl->fbody);
-
- if (fens || fpostinv)
- {
- if (!fens)
- fens = fpostinv;
- else if (fpostinv)
- fens = new CompoundStatement(Loc(), fpostinv, fens);
-
- LabelStatement *ls = new LabelStatement(Loc(), Id::returnLabel, fens);
- funcdecl->returnLabel->statement = ls;
- a->push(funcdecl->returnLabel->statement);
-
- if (f->next->ty != Tvoid && funcdecl->vresult)
- {
- // Create: return vresult;
- Expression *e = new VarExp(Loc(), funcdecl->vresult);
- if (funcdecl->tintro)
- {
- e = e->implicitCastTo(sc, funcdecl->tintro->nextOf());
- e = expressionSemantic(e, sc);
- }
- ReturnStatement *s = new ReturnStatement(Loc(), e);
- a->push(s);
- }
- }
- if (addReturn0(funcdecl))
- {
- // Add a return 0; statement
- Statement *s = new ReturnStatement(Loc(), new IntegerExp(0));
- a->push(s);
- }
-
- Statement *sbody = new CompoundStatement(Loc(), a);
- /* Append destructor calls for parameters as finally blocks.
- */
- if (funcdecl->parameters)
- {
- for (size_t i = 0; i < funcdecl->parameters->length; i++)
- {
- VarDeclaration *v = (*funcdecl->parameters)[i];
-
- if (v->storage_class & (STCref | STCout | STClazy))
- continue;
-
- if (v->needsScopeDtor())
- {
- // same with ExpStatement.scopeCode()
- Statement *s = new DtorExpStatement(Loc(), v->edtor, v);
- v->storage_class |= STCnodtor;
-
- s = statementSemantic(s, sc2);
-
- bool isnothrow = f->isnothrow & !(funcdecl->flags & FUNCFLAGnothrowInprocess);
- int blockexit = blockExit(s, funcdecl, isnothrow);
- if (f->isnothrow && isnothrow && blockexit & BEthrow)
- error(funcdecl->loc, "nothrow %s `%s` may throw", funcdecl->kind(), funcdecl->toPrettyChars());
- if (funcdecl->flags & FUNCFLAGnothrowInprocess && blockexit & BEthrow)
- f->isnothrow = false;
- if (blockExit(sbody, funcdecl, f->isnothrow) == BEfallthru)
- sbody = new CompoundStatement(Loc(), sbody, s);
- else
- sbody = new TryFinallyStatement(Loc(), sbody, s);
- }
- }
- }
- // from this point on all possible 'throwers' are checked
- funcdecl->flags &= ~FUNCFLAGnothrowInprocess;
-
- if (funcdecl->isSynchronized())
- {
- /* Wrap the entire function body in a synchronized statement
- */
- ClassDeclaration *cd = funcdecl->isThis() ? funcdecl->isThis()->isClassDeclaration() : funcdecl->parent->isClassDeclaration();
-
- if (cd)
- {
- if (target.libraryObjectMonitors(funcdecl, sbody))
- {
- Expression *vsync;
- if (funcdecl->isStatic())
- {
- // The monitor is in the ClassInfo
- vsync = new DotIdExp(funcdecl->loc, resolve(funcdecl->loc, sc2, cd, false), Id::classinfo);
- }
- else
- {
- // 'this' is the monitor
- vsync = new VarExp(funcdecl->loc, funcdecl->vthis);
- }
- sbody = new PeelStatement(sbody); // don't redo semantic()
- sbody = new SynchronizedStatement(funcdecl->loc, vsync, sbody);
- sbody = statementSemantic(sbody, sc2);
- }
- }
- else
- {
- funcdecl->error("synchronized function %s must be a member of a class", funcdecl->toChars());
- }
- }
-
- // If declaration has no body, don't set sbody to prevent incorrect codegen.
- if (funcdecl->fbody || allowsContractWithoutBody(funcdecl))
- funcdecl->fbody = sbody;
- }
-
- // Fix up forward-referenced gotos
- if (funcdecl->gotos)
- {
- for (size_t i = 0; i < funcdecl->gotos->length; ++i)
- {
- (*funcdecl->gotos)[i]->checkLabel();
- }
- }
-
- if (funcdecl->naked && (funcdecl->fensures || funcdecl->frequires))
- funcdecl->error("naked assembly functions with contracts are not supported");
-
- sc2->callSuper = 0;
- sc2->pop();
- }
-
- if (funcdecl->checkClosure())
- {
- // We should be setting errors here instead of relying on the global error count.
- //errors = true;
- }
-
- /* If function survived being marked as impure, then it is pure
- */
- if (funcdecl->flags & FUNCFLAGpurityInprocess)
- {
- funcdecl->flags &= ~FUNCFLAGpurityInprocess;
- if (funcdecl->type == f)
- f = (TypeFunction *)f->copy();
- f->purity = PUREfwdref;
- }
-
- if (funcdecl->flags & FUNCFLAGsafetyInprocess)
- {
- funcdecl->flags &= ~FUNCFLAGsafetyInprocess;
- if (funcdecl->type == f)
- f = (TypeFunction *)f->copy();
- f->trust = TRUSTsafe;
- }
-
- if (funcdecl->flags & FUNCFLAGnogcInprocess)
- {
- funcdecl->flags &= ~FUNCFLAGnogcInprocess;
- if (funcdecl->type == f)
- f = (TypeFunction *)f->copy();
- f->isnogc = true;
- }
-
- if (funcdecl->flags & FUNCFLAGreturnInprocess)
- {
- funcdecl->flags &= ~FUNCFLAGreturnInprocess;
- if (funcdecl->storage_class & STCreturn)
- {
- if (funcdecl->type == f)
- f = (TypeFunction *)f->copy();
- f->isreturn = true;
- }
- }
-
- funcdecl->flags &= ~FUNCFLAGinferScope;
-
- // Infer STCscope
- if (funcdecl->parameters)
- {
- size_t nfparams = f->parameterList.length();
- assert(nfparams == funcdecl->parameters->length);
- for (size_t u = 0; u < funcdecl->parameters->length; u++)
- {
- VarDeclaration *v = (*funcdecl->parameters)[u];
- if (v->storage_class & STCmaybescope)
- {
- //printf("Inferring scope for %s\n", v->toChars());
- Parameter *p = f->parameterList[u];
- v->storage_class &= ~STCmaybescope;
- v->storage_class |= STCscope | STCscopeinferred;
- p->storageClass |= STCscope | STCscopeinferred;
- assert(!(p->storageClass & STCmaybescope));
- }
- }
- }
-
- if (funcdecl->vthis && funcdecl->vthis->storage_class & STCmaybescope)
- {
- funcdecl->vthis->storage_class &= ~STCmaybescope;
- funcdecl->vthis->storage_class |= STCscope | STCscopeinferred;
- f->isscope = true;
- f->isscopeinferred = true;
- }
-
- // reset deco to apply inference result to mangled name
- if (f != funcdecl->type)
- f->deco = NULL;
-
- // Do semantic type AFTER pure/nothrow inference.
- if (!f->deco && funcdecl->ident != Id::xopEquals && funcdecl->ident != Id::xopCmp)
- {
- sc = sc->push();
- if (funcdecl->isCtorDeclaration()) // Bugzilla #15665
- sc->flags |= SCOPEctor;
- sc->stc = 0;
- sc->linkage = funcdecl->linkage; // Bugzilla 8496
- funcdecl->type = typeSemantic(f, funcdecl->loc, sc);
- sc = sc->pop();
- }
-
- /* If this function had instantiated with gagging, error reproduction will be
- * done by TemplateInstance::semantic.
- * Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
- */
- funcdecl->semanticRun = PASSsemantic3done;
- funcdecl->semantic3Errors = (global.errors != oldErrors) || (funcdecl->fbody && funcdecl->fbody->isErrorStatement());
- if (funcdecl->type->ty == Terror)
- funcdecl->errors = true;
- //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", funcdecl->parent->toChars(), funcdecl->toChars(), sc, funcdecl->loc.toChars());
- //fflush(stdout);
- }
-
- void visit(Nspace *ns)
- {
- if (ns->semanticRun >= PASSsemantic3)
- return;
- ns->semanticRun = PASSsemantic3;
- if (ns->members)
- {
- sc = sc->push(ns);
- sc->linkage = LINKcpp;
- for (size_t i = 0; i < ns->members->length; i++)
- {
- Dsymbol *s = (*ns->members)[i];
- semantic3(s, sc);
- }
- sc->pop();
- }
- }
-
- void visit(AttribDeclaration *ad)
- {
- Dsymbols *d = ad->include(sc);
-
- if (d)
- {
- Scope *sc2 = ad->newScope(sc);
-
- for (size_t i = 0; i < d->length; i++)
- {
- Dsymbol *s = (*d)[i];
- semantic3(s, sc2);
- }
-
- if (sc2 != sc)
- sc2->pop();
- }
- }
-
- void visit(AggregateDeclaration *ad)
- {
- //printf("AggregateDeclaration::semantic3(%s) type = %s, errors = %d\n", ad->toChars(), ad->type->toChars(), ad->errors);
- if (!ad->members)
- return;
-
- StructDeclaration *sd = ad->isStructDeclaration();
- if (!sc) // from runDeferredSemantic3 for TypeInfo generation
- {
- assert(sd);
- sd->semanticTypeInfoMembers();
- return;
- }
-
- Scope *sc2 = ad->newScope(sc);
-
- for (size_t i = 0; i < ad->members->length; i++)
- {
- Dsymbol *s = (*ad->members)[i];
- semantic3(s, sc2);
- }
-
- sc2->pop();
-
- // don't do it for unused deprecated types
- // or error types
- if (!ad->getRTInfo && Type::rtinfo &&
- (!ad->isDeprecated() || global.params.useDeprecated != DIAGNOSTICerror) &&
- (ad->type && ad->type->ty != Terror))
- {
- // Evaluate: RTinfo!type
- Objects *tiargs = new Objects();
- tiargs->push(ad->type);
- TemplateInstance *ti = new TemplateInstance(ad->loc, Type::rtinfo, tiargs);
-
- Scope *sc3 = ti->tempdecl->_scope->startCTFE();
- sc3->tinst = sc->tinst;
- sc3->minst = sc->minst;
- if (ad->isDeprecated())
- sc3->stc |= STCdeprecated;
-
- dsymbolSemantic(ti, sc3);
- semantic2(ti, sc3);
- semantic3(ti, sc3);
- Expression *e = resolve(Loc(), sc3, ti->toAlias(), false);
-
- sc3->endCTFE();
-
- e = e->ctfeInterpret();
- ad->getRTInfo = e;
- }
-
- if (sd)
- sd->semanticTypeInfoMembers();
- ad->semanticRun = PASSsemantic3done;
- }
-};
-
-/*************************************
- * Does semantic analysis on function bodies.
- */
-void semantic3(Dsymbol *dsym, Scope *sc)
-{
- Semantic3Visitor v(sc);
- dsym->accept(&v);
-}
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
new file mode 100644
index 0000000..ac2b239
--- /dev/null
+++ b/gcc/d/dmd/semantic3.d
@@ -0,0 +1,1624 @@
+/**
+ * Performs the semantic3 stage, which deals with function bodies.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic3.d, _semantic3.d)
+ * Documentation: https://dlang.org/phobos/dmd_semantic3.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/semantic3.d
+ */
+
+module dmd.semantic3;
+
+import core.stdc.stdio;
+import core.stdc.string;
+
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arraytypes;
+import dmd.astcodegen;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.blockexit;
+import dmd.clone;
+import dmd.ctorflow;
+import dmd.dcast;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dimport;
+import dmd.dinterpret;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.dversion;
+import dmd.errors;
+import dmd.escape;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.initsem;
+import dmd.hdrgen;
+import dmd.mtype;
+import dmd.nogc;
+import dmd.nspace;
+import dmd.ob;
+import dmd.objc;
+import dmd.opover;
+import dmd.parse;
+import dmd.root.filename;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+import dmd.root.rootobject;
+import dmd.sideeffect;
+import dmd.statementsem;
+import dmd.staticassert;
+import dmd.tokens;
+import dmd.utf;
+import dmd.semantic2;
+import dmd.statement;
+import dmd.target;
+import dmd.templateparamsem;
+import dmd.typesem;
+import dmd.visitor;
+
+enum LOG = false;
+
+
+/*************************************
+ * Does semantic analysis on function bodies.
+ */
+extern(C++) void semantic3(Dsymbol dsym, Scope* sc)
+{
+ scope v = new Semantic3Visitor(sc);
+ dsym.accept(v);
+}
+
+private extern(C++) final class Semantic3Visitor : Visitor
+{
+ alias visit = Visitor.visit;
+
+ Scope* sc;
+ this(Scope* sc)
+ {
+ this.sc = sc;
+ }
+
+ override void visit(Dsymbol) {}
+
+ override void visit(TemplateInstance tempinst)
+ {
+ static if (LOG)
+ {
+ printf("TemplateInstance.semantic3('%s'), semanticRun = %d\n", tempinst.toChars(), tempinst.semanticRun);
+ }
+ //if (toChars()[0] == 'D') *(char*)0=0;
+ if (tempinst.semanticRun >= PASS.semantic3)
+ return;
+ tempinst.semanticRun = PASS.semantic3;
+ if (tempinst.errors || !tempinst.members)
+ return;
+
+ TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration();
+ assert(tempdecl);
+
+ sc = tempdecl._scope;
+ sc = sc.push(tempinst.argsym);
+ sc = sc.push(tempinst);
+ sc.tinst = tempinst;
+ sc.minst = tempinst.minst;
+
+ int needGagging = (tempinst.gagged && !global.gag);
+ uint olderrors = global.errors;
+ int oldGaggedErrors = -1; // dead-store to prevent spurious warning
+ /* If this is a gagged instantiation, gag errors.
+ * Future optimisation: If the results are actually needed, errors
+ * would already be gagged, so we don't really need to run semantic
+ * on the members.
+ */
+ if (needGagging)
+ oldGaggedErrors = global.startGagging();
+
+ for (size_t i = 0; i < tempinst.members.dim; i++)
+ {
+ Dsymbol s = (*tempinst.members)[i];
+ s.semantic3(sc);
+ if (tempinst.gagged && global.errors != olderrors)
+ break;
+ }
+
+ if (global.errors != olderrors)
+ {
+ if (!tempinst.errors)
+ {
+ if (!tempdecl.literal)
+ tempinst.error(tempinst.loc, "error instantiating");
+ if (tempinst.tinst)
+ tempinst.tinst.printInstantiationTrace();
+ }
+ tempinst.errors = true;
+ }
+ if (needGagging)
+ global.endGagging(oldGaggedErrors);
+
+ sc = sc.pop();
+ sc.pop();
+ }
+
+ override void visit(TemplateMixin tmix)
+ {
+ if (tmix.semanticRun >= PASS.semantic3)
+ return;
+ tmix.semanticRun = PASS.semantic3;
+ static if (LOG)
+ {
+ printf("TemplateMixin.semantic3('%s')\n", tmix.toChars());
+ }
+ if (!tmix.members)
+ return;
+
+ sc = sc.push(tmix.argsym);
+ sc = sc.push(tmix);
+ for (size_t i = 0; i < tmix.members.dim; i++)
+ {
+ Dsymbol s = (*tmix.members)[i];
+ s.semantic3(sc);
+ }
+ sc = sc.pop();
+ sc.pop();
+ }
+
+ override void visit(Module mod)
+ {
+ //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent);
+ if (mod.semanticRun != PASS.semantic2done)
+ return;
+ mod.semanticRun = PASS.semantic3;
+ // Note that modules get their own scope, from scratch.
+ // This is so regardless of where in the syntax a module
+ // gets imported, it is unaffected by context.
+ Scope* sc = Scope.createGlobal(mod); // create root scope
+ //printf("Module = %p\n", sc.scopesym);
+ // Pass 3 semantic routines: do initializers and function bodies
+ for (size_t i = 0; i < mod.members.dim; i++)
+ {
+ Dsymbol s = (*mod.members)[i];
+ //printf("Module %s: %s.semantic3()\n", toChars(), s.toChars());
+ s.semantic3(sc);
+
+ mod.runDeferredSemantic2();
+ }
+ if (mod.userAttribDecl)
+ {
+ mod.userAttribDecl.semantic3(sc);
+ }
+ sc = sc.pop();
+ sc.pop();
+ mod.semanticRun = PASS.semantic3done;
+ }
+
+ override void visit(FuncDeclaration funcdecl)
+ {
+ //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", funcdecl.kind(), funcdecl.toChars(), sc);
+ /* Determine if function should add `return 0;`
+ */
+ bool addReturn0()
+ {
+ //printf("addReturn0()\n");
+ auto f = funcdecl.type.isTypeFunction();
+
+ // C11 5.1.2.2.3
+ if (sc.flags & SCOPE.Cfile && funcdecl.isCMain() && f.next.ty == Tint32)
+ return true;
+
+ return f.next.ty == Tvoid &&
+ (funcdecl.isMain() || global.params.betterC && funcdecl.isCMain());
+ }
+
+ VarDeclaration _arguments = null;
+
+ if (!funcdecl.parent)
+ {
+ if (global.errors)
+ return;
+ //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc);
+ assert(0);
+ }
+ if (funcdecl.errors || isError(funcdecl.parent))
+ {
+ funcdecl.errors = true;
+ return;
+ }
+ //printf("FuncDeclaration::semantic3('%s.%s', %p, sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), funcdecl, sc, funcdecl.loc.toChars());
+ //fflush(stdout);
+ //printf("storage class = x%x %x\n", sc.stc, storage_class);
+ //{ static int x; if (++x == 2) *(char*)0=0; }
+ //printf("\tlinkage = %d\n", sc.linkage);
+
+ if (funcdecl.ident == Id.assign && !funcdecl.inuse)
+ {
+ if (funcdecl.storage_class & STC.inference)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=15044
+ * For generated opAssign function, any errors
+ * from its body need to be gagged.
+ */
+ uint oldErrors = global.startGagging();
+ ++funcdecl.inuse;
+ funcdecl.semantic3(sc);
+ --funcdecl.inuse;
+ if (global.endGagging(oldErrors)) // if errors happened
+ {
+ // Disable generated opAssign, because some members forbid identity assignment.
+ funcdecl.storage_class |= STC.disable;
+ funcdecl.fbody = null; // remove fbody which contains the error
+ funcdecl.semantic3Errors = false;
+ }
+ return;
+ }
+ }
+
+ //printf(" sc.incontract = %d\n", (sc.flags & SCOPE.contract));
+ if (funcdecl.semanticRun >= PASS.semantic3)
+ return;
+ funcdecl.semanticRun = PASS.semantic3;
+ funcdecl.semantic3Errors = false;
+
+ if (!funcdecl.type || funcdecl.type.ty != Tfunction)
+ return;
+ TypeFunction f = cast(TypeFunction)funcdecl.type;
+ if (!funcdecl.inferRetType && f.next.ty == Terror)
+ return;
+
+ if (!funcdecl.fbody && funcdecl.inferRetType && !f.next)
+ {
+ funcdecl.error("has no function body with return type inference");
+ return;
+ }
+
+ uint oldErrors = global.errors;
+ auto fds = FuncDeclSem3(funcdecl,sc);
+
+ fds.checkInContractOverrides();
+
+ // Remember whether we need to generate an 'out' contract.
+ immutable bool needEnsure = FuncDeclaration.needsFensure(funcdecl);
+
+ if (funcdecl.fbody || funcdecl.frequires || needEnsure)
+ {
+ /* Symbol table into which we place parameters and nested functions,
+ * solely to diagnose name collisions.
+ */
+ funcdecl.localsymtab = new DsymbolTable();
+
+ // Establish function scope
+ auto ss = new ScopeDsymbol(funcdecl.loc, null);
+ // find enclosing scope symbol, might skip symbol-less CTFE and/or FuncExp scopes
+ ss.parent = sc.inner().scopesym;
+ ss.endlinnum = funcdecl.endloc.linnum;
+ Scope* sc2 = sc.push(ss);
+ sc2.func = funcdecl;
+ sc2.parent = funcdecl;
+ sc2.ctorflow.callSuper = CSX.none;
+ sc2.sbreak = null;
+ sc2.scontinue = null;
+ sc2.sw = null;
+ sc2.fes = funcdecl.fes;
+ sc2.linkage = LINK.d;
+ sc2.stc &= STC.flowThruFunction;
+ sc2.visibility = Visibility(Visibility.Kind.public_);
+ sc2.explicitVisibility = 0;
+ sc2.aligndecl = null;
+ if (funcdecl.ident != Id.require && funcdecl.ident != Id.ensure)
+ sc2.flags = sc.flags & ~SCOPE.contract;
+ sc2.flags &= ~SCOPE.compile;
+ sc2.tf = null;
+ sc2.os = null;
+ sc2.inLoop = false;
+ sc2.userAttribDecl = null;
+ if (sc2.intypeof == 1)
+ sc2.intypeof = 2;
+ sc2.ctorflow.fieldinit = null;
+
+ /* Note: When a lambda is defined immediately under aggregate member
+ * scope, it should be contextless due to prevent interior pointers.
+ * e.g.
+ * // dg points 'this' - its interior pointer
+ * class C { int x; void delegate() dg = (){ this.x = 1; }; }
+ *
+ * However, lambdas could be used inside typeof, in order to check
+ * some expressions validity at compile time. For such case the lambda
+ * body can access aggregate instance members.
+ * e.g.
+ * class C { int x; static assert(is(typeof({ this.x = 1; }))); }
+ *
+ * To properly accept it, mark these lambdas as member functions.
+ */
+ if (auto fld = funcdecl.isFuncLiteralDeclaration())
+ {
+ if (auto ad = funcdecl.isMember2())
+ {
+ if (!sc.intypeof)
+ {
+ if (fld.tok == TOK.delegate_)
+ funcdecl.error("cannot be %s members", ad.kind());
+ else
+ fld.tok = TOK.function_;
+ }
+ else
+ {
+ if (fld.tok != TOK.function_)
+ fld.tok = TOK.delegate_;
+ }
+ }
+ }
+
+ funcdecl.declareThis(sc2);
+
+ // Reverts: https://issues.dlang.org/show_bug.cgi?id=5710
+ // No compiler supports this, and there was never any spec for it.
+ if (funcdecl.isThis2)
+ {
+ funcdecl.deprecation("function requires a dual-context, which is deprecated");
+ if (auto ti = sc2.parent ? sc2.parent.isInstantiated() : null)
+ ti.printInstantiationTrace(Classification.deprecation);
+ }
+
+ //printf("[%s] ad = %p vthis = %p\n", loc.toChars(), ad, vthis);
+ //if (vthis) printf("\tvthis.type = %s\n", vthis.type.toChars());
+
+ // Declare hidden variable _arguments[] and _argptr
+ if (f.parameterList.varargs == VarArg.variadic)
+ {
+ if (f.linkage == LINK.d)
+ {
+ // Variadic arguments depend on Typeinfo being defined.
+ if (!global.params.useTypeInfo || !Type.dtypeinfo || !Type.typeinfotypelist)
+ {
+ if (!global.params.useTypeInfo)
+ funcdecl.error("D-style variadic functions cannot be used with -betterC");
+ else if (!Type.typeinfotypelist)
+ funcdecl.error("`object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions");
+ else
+ funcdecl.error("`object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions");
+ fatal();
+ }
+
+ // Declare _arguments[]
+ funcdecl.v_arguments = new VarDeclaration(funcdecl.loc, Type.typeinfotypelist.type, Id._arguments_typeinfo, null);
+ funcdecl.v_arguments.storage_class |= STC.temp | STC.parameter;
+ funcdecl.v_arguments.dsymbolSemantic(sc2);
+ sc2.insert(funcdecl.v_arguments);
+ funcdecl.v_arguments.parent = funcdecl;
+
+ //Type t = Type.dtypeinfo.type.constOf().arrayOf();
+ Type t = Type.dtypeinfo.type.arrayOf();
+ _arguments = new VarDeclaration(funcdecl.loc, t, Id._arguments, null);
+ _arguments.storage_class |= STC.temp;
+ _arguments.dsymbolSemantic(sc2);
+ sc2.insert(_arguments);
+ _arguments.parent = funcdecl;
+ }
+ if (f.linkage == LINK.d || f.parameterList.length)
+ {
+ // Declare _argptr
+ Type t = target.va_listType(funcdecl.loc, sc);
+ // Init is handled in FuncDeclaration_toObjFile
+ funcdecl.v_argptr = new VarDeclaration(funcdecl.loc, t, Id._argptr, new VoidInitializer(funcdecl.loc));
+ funcdecl.v_argptr.storage_class |= STC.temp;
+ funcdecl.v_argptr.dsymbolSemantic(sc2);
+ sc2.insert(funcdecl.v_argptr);
+ funcdecl.v_argptr.parent = funcdecl;
+ }
+ }
+
+ /* Declare all the function parameters as variables
+ * and install them in parameters[]
+ */
+ if (const nparams = f.parameterList.length)
+ {
+ /* parameters[] has all the tuples removed, as the back end
+ * doesn't know about tuples
+ */
+ funcdecl.parameters = new VarDeclarations();
+ funcdecl.parameters.reserve(nparams);
+ foreach (i, fparam; f.parameterList)
+ {
+ Identifier id = fparam.ident;
+ StorageClass stc = 0;
+ if (!id)
+ {
+ /* Generate identifier for un-named parameter,
+ * because we need it later on.
+ */
+ fparam.ident = id = Identifier.generateId("_param_", i);
+ stc |= STC.temp;
+ }
+ Type vtype = fparam.type;
+ auto v = new VarDeclaration(funcdecl.loc, vtype, id, null);
+ //printf("declaring parameter %s of type %s\n", v.toChars(), v.type.toChars());
+ stc |= STC.parameter;
+ if (f.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
+ {
+ stc |= STC.variadic;
+ auto vtypeb = vtype.toBasetype();
+ if (vtypeb.ty == Tarray)
+ {
+ /* Since it'll be pointing into the stack for the array
+ * contents, it needs to be `scope`
+ */
+ stc |= STC.scope_;
+ }
+ }
+
+ if ((funcdecl.flags & FUNCFLAG.inferScope) && !(fparam.storageClass & STC.scope_))
+ stc |= STC.maybescope;
+
+ stc |= fparam.storageClass & (STC.IOR | STC.return_ | STC.scope_ | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor | STC.returnScope);
+ v.storage_class = stc;
+ v.dsymbolSemantic(sc2);
+ if (!sc2.insert(v))
+ {
+ funcdecl.error("parameter `%s.%s` is already defined", funcdecl.toChars(), v.toChars());
+ funcdecl.errors = true;
+ }
+ else
+ funcdecl.parameters.push(v);
+ funcdecl.localsymtab.insert(v);
+ v.parent = funcdecl;
+ if (fparam.userAttribDecl)
+ v.userAttribDecl = fparam.userAttribDecl;
+ }
+ }
+
+ // Declare the tuple symbols and put them in the symbol table,
+ // but not in parameters[].
+ if (f.parameterList.parameters)
+ foreach (fparam; *f.parameterList.parameters)
+ {
+ if (!fparam.ident)
+ continue; // never used, so ignore
+ // expand any tuples
+ if (fparam.type.ty != Ttuple)
+ continue;
+
+ TypeTuple t = cast(TypeTuple)fparam.type;
+ size_t dim = Parameter.dim(t.arguments);
+ auto exps = new Objects(dim);
+ foreach (j; 0 .. dim)
+ {
+ Parameter narg = Parameter.getNth(t.arguments, j);
+ assert(narg.ident);
+ VarDeclaration v = sc2.search(Loc.initial, narg.ident, null).isVarDeclaration();
+ assert(v);
+ (*exps)[j] = new VarExp(v.loc, v);
+ }
+ assert(fparam.ident);
+ auto v = new TupleDeclaration(funcdecl.loc, fparam.ident, exps);
+ //printf("declaring tuple %s\n", v.toChars());
+ v.isexp = true;
+ if (!sc2.insert(v))
+ funcdecl.error("parameter `%s.%s` is already defined", funcdecl.toChars(), v.toChars());
+ funcdecl.localsymtab.insert(v);
+ v.parent = funcdecl;
+ }
+
+ // Precondition invariant
+ Statement fpreinv = null;
+ if (funcdecl.addPreInvariant())
+ {
+ Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis);
+ if (e)
+ fpreinv = new ExpStatement(Loc.initial, e);
+ }
+
+ // Postcondition invariant
+ Statement fpostinv = null;
+ if (funcdecl.addPostInvariant())
+ {
+ Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis);
+ if (e)
+ fpostinv = new ExpStatement(Loc.initial, e);
+ }
+
+ // Pre/Postcondition contract
+ if (!funcdecl.fbody)
+ funcdecl.buildEnsureRequire();
+
+ Scope* scout = null;
+ if (needEnsure || funcdecl.addPostInvariant())
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=3657
+ * Set the correct end line number for fensure scope.
+ */
+ uint fensure_endlin = funcdecl.endloc.linnum;
+ if (funcdecl.fensure)
+ if (auto s = funcdecl.fensure.isScopeStatement())
+ fensure_endlin = s.endloc.linnum;
+
+ if ((needEnsure && global.params.useOut == CHECKENABLE.on) || fpostinv)
+ {
+ funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel);
+ }
+
+ // scope of out contract (need for vresult.semantic)
+ auto sym = new ScopeDsymbol(funcdecl.loc, null);
+ sym.parent = sc2.scopesym;
+ sym.endlinnum = fensure_endlin;
+ scout = sc2.push(sym);
+ }
+
+ if (funcdecl.fbody)
+ {
+ auto sym = new ScopeDsymbol(funcdecl.loc, null);
+ sym.parent = sc2.scopesym;
+ sym.endlinnum = funcdecl.endloc.linnum;
+ sc2 = sc2.push(sym);
+
+ auto ad2 = funcdecl.isMemberLocal();
+
+ /* If this is a class constructor
+ */
+ if (ad2 && funcdecl.isCtorDeclaration())
+ {
+ sc2.ctorflow.allocFieldinit(ad2.fields.dim);
+ foreach (v; ad2.fields)
+ {
+ v.ctorinit = 0;
+ }
+ }
+
+ bool inferRef = (f.isref && (funcdecl.storage_class & STC.auto_));
+
+ funcdecl.fbody = funcdecl.fbody.statementSemantic(sc2);
+ if (!funcdecl.fbody)
+ funcdecl.fbody = new CompoundStatement(Loc.initial, new Statements());
+
+ if (funcdecl.naked)
+ {
+ fpreinv = null; // can't accommodate with no stack frame
+ fpostinv = null;
+ }
+
+ assert(funcdecl.type == f || (funcdecl.type.ty == Tfunction && f.purity == PURE.impure && (cast(TypeFunction)funcdecl.type).purity >= PURE.fwdref));
+ f = cast(TypeFunction)funcdecl.type;
+
+ if (funcdecl.inferRetType)
+ {
+ // If no return type inferred yet, then infer a void
+ if (!f.next)
+ f.next = Type.tvoid;
+ if (f.checkRetType(funcdecl.loc))
+ funcdecl.fbody = new ErrorStatement();
+ }
+ if (global.params.vcomplex && f.next !is null)
+ f.next.checkComplexTransition(funcdecl.loc, sc);
+
+ if (funcdecl.returns && !funcdecl.fbody.isErrorStatement())
+ {
+ for (size_t i = 0; i < funcdecl.returns.dim;)
+ {
+ Expression exp = (*funcdecl.returns)[i].exp;
+ if (exp.op == TOK.variable && (cast(VarExp)exp).var == funcdecl.vresult)
+ {
+ if (addReturn0())
+ exp.type = Type.tint32;
+ else
+ exp.type = f.next;
+ // Remove `return vresult;` from returns
+ funcdecl.returns.remove(i);
+ continue;
+ }
+ if (inferRef && f.isref && !exp.type.constConv(f.next)) // https://issues.dlang.org/show_bug.cgi?id=13336
+ f.isref = false;
+ i++;
+ }
+ }
+ if (f.isref) // Function returns a reference
+ {
+ if (funcdecl.storage_class & STC.auto_)
+ funcdecl.storage_class &= ~STC.auto_;
+ }
+
+ // handle NRVO
+ if (!target.isReturnOnStack(f, funcdecl.needThis()) || !funcdecl.checkNRVO())
+ funcdecl.nrvo_can = 0;
+
+ if (funcdecl.fbody.isErrorStatement())
+ {
+ }
+ else if (funcdecl.isStaticCtorDeclaration())
+ {
+ /* It's a static constructor. Ensure that all
+ * ctor consts were initialized.
+ */
+ ScopeDsymbol pd = funcdecl.toParent().isScopeDsymbol();
+ for (size_t i = 0; i < pd.members.dim; i++)
+ {
+ Dsymbol s = (*pd.members)[i];
+ s.checkCtorConstInit();
+ }
+ }
+ else if (ad2 && funcdecl.isCtorDeclaration())
+ {
+ ClassDeclaration cd = ad2.isClassDeclaration();
+
+ // Verify that all the ctorinit fields got initialized
+ if (!(sc2.ctorflow.callSuper & CSX.this_ctor))
+ {
+ foreach (i, v; ad2.fields)
+ {
+ if (v.isThisDeclaration())
+ continue;
+ if (v.ctorinit == 0)
+ {
+ /* Current bugs in the flow analysis:
+ * 1. union members should not produce error messages even if
+ * not assigned to
+ * 2. structs should recognize delegating opAssign calls as well
+ * as delegating calls to other constructors
+ */
+ if (v.isCtorinit() && !v.type.isMutable() && cd)
+ funcdecl.error("missing initializer for %s field `%s`", MODtoChars(v.type.mod), v.toChars());
+ else if (v.storage_class & STC.nodefaultctor)
+ error(funcdecl.loc, "field `%s` must be initialized in constructor", v.toChars());
+ else if (v.type.needsNested())
+ error(funcdecl.loc, "field `%s` must be initialized in constructor, because it is nested struct", v.toChars());
+ }
+ else
+ {
+ bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested());
+ if (mustInit && !(sc2.ctorflow.fieldinit[i].csx & CSX.this_ctor))
+ {
+ funcdecl.error("field `%s` must be initialized but skipped", v.toChars());
+ }
+ }
+ }
+ }
+ sc2.ctorflow.freeFieldinit();
+
+ if (cd && !(sc2.ctorflow.callSuper & CSX.any_ctor) && cd.baseClass && cd.baseClass.ctor)
+ {
+ sc2.ctorflow.callSuper = CSX.none;
+
+ // Insert implicit super() at start of fbody
+ Type tthis = ad2.type.addMod(funcdecl.vthis.type.mod);
+ FuncDeclaration fd = resolveFuncCall(Loc.initial, sc2, cd.baseClass.ctor, null, tthis, null, FuncResolveFlag.quiet);
+ if (!fd)
+ {
+ funcdecl.error("no match for implicit `super()` call in constructor");
+ }
+ else if (fd.storage_class & STC.disable)
+ {
+ funcdecl.error("cannot call `super()` implicitly because it is annotated with `@disable`");
+ }
+ else
+ {
+ Expression e1 = new SuperExp(Loc.initial);
+ Expression e = new CallExp(Loc.initial, e1);
+ e = e.expressionSemantic(sc2);
+ Statement s = new ExpStatement(Loc.initial, e);
+ funcdecl.fbody = new CompoundStatement(Loc.initial, s, funcdecl.fbody);
+ }
+ }
+ //printf("ctorflow.callSuper = x%x\n", sc2.ctorflow.callSuper);
+ }
+
+ /* https://issues.dlang.org/show_bug.cgi?id=17502
+ * Wait until after the return type has been inferred before
+ * generating the contracts for this function, and merging contracts
+ * from overrides.
+ *
+ * https://issues.dlang.org/show_bug.cgi?id=17893
+ * However should take care to generate this before inferered
+ * function attributes are applied, such as 'nothrow'.
+ *
+ * This was originally at the end of the first semantic pass, but
+ * required a fix-up to be done here for the '__result' variable
+ * type of __ensure() inside auto functions, but this didn't work
+ * if the out parameter was implicit.
+ */
+ funcdecl.buildEnsureRequire();
+
+ // Check for errors related to 'nothrow'.
+ const blockexit = funcdecl.fbody.blockExit(funcdecl, f.isnothrow);
+ if (f.isnothrow && blockexit & BE.throw_)
+ error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars());
+
+ if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.flags & FUNCFLAG.hasCatches))
+ {
+ /* Don't generate unwind tables for this function
+ * https://issues.dlang.org/show_bug.cgi?id=17997
+ */
+ funcdecl.eh_none = true;
+ }
+
+ if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
+ {
+ if (funcdecl.type == f)
+ f = cast(TypeFunction)f.copy();
+ f.isnothrow = !(blockexit & BE.throw_);
+ }
+
+ if (funcdecl.fbody.isErrorStatement())
+ {
+ }
+ else if (ad2 && funcdecl.isCtorDeclaration())
+ {
+ /* Append:
+ * return this;
+ * to function body
+ */
+ if (blockexit & BE.fallthru)
+ {
+ Statement s = new ReturnStatement(funcdecl.loc, null);
+ s = s.statementSemantic(sc2);
+ funcdecl.fbody = new CompoundStatement(funcdecl.loc, funcdecl.fbody, s);
+ funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1);
+ }
+ }
+ else if (funcdecl.fes)
+ {
+ // For foreach(){} body, append a return 0;
+ if (blockexit & BE.fallthru)
+ {
+ Expression e = IntegerExp.literal!0;
+ Statement s = new ReturnStatement(Loc.initial, e);
+ funcdecl.fbody = new CompoundStatement(Loc.initial, funcdecl.fbody, s);
+ funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1);
+ }
+ assert(!funcdecl.returnLabel);
+ }
+ else if (f.next.ty == Tnoreturn)
+ {
+ }
+ else
+ {
+ const(bool) inlineAsm = (funcdecl.hasReturnExp & 8) != 0;
+ if ((blockexit & BE.fallthru) && f.next.ty != Tvoid && !inlineAsm && !(sc.flags & SCOPE.Cfile))
+ {
+ if (!funcdecl.hasReturnExp)
+ funcdecl.error("has no `return` statement, but is expected to return a value of type `%s`", f.next.toChars());
+ else
+ funcdecl.error("no `return exp;` or `assert(0);` at end of function");
+ }
+ }
+
+ if (funcdecl.returns)
+ {
+ bool implicit0 = addReturn0();
+ Type tret = implicit0 ? Type.tint32 : f.next;
+ assert(tret.ty != Tvoid);
+ if (funcdecl.vresult || funcdecl.returnLabel)
+ funcdecl.buildResultVar(scout ? scout : sc2, tret);
+
+ /* Cannot move this loop into NrvoWalker, because
+ * returns[i] may be in the nested delegate for foreach-body.
+ */
+ for (size_t i = 0; i < funcdecl.returns.dim; i++)
+ {
+ ReturnStatement rs = (*funcdecl.returns)[i];
+ Expression exp = rs.exp;
+ if (exp.op == TOK.error)
+ continue;
+ if (tret.ty == Terror)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=13702
+ exp = checkGC(sc2, exp);
+ continue;
+ }
+
+ /* If the expression in the return statement (exp) cannot be implicitly
+ * converted to the return type (tret) of the function and if the
+ * type of the expression is type isolated, then it may be possible
+ * that a promotion to `immutable` or `inout` (through a cast) will
+ * match the return type.
+ */
+ if (!exp.implicitConvTo(tret) && funcdecl.isTypeIsolated(exp.type))
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=20073
+ *
+ * The problem is that if the type of the returned expression (exp.type)
+ * is an aggregated declaration with an alias this, the alias this may be
+ * used for the conversion testing without it being an isolated type.
+ *
+ * To make sure this does not happen, we can test here the implicit conversion
+ * only for the aggregated declaration type by using `implicitConvToWithoutAliasThis`.
+ * The implicit conversion with alias this is taken care of later.
+ */
+ AggregateDeclaration aggDecl = isAggregate(exp.type);
+ TypeStruct tstruct;
+ TypeClass tclass;
+ bool hasAliasThis;
+ if (aggDecl && aggDecl.aliasthis)
+ {
+ hasAliasThis = true;
+ tclass = exp.type.isTypeClass();
+ if (!tclass)
+ tstruct = exp.type.isTypeStruct();
+ assert(tclass || tstruct);
+ }
+ if (hasAliasThis)
+ {
+ if (tclass)
+ {
+ if ((cast(TypeClass)(exp.type.immutableOf())).implicitConvToWithoutAliasThis(tret))
+ exp = exp.castTo(sc2, exp.type.immutableOf());
+ else if ((cast(TypeClass)(exp.type.wildOf())).implicitConvToWithoutAliasThis(tret))
+ exp = exp.castTo(sc2, exp.type.wildOf());
+ }
+ else
+ {
+ if ((cast(TypeStruct)exp.type.immutableOf()).implicitConvToWithoutAliasThis(tret))
+ exp = exp.castTo(sc2, exp.type.immutableOf());
+ else if ((cast(TypeStruct)exp.type.immutableOf()).implicitConvToWithoutAliasThis(tret))
+ exp = exp.castTo(sc2, exp.type.wildOf());
+ }
+ }
+ else
+ {
+ if (exp.type.immutableOf().implicitConvTo(tret))
+ exp = exp.castTo(sc2, exp.type.immutableOf());
+ else if (exp.type.wildOf().implicitConvTo(tret))
+ exp = exp.castTo(sc2, exp.type.wildOf());
+ }
+ }
+
+ const hasCopyCtor = exp.type.ty == Tstruct && (cast(TypeStruct)exp.type).sym.hasCopyCtor;
+ // if a copy constructor is present, the return type conversion will be handled by it
+ if (!(hasCopyCtor && exp.isLvalue()))
+ {
+ if (f.isref && !MODimplicitConv(exp.type.mod, tret.mod) && !tret.isTypeSArray())
+ error(exp.loc, "expression `%s` of type `%s` is not implicitly convertible to return type `ref %s`",
+ exp.toChars(), exp.type.toChars(), tret.toChars());
+ else
+ exp = exp.implicitCastTo(sc2, tret);
+ }
+
+ if (f.isref)
+ {
+ // Function returns a reference
+ exp = exp.toLvalue(sc2, exp);
+ checkReturnEscapeRef(sc2, exp, false);
+ exp = exp.optimize(WANTvalue, /*keepLvalue*/ true);
+ }
+ else
+ {
+ exp = exp.optimize(WANTvalue);
+
+ /* https://issues.dlang.org/show_bug.cgi?id=10789
+ * If NRVO is not possible, all returned lvalues should call their postblits.
+ */
+ if (!funcdecl.nrvo_can)
+ exp = doCopyOrMove(sc2, exp, f.next);
+
+ if (tret.hasPointers())
+ checkReturnEscape(sc2, exp, false);
+ }
+
+ exp = checkGC(sc2, exp);
+
+ if (funcdecl.vresult)
+ {
+ // Create: return vresult = exp;
+ exp = new BlitExp(rs.loc, funcdecl.vresult, exp);
+ exp.type = funcdecl.vresult.type;
+
+ if (rs.caseDim)
+ exp = Expression.combine(exp, new IntegerExp(rs.caseDim));
+ }
+ else if (funcdecl.tintro && !tret.equals(funcdecl.tintro.nextOf()))
+ {
+ exp = exp.implicitCastTo(sc2, funcdecl.tintro.nextOf());
+ }
+ rs.exp = exp;
+ }
+ }
+ if (funcdecl.nrvo_var || funcdecl.returnLabel)
+ {
+ scope NrvoWalker nw = new NrvoWalker();
+ nw.fd = funcdecl;
+ nw.sc = sc2;
+ nw.visitStmt(funcdecl.fbody);
+ }
+
+ sc2 = sc2.pop();
+ }
+
+ if (global.params.inclusiveInContracts)
+ {
+ funcdecl.frequire = funcdecl.mergeFrequireInclusivePreview(
+ funcdecl.frequire, funcdecl.fdrequireParams);
+ }
+ else
+ {
+ funcdecl.frequire = funcdecl.mergeFrequire(funcdecl.frequire, funcdecl.fdrequireParams);
+ }
+ funcdecl.fensure = funcdecl.mergeFensure(funcdecl.fensure, Id.result, funcdecl.fdensureParams);
+
+ Statement freq = funcdecl.frequire;
+ Statement fens = funcdecl.fensure;
+
+ /* Do the semantic analysis on the [in] preconditions and
+ * [out] postconditions.
+ */
+ if (freq)
+ {
+ /* frequire is composed of the [in] contracts
+ */
+ auto sym = new ScopeDsymbol(funcdecl.loc, null);
+ sym.parent = sc2.scopesym;
+ sym.endlinnum = funcdecl.endloc.linnum;
+ sc2 = sc2.push(sym);
+ sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.require;
+
+ // BUG: need to error if accessing out parameters
+ // BUG: need to disallow returns and throws
+ // BUG: verify that all in and ref parameters are read
+ freq = freq.statementSemantic(sc2);
+ freq.blockExit(funcdecl, false);
+
+ funcdecl.eh_none = false;
+
+ sc2 = sc2.pop();
+
+ if (global.params.useIn == CHECKENABLE.off)
+ freq = null;
+ }
+ if (fens)
+ {
+ /* fensure is composed of the [out] contracts
+ */
+ if (f.next.ty == Tvoid && funcdecl.fensures)
+ {
+ foreach (e; *funcdecl.fensures)
+ {
+ if (e.id)
+ {
+ funcdecl.error(e.ensure.loc, "`void` functions have no result");
+ //fens = null;
+ }
+ }
+ }
+
+ sc2 = scout; //push
+ sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.ensure;
+
+ // BUG: need to disallow returns and throws
+
+ if (funcdecl.fensure && f.next.ty != Tvoid)
+ funcdecl.buildResultVar(scout, f.next);
+
+ fens = fens.statementSemantic(sc2);
+ fens.blockExit(funcdecl, false);
+
+ funcdecl.eh_none = false;
+
+ sc2 = sc2.pop();
+
+ if (global.params.useOut == CHECKENABLE.off)
+ fens = null;
+ }
+ if (funcdecl.fbody && funcdecl.fbody.isErrorStatement())
+ {
+ }
+ else
+ {
+ auto a = new Statements();
+ // Merge in initialization of 'out' parameters
+ if (funcdecl.parameters)
+ {
+ for (size_t i = 0; i < funcdecl.parameters.dim; i++)
+ {
+ VarDeclaration v = (*funcdecl.parameters)[i];
+ if (v.storage_class & STC.out_)
+ {
+ if (!v._init)
+ {
+ v.error("Zero-length `out` parameters are not allowed.");
+ return;
+ }
+ ExpInitializer ie = v._init.isExpInitializer();
+ assert(ie);
+ if (auto iec = ie.exp.isConstructExp())
+ {
+ // construction occurred in parameter processing
+ auto ec = new AssignExp(iec.loc, iec.e1, iec.e2);
+ ec.type = iec.type;
+ ie.exp = ec;
+ }
+ a.push(new ExpStatement(Loc.initial, ie.exp));
+ }
+ }
+ }
+
+ if (_arguments)
+ {
+ /* Advance to elements[] member of TypeInfo_Tuple with:
+ * _arguments = v_arguments.elements;
+ */
+ Expression e = new VarExp(Loc.initial, funcdecl.v_arguments);
+ e = new DotIdExp(Loc.initial, e, Id.elements);
+ e = new ConstructExp(Loc.initial, _arguments, e);
+ e = e.expressionSemantic(sc2);
+
+ _arguments._init = new ExpInitializer(Loc.initial, e);
+ auto de = new DeclarationExp(Loc.initial, _arguments);
+ a.push(new ExpStatement(Loc.initial, de));
+ }
+
+ // Merge contracts together with body into one compound statement
+
+ if (freq || fpreinv)
+ {
+ if (!freq)
+ freq = fpreinv;
+ else if (fpreinv)
+ freq = new CompoundStatement(Loc.initial, freq, fpreinv);
+
+ a.push(freq);
+ }
+
+ if (funcdecl.fbody)
+ a.push(funcdecl.fbody);
+
+ if (fens || fpostinv)
+ {
+ if (!fens)
+ fens = fpostinv;
+ else if (fpostinv)
+ fens = new CompoundStatement(Loc.initial, fpostinv, fens);
+
+ auto ls = new LabelStatement(Loc.initial, Id.returnLabel, fens);
+ funcdecl.returnLabel.statement = ls;
+ a.push(funcdecl.returnLabel.statement);
+
+ if (f.next.ty != Tvoid && funcdecl.vresult)
+ {
+ // Create: return vresult;
+ Expression e = new VarExp(Loc.initial, funcdecl.vresult);
+ if (funcdecl.tintro)
+ {
+ e = e.implicitCastTo(sc, funcdecl.tintro.nextOf());
+ e = e.expressionSemantic(sc);
+ }
+ auto s = new ReturnStatement(Loc.initial, e);
+ a.push(s);
+ }
+ }
+ if (addReturn0())
+ {
+ // Add a return 0; statement
+ Statement s = new ReturnStatement(Loc.initial, IntegerExp.literal!0);
+ a.push(s);
+ }
+
+ Statement sbody = new CompoundStatement(Loc.initial, a);
+
+ /* Append destructor calls for parameters as finally blocks.
+ */
+ if (funcdecl.parameters)
+ {
+ // check if callee destroys arguments
+ const bool paramsNeedDtor = target.isCalleeDestroyingArgs(f);
+
+ foreach (v; *funcdecl.parameters)
+ {
+ if (v.isReference() || (v.storage_class & STC.lazy_))
+ continue;
+ if (v.needsScopeDtor())
+ {
+ v.storage_class |= STC.nodtor;
+ if (!paramsNeedDtor)
+ continue;
+
+ // same with ExpStatement.scopeCode()
+ Statement s = new DtorExpStatement(Loc.initial, v.edtor, v);
+
+ s = s.statementSemantic(sc2);
+
+ bool isnothrow = f.isnothrow & !(funcdecl.flags & FUNCFLAG.nothrowInprocess);
+ const blockexit = s.blockExit(funcdecl, isnothrow);
+ if (blockexit & BE.throw_)
+ funcdecl.eh_none = false;
+ if (f.isnothrow && isnothrow && blockexit & BE.throw_)
+ error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars());
+ if (funcdecl.flags & FUNCFLAG.nothrowInprocess && blockexit & BE.throw_)
+ f.isnothrow = false;
+
+ if (sbody.blockExit(funcdecl, f.isnothrow) == BE.fallthru)
+ sbody = new CompoundStatement(Loc.initial, sbody, s);
+ else
+ sbody = new TryFinallyStatement(Loc.initial, sbody, s);
+ }
+ }
+ }
+ // from this point on all possible 'throwers' are checked
+ funcdecl.flags &= ~FUNCFLAG.nothrowInprocess;
+
+ if (funcdecl.isSynchronized())
+ {
+ /* Wrap the entire function body in a synchronized statement
+ */
+ ClassDeclaration cd = funcdecl.toParentDecl().isClassDeclaration();
+ if (cd)
+ {
+ if (target.libraryObjectMonitors(funcdecl, sbody))
+ {
+ Expression vsync;
+ if (funcdecl.isStatic())
+ {
+ // The monitor is in the ClassInfo
+ vsync = new DotIdExp(funcdecl.loc, symbolToExp(cd, funcdecl.loc, sc2, false), Id.classinfo);
+ }
+ else
+ {
+ // 'this' is the monitor
+ vsync = new VarExp(funcdecl.loc, funcdecl.vthis);
+ if (funcdecl.isThis2)
+ {
+ vsync = new PtrExp(funcdecl.loc, vsync);
+ vsync = new IndexExp(funcdecl.loc, vsync, IntegerExp.literal!0);
+ }
+ }
+ sbody = new PeelStatement(sbody); // don't redo semantic()
+ sbody = new SynchronizedStatement(funcdecl.loc, vsync, sbody);
+ sbody = sbody.statementSemantic(sc2);
+ }
+ }
+ else
+ {
+ funcdecl.error("synchronized function `%s` must be a member of a class", funcdecl.toChars());
+ }
+ }
+
+ // If declaration has no body, don't set sbody to prevent incorrect codegen.
+ if (funcdecl.fbody || funcdecl.allowsContractWithoutBody())
+ funcdecl.fbody = sbody;
+ }
+
+ // Check for undefined labels
+ if (funcdecl.labtab)
+ foreach (keyValue; funcdecl.labtab.tab.asRange)
+ {
+ //printf(" KV: %s = %s\n", keyValue.key.toChars(), keyValue.value.toChars());
+ LabelDsymbol label = cast(LabelDsymbol)keyValue.value;
+ if (!label.statement && (!label.deleted || label.iasm))
+ {
+ funcdecl.error(label.loc, "label `%s` is undefined", label.toChars());
+ }
+ }
+
+ // Fix up forward-referenced gotos
+ if (funcdecl.gotos)
+ {
+ for (size_t i = 0; i < funcdecl.gotos.dim; ++i)
+ {
+ (*funcdecl.gotos)[i].checkLabel();
+ }
+ }
+
+ if (funcdecl.naked && (funcdecl.fensures || funcdecl.frequires))
+ funcdecl.error("naked assembly functions with contracts are not supported");
+
+ sc2.ctorflow.callSuper = CSX.none;
+ sc2.pop();
+ }
+
+ if (funcdecl.checkClosure())
+ {
+ // We should be setting errors here instead of relying on the global error count.
+ //errors = true;
+ }
+
+ /* If function survived being marked as impure, then it is pure
+ */
+ if (funcdecl.flags & FUNCFLAG.purityInprocess)
+ {
+ funcdecl.flags &= ~FUNCFLAG.purityInprocess;
+ if (funcdecl.type == f)
+ f = cast(TypeFunction)f.copy();
+ f.purity = PURE.fwdref;
+ }
+
+ if (funcdecl.flags & FUNCFLAG.safetyInprocess)
+ {
+ funcdecl.flags &= ~FUNCFLAG.safetyInprocess;
+ if (funcdecl.type == f)
+ f = cast(TypeFunction)f.copy();
+ f.trust = TRUST.safe;
+ }
+
+ if (funcdecl.flags & FUNCFLAG.nogcInprocess)
+ {
+ funcdecl.flags &= ~FUNCFLAG.nogcInprocess;
+ if (funcdecl.type == f)
+ f = cast(TypeFunction)f.copy();
+ f.isnogc = true;
+ }
+
+ if (funcdecl.flags & FUNCFLAG.returnInprocess)
+ {
+ funcdecl.flags &= ~FUNCFLAG.returnInprocess;
+ if (funcdecl.storage_class & STC.return_)
+ {
+ if (funcdecl.type == f)
+ f = cast(TypeFunction)f.copy();
+ f.isreturn = true;
+ if (funcdecl.storage_class & STC.returninferred)
+ f.isreturninferred = true;
+ }
+ }
+
+ funcdecl.flags &= ~FUNCFLAG.inferScope;
+
+ // Eliminate maybescope's
+ {
+ // Create and fill array[] with maybe candidates from the `this` and the parameters
+ VarDeclaration[] array = void;
+
+ VarDeclaration[10] tmp = void;
+ size_t dim = (funcdecl.vthis !is null) + (funcdecl.parameters ? funcdecl.parameters.dim : 0);
+ if (dim <= tmp.length)
+ array = tmp[0 .. dim];
+ else
+ {
+ auto ptr = cast(VarDeclaration*)mem.xmalloc(dim * VarDeclaration.sizeof);
+ array = ptr[0 .. dim];
+ }
+ size_t n = 0;
+ if (funcdecl.vthis)
+ array[n++] = funcdecl.vthis;
+ if (funcdecl.parameters)
+ {
+ foreach (v; *funcdecl.parameters)
+ {
+ array[n++] = v;
+ }
+ }
+
+ eliminateMaybeScopes(array[0 .. n]);
+
+ if (dim > tmp.length)
+ mem.xfree(array.ptr);
+ }
+
+ // Infer STC.scope_
+ if (funcdecl.parameters && !funcdecl.errors)
+ {
+ assert(f.parameterList.length == funcdecl.parameters.dim);
+ foreach (u, p; f.parameterList)
+ {
+ auto v = (*funcdecl.parameters)[u];
+ if (v.storage_class & STC.maybescope)
+ {
+ //printf("Inferring scope for %s\n", v.toChars());
+ notMaybeScope(v);
+ v.storage_class |= STC.scope_ | STC.scopeinferred;
+ p.storageClass |= STC.scope_ | STC.scopeinferred;
+ assert(!(p.storageClass & STC.maybescope));
+ }
+ }
+ }
+
+ if (funcdecl.vthis && funcdecl.vthis.storage_class & STC.maybescope)
+ {
+ notMaybeScope(funcdecl.vthis);
+ funcdecl.vthis.storage_class |= STC.scope_ | STC.scopeinferred;
+ f.isScopeQual = true;
+ f.isscopeinferred = true;
+ }
+
+ // reset deco to apply inference result to mangled name
+ if (f != funcdecl.type)
+ f.deco = null;
+
+ // Do semantic type AFTER pure/nothrow inference.
+ if (!f.deco && funcdecl.ident != Id.xopEquals && funcdecl.ident != Id.xopCmp)
+ {
+ sc = sc.push();
+ if (funcdecl.isCtorDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=#15665
+ f.isctor = true;
+ sc.stc = 0;
+ sc.linkage = funcdecl.linkage; // https://issues.dlang.org/show_bug.cgi?id=8496
+ funcdecl.type = f.typeSemantic(funcdecl.loc, sc);
+ sc = sc.pop();
+ }
+
+ // Do live analysis
+ if (global.params.useDIP1021 && funcdecl.fbody && funcdecl.type.ty != Terror &&
+ funcdecl.type.isTypeFunction().islive)
+ {
+ oblive(funcdecl);
+ }
+
+ /* If this function had instantiated with gagging, error reproduction will be
+ * done by TemplateInstance::semantic.
+ * Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
+ */
+ funcdecl.semanticRun = PASS.semantic3done;
+ funcdecl.semantic3Errors = (global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement());
+ if (funcdecl.type.ty == Terror)
+ funcdecl.errors = true;
+ //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars());
+ //fflush(stdout);
+ }
+
+ override void visit(CtorDeclaration ctor)
+ {
+ //printf("CtorDeclaration()\n%s\n", ctor.fbody.toChars());
+ if (ctor.semanticRun >= PASS.semantic3)
+ return;
+
+ /* If any of the fields of the aggregate have a destructor, add
+ * scope (failure) { this.fieldDtor(); }
+ * as the first statement of the constructor (unless the constructor
+ * doesn't define a body - @disable, extern)
+ *.It is not necessary to add it after
+ * each initialization of a field, because destruction of .init constructed
+ * structs should be benign.
+ * https://issues.dlang.org/show_bug.cgi?id=14246
+ */
+ AggregateDeclaration ad = ctor.isMemberDecl();
+ if (!ctor.fbody || !ad || !ad.fieldDtor || !global.params.dtorFields || global.params.betterC || ctor.type.toTypeFunction.isnothrow)
+ return visit(cast(FuncDeclaration)ctor);
+
+ /* Generate:
+ * this.fieldDtor()
+ */
+ Expression e = new ThisExp(ctor.loc);
+ e.type = ad.type.mutableOf();
+ e = new DotVarExp(ctor.loc, e, ad.fieldDtor, false);
+ auto ce = new CallExp(ctor.loc, e);
+ auto sexp = new ExpStatement(ctor.loc, ce);
+ auto ss = new ScopeStatement(ctor.loc, sexp, ctor.loc);
+
+ // @@@DEPRECATED_2096@@@
+ // Allow negligible attribute violations to allow for a smooth
+ // transition. Remove this after the usual deprecation period
+ // after 2.106.
+ if (global.params.dtorFields == FeatureState.default_)
+ {
+ auto ctf = cast(TypeFunction) ctor.type;
+ auto dtf = cast(TypeFunction) ad.fieldDtor.type;
+
+ const ngErr = ctf.isnogc && !dtf.isnogc;
+ const puErr = ctf.purity && !dtf.purity;
+ const saErr = ctf.trust == TRUST.safe && dtf.trust <= TRUST.system;
+
+ if (ngErr || puErr || saErr)
+ {
+ // storage_class is apparently not set for dtor & ctor
+ OutBuffer ob;
+ stcToBuffer(&ob,
+ (ngErr ? STC.nogc : 0) |
+ (puErr ? STC.pure_ : 0) |
+ (saErr ? STC.system : 0)
+ );
+ ctor.loc.deprecation("`%s` has stricter attributes than its destructor (`%s`)", ctor.toPrettyChars(), ob.peekChars());
+ ctor.loc.deprecationSupplemental("The destructor will be called if an exception is thrown");
+ ctor.loc.deprecationSupplemental("Either make the constructor `nothrow` or adjust the field destructors");
+
+ ce.ignoreAttributes = true;
+ }
+ }
+
+ version (all)
+ {
+ /* Generate:
+ * try { ctor.fbody; }
+ * catch (Exception __o)
+ * { this.fieldDtor(); throw __o; }
+ * This differs from the alternate scope(failure) version in that an Exception
+ * is caught rather than a Throwable. This enables the optimization whereby
+ * the try-catch can be removed if ctor.fbody is nothrow. (nothrow only
+ * applies to Exception.)
+ */
+ Identifier id = Identifier.generateId("__o");
+ auto ts = new ThrowStatement(ctor.loc, new IdentifierExp(ctor.loc, id));
+ auto handler = new CompoundStatement(ctor.loc, ss, ts);
+
+ auto catches = new Catches();
+ auto ctch = new Catch(ctor.loc, getException(), id, handler);
+ catches.push(ctch);
+
+ ctor.fbody = new TryCatchStatement(ctor.loc, ctor.fbody, catches);
+ }
+ else
+ {
+ /* Generate:
+ * scope (failure) { this.fieldDtor(); }
+ * Hopefully we can use this version someday when scope(failure) catches
+ * Exception instead of Throwable.
+ */
+ auto s = new ScopeGuardStatement(ctor.loc, TOK.onScopeFailure, ss);
+ ctor.fbody = new CompoundStatement(ctor.loc, s, ctor.fbody);
+ }
+ visit(cast(FuncDeclaration)ctor);
+ }
+
+
+ override void visit(Nspace ns)
+ {
+ if (ns.semanticRun >= PASS.semantic3)
+ return;
+ ns.semanticRun = PASS.semantic3;
+ static if (LOG)
+ {
+ printf("Nspace::semantic3('%s')\n", ns.toChars());
+ }
+ if (!ns.members)
+ return;
+
+ sc = sc.push(ns);
+ sc.linkage = LINK.cpp;
+ foreach (s; *ns.members)
+ {
+ s.semantic3(sc);
+ }
+ sc.pop();
+ }
+
+ override void visit(AttribDeclaration ad)
+ {
+ Dsymbols* d = ad.include(sc);
+ if (!d)
+ return;
+
+ Scope* sc2 = ad.newScope(sc);
+ for (size_t i = 0; i < d.dim; i++)
+ {
+ Dsymbol s = (*d)[i];
+ s.semantic3(sc2);
+ }
+ if (sc2 != sc)
+ sc2.pop();
+ }
+
+ override void visit(AggregateDeclaration ad)
+ {
+ //printf("AggregateDeclaration::semantic3(sc=%p, %s) type = %s, errors = %d\n", sc, toChars(), type.toChars(), errors);
+ if (!ad.members)
+ return;
+
+ StructDeclaration sd = ad.isStructDeclaration();
+ if (!sc) // from runDeferredSemantic3 for TypeInfo generation
+ {
+ assert(sd);
+ sd.semanticTypeInfoMembers();
+ return;
+ }
+
+ auto sc2 = ad.newScope(sc);
+
+ for (size_t i = 0; i < ad.members.dim; i++)
+ {
+ Dsymbol s = (*ad.members)[i];
+ s.semantic3(sc2);
+ }
+
+ sc2.pop();
+
+ // don't do it for unused deprecated types
+ // or error ypes
+ if (!ad.getRTInfo && Type.rtinfo && (!ad.isDeprecated() || global.params.useDeprecated != DiagnosticReporting.error) && (ad.type && ad.type.ty != Terror))
+ {
+ // Evaluate: RTinfo!type
+ auto tiargs = new Objects();
+ tiargs.push(ad.type);
+ auto ti = new TemplateInstance(ad.loc, Type.rtinfo, tiargs);
+
+ Scope* sc3 = ti.tempdecl._scope.startCTFE();
+ sc3.tinst = sc.tinst;
+ sc3.minst = sc.minst;
+ if (ad.isDeprecated())
+ sc3.stc |= STC.deprecated_;
+
+ ti.dsymbolSemantic(sc3);
+ ti.semantic2(sc3);
+ ti.semantic3(sc3);
+ auto e = symbolToExp(ti.toAlias(), Loc.initial, sc3, false);
+
+ sc3.endCTFE();
+
+ e = e.ctfeInterpret();
+ ad.getRTInfo = e;
+ }
+ if (sd)
+ sd.semanticTypeInfoMembers();
+ ad.semanticRun = PASS.semantic3done;
+ }
+}
+
+private struct FuncDeclSem3
+{
+ // The FuncDeclaration subject to Semantic analysis
+ FuncDeclaration funcdecl;
+
+ // Scope of analysis
+ Scope* sc;
+ this(FuncDeclaration fd,Scope* s)
+ {
+ funcdecl = fd;
+ sc = s;
+ }
+
+ /* Checks that the overriden functions (if any) have in contracts if
+ * funcdecl has an in contract.
+ */
+ void checkInContractOverrides()
+ {
+ if (funcdecl.frequires)
+ {
+ for (size_t i = 0; i < funcdecl.foverrides.dim; i++)
+ {
+ FuncDeclaration fdv = funcdecl.foverrides[i];
+ if (fdv.fbody && !fdv.frequires)
+ {
+ funcdecl.error("cannot have an in contract when overridden function `%s` does not have an in contract", fdv.toPrettyChars());
+ break;
+ }
+ }
+ }
+ }
+}
+
+private void semanticTypeInfoMembers(StructDeclaration sd)
+{
+ if (sd.xeq &&
+ sd.xeq._scope &&
+ sd.xeq.semanticRun < PASS.semantic3done)
+ {
+ uint errors = global.startGagging();
+ sd.xeq.semantic3(sd.xeq._scope);
+ if (global.endGagging(errors))
+ sd.xeq = sd.xerreq;
+ }
+
+ if (sd.xcmp &&
+ sd.xcmp._scope &&
+ sd.xcmp.semanticRun < PASS.semantic3done)
+ {
+ uint errors = global.startGagging();
+ sd.xcmp.semantic3(sd.xcmp._scope);
+ if (global.endGagging(errors))
+ sd.xcmp = sd.xerrcmp;
+ }
+
+ FuncDeclaration ftostr = search_toString(sd);
+ if (ftostr &&
+ ftostr._scope &&
+ ftostr.semanticRun < PASS.semantic3done)
+ {
+ ftostr.semantic3(ftostr._scope);
+ }
+
+ if (sd.xhash &&
+ sd.xhash._scope &&
+ sd.xhash.semanticRun < PASS.semantic3done)
+ {
+ sd.xhash.semantic3(sd.xhash._scope);
+ }
+
+ if (sd.postblit &&
+ sd.postblit._scope &&
+ sd.postblit.semanticRun < PASS.semantic3done)
+ {
+ sd.postblit.semantic3(sd.postblit._scope);
+ }
+
+ if (sd.dtor &&
+ sd.dtor._scope &&
+ sd.dtor.semanticRun < PASS.semantic3done)
+ {
+ sd.dtor.semantic3(sd.dtor._scope);
+ }
+}
diff --git a/gcc/d/dmd/sideeffect.c b/gcc/d/dmd/sideeffect.c
deleted file mode 100644
index 661bd43..0000000
--- a/gcc/d/dmd/sideeffect.c
+++ /dev/null
@@ -1,432 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/sideeffect.c
- */
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "init.h"
-#include "expression.h"
-#include "template.h"
-#include "statement.h"
-#include "mtype.h"
-#include "utf.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "scope.h"
-#include "attrib.h"
-#include "tokens.h"
-
-bool walkPostorder(Expression *e, StoppableVisitor *v);
-bool lambdaHasSideEffect(Expression *e);
-
-/**************************************************
- * Front-end expression rewriting should create temporary variables for
- * non trivial sub-expressions in order to:
- * 1. save evaluation order
- * 2. prevent sharing of sub-expression in AST
- */
-bool isTrivialExp(Expression *e)
-{
- class IsTrivialExp : public StoppableVisitor
- {
- public:
- IsTrivialExp() {}
-
- void visit(Expression *e)
- {
- /* Bugzilla 11201: CallExp is always non trivial expression,
- * especially for inlining.
- */
- if (e->op == TOKcall)
- {
- stop = true;
- return;
- }
-
- // stop walking if we determine this expression has side effects
- stop = lambdaHasSideEffect(e);
- }
- };
-
- IsTrivialExp v;
- return walkPostorder(e, &v) == false;
-}
-
-/********************************************
- * Determine if Expression has any side effects.
- */
-
-bool hasSideEffect(Expression *e)
-{
- class LambdaHasSideEffect : public StoppableVisitor
- {
- public:
- LambdaHasSideEffect() {}
-
- void visit(Expression *e)
- {
- // stop walking if we determine this expression has side effects
- stop = lambdaHasSideEffect(e);
- }
- };
-
- LambdaHasSideEffect v;
- return walkPostorder(e, &v);
-}
-
-/********************************************
- * Determine if the call of f, or function type or delegate type t1, has any side effects.
- * Returns:
- * 0 has any side effects
- * 1 nothrow + constant purity
- * 2 nothrow + strong purity
- */
-
-int callSideEffectLevel(FuncDeclaration *f)
-{
- /* Bugzilla 12760: ctor call always has side effects.
- */
- if (f->isCtorDeclaration())
- return 0;
-
- assert(f->type->ty == Tfunction);
- TypeFunction *tf = (TypeFunction *)f->type;
- if (tf->isnothrow)
- {
- PURE purity = f->isPure();
- if (purity == PUREstrong)
- return 2;
- if (purity == PUREconst)
- return 1;
- }
- return 0;
-}
-
-int callSideEffectLevel(Type *t)
-{
- t = t->toBasetype();
-
- TypeFunction *tf;
- if (t->ty == Tdelegate)
- tf = (TypeFunction *)((TypeDelegate *)t)->next;
- else
- {
- assert(t->ty == Tfunction);
- tf = (TypeFunction *)t;
- }
-
- tf->purityLevel();
- PURE purity = tf->purity;
- if (t->ty == Tdelegate && purity > PUREweak)
- {
- if (tf->isMutable())
- purity = PUREweak;
- else if (!tf->isImmutable())
- purity = PUREconst;
- }
-
- if (tf->isnothrow)
- {
- if (purity == PUREstrong)
- return 2;
- if (purity == PUREconst)
- return 1;
- }
- return 0;
-}
-
-bool lambdaHasSideEffect(Expression *e)
-{
- switch (e->op)
- {
- // Sort the cases by most frequently used first
- case TOKassign:
- case TOKplusplus:
- case TOKminusminus:
- case TOKdeclaration:
- case TOKconstruct:
- case TOKblit:
- case TOKaddass:
- case TOKminass:
- case TOKcatass:
- case TOKmulass:
- case TOKdivass:
- case TOKmodass:
- case TOKshlass:
- case TOKshrass:
- case TOKushrass:
- case TOKandass:
- case TOKorass:
- case TOKxorass:
- case TOKpowass:
- case TOKin:
- case TOKremove:
- case TOKassert:
- case TOKhalt:
- case TOKdelete:
- case TOKnew:
- case TOKnewanonclass:
- return true;
-
- case TOKcall:
- {
- CallExp *ce = (CallExp *)e;
- /* Calling a function or delegate that is pure nothrow
- * has no side effects.
- */
- if (ce->e1->type)
- {
- Type *t = ce->e1->type->toBasetype();
- if (t->ty == Tdelegate)
- t = ((TypeDelegate *)t)->next;
- if (t->ty == Tfunction &&
- (ce->f ? callSideEffectLevel(ce->f)
- : callSideEffectLevel(ce->e1->type)) > 0)
- {
- }
- else
- return true;
- }
- break;
- }
-
- case TOKcast:
- {
- CastExp *ce = (CastExp *)e;
- /* if:
- * cast(classtype)func() // because it may throw
- */
- if (ce->to->ty == Tclass && ce->e1->op == TOKcall && ce->e1->type->ty == Tclass)
- return true;
- break;
- }
-
- default:
- break;
- }
- return false;
-}
-
-
-/***********************************
- * The result of this expression will be discarded.
- * Print error messages if the operation has no side effects (and hence is meaningless).
- * Returns:
- * true if expression has no side effects
- */
-bool discardValue(Expression *e)
-{
- if (lambdaHasSideEffect(e)) // check side-effect shallowly
- return false;
- switch (e->op)
- {
- case TOKcast:
- {
- CastExp *ce = (CastExp *)e;
- if (ce->to->equals(Type::tvoid))
- {
- /*
- * Don't complain about an expression with no effect if it was cast to void
- */
- return false;
- }
- break; // complain
- }
-
- case TOKerror:
- return false;
-
- case TOKvar:
- {
- VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration();
- if (v && (v->storage_class & STCtemp))
- {
- // Bugzilla 5810: Don't complain about an internal generated variable.
- return false;
- }
- break;
- }
- case TOKcall:
- /* Issue 3882: */
- if (global.params.warnings != DIAGNOSTICoff && !global.gag)
- {
- CallExp *ce = (CallExp *)e;
- if (e->type->ty == Tvoid)
- {
- /* Don't complain about calling void-returning functions with no side-effect,
- * because purity and nothrow are inferred, and because some of the
- * runtime library depends on it. Needs more investigation.
- *
- * One possible solution is to restrict this message to only be called in hierarchies that
- * never call assert (and or not called from inside unittest blocks)
- */
- }
- else if (ce->e1->type)
- {
- Type *t = ce->e1->type->toBasetype();
- if (t->ty == Tdelegate)
- t = ((TypeDelegate *)t)->next;
- if (t->ty == Tfunction &&
- (ce->f ? callSideEffectLevel(ce->f)
- : callSideEffectLevel(ce->e1->type)) > 0)
- {
- const char *s;
- if (ce->f)
- s = ce->f->toPrettyChars();
- else if (ce->e1->op == TOKstar)
- {
- // print 'fp' if ce->e1 is (*fp)
- s = ((PtrExp *)ce->e1)->e1->toChars();
- }
- else
- s = ce->e1->toChars();
-
- e->warning("calling %s without side effects discards return value of type %s, prepend a cast(void) if intentional",
- s, e->type->toChars());
- }
- }
- }
- return false;
-
- case TOKscope:
- e->error("%s has no effect", e->toChars());
- return true;
-
- case TOKandand:
- case TOKoror:
- {
- LogicalExp *aae = (LogicalExp *)e;
- return discardValue(aae->e2);
- }
-
- case TOKquestion:
- {
- CondExp *ce = (CondExp *)e;
-
- /* Bugzilla 6178 & 14089: Either CondExp::e1 or e2 may have
- * redundant expression to make those types common. For example:
- *
- * struct S { this(int n); int v; alias v this; }
- * S[int] aa;
- * aa[1] = 0;
- *
- * The last assignment statement will be rewitten to:
- *
- * 1 in aa ? aa[1].value = 0 : (aa[1] = 0, aa[1].this(0)).value;
- *
- * The last DotVarExp is necessary to take assigned value.
- *
- * int value = (aa[1] = 0); // value = aa[1].value
- *
- * To avoid false error, discardValue() should be called only when
- * the both tops of e1 and e2 have actually no side effects.
- */
- if (!lambdaHasSideEffect(ce->e1) &&
- !lambdaHasSideEffect(ce->e2))
- {
- return discardValue(ce->e1) |
- discardValue(ce->e2);
- }
- return false;
- }
-
- case TOKcomma:
- {
- CommaExp *ce = (CommaExp *)e;
- /* Check for compiler-generated code of the form auto __tmp, e, __tmp;
- * In such cases, only check e for side effect (it's OK for __tmp to have
- * no side effect).
- * See Bugzilla 4231 for discussion
- */
- CommaExp *firstComma = ce;
- while (firstComma->e1->op == TOKcomma)
- firstComma = (CommaExp *)firstComma->e1;
- if (firstComma->e1->op == TOKdeclaration &&
- ce->e2->op == TOKvar &&
- ((DeclarationExp *)firstComma->e1)->declaration == ((VarExp*)ce->e2)->var)
- {
- return false;
- }
- // Don't check e1 until we cast(void) the a,b code generation
- //discardValue(ce->e1);
- return discardValue(ce->e2);
- }
-
- case TOKtuple:
- /* Pass without complaint if any of the tuple elements have side effects.
- * Ideally any tuple elements with no side effects should raise an error,
- * this needs more investigation as to what is the right thing to do.
- */
- if (!hasSideEffect(e))
- break;
- return false;
-
- default:
- break;
- }
- e->error("%s has no effect in expression (%s)", Token::toChars(e->op), e->toChars());
- return true;
-}
-
-/**************************************************
- * Build a temporary variable to copy the value of e into.
- * Params:
- * stc = storage classes will be added to the made temporary variable
- * name = name for temporary variable
- * e = original expression
- * Returns:
- * Newly created temporary variable.
- */
-VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e)
-{
- assert(name && name[0] == '_' && name[1] == '_');
- Identifier *id = Identifier::generateId(name);
- ExpInitializer *ez = new ExpInitializer(e->loc, e);
- VarDeclaration *vd = new VarDeclaration(e->loc, e->type, id, ez);
- vd->storage_class = stc;
- vd->storage_class |= STCtemp;
- vd->storage_class |= STCctfe; // temporary is always CTFEable
- return vd;
-}
-
-/**************************************************
- * Build a temporary variable to extract e's evaluation, if e is not trivial.
- * Params:
- * sc = scope
- * name = name for temporary variable
- * e0 = a new side effect part will be appended to it.
- * e = original expression
- * alwaysCopy = if true, build new temporary variable even if e is trivial.
- * Returns:
- * When e is trivial and alwaysCopy == false, e itself is returned.
- * Otherwise, a new VarExp is returned.
- * Note:
- * e's lvalue-ness will be handled well by STCref or STCrvalue.
- */
-Expression *extractSideEffect(Scope *sc, const char *name,
- Expression **e0, Expression *e, bool alwaysCopy = false)
-{
- if (!alwaysCopy && isTrivialExp(e))
- return e;
-
- VarDeclaration *vd = copyToTemp(0, name, e);
- if (e->isLvalue())
- vd->storage_class |= STCref;
- else
- vd->storage_class |= STCrvalue;
-
- Expression *de = new DeclarationExp(vd->loc, vd);
- Expression *ve = new VarExp(vd->loc, vd);
- de = expressionSemantic(de, sc);
- ve = expressionSemantic(ve, sc);
-
- *e0 = Expression::combine(*e0, de);
- return ve;
-}
diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d
new file mode 100644
index 0000000..d238150
--- /dev/null
+++ b/gcc/d/dmd/sideeffect.d
@@ -0,0 +1,418 @@
+/**
+ * Find side-effects of expressions.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d, _sideeffect.d)
+ * Documentation: https://dlang.org/phobos/dmd_sideeffect.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/sideeffect.d
+ */
+
+module dmd.sideeffect;
+
+import dmd.apply;
+import dmd.astenums;
+import dmd.declaration;
+import dmd.dscope;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.identifier;
+import dmd.init;
+import dmd.mtype;
+import dmd.tokens;
+import dmd.visitor;
+
+/**************************************************
+ * Front-end expression rewriting should create temporary variables for
+ * non trivial sub-expressions in order to:
+ * 1. save evaluation order
+ * 2. prevent sharing of sub-expression in AST
+ */
+extern (C++) bool isTrivialExp(Expression e)
+{
+ extern (C++) final class IsTrivialExp : StoppableVisitor
+ {
+ alias visit = typeof(super).visit;
+ public:
+ extern (D) this()
+ {
+ }
+
+ override void visit(Expression e)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=11201
+ * CallExp is always non trivial expression,
+ * especially for inlining.
+ */
+ if (e.op == TOK.call)
+ {
+ stop = true;
+ return;
+ }
+ // stop walking if we determine this expression has side effects
+ stop = lambdaHasSideEffect(e);
+ }
+ }
+
+ scope IsTrivialExp v = new IsTrivialExp();
+ return walkPostorder(e, v) == false;
+}
+
+/********************************************
+ * Determine if Expression has any side effects.
+ *
+ * Params:
+ * e = the expression
+ * assumeImpureCalls = whether function calls should always be assumed to
+ * be impure (e.g. debug is allowed to violate purity)
+ */
+extern (C++) bool hasSideEffect(Expression e, bool assumeImpureCalls = false)
+{
+ extern (C++) final class LambdaHasSideEffect : StoppableVisitor
+ {
+ alias visit = typeof(super).visit;
+ public:
+ extern (D) this()
+ {
+ }
+
+ override void visit(Expression e)
+ {
+ // stop walking if we determine this expression has side effects
+ stop = lambdaHasSideEffect(e, assumeImpureCalls);
+ }
+ }
+
+ scope LambdaHasSideEffect v = new LambdaHasSideEffect();
+ return walkPostorder(e, v);
+}
+
+/********************************************
+ * Determine if the call of f, or function type or delegate type t1, has any side effects.
+ * Returns:
+ * 0 has any side effects
+ * 1 nothrow + constant purity
+ * 2 nothrow + strong purity
+ */
+int callSideEffectLevel(FuncDeclaration f)
+{
+ /* https://issues.dlang.org/show_bug.cgi?id=12760
+ * ctor call always has side effects.
+ */
+ if (f.isCtorDeclaration())
+ return 0;
+ assert(f.type.ty == Tfunction);
+ TypeFunction tf = cast(TypeFunction)f.type;
+ if (tf.isnothrow)
+ {
+ PURE purity = f.isPure();
+ if (purity == PURE.strong)
+ return 2;
+ if (purity == PURE.const_)
+ return 1;
+ }
+ return 0;
+}
+
+int callSideEffectLevel(Type t)
+{
+ t = t.toBasetype();
+ TypeFunction tf;
+ if (t.ty == Tdelegate)
+ tf = cast(TypeFunction)(cast(TypeDelegate)t).next;
+ else
+ {
+ assert(t.ty == Tfunction);
+ tf = cast(TypeFunction)t;
+ }
+ if (!tf.isnothrow) // function can throw
+ return 0;
+
+ tf.purityLevel();
+ PURE purity = tf.purity;
+ if (t.ty == Tdelegate && purity > PURE.weak)
+ {
+ if (tf.isMutable())
+ purity = PURE.weak;
+ else if (!tf.isImmutable())
+ purity = PURE.const_;
+ }
+
+ if (purity == PURE.strong)
+ return 2;
+ if (purity == PURE.const_)
+ return 1;
+ return 0;
+}
+
+private bool lambdaHasSideEffect(Expression e, bool assumeImpureCalls = false)
+{
+ switch (e.op)
+ {
+ // Sort the cases by most frequently used first
+ case TOK.assign:
+ case TOK.plusPlus:
+ case TOK.minusMinus:
+ case TOK.declaration:
+ case TOK.construct:
+ case TOK.blit:
+ case TOK.addAssign:
+ case TOK.minAssign:
+ case TOK.concatenateAssign:
+ case TOK.concatenateElemAssign:
+ case TOK.concatenateDcharAssign:
+ case TOK.mulAssign:
+ case TOK.divAssign:
+ case TOK.modAssign:
+ case TOK.leftShiftAssign:
+ case TOK.rightShiftAssign:
+ case TOK.unsignedRightShiftAssign:
+ case TOK.andAssign:
+ case TOK.orAssign:
+ case TOK.xorAssign:
+ case TOK.powAssign:
+ case TOK.in_:
+ case TOK.remove:
+ case TOK.assert_:
+ case TOK.halt:
+ case TOK.delete_:
+ case TOK.new_:
+ case TOK.newAnonymousClass:
+ return true;
+ case TOK.call:
+ {
+ if (assumeImpureCalls)
+ return true;
+
+ if (e.type && e.type.ty == Tnoreturn)
+ return true;
+
+ CallExp ce = cast(CallExp)e;
+ /* Calling a function or delegate that is pure nothrow
+ * has no side effects.
+ */
+ if (ce.e1.type)
+ {
+ Type t = ce.e1.type.toBasetype();
+ if (t.ty == Tdelegate)
+ t = (cast(TypeDelegate)t).next;
+ if (t.ty == Tfunction && (ce.f ? callSideEffectLevel(ce.f) : callSideEffectLevel(ce.e1.type)) > 0)
+ {
+ }
+ else
+ return true;
+ }
+ break;
+ }
+ case TOK.cast_:
+ {
+ CastExp ce = cast(CastExp)e;
+ /* if:
+ * cast(classtype)func() // because it may throw
+ */
+ if (ce.to.ty == Tclass && ce.e1.op == TOK.call && ce.e1.type.ty == Tclass)
+ return true;
+ break;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+/***********************************
+ * The result of this expression will be discarded.
+ * Print error messages if the operation has no side effects (and hence is meaningless).
+ * Returns:
+ * true if expression has no side effects
+ */
+bool discardValue(Expression e)
+{
+ if (lambdaHasSideEffect(e)) // check side-effect shallowly
+ return false;
+ switch (e.op)
+ {
+ case TOK.cast_:
+ {
+ CastExp ce = cast(CastExp)e;
+ if (ce.to.equals(Type.tvoid))
+ {
+ /*
+ * Don't complain about an expression with no effect if it was cast to void
+ */
+ return false;
+ }
+ break; // complain
+ }
+ case TOK.error:
+ return false;
+ case TOK.variable:
+ {
+ VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
+ if (v && (v.storage_class & STC.temp))
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=5810
+ // Don't complain about an internal generated variable.
+ return false;
+ }
+ break;
+ }
+ case TOK.call:
+ /* Issue 3882: */
+ if (global.params.warnings != DiagnosticReporting.off && !global.gag)
+ {
+ CallExp ce = cast(CallExp)e;
+ if (e.type.ty == Tvoid)
+ {
+ /* Don't complain about calling void-returning functions with no side-effect,
+ * because purity and nothrow are inferred, and because some of the
+ * runtime library depends on it. Needs more investigation.
+ *
+ * One possible solution is to restrict this message to only be called in hierarchies that
+ * never call assert (and or not called from inside unittest blocks)
+ */
+ }
+ else if (ce.e1.type)
+ {
+ Type t = ce.e1.type.toBasetype();
+ if (t.ty == Tdelegate)
+ t = (cast(TypeDelegate)t).next;
+ if (t.ty == Tfunction && (ce.f ? callSideEffectLevel(ce.f) : callSideEffectLevel(ce.e1.type)) > 0)
+ {
+ const(char)* s;
+ if (ce.f)
+ s = ce.f.toPrettyChars();
+ else if (ce.e1.op == TOK.star)
+ {
+ // print 'fp' if ce.e1 is (*fp)
+ s = (cast(PtrExp)ce.e1).e1.toChars();
+ }
+ else
+ s = ce.e1.toChars();
+ e.warning("calling `%s` without side effects discards return value of type `%s`; prepend a `cast(void)` if intentional", s, e.type.toChars());
+ }
+ }
+ }
+ return false;
+ case TOK.andAnd:
+ case TOK.orOr:
+ {
+ LogicalExp aae = cast(LogicalExp)e;
+ return discardValue(aae.e2);
+ }
+ case TOK.question:
+ {
+ CondExp ce = cast(CondExp)e;
+ /* https://issues.dlang.org/show_bug.cgi?id=6178
+ * https://issues.dlang.org/show_bug.cgi?id=14089
+ * Either CondExp::e1 or e2 may have
+ * redundant expression to make those types common. For example:
+ *
+ * struct S { this(int n); int v; alias v this; }
+ * S[int] aa;
+ * aa[1] = 0;
+ *
+ * The last assignment statement will be rewitten to:
+ *
+ * 1 in aa ? aa[1].value = 0 : (aa[1] = 0, aa[1].this(0)).value;
+ *
+ * The last DotVarExp is necessary to take assigned value.
+ *
+ * int value = (aa[1] = 0); // value = aa[1].value
+ *
+ * To avoid false error, discardValue() should be called only when
+ * the both tops of e1 and e2 have actually no side effects.
+ */
+ if (!lambdaHasSideEffect(ce.e1) && !lambdaHasSideEffect(ce.e2))
+ {
+ return discardValue(ce.e1) |
+ discardValue(ce.e2);
+ }
+ return false;
+ }
+ case TOK.comma:
+ {
+ CommaExp ce = cast(CommaExp)e;
+ // Don't complain about compiler-generated comma expressions
+ if (ce.isGenerated)
+ return false;
+
+ // Don't check e1 until we cast(void) the a,b code generation.
+ // This is concretely done in expressionSemantic, if a CommaExp has Tvoid as type
+ return discardValue(ce.e2);
+ }
+ case TOK.tuple:
+ /* Pass without complaint if any of the tuple elements have side effects.
+ * Ideally any tuple elements with no side effects should raise an error,
+ * this needs more investigation as to what is the right thing to do.
+ */
+ if (!hasSideEffect(e))
+ break;
+ return false;
+ default:
+ break;
+ }
+ e.error("`%s` has no effect", e.toChars());
+ return true;
+}
+
+/**************************************************
+ * Build a temporary variable to copy the value of e into.
+ * Params:
+ * stc = storage classes will be added to the made temporary variable
+ * name = name for temporary variable
+ * e = original expression
+ * Returns:
+ * Newly created temporary variable.
+ */
+VarDeclaration copyToTemp(StorageClass stc, const char[] name, Expression e)
+{
+ assert(name[0] == '_' && name[1] == '_');
+ auto vd = new VarDeclaration(e.loc, e.type,
+ Identifier.generateId(name),
+ new ExpInitializer(e.loc, e));
+ vd.storage_class = stc | STC.temp | STC.ctfe; // temporary is always CTFEable
+ return vd;
+}
+
+/**************************************************
+ * Build a temporary variable to extract e's evaluation, if e is not trivial.
+ * Params:
+ * sc = scope
+ * name = name for temporary variable
+ * e0 = a new side effect part will be appended to it.
+ * e = original expression
+ * alwaysCopy = if true, build new temporary variable even if e is trivial.
+ * Returns:
+ * When e is trivial and alwaysCopy == false, e itself is returned.
+ * Otherwise, a new VarExp is returned.
+ * Note:
+ * e's lvalue-ness will be handled well by STC.ref_ or STC.rvalue.
+ */
+Expression extractSideEffect(Scope* sc, const char[] name,
+ ref Expression e0, Expression e, bool alwaysCopy = false)
+{
+ //printf("extractSideEffect(e: %s)\n", e.toChars());
+
+ /* The trouble here is that if CTFE is running, extracting the side effect
+ * results in an assignment, and then the interpreter says it cannot evaluate the
+ * side effect assignment variable. But we don't have to worry about side
+ * effects in function calls anyway, because then they won't CTFE.
+ * https://issues.dlang.org/show_bug.cgi?id=17145
+ */
+ if (!alwaysCopy &&
+ ((sc.flags & SCOPE.ctfe) ? !hasSideEffect(e) : isTrivialExp(e)))
+ return e;
+
+ auto vd = copyToTemp(0, name, e);
+ vd.storage_class |= e.isLvalue() ? STC.ref_ : STC.rvalue;
+
+ e0 = Expression.combine(e0, new DeclarationExp(vd.loc, vd)
+ .expressionSemantic(sc));
+
+ return new VarExp(vd.loc, vd)
+ .expressionSemantic(sc);
+}
diff --git a/gcc/d/dmd/statement.c b/gcc/d/dmd/statement.c
deleted file mode 100644
index 1f8e512..0000000
--- a/gcc/d/dmd/statement.c
+++ /dev/null
@@ -1,1793 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/statement.c
- */
-
-#include "root/dsystem.h"
-
-#include "statement.h"
-#include "errors.h"
-#include "expression.h"
-#include "cond.h"
-#include "init.h"
-#include "staticassert.h"
-#include "scope.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "id.h"
-#include "hdrgen.h"
-#include "parse.h"
-#include "template.h"
-#include "attrib.h"
-#include "import.h"
-
-bool walkPostorder(Statement *s, StoppableVisitor *v);
-StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f);
-bool checkEscapeRef(Scope *sc, Expression *e, bool gag);
-VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
-Statement *makeTupleForeachStatic(Scope *sc, ForeachStatement *fs, bool needExpansion);
-bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
-
-Identifier *fixupLabelName(Scope *sc, Identifier *ident)
-{
- unsigned flags = (sc->flags & SCOPEcontract);
- const char *id = ident->toChars();
- if (flags && flags != SCOPEinvariant &&
- !(id[0] == '_' && id[1] == '_'))
- {
- /* CTFE requires FuncDeclaration::labtab for the interpretation.
- * So fixing the label name inside in/out contracts is necessary
- * for the uniqueness in labtab.
- */
- const char *prefix = flags == SCOPErequire ? "__in_" : "__out_";
- OutBuffer buf;
- buf.printf("%s%s", prefix, ident->toChars());
-
- const char *name = buf.extractChars();
- ident = Identifier::idPool(name);
- }
- return ident;
-}
-
-LabelStatement *checkLabeledLoop(Scope *sc, Statement *statement)
-{
- if (sc->slabel && sc->slabel->statement == statement)
- {
- return sc->slabel;
- }
- return NULL;
-}
-
-/***********************************************************
- * Check an assignment is used as a condition.
- * Intended to be use before the `semantic` call on `e`.
- * Params:
- * e = condition expression which is not yet run semantic analysis.
- * Returns:
- * `e` or ErrorExp.
- */
-Expression *checkAssignmentAsCondition(Expression *e)
-{
- Expression *ec = e;
- while (ec->op == TOKcomma)
- ec = ((CommaExp *)ec)->e2;
- if (ec->op == TOKassign)
- {
- ec->error("assignment cannot be used as a condition, perhaps == was meant?");
- return new ErrorExp();
- }
- return e;
-}
-
-/// Return a type identifier reference to 'object.Throwable'
-TypeIdentifier *getThrowable()
-{
- TypeIdentifier *tid = new TypeIdentifier(Loc(), Id::empty);
- tid->addIdent(Id::object);
- tid->addIdent(Id::Throwable);
- return tid;
-}
-
-/******************************** Statement ***************************/
-
-Statement::Statement(Loc loc)
- : loc(loc)
-{
- // If this is an in{} contract scope statement (skip for determining
- // inlineStatus of a function body for header content)
-}
-
-Statement *Statement::syntaxCopy()
-{
- assert(0);
- return NULL;
-}
-
-/*************************************
- * Do syntax copy of an array of Statement's.
- */
-Statements *Statement::arraySyntaxCopy(Statements *a)
-{
- Statements *b = NULL;
- if (a)
- {
- b = a->copy();
- for (size_t i = 0; i < a->length; i++)
- {
- Statement *s = (*a)[i];
- (*b)[i] = s ? s->syntaxCopy() : NULL;
- }
- }
- return b;
-}
-
-void Statement::print()
-{
- fprintf(stderr, "%s\n", toChars());
- fflush(stderr);
-}
-
-const char *Statement::toChars()
-{
- HdrGenState hgs;
-
- OutBuffer buf;
- ::toCBuffer(this, &buf, &hgs);
- return buf.extractChars();
-}
-
-
-void Statement::error(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- ::verror(loc, format, ap);
- va_end( ap );
-}
-
-void Statement::warning(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- ::vwarning(loc, format, ap);
- va_end( ap );
-}
-
-void Statement::deprecation(const char *format, ...)
-{
- va_list ap;
- va_start(ap, format);
- ::vdeprecation(loc, format, ap);
- va_end( ap );
-}
-
-bool Statement::hasBreak()
-{
- //printf("Statement::hasBreak()\n");
- return false;
-}
-
-bool Statement::hasContinue()
-{
- return false;
-}
-
-/* ============================================== */
-// true if statement uses exception handling
-
-bool Statement::usesEH()
-{
- class UsesEH : public StoppableVisitor
- {
- public:
- void visit(Statement *) {}
- void visit(TryCatchStatement *) { stop = true; }
- void visit(TryFinallyStatement *) { stop = true; }
- void visit(ScopeGuardStatement *) { stop = true; }
- void visit(SynchronizedStatement *) { stop = true; }
- };
-
- UsesEH ueh;
- return walkPostorder(this, &ueh);
-}
-
-/* ============================================== */
-// true if statement 'comes from' somewhere else, like a goto
-
-bool Statement::comeFrom()
-{
- class ComeFrom : public StoppableVisitor
- {
- public:
- void visit(Statement *) {}
- void visit(CaseStatement *) { stop = true; }
- void visit(DefaultStatement *) { stop = true; }
- void visit(LabelStatement *) { stop = true; }
- void visit(AsmStatement *) { stop = true; }
- };
-
- ComeFrom cf;
- return walkPostorder(this, &cf);
-}
-
-/* ============================================== */
-// Return true if statement has executable code.
-
-bool Statement::hasCode()
-{
- class HasCode : public StoppableVisitor
- {
- public:
- void visit(Statement *)
- {
- stop = true;
- }
-
- void visit(ExpStatement *s)
- {
- if (s->exp != NULL)
- {
- stop = s->exp->hasCode();
- }
- }
-
- void visit(CompoundStatement *) {}
- void visit(ScopeStatement *) {}
- void visit(ImportStatement *) {}
- };
-
- HasCode hc;
- return walkPostorder(this, &hc);
-}
-
-Statement *Statement::last()
-{
- return this;
-}
-
-/****************************************
- * If this statement has code that needs to run in a finally clause
- * at the end of the current scope, return that code in the form of
- * a Statement.
- * Output:
- * *sentry code executed upon entry to the scope
- * *sexception code executed upon exit from the scope via exception
- * *sfinally code executed in finally block
- */
-
-Statement *Statement::scopeCode(Scope *, Statement **sentry, Statement **sexception, Statement **sfinally)
-{
- //printf("Statement::scopeCode()\n");
- //print();
- *sentry = NULL;
- *sexception = NULL;
- *sfinally = NULL;
- return this;
-}
-
-/*********************************
- * Flatten out the scope by presenting the statement
- * as an array of statements.
- * Returns NULL if no flattening necessary.
- */
-
-Statements *Statement::flatten(Scope *)
-{
- return NULL;
-}
-
-
-/******************************** ErrorStatement ***************************/
-
-ErrorStatement::ErrorStatement()
- : Statement(Loc())
-{
- assert(global.gaggedErrors || global.errors);
-}
-
-Statement *ErrorStatement::syntaxCopy()
-{
- return this;
-}
-
-/******************************** PeelStatement ***************************/
-
-PeelStatement::PeelStatement(Statement *s)
- : Statement(s->loc)
-{
- this->s = s;
-}
-
-/******************************** ExpStatement ***************************/
-
-ExpStatement::ExpStatement(Loc loc, Expression *exp)
- : Statement(loc)
-{
- this->exp = exp;
-}
-
-ExpStatement::ExpStatement(Loc loc, Dsymbol *declaration)
- : Statement(loc)
-{
- this->exp = new DeclarationExp(loc, declaration);
-}
-
-ExpStatement *ExpStatement::create(Loc loc, Expression *exp)
-{
- return new ExpStatement(loc, exp);
-}
-
-Statement *ExpStatement::syntaxCopy()
-{
- return new ExpStatement(loc, exp ? exp->syntaxCopy() : NULL);
-}
-
-Statement *ExpStatement::scopeCode(Scope *, Statement **sentry, Statement **sexception, Statement **sfinally)
-{
- //printf("ExpStatement::scopeCode()\n");
- //print();
-
- *sentry = NULL;
- *sexception = NULL;
- *sfinally = NULL;
-
- if (exp)
- {
- if (exp->op == TOKdeclaration)
- {
- DeclarationExp *de = (DeclarationExp *)(exp);
- VarDeclaration *v = de->declaration->isVarDeclaration();
- if (v && !v->isDataseg())
- {
- if (v->needsScopeDtor())
- {
- //printf("dtor is: "); v->edtor->print();
- *sfinally = new DtorExpStatement(loc, v->edtor, v);
- v->storage_class |= STCnodtor; // don't add in dtor again
- }
- }
- }
- }
- return this;
-}
-
-/****************************************
- * Convert TemplateMixin members (== Dsymbols) to Statements.
- */
-Statement *toStatement(Dsymbol *s)
-{
- class ToStmt : public Visitor
- {
- public:
- Statement *result;
-
- ToStmt()
- {
- this->result = NULL;
- }
-
- Statement *visitMembers(Loc loc, Dsymbols *a)
- {
- if (!a)
- return NULL;
-
- Statements *statements = new Statements();
- for (size_t i = 0; i < a->length; i++)
- {
- statements->push(toStatement((*a)[i]));
- }
- return new CompoundStatement(loc, statements);
- }
-
- void visit(Dsymbol *s)
- {
- ::error(Loc(), "Internal Compiler Error: cannot mixin %s %s\n", s->kind(), s->toChars());
- result = new ErrorStatement();
- }
-
- void visit(TemplateMixin *tm)
- {
- Statements *a = new Statements();
- for (size_t i = 0; i < tm->members->length; i++)
- {
- Statement *s = toStatement((*tm->members)[i]);
- if (s)
- a->push(s);
- }
- result = new CompoundStatement(tm->loc, a);
- }
-
- /* An actual declaration symbol will be converted to DeclarationExp
- * with ExpStatement.
- */
- Statement *declStmt(Dsymbol *s)
- {
- DeclarationExp *de = new DeclarationExp(s->loc, s);
- de->type = Type::tvoid; // avoid repeated semantic
- return new ExpStatement(s->loc, de);
- }
- void visit(VarDeclaration *d) { result = declStmt(d); }
- void visit(AggregateDeclaration *d) { result = declStmt(d); }
- void visit(FuncDeclaration *d) { result = declStmt(d); }
- void visit(EnumDeclaration *d) { result = declStmt(d); }
- void visit(AliasDeclaration *d) { result = declStmt(d); }
- void visit(TemplateDeclaration *d) { result = declStmt(d); }
-
- /* All attributes have been already picked by the semantic analysis of
- * 'bottom' declarations (function, struct, class, etc).
- * So we don't have to copy them.
- */
- void visit(StorageClassDeclaration *d) { result = visitMembers(d->loc, d->decl); }
- void visit(DeprecatedDeclaration *d) { result = visitMembers(d->loc, d->decl); }
- void visit(LinkDeclaration *d) { result = visitMembers(d->loc, d->decl); }
- void visit(ProtDeclaration *d) { result = visitMembers(d->loc, d->decl); }
- void visit(AlignDeclaration *d) { result = visitMembers(d->loc, d->decl); }
- void visit(UserAttributeDeclaration *d) { result = visitMembers(d->loc, d->decl); }
- void visit(ForwardingAttribDeclaration *d) { result = visitMembers(d->loc, d->decl); }
-
- void visit(StaticAssert *) {}
- void visit(Import *) {}
- void visit(PragmaDeclaration *) {}
-
- void visit(ConditionalDeclaration *d)
- {
- result = visitMembers(d->loc, d->include(NULL));
- }
-
- void visit(StaticForeachDeclaration *d)
- {
- assert(d->sfe && !!d->sfe->aggrfe ^ !!d->sfe->rangefe);
- result = visitMembers(d->loc, d->include(NULL));
- }
-
- void visit(CompileDeclaration *d)
- {
- result = visitMembers(d->loc, d->include(NULL));
- }
- };
-
- if (!s)
- return NULL;
-
- ToStmt v;
- s->accept(&v);
- return v.result;
-}
-
-Statements *ExpStatement::flatten(Scope *sc)
-{
- /* Bugzilla 14243: expand template mixin in statement scope
- * to handle variable destructors.
- */
- if (exp && exp->op == TOKdeclaration)
- {
- Dsymbol *d = ((DeclarationExp *)exp)->declaration;
- if (TemplateMixin *tm = d->isTemplateMixin())
- {
- Expression *e = expressionSemantic(exp, sc);
- if (e->op == TOKerror || tm->errors)
- {
- Statements *a = new Statements();
- a->push(new ErrorStatement());
- return a;
- }
- assert(tm->members);
-
- Statement *s = toStatement(tm);
- Statements *a = new Statements();
- a->push(s);
- return a;
- }
- }
- return NULL;
-}
-
-/******************************** DtorExpStatement ***************************/
-
-DtorExpStatement::DtorExpStatement(Loc loc, Expression *exp, VarDeclaration *v)
- : ExpStatement(loc, exp)
-{
- this->var = v;
-}
-
-Statement *DtorExpStatement::syntaxCopy()
-{
- return new DtorExpStatement(loc, exp ? exp->syntaxCopy() : NULL, var);
-}
-
-/******************************** CompileStatement ***************************/
-
-CompileStatement::CompileStatement(Loc loc, Expression *exp)
- : Statement(loc)
-{
- this->exps = new Expressions();
- this->exps->push(exp);
-}
-
-CompileStatement::CompileStatement(Loc loc, Expressions *exps)
- : Statement(loc)
-{
- this->exps = exps;
-}
-
-Statement *CompileStatement::syntaxCopy()
-{
- return new CompileStatement(loc, Expression::arraySyntaxCopy(exps));
-}
-
-static Statements *errorStatements()
-{
- Statements *a = new Statements();
- a->push(new ErrorStatement());
- return a;
-}
-
-static Statements *compileIt(CompileStatement *cs, Scope *sc)
-{
- //printf("CompileStatement::compileIt() %s\n", exp->toChars());
- OutBuffer buf;
- if (expressionsToString(buf, sc, cs->exps))
- return errorStatements();
-
- unsigned errors = global.errors;
- const size_t len = buf.length();
- const char *str = buf.extractChars();
- Parser p(cs->loc, sc->_module, (const utf8_t *)str, len, false);
- p.nextToken();
-
- Statements *a = new Statements();
- while (p.token.value != TOKeof)
- {
- Statement *s = p.parseStatement(PSsemi | PScurlyscope);
- if (!s || global.errors != errors)
- return errorStatements();
- a->push(s);
- }
- return a;
-}
-
-Statements *CompileStatement::flatten(Scope *sc)
-{
- //printf("CompileStatement::flatten() %s\n", exp->toChars());
- return compileIt(this, sc);
-}
-
-/******************************** CompoundStatement ***************************/
-
-CompoundStatement::CompoundStatement(Loc loc, Statements *s)
- : Statement(loc)
-{
- statements = s;
-}
-
-CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2)
- : Statement(loc)
-{
- statements = new Statements();
- statements->reserve(2);
- statements->push(s1);
- statements->push(s2);
-}
-
-CompoundStatement::CompoundStatement(Loc loc, Statement *s1)
- : Statement(loc)
-{
- statements = new Statements();
- statements->push(s1);
-}
-
-CompoundStatement *CompoundStatement::create(Loc loc, Statement *s1, Statement *s2)
-{
- return new CompoundStatement(loc, s1, s2);
-}
-
-Statement *CompoundStatement::syntaxCopy()
-{
- return new CompoundStatement(loc, Statement::arraySyntaxCopy(statements));
-}
-
-Statements *CompoundStatement::flatten(Scope *)
-{
- return statements;
-}
-
-ReturnStatement *CompoundStatement::isReturnStatement()
-{
- ReturnStatement *rs = NULL;
-
- for (size_t i = 0; i < statements->length; i++)
- {
- Statement *s = (*statements)[i];
- if (s)
- {
- rs = s->isReturnStatement();
- if (rs)
- break;
- }
- }
- return rs;
-}
-
-Statement *CompoundStatement::last()
-{
- Statement *s = NULL;
-
- for (size_t i = statements->length; i; --i)
- { s = (*statements)[i - 1];
- if (s)
- {
- s = s->last();
- if (s)
- break;
- }
- }
- return s;
-}
-
-/******************************** CompoundDeclarationStatement ***************************/
-
-CompoundDeclarationStatement::CompoundDeclarationStatement(Loc loc, Statements *s)
- : CompoundStatement(loc, s)
-{
- statements = s;
-}
-
-Statement *CompoundDeclarationStatement::syntaxCopy()
-{
- Statements *a = new Statements();
- a->setDim(statements->length);
- for (size_t i = 0; i < statements->length; i++)
- {
- Statement *s = (*statements)[i];
- (*a)[i] = s ? s->syntaxCopy() : NULL;
- }
- return new CompoundDeclarationStatement(loc, a);
-}
-
-/**************************** UnrolledLoopStatement ***************************/
-
-UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s)
- : Statement(loc)
-{
- statements = s;
-}
-
-Statement *UnrolledLoopStatement::syntaxCopy()
-{
- Statements *a = new Statements();
- a->setDim(statements->length);
- for (size_t i = 0; i < statements->length; i++)
- {
- Statement *s = (*statements)[i];
- (*a)[i] = s ? s->syntaxCopy() : NULL;
- }
- return new UnrolledLoopStatement(loc, a);
-}
-
-bool UnrolledLoopStatement::hasBreak()
-{
- return true;
-}
-
-bool UnrolledLoopStatement::hasContinue()
-{
- return true;
-}
-
-/******************************** ScopeStatement ***************************/
-
-ScopeStatement::ScopeStatement(Loc loc, Statement *s, Loc endloc)
- : Statement(loc)
-{
- this->statement = s;
- this->endloc = endloc;
-}
-
-Statement *ScopeStatement::syntaxCopy()
-{
- return new ScopeStatement(loc, statement ? statement->syntaxCopy() : NULL, endloc);
-}
-
-ReturnStatement *ScopeStatement::isReturnStatement()
-{
- if (statement)
- return statement->isReturnStatement();
- return NULL;
-}
-
-bool ScopeStatement::hasBreak()
-{
- //printf("ScopeStatement::hasBreak() %s\n", toChars());
- return statement ? statement->hasBreak() : false;
-}
-
-bool ScopeStatement::hasContinue()
-{
- return statement ? statement->hasContinue() : false;
-}
-
-/******************************** ForwardingStatement **********************/
-
-/* Statement whose symbol table contains foreach index variables in a
- * local scope and forwards other members to the parent scope. This
- * wraps a statement.
- *
- * Also see: `ddmd.attrib.ForwardingAttribDeclaration`
- */
-
-ForwardingStatement::ForwardingStatement(Loc loc, ForwardingScopeDsymbol *sym, Statement *s)
- : Statement(loc)
-{
- this->sym = sym;
- assert(s);
- this->statement = s;
-}
-
-ForwardingStatement::ForwardingStatement(Loc loc, Statement *s)
- : Statement(loc)
-{
- this->sym = new ForwardingScopeDsymbol(NULL);
- this->sym->symtab = new DsymbolTable();
- assert(s);
- this->statement = s;
-}
-
-Statement *ForwardingStatement::syntaxCopy()
-{
- return new ForwardingStatement(loc, statement->syntaxCopy());
-}
-
-/***********************
- * ForwardingStatements are distributed over the flattened
- * sequence of statements. This prevents flattening to be
- * "blocked" by a ForwardingStatement and is necessary, for
- * example, to support generating scope guards with `static
- * foreach`:
- *
- * static foreach(i; 0 .. 10) scope(exit) writeln(i);
- * writeln("this is printed first");
- * // then, it prints 10, 9, 8, 7, ...
- */
-
-Statements *ForwardingStatement::flatten(Scope *sc)
-{
- if (!statement)
- {
- return NULL;
- }
- sc = sc->push(sym);
- Statements *a = statement->flatten(sc);
- sc = sc->pop();
- if (!a)
- {
- return a;
- }
- Statements *b = new Statements();
- b->setDim(a->length);
- for (size_t i = 0; i < a->length; i++)
- {
- Statement *s = (*a)[i];
- (*b)[i] = s ? new ForwardingStatement(s->loc, sym, s) : NULL;
- }
- return b;
-}
-
-/******************************** WhileStatement ***************************/
-
-WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b, Loc endloc)
- : Statement(loc)
-{
- condition = c;
- _body = b;
- this->endloc = endloc;
-}
-
-Statement *WhileStatement::syntaxCopy()
-{
- return new WhileStatement(loc,
- condition->syntaxCopy(),
- _body ? _body->syntaxCopy() : NULL,
- endloc);
-}
-
-bool WhileStatement::hasBreak()
-{
- return true;
-}
-
-bool WhileStatement::hasContinue()
-{
- return true;
-}
-
-/******************************** DoStatement ***************************/
-
-DoStatement::DoStatement(Loc loc, Statement *b, Expression *c, Loc endloc)
- : Statement(loc)
-{
- _body = b;
- condition = c;
- this->endloc = endloc;
-}
-
-Statement *DoStatement::syntaxCopy()
-{
- return new DoStatement(loc,
- _body ? _body->syntaxCopy() : NULL,
- condition->syntaxCopy(),
- endloc);
-}
-
-bool DoStatement::hasBreak()
-{
- return true;
-}
-
-bool DoStatement::hasContinue()
-{
- return true;
-}
-
-/******************************** ForStatement ***************************/
-
-ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body, Loc endloc)
- : Statement(loc)
-{
- this->_init = init;
- this->condition = condition;
- this->increment = increment;
- this->_body = body;
- this->endloc = endloc;
- this->relatedLabeled = NULL;
-}
-
-Statement *ForStatement::syntaxCopy()
-{
- return new ForStatement(loc,
- _init ? _init->syntaxCopy() : NULL,
- condition ? condition->syntaxCopy() : NULL,
- increment ? increment->syntaxCopy() : NULL,
- _body->syntaxCopy(),
- endloc);
-}
-
-Statement *ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
-{
- //printf("ForStatement::scopeCode()\n");
- Statement::scopeCode(sc, sentry, sexception, sfinally);
- return this;
-}
-
-bool ForStatement::hasBreak()
-{
- //printf("ForStatement::hasBreak()\n");
- return true;
-}
-
-bool ForStatement::hasContinue()
-{
- return true;
-}
-
-/******************************** ForeachStatement ***************************/
-
-ForeachStatement::ForeachStatement(Loc loc, TOK op, Parameters *parameters,
- Expression *aggr, Statement *body, Loc endloc)
- : Statement(loc)
-{
- this->op = op;
- this->parameters = parameters;
- this->aggr = aggr;
- this->_body = body;
- this->endloc = endloc;
-
- this->key = NULL;
- this->value = NULL;
-
- this->func = NULL;
-
- this->cases = NULL;
- this->gotos = NULL;
-}
-
-Statement *ForeachStatement::syntaxCopy()
-{
- return new ForeachStatement(loc, op,
- Parameter::arraySyntaxCopy(parameters),
- aggr->syntaxCopy(),
- _body ? _body->syntaxCopy() : NULL,
- endloc);
-}
-
-bool ForeachStatement::checkForArgTypes()
-{
- bool result = false;
-
- for (size_t i = 0; i < parameters->length; i++)
- {
- Parameter *p = (*parameters)[i];
- if (!p->type)
- {
- error("cannot infer type for %s", p->ident->toChars());
- p->type = Type::terror;
- result = true;
- }
- }
- return result;
-}
-
-bool ForeachStatement::hasBreak()
-{
- return true;
-}
-
-bool ForeachStatement::hasContinue()
-{
- return true;
-}
-
-/**************************** ForeachRangeStatement ***************************/
-
-
-ForeachRangeStatement::ForeachRangeStatement(Loc loc, TOK op, Parameter *prm,
- Expression *lwr, Expression *upr, Statement *body, Loc endloc)
- : Statement(loc)
-{
- this->op = op;
- this->prm = prm;
- this->lwr = lwr;
- this->upr = upr;
- this->_body = body;
- this->endloc = endloc;
-
- this->key = NULL;
-}
-
-Statement *ForeachRangeStatement::syntaxCopy()
-{
- return new ForeachRangeStatement(loc, op,
- prm->syntaxCopy(),
- lwr->syntaxCopy(),
- upr->syntaxCopy(),
- _body ? _body->syntaxCopy() : NULL,
- endloc);
-}
-
-bool ForeachRangeStatement::hasBreak()
-{
- return true;
-}
-
-bool ForeachRangeStatement::hasContinue()
-{
- return true;
-}
-
-/******************************** IfStatement ***************************/
-
-IfStatement::IfStatement(Loc loc, Parameter *prm, Expression *condition, Statement *ifbody, Statement *elsebody, Loc endloc)
- : Statement(loc)
-{
- this->prm = prm;
- this->condition = condition;
- this->ifbody = ifbody;
- this->elsebody = elsebody;
- this->endloc = endloc;
- this->match = NULL;
-}
-
-Statement *IfStatement::syntaxCopy()
-{
- return new IfStatement(loc,
- prm ? prm->syntaxCopy() : NULL,
- condition->syntaxCopy(),
- ifbody ? ifbody->syntaxCopy() : NULL,
- elsebody ? elsebody->syntaxCopy() : NULL,
- endloc);
-}
-
-/******************************** ConditionalStatement ***************************/
-
-ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody)
- : Statement(loc)
-{
- this->condition = condition;
- this->ifbody = ifbody;
- this->elsebody = elsebody;
-}
-
-Statement *ConditionalStatement::syntaxCopy()
-{
- return new ConditionalStatement(loc,
- condition->syntaxCopy(),
- ifbody->syntaxCopy(),
- elsebody ? elsebody->syntaxCopy() : NULL);
-}
-
-Statements *ConditionalStatement::flatten(Scope *sc)
-{
- Statement *s;
-
- //printf("ConditionalStatement::flatten()\n");
- if (condition->include(sc))
- {
- DebugCondition *dc = condition->isDebugCondition();
- if (dc)
- s = new DebugStatement(loc, ifbody);
- else
- s = ifbody;
- }
- else
- s = elsebody;
-
- Statements *a = new Statements();
- a->push(s);
- return a;
-}
-
-/******************************** StaticForeachStatement ********************/
-
-/* Static foreach statements, like:
- * void main()
- * {
- * static foreach(i; 0 .. 10)
- * {
- * pragma(msg, i);
- * }
- * }
- */
-
-StaticForeachStatement::StaticForeachStatement(Loc loc, StaticForeach *sfe)
- : Statement(loc)
-{
- this->sfe = sfe;
-}
-
-Statement *StaticForeachStatement::syntaxCopy()
-{
- return new StaticForeachStatement(loc, sfe->syntaxCopy());
-}
-
-Statements *StaticForeachStatement::flatten(Scope *sc)
-{
- staticForeachPrepare(sfe, sc);
- if (staticForeachReady(sfe))
- {
- Statement *s = makeTupleForeachStatic(sc, sfe->aggrfe, sfe->needExpansion);
- Statements *result = s->flatten(sc);
- if (result)
- {
- return result;
- }
- result = new Statements();
- result->push(s);
- return result;
- }
- else
- {
- Statements *result = new Statements();
- result->push(new ErrorStatement());
- return result;
- }
-}
-
-/******************************** PragmaStatement ***************************/
-
-PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body)
- : Statement(loc)
-{
- this->ident = ident;
- this->args = args;
- this->_body = body;
-}
-
-Statement *PragmaStatement::syntaxCopy()
-{
- return new PragmaStatement(loc, ident,
- Expression::arraySyntaxCopy(args),
- _body ? _body->syntaxCopy() : NULL);
-}
-
-/******************************** StaticAssertStatement ***************************/
-
-StaticAssertStatement::StaticAssertStatement(StaticAssert *sa)
- : Statement(sa->loc)
-{
- this->sa = sa;
-}
-
-Statement *StaticAssertStatement::syntaxCopy()
-{
- return new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL));
-}
-
-/******************************** SwitchStatement ***************************/
-
-SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal)
- : Statement(loc)
-{
- this->condition = c;
- this->_body = b;
- this->isFinal = isFinal;
- sdefault = NULL;
- tf = NULL;
- cases = NULL;
- hasNoDefault = 0;
- hasVars = 0;
- lastVar = NULL;
-}
-
-Statement *SwitchStatement::syntaxCopy()
-{
- return new SwitchStatement(loc,
- condition->syntaxCopy(),
- _body->syntaxCopy(),
- isFinal);
-}
-
-bool SwitchStatement::hasBreak()
-{
- return true;
-}
-
-static bool checkVar(SwitchStatement *s, VarDeclaration *vd)
-{
- if (!vd || vd->isDataseg() || (vd->storage_class & STCmanifest))
- return false;
-
- VarDeclaration *last = s->lastVar;
- while (last && last != vd)
- last = last->lastVar;
- if (last == vd)
- {
- // All good, the label's scope has no variables
- }
- else if (vd->storage_class & STCexptemp)
- {
- // Lifetime ends at end of expression, so no issue with skipping the statement
- }
- else if (vd->ident == Id::withSym)
- {
- s->deprecation("`switch` skips declaration of `with` temporary at %s", vd->loc.toChars());
- return true;
- }
- else
- {
- s->deprecation("`switch` skips declaration of variable %s at %s", vd->toPrettyChars(), vd->loc.toChars());
- return true;
- }
-
- return false;
-}
-
-bool SwitchStatement::checkLabel()
-{
- const bool error = true;
-
- if (sdefault && checkVar(this, sdefault->lastVar))
- return !error; // return error once fully deprecated
-
- for (size_t i = 0; i < cases->length; i++)
- {
- CaseStatement *scase = (*cases)[i];
- if (scase && checkVar(this, scase->lastVar))
- return !error; // return error once fully deprecated
- }
- return !error;
-}
-
-/******************************** CaseStatement ***************************/
-
-CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s)
- : Statement(loc)
-{
- this->exp = exp;
- this->statement = s;
- index = 0;
- lastVar = NULL;
-}
-
-Statement *CaseStatement::syntaxCopy()
-{
- return new CaseStatement(loc,
- exp->syntaxCopy(),
- statement->syntaxCopy());
-}
-
-int CaseStatement::compare(RootObject *obj)
-{
- // Sort cases so we can do an efficient lookup
- CaseStatement *cs2 = (CaseStatement *)(obj);
-
- return exp->compare(cs2->exp);
-}
-
-/******************************** CaseRangeStatement ***************************/
-
-
-CaseRangeStatement::CaseRangeStatement(Loc loc, Expression *first,
- Expression *last, Statement *s)
- : Statement(loc)
-{
- this->first = first;
- this->last = last;
- this->statement = s;
-}
-
-Statement *CaseRangeStatement::syntaxCopy()
-{
- return new CaseRangeStatement(loc,
- first->syntaxCopy(),
- last->syntaxCopy(),
- statement->syntaxCopy());
-}
-
-/******************************** DefaultStatement ***************************/
-
-DefaultStatement::DefaultStatement(Loc loc, Statement *s)
- : Statement(loc)
-{
- this->statement = s;
- this->lastVar = NULL;
-}
-
-Statement *DefaultStatement::syntaxCopy()
-{
- return new DefaultStatement(loc, statement->syntaxCopy());
-}
-
-/******************************** GotoDefaultStatement ***************************/
-
-GotoDefaultStatement::GotoDefaultStatement(Loc loc)
- : Statement(loc)
-{
- sw = NULL;
-}
-
-Statement *GotoDefaultStatement::syntaxCopy()
-{
- return new GotoDefaultStatement(loc);
-}
-
-/******************************** GotoCaseStatement ***************************/
-
-GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp)
- : Statement(loc)
-{
- cs = NULL;
- this->exp = exp;
-}
-
-Statement *GotoCaseStatement::syntaxCopy()
-{
- return new GotoCaseStatement(loc, exp ? exp->syntaxCopy() : NULL);
-}
-
-/******************************** SwitchErrorStatement ***************************/
-
-SwitchErrorStatement::SwitchErrorStatement(Loc loc)
- : Statement(loc)
-{
-}
-
-/******************************** ReturnStatement ***************************/
-
-ReturnStatement::ReturnStatement(Loc loc, Expression *exp)
- : Statement(loc)
-{
- this->exp = exp;
- this->caseDim = 0;
-}
-
-Statement *ReturnStatement::syntaxCopy()
-{
- return new ReturnStatement(loc, exp ? exp->syntaxCopy() : NULL);
-}
-
-/******************************** BreakStatement ***************************/
-
-BreakStatement::BreakStatement(Loc loc, Identifier *ident)
- : Statement(loc)
-{
- this->ident = ident;
-}
-
-Statement *BreakStatement::syntaxCopy()
-{
- return new BreakStatement(loc, ident);
-}
-
-/******************************** ContinueStatement ***************************/
-
-ContinueStatement::ContinueStatement(Loc loc, Identifier *ident)
- : Statement(loc)
-{
- this->ident = ident;
-}
-
-Statement *ContinueStatement::syntaxCopy()
-{
- return new ContinueStatement(loc, ident);
-}
-
-/******************************** SynchronizedStatement ***************************/
-
-SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body)
- : Statement(loc)
-{
- this->exp = exp;
- this->_body = body;
-}
-
-Statement *SynchronizedStatement::syntaxCopy()
-{
- return new SynchronizedStatement(loc,
- exp ? exp->syntaxCopy() : NULL,
- _body ? _body->syntaxCopy() : NULL);
-}
-
-bool SynchronizedStatement::hasBreak()
-{
- return false; //true;
-}
-
-bool SynchronizedStatement::hasContinue()
-{
- return false; //true;
-}
-
-/******************************** WithStatement ***************************/
-
-WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body, Loc endloc)
- : Statement(loc)
-{
- this->exp = exp;
- this->_body = body;
- this->endloc = endloc;
- wthis = NULL;
-}
-
-Statement *WithStatement::syntaxCopy()
-{
- return new WithStatement(loc,
- exp->syntaxCopy(),
- _body ? _body->syntaxCopy() : NULL, endloc);
-}
-
-/******************************** TryCatchStatement ***************************/
-
-TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Catches *catches)
- : Statement(loc)
-{
- this->_body = body;
- this->catches = catches;
-}
-
-Statement *TryCatchStatement::syntaxCopy()
-{
- Catches *a = new Catches();
- a->setDim(catches->length);
- for (size_t i = 0; i < a->length; i++)
- {
- Catch *c = (*catches)[i];
- (*a)[i] = c->syntaxCopy();
- }
- return new TryCatchStatement(loc, _body->syntaxCopy(), a);
-}
-
-bool TryCatchStatement::hasBreak()
-{
- return false;
-}
-
-/******************************** Catch ***************************/
-
-Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler)
-{
- //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars());
- this->loc = loc;
- this->type = t;
- this->ident = id;
- this->handler = handler;
- var = NULL;
- errors = false;
- internalCatch = false;
-}
-
-Catch *Catch::syntaxCopy()
-{
- Catch *c = new Catch(loc,
- type ? type->syntaxCopy() : getThrowable(),
- ident,
- (handler ? handler->syntaxCopy() : NULL));
- c->internalCatch = internalCatch;
- return c;
-}
-
-/****************************** TryFinallyStatement ***************************/
-
-TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody)
- : Statement(loc)
-{
- this->_body = body;
- this->finalbody = finalbody;
-}
-
-TryFinallyStatement *TryFinallyStatement::create(Loc loc, Statement *body, Statement *finalbody)
-{
- return new TryFinallyStatement(loc, body, finalbody);
-}
-
-Statement *TryFinallyStatement::syntaxCopy()
-{
- return new TryFinallyStatement(loc,
- _body->syntaxCopy(), finalbody->syntaxCopy());
-}
-
-bool TryFinallyStatement::hasBreak()
-{
- return false; //true;
-}
-
-bool TryFinallyStatement::hasContinue()
-{
- return false; //true;
-}
-
-/****************************** ScopeGuardStatement ***************************/
-
-ScopeGuardStatement::ScopeGuardStatement(Loc loc, TOK tok, Statement *statement)
- : Statement(loc)
-{
- this->tok = tok;
- this->statement = statement;
-}
-
-Statement *ScopeGuardStatement::syntaxCopy()
-{
- return new ScopeGuardStatement(loc, tok, statement->syntaxCopy());
-}
-
-Statement *ScopeGuardStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally)
-{
- //printf("ScopeGuardStatement::scopeCode()\n");
- //print();
- *sentry = NULL;
- *sexception = NULL;
- *sfinally = NULL;
-
- Statement *s = new PeelStatement(statement);
-
- switch (tok)
- {
- case TOKon_scope_exit:
- *sfinally = s;
- break;
-
- case TOKon_scope_failure:
- *sexception = s;
- break;
-
- case TOKon_scope_success:
- {
- /* Create:
- * sentry: bool x = false;
- * sexception: x = true;
- * sfinally: if (!x) statement;
- */
- VarDeclaration *v = copyToTemp(0, "__os", new IntegerExp(Loc(), 0, Type::tbool));
- dsymbolSemantic(v, sc);
- *sentry = new ExpStatement(loc, v);
-
- Expression *e = new IntegerExp(Loc(), 1, Type::tbool);
- e = new AssignExp(Loc(), new VarExp(Loc(), v), e);
- *sexception = new ExpStatement(Loc(), e);
-
- e = new VarExp(Loc(), v);
- e = new NotExp(Loc(), e);
- *sfinally = new IfStatement(Loc(), NULL, e, s, NULL, Loc());
-
- break;
- }
-
- default:
- assert(0);
- }
- return NULL;
-}
-
-/******************************** ThrowStatement ***************************/
-
-ThrowStatement::ThrowStatement(Loc loc, Expression *exp)
- : Statement(loc)
-{
- this->exp = exp;
- this->internalThrow = false;
-}
-
-Statement *ThrowStatement::syntaxCopy()
-{
- ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy());
- s->internalThrow = internalThrow;
- return s;
-}
-
-/******************************** DebugStatement **************************/
-
-DebugStatement::DebugStatement(Loc loc, Statement *statement)
- : Statement(loc)
-{
- this->statement = statement;
-}
-
-Statement *DebugStatement::syntaxCopy()
-{
- return new DebugStatement(loc,
- statement ? statement->syntaxCopy() : NULL);
-}
-
-Statements *DebugStatement::flatten(Scope *sc)
-{
- Statements *a = statement ? statement->flatten(sc) : NULL;
- if (a)
- {
- for (size_t i = 0; i < a->length; i++)
- { Statement *s = (*a)[i];
-
- s = new DebugStatement(loc, s);
- (*a)[i] = s;
- }
- }
-
- return a;
-}
-
-/******************************** GotoStatement ***************************/
-
-GotoStatement::GotoStatement(Loc loc, Identifier *ident)
- : Statement(loc)
-{
- this->ident = ident;
- this->label = NULL;
- this->tf = NULL;
- this->os = NULL;
- this->lastVar = NULL;
-}
-
-Statement *GotoStatement::syntaxCopy()
-{
- return new GotoStatement(loc, ident);
-}
-
-bool GotoStatement::checkLabel()
-{
- if (!label->statement)
- {
- error("label `%s` is undefined", label->toChars());
- return true;
- }
-
- if (label->statement->os != os)
- {
- if (os && os->tok == TOKon_scope_failure && !label->statement->os)
- {
- // Jump out from scope(failure) block is allowed.
- }
- else
- {
- if (label->statement->os)
- error("cannot goto in to %s block", Token::toChars(label->statement->os->tok));
- else
- error("cannot goto out of %s block", Token::toChars(os->tok));
- return true;
- }
- }
-
- if (label->statement->tf != tf)
- {
- error("cannot goto in or out of finally block");
- return true;
- }
-
- VarDeclaration *vd = label->statement->lastVar;
- if (!vd || vd->isDataseg() || (vd->storage_class & STCmanifest))
- return false;
-
- VarDeclaration *last = lastVar;
- while (last && last != vd)
- last = last->lastVar;
- if (last == vd)
- {
- // All good, the label's scope has no variables
- }
- else if (vd->ident == Id::withSym)
- {
- error("goto skips declaration of with temporary at %s", vd->loc.toChars());
- return true;
- }
- else
- {
- error("goto skips declaration of variable %s at %s", vd->toPrettyChars(), vd->loc.toChars());
- return true;
- }
-
- return false;
-}
-
-/******************************** LabelStatement ***************************/
-
-LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement)
- : Statement(loc)
-{
- this->ident = ident;
- this->statement = statement;
- this->tf = NULL;
- this->os = NULL;
- this->lastVar = NULL;
- this->gotoTarget = NULL;
- this->breaks = false;
-}
-
-Statement *LabelStatement::syntaxCopy()
-{
- return new LabelStatement(loc, ident, statement ? statement->syntaxCopy() : NULL);
-}
-
-Statement *LabelStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally)
-{
- //printf("LabelStatement::scopeCode()\n");
- if (statement)
- statement = statement->scopeCode(sc, sentry, sexit, sfinally);
- else
- {
- *sentry = NULL;
- *sexit = NULL;
- *sfinally = NULL;
- }
- return this;
-}
-
-Statements *LabelStatement::flatten(Scope *sc)
-{
- Statements *a = NULL;
-
- if (statement)
- {
- a = statement->flatten(sc);
- if (a)
- {
- if (!a->length)
- {
- a->push(new ExpStatement(loc, (Expression *)NULL));
- }
-
- // reuse 'this' LabelStatement
- this->statement = (*a)[0];
- (*a)[0] = this;
- }
- }
-
- return a;
-}
-
-/******************************** LabelDsymbol ***************************/
-
-LabelDsymbol::LabelDsymbol(Identifier *ident)
- : Dsymbol(ident)
-{
- statement = NULL;
-}
-
-LabelDsymbol *LabelDsymbol::create(Identifier *ident)
-{
- return new LabelDsymbol(ident);
-}
-
-LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()?
-{
- return this;
-}
-
-
-/************************ AsmStatement ***************************************/
-
-AsmStatement::AsmStatement(Loc loc, Token *tokens)
- : Statement(loc)
-{
- this->tokens = tokens;
-}
-
-Statement *AsmStatement::syntaxCopy()
-{
- return new AsmStatement(loc, tokens);
-}
-
-
-/************************ InlineAsmStatement **********************************/
-
-InlineAsmStatement::InlineAsmStatement(Loc loc, Token *tokens)
- : AsmStatement(loc, tokens)
-{
- asmcode = NULL;
- asmalign = 0;
- refparam = false;
- naked = false;
- regs = 0;
-}
-
-Statement *InlineAsmStatement::syntaxCopy()
-{
- return new InlineAsmStatement(loc, tokens);
-}
-
-
-/************************ GccAsmStatement ***************************************/
-
-GccAsmStatement::GccAsmStatement(Loc loc, Token *tokens)
- : AsmStatement(loc, tokens)
-{
- this->stc = STCundefined;
- this->insn = NULL;
- this->args = NULL;
- this->outputargs = 0;
- this->names = NULL;
- this->constraints = NULL;
- this->clobbers = NULL;
- this->labels = NULL;
- this->gotos = NULL;
-}
-
-Statement *GccAsmStatement::syntaxCopy()
-{
- return new GccAsmStatement(loc, tokens);
-}
-
-/************************ CompoundAsmStatement ***************************************/
-
-CompoundAsmStatement::CompoundAsmStatement(Loc loc, Statements *s, StorageClass stc)
- : CompoundStatement(loc, s)
-{
- this->stc = stc;
-}
-
-CompoundAsmStatement *CompoundAsmStatement::syntaxCopy()
-{
- Statements *a = new Statements();
- a->setDim(statements->length);
- for (size_t i = 0; i < statements->length; i++)
- {
- Statement *s = (*statements)[i];
- (*a)[i] = s ? s->syntaxCopy() : NULL;
- }
- return new CompoundAsmStatement(loc, a, stc);
-}
-
-Statements *CompoundAsmStatement::flatten(Scope *)
-{
- return NULL;
-}
-
-/************************ ImportStatement ***************************************/
-
-ImportStatement::ImportStatement(Loc loc, Dsymbols *imports)
- : Statement(loc)
-{
- this->imports = imports;
-}
-
-Statement *ImportStatement::syntaxCopy()
-{
- Dsymbols *m = new Dsymbols();
- m->setDim(imports->length);
- for (size_t i = 0; i < imports->length; i++)
- {
- Dsymbol *s = (*imports)[i];
- (*m)[i] = s->syntaxCopy(NULL);
- }
- return new ImportStatement(loc, m);
-}
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
new file mode 100644
index 0000000..b49c903
--- /dev/null
+++ b/gcc/d/dmd/statement.d
@@ -0,0 +1,2053 @@
+/**
+ * Defines AST nodes for statements.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement.d, _statement.d)
+ * Documentation: https://dlang.org/phobos/dmd_statement.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statement.d
+ */
+
+module dmd.statement;
+
+import core.stdc.stdarg;
+import core.stdc.stdio;
+
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.ast_node;
+import dmd.gluelayer;
+import dmd.canthrow;
+import dmd.cond;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dimport;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.func;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.dinterpret;
+import dmd.mtype;
+import dmd.root.outbuffer;
+import dmd.root.rootobject;
+import dmd.sapply;
+import dmd.sideeffect;
+import dmd.staticassert;
+import dmd.tokens;
+import dmd.visitor;
+
+/**
+ * Returns:
+ * `TypeIdentifier` corresponding to `object.Throwable`
+ */
+TypeIdentifier getThrowable()
+{
+ auto tid = new TypeIdentifier(Loc.initial, Id.empty);
+ tid.addIdent(Id.object);
+ tid.addIdent(Id.Throwable);
+ return tid;
+}
+
+/**
+ * Returns:
+ * TypeIdentifier corresponding to `object.Exception`
+ */
+TypeIdentifier getException()
+{
+ auto tid = new TypeIdentifier(Loc.initial, Id.empty);
+ tid.addIdent(Id.object);
+ tid.addIdent(Id.Exception);
+ return tid;
+}
+
+/***********************************************************
+ * Specification: http://dlang.org/spec/statement.html
+ */
+extern (C++) abstract class Statement : ASTNode
+{
+ const Loc loc;
+ const STMT stmt;
+
+ override final DYNCAST dyncast() const
+ {
+ return DYNCAST.statement;
+ }
+
+ final extern (D) this(const ref Loc loc, STMT stmt)
+ {
+ this.loc = loc;
+ this.stmt = stmt;
+ // If this is an in{} contract scope statement (skip for determining
+ // inlineStatus of a function body for header content)
+ }
+
+ Statement syntaxCopy()
+ {
+ assert(0);
+ }
+
+ /*************************************
+ * Do syntax copy of an array of Statement's.
+ */
+ static Statements* arraySyntaxCopy(Statements* a)
+ {
+ Statements* b = null;
+ if (a)
+ {
+ b = a.copy();
+ foreach (i, s; *a)
+ {
+ (*b)[i] = s ? s.syntaxCopy() : null;
+ }
+ }
+ return b;
+ }
+
+ override final const(char)* toChars() const
+ {
+ HdrGenState hgs;
+ OutBuffer buf;
+ .toCBuffer(this, &buf, &hgs);
+ buf.writeByte(0);
+ return buf.extractSlice().ptr;
+ }
+
+ static if (__VERSION__ < 2092)
+ {
+ final void error(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .verror(loc, format, ap);
+ va_end(ap);
+ }
+
+ final void warning(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .vwarning(loc, format, ap);
+ va_end(ap);
+ }
+
+ final void deprecation(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .vdeprecation(loc, format, ap);
+ va_end(ap);
+ }
+ }
+ else
+ {
+ pragma(printf) final void error(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .verror(loc, format, ap);
+ va_end(ap);
+ }
+
+ pragma(printf) final void warning(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .vwarning(loc, format, ap);
+ va_end(ap);
+ }
+
+ pragma(printf) final void deprecation(const(char)* format, ...)
+ {
+ va_list ap;
+ va_start(ap, format);
+ .vdeprecation(loc, format, ap);
+ va_end(ap);
+ }
+ }
+
+ Statement getRelatedLabeled()
+ {
+ return this;
+ }
+
+ /****************************
+ * Determine if an enclosed `break` would apply to this
+ * statement, such as if it is a loop or switch statement.
+ * Returns:
+ * `true` if it does
+ */
+ bool hasBreak() const pure nothrow
+ {
+ //printf("Statement::hasBreak()\n");
+ return false;
+ }
+
+ /****************************
+ * Determine if an enclosed `continue` would apply to this
+ * statement, such as if it is a loop statement.
+ * Returns:
+ * `true` if it does
+ */
+ bool hasContinue() const pure nothrow
+ {
+ return false;
+ }
+
+ /**********************************
+ * Returns:
+ * `true` if statement uses exception handling
+ */
+ final bool usesEH()
+ {
+ extern (C++) final class UsesEH : StoppableVisitor
+ {
+ alias visit = typeof(super).visit;
+ public:
+ override void visit(Statement s)
+ {
+ }
+
+ override void visit(TryCatchStatement s)
+ {
+ stop = true;
+ }
+
+ override void visit(TryFinallyStatement s)
+ {
+ stop = true;
+ }
+
+ override void visit(ScopeGuardStatement s)
+ {
+ stop = true;
+ }
+
+ override void visit(SynchronizedStatement s)
+ {
+ stop = true;
+ }
+ }
+
+ scope UsesEH ueh = new UsesEH();
+ return walkPostorder(this, ueh);
+ }
+
+ /**********************************
+ * Returns:
+ * `true` if statement 'comes from' somewhere else, like a goto
+ */
+ final bool comeFrom()
+ {
+ extern (C++) final class ComeFrom : StoppableVisitor
+ {
+ alias visit = typeof(super).visit;
+ public:
+ override void visit(Statement s)
+ {
+ }
+
+ override void visit(CaseStatement s)
+ {
+ stop = true;
+ }
+
+ override void visit(DefaultStatement s)
+ {
+ stop = true;
+ }
+
+ override void visit(LabelStatement s)
+ {
+ stop = true;
+ }
+
+ override void visit(AsmStatement s)
+ {
+ stop = true;
+ }
+ }
+
+ scope ComeFrom cf = new ComeFrom();
+ return walkPostorder(this, cf);
+ }
+
+ /**********************************
+ * Returns:
+ * `true` if statement has executable code.
+ */
+ final bool hasCode()
+ {
+ extern (C++) final class HasCode : StoppableVisitor
+ {
+ alias visit = typeof(super).visit;
+ public:
+ override void visit(Statement s)
+ {
+ stop = true;
+ }
+
+ override void visit(ExpStatement s)
+ {
+ if (s.exp !is null)
+ {
+ stop = s.exp.hasCode();
+ }
+ }
+
+ override void visit(CompoundStatement s)
+ {
+ }
+
+ override void visit(ScopeStatement s)
+ {
+ }
+
+ override void visit(ImportStatement s)
+ {
+ }
+ }
+
+ scope HasCode hc = new HasCode();
+ return walkPostorder(this, hc);
+ }
+
+ /*******************************
+ * Find last statement in a sequence of statements.
+ * Returns:
+ * the last statement, or `null` if there isn't one
+ */
+ inout(Statement) last() inout nothrow pure
+ {
+ return this;
+ }
+
+ /**************************
+ * Support Visitor Pattern
+ * Params:
+ * v = visitor
+ */
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+
+ /************************************
+ * Does this statement end with a return statement?
+ *
+ * I.e. is it a single return statement or some compound statement
+ * that unconditionally hits a return statement.
+ * Returns:
+ * return statement it ends with, otherwise null
+ */
+ pure nothrow @nogc
+ inout(ReturnStatement) endsWithReturnStatement() inout { return null; }
+
+ final pure inout nothrow @nogc @safe:
+
+ /********************
+ * A cheaper method of doing downcasting of Statements.
+ * Returns:
+ * the downcast statement if it can be downcasted, otherwise `null`
+ */
+ inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; }
+ inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; }
+ inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; }
+ inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; }
+ inout(ReturnStatement) isReturnStatement() { return stmt == STMT.Return ? cast(typeof(return))this : null; }
+ inout(IfStatement) isIfStatement() { return stmt == STMT.If ? cast(typeof(return))this : null; }
+ inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; }
+ inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; }
+ inout(CaseStatement) isCaseStatement() { return stmt == STMT.Case ? cast(typeof(return))this : null; }
+ inout(DefaultStatement) isDefaultStatement() { return stmt == STMT.Default ? cast(typeof(return))this : null; }
+ inout(LabelStatement) isLabelStatement() { return stmt == STMT.Label ? cast(typeof(return))this : null; }
+ inout(GotoStatement) isGotoStatement() { return stmt == STMT.Goto ? cast(typeof(return))this : null; }
+ inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; }
+ inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; }
+ inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; }
+ inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; }
+ inout(CompileStatement) isCompileStatement() { return stmt == STMT.Compile ? cast(typeof(return))this : null; }
+ inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; }
+ inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; }
+ inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; }
+ inout(ForStatement) isForStatement() { return stmt == STMT.For ? cast(typeof(return))this : null; }
+ inout(ForeachStatement) isForeachStatement() { return stmt == STMT.Foreach ? cast(typeof(return))this : null; }
+ inout(SwitchStatement) isSwitchStatement() { return stmt == STMT.Switch ? cast(typeof(return))this : null; }
+ inout(ContinueStatement) isContinueStatement() { return stmt == STMT.Continue ? cast(typeof(return))this : null; }
+ inout(WithStatement) isWithStatement() { return stmt == STMT.With ? cast(typeof(return))this : null; }
+ inout(TryCatchStatement) isTryCatchStatement() { return stmt == STMT.TryCatch ? cast(typeof(return))this : null; }
+ inout(ThrowStatement) isThrowStatement() { return stmt == STMT.Throw ? cast(typeof(return))this : null; }
+ inout(DebugStatement) isDebugStatement() { return stmt == STMT.Debug ? cast(typeof(return))this : null; }
+ inout(TryFinallyStatement) isTryFinallyStatement() { return stmt == STMT.TryFinally ? cast(typeof(return))this : null; }
+ inout(ScopeGuardStatement) isScopeGuardStatement() { return stmt == STMT.ScopeGuard ? cast(typeof(return))this : null; }
+ inout(SwitchErrorStatement) isSwitchErrorStatement() { return stmt == STMT.SwitchError ? cast(typeof(return))this : null; }
+ inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; }
+ inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; }
+ inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; }
+}
+
+/***********************************************************
+ * Any Statement that fails semantic() or has a component that is an ErrorExp or
+ * a TypeError should return an ErrorStatement from semantic().
+ */
+extern (C++) final class ErrorStatement : Statement
+{
+ extern (D) this()
+ {
+ super(Loc.initial, STMT.Error);
+ assert(global.gaggedErrors || global.errors);
+ }
+
+ override ErrorStatement syntaxCopy()
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class PeelStatement : Statement
+{
+ Statement s;
+
+ extern (D) this(Statement s)
+ {
+ super(s.loc, STMT.Peel);
+ this.s = s;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#ExpressionStatement
+ */
+extern (C++) class ExpStatement : Statement
+{
+ Expression exp;
+
+ final extern (D) this(const ref Loc loc, Expression exp)
+ {
+ super(loc, STMT.Exp);
+ this.exp = exp;
+ }
+
+ final extern (D) this(const ref Loc loc, Expression exp, STMT stmt)
+ {
+ super(loc, stmt);
+ this.exp = exp;
+ }
+
+ final extern (D) this(const ref Loc loc, Dsymbol declaration)
+ {
+ super(loc, STMT.Exp);
+ this.exp = new DeclarationExp(loc, declaration);
+ }
+
+ static ExpStatement create(Loc loc, Expression exp)
+ {
+ return new ExpStatement(loc, exp);
+ }
+
+ override ExpStatement syntaxCopy()
+ {
+ return new ExpStatement(loc, exp ? exp.syntaxCopy() : null);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DtorExpStatement : ExpStatement
+{
+ // Wraps an expression that is the destruction of 'var'
+ VarDeclaration var;
+
+ extern (D) this(const ref Loc loc, Expression exp, VarDeclaration var)
+ {
+ super(loc, exp, STMT.DtorExp);
+ this.var = var;
+ }
+
+ override DtorExpStatement syntaxCopy()
+ {
+ return new DtorExpStatement(loc, exp ? exp.syntaxCopy() : null, var);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#mixin-statement
+ */
+extern (C++) final class CompileStatement : Statement
+{
+ Expressions* exps;
+
+ extern (D) this(const ref Loc loc, Expression exp)
+ {
+ Expressions* exps = new Expressions();
+ exps.push(exp);
+ this(loc, exps);
+ }
+
+ extern (D) this(const ref Loc loc, Expressions* exps)
+ {
+ super(loc, STMT.Compile);
+ this.exps = exps;
+ }
+
+ override CompileStatement syntaxCopy()
+ {
+ return new CompileStatement(loc, Expression.arraySyntaxCopy(exps));
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) class CompoundStatement : Statement
+{
+ Statements* statements;
+
+ /**
+ * Construct a `CompoundStatement` using an already existing
+ * array of `Statement`s
+ *
+ * Params:
+ * loc = Instantiation information
+ * statements = An array of `Statement`s, that will referenced by this class
+ */
+ final extern (D) this(const ref Loc loc, Statements* statements)
+ {
+ super(loc, STMT.Compound);
+ this.statements = statements;
+ }
+
+ final extern (D) this(const ref Loc loc, Statements* statements, STMT stmt)
+ {
+ super(loc, stmt);
+ this.statements = statements;
+ }
+
+ /**
+ * Construct a `CompoundStatement` from an array of `Statement`s
+ *
+ * Params:
+ * loc = Instantiation information
+ * sts = A variadic array of `Statement`s, that will copied in this class
+ * The entries themselves will not be copied.
+ */
+ final extern (D) this(const ref Loc loc, Statement[] sts...)
+ {
+ super(loc, STMT.Compound);
+ statements = new Statements();
+ statements.reserve(sts.length);
+ foreach (s; sts)
+ statements.push(s);
+ }
+
+ static CompoundStatement create(Loc loc, Statement s1, Statement s2)
+ {
+ return new CompoundStatement(loc, s1, s2);
+ }
+
+ override CompoundStatement syntaxCopy()
+ {
+ return new CompoundStatement(loc, Statement.arraySyntaxCopy(statements));
+ }
+
+ override final inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure
+ {
+ foreach (s; *statements)
+ {
+ if (s)
+ {
+ if (inout rs = s.endsWithReturnStatement())
+ return rs;
+ }
+ }
+ return null;
+ }
+
+ override final inout(Statement) last() inout nothrow pure
+ {
+ Statement s = null;
+ for (size_t i = statements.dim; i; --i)
+ {
+ s = cast(Statement)(*statements)[i - 1];
+ if (s)
+ {
+ s = cast(Statement)s.last();
+ if (s)
+ break;
+ }
+ }
+ return cast(inout)s;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class CompoundDeclarationStatement : CompoundStatement
+{
+ extern (D) this(const ref Loc loc, Statements* statements)
+ {
+ super(loc, statements, STMT.CompoundDeclaration);
+ }
+
+ override CompoundDeclarationStatement syntaxCopy()
+ {
+ auto a = new Statements(statements.dim);
+ foreach (i, s; *statements)
+ {
+ (*a)[i] = s ? s.syntaxCopy() : null;
+ }
+ return new CompoundDeclarationStatement(loc, a);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * The purpose of this is so that continue will go to the next
+ * of the statements, and break will go to the end of the statements.
+ */
+extern (C++) final class UnrolledLoopStatement : Statement
+{
+ Statements* statements;
+
+ extern (D) this(const ref Loc loc, Statements* statements)
+ {
+ super(loc, STMT.UnrolledLoop);
+ this.statements = statements;
+ }
+
+ override UnrolledLoopStatement syntaxCopy()
+ {
+ auto a = new Statements(statements.dim);
+ foreach (i, s; *statements)
+ {
+ (*a)[i] = s ? s.syntaxCopy() : null;
+ }
+ return new UnrolledLoopStatement(loc, a);
+ }
+
+ override bool hasBreak() const pure nothrow
+ {
+ return true;
+ }
+
+ override bool hasContinue() const pure nothrow
+ {
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) class ScopeStatement : Statement
+{
+ Statement statement;
+ Loc endloc; // location of closing curly bracket
+
+ extern (D) this(const ref Loc loc, Statement statement, Loc endloc)
+ {
+ super(loc, STMT.Scope);
+ this.statement = statement;
+ this.endloc = endloc;
+ }
+
+ override ScopeStatement syntaxCopy()
+ {
+ return new ScopeStatement(loc, statement ? statement.syntaxCopy() : null, endloc);
+ }
+
+ override inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure
+ {
+ if (statement)
+ return statement.endsWithReturnStatement();
+ return null;
+ }
+
+ override bool hasBreak() const pure nothrow
+ {
+ //printf("ScopeStatement::hasBreak() %s\n", toChars());
+ return statement ? statement.hasBreak() : false;
+ }
+
+ override bool hasContinue() const pure nothrow
+ {
+ return statement ? statement.hasContinue() : false;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * Statement whose symbol table contains foreach index variables in a
+ * local scope and forwards other members to the parent scope. This
+ * wraps a statement.
+ *
+ * Also see: `dmd.attrib.ForwardingAttribDeclaration`
+ */
+extern (C++) final class ForwardingStatement : Statement
+{
+ /// The symbol containing the `static foreach` variables.
+ ForwardingScopeDsymbol sym = null;
+ /// The wrapped statement.
+ Statement statement;
+
+ extern (D) this(const ref Loc loc, ForwardingScopeDsymbol sym, Statement statement)
+ {
+ super(loc, STMT.Forwarding);
+ this.sym = sym;
+ assert(statement);
+ this.statement = statement;
+ }
+
+ extern (D) this(const ref Loc loc, Statement statement)
+ {
+ auto sym = new ForwardingScopeDsymbol(null);
+ sym.symtab = new DsymbolTable();
+ this(loc, sym, statement);
+ }
+
+ override ForwardingStatement syntaxCopy()
+ {
+ return new ForwardingStatement(loc, statement.syntaxCopy());
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#while-statement
+ */
+extern (C++) final class WhileStatement : Statement
+{
+ Parameter param;
+ Expression condition;
+ Statement _body;
+ Loc endloc; // location of closing curly bracket
+
+ extern (D) this(const ref Loc loc, Expression condition, Statement _body, Loc endloc, Parameter param = null)
+ {
+ super(loc, STMT.While);
+ this.condition = condition;
+ this._body = _body;
+ this.endloc = endloc;
+ this.param = param;
+ }
+
+ override WhileStatement syntaxCopy()
+ {
+ return new WhileStatement(loc,
+ condition.syntaxCopy(),
+ _body ? _body.syntaxCopy() : null,
+ endloc, param ? param.syntaxCopy() : null);
+ }
+
+ override bool hasBreak() const pure nothrow
+ {
+ return true;
+ }
+
+ override bool hasContinue() const pure nothrow
+ {
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#do-statement
+ */
+extern (C++) final class DoStatement : Statement
+{
+ Statement _body;
+ Expression condition;
+ Loc endloc; // location of ';' after while
+
+ extern (D) this(const ref Loc loc, Statement _body, Expression condition, Loc endloc)
+ {
+ super(loc, STMT.Do);
+ this._body = _body;
+ this.condition = condition;
+ this.endloc = endloc;
+ }
+
+ override DoStatement syntaxCopy()
+ {
+ return new DoStatement(loc,
+ _body ? _body.syntaxCopy() : null,
+ condition.syntaxCopy(),
+ endloc);
+ }
+
+ override bool hasBreak() const pure nothrow
+ {
+ return true;
+ }
+
+ override bool hasContinue() const pure nothrow
+ {
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#for-statement
+ */
+extern (C++) final class ForStatement : Statement
+{
+ Statement _init;
+ Expression condition;
+ Expression increment;
+ Statement _body;
+ Loc endloc; // location of closing curly bracket
+
+ // When wrapped in try/finally clauses, this points to the outermost one,
+ // which may have an associated label. Internal break/continue statements
+ // treat that label as referring to this loop.
+ Statement relatedLabeled;
+
+ extern (D) this(const ref Loc loc, Statement _init, Expression condition, Expression increment, Statement _body, Loc endloc)
+ {
+ super(loc, STMT.For);
+ this._init = _init;
+ this.condition = condition;
+ this.increment = increment;
+ this._body = _body;
+ this.endloc = endloc;
+ }
+
+ override ForStatement syntaxCopy()
+ {
+ return new ForStatement(loc,
+ _init ? _init.syntaxCopy() : null,
+ condition ? condition.syntaxCopy() : null,
+ increment ? increment.syntaxCopy() : null,
+ _body.syntaxCopy(),
+ endloc);
+ }
+
+ override Statement getRelatedLabeled()
+ {
+ return relatedLabeled ? relatedLabeled : this;
+ }
+
+ override bool hasBreak() const pure nothrow
+ {
+ //printf("ForStatement::hasBreak()\n");
+ return true;
+ }
+
+ override bool hasContinue() const pure nothrow
+ {
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#foreach-statement
+ */
+extern (C++) final class ForeachStatement : Statement
+{
+ TOK op; // TOK.foreach_ or TOK.foreach_reverse_
+ Parameters* parameters; // array of Parameters, one for each ForeachType
+ Expression aggr; // ForeachAggregate
+ Statement _body; // NoScopeNonEmptyStatement
+ Loc endloc; // location of closing curly bracket
+
+ VarDeclaration key;
+ VarDeclaration value;
+
+ FuncDeclaration func; // function we're lexically in
+
+ Statements* cases; // put breaks, continues, gotos and returns here
+ ScopeStatements* gotos; // forward referenced goto's go here
+
+ extern (D) this(const ref Loc loc, TOK op, Parameters* parameters, Expression aggr, Statement _body, Loc endloc)
+ {
+ super(loc, STMT.Foreach);
+ this.op = op;
+ this.parameters = parameters;
+ this.aggr = aggr;
+ this._body = _body;
+ this.endloc = endloc;
+ }
+
+ override ForeachStatement syntaxCopy()
+ {
+ return new ForeachStatement(loc, op,
+ Parameter.arraySyntaxCopy(parameters),
+ aggr.syntaxCopy(),
+ _body ? _body.syntaxCopy() : null,
+ endloc);
+ }
+
+ override bool hasBreak() const pure nothrow
+ {
+ return true;
+ }
+
+ override bool hasContinue() const pure nothrow
+ {
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#foreach-range-statement
+ */
+extern (C++) final class ForeachRangeStatement : Statement
+{
+ TOK op; // TOK.foreach_ or TOK.foreach_reverse_
+ Parameter prm; // loop index variable
+ Expression lwr;
+ Expression upr;
+ Statement _body;
+ Loc endloc; // location of closing curly bracket
+
+ VarDeclaration key;
+
+ extern (D) this(const ref Loc loc, TOK op, Parameter prm, Expression lwr, Expression upr, Statement _body, Loc endloc)
+ {
+ super(loc, STMT.ForeachRange);
+ this.op = op;
+ this.prm = prm;
+ this.lwr = lwr;
+ this.upr = upr;
+ this._body = _body;
+ this.endloc = endloc;
+ }
+
+ override ForeachRangeStatement syntaxCopy()
+ {
+ return new ForeachRangeStatement(loc, op, prm.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc);
+ }
+
+ override bool hasBreak() const pure nothrow
+ {
+ return true;
+ }
+
+ override bool hasContinue() const pure nothrow
+ {
+ return true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#if-statement
+ */
+extern (C++) final class IfStatement : Statement
+{
+ Parameter prm;
+ Expression condition;
+ Statement ifbody;
+ Statement elsebody;
+ VarDeclaration match; // for MatchExpression results
+ Loc endloc; // location of closing curly bracket
+
+ extern (D) this(const ref Loc loc, Parameter prm, Expression condition, Statement ifbody, Statement elsebody, Loc endloc)
+ {
+ super(loc, STMT.If);
+ this.prm = prm;
+ this.condition = condition;
+ this.ifbody = ifbody;
+ this.elsebody = elsebody;
+ this.endloc = endloc;
+ }
+
+ override IfStatement syntaxCopy()
+ {
+ return new IfStatement(loc,
+ prm ? prm.syntaxCopy() : null,
+ condition.syntaxCopy(),
+ ifbody ? ifbody.syntaxCopy() : null,
+ elsebody ? elsebody.syntaxCopy() : null,
+ endloc);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/version.html#ConditionalStatement
+ */
+extern (C++) final class ConditionalStatement : Statement
+{
+ Condition condition;
+ Statement ifbody;
+ Statement elsebody;
+
+ extern (D) this(const ref Loc loc, Condition condition, Statement ifbody, Statement elsebody)
+ {
+ super(loc, STMT.Conditional);
+ this.condition = condition;
+ this.ifbody = ifbody;
+ this.elsebody = elsebody;
+ }
+
+ override ConditionalStatement syntaxCopy()
+ {
+ return new ConditionalStatement(loc, condition.syntaxCopy(), ifbody.syntaxCopy(), elsebody ? elsebody.syntaxCopy() : null);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+
+/***********************************************************
+ * https://dlang.org/spec/version.html#StaticForeachStatement
+ * Static foreach statements, like:
+ * void main()
+ * {
+ * static foreach(i; 0 .. 10)
+ * {
+ * pragma(msg, i);
+ * }
+ * }
+ */
+extern (C++) final class StaticForeachStatement : Statement
+{
+ StaticForeach sfe;
+
+ extern (D) this(const ref Loc loc, StaticForeach sfe)
+ {
+ super(loc, STMT.StaticForeach);
+ this.sfe = sfe;
+ }
+
+ override StaticForeachStatement syntaxCopy()
+ {
+ return new StaticForeachStatement(loc, sfe.syntaxCopy());
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#pragma-statement
+ */
+extern (C++) final class PragmaStatement : Statement
+{
+ const Identifier ident;
+ Expressions* args; // array of Expression's
+ Statement _body;
+
+ extern (D) this(const ref Loc loc, const Identifier ident, Expressions* args, Statement _body)
+ {
+ super(loc, STMT.Pragma);
+ this.ident = ident;
+ this.args = args;
+ this._body = _body;
+ }
+
+ override PragmaStatement syntaxCopy()
+ {
+ return new PragmaStatement(loc, ident, Expression.arraySyntaxCopy(args), _body ? _body.syntaxCopy() : null);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/version.html#StaticAssert
+ */
+extern (C++) final class StaticAssertStatement : Statement
+{
+ StaticAssert sa;
+
+ extern (D) this(StaticAssert sa)
+ {
+ super(sa.loc, STMT.StaticAssert);
+ this.sa = sa;
+ }
+
+ override StaticAssertStatement syntaxCopy()
+ {
+ return new StaticAssertStatement(sa.syntaxCopy(null));
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#switch-statement
+ */
+extern (C++) final class SwitchStatement : Statement
+{
+ Expression condition; /// switch(condition)
+ Statement _body; ///
+ bool isFinal; /// https://dlang.org/spec/statement.html#final-switch-statement
+
+ DefaultStatement sdefault; /// default:
+ Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion
+ TryFinallyStatement tf; /// set if in the 'finally' block of a TryFinallyStatement
+ GotoCaseStatements gotoCases; /// array of unresolved GotoCaseStatement's
+ CaseStatements* cases; /// array of CaseStatement's
+ int hasNoDefault; /// !=0 if no default statement
+ int hasVars; /// !=0 if has variable case values
+ VarDeclaration lastVar; /// last observed variable declaration in this statement
+
+ extern (D) this(const ref Loc loc, Expression condition, Statement _body, bool isFinal)
+ {
+ super(loc, STMT.Switch);
+ this.condition = condition;
+ this._body = _body;
+ this.isFinal = isFinal;
+ }
+
+ override SwitchStatement syntaxCopy()
+ {
+ return new SwitchStatement(loc, condition.syntaxCopy(), _body.syntaxCopy(), isFinal);
+ }
+
+ override bool hasBreak() const pure nothrow
+ {
+ return true;
+ }
+
+ /************************************
+ * Returns:
+ * true if error
+ */
+ extern (D) bool checkLabel()
+ {
+ /*
+ * Checks the scope of a label for existing variable declaration.
+ * Params:
+ * vd = last variable declared before this case/default label
+ * Returns: `true` if the variables declared in this label would be skipped.
+ */
+ bool checkVar(VarDeclaration vd)
+ {
+ for (auto v = vd; v && v != lastVar; v = v.lastVar)
+ {
+ if (v.isDataseg() || (v.storage_class & (STC.manifest | STC.temp) && vd.ident != Id.withSym) || v._init.isVoidInitializer())
+ continue;
+ if (vd.ident == Id.withSym)
+ error("`switch` skips declaration of `with` temporary at %s", v.loc.toChars());
+ else
+ error("`switch` skips declaration of variable `%s` at %s", v.toPrettyChars(), v.loc.toChars());
+ return true;
+ }
+ return false;
+ }
+
+ enum error = true;
+
+ if (sdefault && checkVar(sdefault.lastVar))
+ return !error; // return error once fully deprecated
+
+ foreach (scase; *cases)
+ {
+ if (scase && checkVar(scase.lastVar))
+ return !error; // return error once fully deprecated
+ }
+ return !error;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#CaseStatement
+ */
+extern (C++) final class CaseStatement : Statement
+{
+ Expression exp;
+ Statement statement;
+
+ int index; // which case it is (since we sort this)
+ VarDeclaration lastVar;
+ void* extra; // for use by Statement_toIR()
+
+ extern (D) this(const ref Loc loc, Expression exp, Statement statement)
+ {
+ super(loc, STMT.Case);
+ this.exp = exp;
+ this.statement = statement;
+ }
+
+ override CaseStatement syntaxCopy()
+ {
+ return new CaseStatement(loc, exp.syntaxCopy(), statement.syntaxCopy());
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#CaseRangeStatement
+ */
+extern (C++) final class CaseRangeStatement : Statement
+{
+ Expression first;
+ Expression last;
+ Statement statement;
+
+ extern (D) this(const ref Loc loc, Expression first, Expression last, Statement statement)
+ {
+ super(loc, STMT.CaseRange);
+ this.first = first;
+ this.last = last;
+ this.statement = statement;
+ }
+
+ override CaseRangeStatement syntaxCopy()
+ {
+ return new CaseRangeStatement(loc, first.syntaxCopy(), last.syntaxCopy(), statement.syntaxCopy());
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#DefaultStatement
+ */
+extern (C++) final class DefaultStatement : Statement
+{
+ Statement statement;
+
+ VarDeclaration lastVar;
+
+ extern (D) this(const ref Loc loc, Statement statement)
+ {
+ super(loc, STMT.Default);
+ this.statement = statement;
+ }
+
+ override DefaultStatement syntaxCopy()
+ {
+ return new DefaultStatement(loc, statement.syntaxCopy());
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#GotoStatement
+ */
+extern (C++) final class GotoDefaultStatement : Statement
+{
+ SwitchStatement sw;
+
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, STMT.GotoDefault);
+ }
+
+ override GotoDefaultStatement syntaxCopy()
+ {
+ return new GotoDefaultStatement(loc);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#GotoStatement
+ */
+extern (C++) final class GotoCaseStatement : Statement
+{
+ Expression exp; // null, or which case to goto
+
+ CaseStatement cs; // case statement it resolves to
+
+ extern (D) this(const ref Loc loc, Expression exp)
+ {
+ super(loc, STMT.GotoCase);
+ this.exp = exp;
+ }
+
+ override GotoCaseStatement syntaxCopy()
+ {
+ return new GotoCaseStatement(loc, exp ? exp.syntaxCopy() : null);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class SwitchErrorStatement : Statement
+{
+ Expression exp;
+
+ extern (D) this(const ref Loc loc)
+ {
+ super(loc, STMT.SwitchError);
+ }
+
+ final extern (D) this(const ref Loc loc, Expression exp)
+ {
+ super(loc, STMT.SwitchError);
+ this.exp = exp;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#return-statement
+ */
+extern (C++) final class ReturnStatement : Statement
+{
+ Expression exp;
+ size_t caseDim;
+
+ extern (D) this(const ref Loc loc, Expression exp)
+ {
+ super(loc, STMT.Return);
+ this.exp = exp;
+ }
+
+ override ReturnStatement syntaxCopy()
+ {
+ return new ReturnStatement(loc, exp ? exp.syntaxCopy() : null);
+ }
+
+ override inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#break-statement
+ */
+extern (C++) final class BreakStatement : Statement
+{
+ Identifier ident;
+
+ extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ super(loc, STMT.Break);
+ this.ident = ident;
+ }
+
+ override BreakStatement syntaxCopy()
+ {
+ return new BreakStatement(loc, ident);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#continue-statement
+ */
+extern (C++) final class ContinueStatement : Statement
+{
+ Identifier ident;
+
+ extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ super(loc, STMT.Continue);
+ this.ident = ident;
+ }
+
+ override ContinueStatement syntaxCopy()
+ {
+ return new ContinueStatement(loc, ident);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#SynchronizedStatement
+ */
+extern (C++) final class SynchronizedStatement : Statement
+{
+ Expression exp;
+ Statement _body;
+
+ extern (D) this(const ref Loc loc, Expression exp, Statement _body)
+ {
+ super(loc, STMT.Synchronized);
+ this.exp = exp;
+ this._body = _body;
+ }
+
+ override SynchronizedStatement syntaxCopy()
+ {
+ return new SynchronizedStatement(loc, exp ? exp.syntaxCopy() : null, _body ? _body.syntaxCopy() : null);
+ }
+
+ override bool hasBreak() const pure nothrow
+ {
+ return false; //true;
+ }
+
+ override bool hasContinue() const pure nothrow
+ {
+ return false; //true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#with-statement
+ */
+extern (C++) final class WithStatement : Statement
+{
+ Expression exp;
+ Statement _body;
+ VarDeclaration wthis;
+ Loc endloc;
+
+ extern (D) this(const ref Loc loc, Expression exp, Statement _body, Loc endloc)
+ {
+ super(loc, STMT.With);
+ this.exp = exp;
+ this._body = _body;
+ this.endloc = endloc;
+ }
+
+ override WithStatement syntaxCopy()
+ {
+ return new WithStatement(loc, exp.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#try-statement
+ */
+extern (C++) final class TryCatchStatement : Statement
+{
+ Statement _body;
+ Catches* catches;
+
+ Statement tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
+
+ extern (D) this(const ref Loc loc, Statement _body, Catches* catches)
+ {
+ super(loc, STMT.TryCatch);
+ this._body = _body;
+ this.catches = catches;
+ }
+
+ override TryCatchStatement syntaxCopy()
+ {
+ auto a = new Catches(catches.dim);
+ foreach (i, c; *catches)
+ {
+ (*a)[i] = c.syntaxCopy();
+ }
+ return new TryCatchStatement(loc, _body.syntaxCopy(), a);
+ }
+
+ override bool hasBreak() const pure nothrow
+ {
+ return false;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#Catch
+ */
+extern (C++) final class Catch : RootObject
+{
+ const Loc loc;
+ Type type;
+ Identifier ident;
+ Statement handler;
+
+ VarDeclaration var;
+ bool errors; // set if semantic processing errors
+
+ // was generated by the compiler, wasn't present in source code
+ bool internalCatch;
+
+ extern (D) this(const ref Loc loc, Type type, Identifier ident, Statement handler)
+ {
+ //printf("Catch(%s, loc = %s)\n", id.toChars(), loc.toChars());
+ this.loc = loc;
+ this.type = type;
+ this.ident = ident;
+ this.handler = handler;
+ }
+
+ Catch syntaxCopy()
+ {
+ auto c = new Catch(loc, type ? type.syntaxCopy() : getThrowable(), ident, (handler ? handler.syntaxCopy() : null));
+ c.internalCatch = internalCatch;
+ return c;
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#try-statement
+ */
+extern (C++) final class TryFinallyStatement : Statement
+{
+ Statement _body;
+ Statement finalbody;
+
+ Statement tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
+ bool bodyFallsThru; /// true if _body falls through to finally
+
+ extern (D) this(const ref Loc loc, Statement _body, Statement finalbody)
+ {
+ super(loc, STMT.TryFinally);
+ this._body = _body;
+ this.finalbody = finalbody;
+ this.bodyFallsThru = true; // assume true until statementSemantic()
+ }
+
+ static TryFinallyStatement create(Loc loc, Statement _body, Statement finalbody)
+ {
+ return new TryFinallyStatement(loc, _body, finalbody);
+ }
+
+ override TryFinallyStatement syntaxCopy()
+ {
+ return new TryFinallyStatement(loc, _body.syntaxCopy(), finalbody.syntaxCopy());
+ }
+
+ override bool hasBreak() const pure nothrow
+ {
+ return false; //true;
+ }
+
+ override bool hasContinue() const pure nothrow
+ {
+ return false; //true;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#scope-guard-statement
+ */
+extern (C++) final class ScopeGuardStatement : Statement
+{
+ TOK tok;
+ Statement statement;
+
+ extern (D) this(const ref Loc loc, TOK tok, Statement statement)
+ {
+ super(loc, STMT.ScopeGuard);
+ this.tok = tok;
+ this.statement = statement;
+ }
+
+ override ScopeGuardStatement syntaxCopy()
+ {
+ return new ScopeGuardStatement(loc, tok, statement.syntaxCopy());
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#throw-statement
+ */
+extern (C++) final class ThrowStatement : Statement
+{
+ Expression exp;
+
+ // was generated by the compiler, wasn't present in source code
+ bool internalThrow;
+
+ extern (D) this(const ref Loc loc, Expression exp)
+ {
+ super(loc, STMT.Throw);
+ this.exp = exp;
+ }
+
+ override ThrowStatement syntaxCopy()
+ {
+ auto s = new ThrowStatement(loc, exp.syntaxCopy());
+ s.internalThrow = internalThrow;
+ return s;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class DebugStatement : Statement
+{
+ Statement statement;
+
+ extern (D) this(const ref Loc loc, Statement statement)
+ {
+ super(loc, STMT.Debug);
+ this.statement = statement;
+ }
+
+ override DebugStatement syntaxCopy()
+ {
+ return new DebugStatement(loc, statement ? statement.syntaxCopy() : null);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#goto-statement
+ */
+extern (C++) final class GotoStatement : Statement
+{
+ Identifier ident;
+ LabelDsymbol label;
+ Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion
+ TryFinallyStatement tf;
+ ScopeGuardStatement os;
+ VarDeclaration lastVar;
+
+ extern (D) this(const ref Loc loc, Identifier ident)
+ {
+ super(loc, STMT.Goto);
+ this.ident = ident;
+ }
+
+ override GotoStatement syntaxCopy()
+ {
+ return new GotoStatement(loc, ident);
+ }
+
+ extern (D) bool checkLabel()
+ {
+ if (!label.statement)
+ return true; // error should have been issued for this already
+
+ if (label.statement.os != os)
+ {
+ if (os && os.tok == TOK.onScopeFailure && !label.statement.os)
+ {
+ // Jump out from scope(failure) block is allowed.
+ }
+ else
+ {
+ if (label.statement.os)
+ error("cannot `goto` in to `%s` block", Token.toChars(label.statement.os.tok));
+ else
+ error("cannot `goto` out of `%s` block", Token.toChars(os.tok));
+ return true;
+ }
+ }
+
+ if (label.statement.tf != tf)
+ {
+ error("cannot `goto` in or out of `finally` block");
+ return true;
+ }
+
+ Statement stbnext;
+ for (auto stb = tryBody; stb != label.statement.tryBody; stb = stbnext)
+ {
+ if (!stb)
+ {
+ error("cannot `goto` into `try` block");
+ return true;
+ }
+ if (auto stf = stb.isTryFinallyStatement())
+ stbnext = stf.tryBody;
+ else if (auto stc = stb.isTryCatchStatement())
+ stbnext = stc.tryBody;
+ else
+ assert(0);
+ }
+
+ VarDeclaration vd = label.statement.lastVar;
+ if (!vd || vd.isDataseg() || (vd.storage_class & STC.manifest))
+ return false;
+
+ VarDeclaration last = lastVar;
+ while (last && last != vd)
+ last = last.lastVar;
+ if (last == vd)
+ {
+ // All good, the label's scope has no variables
+ }
+ else if (vd.storage_class & STC.exptemp)
+ {
+ // Lifetime ends at end of expression, so no issue with skipping the statement
+ }
+ else if (vd.ident == Id.withSym)
+ {
+ error("`goto` skips declaration of `with` temporary at %s", vd.loc.toChars());
+ return true;
+ }
+ else
+ {
+ error("`goto` skips declaration of variable `%s` at %s", vd.toPrettyChars(), vd.loc.toChars());
+ return true;
+ }
+
+ return false;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#LabeledStatement
+ */
+extern (C++) final class LabelStatement : Statement
+{
+ Identifier ident;
+ Statement statement;
+
+ Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion
+ TryFinallyStatement tf;
+ ScopeGuardStatement os;
+ VarDeclaration lastVar;
+ Statement gotoTarget; // interpret
+ void* extra; // used by Statement_toIR()
+ bool breaks; // someone did a 'break ident'
+
+ extern (D) this(const ref Loc loc, Identifier ident, Statement statement)
+ {
+ super(loc, STMT.Label);
+ this.ident = ident;
+ this.statement = statement;
+ }
+
+ override LabelStatement syntaxCopy()
+ {
+ return new LabelStatement(loc, ident, statement ? statement.syntaxCopy() : null);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ */
+extern (C++) final class LabelDsymbol : Dsymbol
+{
+ LabelStatement statement;
+
+ bool deleted; // set if rewritten to return in foreach delegate
+ bool iasm; // set if used by inline assembler
+
+ extern (D) this(Identifier ident, const ref Loc loc = Loc.initial)
+ {
+ super(loc, ident);
+ }
+
+ static LabelDsymbol create(Identifier ident)
+ {
+ return new LabelDsymbol(ident);
+ }
+
+ // is this a LabelDsymbol()?
+ override LabelDsymbol isLabel()
+ {
+ return this;
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/statement.html#asm
+ */
+extern (C++) class AsmStatement : Statement
+{
+ Token* tokens;
+
+ extern (D) this(const ref Loc loc, Token* tokens)
+ {
+ super(loc, STMT.Asm);
+ this.tokens = tokens;
+ }
+
+ extern (D) this(const ref Loc loc, Token* tokens, STMT stmt)
+ {
+ super(loc, stmt);
+ this.tokens = tokens;
+ }
+
+ override AsmStatement syntaxCopy()
+ {
+ return new AsmStatement(loc, tokens);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/iasm.html
+ */
+extern (C++) final class InlineAsmStatement : AsmStatement
+{
+ code* asmcode;
+ uint asmalign; // alignment of this statement
+ uint regs; // mask of registers modified (must match regm_t in back end)
+ bool refparam; // true if function parameter is referenced
+ bool naked; // true if function is to be naked
+
+ extern (D) this(const ref Loc loc, Token* tokens)
+ {
+ super(loc, tokens, STMT.InlineAsm);
+ }
+
+ override InlineAsmStatement syntaxCopy()
+ {
+ return new InlineAsmStatement(loc, tokens);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
+ * Assembler instructions with D expression operands.
+ */
+extern (C++) final class GccAsmStatement : AsmStatement
+{
+ StorageClass stc; // attributes of the asm {} block
+ Expression insn; // string expression that is the template for assembler code
+ Expressions* args; // input and output operands of the statement
+ uint outputargs; // of the operands in 'args', the number of output operands
+ Identifiers* names; // list of symbolic names for the operands
+ Expressions* constraints; // list of string constants specifying constraints on operands
+ Expressions* clobbers; // list of string constants specifying clobbers and scratch registers
+ Identifiers* labels; // list of goto labels
+ GotoStatements* gotos; // of the goto labels, the equivalent statements they represent
+
+ extern (D) this(const ref Loc loc, Token* tokens)
+ {
+ super(loc, tokens, STMT.GccAsm);
+ }
+
+ override GccAsmStatement syntaxCopy()
+ {
+ return new GccAsmStatement(loc, tokens);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * a complete asm {} block
+ */
+extern (C++) final class CompoundAsmStatement : CompoundStatement
+{
+ StorageClass stc; // postfix attributes like nothrow/pure/@trusted
+
+ extern (D) this(const ref Loc loc, Statements* statements, StorageClass stc)
+ {
+ super(loc, statements, STMT.CompoundAsm);
+ this.stc = stc;
+ }
+
+ override CompoundAsmStatement syntaxCopy()
+ {
+ auto a = new Statements(statements.dim);
+ foreach (i, s; *statements)
+ {
+ (*a)[i] = s ? s.syntaxCopy() : null;
+ }
+ return new CompoundAsmStatement(loc, a, stc);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
+
+/***********************************************************
+ * https://dlang.org/spec/module.html#ImportDeclaration
+ */
+extern (C++) final class ImportStatement : Statement
+{
+ Dsymbols* imports; // Array of Import's
+
+ extern (D) this(const ref Loc loc, Dsymbols* imports)
+ {
+ super(loc, STMT.Import);
+ this.imports = imports;
+ }
+
+ override ImportStatement syntaxCopy()
+ {
+ auto m = new Dsymbols(imports.dim);
+ foreach (i, s; *imports)
+ {
+ (*m)[i] = s.syntaxCopy(null);
+ }
+ return new ImportStatement(loc, m);
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index c64e51a..7825762 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -10,27 +10,21 @@
#pragma once
-#include "root/root.h"
-
#include "arraytypes.h"
#include "ast_node.h"
#include "dsymbol.h"
#include "visitor.h"
#include "tokens.h"
-struct OutBuffer;
struct Scope;
class Expression;
class LabelDsymbol;
class Identifier;
-class Statement;
class IfStatement;
class ExpStatement;
class DefaultStatement;
class VarDeclaration;
class Condition;
-class Module;
-struct Token;
class ErrorStatement;
class ReturnStatement;
class CompoundStatement;
@@ -39,7 +33,6 @@ class StaticAssert;
class AsmStatement;
class GotoStatement;
class ScopeStatement;
-class Catch;
class TryCatchStatement;
class TryFinallyStatement;
class CaseStatement;
@@ -50,14 +43,6 @@ class StaticForeach;
// Back end
struct code;
-Statement *statementSemantic(Statement *s, Scope *sc);
-Statement *semanticNoScope(Statement *s, Scope *sc);
-Statement *semanticScope(Statement *s, Scope *sc, Statement *sbreak, Statement *scontinue);
-void catchSemantic(Catch *c, Scope *sc);
-
-bool inferAggregate(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply);
-bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply);
-
/* How a statement exits; this is returned by blockExit()
*/
enum BE
@@ -74,46 +59,106 @@ enum BE
BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt)
};
+typedef unsigned char STMT;
+enum
+{
+ STMTerror,
+ STMTpeel,
+ STMTexp, STMTdtorExp,
+ STMTcompile,
+ STMTcompound, STMTcompoundDeclaration, STMTcompoundAsm,
+ STMTunrolledLoop,
+ STMTscope,
+ STMTforwarding,
+ STMTwhile,
+ STMTdo,
+ STMTfor,
+ STMTforeach,
+ STMTforeachRange,
+ STMTif,
+ STMTconditional,
+ STMTstaticForeach,
+ STMTpragma,
+ STMTstaticAssert,
+ STMTswitch,
+ STMTcase,
+ STMTcaseRange,
+ STMTdefault,
+ STMTgotoDefault,
+ STMTgotoCase,
+ STMTswitchError,
+ STMTreturn,
+ STMTbreak,
+ STMTcontinue,
+ STMTsynchronized,
+ STMTwith,
+ STMTtryCatch,
+ STMTtryFinally,
+ STMTscopeGuard,
+ STMTthrow,
+ STMTdebug,
+ STMTgoto,
+ STMTlabel,
+ STMTasm, STMTinlineAsm, STMTgccAsm,
+ STMTimport
+};
+
class Statement : public ASTNode
{
public:
Loc loc;
+ STMT stmt;
- Statement(Loc loc);
virtual Statement *syntaxCopy();
- static Statements *arraySyntaxCopy(Statements *a);
- void print();
- const char *toChars();
+ const char *toChars() const;
void error(const char *format, ...);
void warning(const char *format, ...);
void deprecation(const char *format, ...);
virtual Statement *getRelatedLabeled() { return this; }
- virtual bool hasBreak();
- virtual bool hasContinue();
+ virtual bool hasBreak() const;
+ virtual bool hasContinue() const;
bool usesEH();
bool comeFrom();
bool hasCode();
- virtual Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
- virtual Statements *flatten(Scope *sc);
virtual Statement *last();
- // Avoid dynamic_cast
- virtual ErrorStatement *isErrorStatement() { return NULL; }
- virtual ScopeStatement *isScopeStatement() { return NULL; }
- virtual ExpStatement *isExpStatement() { return NULL; }
- virtual CompoundStatement *isCompoundStatement() { return NULL; }
- virtual ReturnStatement *isReturnStatement() { return NULL; }
- virtual IfStatement *isIfStatement() { return NULL; }
- virtual CaseStatement *isCaseStatement() { return NULL; }
- virtual DefaultStatement *isDefaultStatement() { return NULL; }
- virtual LabelStatement *isLabelStatement() { return NULL; }
- virtual GotoDefaultStatement *isGotoDefaultStatement() { return NULL; }
- virtual GotoCaseStatement *isGotoCaseStatement() { return NULL; }
- virtual BreakStatement *isBreakStatement() { return NULL; }
- virtual DtorExpStatement *isDtorExpStatement() { return NULL; }
- virtual ForwardingStatement *isForwardingStatement() { return NULL; }
+ virtual ReturnStatement *endsWithReturnStatement() { return NULL; }
+
+ ErrorStatement *isErrorStatement() { return stmt == STMTerror ? (ErrorStatement*)this : NULL; }
+ ScopeStatement *isScopeStatement() { return stmt == STMTscope ? (ScopeStatement*)this : NULL; }
+ ExpStatement *isExpStatement() { return stmt == STMTexp ? (ExpStatement*)this : NULL; }
+ CompoundStatement *isCompoundStatement() { return stmt == STMTcompound ? (CompoundStatement*)this : NULL; }
+ ReturnStatement *isReturnStatement() { return stmt == STMTreturn ? (ReturnStatement*)this : NULL; }
+ IfStatement *isIfStatement() { return stmt == STMTif ? (IfStatement*)this : NULL; }
+ ConditionalStatement *isConditionalStatement() { return stmt == STMTconditional ? (ConditionalStatement*)this : NULL; }
+ StaticForeachStatement *isStaticForeachStatement() { return stmt == STMTstaticForeach ? (StaticForeachStatement*)this : NULL; }
+ CaseStatement *isCaseStatement() { return stmt == STMTcase ? (CaseStatement*)this : NULL; }
+ DefaultStatement *isDefaultStatement() { return stmt == STMTdefault ? (DefaultStatement*)this : NULL; }
+ LabelStatement *isLabelStatement() { return stmt == STMTlabel ? (LabelStatement*)this : NULL; }
+ GotoDefaultStatement *isGotoDefaultStatement() { return stmt == STMTgotoDefault ? (GotoDefaultStatement*)this : NULL; }
+ GotoCaseStatement *isGotoCaseStatement() { return stmt == STMTgotoCase ? (GotoCaseStatement*)this : NULL; }
+ BreakStatement *isBreakStatement() { return stmt == STMTbreak ? (BreakStatement*)this : NULL; }
+ DtorExpStatement *isDtorExpStatement() { return stmt == STMTdtorExp ? (DtorExpStatement*)this : NULL; }
+ CompileStatement *isCompileStatement() { return stmt == STMTcompile ? (CompileStatement*)this : NULL; }
+ ForwardingStatement *isForwardingStatement() { return stmt == STMTforwarding ? (ForwardingStatement*)this : NULL; }
+ DoStatement *isDoStatement() { return stmt == STMTdo ? (DoStatement*)this : NULL; }
+ ForStatement *isForStatement() { return stmt == STMTfor ? (ForStatement*)this : NULL; }
+ ForeachStatement *isForeachStatement() { return stmt == STMTforeach ? (ForeachStatement*)this : NULL; }
+ SwitchStatement *isSwitchStatement() { return stmt == STMTswitch ? (SwitchStatement*)this : NULL; }
+ ContinueStatement *isContinueStatement() { return stmt == STMTcontinue ? (ContinueStatement*)this : NULL; }
+ WithStatement *isWithStatement() { return stmt == STMTwith ? (WithStatement*)this : NULL; }
+ TryCatchStatement *isTryCatchStatement() { return stmt == STMTtryCatch ? (TryCatchStatement*)this : NULL; }
+ ThrowStatement *isThrowStatement() { return stmt == STMTthrow ? (ThrowStatement*)this : NULL; }
+ DebugStatement *isDebugStatement() { return stmt == STMTdebug ? (DebugStatement*)this : NULL; }
+ TryFinallyStatement *isTryFinallyStatement() { return stmt == STMTtryFinally ? (TryFinallyStatement*)this : NULL; }
+ ScopeGuardStatement *isScopeGuardStatement() { return stmt == STMTscopeGuard ? (ScopeGuardStatement*)this : NULL; }
+ SwitchErrorStatement *isSwitchErrorStatement() { return stmt == STMTswitchError ? (SwitchErrorStatement*)this : NULL; }
+ UnrolledLoopStatement *isUnrolledLoopStatement() { return stmt == STMTunrolledLoop ? (UnrolledLoopStatement*)this : NULL; }
+ ForeachRangeStatement *isForeachRangeStatement() { return stmt == STMTforeachRange ? (ForeachRangeStatement*)this : NULL; }
+ CompoundDeclarationStatement *isCompoundDeclarationStatement() { return stmt == STMTcompoundDeclaration ? (CompoundDeclarationStatement*)this : NULL; }
+
void accept(Visitor *v) { v->visit(this); }
};
@@ -123,10 +168,8 @@ public:
class ErrorStatement : public Statement
{
public:
- ErrorStatement();
- Statement *syntaxCopy();
+ ErrorStatement *syntaxCopy();
- ErrorStatement *isErrorStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
@@ -135,7 +178,6 @@ class PeelStatement : public Statement
public:
Statement *s;
- PeelStatement(Statement *s);
void accept(Visitor *v) { v->visit(this); }
};
@@ -144,14 +186,9 @@ class ExpStatement : public Statement
public:
Expression *exp;
- ExpStatement(Loc loc, Expression *exp);
- ExpStatement(Loc loc, Dsymbol *s);
static ExpStatement *create(Loc loc, Expression *exp);
- Statement *syntaxCopy();
- Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
- Statements *flatten(Scope *sc);
+ ExpStatement *syntaxCopy();
- ExpStatement *isExpStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
@@ -163,11 +200,8 @@ public:
VarDeclaration *var;
- DtorExpStatement(Loc loc, Expression *exp, VarDeclaration *v);
- Statement *syntaxCopy();
+ DtorExpStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
-
- DtorExpStatement *isDtorExpStatement() { return this; }
};
class CompileStatement : public Statement
@@ -175,10 +209,7 @@ class CompileStatement : public Statement
public:
Expressions *exps;
- CompileStatement(Loc loc, Expression *exp);
- CompileStatement(Loc loc, Expressions *exps);
- Statement *syntaxCopy();
- Statements *flatten(Scope *sc);
+ CompileStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -187,24 +218,18 @@ class CompoundStatement : public Statement
public:
Statements *statements;
- CompoundStatement(Loc loc, Statements *s);
- CompoundStatement(Loc loc, Statement *s1);
- CompoundStatement(Loc loc, Statement *s1, Statement *s2);
static CompoundStatement *create(Loc loc, Statement *s1, Statement *s2);
- Statement *syntaxCopy();
- Statements *flatten(Scope *sc);
- ReturnStatement *isReturnStatement();
+ CompoundStatement *syntaxCopy();
+ ReturnStatement *endsWithReturnStatement();
Statement *last();
- CompoundStatement *isCompoundStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
class CompoundDeclarationStatement : public CompoundStatement
{
public:
- CompoundDeclarationStatement(Loc loc, Statements *s);
- Statement *syntaxCopy();
+ CompoundDeclarationStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -216,10 +241,9 @@ class UnrolledLoopStatement : public Statement
public:
Statements *statements;
- UnrolledLoopStatement(Loc loc, Statements *statements);
- Statement *syntaxCopy();
- bool hasBreak();
- bool hasContinue();
+ UnrolledLoopStatement *syntaxCopy();
+ bool hasBreak() const;
+ bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -230,12 +254,10 @@ public:
Statement *statement;
Loc endloc; // location of closing curly bracket
- ScopeStatement(Loc loc, Statement *s, Loc endloc);
- Statement *syntaxCopy();
- ScopeStatement *isScopeStatement() { return this; }
- ReturnStatement *isReturnStatement();
- bool hasBreak();
- bool hasContinue();
+ ScopeStatement *syntaxCopy();
+ ReturnStatement *endsWithReturnStatement();
+ bool hasBreak() const;
+ bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -246,25 +268,21 @@ public:
ForwardingScopeDsymbol *sym;
Statement *statement;
- ForwardingStatement(Loc loc, ForwardingScopeDsymbol *sym, Statement *s);
- ForwardingStatement(Loc loc, Statement *s);
- Statement *syntaxCopy();
- Statements *flatten(Scope *sc);
- ForwardingStatement *isForwardingStatement() { return this; }
+ ForwardingStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
class WhileStatement : public Statement
{
public:
+ Parameter *param;
Expression *condition;
Statement *_body;
Loc endloc; // location of closing curly bracket
- WhileStatement(Loc loc, Expression *c, Statement *b, Loc endloc);
- Statement *syntaxCopy();
- bool hasBreak();
- bool hasContinue();
+ WhileStatement *syntaxCopy();
+ bool hasBreak() const;
+ bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -276,10 +294,9 @@ public:
Expression *condition;
Loc endloc; // location of ';' after while
- DoStatement(Loc loc, Statement *b, Expression *c, Loc endloc);
- Statement *syntaxCopy();
- bool hasBreak();
- bool hasContinue();
+ DoStatement *syntaxCopy();
+ bool hasBreak() const;
+ bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -298,12 +315,10 @@ public:
// treat that label as referring to this loop.
Statement *relatedLabeled;
- ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body, Loc endloc);
- Statement *syntaxCopy();
- Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
+ ForStatement *syntaxCopy();
Statement *getRelatedLabeled() { return relatedLabeled ? relatedLabeled : this; }
- bool hasBreak();
- bool hasContinue();
+ bool hasBreak() const;
+ bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -325,11 +340,9 @@ public:
Statements *cases; // put breaks, continues, gotos and returns here
ScopeStatements *gotos; // forward referenced goto's go here
- ForeachStatement(Loc loc, TOK op, Parameters *parameters, Expression *aggr, Statement *body, Loc endloc);
- Statement *syntaxCopy();
- bool checkForArgTypes();
- bool hasBreak();
- bool hasContinue();
+ ForeachStatement *syntaxCopy();
+ bool hasBreak() const;
+ bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -346,11 +359,9 @@ public:
VarDeclaration *key;
- ForeachRangeStatement(Loc loc, TOK op, Parameter *prm,
- Expression *lwr, Expression *upr, Statement *body, Loc endloc);
- Statement *syntaxCopy();
- bool hasBreak();
- bool hasContinue();
+ ForeachRangeStatement *syntaxCopy();
+ bool hasBreak() const;
+ bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -362,13 +373,10 @@ public:
Expression *condition;
Statement *ifbody;
Statement *elsebody;
- Loc endloc; // location of closing curly bracket
-
VarDeclaration *match; // for MatchExpression results
+ Loc endloc; // location of closing curly bracket
- IfStatement(Loc loc, Parameter *prm, Expression *condition, Statement *ifbody, Statement *elsebody, Loc endloc);
- Statement *syntaxCopy();
- IfStatement *isIfStatement() { return this; }
+ IfStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -380,9 +388,7 @@ public:
Statement *ifbody;
Statement *elsebody;
- ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody);
- Statement *syntaxCopy();
- Statements *flatten(Scope *sc);
+ ConditionalStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -392,9 +398,7 @@ class StaticForeachStatement : public Statement
public:
StaticForeach *sfe;
- StaticForeachStatement(Loc loc, StaticForeach *sfe);
- Statement *syntaxCopy();
- Statements *flatten(Scope *sc);
+ StaticForeachStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -406,8 +410,7 @@ public:
Expressions *args; // array of Expression's
Statement *_body;
- PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body);
- Statement *syntaxCopy();
+ PragmaStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -417,8 +420,7 @@ class StaticAssertStatement : public Statement
public:
StaticAssert *sa;
- StaticAssertStatement(StaticAssert *sa);
- Statement *syntaxCopy();
+ StaticAssertStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -431,6 +433,7 @@ public:
bool isFinal;
DefaultStatement *sdefault;
+ Statement *tryBody; // set to TryCatchStatement or TryFinallyStatement if in _body portion
TryFinallyStatement *tf;
GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's
CaseStatements *cases; // array of CaseStatement's
@@ -438,10 +441,8 @@ public:
int hasVars; // !=0 if has variable case values
VarDeclaration *lastVar;
- SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal);
- Statement *syntaxCopy();
- bool hasBreak();
- bool checkLabel();
+ SwitchStatement *syntaxCopy();
+ bool hasBreak() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -454,11 +455,9 @@ public:
int index; // which case it is (since we sort this)
VarDeclaration *lastVar;
+ void* extra; // for use by Statement_toIR()
- CaseStatement(Loc loc, Expression *exp, Statement *s);
- Statement *syntaxCopy();
- int compare(RootObject *obj);
- CaseStatement *isCaseStatement() { return this; }
+ CaseStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -471,8 +470,7 @@ public:
Expression *last;
Statement *statement;
- CaseRangeStatement(Loc loc, Expression *first, Expression *last, Statement *s);
- Statement *syntaxCopy();
+ CaseRangeStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -483,9 +481,7 @@ public:
Statement *statement;
VarDeclaration *lastVar;
- DefaultStatement(Loc loc, Statement *s);
- Statement *syntaxCopy();
- DefaultStatement *isDefaultStatement() { return this; }
+ DefaultStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -495,9 +491,7 @@ class GotoDefaultStatement : public Statement
public:
SwitchStatement *sw;
- GotoDefaultStatement(Loc loc);
- Statement *syntaxCopy();
- GotoDefaultStatement *isGotoDefaultStatement() { return this; }
+ GotoDefaultStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -508,9 +502,7 @@ public:
Expression *exp; // NULL, or which case to goto
CaseStatement *cs; // case statement it resolves to
- GotoCaseStatement(Loc loc, Expression *exp);
- Statement *syntaxCopy();
- GotoCaseStatement *isGotoCaseStatement() { return this; }
+ GotoCaseStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -518,7 +510,7 @@ public:
class SwitchErrorStatement : public Statement
{
public:
- SwitchErrorStatement(Loc loc);
+ Expression *exp;
void accept(Visitor *v) { v->visit(this); }
};
@@ -529,10 +521,9 @@ public:
Expression *exp;
size_t caseDim;
- ReturnStatement(Loc loc, Expression *exp);
- Statement *syntaxCopy();
+ ReturnStatement *syntaxCopy();
- ReturnStatement *isReturnStatement() { return this; }
+ ReturnStatement *endsWithReturnStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
@@ -541,10 +532,8 @@ class BreakStatement : public Statement
public:
Identifier *ident;
- BreakStatement(Loc loc, Identifier *ident);
- Statement *syntaxCopy();
+ BreakStatement *syntaxCopy();
- BreakStatement *isBreakStatement() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
@@ -553,8 +542,7 @@ class ContinueStatement : public Statement
public:
Identifier *ident;
- ContinueStatement(Loc loc, Identifier *ident);
- Statement *syntaxCopy();
+ ContinueStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -565,10 +553,9 @@ public:
Expression *exp;
Statement *_body;
- SynchronizedStatement(Loc loc, Expression *exp, Statement *body);
- Statement *syntaxCopy();
- bool hasBreak();
- bool hasContinue();
+ SynchronizedStatement *syntaxCopy();
+ bool hasBreak() const;
+ bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -581,8 +568,7 @@ public:
VarDeclaration *wthis;
Loc endloc;
- WithStatement(Loc loc, Expression *exp, Statement *body, Loc endloc);
- Statement *syntaxCopy();
+ WithStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -593,9 +579,10 @@ public:
Statement *_body;
Catches *catches;
- TryCatchStatement(Loc loc, Statement *body, Catches *catches);
- Statement *syntaxCopy();
- bool hasBreak();
+ Statement *tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
+
+ TryCatchStatement *syntaxCopy();
+ bool hasBreak() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -606,9 +593,9 @@ public:
Loc loc;
Type *type;
Identifier *ident;
- VarDeclaration *var;
Statement *handler;
+ VarDeclaration *var;
// set if semantic processing errors
bool errors;
@@ -616,7 +603,6 @@ public:
// wasn't present in source code
bool internalCatch;
- Catch(Loc loc, Type *t, Identifier *id, Statement *handler);
Catch *syntaxCopy();
};
@@ -626,11 +612,13 @@ public:
Statement *_body;
Statement *finalbody;
- TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody);
+ Statement *tryBody; // set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
+ bool bodyFallsThru; // true if _body falls through to finally
+
static TryFinallyStatement *create(Loc loc, Statement *body, Statement *finalbody);
- Statement *syntaxCopy();
- bool hasBreak();
- bool hasContinue();
+ TryFinallyStatement *syntaxCopy();
+ bool hasBreak() const;
+ bool hasContinue() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -641,9 +629,7 @@ public:
TOK tok;
Statement *statement;
- ScopeGuardStatement(Loc loc, TOK tok, Statement *statement);
- Statement *syntaxCopy();
- Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
+ ScopeGuardStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -656,8 +642,7 @@ public:
// wasn't present in source code
bool internalThrow;
- ThrowStatement(Loc loc, Expression *exp);
- Statement *syntaxCopy();
+ ThrowStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -667,9 +652,7 @@ class DebugStatement : public Statement
public:
Statement *statement;
- DebugStatement(Loc loc, Statement *statement);
- Statement *syntaxCopy();
- Statements *flatten(Scope *sc);
+ DebugStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -678,13 +661,12 @@ class GotoStatement : public Statement
public:
Identifier *ident;
LabelDsymbol *label;
+ Statement *tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
TryFinallyStatement *tf;
ScopeGuardStatement *os;
VarDeclaration *lastVar;
- GotoStatement(Loc loc, Identifier *ident);
- Statement *syntaxCopy();
- bool checkLabel();
+ GotoStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -694,19 +676,15 @@ class LabelStatement : public Statement
public:
Identifier *ident;
Statement *statement;
+ Statement *tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
TryFinallyStatement *tf;
ScopeGuardStatement *os;
VarDeclaration *lastVar;
Statement *gotoTarget; // interpret
-
+ void* extra; // used by Statement_toIR()
bool breaks; // someone did a 'break ident'
- LabelStatement(Loc loc, Identifier *ident, Statement *statement);
- Statement *syntaxCopy();
- Statements *flatten(Scope *sc);
- Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
-
- LabelStatement *isLabelStatement() { return this; }
+ LabelStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -716,7 +694,9 @@ class LabelDsymbol : public Dsymbol
public:
LabelStatement *statement;
- LabelDsymbol(Identifier *ident);
+ bool deleted; // set if rewritten to return in foreach delegate
+ bool iasm; // set if used by inline assembler
+
static LabelDsymbol *create(Identifier *ident);
LabelDsymbol *isLabel();
void accept(Visitor *v) { v->visit(this); }
@@ -729,8 +709,7 @@ class AsmStatement : public Statement
public:
Token *tokens;
- AsmStatement(Loc loc, Token *tokens);
- Statement *syntaxCopy();
+ AsmStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -743,8 +722,7 @@ public:
bool refparam; // true if function parameter is referenced
bool naked; // true if function is to be naked
- InlineAsmStatement(Loc loc, Token *tokens);
- Statement *syntaxCopy();
+ InlineAsmStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -762,8 +740,7 @@ public:
Identifiers *labels; // list of goto labels
GotoStatements *gotos; // of the goto labels, the equivalent statements they represent
- GccAsmStatement(Loc loc, Token *tokens);
- Statement *syntaxCopy();
+ GccAsmStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -773,9 +750,7 @@ class CompoundAsmStatement : public CompoundStatement
public:
StorageClass stc; // postfix attributes like nothrow/pure/@trusted
- CompoundAsmStatement(Loc loc, Statements *s, StorageClass stc);
CompoundAsmStatement *syntaxCopy();
- Statements *flatten(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
@@ -785,8 +760,7 @@ class ImportStatement : public Statement
public:
Dsymbols *imports; // Array of Import's
- ImportStatement(Loc loc, Dsymbols *imports);
- Statement *syntaxCopy();
+ ImportStatement *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
diff --git a/gcc/d/dmd/statement_rewrite_walker.d b/gcc/d/dmd/statement_rewrite_walker.d
new file mode 100644
index 0000000..2f6605c
--- /dev/null
+++ b/gcc/d/dmd/statement_rewrite_walker.d
@@ -0,0 +1,194 @@
+/**
+ * Provides a visitor for statements that allows rewriting the currently visited node.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement_rewrite_walker.d, _statement_rewrite_walker.d)
+ * Documentation: https://dlang.org/phobos/dmd_statement_rewrite_walker.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statement_rewrite_walker.d
+ */
+
+module dmd.statement_rewrite_walker;
+
+import core.stdc.stdio;
+
+import dmd.statement;
+import dmd.visitor;
+
+
+/** A visitor to walk entire statements and provides ability to replace any sub-statements.
+ */
+extern (C++) class StatementRewriteWalker : SemanticTimePermissiveVisitor
+{
+ alias visit = SemanticTimePermissiveVisitor.visit;
+
+ /* Point the currently visited statement.
+ * By using replaceCurrent() method, you can replace AST during walking.
+ */
+ Statement* ps;
+
+public:
+ final void visitStmt(ref Statement s)
+ {
+ ps = &s;
+ s.accept(this);
+ }
+
+ final void replaceCurrent(Statement s)
+ {
+ *ps = s;
+ }
+
+ override void visit(PeelStatement s)
+ {
+ if (s.s)
+ visitStmt(s.s);
+ }
+
+ override void visit(CompoundStatement s)
+ {
+ if (s.statements && s.statements.dim)
+ {
+ for (size_t i = 0; i < s.statements.dim; i++)
+ {
+ if ((*s.statements)[i])
+ visitStmt((*s.statements)[i]);
+ }
+ }
+ }
+
+ override void visit(CompoundDeclarationStatement s)
+ {
+ visit(cast(CompoundStatement)s);
+ }
+
+ override void visit(UnrolledLoopStatement s)
+ {
+ if (s.statements && s.statements.dim)
+ {
+ for (size_t i = 0; i < s.statements.dim; i++)
+ {
+ if ((*s.statements)[i])
+ visitStmt((*s.statements)[i]);
+ }
+ }
+ }
+
+ override void visit(ScopeStatement s)
+ {
+ if (s.statement)
+ visitStmt(s.statement);
+ }
+
+ override void visit(WhileStatement s)
+ {
+ if (s._body)
+ visitStmt(s._body);
+ }
+
+ override void visit(DoStatement s)
+ {
+ if (s._body)
+ visitStmt(s._body);
+ }
+
+ override void visit(ForStatement s)
+ {
+ if (s._init)
+ visitStmt(s._init);
+ if (s._body)
+ visitStmt(s._body);
+ }
+
+ override void visit(ForeachStatement s)
+ {
+ if (s._body)
+ visitStmt(s._body);
+ }
+
+ override void visit(ForeachRangeStatement s)
+ {
+ if (s._body)
+ visitStmt(s._body);
+ }
+
+ override void visit(IfStatement s)
+ {
+ if (s.ifbody)
+ visitStmt(s.ifbody);
+ if (s.elsebody)
+ visitStmt(s.elsebody);
+ }
+
+ override void visit(SwitchStatement s)
+ {
+ if (s._body)
+ visitStmt(s._body);
+ }
+
+ override void visit(CaseStatement s)
+ {
+ if (s.statement)
+ visitStmt(s.statement);
+ }
+
+ override void visit(CaseRangeStatement s)
+ {
+ if (s.statement)
+ visitStmt(s.statement);
+ }
+
+ override void visit(DefaultStatement s)
+ {
+ if (s.statement)
+ visitStmt(s.statement);
+ }
+
+ override void visit(SynchronizedStatement s)
+ {
+ if (s._body)
+ visitStmt(s._body);
+ }
+
+ override void visit(WithStatement s)
+ {
+ if (s._body)
+ visitStmt(s._body);
+ }
+
+ override void visit(TryCatchStatement s)
+ {
+ if (s._body)
+ visitStmt(s._body);
+ if (s.catches && s.catches.dim)
+ {
+ for (size_t i = 0; i < s.catches.dim; i++)
+ {
+ Catch c = (*s.catches)[i];
+ if (c && c.handler)
+ visitStmt(c.handler);
+ }
+ }
+ }
+
+ override void visit(TryFinallyStatement s)
+ {
+ if (s._body)
+ visitStmt(s._body);
+ if (s.finalbody)
+ visitStmt(s.finalbody);
+ }
+
+ override void visit(DebugStatement s)
+ {
+ if (s.statement)
+ visitStmt(s.statement);
+ }
+
+ override void visit(LabelStatement s)
+ {
+ if (s.statement)
+ visitStmt(s.statement);
+ }
+}
diff --git a/gcc/d/dmd/statementsem.c b/gcc/d/dmd/statementsem.c
deleted file mode 100644
index 24e534e..0000000
--- a/gcc/d/dmd/statementsem.c
+++ /dev/null
@@ -1,3875 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- */
-
-#include "root/dsystem.h"
-#include "root/rmem.h"
-#include "root/checkedint.h"
-
-#include "errors.h"
-#include "statement.h"
-#include "attrib.h"
-#include "expression.h"
-#include "cond.h"
-#include "init.h"
-#include "staticassert.h"
-#include "module.h"
-#include "scope.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "id.h"
-#include "enum.h"
-#include "template.h"
-#include "import.h"
-#include "target.h"
-#include "visitor.h"
-
-StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f);
-bool checkReturnEscapeRef(Scope *sc, Expression *e, bool gag);
-bool checkThrowEscape(Scope *sc, Expression *e, bool gag);
-LabelStatement *checkLabeledLoop(Scope *sc, Statement *statement);
-Identifier *fixupLabelName(Scope *sc, Identifier *ident);
-FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
-VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
-Expression *checkAssignmentAsCondition(Expression *e);
-TypeIdentifier *getThrowable();
-
-int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow);
-
-class StatementSemanticVisitor : public Visitor
-{
-public:
- Statement *result;
- Scope *sc;
-
- StatementSemanticVisitor(Scope *sc)
- {
- this->result = NULL;
- this->sc = sc;
- }
-
-private:
- void setError()
- {
- result = new ErrorStatement();
- }
-
-public:
- void visit(Statement *s)
- {
- result = s;
- }
-
- void visit(ErrorStatement *s)
- {
- result = s;
- }
-
- void visit(PeelStatement *s)
- {
- /* "peel" off this wrapper, and don't run semantic()
- * on the result.
- */
- result = s->s;
- }
-
- void visit(ExpStatement *s)
- {
- if (s->exp)
- {
- //printf("ExpStatement::semantic() %s\n", s->exp->toChars());
-
- // Allow CommaExp in ExpStatement because return isn't used
- if (s->exp->op == TOKcomma)
- ((CommaExp *)s->exp)->allowCommaExp = true;
-
- s->exp = expressionSemantic(s->exp, sc);
- s->exp = resolveProperties(sc, s->exp);
- s->exp = s->exp->addDtorHook(sc);
- if (checkNonAssignmentArrayOp(s->exp))
- s->exp = new ErrorExp();
- if (FuncDeclaration *f = isFuncAddress(s->exp))
- {
- if (f->checkForwardRef(s->exp->loc))
- s->exp = new ErrorExp();
- }
- if (discardValue(s->exp))
- s->exp = new ErrorExp();
-
- s->exp = s->exp->optimize(WANTvalue);
- s->exp = checkGC(sc, s->exp);
- if (s->exp->op == TOKerror)
- return setError();
- }
- result = s;
- }
-
- void visit(CompileStatement *cs)
- {
- //printf("CompileStatement::semantic() %s\n", cs->exp->toChars());
- Statements *a = cs->flatten(sc);
- if (!a)
- return;
- Statement *s = new CompoundStatement(cs->loc, a);
- result = statementSemantic(s, sc);
- }
-
- void visit(CompoundStatement *cs)
- {
- //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", cs, sc);
- for (size_t i = 0; i < cs->statements->length; )
- {
- Statement *s = (*cs->statements)[i];
- if (s)
- {
- Statements *flt = s->flatten(sc);
- if (flt)
- {
- cs->statements->remove(i);
- cs->statements->insert(i, flt);
- continue;
- }
- s = statementSemantic(s, sc);
- (*cs->statements)[i] = s;
- if (s)
- {
- Statement *sentry;
- Statement *sexception;
- Statement *sfinally;
-
- (*cs->statements)[i] = s->scopeCode(sc, &sentry, &sexception, &sfinally);
- if (sentry)
- {
- sentry = statementSemantic(sentry, sc);
- cs->statements->insert(i, sentry);
- i++;
- }
- if (sexception)
- sexception = statementSemantic(sexception, sc);
- if (sexception)
- {
- if (i + 1 == cs->statements->length && !sfinally)
- {
- }
- else
- {
- /* Rewrite:
- * s; s1; s2;
- * As:
- * s;
- * try { s1; s2; }
- * catch (Throwable __o)
- * { sexception; throw __o; }
- */
- Statements *a = new Statements();
- for (size_t j = i + 1; j < cs->statements->length; j++)
- {
- a->push((*cs->statements)[j]);
- }
- Statement *body = new CompoundStatement(Loc(), a);
- body = new ScopeStatement(Loc(), body, Loc());
-
- Identifier *id = Identifier::generateId("__o");
-
- Statement *handler = new PeelStatement(sexception);
- if (blockExit(sexception, sc->func, false) & BEfallthru)
- {
- ThrowStatement *ts = new ThrowStatement(Loc(), new IdentifierExp(Loc(), id));
- ts->internalThrow = true;
- handler = new CompoundStatement(Loc(), handler, ts);
- }
-
- Catches *catches = new Catches();
- Catch *ctch = new Catch(Loc(), getThrowable(), id, handler);
- ctch->internalCatch = true;
- catches->push(ctch);
-
- s = new TryCatchStatement(Loc(), body, catches);
- if (sfinally)
- s = new TryFinallyStatement(Loc(), s, sfinally);
- s = statementSemantic(s, sc);
-
- cs->statements->setDim(i + 1);
- cs->statements->push(s);
- break;
- }
- }
- else if (sfinally)
- {
- if (0 && i + 1 == cs->statements->length)
- {
- cs->statements->push(sfinally);
- }
- else
- {
- /* Rewrite:
- * s; s1; s2;
- * As:
- * s; try { s1; s2; } finally { sfinally; }
- */
- Statements *a = new Statements();
- for (size_t j = i + 1; j < cs->statements->length; j++)
- {
- a->push((*cs->statements)[j]);
- }
- Statement *body = new CompoundStatement(Loc(), a);
- s = new TryFinallyStatement(Loc(), body, sfinally);
- s = statementSemantic(s, sc);
- cs->statements->setDim(i + 1);
- cs->statements->push(s);
- break;
- }
- }
- }
- else
- {
- /* Remove NULL statements from the list.
- */
- cs->statements->remove(i);
- continue;
- }
- }
- i++;
- }
- for (size_t i = 0; i < cs->statements->length; ++i)
- {
- Lagain:
- Statement *s = (*cs->statements)[i];
- if (!s)
- continue;
-
- Statement *se = s->isErrorStatement();
- if (se)
- {
- result = se;
- return;
- }
-
- /* Bugzilla 11653: 'semantic' may return another CompoundStatement
- * (eg. CaseRangeStatement), so flatten it here.
- */
- Statements *flt = s->flatten(sc);
- if (flt)
- {
- cs->statements->remove(i);
- cs->statements->insert(i, flt);
- if (cs->statements->length <= i)
- break;
- goto Lagain;
- }
- }
- if (cs->statements->length == 1)
- {
- result = (*cs->statements)[0];
- return;
- }
- result = cs;
- }
-
- void visit(UnrolledLoopStatement *uls)
- {
- //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", uls, sc);
- Scope *scd = sc->push();
- scd->sbreak = uls;
- scd->scontinue = uls;
-
- Statement *serror = NULL;
- for (size_t i = 0; i < uls->statements->length; i++)
- {
- Statement *s = (*uls->statements)[i];
- if (s)
- {
- //printf("[%d]: %s\n", i, s->toChars());
- s = statementSemantic(s, scd);
- (*uls->statements)[i] = s;
-
- if (s && !serror)
- serror = s->isErrorStatement();
- }
- }
-
- scd->pop();
- result = serror ? serror : uls;
- }
-
- void visit(ScopeStatement *ss)
- {
- //printf("ScopeStatement::semantic(sc = %p)\n", sc);
- if (ss->statement)
- {
- ScopeDsymbol *sym = new ScopeDsymbol();
- sym->parent = sc->scopesym;
- sym->endlinnum = ss->endloc.linnum;
- sc = sc->push(sym);
-
- Statements *a = ss->statement->flatten(sc);
- if (a)
- {
- ss->statement = new CompoundStatement(ss->loc, a);
- }
-
- ss->statement = statementSemantic(ss->statement, sc);
- if (ss->statement)
- {
- if (ss->statement->isErrorStatement())
- {
- sc->pop();
- result = ss->statement;
- return;
- }
-
- Statement *sentry;
- Statement *sexception;
- Statement *sfinally;
-
- ss->statement = ss->statement->scopeCode(sc, &sentry, &sexception, &sfinally);
- assert(!sentry);
- assert(!sexception);
- if (sfinally)
- {
- //printf("adding sfinally\n");
- sfinally = statementSemantic(sfinally, sc);
- ss->statement = new CompoundStatement(ss->loc, ss->statement, sfinally);
- }
- }
-
- sc->pop();
- }
- result = ss;
- }
-
- void visit(ForwardingStatement *ss)
- {
- assert(ss->sym);
- for (Scope *csc = sc; !ss->sym->forward; csc = csc->enclosing)
- {
- assert(csc);
- ss->sym->forward = csc->scopesym;
- }
- sc = sc->push(ss->sym);
- sc->sbreak = ss;
- sc->scontinue = ss;
- ss->statement = statementSemantic(ss->statement, sc);
- sc = sc->pop();
- result = ss->statement;
- }
-
- void visit(WhileStatement *ws)
- {
- /* Rewrite as a for(;condition;) loop
- */
- Statement *s = new ForStatement(ws->loc, NULL, ws->condition, NULL, ws->_body, ws->endloc);
- s = statementSemantic(s, sc);
- result = s;
- }
-
- void visit(DoStatement *ds)
- {
- sc->noctor++;
- if (ds->_body)
- ds->_body = semanticScope(ds->_body, sc, ds, ds);
- sc->noctor--;
-
- if (ds->condition->op == TOKdotid)
- ((DotIdExp *)ds->condition)->noderef = true;
-
- // check in syntax level
- ds->condition = checkAssignmentAsCondition(ds->condition);
-
- ds->condition = expressionSemantic(ds->condition, sc);
- ds->condition = resolveProperties(sc, ds->condition);
- if (checkNonAssignmentArrayOp(ds->condition))
- ds->condition = new ErrorExp();
- ds->condition = ds->condition->optimize(WANTvalue);
- ds->condition = checkGC(sc, ds->condition);
-
- ds->condition = ds->condition->toBoolean(sc);
-
- if (ds->condition->op == TOKerror)
- return setError();
-
- if (ds->_body && ds->_body->isErrorStatement())
- {
- result = ds->_body;
- return;
- }
-
- result = ds;
- }
-
- void visit(ForStatement *fs)
- {
- //printf("ForStatement::semantic %s\n", toChars());
-
- if (fs->_init)
- {
- /* Rewrite:
- * for (auto v1 = i1, v2 = i2; condition; increment) { ... }
- * to:
- * { auto v1 = i1, v2 = i2; for (; condition; increment) { ... } }
- * then lowered to:
- * auto v1 = i1;
- * try {
- * auto v2 = i2;
- * try {
- * for (; condition; increment) { ... }
- * } finally { v2.~this(); }
- * } finally { v1.~this(); }
- */
- Statements *ainit = new Statements();
- ainit->push(fs->_init);
- fs->_init = NULL;
- ainit->push(fs);
- Statement *s = new CompoundStatement(fs->loc, ainit);
- s = new ScopeStatement(fs->loc, s, fs->endloc);
- s = statementSemantic(s, sc);
- if (!s->isErrorStatement())
- {
- if (LabelStatement *ls = checkLabeledLoop(sc, fs))
- ls->gotoTarget = fs;
- fs->relatedLabeled = s;
- }
- result = s;
- return;
- }
- assert(fs->_init == NULL);
-
- ScopeDsymbol *sym = new ScopeDsymbol();
- sym->parent = sc->scopesym;
- sym->endlinnum = fs->endloc.linnum;
- sc = sc->push(sym);
-
- sc->noctor++;
- if (fs->condition)
- {
- if (fs->condition->op == TOKdotid)
- ((DotIdExp *)fs->condition)->noderef = true;
-
- // check in syntax level
- fs->condition = checkAssignmentAsCondition(fs->condition);
-
- fs->condition = expressionSemantic(fs->condition, sc);
- fs->condition = resolveProperties(sc, fs->condition);
- if (checkNonAssignmentArrayOp(fs->condition))
- fs->condition = new ErrorExp();
- fs->condition = fs->condition->optimize(WANTvalue);
- fs->condition = checkGC(sc, fs->condition);
- fs->condition = fs->condition->toBoolean(sc);
- }
- if (fs->increment)
- {
- if (fs->increment->op == TOKcomma)
- ((CommaExp *)fs->increment)->allowCommaExp = true;
- fs->increment = expressionSemantic(fs->increment, sc);
- fs->increment = resolveProperties(sc, fs->increment);
- if (checkNonAssignmentArrayOp(fs->increment))
- fs->increment = new ErrorExp();
- fs->increment = fs->increment->optimize(WANTvalue);
- fs->increment = checkGC(sc, fs->increment);
- }
-
- sc->sbreak = fs;
- sc->scontinue = fs;
- if (fs->_body)
- fs->_body = semanticNoScope(fs->_body, sc);
- sc->noctor--;
-
- sc->pop();
-
- if ((fs->condition && fs->condition->op == TOKerror) ||
- (fs->increment && fs->increment->op == TOKerror) ||
- (fs->_body && fs->_body->isErrorStatement()))
- return setError();
-
- result = fs;
- }
-
- /***********************
- * Declares a unrolled `foreach` loop variable or a `static foreach` variable.
- *
- * Params:
- * storageClass = The storage class of the variable.
- * type = The declared type of the variable.
- * ident = The name of the variable.
- * e = The initializer of the variable (i.e. the current element of the looped over aggregate).
- * t = The type of the initializer.
- * Returns:
- * `true` iff the declaration was successful.
- */
- bool declareVariable(ForeachStatement *fs, Type *paramtype, TupleExp *te,
- bool needExpansion, bool isStatic, Statements *statements, Dsymbols *declarations,
- StorageClass storageClass, Type *type, Identifier *ident, Expression *e, Type *t)
- {
- Loc loc = fs->loc;
- if (storageClass & (STCout | STClazy) ||
- (storageClass & STCref && !te))
- {
- fs->error("no storage class for value %s", ident->toChars());
- return false;
- }
- Declaration *var;
- if (e)
- {
- Type *tb = e->type->toBasetype();
- Dsymbol *ds = NULL;
- if (!(storageClass & STCmanifest))
- {
- if ((isStatic || tb->ty == Tfunction || tb->ty == Tsarray || storageClass & STCalias) && e->op == TOKvar)
- ds = ((VarExp *)e)->var;
- else if (e->op == TOKtemplate)
- ds = ((TemplateExp *)e)->td;
- else if (e->op == TOKscope)
- ds = ((ScopeExp *)e)->sds;
- else if (e->op == TOKfunction)
- {
- FuncExp *fe = (FuncExp *)e;
- ds = fe->td ? (Dsymbol *)fe->td : fe->fd;
- }
- }
- else if (storageClass & STCalias)
- {
- fs->error("foreach loop variable cannot be both enum and alias");
- return false;
- }
-
- if (ds)
- {
- var = new AliasDeclaration(loc, ident, ds);
- if (storageClass & STCref)
- {
- fs->error("symbol %s cannot be ref", ds->toChars());
- return false;
- }
- if (paramtype)
- {
- fs->error("cannot specify element type for symbol %s", ds->toChars());
- return false;
- }
- }
- else if (e->op == TOKtype)
- {
- var = new AliasDeclaration(loc, ident, e->type);
- if (paramtype)
- {
- fs->error("cannot specify element type for type %s", e->type->toChars());
- return false;
- }
- }
- else
- {
- e = resolveProperties(sc, e);
- Initializer *ie = new ExpInitializer(Loc(), e);
- VarDeclaration *v = new VarDeclaration(loc, type, ident, ie);
- if (storageClass & STCref)
- v->storage_class |= STCref | STCforeach;
- if (isStatic || storageClass & STCmanifest || e->isConst() ||
- e->op == TOKstring ||
- e->op == TOKstructliteral ||
- e->op == TOKarrayliteral)
- {
- if (v->storage_class & STCref)
- {
- if (!isStatic || !needExpansion)
- {
- fs->error("constant value %s cannot be ref", ie->toChars());
- }
- else
- {
- fs->error("constant value %s cannot be ref", ident->toChars());
- }
- return false;
- }
- else
- v->storage_class |= STCmanifest;
- }
- var = v;
- }
- }
- else
- {
- var = new AliasDeclaration(loc, ident, t);
- if (paramtype)
- {
- fs->error("cannot specify element type for symbol %s", fs->toChars());
- return false;
- }
- }
- if (isStatic)
- var->storage_class |= STClocal;
- if (statements)
- statements->push(new ExpStatement(loc, var));
- else if (declarations)
- declarations->push(var);
- else
- assert(0);
- return true;
- }
-
- bool makeTupleForeachBody(ForeachStatement *fs, size_t k,
- Type *paramtype, TupleExp *te, TypeTuple *tuple,
- bool needExpansion, bool isStatic, bool isDecl,
- Statements *statements, Dsymbols *declarations, Dsymbols *dbody)
- {
- Loc loc = fs->loc;
- Expression *e = NULL;
- Type *t = NULL;
- if (te)
- e = (*te->exps)[k];
- else
- t = Parameter::getNth(tuple->arguments, k)->type;
- Parameter *p = (*fs->parameters)[0];
- Statements *stmts = (isDecl) ? NULL : new Statements();
- Dsymbols *decls = (isDecl) ? new Dsymbols() : NULL;
-
- size_t dim = fs->parameters->length;
- if (!needExpansion && dim == 2)
- {
- // Declare key
- if (p->storageClass & (STCout | STCref | STClazy))
- {
- fs->error("no storage class for key %s", p->ident->toChars());
- return false;
- }
- if (isStatic)
- {
- if (!p->type)
- {
- p->type = Type::tsize_t;
- }
- }
- p->type = typeSemantic(p->type, loc, sc);
-
- if (!p->type->isintegral())
- {
- fs->error("foreach: key cannot be of non-integral type `%s`",
- p->type->toChars());
- return false;
- }
-
- unsigned length = te ? te->exps->length : tuple->arguments->length;
- IntRange dimrange = IntRange(SignExtendedNumber(length)).cast(Type::tsize_t);
- // https://issues.dlang.org/show_bug.cgi?id=12504
- dimrange.imax = SignExtendedNumber(dimrange.imax.value-1);
- if (!IntRange::fromType(p->type).contains(dimrange))
- {
- fs->error("index type `%s` cannot cover index range 0..%llu",
- p->type->toChars(), (ulonglong)length);
- return false;
- }
- Initializer *ie = new ExpInitializer(Loc(), new IntegerExp(k));
- VarDeclaration *var = new VarDeclaration(loc, p->type, p->ident, ie);
- var->storage_class |= STCmanifest;
- if (isStatic)
- var->storage_class |= STClocal;
- if (!isDecl)
- stmts->push(new ExpStatement(loc, var));
- else
- decls->push(var);
- p = (*fs->parameters)[1]; // value
- }
-
- if (!isStatic || !needExpansion)
- {
- // Declare value
- if (!declareVariable(fs, paramtype, te, needExpansion, isStatic, stmts, decls,
- p->storageClass, p->type, p->ident, e, t))
- {
- return false;
- }
- }
- else
- {
- // expand tuples into multiple `static foreach` variables.
- assert(e && !t);
- Identifier *ident = Identifier::generateId("__value");
- declareVariable(fs, paramtype, te, needExpansion, isStatic, stmts, decls,
- 0, e->type, ident, e, NULL);
- Identifier *field = Identifier::idPool("tuple");
- Expression *access = new DotIdExp(loc, e, field);
- access = expressionSemantic(access, sc);
- if (!tuple)
- return false;
- //printf("%s\n", tuple->toChars());
- for (size_t l = 0; l < dim; l++)
- {
- Parameter *cp = (*fs->parameters)[l];
- Expression *init_ = new IndexExp(loc, access, new IntegerExp(loc, l, Type::tsize_t));
- init_ = expressionSemantic(init_, sc);
- assert(init_->type);
- declareVariable(fs, paramtype, te, needExpansion, isStatic, stmts, decls,
- p->storageClass, init_->type, cp->ident, init_, NULL);
- }
- }
- Statement *fwdstmt = NULL;
- Dsymbol *fwddecl = NULL;
- if (!isDecl)
- {
- if (fs->_body)
- stmts->push(fs->_body->syntaxCopy());
- fwdstmt = new CompoundStatement(loc, stmts);
- }
- else
- {
- decls->append(Dsymbol::arraySyntaxCopy(dbody));
- }
- if (!isStatic)
- {
- fwdstmt = new ScopeStatement(loc, fwdstmt, fs->endloc);
- }
- else if (!isDecl)
- {
- fwdstmt = new ForwardingStatement(loc, fwdstmt);
- }
- else
- {
- fwddecl = new ForwardingAttribDeclaration(decls);
- }
-
- if (statements)
- statements->push(fwdstmt);
- else if (declarations)
- declarations->push(fwddecl);
- else
- assert(0);
- return true;
- }
-
- /*******************
- * Type check and unroll `foreach` over an expression tuple as well
- * as `static foreach` statements and `static foreach`
- * declarations. For `static foreach` statements and `static
- * foreach` declarations, the visitor interface is used (and the
- * result is written into the `result` field.) For `static
- * foreach` declarations, the resulting Dsymbols* are returned
- * directly.
- *
- * The unrolled body is wrapped into a
- * - UnrolledLoopStatement, for `foreach` over an expression tuple.
- * - ForwardingStatement, for `static foreach` statements.
- * - ForwardingAttribDeclaration, for `static foreach` declarations.
- *
- * `static foreach` variables are declared as `STClocal`, such
- * that they are inserted into the local symbol tables of the
- * forwarding constructs instead of forwarded. For `static
- * foreach` with multiple foreach loop variables whose aggregate
- * has been lowered into a sequence of tuples, this function
- * expands the tuples into multiple `STClocal` `static foreach`
- * variables.
- */
- bool makeTupleForeach(ForeachStatement *fs, bool needExpansion, bool isStatic, bool isDecl,
- Statements *statements, Dsymbols *declarations, Dsymbols *dbody)
- {
- Loc loc = fs->loc;
- size_t dim = fs->parameters->length;
- if (!needExpansion && (dim < 1 || dim > 2))
- {
- fs->error("only one (value) or two (key,value) arguments for tuple foreach");
- return false;
- }
-
- Type *paramtype = (*fs->parameters)[dim-1]->type;
- if (paramtype)
- {
- paramtype = typeSemantic(paramtype, loc, sc);
- if (paramtype->ty == Terror)
- return false;
- }
-
- Type *tab = fs->aggr->type->toBasetype();
- TypeTuple *tuple = (TypeTuple *)tab;
- //printf("aggr: op = %d, %s\n", fs->aggr->op, fs->aggr->toChars());
- size_t n;
- TupleExp *te = NULL;
- if (fs->aggr->op == TOKtuple) // expression tuple
- {
- te = (TupleExp *)fs->aggr;
- n = te->exps->length;
- }
- else if (fs->aggr->op == TOKtype) // type tuple
- {
- n = Parameter::dim(tuple->arguments);
- }
- else
- assert(0);
- for (size_t j = 0; j < n; j++)
- {
- size_t k = (fs->op == TOKforeach) ? j : n - 1 - j;
- if (!makeTupleForeachBody(fs, k, paramtype, te, tuple,
- needExpansion, isStatic, isDecl,
- statements, declarations, dbody))
- return false;
- }
- return true;
- }
-
- Dsymbols *makeTupleForeachStaticDecl(ForeachStatement *fs, Dsymbols *dbody, bool needExpansion)
- {
- assert(sc);
- Dsymbols *declarations = new Dsymbols();
- if (!makeTupleForeach(fs, needExpansion, true, true, NULL, declarations, dbody))
- return NULL;
-
- return declarations;
- }
-
- void makeTupleForeachStatic(ForeachStatement *fs, bool needExpansion)
- {
- Loc loc = fs->loc;
- assert(sc);
- Statements *statements = new Statements();
- if (!makeTupleForeach(fs, needExpansion, true, false, statements, NULL, NULL))
- return setError();
-
- result = new CompoundStatement(loc, statements);
- }
-
- void visit(ForeachStatement *fs)
- {
- //printf("ForeachStatement::semantic() %p\n", fs);
- ScopeDsymbol *sym;
- Statement *s = fs;
- Loc loc = fs->loc;
- size_t dim = fs->parameters->length;
- TypeAArray *taa = NULL;
- Dsymbol *sapply = NULL;
-
- Type *tn = NULL;
- Type *tnv = NULL;
-
- fs->func = sc->func;
- if (fs->func->fes)
- fs->func = fs->func->fes->func;
-
- VarDeclaration *vinit = NULL;
- fs->aggr = expressionSemantic(fs->aggr, sc);
- fs->aggr = resolveProperties(sc, fs->aggr);
- fs->aggr = fs->aggr->optimize(WANTvalue);
- if (fs->aggr->op == TOKerror)
- return setError();
-
- Expression *oaggr = fs->aggr;
- if (fs->aggr->type && fs->aggr->type->toBasetype()->ty == Tstruct &&
- ((TypeStruct *)(fs->aggr->type->toBasetype()))->sym->dtor &&
- fs->aggr->op != TOKtype && !fs->aggr->isLvalue())
- {
- // Bugzilla 14653: Extend the life of rvalue aggregate till the end of foreach.
- vinit = copyToTemp(STCrvalue, "__aggr", fs->aggr);
- dsymbolSemantic(vinit, sc);
- fs->aggr = new VarExp(fs->aggr->loc, vinit);
- }
-
- if (!inferAggregate(fs, sc, sapply))
- {
- const char *msg = "";
- if (fs->aggr->type && isAggregate(fs->aggr->type))
- {
- msg = ", define opApply(), range primitives, or use .tupleof";
- }
- fs->error("invalid foreach aggregate %s%s", oaggr->toChars(), msg);
- return setError();
- }
-
- Dsymbol* sapplyOld = sapply; // 'sapply' will be NULL if and after 'inferApplyArgTypes' errors
-
- /* Check for inference errors
- */
- if (!inferApplyArgTypes(fs, sc, sapply))
- {
- /**
- Try and extract the parameter count of the opApply callback function, e.g.:
- int opApply(int delegate(int, float)) => 2 args
- */
- bool foundMismatch = false;
- size_t foreachParamCount = 0;
- if (sapplyOld)
- {
- if (FuncDeclaration *fd = sapplyOld->isFuncDeclaration())
- {
- ParameterList fparameters = fd->getParameterList();
-
- if (fparameters.length() == 1)
- {
- // first param should be the callback function
- Parameter *fparam = fparameters[0];
- if ((fparam->type->ty == Tpointer || fparam->type->ty == Tdelegate) &&
- fparam->type->nextOf()->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)fparam->type->nextOf();
- foreachParamCount = tf->parameterList.length();
- foundMismatch = true;
- }
- }
- }
- }
-
- //printf("dim = %d, parameters->length = %d\n", dim, fs->parameters->length);
- if (foundMismatch && dim != foreachParamCount)
- {
- const char *plural = foreachParamCount > 1 ? "s" : "";
- fs->error("cannot infer argument types, expected %d argument%s, not %d",
- foreachParamCount, plural, dim);
- }
- else
- fs->error("cannot uniquely infer foreach argument types");
-
- return setError();
- }
-
- Type *tab = fs->aggr->type->toBasetype();
-
- if (tab->ty == Ttuple) // don't generate new scope for tuple loops
- {
- Statements *statements = new Statements();
- if (!makeTupleForeach(fs, false, false, false, statements, NULL, NULL))
- return setError();
-
- result = new UnrolledLoopStatement(loc, statements);
- if (LabelStatement *ls = checkLabeledLoop(sc, fs))
- ls->gotoTarget = result;
- if (fs->aggr->op == TOKtuple)
- {
- TupleExp *te = (TupleExp *)fs->aggr;
- if (te->e0)
- result = new CompoundStatement(loc, new ExpStatement(te->e0->loc, te->e0), result);
- }
- if (vinit)
- result = new CompoundStatement(loc, new ExpStatement(loc, vinit), result);
- result = statementSemantic(result, sc);
- return;
- }
-
- sym = new ScopeDsymbol();
- sym->parent = sc->scopesym;
- sym->endlinnum = fs->endloc.linnum;
- Scope *sc2 = sc->push(sym);
-
- sc2->noctor++;
-
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *p = (*fs->parameters)[i];
- if (p->storageClass & STCmanifest)
- {
- fs->error("cannot declare enum loop variables for non-unrolled foreach");
- }
- if (p->storageClass & STCalias)
- {
- fs->error("cannot declare alias loop variables for non-unrolled foreach");
- }
- }
-
- switch (tab->ty)
- {
- case Tarray:
- case Tsarray:
- {
- if (fs->checkForArgTypes())
- {
- result = fs;
- return;
- }
-
- if (dim < 1 || dim > 2)
- {
- fs->error("only one or two arguments for array foreach");
- goto Lerror2;
- }
-
- // Finish semantic on all foreach parameter types.
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *p = (*fs->parameters)[i];
- p->type = typeSemantic(p->type, loc, sc2);
- p->type = p->type->addStorageClass(p->storageClass);
- }
-
- tn = tab->nextOf()->toBasetype();
-
- if (dim == 2)
- {
- Type *tindex = (*fs->parameters)[0]->type;
- if (!tindex->isintegral())
- {
- fs->error("foreach: key cannot be of non-integral type `%s`",
- tindex->toChars());
- goto Lerror2;
- }
- /* What cases to deprecate implicit conversions for:
- * 1. foreach aggregate is a dynamic array
- * 2. foreach body is lowered to _aApply (see special case below).
- */
- Type *tv = (*fs->parameters)[1]->type->toBasetype();
- if ((tab->ty == Tarray ||
- (tn->ty != tv->ty &&
- (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) &&
- (tv->ty == Tchar || tv->ty == Twchar || tv->ty == Tdchar))) &&
- !Type::tsize_t->implicitConvTo(tindex))
- {
- fs->deprecation("foreach: loop index implicitly converted from `size_t` to `%s`",
- tindex->toChars());
- }
- }
-
- /* Look for special case of parsing char types out of char type
- * array.
- */
- if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
- {
- int i = (dim == 1) ? 0 : 1; // index of value
- Parameter *p = (*fs->parameters)[i];
- tnv = p->type->toBasetype();
- if (tnv->ty != tn->ty &&
- (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar))
- {
- if (p->storageClass & STCref)
- {
- fs->error("foreach: value of UTF conversion cannot be ref");
- goto Lerror2;
- }
- if (dim == 2)
- {
- p = (*fs->parameters)[0];
- if (p->storageClass & STCref)
- {
- fs->error("foreach: key cannot be ref");
- goto Lerror2;
- }
- }
- goto Lapply;
- }
- }
-
- for (size_t i = 0; i < dim; i++)
- {
- // Declare parameterss
- Parameter *p = (*fs->parameters)[i];
- VarDeclaration *var;
-
- if (dim == 2 && i == 0)
- {
- var = new VarDeclaration(loc, p->type->mutableOf(), Identifier::generateId("__key"), NULL);
- var->storage_class |= STCtemp | STCforeach;
- if (var->storage_class & (STCref | STCout))
- var->storage_class |= STCnodtor;
-
- fs->key = var;
- if (p->storageClass & STCref)
- {
- if (var->type->constConv(p->type) <= MATCHnomatch)
- {
- fs->error("key type mismatch, %s to ref %s",
- var->type->toChars(), p->type->toChars());
- goto Lerror2;
- }
- }
- if (tab->ty == Tsarray)
- {
- TypeSArray *ta = (TypeSArray *)tab;
- IntRange dimrange = getIntRange(ta->dim);
- // https://issues.dlang.org/show_bug.cgi?id=12504
- dimrange.imax = SignExtendedNumber(dimrange.imax.value-1);
- if (!IntRange::fromType(var->type).contains(dimrange))
- {
- fs->error("index type `%s` cannot cover index range 0..%llu", p->type->toChars(), ta->dim->toInteger());
- goto Lerror2;
- }
- fs->key->range = new IntRange(SignExtendedNumber(0), dimrange.imax);
- }
- }
- else
- {
- var = new VarDeclaration(loc, p->type, p->ident, NULL);
- var->storage_class |= STCforeach;
- var->storage_class |= p->storageClass & (STCin | STCout | STCref | STC_TYPECTOR);
- if (var->storage_class & (STCref | STCout))
- var->storage_class |= STCnodtor;
-
- fs->value = var;
- if (var->storage_class & STCref)
- {
- if (fs->aggr->checkModifiable(sc2, 1) == 2)
- var->storage_class |= STCctorinit;
-
- Type *t = tab->nextOf();
- if (t->constConv(p->type) <= MATCHnomatch)
- {
- fs->error("argument type mismatch, %s to ref %s",
- t->toChars(), p->type->toChars());
- goto Lerror2;
- }
- }
- }
- }
-
- /* Convert to a ForStatement
- * foreach (key, value; a) body =>
- * for (T[] tmp = a[], size_t key; key < tmp.length; ++key)
- * { T value = tmp[k]; body }
- *
- * foreach_reverse (key, value; a) body =>
- * for (T[] tmp = a[], size_t key = tmp.length; key--; )
- * { T value = tmp[k]; body }
- */
- Identifier *id = Identifier::generateId("__r");
- ExpInitializer *ie = new ExpInitializer(loc, new SliceExp(loc, fs->aggr, NULL, NULL));
- VarDeclaration *tmp;
- if (fs->aggr->op == TOKarrayliteral &&
- !((*fs->parameters)[dim - 1]->storageClass & STCref))
- {
- ArrayLiteralExp *ale = (ArrayLiteralExp *)fs->aggr;
- size_t edim = ale->elements ? ale->elements->length : 0;
- Type *telem = (*fs->parameters)[dim - 1]->type;
-
- // Bugzilla 12936: if telem has been specified explicitly,
- // converting array literal elements to telem might make it @nogc.
- fs->aggr = fs->aggr->implicitCastTo(sc, telem->sarrayOf(edim));
- if (fs->aggr->op == TOKerror)
- goto Lerror2;
-
- // for (T[edim] tmp = a, ...)
- tmp = new VarDeclaration(loc, fs->aggr->type, id, ie);
- }
- else
- tmp = new VarDeclaration(loc, tab->nextOf()->arrayOf(), id, ie);
- tmp->storage_class |= STCtemp;
- tmp->endlinnum = fs->endloc.linnum;
-
- Expression *tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id::length);
-
- if (!fs->key)
- {
- Identifier *idkey = Identifier::generateId("__key");
- fs->key = new VarDeclaration(loc, Type::tsize_t, idkey, NULL);
- fs->key->storage_class |= STCtemp;
- }
- else if (fs->key->type->ty != Type::tsize_t->ty)
- {
- tmp_length = new CastExp(loc, tmp_length, fs->key->type);
- }
- if (fs->op == TOKforeach_reverse)
- fs->key->_init = new ExpInitializer(loc, tmp_length);
- else
- fs->key->_init = new ExpInitializer(loc, new IntegerExp(loc, 0, fs->key->type));
-
- Statements *cs = new Statements();
- if (vinit)
- cs->push(new ExpStatement(loc, vinit));
- cs->push(new ExpStatement(loc, tmp));
- cs->push(new ExpStatement(loc, fs->key));
- Statement *forinit = new CompoundDeclarationStatement(loc, cs);
-
- Expression *cond;
- if (fs->op == TOKforeach_reverse)
- {
- // key--
- cond = new PostExp(TOKminusminus, loc, new VarExp(loc, fs->key));
- }
- else
- {
- // key < tmp.length
- cond = new CmpExp(TOKlt, loc, new VarExp(loc, fs->key), tmp_length);
- }
-
- Expression *increment = NULL;
- if (fs->op == TOKforeach)
- {
- // key += 1
- increment = new AddAssignExp(loc, new VarExp(loc, fs->key), new IntegerExp(loc, 1, fs->key->type));
- }
-
- // T value = tmp[key];
- IndexExp *indexExp = new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, fs->key));
- indexExp->indexIsInBounds = true; // disabling bounds checking in foreach statements.
- fs->value->_init = new ExpInitializer(loc, indexExp);
- Statement *ds = new ExpStatement(loc, fs->value);
-
- if (dim == 2)
- {
- Parameter *p = (*fs->parameters)[0];
- if ((p->storageClass & STCref) && p->type->equals(fs->key->type))
- {
- fs->key->range = NULL;
- AliasDeclaration *v = new AliasDeclaration(loc, p->ident, fs->key);
- fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
- }
- else
- {
- ExpInitializer *ei = new ExpInitializer(loc, new IdentifierExp(loc, fs->key->ident));
- VarDeclaration *v = new VarDeclaration(loc, p->type, p->ident, ei);
- v->storage_class |= STCforeach | (p->storageClass & STCref);
- fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
- if (fs->key->range && !p->type->isMutable())
- {
- /* Limit the range of the key to the specified range
- */
- v->range = new IntRange(fs->key->range->imin, fs->key->range->imax - SignExtendedNumber(1));
- }
- }
- }
- fs->_body = new CompoundStatement(loc, ds, fs->_body);
-
- s = new ForStatement(loc, forinit, cond, increment, fs->_body, fs->endloc);
- if (LabelStatement *ls = checkLabeledLoop(sc, fs)) // Bugzilla 15450: don't use sc2
- ls->gotoTarget = s;
- s = statementSemantic(s, sc2);
- break;
- }
-
- case Taarray:
- if (fs->op == TOKforeach_reverse)
- fs->warning("cannot use foreach_reverse with an associative array");
- if (fs->checkForArgTypes())
- {
- result = fs;
- return;
- }
-
- taa = (TypeAArray *)tab;
- if (dim < 1 || dim > 2)
- {
- fs->error("only one or two arguments for associative array foreach");
- goto Lerror2;
- }
- goto Lapply;
-
- case Tclass:
- case Tstruct:
- /* Prefer using opApply, if it exists
- */
- if (sapply)
- goto Lapply;
-
- {
- /* Look for range iteration, i.e. the properties
- * .empty, .popFront, .popBack, .front and .back
- * foreach (e; aggr) { ... }
- * translates to:
- * for (auto __r = aggr[]; !__r.empty; __r.popFront()) {
- * auto e = __r.front;
- * ...
- * }
- */
- AggregateDeclaration *ad = (tab->ty == Tclass)
- ? (AggregateDeclaration *)((TypeClass *)tab)->sym
- : (AggregateDeclaration *)((TypeStruct *)tab)->sym;
- Identifier *idfront;
- Identifier *idpopFront;
- if (fs->op == TOKforeach)
- {
- idfront = Id::Ffront;
- idpopFront = Id::FpopFront;
- }
- else
- {
- idfront = Id::Fback;
- idpopFront = Id::FpopBack;
- }
- Dsymbol *sfront = ad->search(Loc(), idfront);
- if (!sfront)
- goto Lapply;
-
- /* Generate a temporary __r and initialize it with the aggregate.
- */
- VarDeclaration *r;
- Statement *init;
- if (vinit && fs->aggr->op == TOKvar && ((VarExp *)fs->aggr)->var == vinit)
- {
- r = vinit;
- init = new ExpStatement(loc, vinit);
- }
- else
- {
- r = copyToTemp(0, "__r", fs->aggr);
- dsymbolSemantic(r, sc);
- init = new ExpStatement(loc, r);
- if (vinit)
- init = new CompoundStatement(loc, new ExpStatement(loc, vinit), init);
- }
-
- // !__r.empty
- Expression *e = new VarExp(loc, r);
- e = new DotIdExp(loc, e, Id::Fempty);
- Expression *condition = new NotExp(loc, e);
-
- // __r.idpopFront()
- e = new VarExp(loc, r);
- Expression *increment = new CallExp(loc, new DotIdExp(loc, e, idpopFront));
-
- /* Declaration statement for e:
- * auto e = __r.idfront;
- */
- e = new VarExp(loc, r);
- Expression *einit = new DotIdExp(loc, e, idfront);
- Statement *makeargs, *forbody;
- if (dim == 1)
- {
- Parameter *p = (*fs->parameters)[0];
- VarDeclaration *ve = new VarDeclaration(loc, p->type, p->ident, new ExpInitializer(loc, einit));
- ve->storage_class |= STCforeach;
- ve->storage_class |= p->storageClass & (STCin | STCout | STCref | STC_TYPECTOR);
-
- makeargs = new ExpStatement(loc, ve);
- }
- else
- {
- VarDeclaration *vd = copyToTemp(STCref, "__front", einit);
- dsymbolSemantic(vd, sc);
- makeargs = new ExpStatement(loc, vd);
-
- Type *tfront = NULL;
- if (FuncDeclaration *fd = sfront->isFuncDeclaration())
- {
- if (!fd->functionSemantic())
- goto Lrangeerr;
- tfront = fd->type;
- }
- else if (TemplateDeclaration *td = sfront->isTemplateDeclaration())
- {
- Expressions a;
- if (FuncDeclaration *f = resolveFuncCall(loc, sc, td, NULL, tab, &a, 1))
- tfront = f->type;
- }
- else if (Declaration *d = sfront->isDeclaration())
- {
- tfront = d->type;
- }
- if (!tfront || tfront->ty == Terror)
- goto Lrangeerr;
-
- if (tfront->toBasetype()->ty == Tfunction)
- tfront = tfront->toBasetype()->nextOf();
- if (tfront->ty == Tvoid)
- {
- fs->error("%s.front is void and has no value", oaggr->toChars());
- goto Lerror2;
- }
-
- // Resolve inout qualifier of front type
- tfront = tfront->substWildTo(tab->mod);
-
- Expression *ve = new VarExp(loc, vd);
- ve->type = tfront;
-
- Expressions *exps = new Expressions();
- exps->push(ve);
- int pos = 0;
- while (exps->length < dim)
- {
- pos = expandAliasThisTuples(exps, pos);
- if (pos == -1)
- break;
- }
- if (exps->length != dim)
- {
- const char *plural = exps->length > 1 ? "s" : "";
- fs->error("cannot infer argument types, expected %d argument%s, not %d",
- exps->length, plural, dim);
- goto Lerror2;
- }
-
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *p = (*fs->parameters)[i];
- Expression *exp = (*exps)[i];
- if (!p->type)
- p->type = exp->type;
- p->type = typeSemantic(p->type->addStorageClass(p->storageClass), loc, sc2);
- if (!exp->implicitConvTo(p->type))
- goto Lrangeerr;
-
- VarDeclaration *var = new VarDeclaration(loc, p->type, p->ident, new ExpInitializer(loc, exp));
- var->storage_class |= STCctfe | STCref | STCforeach;
- makeargs = new CompoundStatement(loc, makeargs, new ExpStatement(loc, var));
- }
-
- }
-
- forbody = new CompoundStatement(loc,
- makeargs, fs->_body);
-
- s = new ForStatement(loc, init, condition, increment, forbody, fs->endloc);
- if (LabelStatement *ls = checkLabeledLoop(sc, fs))
- ls->gotoTarget = s;
- s = statementSemantic(s, sc2);
- break;
-
- Lrangeerr:
- fs->error("cannot infer argument types");
- goto Lerror2;
- }
- case Tdelegate:
- if (fs->op == TOKforeach_reverse)
- fs->deprecation("cannot use foreach_reverse with a delegate");
- Lapply:
- {
- if (fs->checkForArgTypes())
- {
- fs->_body = semanticNoScope(fs->_body, sc2);
- result = fs;
- return;
- }
-
- TypeFunction *tfld = NULL;
- if (sapply)
- {
- FuncDeclaration *fdapply = sapply->isFuncDeclaration();
- if (fdapply)
- {
- assert(fdapply->type && fdapply->type->ty == Tfunction);
- tfld = (TypeFunction *)typeSemantic(fdapply->type, loc, sc2);
- goto Lget;
- }
- else if (tab->ty == Tdelegate)
- {
- tfld = (TypeFunction *)tab->nextOf();
- Lget:
- //printf("tfld = %s\n", tfld->toChars());
- if (tfld->parameterList.parameters->length == 1)
- {
- Parameter *p = tfld->parameterList[0];
- if (p->type && p->type->ty == Tdelegate)
- {
- Type *t = typeSemantic(p->type, loc, sc2);
- assert(t->ty == Tdelegate);
- tfld = (TypeFunction *)t->nextOf();
- }
- }
- }
- }
-
- /* Turn body into the function literal:
- * int delegate(ref T param) { body }
- */
- Parameters *params = new Parameters();
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *p = (*fs->parameters)[i];
- StorageClass stc = STCref;
- Identifier *id;
-
- p->type = typeSemantic(p->type, loc, sc2);
- p->type = p->type->addStorageClass(p->storageClass);
- if (tfld)
- {
- Parameter *prm = tfld->parameterList[i];
- //printf("\tprm = %s%s\n", (prm->storageClass&STCref?"ref ":""), prm->ident->toChars());
- stc = prm->storageClass & STCref;
- id = p->ident; // argument copy is not need.
- if ((p->storageClass & STCref) != stc)
- {
- if (!stc)
- {
- fs->error("foreach: cannot make %s ref", p->ident->toChars());
- goto Lerror2;
- }
- goto LcopyArg;
- }
- }
- else if (p->storageClass & STCref)
- {
- // default delegate parameters are marked as ref, then
- // argument copy is not need.
- id = p->ident;
- }
- else
- {
- // Make a copy of the ref argument so it isn't
- // a reference.
- LcopyArg:
- id = Identifier::generateId("__applyArg", (int)i);
-
- Initializer *ie = new ExpInitializer(Loc(), new IdentifierExp(Loc(), id));
- VarDeclaration *v = new VarDeclaration(Loc(), p->type, p->ident, ie);
- v->storage_class |= STCtemp;
- s = new ExpStatement(Loc(), v);
- fs->_body = new CompoundStatement(loc, s, fs->_body);
- }
- params->push(new Parameter(stc, p->type, id, NULL, NULL));
- }
- // Bugzilla 13840: Throwable nested function inside nothrow function is acceptable.
- StorageClass stc = mergeFuncAttrs(STCsafe | STCpure | STCnogc, fs->func);
- tfld = new TypeFunction(ParameterList(params), Type::tint32, LINKd, stc);
- fs->cases = new Statements();
- fs->gotos = new ScopeStatements();
- FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, Loc(), tfld, TOKdelegate, fs);
- fld->fbody = fs->_body;
- Expression *flde = new FuncExp(loc, fld);
- flde = expressionSemantic(flde, sc2);
- fld->tookAddressOf = 0;
-
- // Resolve any forward referenced goto's
- for (size_t i = 0; i < fs->gotos->length; i++)
- {
- GotoStatement *gs = (GotoStatement *)(*fs->gotos)[i]->statement;
- if (!gs->label->statement)
- {
- // 'Promote' it to this scope, and replace with a return
- fs->cases->push(gs);
- s = new ReturnStatement(Loc(), new IntegerExp(fs->cases->length + 1));
- (*fs->gotos)[i]->statement = s;
- }
- }
-
- Expression *e = NULL;
- Expression *ec;
- if (vinit)
- {
- e = new DeclarationExp(loc, vinit);
- e = expressionSemantic(e, sc2);
- if (e->op == TOKerror)
- goto Lerror2;
- }
-
- if (taa)
- {
- // Check types
- Parameter *p = (*fs->parameters)[0];
- bool isRef = (p->storageClass & STCref) != 0;
- Type *ta = p->type;
- if (dim == 2)
- {
- Type *ti = (isRef ? taa->index->addMod(MODconst) : taa->index);
- if (isRef ? !ti->constConv(ta) : !ti->implicitConvTo(ta))
- {
- fs->error("foreach: index must be type %s, not %s", ti->toChars(), ta->toChars());
- goto Lerror2;
- }
- p = (*fs->parameters)[1];
- isRef = (p->storageClass & STCref) != 0;
- ta = p->type;
- }
- Type *taav = taa->nextOf();
- if (isRef ? !taav->constConv(ta) : !taav->implicitConvTo(ta))
- {
- fs->error("foreach: value must be type %s, not %s", taav->toChars(), ta->toChars());
- goto Lerror2;
- }
-
- /* Call:
- * extern(C) int _aaApply(void*, in size_t, int delegate(void*))
- * _aaApply(aggr, keysize, flde)
- *
- * extern(C) int _aaApply2(void*, in size_t, int delegate(void*, void*))
- * _aaApply2(aggr, keysize, flde)
- */
- static const char *name[2] = { "_aaApply", "_aaApply2" };
- static FuncDeclaration *fdapply[2] = { NULL, NULL };
- static TypeDelegate *fldeTy[2] = { NULL, NULL };
-
- unsigned char i = (dim == 2 ? 1 : 0);
- if (!fdapply[i])
- {
- params = new Parameters();
- params->push(new Parameter(0, Type::tvoid->pointerTo(), NULL, NULL, NULL));
- params->push(new Parameter(STCin, Type::tsize_t, NULL, NULL, NULL));
- Parameters* dgparams = new Parameters;
- dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL, NULL));
- if (dim == 2)
- dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL, NULL));
- fldeTy[i] = new TypeDelegate(new TypeFunction(ParameterList(dgparams),
- Type::tint32, LINKd));
- params->push(new Parameter(0, fldeTy[i], NULL, NULL, NULL));
- fdapply[i] = FuncDeclaration::genCfunc(params, Type::tint32, name[i]);
- }
-
- Expressions *exps = new Expressions();
- exps->push(fs->aggr);
- d_uns64 keysize = taa->index->size();
- if (keysize == SIZE_INVALID)
- goto Lerror2;
- assert(keysize < UINT64_MAX - target.ptrsize);
- keysize = (keysize + (target.ptrsize - 1)) & ~(target.ptrsize - 1);
- // paint delegate argument to the type runtime expects
- if (!fldeTy[i]->equals(flde->type))
- {
- flde = new CastExp(loc, flde, flde->type);
- flde->type = fldeTy[i];
- }
- exps->push(new IntegerExp(Loc(), keysize, Type::tsize_t));
- exps->push(flde);
-
- ec = new VarExp(Loc(), fdapply[i], false);
- ec = new CallExp(loc, ec, exps);
- ec->type = Type::tint32; // don't run semantic() on ec
- }
- else if (tab->ty == Tarray || tab->ty == Tsarray)
- {
- /* Call:
- * _aApply(aggr, flde)
- */
- static const char fntab[9][3] =
- { "cc","cw","cd",
- "wc","cc","wd",
- "dc","dw","dd"
- };
- const int BUFFER_LEN = 7+1+2+ sizeof(dim)*3 + 1;
- char fdname[BUFFER_LEN];
- int flag;
-
- switch (tn->ty)
- {
- case Tchar: flag = 0; break;
- case Twchar: flag = 3; break;
- case Tdchar: flag = 6; break;
- default: assert(0);
- }
- switch (tnv->ty)
- {
- case Tchar: flag += 0; break;
- case Twchar: flag += 1; break;
- case Tdchar: flag += 2; break;
- default: assert(0);
- }
- const char *r = (fs->op == TOKforeach_reverse) ? "R" : "";
- int j = sprintf(fdname, "_aApply%s%.*s%llu", r, 2, fntab[flag], (ulonglong)dim);
- assert(j < BUFFER_LEN);
-
- FuncDeclaration *fdapply;
- TypeDelegate *dgty;
- params = new Parameters();
- params->push(new Parameter(STCin, tn->arrayOf(), NULL, NULL, NULL));
- Parameters* dgparams = new Parameters;
- dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL, NULL));
- if (dim == 2)
- dgparams->push(new Parameter(0, Type::tvoidptr, NULL, NULL, NULL));
- dgty = new TypeDelegate(new TypeFunction(ParameterList(dgparams),
- Type::tint32, LINKd));
- params->push(new Parameter(0, dgty, NULL, NULL, NULL));
- fdapply = FuncDeclaration::genCfunc(params, Type::tint32, fdname);
-
- if (tab->ty == Tsarray)
- fs->aggr = fs->aggr->castTo(sc2, tn->arrayOf());
-
- // paint delegate argument to the type runtime expects
- if (!dgty->equals(flde->type)) {
- flde = new CastExp(loc, flde, flde->type);
- flde->type = dgty;
- }
-
- ec = new VarExp(Loc(), fdapply, false);
- ec = new CallExp(loc, ec, fs->aggr, flde);
- ec->type = Type::tint32; // don't run semantic() on ec
- }
- else if (tab->ty == Tdelegate)
- {
- /* Call:
- * aggr(flde)
- */
- if (fs->aggr->op == TOKdelegate &&
- ((DelegateExp *)fs->aggr)->func->isNested())
- {
- // See Bugzilla 3560
- fs->aggr = ((DelegateExp *)fs->aggr)->e1;
- }
- ec = new CallExp(loc, fs->aggr, flde);
- ec = expressionSemantic(ec, sc2);
- if (ec->op == TOKerror)
- goto Lerror2;
- if (ec->type != Type::tint32)
- {
- fs->error("opApply() function for %s must return an int", tab->toChars());
- goto Lerror2;
- }
- }
- else
- {
- if (global.params.vsafe)
- fld->tookAddressOf = 1; // allocate a closure unless the opApply() uses 'scope'
-
- assert(tab->ty == Tstruct || tab->ty == Tclass);
- assert(sapply);
- /* Call:
- * aggr.apply(flde)
- */
- ec = new DotIdExp(loc, fs->aggr, sapply->ident);
- ec = new CallExp(loc, ec, flde);
- ec = expressionSemantic(ec, sc2);
- if (ec->op == TOKerror)
- goto Lerror2;
- if (ec->type != Type::tint32)
- {
- fs->error("opApply() function for %s must return an int", tab->toChars());
- goto Lerror2;
- }
- }
- e = Expression::combine(e, ec);
-
- if (!fs->cases->length)
- {
- // Easy case, a clean exit from the loop
- e = new CastExp(loc, e, Type::tvoid); // Bugzilla 13899
- s = new ExpStatement(loc, e);
- }
- else
- {
- // Construct a switch statement around the return value
- // of the apply function.
- Statements *a = new Statements();
-
- // default: break; takes care of cases 0 and 1
- s = new BreakStatement(Loc(), NULL);
- s = new DefaultStatement(Loc(), s);
- a->push(s);
-
- // cases 2...
- for (size_t i = 0; i < fs->cases->length; i++)
- {
- s = (*fs->cases)[i];
- s = new CaseStatement(Loc(), new IntegerExp(i + 2), s);
- a->push(s);
- }
-
- s = new CompoundStatement(loc, a);
- s = new SwitchStatement(loc, e, s, false);
- }
- s = statementSemantic(s, sc2);
- break;
- }
- case Terror:
- Lerror2:
- s = new ErrorStatement();
- break;
-
- default:
- fs->error("foreach: %s is not an aggregate type", fs->aggr->type->toChars());
- goto Lerror2;
- }
- sc2->noctor--;
- sc2->pop();
- result = s;
- }
-
- void visit(ForeachRangeStatement *fs)
- {
- //printf("ForeachRangeStatement::semantic() %p\n", fs);
- Loc loc = fs->loc;
- fs->lwr = expressionSemantic(fs->lwr, sc);
- fs->lwr = resolveProperties(sc, fs->lwr);
- fs->lwr = fs->lwr->optimize(WANTvalue);
- if (!fs->lwr->type)
- {
- fs->error("invalid range lower bound %s", fs->lwr->toChars());
- Lerror:
- return setError();
- }
-
- fs->upr = expressionSemantic(fs->upr, sc);
- fs->upr = resolveProperties(sc, fs->upr);
- fs->upr = fs->upr->optimize(WANTvalue);
- if (!fs->upr->type)
- {
- fs->error("invalid range upper bound %s", fs->upr->toChars());
- goto Lerror;
- }
-
- if (fs->prm->type)
- {
- fs->prm->type = typeSemantic(fs->prm->type, loc, sc);
- fs->prm->type = fs->prm->type->addStorageClass(fs->prm->storageClass);
- fs->lwr = fs->lwr->implicitCastTo(sc, fs->prm->type);
-
- if (fs->upr->implicitConvTo(fs->prm->type) || (fs->prm->storageClass & STCref))
- {
- fs->upr = fs->upr->implicitCastTo(sc, fs->prm->type);
- }
- else
- {
- // See if upr-1 fits in prm->type
- Expression *limit = new MinExp(loc, fs->upr, new IntegerExp(1));
- limit = expressionSemantic(limit, sc);
- limit = limit->optimize(WANTvalue);
- if (!limit->implicitConvTo(fs->prm->type))
- {
- fs->upr = fs->upr->implicitCastTo(sc, fs->prm->type);
- }
- }
- }
- else
- {
- /* Must infer types from lwr and upr
- */
- Type *tlwr = fs->lwr->type->toBasetype();
- if (tlwr->ty == Tstruct || tlwr->ty == Tclass)
- {
- /* Just picking the first really isn't good enough.
- */
- fs->prm->type = fs->lwr->type;
- }
- else if (fs->lwr->type == fs->upr->type)
- {
- /* Same logic as CondExp ?lwr:upr
- */
- fs->prm->type = fs->lwr->type;
- }
- else
- {
- AddExp ea(loc, fs->lwr, fs->upr);
- if (typeCombine(&ea, sc))
- return setError();
- fs->prm->type = ea.type;
- fs->lwr = ea.e1;
- fs->upr = ea.e2;
- }
- fs->prm->type = fs->prm->type->addStorageClass(fs->prm->storageClass);
- }
- if (fs->prm->type->ty == Terror ||
- fs->lwr->op == TOKerror ||
- fs->upr->op == TOKerror)
- {
- return setError();
- }
-
- /* Convert to a for loop:
- * foreach (key; lwr .. upr) =>
- * for (auto key = lwr, auto tmp = upr; key < tmp; ++key)
- *
- * foreach_reverse (key; lwr .. upr) =>
- * for (auto tmp = lwr, auto key = upr; key-- > tmp;)
- */
- ExpInitializer *ie = new ExpInitializer(loc, (fs->op == TOKforeach) ? fs->lwr : fs->upr);
- fs->key = new VarDeclaration(loc, fs->upr->type->mutableOf(), Identifier::generateId("__key"), ie);
- fs->key->storage_class |= STCtemp;
- SignExtendedNumber lower = getIntRange(fs->lwr).imin;
- SignExtendedNumber upper = getIntRange(fs->upr).imax;
- if (lower <= upper)
- {
- fs->key->range = new IntRange(lower, upper);
- }
-
- Identifier *id = Identifier::generateId("__limit");
- ie = new ExpInitializer(loc, (fs->op == TOKforeach) ? fs->upr : fs->lwr);
- VarDeclaration *tmp = new VarDeclaration(loc, fs->upr->type, id, ie);
- tmp->storage_class |= STCtemp;
-
- Statements *cs = new Statements();
- // Keep order of evaluation as lwr, then upr
- if (fs->op == TOKforeach)
- {
- cs->push(new ExpStatement(loc, fs->key));
- cs->push(new ExpStatement(loc, tmp));
- }
- else
- {
- cs->push(new ExpStatement(loc, tmp));
- cs->push(new ExpStatement(loc, fs->key));
- }
- Statement *forinit = new CompoundDeclarationStatement(loc, cs);
-
- Expression *cond;
- if (fs->op == TOKforeach_reverse)
- {
- cond = new PostExp(TOKminusminus, loc, new VarExp(loc, fs->key));
- if (fs->prm->type->isscalar())
- {
- // key-- > tmp
- cond = new CmpExp(TOKgt, loc, cond, new VarExp(loc, tmp));
- }
- else
- {
- // key-- != tmp
- cond = new EqualExp(TOKnotequal, loc, cond, new VarExp(loc, tmp));
- }
- }
- else
- {
- if (fs->prm->type->isscalar())
- {
- // key < tmp
- cond = new CmpExp(TOKlt, loc, new VarExp(loc, fs->key), new VarExp(loc, tmp));
- }
- else
- {
- // key != tmp
- cond = new EqualExp(TOKnotequal, loc, new VarExp(loc, fs->key), new VarExp(loc, tmp));
- }
- }
-
- Expression *increment = NULL;
- if (fs->op == TOKforeach)
- {
- // key += 1
- //increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1));
- increment = new PreExp(TOKpreplusplus, loc, new VarExp(loc, fs->key));
- }
-
- if ((fs->prm->storageClass & STCref) && fs->prm->type->equals(fs->key->type))
- {
- fs->key->range = NULL;
- AliasDeclaration *v = new AliasDeclaration(loc, fs->prm->ident, fs->key);
- fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
- }
- else
- {
- ie = new ExpInitializer(loc, new CastExp(loc, new VarExp(loc, fs->key), fs->prm->type));
- VarDeclaration *v = new VarDeclaration(loc, fs->prm->type, fs->prm->ident, ie);
- v->storage_class |= STCtemp | STCforeach | (fs->prm->storageClass & STCref);
- fs->_body = new CompoundStatement(loc, new ExpStatement(loc, v), fs->_body);
- if (fs->key->range && !fs->prm->type->isMutable())
- {
- /* Limit the range of the key to the specified range
- */
- v->range = new IntRange(fs->key->range->imin, fs->key->range->imax - SignExtendedNumber(1));
- }
- }
- if (fs->prm->storageClass & STCref)
- {
- if (fs->key->type->constConv(fs->prm->type) <= MATCHnomatch)
- {
- fs->error("prmument type mismatch, %s to ref %s",
- fs->key->type->toChars(), fs->prm->type->toChars());
- goto Lerror;
- }
- }
-
- ForStatement *s = new ForStatement(loc, forinit, cond, increment, fs->_body, fs->endloc);
- if (LabelStatement *ls = checkLabeledLoop(sc, fs))
- ls->gotoTarget = s;
- result = statementSemantic(s, sc);
- }
-
- void visit(IfStatement *ifs)
- {
- // Evaluate at runtime
- unsigned cs0 = sc->callSuper;
- unsigned cs1;
- unsigned *fi0 = sc->saveFieldInit();
- unsigned *fi1 = NULL;
-
- // check in syntax level
- ifs->condition = checkAssignmentAsCondition(ifs->condition);
-
- ScopeDsymbol *sym = new ScopeDsymbol();
- sym->parent = sc->scopesym;
- sym->endlinnum = ifs->endloc.linnum;
- Scope *scd = sc->push(sym);
- if (ifs->prm)
- {
- /* Declare prm, which we will set to be the
- * result of condition.
- */
- ExpInitializer *ei = new ExpInitializer(ifs->loc, ifs->condition);
- ifs->match = new VarDeclaration(ifs->loc, ifs->prm->type, ifs->prm->ident, ei);
- ifs->match->parent = sc->func;
- ifs->match->storage_class |= ifs->prm->storageClass;
- dsymbolSemantic(ifs->match, scd);
-
- DeclarationExp *de = new DeclarationExp(ifs->loc, ifs->match);
- VarExp *ve = new VarExp(ifs->loc, ifs->match);
- ifs->condition = new CommaExp(ifs->loc, de, ve);
- ifs->condition = expressionSemantic(ifs->condition, scd);
-
- if (ifs->match->edtor)
- {
- Statement *sdtor = new DtorExpStatement(ifs->loc, ifs->match->edtor, ifs->match);
- sdtor = new ScopeGuardStatement(ifs->loc, TOKon_scope_exit, sdtor);
- ifs->ifbody = new CompoundStatement(ifs->loc, sdtor, ifs->ifbody);
- ifs->match->storage_class |= STCnodtor;
- }
- }
- else
- {
- if (ifs->condition->op == TOKdotid)
- ((DotIdExp *)ifs->condition)->noderef = true;
-
- ifs->condition = expressionSemantic(ifs->condition, sc);
- ifs->condition = resolveProperties(sc, ifs->condition);
- ifs->condition = ifs->condition->addDtorHook(sc);
- }
- if (checkNonAssignmentArrayOp(ifs->condition))
- ifs->condition = new ErrorExp();
- ifs->condition = checkGC(sc, ifs->condition);
-
- // Convert to boolean after declaring prm so this works:
- // if (S prm = S()) {}
- // where S is a struct that defines opCast!bool.
- ifs->condition = ifs->condition->toBoolean(sc);
-
- // If we can short-circuit evaluate the if statement, don't do the
- // semantic analysis of the skipped code.
- // This feature allows a limited form of conditional compilation.
- ifs->condition = ifs->condition->optimize(WANTvalue);
- ifs->ifbody = semanticNoScope(ifs->ifbody, scd);
- scd->pop();
-
- cs1 = sc->callSuper;
- fi1 = sc->fieldinit;
- sc->callSuper = cs0;
- sc->fieldinit = fi0;
- if (ifs->elsebody)
- ifs->elsebody = semanticScope(ifs->elsebody, sc, NULL, NULL);
- sc->mergeCallSuper(ifs->loc, cs1);
- sc->mergeFieldInit(ifs->loc, fi1);
-
- if (ifs->condition->op == TOKerror ||
- (ifs->ifbody && ifs->ifbody->isErrorStatement()) ||
- (ifs->elsebody && ifs->elsebody->isErrorStatement()))
- {
- return setError();
- }
- result = ifs;
- }
-
- void visit(ConditionalStatement *cs)
- {
- //printf("ConditionalStatement::semantic()\n");
-
- // If we can short-circuit evaluate the if statement, don't do the
- // semantic analysis of the skipped code.
- // This feature allows a limited form of conditional compilation.
- if (cs->condition->include(sc))
- {
- DebugCondition *dc = cs->condition->isDebugCondition();
- if (dc)
- {
- sc = sc->push();
- sc->flags |= SCOPEdebug;
- cs->ifbody = statementSemantic(cs->ifbody, sc);
- sc->pop();
- }
- else
- cs->ifbody = statementSemantic(cs->ifbody, sc);
- result = cs->ifbody;
- }
- else
- {
- if (cs->elsebody)
- cs->elsebody = statementSemantic(cs->elsebody, sc);
- result = cs->elsebody;
- }
- }
-
- void visit(PragmaStatement *ps)
- {
- // Should be merged with PragmaDeclaration
- //printf("PragmaStatement::semantic() %s\n", ps->toChars());
- //printf("body = %p\n", ps->_body);
- if (ps->ident == Id::msg)
- {
- if (ps->args)
- {
- for (size_t i = 0; i < ps->args->length; i++)
- {
- Expression *e = (*ps->args)[i];
-
- sc = sc->startCTFE();
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
- sc = sc->endCTFE();
- // pragma(msg) is allowed to contain types as well as expressions
- e = ctfeInterpretForPragmaMsg(e);
- if (e->op == TOKerror)
- {
- errorSupplemental(ps->loc, "while evaluating pragma(msg, %s)", (*ps->args)[i]->toChars());
- goto Lerror;
- }
- StringExp *se = e->toStringExp();
- if (se)
- {
- se = se->toUTF8(sc);
- fprintf(stderr, "%.*s", (int)se->len, (char *)se->string);
- }
- else
- fprintf(stderr, "%s", e->toChars());
- }
- fprintf(stderr, "\n");
- }
- }
- else if (ps->ident == Id::lib)
- {
- /* Should this be allowed?
- */
- ps->error("pragma(lib) not allowed as statement");
- goto Lerror;
- }
- else if (ps->ident == Id::startaddress)
- {
- if (!ps->args || ps->args->length != 1)
- ps->error("function name expected for start address");
- else
- {
- Expression *e = (*ps->args)[0];
-
- sc = sc->startCTFE();
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
- sc = sc->endCTFE();
-
- e = e->ctfeInterpret();
- (*ps->args)[0] = e;
- Dsymbol *sa = getDsymbol(e);
- if (!sa || !sa->isFuncDeclaration())
- {
- ps->error("function name expected for start address, not `%s`", e->toChars());
- goto Lerror;
- }
- if (ps->_body)
- {
- ps->_body = statementSemantic(ps->_body, sc);
- if (ps->_body->isErrorStatement())
- {
- result = ps->_body;
- return;
- }
- }
- result = ps;
- return;
- }
- }
- else if (ps->ident == Id::Pinline)
- {
- PINLINE inlining = PINLINEdefault;
- if (!ps->args || ps->args->length == 0)
- inlining = PINLINEdefault;
- else if (!ps->args || ps->args->length != 1)
- {
- ps->error("boolean expression expected for pragma(inline)");
- goto Lerror;
- }
- else
- {
- Expression *e = (*ps->args)[0];
-
- if (e->op != TOKint64 || !e->type->equals(Type::tbool))
- {
- ps->error("pragma(inline, true or false) expected, not %s", e->toChars());
- goto Lerror;
- }
-
- if (e->isBool(true))
- inlining = PINLINEalways;
- else if (e->isBool(false))
- inlining = PINLINEnever;
-
- FuncDeclaration *fd = sc->func;
- if (!fd)
- {
- ps->error("pragma(inline) is not inside a function");
- goto Lerror;
- }
- fd->inlining = inlining;
- }
- }
- else
- {
- ps->error("unrecognized pragma(%s)", ps->ident->toChars());
- goto Lerror;
- }
-
- if (ps->_body)
- {
- if (ps->ident == Id::msg || ps->ident == Id::startaddress)
- {
- ps->error("`pragma(%s)` is missing a terminating `;`", ps->ident->toChars());
- return setError();
- }
- ps->_body = statementSemantic(ps->_body, sc);
- }
- result = ps->_body;
- return;
-
- Lerror:
- return setError();
- }
-
- void visit(StaticAssertStatement *s)
- {
- semantic2(s->sa, sc);
- }
-
- void visit(SwitchStatement *ss)
- {
- //printf("SwitchStatement::semantic(%p)\n", ss);
- ss->tf = sc->tf;
- if (ss->cases)
- {
- result = ss; // already run
- return;
- }
- bool conditionError = false;
- ss->condition = expressionSemantic(ss->condition, sc);
- ss->condition = resolveProperties(sc, ss->condition);
-
- Type *att = NULL;
- TypeEnum *te = NULL;
- while (ss->condition->op != TOKerror)
- {
- // preserve enum type for final switches
- if (ss->condition->type->ty == Tenum)
- te = (TypeEnum *)ss->condition->type;
- if (ss->condition->type->isString())
- {
- // If it's not an array, cast it to one
- if (ss->condition->type->ty != Tarray)
- {
- ss->condition = ss->condition->implicitCastTo(sc, ss->condition->type->nextOf()->arrayOf());
- }
- ss->condition->type = ss->condition->type->constOf();
- break;
- }
- ss->condition = integralPromotions(ss->condition, sc);
- if (ss->condition->op != TOKerror && ss->condition->type->isintegral())
- break;
-
- AggregateDeclaration *ad = isAggregate(ss->condition->type);
- if (ad && ad->aliasthis && ss->condition->type != att)
- {
- if (!att && ss->condition->type->checkAliasThisRec())
- att = ss->condition->type;
- if (Expression *e = resolveAliasThis(sc, ss->condition, true))
- {
- ss->condition = e;
- continue;
- }
- }
-
- if (ss->condition->op != TOKerror)
- {
- ss->error("`%s` must be of integral or string type, it is a %s",
- ss->condition->toChars(), ss->condition->type->toChars());
- conditionError = true;
- break;
- }
- }
- if (checkNonAssignmentArrayOp(ss->condition))
- ss->condition = new ErrorExp();
- ss->condition = ss->condition->optimize(WANTvalue);
- ss->condition = checkGC(sc, ss->condition);
- if (ss->condition->op == TOKerror)
- conditionError = true;
-
- bool needswitcherror = false;
-
- ss->lastVar = sc->lastVar;
-
- sc = sc->push();
- sc->sbreak = ss;
- sc->sw = ss;
-
- ss->cases = new CaseStatements();
- sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead
- ss->_body = statementSemantic(ss->_body, sc);
- sc->noctor--;
-
- if (conditionError || (ss->_body && ss->_body->isErrorStatement()))
- goto Lerror;
-
- // Resolve any goto case's with exp
- for (size_t i = 0; i < ss->gotoCases.length; i++)
- {
- GotoCaseStatement *gcs = ss->gotoCases[i];
-
- if (!gcs->exp)
- {
- gcs->error("no case statement following goto case;");
- goto Lerror;
- }
-
- for (Scope *scx = sc; scx; scx = scx->enclosing)
- {
- if (!scx->sw)
- continue;
- for (size_t j = 0; j < scx->sw->cases->length; j++)
- {
- CaseStatement *cs = (*scx->sw->cases)[j];
-
- if (cs->exp->equals(gcs->exp))
- {
- gcs->cs = cs;
- goto Lfoundcase;
- }
- }
- }
- gcs->error("case %s not found", gcs->exp->toChars());
- goto Lerror;
-
- Lfoundcase:
- ;
- }
-
- if (ss->isFinal)
- {
- Type *t = ss->condition->type;
- Dsymbol *ds;
- EnumDeclaration *ed = NULL;
- if (t && ((ds = t->toDsymbol(sc)) != NULL))
- ed = ds->isEnumDeclaration(); // typedef'ed enum
- if (!ed && te && ((ds = te->toDsymbol(sc)) != NULL))
- ed = ds->isEnumDeclaration();
- if (ed)
- {
- size_t dim = ed->members->length;
- for (size_t i = 0; i < dim; i++)
- {
- EnumMember *em = (*ed->members)[i]->isEnumMember();
- if (em)
- {
- for (size_t j = 0; j < ss->cases->length; j++)
- {
- CaseStatement *cs = (*ss->cases)[j];
- if (cs->exp->equals(em->value()) ||
- (!cs->exp->type->isString() && !em->value()->type->isString() &&
- cs->exp->toInteger() == em->value()->toInteger()))
- goto L1;
- }
- ss->error("enum member %s not represented in final switch", em->toChars());
- goto Lerror;
- }
- L1:
- ;
- }
- }
- else
- needswitcherror = true;
- }
-
- if (!sc->sw->sdefault && (!ss->isFinal || needswitcherror || global.params.useAssert == CHECKENABLEon))
- {
- ss->hasNoDefault = 1;
-
- if (!ss->isFinal && (!ss->_body || !ss->_body->isErrorStatement()))
- ss->error("switch statement without a default; use `final switch` or add `default: assert(0);` or add `default: break;`");
-
- // Generate runtime error if the default is hit
- Statements *a = new Statements();
- CompoundStatement *cs;
- Statement *s;
-
- if (global.params.useSwitchError == CHECKENABLEon &&
- global.params.checkAction != CHECKACTION_halt)
- {
- if (global.params.checkAction == CHECKACTION_C)
- {
- /* Rewrite as an assert(0) and let e2ir generate
- * the call to the C assert failure function
- */
- s = new ExpStatement(ss->loc, new AssertExp(ss->loc, new IntegerExp(ss->loc, 0, Type::tint32)));
- }
- else
- s = new SwitchErrorStatement(ss->loc);
- }
- else
- s = new ExpStatement(ss->loc, new HaltExp(ss->loc));
-
- a->reserve(2);
- sc->sw->sdefault = new DefaultStatement(ss->loc, s);
- a->push(ss->_body);
- if (blockExit(ss->_body, sc->func, false) & BEfallthru)
- a->push(new BreakStatement(Loc(), NULL));
- a->push(sc->sw->sdefault);
- cs = new CompoundStatement(ss->loc, a);
- ss->_body = cs;
- }
-
- if (ss->checkLabel())
- goto Lerror;
-
- sc->pop();
- result = ss;
- return;
-
- Lerror:
- sc->pop();
- result = new ErrorStatement();
- }
-
- void visit(CaseStatement *cs)
- {
- SwitchStatement *sw = sc->sw;
- bool errors = false;
-
- //printf("CaseStatement::semantic() %s\n", cs->toChars());
- sc = sc->startCTFE();
- cs->exp = expressionSemantic(cs->exp, sc);
- cs->exp = resolveProperties(sc, cs->exp);
- sc = sc->endCTFE();
- if (sw)
- {
- cs->exp = cs->exp->implicitCastTo(sc, sw->condition->type);
- cs->exp = cs->exp->optimize(WANTvalue | WANTexpand);
-
- Expression *e = cs->exp;
- // Remove all the casts the user and/or implicitCastTo may introduce
- // otherwise we'd sometimes fail the check below.
- while (e->op == TOKcast)
- e = ((CastExp *)e)->e1;
-
- /* This is where variables are allowed as case expressions.
- */
- if (e->op == TOKvar)
- {
- VarExp *ve = (VarExp *)e;
- VarDeclaration *v = ve->var->isVarDeclaration();
- Type *t = cs->exp->type->toBasetype();
- if (v && (t->isintegral() || t->ty == Tclass))
- {
- /* Flag that we need to do special code generation
- * for this, i.e. generate a sequence of if-then-else
- */
- sw->hasVars = 1;
-
- /* TODO check if v can be uninitialized at that point.
- */
- if (!v->isConst() && !v->isImmutable())
- {
- cs->deprecation("case variables have to be const or immutable");
- }
-
- if (sw->isFinal)
- {
- cs->error("case variables not allowed in final switch statements");
- errors = true;
- }
-
- /* Also check if the VarExp is declared in a scope outside of this one.
- * 'scx' is set to the scope of the switch statement.
- */
- for (Scope *scx = sc; scx; scx = scx->enclosing)
- {
- if (scx->enclosing && scx->enclosing->sw == sw)
- continue;
- assert(scx->sw == sw);
-
- if (!scx->search(cs->exp->loc, v->ident, NULL))
- {
- cs->error("case variable `%s` declared at %s cannot be declared in switch body",
- v->toChars(), v->loc.toChars());
- errors = true;
- }
- break;
- }
- goto L1;
- }
- }
- else
- cs->exp = cs->exp->ctfeInterpret();
-
- if (StringExp *se = cs->exp->toStringExp())
- cs->exp = se;
- else if (cs->exp->op != TOKint64 && cs->exp->op != TOKerror)
- {
- cs->error("case must be a string or an integral constant, not %s", cs->exp->toChars());
- errors = true;
- }
-
- L1:
- for (size_t i = 0; i < sw->cases->length; i++)
- {
- CaseStatement *cs2 = (*sw->cases)[i];
-
- //printf("comparing '%s' with '%s'\n", cs->exp->toChars(), cs2->exp->toChars());
- if (cs2->exp->equals(cs->exp))
- {
- cs->error("duplicate case %s in switch statement", cs->exp->toChars());
- errors = true;
- break;
- }
- }
-
- sw->cases->push(cs);
-
- // Resolve any goto case's with no exp to this case statement
- for (size_t i = 0; i < sw->gotoCases.length; )
- {
- GotoCaseStatement *gcs = sw->gotoCases[i];
-
- if (!gcs->exp)
- {
- gcs->cs = cs;
- sw->gotoCases.remove(i); // remove from array
- continue;
- }
- i++;
- }
-
- if (sc->sw->tf != sc->tf)
- {
- cs->error("switch and case are in different finally blocks");
- errors = true;
- }
- }
- else
- {
- cs->error("case not in switch statement");
- errors = true;
- }
- cs->statement = statementSemantic(cs->statement, sc);
- if (cs->statement->isErrorStatement())
- {
- result = cs->statement;
- return;
- }
- if (errors || cs->exp->op == TOKerror)
- return setError();
-
- cs->lastVar = sc->lastVar;
- result = cs;
- }
-
- void visit(CaseRangeStatement *crs)
- {
- SwitchStatement *sw = sc->sw;
- if (sw == NULL)
- {
- crs->error("case range not in switch statement");
- return setError();
- }
-
- //printf("CaseRangeStatement::semantic() %s\n", toChars());
- bool errors = false;
- if (sw->isFinal)
- {
- crs->error("case ranges not allowed in final switch");
- errors = true;
- }
-
- sc = sc->startCTFE();
- crs->first = expressionSemantic(crs->first, sc);
- crs->first = resolveProperties(sc, crs->first);
- sc = sc->endCTFE();
- crs->first = crs->first->implicitCastTo(sc, sw->condition->type);
- crs->first = crs->first->ctfeInterpret();
-
- sc = sc->startCTFE();
- crs->last = expressionSemantic(crs->last, sc);
- crs->last = resolveProperties(sc, crs->last);
- sc = sc->endCTFE();
- crs->last = crs->last->implicitCastTo(sc, sw->condition->type);
- crs->last = crs->last->ctfeInterpret();
-
- if (crs->first->op == TOKerror || crs->last->op == TOKerror || errors)
- {
- if (crs->statement)
- statementSemantic(crs->statement, sc);
- return setError();
- }
-
- uinteger_t fval = crs->first->toInteger();
- uinteger_t lval = crs->last->toInteger();
-
-
- if ( (crs->first->type->isunsigned() && fval > lval) ||
- (!crs->first->type->isunsigned() && (sinteger_t)fval > (sinteger_t)lval))
- {
- crs->error("first case %s is greater than last case %s",
- crs->first->toChars(), crs->last->toChars());
- errors = true;
- lval = fval;
- }
-
- if (lval - fval > 256)
- {
- crs->error("had %llu cases which is more than 256 cases in case range", lval - fval);
- errors = true;
- lval = fval + 256;
- }
-
- if (errors)
- return setError();
-
- /* This works by replacing the CaseRange with an array of Case's.
- *
- * case a: .. case b: s;
- * =>
- * case a:
- * [...]
- * case b:
- * s;
- */
-
- Statements *statements = new Statements();
- for (uinteger_t i = fval; i != lval + 1; i++)
- {
- Statement *s = crs->statement;
- if (i != lval) // if not last case
- s = new ExpStatement(crs->loc, (Expression *)NULL);
- Expression *e = new IntegerExp(crs->loc, i, crs->first->type);
- Statement *cs = new CaseStatement(crs->loc, e, s);
- statements->push(cs);
- }
- Statement *s = new CompoundStatement(crs->loc, statements);
- s = statementSemantic(s, sc);
- result = s;
- }
-
- void visit(DefaultStatement *ds)
- {
- //printf("DefaultStatement::semantic()\n");
- bool errors = false;
- if (sc->sw)
- {
- if (sc->sw->sdefault)
- {
- ds->error("switch statement already has a default");
- errors = true;
- }
- sc->sw->sdefault = ds;
-
- if (sc->sw->tf != sc->tf)
- {
- ds->error("switch and default are in different finally blocks");
- errors = true;
- }
- if (sc->sw->isFinal)
- {
- ds->error("default statement not allowed in final switch statement");
- errors = true;
- }
- }
- else
- {
- ds->error("default not in switch statement");
- errors = true;
- }
- ds->statement = statementSemantic(ds->statement, sc);
- if (errors || ds->statement->isErrorStatement())
- return setError();
-
- ds->lastVar = sc->lastVar;
- result = ds;
- }
-
- void visit(GotoDefaultStatement *gds)
- {
- gds->sw = sc->sw;
- if (!gds->sw)
- {
- gds->error("goto default not in switch statement");
- return setError();
- }
- if (gds->sw->isFinal)
- {
- gds->error("goto default not allowed in final switch statement");
- return setError();
- }
- result = gds;
- }
-
- void visit(GotoCaseStatement *gcs)
- {
- if (!sc->sw)
- {
- gcs->error("goto case not in switch statement");
- return setError();
- }
-
- if (gcs->exp)
- {
- gcs->exp = expressionSemantic(gcs->exp, sc);
- gcs->exp = gcs->exp->implicitCastTo(sc, sc->sw->condition->type);
- gcs->exp = gcs->exp->optimize(WANTvalue);
- if (gcs->exp->op == TOKerror)
- return setError();
- }
-
- sc->sw->gotoCases.push(gcs);
- result = gcs;
- }
-
- void visit(ReturnStatement *rs)
- {
- //printf("ReturnStatement::semantic() %s\n", toChars());
-
- FuncDeclaration *fd = sc->parent->isFuncDeclaration();
-
- if (fd->fes)
- fd = fd->fes->func; // fd is now function enclosing foreach
-
- TypeFunction *tf = (TypeFunction *)fd->type;
- assert(tf->ty == Tfunction);
-
- if (rs->exp && rs->exp->op == TOKvar && ((VarExp *)rs->exp)->var == fd->vresult)
- {
- // return vresult;
- if (sc->fes)
- {
- assert(rs->caseDim == 0);
- sc->fes->cases->push(rs);
- result = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->length + 1));
- return;
- }
- if (fd->returnLabel)
- {
- GotoStatement *gs = new GotoStatement(rs->loc, Id::returnLabel);
- gs->label = fd->returnLabel;
- result = gs;
- return;
- }
-
- if (!fd->returns)
- fd->returns = new ReturnStatements();
- fd->returns->push(rs);
- result = rs;
- return;
- }
-
- Type *tret = tf->next;
- Type *tbret = tret ? tret->toBasetype() : NULL;
-
- bool inferRef = (tf->isref && (fd->storage_class & STCauto));
- Expression *e0 = NULL;
-
- bool errors = false;
- if (sc->flags & SCOPEcontract)
- {
- rs->error("return statements cannot be in contracts");
- errors = true;
- }
- if (sc->os && sc->os->tok != TOKon_scope_failure)
- {
- rs->error("return statements cannot be in %s bodies", Token::toChars(sc->os->tok));
- errors = true;
- }
- if (sc->tf)
- {
- rs->error("return statements cannot be in finally bodies");
- errors = true;
- }
-
- if (fd->isCtorDeclaration())
- {
- if (rs->exp)
- {
- rs->error("cannot return expression from constructor");
- errors = true;
- }
-
- // Constructors implicitly do:
- // return this;
- rs->exp = new ThisExp(Loc());
- rs->exp->type = tret;
- }
- else if (rs->exp)
- {
- fd->hasReturnExp |= (fd->hasReturnExp & 1 ? 16 : 1);
-
- FuncLiteralDeclaration *fld = fd->isFuncLiteralDeclaration();
- if (tret)
- rs->exp = inferType(rs->exp, tret);
- else if (fld && fld->treq)
- rs->exp = inferType(rs->exp, fld->treq->nextOf()->nextOf());
- rs->exp = expressionSemantic(rs->exp, sc);
-
- // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (rs->exp->op == TOKtype)
- rs->exp = resolveAliasThis(sc, rs->exp);
-
- rs->exp = resolveProperties(sc, rs->exp);
- if (rs->exp->checkType())
- rs->exp = new ErrorExp();
- if (FuncDeclaration *f = isFuncAddress(rs->exp))
- {
- if (fd->inferRetType && f->checkForwardRef(rs->exp->loc))
- rs->exp = new ErrorExp();
- }
- if (checkNonAssignmentArrayOp(rs->exp))
- rs->exp = new ErrorExp();
-
- // Extract side-effect part
- rs->exp = Expression::extractLast(rs->exp, &e0);
- if (rs->exp->op == TOKcall)
- rs->exp = valueNoDtor(rs->exp);
-
- if (e0)
- e0 = e0->optimize(WANTvalue);
-
- /* Void-return function can have void typed expression
- * on return statement.
- */
- if ((tbret && tbret->ty == Tvoid) || rs->exp->type->ty == Tvoid)
- {
- if (rs->exp->type->ty != Tvoid)
- {
- rs->error("cannot return non-void from void function");
- errors = true;
-
- rs->exp = new CastExp(rs->loc, rs->exp, Type::tvoid);
- rs->exp = expressionSemantic(rs->exp, sc);
- }
-
- /* Replace:
- * return exp;
- * with:
- * exp; return;
- */
- e0 = Expression::combine(e0, rs->exp);
- rs->exp = NULL;
- }
- if (e0)
- e0 = checkGC(sc, e0);
- }
-
- if (rs->exp)
- {
- if (fd->inferRetType) // infer return type
- {
- if (!tret)
- {
- tf->next = rs->exp->type;
- }
- else if (tret->ty != Terror && !rs->exp->type->equals(tret))
- {
- int m1 = rs->exp->type->implicitConvTo(tret);
- int m2 = tret->implicitConvTo(rs->exp->type);
- //printf("exp->type = %s m2<-->m1 tret %s\n", rs->exp->type->toChars(), tret->toChars());
- //printf("m1 = %d, m2 = %d\n", m1, m2);
-
- if (m1 && m2)
- ;
- else if (!m1 && m2)
- tf->next = rs->exp->type;
- else if (m1 && !m2)
- ;
- else if (rs->exp->op != TOKerror)
- {
- rs->error("mismatched function return type inference of %s and %s",
- rs->exp->type->toChars(), tret->toChars());
- errors = true;
- tf->next = Type::terror;
- }
- }
-
- tret = tf->next;
- tbret = tret->toBasetype();
- }
-
- if (inferRef) // deduce 'auto ref'
- {
- /* Determine "refness" of function return:
- * if it's an lvalue, return by ref, else return by value
- */
- if (rs->exp->isLvalue())
- {
- /* May return by ref
- */
- if (checkReturnEscapeRef(sc, rs->exp, true))
- tf->isref = false; // return by value
- }
- else
- tf->isref = false; // return by value
-
- /* The "refness" is determined by all of return statements.
- * This means:
- * return 3; return x; // ok, x can be a value
- * return x; return 3; // ok, x can be a value
- */
- }
- }
- else
- {
- // infer return type
- if (fd->inferRetType)
- {
- if (tf->next && tf->next->ty != Tvoid)
- {
- if (tf->next->ty != Terror)
- {
- rs->error("mismatched function return type inference of void and %s",
- tf->next->toChars());
- }
- errors = true;
- tf->next = Type::terror;
- }
- else
- tf->next = Type::tvoid;
-
- tret = tf->next;
- tbret = tret->toBasetype();
- }
-
- if (inferRef) // deduce 'auto ref'
- tf->isref = false;
-
- if (tbret->ty != Tvoid) // if non-void return
- {
- if (tbret->ty != Terror)
- rs->error("return expression expected");
- errors = true;
- }
- else if (fd->isMain())
- {
- // main() returns 0, even if it returns void
- rs->exp = new IntegerExp(0);
- }
- }
-
- // If any branches have called a ctor, but this branch hasn't, it's an error
- if (sc->callSuper & CSXany_ctor &&
- !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor)))
- {
- rs->error("return without calling constructor");
- errors = true;
- }
- sc->callSuper |= CSXreturn;
- if (sc->fieldinit)
- {
- AggregateDeclaration *ad = fd->isMember2();
- assert(ad);
- size_t dim = sc->fieldinit_dim;
- for (size_t i = 0; i < dim; i++)
- {
- VarDeclaration *v = ad->fields[i];
- bool mustInit = (v->storage_class & STCnodefaultctor ||
- v->type->needsNested());
- if (mustInit && !(sc->fieldinit[i] & CSXthis_ctor))
- {
- rs->error("an earlier return statement skips field %s initialization", v->toChars());
- errors = true;
- }
- sc->fieldinit[i] |= CSXreturn;
- }
- }
-
- if (errors)
- return setError();
-
- if (sc->fes)
- {
- if (!rs->exp)
- {
- // Send out "case receiver" statement to the foreach.
- // return exp;
- Statement *s = new ReturnStatement(Loc(), rs->exp);
- sc->fes->cases->push(s);
-
- // Immediately rewrite "this" return statement as:
- // return cases->length+1;
- rs->exp = new IntegerExp(sc->fes->cases->length + 1);
- if (e0)
- {
- result = new CompoundStatement(rs->loc, new ExpStatement(rs->loc, e0), rs);
- return;
- }
- result = rs;
- return;
- }
- else
- {
- fd->buildResultVar(NULL, rs->exp->type);
- bool r = fd->vresult->checkNestedReference(sc, Loc());
- assert(!r); // vresult should be always accessible
-
- // Send out "case receiver" statement to the foreach.
- // return vresult;
- Statement *s = new ReturnStatement(Loc(), new VarExp(Loc(), fd->vresult));
- sc->fes->cases->push(s);
-
- // Save receiver index for the later rewriting from:
- // return exp;
- // to:
- // vresult = exp; retrun caseDim;
- rs->caseDim = sc->fes->cases->length + 1;
- }
- }
- if (rs->exp)
- {
- if (!fd->returns)
- fd->returns = new ReturnStatements();
- fd->returns->push(rs);
- }
- if (e0)
- {
- result = new CompoundStatement(rs->loc, new ExpStatement(rs->loc, e0), rs);
- return;
- }
- result = rs;
- }
-
- void visit(BreakStatement *bs)
- {
- //printf("BreakStatement::semantic()\n");
- // If:
- // break Identifier;
- if (bs->ident)
- {
- bs->ident = fixupLabelName(sc, bs->ident);
-
- FuncDeclaration *thisfunc = sc->func;
-
- for (Scope *scx = sc; scx; scx = scx->enclosing)
- {
- if (scx->func != thisfunc) // if in enclosing function
- {
- if (sc->fes) // if this is the body of a foreach
- {
- /* Post this statement to the fes, and replace
- * it with a return value that caller will put into
- * a switch. Caller will figure out where the break
- * label actually is.
- * Case numbers start with 2, not 0, as 0 is continue
- * and 1 is break.
- */
- sc->fes->cases->push(bs);
- result = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->length + 1));
- return;
- }
- break; // can't break to it
- }
-
- LabelStatement *ls = scx->slabel;
- if (ls && ls->ident == bs->ident)
- {
- Statement *s = ls->statement;
-
- if (!s || !s->hasBreak())
- bs->error("label `%s` has no break", bs->ident->toChars());
- else if (ls->tf != sc->tf)
- bs->error("cannot break out of finally block");
- else
- {
- ls->breaks = true;
- result = bs;
- return;
- }
- return setError();
- }
- }
- bs->error("enclosing label `%s` for break not found", bs->ident->toChars());
- return setError();
- }
- else if (!sc->sbreak)
- {
- if (sc->os && sc->os->tok != TOKon_scope_failure)
- {
- bs->error("break is not inside %s bodies", Token::toChars(sc->os->tok));
- }
- else if (sc->fes)
- {
- // Replace break; with return 1;
- result = new ReturnStatement(Loc(), new IntegerExp(1));
- return;
- }
- else
- bs->error("break is not inside a loop or switch");
- return setError();
- }
- else if (sc->sbreak->isForwardingStatement())
- {
- bs->error("must use labeled `break` within `static foreach`");
- }
- result = bs;
- }
-
- void visit(ContinueStatement *cs)
- {
- //printf("ContinueStatement::semantic() %p\n", cs);
- if (cs->ident)
- {
- cs->ident = fixupLabelName(sc, cs->ident);
-
- Scope *scx;
- FuncDeclaration *thisfunc = sc->func;
-
- for (scx = sc; scx; scx = scx->enclosing)
- {
- LabelStatement *ls;
-
- if (scx->func != thisfunc) // if in enclosing function
- {
- if (sc->fes) // if this is the body of a foreach
- {
- for (; scx; scx = scx->enclosing)
- {
- ls = scx->slabel;
- if (ls && ls->ident == cs->ident && ls->statement == sc->fes)
- {
- // Replace continue ident; with return 0;
- result = new ReturnStatement(Loc(), new IntegerExp(0));
- return;
- }
- }
-
- /* Post this statement to the fes, and replace
- * it with a return value that caller will put into
- * a switch. Caller will figure out where the break
- * label actually is.
- * Case numbers start with 2, not 0, as 0 is continue
- * and 1 is break.
- */
- sc->fes->cases->push(cs);
- result = new ReturnStatement(Loc(), new IntegerExp(sc->fes->cases->length + 1));
- return;
- }
- break; // can't continue to it
- }
-
- ls = scx->slabel;
- if (ls && ls->ident == cs->ident)
- {
- Statement *s = ls->statement;
-
- if (!s || !s->hasContinue())
- cs->error("label `%s` has no continue", cs->ident->toChars());
- else if (ls->tf != sc->tf)
- cs->error("cannot continue out of finally block");
- else
- {
- result = cs;
- return;
- }
- return setError();
- }
- }
- cs->error("enclosing label `%s` for continue not found", cs->ident->toChars());
- return setError();
- }
- else if (!sc->scontinue)
- {
- if (sc->os && sc->os->tok != TOKon_scope_failure)
- {
- cs->error("continue is not inside %s bodies", Token::toChars(sc->os->tok));
- }
- else if (sc->fes)
- {
- // Replace continue; with return 0;
- result = new ReturnStatement(Loc(), new IntegerExp(0));
- return;
- }
- else
- cs->error("continue is not inside a loop");
- return setError();
- }
- else if (sc->scontinue->isForwardingStatement())
- {
- cs->error("must use labeled `continue` within `static foreach`");
- }
- result = cs;
- }
-
- void visit(SynchronizedStatement *ss)
- {
- if (ss->exp)
- {
- ss->exp = expressionSemantic(ss->exp, sc);
- ss->exp = resolveProperties(sc, ss->exp);
- ss->exp = ss->exp->optimize(WANTvalue);
- ss->exp = checkGC(sc, ss->exp);
- if (ss->exp->op == TOKerror)
- goto Lbody;
- ClassDeclaration *cd = ss->exp->type->isClassHandle();
- if (!cd)
- {
- ss->error("can only synchronize on class objects, not `%s`", ss->exp->type->toChars());
- return setError();
- }
- else if (cd->isInterfaceDeclaration())
- {
- /* Cast the interface to an object, as the object has the monitor,
- * not the interface.
- */
- if (!ClassDeclaration::object)
- {
- ss->error("missing or corrupt object.d");
- fatal();
- }
-
- Type *t = ClassDeclaration::object->type;
- t = typeSemantic(t, Loc(), sc)->toBasetype();
- assert(t->ty == Tclass);
-
- ss->exp = new CastExp(ss->loc, ss->exp, t);
- ss->exp = expressionSemantic(ss->exp, sc);
- }
-
- /* Rewrite as:
- * auto tmp = exp;
- * _d_monitorenter(tmp);
- * try { body } finally { _d_monitorexit(tmp); }
- */
- VarDeclaration *tmp = copyToTemp(0, "__sync", ss->exp);
- dsymbolSemantic(tmp, sc);
-
- Statements *cs = new Statements();
- cs->push(new ExpStatement(ss->loc, tmp));
-
- Parameters* args = new Parameters;
- args->push(new Parameter(0, ClassDeclaration::object->type, NULL, NULL, NULL));
-
- FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter);
- Expression *e = new CallExp(ss->loc, new VarExp(ss->loc, fdenter, false), new VarExp(ss->loc, tmp));
- e->type = Type::tvoid; // do not run semantic on e
- cs->push(new ExpStatement(ss->loc, e));
-
- FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorexit);
- e = new CallExp(ss->loc, new VarExp(ss->loc, fdexit, false), new VarExp(ss->loc, tmp));
- e->type = Type::tvoid; // do not run semantic on e
- Statement *s = new ExpStatement(ss->loc, e);
- s = new TryFinallyStatement(ss->loc, ss->_body, s);
- cs->push(s);
-
- s = new CompoundStatement(ss->loc, cs);
- result = statementSemantic(s, sc);
- return;
- }
- else
- {
- /* Generate our own critical section, then rewrite as:
- * __gshared void* __critsec;
- * _d_criticalenter2(&__critsec);
- * try { body } finally { _d_criticalexit(__critsec); }
- */
- Identifier *id = Identifier::generateId("__critsec");
- Type *t = Type::tvoidptr;
- VarDeclaration *tmp = new VarDeclaration(ss->loc, t, id, NULL);
- tmp->storage_class |= STCtemp | STCgshared | STCstatic;
- Expression *tmpExp = new VarExp(ss->loc, tmp);
-
- Statements *cs = new Statements();
- cs->push(new ExpStatement(ss->loc, tmp));
-
- /* This is just a dummy variable for "goto skips declaration" error.
- * Backend optimizer could remove this unused variable.
- */
- VarDeclaration *v = new VarDeclaration(ss->loc, Type::tvoidptr, Identifier::generateId("__sync"), NULL);
- dsymbolSemantic(v, sc);
- cs->push(new ExpStatement(ss->loc, v));
-
- Parameters* args = new Parameters;
- args->push(new Parameter(0, t->pointerTo(), NULL, NULL, NULL));
-
- FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter, STCnothrow);
- Expression *e = new AddrExp(ss->loc, tmpExp);
- e = expressionSemantic(e, sc);
- e = new CallExp(ss->loc, new VarExp(ss->loc, fdenter, false), e);
- e->type = Type::tvoid; // do not run semantic on e
- cs->push(new ExpStatement(ss->loc, e));
-
- FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalexit, STCnothrow);
- e = expressionSemantic(tmpExp, sc);
- e = new CallExp(ss->loc, new VarExp(ss->loc, fdexit, false), e);
- e->type = Type::tvoid; // do not run semantic on e
- Statement *s = new ExpStatement(ss->loc, e);
- s = new TryFinallyStatement(ss->loc, ss->_body, s);
- cs->push(s);
-
- s = new CompoundStatement(ss->loc, cs);
- result = statementSemantic(s, sc);
- return;
- }
- Lbody:
- if (ss->_body)
- ss->_body = statementSemantic(ss->_body, sc);
- if (ss->_body && ss->_body->isErrorStatement())
- {
- result = ss->_body;
- return;
- }
- result = ss;
- }
-
- void visit(WithStatement *ws)
- {
- ScopeDsymbol *sym;
- Initializer *init;
-
- //printf("WithStatement::semantic()\n");
- ws->exp = expressionSemantic(ws->exp, sc);
- ws->exp = resolveProperties(sc, ws->exp);
- ws->exp = ws->exp->optimize(WANTvalue);
- ws->exp = checkGC(sc, ws->exp);
- if (ws->exp->op == TOKerror)
- return setError();
- if (ws->exp->op == TOKscope)
- {
- sym = new WithScopeSymbol(ws);
- sym->parent = sc->scopesym;
- sym->endlinnum = ws->endloc.linnum;
- }
- else if (ws->exp->op == TOKtype)
- {
- Dsymbol *s = ((TypeExp *)ws->exp)->type->toDsymbol(sc);
- if (!s || !s->isScopeDsymbol())
- {
- ws->error("with type %s has no members", ws->exp->toChars());
- return setError();
- }
- sym = new WithScopeSymbol(ws);
- sym->parent = sc->scopesym;
- sym->endlinnum = ws->endloc.linnum;
- }
- else
- {
- Type *t = ws->exp->type->toBasetype();
-
- Expression *olde = ws->exp;
- if (t->ty == Tpointer)
- {
- ws->exp = new PtrExp(ws->loc, ws->exp);
- ws->exp = expressionSemantic(ws->exp, sc);
- t = ws->exp->type->toBasetype();
- }
-
- assert(t);
- t = t->toBasetype();
- if (t->isClassHandle())
- {
- init = new ExpInitializer(ws->loc, ws->exp);
- ws->wthis = new VarDeclaration(ws->loc, ws->exp->type, Id::withSym, init);
- dsymbolSemantic(ws->wthis, sc);
-
- sym = new WithScopeSymbol(ws);
- sym->parent = sc->scopesym;
- sym->endlinnum = ws->endloc.linnum;
- }
- else if (t->ty == Tstruct)
- {
- if (!ws->exp->isLvalue())
- {
- /* Re-write to
- * {
- * auto __withtmp = exp
- * with(__withtmp)
- * {
- * ...
- * }
- * }
- */
- VarDeclaration *tmp = copyToTemp(0, "__withtmp", ws->exp);
- dsymbolSemantic(tmp, sc);
- ExpStatement *es = new ExpStatement(ws->loc, tmp);
- ws->exp = new VarExp(ws->loc, tmp);
- Statement *ss = new ScopeStatement(ws->loc, new CompoundStatement(ws->loc, es, ws), ws->endloc);
- result = statementSemantic(ss, sc);
- return;
- }
- Expression *e = ws->exp->addressOf();
- init = new ExpInitializer(ws->loc, e);
- ws->wthis = new VarDeclaration(ws->loc, e->type, Id::withSym, init);
- dsymbolSemantic(ws->wthis, sc);
- sym = new WithScopeSymbol(ws);
- // Need to set the scope to make use of resolveAliasThis
- sym->setScope(sc);
- sym->parent = sc->scopesym;
- sym->endlinnum = ws->endloc.linnum;
- }
- else
- {
- ws->error("with expressions must be aggregate types or pointers to them, not `%s`", olde->type->toChars());
- return setError();
- }
- }
-
- if (ws->_body)
- {
- sym->_scope = sc;
- sc = sc->push(sym);
- sc->insert(sym);
- ws->_body = statementSemantic(ws->_body, sc);
- sc->pop();
- if (ws->_body && ws->_body->isErrorStatement())
- {
- result = ws->_body;
- return;
- }
- }
-
- result = ws;
- }
-
- void visit(TryCatchStatement *tcs)
- {
- if (!global.params.useExceptions)
- {
- tcs->error("Cannot use try-catch statements with -betterC");
- return setError();
- }
-
- if (!ClassDeclaration::throwable)
- {
- tcs->error("Cannot use try-catch statements because `object.Throwable` was not declared");
- return setError();
- }
-
- unsigned flags = 0;
- const unsigned FLAGcpp = 1;
- const unsigned FLAGd = 2;
-
- tcs->_body = semanticScope(tcs->_body, sc, NULL, NULL);
- assert(tcs->_body);
-
- /* Even if body is empty, still do semantic analysis on catches
- */
- bool catchErrors = false;
- for (size_t i = 0; i < tcs->catches->length; i++)
- {
- Catch *c = (*tcs->catches)[i];
- catchSemantic(c, sc);
- if (c->errors)
- {
- catchErrors = true;
- continue;
- }
- ClassDeclaration *cd = c->type->toBasetype()->isClassHandle();
- flags |= cd->isCPPclass() ? FLAGcpp : FLAGd;
-
- // Determine if current catch 'hides' any previous catches
- for (size_t j = 0; j < i; j++)
- {
- Catch *cj = (*tcs->catches)[j];
- const char *si = c->loc.toChars();
- const char *sj = cj->loc.toChars();
-
- if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype()))
- {
- tcs->error("catch at %s hides catch at %s", sj, si);
- catchErrors = true;
- }
- }
- }
-
- if (sc->func)
- {
- if (flags == (FLAGcpp | FLAGd))
- {
- tcs->error("cannot mix catching D and C++ exceptions in the same try-catch");
- catchErrors = true;
- }
- }
-
- if (catchErrors)
- return setError();
-
- if (tcs->_body->isErrorStatement())
- {
- result = tcs->_body;
- return;
- }
-
- /* If the try body never throws, we can eliminate any catches
- * of recoverable exceptions.
- */
-
- if (!(blockExit(tcs->_body, sc->func, false) & BEthrow) && ClassDeclaration::exception)
- {
- for (size_t i = 0; i < tcs->catches->length; i++)
- {
- Catch *c = (*tcs->catches)[i];
-
- /* If catch exception type is derived from Exception
- */
- if (c->type->toBasetype()->implicitConvTo(ClassDeclaration::exception->type) &&
- (!c->handler || !c->handler->comeFrom()))
- {
- // Remove c from the array of catches
- tcs->catches->remove(i);
- --i;
- }
- }
- }
-
- if (tcs->catches->length == 0)
- {
- result = tcs->_body->hasCode() ? tcs->_body : NULL;
- return;
- }
-
- result = tcs;
- }
-
- void visit(TryFinallyStatement *tfs)
- {
- //printf("TryFinallyStatement::semantic()\n");
- tfs->_body = statementSemantic(tfs->_body, sc);
- sc = sc->push();
- sc->tf = tfs;
- sc->sbreak = NULL;
- sc->scontinue = NULL; // no break or continue out of finally block
- tfs->finalbody = semanticNoScope(tfs->finalbody, sc);
- sc->pop();
-
- if (!tfs->_body)
- {
- result = tfs->finalbody;
- return;
- }
-
- if (!tfs->finalbody)
- {
- result = tfs->_body;
- return;
- }
-
- int blockexit = blockExit(tfs->_body, sc->func, false);
-
- // if not worrying about exceptions
- if (!(global.params.useExceptions && ClassDeclaration::throwable))
- blockexit &= ~BEthrow; // don't worry about paths that otherwise may throw
-
- // Don't care about paths that halt, either
- if ((blockexit & ~BEhalt) == BEfallthru)
- {
- result = new CompoundStatement(tfs->loc, tfs->_body, tfs->finalbody);
- return;
- }
- result = tfs;
- }
-
- void visit(ScopeGuardStatement *oss)
- {
- if (oss->tok != TOKon_scope_exit)
- {
- // scope(success) and scope(failure) are rewritten to try-catch(-finally) statement,
- // so the generated catch block cannot be placed in finally block.
- // See also Catch::semantic.
- if (sc->os && sc->os->tok != TOKon_scope_failure)
- {
- // If enclosing is scope(success) or scope(exit), this will be placed in finally block.
- oss->error("cannot put %s statement inside %s", Token::toChars(oss->tok), Token::toChars(sc->os->tok));
- return setError();
- }
- if (sc->tf)
- {
- oss->error("cannot put %s statement inside finally block", Token::toChars(oss->tok));
- return setError();
- }
- }
-
- sc = sc->push();
- sc->tf = NULL;
- sc->os = oss;
- if (oss->tok != TOKon_scope_failure)
- {
- // Jump out from scope(failure) block is allowed.
- sc->sbreak = NULL;
- sc->scontinue = NULL;
- }
- oss->statement = semanticNoScope(oss->statement, sc);
- sc->pop();
-
- if (!oss->statement || oss->statement->isErrorStatement())
- {
- result = oss->statement;
- return;
- }
- result = oss;
- }
-
- void visit(ThrowStatement *ts)
- {
- //printf("ThrowStatement::semantic()\n");
-
- if (!global.params.useExceptions)
- {
- ts->error("Cannot use `throw` statements with -betterC");
- return setError();
- }
-
- if (!ClassDeclaration::throwable)
- {
- ts->error("Cannot use `throw` statements because `object.Throwable` was not declared");
- return setError();
- }
-
- FuncDeclaration *fd = sc->parent->isFuncDeclaration();
- fd->hasReturnExp |= 2;
-
- ts->exp = expressionSemantic(ts->exp, sc);
- ts->exp = resolveProperties(sc, ts->exp);
- ts->exp = checkGC(sc, ts->exp);
- if (ts->exp->op == TOKerror)
- return setError();
-
- checkThrowEscape(sc, ts->exp, false);
-
- ClassDeclaration *cd = ts->exp->type->toBasetype()->isClassHandle();
- if (!cd || ((cd != ClassDeclaration::throwable) && !ClassDeclaration::throwable->isBaseOf(cd, NULL)))
- {
- ts->error("can only throw class objects derived from Throwable, not type %s", ts->exp->type->toChars());
- return setError();
- }
-
- result = ts;
- }
-
- void visit(DebugStatement *ds)
- {
- if (ds->statement)
- {
- sc = sc->push();
- sc->flags |= SCOPEdebug;
- ds->statement = statementSemantic(ds->statement, sc);
- sc->pop();
- }
- result = ds->statement;
- }
-
- void visit(GotoStatement *gs)
- {
- //printf("GotoStatement::semantic()\n");
- FuncDeclaration *fd = sc->func;
-
- gs->ident = fixupLabelName(sc, gs->ident);
- gs->label = fd->searchLabel(gs->ident);
- gs->tf = sc->tf;
- gs->os = sc->os;
- gs->lastVar = sc->lastVar;
-
- if (!gs->label->statement && sc->fes)
- {
- /* Either the goto label is forward referenced or it
- * is in the function that the enclosing foreach is in.
- * Can't know yet, so wrap the goto in a scope statement
- * so we can patch it later, and add it to a 'look at this later'
- * list.
- */
- ScopeStatement *ss = new ScopeStatement(gs->loc, gs, gs->loc);
- sc->fes->gotos->push(ss); // 'look at this later' list
- result = ss;
- return;
- }
-
- // Add to fwdref list to check later
- if (!gs->label->statement)
- {
- if (!fd->gotos)
- fd->gotos = new GotoStatements();
- fd->gotos->push(gs);
- }
- else if (gs->checkLabel())
- return setError();
-
- result = gs;
- }
-
- void visit(LabelStatement *ls)
- {
- //printf("LabelStatement::semantic()\n");
- FuncDeclaration *fd = sc->parent->isFuncDeclaration();
-
- ls->ident = fixupLabelName(sc, ls->ident);
- ls->tf = sc->tf;
- ls->os = sc->os;
- ls->lastVar = sc->lastVar;
-
- LabelDsymbol *ls2 = fd->searchLabel(ls->ident);
- if (ls2->statement)
- {
- ls->error("label `%s` already defined", ls2->toChars());
- return setError();
- }
- else
- ls2->statement = ls;
-
- sc = sc->push();
- sc->scopesym = sc->enclosing->scopesym;
- sc->callSuper |= CSXlabel;
- if (sc->fieldinit)
- {
- size_t dim = sc->fieldinit_dim;
- for (size_t i = 0; i < dim; i++)
- sc->fieldinit[i] |= CSXlabel;
- }
- sc->slabel = ls;
- if (ls->statement)
- ls->statement = statementSemantic(ls->statement, sc);
- sc->pop();
-
- result = ls;
- }
-
- void visit(AsmStatement *s)
- {
- result = asmSemantic(s, sc);
- }
-
- void visit(CompoundAsmStatement *cas)
- {
- // Apply postfix attributes of the asm block to each statement.
- sc = sc->push();
- sc->stc |= cas->stc;
-
- for (size_t i = 0; i < cas->statements->length; i++)
- {
- Statement *s = (*cas->statements)[i];
- (*cas->statements)[i] = s ? statementSemantic(s, sc) : NULL;
- }
-
- assert(sc->func);
- // use setImpure/setGC when the deprecation cycle is over
- PURE purity;
- if (!(cas->stc & STCpure) && (purity = sc->func->isPureBypassingInference()) != PUREimpure && purity != PUREfwdref)
- cas->deprecation("asm statement is assumed to be impure - mark it with `pure` if it is not");
- if (!(cas->stc & STCnogc) && sc->func->isNogcBypassingInference())
- cas->deprecation("asm statement is assumed to use the GC - mark it with `@nogc` if it does not");
- if (!(cas->stc & (STCtrusted|STCsafe)) && sc->func->setUnsafe())
- cas->error("asm statement is assumed to be @system - mark it with `@trusted` if it is not");
-
- sc->pop();
- result = cas;
- }
-
- void visit(ImportStatement *imps)
- {
- for (size_t i = 0; i < imps->imports->length; i++)
- {
- Import *s = (*imps->imports)[i]->isImport();
- assert(!s->aliasdecls.length);
- for (size_t j = 0; j < s->names.length; j++)
- {
- Identifier *name = s->names[j];
- Identifier *alias = s->aliases[j];
-
- if (!alias)
- alias = name;
-
- TypeIdentifier *tname = new TypeIdentifier(s->loc, name);
- AliasDeclaration *ad = new AliasDeclaration(s->loc, alias, tname);
- ad->_import = s;
- s->aliasdecls.push(ad);
- }
-
- dsymbolSemantic(s, sc);
- // https://issues.dlang.org/show_bug.cgi?id=19942
- // If the module that's being imported doesn't exist, don't add it to the symbol table
- // for the current scope.
- if (s->mod != NULL)
- {
- Module::addDeferredSemantic2(s); // Bugzilla 14666
- sc->insert(s);
-
- for (size_t j = 0; j < s->aliasdecls.length; j++)
- {
- sc->insert(s->aliasdecls[j]);
- }
- }
- }
- result = imps;
- }
-};
-
-Statement *statementSemantic(Statement *s, Scope *sc)
-{
- StatementSemanticVisitor v = StatementSemanticVisitor(sc);
- s->accept(&v);
- return v.result;
-}
-
-void catchSemantic(Catch *c, Scope *sc)
-{
- //printf("Catch::semantic(%s)\n", ident->toChars());
-
- if (sc->os && sc->os->tok != TOKon_scope_failure)
- {
- // If enclosing is scope(success) or scope(exit), this will be placed in finally block.
- error(c->loc, "cannot put catch statement inside %s", Token::toChars(sc->os->tok));
- c->errors = true;
- }
- if (sc->tf)
- {
- /* This is because the _d_local_unwind() gets the stack munged
- * up on this. The workaround is to place any try-catches into
- * a separate function, and call that.
- * To fix, have the compiler automatically convert the finally
- * body into a nested function.
- */
- error(c->loc, "cannot put catch statement inside finally block");
- c->errors = true;
- }
-
- ScopeDsymbol *sym = new ScopeDsymbol();
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
-
- if (!c->type)
- {
- deprecation(c->loc, "catch statement without an exception specification is deprecated; use catch(Throwable) for old behavior");
-
- // reference .object.Throwable
- c->type = getThrowable();
- }
- c->type = typeSemantic(c->type, c->loc, sc);
- if (c->type == Type::terror)
- c->errors = true;
- else
- {
- ClassDeclaration *cd = c->type->toBasetype()->isClassHandle();
- if (!cd)
- {
- error(c->loc, "can only catch class objects, not `%s`", c->type->toChars());
- c->errors = true;
- }
- else if (cd->isCPPclass())
- {
- if (!target.cpp.exceptions)
- {
- error(c->loc, "catching C++ class objects not supported for this target");
- c->errors = true;
- }
- if (sc->func && !sc->intypeof && !c->internalCatch && sc->func->setUnsafe())
- {
- error(c->loc, "cannot catch C++ class objects in @safe code");
- c->errors = true;
- }
- }
- else if (cd != ClassDeclaration::throwable && !ClassDeclaration::throwable->isBaseOf(cd, NULL))
- {
- error(c->loc, "can only catch class objects derived from Throwable, not `%s`", c->type->toChars());
- c->errors = true;
- }
- else if (sc->func && !sc->intypeof && !c->internalCatch &&
- cd != ClassDeclaration::exception && !ClassDeclaration::exception->isBaseOf(cd, NULL) &&
- sc->func->setUnsafe())
- {
- error(c->loc, "can only catch class objects derived from Exception in @safe code, not `%s`", c->type->toChars());
- c->errors = true;
- }
-
- if (c->ident)
- {
- c->var = new VarDeclaration(c->loc, c->type, c->ident, NULL);
- dsymbolSemantic(c->var, sc);
- sc->insert(c->var);
- }
- c->handler = statementSemantic(c->handler, sc);
- if (c->handler && c->handler->isErrorStatement())
- c->errors = true;
- }
- sc->pop();
-}
-
-Statement *semanticNoScope(Statement *s, Scope *sc)
-{
- //printf("Statement::semanticNoScope() %s\n", toChars());
- if (!s->isCompoundStatement() && !s->isScopeStatement())
- {
- s = new CompoundStatement(s->loc, s); // so scopeCode() gets called
- }
- s = statementSemantic(s, sc);
- return s;
-}
-
-// Same as semanticNoScope(), but do create a new scope
-Statement *semanticScope(Statement *s, Scope *sc, Statement *sbreak, Statement *scontinue)
-{
- ScopeDsymbol *sym = new ScopeDsymbol();
- sym->parent = sc->scopesym;
- Scope *scd = sc->push(sym);
- if (sbreak)
- scd->sbreak = sbreak;
- if (scontinue)
- scd->scontinue = scontinue;
- s = semanticNoScope(s, scd);
- scd->pop();
- return s;
-}
-
-/*******************
- * See StatementSemanticVisitor.makeTupleForeach. This is a simple
- * wrapper that returns the generated statements/declarations.
- */
-Statement *makeTupleForeachStatic(Scope *sc, ForeachStatement *fs, bool needExpansion)
-{
- StatementSemanticVisitor v = StatementSemanticVisitor(sc);
- v.makeTupleForeachStatic(fs, needExpansion);
- return v.result;
-}
-
-Dsymbols *makeTupleForeachStaticDecl(Scope *sc, ForeachStatement *fs, Dsymbols *dbody, bool needExpansion)
-{
- StatementSemanticVisitor v = StatementSemanticVisitor(sc);
- return v.makeTupleForeachStaticDecl(fs, dbody, needExpansion);
-}
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
new file mode 100644
index 0000000..f067c91
--- /dev/null
+++ b/gcc/d/dmd/statementsem.d
@@ -0,0 +1,4995 @@
+/**
+ * Does semantic analysis for statements.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statementsem.d, _statementsem.d)
+ * Documentation: https://dlang.org/phobos/dmd_statementsem.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statementsem.d
+ */
+
+module dmd.statementsem;
+
+import core.stdc.stdio;
+
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arrayop;
+import dmd.arraytypes;
+import dmd.astcodegen;
+import dmd.astenums;
+import dmd.ast_node;
+import dmd.attrib;
+import dmd.blockexit;
+import dmd.clone;
+import dmd.cond;
+import dmd.ctorflow;
+import dmd.dcast;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dimport;
+import dmd.dinterpret;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.escape;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.gluelayer;
+import dmd.id;
+import dmd.identifier;
+import dmd.init;
+import dmd.intrange;
+import dmd.mtype;
+import dmd.nogc;
+import dmd.opover;
+import dmd.parse;
+import dmd.printast;
+import dmd.root.outbuffer;
+import dmd.root.string;
+import dmd.semantic2;
+import dmd.sideeffect;
+import dmd.statement;
+import dmd.staticassert;
+import dmd.target;
+import dmd.tokens;
+import dmd.typesem;
+import dmd.visitor;
+import dmd.compiler;
+
+version (DMDLIB)
+{
+ version = CallbackAPI;
+}
+
+/*****************************************
+ * CTFE requires FuncDeclaration::labtab for the interpretation.
+ * So fixing the label name inside in/out contracts is necessary
+ * for the uniqueness in labtab.
+ * Params:
+ * sc = context
+ * ident = statement label name to be adjusted
+ * Returns:
+ * adjusted label name
+ */
+private Identifier fixupLabelName(Scope* sc, Identifier ident)
+{
+ uint flags = (sc.flags & SCOPE.contract);
+ const id = ident.toString();
+ if (flags && flags != SCOPE.invariant_ &&
+ !(id.length >= 2 && id[0] == '_' && id[1] == '_')) // does not start with "__"
+ {
+ OutBuffer buf;
+ buf.writestring(flags == SCOPE.require ? "__in_" : "__out_");
+ buf.writestring(ident.toString());
+
+ ident = Identifier.idPool(buf[]);
+ }
+ return ident;
+}
+
+/*******************************************
+ * Check to see if statement is the innermost labeled statement.
+ * Params:
+ * sc = context
+ * statement = Statement to check
+ * Returns:
+ * if `true`, then the `LabelStatement`, otherwise `null`
+ */
+private LabelStatement checkLabeledLoop(Scope* sc, Statement statement)
+{
+ if (sc.slabel && sc.slabel.statement == statement)
+ {
+ return sc.slabel;
+ }
+ return null;
+}
+
+/***********************************************************
+ * Check an assignment is used as a condition.
+ * Intended to be use before the `semantic` call on `e`.
+ * Params:
+ * e = condition expression which is not yet run semantic analysis.
+ * Returns:
+ * `e` or ErrorExp.
+ */
+private Expression checkAssignmentAsCondition(Expression e)
+{
+ auto ec = lastComma(e);
+ if (ec.op == TOK.assign)
+ {
+ ec.error("assignment cannot be used as a condition, perhaps `==` was meant?");
+ return ErrorExp.get();
+ }
+ return e;
+}
+
+// Performs semantic analysis in Statement AST nodes
+extern(C++) Statement statementSemantic(Statement s, Scope* sc)
+{
+ version (CallbackAPI)
+ Compiler.onStatementSemanticStart(s, sc);
+
+ scope v = new StatementSemanticVisitor(sc);
+ s.accept(v);
+
+ version (CallbackAPI)
+ Compiler.onStatementSemanticDone(s, sc);
+
+ return v.result;
+}
+
+private extern (C++) final class StatementSemanticVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+
+ Statement result;
+ Scope* sc;
+
+ this(Scope* sc)
+ {
+ this.sc = sc;
+ }
+
+ private void setError()
+ {
+ result = new ErrorStatement();
+ }
+
+ override void visit(Statement s)
+ {
+ result = s;
+ }
+
+ override void visit(ErrorStatement s)
+ {
+ result = s;
+ }
+
+ override void visit(PeelStatement s)
+ {
+ /* "peel" off this wrapper, and don't run semantic()
+ * on the result.
+ */
+ result = s.s;
+ }
+
+ override void visit(ExpStatement s)
+ {
+ /* https://dlang.org/spec/statement.html#expression-statement
+ */
+
+ if (!s.exp)
+ {
+ result = s;
+ return;
+ }
+ //printf("ExpStatement::semantic() %s\n", exp.toChars());
+
+ // Allow CommaExp in ExpStatement because return isn't used
+ CommaExp.allow(s.exp);
+
+ s.exp = s.exp.expressionSemantic(sc);
+ s.exp = resolveProperties(sc, s.exp);
+ s.exp = s.exp.addDtorHook(sc);
+ if (checkNonAssignmentArrayOp(s.exp))
+ s.exp = ErrorExp.get();
+ if (auto f = isFuncAddress(s.exp))
+ {
+ if (f.checkForwardRef(s.exp.loc))
+ s.exp = ErrorExp.get();
+ }
+ if (discardValue(s.exp))
+ s.exp = ErrorExp.get();
+
+ s.exp = s.exp.optimize(WANTvalue);
+ s.exp = checkGC(sc, s.exp);
+ if (s.exp.op == TOK.error)
+ return setError();
+ result = s;
+ }
+
+ override void visit(CompileStatement cs)
+ {
+ /* https://dlang.org/spec/statement.html#mixin-statement
+ */
+
+ //printf("CompileStatement::semantic() %s\n", exp.toChars());
+ Statements* a = cs.flatten(sc);
+ if (!a)
+ return;
+ Statement s = new CompoundStatement(cs.loc, a);
+ result = s.statementSemantic(sc);
+ }
+
+ override void visit(CompoundStatement cs)
+ {
+ //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", cs, sc);
+ version (none)
+ {
+ foreach (i, s; cs.statements)
+ {
+ if (s)
+ printf("[%d]: %s", i, s.toChars());
+ }
+ }
+
+ for (size_t i = 0; i < cs.statements.dim;)
+ {
+ Statement s = (*cs.statements)[i];
+ if (!s)
+ {
+ ++i;
+ continue;
+ }
+
+ Statements* flt = s.flatten(sc);
+ if (flt)
+ {
+ cs.statements.remove(i);
+ cs.statements.insert(i, flt);
+ continue;
+ }
+ s = s.statementSemantic(sc);
+ (*cs.statements)[i] = s;
+ if (!s)
+ {
+ /* Remove NULL statements from the list.
+ */
+ cs.statements.remove(i);
+ continue;
+ }
+ if (s.isErrorStatement())
+ {
+ result = s; // propagate error up the AST
+ ++i;
+ continue; // look for errors in rest of statements
+ }
+ Statement sentry;
+ Statement sexception;
+ Statement sfinally;
+
+ (*cs.statements)[i] = s.scopeCode(sc, sentry, sexception, sfinally);
+ if (sentry)
+ {
+ sentry = sentry.statementSemantic(sc);
+ cs.statements.insert(i, sentry);
+ i++;
+ }
+ if (sexception)
+ sexception = sexception.statementSemantic(sc);
+ if (sexception)
+ {
+ /* Returns: true if statements[] are empty statements
+ */
+ static bool isEmpty(const Statement[] statements)
+ {
+ foreach (s; statements)
+ {
+ if (const cs = s.isCompoundStatement())
+ {
+ if (!isEmpty((*cs.statements)[]))
+ return false;
+ }
+ else
+ return false;
+ }
+ return true;
+ }
+
+ if (!sfinally && isEmpty((*cs.statements)[i + 1 .. cs.statements.dim]))
+ {
+ }
+ else
+ {
+ /* Rewrite:
+ * s; s1; s2;
+ * As:
+ * s;
+ * try { s1; s2; }
+ * catch (Throwable __o)
+ * { sexception; throw __o; }
+ */
+ auto a = new Statements();
+ a.pushSlice((*cs.statements)[i + 1 .. cs.statements.length]);
+ cs.statements.setDim(i + 1);
+
+ Statement _body = new CompoundStatement(Loc.initial, a);
+ _body = new ScopeStatement(Loc.initial, _body, Loc.initial);
+
+ Identifier id = Identifier.generateId("__o");
+
+ Statement handler = new PeelStatement(sexception);
+ if (sexception.blockExit(sc.func, false) & BE.fallthru)
+ {
+ auto ts = new ThrowStatement(Loc.initial, new IdentifierExp(Loc.initial, id));
+ ts.internalThrow = true;
+ handler = new CompoundStatement(Loc.initial, handler, ts);
+ }
+
+ auto catches = new Catches();
+ auto ctch = new Catch(Loc.initial, getThrowable(), id, handler);
+ ctch.internalCatch = true;
+ catches.push(ctch);
+
+ Statement st = new TryCatchStatement(Loc.initial, _body, catches);
+ if (sfinally)
+ st = new TryFinallyStatement(Loc.initial, st, sfinally);
+ st = st.statementSemantic(sc);
+
+ cs.statements.push(st);
+ break;
+ }
+ }
+ else if (sfinally)
+ {
+ if (0 && i + 1 == cs.statements.dim)
+ {
+ cs.statements.push(sfinally);
+ }
+ else
+ {
+ /* Rewrite:
+ * s; s1; s2;
+ * As:
+ * s; try { s1; s2; } finally { sfinally; }
+ */
+ auto a = new Statements();
+ a.pushSlice((*cs.statements)[i + 1 .. cs.statements.length]);
+ cs.statements.setDim(i + 1);
+
+ auto _body = new CompoundStatement(Loc.initial, a);
+ Statement stf = new TryFinallyStatement(Loc.initial, _body, sfinally);
+ stf = stf.statementSemantic(sc);
+ cs.statements.push(stf);
+ break;
+ }
+ }
+ i++;
+ }
+
+ /* Flatten them in place
+ */
+ void flatten(Statements* statements)
+ {
+ for (size_t i = 0; i < statements.length;)
+ {
+ Statement s = (*statements)[i];
+ if (s)
+ {
+ if (auto flt = s.flatten(sc))
+ {
+ statements.remove(i);
+ statements.insert(i, flt);
+ continue;
+ }
+ }
+ ++i;
+ }
+ }
+
+ /* https://issues.dlang.org/show_bug.cgi?id=11653
+ * 'semantic' may return another CompoundStatement
+ * (eg. CaseRangeStatement), so flatten it here.
+ */
+ flatten(cs.statements);
+
+ foreach (s; *cs.statements)
+ {
+ if (!s)
+ continue;
+
+ if (auto se = s.isErrorStatement())
+ {
+ result = se;
+ return;
+ }
+ }
+
+ if (cs.statements.length == 1)
+ {
+ result = (*cs.statements)[0];
+ return;
+ }
+ result = cs;
+ }
+
+ override void visit(UnrolledLoopStatement uls)
+ {
+ //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", uls, sc);
+ Scope* scd = sc.push();
+ scd.sbreak = uls;
+ scd.scontinue = uls;
+
+ Statement serror = null;
+ foreach (i, ref s; *uls.statements)
+ {
+ if (s)
+ {
+ //printf("[%d]: %s\n", i, s.toChars());
+ s = s.statementSemantic(scd);
+ if (s && !serror)
+ serror = s.isErrorStatement();
+ }
+ }
+
+ scd.pop();
+ result = serror ? serror : uls;
+ }
+
+ override void visit(ScopeStatement ss)
+ {
+ //printf("ScopeStatement::semantic(sc = %p)\n", sc);
+ if (!ss.statement)
+ {
+ result = ss;
+ return;
+ }
+
+ ScopeDsymbol sym = new ScopeDsymbol();
+ sym.parent = sc.scopesym;
+ sym.endlinnum = ss.endloc.linnum;
+ sc = sc.push(sym);
+
+ Statements* a = ss.statement.flatten(sc);
+ if (a)
+ {
+ ss.statement = new CompoundStatement(ss.loc, a);
+ }
+
+ ss.statement = ss.statement.statementSemantic(sc);
+ if (ss.statement)
+ {
+ if (ss.statement.isErrorStatement())
+ {
+ sc.pop();
+ result = ss.statement;
+ return;
+ }
+
+ Statement sentry;
+ Statement sexception;
+ Statement sfinally;
+ ss.statement = ss.statement.scopeCode(sc, sentry, sexception, sfinally);
+ assert(!sentry);
+ assert(!sexception);
+ if (sfinally)
+ {
+ //printf("adding sfinally\n");
+ sfinally = sfinally.statementSemantic(sc);
+ ss.statement = new CompoundStatement(ss.loc, ss.statement, sfinally);
+ }
+ }
+ sc.pop();
+ result = ss;
+ }
+
+ override void visit(ForwardingStatement ss)
+ {
+ assert(ss.sym);
+ for (Scope* csc = sc; !ss.sym.forward; csc = csc.enclosing)
+ {
+ assert(csc);
+ ss.sym.forward = csc.scopesym;
+ }
+ sc = sc.push(ss.sym);
+ sc.sbreak = ss;
+ sc.scontinue = ss;
+ ss.statement = ss.statement.statementSemantic(sc);
+ sc = sc.pop();
+ result = ss.statement;
+ }
+
+ override void visit(WhileStatement ws)
+ {
+ /* Rewrite as a for(;condition;) loop
+ * https://dlang.org/spec/statement.html#while-statement
+ */
+ Expression cond = ws.condition;
+ Statement _body = ws._body;
+ if (ws.param)
+ {
+ /**
+ * If the while loop is of form `while(auto a = exp) { loop_body }`,
+ * rewrite to:
+ *
+ * while(true)
+ * if (auto a = exp)
+ * { loop_body }
+ * else
+ * { break; }
+ */
+ _body = new IfStatement(ws.loc, ws.param, ws.condition, ws._body, new BreakStatement(ws.loc, null), ws.endloc);
+ cond = IntegerExp.createBool(true);
+ }
+ Statement s = new ForStatement(ws.loc, null, cond, null, _body, ws.endloc);
+ s = s.statementSemantic(sc);
+ result = s;
+ }
+
+ override void visit(DoStatement ds)
+ {
+ /* https://dlang.org/spec/statement.html#do-statement
+ */
+ const inLoopSave = sc.inLoop;
+ sc.inLoop = true;
+ if (ds._body)
+ ds._body = ds._body.semanticScope(sc, ds, ds, null);
+ sc.inLoop = inLoopSave;
+
+ if (ds.condition.op == TOK.dotIdentifier)
+ (cast(DotIdExp)ds.condition).noderef = true;
+
+ // check in syntax level
+ ds.condition = checkAssignmentAsCondition(ds.condition);
+
+ ds.condition = ds.condition.expressionSemantic(sc);
+ ds.condition = resolveProperties(sc, ds.condition);
+ if (checkNonAssignmentArrayOp(ds.condition))
+ ds.condition = ErrorExp.get();
+ ds.condition = ds.condition.optimize(WANTvalue);
+ ds.condition = checkGC(sc, ds.condition);
+
+ ds.condition = ds.condition.toBoolean(sc);
+
+ if (ds.condition.op == TOK.error)
+ return setError();
+ if (ds._body && ds._body.isErrorStatement())
+ {
+ result = ds._body;
+ return;
+ }
+
+ result = ds;
+ }
+
+ override void visit(ForStatement fs)
+ {
+ /* https://dlang.org/spec/statement.html#for-statement
+ */
+ //printf("ForStatement::semantic %s\n", fs.toChars());
+
+ if (fs._init)
+ {
+ /* Rewrite:
+ * for (auto v1 = i1, v2 = i2; condition; increment) { ... }
+ * to:
+ * { auto v1 = i1, v2 = i2; for (; condition; increment) { ... } }
+ * then lowered to:
+ * auto v1 = i1;
+ * try {
+ * auto v2 = i2;
+ * try {
+ * for (; condition; increment) { ... }
+ * } finally { v2.~this(); }
+ * } finally { v1.~this(); }
+ */
+ auto ainit = new Statements();
+ ainit.push(fs._init);
+ fs._init = null;
+ ainit.push(fs);
+ Statement s = new CompoundStatement(fs.loc, ainit);
+ s = new ScopeStatement(fs.loc, s, fs.endloc);
+ s = s.statementSemantic(sc);
+ if (!s.isErrorStatement())
+ {
+ if (LabelStatement ls = checkLabeledLoop(sc, fs))
+ ls.gotoTarget = fs;
+ fs.relatedLabeled = s;
+ }
+ result = s;
+ return;
+ }
+ assert(fs._init is null);
+
+ auto sym = new ScopeDsymbol();
+ sym.parent = sc.scopesym;
+ sym.endlinnum = fs.endloc.linnum;
+ sc = sc.push(sym);
+ sc.inLoop = true;
+
+ if (fs.condition)
+ {
+ if (fs.condition.op == TOK.dotIdentifier)
+ (cast(DotIdExp)fs.condition).noderef = true;
+
+ // check in syntax level
+ fs.condition = checkAssignmentAsCondition(fs.condition);
+
+ fs.condition = fs.condition.expressionSemantic(sc);
+ fs.condition = resolveProperties(sc, fs.condition);
+ if (checkNonAssignmentArrayOp(fs.condition))
+ fs.condition = ErrorExp.get();
+ fs.condition = fs.condition.optimize(WANTvalue);
+ fs.condition = checkGC(sc, fs.condition);
+
+ fs.condition = fs.condition.toBoolean(sc);
+ }
+ if (fs.increment)
+ {
+ CommaExp.allow(fs.increment);
+ fs.increment = fs.increment.expressionSemantic(sc);
+ fs.increment = resolveProperties(sc, fs.increment);
+ if (checkNonAssignmentArrayOp(fs.increment))
+ fs.increment = ErrorExp.get();
+ fs.increment = fs.increment.optimize(WANTvalue);
+ fs.increment = checkGC(sc, fs.increment);
+ }
+
+ sc.sbreak = fs;
+ sc.scontinue = fs;
+ if (fs._body)
+ fs._body = fs._body.semanticNoScope(sc);
+
+ sc.pop();
+
+ if (fs.condition && fs.condition.op == TOK.error ||
+ fs.increment && fs.increment.op == TOK.error ||
+ fs._body && fs._body.isErrorStatement())
+ return setError();
+ result = fs;
+ }
+
+ /*******************
+ * Determines the return type of makeTupleForeach.
+ */
+ private static template MakeTupleForeachRet(bool isDecl)
+ {
+ static if(isDecl)
+ {
+ alias MakeTupleForeachRet = Dsymbols*;
+ }
+ else
+ {
+ alias MakeTupleForeachRet = void;
+ }
+ }
+
+ /*******************
+ * Type check and unroll `foreach` over an expression tuple as well
+ * as `static foreach` statements and `static foreach`
+ * declarations. For `static foreach` statements and `static
+ * foreach` declarations, the visitor interface is used (and the
+ * result is written into the `result` field.) For `static
+ * foreach` declarations, the resulting Dsymbols* are returned
+ * directly.
+ *
+ * The unrolled body is wrapped into a
+ * - UnrolledLoopStatement, for `foreach` over an expression tuple.
+ * - ForwardingStatement, for `static foreach` statements.
+ * - ForwardingAttribDeclaration, for `static foreach` declarations.
+ *
+ * `static foreach` variables are declared as `STC.local`, such
+ * that they are inserted into the local symbol tables of the
+ * forwarding constructs instead of forwarded. For `static
+ * foreach` with multiple foreach loop variables whose aggregate
+ * has been lowered into a sequence of tuples, this function
+ * expands the tuples into multiple `STC.local` `static foreach`
+ * variables.
+ */
+ MakeTupleForeachRet!isDecl makeTupleForeach(bool isStatic, bool isDecl)(ForeachStatement fs, TupleForeachArgs!(isStatic, isDecl) args)
+ {
+ auto returnEarly()
+ {
+ static if (isDecl)
+ {
+ return null;
+ }
+ else
+ {
+ result = new ErrorStatement();
+ return;
+ }
+ }
+ static if(isDecl)
+ {
+ static assert(isStatic);
+ auto dbody = args[0];
+ }
+ static if(isStatic)
+ {
+ auto needExpansion = args[$-1];
+ assert(sc);
+ }
+
+ auto loc = fs.loc;
+ size_t dim = fs.parameters.dim;
+ static if(isStatic) bool skipCheck = needExpansion;
+ else enum skipCheck = false;
+ if (!skipCheck && (dim < 1 || dim > 2))
+ {
+ fs.error("only one (value) or two (key,value) arguments for tuple `foreach`");
+ setError();
+ return returnEarly();
+ }
+
+ Type paramtype = (*fs.parameters)[dim - 1].type;
+ if (paramtype)
+ {
+ paramtype = paramtype.typeSemantic(loc, sc);
+ if (paramtype.ty == Terror)
+ {
+ setError();
+ return returnEarly();
+ }
+ }
+
+ Type tab = fs.aggr.type.toBasetype();
+ TypeTuple tuple = cast(TypeTuple)tab;
+ static if(!isDecl)
+ {
+ auto statements = new Statements();
+ }
+ else
+ {
+ auto declarations = new Dsymbols();
+ }
+ //printf("aggr: op = %d, %s\n", fs.aggr.op, fs.aggr.toChars());
+ size_t n;
+ TupleExp te = null;
+ if (fs.aggr.op == TOK.tuple) // expression tuple
+ {
+ te = cast(TupleExp)fs.aggr;
+ n = te.exps.dim;
+ }
+ else if (fs.aggr.op == TOK.type) // type tuple
+ {
+ n = Parameter.dim(tuple.arguments);
+ }
+ else
+ assert(0);
+ foreach (j; 0 .. n)
+ {
+ size_t k = (fs.op == TOK.foreach_) ? j : n - 1 - j;
+ Expression e = null;
+ Type t = null;
+ if (te)
+ e = (*te.exps)[k];
+ else
+ t = Parameter.getNth(tuple.arguments, k).type;
+ Parameter p = (*fs.parameters)[0];
+ static if(!isDecl)
+ {
+ auto st = new Statements();
+ }
+ else
+ {
+ auto st = new Dsymbols();
+ }
+
+ static if(isStatic) bool skip = needExpansion;
+ else enum skip = false;
+ if (!skip && dim == 2)
+ {
+ // Declare key
+ if (p.storageClass & (STC.out_ | STC.ref_ | STC.lazy_))
+ {
+ fs.error("no storage class for key `%s`", p.ident.toChars());
+ setError();
+ return returnEarly();
+ }
+ static if(isStatic)
+ {
+ if(!p.type)
+ {
+ p.type = Type.tsize_t;
+ }
+ }
+ p.type = p.type.typeSemantic(loc, sc);
+
+ if (!p.type.isintegral())
+ {
+ fs.error("foreach: key cannot be of non-integral type `%s`",
+ p.type.toChars());
+ setError();
+ return returnEarly();
+ }
+
+ const length = te ? te.exps.length : tuple.arguments.length;
+ IntRange dimrange = IntRange(SignExtendedNumber(length))._cast(Type.tsize_t);
+ // https://issues.dlang.org/show_bug.cgi?id=12504
+ dimrange.imax = SignExtendedNumber(dimrange.imax.value-1);
+ if (!IntRange.fromType(p.type).contains(dimrange))
+ {
+ fs.error("index type `%s` cannot cover index range 0..%llu",
+ p.type.toChars(), cast(ulong)length);
+ setError();
+ return returnEarly();
+ }
+ Initializer ie = new ExpInitializer(Loc.initial, new IntegerExp(k));
+ auto var = new VarDeclaration(loc, p.type, p.ident, ie);
+ var.storage_class |= STC.manifest;
+ static if(isStatic) var.storage_class |= STC.local;
+ static if(!isDecl)
+ {
+ st.push(new ExpStatement(loc, var));
+ }
+ else
+ {
+ st.push(var);
+ }
+ p = (*fs.parameters)[1]; // value
+ }
+ /***********************
+ * Declares a unrolled `foreach` loop variable or a `static foreach` variable.
+ *
+ * Params:
+ * storageClass = The storage class of the variable.
+ * type = The declared type of the variable.
+ * ident = The name of the variable.
+ * e = The initializer of the variable (i.e. the current element of the looped over aggregate).
+ * t = The type of the initializer.
+ * Returns:
+ * `true` iff the declaration was successful.
+ */
+ bool declareVariable(StorageClass storageClass, Type type, Identifier ident, Expression e, Type t)
+ {
+ if (storageClass & (STC.out_ | STC.lazy_) ||
+ storageClass & STC.ref_ && !te)
+ {
+ fs.error("no storage class for value `%s`", ident.toChars());
+ setError();
+ return false;
+ }
+ Declaration var;
+ if (e)
+ {
+ Type tb = e.type.toBasetype();
+ Dsymbol ds = null;
+ if (!(storageClass & STC.manifest))
+ {
+ if ((isStatic || tb.ty == Tfunction || storageClass&STC.alias_) && e.op == TOK.variable)
+ ds = (cast(VarExp)e).var;
+ else if (e.op == TOK.template_)
+ ds = (cast(TemplateExp)e).td;
+ else if (e.op == TOK.scope_)
+ ds = (cast(ScopeExp)e).sds;
+ else if (e.op == TOK.function_)
+ {
+ auto fe = cast(FuncExp)e;
+ ds = fe.td ? cast(Dsymbol)fe.td : fe.fd;
+ }
+ else if (e.op == TOK.overloadSet)
+ ds = (cast(OverExp)e).vars;
+ }
+ else if (storageClass & STC.alias_)
+ {
+ fs.error("`foreach` loop variable cannot be both `enum` and `alias`");
+ setError();
+ return false;
+ }
+
+ if (ds)
+ {
+ var = new AliasDeclaration(loc, ident, ds);
+ if (storageClass & STC.ref_)
+ {
+ fs.error("symbol `%s` cannot be `ref`", ds.toChars());
+ setError();
+ return false;
+ }
+ if (paramtype)
+ {
+ fs.error("cannot specify element type for symbol `%s`", ds.toChars());
+ setError();
+ return false;
+ }
+ }
+ else if (e.op == TOK.type)
+ {
+ var = new AliasDeclaration(loc, ident, e.type);
+ if (paramtype)
+ {
+ fs.error("cannot specify element type for type `%s`", e.type.toChars());
+ setError();
+ return false;
+ }
+ }
+ else
+ {
+ e = resolveProperties(sc, e);
+ Initializer ie = new ExpInitializer(Loc.initial, e);
+ auto v = new VarDeclaration(loc, type, ident, ie, storageClass);
+ if (storageClass & STC.ref_)
+ v.storage_class |= STC.ref_ | STC.foreach_;
+ if (isStatic || storageClass&STC.manifest || e.isConst() ||
+ e.op == TOK.string_ ||
+ e.op == TOK.structLiteral ||
+ e.op == TOK.arrayLiteral)
+ {
+ if (v.storage_class & STC.ref_)
+ {
+ static if (!isStatic)
+ {
+ fs.error("constant value `%s` cannot be `ref`", ie.toChars());
+ }
+ else
+ {
+ if (!needExpansion)
+ {
+ fs.error("constant value `%s` cannot be `ref`", ie.toChars());
+ }
+ else
+ {
+ fs.error("constant value `%s` cannot be `ref`", ident.toChars());
+ }
+ }
+ setError();
+ return false;
+ }
+ else
+ v.storage_class |= STC.manifest;
+ }
+ var = v;
+ }
+ }
+ else
+ {
+ var = new AliasDeclaration(loc, ident, t);
+ if (paramtype)
+ {
+ fs.error("cannot specify element type for symbol `%s`", fs.toChars());
+ setError();
+ return false;
+ }
+ }
+ static if (isStatic)
+ {
+ var.storage_class |= STC.local;
+ }
+ static if (!isDecl)
+ {
+ st.push(new ExpStatement(loc, var));
+ }
+ else
+ {
+ st.push(var);
+ }
+ return true;
+ }
+ static if (!isStatic)
+ {
+ // Declare value
+ if (!declareVariable(p.storageClass, p.type, p.ident, e, t))
+ {
+ return returnEarly();
+ }
+ }
+ else
+ {
+ if (!needExpansion)
+ {
+ // Declare value
+ if (!declareVariable(p.storageClass, p.type, p.ident, e, t))
+ {
+ return returnEarly();
+ }
+ }
+ else
+ { // expand tuples into multiple `static foreach` variables.
+ assert(e && !t);
+ auto ident = Identifier.generateId("__value");
+ declareVariable(0, e.type, ident, e, null);
+ import dmd.cond: StaticForeach;
+ auto field = Identifier.idPool(StaticForeach.tupleFieldName.ptr,StaticForeach.tupleFieldName.length);
+ Expression access = new DotIdExp(loc, e, field);
+ access = expressionSemantic(access, sc);
+ if (!tuple) return returnEarly();
+ //printf("%s\n",tuple.toChars());
+ foreach (l; 0 .. dim)
+ {
+ auto cp = (*fs.parameters)[l];
+ Expression init_ = new IndexExp(loc, access, new IntegerExp(loc, l, Type.tsize_t));
+ init_ = init_.expressionSemantic(sc);
+ assert(init_.type);
+ declareVariable(p.storageClass, init_.type, cp.ident, init_, null);
+ }
+ }
+ }
+
+ static if (!isDecl)
+ {
+ if (fs._body) // https://issues.dlang.org/show_bug.cgi?id=17646
+ st.push(fs._body.syntaxCopy());
+ Statement res = new CompoundStatement(loc, st);
+ }
+ else
+ {
+ st.append(Dsymbol.arraySyntaxCopy(dbody));
+ }
+ static if (!isStatic)
+ {
+ res = new ScopeStatement(loc, res, fs.endloc);
+ }
+ else static if (!isDecl)
+ {
+ auto fwd = new ForwardingStatement(loc, res);
+ res = fwd;
+ }
+ else
+ {
+ import dmd.attrib: ForwardingAttribDeclaration;
+ auto res = new ForwardingAttribDeclaration(st);
+ }
+ static if (!isDecl)
+ {
+ statements.push(res);
+ }
+ else
+ {
+ declarations.push(res);
+ }
+ }
+
+ static if (!isStatic)
+ {
+ Statement res = new UnrolledLoopStatement(loc, statements);
+ if (LabelStatement ls = checkLabeledLoop(sc, fs))
+ ls.gotoTarget = res;
+ if (te && te.e0)
+ res = new CompoundStatement(loc, new ExpStatement(te.e0.loc, te.e0), res);
+ }
+ else static if (!isDecl)
+ {
+ Statement res = new CompoundStatement(loc, statements);
+ }
+ else
+ {
+ auto res = declarations;
+ }
+ static if (!isDecl)
+ {
+ result = res;
+ }
+ else
+ {
+ return res;
+ }
+ }
+
+ override void visit(ForeachStatement fs)
+ {
+ /* https://dlang.org/spec/statement.html#foreach-statement
+ */
+
+ //printf("ForeachStatement::semantic() %p\n", fs);
+
+ /******
+ * Issue error if any of the ForeachTypes were not supplied and could not be inferred.
+ * Returns:
+ * true if error issued
+ */
+ static bool checkForArgTypes(ForeachStatement fs)
+ {
+ bool result = false;
+ foreach (p; *fs.parameters)
+ {
+ if (!p.type)
+ {
+ fs.error("cannot infer type for `foreach` variable `%s`, perhaps set it explicitly", p.ident.toChars());
+ p.type = Type.terror;
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ const loc = fs.loc;
+ const dim = fs.parameters.dim;
+
+ fs.func = sc.func;
+ if (fs.func.fes)
+ fs.func = fs.func.fes.func;
+
+ VarDeclaration vinit = null;
+ fs.aggr = fs.aggr.expressionSemantic(sc);
+ fs.aggr = resolveProperties(sc, fs.aggr);
+ fs.aggr = fs.aggr.optimize(WANTvalue);
+ if (fs.aggr.op == TOK.error)
+ return setError();
+ Expression oaggr = fs.aggr; // remember original for error messages
+ if (fs.aggr.type && fs.aggr.type.toBasetype().ty == Tstruct &&
+ (cast(TypeStruct)(fs.aggr.type.toBasetype())).sym.dtor &&
+ fs.aggr.op != TOK.type && !fs.aggr.isLvalue())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=14653
+ // Extend the life of rvalue aggregate till the end of foreach.
+ vinit = copyToTemp(STC.rvalue, "__aggr", fs.aggr);
+ vinit.endlinnum = fs.endloc.linnum;
+ vinit.dsymbolSemantic(sc);
+ fs.aggr = new VarExp(fs.aggr.loc, vinit);
+ }
+
+ /* If aggregate is a vector type, add the .array to make it a static array
+ */
+ if (fs.aggr.type)
+ if (auto tv = fs.aggr.type.toBasetype().isTypeVector())
+ {
+ auto vae = new VectorArrayExp(fs.aggr.loc, fs.aggr);
+ vae.type = tv.basetype;
+ fs.aggr = vae;
+ }
+
+ Dsymbol sapply = null; // the inferred opApply() or front() function
+ if (!inferForeachAggregate(sc, fs.op == TOK.foreach_, fs.aggr, sapply))
+ {
+ const(char)* msg = "";
+ if (fs.aggr.type && isAggregate(fs.aggr.type))
+ {
+ msg = ", define `opApply()`, range primitives, or use `.tupleof`";
+ }
+ fs.error("invalid `foreach` aggregate `%s`%s", oaggr.toChars(), msg);
+ return setError();
+ }
+
+ Dsymbol sapplyOld = sapply; // 'sapply' will be NULL if and after 'inferApplyArgTypes' errors
+
+ /* Check for inference errors
+ */
+ if (!inferApplyArgTypes(fs, sc, sapply))
+ {
+ /**
+ Try and extract the parameter count of the opApply callback function, e.g.:
+ int opApply(int delegate(int, float)) => 2 args
+ */
+ bool foundMismatch = false;
+ size_t foreachParamCount = 0;
+ if (sapplyOld)
+ {
+ if (FuncDeclaration fd = sapplyOld.isFuncDeclaration())
+ {
+ auto fparameters = fd.getParameterList();
+
+ if (fparameters.length == 1)
+ {
+ // first param should be the callback function
+ Parameter fparam = fparameters[0];
+ if ((fparam.type.ty == Tpointer ||
+ fparam.type.ty == Tdelegate) &&
+ fparam.type.nextOf().ty == Tfunction)
+ {
+ TypeFunction tf = cast(TypeFunction)fparam.type.nextOf();
+ foreachParamCount = tf.parameterList.length;
+ foundMismatch = true;
+ }
+ }
+ }
+ }
+
+ //printf("dim = %d, parameters.dim = %d\n", dim, parameters.dim);
+ if (foundMismatch && dim != foreachParamCount)
+ {
+ const(char)* plural = foreachParamCount > 1 ? "s" : "";
+ fs.error("cannot infer argument types, expected %llu argument%s, not %llu",
+ cast(ulong) foreachParamCount, plural, cast(ulong) dim);
+ }
+ else
+ fs.error("cannot uniquely infer `foreach` argument types");
+
+ return setError();
+ }
+
+ Type tab = fs.aggr.type.toBasetype();
+
+ if (tab.ty == Ttuple) // don't generate new scope for tuple loops
+ {
+ makeTupleForeach!(false,false)(fs);
+ if (vinit)
+ result = new CompoundStatement(loc, new ExpStatement(loc, vinit), result);
+ result = result.statementSemantic(sc);
+ return;
+ }
+
+ auto sym = new ScopeDsymbol();
+ sym.parent = sc.scopesym;
+ sym.endlinnum = fs.endloc.linnum;
+ auto sc2 = sc.push(sym);
+ sc2.inLoop = true;
+
+ foreach (Parameter p; *fs.parameters)
+ {
+ if (p.storageClass & STC.manifest)
+ {
+ fs.error("cannot declare `enum` loop variables for non-unrolled foreach");
+ }
+ if (p.storageClass & STC.alias_)
+ {
+ fs.error("cannot declare `alias` loop variables for non-unrolled foreach");
+ }
+ }
+
+ void retError()
+ {
+ sc2.pop();
+ result = new ErrorStatement();
+ }
+
+ void rangeError()
+ {
+ fs.error("cannot infer argument types");
+ return retError();
+ }
+
+ void retStmt(Statement s)
+ {
+ if (!s)
+ return retError();
+ s = s.statementSemantic(sc2);
+ sc2.pop();
+ result = s;
+ }
+
+ TypeAArray taa = null;
+ Type tn = null;
+ Type tnv = null;
+ Statement apply()
+ {
+ if (checkForArgTypes(fs))
+ return null;
+
+ TypeFunction tfld = null;
+ if (sapply)
+ {
+ FuncDeclaration fdapply = sapply.isFuncDeclaration();
+ if (fdapply)
+ {
+ assert(fdapply.type && fdapply.type.ty == Tfunction);
+ tfld = cast(TypeFunction)fdapply.type.typeSemantic(loc, sc2);
+ goto Lget;
+ }
+ else if (tab.ty == Tdelegate)
+ {
+ tfld = cast(TypeFunction)tab.nextOf();
+ Lget:
+ //printf("tfld = %s\n", tfld.toChars());
+ if (tfld.parameterList.parameters.dim == 1)
+ {
+ Parameter p = tfld.parameterList[0];
+ if (p.type && p.type.ty == Tdelegate)
+ {
+ auto t = p.type.typeSemantic(loc, sc2);
+ assert(t.ty == Tdelegate);
+ tfld = cast(TypeFunction)t.nextOf();
+ }
+ //printf("tfld = %s\n", tfld.toChars());
+ }
+ }
+ }
+
+ FuncExp flde = foreachBodyToFunction(sc2, fs, tfld);
+ if (!flde)
+ return null;
+
+ // Resolve any forward referenced goto's
+ foreach (ScopeStatement ss; *fs.gotos)
+ {
+ GotoStatement gs = ss.statement.isGotoStatement();
+ if (!gs.label.statement)
+ {
+ // 'Promote' it to this scope, and replace with a return
+ fs.cases.push(gs);
+ ss.statement = new ReturnStatement(Loc.initial, new IntegerExp(fs.cases.dim + 1));
+ }
+ }
+
+ Expression e = null;
+ Expression ec;
+ if (vinit)
+ {
+ e = new DeclarationExp(loc, vinit);
+ e = e.expressionSemantic(sc2);
+ if (e.op == TOK.error)
+ return null;
+ }
+
+ if (taa)
+ ec = applyAssocArray(fs, flde, taa);
+ else if (tab.ty == Tarray || tab.ty == Tsarray)
+ ec = applyArray(fs, flde, sc2, tn, tnv, tab.ty);
+ else if (tab.ty == Tdelegate)
+ ec = applyDelegate(fs, flde, sc2, tab);
+ else
+ ec = applyOpApply(fs, tab, sapply, sc2, flde);
+ if (!ec)
+ return null;
+ e = Expression.combine(e, ec);
+ return loopReturn(e, fs.cases, loc);
+ }
+ switch (tab.ty)
+ {
+ case Tarray:
+ case Tsarray:
+ {
+ if (checkForArgTypes(fs))
+ return retError();
+
+ if (dim < 1 || dim > 2)
+ {
+ fs.error("only one or two arguments for array `foreach`");
+ return retError();
+ }
+
+ // Finish semantic on all foreach parameter types.
+ foreach (i; 0 .. dim)
+ {
+ Parameter p = (*fs.parameters)[i];
+ p.type = p.type.typeSemantic(loc, sc2);
+ p.type = p.type.addStorageClass(p.storageClass);
+ }
+
+ tn = tab.nextOf().toBasetype();
+
+ if (dim == 2)
+ {
+ Type tindex = (*fs.parameters)[0].type;
+ if (!tindex.isintegral())
+ {
+ fs.error("foreach: key cannot be of non-integral type `%s`", tindex.toChars());
+ return retError();
+ }
+ /* What cases to deprecate implicit conversions for:
+ * 1. foreach aggregate is a dynamic array
+ * 2. foreach body is lowered to _aApply (see special case below).
+ */
+ Type tv = (*fs.parameters)[1].type.toBasetype();
+ if ((tab.ty == Tarray ||
+ (tn.ty != tv.ty && tn.ty.isSomeChar && tv.ty.isSomeChar)) &&
+ !Type.tsize_t.implicitConvTo(tindex))
+ {
+ fs.deprecation("foreach: loop index implicitly converted from `size_t` to `%s`",
+ tindex.toChars());
+ }
+ }
+
+ /* Look for special case of parsing char types out of char type
+ * array.
+ */
+ if (tn.ty.isSomeChar)
+ {
+ int i = (dim == 1) ? 0 : 1; // index of value
+ Parameter p = (*fs.parameters)[i];
+ tnv = p.type.toBasetype();
+ if (tnv.ty != tn.ty && tnv.ty.isSomeChar)
+ {
+ if (p.storageClass & STC.ref_)
+ {
+ fs.error("`foreach`: value of UTF conversion cannot be `ref`");
+ return retError();
+ }
+ if (dim == 2)
+ {
+ p = (*fs.parameters)[0];
+ if (p.storageClass & STC.ref_)
+ {
+ fs.error("`foreach`: key cannot be `ref`");
+ return retError();
+ }
+ }
+ return retStmt(apply());
+ }
+ }
+
+ // Declare the key
+ if (dim == 2)
+ {
+ Parameter p = (*fs.parameters)[0];
+ auto var = new VarDeclaration(loc, p.type.mutableOf(), Identifier.generateId("__key"), null);
+ var.storage_class |= STC.temp | STC.foreach_;
+ if (var.storage_class & (STC.ref_ | STC.out_))
+ var.storage_class |= STC.nodtor;
+
+ fs.key = var;
+ if (p.storageClass & STC.ref_)
+ {
+ if (var.type.constConv(p.type) == MATCH.nomatch)
+ {
+ fs.error("key type mismatch, `%s` to `ref %s`",
+ var.type.toChars(), p.type.toChars());
+ return retError();
+ }
+ }
+ if (tab.ty == Tsarray)
+ {
+ TypeSArray ta = cast(TypeSArray)tab;
+ IntRange dimrange = getIntRange(ta.dim);
+ // https://issues.dlang.org/show_bug.cgi?id=12504
+ dimrange.imax = SignExtendedNumber(dimrange.imax.value-1);
+ if (!IntRange.fromType(var.type).contains(dimrange))
+ {
+ fs.error("index type `%s` cannot cover index range 0..%llu",
+ p.type.toChars(), ta.dim.toInteger());
+ return retError();
+ }
+ fs.key.range = new IntRange(SignExtendedNumber(0), dimrange.imax);
+ }
+ }
+ // Now declare the value
+ {
+ Parameter p = (*fs.parameters)[dim - 1];
+ auto var = new VarDeclaration(loc, p.type, p.ident, null);
+ var.storage_class |= STC.foreach_;
+ var.storage_class |= p.storageClass & (STC.scope_ | STC.IOR | STC.TYPECTOR);
+ if (var.isReference())
+ var.storage_class |= STC.nodtor;
+
+ fs.value = var;
+ if (var.storage_class & STC.ref_)
+ {
+ if (fs.aggr.checkModifiable(sc2, ModifyFlags.noError) == Modifiable.initialization)
+ var.storage_class |= STC.ctorinit;
+
+ Type t = tab.nextOf();
+ if (t.constConv(p.type) == MATCH.nomatch)
+ {
+ fs.error("argument type mismatch, `%s` to `ref %s`",
+ t.toChars(), p.type.toChars());
+ return retError();
+ }
+ }
+ }
+
+ /* Convert to a ForStatement
+ * foreach (key, value; a) body =>
+ * for (T[] tmp = a[], size_t key; key < tmp.length; ++key)
+ * { T value = tmp[k]; body }
+ *
+ * foreach_reverse (key, value; a) body =>
+ * for (T[] tmp = a[], size_t key = tmp.length; key--; )
+ * { T value = tmp[k]; body }
+ */
+ auto id = Identifier.generateId("__r");
+ auto ie = new ExpInitializer(loc, new SliceExp(loc, fs.aggr, null, null));
+ const valueIsRef = cast(bool) ((*fs.parameters)[dim - 1].storageClass & STC.ref_);
+ VarDeclaration tmp;
+ if (fs.aggr.op == TOK.arrayLiteral && !valueIsRef)
+ {
+ auto ale = cast(ArrayLiteralExp)fs.aggr;
+ size_t edim = ale.elements ? ale.elements.dim : 0;
+ auto telem = (*fs.parameters)[dim - 1].type;
+
+ // https://issues.dlang.org/show_bug.cgi?id=12936
+ // if telem has been specified explicitly,
+ // converting array literal elements to telem might make it @nogc.
+ fs.aggr = fs.aggr.implicitCastTo(sc, telem.sarrayOf(edim));
+ if (fs.aggr.op == TOK.error)
+ return retError();
+
+ // for (T[edim] tmp = a, ...)
+ tmp = new VarDeclaration(loc, fs.aggr.type, id, ie);
+ }
+ else
+ {
+ tmp = new VarDeclaration(loc, tab.nextOf().arrayOf(), id, ie);
+ if (!valueIsRef)
+ tmp.storage_class |= STC.scope_;
+ }
+ tmp.storage_class |= STC.temp;
+
+ Expression tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id.length);
+
+ if (!fs.key)
+ {
+ Identifier idkey = Identifier.generateId("__key");
+ fs.key = new VarDeclaration(loc, Type.tsize_t, idkey, null);
+ fs.key.storage_class |= STC.temp;
+ }
+ else if (fs.key.type.ty != Type.tsize_t.ty)
+ {
+ tmp_length = new CastExp(loc, tmp_length, fs.key.type);
+ }
+ if (fs.op == TOK.foreach_reverse_)
+ fs.key._init = new ExpInitializer(loc, tmp_length);
+ else
+ fs.key._init = new ExpInitializer(loc, new IntegerExp(loc, 0, fs.key.type));
+
+ auto cs = new Statements();
+ if (vinit)
+ cs.push(new ExpStatement(loc, vinit));
+ cs.push(new ExpStatement(loc, tmp));
+ cs.push(new ExpStatement(loc, fs.key));
+ Statement forinit = new CompoundDeclarationStatement(loc, cs);
+
+ Expression cond;
+ if (fs.op == TOK.foreach_reverse_)
+ {
+ // key--
+ cond = new PostExp(TOK.minusMinus, loc, new VarExp(loc, fs.key));
+ }
+ else
+ {
+ // key < tmp.length
+ cond = new CmpExp(TOK.lessThan, loc, new VarExp(loc, fs.key), tmp_length);
+ }
+
+ Expression increment = null;
+ if (fs.op == TOK.foreach_)
+ {
+ // key += 1
+ increment = new AddAssignExp(loc, new VarExp(loc, fs.key), new IntegerExp(loc, 1, fs.key.type));
+ }
+
+ // T value = tmp[key];
+ IndexExp indexExp = new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, fs.key));
+ indexExp.indexIsInBounds = true; // disabling bounds checking in foreach statements.
+ fs.value._init = new ExpInitializer(loc, indexExp);
+ Statement ds = new ExpStatement(loc, fs.value);
+
+ if (dim == 2)
+ {
+ Parameter p = (*fs.parameters)[0];
+ if ((p.storageClass & STC.ref_) && p.type.equals(fs.key.type))
+ {
+ fs.key.range = null;
+ auto v = new AliasDeclaration(loc, p.ident, fs.key);
+ fs._body = new CompoundStatement(loc, new ExpStatement(loc, v), fs._body);
+ }
+ else
+ {
+ auto ei = new ExpInitializer(loc, new IdentifierExp(loc, fs.key.ident));
+ auto v = new VarDeclaration(loc, p.type, p.ident, ei);
+ v.storage_class |= STC.foreach_ | (p.storageClass & STC.ref_);
+ fs._body = new CompoundStatement(loc, new ExpStatement(loc, v), fs._body);
+ if (fs.key.range && !p.type.isMutable())
+ {
+ /* Limit the range of the key to the specified range
+ */
+ v.range = new IntRange(fs.key.range.imin, fs.key.range.imax - SignExtendedNumber(1));
+ }
+ }
+ }
+ fs._body = new CompoundStatement(loc, ds, fs._body);
+
+ Statement s = new ForStatement(loc, forinit, cond, increment, fs._body, fs.endloc);
+ if (auto ls = checkLabeledLoop(sc, fs)) // https://issues.dlang.org/show_bug.cgi?id=15450
+ // don't use sc2
+ ls.gotoTarget = s;
+ return retStmt(s);
+ }
+ case Taarray:
+ if (fs.op == TOK.foreach_reverse_)
+ fs.warning("cannot use `foreach_reverse` with an associative array");
+ if (checkForArgTypes(fs))
+ return retError();
+
+ taa = cast(TypeAArray)tab;
+ if (dim < 1 || dim > 2)
+ {
+ fs.error("only one or two arguments for associative array `foreach`");
+ return retError();
+ }
+ return retStmt(apply());
+
+ case Tclass:
+ case Tstruct:
+ /* Prefer using opApply, if it exists
+ */
+ if (sapply)
+ return retStmt(apply());
+ {
+ /* Look for range iteration, i.e. the properties
+ * .empty, .popFront, .popBack, .front and .back
+ * foreach (e; aggr) { ... }
+ * translates to:
+ * for (auto __r = aggr[]; !__r.empty; __r.popFront()) {
+ * auto e = __r.front;
+ * ...
+ * }
+ */
+ auto ad = (tab.ty == Tclass) ?
+ cast(AggregateDeclaration)(cast(TypeClass)tab).sym :
+ cast(AggregateDeclaration)(cast(TypeStruct)tab).sym;
+ Identifier idfront;
+ Identifier idpopFront;
+ if (fs.op == TOK.foreach_)
+ {
+ idfront = Id.Ffront;
+ idpopFront = Id.FpopFront;
+ }
+ else
+ {
+ idfront = Id.Fback;
+ idpopFront = Id.FpopBack;
+ }
+ auto sfront = ad.search(Loc.initial, idfront);
+ if (!sfront)
+ return retStmt(apply());
+
+ /* Generate a temporary __r and initialize it with the aggregate.
+ */
+ VarDeclaration r;
+ Statement _init;
+ if (vinit && fs.aggr.op == TOK.variable && (cast(VarExp)fs.aggr).var == vinit)
+ {
+ r = vinit;
+ _init = new ExpStatement(loc, vinit);
+ }
+ else
+ {
+ r = copyToTemp(0, "__r", fs.aggr);
+ r.dsymbolSemantic(sc);
+ _init = new ExpStatement(loc, r);
+ if (vinit)
+ _init = new CompoundStatement(loc, new ExpStatement(loc, vinit), _init);
+ }
+
+ // !__r.empty
+ Expression e = new VarExp(loc, r);
+ e = new DotIdExp(loc, e, Id.Fempty);
+ Expression condition = new NotExp(loc, e);
+
+ // __r.idpopFront()
+ e = new VarExp(loc, r);
+ Expression increment = new CallExp(loc, new DotIdExp(loc, e, idpopFront));
+
+ /* Declaration statement for e:
+ * auto e = __r.idfront;
+ */
+ e = new VarExp(loc, r);
+ Expression einit = new DotIdExp(loc, e, idfront);
+ Statement makeargs, forbody;
+ bool ignoreRef = false; // If a range returns a non-ref front we ignore ref on foreach
+
+ Type tfront;
+ if (auto fd = sfront.isFuncDeclaration())
+ {
+ if (!fd.functionSemantic())
+ return rangeError();
+ tfront = fd.type;
+ }
+ else if (auto td = sfront.isTemplateDeclaration())
+ {
+ Expressions a;
+ if (auto f = resolveFuncCall(loc, sc, td, null, tab, &a, FuncResolveFlag.quiet))
+ tfront = f.type;
+ }
+ else if (auto d = sfront.toAlias().isDeclaration())
+ {
+ tfront = d.type;
+ }
+ if (!tfront || tfront.ty == Terror)
+ return rangeError();
+ if (tfront.toBasetype().ty == Tfunction)
+ {
+ auto ftt = cast(TypeFunction)tfront.toBasetype();
+ tfront = tfront.toBasetype().nextOf();
+ if (!ftt.isref)
+ {
+ // .front() does not return a ref. We ignore ref on foreach arg.
+ // see https://issues.dlang.org/show_bug.cgi?id=11934
+ if (tfront.needsDestruction()) ignoreRef = true;
+ }
+ }
+ if (tfront.ty == Tvoid)
+ {
+ fs.error("`%s.front` is `void` and has no value", oaggr.toChars());
+ return retError();
+ }
+
+ if (dim == 1)
+ {
+ auto p = (*fs.parameters)[0];
+ auto ve = new VarDeclaration(loc, p.type, p.ident, new ExpInitializer(loc, einit));
+ ve.storage_class |= STC.foreach_;
+ ve.storage_class |= p.storageClass & (STC.scope_ | STC.IOR | STC.TYPECTOR);
+
+ if (ignoreRef)
+ ve.storage_class &= ~STC.ref_;
+
+ makeargs = new ExpStatement(loc, ve);
+ }
+ else
+ {
+ auto vd = copyToTemp(STC.ref_, "__front", einit);
+ vd.dsymbolSemantic(sc);
+ makeargs = new ExpStatement(loc, vd);
+
+ // Resolve inout qualifier of front type
+ tfront = tfront.substWildTo(tab.mod);
+
+ Expression ve = new VarExp(loc, vd);
+ ve.type = tfront;
+
+ auto exps = new Expressions();
+ exps.push(ve);
+ int pos = 0;
+ while (exps.dim < dim)
+ {
+ pos = expandAliasThisTuples(exps, pos);
+ if (pos == -1)
+ break;
+ }
+ if (exps.dim != dim)
+ {
+ const(char)* plural = exps.dim > 1 ? "s" : "";
+ fs.error("cannot infer argument types, expected %llu argument%s, not %llu",
+ cast(ulong) exps.dim, plural, cast(ulong) dim);
+ return retError();
+ }
+
+ foreach (i; 0 .. dim)
+ {
+ auto p = (*fs.parameters)[i];
+ auto exp = (*exps)[i];
+ version (none)
+ {
+ printf("[%d] p = %s %s, exp = %s %s\n", i,
+ p.type ? p.type.toChars() : "?", p.ident.toChars(),
+ exp.type.toChars(), exp.toChars());
+ }
+ if (!p.type)
+ p.type = exp.type;
+
+ auto sc = p.storageClass;
+ if (ignoreRef) sc &= ~STC.ref_;
+ p.type = p.type.addStorageClass(sc).typeSemantic(loc, sc2);
+ if (!exp.implicitConvTo(p.type))
+ return rangeError();
+
+ auto var = new VarDeclaration(loc, p.type, p.ident, new ExpInitializer(loc, exp));
+ var.storage_class |= STC.ctfe | STC.ref_ | STC.foreach_;
+ makeargs = new CompoundStatement(loc, makeargs, new ExpStatement(loc, var));
+ }
+ }
+
+ forbody = new CompoundStatement(loc, makeargs, fs._body);
+
+ Statement s = new ForStatement(loc, _init, condition, increment, forbody, fs.endloc);
+ if (auto ls = checkLabeledLoop(sc, fs))
+ ls.gotoTarget = s;
+
+ version (none)
+ {
+ printf("init: %s\n", _init.toChars());
+ printf("condition: %s\n", condition.toChars());
+ printf("increment: %s\n", increment.toChars());
+ printf("body: %s\n", forbody.toChars());
+ }
+ return retStmt(s);
+ }
+ case Tdelegate:
+ if (fs.op == TOK.foreach_reverse_)
+ fs.deprecation("cannot use `foreach_reverse` with a delegate");
+ return retStmt(apply());
+ case Terror:
+ return retError();
+ default:
+ fs.error("`foreach`: `%s` is not an aggregate type", fs.aggr.type.toChars());
+ return retError();
+ }
+ }
+
+ private static extern(D) Expression applyOpApply(ForeachStatement fs, Type tab, Dsymbol sapply,
+ Scope* sc2, Expression flde)
+ {
+ version (none)
+ {
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ {
+ message(loc, "To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`");
+ }
+ (cast(FuncExp)flde).fd.tookAddressOf = 1;
+ }
+ else
+ {
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ ++(cast(FuncExp)flde).fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope'
+ }
+ assert(tab.ty == Tstruct || tab.ty == Tclass);
+ assert(sapply);
+ /* Call:
+ * aggr.apply(flde)
+ */
+ Expression ec;
+ ec = new DotIdExp(fs.loc, fs.aggr, sapply.ident);
+ ec = new CallExp(fs.loc, ec, flde);
+ ec = ec.expressionSemantic(sc2);
+ if (ec.op == TOK.error)
+ return null;
+ if (ec.type != Type.tint32)
+ {
+ fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars());
+ return null;
+ }
+ return ec;
+ }
+
+ private static extern(D) Expression applyDelegate(ForeachStatement fs, Expression flde,
+ Scope* sc2, Type tab)
+ {
+ Expression ec;
+ /* Call:
+ * aggr(flde)
+ */
+ if (fs.aggr.op == TOK.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() &&
+ !(cast(DelegateExp)fs.aggr).func.needThis())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=3560
+ fs.aggr = (cast(DelegateExp)fs.aggr).e1;
+ }
+ ec = new CallExp(fs.loc, fs.aggr, flde);
+ ec = ec.expressionSemantic(sc2);
+ if (ec.op == TOK.error)
+ return null;
+ if (ec.type != Type.tint32)
+ {
+ fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars());
+ return null;
+ }
+ return ec;
+ }
+
+ private static extern(D) Expression applyArray(ForeachStatement fs, Expression flde,
+ Scope* sc2, Type tn, Type tnv, TY tabty)
+ {
+ Expression ec;
+ const dim = fs.parameters.dim;
+ const loc = fs.loc;
+ /* Call:
+ * _aApply(aggr, flde)
+ */
+ __gshared const(char)** fntab =
+ [
+ "cc", "cw", "cd",
+ "wc", "cc", "wd",
+ "dc", "dw", "dd"
+ ];
+
+ const(size_t) BUFFER_LEN = 7 + 1 + 2 + dim.sizeof * 3 + 1;
+ char[BUFFER_LEN] fdname;
+ int flag;
+
+ switch (tn.ty)
+ {
+ case Tchar: flag = 0; break;
+ case Twchar: flag = 3; break;
+ case Tdchar: flag = 6; break;
+ default:
+ assert(0);
+ }
+ switch (tnv.ty)
+ {
+ case Tchar: flag += 0; break;
+ case Twchar: flag += 1; break;
+ case Tdchar: flag += 2; break;
+ default:
+ assert(0);
+ }
+ const(char)* r = (fs.op == TOK.foreach_reverse_) ? "R" : "";
+ int j = sprintf(fdname.ptr, "_aApply%s%.*s%llu", r, 2, fntab[flag], cast(ulong)dim);
+ assert(j < BUFFER_LEN);
+
+ FuncDeclaration fdapply;
+ TypeDelegate dgty;
+ auto params = new Parameters();
+ params.push(new Parameter(STC.in_, tn.arrayOf(), null, null, null));
+ auto dgparams = new Parameters();
+ dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null));
+ if (dim == 2)
+ dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null));
+ dgty = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d));
+ params.push(new Parameter(0, dgty, null, null, null));
+ fdapply = FuncDeclaration.genCfunc(params, Type.tint32, fdname.ptr);
+
+ if (tabty == Tsarray)
+ fs.aggr = fs.aggr.castTo(sc2, tn.arrayOf());
+ // paint delegate argument to the type runtime expects
+ Expression fexp = flde;
+ if (!dgty.equals(flde.type))
+ {
+ fexp = new CastExp(loc, flde, flde.type);
+ fexp.type = dgty;
+ }
+ ec = new VarExp(Loc.initial, fdapply, false);
+ ec = new CallExp(loc, ec, fs.aggr, fexp);
+ ec.type = Type.tint32; // don't run semantic() on ec
+ return ec;
+ }
+
+ private static extern(D) Expression applyAssocArray(ForeachStatement fs, Expression flde, TypeAArray taa)
+ {
+ Expression ec;
+ const dim = fs.parameters.dim;
+ // Check types
+ Parameter p = (*fs.parameters)[0];
+ bool isRef = (p.storageClass & STC.ref_) != 0;
+ Type ta = p.type;
+ if (dim == 2)
+ {
+ Type ti = (isRef ? taa.index.addMod(MODFlags.const_) : taa.index);
+ if (isRef ? !ti.constConv(ta) : !ti.implicitConvTo(ta))
+ {
+ fs.error("`foreach`: index must be type `%s`, not `%s`",
+ ti.toChars(), ta.toChars());
+ return null;
+ }
+ p = (*fs.parameters)[1];
+ isRef = (p.storageClass & STC.ref_) != 0;
+ ta = p.type;
+ }
+ Type taav = taa.nextOf();
+ if (isRef ? !taav.constConv(ta) : !taav.implicitConvTo(ta))
+ {
+ fs.error("`foreach`: value must be type `%s`, not `%s`",
+ taav.toChars(), ta.toChars());
+ return null;
+ }
+
+ /* Call:
+ * extern(C) int _aaApply(void*, in size_t, int delegate(void*))
+ * _aaApply(aggr, keysize, flde)
+ *
+ * extern(C) int _aaApply2(void*, in size_t, int delegate(void*, void*))
+ * _aaApply2(aggr, keysize, flde)
+ */
+ __gshared FuncDeclaration* fdapply = [null, null];
+ __gshared TypeDelegate* fldeTy = [null, null];
+ ubyte i = (dim == 2 ? 1 : 0);
+ if (!fdapply[i])
+ {
+ auto params = new Parameters();
+ params.push(new Parameter(0, Type.tvoid.pointerTo(), null, null, null));
+ params.push(new Parameter(STC.const_, Type.tsize_t, null, null, null));
+ auto dgparams = new Parameters();
+ dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null));
+ if (dim == 2)
+ dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null));
+ fldeTy[i] = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d));
+ params.push(new Parameter(0, fldeTy[i], null, null, null));
+ fdapply[i] = FuncDeclaration.genCfunc(params, Type.tint32, i ? Id._aaApply2 : Id._aaApply);
+ }
+
+ auto exps = new Expressions();
+ exps.push(fs.aggr);
+ auto keysize = taa.index.size();
+ if (keysize == SIZE_INVALID)
+ return null;
+ assert(keysize < keysize.max - target.ptrsize);
+ keysize = (keysize + (target.ptrsize - 1)) & ~(target.ptrsize - 1);
+ // paint delegate argument to the type runtime expects
+ Expression fexp = flde;
+ if (!fldeTy[i].equals(flde.type))
+ {
+ fexp = new CastExp(fs.loc, flde, flde.type);
+ fexp.type = fldeTy[i];
+ }
+ exps.push(new IntegerExp(Loc.initial, keysize, Type.tsize_t));
+ exps.push(fexp);
+ ec = new VarExp(Loc.initial, fdapply[i], false);
+ ec = new CallExp(fs.loc, ec, exps);
+ ec.type = Type.tint32; // don't run semantic() on ec
+ return ec;
+ }
+
+ private static extern(D) Statement loopReturn(Expression e, Statements* cases, const ref Loc loc)
+ {
+ if (!cases.dim)
+ {
+ // Easy case, a clean exit from the loop
+ e = new CastExp(loc, e, Type.tvoid); // https://issues.dlang.org/show_bug.cgi?id=13899
+ return new ExpStatement(loc, e);
+ }
+ // Construct a switch statement around the return value
+ // of the apply function.
+ Statement s;
+ auto a = new Statements();
+
+ // default: break; takes care of cases 0 and 1
+ s = new BreakStatement(Loc.initial, null);
+ s = new DefaultStatement(Loc.initial, s);
+ a.push(s);
+
+ // cases 2...
+ foreach (i, c; *cases)
+ {
+ s = new CaseStatement(Loc.initial, new IntegerExp(i + 2), c);
+ a.push(s);
+ }
+
+ s = new CompoundStatement(loc, a);
+ return new SwitchStatement(loc, e, s, false);
+ }
+ /*************************************
+ * Turn foreach body into the function literal:
+ * int delegate(ref T param) { body }
+ * Params:
+ * sc = context
+ * fs = ForeachStatement
+ * tfld = type of function literal to be created, can be null
+ * Returns:
+ * Function literal created, as an expression
+ * null if error.
+ */
+ static FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFunction tfld)
+ {
+ auto params = new Parameters();
+ foreach (i; 0 .. fs.parameters.dim)
+ {
+ Parameter p = (*fs.parameters)[i];
+ StorageClass stc = STC.ref_;
+ Identifier id;
+
+ p.type = p.type.typeSemantic(fs.loc, sc);
+ p.type = p.type.addStorageClass(p.storageClass);
+ if (tfld)
+ {
+ Parameter prm = tfld.parameterList[i];
+ //printf("\tprm = %s%s\n", (prm.storageClass&STC.ref_?"ref ":"").ptr, prm.ident.toChars());
+ stc = prm.storageClass & STC.ref_;
+ id = p.ident; // argument copy is not need.
+ if ((p.storageClass & STC.ref_) != stc)
+ {
+ if (!stc)
+ {
+ fs.error("`foreach`: cannot make `%s` `ref`", p.ident.toChars());
+ return null;
+ }
+ goto LcopyArg;
+ }
+ }
+ else if (p.storageClass & STC.ref_)
+ {
+ // default delegate parameters are marked as ref, then
+ // argument copy is not need.
+ id = p.ident;
+ }
+ else
+ {
+ // Make a copy of the ref argument so it isn't
+ // a reference.
+ LcopyArg:
+ id = Identifier.generateId("__applyArg", cast(int)i);
+
+ Initializer ie = new ExpInitializer(fs.loc, new IdentifierExp(fs.loc, id));
+ auto v = new VarDeclaration(fs.loc, p.type, p.ident, ie);
+ v.storage_class |= STC.temp;
+ Statement s = new ExpStatement(fs.loc, v);
+ fs._body = new CompoundStatement(fs.loc, s, fs._body);
+ }
+ params.push(new Parameter(stc, p.type, id, null, null));
+ }
+ // https://issues.dlang.org/show_bug.cgi?id=13840
+ // Throwable nested function inside nothrow function is acceptable.
+ StorageClass stc = mergeFuncAttrs(STC.safe | STC.pure_ | STC.nogc, fs.func);
+ auto tf = new TypeFunction(ParameterList(params), Type.tint32, LINK.d, stc);
+ fs.cases = new Statements();
+ fs.gotos = new ScopeStatements();
+ auto fld = new FuncLiteralDeclaration(fs.loc, fs.endloc, tf, TOK.delegate_, fs);
+ fld.fbody = fs._body;
+ Expression flde = new FuncExp(fs.loc, fld);
+ flde = flde.expressionSemantic(sc);
+ fld.tookAddressOf = 0;
+ if (flde.op == TOK.error)
+ return null;
+ return cast(FuncExp)flde;
+ }
+
+ override void visit(ForeachRangeStatement fs)
+ {
+ /* https://dlang.org/spec/statement.html#foreach-range-statement
+ */
+
+ //printf("ForeachRangeStatement::semantic() %p\n", fs);
+ auto loc = fs.loc;
+ fs.lwr = fs.lwr.expressionSemantic(sc);
+ fs.lwr = resolveProperties(sc, fs.lwr);
+ fs.lwr = fs.lwr.optimize(WANTvalue);
+ if (!fs.lwr.type)
+ {
+ fs.error("invalid range lower bound `%s`", fs.lwr.toChars());
+ return setError();
+ }
+
+ fs.upr = fs.upr.expressionSemantic(sc);
+ fs.upr = resolveProperties(sc, fs.upr);
+ fs.upr = fs.upr.optimize(WANTvalue);
+ if (!fs.upr.type)
+ {
+ fs.error("invalid range upper bound `%s`", fs.upr.toChars());
+ return setError();
+ }
+
+ if (fs.prm.type)
+ {
+ fs.prm.type = fs.prm.type.typeSemantic(loc, sc);
+ fs.prm.type = fs.prm.type.addStorageClass(fs.prm.storageClass);
+ fs.lwr = fs.lwr.implicitCastTo(sc, fs.prm.type);
+
+ if (fs.upr.implicitConvTo(fs.prm.type) || (fs.prm.storageClass & STC.ref_))
+ {
+ fs.upr = fs.upr.implicitCastTo(sc, fs.prm.type);
+ }
+ else
+ {
+ // See if upr-1 fits in prm.type
+ Expression limit = new MinExp(loc, fs.upr, IntegerExp.literal!1);
+ limit = limit.expressionSemantic(sc);
+ limit = limit.optimize(WANTvalue);
+ if (!limit.implicitConvTo(fs.prm.type))
+ {
+ fs.upr = fs.upr.implicitCastTo(sc, fs.prm.type);
+ }
+ }
+ }
+ else
+ {
+ /* Must infer types from lwr and upr
+ */
+ Type tlwr = fs.lwr.type.toBasetype();
+ if (tlwr.ty == Tstruct || tlwr.ty == Tclass)
+ {
+ /* Just picking the first really isn't good enough.
+ */
+ fs.prm.type = fs.lwr.type;
+ }
+ else if (fs.lwr.type == fs.upr.type)
+ {
+ /* Same logic as CondExp ?lwr:upr
+ */
+ fs.prm.type = fs.lwr.type;
+ }
+ else
+ {
+ scope AddExp ea = new AddExp(loc, fs.lwr, fs.upr);
+ if (typeCombine(ea, sc))
+ return setError();
+ fs.prm.type = ea.type;
+ fs.lwr = ea.e1;
+ fs.upr = ea.e2;
+ }
+ fs.prm.type = fs.prm.type.addStorageClass(fs.prm.storageClass);
+ }
+ if (fs.prm.type.ty == Terror || fs.lwr.op == TOK.error || fs.upr.op == TOK.error)
+ {
+ return setError();
+ }
+
+ /* Convert to a for loop:
+ * foreach (key; lwr .. upr) =>
+ * for (auto key = lwr, auto tmp = upr; key < tmp; ++key)
+ *
+ * foreach_reverse (key; lwr .. upr) =>
+ * for (auto tmp = lwr, auto key = upr; key-- > tmp;)
+ */
+ auto ie = new ExpInitializer(loc, (fs.op == TOK.foreach_) ? fs.lwr : fs.upr);
+ fs.key = new VarDeclaration(loc, fs.upr.type.mutableOf(), Identifier.generateId("__key"), ie);
+ fs.key.storage_class |= STC.temp;
+ SignExtendedNumber lower = getIntRange(fs.lwr).imin;
+ SignExtendedNumber upper = getIntRange(fs.upr).imax;
+ if (lower <= upper)
+ {
+ fs.key.range = new IntRange(lower, upper);
+ }
+
+ Identifier id = Identifier.generateId("__limit");
+ ie = new ExpInitializer(loc, (fs.op == TOK.foreach_) ? fs.upr : fs.lwr);
+ auto tmp = new VarDeclaration(loc, fs.upr.type, id, ie);
+ tmp.storage_class |= STC.temp;
+
+ auto cs = new Statements();
+ // Keep order of evaluation as lwr, then upr
+ if (fs.op == TOK.foreach_)
+ {
+ cs.push(new ExpStatement(loc, fs.key));
+ cs.push(new ExpStatement(loc, tmp));
+ }
+ else
+ {
+ cs.push(new ExpStatement(loc, tmp));
+ cs.push(new ExpStatement(loc, fs.key));
+ }
+ Statement forinit = new CompoundDeclarationStatement(loc, cs);
+
+ Expression cond;
+ if (fs.op == TOK.foreach_reverse_)
+ {
+ cond = new PostExp(TOK.minusMinus, loc, new VarExp(loc, fs.key));
+ if (fs.prm.type.isscalar())
+ {
+ // key-- > tmp
+ cond = new CmpExp(TOK.greaterThan, loc, cond, new VarExp(loc, tmp));
+ }
+ else
+ {
+ // key-- != tmp
+ cond = new EqualExp(TOK.notEqual, loc, cond, new VarExp(loc, tmp));
+ }
+ }
+ else
+ {
+ if (fs.prm.type.isscalar())
+ {
+ // key < tmp
+ cond = new CmpExp(TOK.lessThan, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp));
+ }
+ else
+ {
+ // key != tmp
+ cond = new EqualExp(TOK.notEqual, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp));
+ }
+ }
+
+ Expression increment = null;
+ if (fs.op == TOK.foreach_)
+ {
+ // key += 1
+ //increment = new AddAssignExp(loc, new VarExp(loc, fs.key), IntegerExp.literal!1);
+ increment = new PreExp(TOK.prePlusPlus, loc, new VarExp(loc, fs.key));
+ }
+ if ((fs.prm.storageClass & STC.ref_) && fs.prm.type.equals(fs.key.type))
+ {
+ fs.key.range = null;
+ auto v = new AliasDeclaration(loc, fs.prm.ident, fs.key);
+ fs._body = new CompoundStatement(loc, new ExpStatement(loc, v), fs._body);
+ }
+ else
+ {
+ ie = new ExpInitializer(loc, new CastExp(loc, new VarExp(loc, fs.key), fs.prm.type));
+ auto v = new VarDeclaration(loc, fs.prm.type, fs.prm.ident, ie);
+ v.storage_class |= STC.temp | STC.foreach_ | (fs.prm.storageClass & STC.ref_);
+ fs._body = new CompoundStatement(loc, new ExpStatement(loc, v), fs._body);
+ if (fs.key.range && !fs.prm.type.isMutable())
+ {
+ /* Limit the range of the key to the specified range
+ */
+ v.range = new IntRange(fs.key.range.imin, fs.key.range.imax - SignExtendedNumber(1));
+ }
+ }
+ if (fs.prm.storageClass & STC.ref_)
+ {
+ if (fs.key.type.constConv(fs.prm.type) == MATCH.nomatch)
+ {
+ fs.error("argument type mismatch, `%s` to `ref %s`", fs.key.type.toChars(), fs.prm.type.toChars());
+ return setError();
+ }
+ }
+
+ auto s = new ForStatement(loc, forinit, cond, increment, fs._body, fs.endloc);
+ if (LabelStatement ls = checkLabeledLoop(sc, fs))
+ ls.gotoTarget = s;
+ result = s.statementSemantic(sc);
+ }
+
+ override void visit(IfStatement ifs)
+ {
+ /* https://dlang.org/spec/statement.html#IfStatement
+ */
+
+ // check in syntax level
+ ifs.condition = checkAssignmentAsCondition(ifs.condition);
+
+ auto sym = new ScopeDsymbol();
+ sym.parent = sc.scopesym;
+ sym.endlinnum = ifs.endloc.linnum;
+ Scope* scd = sc.push(sym);
+ if (ifs.prm)
+ {
+ /* Declare prm, which we will set to be the
+ * result of condition.
+ */
+ auto ei = new ExpInitializer(ifs.loc, ifs.condition);
+ ifs.match = new VarDeclaration(ifs.loc, ifs.prm.type, ifs.prm.ident, ei);
+ ifs.match.parent = scd.func;
+ ifs.match.storage_class |= ifs.prm.storageClass;
+ ifs.match.dsymbolSemantic(scd);
+
+ auto de = new DeclarationExp(ifs.loc, ifs.match);
+ auto ve = new VarExp(ifs.loc, ifs.match);
+ ifs.condition = new CommaExp(ifs.loc, de, ve);
+ ifs.condition = ifs.condition.expressionSemantic(scd);
+
+ if (ifs.match.edtor)
+ {
+ Statement sdtor = new DtorExpStatement(ifs.loc, ifs.match.edtor, ifs.match);
+ sdtor = new ScopeGuardStatement(ifs.loc, TOK.onScopeExit, sdtor);
+ ifs.ifbody = new CompoundStatement(ifs.loc, sdtor, ifs.ifbody);
+ ifs.match.storage_class |= STC.nodtor;
+
+ // the destructor is always called
+ // whether the 'ifbody' is executed or not
+ Statement sdtor2 = new DtorExpStatement(ifs.loc, ifs.match.edtor, ifs.match);
+ if (ifs.elsebody)
+ ifs.elsebody = new CompoundStatement(ifs.loc, sdtor2, ifs.elsebody);
+ else
+ ifs.elsebody = sdtor2;
+ }
+ }
+ else
+ {
+ if (ifs.condition.op == TOK.dotIdentifier)
+ (cast(DotIdExp)ifs.condition).noderef = true;
+
+ ifs.condition = ifs.condition.expressionSemantic(scd);
+ ifs.condition = resolveProperties(scd, ifs.condition);
+ ifs.condition = ifs.condition.addDtorHook(scd);
+ }
+ if (checkNonAssignmentArrayOp(ifs.condition))
+ ifs.condition = ErrorExp.get();
+ ifs.condition = checkGC(scd, ifs.condition);
+
+ // Convert to boolean after declaring prm so this works:
+ // if (S prm = S()) {}
+ // where S is a struct that defines opCast!bool.
+ ifs.condition = ifs.condition.toBoolean(scd);
+
+ // If we can short-circuit evaluate the if statement, don't do the
+ // semantic analysis of the skipped code.
+ // This feature allows a limited form of conditional compilation.
+ ifs.condition = ifs.condition.optimize(WANTvalue);
+
+ // Save 'root' of two branches (then and else) at the point where it forks
+ CtorFlow ctorflow_root = scd.ctorflow.clone();
+
+ ifs.ifbody = ifs.ifbody.semanticNoScope(scd);
+ scd.pop();
+
+ CtorFlow ctorflow_then = sc.ctorflow; // move flow results
+ sc.ctorflow = ctorflow_root; // reset flow analysis back to root
+ if (ifs.elsebody)
+ ifs.elsebody = ifs.elsebody.semanticScope(sc, null, null, null);
+
+ // Merge 'then' results into 'else' results
+ sc.merge(ifs.loc, ctorflow_then);
+
+ ctorflow_then.freeFieldinit(); // free extra copy of the data
+
+ if (ifs.condition.op == TOK.error ||
+ (ifs.ifbody && ifs.ifbody.isErrorStatement()) ||
+ (ifs.elsebody && ifs.elsebody.isErrorStatement()))
+ {
+ return setError();
+ }
+ result = ifs;
+ }
+
+ override void visit(ConditionalStatement cs)
+ {
+ //printf("ConditionalStatement::semantic()\n");
+
+ // If we can short-circuit evaluate the if statement, don't do the
+ // semantic analysis of the skipped code.
+ // This feature allows a limited form of conditional compilation.
+ if (cs.condition.include(sc))
+ {
+ DebugCondition dc = cs.condition.isDebugCondition();
+ if (dc)
+ {
+ sc = sc.push();
+ sc.flags |= SCOPE.debug_;
+ cs.ifbody = cs.ifbody.statementSemantic(sc);
+ sc.pop();
+ }
+ else
+ cs.ifbody = cs.ifbody.statementSemantic(sc);
+ result = cs.ifbody;
+ }
+ else
+ {
+ if (cs.elsebody)
+ cs.elsebody = cs.elsebody.statementSemantic(sc);
+ result = cs.elsebody;
+ }
+ }
+
+ override void visit(PragmaStatement ps)
+ {
+ /* https://dlang.org/spec/statement.html#pragma-statement
+ */
+ // Should be merged with PragmaDeclaration
+
+ //printf("PragmaStatement::semantic() %s\n", ps.toChars());
+ //printf("body = %p\n", ps._body);
+ if (ps.ident == Id.msg)
+ {
+ if (ps.args)
+ {
+ foreach (arg; *ps.args)
+ {
+ sc = sc.startCTFE();
+ auto e = arg.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ sc = sc.endCTFE();
+
+ // pragma(msg) is allowed to contain types as well as expressions
+ e = ctfeInterpretForPragmaMsg(e);
+ if (e.op == TOK.error)
+ {
+ errorSupplemental(ps.loc, "while evaluating `pragma(msg, %s)`", arg.toChars());
+ return setError();
+ }
+ if (auto se = e.toStringExp())
+ {
+ const slice = se.toUTF8(sc).peekString();
+ fprintf(stderr, "%.*s", cast(int)slice.length, slice.ptr);
+ }
+ else
+ fprintf(stderr, "%s", e.toChars());
+ }
+ fprintf(stderr, "\n");
+ }
+ }
+ else if (ps.ident == Id.lib)
+ {
+ version (all)
+ {
+ /* Should this be allowed?
+ */
+ ps.error("`pragma(lib)` not allowed as statement");
+ return setError();
+ }
+ else
+ {
+ if (!ps.args || ps.args.dim != 1)
+ {
+ ps.error("`string` expected for library name");
+ return setError();
+ }
+ else
+ {
+ auto se = semanticString(sc, (*ps.args)[0], "library name");
+ if (!se)
+ return setError();
+
+ if (global.params.verbose)
+ {
+ message("library %.*s", cast(int)se.len, se.string);
+ }
+ }
+ }
+ }
+ else if (ps.ident == Id.linkerDirective)
+ {
+ /* Should this be allowed?
+ */
+ ps.error("`pragma(linkerDirective)` not allowed as statement");
+ return setError();
+ }
+ else if (ps.ident == Id.startaddress)
+ {
+ if (!ps.args || ps.args.dim != 1)
+ ps.error("function name expected for start address");
+ else
+ {
+ Expression e = (*ps.args)[0];
+ sc = sc.startCTFE();
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ sc = sc.endCTFE();
+
+ e = e.ctfeInterpret();
+ (*ps.args)[0] = e;
+ Dsymbol sa = getDsymbol(e);
+ if (!sa || !sa.isFuncDeclaration())
+ {
+ ps.error("function name expected for start address, not `%s`", e.toChars());
+ return setError();
+ }
+ if (ps._body)
+ {
+ ps._body = ps._body.statementSemantic(sc);
+ if (ps._body.isErrorStatement())
+ {
+ result = ps._body;
+ return;
+ }
+ }
+ result = ps;
+ return;
+ }
+ }
+ else if (ps.ident == Id.Pinline)
+ {
+ PINLINE inlining = PINLINE.default_;
+ if (!ps.args || ps.args.dim == 0)
+ inlining = PINLINE.default_;
+ else if (!ps.args || ps.args.dim != 1)
+ {
+ ps.error("boolean expression expected for `pragma(inline)`");
+ return setError();
+ }
+ else
+ {
+ Expression e = (*ps.args)[0];
+ sc = sc.startCTFE();
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ sc = sc.endCTFE();
+ e = e.ctfeInterpret();
+ e = e.toBoolean(sc);
+ if (e.isErrorExp())
+ {
+ ps.error("pragma(`inline`, `true` or `false`) expected, not `%s`", (*ps.args)[0].toChars());
+ return setError();
+ }
+
+ if (e.isBool(true))
+ inlining = PINLINE.always;
+ else if (e.isBool(false))
+ inlining = PINLINE.never;
+
+ FuncDeclaration fd = sc.func;
+ if (!fd)
+ {
+ ps.error("`pragma(inline)` is not inside a function");
+ return setError();
+ }
+ fd.inlining = inlining;
+ }
+ }
+ else if (!global.params.ignoreUnsupportedPragmas)
+ {
+ ps.error("unrecognized `pragma(%s)`", ps.ident.toChars());
+ return setError();
+ }
+
+ if (ps._body)
+ {
+ if (ps.ident == Id.msg || ps.ident == Id.startaddress)
+ {
+ ps.error("`pragma(%s)` is missing a terminating `;`", ps.ident.toChars());
+ return setError();
+ }
+ ps._body = ps._body.statementSemantic(sc);
+ }
+ result = ps._body;
+ }
+
+ override void visit(StaticAssertStatement s)
+ {
+ s.sa.semantic2(sc);
+ if (s.sa.errors)
+ return setError();
+ }
+
+ override void visit(SwitchStatement ss)
+ {
+ /* https://dlang.org/spec/statement.html#switch-statement
+ */
+
+ //printf("SwitchStatement::semantic(%p)\n", ss);
+ ss.tryBody = sc.tryBody;
+ ss.tf = sc.tf;
+ if (ss.cases)
+ {
+ result = ss; // already run
+ return;
+ }
+
+ bool conditionError = false;
+ ss.condition = ss.condition.expressionSemantic(sc);
+ ss.condition = resolveProperties(sc, ss.condition);
+
+ Type att = null;
+ TypeEnum te = null;
+ while (ss.condition.op != TOK.error)
+ {
+ // preserve enum type for final switches
+ if (ss.condition.type.ty == Tenum)
+ te = cast(TypeEnum)ss.condition.type;
+ if (ss.condition.type.isString())
+ {
+ // If it's not an array, cast it to one
+ if (ss.condition.type.ty != Tarray)
+ {
+ ss.condition = ss.condition.implicitCastTo(sc, ss.condition.type.nextOf().arrayOf());
+ }
+ ss.condition.type = ss.condition.type.constOf();
+ break;
+ }
+ ss.condition = integralPromotions(ss.condition, sc);
+ if (ss.condition.op != TOK.error && ss.condition.type.isintegral())
+ break;
+
+ auto ad = isAggregate(ss.condition.type);
+ if (ad && ad.aliasthis && !isRecursiveAliasThis(att, ss.condition.type))
+ {
+ if (auto e = resolveAliasThis(sc, ss.condition, true))
+ {
+ ss.condition = e;
+ continue;
+ }
+ }
+
+ if (ss.condition.op != TOK.error)
+ {
+ ss.error("`%s` must be of integral or string type, it is a `%s`",
+ ss.condition.toChars(), ss.condition.type.toChars());
+ conditionError = true;
+ break;
+ }
+ }
+ if (checkNonAssignmentArrayOp(ss.condition))
+ ss.condition = ErrorExp.get();
+ ss.condition = ss.condition.optimize(WANTvalue);
+ ss.condition = checkGC(sc, ss.condition);
+ if (ss.condition.op == TOK.error)
+ conditionError = true;
+
+ bool needswitcherror = false;
+
+ ss.lastVar = sc.lastVar;
+
+ sc = sc.push();
+ sc.sbreak = ss;
+ sc.sw = ss;
+
+ ss.cases = new CaseStatements();
+ const inLoopSave = sc.inLoop;
+ sc.inLoop = true; // BUG: should use Scope::mergeCallSuper() for each case instead
+ ss._body = ss._body.statementSemantic(sc);
+ sc.inLoop = inLoopSave;
+
+ if (conditionError || (ss._body && ss._body.isErrorStatement()))
+ {
+ sc.pop();
+ return setError();
+ }
+
+ // Resolve any goto case's with exp
+ Lgotocase:
+ foreach (gcs; ss.gotoCases)
+ {
+ if (!gcs.exp)
+ {
+ gcs.error("no `case` statement following `goto case;`");
+ sc.pop();
+ return setError();
+ }
+
+ for (Scope* scx = sc; scx; scx = scx.enclosing)
+ {
+ if (!scx.sw)
+ continue;
+ foreach (cs; *scx.sw.cases)
+ {
+ if (cs.exp.equals(gcs.exp))
+ {
+ gcs.cs = cs;
+ continue Lgotocase;
+ }
+ }
+ }
+ gcs.error("`case %s` not found", gcs.exp.toChars());
+ sc.pop();
+ return setError();
+ }
+
+ if (ss.isFinal)
+ {
+ Type t = ss.condition.type;
+ Dsymbol ds;
+ EnumDeclaration ed = null;
+ if (t && ((ds = t.toDsymbol(sc)) !is null))
+ ed = ds.isEnumDeclaration(); // typedef'ed enum
+ if (!ed && te && ((ds = te.toDsymbol(sc)) !is null))
+ ed = ds.isEnumDeclaration();
+ if (ed && ss.cases.length < ed.members.length)
+ {
+ int missingMembers = 0;
+ const maxShown = !global.params.verbose ? 6 : int.max;
+ Lmembers:
+ foreach (es; *ed.members)
+ {
+ EnumMember em = es.isEnumMember();
+ if (em)
+ {
+ foreach (cs; *ss.cases)
+ {
+ if (cs.exp.equals(em.value) || (!cs.exp.type.isString() &&
+ !em.value.type.isString() && cs.exp.toInteger() == em.value.toInteger()))
+ continue Lmembers;
+ }
+ if (missingMembers == 0)
+ ss.error("missing cases for `enum` members in `final switch`:");
+
+ if (missingMembers < maxShown)
+ errorSupplemental(ss.loc, "`%s`", em.toChars());
+ missingMembers++;
+ }
+ }
+ if (missingMembers > 0)
+ {
+ if (missingMembers > maxShown)
+ errorSupplemental(ss.loc, "... (%d more, -v to show) ...", missingMembers - maxShown);
+ sc.pop();
+ return setError();
+ }
+ }
+ else
+ needswitcherror = true;
+ }
+
+ if (!sc.sw.sdefault && (!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on))
+ {
+ ss.hasNoDefault = 1;
+
+ if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()))
+ ss.error("`switch` statement without a `default`; use `final switch` or add `default: assert(0);` or add `default: break;`");
+
+ // Generate runtime error if the default is hit
+ auto a = new Statements();
+ CompoundStatement cs;
+ Statement s;
+
+ if (global.params.useSwitchError == CHECKENABLE.on &&
+ global.params.checkAction != CHECKACTION.halt)
+ {
+ if (global.params.checkAction == CHECKACTION.C)
+ {
+ /* Rewrite as an assert(0) and let e2ir generate
+ * the call to the C assert failure function
+ */
+ s = new ExpStatement(ss.loc, new AssertExp(ss.loc, IntegerExp.literal!0));
+ }
+ else
+ {
+ if (!verifyHookExist(ss.loc, *sc, Id.__switch_error, "generating assert messages"))
+ return setError();
+
+ Expression sl = new IdentifierExp(ss.loc, Id.empty);
+ sl = new DotIdExp(ss.loc, sl, Id.object);
+ sl = new DotIdExp(ss.loc, sl, Id.__switch_error);
+
+ Expressions* args = new Expressions(2);
+ (*args)[0] = new StringExp(ss.loc, ss.loc.filename.toDString());
+ (*args)[1] = new IntegerExp(ss.loc.linnum);
+
+ sl = new CallExp(ss.loc, sl, args);
+ sl = sl.expressionSemantic(sc);
+
+ s = new SwitchErrorStatement(ss.loc, sl);
+ }
+ }
+ else
+ s = new ExpStatement(ss.loc, new HaltExp(ss.loc));
+
+ a.reserve(2);
+ sc.sw.sdefault = new DefaultStatement(ss.loc, s);
+ a.push(ss._body);
+ if (ss._body.blockExit(sc.func, false) & BE.fallthru)
+ a.push(new BreakStatement(Loc.initial, null));
+ a.push(sc.sw.sdefault);
+ cs = new CompoundStatement(ss.loc, a);
+ ss._body = cs;
+ }
+
+ if (ss.checkLabel())
+ {
+ sc.pop();
+ return setError();
+ }
+
+
+ if (!ss.condition.type.isString())
+ {
+ sc.pop();
+ result = ss;
+ return;
+ }
+
+ // Transform a switch with string labels into a switch with integer labels.
+
+ // The integer value of each case corresponds to the index of each label
+ // string in the sorted array of label strings.
+
+ // The value of the integer condition is obtained by calling the druntime template
+ // switch(object.__switch(cond, options...)) {0: {...}, 1: {...}, ...}
+
+ // We sort a copy of the array of labels because we want to do a binary search in object.__switch,
+ // without modifying the order of the case blocks here in the compiler.
+
+ if (!verifyHookExist(ss.loc, *sc, Id.__switch, "switch cases on strings"))
+ return setError();
+
+ size_t numcases = 0;
+ if (ss.cases)
+ numcases = ss.cases.dim;
+
+ for (size_t i = 0; i < numcases; i++)
+ {
+ CaseStatement cs = (*ss.cases)[i];
+ cs.index = cast(int)i;
+ }
+
+ // Make a copy of all the cases so that qsort doesn't scramble the actual
+ // data we pass to codegen (the order of the cases in the switch).
+ CaseStatements *csCopy = (*ss.cases).copy();
+
+ if (numcases)
+ {
+ static int sort_compare(in CaseStatement* x, in CaseStatement* y) @trusted
+ {
+ auto se1 = x.exp.isStringExp();
+ auto se2 = y.exp.isStringExp();
+ return (se1 && se2) ? se1.compare(se2) : 0;
+ }
+ // Sort cases for efficient lookup
+ csCopy.sort!sort_compare;
+ }
+
+ // The actual lowering
+ auto arguments = new Expressions();
+ arguments.push(ss.condition);
+
+ auto compileTimeArgs = new Objects();
+
+ // The type & label no.
+ compileTimeArgs.push(new TypeExp(ss.loc, ss.condition.type.nextOf()));
+
+ // The switch labels
+ foreach (caseString; *csCopy)
+ {
+ compileTimeArgs.push(caseString.exp);
+ }
+
+ Expression sl = new IdentifierExp(ss.loc, Id.empty);
+ sl = new DotIdExp(ss.loc, sl, Id.object);
+ sl = new DotTemplateInstanceExp(ss.loc, sl, Id.__switch, compileTimeArgs);
+
+ sl = new CallExp(ss.loc, sl, arguments);
+ sl = sl.expressionSemantic(sc);
+ ss.condition = sl;
+
+ auto i = 0;
+ foreach (c; *csCopy)
+ {
+ (*ss.cases)[c.index].exp = new IntegerExp(i++);
+ }
+
+ //printf("%s\n", ss._body.toChars());
+ ss.statementSemantic(sc);
+
+ sc.pop();
+ result = ss;
+ }
+
+ override void visit(CaseStatement cs)
+ {
+ SwitchStatement sw = sc.sw;
+ bool errors = false;
+
+ //printf("CaseStatement::semantic() %s\n", toChars());
+ sc = sc.startCTFE();
+ cs.exp = cs.exp.expressionSemantic(sc);
+ cs.exp = resolveProperties(sc, cs.exp);
+ sc = sc.endCTFE();
+
+ if (sw)
+ {
+ Expression initialExp = cs.exp;
+
+ cs.exp = cs.exp.implicitCastTo(sc, sw.condition.type);
+ cs.exp = cs.exp.optimize(WANTvalue | WANTexpand);
+
+ Expression e = cs.exp;
+ // Remove all the casts the user and/or implicitCastTo may introduce
+ // otherwise we'd sometimes fail the check below.
+ while (e.op == TOK.cast_)
+ e = (cast(CastExp)e).e1;
+
+ /* This is where variables are allowed as case expressions.
+ */
+ if (e.op == TOK.variable)
+ {
+ VarExp ve = cast(VarExp)e;
+ VarDeclaration v = ve.var.isVarDeclaration();
+ Type t = cs.exp.type.toBasetype();
+ if (v && (t.isintegral() || t.ty == Tclass))
+ {
+ /* Flag that we need to do special code generation
+ * for this, i.e. generate a sequence of if-then-else
+ */
+ sw.hasVars = 1;
+
+ /* TODO check if v can be uninitialized at that point.
+ */
+ if (!v.isConst() && !v.isImmutable())
+ {
+ cs.error("`case` variables have to be `const` or `immutable`");
+ }
+
+ if (sw.isFinal)
+ {
+ cs.error("`case` variables not allowed in `final switch` statements");
+ errors = true;
+ }
+
+ /* Find the outermost scope `scx` that set `sw`.
+ * Then search scope `scx` for a declaration of `v`.
+ */
+ for (Scope* scx = sc; scx; scx = scx.enclosing)
+ {
+ if (scx.enclosing && scx.enclosing.sw == sw)
+ continue;
+ assert(scx.sw == sw);
+
+ if (!scx.search(cs.exp.loc, v.ident, null))
+ {
+ cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body",
+ v.toChars(), v.loc.toChars());
+ errors = true;
+ }
+ break;
+ }
+ goto L1;
+ }
+ }
+ else
+ cs.exp = cs.exp.ctfeInterpret();
+
+ if (StringExp se = cs.exp.toStringExp())
+ cs.exp = se;
+ else if (cs.exp.op != TOK.int64 && cs.exp.op != TOK.error)
+ {
+ cs.error("`case` must be a `string` or an integral constant, not `%s`", cs.exp.toChars());
+ errors = true;
+ }
+
+ L1:
+ foreach (cs2; *sw.cases)
+ {
+ //printf("comparing '%s' with '%s'\n", exp.toChars(), cs.exp.toChars());
+ if (cs2.exp.equals(cs.exp))
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=15909
+ cs.error("duplicate `case %s` in `switch` statement", initialExp.toChars());
+ errors = true;
+ break;
+ }
+ }
+
+ sw.cases.push(cs);
+
+ // Resolve any goto case's with no exp to this case statement
+ for (size_t i = 0; i < sw.gotoCases.dim;)
+ {
+ GotoCaseStatement gcs = sw.gotoCases[i];
+ if (!gcs.exp)
+ {
+ gcs.cs = cs;
+ sw.gotoCases.remove(i); // remove from array
+ continue;
+ }
+ i++;
+ }
+
+ if (sc.sw.tf != sc.tf)
+ {
+ cs.error("`switch` and `case` are in different `finally` blocks");
+ errors = true;
+ }
+ if (sc.sw.tryBody != sc.tryBody)
+ {
+ cs.error("case cannot be in different `try` block level from `switch`");
+ errors = true;
+ }
+ }
+ else
+ {
+ cs.error("`case` not in `switch` statement");
+ errors = true;
+ }
+
+ sc.ctorflow.orCSX(CSX.label);
+ cs.statement = cs.statement.statementSemantic(sc);
+ if (cs.statement.isErrorStatement())
+ {
+ result = cs.statement;
+ return;
+ }
+ if (errors || cs.exp.op == TOK.error)
+ return setError();
+
+ cs.lastVar = sc.lastVar;
+ result = cs;
+ }
+
+ override void visit(CaseRangeStatement crs)
+ {
+ SwitchStatement sw = sc.sw;
+ if (sw is null)
+ {
+ crs.error("case range not in `switch` statement");
+ return setError();
+ }
+
+ //printf("CaseRangeStatement::semantic() %s\n", toChars());
+ bool errors = false;
+ if (sw.isFinal)
+ {
+ crs.error("case ranges not allowed in `final switch`");
+ errors = true;
+ }
+
+ sc = sc.startCTFE();
+ crs.first = crs.first.expressionSemantic(sc);
+ crs.first = resolveProperties(sc, crs.first);
+ sc = sc.endCTFE();
+ crs.first = crs.first.implicitCastTo(sc, sw.condition.type);
+ crs.first = crs.first.ctfeInterpret();
+
+ sc = sc.startCTFE();
+ crs.last = crs.last.expressionSemantic(sc);
+ crs.last = resolveProperties(sc, crs.last);
+ sc = sc.endCTFE();
+ crs.last = crs.last.implicitCastTo(sc, sw.condition.type);
+ crs.last = crs.last.ctfeInterpret();
+
+ if (crs.first.op == TOK.error || crs.last.op == TOK.error || errors)
+ {
+ if (crs.statement)
+ crs.statement.statementSemantic(sc);
+ return setError();
+ }
+
+ uinteger_t fval = crs.first.toInteger();
+ uinteger_t lval = crs.last.toInteger();
+ if ((crs.first.type.isunsigned() && fval > lval) || (!crs.first.type.isunsigned() && cast(sinteger_t)fval > cast(sinteger_t)lval))
+ {
+ crs.error("first `case %s` is greater than last `case %s`", crs.first.toChars(), crs.last.toChars());
+ errors = true;
+ lval = fval;
+ }
+
+ if (lval - fval > 256)
+ {
+ crs.error("had %llu cases which is more than 256 cases in case range", lval - fval);
+ errors = true;
+ lval = fval + 256;
+ }
+
+ if (errors)
+ return setError();
+
+ /* This works by replacing the CaseRange with an array of Case's.
+ *
+ * case a: .. case b: s;
+ * =>
+ * case a:
+ * [...]
+ * case b:
+ * s;
+ */
+
+ auto statements = new Statements();
+ for (uinteger_t i = fval; i != lval + 1; i++)
+ {
+ Statement s = crs.statement;
+ if (i != lval) // if not last case
+ s = new ExpStatement(crs.loc, cast(Expression)null);
+ Expression e = new IntegerExp(crs.loc, i, crs.first.type);
+ Statement cs = new CaseStatement(crs.loc, e, s);
+ statements.push(cs);
+ }
+ Statement s = new CompoundStatement(crs.loc, statements);
+ sc.ctorflow.orCSX(CSX.label);
+ s = s.statementSemantic(sc);
+ result = s;
+ }
+
+ override void visit(DefaultStatement ds)
+ {
+ //printf("DefaultStatement::semantic()\n");
+ bool errors = false;
+ if (sc.sw)
+ {
+ if (sc.sw.sdefault)
+ {
+ ds.error("`switch` statement already has a default");
+ errors = true;
+ }
+ sc.sw.sdefault = ds;
+
+ if (sc.sw.tf != sc.tf)
+ {
+ ds.error("`switch` and `default` are in different `finally` blocks");
+ errors = true;
+ }
+ if (sc.sw.tryBody != sc.tryBody)
+ {
+ ds.error("default cannot be in different `try` block level from `switch`");
+ errors = true;
+ }
+ if (sc.sw.isFinal)
+ {
+ ds.error("`default` statement not allowed in `final switch` statement");
+ errors = true;
+ }
+ }
+ else
+ {
+ ds.error("`default` not in `switch` statement");
+ errors = true;
+ }
+
+ sc.ctorflow.orCSX(CSX.label);
+ ds.statement = ds.statement.statementSemantic(sc);
+ if (errors || ds.statement.isErrorStatement())
+ return setError();
+
+ ds.lastVar = sc.lastVar;
+ result = ds;
+ }
+
+ override void visit(GotoDefaultStatement gds)
+ {
+ /* https://dlang.org/spec/statement.html#goto-statement
+ */
+
+ gds.sw = sc.sw;
+ if (!gds.sw)
+ {
+ gds.error("`goto default` not in `switch` statement");
+ return setError();
+ }
+ if (gds.sw.isFinal)
+ {
+ gds.error("`goto default` not allowed in `final switch` statement");
+ return setError();
+ }
+ result = gds;
+ }
+
+ override void visit(GotoCaseStatement gcs)
+ {
+ /* https://dlang.org/spec/statement.html#goto-statement
+ */
+
+ if (!sc.sw)
+ {
+ gcs.error("`goto case` not in `switch` statement");
+ return setError();
+ }
+
+ if (gcs.exp)
+ {
+ gcs.exp = gcs.exp.expressionSemantic(sc);
+ gcs.exp = gcs.exp.implicitCastTo(sc, sc.sw.condition.type);
+ gcs.exp = gcs.exp.optimize(WANTvalue);
+ if (gcs.exp.op == TOK.error)
+ return setError();
+ }
+
+ sc.sw.gotoCases.push(gcs);
+ result = gcs;
+ }
+
+ override void visit(ReturnStatement rs)
+ {
+ /* https://dlang.org/spec/statement.html#return-statement
+ */
+
+ //printf("ReturnStatement.dsymbolSemantic() %p, %s\n", rs, rs.toChars());
+
+ FuncDeclaration fd = sc.parent.isFuncDeclaration();
+ if (fd.fes)
+ fd = fd.fes.func; // fd is now function enclosing foreach
+
+ TypeFunction tf = cast(TypeFunction)fd.type;
+ assert(tf.ty == Tfunction);
+
+ if (rs.exp && rs.exp.op == TOK.variable && (cast(VarExp)rs.exp).var == fd.vresult)
+ {
+ // return vresult;
+ if (sc.fes)
+ {
+ assert(rs.caseDim == 0);
+ sc.fes.cases.push(rs);
+ result = new ReturnStatement(Loc.initial, new IntegerExp(sc.fes.cases.dim + 1));
+ return;
+ }
+ if (fd.returnLabel)
+ {
+ auto gs = new GotoStatement(rs.loc, Id.returnLabel);
+ gs.label = fd.returnLabel;
+ result = gs;
+ return;
+ }
+
+ if (!fd.returns)
+ fd.returns = new ReturnStatements();
+ fd.returns.push(rs);
+ result = rs;
+ return;
+ }
+
+ Type tret = tf.next;
+ Type tbret = tret ? tret.toBasetype() : null;
+
+ bool inferRef = (tf.isref && (fd.storage_class & STC.auto_));
+ Expression e0 = null;
+
+ bool errors = false;
+ if (sc.flags & SCOPE.contract)
+ {
+ rs.error("`return` statements cannot be in contracts");
+ errors = true;
+ }
+ if (sc.os && sc.os.tok != TOK.onScopeFailure)
+ {
+ rs.error("`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok));
+ errors = true;
+ }
+ if (sc.tf)
+ {
+ rs.error("`return` statements cannot be in `finally` bodies");
+ errors = true;
+ }
+
+ if (fd.isCtorDeclaration())
+ {
+ if (rs.exp)
+ {
+ rs.error("cannot return expression from constructor");
+ errors = true;
+ }
+
+ // Constructors implicitly do:
+ // return this;
+ rs.exp = new ThisExp(Loc.initial);
+ rs.exp.type = tret;
+ }
+ else if (rs.exp)
+ {
+ fd.hasReturnExp |= (fd.hasReturnExp & 1 ? 16 : 1);
+
+ FuncLiteralDeclaration fld = fd.isFuncLiteralDeclaration();
+ if (tret)
+ rs.exp = inferType(rs.exp, tret);
+ else if (fld && fld.treq)
+ rs.exp = inferType(rs.exp, fld.treq.nextOf().nextOf());
+
+ rs.exp = rs.exp.expressionSemantic(sc);
+ // If we're returning by ref, allow the expression to be `shared`
+ const returnSharedRef = (tf.isref && (fd.inferRetType || tret.isShared()));
+ rs.exp.checkSharedAccess(sc, returnSharedRef);
+
+ // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
+ if (rs.exp.op == TOK.type)
+ rs.exp = resolveAliasThis(sc, rs.exp);
+
+ rs.exp = resolveProperties(sc, rs.exp);
+ if (rs.exp.checkType())
+ rs.exp = ErrorExp.get();
+ if (auto f = isFuncAddress(rs.exp))
+ {
+ if (fd.inferRetType && f.checkForwardRef(rs.exp.loc))
+ rs.exp = ErrorExp.get();
+ }
+ if (checkNonAssignmentArrayOp(rs.exp))
+ rs.exp = ErrorExp.get();
+
+ // Extract side-effect part
+ rs.exp = Expression.extractLast(rs.exp, e0);
+ if (rs.exp.op == TOK.call)
+ rs.exp = valueNoDtor(rs.exp);
+
+ if (e0)
+ e0 = e0.optimize(WANTvalue);
+
+ /* Void-return function can have void typed expression
+ * on return statement.
+ */
+ if (tbret && tbret.ty == Tvoid || rs.exp.type.ty == Tvoid)
+ {
+ if (rs.exp.type.ty != Tvoid)
+ {
+ rs.error("cannot return non-void from `void` function");
+ errors = true;
+ rs.exp = new CastExp(rs.loc, rs.exp, Type.tvoid);
+ rs.exp = rs.exp.expressionSemantic(sc);
+ }
+
+ /* Replace:
+ * return exp;
+ * with:
+ * exp; return;
+ */
+ e0 = Expression.combine(e0, rs.exp);
+ rs.exp = null;
+ }
+ if (e0)
+ e0 = checkGC(sc, e0);
+ }
+
+ if (rs.exp)
+ {
+ if (fd.inferRetType) // infer return type
+ {
+ if (!tret)
+ {
+ tf.next = rs.exp.type;
+ }
+ else if (tret.ty != Terror && !rs.exp.type.equals(tret))
+ {
+ int m1 = rs.exp.type.implicitConvTo(tret);
+ int m2 = tret.implicitConvTo(rs.exp.type);
+ //printf("exp.type = %s m2<-->m1 tret %s\n", exp.type.toChars(), tret.toChars());
+ //printf("m1 = %d, m2 = %d\n", m1, m2);
+
+ if (m1 && m2)
+ {
+ }
+ else if (!m1 && m2)
+ tf.next = rs.exp.type;
+ else if (m1 && !m2)
+ {
+ }
+ else if (rs.exp.op != TOK.error)
+ {
+ rs.error("Expected return type of `%s`, not `%s`:",
+ tret.toChars(),
+ rs.exp.type.toChars());
+ errorSupplemental((fd.returns) ? (*fd.returns)[0].loc : fd.loc,
+ "Return type of `%s` inferred here.",
+ tret.toChars());
+
+ errors = true;
+ tf.next = Type.terror;
+ }
+ }
+
+ tret = tf.next;
+ tbret = tret.toBasetype();
+ }
+
+ if (inferRef) // deduce 'auto ref'
+ {
+ /* Determine "refness" of function return:
+ * if it's an lvalue, return by ref, else return by value
+ * https://dlang.org/spec/function.html#auto-ref-functions
+ */
+
+ void turnOffRef(scope void delegate() supplemental)
+ {
+ tf.isref = false; // return by value
+ tf.isreturn = false; // ignore 'return' attribute, whether explicit or inferred
+ fd.storage_class &= ~STC.return_;
+
+ // If we previously assumed the function could be ref when
+ // checking for `shared`, make sure we were right
+ if (global.params.noSharedAccess && rs.exp.type.isShared())
+ {
+ fd.error("function returns `shared` but cannot be inferred `ref`");
+ supplemental();
+ }
+ }
+
+ if (rs.exp.isLvalue())
+ {
+ /* May return by ref
+ */
+ if (checkReturnEscapeRef(sc, rs.exp, true))
+ turnOffRef(() { checkReturnEscapeRef(sc, rs.exp, false); });
+ else if (!rs.exp.type.constConv(tf.next))
+ turnOffRef(
+ () => rs.loc.errorSupplemental("cannot implicitly convert `%s` of type `%s` to `%s`",
+ rs.exp.toChars(), rs.exp.type.toChars(), tf.next.toChars())
+ );
+ }
+ else
+ turnOffRef(
+ () => rs.loc.errorSupplemental("return value `%s` is not an lvalue", rs.exp.toChars())
+ );
+
+ /* The "refness" is determined by all of return statements.
+ * This means:
+ * return 3; return x; // ok, x can be a value
+ * return x; return 3; // ok, x can be a value
+ */
+ }
+ }
+ else
+ {
+ // infer return type
+ if (fd.inferRetType)
+ {
+ if (tf.next && tf.next.ty != Tvoid)
+ {
+ if (tf.next.ty != Terror)
+ {
+ rs.error("mismatched function return type inference of `void` and `%s`", tf.next.toChars());
+ }
+ errors = true;
+ tf.next = Type.terror;
+ }
+ else
+ tf.next = Type.tvoid;
+
+ tret = tf.next;
+ tbret = tret.toBasetype();
+ }
+
+ if (inferRef) // deduce 'auto ref'
+ tf.isref = false;
+
+ if (tbret.ty != Tvoid) // if non-void return
+ {
+ if (tbret.ty != Terror)
+ rs.error("`return` expression expected");
+ errors = true;
+ }
+ else if (fd.isMain())
+ {
+ // main() returns 0, even if it returns void
+ rs.exp = IntegerExp.literal!0;
+ }
+ }
+
+ // If any branches have called a ctor, but this branch hasn't, it's an error
+ if (sc.ctorflow.callSuper & CSX.any_ctor && !(sc.ctorflow.callSuper & (CSX.this_ctor | CSX.super_ctor)))
+ {
+ rs.error("`return` without calling constructor");
+ errors = true;
+ }
+
+ if (sc.ctorflow.fieldinit.length) // if aggregate fields are being constructed
+ {
+ auto ad = fd.isMemberLocal();
+ assert(ad);
+ foreach (i, v; ad.fields)
+ {
+ bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested());
+ if (mustInit && !(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor))
+ {
+ rs.error("an earlier `return` statement skips field `%s` initialization", v.toChars());
+ errors = true;
+ }
+ }
+ }
+ sc.ctorflow.orCSX(CSX.return_);
+
+ if (errors)
+ return setError();
+
+ if (sc.fes)
+ {
+ if (!rs.exp)
+ {
+ // Send out "case receiver" statement to the foreach.
+ // return exp;
+ Statement s = new ReturnStatement(Loc.initial, rs.exp);
+ sc.fes.cases.push(s);
+
+ // Immediately rewrite "this" return statement as:
+ // return cases.dim+1;
+ rs.exp = new IntegerExp(sc.fes.cases.dim + 1);
+ if (e0)
+ {
+ result = new CompoundStatement(rs.loc, new ExpStatement(rs.loc, e0), rs);
+ return;
+ }
+ result = rs;
+ return;
+ }
+ else
+ {
+ fd.buildResultVar(null, rs.exp.type);
+ bool r = fd.vresult.checkNestedReference(sc, Loc.initial);
+ assert(!r); // vresult should be always accessible
+
+ // Send out "case receiver" statement to the foreach.
+ // return vresult;
+ Statement s = new ReturnStatement(Loc.initial, new VarExp(Loc.initial, fd.vresult));
+ sc.fes.cases.push(s);
+
+ // Save receiver index for the later rewriting from:
+ // return exp;
+ // to:
+ // vresult = exp; retrun caseDim;
+ rs.caseDim = sc.fes.cases.dim + 1;
+ }
+ }
+ if (rs.exp)
+ {
+ if (!fd.returns)
+ fd.returns = new ReturnStatements();
+ fd.returns.push(rs);
+ }
+ if (e0)
+ {
+ if (e0.op == TOK.declaration || e0.op == TOK.comma)
+ {
+ rs.exp = Expression.combine(e0, rs.exp);
+ }
+ else
+ {
+ result = new CompoundStatement(rs.loc, new ExpStatement(rs.loc, e0), rs);
+ return;
+ }
+ }
+ result = rs;
+ }
+
+ override void visit(BreakStatement bs)
+ {
+ /* https://dlang.org/spec/statement.html#break-statement
+ */
+
+ //printf("BreakStatement::semantic()\n");
+
+ // If:
+ // break Identifier;
+ if (bs.ident)
+ {
+ bs.ident = fixupLabelName(sc, bs.ident);
+
+ FuncDeclaration thisfunc = sc.func;
+
+ for (Scope* scx = sc; scx; scx = scx.enclosing)
+ {
+ if (scx.func != thisfunc) // if in enclosing function
+ {
+ if (sc.fes) // if this is the body of a foreach
+ {
+ /* Post this statement to the fes, and replace
+ * it with a return value that caller will put into
+ * a switch. Caller will figure out where the break
+ * label actually is.
+ * Case numbers start with 2, not 0, as 0 is continue
+ * and 1 is break.
+ */
+ sc.fes.cases.push(bs);
+ result = new ReturnStatement(Loc.initial, new IntegerExp(sc.fes.cases.dim + 1));
+ return;
+ }
+ break; // can't break to it
+ }
+
+ LabelStatement ls = scx.slabel;
+ if (ls && ls.ident == bs.ident)
+ {
+ Statement s = ls.statement;
+ if (!s || !s.hasBreak())
+ bs.error("label `%s` has no `break`", bs.ident.toChars());
+ else if (ls.tf != sc.tf)
+ bs.error("cannot break out of `finally` block");
+ else
+ {
+ ls.breaks = true;
+ result = bs;
+ return;
+ }
+ return setError();
+ }
+ }
+ bs.error("enclosing label `%s` for `break` not found", bs.ident.toChars());
+ return setError();
+ }
+ else if (!sc.sbreak)
+ {
+ if (sc.os && sc.os.tok != TOK.onScopeFailure)
+ {
+ bs.error("`break` is not allowed inside `%s` bodies", Token.toChars(sc.os.tok));
+ }
+ else if (sc.fes)
+ {
+ // Replace break; with return 1;
+ result = new ReturnStatement(Loc.initial, IntegerExp.literal!1);
+ return;
+ }
+ else
+ bs.error("`break` is not inside a loop or `switch`");
+ return setError();
+ }
+ else if (sc.sbreak.isForwardingStatement())
+ {
+ bs.error("must use labeled `break` within `static foreach`");
+ }
+ result = bs;
+ }
+
+ override void visit(ContinueStatement cs)
+ {
+ /* https://dlang.org/spec/statement.html#continue-statement
+ */
+
+ //printf("ContinueStatement::semantic() %p\n", cs);
+ if (cs.ident)
+ {
+ cs.ident = fixupLabelName(sc, cs.ident);
+
+ Scope* scx;
+ FuncDeclaration thisfunc = sc.func;
+
+ for (scx = sc; scx; scx = scx.enclosing)
+ {
+ LabelStatement ls;
+ if (scx.func != thisfunc) // if in enclosing function
+ {
+ if (sc.fes) // if this is the body of a foreach
+ {
+ for (; scx; scx = scx.enclosing)
+ {
+ ls = scx.slabel;
+ if (ls && ls.ident == cs.ident && ls.statement == sc.fes)
+ {
+ // Replace continue ident; with return 0;
+ result = new ReturnStatement(Loc.initial, IntegerExp.literal!0);
+ return;
+ }
+ }
+
+ /* Post this statement to the fes, and replace
+ * it with a return value that caller will put into
+ * a switch. Caller will figure out where the break
+ * label actually is.
+ * Case numbers start with 2, not 0, as 0 is continue
+ * and 1 is break.
+ */
+ sc.fes.cases.push(cs);
+ result = new ReturnStatement(Loc.initial, new IntegerExp(sc.fes.cases.dim + 1));
+ return;
+ }
+ break; // can't continue to it
+ }
+
+ ls = scx.slabel;
+ if (ls && ls.ident == cs.ident)
+ {
+ Statement s = ls.statement;
+ if (!s || !s.hasContinue())
+ cs.error("label `%s` has no `continue`", cs.ident.toChars());
+ else if (ls.tf != sc.tf)
+ cs.error("cannot continue out of `finally` block");
+ else
+ {
+ result = cs;
+ return;
+ }
+ return setError();
+ }
+ }
+ cs.error("enclosing label `%s` for `continue` not found", cs.ident.toChars());
+ return setError();
+ }
+ else if (!sc.scontinue)
+ {
+ if (sc.os && sc.os.tok != TOK.onScopeFailure)
+ {
+ cs.error("`continue` is not allowed inside `%s` bodies", Token.toChars(sc.os.tok));
+ }
+ else if (sc.fes)
+ {
+ // Replace continue; with return 0;
+ result = new ReturnStatement(Loc.initial, IntegerExp.literal!0);
+ return;
+ }
+ else
+ cs.error("`continue` is not inside a loop");
+ return setError();
+ }
+ else if (sc.scontinue.isForwardingStatement())
+ {
+ cs.error("must use labeled `continue` within `static foreach`");
+ }
+ result = cs;
+ }
+
+ override void visit(SynchronizedStatement ss)
+ {
+ /* https://dlang.org/spec/statement.html#synchronized-statement
+ */
+
+ if (ss.exp)
+ {
+ ss.exp = ss.exp.expressionSemantic(sc);
+ ss.exp = resolveProperties(sc, ss.exp);
+ ss.exp = ss.exp.optimize(WANTvalue);
+ ss.exp = checkGC(sc, ss.exp);
+ if (ss.exp.op == TOK.error)
+ {
+ if (ss._body)
+ ss._body = ss._body.statementSemantic(sc);
+ return setError();
+ }
+
+ ClassDeclaration cd = ss.exp.type.isClassHandle();
+ if (!cd)
+ {
+ ss.error("can only `synchronize` on class objects, not `%s`", ss.exp.type.toChars());
+ return setError();
+ }
+ else if (cd.isInterfaceDeclaration())
+ {
+ /* Cast the interface to an object, as the object has the monitor,
+ * not the interface.
+ */
+ if (!ClassDeclaration.object)
+ {
+ ss.error("missing or corrupt object.d");
+ fatal();
+ }
+
+ Type t = ClassDeclaration.object.type;
+ t = t.typeSemantic(Loc.initial, sc).toBasetype();
+ assert(t.ty == Tclass);
+
+ ss.exp = new CastExp(ss.loc, ss.exp, t);
+ ss.exp = ss.exp.expressionSemantic(sc);
+ }
+ version (all)
+ {
+ /* Rewrite as:
+ * auto tmp = exp;
+ * _d_monitorenter(tmp);
+ * try { body } finally { _d_monitorexit(tmp); }
+ */
+ auto tmp = copyToTemp(0, "__sync", ss.exp);
+ tmp.dsymbolSemantic(sc);
+
+ auto cs = new Statements();
+ cs.push(new ExpStatement(ss.loc, tmp));
+
+ auto args = new Parameters();
+ args.push(new Parameter(0, ClassDeclaration.object.type, null, null, null));
+
+ FuncDeclaration fdenter = FuncDeclaration.genCfunc(args, Type.tvoid, Id.monitorenter);
+ Expression e = new CallExp(ss.loc, fdenter, new VarExp(ss.loc, tmp));
+ e.type = Type.tvoid; // do not run semantic on e
+
+ cs.push(new ExpStatement(ss.loc, e));
+ FuncDeclaration fdexit = FuncDeclaration.genCfunc(args, Type.tvoid, Id.monitorexit);
+ e = new CallExp(ss.loc, fdexit, new VarExp(ss.loc, tmp));
+ e.type = Type.tvoid; // do not run semantic on e
+ Statement s = new ExpStatement(ss.loc, e);
+ s = new TryFinallyStatement(ss.loc, ss._body, s);
+ cs.push(s);
+
+ s = new CompoundStatement(ss.loc, cs);
+ result = s.statementSemantic(sc);
+ }
+ }
+ else
+ {
+ /* Generate our own critical section, then rewrite as:
+ * static shared void* __critsec;
+ * _d_criticalenter2(&__critsec);
+ * try { body } finally { _d_criticalexit(__critsec); }
+ */
+ auto id = Identifier.generateId("__critsec");
+ auto t = Type.tvoidptr;
+ auto tmp = new VarDeclaration(ss.loc, t, id, null);
+ tmp.storage_class |= STC.temp | STC.shared_ | STC.static_;
+ Expression tmpExp = new VarExp(ss.loc, tmp);
+
+ auto cs = new Statements();
+ cs.push(new ExpStatement(ss.loc, tmp));
+
+ /* This is just a dummy variable for "goto skips declaration" error.
+ * Backend optimizer could remove this unused variable.
+ */
+ auto v = new VarDeclaration(ss.loc, Type.tvoidptr, Identifier.generateId("__sync"), null);
+ v.dsymbolSemantic(sc);
+ cs.push(new ExpStatement(ss.loc, v));
+
+ auto enterArgs = new Parameters();
+ enterArgs.push(new Parameter(0, t.pointerTo(), null, null, null));
+
+ FuncDeclaration fdenter = FuncDeclaration.genCfunc(enterArgs, Type.tvoid, Id.criticalenter, STC.nothrow_);
+ Expression e = new AddrExp(ss.loc, tmpExp);
+ e = e.expressionSemantic(sc);
+ e = new CallExp(ss.loc, fdenter, e);
+ e.type = Type.tvoid; // do not run semantic on e
+ cs.push(new ExpStatement(ss.loc, e));
+
+ auto exitArgs = new Parameters();
+ exitArgs.push(new Parameter(0, t, null, null, null));
+
+ FuncDeclaration fdexit = FuncDeclaration.genCfunc(exitArgs, Type.tvoid, Id.criticalexit, STC.nothrow_);
+ e = new CallExp(ss.loc, fdexit, tmpExp);
+ e.type = Type.tvoid; // do not run semantic on e
+ Statement s = new ExpStatement(ss.loc, e);
+ s = new TryFinallyStatement(ss.loc, ss._body, s);
+ cs.push(s);
+
+ s = new CompoundStatement(ss.loc, cs);
+ result = s.statementSemantic(sc);
+ }
+ }
+
+ override void visit(WithStatement ws)
+ {
+ /* https://dlang.org/spec/statement.html#with-statement
+ */
+
+ ScopeDsymbol sym;
+ Initializer _init;
+
+ //printf("WithStatement::semantic()\n");
+ ws.exp = ws.exp.expressionSemantic(sc);
+ ws.exp = resolveProperties(sc, ws.exp);
+ ws.exp = ws.exp.optimize(WANTvalue);
+ ws.exp = checkGC(sc, ws.exp);
+ if (ws.exp.op == TOK.error)
+ return setError();
+ if (ws.exp.op == TOK.scope_)
+ {
+ sym = new WithScopeSymbol(ws);
+ sym.parent = sc.scopesym;
+ sym.endlinnum = ws.endloc.linnum;
+ }
+ else if (ws.exp.op == TOK.type)
+ {
+ Dsymbol s = (cast(TypeExp)ws.exp).type.toDsymbol(sc);
+ if (!s || !s.isScopeDsymbol())
+ {
+ ws.error("`with` type `%s` has no members", ws.exp.toChars());
+ return setError();
+ }
+ sym = new WithScopeSymbol(ws);
+ sym.parent = sc.scopesym;
+ sym.endlinnum = ws.endloc.linnum;
+ }
+ else
+ {
+ Type t = ws.exp.type.toBasetype();
+
+ Expression olde = ws.exp;
+ if (t.ty == Tpointer)
+ {
+ ws.exp = new PtrExp(ws.loc, ws.exp);
+ ws.exp = ws.exp.expressionSemantic(sc);
+ t = ws.exp.type.toBasetype();
+ }
+
+ assert(t);
+ t = t.toBasetype();
+ if (t.isClassHandle())
+ {
+ _init = new ExpInitializer(ws.loc, ws.exp);
+ ws.wthis = new VarDeclaration(ws.loc, ws.exp.type, Id.withSym, _init);
+ ws.wthis.storage_class |= STC.temp;
+ ws.wthis.dsymbolSemantic(sc);
+
+ sym = new WithScopeSymbol(ws);
+ sym.parent = sc.scopesym;
+ sym.endlinnum = ws.endloc.linnum;
+ }
+ else if (t.ty == Tstruct)
+ {
+ if (!ws.exp.isLvalue())
+ {
+ /* Re-write to
+ * {
+ * auto __withtmp = exp
+ * with(__withtmp)
+ * {
+ * ...
+ * }
+ * }
+ */
+ auto tmp = copyToTemp(0, "__withtmp", ws.exp);
+ tmp.dsymbolSemantic(sc);
+ auto es = new ExpStatement(ws.loc, tmp);
+ ws.exp = new VarExp(ws.loc, tmp);
+ Statement ss = new ScopeStatement(ws.loc, new CompoundStatement(ws.loc, es, ws), ws.endloc);
+ result = ss.statementSemantic(sc);
+ return;
+ }
+ Expression e = ws.exp.addressOf();
+ _init = new ExpInitializer(ws.loc, e);
+ ws.wthis = new VarDeclaration(ws.loc, e.type, Id.withSym, _init);
+ ws.wthis.storage_class |= STC.temp;
+ ws.wthis.dsymbolSemantic(sc);
+ sym = new WithScopeSymbol(ws);
+ // Need to set the scope to make use of resolveAliasThis
+ sym.setScope(sc);
+ sym.parent = sc.scopesym;
+ sym.endlinnum = ws.endloc.linnum;
+ }
+ else
+ {
+ ws.error("`with` expressions must be aggregate types or pointers to them, not `%s`", olde.type.toChars());
+ return setError();
+ }
+ }
+
+ if (ws._body)
+ {
+ sym._scope = sc;
+ sc = sc.push(sym);
+ sc.insert(sym);
+ ws._body = ws._body.statementSemantic(sc);
+ sc.pop();
+ if (ws._body && ws._body.isErrorStatement())
+ {
+ result = ws._body;
+ return;
+ }
+ }
+
+ result = ws;
+ }
+
+ // https://dlang.org/spec/statement.html#TryStatement
+ override void visit(TryCatchStatement tcs)
+ {
+ //printf("TryCatchStatement.semantic()\n");
+
+ if (!global.params.useExceptions)
+ {
+ tcs.error("Cannot use try-catch statements with -betterC");
+ return setError();
+ }
+
+ if (!ClassDeclaration.throwable)
+ {
+ tcs.error("Cannot use try-catch statements because `object.Throwable` was not declared");
+ return setError();
+ }
+
+ uint flags;
+ enum FLAGcpp = 1;
+ enum FLAGd = 2;
+
+ tcs.tryBody = sc.tryBody; // chain on the in-flight tryBody
+ tcs._body = tcs._body.semanticScope(sc, null, null, tcs);
+ assert(tcs._body);
+
+ /* Even if body is empty, still do semantic analysis on catches
+ */
+ bool catchErrors = false;
+ foreach (i, c; *tcs.catches)
+ {
+ c.catchSemantic(sc);
+ if (c.errors)
+ {
+ catchErrors = true;
+ continue;
+ }
+ auto cd = c.type.toBasetype().isClassHandle();
+ flags |= cd.isCPPclass() ? FLAGcpp : FLAGd;
+
+ // Determine if current catch 'hides' any previous catches
+ foreach (j; 0 .. i)
+ {
+ Catch cj = (*tcs.catches)[j];
+ const si = c.loc.toChars();
+ const sj = cj.loc.toChars();
+ if (c.type.toBasetype().implicitConvTo(cj.type.toBasetype()))
+ {
+ tcs.error("`catch` at %s hides `catch` at %s", sj, si);
+ catchErrors = true;
+ }
+ }
+ }
+
+ if (sc.func)
+ {
+ sc.func.flags |= FUNCFLAG.hasCatches;
+ if (flags == (FLAGcpp | FLAGd))
+ {
+ tcs.error("cannot mix catching D and C++ exceptions in the same try-catch");
+ catchErrors = true;
+ }
+ }
+
+ if (catchErrors)
+ return setError();
+
+ if (tcs._body.isErrorStatement())
+ {
+ result = tcs._body;
+ return;
+ }
+
+ /* If the try body never throws, we can eliminate any catches
+ * of recoverable exceptions.
+ */
+ if (!(tcs._body.blockExit(sc.func, false) & BE.throw_) && ClassDeclaration.exception)
+ {
+ foreach_reverse (i; 0 .. tcs.catches.dim)
+ {
+ Catch c = (*tcs.catches)[i];
+
+ /* If catch exception type is derived from Exception
+ */
+ if (c.type.toBasetype().implicitConvTo(ClassDeclaration.exception.type) &&
+ (!c.handler || !c.handler.comeFrom()))
+ {
+ // Remove c from the array of catches
+ tcs.catches.remove(i);
+ }
+ }
+ }
+
+ if (tcs.catches.dim == 0)
+ {
+ result = tcs._body.hasCode() ? tcs._body : null;
+ return;
+ }
+
+ result = tcs;
+ }
+
+ override void visit(TryFinallyStatement tfs)
+ {
+ //printf("TryFinallyStatement::semantic()\n");
+ tfs.tryBody = sc.tryBody; // chain on in-flight tryBody
+ tfs._body = tfs._body.semanticScope(sc, null, null, tfs);
+
+ sc = sc.push();
+ sc.tf = tfs;
+ sc.sbreak = null;
+ sc.scontinue = null; // no break or continue out of finally block
+ tfs.finalbody = tfs.finalbody.semanticNoScope(sc);
+ sc.pop();
+
+ if (!tfs._body)
+ {
+ result = tfs.finalbody;
+ return;
+ }
+ if (!tfs.finalbody)
+ {
+ result = tfs._body;
+ return;
+ }
+
+ auto blockexit = tfs._body.blockExit(sc.func, false);
+
+ // if not worrying about exceptions
+ if (!(global.params.useExceptions && ClassDeclaration.throwable))
+ blockexit &= ~BE.throw_; // don't worry about paths that otherwise may throw
+
+ // Don't care about paths that halt, either
+ if ((blockexit & ~BE.halt) == BE.fallthru)
+ {
+ result = new CompoundStatement(tfs.loc, tfs._body, tfs.finalbody);
+ return;
+ }
+ tfs.bodyFallsThru = (blockexit & BE.fallthru) != 0;
+ result = tfs;
+ }
+
+ override void visit(ScopeGuardStatement oss)
+ {
+ /* https://dlang.org/spec/statement.html#scope-guard-statement
+ */
+
+ if (oss.tok != TOK.onScopeExit)
+ {
+ // scope(success) and scope(failure) are rewritten to try-catch(-finally) statement,
+ // so the generated catch block cannot be placed in finally block.
+ // See also Catch::semantic.
+ if (sc.os && sc.os.tok != TOK.onScopeFailure)
+ {
+ // If enclosing is scope(success) or scope(exit), this will be placed in finally block.
+ oss.error("cannot put `%s` statement inside `%s`", Token.toChars(oss.tok), Token.toChars(sc.os.tok));
+ return setError();
+ }
+ if (sc.tf)
+ {
+ oss.error("cannot put `%s` statement inside `finally` block", Token.toChars(oss.tok));
+ return setError();
+ }
+ }
+
+ sc = sc.push();
+ sc.tf = null;
+ sc.os = oss;
+ if (oss.tok != TOK.onScopeFailure)
+ {
+ // Jump out from scope(failure) block is allowed.
+ sc.sbreak = null;
+ sc.scontinue = null;
+ }
+ oss.statement = oss.statement.semanticNoScope(sc);
+ sc.pop();
+
+ if (!oss.statement || oss.statement.isErrorStatement())
+ {
+ result = oss.statement;
+ return;
+ }
+ result = oss;
+ }
+
+ override void visit(ThrowStatement ts)
+ {
+ /* https://dlang.org/spec/statement.html#throw-statement
+ */
+
+ //printf("ThrowStatement::semantic()\n");
+
+ if (!global.params.useExceptions)
+ {
+ ts.error("Cannot use `throw` statements with -betterC");
+ return setError();
+ }
+
+ if (!ClassDeclaration.throwable)
+ {
+ ts.error("Cannot use `throw` statements because `object.Throwable` was not declared");
+ return setError();
+ }
+
+ FuncDeclaration fd = sc.parent.isFuncDeclaration();
+ fd.hasReturnExp |= 2;
+
+ if (ts.exp.op == TOK.new_)
+ {
+ NewExp ne = cast(NewExp)ts.exp;
+ ne.thrownew = true;
+ }
+
+ ts.exp = ts.exp.expressionSemantic(sc);
+ ts.exp = resolveProperties(sc, ts.exp);
+ ts.exp = checkGC(sc, ts.exp);
+ if (ts.exp.op == TOK.error)
+ return setError();
+
+ checkThrowEscape(sc, ts.exp, false);
+
+ ClassDeclaration cd = ts.exp.type.toBasetype().isClassHandle();
+ if (!cd || ((cd != ClassDeclaration.throwable) && !ClassDeclaration.throwable.isBaseOf(cd, null)))
+ {
+ ts.error("can only throw class objects derived from `Throwable`, not type `%s`", ts.exp.type.toChars());
+ return setError();
+ }
+
+ result = ts;
+ }
+
+ override void visit(DebugStatement ds)
+ {
+ if (ds.statement)
+ {
+ sc = sc.push();
+ sc.flags |= SCOPE.debug_;
+ ds.statement = ds.statement.statementSemantic(sc);
+ sc.pop();
+ }
+ result = ds.statement;
+ }
+
+ override void visit(GotoStatement gs)
+ {
+ /* https://dlang.org/spec/statement.html#goto-statement
+ */
+
+ //printf("GotoStatement::semantic()\n");
+ FuncDeclaration fd = sc.func;
+
+ gs.ident = fixupLabelName(sc, gs.ident);
+ gs.label = fd.searchLabel(gs.ident, gs.loc);
+ gs.tryBody = sc.tryBody;
+ gs.tf = sc.tf;
+ gs.os = sc.os;
+ gs.lastVar = sc.lastVar;
+
+ if (!gs.label.statement && sc.fes)
+ {
+ /* Either the goto label is forward referenced or it
+ * is in the function that the enclosing foreach is in.
+ * Can't know yet, so wrap the goto in a scope statement
+ * so we can patch it later, and add it to a 'look at this later'
+ * list.
+ */
+ gs.label.deleted = true;
+ auto ss = new ScopeStatement(gs.loc, gs, gs.loc);
+ sc.fes.gotos.push(ss); // 'look at this later' list
+ result = ss;
+ return;
+ }
+
+ // Add to fwdref list to check later
+ if (!gs.label.statement)
+ {
+ if (!fd.gotos)
+ fd.gotos = new GotoStatements();
+ fd.gotos.push(gs);
+ }
+ else if (gs.checkLabel())
+ return setError();
+
+ result = gs;
+ }
+
+ override void visit(LabelStatement ls)
+ {
+ //printf("LabelStatement::semantic()\n");
+ FuncDeclaration fd = sc.parent.isFuncDeclaration();
+
+ ls.ident = fixupLabelName(sc, ls.ident);
+ ls.tryBody = sc.tryBody;
+ ls.tf = sc.tf;
+ ls.os = sc.os;
+ ls.lastVar = sc.lastVar;
+
+ LabelDsymbol ls2 = fd.searchLabel(ls.ident, ls.loc);
+ if (ls2.statement)
+ {
+ ls.error("label `%s` already defined", ls2.toChars());
+ return setError();
+ }
+ else
+ ls2.statement = ls;
+
+ sc = sc.push();
+ sc.scopesym = sc.enclosing.scopesym;
+
+ sc.ctorflow.orCSX(CSX.label);
+
+ sc.slabel = ls;
+ if (ls.statement)
+ ls.statement = ls.statement.statementSemantic(sc);
+ sc.pop();
+
+ result = ls;
+ }
+
+ override void visit(AsmStatement s)
+ {
+ /* https://dlang.org/spec/statement.html#asm
+ */
+
+ //printf("AsmStatement()::semantic()\n");
+ result = asmSemantic(s, sc);
+ }
+
+ override void visit(CompoundAsmStatement cas)
+ {
+ //printf("CompoundAsmStatement()::semantic()\n");
+ // Apply postfix attributes of the asm block to each statement.
+ sc = sc.push();
+ sc.stc |= cas.stc;
+
+ /* Go through the statements twice, first to declare any labels,
+ * second for anything else.
+ */
+
+ foreach (ref s; *cas.statements)
+ {
+ if (s)
+ {
+ if (auto ls = s.isLabelStatement())
+ {
+ sc.func.searchLabel(ls.ident, ls.loc);
+ }
+ }
+ }
+
+ foreach (ref s; *cas.statements)
+ {
+ s = s ? s.statementSemantic(sc) : null;
+ }
+
+ assert(sc.func);
+ // use setImpure/setGC when the deprecation cycle is over
+ PURE purity;
+ if (!(cas.stc & STC.pure_) && (purity = sc.func.isPureBypassingInference()) != PURE.impure && purity != PURE.fwdref)
+ cas.deprecation("`asm` statement is assumed to be impure - mark it with `pure` if it is not");
+ if (!(cas.stc & STC.nogc) && sc.func.isNogcBypassingInference())
+ cas.deprecation("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not");
+ if (!(cas.stc & (STC.trusted | STC.safe)) && sc.func.setUnsafe())
+ cas.error("`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not");
+
+ sc.pop();
+ result = cas;
+ }
+
+ override void visit(ImportStatement imps)
+ {
+ /* https://dlang.org/spec/module.html#ImportDeclaration
+ */
+
+ foreach (i; 0 .. imps.imports.dim)
+ {
+ Import s = (*imps.imports)[i].isImport();
+ assert(!s.aliasdecls.dim);
+ foreach (j, name; s.names)
+ {
+ Identifier _alias = s.aliases[j];
+ if (!_alias)
+ _alias = name;
+
+ auto tname = new TypeIdentifier(s.loc, name);
+ auto ad = new AliasDeclaration(s.loc, _alias, tname);
+ ad._import = s;
+ s.aliasdecls.push(ad);
+ }
+
+ s.dsymbolSemantic(sc);
+
+ // https://issues.dlang.org/show_bug.cgi?id=19942
+ // If the module that's being imported doesn't exist, don't add it to the symbol table
+ // for the current scope.
+ if (s.mod !is null)
+ {
+ Module.addDeferredSemantic2(s); // https://issues.dlang.org/show_bug.cgi?id=14666
+ sc.insert(s);
+
+ foreach (aliasdecl; s.aliasdecls)
+ {
+ sc.insert(aliasdecl);
+ }
+ }
+ }
+ result = imps;
+ }
+}
+
+void catchSemantic(Catch c, Scope* sc)
+{
+ //printf("Catch::semantic(%s)\n", ident.toChars());
+
+ if (sc.os && sc.os.tok != TOK.onScopeFailure)
+ {
+ // If enclosing is scope(success) or scope(exit), this will be placed in finally block.
+ error(c.loc, "cannot put `catch` statement inside `%s`", Token.toChars(sc.os.tok));
+ c.errors = true;
+ }
+ if (sc.tf)
+ {
+ /* This is because the _d_local_unwind() gets the stack munged
+ * up on this. The workaround is to place any try-catches into
+ * a separate function, and call that.
+ * To fix, have the compiler automatically convert the finally
+ * body into a nested function.
+ */
+ error(c.loc, "cannot put `catch` statement inside `finally` block");
+ c.errors = true;
+ }
+
+ auto sym = new ScopeDsymbol();
+ sym.parent = sc.scopesym;
+ sc = sc.push(sym);
+
+ if (!c.type)
+ {
+ error(c.loc, "`catch` statement without an exception specification is deprecated");
+ errorSupplemental(c.loc, "use `catch(Throwable)` for old behavior");
+ c.errors = true;
+
+ // reference .object.Throwable
+ c.type = getThrowable();
+ }
+ c.type = c.type.typeSemantic(c.loc, sc);
+ if (c.type == Type.terror)
+ {
+ c.errors = true;
+ sc.pop();
+ return;
+ }
+
+ StorageClass stc;
+ auto cd = c.type.toBasetype().isClassHandle();
+ if (!cd)
+ {
+ error(c.loc, "can only catch class objects, not `%s`", c.type.toChars());
+ c.errors = true;
+ }
+ else if (cd.isCPPclass())
+ {
+ if (!target.cpp.exceptions)
+ {
+ error(c.loc, "catching C++ class objects not supported for this target");
+ c.errors = true;
+ }
+ if (sc.func && !sc.intypeof && !c.internalCatch && sc.func.setUnsafe())
+ {
+ error(c.loc, "cannot catch C++ class objects in `@safe` code");
+ c.errors = true;
+ }
+ }
+ else if (cd != ClassDeclaration.throwable && !ClassDeclaration.throwable.isBaseOf(cd, null))
+ {
+ error(c.loc, "can only catch class objects derived from `Throwable`, not `%s`", c.type.toChars());
+ c.errors = true;
+ }
+ else if (sc.func && !sc.intypeof && !c.internalCatch && ClassDeclaration.exception &&
+ cd != ClassDeclaration.exception && !ClassDeclaration.exception.isBaseOf(cd, null) &&
+ sc.func.setUnsafe())
+ {
+ error(c.loc, "can only catch class objects derived from `Exception` in `@safe` code, not `%s`", c.type.toChars());
+ c.errors = true;
+ }
+ else if (global.params.ehnogc)
+ {
+ stc |= STC.scope_;
+ }
+
+ // DIP1008 requires destruction of the Throwable, even if the user didn't specify an identifier
+ auto ident = c.ident;
+ if (!ident && global.params.ehnogc)
+ ident = Identifier.generateAnonymousId("var");
+
+ if (ident)
+ {
+ c.var = new VarDeclaration(c.loc, c.type, ident, null, stc);
+ c.var.iscatchvar = true;
+ c.var.dsymbolSemantic(sc);
+ sc.insert(c.var);
+
+ if (global.params.ehnogc && stc & STC.scope_)
+ {
+ /* Add a destructor for c.var
+ * try { handler } finally { if (!__ctfe) _d_delThrowable(var); }
+ */
+ assert(!c.var.edtor); // ensure we didn't create one in callScopeDtor()
+
+ Loc loc = c.loc;
+ Expression e = new VarExp(loc, c.var);
+ e = new CallExp(loc, new IdentifierExp(loc, Id._d_delThrowable), e);
+
+ Expression ec = new IdentifierExp(loc, Id.ctfe);
+ ec = new NotExp(loc, ec);
+ Statement s = new IfStatement(loc, null, ec, new ExpStatement(loc, e), null, loc);
+ c.handler = new TryFinallyStatement(loc, c.handler, s);
+ }
+
+ }
+ c.handler = c.handler.statementSemantic(sc);
+ if (c.handler && c.handler.isErrorStatement())
+ c.errors = true;
+
+ sc.pop();
+}
+
+Statement semanticNoScope(Statement s, Scope* sc)
+{
+ //printf("Statement::semanticNoScope() %s\n", toChars());
+ if (!s.isCompoundStatement() && !s.isScopeStatement())
+ {
+ s = new CompoundStatement(s.loc, s); // so scopeCode() gets called
+ }
+ s = s.statementSemantic(sc);
+ return s;
+}
+
+// Same as semanticNoScope(), but do create a new scope
+private Statement semanticScope(Statement s, Scope* sc, Statement sbreak, Statement scontinue, Statement tryBody)
+{
+ auto sym = new ScopeDsymbol();
+ sym.parent = sc.scopesym;
+ Scope* scd = sc.push(sym);
+ if (sbreak)
+ scd.sbreak = sbreak;
+ if (scontinue)
+ scd.scontinue = scontinue;
+ if (tryBody)
+ scd.tryBody = tryBody;
+ s = s.semanticNoScope(scd);
+ scd.pop();
+ return s;
+}
+
+
+/****************************************
+ * If `statement` has code that needs to run in a finally clause
+ * at the end of the current scope, return that code in the form of
+ * a Statement.
+ * Params:
+ * statement = the statement
+ * sc = context
+ * sentry = set to code executed upon entry to the scope
+ * sexception = set to code executed upon exit from the scope via exception
+ * sfinally = set to code executed in finally block
+ * Returns:
+ * code to be run in the finally clause
+ */
+Statement scopeCode(Statement statement, Scope* sc, out Statement sentry, out Statement sexception, out Statement sfinally)
+{
+ if (auto es = statement.isExpStatement())
+ {
+ if (es.exp && es.exp.op == TOK.declaration)
+ {
+ auto de = cast(DeclarationExp)es.exp;
+ auto v = de.declaration.isVarDeclaration();
+ if (v && !v.isDataseg())
+ {
+ if (v.needsScopeDtor())
+ {
+ sfinally = new DtorExpStatement(es.loc, v.edtor, v);
+ v.storage_class |= STC.nodtor; // don't add in dtor again
+ }
+ }
+ }
+ return es;
+
+ }
+ else if (auto sgs = statement.isScopeGuardStatement())
+ {
+ Statement s = new PeelStatement(sgs.statement);
+
+ switch (sgs.tok)
+ {
+ case TOK.onScopeExit:
+ sfinally = s;
+ break;
+
+ case TOK.onScopeFailure:
+ sexception = s;
+ break;
+
+ case TOK.onScopeSuccess:
+ {
+ /* Create:
+ * sentry: bool x = false;
+ * sexception: x = true;
+ * sfinally: if (!x) statement;
+ */
+ auto v = copyToTemp(0, "__os", IntegerExp.createBool(false));
+ v.dsymbolSemantic(sc);
+ sentry = new ExpStatement(statement.loc, v);
+
+ Expression e = IntegerExp.createBool(true);
+ e = new AssignExp(Loc.initial, new VarExp(Loc.initial, v), e);
+ sexception = new ExpStatement(Loc.initial, e);
+
+ e = new VarExp(Loc.initial, v);
+ e = new NotExp(Loc.initial, e);
+ sfinally = new IfStatement(Loc.initial, null, e, s, null, Loc.initial);
+
+ break;
+ }
+ default:
+ assert(0);
+ }
+ return null;
+ }
+ else if (auto ls = statement.isLabelStatement())
+ {
+ if (ls.statement)
+ ls.statement = ls.statement.scopeCode(sc, sentry, sexception, sfinally);
+ return ls;
+ }
+
+ return statement;
+}
+
+
+/*******************
+ * Determines additional argument types for makeTupleForeach.
+ */
+static template TupleForeachArgs(bool isStatic, bool isDecl)
+{
+ alias Seq(T...)=T;
+ static if(isStatic) alias T = Seq!(bool);
+ else alias T = Seq!();
+ static if(!isDecl) alias TupleForeachArgs = T;
+ else alias TupleForeachArgs = Seq!(Dsymbols*,T);
+}
+
+/*******************
+ * Determines the return type of makeTupleForeach.
+ */
+static template TupleForeachRet(bool isStatic, bool isDecl)
+{
+ alias Seq(T...)=T;
+ static if(!isDecl) alias TupleForeachRet = Statement;
+ else alias TupleForeachRet = Dsymbols*;
+}
+
+
+/*******************
+ * See StatementSemanticVisitor.makeTupleForeach. This is a simple
+ * wrapper that returns the generated statements/declarations.
+ */
+TupleForeachRet!(isStatic, isDecl) makeTupleForeach(bool isStatic, bool isDecl)(Scope* sc, ForeachStatement fs, TupleForeachArgs!(isStatic, isDecl) args)
+{
+ scope v = new StatementSemanticVisitor(sc);
+ static if(!isDecl)
+ {
+ v.makeTupleForeach!(isStatic, isDecl)(fs, args);
+ return v.result;
+ }
+ else
+ {
+ return v.makeTupleForeach!(isStatic, isDecl)(fs, args);
+ }
+}
+
+/*********************************
+ * Flatten out the scope by presenting `statement`
+ * as an array of statements.
+ * Params:
+ * statement = the statement to flatten
+ * sc = context
+ * Returns:
+ * The array of `Statements`, or `null` if no flattening necessary
+ */
+private Statements* flatten(Statement statement, Scope* sc)
+{
+ static auto errorStatements()
+ {
+ auto a = new Statements();
+ a.push(new ErrorStatement());
+ return a;
+ }
+
+
+ /*compound and expression statements have classes that inherit from them with the same
+ *flattening behavior, so the isXXX methods won't work
+ */
+ switch(statement.stmt)
+ {
+ case STMT.Compound:
+ case STMT.CompoundDeclaration:
+ return (cast(CompoundStatement)statement).statements;
+
+ case STMT.Exp:
+ case STMT.DtorExp:
+ auto es = cast(ExpStatement)statement;
+ /* https://issues.dlang.org/show_bug.cgi?id=14243
+ * expand template mixin in statement scope
+ * to handle variable destructors.
+ */
+ if (!es.exp || es.exp.op != TOK.declaration)
+ return null;
+
+ Dsymbol d = (cast(DeclarationExp)es.exp).declaration;
+ auto tm = d.isTemplateMixin();
+ if (!tm)
+ return null;
+
+ Expression e = es.exp.expressionSemantic(sc);
+ if (e.op == TOK.error || tm.errors)
+ return errorStatements();
+ assert(tm.members);
+
+ Statement s = toStatement(tm);
+ version (none)
+ {
+ OutBuffer buf;
+ buf.doindent = 1;
+ HdrGenState hgs;
+ hgs.hdrgen = true;
+ toCBuffer(s, &buf, &hgs);
+ printf("tm ==> s = %s\n", buf.peekChars());
+ }
+ auto a = new Statements();
+ a.push(s);
+ return a;
+
+ case STMT.Forwarding:
+ /***********************
+ * ForwardingStatements are distributed over the flattened
+ * sequence of statements. This prevents flattening to be
+ * "blocked" by a ForwardingStatement and is necessary, for
+ * example, to support generating scope guards with `static
+ * foreach`:
+ *
+ * static foreach(i; 0 .. 10) scope(exit) writeln(i);
+ * writeln("this is printed first");
+ * // then, it prints 10, 9, 8, 7, ...
+ */
+ auto fs = statement.isForwardingStatement();
+ if (!fs.statement)
+ {
+ return null;
+ }
+ sc = sc.push(fs.sym);
+ auto a = fs.statement.flatten(sc);
+ sc = sc.pop();
+ if (!a)
+ {
+ return a;
+ }
+ auto b = new Statements(a.dim);
+ foreach (i, s; *a)
+ {
+ (*b)[i] = s ? new ForwardingStatement(s.loc, fs.sym, s) : null;
+ }
+ return b;
+
+ case STMT.Conditional:
+ auto cs = statement.isConditionalStatement();
+ Statement s;
+
+ //printf("ConditionalStatement::flatten()\n");
+ if (cs.condition.include(sc))
+ {
+ DebugCondition dc = cs.condition.isDebugCondition();
+ if (dc)
+ {
+ s = new DebugStatement(cs.loc, cs.ifbody);
+ debugThrowWalker(cs.ifbody);
+ }
+ else
+ s = cs.ifbody;
+ }
+ else
+ s = cs.elsebody;
+
+ auto a = new Statements();
+ a.push(s);
+ return a;
+
+ case STMT.StaticForeach:
+ auto sfs = statement.isStaticForeachStatement();
+ sfs.sfe.prepare(sc);
+ if (sfs.sfe.ready())
+ {
+ auto s = makeTupleForeach!(true, false)(sc, sfs.sfe.aggrfe, sfs.sfe.needExpansion);
+ auto result = s.flatten(sc);
+ if (result)
+ {
+ return result;
+ }
+ result = new Statements();
+ result.push(s);
+ return result;
+ }
+ else
+ return errorStatements();
+
+ case STMT.Debug:
+ auto ds = statement.isDebugStatement();
+ Statements* a = ds.statement ? ds.statement.flatten(sc) : null;
+ if (!a)
+ return null;
+
+ foreach (ref s; *a)
+ {
+ s = new DebugStatement(ds.loc, s);
+ }
+ return a;
+
+ case STMT.Label:
+ auto ls = statement.isLabelStatement();
+ if (!ls.statement)
+ return null;
+
+ Statements* a = null;
+ a = ls.statement.flatten(sc);
+ if (!a)
+ return null;
+
+ if (!a.dim)
+ {
+ a.push(new ExpStatement(ls.loc, cast(Expression)null));
+ }
+
+ // reuse 'this' LabelStatement
+ ls.statement = (*a)[0];
+ (*a)[0] = ls;
+ return a;
+
+ case STMT.Compile:
+ auto cs = statement.isCompileStatement();
+
+
+ OutBuffer buf;
+ if (expressionsToString(buf, sc, cs.exps))
+ return errorStatements();
+
+ const errors = global.errors;
+ const len = buf.length;
+ buf.writeByte(0);
+ const str = buf.extractSlice()[0 .. len];
+ scope p = new Parser!ASTCodegen(cs.loc, sc._module, str, false);
+ p.nextToken();
+
+ auto a = new Statements();
+ while (p.token.value != TOK.endOfFile)
+ {
+ Statement s = p.parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
+ if (!s || global.errors != errors)
+ return errorStatements();
+ a.push(s);
+ }
+ return a;
+ default:
+ return null;
+ }
+}
+
+/***********************************************************
+ * Convert TemplateMixin members (== Dsymbols) to Statements.
+ */
+private Statement toStatement(Dsymbol s)
+{
+ extern (C++) final class ToStmt : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ Statement result;
+
+ Statement visitMembers(Loc loc, Dsymbols* a)
+ {
+ if (!a)
+ return null;
+
+ auto statements = new Statements();
+ foreach (s; *a)
+ {
+ statements.push(toStatement(s));
+ }
+ return new CompoundStatement(loc, statements);
+ }
+
+ override void visit(Dsymbol s)
+ {
+ .error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars());
+ result = new ErrorStatement();
+ }
+
+ override void visit(TemplateMixin tm)
+ {
+ auto a = new Statements();
+ foreach (m; *tm.members)
+ {
+ Statement s = toStatement(m);
+ if (s)
+ a.push(s);
+ }
+ result = new CompoundStatement(tm.loc, a);
+ }
+
+ /* An actual declaration symbol will be converted to DeclarationExp
+ * with ExpStatement.
+ */
+ Statement declStmt(Dsymbol s)
+ {
+ auto de = new DeclarationExp(s.loc, s);
+ de.type = Type.tvoid; // avoid repeated semantic
+ return new ExpStatement(s.loc, de);
+ }
+
+ override void visit(VarDeclaration d)
+ {
+ result = declStmt(d);
+ }
+
+ override void visit(AggregateDeclaration d)
+ {
+ result = declStmt(d);
+ }
+
+ override void visit(FuncDeclaration d)
+ {
+ result = declStmt(d);
+ }
+
+ override void visit(EnumDeclaration d)
+ {
+ result = declStmt(d);
+ }
+
+ override void visit(AliasDeclaration d)
+ {
+ result = declStmt(d);
+ }
+
+ override void visit(TemplateDeclaration d)
+ {
+ result = declStmt(d);
+ }
+
+ /* All attributes have been already picked by the semantic analysis of
+ * 'bottom' declarations (function, struct, class, etc).
+ * So we don't have to copy them.
+ */
+ override void visit(StorageClassDeclaration d)
+ {
+ result = visitMembers(d.loc, d.decl);
+ }
+
+ override void visit(DeprecatedDeclaration d)
+ {
+ result = visitMembers(d.loc, d.decl);
+ }
+
+ override void visit(LinkDeclaration d)
+ {
+ result = visitMembers(d.loc, d.decl);
+ }
+
+ override void visit(VisibilityDeclaration d)
+ {
+ result = visitMembers(d.loc, d.decl);
+ }
+
+ override void visit(AlignDeclaration d)
+ {
+ result = visitMembers(d.loc, d.decl);
+ }
+
+ override void visit(UserAttributeDeclaration d)
+ {
+ result = visitMembers(d.loc, d.decl);
+ }
+
+ override void visit(ForwardingAttribDeclaration d)
+ {
+ result = visitMembers(d.loc, d.decl);
+ }
+
+ override void visit(StaticAssert s)
+ {
+ }
+
+ override void visit(Import s)
+ {
+ }
+
+ override void visit(PragmaDeclaration d)
+ {
+ }
+
+ override void visit(ConditionalDeclaration d)
+ {
+ result = visitMembers(d.loc, d.include(null));
+ }
+
+ override void visit(StaticForeachDeclaration d)
+ {
+ assert(d.sfe && !!d.sfe.aggrfe ^ !!d.sfe.rangefe);
+ result = visitMembers(d.loc, d.include(null));
+ }
+
+ override void visit(CompileDeclaration d)
+ {
+ result = visitMembers(d.loc, d.include(null));
+ }
+ }
+
+ if (!s)
+ return null;
+
+ scope ToStmt v = new ToStmt();
+ s.accept(v);
+ return v.result;
+}
+
+/**
+Marks all occurring ThrowStatements as internalThrows.
+This is intended to be called from a DebugStatement as it allows
+to mark all its nodes as nothrow.
+
+Params:
+ s = AST Node to traverse
+*/
+private void debugThrowWalker(Statement s)
+{
+
+ extern(C++) final class DebugWalker : SemanticTimeTransitiveVisitor
+ {
+ alias visit = SemanticTimeTransitiveVisitor.visit;
+ public:
+
+ override void visit(ThrowStatement s)
+ {
+ s.internalThrow = true;
+ }
+
+ override void visit(CallExp s)
+ {
+ s.inDebugStatement = true;
+ }
+ }
+
+ scope walker = new DebugWalker();
+ s.accept(walker);
+}
diff --git a/gcc/d/dmd/staticassert.c b/gcc/d/dmd/staticassert.c
deleted file mode 100644
index c2d0f5b..0000000
--- a/gcc/d/dmd/staticassert.c
+++ /dev/null
@@ -1,55 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/staticassert.c
- */
-
-#include "root/dsystem.h"
-
-#include "mars.h"
-#include "dsymbol.h"
-#include "staticassert.h"
-#include "expression.h"
-#include "id.h"
-#include "scope.h"
-#include "template.h"
-#include "declaration.h"
-
-bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
-
-/********************************* AttribDeclaration ****************************/
-
-StaticAssert::StaticAssert(Loc loc, Expression *exp, Expression *msg)
- : Dsymbol(Id::empty)
-{
- this->loc = loc;
- this->exp = exp;
- this->msg = msg;
-}
-
-Dsymbol *StaticAssert::syntaxCopy(Dsymbol *s)
-{
- assert(!s);
- return new StaticAssert(loc, exp->syntaxCopy(), msg ? msg->syntaxCopy() : NULL);
-}
-
-void StaticAssert::addMember(Scope *, ScopeDsymbol *)
-{
- // we didn't add anything
-}
-
-bool StaticAssert::oneMember(Dsymbol **ps, Identifier *)
-{
- //printf("StaticAssert::oneMember())\n");
- *ps = NULL;
- return true;
-}
-
-const char *StaticAssert::kind() const
-{
- return "static assert";
-}
diff --git a/gcc/d/dmd/staticassert.d b/gcc/d/dmd/staticassert.d
new file mode 100644
index 0000000..984dc42
--- /dev/null
+++ b/gcc/d/dmd/staticassert.d
@@ -0,0 +1,66 @@
+/**
+ * Defines the `Dsymbol` representing a `static assert()`.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/version.html#static-assert, Static Assert)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/staticassert.d, _staticassert.d)
+ * Documentation: https://dlang.org/phobos/dmd_staticassert.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/staticassert.d
+ */
+
+module dmd.staticassert;
+
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.expression;
+import dmd.globals;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.visitor;
+
+/***********************************************************
+ */
+extern (C++) final class StaticAssert : Dsymbol
+{
+ Expression exp;
+ Expression msg;
+
+ extern (D) this(const ref Loc loc, Expression exp, Expression msg)
+ {
+ super(loc, Id.empty);
+ this.exp = exp;
+ this.msg = msg;
+ }
+
+ override StaticAssert syntaxCopy(Dsymbol s)
+ {
+ assert(!s);
+ return new StaticAssert(loc, exp.syntaxCopy(), msg ? msg.syntaxCopy() : null);
+ }
+
+ override void addMember(Scope* sc, ScopeDsymbol sds)
+ {
+ // we didn't add anything
+ }
+
+ override bool oneMember(Dsymbol* ps, Identifier ident)
+ {
+ //printf("StaticAssert::oneMember())\n");
+ *ps = null;
+ return true;
+ }
+
+ override const(char)* kind() const
+ {
+ return "static assert";
+ }
+
+ override void accept(Visitor v)
+ {
+ v.visit(this);
+ }
+}
diff --git a/gcc/d/dmd/staticassert.h b/gcc/d/dmd/staticassert.h
index 6d43cb7..8f88080 100644
--- a/gcc/d/dmd/staticassert.h
+++ b/gcc/d/dmd/staticassert.h
@@ -5,7 +5,7 @@
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/dlang/dmd/blob/master/src/staticassert.h
+ * https://github.com/dlang/dmd/blob/master/src/dmd/staticassert.h
*/
#pragma once
@@ -20,9 +20,7 @@ public:
Expression *exp;
Expression *msg;
- StaticAssert(Loc loc, Expression *exp, Expression *msg);
-
- Dsymbol *syntaxCopy(Dsymbol *s);
+ StaticAssert *syntaxCopy(Dsymbol *s);
void addMember(Scope *sc, ScopeDsymbol *sds);
bool oneMember(Dsymbol **ps, Identifier *ident);
const char *kind() const;
diff --git a/gcc/d/dmd/staticcond.c b/gcc/d/dmd/staticcond.c
deleted file mode 100644
index ef0a35f..0000000
--- a/gcc/d/dmd/staticcond.c
+++ /dev/null
@@ -1,96 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/staticcond.c
- */
-
-#include "mars.h"
-#include "expression.h"
-#include "mtype.h"
-#include "scope.h"
-
-/********************************************
- * Semantically analyze and then evaluate a static condition at compile time.
- * This is special because short circuit operators &&, || and ?: at the top
- * level are not semantically analyzed if the result of the expression is not
- * necessary.
- * Params:
- * exp = original expression, for error messages
- * Returns:
- * true if evaluates to true
- */
-
-bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors)
-{
- if (e->op == TOKandand || e->op == TOKoror)
- {
- LogicalExp *aae = (LogicalExp *)e;
- bool result = evalStaticCondition(sc, exp, aae->e1, errors);
- if (errors)
- return false;
- if (e->op == TOKandand)
- {
- if (!result)
- return false;
- }
- else
- {
- if (result)
- return true;
- }
- result = evalStaticCondition(sc, exp, aae->e2, errors);
- return !errors && result;
- }
-
- if (e->op == TOKquestion)
- {
- CondExp *ce = (CondExp *)e;
- bool result = evalStaticCondition(sc, exp, ce->econd, errors);
- if (errors)
- return false;
- Expression *leg = result ? ce->e1 : ce->e2;
- result = evalStaticCondition(sc, exp, leg, errors);
- return !errors && result;
- }
-
- unsigned nerrors = global.errors;
-
- sc = sc->startCTFE();
- sc->flags |= SCOPEcondition;
-
- e = expressionSemantic(e, sc);
- e = resolveProperties(sc, e);
-
- sc = sc->endCTFE();
- e = e->optimize(WANTvalue);
-
- if (nerrors != global.errors ||
- e->op == TOKerror ||
- e->type->toBasetype() == Type::terror)
- {
- errors = true;
- return false;
- }
-
- if (!e->type->isBoolean())
- {
- exp->error("expression %s of type %s does not have a boolean value", exp->toChars(), e->type->toChars());
- errors = true;
- return false;
- }
-
- e = e->ctfeInterpret();
-
- if (e->isBool(true))
- return true;
- else if (e->isBool(false))
- return false;
-
- e->error("expression %s is not constant", e->toChars());
- errors = true;
- return false;
-}
diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d
new file mode 100644
index 0000000..2f27414
--- /dev/null
+++ b/gcc/d/dmd/staticcond.d
@@ -0,0 +1,424 @@
+/**
+ * Lazily evaluate static conditions for `static if`, `static assert` and template constraints.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/staticcond.d, _staticcond.d)
+ * Documentation: https://dlang.org/phobos/dmd_staticcond.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/staticcond.d
+ */
+
+module dmd.staticcond;
+
+import dmd.arraytypes;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.globals;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.root.array;
+import dmd.root.outbuffer;
+import dmd.tokens;
+
+
+
+/********************************************
+ * Semantically analyze and then evaluate a static condition at compile time.
+ * This is special because short circuit operators &&, || and ?: at the top
+ * level are not semantically analyzed if the result of the expression is not
+ * necessary.
+ * Params:
+ * sc = instantiating scope
+ * original = original expression, for error messages
+ * e = resulting expression
+ * errors = set to `true` if errors occurred
+ * negatives = array to store negative clauses
+ * Returns:
+ * true if evaluates to true
+ */
+bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool errors, Expressions* negatives = null)
+{
+ if (negatives)
+ negatives.setDim(0);
+
+ bool impl(Expression e)
+ {
+ if (e.op == TOK.not)
+ {
+ NotExp ne = cast(NotExp)e;
+ return !impl(ne.e1);
+ }
+
+ if (e.op == TOK.andAnd || e.op == TOK.orOr)
+ {
+ LogicalExp aae = cast(LogicalExp)e;
+ bool result = impl(aae.e1);
+ if (errors)
+ return false;
+ if (e.op == TOK.andAnd)
+ {
+ if (!result)
+ return false;
+ }
+ else
+ {
+ if (result)
+ return true;
+ }
+ result = impl(aae.e2);
+ return !errors && result;
+ }
+
+ if (e.op == TOK.question)
+ {
+ CondExp ce = cast(CondExp)e;
+ bool result = impl(ce.econd);
+ if (errors)
+ return false;
+ Expression leg = result ? ce.e1 : ce.e2;
+ result = impl(leg);
+ return !errors && result;
+ }
+
+ Expression before = e;
+ const uint nerrors = global.errors;
+
+ sc = sc.startCTFE();
+ sc.flags |= SCOPE.condition;
+
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ e = e.toBoolean(sc);
+
+ sc = sc.endCTFE();
+ e = e.optimize(WANTvalue);
+
+ if (nerrors != global.errors ||
+ e.op == TOK.error ||
+ e.type.toBasetype() == Type.terror)
+ {
+ errors = true;
+ return false;
+ }
+
+ e = e.ctfeInterpret();
+
+ if (e.isBool(true))
+ return true;
+ else if (e.isBool(false))
+ {
+ if (negatives)
+ negatives.push(before);
+ return false;
+ }
+
+ e.error("expression `%s` is not constant", e.toChars());
+ errors = true;
+ return false;
+ }
+ return impl(e);
+}
+
+/********************************************
+ * Format a static condition as a tree-like structure, marking failed and
+ * bypassed expressions.
+ * Params:
+ * original = original expression
+ * instantiated = instantiated expression
+ * negatives = array with negative clauses from `instantiated` expression
+ * full = controls whether it shows the full output or only failed parts
+ * itemCount = returns the number of written clauses
+ * Returns:
+ * formatted string or `null` if the expressions were `null`, or if the
+ * instantiated expression is not based on the original one
+ */
+const(char)* visualizeStaticCondition(Expression original, Expression instantiated,
+ const Expression[] negatives, bool full, ref uint itemCount)
+{
+ if (!original || !instantiated || original.loc !is instantiated.loc)
+ return null;
+
+ OutBuffer buf;
+
+ if (full)
+ itemCount = visualizeFull(original, instantiated, negatives, buf);
+ else
+ itemCount = visualizeShort(original, instantiated, negatives, buf);
+
+ return buf.extractChars();
+}
+
+private uint visualizeFull(Expression original, Expression instantiated,
+ const Expression[] negatives, ref OutBuffer buf)
+{
+ // tree-like structure; traverse and format simultaneously
+ uint count;
+ uint indent;
+
+ static void printOr(uint indent, ref OutBuffer buf)
+ {
+ buf.reserve(indent * 4 + 8);
+ foreach (i; 0 .. indent)
+ buf.writestring(" ");
+ buf.writestring(" or:\n");
+ }
+
+ // returns true if satisfied
+ bool impl(Expression orig, Expression e, bool inverted, bool orOperand, bool unreached)
+ {
+ TOK op = orig.op;
+
+ // lower all 'not' to the bottom
+ // !(A && B) -> !A || !B
+ // !(A || B) -> !A && !B
+ if (inverted)
+ {
+ if (op == TOK.andAnd)
+ op = TOK.orOr;
+ else if (op == TOK.orOr)
+ op = TOK.andAnd;
+ }
+
+ if (op == TOK.not)
+ {
+ NotExp no = cast(NotExp)orig;
+ NotExp ne = cast(NotExp)e;
+ assert(ne);
+ return impl(no.e1, ne.e1, !inverted, orOperand, unreached);
+ }
+ else if (op == TOK.andAnd)
+ {
+ BinExp bo = cast(BinExp)orig;
+ BinExp be = cast(BinExp)e;
+ assert(be);
+ const r1 = impl(bo.e1, be.e1, inverted, false, unreached);
+ const r2 = impl(bo.e2, be.e2, inverted, false, unreached || !r1);
+ return r1 && r2;
+ }
+ else if (op == TOK.orOr)
+ {
+ if (!orOperand) // do not indent A || B || C twice
+ indent++;
+ BinExp bo = cast(BinExp)orig;
+ BinExp be = cast(BinExp)e;
+ assert(be);
+ const r1 = impl(bo.e1, be.e1, inverted, true, unreached);
+ printOr(indent, buf);
+ const r2 = impl(bo.e2, be.e2, inverted, true, unreached);
+ if (!orOperand)
+ indent--;
+ return r1 || r2;
+ }
+ else if (op == TOK.question)
+ {
+ CondExp co = cast(CondExp)orig;
+ CondExp ce = cast(CondExp)e;
+ assert(ce);
+ if (!inverted)
+ {
+ // rewrite (A ? B : C) as (A && B || !A && C)
+ if (!orOperand)
+ indent++;
+ const r1 = impl(co.econd, ce.econd, inverted, false, unreached);
+ const r2 = impl(co.e1, ce.e1, inverted, false, unreached || !r1);
+ printOr(indent, buf);
+ const r3 = impl(co.econd, ce.econd, !inverted, false, unreached);
+ const r4 = impl(co.e2, ce.e2, inverted, false, unreached || !r3);
+ if (!orOperand)
+ indent--;
+ return r1 && r2 || r3 && r4;
+ }
+ else
+ {
+ // rewrite !(A ? B : C) as (!A || !B) && (A || !C)
+ if (!orOperand)
+ indent++;
+ const r1 = impl(co.econd, ce.econd, inverted, false, unreached);
+ printOr(indent, buf);
+ const r2 = impl(co.e1, ce.e1, inverted, false, unreached);
+ const r12 = r1 || r2;
+ const r3 = impl(co.econd, ce.econd, !inverted, false, unreached || !r12);
+ printOr(indent, buf);
+ const r4 = impl(co.e2, ce.e2, inverted, false, unreached || !r12);
+ if (!orOperand)
+ indent--;
+ return (r1 || r2) && (r3 || r4);
+ }
+ }
+ else // 'primitive' expression
+ {
+ buf.reserve(indent * 4 + 4);
+ foreach (i; 0 .. indent)
+ buf.writestring(" ");
+
+ // find its value; it may be not computed, if there was a short circuit,
+ // but we handle this case with `unreached` flag
+ bool value = true;
+ if (!unreached)
+ {
+ foreach (fe; negatives)
+ {
+ if (fe is e)
+ {
+ value = false;
+ break;
+ }
+ }
+ }
+ // write the marks first
+ const satisfied = inverted ? !value : value;
+ if (!satisfied && !unreached)
+ buf.writestring(" > ");
+ else if (unreached)
+ buf.writestring(" - ");
+ else
+ buf.writestring(" ");
+ // then the expression itself
+ if (inverted)
+ buf.writeByte('!');
+ buf.writestring(orig.toChars);
+ buf.writenl();
+ count++;
+ return satisfied;
+ }
+ }
+
+ impl(original, instantiated, false, true, false);
+ return count;
+}
+
+private uint visualizeShort(Expression original, Expression instantiated,
+ const Expression[] negatives, ref OutBuffer buf)
+{
+ // simple list; somewhat similar to long version, so no comments
+ // one difference is that it needs to hold items to display in a stack
+
+ static struct Item
+ {
+ Expression orig;
+ bool inverted;
+ }
+
+ Array!Item stack;
+
+ bool impl(Expression orig, Expression e, bool inverted)
+ {
+ TOK op = orig.op;
+
+ if (inverted)
+ {
+ if (op == TOK.andAnd)
+ op = TOK.orOr;
+ else if (op == TOK.orOr)
+ op = TOK.andAnd;
+ }
+
+ if (op == TOK.not)
+ {
+ NotExp no = cast(NotExp)orig;
+ NotExp ne = cast(NotExp)e;
+ assert(ne);
+ return impl(no.e1, ne.e1, !inverted);
+ }
+ else if (op == TOK.andAnd)
+ {
+ BinExp bo = cast(BinExp)orig;
+ BinExp be = cast(BinExp)e;
+ assert(be);
+ bool r = impl(bo.e1, be.e1, inverted);
+ r = r && impl(bo.e2, be.e2, inverted);
+ return r;
+ }
+ else if (op == TOK.orOr)
+ {
+ BinExp bo = cast(BinExp)orig;
+ BinExp be = cast(BinExp)e;
+ assert(be);
+ const lbefore = stack.length;
+ bool r = impl(bo.e1, be.e1, inverted);
+ r = r || impl(bo.e2, be.e2, inverted);
+ if (r)
+ stack.setDim(lbefore); // purge added positive items
+ return r;
+ }
+ else if (op == TOK.question)
+ {
+ CondExp co = cast(CondExp)orig;
+ CondExp ce = cast(CondExp)e;
+ assert(ce);
+ if (!inverted)
+ {
+ const lbefore = stack.length;
+ bool a = impl(co.econd, ce.econd, inverted);
+ a = a && impl(co.e1, ce.e1, inverted);
+ bool b;
+ if (!a)
+ {
+ b = impl(co.econd, ce.econd, !inverted);
+ b = b && impl(co.e2, ce.e2, inverted);
+ }
+ const r = a || b;
+ if (r)
+ stack.setDim(lbefore);
+ return r;
+ }
+ else
+ {
+ bool a;
+ {
+ const lbefore = stack.length;
+ a = impl(co.econd, ce.econd, inverted);
+ a = a || impl(co.e1, ce.e1, inverted);
+ if (a)
+ stack.setDim(lbefore);
+ }
+ bool b;
+ if (a)
+ {
+ const lbefore = stack.length;
+ b = impl(co.econd, ce.econd, !inverted);
+ b = b || impl(co.e2, ce.e2, inverted);
+ if (b)
+ stack.setDim(lbefore);
+ }
+ return a && b;
+ }
+ }
+ else // 'primitive' expression
+ {
+ bool value = true;
+ foreach (fe; negatives)
+ {
+ if (fe is e)
+ {
+ value = false;
+ break;
+ }
+ }
+ const satisfied = inverted ? !value : value;
+ if (!satisfied)
+ stack.push(Item(orig, inverted));
+ return satisfied;
+ }
+ }
+
+ impl(original, instantiated, false);
+
+ foreach (i; 0 .. stack.length)
+ {
+ // write the expression only
+ buf.writestring(" ");
+ if (stack[i].inverted)
+ buf.writeByte('!');
+ buf.writestring(stack[i].orig.toChars);
+ // here with no trailing newline
+ if (i + 1 < stack.length)
+ buf.writenl();
+ }
+ return cast(uint)stack.length;
+}
diff --git a/gcc/d/dmd/stmtstate.d b/gcc/d/dmd/stmtstate.d
new file mode 100644
index 0000000..bb13d7c
--- /dev/null
+++ b/gcc/d/dmd/stmtstate.d
@@ -0,0 +1,142 @@
+/**
+ * Used to help transform statement AST into flow graph.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/stmtstate.d, _stmtstate.d)
+ * Documentation: https://dlang.org/phobos/dmd_stmtstate.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/stmtstate.d
+ */
+
+module dmd.stmtstate;
+
+import dmd.identifier;
+import dmd.statement;
+
+
+/************************************************
+ * Used to traverse the statement AST to transform it into
+ * a flow graph.
+ * Keeps track of things like "where does the `break` go".
+ * Params:
+ * block = type of the flow graph node
+ */
+struct StmtState(block)
+{
+ StmtState* prev;
+ Statement statement;
+
+ Identifier ident;
+ block* breakBlock;
+ block* contBlock;
+ block* switchBlock;
+ block* defaultBlock;
+ block* finallyBlock;
+ block* tryBlock;
+
+ this(StmtState* prev, Statement statement)
+ {
+ this.prev = prev;
+ this.statement = statement;
+ if (prev)
+ this.tryBlock = prev.tryBlock;
+ }
+
+ block* getBreakBlock(Identifier ident)
+ {
+ StmtState* bc;
+ if (ident)
+ {
+ Statement related = null;
+ block* ret = null;
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ // The label for a breakBlock may actually be some levels up (e.g.
+ // on a try/finally wrapping a loop). We'll see if this breakBlock
+ // is the one to return once we reach that outer statement (which
+ // in many cases will be this same statement).
+ if (bc.breakBlock)
+ {
+ related = bc.statement.getRelatedLabeled();
+ ret = bc.breakBlock;
+ }
+ if (bc.statement == related && bc.prev.ident == ident)
+ return ret;
+ }
+ }
+ else
+ {
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ if (bc.breakBlock)
+ return bc.breakBlock;
+ }
+ }
+ return null;
+ }
+
+ block* getContBlock(Identifier ident)
+ {
+ StmtState* bc;
+ if (ident)
+ {
+ block* ret = null;
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ // The label for a contBlock may actually be some levels up (e.g.
+ // on a try/finally wrapping a loop). We'll see if this contBlock
+ // is the one to return once we reach that outer statement (which
+ // in many cases will be this same statement).
+ if (bc.contBlock)
+ {
+ ret = bc.contBlock;
+ }
+ if (bc.prev && bc.prev.ident == ident)
+ return ret;
+ }
+ }
+ else
+ {
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ if (bc.contBlock)
+ return bc.contBlock;
+ }
+ }
+ return null;
+ }
+
+ block* getSwitchBlock()
+ {
+ StmtState* bc;
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ if (bc.switchBlock)
+ return bc.switchBlock;
+ }
+ return null;
+ }
+
+ block* getDefaultBlock()
+ {
+ StmtState* bc;
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ if (bc.defaultBlock)
+ return bc.defaultBlock;
+ }
+ return null;
+ }
+
+ block* getFinallyBlock()
+ {
+ StmtState* bc;
+ for (bc = &this; bc; bc = bc.prev)
+ {
+ if (bc.finallyBlock)
+ return bc.finallyBlock;
+ }
+ return null;
+ }
+}
diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d
new file mode 100644
index 0000000..d5b3de2
--- /dev/null
+++ b/gcc/d/dmd/target.d
@@ -0,0 +1,438 @@
+/**
+ * Handles target-specific parameters
+ *
+ * In order to allow for cross compilation, when the compiler produces a binary
+ * for a different platform than it is running on, target information needs
+ * to be abstracted. This is done in this module, primarily through `Target`.
+ *
+ * Note:
+ * While DMD itself does not support cross-compilation, GDC and LDC do.
+ * Hence, this module is (sometimes heavily) modified by them,
+ * and contributors should review how their changes affect them.
+ *
+ * See_Also:
+ * - $(LINK2 https://wiki.osdev.org/Target_Triplet, Target Triplets)
+ * - $(LINK2 https://github.com/ldc-developers/ldc, LDC repository)
+ * - $(LINK2 https://github.com/D-Programming-GDC/gcc, GDC repository)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/target.d, _target.d)
+ * Documentation: https://dlang.org/phobos/dmd_target.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/target.d
+ */
+
+module dmd.target;
+
+import dmd.globals : Param;
+
+enum CPU
+{
+ x87,
+ mmx,
+ sse,
+ sse2,
+ sse3,
+ ssse3,
+ sse4_1,
+ sse4_2,
+ avx, // AVX1 instruction set
+ avx2, // AVX2 instruction set
+ avx512, // AVX-512 instruction set
+
+ // Special values that don't survive past the command line processing
+ baseline, // (default) the minimum capability CPU
+ native // the machine the compiler is being run on
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Describes a back-end target. At present it is incomplete, but in the future
+ * it should grow to contain most or all target machine and target O/S specific
+ * information.
+ *
+ * In many cases, calls to sizeof() can't be used directly for getting data type
+ * sizes since cross compiling is supported and would end up using the host
+ * sizes rather than the target sizes.
+ */
+extern (C++) struct Target
+{
+ import dmd.dscope : Scope;
+ import dmd.expression : Expression;
+ import dmd.func : FuncDeclaration;
+ import dmd.globals : LINK, Loc, d_int64;
+ import dmd.astenums : TY;
+ import dmd.mtype : Type, TypeFunction, TypeTuple;
+ import dmd.root.ctfloat : real_t;
+ import dmd.statement : Statement;
+
+ /// Bit decoding of the Target.OS
+ enum OS : ubyte
+ {
+ /* These are mutually exclusive; one and only one is set.
+ * Match spelling and casing of corresponding version identifiers
+ */
+ Freestanding = 0,
+ linux = 1,
+ Windows = 2,
+ OSX = 4,
+ OpenBSD = 8,
+ FreeBSD = 0x10,
+ Solaris = 0x20,
+ DragonFlyBSD = 0x40,
+
+ // Combination masks
+ all = linux | Windows | OSX | OpenBSD | FreeBSD | Solaris | DragonFlyBSD,
+ Posix = linux | OSX | OpenBSD | FreeBSD | Solaris | DragonFlyBSD,
+ }
+
+ OS os;
+ ubyte osMajor;
+
+ // D ABI
+ ubyte ptrsize; /// size of a pointer in bytes
+ ubyte realsize; /// size a real consumes in memory
+ ubyte realpad; /// padding added to the CPU real size to bring it up to realsize
+ ubyte realalignsize; /// alignment for reals
+ ubyte classinfosize; /// size of `ClassInfo`
+ ulong maxStaticDataSize; /// maximum size of static data
+
+ /// C ABI
+ TargetC c;
+
+ /// C++ ABI
+ TargetCPP cpp;
+
+ /// Objective-C ABI
+ TargetObjC objc;
+
+ /// Architecture name
+ const(char)[] architectureName;
+ CPU cpu = CPU.baseline; // CPU instruction set to target
+ bool is64bit; // generate 64 bit code for x86_64; true by default for 64 bit dmd
+ bool isLP64; // pointers are 64 bits
+
+ // Environmental
+ const(char)[] obj_ext; /// extension for object files
+ const(char)[] lib_ext; /// extension for static library files
+ const(char)[] dll_ext; /// extension for dynamic library files
+ bool run_noext; /// allow -run sources without extensions
+ bool mscoff = false; // for Win32: write MsCoff object files instead of OMF
+ /**
+ * Values representing all properties for floating point types
+ */
+ extern (C++) struct FPTypeProperties(T)
+ {
+ real_t max; /// largest representable value that's not infinity
+ real_t min_normal; /// smallest representable normalized value that's not 0
+ real_t nan; /// NaN value
+ real_t infinity; /// infinity value
+ real_t epsilon; /// smallest increment to the value 1
+
+ d_int64 dig; /// number of decimal digits of precision
+ d_int64 mant_dig; /// number of bits in mantissa
+ d_int64 max_exp; /// maximum int value such that 2$(SUPERSCRIPT `max_exp-1`) is representable
+ d_int64 min_exp; /// minimum int value such that 2$(SUPERSCRIPT `min_exp-1`) is representable as a normalized value
+ d_int64 max_10_exp; /// maximum int value such that 10$(SUPERSCRIPT `max_10_exp` is representable)
+ d_int64 min_10_exp; /// minimum int value such that 10$(SUPERSCRIPT `min_10_exp`) is representable as a normalized value
+ }
+
+ FPTypeProperties!float FloatProperties; ///
+ FPTypeProperties!double DoubleProperties; ///
+ FPTypeProperties!real_t RealProperties; ///
+
+ private Type tvalist; // cached lazy result of va_listType()
+
+ private const(Param)* params; // cached reference to global.params
+
+ /**
+ * Initialize the Target
+ */
+ extern (C++) void _init(ref const Param params);
+
+
+ /**
+ * Deinitializes the global state of the compiler.
+ *
+ * This can be used to restore the state set by `_init` to its original
+ * state.
+ */
+ void deinitialize()
+ {
+ this = this.init;
+ }
+
+ /**
+ * Requested target memory alignment size of the given type.
+ * Params:
+ * type = type to inspect
+ * Returns:
+ * alignment in bytes
+ */
+ extern (C++) uint alignsize(Type type);
+
+ /**
+ * Requested target field alignment size of the given type.
+ * Params:
+ * type = type to inspect
+ * Returns:
+ * alignment in bytes
+ */
+ extern (C++) uint fieldalign(Type type);
+
+ /**
+ * Type for the `va_list` type for the target; e.g., required for `_argptr`
+ * declarations.
+ * NOTE: For Posix/x86_64 this returns the type which will really
+ * be used for passing an argument of type va_list.
+ * Returns:
+ * `Type` that represents `va_list`.
+ */
+ extern (C++) Type va_listType(const ref Loc loc, Scope* sc);
+
+ /**
+ * Checks whether the target supports a vector type.
+ * Params:
+ * sz = vector type size in bytes
+ * type = vector element type
+ * Returns:
+ * 0 vector type is supported,
+ * 1 vector type is not supported on the target at all
+ * 2 vector element type is not supported
+ * 3 vector size is not supported
+ */
+ extern (C++) int isVectorTypeSupported(int sz, Type type);
+
+ /**
+ * Checks whether the target supports the given operation for vectors.
+ * Params:
+ * type = target type of operation
+ * op = the unary or binary op being done on the `type`
+ * t2 = type of second operand if `op` is a binary operation
+ * Returns:
+ * true if the operation is supported or type is not a vector
+ */
+ extern (C++) bool isVectorOpSupported(Type type, uint op, Type t2 = null);
+
+ /**
+ * Default system linkage for the target.
+ * Returns:
+ * `LINK` to use for `extern(System)`
+ */
+ extern (C++) LINK systemLinkage();
+
+ /**
+ * Describes how an argument type is passed to a function on target.
+ * Params:
+ * t = type to break down
+ * Returns:
+ * tuple of types if type is passed in one or more registers
+ * empty tuple if type is always passed on the stack
+ * null if the type is a `void` or argtypes aren't supported by the target
+ */
+ extern (C++) TypeTuple toArgTypes(Type t);
+
+ /**
+ * Determine return style of function - whether in registers or
+ * through a hidden pointer to the caller's stack.
+ * Params:
+ * tf = function type to check
+ * needsThis = true if the function type is for a non-static member function
+ * Returns:
+ * true if return value from function is on the stack
+ */
+ extern (C++) bool isReturnOnStack(TypeFunction tf, bool needsThis);
+
+ /***
+ * Determine the size a value of type `t` will be when it
+ * is passed on the function parameter stack.
+ * Params:
+ * loc = location to use for error messages
+ * t = type of parameter
+ * Returns:
+ * size used on parameter stack
+ */
+ extern (C++) ulong parameterSize(const ref Loc loc, Type t);
+
+ /**
+ * Decides whether an `in` parameter of the specified POD type is to be
+ * passed by reference or by value. To be used with `-preview=in` only!
+ * Params:
+ * t = type of the `in` parameter, must be a POD
+ * Returns:
+ * `true` if the `in` parameter is to be passed by reference
+ */
+ extern(C++) bool preferPassByRef(Type t);
+
+ /**
+ * Get targetInfo by key
+ * Params:
+ * name = name of targetInfo to get
+ * loc = location to use for error messages
+ * Returns:
+ * Expression for the requested targetInfo
+ */
+ extern (C++) Expression getTargetInfo(const(char)* name, const ref Loc loc);
+
+ /**
+ * Params:
+ * tf = type of function being called
+ * Returns: `true` if the callee invokes destructors for arguments.
+ */
+ extern (C++) bool isCalleeDestroyingArgs(TypeFunction tf);
+
+ /**
+ * Returns true if the implementation for object monitors is always defined
+ * in the D runtime library (rt/monitor_.d).
+ * Params:
+ * fd = function with `synchronized` storage class.
+ * fbody = entire function body of `fd`
+ * Returns:
+ * `false` if the target backend handles synchronizing monitors.
+ */
+ extern (C++) bool libraryObjectMonitors(FuncDeclaration fd, Statement fbody);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Functions and variables specific to interfacing with extern(C) ABI.
+ */
+struct TargetC
+{
+ enum Runtime : ubyte
+ {
+ Unspecified,
+ Bionic,
+ DigitalMars,
+ Glibc,
+ Microsoft,
+ Musl,
+ Newlib,
+ UClibc,
+ WASI,
+ }
+
+ enum BitFieldStyle : ubyte
+ {
+ Unspecified,
+ Dm_Ms, /// Digital Mars and Microsoft C compilers
+ /// https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields?view=msvc-160
+ /// https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160
+ Gcc_Clang, /// gcc and clang
+ }
+
+ ubyte longsize; /// size of a C `long` or `unsigned long` type
+ ubyte long_doublesize; /// size of a C `long double`
+ ubyte wchar_tsize; /// size of a C `wchar_t` type
+ Runtime runtime; /// vendor of the C runtime to link against
+ BitFieldStyle bitFieldStyle; /// different C compilers do it differently
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Functions and variables specific to interface with extern(C++) ABI.
+ */
+struct TargetCPP
+{
+ import dmd.dsymbol : Dsymbol;
+ import dmd.dclass : ClassDeclaration;
+ import dmd.func : FuncDeclaration;
+ import dmd.mtype : Parameter, Type;
+
+ enum Runtime : ubyte
+ {
+ Unspecified,
+ Clang,
+ DigitalMars,
+ Gcc,
+ Microsoft,
+ Sun
+ }
+ bool reverseOverloads; /// set if overloaded functions are grouped and in reverse order (such as in dmc and cl)
+ bool exceptions; /// set if catching C++ exceptions is supported
+ bool twoDtorInVtable; /// target C++ ABI puts deleting and non-deleting destructor into vtable
+ bool wrapDtorInExternD; /// set if C++ dtors require a D wrapper to be callable from runtime
+ Runtime runtime; /// vendor of the C++ runtime to link against
+
+ /**
+ * Mangle the given symbol for C++ ABI.
+ * Params:
+ * s = declaration with C++ linkage
+ * Returns:
+ * string mangling of symbol
+ */
+ extern (C++) const(char)* toMangle(Dsymbol s);
+
+ /**
+ * Get RTTI mangling of the given class declaration for C++ ABI.
+ * Params:
+ * cd = class with C++ linkage
+ * Returns:
+ * string mangling of C++ typeinfo
+ */
+ extern (C++) const(char)* typeInfoMangle(ClassDeclaration cd);
+
+ /**
+ * Get mangle name of a this-adjusting thunk to the given function
+ * declaration for C++ ABI.
+ * Params:
+ * fd = function with C++ linkage
+ * offset = call offset to the vptr
+ * Returns:
+ * string mangling of C++ thunk, or null if unhandled
+ */
+ extern (C++) const(char)* thunkMangle(FuncDeclaration fd, int offset);
+
+ /**
+ * Gets vendor-specific type mangling for C++ ABI.
+ * Params:
+ * t = type to inspect
+ * Returns:
+ * string if type is mangled specially on target
+ * null if unhandled
+ */
+ extern (C++) const(char)* typeMangle(Type t);
+
+ /**
+ * Get the type that will really be used for passing the given argument
+ * to an `extern(C++)` function.
+ * Params:
+ * p = parameter to be passed.
+ * Returns:
+ * `Type` to use for parameter `p`.
+ */
+ extern (C++) Type parameterType(Parameter p);
+
+ /**
+ * Checks whether type is a vendor-specific fundamental type.
+ * Params:
+ * t = type to inspect
+ * isFundamental = where to store result
+ * Returns:
+ * true if isFundamental was set by function
+ */
+ extern (C++) bool fundamentalType(const Type t, ref bool isFundamental);
+
+ /**
+ * Get the starting offset position for fields of an `extern(C++)` class
+ * that is derived from the given base class.
+ * Params:
+ * baseClass = base class with C++ linkage
+ * Returns:
+ * starting offset to lay out derived class fields
+ */
+ extern (C++) uint derivedClassOffset(ClassDeclaration baseClass);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/**
+ * Functions and variables specific to interface with extern(Objective-C) ABI.
+ */
+struct TargetObjC
+{
+ bool supported; /// set if compiler can interface with Objective-C
+}
+
+////////////////////////////////////////////////////////////////////////////////
+extern (C++) __gshared Target target;
diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h
index f8f977c..83281a6 100644
--- a/gcc/d/dmd/target.h
+++ b/gcc/d/dmd/target.h
@@ -23,22 +23,75 @@ class FuncDeclaration;
class Parameter;
class Statement;
class Type;
-class TypeFunction;
class TypeTuple;
-struct OutBuffer;
+class TypeFunction;
+
+enum class CPU
+{
+ x87,
+ mmx,
+ sse,
+ sse2,
+ sse3,
+ ssse3,
+ sse4_1,
+ sse4_2,
+ avx, // AVX1 instruction set
+ avx2, // AVX2 instruction set
+ avx512, // AVX-512 instruction set
+
+ // Special values that don't survive past the command line processing
+ baseline, // (default) the minimum capability CPU
+ native // the machine the compiler is being run on
+};
struct TargetC
{
- unsigned longsize; // size of a C 'long' or 'unsigned long' type
- unsigned long_doublesize; // size of a C 'long double'
- Type *twchar_t; // C 'wchar_t' type
+ enum class Runtime : unsigned char
+ {
+ Unspecified,
+ Bionic,
+ DigitalMars,
+ Glibc,
+ Microsoft,
+ Musl,
+ Newlib,
+ UClibc,
+ WASI,
+ };
+
+ enum class BitFieldStyle : unsigned char
+ {
+ Unspecified,
+ Dm_Ms, // Digital Mars and Microsoft C compilers
+ // https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields?view=msvc-160
+ // https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160
+ Gcc_Clang, // gcc and clang
+ };
+
+ uint8_t longsize; // size of a C 'long' or 'unsigned long' type
+ uint8_t long_doublesize; // size of a C 'long double'
+ uint8_t wchar_tsize; // size of a C 'wchar_t' type
+ Runtime runtime;
+ BitFieldStyle bitFieldStyle; // different C compilers do it differently
};
struct TargetCPP
{
+ enum class Runtime : unsigned char
+ {
+ Unspecified,
+ Clang,
+ DigitalMars,
+ Gcc,
+ Microsoft,
+ Sun
+ };
bool reverseOverloads; // with dmc and cl, overloaded functions are grouped and in reverse order
bool exceptions; // set if catching C++ exceptions is supported
bool twoDtorInVtable; // target C++ ABI puts deleting and non-deleting destructor into vtable
+ bool wrapDtorInExternD; // set if C++ dtors require a D wrapper to be callable from runtime
+ Runtime runtime;
const char *toMangle(Dsymbol *s);
const char *typeInfoMangle(ClassDeclaration *cd);
@@ -56,13 +109,35 @@ struct TargetObjC
struct Target
{
+ typedef unsigned char OS;
+ enum
+ {
+ /* These are mutually exclusive; one and only one is set.
+ * Match spelling and casing of corresponding version identifiers
+ */
+ OS_Freestanding = 0,
+ OS_linux = 1,
+ OS_Windows = 2,
+ OS_OSX = 4,
+ OS_OpenBSD = 8,
+ OS_FreeBSD = 0x10,
+ OS_Solaris = 0x20,
+ OS_DragonFlyBSD = 0x40,
+
+ // Combination masks
+ all = OS_linux | OS_Windows | OS_OSX | OS_OpenBSD | OS_FreeBSD | OS_Solaris | OS_DragonFlyBSD,
+ Posix = OS_linux | OS_OSX | OS_OpenBSD | OS_FreeBSD | OS_Solaris | OS_DragonFlyBSD,
+ };
+
+ OS os;
+ uint8_t osMajor;
// D ABI
- unsigned ptrsize;
- unsigned realsize; // size a real consumes in memory
- unsigned realpad; // 'padding' added to the CPU real size to bring it up to realsize
- unsigned realalignsize; // alignment for reals
- unsigned classinfosize; // size of 'ClassInfo'
- unsigned long long maxStaticDataSize; // maximum size of static data
+ uint8_t ptrsize;
+ uint8_t realsize; // size a real consumes in memory
+ uint8_t realpad; // 'padding' added to the CPU real size to bring it up to realsize
+ uint8_t realalignsize; // alignment for reals
+ uint8_t classinfosize; // size of 'ClassInfo'
+ uint64_t maxStaticDataSize; // maximum size of static data
// C ABI
TargetC c;
@@ -73,13 +148,24 @@ struct Target
// Objective-C ABI
TargetObjC objc;
+ DString architectureName; // name of the platform architecture (e.g. X86_64)
+ CPU cpu; // CPU instruction set to target
+ bool is64bit; // generate 64 bit code for x86_64; true by default for 64 bit dmd
+ bool isLP64; // pointers are 64 bits
+
+ // Environmental
+ DString obj_ext; /// extension for object files
+ DString lib_ext; /// extension for static library files
+ DString dll_ext; /// extension for dynamic library files
+ bool run_noext; /// allow -run sources without extensions
+ bool mscoff; /// for Win32: write COFF object files instead of OMF
+
template <typename T>
struct FPTypeProperties
{
real_t max;
real_t min_normal;
real_t nan;
- real_t snan;
real_t infinity;
real_t epsilon;
@@ -97,21 +183,27 @@ struct Target
private:
Type *tvalist;
+ const Param *params;
public:
void _init(const Param& params);
// Type sizes and support.
+ void setTriple(const char* _triple);
unsigned alignsize(Type *type);
unsigned fieldalign(Type *type);
Type *va_listType(const Loc &loc, Scope *sc); // get type of va_list
int isVectorTypeSupported(int sz, Type *type);
- bool isVectorOpSupported(Type *type, TOK op, Type *t2 = NULL);
+ bool isVectorOpSupported(Type *type, unsigned op, Type *t2 = NULL);
// ABI and backend.
LINK systemLinkage();
TypeTuple *toArgTypes(Type *t);
bool isReturnOnStack(TypeFunction *tf, bool needsThis);
+ d_uns64 parameterSize(const Loc& loc, Type *t);
+ bool preferPassByRef(Type *t);
Expression *getTargetInfo(const char* name, const Loc& loc);
+ bool isCalleeDestroyingArgs(TypeFunction* tf);
bool libraryObjectMonitors(FuncDeclaration *fd, Statement *fbody);
+ void addPredefinedGlobalIdentifiers() const;
};
extern Target target;
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index 086ec72..08ce9ac 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -10,12 +10,9 @@
#pragma once
-#include "root/root.h"
#include "arraytypes.h"
#include "dsymbol.h"
-
-struct OutBuffer;
class Identifier;
class TemplateInstance;
class TemplateParameter;
@@ -26,18 +23,10 @@ class TemplateAliasParameter;
class TemplateTupleParameter;
class Type;
class TypeQualified;
-class TypeTypeof;
struct Scope;
class Expression;
-class AliasDeclaration;
class FuncDeclaration;
class Parameter;
-enum MATCH;
-enum PASS;
-
-bool tpsemantic(TemplateParameter *tp, Scope *sc, TemplateParameters *parameters);
-RootObject *aliasParameterSemantic(Loc loc, Scope *sc, RootObject *o, TemplateParameters *parameters);
-void templateInstanceSemantic(TemplateInstance *tempinst, Scope *sc, Expressions *fargs);
class Tuple : public RootObject
{
@@ -45,9 +34,9 @@ public:
Objects objects;
// kludge for template.isType()
- int dyncast() const { return DYNCAST_TUPLE; }
+ DYNCAST dyncast() const { return DYNCAST_TUPLE; }
- const char *toChars() { return objects.toChars(); }
+ const char *toChars() const { return objects.toChars(); }
};
struct TemplatePrevious
@@ -78,38 +67,29 @@ public:
bool ismixin; // template declaration is only to be used as a mixin
bool isstatic; // this is static template declaration
bool isTrivialAliasSeq; // matches `template AliasSeq(T...) { alias AliasSeq = T; }
- bool isTrivialAlias; // matches `template Alias(T) { alias Alias = T; }
- Prot protection;
+ bool isTrivialAlias; // matches pattern `template Alias(T) { alias Alias = qualifiers(T); }`
+ bool deprecated_; // this template declaration is deprecated
+ Visibility visibility;
int inuse; // for recursive expansion detection
TemplatePrevious *previous; // threaded list of previous instantiation attempts on stack
- TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters,
- Expression *constraint, Dsymbols *decldefs, bool ismixin = false, bool literal = false);
- Dsymbol *syntaxCopy(Dsymbol *);
+ TemplateDeclaration *syntaxCopy(Dsymbol *);
bool overloadInsert(Dsymbol *s);
bool hasStaticCtorOrDtor();
const char *kind() const;
- const char *toChars();
-
- Prot prot();
+ const char *toChars() const;
- bool evaluateConstraint(TemplateInstance *ti, Scope *sc, Scope *paramscope, Objects *dedtypes, FuncDeclaration *fd);
+ Visibility visible();
- MATCH matchWithInstance(Scope *sc, TemplateInstance *ti, Objects *atypes, Expressions *fargs, int flag);
MATCH leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs);
-
- MATCH deduceFunctionTemplateMatch(TemplateInstance *ti, Scope *sc, FuncDeclaration *&fd, Type *tthis, Expressions *fargs);
RootObject *declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o);
- FuncDeclaration *doHeaderInstantiation(TemplateInstance *ti, Scope *sc, FuncDeclaration *fd, Type *tthis, Expressions *fargs);
- TemplateInstance *findExistingInstance(TemplateInstance *tithis, Expressions *fargs);
- TemplateInstance *addInstance(TemplateInstance *ti);
- void removeInstance(TemplateInstance *handle);
TemplateDeclaration *isTemplateDeclaration() { return this; }
TemplateTupleParameter *isVariadic();
- bool isOverloadable();
+ bool isDeprecated() const;
+ bool isOverloadable() const;
void accept(Visitor *v) { v->visit(this); }
};
@@ -141,8 +121,6 @@ public:
*/
bool dependent;
- TemplateParameter(Loc loc, Identifier *ident);
-
virtual TemplateTypeParameter *isTemplateTypeParameter();
virtual TemplateValueParameter *isTemplateValueParameter();
virtual TemplateAliasParameter *isTemplateAliasParameter();
@@ -156,14 +134,9 @@ public:
virtual RootObject *defaultArg(Loc instLoc, Scope *sc) = 0;
virtual bool hasDefaultArg() = 0;
- /* Match actual argument against parameter.
- */
- virtual MATCH matchArg(Loc instLoc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
- virtual MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 0;
-
/* Create dummy argument based on parameter.
*/
- virtual void *dummyArg() = 0;
+ virtual RootObject *dummyArg() = 0;
void accept(Visitor *v) { v->visit(this); }
};
@@ -172,24 +145,18 @@ public:
*/
class TemplateTypeParameter : public TemplateParameter
{
- using TemplateParameter::matchArg;
public:
Type *specType; // type parameter: if !=NULL, this is the type specialization
Type *defaultType;
- static Type *tdummy;
-
- TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType);
-
TemplateTypeParameter *isTemplateTypeParameter();
- TemplateParameter *syntaxCopy();
+ TemplateTypeParameter *syntaxCopy();
bool declareParameter(Scope *sc);
void print(RootObject *oarg, RootObject *oded);
RootObject *specialization();
RootObject *defaultArg(Loc instLoc, Scope *sc);
bool hasDefaultArg();
- MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
- void *dummyArg();
+ RootObject *dummyArg();
void accept(Visitor *v) { v->visit(this); }
};
@@ -199,10 +166,8 @@ public:
class TemplateThisParameter : public TemplateTypeParameter
{
public:
- TemplateThisParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType);
-
TemplateThisParameter *isTemplateThisParameter();
- TemplateParameter *syntaxCopy();
+ TemplateThisParameter *syntaxCopy();
void accept(Visitor *v) { v->visit(this); }
};
@@ -211,25 +176,19 @@ public:
*/
class TemplateValueParameter : public TemplateParameter
{
- using TemplateParameter::matchArg;
public:
Type *valType;
Expression *specValue;
Expression *defaultValue;
- static AA *edummies;
-
- TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue);
-
TemplateValueParameter *isTemplateValueParameter();
- TemplateParameter *syntaxCopy();
+ TemplateValueParameter *syntaxCopy();
bool declareParameter(Scope *sc);
void print(RootObject *oarg, RootObject *oded);
RootObject *specialization();
RootObject *defaultArg(Loc instLoc, Scope *sc);
bool hasDefaultArg();
- MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
- void *dummyArg();
+ RootObject *dummyArg();
void accept(Visitor *v) { v->visit(this); }
};
@@ -238,25 +197,19 @@ public:
*/
class TemplateAliasParameter : public TemplateParameter
{
- using TemplateParameter::matchArg;
public:
Type *specType;
RootObject *specAlias;
RootObject *defaultAlias;
- static Dsymbol *sdummy;
-
- TemplateAliasParameter(Loc loc, Identifier *ident, Type *specType, RootObject *specAlias, RootObject *defaultAlias);
-
TemplateAliasParameter *isTemplateAliasParameter();
- TemplateParameter *syntaxCopy();
+ TemplateAliasParameter *syntaxCopy();
bool declareParameter(Scope *sc);
void print(RootObject *oarg, RootObject *oded);
RootObject *specialization();
RootObject *defaultArg(Loc instLoc, Scope *sc);
bool hasDefaultArg();
- MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
- void *dummyArg();
+ RootObject *dummyArg();
void accept(Visitor *v) { v->visit(this); }
};
@@ -266,18 +219,14 @@ public:
class TemplateTupleParameter : public TemplateParameter
{
public:
- TemplateTupleParameter(Loc loc, Identifier *ident);
-
TemplateTupleParameter *isTemplateTupleParameter();
- TemplateParameter *syntaxCopy();
+ TemplateTupleParameter *syntaxCopy();
bool declareParameter(Scope *sc);
void print(RootObject *oarg, RootObject *oded);
RootObject *specialization();
RootObject *defaultArg(Loc instLoc, Scope *sc);
bool hasDefaultArg();
- MATCH matchArg(Loc loc, Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
- MATCH matchArg(Scope *sc, RootObject *oarg, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam);
- void *dummyArg();
+ RootObject *dummyArg();
void accept(Visitor *v) { v->visit(this); }
};
@@ -300,16 +249,14 @@ public:
// [int, char, 100]
Objects tdtypes;
+ // Modules imported by this template instance
+ Modules importedModules;
+
Dsymbol *tempdecl; // referenced by foo.bar.abc
Dsymbol *enclosing; // if referencing local symbols, this is the context
Dsymbol *aliasdecl; // !=NULL if instance is an alias for its sole member
TemplateInstance *inst; // refer to existing instance
ScopeDsymbol *argsym; // argument symbol table
- int inuse; // for recursive expansion detection
- int nest; // for recursive pretty printing detection
- bool semantictiargsdone; // has semanticTiargs() been done?
- bool havetempdecl; // if used second constructor
- bool gagged; // if the instantiation is done with error gagging
hash_t hash; // cached result of toHash()
Expressions *fargs; // for function template, these are the function arguments
@@ -323,37 +270,22 @@ public:
TemplateInstance *tnext; // non-first instantiated instances
Module *minst; // the top module that instantiated this instance
- TemplateInstance(Loc loc, Identifier *temp_id);
- TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs);
- static Objects *arraySyntaxCopy(Objects *objs);
- Dsymbol *syntaxCopy(Dsymbol *);
+private:
+ unsigned short _nest; // for recursive pretty printing detection, 3 MSBs reserved for flags
+public:
+ unsigned char inuse; // for recursive expansion detection
+
+ TemplateInstance *syntaxCopy(Dsymbol *);
Dsymbol *toAlias(); // resolve real symbol
const char *kind() const;
bool oneMember(Dsymbol **ps, Identifier *ident);
- const char *toChars();
+ const char *toChars() const;
const char* toPrettyCharsHelper();
- void printInstantiationTrace();
Identifier *getIdent();
- int compare(RootObject *o);
hash_t toHash();
bool needsCodegen();
- // Internal
- bool findTempDecl(Scope *sc, WithScopeSymbol **pwithsym);
- bool updateTempDecl(Scope *sc, Dsymbol *s);
- static bool semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags);
- bool semanticTiargs(Scope *sc);
- bool findBestMatch(Scope *sc, Expressions *fargs);
- bool needsTypeInference(Scope *sc, int flag = 0);
- bool hasNestedArgs(Objects *tiargs, bool isstatic);
- Dsymbols *appendToModuleMember();
- void declareParameters(Scope *sc);
- Identifier *genIdent(Objects *args);
- void expandMembers(Scope *sc);
- void tryExpandMembers(Scope *sc);
- void trySemantic3(Scope *sc2);
-
TemplateInstance *isTemplateInstance() { return this; }
void accept(Visitor *v) { v->visit(this); }
};
@@ -363,16 +295,12 @@ class TemplateMixin : public TemplateInstance
public:
TypeQualified *tqual;
- TemplateMixin(Loc loc, Identifier *ident, TypeQualified *tqual, Objects *tiargs);
- Dsymbol *syntaxCopy(Dsymbol *s);
+ TemplateMixin *syntaxCopy(Dsymbol *s);
const char *kind() const;
bool oneMember(Dsymbol **ps, Identifier *ident);
- int apply(Dsymbol_apply_ft_t fp, void *param);
bool hasPointers();
- void setFieldOffset(AggregateDeclaration *ad, unsigned *poffset, bool isunion);
- const char *toChars();
-
- bool findTempDecl(Scope *sc);
+ void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
+ const char *toChars() const;
TemplateMixin *isTemplateMixin() { return this; }
void accept(Visitor *v) { v->visit(this); }
@@ -383,9 +311,5 @@ Dsymbol *isDsymbol(RootObject *o);
Type *isType(RootObject *o);
Tuple *isTuple(RootObject *o);
Parameter *isParameter(RootObject *o);
-bool arrayObjectIsError(Objects *args);
-bool isError(RootObject *o);
-Type *getType(RootObject *o);
-Dsymbol *getDsymbol(RootObject *o);
-
-RootObject *objectSyntaxCopy(RootObject *o);
+TemplateParameter *isTemplateParameter(RootObject *o);
+bool isError(const RootObject *const o);
diff --git a/gcc/d/dmd/templateparamsem.c b/gcc/d/dmd/templateparamsem.c
deleted file mode 100644
index d3e9b23..0000000
--- a/gcc/d/dmd/templateparamsem.c
+++ /dev/null
@@ -1,116 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- */
-
-#include "template.h"
-#include "mtype.h"
-#include "scope.h"
-#include "visitor.h"
-
-bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0);
-
-class TemplateParameterSemanticVisitor : public Visitor
-{
-public:
- Scope *sc;
- TemplateParameters *parameters;
- bool result;
-
- TemplateParameterSemanticVisitor(Scope *sc, TemplateParameters *parameters)
- {
- this->sc = sc;
- this->parameters = parameters;
- this->result = false;
- }
-
- void visit(TemplateTypeParameter *ttp)
- {
- //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars());
- if (ttp->specType && !reliesOnTident(ttp->specType, parameters))
- {
- ttp->specType = typeSemantic(ttp->specType, ttp->loc, sc);
- }
- result = !(ttp->specType && isError(ttp->specType));
- }
-
- void visit(TemplateValueParameter *tvp)
- {
- tvp->valType = typeSemantic(tvp->valType, tvp->loc, sc);
-
- result = !isError(tvp->valType);
- }
-
- void visit(TemplateAliasParameter *tap)
- {
- if (tap->specType && !reliesOnTident(tap->specType, parameters))
- {
- tap->specType = typeSemantic(tap->specType, tap->loc, sc);
- }
- tap->specAlias = aliasParameterSemantic(tap->loc, sc, tap->specAlias, parameters);
- result = !(tap->specType && isError(tap->specType)) &&
- !(tap->specAlias && isError(tap->specAlias));
- }
-
- void visit(TemplateTupleParameter *)
- {
- result = true;
- }
-};
-
-/************************************************
- * Performs semantic on TemplateParameter AST nodes.
- *
- * Params:
- * tp = element of `parameters` to be semantically analyzed
- * sc = context
- * parameters = array of `TemplateParameters` supplied to the `TemplateDeclaration`
- * Returns:
- * `true` if no errors
- */
-bool tpsemantic(TemplateParameter *tp, Scope *sc, TemplateParameters *parameters)
-{
- TemplateParameterSemanticVisitor v(sc, parameters);
- tp->accept(&v);
- return v.result;
-}
-
-/***********************************************
- * Support function for performing semantic analysis on `TemplateAliasParameter`.
- *
- * Params:
- * loc = location (for error messages)
- * sc = context
- * o = object to run semantic() on, the `TemplateAliasParameter`s `specAlias` or `defaultAlias`
- * parameters = array of `TemplateParameters` supplied to the `TemplateDeclaration`
- * Returns:
- * object resulting from running `semantic` on `o`
- */
-RootObject *aliasParameterSemantic(Loc loc, Scope *sc, RootObject *o, TemplateParameters *parameters)
-{
- if (o)
- {
- Expression *ea = isExpression(o);
- Type *ta = isType(o);
- if (ta && (!parameters || !reliesOnTident(ta, parameters)))
- {
- Dsymbol *s = ta->toDsymbol(sc);
- if (s)
- o = s;
- else
- o = typeSemantic(ta, loc, sc);
- }
- else if (ea)
- {
- sc = sc->startCTFE();
- ea = expressionSemantic(ea, sc);
- sc = sc->endCTFE();
- o = ea->ctfeInterpret();
- }
- }
- return o;
-}
diff --git a/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d
new file mode 100644
index 0000000..620492f
--- /dev/null
+++ b/gcc/d/dmd/templateparamsem.d
@@ -0,0 +1,190 @@
+/**
+ * Semantic analysis of template parameters.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/templateparamsem.d, _templateparamsem.d)
+ * Documentation: https://dlang.org/phobos/dmd_templateparamsem.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/templateparamsem.d
+ */
+
+module dmd.templateparamsem;
+
+import dmd.arraytypes;
+import dmd.dsymbol;
+import dmd.dscope;
+import dmd.dtemplate;
+import dmd.globals;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.root.rootobject;
+import dmd.mtype;
+import dmd.typesem;
+import dmd.visitor;
+
+/************************************************
+ * Performs semantic on TemplateParameter AST nodes.
+ *
+ * Params:
+ * tp = element of `parameters` to be semantically analyzed
+ * sc = context
+ * parameters = array of `TemplateParameters` supplied to the `TemplateDeclaration`
+ * Returns:
+ * `true` if no errors
+ */
+extern(C++) bool tpsemantic(TemplateParameter tp, Scope* sc, TemplateParameters* parameters)
+{
+ scope v = new TemplateParameterSemanticVisitor(sc, parameters);
+ tp.accept(v);
+ return v.result;
+}
+
+
+private extern (C++) final class TemplateParameterSemanticVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+
+ Scope* sc;
+ TemplateParameters* parameters;
+ bool result;
+
+ this(Scope* sc, TemplateParameters* parameters)
+ {
+ this.sc = sc;
+ this.parameters = parameters;
+ }
+
+ override void visit(TemplateTypeParameter ttp)
+ {
+ //printf("TemplateTypeParameter.semantic('%s')\n", ident.toChars());
+ if (ttp.specType && !reliesOnTident(ttp.specType, parameters))
+ {
+ ttp.specType = ttp.specType.typeSemantic(ttp.loc, sc);
+ }
+ version (none)
+ {
+ // Don't do semantic() until instantiation
+ if (ttp.defaultType)
+ {
+ ttp.defaultType = ttp.defaultType.typeSemantic(ttp.loc, sc);
+ }
+ }
+ result = !(ttp.specType && isError(ttp.specType));
+ }
+
+ override void visit(TemplateValueParameter tvp)
+ {
+ tvp.valType = tvp.valType.typeSemantic(tvp.loc, sc);
+ version (none)
+ {
+ // defer semantic analysis to arg match
+ if (tvp.specValue)
+ {
+ Expression e = tvp.specValue;
+ sc = sc.startCTFE();
+ e = e.semantic(sc);
+ sc = sc.endCTFE();
+ e = e.implicitCastTo(sc, tvp.valType);
+ e = e.ctfeInterpret();
+ if (e.op == TOK.int64 || e.op == TOK.float64 ||
+ e.op == TOK.complex80 || e.op == TOK.null_ || e.op == TOK.string_)
+ tvp.specValue = e;
+ }
+
+ if (tvp.defaultValue)
+ {
+ Expression e = defaultValue;
+ sc = sc.startCTFE();
+ e = e.semantic(sc);
+ sc = sc.endCTFE();
+ e = e.implicitCastTo(sc, tvp.valType);
+ e = e.ctfeInterpret();
+ if (e.op == TOK.int64)
+ tvp.defaultValue = e;
+ }
+ }
+ result = !isError(tvp.valType);
+ }
+
+ override void visit(TemplateAliasParameter tap)
+ {
+ if (tap.specType && !reliesOnTident(tap.specType, parameters))
+ {
+ tap.specType = tap.specType.typeSemantic(tap.loc, sc);
+ }
+ tap.specAlias = aliasParameterSemantic(tap.loc, sc, tap.specAlias, parameters);
+ version (none)
+ {
+ // Don't do semantic() until instantiation
+ if (tap.defaultAlias)
+ tap.defaultAlias = tap.defaultAlias.semantic(tap.loc, sc);
+ }
+ result = !(tap.specType && isError(tap.specType)) && !(tap.specAlias && isError(tap.specAlias));
+ }
+
+ override void visit(TemplateTupleParameter ttp)
+ {
+ result = true;
+ }
+}
+
+/***********************************************
+ * Support function for performing semantic analysis on `TemplateAliasParameter`.
+ *
+ * Params:
+ * loc = location (for error messages)
+ * sc = context
+ * o = object to run semantic() on, the `TemplateAliasParameter`s `specAlias` or `defaultAlias`
+ * parameters = array of `TemplateParameters` supplied to the `TemplateDeclaration`
+ * Returns:
+ * object resulting from running `semantic` on `o`
+ */
+RootObject aliasParameterSemantic(Loc loc, Scope* sc, RootObject o, TemplateParameters* parameters)
+{
+ if (!o)
+ return null;
+
+ Expression ea = isExpression(o);
+ RootObject eaCTFE()
+ {
+ sc = sc.startCTFE();
+ ea = ea.expressionSemantic(sc);
+ sc = sc.endCTFE();
+ return ea.ctfeInterpret();
+ }
+ Type ta = isType(o);
+ if (ta && (!parameters || !reliesOnTident(ta, parameters)))
+ {
+ Dsymbol s = ta.toDsymbol(sc);
+ if (s)
+ return s;
+ else if (TypeInstance ti = ta.isTypeInstance())
+ {
+ Type t;
+ const errors = global.errors;
+ ta.resolve(loc, sc, ea, t, s);
+ // if we had an error evaluating the symbol, suppress further errors
+ if (!t && errors != global.errors)
+ return Type.terror;
+ // We might have something that looks like a type
+ // but is actually an expression or a dsymbol
+ // see https://issues.dlang.org/show_bug.cgi?id=16472
+ if (t)
+ return t.typeSemantic(loc, sc);
+ else if (ea)
+ {
+ return eaCTFE();
+ }
+ else if (s)
+ return s;
+ else
+ assert(0);
+ }
+ else
+ return ta.typeSemantic(loc, sc);
+ }
+ else if (ea)
+ return eaCTFE();
+ return o;
+}
diff --git a/gcc/d/dmd/tokens.c b/gcc/d/dmd/tokens.c
deleted file mode 100644
index eb06bee..0000000
--- a/gcc/d/dmd/tokens.c
+++ /dev/null
@@ -1,476 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/lexer.c
- */
-
-#include "root/dsystem.h"
-
-#include "tokens.h"
-#include "root/rmem.h"
-#include "root/outbuffer.h"
-#include "id.h"
-#include "identifier.h"
-#include "utf.h"
-
-/************************* Token **********************************************/
-
-Token *Token::freelist = NULL;
-
-const char *Token::tochars[TOKMAX];
-
-Token *Token::alloc()
-{
- if (Token::freelist)
- {
- Token *t = freelist;
- freelist = t->next;
- t->next = NULL;
- return t;
- }
-
- return new Token();
-}
-
-void Token::free()
-{
- next = freelist;
- freelist = this;
-}
-
-const char *Token::toChars() const
-{
- static char buffer[3 + 3 * sizeof(floatvalue) + 1];
-
- const char *p = &buffer[0];
- switch (value)
- {
- case TOKint32v:
- sprintf(&buffer[0],"%d",(d_int32)int64value);
- break;
-
- case TOKuns32v:
- case TOKcharv:
- case TOKwcharv:
- case TOKdcharv:
- sprintf(&buffer[0],"%uU",(d_uns32)uns64value);
- break;
-
- case TOKint64v:
- sprintf(&buffer[0],"%lldL",(longlong)int64value);
- break;
-
- case TOKuns64v:
- sprintf(&buffer[0],"%lluUL",(ulonglong)uns64value);
- break;
-
- case TOKfloat32v:
- CTFloat::sprint(&buffer[0], 'g', floatvalue);
- strcat(&buffer[0], "f");
- break;
-
- case TOKfloat64v:
- CTFloat::sprint(&buffer[0], 'g', floatvalue);
- break;
-
- case TOKfloat80v:
- CTFloat::sprint(&buffer[0], 'g', floatvalue);
- strcat(&buffer[0], "L");
- break;
-
- case TOKimaginary32v:
- CTFloat::sprint(&buffer[0], 'g', floatvalue);
- strcat(&buffer[0], "fi");
- break;
-
- case TOKimaginary64v:
- CTFloat::sprint(&buffer[0], 'g', floatvalue);
- strcat(&buffer[0], "i");
- break;
-
- case TOKimaginary80v:
- CTFloat::sprint(&buffer[0], 'g', floatvalue);
- strcat(&buffer[0], "Li");
- break;
-
- case TOKstring:
- {
- OutBuffer buf;
- buf.writeByte('"');
- for (size_t i = 0; i < len; )
- {
- unsigned c;
- utf_decodeChar((utf8_t *)ustring, len, &i, &c);
- switch (c)
- {
- case 0:
- break;
-
- case '"':
- case '\\':
- buf.writeByte('\\');
- /* fall through */
- default:
- if (c <= 0x7F)
- {
- if (isprint(c))
- buf.writeByte(c);
- else
- buf.printf("\\x%02x", c);
- }
- else if (c <= 0xFFFF)
- buf.printf("\\u%04x", c);
- else
- buf.printf("\\U%08x", c);
- continue;
- }
- break;
- }
- buf.writeByte('"');
- if (postfix)
- buf.writeByte(postfix);
- p = buf.extractChars();
- }
- break;
-
- case TOKxstring:
- {
- OutBuffer buf;
- buf.writeByte('x');
- buf.writeByte('"');
- for (size_t i = 0; i < len; i++)
- {
- if (i)
- buf.writeByte(' ');
- buf.printf("%02x", ustring[i]);
- }
- buf.writeByte('"');
- if (postfix)
- buf.writeByte(postfix);
- buf.writeByte(0);
- p = (char *)buf.extractData();
- break;
- }
-
- case TOKidentifier:
- case TOKenum:
- case TOKstruct:
- case TOKimport:
- case TOKwchar: case TOKdchar:
- case TOKbool: case TOKchar:
- case TOKint8: case TOKuns8:
- case TOKint16: case TOKuns16:
- case TOKint32: case TOKuns32:
- case TOKint64: case TOKuns64:
- case TOKint128: case TOKuns128:
- case TOKfloat32: case TOKfloat64: case TOKfloat80:
- case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
- case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
- case TOKvoid:
- p = ident->toChars();
- break;
-
- default:
- p = toChars(value);
- break;
- }
- return p;
-}
-
-const char *Token::toChars(TOK value)
-{
- static char buffer[3 + 3 * sizeof(value) + 1];
-
- const char *p = tochars[value];
- if (!p)
- {
- sprintf(&buffer[0],"TOK%d",value);
- p = &buffer[0];
- }
- return p;
-}
-
-/****************************************
- */
-
-struct Keyword
-{
- const char *name;
- TOK value;
-};
-
-static size_t nkeywords;
-static Keyword keywords[] =
-{
- { "this", TOKthis },
- { "super", TOKsuper },
- { "assert", TOKassert },
- { "null", TOKnull },
- { "true", TOKtrue },
- { "false", TOKfalse },
- { "cast", TOKcast },
- { "new", TOKnew },
- { "delete", TOKdelete },
- { "throw", TOKthrow },
- { "module", TOKmodule },
- { "pragma", TOKpragma },
- { "typeof", TOKtypeof },
- { "typeid", TOKtypeid },
-
- { "template", TOKtemplate },
-
- { "void", TOKvoid },
- { "byte", TOKint8 },
- { "ubyte", TOKuns8 },
- { "short", TOKint16 },
- { "ushort", TOKuns16 },
- { "int", TOKint32 },
- { "uint", TOKuns32 },
- { "long", TOKint64 },
- { "ulong", TOKuns64 },
- { "cent", TOKint128, },
- { "ucent", TOKuns128, },
- { "float", TOKfloat32 },
- { "double", TOKfloat64 },
- { "real", TOKfloat80 },
-
- { "bool", TOKbool },
- { "char", TOKchar },
- { "wchar", TOKwchar },
- { "dchar", TOKdchar },
-
- { "ifloat", TOKimaginary32 },
- { "idouble", TOKimaginary64 },
- { "ireal", TOKimaginary80 },
-
- { "cfloat", TOKcomplex32 },
- { "cdouble", TOKcomplex64 },
- { "creal", TOKcomplex80 },
-
- { "delegate", TOKdelegate },
- { "function", TOKfunction },
-
- { "is", TOKis },
- { "if", TOKif },
- { "else", TOKelse },
- { "while", TOKwhile },
- { "for", TOKfor },
- { "do", TOKdo },
- { "switch", TOKswitch },
- { "case", TOKcase },
- { "default", TOKdefault },
- { "break", TOKbreak },
- { "continue", TOKcontinue },
- { "synchronized", TOKsynchronized },
- { "return", TOKreturn },
- { "goto", TOKgoto },
- { "try", TOKtry },
- { "catch", TOKcatch },
- { "finally", TOKfinally },
- { "with", TOKwith },
- { "asm", TOKasm },
- { "foreach", TOKforeach },
- { "foreach_reverse", TOKforeach_reverse },
- { "scope", TOKscope },
-
- { "struct", TOKstruct },
- { "class", TOKclass },
- { "interface", TOKinterface },
- { "union", TOKunion },
- { "enum", TOKenum },
- { "import", TOKimport },
- { "mixin", TOKmixin },
- { "static", TOKstatic },
- { "final", TOKfinal },
- { "const", TOKconst },
- { "alias", TOKalias },
- { "override", TOKoverride },
- { "abstract", TOKabstract },
- { "debug", TOKdebug },
- { "deprecated", TOKdeprecated },
- { "in", TOKin },
- { "out", TOKout },
- { "inout", TOKinout },
- { "lazy", TOKlazy },
- { "auto", TOKauto },
-
- { "align", TOKalign },
- { "extern", TOKextern },
- { "private", TOKprivate },
- { "package", TOKpackage },
- { "protected", TOKprotected },
- { "public", TOKpublic },
- { "export", TOKexport },
-
- { "invariant", TOKinvariant },
- { "unittest", TOKunittest },
- { "version", TOKversion },
-
- { "__argTypes", TOKargTypes },
- { "__parameters", TOKparameters },
- { "ref", TOKref },
- { "macro", TOKmacro },
-
- { "pure", TOKpure },
- { "nothrow", TOKnothrow },
- { "__gshared", TOKgshared },
- { "__traits", TOKtraits },
- { "__vector", TOKvector },
- { "__overloadset", TOKoverloadset },
- { "__FILE__", TOKfile },
- { "__FILE_FULL_PATH__", TOKfilefullpath },
- { "__LINE__", TOKline },
- { "__MODULE__", TOKmodulestring },
- { "__FUNCTION__", TOKfuncstring },
- { "__PRETTY_FUNCTION__", TOKprettyfunc },
- { "shared", TOKshared },
- { "immutable", TOKimmutable },
- { NULL, TOKreserved }
-};
-
-int Token::isKeyword()
-{
- for (size_t u = 0; u < nkeywords; u++)
- {
- if (keywords[u].value == value)
- return 1;
- }
- return 0;
-}
-
-struct TokenInitializer
-{
- TokenInitializer();
-};
-
-static TokenInitializer tokeninitializer;
-
-TokenInitializer::TokenInitializer()
-{
- Identifier::initTable();
- for (nkeywords = 0; keywords[nkeywords].name; nkeywords++)
- {
- //printf("keyword[%d] = '%s'\n",u, keywords[u].name);
- const char *s = keywords[nkeywords].name;
- size_t len = strlen(s);
- TOK v = keywords[nkeywords].value;
- Identifier::idPool(s, len, v);
-
- //printf("tochars[%d] = '%s'\n",v, s);
- Token::tochars[v] = s;
- }
-
- Token::tochars[TOKeof] = "EOF";
- Token::tochars[TOKlcurly] = "{";
- Token::tochars[TOKrcurly] = "}";
- Token::tochars[TOKlparen] = "(";
- Token::tochars[TOKrparen] = ")";
- Token::tochars[TOKlbracket] = "[";
- Token::tochars[TOKrbracket] = "]";
- Token::tochars[TOKsemicolon] = ";";
- Token::tochars[TOKcolon] = ":";
- Token::tochars[TOKcomma] = ",";
- Token::tochars[TOKdot] = ".";
- Token::tochars[TOKxor] = "^";
- Token::tochars[TOKxorass] = "^=";
- Token::tochars[TOKassign] = "=";
- Token::tochars[TOKconstruct] = "=";
- Token::tochars[TOKblit] = "=";
- Token::tochars[TOKlt] = "<";
- Token::tochars[TOKgt] = ">";
- Token::tochars[TOKle] = "<=";
- Token::tochars[TOKge] = ">=";
- Token::tochars[TOKequal] = "==";
- Token::tochars[TOKnotequal] = "!=";
- Token::tochars[TOKnotidentity] = "!is";
-
- Token::tochars[TOKunord] = "!<>=";
- Token::tochars[TOKue] = "!<>";
- Token::tochars[TOKlg] = "<>";
- Token::tochars[TOKleg] = "<>=";
- Token::tochars[TOKule] = "!>";
- Token::tochars[TOKul] = "!>=";
- Token::tochars[TOKuge] = "!<";
- Token::tochars[TOKug] = "!<=";
-
- Token::tochars[TOKnot] = "!";
- Token::tochars[TOKshl] = "<<";
- Token::tochars[TOKshr] = ">>";
- Token::tochars[TOKushr] = ">>>";
- Token::tochars[TOKadd] = "+";
- Token::tochars[TOKmin] = "-";
- Token::tochars[TOKmul] = "*";
- Token::tochars[TOKdiv] = "/";
- Token::tochars[TOKmod] = "%";
- Token::tochars[TOKslice] = "..";
- Token::tochars[TOKdotdotdot] = "...";
- Token::tochars[TOKand] = "&";
- Token::tochars[TOKandand] = "&&";
- Token::tochars[TOKor] = "|";
- Token::tochars[TOKoror] = "||";
- Token::tochars[TOKarray] = "[]";
- Token::tochars[TOKindex] = "[i]";
- Token::tochars[TOKaddress] = "&";
- Token::tochars[TOKstar] = "*";
- Token::tochars[TOKtilde] = "~";
- Token::tochars[TOKdollar] = "$";
- Token::tochars[TOKcast] = "cast";
- Token::tochars[TOKplusplus] = "++";
- Token::tochars[TOKminusminus] = "--";
- Token::tochars[TOKpreplusplus] = "++";
- Token::tochars[TOKpreminusminus] = "--";
- Token::tochars[TOKtype] = "type";
- Token::tochars[TOKquestion] = "?";
- Token::tochars[TOKneg] = "-";
- Token::tochars[TOKuadd] = "+";
- Token::tochars[TOKvar] = "var";
- Token::tochars[TOKaddass] = "+=";
- Token::tochars[TOKminass] = "-=";
- Token::tochars[TOKmulass] = "*=";
- Token::tochars[TOKdivass] = "/=";
- Token::tochars[TOKmodass] = "%=";
- Token::tochars[TOKshlass] = "<<=";
- Token::tochars[TOKshrass] = ">>=";
- Token::tochars[TOKushrass] = ">>>=";
- Token::tochars[TOKandass] = "&=";
- Token::tochars[TOKorass] = "|=";
- Token::tochars[TOKcatass] = "~=";
- Token::tochars[TOKcat] = "~";
- Token::tochars[TOKcall] = "call";
- Token::tochars[TOKidentity] = "is";
- Token::tochars[TOKnotidentity] = "!is";
-
- Token::tochars[TOKorass] = "|=";
- Token::tochars[TOKidentifier] = "identifier";
- Token::tochars[TOKat] = "@";
- Token::tochars[TOKpow] = "^^";
- Token::tochars[TOKpowass] = "^^=";
- Token::tochars[TOKgoesto] = "=>";
- Token::tochars[TOKpound] = "#";
-
- // For debugging
- Token::tochars[TOKerror] = "error";
- Token::tochars[TOKdotid] = "dotid";
- Token::tochars[TOKdottd] = "dottd";
- Token::tochars[TOKdotti] = "dotti";
- Token::tochars[TOKdotvar] = "dotvar";
- Token::tochars[TOKdottype] = "dottype";
- Token::tochars[TOKsymoff] = "symoff";
- Token::tochars[TOKarraylength] = "arraylength";
- Token::tochars[TOKarrayliteral] = "arrayliteral";
- Token::tochars[TOKassocarrayliteral] = "assocarrayliteral";
- Token::tochars[TOKstructliteral] = "structliteral";
- Token::tochars[TOKstring] = "string";
- Token::tochars[TOKdsymbol] = "symbol";
- Token::tochars[TOKtuple] = "tuple";
- Token::tochars[TOKdeclaration] = "declaration";
- Token::tochars[TOKon_scope_exit] = "scope(exit)";
- Token::tochars[TOKon_scope_success] = "scope(success)";
- Token::tochars[TOKon_scope_failure] = "scope(failure)";
- Token::tochars[TOKdelegateptr] = "delegateptr";
- Token::tochars[TOKvectorarray] = "vectorarray";
-}
diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d
new file mode 100644
index 0000000..7680fb8
--- /dev/null
+++ b/gcc/d/dmd/tokens.d
@@ -0,0 +1,1022 @@
+/**
+ * Defines lexical tokens.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/lex.html#tokens, Tokens)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/tokens.d, _tokens.d)
+ * Documentation: https://dlang.org/phobos/dmd_tokens.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/tokens.d
+ */
+
+module dmd.tokens;
+
+import core.stdc.ctype;
+import core.stdc.stdio;
+import core.stdc.string;
+import dmd.globals;
+import dmd.identifier;
+import dmd.root.ctfloat;
+import dmd.root.outbuffer;
+import dmd.root.rmem;
+import dmd.utf;
+
+enum TOK : ushort
+{
+ reserved,
+
+ // Other
+ leftParenthesis,
+ rightParenthesis,
+ leftBracket,
+ rightBracket,
+ leftCurly,
+ rightCurly,
+ colon,
+ negate,
+ semicolon,
+ dotDotDot,
+ endOfFile,
+ cast_,
+ null_,
+ assert_,
+ true_,
+ false_,
+ array,
+ call,
+ address,
+ type,
+ throw_,
+ new_,
+ delete_,
+ star,
+ symbolOffset,
+ variable,
+ dotVariable,
+ dotIdentifier,
+ dotTemplateInstance,
+ dotType,
+ slice,
+ arrayLength,
+ version_,
+ module_,
+ dollar,
+ template_,
+ dotTemplateDeclaration,
+ declaration,
+ typeof_,
+ pragma_,
+ dSymbol,
+ typeid_,
+ uadd,
+ remove,
+ newAnonymousClass,
+ comment,
+ arrayLiteral,
+ assocArrayLiteral,
+ structLiteral,
+ classReference,
+ thrownException,
+ delegatePointer,
+ delegateFunctionPointer,
+
+ // Operators
+ lessThan = 54,
+ greaterThan,
+ lessOrEqual,
+ greaterOrEqual,
+ equal,
+ notEqual,
+ identity,
+ notIdentity,
+ index,
+ is_,
+
+ leftShift = 64,
+ rightShift,
+ leftShiftAssign,
+ rightShiftAssign,
+ unsignedRightShift,
+ unsignedRightShiftAssign,
+ concatenate,
+ concatenateAssign, // ~=
+ concatenateElemAssign,
+ concatenateDcharAssign,
+ add,
+ min,
+ addAssign,
+ minAssign,
+ mul,
+ div,
+ mod,
+ mulAssign,
+ divAssign,
+ modAssign,
+ and,
+ or,
+ xor,
+ andAssign,
+ orAssign,
+ xorAssign,
+ assign,
+ not,
+ tilde,
+ plusPlus,
+ minusMinus,
+ construct,
+ blit,
+ dot,
+ comma,
+ question,
+ andAnd,
+ orOr,
+ prePlusPlus,
+ preMinusMinus,
+
+ // Numeric literals
+ int32Literal = 104,
+ uns32Literal,
+ int64Literal,
+ uns64Literal,
+ int128Literal,
+ uns128Literal,
+ float32Literal,
+ float64Literal,
+ float80Literal,
+ imaginary32Literal,
+ imaginary64Literal,
+ imaginary80Literal,
+
+ // Char constants
+ charLiteral = 116,
+ wcharLiteral,
+ dcharLiteral,
+
+ // Leaf operators
+ identifier = 119,
+ string_,
+ hexadecimalString,
+ this_,
+ super_,
+ halt,
+ tuple,
+ error,
+
+ // Basic types
+ void_ = 127,
+ int8,
+ uns8,
+ int16,
+ uns16,
+ int32,
+ uns32,
+ int64,
+ uns64,
+ int128,
+ uns128,
+ float32,
+ float64,
+ float80,
+ imaginary32,
+ imaginary64,
+ imaginary80,
+ complex32,
+ complex64,
+ complex80,
+ char_,
+ wchar_,
+ dchar_,
+ bool_,
+
+ // Aggregates
+ struct_ = 151,
+ class_,
+ interface_,
+ union_,
+ enum_,
+ import_,
+ alias_,
+ override_,
+ delegate_,
+ function_,
+ mixin_,
+ align_,
+ extern_,
+ private_,
+ protected_,
+ public_,
+ export_,
+ static_,
+ final_,
+ const_,
+ abstract_,
+ debug_,
+ deprecated_,
+ in_,
+ out_,
+ inout_,
+ lazy_,
+ auto_,
+ package_,
+ immutable_,
+
+ // Statements
+ if_ = 181,
+ else_,
+ while_,
+ for_,
+ do_,
+ switch_,
+ case_,
+ default_,
+ break_,
+ continue_,
+ with_,
+ synchronized_,
+ return_,
+ goto_,
+ try_,
+ catch_,
+ finally_,
+ asm_,
+ foreach_,
+ foreach_reverse_,
+ scope_,
+ onScopeExit,
+ onScopeFailure,
+ onScopeSuccess,
+
+ // Contracts
+ invariant_ = 205,
+
+ // Testing
+ unittest_,
+
+ // Added after 1.0
+ argumentTypes,
+ ref_,
+ macro_,
+
+ parameters = 210,
+ traits,
+ overloadSet,
+ pure_,
+ nothrow_,
+ gshared,
+ line,
+ file,
+ fileFullPath,
+ moduleString, // __MODULE__
+ functionString, // __FUNCTION__
+ prettyFunction, // __PRETTY_FUNCTION__
+ shared_,
+ at,
+ pow,
+ powAssign,
+ goesTo,
+ vector,
+ pound,
+
+ interval = 229,
+ voidExpression,
+ cantExpression,
+ showCtfeContext,
+
+ objcClassReference,
+ vectorArray,
+
+ arrow, // ->
+ colonColon, // ::
+ wchar_tLiteral,
+ compoundLiteral, // ( type-name ) { initializer-list }
+
+ // C only keywords
+ inline,
+ register,
+ restrict,
+ signed,
+ sizeof_,
+ typedef_,
+ unsigned,
+ volatile,
+ _Alignas,
+ _Alignof,
+ _Atomic,
+ _Bool,
+ _Complex,
+ _Generic,
+ _Imaginary,
+ _Noreturn,
+ _Static_assert,
+ _Thread_local,
+
+ // C only extended keywords
+ __cdecl,
+ __declspec,
+ __attribute__,
+}
+
+enum FirstCKeyword = TOK.inline;
+
+// Assert that all token enum members have consecutive values and
+// that none of them overlap
+static assert(() {
+ foreach (idx, enumName; __traits(allMembers, TOK)) {
+ static if (idx != __traits(getMember, TOK, enumName)) {
+ pragma(msg, "Error: Expected TOK.", enumName, " to be ", idx, " but is ", __traits(getMember, TOK, enumName));
+ static assert(0);
+ }
+ }
+ return true;
+}());
+
+/****************************************
+ */
+
+private immutable TOK[] keywords =
+[
+ TOK.this_,
+ TOK.super_,
+ TOK.assert_,
+ TOK.null_,
+ TOK.true_,
+ TOK.false_,
+ TOK.cast_,
+ TOK.new_,
+ TOK.delete_,
+ TOK.throw_,
+ TOK.module_,
+ TOK.pragma_,
+ TOK.typeof_,
+ TOK.typeid_,
+ TOK.template_,
+ TOK.void_,
+ TOK.int8,
+ TOK.uns8,
+ TOK.int16,
+ TOK.uns16,
+ TOK.int32,
+ TOK.uns32,
+ TOK.int64,
+ TOK.uns64,
+ TOK.int128,
+ TOK.uns128,
+ TOK.float32,
+ TOK.float64,
+ TOK.float80,
+ TOK.bool_,
+ TOK.char_,
+ TOK.wchar_,
+ TOK.dchar_,
+ TOK.imaginary32,
+ TOK.imaginary64,
+ TOK.imaginary80,
+ TOK.complex32,
+ TOK.complex64,
+ TOK.complex80,
+ TOK.delegate_,
+ TOK.function_,
+ TOK.is_,
+ TOK.if_,
+ TOK.else_,
+ TOK.while_,
+ TOK.for_,
+ TOK.do_,
+ TOK.switch_,
+ TOK.case_,
+ TOK.default_,
+ TOK.break_,
+ TOK.continue_,
+ TOK.synchronized_,
+ TOK.return_,
+ TOK.goto_,
+ TOK.try_,
+ TOK.catch_,
+ TOK.finally_,
+ TOK.with_,
+ TOK.asm_,
+ TOK.foreach_,
+ TOK.foreach_reverse_,
+ TOK.scope_,
+ TOK.struct_,
+ TOK.class_,
+ TOK.interface_,
+ TOK.union_,
+ TOK.enum_,
+ TOK.import_,
+ TOK.mixin_,
+ TOK.static_,
+ TOK.final_,
+ TOK.const_,
+ TOK.alias_,
+ TOK.override_,
+ TOK.abstract_,
+ TOK.debug_,
+ TOK.deprecated_,
+ TOK.in_,
+ TOK.out_,
+ TOK.inout_,
+ TOK.lazy_,
+ TOK.auto_,
+ TOK.align_,
+ TOK.extern_,
+ TOK.private_,
+ TOK.package_,
+ TOK.protected_,
+ TOK.public_,
+ TOK.export_,
+ TOK.invariant_,
+ TOK.unittest_,
+ TOK.version_,
+ TOK.argumentTypes,
+ TOK.parameters,
+ TOK.ref_,
+ TOK.macro_,
+ TOK.pure_,
+ TOK.nothrow_,
+ TOK.gshared,
+ TOK.traits,
+ TOK.vector,
+ TOK.overloadSet,
+ TOK.file,
+ TOK.fileFullPath,
+ TOK.line,
+ TOK.moduleString,
+ TOK.functionString,
+ TOK.prettyFunction,
+ TOK.shared_,
+ TOK.immutable_,
+
+ // C only keywords
+ TOK.inline,
+ TOK.register,
+ TOK.restrict,
+ TOK.signed,
+ TOK.sizeof_,
+ TOK.typedef_,
+ TOK.unsigned,
+ TOK.volatile,
+ TOK._Alignas,
+ TOK._Alignof,
+ TOK._Atomic,
+ TOK._Bool,
+ TOK._Complex,
+ TOK._Generic,
+ TOK._Imaginary,
+ TOK._Noreturn,
+ TOK._Static_assert,
+ TOK._Thread_local,
+
+ // C only extended keywords
+ TOK.__cdecl,
+ TOK.__declspec,
+ TOK.__attribute__,
+];
+
+// Initialize the identifier pool
+shared static this() nothrow
+{
+ Identifier.initTable();
+ foreach (kw; keywords)
+ {
+ //printf("keyword[%d] = '%s'\n",kw, tochars[kw].ptr);
+ Identifier.idPool(Token.tochars[kw].ptr, Token.tochars[kw].length, cast(uint)kw);
+ }
+}
+
+/************************************
+ * This is used to pick the C keywords out of the tokens.
+ * If it's not a C keyword, then it's an identifier.
+ */
+static immutable TOK[TOK.max + 1] Ckeywords =
+() {
+ with (TOK)
+ {
+ TOK[TOK.max + 1] tab = identifier; // default to identifier
+ enum Ckwds = [ auto_, break_, case_, char_, const_, continue_, default_, do_, float64, else_,
+ enum_, extern_, float32, for_, goto_, if_, inline, int32, int64, register,
+ restrict, return_, int16, signed, sizeof_, static_, struct_, switch_, typedef_,
+ union_, unsigned, void_, volatile, while_, asm_,
+ _Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn,
+ _Static_assert, _Thread_local, __cdecl, __declspec, __attribute__ ];
+
+ foreach (kw; Ckwds)
+ tab[kw] = cast(TOK) kw;
+
+ return tab;
+ }
+} ();
+
+
+/***********************************************************
+ */
+extern (C++) struct Token
+{
+ Token* next;
+ Loc loc;
+ const(char)* ptr; // pointer to first character of this token within buffer
+ TOK value;
+ const(char)[] blockComment; // doc comment string prior to this token
+ const(char)[] lineComment; // doc comment for previous token
+
+ union
+ {
+ // Integers
+ sinteger_t intvalue;
+ uinteger_t unsvalue;
+ // Floats
+ real_t floatvalue;
+
+ struct
+ {
+ const(char)* ustring; // UTF8 string
+ uint len;
+ ubyte postfix; // 'c', 'w', 'd'
+ }
+
+ Identifier ident;
+ }
+
+ extern (D) private static immutable string[TOK.max + 1] tochars =
+ [
+ // Keywords
+ TOK.this_: "this",
+ TOK.super_: "super",
+ TOK.assert_: "assert",
+ TOK.null_: "null",
+ TOK.true_: "true",
+ TOK.false_: "false",
+ TOK.cast_: "cast",
+ TOK.new_: "new",
+ TOK.delete_: "delete",
+ TOK.throw_: "throw",
+ TOK.module_: "module",
+ TOK.pragma_: "pragma",
+ TOK.typeof_: "typeof",
+ TOK.typeid_: "typeid",
+ TOK.template_: "template",
+ TOK.void_: "void",
+ TOK.int8: "byte",
+ TOK.uns8: "ubyte",
+ TOK.int16: "short",
+ TOK.uns16: "ushort",
+ TOK.int32: "int",
+ TOK.uns32: "uint",
+ TOK.int64: "long",
+ TOK.uns64: "ulong",
+ TOK.int128: "cent",
+ TOK.uns128: "ucent",
+ TOK.float32: "float",
+ TOK.float64: "double",
+ TOK.float80: "real",
+ TOK.bool_: "bool",
+ TOK.char_: "char",
+ TOK.wchar_: "wchar",
+ TOK.dchar_: "dchar",
+ TOK.imaginary32: "ifloat",
+ TOK.imaginary64: "idouble",
+ TOK.imaginary80: "ireal",
+ TOK.complex32: "cfloat",
+ TOK.complex64: "cdouble",
+ TOK.complex80: "creal",
+ TOK.delegate_: "delegate",
+ TOK.function_: "function",
+ TOK.is_: "is",
+ TOK.if_: "if",
+ TOK.else_: "else",
+ TOK.while_: "while",
+ TOK.for_: "for",
+ TOK.do_: "do",
+ TOK.switch_: "switch",
+ TOK.case_: "case",
+ TOK.default_: "default",
+ TOK.break_: "break",
+ TOK.continue_: "continue",
+ TOK.synchronized_: "synchronized",
+ TOK.return_: "return",
+ TOK.goto_: "goto",
+ TOK.try_: "try",
+ TOK.catch_: "catch",
+ TOK.finally_: "finally",
+ TOK.with_: "with",
+ TOK.asm_: "asm",
+ TOK.foreach_: "foreach",
+ TOK.foreach_reverse_: "foreach_reverse",
+ TOK.scope_: "scope",
+ TOK.struct_: "struct",
+ TOK.class_: "class",
+ TOK.interface_: "interface",
+ TOK.union_: "union",
+ TOK.enum_: "enum",
+ TOK.import_: "import",
+ TOK.mixin_: "mixin",
+ TOK.static_: "static",
+ TOK.final_: "final",
+ TOK.const_: "const",
+ TOK.alias_: "alias",
+ TOK.override_: "override",
+ TOK.abstract_: "abstract",
+ TOK.debug_: "debug",
+ TOK.deprecated_: "deprecated",
+ TOK.in_: "in",
+ TOK.out_: "out",
+ TOK.inout_: "inout",
+ TOK.lazy_: "lazy",
+ TOK.auto_: "auto",
+ TOK.align_: "align",
+ TOK.extern_: "extern",
+ TOK.private_: "private",
+ TOK.package_: "package",
+ TOK.protected_: "protected",
+ TOK.public_: "public",
+ TOK.export_: "export",
+ TOK.invariant_: "invariant",
+ TOK.unittest_: "unittest",
+ TOK.version_: "version",
+ TOK.argumentTypes: "__argTypes",
+ TOK.parameters: "__parameters",
+ TOK.ref_: "ref",
+ TOK.macro_: "macro",
+ TOK.pure_: "pure",
+ TOK.nothrow_: "nothrow",
+ TOK.gshared: "__gshared",
+ TOK.traits: "__traits",
+ TOK.vector: "__vector",
+ TOK.overloadSet: "__overloadset",
+ TOK.file: "__FILE__",
+ TOK.fileFullPath: "__FILE_FULL_PATH__",
+ TOK.line: "__LINE__",
+ TOK.moduleString: "__MODULE__",
+ TOK.functionString: "__FUNCTION__",
+ TOK.prettyFunction: "__PRETTY_FUNCTION__",
+ TOK.shared_: "shared",
+ TOK.immutable_: "immutable",
+
+ TOK.endOfFile: "End of File",
+ TOK.leftCurly: "{",
+ TOK.rightCurly: "}",
+ TOK.leftParenthesis: "(",
+ TOK.rightParenthesis: ")",
+ TOK.leftBracket: "[",
+ TOK.rightBracket: "]",
+ TOK.semicolon: ";",
+ TOK.colon: ":",
+ TOK.comma: ",",
+ TOK.dot: ".",
+ TOK.xor: "^",
+ TOK.xorAssign: "^=",
+ TOK.assign: "=",
+ TOK.construct: "=",
+ TOK.blit: "=",
+ TOK.lessThan: "<",
+ TOK.greaterThan: ">",
+ TOK.lessOrEqual: "<=",
+ TOK.greaterOrEqual: ">=",
+ TOK.equal: "==",
+ TOK.notEqual: "!=",
+ TOK.not: "!",
+ TOK.leftShift: "<<",
+ TOK.rightShift: ">>",
+ TOK.unsignedRightShift: ">>>",
+ TOK.add: "+",
+ TOK.min: "-",
+ TOK.mul: "*",
+ TOK.div: "/",
+ TOK.mod: "%",
+ TOK.slice: "..",
+ TOK.dotDotDot: "...",
+ TOK.and: "&",
+ TOK.andAnd: "&&",
+ TOK.or: "|",
+ TOK.orOr: "||",
+ TOK.array: "[]",
+ TOK.index: "[i]",
+ TOK.address: "&",
+ TOK.star: "*",
+ TOK.tilde: "~",
+ TOK.dollar: "$",
+ TOK.plusPlus: "++",
+ TOK.minusMinus: "--",
+ TOK.prePlusPlus: "++",
+ TOK.preMinusMinus: "--",
+ TOK.type: "type",
+ TOK.question: "?",
+ TOK.negate: "-",
+ TOK.uadd: "+",
+ TOK.variable: "var",
+ TOK.addAssign: "+=",
+ TOK.minAssign: "-=",
+ TOK.mulAssign: "*=",
+ TOK.divAssign: "/=",
+ TOK.modAssign: "%=",
+ TOK.leftShiftAssign: "<<=",
+ TOK.rightShiftAssign: ">>=",
+ TOK.unsignedRightShiftAssign: ">>>=",
+ TOK.andAssign: "&=",
+ TOK.orAssign: "|=",
+ TOK.concatenateAssign: "~=",
+ TOK.concatenateElemAssign: "~=",
+ TOK.concatenateDcharAssign: "~=",
+ TOK.concatenate: "~",
+ TOK.call: "call",
+ TOK.identity: "is",
+ TOK.notIdentity: "!is",
+ TOK.identifier: "identifier",
+ TOK.at: "@",
+ TOK.pow: "^^",
+ TOK.powAssign: "^^=",
+ TOK.goesTo: "=>",
+ TOK.pound: "#",
+ TOK.arrow: "->",
+ TOK.colonColon: "::",
+
+ // For debugging
+ TOK.error: "error",
+ TOK.dotIdentifier: "dotid",
+ TOK.dotTemplateDeclaration: "dottd",
+ TOK.dotTemplateInstance: "dotti",
+ TOK.dotVariable: "dotvar",
+ TOK.dotType: "dottype",
+ TOK.symbolOffset: "symoff",
+ TOK.arrayLength: "arraylength",
+ TOK.arrayLiteral: "arrayliteral",
+ TOK.assocArrayLiteral: "assocarrayliteral",
+ TOK.structLiteral: "structliteral",
+ TOK.string_: "string",
+ TOK.dSymbol: "symbol",
+ TOK.tuple: "tuple",
+ TOK.declaration: "declaration",
+ TOK.onScopeExit: "scope(exit)",
+ TOK.onScopeSuccess: "scope(success)",
+ TOK.onScopeFailure: "scope(failure)",
+ TOK.delegatePointer: "delegateptr",
+
+ // Finish up
+ TOK.reserved: "reserved",
+ TOK.remove: "remove",
+ TOK.newAnonymousClass: "newanonclass",
+ TOK.comment: "comment",
+ TOK.classReference: "classreference",
+ TOK.thrownException: "thrownexception",
+ TOK.delegateFunctionPointer: "delegatefuncptr",
+ TOK.int32Literal: "int32v",
+ TOK.uns32Literal: "uns32v",
+ TOK.int64Literal: "int64v",
+ TOK.uns64Literal: "uns64v",
+ TOK.int128Literal: "int128v",
+ TOK.uns128Literal: "uns128v",
+ TOK.float32Literal: "float32v",
+ TOK.float64Literal: "float64v",
+ TOK.float80Literal: "float80v",
+ TOK.imaginary32Literal: "imaginary32v",
+ TOK.imaginary64Literal: "imaginary64v",
+ TOK.imaginary80Literal: "imaginary80v",
+ TOK.charLiteral: "charv",
+ TOK.wcharLiteral: "wcharv",
+ TOK.dcharLiteral: "dcharv",
+ TOK.wchar_tLiteral: "wchar_tv",
+ TOK.compoundLiteral: "compoundliteral",
+
+ TOK.halt: "halt",
+ TOK.hexadecimalString: "xstring",
+
+ TOK.interval: "interval",
+ TOK.voidExpression: "voidexp",
+ TOK.cantExpression: "cantexp",
+ TOK.showCtfeContext : "showCtfeContext",
+
+ TOK.objcClassReference: "class",
+ TOK.vectorArray: "vectorarray",
+
+ // C only keywords
+ TOK.inline : "inline",
+ TOK.register : "register",
+ TOK.restrict : "restrict",
+ TOK.signed : "signed",
+ TOK.sizeof_ : "sizeof",
+ TOK.typedef_ : "typedef",
+ TOK.unsigned : "unsigned",
+ TOK.volatile : "volatile",
+ TOK._Alignas : "_Alignas",
+ TOK._Alignof : "_Alignof",
+ TOK._Atomic : "_Atomic",
+ TOK._Bool : "_Bool",
+ TOK._Complex : "_Complex",
+ TOK._Generic : "_Generic",
+ TOK._Imaginary: "_Imaginary",
+ TOK._Noreturn : "_Noreturn",
+ TOK._Static_assert : "_Static_assert",
+ TOK._Thread_local : "_Thread_local",
+
+ // C only extended keywords
+ TOK.__cdecl : "__cdecl",
+ TOK.__declspec : "__declspec",
+ TOK.__attribute__ : "__attribute__",
+ ];
+
+ static assert(() {
+ foreach (s; tochars)
+ assert(s.length);
+ return true;
+ }());
+
+nothrow:
+
+ int isKeyword() const
+ {
+ foreach (kw; keywords)
+ {
+ if (kw == value)
+ return 1;
+ }
+ return 0;
+ }
+
+ /****
+ * Set to contents of ptr[0..length]
+ * Params:
+ * ptr = pointer to string
+ * length = length of string
+ */
+ void setString(const(char)* ptr, size_t length)
+ {
+ auto s = cast(char*)mem.xmalloc_noscan(length + 1);
+ memcpy(s, ptr, length);
+ s[length] = 0;
+ ustring = s;
+ len = cast(uint)length;
+ postfix = 0;
+ }
+
+ /****
+ * Set to contents of buf
+ * Params:
+ * buf = string (not zero terminated)
+ */
+ void setString(const ref OutBuffer buf)
+ {
+ setString(cast(const(char)*)buf[].ptr, buf.length);
+ }
+
+ /****
+ * Set to empty string
+ */
+ void setString()
+ {
+ ustring = "";
+ len = 0;
+ postfix = 0;
+ }
+
+ extern (C++) const(char)* toChars() const
+ {
+ __gshared char[3 + 3 * floatvalue.sizeof + 1] buffer;
+ const(char)* p = &buffer[0];
+ switch (value)
+ {
+ case TOK.int32Literal:
+ sprintf(&buffer[0], "%d", cast(d_int32)intvalue);
+ break;
+ case TOK.uns32Literal:
+ case TOK.charLiteral:
+ case TOK.wcharLiteral:
+ case TOK.dcharLiteral:
+ case TOK.wchar_tLiteral:
+ sprintf(&buffer[0], "%uU", cast(d_uns32)unsvalue);
+ break;
+ case TOK.int64Literal:
+ sprintf(&buffer[0], "%lldL", cast(long)intvalue);
+ break;
+ case TOK.uns64Literal:
+ sprintf(&buffer[0], "%lluUL", cast(ulong)unsvalue);
+ break;
+ case TOK.float32Literal:
+ CTFloat.sprint(&buffer[0], 'g', floatvalue);
+ strcat(&buffer[0], "f");
+ break;
+ case TOK.float64Literal:
+ CTFloat.sprint(&buffer[0], 'g', floatvalue);
+ break;
+ case TOK.float80Literal:
+ CTFloat.sprint(&buffer[0], 'g', floatvalue);
+ strcat(&buffer[0], "L");
+ break;
+ case TOK.imaginary32Literal:
+ CTFloat.sprint(&buffer[0], 'g', floatvalue);
+ strcat(&buffer[0], "fi");
+ break;
+ case TOK.imaginary64Literal:
+ CTFloat.sprint(&buffer[0], 'g', floatvalue);
+ strcat(&buffer[0], "i");
+ break;
+ case TOK.imaginary80Literal:
+ CTFloat.sprint(&buffer[0], 'g', floatvalue);
+ strcat(&buffer[0], "Li");
+ break;
+ case TOK.string_:
+ {
+ OutBuffer buf;
+ buf.writeByte('"');
+ for (size_t i = 0; i < len;)
+ {
+ dchar c;
+ utf_decodeChar(ustring[0 .. len], i, c);
+ switch (c)
+ {
+ case 0:
+ break;
+ case '"':
+ case '\\':
+ buf.writeByte('\\');
+ goto default;
+ default:
+ if (c <= 0x7F)
+ {
+ if (isprint(c))
+ buf.writeByte(c);
+ else
+ buf.printf("\\x%02x", c);
+ }
+ else if (c <= 0xFFFF)
+ buf.printf("\\u%04x", c);
+ else
+ buf.printf("\\U%08x", c);
+ continue;
+ }
+ break;
+ }
+ buf.writeByte('"');
+ if (postfix)
+ buf.writeByte(postfix);
+ buf.writeByte(0);
+ p = buf.extractSlice().ptr;
+ }
+ break;
+ case TOK.hexadecimalString:
+ {
+ OutBuffer buf;
+ buf.writeByte('x');
+ buf.writeByte('"');
+ foreach (size_t i; 0 .. len)
+ {
+ if (i)
+ buf.writeByte(' ');
+ buf.printf("%02x", ustring[i]);
+ }
+ buf.writeByte('"');
+ if (postfix)
+ buf.writeByte(postfix);
+ buf.writeByte(0);
+ p = buf.extractSlice().ptr;
+ break;
+ }
+ case TOK.identifier:
+ case TOK.enum_:
+ case TOK.struct_:
+ case TOK.import_:
+ case TOK.wchar_:
+ case TOK.dchar_:
+ case TOK.bool_:
+ case TOK.char_:
+ case TOK.int8:
+ case TOK.uns8:
+ case TOK.int16:
+ case TOK.uns16:
+ case TOK.int32:
+ case TOK.uns32:
+ case TOK.int64:
+ case TOK.uns64:
+ case TOK.int128:
+ case TOK.uns128:
+ case TOK.float32:
+ case TOK.float64:
+ case TOK.float80:
+ case TOK.imaginary32:
+ case TOK.imaginary64:
+ case TOK.imaginary80:
+ case TOK.complex32:
+ case TOK.complex64:
+ case TOK.complex80:
+ case TOK.void_:
+ p = ident.toChars();
+ break;
+ default:
+ p = toChars(value);
+ break;
+ }
+ return p;
+ }
+
+ static const(char)* toChars(uint value)
+ {
+ return toString(value).ptr;
+ }
+
+ extern (D) static string toString(uint value) pure nothrow @nogc @safe
+ {
+ return tochars[value];
+ }
+}
+
diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h
index f79d841..0fd6634 100644
--- a/gcc/d/dmd/tokens.h
+++ b/gcc/d/dmd/tokens.h
@@ -10,6 +10,7 @@
#pragma once
+#include "root/dcompat.h"
#include "root/port.h"
#include "globals.h"
@@ -31,7 +32,8 @@ class Identifier;
? && ||
*/
-enum TOK
+typedef unsigned short TOK;
+enum
{
TOKreserved,
@@ -76,15 +78,10 @@ enum TOK
TOKindex, TOKis,
// 64
- // NCEG floating point compares
- // !<>= <> <>= !> !>= !< !<= !<>
- TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue,
-
-// 72
TOKshl, TOKshr,
TOKshlass, TOKshrass,
TOKushr, TOKushrass,
- TOKcat, TOKcatass, // ~ ~=
+ TOKcat, TOKcatass, TOKcatelemass, TOKcatdcharass, // ~ ~=
TOKadd, TOKmin, TOKaddass, TOKminass,
TOKmul, TOKdiv, TOKmod,
TOKmulass, TOKdivass, TOKmodass,
@@ -92,11 +89,11 @@ enum TOK
TOKandass, TOKorass, TOKxorass,
TOKassign, TOKnot, TOKtilde,
TOKplusplus, TOKminusminus, TOKconstruct, TOKblit,
- TOKdot, TOKarrow, TOKcomma,
+ TOKdot, TOKcomma,
TOKquestion, TOKandand, TOKoror,
TOKpreplusplus, TOKpreminusminus,
-// 111
+// 105
// Numeric literals
TOKint32v, TOKuns32v,
TOKint64v, TOKuns64v,
@@ -125,7 +122,7 @@ enum TOK
TOKcomplex32, TOKcomplex64, TOKcomplex80,
TOKchar, TOKwchar, TOKdchar, TOKbool,
-// 158
+// 152
// Aggregates
TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport,
TOKalias, TOKoverride, TOKdelegate, TOKfunction,
@@ -134,8 +131,9 @@ enum TOK
TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport,
TOKstatic, TOKfinal, TOKconst, TOKabstract,
TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy,
- TOKauto, TOKpackage, TOKmanifest, TOKimmutable,
+ TOKauto, TOKpackage, TOKimmutable,
+// 182
// Statements
TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch,
TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith,
@@ -144,6 +142,7 @@ enum TOK
TOKscope,
TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success,
+// 206
// Contracts
TOKinvariant,
@@ -155,6 +154,7 @@ enum TOK
TOKref,
TOKmacro,
+// 211
TOKparameters,
TOKtraits,
TOKoverloadset,
@@ -175,12 +175,42 @@ enum TOK
TOKvector,
TOKpound,
+// 230
TOKinterval,
TOKvoidexp,
TOKcantexp,
+ TOKshowctfecontext,
+ TOKobjc_class_reference,
TOKvectorarray,
+ TOKarrow,
+ TOKcolonColon,
+ TOKwchar_tLiteral,
+
+ TOKinline,
+ TOKregister,
+ TOKrestrict,
+ TOKsigned,
+ TOKsizeof_,
+ TOKtypedef_,
+ TOKunsigned,
+ TOKvolatile,
+ TOK_Alignas,
+ TOK_Alignof,
+ TOK_Atomic,
+ TOK_Bool,
+ TOK_Complex,
+ TOK_Generic,
+ TOK_Imaginary,
+ TOK_Noreturn,
+ TOK_Static_assert,
+ TOK_Thread_local,
+
+ TOK__cdecl,
+ TOK__declspec,
+ TOK__attribute__,
+
TOKMAX
};
@@ -196,15 +226,15 @@ struct Token
{
Token *next;
Loc loc;
- const utf8_t *ptr; // pointer to first character of this token within buffer
+ const utf8_t *ptr; // pointer to first character of this token within buffer
TOK value;
- const utf8_t *blockComment; // doc comment string prior to this token
- const utf8_t *lineComment; // doc comment for previous token
+ DString blockComment; // doc comment string prior to this token
+ DString lineComment; // doc comment for previous token
union
{
// Integers
- d_int64 int64value;
- d_uns64 uns64value;
+ sinteger_t intvalue;
+ uinteger_t unsvalue;
// Floats
real_t floatvalue;
@@ -218,16 +248,13 @@ struct Token
Identifier *ident;
};
- static const char *tochars[TOKMAX];
-
- static Token *freelist;
- static Token *alloc();
void free();
Token() : next(NULL) {}
int isKeyword();
const char *toChars() const;
- static const char *toChars(TOK);
+
+ static const char *toChars(unsigned value);
};
#if defined(__GNUC__)
diff --git a/gcc/d/dmd/traits.c b/gcc/d/dmd/traits.c
deleted file mode 100644
index 5a9f58b..0000000
--- a/gcc/d/dmd/traits.c
+++ /dev/null
@@ -1,1973 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/traits.c
- */
-
-#include "root/dsystem.h"
-#include "root/rmem.h"
-#include "root/aav.h"
-#include "root/checkedint.h"
-
-#include "errors.h"
-#include "mtype.h"
-#include "init.h"
-#include "expression.h"
-#include "template.h"
-#include "utf.h"
-#include "enum.h"
-#include "scope.h"
-#include "hdrgen.h"
-#include "statement.h"
-#include "declaration.h"
-#include "aggregate.h"
-#include "import.h"
-#include "id.h"
-#include "dsymbol.h"
-#include "module.h"
-#include "attrib.h"
-#include "parse.h"
-#include "root/speller.h"
-#include "target.h"
-
-typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s);
-int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL);
-void freeFieldinit(Scope *sc);
-Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-Package *resolveIsPackage(Dsymbol *sym);
-Expression *typeToExpression(Type *t);
-Type *decoToType(const char *deco);
-bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
-
-
-/************************************************
- * Delegate to be passed to overloadApply() that looks
- * for functions matching a trait.
- */
-
-struct Ptrait
-{
- Dsymbol *sym;
- Expression *e1;
- Expressions *exps; // collected results
- Identifier *ident; // which trait we're looking for
- bool includeTemplates;
- AA **funcTypeHash;
-};
-
-/* Compute the function signature and insert it in the
- * hashtable, if not present. This is needed so that
- * traits(getOverlods, F3, "visit") does not count `int visit(int)`
- * twice in the following example:
- *
- * =============================================
- * interface F1 { int visit(int);}
- * interface F2 { int visit(int); void visit(); }
- * interface F3 : F2, F1 {}
- *==============================================
- */
-static void insertInterfaceInheritedFunction(Ptrait *p, FuncDeclaration *fd, Expression *e)
-{
- Identifier *signature = Identifier::idPool(fd->type->toChars());
- //printf("%s - %s\n", fd->toChars, signature);
- if (!dmd_aaGetRvalue(*p->funcTypeHash, (void *)signature))
- {
- bool* value = (bool*) dmd_aaGet(p->funcTypeHash, (void *)signature);
- *value = true;
- p->exps->push(e);
- }
-}
-
-static int fptraits(void *param, Dsymbol *s)
-{
- Ptrait *p = (Ptrait *)param;
- if (p->includeTemplates)
- {
- p->exps->push(new DsymbolExp(Loc(),s, false));
- return 0;
- }
- FuncDeclaration *fd = s->isFuncDeclaration();
- if (!fd)
- return 0;
-
- if (p->ident == Id::getVirtualFunctions && !fd->isVirtual())
- return 0;
-
- if (p->ident == Id::getVirtualMethods && !fd->isVirtualMethod())
- return 0;
-
- Expression *e;
- FuncAliasDeclaration* ad = new FuncAliasDeclaration(fd->ident, fd, false);
- ad->protection = fd->protection;
- if (p->e1)
- e = new DotVarExp(Loc(), p->e1, ad, false);
- else
- e = new DsymbolExp(Loc(), ad, false);
- // if the parent is an interface declaration
- // we must check for functions with the same signature
- // in different inherited interfaces
- if (p->sym && p->sym->isInterfaceDeclaration())
- insertInterfaceInheritedFunction(p, fd, e);
- else
- p->exps->push(e);
- return 0;
-}
-
-/**
- * Collects all unit test functions from the given array of symbols.
- *
- * This is a helper function used by the implementation of __traits(getUnitTests).
- *
- * Input:
- * symbols array of symbols to collect the functions from
- * uniqueUnitTests an associative array (should actually be a set) to
- * keep track of already collected functions. We're
- * using an AA here to avoid doing a linear search of unitTests
- *
- * Output:
- * unitTests array of DsymbolExp's of the collected unit test functions
- * uniqueUnitTests updated with symbols from unitTests[ ]
- */
-static void collectUnitTests(Dsymbols *symbols, AA *uniqueUnitTests, Expressions *unitTests)
-{
- if (!symbols)
- return;
- for (size_t i = 0; i < symbols->length; i++)
- {
- Dsymbol *symbol = (*symbols)[i];
- UnitTestDeclaration *unitTest = symbol->isUnitTestDeclaration();
- if (unitTest)
- {
- if (!dmd_aaGetRvalue(uniqueUnitTests, (void *)unitTest))
- {
- FuncAliasDeclaration* ad = new FuncAliasDeclaration(unitTest->ident, unitTest, false);
- ad->protection = unitTest->protection;
- Expression* e = new DsymbolExp(Loc(), ad, false);
- unitTests->push(e);
- bool* value = (bool*) dmd_aaGet(&uniqueUnitTests, (void *)unitTest);
- *value = true;
- }
- }
- else
- {
- AttribDeclaration *attrDecl = symbol->isAttribDeclaration();
-
- if (attrDecl)
- {
- Dsymbols *decl = attrDecl->include(NULL);
- collectUnitTests(decl, uniqueUnitTests, unitTests);
- }
- }
- }
-}
-
-/***************************************************
- * Determine if type t is copyable.
- * Params:
- * t = type to check
- * Returns:
- * true if we can copy it
- */
-static bool isCopyable(Type *t)
-{
- //printf("isCopyable() %s\n", t->toChars());
- if (TypeStruct *ts = t->isTypeStruct())
- {
- if (ts->sym->postblit &&
- (ts->sym->postblit->storage_class & STCdisable))
- return false;
- }
- return true;
-}
-
-/************************ TraitsExp ************************************/
-
-static Expression *True(TraitsExp *e) { return new IntegerExp(e->loc, true, Type::tbool); }
-static Expression *False(TraitsExp *e) { return new IntegerExp(e->loc, false, Type::tbool); }
-
-/**************************************
- * Convert `Expression` or `Type` to corresponding `Dsymbol`,
- * additionally strip off expression contexts.
- *
- * Some symbol related `__traits` ignore arguments expression contexts.
- * For example:
- * struct S { void f() {} }
- * S s;
- * pragma(msg, __traits(isNested, s.f));
- * // s.f is DotVarExp, but __traits(isNested) needs a FuncDeclaration.
- *
- * This is used for that common `__traits` behavior.
- */
-static Dsymbol *getDsymbolWithoutExpCtx(RootObject *oarg)
-{
- if (Expression *e = isExpression(oarg))
- {
- if (e->op == TOKdotvar)
- return ((DotVarExp *)e)->var;
- if (e->op == TOKdottd)
- return ((DotTemplateExp *)e)->td;
- }
- return getDsymbol(oarg);
-}
-
-/**
- Gets the function type from a given AST node
- if the node is a function of some sort.
-
- Params:
- o = an AST node to check for a `TypeFunction`
- fdp = optional pointer to a function declararion, to be set
- if `o` is a function declarartion.
-
- Returns:
- a type node if `o` is a declaration of
- a delegate, function, function-pointer
- or a variable of the former. Otherwise, `null`.
-*/
-static TypeFunction *toTypeFunction(RootObject *o, FuncDeclaration **fdp = NULL)
-{
- Dsymbol *s = getDsymbolWithoutExpCtx(o);
- Type *t = isType(o);
- TypeFunction *tf = NULL;
-
- if (s)
- {
- FuncDeclaration *fd = s->isFuncDeclaration();
- if (fd)
- {
- t = fd->type;
- if (fdp)
- *fdp = fd;
- }
- else if (VarDeclaration *vd = s->isVarDeclaration())
- t = vd->type;
- }
- if (t)
- {
- if (t->ty == Tfunction)
- tf = (TypeFunction *)t;
- else if (t->ty == Tdelegate)
- tf = (TypeFunction *)t->nextOf();
- else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
- tf = (TypeFunction *)t->nextOf();
- }
-
- return tf;
-}
-
-static bool isTypeArithmetic(Type *t) { return t->isintegral() || t->isfloating(); }
-static bool isTypeFloating(Type *t) { return t->isfloating(); }
-static bool isTypeIntegral(Type *t) { return t->isintegral(); }
-static bool isTypeScalar(Type *t) { return t->isscalar(); }
-static bool isTypeUnsigned(Type *t) { return t->isunsigned(); }
-static bool isTypeAssociativeArray(Type *t) { return t->toBasetype()->ty == Taarray; }
-static bool isTypeStaticArray(Type *t) { return t->toBasetype()->ty == Tsarray; }
-static bool isTypeAbstractClass(Type *t) { return t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract(); }
-static bool isTypeFinalClass(Type *t) { return t->toBasetype()->ty == Tclass && (((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) != 0; }
-
-static Expression *isTypeX(TraitsExp *e, bool (*fp)(Type *t))
-{
- if (!e->args || !e->args->length)
- return False(e);
- for (size_t i = 0; i < e->args->length; i++)
- {
- Type *t = getType((*e->args)[i]);
- if (!t || !fp(t))
- return False(e);
- }
- return True(e);
-}
-
-static bool isDsymDeprecated(Dsymbol *s) { return s->isDeprecated(); }
-
-static int fpisTemplate(void *, Dsymbol *s)
-{
- if (s->isTemplateDeclaration())
- return 1;
-
- return 0;
-}
-
-bool isTemplate(Dsymbol *s)
-{
- if (!s->toAlias()->isOverloadable())
- return false;
-
- return overloadApply(s, NULL, &fpisTemplate) != 0;
-}
-
-static Expression *isDsymX(TraitsExp *e, bool (*fp)(Dsymbol *s))
-{
- if (!e->args || !e->args->length)
- return False(e);
- for (size_t i = 0; i < e->args->length; i++)
- {
- Dsymbol *s = getDsymbolWithoutExpCtx((*e->args)[i]);
- if (!s || !fp(s))
- return False(e);
- }
- return True(e);
-}
-
-static bool isFuncAbstractFunction(FuncDeclaration *f) { return f->isAbstract(); }
-static bool isFuncVirtualFunction(FuncDeclaration *f) { return f->isVirtual(); }
-static bool isFuncVirtualMethod(FuncDeclaration *f) { return f->isVirtualMethod(); }
-static bool isFuncFinalFunction(FuncDeclaration *f) { return f->isFinalFunc(); }
-static bool isFuncStaticFunction(FuncDeclaration *f) { return !f->needThis() && !f->isNested(); }
-static bool isFuncOverrideFunction(FuncDeclaration *f) { return f->isOverride(); }
-
-static Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f))
-{
- if (!e->args || !e->args->length)
- return False(e);
- for (size_t i = 0; i < e->args->length; i++)
- {
- Dsymbol *s = getDsymbolWithoutExpCtx((*e->args)[i]);
- if (!s)
- return False(e);
- FuncDeclaration *f = s->isFuncDeclaration();
- if (!f || !fp(f))
- return False(e);
- }
- return True(e);
-}
-
-static bool isDeclDisabled(Declaration *d) { return d->isDisabled(); }
-static bool isDeclFuture(Declaration *d) { return d->isFuture(); }
-static bool isDeclRef(Declaration *d) { return d->isRef(); }
-static bool isDeclOut(Declaration *d) { return d->isOut(); }
-static bool isDeclLazy(Declaration *d) { return (d->storage_class & STClazy) != 0; }
-
-static Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d))
-{
- if (!e->args || !e->args->length)
- return False(e);
- for (size_t i = 0; i < e->args->length; i++)
- {
- Dsymbol *s = getDsymbolWithoutExpCtx((*e->args)[i]);
- if (!s)
- return False(e);
- Declaration *d = s->isDeclaration();
- if (!d || !fp(d))
- return False(e);
- }
- return True(e);
-}
-
-static bool isPkgModule(Package *p) { return p->isModule() || p->isPackageMod(); }
-static bool isPkgPackage(Package *p) { return p->isModule() == NULL; }
-
-static Expression *isPkgX(TraitsExp *e, bool (*fp)(Package *p))
-{
- if (!e->args || !e->args->length)
- return False(e);
- for (size_t i = 0; i < e->args->length; i++)
- {
- Dsymbol *s = getDsymbolWithoutExpCtx((*e->args)[i]);
- if (!s)
- return False(e);
- Package *p = resolveIsPackage(s);
- if (!p || !fp(p))
- return False(e);
- }
- return True(e);
-}
-
-// callback for TypeFunction::attributesApply
-struct PushAttributes
-{
- Expressions *mods;
-
- static int fp(void *param, const char *str)
- {
- PushAttributes *p = (PushAttributes *)param;
- p->mods->push(new StringExp(Loc(), const_cast<char *>(str)));
- return 0;
- }
-};
-
-StringTable traitsStringTable;
-
-struct TraitsInitializer
-{
- TraitsInitializer();
-};
-
-static TraitsInitializer traitsinitializer;
-
-TraitsInitializer::TraitsInitializer()
-{
- const char* traits[] = {
- "isAbstractClass",
- "isArithmetic",
- "isAssociativeArray",
- "isDisabled",
- "isDeprecated",
- "isFuture",
- "isFinalClass",
- "isPOD",
- "isNested",
- "isFloating",
- "isIntegral",
- "isScalar",
- "isStaticArray",
- "isUnsigned",
- "isVirtualFunction",
- "isVirtualMethod",
- "isAbstractFunction",
- "isFinalFunction",
- "isOverrideFunction",
- "isStaticFunction",
- "isModule",
- "isPackage",
- "isRef",
- "isOut",
- "isLazy",
- "isReturnOnStack",
- "hasMember",
- "identifier",
- "getProtection",
- "getVisibility",
- "parent",
- "child",
- "getLinkage",
- "getMember",
- "getOverloads",
- "getVirtualFunctions",
- "getVirtualMethods",
- "classInstanceSize",
- "allMembers",
- "derivedMembers",
- "isSame",
- "compiles",
- "getAliasThis",
- "getAttributes",
- "getFunctionAttributes",
- "getFunctionVariadicStyle",
- "getParameterStorageClasses",
- "getUnitTests",
- "getVirtualIndex",
- "getPointerBitmap",
- "isZeroInit",
- "getTargetInfo",
- "getLocation",
- "hasPostblit",
- "isCopyable",
- NULL
- };
-
- traitsStringTable._init(56);
-
- for (size_t idx = 0;; idx++)
- {
- const char *s = traits[idx];
- if (!s) break;
- StringValue *sv = traitsStringTable.insert(s, strlen(s), const_cast<char *>(s));
- assert(sv);
- }
-}
-
-void *trait_search_fp(void *, const char *seed, int* cost)
-{
- //printf("trait_search_fp('%s')\n", seed);
- size_t len = strlen(seed);
- if (!len)
- return NULL;
-
- *cost = 0;
- StringValue *sv = traitsStringTable.lookup(seed, len);
- return sv ? (void*)sv->ptrvalue : NULL;
-}
-
-/**
- * get an array of size_t values that indicate possible pointer words in memory
- * if interpreted as the type given as argument
- * the first array element is the size of the type for independent interpretation
- * of the array
- * following elements bits represent one word (4/8 bytes depending on the target
- * architecture). If set the corresponding memory might contain a pointer/reference.
- *
- * [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...]
- */
-Expression *pointerBitmap(TraitsExp *e)
-{
- if (!e->args || e->args->length != 1)
- {
- error(e->loc, "a single type expected for trait pointerBitmap");
- return new ErrorExp();
- }
- Type *t = getType((*e->args)[0]);
- if (!t)
- {
- error(e->loc, "%s is not a type", (*e->args)[0]->toChars());
- return new ErrorExp();
- }
- d_uns64 sz;
- if (t->ty == Tclass && !((TypeClass*)t)->sym->isInterfaceDeclaration())
- sz = ((TypeClass*)t)->sym->AggregateDeclaration::size(e->loc);
- else
- sz = t->size(e->loc);
- if (sz == SIZE_INVALID)
- return new ErrorExp();
-
- const d_uns64 sz_size_t = Type::tsize_t->size(e->loc);
- if (sz > UINT64_MAX - sz_size_t)
- {
- error(e->loc, "size overflow for type %s", t->toChars());
- return new ErrorExp();
- }
-
- d_uns64 bitsPerWord = sz_size_t * 8;
- d_uns64 cntptr = (sz + sz_size_t - 1) / sz_size_t;
- d_uns64 cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord;
- Array<d_uns64> data;
- data.setDim((size_t)cntdata);
- data.zero();
-
- class PointerBitmapVisitor : public Visitor
- {
- public:
- PointerBitmapVisitor(Array<d_uns64>* _data, d_uns64 _sz_size_t)
- : data(_data), offset(0), sz_size_t(_sz_size_t), error(false)
- {}
-
- void setpointer(d_uns64 off)
- {
- d_uns64 ptroff = off / sz_size_t;
- (*data)[(size_t)(ptroff / (8 * sz_size_t))] |= 1LL << (ptroff % (8 * sz_size_t));
- }
- virtual void visit(Type *t)
- {
- Type *tb = t->toBasetype();
- if (tb != t)
- tb->accept(this);
- }
- virtual void visit(TypeError *t) { visit((Type *)t); }
- virtual void visit(TypeNext *) { assert(0); }
- virtual void visit(TypeBasic *t)
- {
- if (t->ty == Tvoid)
- setpointer(offset);
- }
- virtual void visit(TypeVector *) { }
- virtual void visit(TypeArray *) { assert(0); }
- virtual void visit(TypeSArray *t)
- {
- d_uns64 arrayoff = offset;
- d_uns64 nextsize = t->next->size();
- if (nextsize == SIZE_INVALID)
- error = true;
- d_uns64 dim = t->dim->toInteger();
- for (d_uns64 i = 0; i < dim; i++)
- {
- offset = arrayoff + i * nextsize;
- t->next->accept(this);
- }
- offset = arrayoff;
- }
- virtual void visit(TypeDArray *) { setpointer(offset + sz_size_t); } // dynamic array is {length,ptr}
- virtual void visit(TypeAArray *) { setpointer(offset); }
- virtual void visit(TypePointer *t)
- {
- if (t->nextOf()->ty != Tfunction) // don't mark function pointers
- setpointer(offset);
- }
- virtual void visit(TypeReference *) { setpointer(offset); }
- virtual void visit(TypeClass *) { setpointer(offset); }
- virtual void visit(TypeFunction *) { }
- virtual void visit(TypeDelegate *) { setpointer(offset); } // delegate is {context, function}
- virtual void visit(TypeQualified *) { assert(0); } // assume resolved
- virtual void visit(TypeIdentifier *) { assert(0); }
- virtual void visit(TypeInstance *) { assert(0); }
- virtual void visit(TypeTypeof *) { assert(0); }
- virtual void visit(TypeReturn *) { assert(0); }
- virtual void visit(TypeEnum *t) { visit((Type *)t); }
- virtual void visit(TypeTuple *t) { visit((Type *)t); }
- virtual void visit(TypeSlice *) { assert(0); }
- virtual void visit(TypeNull *) { } // always a null pointer
-
- virtual void visit(TypeStruct *t)
- {
- d_uns64 structoff = offset;
- for (size_t i = 0; i < t->sym->fields.length; i++)
- {
- VarDeclaration *v = t->sym->fields[i];
- offset = structoff + v->offset;
- if (v->type->ty == Tclass)
- setpointer(offset);
- else
- v->type->accept(this);
- }
- offset = structoff;
- }
-
- // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references
- void visitClass(TypeClass* t)
- {
- d_uns64 classoff = offset;
-
- // skip vtable-ptr and monitor
- if (t->sym->baseClass)
- visitClass((TypeClass*)t->sym->baseClass->type);
-
- for (size_t i = 0; i < t->sym->fields.length; i++)
- {
- VarDeclaration *v = t->sym->fields[i];
- offset = classoff + v->offset;
- v->type->accept(this);
- }
- offset = classoff;
- }
-
- Array<d_uns64>* data;
- d_uns64 offset;
- d_uns64 sz_size_t;
- bool error;
- };
-
- PointerBitmapVisitor pbv(&data, sz_size_t);
- if (t->ty == Tclass)
- pbv.visitClass((TypeClass*)t);
- else
- t->accept(&pbv);
- if (pbv.error)
- return new ErrorExp();
-
- Expressions* exps = new Expressions;
- exps->push(new IntegerExp(e->loc, sz, Type::tsize_t));
- for (d_uns64 i = 0; i < cntdata; i++)
- exps->push(new IntegerExp(e->loc, data[(size_t)i], Type::tsize_t));
-
- ArrayLiteralExp* ale = new ArrayLiteralExp(e->loc, Type::tsize_t->sarrayOf(cntdata + 1), exps);
- return ale;
-}
-
-static Expression *dimError(TraitsExp *e, int expected, int dim)
-{
- e->error("expected %d arguments for `%s` but had %d", expected, e->ident->toChars(), dim);
- return new ErrorExp();
-}
-
-Expression *semanticTraits(TraitsExp *e, Scope *sc)
-{
- if (e->ident != Id::compiles &&
- e->ident != Id::isSame &&
- e->ident != Id::identifier &&
- e->ident != Id::getProtection && e->ident != Id::getVisibility &&
- e->ident != Id::getAttributes)
- {
- // Pretend we're in a deprecated scope so that deprecation messages
- // aren't triggered when checking if a symbol is deprecated
- const StorageClass save = sc->stc;
- if (e->ident == Id::isDeprecated)
- sc->stc |= STCdeprecated;
- if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1))
- {
- sc->stc = save;
- return new ErrorExp();
- }
- sc->stc = save;
- }
- size_t dim = e->args ? e->args->length : 0;
-
- if (e->ident == Id::isArithmetic)
- {
- return isTypeX(e, &isTypeArithmetic);
- }
- else if (e->ident == Id::isFloating)
- {
- return isTypeX(e, &isTypeFloating);
- }
- else if (e->ident == Id::isIntegral)
- {
- return isTypeX(e, &isTypeIntegral);
- }
- else if (e->ident == Id::isScalar)
- {
- return isTypeX(e, &isTypeScalar);
- }
- else if (e->ident == Id::isUnsigned)
- {
- return isTypeX(e, &isTypeUnsigned);
- }
- else if (e->ident == Id::isAssociativeArray)
- {
- return isTypeX(e, &isTypeAssociativeArray);
- }
- else if (e->ident == Id::isDeprecated)
- {
- return isDsymX(e, &isDsymDeprecated);
- }
- else if (e->ident == Id::isFuture)
- {
- return isDeclX(e, &isDeclFuture);
- }
- else if (e->ident == Id::isStaticArray)
- {
- return isTypeX(e, &isTypeStaticArray);
- }
- else if (e->ident == Id::isAbstractClass)
- {
- return isTypeX(e, &isTypeAbstractClass);
- }
- else if (e->ident == Id::isFinalClass)
- {
- return isTypeX(e, &isTypeFinalClass);
- }
- else if (e->ident == Id::isTemplate)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isDsymX(e, &isTemplate);
- }
- else if (e->ident == Id::isPOD)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Type *t = isType(o);
- if (!t)
- {
- e->error("type expected as second argument of __traits %s instead of %s",
- e->ident->toChars(), o->toChars());
- return new ErrorExp();
- }
-
- Type *tb = t->baseElemOf();
- if (StructDeclaration *sd = (tb->ty == Tstruct) ? ((TypeStruct *)tb)->sym : NULL)
- {
- return (sd->isPOD()) ? True(e) : False(e);
- }
- return True(e);
- }
- else if (e->ident == Id::hasPostblit)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Type *t = isType(o);
- if (!t)
- {
- e->error("type expected as second argument of __traits %s instead of %s",
- e->ident->toChars(), o->toChars());
- return new ErrorExp();
- }
-
- Type *tb = t->baseElemOf();
- if (StructDeclaration *sd = (tb->ty == Tstruct) ? ((TypeStruct *)tb)->sym : NULL)
- {
- return sd->postblit ? True(e) : False(e);
- }
- return False(e);
- }
- else if (e->ident == Id::isCopyable)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Type *t = isType(o);
- if (!t)
- {
- e->error("type expected as second argument of __traits %s instead of %s",
- e->ident->toChars(), o->toChars());
- return new ErrorExp();
- }
-
- return isCopyable(t) ? True(e) : False(e);
- }
- else if (e->ident == Id::isNested)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Dsymbol *s = getDsymbolWithoutExpCtx(o);
- if (!s)
- {
- }
- else if (AggregateDeclaration *a = s->isAggregateDeclaration())
- {
- return a->isNested() ? True(e) : False(e);
- }
- else if (FuncDeclaration *f = s->isFuncDeclaration())
- {
- return f->isNested() ? True(e) : False(e);
- }
-
- e->error("aggregate or function expected instead of `%s`", o->toChars());
- return new ErrorExp();
- }
- else if (e->ident == Id::isDisabled)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isDeclX(e, &isDeclDisabled);
- }
- else if (e->ident == Id::isAbstractFunction)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isFuncX(e, &isFuncAbstractFunction);
- }
- else if (e->ident == Id::isVirtualFunction)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isFuncX(e, &isFuncVirtualFunction);
- }
- else if (e->ident == Id::isVirtualMethod)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isFuncX(e, &isFuncVirtualMethod);
- }
- else if (e->ident == Id::isFinalFunction)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isFuncX(e, &isFuncFinalFunction);
- }
- else if (e->ident == Id::isOverrideFunction)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isFuncX(e, &isFuncOverrideFunction);
- }
- else if (e->ident == Id::isStaticFunction)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isFuncX(e, &isFuncStaticFunction);
- }
- else if (e->ident == Id::isModule)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isPkgX(e, &isPkgModule);
- }
- else if (e->ident == Id::isPackage)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isPkgX(e, &isPkgPackage);
- }
- else if (e->ident == Id::isRef)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isDeclX(e, &isDeclRef);
- }
- else if (e->ident == Id::isOut)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isDeclX(e, &isDeclOut);
- }
- else if (e->ident == Id::isLazy)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- return isDeclX(e, &isDeclLazy);
- }
- else if (e->ident == Id::identifier)
- {
- // Get identifier for symbol as a string literal
- /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
- * a symbol should not be folded to a constant.
- * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
- */
- if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 2))
- return new ErrorExp();
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Identifier *id = NULL;
- if (Parameter *po = isParameter(o))
- {
- if (!po->ident)
- {
- e->error("argument `%s` has no identifier", po->type->toChars());
- return new ErrorExp();
- }
- id = po->ident;
- }
- else
- {
- Dsymbol *s = getDsymbolWithoutExpCtx(o);
- if (!s || !s->ident)
- {
- e->error("argument %s has no identifier", o->toChars());
- return new ErrorExp();
- }
- id = s->ident;
- }
-
- StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars()));
- return expressionSemantic(se, sc);
- }
- else if (e->ident == Id::getProtection || e->ident == Id::getVisibility)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- Scope *sc2 = sc->push();
- sc2->flags = sc->flags | SCOPEnoaccesscheck | SCOPEignoresymbolvisibility;
- bool ok = TemplateInstance::semanticTiargs(e->loc, sc2, e->args, 1);
- sc2->pop();
- if (!ok)
- return new ErrorExp();
-
- RootObject *o = (*e->args)[0];
- Dsymbol *s = getDsymbolWithoutExpCtx(o);
- if (!s)
- {
- if (!isError(o))
- e->error("argument %s has no protection", o->toChars());
- return new ErrorExp();
- }
- if (s->semanticRun == PASSinit)
- dsymbolSemantic(s, NULL);
-
- const char *protName = protectionToChars(s->prot().kind); // TODO: How about package(names)
- assert(protName);
- StringExp *se = new StringExp(e->loc, const_cast<char *>(protName));
- return expressionSemantic(se, sc);
- }
- else if (e->ident == Id::parent)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Dsymbol *s = getDsymbolWithoutExpCtx(o);
- if (s)
- {
- if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943
- s = fd->toAliasFunc();
- if (!s->isImport()) // Bugzilla 8922
- s = s->toParent();
- }
- if (!s || s->isImport())
- {
- e->error("argument %s has no parent", o->toChars());
- return new ErrorExp();
- }
-
- if (FuncDeclaration *f = s->isFuncDeclaration())
- {
- if (TemplateDeclaration *td = getFuncTemplateDecl(f))
- {
- if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
- td = td->overroot; // then get the start
- Expression *ex = new TemplateExp(e->loc, td, f);
- ex = expressionSemantic(ex, sc);
- return ex;
- }
-
- if (FuncLiteralDeclaration *fld = f->isFuncLiteralDeclaration())
- {
- // Directly translate to VarExp instead of FuncExp
- Expression *ex = new VarExp(e->loc, fld, true);
- return expressionSemantic(ex, sc);
- }
- }
-
- return resolve(e->loc, sc, s, false);
- }
- else if (e->ident == Id::child)
- {
- if (dim != 2)
- return dimError(e, 2, dim);
-
- Expression *ex;
- RootObject *op = (*e->args)[0];
- if (Dsymbol *symp = getDsymbol(op))
- ex = new DsymbolExp(e->loc, symp);
- else if (Expression *exp = isExpression(op))
- ex = exp;
- else
- {
- e->error("symbol or expression expected as first argument of __traits `child` instead of `%s`", op->toChars());
- return new ErrorExp();
- }
-
- ex = expressionSemantic(ex, sc);
- RootObject *oc = (*e->args)[1];
- Dsymbol *symc = getDsymbol(oc);
- if (!symc)
- {
- e->error("symbol expected as second argument of __traits `child` instead of `%s`", oc->toChars());
- return new ErrorExp();
- }
-
- if (Declaration *d = symc->isDeclaration())
- ex = new DotVarExp(e->loc, ex, d);
- else if (TemplateDeclaration *td = symc->isTemplateDeclaration())
- ex = new DotExp(e->loc, ex, new TemplateExp(e->loc, td));
- else if (ScopeDsymbol *ti = symc->isScopeDsymbol())
- ex = new DotExp(e->loc, ex, new ScopeExp(e->loc, ti));
- else
- assert(0);
-
- ex = expressionSemantic(ex, sc);
- return ex;
- }
- else if (e->ident == Id::toType)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- Expression *ex = isExpression((*e->args)[0]);
- if (!ex)
- {
- e->error("expression expected as second argument of __traits `%s`", e->ident->toChars());
- return new ErrorExp();
- }
- ex = ex->ctfeInterpret();
-
- StringExp *se = semanticString(sc, ex, "__traits(toType, string)");
- if (!se)
- {
- return new ErrorExp();
- }
- Type *t = decoToType(se->toUTF8(sc)->toPtr());
- if (!t)
- {
- e->error("cannot determine `%s`", e->toChars());
- return new ErrorExp();
- }
- ex = new TypeExp(e->loc, t);
- ex = expressionSemantic(ex, sc);
- return ex;
- }
- else if (e->ident == Id::hasMember ||
- e->ident == Id::getMember ||
- e->ident == Id::getOverloads ||
- e->ident == Id::getVirtualMethods ||
- e->ident == Id::getVirtualFunctions)
- {
- if (dim != 2 && !(dim == 3 && e->ident == Id::getOverloads))
- return dimError(e, 2, dim);
-
- RootObject *o = (*e->args)[0];
- Expression *ex = isExpression((*e->args)[1]);
- if (!ex)
- {
- e->error("expression expected as second argument of __traits %s", e->ident->toChars());
- return new ErrorExp();
- }
- ex = ex->ctfeInterpret();
-
- bool includeTemplates = false;
- if (dim == 3 && e->ident == Id::getOverloads)
- {
- Expression *b = isExpression((*e->args)[2]);
- b = b->ctfeInterpret();
- if (!b->type->equals(Type::tbool))
- {
- e->error("`bool` expected as third argument of `__traits(getOverloads)`, not `%s` of type `%s`", b->toChars(), b->type->toChars());
- return new ErrorExp();
- }
- includeTemplates = b->isBool(true);
- }
-
- StringExp *se = ex->toStringExp();
- if (!se || se->len == 0)
- {
- e->error("string expected as second argument of __traits %s instead of %s", e->ident->toChars(), ex->toChars());
- return new ErrorExp();
- }
- se = se->toUTF8(sc);
-
- if (se->sz != 1)
- {
- e->error("string must be chars");
- return new ErrorExp();
- }
- Identifier *id = Identifier::idPool((char *)se->string, se->len);
-
- /* Prefer dsymbol, because it might need some runtime contexts.
- */
- Dsymbol *sym = getDsymbol(o);
- if (sym)
- {
- if (e->ident == Id::hasMember)
- {
- if (sym->search(e->loc, id) != NULL)
- return True(e);
- }
- ex = new DsymbolExp(e->loc, sym);
- ex = new DotIdExp(e->loc, ex, id);
- }
- else if (Type *t = isType(o))
- ex = typeDotIdExp(e->loc, t, id);
- else if (Expression *ex2 = isExpression(o))
- ex = new DotIdExp(e->loc, ex2, id);
- else
- {
- e->error("invalid first argument");
- return new ErrorExp();
- }
-
- // ignore symbol visibility and disable access checks for these traits
- Scope *scx = sc->push();
- scx->flags |= SCOPEignoresymbolvisibility | SCOPEnoaccesscheck;
-
- if (e->ident == Id::hasMember)
- {
- /* Take any errors as meaning it wasn't found
- */
- ex = trySemantic(ex, scx);
- scx->pop();
- return ex ? True(e) : False(e);
- }
- else if (e->ident == Id::getMember)
- {
- if (ex->op == TOKdotid)
- // Prevent semantic() from replacing Symbol with its initializer
- ((DotIdExp *)ex)->wantsym = true;
- ex = expressionSemantic(ex, scx);
- scx->pop();
- return ex;
- }
- else if (e->ident == Id::getVirtualFunctions ||
- e->ident == Id::getVirtualMethods ||
- e->ident == Id::getOverloads)
- {
- unsigned errors = global.errors;
- Expression *eorig = ex;
- ex = expressionSemantic(ex, scx);
- if (errors < global.errors)
- e->error("%s cannot be resolved", eorig->toChars());
- //ex->print();
-
- /* Create tuple of functions of ex
- */
- Expressions *exps = new Expressions();
- Dsymbol *f;
- if (ex->op == TOKvar)
- {
- VarExp *ve = (VarExp *)ex;
- f = ve->var->isFuncDeclaration();
- ex = NULL;
- }
- else if (ex->op == TOKdotvar)
- {
- DotVarExp *dve = (DotVarExp *)ex;
- f = dve->var->isFuncDeclaration();
- if (dve->e1->op == TOKdottype || dve->e1->op == TOKthis)
- ex = NULL;
- else
- ex = dve->e1;
- }
- else if (ex->op == TOKtemplate)
- {
- TemplateExp *te = (TemplateExp *)ex;
- TemplateDeclaration *td = te->td;
- f = td;
- if (td && td->funcroot)
- f = td->funcroot;
- ex = NULL;
- }
- else
- f = NULL;
- Ptrait p;
- p.sym = sym;
- p.exps = exps;
- p.e1 = ex;
- p.ident = e->ident;
- p.includeTemplates = includeTemplates;
- AA *funcTypeHash = NULL;
- p.funcTypeHash = &funcTypeHash;
-
- InterfaceDeclaration *ifd = NULL;
- if (sym)
- ifd = sym->isInterfaceDeclaration();
- // If the symbol passed as a parameter is an
- // interface that inherits other interfaces
- if (ifd && ifd->interfaces.length)
- {
- // check the overloads of each inherited interface individually
- for (size_t i = 0; i < ifd->interfaces.length; i++)
- {
- BaseClass *bc = ifd->interfaces.ptr[i];
- if (Dsymbol *fd = bc->sym->search(e->loc, f->ident))
- overloadApply(fd, &p, &fptraits);
- }
- }
- else
- overloadApply(f, &p, &fptraits);
-
- ex = new TupleExp(e->loc, exps);
- ex = expressionSemantic(ex, scx);
- scx->pop();
- return ex;
- }
- else
- assert(0);
- }
- else if (e->ident == Id::classInstanceSize)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Dsymbol *s = getDsymbol(o);
- ClassDeclaration *cd = s ? s->isClassDeclaration() : NULL;
- if (!cd)
- {
- e->error("first argument is not a class");
- return new ErrorExp();
- }
- if (cd->sizeok != SIZEOKdone)
- {
- cd->size(cd->loc);
- }
- if (cd->sizeok != SIZEOKdone)
- {
- e->error("%s %s is forward referenced", cd->kind(), cd->toChars());
- return new ErrorExp();
- }
-
- return new IntegerExp(e->loc, cd->structsize, Type::tsize_t);
- }
- else if (e->ident == Id::getAliasThis)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Dsymbol *s = getDsymbol(o);
- AggregateDeclaration *ad = s ? s->isAggregateDeclaration() : NULL;
- if (!ad)
- {
- e->error("argument is not an aggregate type");
- return new ErrorExp();
- }
-
- Expressions *exps = new Expressions();
- if (ad->aliasthis)
- exps->push(new StringExp(e->loc, const_cast<char *>(ad->aliasthis->ident->toChars())));
- Expression *ex = new TupleExp(e->loc, exps);
- ex = expressionSemantic(ex, sc);
- return ex;
- }
- else if (e->ident == Id::getAttributes)
- {
- /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
- * a symbol should not be folded to a constant.
- * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
- */
- if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 3))
- return new ErrorExp();
-
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Parameter *po = isParameter(o);
- Dsymbol *s = getDsymbolWithoutExpCtx(o);
- UserAttributeDeclaration *udad = NULL;
- if (po)
- {
- udad = po->userAttribDecl;
- }
- else if (s)
- {
- if (Import *imp = s->isImport())
- {
- s = imp->mod;
- }
- //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->_scope);
- udad = s->userAttribDecl;
- }
- else
- {
- e->error("first argument is not a symbol");
- return new ErrorExp();
- }
-
- Expressions *exps = udad ? udad->getAttributes() : new Expressions();
- TupleExp *tup = new TupleExp(e->loc, exps);
- return expressionSemantic(tup, sc);
- }
- else if (e->ident == Id::getFunctionAttributes)
- {
- /* extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs.
- * https://dlang.org/spec/traits.html#getFunctionAttributes
- */
- if (dim != 1)
- return dimError(e, 1, dim);
-
- TypeFunction *tf = toTypeFunction((*e->args)[0]);
-
- if (!tf)
- {
- e->error("first argument is not a function");
- return new ErrorExp();
- }
-
- Expressions *mods = new Expressions();
- PushAttributes pa;
- pa.mods = mods;
- tf->modifiersApply(&pa, &PushAttributes::fp);
- tf->attributesApply(&pa, &PushAttributes::fp, TRUSTformatSystem);
-
- TupleExp *tup = new TupleExp(e->loc, mods);
- return expressionSemantic(tup, sc);
- }
- else if (e->ident == Id::isReturnOnStack)
- {
- /* Extract as a boolean if function return value is on the stack
- * https://dlang.org/spec/traits.html#isReturnOnStack
- */
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- FuncDeclaration *fd = NULL;
- TypeFunction *tf = toTypeFunction(o, &fd);
-
- if (!tf)
- {
- e->error("argument to `__traits(isReturnOnStack, %s)` is not a function", o->toChars());
- return new ErrorExp();
- }
-
- bool value = target.isReturnOnStack(tf, fd && fd->needThis());
- return new IntegerExp(e->loc, value, Type::tbool);
- }
- else if (e->ident == Id::getFunctionVariadicStyle)
- {
- /* Accept a symbol or a type. Returns one of the following:
- * "none" not a variadic function
- * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments`
- * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg
- * "typesafe" void typesafe(T[] ...)
- */
- // get symbol linkage as a string
- if (dim != 1)
- return dimError(e, 1, dim);
-
- LINK link;
- VarArg varargs;
- RootObject *o = (*e->args)[0];
- FuncDeclaration *fd = NULL;
- TypeFunction *tf = toTypeFunction(o, &fd);
-
- if (tf)
- {
- link = tf->linkage;
- varargs = tf->parameterList.varargs;
- }
- else
- {
- if (!fd)
- {
- e->error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o->toChars());
- return new ErrorExp();
- }
- link = fd->linkage;
- varargs = fd->getParameterList().varargs;
- }
- const char *style;
- switch (varargs)
- {
- case 0: style = "none"; break;
- case 1: style = (link == LINKd) ? "argptr"
- : "stdarg"; break;
- case 2: style = "typesafe"; break;
- default:
- assert(0);
- }
- StringExp *se = new StringExp(e->loc, const_cast<char*>(style));
- return expressionSemantic(se, sc);
- }
- else if (e->ident == Id::getParameterStorageClasses)
- {
- /* Accept a function symbol or a type, followed by a parameter index.
- * Returns a tuple of strings of the parameter's storage classes.
- */
- // get symbol linkage as a string
- if (dim != 2)
- return dimError(e, 2, dim);
-
- RootObject *o = (*e->args)[0];
- RootObject *o1 = (*e->args)[1];
-
- FuncDeclaration *fd = NULL;
- TypeFunction *tf = toTypeFunction(o, &fd);
-
- ParameterList fparams;
- if (tf)
- {
- fparams = tf->parameterList;
- }
- else
- {
- if (!fd)
- {
- e->error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function",
- o->toChars(), o1->toChars());
- return new ErrorExp();
- }
- fparams = fd->getParameterList();
- }
-
- StorageClass stc;
-
- // Set stc to storage class of the ith parameter
- Expression *ex = isExpression((*e->args)[1]);
- if (!ex)
- {
- e->error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`",
- o->toChars(), o1->toChars());
- return new ErrorExp();
- }
- ex = ex->ctfeInterpret();
- uinteger_t ii = ex->toUInteger();
- if (ii >= fparams.length())
- {
- e->error("parameter index must be in range 0..%u not %s", (unsigned)fparams.length(), ex->toChars());
- return new ErrorExp();
- }
-
- unsigned n = (unsigned)ii;
- Parameter *p = fparams[n];
- stc = p->storageClass;
-
- // This mirrors hdrgen.visit(Parameter p)
- if (p->type && p->type->mod & MODshared)
- stc &= ~STCshared;
-
- Expressions *exps = new Expressions;
-
- if (stc & STCauto)
- exps->push(new StringExp(e->loc, const_cast<char *>("auto")));
- if (stc & STCreturn)
- exps->push(new StringExp(e->loc, const_cast<char *>("return")));
-
- if (stc & STCout)
- exps->push(new StringExp(e->loc, const_cast<char *>("out")));
- else if (stc & STCref)
- exps->push(new StringExp(e->loc, const_cast<char *>("ref")));
- else if (stc & STCin)
- exps->push(new StringExp(e->loc, const_cast<char *>("in")));
- else if (stc & STClazy)
- exps->push(new StringExp(e->loc, const_cast<char *>("lazy")));
- else if (stc & STCalias)
- exps->push(new StringExp(e->loc, const_cast<char *>("alias")));
-
- if (stc & STCconst)
- exps->push(new StringExp(e->loc, const_cast<char *>("const")));
- if (stc & STCimmutable)
- exps->push(new StringExp(e->loc, const_cast<char *>("immutable")));
- if (stc & STCwild)
- exps->push(new StringExp(e->loc, const_cast<char *>("inout")));
- if (stc & STCshared)
- exps->push(new StringExp(e->loc, const_cast<char *>("shared")));
- if (stc & STCscope && !(stc & STCscopeinferred))
- exps->push(new StringExp(e->loc, const_cast<char *>("scope")));
-
- TupleExp *tup = new TupleExp(e->loc, exps);
- return expressionSemantic(tup, sc);
- }
- else if (e->ident == Id::getLinkage)
- {
- // get symbol linkage as a string
- if (dim != 1)
- return dimError(e, 1, dim);
-
- LINK link;
- RootObject *o = (*e->args)[0];
-
- TypeFunction *tf = toTypeFunction(o);
-
- if (tf)
- link = tf->linkage;
- else
- {
- Dsymbol *s = getDsymbol(o);
- Declaration *d = NULL;
- AggregateDeclaration *ad = NULL;
- if (!s || ((d = s->isDeclaration()) == NULL
- && (ad = s->isAggregateDeclaration()) == NULL))
- {
- e->error("argument to `__traits(getLinkage, %s)` is not a declaration", o->toChars());
- return new ErrorExp();
- }
- if (d != NULL)
- link = d->linkage;
- else
- {
- switch (ad->classKind)
- {
- case ClassKind::d:
- link = LINKd;
- break;
- case ClassKind::cpp:
- link = LINKcpp;
- break;
- case ClassKind::objc:
- link = LINKobjc;
- break;
- default:
- assert(0);
- }
- }
- }
- const char *linkage = linkageToChars(link);
- StringExp *se = new StringExp(e->loc, const_cast<char *>(linkage));
- return expressionSemantic(se, sc);
- }
- else if (e->ident == Id::allMembers ||
- e->ident == Id::derivedMembers)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Dsymbol *s = getDsymbol(o);
- if (!s)
- {
- e->error("argument has no members");
- return new ErrorExp();
- }
- if (Import *imp = s->isImport())
- {
- // Bugzilla 9692
- s = imp->mod;
- }
-
- // https://issues.dlang.org/show_bug.cgi?id=16044
- if (Package *p = s->isPackage())
- {
- if (Module *pm = p->isPackageMod())
- s = pm;
- }
-
- ScopeDsymbol *sds = s->isScopeDsymbol();
- if (!sds || sds->isTemplateDeclaration())
- {
- e->error("%s %s has no members", s->kind(), s->toChars());
- return new ErrorExp();
- }
-
- // use a struct as local function
- struct PushIdentsDg
- {
- ScopeDsymbol *sds;
- Identifiers *idents;
-
- static int dg(void *ctx, size_t, Dsymbol *sm)
- {
- if (!sm)
- return 1;
-
- // skip local symbols, such as static foreach loop variables
- if (Declaration *decl = sm->isDeclaration())
- {
- if (decl->storage_class & STClocal)
- {
- return 0;
- }
- }
-
- // https://issues.dlang.org/show_bug.cgi?id=20915
- // skip version and debug identifiers
- if (sm->isVersionSymbol() || sm->isDebugSymbol())
- return 0;
-
- //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
- if (sm->ident)
- {
- // https://issues.dlang.org/show_bug.cgi?id=10096
- // https://issues.dlang.org/show_bug.cgi?id=10100
- // Skip over internal members in __traits(allMembers)
- if ((sm->isCtorDeclaration() && sm->ident != Id::ctor) ||
- (sm->isDtorDeclaration() && sm->ident != Id::dtor) ||
- (sm->isPostBlitDeclaration() && sm->ident != Id::postblit) ||
- sm->isInvariantDeclaration() ||
- sm->isUnitTestDeclaration())
- {
- return 0;
- }
-
- if (sm->ident == Id::empty)
- {
- return 0;
- }
- if (sm->isTypeInfoDeclaration()) // Bugzilla 15177
- return 0;
- PushIdentsDg *pid = (PushIdentsDg *)ctx;
- if (!pid->sds->isModule() && sm->isImport()) // Bugzilla 17057
- return 0;
-
- //printf("\t%s\n", sm->ident->toChars());
- Identifiers *idents = pid->idents;
-
- /* Skip if already present in idents[]
- */
- for (size_t j = 0; j < idents->length; j++)
- {
- Identifier *id = (*idents)[j];
- if (id == sm->ident)
- return 0;
- }
-
- idents->push(sm->ident);
- }
- else
- {
- EnumDeclaration *ed = sm->isEnumDeclaration();
- if (ed)
- {
- ScopeDsymbol_foreach(NULL, ed->members, &PushIdentsDg::dg, ctx);
- }
- }
- return 0;
- }
- };
-
- Identifiers *idents = new Identifiers;
- PushIdentsDg ctx;
- ctx.sds = sds;
- ctx.idents = idents;
- ScopeDsymbol_foreach(sc, sds->members, &PushIdentsDg::dg, &ctx);
- ClassDeclaration *cd = sds->isClassDeclaration();
- if (cd && e->ident == Id::allMembers)
- {
- if (cd->semanticRun < PASSsemanticdone)
- dsymbolSemantic(cd, NULL); // Bugzilla 13668: Try to resolve forward reference
-
- struct PushBaseMembers
- {
- static void dg(ClassDeclaration *cd, PushIdentsDg *ctx)
- {
- for (size_t i = 0; i < cd->baseclasses->length; i++)
- {
- ClassDeclaration *cb = (*cd->baseclasses)[i]->sym;
- assert(cb);
- ScopeDsymbol_foreach(NULL, cb->members, &PushIdentsDg::dg, ctx);
- if (cb->baseclasses->length)
- dg(cb, ctx);
- }
- }
- };
- PushBaseMembers::dg(cd, &ctx);
- }
-
- // Turn Identifiers into StringExps reusing the allocated array
- assert(sizeof(Expressions) == sizeof(Identifiers));
- Expressions *exps = (Expressions *)idents;
- for (size_t i = 0; i < idents->length; i++)
- {
- Identifier *id = (*idents)[i];
- StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars()));
- (*exps)[i] = se;
- }
-
- /* Making this a tuple is more flexible, as it can be statically unrolled.
- * To make an array literal, enclose __traits in [ ]:
- * [ __traits(allMembers, ...) ]
- */
- Expression *ex = new TupleExp(e->loc, exps);
- ex = expressionSemantic(ex, sc);
- return ex;
- }
- else if (e->ident == Id::compiles)
- {
- /* Determine if all the objects - types, expressions, or symbols -
- * compile without error
- */
- if (!dim)
- return False(e);
-
- for (size_t i = 0; i < dim; i++)
- {
- unsigned errors = global.startGagging();
- Scope *sc2 = sc->push();
- sc2->tinst = NULL;
- sc2->minst = NULL;
- sc2->flags = (sc->flags & ~(SCOPEctfe | SCOPEcondition)) | SCOPEcompile | SCOPEfullinst;
- bool err = false;
-
- RootObject *o = (*e->args)[i];
- Type *t = isType(o);
- while (t)
- {
- if (TypeMixin *tm = t->isTypeMixin())
- {
- /* The mixin string could be a type or an expression.
- * Have to try compiling it to see.
- */
- OutBuffer buf;
- if (expressionsToString(buf, sc, tm->exps))
- {
- err = true;
- break;
- }
- const size_t len = buf.length();
- const char *str = buf.extractChars();
- Parser p(e->loc, sc->_module, (const utf8_t *)str, len, false);
- p.nextToken();
- //printf("p.loc.linnum = %d\n", p.loc.linnum);
-
- o = p.parseTypeOrAssignExp(TOKeof);
- if (p.errors || p.token.value != TOKeof)
- {
- err = true;
- break;
- }
- t = isType(o);
- }
- else
- break;
- }
-
- if (!err)
- {
- Expression *ex = t ? typeToExpression(t) : isExpression(o);
- if (!ex && t)
- {
- Dsymbol *s;
- t->resolve(e->loc, sc2, &ex, &t, &s);
- if (t)
- {
- typeSemantic(t, e->loc, sc2);
- if (t->ty == Terror)
- err = true;
- }
- else if (s && s->errors)
- err = true;
- }
- if (ex)
- {
- ex = expressionSemantic(ex, sc2);
- ex = resolvePropertiesOnly(sc2, ex);
- ex = ex->optimize(WANTvalue);
- if (sc2->func && sc2->func->type->ty == Tfunction)
- {
- TypeFunction *tf = (TypeFunction *)sc2->func->type;
- canThrow(ex, sc2->func, tf->isnothrow);
- }
- ex = checkGC(sc2, ex);
- if (ex->op == TOKerror)
- err = true;
- }
- }
-
- // Carefully detach the scope from the parent and throw it away as
- // we only need it to evaluate the expression
- // https://issues.dlang.org/show_bug.cgi?id=15428
- freeFieldinit(sc2);
- sc2->enclosing = NULL;
- sc2->pop();
-
- if (global.endGagging(errors) || err)
- {
- return False(e);
- }
- }
- return True(e);
- }
- else if (e->ident == Id::isSame)
- {
- /* Determine if two symbols are the same
- */
- if (dim != 2)
- return dimError(e, 2, dim);
-
- if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 0))
- return new ErrorExp();
-
- RootObject *o1 = (*e->args)[0];
- RootObject *o2 = (*e->args)[1];
-
- // issue 12001, allow isSame, <BasicType>, <BasicType>
- Type *t1 = isType(o1);
- Type *t2 = isType(o2);
- if (t1 && t2 && t1->equals(t2))
- return True(e);
-
- Dsymbol *s1 = getDsymbol(o1);
- Dsymbol *s2 = getDsymbol(o2);
- //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars());
- if (!s1 && !s2)
- {
- Expression *ea1 = isExpression(o1);
- Expression *ea2 = isExpression(o2);
- if (ea1 && ea2)
- {
- if (ea1->equals(ea2))
- return True(e);
- }
- }
- if (!s1 || !s2)
- return False(e);
- s1 = s1->toAlias();
- s2 = s2->toAlias();
-
- if (s1->isFuncAliasDeclaration())
- s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc();
- if (s2->isFuncAliasDeclaration())
- s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc();
-
- return (s1 == s2) ? True(e) : False(e);
- }
- else if (e->ident == Id::getUnitTests)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Dsymbol *s = getDsymbolWithoutExpCtx(o);
- if (!s)
- {
- e->error("argument %s to __traits(getUnitTests) must be a module or aggregate",
- o->toChars());
- return new ErrorExp();
- }
- if (Import *imp = s->isImport()) // Bugzilla 10990
- s = imp->mod;
-
- ScopeDsymbol* sds = s->isScopeDsymbol();
- if (!sds)
- {
- e->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s",
- s->toChars(), s->kind());
- return new ErrorExp();
- }
-
- Expressions *exps = new Expressions();
- if (global.params.useUnitTests)
- {
- // Should actually be a set
- AA* uniqueUnitTests = NULL;
- collectUnitTests(sds->members, uniqueUnitTests, exps);
- }
- TupleExp *te= new TupleExp(e->loc, exps);
- return expressionSemantic(te, sc);
- }
- else if (e->ident == Id::getVirtualIndex)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Dsymbol *s = getDsymbolWithoutExpCtx(o);
-
- FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
- if (!fd)
- {
- e->error("first argument to __traits(getVirtualIndex) must be a function");
- return new ErrorExp();
- }
-
- fd = fd->toAliasFunc(); // Neccessary to support multiple overloads.
- return new IntegerExp(e->loc, fd->vtblIndex, Type::tptrdiff_t);
- }
- else if (e->ident == Id::getPointerBitmap)
- {
- return pointerBitmap(e);
- }
- else if (e->ident == Id::isZeroInit)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- RootObject *o = (*e->args)[0];
- Type *t = isType(o);
- if (!t)
- {
- e->error("type expected as second argument of __traits `%s` instead of `%s`",
- e->ident->toChars(), o->toChars());
- return new ErrorExp();
- }
-
- Type *tb = t->baseElemOf();
- return tb->isZeroInit(e->loc) ? True(e) : False(e);
- }
- else if (e->ident == Id::getTargetInfo)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
-
- Expression *ex = isExpression((*e->args)[0]);
- StringExp *se = ex ? ex->ctfeInterpret()->toStringExp() : NULL;
- if (!ex || !se || se->len == 0)
- {
- e->error("string expected as argument of __traits `%s` instead of `%s`", e->ident->toChars(), ex->toChars());
- return new ErrorExp();
- }
- se = se->toUTF8(sc);
-
- Expression *r = target.getTargetInfo(se->toPtr(), e->loc);
- if (!r)
- {
- e->error("`getTargetInfo` key `\"%s\"` not supported by this implementation", se->toPtr());
- return new ErrorExp();
- }
- return expressionSemantic(r, sc);
- }
- else if (e->ident == Id::getLocation)
- {
- if (dim != 1)
- return dimError(e, 1, dim);
- RootObject *arg0 = (*e->args)[0];
- Dsymbol *s = getDsymbolWithoutExpCtx(arg0);
- if (!s || !s->loc.filename)
- {
- e->error("can only get the location of a symbol, not `%s`", arg0->toChars());
- return new ErrorExp();
- }
-
- const FuncDeclaration *fd = s->isFuncDeclaration();
- if (fd && fd->overnext)
- {
- e->error("cannot get location of an overload set, "
- "use `__traits(getOverloads, ..., \"%s\"%s)[N]` "
- "to get the Nth overload",
- arg0->toChars(), "");
- return new ErrorExp();
- }
-
- Expressions *exps = new Expressions();
- exps->setDim(3);
- (*exps)[0] = new StringExp(e->loc, const_cast<char *>(s->loc.filename), strlen(s->loc.filename));
- (*exps)[1] = new IntegerExp(e->loc, s->loc.linnum, Type::tint32);
- (*exps)[2] = new IntegerExp(e->loc, s->loc.charnum, Type::tint32);
- TupleExp *tup = new TupleExp(e->loc, exps);
- return expressionSemantic(tup, sc);
- }
-
- if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars))
- e->error("unrecognized trait `%s`, did you mean `%s`?", e->ident->toChars(), sub);
- else
- e->error("unrecognized trait `%s`", e->ident->toChars());
- return new ErrorExp();
-
- e->error("wrong number of arguments %d", (int)dim);
- return new ErrorExp();
-}
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
new file mode 100644
index 0000000..8f968ed
--- /dev/null
+++ b/gcc/d/dmd/traits.d
@@ -0,0 +1,2202 @@
+/**
+ * Handle introspection functionality of the `__traits()` construct.
+ *
+ * Specification: $(LINK2 https://dlang.org/spec/traits.html, Traits)
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/traits.d, _traits.d)
+ * Documentation: https://dlang.org/phobos/dmd_traits.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/traits.d
+ */
+
+module dmd.traits;
+
+import core.stdc.stdio;
+
+import dmd.aggregate;
+import dmd.arraytypes;
+import dmd.astcodegen;
+import dmd.astenums;
+import dmd.attrib;
+import dmd.canthrow;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.dimport;
+import dmd.dmangle;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.mtype;
+import dmd.nogc;
+import dmd.parse;
+import dmd.root.array;
+import dmd.root.speller;
+import dmd.root.stringtable;
+import dmd.target;
+import dmd.tokens;
+import dmd.typesem;
+import dmd.visitor;
+import dmd.root.rootobject;
+import dmd.root.outbuffer;
+import dmd.root.string;
+
+enum LOGSEMANTIC = false;
+
+/************************ TraitsExp ************************************/
+
+/**************************************
+ * Convert `Expression` or `Type` to corresponding `Dsymbol`, additionally
+ * stripping off expression contexts.
+ *
+ * Some symbol related `__traits` ignore arguments expression contexts.
+ * For example:
+ * ----
+ * struct S { void f() {} }
+ * S s;
+ * pragma(msg, __traits(isNested, s.f));
+ * // s.f is `DotVarExp`, but `__traits(isNested)`` needs a `FuncDeclaration`.
+ * ----
+ *
+ * This is used for that common `__traits` behavior.
+ *
+ * Input:
+ * oarg object to get the symbol for
+ * Returns:
+ * Dsymbol the corresponding symbol for oarg
+ */
+private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg)
+{
+ if (auto e = isExpression(oarg))
+ {
+ if (e.op == TOK.dotVariable)
+ return (cast(DotVarExp)e).var;
+ if (e.op == TOK.dotTemplateDeclaration)
+ return (cast(DotTemplateExp)e).td;
+ }
+ return getDsymbol(oarg);
+}
+
+private const StringTable!bool traitsStringTable;
+
+shared static this()
+{
+ static immutable string[] names =
+ [
+ "isAbstractClass",
+ "isArithmetic",
+ "isAssociativeArray",
+ "isDisabled",
+ "isDeprecated",
+ "isFuture",
+ "isFinalClass",
+ "isPOD",
+ "isNested",
+ "isFloating",
+ "isIntegral",
+ "isScalar",
+ "isStaticArray",
+ "isUnsigned",
+ "isVirtualFunction",
+ "isVirtualMethod",
+ "isAbstractFunction",
+ "isFinalFunction",
+ "isOverrideFunction",
+ "isStaticFunction",
+ "isModule",
+ "isPackage",
+ "isRef",
+ "isOut",
+ "isLazy",
+ "isReturnOnStack",
+ "hasMember",
+ "identifier",
+ "getProtection",
+ "getVisibility",
+ "parent",
+ "child",
+ "getLinkage",
+ "getMember",
+ "getOverloads",
+ "getVirtualFunctions",
+ "getVirtualMethods",
+ "classInstanceSize",
+ "allMembers",
+ "derivedMembers",
+ "isSame",
+ "compiles",
+ "getAliasThis",
+ "getAttributes",
+ "getFunctionAttributes",
+ "getFunctionVariadicStyle",
+ "getParameterStorageClasses",
+ "getUnitTests",
+ "getVirtualIndex",
+ "getPointerBitmap",
+ "isZeroInit",
+ "getTargetInfo",
+ "getLocation",
+ "hasPostblit",
+ "hasCopyConstructor",
+ "isCopyable",
+ ];
+
+ StringTable!(bool)* stringTable = cast(StringTable!(bool)*) &traitsStringTable;
+ stringTable._init(names.length);
+
+ foreach (s; names)
+ {
+ auto sv = stringTable.insert(s, true);
+ assert(sv);
+ }
+}
+
+/**
+ * get an array of size_t values that indicate possible pointer words in memory
+ * if interpreted as the type given as argument
+ * Returns: the size of the type in bytes, d_uns64.max on error
+ */
+d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data)
+{
+ d_uns64 sz;
+ if (t.ty == Tclass && !(cast(TypeClass)t).sym.isInterfaceDeclaration())
+ sz = (cast(TypeClass)t).sym.AggregateDeclaration.size(loc);
+ else
+ sz = t.size(loc);
+ if (sz == SIZE_INVALID)
+ return d_uns64.max;
+
+ const sz_size_t = Type.tsize_t.size(loc);
+ if (sz > sz.max - sz_size_t)
+ {
+ error(loc, "size overflow for type `%s`", t.toChars());
+ return d_uns64.max;
+ }
+
+ d_uns64 bitsPerWord = sz_size_t * 8;
+ d_uns64 cntptr = (sz + sz_size_t - 1) / sz_size_t;
+ d_uns64 cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord;
+
+ data.setDim(cast(size_t)cntdata);
+ data.zero();
+
+ extern (C++) final class PointerBitmapVisitor : Visitor
+ {
+ alias visit = Visitor.visit;
+ public:
+ extern (D) this(Array!(d_uns64)* _data, d_uns64 _sz_size_t)
+ {
+ this.data = _data;
+ this.sz_size_t = _sz_size_t;
+ }
+
+ void setpointer(d_uns64 off)
+ {
+ d_uns64 ptroff = off / sz_size_t;
+ (*data)[cast(size_t)(ptroff / (8 * sz_size_t))] |= 1L << (ptroff % (8 * sz_size_t));
+ }
+
+ override void visit(Type t)
+ {
+ Type tb = t.toBasetype();
+ if (tb != t)
+ tb.accept(this);
+ }
+
+ override void visit(TypeError t)
+ {
+ visit(cast(Type)t);
+ }
+
+ override void visit(TypeNext t)
+ {
+ assert(0);
+ }
+
+ override void visit(TypeBasic t)
+ {
+ if (t.ty == Tvoid)
+ setpointer(offset);
+ }
+
+ override void visit(TypeVector t)
+ {
+ }
+
+ override void visit(TypeArray t)
+ {
+ assert(0);
+ }
+
+ override void visit(TypeSArray t)
+ {
+ d_uns64 arrayoff = offset;
+ d_uns64 nextsize = t.next.size();
+ if (nextsize == SIZE_INVALID)
+ error = true;
+ d_uns64 dim = t.dim.toInteger();
+ for (d_uns64 i = 0; i < dim; i++)
+ {
+ offset = arrayoff + i * nextsize;
+ t.next.accept(this);
+ }
+ offset = arrayoff;
+ }
+
+ override void visit(TypeDArray t)
+ {
+ setpointer(offset + sz_size_t);
+ }
+
+ // dynamic array is {length,ptr}
+ override void visit(TypeAArray t)
+ {
+ setpointer(offset);
+ }
+
+ override void visit(TypePointer t)
+ {
+ if (t.nextOf().ty != Tfunction) // don't mark function pointers
+ setpointer(offset);
+ }
+
+ override void visit(TypeReference t)
+ {
+ setpointer(offset);
+ }
+
+ override void visit(TypeClass t)
+ {
+ setpointer(offset);
+ }
+
+ override void visit(TypeFunction t)
+ {
+ }
+
+ override void visit(TypeDelegate t)
+ {
+ setpointer(offset);
+ }
+
+ // delegate is {context, function}
+ override void visit(TypeQualified t)
+ {
+ assert(0);
+ }
+
+ // assume resolved
+ override void visit(TypeIdentifier t)
+ {
+ assert(0);
+ }
+
+ override void visit(TypeInstance t)
+ {
+ assert(0);
+ }
+
+ override void visit(TypeTypeof t)
+ {
+ assert(0);
+ }
+
+ override void visit(TypeReturn t)
+ {
+ assert(0);
+ }
+
+ override void visit(TypeEnum t)
+ {
+ visit(cast(Type)t);
+ }
+
+ override void visit(TypeTuple t)
+ {
+ visit(cast(Type)t);
+ }
+
+ override void visit(TypeSlice t)
+ {
+ assert(0);
+ }
+
+ override void visit(TypeNull t)
+ {
+ // always a null pointer
+ }
+
+ override void visit(TypeStruct t)
+ {
+ d_uns64 structoff = offset;
+ foreach (v; t.sym.fields)
+ {
+ offset = structoff + v.offset;
+ if (v.type.ty == Tclass)
+ setpointer(offset);
+ else
+ v.type.accept(this);
+ }
+ offset = structoff;
+ }
+
+ // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references
+ void visitClass(TypeClass t)
+ {
+ d_uns64 classoff = offset;
+ // skip vtable-ptr and monitor
+ if (t.sym.baseClass)
+ visitClass(cast(TypeClass)t.sym.baseClass.type);
+ foreach (v; t.sym.fields)
+ {
+ offset = classoff + v.offset;
+ v.type.accept(this);
+ }
+ offset = classoff;
+ }
+
+ Array!(d_uns64)* data;
+ d_uns64 offset;
+ d_uns64 sz_size_t;
+ bool error;
+ }
+
+ scope PointerBitmapVisitor pbv = new PointerBitmapVisitor(data, sz_size_t);
+ if (t.ty == Tclass)
+ pbv.visitClass(cast(TypeClass)t);
+ else
+ t.accept(pbv);
+ return pbv.error ? d_uns64.max : sz;
+}
+
+/**
+ * get an array of size_t values that indicate possible pointer words in memory
+ * if interpreted as the type given as argument
+ * the first array element is the size of the type for independent interpretation
+ * of the array
+ * following elements bits represent one word (4/8 bytes depending on the target
+ * architecture). If set the corresponding memory might contain a pointer/reference.
+ *
+ * Returns: [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...]
+ */
+private Expression pointerBitmap(TraitsExp e)
+{
+ if (!e.args || e.args.dim != 1)
+ {
+ error(e.loc, "a single type expected for trait pointerBitmap");
+ return ErrorExp.get();
+ }
+
+ Type t = getType((*e.args)[0]);
+ if (!t)
+ {
+ error(e.loc, "`%s` is not a type", (*e.args)[0].toChars());
+ return ErrorExp.get();
+ }
+
+ Array!(d_uns64) data;
+ d_uns64 sz = getTypePointerBitmap(e.loc, t, &data);
+ if (sz == d_uns64.max)
+ return ErrorExp.get();
+
+ auto exps = new Expressions(data.dim + 1);
+ (*exps)[0] = new IntegerExp(e.loc, sz, Type.tsize_t);
+ foreach (size_t i; 1 .. exps.dim)
+ (*exps)[i] = new IntegerExp(e.loc, data[cast(size_t) (i - 1)], Type.tsize_t);
+
+ auto ale = new ArrayLiteralExp(e.loc, Type.tsize_t.sarrayOf(data.dim + 1), exps);
+ return ale;
+}
+
+Expression semanticTraits(TraitsExp e, Scope* sc)
+{
+ static if (LOGSEMANTIC)
+ {
+ printf("TraitsExp::semantic() %s\n", e.toChars());
+ }
+
+ if (e.ident != Id.compiles &&
+ e.ident != Id.isSame &&
+ e.ident != Id.identifier &&
+ e.ident != Id.getProtection && e.ident != Id.getVisibility &&
+ e.ident != Id.getAttributes)
+ {
+ // Pretend we're in a deprecated scope so that deprecation messages
+ // aren't triggered when checking if a symbol is deprecated
+ const save = sc.stc;
+ if (e.ident == Id.isDeprecated)
+ sc.stc |= STC.deprecated_;
+ if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 1))
+ {
+ sc.stc = save;
+ return ErrorExp.get();
+ }
+ sc.stc = save;
+ }
+ size_t dim = e.args ? e.args.dim : 0;
+
+ Expression dimError(int expected)
+ {
+ e.error("expected %d arguments for `%s` but had %d", expected, e.ident.toChars(), cast(int)dim);
+ return ErrorExp.get();
+ }
+
+ static IntegerExp True()
+ {
+ return IntegerExp.createBool(true);
+ }
+
+ static IntegerExp False()
+ {
+ return IntegerExp.createBool(false);
+ }
+
+ /********
+ * Gets the function type from a given AST node
+ * if the node is a function of some sort.
+ * Params:
+ * o = an AST node to check for a `TypeFunction`
+ * fdp = if `o` is a FuncDeclaration then fdp is set to that, otherwise `null`
+ * Returns:
+ * a type node if `o` is a declaration of
+ * a delegate, function, function-pointer or a variable of the former.
+ * Otherwise, `null`.
+ */
+ static TypeFunction toTypeFunction(RootObject o, out FuncDeclaration fdp)
+ {
+ Type t;
+ if (auto s = getDsymbolWithoutExpCtx(o))
+ {
+ if (auto fd = s.isFuncDeclaration())
+ {
+ t = fd.type;
+ fdp = fd;
+ }
+ else if (auto vd = s.isVarDeclaration())
+ t = vd.type;
+ else
+ t = isType(o);
+ }
+ else
+ t = isType(o);
+
+ if (t)
+ {
+ if (auto tf = t.isFunction_Delegate_PtrToFunction())
+ return tf;
+ }
+
+ return null;
+ }
+
+ IntegerExp isX(T)(bool delegate(T) fp)
+ {
+ if (!dim)
+ return False();
+ foreach (o; *e.args)
+ {
+ static if (is(T == Type))
+ auto y = getType(o);
+
+ static if (is(T : Dsymbol))
+ {
+ auto s = getDsymbolWithoutExpCtx(o);
+ if (!s)
+ return False();
+ }
+ static if (is(T == Dsymbol))
+ alias y = s;
+ static if (is(T == Declaration))
+ auto y = s.isDeclaration();
+ static if (is(T == FuncDeclaration))
+ auto y = s.isFuncDeclaration();
+
+ if (!y || !fp(y))
+ return False();
+ }
+ return True();
+ }
+
+ alias isTypeX = isX!Type;
+ alias isDsymX = isX!Dsymbol;
+ alias isDeclX = isX!Declaration;
+ alias isFuncX = isX!FuncDeclaration;
+
+ Expression isPkgX(bool function(Package) fp)
+ {
+ return isDsymX((Dsymbol sym) {
+ Package p = resolveIsPackage(sym);
+ return (p !is null) && fp(p);
+ });
+ }
+
+ if (e.ident == Id.isArithmetic)
+ {
+ return isTypeX(t => t.isintegral() || t.isfloating());
+ }
+ if (e.ident == Id.isFloating)
+ {
+ return isTypeX(t => t.isfloating());
+ }
+ if (e.ident == Id.isIntegral)
+ {
+ return isTypeX(t => t.isintegral());
+ }
+ if (e.ident == Id.isScalar)
+ {
+ return isTypeX(t => t.isscalar());
+ }
+ if (e.ident == Id.isUnsigned)
+ {
+ return isTypeX(t => t.isunsigned());
+ }
+ if (e.ident == Id.isAssociativeArray)
+ {
+ return isTypeX(t => t.toBasetype().ty == Taarray);
+ }
+ if (e.ident == Id.isDeprecated)
+ {
+ if (global.params.vcomplex)
+ {
+ if (isTypeX(t => t.iscomplex() || t.isimaginary()).isBool(true))
+ return True();
+ }
+ return isDsymX(t => t.isDeprecated());
+ }
+ if (e.ident == Id.isFuture)
+ {
+ return isDeclX(t => t.isFuture());
+ }
+ if (e.ident == Id.isStaticArray)
+ {
+ return isTypeX(t => t.toBasetype().ty == Tsarray);
+ }
+ if (e.ident == Id.isAbstractClass)
+ {
+ return isTypeX(t => t.toBasetype().ty == Tclass &&
+ (cast(TypeClass)t.toBasetype()).sym.isAbstract());
+ }
+ if (e.ident == Id.isFinalClass)
+ {
+ return isTypeX(t => t.toBasetype().ty == Tclass &&
+ ((cast(TypeClass)t.toBasetype()).sym.storage_class & STC.final_) != 0);
+ }
+ if (e.ident == Id.isTemplate)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isDsymX((s)
+ {
+ if (!s.toAlias().isOverloadable())
+ return false;
+ return overloadApply(s,
+ sm => sm.isTemplateDeclaration() !is null) != 0;
+ });
+ }
+ if (e.ident == Id.isPOD)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto t = isType(o);
+ if (!t)
+ {
+ e.error("type expected as second argument of __traits `%s` instead of `%s`",
+ e.ident.toChars(), o.toChars());
+ return ErrorExp.get();
+ }
+
+ Type tb = t.baseElemOf();
+ if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null)
+ {
+ return sd.isPOD() ? True() : False();
+ }
+ return True();
+ }
+ if (e.ident == Id.hasCopyConstructor || e.ident == Id.hasPostblit)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto t = isType(o);
+ if (!t)
+ {
+ e.error("type expected as second argument of __traits `%s` instead of `%s`",
+ e.ident.toChars(), o.toChars());
+ return ErrorExp.get();
+ }
+
+ Type tb = t.baseElemOf();
+ if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null)
+ {
+ return (e.ident == Id.hasPostblit) ? (sd.postblit ? True() : False())
+ : (sd.hasCopyCtor ? True() : False());
+ }
+ return False();
+ }
+ if (e.ident == Id.isCopyable)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto t = isType(o);
+ if (!t)
+ {
+ e.error("type expected as second argument of __traits `%s` instead of `%s`",
+ e.ident.toChars(), o.toChars());
+ return ErrorExp.get();
+ }
+
+ t = t.toBasetype(); // get the base in case `t` is an `enum`
+
+ if (auto ts = t.isTypeStruct())
+ {
+ ts.sym.dsymbolSemantic(sc);
+ }
+
+ return isCopyable(t) ? True() : False();
+ }
+
+ if (e.ident == Id.isNested)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto s = getDsymbolWithoutExpCtx(o);
+ if (!s)
+ {
+ }
+ else if (auto ad = s.isAggregateDeclaration())
+ {
+ return ad.isNested() ? True() : False();
+ }
+ else if (auto fd = s.isFuncDeclaration())
+ {
+ return fd.isNested() ? True() : False();
+ }
+
+ e.error("aggregate or function expected instead of `%s`", o.toChars());
+ return ErrorExp.get();
+ }
+ if (e.ident == Id.isDisabled)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isDeclX(f => f.isDisabled());
+ }
+ if (e.ident == Id.isAbstractFunction)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isFuncX(f => f.isAbstract());
+ }
+ if (e.ident == Id.isVirtualFunction)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isFuncX(f => f.isVirtual());
+ }
+ if (e.ident == Id.isVirtualMethod)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isFuncX(f => f.isVirtualMethod());
+ }
+ if (e.ident == Id.isFinalFunction)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isFuncX(f => f.isFinalFunc());
+ }
+ if (e.ident == Id.isOverrideFunction)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isFuncX(f => f.isOverride());
+ }
+ if (e.ident == Id.isStaticFunction)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isFuncX(f => !f.needThis() && !f.isNested());
+ }
+ if (e.ident == Id.isModule)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isPkgX(p => p.isModule() || p.isPackageMod());
+ }
+ if (e.ident == Id.isPackage)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isPkgX(p => p.isModule() is null);
+ }
+ if (e.ident == Id.isRef)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isDeclX(d => d.isRef());
+ }
+ if (e.ident == Id.isOut)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isDeclX(d => d.isOut());
+ }
+ if (e.ident == Id.isLazy)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ return isDeclX(d => (d.storage_class & STC.lazy_) != 0);
+ }
+ if (e.ident == Id.identifier)
+ {
+ // Get identifier for symbol as a string literal
+ /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
+ * a symbol should not be folded to a constant.
+ * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
+ */
+ if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 2))
+ return ErrorExp.get();
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ Identifier id;
+ if (auto po = isParameter(o))
+ {
+ if (!po.ident)
+ {
+ e.error("argument `%s` has no identifier", po.type.toChars());
+ return ErrorExp.get();
+ }
+ id = po.ident;
+ }
+ else
+ {
+ Dsymbol s = getDsymbolWithoutExpCtx(o);
+ if (!s || !s.ident)
+ {
+ e.error("argument `%s` has no identifier", o.toChars());
+ return ErrorExp.get();
+ }
+ id = s.ident;
+ }
+
+ auto se = new StringExp(e.loc, id.toString());
+ return se.expressionSemantic(sc);
+ }
+ if (e.ident == Id.getProtection || e.ident == Id.getVisibility)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ Scope* sc2 = sc.push();
+ sc2.flags = sc.flags | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility;
+ bool ok = TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1);
+ sc2.pop();
+ if (!ok)
+ return ErrorExp.get();
+
+ auto o = (*e.args)[0];
+ auto s = getDsymbolWithoutExpCtx(o);
+ if (!s)
+ {
+ if (!isError(o))
+ e.error("argument `%s` has no visibility", o.toChars());
+ return ErrorExp.get();
+ }
+ if (s.semanticRun == PASS.init)
+ s.dsymbolSemantic(null);
+
+ auto protName = visibilityToString(s.visible().kind); // TODO: How about package(names)
+ assert(protName);
+ auto se = new StringExp(e.loc, protName);
+ return se.expressionSemantic(sc);
+ }
+ if (e.ident == Id.parent)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto s = getDsymbolWithoutExpCtx(o);
+ if (s)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=12496
+ // Consider:
+ // class T1
+ // {
+ // class C(uint value) { }
+ // }
+ // __traits(parent, T1.C!2)
+ if (auto ad = s.isAggregateDeclaration()) // `s` is `C`
+ {
+ if (ad.isNested()) // `C` is nested
+ {
+ if (auto p = s.toParent()) // `C`'s parent is `C!2`, believe it or not
+ {
+ if (p.isTemplateInstance()) // `C!2` is a template instance
+ {
+ s = p; // `C!2`'s parent is `T1`
+ auto td = (cast(TemplateInstance)p).tempdecl;
+ if (td)
+ s = td; // get the declaration context just in case there's two contexts
+ }
+ }
+ }
+ }
+
+ if (auto fd = s.isFuncDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=8943
+ s = fd.toAliasFunc();
+ if (!s.isImport()) // https://issues.dlang.org/show_bug.cgi?id=8922
+ s = s.toParent();
+ }
+ if (!s || s.isImport())
+ {
+ e.error("argument `%s` has no parent", o.toChars());
+ return ErrorExp.get();
+ }
+
+ if (auto f = s.isFuncDeclaration())
+ {
+ if (auto td = getFuncTemplateDecl(f))
+ {
+ if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
+ td = td.overroot; // then get the start
+ Expression ex = new TemplateExp(e.loc, td, f);
+ ex = ex.expressionSemantic(sc);
+ return ex;
+ }
+ if (auto fld = f.isFuncLiteralDeclaration())
+ {
+ // Directly translate to VarExp instead of FuncExp
+ Expression ex = new VarExp(e.loc, fld, true);
+ return ex.expressionSemantic(sc);
+ }
+ }
+ return symbolToExp(s, e.loc, sc, false);
+ }
+ if (e.ident == Id.child)
+ {
+ if (dim != 2)
+ return dimError(2);
+
+ Expression ex;
+ auto op = (*e.args)[0];
+ if (auto symp = getDsymbol(op))
+ ex = new DsymbolExp(e.loc, symp);
+ else if (auto exp = op.isExpression())
+ ex = exp;
+ else
+ {
+ e.error("symbol or expression expected as first argument of __traits `child` instead of `%s`", op.toChars());
+ return ErrorExp.get();
+ }
+
+ ex = ex.expressionSemantic(sc);
+ auto oc = (*e.args)[1];
+ auto symc = getDsymbol(oc);
+ if (!symc)
+ {
+ e.error("symbol expected as second argument of __traits `child` instead of `%s`", oc.toChars());
+ return ErrorExp.get();
+ }
+
+ if (auto d = symc.isDeclaration())
+ ex = new DotVarExp(e.loc, ex, d);
+ else if (auto td = symc.isTemplateDeclaration())
+ ex = new DotExp(e.loc, ex, new TemplateExp(e.loc, td));
+ else if (auto ti = symc.isScopeDsymbol())
+ ex = new DotExp(e.loc, ex, new ScopeExp(e.loc, ti));
+ else
+ assert(0);
+
+ ex = ex.expressionSemantic(sc);
+ return ex;
+ }
+ if (e.ident == Id.toType)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto ex = isExpression((*e.args)[0]);
+ if (!ex)
+ {
+ e.error("expression expected as second argument of __traits `%s`", e.ident.toChars());
+ return ErrorExp.get();
+ }
+ ex = ex.ctfeInterpret();
+
+ StringExp se = semanticString(sc, ex, "__traits(toType, string)");
+ if (!se)
+ {
+ return ErrorExp.get();
+ }
+ Type t = decoToType(se.toUTF8(sc).peekString());
+ if (!t)
+ {
+ e.error("cannot determine `%s`", e.toChars());
+ return ErrorExp.get();
+ }
+ return (new TypeExp(e.loc, t)).expressionSemantic(sc);
+ }
+ if (e.ident == Id.hasMember ||
+ e.ident == Id.getMember ||
+ e.ident == Id.getOverloads ||
+ e.ident == Id.getVirtualMethods ||
+ e.ident == Id.getVirtualFunctions)
+ {
+ if (dim != 2 && !(dim == 3 && e.ident == Id.getOverloads))
+ return dimError(2);
+
+ auto o = (*e.args)[0];
+ auto ex = isExpression((*e.args)[1]);
+ if (!ex)
+ {
+ e.error("expression expected as second argument of __traits `%s`", e.ident.toChars());
+ return ErrorExp.get();
+ }
+ ex = ex.ctfeInterpret();
+
+ bool includeTemplates = false;
+ if (dim == 3 && e.ident == Id.getOverloads)
+ {
+ auto b = isExpression((*e.args)[2]);
+ b = b.ctfeInterpret();
+ if (!b.type.equals(Type.tbool))
+ {
+ e.error("`bool` expected as third argument of `__traits(getOverloads)`, not `%s` of type `%s`", b.toChars(), b.type.toChars());
+ return ErrorExp.get();
+ }
+ includeTemplates = b.isBool(true);
+ }
+
+ StringExp se = ex.toStringExp();
+ if (!se || se.len == 0)
+ {
+ e.error("string expected as second argument of __traits `%s` instead of `%s`", e.ident.toChars(), ex.toChars());
+ return ErrorExp.get();
+ }
+ se = se.toUTF8(sc);
+
+ if (se.sz != 1)
+ {
+ e.error("string must be chars");
+ return ErrorExp.get();
+ }
+ auto id = Identifier.idPool(se.peekString());
+
+ /* Prefer a Type, because getDsymbol(Type) can lose type modifiers.
+ Then a Dsymbol, because it might need some runtime contexts.
+ */
+
+ Dsymbol sym = getDsymbol(o);
+ if (auto t = isType(o))
+ ex = typeDotIdExp(e.loc, t, id);
+ else if (sym)
+ {
+ if (e.ident == Id.hasMember)
+ {
+ if (auto sm = sym.search(e.loc, id))
+ return True();
+ }
+ ex = new DsymbolExp(e.loc, sym);
+ ex = new DotIdExp(e.loc, ex, id);
+ }
+ else if (auto ex2 = isExpression(o))
+ ex = new DotIdExp(e.loc, ex2, id);
+ else
+ {
+ e.error("invalid first argument");
+ return ErrorExp.get();
+ }
+
+ // ignore symbol visibility and disable access checks for these traits
+ Scope* scx = sc.push();
+ scx.flags |= SCOPE.ignoresymbolvisibility | SCOPE.noaccesscheck;
+ scope (exit) scx.pop();
+
+ if (e.ident == Id.hasMember)
+ {
+ /* Take any errors as meaning it wasn't found
+ */
+ ex = ex.trySemantic(scx);
+ return ex ? True() : False();
+ }
+ else if (e.ident == Id.getMember)
+ {
+ if (ex.op == TOK.dotIdentifier)
+ // Prevent semantic() from replacing Symbol with its initializer
+ (cast(DotIdExp)ex).wantsym = true;
+ ex = ex.expressionSemantic(scx);
+ return ex;
+ }
+ else if (e.ident == Id.getVirtualFunctions ||
+ e.ident == Id.getVirtualMethods ||
+ e.ident == Id.getOverloads)
+ {
+ uint errors = global.errors;
+ Expression eorig = ex;
+ ex = ex.expressionSemantic(scx);
+ if (errors < global.errors)
+ e.error("`%s` cannot be resolved", eorig.toChars());
+
+ /* Create tuple of functions of ex
+ */
+ auto exps = new Expressions();
+ Dsymbol f;
+ if (auto ve = ex.isVarExp)
+ {
+ if (ve.var.isFuncDeclaration() || ve.var.isOverDeclaration())
+ f = ve.var;
+ ex = null;
+ }
+ else if (auto dve = ex.isDotVarExp)
+ {
+ if (dve.var.isFuncDeclaration() || dve.var.isOverDeclaration())
+ f = dve.var;
+ if (dve.e1.op == TOK.dotType || dve.e1.op == TOK.this_)
+ ex = null;
+ else
+ ex = dve.e1;
+ }
+ else if (auto te = ex.isTemplateExp)
+ {
+ auto td = te.td;
+ f = td;
+ if (td && td.funcroot)
+ f = td.funcroot;
+ ex = null;
+ }
+ else if (auto dte = ex.isDotTemplateExp)
+ {
+ auto td = dte.td;
+ f = td;
+ if (td && td.funcroot)
+ f = td.funcroot;
+ ex = null;
+ if (dte.e1.op != TOK.dotType && dte.e1.op != TOK.this_)
+ ex = dte.e1;
+ }
+ bool[string] funcTypeHash;
+
+ /* Compute the function signature and insert it in the
+ * hashtable, if not present. This is needed so that
+ * traits(getOverlods, F3, "visit") does not count `int visit(int)`
+ * twice in the following example:
+ *
+ * =============================================
+ * interface F1 { int visit(int);}
+ * interface F2 { int visit(int); void visit(); }
+ * interface F3 : F2, F1 {}
+ *==============================================
+ */
+ void insertInterfaceInheritedFunction(FuncDeclaration fd, Expression e)
+ {
+ auto signature = fd.type.toString();
+ //printf("%s - %s\n", fd.toChars, signature);
+ if (signature !in funcTypeHash)
+ {
+ funcTypeHash[signature] = true;
+ exps.push(e);
+ }
+ }
+
+ int dg(Dsymbol s)
+ {
+ auto fd = s.isFuncDeclaration();
+ if (!fd)
+ {
+ if (includeTemplates)
+ {
+ if (auto td = s.isTemplateDeclaration())
+ {
+ // if td is part of an overload set we must take a copy
+ // which shares the same `instances` cache but without
+ // `overroot` and `overnext` set to avoid overload
+ // behaviour in the result.
+ if (td.overnext !is null)
+ {
+ if (td.instances is null)
+ {
+ // create an empty AA just to copy it
+ scope ti = new TemplateInstance(Loc.initial, Id.empty, null);
+ auto tib = TemplateInstanceBox(ti);
+ td.instances[tib] = null;
+ td.instances.clear();
+ }
+ td = td.syntaxCopy(null);
+ import core.stdc.string : memcpy;
+ memcpy(cast(void*) td, cast(void*) s,
+ __traits(classInstanceSize, TemplateDeclaration));
+ td.overroot = null;
+ td.overnext = null;
+ }
+
+ auto e = ex ? new DotTemplateExp(Loc.initial, ex, td)
+ : new DsymbolExp(Loc.initial, td);
+ exps.push(e);
+ }
+ }
+ return 0;
+ }
+ if (e.ident == Id.getVirtualFunctions && !fd.isVirtual())
+ return 0;
+ if (e.ident == Id.getVirtualMethods && !fd.isVirtualMethod())
+ return 0;
+
+ auto fa = new FuncAliasDeclaration(fd.ident, fd, false);
+ fa.visibility = fd.visibility;
+
+ auto e = ex ? new DotVarExp(Loc.initial, ex, fa, false)
+ : new DsymbolExp(Loc.initial, fa, false);
+
+ // if the parent is an interface declaration
+ // we must check for functions with the same signature
+ // in different inherited interfaces
+ if (sym && sym.isInterfaceDeclaration())
+ insertInterfaceInheritedFunction(fd, e);
+ else
+ exps.push(e);
+ return 0;
+ }
+
+ InterfaceDeclaration ifd = null;
+ if (sym)
+ ifd = sym.isInterfaceDeclaration();
+ // If the symbol passed as a parameter is an
+ // interface that inherits other interfaces
+ overloadApply(f, &dg);
+ if (ifd && ifd.interfaces && f)
+ {
+ // check the overloads of each inherited interface individually
+ foreach (bc; ifd.interfaces)
+ {
+ if (auto fd = bc.sym.search(e.loc, f.ident))
+ overloadApply(fd, &dg);
+ }
+ }
+
+ auto tup = new TupleExp(e.loc, exps);
+ return tup.expressionSemantic(scx);
+ }
+ else
+ assert(0);
+ }
+ if (e.ident == Id.classInstanceSize)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto s = getDsymbol(o);
+ auto cd = s ? s.isClassDeclaration() : null;
+ if (!cd)
+ {
+ e.error("first argument is not a class");
+ return ErrorExp.get();
+ }
+ if (cd.sizeok != Sizeok.done)
+ {
+ cd.size(e.loc);
+ }
+ if (cd.sizeok != Sizeok.done)
+ {
+ e.error("%s `%s` is forward referenced", cd.kind(), cd.toChars());
+ return ErrorExp.get();
+ }
+
+ return new IntegerExp(e.loc, cd.structsize, Type.tsize_t);
+ }
+ if (e.ident == Id.getAliasThis)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto s = getDsymbol(o);
+ auto ad = s ? s.isAggregateDeclaration() : null;
+
+ auto exps = new Expressions();
+ if (ad && ad.aliasthis)
+ exps.push(new StringExp(e.loc, ad.aliasthis.ident.toString()));
+ Expression ex = new TupleExp(e.loc, exps);
+ ex = ex.expressionSemantic(sc);
+ return ex;
+ }
+ if (e.ident == Id.getAttributes)
+ {
+ /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
+ * a symbol should not be folded to a constant.
+ * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
+ */
+ if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 3))
+ return ErrorExp.get();
+
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto po = isParameter(o);
+ auto s = getDsymbolWithoutExpCtx(o);
+ UserAttributeDeclaration udad = null;
+ if (po)
+ {
+ udad = po.userAttribDecl;
+ }
+ else if (s)
+ {
+ if (s.isImport())
+ {
+ s = s.isImport().mod;
+ }
+ //printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s.scope);
+ udad = s.userAttribDecl;
+ }
+ else
+ {
+ version (none)
+ {
+ Expression x = isExpression(o);
+ Type t = isType(o);
+ if (x)
+ printf("e = %s %s\n", Token.toChars(x.op), x.toChars());
+ if (t)
+ printf("t = %d %s\n", t.ty, t.toChars());
+ }
+ e.error("first argument is not a symbol");
+ return ErrorExp.get();
+ }
+
+ auto exps = udad ? udad.getAttributes() : new Expressions();
+ auto tup = new TupleExp(e.loc, exps);
+ return tup.expressionSemantic(sc);
+ }
+ if (e.ident == Id.getFunctionAttributes)
+ {
+ /* Extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs.
+ * https://dlang.org/spec/traits.html#getFunctionAttributes
+ */
+ if (dim != 1)
+ return dimError(1);
+
+ FuncDeclaration fd;
+ TypeFunction tf = toTypeFunction((*e.args)[0], fd);
+
+ if (!tf)
+ {
+ e.error("first argument is not a function");
+ return ErrorExp.get();
+ }
+
+ auto mods = new Expressions();
+
+ void addToMods(string str)
+ {
+ mods.push(new StringExp(Loc.initial, str));
+ }
+ tf.modifiersApply(&addToMods);
+ tf.attributesApply(&addToMods, TRUSTformatSystem);
+
+ auto tup = new TupleExp(e.loc, mods);
+ return tup.expressionSemantic(sc);
+ }
+ if (e.ident == Id.isReturnOnStack)
+ {
+ /* Extract as a boolean if function return value is on the stack
+ * https://dlang.org/spec/traits.html#isReturnOnStack
+ */
+ if (dim != 1)
+ return dimError(1);
+
+ RootObject o = (*e.args)[0];
+ FuncDeclaration fd;
+ TypeFunction tf = toTypeFunction(o, fd);
+
+ if (!tf)
+ {
+ e.error("argument to `__traits(isReturnOnStack, %s)` is not a function", o.toChars());
+ return ErrorExp.get();
+ }
+
+ bool value = target.isReturnOnStack(tf, fd && fd.needThis());
+ return IntegerExp.createBool(value);
+ }
+ if (e.ident == Id.getFunctionVariadicStyle)
+ {
+ /* Accept a symbol or a type. Returns one of the following:
+ * "none" not a variadic function
+ * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments`
+ * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg
+ * "typesafe" void typesafe(T[] ...)
+ */
+ // get symbol linkage as a string
+ if (dim != 1)
+ return dimError(1);
+
+ LINK link;
+ VarArg varargs;
+ auto o = (*e.args)[0];
+
+ FuncDeclaration fd;
+ TypeFunction tf = toTypeFunction(o, fd);
+
+ if (tf)
+ {
+ link = tf.linkage;
+ varargs = tf.parameterList.varargs;
+ }
+ else
+ {
+ if (!fd)
+ {
+ e.error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o.toChars());
+ return ErrorExp.get();
+ }
+ link = fd.linkage;
+ varargs = fd.getParameterList().varargs;
+ }
+ string style;
+ final switch (varargs)
+ {
+ case VarArg.none: style = "none"; break;
+ case VarArg.variadic: style = (link == LINK.d)
+ ? "argptr"
+ : "stdarg"; break;
+ case VarArg.typesafe: style = "typesafe"; break;
+ }
+ auto se = new StringExp(e.loc, style);
+ return se.expressionSemantic(sc);
+ }
+ if (e.ident == Id.getParameterStorageClasses)
+ {
+ /* Accept a function symbol or a type, followed by a parameter index.
+ * Returns a tuple of strings of the parameter's storage classes.
+ */
+ // get symbol linkage as a string
+ if (dim != 2)
+ return dimError(2);
+
+ auto o = (*e.args)[0];
+ auto o1 = (*e.args)[1];
+
+ FuncDeclaration fd;
+ TypeFunction tf = toTypeFunction(o, fd);
+
+ ParameterList fparams;
+ if (tf)
+ fparams = tf.parameterList;
+ else if (fd)
+ fparams = fd.getParameterList();
+ else
+ {
+ e.error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function",
+ o.toChars(), o1.toChars());
+ return ErrorExp.get();
+ }
+
+ // Avoid further analysis for invalid functions leading to misleading error messages
+ if (!fparams.parameters)
+ return ErrorExp.get();
+
+ StorageClass stc;
+
+ // Set stc to storage class of the ith parameter
+ auto ex = isExpression((*e.args)[1]);
+ if (!ex)
+ {
+ e.error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`",
+ o.toChars(), o1.toChars());
+ return ErrorExp.get();
+ }
+ ex = ex.ctfeInterpret();
+ auto ii = ex.toUInteger();
+ if (ii >= fparams.length)
+ {
+ e.error("parameter index must be in range 0..%u not %s", cast(uint)fparams.length, ex.toChars());
+ return ErrorExp.get();
+ }
+
+ uint n = cast(uint)ii;
+ Parameter p = fparams[n];
+ stc = p.storageClass;
+
+ // This mirrors hdrgen.visit(Parameter p)
+ if (p.type && p.type.mod & MODFlags.shared_)
+ stc &= ~STC.shared_;
+
+ auto exps = new Expressions;
+
+ void push(string s)
+ {
+ exps.push(new StringExp(e.loc, s));
+ }
+
+ if (stc & STC.auto_)
+ push("auto");
+ if (stc & STC.return_)
+ push("return");
+
+ if (stc & STC.out_)
+ push("out");
+ else if (stc & STC.in_)
+ push("in");
+ else if (stc & STC.ref_)
+ push("ref");
+ else if (stc & STC.lazy_)
+ push("lazy");
+ else if (stc & STC.alias_)
+ push("alias");
+
+ if (stc & STC.const_)
+ push("const");
+ if (stc & STC.immutable_)
+ push("immutable");
+ if (stc & STC.wild)
+ push("inout");
+ if (stc & STC.shared_)
+ push("shared");
+ if (stc & STC.scope_ && !(stc & STC.scopeinferred))
+ push("scope");
+
+ auto tup = new TupleExp(e.loc, exps);
+ return tup.expressionSemantic(sc);
+ }
+ if (e.ident == Id.getLinkage)
+ {
+ // get symbol linkage as a string
+ if (dim != 1)
+ return dimError(1);
+
+ LINK link;
+ auto o = (*e.args)[0];
+
+ FuncDeclaration fd;
+ TypeFunction tf = toTypeFunction(o, fd);
+
+ if (tf)
+ link = tf.linkage;
+ else
+ {
+ auto s = getDsymbol(o);
+ Declaration d;
+ AggregateDeclaration agg;
+ if (!s || ((d = s.isDeclaration()) is null && (agg = s.isAggregateDeclaration()) is null))
+ {
+ e.error("argument to `__traits(getLinkage, %s)` is not a declaration", o.toChars());
+ return ErrorExp.get();
+ }
+
+ if (d !is null)
+ link = d.linkage;
+ else
+ {
+ // Resolves forward references
+ if (agg.sizeok != Sizeok.done)
+ {
+ agg.size(e.loc);
+ if (agg.sizeok != Sizeok.done)
+ {
+ e.error("%s `%s` is forward referenced", agg.kind(), agg.toChars());
+ return ErrorExp.get();
+ }
+ }
+
+ final switch (agg.classKind)
+ {
+ case ClassKind.d:
+ link = LINK.d;
+ break;
+ case ClassKind.cpp:
+ link = LINK.cpp;
+ break;
+ case ClassKind.objc:
+ link = LINK.objc;
+ break;
+ case ClassKind.c:
+ link = LINK.c;
+ break;
+ }
+ }
+ }
+ auto linkage = linkageToChars(link);
+ auto se = new StringExp(e.loc, linkage.toDString());
+ return se.expressionSemantic(sc);
+ }
+ if (e.ident == Id.allMembers ||
+ e.ident == Id.derivedMembers)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto s = getDsymbol(o);
+ if (!s)
+ {
+ e.error("In expression `%s` `%s` can't have members", e.toChars(), o.toChars());
+ e.errorSupplemental("`%s` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation", o.toChars());
+
+ return ErrorExp.get();
+ }
+ if (auto imp = s.isImport())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=9692
+ s = imp.mod;
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=16044
+ if (auto p = s.isPackage())
+ {
+ if (auto pm = p.isPackageMod())
+ s = pm;
+ }
+
+ auto sds = s.isScopeDsymbol();
+ if (!sds || sds.isTemplateDeclaration())
+ {
+ e.error("In expression `%s` %s `%s` has no members", e.toChars(), s.kind(), s.toChars());
+ e.errorSupplemental("`%s` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation", s.toChars());
+ return ErrorExp.get();
+ }
+
+ auto idents = new Identifiers();
+
+ int pushIdentsDg(size_t n, Dsymbol sm)
+ {
+ if (!sm)
+ return 1;
+
+ // skip local symbols, such as static foreach loop variables
+ if (auto decl = sm.isDeclaration())
+ {
+ if (decl.storage_class & STC.local)
+ {
+ return 0;
+ }
+ // skip 'this' context pointers
+ else if (decl.isThisDeclaration())
+ return 0;
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=20915
+ // skip version and debug identifiers
+ if (sm.isVersionSymbol() || sm.isDebugSymbol())
+ return 0;
+
+ //printf("\t[%i] %s %s\n", i, sm.kind(), sm.toChars());
+ if (sm.ident)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=10096
+ // https://issues.dlang.org/show_bug.cgi?id=10100
+ // Skip over internal members in __traits(allMembers)
+ if ((sm.isCtorDeclaration() && sm.ident != Id.ctor) ||
+ (sm.isDtorDeclaration() && sm.ident != Id.dtor) ||
+ (sm.isPostBlitDeclaration() && sm.ident != Id.postblit) ||
+ sm.isInvariantDeclaration() ||
+ sm.isUnitTestDeclaration())
+
+ {
+ return 0;
+ }
+ if (sm.ident == Id.empty)
+ {
+ return 0;
+ }
+ if (sm.isTypeInfoDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=15177
+ return 0;
+ if ((!sds.isModule() && !sds.isPackage()) && sm.isImport()) // https://issues.dlang.org/show_bug.cgi?id=17057
+ return 0;
+
+ //printf("\t%s\n", sm.ident.toChars());
+
+ /* Skip if already present in idents[]
+ */
+ foreach (id; *idents)
+ {
+ if (id == sm.ident)
+ return 0;
+
+ // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop.
+ debug
+ {
+ import core.stdc.string : strcmp;
+ assert(strcmp(id.toChars(), sm.ident.toChars()) != 0);
+ }
+ }
+ idents.push(sm.ident);
+ }
+ else if (auto ed = sm.isEnumDeclaration())
+ {
+ ScopeDsymbol._foreach(null, ed.members, &pushIdentsDg);
+ }
+ return 0;
+ }
+
+ ScopeDsymbol._foreach(sc, sds.members, &pushIdentsDg);
+ auto cd = sds.isClassDeclaration();
+ if (cd && e.ident == Id.allMembers)
+ {
+ if (cd.semanticRun < PASS.semanticdone)
+ cd.dsymbolSemantic(null); // https://issues.dlang.org/show_bug.cgi?id=13668
+ // Try to resolve forward reference
+
+ void pushBaseMembersDg(ClassDeclaration cd)
+ {
+ for (size_t i = 0; i < cd.baseclasses.dim; i++)
+ {
+ auto cb = (*cd.baseclasses)[i].sym;
+ assert(cb);
+ ScopeDsymbol._foreach(null, cb.members, &pushIdentsDg);
+ if (cb.baseclasses.dim)
+ pushBaseMembersDg(cb);
+ }
+ }
+
+ pushBaseMembersDg(cd);
+ }
+
+ // Turn Identifiers into StringExps reusing the allocated array
+ assert(Expressions.sizeof == Identifiers.sizeof);
+ auto exps = cast(Expressions*)idents;
+ foreach (i, id; *idents)
+ {
+ auto se = new StringExp(e.loc, id.toString());
+ (*exps)[i] = se;
+ }
+
+ /* Making this a tuple is more flexible, as it can be statically unrolled.
+ * To make an array literal, enclose __traits in [ ]:
+ * [ __traits(allMembers, ...) ]
+ */
+ Expression ex = new TupleExp(e.loc, exps);
+ ex = ex.expressionSemantic(sc);
+ return ex;
+ }
+ if (e.ident == Id.compiles)
+ {
+ /* Determine if all the objects - types, expressions, or symbols -
+ * compile without error
+ */
+ if (!dim)
+ return False();
+
+ foreach (o; *e.args)
+ {
+ uint errors = global.startGagging();
+ Scope* sc2 = sc.push();
+ sc2.tinst = null;
+ sc2.minst = null;
+ sc2.flags = (sc.flags & ~(SCOPE.ctfe | SCOPE.condition)) | SCOPE.compile | SCOPE.fullinst;
+
+ bool err = false;
+
+ auto t = isType(o);
+ while (t)
+ {
+ if (auto tm = t.isTypeMixin())
+ {
+ /* The mixin string could be a type or an expression.
+ * Have to try compiling it to see.
+ */
+ OutBuffer buf;
+ if (expressionsToString(buf, sc, tm.exps))
+ {
+ err = true;
+ break;
+ }
+ const olderrors = global.errors;
+ const len = buf.length;
+ buf.writeByte(0);
+ const str = buf.extractSlice()[0 .. len];
+ scope p = new Parser!ASTCodegen(e.loc, sc._module, str, false);
+ p.nextToken();
+ //printf("p.loc.linnum = %d\n", p.loc.linnum);
+
+ o = p.parseTypeOrAssignExp(TOK.endOfFile);
+ if (olderrors != global.errors || p.token.value != TOK.endOfFile)
+ {
+ err = true;
+ break;
+ }
+ t = o.isType();
+ }
+ else
+ break;
+ }
+
+ if (!err)
+ {
+ auto ex = t ? t.typeToExpression() : isExpression(o);
+ if (!ex && t)
+ {
+ Dsymbol s;
+ t.resolve(e.loc, sc2, ex, t, s);
+ if (t)
+ {
+ t.typeSemantic(e.loc, sc2);
+ if (t.ty == Terror)
+ err = true;
+ }
+ else if (s && s.errors)
+ err = true;
+ }
+ if (ex)
+ {
+ ex = ex.expressionSemantic(sc2);
+ ex = resolvePropertiesOnly(sc2, ex);
+ ex = ex.optimize(WANTvalue);
+ if (sc2.func && sc2.func.type.ty == Tfunction)
+ {
+ const tf = cast(TypeFunction)sc2.func.type;
+ err |= tf.isnothrow && canThrow(ex, sc2.func, false);
+ }
+ ex = checkGC(sc2, ex);
+ if (ex.op == TOK.error)
+ err = true;
+ }
+ }
+
+ // Carefully detach the scope from the parent and throw it away as
+ // we only need it to evaluate the expression
+ // https://issues.dlang.org/show_bug.cgi?id=15428
+ sc2.detach();
+
+ if (global.endGagging(errors) || err)
+ {
+ return False();
+ }
+ }
+ return True();
+ }
+ if (e.ident == Id.isSame)
+ {
+ /* Determine if two symbols are the same
+ */
+ if (dim != 2)
+ return dimError(2);
+
+ // https://issues.dlang.org/show_bug.cgi?id=20761
+ // tiarg semantic may expand in place the list of arguments, for example:
+ //
+ // before tiarg sema: __traits(isSame, seq!(0,0), seq!(1,1))
+ // after : __traits(isSame, 0, 0, 1, 1)
+ //
+ // so we split in two lists
+ Objects ob1;
+ ob1.push((*e.args)[0]);
+ Objects ob2;
+ ob2.push((*e.args)[1]);
+ if (!TemplateInstance.semanticTiargs(e.loc, sc, &ob1, 0))
+ return ErrorExp.get();
+ if (!TemplateInstance.semanticTiargs(e.loc, sc, &ob2, 0))
+ return ErrorExp.get();
+ if (ob1.dim != ob2.dim)
+ return False();
+ foreach (immutable i; 0 .. ob1.dim)
+ if (!ob1[i].isSame(ob2[i], sc))
+ return False();
+ return True();
+ }
+ if (e.ident == Id.getUnitTests)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto s = getDsymbolWithoutExpCtx(o);
+ if (!s)
+ {
+ e.error("argument `%s` to __traits(getUnitTests) must be a module or aggregate",
+ o.toChars());
+ return ErrorExp.get();
+ }
+ if (auto imp = s.isImport()) // https://issues.dlang.org/show_bug.cgi?id=10990
+ s = imp.mod;
+
+ auto sds = s.isScopeDsymbol();
+ if (!sds || sds.isTemplateDeclaration())
+ {
+ e.error("argument `%s` to __traits(getUnitTests) must be a module or aggregate, not a %s",
+ s.toChars(), s.kind());
+ return ErrorExp.get();
+ }
+
+ auto exps = new Expressions();
+ if (global.params.useUnitTests)
+ {
+ bool[void*] uniqueUnitTests;
+
+ void symbolDg(Dsymbol s)
+ {
+ if (auto ad = s.isAttribDeclaration())
+ {
+ ad.include(null).foreachDsymbol(&symbolDg);
+ }
+ else if (auto tm = s.isTemplateMixin())
+ {
+ tm.members.foreachDsymbol(&symbolDg);
+ }
+ else if (auto ud = s.isUnitTestDeclaration())
+ {
+ if (cast(void*)ud in uniqueUnitTests)
+ return;
+
+ uniqueUnitTests[cast(void*)ud] = true;
+
+ auto ad = new FuncAliasDeclaration(ud.ident, ud, false);
+ ad.visibility = ud.visibility;
+
+ auto e = new DsymbolExp(Loc.initial, ad, false);
+ exps.push(e);
+ }
+ }
+
+ sds.members.foreachDsymbol(&symbolDg);
+ }
+ auto te = new TupleExp(e.loc, exps);
+ return te.expressionSemantic(sc);
+ }
+ if (e.ident == Id.getVirtualIndex)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ auto s = getDsymbolWithoutExpCtx(o);
+
+ auto fd = s ? s.isFuncDeclaration() : null;
+ if (!fd)
+ {
+ e.error("first argument to __traits(getVirtualIndex) must be a function");
+ return ErrorExp.get();
+ }
+
+ fd = fd.toAliasFunc(); // Necessary to support multiple overloads.
+ return new IntegerExp(e.loc, fd.vtblIndex, Type.tptrdiff_t);
+ }
+ if (e.ident == Id.getPointerBitmap)
+ {
+ return pointerBitmap(e);
+ }
+ if (e.ident == Id.isZeroInit)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ Type t = isType(o);
+ if (!t)
+ {
+ e.error("type expected as second argument of __traits `%s` instead of `%s`",
+ e.ident.toChars(), o.toChars());
+ return ErrorExp.get();
+ }
+
+ Type tb = t.baseElemOf();
+ return tb.isZeroInit(e.loc) ? True() : False();
+ }
+ if (e.ident == Id.getTargetInfo)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto ex = isExpression((*e.args)[0]);
+ StringExp se = ex ? ex.ctfeInterpret().toStringExp() : null;
+ if (!ex || !se || se.len == 0)
+ {
+ e.error("string expected as argument of __traits `%s` instead of `%s`", e.ident.toChars(), ex.toChars());
+ return ErrorExp.get();
+ }
+ se = se.toUTF8(sc);
+
+ const slice = se.peekString();
+ Expression r = target.getTargetInfo(slice.ptr, e.loc); // BUG: reliance on terminating 0
+ if (!r)
+ {
+ e.error("`getTargetInfo` key `\"%.*s\"` not supported by this implementation",
+ cast(int)slice.length, slice.ptr);
+ return ErrorExp.get();
+ }
+ return r.expressionSemantic(sc);
+ }
+ if (e.ident == Id.getLocation)
+ {
+ if (dim != 1)
+ return dimError(1);
+ auto arg0 = (*e.args)[0];
+ Dsymbol s = getDsymbolWithoutExpCtx(arg0);
+ if (!s || !s.loc.isValid())
+ {
+ e.error("can only get the location of a symbol, not `%s`", arg0.toChars());
+ return ErrorExp.get();
+ }
+
+ const fd = s.isFuncDeclaration();
+ // FIXME:td.overnext is always set, even when using an index on it
+ //const td = s.isTemplateDeclaration();
+ if ((fd && fd.overnext) /*|| (td && td.overnext)*/)
+ {
+ e.error("cannot get location of an overload set, " ~
+ "use `__traits(getOverloads, ..., \"%s\"%s)[N]` " ~
+ "to get the Nth overload",
+ arg0.toChars(), /*td ? ", true".ptr :*/ "".ptr);
+ return ErrorExp.get();
+ }
+
+ auto exps = new Expressions(3);
+ (*exps)[0] = new StringExp(e.loc, s.loc.filename.toDString());
+ (*exps)[1] = new IntegerExp(e.loc, s.loc.linnum,Type.tint32);
+ (*exps)[2] = new IntegerExp(e.loc, s.loc.charnum,Type.tint32);
+ auto tup = new TupleExp(e.loc, exps);
+ return tup.expressionSemantic(sc);
+ }
+ if (e.ident == Id.getCppNamespaces)
+ {
+ auto o = (*e.args)[0];
+ auto s = getDsymbolWithoutExpCtx(o);
+ auto exps = new Expressions(0);
+ if (auto d = s.isDeclaration())
+ {
+ if (d.inuse)
+ {
+ d.error("circular reference in `__traits(GetCppNamespaces,...)`");
+ return ErrorExp.get();
+ }
+ d.inuse = 1;
+ }
+
+ /**
+ Prepend the namespaces in the linked list `ns` to `es`.
+
+ Returns: true if `ns` contains an `ErrorExp`.
+ */
+ bool prependNamespaces(Expressions* es, CPPNamespaceDeclaration ns)
+ {
+ // Semantic processing will convert `extern(C++, "a", "b", "c")`
+ // into `extern(C++, "a") extern(C++, "b") extern(C++, "c")`,
+ // creating a linked list what `a`'s `cppnamespace` points to `b`,
+ // and `b`'s points to `c`. Our entry point is `a`.
+ for (; ns !is null; ns = ns.cppnamespace)
+ {
+ ns.dsymbolSemantic(sc);
+
+ if (ns.exp.isErrorExp())
+ return true;
+
+ auto se = ns.exp.toStringExp();
+ // extern(C++, (emptyTuple))
+ // struct D {}
+ // will produce a blank ident
+ if (!se.len)
+ continue;
+ es.insert(0, se);
+ }
+ return false;
+ }
+ for (auto p = s; !p.isModule(); p = p.toParent())
+ {
+ p.dsymbolSemantic(sc);
+ auto pp = p.toParent();
+ if (pp.isTemplateInstance())
+ {
+ if (!p.cppnamespace)
+ continue;
+ //if (!p.toParent().cppnamespace)
+ // continue;
+ auto inner = new Expressions(0);
+ auto outer = new Expressions(0);
+ if (prependNamespaces(inner, p.cppnamespace)) return ErrorExp.get();
+ if (prependNamespaces(outer, pp.cppnamespace)) return ErrorExp.get();
+
+ size_t i = 0;
+ while(i < outer.dim && ((*inner)[i]) == (*outer)[i])
+ i++;
+
+ foreach_reverse (ns; (*inner)[][i .. $])
+ exps.insert(0, ns);
+ continue;
+ }
+
+ if (p.isNspace())
+ exps.insert(0, new StringExp(p.loc, p.ident.toString()));
+
+ if (prependNamespaces(exps, p.cppnamespace))
+ return ErrorExp.get();
+ }
+ if (auto d = s.isDeclaration())
+ d.inuse = 0;
+ auto tup = new TupleExp(e.loc, exps);
+ return tup.expressionSemantic(sc);
+ }
+
+ static const(char)[] trait_search_fp(const(char)[] seed, out int cost)
+ {
+ //printf("trait_search_fp('%s')\n", seed);
+ if (!seed.length)
+ return null;
+ cost = 0; // all the same cost
+ const sv = traitsStringTable.lookup(seed);
+ return sv ? sv.toString() : null;
+ }
+
+ if (auto sub = speller!trait_search_fp(e.ident.toString()))
+ e.error("unrecognized trait `%s`, did you mean `%.*s`?", e.ident.toChars(), cast(int) sub.length, sub.ptr);
+ else
+ e.error("unrecognized trait `%s`", e.ident.toChars());
+ return ErrorExp.get();
+}
+
+/// compare arguments of __traits(isSame)
+private bool isSame(RootObject o1, RootObject o2, Scope* sc)
+{
+ static FuncLiteralDeclaration isLambda(RootObject oarg)
+ {
+ if (auto t = isDsymbol(oarg))
+ {
+ if (auto td = t.isTemplateDeclaration())
+ {
+ if (td.members && td.members.dim == 1)
+ {
+ if (auto fd = (*td.members)[0].isFuncLiteralDeclaration())
+ return fd;
+ }
+ }
+ }
+ else if (auto ea = isExpression(oarg))
+ {
+ if (ea.op == TOK.function_)
+ {
+ if (auto fe = cast(FuncExp)ea)
+ return fe.fd;
+ }
+ }
+ return null;
+ }
+
+ auto l1 = isLambda(o1);
+ auto l2 = isLambda(o2);
+
+ if (l1 && l2)
+ {
+ import dmd.lambdacomp : isSameFuncLiteral;
+ if (isSameFuncLiteral(l1, l2, sc))
+ return true;
+ }
+
+ // issue 12001, allow isSame, <BasicType>, <BasicType>
+ Type t1 = isType(o1);
+ Type t2 = isType(o2);
+ if (t1 && t2 && t1.equals(t2))
+ return true;
+
+ auto s1 = getDsymbol(o1);
+ auto s2 = getDsymbol(o2);
+ //printf("isSame: %s, %s\n", o1.toChars(), o2.toChars());
+ version (none)
+ {
+ printf("o1: %p\n", o1);
+ printf("o2: %p\n", o2);
+ if (!s1)
+ {
+ if (auto ea = isExpression(o1))
+ printf("%s\n", ea.toChars());
+ if (auto ta = isType(o1))
+ printf("%s\n", ta.toChars());
+ return false;
+ }
+ else
+ printf("%s %s\n", s1.kind(), s1.toChars());
+ }
+ if (!s1 && !s2)
+ {
+ auto ea1 = isExpression(o1);
+ auto ea2 = isExpression(o2);
+ if (ea1 && ea2)
+ {
+ if (ea1.equals(ea2))
+ return true;
+ }
+ }
+ if (!s1 || !s2)
+ return false;
+
+ s1 = s1.toAlias();
+ s2 = s2.toAlias();
+
+ if (auto fa1 = s1.isFuncAliasDeclaration())
+ s1 = fa1.toAliasFunc();
+ if (auto fa2 = s2.isFuncAliasDeclaration())
+ s2 = fa2.toAliasFunc();
+
+ // https://issues.dlang.org/show_bug.cgi?id=11259
+ // compare import symbol to a package symbol
+ static bool cmp(Dsymbol s1, Dsymbol s2)
+ {
+ auto imp = s1.isImport();
+ return imp && imp.pkg && imp.pkg == s2.isPackage();
+ }
+
+ if (cmp(s1,s2) || cmp(s2,s1))
+ return true;
+
+ if (s1 == s2)
+ return true;
+
+ // https://issues.dlang.org/show_bug.cgi?id=18771
+ // OverloadSets are equal if they contain the same functions
+ auto overSet1 = s1.isOverloadSet();
+ if (!overSet1)
+ return false;
+
+ auto overSet2 = s2.isOverloadSet();
+ if (!overSet2)
+ return false;
+
+ if (overSet1.a.dim != overSet2.a.dim)
+ return false;
+
+ // OverloadSets contain array of Dsymbols => O(n*n)
+ // to compare for equality as the order of overloads
+ // might not be the same
+Lnext:
+ foreach(overload1; overSet1.a)
+ {
+ foreach(overload2; overSet2.a)
+ {
+ if (overload1 == overload2)
+ continue Lnext;
+ }
+ return false;
+ }
+ return true;
+}
diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d
new file mode 100644
index 0000000..0479d5a
--- /dev/null
+++ b/gcc/d/dmd/transitivevisitor.d
@@ -0,0 +1,1207 @@
+/**
+ * Documentation: https://dlang.org/phobos/dmd_transitivevisitor.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/transitivevisitor.d
+ */
+
+module dmd.transitivevisitor;
+
+import dmd.astenums;
+import dmd.permissivevisitor;
+import dmd.tokens;
+import dmd.root.rootobject;
+
+import core.stdc.stdio;
+
+/** Visitor that implements the AST traversal logic. The nodes just accept their children.
+ */
+extern(C++) class ParseTimeTransitiveVisitor(AST) : PermissiveVisitor!AST
+{
+ alias visit = PermissiveVisitor!AST.visit;
+ mixin ParseVisitMethods!AST;
+}
+
+/* This mixin implements the AST traversal logic for parse time AST nodes. The same code
+ * is used for semantic time AST node traversal, so in order to not duplicate the code,
+ * the template mixin is used.
+ */
+package mixin template ParseVisitMethods(AST)
+{
+
+// Statement Nodes
+//===========================================================
+ override void visit(AST.ExpStatement s)
+ {
+ //printf("Visiting ExpStatement\n");
+ if (s.exp)
+ {
+ if (auto de = s.exp.isDeclarationExp())
+ de.declaration.accept(this);
+ else
+ s.exp.accept(this);
+ }
+ }
+
+ override void visit(AST.CompileStatement s)
+ {
+ //printf("Visiting CompileStatement\n");
+ visitArgs(s.exps);
+ }
+
+ override void visit(AST.CompoundStatement s)
+ {
+ //printf("Visiting CompoundStatement\n");
+ foreach (sx; *s.statements)
+ {
+ if (sx)
+ sx.accept(this);
+ }
+ }
+
+ void visitVarDecl(AST.VarDeclaration v)
+ {
+ //printf("Visiting VarDeclaration\n");
+ if (v.type)
+ visitType(v.type);
+ if (v._init)
+ {
+ if (auto ie = v._init.isExpInitializer())
+ {
+ if (auto ce = ie.exp.isConstructExp())
+ ce.e2.accept(this);
+ else if (auto be = ie.exp.isBlitExp())
+ be.e2.accept(this);
+ else
+ v._init.accept(this);
+ }
+ else
+ v._init.accept(this);
+ }
+ }
+
+ override void visit(AST.CompoundDeclarationStatement s)
+ {
+ //printf("Visiting CompoundDeclarationStatement\n");
+ foreach (sx; *s.statements)
+ {
+ if (!sx)
+ continue;
+ if (auto ds = sx.isExpStatement())
+ {
+ if (auto de = ds.exp.isDeclarationExp())
+ {
+ auto d = de.declaration;
+ assert(d.isDeclaration());
+ if (auto v = d.isVarDeclaration())
+ visitVarDecl(v);
+ else
+ d.accept(this);
+ }
+ }
+ }
+ }
+
+ override void visit(AST.ScopeStatement s)
+ {
+ //printf("Visiting ScopeStatement\n");
+ if (s.statement)
+ s.statement.accept(this);
+ }
+
+ override void visit(AST.WhileStatement s)
+ {
+ //printf("Visiting WhileStatement\n");
+ s.condition.accept(this);
+ if (s._body)
+ s._body.accept(this);
+ }
+
+ override void visit(AST.DoStatement s)
+ {
+ //printf("Visiting DoStatement\n");
+ if (s._body)
+ s._body.accept(this);
+ s.condition.accept(this);
+ }
+
+ override void visit(AST.ForStatement s)
+ {
+ //printf("Visiting ForStatement\n");
+ if (s._init)
+ s._init.accept(this);
+ if (s.condition)
+ s.condition.accept(this);
+ if (s.increment)
+ s.increment.accept(this);
+ if (s._body)
+ s._body.accept(this);
+ }
+
+ override void visit(AST.ForeachStatement s)
+ {
+ //printf("Visiting ForeachStatement\n");
+ foreach (p; *s.parameters)
+ if (p.type)
+ visitType(p.type);
+ s.aggr.accept(this);
+ if (s._body)
+ s._body.accept(this);
+ }
+
+ override void visit(AST.ForeachRangeStatement s)
+ {
+ //printf("Visiting ForeachRangeStatement\n");
+ if (s.prm.type)
+ visitType(s.prm.type);
+ s.lwr.accept(this);
+ s.upr.accept(this);
+ if (s._body)
+ s._body.accept(this);
+ }
+
+ override void visit(AST.IfStatement s)
+ {
+ //printf("Visiting IfStatement\n");
+ if (s.prm && s.prm.type)
+ visitType(s.prm.type);
+ s.condition.accept(this);
+ s.ifbody.accept(this);
+ if (s.elsebody)
+ s.elsebody.accept(this);
+ }
+
+ override void visit(AST.ConditionalStatement s)
+ {
+ //printf("Visiting ConditionalStatement\n");
+ s.condition.accept(this);
+ if (s.ifbody)
+ s.ifbody.accept(this);
+ if (s.elsebody)
+ s.elsebody.accept(this);
+ }
+
+ void visitArgs(AST.Expressions* expressions, AST.Expression basis = null)
+ {
+ if (!expressions || !expressions.dim)
+ return;
+ foreach (el; *expressions)
+ {
+ if (!el)
+ el = basis;
+ if (el)
+ el.accept(this);
+ }
+ }
+
+ override void visit(AST.PragmaStatement s)
+ {
+ //printf("Visiting PragmaStatement\n");
+ if (s.args && s.args.dim)
+ visitArgs(s.args);
+ if (s._body)
+ s._body.accept(this);
+ }
+
+ override void visit(AST.StaticAssertStatement s)
+ {
+ //printf("Visiting StaticAssertStatement\n");
+ s.sa.accept(this);
+ }
+
+ override void visit(AST.SwitchStatement s)
+ {
+ //printf("Visiting SwitchStatement\n");
+ s.condition.accept(this);
+ if (s._body)
+ s._body.accept(this);
+ }
+
+ override void visit(AST.CaseStatement s)
+ {
+ //printf("Visiting CaseStatement\n");
+ s.exp.accept(this);
+ s.statement.accept(this);
+ }
+
+ override void visit(AST.CaseRangeStatement s)
+ {
+ //printf("Visiting CaseRangeStatement\n");
+ s.first.accept(this);
+ s.last.accept(this);
+ s.statement.accept(this);
+ }
+
+ override void visit(AST.DefaultStatement s)
+ {
+ //printf("Visiting DefaultStatement\n");
+ s.statement.accept(this);
+ }
+
+ override void visit(AST.GotoCaseStatement s)
+ {
+ //printf("Visiting GotoCaseStatement\n");
+ if (s.exp)
+ s.exp.accept(this);
+ }
+
+ override void visit(AST.ReturnStatement s)
+ {
+ //printf("Visiting ReturnStatement\n");
+ if (s.exp)
+ s.exp.accept(this);
+ }
+
+ override void visit(AST.SynchronizedStatement s)
+ {
+ //printf("Visiting SynchronizedStatement\n");
+ if (s.exp)
+ s.exp.accept(this);
+ if (s._body)
+ s._body.accept(this);
+ }
+
+ override void visit(AST.WithStatement s)
+ {
+ //printf("Visiting WithStatement\n");
+ s.exp.accept(this);
+ if (s._body)
+ s._body.accept(this);
+ }
+
+ override void visit(AST.TryCatchStatement s)
+ {
+ //printf("Visiting TryCatchStatement\n");
+ if (s._body)
+ s._body.accept(this);
+ foreach (c; *s.catches)
+ visit(c);
+ }
+
+ override void visit(AST.TryFinallyStatement s)
+ {
+ //printf("Visiting TryFinallyStatement\n");
+ s._body.accept(this);
+ s.finalbody.accept(this);
+ }
+
+ override void visit(AST.ScopeGuardStatement s)
+ {
+ //printf("Visiting ScopeGuardStatement\n");
+ s.statement.accept(this);
+ }
+
+ override void visit(AST.ThrowStatement s)
+ {
+ //printf("Visiting ThrowStatement\n");
+ s.exp.accept(this);
+ }
+
+ override void visit(AST.LabelStatement s)
+ {
+ //printf("Visiting LabelStatement\n");
+ if (s.statement)
+ s.statement.accept(this);
+ }
+
+ override void visit(AST.ImportStatement s)
+ {
+ //printf("Visiting ImportStatement\n");
+ foreach (imp; *s.imports)
+ imp.accept(this);
+ }
+
+ void visit(AST.Catch c)
+ {
+ //printf("Visiting Catch\n");
+ if (c.type)
+ visitType(c.type);
+ if (c.handler)
+ c.handler.accept(this);
+ }
+
+// Type Nodes
+//============================================================
+
+ void visitType(AST.Type t)
+ {
+ //printf("Visiting Type\n");
+ if (!t)
+ return;
+ if (auto tf = t.isTypeFunction())
+ {
+ visitFunctionType(tf, null);
+ return;
+ }
+ else
+ t.accept(this);
+ }
+
+ void visitFunctionType(AST.TypeFunction t, AST.TemplateDeclaration td)
+ {
+ if (t.next)
+ visitType(t.next);
+ if (td)
+ {
+ foreach (p; *td.origParameters)
+ p.accept(this);
+ }
+ visitParameters(t.parameterList.parameters);
+ }
+
+ void visitParameters(AST.Parameters* parameters)
+ {
+ if (parameters)
+ {
+ size_t dim = AST.Parameter.dim(parameters);
+ foreach(i; 0..dim)
+ {
+ AST.Parameter fparam = AST.Parameter.getNth(parameters, i);
+ fparam.accept(this);
+ }
+ }
+ }
+
+ override void visit(AST.TypeVector t)
+ {
+ //printf("Visiting TypeVector\n");
+ if (!t.basetype)
+ return;
+ t.basetype.accept(this);
+ }
+
+ override void visit(AST.TypeSArray t)
+ {
+ //printf("Visiting TypeSArray\n");
+ t.next.accept(this);
+ }
+
+ override void visit(AST.TypeDArray t)
+ {
+ //printf("Visiting TypeDArray\n");
+ t.next.accept(this);
+ }
+
+ override void visit(AST.TypeAArray t)
+ {
+ //printf("Visiting TypeAArray\n");
+ t.next.accept(this);
+ t.index.accept(this);
+ }
+
+ override void visit(AST.TypePointer t)
+ {
+ //printf("Visiting TypePointer\n");
+ if (auto tf = t.next.isTypeFunction())
+ {
+ visitFunctionType(tf, null);
+ }
+ else
+ t.next.accept(this);
+ }
+
+ override void visit(AST.TypeReference t)
+ {
+ //printf("Visiting TypeReference\n");
+ t.next.accept(this);
+ }
+
+ override void visit(AST.TypeFunction t)
+ {
+ //printf("Visiting TypeFunction\n");
+ visitFunctionType(t, null);
+ }
+
+ override void visit(AST.TypeDelegate t)
+ {
+ //printf("Visiting TypeDelegate\n");
+ visitFunctionType(t.next.isTypeFunction(), null);
+ }
+
+ void visitTypeQualified(AST.TypeQualified t)
+ {
+ //printf("Visiting TypeQualified\n");
+ foreach (id; t.idents)
+ {
+ if (id.dyncast() == DYNCAST.dsymbol)
+ (cast(AST.TemplateInstance)id).accept(this);
+ else if (id.dyncast() == DYNCAST.expression)
+ (cast(AST.Expression)id).accept(this);
+ else if (id.dyncast() == DYNCAST.type)
+ (cast(AST.Type)id).accept(this);
+ }
+ }
+
+ override void visit(AST.TypeIdentifier t)
+ {
+ //printf("Visiting TypeIdentifier\n");
+ visitTypeQualified(t);
+ }
+
+ override void visit(AST.TypeInstance t)
+ {
+ //printf("Visiting TypeInstance\n");
+ t.tempinst.accept(this);
+ visitTypeQualified(t);
+ }
+
+ override void visit(AST.TypeTypeof t)
+ {
+ //printf("Visiting TypeTypeof\n");
+ t.exp.accept(this);
+ visitTypeQualified(t);
+ }
+
+ override void visit(AST.TypeReturn t)
+ {
+ //printf("Visiting TypeReturn\n");
+ visitTypeQualified(t);
+ }
+
+ override void visit(AST.TypeTuple t)
+ {
+ //printf("Visiting TypeTuple\n");
+ visitParameters(t.arguments);
+ }
+
+ override void visit(AST.TypeSlice t)
+ {
+ //printf("Visiting TypeSlice\n");
+ t.next.accept(this);
+ t.lwr.accept(this);
+ t.upr.accept(this);
+ }
+
+ override void visit(AST.TypeTraits t)
+ {
+ t.exp.accept(this);
+ }
+
+ override void visit(AST.TypeMixin t)
+ {
+ visitArgs(t.exps);
+ }
+
+// Miscellaneous
+//========================================================
+
+ override void visit(AST.StaticAssert s)
+ {
+ //printf("Visiting StaticAssert\n");
+ s.exp.accept(this);
+ if (s.msg)
+ s.msg.accept(this);
+ }
+
+ override void visit(AST.EnumMember em)
+ {
+ //printf("Visiting EnumMember\n");
+ if (em.type)
+ visitType(em.type);
+ if (em.value)
+ em.value.accept(this);
+ }
+
+// Declarations
+//=========================================================
+ void visitAttribDeclaration(AST.AttribDeclaration d)
+ {
+ if (d.decl)
+ foreach (de; *d.decl)
+ de.accept(this);
+ }
+
+ override void visit(AST.AttribDeclaration d)
+ {
+ //printf("Visiting AttribDeclaration\n");
+ visitAttribDeclaration(d);
+ }
+
+ override void visit(AST.StorageClassDeclaration d)
+ {
+ //printf("Visiting StorageClassDeclaration\n");
+ visitAttribDeclaration(cast(AST.AttribDeclaration)d);
+ }
+
+ override void visit(AST.DeprecatedDeclaration d)
+ {
+ //printf("Visiting DeprecatedDeclaration\n");
+ d.msg.accept(this);
+ visitAttribDeclaration(cast(AST.AttribDeclaration)d);
+ }
+
+ override void visit(AST.LinkDeclaration d)
+ {
+ //printf("Visiting LinkDeclaration\n");
+ visitAttribDeclaration(cast(AST.AttribDeclaration)d);
+ }
+
+ override void visit(AST.CPPMangleDeclaration d)
+ {
+ //printf("Visiting CPPMangleDeclaration\n");
+ visitAttribDeclaration(cast(AST.AttribDeclaration)d);
+ }
+
+ override void visit(AST.VisibilityDeclaration d)
+ {
+ //printf("Visiting VisibilityDeclaration\n");
+ visitAttribDeclaration(cast(AST.AttribDeclaration)d);
+ }
+
+ override void visit(AST.AlignDeclaration d)
+ {
+ //printf("Visiting AlignDeclaration\n");
+ visitAttribDeclaration(cast(AST.AttribDeclaration)d);
+ }
+
+ override void visit(AST.AnonDeclaration d)
+ {
+ //printf("Visiting AnonDeclaration\n");
+ visitAttribDeclaration(cast(AST.AttribDeclaration)d);
+ }
+
+ override void visit(AST.PragmaDeclaration d)
+ {
+ //printf("Visiting PragmaDeclaration\n");
+ if (d.args && d.args.dim)
+ visitArgs(d.args);
+ visitAttribDeclaration(cast(AST.AttribDeclaration)d);
+ }
+
+ override void visit(AST.ConditionalDeclaration d)
+ {
+ //printf("Visiting ConditionalDeclaration\n");
+ d.condition.accept(this);
+ if (d.decl)
+ foreach (de; *d.decl)
+ de.accept(this);
+ if (d.elsedecl)
+ foreach (de; *d.elsedecl)
+ de.accept(this);
+ }
+
+ override void visit(AST.CompileDeclaration d)
+ {
+ //printf("Visiting compileDeclaration\n");
+ visitArgs(d.exps);
+ }
+
+ override void visit(AST.UserAttributeDeclaration d)
+ {
+ //printf("Visiting UserAttributeDeclaration\n");
+ visitArgs(d.atts);
+ visitAttribDeclaration(cast(AST.AttribDeclaration)d);
+ }
+
+ void visitFuncBody(AST.FuncDeclaration f)
+ {
+ //printf("Visiting funcBody\n");
+ if (f.frequires)
+ {
+ foreach (frequire; *f.frequires)
+ {
+ frequire.accept(this);
+ }
+ }
+ if (f.fensures)
+ {
+ foreach (fensure; *f.fensures)
+ {
+ fensure.ensure.accept(this);
+ }
+ }
+ if (f.fbody)
+ {
+ f.fbody.accept(this);
+ }
+ }
+
+ void visitBaseClasses(AST.ClassDeclaration d)
+ {
+ //printf("Visiting ClassDeclaration\n");
+ if (!d || !d.baseclasses.dim)
+ return;
+ foreach (b; *d.baseclasses)
+ visitType(b.type);
+ }
+
+ bool visitEponymousMember(AST.TemplateDeclaration d)
+ {
+ //printf("Visiting EponymousMember\n");
+ if (!d.members || d.members.dim != 1)
+ return false;
+ AST.Dsymbol onemember = (*d.members)[0];
+ if (onemember.ident != d.ident)
+ return false;
+
+ if (AST.FuncDeclaration fd = onemember.isFuncDeclaration())
+ {
+ assert(fd.type);
+ visitFunctionType(fd.type.isTypeFunction(), d);
+ if (d.constraint)
+ d.constraint.accept(this);
+ visitFuncBody(fd);
+
+ return true;
+ }
+
+ if (AST.AggregateDeclaration ad = onemember.isAggregateDeclaration())
+ {
+ visitTemplateParameters(d.parameters);
+ if (d.constraint)
+ d.constraint.accept(this);
+ visitBaseClasses(ad.isClassDeclaration());
+
+ if (ad.members)
+ foreach (s; *ad.members)
+ s.accept(this);
+
+ return true;
+ }
+
+ if (AST.VarDeclaration vd = onemember.isVarDeclaration())
+ {
+ if (d.constraint)
+ return false;
+ if (vd.type)
+ visitType(vd.type);
+ visitTemplateParameters(d.parameters);
+ if (vd._init)
+ {
+ // note similarity of this code with visitVarDecl()
+ if (auto ie = vd._init.isExpInitializer())
+ {
+ if (auto ce = ie.exp.isConstructExp())
+ ce.e2.accept(this);
+ else if (auto be = ie.exp.isBlitExp())
+ be.e2.accept(this);
+ else
+ vd._init.accept(this);
+ }
+ else
+ vd._init.accept(this);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void visitTemplateParameters(AST.TemplateParameters* parameters)
+ {
+ if (!parameters || !parameters.dim)
+ return;
+ foreach (p; *parameters)
+ p.accept(this);
+ }
+
+ override void visit(AST.TemplateDeclaration d)
+ {
+ //printf("Visiting TemplateDeclaration\n");
+ if (visitEponymousMember(d))
+ return;
+
+ visitTemplateParameters(d.parameters);
+ if (d.constraint)
+ d.constraint.accept(this);
+
+ foreach (s; *d.members)
+ s.accept(this);
+ }
+
+ void visitObject(RootObject oarg)
+ {
+ if (auto t = AST.isType(oarg))
+ {
+ visitType(t);
+ }
+ else if (auto e = AST.isExpression(oarg))
+ {
+ e.accept(this);
+ }
+ else if (auto v = AST.isTuple(oarg))
+ {
+ auto args = &v.objects;
+ foreach (arg; *args)
+ visitObject(arg);
+ }
+ }
+
+ void visitTiargs(AST.TemplateInstance ti)
+ {
+ //printf("Visiting tiargs\n");
+ if (!ti.tiargs)
+ return;
+ foreach (arg; *ti.tiargs)
+ {
+ visitObject(arg);
+ }
+ }
+
+ override void visit(AST.TemplateInstance ti)
+ {
+ //printf("Visiting TemplateInstance\n");
+ visitTiargs(ti);
+ }
+
+ override void visit(AST.TemplateMixin tm)
+ {
+ //printf("Visiting TemplateMixin\n");
+ visitType(tm.tqual);
+ visitTiargs(tm);
+ }
+
+ override void visit(AST.EnumDeclaration d)
+ {
+ //printf("Visiting EnumDeclaration\n");
+ if (d.memtype)
+ visitType(d.memtype);
+ if (!d.members)
+ return;
+ foreach (em; *d.members)
+ {
+ if (!em)
+ continue;
+ em.accept(this);
+ }
+ }
+
+ override void visit(AST.Nspace d)
+ {
+ //printf("Visiting Nspace\n");
+ foreach(s; *d.members)
+ s.accept(this);
+ }
+
+ override void visit(AST.StructDeclaration d)
+ {
+ //printf("Visiting StructDeclaration\n");
+ if (!d.members)
+ return;
+ foreach (s; *d.members)
+ s.accept(this);
+ }
+
+ override void visit(AST.ClassDeclaration d)
+ {
+ //printf("Visiting ClassDeclaration\n");
+ visitBaseClasses(d);
+ if (d.members)
+ foreach (s; *d.members)
+ s.accept(this);
+ }
+
+ override void visit(AST.AliasDeclaration d)
+ {
+ //printf("Visting AliasDeclaration\n");
+ if (d.aliassym)
+ d.aliassym.accept(this);
+ else
+ visitType(d.type);
+ }
+
+ override void visit(AST.AliasAssign d)
+ {
+ //printf("Visting AliasAssign\n");
+ if (d.aliassym)
+ d.aliassym.accept(this);
+ else
+ visitType(d.type);
+ }
+
+ override void visit(AST.VarDeclaration d)
+ {
+ //printf("Visiting VarDeclaration\n");
+ visitVarDecl(d);
+ }
+
+ override void visit(AST.FuncDeclaration f)
+ {
+ //printf("Visiting FuncDeclaration\n");
+ auto tf = f.type.isTypeFunction();
+ visitType(tf);
+ visitFuncBody(f);
+ }
+
+ override void visit(AST.FuncLiteralDeclaration f)
+ {
+ //printf("Visiting FuncLiteralDeclaration\n");
+ if (f.type.ty == Terror)
+ return;
+ auto tf = f.type.isTypeFunction();
+ if (!f.inferRetType && tf.next)
+ visitType(tf.next);
+ visitParameters(tf.parameterList.parameters);
+ AST.CompoundStatement cs = f.fbody.isCompoundStatement();
+ AST.Statement s = !cs ? f.fbody : null;
+ AST.ReturnStatement rs = s ? s.isReturnStatement() : null;
+ if (rs && rs.exp)
+ rs.exp.accept(this);
+ else
+ visitFuncBody(f);
+ }
+
+ override void visit(AST.PostBlitDeclaration d)
+ {
+ //printf("Visiting PostBlitDeclaration\n");
+ visitFuncBody(d);
+ }
+
+ override void visit(AST.DtorDeclaration d)
+ {
+ //printf("Visiting DtorDeclaration\n");
+ visitFuncBody(d);
+ }
+
+ override void visit(AST.StaticCtorDeclaration d)
+ {
+ //printf("Visiting StaticCtorDeclaration\n");
+ visitFuncBody(d);
+ }
+
+ override void visit(AST.StaticDtorDeclaration d)
+ {
+ //printf("Visiting StaticDtorDeclaration\n");
+ visitFuncBody(d);
+ }
+
+ override void visit(AST.InvariantDeclaration d)
+ {
+ //printf("Visiting InvariantDeclaration\n");
+ visitFuncBody(d);
+ }
+
+ override void visit(AST.UnitTestDeclaration d)
+ {
+ //printf("Visiting UnitTestDeclaration\n");
+ visitFuncBody(d);
+ }
+
+ override void visit(AST.NewDeclaration d)
+ {
+ //printf("Visiting NewDeclaration\n");
+ }
+
+// Initializers
+//============================================================
+
+ override void visit(AST.StructInitializer si)
+ {
+ //printf("Visiting StructInitializer\n");
+ foreach (i, const id; si.field)
+ if (auto iz = si.value[i])
+ iz.accept(this);
+ }
+
+ override void visit(AST.ArrayInitializer ai)
+ {
+ //printf("Visiting ArrayInitializer\n");
+ foreach (i, ex; ai.index)
+ {
+ if (ex)
+ ex.accept(this);
+ if (auto iz = ai.value[i])
+ iz.accept(this);
+ }
+ }
+
+ override void visit(AST.ExpInitializer ei)
+ {
+ //printf("Visiting ExpInitializer\n");
+ ei.exp.accept(this);
+ }
+
+ override void visit(AST.CInitializer ci)
+ {
+ //printf("Visiting CInitializer\n");
+ foreach (di; ci.initializerList)
+ {
+ foreach (des; (*di.designatorList)[])
+ {
+ if (des.exp)
+ des.exp.accept(this);
+ }
+ di.initializer.accept(this);
+ }
+ }
+
+// Expressions
+//===================================================
+
+ override void visit(AST.ArrayLiteralExp e)
+ {
+ //printf("Visiting ArrayLiteralExp\n");
+ visitArgs(e.elements, e.basis);
+ }
+
+ override void visit(AST.AssocArrayLiteralExp e)
+ {
+ //printf("Visiting AssocArrayLiteralExp\n");
+ foreach (i, key; *e.keys)
+ {
+ key.accept(this);
+ ((*e.values)[i]).accept(this);
+ }
+ }
+
+ override void visit(AST.TypeExp e)
+ {
+ //printf("Visiting TypeExp\n");
+ visitType(e.type);
+ }
+
+ override void visit(AST.ScopeExp e)
+ {
+ //printf("Visiting ScopeExp\n");
+ if (e.sds.isTemplateInstance())
+ e.sds.accept(this);
+ }
+
+ override void visit(AST.NewExp e)
+ {
+ //printf("Visiting NewExp\n");
+ if (e.thisexp)
+ e.thisexp.accept(this);
+ if (e.newargs && e.newargs.dim)
+ visitArgs(e.newargs);
+ visitType(e.newtype);
+ if (e.arguments && e.arguments.dim)
+ visitArgs(e.arguments);
+ }
+
+ override void visit(AST.NewAnonClassExp e)
+ {
+ //printf("Visiting NewAnonClassExp\n");
+ if (e.thisexp)
+ e.thisexp.accept(this);
+ if (e.newargs && e.newargs.dim)
+ visitArgs(e.newargs);
+ if (e.arguments && e.arguments.dim)
+ visitArgs(e.arguments);
+ if (e.cd)
+ e.cd.accept(this);
+ }
+
+ override void visit(AST.TupleExp e)
+ {
+ //printf("Visiting TupleExp\n");
+ if (e.e0)
+ e.e0.accept(this);
+ visitArgs(e.exps);
+ }
+
+ override void visit(AST.FuncExp e)
+ {
+ //printf("Visiting FuncExp\n");
+ e.fd.accept(this);
+ }
+
+ override void visit(AST.DeclarationExp e)
+ {
+ //printf("Visiting DeclarationExp\n");
+ if (auto v = e.declaration.isVarDeclaration())
+ visitVarDecl(v);
+ else
+ e.declaration.accept(this);
+ }
+
+ override void visit(AST.TypeidExp e)
+ {
+ //printf("Visiting TypeidExp\n");
+ visitObject(e.obj);
+ }
+
+ override void visit(AST.TraitsExp e)
+ {
+ //printf("Visiting TraitExp\n");
+ if (e.args)
+ foreach (arg; *e.args)
+ visitObject(arg);
+ }
+
+ override void visit(AST.IsExp e)
+ {
+ //printf("Visiting IsExp\n");
+ visitType(e.targ);
+ if (e.tspec)
+ visitType(e.tspec);
+ if (e.parameters && e.parameters.dim)
+ visitTemplateParameters(e.parameters);
+ }
+
+ override void visit(AST.UnaExp e)
+ {
+ //printf("Visiting UnaExp\n");
+ e.e1.accept(this);
+ }
+
+ override void visit(AST.BinExp e)
+ {
+ //printf("Visiting BinExp\n");
+ e.e1.accept(this);
+ e.e2.accept(this);
+ }
+
+ override void visit(AST.MixinExp e)
+ {
+ //printf("Visiting MixinExp\n");
+ visitArgs(e.exps);
+ }
+
+ override void visit(AST.ImportExp e)
+ {
+ //printf("Visiting ImportExp\n");
+ e.e1.accept(this);
+ }
+
+ override void visit(AST.AssertExp e)
+ {
+ //printf("Visiting AssertExp\n");
+ e.e1.accept(this);
+ if (e.msg)
+ e.msg.accept(this);
+ }
+
+ override void visit(AST.DotIdExp e)
+ {
+ //printf("Visiting DotIdExp\n");
+ e.e1.accept(this);
+ }
+
+ override void visit(AST.DotTemplateInstanceExp e)
+ {
+ //printf("Visiting DotTemplateInstanceExp\n");
+ e.e1.accept(this);
+ e.ti.accept(this);
+ }
+
+ override void visit(AST.CallExp e)
+ {
+ //printf("Visiting CallExp\n");
+ e.e1.accept(this);
+ visitArgs(e.arguments);
+ }
+
+ override void visit(AST.PtrExp e)
+ {
+ //printf("Visiting PtrExp\n");
+ e.e1.accept(this);
+ }
+
+ override void visit(AST.DeleteExp e)
+ {
+ //printf("Visiting DeleteExp\n");
+ e.e1.accept(this);
+ }
+
+ override void visit(AST.CastExp e)
+ {
+ //printf("Visiting CastExp\n");
+ if (e.to)
+ visitType(e.to);
+ e.e1.accept(this);
+ }
+
+ override void visit(AST.IntervalExp e)
+ {
+ //printf("Visiting IntervalExp\n");
+ e.lwr.accept(this);
+ e.upr.accept(this);
+ }
+
+ override void visit(AST.ArrayExp e)
+ {
+ //printf("Visiting ArrayExp\n");
+ e.e1.accept(this);
+ visitArgs(e.arguments);
+ }
+
+ override void visit(AST.PostExp e)
+ {
+ //printf("Visiting PostExp\n");
+ e.e1.accept(this);
+ }
+
+ override void visit(AST.CondExp e)
+ {
+ //printf("Visiting CondExp\n");
+ e.econd.accept(this);
+ e.e1.accept(this);
+ e.e2.accept(this);
+ }
+
+ override void visit(AST.GenericExp e)
+ {
+ //printf("Visiting GenericExp\n");
+ e.cntlExp.accept(this);
+ foreach (i; 0 .. (*e.types).length)
+ {
+ if (auto t = (*e.types)[i]) // null means default case
+ t.accept(this);
+ (*e.exps )[i].accept(this);
+ }
+ }
+
+// Template Parameter
+//===========================================================
+
+ override void visit(AST.TemplateTypeParameter tp)
+ {
+ //printf("Visiting TemplateTypeParameter\n");
+ if (tp.specType)
+ visitType(tp.specType);
+ if (tp.defaultType)
+ visitType(tp.defaultType);
+ }
+
+ override void visit(AST.TemplateThisParameter tp)
+ {
+ //printf("Visiting TemplateThisParameter\n");
+ visit(cast(AST.TemplateTypeParameter)tp);
+ }
+
+ override void visit(AST.TemplateAliasParameter tp)
+ {
+ //printf("Visiting TemplateAliasParameter\n");
+ if (tp.specType)
+ visitType(tp.specType);
+ if (tp.specAlias)
+ visitObject(tp.specAlias);
+ if (tp.defaultAlias)
+ visitObject(tp.defaultAlias);
+ }
+
+ override void visit(AST.TemplateValueParameter tp)
+ {
+ //printf("Visiting TemplateValueParameter\n");
+ visitType(tp.valType);
+ if (tp.specValue)
+ tp.specValue.accept(this);
+ if (tp.defaultValue)
+ tp.defaultValue.accept(this);
+ }
+
+//===========================================================
+
+ override void visit(AST.StaticIfCondition c)
+ {
+ //printf("Visiting StaticIfCondition\n");
+ c.exp.accept(this);
+ }
+
+ override void visit(AST.Parameter p)
+ {
+ //printf("Visiting Parameter\n");
+ visitType(p.type);
+ if (p.defaultArg)
+ p.defaultArg.accept(this);
+ }
+
+ override void visit(AST.Module m)
+ {
+ //printf("Visiting Module\n");
+ foreach (s; *m.members)
+ {
+ s.accept(this);
+ }
+ }
+}
diff --git a/gcc/d/dmd/typesem.c b/gcc/d/dmd/typesem.c
deleted file mode 100644
index 31e93c2..0000000
--- a/gcc/d/dmd/typesem.c
+++ /dev/null
@@ -1,1462 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- */
-
-#include "root/dsystem.h"
-#include "root/checkedint.h"
-
-#include "mtype.h"
-#include "aggregate.h"
-#include "enum.h"
-#include "errors.h"
-#include "expression.h"
-#include "hdrgen.h"
-#include "id.h"
-#include "init.h"
-#include "parse.h"
-#include "scope.h"
-#include "target.h"
-#include "template.h"
-#include "visitor.h"
-
-Expression *typeToExpression(Type *t);
-Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
-bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
-char *MODtoChars(MOD mod);
-
-class TypeToExpressionVisitor : public Visitor
-{
-public:
- Expression *result;
- Type *itype;
-
- TypeToExpressionVisitor(Type *itype)
- {
- this->result = NULL;
- this->itype = itype;
- }
-
- void visit(Type *)
- {
- result = NULL;
- }
-
- void visit(TypeSArray *t)
- {
- Expression *e = typeToExpression(t->next);
- if (e)
- e = new ArrayExp(t->dim->loc, e, t->dim);
- result = e;
- }
-
- void visit(TypeAArray *t)
- {
- Expression *e = typeToExpression(t->next);
- if (e)
- {
- Expression *ei = typeToExpression(t->index);
- if (ei)
- {
- result = new ArrayExp(t->loc, e, ei);
- return;
- }
- }
- result = NULL;
- }
-
- void visit(TypeIdentifier *t)
- {
- result = typeToExpressionHelper(t, new IdentifierExp(t->loc, t->ident));
- }
-
- void visit(TypeInstance *t)
- {
- result = typeToExpressionHelper(t, new ScopeExp(t->loc, t->tempinst));
- }
-
- void visit(TypeMixin *t)
- {
- result = new TypeExp(t->loc, t);
- }
-};
-
-/* We've mistakenly parsed this as a type.
- * Redo it as an Expression.
- * NULL if cannot.
- */
-Expression *typeToExpression(Type *t)
-{
- if (t->mod)
- return NULL;
- TypeToExpressionVisitor v = TypeToExpressionVisitor(t);
- t->accept(&v);
- return v.result;
-}
-
-/* Helper function for `typeToExpression`. Contains common code
- * for TypeQualified derived classes.
- */
-Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i)
-{
- //printf("toExpressionHelper(e = %s %s)\n", Token::toChars(e->op), e->toChars());
- for (; i < t->idents.length; i++)
- {
- RootObject *id = t->idents[i];
- //printf("\t[%d] e: '%s', id: '%s'\n", i, e->toChars(), id->toChars());
-
- switch (id->dyncast())
- {
- case DYNCAST_IDENTIFIER:
- {
- // ... '. ident'
- e = new DotIdExp(e->loc, e, (Identifier *)id);
- break;
- }
- case DYNCAST_DSYMBOL:
- {
- // ... '. name!(tiargs)'
- TemplateInstance *ti = ((Dsymbol *)id)->isTemplateInstance();
- assert(ti);
- e = new DotTemplateInstanceExp(e->loc, e, ti->name, ti->tiargs);
- break;
- }
- case DYNCAST_TYPE: // Bugzilla 1215
- {
- // ... '[type]'
- e = new ArrayExp(t->loc, e, new TypeExp(t->loc, (Type *)id));
- break;
- }
- case DYNCAST_EXPRESSION: // Bugzilla 1215
- {
- // ... '[expr]'
- e = new ArrayExp(t->loc, e, (Expression *)id);
- break;
- }
- default:
- assert(0);
- }
- }
- return e;
-}
-
-/**************************
- * This evaluates exp while setting length to be the number
- * of elements in the tuple t.
- */
-static Expression *semanticLength(Scope *sc, Type *t, Expression *exp)
-{
- if (t->ty == Ttuple)
- {
- ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t);
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
-
- sc = sc->startCTFE();
- exp = expressionSemantic(exp, sc);
- sc = sc->endCTFE();
-
- sc->pop();
- }
- else
- {
- sc = sc->startCTFE();
- exp = expressionSemantic(exp, sc);
- sc = sc->endCTFE();
- }
-
- return exp;
-}
-
-static Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp)
-{
- ScopeDsymbol *sym = new ArrayScopeSymbol(sc, s);
- sym->parent = sc->scopesym;
- sc = sc->push(sym);
-
- sc = sc->startCTFE();
- exp = expressionSemantic(exp, sc);
- sc = sc->endCTFE();
-
- sc->pop();
- return exp;
-}
-
-/******************************************
- * Compile the MixinType, returning the type or expression AST.
- *
- * Doesn't run semantic() on the returned object.
- * Params:
- * tm = mixin to compile as a type or expression
- * loc = location for error messages
- * sc = context
- * Return:
- * null if error, else RootObject AST as parsed
- */
-RootObject *compileTypeMixin(TypeMixin *tm, Loc loc, Scope *sc)
-{
- OutBuffer buf;
- if (expressionsToString(buf, sc, tm->exps))
- return NULL;
-
- const unsigned errors = global.errors;
- const size_t len = buf.length();
- const char *str = buf.extractChars();
- Parser p(loc, sc->_module, (const utf8_t *)str, len, false);
- p.nextToken();
- //printf("p.loc.linnum = %d\n", p.loc.linnum);
-
- RootObject *o = p.parseTypeOrAssignExp(TOKeof);
- if (errors != global.errors)
- {
- assert(global.errors != errors); // should have caught all these cases
- return NULL;
- }
- if (p.token.value != TOKeof)
- {
- ::error(loc, "incomplete mixin type `%s`", str);
- return NULL;
- }
-
- Type *t = isType(o);
- Expression *e = t ? typeToExpression(t) : isExpression(o);
-
- return (!e && t) ? (RootObject *)t : (RootObject *)e;
-}
-
-/******************************************
- * Perform semantic analysis on a type.
- * Params:
- * type = Type AST node
- * loc = the location of the type
- * sc = context
- * Returns:
- * `Type` with completed semantic analysis, `Terror` if errors
- * were encountered
- */
-Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
-{
- class TypeSemanticVisitor : public Visitor
- {
- public:
- Loc loc;
- Scope *sc;
- Type *result;
-
- TypeSemanticVisitor(const Loc &loc, Scope *sc)
- {
- this->loc = loc;
- this->sc = sc;
- this->result = NULL;
- }
-
- private:
- void error()
- {
- result = Type::terror;
- }
-
- public:
- void visit(Type *t)
- {
- if (t->ty == Tint128 || t->ty == Tuns128)
- {
- ::error(loc, "cent and ucent types not implemented");
- return error();
- }
-
- result = t->merge();
- }
-
- void visit(TypeVector *mtype)
- {
- unsigned int errors = global.errors;
- mtype->basetype = typeSemantic(mtype->basetype, loc, sc);
- if (errors != global.errors)
- return error();
- mtype->basetype = mtype->basetype->toBasetype()->mutableOf();
- if (mtype->basetype->ty != Tsarray)
- {
- ::error(loc, "T in __vector(T) must be a static array, not %s", mtype->basetype->toChars());
- return error();
- }
- TypeSArray *t = (TypeSArray *)mtype->basetype;
- int sz = (int)t->size(loc);
- switch (target.isVectorTypeSupported(sz, t->nextOf()))
- {
- case 0: // valid
- break;
- case 1: // no support at all
- ::error(loc, "SIMD vector types not supported on this platform");
- return error();
- case 2: // invalid base type
- ::error(loc, "vector type %s is not supported on this platform", mtype->toChars());
- return error();
- case 3: // invalid size
- ::error(loc, "%d byte vector type %s is not supported on this platform", sz, mtype->toChars());
- return error();
- default:
- assert(0);
- }
- result = mtype->merge();
- }
-
- void visit(TypeSArray *mtype)
- {
- //printf("TypeSArray::semantic() %s\n", mtype->toChars());
-
- Type *t;
- Expression *e;
- Dsymbol *s;
- mtype->next->resolve(loc, sc, &e, &t, &s);
-
- if (mtype->dim && s && s->isTupleDeclaration())
- {
- TupleDeclaration *sd = s->isTupleDeclaration();
-
- mtype->dim = semanticLength(sc, sd, mtype->dim);
- mtype->dim = mtype->dim->ctfeInterpret();
- if(mtype->dim->op == TOKerror)
- return error();
-
- uinteger_t d = mtype->dim->toUInteger();
- if (d >= sd->objects->length)
- {
- ::error(loc, "tuple index %llu exceeds %llu", (unsigned long long)d, (unsigned long long)sd->objects->length);
- return error();
- }
-
- RootObject *o = (*sd->objects)[(size_t)d];
- if (o->dyncast() != DYNCAST_TYPE)
- {
- ::error(loc, "%s is not a type", mtype->toChars());
- return error();
- }
- result = ((Type *)o)->addMod(mtype->mod);
- return;
- }
-
- if (t && t->ty == Terror)
- return error();
-
- Type *tn = typeSemantic(mtype->next, loc, sc);
- if (tn->ty == Terror)
- return error();
-
- Type *tbn = tn->toBasetype();
- if (mtype->dim)
- {
- unsigned int errors = global.errors;
- mtype->dim = semanticLength(sc, tbn, mtype->dim);
- if (errors != global.errors)
- return error();
-
- mtype->dim = mtype->dim->optimize(WANTvalue);
- mtype->dim = mtype->dim->ctfeInterpret();
- if (mtype->dim->op == TOKerror)
- return error();
- errors = global.errors;
- dinteger_t d1 = mtype->dim->toInteger();
- if (errors != global.errors)
- return error();
-
- mtype->dim = mtype->dim->implicitCastTo(sc, Type::tsize_t);
- mtype->dim = mtype->dim->optimize(WANTvalue);
- if (mtype->dim->op == TOKerror)
- return error();
- errors = global.errors;
- dinteger_t d2 = mtype->dim->toInteger();
- if (errors != global.errors)
- return error();
-
- if (mtype->dim->op == TOKerror)
- return error();
-
- if (d1 != d2)
- {
- Loverflow:
- ::error(loc, "%s size %llu * %llu exceeds 0x%llx size limit for static array",
- mtype->toChars(), (unsigned long long)tbn->size(loc), (unsigned long long)d1, target.maxStaticDataSize);
- return error();
- }
-
- Type *tbx = tbn->baseElemOf();
- if ((tbx->ty == Tstruct && !((TypeStruct *)tbx)->sym->members) ||
- (tbx->ty == Tenum && !((TypeEnum *)tbx)->sym->members))
- {
- /* To avoid meaningless error message, skip the total size limit check
- * when the bottom of element type is opaque.
- */
- }
- else if (tbn->isTypeBasic() ||
- tbn->ty == Tpointer ||
- tbn->ty == Tarray ||
- tbn->ty == Tsarray ||
- tbn->ty == Taarray ||
- (tbn->ty == Tstruct && (((TypeStruct *)tbn)->sym->sizeok == SIZEOKdone)) ||
- tbn->ty == Tclass)
- {
- /* Only do this for types that don't need to have semantic()
- * run on them for the size, since they may be forward referenced.
- */
- bool overflow = false;
- if (mulu(tbn->size(loc), d2, overflow) >= target.maxStaticDataSize || overflow)
- goto Loverflow;
- }
- }
- switch (tbn->ty)
- {
- case Ttuple:
- {
- // Index the tuple to get the type
- assert(mtype->dim);
- TypeTuple *tt = (TypeTuple *)tbn;
- uinteger_t d = mtype->dim->toUInteger();
- if (d >= tt->arguments->length)
- {
- ::error(loc, "tuple index %llu exceeds %llu", (unsigned long long)d, (unsigned long long)tt->arguments->length);
- return error();
- }
- Type *telem = (*tt->arguments)[(size_t)d]->type;
- result = telem->addMod(mtype->mod);
- return;
- }
- case Tfunction:
- case Tnone:
- ::error(loc, "cannot have array of %s", tbn->toChars());
- return error();
- default:
- break;
- }
- if (tbn->isscope())
- {
- ::error(loc, "cannot have array of scope %s", tbn->toChars());
- return error();
- }
-
- /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
- * and const(T)[3] become const(T[3])
- */
- mtype->next = tn;
- mtype->transitive();
- result = mtype->addMod(tn->mod)->merge();
- }
-
- void visit(TypeDArray *mtype)
- {
- Type *tn = typeSemantic(mtype->next, loc,sc);
- Type *tbn = tn->toBasetype();
- switch (tbn->ty)
- {
- case Ttuple:
- result = tbn;
- return;
- case Tfunction:
- case Tnone:
- ::error(loc, "cannot have array of %s", tbn->toChars());
- return error();
- case Terror:
- return error();
- default:
- break;
- }
- if (tn->isscope())
- {
- ::error(loc, "cannot have array of scope %s", tn->toChars());
- return error();
- }
- mtype->next = tn;
- mtype->transitive();
- result = mtype->merge();
- }
-
- void visit(TypeAArray *mtype)
- {
- //printf("TypeAArray::semantic() %s index->ty = %d\n", mtype->toChars(), mtype->index->ty);
- if (mtype->deco)
- {
- result = mtype;
- return;
- }
-
- mtype->loc = loc;
- mtype->sc = sc;
- if (sc)
- sc->setNoFree();
-
- // Deal with the case where we thought the index was a type, but
- // in reality it was an expression.
- if (mtype->index->ty == Tident || mtype->index->ty == Tinstance || mtype->index->ty == Tsarray ||
- mtype->index->ty == Ttypeof || mtype->index->ty == Treturn || mtype->index->ty == Tmixin)
- {
- Expression *e;
- Type *t;
- Dsymbol *s;
-
- mtype->index->resolve(loc, sc, &e, &t, &s);
- if (e)
- {
- // It was an expression -
- // Rewrite as a static array
- TypeSArray *tsa = new TypeSArray(mtype->next, e);
- result = typeSemantic(tsa, loc, sc);
- return;
- }
- else if (t)
- mtype->index = typeSemantic(t, loc, sc);
- else
- {
- mtype->index->error(loc, "index is not a type or an expression");
- return error();
- }
- }
- else
- mtype->index = typeSemantic(mtype->index, loc,sc);
- mtype->index = mtype->index->merge2();
-
- if (mtype->index->nextOf() && !mtype->index->nextOf()->isImmutable())
- {
- mtype->index = mtype->index->constOf()->mutableOf();
- }
-
- switch (mtype->index->toBasetype()->ty)
- {
- case Tfunction:
- case Tvoid:
- case Tnone:
- case Ttuple:
- ::error(loc, "cannot have associative array key of %s", mtype->index->toBasetype()->toChars());
- /* fall through */
- case Terror:
- return error();
- default:
- break;
- }
- Type *tbase = mtype->index->baseElemOf();
- while (tbase->ty == Tarray)
- tbase = tbase->nextOf()->baseElemOf();
- if (tbase->ty == Tstruct)
- {
- /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
- */
- StructDeclaration *sd = ((TypeStruct *)tbase)->sym;
- if (sd->semanticRun < PASSsemanticdone)
- dsymbolSemantic(sd, NULL);
-
- // duplicate a part of StructDeclaration::semanticTypeInfoMembers
- //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", mtype->toChars(), sd->xeq, sd->xerreq, sd->xhash);
- if (sd->xeq &&
- sd->xeq->_scope &&
- sd->xeq->semanticRun < PASSsemantic3done)
- {
- unsigned errors = global.startGagging();
- semantic3(sd->xeq, sd->xeq->_scope);
- if (global.endGagging(errors))
- sd->xeq = sd->xerreq;
- }
-
- const char *s = (mtype->index->toBasetype()->ty != Tstruct) ? "bottom of " : "";
- if (!sd->xeq)
- {
- // If sd->xhash != NULL:
- // sd or its fields have user-defined toHash.
- // AA assumes that its result is consistent with bitwise equality.
- // else:
- // bitwise equality & hashing
- }
- else if (sd->xeq == sd->xerreq)
- {
- if (search_function(sd, Id::eq))
- {
- ::error(loc, "%sAA key type %s does not have `bool opEquals(ref const %s) const`",
- s, sd->toChars(), sd->toChars());
- }
- else
- {
- ::error(loc, "%sAA key type %s does not support const equality",
- s, sd->toChars());
- }
- return error();
- }
- else if (!sd->xhash)
- {
- if (search_function(sd, Id::eq))
- {
- ::error(loc, "%sAA key type %s should have `size_t toHash() const nothrow @safe` if opEquals defined",
- s, sd->toChars());
- }
- else
- {
- ::error(loc, "%sAA key type %s supports const equality but doesn't support const hashing",
- s, sd->toChars());
- }
- return error();
- }
- else
- {
- // defined equality & hashing
- assert(sd->xeq && sd->xhash);
-
- /* xeq and xhash may be implicitly defined by compiler. For example:
- * struct S { int[] arr; }
- * With 'arr' field equality and hashing, compiler will implicitly
- * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
- */
- }
- }
- else if (tbase->ty == Tclass && !((TypeClass *)tbase)->sym->isInterfaceDeclaration())
- {
- ClassDeclaration *cd = ((TypeClass *)tbase)->sym;
- if (cd->semanticRun < PASSsemanticdone)
- dsymbolSemantic(cd, NULL);
-
- if (!ClassDeclaration::object)
- {
- ::error(Loc(), "missing or corrupt object.d");
- fatal();
- }
-
- static FuncDeclaration *feq = NULL;
- static FuncDeclaration *fcmp = NULL;
- static FuncDeclaration *fhash = NULL;
- if (!feq) feq = search_function(ClassDeclaration::object, Id::eq)->isFuncDeclaration();
- if (!fcmp) fcmp = search_function(ClassDeclaration::object, Id::cmp)->isFuncDeclaration();
- if (!fhash) fhash = search_function(ClassDeclaration::object, Id::tohash)->isFuncDeclaration();
- assert(fcmp && feq && fhash);
-
- if (feq->vtblIndex < (int)cd->vtbl.length && cd->vtbl[feq ->vtblIndex] == feq)
- {
- if (fcmp->vtblIndex < (int)cd->vtbl.length && cd->vtbl[fcmp->vtblIndex] != fcmp)
- {
- const char *s = (mtype->index->toBasetype()->ty != Tclass) ? "bottom of " : "";
- ::error(loc, "%sAA key type %s now requires equality rather than comparison",
- s, cd->toChars());
- errorSupplemental(loc, "Please override Object.opEquals and toHash.");
- }
- }
- }
- mtype->next = typeSemantic(mtype->next, loc,sc)->merge2();
- mtype->transitive();
-
- switch (mtype->next->toBasetype()->ty)
- {
- case Tfunction:
- case Tvoid:
- case Tnone:
- case Ttuple:
- ::error(loc, "cannot have associative array of %s", mtype->next->toChars());
- /* fall through */
- case Terror:
- return error();
- }
- if (mtype->next->isscope())
- {
- ::error(loc, "cannot have array of scope %s", mtype->next->toChars());
- return error();
- }
- result = mtype->merge();
- }
-
- void visit(TypePointer *mtype)
- {
- //printf("TypePointer::semantic() %s\n", mtype->toChars());
- if (mtype->deco)
- {
- result = mtype;
- return;
- }
- Type *n = typeSemantic(mtype->next, loc, sc);
- switch (n->toBasetype()->ty)
- {
- case Ttuple:
- ::error(loc, "cannot have pointer to %s", n->toChars());
- /* fall through */
- case Terror:
- return error();
- default:
- break;
- }
- if (n != mtype->next)
- {
- mtype->deco = NULL;
- }
- mtype->next = n;
- if (mtype->next->ty != Tfunction)
- {
- mtype->transitive();
- result = mtype->merge();
- return;
- }
- mtype->deco = mtype->merge()->deco;
- /* Don't return merge(), because arg identifiers and default args
- * can be different
- * even though the types match
- */
- result = mtype;
- }
-
- void visit(TypeReference *mtype)
- {
- //printf("TypeReference::semantic()\n");
- Type *n = typeSemantic(mtype->next, loc, sc);
- if (n != mtype->next)
- mtype->deco = NULL;
- mtype->next = n;
- mtype->transitive();
- result = mtype->merge();
- }
-
-
- void visit(TypeFunction *mtype)
- {
- if (mtype->deco) // if semantic() already run
- {
- //printf("already done\n");
- result = mtype;
- return;
- }
- //printf("TypeFunction::semantic() this = %p\n", this);
- //printf("TypeFunction::semantic() %s, sc->stc = %llx, fargs = %p\n", mtype->toChars(), sc->stc, mtype->fargs);
-
- bool errors = false;
-
- if (mtype->inuse > global.recursionLimit)
- {
- mtype->inuse = 0;
- ::error(loc, "recursive type");
- return error();
- }
-
- /* Copy in order to not mess up original.
- * This can produce redundant copies if inferring return type,
- * as semantic() will get called again on this.
- */
- TypeFunction *tf = mtype->copy()->toTypeFunction();
- if (mtype->parameterList.parameters)
- {
- tf->parameterList.parameters = mtype->parameterList.parameters->copy();
- for (size_t i = 0; i < mtype->parameterList.parameters->length; i++)
- {
- void *pp = mem.xmalloc(sizeof(Parameter));
- Parameter *p = (Parameter *)memcpy(pp, (void *)(*mtype->parameterList.parameters)[i],
- sizeof(Parameter));
- (*tf->parameterList.parameters)[i] = p;
- }
- }
-
- if (sc->stc & STCpure)
- tf->purity = PUREfwdref;
- if (sc->stc & STCnothrow)
- tf->isnothrow = true;
- if (sc->stc & STCnogc)
- tf->isnogc = true;
- if (sc->stc & STCref)
- tf->isref = true;
- if (sc->stc & STCreturn)
- tf->isreturn = true;
- if (sc->stc & STCscope)
- tf->isscope = true;
- if (sc->stc & STCscopeinferred)
- tf->isscopeinferred = true;
- //if ((sc->stc & (STCreturn | STCref)) == STCreturn)
- // tf->isscope = true; // return by itself means 'return scope'
-
- if (tf->trust == TRUSTdefault)
- {
- if (sc->stc & STCsafe)
- tf->trust = TRUSTsafe;
- if (sc->stc & STCsystem)
- tf->trust = TRUSTsystem;
- if (sc->stc & STCtrusted)
- tf->trust = TRUSTtrusted;
- }
-
- if (sc->stc & STCproperty)
- tf->isproperty = true;
-
- tf->linkage = sc->linkage;
- bool wildreturn = false;
- if (tf->next)
- {
- sc = sc->push();
- sc->stc &= ~(STC_TYPECTOR | STC_FUNCATTR);
- tf->next = typeSemantic(tf->next, loc, sc);
- sc = sc->pop();
- errors |= tf->checkRetType(loc);
- if (tf->next->isscope() && !(sc->flags & SCOPEctor))
- {
- ::error(loc, "functions cannot return scope %s", tf->next->toChars());
- errors = true;
- }
- if (tf->next->hasWild())
- wildreturn = true;
-
- if (tf->isreturn && !tf->isref && !tf->next->hasPointers())
- {
- tf->isreturn = false;
- }
- }
-
- unsigned char wildparams = 0;
- if (tf->parameterList.parameters)
- {
- /* Create a scope for evaluating the default arguments for the parameters
- */
- Scope *argsc = sc->push();
- argsc->stc = 0; // don't inherit storage class
- argsc->protection = Prot(Prot::public_);
- argsc->func = NULL;
-
- size_t dim = tf->parameterList.length();
- for (size_t i = 0; i < dim; i++)
- {
- Parameter *fparam = tf->parameterList[i];
- mtype->inuse++;
- fparam->type = typeSemantic(fparam->type, loc, argsc);
- mtype->inuse--;
-
- if (fparam->type->ty == Terror)
- {
- errors = true;
- continue;
- }
-
- fparam->type = fparam->type->addStorageClass(fparam->storageClass);
-
- if (fparam->storageClass & (STCauto | STCalias | STCstatic))
- {
- if (!fparam->type)
- continue;
- }
-
- Type *t = fparam->type->toBasetype();
-
- if (t->ty == Tfunction)
- {
- ::error(loc, "cannot have parameter of function type %s", fparam->type->toChars());
- errors = true;
- }
- else if (!(fparam->storageClass & (STCref | STCout)) &&
- (t->ty == Tstruct || t->ty == Tsarray || t->ty == Tenum))
- {
- Type *tb2 = t->baseElemOf();
- if ((tb2->ty == Tstruct && !((TypeStruct *)tb2)->sym->members) ||
- (tb2->ty == Tenum && !((TypeEnum *)tb2)->sym->memtype))
- {
- ::error(loc, "cannot have parameter of opaque type %s by value", fparam->type->toChars());
- errors = true;
- }
- }
- else if (!(fparam->storageClass & STClazy) && t->ty == Tvoid)
- {
- ::error(loc, "cannot have parameter of type %s", fparam->type->toChars());
- errors = true;
- }
-
- if ((fparam->storageClass & (STCref | STCwild)) == (STCref | STCwild))
- {
- // 'ref inout' implies 'return'
- fparam->storageClass |= STCreturn;
- }
-
- if (fparam->storageClass & STCreturn)
- {
- if (fparam->storageClass & (STCref | STCout))
- {
- // Disabled for the moment awaiting improvement to allow return by ref
- // to be transformed into return by scope.
- if (0 && !tf->isref)
- {
- StorageClass stc = fparam->storageClass & (STCref | STCout);
- ::error(loc, "parameter `%s` is `return %s` but function does not return by `ref`",
- fparam->ident ? fparam->ident->toChars() : "",
- stcToChars(stc));
- errors = true;
- }
- }
- else
- {
- fparam->storageClass |= STCscope; // 'return' implies 'scope'
- if (tf->isref)
- {
- }
- else if (!tf->isref && tf->next && !tf->next->hasPointers())
- {
- fparam->storageClass &= STCreturn; // https://issues.dlang.org/show_bug.cgi?id=18963
- }
- }
- }
-
- if (fparam->storageClass & (STCref | STClazy))
- {
- }
- else if (fparam->storageClass & STCout)
- {
- if (unsigned char m = fparam->type->mod & (MODimmutable | MODconst | MODwild))
- {
- ::error(loc, "cannot have %s out parameter of type %s", MODtoChars(m), t->toChars());
- errors = true;
- }
- else
- {
- Type *tv = t;
- while (tv->ty == Tsarray)
- tv = tv->nextOf()->toBasetype();
- if (tv->ty == Tstruct && ((TypeStruct *)tv)->sym->noDefaultCtor)
- {
- ::error(loc, "cannot have out parameter of type %s because the default construction is disabled",
- fparam->type->toChars());
- errors = true;
- }
- }
- }
-
- if (fparam->storageClass & STCscope && !fparam->type->hasPointers() && fparam->type->ty != Ttuple)
- {
- fparam->storageClass &= ~STCscope;
- if (!(fparam->storageClass & STCref))
- fparam->storageClass &= ~STCreturn;
- }
-
- if (t->hasWild())
- {
- wildparams |= 1;
- //if (tf->next && !wildreturn)
- // ::error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
- }
-
- if (fparam->defaultArg)
- {
- Expression *e = fparam->defaultArg;
- if (fparam->storageClass & (STCref | STCout))
- {
- e = expressionSemantic(e, argsc);
- e = resolveProperties(argsc, e);
- }
- else
- {
- e = inferType(e, fparam->type);
- Initializer *iz = new ExpInitializer(e->loc, e);
- iz = initializerSemantic(iz, argsc, fparam->type, INITnointerpret);
- e = initializerToExpression(iz);
- }
- if (e->op == TOKfunction) // see Bugzilla 4820
- {
- FuncExp *fe = (FuncExp *)e;
- // Replace function literal with a function symbol,
- // since default arg expression must be copied when used
- // and copying the literal itself is wrong.
- e = new VarExp(e->loc, fe->fd, false);
- e = new AddrExp(e->loc, e);
- e = expressionSemantic(e, argsc);
- }
- e = e->implicitCastTo(argsc, fparam->type);
-
- // default arg must be an lvalue
- if (fparam->storageClass & (STCout | STCref))
- e = e->toLvalue(argsc, e);
-
- fparam->defaultArg = e;
- if (e->op == TOKerror)
- errors = true;
- }
-
- /* If fparam after semantic() turns out to be a tuple, the number of parameters may
- * change.
- */
- if (t->ty == Ttuple)
- {
- /* TypeFunction::parameter also is used as the storage of
- * Parameter objects for FuncDeclaration. So we should copy
- * the elements of TypeTuple::arguments to avoid unintended
- * sharing of Parameter object among other functions.
- */
- TypeTuple *tt = (TypeTuple *)t;
- if (tt->arguments && tt->arguments->length)
- {
- /* Propagate additional storage class from tuple parameters to their
- * element-parameters.
- * Make a copy, as original may be referenced elsewhere.
- */
- size_t tdim = tt->arguments->length;
- Parameters *newparams = new Parameters();
- newparams->setDim(tdim);
- for (size_t j = 0; j < tdim; j++)
- {
- Parameter *narg = (*tt->arguments)[j];
-
- // Bugzilla 12744: If the storage classes of narg
- // conflict with the ones in fparam, it's ignored.
- StorageClass stc = fparam->storageClass | narg->storageClass;
- StorageClass stc1 = fparam->storageClass & (STCref | STCout | STClazy);
- StorageClass stc2 = narg->storageClass & (STCref | STCout | STClazy);
- if (stc1 && stc2 && stc1 != stc2)
- {
- OutBuffer buf1; stcToBuffer(&buf1, stc1 | ((stc1 & STCref) ? (fparam->storageClass & STCauto) : 0));
- OutBuffer buf2; stcToBuffer(&buf2, stc2);
-
- ::error(loc, "incompatible parameter storage classes `%s` and `%s`",
- buf1.peekChars(), buf2.peekChars());
- errors = true;
- stc = stc1 | (stc & ~(STCref | STCout | STClazy));
- }
-
- (*newparams)[j] = new Parameter(
- stc, narg->type, narg->ident, narg->defaultArg, narg->userAttribDecl);
- }
- fparam->type = new TypeTuple(newparams);
- }
- fparam->storageClass = 0;
-
- /* Reset number of parameters, and back up one to do this fparam again,
- * now that it is a tuple
- */
- dim = tf->parameterList.length();
- i--;
- continue;
- }
-
- /* Resolve "auto ref" storage class to be either ref or value,
- * based on the argument matching the parameter
- */
- if (fparam->storageClass & STCauto)
- {
- if (mtype->fargs && i < mtype->fargs->length && (fparam->storageClass & STCref))
- {
- Expression *farg = (*mtype->fargs)[i];
- if (farg->isLvalue())
- ; // ref parameter
- else
- fparam->storageClass &= ~STCref; // value parameter
- fparam->storageClass &= ~STCauto; // Bugzilla 14656
- fparam->storageClass |= STCautoref;
- }
- else
- {
- ::error(loc, "`auto` can only be used as part of `auto ref` for template function parameters");
- errors = true;
- }
- }
-
- // Remove redundant storage classes for type, they are already applied
- fparam->storageClass &= ~(STC_TYPECTOR | STCin);
- }
- argsc->pop();
- }
- if (tf->isWild())
- wildparams |= 2;
-
- if (wildreturn && !wildparams)
- {
- ::error(loc, "inout on return means inout must be on a parameter as well for %s", mtype->toChars());
- errors = true;
- }
- tf->iswild = wildparams;
-
- if (tf->isproperty && (tf->parameterList.varargs != VARARGnone || tf->parameterList.length() > 2))
- {
- ::error(loc, "properties can only have zero, one, or two parameter");
- errors = true;
- }
-
- if (tf->parameterList.varargs == VARARGvariadic && tf->linkage != LINKd && tf->parameterList.length() == 0)
- {
- ::error(loc, "variadic functions with non-D linkage must have at least one parameter");
- errors = true;
- }
-
- if (errors)
- return error();
-
- if (tf->next)
- tf->deco = tf->merge()->deco;
-
- /* Don't return merge(), because arg identifiers and default args
- * can be different
- * even though the types match
- */
- result = tf;
- }
-
- void visit(TypeDelegate *mtype)
- {
- //printf("TypeDelegate::semantic() %s\n", mtype->toChars());
- if (mtype->deco) // if semantic() already run
- {
- //printf("already done\n");
- result = mtype;
- return;
- }
- mtype->next = typeSemantic(mtype->next, loc,sc);
- if (mtype->next->ty != Tfunction)
- return error();
-
- /* In order to deal with Bugzilla 4028, perhaps default arguments should
- * be removed from next before the merge.
- */
-
- /* Don't return merge(), because arg identifiers and default args
- * can be different
- * even though the types match
- */
- mtype->deco = mtype->merge()->deco;
- result = mtype;
- }
-
- void visit(TypeTraits *mtype)
- {
- if (mtype->ty == Terror)
- {
- result = mtype;
- return;
- }
-
- const int inAlias = (sc->flags & SCOPEalias) != 0;
- if (mtype->exp->ident != Id::allMembers &&
- mtype->exp->ident != Id::derivedMembers &&
- mtype->exp->ident != Id::getMember &&
- mtype->exp->ident != Id::parent &&
- mtype->exp->ident != Id::child &&
- mtype->exp->ident != Id::toType &&
- mtype->exp->ident != Id::getOverloads &&
- mtype->exp->ident != Id::getVirtualFunctions &&
- mtype->exp->ident != Id::getVirtualMethods &&
- mtype->exp->ident != Id::getAttributes &&
- mtype->exp->ident != Id::getUnitTests &&
- mtype->exp->ident != Id::getAliasThis)
- {
- static const char *ctxt[2] = {"as type", "in alias"};
- ::error(loc, "trait `%s` is either invalid or not supported %s",
- mtype->exp->ident->toChars(), ctxt[inAlias]);
- mtype->ty = Terror;
- result = mtype;
- return;
- }
-
- if (Expression *e = semanticTraits(mtype->exp, sc))
- {
- switch (e->op)
- {
- case TOKdotvar:
- mtype->sym = ((DotVarExp *)e)->var;
- break;
- case TOKvar:
- mtype->sym = ((VarExp *)e)->var;
- break;
- case TOKfunction:
- {
- FuncExp *fe = (FuncExp *)e;
- if (fe->td)
- mtype->sym = fe->td;
- else
- mtype->sym = fe->fd;
- break;
- }
- case TOKdottd:
- mtype->sym = ((DotTemplateExp*)e)->td;
- break;
- case TOKdsymbol:
- mtype->sym = ((DsymbolExp *)e)->s;
- break;
- case TOKtemplate:
- mtype->sym = ((TemplateExp *)e)->td;
- break;
- case TOKscope:
- mtype->sym = ((ScopeExp *)e)->sds;
- break;
- case TOKtuple:
- {
- TupleExp *te = e->toTupleExp();
- Objects *elems = new Objects;
- elems->setDim(te->exps->length);
- for (size_t i = 0; i < elems->length; i++)
- {
- Expression *src = (*te->exps)[i];
- switch (src->op)
- {
- case TOKtype:
- (*elems)[i] = ((TypeExp *)src)->type;
- break;
- case TOKdottype:
- (*elems)[i] = ((DotTypeExp *)src)->type;
- break;
- case TOKoverloadset:
- (*elems)[i] = ((OverExp *)src)->type;
- break;
- default:
- if (Dsymbol *sym = isDsymbol(src))
- (*elems)[i] = sym;
- else
- (*elems)[i] = src;
- }
- }
- TupleDeclaration *td = new TupleDeclaration(e->loc,
- Identifier::generateId("__aliastup"), elems);
- mtype->sym = td;
- break;
- }
- case TOKdottype:
- result = isType(((DotTypeExp *)e)->sym);
- break;
- case TOKtype:
- result = ((TypeExp *)e)->type;
- break;
- case TOKoverloadset:
- result = ((OverExp *)e)->type;
- break;
- default:
- break;
- }
- }
-
- if (result)
- result = result->addMod(mtype->mod);
- if (!inAlias && !result)
- {
- if (!global.errors)
- ::error(loc, "`%s` does not give a valid type", mtype->toChars());
- return error();
- }
- }
-
- void visit(TypeIdentifier *mtype)
- {
- Type *t;
- Expression *e;
- Dsymbol *s;
-
- //printf("TypeIdentifier::semantic(%s)\n", mtype->toChars());
- mtype->resolve(loc, sc, &e, &t, &s);
- if (t)
- {
- //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco);
- t = t->addMod(mtype->mod);
- }
- else
- {
- if (s)
- {
- s->error(loc, "is used as a type");
- //halt();
- }
- else
- ::error(loc, "%s is used as a type", mtype->toChars());
- return error();
- }
- //t->print();
- result = t;
- }
-
- void visit(TypeInstance *mtype)
- {
- Type *t;
- Expression *e;
- Dsymbol *s;
-
- //printf("TypeInstance::semantic(%p, %s)\n", this, mtype->toChars());
- {
- unsigned errors = global.errors;
- mtype->resolve(loc, sc, &e, &t, &s);
- // if we had an error evaluating the symbol, suppress further errors
- if (!t && errors != global.errors)
- return error();
- }
-
- if (!t)
- {
- if (!e && s && s->errors)
- {
- // if there was an error evaluating the symbol, it might actually
- // be a type. Avoid misleading error messages.
- ::error(loc, "%s had previous errors", mtype->toChars());
- }
- else
- ::error(loc, "%s is used as a type", mtype->toChars());
- return error();
- }
- result = t;
- }
-
- void visit(TypeTypeof *mtype)
- {
- //printf("TypeTypeof::semantic() %s\n", mtype->toChars());
-
- Expression *e;
- Type *t;
- Dsymbol *s;
- mtype->resolve(loc, sc, &e, &t, &s);
- if (s && (t = s->getType()) != NULL)
- t = t->addMod(mtype->mod);
- if (!t)
- {
- ::error(loc, "%s is used as a type", mtype->toChars());
- return error();
- }
- result = t;
- }
-
- void visit(TypeReturn *mtype)
- {
- //printf("TypeReturn::semantic() %s\n", mtype->toChars());
-
- Expression *e;
- Type *t;
- Dsymbol *s;
- mtype->resolve(loc, sc, &e, &t, &s);
- if (s && (t = s->getType()) != NULL)
- t = t->addMod(mtype->mod);
- if (!t)
- {
- ::error(loc, "%s is used as a type", mtype->toChars());
- return error();
- }
- result = t;
- }
-
- void visit(TypeEnum *mtype)
- {
- //printf("TypeEnum::semantic() %s\n", mtype->toChars());
- result = mtype->deco ? mtype : mtype->merge();
- }
-
- void visit(TypeStruct *mtype)
- {
- //printf("TypeStruct::semantic('%s')\n", mtype->toChars());
- if (mtype->deco)
- {
- if (sc && sc->cppmangle != CPPMANGLEdefault)
- {
- if (mtype->cppmangle == CPPMANGLEdefault)
- mtype->cppmangle = sc->cppmangle;
- else
- assert(mtype->cppmangle == sc->cppmangle);
- }
- result = mtype;
- return;
- }
-
- /* Don't semantic for sym because it should be deferred until
- * sizeof needed or its members accessed.
- */
- // instead, parent should be set correctly
- assert(mtype->sym->parent);
-
- if (mtype->sym->type->ty == Terror)
- return error();
- if (sc)
- mtype->cppmangle = sc->cppmangle;
- result = mtype->merge();
- }
-
- void visit(TypeClass *mtype)
- {
- //printf("TypeClass::semantic(%s)\n", mtype->toChars());
- if (mtype->deco)
- {
- if (sc && sc->cppmangle != CPPMANGLEdefault)
- {
- if (mtype->cppmangle == CPPMANGLEdefault)
- mtype->cppmangle = sc->cppmangle;
- else
- assert(mtype->cppmangle == sc->cppmangle);
- }
- result = mtype;
- return;
- }
-
- /* Don't semantic for sym because it should be deferred until
- * sizeof needed or its members accessed.
- */
- // instead, parent should be set correctly
- assert(mtype->sym->parent);
-
- if (mtype->sym->type->ty == Terror)
- return error();
- if (sc)
- mtype->cppmangle = sc->cppmangle;
- result = mtype->merge();
- }
-
- void visit(TypeTuple *mtype)
- {
- //printf("TypeTuple::semantic(this = %p)\n", this);
- //printf("TypeTuple::semantic() %p, %s\n", this, mtype->toChars());
- if (!mtype->deco)
- mtype->deco = mtype->merge()->deco;
-
- /* Don't return merge(), because a tuple with one type has the
- * same deco as that type.
- */
- result = mtype;
- }
-
- void visit(TypeSlice *mtype)
- {
- //printf("TypeSlice::semantic() %s\n", mtype->toChars());
- Type *tn = typeSemantic(mtype->next, loc, sc);
- //printf("next: %s\n", tn->toChars());
-
- Type *tbn = tn->toBasetype();
- if (tbn->ty != Ttuple)
- {
- ::error(loc, "can only slice tuple types, not %s", tbn->toChars());
- return error();
- }
- TypeTuple *tt = (TypeTuple *)tbn;
-
- mtype->lwr = semanticLength(sc, tbn, mtype->lwr);
- mtype->lwr = mtype->lwr->ctfeInterpret();
- uinteger_t i1 = mtype->lwr->toUInteger();
-
- mtype->upr = semanticLength(sc, tbn, mtype->upr);
- mtype->upr = mtype->upr->ctfeInterpret();
- uinteger_t i2 = mtype->upr->toUInteger();
-
- if (!(i1 <= i2 && i2 <= tt->arguments->length))
- {
- ::error(loc, "slice `[%llu..%llu]` is out of range of [0..%llu]",
- (unsigned long long)i1, (unsigned long long)i2, (unsigned long long)tt->arguments->length);
- return error();
- }
-
- mtype->next = tn;
- mtype->transitive();
-
- Parameters *args = new Parameters;
- args->reserve((size_t)(i2 - i1));
- for (size_t i = (size_t)i1; i < (size_t)i2; i++)
- {
- Parameter *arg = (*tt->arguments)[i];
- args->push(arg);
- }
- Type *t = new TypeTuple(args);
- result = typeSemantic(t, loc, sc);
- }
-
- void visit(TypeMixin *mtype)
- {
- //printf("TypeMixin::semantic() %s\n", mtype->toChars());
-
- Expression *e = NULL;
- Type *t = NULL;
- Dsymbol *s = NULL;
- mtype->resolve(loc, sc, &e, &t, &s);
-
- if (t && t->ty != Terror)
- {
- result = t;
- return;
- }
-
- ::error(mtype->loc, "`mixin(%s)` does not give a valid type", mtype->obj->toChars());
- return error();
- }
- };
- TypeSemanticVisitor v(loc, sc);
- type->accept(&v);
- return v.result;
-}
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
new file mode 100644
index 0000000..ace4e42
--- /dev/null
+++ b/gcc/d/dmd/typesem.d
@@ -0,0 +1,4896 @@
+/**
+ * Semantic analysis for D types.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typesem.d, _typesem.d)
+ * Documentation: https://dlang.org/phobos/dmd_typesem.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typesem.d
+ */
+
+module dmd.typesem;
+
+import core.checkedint;
+import core.stdc.string;
+import core.stdc.stdio;
+
+import dmd.access;
+import dmd.aggregate;
+import dmd.aliasthis;
+import dmd.arrayop;
+import dmd.arraytypes;
+import dmd.astcodegen;
+import dmd.astenums;
+import dmd.complex;
+import dmd.dcast;
+import dmd.dclass;
+import dmd.declaration;
+import dmd.denum;
+import dmd.dimport;
+import dmd.dmangle;
+import dmd.dmodule;
+import dmd.dscope;
+import dmd.dstruct;
+import dmd.dsymbol;
+import dmd.dsymbolsem;
+import dmd.dtemplate;
+import dmd.errors;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.func;
+import dmd.globals;
+import dmd.hdrgen;
+import dmd.id;
+import dmd.identifier;
+import dmd.imphint;
+import dmd.init;
+import dmd.initsem;
+import dmd.visitor;
+import dmd.mtype;
+import dmd.objc;
+import dmd.opover;
+import dmd.parse;
+import dmd.root.ctfloat;
+import dmd.root.rmem;
+import dmd.root.outbuffer;
+import dmd.root.rootobject;
+import dmd.root.string;
+import dmd.root.stringtable;
+import dmd.safe;
+import dmd.semantic3;
+import dmd.sideeffect;
+import dmd.target;
+import dmd.tokens;
+
+/**************************
+ * This evaluates exp while setting length to be the number
+ * of elements in the tuple t.
+ */
+private Expression semanticLength(Scope* sc, Type t, Expression exp)
+{
+ if (auto tt = t.isTypeTuple())
+ {
+ ScopeDsymbol sym = new ArrayScopeSymbol(sc, tt);
+ sym.parent = sc.scopesym;
+ sc = sc.push(sym);
+ sc = sc.startCTFE();
+ exp = exp.expressionSemantic(sc);
+ exp = resolveProperties(sc, exp);
+ sc = sc.endCTFE();
+ sc.pop();
+ }
+ else
+ {
+ sc = sc.startCTFE();
+ exp = exp.expressionSemantic(sc);
+ exp = resolveProperties(sc, exp);
+ sc = sc.endCTFE();
+ }
+ return exp;
+}
+
+private Expression semanticLength(Scope* sc, TupleDeclaration tup, Expression exp)
+{
+ ScopeDsymbol sym = new ArrayScopeSymbol(sc, tup);
+ sym.parent = sc.scopesym;
+
+ sc = sc.push(sym);
+ sc = sc.startCTFE();
+ exp = exp.expressionSemantic(sc);
+ exp = resolveProperties(sc, exp);
+ sc = sc.endCTFE();
+ sc.pop();
+
+ return exp;
+}
+
+/*************************************
+ * Resolve a tuple index, `s[oindex]`, by figuring out what `s[oindex]` represents.
+ * Setting one of pe/pt/ps.
+ * Params:
+ * loc = location for error messages
+ * sc = context
+ * s = symbol being indexed - could be a tuple, could be an expression
+ * pe = set if s[oindex] is an Expression, otherwise null
+ * pt = set if s[oindex] is a Type, otherwise null
+ * ps = set if s[oindex] is a Dsymbol, otherwise null
+ * oindex = index into s
+ */
+private void resolveTupleIndex(const ref Loc loc, Scope* sc, Dsymbol s, out Expression pe, out Type pt, out Dsymbol ps, RootObject oindex)
+{
+ auto tup = s.isTupleDeclaration();
+
+ auto eindex = isExpression(oindex);
+ auto tindex = isType(oindex);
+ auto sindex = isDsymbol(oindex);
+
+ if (!tup)
+ {
+ // It's really an index expression
+ if (tindex)
+ eindex = new TypeExp(loc, tindex);
+ else if (sindex)
+ eindex = symbolToExp(sindex, loc, sc, false);
+ Expression e = new IndexExp(loc, symbolToExp(s, loc, sc, false), eindex);
+ e = e.expressionSemantic(sc);
+ resolveExp(e, pt, pe, ps);
+ return;
+ }
+
+ // Convert oindex to Expression, then try to resolve to constant.
+ if (tindex)
+ tindex.resolve(loc, sc, eindex, tindex, sindex);
+ if (sindex)
+ eindex = symbolToExp(sindex, loc, sc, false);
+ if (!eindex)
+ {
+ .error(loc, "index `%s` is not an expression", oindex.toChars());
+ pt = Type.terror;
+ return;
+ }
+
+ eindex = semanticLength(sc, tup, eindex);
+ eindex = eindex.ctfeInterpret();
+ if (eindex.op == TOK.error)
+ {
+ pt = Type.terror;
+ return;
+ }
+ const(uinteger_t) d = eindex.toUInteger();
+ if (d >= tup.objects.dim)
+ {
+ .error(loc, "tuple index `%llu` exceeds length %zu", d, tup.objects.dim);
+ pt = Type.terror;
+ return;
+ }
+
+ RootObject o = (*tup.objects)[cast(size_t)d];
+ ps = isDsymbol(o);
+ if (auto t = isType(o))
+ pt = t.typeSemantic(loc, sc);
+ if (auto e = isExpression(o))
+ resolveExp(e, pt, pe, ps);
+}
+
+/*************************************
+ * Takes an array of Identifiers and figures out if
+ * it represents a Type, Expression, or Dsymbol.
+ * Params:
+ * mt = array of identifiers
+ * loc = location for error messages
+ * sc = context
+ * s = symbol to start search at
+ * scopesym = unused
+ * pe = set if expression otherwise null
+ * pt = set if type otherwise null
+ * ps = set if symbol otherwise null
+ * typeid = set if in TypeidExpression https://dlang.org/spec/expression.html#TypeidExpression
+ */
+private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymbol s, Dsymbol scopesym,
+ out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
+{
+ version (none)
+ {
+ printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, mt.toChars());
+ if (scopesym)
+ printf("\tscopesym = '%s'\n", scopesym.toChars());
+ }
+
+ if (!s)
+ {
+ /* Look for what user might have intended
+ */
+ const p = mt.mutableOf().unSharedOf().toChars();
+ auto id = Identifier.idPool(p, cast(uint)strlen(p));
+ if (const n = importHint(id.toString()))
+ error(loc, "`%s` is not defined, perhaps `import %.*s;` ?", p, cast(int)n.length, n.ptr);
+ else if (auto s2 = sc.search_correct(id))
+ error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2.kind(), s2.toChars());
+ else if (const q = Scope.search_correct_C(id))
+ error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q);
+ else
+ error(loc, "undefined identifier `%s`", p);
+
+ pt = Type.terror;
+ return;
+ }
+
+ //printf("\t1: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
+ Declaration d = s.isDeclaration();
+ if (d && (d.storage_class & STC.templateparameter))
+ s = s.toAlias();
+ else
+ {
+ // check for deprecated or disabled aliases
+ // functions are checked after overloading
+ // templates are checked after matching constraints
+ if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
+ s.checkDeprecated(loc, sc);
+ if (d)
+ d.checkDisabled(loc, sc, true);
+ }
+ s = s.toAlias();
+ //printf("\t2: s = '%s' %p, kind = '%s'\n",s.toChars(), s, s.kind());
+ for (size_t i = 0; i < mt.idents.dim; i++)
+ {
+ RootObject id = mt.idents[i];
+ if (id.dyncast() == DYNCAST.expression ||
+ id.dyncast() == DYNCAST.type)
+ {
+ Type tx;
+ Expression ex;
+ Dsymbol sx;
+ resolveTupleIndex(loc, sc, s, ex, tx, sx, id);
+ if (sx)
+ {
+ s = sx.toAlias();
+ continue;
+ }
+ if (tx)
+ ex = new TypeExp(loc, tx);
+ assert(ex);
+
+ ex = typeToExpressionHelper(mt, ex, i + 1);
+ ex = ex.expressionSemantic(sc);
+ resolveExp(ex, pt, pe, ps);
+ return;
+ }
+
+ Type t = s.getType(); // type symbol, type alias, or type tuple?
+ uint errorsave = global.errors;
+ int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports;
+
+ Dsymbol sm = s.searchX(loc, sc, id, flags);
+ if (sm)
+ {
+ if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, sm))
+ {
+ .error(loc, "`%s` is not visible from module `%s`", sm.toPrettyChars(), sc._module.toChars());
+ sm = null;
+ }
+ // Same check as in Expression.semanticY(DotIdExp)
+ else if (sm.isPackage() && checkAccess(sc, cast(Package)sm))
+ {
+ // @@@DEPRECATED_2.096@@@
+ // Should be an error in 2.106. Just remove the deprecation call
+ // and uncomment the null assignment
+ deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", sm.kind(), sm.toPrettyChars(), sm.toPrettyChars());
+ //sm = null;
+ }
+ }
+ if (global.errors != errorsave)
+ {
+ pt = Type.terror;
+ return;
+ }
+
+ void helper3()
+ {
+ Expression e;
+ VarDeclaration v = s.isVarDeclaration();
+ FuncDeclaration f = s.isFuncDeclaration();
+ if (intypeid || !v && !f)
+ e = symbolToExp(s, loc, sc, true);
+ else
+ e = new VarExp(loc, s.isDeclaration(), true);
+
+ e = typeToExpressionHelper(mt, e, i);
+ e = e.expressionSemantic(sc);
+ resolveExp(e, pt, pe, ps);
+ }
+
+ //printf("\t3: s = %p %s %s, sm = %p\n", s, s.kind(), s.toChars(), sm);
+ if (intypeid && !t && sm && sm.needThis())
+ return helper3();
+
+ if (VarDeclaration v = s.isVarDeclaration())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=19913
+ // v.type would be null if it is a forward referenced member.
+ if (v.type is null)
+ v.dsymbolSemantic(sc);
+ if (v.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) ||
+ v.type.isConst() || v.type.isImmutable())
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=13087
+ // this.field is not constant always
+ if (!v.isThisDeclaration())
+ return helper3();
+ }
+ }
+ if (!sm)
+ {
+ if (!t)
+ {
+ if (s.isDeclaration()) // var, func, or tuple declaration?
+ {
+ t = s.isDeclaration().type;
+ if (!t && s.isTupleDeclaration()) // expression tuple?
+ return helper3();
+ }
+ else if (s.isTemplateInstance() ||
+ s.isImport() || s.isPackage() || s.isModule())
+ {
+ return helper3();
+ }
+ }
+ if (t)
+ {
+ sm = t.toDsymbol(sc);
+ if (sm && id.dyncast() == DYNCAST.identifier)
+ {
+ sm = sm.search(loc, cast(Identifier)id, IgnorePrivateImports);
+ if (!sm)
+ return helper3();
+ }
+ else
+ return helper3();
+ }
+ else
+ {
+ if (id.dyncast() == DYNCAST.dsymbol)
+ {
+ // searchX already handles errors for template instances
+ assert(global.errors);
+ }
+ else
+ {
+ assert(id.dyncast() == DYNCAST.identifier);
+ sm = s.search_correct(cast(Identifier)id);
+ if (sm)
+ error(loc, "identifier `%s` of `%s` is not defined, did you mean %s `%s`?", id.toChars(), mt.toChars(), sm.kind(), sm.toChars());
+ else
+ error(loc, "identifier `%s` of `%s` is not defined", id.toChars(), mt.toChars());
+ }
+ pe = ErrorExp.get();
+ return;
+ }
+ }
+ s = sm.toAlias();
+ }
+
+ if (auto em = s.isEnumMember())
+ {
+ // It's not a type, it's an expression
+ pe = em.getVarExp(loc, sc);
+ return;
+ }
+ if (auto v = s.isVarDeclaration())
+ {
+ /* This is mostly same with DsymbolExp::semantic(), but we cannot use it
+ * because some variables used in type context need to prevent lowering
+ * to a literal or contextful expression. For example:
+ *
+ * enum a = 1; alias b = a;
+ * template X(alias e){ alias v = e; } alias x = X!(1);
+ * struct S { int v; alias w = v; }
+ * // TypeIdentifier 'a', 'e', and 'v' should be TOK.variable,
+ * // because getDsymbol() need to work in AliasDeclaration::semantic().
+ */
+ if (!v.type ||
+ !v.type.deco && v.inuse)
+ {
+ if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
+ error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
+ else
+ error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
+ pt = Type.terror;
+ return;
+ }
+ if (v.type.ty == Terror)
+ pt = Type.terror;
+ else
+ pe = new VarExp(loc, v);
+ return;
+ }
+ if (auto fld = s.isFuncLiteralDeclaration())
+ {
+ //printf("'%s' is a function literal\n", fld.toChars());
+ auto e = new FuncExp(loc, fld);
+ pe = e.expressionSemantic(sc);
+ return;
+ }
+ version (none)
+ {
+ if (FuncDeclaration fd = s.isFuncDeclaration())
+ {
+ pe = new DsymbolExp(loc, fd);
+ return;
+ }
+ }
+
+ Type t;
+ while (1)
+ {
+ t = s.getType();
+ if (t)
+ break;
+ ps = s;
+ return;
+ }
+
+ if (auto ti = t.isTypeInstance())
+ if (ti != mt && !ti.deco)
+ {
+ if (!ti.tempinst.errors)
+ error(loc, "forward reference to `%s`", ti.toChars());
+ pt = Type.terror;
+ return;
+ }
+
+ if (t.ty == Ttuple)
+ pt = t;
+ else
+ pt = t.merge();
+}
+
+/************************************
+ * Transitively search a type for all function types.
+ * If any function types with parameters are found that have parameter identifiers
+ * or default arguments, remove those and create a new type stripped of those.
+ * This is used to determine the "canonical" version of a type which is useful for
+ * comparisons.
+ * Params:
+ * t = type to scan
+ * Returns:
+ * `t` if no parameter identifiers or default arguments found, otherwise a new type that is
+ * the same as t but with no parameter identifiers or default arguments.
+ */
+private Type stripDefaultArgs(Type t)
+{
+ static Parameters* stripParams(Parameters* parameters)
+ {
+ static Parameter stripParameter(Parameter p)
+ {
+ Type t = stripDefaultArgs(p.type);
+ return (t != p.type || p.defaultArg || p.ident || p.userAttribDecl)
+ ? new Parameter(p.storageClass, t, null, null, null)
+ : null;
+ }
+
+ if (parameters)
+ {
+ foreach (i, p; *parameters)
+ {
+ Parameter ps = stripParameter(p);
+ if (ps)
+ {
+ // Replace params with a copy we can modify
+ Parameters* nparams = new Parameters(parameters.dim);
+
+ foreach (j, ref np; *nparams)
+ {
+ Parameter pj = (*parameters)[j];
+ if (j < i)
+ np = pj;
+ else if (j == i)
+ np = ps;
+ else
+ {
+ Parameter nps = stripParameter(pj);
+ np = nps ? nps : pj;
+ }
+ }
+ return nparams;
+ }
+ }
+ }
+ return parameters;
+ }
+
+ if (t is null)
+ return t;
+
+ if (auto tf = t.isTypeFunction())
+ {
+ Type tret = stripDefaultArgs(tf.next);
+ Parameters* params = stripParams(tf.parameterList.parameters);
+ if (tret == tf.next && params == tf.parameterList.parameters)
+ return t;
+ TypeFunction tr = cast(TypeFunction)tf.copy();
+ tr.parameterList.parameters = params;
+ tr.next = tret;
+ //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
+ return tr;
+ }
+ else if (auto tt = t.isTypeTuple())
+ {
+ Parameters* args = stripParams(tt.arguments);
+ if (args == tt.arguments)
+ return t;
+ TypeTuple tr = cast(TypeTuple)t.copy();
+ tr.arguments = args;
+ return tr;
+ }
+ else if (t.ty == Tenum)
+ {
+ // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
+ return t;
+ }
+ else
+ {
+ Type tn = t.nextOf();
+ Type n = stripDefaultArgs(tn);
+ if (n == tn)
+ return t;
+ TypeNext tr = cast(TypeNext)t.copy();
+ tr.next = n;
+ return tr;
+ }
+}
+
+/******************************************
+ * We've mistakenly parsed `t` as a type.
+ * Redo `t` as an Expression only if there are no type modifiers.
+ * Params:
+ * t = mistaken type
+ * Returns:
+ * t redone as Expression, null if cannot
+ */
+Expression typeToExpression(Type t)
+{
+ static Expression visitSArray(TypeSArray t)
+ {
+ if (auto e = t.next.typeToExpression())
+ return new ArrayExp(t.dim.loc, e, t.dim);
+ return null;
+ }
+
+ static Expression visitAArray(TypeAArray t)
+ {
+ if (auto e = t.next.typeToExpression())
+ {
+ if (auto ei = t.index.typeToExpression())
+ return new ArrayExp(t.loc, e, ei);
+ }
+ return null;
+ }
+
+ static Expression visitIdentifier(TypeIdentifier t)
+ {
+ return typeToExpressionHelper(t, new IdentifierExp(t.loc, t.ident));
+ }
+
+ static Expression visitInstance(TypeInstance t)
+ {
+ return typeToExpressionHelper(t, new ScopeExp(t.loc, t.tempinst));
+ }
+
+ // easy way to enable 'auto v = new int[mixin("exp")];' in 2.088+
+ static Expression visitMixin(TypeMixin t)
+ {
+ return new TypeExp(t.loc, t);
+ }
+
+ if (t.mod)
+ return null;
+ switch (t.ty)
+ {
+ case Tsarray: return visitSArray(cast(TypeSArray) t);
+ case Taarray: return visitAArray(cast(TypeAArray) t);
+ case Tident: return visitIdentifier(cast(TypeIdentifier) t);
+ case Tinstance: return visitInstance(cast(TypeInstance) t);
+ case Tmixin: return visitMixin(cast(TypeMixin) t);
+ default: return null;
+ }
+}
+
+/* Helper function for `typeToExpression`. Contains common code
+ * for TypeQualified derived classes.
+ */
+Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0)
+{
+ //printf("toExpressionHelper(e = %s %s)\n", Token.toChars(e.op), e.toChars());
+ foreach (id; t.idents[i .. t.idents.dim])
+ {
+ //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
+
+ final switch (id.dyncast())
+ {
+ // ... '. ident'
+ case DYNCAST.identifier:
+ e = new DotIdExp(e.loc, e, cast(Identifier)id);
+ break;
+
+ // ... '. name!(tiargs)'
+ case DYNCAST.dsymbol:
+ auto ti = (cast(Dsymbol)id).isTemplateInstance();
+ assert(ti);
+ e = new DotTemplateInstanceExp(e.loc, e, ti.name, ti.tiargs);
+ break;
+
+ // ... '[type]'
+ case DYNCAST.type: // https://issues.dlang.org/show_bug.cgi?id=1215
+ e = new ArrayExp(t.loc, e, new TypeExp(t.loc, cast(Type)id));
+ break;
+
+ // ... '[expr]'
+ case DYNCAST.expression: // https://issues.dlang.org/show_bug.cgi?id=1215
+ e = new ArrayExp(t.loc, e, cast(Expression)id);
+ break;
+
+ case DYNCAST.object:
+ case DYNCAST.tuple:
+ case DYNCAST.parameter:
+ case DYNCAST.statement:
+ case DYNCAST.condition:
+ case DYNCAST.templateparameter:
+ case DYNCAST.initializer:
+ assert(0);
+ }
+ }
+ return e;
+}
+
+/******************************************
+ * Perform semantic analysis on a type.
+ * Params:
+ * type = Type AST node
+ * loc = the location of the type
+ * sc = context
+ * Returns:
+ * `Type` with completed semantic analysis, `Terror` if errors
+ * were encountered
+ */
+extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
+{
+ static Type error()
+ {
+ return Type.terror;
+ }
+
+ Type visitType(Type t)
+ {
+ if (t.ty == Tint128 || t.ty == Tuns128)
+ {
+ .error(loc, "`cent` and `ucent` types not implemented");
+ return error();
+ }
+
+ return t.merge();
+ }
+
+ Type visitVector(TypeVector mtype)
+ {
+ const errors = global.errors;
+ mtype.basetype = mtype.basetype.typeSemantic(loc, sc);
+ if (errors != global.errors)
+ return error();
+ mtype.basetype = mtype.basetype.toBasetype().mutableOf();
+ if (mtype.basetype.ty != Tsarray)
+ {
+ .error(loc, "T in __vector(T) must be a static array, not `%s`", mtype.basetype.toChars());
+ return error();
+ }
+ TypeSArray t = cast(TypeSArray)mtype.basetype;
+ const sz = cast(int)t.size(loc);
+ final switch (target.isVectorTypeSupported(sz, t.nextOf()))
+ {
+ case 0:
+ // valid
+ break;
+
+ case 1:
+ // no support at all
+ .error(loc, "SIMD vector types not supported on this platform");
+ return error();
+
+ case 2:
+ // invalid base type
+ .error(loc, "vector type `%s` is not supported on this platform", mtype.toChars());
+ return error();
+
+ case 3:
+ // invalid size
+ .error(loc, "%d byte vector type `%s` is not supported on this platform", sz, mtype.toChars());
+ return error();
+ }
+ return merge(mtype);
+ }
+
+ Type visitSArray(TypeSArray mtype)
+ {
+ //printf("TypeSArray::semantic() %s\n", toChars());
+ Type t;
+ Expression e;
+ Dsymbol s;
+ mtype.next.resolve(loc, sc, e, t, s);
+
+ if (auto tup = s ? s.isTupleDeclaration() : null)
+ {
+ mtype.dim = semanticLength(sc, tup, mtype.dim);
+ mtype.dim = mtype.dim.ctfeInterpret();
+ if (mtype.dim.op == TOK.error)
+ return error();
+
+ uinteger_t d = mtype.dim.toUInteger();
+ if (d >= tup.objects.dim)
+ {
+ .error(loc, "tuple index %llu exceeds %llu", cast(ulong)d, cast(ulong)tup.objects.dim);
+ return error();
+ }
+
+ RootObject o = (*tup.objects)[cast(size_t)d];
+ if (o.dyncast() != DYNCAST.type)
+ {
+ .error(loc, "`%s` is not a type", mtype.toChars());
+ return error();
+ }
+ return (cast(Type)o).addMod(mtype.mod);
+ }
+
+ if (t && t.ty == Terror)
+ return error();
+
+ Type tn = mtype.next.typeSemantic(loc, sc);
+ if (tn.ty == Terror)
+ return error();
+
+ Type tbn = tn.toBasetype();
+ if (mtype.dim)
+ {
+ auto errors = global.errors;
+ mtype.dim = semanticLength(sc, tbn, mtype.dim);
+ if (errors != global.errors)
+ return error();
+
+ mtype.dim = mtype.dim.optimize(WANTvalue);
+ mtype.dim = mtype.dim.ctfeInterpret();
+ if (mtype.dim.op == TOK.error)
+ return error();
+
+ errors = global.errors;
+ dinteger_t d1 = mtype.dim.toInteger();
+ if (errors != global.errors)
+ return error();
+
+ mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
+ mtype.dim = mtype.dim.optimize(WANTvalue);
+ if (mtype.dim.op == TOK.error)
+ return error();
+
+ errors = global.errors;
+ dinteger_t d2 = mtype.dim.toInteger();
+ if (errors != global.errors)
+ return error();
+
+ if (mtype.dim.op == TOK.error)
+ return error();
+
+ Type overflowError()
+ {
+ .error(loc, "`%s` size %llu * %llu exceeds 0x%llx size limit for static array",
+ mtype.toChars(), cast(ulong)tbn.size(loc), cast(ulong)d1, target.maxStaticDataSize);
+ return error();
+ }
+
+ if (d1 != d2)
+ return overflowError();
+
+ Type tbx = tbn.baseElemOf();
+ if (tbx.ty == Tstruct && !(cast(TypeStruct)tbx).sym.members ||
+ tbx.ty == Tenum && !(cast(TypeEnum)tbx).sym.members)
+ {
+ /* To avoid meaningless error message, skip the total size limit check
+ * when the bottom of element type is opaque.
+ */
+ }
+ else if (tbn.isTypeBasic() ||
+ tbn.ty == Tpointer ||
+ tbn.ty == Tarray ||
+ tbn.ty == Tsarray ||
+ tbn.ty == Taarray ||
+ (tbn.ty == Tstruct && ((cast(TypeStruct)tbn).sym.sizeok == Sizeok.done)) ||
+ tbn.ty == Tclass)
+ {
+ /* Only do this for types that don't need to have semantic()
+ * run on them for the size, since they may be forward referenced.
+ */
+ bool overflow = false;
+ if (mulu(tbn.size(loc), d2, overflow) >= target.maxStaticDataSize || overflow)
+ return overflowError();
+ }
+ }
+ switch (tbn.ty)
+ {
+ case Ttuple:
+ {
+ // Index the tuple to get the type
+ assert(mtype.dim);
+ TypeTuple tt = cast(TypeTuple)tbn;
+ uinteger_t d = mtype.dim.toUInteger();
+ if (d >= tt.arguments.dim)
+ {
+ .error(loc, "tuple index %llu exceeds %llu", cast(ulong)d, cast(ulong)tt.arguments.dim);
+ return error();
+ }
+ Type telem = (*tt.arguments)[cast(size_t)d].type;
+ return telem.addMod(mtype.mod);
+ }
+
+ case Tfunction:
+ case Tnone:
+ .error(loc, "cannot have array of `%s`", tbn.toChars());
+ return error();
+
+ default:
+ break;
+ }
+ if (tbn.isscope())
+ {
+ .error(loc, "cannot have array of scope `%s`", tbn.toChars());
+ return error();
+ }
+
+ /* Ensure things like const(immutable(T)[3]) become immutable(T[3])
+ * and const(T)[3] become const(T[3])
+ */
+ mtype.next = tn;
+ mtype.transitive();
+ return mtype.addMod(tn.mod).merge();
+ }
+
+ Type visitDArray(TypeDArray mtype)
+ {
+ Type tn = mtype.next.typeSemantic(loc, sc);
+ Type tbn = tn.toBasetype();
+ switch (tbn.ty)
+ {
+ case Ttuple:
+ return tbn;
+
+ case Tfunction:
+ case Tnone:
+ .error(loc, "cannot have array of `%s`", tbn.toChars());
+ return error();
+
+ case Terror:
+ return error();
+
+ default:
+ break;
+ }
+ if (tn.isscope())
+ {
+ .error(loc, "cannot have array of scope `%s`", tn.toChars());
+ return error();
+ }
+ mtype.next = tn;
+ mtype.transitive();
+ return merge(mtype);
+ }
+
+ Type visitAArray(TypeAArray mtype)
+ {
+ //printf("TypeAArray::semantic() %s index.ty = %d\n", mtype.toChars(), mtype.index.ty);
+ if (mtype.deco)
+ {
+ return mtype;
+ }
+
+ mtype.loc = loc;
+ if (sc)
+ sc.setNoFree();
+
+ // Deal with the case where we thought the index was a type, but
+ // in reality it was an expression.
+ if (mtype.index.ty == Tident || mtype.index.ty == Tinstance || mtype.index.ty == Tsarray || mtype.index.ty == Ttypeof || mtype.index.ty == Treturn || mtype.index.ty == Tmixin)
+ {
+ Expression e;
+ Type t;
+ Dsymbol s;
+ mtype.index.resolve(loc, sc, e, t, s);
+
+ // https://issues.dlang.org/show_bug.cgi?id=15478
+ if (s)
+ e = symbolToExp(s, loc, sc, false);
+
+ if (e)
+ {
+ // It was an expression -
+ // Rewrite as a static array
+ auto tsa = new TypeSArray(mtype.next, e);
+ return tsa.typeSemantic(loc, sc);
+ }
+ else if (t)
+ mtype.index = t.typeSemantic(loc, sc);
+ else
+ {
+ .error(loc, "index is not a type or an expression");
+ return error();
+ }
+ }
+ else
+ mtype.index = mtype.index.typeSemantic(loc, sc);
+ mtype.index = mtype.index.merge2();
+
+ if (mtype.index.nextOf() && !mtype.index.nextOf().isImmutable())
+ {
+ mtype.index = mtype.index.constOf().mutableOf();
+ version (none)
+ {
+ printf("index is %p %s\n", mtype.index, mtype.index.toChars());
+ mtype.index.check();
+ printf("index.mod = x%x\n", mtype.index.mod);
+ printf("index.ito = x%p\n", mtype.index.getMcache().ito);
+ if (mtype.index.getMcache().ito)
+ {
+ printf("index.ito.mod = x%x\n", mtype.index.getMcache().ito.mod);
+ printf("index.ito.ito = x%p\n", mtype.index.getMcache().ito.getMcache().ito);
+ }
+ }
+ }
+
+ switch (mtype.index.toBasetype().ty)
+ {
+ case Tfunction:
+ case Tvoid:
+ case Tnone:
+ case Ttuple:
+ .error(loc, "cannot have associative array key of `%s`", mtype.index.toBasetype().toChars());
+ goto case Terror;
+ case Terror:
+ return error();
+
+ default:
+ break;
+ }
+ Type tbase = mtype.index.baseElemOf();
+ while (tbase.ty == Tarray)
+ tbase = tbase.nextOf().baseElemOf();
+ if (auto ts = tbase.isTypeStruct())
+ {
+ /* AA's need typeid(index).equals() and getHash(). Issue error if not correctly set up.
+ */
+ StructDeclaration sd = ts.sym;
+ if (sd.semanticRun < PASS.semanticdone)
+ sd.dsymbolSemantic(null);
+
+ // duplicate a part of StructDeclaration::semanticTypeInfoMembers
+ //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
+
+ if (sd.xeq && sd.xeq.generated && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
+ {
+ uint errors = global.startGagging();
+ sd.xeq.semantic3(sd.xeq._scope);
+ if (global.endGagging(errors))
+ sd.xeq = sd.xerreq;
+ }
+
+
+ //printf("AA = %s, key: xeq = %p, xhash = %p\n", toChars(), sd.xeq, sd.xhash);
+ const(char)* s = (mtype.index.toBasetype().ty != Tstruct) ? "bottom of " : "";
+ if (!sd.xeq)
+ {
+ // If sd.xhash != NULL:
+ // sd or its fields have user-defined toHash.
+ // AA assumes that its result is consistent with bitwise equality.
+ // else:
+ // bitwise equality & hashing
+ }
+ else if (sd.xeq == sd.xerreq)
+ {
+ if (search_function(sd, Id.eq))
+ {
+ .error(loc, "%sAA key type `%s` does not have `bool opEquals(ref const %s) const`", s, sd.toChars(), sd.toChars());
+ }
+ else
+ {
+ .error(loc, "%sAA key type `%s` does not support const equality", s, sd.toChars());
+ }
+ return error();
+ }
+ else if (!sd.xhash)
+ {
+ if (search_function(sd, Id.eq))
+ {
+ .error(loc, "%sAA key type `%s` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined", s, sd.toChars());
+ }
+ else
+ {
+ .error(loc, "%sAA key type `%s` supports const equality but doesn't support const hashing", s, sd.toChars());
+ }
+ return error();
+ }
+ else
+ {
+ // defined equality & hashing
+ assert(sd.xeq && sd.xhash);
+
+ /* xeq and xhash may be implicitly defined by compiler. For example:
+ * struct S { int[] arr; }
+ * With 'arr' field equality and hashing, compiler will implicitly
+ * generate functions for xopEquals and xtoHash in TypeInfo_Struct.
+ */
+ }
+ }
+ else if (tbase.ty == Tclass && !(cast(TypeClass)tbase).sym.isInterfaceDeclaration())
+ {
+ ClassDeclaration cd = (cast(TypeClass)tbase).sym;
+ if (cd.semanticRun < PASS.semanticdone)
+ cd.dsymbolSemantic(null);
+
+ if (!ClassDeclaration.object)
+ {
+ .error(Loc.initial, "missing or corrupt object.d");
+ fatal();
+ }
+
+ __gshared FuncDeclaration feq = null;
+ __gshared FuncDeclaration fcmp = null;
+ __gshared FuncDeclaration fhash = null;
+ if (!feq)
+ feq = search_function(ClassDeclaration.object, Id.eq).isFuncDeclaration();
+ if (!fcmp)
+ fcmp = search_function(ClassDeclaration.object, Id.cmp).isFuncDeclaration();
+ if (!fhash)
+ fhash = search_function(ClassDeclaration.object, Id.tohash).isFuncDeclaration();
+ assert(fcmp && feq && fhash);
+
+ if (feq.vtblIndex < cd.vtbl.dim && cd.vtbl[feq.vtblIndex] == feq)
+ {
+ version (all)
+ {
+ if (fcmp.vtblIndex < cd.vtbl.dim && cd.vtbl[fcmp.vtblIndex] != fcmp)
+ {
+ const(char)* s = (mtype.index.toBasetype().ty != Tclass) ? "bottom of " : "";
+ .error(loc, "%sAA key type `%s` now requires equality rather than comparison", s, cd.toChars());
+ errorSupplemental(loc, "Please override `Object.opEquals` and `Object.toHash`.");
+ }
+ }
+ }
+ }
+ mtype.next = mtype.next.typeSemantic(loc, sc).merge2();
+ mtype.transitive();
+
+ switch (mtype.next.toBasetype().ty)
+ {
+ case Tfunction:
+ case Tvoid:
+ case Tnone:
+ case Ttuple:
+ .error(loc, "cannot have associative array of `%s`", mtype.next.toChars());
+ goto case Terror;
+ case Terror:
+ return error();
+ default:
+ break;
+ }
+ if (mtype.next.isscope())
+ {
+ .error(loc, "cannot have array of scope `%s`", mtype.next.toChars());
+ return error();
+ }
+ return merge(mtype);
+ }
+
+ Type visitPointer(TypePointer mtype)
+ {
+ //printf("TypePointer::semantic() %s\n", toChars());
+ if (mtype.deco)
+ {
+ return mtype;
+ }
+ Type n = mtype.next.typeSemantic(loc, sc);
+ switch (n.toBasetype().ty)
+ {
+ case Ttuple:
+ .error(loc, "cannot have pointer to `%s`", n.toChars());
+ goto case Terror;
+ case Terror:
+ return error();
+ default:
+ break;
+ }
+ if (n != mtype.next)
+ {
+ mtype.deco = null;
+ }
+ mtype.next = n;
+ if (mtype.next.ty != Tfunction)
+ {
+ mtype.transitive();
+ return merge(mtype);
+ }
+ version (none)
+ {
+ return merge(mtype);
+ }
+ else
+ {
+ mtype.deco = merge(mtype).deco;
+ /* Don't return merge(), because arg identifiers and default args
+ * can be different
+ * even though the types match
+ */
+ return mtype;
+ }
+ }
+
+ Type visitReference(TypeReference mtype)
+ {
+ //printf("TypeReference::semantic()\n");
+ Type n = mtype.next.typeSemantic(loc, sc);
+ if (n != mtype.next)
+ mtype.deco = null;
+ mtype.next = n;
+ mtype.transitive();
+ return merge(mtype);
+ }
+
+ Type visitFunction(TypeFunction mtype)
+ {
+ if (mtype.deco) // if semantic() already run
+ {
+ //printf("already done\n");
+ return mtype;
+ }
+ //printf("TypeFunction::semantic() this = %p\n", this);
+ //printf("TypeFunction::semantic() %s, sc.stc = %llx, fargs = %p\n", toChars(), sc.stc, fargs);
+
+ bool errors = false;
+
+ if (mtype.inuse > global.recursionLimit)
+ {
+ mtype.inuse = 0;
+ .error(loc, "recursive type");
+ return error();
+ }
+
+ /* Copy in order to not mess up original.
+ * This can produce redundant copies if inferring return type,
+ * as semantic() will get called again on this.
+ */
+ TypeFunction tf = mtype.copy().toTypeFunction();
+ if (mtype.parameterList.parameters)
+ {
+ tf.parameterList.parameters = mtype.parameterList.parameters.copy();
+ for (size_t i = 0; i < mtype.parameterList.parameters.dim; i++)
+ {
+ Parameter p = cast(Parameter)mem.xmalloc(__traits(classInstanceSize, Parameter));
+ memcpy(cast(void*)p, cast(void*)(*mtype.parameterList.parameters)[i], __traits(classInstanceSize, Parameter));
+ (*tf.parameterList.parameters)[i] = p;
+ }
+ }
+
+ if (sc.stc & STC.pure_)
+ tf.purity = PURE.fwdref;
+ if (sc.stc & STC.nothrow_)
+ tf.isnothrow = true;
+ if (sc.stc & STC.nogc)
+ tf.isnogc = true;
+ if (sc.stc & STC.ref_)
+ tf.isref = true;
+ if (sc.stc & STC.return_)
+ tf.isreturn = true;
+ if (sc.stc & STC.returninferred)
+ tf.isreturninferred = true;
+ if (sc.stc & STC.scope_)
+ tf.isScopeQual = true;
+ if (sc.stc & STC.scopeinferred)
+ tf.isscopeinferred = true;
+
+// if (tf.isreturn && !tf.isref)
+// tf.isScopeQual = true; // return by itself means 'return scope'
+
+ if (tf.trust == TRUST.default_)
+ {
+ if (sc.stc & STC.safe)
+ tf.trust = TRUST.safe;
+ else if (sc.stc & STC.system)
+ tf.trust = TRUST.system;
+ else if (sc.stc & STC.trusted)
+ tf.trust = TRUST.trusted;
+ }
+
+ if (sc.stc & STC.property)
+ tf.isproperty = true;
+ if (sc.stc & STC.live)
+ tf.islive = true;
+
+ tf.linkage = sc.linkage;
+ version (none)
+ {
+ /* If the parent is @safe, then this function defaults to safe
+ * too.
+ * If the parent's @safe-ty is inferred, then this function's @safe-ty needs
+ * to be inferred first.
+ */
+ if (tf.trust == TRUST.default_)
+ for (Dsymbol p = sc.func; p; p = p.toParent2())
+ {
+ FuncDeclaration fd = p.isFuncDeclaration();
+ if (fd)
+ {
+ if (fd.isSafeBypassingInference())
+ tf.trust = TRUST.safe; // default to @safe
+ break;
+ }
+ }
+ }
+
+ bool wildreturn = false;
+ if (tf.next)
+ {
+ sc = sc.push();
+ sc.stc &= ~(STC.TYPECTOR | STC.FUNCATTR);
+ tf.next = tf.next.typeSemantic(loc, sc);
+ sc = sc.pop();
+ errors |= tf.checkRetType(loc);
+ if (tf.next.isscope() && !tf.isctor)
+ {
+ .error(loc, "functions cannot return `scope %s`", tf.next.toChars());
+ errors = true;
+ }
+ if (tf.next.hasWild())
+ wildreturn = true;
+
+ if (tf.isreturn && !tf.isref && !tf.next.hasPointers())
+ {
+ tf.isreturn = false;
+ }
+ }
+
+ /// Perform semantic on the default argument to a parameter
+ /// Modify the `defaultArg` field of `fparam`, which must not be `null`
+ /// Returns `false` whether an error was encountered.
+ static bool defaultArgSemantic (ref Parameter fparam, Scope* sc)
+ {
+ Expression e = fparam.defaultArg;
+ const isRefOrOut = fparam.isReference();
+ const isAuto = fparam.storageClass & (STC.auto_ | STC.autoref);
+ if (isRefOrOut && !isAuto)
+ {
+ e = e.expressionSemantic(sc);
+ e = resolveProperties(sc, e);
+ }
+ else
+ {
+ e = inferType(e, fparam.type);
+ Initializer iz = new ExpInitializer(e.loc, e);
+ iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret);
+ e = iz.initializerToExpression();
+ }
+ if (e.op == TOK.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
+ {
+ FuncExp fe = cast(FuncExp)e;
+ // Replace function literal with a function symbol,
+ // since default arg expression must be copied when used
+ // and copying the literal itself is wrong.
+ e = new VarExp(e.loc, fe.fd, false);
+ e = new AddrExp(e.loc, e);
+ e = e.expressionSemantic(sc);
+ }
+ if (isRefOrOut && (!isAuto || e.isLvalue())
+ && !MODimplicitConv(e.type.mod, fparam.type.mod))
+ {
+ const(char)* errTxt = fparam.storageClass & STC.ref_ ? "ref" : "out";
+ .error(e.loc, "expression `%s` of type `%s` is not implicitly convertible to type `%s %s` of parameter `%s`",
+ e.toChars(), e.type.toChars(), errTxt, fparam.type.toChars(), fparam.toChars());
+ }
+ e = e.implicitCastTo(sc, fparam.type);
+
+ // default arg must be an lvalue
+ if (isRefOrOut && !isAuto &&
+ !(global.params.previewIn && (fparam.storageClass & STC.in_)) &&
+ !(global.params.rvalueRefParam))
+ e = e.toLvalue(sc, e);
+
+ fparam.defaultArg = e;
+ return (e.op != TOK.error);
+ }
+
+ ubyte wildparams = 0;
+ if (tf.parameterList.parameters)
+ {
+ /* Create a scope for evaluating the default arguments for the parameters
+ */
+ Scope* argsc = sc.push();
+ argsc.stc = 0; // don't inherit storage class
+ argsc.visibility = Visibility(Visibility.Kind.public_);
+ argsc.func = null;
+
+ size_t dim = tf.parameterList.length;
+ for (size_t i = 0; i < dim; i++)
+ {
+ Parameter fparam = tf.parameterList[i];
+ fparam.storageClass |= STC.parameter;
+ mtype.inuse++;
+ fparam.type = fparam.type.typeSemantic(loc, argsc);
+ mtype.inuse--;
+
+ if (fparam.type.ty == Terror)
+ {
+ errors = true;
+ continue;
+ }
+
+ fparam.type = fparam.type.addStorageClass(fparam.storageClass);
+
+ if (fparam.storageClass & (STC.auto_ | STC.alias_ | STC.static_))
+ {
+ if (!fparam.type)
+ continue;
+ }
+
+ Type t = fparam.type.toBasetype();
+
+ /* If fparam after semantic() turns out to be a tuple, the number of parameters may
+ * change.
+ */
+ if (auto tt = t.isTypeTuple())
+ {
+ /* TypeFunction::parameter also is used as the storage of
+ * Parameter objects for FuncDeclaration. So we should copy
+ * the elements of TypeTuple::arguments to avoid unintended
+ * sharing of Parameter object among other functions.
+ */
+ if (tt.arguments && tt.arguments.dim)
+ {
+ /* Propagate additional storage class from tuple parameters to their
+ * element-parameters.
+ * Make a copy, as original may be referenced elsewhere.
+ */
+ size_t tdim = tt.arguments.dim;
+ auto newparams = new Parameters(tdim);
+ for (size_t j = 0; j < tdim; j++)
+ {
+ Parameter narg = (*tt.arguments)[j];
+
+ // https://issues.dlang.org/show_bug.cgi?id=12744
+ // If the storage classes of narg
+ // conflict with the ones in fparam, it's ignored.
+ StorageClass stc = fparam.storageClass | narg.storageClass;
+ StorageClass stc1 = fparam.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
+ StorageClass stc2 = narg.storageClass & (STC.ref_ | STC.out_ | STC.lazy_);
+ if (stc1 && stc2 && stc1 != stc2)
+ {
+ OutBuffer buf1; stcToBuffer(&buf1, stc1 | ((stc1 & STC.ref_) ? (fparam.storageClass & STC.auto_) : 0));
+ OutBuffer buf2; stcToBuffer(&buf2, stc2);
+
+ .error(loc, "incompatible parameter storage classes `%s` and `%s`",
+ buf1.peekChars(), buf2.peekChars());
+ errors = true;
+ stc = stc1 | (stc & ~(STC.ref_ | STC.out_ | STC.lazy_));
+ }
+ (*newparams)[j] = new Parameter(
+ stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl);
+ }
+ fparam.type = new TypeTuple(newparams);
+ }
+ fparam.storageClass = STC.parameter;
+
+ /* Reset number of parameters, and back up one to do this fparam again,
+ * now that it is a tuple
+ */
+ dim = tf.parameterList.length;
+ i--;
+ continue;
+ }
+
+ if (t.ty == Tfunction)
+ {
+ .error(loc, "cannot have parameter of function type `%s`", fparam.type.toChars());
+ errors = true;
+ }
+ else if (!fparam.isReference() &&
+ (t.ty == Tstruct || t.ty == Tsarray || t.ty == Tenum))
+ {
+ Type tb2 = t.baseElemOf();
+ if (tb2.ty == Tstruct && !(cast(TypeStruct)tb2).sym.members ||
+ tb2.ty == Tenum && !(cast(TypeEnum)tb2).sym.memtype)
+ {
+ if (global.params.previewIn && (fparam.storageClass & STC.in_))
+ {
+ .error(loc, "cannot infer `ref` for `in` parameter `%s` of opaque type `%s`",
+ fparam.toChars(), fparam.type.toChars());
+ }
+ else
+ .error(loc, "cannot have parameter of opaque type `%s` by value",
+ fparam.type.toChars());
+ errors = true;
+ }
+ }
+ else if (!(fparam.storageClass & STC.lazy_) && t.ty == Tvoid)
+ {
+ .error(loc, "cannot have parameter of type `%s`", fparam.type.toChars());
+ errors = true;
+ }
+
+ if ((fparam.storageClass & (STC.ref_ | STC.wild)) == (STC.ref_ | STC.wild))
+ {
+ // 'ref inout' implies 'return'
+ fparam.storageClass |= STC.return_;
+ }
+
+ if (fparam.storageClass & STC.return_)
+ {
+ if (fparam.isReference())
+ {
+ // Disabled for the moment awaiting improvement to allow return by ref
+ // to be transformed into return by scope.
+ if (0 && !tf.isref)
+ {
+ auto stc = fparam.storageClass & (STC.ref_ | STC.out_);
+ .error(loc, "parameter `%s` is `return %s` but function does not return by `ref`",
+ fparam.ident ? fparam.ident.toChars() : "",
+ stcToString(stc).ptr);
+ errors = true;
+ }
+ }
+ else
+ {
+ if (!(fparam.storageClass & STC.scope_))
+ fparam.storageClass |= STC.scope_ | STC.scopeinferred; // 'return' implies 'scope'
+ if (tf.isref)
+ {
+ }
+ else if (tf.next && !tf.next.hasPointers() && tf.next.toBasetype().ty != Tvoid)
+ {
+ fparam.storageClass &= ~STC.return_; // https://issues.dlang.org/show_bug.cgi?id=18963
+ }
+ }
+ }
+
+ if (fparam.storageClass & STC.out_)
+ {
+ if (ubyte m = fparam.type.mod & (MODFlags.immutable_ | MODFlags.const_ | MODFlags.wild))
+ {
+ .error(loc, "cannot have `%s out` parameter of type `%s`", MODtoChars(m), t.toChars());
+ errors = true;
+ }
+ else
+ {
+ Type tv = t.baseElemOf();
+ if (tv.ty == Tstruct && (cast(TypeStruct)tv).sym.noDefaultCtor)
+ {
+ .error(loc, "cannot have `out` parameter of type `%s` because the default construction is disabled", fparam.type.toChars());
+ errors = true;
+ }
+ }
+ }
+
+ if (t.hasWild())
+ {
+ wildparams |= 1;
+ //if (tf.next && !wildreturn)
+ // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)");
+ }
+
+ /* Scope attribute is not necessary if the parameter type does not have pointers
+ */
+ /* Constructors are treated as if they are being returned through the hidden parameter,
+ * which is by ref, and the ref there is ignored.
+ */
+ const returnByRef = tf.isref && !tf.isctor;
+ if (!returnByRef && isRefReturnScope(fparam.storageClass))
+ {
+ /* if `ref return scope`, evaluate to `ref` `return scope`
+ */
+ fparam.storageClass |= STC.returnScope;
+ }
+ const sr = buildScopeRef(fparam.storageClass);
+ switch (sr)
+ {
+ case ScopeRef.Scope:
+ case ScopeRef.RefScope:
+ case ScopeRef.ReturnRef_Scope:
+ if (!fparam.type.hasPointers())
+ fparam.storageClass &= ~STC.scope_;
+ break;
+
+ case ScopeRef.ReturnScope:
+ case ScopeRef.Ref_ReturnScope:
+ if (!fparam.type.hasPointers())
+ fparam.storageClass &= ~(STC.return_ | STC.scope_ | STC.returnScope);
+ break;
+
+ default:
+ break;
+ }
+
+ /* now set STC.returnScope based only on tf.isref. This is inconsistent, as mentioned above,
+ * but necessary for compatibility for now.
+ */
+ fparam.storageClass &= ~STC.returnScope;
+ if (!tf.isref && isRefReturnScope(fparam.storageClass))
+ {
+ /* if `ref return scope`, evaluate to `ref` `return scope`
+ */
+ fparam.storageClass |= STC.returnScope;
+ }
+
+ // Remove redundant storage classes for type, they are already applied
+ fparam.storageClass &= ~(STC.TYPECTOR);
+
+ // -preview=in: add `ref` storage class to suited `in` params
+ if (global.params.previewIn && (fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_)
+ {
+ auto ts = t.baseElemOf().isTypeStruct();
+ const isPOD = !ts || ts.sym.isPOD();
+ if (!isPOD || target.preferPassByRef(t))
+ fparam.storageClass |= STC.ref_;
+ }
+ }
+
+ // Now that we completed semantic for the argument types,
+ // run semantic on their default values,
+ // bearing in mind tuples have been expanded.
+ // We need to keep a pair of [oidx, eidx] (original index,
+ // extended index), as we need to run semantic when `oidx` changes.
+ size_t tupleOrigIdx = size_t.max;
+ size_t tupleExtIdx = size_t.max;
+ foreach (oidx, oparam, eidx, eparam; tf.parameterList)
+ {
+ // oparam (original param) will always have the default arg
+ // if there's one, but `eparam` will not if it's an expanded
+ // tuple. When we see an expanded tuple, we need to save its
+ // position to get the offset in it later on.
+ if (oparam.defaultArg)
+ {
+ // Get the obvious case out of the way
+ if (oparam is eparam)
+ errors |= !defaultArgSemantic(eparam, argsc);
+ // We're seeing a new tuple
+ else if (tupleOrigIdx == size_t.max || tupleOrigIdx < oidx)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=18572
+ *
+ * If a tuple parameter has a default argument, when expanding the parameter
+ * tuple the default argument tuple must also be expanded.
+ */
+ tupleOrigIdx = oidx;
+ tupleExtIdx = eidx;
+ errors |= !defaultArgSemantic(oparam, argsc);
+ TupleExp te = oparam.defaultArg.isTupleExp();
+ if (te && te.exps && te.exps.length)
+ eparam.defaultArg = (*te.exps)[0];
+ }
+ // Processing an already-seen tuple
+ else
+ {
+ TupleExp te = oparam.defaultArg.isTupleExp();
+ if (te && te.exps && te.exps.length)
+ eparam.defaultArg = (*te.exps)[eidx - tupleExtIdx];
+ }
+ }
+
+ // We need to know the default argument to resolve `auto ref`,
+ // hence why this has to take place as the very last step.
+ /* Resolve "auto ref" storage class to be either ref or value,
+ * based on the argument matching the parameter
+ */
+ if (eparam.storageClass & STC.auto_)
+ {
+ Expression farg = mtype.fargs && eidx < mtype.fargs.dim ?
+ (*mtype.fargs)[eidx] : eparam.defaultArg;
+ if (farg && (eparam.storageClass & STC.ref_))
+ {
+ if (!farg.isLvalue())
+ eparam.storageClass &= ~STC.ref_; // value parameter
+ eparam.storageClass &= ~STC.auto_; // https://issues.dlang.org/show_bug.cgi?id=14656
+ eparam.storageClass |= STC.autoref;
+ }
+ else if (mtype.incomplete && (eparam.storageClass & STC.ref_))
+ {
+ // the default argument may have been temporarily removed,
+ // see usage of `TypeFunction.incomplete`.
+ // https://issues.dlang.org/show_bug.cgi?id=19891
+ eparam.storageClass &= ~STC.auto_;
+ eparam.storageClass |= STC.autoref;
+ }
+ else
+ {
+ .error(loc, "`auto` can only be used as part of `auto ref` for template function parameters");
+ errors = true;
+ }
+ }
+ }
+
+ argsc.pop();
+ }
+ if (tf.isWild())
+ wildparams |= 2;
+
+ if (wildreturn && !wildparams)
+ {
+ .error(loc, "`inout` on `return` means `inout` must be on a parameter as well for `%s`", mtype.toChars());
+ errors = true;
+ }
+ tf.isInOutParam = (wildparams & 1) != 0;
+ tf.isInOutQual = (wildparams & 2) != 0;
+
+ if (tf.isproperty && (tf.parameterList.varargs != VarArg.none || tf.parameterList.length > 2))
+ {
+ .error(loc, "properties can only have zero, one, or two parameter");
+ errors = true;
+ }
+
+ if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0)
+ {
+ .error(loc, "variadic functions with non-D linkage must have at least one parameter");
+ errors = true;
+ }
+
+ if (errors)
+ return error();
+
+ if (tf.next)
+ tf.deco = tf.merge().deco;
+
+ /* Don't return merge(), because arg identifiers and default args
+ * can be different
+ * even though the types match
+ */
+ return tf;
+ }
+
+ Type visitDelegate(TypeDelegate mtype)
+ {
+ //printf("TypeDelegate::semantic() %s\n", mtype.toChars());
+ if (mtype.deco) // if semantic() already run
+ {
+ //printf("already done\n");
+ return mtype;
+ }
+ mtype.next = mtype.next.typeSemantic(loc, sc);
+ if (mtype.next.ty != Tfunction)
+ return error();
+
+ /* In order to deal with https://issues.dlang.org/show_bug.cgi?id=4028
+ * perhaps default arguments should
+ * be removed from next before the merge.
+ */
+ version (none)
+ {
+ return mtype.merge();
+ }
+ else
+ {
+ /* Don't return merge(), because arg identifiers and default args
+ * can be different
+ * even though the types match
+ */
+ mtype.deco = mtype.merge().deco;
+ return mtype;
+ }
+ }
+
+ Type visitIdentifier(TypeIdentifier mtype)
+ {
+ Type t;
+ Expression e;
+ Dsymbol s;
+ //printf("TypeIdentifier::semantic(%s)\n", mtype.toChars());
+ mtype.resolve(loc, sc, e, t, s);
+ if (t)
+ {
+ //printf("\tit's a type %d, %s, %s\n", t.ty, t.toChars(), t.deco);
+ return t.addMod(mtype.mod);
+ }
+ else
+ {
+ if (s)
+ {
+ auto td = s.isTemplateDeclaration;
+ if (td && td.onemember && td.onemember.isAggregateDeclaration)
+ .error(loc, "template %s `%s` is used as a type without instantiation"
+ ~ "; to instantiate it use `%s!(arguments)`",
+ s.kind, s.toPrettyChars, s.ident.toChars);
+ else
+ .error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars);
+ //assert(0);
+ }
+ else if (e.op == TOK.variable) // special case: variable is used as a type
+ {
+ Dsymbol varDecl = mtype.toDsymbol(sc);
+ const(Loc) varDeclLoc = varDecl.getLoc();
+ Module varDeclModule = varDecl.getModule();
+
+ .error(loc, "variable `%s` is used as a type", mtype.toChars());
+
+ if (varDeclModule != sc._module) // variable is imported
+ {
+ const(Loc) varDeclModuleImportLoc = varDeclModule.getLoc();
+ .errorSupplemental(
+ varDeclModuleImportLoc,
+ "variable `%s` is imported here from: `%s`",
+ varDecl.toChars,
+ varDeclModule.toPrettyChars,
+ );
+ }
+
+ .errorSupplemental(varDeclLoc, "variable `%s` is declared here", varDecl.toChars);
+ }
+ else
+ .error(loc, "`%s` is used as a type", mtype.toChars());
+ return error();
+ }
+ }
+
+ Type visitInstance(TypeInstance mtype)
+ {
+ Type t;
+ Expression e;
+ Dsymbol s;
+
+ //printf("TypeInstance::semantic(%p, %s)\n", this, toChars());
+ {
+ const errors = global.errors;
+ mtype.resolve(loc, sc, e, t, s);
+ // if we had an error evaluating the symbol, suppress further errors
+ if (!t && errors != global.errors)
+ return error();
+ }
+
+ if (!t)
+ {
+ if (!e && s && s.errors)
+ {
+ // if there was an error evaluating the symbol, it might actually
+ // be a type. Avoid misleading error messages.
+ .error(loc, "`%s` had previous errors", mtype.toChars());
+ }
+ else
+ .error(loc, "`%s` is used as a type", mtype.toChars());
+ return error();
+ }
+ return t;
+ }
+
+ Type visitTypeof(TypeTypeof mtype)
+ {
+ //printf("TypeTypeof::semantic() %s\n", mtype.toChars());
+ Expression e;
+ Type t;
+ Dsymbol s;
+ mtype.resolve(loc, sc, e, t, s);
+ if (s && (t = s.getType()) !is null)
+ t = t.addMod(mtype.mod);
+ if (!t)
+ {
+ .error(loc, "`%s` is used as a type", mtype.toChars());
+ return error();
+ }
+ return t;
+ }
+
+ Type visitTraits(TypeTraits mtype)
+ {
+ if (mtype.ty == Terror)
+ return mtype;
+
+ const inAlias = (sc.flags & SCOPE.alias_) != 0;
+ if (mtype.exp.ident != Id.allMembers &&
+ mtype.exp.ident != Id.derivedMembers &&
+ mtype.exp.ident != Id.getMember &&
+ mtype.exp.ident != Id.parent &&
+ mtype.exp.ident != Id.child &&
+ mtype.exp.ident != Id.toType &&
+ mtype.exp.ident != Id.getOverloads &&
+ mtype.exp.ident != Id.getVirtualFunctions &&
+ mtype.exp.ident != Id.getVirtualMethods &&
+ mtype.exp.ident != Id.getAttributes &&
+ mtype.exp.ident != Id.getUnitTests &&
+ mtype.exp.ident != Id.getAliasThis)
+ {
+ static immutable (const(char)*)[2] ctxt = ["as type", "in alias"];
+ .error(mtype.loc, "trait `%s` is either invalid or not supported %s",
+ mtype.exp.ident.toChars, ctxt[inAlias]);
+ mtype.ty = Terror;
+ return mtype;
+ }
+
+ import dmd.traits : semanticTraits;
+ Type result;
+
+ if (Expression e = semanticTraits(mtype.exp, sc))
+ {
+ switch (e.op)
+ {
+ case TOK.dotVariable:
+ mtype.sym = (cast(DotVarExp)e).var;
+ break;
+ case TOK.variable:
+ mtype.sym = (cast(VarExp)e).var;
+ break;
+ case TOK.function_:
+ auto fe = cast(FuncExp)e;
+ mtype.sym = fe.td ? fe.td : fe.fd;
+ break;
+ case TOK.dotTemplateDeclaration:
+ mtype.sym = (cast(DotTemplateExp)e).td;
+ break;
+ case TOK.dSymbol:
+ mtype.sym = (cast(DsymbolExp)e).s;
+ break;
+ case TOK.template_:
+ mtype.sym = (cast(TemplateExp)e).td;
+ break;
+ case TOK.scope_:
+ mtype.sym = (cast(ScopeExp)e).sds;
+ break;
+ case TOK.tuple:
+ TupleExp te = e.toTupleExp();
+ Objects* elems = new Objects(te.exps.dim);
+ foreach (i; 0 .. elems.dim)
+ {
+ auto src = (*te.exps)[i];
+ switch (src.op)
+ {
+ case TOK.type:
+ (*elems)[i] = (cast(TypeExp)src).type;
+ break;
+ case TOK.dotType:
+ (*elems)[i] = (cast(DotTypeExp)src).sym.isType();
+ break;
+ case TOK.overloadSet:
+ (*elems)[i] = (cast(OverExp)src).type;
+ break;
+ default:
+ if (auto sym = isDsymbol(src))
+ (*elems)[i] = sym;
+ else
+ (*elems)[i] = src;
+ }
+ }
+ TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems);
+ mtype.sym = td;
+ break;
+ case TOK.dotType:
+ result = (cast(DotTypeExp)e).sym.isType();
+ break;
+ case TOK.type:
+ result = (cast(TypeExp)e).type;
+ break;
+ case TOK.overloadSet:
+ result = (cast(OverExp)e).type;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (result)
+ result = result.addMod(mtype.mod);
+ if (!inAlias && !result)
+ {
+ if (!global.errors)
+ .error(mtype.loc, "`%s` does not give a valid type", mtype.toChars);
+ return error();
+ }
+
+ return result;
+ }
+
+ Type visitReturn(TypeReturn mtype)
+ {
+ //printf("TypeReturn::semantic() %s\n", toChars());
+ Expression e;
+ Type t;
+ Dsymbol s;
+ mtype.resolve(loc, sc, e, t, s);
+ if (s && (t = s.getType()) !is null)
+ t = t.addMod(mtype.mod);
+ if (!t)
+ {
+ .error(loc, "`%s` is used as a type", mtype.toChars());
+ return error();
+ }
+ return t;
+ }
+
+ Type visitStruct(TypeStruct mtype)
+ {
+ //printf("TypeStruct::semantic('%s')\n", mtype.toChars());
+ if (mtype.deco)
+ return mtype;
+
+ /* Don't semantic for sym because it should be deferred until
+ * sizeof needed or its members accessed.
+ */
+ // instead, parent should be set correctly
+ assert(mtype.sym.parent);
+
+ if (mtype.sym.type.ty == Terror)
+ return error();
+
+ return merge(mtype);
+ }
+
+ Type visitEnum(TypeEnum mtype)
+ {
+ //printf("TypeEnum::semantic() %s\n", toChars());
+ return mtype.deco ? mtype : merge(mtype);
+ }
+
+ Type visitClass(TypeClass mtype)
+ {
+ //printf("TypeClass::semantic(%s)\n", mtype.toChars());
+ if (mtype.deco)
+ return mtype;
+
+ /* Don't semantic for sym because it should be deferred until
+ * sizeof needed or its members accessed.
+ */
+ // instead, parent should be set correctly
+ assert(mtype.sym.parent);
+
+ if (mtype.sym.type.ty == Terror)
+ return error();
+
+ return merge(mtype);
+ }
+
+ Type visitTuple(TypeTuple mtype)
+ {
+ //printf("TypeTuple::semantic(this = %p)\n", this);
+ //printf("TypeTuple::semantic() %p, %s\n", this, toChars());
+ if (!mtype.deco)
+ mtype.deco = merge(mtype).deco;
+
+ /* Don't return merge(), because a tuple with one type has the
+ * same deco as that type.
+ */
+ return mtype;
+ }
+
+ Type visitSlice(TypeSlice mtype)
+ {
+ //printf("TypeSlice::semantic() %s\n", toChars());
+ Type tn = mtype.next.typeSemantic(loc, sc);
+ //printf("next: %s\n", tn.toChars());
+
+ Type tbn = tn.toBasetype();
+ if (tbn.ty != Ttuple)
+ {
+ .error(loc, "can only slice tuple types, not `%s`", tbn.toChars());
+ return error();
+ }
+ TypeTuple tt = cast(TypeTuple)tbn;
+
+ mtype.lwr = semanticLength(sc, tbn, mtype.lwr);
+ mtype.upr = semanticLength(sc, tbn, mtype.upr);
+ mtype.lwr = mtype.lwr.ctfeInterpret();
+ mtype.upr = mtype.upr.ctfeInterpret();
+ if (mtype.lwr.op == TOK.error || mtype.upr.op == TOK.error)
+ return error();
+
+ uinteger_t i1 = mtype.lwr.toUInteger();
+ uinteger_t i2 = mtype.upr.toUInteger();
+ if (!(i1 <= i2 && i2 <= tt.arguments.dim))
+ {
+ .error(loc, "slice `[%llu..%llu]` is out of range of `[0..%llu]`",
+ cast(ulong)i1, cast(ulong)i2, cast(ulong)tt.arguments.dim);
+ return error();
+ }
+
+ mtype.next = tn;
+ mtype.transitive();
+
+ auto args = new Parameters();
+ args.reserve(cast(size_t)(i2 - i1));
+ foreach (arg; (*tt.arguments)[cast(size_t)i1 .. cast(size_t)i2])
+ {
+ args.push(arg);
+ }
+ Type t = new TypeTuple(args);
+ return t.typeSemantic(loc, sc);
+ }
+
+ Type visitMixin(TypeMixin mtype)
+ {
+ //printf("TypeMixin::semantic() %s\n", toChars());
+
+ Expression e;
+ Type t;
+ Dsymbol s;
+ mtype.resolve(loc, sc, e, t, s);
+
+ if (t && t.ty != Terror)
+ return t;
+
+ .error(mtype.loc, "`mixin(%s)` does not give a valid type", mtype.obj.toChars);
+ return error();
+ }
+
+ Type visitTag(TypeTag mtype)
+ {
+ //printf("TypeTag.semantic() %s\n", mtype.toChars());
+ if (mtype.resolved)
+ {
+ /* struct S s, *p;
+ */
+ //printf("already resolved\n");
+ return mtype.resolved;
+ }
+
+ /* Declare mtype as a struct/union/enum declaration
+ */
+ void declareTag()
+ {
+ void declare(ScopeDsymbol sd)
+ {
+ sd.members = mtype.members;
+ auto scopesym = sc.inner().scopesym;
+ if (scopesym.members)
+ scopesym.members.push(sd);
+ if (scopesym.symtab && !scopesym.symtabInsert(sd))
+ {
+ Dsymbol s2 = scopesym.symtabLookup(sd, mtype.id);
+ handleTagSymbols(*sc, sd, s2, scopesym);
+ }
+ sd.parent = sc.parent;
+ sd.dsymbolSemantic(sc);
+ }
+
+ switch (mtype.tok)
+ {
+ case TOK.enum_:
+ auto ed = new EnumDeclaration(mtype.loc, mtype.id, Type.tint32);
+ declare(ed);
+ mtype.resolved = visitEnum(new TypeEnum(ed));
+ break;
+
+ case TOK.struct_:
+ auto sd = new StructDeclaration(mtype.loc, mtype.id, false);
+ declare(sd);
+ mtype.resolved = visitStruct(new TypeStruct(sd));
+ break;
+
+ case TOK.union_:
+ auto ud = new UnionDeclaration(mtype.loc, mtype.id);
+ declare(ud);
+ mtype.resolved = visitStruct(new TypeStruct(ud));
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+
+ /* If it doesn't have a tag by now, supply one.
+ * It'll be unique, and therefore introducing.
+ * Declare it, and done.
+ */
+ if (!mtype.id)
+ {
+ mtype.id = Identifier.generateId("__tag"[]);
+ declareTag();
+ return mtype.resolved;
+ }
+
+ /* look for pre-existing declaration
+ */
+ Dsymbol scopesym;
+ auto s = sc.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace);
+ if (!s || s.isModule())
+ {
+ // no pre-existing declaration, so declare it
+ if (mtype.tok == TOK.enum_ && !mtype.members)
+ .error(mtype.loc, "`enum %s` is incomplete without members", mtype.id.toChars()); // C11 6.7.2.3-3
+ declareTag();
+ return mtype.resolved;
+ }
+
+ /* A redeclaration only happens if both declarations are in
+ * the same scope
+ */
+ const bool redeclar = (scopesym == sc.inner().scopesym);
+
+ if (redeclar)
+ {
+ if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
+ {
+ auto ed = s.isEnumDeclaration();
+ if (mtype.members && ed.members)
+ .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
+ else if (!ed.members)
+ {
+ ed.members = mtype.members;
+ }
+ else
+ {
+ }
+ mtype.resolved = ed.type;
+ }
+ else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
+ mtype.tok == TOK.struct_ && s.isStructDeclaration())
+ {
+ // Add members to original declaration
+ auto sd = s.isStructDeclaration();
+ if (mtype.members && sd.members)
+ {
+ /* struct S { int b; };
+ * struct S { int a; } *s;
+ */
+ .error(mtype.loc, "`%s` already has members", mtype.id.toChars());
+ }
+ else if (!sd.members)
+ {
+ /* struct S;
+ * struct S { int a; } *s;
+ */
+ sd.members = mtype.members;
+ }
+ else
+ {
+ /* struct S { int a; };
+ * struct S *s;
+ */
+ }
+ mtype.resolved = sd.type;
+ }
+ else
+ {
+ /* int S;
+ * struct S { int a; } *s;
+ */
+ .error(mtype.loc, "redeclaration of `%s`", mtype.id.toChars());
+ mtype.resolved = error();
+ }
+ }
+ else if (mtype.members)
+ {
+ /* struct S;
+ * { struct S { int a; } *s; }
+ */
+ declareTag();
+ }
+ else
+ {
+ if (mtype.tok == TOK.enum_ && s.isEnumDeclaration())
+ {
+ mtype.resolved = s.isEnumDeclaration().type;
+ }
+ else if (mtype.tok == TOK.union_ && s.isUnionDeclaration() ||
+ mtype.tok == TOK.struct_ && s.isStructDeclaration())
+ {
+ /* struct S;
+ * { struct S *s; }
+ */
+ mtype.resolved = s.isStructDeclaration().type;
+ }
+ else
+ {
+ /* union S;
+ * { struct S *s; }
+ */
+ .error(mtype.loc, "redeclaring `%s %s` as `%s %s`",
+ s.kind(), s.toChars(), Token.toChars(mtype.tok), mtype.id.toChars());
+ declareTag();
+ }
+ }
+ return mtype.resolved;
+ }
+
+ switch (type.ty)
+ {
+ default: return visitType(type);
+ case Tvector: return visitVector(cast(TypeVector)type);
+ case Tsarray: return visitSArray(cast(TypeSArray)type);
+ case Tarray: return visitDArray(cast(TypeDArray)type);
+ case Taarray: return visitAArray(cast(TypeAArray)type);
+ case Tpointer: return visitPointer(cast(TypePointer)type);
+ case Treference: return visitReference(cast(TypeReference)type);
+ case Tfunction: return visitFunction(cast(TypeFunction)type);
+ case Tdelegate: return visitDelegate(cast(TypeDelegate)type);
+ case Tident: return visitIdentifier(cast(TypeIdentifier)type);
+ case Tinstance: return visitInstance(cast(TypeInstance)type);
+ case Ttypeof: return visitTypeof(cast(TypeTypeof)type);
+ case Ttraits: return visitTraits(cast(TypeTraits)type);
+ case Treturn: return visitReturn(cast(TypeReturn)type);
+ case Tstruct: return visitStruct(cast(TypeStruct)type);
+ case Tenum: return visitEnum(cast(TypeEnum)type);
+ case Tclass: return visitClass(cast(TypeClass)type);
+ case Ttuple: return visitTuple (cast(TypeTuple)type);
+ case Tslice: return visitSlice(cast(TypeSlice)type);
+ case Tmixin: return visitMixin(cast(TypeMixin)type);
+ case Ttag: return visitTag(cast(TypeTag)type);
+ }
+}
+
+/******************************************
+ * Compile the MixinType, returning the type or expression AST.
+ *
+ * Doesn't run semantic() on the returned object.
+ * Params:
+ * tm = mixin to compile as a type or expression
+ * loc = location for error messages
+ * sc = context
+ * Return:
+ * null if error, else RootObject AST as parsed
+ */
+RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
+{
+ OutBuffer buf;
+ if (expressionsToString(buf, sc, tm.exps))
+ return null;
+
+ const errors = global.errors;
+ const len = buf.length;
+ buf.writeByte(0);
+ const str = buf.extractSlice()[0 .. len];
+ scope p = new Parser!ASTCodegen(loc, sc._module, str, false);
+ p.nextToken();
+ //printf("p.loc.linnum = %d\n", p.loc.linnum);
+
+ auto o = p.parseTypeOrAssignExp(TOK.endOfFile);
+ if (errors != global.errors)
+ {
+ assert(global.errors != errors); // should have caught all these cases
+ return null;
+ }
+ if (p.token.value != TOK.endOfFile)
+ {
+ .error(loc, "incomplete mixin type `%s`", str.ptr);
+ return null;
+ }
+
+ Type t = o.isType();
+ Expression e = t ? t.typeToExpression() : o.isExpression();
+
+ return (!e && t) ? t : e;
+}
+
+
+/************************************
+ * If an identical type to `type` is in `type.stringtable`, return
+ * the latter one. Otherwise, add it to `type.stringtable`.
+ * Some types don't get merged and are returned as-is.
+ * Params:
+ * type = Type to check against existing types
+ * Returns:
+ * the type that was merged
+ */
+Type merge(Type type)
+{
+ switch (type.ty)
+ {
+ case Terror:
+ case Ttypeof:
+ case Tident:
+ case Tinstance:
+ case Tmixin:
+ return type;
+
+ case Tsarray:
+ // prevents generating the mangle if the array dim is not yet known
+ if (!(cast(TypeSArray) type).dim.isIntegerExp())
+ return type;
+ goto default;
+
+ case Tenum:
+ break;
+
+ case Taarray:
+ if (!(cast(TypeAArray)type).index.merge().deco)
+ return type;
+ goto default;
+
+ default:
+ if (type.nextOf() && !type.nextOf().deco)
+ return type;
+ break;
+ }
+
+ //printf("merge(%s)\n", toChars());
+ if (!type.deco)
+ {
+ OutBuffer buf;
+ buf.reserve(32);
+
+ mangleToBuffer(type, &buf);
+
+ auto sv = type.stringtable.update(buf[]);
+ if (sv.value)
+ {
+ Type t = sv.value;
+ debug
+ {
+ import core.stdc.stdio;
+ if (!t.deco)
+ printf("t = %s\n", t.toChars());
+ }
+ assert(t.deco);
+ //printf("old value, deco = '%s' %p\n", t.deco, t.deco);
+ return t;
+ }
+ else
+ {
+ Type t = stripDefaultArgs(type);
+ sv.value = t;
+ type.deco = t.deco = cast(char*)sv.toDchars();
+ //printf("new value, deco = '%s' %p\n", t.deco, t.deco);
+ return t;
+ }
+ }
+ return type;
+}
+
+/***************************************
+ * Calculate built-in properties which just the type is necessary.
+ *
+ * Params:
+ * t = the type for which the property is calculated
+ * scope_ = the scope from which the property is being accessed. Used for visibility checks only.
+ * loc = the location where the property is encountered
+ * ident = the identifier of the property
+ * flag = if flag & 1, don't report "not a property" error and just return NULL.
+ * Returns:
+ * expression representing the property, or null if not a property and (flag & 1)
+ */
+Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier ident, int flag)
+{
+ Expression visitType(Type mt)
+ {
+ Expression e;
+ static if (LOGDOTEXP)
+ {
+ printf("Type::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
+ }
+ if (ident == Id.__sizeof)
+ {
+ d_uns64 sz = mt.size(loc);
+ if (sz == SIZE_INVALID)
+ return ErrorExp.get();
+ e = new IntegerExp(loc, sz, Type.tsize_t);
+ }
+ else if (ident == Id.__xalignof)
+ {
+ const explicitAlignment = mt.alignment();
+ const naturalAlignment = mt.alignsize();
+ const actualAlignment = (explicitAlignment == STRUCTALIGN_DEFAULT ? naturalAlignment : explicitAlignment);
+ e = new IntegerExp(loc, actualAlignment, Type.tsize_t);
+ }
+ else if (ident == Id._init)
+ {
+ Type tb = mt.toBasetype();
+ e = mt.defaultInitLiteral(loc);
+ if (tb.ty == Tstruct && tb.needsNested())
+ {
+ e.isStructLiteralExp().useStaticInit = true;
+ }
+ }
+ else if (ident == Id._mangleof)
+ {
+ if (!mt.deco)
+ {
+ error(loc, "forward reference of type `%s.mangleof`", mt.toChars());
+ e = ErrorExp.get();
+ }
+ else
+ {
+ e = new StringExp(loc, mt.deco.toDString());
+ Scope sc;
+ e = e.expressionSemantic(&sc);
+ }
+ }
+ else if (ident == Id.stringof)
+ {
+ const s = mt.toChars();
+ e = new StringExp(loc, s.toDString());
+ Scope sc;
+ e = e.expressionSemantic(&sc);
+ }
+ else if (flag && mt != Type.terror)
+ {
+ return null;
+ }
+ else
+ {
+ Dsymbol s = null;
+ if (mt.ty == Tstruct || mt.ty == Tclass || mt.ty == Tenum)
+ s = mt.toDsymbol(null);
+ if (s)
+ s = s.search_correct(ident);
+ if (s && !symbolIsVisible(scope_, s))
+ s = null;
+ if (mt != Type.terror)
+ {
+ if (s)
+ error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident.toChars(), mt.toChars(), s.toPrettyChars());
+ else if (ident == Id.call && mt.ty == Tclass)
+ error(loc, "no property `%s` for type `%s`, did you mean `new %s`?", ident.toChars(), mt.toChars(), mt.toPrettyChars());
+
+ else if (const n = importHint(ident.toString()))
+ error(loc, "no property `%s` for type `%s`, perhaps `import %.*s;` is needed?", ident.toChars(), mt.toChars(), cast(int)n.length, n.ptr);
+ else
+ {
+ error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true));
+ if (auto dsym = mt.toDsymbol(scope_))
+ if (auto sym = dsym.isAggregateDeclaration())
+ {
+ if (auto fd = search_function(sym, Id.opDispatch))
+ errorSupplemental(loc, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
+ else if (!sym.members)
+ errorSupplemental(sym.loc, "`%s %s` is opaque and has no members.", sym.kind, mt.toPrettyChars(true));
+ }
+ }
+ }
+ e = ErrorExp.get();
+ }
+ return e;
+ }
+
+ Expression visitError(TypeError)
+ {
+ return ErrorExp.get();
+ }
+
+ Expression visitBasic(TypeBasic mt)
+ {
+ Expression integerValue(dinteger_t i)
+ {
+ return new IntegerExp(loc, i, mt);
+ }
+
+ Expression intValue(dinteger_t i)
+ {
+ return new IntegerExp(loc, i, Type.tint32);
+ }
+
+ Expression floatValue(real_t r)
+ {
+ if (mt.isreal() || mt.isimaginary())
+ return new RealExp(loc, r, mt);
+ else
+ {
+ return new ComplexExp(loc, complex_t(r, r), mt);
+ }
+ }
+
+ //printf("TypeBasic::getProperty('%s')\n", ident.toChars());
+ if (ident == Id.max)
+ {
+ switch (mt.ty)
+ {
+ case Tint8: return integerValue(byte.max);
+ case Tuns8: return integerValue(ubyte.max);
+ case Tint16: return integerValue(short.max);
+ case Tuns16: return integerValue(ushort.max);
+ case Tint32: return integerValue(int.max);
+ case Tuns32: return integerValue(uint.max);
+ case Tint64: return integerValue(long.max);
+ case Tuns64: return integerValue(ulong.max);
+ case Tbool: return integerValue(bool.max);
+ case Tchar: return integerValue(char.max);
+ case Twchar: return integerValue(wchar.max);
+ case Tdchar: return integerValue(dchar.max);
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32: return floatValue(target.FloatProperties.max);
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64: return floatValue(target.DoubleProperties.max);
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80: return floatValue(target.RealProperties.max);
+ default: break;
+ }
+ }
+ else if (ident == Id.min)
+ {
+ switch (mt.ty)
+ {
+ case Tint8: return integerValue(byte.min);
+ case Tuns8:
+ case Tuns16:
+ case Tuns32:
+ case Tuns64:
+ case Tbool:
+ case Tchar:
+ case Twchar:
+ case Tdchar: return integerValue(0);
+ case Tint16: return integerValue(short.min);
+ case Tint32: return integerValue(int.min);
+ case Tint64: return integerValue(long.min);
+ default: break;
+ }
+ }
+ else if (ident == Id.min_normal)
+ {
+ switch (mt.ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32: return floatValue(target.FloatProperties.min_normal);
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64: return floatValue(target.DoubleProperties.min_normal);
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80: return floatValue(target.RealProperties.min_normal);
+ default: break;
+ }
+ }
+ else if (ident == Id.nan)
+ {
+ switch (mt.ty)
+ {
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ case Timaginary32:
+ case Timaginary64:
+ case Timaginary80:
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80: return floatValue(target.RealProperties.nan);
+ default: break;
+ }
+ }
+ else if (ident == Id.infinity)
+ {
+ switch (mt.ty)
+ {
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ case Timaginary32:
+ case Timaginary64:
+ case Timaginary80:
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80: return floatValue(target.RealProperties.infinity);
+ default: break;
+ }
+ }
+ else if (ident == Id.dig)
+ {
+ switch (mt.ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32: return intValue(target.FloatProperties.dig);
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64: return intValue(target.DoubleProperties.dig);
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80: return intValue(target.RealProperties.dig);
+ default: break;
+ }
+ }
+ else if (ident == Id.epsilon)
+ {
+ switch (mt.ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32: return floatValue(target.FloatProperties.epsilon);
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64: return floatValue(target.DoubleProperties.epsilon);
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80: return floatValue(target.RealProperties.epsilon);
+ default: break;
+ }
+ }
+ else if (ident == Id.mant_dig)
+ {
+ switch (mt.ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32: return intValue(target.FloatProperties.mant_dig);
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64: return intValue(target.DoubleProperties.mant_dig);
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80: return intValue(target.RealProperties.mant_dig);
+ default: break;
+ }
+ }
+ else if (ident == Id.max_10_exp)
+ {
+ switch (mt.ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32: return intValue(target.FloatProperties.max_10_exp);
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64: return intValue(target.DoubleProperties.max_10_exp);
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80: return intValue(target.RealProperties.max_10_exp);
+ default: break;
+ }
+ }
+ else if (ident == Id.max_exp)
+ {
+ switch (mt.ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32: return intValue(target.FloatProperties.max_exp);
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64: return intValue(target.DoubleProperties.max_exp);
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80: return intValue(target.RealProperties.max_exp);
+ default: break;
+ }
+ }
+ else if (ident == Id.min_10_exp)
+ {
+ switch (mt.ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32: return intValue(target.FloatProperties.min_10_exp);
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64: return intValue(target.DoubleProperties.min_10_exp);
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80: return intValue(target.RealProperties.min_10_exp);
+ default: break;
+ }
+ }
+ else if (ident == Id.min_exp)
+ {
+ switch (mt.ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ case Tfloat32: return intValue(target.FloatProperties.min_exp);
+ case Tcomplex64:
+ case Timaginary64:
+ case Tfloat64: return intValue(target.DoubleProperties.min_exp);
+ case Tcomplex80:
+ case Timaginary80:
+ case Tfloat80: return intValue(target.RealProperties.min_exp);
+ default: break;
+ }
+ }
+ return visitType(mt);
+ }
+
+ Expression visitVector(TypeVector mt)
+ {
+ return visitType(mt);
+ }
+
+ Expression visitEnum(TypeEnum mt)
+ {
+ Expression e;
+ if (ident == Id.max || ident == Id.min)
+ {
+ return mt.sym.getMaxMinValue(loc, ident);
+ }
+ else if (ident == Id._init)
+ {
+ e = mt.defaultInitLiteral(loc);
+ }
+ else if (ident == Id.stringof)
+ {
+ e = new StringExp(loc, mt.toString());
+ Scope sc;
+ e = e.expressionSemantic(&sc);
+ }
+ else if (ident == Id._mangleof)
+ {
+ e = visitType(mt);
+ }
+ else
+ {
+ e = mt.toBasetype().getProperty(scope_, loc, ident, flag);
+ }
+ return e;
+ }
+
+ Expression visitTuple(TypeTuple mt)
+ {
+ Expression e;
+ static if (LOGDOTEXP)
+ {
+ printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", mt.toChars(), ident.toChars());
+ }
+ if (ident == Id.length)
+ {
+ e = new IntegerExp(loc, mt.arguments.dim, Type.tsize_t);
+ }
+ else if (ident == Id._init)
+ {
+ e = mt.defaultInitLiteral(loc);
+ }
+ else if (flag)
+ {
+ e = null;
+ }
+ else
+ {
+ error(loc, "no property `%s` for tuple `%s`", ident.toChars(), mt.toChars());
+ e = ErrorExp.get();
+ }
+ return e;
+ }
+
+ switch (t.ty)
+ {
+ default: return t.isTypeBasic() ?
+ visitBasic(cast(TypeBasic)t) :
+ visitType(t);
+
+ case Terror: return visitError (cast(TypeError)t);
+ case Tvector: return visitVector(cast(TypeVector)t);
+ case Tenum: return visitEnum (cast(TypeEnum)t);
+ case Ttuple: return visitTuple (cast(TypeTuple)t);
+ }
+}
+
+/***************************************
+ * Determine if Expression `exp` should instead be a Type, a Dsymbol, or remain an Expression.
+ * Params:
+ * exp = Expression to look at
+ * t = if exp should be a Type, set t to that Type else null
+ * s = if exp should be a Dsymbol, set s to that Dsymbol else null
+ * e = if exp should remain an Expression, set e to that Expression else null
+ *
+ */
+private void resolveExp(Expression exp, out Type t, out Expression e, out Dsymbol s)
+{
+ if (exp.isTypeExp())
+ t = exp.type;
+ else if (auto ve = exp.isVarExp())
+ {
+ if (auto v = ve.var.isVarDeclaration())
+ e = exp;
+ else
+ s = ve.var;
+ }
+ else if (auto te = exp.isTemplateExp())
+ s = te.td;
+ else if (auto se = exp.isScopeExp())
+ s = se.sds;
+ else if (exp.isFuncExp())
+ s = getDsymbol(exp);
+ else if (auto dte = exp.isDotTemplateExp())
+ s = dte.td;
+ else if (exp.isErrorExp())
+ t = Type.terror;
+ else
+ e = exp;
+}
+
+/************************************
+ * Resolve type 'mt' to either type, symbol, or expression.
+ * If errors happened, resolved to Type.terror.
+ *
+ * Params:
+ * mt = type to be resolved
+ * loc = the location where the type is encountered
+ * sc = the scope of the type
+ * pe = is set if t is an expression
+ * pt = is set if t is a type
+ * ps = is set if t is a symbol
+ * intypeid = true if in type id
+ */
+void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type pt, out Dsymbol ps, bool intypeid = false)
+{
+ void returnExp(Expression e)
+ {
+ pe = e;
+ pt = null;
+ ps = null;
+ }
+
+ void returnType(Type t)
+ {
+ pe = null;
+ pt = t;
+ ps = null;
+ }
+
+ void returnSymbol(Dsymbol s)
+ {
+ pe = null;
+ pt = null;
+ ps = s;
+ }
+
+ void returnError()
+ {
+ returnType(Type.terror);
+ }
+
+ void visitType(Type mt)
+ {
+ //printf("Type::resolve() %s, %d\n", mt.toChars(), mt.ty);
+ Type t = typeSemantic(mt, loc, sc);
+ assert(t);
+ returnType(t);
+ }
+
+ void visitSArray(TypeSArray mt)
+ {
+ //printf("TypeSArray::resolve() %s\n", mt.toChars());
+ mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
+ //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
+ if (pe)
+ {
+ // It's really an index expression
+ if (Dsymbol s = getDsymbol(pe))
+ pe = new DsymbolExp(loc, s);
+ returnExp(new ArrayExp(loc, pe, mt.dim));
+ }
+ else if (ps)
+ {
+ Dsymbol s = ps;
+ if (auto tup = s.isTupleDeclaration())
+ {
+ mt.dim = semanticLength(sc, tup, mt.dim);
+ mt.dim = mt.dim.ctfeInterpret();
+ if (mt.dim.op == TOK.error)
+ return returnError();
+
+ const d = mt.dim.toUInteger();
+ if (d >= tup.objects.dim)
+ {
+ error(loc, "tuple index `%llu` exceeds length %llu", d, cast(ulong) tup.objects.dim);
+ return returnError();
+ }
+
+ RootObject o = (*tup.objects)[cast(size_t)d];
+ if (o.dyncast() == DYNCAST.dsymbol)
+ {
+ return returnSymbol(cast(Dsymbol)o);
+ }
+ if (o.dyncast() == DYNCAST.expression)
+ {
+ Expression e = cast(Expression)o;
+ if (e.op == TOK.dSymbol)
+ return returnSymbol((cast(DsymbolExp)e).s);
+ else
+ return returnExp(e);
+ }
+ if (o.dyncast() == DYNCAST.type)
+ {
+ return returnType((cast(Type)o).addMod(mt.mod));
+ }
+
+ /* Create a new TupleDeclaration which
+ * is a slice [d..d+1] out of the old one.
+ * Do it this way because TemplateInstance::semanticTiargs()
+ * can handle unresolved Objects this way.
+ */
+ auto objects = new Objects(1);
+ (*objects)[0] = o;
+ return returnSymbol(new TupleDeclaration(loc, tup.ident, objects));
+ }
+ else
+ return visitType(mt);
+ }
+ else
+ {
+ if (pt.ty != Terror)
+ mt.next = pt; // prevent re-running semantic() on 'next'
+ visitType(mt);
+ }
+
+ }
+
+ void visitDArray(TypeDArray mt)
+ {
+ //printf("TypeDArray::resolve() %s\n", mt.toChars());
+ mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
+ //printf("s = %p, e = %p, t = %p\n", ps, pe, pt);
+ if (pe)
+ {
+ // It's really a slice expression
+ if (Dsymbol s = getDsymbol(pe))
+ pe = new DsymbolExp(loc, s);
+ returnExp(new ArrayExp(loc, pe));
+ }
+ else if (ps)
+ {
+ if (auto tup = ps.isTupleDeclaration())
+ {
+ // keep ps
+ }
+ else
+ visitType(mt);
+ }
+ else
+ {
+ if (pt.ty != Terror)
+ mt.next = pt; // prevent re-running semantic() on 'next'
+ visitType(mt);
+ }
+ }
+
+ void visitAArray(TypeAArray mt)
+ {
+ //printf("TypeAArray::resolve() %s\n", mt.toChars());
+ // Deal with the case where we thought the index was a type, but
+ // in reality it was an expression.
+ if (mt.index.ty == Tident || mt.index.ty == Tinstance || mt.index.ty == Tsarray)
+ {
+ Expression e;
+ Type t;
+ Dsymbol s;
+ mt.index.resolve(loc, sc, e, t, s, intypeid);
+ if (e)
+ {
+ // It was an expression -
+ // Rewrite as a static array
+ auto tsa = new TypeSArray(mt.next, e);
+ tsa.mod = mt.mod; // just copy mod field so tsa's semantic is not yet done
+ return tsa.resolve(loc, sc, pe, pt, ps, intypeid);
+ }
+ else if (t)
+ mt.index = t;
+ else
+ .error(loc, "index is not a type or an expression");
+ }
+ visitType(mt);
+ }
+
+ /*************************************
+ * Takes an array of Identifiers and figures out if
+ * it represents a Type or an Expression.
+ * Output:
+ * if expression, pe is set
+ * if type, pt is set
+ */
+ void visitIdentifier(TypeIdentifier mt)
+ {
+ //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
+ if ((mt.ident.equals(Id._super) || mt.ident.equals(Id.This)) && !hasThis(sc))
+ {
+ // @@@DEPRECATED_v2.091@@@.
+ // Made an error in 2.086.
+ // Eligible for removal in 2.091.
+ if (mt.ident.equals(Id._super))
+ {
+ error(mt.loc, "Using `super` as a type is obsolete. Use `typeof(super)` instead");
+ }
+ // @@@DEPRECATED_v2.091@@@.
+ // Made an error in 2.086.
+ // Eligible for removal in 2.091.
+ if (mt.ident.equals(Id.This))
+ {
+ error(mt.loc, "Using `this` as a type is obsolete. Use `typeof(this)` instead");
+ }
+ if (AggregateDeclaration ad = sc.getStructClassScope())
+ {
+ if (ClassDeclaration cd = ad.isClassDeclaration())
+ {
+ if (mt.ident.equals(Id.This))
+ mt.ident = cd.ident;
+ else if (cd.baseClass && mt.ident.equals(Id._super))
+ mt.ident = cd.baseClass.ident;
+ }
+ else
+ {
+ StructDeclaration sd = ad.isStructDeclaration();
+ if (sd && mt.ident.equals(Id.This))
+ mt.ident = sd.ident;
+ }
+ }
+ }
+ if (mt.ident == Id.ctfe)
+ {
+ error(loc, "variable `__ctfe` cannot be read at compile time");
+ return returnError();
+ }
+
+ Dsymbol scopesym;
+ Dsymbol s = sc.search(loc, mt.ident, &scopesym);
+ /*
+ * https://issues.dlang.org/show_bug.cgi?id=1170
+ * https://issues.dlang.org/show_bug.cgi?id=10739
+ *
+ * If a symbol is not found, it might be declared in
+ * a mixin-ed string or a mixin-ed template, so before
+ * issuing an error semantically analyze all string/template
+ * mixins that are members of the current ScopeDsymbol.
+ */
+ if (!s && sc.enclosing)
+ {
+ ScopeDsymbol sds = sc.enclosing.scopesym;
+ if (sds && sds.members)
+ {
+ void semanticOnMixin(Dsymbol member)
+ {
+ if (auto compileDecl = member.isCompileDeclaration())
+ compileDecl.dsymbolSemantic(sc);
+ else if (auto mixinTempl = member.isTemplateMixin())
+ mixinTempl.dsymbolSemantic(sc);
+ }
+ sds.members.foreachDsymbol( s => semanticOnMixin(s) );
+ s = sc.search(loc, mt.ident, &scopesym);
+ }
+ }
+
+ if (s)
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=16042
+ // If `f` is really a function template, then replace `f`
+ // with the function template declaration.
+ if (auto f = s.isFuncDeclaration())
+ {
+ if (auto td = getFuncTemplateDecl(f))
+ {
+ // If not at the beginning of the overloaded list of
+ // `TemplateDeclaration`s, then get the beginning
+ if (td.overroot)
+ td = td.overroot;
+ s = td;
+ }
+ }
+ }
+
+ mt.resolveHelper(loc, sc, s, scopesym, pe, pt, ps, intypeid);
+ if (pt)
+ pt = pt.addMod(mt.mod);
+ }
+
+ void visitInstance(TypeInstance mt)
+ {
+ // Note close similarity to TypeIdentifier::resolve()
+
+ //printf("TypeInstance::resolve(sc = %p, tempinst = '%s')\n", sc, mt.tempinst.toChars());
+ mt.tempinst.dsymbolSemantic(sc);
+ if (!global.gag && mt.tempinst.errors)
+ return returnError();
+
+ mt.resolveHelper(loc, sc, mt.tempinst, null, pe, pt, ps, intypeid);
+ if (pt)
+ pt = pt.addMod(mt.mod);
+ //if (pt) printf("pt = %d '%s'\n", pt.ty, pt.toChars());
+ }
+
+ void visitTypeof(TypeTypeof mt)
+ {
+ //printf("TypeTypeof::resolve(this = %p, sc = %p, idents = '%s')\n", mt, sc, mt.toChars());
+ //static int nest; if (++nest == 50) *(char*)0=0;
+ if (sc is null)
+ {
+ error(loc, "Invalid scope.");
+ return returnError();
+ }
+ if (mt.inuse)
+ {
+ mt.inuse = 2;
+ error(loc, "circular `typeof` definition");
+ Lerr:
+ mt.inuse--;
+ return returnError();
+ }
+ mt.inuse++;
+
+ /* Currently we cannot evaluate 'exp' in speculative context, because
+ * the type implementation may leak to the final execution. Consider:
+ *
+ * struct S(T) {
+ * string toString() const { return "x"; }
+ * }
+ * void main() {
+ * alias X = typeof(S!int());
+ * assert(typeid(X).toString() == "x");
+ * }
+ */
+ Scope* sc2 = sc.push();
+
+ if (!mt.exp.isTypeidExp())
+ /* Treat typeof(typeid(exp)) as needing
+ * the full semantic analysis of the typeid.
+ * https://issues.dlang.org/show_bug.cgi?id=20958
+ */
+ sc2.intypeof = 1;
+
+ auto exp2 = mt.exp.expressionSemantic(sc2);
+ exp2 = resolvePropertiesOnly(sc2, exp2);
+ sc2.pop();
+
+ if (exp2.op == TOK.error)
+ {
+ if (!global.gag)
+ mt.exp = exp2;
+ goto Lerr;
+ }
+ mt.exp = exp2;
+
+ if (mt.exp.op == TOK.type ||
+ mt.exp.op == TOK.scope_)
+ {
+ if (mt.exp.checkType())
+ goto Lerr;
+
+ /* Today, 'typeof(func)' returns void if func is a
+ * function template (TemplateExp), or
+ * template lambda (FuncExp).
+ * It's actually used in Phobos as an idiom, to branch code for
+ * template functions.
+ */
+ }
+ if (auto f = mt.exp.op == TOK.variable ? (cast( VarExp)mt.exp).var.isFuncDeclaration()
+ : mt.exp.op == TOK.dotVariable ? (cast(DotVarExp)mt.exp).var.isFuncDeclaration() : null)
+ {
+ // f might be a unittest declaration which is incomplete when compiled
+ // without -unittest. That causes a segfault in checkForwardRef, see
+ // https://issues.dlang.org/show_bug.cgi?id=20626
+ if ((!f.isUnitTestDeclaration() || global.params.useUnitTests) && f.checkForwardRef(loc))
+ goto Lerr;
+ }
+ if (auto f = isFuncAddress(mt.exp))
+ {
+ if (f.checkForwardRef(loc))
+ goto Lerr;
+ }
+
+ Type t = mt.exp.type;
+ if (!t)
+ {
+ error(loc, "expression `%s` has no type", mt.exp.toChars());
+ goto Lerr;
+ }
+ if (t.ty == Ttypeof)
+ {
+ error(loc, "forward reference to `%s`", mt.toChars());
+ goto Lerr;
+ }
+ if (mt.idents.dim == 0)
+ {
+ returnType(t.addMod(mt.mod));
+ }
+ else
+ {
+ if (Dsymbol s = t.toDsymbol(sc))
+ mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
+ else
+ {
+ auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
+ e = e.expressionSemantic(sc);
+ resolveExp(e, pt, pe, ps);
+ }
+ if (pt)
+ pt = pt.addMod(mt.mod);
+ }
+ mt.inuse--;
+ }
+
+ void visitReturn(TypeReturn mt)
+ {
+ //printf("TypeReturn::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
+ Type t;
+ {
+ FuncDeclaration func = sc.func;
+ if (!func)
+ {
+ error(loc, "`typeof(return)` must be inside function");
+ return returnError();
+ }
+ if (func.fes)
+ func = func.fes.func;
+ t = func.type.nextOf();
+ if (!t)
+ {
+ error(loc, "cannot use `typeof(return)` inside function `%s` with inferred return type", sc.func.toChars());
+ return returnError();
+ }
+ }
+ if (mt.idents.dim == 0)
+ {
+ return returnType(t.addMod(mt.mod));
+ }
+ else
+ {
+ if (Dsymbol s = t.toDsymbol(sc))
+ mt.resolveHelper(loc, sc, s, null, pe, pt, ps, intypeid);
+ else
+ {
+ auto e = typeToExpressionHelper(mt, new TypeExp(loc, t));
+ e = e.expressionSemantic(sc);
+ resolveExp(e, pt, pe, ps);
+ }
+ if (pt)
+ pt = pt.addMod(mt.mod);
+ }
+ }
+
+ void visitSlice(TypeSlice mt)
+ {
+ mt.next.resolve(loc, sc, pe, pt, ps, intypeid);
+ if (pe)
+ {
+ // It's really a slice expression
+ if (Dsymbol s = getDsymbol(pe))
+ pe = new DsymbolExp(loc, s);
+ return returnExp(new ArrayExp(loc, pe, new IntervalExp(loc, mt.lwr, mt.upr)));
+ }
+ else if (ps)
+ {
+ Dsymbol s = ps;
+ TupleDeclaration td = s.isTupleDeclaration();
+ if (td)
+ {
+ /* It's a slice of a TupleDeclaration
+ */
+ ScopeDsymbol sym = new ArrayScopeSymbol(sc, td);
+ sym.parent = sc.scopesym;
+ sc = sc.push(sym);
+ sc = sc.startCTFE();
+ mt.lwr = mt.lwr.expressionSemantic(sc);
+ mt.upr = mt.upr.expressionSemantic(sc);
+ sc = sc.endCTFE();
+ sc = sc.pop();
+
+ mt.lwr = mt.lwr.ctfeInterpret();
+ mt.upr = mt.upr.ctfeInterpret();
+ const i1 = mt.lwr.toUInteger();
+ const i2 = mt.upr.toUInteger();
+ if (!(i1 <= i2 && i2 <= td.objects.dim))
+ {
+ error(loc, "slice `[%llu..%llu]` is out of range of [0..%llu]", i1, i2, cast(ulong) td.objects.dim);
+ return returnError();
+ }
+
+ if (i1 == 0 && i2 == td.objects.dim)
+ {
+ return returnSymbol(td);
+ }
+
+ /* Create a new TupleDeclaration which
+ * is a slice [i1..i2] out of the old one.
+ */
+ auto objects = new Objects(cast(size_t)(i2 - i1));
+ for (size_t i = 0; i < objects.dim; i++)
+ {
+ (*objects)[i] = (*td.objects)[cast(size_t)i1 + i];
+ }
+
+ return returnSymbol(new TupleDeclaration(loc, td.ident, objects));
+ }
+ else
+ visitType(mt);
+ }
+ else
+ {
+ if (pt.ty != Terror)
+ mt.next = pt; // prevent re-running semantic() on 'next'
+ visitType(mt);
+ }
+ }
+
+ void visitMixin(TypeMixin mt)
+ {
+ RootObject o = mt.obj;
+
+ // if already resolved just set pe/pt/ps and return.
+ if (o)
+ {
+ pe = o.isExpression();
+ pt = o.isType();
+ ps = o.isDsymbol();
+ return;
+ }
+
+ o = mt.compileTypeMixin(loc, sc);
+ if (auto t = o.isType())
+ {
+ resolve(t, loc, sc, pe, pt, ps, intypeid);
+ if (pt)
+ pt = pt.addMod(mt.mod);
+ }
+ else if (auto e = o.isExpression())
+ {
+ e = e.expressionSemantic(sc);
+ if (auto et = e.isTypeExp())
+ returnType(et.type.addMod(mt.mod));
+ else
+ returnExp(e);
+ }
+ else
+ returnError();
+
+ // save the result
+ mt.obj = pe ? pe : (pt ? pt : ps);
+ }
+
+ void visitTraits(TypeTraits tt)
+ {
+ if (Type t = typeSemantic(tt, loc, sc))
+ returnType(t);
+ else if (tt.sym)
+ returnSymbol(tt.sym);
+ else
+ return returnError();
+ }
+
+ switch (mt.ty)
+ {
+ default: visitType (mt); break;
+ case Tsarray: visitSArray (cast(TypeSArray)mt); break;
+ case Tarray: visitDArray (cast(TypeDArray)mt); break;
+ case Taarray: visitAArray (cast(TypeAArray)mt); break;
+ case Tident: visitIdentifier(cast(TypeIdentifier)mt); break;
+ case Tinstance: visitInstance (cast(TypeInstance)mt); break;
+ case Ttypeof: visitTypeof (cast(TypeTypeof)mt); break;
+ case Treturn: visitReturn (cast(TypeReturn)mt); break;
+ case Tslice: visitSlice (cast(TypeSlice)mt); break;
+ case Tmixin: visitMixin (cast(TypeMixin)mt); break;
+ case Ttraits: visitTraits (cast(TypeTraits)mt); break;
+ }
+}
+
+/************************
+ * Access the members of the object e. This type is same as e.type.
+ * Params:
+ * mt = type for which the dot expression is used
+ * sc = instantiating scope
+ * e = expression to convert
+ * ident = identifier being used
+ * flag = DotExpFlag bit flags
+ *
+ * Returns:
+ * resulting expression with e.ident resolved
+ */
+Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
+{
+ Expression visitType(Type mt)
+ {
+ VarDeclaration v = null;
+ static if (LOGDOTEXP)
+ {
+ printf("Type::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
+ }
+ Expression ex = e.lastComma();
+ if (ex.op == TOK.dotVariable)
+ {
+ DotVarExp dv = cast(DotVarExp)ex;
+ v = dv.var.isVarDeclaration();
+ }
+ else if (ex.op == TOK.variable)
+ {
+ VarExp ve = cast(VarExp)ex;
+ v = ve.var.isVarDeclaration();
+ }
+ if (v)
+ {
+ if (ident == Id.offsetof)
+ {
+ v.dsymbolSemantic(null);
+ if (v.isField())
+ {
+ auto ad = v.toParent().isAggregateDeclaration();
+ objc.checkOffsetof(e, ad);
+ ad.size(e.loc);
+ if (ad.sizeok != Sizeok.done)
+ return ErrorExp.get();
+ return new IntegerExp(e.loc, v.offset, Type.tsize_t);
+ }
+ }
+ else if (ident == Id._init)
+ {
+ Type tb = mt.toBasetype();
+ e = mt.defaultInitLiteral(e.loc);
+ if (tb.ty == Tstruct && tb.needsNested())
+ {
+ e.isStructLiteralExp().useStaticInit = true;
+ }
+ goto Lreturn;
+ }
+ }
+ if (ident == Id.stringof)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=3796
+ * this should demangle e.type.deco rather than
+ * pretty-printing the type.
+ */
+ e = new StringExp(e.loc, e.toString());
+ }
+ else
+ e = mt.getProperty(sc, e.loc, ident, flag & DotExpFlag.gag);
+
+ Lreturn:
+ if (e)
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ Expression visitError(TypeError)
+ {
+ return ErrorExp.get();
+ }
+
+ Expression visitBasic(TypeBasic mt)
+ {
+ static if (LOGDOTEXP)
+ {
+ printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
+ }
+ Type t;
+ if (ident == Id.re)
+ {
+ switch (mt.ty)
+ {
+ case Tcomplex32:
+ t = mt.tfloat32;
+ goto L1;
+
+ case Tcomplex64:
+ t = mt.tfloat64;
+ goto L1;
+
+ case Tcomplex80:
+ t = mt.tfloat80;
+ goto L1;
+ L1:
+ e = e.castTo(sc, t);
+ break;
+
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80:
+ break;
+
+ case Timaginary32:
+ t = mt.tfloat32;
+ goto L2;
+
+ case Timaginary64:
+ t = mt.tfloat64;
+ goto L2;
+
+ case Timaginary80:
+ t = mt.tfloat80;
+ goto L2;
+ L2:
+ e = new RealExp(e.loc, CTFloat.zero, t);
+ break;
+
+ default:
+ e = mt.Type.getProperty(sc, e.loc, ident, flag);
+ break;
+ }
+ }
+ else if (ident == Id.im)
+ {
+ Type t2;
+ switch (mt.ty)
+ {
+ case Tcomplex32:
+ t = mt.timaginary32;
+ t2 = mt.tfloat32;
+ goto L3;
+
+ case Tcomplex64:
+ t = mt.timaginary64;
+ t2 = mt.tfloat64;
+ goto L3;
+
+ case Tcomplex80:
+ t = mt.timaginary80;
+ t2 = mt.tfloat80;
+ goto L3;
+ L3:
+ e = e.castTo(sc, t);
+ e.type = t2;
+ break;
+
+ case Timaginary32:
+ t = mt.tfloat32;
+ goto L4;
+
+ case Timaginary64:
+ t = mt.tfloat64;
+ goto L4;
+
+ case Timaginary80:
+ t = mt.tfloat80;
+ goto L4;
+ L4:
+ e = e.copy();
+ e.type = t;
+ break;
+
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80:
+ e = new RealExp(e.loc, CTFloat.zero, mt);
+ break;
+
+ default:
+ e = mt.Type.getProperty(sc, e.loc, ident, flag);
+ break;
+ }
+ }
+ else
+ {
+ return visitType(mt);
+ }
+ if (!(flag & 1) || e)
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ Expression visitVector(TypeVector mt)
+ {
+ static if (LOGDOTEXP)
+ {
+ printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
+ }
+ if (ident == Id.ptr && e.op == TOK.call)
+ {
+ /* The trouble with TOK.call is the return ABI for float[4] is different from
+ * __vector(float[4]), and a type paint won't do.
+ */
+ e = new AddrExp(e.loc, e);
+ e = e.expressionSemantic(sc);
+ return e.castTo(sc, mt.basetype.nextOf().pointerTo());
+ }
+ if (ident == Id.array)
+ {
+ //e = e.castTo(sc, basetype);
+ // Keep lvalue-ness
+ e = new VectorArrayExp(e.loc, e);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ if (ident == Id._init || ident == Id.offsetof || ident == Id.stringof || ident == Id.__xalignof)
+ {
+ // init should return a new VectorExp
+ // https://issues.dlang.org/show_bug.cgi?id=12776
+ // offsetof does not work on a cast expression, so use e directly
+ // stringof should not add a cast to the output
+ return visitType(mt);
+ }
+
+ // Properties based on the vector element type and are values of the element type
+ if (ident == Id.max || ident == Id.min || ident == Id.min_normal ||
+ ident == Id.nan || ident == Id.infinity || ident == Id.epsilon)
+ {
+ auto vet = mt.basetype.isTypeSArray().next; // vector element type
+ if (auto ev = getProperty(vet, sc, e.loc, ident, DotExpFlag.gag))
+ return ev.castTo(sc, mt); // 'broadcast' ev to the vector elements
+ }
+
+ return mt.basetype.dotExp(sc, e.castTo(sc, mt.basetype), ident, flag);
+ }
+
+ Expression visitArray(TypeArray mt)
+ {
+ static if (LOGDOTEXP)
+ {
+ printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
+ }
+
+ e = visitType(mt);
+
+ if (!(flag & 1) || e)
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ Expression visitSArray(TypeSArray mt)
+ {
+ static if (LOGDOTEXP)
+ {
+ printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
+ }
+ if (ident == Id.length)
+ {
+ Loc oldLoc = e.loc;
+ e = mt.dim.copy();
+ e.loc = oldLoc;
+ }
+ else if (ident == Id.ptr)
+ {
+ if (e.op == TOK.type)
+ {
+ e.error("`%s` is not an expression", e.toChars());
+ return ErrorExp.get();
+ }
+ else if (checkUnsafeDotExp(sc, e, ident, flag))
+ {
+ return ErrorExp.get();
+ }
+ e = e.castTo(sc, e.type.nextOf().pointerTo());
+ }
+ else
+ {
+ e = visitArray(mt);
+ }
+ if (!(flag & 1) || e)
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ Expression visitDArray(TypeDArray mt)
+ {
+ static if (LOGDOTEXP)
+ {
+ printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
+ }
+ if (e.op == TOK.type && (ident == Id.length || ident == Id.ptr))
+ {
+ e.error("`%s` is not an expression", e.toChars());
+ return ErrorExp.get();
+ }
+ if (ident == Id.length)
+ {
+ if (e.op == TOK.string_)
+ {
+ StringExp se = cast(StringExp)e;
+ return new IntegerExp(se.loc, se.len, Type.tsize_t);
+ }
+ if (e.op == TOK.null_)
+ {
+ return new IntegerExp(e.loc, 0, Type.tsize_t);
+ }
+ if (checkNonAssignmentArrayOp(e))
+ {
+ return ErrorExp.get();
+ }
+ e = new ArrayLengthExp(e.loc, e);
+ e.type = Type.tsize_t;
+ return e;
+ }
+ else if (ident == Id.ptr)
+ {
+ if (checkUnsafeDotExp(sc, e, ident, flag))
+ return ErrorExp.get();
+ return e.castTo(sc, mt.next.pointerTo());
+ }
+ else
+ {
+ return visitArray(mt);
+ }
+ }
+
+ Expression visitAArray(TypeAArray mt)
+ {
+ static if (LOGDOTEXP)
+ {
+ printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
+ }
+ if (ident == Id.length)
+ {
+ __gshared FuncDeclaration fd_aaLen = null;
+ if (fd_aaLen is null)
+ {
+ auto fparams = new Parameters();
+ fparams.push(new Parameter(STC.const_ | STC.scope_, mt, null, null, null));
+ fd_aaLen = FuncDeclaration.genCfunc(fparams, Type.tsize_t, Id.aaLen);
+ TypeFunction tf = fd_aaLen.type.toTypeFunction();
+ tf.purity = PURE.const_;
+ tf.isnothrow = true;
+ tf.isnogc = false;
+ }
+ Expression ev = new VarExp(e.loc, fd_aaLen, false);
+ e = new CallExp(e.loc, ev, e);
+ e.type = fd_aaLen.type.toTypeFunction().next;
+ return e;
+ }
+ else
+ {
+ return visitType(mt);
+ }
+ }
+
+ Expression visitReference(TypeReference mt)
+ {
+ static if (LOGDOTEXP)
+ {
+ printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
+ }
+ // References just forward things along
+ return mt.next.dotExp(sc, e, ident, flag);
+ }
+
+ Expression visitDelegate(TypeDelegate mt)
+ {
+ static if (LOGDOTEXP)
+ {
+ printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
+ }
+ if (ident == Id.ptr)
+ {
+ e = new DelegatePtrExp(e.loc, e);
+ e = e.expressionSemantic(sc);
+ }
+ else if (ident == Id.funcptr)
+ {
+ if (checkUnsafeDotExp(sc, e, ident, flag))
+ {
+ return ErrorExp.get();
+ }
+ e = new DelegateFuncptrExp(e.loc, e);
+ e = e.expressionSemantic(sc);
+ }
+ else
+ {
+ return visitType(mt);
+ }
+ return e;
+ }
+
+ /***************************************
+ * Figures out what to do with an undefined member reference
+ * for classes and structs.
+ *
+ * If flag & 1, don't report "not a property" error and just return NULL.
+ */
+ Expression noMember(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
+ {
+ //printf("Type.noMember(e: %s ident: %s flag: %d)\n", e.toChars(), ident.toChars(), flag);
+
+ bool gagError = flag & 1;
+
+ __gshared int nest; // https://issues.dlang.org/show_bug.cgi?id=17380
+
+ static Expression returnExp(Expression e)
+ {
+ --nest;
+ return e;
+ }
+
+ if (++nest > global.recursionLimit)
+ {
+ .error(e.loc, "cannot resolve identifier `%s`", ident.toChars());
+ return returnExp(gagError ? null : ErrorExp.get());
+ }
+
+
+ assert(mt.ty == Tstruct || mt.ty == Tclass);
+ auto sym = mt.toDsymbol(sc).isAggregateDeclaration();
+ assert(sym);
+ if (// https://issues.dlang.org/show_bug.cgi?id=22054
+ // if a class or struct does not have a body
+ // there is no point in searching for its members
+ sym.members &&
+ ident != Id.__sizeof &&
+ ident != Id.__xalignof &&
+ ident != Id._init &&
+ ident != Id._mangleof &&
+ ident != Id.stringof &&
+ ident != Id.offsetof &&
+ // https://issues.dlang.org/show_bug.cgi?id=15045
+ // Don't forward special built-in member functions.
+ ident != Id.ctor &&
+ ident != Id.dtor &&
+ ident != Id.__xdtor &&
+ ident != Id.postblit &&
+ ident != Id.__xpostblit)
+ {
+ /* Look for overloaded opDot() to see if we should forward request
+ * to it.
+ */
+ if (auto fd = search_function(sym, Id.opDot))
+ {
+ /* Rewrite e.ident as:
+ * e.opDot().ident
+ */
+ e = build_overload(e.loc, sc, e, null, fd);
+ // @@@DEPRECATED_2.087@@@.
+ e.deprecation("`opDot` is deprecated. Use `alias this`");
+ e = new DotIdExp(e.loc, e, ident);
+ return returnExp(e.expressionSemantic(sc));
+ }
+
+ /* Look for overloaded opDispatch to see if we should forward request
+ * to it.
+ */
+ if (auto fd = search_function(sym, Id.opDispatch))
+ {
+ /* Rewrite e.ident as:
+ * e.opDispatch!("ident")
+ */
+ TemplateDeclaration td = fd.isTemplateDeclaration();
+ if (!td)
+ {
+ fd.error("must be a template `opDispatch(string s)`, not a %s", fd.kind());
+ return returnExp(ErrorExp.get());
+ }
+ auto se = new StringExp(e.loc, ident.toString());
+ auto tiargs = new Objects();
+ tiargs.push(se);
+ auto dti = new DotTemplateInstanceExp(e.loc, e, Id.opDispatch, tiargs);
+ dti.ti.tempdecl = td;
+ /* opDispatch, which doesn't need IFTI, may occur instantiate error.
+ * e.g.
+ * template opDispatch(name) if (isValid!name) { ... }
+ */
+ uint errors = gagError ? global.startGagging() : 0;
+ e = dti.semanticY(sc, 0);
+ if (gagError && global.endGagging(errors))
+ e = null;
+ return returnExp(e);
+ }
+
+ /* See if we should forward to the alias this.
+ */
+ auto alias_e = resolveAliasThis(sc, e, gagError);
+ if (alias_e && alias_e != e)
+ {
+ /* Rewrite e.ident as:
+ * e.aliasthis.ident
+ */
+ auto die = new DotIdExp(e.loc, alias_e, ident);
+
+ auto errors = gagError ? 0 : global.startGagging();
+ auto exp = die.semanticY(sc, gagError);
+ if (!gagError)
+ {
+ global.endGagging(errors);
+ if (exp && exp.op == TOK.error)
+ exp = null;
+ }
+
+ if (exp && gagError)
+ // now that we know that the alias this leads somewhere useful,
+ // go back and print deprecations/warnings that we skipped earlier due to the gag
+ resolveAliasThis(sc, e, false);
+
+ return returnExp(exp);
+ }
+ }
+ return returnExp(visitType(mt));
+ }
+
+ Expression visitStruct(TypeStruct mt)
+ {
+ Dsymbol s;
+ static if (LOGDOTEXP)
+ {
+ printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
+ }
+ assert(e.op != TOK.dot);
+
+ // https://issues.dlang.org/show_bug.cgi?id=14010
+ if (ident == Id._mangleof)
+ {
+ return mt.getProperty(sc, e.loc, ident, flag & 1);
+ }
+
+ /* If e.tupleof
+ */
+ if (ident == Id._tupleof)
+ {
+ /* Create a TupleExp out of the fields of the struct e:
+ * (e.field0, e.field1, e.field2, ...)
+ */
+ e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
+
+ if (!mt.sym.determineFields())
+ {
+ error(e.loc, "unable to determine fields of `%s` because of forward references", mt.toChars());
+ }
+
+ Expression e0;
+ Expression ev = e.op == TOK.type ? null : e;
+ if (ev)
+ ev = extractSideEffect(sc, "__tup", e0, ev);
+
+ auto exps = new Expressions();
+ exps.reserve(mt.sym.fields.dim);
+ for (size_t i = 0; i < mt.sym.fields.dim; i++)
+ {
+ VarDeclaration v = mt.sym.fields[i];
+ Expression ex;
+ if (ev)
+ ex = new DotVarExp(e.loc, ev, v);
+ else
+ {
+ ex = new VarExp(e.loc, v);
+ ex.type = ex.type.addMod(e.type.mod);
+ }
+ exps.push(ex);
+ }
+
+ e = new TupleExp(e.loc, e0, exps);
+ Scope* sc2 = sc.push();
+ sc2.flags |= global.params.useDIP1000 == FeatureState.enabled ? SCOPE.onlysafeaccess : SCOPE.noaccesscheck;
+ e = e.expressionSemantic(sc2);
+ sc2.pop();
+ return e;
+ }
+
+ immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
+ s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
+ L1:
+ if (!s)
+ {
+ return noMember(mt, sc, e, ident, flag);
+ }
+ if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
+ {
+ return noMember(mt, sc, e, ident, flag);
+ }
+ s = s.toAlias();
+
+ if (auto em = s.isEnumMember())
+ {
+ return em.getVarExp(e.loc, sc);
+ }
+ if (auto v = s.isVarDeclaration())
+ {
+ v.checkDeprecated(e.loc, sc);
+ v.checkDisabled(e.loc, sc);
+ if (!v.type ||
+ !v.type.deco && v.inuse)
+ {
+ if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
+ e.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
+ else
+ e.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
+ return ErrorExp.get();
+ }
+ if (v.type.ty == Terror)
+ {
+ return ErrorExp.get();
+ }
+
+ if ((v.storage_class & STC.manifest) && v._init)
+ {
+ if (v.inuse)
+ {
+ e.error("circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
+ return ErrorExp.get();
+ }
+ checkAccess(e.loc, sc, null, v);
+ Expression ve = new VarExp(e.loc, v);
+ if (!isTrivialExp(e))
+ {
+ ve = new CommaExp(e.loc, e, ve);
+ }
+ return ve.expressionSemantic(sc);
+ }
+ }
+
+ if (auto t = s.getType())
+ {
+ return (new TypeExp(e.loc, t)).expressionSemantic(sc);
+ }
+
+ TemplateMixin tm = s.isTemplateMixin();
+ if (tm)
+ {
+ return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
+ }
+
+ TemplateDeclaration td = s.isTemplateDeclaration();
+ if (td)
+ {
+ if (e.op == TOK.type)
+ e = new TemplateExp(e.loc, td);
+ else
+ e = new DotTemplateExp(e.loc, e, td);
+ return e.expressionSemantic(sc);
+ }
+
+ TemplateInstance ti = s.isTemplateInstance();
+ if (ti)
+ {
+ if (!ti.semanticRun)
+ {
+ ti.dsymbolSemantic(sc);
+ if (!ti.inst || ti.errors) // if template failed to expand
+ {
+ return ErrorExp.get();
+ }
+ }
+ s = ti.inst.toAlias();
+ if (!s.isTemplateInstance())
+ goto L1;
+ if (e.op == TOK.type)
+ e = new ScopeExp(e.loc, ti);
+ else
+ e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
+ return e.expressionSemantic(sc);
+ }
+
+ if (s.isImport() || s.isModule() || s.isPackage())
+ {
+ return symbolToExp(s, e.loc, sc, false);
+ }
+
+ OverloadSet o = s.isOverloadSet();
+ if (o)
+ {
+ auto oe = new OverExp(e.loc, o);
+ if (e.op == TOK.type)
+ {
+ return oe;
+ }
+ return new DotExp(e.loc, e, oe);
+ }
+
+ Declaration d = s.isDeclaration();
+ if (!d)
+ {
+ e.error("`%s.%s` is not a declaration", e.toChars(), ident.toChars());
+ return ErrorExp.get();
+ }
+
+ if (e.op == TOK.type)
+ {
+ /* It's:
+ * Struct.d
+ */
+ if (TupleDeclaration tup = d.isTupleDeclaration())
+ {
+ e = new TupleExp(e.loc, tup);
+ return e.expressionSemantic(sc);
+ }
+ if (d.needThis() && sc.intypeof != 1)
+ {
+ /* Rewrite as:
+ * this.d
+ */
+ if (hasThis(sc))
+ {
+ e = new DotVarExp(e.loc, new ThisExp(e.loc), d);
+ return e.expressionSemantic(sc);
+ }
+ }
+ if (d.semanticRun == PASS.init)
+ d.dsymbolSemantic(null);
+ checkAccess(e.loc, sc, e, d);
+ auto ve = new VarExp(e.loc, d);
+ if (d.isVarDeclaration() && d.needThis())
+ ve.type = d.type.addMod(e.type.mod);
+ return ve;
+ }
+
+ bool unreal = e.op == TOK.variable && (cast(VarExp)e).var.isField();
+ if (d.isDataseg() || unreal && d.isField())
+ {
+ // (e, d)
+ checkAccess(e.loc, sc, e, d);
+ Expression ve = new VarExp(e.loc, d);
+ e = unreal ? ve : new CommaExp(e.loc, e, ve);
+ return e.expressionSemantic(sc);
+ }
+
+ e = new DotVarExp(e.loc, e, d);
+ return e.expressionSemantic(sc);
+ }
+
+ Expression visitEnum(TypeEnum mt)
+ {
+ static if (LOGDOTEXP)
+ {
+ printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e.toChars(), ident.toChars(), mt.toChars());
+ }
+ // https://issues.dlang.org/show_bug.cgi?id=14010
+ if (ident == Id._mangleof)
+ {
+ return mt.getProperty(sc, e.loc, ident, flag & 1);
+ }
+
+ if (mt.sym.semanticRun < PASS.semanticdone)
+ mt.sym.dsymbolSemantic(null);
+
+ Dsymbol s = mt.sym.search(e.loc, ident);
+ if (!s)
+ {
+ if (ident == Id.max || ident == Id.min || ident == Id._init)
+ {
+ return mt.getProperty(sc, e.loc, ident, flag & 1);
+ }
+
+ Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, 1);
+ if (!(flag & 1) && !res)
+ {
+ if (auto ns = mt.sym.search_correct(ident))
+ e.error("no property `%s` for type `%s`. Did you mean `%s.%s` ?", ident.toChars(), mt.toChars(), mt.toChars(),
+ ns.toChars());
+ else
+ e.error("no property `%s` for type `%s`", ident.toChars(),
+ mt.toChars());
+
+ return ErrorExp.get();
+ }
+ return res;
+ }
+ EnumMember m = s.isEnumMember();
+ return m.getVarExp(e.loc, sc);
+ }
+
+ Expression visitClass(TypeClass mt)
+ {
+ Dsymbol s;
+ static if (LOGDOTEXP)
+ {
+ printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
+ }
+ assert(e.op != TOK.dot);
+
+ // https://issues.dlang.org/show_bug.cgi?id=12543
+ if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
+ {
+ return mt.Type.getProperty(sc, e.loc, ident, 0);
+ }
+
+ /* If e.tupleof
+ */
+ if (ident == Id._tupleof)
+ {
+ objc.checkTupleof(e, mt);
+
+ /* Create a TupleExp
+ */
+ e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
+
+ mt.sym.size(e.loc); // do semantic of type
+
+ Expression e0;
+ Expression ev = e.op == TOK.type ? null : e;
+ if (ev)
+ ev = extractSideEffect(sc, "__tup", e0, ev);
+
+ auto exps = new Expressions();
+ exps.reserve(mt.sym.fields.dim);
+ for (size_t i = 0; i < mt.sym.fields.dim; i++)
+ {
+ VarDeclaration v = mt.sym.fields[i];
+ // Don't include hidden 'this' pointer
+ if (v.isThisDeclaration())
+ continue;
+ Expression ex;
+ if (ev)
+ ex = new DotVarExp(e.loc, ev, v);
+ else
+ {
+ ex = new VarExp(e.loc, v);
+ ex.type = ex.type.addMod(e.type.mod);
+ }
+ exps.push(ex);
+ }
+
+ e = new TupleExp(e.loc, e0, exps);
+ Scope* sc2 = sc.push();
+ sc2.flags |= global.params.useDIP1000 == FeatureState.enabled ? SCOPE.onlysafeaccess : SCOPE.noaccesscheck;
+ e = e.expressionSemantic(sc2);
+ sc2.pop();
+ return e;
+ }
+
+ int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
+ s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
+
+ L1:
+ if (!s)
+ {
+ // See if it's a 'this' class or a base class
+ if (mt.sym.ident == ident)
+ {
+ if (e.op == TOK.type)
+ {
+ return mt.Type.getProperty(sc, e.loc, ident, 0);
+ }
+ e = new DotTypeExp(e.loc, e, mt.sym);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ if (auto cbase = mt.sym.searchBase(ident))
+ {
+ if (e.op == TOK.type)
+ {
+ return mt.Type.getProperty(sc, e.loc, ident, 0);
+ }
+ if (auto ifbase = cbase.isInterfaceDeclaration())
+ e = new CastExp(e.loc, e, ifbase.type);
+ else
+ e = new DotTypeExp(e.loc, e, cbase);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ if (ident == Id.classinfo)
+ {
+ if (!Type.typeinfoclass)
+ {
+ error(e.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
+ return ErrorExp.get();
+ }
+
+ Type t = Type.typeinfoclass.type;
+ if (e.op == TOK.type || e.op == TOK.dotType)
+ {
+ /* For type.classinfo, we know the classinfo
+ * at compile time.
+ */
+ if (!mt.sym.vclassinfo)
+ mt.sym.vclassinfo = new TypeInfoClassDeclaration(mt.sym.type);
+ e = new VarExp(e.loc, mt.sym.vclassinfo);
+ e = e.addressOf();
+ e.type = t; // do this so we don't get redundant dereference
+ }
+ else
+ {
+ /* For class objects, the classinfo reference is the first
+ * entry in the vtbl[]
+ */
+ e = new PtrExp(e.loc, e);
+ e.type = t.pointerTo();
+ if (mt.sym.isInterfaceDeclaration())
+ {
+ if (mt.sym.isCPPinterface())
+ {
+ /* C++ interface vtbl[]s are different in that the
+ * first entry is always pointer to the first virtual
+ * function, not classinfo.
+ * We can't get a .classinfo for it.
+ */
+ error(e.loc, "no `.classinfo` for C++ interface objects");
+ }
+ /* For an interface, the first entry in the vtbl[]
+ * is actually a pointer to an instance of struct Interface.
+ * The first member of Interface is the .classinfo,
+ * so add an extra pointer indirection.
+ */
+ e.type = e.type.pointerTo();
+ e = new PtrExp(e.loc, e);
+ e.type = t.pointerTo();
+ }
+ e = new PtrExp(e.loc, e, t);
+ }
+ return e;
+ }
+
+ if (ident == Id.__vptr)
+ {
+ /* The pointer to the vtbl[]
+ * *cast(immutable(void*)**)e
+ */
+ e = e.castTo(sc, mt.tvoidptr.immutableOf().pointerTo().pointerTo());
+ e = new PtrExp(e.loc, e);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ if (ident == Id.__monitor && mt.sym.hasMonitor())
+ {
+ /* The handle to the monitor (call it a void*)
+ * *(cast(void**)e + 1)
+ */
+ e = e.castTo(sc, mt.tvoidptr.pointerTo());
+ e = new AddExp(e.loc, e, IntegerExp.literal!1);
+ e = new PtrExp(e.loc, e);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ if (ident == Id.outer && mt.sym.vthis)
+ {
+ if (mt.sym.vthis.semanticRun == PASS.init)
+ mt.sym.vthis.dsymbolSemantic(null);
+
+ if (auto cdp = mt.sym.toParentLocal().isClassDeclaration())
+ {
+ auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
+ dve.type = cdp.type.addMod(e.type.mod);
+ return dve;
+ }
+
+ /* https://issues.dlang.org/show_bug.cgi?id=15839
+ * Find closest parent class through nested functions.
+ */
+ for (auto p = mt.sym.toParentLocal(); p; p = p.toParentLocal())
+ {
+ auto fd = p.isFuncDeclaration();
+ if (!fd)
+ break;
+ auto ad = fd.isThis();
+ if (!ad && fd.isNested())
+ continue;
+ if (!ad)
+ break;
+ if (auto cdp = ad.isClassDeclaration())
+ {
+ auto ve = new ThisExp(e.loc);
+
+ ve.var = fd.vthis;
+ const nestedError = fd.vthis.checkNestedReference(sc, e.loc);
+ assert(!nestedError);
+
+ ve.type = cdp.type.addMod(fd.vthis.type.mod).addMod(e.type.mod);
+ return ve;
+ }
+ break;
+ }
+
+ // Continue to show enclosing function's frame (stack or closure).
+ auto dve = new DotVarExp(e.loc, e, mt.sym.vthis);
+ dve.type = mt.sym.vthis.type.addMod(e.type.mod);
+ return dve;
+ }
+
+ return noMember(mt, sc, e, ident, flag & 1);
+ }
+ if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
+ {
+ return noMember(mt, sc, e, ident, flag);
+ }
+ if (!s.isFuncDeclaration()) // because of overloading
+ {
+ s.checkDeprecated(e.loc, sc);
+ if (auto d = s.isDeclaration())
+ d.checkDisabled(e.loc, sc);
+ }
+ s = s.toAlias();
+
+ if (auto em = s.isEnumMember())
+ {
+ return em.getVarExp(e.loc, sc);
+ }
+ if (auto v = s.isVarDeclaration())
+ {
+ if (!v.type ||
+ !v.type.deco && v.inuse)
+ {
+ if (v.inuse) // https://issues.dlang.org/show_bug.cgi?id=9494
+ e.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
+ else
+ e.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
+ return ErrorExp.get();
+ }
+ if (v.type.ty == Terror)
+ {
+ return ErrorExp.get();
+ }
+
+ if ((v.storage_class & STC.manifest) && v._init)
+ {
+ if (v.inuse)
+ {
+ e.error("circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
+ return ErrorExp.get();
+ }
+ checkAccess(e.loc, sc, null, v);
+ Expression ve = new VarExp(e.loc, v);
+ ve = ve.expressionSemantic(sc);
+ return ve;
+ }
+ }
+
+ if (auto t = s.getType())
+ {
+ return (new TypeExp(e.loc, t)).expressionSemantic(sc);
+ }
+
+ TemplateMixin tm = s.isTemplateMixin();
+ if (tm)
+ {
+ return new DotExp(e.loc, e, new ScopeExp(e.loc, tm)).expressionSemantic(sc);
+ }
+
+ TemplateDeclaration td = s.isTemplateDeclaration();
+
+ Expression toTemplateExp(TemplateDeclaration td)
+ {
+ if (e.op == TOK.type)
+ e = new TemplateExp(e.loc, td);
+ else
+ e = new DotTemplateExp(e.loc, e, td);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ if (td)
+ {
+ return toTemplateExp(td);
+ }
+
+ TemplateInstance ti = s.isTemplateInstance();
+ if (ti)
+ {
+ if (!ti.semanticRun)
+ {
+ ti.dsymbolSemantic(sc);
+ if (!ti.inst || ti.errors) // if template failed to expand
+ {
+ return ErrorExp.get();
+ }
+ }
+ s = ti.inst.toAlias();
+ if (!s.isTemplateInstance())
+ goto L1;
+ if (e.op == TOK.type)
+ e = new ScopeExp(e.loc, ti);
+ else
+ e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
+ return e.expressionSemantic(sc);
+ }
+
+ if (s.isImport() || s.isModule() || s.isPackage())
+ {
+ e = symbolToExp(s, e.loc, sc, false);
+ return e;
+ }
+
+ OverloadSet o = s.isOverloadSet();
+ if (o)
+ {
+ auto oe = new OverExp(e.loc, o);
+ if (e.op == TOK.type)
+ {
+ return oe;
+ }
+ return new DotExp(e.loc, e, oe);
+ }
+
+ Declaration d = s.isDeclaration();
+ if (!d)
+ {
+ e.error("`%s.%s` is not a declaration", e.toChars(), ident.toChars());
+ return ErrorExp.get();
+ }
+
+ if (e.op == TOK.type)
+ {
+ /* It's:
+ * Class.d
+ */
+ if (TupleDeclaration tup = d.isTupleDeclaration())
+ {
+ e = new TupleExp(e.loc, tup);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ if (mt.sym.classKind == ClassKind.objc
+ && d.isFuncDeclaration()
+ && d.isFuncDeclaration().isStatic
+ && d.isFuncDeclaration().objc.selector)
+ {
+ auto classRef = new ObjcClassReferenceExp(e.loc, mt.sym);
+ return new DotVarExp(e.loc, classRef, d).expressionSemantic(sc);
+ }
+ else if (d.needThis() && sc.intypeof != 1)
+ {
+ /* Rewrite as:
+ * this.d
+ */
+ AggregateDeclaration ad = d.isMemberLocal();
+ if (auto f = hasThis(sc))
+ {
+ // This is almost same as getRightThis() in expressionsem.d
+ Expression e1;
+ Type t;
+ /* returns: true to continue, false to return */
+ if (f.isThis2)
+ {
+ if (f.followInstantiationContext(ad))
+ {
+ e1 = new VarExp(e.loc, f.vthis);
+ e1 = new PtrExp(e1.loc, e1);
+ e1 = new IndexExp(e1.loc, e1, IntegerExp.literal!1);
+ auto pd = f.toParent2().isDeclaration();
+ assert(pd);
+ t = pd.type.toBasetype();
+ e1 = getThisSkipNestedFuncs(e1.loc, sc, f.toParent2(), ad, e1, t, d, true);
+ if (!e1)
+ {
+ e = new VarExp(e.loc, d);
+ return e;
+ }
+ goto L2;
+ }
+ }
+ e1 = new ThisExp(e.loc);
+ e1 = e1.expressionSemantic(sc);
+ L2:
+ t = e1.type.toBasetype();
+ ClassDeclaration cd = e.type.isClassHandle();
+ ClassDeclaration tcd = t.isClassHandle();
+ if (cd && tcd && (tcd == cd || cd.isBaseOf(tcd, null)))
+ {
+ e = new DotTypeExp(e1.loc, e1, cd);
+ e = new DotVarExp(e.loc, e, d);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+ if (tcd && tcd.isNested())
+ {
+ /* e1 is the 'this' pointer for an inner class: tcd.
+ * Rewrite it as the 'this' pointer for the outer class.
+ */
+ auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
+ e1 = new DotVarExp(e.loc, e1, vthis);
+ e1.type = vthis.type;
+ e1.type = e1.type.addMod(t.mod);
+ // Do not call ensureStaticLinkTo()
+ //e1 = e1.expressionSemantic(sc);
+
+ // Skip up over nested functions, and get the enclosing
+ // class type.
+ e1 = getThisSkipNestedFuncs(e1.loc, sc, tcd.toParentP(ad), ad, e1, t, d, true);
+ if (!e1)
+ {
+ e = new VarExp(e.loc, d);
+ return e;
+ }
+ goto L2;
+ }
+ }
+ }
+ //printf("e = %s, d = %s\n", e.toChars(), d.toChars());
+ if (d.semanticRun == PASS.init)
+ d.dsymbolSemantic(null);
+
+ // If static function, get the most visible overload.
+ // Later on the call is checked for correctness.
+ // https://issues.dlang.org/show_bug.cgi?id=12511
+ Dsymbol d2 = d;
+ if (auto fd = d.isFuncDeclaration())
+ {
+ import dmd.access : mostVisibleOverload;
+ d2 = mostVisibleOverload(fd, sc._module);
+ }
+
+ checkAccess(e.loc, sc, e, d2);
+ if (d2.isDeclaration())
+ {
+ d = cast(Declaration)d2;
+ auto ve = new VarExp(e.loc, d);
+ if (d.isVarDeclaration() && d.needThis())
+ ve.type = d.type.addMod(e.type.mod);
+ return ve;
+ }
+ else if (d2.isTemplateDeclaration())
+ {
+ return toTemplateExp(cast(TemplateDeclaration)d2);
+ }
+ else
+ assert(0);
+ }
+
+ bool unreal = e.op == TOK.variable && (cast(VarExp)e).var.isField();
+ if (d.isDataseg() || unreal && d.isField())
+ {
+ // (e, d)
+ checkAccess(e.loc, sc, e, d);
+ Expression ve = new VarExp(e.loc, d);
+ e = unreal ? ve : new CommaExp(e.loc, e, ve);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ e = new DotVarExp(e.loc, e, d);
+ e = e.expressionSemantic(sc);
+ return e;
+ }
+
+ switch (mt.ty)
+ {
+ case Tvector: return visitVector (cast(TypeVector)mt);
+ case Tsarray: return visitSArray (cast(TypeSArray)mt);
+ case Tstruct: return visitStruct (cast(TypeStruct)mt);
+ case Tenum: return visitEnum (cast(TypeEnum)mt);
+ case Terror: return visitError (cast(TypeError)mt);
+ case Tarray: return visitDArray (cast(TypeDArray)mt);
+ case Taarray: return visitAArray (cast(TypeAArray)mt);
+ case Treference: return visitReference(cast(TypeReference)mt);
+ case Tdelegate: return visitDelegate (cast(TypeDelegate)mt);
+ case Tclass: return visitClass (cast(TypeClass)mt);
+
+ default: return mt.isTypeBasic()
+ ? visitBasic(cast(TypeBasic)mt)
+ : visitType(mt);
+ }
+}
+
+
+/************************
+ * Get the the default initialization expression for a type.
+ * Params:
+ * mt = the type for which the init expression is returned
+ * loc = the location where the expression needs to be evaluated
+ *
+ * Returns:
+ * The initialization expression for the type.
+ */
+Expression defaultInit(Type mt, const ref Loc loc)
+{
+ Expression visitBasic(TypeBasic mt)
+ {
+ static if (LOGDEFAULTINIT)
+ {
+ printf("TypeBasic::defaultInit() '%s'\n", mt.toChars());
+ }
+ dinteger_t value = 0;
+
+ switch (mt.ty)
+ {
+ case Tchar:
+ value = 0xFF;
+ break;
+
+ case Twchar:
+ case Tdchar:
+ value = 0xFFFF;
+ break;
+
+ case Timaginary32:
+ case Timaginary64:
+ case Timaginary80:
+ case Tfloat32:
+ case Tfloat64:
+ case Tfloat80:
+ return new RealExp(loc, target.RealProperties.nan, mt);
+
+ case Tcomplex32:
+ case Tcomplex64:
+ case Tcomplex80:
+ {
+ // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN).
+ const cvalue = complex_t(target.RealProperties.nan, target.RealProperties.nan);
+ return new ComplexExp(loc, cvalue, mt);
+ }
+
+ case Tvoid:
+ error(loc, "`void` does not have a default initializer");
+ return ErrorExp.get();
+
+ default:
+ break;
+ }
+ return new IntegerExp(loc, value, mt);
+ }
+
+ Expression visitVector(TypeVector mt)
+ {
+ //printf("TypeVector::defaultInit()\n");
+ assert(mt.basetype.ty == Tsarray);
+ Expression e = mt.basetype.defaultInit(loc);
+ auto ve = new VectorExp(loc, e, mt);
+ ve.type = mt;
+ ve.dim = cast(int)(mt.basetype.size(loc) / mt.elementType().size(loc));
+ return ve;
+ }
+
+ Expression visitSArray(TypeSArray mt)
+ {
+ static if (LOGDEFAULTINIT)
+ {
+ printf("TypeSArray::defaultInit() '%s'\n", mt.toChars());
+ }
+ if (mt.next.ty == Tvoid)
+ return mt.tuns8.defaultInit(loc);
+ else
+ return mt.next.defaultInit(loc);
+ }
+
+ Expression visitFunction(TypeFunction mt)
+ {
+ error(loc, "`function` does not have a default initializer");
+ return ErrorExp.get();
+ }
+
+ Expression visitStruct(TypeStruct mt)
+ {
+ static if (LOGDEFAULTINIT)
+ {
+ printf("TypeStruct::defaultInit() '%s'\n", mt.toChars());
+ }
+ Declaration d = new SymbolDeclaration(mt.sym.loc, mt.sym);
+ assert(d);
+ d.type = mt;
+ d.storage_class |= STC.rvalue; // https://issues.dlang.org/show_bug.cgi?id=14398
+ return new VarExp(mt.sym.loc, d);
+ }
+
+ Expression visitEnum(TypeEnum mt)
+ {
+ static if (LOGDEFAULTINIT)
+ {
+ printf("TypeEnum::defaultInit() '%s'\n", mt.toChars());
+ }
+ // Initialize to first member of enum
+ Expression e = mt.sym.getDefaultValue(loc);
+ e = e.copy();
+ e.loc = loc;
+ e.type = mt; // to deal with const, immutable, etc., variants
+ return e;
+ }
+
+ Expression visitTuple(TypeTuple mt)
+ {
+ static if (LOGDEFAULTINIT)
+ {
+ printf("TypeTuple::defaultInit() '%s'\n", mt.toChars());
+ }
+ auto exps = new Expressions(mt.arguments.dim);
+ for (size_t i = 0; i < mt.arguments.dim; i++)
+ {
+ Parameter p = (*mt.arguments)[i];
+ assert(p.type);
+ Expression e = p.type.defaultInitLiteral(loc);
+ if (e.op == TOK.error)
+ {
+ return e;
+ }
+ (*exps)[i] = e;
+ }
+ return new TupleExp(loc, exps);
+ }
+
+ Expression visitNoreturn(TypeNoreturn mt)
+ {
+ static if (LOGDEFAULTINIT)
+ {
+ printf("TypeNoreturn::defaultInit() '%s'\n", mt.toChars());
+ }
+ auto cond = IntegerExp.createBool(false);
+ auto msg = new StringExp(loc, "Accessed expression of type `noreturn`");
+ auto ae = new AssertExp(loc, cond, msg);
+ ae.type = mt;
+ return ae;
+ }
+
+ switch (mt.ty)
+ {
+ case Tvector: return visitVector (cast(TypeVector)mt);
+ case Tsarray: return visitSArray (cast(TypeSArray)mt);
+ case Tfunction: return visitFunction(cast(TypeFunction)mt);
+ case Tstruct: return visitStruct (cast(TypeStruct)mt);
+ case Tenum: return visitEnum (cast(TypeEnum)mt);
+ case Ttuple: return visitTuple (cast(TypeTuple)mt);
+
+ case Tnull: return new NullExp(Loc.initial, Type.tnull);
+
+ case Terror: return ErrorExp.get();
+
+ case Tarray:
+ case Taarray:
+ case Tpointer:
+ case Treference:
+ case Tdelegate:
+ case Tclass: return new NullExp(loc, mt);
+ case Tnoreturn: return visitNoreturn(cast(TypeNoreturn) mt);
+
+ default: return mt.isTypeBasic() ?
+ visitBasic(cast(TypeBasic)mt) :
+ null;
+ }
+}
+
+
+/******************************
+ * Get the value of the .max/.min property of `ed` as an Expression.
+ * Lazily computes the value and caches it in maxval/minval.
+ * Reports any errors.
+ * Params:
+ * ed = the EnumDeclaration being examined
+ * loc = location to use for error messages
+ * id = Id::max or Id::min
+ * Returns:
+ * corresponding value of .max/.min
+ */
+private Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
+{
+ //printf("EnumDeclaration::getMaxValue()\n");
+
+ static Expression pvalToResult(Expression e, const ref Loc loc)
+ {
+ if (e.op != TOK.error)
+ {
+ e = e.copy();
+ e.loc = loc;
+ }
+ return e;
+ }
+
+ Expression* pval = (id == Id.max) ? &ed.maxval : &ed.minval;
+
+ Expression errorReturn()
+ {
+ *pval = ErrorExp.get();
+ return *pval;
+ }
+
+ if (ed.inuse)
+ {
+ ed.error(loc, "recursive definition of `.%s` property", id.toChars());
+ return errorReturn();
+ }
+ if (*pval)
+ return pvalToResult(*pval, loc);
+
+ if (ed._scope)
+ dsymbolSemantic(ed, ed._scope);
+ if (ed.errors)
+ return errorReturn();
+ if (!ed.members)
+ {
+ if (ed.isSpecial())
+ {
+ /* Allow these special enums to not need a member list
+ */
+ return ed.memtype.getProperty(ed._scope, loc, id, 0);
+ }
+
+ ed.error(loc, "is opaque and has no `.%s`", id.toChars());
+ return errorReturn();
+ }
+ if (!(ed.memtype && ed.memtype.isintegral()))
+ {
+ ed.error(loc, "has no `.%s` property because base type `%s` is not an integral type",
+ id.toChars(), ed.memtype ? ed.memtype.toChars() : "");
+ return errorReturn();
+ }
+
+ bool first = true;
+ for (size_t i = 0; i < ed.members.dim; i++)
+ {
+ EnumMember em = (*ed.members)[i].isEnumMember();
+ if (!em)
+ continue;
+ if (em.errors)
+ {
+ ed.errors = true;
+ continue;
+ }
+
+ if (em.semanticRun < PASS.semanticdone)
+ {
+ em.error("is forward referenced looking for `.%s`", id.toChars());
+ ed.errors = true;
+ continue;
+ }
+
+ if (first)
+ {
+ *pval = em.value;
+ first = false;
+ }
+ else
+ {
+ /* In order to work successfully with UDTs,
+ * build expressions to do the comparisons,
+ * and let the semantic analyzer and constant
+ * folder give us the result.
+ */
+
+ /* Compute:
+ * if (e > maxval)
+ * maxval = e;
+ */
+ Expression e = em.value;
+ Expression ec = new CmpExp(id == Id.max ? TOK.greaterThan : TOK.lessThan, em.loc, e, *pval);
+ ed.inuse++;
+ ec = ec.expressionSemantic(em._scope);
+ ed.inuse--;
+ ec = ec.ctfeInterpret();
+ if (ec.op == TOK.error)
+ {
+ ed.errors = true;
+ continue;
+ }
+ if (ec.toInteger())
+ *pval = e;
+ }
+ }
+ return ed.errors ? errorReturn() : pvalToResult(*pval, loc);
+}
diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d
new file mode 100644
index 0000000..d8160f0
--- /dev/null
+++ b/gcc/d/dmd/typinf.d
@@ -0,0 +1,28 @@
+/**
+ * Generate `TypeInfo` objects, which are needed for run-time introspection of classes.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typeinf.d, _typeinf.d)
+ * Documentation: https://dlang.org/phobos/dmd_typinf.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typinf.d
+ */
+
+module dmd.typinf;
+
+import dmd.dscope;
+import dmd.globals;
+import dmd.mtype;
+
+/****************************************************
+ * Gets the type of the `TypeInfo` object associated with `t`
+ * Params:
+ * loc = the location for reporting line nunbers in errors
+ * t = the type to get the type of the `TypeInfo` object for
+ * sc = the scope
+ * Returns:
+ * The type of the `TypeInfo` object associated with `t`
+ */
+extern (C++) Type getTypeInfoType(Loc loc, Type t, Scope* sc);
+
diff --git a/gcc/d/dmd/utf.c b/gcc/d/dmd/utf.c
deleted file mode 100644
index f6b5435..0000000
--- a/gcc/d/dmd/utf.c
+++ /dev/null
@@ -1,306 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 2003-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/D-Programming-Language/dmd/blob/master/src/utf.c
- */
-
-/// Description of UTF-8 in [1]. Unicode non-characters and private-use
-/// code points described in [2],[4].
-///
-/// References:
-/// [1] http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
-/// [2] http://en.wikipedia.org/wiki/Unicode
-/// [3] http://unicode.org/faq/utf_bom.html
-/// [4] http://www.unicode.org/versions/Unicode6.1.0/ch03.pdf
-
-#include "utf.h"
-
-/* The following encodings are valid, except for the 5 and 6 byte
- * combinations:
- * 0xxxxxxx
- * 110xxxxx 10xxxxxx
- * 1110xxxx 10xxxxxx 10xxxxxx
- * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
- * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
- */
-const unsigned UTF8_STRIDE[256] =
-{
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
- 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
- 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF,
-};
-
-// UTF-8 decoding errors
-char const UTF8_DECODE_OUTSIDE_CODE_SPACE[] = "Outside Unicode code space";
-char const UTF8_DECODE_TRUNCATED_SEQUENCE[] = "Truncated UTF-8 sequence";
-char const UTF8_DECODE_OVERLONG[] = "Overlong UTF-8 sequence";
-char const UTF8_DECODE_INVALID_TRAILER[] = "Invalid trailing code unit";
-char const UTF8_DECODE_INVALID_CODE_POINT[] = "Invalid code point decoded";
-
-// UTF-16 decoding errors
-char const UTF16_DECODE_TRUNCATED_SEQUENCE[]= "Truncated UTF-16 sequence";
-char const UTF16_DECODE_INVALID_SURROGATE[] = "Invalid low surrogate";
-char const UTF16_DECODE_UNPAIRED_SURROGATE[]= "Unpaired surrogate";
-char const UTF16_DECODE_INVALID_CODE_POINT[]= "Invalid code point decoded";
-
-/// The Unicode code space is the range of code points [0x000000,0x10FFFF]
-/// except the UTF-16 surrogate pairs in the range [0xD800,0xDFFF]
-/// and non-characters (which end in 0xFFFE or 0xFFFF).
-bool utf_isValidDchar(dchar_t c)
-{
- // TODO: Whether non-char code points should be rejected is pending review
- // largest character code point
- if (c > 0x10FFFF)
- return false;
- // surrogate pairs
- if (0xD800 <= c && c <= 0xDFFF)
- return false;
- // non-characters
- if ((c & 0xFFFFFE) == 0x00FFFE)
- return false;
- return true;
-}
-
-/*******************************
- * Return !=0 if unicode alpha.
- * Use table from C99 Appendix D.
- */
-
-bool isUniAlpha(dchar_t c)
-{
- size_t high = ALPHA_TABLE_LENGTH - 1;
- // Shortcut search if c is out of range
- size_t low
- = (c < ALPHA_TABLE[0][0] || ALPHA_TABLE[high][1] < c) ? high + 1 : 0;
- // Binary search
- while (low <= high)
- {
- size_t mid = (low + high) >> 1;
- if (c < ALPHA_TABLE[mid][0])
- high = mid - 1;
- else if (ALPHA_TABLE[mid][1] < c)
- low = mid + 1;
- else
- {
- assert(ALPHA_TABLE[mid][0] <= c && c <= ALPHA_TABLE[mid][1]);
- return true;
- }
- }
- return false;
-}
-
-/**
- * Returns the code length of c in code units.
- */
-
-int utf_codeLengthChar(dchar_t c)
-{
- if (c <= 0x7F)
- return 1;
- if (c <= 0x7FF)
- return 2;
- if (c <= 0xFFFF)
- return 3;
- if (c <= 0x10FFFF)
- return 4;
- assert(false);
- return 6;
-}
-
-int utf_codeLengthWchar(dchar_t c)
-{
- return c <= 0xFFFF ? 1 : 2;
-}
-
-/**
- * Returns the code length of c in code units for the encoding.
- * sz is the encoding: 1 = utf8, 2 = utf16, 4 = utf32.
- */
-
-int utf_codeLength(int sz, dchar_t c)
-{
- if (sz == 1)
- return utf_codeLengthChar(c);
- if (sz == 2)
- return utf_codeLengthWchar(c);
- assert(sz == 4);
- return 1;
-}
-
-void utf_encodeChar(utf8_t *s, dchar_t c)
-{
- assert(s != NULL);
- assert(utf_isValidDchar(c));
- if (c <= 0x7F)
- {
- s[0] = static_cast<utf8_t>(c);
- }
- else if (c <= 0x07FF)
- {
- s[0] = static_cast<utf8_t>(0xC0 | (c >> 6));
- s[1] = static_cast<utf8_t>(0x80 | (c & 0x3F));
- }
- else if (c <= 0xFFFF)
- {
- s[0] = static_cast<utf8_t>(0xE0 | (c >> 12));
- s[1] = static_cast<utf8_t>(0x80 | ((c >> 6) & 0x3F));
- s[2] = static_cast<utf8_t>(0x80 | (c & 0x3F));
- }
- else if (c <= 0x10FFFF)
- {
- s[0] = static_cast<utf8_t>(0xF0 | (c >> 18));
- s[1] = static_cast<utf8_t>(0x80 | ((c >> 12) & 0x3F));
- s[2] = static_cast<utf8_t>(0x80 | ((c >> 6) & 0x3F));
- s[3] = static_cast<utf8_t>(0x80 | (c & 0x3F));
- }
- else
- assert(0);
-}
-
-void utf_encodeWchar(utf16_t *s, dchar_t c)
-{
- assert(s != NULL);
- assert(utf_isValidDchar(c));
- if (c <= 0xFFFF)
- {
- s[0] = static_cast<utf16_t>(c);
- }
- else
- {
- s[0] = static_cast<utf16_t>((((c - 0x010000) >> 10) & 0x03FF) + 0xD800);
- s[1] = static_cast<utf16_t>(((c - 0x010000) & 0x03FF) + 0xDC00);
- }
-}
-
-void utf_encode(int sz, void *s, dchar_t c)
-{
- if (sz == 1)
- utf_encodeChar((utf8_t *)s, c);
- else if (sz == 2)
- utf_encodeWchar((utf16_t *)s, c);
- else
- {
- assert(sz == 4);
- *((utf32_t *)s) = c;
- }
-}
-
-/********************************************
- * Decode a UTF-8 sequence as a single UTF-32 code point.
- * Returns:
- * NULL success
- * !=NULL error message string
- */
-
-const char *utf_decodeChar(utf8_t const *s, size_t len, size_t *pidx, dchar_t *presult)
-{
- assert(s != NULL);
- assert(pidx != NULL);
- assert(presult != NULL);
- size_t i = (*pidx)++;
- assert(i < len);
- utf8_t u = s[i];
- // Pre-stage results for ASCII and error cases
- *presult = u;
-
- //printf("utf_decodeChar(s = %02x, %02x, %02x len = %d)\n", u, s[1], s[2], len);
-
- // Get expected sequence length
- size_t n = UTF8_STRIDE[u];
- switch (n)
- {
- case 1: // ASCII
- return UTF8_DECODE_OK;
- case 2: case 3: case 4: // multi-byte UTF-8
- break;
- default: // 5- or 6-byte sequence
- return UTF8_DECODE_OUTSIDE_CODE_SPACE;
- }
- if (len < i + n) // source too short
- return UTF8_DECODE_TRUNCATED_SEQUENCE;
-
- // Pick off 7 - n low bits from first code unit
- utf32_t c = u & ((1 << (7 - n)) - 1);
- /* The following combinations are overlong, and illegal:
- * 1100000x (10xxxxxx)
- * 11100000 100xxxxx (10xxxxxx)
- * 11110000 1000xxxx (10xxxxxx 10xxxxxx)
- * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
- * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
- */
- utf8_t u2 = s[++i];
- // overlong combination
- if ((u & 0xFE) == 0xC0 ||
- (u == 0xE0 && (u2 & 0xE0) == 0x80) ||
- (u == 0xF0 && (u2 & 0xF0) == 0x80) ||
- (u == 0xF8 && (u2 & 0xF8) == 0x80) ||
- (u == 0xFC && (u2 & 0xFC) == 0x80))
- return UTF8_DECODE_OVERLONG;
- // Decode remaining bits
- for (n += i - 1; i != n; ++i)
- {
- u = s[i];
- if ((u & 0xC0) != 0x80) // trailing bytes are 10xxxxxx
- return UTF8_DECODE_INVALID_TRAILER;
- c = (c << 6) | (u & 0x3F);
- }
- if (!utf_isValidDchar(c))
- return UTF8_DECODE_INVALID_CODE_POINT;
- *pidx = i;
- *presult = c;
- return UTF8_DECODE_OK;
-}
-
-/********************************************
- * Decode a UTF-16 sequence as a single UTF-32 code point.
- * Returns:
- * NULL success
- * !=NULL error message string
- */
-
-const char *utf_decodeWchar(utf16_t const *s, size_t len, size_t *pidx, dchar_t *presult)
-{
- assert(s != NULL);
- assert(pidx != NULL);
- assert(presult != NULL);
- size_t i = (*pidx)++;
- assert(i < len);
- // Pre-stage results for ASCII and error cases
- utf32_t u = *presult = s[i];
-
- if (u < 0x80) // ASCII
- return UTF16_DECODE_OK;
- if (0xD800 <= u && u <= 0xDBFF) // Surrogate pair
- { if (len <= i + 1)
- return UTF16_DECODE_TRUNCATED_SEQUENCE;
- utf16_t u2 = s[i + 1];
- if (u2 < 0xDC00 || 0xDFFF < u)
- return UTF16_DECODE_INVALID_SURROGATE;
- u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00);
- ++*pidx;
- }
- else if (0xDC00 <= u && u <= 0xDFFF)
- return UTF16_DECODE_UNPAIRED_SURROGATE;
- if (!utf_isValidDchar(u))
- return UTF16_DECODE_INVALID_CODE_POINT;
- *presult = u;
- return UTF16_DECODE_OK;
-}
diff --git a/gcc/d/dmd/utf.d b/gcc/d/dmd/utf.d
new file mode 100644
index 0000000..1125c21
--- /dev/null
+++ b/gcc/d/dmd/utf.d
@@ -0,0 +1,561 @@
+/**
+ * Functions related to UTF encoding.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/utf.d, _utf.d)
+ * Documentation: https://dlang.org/phobos/dmd_utf.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/utf.d
+ */
+
+module dmd.utf;
+
+nothrow pure @nogc:
+
+/// The Unicode code space is the range of code points [0x000000,0x10FFFF]
+/// except the UTF-16 surrogate pairs in the range [0xD800,0xDFFF]
+bool utf_isValidDchar(dchar c)
+{
+ // TODO: Whether non-char code points should be rejected is pending review.
+ // 0xFFFE and 0xFFFF are valid for internal use, like Phobos std.utf.isValidDChar
+ // See also https://issues.dlang.org/show_bug.cgi?id=1357
+ if (c < 0xD800) // Almost all characters in a typical document.
+ return true;
+ if (c > 0xDFFF && c <= 0x10FFFF)
+ return true;
+ return false;
+}
+
+/*******************************
+ * Return !=0 if unicode alpha.
+ * Use table from C99 Appendix D.
+ */
+bool isUniAlpha(dchar c)
+{
+ static immutable wchar[2][] ALPHA_TABLE =
+ [
+ [0x00AA, 0x00AA],
+ [0x00B5, 0x00B5],
+ [0x00B7, 0x00B7],
+ [0x00BA, 0x00BA],
+ [0x00C0, 0x00D6],
+ [0x00D8, 0x00F6],
+ [0x00F8, 0x01F5],
+ [0x01FA, 0x0217],
+ [0x0250, 0x02A8],
+ [0x02B0, 0x02B8],
+ [0x02BB, 0x02BB],
+ [0x02BD, 0x02C1],
+ [0x02D0, 0x02D1],
+ [0x02E0, 0x02E4],
+ [0x037A, 0x037A],
+ [0x0386, 0x0386],
+ [0x0388, 0x038A],
+ [0x038C, 0x038C],
+ [0x038E, 0x03A1],
+ [0x03A3, 0x03CE],
+ [0x03D0, 0x03D6],
+ [0x03DA, 0x03DA],
+ [0x03DC, 0x03DC],
+ [0x03DE, 0x03DE],
+ [0x03E0, 0x03E0],
+ [0x03E2, 0x03F3],
+ [0x0401, 0x040C],
+ [0x040E, 0x044F],
+ [0x0451, 0x045C],
+ [0x045E, 0x0481],
+ [0x0490, 0x04C4],
+ [0x04C7, 0x04C8],
+ [0x04CB, 0x04CC],
+ [0x04D0, 0x04EB],
+ [0x04EE, 0x04F5],
+ [0x04F8, 0x04F9],
+ [0x0531, 0x0556],
+ [0x0559, 0x0559],
+ [0x0561, 0x0587],
+ [0x05B0, 0x05B9],
+ [0x05BB, 0x05BD],
+ [0x05BF, 0x05BF],
+ [0x05C1, 0x05C2],
+ [0x05D0, 0x05EA],
+ [0x05F0, 0x05F2],
+ [0x0621, 0x063A],
+ [0x0640, 0x0652],
+ [0x0660, 0x0669],
+ [0x0670, 0x06B7],
+ [0x06BA, 0x06BE],
+ [0x06C0, 0x06CE],
+ [0x06D0, 0x06DC],
+ [0x06E5, 0x06E8],
+ [0x06EA, 0x06ED],
+ [0x06F0, 0x06F9],
+ [0x0901, 0x0903],
+ [0x0905, 0x0939],
+ [0x093D, 0x094D],
+ [0x0950, 0x0952],
+ [0x0958, 0x0963],
+ [0x0966, 0x096F],
+ [0x0981, 0x0983],
+ [0x0985, 0x098C],
+ [0x098F, 0x0990],
+ [0x0993, 0x09A8],
+ [0x09AA, 0x09B0],
+ [0x09B2, 0x09B2],
+ [0x09B6, 0x09B9],
+ [0x09BE, 0x09C4],
+ [0x09C7, 0x09C8],
+ [0x09CB, 0x09CD],
+ [0x09DC, 0x09DD],
+ [0x09DF, 0x09E3],
+ [0x09E6, 0x09F1],
+ [0x0A02, 0x0A02],
+ [0x0A05, 0x0A0A],
+ [0x0A0F, 0x0A10],
+ [0x0A13, 0x0A28],
+ [0x0A2A, 0x0A30],
+ [0x0A32, 0x0A33],
+ [0x0A35, 0x0A36],
+ [0x0A38, 0x0A39],
+ [0x0A3E, 0x0A42],
+ [0x0A47, 0x0A48],
+ [0x0A4B, 0x0A4D],
+ [0x0A59, 0x0A5C],
+ [0x0A5E, 0x0A5E],
+ [0x0A66, 0x0A6F],
+ [0x0A74, 0x0A74],
+ [0x0A81, 0x0A83],
+ [0x0A85, 0x0A8B],
+ [0x0A8D, 0x0A8D],
+ [0x0A8F, 0x0A91],
+ [0x0A93, 0x0AA8],
+ [0x0AAA, 0x0AB0],
+ [0x0AB2, 0x0AB3],
+ [0x0AB5, 0x0AB9],
+ [0x0ABD, 0x0AC5],
+ [0x0AC7, 0x0AC9],
+ [0x0ACB, 0x0ACD],
+ [0x0AD0, 0x0AD0],
+ [0x0AE0, 0x0AE0],
+ [0x0AE6, 0x0AEF],
+ [0x0B01, 0x0B03],
+ [0x0B05, 0x0B0C],
+ [0x0B0F, 0x0B10],
+ [0x0B13, 0x0B28],
+ [0x0B2A, 0x0B30],
+ [0x0B32, 0x0B33],
+ [0x0B36, 0x0B39],
+ [0x0B3D, 0x0B43],
+ [0x0B47, 0x0B48],
+ [0x0B4B, 0x0B4D],
+ [0x0B5C, 0x0B5D],
+ [0x0B5F, 0x0B61],
+ [0x0B66, 0x0B6F],
+ [0x0B82, 0x0B83],
+ [0x0B85, 0x0B8A],
+ [0x0B8E, 0x0B90],
+ [0x0B92, 0x0B95],
+ [0x0B99, 0x0B9A],
+ [0x0B9C, 0x0B9C],
+ [0x0B9E, 0x0B9F],
+ [0x0BA3, 0x0BA4],
+ [0x0BA8, 0x0BAA],
+ [0x0BAE, 0x0BB5],
+ [0x0BB7, 0x0BB9],
+ [0x0BBE, 0x0BC2],
+ [0x0BC6, 0x0BC8],
+ [0x0BCA, 0x0BCD],
+ [0x0BE7, 0x0BEF],
+ [0x0C01, 0x0C03],
+ [0x0C05, 0x0C0C],
+ [0x0C0E, 0x0C10],
+ [0x0C12, 0x0C28],
+ [0x0C2A, 0x0C33],
+ [0x0C35, 0x0C39],
+ [0x0C3E, 0x0C44],
+ [0x0C46, 0x0C48],
+ [0x0C4A, 0x0C4D],
+ [0x0C60, 0x0C61],
+ [0x0C66, 0x0C6F],
+ [0x0C82, 0x0C83],
+ [0x0C85, 0x0C8C],
+ [0x0C8E, 0x0C90],
+ [0x0C92, 0x0CA8],
+ [0x0CAA, 0x0CB3],
+ [0x0CB5, 0x0CB9],
+ [0x0CBE, 0x0CC4],
+ [0x0CC6, 0x0CC8],
+ [0x0CCA, 0x0CCD],
+ [0x0CDE, 0x0CDE],
+ [0x0CE0, 0x0CE1],
+ [0x0CE6, 0x0CEF],
+ [0x0D02, 0x0D03],
+ [0x0D05, 0x0D0C],
+ [0x0D0E, 0x0D10],
+ [0x0D12, 0x0D28],
+ [0x0D2A, 0x0D39],
+ [0x0D3E, 0x0D43],
+ [0x0D46, 0x0D48],
+ [0x0D4A, 0x0D4D],
+ [0x0D60, 0x0D61],
+ [0x0D66, 0x0D6F],
+ [0x0E01, 0x0E3A],
+ [0x0E40, 0x0E5B],
+ [0x0E81, 0x0E82],
+ [0x0E84, 0x0E84],
+ [0x0E87, 0x0E88],
+ [0x0E8A, 0x0E8A],
+ [0x0E8D, 0x0E8D],
+ [0x0E94, 0x0E97],
+ [0x0E99, 0x0E9F],
+ [0x0EA1, 0x0EA3],
+ [0x0EA5, 0x0EA5],
+ [0x0EA7, 0x0EA7],
+ [0x0EAA, 0x0EAB],
+ [0x0EAD, 0x0EAE],
+ [0x0EB0, 0x0EB9],
+ [0x0EBB, 0x0EBD],
+ [0x0EC0, 0x0EC4],
+ [0x0EC6, 0x0EC6],
+ [0x0EC8, 0x0ECD],
+ [0x0ED0, 0x0ED9],
+ [0x0EDC, 0x0EDD],
+ [0x0F00, 0x0F00],
+ [0x0F18, 0x0F19],
+ [0x0F20, 0x0F33],
+ [0x0F35, 0x0F35],
+ [0x0F37, 0x0F37],
+ [0x0F39, 0x0F39],
+ [0x0F3E, 0x0F47],
+ [0x0F49, 0x0F69],
+ [0x0F71, 0x0F84],
+ [0x0F86, 0x0F8B],
+ [0x0F90, 0x0F95],
+ [0x0F97, 0x0F97],
+ [0x0F99, 0x0FAD],
+ [0x0FB1, 0x0FB7],
+ [0x0FB9, 0x0FB9],
+ [0x10A0, 0x10C5],
+ [0x10D0, 0x10F6],
+ [0x1E00, 0x1E9B],
+ [0x1EA0, 0x1EF9],
+ [0x1F00, 0x1F15],
+ [0x1F18, 0x1F1D],
+ [0x1F20, 0x1F45],
+ [0x1F48, 0x1F4D],
+ [0x1F50, 0x1F57],
+ [0x1F59, 0x1F59],
+ [0x1F5B, 0x1F5B],
+ [0x1F5D, 0x1F5D],
+ [0x1F5F, 0x1F7D],
+ [0x1F80, 0x1FB4],
+ [0x1FB6, 0x1FBC],
+ [0x1FBE, 0x1FBE],
+ [0x1FC2, 0x1FC4],
+ [0x1FC6, 0x1FCC],
+ [0x1FD0, 0x1FD3],
+ [0x1FD6, 0x1FDB],
+ [0x1FE0, 0x1FEC],
+ [0x1FF2, 0x1FF4],
+ [0x1FF6, 0x1FFC],
+ [0x203F, 0x2040],
+ [0x207F, 0x207F],
+ [0x2102, 0x2102],
+ [0x2107, 0x2107],
+ [0x210A, 0x2113],
+ [0x2115, 0x2115],
+ [0x2118, 0x211D],
+ [0x2124, 0x2124],
+ [0x2126, 0x2126],
+ [0x2128, 0x2128],
+ [0x212A, 0x2131],
+ [0x2133, 0x2138],
+ [0x2160, 0x2182],
+ [0x3005, 0x3007],
+ [0x3021, 0x3029],
+ [0x3041, 0x3093],
+ [0x309B, 0x309C],
+ [0x30A1, 0x30F6],
+ [0x30FB, 0x30FC],
+ [0x3105, 0x312C],
+ [0x4E00, 0x9FA5],
+ [0xAC00, 0xD7A3]
+ ];
+
+ size_t high = ALPHA_TABLE.length - 1;
+ // Shortcut search if c is out of range
+ size_t low = (c < ALPHA_TABLE[0][0] || ALPHA_TABLE[high][1] < c) ? high + 1 : 0;
+ // Binary search
+ while (low <= high)
+ {
+ size_t mid = (low + high) >> 1;
+ if (c < ALPHA_TABLE[mid][0])
+ high = mid - 1;
+ else if (ALPHA_TABLE[mid][1] < c)
+ low = mid + 1;
+ else
+ {
+ assert(ALPHA_TABLE[mid][0] <= c && c <= ALPHA_TABLE[mid][1]);
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Returns the code length of c in code units.
+ */
+int utf_codeLengthChar(dchar c)
+{
+ if (c <= 0x7F)
+ return 1;
+ if (c <= 0x7FF)
+ return 2;
+ if (c <= 0xFFFF)
+ return 3;
+ if (c <= 0x10FFFF)
+ return 4;
+ assert(false);
+}
+
+int utf_codeLengthWchar(dchar c)
+{
+ return c <= 0xFFFF ? 1 : 2;
+}
+
+/**
+ * Returns the code length of c in code units for the encoding.
+ * sz is the encoding: 1 = utf8, 2 = utf16, 4 = utf32.
+ */
+int utf_codeLength(int sz, dchar c)
+{
+ if (sz == 1)
+ return utf_codeLengthChar(c);
+ if (sz == 2)
+ return utf_codeLengthWchar(c);
+ assert(sz == 4);
+ return 1;
+}
+
+void utf_encodeChar(char* s, dchar c)
+{
+ assert(s !is null);
+ assert(utf_isValidDchar(c));
+ if (c <= 0x7F)
+ {
+ s[0] = cast(char)c;
+ }
+ else if (c <= 0x07FF)
+ {
+ s[0] = cast(char)(0xC0 | (c >> 6));
+ s[1] = cast(char)(0x80 | (c & 0x3F));
+ }
+ else if (c <= 0xFFFF)
+ {
+ s[0] = cast(char)(0xE0 | (c >> 12));
+ s[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+ s[2] = cast(char)(0x80 | (c & 0x3F));
+ }
+ else if (c <= 0x10FFFF)
+ {
+ s[0] = cast(char)(0xF0 | (c >> 18));
+ s[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
+ s[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+ s[3] = cast(char)(0x80 | (c & 0x3F));
+ }
+ else
+ assert(0);
+}
+
+void utf_encodeWchar(wchar* s, dchar c)
+{
+ assert(s !is null);
+ assert(utf_isValidDchar(c));
+ if (c <= 0xFFFF)
+ {
+ s[0] = cast(wchar)c;
+ }
+ else
+ {
+ s[0] = cast(wchar)((((c - 0x010000) >> 10) & 0x03FF) + 0xD800);
+ s[1] = cast(wchar)(((c - 0x010000) & 0x03FF) + 0xDC00);
+ }
+}
+
+void utf_encode(int sz, void* s, dchar c)
+{
+ if (sz == 1)
+ utf_encodeChar(cast(char*)s, c);
+ else if (sz == 2)
+ utf_encodeWchar(cast(wchar*)s, c);
+ else
+ {
+ assert(sz == 4);
+ *(cast(dchar*)s) = c;
+ }
+}
+
+/********************************************
+ * Decode a UTF-8 sequence as a single UTF-32 code point.
+ * Params:
+ * s = UTF-8 sequence
+ * ridx = starting index in s[], updated to reflect number of code units decoded
+ * rresult = set to character decoded
+ * Returns:
+ * null on success, otherwise error message string
+ */
+string utf_decodeChar(const(char)[] s, ref size_t ridx, out dchar rresult)
+{
+ // UTF-8 decoding errors
+ static immutable string UTF8_DECODE_OK = null; // no error
+ static immutable string UTF8_DECODE_OUTSIDE_CODE_SPACE = "Outside Unicode code space";
+ static immutable string UTF8_DECODE_TRUNCATED_SEQUENCE = "Truncated UTF-8 sequence";
+ static immutable string UTF8_DECODE_OVERLONG = "Overlong UTF-8 sequence";
+ static immutable string UTF8_DECODE_INVALID_TRAILER = "Invalid trailing code unit";
+ static immutable string UTF8_DECODE_INVALID_CODE_POINT = "Invalid code point decoded";
+
+ /* The following encodings are valid, except for the 5 and 6 byte
+ * combinations:
+ * 0xxxxxxx
+ * 110xxxxx 10xxxxxx
+ * 1110xxxx 10xxxxxx 10xxxxxx
+ * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ */
+ static immutable ubyte[256] UTF8_STRIDE =
+ [
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+ 1,1,1,1, 1,1,1,1,
+
+ 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
+ 0xFF,0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF,
+
+ 2,2,2,2, 2,2,2,2,
+ 2,2,2,2, 2,2,2,2,
+ 2,2,2,2, 2,2,2,2,
+ 2,2,2,2, 2,2,2,2,
+
+ 3,3,3,3, 3,3,3,3,
+ 3,3,3,3, 3,3,3,3,
+
+ 4,4,4,4, 4,4,4,4,
+ 5,5,5,5, 6,6,0xFF,0xFF
+ ];
+
+ assert(s !is null);
+ size_t i = ridx++;
+
+ const char u = s[i];
+ // Pre-stage results for ASCII and error cases
+ rresult = u;
+ //printf("utf_decodeChar(s = %02x, %02x, %02x len = %d)\n", u, s[1], s[2], len);
+ // Get expected sequence length
+ const size_t n = UTF8_STRIDE[u];
+ switch (n)
+ {
+ case 1:
+ // ASCII
+ return UTF8_DECODE_OK;
+ case 2:
+ case 3:
+ case 4:
+ // multi-byte UTF-8
+ break;
+ default:
+ // 5- or 6-byte sequence
+ return UTF8_DECODE_OUTSIDE_CODE_SPACE;
+ }
+ if (s.length < i + n) // source too short
+ return UTF8_DECODE_TRUNCATED_SEQUENCE;
+ // Pick off 7 - n low bits from first code unit
+ dchar c = u & ((1 << (7 - n)) - 1);
+ /* The following combinations are overlong, and illegal:
+ * 1100000x (10xxxxxx)
+ * 11100000 100xxxxx (10xxxxxx)
+ * 11110000 1000xxxx (10xxxxxx 10xxxxxx)
+ * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
+ * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+ */
+ const char u2 = s[++i];
+ // overlong combination
+ if ((u & 0xFE) == 0xC0 || (u == 0xE0 && (u2 & 0xE0) == 0x80) || (u == 0xF0 && (u2 & 0xF0) == 0x80) || (u == 0xF8 && (u2 & 0xF8) == 0x80) || (u == 0xFC && (u2 & 0xFC) == 0x80))
+ return UTF8_DECODE_OVERLONG;
+ // Decode remaining bits
+ for (const m = n + i - 1; i != m; ++i)
+ {
+ const u3 = s[i];
+ if ((u3 & 0xC0) != 0x80) // trailing bytes are 10xxxxxx
+ return UTF8_DECODE_INVALID_TRAILER;
+ c = (c << 6) | (u3 & 0x3F);
+ }
+ if (!utf_isValidDchar(c))
+ return UTF8_DECODE_INVALID_CODE_POINT;
+ ridx = i;
+ rresult = c;
+ return UTF8_DECODE_OK;
+}
+
+/********************************************
+ * Decode a UTF-16 sequence as a single UTF-32 code point.
+ * Params:
+ * s = UTF-16 sequence
+ * ridx = starting index in s[], updated to reflect number of code units decoded
+ * rresult = set to character decoded
+ * Returns:
+ * null on success, otherwise error message string
+ */
+string utf_decodeWchar(const(wchar)[] s, ref size_t ridx, out dchar rresult)
+{
+ // UTF-16 decoding errors
+ static immutable string UTF16_DECODE_OK = null; // no error
+ static immutable string UTF16_DECODE_TRUNCATED_SEQUENCE = "Truncated UTF-16 sequence";
+ static immutable string UTF16_DECODE_INVALID_SURROGATE = "Invalid low surrogate";
+ static immutable string UTF16_DECODE_UNPAIRED_SURROGATE = "Unpaired surrogate";
+ static immutable string UTF16_DECODE_INVALID_CODE_POINT = "Invalid code point decoded";
+
+ assert(s !is null);
+ size_t i = ridx++;
+
+ // Pre-stage results for single wchar and error cases
+ dchar u = rresult = s[i];
+ if (u < 0xD800) // Single wchar codepoint
+ return UTF16_DECODE_OK;
+ if (0xD800 <= u && u <= 0xDBFF) // Surrogate pair
+ {
+ if (s.length <= i + 1)
+ return UTF16_DECODE_TRUNCATED_SEQUENCE;
+ wchar u2 = s[i + 1];
+ if (u2 < 0xDC00 || 0xDFFF < u)
+ return UTF16_DECODE_INVALID_SURROGATE;
+ u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00);
+ ++ridx;
+ }
+ else if (0xDC00 <= u && u <= 0xDFFF)
+ return UTF16_DECODE_UNPAIRED_SURROGATE;
+ if (!utf_isValidDchar(u))
+ return UTF16_DECODE_INVALID_CODE_POINT;
+ rresult = u;
+ return UTF16_DECODE_OK;
+}
diff --git a/gcc/d/dmd/utils.c b/gcc/d/dmd/utils.c
deleted file mode 100644
index c9e6322..0000000
--- a/gcc/d/dmd/utils.c
+++ /dev/null
@@ -1,123 +0,0 @@
-
-/* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
- * written by Walter Bright
- * http://www.digitalmars.com
- * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
- */
-
-#include "root/dsystem.h"
-#include "mars.h"
-#include "globals.h"
-#include "root/file.h"
-#include "root/filename.h"
-#include "root/outbuffer.h"
-#include "root/rmem.h"
-
-/**
- * Normalize path by turning forward slashes into backslashes
- *
- * Params:
- * src = Source path, using unix-style ('/') path separators
- *
- * Returns:
- * A newly-allocated string with '/' turned into backslashes
- */
-const char * toWinPath(const char *src)
-{
- if (src == NULL)
- return NULL;
-
- char *result = mem.xstrdup(src);
- char *p = result;
- while (*p != '\0')
- {
- if (*p == '/')
- *p = '\\';
- p++;
- }
- return result;
-}
-
-/**
- * Reads a file, terminate the program on error
- *
- * Params:
- * loc = The line number information from where the call originates
- * f = a `ddmd.root.file.File` handle to read
- */
-void readFile(Loc loc, File *f)
-{
- if (f->read())
- {
- error(loc, "Error reading file '%s'", f->name->toChars());
- fatal();
- }
-}
-
-/**
- * Writes a file, terminate the program on error
- *
- * Params:
- * loc = The line number information from where the call originates
- * f = a `ddmd.root.file.File` handle to write
- */
-void writeFile(Loc loc, File *f)
-{
- if (f->write())
- {
- error(loc, "Error writing file '%s'", f->name->toChars());
- fatal();
- }
-}
-
-/**
- * Ensure the root path (the path minus the name) of the provided path
- * exists, and terminate the process if it doesn't.
- *
- * Params:
- * loc = The line number information from where the call originates
- * name = a path to check (the name is stripped)
- */
-void ensurePathToNameExists(Loc loc, const char *name)
-{
- const char *pt = FileName::path(name);
- if (*pt)
- {
- if (FileName::ensurePathExists(pt))
- {
- error(loc, "cannot create directory %s", pt);
- fatal();
- }
- }
- FileName::free(pt);
-}
-
-/**
- * Takes a path, and escapes '(', ')' and backslashes
- *
- * Params:
- * buf = Buffer to write the escaped path to
- * fname = Path to escape
- */
-void escapePath(OutBuffer *buf, const char *fname)
-{
- while (1)
- {
- switch (*fname)
- {
- case 0:
- return;
- case '(':
- case ')':
- case '\\':
- buf->writeByte('\\');
- /* fall through */
- default:
- buf->writeByte(*fname);
- break;
- }
- fname++;
- }
-}
diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d
new file mode 100644
index 0000000..600521f
--- /dev/null
+++ b/gcc/d/dmd/utils.d
@@ -0,0 +1,298 @@
+/**
+ * This module defines some utility functions for DMD.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/utils.d, _utils.d)
+ * Documentation: https://dlang.org/phobos/dmd_utils.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/utils.d
+ */
+
+module dmd.utils;
+
+import core.stdc.string;
+import dmd.errors;
+import dmd.globals;
+import dmd.root.file;
+import dmd.root.filename;
+import dmd.root.outbuffer;
+import dmd.root.string;
+
+
+/**
+ * Normalize path by turning forward slashes into backslashes
+ *
+ * Params:
+ * src = Source path, using unix-style ('/') path separators
+ *
+ * Returns:
+ * A newly-allocated string with '/' turned into backslashes
+ */
+const(char)* toWinPath(const(char)* src)
+{
+ if (src is null)
+ return null;
+ char* result = strdup(src);
+ char* p = result;
+ while (*p != '\0')
+ {
+ if (*p == '/')
+ *p = '\\';
+ p++;
+ }
+ return result;
+}
+
+
+/**
+ * Reads a file, terminate the program on error
+ *
+ * Params:
+ * loc = The line number information from where the call originates
+ * filename = Path to file
+ */
+FileBuffer readFile(Loc loc, const(char)* filename)
+{
+ return readFile(loc, filename.toDString());
+}
+
+/// Ditto
+FileBuffer readFile(Loc loc, const(char)[] filename)
+{
+ auto result = File.read(filename);
+ if (!result.success)
+ {
+ error(loc, "Error reading file `%.*s`", cast(int)filename.length, filename.ptr);
+ fatal();
+ }
+ return FileBuffer(result.extractSlice());
+}
+
+
+/**
+ * Writes a file, terminate the program on error
+ *
+ * Params:
+ * loc = The line number information from where the call originates
+ * filename = Path to file
+ * data = Full content of the file to be written
+ */
+extern (D) void writeFile(Loc loc, const(char)[] filename, const void[] data)
+{
+ ensurePathToNameExists(Loc.initial, filename);
+ if (!File.update(filename, data))
+ {
+ error(loc, "Error writing file '%*.s'", cast(int) filename.length, filename.ptr);
+ fatal();
+ }
+}
+
+
+/**
+ * Ensure the root path (the path minus the name) of the provided path
+ * exists, and terminate the process if it doesn't.
+ *
+ * Params:
+ * loc = The line number information from where the call originates
+ * name = a path to check (the name is stripped)
+ */
+void ensurePathToNameExists(Loc loc, const(char)[] name)
+{
+ const char[] pt = FileName.path(name);
+ if (pt.length)
+ {
+ if (!FileName.ensurePathExists(pt))
+ {
+ error(loc, "cannot create directory %*.s", cast(int) pt.length, pt.ptr);
+ fatal();
+ }
+ }
+ FileName.free(pt.ptr);
+}
+
+
+/**
+ * Takes a path, and escapes '(', ')' and backslashes
+ *
+ * Params:
+ * buf = Buffer to write the escaped path to
+ * fname = Path to escape
+ */
+void escapePath(OutBuffer* buf, const(char)* fname)
+{
+ while (1)
+ {
+ switch (*fname)
+ {
+ case 0:
+ return;
+ case '(':
+ case ')':
+ case '\\':
+ buf.writeByte('\\');
+ goto default;
+ default:
+ buf.writeByte(*fname);
+ break;
+ }
+ fname++;
+ }
+}
+
+/**
+ * Takes a path, and make it compatible with GNU Makefile format.
+ *
+ * GNU make uses a weird quoting scheme for white space.
+ * A space or tab preceded by 2N+1 backslashes represents N backslashes followed by space;
+ * a space or tab preceded by 2N backslashes represents N backslashes at the end of a file name;
+ * and backslashes in other contexts should not be doubled.
+ *
+ * Params:
+ * buf = Buffer to write the escaped path to
+ * fname = Path to escape
+ */
+void writeEscapedMakePath(ref OutBuffer buf, const(char)* fname)
+{
+ uint slashes;
+
+ while (*fname)
+ {
+ switch (*fname)
+ {
+ case '\\':
+ slashes++;
+ break;
+ case '$':
+ buf.writeByte('$');
+ goto default;
+ case ' ':
+ case '\t':
+ while (slashes--)
+ buf.writeByte('\\');
+ goto case;
+ case '#':
+ buf.writeByte('\\');
+ goto default;
+ case ':':
+ // ':' not escaped on Windows because it can
+ // create problems with absolute paths (e.g. C:\Project)
+ version (Windows) {}
+ else
+ {
+ buf.writeByte('\\');
+ }
+ goto default;
+ default:
+ slashes = 0;
+ break;
+ }
+
+ buf.writeByte(*fname);
+ fname++;
+ }
+}
+
+///
+unittest
+{
+ version (Windows)
+ {
+ enum input = `C:\My Project\file#4$.ext`;
+ enum expected = `C:\My\ Project\file\#4$$.ext`;
+ }
+ else
+ {
+ enum input = `/foo\bar/weird$.:name#\ with spaces.ext`;
+ enum expected = `/foo\bar/weird$$.\:name\#\\\ with\ spaces.ext`;
+ }
+
+ OutBuffer buf;
+ buf.writeEscapedMakePath(input);
+ assert(buf[] == expected);
+}
+
+/**
+ * Convert string to integer.
+ *
+ * Params:
+ * T = Type of integer to parse
+ * val = Variable to store the result in
+ * p = slice to start of string digits
+ * max = max allowable value (inclusive), defaults to `T.max`
+ *
+ * Returns:
+ * `false` on error, `true` on success
+ */
+bool parseDigits(T)(ref T val, const(char)[] p, const T max = T.max)
+ @safe pure @nogc nothrow
+{
+ import core.checkedint : mulu, addu, muls, adds;
+
+ // mul* / add* doesn't support types < int
+ static if (T.sizeof < int.sizeof)
+ {
+ int value;
+ alias add = adds;
+ alias mul = muls;
+ }
+ // unsigned
+ else static if (T.min == 0)
+ {
+ T value;
+ alias add = addu;
+ alias mul = mulu;
+ }
+ else
+ {
+ T value;
+ alias add = adds;
+ alias mul = muls;
+ }
+
+ bool overflow;
+ foreach (char c; p)
+ {
+ if (c > '9' || c < '0')
+ return false;
+ value = mul(value, 10, overflow);
+ value = add(value, uint(c - '0'), overflow);
+ }
+ // If it overflows, value must be > to `max` (since `max` is `T`)
+ val = cast(T) value;
+ return !overflow && value <= max;
+}
+
+///
+@safe pure nothrow @nogc unittest
+{
+ byte b;
+ ubyte ub;
+ short s;
+ ushort us;
+ int i;
+ uint ui;
+ long l;
+ ulong ul;
+
+ assert(b.parseDigits("42") && b == 42);
+ assert(ub.parseDigits("42") && ub == 42);
+
+ assert(s.parseDigits("420") && s == 420);
+ assert(us.parseDigits("42000") && us == 42_000);
+
+ assert(i.parseDigits("420000") && i == 420_000);
+ assert(ui.parseDigits("420000") && ui == 420_000);
+
+ assert(l.parseDigits("42000000000") && l == 42_000_000_000);
+ assert(ul.parseDigits("82000000000") && ul == 82_000_000_000);
+
+ assert(!b.parseDigits(ubyte.max.stringof));
+ assert(!b.parseDigits("WYSIWYG"));
+ assert(!b.parseDigits("-42"));
+ assert(!b.parseDigits("200"));
+ assert(ub.parseDigits("200") && ub == 200);
+ assert(i.parseDigits(int.max.stringof) && i == int.max);
+ assert(i.parseDigits("420", 500) && i == 420);
+ assert(!i.parseDigits("420", 400));
+}
diff --git a/gcc/d/dmd/version.h b/gcc/d/dmd/version.h
index 33811ee..6c5e2f0 100644
--- a/gcc/d/dmd/version.h
+++ b/gcc/d/dmd/version.h
@@ -5,7 +5,7 @@
* http://www.digitalmars.com
* Distributed under the Boost Software License, Version 1.0.
* http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/dlang/dmd/blob/master/src/version.h
+ * https://github.com/dlang/dmd/blob/master/src/dmd/version.h
*/
#pragma once
@@ -17,14 +17,12 @@ class DebugSymbol : public Dsymbol
public:
unsigned level;
- DebugSymbol(Loc loc, Identifier *ident);
- DebugSymbol(Loc loc, unsigned level);
- Dsymbol *syntaxCopy(Dsymbol *);
+ DebugSymbol *syntaxCopy(Dsymbol *);
- const char *toChars();
+ const char *toChars() const;
void addMember(Scope *sc, ScopeDsymbol *sds);
const char *kind() const;
- DebugSymbol *isDebugSymbol() { return this; }
+ DebugSymbol *isDebugSymbol();
void accept(Visitor *v) { v->visit(this); }
};
@@ -33,13 +31,11 @@ class VersionSymbol : public Dsymbol
public:
unsigned level;
- VersionSymbol(Loc loc, Identifier *ident);
- VersionSymbol(Loc loc, unsigned level);
- Dsymbol *syntaxCopy(Dsymbol *);
+ VersionSymbol *syntaxCopy(Dsymbol *);
- const char *toChars();
+ const char *toChars() const;
void addMember(Scope *sc, ScopeDsymbol *sds);
const char *kind() const;
- VersionSymbol *isVersionSymbol() { return this; }
+ VersionSymbol *isVersionSymbol();
void accept(Visitor *v) { v->visit(this); }
};
diff --git a/gcc/d/dmd/visitor.d b/gcc/d/dmd/visitor.d
new file mode 100644
index 0000000..8b9c012
--- /dev/null
+++ b/gcc/d/dmd/visitor.d
@@ -0,0 +1,254 @@
+/**
+ * Provides a visitor class visiting all AST nodes present in the compiler.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/visitor.d, _visitor.d)
+ * Documentation: https://dlang.org/phobos/dmd_visitor.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/visitor.d
+ */
+
+module dmd.visitor;
+
+import dmd.astcodegen;
+import dmd.astenums;
+import dmd.parsetimevisitor;
+import dmd.tokens;
+import dmd.transitivevisitor;
+import dmd.expression;
+import dmd.root.rootobject;
+
+/**
+ * Classic Visitor class which implements visit methods for all the AST
+ * nodes present in the compiler. The visit methods for AST nodes
+ * created at parse time are inherited while the visiting methods
+ * for AST nodes created at semantic time are implemented.
+ */
+extern (C++) class Visitor : ParseTimeVisitor!ASTCodegen
+{
+ alias visit = ParseTimeVisitor!ASTCodegen.visit;
+public:
+ void visit(ASTCodegen.ErrorStatement s) { visit(cast(ASTCodegen.Statement)s); }
+ void visit(ASTCodegen.PeelStatement s) { visit(cast(ASTCodegen.Statement)s); }
+ void visit(ASTCodegen.UnrolledLoopStatement s) { visit(cast(ASTCodegen.Statement)s); }
+ void visit(ASTCodegen.SwitchErrorStatement s) { visit(cast(ASTCodegen.Statement)s); }
+ void visit(ASTCodegen.DebugStatement s) { visit(cast(ASTCodegen.Statement)s); }
+ void visit(ASTCodegen.DtorExpStatement s) { visit(cast(ASTCodegen.ExpStatement)s); }
+ void visit(ASTCodegen.ForwardingStatement s) { visit(cast(ASTCodegen.Statement)s); }
+ void visit(ASTCodegen.OverloadSet s) { visit(cast(ASTCodegen.Dsymbol)s); }
+ void visit(ASTCodegen.LabelDsymbol s) { visit(cast(ASTCodegen.Dsymbol)s); }
+ void visit(ASTCodegen.WithScopeSymbol s) { visit(cast(ASTCodegen.ScopeDsymbol)s); }
+ void visit(ASTCodegen.ArrayScopeSymbol s) { visit(cast(ASTCodegen.ScopeDsymbol)s); }
+ void visit(ASTCodegen.OverDeclaration s) { visit(cast(ASTCodegen.Declaration)s); }
+ void visit(ASTCodegen.SymbolDeclaration s) { visit(cast(ASTCodegen.Declaration)s); }
+ void visit(ASTCodegen.ForwardingAttribDeclaration s) { visit(cast(ASTCodegen.AttribDeclaration)s); }
+ void visit(ASTCodegen.ThisDeclaration s) { visit(cast(ASTCodegen.VarDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoDeclaration s) { visit(cast(ASTCodegen.VarDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoStructDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoClassDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoInterfaceDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoPointerDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoArrayDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoStaticArrayDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoAssociativeArrayDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoEnumDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoFunctionDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoDelegateDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoTupleDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoConstDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoInvariantDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoSharedDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoWildDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.TypeInfoVectorDeclaration s) { visit(cast(ASTCodegen.TypeInfoDeclaration)s); }
+ void visit(ASTCodegen.FuncAliasDeclaration s) { visit(cast(ASTCodegen.FuncDeclaration)s); }
+ void visit(ASTCodegen.ErrorInitializer i) { visit(cast(ASTCodegen.Initializer)i); }
+ void visit(ASTCodegen.ErrorExp e) { visit(cast(ASTCodegen.Expression)e); }
+ void visit(ASTCodegen.ComplexExp e) { visit(cast(ASTCodegen.Expression)e); }
+ void visit(ASTCodegen.StructLiteralExp e) { visit(cast(ASTCodegen.Expression)e); }
+ void visit(ASTCodegen.CompoundLiteralExp e) { visit(cast(ASTCodegen.Expression)e); }
+ void visit(ASTCodegen.ObjcClassReferenceExp e) { visit(cast(ASTCodegen.Expression)e); }
+ void visit(ASTCodegen.SymOffExp e) { visit(cast(ASTCodegen.SymbolExp)e); }
+ void visit(ASTCodegen.OverExp e) { visit(cast(ASTCodegen.Expression)e); }
+ void visit(ASTCodegen.HaltExp e) { visit(cast(ASTCodegen.Expression)e); }
+ void visit(ASTCodegen.DotTemplateExp e) { visit(cast(ASTCodegen.UnaExp)e); }
+ void visit(ASTCodegen.DotVarExp e) { visit(cast(ASTCodegen.UnaExp)e); }
+ void visit(ASTCodegen.DelegateExp e) { visit(cast(ASTCodegen.UnaExp)e); }
+ void visit(ASTCodegen.DotTypeExp e) { visit(cast(ASTCodegen.UnaExp)e); }
+ void visit(ASTCodegen.VectorExp e) { visit(cast(ASTCodegen.UnaExp)e); }
+ void visit(ASTCodegen.VectorArrayExp e) { visit(cast(ASTCodegen.UnaExp)e); }
+ void visit(ASTCodegen.SliceExp e) { visit(cast(ASTCodegen.UnaExp)e); }
+ void visit(ASTCodegen.ArrayLengthExp e) { visit(cast(ASTCodegen.UnaExp)e); }
+ void visit(ASTCodegen.DelegatePtrExp e) { visit(cast(ASTCodegen.UnaExp)e); }
+ void visit(ASTCodegen.DelegateFuncptrExp e) { visit(cast(ASTCodegen.UnaExp)e); }
+ void visit(ASTCodegen.DotExp e) { visit(cast(ASTCodegen.BinExp)e); }
+ void visit(ASTCodegen.IndexExp e) { visit(cast(ASTCodegen.BinExp)e); }
+ void visit(ASTCodegen.ConstructExp e) { visit(cast(ASTCodegen.AssignExp)e); }
+ void visit(ASTCodegen.BlitExp e) { visit(cast(ASTCodegen.AssignExp)e); }
+ void visit(ASTCodegen.RemoveExp e) { visit(cast(ASTCodegen.BinExp)e); }
+ void visit(ASTCodegen.ClassReferenceExp e) { visit(cast(ASTCodegen.Expression)e); }
+ void visit(ASTCodegen.VoidInitExp e) { visit(cast(ASTCodegen.Expression)e); }
+ void visit(ASTCodegen.ThrownExceptionExp e) { visit(cast(ASTCodegen.Expression)e); }
+}
+
+/**
+ * The PermissiveVisitor overrides the root AST nodes with
+ * empty visiting methods.
+ */
+extern (C++) class SemanticTimePermissiveVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+
+ override void visit(ASTCodegen.Dsymbol){}
+ override void visit(ASTCodegen.Parameter){}
+ override void visit(ASTCodegen.Statement){}
+ override void visit(ASTCodegen.Type){}
+ override void visit(ASTCodegen.Expression){}
+ override void visit(ASTCodegen.TemplateParameter){}
+ override void visit(ASTCodegen.Condition){}
+ override void visit(ASTCodegen.Initializer){}
+}
+
+/**
+ * The TransitiveVisitor implements the AST traversal logic for all AST nodes.
+ */
+extern (C++) class SemanticTimeTransitiveVisitor : SemanticTimePermissiveVisitor
+{
+ alias visit = SemanticTimePermissiveVisitor.visit;
+
+ mixin ParseVisitMethods!ASTCodegen __methods;
+ alias visit = __methods.visit;
+
+ override void visit(ASTCodegen.PeelStatement s)
+ {
+ if (s.s)
+ s.s.accept(this);
+ }
+
+ override void visit(ASTCodegen.UnrolledLoopStatement s)
+ {
+ foreach(sx; *s.statements)
+ {
+ if (sx)
+ sx.accept(this);
+ }
+ }
+
+ override void visit(ASTCodegen.DebugStatement s)
+ {
+ if (s.statement)
+ s.statement.accept(this);
+ }
+
+ override void visit(ASTCodegen.ForwardingStatement s)
+ {
+ if (s.statement)
+ s.statement.accept(this);
+ }
+
+ override void visit(ASTCodegen.StructLiteralExp e)
+ {
+ // CTFE can generate struct literals that contain an AddrExp pointing to themselves,
+ // need to avoid infinite recursion.
+ if (!(e.stageflags & stageToCBuffer))
+ {
+ int old = e.stageflags;
+ e.stageflags |= stageToCBuffer;
+ foreach (el; *e.elements)
+ if (el)
+ el.accept(this);
+ e.stageflags = old;
+ }
+ }
+
+ override void visit(ASTCodegen.CompoundLiteralExp e)
+ {
+ if (e.initializer)
+ e.initializer.accept(this);
+ }
+
+ override void visit(ASTCodegen.DotTemplateExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(ASTCodegen.DotVarExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(ASTCodegen.DelegateExp e)
+ {
+ if (!e.func.isNested() || e.func.needThis())
+ e.e1.accept(this);
+ }
+
+ override void visit(ASTCodegen.DotTypeExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(ASTCodegen.VectorExp e)
+ {
+ visitType(e.to);
+ e.e1.accept(this);
+ }
+
+ override void visit(ASTCodegen.VectorArrayExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(ASTCodegen.SliceExp e)
+ {
+ e.e1.accept(this);
+ if (e.upr)
+ e.upr.accept(this);
+ if (e.lwr)
+ e.lwr.accept(this);
+ }
+
+ override void visit(ASTCodegen.ArrayLengthExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(ASTCodegen.DelegatePtrExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(ASTCodegen.DelegateFuncptrExp e)
+ {
+ e.e1.accept(this);
+ }
+
+ override void visit(ASTCodegen.DotExp e)
+ {
+ e.e1.accept(this);
+ e.e2.accept(this);
+ }
+
+ override void visit(ASTCodegen.IndexExp e)
+ {
+ e.e1.accept(this);
+ e.e2.accept(this);
+ }
+
+ override void visit(ASTCodegen.RemoveExp e)
+ {
+ e.e1.accept(this);
+ e.e2.accept(this);
+ }
+}
+
+extern (C++) class StoppableVisitor : Visitor
+{
+ alias visit = Visitor.visit;
+public:
+ bool stop;
+
+ final extern (D) this()
+ {
+ }
+}
diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h
index 09ba202..e61f16d 100644
--- a/gcc/d/dmd/visitor.h
+++ b/gcc/d/dmd/visitor.h
@@ -84,6 +84,7 @@ class TypeNull;
class TypeNoreturn;
class TypeTraits;
class TypeMixin;
+class TypeTag;
class Dsymbol;
@@ -101,7 +102,8 @@ class StorageClassDeclaration;
class DeprecatedDeclaration;
class LinkDeclaration;
class CPPMangleDeclaration;
-class ProtDeclaration;
+class CPPNamespaceDeclaration;
+class VisibilityDeclaration;
class AlignDeclaration;
class AnonDeclaration;
class PragmaDeclaration;
@@ -122,6 +124,7 @@ class Module;
class WithScopeSymbol;
class ArrayScopeSymbol;
class Nspace;
+class AliasAssign;
class AggregateDeclaration;
class StructDeclaration;
@@ -136,6 +139,7 @@ class OverDeclaration;
class VarDeclaration;
class SymbolDeclaration;
class ThisDeclaration;
+class BitFieldDeclaration;
class TypeInfoDeclaration;
class TypeInfoStructDeclaration;
@@ -168,7 +172,6 @@ class SharedStaticDtorDeclaration;
class InvariantDeclaration;
class UnitTestDeclaration;
class NewDeclaration;
-class DeleteDeclaration;
class Initializer;
class VoidInitializer;
@@ -176,6 +179,7 @@ class ErrorInitializer;
class StructInitializer;
class ArrayInitializer;
class ExpInitializer;
+class CInitializer;
class Expression;
class IntegerExp;
@@ -193,6 +197,8 @@ class TupleExp;
class ArrayLiteralExp;
class AssocArrayLiteralExp;
class StructLiteralExp;
+class CompoundLiteralExp;
+class ObjcClassReferenceExp;
class TypeExp;
class ScopeExp;
class TemplateExp;
@@ -211,7 +217,7 @@ class IsExp;
class UnaExp;
class BinExp;
class BinAssignExp;
-class CompileExp;
+class MixinExp;
class ImportExp;
class AssertExp;
class DotIdExp;
@@ -287,6 +293,7 @@ class PrettyFuncInitExp;
class ClassReferenceExp;
class VoidInitExp;
class ThrownExceptionExp;
+class GenericExp;
class TemplateParameter;
class TemplateTypeParameter;
@@ -303,135 +310,301 @@ class StaticIfCondition;
class Parameter;
-class Visitor
+class ParseTimeVisitor
{
public:
+ virtual void visit(Dsymbol *) { assert(0); }
+ virtual void visit(Parameter *) { assert(0); }
virtual void visit(Statement *) { assert(0); }
- virtual void visit(ErrorStatement *s) { visit((Statement *)s); }
- virtual void visit(PeelStatement *s) { visit((Statement *)s); }
- virtual void visit(ExpStatement *s) { visit((Statement *)s); }
- virtual void visit(DtorExpStatement *s) { visit((ExpStatement *)s); }
- virtual void visit(CompileStatement *s) { visit((Statement *)s); }
- virtual void visit(CompoundStatement *s) { visit((Statement *)s); }
- virtual void visit(CompoundDeclarationStatement *s) { visit((CompoundStatement *)s); }
- virtual void visit(UnrolledLoopStatement *s) { visit((Statement *)s); }
+ virtual void visit(Type *) { assert(0); }
+ virtual void visit(Expression *) { assert(0); }
+ virtual void visit(TemplateParameter *) { assert(0); }
+ virtual void visit(Condition *) { assert(0); }
+ virtual void visit(Initializer *) { assert(0); }
+
+ // Dsymbols
+ virtual void visit(AliasThis *s) { visit((Dsymbol *)s); }
+ virtual void visit(Declaration *s) { visit((Dsymbol *)s); }
+ virtual void visit(ScopeDsymbol *s) { visit((Dsymbol *)s); }
+ virtual void visit(Import *s) { visit((Dsymbol *)s); }
+ virtual void visit(AttribDeclaration *s) { visit((Dsymbol *)s); }
+ virtual void visit(StaticAssert *s) { visit((Dsymbol *)s); }
+ virtual void visit(DebugSymbol *s) { visit((Dsymbol *)s); }
+ virtual void visit(VersionSymbol *s) { visit((Dsymbol *)s); }
+ virtual void visit(AliasAssign *s) { visit((Dsymbol *)s); }
+
+ // ScopeDsymbols
+ virtual void visit(Package *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(EnumDeclaration *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(AggregateDeclaration *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(TemplateDeclaration *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(TemplateInstance *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(Nspace *s) { visit((ScopeDsymbol *)s); }
+
+ // Declarations
+ virtual void visit(VarDeclaration *s) { visit((Declaration *)s); }
+ virtual void visit(FuncDeclaration *s) { visit((Declaration *)s); }
+ virtual void visit(AliasDeclaration *s) { visit((Declaration *)s); }
+ virtual void visit(TupleDeclaration *s) { visit((Declaration *)s); }
+
+ // FuncDeclarations
+ virtual void visit(FuncLiteralDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(PostBlitDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(CtorDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(DtorDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(InvariantDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(UnitTestDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(NewDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(StaticCtorDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(StaticDtorDeclaration *s) { visit((FuncDeclaration *)s); }
+ virtual void visit(SharedStaticCtorDeclaration *s) { visit((StaticCtorDeclaration *)s); }
+ virtual void visit(SharedStaticDtorDeclaration *s) { visit((StaticDtorDeclaration *)s); }
+
+ // AttribDeclarations
+ virtual void visit(CompileDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(UserAttributeDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(LinkDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(AnonDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(AlignDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(CPPMangleDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(CPPNamespaceDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(VisibilityDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(PragmaDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(StorageClassDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(ConditionalDeclaration *s) { visit((AttribDeclaration *)s); }
+ virtual void visit(StaticForeachDeclaration *s) { visit((AttribDeclaration *)s); }
+
+ // Miscellaneous
+ virtual void visit(DeprecatedDeclaration *s) { visit((StorageClassDeclaration *)s); }
+ virtual void visit(StaticIfDeclaration *s) { visit((ConditionalDeclaration *)s); }
+ virtual void visit(EnumMember *s) { visit((VarDeclaration *)s); }
+ virtual void visit(Module *s) { visit((Package *)s); }
+ virtual void visit(StructDeclaration *s) { visit((AggregateDeclaration *)s); }
+ virtual void visit(UnionDeclaration *s) { visit((StructDeclaration *)s); }
+ virtual void visit(ClassDeclaration *s) { visit((AggregateDeclaration *)s); }
+ virtual void visit(InterfaceDeclaration *s) { visit((ClassDeclaration *)s); }
+ virtual void visit(TemplateMixin *s) { visit((TemplateInstance *)s); }
+ virtual void visit(BitFieldDeclaration *s) { visit((VarDeclaration *)s); }
+
+ // Statements
+ virtual void visit(ImportStatement *s) { visit((Statement *)s); }
virtual void visit(ScopeStatement *s) { visit((Statement *)s); }
- virtual void visit(ForwardingStatement *s) { visit((Statement *)s); }
+ virtual void visit(ReturnStatement *s) { visit((Statement *)s); }
+ virtual void visit(LabelStatement *s) { visit((Statement *)s); }
+ virtual void visit(StaticAssertStatement *s) { visit((Statement *)s); }
+ virtual void visit(CompileStatement *s) { visit((Statement *)s); }
virtual void visit(WhileStatement *s) { visit((Statement *)s); }
- virtual void visit(DoStatement *s) { visit((Statement *)s); }
virtual void visit(ForStatement *s) { visit((Statement *)s); }
- virtual void visit(ForeachStatement *s) { visit((Statement *)s); }
+ virtual void visit(DoStatement *s) { visit((Statement *)s); }
virtual void visit(ForeachRangeStatement *s) { visit((Statement *)s); }
- virtual void visit(StaticForeachStatement *s) { visit((Statement *)s); }
+ virtual void visit(ForeachStatement *s) { visit((Statement *)s); }
virtual void visit(IfStatement *s) { visit((Statement *)s); }
+ virtual void visit(ScopeGuardStatement *s) { visit((Statement *)s); }
virtual void visit(ConditionalStatement *s) { visit((Statement *)s); }
+ virtual void visit(StaticForeachStatement *s) { visit((Statement *)s); }
virtual void visit(PragmaStatement *s) { visit((Statement *)s); }
- virtual void visit(StaticAssertStatement *s) { visit((Statement *)s); }
virtual void visit(SwitchStatement *s) { visit((Statement *)s); }
- virtual void visit(CaseStatement *s) { visit((Statement *)s); }
virtual void visit(CaseRangeStatement *s) { visit((Statement *)s); }
+ virtual void visit(CaseStatement *s) { visit((Statement *)s); }
virtual void visit(DefaultStatement *s) { visit((Statement *)s); }
- virtual void visit(GotoDefaultStatement *s) { visit((Statement *)s); }
- virtual void visit(GotoCaseStatement *s) { visit((Statement *)s); }
- virtual void visit(SwitchErrorStatement *s) { visit((Statement *)s); }
- virtual void visit(ReturnStatement *s) { visit((Statement *)s); }
virtual void visit(BreakStatement *s) { visit((Statement *)s); }
virtual void visit(ContinueStatement *s) { visit((Statement *)s); }
+ virtual void visit(GotoDefaultStatement *s) { visit((Statement *)s); }
+ virtual void visit(GotoCaseStatement *s) { visit((Statement *)s); }
+ virtual void visit(GotoStatement *s) { visit((Statement *)s); }
virtual void visit(SynchronizedStatement *s) { visit((Statement *)s); }
virtual void visit(WithStatement *s) { visit((Statement *)s); }
virtual void visit(TryCatchStatement *s) { visit((Statement *)s); }
virtual void visit(TryFinallyStatement *s) { visit((Statement *)s); }
- virtual void visit(ScopeGuardStatement *s) { visit((Statement *)s); }
virtual void visit(ThrowStatement *s) { visit((Statement *)s); }
- virtual void visit(DebugStatement *s) { visit((Statement *)s); }
- virtual void visit(GotoStatement *s) { visit((Statement *)s); }
- virtual void visit(LabelStatement *s) { visit((Statement *)s); }
virtual void visit(AsmStatement *s) { visit((Statement *)s); }
+ virtual void visit(ExpStatement *s) { visit((Statement *)s); }
+ virtual void visit(CompoundStatement *s) { visit((Statement *)s); }
+
+ // CompoundStatements
+ virtual void visit(CompoundDeclarationStatement *s) { visit((CompoundStatement *)s); }
+ virtual void visit(CompoundAsmStatement *s) { visit((CompoundStatement *)s); }
+
+ // AsmStatements
virtual void visit(InlineAsmStatement *s) { visit((AsmStatement *)s); }
virtual void visit(GccAsmStatement *s) { visit((AsmStatement *)s); }
- virtual void visit(CompoundAsmStatement *s) { visit((CompoundStatement *)s); }
- virtual void visit(ImportStatement *s) { visit((Statement *)s); }
- virtual void visit(Type *) { assert(0); }
- virtual void visit(TypeError *t) { visit((Type *)t); }
- virtual void visit(TypeNext *t) { visit((Type *)t); }
+ // Types
virtual void visit(TypeBasic *t) { visit((Type *)t); }
+ virtual void visit(TypeError *t) { visit((Type *)t); }
+ virtual void visit(TypeNull *t) { visit((Type *)t); }
+ virtual void visit(TypeNoreturn *t) { visit((Type *)t); }
virtual void visit(TypeVector *t) { visit((Type *)t); }
+ virtual void visit(TypeEnum *t) { visit((Type *)t); }
+ virtual void visit(TypeTuple *t) { visit((Type *)t); }
+ virtual void visit(TypeClass *t) { visit((Type *)t); }
+ virtual void visit(TypeStruct *t) { visit((Type *)t); }
+ virtual void visit(TypeNext *t) { visit((Type *)t); }
+ virtual void visit(TypeQualified *t) { visit((Type *)t); }
+ virtual void visit(TypeTraits *t) { visit((Type *)t); }
+ virtual void visit(TypeMixin *t) { visit((Type *)t); }
+ virtual void visit(TypeTag *t) { visit((Type *)t); }
+
+ // TypeNext
+ virtual void visit(TypeReference *t) { visit((TypeNext *)t); }
+ virtual void visit(TypeSlice *t) { visit((TypeNext *)t); }
+ virtual void visit(TypeDelegate *t) { visit((TypeNext *)t); }
+ virtual void visit(TypePointer *t) { visit((TypeNext *)t); }
+ virtual void visit(TypeFunction *t) { visit((TypeNext *)t); }
virtual void visit(TypeArray *t) { visit((TypeNext *)t); }
- virtual void visit(TypeSArray *t) { visit((TypeArray *)t); }
+
+ // TypeArray
virtual void visit(TypeDArray *t) { visit((TypeArray *)t); }
virtual void visit(TypeAArray *t) { visit((TypeArray *)t); }
- virtual void visit(TypePointer *t) { visit((TypeNext *)t); }
- virtual void visit(TypeReference *t) { visit((TypeNext *)t); }
- virtual void visit(TypeFunction *t) { visit((TypeNext *)t); }
- virtual void visit(TypeDelegate *t) { visit((TypeNext *)t); }
- virtual void visit(TypeQualified *t) { visit((Type *)t); }
+ virtual void visit(TypeSArray *t) { visit((TypeArray *)t); }
+
+ // TypeQualified
virtual void visit(TypeIdentifier *t) { visit((TypeQualified *)t); }
- virtual void visit(TypeInstance *t) { visit((TypeQualified *)t); }
- virtual void visit(TypeTypeof *t) { visit((TypeQualified *)t); }
virtual void visit(TypeReturn *t) { visit((TypeQualified *)t); }
- virtual void visit(TypeStruct *t) { visit((Type *)t); }
- virtual void visit(TypeEnum *t) { visit((Type *)t); }
- virtual void visit(TypeClass *t) { visit((Type *)t); }
- virtual void visit(TypeTuple *t) { visit((Type *)t); }
- virtual void visit(TypeSlice *t) { visit((TypeNext *)t); }
- virtual void visit(TypeNull *t) { visit((Type *)t); }
- virtual void visit(TypeNoreturn *t) { visit((Type *)t); }
- virtual void visit(TypeTraits *t) { visit((Type *)t); }
- virtual void visit(TypeMixin *t) { visit((Type *)t); }
+ virtual void visit(TypeTypeof *t) { visit((TypeQualified *)t); }
+ virtual void visit(TypeInstance *t) { visit((TypeQualified *)t); }
- virtual void visit(Dsymbol *) { assert(0); }
+ // Expressions
+ virtual void visit(DeclarationExp *e) { visit((Expression *)e); }
+ virtual void visit(IntegerExp *e) { visit((Expression *)e); }
+ virtual void visit(NewAnonClassExp *e) { visit((Expression *)e); }
+ virtual void visit(IsExp *e) { visit((Expression *)e); }
+ virtual void visit(RealExp *e) { visit((Expression *)e); }
+ virtual void visit(NullExp *e) { visit((Expression *)e); }
+ virtual void visit(TypeidExp *e) { visit((Expression *)e); }
+ virtual void visit(TraitsExp *e) { visit((Expression *)e); }
+ virtual void visit(StringExp *e) { visit((Expression *)e); }
+ virtual void visit(NewExp *e) { visit((Expression *)e); }
+ virtual void visit(AssocArrayLiteralExp *e) { visit((Expression *)e); }
+ virtual void visit(ArrayLiteralExp *e) { visit((Expression *)e); }
+ virtual void visit(MixinExp *e) { visit((Expression *)e); }
+ virtual void visit(FuncExp *e) { visit((Expression *)e); }
+ virtual void visit(IntervalExp *e) { visit((Expression *)e); }
+ virtual void visit(TypeExp *e) { visit((Expression *)e); }
+ virtual void visit(ScopeExp *e) { visit((Expression *)e); }
+ virtual void visit(IdentifierExp *e) { visit((Expression *)e); }
+ virtual void visit(UnaExp *e) { visit((Expression *)e); }
+ virtual void visit(DefaultInitExp *e) { visit((Expression *)e); }
+ virtual void visit(BinExp *e) { visit((Expression *)e); }
+ virtual void visit(DsymbolExp *e) { visit((Expression *)e); }
+ virtual void visit(TemplateExp *e) { visit((Expression *)e); }
+ virtual void visit(SymbolExp *e) { visit((Expression *)e); }
+ virtual void visit(TupleExp *e) { visit((Expression *)e); }
+ virtual void visit(ThisExp *e) { visit((Expression *)e); }
+ virtual void visit(GenericExp *e) { visit((Expression *)e); }
- virtual void visit(StaticAssert *s) { visit((Dsymbol *)s); }
- virtual void visit(DebugSymbol *s) { visit((Dsymbol *)s); }
- virtual void visit(VersionSymbol *s) { visit((Dsymbol *)s); }
- virtual void visit(EnumMember *s) { visit((VarDeclaration *)s); }
- virtual void visit(Import *s) { visit((Dsymbol *)s); }
- virtual void visit(OverloadSet *s) { visit((Dsymbol *)s); }
- virtual void visit(LabelDsymbol *s) { visit((Dsymbol *)s); }
- virtual void visit(AliasThis *s) { visit((Dsymbol *)s); }
+ // Miscellaneous
+ virtual void visit(VarExp *e) { visit((SymbolExp *)e); }
+ virtual void visit(DollarExp *e) { visit((IdentifierExp *)e); }
+ virtual void visit(SuperExp *e) { visit((ThisExp *)e); }
- virtual void visit(AttribDeclaration *s) { visit((Dsymbol *)s); }
- virtual void visit(StorageClassDeclaration *s) { visit((AttribDeclaration *)s); }
- virtual void visit(DeprecatedDeclaration *s) { visit((StorageClassDeclaration *)s); }
- virtual void visit(LinkDeclaration *s) { visit((AttribDeclaration *)s); }
- virtual void visit(CPPMangleDeclaration *s) { visit((AttribDeclaration *)s); }
- virtual void visit(ProtDeclaration *s) { visit((AttribDeclaration *)s); }
- virtual void visit(AlignDeclaration *s) { visit((AttribDeclaration *)s); }
- virtual void visit(AnonDeclaration *s) { visit((AttribDeclaration *)s); }
- virtual void visit(PragmaDeclaration *s) { visit((AttribDeclaration *)s); }
- virtual void visit(ConditionalDeclaration *s) { visit((AttribDeclaration *)s); }
- virtual void visit(StaticIfDeclaration *s) { visit((ConditionalDeclaration *)s); }
- virtual void visit(StaticForeachDeclaration *s) { visit((AttribDeclaration *)s); }
- virtual void visit(CompileDeclaration *s) { visit((AttribDeclaration *)s); }
- virtual void visit(UserAttributeDeclaration *s) { visit((AttribDeclaration *)s); }
- virtual void visit(ForwardingAttribDeclaration *s) { visit((AttribDeclaration *)s); }
+ // UnaExp
+ virtual void visit(AddrExp *e) { visit((UnaExp *)e); }
+ virtual void visit(PreExp *e) { visit((UnaExp *)e); }
+ virtual void visit(PtrExp *e) { visit((UnaExp *)e); }
+ virtual void visit(NegExp *e) { visit((UnaExp *)e); }
+ virtual void visit(UAddExp *e) { visit((UnaExp *)e); }
+ virtual void visit(NotExp *e) { visit((UnaExp *)e); }
+ virtual void visit(ComExp *e) { visit((UnaExp *)e); }
+ virtual void visit(DeleteExp *e) { visit((UnaExp *)e); }
+ virtual void visit(CastExp *e) { visit((UnaExp *)e); }
+ virtual void visit(CallExp *e) { visit((UnaExp *)e); }
+ virtual void visit(DotIdExp *e) { visit((UnaExp *)e); }
+ virtual void visit(AssertExp *e) { visit((UnaExp *)e); }
+ virtual void visit(ImportExp *e) { visit((UnaExp *)e); }
+ virtual void visit(DotTemplateInstanceExp *e) { visit((UnaExp *)e); }
+ virtual void visit(ArrayExp *e) { visit((UnaExp *)e); }
- virtual void visit(ScopeDsymbol *s) { visit((Dsymbol *)s); }
- virtual void visit(TemplateDeclaration *s) { visit((ScopeDsymbol *)s); }
- virtual void visit(TemplateInstance *s) { visit((ScopeDsymbol *)s); }
- virtual void visit(TemplateMixin *s) { visit((TemplateInstance *)s); }
- virtual void visit(EnumDeclaration *s) { visit((ScopeDsymbol *)s); }
- virtual void visit(Package *s) { visit((ScopeDsymbol *)s); }
- virtual void visit(Module *s) { visit((Package *)s); }
- virtual void visit(WithScopeSymbol *s) { visit((ScopeDsymbol *)s); }
- virtual void visit(ArrayScopeSymbol *s) { visit((ScopeDsymbol *)s); }
- virtual void visit(Nspace *s) { visit((ScopeDsymbol *)s); }
+ // DefaultInitExp
+ virtual void visit(FuncInitExp *e) { visit((DefaultInitExp *)e); }
+ virtual void visit(PrettyFuncInitExp *e) { visit((DefaultInitExp *)e); }
+ virtual void visit(FileInitExp *e) { visit((DefaultInitExp *)e); }
+ virtual void visit(LineInitExp *e) { visit((DefaultInitExp *)e); }
+ virtual void visit(ModuleInitExp *e) { visit((DefaultInitExp *)e); }
- virtual void visit(AggregateDeclaration *s) { visit((ScopeDsymbol *)s); }
- virtual void visit(StructDeclaration *s) { visit((AggregateDeclaration *)s); }
- virtual void visit(UnionDeclaration *s) { visit((StructDeclaration *)s); }
- virtual void visit(ClassDeclaration *s) { visit((AggregateDeclaration *)s); }
- virtual void visit(InterfaceDeclaration *s) { visit((ClassDeclaration *)s); }
+ // BinExp
+ virtual void visit(CommaExp *e) { visit((BinExp *)e); }
+ virtual void visit(PostExp *e) { visit((BinExp *)e); }
+ virtual void visit(PowExp *e) { visit((BinExp *)e); }
+ virtual void visit(MulExp *e) { visit((BinExp *)e); }
+ virtual void visit(DivExp *e) { visit((BinExp *)e); }
+ virtual void visit(ModExp *e) { visit((BinExp *)e); }
+ virtual void visit(AddExp *e) { visit((BinExp *)e); }
+ virtual void visit(MinExp *e) { visit((BinExp *)e); }
+ virtual void visit(CatExp *e) { visit((BinExp *)e); }
+ virtual void visit(ShlExp *e) { visit((BinExp *)e); }
+ virtual void visit(ShrExp *e) { visit((BinExp *)e); }
+ virtual void visit(UshrExp *e) { visit((BinExp *)e); }
+ virtual void visit(EqualExp *e) { visit((BinExp *)e); }
+ virtual void visit(InExp *e) { visit((BinExp *)e); }
+ virtual void visit(IdentityExp *e) { visit((BinExp *)e); }
+ virtual void visit(CmpExp *e) { visit((BinExp *)e); }
+ virtual void visit(AndExp *e) { visit((BinExp *)e); }
+ virtual void visit(XorExp *e) { visit((BinExp *)e); }
+ virtual void visit(OrExp *e) { visit((BinExp *)e); }
+ virtual void visit(LogicalExp *e) { visit((BinExp *)e); }
+ virtual void visit(CondExp *e) { visit((BinExp *)e); }
+ virtual void visit(AssignExp *e) { visit((BinExp *)e); }
+ virtual void visit(BinAssignExp *e) { visit((BinExp *)e); }
- virtual void visit(Declaration *s) { visit((Dsymbol *)s); }
- virtual void visit(TupleDeclaration *s) { visit((Declaration *)s); }
- virtual void visit(AliasDeclaration *s) { visit((Declaration *)s); }
+ // BinAssignExp
+ virtual void visit(AddAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(MinAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(MulAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(DivAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(ModAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(PowAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(AndAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(OrAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(XorAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(ShlAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(ShrAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(UshrAssignExp *e) { visit((BinAssignExp *)e); }
+ virtual void visit(CatAssignExp *e) { visit((BinAssignExp *)e); }
+
+ // TemplateParameter
+ virtual void visit(TemplateAliasParameter *tp) { visit((TemplateParameter *)tp); }
+ virtual void visit(TemplateTypeParameter *tp) { visit((TemplateParameter *)tp); }
+ virtual void visit(TemplateTupleParameter *tp) { visit((TemplateParameter *)tp); }
+ virtual void visit(TemplateValueParameter *tp) { visit((TemplateParameter *)tp); }
+
+ virtual void visit(TemplateThisParameter *tp) { visit((TemplateTypeParameter *)tp); }
+
+ // Condition
+ virtual void visit(StaticIfCondition *c) { visit((Condition *)c); }
+ virtual void visit(DVCondition *c) { visit((Condition *)c); }
+ virtual void visit(DebugCondition *c) { visit((DVCondition *)c); }
+ virtual void visit(VersionCondition *c) { visit((DVCondition *)c); }
+
+ // Initializer
+ virtual void visit(ExpInitializer *i) { visit((Initializer *)i); }
+ virtual void visit(StructInitializer *i) { visit((Initializer *)i); }
+ virtual void visit(ArrayInitializer *i) { visit((Initializer *)i); }
+ virtual void visit(VoidInitializer *i) { visit((Initializer *)i); }
+ virtual void visit(CInitializer *i) { visit((Initializer *)i); }
+};
+
+class Visitor : public ParseTimeVisitor
+{
+public:
+ using ParseTimeVisitor::visit;
+
+ // Miscellaneous
+ virtual void visit(ErrorStatement *s) { visit((Statement *)s); }
+ virtual void visit(PeelStatement *s) { visit((Statement *)s); }
+ virtual void visit(UnrolledLoopStatement *s) { visit((Statement *)s); }
+ virtual void visit(SwitchErrorStatement *s) { visit((Statement *)s); }
+ virtual void visit(DebugStatement *s) { visit((Statement *)s); }
+ virtual void visit(DtorExpStatement *s) { visit((ExpStatement *)s); }
+ virtual void visit(ForwardingStatement *s) { visit((Statement *)s); }
+ virtual void visit(OverloadSet *s) { visit((Dsymbol *)s); }
+ virtual void visit(LabelDsymbol *s) { visit((Dsymbol *)s); }
+ virtual void visit(WithScopeSymbol *s) { visit((ScopeDsymbol *)s); }
+ virtual void visit(ArrayScopeSymbol *s) { visit((ScopeDsymbol *)s); }
virtual void visit(OverDeclaration *s) { visit((Declaration *)s); }
- virtual void visit(VarDeclaration *s) { visit((Declaration *)s); }
virtual void visit(SymbolDeclaration *s) { visit((Declaration *)s); }
+ virtual void visit(ForwardingAttribDeclaration *s) { visit((AttribDeclaration *)s); }
virtual void visit(ThisDeclaration *s) { visit((VarDeclaration *)s); }
-
virtual void visit(TypeInfoDeclaration *s) { visit((VarDeclaration *)s); }
virtual void visit(TypeInfoStructDeclaration *s) { visit((TypeInfoDeclaration *)s); }
virtual void visit(TypeInfoClassDeclaration *s) { visit((TypeInfoDeclaration *)s); }
@@ -449,154 +622,34 @@ public:
virtual void visit(TypeInfoSharedDeclaration *s) { visit((TypeInfoDeclaration *)s); }
virtual void visit(TypeInfoWildDeclaration *s) { visit((TypeInfoDeclaration *)s); }
virtual void visit(TypeInfoVectorDeclaration *s) { visit((TypeInfoDeclaration *)s); }
-
- virtual void visit(FuncDeclaration *s) { visit((Declaration *)s); }
virtual void visit(FuncAliasDeclaration *s) { visit((FuncDeclaration *)s); }
- virtual void visit(FuncLiteralDeclaration *s) { visit((FuncDeclaration *)s); }
- virtual void visit(CtorDeclaration *s) { visit((FuncDeclaration *)s); }
- virtual void visit(PostBlitDeclaration *s) { visit((FuncDeclaration *)s); }
- virtual void visit(DtorDeclaration *s) { visit((FuncDeclaration *)s); }
- virtual void visit(StaticCtorDeclaration *s) { visit((FuncDeclaration *)s); }
- virtual void visit(SharedStaticCtorDeclaration *s) { visit((StaticCtorDeclaration *)s); }
- virtual void visit(StaticDtorDeclaration *s) { visit((FuncDeclaration *)s); }
- virtual void visit(SharedStaticDtorDeclaration *s) { visit((StaticDtorDeclaration *)s); }
- virtual void visit(InvariantDeclaration *s) { visit((FuncDeclaration *)s); }
- virtual void visit(UnitTestDeclaration *s) { visit((FuncDeclaration *)s); }
- virtual void visit(NewDeclaration *s) { visit((FuncDeclaration *)s); }
- virtual void visit(DeleteDeclaration *s) { visit((FuncDeclaration *)s); }
-
- virtual void visit(Initializer *) { assert(0); }
- virtual void visit(VoidInitializer *i) { visit((Initializer *)i); }
virtual void visit(ErrorInitializer *i) { visit((Initializer *)i); }
- virtual void visit(StructInitializer *i) { visit((Initializer *)i); }
- virtual void visit(ArrayInitializer *i) { visit((Initializer *)i); }
- virtual void visit(ExpInitializer *i) { visit((Initializer *)i); }
-
- virtual void visit(Expression *) { assert(0); }
- virtual void visit(IntegerExp *e) { visit((Expression *)e); }
virtual void visit(ErrorExp *e) { visit((Expression *)e); }
- virtual void visit(RealExp *e) { visit((Expression *)e); }
virtual void visit(ComplexExp *e) { visit((Expression *)e); }
- virtual void visit(IdentifierExp *e) { visit((Expression *)e); }
- virtual void visit(DollarExp *e) { visit((IdentifierExp *)e); }
- virtual void visit(DsymbolExp *e) { visit((Expression *)e); }
- virtual void visit(ThisExp *e) { visit((Expression *)e); }
- virtual void visit(SuperExp *e) { visit((ThisExp *)e); }
- virtual void visit(NullExp *e) { visit((Expression *)e); }
- virtual void visit(StringExp *e) { visit((Expression *)e); }
- virtual void visit(TupleExp *e) { visit((Expression *)e); }
- virtual void visit(ArrayLiteralExp *e) { visit((Expression *)e); }
- virtual void visit(AssocArrayLiteralExp *e) { visit((Expression *)e); }
virtual void visit(StructLiteralExp *e) { visit((Expression *)e); }
- virtual void visit(TypeExp *e) { visit((Expression *)e); }
- virtual void visit(ScopeExp *e) { visit((Expression *)e); }
- virtual void visit(TemplateExp *e) { visit((Expression *)e); }
- virtual void visit(NewExp *e) { visit((Expression *)e); }
- virtual void visit(NewAnonClassExp *e) { visit((Expression *)e); }
- virtual void visit(SymbolExp *e) { visit((Expression *)e); }
+ virtual void visit(CompoundLiteralExp *e) { visit((Expression *)e); }
+ virtual void visit(ObjcClassReferenceExp *e) { visit((Expression *)e); }
virtual void visit(SymOffExp *e) { visit((SymbolExp *)e); }
- virtual void visit(VarExp *e) { visit((SymbolExp *)e); }
virtual void visit(OverExp *e) { visit((Expression *)e); }
- virtual void visit(FuncExp *e) { visit((Expression *)e); }
- virtual void visit(DeclarationExp *e) { visit((Expression *)e); }
- virtual void visit(TypeidExp *e) { visit((Expression *)e); }
- virtual void visit(TraitsExp *e) { visit((Expression *)e); }
virtual void visit(HaltExp *e) { visit((Expression *)e); }
- virtual void visit(IsExp *e) { visit((Expression *)e); }
- virtual void visit(UnaExp *e) { visit((Expression *)e); }
- virtual void visit(BinExp *e) { visit((Expression *)e); }
- virtual void visit(BinAssignExp *e) { visit((BinExp *)e); }
- virtual void visit(CompileExp *e) { visit((UnaExp *)e); }
- virtual void visit(ImportExp *e) { visit((UnaExp *)e); }
- virtual void visit(AssertExp *e) { visit((UnaExp *)e); }
- virtual void visit(DotIdExp *e) { visit((UnaExp *)e); }
virtual void visit(DotTemplateExp *e) { visit((UnaExp *)e); }
virtual void visit(DotVarExp *e) { visit((UnaExp *)e); }
- virtual void visit(DotTemplateInstanceExp *e) { visit((UnaExp *)e); }
virtual void visit(DelegateExp *e) { visit((UnaExp *)e); }
virtual void visit(DotTypeExp *e) { visit((UnaExp *)e); }
- virtual void visit(CallExp *e) { visit((UnaExp *)e); }
- virtual void visit(AddrExp *e) { visit((UnaExp *)e); }
- virtual void visit(PtrExp *e) { visit((UnaExp *)e); }
- virtual void visit(NegExp *e) { visit((UnaExp *)e); }
- virtual void visit(UAddExp *e) { visit((UnaExp *)e); }
- virtual void visit(ComExp *e) { visit((UnaExp *)e); }
- virtual void visit(NotExp *e) { visit((UnaExp *)e); }
- virtual void visit(DeleteExp *e) { visit((UnaExp *)e); }
- virtual void visit(CastExp *e) { visit((UnaExp *)e); }
virtual void visit(VectorExp *e) { visit((UnaExp *)e); }
virtual void visit(VectorArrayExp *e) { visit((UnaExp *)e); }
virtual void visit(SliceExp *e) { visit((UnaExp *)e); }
virtual void visit(ArrayLengthExp *e) { visit((UnaExp *)e); }
- virtual void visit(IntervalExp *e) { visit((Expression *)e); }
virtual void visit(DelegatePtrExp *e) { visit((UnaExp *)e); }
virtual void visit(DelegateFuncptrExp *e) { visit((UnaExp *)e); }
- virtual void visit(ArrayExp *e) { visit((UnaExp *)e); }
virtual void visit(DotExp *e) { visit((BinExp *)e); }
- virtual void visit(CommaExp *e) { visit((BinExp *)e); }
virtual void visit(IndexExp *e) { visit((BinExp *)e); }
- virtual void visit(PostExp *e) { visit((BinExp *)e); }
- virtual void visit(PreExp *e) { visit((UnaExp *)e); }
- virtual void visit(AssignExp *e) { visit((BinExp *)e); }
virtual void visit(ConstructExp *e) { visit((AssignExp *)e); }
virtual void visit(BlitExp *e) { visit((AssignExp *)e); }
- virtual void visit(AddAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(MinAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(MulAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(DivAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(ModAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(AndAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(OrAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(XorAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(PowAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(ShlAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(ShrAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(UshrAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(CatAssignExp *e) { visit((BinAssignExp *)e); }
- virtual void visit(AddExp *e) { visit((BinExp *)e); }
- virtual void visit(MinExp *e) { visit((BinExp *)e); }
- virtual void visit(CatExp *e) { visit((BinExp *)e); }
- virtual void visit(MulExp *e) { visit((BinExp *)e); }
- virtual void visit(DivExp *e) { visit((BinExp *)e); }
- virtual void visit(ModExp *e) { visit((BinExp *)e); }
- virtual void visit(PowExp *e) { visit((BinExp *)e); }
- virtual void visit(ShlExp *e) { visit((BinExp *)e); }
- virtual void visit(ShrExp *e) { visit((BinExp *)e); }
- virtual void visit(UshrExp *e) { visit((BinExp *)e); }
- virtual void visit(AndExp *e) { visit((BinExp *)e); }
- virtual void visit(OrExp *e) { visit((BinExp *)e); }
- virtual void visit(XorExp *e) { visit((BinExp *)e); }
- virtual void visit(LogicalExp *e) { visit((BinExp *)e); }
- virtual void visit(CmpExp *e) { visit((BinExp *)e); }
- virtual void visit(InExp *e) { visit((BinExp *)e); }
virtual void visit(RemoveExp *e) { visit((BinExp *)e); }
- virtual void visit(EqualExp *e) { visit((BinExp *)e); }
- virtual void visit(IdentityExp *e) { visit((BinExp *)e); }
- virtual void visit(CondExp *e) { visit((BinExp *)e); }
- virtual void visit(DefaultInitExp *e) { visit((Expression *)e); }
- virtual void visit(FileInitExp *e) { visit((DefaultInitExp *)e); }
- virtual void visit(LineInitExp *e) { visit((DefaultInitExp *)e); }
- virtual void visit(ModuleInitExp *e) { visit((DefaultInitExp *)e); }
- virtual void visit(FuncInitExp *e) { visit((DefaultInitExp *)e); }
- virtual void visit(PrettyFuncInitExp *e) { visit((DefaultInitExp *)e); }
virtual void visit(ClassReferenceExp *e) { visit((Expression *)e); }
virtual void visit(VoidInitExp *e) { visit((Expression *)e); }
virtual void visit(ThrownExceptionExp *e) { visit((Expression *)e); }
-
- virtual void visit(TemplateParameter *) { assert(0); }
- virtual void visit(TemplateTypeParameter *tp) { visit((TemplateParameter *)tp); }
- virtual void visit(TemplateThisParameter *tp) { visit((TemplateTypeParameter *)tp); }
- virtual void visit(TemplateValueParameter *tp) { visit((TemplateParameter *)tp); }
- virtual void visit(TemplateAliasParameter *tp) { visit((TemplateParameter *)tp); }
- virtual void visit(TemplateTupleParameter *tp) { visit((TemplateParameter *)tp); }
-
- virtual void visit(Condition *) { assert(0); }
- virtual void visit(DVCondition *c) { visit((Condition *)c); }
- virtual void visit(DebugCondition *c) { visit((DVCondition *)c); }
- virtual void visit(VersionCondition *c) { visit((DVCondition *)c); }
- virtual void visit(StaticIfCondition *c) { visit((Condition *)c); }
-
- virtual void visit(Parameter *) { assert(0); }
};
class StoppableVisitor : public Visitor
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index ea21bd5..3168056 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -249,7 +249,7 @@ public:
tree t1 = build_expr (e->e1);
tree t2 = build_expr (e->e2);
- if (e->type->ty != Tvoid)
+ if (e->type->ty != TY::Tvoid)
{
t1 = convert_expr (t1, e->e1->type, e->type);
t2 = convert_expr (t2, e->e2->type, e->type);
@@ -268,8 +268,8 @@ public:
Type *tb1 = e->e1->type->toBasetype ();
Type *tb2 = e->e2->type->toBasetype ();
- if ((tb1->ty == Tsarray || tb1->ty == Tarray)
- && (tb2->ty == Tsarray || tb2->ty == Tarray))
+ if ((tb1->ty == TY::Tsarray || tb1->ty == TY::Tarray)
+ && (tb2->ty == TY::Tsarray || tb2->ty == TY::Tarray))
{
/* For static and dynamic arrays, identity is defined as referring to
the same array elements and the same number of elements. */
@@ -278,7 +278,7 @@ public:
this->result_ = d_convert (build_ctype (e->type),
build_boolop (code, t1, t2));
}
- else if (tb1->isfloating () && tb1->ty != Tvector)
+ else if (tb1->isfloating () && tb1->ty != TY::Tvector)
{
/* For floating-point values, identity is defined as the bits in the
operands being identical. */
@@ -333,8 +333,8 @@ public:
Type *tb2 = e->e2->type->toBasetype ();
tree_code code = (e->op == TOKequal) ? EQ_EXPR : NE_EXPR;
- if ((tb1->ty == Tsarray || tb1->ty == Tarray)
- && (tb2->ty == Tsarray || tb2->ty == Tarray))
+ if ((tb1->ty == TY::Tsarray || tb1->ty == TY::Tarray)
+ && (tb2->ty == TY::Tsarray || tb2->ty == TY::Tarray))
{
/* For static and dynamic arrays, equality is defined as the lengths of
the arrays matching, and all the elements are equal. */
@@ -346,8 +346,9 @@ public:
e1.length == e2.length && memcmp(e1.ptr, e2.ptr, size) == 0;
Or when generating a NE expression:
e1.length != e2.length || memcmp(e1.ptr, e2.ptr, size) != 0; */
- if ((t1elem->isintegral () || t1elem->ty == Tvoid
- || (t1elem->ty == Tstruct && !t1elem->isTypeStruct ()->sym->xeq))
+ if ((t1elem->isintegral () || t1elem->ty == TY::Tvoid
+ || (t1elem->ty == TY::Tstruct
+ && !t1elem->isTypeStruct ()->sym->xeq))
&& t1elem->ty == t2elem->ty)
{
tree t1 = d_array_convert (e->e1);
@@ -368,7 +369,7 @@ public:
/* Compare arrays using memcmp if possible, otherwise for structs,
each field is compared inline. */
- if (t1elem->ty != Tstruct
+ if (t1elem->ty != TY::Tstruct
|| identity_compare_p (t1elem->isTypeStruct ()->sym))
{
tree size = size_mult_expr (t1len, size_int (t1elem->size ()));
@@ -398,7 +399,7 @@ public:
/* Finally, check if lengths of both arrays match if dynamic.
The frontend should have already guaranteed that static arrays
have same size. */
- if (tb1->ty == Tsarray && tb2->ty == Tsarray)
+ if (tb1->ty == TY::Tsarray && tb2->ty == TY::Tsarray)
gcc_assert (tb1->size () == tb2->size ());
else
{
@@ -444,7 +445,7 @@ public:
this->result_ = build_struct_comparison (code, ts->sym, t1, t2);
}
- else if (tb1->ty == Taarray && tb2->ty == Taarray)
+ else if (tb1->ty == TY::Taarray && tb2->ty == TY::Taarray)
{
/* Use _aaEqual() for associative arrays. */
tree result = build_libcall (LIBCALL_AAEQUAL, e->type, 3,
@@ -518,23 +519,14 @@ public:
gcc_unreachable ();
}
- if ((tb1->ty == Tsarray || tb1->ty == Tarray)
- && (tb2->ty == Tsarray || tb2->ty == Tarray))
+ /* For static and dynamic arrays, the relational op is turned into a
+ library call. It is not lowered during codegen. */
+ if ((tb1->ty == TY::Tsarray || tb1->ty == TY::Tarray)
+ && (tb2->ty == TY::Tsarray || tb2->ty == TY::Tarray))
{
- /* For static and dynamic arrays, the result of the relational op is
- the result of the operator applied to the first non-equal element
- of the array. If two arrays compare equal, but are of different
- lengths, the shorter array compares as less than the longer. */
- Type *telem = tb1->nextOf ()->toBasetype ();
-
- tree call = build_libcall (LIBCALL_ADCMP2, Type::tint32, 3,
- d_array_convert (e->e1),
- d_array_convert (e->e2),
- build_typeinfo (e->loc, telem->arrayOf ()));
- result = build_boolop (code, call, integer_zero_node);
-
- this->result_ = d_convert (build_ctype (e->type), result);
- return;
+ error ("cannot handle comparison of type %<%s == %s%>",
+ tb1->toChars (), tb2->toChars ());
+ gcc_unreachable ();
}
/* Simple comparison. */
@@ -550,7 +542,7 @@ public:
{
tree_code code = (e->op == TOKandand) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
- if (e->e2->type->toBasetype ()->ty != Tvoid)
+ if (e->e2->type->toBasetype ()->ty != TY::Tvoid)
{
tree t1 = build_expr (e->e1);
tree t2 = build_expr (e->e2);
@@ -618,7 +610,8 @@ public:
The front-end rewrites `(p1 - p2)' into `(p1 - p2) / stride'. */
if (MinExp *me = e->e1->isMinExp ())
{
- if (me->e1->type->ty == Tpointer && me->e2->type->ty == Tpointer
+ if (me->e1->type->ty == TY::Tpointer
+ && me->e2->type->ty == TY::Tpointer
&& e->e2->op == TOKint64)
{
code = EXACT_DIV_EXPR;
@@ -678,7 +671,7 @@ public:
Type *tb2 = e->e2->type->toBasetype ();
Type *etype;
- if (tb1->ty == Tarray || tb1->ty == Tsarray)
+ if (tb1->ty == TY::Tarray || tb1->ty == TY::Tsarray)
etype = tb1->nextOf ();
else
etype = tb2->nextOf ();
@@ -839,13 +832,13 @@ public:
tree ptr = d_save_expr (build_address (lhs));
tree result = NULL_TREE;
- if (tb1->ty == Tarray && tb2->ty == Tdchar
- && (etype->ty == Tchar || etype->ty == Twchar))
+ if (tb1->ty == TY::Tarray && tb2->ty == TY::Tdchar
+ && (etype->ty == TY::Tchar || etype->ty == TY::Twchar))
{
/* Append a dchar to a char[] or wchar[]:
The assignment is handled by the D run-time library, so only
need to call `_d_arrayappend[cw]d(&e1, e2)' */
- libcall_fn libcall = (etype->ty == Tchar)
+ libcall_fn libcall = (etype->ty == TY::Tchar)
? LIBCALL_ARRAYAPPENDCD : LIBCALL_ARRAYAPPENDWD;
result = build_libcall (libcall, e->type, 2,
@@ -853,9 +846,9 @@ public:
}
else
{
- gcc_assert (tb1->ty == Tarray || tb2->ty == Tsarray);
+ gcc_assert (tb1->ty == TY::Tarray || tb2->ty == TY::Tsarray);
- if ((tb2->ty == Tarray || tb2->ty == Tsarray)
+ if ((tb2->ty == TY::Tarray || tb2->ty == TY::Tsarray)
&& same_type_p (etype, tb2->nextOf ()->toBasetype ()))
{
/* Append an array to another array:
@@ -917,23 +910,9 @@ public:
/* Look for array.length = n; */
if (e->e1->op == TOKarraylength)
{
- /* Assignment to an array's length property; resize the array. */
- ArrayLengthExp *ale = e->e1->isArrayLengthExp ();
- tree newlength = convert_expr (build_expr (e->e2), e->e2->type,
- Type::tsize_t);
- tree ptr = build_address (build_expr (ale->e1));
-
- /* Don't want the basetype for the element type. */
- Type *etype = ale->e1->type->toBasetype ()->nextOf ();
- libcall_fn libcall = etype->isZeroInit ()
- ? LIBCALL_ARRAYSETLENGTHT : LIBCALL_ARRAYSETLENGTHIT;
-
- tree result = build_libcall (libcall, ale->e1->type, 3,
- build_typeinfo (ale->loc, ale->e1->type),
- newlength, ptr);
-
- this->result_ = d_array_length (result);
- return;
+ /* This case should have been rewritten to `_d_arraysetlengthT` in the
+ semantic phase. */
+ gcc_unreachable ();
}
/* Look for array[] = n; */
@@ -947,13 +926,17 @@ public:
bool postblit = needs_postblit (etype) && lvalue_p (e->e2);
bool destructor = needs_dtor (etype);
- if (e->memset & blockAssign)
+ if (e->memset == MemorySet::blockAssign)
{
/* Set a range of elements to one value. */
- tree t1 = d_save_expr (build_expr (e->e1));
+ tree t1 = build_expr (e->e1);
tree t2 = build_expr (e->e2);
tree result;
+ /* Extract any array bounds checks from the slice expression. */
+ tree init = stabilize_expr (&t1);
+ t1 = d_save_expr (t1);
+
if ((postblit || destructor) && e->op != TOKblit)
{
libcall_fn libcall = (e->op == TOKconstruct)
@@ -962,15 +945,12 @@ public:
Type *tm = etype->unSharedOf ()->mutableOf ();
tree ti = build_typeinfo (e->loc, tm);
- tree result = build_libcall (libcall, Type::tvoid, 4,
- d_array_ptr (t1),
- build_address (t2),
- d_array_length (t1), ti);
- this->result_ = compound_expr (result, t1);
- return;
+ result = build_libcall (libcall, Type::tvoid, 4,
+ d_array_ptr (t1),
+ build_address (t2),
+ d_array_length (t1), ti);
}
-
- if (integer_zerop (t2))
+ else if (integer_zerop (t2))
{
tree size = size_mult_expr (d_array_length (t1),
size_int (etype->size ()));
@@ -980,12 +960,13 @@ public:
result = build_array_set (d_array_ptr (t1),
d_array_length (t1), t2);
+ result = compound_expr (init, result);
this->result_ = compound_expr (result, t1);
}
else
{
/* Perform a memcpy operation. */
- gcc_assert (e->e2->type->ty != Tpointer);
+ gcc_assert (e->e2->type->ty != TY::Tpointer);
if (!postblit && !destructor)
{
@@ -1056,7 +1037,7 @@ public:
}
/* Look for reference initializations. */
- if (e->memset & referenceInit)
+ if (e->memset == MemorySet::referenceInit)
{
gcc_assert (e->op == TOKconstruct || e->op == TOKblit);
gcc_assert (e->e1->op == TOKvar);
@@ -1082,7 +1063,7 @@ public:
tree_code modifycode = (e->op == TOKconstruct) ? INIT_EXPR : MODIFY_EXPR;
/* Look for struct assignment. */
- if (tb1->ty == Tstruct)
+ if (tb1->ty == TY::Tstruct)
{
tree t1 = build_expr (e->e1);
tree t2 = convert_for_assignment (build_expr (e->e2, false, true),
@@ -1136,7 +1117,7 @@ public:
}
/* Look for static array assignment. */
- if (tb1->ty == Tsarray)
+ if (tb1->ty == TY::Tsarray)
{
/* Look for array = 0. */
if (e->e2->op == TOKint64)
@@ -1148,7 +1129,7 @@ public:
}
Type *etype = tb1->nextOf ();
- gcc_assert (e->e2->type->toBasetype ()->ty == Tsarray);
+ gcc_assert (e->e2->type->toBasetype ()->ty == TY::Tsarray);
/* Determine if we need to run postblit. */
bool postblit = needs_postblit (etype);
@@ -1171,7 +1152,8 @@ public:
return;
}
- Type *arrtype = (e->type->ty == Tsarray) ? etype->arrayOf () : e->type;
+ Type *arrtype = (e->type->ty == TY::Tsarray)
+ ? etype->arrayOf () : e->type;
tree result;
if (e->op == TOKconstruct)
@@ -1198,7 +1180,7 @@ public:
}
/* Cast the libcall result back to a static array. */
- if (e->type->ty == Tsarray)
+ if (e->type->ty == TY::Tsarray)
result = indirect_ref (build_ctype (e->type),
d_array_ptr (result));
@@ -1243,7 +1225,7 @@ public:
{
Type *tb1 = e->e1->type->toBasetype ();
- if (tb1->ty == Taarray)
+ if (tb1->ty == TY::Taarray)
{
/* Get the key for the associative array. */
Type *tkey = tb1->isTypeAArray ()->index->toBasetype ();
@@ -1289,7 +1271,7 @@ public:
tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ());
tree length = NULL_TREE;
- if (tb1->ty != Tpointer)
+ if (tb1->ty != TY::Tpointer)
length = get_array_length (array, tb1);
else
gcc_assert (e->lengthVar == NULL);
@@ -1304,7 +1286,7 @@ public:
/* If it's a static array and the index is constant, the front end has
already checked the bounds. */
- if (tb1->ty != Tpointer)
+ if (tb1->ty != TY::Tpointer)
index = build_bounds_index_condition (e, index, length);
/* Index the .ptr. */
@@ -1330,7 +1312,7 @@ public:
void visit (ArrayLengthExp *e)
{
- if (e->e1->type->toBasetype ()->ty == Tarray)
+ if (e->e1->type->toBasetype ()->ty == TY::Tarray)
this->result_ = d_array_length (build_expr (e->e1));
else
{
@@ -1364,13 +1346,13 @@ public:
{
Type *tb = e->type->toBasetype ();
Type *tb1 = e->e1->type->toBasetype ();
- gcc_assert (tb->ty == Tarray || tb->ty == Tsarray);
+ gcc_assert (tb->ty == TY::Tarray || tb->ty == TY::Tsarray);
/* Use convert-to-dynamic-array code if possible. */
if (!e->lwr)
{
tree result = build_expr (e->e1);
- if (e->e1->type->toBasetype ()->ty == Tsarray)
+ if (e->e1->type->toBasetype ()->ty == TY::Tsarray)
result = convert_expr (result, e->e1->type, e->type);
this->result_ = result;
@@ -1386,7 +1368,7 @@ public:
/* Our array is already a SAVE_EXPR if necessary, so we don't make length
a SAVE_EXPR which is, at most, a COMPONENT_REF on top of array. */
- if (tb1->ty != Tpointer)
+ if (tb1->ty != TY::Tpointer)
length = get_array_length (array, tb1);
else
gcc_assert (e->lengthVar == NULL);
@@ -1415,13 +1397,13 @@ public:
/* Nothing more to do for static arrays, their bounds checking has been
done at compile-time. */
- if (tb->ty == Tsarray)
+ if (tb->ty == TY::Tsarray)
{
this->result_ = indirect_ref (build_ctype (e->type), ptr);
return;
}
else
- gcc_assert (tb->ty == Tarray);
+ gcc_assert (tb->ty == TY::Tarray);
/* Generate bounds checking code. */
tree newlength = build_bounds_slice_condition (e, lwr_tree, upr_tree,
@@ -1440,7 +1422,7 @@ public:
tree result = build_expr (e->e1, this->constp_, this->literalp_);
/* Just evaluate e1 if it has any side effects. */
- if (tbtype->ty == Tvoid)
+ if (tbtype->ty == TY::Tvoid)
this->result_ = build_nop (build_ctype (tbtype), result);
else
this->result_ = convert_for_rvalue (result, ebtype, tbtype);
@@ -1453,7 +1435,7 @@ public:
tree t1 = build_expr (e->e1);
Type *tb1 = e->e1->type->toBasetype ();
- if (tb1->ty == Tclass)
+ if (tb1->ty == TY::Tclass)
{
/* For class object references, if there is a destructor for that class,
the destructor is called for the object instance. */
@@ -1480,7 +1462,7 @@ public:
t1 = build_address (t1);
this->result_ = build_libcall (libcall, Type::tvoid, 1, t1);
}
- else if (tb1->ty == Tarray)
+ else if (tb1->ty == TY::Tarray)
{
/* For dynamic arrays, the garbage collector is called to immediately
release the memory. */
@@ -1498,7 +1480,7 @@ public:
this->result_ = build_libcall (LIBCALL_DELARRAYT, Type::tvoid, 2,
build_address (t1), ti);
}
- else if (tb1->ty == Tpointer)
+ else if (tb1->ty == TY::Tpointer)
{
/* For pointers to a struct instance, if the struct has overloaded
operator delete, then that operator is called. */
@@ -1533,7 +1515,7 @@ public:
void visit (RemoveExp *e)
{
/* Check that the array is actually an associative array. */
- if (e->e1->type->toBasetype ()->ty == Taarray)
+ if (e->e1->type->toBasetype ()->ty == TY::Taarray)
{
Type *tb = e->e1->type->toBasetype ();
Type *tkey = tb->isTypeAArray ()->index->toBasetype ();
@@ -1569,7 +1551,7 @@ public:
void visit (ComExp *e)
{
TY ty1 = e->e1->type->toBasetype ()->ty;
- gcc_assert (ty1 != Tarray && ty1 != Tsarray);
+ gcc_assert (ty1 != TY::Tarray && ty1 != TY::Tsarray);
this->result_ = fold_build1 (BIT_NOT_EXPR, build_ctype (e->type),
build_expr (e->e1));
@@ -1580,7 +1562,7 @@ public:
void visit (NegExp *e)
{
TY ty1 = e->e1->type->toBasetype ()->ty;
- gcc_assert (ty1 != Tarray && ty1 != Tsarray);
+ gcc_assert (ty1 != TY::Tarray && ty1 != TY::Tsarray);
tree type = build_ctype (e->type);
tree expr = build_expr (e->e1);
@@ -1630,7 +1612,7 @@ public:
/* Produce better code by converting *(#record + n) to
COMPONENT_REFERENCE. Otherwise, the variable will always be
allocated in memory because its address is taken. */
- if (tnext && tnext->ty == Tstruct)
+ if (tnext && tnext->ty == TY::Tstruct)
{
StructDeclaration *sd = tnext->isTypeStruct ()->sym;
@@ -1716,7 +1698,7 @@ public:
gcc_assert (var->isFuncDeclaration () && !var->needThis ());
}
- if (e1b->op == TOKdotvar && tb->ty != Tdelegate)
+ if (e1b->op == TOKdotvar && tb->ty != TY::Tdelegate)
{
DotVarExp *dve = e1b->isDotVarExp ();
@@ -1775,7 +1757,7 @@ public:
/* C++ constructors return void, even though front-end semantic
treats them as implicitly returning `this'. Set returnvalue
to override the result of this expression. */
- if (fd->isCtorDeclaration () && fd->linkage == LINKcpp)
+ if (fd->isCtorDeclaration () && fd->linkage == LINK::cpp)
{
thisexp = d_save_expr (thisexp);
returnvalue = thisexp;
@@ -1805,7 +1787,7 @@ public:
extract_from_method_call (callee, callee, object);
}
- else if (tb->ty == Tdelegate)
+ else if (tb->ty == TY::Tdelegate)
{
/* Delegate call, extract .object and .funcptr from var. */
callee = d_save_expr (callee);
@@ -1850,7 +1832,7 @@ public:
if (returnvalue != NULL_TREE)
exp = compound_expr (exp, returnvalue);
- if (tf->isref)
+ if (tf->isref ())
exp = build_deref (exp);
/* Some library calls are defined to return a generic type.
@@ -1888,7 +1870,7 @@ public:
tree fndecl;
tree object;
- if (e->func->isNested ())
+ if (e->func->isNested () && !e->func->isThis ())
{
if (e->e1->op == TOKnull)
object = build_expr (e->e1);
@@ -1909,12 +1891,12 @@ public:
object = build_expr (e->e1);
/* Want reference to `this' object. */
- if (e->e1->type->ty != Tclass && e->e1->type->ty != Tpointer)
+ if (e->e1->type->ty != TY::Tclass && e->e1->type->ty != TY::Tpointer)
object = build_address (object);
/* Object reference could be the outer `this' field of a class or
closure of type `void*'. Cast it to the right type. */
- if (e->e1->type->ty == Tclass)
+ if (e->e1->type->ty == TY::Tclass)
object = d_convert (build_ctype (e->e1->type), object);
fndecl = get_symbol_decl (e->func);
@@ -1958,7 +1940,7 @@ public:
{
tree object = build_expr (e->e1);
- if (e->e1->type->toBasetype ()->ty != Tstruct)
+ if (e->e1->type->toBasetype ()->ty != TY::Tstruct)
object = build_deref (object);
this->result_ = component_ref (object, get_symbol_decl (vd));
@@ -2005,7 +1987,7 @@ public:
{
/* If the condition is a D class or struct object with an invariant,
call it if the condition result is true. */
- if (tb1->ty == Tclass)
+ if (tb1->ty == TY::Tclass)
{
ClassDeclaration *cd = tb1->isClassHandle ();
if (!cd->isInterfaceDeclaration () && !cd->isCPPclass ())
@@ -2015,7 +1997,8 @@ public:
Type::tvoid, 1, arg);
}
}
- else if (tb1->ty == Tpointer && tb1->nextOf ()->ty == Tstruct)
+ else if (tb1->ty == TY::Tpointer
+ && tb1->nextOf ()->ty == TY::Tstruct)
{
StructDeclaration *sd = tb1->nextOf ()->isTypeStruct ()->sym;
if (sd->inv != NULL)
@@ -2093,7 +2076,7 @@ public:
else if (Expression *tid = isExpression (e->obj))
{
Type *type = tid->type->toBasetype ();
- assert (type->ty == Tclass);
+ assert (type->ty == TY::Tclass);
/* Generate **classptr to get the classinfo. */
tree ci = build_expr (tid);
@@ -2117,7 +2100,7 @@ public:
Type *ftype = e->type->toBasetype ();
/* This check is for lambda's, remove `vthis' as function isn't nested. */
- if (e->fd->tok == TOKreserved && ftype->ty == Tpointer)
+ if (e->fd->tok == TOKreserved && ftype->ty == TY::Tpointer)
{
e->fd->tok = TOKfunction;
e->fd->vthis = NULL;
@@ -2226,7 +2209,7 @@ public:
tree init = NULL_TREE;
if (var && (var->isConst () || var->isImmutable ())
- && e->type->toBasetype ()->ty != Tsarray && var->_init)
+ && e->type->toBasetype ()->ty != TY::Tsarray && var->_init)
{
if (var->inuse)
error_at (make_location_t (e->loc), "recursive reference %qs",
@@ -2279,7 +2262,7 @@ public:
result = get_decl_tree (fd->vthis);
}
- if (e->type->ty == Tstruct)
+ if (e->type->ty == TY::Tstruct)
result = build_deref (result);
this->result_ = result;
@@ -2293,10 +2276,7 @@ public:
Type *tb = e->type->toBasetype ();
tree result;
- if (e->allocator)
- gcc_assert (e->newargs);
-
- if (tb->ty == Tclass)
+ if (tb->ty == TY::Tclass)
{
/* Allocating a new class. */
tb = e->newtype->toBasetype ();
@@ -2315,20 +2295,13 @@ public:
new_call = build_nop (type, build_address (var));
setup_exp = modify_expr (var, aggregate_initializer_decl (cd));
}
- else if (e->allocator)
- {
- /* Call class allocator, and copy the initializer into memory. */
- new_call = d_build_call_expr (e->allocator, NULL_TREE, e->newargs);
- new_call = d_save_expr (new_call);
- new_call = build_nop (type, new_call);
- setup_exp = modify_expr (build_deref (new_call),
- aggregate_initializer_decl (cd));
- }
else
{
/* Generate: _d_newclass() */
tree arg = build_address (get_classinfo_decl (cd));
- new_call = build_libcall (LIBCALL_NEWCLASS, tb, 1, arg);
+ libcall_fn libcall = (global.params.ehnogc && e->thrownew)
+ ? LIBCALL_NEWTHROW : LIBCALL_NEWCLASS;
+ new_call = build_libcall (libcall, tb, 1, arg);
}
/* Set the context pointer for nested classes. */
@@ -2340,13 +2313,15 @@ public:
if (e->thisexp)
{
ClassDeclaration *tcd = e->thisexp->type->isClassHandle ();
- Dsymbol *outer = cd->toParent2 ();
- int offset = 0;
+ /* The class or function we're nested in. */
+ Dsymbol *outer = cd->toParentLocal ();
value = build_expr (e->thisexp);
+
if (outer != tcd)
{
ClassDeclaration *ocd = outer->isClassDeclaration ();
+ int offset = 0;
gcc_assert (ocd->isBaseOf (tcd, &offset));
/* Could just add offset... */
value = convert_expr (value, e->thisexp->type, ocd->type);
@@ -2375,7 +2350,8 @@ public:
if (e->argprefix)
result = compound_expr (build_expr (e->argprefix), result);
}
- else if (tb->ty == Tpointer && tb->nextOf ()->toBasetype ()->ty == Tstruct)
+ else if (tb->ty == TY::Tpointer
+ && tb->nextOf ()->toBasetype ()->ty == TY::Tstruct)
{
/* Allocating memory for a new struct. */
Type *htype = e->newtype->toBasetype ();
@@ -2393,20 +2369,11 @@ public:
return;
}
- if (e->allocator)
- {
- /* Call struct allocator. */
- new_call = d_build_call_expr (e->allocator, NULL_TREE, e->newargs);
- new_call = build_nop (build_ctype (tb), new_call);
- }
- else
- {
- /* Generate: _d_newitemT() */
- libcall_fn libcall = htype->isZeroInit ()
- ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT;
- tree arg = build_typeinfo (e->loc, e->newtype);
- new_call = build_libcall (libcall, tb, 1, arg);
- }
+ /* Generate: _d_newitemT() */
+ libcall_fn libcall = htype->isZeroInit ()
+ ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT;
+ tree arg = build_typeinfo (e->loc, e->newtype);
+ new_call = build_libcall (libcall, tb, 1, arg);
if (e->member || !e->arguments)
{
@@ -2449,13 +2416,12 @@ public:
if (e->argprefix)
result = compound_expr (build_expr (e->argprefix), result);
}
- else if (tb->ty == Tarray)
+ else if (tb->ty == TY::Tarray)
{
/* Allocating memory for a new D array. */
tb = e->newtype->toBasetype ();
TypeDArray *tarray = tb->isTypeDArray ();
- gcc_assert (!e->allocator);
gcc_assert (e->arguments && e->arguments->length >= 1);
if (e->arguments->length == 1)
@@ -2492,7 +2458,7 @@ public:
Expression *arg = (*e->arguments)[i];
CONSTRUCTOR_APPEND_ELT (elms, size_int (i), build_expr (arg));
- gcc_assert (telem->ty == Tarray);
+ gcc_assert (telem->ty == TY::Tarray);
telem = telem->toBasetype ()->nextOf ();
gcc_assert (telem);
}
@@ -2517,7 +2483,7 @@ public:
if (e->argprefix)
result = compound_expr (build_expr (e->argprefix), result);
}
- else if (tb->ty == Tpointer)
+ else if (tb->ty == TY::Tpointer)
{
/* Allocating memory for a new pointer. */
TypePointer *tpointer = tb->isTypePointer ();
@@ -2576,15 +2542,15 @@ public:
switch (e->type->toBasetype ()->ty)
{
- case Tcomplex32:
+ case TY::Tcomplex32:
tnext = (TypeBasic *) Type::tfloat32;
break;
- case Tcomplex64:
+ case TY::Tcomplex64:
tnext = (TypeBasic *) Type::tfloat64;
break;
- case Tcomplex80:
+ case TY::Tcomplex80:
tnext = (TypeBasic *) Type::tfloat80;
break;
@@ -2605,7 +2571,7 @@ public:
Type *tb = e->type->toBasetype ();
tree type = build_ctype (e->type);
- if (tb->ty == Tsarray)
+ if (tb->ty == TY::Tsarray)
{
/* Turn the string into a constructor for the static array. */
vec <constructor_elt, va_gc> *elms = NULL;
@@ -2635,7 +2601,7 @@ public:
TREE_TYPE (value) = make_array_type (tb->nextOf (), length + 1);
value = build_address (value);
- if (tb->ty == Tarray)
+ if (tb->ty == TY::Tarray)
value = d_array_value (type, size_int (e->len), value);
TREE_CONSTANT (value) = 1;
@@ -2674,15 +2640,16 @@ public:
Type *tb = e->type->toBasetype ();
/* Implicitly convert void[n] to ubyte[n]. */
- if (tb->ty == Tsarray && tb->nextOf ()->toBasetype ()->ty == Tvoid)
+ if (tb->ty == TY::Tsarray && tb->nextOf ()->toBasetype ()->ty == TY::Tvoid)
tb = Type::tuns8->sarrayOf (tb->isTypeSArray ()->dim->toUInteger ());
- gcc_assert (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tpointer);
+ gcc_assert (tb->ty == TY::Tarray || tb->ty == TY::Tsarray
+ || tb->ty == TY::Tpointer);
/* Handle empty array literals. */
if (e->elements->length == 0)
{
- if (tb->ty == Tarray)
+ if (tb->ty == TY::Tarray)
this->result_ = d_array_value (build_ctype (e->type),
size_int (0), null_pointer_node);
else
@@ -2732,15 +2699,15 @@ public:
tree type = build_ctype (e->type);
/* Nothing else to do for static arrays. */
- if (tb->ty == Tsarray || this->constp_)
+ if (tb->ty == TY::Tsarray || this->constp_)
{
/* Can't take the address of the constructor, so create an anonymous
static symbol, and then refer to it. */
- if (tb->ty != Tsarray)
+ if (tb->ty != TY::Tsarray)
{
tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor, "A");
ctor = build_address (decl);
- if (tb->ty == Tarray)
+ if (tb->ty == TY::Tarray)
ctor = d_array_value (type, size_int (e->elements->length), ctor);
d_pushdecl (decl);
@@ -2789,7 +2756,7 @@ public:
/* Return the array pointed to by MEM. */
result = compound_expr (result, mem);
- if (tb->ty == Tarray)
+ if (tb->ty == TY::Tarray)
result = d_array_value (type, size_int (e->elements->length), result);
this->result_ = compound_expr (saved_elems, result);
@@ -2882,7 +2849,7 @@ public:
gcc_assert (e->elements->length <= e->sd->fields.length);
Type *tb = e->type->toBasetype ();
- gcc_assert (tb->ty == Tstruct);
+ gcc_assert (tb->ty == TY::Tstruct);
for (size_t i = 0; i < e->elements->length; i++)
{
@@ -2895,7 +2862,7 @@ public:
Type *ftype = field->type->toBasetype ();
tree value = NULL_TREE;
- if (ftype->ty == Tsarray && !same_type_p (type, ftype))
+ if (ftype->ty == TY::Tsarray && !same_type_p (type, ftype))
{
/* Initialize a static array with a single element. */
tree elem = build_expr (exp, this->constp_, true);
@@ -3126,7 +3093,7 @@ build_return_dtor (Expression *e, Type *type, TypeFunction *tf)
tree result = build_expr (e);
/* Convert for initializing the DECL_RESULT. */
- if (tf->isref)
+ if (tf->isref ())
{
/* If we are returning a reference, take the address. */
result = convert_expr (result, e->type, type);
diff --git a/gcc/d/imports.cc b/gcc/d/imports.cc
index 2288843..740a020 100644
--- a/gcc/d/imports.cc
+++ b/gcc/d/imports.cc
@@ -68,7 +68,7 @@ public:
void visit (Module *m)
{
Loc loc = (m->md != NULL) ? m->md->loc
- : Loc (m->srcfile->toChars (), 1, 0);
+ : Loc (m->srcfile.toChars (), 1, 0);
m->isym = build_decl (make_location_t (loc), NAMESPACE_DECL,
get_identifier (m->toPrettyChars ()),
@@ -130,11 +130,11 @@ public:
/* Type imports should really be part of their own visit method. */
if (type != NULL)
{
- if (type->ty == Tenum)
+ if (type->ty == TY::Tenum)
dsym = type->isTypeEnum ()->sym;
- else if (type->ty == Tstruct)
+ else if (type->ty == TY::Tstruct)
dsym = type->isTypeStruct ()->sym;
- else if (type->ty == Tclass)
+ else if (type->ty == TY::Tclass)
dsym = type->isTypeClass ()->sym;
}
}
diff --git a/gcc/d/intrinsics.cc b/gcc/d/intrinsics.cc
index 539dc0c..b14b0ca 100644
--- a/gcc/d/intrinsics.cc
+++ b/gcc/d/intrinsics.cc
@@ -20,9 +20,9 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "dmd/declaration.h"
+#include "dmd/expression.h"
#include "dmd/identifier.h"
#include "dmd/mangle.h"
-#include "dmd/mangle.h"
#include "dmd/module.h"
#include "dmd/template.h"
@@ -76,12 +76,12 @@ static const intrinsic_decl intrinsic_decls[] =
void
maybe_set_intrinsic (FuncDeclaration *decl)
{
- if (!decl->ident || decl->builtin != BUILTINunknown)
+ if (!decl->ident || decl->builtin != BUILTIN::unknown)
return;
/* The builtin flag is updated only if we can evaluate the intrinsic
at compile-time. Such as the math or bitop intrinsics. */
- decl->builtin = BUILTINunimp;
+ decl->builtin = BUILTIN::unimp;
/* Check if it's a compiler intrinsic. We only require that any
internally recognised intrinsics are declared in a module with
@@ -177,12 +177,12 @@ maybe_set_intrinsic (FuncDeclaration *decl)
built-in function. It could be `int pow(int, int)'. */
tree rettype = TREE_TYPE (TREE_TYPE (decl->csym));
if (mathfn_built_in (rettype, BUILT_IN_POW) != NULL_TREE)
- decl->builtin = BUILTINgcc;
+ decl->builtin = BUILTIN::gcc;
break;
}
default:
- decl->builtin = BUILTINgcc;
+ decl->builtin = BUILTIN::gcc;
break;
}
diff --git a/gcc/d/intrinsics.def b/gcc/d/intrinsics.def
index f5af2a5..1f350f3 100644
--- a/gcc/d/intrinsics.def
+++ b/gcc/d/intrinsics.def
@@ -77,12 +77,12 @@ DEF_D_BUILTIN (INTRINSIC_POPCNT32, BUILT_IN_NONE, "popcnt", "core.bitop",
DEF_D_BUILTIN (INTRINSIC_POPCNT64, BUILT_IN_NONE, "popcnt", "core.bitop",
"FNaNbNiNfmZi")
-DEF_D_BUILTIN (INTRINSIC_ROL, BUILT_IN_NONE, "rol", "core.bitop", "FNaI1TkZI1T")
+DEF_D_BUILTIN (INTRINSIC_ROL, BUILT_IN_NONE, "rol", "core.bitop", "FNa@1TkZ@1T")
DEF_D_BUILTIN (INTRINSIC_ROL_TIARG, BUILT_IN_NONE, "rol", "core.bitop",
- "FNaI1TZI1T")
-DEF_D_BUILTIN (INTRINSIC_ROR, BUILT_IN_NONE, "ror", "core.bitop", "FNaI1TkZI1T")
+ "FNa@1TZ@1T")
+DEF_D_BUILTIN (INTRINSIC_ROR, BUILT_IN_NONE, "ror", "core.bitop", "FNa@1TkZ@1T")
DEF_D_BUILTIN (INTRINSIC_ROR_TIARG, BUILT_IN_NONE, "ror", "core.bitop",
- "FNaI1TZI1T")
+ "FNa@1TZ@1T")
/* core.volatile intrinsics. */
@@ -183,75 +183,74 @@ DEF_D_BUILTIN (INTRINSIC_SQRT, BUILT_IN_SQRT, "sqrt", "core.math",
DEF_D_BUILTIN (INTRINSIC_SQRTL, BUILT_IN_SQRTL, "sqrt", "core.math",
"FNaNbNiNfeZe")
DEF_D_BUILTIN (INTRINSIC_TOPRECF, BUILT_IN_NONE, "toPrec", "core.math",
- "FfZI1T")
-DEF_D_BUILTIN (INTRINSIC_TOPREC, BUILT_IN_NONE, "toPrec", "core.math", "FdZI1T")
+ "FfZ@1T")
+DEF_D_BUILTIN (INTRINSIC_TOPREC, BUILT_IN_NONE, "toPrec", "core.math", "FdZ@1T")
DEF_D_BUILTIN (INTRINSIC_TOPRECL, BUILT_IN_NONE, "toPrec", "core.math",
- "FeZI1T")
+ "FeZ@1T")
/* std.math intrinsics. */
-DEF_CTFE_BUILTIN (INTRINSIC_TAN, BUILT_IN_TANL, "tan", "std.math",
+DEF_CTFE_BUILTIN (INTRINSIC_TAN, BUILT_IN_TANL, "tan", "std.math.trigonometry",
"FNaNbNiNeeZe")
-DEF_CTFE_BUILTIN (INTRINSIC_ISNAN, BUILT_IN_ISNAN, "isNaN", "std.math",
- "FNaNbNiNeI1XZb")
+
+DEF_CTFE_BUILTIN (INTRINSIC_ISNAN, BUILT_IN_ISNAN, "isNaN", "std.math.traits",
+ "FNaNbNiNe@1XZb")
DEF_CTFE_BUILTIN (INTRINSIC_ISINFINITY, BUILT_IN_ISINF, "isInfinity",
- "std.math", "FNaNbNiNeI1XZb")
-DEF_CTFE_BUILTIN (INTRINSIC_ISFINITE, BUILT_IN_ISFINITE, "isFinite", "std.math",
- "FNaNbNiNeI1XZb")
+ "std.math.traits", "FNaNbNiNe@1XZb")
+DEF_CTFE_BUILTIN (INTRINSIC_ISFINITE, BUILT_IN_ISFINITE, "isFinite",
+ "std.math.traits", "FNaNbNiNe@1XZb")
+DEF_CTFE_BUILTIN (INTRINSIC_COPYSIGN, BUILT_IN_NONE, "copysign",
+ "std.math.traits", "FNaNbNiNe@1R@1XZ@1R")
+DEF_CTFE_BUILTIN (INTRINSIC_COPYSIGNI, BUILT_IN_NONE, "copysign",
+ "std.math.traits", "FNaNbNiNe@1X@1RZ@1R")
-DEF_CTFE_BUILTIN (INTRINSIC_EXP, BUILT_IN_EXPL, "exp", "std.math",
- "FNaNbNiNeeZe")
-DEF_CTFE_BUILTIN (INTRINSIC_EXPM1, BUILT_IN_EXPM1L, "expm1", "std.math",
- "FNaNbNiNeeZe")
-DEF_CTFE_BUILTIN (INTRINSIC_EXP2, BUILT_IN_EXP2L, "exp2", "std.math",
+DEF_CTFE_BUILTIN (INTRINSIC_EXP, BUILT_IN_EXPL, "exp", "std.math.exponential",
"FNaNbNiNeeZe")
-
-DEF_CTFE_BUILTIN (INTRINSIC_LOG, BUILT_IN_LOGL, "log", "std.math",
- "FNaNbNiNfeZe")
-DEF_CTFE_BUILTIN (INTRINSIC_LOG2, BUILT_IN_LOG2L, "log2", "std.math",
- "FNaNbNiNfeZe")
-DEF_CTFE_BUILTIN (INTRINSIC_LOG10, BUILT_IN_LOG10L, "log10", "std.math",
+DEF_CTFE_BUILTIN (INTRINSIC_EXPM1, BUILT_IN_EXPM1L, "expm1",
+ "std.math.exponential", "FNaNbNiNeeZe")
+DEF_CTFE_BUILTIN (INTRINSIC_EXP2, BUILT_IN_EXP2L, "exp2",
+ "std.math.exponential", "FNaNbNiNeeZe")
+DEF_CTFE_BUILTIN (INTRINSIC_LOG, BUILT_IN_LOGL, "log", "std.math.exponential",
"FNaNbNiNfeZe")
+DEF_CTFE_BUILTIN (INTRINSIC_LOG2, BUILT_IN_LOG2L, "log2",
+ "std.math.exponential", "FNaNbNiNfeZe")
+DEF_CTFE_BUILTIN (INTRINSIC_LOG10, BUILT_IN_LOG10L, "log10",
+ "std.math.exponential", "FNaNbNiNfeZe")
+DEF_CTFE_BUILTIN (INTRINSIC_POW, BUILT_IN_NONE, "pow", "std.math.exponential",
+ "FNaNbNiNe@1F@1GZ@")
-DEF_CTFE_BUILTIN (INTRINSIC_ROUND, BUILT_IN_ROUNDL, "round", "std.math",
- "FNbNiNeeZe")
-DEF_CTFE_BUILTIN (INTRINSIC_FLOORF, BUILT_IN_FLOORF, "floor", "std.math",
- "FNaNbNiNefZf")
-DEF_CTFE_BUILTIN (INTRINSIC_FLOOR, BUILT_IN_FLOOR, "floor", "std.math",
+DEF_CTFE_BUILTIN (INTRINSIC_ROUND, BUILT_IN_ROUNDL, "round",
+ "std.math.rounding", "FNaNbNiNeeZe")
+DEF_CTFE_BUILTIN (INTRINSIC_FLOORF, BUILT_IN_FLOORF, "floor",
+ "std.math.rounding", "FNaNbNiNefZf")
+DEF_CTFE_BUILTIN (INTRINSIC_FLOOR, BUILT_IN_FLOOR, "floor", "std.math.rounding",
"FNaNbNiNedZd")
-DEF_CTFE_BUILTIN (INTRINSIC_FLOORL, BUILT_IN_FLOORL, "floor", "std.math",
- "FNaNbNiNeeZe")
-DEF_CTFE_BUILTIN (INTRINSIC_CEILF, BUILT_IN_CEILF, "ceil", "std.math",
+DEF_CTFE_BUILTIN (INTRINSIC_FLOORL, BUILT_IN_FLOORL, "floor",
+ "std.math.rounding", "FNaNbNiNeeZe")
+DEF_CTFE_BUILTIN (INTRINSIC_CEILF, BUILT_IN_CEILF, "ceil", "std.math.rounding",
"FNaNbNiNefZf")
-DEF_CTFE_BUILTIN (INTRINSIC_CEIL, BUILT_IN_CEIL, "ceil", "std.math",
+DEF_CTFE_BUILTIN (INTRINSIC_CEIL, BUILT_IN_CEIL, "ceil", "std.math.rounding",
"FNaNbNiNedZd")
-DEF_CTFE_BUILTIN (INTRINSIC_CEILL, BUILT_IN_CEILL, "ceil", "std.math",
+DEF_CTFE_BUILTIN (INTRINSIC_CEILL, BUILT_IN_CEILL, "ceil", "std.math.rounding",
"FNaNbNiNeeZe")
+DEF_CTFE_BUILTIN (INTRINSIC_TRUNC, BUILT_IN_TRUNCL, "trunc",
+ "std.math.rounding", "FNaNbNiNeeZe")
-DEF_CTFE_BUILTIN (INTRINSIC_TRUNC, BUILT_IN_TRUNCL, "trunc", "std.math",
- "FNbNiNeeZe")
-DEF_CTFE_BUILTIN (INTRINSIC_FMIN, BUILT_IN_FMINL, "fmin", "std.math",
+DEF_CTFE_BUILTIN (INTRINSIC_FMIN, BUILT_IN_FMINL, "fmin", "std.math.operations",
"FNaNbNiNfeeZe")
-DEF_CTFE_BUILTIN (INTRINSIC_FMAX, BUILT_IN_FMAXL, "fmax", "std.math",
+DEF_CTFE_BUILTIN (INTRINSIC_FMAX, BUILT_IN_FMAXL, "fmax", "std.math.operations",
"FNaNbNiNfeeZe")
-DEF_CTFE_BUILTIN (INTRINSIC_COPYSIGN, BUILT_IN_NONE, "copysign", "std.math",
- "FNaNbNiNeI1RI1XZI1R")
-DEF_CTFE_BUILTIN (INTRINSIC_COPYSIGNI, BUILT_IN_NONE, "copysign", "std.math",
- "FNaNbNiNeI1XI1RZI1R")
-
-DEF_CTFE_BUILTIN (INTRINSIC_POW, BUILT_IN_NONE, "pow", "std.math",
- "FNaNbNiNeI1FI1GZ@")
-DEF_CTFE_BUILTIN (INTRINSIC_FMA, BUILT_IN_FMAL, "fma", "std.math",
+DEF_CTFE_BUILTIN (INTRINSIC_FMA, BUILT_IN_FMAL, "fma", "std.math.operations",
"FNaNbNiNfeeeZe")
/* core.stdc.stdarg intrinsics. */
DEF_D_BUILTIN (INTRINSIC_VA_ARG, BUILT_IN_NONE, "va_arg", "core.stdc.stdarg",
- "FKI7va_listKI1TZv")
+ "FK@7va_listK@1TZv")
DEF_D_BUILTIN (INTRINSIC_C_VA_ARG, BUILT_IN_NONE, "va_arg", "core.stdc.stdarg",
- "FKI7va_listZI1T")
+ "FK@7va_listZ@1T")
DEF_D_BUILTIN (INTRINSIC_VASTART, BUILT_IN_NONE, "va_start", "core.stdc.stdarg",
- "FJI7va_listKI1TZv")
+ "FJ@7va_listK@1TZv")
#undef DEF_D_BUILTIN
#undef DEF_CTFE_BUILTIN
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
index ded218f..f7f90fb 100644
--- a/gcc/d/lang.opt
+++ b/gcc/d/lang.opt
@@ -209,6 +209,40 @@ fbuiltin
D Var(flag_no_builtin, 0)
; Documented in C
+fcheck=assert
+D Alias(fassert)
+
+fcheck=bounds
+D Alias(fbounds-check)
+
+fcheck=in
+D Alias(fpreconditions)
+
+fcheck=invariant
+D Alias(finvariants)
+
+fcheck=out
+D Alias(fpostconditions)
+
+fcheck=switch
+D Alias(fswitch-errors)
+
+fcheckaction=
+D Joined RejectNegative Enum(check_action) Var(flag_check_action)
+-fcheckaction=[throw,halt,context] Behavior on contract failure.
+
+Enum
+Name(check_action) Type(int) UnknownError(unknown checkaction setting %qs)
+
+EnumValue
+Enum(check_action) String(throw) Value(0)
+
+EnumValue
+Enum(check_action) String(halt) Value(1)
+
+EnumValue
+Enum(check_action) String(context) Value(2)
+
fdebug
D
Compile in debug code.
@@ -237,10 +271,43 @@ fdruntime
D
Assume that standard D runtime libraries and \"D main\" exist.
+fdump-c++-spec-verbose
+D RejectNegative
+Add comments for ignored declarations in the generated C++ header.
+
+fdump-c++-spec=
+D RejectNegative Joined
+-fdump-cxx-spec=<filename> Write all declarations as C++ code to <file>.
+
fdump-d-original
D
Display the frontend AST after parsing and semantic passes.
+fextern-std=
+D Joined RejectNegative Enum(extern_stdcpp) Var(flag_extern_stdcpp)
+-fextern-std=<standard> Set C++ name mangling compatibility with <standard>.
+
+Enum
+Name(extern_stdcpp) Type(int) UnknownError(unknown C++ standard %qs)
+
+EnumValue
+Enum(extern_stdcpp) String(c++98) Value(199711)
+
+EnumValue
+Enum(extern_stdcpp) String(c++03) Value(199711)
+
+EnumValue
+Enum(extern_stdcpp) String(c++11) Value(201103)
+
+EnumValue
+Enum(extern_stdcpp) String(c++14) Value(201402)
+
+EnumValue
+Enum(extern_stdcpp) String(c++17) Value(201703)
+
+EnumValue
+Enum(extern_stdcpp) String(c++20) Value(202002)
+
fignore-unknown-pragmas
D
Ignore unsupported pragmas.
@@ -273,33 +340,97 @@ fpreconditions
D Var(flag_preconditions)
Generate code for precondition contracts.
+fpreview=all
+D RejectNegative
+Turn on all upcoming D language features.
+
+fpreview=dip1000
+D RejectNegative
+Implement DIP1000: Scoped pointers.
+
+fpreview=dip1008
+D RejectNegative
+Implement DIP1008: Allow exceptions in @nogc code.
+
+fpreview=dip1021
+D RejectNegative
+Implement DIP1021: Mutable function arguments.
+
+fpreview=dip25
+D RejectNegative
+Implement DIP25: Sealed references.
+
+fpreview=dtorfields
+D RejectNegative
+Destruct fields of partially constructed objects.
+
+fpreview=fieldwise
+D RejectNegative
+Use field-wise comparisons for struct equality.
+
+fpreview=fixaliasthis
+D RejectNegative
+When a symbol is resolved, check alias this scope before going to upper scopes.
+
+fpreview=in
+D RejectNegative
+Implement 'in' parameters to mean scope const.
+
+fpreview=inclusiveincontracts
+D RejectNegative
+Implement 'in' contracts of overridden methods to be a superset of parent contract.
+
+fpreview=intpromote
+D RejectNegative
+Use C-style integral promotion for unary '+', '-' and '~'.
+
+fpreview=nosharedaccess
+D RejectNegative
+Disable access to shared memory objects.
+
+fpreview=rvaluerefparam
+D RejectNegative
+Enable rvalue arguments to ref parameters.
+
+fpreview=shortenedmethods
+D RejectNegative
+Allow use of '=>' for methods and top-level functions in addition to lambdas.
+
frelease
D
Compile release version.
+frevert=all
+D RejectNegative
+Turn off all revertable D language features.
+
+frevert=dip25
+D RejectNegative
+Revert DIP25: Sealed references.
+
+frevert=dtorfields
+D RejectNegative
+Don't destruct fields of partially constructed objects.
+
+frevert=markdown
+D RejectNegative
+Disable Markdown replacements in Ddoc.
+
frtti
D
; Documented in C
+fsave-mixins=
+D Joined RejectNegative
+-fsave-mixins=<filename> Expand and save mixins to file specified by <filename>.
+
fswitch-errors
D Var(flag_switch_errors)
Generate code for switches without a default case.
ftransition=all
D RejectNegative
-List information on all language changes.
-
-ftransition=complex
-D RejectNegative
-List all usages of complex or imaginary types.
-
-ftransition=dip1000
-D RejectNegative
-Implement DIP1000: Scoped pointers (experimental).
-
-ftransition=dip25
-D RejectNegative
-Implement DIP25: Sealed references (experimental).
+List information on all D language transitions.
ftransition=field
D RejectNegative
@@ -309,10 +440,18 @@ ftransition=nogc
D RejectNegative
List all hidden GC allocations.
+ftransition=templates
+D RejectNegative
+List statistics on template instantiations.
+
ftransition=tls
D RejectNegative
List all variables going into thread local storage.
+ftransition=vmarkdown
+D RejectNegative
+List instances of Markdown replacements in Ddoc.
+
funittest
D
Compile in unittest code.
diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc
index 8786344..06eb5ae 100644
--- a/gcc/d/modules.cc
+++ b/gcc/d/modules.cc
@@ -125,7 +125,7 @@ static Module *current_module_decl;
by both module initialization and dso handlers. */
static FuncDeclaration *
-get_internal_fn (tree ident, const Prot &prot)
+get_internal_fn (tree ident, const Visibility &visibility)
{
Module *mod = current_module_decl;
const char *name = IDENTIFIER_POINTER (ident);
@@ -142,9 +142,9 @@ get_internal_fn (tree ident, const Prot &prot)
FuncDeclaration *fd = FuncDeclaration::genCfunc (NULL, Type::tvoid,
Identifier::idPool (name));
fd->generated = true;
- fd->loc = Loc (mod->srcfile->toChars (), 1, 0);
+ fd->loc = Loc (mod->srcfile.toChars (), 1, 0);
fd->parent = mod;
- fd->protection = prot;
+ fd->visibility = visibility;
fd->semanticRun = PASSsemantic3done;
return fd;
@@ -156,7 +156,9 @@ get_internal_fn (tree ident, const Prot &prot)
static tree
build_internal_fn (tree ident, tree expr)
{
- FuncDeclaration *fd = get_internal_fn (ident, Prot (Prot::private_));
+ Visibility visibility;
+ visibility.kind = Visibility::private_;
+ FuncDeclaration *fd = get_internal_fn (ident, visibility);
tree decl = get_symbol_decl (fd);
tree old_context = start_function (fd);
@@ -338,8 +340,9 @@ build_dso_cdtor_fn (bool ctor_p)
}
}
*/
- FuncDeclaration *fd = get_internal_fn (get_identifier (name),
- Prot (Prot::public_));
+ Visibility visibility;
+ visibility.kind = Visibility::public_;
+ FuncDeclaration *fd = get_internal_fn (get_identifier (name), visibility);
tree decl = get_symbol_decl (fd);
TREE_PUBLIC (decl) = 1;
@@ -740,7 +743,8 @@ build_module_tree (Module *decl)
/* Associate the module info symbol with a mock module. */
const char *name = concat (GDC_PREFIX ("modtest__"),
decl->ident->toChars (), NULL);
- Module *tm = Module::create (decl->arg, Identifier::idPool (name), 0, 0);
+ Module *tm = Module::create (decl->arg.ptr, Identifier::idPool (name),
+ 0, 0);
Dsymbols members;
/* Setting parent puts module in the same package as the current, to
@@ -780,9 +784,7 @@ build_module_tree (Module *decl)
/* Default behavior is to always generate module info because of templates.
Can be switched off for not compiling against runtime library. */
- if (global.params.useModuleInfo
- && Module::moduleinfo != NULL
- && decl->ident != Identifier::idPool ("__entrypoint"))
+ if (global.params.useModuleInfo && Module::moduleinfo != NULL)
{
if (mi.ctors || mi.ctorgates)
decl->sctor = build_funcs_gates_fn (get_identifier ("*__modctor"),
diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def
index 0296233..fdff6db 100644
--- a/gcc/d/runtime.def
+++ b/gcc/d/runtime.def
@@ -34,6 +34,8 @@ along with GCC; see the file COPYING3. If not see
3, LCT_ ## T1, LCT_ ## T2, LCT_ ## T3
#define P4(T1, T2, T3, T4) \
4, LCT_ ## T1, LCT_ ## T2, LCT_ ## T3, LCT_ ## T4
+#define P5(T1, T2, T3, T4, T5) \
+ 5, LCT_ ## T1, LCT_ ## T2, LCT_ ## T3, LCT_ ## T4, LCT_ ## T5
#define RT(T1) LCT_ ## T1
/* Used when an assert() contract fails. */
@@ -51,9 +53,15 @@ DEF_D_RUNTIME (UNITTEST_MSG, "_d_unittest_msg", RT(VOID),
/* Used when an array index outside the bounds of its range. */
DEF_D_RUNTIME (ARRAYBOUNDSP, "_d_arrayboundsp", RT(VOID),
P2(IMMUTABLE_CHARPTR, UINT), ECF_NORETURN)
+DEF_D_RUNTIME (ARRAYBOUNDS_SLICEP, "_d_arraybounds_slicep", RT(VOID),
+ P5(IMMUTABLE_CHARPTR, UINT, SIZE_T, SIZE_T, SIZE_T),
+ ECF_NORETURN)
+DEF_D_RUNTIME (ARRAYBOUNDS_INDEXP, "_d_arraybounds_indexp", RT(VOID),
+ P4(IMMUTABLE_CHARPTR, UINT, SIZE_T, SIZE_T), ECF_NORETURN)
/* Used when calling new on a class. */
DEF_D_RUNTIME (NEWCLASS, "_d_newclass", RT(OBJECT), P1(CONST_CLASSINFO), 0)
+DEF_D_RUNTIME (NEWTHROW, "_d_newThrowable", RT(OBJECT), P1(CONST_CLASSINFO), 0)
/* Used when calling delete on a class or interface. */
DEF_D_RUNTIME (DELCLASS, "_d_delclass", RT(VOID), P1(VOIDPTR), 0)
@@ -104,13 +112,6 @@ DEF_D_RUNTIME (DELARRAYT, "_d_delarray_t", RT(VOID),
arrays. Such as an array of structs or classes. */
DEF_D_RUNTIME (ADEQ2, "_adEq2", RT(INT),
P3(ARRAY_VOID, ARRAY_VOID, CONST_TYPEINFO), 0)
-DEF_D_RUNTIME (ADCMP2, "_adCmp2", RT(INT),
- P3(ARRAY_VOID, ARRAY_VOID, CONST_TYPEINFO), 0)
-
-/* Used when casting from one array type to another where the index type
- sizes differ. Such as from int[] to short[]. */
-DEF_D_RUNTIME (ARRAYCAST, "_d_arraycast", RT(ARRAY_VOID),
- P3(SIZE_T, SIZE_T, ARRAY_VOID), 0)
/* Used for (array.length = n) expressions. The `i' variant is for when the
initializer is nonzero. */
@@ -206,23 +207,10 @@ DEF_D_RUNTIME (CXA_END_CATCH, "__cxa_end_catch", RT(VOID), P0(), 0)
DEF_D_RUNTIME (INVARIANT, "_D9invariant12_d_invariantFC6ObjectZv", RT(VOID),
P1(OBJECT), 0)
-/* Used when performing a switch/cases on a string. The `u' and `d' variants
- are for UTF-16 and UTF-32 strings respectively. */
-DEF_D_RUNTIME (SWITCH_STRING, "_d_switch_string", RT(INT),
- P2(ARRAY_STRING, STRING), 0)
-DEF_D_RUNTIME (SWITCH_USTRING, "_d_switch_ustring", RT(INT),
- P2(ARRAY_WSTRING, WSTRING), 0)
-DEF_D_RUNTIME (SWITCH_DSTRING, "_d_switch_dstring", RT(INT),
- P2(ARRAY_DSTRING, DSTRING), 0)
-
-/* Used when throwing an error that a switch statement has no default case,
- and yet none of the existing cases matched. */
-DEF_D_RUNTIME (SWITCH_ERROR, "_d_switch_error", RT(VOID), P2(STRING, UINT),
- ECF_NORETURN)
-
#undef P0
#undef P1
#undef P2
#undef P3
#undef P4
+#undef P5
#undef RT
diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc
index 1c9da10..55d63f8 100644
--- a/gcc/d/toir.cc
+++ b/gcc/d/toir.cc
@@ -413,18 +413,6 @@ public:
else
error_at (location, "cannot %<goto%> into %<catch%> block");
}
- else if (s->isCaseStatement ())
- {
- location = make_location_t (s->loc);
- error_at (location, "case cannot be in different "
- "%<try%> block level from %<switch%>");
- }
- else if (s->isDefaultStatement ())
- {
- location = make_location_t (s->loc);
- error_at (location, "default cannot be in different "
- "%<try%> block level from %<switch%>");
- }
else
gcc_unreachable ();
}
@@ -709,7 +697,8 @@ public:
{
/* The break label may actually be some levels up.
eg: on a try/finally wrapping a loop. */
- LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
+ LabelDsymbol *sym = this->func_->searchLabel (s->ident, s->loc);
+ LabelStatement *label = sym->statement;
gcc_assert (label != NULL);
Statement *stmt = label->statement->getRelatedLabeled ();
this->do_jump (this->lookup_bc_label (stmt, bc_break));
@@ -725,7 +714,8 @@ public:
{
if (s->ident)
{
- LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
+ LabelDsymbol *sym = this->func_->searchLabel (s->ident, s->loc);
+ LabelStatement *label = sym->statement;
gcc_assert (label != NULL);
this->do_jump (this->lookup_bc_label (label->statement,
bc_continue));
@@ -759,7 +749,7 @@ public:
if (this->is_return_label (s->ident))
sym = this->func_->returnLabel;
else
- sym = this->func_->searchLabel (s->ident);
+ sym = this->func_->searchLabel (s->ident, s->loc);
/* If no label found, there was an error. */
tree label = this->define_label (sym->statement, sym->ident);
@@ -784,69 +774,9 @@ public:
tree condition = build_expr_dtor (s->condition);
Type *condtype = s->condition->type->toBasetype ();
- /* A switch statement on a string gets turned into a library call,
- which does a binary lookup on list of string cases. */
- if (s->condition->type->isString ())
- {
- Type *etype = condtype->nextOf ()->toBasetype ();
- libcall_fn libcall;
-
- switch (etype->ty)
- {
- case Tchar:
- libcall = LIBCALL_SWITCH_STRING;
- break;
-
- case Twchar:
- libcall = LIBCALL_SWITCH_USTRING;
- break;
-
- case Tdchar:
- libcall = LIBCALL_SWITCH_DSTRING;
- break;
-
- default:
- ::error ("switch statement value must be an array of "
- "some character type, not %s", etype->toChars ());
- gcc_unreachable ();
- }
-
- /* Apparently the backend is supposed to sort and set the indexes
- on the case array, have to change them to be usable. */
- Type *satype = condtype->sarrayOf (s->cases->length);
- vec <constructor_elt, va_gc> *elms = NULL;
-
- s->cases->sort ();
-
- for (size_t i = 0; i < s->cases->length; i++)
- {
- CaseStatement *cs = (*s->cases)[i];
- cs->index = i;
-
- if (cs->exp->op != TOKstring)
- s->error ("case '%s' is not a string", cs->exp->toChars ());
- else
- {
- tree exp = build_expr (cs->exp, true);
- CONSTRUCTOR_APPEND_ELT (elms, size_int (i), exp);
- }
- }
-
- /* Build static declaration to reference constructor. */
- tree ctor = build_constructor (build_ctype (satype), elms);
- tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor);
- TREE_READONLY (decl) = 1;
- d_pushdecl (decl);
- rest_of_decl_compilation (decl, 1, 0);
-
- /* Pass it as a dynamic array. */
- decl = d_array_value (build_ctype (condtype->arrayOf ()),
- size_int (s->cases->length),
- build_address (decl));
-
- condition = build_libcall (libcall, Type::tint32, 2, decl, condition);
- }
- else if (!condtype->isscalar ())
+ /* A switch statement on a string gets turned into a library call.
+ It is not lowered during codegen. */
+ if (!condtype->isscalar ())
{
error ("cannot handle switch condition of type %s",
condtype->toChars ());
@@ -992,7 +922,10 @@ public:
void visit (SwitchErrorStatement *s)
{
- add_stmt (build_assert_call (s->loc, LIBCALL_SWITCH_ERROR));
+ /* A throw SwitchError statement gets turned into a library call.
+ The call is wrapped in the enclosed expression. */
+ gcc_assert (s->exp != NULL);
+ add_stmt (build_expr (s->exp));
}
/* A return statement exits the current function and supplies its return
@@ -1000,7 +933,7 @@ public:
void visit (ReturnStatement *s)
{
- if (s->exp == NULL || s->exp->type->toBasetype ()->ty == Tvoid)
+ if (s->exp == NULL || s->exp->type->toBasetype ()->ty == TY::Tvoid)
{
/* Return has no value. */
add_stmt (return_expr (NULL_TREE));
@@ -1012,7 +945,7 @@ public:
? this->func_->tintro->nextOf () : tf->nextOf ();
if ((this->func_->isMain () || this->func_->isCMain ())
- && type->toBasetype ()->ty == Tvoid)
+ && type->toBasetype ()->ty == TY::Tvoid)
type = Type::tint32;
if (this->func_->shidden)
@@ -1020,7 +953,7 @@ public:
/* Returning by hidden reference, store the result into the retval decl.
The result returned then becomes the retval reference itself. */
tree decl = DECL_RESULT (get_symbol_decl (this->func_));
- gcc_assert (!tf->isref);
+ gcc_assert (!tf->isref ());
/* If returning via NRVO, just refer to the DECL_RESULT; this differs
from using NULL_TREE in that it indicates that we care about the
@@ -1096,7 +1029,7 @@ public:
add_stmt (return_expr (decl));
}
- else if (tf->next->ty == Tnoreturn)
+ else if (tf->next->ty == TY::Tnoreturn)
{
/* Returning an expression that has no value, but has a side effect
that should never return. */
@@ -1514,7 +1447,7 @@ public:
/* If the function has been annotated with `pragma(inline)', then mark
the asm expression as being inline as well. */
- if (this->func_->inlining == PINLINEalways)
+ if (this->func_->inlining == PINLINE::always)
ASM_INLINE_P (exp) = 1;
add_stmt (exp);
diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc
index fd8c746..065f6b3 100644
--- a/gcc/d/typeinfo.cc
+++ b/gcc/d/typeinfo.cc
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
#include "stor-layout.h"
#include "d-tree.h"
+#include "d-frontend.h"
#include "d-target.h"
@@ -110,37 +111,37 @@ get_typeinfo_kind (Type *type)
switch (type->ty)
{
- case Tpointer:
+ case TY::Tpointer:
return TK_POINTER_TYPE;
- case Tarray:
+ case TY::Tarray:
return TK_ARRAY_TYPE;
- case Tsarray:
+ case TY::Tsarray:
return TK_STATICARRAY_TYPE;
- case Taarray:
+ case TY::Taarray:
return TK_ASSOCIATIVEARRAY_TYPE;
- case Tstruct:
+ case TY::Tstruct:
return TK_STRUCT_TYPE;
- case Tvector:
+ case TY::Tvector:
return TK_VECTOR_TYPE;
- case Tenum:
+ case TY::Tenum:
return TK_ENUMERAL_TYPE;
- case Tfunction:
+ case TY::Tfunction:
return TK_FUNCTION_TYPE;
- case Tdelegate:
+ case TY::Tdelegate:
return TK_DELEGATE_TYPE;
- case Ttuple:
+ case TY::Ttuple:
return TK_TYPELIST_TYPE;
- case Tclass:
+ case TY::Tclass:
if (type->isTypeClass ()->sym->isInterfaceDeclaration ())
return TK_INTERFACE_TYPE;
else
@@ -216,7 +217,7 @@ make_frontend_typeinfo (Identifier *ident, ClassDeclaration *base = NULL)
= ClassDeclaration::create (loc, Identifier::idPool ("Object"),
NULL, NULL, true);
object->parent = object_module;
- object->members = new Dsymbols;
+ object->members = d_gc_malloc<Dsymbols> ();
object->storage_class |= STCtemp;
}
@@ -228,7 +229,7 @@ make_frontend_typeinfo (Identifier *ident, ClassDeclaration *base = NULL)
ClassDeclaration *tinfo = ClassDeclaration::create (loc, ident, NULL, NULL,
true);
tinfo->parent = object_module;
- tinfo->members = new Dsymbols;
+ tinfo->members = d_gc_malloc<Dsymbols> ();
dsymbolSemantic (tinfo, object_module->_scope);
tinfo->baseClass = base;
/* This is a compiler generated class, and shouldn't be mistaken for being
@@ -836,7 +837,7 @@ public:
/* Name of the class declaration. */
const char *name = cd->ident->toChars ();
if (!(strlen (name) > 9 && memcmp (name, "TypeInfo_", 9) == 0))
- name = cd->toPrettyChars ();
+ name = cd->toPrettyChars (true);
this->layout_string (name);
/* The vtable of the class declaration. */
@@ -857,7 +858,7 @@ public:
this->layout_field (base);
/* void *destructor; */
- tree dtor = (cd->dtor) ? build_address (get_symbol_decl (cd->dtor))
+ tree dtor = (cd->tidtor) ? build_address (get_symbol_decl (cd->tidtor))
: null_pointer_node;
this->layout_field (dtor);
@@ -911,10 +912,7 @@ public:
this->layout_field (build_integer_cst (flags, d_uint_type));
/* void *deallocator; */
- tree ddtor = (cd->aggDelete)
- ? build_address (get_symbol_decl (cd->aggDelete))
- : null_pointer_node;
- this->layout_field (ddtor);
+ this->layout_field (null_pointer_node);
/* OffsetTypeInfo[] m_offTi; (not implemented) */
this->layout_field (null_array_node);
@@ -942,7 +940,7 @@ public:
this->layout_field (null_array_node);
/* Name of the interface declaration. */
- this->layout_string (cd->toPrettyChars ());
+ this->layout_string (cd->toPrettyChars (true));
/* No vtable for interface declaration. */
this->layout_field (null_array_node);
@@ -1024,7 +1022,7 @@ public:
/* Layout of TypeInfo_Struct is:
void **__vptr;
void *__monitor;
- string name;
+ string mangledName;
void[] m_init;
hash_t function(in void*) xtoHash;
bool function(in void*, in void*) xopEquals;
@@ -1047,8 +1045,8 @@ public:
if (!sd->members)
return;
- /* Name of the struct declaration. */
- this->layout_string (sd->toPrettyChars ());
+ /* Mangled name of the struct declaration. */
+ this->layout_string (ti->deco);
/* Default initializer for struct. */
tree ptr = (sd->zeroInit) ? null_pointer_node
@@ -1064,7 +1062,7 @@ public:
if (sd->xhash)
{
TypeFunction *tf = sd->xhash->type->toTypeFunction ();
- if (!tf->isnothrow || tf->trust == TRUSTsystem)
+ if (!tf->isnothrow () || tf->trust == TRUST::system)
{
warning (sd->xhash->loc, "toHash() must be declared as "
"extern (D) size_t toHash() const nothrow @safe, "
@@ -1096,7 +1094,7 @@ public:
this->layout_field (build_integer_cst (m_flags, d_uint_type));
/* void function(void*) xdtor; */
- tree dtor = (sd->dtor) ? build_address (get_symbol_decl (sd->dtor))
+ tree dtor = (sd->tidtor) ? build_address (get_symbol_decl (sd->tidtor))
: null_pointer_node;
this->layout_field (dtor);
@@ -1298,17 +1296,17 @@ layout_classinfo_interfaces (ClassDeclaration *decl)
static bool
builtin_typeinfo_p (Type *type)
{
- if (type->isTypeBasic () || type->ty == Tclass || type->ty == Tnull)
+ if (type->isTypeBasic () || type->ty == TY::Tclass || type->ty == TY::Tnull)
return !type->mod;
- if (type->ty == Tarray)
+ if (type->ty == TY::Tarray)
{
/* Strings are so common, make them builtin. */
Type *next = type->nextOf ();
return !type->mod
&& ((next->isTypeBasic () != NULL && !next->mod)
- || (next->ty == Tchar && next->mod == MODimmutable)
- || (next->ty == Tchar && next->mod == MODconst));
+ || (next->ty == TY::Tchar && next->mod == MODimmutable)
+ || (next->ty == TY::Tchar && next->mod == MODconst));
}
return false;
@@ -1361,7 +1359,7 @@ get_typeinfo_decl (TypeInfoDeclaration *decl)
if (decl->csym)
return decl->csym;
- gcc_assert (decl->tinfo->ty != Terror);
+ gcc_assert (decl->tinfo->ty != TY::Terror);
TypeInfoDeclVisitor v = TypeInfoDeclVisitor ();
decl->accept (&v);
@@ -1436,7 +1434,7 @@ check_typeinfo_type (const Loc &loc, Scope *sc)
tree
build_typeinfo (const Loc &loc, Type *type)
{
- gcc_assert (type->ty != Terror);
+ gcc_assert (type->ty != TY::Terror);
check_typeinfo_type (loc, NULL);
create_typeinfo (type, NULL);
return build_address (get_typeinfo_decl (type->vtinfo));
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index fc8a133..db500ee 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -94,7 +94,7 @@ bool
valist_array_p (Type *type)
{
Type *tvalist = target.va_listType (Loc (), NULL);
- if (tvalist->ty == Tsarray)
+ if (tvalist->ty == TY::Tsarray)
{
Type *tb = type->toBasetype ();
if (same_type_p (tb, tvalist))
@@ -170,7 +170,7 @@ make_array_type (Type *type, unsigned HOST_WIDE_INT size)
{
/* In [arrays/void-arrays], void arrays can also be static, the length is
specified in bytes. */
- if (type->toBasetype ()->ty == Tvoid)
+ if (type->toBasetype ()->ty == TY::Tvoid)
type = Type::tuns8;
/* In [arrays/static-arrays], a static array with a dimension of 0 is allowed,
@@ -546,9 +546,9 @@ merge_aggregate_types (Type *type, tree deco)
{
AggregateDeclaration *sym;
- if (type->ty == Tstruct)
+ if (type->ty == TY::Tstruct)
sym = type->isTypeStruct ()->sym;
- else if (type->ty == Tclass)
+ else if (type->ty == TY::Tclass)
sym = type->isTypeClass ()->sym;
else
gcc_unreachable ();
@@ -646,31 +646,31 @@ public:
switch (t->ty)
{
- case Tvoid: t->ctype = void_type_node; break;
- case Tbool: t->ctype = d_bool_type; break;
- case Tint8: t->ctype = d_byte_type; break;
- case Tuns8: t->ctype = d_ubyte_type; break;
- case Tint16: t->ctype = d_short_type; break;
- case Tuns16: t->ctype = d_ushort_type; break;
- case Tint32: t->ctype = d_int_type; break;
- case Tuns32: t->ctype = d_uint_type; break;
- case Tint64: t->ctype = d_long_type; break;
- case Tuns64: t->ctype = d_ulong_type; break;
- case Tint128: t->ctype = d_cent_type; break;
- case Tuns128: t->ctype = d_ucent_type; break;
- case Tfloat32: t->ctype = float_type_node; break;
- case Tfloat64: t->ctype = double_type_node; break;
- case Tfloat80: t->ctype = long_double_type_node; break;
- case Timaginary32: t->ctype = ifloat_type_node; break;
- case Timaginary64: t->ctype = idouble_type_node; break;
- case Timaginary80: t->ctype = ireal_type_node; break;
- case Tcomplex32: t->ctype = complex_float_type_node; break;
- case Tcomplex64: t->ctype = complex_double_type_node; break;
- case Tcomplex80: t->ctype = complex_long_double_type_node; break;
- case Tchar: t->ctype = char8_type_node; break;
- case Twchar: t->ctype = char16_type_node; break;
- case Tdchar: t->ctype = char32_type_node; break;
- default: gcc_unreachable ();
+ case TY::Tvoid: t->ctype = void_type_node; break;
+ case TY::Tbool: t->ctype = d_bool_type; break;
+ case TY::Tint8: t->ctype = d_byte_type; break;
+ case TY::Tuns8: t->ctype = d_ubyte_type; break;
+ case TY::Tint16: t->ctype = d_short_type; break;
+ case TY::Tuns16: t->ctype = d_ushort_type; break;
+ case TY::Tint32: t->ctype = d_int_type; break;
+ case TY::Tuns32: t->ctype = d_uint_type; break;
+ case TY::Tint64: t->ctype = d_long_type; break;
+ case TY::Tuns64: t->ctype = d_ulong_type; break;
+ case TY::Tint128: t->ctype = d_cent_type; break;
+ case TY::Tuns128: t->ctype = d_ucent_type; break;
+ case TY::Tfloat32: t->ctype = float_type_node; break;
+ case TY::Tfloat64: t->ctype = double_type_node; break;
+ case TY::Tfloat80: t->ctype = long_double_type_node; break;
+ case TY::Timaginary32: t->ctype = ifloat_type_node; break;
+ case TY::Timaginary64: t->ctype = idouble_type_node; break;
+ case TY::Timaginary80: t->ctype = ireal_type_node; break;
+ case TY::Tcomplex32: t->ctype = complex_float_type_node; break;
+ case TY::Tcomplex64: t->ctype = complex_double_type_node; break;
+ case TY::Tcomplex80: t->ctype = complex_long_double_type_node; break;
+ case TY::Tchar: t->ctype = char8_type_node; break;
+ case TY::Twchar: t->ctype = char16_type_node; break;
+ case TY::Tdchar: t->ctype = char32_type_node; break;
+ default: gcc_unreachable ();
}
TYPE_NAME (t->ctype) = get_identifier (t->toChars ());
@@ -786,7 +786,7 @@ public:
if (t->next != NULL)
{
fntype = build_ctype (t->next);
- if (t->isref)
+ if (t->isref ())
fntype = build_reference_type (fntype);
}
else
@@ -800,7 +800,7 @@ public:
/* Handle any special support for calling conventions. */
switch (t->linkage)
{
- case LINKwindows:
+ case LINK::windows:
{
/* [attribute/linkage]
@@ -815,10 +815,10 @@ public:
break;
}
- case LINKc:
- case LINKcpp:
- case LINKd:
- case LINKobjc:
+ case LINK::c:
+ case LINK::cpp:
+ case LINK::d:
+ case LINK::objc:
/* [abi/function-calling-conventions]
The extern (C) and extern (D) calling convention matches
@@ -1013,8 +1013,8 @@ public:
TYPE_CONTEXT (t->ctype) = d_decl_context (t->sym);
build_type_decl (t->ctype, t->sym);
- /* For structs with a user defined postblit or a destructor,
- also set TREE_ADDRESSABLE on the type and all variants.
+ /* For structs with a user defined postblit, copy constructor, or a
+ destructor, also set TREE_ADDRESSABLE on the type and all variants.
This will make the struct be passed around by reference. */
if (!t->sym->isPOD ())
{
diff --git a/gcc/d/verstr.h b/gcc/d/verstr.h
deleted file mode 100644
index 0dd41ee..0000000
--- a/gcc/d/verstr.h
+++ /dev/null
@@ -1 +0,0 @@
-"2.076.1"
diff --git a/gcc/po/EXCLUDES b/gcc/po/EXCLUDES
index 29ecd06..d2c5cbf 100644
--- a/gcc/po/EXCLUDES
+++ b/gcc/po/EXCLUDES
@@ -53,46 +53,3 @@ genrecog.c
gensupport.c
gensupport.h
read-md.c
-
-# These files are part of the front end to D, and have no i18n support.
-d/dmd/arrayop.c
-d/dmd/attrib.c
-d/dmd/blockexit.c
-d/dmd/canthrow.c
-d/dmd/constfold.c
-d/dmd/cppmangle.c
-d/dmd/ctfeexpr.c
-d/dmd/dcast.c
-d/dmd/dclass.c
-d/dmd/declaration.c
-d/dmd/denum.c
-d/dmd/dimport.c
-d/dmd/dinterpret.c
-d/dmd/dmangle.c
-d/dmd/dmodule.c
-d/dmd/doc.c
-d/dmd/dscope.c
-d/dmd/dstruct.c
-d/dmd/dsymbol.c
-d/dmd/dtemplate.c
-d/dmd/dversion.c
-d/dmd/expression.c
-d/dmd/expressionsem.c
-d/dmd/func.c
-d/dmd/iasmgcc.c
-d/dmd/initsem.c
-d/dmd/lexer.c
-d/dmd/mtype.c
-d/dmd/nogc.c
-d/dmd/nspace.c
-d/dmd/objc.c
-d/dmd/opover.c
-d/dmd/optimize.c
-d/dmd/parse.c
-d/dmd/safe.c
-d/dmd/sideeffect.c
-d/dmd/statement.c
-d/dmd/statementsem.c
-d/dmd/staticassert.c
-d/dmd/staticcond.c
-d/dmd/traits.c
diff --git a/gcc/testsuite/gdc.dg/Wcastresult2.d b/gcc/testsuite/gdc.dg/Wcastresult2.d
index 56d2dd2..83d189a 100644
--- a/gcc/testsuite/gdc.dg/Wcastresult2.d
+++ b/gcc/testsuite/gdc.dg/Wcastresult2.d
@@ -1,5 +1,5 @@
// { dg-do compile }
-// { dg-options "-Wcast-result" }
+// { dg-options "-Wcast-result -Wno-deprecated" }
void test()
{
diff --git a/gcc/testsuite/gdc.dg/asm1.d b/gcc/testsuite/gdc.dg/asm1.d
index dce3676..1b249ee 100644
--- a/gcc/testsuite/gdc.dg/asm1.d
+++ b/gcc/testsuite/gdc.dg/asm1.d
@@ -24,9 +24,9 @@ void parse3()
{
asm { "" [; }
// { dg-error "expression expected, not ';'" "" { target *-*-* } .-1 }
- // { dg-error "found 'EOF' when expecting ','" "" { target *-*-* } .-2 }
- // { dg-error "found 'EOF' when expecting ']'" "" { target *-*-* } .-3 }
- // { dg-error "found 'EOF' when expecting ';'" "" { target *-*-* } .-4 }
+ // { dg-error "found 'End of File' when expecting ','" "" { target *-*-* } .-2 }
+ // { dg-error "found 'End of File' when expecting ']'" "" { target *-*-* } .-3 }
+ // { dg-error "found 'End of File' when expecting ';'" "" { target *-*-* } .-4 }
}
void parse4()
@@ -46,8 +46,8 @@ void semantic1()
;
}
asm { "" : : : : L1, L2; }
- // { dg-error "goto skips declaration of variable asm1.semantic1.one" "" { target *-*-* } .-1 }
- // { dg-error "goto skips declaration of variable asm1.semantic1.two" "" { target *-*-* } .-2 }
+ // { dg-error "'goto' skips declaration of variable 'asm1.semantic1.one'" "" { target *-*-* } .-1 }
+ // { dg-error "'goto' skips declaration of variable 'asm1.semantic1.two'" "" { target *-*-* } .-2 }
{
int two;
L2:
@@ -58,19 +58,19 @@ void semantic1()
void semantic2a(X...)(X expr)
{
alias X[0] var1;
- asm { "%0" : "=m" (var1); } // { dg-error "double 'double' is a type, not an lvalue" }
+ asm { "%0" : "=m" (var1); } // { dg-error "double' is a 'double' definition and cannot be modified" }
}
void semantic2()
{
- semantic2a(3.6); // { dg-error "template instance asm1.semantic2a!double error instantiating" }
+ semantic2a(3.6); // { dg-error "template instance 'asm1.semantic2a!double' error instantiating" }
}
void semantic3()
{
asm
{
- unknown; // { dg-error "undefined identifier" }
+ unknown; // { dg-error "undefined identifier 'unknown'" }
}
}
@@ -86,6 +86,6 @@ void semantic4()
{
asm
{
- "%0" : : "m" (S4.foo); // { dg-error "template instance opDispatch!\"foo\" has no value" }
+ "%0" : : "m" (S4.foo); // { dg-error "template instance 'opDispatch!\"foo\"' has no value" }
}
}
diff --git a/gcc/testsuite/gdc.dg/asm2.d b/gcc/testsuite/gdc.dg/asm2.d
index bce0e41..5b86e35 100644
--- a/gcc/testsuite/gdc.dg/asm2.d
+++ b/gcc/testsuite/gdc.dg/asm2.d
@@ -3,6 +3,6 @@ module asm2;
void test()
{
- asm const shared { } // { dg-error "const/immutable/shared/inout attributes are not allowed on asm blocks" }
+ asm const shared { } // { dg-error "'const'/'immutable'/'shared'/'inout' attributes are not allowed on 'asm' blocks" }
}
diff --git a/gcc/testsuite/gdc.dg/asm3.d b/gcc/testsuite/gdc.dg/asm3.d
index 333d83e..d792b24 100644
--- a/gcc/testsuite/gdc.dg/asm3.d
+++ b/gcc/testsuite/gdc.dg/asm3.d
@@ -2,23 +2,23 @@
// { dg-options "-Wall -Wdeprecated -Werror" }
module asm3;
-void test1() nothrow // { dg-error "nothrow function 'asm3.test1' may throw" }
+void test1() nothrow
{
- asm { } // { dg-error "asm statement is assumed to throw - mark it with 'nothrow' if it does not" }
+ asm { } // { dg-error "'asm' statement is assumed to throw - mark it with 'nothrow' if it does not" }
}
void test2() pure
{
- asm { } // { dg-error "asm statement is assumed to be impure - mark it with 'pure' if it is not" }
+ asm { } // { dg-error "'asm' statement is assumed to be impure - mark it with 'pure' if it is not" }
}
void test3() @nogc
{
- asm { } // { dg-error "asm statement is assumed to use the GC - mark it with '@nogc' if it does not" }
+ asm { } // { dg-error "'asm' statement is assumed to use the GC - mark it with '@nogc' if it does not" }
}
void test4() @safe
{
- asm { } // { dg-error "asm statement is assumed to be @system - mark it with '@trusted' if it is not" }
+ asm { } // { dg-error "'asm' statement is assumed to be '@system' - mark it with '@trusted' if it is not" }
}
diff --git a/gcc/testsuite/gdc.dg/gdc282.d b/gcc/testsuite/gdc.dg/gdc282.d
index ce84050..93e11fa 100644
--- a/gcc/testsuite/gdc.dg/gdc282.d
+++ b/gcc/testsuite/gdc.dg/gdc282.d
@@ -12,7 +12,7 @@ class C282a
{
}
- void f282() // { dg-error "conflicts with gdc282.C282a.f282" }
+ void f282() // { dg-error "conflicts with previous declaration" }
{
}
}
@@ -27,7 +27,7 @@ class C282b
{
}
- void f282() // { dg-error "conflicts with gdc282.C282b.f282" }
+ void f282() // { dg-error "conflicts with previous declaration" }
{
}
}
@@ -42,7 +42,7 @@ class C282c
{
}
- void f282() // { dg-error "conflicts with gdc282.C282c.f282" }
+ void f282() // { dg-error "conflicts with previous declaration" }
{
}
}
diff --git a/gcc/testsuite/gdc.dg/imports/gdc170.d b/gcc/testsuite/gdc.dg/imports/gdc170.d
index f9fea1f..aedef60 100644
--- a/gcc/testsuite/gdc.dg/imports/gdc170.d
+++ b/gcc/testsuite/gdc.dg/imports/gdc170.d
@@ -7,12 +7,12 @@ class bar(T)
template foo(T)
{
- bar!T foo1(T2)() if (true) body { return null; }
+ bar!T foo1(T2)() if (true) do { return null; }
bar!T foo2(T2)() { return null; }
- bar!T foo3(T2 = void)() if (true) body { return null; }
+ bar!T foo3(T2 = void)() if (true) do { return null; }
bar!T foo4(T2 = void)() { return null; }
- void foo5(T2)(bar!T x) if (true) body {}
+ void foo5(T2)(bar!T x) if (true) do {}
void foo6(T2)(bar!T x) {}
- void foo7(T2 = void)(bar!T x) if (true) body {}
+ void foo7(T2 = void)(bar!T x) if (true) do {}
void foo8(T2 = void)(bar!T x) {}
}
diff --git a/gcc/testsuite/gdc.dg/intrinsics.d b/gcc/testsuite/gdc.dg/intrinsics.d
index d9ccc0e..dca40d2 100644
--- a/gcc/testsuite/gdc.dg/intrinsics.d
+++ b/gcc/testsuite/gdc.dg/intrinsics.d
@@ -35,22 +35,6 @@ ulong test_bswap(ulong a) { return bswap(a); }
int test_popcnt(uint a) { return popcnt(a); }
// { dg-final { scan-tree-dump " __builtin_popcount(l|ll) " "original" } }
int test_popcnt(ulong a) { return popcnt(a); }
-// { dg-final { scan-tree-dump "\\(volatile ubyte \\*\\) a;" "original" } }
-ubyte test_volatileLoad(ubyte *a) { return volatileLoad(a); }
-// { dg-final { scan-tree-dump "\\(volatile ushort \\*\\) a;" "original" } }
-ushort test_volatileLoad(ushort *a) { return volatileLoad(a); }
-// { dg-final { scan-tree-dump "\\(volatile uint \\*\\) a;" "original" } }
-uint test_volatileLoad(uint *a) { return volatileLoad(a); }
-// { dg-final { scan-tree-dump "\\(volatile ulong \\*\\) a;" "original" } }
-ulong test_volatileLoad(ulong *a) { return volatileLoad(a); }
-// { dg-final { scan-tree-dump "\\(volatile ubyte \\*\\) a = b" "original" } }
-void test_volatileStore(ubyte *a, ubyte b) { return volatileStore(a, b); }
-// { dg-final { scan-tree-dump "\\(volatile ushort \\*\\) a = b" "original" } }
-void test_volatileStore(ushort *a, ushort b) { return volatileStore(a, b); }
-// { dg-final { scan-tree-dump "\\(volatile uint \\*\\) a = b" "original" } }
-void test_volatileStore(uint *a, uint b) { return volatileStore(a, b); }
-// { dg-final { scan-tree-dump "\\(volatile ulong \\*\\) a = b" "original" } }
-void test_volatileStore(ulong *a, ulong b) { return volatileStore(a, b); }
// { dg-final { scan-tree-dump " a r<< b;" "original" } }
ubyte test_rol(ubyte a, uint b) { return rol!ubyte(a, b); }
// { dg-final { scan-tree-dump " a r>> 31;" "original" } }
@@ -141,6 +125,26 @@ real test_toPrecl(double a) { return toPrec!real(a); }
real test_toPrecl(real a) { return toPrec!real(a); }
//////////////////////////////////////////////////////
+// core.volatile
+
+// { dg-final { scan-tree-dump "\\(volatile ubyte \\*\\) a;" "original" } }
+ubyte test_volatileLoad(ubyte *a) { return volatileLoad(a); }
+// { dg-final { scan-tree-dump "\\(volatile ushort \\*\\) a;" "original" } }
+ushort test_volatileLoad(ushort *a) { return volatileLoad(a); }
+// { dg-final { scan-tree-dump "\\(volatile uint \\*\\) a;" "original" } }
+uint test_volatileLoad(uint *a) { return volatileLoad(a); }
+// { dg-final { scan-tree-dump "\\(volatile ulong \\*\\) a;" "original" } }
+ulong test_volatileLoad(ulong *a) { return volatileLoad(a); }
+// { dg-final { scan-tree-dump "\\(volatile ubyte \\*\\) a = b" "original" } }
+void test_volatileStore(ubyte *a, ubyte b) { return volatileStore(a, b); }
+// { dg-final { scan-tree-dump "\\(volatile ushort \\*\\) a = b" "original" } }
+void test_volatileStore(ushort *a, ushort b) { return volatileStore(a, b); }
+// { dg-final { scan-tree-dump "\\(volatile uint \\*\\) a = b" "original" } }
+void test_volatileStore(uint *a, uint b) { return volatileStore(a, b); }
+// { dg-final { scan-tree-dump "\\(volatile ulong \\*\\) a = b" "original" } }
+void test_volatileStore(ulong *a, ulong b) { return volatileStore(a, b); }
+
+//////////////////////////////////////////////////////
// core.stdc.stdarg
// { dg-final { scan-tree-dump-not " va_arg " "original" } }
diff --git a/gcc/testsuite/gdc.dg/pr101672.d b/gcc/testsuite/gdc.dg/pr101672.d
index 292fd76..8b337a4 100644
--- a/gcc/testsuite/gdc.dg/pr101672.d
+++ b/gcc/testsuite/gdc.dg/pr101672.d
@@ -8,7 +8,7 @@ interface I101672
static int i101672;
}
-class A101672 : I101672 // { dg-error "class object.A101672 missing or corrupt object.d" }
+class A101672 : I101672
{
static int a101672;
}
diff --git a/gcc/testsuite/gdc.dg/pr90650a.d b/gcc/testsuite/gdc.dg/pr90650a.d
index 57228ca..62b7994 100644
--- a/gcc/testsuite/gdc.dg/pr90650a.d
+++ b/gcc/testsuite/gdc.dg/pr90650a.d
@@ -10,5 +10,5 @@ class c
void g ()
{
- if (0 & [0] & c.f()) {} // { dg-error "array operation \\\[0\\\] & 0 & f\\(\\) without destination memory not allowed" }
+ if (0 & [0] & c.f()) {} // { dg-error "array operation .\\\[0\\\] & 0 & f\\(\\). without destination memory not allowed" }
}
diff --git a/gcc/testsuite/gdc.dg/pr90650b.d b/gcc/testsuite/gdc.dg/pr90650b.d
index 2b3192e..11a0225 100644
--- a/gcc/testsuite/gdc.dg/pr90650b.d
+++ b/gcc/testsuite/gdc.dg/pr90650b.d
@@ -9,5 +9,5 @@ class c
}
void g ()
{
- if ([0] & c.f()) {} // { dg-error "array operation \\\[0\\\] & f\\(\\) without destination memory not allowed" }
+ if ([0] & c.f()) {} // { dg-error "array operation .\\\[0\\\] & f\\(\\). without destination memory not allowed" }
}
diff --git a/gcc/testsuite/gdc.dg/pr94777a.d b/gcc/testsuite/gdc.dg/pr94777a.d
index a58fa55..d0cb556 100644
--- a/gcc/testsuite/gdc.dg/pr94777a.d
+++ b/gcc/testsuite/gdc.dg/pr94777a.d
@@ -11,5 +11,5 @@ void f94777()
this(this) { }
}
auto var = S94777(0);
- variadic(var, S94777(1));
+ variadic(var, S94777(1)); // { dg-error "cannot pass types with postblits or copy constructors as variadic arguments" }
}
diff --git a/gcc/testsuite/gdc.dg/pr94777c.d b/gcc/testsuite/gdc.dg/pr94777c.d
new file mode 100644
index 0000000..9b725c0
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr94777c.d
@@ -0,0 +1,62 @@
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94777
+// { dg-additional-options "-funittest" }
+// { dg-do compile }
+
+void testVariadic(T)(int nargs, ...)
+{
+ import core.stdc.stdarg;
+ foreach(i; 0 .. nargs)
+ {
+ auto arg = va_arg!T(_argptr);
+ static if (__traits(compiles, arg.value))
+ {
+ assert(arg.value == i);
+ }
+ else static if (__traits(compiles, arg[0]))
+ {
+ foreach (value; arg)
+ assert(value == i);
+ }
+ else
+ {
+ assert(arg == T.init);
+ }
+ }
+}
+
+/******************************************/
+
+struct Postblit
+{
+ static int count = 0;
+ int value;
+ this(this) { count++; }
+}
+
+unittest
+{
+ auto a0 = Postblit(0);
+ auto a1 = Postblit(1);
+ auto a2 = Postblit(2);
+ testVariadic!Postblit(3, a0, a1, a2); // { dg-error "cannot pass types with postblits or copy constructors as variadic arguments" }
+ assert(Postblit.count == 3);
+}
+
+/******************************************/
+
+struct CopyConstructor
+{
+ static int count = 0;
+ int value;
+ this(int v) { this.value = v; }
+ this(ref typeof(this) other) { count++; this.value = other.value; }
+}
+
+unittest
+{
+ auto a0 = CopyConstructor(0);
+ auto a1 = CopyConstructor(1);
+ auto a2 = CopyConstructor(2);
+ testVariadic!CopyConstructor(3, a0, a1, a2); // { dg-error "cannot pass types with postblits or copy constructors as variadic arguments" }
+ assert(CopyConstructor.count == 3);
+}
diff --git a/gcc/testsuite/gdc.dg/pr95250.d b/gcc/testsuite/gdc.dg/pr95250.d
index dfb8abb..ba0adea 100644
--- a/gcc/testsuite/gdc.dg/pr95250.d
+++ b/gcc/testsuite/gdc.dg/pr95250.d
@@ -15,4 +15,4 @@ void* f(T)(T a, T b)
}
static assert(is(typeof(f!(void*)(null, null)) == void*));
-// { dg-error "static assert \(.*\) is false" "" { target *-*-* } .-1 }
+// { dg-error "static assert: \(.*\) is false" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/gdc.dg/pr96156b.d b/gcc/testsuite/gdc.dg/pr96156b.d
new file mode 100644
index 0000000..ae79d56
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr96156b.d
@@ -0,0 +1,17 @@
+@safe unittest
+{
+ struct CustomString
+ {
+ @safe:
+ string _impl;
+ @property bool empty() const { return !_impl.length; }
+ }
+
+ CustomString find(CustomString a, CustomString b)
+ {
+ return CustomString.init;
+ }
+
+ auto r = find(CustomString("a"), CustomString("b"));
+ assert(r.empty);
+}
diff --git a/gcc/testsuite/gdc.dg/pr96157c.d b/gcc/testsuite/gdc.dg/pr96157c.d
new file mode 100644
index 0000000..8f48cbd
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr96157c.d
@@ -0,0 +1,40 @@
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96157
+// { dg-options "-fno-moduleinfo -fno-rtti" }
+// { dg-do compile }
+
+struct CodepointSet
+{
+ CowArray!string data;
+}
+
+struct CowArray(SP)
+{
+ ~this()
+ {
+ if (data.length)
+ refCount;
+ }
+ @property refCount() { return data[$-1]; }
+
+ uint[] data;
+}
+
+int ucmp() { return 1; }
+
+bool loadProperty () {
+
+ CodepointSet target;
+ if (ucmp)
+ CodepointSet();
+ else if (ucmp|| ucmp)
+ target = CodepointSet();
+ else if (ucmp|| ucmp)
+ target = CodepointSet();
+ else if (ucmp|| ucmp)
+ target = CodepointSet();
+ else if (ucmp)
+ target = CodepointSet();
+ else if (ucmp)
+ target = CodepointSet();
+ return true;
+}
diff --git a/gcc/testsuite/gdc.dg/pr96869.d b/gcc/testsuite/gdc.dg/pr96869.d
index c4ace30..348da1b 100644
--- a/gcc/testsuite/gdc.dg/pr96869.d
+++ b/gcc/testsuite/gdc.dg/pr96869.d
@@ -2,31 +2,31 @@
// { dg-do compile }
__vector(float[0]) var01;
-// { dg-error "0 byte vector type __vector\\\(float\\\[0\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "0 byte vector type '__vector\\\(float\\\[0\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
__vector(float[3]) var02;
-// { dg-error "12 byte vector type __vector\\\(float\\\[3\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "12 byte vector type '__vector\\\(float\\\[3\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
__vector(float[][4]) var03;
-// { dg-error "vector type __vector\\\(float\\\[\\\]\\\[4\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "vector type '__vector\\\(float\\\[\\\]\\\[4\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
__vector(float[4][4]) var04;
-// { dg-error "vector type __vector\\\(float\\\[4\\\]\\\[4\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "vector type '__vector\\\(float\\\[4\\\]\\\[4\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
__vector(float[float][4]) var05;
-// { dg-error "vector type __vector\\\(float\\\[float\\\]\\\[4\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "vector type '__vector\\\(float\\\[float\\\]\\\[4\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
__vector(float function()[4]) var06;
-// { dg-error "vector type __vector\\\(float function\\\(\\\)\\\[4\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "vector type '__vector\\\(float function\\\(\\\)\\\[4\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
__vector(float delegate()[4]) var07;
-// { dg-error "vector type __vector\\\(float delegate\\\(\\\)\\\[4\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "vector type '__vector\\\(float delegate\\\(\\\)\\\[4\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
enum E { a, b, c }
__vector(E[4]) var08;
-// { dg-error "vector type __vector\\\(E\\\[4\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "vector type '__vector\\\(E\\\[4\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
struct S { float a; }
__vector(S[4]) var09;
-// { dg-error "vector type __vector\\\(S\\\[4\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "vector type '__vector\\\(S\\\[4\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
class C { float a; }
__vector(C[4]) var10;
-// { dg-error "vector type __vector\\\(C\\\[4\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "vector type '__vector\\\(C\\\[4\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
__vector(cfloat[4]) var11;
-// { dg-error "vector type __vector\\\(cfloat\\\[4\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "vector type '__vector\\\(cfloat\\\[4\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
__vector(bool[4]) var12;
-// { dg-error "vector type __vector\\\(bool\\\[4\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "vector type '__vector\\\(bool\\\[4\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
__vector(real[128]) var13;
-// { dg-error "vector type __vector\\\(real\\\[128\\\]\\\) is not supported on this platform" "" { target *-*-* } .-1 }
+// { dg-error "vector type '__vector\\\(real\\\[128\\\]\\\)' is not supported on this platform" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/gdc.dg/pr98277.d b/gcc/testsuite/gdc.dg/pr98277.d
index d3b859f..0dff142 100644
--- a/gcc/testsuite/gdc.dg/pr98277.d
+++ b/gcc/testsuite/gdc.dg/pr98277.d
@@ -7,7 +7,7 @@ enum Side
right
}
-ref int getSide(Side side, ref int left, ref int right)
+ref int getSide(Side side, return ref int left, return ref int right)
{
return side == Side.left ? left : right;
}
diff --git a/gcc/testsuite/gdc.dg/pr98457.d b/gcc/testsuite/gdc.dg/pr98457.d
index bc0d8af..0cc83ac 100644
--- a/gcc/testsuite/gdc.dg/pr98457.d
+++ b/gcc/testsuite/gdc.dg/pr98457.d
@@ -3,7 +3,7 @@
void main()
{
- writef!"%s"; // { dg-error "template instance writef!\"%s\" template .writef. is not defined" }
- writef!"`%s"; // { dg-error "template instance writef!\"`%s\" template .writef. is not defined" }
- writef!"%%s`"; // { dg-error "template instance writef!\"%%s`\" template .writef. is not defined" }
+ writef!"%s"; // { dg-error "template instance .writef!\"%s\". template .writef. is not defined" }
+ writef!"`%s"; // { dg-error "template instance .writef!\"`%s\". template .writef. is not defined" }
+ writef!"%%s`"; // { dg-error "template instance .writef!\"%%s`\". template .writef. is not defined" }
}
diff --git a/gcc/testsuite/gdc.dg/simd1.d b/gcc/testsuite/gdc.dg/simd1.d
index 374dcae..b25b99e 100644
--- a/gcc/testsuite/gdc.dg/simd1.d
+++ b/gcc/testsuite/gdc.dg/simd1.d
@@ -26,14 +26,6 @@ void test1()
static assert(!__traits(compiles, v1 > v2));
static assert(!__traits(compiles, v1 <= v2));
static assert(!__traits(compiles, v1 >= v2));
- static assert(!__traits(compiles, v1 <> v2));
- static assert(!__traits(compiles, v1 !< v2));
- static assert(!__traits(compiles, v1 !> v2));
- static assert(!__traits(compiles, v1 !<> v2));
- static assert(!__traits(compiles, v1 <>= v2));
- static assert(!__traits(compiles, v1 !<= v2));
- static assert(!__traits(compiles, v1 !>= v2));
- static assert(!__traits(compiles, v1 !<>= v2));
static assert(!__traits(compiles, v1 << 1));
static assert(!__traits(compiles, v1 >> 1));
static assert(!__traits(compiles, v1 >>> 1));
diff --git a/gcc/testsuite/gdc.dg/simd2a.d b/gcc/testsuite/gdc.dg/simd2a.d
index b630a47..0fb391c 100644
--- a/gcc/testsuite/gdc.dg/simd2a.d
+++ b/gcc/testsuite/gdc.dg/simd2a.d
@@ -24,14 +24,6 @@ void test2a()
static assert(!__traits(compiles, v1 > v2));
static assert(!__traits(compiles, v1 <= v2));
static assert(!__traits(compiles, v1 >= v2));
- static assert(!__traits(compiles, v1 <> v2));
- static assert(!__traits(compiles, v1 !< v2));
- static assert(!__traits(compiles, v1 !> v2));
- static assert(!__traits(compiles, v1 !<> v2));
- static assert(!__traits(compiles, v1 <>= v2));
- static assert(!__traits(compiles, v1 !<= v2));
- static assert(!__traits(compiles, v1 !>= v2));
- static assert(!__traits(compiles, v1 !<>= v2));
v1 = v2 << 1;
v1 = v2 >> 1;
v1 = v2 >>> 1;
diff --git a/gcc/testsuite/gdc.dg/simd2b.d b/gcc/testsuite/gdc.dg/simd2b.d
index 35c4288..41a4eb3 100644
--- a/gcc/testsuite/gdc.dg/simd2b.d
+++ b/gcc/testsuite/gdc.dg/simd2b.d
@@ -24,14 +24,6 @@ void test2b()
static assert(!__traits(compiles, v1 > v2));
static assert(!__traits(compiles, v1 <= v2));
static assert(!__traits(compiles, v1 >= v2));
- static assert(!__traits(compiles, v1 <> v2));
- static assert(!__traits(compiles, v1 !< v2));
- static assert(!__traits(compiles, v1 !> v2));
- static assert(!__traits(compiles, v1 !<> v2));
- static assert(!__traits(compiles, v1 <>= v2));
- static assert(!__traits(compiles, v1 !<= v2));
- static assert(!__traits(compiles, v1 !>= v2));
- static assert(!__traits(compiles, v1 !<>= v2));
v1 = v2 << 1;
v1 = v2 >> 1;
v1 = v2 >>> 1;
diff --git a/gcc/testsuite/gdc.dg/simd2c.d b/gcc/testsuite/gdc.dg/simd2c.d
index 2f19e75..a995709 100644
--- a/gcc/testsuite/gdc.dg/simd2c.d
+++ b/gcc/testsuite/gdc.dg/simd2c.d
@@ -24,14 +24,6 @@ void test2c()
static assert(!__traits(compiles, v1 > v2));
static assert(!__traits(compiles, v1 <= v2));
static assert(!__traits(compiles, v1 >= v2));
- static assert(!__traits(compiles, v1 <> v2));
- static assert(!__traits(compiles, v1 !< v2));
- static assert(!__traits(compiles, v1 !> v2));
- static assert(!__traits(compiles, v1 !<> v2));
- static assert(!__traits(compiles, v1 <>= v2));
- static assert(!__traits(compiles, v1 !<= v2));
- static assert(!__traits(compiles, v1 !>= v2));
- static assert(!__traits(compiles, v1 !<>= v2));
v1 = v2 << 1;
v1 = v2 >> 1;
v1 = v2 >>> 1;
diff --git a/gcc/testsuite/gdc.dg/simd2d.d b/gcc/testsuite/gdc.dg/simd2d.d
index 9d378e4..d578734 100644
--- a/gcc/testsuite/gdc.dg/simd2d.d
+++ b/gcc/testsuite/gdc.dg/simd2d.d
@@ -24,14 +24,6 @@ void test2d()
static assert(!__traits(compiles, v1 > v2));
static assert(!__traits(compiles, v1 <= v2));
static assert(!__traits(compiles, v1 >= v2));
- static assert(!__traits(compiles, v1 <> v2));
- static assert(!__traits(compiles, v1 !< v2));
- static assert(!__traits(compiles, v1 !> v2));
- static assert(!__traits(compiles, v1 !<> v2));
- static assert(!__traits(compiles, v1 <>= v2));
- static assert(!__traits(compiles, v1 !<= v2));
- static assert(!__traits(compiles, v1 !>= v2));
- static assert(!__traits(compiles, v1 !<>= v2));
v1 = v2 << 1;
v1 = v2 >> 1;
v1 = v2 >>> 1;
diff --git a/gcc/testsuite/gdc.dg/simd2e.d b/gcc/testsuite/gdc.dg/simd2e.d
index 30d7c1a..d33574a 100644
--- a/gcc/testsuite/gdc.dg/simd2e.d
+++ b/gcc/testsuite/gdc.dg/simd2e.d
@@ -24,14 +24,6 @@ void test2e()
static assert(!__traits(compiles, v1 > v2));
static assert(!__traits(compiles, v1 <= v2));
static assert(!__traits(compiles, v1 >= v2));
- static assert(!__traits(compiles, v1 <> v2));
- static assert(!__traits(compiles, v1 !< v2));
- static assert(!__traits(compiles, v1 !> v2));
- static assert(!__traits(compiles, v1 !<> v2));
- static assert(!__traits(compiles, v1 <>= v2));
- static assert(!__traits(compiles, v1 !<= v2));
- static assert(!__traits(compiles, v1 !>= v2));
- static assert(!__traits(compiles, v1 !<>= v2));
v1 = v2 << 1;
v1 = v2 >> 1;
v1 = v2 >>> 1;
diff --git a/gcc/testsuite/gdc.dg/simd2f.d b/gcc/testsuite/gdc.dg/simd2f.d
index f844880..5845249 100644
--- a/gcc/testsuite/gdc.dg/simd2f.d
+++ b/gcc/testsuite/gdc.dg/simd2f.d
@@ -24,14 +24,6 @@ void test2f()
static assert(!__traits(compiles, v1 > v2));
static assert(!__traits(compiles, v1 <= v2));
static assert(!__traits(compiles, v1 >= v2));
- static assert(!__traits(compiles, v1 <> v2));
- static assert(!__traits(compiles, v1 !< v2));
- static assert(!__traits(compiles, v1 !> v2));
- static assert(!__traits(compiles, v1 !<> v2));
- static assert(!__traits(compiles, v1 <>= v2));
- static assert(!__traits(compiles, v1 !<= v2));
- static assert(!__traits(compiles, v1 !>= v2));
- static assert(!__traits(compiles, v1 !<>= v2));
v1 = v2 << 1;
v1 = v2 >> 1;
v1 = v2 >>> 1;
diff --git a/gcc/testsuite/gdc.dg/simd2g.d b/gcc/testsuite/gdc.dg/simd2g.d
index 8e8bc15..ce438f2 100644
--- a/gcc/testsuite/gdc.dg/simd2g.d
+++ b/gcc/testsuite/gdc.dg/simd2g.d
@@ -24,14 +24,6 @@ void test2g()
static assert(!__traits(compiles, v1 > v2));
static assert(!__traits(compiles, v1 <= v2));
static assert(!__traits(compiles, v1 >= v2));
- static assert(!__traits(compiles, v1 <> v2));
- static assert(!__traits(compiles, v1 !< v2));
- static assert(!__traits(compiles, v1 !> v2));
- static assert(!__traits(compiles, v1 !<> v2));
- static assert(!__traits(compiles, v1 <>= v2));
- static assert(!__traits(compiles, v1 !<= v2));
- static assert(!__traits(compiles, v1 !>= v2));
- static assert(!__traits(compiles, v1 !<>= v2));
v1 = v2 << 1;
v1 = v2 >> 1;
v1 = v2 >>> 1;
diff --git a/gcc/testsuite/gdc.dg/simd2h.d b/gcc/testsuite/gdc.dg/simd2h.d
index f7542e8..c631c76 100644
--- a/gcc/testsuite/gdc.dg/simd2h.d
+++ b/gcc/testsuite/gdc.dg/simd2h.d
@@ -24,14 +24,6 @@ void test2h()
static assert(!__traits(compiles, v1 > v2));
static assert(!__traits(compiles, v1 <= v2));
static assert(!__traits(compiles, v1 >= v2));
- static assert(!__traits(compiles, v1 <> v2));
- static assert(!__traits(compiles, v1 !< v2));
- static assert(!__traits(compiles, v1 !> v2));
- static assert(!__traits(compiles, v1 !<> v2));
- static assert(!__traits(compiles, v1 <>= v2));
- static assert(!__traits(compiles, v1 !<= v2));
- static assert(!__traits(compiles, v1 !>= v2));
- static assert(!__traits(compiles, v1 !<>= v2));
v1 = v2 << 1;
v1 = v2 >> 1;
v1 = v2 >>> 1;
diff --git a/gcc/testsuite/gdc.dg/simd2i.d b/gcc/testsuite/gdc.dg/simd2i.d
index 2e3587d..6946c79 100644
--- a/gcc/testsuite/gdc.dg/simd2i.d
+++ b/gcc/testsuite/gdc.dg/simd2i.d
@@ -24,14 +24,6 @@ void test2i()
static assert(!__traits(compiles, v1 > v2));
static assert(!__traits(compiles, v1 <= v2));
static assert(!__traits(compiles, v1 >= v2));
- static assert(!__traits(compiles, v1 <> v2));
- static assert(!__traits(compiles, v1 !< v2));
- static assert(!__traits(compiles, v1 !> v2));
- static assert(!__traits(compiles, v1 !<> v2));
- static assert(!__traits(compiles, v1 <>= v2));
- static assert(!__traits(compiles, v1 !<= v2));
- static assert(!__traits(compiles, v1 !>= v2));
- static assert(!__traits(compiles, v1 !<>= v2));
static assert(!__traits(compiles, v1 << 1));
static assert(!__traits(compiles, v1 >> 1));
static assert(!__traits(compiles, v1 >>> 1));
diff --git a/gcc/testsuite/gdc.dg/simd2j.d b/gcc/testsuite/gdc.dg/simd2j.d
index 7b60784..ecfdbf3 100644
--- a/gcc/testsuite/gdc.dg/simd2j.d
+++ b/gcc/testsuite/gdc.dg/simd2j.d
@@ -24,14 +24,6 @@ void test2j()
static assert(!__traits(compiles, v1 > v2));
static assert(!__traits(compiles, v1 <= v2));
static assert(!__traits(compiles, v1 >= v2));
- static assert(!__traits(compiles, v1 <> v2));
- static assert(!__traits(compiles, v1 !< v2));
- static assert(!__traits(compiles, v1 !> v2));
- static assert(!__traits(compiles, v1 !<> v2));
- static assert(!__traits(compiles, v1 <>= v2));
- static assert(!__traits(compiles, v1 !<= v2));
- static assert(!__traits(compiles, v1 !>= v2));
- static assert(!__traits(compiles, v1 !<>= v2));
static assert(!__traits(compiles, v1 << 1));
static assert(!__traits(compiles, v1 >> 1));
static assert(!__traits(compiles, v1 >>> 1));
diff --git a/gcc/testsuite/gdc.dg/simd7951.d b/gcc/testsuite/gdc.dg/simd7951.d
index 99ce151..4e467ef 100644
--- a/gcc/testsuite/gdc.dg/simd7951.d
+++ b/gcc/testsuite/gdc.dg/simd7951.d
@@ -19,4 +19,5 @@ void test7951_2()
f1.array = v1;
f2.array = v2;
f3 = f1 + f2;
+ assert((cast(float[4])f3)[2] == 6);
}
diff --git a/gcc/testsuite/gdc.dg/simd_ctfe.d b/gcc/testsuite/gdc.dg/simd_ctfe.d
new file mode 100644
index 0000000..b254cf3
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/simd_ctfe.d
@@ -0,0 +1,87 @@
+// { dg-do compile }
+import core.simd;
+
+// https://issues.dlang.org/show_bug.cgi?id=19627
+enum int[4] fail19627 = cast(int[4])int4(0);
+
+// https://issues.dlang.org/show_bug.cgi?id=19628
+enum ice19628a = int4.init[0];
+enum ice19628b = int4.init.array[0];
+enum ice19628c = (cast(int[4])int4.init.array)[0];
+enum ice19628d = (cast(int[4])int4.init)[0];
+
+// https://issues.dlang.org/show_bug.cgi?id=19629
+enum fail19629a = int4(0)[0];
+enum fail19629b = int4(0).array[0];
+enum fail19629c = (cast(int[4])int4(0).array)[0];
+enum fail19628d = (cast(int[4])int4(0))[0];
+
+// https://issues.dlang.org/show_bug.cgi?id=19630
+enum fail19630a = int4.init[1..2];
+enum fail19630b = int4.init.array[1..2];
+enum fail19630c = (cast(int[4])int4.init.array)[1..2];
+enum fail19630d = int4(0)[1..2];
+enum fail19630e = int4(0).array[1..2];
+enum fail19630f = (cast(int[4])int4(0).array)[1..2];
+enum fail19630g = (cast(int[4])int4.init)[1..2];
+enum fail19630h = (cast(int[4])int4(0))[1..2];
+
+// Same tests as above, but use access via enum.
+enum int4 V1 = int4.init;
+enum int[4] V2 = int4.init.array;
+enum int[4] V3 = cast(int[4])int4.init;
+enum int[4] V4 = cast(int[4])int4.init.array;
+enum int4 V5 = int4(0);
+enum int[4] V6 = int4(0).array;
+enum int[4] V7 = cast(int[4])int4(0);
+enum int[4] V8 = cast(int[4])int4(0).array;
+
+// CTFE index tests
+enum I1 = V1[0]; static assert(I1 == 0);
+enum I2 = V2[0]; static assert(I2 == 0);
+enum I3 = V3[0]; static assert(I3 == 0);
+enum I4 = V4[0]; static assert(I4 == 0);
+enum I5 = V5[0]; static assert(I5 == 0);
+enum I6 = V6[0]; static assert(I6 == 0);
+enum I7 = V7[0]; static assert(I7 == 0);
+enum I8 = V8[0]; static assert(I8 == 0);
+
+// CTFE slice tests
+enum S1 = V1[1..2]; static assert(S1 == [0]);
+enum S2 = V2[1..2]; static assert(S2 == [0]);
+enum S3 = V3[1..2]; static assert(S3 == [0]);
+enum S4 = V4[1..2]; static assert(S4 == [0]);
+enum S5 = V5[1..2]; static assert(S5 == [0]);
+enum S6 = V6[1..2]; static assert(S6 == [0]);
+enum S7 = V7[1..2]; static assert(S7 == [0]);
+enum S8 = V8[1..2]; static assert(S8 == [0]);
+
+// Same tests as above, but use access via immutable.
+//immutable int4 v1 = int4.init; // Cannot cast to immutable at compile time
+immutable int[4] v2 = int4.init.array;
+immutable int[4] v3 = cast(int[4])int4.init;
+immutable int[4] v4 = cast(int[4])int4.init.array;
+//immutable int4 v5 = int4(0); // Cannot cast to immutable at compile time
+immutable int[4] v6 = int4(0).array;
+immutable int[4] v7 = cast(int[4])int4(0);
+immutable int[4] v8 = cast(int[4])int4(0).array;
+
+// CTFE index tests
+//immutable i1 = v1[0]; static assert(i1 == 0);
+immutable i2 = v2[0]; static assert(i2 == 0);
+immutable i3 = v3[0]; static assert(i3 == 0);
+immutable i4 = v4[0]; static assert(i4 == 0);
+//immutable i5 = v5[0]; static assert(i5 == 0);
+immutable i6 = v6[0]; static assert(i6 == 0);
+immutable i7 = v7[0]; static assert(i7 == 0);
+immutable i8 = v8[0]; static assert(i8 == 0);
+
+// CTFE slice tests
+//immutable s1 = v1[1..2]; static assert(s1 == [0]);
+immutable s2 = v2[1..2]; static assert(s2 == [0]);
+immutable s3 = v3[1..2]; static assert(s3 == [0]);
+immutable s4 = v4[1..2]; static assert(s4 == [0]);
+//immutable s5 = v5[1..2]; static assert(s5 == [0]);
+immutable s6 = v6[1..2]; static assert(s6 == [0]);
+immutable s7 = v7[1..2]; static assert(s7 == [0]);
+immutable s8 = v8[1..2]; static assert(s8 == [0]);
diff --git a/gcc/testsuite/gdc.dg/torture/gdc309.d b/gcc/testsuite/gdc.dg/torture/gdc309.d
index d14634a..acda2bb 100644
--- a/gcc/testsuite/gdc.dg/torture/gdc309.d
+++ b/gcc/testsuite/gdc.dg/torture/gdc309.d
@@ -1,4 +1,5 @@
// https://bugzilla.gdcproject.org/show_bug.cgi?id=309
+// { dg-additional-options "-Wno-deprecated" }
// { dg-do run }
// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
diff --git a/gcc/testsuite/gdc.dg/torture/pr94424.d b/gcc/testsuite/gdc.dg/torture/pr94424.d
index 2910c9a..dc30639 100644
--- a/gcc/testsuite/gdc.dg/torture/pr94424.d
+++ b/gcc/testsuite/gdc.dg/torture/pr94424.d
@@ -17,3 +17,19 @@
assert(__cmp([c2, c2], [c1, c1]) > 0);
assert(__cmp([c2, c2], [c2, c1]) > 0);
}
+
+@safe unittest
+{
+ struct C
+ {
+ char i;
+ this(char i) { this.i = i; }
+ }
+
+ auto c1 = C(1);
+ auto c2 = C(2);
+
+ assert(__cmp([c1, c1][], [c2, c2][]) < 0);
+ assert(__cmp([c2, c2], [c1, c1]) > 0);
+ assert(__cmp([c2, c2], [c2, c1]) > 0);
+}
diff --git a/gcc/testsuite/gdc.dg/torture/pr94777b.d b/gcc/testsuite/gdc.dg/torture/pr94777b.d
index 2f0f9d9..e9da63f 100644
--- a/gcc/testsuite/gdc.dg/torture/pr94777b.d
+++ b/gcc/testsuite/gdc.dg/torture/pr94777b.d
@@ -27,42 +27,6 @@ void testVariadic(T)(int nargs, ...)
/******************************************/
-struct Constructor
-{
- static int count;
- int value;
- this(int v) { count++; this.value = v; }
-}
-
-unittest
-{
- auto a0 = Constructor(0);
- auto a1 = Constructor(1);
- auto a2 = Constructor(2);
- testVariadic!Constructor(3, a0, a1, a2);
- assert(Constructor.count == 3);
-}
-
-/******************************************/
-
-struct Postblit
-{
- static int count = 0;
- int value;
- this(this) { count++; }
-}
-
-unittest
-{
- auto a0 = Postblit(0);
- auto a1 = Postblit(1);
- auto a2 = Postblit(2);
- testVariadic!Postblit(3, a0, a1, a2);
- assert(Postblit.count == 3);
-}
-
-/******************************************/
-
struct Destructor
{
static int count = 0;
@@ -80,102 +44,3 @@ unittest
}
assert(Destructor.count == 3);
}
-
-/******************************************/
-
-struct CopyConstructor
-{
- static int count = 0;
- int value;
- this(int v) { this.value = v; }
- this(ref typeof(this) other) { count++; this.value = other.value; }
-}
-
-unittest
-{
- auto a0 = CopyConstructor(0);
- auto a1 = CopyConstructor(1);
- auto a2 = CopyConstructor(2);
- testVariadic!CopyConstructor(3, a0, a1, a2);
- // NOTE: Cpctors are not implemented yet.
- assert(CopyConstructor.count == 0 || CopyConstructor.count == 3);
-}
-
-/******************************************/
-
-unittest
-{
- struct Nested
- {
- int value;
- }
-
- auto a0 = Nested(0);
- auto a1 = Nested(1);
- auto a2 = Nested(2);
- testVariadic!Nested(3, a0, a1, a2);
-}
-
-/******************************************/
-
-unittest
-{
- struct Nested2
- {
- int value;
- }
-
- void testVariadic2(int nargs, ...)
- {
- import core.stdc.stdarg;
- foreach(i; 0 .. nargs)
- {
- auto arg = va_arg!Nested2(_argptr);
- assert(arg.value == i);
- }
- }
-
- auto a0 = Nested2(0);
- auto a1 = Nested2(1);
- auto a2 = Nested2(2);
- testVariadic2(3, a0, a1, a2);
-}
-
-/******************************************/
-
-struct EmptyStruct
-{
-}
-
-unittest
-{
- auto a0 = EmptyStruct();
- auto a1 = EmptyStruct();
- auto a2 = EmptyStruct();
- testVariadic!EmptyStruct(3, a0, a1, a2);
-}
-
-/******************************************/
-
-alias StaticArray = int[4];
-
-unittest
-{
- StaticArray a0 = 0;
- StaticArray a1 = 1;
- StaticArray a2 = 2;
- // XBUG: Front-end rewrites static arrays as dynamic arrays.
- //testVariadic!StaticArray(3, a0, a1, a2);
-}
-
-/******************************************/
-
-alias EmptyArray = void[0];
-
-unittest
-{
- auto a0 = EmptyArray.init;
- auto a1 = EmptyArray.init;
- auto a2 = EmptyArray.init;
- testVariadic!EmptyArray(3, a0, a1, a2);
-}
diff --git a/gcc/testsuite/gdc.dg/torture/simd17344.d b/gcc/testsuite/gdc.dg/torture/simd17344.d
new file mode 100644
index 0000000..fd5ffbe
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/torture/simd17344.d
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=17344
+// { dg-additional-options "-mavx" { target avx_runtime } }
+// { dg-do run { target { avx_runtime || vect_sizes_16B_8B } } }
+// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
+
+void main()
+{
+ __vector(int[4]) vec1 = 2, vec2 = vec1++;
+ assert(cast(int[4])vec1 == [3, 3, 3, 3]);
+ assert(cast(int[4])vec2 == [2, 2, 2, 2]);
+}
diff --git a/gcc/testsuite/gdc.dg/torture/simd20052.d b/gcc/testsuite/gdc.dg/torture/simd20052.d
new file mode 100644
index 0000000..4587351
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/torture/simd20052.d
@@ -0,0 +1,17 @@
+// { dg-additional-options "-mavx2" { target avx2_runtime } }
+// { dg-do run { target { avx2_runtime || vect_sizes_32B_16B } } }
+// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
+import core.simd;
+
+auto test20052()
+{
+ struct S { long4 v; }
+ S s;
+ return s;
+}
+
+void main()
+{
+ test20052();
+}
+
diff --git a/gcc/testsuite/gdc.dg/torture/simd6.d b/gcc/testsuite/gdc.dg/torture/simd6.d
new file mode 100644
index 0000000..d8de02e
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/torture/simd6.d
@@ -0,0 +1,26 @@
+// { dg-additional-options "-mavx2" { target avx2_runtime } }
+// { dg-do run { target { avx2_runtime || vect_sizes_32B_16B } } }
+// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
+import core.simd;
+
+void test6a()
+{
+ // stack occasionally misaligned
+ float f = 0;
+ long4 v;
+ assert((cast(size_t)&v) % 32 == 0);
+ v += 1;
+}
+
+void test6b()
+{
+ struct S {long4 v;}
+ S s;
+ assert((cast(size_t)&s) % 32 == 0);
+}
+
+void main()
+{
+ test6a();
+ test6b();
+}
diff --git a/gcc/testsuite/gdc.dg/torture/simd7.d b/gcc/testsuite/gdc.dg/torture/simd7.d
new file mode 100644
index 0000000..6e890de
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/torture/simd7.d
@@ -0,0 +1,18 @@
+// { dg-additional-options "-mavx2" { target avx2_runtime } }
+// { dg-do run { target { avx2_runtime || vect_sizes_32B_16B } } }
+// { dg-skip-if "needs gcc/config.d" { ! d_runtime } }
+import core.simd;
+
+double4 test7r(double4 v)
+{
+ return v;
+}
+
+void main()
+{
+ // 32 bytes sliced down to 16 bytes
+ double4 v = 1;
+ double4 r = test7r(v);
+ assert(v[2] == r[2]);
+ assert(v[3] == r[3]);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/a3682.d b/gcc/testsuite/gdc.test/compilable/a3682.d
index 69191ec..4be63a35 100644
--- a/gcc/testsuite/gdc.test/compilable/a3682.d
+++ b/gcc/testsuite/gdc.test/compilable/a3682.d
@@ -1,7 +1,7 @@
-// EXTRA_SOURCES: imports/b3682.d
+// COMPILED_IMPORTS: imports/b3682.d
// PERMUTE_ARGS:
-// 3682
+// https://issues.dlang.org/show_bug.cgi?id=3682
struct Tuple(Types...)
{
diff --git a/gcc/testsuite/gdc.test/compilable/aliasassign.d b/gcc/testsuite/gdc.test/compilable/aliasassign.d
new file mode 100644
index 0000000..e355e49
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/aliasassign.d
@@ -0,0 +1,41 @@
+template AliasSeq(T...) { alias AliasSeq = T; }
+
+template Unqual(T)
+{
+ static if (is(T U == const U))
+ alias Unqual = U;
+ else static if (is(T U == immutable U))
+ alias Unqual = U;
+ else
+ alias Unqual = T;
+}
+
+template staticMap(alias F, T...)
+{
+ alias A = AliasSeq!();
+ static foreach (t; T)
+ A = AliasSeq!(A, F!t); // what's tested
+ alias staticMap = A;
+}
+
+alias TK = staticMap!(Unqual, int, const uint);
+//pragma(msg, TK);
+static assert(is(TK == AliasSeq!(int, uint)));
+
+/**************************************************/
+
+template reverse(T...)
+{
+ alias A = AliasSeq!();
+ static foreach (t; T)
+ A = AliasSeq!(t, A); // what's tested
+ alias reverse = A;
+}
+
+enum X2 = 3;
+alias TK2 = reverse!(int, const uint, X2);
+//pragma(msg, TK2);
+static assert(TK2[0] == 3);
+static assert(is(TK2[1] == const(uint)));
+static assert(is(TK2[2] == int));
+
diff --git a/gcc/testsuite/gdc.test/compilable/aliasdecl.d b/gcc/testsuite/gdc.test/compilable/aliasdecl.d
index 90e21ef..5bacbc6 100644
--- a/gcc/testsuite/gdc.test/compilable/aliasdecl.d
+++ b/gcc/testsuite/gdc.test/compilable/aliasdecl.d
@@ -29,6 +29,13 @@ void main()
static assert(is(Y4 == void delegate() const));
static assert(is(Y5.Type == int));
+ // https://issues.dlang.org/show_bug.cgi?id=18429
+ struct S
+ {
+ alias a this;
+ enum a = 1;
+ }
+
/+ struct S
{
int value;
diff --git a/gcc/testsuite/gdc.test/compilable/art4769.d b/gcc/testsuite/gdc.test/compilable/art4769.d
index b962058..34adcda 100644
--- a/gcc/testsuite/gdc.test/compilable/art4769.d
+++ b/gcc/testsuite/gdc.test/compilable/art4769.d
@@ -1,6 +1,6 @@
// http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D.bugs&article_id=4769
-// EXTRA_SOURCES: imports/art4769a.d imports/art4769b.d
+// COMPILED_IMPORTS: imports/art4769a.d imports/art4769b.d
// PERMUTE_ARGS:
module art4769;
diff --git a/gcc/testsuite/gdc.test/compilable/b1215.d b/gcc/testsuite/gdc.test/compilable/b1215.d
index d3b0ccd..6828819 100644
--- a/gcc/testsuite/gdc.test/compilable/b1215.d
+++ b/gcc/testsuite/gdc.test/compilable/b1215.d
@@ -70,7 +70,7 @@ struct C(Args...)
alias Z = A!(B,B,C!(B,B));
/***************************************************/
-// 14889
+// https://issues.dlang.org/show_bug.cgi?id=14889
struct A14889(alias Exc)
{
@@ -85,7 +85,7 @@ alias X14889b = TT14889!(A14889!Throwable);
alias Y14889b = X14889b[0].ExceptionType;
/***************************************************/
-// 14889
+// https://issues.dlang.org/show_bug.cgi?id=14889
alias TypeTuple14900(T...) = T;
@@ -107,7 +107,7 @@ void test14900()
}
/***************************************************/
-// 14911
+// https://issues.dlang.org/show_bug.cgi?id=14911
void test14911()
{
@@ -119,7 +119,7 @@ void test14911()
}
/***************************************************/
-// 14986
+// https://issues.dlang.org/show_bug.cgi?id=14986
alias Id14986(alias a) = a;
diff --git a/gcc/testsuite/gdc.test/compilable/b12504.d b/gcc/testsuite/gdc.test/compilable/b12504.d
new file mode 100644
index 0000000..944ff6e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b12504.d
@@ -0,0 +1,44 @@
+// https://issues.dlang.org/show_bug.cgi?id=12504
+void main()
+{
+ {
+ int[0xFF + 1] sta;
+ foreach (ubyte i; 0 .. sta.length) {}
+ foreach (ubyte i, x; sta) {}
+ }
+ {
+ int[0x7F + 1] sta;
+ foreach (byte i; 0 .. sta.length) {}
+ foreach (byte i, x; sta) {}
+ }
+ {
+ int[0xFFFF + 1] sta;
+ foreach (ushort i; 0 .. sta.length) {}
+ foreach (ushort i, x; sta) {}
+ }
+ {
+ int[0x7FFF + 1] sta;
+ foreach (short i; 0 .. sta.length) {}
+ foreach (short i, x; sta) {}
+ }
+ {
+ immutable int[0xFF + 1] sta;
+ static foreach (ubyte i; 0 .. sta.length) {}
+ static foreach (ubyte i, x; sta) {}
+ }
+ {
+ immutable int[0x7F + 1] sta;
+ static foreach (byte i; 0 .. sta.length) {}
+ static foreach (byte i, x; sta) {}
+ }
+ {
+ immutable int[0xFFFF + 1] sta;
+ static foreach (ushort i; 0 .. sta.length) {}
+ static foreach (ushort i, x; sta) {}
+ }
+ {
+ immutable int[0x7FFF + 1] sta;
+ static foreach (short i; 0 .. sta.length) {}
+ static foreach (short i, x; sta) {}
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/b15206.d b/gcc/testsuite/gdc.test/compilable/b15206.d
new file mode 100644
index 0000000..13e7c00
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b15206.d
@@ -0,0 +1,19 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -O
+
+void main()
+{
+}
+
+struct Line
+{
+ double slope;
+ double intercept;
+}
+
+Line nLineProjection(double[] historicData)
+{
+ Line projLine;
+ projLine.intercept = historicData[$-1] + projLine.slope;
+ return projLine;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/b16360.d b/gcc/testsuite/gdc.test/compilable/b16360.d
new file mode 100644
index 0000000..1141579
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b16360.d
@@ -0,0 +1,39 @@
+/*
+REQUIRED_ARGS: -inline -wi
+
+TEST_OUTPUT:
+---
+compilable/b16360.d(12): Warning: cannot inline function `b16360.foo`
+compilable/b16360.d(25): Warning: cannot inline function `b16360.bar`
+---
+*/
+
+pragma(inline, true)
+auto foo()
+{
+ static struct U
+ {
+ int a = 42;
+ float b;
+ ~this(){} // __dtor: inline not allowed
+ }
+ U u;
+ return u.a;
+}
+
+pragma(inline, true)
+auto bar()
+{
+ class U // class : inline not allowed
+ {
+ int a = 42;
+ float b;
+ }
+ return (new U).a;
+}
+
+void main()
+{
+ auto f = foo();
+ auto b = bar();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/b16697.d b/gcc/testsuite/gdc.test/compilable/b16697.d
index 78c9a2b..680a9d4 100644
--- a/gcc/testsuite/gdc.test/compilable/b16697.d
+++ b/gcc/testsuite/gdc.test/compilable/b16697.d
@@ -1,13 +1,18 @@
-version(D_SIMD)
+static assert(!is( float == __vector));
+static assert(!is( float[1] == __vector));
+static assert(!is( float[4] == __vector));
+static assert(!is(__vector(float[3]) == __vector));
+static assert(!is(__vector(float[5]) == __vector));
+
+static if (__traits(compiles, __vector(float[4])))
{
- static assert(!is( float == __vector));
- static assert(!is( float[1] == __vector));
- static assert(!is( float[4] == __vector));
- static assert( is(__vector(float[4]) == __vector));
- static assert(!is(__vector(float[3]) == __vector));
- static assert(!is(__vector(float[5]) == __vector));
- static assert( is(__vector(float[4]) X == __vector) &&
- is(X == float[4]));
- static assert( is(__vector(byte[16]) X == __vector) &&
- is(X == byte[16]));
+ static assert(is(__vector(float[4]) == __vector));
+ static assert(is(__vector(float[4]) X == __vector) &&
+ is(X == float[4]));
+}
+
+static if (__traits(compiles, __vector(byte[16])))
+{
+ static assert(is(__vector(byte[16]) X == __vector) &&
+ is(X == byte[16]));
}
diff --git a/gcc/testsuite/gdc.test/compilable/b16967.d b/gcc/testsuite/gdc.test/compilable/b16967.d
index 2b02fc3..57bc1c1 100644
--- a/gcc/testsuite/gdc.test/compilable/b16967.d
+++ b/gcc/testsuite/gdc.test/compilable/b16967.d
@@ -1,4 +1,4 @@
-/*
+/*
* REQUIRED_ARGS: -c
* TEST_OUTPUT:
---
@@ -27,7 +27,7 @@ out(v)
break;
}
}
-body
+do
{
return 42;
}
diff --git a/gcc/testsuite/gdc.test/compilable/b17111.d b/gcc/testsuite/gdc.test/compilable/b17111.d
index 6bf5da9..9e79a20 100644
--- a/gcc/testsuite/gdc.test/compilable/b17111.d
+++ b/gcc/testsuite/gdc.test/compilable/b17111.d
@@ -1,16 +1,7 @@
-/*
-TEST_OUTPUT:
----
-compilable/b17111.d(16): Deprecation: `case` variables have to be `const` or `immutable`
-compilable/b17111.d(17): Deprecation: `case` variables have to be `const` or `immutable`
----
-*/
alias TestType = ubyte;
-void test()
+void test(immutable TestType a, immutable TestType b, TestType c)
{
- TestType a,b,c;
-
switch(c)
{
case a: break;
diff --git a/gcc/testsuite/gdc.test/compilable/b17651.d b/gcc/testsuite/gdc.test/compilable/b17651.d
new file mode 100644
index 0000000..9b41b9e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b17651.d
@@ -0,0 +1,6 @@
+// REQUIRED_ARGS: -c -D -Ddtest_results/compilable
+/**
+Macros:
+Escapes=/a/b/
+*/
+void foo() {}
diff --git a/gcc/testsuite/gdc.test/compilable/b18197.d b/gcc/testsuite/gdc.test/compilable/b18197.d
new file mode 100644
index 0000000..c6f92e1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b18197.d
@@ -0,0 +1,17 @@
+// REQUIRED_ARGS: -c -m32 -O -inline
+
+struct A
+{
+ double a;
+}
+
+A makeA(double value)
+{
+ return A(value);
+}
+
+double test(double x)
+{
+ ulong p = *cast(ulong *)&x;
+ return makeA(x).a;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/b18242.d b/gcc/testsuite/gdc.test/compilable/b18242.d
new file mode 100644
index 0000000..5dcaeca
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b18242.d
@@ -0,0 +1,19 @@
+// REQUIRED_ARGS: -c
+// PERMUTE_ARGS:
+module object;
+
+class Object { }
+
+class TypeInfo { }
+class TypeInfo_Class : TypeInfo
+{
+ version(D_LP64) { ubyte[136] _x; } else { ubyte[68] _x; }
+}
+
+class Throwable { }
+
+int _d_run_main()
+{
+ try { } catch(Throwable e) { return 1; }
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/b18489.d b/gcc/testsuite/gdc.test/compilable/b18489.d
new file mode 100644
index 0000000..2cc386f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b18489.d
@@ -0,0 +1,8 @@
+// REQUIRED_ARGS: -O -m64
+import core.simd;
+
+double dot (double2 a) {
+ return a.ptr[0] * a.ptr[1];
+}
+
+void main () { }
diff --git a/gcc/testsuite/gdc.test/compilable/b19432.d b/gcc/testsuite/gdc.test/compilable/b19432.d
new file mode 100644
index 0000000..cf0dd87
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b19432.d
@@ -0,0 +1,5 @@
+
+void main(){
+ enum a = 18446744073709551615; // 2^^64 - 1
+ ulong b = 18446744073709551615; // 2^^64 - 1
+}
diff --git a/gcc/testsuite/gdc.test/compilable/b19442.d b/gcc/testsuite/gdc.test/compilable/b19442.d
new file mode 100644
index 0000000..4e7e933
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b19442.d
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=19442
+enum x1 = 42;
+enum x2 = mixin('x', 1);
+enum x3 = mixin(wchar('x'), 2);
+enum x4 = mixin(dchar('x'), 3);
+static assert(x2 == 42);
+static assert(x3 == 42);
+static assert(x4 == 42);
+
+mixin(`enum string s = "`, wchar('ö'), dchar('ðŸº'), `";`);
+static assert(s == "öðŸº");
diff --git a/gcc/testsuite/gdc.test/compilable/b19775.d b/gcc/testsuite/gdc.test/compilable/b19775.d
new file mode 100644
index 0000000..ec504d4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b19775.d
@@ -0,0 +1,14 @@
+// https://issues.dlang.org/show_bug.cgi?id=19775
+enum x1 = 42;
+enum ident(alias a, args...) = mixin(a, args);
+
+//enum x2 = ident!("x1"); //FIXME - empty args
+enum x2 = x1;
+enum x3 = ident!("x", 2);
+enum x4 = ident!('x', "", 3);
+enum x5 = ident!("", 'x', 4);
+
+//static assert(x2 == 42);
+static assert(x3 == 42);
+static assert(x4 == 42);
+static assert(x5 == 42);
diff --git a/gcc/testsuite/gdc.test/compilable/b19829.d b/gcc/testsuite/gdc.test/compilable/b19829.d
new file mode 100644
index 0000000..7f4b282
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b19829.d
@@ -0,0 +1,4 @@
+static assert(!__traits(isSame, (i){ return i,x.value; }, a => a.value));
+static assert(!__traits(isSame, i => x[i].value, a => a.value));
+static assert(!__traits(isSame, i => [i].value, a => a.value));
+static assert(__traits(isSame, i => i.value, a => a.value));
diff --git a/gcc/testsuite/gdc.test/compilable/b20045.d b/gcc/testsuite/gdc.test/compilable/b20045.d
new file mode 100644
index 0000000..988bbca5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b20045.d
@@ -0,0 +1,2 @@
+alias U = const ubyte[uint.sizeof]*;
+static assert (is(U == const(ubyte[4]*)));
diff --git a/gcc/testsuite/gdc.test/compilable/b20067.d b/gcc/testsuite/gdc.test/compilable/b20067.d
new file mode 100644
index 0000000..af79cab
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b20067.d
@@ -0,0 +1,23 @@
+struct S1
+{
+ int i;
+ @property int ii(){return 0;}
+ @property bool b(){return true;}
+ alias empty = b;
+ alias front = ii;
+ void popFront(){}
+}
+struct S2
+{
+ int i;
+ bool b;
+ alias empty = b;
+ alias front = i;
+ void popFront(){}
+}
+
+void main()
+{
+ foreach(n; S1()) { } // 2.086: Error: cannot infer argument types
+ foreach(n; S2()) { } // 2.086: Error: cannot infer argument types
+}
diff --git a/gcc/testsuite/gdc.test/compilable/b20758.d b/gcc/testsuite/gdc.test/compilable/b20758.d
new file mode 100644
index 0000000..58b30b1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b20758.d
@@ -0,0 +1,15 @@
+module b20758;
+
+template foo(A...) { }
+
+int attr() {return 1;}
+@attr int y;
+
+alias A = __traits(getAttributes, y);
+alias B = __traits(getOverloads, b20758, "attr");
+static assert(__traits(isSame, foo!(A[0]), foo!(attr)));
+static assert(__traits(isSame, foo!(A), foo!(attr)));
+static assert(__traits(isSame, foo!(attr), foo!(B[0])));
+static assert(__traits(isSame, foo!(attr), foo!(B)));
+
+void main() { }
diff --git a/gcc/testsuite/gdc.test/compilable/b20780.d b/gcc/testsuite/gdc.test/compilable/b20780.d
new file mode 100644
index 0000000..366a2d9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b20780.d
@@ -0,0 +1,13 @@
+void main()
+{
+ struct A;
+ struct B { struct CD;}
+ alias V = void;
+ alias I = int;
+ V test0(@A I) {}
+ V test1(@A I p) {}
+ V test2(@A @(B) I) {}
+ V test3(@(B.CD) @B I) {}
+ V test4(@A I, @B @A I) {}
+ V test5(@A I p, @(B.CD) @A I ) {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/b20833.d b/gcc/testsuite/gdc.test/compilable/b20833.d
new file mode 100644
index 0000000..429d1f5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b20833.d
@@ -0,0 +1,20 @@
+struct A
+{
+ void foo(T)(T t) {}
+ void foo(long l) {}
+
+ void bar(long l) {}
+ void bar(T)(T t) {}
+}
+
+static assert(__traits(getOverloads, A, "foo").length == 1);
+static assert(__traits(getOverloads, A.init, "foo").length == 1);
+
+static assert(__traits(getOverloads, A, "foo", true).length == 2);
+static assert(__traits(getOverloads, A.init, "foo", true).length == 2);
+
+static assert(__traits(getOverloads, A, "bar").length == 1);
+static assert(__traits(getOverloads, A.init, "bar").length == 1);
+
+static assert(__traits(getOverloads, A, "bar", true).length == 2);
+static assert(__traits(getOverloads, A.init, "bar", true).length == 2);
diff --git a/gcc/testsuite/gdc.test/compilable/b20885.d b/gcc/testsuite/gdc.test/compilable/b20885.d
new file mode 100644
index 0000000..6e87184
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b20885.d
@@ -0,0 +1,16 @@
+module b20885;
+
+struct S
+{
+ alias P = void*;
+}
+
+void main()
+{
+ alias P = void*;
+ alias PP = void**;
+ PP[1] a = null;
+ if (const void** b = a[0]){} // OK
+ if (const P* b = a[0]){} // NG
+ if (const S.P* b = a[0]){} // NG
+}
diff --git a/gcc/testsuite/gdc.test/compilable/b20938.d b/gcc/testsuite/gdc.test/compilable/b20938.d
new file mode 100644
index 0000000..efcf4aa
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b20938.d
@@ -0,0 +1,22 @@
+// issue 20938 - Cannot create const arrays mixing immutable and mutable structs with indirections
+struct S { int[] a; }
+enum A { a }
+enum B { b }
+
+void fun() {
+ int* pi;
+ immutable int* ipi;
+ int[] ai;
+ immutable int[] iai;
+ S s;
+ immutable S _is;
+ Object o;
+ immutable Object io;
+
+ auto a = [pi, ipi];
+ auto b = [ai, iai];
+ auto c = [s, _is];
+ auto d = [o, io];
+
+ auto e = [A.a, B.b];
+}
diff --git a/gcc/testsuite/gdc.test/compilable/b21285.d b/gcc/testsuite/gdc.test/compilable/b21285.d
new file mode 100644
index 0000000..11eea74
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/b21285.d
@@ -0,0 +1,27 @@
+// REQUIRED_ARGS: -unittest
+// Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master).
+unittest
+{
+ string path;
+ int bank;
+ static string path2;
+ static int bank2;
+
+ // delegates
+ auto a = [
+ (string arg) { path = arg; },
+ (string arg) { bank = 1; throw new Exception(""); }
+ ];
+
+ // functions
+ auto ab = [
+ (string arg) { path2 = arg; },
+ (string arg) { bank2 = 1; throw new Exception(""); }
+ ];
+
+ alias dg = void delegate(string) pure @safe;
+ alias fn = void function(string) @safe;
+
+ static assert(is(typeof(a[0]) == dg));
+ static assert(is(typeof(ab[0]) == fn));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/b33.d b/gcc/testsuite/gdc.test/compilable/b33.d
index d422959..cba6fe2 100644
--- a/gcc/testsuite/gdc.test/compilable/b33.d
+++ b/gcc/testsuite/gdc.test/compilable/b33.d
@@ -1,4 +1,4 @@
-// EXTRA_SOURCES: imports/b33a.d
+// COMPILED_IMPORTS: imports/b33a.d
// PERMUTE_ARGS:
module b33;
diff --git a/gcc/testsuite/gdc.test/compilable/b6227.d b/gcc/testsuite/gdc.test/compilable/b6227.d
index 6ec2dd0..2a7700a 100644
--- a/gcc/testsuite/gdc.test/compilable/b6227.d
+++ b/gcc/testsuite/gdc.test/compilable/b6227.d
@@ -1,9 +1,3 @@
-/* TEST_OUTPUT:
----
-compilable/b6227.d(17): Deprecation: Comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType`
-compilable/b6227.d(18): Deprecation: Comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType`
----
-*/
enum X {
O,
R
@@ -14,5 +8,3 @@ enum Y {
static assert( (X.O == cast(const)X.O));
static assert( (X.O == X.O));
static assert( (X.O != X.R));
-static assert(!(X.O != Y.U));
-static assert( (X.O == Y.U));
diff --git a/gcc/testsuite/gdc.test/compilable/b6395.d b/gcc/testsuite/gdc.test/compilable/b6395.d
index afbe3f1..94f4bc3 100644
--- a/gcc/testsuite/gdc.test/compilable/b6395.d
+++ b/gcc/testsuite/gdc.test/compilable/b6395.d
@@ -1,7 +1,7 @@
// REQUIRED_ARGS: -Icompilable/extra-files
// EXTRA_FILES: extra-files/c6395.d
-// 6395
+// https://issues.dlang.org/show_bug.cgi?id=6395
import c6395;
diff --git a/gcc/testsuite/gdc.test/compilable/b6400.d b/gcc/testsuite/gdc.test/compilable/b6400.d
deleted file mode 100644
index 2c71107..0000000
--- a/gcc/testsuite/gdc.test/compilable/b6400.d
+++ /dev/null
@@ -1,37 +0,0 @@
-/* TEST_OUTPUT:
----
-Foo
-Bar
----
-*/
-class Foo
-{
- void opDispatch(string name)() { pragma(msg, "Foo"); }
-}
-class Bar
-{
- void opDispatch(string name)() { pragma(msg, "Bar"); }
-}
-class Baz
-{
-}
-
-void main()
-{
- auto foo = new Foo;
- auto bar = new Bar;
- auto baz = new Baz;
-
- with (foo)
- {
- f0();
- with (bar)
- {
- f1();
- }
- with (baz)
- {
- static assert(!__traits(compiles, f2()));
- }
- }
-}
diff --git a/gcc/testsuite/gdc.test/compilable/betterc.d b/gcc/testsuite/gdc.test/compilable/betterc.d
new file mode 100644
index 0000000..7df9bc2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/betterc.d
@@ -0,0 +1,27 @@
+/* REQUIRED_ARGS: -betterC
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=17787
+version (D_BetterC)
+{
+}
+else
+{
+ static assert(0);
+}
+
+// -betterC does not support `ModuleInfo`, `TypeInfo`, or exception handling
+version (D_ModuleInfo)
+{
+ static assert(0);
+}
+
+version (D_Exceptions)
+{
+ static assert(0);
+}
+
+version (D_TypeInfo)
+{
+ static assert(0);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/bug21196.d b/gcc/testsuite/gdc.test/compilable/bug21196.d
new file mode 100644
index 0000000..c2f9a43
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/bug21196.d
@@ -0,0 +1,31 @@
+/*
+REQUIRED_ARGS: -de
+*/
+
+// This test can be removed once the deprecation period is over
+deprecated void appendSlices ( Types ... ) ( ref void[][] slices, ref Types x )
+{
+ foreach (i, T; Types)
+ {
+ static if (is(T Element: Element[]))
+ {
+ static if (is(T == Element[]))
+ {
+ slices ~= (cast(void*)(&x[i]))[0 .. size_t.sizeof];
+ }
+ // Append a slice to the array content.
+ slices ~= x[i];
+ }
+ else
+ {
+ slices ~= (cast(void*)(&x[i]))[0 .. x[i].sizeof];
+ }
+ }
+}
+
+deprecated void myTest()
+{
+ void[][] slices;
+ char[] str = "Hello World!".dup;
+ appendSlices(slices, str);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/callconv.d b/gcc/testsuite/gdc.test/compilable/callconv.d
index 145ebb1..42c47d8 100644
--- a/gcc/testsuite/gdc.test/compilable/callconv.d
+++ b/gcc/testsuite/gdc.test/compilable/callconv.d
@@ -1,10 +1,9 @@
// PERMUTE_ARGS:
-
import core.stdc.stdarg;
struct ABC
{
- int x[4];
+ int[4] x;
}
ABC abc;
diff --git a/gcc/testsuite/gdc.test/compilable/ccompile.d b/gcc/testsuite/gdc.test/compilable/ccompile.d
new file mode 100644
index 0000000..22c749c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ccompile.d
@@ -0,0 +1,36 @@
+
+/* REQUIRED_ARGS: -O
+ */
+
+// Adapted from DMC++ test file test3/ccompile.c
+
+
+ struct HDS {
+ char state;
+ uint done;
+ uint retry;
+ uint[15] tests;
+ }
+
+void funchds(char *p_adults)
+{
+ int cupx, chemx;
+ HDS *p_cup;
+
+ for (cupx = 1, p_cup = null; cupx <= 48 ; cupx ++, p_cup ++)
+ {
+ for (chemx = 0; chemx < 15 ; chemx++)
+ {
+ if (p_cup.done) {
+ if (p_cup.tests [chemx]) {
+ *p_adults++ = 3;
+ }
+ if (p_cup.done && (p_cup.tests [chemx])) {
+ *p_adults++ = 4;
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/gcc/testsuite/gdc.test/compilable/cdcmp.d b/gcc/testsuite/gdc.test/compilable/cdcmp.d
new file mode 100644
index 0000000..614bdc8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/cdcmp.d
@@ -0,0 +1,148 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -O
+// POST_SCRIPT: compilable/extra-files/objdump-postscript.sh
+// only testing on SYSV-ABI, but backend code is identical across platforms
+// DISABLED: win32 win64 osx linux32 freebsd32 freebsd64
+
+bool test_ltz(ubyte x) { return x < 0; }
+bool test_lez(ubyte x) { return x <= 0; }
+bool test_eqz(ubyte x) { return x == 0; }
+bool test_nez(ubyte x) { return x != 0; }
+bool test_gez(ubyte x) { return x >= 0; }
+bool test_gtz(ubyte x) { return x > 0; }
+
+bool test_ltz(byte x) { return x < 0; }
+bool test_lez(byte x) { return x <= 0; }
+bool test_eqz(byte x) { return x == 0; }
+bool test_nez(byte x) { return x != 0; }
+bool test_gez(byte x) { return x >= 0; }
+bool test_gtz(byte x) { return x > 0; }
+
+bool test_ltz(ushort x) { return x < 0; }
+bool test_lez(ushort x) { return x <= 0; }
+bool test_eqz(ushort x) { return x == 0; }
+bool test_nez(ushort x) { return x != 0; }
+bool test_gez(ushort x) { return x >= 0; }
+bool test_gtz(ushort x) { return x > 0; }
+
+bool test_ltz(short x) { return x < 0; }
+bool test_lez(short x) { return x <= 0; }
+bool test_eqz(short x) { return x == 0; }
+bool test_nez(short x) { return x != 0; }
+bool test_gez(short x) { return x >= 0; }
+bool test_gtz(short x) { return x > 0; }
+
+bool test_ltz(uint x) { return x < 0; }
+bool test_lez(uint x) { return x <= 0; }
+bool test_eqz(uint x) { return x == 0; }
+bool test_nez(uint x) { return x != 0; }
+bool test_gez(uint x) { return x >= 0; }
+bool test_gtz(uint x) { return x > 0; }
+
+bool test_ltz(int x) { return x < 0; }
+bool test_lez(int x) { return x <= 0; }
+bool test_eqz(int x) { return x == 0; }
+bool test_nez(int x) { return x != 0; }
+bool test_gez(int x) { return x >= 0; }
+bool test_gtz(int x) { return x > 0; }
+
+bool test_ltz(ulong x) { return x < 0; }
+bool test_lez(ulong x) { return x <= 0; }
+bool test_eqz(ulong x) { return x == 0; }
+bool test_nez(ulong x) { return x != 0; }
+bool test_gez(ulong x) { return x >= 0; }
+bool test_gtz(ulong x) { return x > 0; }
+
+bool test_ltz(long x) { return x < 0; }
+bool test_lez(long x) { return x <= 0; }
+bool test_eqz(long x) { return x == 0; }
+bool test_nez(long x) { return x != 0; }
+bool test_gez(long x) { return x >= 0; }
+bool test_gtz(long x) { return x > 0; }
+
+bool test_ltz(float x) { return x < 0; }
+bool test_lez(float x) { return x <= 0; }
+bool test_eqz(float x) { return x == 0; }
+bool test_nez(float x) { return x != 0; }
+bool test_gez(float x) { return x >= 0; }
+bool test_gtz(float x) { return x > 0; }
+
+bool test_ltz(double x) { return x < 0; }
+bool test_lez(double x) { return x <= 0; }
+bool test_eqz(double x) { return x == 0; }
+bool test_nez(double x) { return x != 0; }
+bool test_gez(double x) { return x >= 0; }
+bool test_gtz(double x) { return x > 0; }
+
+/* ----------------------------------- */
+
+bool test_lt(ubyte x, ubyte y) { return x < y; }
+bool test_le(ubyte x, ubyte y) { return x <= y; }
+bool test_eq(ubyte x, ubyte y) { return x == y; }
+bool test_ne(ubyte x, ubyte y) { return x != y; }
+bool test_ge(ubyte x, ubyte y) { return x >= y; }
+bool test_gt(ubyte x, ubyte y) { return x > y; }
+
+bool test_lt(byte x, byte y) { return x < y; }
+bool test_le(byte x, byte y) { return x <= y; }
+bool test_eq(byte x, byte y) { return x == y; }
+bool test_ne(byte x, byte y) { return x != y; }
+bool test_ge(byte x, byte y) { return x >= y; }
+bool test_gt(byte x, byte y) { return x > y; }
+
+bool test_lt(ushort x, ushort y) { return x < y; }
+bool test_le(ushort x, ushort y) { return x <= y; }
+bool test_eq(ushort x, ushort y) { return x == y; }
+bool test_ne(ushort x, ushort y) { return x != y; }
+bool test_ge(ushort x, ushort y) { return x >= y; }
+bool test_gt(ushort x, ushort y) { return x > y; }
+
+bool test_lt(short x, short y) { return x < y; }
+bool test_le(short x, short y) { return x <= y; }
+bool test_eq(short x, short y) { return x == y; }
+bool test_ne(short x, short y) { return x != y; }
+bool test_ge(short x, short y) { return x >= y; }
+bool test_gt(short x, short y) { return x > y; }
+
+bool test_lt(uint x, uint y) { return x < y; }
+bool test_le(uint x, uint y) { return x <= y; }
+bool test_eq(uint x, uint y) { return x == y; }
+bool test_ne(uint x, uint y) { return x != y; }
+bool test_ge(uint x, uint y) { return x >= y; }
+bool test_gt(uint x, uint y) { return x > y; }
+
+bool test_lt(int x, int y) { return x < y; }
+bool test_le(int x, int y) { return x <= y; }
+bool test_eq(int x, int y) { return x == y; }
+bool test_ne(int x, int y) { return x != y; }
+bool test_ge(int x, int y) { return x >= y; }
+bool test_gt(int x, int y) { return x > y; }
+
+bool test_lt(ulong x, ulong y) { return x < y; }
+bool test_le(ulong x, ulong y) { return x <= y; }
+bool test_eq(ulong x, ulong y) { return x == y; }
+bool test_ne(ulong x, ulong y) { return x != y; }
+bool test_ge(ulong x, ulong y) { return x >= y; }
+bool test_gt(ulong x, ulong y) { return x > y; }
+
+bool test_lt(long x, long y) { return x < y; }
+bool test_le(long x, long y) { return x <= y; }
+bool test_eq(long x, long y) { return x == y; }
+bool test_ne(long x, long y) { return x != y; }
+bool test_ge(long x, long y) { return x >= y; }
+bool test_gt(long x, long y) { return x > y; }
+
+bool test_lt(float x, float y) { return x < y; }
+bool test_le(float x, float y) { return x <= y; }
+bool test_eq(float x, float y) { return x == y; }
+bool test_ne(float x, float y) { return x != y; }
+bool test_ge(float x, float y) { return x >= y; }
+bool test_gt(float x, float y) { return x > y; }
+
+bool test_lt(double x, double y) { return x < y; }
+bool test_le(double x, double y) { return x <= y; }
+bool test_eq(double x, double y) { return x == y; }
+bool test_ne(double x, double y) { return x != y; }
+bool test_ge(double x, double y) { return x >= y; }
+bool test_gt(double x, double y) { return x > y; }
+
diff --git a/gcc/testsuite/gdc.test/compilable/chkformat.d b/gcc/testsuite/gdc.test/compilable/chkformat.d
new file mode 100644
index 0000000..ccbe974
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/chkformat.d
@@ -0,0 +1,27 @@
+// https://issues.dlang.org/show_bug.cgi?id=20643
+// https://issues.dlang.org/show_bug.cgi?id=20644
+/*
+TEST_OUTPUT:
+----
+compilable/chkformat.d(14): Deprecation: more format specifiers than 0 arguments
+----
+*/
+import core.stdc.stdio;
+
+void main()
+{
+ // b20643
+ printf("%d \n");
+
+ // b20644
+ ubyte b;
+ printf("%hhu \n", b);
+
+ char c = '-';
+ printf("%c", c);
+
+ short s;
+ printf("%hd", s);
+
+ printf("%hn", &s);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/commontype.d b/gcc/testsuite/gdc.test/compilable/commontype.d
new file mode 100644
index 0000000..076e29b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/commontype.d
@@ -0,0 +1,486 @@
+// REQUIRED_ARGS: -mcpu=avx2
+
+import core.simd;
+
+
+version = CondExp;
+//version = ReturnInfer;
+
+T rvalueOf(T)();
+
+version (CondExp)
+{
+ alias X(T, U) = typeof(0 ? rvalueOf!T : rvalueOf!U);
+}
+else version (ReturnInfer)
+{
+ alias X(T, U) = typeof({ if (0) return rvalueOf!T; else return rvalueOf!U;}());
+}
+else
+ static assert(0);
+
+enum Error(T, U) = !__traits(compiles, X!(T, U));
+
+
+interface I {}
+class B {}
+class C : B, I {}
+class D : B {}
+class K {}
+struct SI { I o; alias o this; }
+struct SC { C o; alias o this; }
+struct SB { B o; alias o this; }
+struct SD { D o; alias o this; }
+struct SK { K o; alias o this; }
+struct SiC { immutable(C) o; alias o this; }
+
+struct S { int a; }
+struct Si { int a; alias a this; }
+struct Si2 { int a; alias a this; }
+struct Sl { long a; alias a this; }
+
+/******************************
+ * Basic types
+ */
+
+static assert(is( X!( byte, byte ) == byte ));
+static assert(is( X!( ubyte, ubyte ) == ubyte ));
+static assert(is( X!( byte, ubyte ) == int ));
+static assert(is( X!( byte, short ) == int ));
+static assert(is( X!( byte, ushort ) == int ));
+static assert(is( X!( byte, const(byte) ) == int ));
+static assert(is( X!( ubyte, const(ubyte) ) == int ));
+
+static assert(is( X!( short, short ) == short ));
+static assert(is( X!( ushort, ushort ) == ushort ));
+static assert(is( X!( short, ushort ) == int ));
+static assert(is( X!( short, const(short) ) == int ));
+static assert(is( X!( ushort, const(ushort) ) == int ));
+
+static assert(is( X!( int, int ) == int ));
+static assert(is( X!( int, uint ) == uint ));
+static assert(is( X!( uint, uint ) == uint ));
+
+static assert(is( X!( int, long ) == long ));
+static assert(is( X!( int, ulong ) == ulong ));
+
+static assert(is( X!( float, float ) == float ));
+static assert(is( X!( float, int ) == float ));
+static assert(is( X!( float, uint ) == float ));
+static assert(is( X!( float, long ) == float ));
+static assert(is( X!( float, ulong ) == float ));
+static assert(is( X!( float, double ) == double ));
+static assert(is( X!( float, real ) == real ));
+
+static assert(is( X!( char, char ) == char ));
+static assert(is( X!( char, byte ) == int ));
+static assert(is( X!( char, ubyte ) == int ));
+static assert(is( X!( char, wchar ) == dchar ));
+static assert(is( X!( char, dchar ) == dchar ));
+static assert(is( X!( char, const(char) ) == const(char) ));
+static assert(is( X!( wchar, const(wchar) ) == const(wchar) ));
+static assert(is( X!( dchar, const(dchar) ) == const(dchar) ));
+static assert(is( X!( char, immutable(char) ) == const(char) ));
+static assert(Error!( char, shared(char) ));
+
+static assert(is( X!( char, float ) == float ));
+
+static assert(is( X!( immutable(int), int ) == int ));
+static assert(is( X!( const(int), int ) == int ));
+static assert(is( X!( shared(int), int ) == int ));
+static assert(is( X!( immutable(int), const(shared(int)) ) == int ));
+static assert(is( X!( shared(int), const(int) ) == int ));
+
+/******************************
+ * Strings
+ */
+
+static assert(is( X!( string, string ) == string ));
+static assert(Error!( wstring, string ));
+static assert(Error!( dstring, string ));
+static assert(Error!( dstring, wstring ));
+static assert(is( X!( const(char)[], string ) == const(char)[] ));
+static assert(is( X!( char[], string ) == const(char)[] ));
+static assert(is( X!( string, immutable(string) ) == immutable(string) )); // `const`
+static assert(is( X!( immutable(string), string ) == string )); // not commutative
+
+/******************************
+ * Enums
+ */
+
+enum Ei : int { a, }
+enum Eb : byte { a, }
+enum Ec : char { a, }
+enum Ew : wchar { a, }
+
+static assert(is( X!( Ei, Ei ) == Ei ));
+static assert(is( X!( Ei, const(Ei) ) == const(Ei) ));
+static assert(is( X!( Ei, immutable(Ei) ) == const(Ei) ));
+static assert(is( X!( Eb, Eb ) == Eb ));
+static assert(is( X!( Eb, const(Eb) ) == int ));
+static assert(is( X!( Eb, immutable(Eb) ) == int ));
+static assert(is( X!( Ei, Eb ) == int ));
+static assert(is( X!( Ei, const(Eb) ) == int ));
+static assert(is( X!( Ei, immutable(Eb) ) == int ));
+
+static assert(is( X!( Ec, Ec ) == Ec ));
+static assert(is( X!( Ec, const(Ec) ) == const(char) ));
+static assert(is( X!( Ec, immutable(Ec) ) == const(char) ));
+static assert(is( X!( Ew, Ew ) == Ew ));
+static assert(is( X!( Ew, const(Ew) ) == const(wchar) ));
+static assert(is( X!( Ew, immutable(Ew) ) == const(wchar) ));
+static assert(is( X!( Ew, Ec ) == dchar ));
+static assert(is( X!( Ew, const(Ec) ) == dchar ));
+static assert(is( X!( Ew, immutable(Ec) ) == dchar ));
+
+/******************************
+ * Tuple
+ */
+
+alias Tuple(Args...) = Args;
+static assert(!__traits(compiles ,typeof(0 ? Tuple!1 : Tuple!1)));
+
+/******************************
+ * Pointers
+ */
+
+static assert(is( X!( int*, int* ) == int* ));
+static assert(is( X!( const(int*), const(int)* ) == const(int*) ));
+static assert(is( X!( const(int)*, const(int*) ) == const(int)* )); // not commutative
+static assert(Error!( uint*, int* ));
+static assert(is( X!( int function(), int function() ) == int function() ));
+
+// void pointer
+static assert(is( X!( void*, int* ) == int* ));
+static assert(is( X!( int*, void* ) == int* ));
+static assert(is( X!( const(int)*, void* ) == const(int)* ));
+static assert(is( X!( const(int*), void* ) == const(int*) ));
+static assert(is( X!( int*, const(void)* ) == int* )); // `const`
+static assert(is( X!( int*, const(void*) ) == int* )); // `const`
+static assert(is( X!( int*, shared(void*) ) == int* )); // should fail
+static assert(is( X!( int*, shared(void)* ) == int* )); // should fail
+
+static assert(Error!( int**, void** )); // should work
+
+static assert(is( X!( void*, int function() ) == int function() ));
+static assert(is( X!( immutable(void*), int function() ) == int function() )); // `const`
+
+// implicit conversion
+static assert(is( X!( int*, const(int*) ) == const(int*) ));
+static assert(is( X!( int*, const(int)* ) == const(int)* ));
+static assert(is( X!( int***, const(int)*** ) == const(int**)* ));
+static assert(is( X!( immutable(int)***, const(int)*** ) == const(int**)* ));
+static assert(is( X!( immutable(int)***, const(shared(int))*** ) == const(shared(int)**)* ));
+
+// common modifier
+static assert(is( X!( immutable(int)*, int* ) == const(int)* ));
+static assert(is( X!( immutable(int*), int* ) == const(int)* ));
+static assert(is( X!( immutable(int)*, shared(int)* ) == shared(const(int))* ));
+static assert(Error!( shared(int)*, int* ));
+
+static assert(is( X!( immutable(int)***, int*** ) == const(int**)* )); // `const(int)***`
+static assert(is( X!( shared(const(int)***), shared(int***) ) == const(shared(int*)*)* )); // `shared(const(int)***)`
+static assert(is( X!( shared(const(int)***), shared(int**)* ) == const(shared(int*)*)* ));
+static assert(Error!( shared(const(int)***), shared(int*)** ));
+
+
+// class pointer
+static assert(is( X!( C*, B* ) == B* ));
+static assert(is( X!( const(C)*, B* ) == const(B)* ));
+static assert(Error!( shared(C)*, B* ));
+static assert(is( X!( immutable(C)*, B* ) == const(B)* ));
+static assert(is( X!( immutable(C*), B* ) == const(B)* ));
+static assert(is( X!( C**, B** ) == const(B*)* )); // `B**`
+static assert(is( X!( B**, C** ) == const(B*)* )); // `B**`
+static assert(is( X!( C***, B*** ) == const(B**)* )); // `B***`
+
+static assert(is( X!( C*, I* ) == I* ));
+static assert(is( X!( I*, C* ) == I* ));
+static assert(Error!( C**, I** ));
+
+static assert(Error!( C*, D* )); // should work
+
+// function pointer
+static assert(is( X!( immutable(int function()), int function() ) == immutable(int function()) ));
+static assert(is( X!( int function(), immutable(int function()) ) == int function() )); // not commutative
+static assert(is( X!( int function(), shared(int function()) ) == int function() ));
+
+static assert(is( X!( int function(), const(int) function() ) == const(int) function() ));
+static assert(is( X!( int function(), immutable(int) function() ) == immutable(int) function() )); // `const`
+static assert(is( X!( immutable(int) function(), int function() ) == int function() )); // not commutative
+
+static assert(Error!( uint function(), int function() ));
+
+static assert(is( X!( C function(), B function() ) == B function() ));
+static assert(is( X!( B function(), C function() ) == B function() ));
+static assert(is( X!( C function(), const(B) function() ) == const(B) function() ));
+static assert(Error!( const(C) function(), B function() )); // should work
+static assert(Error!( C* function(), B* function() )); // should work
+static assert(Error!( C function(), I function() ));
+static assert(Error!( C* function(), I* function() ));
+
+static assert(is( X!( C delegate(), B delegate() ) == B delegate() ));
+static assert(Error!( C delegate(), I delegate() ));
+
+static assert(Error!( C function(), D function() )); // should work
+
+static assert(Error!( void function(int), void function(const(int)) )); // should work
+
+static assert(Error!( void function(C), void function(B) ));
+static assert(Error!( void function(C*), void function(B*) ));
+static assert(Error!( void function(const(C)*), void function(B*) ));
+static assert(is( X!( void function(C*), void function(const(B*)) ) == void function(C*) )); // !?
+
+static assert(is( X!( void function(C), void function(const(C)) ) == void function(C) ));
+static assert(is( X!( void function(C), void function(const(C)) ) == void function(C) ));
+
+static assert(is( X!( void function() pure nothrow @nogc @safe, void function() ) == void function() ));
+static assert(is( X!( void function() pure @safe, void function() @nogc ) == void function() ));
+static assert(is( X!( void function() pure @trusted, void function() nothrow @safe ) == void function() @trusted ));
+static assert(is( X!( void function() @trusted, void function() ) == void function()));
+static assert(is( X!( void function() @trusted, void function() @trusted ) == void function() @trusted ));
+static assert(is( X!( void function() @safe, void function() @trusted ) == void function() @trusted ));
+static assert(is( X!( void function() @trusted, void function() @safe ) == void function() @safe )); // not commutative
+
+static assert(is( X!( const(int function())*, int function()* ) == const(int function())* ));
+static assert(is( X!( immutable(int function())*, int function()* ) == const(int function())* ));
+static assert(Error!( shared(int function())*, int function()* ));
+static assert(is( X!( shared(int function())*, immutable(int function())* ) == shared(const(int function()))* ));
+
+
+/******************************
+ * Arrays
+ */
+
+static assert(is( X!( int[4], int[4] ) == int[4] ));
+static assert(is( X!( int[], int[] ) == int[] ));
+
+// static array modifier conversion
+static assert(is( X!( const(int)[4], int[4] ) == int[4] ));
+static assert(is( X!( int[4], const(int)[4] ) == const(int)[4] )); // not commutative
+static assert(is( X!( const(int)[4], immutable(int)[4] ) == immutable(int)[4] ));
+static assert(is( X!( immutable(int)[4], const(int)[4] ) == const(int)[4] )); // not commutative
+static assert(is( X!( int[4], immutable(int)[4] ) == immutable(int)[4] ));
+static assert(is( X!( immutable(int)[4], int[4] ) == int[4] )); // not commutative
+static assert(Error!( shared(int)[4], int[4] )); // should work
+static assert(Error!( int[4], shared(int)[4] )); // should work
+static assert(Error!( shared(int)[4], const(int)[4] )); // should work
+static assert(Error!( const(int)[4] , shared(int)[4])); // should work
+static assert(is( X!( shared(const(int))[4], shared(int)[4] ) == shared(int)[4] ));
+static assert(is( X!( shared(int)[4], shared(const(int))[4] ) == shared(const(int))[4] )); // not commutative
+static assert(is( X!( shared(const(int))[4], immutable(int)[4] ) == shared(const(int))[4] ));
+static assert(is( X!( immutable(int)[4], shared(const(int))[4] ) == shared(const(int))[4] ));
+
+static assert(is( X!( immutable(int)[4], shared(int)[4] ) == shared(const(int))[] )); // `[4]`
+static assert(is( X!( shared(int)[4], immutable(int)[4] ) == shared(const(int))[] )); // `[4]`
+
+static assert(is( X!( int*[4], const(int)*[4] ) == const(int)*[4]));
+static assert(is( X!( const(int)*[4], int*[4] ) == const(int)*[4]));
+static assert(is( X!( immutable(int)*[4], const(int)*[4] ) == const(int)*[4]));
+static assert(is( X!( const(int)*[4], immutable(int)*[4] ) == const(int)*[4]));
+static assert(Error!( int*[4], immutable(int)*[4] )); // should work
+static assert(Error!( immutable(int)*[4], int*[4] )); // should work
+static assert(Error!( int*[4], shared(int)*[4] ));
+static assert(Error!( shared(int)*[4], int*[4] ));
+static assert(Error!( shared(int)*[4], immutable(int)*[4] )); // should work
+static assert(Error!( immutable(int)*[4], shared(int)*[4] )); // should work
+static assert(is( X!( shared(const(int))*[4], shared(int)*[4] ) == shared(const(int))*[4] ));
+static assert(is( X!( shared(int)*[4], shared(const(int))*[4] ) == shared(const(int))*[4] ));
+
+static assert(is( X!( C[4], const(C)[4] ) == const(C)[4] ));
+static assert(is( X!( const(C)[4], C[4] ) == const(C)[4] ));
+static assert(is( X!( C[4], immutable(C)[4] ) == const(C)[] )); // `[4]`
+static assert(is( X!( immutable(C)[4], C[4] ) == const(C)[] )); // `[4]`
+static assert(Error!( shared(C)[4], C[4] ));
+static assert(Error!( C[4], shared(C)[4] ));
+static assert(is( X!( shared(C)[4], immutable(C)[4] ) == shared(const(C))[] )); // `[4]`
+static assert(is( X!( immutable(C)[4], shared(C)[4] ) == shared(const(C))[] )); // `[4]`
+static assert(is( X!( shared(const(C))[4], shared(C)[4] ) == shared(const(C))[4] ));
+static assert(is( X!( shared(C)[4], shared(const(C))[4] ) == shared(const(C))[4] ));
+
+// base class conversion
+static assert(is( X!(C[4], B[4]) ));
+static assert(Error!( C[4], I[4] ));
+static assert(Error!( C[4], D[4] ));
+static assert(is( X!( C[4], const(B)[4] ) == const(B)[4] ));
+static assert(Error!( C[4], const(I)[4] ));
+static assert(Error!( C[4], const(D)[4] ));
+static assert(Error!( C*[4], B*[4] ));
+static assert(Error!( C*[4], I*[4] ));
+static assert(Error!( C*[4], D*[4] ));
+static assert(is( X!( C*[4], const(B*)[4] ) == const(B*)[] )); // !?
+static assert(Error!( C*[4], const(I*)[4] ));
+static assert(Error!( C*[4], const(D*)[4] ));
+static assert(Error!( C*[4], B**[4] ));
+static assert(Error!( C*[4], const(B*)*[4] ));
+static assert(Error!( C*[4], const(B**)[4] ));
+
+// static to dynamic
+static assert(is( X!( int[4], void[4] ) == void[] ));
+static assert(is( X!( void[4], int[4] ) == void[] ));
+static assert(is( X!( int[4], int[3] ) == int[] ));
+static assert(is( X!( int[4], const(int)[3] ) == const(int)[] ));
+static assert(is( X!( int[4], int[] ) == int[] ));
+static assert(is( X!( const(int)[4], int[] ) == const(int)[] ));
+static assert(is( X!( int[4], const(int)[] ) == const(int)[] ));
+static assert(is( X!( int[4], void[] ) == void[] ));
+static assert(is( X!( const(int)[4], void[] ) == const(void)[] ));
+static assert(Error!( int*[4], void*[4] )); // should work
+static assert(Error!( int*[4], void*[] )); // should work
+static assert(is( X!( int*[4], int*[] ) == int*[] ));
+static assert(is( X!( const(int*)[4], int*[] ) == const(int*)[] ));
+static assert(is( X!( int*[4], const(int*)[] ) == const(int*)[] ));
+static assert(Error!( const(int)*[4], int*[] )); // should work
+static assert(Error!( int*[4], const(int)*[] )); // should work
+static assert(Error!( int[4], long[] ));
+static assert(Error!( int[4], uint[] ));
+static assert(Error!( int[4], short[] ));
+static assert(Error!( C[4], B[] ));
+static assert(Error!( C[4], I[] ));
+static assert(Error!( C[4], D[] ));
+static assert(Error!( C*[4], B*[] ));
+static assert(Error!( C*[4], I*[] ));
+static assert(Error!( C*[4], D*[] ));
+
+// dynamic arrays
+static assert(is( X!( int[], int[] ) == int[] ));
+static assert(is( X!( int[], const(int)[] ) == const(int)[] ));
+static assert(is( X!( const(int)[], int[] ) == const(int)[] ));
+static assert(is( X!( int[], immutable(int)[] ) == const(int)[] ));
+static assert(is( X!( immutable(int)[], int[] ) == const(int)[] ));
+static assert(Error!( int[], shared(int)[] ));
+static assert(Error!( shared(int)[], int[] ));
+static assert(is( X!( shared(int)[], immutable(int)[] ) == shared(const(int))[] ));
+static assert(is( X!( immutable(int)[], shared(int)[] ) == shared(const(int))[] ));
+static assert(Error!( const(int)[], shared(int)[] ));
+static assert(Error!( shared(int)[], const(int)[] ));
+
+static assert(is( X!( int[], void[] ) == void[] ));
+static assert(is( X!( void[], int[] ) == void[] ));
+static assert(is( X!( int[], const(void)[] ) == const(void)[] ));
+static assert(is( X!( const(int)[], void[] ) == const(void)[] ));
+
+static assert(is( X!( int*[], const(int*)[] ) == const(int*)[] ));
+static assert(is( X!( const(int*)[], int*[] ) == const(int*)[] ));
+static assert(Error!( int*[], const(int)*[] )); // should work
+static assert(Error!( const(int)*[], int*[] )); // should work
+
+static assert(is( X!( C[], const(C)[] ) == const(C)[] ));
+static assert(is( X!( const(C)[], C[] ) == const(C)[] ));
+
+static assert(Error!( int[], long[] ));
+static assert(Error!( int[], uint[] ));
+static assert(Error!( int[], short[] ));
+
+static assert(Error!( C[], B[] ));
+static assert(Error!( C[], I[] ));
+static assert(Error!( C[], D[] ));
+static assert(Error!( C*[], B*[] ));
+static assert(Error!( C*[], I*[] ));
+static assert(Error!( C*[], D*[] ));
+
+/******************************
+ * Associative arrays
+ */
+
+static assert(is( X!( int[int], int[int] ) == int[int] ));
+static assert(Error!( const(int[int]), int[int] )); // should work
+static assert(Error!( immutable(int[int]), int[int] )); // should work
+static assert(Error!( shared(int[int]), int[int] ));
+
+/******************************
+ * Classes
+ */
+
+static assert(Error!( C, void* ));
+static assert(Error!( void*, C ));
+
+static assert(is( X!( C, C ) == C ));
+static assert(is( X!( C, B ) == B ));
+static assert(is( X!( C, I ) == I ));
+static assert(is( X!( C, D ) == B ));
+static assert(is( X!( C, K ) == Object ));
+
+static assert(is( X!( C, SC ) == C ));
+static assert(is( X!( C, SB ) == B ));
+static assert(is( X!( C, SI ) == I ));
+static assert(is( X!( C, SD ) == B ));
+static assert(is( X!( C, SK ) == Object ));
+
+static assert(is( X!( C, immutable(C) ) == const(C) ));
+static assert(is( X!( C, immutable(I) ) == const(I) ));
+static assert(is( X!( C, immutable(B) ) == const(B) ));
+static assert(is( X!( C, immutable(D) ) == const(B) ));
+static assert(is( X!( C, immutable(K) ) == const(Object) ));
+
+static assert(Error!( C, immutable(SC) )); // should work
+static assert(Error!( C, immutable(SI) )); // should work
+static assert(Error!( immutable(SI), C )); // should work
+static assert(Error!( C, immutable(SB) )); // should work
+static assert(Error!( C, immutable(SD) )); // should work
+static assert(Error!( C, immutable(SK) )); // should work
+
+static assert(is( X!( const(C), C ) == const(C) ));
+static assert(is( X!( const(C), I ) == const(I) ));
+static assert(is( X!( const(C), B ) == const(B) ));
+static assert(is( X!( const(C), D ) == const(B) ));
+static assert(is( X!( const(C), K ) == const(Object) ));
+
+static assert(is( X!( const(C), SC ) == const(C)));
+static assert(Error!( const(C), SI )); // should work
+static assert(is( X!( const(SI), const(C) ) == const(I) )); // should work
+static assert(is( X!( const(C), SB ) == const(B)));
+static assert(is( X!( const(C), SD ) == const(B)));
+static assert(is( X!( const(C), SK ) == Object)); // `const`
+
+static assert(is( X!( SiC, SC ) == const(C) ));
+
+/******************************
+ * Structs
+ */
+
+static assert(is( X!( S, S ) == S ));
+static assert(is( X!( S, immutable(S) ) == const(S) ));
+static assert(Error!( S, shared(S) ));
+static assert(is( X!( Si, Si ) == Si ));
+static assert(is( X!( Si, int ) == int ));
+static assert(is( X!( int, Si ) == int ));
+static assert(is( X!( Si, Si2 ) == int ));
+
+static assert(is( X!( int, Sl ) == long ));
+static assert(is( X!( Si, Sl ) == long ));
+
+
+/******************************
+ * Vectors
+ */
+
+static if (__traits(compiles, int4))
+{
+ static assert(is( X!( int4, int4 ) == int4));
+ static assert(is( X!( int4, const(int4) ) == const(int4)));
+ static assert(is( X!( int4, immutable(int4) ) == const(int4)));
+ static assert(is( X!( __vector(const(int)[4]), int4 ) == int4));
+ static assert(is( X!( int4, __vector(const(int)[4]) ) == int4));
+
+ static assert(Error!( int[4], int4 ));
+ static assert(Error!( int4, int[4] ));
+}
+
+static if (__traits(compiles, { byte16 a; void16 b; })) static assert(Error!( byte16, void16 ));
+static if (__traits(compiles, { int4 a; void16 b; })) static assert(Error!( int4, void16 ));
+static if (__traits(compiles, { float4 a; void16 b; })) static assert(Error!( float4, void16 ));
+static if (__traits(compiles, { byte16 a; ubyte16 b; })) static assert(Error!( byte16, ubyte16 ));
+static if (__traits(compiles, { short8 a; ushort8 b; })) static assert(Error!( short8, ushort8 ));
+static if (__traits(compiles, { int4 a; uint4 b; })) static assert(Error!( int4, uint4 ));
+static if (__traits(compiles, { int4 a; float4 b; })) static assert(Error!( int4, float4 ));
+static if (__traits(compiles, { long4 a; ulong4 b; })) static assert(Error!( long4, ulong4 ));
+static if (__traits(compiles, { double4 a; float8 b; })) static assert(Error!( double4, float8 ));
+
+/******************************
+ * Null
+ */
+
+static assert(is( X!( typeof(null), int* ) == int*));
+static assert(is( X!( typeof(null), int[] ) == int[]));
+static assert(is( X!( typeof(null), int[int] ) == int[int]));
diff --git a/gcc/testsuite/gdc.test/compilable/compile1.d b/gcc/testsuite/gdc.test/compilable/compile1.d
index 86d84af..40fba48 100644
--- a/gcc/testsuite/gdc.test/compilable/compile1.d
+++ b/gcc/testsuite/gdc.test/compilable/compile1.d
@@ -1,8 +1,15 @@
+// COMPILABLE_MATH_TEST
// PERMUTE_ARGS:
+// EXTRA_FILES: imports/a12506.d
+/* TEST_OUTPUT:
+---
+compilable/compile1.d(229): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+---
+*/
-/**************************************************
- 1748 class template with stringof
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=1748
+// class template with stringof
struct S1748(T) {}
static assert(S1748!int.stringof == "S1748!int");
@@ -10,18 +17,17 @@ static assert(S1748!int.stringof == "S1748!int");
class C1748(T) {}
static assert(C1748!int.stringof == "C1748!int");
-/**************************************************
- 2354 pragma + single semicolon DeclarationBlock
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=2354
+// pragma + single semicolon DeclarationBlock
version(all)
pragma(inline, true);
else
pragma(inline, false);
-/**************************************************
- 2438
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=2438
alias void delegate() Dg2438;
@@ -35,9 +41,8 @@ alias typeof(Dg2438.init.funcptr) FP2438b;
static assert(is(CP2438b == void*));
static assert(is(FP2438b == void function()));
-/**************************************************
- 4225
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=4225
struct Foo4225
{
@@ -49,9 +54,9 @@ struct Foo4225
}
}
-/**************************************************
- 5996 ICE(expression.c)
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5996
+// ICE(expression.c)
template T5996(T)
{
@@ -62,17 +67,19 @@ template T5996(T)
}
static assert(!is(typeof(T5996!(int).bug5996())));
-/**************************************************
- 8532 segfault(mtype.c) - type inference + pure
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8532
+// segfault(mtype.c) - type inference + pure
+
auto segfault8532(Y, R ...)(R r, Y val) pure
{ return segfault8532(r, val); }
static assert(!is(typeof( segfault8532(1,2,3))));
-/**************************************************
- 8982 ICE(ctfeexpr.c) __parameters with error in default value
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8982
+// ICE(ctfeexpr.c) __parameters with error in default value
+
template ice8982(T)
{
void bug8982(ref const int v = 7){}
@@ -85,16 +92,17 @@ template ice8982(T)
static assert(!is(ice8982!(int)));
-/**************************************************
- 8801 ICE assigning to __ctfe
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8801
+// ICE assigning to __ctfe
+
static assert(!is(typeof( { bool __ctfe= true; })));
static assert(!is(typeof( { __ctfe |= true; })));
-/**************************************************
- 5932 ICE(s2ir.c)
- 6675 ICE(glue.c)
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5932
+// https://issues.dlang.org/show_bug.cgi?id=6675
+// ICE(s2ir.c), ICE(glue.c)
void bug3932(T)() {
static assert( 0 );
@@ -113,9 +121,9 @@ static assert(!is(typeof(
}()
)));
-/**************************************************
- 6650 ICE(glue.c) or wrong-code
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6650
+// ICE(glue.c) or wrong-code
auto bug6650(X)(X y)
{
@@ -127,9 +135,9 @@ auto bug6650(X)(X y)
static assert(!is(typeof(bug6650!(int)(6))));
static assert(!is(typeof(bug6650!(int)(18))));
-/**************************************************
- 14710 VC-built DMD crashes on templated variadic function IFTI
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=14710
+// VC-built DMD crashes on templated variadic function IFTI
void bug14710a(T)(T val, T[] arr...)
{
@@ -140,9 +148,9 @@ void bug14710b()
bug14710a("", "");
}
-/**************************************************
- 6661 Templates instantiated only through is(typeof()) shouldn't cause errors
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6661
+// Templates instantiated only through is(typeof()) shouldn't cause errors
template bug6661(Q)
{
@@ -168,9 +176,9 @@ template bug6661x(Q)
// should pass, but doesn't in current
//static assert(!is(typeof(bug6661x!(int))));
-/**************************************************
- 6599 ICE(constfold.c) or segfault
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6599
+// ICE(constfold.c) or segfault
string bug6599extraTest(string x) { return x ~ "abc"; }
@@ -191,9 +199,9 @@ template Bug6599(X)
static assert(!is(typeof(Bug6599!int)));
-/**************************************************
- 8422 TypeTuple of tuples can't be read at compile time
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8422
+// TypeTuple of tuples can't be read at compile time
template TypeTuple8422(TList...)
{
@@ -215,9 +223,9 @@ void test8422()
}
}
-/**************************************************
- 6096 ICE(el.c) with -O
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6096
+// ICE(el.c) with -O
cdouble c6096;
@@ -227,35 +235,35 @@ int bug6096()
return 1;
}
-/**************************************************
- 7681 Segfault
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7681
+// Segfault
static assert( !is(typeof( (){
undefined ~= delegate(){}; return 7;
}())));
-/**************************************************
- 8639 Buffer overflow
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8639
+// Buffer overflow
void t8639(alias a)() {}
void bug8639() {
t8639!({auto r = -real.max;})();
}
-/**************************************************
- 7751 Segfault
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7751
+// Segfault
static assert( !is(typeof( (){
bar[]r; r ~= [];
return 7;
}())));
-/**************************************************
- 7639 Segfault
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7639
+// Segfault
static assert( !is(typeof( (){
enum foo =
@@ -264,9 +272,8 @@ static assert( !is(typeof( (){
];
})));
-/**************************************************
- 11991
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11991
void main()
{
@@ -280,9 +287,8 @@ void main()
}
}
-/**************************************************
- 11939
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11939
void test11939()
{
@@ -293,9 +299,8 @@ void test11939()
throw new Exception("");
}
-/**************************************************
- 5796
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5796
template A(B) {
pragma(lib, "missing ;")
@@ -304,18 +309,17 @@ template A(B) {
static assert(!is(typeof(A!(int))));
-/**************************************************
- 6720
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6720
+
void bug6720() { }
static assert(!is(typeof(
cast(bool)bug6720()
)));
-/**************************************************
- 1099
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=1099
template Mix1099(int a) {
alias typeof(this) ThisType;
@@ -331,9 +335,9 @@ struct Foo1099 {
mixin Mix1099!(2);
}
-/**************************************************
- 8788 - super() and return
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8788
+// super() and return
class B8788 {
this ( ) { }
@@ -435,9 +439,9 @@ static assert(!is(typeof( { new C8788!(7)(0); } )));
static assert(!is(typeof( { new C8788!(8)(0); } )));
static assert(!is(typeof( { new C8788!(9)(0); } )));
-/**************************************************
- 4967, 7058
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=4967
+// https://issues.dlang.org/show_bug.cgi?id=7058
enum Bug7058 bug7058 = { 1.5f, 2};
static assert(bug7058.z == 99);
@@ -498,7 +502,7 @@ alias test8163!(ubyte, ubyte, ushort, float) _BBSf;
/***************************************************/
-// 4757
+// https://issues.dlang.org/show_bug.cgi?id=4757
auto foo4757(T)(T)
{
@@ -518,7 +522,7 @@ void test4757()
}
/***************************************************/
-// 9348
+// https://issues.dlang.org/show_bug.cgi?id=9348
void test9348()
{
@@ -529,7 +533,7 @@ void test9348()
}
/***************************************************/
-// 9690
+// https://issues.dlang.org/show_bug.cgi?id=9690
@disable
{
@@ -545,7 +549,7 @@ void test9348()
}
/***************************************************/
-// 9987
+// https://issues.dlang.org/show_bug.cgi?id=9987
static if (is(object.ModuleInfo == struct))
{
@@ -564,7 +568,7 @@ static if (is(object.ModuleInfo == class))
}
/***************************************************/
-// 10158
+// https://issues.dlang.org/show_bug.cgi?id=10158
class Outer10158
{
@@ -586,7 +590,7 @@ void test10158()
}
/***************************************************/
-// 10326
+// https://issues.dlang.org/show_bug.cgi?id=10326
class C10326
{
@@ -596,7 +600,7 @@ class C10326
}
/***************************************************/
-// 11042
+// https://issues.dlang.org/show_bug.cgi?id=11042
static if ((true || error) == true ) {} else { static assert(0); }
static if ((false && error) == false) {} else { static assert(0); }
@@ -620,7 +624,7 @@ int f11042a3()() if (__traits(compiles, true || error) == false) { return 0; }
int f11042b3()() if (__traits(compiles, false && error) == false) { return 0; } enum x11042b3 = f11042b3();
/***************************************************/
-// 11554
+// https://issues.dlang.org/show_bug.cgi?id=11554
enum E11554;
static assert(is(E11554 == enum));
@@ -629,7 +633,7 @@ struct Bro11554(N...) {}
static assert(!is(E11554 unused : Bro11554!M, M...));
/***************************************************/
-// 12302
+// https://issues.dlang.org/show_bug.cgi?id=12302
template isCallable12302(T...)
if (T.length == 1)
@@ -657,7 +661,7 @@ A12302 func12302() { return null; }
enum b12302 = isCallable12302!func12302;
/***************************************************/
-// 12476
+// https://issues.dlang.org/show_bug.cgi?id=12476
template A12476(T) { }
@@ -686,14 +690,14 @@ static assert(__traits(isSame, sb12476, A12476!int));
static assert(__traits(isSame, cb12476, A12476!int));
/***************************************************/
-// 12506
+// https://issues.dlang.org/show_bug.cgi?id=12506
import imports.a12506;
private bool[9] r12506a = f12506!(i => true)(); // OK
private immutable bool[9] r12506b = f12506!(i => true)(); // OK <- error
/***************************************************/
-// 12555
+// https://issues.dlang.org/show_bug.cgi?id=12555
class A12555(T)
{
@@ -705,7 +709,7 @@ static assert(!__traits(compiles, {
}));
/***************************************************/
-// 11622
+// https://issues.dlang.org/show_bug.cgi?id=11622
class A11622(T)
{
@@ -724,7 +728,7 @@ static assert(!__traits(compiles, {
}));
/***************************************************/
-// 12688
+// https://issues.dlang.org/show_bug.cgi?id=12688
void writeln12688(A...)(A) {}
@@ -741,7 +745,7 @@ void test12688()
}
/***************************************************/
-// 12703
+// https://issues.dlang.org/show_bug.cgi?id=12703
struct S12703
{
@@ -754,7 +758,7 @@ final class C12703
}
/***************************************************/
-// 12799
+// https://issues.dlang.org/show_bug.cgi?id=12799
struct A12799
{
@@ -764,12 +768,12 @@ struct A12799
}
/***************************************************/
-// 13236
+// https://issues.dlang.org/show_bug.cgi?id=13236
enum bug13286 = is(typeof({ struct S { S x; } }));
/***************************************************/
-// 13280
+// https://issues.dlang.org/show_bug.cgi?id=13280
struct S13280
{
@@ -780,7 +784,7 @@ struct S13280
}
/***************************************************/
-// 13481
+// https://issues.dlang.org/show_bug.cgi?id=13481
mixin template Mix13481(void function() callback)
{
@@ -791,7 +795,7 @@ mixin template Mix13481(void function() callback)
}
/***************************************************/
-// 13564
+// https://issues.dlang.org/show_bug.cgi?id=13564
class E13564(T)
{
@@ -818,7 +822,7 @@ void test13564()
}
/***************************************************/
-// 14166
+// https://issues.dlang.org/show_bug.cgi?id=14166
struct Proxy14166(T)
{
@@ -868,7 +872,7 @@ static assert(is(typeof(makeAA14166()[0] = 1) == X14166)); // ok <- error
static assert(is(typeof(tup14166.field = makeTup14166()) == TT14166!(int, int))); // ok <- error
/***************************************************/
-// 14388
+// https://issues.dlang.org/show_bug.cgi?id=14388
@property immutable(T)[] idup14388(T)(T[] a)
{
@@ -913,7 +917,7 @@ void test14388()
}
/***************************************************/
-// 15163
+// https://issues.dlang.org/show_bug.cgi?id=15163
void function() func15164(int[] arr)
{
@@ -926,9 +930,9 @@ void test15163()
func15164(arr[0])();
}
-/**************************************************
- 3438
-**************************************************/
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=3438
+
import core.vararg;
struct S3438_1 { this(int x, int y = 1) { } }
struct S3438_2 { this(int x, ...) { } }
@@ -937,7 +941,7 @@ struct S3438_4 { this(...) { } }
struct S3438_5 { this(int[] arr...) { } }
/***************************************************/
-// 15362
+// https://issues.dlang.org/show_bug.cgi?id=15362
void func15362()
{
@@ -952,7 +956,7 @@ void func15362()
}
/***************************************************/
-// 15799
+// https://issues.dlang.org/show_bug.cgi?id=15799
interface I15799
{
@@ -963,3 +967,28 @@ interface I15799
assert(n);
}; // Semicolon is not a part of function declaration. It's an empty declaration.
}
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=21163
+
+struct B21163
+{
+ void function(scope int) fp;
+}
+
+B21163 b21163 = {
+ (scope int x){}
+};
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11624
+
+interface I11624
+{
+ void foo();
+}
+
+static assert(!__traits(compiles,
+{
+ static class C11624 : I11624 { }
+}));
diff --git a/gcc/testsuite/gdc.test/compilable/cpp_abi_tag_unused.d b/gcc/testsuite/gdc.test/compilable/cpp_abi_tag_unused.d
new file mode 100644
index 0000000..bac39cb
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/cpp_abi_tag_unused.d
@@ -0,0 +1,21 @@
+/* DISABLED: win32 win64
+REQUIRED_ARGS: -extern-std=c++11
+*/
+
+#line 100
+
+// Make sure that bad things don't happen if the user isn't using
+// `core.attribute`'s definition
+struct gnuAbiTag
+{
+ string[] args;
+}
+
+extern(C++):
+
+@gnuAbiTag(["42"])
+struct A {}
+
+__gshared A a;
+
+static assert(a.mangleof == "a");
diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle.d b/gcc/testsuite/gdc.test/compilable/cppmangle.d
index 954a9be..1820de9 100644
--- a/gcc/testsuite/gdc.test/compilable/cppmangle.d
+++ b/gcc/testsuite/gdc.test/compilable/cppmangle.d
@@ -1,7 +1,9 @@
-
+// EXTRA_FILES: cppmangle2.d
// Test C++ name mangling.
-// See Bugs 4059, 5148, 7024, 10058
-
+// https://issues.dlang.org/show_bug.cgi?id=4059
+// https://issues.dlang.org/show_bug.cgi?id=5148
+// https://issues.dlang.org/show_bug.cgi?id=7024
+// https://issues.dlang.org/show_bug.cgi?id=10058
import core.stdc.stdio;
@@ -43,7 +45,7 @@ void test1()
c.bar(4, 5, 6);
}
-version (linux)
+version (Posix)
{
static assert(foo.mangleof == "_Z3fooiii");
static assert(foob.mangleof == "_Z4foobiii");
@@ -79,7 +81,7 @@ void test2()
assert(i == 8);
}
-version (linux)
+version (Posix)
{
static assert (getD.mangleof == "_Z4getDv");
static assert (D.bar.mangleof == "_ZN1D3barEiii");
@@ -116,7 +118,7 @@ void test3()
assert(i == 8);
}
-version (linux)
+version (Posix)
{
static assert (callE.mangleof == "_Z5callEP1E");
static assert (E.bar.mangleof == "_ZN1E3barEiii");
@@ -132,7 +134,7 @@ void test4()
foo4(null);
}
-version (linux)
+version (Posix)
{
static assert(foo4.mangleof == "_Z4foo4Pc");
}
@@ -158,7 +160,7 @@ void test5()
assert(f.p == cast(void*)b);
}
-version (linux)
+version (Posix)
{
static assert(bar5.getFoo.mangleof == "_ZN4bar56getFooEi");
static assert (newBar.mangleof == "_Z6newBarv");
@@ -181,14 +183,14 @@ extern (C) int foosize6();
void test6()
{
S6 f = foo6();
- printf("%d %d\n", foosize6(), S6.sizeof);
+ printf("%d %d\n", foosize6(), cast(int)S6.sizeof);
assert(foosize6() == S6.sizeof);
assert(f.i == 42);
printf("f.d = %g\n", f.d);
assert(f.d == 2.5);
}
-version (linux)
+version (Posix)
{
static assert (foo6.mangleof == "_Z4foo6v");
}
@@ -205,7 +207,7 @@ struct S
void test7()
{
- printf("%d %d\n", foo7(), S.sizeof);
+ printf("%d %d\n", foo7(), cast(int)S.sizeof);
assert(foo7() == S.sizeof);
}
@@ -219,13 +221,13 @@ void test8()
foo8(&c);
}
-version (linux)
+version (Posix)
{
static assert(foo8.mangleof == "_Z4foo8PKc");
}
/****************************************/
-// 4059
+// https://issues.dlang.org/show_bug.cgi?id=4059
struct elem9 { }
@@ -237,13 +239,13 @@ void test9()
foobar9(a, a);
}
-version (linux)
+version (Posix)
{
static assert(foobar9.mangleof == "_Z7foobar9P5elem9S0_");
}
/****************************************/
-// 5148
+// https://issues.dlang.org/show_bug.cgi?id=5148
extern (C++)
{
@@ -270,8 +272,15 @@ void test10()
foo10(e,e);
}
+// https://issues.dlang.org/show_bug.cgi?id=19504
+extern(C++) struct Class19504 {
+ pragma(mangle, "HOHOHO")
+ ~this();
+}
+static assert(Class19504.__xdtor.mangleof == "HOHOHO");
+
/**************************************/
-// 10058
+// https://issues.dlang.org/show_bug.cgi?id=10058
extern (C++)
{
@@ -289,7 +298,7 @@ extern (C++)
void test10058l(void* function(void*), void* function(const (void)*), const(void)* function(void*)) { }
}
-version (linux)
+version (Posix)
{
static assert(test10058a.mangleof == "_Z10test10058aPv");
static assert(test10058b.mangleof == "_Z10test10058bPFvPvE");
@@ -306,7 +315,7 @@ version (linux)
}
/**************************************/
-// 11696
+// https://issues.dlang.org/show_bug.cgi?id=11696
class Expression;
struct Loc {}
@@ -320,7 +329,7 @@ class CallExp
static void test11696d(Loc, Expression*, Expression*);
}
-version (linux)
+version (Posix)
{
static assert(CallExp.test11696a.mangleof == "_ZN7CallExp10test11696aE3LocP10ExpressionS2_");
static assert(CallExp.test11696b.mangleof == "_ZN7CallExp10test11696bE3LocP10ExpressionPS2_");
@@ -329,7 +338,7 @@ version (linux)
}
/**************************************/
-// 13337
+// https://issues.dlang.org/show_bug.cgi?id=13337
extern(C++, N13337a.N13337b.N13337c)
{
@@ -337,13 +346,22 @@ extern(C++, N13337a.N13337b.N13337c)
void foo13337(S13337 s);
}
-version (linux)
+extern(C++, `N13337a`, `N13337b`, `N13337c`)
+{
+ struct S13337_2{}
+ void foo13337_2(S13337 s);
+ void foo13337_3(S13337_2 s);
+}
+
+version (Posix)
{
static assert(foo13337.mangleof == "_ZN7N13337a7N13337b7N13337c8foo13337ENS1_6S13337E");
+ static assert(foo13337_2.mangleof == "_ZN7N13337a7N13337b7N13337c10foo13337_2ENS1_6S13337E");
+ static assert(foo13337_3.mangleof == "_ZN7N13337a7N13337b7N13337c10foo13337_3ENS1_8S13337_2E");
}
/**************************************/
-// 15789
+// https://issues.dlang.org/show_bug.cgi?id=15789
extern (C++) void test15789a(T...)(T args);
@@ -353,11 +371,11 @@ void test15789()
}
/**************************************/
-// 7030
+// https://issues.dlang.org/show_bug.cgi?id=7030
extern(C++)
{
- struct T
+ struct Struct7030
{
void foo(int) const;
void bar(int);
@@ -367,9 +385,895 @@ extern(C++)
version (Posix)
{
- static assert(T.foo.mangleof == "_ZNK1T3fooEi");
- static assert(T.bar.mangleof == "_ZN1T3barEi");
- static assert(T.boo.mangleof == "_ZN1T3booE");
+ static assert(Struct7030.foo.mangleof == "_ZNK10Struct70303fooEi");
+ static assert(Struct7030.bar.mangleof == "_ZN10Struct70303barEi");
+ static assert(Struct7030.boo.mangleof == "_ZN10Struct70303booE");
+}
+
+/****************************************/
+
+// Special cases of Itanium mangling
+
+extern (C++, std)
+{
+ struct pair(T1, T2)
+ {
+ void swap(ref pair other);
+ }
+
+ struct allocator(T)
+ {
+ uint fooa() const;
+ uint foob();
+ }
+
+ struct basic_string(T1, T2, T3)
+ {
+ uint fooa();
+ }
+
+ struct basic_istream(T1, T2)
+ {
+ uint fooc();
+ }
+
+ struct basic_ostream(T1, T2)
+ {
+ uint food();
+ }
+
+ struct basic_iostream(T1, T2)
+ {
+ uint fooe();
+ }
+
+ struct char_traits(T)
+ {
+ uint foof();
+ }
+
+ struct vector (T);
+
+ struct test18957 {}
+}
+
+extern (C++, `std`)
+{
+ struct pair(T1, T2)
+ {
+ void swap(ref pair other);
+ }
+
+ struct allocator(T)
+ {
+ uint fooa() const;
+ uint foob();
+ }
+
+ struct basic_string(T1, T2, T3)
+ {
+ uint fooa();
+ }
+
+ struct basic_istream(T1, T2)
+ {
+ uint fooc();
+ }
+
+ struct basic_ostream(T1, T2)
+ {
+ uint food();
+ }
+
+ struct basic_iostream(T1, T2)
+ {
+ uint fooe();
+ }
+
+ struct char_traits(T)
+ {
+ uint foof();
+ }
+
+ struct vector (T);
+
+ struct Struct18957 {}
+}
+
+extern(C++)
+{
+ // Nspace
+ std.allocator!int func_18957_1(std.allocator!(int)* v);
+ // CPPNamespaceAttribute
+ allocator!int func_18957_2(allocator!(int)* v);
+ X func_18957_2(X)(X* v);
+}
+
+extern (C++)
+{
+ void func_20413(pair!(int, float), pair!(float, int));
+}
+
+version (Posix)
+{
+ // https://issues.dlang.org/show_bug.cgi?id=17947
+ static assert(std.pair!(void*, void*).swap.mangleof == "_ZNSt4pairIPvS0_E4swapERS1_");
+ static assert(std.allocator!int.fooa.mangleof == "_ZNKSaIiE4fooaEv");
+ static assert(std.allocator!int.foob.mangleof == "_ZNSaIiE4foobEv");
+ static assert(std.basic_string!(char,int,uint).fooa.mangleof == "_ZNSbIcijE4fooaEv");
+ static assert(std.basic_string!(char, std.char_traits!char, std.allocator!char).fooa.mangleof == "_ZNSs4fooaEv");
+ static assert(std.basic_istream!(char, std.char_traits!char).fooc.mangleof == "_ZNSi4foocEv");
+ static assert(std.basic_ostream!(char, std.char_traits!char).food.mangleof == "_ZNSo4foodEv");
+ static assert(std.basic_iostream!(char, std.char_traits!char).fooe.mangleof == "_ZNSd4fooeEv");
+
+ static assert(func_18957_1.mangleof == `_Z12func_18957_1PSaIiE`);
+ static assert(func_18957_2!(std.allocator!int).mangleof == `_Z12func_18957_2ISaIiEET_PS1_`);
+
+
+ static assert(pair!(void*, void*).swap.mangleof == "_ZNSt4pairIPvS0_E4swapERS1_");
+ static assert(allocator!int.fooa.mangleof == "_ZNKSaIiE4fooaEv");
+ static assert(allocator!int.foob.mangleof == "_ZNSaIiE4foobEv");
+ static assert(basic_string!(char,int,uint).fooa.mangleof == "_ZNSbIcijE4fooaEv");
+ static assert(basic_string!(char, char_traits!char, allocator!char).fooa.mangleof == "_ZNSs4fooaEv");
+ static assert(basic_istream!(char, char_traits!char).fooc.mangleof == "_ZNSi4foocEv");
+ static assert(basic_ostream!(char, char_traits!char).food.mangleof == "_ZNSo4foodEv");
+ static assert(basic_iostream!(char, char_traits!char).fooe.mangleof == "_ZNSd4fooeEv");
+
+ static assert(func_18957_2.mangleof == `_Z12func_18957_2PSaIiE`);
+ static assert(func_18957_2!(allocator!int).mangleof == `_Z12func_18957_2ISaIiEET_PS1_`);
+
+ static assert(func_20413.mangleof == `_Z10func_20413St4pairIifES_IfiE`);
+}
+
+/**************************************/
+
+alias T36 = int ********** ********** ********** **********;
+
+extern (C++) void test36(T36, T36*) { }
+
+version (Posix)
+{
+ static assert(test36.mangleof == "_Z6test36PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPiPS12_");
+}
+
+/*****************************************/
+// https://issues.dlang.org/show_bug.cgi?id=17772
+
+extern(C++, SPACE)
+int test37(T)(){ return 0;}
+
+extern(C++, `SPACE`)
+int test37(T)(){ return 0;}
+
+version (Posix) // all non-Windows machines
+{
+ static assert(SPACE.test37!int.mangleof == "_ZN5SPACE6test37IiEEiv");
+ static assert(test37!int.mangleof == "_ZN5SPACE6test37IiEEiv");
+}
+
+/**************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15388
+
+extern (C++) void test15388(typeof(null));
+
+version (Posix)
+{
+ static assert(test15388.mangleof == "_Z9test15388Dn");
+}
+version (Windows)
+{
+ static assert(test15388.mangleof == "?test15388@@YAX$$T@Z");
+}
+
+/**************************************/
+// https://issues.dlang.org/show_bug.cgi?id=14086
+
+extern (C++) class Test14086
+{
+ this();
+ ~this();
+}
+extern (C++) class Test14086_2
+{
+ final ~this();
+}
+extern (C++) struct Test14086_S
+{
+ this(int);
+ ~this();
+}
+
+version(Posix)
+{
+ static assert(Test14086.__ctor.mangleof == "_ZN9Test14086C1Ev");
+ static assert(Test14086.__dtor.mangleof == "_ZN9Test14086D1Ev");
+ static assert(Test14086_2.__dtor.mangleof == "_ZN11Test14086_2D1Ev");
+ static assert(Test14086_S.__ctor.mangleof == "_ZN11Test14086_SC1Ei");
+ static assert(Test14086_S.__dtor.mangleof == "_ZN11Test14086_SD1Ev");
+}
+version(Win32)
+{
+ static assert(Test14086.__ctor.mangleof == "??0Test14086@@QAE@XZ");
+ static assert(Test14086.__dtor.mangleof == "??1Test14086@@UAE@XZ");
+ static assert(Test14086_2.__dtor.mangleof == "??1Test14086_2@@QAE@XZ");
+ static assert(Test14086_S.__ctor.mangleof == "??0Test14086_S@@QAE@H@Z");
+ static assert(Test14086_S.__dtor.mangleof == "??1Test14086_S@@QAE@XZ");
+}
+version(Win64)
+{
+ static assert(Test14086.__ctor.mangleof == "??0Test14086@@QEAA@XZ");
+ static assert(Test14086.__dtor.mangleof == "??1Test14086@@UEAA@XZ");
+ static assert(Test14086_2.__dtor.mangleof == "??1Test14086_2@@QEAA@XZ");
+ static assert(Test14086_S.__ctor.mangleof == "??0Test14086_S@@QEAA@H@Z");
+ static assert(Test14086_S.__dtor.mangleof == "??1Test14086_S@@QEAA@XZ");
+}
+
+/**************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18888
+
+extern (C++)
+struct T18888(T)
+{
+ void fun();
+}
+
+extern (C++)
+struct S18888(alias arg = T18888)
+{
+ alias I = T18888!(arg!int);
+}
+
+version(Posix)
+{
+ static assert(S18888!().I.fun.mangleof == "_ZN6T18888IS_IiEE3funEv");
+}
+version(Win32)
+{
+ static assert(S18888!().I.fun.mangleof == "?fun@?$T18888@U?$T18888@H@@@@QAEXXZ");
+}
+version(Win64)
+{
+ static assert(S18888!().I.fun.mangleof == "?fun@?$T18888@U?$T18888@H@@@@QEAAXXZ");
+}
+
+/**************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18890
+
+extern (C++) class C18890
+{
+ ~this() {}
+}
+extern (C++) class C18890_2
+{
+ ~this() {}
+ extern (C++) struct Agg
+ {
+ ~this() {}
+ }
+ Agg s;
+}
+
+version (Posix)
+{
+ static assert(C18890.__dtor.mangleof == "_ZN6C18890D1Ev");
+ static assert(C18890.__xdtor.mangleof == "_ZN6C18890D1Ev");
+ static assert(C18890_2.__dtor.mangleof == "_ZN8C18890_26__dtorEv");
+ static assert(C18890_2.__xdtor.mangleof == "_ZN8C18890_2D1Ev");
+}
+version (Win32)
+{
+ static assert(C18890.__dtor.mangleof == "??1C18890@@UAE@XZ");
+ static assert(C18890.__xdtor.mangleof == "??_GC18890@@UAEPAXI@Z");
+ static assert(C18890_2.__dtor.mangleof == "?__dtor@C18890_2@@UAEXXZ");
+ static assert(C18890_2.__xdtor.mangleof == "??_GC18890_2@@UAEPAXI@Z");
+}
+version (Win64)
+{
+ static assert(C18890.__dtor.mangleof == "??1C18890@@UEAA@XZ");
+ static assert(C18890.__xdtor.mangleof == "??_GC18890@@UEAAPEAXI@Z");
+ static assert(C18890_2.__dtor.mangleof == "?__dtor@C18890_2@@UEAAXXZ");
+ static assert(C18890_2.__xdtor.mangleof == "??_GC18890_2@@UEAAPEAXI@Z");
+}
+
+/**************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18891
+
+extern (C++) class C18891
+{
+ ~this();
+ extern (C++) struct Agg
+ {
+ ~this() {}
+ }
+ Agg s;
+}
+
+version (Posix)
+{
+ static assert(C18891.__dtor.mangleof == "_ZN6C18891D1Ev");
+ static assert(C18891.__xdtor.mangleof == "_ZN6C18891D1Ev");
+}
+version (Win32)
+{
+ static assert(C18891.__dtor.mangleof == "??1C18891@@UAE@XZ");
+ static assert(C18891.__xdtor.mangleof == "??_GC18891@@UAEPAXI@Z");
+}
+version (Win64)
+{
+ static assert(C18891.__dtor.mangleof == "??1C18891@@UEAA@XZ");
+ static assert(C18891.__xdtor.mangleof == "??_GC18891@@UEAAPEAXI@Z");
+}
+
+/**************************************/
+// Test C++ operator mangling
+
+extern (C++) struct TestOperators
+{
+ int opCast(T)();
+ int opBinary(string op)(int x);
+ int opUnary(string op)();
+ int opOpAssign(string op)(int x);
+ int opIndex(int x);
+ bool opEquals(int x);
+ int opCall(int, float);
+ int opAssign(int);
+}
+
+version (Posix)
+{
+ static assert(TestOperators.opUnary!"*".mangleof == "_ZN13TestOperatorsdeEv");
+ static assert(TestOperators.opUnary!"++".mangleof == "_ZN13TestOperatorsppEv");
+ static assert(TestOperators.opUnary!"--".mangleof == "_ZN13TestOperatorsmmEv");
+ static assert(TestOperators.opUnary!"-".mangleof == "_ZN13TestOperatorsngEv");
+ static assert(TestOperators.opUnary!"+".mangleof == "_ZN13TestOperatorspsEv");
+ static assert(TestOperators.opUnary!"~".mangleof == "_ZN13TestOperatorscoEv");
+ static assert(TestOperators.opBinary!">>".mangleof == "_ZN13TestOperatorsrsEi");
+ static assert(TestOperators.opBinary!"<<".mangleof == "_ZN13TestOperatorslsEi");
+ static assert(TestOperators.opBinary!"*".mangleof == "_ZN13TestOperatorsmlEi");
+ static assert(TestOperators.opBinary!"-".mangleof == "_ZN13TestOperatorsmiEi");
+ static assert(TestOperators.opBinary!"+".mangleof == "_ZN13TestOperatorsplEi");
+ static assert(TestOperators.opBinary!"&".mangleof == "_ZN13TestOperatorsanEi");
+ static assert(TestOperators.opBinary!"/".mangleof == "_ZN13TestOperatorsdvEi");
+ static assert(TestOperators.opBinary!"%".mangleof == "_ZN13TestOperatorsrmEi");
+ static assert(TestOperators.opBinary!"^".mangleof == "_ZN13TestOperatorseoEi");
+ static assert(TestOperators.opBinary!"|".mangleof == "_ZN13TestOperatorsorEi");
+ static assert(TestOperators.opOpAssign!"*".mangleof == "_ZN13TestOperatorsmLEi");
+ static assert(TestOperators.opOpAssign!"+".mangleof == "_ZN13TestOperatorspLEi");
+ static assert(TestOperators.opOpAssign!"-".mangleof == "_ZN13TestOperatorsmIEi");
+ static assert(TestOperators.opOpAssign!"/".mangleof == "_ZN13TestOperatorsdVEi");
+ static assert(TestOperators.opOpAssign!"%".mangleof == "_ZN13TestOperatorsrMEi");
+ static assert(TestOperators.opOpAssign!">>".mangleof == "_ZN13TestOperatorsrSEi");
+ static assert(TestOperators.opOpAssign!"<<".mangleof == "_ZN13TestOperatorslSEi");
+ static assert(TestOperators.opOpAssign!"&".mangleof == "_ZN13TestOperatorsaNEi");
+ static assert(TestOperators.opOpAssign!"|".mangleof == "_ZN13TestOperatorsoREi");
+ static assert(TestOperators.opOpAssign!"^".mangleof == "_ZN13TestOperatorseOEi");
+ static assert(TestOperators.opCast!int.mangleof == "_ZN13TestOperatorscviEv");
+ static assert(TestOperators.opAssign.mangleof == "_ZN13TestOperatorsaSEi");
+ static assert(TestOperators.opEquals.mangleof == "_ZN13TestOperatorseqEi");
+ static assert(TestOperators.opIndex.mangleof == "_ZN13TestOperatorsixEi");
+ static assert(TestOperators.opCall.mangleof == "_ZN13TestOperatorsclEif");
+}
+version (Win32)
+{
+ static assert(TestOperators.opUnary!"*".mangleof == "??DTestOperators@@QAEHXZ");
+ static assert(TestOperators.opUnary!"++".mangleof == "??ETestOperators@@QAEHXZ");
+ static assert(TestOperators.opUnary!"--".mangleof == "??FTestOperators@@QAEHXZ");
+ static assert(TestOperators.opUnary!"-".mangleof == "??GTestOperators@@QAEHXZ");
+ static assert(TestOperators.opUnary!"+".mangleof == "??HTestOperators@@QAEHXZ");
+ static assert(TestOperators.opUnary!"~".mangleof == "??STestOperators@@QAEHXZ");
+ static assert(TestOperators.opBinary!">>".mangleof == "??5TestOperators@@QAEHH@Z");
+ static assert(TestOperators.opBinary!"<<".mangleof == "??6TestOperators@@QAEHH@Z");
+ static assert(TestOperators.opBinary!"*".mangleof == "??DTestOperators@@QAEHH@Z");
+ static assert(TestOperators.opBinary!"-".mangleof == "??GTestOperators@@QAEHH@Z");
+ static assert(TestOperators.opBinary!"+".mangleof == "??HTestOperators@@QAEHH@Z");
+ static assert(TestOperators.opBinary!"&".mangleof == "??ITestOperators@@QAEHH@Z");
+ static assert(TestOperators.opBinary!"/".mangleof == "??KTestOperators@@QAEHH@Z");
+ static assert(TestOperators.opBinary!"%".mangleof == "??LTestOperators@@QAEHH@Z");
+ static assert(TestOperators.opBinary!"^".mangleof == "??TTestOperators@@QAEHH@Z");
+ static assert(TestOperators.opBinary!"|".mangleof == "??UTestOperators@@QAEHH@Z");
+ static assert(TestOperators.opOpAssign!"*".mangleof == "??XTestOperators@@QAEHH@Z");
+ static assert(TestOperators.opOpAssign!"+".mangleof == "??YTestOperators@@QAEHH@Z");
+ static assert(TestOperators.opOpAssign!"-".mangleof == "??ZTestOperators@@QAEHH@Z");
+ static assert(TestOperators.opOpAssign!"/".mangleof == "??_0TestOperators@@QAEHH@Z");
+ static assert(TestOperators.opOpAssign!"%".mangleof == "??_1TestOperators@@QAEHH@Z");
+ static assert(TestOperators.opOpAssign!">>".mangleof == "??_2TestOperators@@QAEHH@Z");
+ static assert(TestOperators.opOpAssign!"<<".mangleof == "??_3TestOperators@@QAEHH@Z");
+ static assert(TestOperators.opOpAssign!"&".mangleof == "??_4TestOperators@@QAEHH@Z");
+ static assert(TestOperators.opOpAssign!"|".mangleof == "??_5TestOperators@@QAEHH@Z");
+ static assert(TestOperators.opOpAssign!"^".mangleof == "??_6TestOperators@@QAEHH@Z");
+ static assert(TestOperators.opCast!int.mangleof == "??BTestOperators@@QAEHXZ");
+ static assert(TestOperators.opAssign.mangleof == "??4TestOperators@@QAEHH@Z");
+ static assert(TestOperators.opEquals.mangleof == "??8TestOperators@@QAE_NH@Z");
+ static assert(TestOperators.opIndex.mangleof == "??ATestOperators@@QAEHH@Z");
+ static assert(TestOperators.opCall.mangleof == "??RTestOperators@@QAEHHM@Z");
+}
+version (Win64)
+{
+ static assert(TestOperators.opUnary!"*".mangleof == "??DTestOperators@@QEAAHXZ");
+ static assert(TestOperators.opUnary!"++".mangleof == "??ETestOperators@@QEAAHXZ");
+ static assert(TestOperators.opUnary!"--".mangleof == "??FTestOperators@@QEAAHXZ");
+ static assert(TestOperators.opUnary!"-".mangleof == "??GTestOperators@@QEAAHXZ");
+ static assert(TestOperators.opUnary!"+".mangleof == "??HTestOperators@@QEAAHXZ");
+ static assert(TestOperators.opUnary!"~".mangleof == "??STestOperators@@QEAAHXZ");
+ static assert(TestOperators.opBinary!">>".mangleof == "??5TestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opBinary!"<<".mangleof == "??6TestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opBinary!"*".mangleof == "??DTestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opBinary!"-".mangleof == "??GTestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opBinary!"+".mangleof == "??HTestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opBinary!"&".mangleof == "??ITestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opBinary!"/".mangleof == "??KTestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opBinary!"%".mangleof == "??LTestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opBinary!"^".mangleof == "??TTestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opBinary!"|".mangleof == "??UTestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opOpAssign!"*".mangleof == "??XTestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opOpAssign!"+".mangleof == "??YTestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opOpAssign!"-".mangleof == "??ZTestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opOpAssign!"/".mangleof == "??_0TestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opOpAssign!"%".mangleof == "??_1TestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opOpAssign!">>".mangleof == "??_2TestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opOpAssign!"<<".mangleof == "??_3TestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opOpAssign!"&".mangleof == "??_4TestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opOpAssign!"|".mangleof == "??_5TestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opOpAssign!"^".mangleof == "??_6TestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opCast!int.mangleof == "??BTestOperators@@QEAAHXZ");
+ static assert(TestOperators.opAssign.mangleof == "??4TestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opEquals.mangleof == "??8TestOperators@@QEAA_NH@Z");
+ static assert(TestOperators.opIndex.mangleof == "??ATestOperators@@QEAAHH@Z");
+ static assert(TestOperators.opCall.mangleof == "??RTestOperators@@QEAAHHM@Z");
+}
+
+import cppmangle2;
+extern(C++, Namespace18922)
+{
+ // Nspace
+ void func18922(cppmangle2.Namespace18922.Struct18922) {}
+ // CPPNamespaceAttribute
+ void func18922_1(Struct18922) {}
+}
+
+extern(C++, `Namespace18922`)
+{
+ // Nspace
+ void func18922_2(cppmangle2.Namespace18922.Struct18922) {}
+ // CPPNamespaceAttribute
+ void func18922_3(Struct18922) {}
+}
+
+version (Posix)
+{
+ static assert(func18922.mangleof == "_ZN14Namespace189229func18922ENS_11Struct18922E");
+ static assert(func18922_1.mangleof == "_ZN14Namespace1892211func18922_1ENS_11Struct18922E");
+ static assert(func18922_2.mangleof == "_ZN14Namespace1892211func18922_2ENS_11Struct18922E");
+ static assert(func18922_3.mangleof == "_ZN14Namespace1892211func18922_3ENS_11Struct18922E");
+}
+else version(Windows)
+{
+ static assert(func18922.mangleof == "?func18922@Namespace18922@@YAXUStruct18922@1@@Z");
+ static assert(func18922_1.mangleof == "?func18922_1@Namespace18922@@YAXUStruct18922@1@@Z");
+ static assert(func18922_2.mangleof == "?func18922_2@Namespace18922@@YAXUStruct18922@1@@Z");
+ static assert(func18922_3.mangleof == "?func18922_3@Namespace18922@@YAXUStruct18922@1@@Z");
+}
+
+/**************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18957
+// extern(C++) doesn't mangle 'std' correctly on posix systems
+
+version (Posix)
+{
+ // https://godbolt.org/z/C5T2LQ
+ /+
+ namespace std
+ {
+ struct test18957 {};
+ }
+ void test18957(const std::test18957& t) {}
+ +/
+ extern (C++) void test18957(ref const(Struct18957) t) {}
+
+ static assert(test18957.mangleof == "_Z9test18957RKSt11Struct18957");
+}
+
+/**************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19043
+// Incorrect mangling for extern(C++) const template parameter on windows
+
+extern(C++) struct test19043(T) {}
+
+extern(C++) void test19043a(test19043!(const(char)) a) {}
+extern(C++) void test19043b(T)(T a) {}
+version(Windows)
+{
+ static assert(test19043a.mangleof == "?test19043a@@YAXU?$test19043@$$CBD@@@Z");
+ static assert(test19043b!(test19043!(const(char))).mangleof ==
+ "??$test19043b@U?$test19043@$$CBD@@@@YAXU?$test19043@$$CBD@@@Z");
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=16479
+// Missing substitution while mangling C++ template parameter for functions
+version (Posix) extern (C++)
+{
+ // Make sure aliases are still resolved
+ alias Alias16479 = int;
+ Alias16479 func16479_0 (FuncT1) (FuncT1, Alias16479);
+ static assert(func16479_0!(int).mangleof == `_Z11func16479_0IiEiT_i`);
+
+ // Simple substitution on return type
+ FuncT1* func16479_1 (FuncT1) ();
+ static assert(func16479_1!(int).mangleof == `_Z11func16479_1IiEPT_v`);
+
+ // Simple substitution on parameter
+ void func16479_2 (FuncT1) (FuncT1);
+ static assert(func16479_2!(int).mangleof == `_Z11func16479_2IiEvT_`);
+
+ // Make sure component substition is prefered over template parameter
+ FuncT1* func16479_3 (FuncT1) (FuncT1);
+ static assert(func16479_3!(int).mangleof == `_Z11func16479_3IiEPT_S0_`);
+
+ struct Array16479 (Arg) { Arg* data; }
+ struct Array16479_2 (Arg, int Size) { Arg[Size] data; }
+ struct Value16479 (int Value1, int Value2) { int data; }
+
+ // Make sure template parameter substitution happens on templated return
+ Array16479!(FuncT2) func16479_4 (FuncT1, FuncT2) (FuncT1);
+ static assert(func16479_4!(int, float).mangleof
+ == `_Z11func16479_4IifE10Array16479IT0_ET_`);
+
+ // Make sure template parameter substitution happens with values
+ Value16479!(Value2, Value1)* func16479_5 (int Value1, int Value2) ();
+ static assert(func16479_5!(1, 1).mangleof
+ == `_Z11func16479_5ILi1ELi1EEP10Value16479IXT0_EXT_EEv`);
+
+ // But make sure it's not substituting *too many* values
+ Value16479!(1, 1)* func16479_6 (int Value1, int Value2) ();
+ static assert(func16479_6!(1, 1).mangleof
+ == `_Z11func16479_6ILi1ELi1EEP10Value16479ILi1ELi1EEv`);
+
+ // Or too many types
+ Array16479!(int) func16479_7 (FuncT1, FuncT2) (FuncT1);
+ static assert(func16479_7!(int, int).mangleof
+ == `_Z11func16479_7IiiE10Array16479IiET_`);
+
+ // Also must check the parameters for template param substitution
+ void func16479_8 (FuncT1) (Array16479!(FuncT1));
+ static assert(func16479_8!(int).mangleof
+ == `_Z11func16479_8IiEv10Array16479IT_E`);
+
+ // And non-substitution
+ void func16479_9 (FuncT1) (Array16479!(int));
+ static assert(func16479_9!(int).mangleof
+ == `_Z11func16479_9IiEv10Array16479IiE`);
+
+ // Now let's have a bit of fun with alias parameters,
+ // starting with C functions
+ // TODO: Why is this mangled by g++:
+ /*
+ extern "C"
+ {
+ void externC16479 (int);
+ }
+
+ template<void (*Print)(int)>
+ void func16479_10 ();
+
+ void foo () { func16479_10<externC16479>(); }
+ */
+ extern (C) void externC16479 (int);
+ void func16479_10 (alias Print) ();
+ static assert(func16479_10!(externC16479).mangleof
+ == `_Z12func16479_10IXadL_Z12externC16479EEEvv`);
+
+ /**
+ * Let's not exclude C++ functions
+ * Note:
+ * Passing a function as template parameter has an implicit
+ * `&` operator prepended to it, so the following code:
+ * ---
+ * void CPPPrinter16479(const char*);
+ * template<void (*Print)(const char*)> void func16479_11 ();
+ * void foo () { func16479_11<CPPPrinter16479>(); }
+ * ---
+ * Gets mangled as `func16479_11<&CPPPrinter16479>()` would,
+ * which means the expression part of the template argument is
+ * mangled as `XadL_Z[...]E` not `XL_Z[...]E`
+ * (expressions always begin with a code anyway).
+ */
+ extern(C++) void CPPPrinter16479(const(char)*);
+ extern(C++, Namespace16479) void CPPPrinterNS16479(const(char)*);
+ extern(C++, `Namespace16479`) void CPPPrinterNS16479_1(const(char)*);
+ void func16479_11 (alias Print) ();
+ static assert(func16479_11!(CPPPrinter16479).mangleof
+ == `_Z12func16479_11IXadL_Z15CPPPrinter16479PKcEEEvv`);
+ static assert(func16479_11!(CPPPrinterNS16479).mangleof
+ == `_Z12func16479_11IXadL_ZN14Namespace1647917CPPPrinterNS16479EPKcEEEvv`);
+ static assert(func16479_11!(CPPPrinterNS16479_1).mangleof
+ == `_Z12func16479_11IXadL_ZN14Namespace1647919CPPPrinterNS16479_1EPKcEEEvv`);
+
+ // Functions are fine, but templates are finer
+ // ---
+ // template<template<typename, int> class Container, typename T, int Val>
+ // Container<T, Val> func16479_12 ();
+ // ---
+ Container!(T, Val) func16479_12 (alias Container, T, int Val) ();
+ static assert(func16479_12!(Array16479_2, int, 42).mangleof
+ == `_Z12func16479_12I12Array16479_2iLi42EET_IT0_XT1_EEv`);
+
+ // Substitution needs to happen on the most specialized type
+ // Iow, `ref T identity (T) (ref T v);` should be mangled as
+ // `_Z8identityIiET_*S1_*`, not as `_Z8identityIiET_*RS0_*`
+ ref FuncT1 func16479_13_1 (FuncT1) (ref FuncT1);
+ FuncT1* func16479_13_2 (FuncT1) (FuncT1*);
+ void func16479_13_3 (FuncT1) (FuncT1*, FuncT1*);
+ FuncT1** func16479_13_4 (FuncT1) (FuncT1*, FuncT1);
+ FuncT1 func16479_13_5 (FuncT1) (FuncT1*, FuncT1**);
+ static assert(func16479_13_1!(int).mangleof == `_Z14func16479_13_1IiERT_S1_`);
+ static assert(func16479_13_2!(float).mangleof == `_Z14func16479_13_2IfEPT_S1_`);
+ static assert(func16479_13_3!(int).mangleof == `_Z14func16479_13_3IiEvPT_S1_`);
+ static assert(func16479_13_4!(int).mangleof == `_Z14func16479_13_4IiEPPT_S1_S0_`);
+ static assert(func16479_13_5!(int).mangleof == `_Z14func16479_13_5IiET_PS0_PS1_`);
+
+ // Opaque types result in a slightly different AST
+ vector!T* func16479_14 (T) (T v);
+ static assert(func16479_14!(int).mangleof == `_Z12func16479_14IiEPSt6vectorIT_ES1_`);
+
+ struct Foo16479_15 (T);
+ struct Baguette16479_15 (T);
+ struct Bar16479_15 (T);
+ struct FooBar16479_15 (A, B);
+ void inst16479_15_2 (A, B) ();
+ void inst16479_15_3 (A, B, C) ();
+
+ static assert(inst16479_15_2!(Bar16479_15!int, int).mangleof
+ == `_Z14inst16479_15_2I11Bar16479_15IiEiEvv`);
+ static assert(inst16479_15_2!(int, Bar16479_15!int).mangleof
+ == `_Z14inst16479_15_2Ii11Bar16479_15IiEEvv`);
+ static assert(inst16479_15_2!(Bar16479_15!int, FooBar16479_15!(Bar16479_15!int, Foo16479_15!(Bar16479_15!(Foo16479_15!int)))).mangleof
+ == `_Z14inst16479_15_2I11Bar16479_15IiE14FooBar16479_15IS1_11Foo16479_15IS0_IS3_IiEEEEEvv`);
+ static assert(inst16479_15_3!(int, Bar16479_15!int, FooBar16479_15!(Bar16479_15!int, Foo16479_15!(Bar16479_15!(Foo16479_15!int)))).mangleof
+ == `_Z14inst16479_15_3Ii11Bar16479_15IiE14FooBar16479_15IS1_11Foo16479_15IS0_IS3_IiEEEEEvv`);
+
+ static import cppmangle2;
+ cppmangle2.Struct18922* func16479_16_1 (T) (T*);
+ static assert(func16479_16_1!int.mangleof == `_Z14func16479_16_1IiEPN14Namespace1892211Struct18922EPT_`);
+ T* func16479_16_2 (T) (T*);
+ static assert(func16479_16_2!int.mangleof == `_Z14func16479_16_2IiEPT_S1_`);
+ static assert(func16479_16_2!(cppmangle2.vector!int).mangleof == `_Z14func16479_16_2ISt6vectorIiEEPT_S3_`);
+ static assert(func16479_16_2!(cppmangle2.vector!int).mangleof
+ == func16479_16_2!(cppmangle2.vector!int).mangleof);
+ cppmangle2.vector!T* func16479_16_3 (T) (T*);
+ static assert(func16479_16_3!int.mangleof == `_Z14func16479_16_3IiEPSt6vectorIiEPT_`);
+
+ extern(C++, `fakestd`) {
+ extern (C++, `__1`) {
+ struct allocator16479 (T);
+ struct vector16479(T, alloc = allocator16479!T);
+ }
+ }
+ vector16479!(T, allocator16479!T)* func16479_17_1(T)();
+ vector16479!(T)* func16479_17_2(T)();
+ static assert(func16479_17_1!int.mangleof == `_Z14func16479_17_1IiEPN7fakestd3__111vector16479IT_NS1_14allocator16479IS3_EEEEv`);
+ static assert(func16479_17_2!int.mangleof == `_Z14func16479_17_2IiEPN7fakestd3__111vector16479IT_NS1_14allocator16479IS3_EEEEv`);
+
+ // Make sure substitution takes place everywhere in template arg list
+ extern(C++, "ns") void func16479_18_1(T, X)(int, X, T, float);
+ extern(C++, "ns") void func16479_18_2(T, X)(X, int, T, float);
+ static assert(func16479_18_1!(double, char).mangleof == `_ZN2ns14func16479_18_1IdcEEviT0_T_f`);
+ static assert(func16479_18_2!(double, char).mangleof == `_ZN2ns14func16479_18_2IdcEEvT0_iT_f`);
+}
+
+/**************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19278
+// extern(C++, "name") doesn't accept expressions
+
+extern(C++, "hello" ~ "world")
+{
+ void test19278();
+}
+enum NS = "lookup";
+extern(C++, (NS))
+{
+ void test19278_2();
+}
+alias AliasSeq(Args...) = Args;
+alias Tup = AliasSeq!("hello", "world");
+extern(C++, (Tup))
+{
+ void test19278_3();
+ __gshared size_t test19278_var;
+}
+extern(C++, (AliasSeq!(Tup, "yay")))
+{
+ void test19278_4();
+}
+version(Win64)
+{
+ static assert(test19278.mangleof == "?test19278@helloworld@@YAXXZ");
+ static assert(test19278_2.mangleof == "?test19278_2@lookup@@YAXXZ");
+ static assert(test19278_3.mangleof == "?test19278_3@world@hello@@YAXXZ");
+ static assert(test19278_4.mangleof == "?test19278_4@yay@world@hello@@YAXXZ");
+ static assert(test19278_var.mangleof == "?test19278_var@world@hello@@3_KA");
+}
+else version(Posix)
+{
+ static assert(test19278.mangleof == "_ZN10helloworld9test19278Ev");
+ static assert(test19278_2.mangleof == "_ZN6lookup11test19278_2Ev");
+ static assert(test19278_3.mangleof == "_ZN5hello5world11test19278_3Ev");
+ static assert(test19278_4.mangleof == "_ZN5hello5world3yay11test19278_4Ev");
+ static assert(test19278_var.mangleof == "_ZN5hello5world13test19278_varE");
+}
+
+/**************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18958
+// Issue 18958 - extern(C++) wchar, dchar mangling not correct
+
+version(Posix)
+ enum __c_wchar_t : dchar;
+else version(Windows)
+ enum __c_wchar_t : wchar;
+alias wchar_t = __c_wchar_t;
+extern (C++) void test_char_mangling(char, wchar, dchar, wchar_t);
+version (Posix)
+{
+ static assert(test_char_mangling.mangleof == "_Z18test_char_manglingcDsDiw");
+}
+version (Win64)
+{
+ static assert(test_char_mangling.mangleof == "?test_char_mangling@@YAXD_S_U_W@Z");
+}
+
+// https://github.com/dlang/dmd/pull/10021/files#r294055424
+version (Posix)
+{
+ extern(C++, PR10021_NS) struct PR10021_Struct(T){}
+ extern(C++) void PR10021_fun(int i)(PR10021_Struct!int);
+ static assert(PR10021_fun!0.mangleof == `_Z11PR10021_funILi0EEvN10PR10021_NS14PR10021_StructIiEE`);
+}
+
+// https://github.com/dlang/dmd/pull/10021#discussion_r294095749
+version (Posix)
+{
+ extern(C++, "a", "b")
+ struct PR10021_Struct2
+ {
+ void func();
+ void func2(PR10021_Struct2*);
+ }
+ static assert(PR10021_Struct2.func.mangleof == `_ZN1a1b15PR10021_Struct24funcEv`);
+ static assert(PR10021_Struct2.func2.mangleof == `_ZN1a1b15PR10021_Struct25func2EPS1_`);
+}
+
+/// https://issues.dlang.org/show_bug.cgi?id=20022
+version (Posix)
+{
+ extern(C++, `ns20022`) enum Enum20022_1 { A = 1, }
+ extern(C++) void fun20022_1(Enum20022_1);
+ extern(C++, `ns20022`) void fun20022_2(Enum20022_1);
+
+ extern(C++, ns20022)
+ {
+ enum Enum20022_2 { A = 1, }
+ void fun20022_5(Enum20022_1);
+ void fun20022_6(Enum20022_2);
+ }
+ extern(C++) void fun20022_3(Enum20022_2);
+ extern(C++, `ns20022`) void fun20022_4(Enum20022_2);
+
+ static assert(fun20022_1.mangleof == `_Z10fun20022_1N7ns2002211Enum20022_1E`);
+ static assert(fun20022_2.mangleof == `_ZN7ns2002210fun20022_2ENS_11Enum20022_1E`);
+
+ static assert(fun20022_3.mangleof == `_Z10fun20022_3N7ns2002211Enum20022_2E`);
+ static assert(fun20022_4.mangleof == `_ZN7ns2002210fun20022_4ENS_11Enum20022_2E`);
+ static assert(fun20022_5.mangleof == `_ZN7ns2002210fun20022_5ENS_11Enum20022_1E`);
+ static assert(fun20022_6.mangleof == `_ZN7ns2002210fun20022_6ENS_11Enum20022_2E`);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20094
+version (Posix)
+{
+ extern(C++, "ns20094")
+ {
+ struct xvector20094 (T) {}
+ alias V20094 = xvector20094!(ubyte);
+ }
+
+ extern(C++) void test20094(xvector20094!(V20094)* v);
+ static assert(test20094.mangleof == `_Z9test20094PN7ns2009412xvector20094INS0_IhEEEE`);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20223
+version (Posix)
+{
+ extern(C++)
+ {
+ int test20223_1(T)(int function(const(T)* value));
+ int test20223_2(T)(int function(ref const(T) value));
+
+ struct Struct20223_1 {}
+ struct Struct20223_2 {}
+ int test20223_3(ref const Struct20223_1, Struct20223_2*, Struct20223_2*);
+ int test20223_4(ref const Struct20223_1, const ref Struct20223_2, Struct20223_2*);
+
+ struct Struct20223_3 (T) {}
+ void test20223_5(ref Struct20223_1, ref Struct20223_3!(const(char)*),
+ ref Struct20223_3!(const(char)*));
+ }
+ static assert(test20223_1!int.mangleof == `_Z11test20223_1IiEiPFiPKT_E`);
+ static assert(test20223_2!int.mangleof == `_Z11test20223_2IiEiPFiRKT_E`);
+ static assert(test20223_1!(int*).mangleof == `_Z11test20223_1IPiEiPFiPKT_E`);
+ static assert(test20223_2!(int*).mangleof == `_Z11test20223_2IPiEiPFiRKT_E`);
+ static assert(test20223_3.mangleof == `_Z11test20223_3RK13Struct20223_1P13Struct20223_2S3_`);
+ static assert(test20223_4.mangleof == `_Z11test20223_4RK13Struct20223_1RK13Struct20223_2PS2_`);
+ static assert(test20223_5.mangleof == `_Z11test20223_5R13Struct20223_1R13Struct20223_3IPKcES5_`);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20224
+version (Posix)
+{
+ extern(C++) public int test20224_1(T)(set20224!T set); // ok
+ extern(C++) public int test20224_2(T)(ref set20224!T set); // segfault
+
+ extern(C++) struct set20224 (T)
+ {
+ void test ()
+ {
+ test20224_1!T(this);
+ test20224_2!T(this); // segfaults
+ }
+ }
+
+ extern(D) void func20224 ()
+ {
+ set20224!int x;
+ }
+}
+
+/**************************************/
+
+version (Posix)
+{
+ extern (C++) struct Loc2 {};
+ extern (C++) class FuncDeclaration
+ {
+ static FuncDeclaration create(ref const Loc2, ref const Loc2);
+ };
+ extern (C++) FuncDeclaration FuncDeclaration_create(ref const Loc2, ref const Loc2);
+
+ static assert(FuncDeclaration_create.mangleof == `_Z22FuncDeclaration_createRK4Loc2S1_`);
+ static assert(FuncDeclaration.create.mangleof == `_ZN15FuncDeclaration6createERK4Loc2S2_`);
+}
+
+enum Enum19542 = func19542!(int).mangleof;
+
+extern(C++, `bar`)
+{
+ void func19542(T)();
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20700
+// Only testing on WIn64 because the mangling includes 'E',
+// and the bug can be tested on either platform
+version (Win64) extern(C++)
+{
+ void test20700_1(Struct20700);
+ extern(C++, class) struct Struct20700 {}
+ void test20700_2(Struct20700);
+
+ // Note: Needs to be `V` (`class`), not `U` (`struct`)
+ static assert(test20700_1.mangleof == `?test20700_1@@YAXVStruct20700@@@Z`);
+ static assert(test20700_2.mangleof == `?test20700_2@@YAXVStruct20700@@@Z`);
+
+ // Test that the scope is not "sticky" on the arguments
+ void test20700_3(TStruct20700_1!DefaultClass20700_1);
+ extern(C++, class) struct TStruct20700_1 (T1, T2 = DefaultStruct20700_1) {}
+ extern(C++, class) struct DefaultStruct20700_1 {}
+ extern(C++, struct) class DefaultClass20700_1 {}
+ static assert(test20700_3.mangleof == `?test20700_3@@YAXV?$TStruct20700_1@PEAUDefaultClass20700_1@@VDefaultStruct20700_1@@@@@Z`);
+
+ // Each test needs to be independent symbol to trigger a new semantic pass
+ void test20700_4(TStruct20700_2!(DefaultClass20700_2, DefaultStruct20700_2));
+ extern(C++, struct) class TStruct20700_2 (T1, T2 = DefaultClass20700_2) {}
+ extern(C++, class) struct DefaultStruct20700_2 {}
+ extern(C++, struct) class DefaultClass20700_2 {}
+ static assert(test20700_4.mangleof == `?test20700_4@@YAXPEAU?$TStruct20700_2@PEAUDefaultClass20700_2@@VDefaultStruct20700_2@@@@@Z`);
}
/*****************************************/
diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle2.d b/gcc/testsuite/gdc.test/compilable/cppmangle2.d
new file mode 100644
index 0000000..d507d36
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/cppmangle2.d
@@ -0,0 +1,21 @@
+module cppmangle2;
+
+extern(C++, Namespace18922)
+{
+ struct Struct18922 { int i; }
+}
+
+extern(C++, std)
+{
+ struct vector (T);
+}
+
+extern(C++, `Namespace18922`)
+{
+ struct Struct18922 { int i; }
+}
+
+extern(C++, `std`)
+{
+ struct vector (T);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle3.d b/gcc/testsuite/gdc.test/compilable/cppmangle3.d
index 4c48012..531509c 100644
--- a/gcc/testsuite/gdc.test/compilable/cppmangle3.d
+++ b/gcc/testsuite/gdc.test/compilable/cppmangle3.d
@@ -1,3 +1,6 @@
+// https://issues.dlang.org/show_bug.cgi?id=15512
+// https://issues.dlang.org/show_bug.cgi?id=19893
+// https://issues.dlang.org/show_bug.cgi?id=19920
module cppmangle3;
@@ -34,4 +37,22 @@ struct Foo
alias Alias(alias a) = a;
alias Alias(T) = T;
-static assert(is(Alias!(__traits(parent, bar)) == Foo));
+static assert(is(Alias!(__traits(parent, Foo.bar)) == Foo));
+
+extern(C++, "std"):
+debug = 456;
+debug = def;
+version = 456;
+version = def;
+
+extern(C++, "std")
+{
+ debug = 456;
+ debug = def;
+ version = 456;
+ version = def;
+}
+
+extern(C++, "foo")
+extern(C++, "bar")
+version = baz;
diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle_abitag.d b/gcc/testsuite/gdc.test/compilable/cppmangle_abitag.d
new file mode 100644
index 0000000..f681174
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/cppmangle_abitag.d
@@ -0,0 +1,106 @@
+// DISABLED: win32 win64
+// REQUIRED_ARGS: -extern-std=c++11
+/*
+ * Test C++ abi-tag name mangling.
+ * https://issues.dlang.org/show_bug.cgi?id=19949
+ */
+
+import core.attribute;
+
+extern(C++):
+
+alias Tuple(A...) = A;
+enum foo_bar = gnuAbiTag("foo", "bar");
+
+@foo_bar
+struct S
+{
+ int i;
+ this(int);
+}
+
+@foo_bar
+extern __gshared int a;
+static assert(a.mangleof == "_Z1aB3barB3foo");
+
+extern __gshared S b;
+static assert(b.mangleof == "_Z1bB3barB3foo");
+
+@foo_bar
+int f();
+static assert(f.mangleof == "_Z1fB3barB3foov");
+
+S gs(int);
+S gss(S, int);
+static assert(gs.mangleof == "_Z2gsB3barB3fooi");
+static assert(gss.mangleof == "_Z3gss1SB3barB3fooi");
+
+@foo_bar
+S fss(S, int);
+static assert(gs.mangleof == "_Z2gsB3barB3fooi");
+
+T gt(T)(int);
+T gtt(T)(T, int);
+static assert(gt!S.mangleof == "_Z2gtI1SB3barB3fooET_i");
+static assert(gtt!S.mangleof == "_Z3gttI1SB3barB3fooET_S1_i");
+
+@foo_bar
+T ft(T)(int);
+// matches Clang and GCC <= 6
+static assert(ft!S.mangleof == "_Z2ftB3barB3fooI1SB3barB3fooET_i");
+
+@foo_bar
+T ftt(T)(T, int);
+// matches Clang and GCC <= 6
+static assert(ftt!S.mangleof == "_Z3fttB3barB3fooI1SB3barB3fooET_S1_i");
+
+// GCC >= 6 only
+@gnuAbiTag("ENN")
+enum E0 { a = 0xa, }
+E0 fe();
+E0 fei(int i)();
+static assert(fe.mangleof == "_Z2feB3ENNv");
+static assert(fei!0.mangleof == "_Z3feiILi0EE2E0B3ENNv");
+
+// Linux std::string
+// https://issues.dlang.org/show_bug.cgi?id=14956#c13
+extern(C++, "std")
+{
+ struct allocator(T);
+ struct char_traits(CharT);
+
+ extern(C++, "__cxx11")
+ {
+ @gnuAbiTag("cxx11")
+ struct basic_string(CharT, Traits=char_traits!CharT, Allocator=allocator!CharT)
+ {
+ const char* data();
+ size_t length() const;
+ }
+ }
+ alias string_ = basic_string!char;
+}
+string_* toString(const char*);
+static assert(toString.mangleof == "_Z8toStringB5cxx11PKc");
+
+@gnuAbiTag("A", "B")
+{
+ void fun0();
+ static assert(fun0.mangleof == "_Z4fun0B1AB1Bv");
+}
+
+@gnuAbiTag("C", "D"):
+
+void fun1();
+static assert(fun1.mangleof == "_Z4fun1B1CB1Dv");
+
+void fun2();
+static assert(fun2.mangleof == "_Z4fun2B1CB1Dv");
+
+auto fun3()
+{
+ @gnuAbiTag("Nested")
+ extern(C++) struct T {}
+ return T();
+}
+static assert(fun3.mangleof == "_Z4fun3B1CB1DB6Nestedv");
diff --git a/gcc/testsuite/gdc.test/compilable/ctfe_math.d b/gcc/testsuite/gdc.test/compilable/ctfe_math.d
index 334b75a..65c9985 100644
--- a/gcc/testsuite/gdc.test/compilable/ctfe_math.d
+++ b/gcc/testsuite/gdc.test/compilable/ctfe_math.d
@@ -5,10 +5,10 @@ import std.math;
void main()
{
- static assert(approxEqual(sin(2.0L), 0.9092974L));
- static assert(approxEqual(cos(2.0), -0.4161468));
- static assert(approxEqual(tan(2.0f), -2.185040f));
- static assert(approxEqual(sqrt(2.0L), 1.414214L));
+ static assert(isClose(sin(2.0L), 0.9092974268));
+ static assert(isClose(cos(2.0), -0.4161468365));
+ static assert(isClose(tan(2.0f), -2.185040f, 1e-5));
+ static assert(isClose(sqrt(2.0L), 1.4142135623));
static assert(fabs(-2.0) == 2.0);
static assert(ldexp(2.5f, 3) == 20.0f);
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc1.d b/gcc/testsuite/gdc.test/compilable/ddoc1.d
index fa5042a..23e721d 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc1.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc1.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 1
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
// REQUIRED_ARGS: -d
/** This module is for ABC
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10.d b/gcc/testsuite/gdc.test/compilable/ddoc10.d
index 90ab5a1..6a7a481 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc10.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc10.d
@@ -1,8 +1,8 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-// 294
+// https://issues.dlang.org/show_bug.cgi?id=294
/// The foo
struct Foo(T) { }
@@ -142,7 +142,7 @@ struct S
/****
*/
- const pure nothrow this(this) { }
+ pure nothrow this(this) { }
/****
*/
@@ -177,7 +177,7 @@ struct T
}
-// 14547
+// https://issues.dlang.org/show_bug.cgi?id=14547
/// doc-comment
int x14547 = 1;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10236.d b/gcc/testsuite/gdc.test/compilable/ddoc10236.d
index 1c54761..c272894 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc10236.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc10236.d
@@ -4,10 +4,12 @@
/*
TEST_OUTPUT:
---
-compilable/ddoc10236.d(33): Warning: Ddoc: parameter count mismatch
-compilable/ddoc10236.d(45): Warning: Ddoc: function declaration has no parameter 'y'
-compilable/ddoc10236.d(57): Warning: Ddoc: function declaration has no parameter 'y'
-compilable/ddoc10236.d(57): Warning: Ddoc: parameter count mismatch
+compilable/ddoc10236.d(35): Warning: Ddoc: parameter count mismatch, expected 2, got 1
+compilable/ddoc10236.d(47): Warning: Ddoc: function declaration has no parameter 'y'
+compilable/ddoc10236.d(59): Warning: Ddoc: function declaration has no parameter 'y'
+compilable/ddoc10236.d(59): Warning: Ddoc: parameter count mismatch, expected 1, got 2
+compilable/ddoc10236.d(71): Warning: Ddoc: parameter count mismatch, expected 2, got 0
+compilable/ddoc10236.d(71): Note that the format is `param = description`
---
*/
@@ -57,3 +59,15 @@ void foo_no_param_y(int x, int z) // Warning: Ddoc: function declaration has no
void foo_count_mismatch_no_param_y(int x)
{
}
+
+/***********************************
+ * foo_count_mismatch_wrong_format does this.
+ * Params:
+ * x : is for this
+ * and not for that
+ * y : is for that
+ */
+
+void foo_count_mismatch_wrong_format(int x, int y)
+{
+}
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10236b.d b/gcc/testsuite/gdc.test/compilable/ddoc10236b.d
index 065ced0..85783e8 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc10236b.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc10236b.d
@@ -4,10 +4,11 @@
/*
TEST_OUTPUT:
---
-compilable/ddoc10236b.d(43): Warning: Ddoc: parameter count mismatch
-compilable/ddoc10236b.d(55): Warning: Ddoc: function declaration has no parameter 'y'
-compilable/ddoc10236b.d(67): Warning: Ddoc: function declaration has no parameter 'y'
-compilable/ddoc10236b.d(67): Warning: Ddoc: parameter count mismatch
+compilable/ddoc10236b.d(44): Warning: Ddoc: parameter count mismatch, expected 1, got 0
+compilable/ddoc10236b.d(44): Note that the format is `param = description`
+compilable/ddoc10236b.d(56): Warning: Ddoc: function declaration has no parameter 'y'
+compilable/ddoc10236b.d(68): Warning: Ddoc: function declaration has no parameter 'y'
+compilable/ddoc10236b.d(68): Warning: Ddoc: parameter count mismatch, expected 0, got 1
---
*/
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10325.d b/gcc/testsuite/gdc.test/compilable/ddoc10325.d
index 4f0068a..a976f5a 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc10325.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc10325.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10325
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc10325;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10334.d b/gcc/testsuite/gdc.test/compilable/ddoc10334.d
index 3ff148d..dd7a0f4 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc10334.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc10334.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10334
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc10334;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10366.d b/gcc/testsuite/gdc.test/compilable/ddoc10366.d
index 5bc5f64..a5fc9b2 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc10366.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc10366.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10366
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
///
struct S(T)
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10367.d b/gcc/testsuite/gdc.test/compilable/ddoc10367.d
index 836c7d0..7e2dedb 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc10367.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc10367.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10367
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
// REQUIRED_ARGS: -m32
// EXTRA_SOURCES: extra-files/ddoc10367.ddoc
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10869.d b/gcc/testsuite/gdc.test/compilable/ddoc10869.d
index 11b4854..8745fbd 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc10869.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc10869.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10869
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc10869;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10870.d b/gcc/testsuite/gdc.test/compilable/ddoc10870.d
index 95a82ed..ad16837 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc10870.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc10870.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 10870
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
///
interface I
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc11.d b/gcc/testsuite/gdc.test/compilable/ddoc11.d
index cf6070e..3fcf2ca 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc11.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc11.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 11
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/// The various floating point exceptions
enum
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc11479.d b/gcc/testsuite/gdc.test/compilable/ddoc11479.d
index d2ddb19..5b00dc8 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc11479.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc11479.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 11479
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc11479;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc11511.d b/gcc/testsuite/gdc.test/compilable/ddoc11511.d
index ba5829e..117eba4 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc11511.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc11511.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -w -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 11511
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc11511;
/**
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc11823.d b/gcc/testsuite/gdc.test/compilable/ddoc11823.d
index dfde4b6..c9af38f 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc11823.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc11823.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 11823
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc11823;
/// file function name is _file, arg defaults to __FILE__ but not __something__
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc12.d b/gcc/testsuite/gdc.test/compilable/ddoc12.d
index 4fdf9cf..337f37a 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc12.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc12.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 12
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
int ruhred; /// This documents correctly.
int rühred; /// This should too
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc12706.d b/gcc/testsuite/gdc.test/compilable/ddoc12706.d
index 399583c..a19ba21 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc12706.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc12706.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 12706
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
///
void test()(string[] args) if (args[$])
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc12745.d b/gcc/testsuite/gdc.test/compilable/ddoc12745.d
index 2bfaee6..a2cf74b 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc12745.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc12745.d
@@ -1,7 +1,7 @@
// EXTRA_SOURCES:
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 12745
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/**
i underlined $(BR)
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc13.d b/gcc/testsuite/gdc.test/compilable/ddoc13.d
index eafc8b2..9985bb0 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc13.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc13.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 13
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/// struct doc
struct Bug4107(T)
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc13270.d b/gcc/testsuite/gdc.test/compilable/ddoc13270.d
index 6b04922..3d2f47e 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc13270.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc13270.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS: -w
// REQUIRED_ARGS: -o- -D -Dd${RESULTS_DIR}/compilable
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 13270
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc13270;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc13645.d b/gcc/testsuite/gdc.test/compilable/ddoc13645.d
index f12b376..35bb7f0 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc13645.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc13645.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 13645
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/**
Documentation comment on module
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc14.d b/gcc/testsuite/gdc.test/compilable/ddoc14.d
index fe1fcc1..a8b6d4d 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc14.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc14.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 14
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
alias void V;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc14383.d b/gcc/testsuite/gdc.test/compilable/ddoc14383.d
index 273b058..0f8d51c 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc14383.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc14383.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 14383
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/**
* Module docs.
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc14413.d b/gcc/testsuite/gdc.test/compilable/ddoc14413.d
index dace15f..3586476 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc14413.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc14413.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 14413
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc14413;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc14778.d b/gcc/testsuite/gdc.test/compilable/ddoc14778.d
index 6bb2353..a3c1728 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc14778.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc14778.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 14778
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc14778;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc15475.d b/gcc/testsuite/gdc.test/compilable/ddoc15475.d
index f192352..64c07ff 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc15475.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc15475.d
@@ -1,6 +1,7 @@
-// PERMUTE_ARGS:
-// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 15475
+/* PERMUTE_ARGS:
+REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
+*/
/**
My module
@@ -8,5 +9,25 @@ My module
// Computes the interval [x,y)
auto interval = computeInterval(x, y);
----
+
+Backslash-escape parentheses with `\(` and `\)`.
+
+---
+(
+---
+
+---
+)
+---
+
+---
+ Here are some nested `backticks`
+ // Another interval [x,y)
+---
+
+---
+ This won't end the code block: --- )
+ // Yet another interval [x,y)
+---
*/
module ddoc15475;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc17697.d b/gcc/testsuite/gdc.test/compilable/ddoc17697.d
index 3d97c2c..8edff32 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc17697.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc17697.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 17697
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/***
* See:
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc18361.d b/gcc/testsuite/gdc.test/compilable/ddoc18361.d
new file mode 100644
index 0000000..584b995
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc18361.d
@@ -0,0 +1,27 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
+// REQUIRED_ARGS: -d
+
+// Test notes: 'main' is the symbol being documented (DDOC_AUTO_PSYMBOL),
+// 'arguments' is a parameter (DDOC_AUTO_PARAM), and 'false' is a keyword
+// (DDOC_AUTO_KEYWORD).
+/**
+ * The main thing this program does is nothing, and I do _not want to hear any
+ * false arguments about that!
+ *
+ * Macros:
+ * DDOC_AUTO_PSYMBOL = $0
+ * DDOC_AUTO_KEYWORD = $0
+ * DDOC_AUTO_PARAM = $0
+ * DDOC_AUTO_PSYMBOL_SUPPRESS = HALPIMBEINGSUPPRESSED $0
+ *
+ * DDOC = $(BODY)
+ * DDOC_DECL = $0
+ * DDOC_MEMBER_HEADER =
+ * DDOC_MODULE_MEMBERS = $0
+ * DDOC_MEMBER = $0
+ */
+void main(string[] arguments)
+{
+}
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc198.d b/gcc/testsuite/gdc.test/compilable/ddoc198.d
index 16485b7..d5bc848 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc198.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc198.d
@@ -1,7 +1,7 @@
// EXTRA_SOURCES: extra-files/ddoc198.ddoc
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 198
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc198;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc19814.d b/gcc/testsuite/gdc.test/compilable/ddoc19814.d
new file mode 100644
index 0000000..b1fd15e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc19814.d
@@ -0,0 +1,23 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
+
+/*
+TEST_OUTPUT:
+----
+----
+*/
+
+/++
+ + Nested Code
+ +
+ + ------------------------------------
+ + /**
+ + * Examples:
+ + * --------------------
+ + * writeln("3"); // writes '3' to stdout
+ + * --------------------
+ + */
+ + ------------------------------------
+ +/
+module test.compilable.ddoc_markdown_nested_code;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc2.d b/gcc/testsuite/gdc.test/compilable/ddoc2.d
index 54e492f..2a7e457 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc2.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc2.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 2
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/**
* Summary
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc2273.d b/gcc/testsuite/gdc.test/compilable/ddoc2273.d
index 413ba71..ec3b74a 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc2273.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc2273.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 2273
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
// REQUIRED_ARGS: -m32
module ddoc2273;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc4.d b/gcc/testsuite/gdc.test/compilable/ddoc4.d
index d067736..e52067b 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc4.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc4.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 4
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/**
a
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc4162.d b/gcc/testsuite/gdc.test/compilable/ddoc4162.d
index 3946eca..dd24475 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc4162.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc4162.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 4162
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
///
interface A
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc5.d b/gcc/testsuite/gdc.test/compilable/ddoc5.d
index 4a8c396..4ddc123 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc5.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc5.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 5
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/**
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc5446.d b/gcc/testsuite/gdc.test/compilable/ddoc5446.d
index 2e33617..0596088 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc5446.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc5446.d
@@ -1,6 +1,7 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 5446
+// EXTRA_FILES: ddoc5446a.d ddoc5446b.d
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc5446;
import ddoc5446a;
private import ddoc5446b;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc6.d b/gcc/testsuite/gdc.test/compilable/ddoc6.d
index 6d13090..69bd64a 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc6.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc6.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 6
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/**
*
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc648.d b/gcc/testsuite/gdc.test/compilable/ddoc648.d
index 49c9097..ce86543 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc648.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc648.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 648
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc648;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc6491.d b/gcc/testsuite/gdc.test/compilable/ddoc6491.d
index 028792a..5fe37a3 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc6491.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc6491.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 6491
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc6491;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc7.d b/gcc/testsuite/gdc.test/compilable/ddoc7.d
index 8185183..9c28d1b 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc7.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc7.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 7
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
//-----------------------------------------------
/// my enum
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc7555.d b/gcc/testsuite/gdc.test/compilable/ddoc7555.d
index efbb547..ec3001c 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc7555.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc7555.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 7555
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc7555;
/**
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc7656.d b/gcc/testsuite/gdc.test/compilable/ddoc7656.d
index 7a0ef0d..82766dc 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc7656.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc7656.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 7656
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc7656;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc7715.d b/gcc/testsuite/gdc.test/compilable/ddoc7715.d
index ee33b28..ddffaf2 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc7715.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc7715.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 7715
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc7656;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc7795.d b/gcc/testsuite/gdc.test/compilable/ddoc7795.d
index c100f5d..2a6ba02 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc7795.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc7795.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 7795
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc7795;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc8.d b/gcc/testsuite/gdc.test/compilable/ddoc8.d
index 6683b1b..f3da3c0 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc8.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc8.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 8
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/** foo */
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc8271.d b/gcc/testsuite/gdc.test/compilable/ddoc8271.d
index 45aca90..983c0ca 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc8271.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc8271.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 8271
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc8271;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc8739.d b/gcc/testsuite/gdc.test/compilable/ddoc8739.d
index cf7da98..005f93d 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc8739.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc8739.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 8739
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc8739;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9.d b/gcc/testsuite/gdc.test/compilable/ddoc9.d
index 21f312d..09d54ef 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9.d
@@ -1,8 +1,8 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-// 273
+// https://issues.dlang.org/show_bug.cgi?id=273
/// Template Documentation (OK)
template Template(T) { }
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9037.d b/gcc/testsuite/gdc.test/compilable/ddoc9037.d
index ac4ace2..7f113ea 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9037.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9037.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9037
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc9037;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9155.d b/gcc/testsuite/gdc.test/compilable/ddoc9155.d
index 82b7f63..9f5a59a 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9155.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9155.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9155
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc9155;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9305.d b/gcc/testsuite/gdc.test/compilable/ddoc9305.d
index 9c9b890..a28fe10 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9305.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9305.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9305
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc9305;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9369.d b/gcc/testsuite/gdc.test/compilable/ddoc9369.d
index 13bce82..ba44891 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9369.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9369.d
@@ -1,7 +1,7 @@
// PERMUTE_ARGS:
// EXTRA_SOURCES: extra-files/ddoc9369.ddoc
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9369
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/**
Sample:
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9475.d b/gcc/testsuite/gdc.test/compilable/ddoc9475.d
index 460269c..262fa7d 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9475.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9475.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -w -o- -c -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9475
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc9475;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9497a.d b/gcc/testsuite/gdc.test/compilable/ddoc9497a.d
index 6617434..422ed08 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9497a.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9497a.d
@@ -1,7 +1,7 @@
// EXTRA_SOURCES: extra-files/ddoc9497a.ddoc
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9497a
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/**
foo function.
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9497b.d b/gcc/testsuite/gdc.test/compilable/ddoc9497b.d
index 62ab44c..d059af8 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9497b.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9497b.d
@@ -1,7 +1,7 @@
// EXTRA_SOURCES: extra-files/ddoc9497b.ddoc
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9497b
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/**
foo function.
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9497c.d b/gcc/testsuite/gdc.test/compilable/ddoc9497c.d
index da9e3df..fb32aef 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9497c.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9497c.d
@@ -1,7 +1,7 @@
// EXTRA_SOURCES: extra-files/ddoc9497c.ddoc
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9497c
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/**
foo function.
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9497d.d b/gcc/testsuite/gdc.test/compilable/ddoc9497d.d
index c42f013..a8aa26b 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9497d.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9497d.d
@@ -1,7 +1,7 @@
// EXTRA_SOURCES: extra-files/ddoc9497d.ddoc
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9497d
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/**
foo function.
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9676a.d b/gcc/testsuite/gdc.test/compilable/ddoc9676a.d
index 326c2cf..c5f0f79 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9676a.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9676a.d
@@ -1,7 +1,7 @@
// PERMUTE_ARGS:
// EXTRA_SOURCES: extra-files/ddoc9676a.ddoc
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9676a
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc9676a;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9676b.d b/gcc/testsuite/gdc.test/compilable/ddoc9676b.d
index 6314549..433ec71 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9676b.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9676b.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9676b
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc9676b;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9727.d b/gcc/testsuite/gdc.test/compilable/ddoc9727.d
index 14e5fd2..d15a3bf 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9727.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9727.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9727
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc9727;
/** The function foo. */
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9789.d b/gcc/testsuite/gdc.test/compilable/ddoc9789.d
index b220c7f..ddbb763 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9789.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9789.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
-// REQUIRED_ARGS: -D -w -o- -c -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9789
+// REQUIRED_ARGS: -D -w -o- -Dd${RESULTS_DIR}/compilable -o-
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddoc9789;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9903.d b/gcc/testsuite/gdc.test/compilable/ddoc9903.d
index 00b6a79..2e0d1ae 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9903.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9903.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh 9903
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/// sss
struct S9903X {}
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks.d
new file mode 100644
index 0000000..8242b98
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks.d
@@ -0,0 +1,30 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_breaks.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_breaks.html
+
+/++
+# Thematic Breaks
+
+Some text before
+***
+Some text in between
+____________________
+Some text after
+
+---
+This is a code block
+---
+
+But this is a thematic break:
+
+- - -
+
+## Not Thematic Breaks
+
+- -
+__
+**
+
++/
+module ddoc_markdown_lists;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks_verbose.d
new file mode 100644
index 0000000..1ff26b0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks_verbose.d
@@ -0,0 +1,13 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o- -transition=vmarkdown
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_breaks_verbose.html
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_breaks_verbose.html
+
+/++
+Thematic Breaks
+
+___
+- - -
+***
++/
+module ddoc_markdown_breaks;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code.d
new file mode 100644
index 0000000..56e6be3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code.d
@@ -0,0 +1,46 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_code.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_code.html
+
+/++
+# Code Blocks
+
+---
+A regular ol' code block (note the uneven delimiter lengths)
+----
+
+```
+A backtick-fenced code block
+```
+
+~~~
+A tilde-fenced code block
+~~~
+
+--- d
+A hyphen-fenced D code block
+---
+
+--- d delish
+A backtick-fenced D code block
+---
+
+~~~ d
+A tilde-fenced D code block
+~~~
+
+--- ruby
+A hyphen-fenced ruby code block
+---
+
+--- ruby delish
+A backtick-fenced ruby code block
+---
+
+~~~ ruby
+A tilde-fenced ruby code block
+~~~
+
++/
+module test.compilable.ddoc_markdown_code;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code_verbose.d
new file mode 100644
index 0000000..eb64c04
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code_verbose.d
@@ -0,0 +1,13 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_code_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_code_verbose.html
+
+/++
+Code:
+
+``` ruby red
+RWBY
+```
++/
+module test.compilable.ddoc_markdown_code_verbose;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis.d
new file mode 100644
index 0000000..8bbcbdf
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis.d
@@ -0,0 +1,45 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_emphasis.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_emphasis.html
+
+/++
+Markdown Emphasis:
+
+*emphasized text*
+
+*emphasized text
+on more than one line*
+
+**strongly emphasized text**
+
+*in*seperable
+
+***tricky** emphasis*
+
+*more **tricky emphasis***
+
+*tricky**unspaced***
+
+*more**tricky**unspaced*
+
+*highly **nested *emphasis* in this** line*
+
+$(B *inside a macro*)
+
+*$(B outside a macro)*
+
+**The following aren't Markdown emphasis:**
+
+a * not emphasis*
+
+a*"not either"*
+
+*nor this *
+
+*jumping $(B into a macro*)
+
+$(B *jumping) out of a macro*
+
++/
+module ddoc_markdown_emphasis;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis_verbose.d
new file mode 100644
index 0000000..07904c1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis_verbose.d
@@ -0,0 +1,13 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o- -transition=vmarkdown
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_emphasis_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_emphasis_verbose.html
+
+/++
+Markdown Emphasis:
+
+*emphasized text*
+
+**strongly emphasized text**
++/
+module ddoc_markdown_emphasis;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_escapes.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_escapes.d
new file mode 100644
index 0000000..4d8c8ae
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_escapes.d
@@ -0,0 +1,27 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_escapes.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_escapes.html
+
+/++
+Backslash Escapes:
+
+\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}
+
+But not in code:
+
+---
+\{\}
+---
+
+`\{\}`
+
+Nor in HTML:
+
+<tag attr="\{\}"></tag>
+
+Nor before things that aren't punctuation:
+
+C:\dlang\dmd
++/
+module ddoc_markdown_escapes;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings.d
new file mode 100644
index 0000000..e7191f8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings.d
@@ -0,0 +1,40 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_headings.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_headings.html
+
+/++
+# ATX-Style Headings
+
+# H1
+## H2
+### H3
+#### H4
+##### H5
+###### H6
+
+ ### headings
+ ## with initial
+ # spaces
+
+## heading with *emphasis*
+
+## heading with trailing `#`'s #######
+## heading with trailing literal ##'s
+## heading with another trailing literal#
+## heading with backslash-escaped trailing #\##
+
+## Some empty headers:
+##
+#
+### ###
+
+# Not Headings
+
+#hashtag not a heading because there's no space after the `#`
+
+####### Not a heading because it has more than 6 `#`'s
+
+\## Not a heading because of the preceeding backslash
++/
+module ddoc_markdown_headings;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings_verbose.d
new file mode 100644
index 0000000..6448463
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings_verbose.d
@@ -0,0 +1,9 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_headings_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_headings_verbose.html
+
+/++
+# Heading
++/
+module ddoc_markdown_headings_verbose;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links.d
new file mode 100644
index 0000000..349175b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links.d
@@ -0,0 +1,42 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_links.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_links.html
+
+/++
+# Links
+
+[D Site]: https://dlang.org 'D lives here'
+[unused reference]: https://nowhere.com
+
+A link to [printf].
+
+A link to [the base object][Object].
+
+Not a link because it's an associative array: int[Object].
+
+An inline link to [the D homepage](https://dlang.org).
+
+A reference link to [the **D** homepage][d site].
+
+Not a reference link because it [links to nothing][nonexistent].
+
+A simple link to [dub].
+
+A slightly less simple link to [dub][].
+
+An image: ![D-Man](https://dlang.org/images/d3.png)
+Another image: ![D-Man again][dman-error]
+
+[dub]: <https://code.dlang.org>
+[dman-error]: https://dlang.org/images/dman-error.jpg
+
+$(P
+ [tour]: https://tour.dlang.org
+
+ Here's a [reference to the tour][tour] inside a macro.
+)
++/
+module test.compilable.ddoc_markdown_links;
+
+import core.stdc.stdio;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links_verbose.d
new file mode 100644
index 0000000..435b426
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links_verbose.d
@@ -0,0 +1,17 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_links_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_links_verbose.html
+
+/++
+Links:
+
+A link to [Object].
+An inline link to [the D homepage](https://dlang.org).
+A simple link to [dub].
+A slightly less simple link to [dub][].
+An image: ![D-Man](https://dlang.org/images/d3.png)
+
+[dub]: https://code.dlang.org
++/
+module test.compilable.ddoc_markdown_links_verbose;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists.d
new file mode 100644
index 0000000..1e5ff56
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists.d
@@ -0,0 +1,68 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_lists.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_lists.html
+
+/++
+# Lists
+
+## Unordered
+
+- item one
+
+ *part of* item one
+
+ ---
+ // code in item one
+ ---
+
+ **not** part of item one
+
++ + three
+- different
+* lists
+
+- list with
+-
+- empty item
+
+- parent item
+ - child item
+
+- sibling item
+ - sibling item
+
+After text:
+- ### heading
+- and item
+
+## Ordered
+
+0. zero
+1. one
+
+List separator text
+
+3. list that starts with three
+
+1. parent item
+ 1. child item
+
+1. sibling item
+ 2. sibling item
+
+## Not Lists
+
+-no initial space
+
+2.no initial space
+
+1234567890. too many numbers
+
+-1. negative
+
+New lists must start with 1, not
+6. So this isn't a list.
+
++/
+module ddoc_markdown_lists;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists_verbose.d
new file mode 100644
index 0000000..4fd1a80
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists_verbose.d
@@ -0,0 +1,9 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_lists_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_lists_verbose.html
+
+/++
+- list item
++/
+module ddoc_markdown_lists_verbose;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote.d
new file mode 100644
index 0000000..27cfc43
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote.d
@@ -0,0 +1,53 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_quote.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_quote.html
+
+/++
+# Quote Blocks
+
+> “It seems to me that most of the ‘new’ programming languages fall into one of
+two categories: Those from academia with radical new paradigms and those from
+large corporations with a focus on RAD and the web. Maybe it’s time for a new
+language born out of practical experience implementing compilers.†-- Michael
+
+> Great, just what I need.. another D in programming. -- Segfault
+
+> To D, or not to D. -- Willeam NerdSpeare
+
+> "What I am going to tell you about is what we teach our programming students in the third or fourth year of graduate school... It is my task to convince you not to turn away because you don't understand it. You see my programming students don't understand it... That is because I don't understand it. Nobody does."
+-- Richard Deeman
+
+Here's a bit of text between quotes.
+
+> This is a quote
+> > And this is a nested quote
+
+> This is a quote with a > symbol in it
+
+> This is a quote
+with a continuation
+
+> This quote
+- is ended by this list
+
+> This quote
+### is ended by this heading
+
+> This quote is ended by a thematic break:
+____
+
+> This quote
+```
+is ended by this code
+```
+
+> ### Some things inside a quote block:
+> ___
+> ---
+> Some code
+> ---
+> - a list
+
++/
+module test.compilable.ddoc_markdown_code;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote_verbose.d
new file mode 100644
index 0000000..f16e539
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote_verbose.d
@@ -0,0 +1,11 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_quote_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_quote_verbose.html
+
+/++
+Quote Block:
+
+> Great, just what I need.. another D in programming. -- Segfault
++/
+module test.compilable.ddoc_markdown_code_verbose;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables.d
new file mode 100644
index 0000000..231364a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables.d
@@ -0,0 +1,42 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_tables.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_tables.html
+
+/++
+# Tables
+
+| Rounding mode | rndint(4.5) | rndint(5.5) | rndint(-4.5) | Notes |
+| ------------- | ----------: | ----------: | -----------: | ----- |
+| Round to nearest | 4 | 6 | -4 | Ties round to an even number |
+| Round down | 4 | 5 | -5 | &nbsp; |
+| Round up | 5 | 6 | -4 | &nbsp; |
+| Round to zero | 4 | 5 | -4 | &nbsp; |
+
+ this|that
+ ----|----
+ cell|cell<br>sell
+
+| abc | def |
+| --- | --- |
+| bar |
+| *bar* | baz | boo |
+
+> | quote |
+> | ----- |
+> | table |
+
+* | list |
+ | ---- |
+ | table |
+
+| default | left | center | right |
+| --- | :-- | :--: | --: |
+
+Look Ma, a table without a body!
+
+| not | a | table |
+| -- |
+| wrong number of header columns |
++/
+module test.compilable.ddoc_markdown_tables;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_verbose.d
new file mode 100644
index 0000000..d1aac1c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_verbose.d
@@ -0,0 +1,13 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_tables_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_tables_verbose.html
+
+/++
+Table:
+
+| this | that |
+| ---- | ---- |
+| cell | cell |
++/
+module test.compilable.ddoc_markdown_tables_verbose;
diff --git a/gcc/testsuite/gdc.test/compilable/ddocbackticks.d b/gcc/testsuite/gdc.test/compilable/ddocbackticks.d
index 8249c4b..533ff0c 100644
--- a/gcc/testsuite/gdc.test/compilable/ddocbackticks.d
+++ b/gcc/testsuite/gdc.test/compilable/ddocbackticks.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh backticks
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
/++
Closely related to std.datetime is <a href="core_time.html">`core.time`</a>,
diff --git a/gcc/testsuite/gdc.test/compilable/ddocunittest.d b/gcc/testsuite/gdc.test/compilable/ddocunittest.d
index 8c691b6..2762064 100644
--- a/gcc/testsuite/gdc.test/compilable/ddocunittest.d
+++ b/gcc/testsuite/gdc.test/compilable/ddocunittest.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS: -unittest
-// REQUIRED_ARGS: -D -w -o- -c -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh unittest
+// REQUIRED_ARGS: -D -w -o- -Dd${RESULTS_DIR}/compilable -o-
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
module ddocunittest;
@@ -189,12 +189,6 @@ static import core.stdc.stdlib;
unittest { fooStaticImport(); }
///
-void fooPublicImport() {}
-public import core.stdc.string;
-/// test
-unittest { fooPublicImport(); }
-
-///
void fooSelectiveImport() {}
import core.stdc.ctype : isalpha;
/// test
@@ -206,6 +200,32 @@ import io = core.stdc.stdio;
/// test
unittest { fooRenamedImport(); }
+/// This is a public import
+public import core.stdc.string;
+
+/// This is a mutiple public import
+public import core.stdc.stdarg, core.stdc.stdlib;
+
+/// This is a public selective import
+public import core.stdc.string : memcpy;
+
+/// This is a public selective renamed import
+public import core.stdc.string : copy = memcpy;
+
+/// This is a public multiple selective import
+public import core.stdc.string : memcpy, memcmp;
+
+/// This is a public multiple selective renamed import
+public import core.stdc.string : copy = memcpy, compare = memcmp;
+
+/// This is a public renamed import
+public import str = core.stdc.string;
+
+// This is a public import without a DDoc comment.
+// It should not be emitted to the documentation file.
+public import core.stdc.stdlib;
+
+
// ------------------------------------
// documented unittest after conditional declarations
@@ -276,7 +296,7 @@ else
unittest { int x6b; }
// ------------------------------------
-// 9474
+// https://issues.dlang.org/show_bug.cgi?id=9474
///
void foo9474() { }
@@ -323,7 +343,7 @@ template Template9474()
unittest { alias Template9474!() T; }
// ------------------------------------
-// 9713
+// https://issues.dlang.org/show_bug.cgi?id=9713
///
void fooNoDescription() {}
@@ -334,7 +354,7 @@ unittest { if (true) {fooNoDescription(); } /* comment */ }
// ------------------------------------
-/// test for bugzilla 9757
+/// test for https://issues.dlang.org/show_bug.cgi?id=9757
void foo9757() {}
/// ditto
void bar9757() {}
@@ -371,7 +391,7 @@ unittest
}
// ------------------------------------
-// Issue 9758
+// https://issues.dlang.org/show_bug.cgi?id=9758
/// test
void foo(){}
@@ -380,7 +400,7 @@ void foo(){}
unittest { }
// ------------------------------------
-// Issue 10519
+// https://issues.dlang.org/show_bug.cgi?id=10519
///
bool balancedParens10519(string, char, char) { return true; }
@@ -392,7 +412,7 @@ unittest
}
// ------------------------------------
-// Issue 12097
+// https://issues.dlang.org/show_bug.cgi?id=12097
/// declaration
struct S12097
@@ -420,7 +440,7 @@ unittest
}
// ------------------------------------
-// 14594
+// https://issues.dlang.org/show_bug.cgi?id=14594
/*******************
* testA
diff --git a/gcc/testsuite/gdc.test/compilable/debugInference.d b/gcc/testsuite/gdc.test/compilable/debugInference.d
new file mode 100644
index 0000000..1d4f157
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/debugInference.d
@@ -0,0 +1,55 @@
+/*
+REQUIRED_ARGS: -debug
+TEST_OUTPUT:
+---
+compilable/debugInference.d(35): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+---
+https://issues.dlang.org/show_bug.cgi?id=20507
+*/
+
+
+void main() pure nothrow @safe @nogc
+{
+ debug foo();
+ bar!()();
+}
+
+void foo() @system
+{
+ // Just to be sure its neither @nogc, pure or nothrow
+ __gshared int counter = 0;
+
+ if (counter++)
+ throw new Exception(new immutable(char)[counter]);
+}
+
+void bar()()
+{
+ debug {
+ foo();
+
+ auto fPtr = &S.f;
+ auto f2Ptr = &f2;
+
+ S s;
+ delete s;
+
+ int* ptr = cast(int*) 0;
+ int[] slice = ptr[0 .. 4];
+ int val = ptr[1];
+
+ void[] bytes = slice;
+ bytes[] = bytes[];
+
+ scope int n;
+ int* pn = &n;
+ }
+}
+
+class S {
+ void f() @safe {}
+}
+
+ref int f2(return ref int i) {
+ return i;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/defa.d b/gcc/testsuite/gdc.test/compilable/defa.d
index 4fb700b..a922207 100644
--- a/gcc/testsuite/gdc.test/compilable/defa.d
+++ b/gcc/testsuite/gdc.test/compilable/defa.d
@@ -1,5 +1,5 @@
// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/defaa.d imports/defab.d imports/defac.d imports/defad.d
module defa;
private import imports.defaa;
diff --git a/gcc/testsuite/gdc.test/compilable/depmsg.d b/gcc/testsuite/gdc.test/compilable/depmsg.d
index c841916..9b005d8 100644
--- a/gcc/testsuite/gdc.test/compilable/depmsg.d
+++ b/gcc/testsuite/gdc.test/compilable/depmsg.d
@@ -1,6 +1,22 @@
-// REQUIRED_ARGS: -d
-// PERMUTE_ARGS: -dw
-
+/*
+REQUIRED_ARGS: -dw
+TEST_OUTPUT:
+---
+compilable/depmsg.d(39): Deprecation: struct `depmsg.main.Inner.A` is deprecated - With message!
+compilable/depmsg.d(39): Deprecation: struct `depmsg.main.Inner.A` is deprecated - With message!
+compilable/depmsg.d(40): Deprecation: class `depmsg.main.Inner.B` is deprecated - With message!
+compilable/depmsg.d(40): Deprecation: class `depmsg.main.Inner.B` is deprecated - With message!
+compilable/depmsg.d(41): Deprecation: interface `depmsg.main.Inner.C` is deprecated - With message!
+compilable/depmsg.d(41): Deprecation: interface `depmsg.main.Inner.C` is deprecated - With message!
+compilable/depmsg.d(42): Deprecation: union `depmsg.main.Inner.D` is deprecated - With message!
+compilable/depmsg.d(42): Deprecation: union `depmsg.main.Inner.D` is deprecated - With message!
+compilable/depmsg.d(43): Deprecation: enum `depmsg.main.Inner.E` is deprecated - With message!
+compilable/depmsg.d(43): Deprecation: enum `depmsg.main.Inner.E` is deprecated - With message!
+compilable/depmsg.d(45): Deprecation: alias `depmsg.main.Inner.G` is deprecated - With message!
+compilable/depmsg.d(46): Deprecation: variable `depmsg.main.Inner.H` is deprecated - With message!
+compilable/depmsg.d(47): Deprecation: class `depmsg.main.Inner.I()` is deprecated - With message!
+---
+*/
void main()
{
class Inner
diff --git a/gcc/testsuite/gdc.test/compilable/depsOutput9948.d b/gcc/testsuite/gdc.test/compilable/depsOutput9948.d
deleted file mode 100644
index 0876094..0000000
--- a/gcc/testsuite/gdc.test/compilable/depsOutput9948.d
+++ /dev/null
@@ -1,12 +0,0 @@
-// PERMUTE_ARGS:
-// REQUIRED_ARGS: -deps=${RESULTS_DIR}/compilable/depsOutput9948.deps
-// POST_SCRIPT: compilable/extra-files/depsOutput.sh
-// EXTRA_SOURCES: extra-files/depsOutput9948a.d
-
-module depsOutput9948;
-import depsOutput9948a;
-
-void main()
-{
- templateFunc!("import std.string;")();
-}
diff --git a/gcc/testsuite/gdc.test/compilable/dip22.d b/gcc/testsuite/gdc.test/compilable/dip22.d
index 5c0201a..0471218 100644
--- a/gcc/testsuite/gdc.test/compilable/dip22.d
+++ b/gcc/testsuite/gdc.test/compilable/dip22.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/dip22.d
import imports.dip22;
class Foo : Base1, Base2
diff --git a/gcc/testsuite/gdc.test/compilable/dip22d.d b/gcc/testsuite/gdc.test/compilable/dip22d.d
index 1becf0c..cfb27fa 100644
--- a/gcc/testsuite/gdc.test/compilable/dip22d.d
+++ b/gcc/testsuite/gdc.test/compilable/dip22d.d
@@ -1,6 +1,5 @@
-/*
-REQUIRED_ARGS:
-*/
+// REQUIRED_ARGS:
+// EXTRA_FILES: imports/dip22d.d imports/dip22e.d
// https://github.com/dlang/DIPs/blob/master/DIPs/archive/DIP22.md
diff --git a/gcc/testsuite/gdc.test/compilable/disable_new.d b/gcc/testsuite/gdc.test/compilable/disable_new.d
new file mode 100644
index 0000000..647d47f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/disable_new.d
@@ -0,0 +1,11 @@
+class C
+{
+ // force user of a type to use an external allocation strategy
+ @disable new();
+}
+
+struct S
+{
+ // force user of a type to use an external allocation strategy
+ @disable new();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_21217.d b/gcc/testsuite/gdc.test/compilable/dtoh_21217.d
new file mode 100644
index 0000000..8836ad1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_21217.d
@@ -0,0 +1,91 @@
+/*
+REQUIRED_ARGS: -HC=verbose -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler v$n$
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+struct Foo final
+{
+ int32_t a;
+ enum : int32_t { b = 2 };
+
+ // Ignored enum `dtoh_21217.Foo.c` because it is `private`.
+protected:
+ enum : int32_t { d = 4 };
+
+ enum : int32_t { e = 5 };
+
+public:
+ enum : int32_t { f = 6 };
+
+ enum : int32_t { g = 7 };
+
+private:
+ enum class Bar
+ {
+ a = 1,
+ b = 2,
+ };
+
+ // Ignored enum `dtoh_21217.Foo.h` because it is `private`.
+public:
+ Foo() :
+ a(1)
+ {
+ }
+ Foo(int32_t a) :
+ a(a)
+ {}
+};
+
+---
+*/
+
+
+extern(C++) struct Foo {
+ int a = 1;
+ enum b = 2;
+ private enum c = 3;
+ protected enum d = 4;
+ package enum e = 5;
+ public enum f = 6;
+ export enum g = 7;
+
+ private enum Bar { a = 1, b = 2 }
+ private enum h = Bar.a;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration.d
new file mode 100644
index 0000000..e0a96d4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration.d
@@ -0,0 +1,217 @@
+/+
+REQUIRED_ARGS: -HC=silent -c -o- -Icompilable/extra-files
+PERMUTE_ARGS:
+EXTRA_FILES: extra-files/dtoh_imports.d extra-files/dtoh_imports2.d
+
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+class C;
+
+extern void importFunc();
+
+class ImportsC
+{
+};
+
+typedef int32_t MyStdcInt;
+
+enum
+{
+ IgnoreErrors = 0,
+};
+
+typedef int32_t T;
+
+extern "C" int32_t x;
+
+extern "C" int32_t foo(int32_t x);
+
+extern int32_t foo2(int32_t x);
+
+struct S;
+
+typedef S aliasS;
+
+struct S2;
+
+typedef S2 aliasS2;
+
+typedef C* aliasC;
+
+class C2;
+
+typedef C2* aliasC2;
+
+typedef size_t(*F)(size_t x);
+
+template <typename T, typename U>
+struct TS final
+{
+ TS()
+ {
+ }
+};
+
+template <typename T, typename U>
+using TSD = TS<T, U>;
+typedef TSD<int32_t, int16_t > TSI;
+
+using aliasName = ImportsC;
+
+using MyStdc = MyStdcInt;
+
+struct FullImport final
+{
+ using ImportsC = ::ImportsC;
+ using MyStdcInt = ::MyStdcInt;
+ FullImport()
+ {
+ }
+};
+
+struct SelectiveImports final
+{
+ using aliasName = ::ImportsC;
+ SelectiveImports()
+ {
+ }
+};
+
+struct PrivateImport final
+{
+ PrivateImport()
+ {
+ }
+};
+
+typedef /* noreturn */ char Impossible[0];
+
+template <typename T>
+struct Array final
+{
+ // Ignoring var length alignment 0
+ uint32_t length;
+ Array()
+ {
+ }
+};
+
+typedef Array<char > DString;
+---
++/
+
+extern (C++):
+
+alias T = int;
+
+extern (C) int x;
+
+alias u = x;
+
+extern (C) int foo(int x)
+{
+ return x * 42;
+}
+
+alias fun = foo;
+
+extern (C++) int foo2(int x)
+{
+ return x * 42;
+}
+
+alias fun2 = foo2;
+
+extern (C) struct S;
+
+alias aliasS = S;
+
+extern (C++) struct S2;
+
+alias aliasS2 = S2;
+
+extern (C) class C;
+
+alias aliasC = C;
+
+extern (C++) class C2;
+
+alias aliasC2 = C2;
+
+alias F = size_t function (size_t x);
+
+extern(C++) struct TS(T, U) {}
+alias TSD = TS;
+alias TSI = TSD!(int, short);
+
+public import dtoh_imports :
+ importFunc,
+ aliasName = ImportsC,
+ MyStdc = MyStdcInt;
+
+struct FullImport
+{
+ public import dtoh_imports;
+
+}
+
+struct SelectiveImports
+{
+ public import dtoh_imports :
+ importFunc,
+ aliasName = ImportsC;
+
+ public static import dtoh_imports;
+}
+
+struct PrivateImport
+{
+ import dtoh_imports;
+
+}
+
+alias Impossible = noreturn;
+
+struct Array(T)
+{
+ uint length;
+ alias opDollar = length;
+ alias dim = length;
+}
+alias DString = Array!(char);
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration_98.d b/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration_98.d
new file mode 100644
index 0000000..1499d04
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_AliasDeclaration_98.d
@@ -0,0 +1,56 @@
+/*
+REQUIRED_ARGS: -HC=verbose -extern-std=c++98 -o-
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler v$n$
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+template <typename T, typename U>
+struct TS final
+{
+ TS()
+ {
+ }
+};
+
+// Ignored dtoh_AliasDeclaration_98.TSD because `using` declarations require C++ 11
+---
+*/
+
+extern(C++):
+
+struct TS(T, U) {}
+alias TSD = TS;
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d
new file mode 100644
index 0000000..bcf5558
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d
@@ -0,0 +1,106 @@
+/*
+REQUIRED_ARGS: -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+struct S final
+{
+ union
+ {
+ int32_t x;
+ char c[4$?:32=u|64=LLU$];
+ };
+ struct
+ {
+ int32_t y;
+ double z;
+ extern "C" void foo();
+ void bar();
+ };
+ struct
+ {
+ int32_t outerPrivate;
+ };
+ struct
+ {
+ int32_t innerPrivate;
+ int32_t innerBar;
+ };
+ S()
+ {
+ }
+};
+
+extern void foo();
+---
+*/
+
+extern (C++) struct S
+{
+ union
+ {
+ int x;
+ char[4] c;
+ }
+
+ struct
+ {
+ int y;
+ double z;
+ extern(C) void foo() {}
+ extern(C++) void bar() {}
+ }
+
+ // Private not emitted because AnonDeclaration has no protection
+ private struct
+ {
+ int outerPrivate;
+ }
+
+ public struct {
+ // Private cannot be exported to C++
+ private int innerPrivate;
+ int innerBar;
+ }
+}
+
+extern (D)
+{
+ extern(C++) void foo() {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d
new file mode 100644
index 0000000..6995a67
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d
@@ -0,0 +1,67 @@
+/*
+REQUIRED_ARGS: -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+namespace nameSpace
+{
+ extern void fn();
+
+ namespace nameSpace2
+ {
+ extern void fn2();
+
+ }
+ extern double identity(double _param_0);
+
+}
+---
+*/
+
+extern(C++, "nameSpace")
+{
+ void fn() {}
+
+ extern(C++, nameSpace2)
+ {
+ void fn2() {}
+ }
+
+ double identity(double) { return _param_0; }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d
new file mode 100644
index 0000000..6274e9f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d
@@ -0,0 +1,347 @@
+/++
+REQUIRED_ARGS: -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+class ForwardClass;
+
+class BaseClass
+{
+public:
+ virtual void memberFun(ForwardClass* sds);
+};
+
+class C
+{
+public:
+ int8_t a;
+ int32_t b;
+ int64_t c;
+};
+
+class C2
+{
+public:
+ int32_t a;
+ int32_t b;
+ int64_t c;
+ C2(int32_t a);
+ virtual const C* const constRet();
+ virtual void constPar(const C* const c);
+ virtual void constThis() const;
+};
+
+class Aligned
+{
+public:
+ int8_t a;
+ int32_t b;
+ int64_t c;
+ Aligned(int32_t a);
+};
+
+class A
+{
+public:
+ int32_t a;
+ C* c;
+ virtual void foo();
+ extern "C" virtual void bar();
+ virtual void baz(int32_t x = 42);
+ struct
+ {
+ int32_t x;
+ int32_t y;
+ };
+ union
+ {
+ int32_t u1;
+ char u2[4$?:32=u|64=LLU$];
+ };
+ struct Inner final
+ {
+ int32_t x;
+ Inner() :
+ x()
+ {
+ }
+ Inner(int32_t x) :
+ x(x)
+ {}
+ };
+
+ class InnerC
+ {
+ public:
+ int32_t x;
+ };
+
+ class NonStaticInnerC
+ {
+ public:
+ int32_t x;
+ A* this;
+ };
+
+ typedef Inner I;
+ class CC;
+
+};
+
+class I1
+{
+public:
+ virtual void foo() = 0;
+};
+
+class I2 : public I1
+{
+public:
+ virtual void bar() = 0;
+};
+
+class B : public A, public I1, public I2
+{
+public:
+ using A::bar;
+ void foo();
+ void bar();
+};
+
+class Parent
+{
+ virtual void __vtable_slot_0();
+ virtual void __vtable_slot_1();
+public:
+ virtual void foo();
+};
+
+class Child final : public Parent
+{
+public:
+ void foo() /* const */;
+};
+
+class VisitorBase
+{
+public:
+ virtual void vir();
+ void stat();
+};
+
+class VisitorInter : public VisitorBase
+{
+public:
+ using VisitorBase::vir;
+ virtual void vir(int32_t i);
+ using VisitorBase::stat;
+ void stat(int32_t i);
+};
+
+class Visitor : public VisitorInter
+{
+public:
+ using VisitorInter::vir;
+ using VisitorInter::stat;
+ virtual void vir(bool b);
+ virtual void vir(char d);
+};
+
+class ForwardClass : public BaseClass
+{
+};
+---
++/
+
+/*
+ClassDeclaration has the following issues:
+ * align(n) does nothing. You can use align on classes in C++, though It is generally regarded as bad practice and should be avoided
+*/
+
+extern (C++) class C
+{
+ byte a;
+ int b;
+ long c;
+}
+
+extern (C++) class C2
+{
+ int a = 42;
+ int b;
+ long c;
+
+ this(int a) {}
+
+ const(C) constRet() { return null; }
+ void constPar(const C c) {}
+ void constThis() const {}
+}
+
+extern (C) class C3
+{
+ int a = 42;
+ int b;
+ long c;
+
+ this(int a) {}
+}
+
+extern (C++) align(1) class Aligned
+{
+ byte a;
+ int b;
+ long c;
+
+ this(int a) {}
+}
+
+extern (C++) class A
+{
+ int a;
+ C c;
+
+ void foo();
+ extern (C) void bar() {}
+ extern (C++) void baz(int x = 42) {}
+
+ struct
+ {
+ int x;
+ int y;
+ }
+
+ union
+ {
+ int u1;
+ char[4] u2;
+ }
+
+ struct Inner
+ {
+ int x;
+ }
+
+ static extern(C++) class InnerC
+ {
+ int x;
+ }
+
+ class NonStaticInnerC
+ {
+ int x;
+ }
+
+ alias I = Inner;
+
+ extern(C++) class CC;
+
+}
+
+extern(C++):
+interface I1
+{
+ void foo();
+}
+interface I2 : I1
+{
+ void bar();
+}
+
+class B : A, I1, I2
+{
+ alias bar = A.bar;
+ override void foo() {}
+ override void bar() {}
+}
+
+class Parent
+{
+ extern(D) void over() {}
+ extern(D) void over(int) {}
+ void foo() {}
+}
+
+final class Child : Parent
+{
+ extern(D) override void over() {}
+ override void foo() const {}
+}
+
+class VisitorBase
+{
+ void vir() {}
+
+ final void stat() {}
+}
+
+class VisitorInter : VisitorBase
+{
+ alias vir = VisitorBase.vir;
+ void vir(int i) {}
+
+ alias stat = VisitorBase.stat;
+ final void stat(int i) {}
+}
+
+class Visitor : VisitorInter
+{
+ alias vir = VisitorInter.vir;
+
+ alias stat = VisitorInter.stat;
+
+ mixin Methods!() m;
+ alias vir = m.vir;
+}
+
+mixin template Methods()
+{
+ extern(C++) void vir(bool b) {}
+
+ extern(C++) void vir(char d) {}
+}
+
+class ForwardClass : BaseClass
+{
+}
+
+class BaseClass
+{
+ void memberFun(ForwardClass sds);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d
new file mode 100644
index 0000000..1bfc25b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d
@@ -0,0 +1,286 @@
+/*
+REQUIRED_ARGS: -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+struct S final
+{
+ int8_t a;
+ int32_t b;
+ int64_t c;
+ _d_dynamicArray< int32_t > arr;
+ S() :
+ a(),
+ b(),
+ c(),
+ arr()
+ {
+ }
+ S(int8_t a, int32_t b = 0, int64_t c = 0LL, _d_dynamicArray< int32_t > arr = {}) :
+ a(a),
+ b(b),
+ c(c),
+ arr(arr)
+ {}
+};
+
+struct S2 final
+{
+ int32_t a;
+ int32_t b;
+ int64_t c;
+ S d;
+ S2(int32_t a);
+ S2(char ) = delete;
+ S2() :
+ a(42),
+ b(),
+ c()
+ {
+ }
+};
+
+struct S3 final
+{
+ int32_t a;
+ int32_t b;
+ int64_t c;
+ extern "C" S3(int32_t a);
+ S3() :
+ a(42),
+ b(),
+ c()
+ {
+ }
+};
+
+struct S4 final
+{
+ int32_t a;
+ int64_t b;
+ int32_t c;
+ int8_t d;
+ S4() :
+ a(),
+ b(),
+ c(),
+ d()
+ {
+ }
+ S4(int32_t a, int64_t b = 0LL, int32_t c = 0, int8_t d = 0) :
+ a(a),
+ b(b),
+ c(c),
+ d(d)
+ {}
+};
+
+#pragma pack(push, 1)
+struct Aligned final
+{
+ int8_t a;
+ int32_t b;
+ int64_t c;
+ Aligned(int32_t a);
+ Aligned() :
+ a(),
+ b(),
+ c()
+ {
+ }
+};
+#pragma pack(pop)
+
+struct Null final
+{
+ void* field;
+ Null() :
+ field(nullptr)
+ {
+ }
+ Null(void* field) :
+ field(field)
+ {}
+};
+
+struct A final
+{
+ int32_t a;
+ S s;
+ extern "C" void bar();
+ void baz(int32_t x = 42);
+ struct
+ {
+ int32_t x;
+ int32_t y;
+ };
+ union
+ {
+ int32_t u1;
+ char u2[4$?:32=u|64=LLU$];
+ };
+ struct Inner final
+ {
+ int32_t x;
+ Inner() :
+ x()
+ {
+ }
+ Inner(int32_t x) :
+ x(x)
+ {}
+ };
+
+ typedef Inner I;
+ class C;
+
+ A() :
+ a(),
+ s()
+ {
+ }
+ A(int32_t a, S s = S(0, 0, 0LL, {})) :
+ a(a),
+ s(s)
+ {}
+};
+
+union U
+{
+ int32_t i;
+ char c;
+};
+---
+*/
+
+/*
+StructDeclaration has the following issues:
+ * align different than 1 does nothing; we should support align(n), where `n` in [1, 2, 4, 8, 16]
+ * align(n): inside struct definition doesn’t add alignment, but breaks generation of default ctors
+*/
+
+extern (C++) struct S
+{
+ byte a;
+ int b;
+ long c;
+ int[] arr;
+}
+
+extern (C++) struct S2
+{
+ int a = 42;
+ int b;
+ long c;
+ S d = void;
+
+ this(int a) {}
+ extern(D) this(int, int, long) {}
+ @disable this(char);
+}
+
+extern (C) struct S3
+{
+ int a = 42;
+ int b;
+ long c;
+
+ this(int a) {}
+}
+
+extern (C) struct S4
+{
+ int a;
+ long b;
+ int c;
+ byte d;
+}
+
+extern (C++) align(1) struct Aligned
+{
+ //align(1):
+ byte a;
+ int b;
+ long c;
+
+ this(int a) {}
+}
+
+extern (C++) struct Null
+{
+ void* field = null;
+}
+
+extern (C++) struct A
+{
+ int a;
+ S s;
+
+ extern (D) void foo();
+ extern (C) void bar() {}
+ extern (C++) void baz(int x = 42) {}
+
+ struct
+ {
+ int x;
+ int y;
+ }
+
+ union
+ {
+ int u1;
+ char[4] u2;
+ }
+
+ struct Inner
+ {
+ int x;
+ }
+
+ alias I = Inner;
+
+ extern(C++) class C;
+
+}
+
+extern(C++) union U
+{
+ int i;
+ char c;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d
new file mode 100644
index 0000000..5f747fd
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d
@@ -0,0 +1,401 @@
+/*
+REQUIRED_ARGS: -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+typedef uint$?:32=32|64=64$_t size_t;
+
+struct Outer final
+{
+ int32_t a;
+ struct Member final
+ {
+ typedef int32_t Nested;
+ Member()
+ {
+ }
+ };
+
+ Outer() :
+ a()
+ {
+ }
+ Outer(int32_t a) :
+ a(a)
+ {}
+};
+
+enum : int32_t { SomeOtherLength = 1 };
+
+struct ActualBuffer final
+{
+ ActualBuffer()
+ {
+ }
+};
+
+template <typename T>
+struct A final
+{
+ // Ignoring var x alignment 0
+ T x;
+ // Ignoring var Enum alignment 0
+ enum : int32_t { Enum = 42 };
+
+ // Ignoring var GsharedNum alignment 0
+ static int32_t GsharedNum;
+ // Ignoring var MemNum alignment 0
+ const int32_t MemNum;
+ void foo();
+ A()
+ {
+ }
+};
+
+template <typename T>
+struct NotInstantiated final
+{
+ // Ignoring var noInit alignment 0
+ // Ignoring var missingSem alignment 0
+ NotInstantiated()
+ {
+ }
+};
+
+struct B final
+{
+ A<int32_t > x;
+ B() :
+ x()
+ {
+ }
+ B(A<int32_t > x) :
+ x(x)
+ {}
+};
+
+template <typename T>
+struct Foo final
+{
+ // Ignoring var val alignment 0
+ T val;
+ Foo()
+ {
+ }
+};
+
+template <typename T>
+struct Bar final
+{
+ // Ignoring var v alignment 0
+ Foo<T > v;
+ Bar()
+ {
+ }
+};
+
+template <typename T>
+struct Array final
+{
+ typedef Array This;
+ typedef typeof(1 + 2) Int;
+ typedef typeof(T::a) IC;
+ Array(size_t dim);
+ ~Array();
+ void get() const;
+ template <typename T>
+ bool opCast() const;
+ // Ignoring var i alignment 0
+ typename T::Member i;
+ // Ignoring var j alignment 0
+ typename Outer::Member::Nested j;
+ void visit(typename T::Member::Nested i);
+ Array()
+ {
+ }
+};
+
+template <typename T, typename U>
+extern T foo(U u);
+
+extern A<A<int32_t > > aaint;
+
+template <typename T>
+class Parent
+{
+ // Ignoring var parentMember alignment 0
+public:
+ T parentMember;
+ void parentFinal();
+ virtual void parentVirtual();
+};
+
+template <typename T>
+class Child final : public Parent<T >
+{
+ // Ignoring var childMember alignment 0
+public:
+ T childMember;
+ void parentVirtual();
+ T childFinal();
+};
+
+extern void withDefTempl(A<int32_t > a = A<int32_t >(2, 13));
+
+template <typename T>
+extern void withDefTempl2(A<T > a = static_cast<A<T >>(A<T >(2)));
+
+class ChildInt : public Parent<int32_t >
+{
+};
+
+struct HasMixins final
+{
+ void foo(int32_t t);
+ HasMixins()
+ {
+ }
+};
+
+template <typename T>
+struct HasMixinsTemplate final
+{
+ void foo(T t);
+ HasMixinsTemplate()
+ {
+ }
+};
+
+extern HasMixinsTemplate<bool > hmti;
+
+template <typename T>
+struct NotAA final
+{
+ // Ignoring var length alignment 0
+ enum : int32_t { length = 12 };
+
+ // Ignoring var buffer alignment 0
+ T buffer[length];
+ // Ignoring var otherBuffer alignment 0
+ T otherBuffer[SomeOtherLength];
+ // Ignoring var calcBuffer alignment 0
+ T calcBuffer[foo(1)];
+ NotAA()
+ {
+ }
+};
+
+template <typename Buffer>
+struct BufferTmpl final
+{
+ // Ignoring var buffer alignment 0
+ Buffer buffer;
+ // Ignoring var buffer2 alignment 0
+ Buffer buffer2;
+ BufferTmpl()
+ {
+ }
+};
+
+struct ImportedBuffer final
+{
+ typedef ActualBuffer Buffer;
+ ActualBuffer buffer2;
+ ImportedBuffer()
+ {
+ }
+};
+---
+*/
+
+extern (C++) struct A(T)
+{
+ T x;
+ enum Enum = 42;
+ __gshared GsharedNum = 43;
+ immutable MemNum = 13;
+ void foo() {}
+}
+
+// Invalid declarations accepted because it's not instantiated
+extern (C++) struct NotInstantiated(T)
+{
+ enum T noInit;
+ enum missingSem = T.init;
+}
+
+extern (C++) struct B
+{
+ A!int x;
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20604
+extern(C++)
+{
+ struct Foo (T)
+ {
+ T val;
+ }
+
+ struct Bar (T)
+ {
+ Foo!T v;
+ }
+}
+
+extern (C++) struct Array(T)
+{
+ alias This = typeof(this);
+ alias Int = typeof(1 + 2);
+ alias IC = typeof(T.a);
+
+ this(size_t dim) pure nothrow {}
+ @disable this(this);
+ ~this() {}
+ void get() const {}
+
+ bool opCast(T)() const pure nothrow @nogc @safe
+ if (is(T == bool))
+ {
+ return str.ptr !is null;
+ }
+
+ T.Member i;
+ Outer.Member.Nested j;
+ void visit(T.Member.Nested i) {}
+}
+
+struct Outer
+{
+ int a;
+ static struct Member
+ {
+ alias Nested = int;
+ }
+}
+
+// alias AO = Array!Outer;
+
+extern(C++) T foo(T, U)(U u) { return T.init; }
+
+extern(C++) __gshared A!(A!int) aaint;
+
+extern(C++) class Parent(T)
+{
+ T parentMember;
+ final void parentFinal() {}
+ void parentVirtual() {}
+}
+
+extern(C++) final class Child(T) : Parent!T
+{
+ T childMember;
+ override void parentVirtual() {}
+ T childFinal() { return T.init; }
+}
+
+extern(C++) void withDefTempl(A!int a = A!int(2)) {}
+
+extern(C++) void withDefTempl2(T)(A!T a = A!T(2)) {}
+
+extern(C++) alias withDefTempl2Inst = withDefTempl2!int;
+
+extern(C++) class ChildInt : Parent!int {}
+
+/******************************************************
+ * Mixins
+ */
+
+extern (C++):
+
+mixin template MixinA(T)
+{
+ void foo(T t) {}
+}
+
+mixin template MixinB() {}
+
+struct HasMixins
+{
+ mixin MixinA!int;
+ mixin MixinB;
+}
+
+struct HasMixinsTemplate(T)
+{
+ mixin MixinA!T;
+ mixin MixinB;
+}
+
+__gshared HasMixinsTemplate!bool hmti;
+
+/// Declarations that look like associative arrays
+
+extern(D) enum SomeOtherLength = 1;
+
+struct NotAA(T)
+{
+ private:
+ enum length = 12;
+ public:
+ T[length] buffer;
+ T[SomeOtherLength] otherBuffer;
+ T[foo(1)] calcBuffer;
+}
+
+// Same name but hidden by the template paramter
+extern (D) struct Buffer {}
+extern (D) struct ActualBuffer {}
+
+struct BufferTmpl(Buffer)
+{
+ Buffer buffer;
+ mixin BufferMixin!();
+}
+
+struct ImportedBuffer
+{
+ alias Buffer = ActualBuffer;
+ mixin BufferMixin!();
+}
+
+mixin template BufferMixin()
+{
+ Buffer buffer2;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_UnionDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_UnionDeclaration.d
new file mode 100644
index 0000000..b609cc2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_UnionDeclaration.d
@@ -0,0 +1,93 @@
+/+
+REQUIRED_ARGS: -o- -HC
+
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+union U1
+{
+ int32_t a;
+ double d;
+};
+
+union U2
+{
+ double d;
+ char* ptr;
+};
+
+struct S final
+{
+ int32_t i;
+ U1 u1;
+ U2 u2;
+ S() :
+ i(),
+ u1(),
+ u2()
+ {
+ }
+ S(int32_t i, U1 u1 = U1(0), U2 u2 = U2(NAN)) :
+ i(i),
+ u1(u1),
+ u2(u2)
+ {}
+};
+---
++/
+
+extern (C++):
+
+union U1
+{
+ int a;
+ double d;
+}
+
+union U2
+{
+ double d;
+ char* ptr;
+}
+
+struct S
+{
+ int i;
+ U1 u1;
+ U2 u2;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_VarDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_VarDeclaration.d
new file mode 100644
index 0000000..f9e57f9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_VarDeclaration.d
@@ -0,0 +1,116 @@
+/*
+REQUIRED_ARGS: -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+#if !defined(_d_real)
+# define _d_real long double
+#endif
+
+extern "C" int32_t z;
+
+extern int32_t t;
+
+struct S;
+
+struct S2;
+
+class C2;
+
+union U;
+
+union U2;
+
+extern "C" size_t v;
+
+extern nullptr_t typeof_null;
+
+extern nullptr_t inferred_null;
+
+extern int32_t i;
+
+extern _d_real r;
+
+extern int32_t si[4$?:32=u|64=LLU$];
+
+extern const _d_dynamicArray< const int32_t > di;
+
+extern void* ii;
+
+extern const int32_t* const pi;
+
+extern int16_t(*func)(float , bool , ...);
+---
+*/
+
+int x = 42;
+
+extern int y;
+
+extern (C) int z;
+
+extern (C++) __gshared int t;
+
+extern (C) struct S;
+
+extern (C++) struct S2;
+
+extern (C) class C;
+
+extern (C++) class C2;
+
+extern (C) union U;
+
+extern (C++) union U2;
+
+extern (C) size_t v;
+
+extern (C++) __gshared typeof(null) typeof_null = null;
+extern (C++) __gshared inferred_null = null;
+
+extern(C++):
+__gshared
+{
+ int i;
+ real r;
+ int[4] si;
+ const int[] di;
+ int[int] ii;
+ const int* pi;
+ short function(float, bool, ...) func;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_cpp98_compat.d b/gcc/testsuite/gdc.test/compilable/dtoh_cpp98_compat.d
new file mode 100644
index 0000000..b291cf6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_cpp98_compat.d
@@ -0,0 +1,142 @@
+/*
+REQUIRED_ARGS: -extern-std=c++98 -HC -c -o- -Icompilable/extra-files
+PERMUTE_ARGS:
+EXTRA_FILES: extra-files/dtoh_imports.d extra-files/dtoh_imports2.d
+
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+class ImportsC
+{
+};
+
+struct Null final
+{
+ void* field;
+ _d_dynamicArray< const char > null_;
+private:
+ Null(int32_t );
+public:
+ Null() :
+ field(NULL),
+ null_()
+ {
+ }
+ Null(void* field, _d_dynamicArray< const char > null_ = _d_dynamicArray< const char >()) :
+ field(field),
+ null_(null_)
+ {}
+};
+
+extern void* typeof_null;
+
+extern void* inferred_null;
+
+struct MyString final
+{
+ _d_dynamicArray< const char > str;
+ MyString() :
+ str()
+ {
+ }
+ MyString(_d_dynamicArray< const char > str) :
+ str(str)
+ {}
+};
+
+struct Wrapper final
+{
+ MyString s1;
+ MyString s2;
+ Wrapper() :
+ s1(MyString(_d_dynamicArray< const char >( 5, "Hello" ))),
+ s2(MyString(_d_dynamicArray< const char >()))
+ {
+ }
+ Wrapper(MyString s1, MyString s2 = MyString(_d_dynamicArray< const char >())) :
+ s1(s1),
+ s2(s2)
+ {}
+};
+
+class UsingBase
+{
+public:
+ virtual void foo();
+};
+
+class UsingChild : public UsingBase
+{
+public:
+};
+---
+*/
+
+extern (C++) struct Null
+{
+ void* field = null;
+ string null_ = null;
+
+ @disable this(int);
+}
+
+extern (C++) __gshared typeof(null) typeof_null = null;
+extern (C++) __gshared inferred_null = null;
+
+extern (C++) struct MyString
+{
+ string str;
+}
+
+extern (C++) struct Wrapper
+{
+ MyString s1 = MyString("Hello");
+ MyString s2 = MyString(null);
+}
+
+extern (C++) class UsingBase
+{
+ void foo() {}
+}
+
+extern (C++) class UsingChild : UsingBase
+{
+ alias foo = UsingBase.foo;
+}
+
+public import dtoh_imports : aliasName = ImportsC;
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_enum.d b/gcc/testsuite/gdc.test/compilable/dtoh_enum.d
new file mode 100644
index 0000000..6a0dfd9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_enum.d
@@ -0,0 +1,271 @@
+/+
+REQUIRED_ARGS: -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+enum : int32_t { Anon = 10 };
+
+enum : bool { Anon2 = true };
+
+static const char* const Anon3 = "wow";
+
+enum class Enum
+{
+ One = 0,
+ Two = 1,
+};
+
+extern const Enum constEnum;
+
+enum class EnumDefaultType
+{
+ One = 1,
+ Two = 2,
+};
+
+enum class EnumWithType : int8_t
+{
+ One = 1,
+ Two = 2,
+};
+
+enum
+{
+ AnonOne = 1,
+ AnonTwo = 2,
+};
+
+enum : int64_t
+{
+ AnonWithTypeOne = 1LL,
+ AnonWithTypeTwo = 2LL,
+};
+
+namespace EnumWithStringType
+{
+ static const char* const One = "1";
+ static const char* const Two = "2";
+};
+
+namespace EnumWStringType
+{
+ static const char16_t* const One = u"1";
+};
+
+namespace EnumDStringType
+{
+ static const char32_t* const One = U"1";
+};
+
+namespace EnumWithImplicitType
+{
+ static const char* const One = "1";
+ static const char* const Two = "2";
+};
+
+namespace
+{
+ static const char* const AnonWithStringOne = "1";
+ static const char* const AnonWithStringTwo = "2";
+};
+
+enum : int32_t { AnonMixedOne = 1 };
+enum : int64_t { AnonMixedTwo = 2LL };
+static const char* const AnonMixedA = "a";
+
+
+enum class STC
+{
+ a = 1,
+ b = 2,
+};
+
+static STC const STC_D = (STC)3;
+
+struct Foo final
+{
+ int32_t i;
+ Foo() :
+ i()
+ {
+ }
+ Foo(int32_t i) :
+ i(i)
+ {}
+};
+
+namespace MyEnum
+{
+ static Foo const A = Foo(42);
+ static Foo const B = Foo(84);
+};
+
+static /* MyEnum */ Foo const test = Foo(42);
+
+struct FooCpp final
+{
+ int32_t i;
+ FooCpp() :
+ i()
+ {
+ }
+ FooCpp(int32_t i) :
+ i(i)
+ {}
+};
+
+namespace MyEnumCpp
+{
+ static FooCpp const A = FooCpp(42);
+ static FooCpp const B = FooCpp(84);
+};
+
+static /* MyEnum */ Foo const testCpp = Foo(42);
+
+extern const bool e_b;
+
+enum class opaque;
+enum class typedOpaque : int64_t;
+---
++/
+
+extern(C++):
+
+enum Anon = 10;
+extern(C++) enum Anon2 = true;
+extern(C++) enum Anon3 = "wow";
+
+enum Enum
+{
+ One,
+ Two
+}
+
+extern(C++) __gshared const(Enum) constEnum;
+
+enum EnumDefaultType : int
+{
+ One = 1,
+ Two = 2
+}
+
+enum EnumWithType : byte
+{
+ One = 1,
+ Two = 2
+}
+
+enum
+{
+ AnonOne = 1,
+ AnonTwo = 2
+}
+
+enum : long
+{
+ AnonWithTypeOne = 1,
+ AnonWithTypeTwo = 2
+}
+
+enum EnumWithStringType : string
+{
+ One = "1",
+ Two = "2"
+}
+
+enum EnumWStringType : wstring
+{
+ One = "1"
+}
+
+enum EnumDStringType : dstring
+{
+ One = "1"
+}
+
+enum EnumWithImplicitType
+{
+ One = "1",
+ Two = "2"
+}
+
+enum : string
+{
+ AnonWithStringOne = "1",
+ AnonWithStringTwo = "2"
+}
+
+enum
+{
+ AnonMixedOne = 1,
+ long AnonMixedTwo = 2,
+ string AnonMixedA = "a"
+}
+
+enum STC
+{
+ a = 1,
+ b = 2,
+}
+
+extern(C++) enum STC_D = STC.a | STC.b;
+
+struct Foo { int i; }
+enum MyEnum { A = Foo(42), B = Foo(84) }
+extern(C++) enum test = MyEnum.A;
+
+extern(C++) struct FooCpp { int i; }
+enum MyEnumCpp { A = FooCpp(42), B = FooCpp(84) }
+extern(C++) enum testCpp = MyEnum.A;
+
+// currently unsupported enums
+extern(C++) enum b = [1, 2, 3];
+extern(C++) enum c = [2: 3];
+
+extern(C) void foo();
+extern(C++) enum d = &foo;
+
+__gshared immutable bool e_b;
+extern(C++) enum e = &e_b;
+
+enum opaque;
+enum typedOpaque : long;
+enum arrayOpaque : int[4]; // Cannot be exported to C++
+
+extern(D) enum hidden_d = 42; // Linkage prevents being exported to C++
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_enum_cpp98.d b/gcc/testsuite/gdc.test/compilable/dtoh_enum_cpp98.d
new file mode 100644
index 0000000..2330d76
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_enum_cpp98.d
@@ -0,0 +1,244 @@
+/+
+REQUIRED_ARGS: -extern-std=c++98 -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+static int32_t const Anon = 10;
+
+static bool const Anon2 = true;
+
+static const char* const Anon3 = "wow";
+
+enum Enum
+{
+ Enum_One = 0,
+ Enum_Two = 1,
+};
+
+enum EnumDefaultType
+{
+ EnumDefaultType_One = 1,
+ EnumDefaultType_Two = 2,
+};
+
+enum EnumWithType
+{
+ EnumWithType_One = 1,
+ EnumWithType_Two = 2,
+};
+
+enum
+{
+ AnonOne = 1,
+ AnonTwo = 2,
+};
+
+enum
+{
+ AnonWithTypeOne = 1LL,
+ AnonWithTypeTwo = 2LL,
+};
+
+namespace EnumWithStringType
+{
+ static const char* const One = "1";
+ static const char* const Two = "2";
+};
+
+namespace EnumWithImplicitType
+{
+ static const char* const One = "1";
+ static const char* const Two = "2";
+};
+
+namespace
+{
+ static const char* const AnonWithStringOne = "1";
+ static const char* const AnonWithStringTwo = "2";
+};
+
+static int32_t const AnonMixedOne = 1;
+static int64_t const AnonMixedTwo = 2LL;
+static const char* const AnonMixedA = "a";
+
+
+enum STC
+{
+ STC_a = 1,
+ STC_b = 2,
+};
+
+static STC const STC_D = (STC)3;
+
+struct Foo final
+{
+ int32_t i;
+ Foo() :
+ i()
+ {
+ }
+ Foo(int32_t i) :
+ i(i)
+ {}
+};
+
+namespace MyEnum
+{
+ static Foo const A = Foo(42);
+ static Foo const B = Foo(84);
+};
+
+static /* MyEnum */ Foo const test = Foo(42);
+
+struct FooCpp final
+{
+ int32_t i;
+ FooCpp() :
+ i()
+ {
+ }
+ FooCpp(int32_t i) :
+ i(i)
+ {}
+};
+
+namespace MyEnumCpp
+{
+ static FooCpp const A = FooCpp(42);
+ static FooCpp const B = FooCpp(84);
+};
+
+static /* MyEnum */ Foo const testCpp = Foo(42);
+
+extern const bool e_b;
+---
++/
+
+extern(C++):
+enum Anon = 10;
+extern(C++) enum Anon2 = true;
+extern(C++) enum Anon3 = "wow";
+
+enum Enum
+{
+ One,
+ Two
+}
+
+enum EnumDefaultType : int
+{
+ One = 1,
+ Two = 2
+}
+
+enum EnumWithType : byte
+{
+ One = 1,
+ Two = 2
+}
+
+enum
+{
+ AnonOne = 1,
+ AnonTwo = 2
+}
+
+enum : long
+{
+ AnonWithTypeOne = 1,
+ AnonWithTypeTwo = 2
+}
+
+enum EnumWithStringType : string
+{
+ One = "1",
+ Two = "2"
+}
+
+enum EnumWithImplicitType
+{
+ One = "1",
+ Two = "2"
+}
+
+enum : string
+{
+ AnonWithStringOne = "1",
+ AnonWithStringTwo = "2"
+}
+
+enum
+{
+ AnonMixedOne = 1,
+ long AnonMixedTwo = 2,
+ string AnonMixedA = "a"
+}
+
+enum STC
+{
+ a = 1,
+ b = 2,
+}
+
+extern(C++) enum STC_D = STC.a | STC.b;
+
+struct Foo { int i; }
+enum MyEnum { A = Foo(42), B = Foo(84) }
+extern(C++) enum test = MyEnum.A;
+
+extern(C++) struct FooCpp { int i; }
+enum MyEnumCpp { A = FooCpp(42), B = FooCpp(84) }
+extern(C++) enum testCpp = MyEnum.A;
+
+// currently unsupported enums
+extern(C++) enum b = [1, 2, 3];
+extern(C++) enum c = [2: 3];
+
+extern(C) void foo();
+extern(C++) enum d = &foo;
+
+__gshared immutable bool e_b;
+extern(C++) enum e = &e_b;
+
+// Opaque enums require C++ 11
+enum opaque;
+enum typedOpaque : long;
+enum arrayOpaque : int[4];
+
+extern(D) enum hidden_d = 42; // Linkage prevents being exported to C++
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_expressions.d b/gcc/testsuite/gdc.test/compilable/dtoh_expressions.d
new file mode 100644
index 0000000..7919c67
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_expressions.d
@@ -0,0 +1,127 @@
+/+
+REQUIRED_ARGS: -o- -HC
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+extern int32_t foo();
+
+extern int32_t* somePtr;
+
+extern void insertedCast(double a = (double) foo());
+
+extern void explicitCast(int32_t b = foo());
+
+extern void requiredCast(void* ptr = (void*) foo());
+
+extern void stcCast(const int32_t* const ci = (const int32_t* const) somePtr);
+
+---
++/
+
+extern (C++):
+
+int foo() { return 0; }
+
+__gshared int* somePtr;
+
+void insertedCast(double a = foo()) {}
+
+void explicitCast(int b = cast(int) foo()) {}
+
+void requiredCast(void* ptr = cast(void*) foo()) {}
+
+void stcCast(const int* ci = cast(immutable) somePtr) {}
+
+/+
+TEST_OUTPUT:
+---
+template <typename T>
+extern T insertedTmpl(double a = static_cast<double>(foo()));
+
+template <typename T>
+extern T explicitTmpl(int32_t b = (int32_t) foo());
+
+template <typename T>
+extern T requiredTmpl(void* ptr = (void*) foo());
+
+template <typename T>
+extern T stcCastTmpl(int32_t* ci = (int32_t*) somePtr);
+
+template <typename T>
+extern T paramCastTmpl(int32_t* ci = (T) somePtr);
+---
++/
+
+T insertedTmpl(T)(double a = foo()) {}
+
+T explicitTmpl(T)(int b = cast(int) foo()) {}
+
+T requiredTmpl(T)(void* ptr = cast(void*) foo()) {}
+
+T stcCastTmpl(T)(const int* ci = cast(immutable) somePtr) {}
+
+T paramCastTmpl(T)(const int* ci = cast(T) somePtr) {}
+
+/+
+TEST_OUTPUT:
+---
+
+struct Data final
+{
+ static Data* pt;
+ static int32_t* bar();
+ Data()
+ {
+ }
+};
+
+extern void useData(bool a = !Data::pt, bool b = Data::bar() == nullptr, bool c = Data::bar() != nullptr);
+---
++/
+
+struct Data
+{
+ __gshared Data* pt;
+ static int* bar() { return null; }
+}
+
+void useData(
+ bool a = !Data.pt,
+ bool b = Data.bar() is null,
+ bool c = Data.bar() !is null
+) {}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_extern_type.d b/gcc/testsuite/gdc.test/compilable/dtoh_extern_type.d
new file mode 100644
index 0000000..91641a6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_extern_type.d
@@ -0,0 +1,174 @@
+/*
+https://issues.dlang.org/show_bug.cgi?id=21219
+
+REQUIRED_ARGS: -o- -HC
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+#if !defined(_d_real)
+# define _d_real long double
+#endif
+
+class ClassFromStruct final
+{
+public:
+ void foo();
+ ClassFromStruct()
+ {
+ }
+};
+
+class ClassFromClass
+{
+public:
+ virtual void foo();
+};
+
+struct StructFromStruct final
+{
+ void foo();
+ StructFromStruct()
+ {
+ }
+};
+
+struct StructFromClass
+{
+ virtual void foo();
+};
+
+struct Floats final
+{
+ float f;
+ double d;
+ _d_real r;
+ double nan;
+ double inf;
+ double nInf;
+ Floats() :
+ f(1.23F),
+ d(4.56),
+ r(7.89L),
+ nan(NAN),
+ inf(INFINITY),
+ nInf(-INFINITY)
+ {
+ }
+ Floats(float f, double d = 4.56, _d_real r = 7.89L, double nan = NAN, double inf = INFINITY, double nInf = -INFINITY) :
+ f(f),
+ d(d),
+ r(r),
+ nan(nan),
+ inf(inf),
+ nInf(nInf)
+ {}
+};
+
+struct Null final
+{
+ _d_dynamicArray< const char > null_;
+ Null() :
+ null_()
+ {
+ }
+ Null(_d_dynamicArray< const char > null_) :
+ null_(null_)
+ {}
+};
+
+struct Wrapper final
+{
+ Null n1;
+ Null n2;
+ Wrapper() :
+ n1(Null({ 5, "Hello" })),
+ n2(Null({}))
+ {
+ }
+ Wrapper(Null n1, Null n2 = Null({})) :
+ n1(n1),
+ n2(n2)
+ {}
+};
+
+extern const _d_dynamicArray< const char > helloWorld;
+---
+*/
+
+extern (C++, class) struct ClassFromStruct
+{
+ void foo() {}
+}
+
+extern (C++, class) class ClassFromClass
+{
+ void foo() {}
+}
+
+extern (C++, struct) struct StructFromStruct
+{
+ void foo() {}
+}
+
+extern (C++, struct) class StructFromClass
+{
+ void foo() {}
+}
+
+extern(C++) struct Floats
+{
+ float f = 1.23f;
+ double d = 4.56;
+ real r = 7.89L;
+
+ double nan = double.nan;
+ double inf = double.infinity;
+ double nInf = -double.infinity;
+}
+
+extern (C++) struct Null
+{
+ string null_ = null;
+}
+
+extern (C++) struct Wrapper
+{
+ Null n1 = Null("Hello");
+ Null n2 = Null(null);
+}
+
+extern(C++) __gshared immutable string helloWorld = `"Hello\World!"`;
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d b/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d
new file mode 100644
index 0000000..483e58f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d
@@ -0,0 +1,265 @@
+/*
+REQUIRED_ARGS: -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+struct Child;
+class Struct;
+enum class Enum;
+class ExternDClass;
+struct ExternDStruct;
+template <typename T>
+class TemplClass;
+template <typename T>
+class TemplStruct;
+template <typename T>
+class ExternDTemplClass;
+struct OnlyByRef;
+
+struct Parent
+{
+ virtual void bar();
+};
+
+struct OuterStruct final
+{
+ struct NestedStruct final
+ {
+ NestedStruct()
+ {
+ }
+ };
+
+ OuterStruct()
+ {
+ }
+};
+
+struct ExternDStructRequired final
+{
+ int32_t member;
+ ExternDStructRequired() :
+ member()
+ {
+ }
+ ExternDStructRequired(int32_t member) :
+ member(member)
+ {}
+};
+
+template <typename T>
+struct ExternDTemplStruct final
+{
+ // Ignoring var member alignment 0
+ T member;
+ ExternDTemplStruct()
+ {
+ }
+};
+
+extern Child* child;
+
+struct Child : public Parent
+{
+};
+
+extern Struct* strPtr;
+
+class Struct final
+{
+public:
+ Struct()
+ {
+ }
+};
+
+extern Enum* enumPtr;
+
+enum class Enum
+{
+ foo = 0,
+};
+
+extern OuterStruct::NestedStruct* nestedStrPtr;
+
+extern ExternDClass* externDClassPtr;
+
+extern ExternDStruct* externDStrPtr;
+
+extern ExternDStructRequired externDStr2;
+
+extern TemplClass<int32_t >* templClass;
+
+template <typename T>
+class TemplClass
+{
+ // Ignoring var member alignment 0
+public:
+ T member;
+};
+
+extern TemplStruct<int32_t >* templStruct;
+
+template <typename T>
+class TemplStruct
+{
+ // Ignoring var member alignment 0
+public:
+ T member;
+};
+
+extern ExternDTemplClass<int32_t >* externTemplClass;
+
+extern ExternDTemplStruct<int32_t > externTemplStruct;
+
+extern void foo(OnlyByRef& obr);
+
+---
+*/
+
+extern (C++):
+
+__gshared Child child;
+
+extern (C++, struct)
+class Child : Parent {}
+
+extern (C++, struct)
+class Parent {
+ void bar() {}
+}
+
+//******************************************************
+
+__gshared Struct* strPtr;
+
+extern (C++, class)
+struct Struct {}
+
+//******************************************************
+
+__gshared Enum* enumPtr;
+
+enum Enum
+{
+ foo
+}
+
+//******************************************************
+
+__gshared OuterStruct.NestedStruct* nestedStrPtr;
+
+struct OuterStruct
+{
+ static struct NestedStruct {}
+}
+
+//******************************************************
+
+__gshared ExternDClass externDClassPtr;
+
+// Not emitted because the forward declaration suffices
+extern(D) class ExternDClass
+{
+ int member;
+}
+
+//******************************************************
+
+__gshared ExternDStruct* externDStrPtr;
+
+// Not emitted because the forward declaration suffices
+extern(D) struct ExternDStruct
+{
+ int member;
+}
+
+//******************************************************
+
+__gshared ExternDStructRequired externDStr2;
+
+// Emitted because the forward declaration is not sufficient when declaring an instance
+extern(D) struct ExternDStructRequired
+{
+ int member;
+}
+
+//******************************************************
+
+__gshared TemplClass!int templClass;
+
+class TemplClass(T)
+{
+ T member;
+}
+
+//******************************************************
+
+__gshared TemplStruct!int templStruct;
+
+class TemplStruct(T)
+{
+ T member;
+}
+
+//******************************************************
+
+__gshared ExternDTemplClass!int externTemplClass;
+
+// Not emitted because the forward declaration suffices
+extern(D) class ExternDTemplClass(T)
+{
+ T member;
+}
+
+//******************************************************
+
+__gshared ExternDTemplStruct!int externTemplStruct;
+
+// Required
+extern(D) struct ExternDTemplStruct(T)
+{
+ T member;
+}
+
+//******************************************************
+
+extern(D) struct OnlyByRef {}
+
+void foo(ref OnlyByRef obr) {}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_functions.d b/gcc/testsuite/gdc.test/compilable/dtoh_functions.d
new file mode 100644
index 0000000..1ee6ce6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_functions.d
@@ -0,0 +1,276 @@
+/+
+REQUIRED_ARGS: -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+struct S final
+{
+ int32_t i;
+ int32_t get(int32_t , int32_t );
+ static int32_t get();
+ static const int32_t staticVar;
+ void useVars(int32_t pi = i, int32_t psv = staticVar);
+ struct Nested final
+ {
+ void useStaticVar(int32_t i = staticVar);
+ Nested()
+ {
+ }
+ };
+
+ S() :
+ i()
+ {
+ }
+ S(int32_t i) :
+ i(i)
+ {}
+};
+
+extern "C" int32_t bar(int32_t x);
+
+extern "C" int32_t bar2(int32_t x);
+
+extern "C" int32_t bar4(int32_t x = 42);
+
+extern int32_t baz(int32_t x);
+
+extern int32_t baz2(int32_t x);
+
+extern int32_t baz4(int32_t x = 42);
+
+extern size_t baz5(size_t x = 42);
+
+extern size_t& bazRef(size_t& x);
+
+enum class E : int64_t
+{
+ m = 1LL,
+};
+
+enum class MS : uint8_t
+{
+ dm = 0u,
+};
+
+namespace MSN
+{
+ static S const s = S(42);
+};
+
+struct W1 final
+{
+ MS ms;
+ /* MSN */ S msn;
+ W1()
+ {
+ }
+ W1(MS ms, /* MSN */ S msn = S(42)) :
+ ms(ms),
+ msn(msn)
+ {}
+};
+
+struct W2 final
+{
+ W1 w1;
+ W2() :
+ w1()
+ {
+ }
+ W2(W1 w1) :
+ w1(w1)
+ {}
+};
+
+extern W2 w2;
+
+extern void enums(uint64_t e = $?:32=1LLU|64=static_cast<uint64_t>(E::m)$, uint8_t e2 = static_cast<uint8_t>(w2.w1.ms), S s = static_cast<S>(w2.w1.msn));
+
+extern S s;
+
+extern void aggregates(int32_t a = s.i, int32_t b = s.get(1, 2), int32_t c = S::get(), int32_t d = S::staticVar);
+
+struct S2 final
+{
+ S s;
+ struct S3 final
+ {
+ static int32_t i;
+ S3()
+ {
+ }
+ };
+
+ S2() :
+ s()
+ {
+ }
+ S2(S s) :
+ s(s)
+ {}
+};
+
+extern S2 s2;
+
+extern void chains(int32_t a = s2.s.i, int32_t b = S2::S3::i);
+
+extern S* ptr;
+
+extern int32_t(*f)(int32_t );
+
+extern void special(int32_t a = ptr->i, int32_t b = ptr->get(1, 2), int32_t j = (*f)(1));
+
+extern void variadic(int32_t _param_0, ...);
+---
++/
+
+int foo(int x)
+{
+ return x * 42;
+}
+
+extern (C) int fun();
+extern (C++) int fun2();
+
+extern (C) int bar(int x)
+{
+ return x * 42;
+}
+
+extern (C) static int bar2(int x)
+{
+ return x * 42;
+}
+
+extern (C) private int bar3(int x)
+{
+ return x * 42;
+}
+
+extern (C) int bar4(int x = 42)
+{
+ return x * 42;
+}
+
+extern (C++) int baz(int x)
+{
+ return x * 42;
+}
+
+extern (C++) static int baz2(int x)
+{
+ return x * 42;
+}
+
+extern (C++) private int baz3(int x)
+{
+ return x * 42;
+}
+
+extern (C++) int baz4(int x = 42)
+{
+ return x * 42;
+}
+
+extern (C++) size_t baz5(size_t x = 42)
+{
+ return x * 42;
+}
+
+extern (C++) ref size_t bazRef(return ref size_t x)
+{
+ return x;
+}
+
+extern (C++):
+
+enum E : long
+{
+ m = 1
+}
+
+enum MS : ubyte { dm }
+enum MSN : S { s = S(42) }
+struct W1 { MS ms; MSN msn; }
+struct W2 { W1 w1; }
+__gshared W2 w2;
+
+void enums(ulong e = E.m, ubyte e2 = w2.w1.ms, S s = w2.w1.msn) {}
+
+struct S
+{
+ int i;
+ int get(int, int);
+ static int get();
+ __gshared const int staticVar;
+
+ void useVars(int pi = i, int psv = staticVar) {}
+
+ struct Nested
+ {
+ void useStaticVar(int i = staticVar) {}
+ }
+}
+
+__gshared S s;
+
+void aggregates(int a = s.i, int b = s.get(1, 2), int c = S.get(), int d = S.staticVar) {}
+
+struct S2
+{
+
+ S s;
+ static struct S3
+ {
+ __gshared int i = 3;
+ }
+}
+
+__gshared S2 s2;
+
+void chains(int a = s2.s.i, int b = S2.S3.i) {}
+
+__gshared S* ptr;
+__gshared int function(int) f;
+
+void special(int a = ptr.i, int b = ptr.get(1, 2), int j = f(1)) {}
+
+import core.stdc.stdarg;
+void variadic(int, ...) {}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d b/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d
new file mode 100644
index 0000000..54bbc79
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_ignored.d
@@ -0,0 +1,147 @@
+/++
+REQUIRED_ARGS: -HC=verbose -c -o- -d
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler v$n$
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+#if !defined(_d_real)
+# define _d_real long double
+#endif
+
+class WithImaginary
+{
+public:
+ float memberIf;
+ double memberId;
+ _d_real memberIr;
+ _Complex float memberCf;
+ _Complex double memberCd;
+ _Complex _d_real memberCr;
+ _d_dynamicArray< float > nested;
+ // Ignored function dtoh_ignored.WithImaginary.onReturn because its return type cannot be mapped to C++
+private:
+ virtual void __vtable_slot_0();
+ // Ignored function dtoh_ignored.WithImaginary.onParam because one of its parameters has type `ifloat` which cannot be mapped to C++
+ virtual void __vtable_slot_1();
+};
+
+template <typename T>
+struct WithImaginaryTemplate final
+{
+ // Ignoring var member alignment 0
+ float member;
+ // Ignored function onReturn because its return type cannot be mapped to C++
+ // Ignored function onParam because one of its parameters has type `ifloat` which cannot be mapped to C++
+ // Ignoring var onVariable alignment 0
+ // Ignored variable onVariable because its type cannot be mapped to C++
+ WithImaginaryTemplate()
+ {
+ }
+};
+
+extern WithImaginaryTemplate<int32_t > instance;
+
+// Ignored variable dtoh_ignored.onVariable because its type cannot be mapped to C++
+// Ignored variable dtoh_ignored.onVariablePointer because its type cannot be mapped to C++
+// Ignored variable dtoh_ignored.onVariableSlice because its type cannot be mapped to C++
+// Ignored variable dtoh_ignored.onVariableArray because its type cannot be mapped to C++
+extern void* onVariableAssocArray;
+
+// Ignored variable dtoh_ignored.onVariableFunction because its type cannot be mapped to C++
+// Ignored variable dtoh_ignored.onVariableFunctionParam because its type cannot be mapped to C++
+// Ignored variable dtoh_ignored.onVariableDelegate because its type cannot be mapped to C++
+// Ignored function dtoh_ignored.myExit because its return type cannot be mapped to C++
+---
++/
+
+extern (C++):
+
+class WithImaginary
+{
+ ifloat memberIf;
+ idouble memberId;
+ ireal memberIr;
+
+ cfloat memberCf;
+ cdouble memberCd;
+ creal memberCr;
+
+ ifloat[] nested;
+
+ ifloat onReturn()
+ {
+ return 0i;
+ }
+
+ void onParam(ifloat) {}
+}
+
+struct WithImaginaryTemplate(T)
+{
+ ifloat member;
+
+ ifloat onReturn()
+ {
+ return 0i;
+ }
+
+ void onParam(ifloat)
+ {
+ }
+
+ __gshared ifloat onVariable;
+}
+
+__gshared WithImaginaryTemplate!int instance;
+
+__gshared ifloat onVariable;
+
+__gshared ifloat** onVariablePointer;
+
+__gshared ifloat[] onVariableSlice;
+
+__gshared ifloat[2] onVariableArray;
+
+__gshared ifloat[int] onVariableAssocArray;
+
+__gshared ifloat function() onVariableFunction;
+
+__gshared void function(ifloat) onVariableFunctionParam;
+
+__gshared ifloat delegate() onVariableDelegate;
+
+noreturn myExit() {}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d b/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d
new file mode 100644
index 0000000..821c37c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d
@@ -0,0 +1,170 @@
+/+
+REQUIRED_ARGS: -HC -c -o- -wi -extern-std=c++20
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+compilable/dtoh_invalid_identifiers.d(103): Warning: function `register` is a keyword in C++
+compilable/dtoh_invalid_identifiers.d(103): The generated C++ header will contain identifiers that are keywords in C++
+compilable/dtoh_invalid_identifiers.d(105): Warning: namespace `const_cast` is a keyword in C++
+compilable/dtoh_invalid_identifiers.d(116): Warning: function `and` is a special operator in C++
+compilable/dtoh_invalid_identifiers.d(121): Warning: enum `mutable` is a keyword in C++
+compilable/dtoh_invalid_identifiers.d(123): Warning: alias `char8_t` is a keyword in C++20
+compilable/dtoh_invalid_identifiers.d(141): Warning: function `offsetof` is a default macro in C++
+compilable/dtoh_invalid_identifiers.d(143): Warning: function `wchar_t` is a keyword in C++11
+compilable/dtoh_invalid_identifiers.d(145): Warning: function `__attribute__` is a reserved identifier in C++
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+extern void register(int32_t* ptr);
+
+namespace const_cast
+{
+ extern void bar();
+
+}
+template <typename register_>
+struct S final
+{
+ // Ignoring var x alignment 0
+ register_ x;
+ S()
+ {
+ }
+};
+
+struct S2 final
+{
+ int32_t register_;
+ void and();
+ S2() :
+ register_()
+ {
+ }
+ S2(int32_t register_) :
+ register_(register_)
+ {}
+};
+
+extern void f(int32_t alignas_);
+
+enum class mutable
+{
+ yes = 0,
+ no = 1,
+};
+
+typedef S<char > char8_t;
+
+class Base
+{
+public:
+ virtual void foo();
+};
+
+template <typename typename_>
+class Alias : public typename_
+{
+};
+
+extern void user(Alias<Base* >* i);
+
+template <typename typename_>
+struct InvalidNames final
+{
+ // Ignoring var register alignment 0
+ typename_ register_;
+ void foo(typename_ and_);
+ InvalidNames()
+ {
+ }
+};
+
+extern void useInvalid(InvalidNames<int32_t > _param_0);
+
+extern size_t offsetof();
+
+extern void wchar_t();
+
+extern void __attribute__();
+---
++/
+#line 100
+extern(C++):
+
+__gshared bool and;
+void register(int* ptr) {}
+
+extern(C++, const_cast)
+void bar() {}
+
+struct S(register)
+{
+ register x;
+}
+
+struct S2
+{
+ int register;
+ void and() {}
+}
+
+void f(int alignas) {}
+
+enum mutable { yes, no }
+
+alias char8_t = S!char;
+
+class Base {
+ void foo() {}
+}
+class Alias(typename) : typename {}
+
+void user(Alias!Base i) {}
+
+struct InvalidNames(typename)
+{
+ typename register;
+
+ void foo(typename and) {}
+}
+
+void useInvalid(InvalidNames!int) {}
+
+size_t offsetof() { return 0; }
+
+void wchar_t() {}
+
+void __attribute__() {}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_names.d b/gcc/testsuite/gdc.test/compilable/dtoh_names.d
new file mode 100644
index 0000000..068fc68
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_names.d
@@ -0,0 +1,260 @@
+/+
+REQUIRED_ARGS: -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+struct Outer final
+{
+ static Outer* outerPtr;
+ static Middle::Inner* outerToInnerPtr;
+ static Middle::InnerTmpl<int32_t >* outerToInnerTmplPtr;
+ struct Middle final
+ {
+ static Outer* middleOuterPtr;
+ static Middle* middlePtr;
+ static Inner* middleInnerPtr;
+ struct Inner final
+ {
+ static Outer* innerOuterPtr;
+ static Middle* innerPtr;
+ static Inner* innerInnerPtr;
+ static InnerTmpl<int32_t >* innerInnerTmplPtr;
+ Inner()
+ {
+ }
+ };
+
+ template <typename U>
+ struct InnerTmpl final
+ {
+ // Ignoring var innerTmplOuterPtr alignment 0
+ static Outer* innerTmplOuterPtr;
+ // Ignoring var innerTmplPtr alignment 0
+ static Middle* innerTmplPtr;
+ // Ignoring var innerTmplInnerPtr alignment 0
+ static Inner* innerTmplInnerPtr;
+ // Ignoring var innerTmplInnerTmplPtr alignment 0
+ static InnerTmpl* innerTmplInnerTmplPtr;
+ InnerTmpl()
+ {
+ }
+ };
+
+ Middle()
+ {
+ }
+ };
+
+ template <typename T>
+ struct MiddleTmpl final
+ {
+ // Ignoring var middleTmplPtr alignment 0
+ static MiddleTmpl<T >* middleTmplPtr;
+ // Ignoring var middleTmplInnerTmplPtr alignment 0
+ static MiddleTmpl<T >* middleTmplInnerTmplPtr;
+ struct Inner final
+ {
+ // Ignoring var ptr alignment 0
+ static Inner* ptr;
+ // Ignoring var ptr2 alignment 0
+ static MiddleTmpl<T >* ptr2;
+ Inner()
+ {
+ }
+ };
+
+ template <typename U>
+ struct InnerTmpl final
+ {
+ // Ignoring var innerTmplPtr alignment 0
+ static InnerTmpl* innerTmplPtr;
+ // Ignoring var innerTmplPtrDiff alignment 0
+ static InnerTmpl<char >* innerTmplPtrDiff;
+ // Ignoring var middleTmplInnerTmplPtr alignment 0
+ static MiddleTmpl<T >* middleTmplInnerTmplPtr;
+ // Ignoring var a alignment 0
+ static T a;
+ static U bar();
+ InnerTmpl()
+ {
+ }
+ };
+
+ MiddleTmpl()
+ {
+ }
+ };
+
+ Outer()
+ {
+ }
+};
+
+---
++/
+
+extern(C++):
+
+struct Outer
+{
+ __gshared Outer* outerPtr;
+ __gshared Middle.Inner* outerToInnerPtr;
+ __gshared Middle.InnerTmpl!int* outerToInnerTmplPtr;
+
+ static struct Middle
+ {
+ __gshared Outer* middleOuterPtr;
+ __gshared Middle* middlePtr;
+ __gshared Inner* middleInnerPtr;
+
+ static struct Inner
+ {
+ __gshared Outer* innerOuterPtr;
+ __gshared Middle* innerPtr;
+ __gshared Inner* innerInnerPtr;
+ __gshared InnerTmpl!int* innerInnerTmplPtr;
+ }
+
+ static struct InnerTmpl(U)
+ {
+ __gshared Outer* innerTmplOuterPtr;
+ __gshared Middle* innerTmplPtr;
+ __gshared Inner* innerTmplInnerPtr;
+ __gshared InnerTmpl* innerTmplInnerTmplPtr;
+ }
+ }
+
+ static struct MiddleTmpl(T)
+ {
+ __gshared MiddleTmpl!T* middleTmplPtr;
+ __gshared MiddleTmpl!T.Inner* middleTmplInnerTmplPtr;
+
+ static struct Inner
+ {
+ __gshared Inner* ptr;
+ __gshared MiddleTmpl!T.Inner* ptr2;
+ }
+
+ static struct InnerTmpl(U)
+ {
+ __gshared InnerTmpl* innerTmplPtr;
+ __gshared InnerTmpl!char* innerTmplPtrDiff;
+ __gshared MiddleTmpl!T.Inner* middleTmplInnerTmplPtr;
+
+ __gshared T a;
+ static U bar() { return U.init; }
+ }
+ }
+}
+
+/+
+TEST_OUTPUT:
+---
+extern Outer::Middle::Inner inner;
+
+extern Outer::Middle::InnerTmpl<int32_t > innerTmpl;
+
+extern Outer::MiddleTmpl<int32_t >::Inner middleTmpl;
+
+extern Outer::MiddleTmpl<int32_t >::InnerTmpl<double > bothTmpl;
+
+---
++/
+
+__gshared Outer.Middle.Inner inner;
+
+__gshared Outer.Middle.InnerTmpl!int innerTmpl;
+
+__gshared Outer.MiddleTmpl!int.Inner middleTmpl;
+
+__gshared Outer.MiddleTmpl!int.InnerTmpl!double bothTmpl;
+
+/+
+TEST_OUTPUT:
+---
+typedef Outer::MiddleTmpl<int32_t >::InnerTmpl<double > FullTmplInst;
+
+template <typename U>
+using FullTmpl = Outer::MiddleTmpl<int32_t >::InnerTmpl<U>;
+---
++/
+
+alias FullTmplInst = Outer.MiddleTmpl!int.InnerTmpl!double;
+
+alias FullTmpl = Outer.MiddleTmpl!int.InnerTmpl;
+
+/+
+TEST_OUTPUT:
+---
+extern void dotId(int32_t a = Outer::MiddleTmpl<int32_t >::InnerTmpl<double >::a);
+
+---
++/
+
+void dotId( int a = Outer.MiddleTmpl!int.InnerTmpl!double.a ) {}
+
+/+
+TEST_OUTPUT:
+---
+extern void castExp(double a = (double) Outer::MiddleTmpl<int32_t >::InnerTmpl<double >::a);
+
+---
++/
+
+void castExp( double a = Outer.MiddleTmpl!int.InnerTmpl!double.a ) {}
+
+/+
+TEST_OUTPUT:
+---
+extern void structLit(Outer::MiddleTmpl<int32_t >::InnerTmpl<double > a = Outer::MiddleTmpl<int32_t >::InnerTmpl<double >());
+
+---
++/
+
+void structLit( Outer.MiddleTmpl!int.InnerTmpl!double a = Outer.MiddleTmpl!int.InnerTmpl!double() ) {}
+
+/+
+TEST_OUTPUT:
+---
+extern void callExp(double a = Outer::MiddleTmpl<int32_t >::InnerTmpl<double >::bar());
+
+---
++/
+
+void callExp( double a = Outer.MiddleTmpl!int.InnerTmpl!double.bar() ) {}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_protection.d b/gcc/testsuite/gdc.test/compilable/dtoh_protection.d
new file mode 100644
index 0000000..2180c41
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_protection.d
@@ -0,0 +1,218 @@
+/**
+https://issues.dlang.org/show_bug.cgi?id=21218
+
+REQUIRED_ARGS: -HC -o-
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+struct S1 final
+{
+ int32_t a;
+protected:
+ int32_t b;
+ int32_t c;
+ int32_t d;
+private:
+ int32_t e;
+public:
+ S1()
+ {
+ }
+};
+
+class S2 final
+{
+public:
+ int32_t af();
+protected:
+ int32_t bf();
+ int32_t cf();
+ int32_t df();
+public:
+ S2()
+ {
+ }
+};
+
+class C1
+{
+public:
+ int32_t a;
+protected:
+ int32_t b;
+ int32_t c;
+ int32_t d;
+private:
+ int32_t e;
+};
+
+struct C2
+{
+ virtual int32_t af();
+protected:
+ virtual int32_t bf();
+ int32_t cf();
+ int32_t df();
+};
+
+struct Outer final
+{
+private:
+ int32_t privateOuter;
+public:
+ struct PublicInnerStruct final
+ {
+ private:
+ int32_t privateInner;
+ public:
+ int32_t publicInner;
+ PublicInnerStruct() :
+ publicInner()
+ {
+ }
+ PublicInnerStruct(int32_t publicInner) :
+ publicInner(publicInner)
+ {}
+ };
+
+private:
+ struct PrivateInnerClass final
+ {
+ private:
+ int32_t privateInner;
+ public:
+ int32_t publicInner;
+ PrivateInnerClass() :
+ publicInner()
+ {
+ }
+ PrivateInnerClass(int32_t publicInner) :
+ publicInner(publicInner)
+ {}
+ };
+
+public:
+ class PublicInnerInterface
+ {
+ public:
+ virtual void foo() = 0;
+ };
+
+private:
+ enum class PrivateInnerEnum
+ {
+ A = 0,
+ B = 1,
+ };
+
+public:
+ typedef PrivateInnerEnum PublicAlias;
+ Outer()
+ {
+ }
+};
+---
+*/
+
+module compilable.dtoh_protection;
+
+extern(C++) struct S1
+{
+ public int a;
+ protected int b;
+ package int c;
+ package(compilable) int d;
+ private int e;
+}
+
+extern(C++, class) struct S2
+{
+ public int af();
+ protected int bf();
+ package int cf();
+ package(compilable) int df();
+ private int ef();
+}
+
+extern(C++) class C1
+{
+ public int a;
+ protected int b;
+ package int c;
+ package(compilable) int d;
+ private int e;
+}
+
+extern(C++, struct) class C2
+{
+ public int af();
+ protected int bf();
+ package int cf();
+ package(compilable) int df();
+ private int ef();
+}
+
+extern(C++) struct Outer
+{
+ private int privateOuter;
+
+ static struct PublicInnerStruct
+ {
+ private int privateInner;
+ int publicInner;
+ }
+
+ private static struct PrivateInnerClass
+ {
+ private int privateInner;
+ int publicInner;
+ }
+
+ static interface PublicInnerInterface
+ {
+ void foo();
+ }
+
+ private static enum PrivateInnerEnum
+ {
+ A,
+ B
+ }
+
+ public alias PublicAlias = PrivateInnerEnum;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_required_symbols.d b/gcc/testsuite/gdc.test/compilable/dtoh_required_symbols.d
new file mode 100644
index 0000000..6e2d2f1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_required_symbols.d
@@ -0,0 +1,225 @@
+/+
+REQUIRED_ARGS: -o- -HC
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+class ExternDClass;
+struct ExternDStruct2;
+struct ExternDStruct3;
+
+struct ExternDStruct final
+{
+ int32_t i;
+ double d;
+ ExternDStruct() :
+ i(),
+ d()
+ {
+ }
+ ExternDStruct(int32_t i, double d = NAN) :
+ i(i),
+ d(d)
+ {}
+};
+
+enum class ExternDEnum
+{
+ A = 0,
+};
+
+template <>
+struct ExternDStructTemplate final
+{
+ // Ignoring var i alignment 0
+ int32_t i;
+ // Ignoring var d alignment 0
+ double d;
+ ExternDStructTemplate()
+ {
+ }
+};
+
+class Object
+{
+ virtual void __vtable_slot_0();
+ virtual void __vtable_slot_1();
+ virtual void __vtable_slot_2();
+ virtual void __vtable_slot_3();
+public:
+ class Monitor
+ {
+ virtual void __vtable_slot_4();
+ virtual void __vtable_slot_5();
+ };
+
+};
+
+class ExternDClass : public Object
+{
+public:
+ int32_t i;
+ double d;
+};
+
+struct ExternDStruct2 final
+{
+ int32_t doStuff();
+ ExternDStruct2()
+ {
+ }
+};
+
+struct ExternDStruct3 final
+{
+ int32_t a;
+ ExternDStruct3() :
+ a()
+ {
+ }
+ ExternDStruct3(int32_t a) :
+ a(a)
+ {}
+};
+
+namespace ExternDEnum2
+{
+ static ExternDStruct3 const A = ExternDStruct3(1);
+};
+
+struct ExternCppStruct final
+{
+ ExternDStruct s;
+ ExternDEnum e;
+ ExternDStructTemplate< > st;
+ ExternCppStruct() :
+ s(),
+ st()
+ {
+ }
+ ExternCppStruct(ExternDStruct s, ExternDEnum e = (ExternDEnum)0, ExternDStructTemplate< > st = ExternDStructTemplate< >(0, NAN)) :
+ s(s),
+ e(e),
+ st(st)
+ {}
+};
+
+extern ExternDClass* globalC;
+
+extern void foo(int32_t arg = globalC.i);
+
+extern ExternDStruct2* globalS2;
+
+extern void bar(int32_t arg = globalS2->doStuff());
+
+extern /* ExternDEnum2 */ ExternDStruct3* globalE2;
+
+extern void baz(int32_t arg = globalE2->a);
+---
+
+Known issues:
+- class declarations must be emitted on member access
++/
+
+// extern(D) symbols are ignored upon first visit but required later
+
+struct ExternDStruct
+{
+ int i;
+ double d;
+
+ // None of these can be emitted due to the mismatched mangling
+ static double staticDouble;
+ static shared double staticSharedDouble;
+ __gshared double sharedDouble;
+}
+
+struct ExternDStruct2
+{
+ extern(C++) int doStuff()
+ {
+ return 1;
+ }
+}
+
+struct ExternDStruct3
+{
+ int a;
+}
+
+class ExternDClass
+{
+ int i;
+ double d;
+}
+
+enum ExternDEnum
+{
+ A
+}
+
+enum ExternDEnum2 : ExternDStruct3
+{
+ A = ExternDStruct3(1)
+}
+
+struct ExternDStructTemplate()
+{
+ int i;
+ double d;
+}
+
+extern (C++):
+
+struct ExternCppStruct
+{
+ ExternDStruct s;
+ ExternDEnum e;
+ ExternDStructTemplate!() st;
+}
+
+__gshared ExternDClass globalC;
+
+void foo(int arg = globalC.i) {}
+
+__gshared ExternDStruct2* globalS2;
+
+void bar(int arg = globalS2.doStuff()) {}
+
+__gshared ExternDEnum2* globalE2;
+
+void baz(int arg = globalE2.a) {}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d b/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d
new file mode 100644
index 0000000..a7c0a0d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d
@@ -0,0 +1,90 @@
+/+
+REQUIRED_ARGS: -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+enum class __c_not_special;
+extern "C" void fn_long(long _param_0);
+
+extern "C" void fn_ulong(unsigned long _param_0);
+
+extern "C" void fn_longlong(long long _param_0);
+
+extern "C" void fn_ulonglong(unsigned long long _param_0);
+
+extern "C" void fn_long_double(long double _param_0);
+
+extern "C" void fn_wchar_t(wchar_t _param_0);
+
+extern "C" void fn_complex_float(_Complex float _param_0);
+
+extern "C" void fn_complex_double(_Complex double _param_0);
+
+extern "C" void fn_complex_real(_Complex long double _param_0);
+
+extern "C" void fn_not_special(__c_not_special _param_0);
+
+---
++/
+
+enum __c_long : int;
+enum __c_ulong : int;
+enum __c_longlong : int;
+enum __c_ulonglong : int;
+enum __c_long_double : int;
+enum __c_wchar_t : int;
+enum __c_complex_float : int;
+enum __c_complex_double : int;
+enum __c_complex_real : int;
+enum __c_not_special : int;
+
+extern(C) void fn_long(__c_long) {}
+extern(C) void fn_ulong(__c_ulong) {}
+extern(C) void fn_longlong(__c_longlong) {}
+extern(C) void fn_ulonglong(__c_ulonglong) {}
+
+extern(C) void fn_long_double(__c_long_double) {}
+
+extern(C) void fn_wchar_t(__c_wchar_t) {}
+
+extern(C) void fn_complex_float(__c_complex_float) {}
+extern(C) void fn_complex_double(__c_complex_double) {}
+extern(C) void fn_complex_real(__c_complex_real) {}
+
+extern(C) void fn_not_special(__c_not_special) {}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_unittest_block.d b/gcc/testsuite/gdc.test/compilable/dtoh_unittest_block.d
new file mode 100644
index 0000000..ac58d0e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_unittest_block.d
@@ -0,0 +1,52 @@
+/*
+REQUIRED_ARGS: -HC -c -o-
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+
+---
+*/
+
+unittest
+{
+ extern (C++) int foo(int x)
+ {
+ return x * 42;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_verbose.d b/gcc/testsuite/gdc.test/compilable/dtoh_verbose.d
new file mode 100644
index 0000000..505ffdc
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_verbose.d
@@ -0,0 +1,172 @@
+/*
+REQUIRED_ARGS: -HC=verbose -o- -Icompilable/extra-files
+PERMUTE_ARGS:
+EXTRA_FILES: extra-files/dtoh_imports.d extra-files/dtoh_imports2.d
+
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler v$n$
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+extern void importFunc();
+
+// Ignored function dtoh_verbose.foo because of linkage
+// Ignored variable dtoh_verbose.i because of linkage
+// Ignored function dtoh_verbose.bar because of linkage
+// Ignored struct dtoh_verbose.S because of linkage
+// Ignored class dtoh_verbose.C because of linkage
+// Ignored function dtoh_verbose.bar because it is extern
+// Ignored variable dtoh_verbose.i1 because of linkage
+// Ignored template dtoh_verbose.templ(T)(T t) because of linkage
+// Ignored alias dtoh_verbose.inst because of linkage
+// Ignored enum dtoh_verbose.arrayOpaque because of its base type
+// Ignored renamed import `myFunc = importFunc` because `using` only supports types
+struct A final
+{
+ // Ignored renamed import `myFunc = importFunc` because `using` only supports types
+ A()
+ {
+ }
+};
+
+struct Hidden final
+{
+ // Ignored function dtoh_verbose.Hidden.hidden because it is private
+ Hidden()
+ {
+ }
+};
+
+// Ignored alias dtoh_verbose.D because of linkage
+class Visitor
+{
+public:
+ virtual void stat();
+ // Ignored dtoh_verbose.Visitor.bar because `using` cannot rename functions in aggregates
+ // Ignored dtoh_verbose.Visitor.unused because free functions cannot be aliased in C++
+};
+
+extern void unused();
+
+// Ignored variable dtoh_verbose.and because its name is a special operator in C++
+template <typename T>
+struct FullImportTmpl final
+{
+ // Ignored `dtoh_imports` because it's inside of a template declaration
+ FullImportTmpl()
+ {
+ }
+};
+
+template <typename T>
+struct SelectiveImportsTmpl final
+{
+ // Ignored `__anonymous` because it's inside of a template declaration
+ SelectiveImportsTmpl()
+ {
+ }
+};
+---
+*/
+
+void foo() {}
+
+extern (D) {
+ int i;
+}
+
+void bar();
+
+struct S {}
+
+class C {}
+
+extern(C++) void bar();
+
+int i1;
+
+void templ(T)(T t) {}
+
+alias inst = templ!int;
+
+extern(C++)
+enum arrayOpaque : int[4];
+
+public import dtoh_imports : myFunc = importFunc;
+
+extern(C++) struct A
+{
+ public import dtoh_imports : myFunc = importFunc;
+}
+
+extern(C++) struct Hidden
+{
+ private void hidden() {}
+}
+
+private {
+ enum PI = 4;
+}
+
+alias D = size_t delegate (size_t x);
+
+extern(C++) T foo(T) = T.init;
+
+extern(C++) class Visitor
+{
+ void stat() {}
+
+ // Ignored because those cannot be represented in C++
+ alias bar = stat;
+ alias unused = .unused;
+}
+
+extern(C++) void unused() {}
+
+extern(C++) __gshared bool and;
+
+extern(C++) struct FullImportTmpl(T)
+{
+ public import dtoh_imports;
+
+}
+
+extern(C++) struct SelectiveImportsTmpl(T)
+{
+ public import dtoh_imports :
+ importFunc,
+ aliasName = ImportsC;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtorfields.d b/gcc/testsuite/gdc.test/compilable/dtorfields.d
new file mode 100644
index 0000000..1622f3e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtorfields.d
@@ -0,0 +1,52 @@
+// REQUIRED_ARGS: -preview=dtorfields
+//
+// https://issues.dlang.org/show_bug.cgi?id=21709
+// PERMUTE_ARGS: -betterC
+
+/******************************************
+ * https://issues.dlang.org/show_bug.cgi?id=20934
+ */
+struct HasDtor
+{
+ ~this() {}
+}
+
+struct Disable
+{
+ HasDtor member;
+ this() @disable;
+}
+
+extern(C++) class Extern
+{
+ HasDtor member;
+ this();
+}
+
+/******************************************
+ * https://issues.dlang.org/show_bug.cgi?id=21213
+ */
+class Parent
+{
+ this() nothrow pure @nogc @safe {}
+}
+
+class Child : Parent
+{
+ HasDtor member;
+}
+
+/******************************************
+ * https://issues.dlang.org/show_bug.cgi?id=21225
+ */
+
+struct NothrowConstructed
+{
+ ~this() {}
+}
+
+struct NothrowConstructor
+{
+ NothrowConstructed member;
+ this(int) pure nothrow {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/dtorfields_deprecation.d b/gcc/testsuite/gdc.test/compilable/dtorfields_deprecation.d
new file mode 100644
index 0000000..83014e3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dtorfields_deprecation.d
@@ -0,0 +1,49 @@
+/**
+Checks that code still compiles when -preview=dtorfields is enabled by default
+but issues an appropriate deprecation message.
+
+Remove this test when the deprecations period ends, see visit(CtorDeclaration)
+in semantic3.d
+
+TEST_OUTPUT:
+---
+compilable/dtorfields_deprecation.d(30): Deprecation: `dtorfields_deprecation.Pure.this` has stricter attributes than its destructor (`pure`)
+compilable/dtorfields_deprecation.d(30): The destructor will be called if an exception is thrown
+compilable/dtorfields_deprecation.d(30): Either make the constructor `nothrow` or adjust the field destructors
+compilable/dtorfields_deprecation.d(42): Deprecation: `dtorfields_deprecation.NoGC.this` has stricter attributes than its destructor (`@nogc`)
+compilable/dtorfields_deprecation.d(42): The destructor will be called if an exception is thrown
+compilable/dtorfields_deprecation.d(42): Either make the constructor `nothrow` or adjust the field destructors
+compilable/dtorfields_deprecation.d(48): Deprecation: `dtorfields_deprecation.Safe.this` has stricter attributes than its destructor (`@system`)
+compilable/dtorfields_deprecation.d(48): The destructor will be called if an exception is thrown
+compilable/dtorfields_deprecation.d(48): Either make the constructor `nothrow` or adjust the field destructors
+---
+**/
+
+struct HasDtor
+{
+ ~this() {}
+}
+
+struct Pure
+{
+ HasDtor member;
+ this(int) pure {}
+}
+
+struct Nothrow
+{
+ HasDtor member;
+ this(int) nothrow {}
+}
+
+struct NoGC
+{
+ HasDtor member;
+ this(int) @nogc {}
+}
+
+struct Safe
+{
+ HasDtor member;
+ this(int) @safe {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/c6395.d b/gcc/testsuite/gdc.test/compilable/extra-files/c6395.d
index 47e9c9c..58c76bc 100644
--- a/gcc/testsuite/gdc.test/compilable/extra-files/c6395.d
+++ b/gcc/testsuite/gdc.test/compilable/extra-files/c6395.d
@@ -1,4 +1,4 @@
-// 6395
+// https://issues.dlang.org/show_bug.cgi?id=6395
template map(alias fun) {
auto map(Range)(Range r) {
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/depsOutput9948a.d b/gcc/testsuite/gdc.test/compilable/extra-files/depsOutput9948a.d
deleted file mode 100644
index 3f4e3a3..0000000
--- a/gcc/testsuite/gdc.test/compilable/extra-files/depsOutput9948a.d
+++ /dev/null
@@ -1,6 +0,0 @@
-module depsOutput9948a;
-
-void templateFunc(string myImport)()
-{
- mixin(myImport);
-} \ No newline at end of file
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/dtoh_imports.d b/gcc/testsuite/gdc.test/compilable/extra-files/dtoh_imports.d
new file mode 100644
index 0000000..917ac29
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/extra-files/dtoh_imports.d
@@ -0,0 +1,13 @@
+extern(C++):
+
+public import dtoh_imports2 : MyStdcInt = customInt;
+
+class ImportsC {}
+
+void importFunc() {}
+
+private struct HiddenData {}
+
+enum : int {
+ IgnoreErrors
+}
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/dtoh_imports2.d b/gcc/testsuite/gdc.test/compilable/extra-files/dtoh_imports2.d
new file mode 100644
index 0000000..6ff5d8e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/extra-files/dtoh_imports2.d
@@ -0,0 +1,3 @@
+extern(C++):
+
+alias customInt = int;
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/emptymain.d b/gcc/testsuite/gdc.test/compilable/extra-files/emptymain.d
new file mode 100644
index 0000000..5d1cc79
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/extra-files/emptymain.d
@@ -0,0 +1 @@
+void main() { } \ No newline at end of file
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d
index 5eb6afd..209d4a0 100644
--- a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d
+++ b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d
@@ -1,10 +1,14 @@
+// REQUIRED_ARGS: -ignore
module foo.bar;
import core.vararg;
-import std.stdio;
+
+// Only compilable, declare inline
+void writeln(T...)(T) {}
pragma(lib, "test");
pragma(msg, "Hello World");
+pragma(linkerDirective, "/DEFAULTLIB:test2");
static assert(true, "message");
@@ -43,11 +47,11 @@ out (result)
{
assert(result == 0);
}
-body
+do
{
float f = float.infinity;
int i = cast(int) f;
- writeln((i,1),2);
+ writeln(i,1,2);
writeln(cast(int)float.max);
assert(i == cast(int)float.max);
assert(i == 0x80000000);
@@ -60,7 +64,7 @@ template Foo(T, int V)
{
void foo(...)
{
- static if (is(Object _ : X!TL, alias X, TL...)) {} // Bugzilla 10044
+ static if (is(Object _ : X!TL, alias X, TL...)) {} // https://issues.dlang.org/show_bug.cgi?id=10044
auto x = __traits(hasMember, Object, "noMember");
auto y = is(Object : X!TL, alias X, TL...);
@@ -82,7 +86,7 @@ template Foo(T, int V)
d--;
asm
- { naked ;
+ { naked ;
mov EAX, 3;
}
@@ -157,11 +161,11 @@ template Foo(T, int V)
}
try
- bar(1, 2);
+ bar(1, 2);
catch(Object o)
- x++;
+ x++;
finally
- x--;
+ x--;
Object o;
synchronized (o)
@@ -269,9 +273,6 @@ class Test
pure nothrow @safe @nogc unittest {}
pure nothrow @safe @nogc invariant {}
pure nothrow @safe @nogc invariant (true);
-
- pure nothrow @safe @nogc new (size_t sz) { return null; }
- pure nothrow @safe @nogc delete (void* p) { }
}
template templ( T )
@@ -410,16 +411,16 @@ struct T12
}
-// 6591
-import std.stdio : writeln, F = File;
+// https://issues.dlang.org/show_bug.cgi?id=6591
+import core.stdc.stdio : printf, F = FILE;
void foo6591()()
{
- import std.stdio : writeln, F = File;
+ import core.stdc.stdio : printf, F = FILE;
}
-// 8081
+// https://issues.dlang.org/show_bug.cgi?id=8081
version(unittest) {
pure nothrow unittest {}
pure nothrow unittest {}
@@ -430,7 +431,7 @@ version(unittest) {
}
-// 10334
+// https://issues.dlang.org/show_bug.cgi?id=10334
template Foo10334(T) if (Bar10334!()) {} ///
template Foo10334(T) if (Bar10334!100) {} ///
@@ -459,7 +460,7 @@ mixin Test10334!int a; ///
mixin Test10334!(int,long) b; ///
mixin Test10334!"str" c; ///
-// 12266
+// https://issues.dlang.org/show_bug.cgi?id=12266
auto clamp12266a(T1, T2, T3)(T1 x, T2 min_val, T3 max_val)
{
return 0;
@@ -473,10 +474,10 @@ pure clamp12266b(T1, T2, T3)(T1 x, T2 min_val, T3 max_val)
return 0;
}
-// 13832
+// https://issues.dlang.org/show_bug.cgi?id=13832
alias Dg13832 = ref int delegate();
-// 16590
+// https://issues.dlang.org/show_bug.cgi?id=16590
class TestClass {
int aa;
int b1, b2;
@@ -538,13 +539,50 @@ class Foo2A {
}
-// bugzilla 15676
+// https://issues.dlang.org/show_bug.cgi?id=15676
struct Foo3A(T)
{
@disable this(this);
@disable this();
}
+// return ref, return scope, return ref scope
+ref int foo(return ref int a) @safe
+{
+ return a;
+}
+
+int* foo(return scope int* a) @safe
+{
+ return a;
+}
+
+ref int* foo(scope return ref int* a) @safe
+{
+ return a;
+}
+
+struct SafeS
+{
+@safe:
+ ref SafeS foo() return
+ {
+ return this;
+ }
+
+ SafeS foo2() return scope
+ {
+ return this;
+ }
+
+ ref SafeS foo3() return scope
+ {
+ return this;
+ }
+
+ int* p;
+}
+
void test13x(@(10) int a, @(20) int, @(30) @(40) int[] arr...) {}
enum Test14UDA1;
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header17125.d b/gcc/testsuite/gdc.test/compilable/extra-files/header17125.d
new file mode 100644
index 0000000..1b979ab
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/extra-files/header17125.d
@@ -0,0 +1,5 @@
+void func1(real value = 10.35e4L);
+void func2(real value = 520.199e3F);
+void func3(real value = 9.70e5);
+void func4(real value = 1024.5e2F);
+void func5(real value = 41250.2e1L);
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header18365.d b/gcc/testsuite/gdc.test/compilable/extra-files/header18365.d
new file mode 100644
index 0000000..64d8ad0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/extra-files/header18365.d
@@ -0,0 +1,6 @@
+module foo.bar.ba;
+nothrow pure @nogc @safe package(foo)
+{
+ void foo();
+ nothrow pure @nogc @safe package(foo.bar) void foo2();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header2.d b/gcc/testsuite/gdc.test/compilable/extra-files/header2.d
index f8c52ff..7dc4659 100644
--- a/gcc/testsuite/gdc.test/compilable/extra-files/header2.d
+++ b/gcc/testsuite/gdc.test/compilable/extra-files/header2.d
@@ -18,7 +18,7 @@ void foo2(const C2 c);
struct Foo3
{
int k;
- ~this() @trusted @disable @nogc { k = 1; }
+ ~this() @trusted @disable @nogc @live { k = 1; }
this(this) { k = 2; }
}
@@ -91,7 +91,7 @@ template templateVariableBar(T) if (is(T == int))
auto flit = 3 / 2.0;
-// 11217
+// https://issues.dlang.org/show_bug.cgi?id=11217
void foo11217()( const int[] arr) {}
void foo11217()(immutable int[] arr) {}
void foo11217()( ref int[] arr) {}
@@ -101,7 +101,7 @@ void foo11217()( scope int[] arr) {}
void foo11217()( in int[] arr) {}
void foo11217()( inout int[] arr) {}
-// 13275
+// https://issues.dlang.org/show_bug.cgi?id=13275
void test13275()
{
if ( auto n = 1) {}
@@ -141,12 +141,69 @@ void test13275()
foreach (shared const(int) e; [1,2]) {}
}
-// 9766
+// https://issues.dlang.org/show_bug.cgi?id=9766
align (1) struct S9766
{
+align {}
align (true ? 2 : 3):
int var1;
align:
int var2;
}
+
+align(2) struct S12200_1
+{
+align:
+}
+
+align(2) struct S12200_2
+{
+align(1):
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=16140
+void gun()()
+{
+ int[] res;
+ while (auto va = fun()) {} // expression expected, not 'auto'
+
+ while (true)
+ if (auto va = fun()) {}
+ else break;
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=16649
+void leFoo()()
+{
+ sign = a == 2 ? false : (y < 0) ^ sign;
+ sign = a == 2 ? false : sign ^ (y < 0);
+ sign = 2 + 3 | 7 + 5;
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=17371
+interface LeInterface
+{}
+class LeClass
+{
+ this()
+ {
+ auto foo = new class () LeInterface {};
+ }
+}
+const levar = new class LeClass, LeInterface {};
+
+// https://issues.dlang.org/show_bug.cgi?id=20074
+class CC
+{
+ void fun()() @safe
+ {
+ () @trusted pure
+ {
+ } ();
+ }
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=17663
+private:
+public struct Export {}
diff --git a/gcc/testsuite/gdc.test/compilable/fail137.d b/gcc/testsuite/gdc.test/compilable/fail137.d
new file mode 100644
index 0000000..c6876d1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/fail137.d
@@ -0,0 +1,26 @@
+// https://issues.dlang.org/show_bug.cgi?id=751
+// Compiler segfault on template expansion
+
+extern(C) int printf(const char*, ...);
+
+template TypeTuple( TList... )
+{
+ alias TList TypeTuple;
+}
+
+template IndexOf( T, TList... )
+{
+ static if( TList.length == 0 )
+ const size_t IndexOf = 1;
+ else static if( is( T == typeof( TList[0] ) ) )
+ const size_t IndexOf = 0;
+ else
+ const size_t IndexOf = 1 + IndexOf!( T, (TList[1 .. $]) );
+}
+
+void main()
+{
+ TypeTuple!(int, long) T;
+ printf( "%u\n", cast(uint)IndexOf!(long, T) );
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/fieldwise.d b/gcc/testsuite/gdc.test/compilable/fieldwise.d
new file mode 100644
index 0000000..dfa76b4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/fieldwise.d
@@ -0,0 +1,11 @@
+// REQUIRED_ARGS: -preview=dip1000 -preview=fieldwise
+// EXTRA_FILES: imports/impfieldwise.d
+
+import imports.impfieldwise;
+
+@safe:
+
+bool test(S s, S t)
+{
+ return s == t; // comparison can access fields for ==
+}
diff --git a/gcc/testsuite/gdc.test/compilable/filefullpath_18911.d b/gcc/testsuite/gdc.test/compilable/filefullpath_18911.d
new file mode 100644
index 0000000..3d88ac2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/filefullpath_18911.d
@@ -0,0 +1,9 @@
+// REQUIRED_ARGS: -Icompilable/imports -c -o-
+// EXTRA_FILES: imports/a18911.d
+
+import a18911;
+
+enum THIS_FILE = __FILE_FULL_PATH__;
+enum suffix_this = "filefullpath_18911.d";
+
+static assert(THIS_FILE[0..$-suffix_this.length-1] == A_FILE[0..$-suffix_a.length-1]);
diff --git a/gcc/testsuite/gdc.test/compilable/fix13165.d b/gcc/testsuite/gdc.test/compilable/fix13165.d
new file mode 100644
index 0000000..a26cfd6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/fix13165.d
@@ -0,0 +1,12 @@
+/* REQUIRED_ARGS: -w -profile
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=13165
+
+void main()
+{
+ int i;
+ if (!i)
+ throw new Exception("Error");
+ assert(0);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/fix17145.d b/gcc/testsuite/gdc.test/compilable/fix17145.d
new file mode 100644
index 0000000..ab34c71
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/fix17145.d
@@ -0,0 +1,13 @@
+// https://issues.dlang.org/show_bug.cgi?id=17145
+
+auto tuple(T...)(T t) {
+ struct Result {
+ T expand;
+ }
+ return Result(t);
+}
+
+void baz()
+{
+ enum zoo = tuple(1, 2).expand; // Error: value of __tup1847 is not known at compile time
+}
diff --git a/gcc/testsuite/gdc.test/compilable/fix20416.d b/gcc/testsuite/gdc.test/compilable/fix20416.d
new file mode 100644
index 0000000..19ad74d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/fix20416.d
@@ -0,0 +1,36 @@
+/* REQUIRED_ARGS: -preview=dip1000
+*/
+
+/********************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=20416
+
+alias P = int*;
+
+ref P foo(return ref P);
+
+P bar()
+{
+ P result;
+ return foo(result);
+}
+
+
+/********************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=20416
+
+
+struct S
+{
+ string x;
+ ref S foo() return;
+}
+
+
+S bar2()
+{
+ S result;
+ return result.foo();
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/fix21647.d b/gcc/testsuite/gdc.test/compilable/fix21647.d
index c129fa0..c1e1c48 100644
--- a/gcc/testsuite/gdc.test/compilable/fix21647.d
+++ b/gcc/testsuite/gdc.test/compilable/fix21647.d
@@ -1,5 +1,5 @@
/*
-REQUIRED_ARGS:
+REQUIRED_ARGS: -preview=rvaluerefparam
TEST_OUTPUT:
---
cast(void)0
@@ -28,3 +28,11 @@ void test3() { pragma(msg, V); }
pragma(msg, foo());
pragma(msg, main());
pragma(msg, V);
+
+/*************************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8255
+
+struct G {}
+struct F(T) { void f(ref T) {} }
+pragma(msg, F!G().f(G.init));
+
diff --git a/gcc/testsuite/gdc.test/compilable/fix21684.d b/gcc/testsuite/gdc.test/compilable/fix21684.d
new file mode 100644
index 0000000..116f1e4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/fix21684.d
@@ -0,0 +1,7 @@
+// https://issues.dlang.org/show_bug.cgi?id=21684
+
+
+struct S
+{
+ int[100_000] a;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/fix22180.d b/gcc/testsuite/gdc.test/compilable/fix22180.d
new file mode 100644
index 0000000..a4c32e0d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/fix22180.d
@@ -0,0 +1,5 @@
+// https://issues.dlang.org/show_bug.cgi?id=22180
+
+align(8) { int x; }
+//pragma(msg, x.alignof);
+static assert(x.alignof == 8);
diff --git a/gcc/testsuite/gdc.test/compilable/forward1.d b/gcc/testsuite/gdc.test/compilable/forward1.d
index 7417b03..7c5f76d 100644
--- a/gcc/testsuite/gdc.test/compilable/forward1.d
+++ b/gcc/testsuite/gdc.test/compilable/forward1.d
@@ -1,6 +1,7 @@
// REQUIRED_ARGS: -g
-// 104. fails only with -g
+// https://issues.dlang.org/show_bug.cgi?id=104
+// fails only with -g
Foofunc f;
alias int Foo;
diff --git a/gcc/testsuite/gdc.test/compilable/future.d b/gcc/testsuite/gdc.test/compilable/future.d
index 89a1396..3043984 100644
--- a/gcc/testsuite/gdc.test/compilable/future.d
+++ b/gcc/testsuite/gdc.test/compilable/future.d
@@ -1,7 +1,7 @@
/* PERMUTE_ARGS:
* TEST_OUTPUT:
---
-compilable/future.d(15): Deprecation: @future base class method future.A.msg is being overridden by future.B.msg; rename the latter
+compilable/future.d(15): Deprecation: `@__future` base class method `future.A.msg` is being overridden by `future.B.msg`; rename the latter
---
*/
diff --git a/gcc/testsuite/gdc.test/compilable/futurexf.d b/gcc/testsuite/gdc.test/compilable/futurexf.d
index c550b68..0a2df69 100644
--- a/gcc/testsuite/gdc.test/compilable/futurexf.d
+++ b/gcc/testsuite/gdc.test/compilable/futurexf.d
@@ -1,5 +1,5 @@
/* PERMUTE_ARGS:
- REQUIRED_ARGS: -Xffuture.json
+ REQUIRED_ARGS: -Xf${RESULTS_DIR}/compilable/futurexf.json
*/
class A
diff --git a/gcc/testsuite/gdc.test/compilable/fwdref21063.d b/gcc/testsuite/gdc.test/compilable/fwdref21063.d
new file mode 100644
index 0000000..2d0ca7f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/fwdref21063.d
@@ -0,0 +1,14 @@
+template Info(T, int line) {
+ static assert(__traits(getLinkage, T) == "C++");
+ alias Info = void;
+}
+
+// Forward reference
+static assert(__traits(getLinkage, Klass) == "C++");
+alias info1 = Info!(Klass, __LINE__);
+
+extern (C++) class Klass { void derp() {} }
+
+// Backward reference
+static assert(__traits(getLinkage, Klass) == "C++");
+alias info2 = Info!(Klass, __LINE__);
diff --git a/gcc/testsuite/gdc.test/compilable/header18364.d b/gcc/testsuite/gdc.test/compilable/header18364.d
new file mode 100644
index 0000000..c7e1e67
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/header18364.d
@@ -0,0 +1,24 @@
+/*
+REQUIRED_ARGS: -o- -Hf${RESULTS_DIR}/compilable/header18364.di
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/header18364.di
+
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/header18364.di
+// D import file generated from 'compilable/header18364.d'
+module foo.bar.ba;
+nothrow pure @nogc @safe package(foo)
+{
+ void foo();
+ nothrow pure @nogc @safe package(foo.bar) void foo2();
+}
+---
+*/
+
+module foo.bar.ba;
+@safe pure nothrow @nogc package(foo):
+void foo();
+
+@safe pure nothrow @nogc package(foo.bar):
+void foo2();
diff --git a/gcc/testsuite/gdc.test/compilable/header18365.d b/gcc/testsuite/gdc.test/compilable/header18365.d
new file mode 100644
index 0000000..7e51fb2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/header18365.d
@@ -0,0 +1,34 @@
+/*
+REQUIRED_ARGS: -c -o- -Hf${RESULTS_DIR}/compilable/header18365.di
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/header18365.di
+
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/header18365.di
+// D import file generated from 'compilable/header18365.d'
+struct FullCaseEntry
+{
+ dchar[3] seq;
+ ubyte n;
+ ubyte size;
+ ubyte entry_len;
+ auto const pure nothrow @nogc @property @trusted value() return
+ {
+ return seq[0..entry_len];
+ }
+}
+---
+*/
+
+struct FullCaseEntry
+{
+ dchar[3] seq;
+ ubyte n, size;
+ ubyte entry_len;
+
+ @property auto value() const @trusted pure nothrow @nogc return
+ {
+ return seq[0 .. entry_len];
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/ice11054.d b/gcc/testsuite/gdc.test/compilable/ice11054.d
index 1b8c63bd..5e35d5c 100644
--- a/gcc/testsuite/gdc.test/compilable/ice11054.d
+++ b/gcc/testsuite/gdc.test/compilable/ice11054.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/ice11054a.d
import imports.ice11054a;
static assert(!__traits(compiles, tuple()));
diff --git a/gcc/testsuite/gdc.test/compilable/ice11300.d b/gcc/testsuite/gdc.test/compilable/ice11300.d
index 473a1c2..6fccb15 100644
--- a/gcc/testsuite/gdc.test/compilable/ice11300.d
+++ b/gcc/testsuite/gdc.test/compilable/ice11300.d
@@ -1,5 +1,5 @@
// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/ice11300a.d
module ice11300;
import imports.ice11300a;
enum value = 42;
diff --git a/gcc/testsuite/gdc.test/compilable/ice13403.d b/gcc/testsuite/gdc.test/compilable/ice13403.d
index bb7c4e5..e452896 100644
--- a/gcc/testsuite/gdc.test/compilable/ice13403.d
+++ b/gcc/testsuite/gdc.test/compilable/ice13403.d
@@ -1,5 +1,6 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS: -o-
+// EXTRA_FILES: imports/ice13403a.d
import imports.ice13403a;
void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/ice13819.d b/gcc/testsuite/gdc.test/compilable/ice13819.d
new file mode 100644
index 0000000..88e93c6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ice13819.d
@@ -0,0 +1,7 @@
+// REQUIRED_ARGS: -O
+auto f (double a)
+{
+ return a % 2 != 0;
+}
+
+void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/ice1524.d b/gcc/testsuite/gdc.test/compilable/ice1524.d
index ffcf81b..6e59366 100644
--- a/gcc/testsuite/gdc.test/compilable/ice1524.d
+++ b/gcc/testsuite/gdc.test/compilable/ice1524.d
@@ -1,4 +1,5 @@
-// Issue 1524 - ICE(constfold.c) on using "is" with strings in CTFE
+// https://issues.dlang.org/show_bug.cgi?id=1524
+// ICE(constfold.c) on using "is" with strings in CTFE
/* 1524 PATCH Assertion failure: '0' on line 863 in file 'constfold.c'
constfold.c
diff --git a/gcc/testsuite/gdc.test/compilable/ice20044.d b/gcc/testsuite/gdc.test/compilable/ice20044.d
new file mode 100644
index 0000000..f85342c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ice20044.d
@@ -0,0 +1,10 @@
+struct Algebraic(T...)
+{
+ T t;
+}
+
+struct This;
+
+struct While(T) { T[] body; }
+
+alias Stmt = Algebraic!(While!(This));
diff --git a/gcc/testsuite/gdc.test/compilable/ice20415.d b/gcc/testsuite/gdc.test/compilable/ice20415.d
new file mode 100644
index 0000000..5eaafec
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ice20415.d
@@ -0,0 +1,16 @@
+// REQUIRED_ARGS: -O
+void t()
+{
+ auto a = A(false ? B().p : null);
+}
+
+struct A
+{
+ void* p;
+}
+
+struct B
+{
+ void* p;
+ ~this() {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/ice6538.d b/gcc/testsuite/gdc.test/compilable/ice6538.d
index 12d1ed0..2329f16 100644
--- a/gcc/testsuite/gdc.test/compilable/ice6538.d
+++ b/gcc/testsuite/gdc.test/compilable/ice6538.d
@@ -1,7 +1,7 @@
/**************************************/
-// 6538
+// https://issues.dlang.org/show_bug.cgi?id=6538
template allSatisfy(alias F, T...) { enum bool allSatisfy = true; }
template isIntegral(T) { enum bool isIntegral = true; }
@@ -23,7 +23,7 @@ void test6538b()
}
/**************************************/
-// 9361
+// https://issues.dlang.org/show_bug.cgi?id=9361
template Sym(alias A)
{
diff --git a/gcc/testsuite/gdc.test/compilable/ice854.d b/gcc/testsuite/gdc.test/compilable/ice854.d
index 3ede52e..13a5aff 100644
--- a/gcc/testsuite/gdc.test/compilable/ice854.d
+++ b/gcc/testsuite/gdc.test/compilable/ice854.d
@@ -1,4 +1,5 @@
-// Issue 854 - TypeTuple in anonymous delegate causes ice in glue.c
+// https://issues.dlang.org/show_bug.cgi?id=854
+// TypeTuple in anonymous delegate causes ice in glue.c
/* 854 VOTE PATCH (=2863, =2251?) Assertion failure: '0' on line 935 in file 'glue.c'
I haven't checked this patch myself.
diff --git a/gcc/testsuite/gdc.test/compilable/implicitconv.d b/gcc/testsuite/gdc.test/compilable/implicitconv.d
new file mode 100644
index 0000000..6fc7abf
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/implicitconv.d
@@ -0,0 +1,33 @@
+enum __c_wchar_t : wchar;
+
+alias wchar_t = __c_wchar_t;
+
+immutable(wchar_t)[] a = "somestring";
+const(wchar_t)[] b = "somestring";
+immutable(wchar_t)* c = "somestring";
+const(wchar_t)* d = "somestring";
+
+string foo = "foo";
+
+static assert(!__traits(compiles, { immutable(wchar_t)[] bar = foo; } ));
+static assert(!__traits(compiles, { const(wchar_t)[] bar = foo; } ));
+static assert(!__traits(compiles, { immutable(wchar_t)* bar = foo; } ));
+static assert(!__traits(compiles, { const(wchar_t)* bar = foo; } ));
+
+// https://issues.dlang.org/show_bug.cgi?id=17141
+static assert(is(typeof(true ? char.init : char.init) == char));
+static assert(is(typeof(true ? char.init : wchar.init) == dchar));
+static assert(is(typeof(true ? char.init : dchar.init) == dchar));
+static assert(is(typeof(true ? wchar.init : wchar.init) == wchar));
+static assert(is(typeof(true ? wchar.init : dchar.init) == dchar));
+static assert(is(typeof(true ? dchar.init : dchar.init) == dchar));
+
+enum cenum : char { a }
+enum wenum : wchar{ b }
+enum denum : dchar{ c }
+
+static assert(is(typeof(true ? char.init : cenum.init) == char));
+static assert(is(typeof(true ? wchar.init : cenum.init) == dchar));
+static assert(is(typeof(true ? char.init : wenum.init) == dchar));
+static assert(is(typeof(true ? dchar.init : wenum.init) == dchar));
+static assert(is(typeof(true ? cenum.init : wenum.init) == dchar));
diff --git a/gcc/testsuite/gdc.test/compilable/imports/a12511.d b/gcc/testsuite/gdc.test/compilable/imports/a12511.d
new file mode 100644
index 0000000..262bb61
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/a12511.d
@@ -0,0 +1,7 @@
+module a12511;
+
+public class A
+{
+ private static void foo() {}
+ public static void foo(int) {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/a18911.d b/gcc/testsuite/gdc.test/compilable/imports/a18911.d
new file mode 100644
index 0000000..81b46e0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/a18911.d
@@ -0,0 +1,2 @@
+enum A_FILE = __FILE_FULL_PATH__;
+enum suffix_a = "imports/a18911.d";
diff --git a/gcc/testsuite/gdc.test/compilable/imports/cstuff3.c b/gcc/testsuite/gdc.test/compilable/imports/cstuff3.c
new file mode 100644
index 0000000..f6aaf3b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/cstuff3.c
@@ -0,0 +1,6 @@
+// check bugs in importing C files
+
+int squared(int a)
+{
+ return a * a;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/g313.d b/gcc/testsuite/gdc.test/compilable/imports/g313.d
index 92e703a..0a9d26b 100644
--- a/gcc/testsuite/gdc.test/compilable/imports/g313.d
+++ b/gcc/testsuite/gdc.test/compilable/imports/g313.d
@@ -1,6 +1,6 @@
module imports.g313;
-// adds public package imports (see Bugzilla 15900)
+// adds public package imports (see https://issues.dlang.org/show_bug.cgi?id=15900)
public import imports.g313public;
// same w/ deferred semantics
static if (true)
diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp16088.d b/gcc/testsuite/gdc.test/compilable/imports/imp16088.d
new file mode 100644
index 0000000..5c5bc5e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/imp16088.d
@@ -0,0 +1 @@
+module imports.imp16088;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp21832.d b/gcc/testsuite/gdc.test/compilable/imports/imp21832.d
new file mode 100644
index 0000000..ee4a1d6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/imp21832.d
@@ -0,0 +1,24 @@
+module imports.imp21832;
+static if(1)
+{
+ int fun(int a)
+ {
+ return a;
+ }
+ int tpl()(int a)
+ {
+ return a;
+ }
+}
+
+deprecated
+{
+ int fun(char a)
+ {
+ return a;
+ }
+ int tpl()(char a)
+ {
+ return a;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp22122.d b/gcc/testsuite/gdc.test/compilable/imports/imp22122.d
new file mode 100644
index 0000000..b29bae0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/imp22122.d
@@ -0,0 +1,5 @@
+module imports.imp22122;
+
+package struct Imp22122
+{
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/impfieldwise.d b/gcc/testsuite/gdc.test/compilable/imports/impfieldwise.d
new file mode 100644
index 0000000..df9b987
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/impfieldwise.d
@@ -0,0 +1,8 @@
+@safe:
+
+struct S
+{
+ private:
+ @safe:
+ int a, b;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/pkg11847/mod11847.d b/gcc/testsuite/gdc.test/compilable/imports/pkg11847/mod11847.d
new file mode 100644
index 0000000..5f8ef76
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/pkg11847/mod11847.d
@@ -0,0 +1,3 @@
+module pkg11847.mod11847;
+
+int func() { return 2; }
diff --git a/gcc/testsuite/gdc.test/compilable/imports/pkg11847/package.d b/gcc/testsuite/gdc.test/compilable/imports/pkg11847/package.d
new file mode 100644
index 0000000..0a6c1ec
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/pkg11847/package.d
@@ -0,0 +1,3 @@
+module pkg11847;
+
+int func() { return 1; }
diff --git a/gcc/testsuite/gdc.test/compilable/imports/protectionimp.d b/gcc/testsuite/gdc.test/compilable/imports/protectionimp.d
index 6c99cf3..2f3c711 100644
--- a/gcc/testsuite/gdc.test/compilable/imports/protectionimp.d
+++ b/gcc/testsuite/gdc.test/compilable/imports/protectionimp.d
@@ -22,7 +22,7 @@ private alias privC privA;
public mixin template publMT() {}
/***************************************************/
-// 14169
+// https://issues.dlang.org/show_bug.cgi?id=14169
template GetName14169(TemplateParam)
{
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test11563std_traits.d b/gcc/testsuite/gdc.test/compilable/imports/test11563std_traits.d
index 983fd11..0ee4643 100644
--- a/gcc/testsuite/gdc.test/compilable/imports/test11563std_traits.d
+++ b/gcc/testsuite/gdc.test/compilable/imports/test11563std_traits.d
@@ -16,7 +16,7 @@ template moduleName(alias T)
}
else
{
- pragma(msg, "--error--");
+ enum moduleName = "--error--";
}
}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test13582.d b/gcc/testsuite/gdc.test/compilable/imports/test13582.d
new file mode 100644
index 0000000..493dbc3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test13582.d
@@ -0,0 +1 @@
+deprecated module imports.test13582;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test16709a.d b/gcc/testsuite/gdc.test/compilable/imports/test16709a.d
new file mode 100644
index 0000000..99d1fef
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test16709a.d
@@ -0,0 +1,2 @@
+module test16709a;
+public import imports.test16709b:to;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test16709b.d b/gcc/testsuite/gdc.test/compilable/imports/test16709b.d
new file mode 100644
index 0000000..8fa00ab
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test16709b.d
@@ -0,0 +1,5 @@
+module test16709b;
+public:
+
+import imports.test16709c;
+import imports.test16709d;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test16709c.d b/gcc/testsuite/gdc.test/compilable/imports/test16709c.d
new file mode 100644
index 0000000..1b45163
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test16709c.d
@@ -0,0 +1,2 @@
+void to(string units, D)(D td) { }
+
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test16709d.d b/gcc/testsuite/gdc.test/compilable/imports/test16709d.d
new file mode 100644
index 0000000..9f928af
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test16709d.d
@@ -0,0 +1,2 @@
+void to(T, D)(D td) { }
+
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test17441foo/bar.d b/gcc/testsuite/gdc.test/compilable/imports/test17441foo/bar.d
new file mode 100644
index 0000000..5b46b9e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test17441foo/bar.d
@@ -0,0 +1 @@
+module imports.test17441foo.bar;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test17441foo/package.d b/gcc/testsuite/gdc.test/compilable/imports/test17441foo/package.d
new file mode 100644
index 0000000..d795f45
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test17441foo/package.d
@@ -0,0 +1 @@
+module imports.test17441foo;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test17541_2.d b/gcc/testsuite/gdc.test/compilable/imports/test17541_2.d
new file mode 100644
index 0000000..4554bf2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test17541_2.d
@@ -0,0 +1,20 @@
+module two;
+
+import one;
+
+struct ET(bool a)
+{
+ enum e = BB.MAX_NUM_FIBERS;
+}
+
+alias Event = ET!false;
+
+struct TWOR(size_t M)
+{
+ Event e;
+
+ void open()
+ {
+ bb.foo();
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test17541_3.d b/gcc/testsuite/gdc.test/compilable/imports/test17541_3.d
new file mode 100644
index 0000000..5ddec9e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test17541_3.d
@@ -0,0 +1,15 @@
+module three;
+
+void aaa() @nogc
+{
+
+}
+
+struct TT(T)
+{
+ void insertabcdefg(T) // @nogc <-- deduction problem
+ {
+ //static assert(insertabcdefg.mangleof == "_D5three__T2TTTiZQg13insertabcdefgMFiZv");
+ aaa();
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test18651/algorithm.d b/gcc/testsuite/gdc.test/compilable/imports/test18651/algorithm.d
new file mode 100644
index 0000000..970f072
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test18651/algorithm.d
@@ -0,0 +1,14 @@
+struct SortedRange(Range)
+{
+ Range _input;
+}
+
+auto sort(Range)(Range)
+{
+ return SortedRange!Range();
+}
+
+auto uniq(Range)(Range)
+{
+ return SortedRange!Range();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test18651/b.d b/gcc/testsuite/gdc.test/compilable/imports/test18651/b.d
new file mode 100644
index 0000000..8ca3ca2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test18651/b.d
@@ -0,0 +1 @@
+import imports.test18651.c;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test18651/c.d b/gcc/testsuite/gdc.test/compilable/imports/test18651/c.d
new file mode 100644
index 0000000..93b1d95
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test18651/c.d
@@ -0,0 +1,4 @@
+module imports.test18651.c;
+import imports.test18651.algorithm;
+
+const var = sort(string[].init);
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test18651/datetime.d b/gcc/testsuite/gdc.test/compilable/imports/test18651/datetime.d
new file mode 100644
index 0000000..43d5d66
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test18651/datetime.d
@@ -0,0 +1,7 @@
+void parseTZConversions()
+{
+ import imports.test18651.algorithm;
+
+ string[] value;
+ value.sort.uniq;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test18771a.d b/gcc/testsuite/gdc.test/compilable/imports/test18771a.d
new file mode 100644
index 0000000..7527c31
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test18771a.d
@@ -0,0 +1,3 @@
+module imports.test18771a;
+
+void foo(int) {}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test18771b.d b/gcc/testsuite/gdc.test/compilable/imports/test18771b.d
new file mode 100644
index 0000000..f48dc5f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test18771b.d
@@ -0,0 +1,3 @@
+module imports.test18771b;
+
+void foo(string) {}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test18771c.d b/gcc/testsuite/gdc.test/compilable/imports/test18771c.d
new file mode 100644
index 0000000..dc986d2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test18771c.d
@@ -0,0 +1,4 @@
+module imports.test18771c;
+
+import imports.test18771a, imports.test18771b;
+alias fooC = foo;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test18771d.d b/gcc/testsuite/gdc.test/compilable/imports/test18771d.d
new file mode 100644
index 0000000..fbf2034
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test18771d.d
@@ -0,0 +1,4 @@
+module imports.test18771d;
+
+import imports.test18771b, imports.test18771a;
+alias fooD = foo;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19187.d b/gcc/testsuite/gdc.test/compilable/imports/test19187.d
new file mode 100644
index 0000000..3bf435e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19187.d
@@ -0,0 +1,4 @@
+module imports.test19187;
+void test()() { }
+alias foo = test;
+alias foo = test;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19344.d b/gcc/testsuite/gdc.test/compilable/imports/test19344.d
new file mode 100644
index 0000000..437968a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19344.d
@@ -0,0 +1,6 @@
+module imports.test19344;
+
+template getUDAs(alias symbol, alias attribute)
+{
+ alias getUDAs = __traits(getAttributes, symbol);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19656a.d b/gcc/testsuite/gdc.test/compilable/imports/test19656a.d
new file mode 100644
index 0000000..14642eaa
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19656a.d
@@ -0,0 +1,3 @@
+import test19656;
+
+class Corge: Foo { }
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19656b.d b/gcc/testsuite/gdc.test/compilable/imports/test19656b.d
new file mode 100644
index 0000000..ffcf17a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19656b.d
@@ -0,0 +1,13 @@
+import test19656;
+
+class Bar { }
+
+class Qux(T): Foo
+{
+ override void thunk() { }
+}
+
+class Fred
+{
+ Qux!Bar _q;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19656c.d b/gcc/testsuite/gdc.test/compilable/imports/test19656c.d
new file mode 100644
index 0000000..e4ccfee
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19656c.d
@@ -0,0 +1,3 @@
+import imports.test19656b;
+
+class Thud { }
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19657b.d b/gcc/testsuite/gdc.test/compilable/imports/test19657b.d
new file mode 100644
index 0000000..406cf6d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19657b.d
@@ -0,0 +1,6 @@
+import test19657g;
+import test19657a;
+import test19657e;
+class Frop: Seq {
+ override bool func(Foo rhs, Bar bee) { return false; }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19657c.d b/gcc/testsuite/gdc.test/compilable/imports/test19657c.d
new file mode 100644
index 0000000..e715ef0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19657c.d
@@ -0,0 +1,2 @@
+import test19657a;
+class Pol: Foo {}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19657d.d b/gcc/testsuite/gdc.test/compilable/imports/test19657d.d
new file mode 100644
index 0000000..59c9a54
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19657d.d
@@ -0,0 +1,2 @@
+import test19657a;
+class Trump: Foo {}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19657e.d b/gcc/testsuite/gdc.test/compilable/imports/test19657e.d
new file mode 100644
index 0000000..9707b2b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19657e.d
@@ -0,0 +1,2 @@
+import test19657f;
+class Bar { }
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19657f.d b/gcc/testsuite/gdc.test/compilable/imports/test19657f.d
new file mode 100644
index 0000000..b291018
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19657f.d
@@ -0,0 +1,3 @@
+class Baz {
+ import test19657d;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19657g.d b/gcc/testsuite/gdc.test/compilable/imports/test19657g.d
new file mode 100644
index 0000000..d641b20
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19657g.d
@@ -0,0 +1,2 @@
+import test19657d;
+class Seq: Trump {}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19746a.d b/gcc/testsuite/gdc.test/compilable/imports/test19746a.d
new file mode 100644
index 0000000..d0c6a8f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19746a.d
@@ -0,0 +1,2 @@
+import test19746;
+class Bar: Foo { }
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19746b.d b/gcc/testsuite/gdc.test/compilable/imports/test19746b.d
new file mode 100644
index 0000000..1ceacb4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19746b.d
@@ -0,0 +1,2 @@
+import test19746d;
+class Frop { }
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19746c.d b/gcc/testsuite/gdc.test/compilable/imports/test19746c.d
new file mode 100644
index 0000000..a90b048
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19746c.d
@@ -0,0 +1,2 @@
+import test19746a;
+class Qux: Bar { }
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19746d.d b/gcc/testsuite/gdc.test/compilable/imports/test19746d.d
new file mode 100644
index 0000000..36a3f82
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19746d.d
@@ -0,0 +1,10 @@
+import test19746;
+class Baz(T): Foo { }
+class Dap(T): Baz!T
+{
+ override void thunk() {}
+}
+class Zoo
+{
+ Dap!int _dap;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19750a.d b/gcc/testsuite/gdc.test/compilable/imports/test19750a.d
new file mode 100644
index 0000000..6677e2a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19750a.d
@@ -0,0 +1,2 @@
+import test19750c;
+class Bar {}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19750b.d b/gcc/testsuite/gdc.test/compilable/imports/test19750b.d
new file mode 100644
index 0000000..f0d8f90
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19750b.d
@@ -0,0 +1,2 @@
+import test19750d;
+class Frop {}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19750c.d b/gcc/testsuite/gdc.test/compilable/imports/test19750c.d
new file mode 100644
index 0000000..8de5797
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19750c.d
@@ -0,0 +1,4 @@
+import test19750d;
+class Qux: Thud {
+ override void thunk() {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test19750d.d b/gcc/testsuite/gdc.test/compilable/imports/test19750d.d
new file mode 100644
index 0000000..06cf58b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test19750d.d
@@ -0,0 +1,6 @@
+import test19750;
+class Dap(T) {}
+class Thud: Foo {
+ Dap!int _dap;
+ void thunk() { }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test21227/..foo/a.txt b/gcc/testsuite/gdc.test/compilable/imports/test21227/..foo/a.txt
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test21227/..foo/a.txt
@@ -0,0 +1 @@
+hello
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test21227/a..b.txt b/gcc/testsuite/gdc.test/compilable/imports/test21227/a..b.txt
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test21227/a..b.txt
@@ -0,0 +1 @@
+hello
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test21227/a.txt b/gcc/testsuite/gdc.test/compilable/imports/test21227/a.txt
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test21227/a.txt
@@ -0,0 +1 @@
+hello
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test21464a.d b/gcc/testsuite/gdc.test/compilable/imports/test21464a.d
new file mode 100644
index 0000000..e3468f8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test21464a.d
@@ -0,0 +1,4 @@
+struct Mallocator
+{
+ static shared Mallocator instance;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test63a.d b/gcc/testsuite/gdc.test/compilable/imports/test63a.d
index a8edbd8..d53b034 100644
--- a/gcc/testsuite/gdc.test/compilable/imports/test63a.d
+++ b/gcc/testsuite/gdc.test/compilable/imports/test63a.d
@@ -4,7 +4,7 @@ private import test63;
struct s {
- char a[ SIZE ];
+ char[SIZE] a;
}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/testcontracts.d b/gcc/testsuite/gdc.test/compilable/imports/testcontracts.d
index f7414ce..5d30965 100644
--- a/gcc/testsuite/gdc.test/compilable/imports/testcontracts.d
+++ b/gcc/testsuite/gdc.test/compilable/imports/testcontracts.d
@@ -11,7 +11,7 @@ class Base3602
assert(x > 0);
assert(y > 0);
}
- body
+ do
{
}
}
@@ -25,7 +25,7 @@ class Base5230
out (res)
{
}
- body
+ do
{
return 42;
}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/testlambda1.d b/gcc/testsuite/gdc.test/compilable/imports/testlambda1.d
new file mode 100644
index 0000000..c0a9696
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/testlambda1.d
@@ -0,0 +1,3 @@
+module imports.testlambda1;
+
+int bar() { return 7; }
diff --git a/gcc/testsuite/gdc.test/compilable/imports/testlambda2.d b/gcc/testsuite/gdc.test/compilable/imports/testlambda2.d
new file mode 100644
index 0000000..e96ef9f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/testlambda2.d
@@ -0,0 +1,3 @@
+module imports.testlambda2;
+
+int bar() { return 7; }
diff --git a/gcc/testsuite/gdc.test/compilable/imports/u20958.d b/gcc/testsuite/gdc.test/compilable/imports/u20958.d
new file mode 100644
index 0000000..df67583
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/u20958.d
@@ -0,0 +1,6 @@
+struct W()
+{
+ int[] J;
+}
+
+typeof(typeid(W!())) OB;
diff --git a/gcc/testsuite/gdc.test/compilable/interpret3.d b/gcc/testsuite/gdc.test/compilable/interpret3.d
index a2830ea..ff85856 100644
--- a/gcc/testsuite/gdc.test/compilable/interpret3.d
+++ b/gcc/testsuite/gdc.test/compilable/interpret3.d
@@ -2,8 +2,7 @@
/*
TEST_OUTPUT:
---
-compilable/interpret3.d(2914): Deprecation: `case` variables have to be `const` or `immutable`
-compilable/interpret3.d(6351): Deprecation: identity comparison of static arrays implicitly coerces them to slices, which are compared by reference
+compilable/interpret3.d(6350): Deprecation: identity comparison of static arrays implicitly coerces them to slices, which are compared by reference
---
*/
@@ -14,9 +13,9 @@ template compiles(int T)
alias TypeTuple(T...) = T;
-/**************************************************
- 3901 Arbitrary struct assignment, ref return
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=3901
+// Arbitrary struct assignment, ref return
struct ArrayRet
{
@@ -31,7 +30,7 @@ int arrayRetTest(int z)
}
static assert(arrayRetTest(51) == 51);
-// Bugzilla 3842 -- must not segfault
+// https://issues.dlang.org/show_bug.cgi?id=3842 -- must not segfault
int ice3842(int z)
{
ArrayRet w;
@@ -85,24 +84,24 @@ struct RetRefStruct
// Return value reference tests, for D2 only.
-ref RetRefStruct reffunc1(ref RetRefStruct a)
+ref RetRefStruct reffunc1(return ref RetRefStruct a)
{
int y = a.x;
return a;
}
-ref RetRefStruct reffunc2(ref RetRefStruct a)
+ref RetRefStruct reffunc2(return ref RetRefStruct a)
{
RetRefStruct z = a;
return reffunc1(a);
}
-ref int reffunc7(ref RetRefStruct aa)
+ref int reffunc7(return ref RetRefStruct aa)
{
return reffunc1(aa).x;
}
-ref int reffunc3(ref int a)
+ref int reffunc3(return ref int a)
{
return a;
}
@@ -111,18 +110,18 @@ struct RefTestStruct
{
RetRefStruct r;
- ref RefTestStruct reffunc4(ref RetRefStruct[3] a)
+ ref RefTestStruct reffunc4(ref RetRefStruct[3] a) return
{
return this;
}
- ref int reffunc6()
+ ref int reffunc6() return
{
return this.r.x;
}
}
-ref RetRefStruct reffunc5(ref RetRefStruct[3] a)
+ref RetRefStruct reffunc5(return ref RetRefStruct[3] a)
{
int t = 1;
for (int i = 0; i < 10; ++i)
@@ -189,9 +188,9 @@ static assert(retRefTest2() == 2);
static assert(retRefTest3() == 26);
static assert(retRefTest4() == 218);
-/**************************************************
- Bug 7887 assign to returned reference
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7887
+// assign to returned reference
bool test7887()
{
@@ -202,9 +201,9 @@ bool test7887()
}
static assert(test7887());
-/**************************************************
- Bug 7473 struct non-ref
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7473
+// struct non-ref
struct S7473
{
@@ -242,9 +241,8 @@ void bug7473b(S7473b s)
s.m.i = 2;
}
-/**************************************************
- Bug 4389
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=4389
int bug4389()
{
@@ -296,7 +294,8 @@ string ice4390()
static assert(mixin(ice4390()) == ``);
-// bug 5248 (D1 + D2)
+// https://issues.dlang.org/show_bug.cgi?id=5248
+// (D1 + D2)
struct Leaf5248
{
string Compile_not_ovloaded()
@@ -316,9 +315,9 @@ struct Matrix5248
static assert(Matrix5248().Compile());
-/**************************************************
- 4837 >>>=
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=4837
+// >>>=
bool bug4837()
{
@@ -333,9 +332,9 @@ bool bug4837()
static assert(bug4837());
-/**************************************************
- 10252 shift out of range
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10252
+// shift out of range
int lshr10252(int shift)
{
@@ -362,9 +361,9 @@ static assert(!is(typeof(compiles!(rshr10252(80)))));
static assert( is(typeof(compiles!(ushr10252( 2)))));
static assert(!is(typeof(compiles!(ushr10252(60)))));
-/**************************************************
- 1982 CTFE null problems
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=1982
+// CTFE null problems
enum a1982 = [1, 2, 3];
static assert(a1982 !is null);
@@ -375,16 +374,16 @@ static assert(!foo1982().length);
static assert(null is null);
-/**************************************************
- 7988 CTFE return values should be allowed in compile-time expressions
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7988
+// CTFE return values should be allowed in compile-time expressions
class X7988 { int y; this() { y = 2; } }
static assert((new X7988).y == 2);
-/**************************************************
- 8253 ICE: calling of member function of non-CTFE class variable
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8253
+// ICE: calling of member function of non-CTFE class variable
class Bug8253
{
@@ -396,9 +395,9 @@ class Bug8253
Bug8253 m8253;
static assert(!is(typeof(compiles!(m8253.j()))));
-/**************************************************
- 8285 Issue with slice returned from CTFE function
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8285
+// Issue with slice returned from CTFE function
string foo8285()
{
@@ -475,9 +474,9 @@ int thisbug2()
static assert(thisbug2());
-/**************************************************
- 6972 ICE with cast()cast()assign
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6972
+// ICE with cast()cast()assign
int bug6972()
{
@@ -487,9 +486,8 @@ int bug6972()
}
static assert(bug6972() == 3);
-/**************************************************
- Bug 6164
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6164
size_t bug6164()
{
@@ -641,7 +639,7 @@ size_t bug5524(int x, int[] more...)
static assert(bug5524(3) == 10);
-// 5722
+// https://issues.dlang.org/show_bug.cgi?id=5722
static assert(("" ~ "\&copy;"[0]).length == 1);
const char[] null5722 = null;
@@ -650,8 +648,13 @@ static assert(("\&copy;"[0] ~ null5722).length == 1);
/*******************************************
* Tests for CTFE Array support.
- * Including bugs 1330, 3801, 3835, 4050,
- * 4051, 5147, and major functionality
+ * https://issues.dlang.org/show_bug.cgi?id=1330
+ * https://issues.dlang.org/show_bug.cgi?id=3801
+ * https://issues.dlang.org/show_bug.cgi?id=3835
+ * https://issues.dlang.org/show_bug.cgi?id=4050
+ * https://issues.dlang.org/show_bug.cgi?id=4051
+ * https://issues.dlang.org/show_bug.cgi?id=5147
+ * and major functionality
*******************************************/
char[] bug1330StringIndex()
@@ -971,7 +974,7 @@ auto bug5852(const(string) s)
}
static assert(bug5852("abc") == 3);
-// 7217
+// https://issues.dlang.org/show_bug.cgi?id=7217
struct S7217 { int[] arr; }
@@ -998,7 +1001,8 @@ static assert(
return true;
}());
-// 7185 char[].length = n
+// https://issues.dlang.org/show_bug.cgi?id=7185
+// char[].length = n
bool bug7185()
{
@@ -1021,9 +1025,8 @@ bool bug9908()
}
static assert(bug9908());
-/*******************************************
- 6934
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6934
struct Struct6934
{
@@ -1049,15 +1052,13 @@ int bug6934()
}
static assert(bug6934());
-/*******************************************
- Bug 5671
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5671
static assert(['a', 'b'] ~ "c" == "abc");
-/*******************************************
- 8624
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8624
int evil8624()
{
@@ -1070,9 +1071,9 @@ int evil8624()
}
static assert(evil8624());
-/*******************************************
- 8644 array literal >,<
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8644
+// array literal >,<
int bug8644()
{
@@ -1090,18 +1091,16 @@ int bug8644()
}
static assert(bug8644());
-/*******************************************
- Bug 6159
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6159
struct A6159 {}
static assert({ return A6159.init is A6159.init; }());
static assert({ return [1] is [1]; }());
-/*******************************************
- Bug 5685
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5685
string bug5685()
{
@@ -1115,9 +1114,9 @@ struct Bug5865
}
}
-/*******************************************
- 6235 - Regression ICE on $ in template
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6235
+// Regression ICE on $ in template
struct Bug6235(R)
{
@@ -1126,15 +1125,14 @@ struct Bug6235(R)
Bug6235!(ubyte[]) bug6235;
-/*******************************************
- 8673 ICE
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8673
+// ICE
enum dollar8673 = [0][(() => $ - 1)()];
-/*******************************************
- Bug 5840
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5840
struct Bug5840
{
@@ -1164,9 +1162,8 @@ int bug5840(int u)
}
static assert(bug5840(1) == 56);
-/*******************************************
- 7810
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7810
int bug7810()
{
@@ -1207,9 +1204,8 @@ public:
}
const testTODsThrownZ = TimeOfDayZ(0);
-/*******************************************
- Bug 5954
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5954
struct Bug5954
{
@@ -1225,9 +1221,8 @@ void bug5954()
static assert(f.x == 10);
}
-/*******************************************
- Bug 5972
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5972
int bug5972()
{
@@ -1258,16 +1253,16 @@ int wconcat(wstring replace)
}
static assert(wconcat("X"w));
-/*******************************************
- 10397 string concat
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10397
+// string concat
static assert(!is(typeof(compiles!("abc" ~ undefined))));
static assert(!is(typeof(compiles!(otherundefined ~ "abc"))));
-/*******************************************
- 9634 struct concat
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=9634
+// struct concat
struct Bug9634
{
@@ -1292,9 +1287,8 @@ bool bug9634()
static assert(bug9634());
-/*******************************************
- Bug 4001: A Space Oddity
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=4001: A Space Oddity
int space() { return 4001; }
@@ -1305,15 +1299,14 @@ void oddity4001(int q)
static assert(bowie == 4001);
}
-/*******************************************
- Bug 3779
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=3779
static const bug3779 = ["123"][0][$ - 1];
-/*******************************************
- Bug 8893 ICE with bad struct literal
-*******************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8893
+// ICE with bad struct literal
struct Foo8893
{
@@ -1333,7 +1326,7 @@ struct Zadok
{
int[3] z;
char[4] s = void;
- ref int[] fog(ref int[] q) { return q; }
+ ref int[] fog(return ref int[] q) { return q; }
int bfg()
{
z[0] = 56;
@@ -1394,9 +1387,9 @@ int quop()
static assert(quop() == 8);
static assert(quop() == 8); // check for clobbering
-/**************************************************
- Bug 5676 tuple assign of struct that has void opAssign
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5676
+// tuple assign of struct that has void opAssign
struct S5676
{
@@ -1420,9 +1413,9 @@ bool ice5676()
static assert(ice5676());
-/**************************************************
- Bug 5682 Wrong CTFE with operator overloading
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5682
+// Wrong CTFE with operator overloading
struct A
{
@@ -1555,9 +1548,9 @@ int sdfgasf()
}
static assert(sdfgasf() == 1);
-/**************************************************
- 8830 slice of slice.ptr
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8830
+// slice of slice.ptr
string bug8830(string s)
{
@@ -1566,9 +1559,9 @@ string bug8830(string s)
}
static assert(bug8830("hello") == "el");
-/**************************************************
- 8608 ICE
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8608
+// ICE
void bug8608(ref int m) {}
void test8608()
@@ -1584,9 +1577,8 @@ void test8608()
static assert(!is(typeof(compiles!(foo(true) ))));
}
-/**************************************************
- Bug 7770
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7770
immutable char[] foo7770 = "abcde";
@@ -1609,9 +1601,9 @@ void baz7770()
static assert(bug7770b(foo7770[$ - 2]));
}
-/**************************************************
- 8601 ICE
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8601
+// ICE
dchar bug8601(dstring s)
{
@@ -1622,9 +1614,8 @@ dchar bug8601(dstring s)
enum dstring e8601 = [cast(dchar)'o', 'n'];
static assert(bug8601(e8601) == 'n');
-/**************************************************
- Bug 6015
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6015
struct Foo6015
{
@@ -1644,9 +1635,8 @@ bool func6015(string input)
static assert(func6015("test"));
-/**************************************************
- Bug 6001
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6001
void bug6001e(ref int[] s)
{
@@ -1694,10 +1684,11 @@ bool bug6001h()
}
static assert(bug6001h());
-/**************************************************
- 10243 wrong code *&arr as ref parameter
- 10551 wrong code (&arr)[0] as ref parameter
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10243
+// wrong code *&arr as ref parameter
+// https://issues.dlang.org/show_bug.cgi?id=10551
+// wrong code (&arr)[0] as ref parameter
void bug10243(ref int n)
{
@@ -1725,9 +1716,8 @@ bool test10243()
static assert(test10243());
-/**************************************************
- Bug 4910
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=4910
int bug4910(int a)
{
@@ -1739,9 +1729,9 @@ static assert(!is(typeof(Compiles!(bug4910(var4910)))));
static assert(bug4910(123));
-/**************************************************
- Bug 5845 - Regression(2.041)
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5845
+// Regression(2.041)
void test5845(ulong cols) {}
@@ -1762,9 +1752,8 @@ ulong nqueen(int n)
static assert(nqueen(2) == 65);
-/**************************************************
- Bug 5258
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5258
struct Foo5258 { int x; }
void bar5258(int n, ref Foo5258 fong)
@@ -1819,9 +1808,8 @@ size_t bug5258c()
}
static assert(bug5258c() == 20);
-/**************************************************
- Bug 6049
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6049
struct Bug6049
{
@@ -1834,9 +1822,8 @@ const Bug6049[] foo6049 = [Bug6049(6), Bug6049(17)];
static assert(foo6049[0].m == 6);
-/**************************************************
- Bug 6052
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6052
struct Bug6052
{
@@ -1939,9 +1926,8 @@ static assert({
return true;
}());
-/**************************************************
- Bug 6749
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6749
struct CtState
{
@@ -1989,9 +1975,9 @@ int keyAssign()
}
static assert(keyAssign() == 5);
-/**************************************************
- Bug 6054 -- AA literals
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6054
+// AA literals
enum x6054 = {
auto p = {
@@ -2002,9 +1988,8 @@ enum x6054 = {
return p;
}();
-/**************************************************
- Bug 6077
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6077
enum bug6077 = {
string s;
@@ -2012,9 +1997,9 @@ enum bug6077 = {
return s ~ t;
}();
-/**************************************************
- Bug 6078 -- Pass null array by ref
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6078
+// Pass null array by ref
struct Foo6078
{
@@ -2042,9 +2027,9 @@ static assert({
return bug6078(f.bar);
}() == 2);
-/**************************************************
- Bug 6079 -- Array bounds checking
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6079
+// Array bounds checking
static assert(!is(typeof(compiles!({
int[] x = [1, 2, 3, 4];
@@ -2053,9 +2038,8 @@ static assert(!is(typeof(compiles!({
}()
))));
-/**************************************************
- Bug 6100
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6100
struct S6100
{
@@ -2071,9 +2055,9 @@ S6100 init6100(int x)
static const S6100[2] s6100a = [init6100(1), init6100(2)];
static assert(s6100a[0].a == 1);
-/**************************************************
- Bug 4825 -- failed with -inline
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=4825
+// failed with -inline
int a4825()
{
@@ -2095,9 +2079,9 @@ void c4825()
static const int f = b4825();
}
-/**************************************************
- Bug 5708 -- failed with -inline
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5708
+// failed with -inline
string b5708(string s) { return s; }
string a5708(string s) { return b5708(s); }
@@ -2109,9 +2093,9 @@ void bug5708()
static assert(a5708("bar") == "bar");
}
-/**************************************************
- Bug 6120 -- failed with -inline
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6120
+// failed with -inline
struct Bug6120(T)
{
@@ -2122,9 +2106,9 @@ static assert({
return true;
}());
-/**************************************************
- Bug 6123 -- failed with -inline
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6123
+// failed with -inline
struct Bug6123(T)
{
@@ -2137,9 +2121,9 @@ static assert({
return true;
}());
-/**************************************************
- Bug 6053 -- ICE involving pointers
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6053
+// ICE involving pointers
static assert({
int* a = null;
@@ -2328,9 +2312,9 @@ bool nullptrcmp()
}
static assert(nullptrcmp());
-/**************************************************
- 10840 null pointer in dotvar
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10840
+// null pointer in dotvar
struct Data10840
{
@@ -2357,9 +2341,9 @@ bool bug10840(int n)
static assert(bug10840(0));
static assert(!is(typeof(Compileable!(bug10840(1)))));
-/**************************************************
- 8216 ptr inside a pointer range
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8216
+// ptr inside a pointer range
// Four-pointer relations. Return true if [p1 .. p2] points inside [q1 .. q2]
// (where the end points don't coincide).
@@ -2405,9 +2389,9 @@ bool bug8216()
}
static assert(bug8216());
-/**************************************************
- 6517 ptr++, ptr--
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6517
+// ptr++, ptr--
int bug6517()
{
@@ -2468,16 +2452,15 @@ static assert({
return 6;
}() == 6);
-/**************************************************
- Reduced version of bug 5615
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5615
const(char)[] passthrough(const(char)[] x)
{
return x;
}
-sizediff_t checkPass(Char1)(const(Char1)[] s)
+ptrdiff_t checkPass(Char1)(const(Char1)[] s)
{
const(Char1)[] balance = s[1 .. $];
return passthrough(balance).ptr - s.ptr;
@@ -2588,9 +2571,9 @@ struct AList
static assert(AList.checkList() == 2);
-/**************************************************
- 7194 pointers as struct members
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7194
+// pointers as struct members
struct S7194 { int* p, p2; }
@@ -2620,9 +2603,9 @@ int g7194()
static assert(f7194() == 0);
static assert(!is(typeof(compiles!(g7194()))));
-/**************************************************
- 7248 recursive struct pointers in array
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7248
+// recursive struct pointers in array
struct S7248 { S7248* ptr; }
@@ -2636,9 +2619,9 @@ bool bug7248()
}
static assert(bug7248());
-/**************************************************
- 7216 calling a struct pointer member
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7216
+// calling a struct pointer member
struct S7216
{
@@ -2662,9 +2645,9 @@ bool bug7216()
static assert(bug7216());
-/**************************************************
- 10858 Wrong code with array of pointers
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10858
+// Wrong code with array of pointers
bool bug10858()
{
@@ -2675,9 +2658,9 @@ bool bug10858()
}
static assert(bug10858());
-/**************************************************
- 12528 - painting inout type for value type literals
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12528
+// painting inout type for value type literals
inout(T)[] dup12528(T)(inout(T)[] a)
{
@@ -2692,9 +2675,9 @@ enum arr12528V2 = dup12528([0, 1]);
static assert(arr12528V1 == [0]);
static assert(arr12528V2 == [0, 1]);
-/**************************************************
- 9745 Allow pointers to static variables
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=9745
+// Allow pointers to static variables
shared int x9745;
shared int[5] y9745;
@@ -2751,9 +2734,9 @@ bool test9745b()
}
static assert(test9745b());
-/**************************************************
- 9364 ICE with pointer to local struct
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=9364
+// ICE with pointer to local struct
struct S9364
{
@@ -2769,9 +2752,9 @@ bool bug9364()
static assert(bug9364());
-/**************************************************
- 10251 Pointers to const globals
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10251
+// Pointers to const globals
static const int glob10251 = 7;
@@ -2783,9 +2766,9 @@ const(int)* bug10251()
static a10251 = &glob10251; // OK
static b10251 = bug10251();
-/**************************************************
- 4065 [CTFE] AA "in" operator doesn't work
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=4065
+// [CTFE] AA "in" operator doesn't work
bool bug4065(string s)
{
@@ -2807,9 +2790,9 @@ static assert(!bug4065("xx"));
static assert( bug4065("aa"));
static assert( bug4065("bb"));
-/**************************************************
- 12689 - assigning via pointer from 'in' expression
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12689
+// assigning via pointer from 'in' expression
int g12689()
{
@@ -2855,9 +2838,9 @@ int ptrSlice()
}
static assert(ptrSlice() == 2);
-/**************************************************
- 6344 - create empty slice from null pointer
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6344
+// create empty slice from null pointer
static assert({
char* c = null;
@@ -2865,18 +2848,18 @@ static assert({
return true;
}());
-/**************************************************
- 8365 - block assignment of enum arrays
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8365
+// block assignment of enum arrays
enum E8365 { first = 7, second, third, fourth }
static assert({ E8365[2] x; return x[0]; }() == E8365.first);
static assert({ E8365[2][2] x; return x[0][0]; }() == E8365.first);
static assert({ E8365[2][2][2] x; return x[0][0][0]; }() == E8365.first);
-/**************************************************
- 4448 - labelled break + continue
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=4448
+// labelled break + continue
int bug4448()
{
@@ -2918,27 +2901,27 @@ L1:
}
static assert(bug4448b() == 3);
-/**************************************************
- 6985 - non-constant case
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6985
+// Formerly, non-constant case, but switch cases with mutable cases now error
+// Currently: run-time constant variable case
int bug6985(int z)
{
- int q = z * 2 - 6;
+ const int q = z * 2 - 6;
switch(z)
{
case q:
- q = 87;
- break;
+ return 87;
default:
}
return q;
}
static assert(bug6985(6) == 87);
-/**************************************************
- 6281 - [CTFE] A null pointer '!is null' returns 'true'
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6281
+// [CTFE] A null pointer '!is null' returns 'true'
static assert(!{
auto p = null;
@@ -2950,9 +2933,9 @@ static assert(!{
return p != null;
}());
-/**************************************************
- 6331 - evaluate SliceExp on if condition
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6331
+// evaluate SliceExp on if condition
bool bug6331(string s)
{
@@ -2962,9 +2945,9 @@ bool bug6331(string s)
}
static assert(bug6331("str"));
-/**************************************************
- 6283 - assign to AA with slice as index
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6283
+// assign to AA with slice as index
static assert({
immutable p = "pp";
@@ -2992,9 +2975,9 @@ static assert({
return true;
}());
-/**************************************************
- 6282 - dereference 'in' of an AA
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6282
+// dereference 'in' of an AA
static assert({
int[] w = new int[4];
@@ -3008,9 +2991,9 @@ static assert({
return n;
}() == "1");
-/**************************************************
- 6337 - member function call on struct literal
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6337
+// member function call on struct literal
struct Bug6337
{
@@ -3027,17 +3010,16 @@ struct Bug6337
}
static assert(Bug6337().ctfe() == 6);
-/**************************************************
- 6603 call manifest function pointer
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6603
+// call manifest function pointer
int f6603(int a) { return a + 5; }
enum bug6603 = &f6603;
static assert(bug6603(6) == 11);
-/**************************************************
- 6375
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6375
struct D6375
{
@@ -3067,9 +3049,9 @@ static assert({
return true;
}());
-/**************************************************
- 6280 Converting pointers to bool
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6280
+// Converting pointers to bool
static assert({
if ((0 in [0:0])) {}
@@ -3077,9 +3059,9 @@ static assert({
return true;
}());
-/**************************************************
- 6276 ~=
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6276
+// ~=
struct Bug6276
{
@@ -3092,9 +3074,9 @@ static assert({
return true;
}());
-/**************************************************
- 6374 ptr[n] = x, x = ptr[n]
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6374
+// ptr[n] = x, x = ptr[n]
static assert({
int[] arr = [1];
@@ -3104,9 +3086,9 @@ static assert({
return arr[0];
}() == 2);
-/**************************************************
- 6306 recursion and local variables
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6306
+// recursion and local variables
void recurse6306()
{
@@ -3124,9 +3106,9 @@ bool bug6306(bool b)
}
static assert(bug6306(true));
-/**************************************************
- 6386 ICE on unsafe pointer cast
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6386
+// ICE on unsafe pointer cast
static assert(!is(typeof(compiles!({
int x = 123;
@@ -3145,9 +3127,9 @@ static assert({
return *q;
}());
-/**************************************************
- 6420 ICE on dereference of invalid pointer
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6420
+// ICE on dereference of invalid pointer
static assert({
// Should compile, but pointer can't be dereferenced
@@ -3202,9 +3184,9 @@ static assert(!is(typeof(compiles!({
}()
))));
-/**************************************************
- 6250 deref pointers to array
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6250
+// deref pointers to array
int[]* simple6250(int[]* x) { return x; }
@@ -3280,9 +3262,9 @@ long ctfeSort6250b()
static assert(ctfeSort6250b() == 57);
-/**************************************************
- 6672 circular references in array
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6672
+// circular references in array
void bug6672(ref string lhs, ref string rhs)
{
@@ -3334,9 +3316,9 @@ static assert({
return true;
}());
-/**************************************************
- 6399 (*p).length = n
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6399
+// (*p).length = n
struct A6399
{
@@ -3354,9 +3336,9 @@ static assert({
return a.subLen();
}() == 4);
-/**************************************************
- 7789 (*p).length++ where *p is null
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7789
+// (*p).length++ where *p is null
struct S7789
{
@@ -3371,9 +3353,9 @@ struct S7789
static assert(S7789().foo());
-/**************************************************
- 6418 member named 'length'
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6418
+// member named 'length'
struct Bug6418
{
@@ -3381,9 +3363,9 @@ struct Bug6418
}
static assert(Bug6418.init.length == 189);
-/**************************************************
- 4021 rehash
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=4021
+// rehash
bool bug4021()
{
@@ -3393,9 +3375,9 @@ bool bug4021()
}
static assert(bug4021());
-/**************************************************
- 11629 crash on AA.rehash
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11629
+// crash on AA.rehash
struct Base11629
{
@@ -3413,10 +3395,11 @@ struct Base11629
}
enum ct11629 = Base11629(4);
-/**************************************************
- 3512 foreach (dchar; string)
- 6558 foreach (int, dchar; string)
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=3512
+// foreach (dchar; string)
+// https://issues.dlang.org/show_bug.cgi?id=6558
+// foreach (int, dchar; string)
bool test3512()
{
@@ -3552,9 +3535,9 @@ bool test3512()
}
static assert(test3512());
-/**************************************************
- 6510 ICE only with -inline
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6510
+// ICE only with -inline
struct Stack6510
{
@@ -3585,9 +3568,9 @@ void test6510()
static assert(bug6510() == 3);
}
-/**************************************************
- 6511 arr[] shouldn't make a copy
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6511
+// arr[] shouldn't make a copy
T bug6511(T)()
{
@@ -3598,9 +3581,9 @@ T bug6511(T)()
static assert(bug6511!ulong() == 2);
static assert(bug6511!long() == 2);
-/**************************************************
- 6512 new T[][]
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6512
+// new T[][]
bool bug6512(int m)
{
@@ -3620,9 +3603,9 @@ bool bug6512(int m)
}
static assert(bug6512(3));
-/**************************************************
- 6516 ICE(constfold.c)
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6516
+// ICE(constfold.c)
dstring bug6516()
{
@@ -3631,9 +3614,9 @@ dstring bug6516()
static assert(bug6516() == ""d);
-/**************************************************
- 6727 ICE(interpret.c)
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6727
+// ICE(interpret.c)
const(char)* ice6727(const(char)* z) { return z; }
static assert({
@@ -3641,9 +3624,9 @@ static assert({
return true;
}());
-/**************************************************
- 6721 Cannot get pointer to start of char[]
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6721
+// Cannot get pointer to start of char[]
static assert({
char[] c1 = "".dup;
@@ -3653,9 +3636,9 @@ static assert({
return 6;
}() == 6);
-/**************************************************
- 6693 Assign to null AA
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6693
+// Assign to null AA
struct S6693
{
@@ -3672,9 +3655,9 @@ static assert({
return 6693;
}() == 6693);
-/**************************************************
- 7602 Segfault AA.keys on null AA
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7602
+// Segfault AA.keys on null AA
string[] test7602()
{
@@ -3684,9 +3667,9 @@ string[] test7602()
enum bug7602 = test7602();
-/**************************************************
- 6739 Nested AA assignment
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6739
+// Nested AA assignment
static assert({
int[int][int][int] aaa;
@@ -3703,9 +3686,9 @@ static assert({
return kk;
}() == 9);
-/**************************************************
- 6751 ref AA assignment
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6751
+// ref AA assignment
void bug6751(ref int[int] aa)
{
@@ -3763,9 +3746,9 @@ void bug6751c(ref int[int][int] aa)
aa = [38: [56 : 77]];
}
-/**************************************************
- 7790 AA foreach ref
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7790
+// AA foreach ref
struct S7790
{
@@ -3781,18 +3764,18 @@ size_t bug7790(S7790[string] tree)
static assert(bug7790(["a":S7790(0)]) == 1);
-/**************************************************
- 6765 null AA.length
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6765
+// null AA.length
static assert({
int[int] w;
return w.length;
}() == 0);
-/**************************************************
- 6769 AA.keys, AA.values with -inline
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6769
+// AA.keys, AA.values with -inline
static assert({
double[char[3]] w = ["abc" : 2.3];
@@ -3800,9 +3783,9 @@ static assert({
return w.keys.length;
}() == 1);
-/**************************************************
- 4022 AA.get
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=4022
+// AA.get
static assert({
int[int] aa = [58: 13];
@@ -3812,9 +3795,9 @@ static assert({
return r;
}() == 1000);
-/**************************************************
- 6775 AA.opApply
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6775
+// AA.opApply
static assert({
int[int] aa = [58: 17, 45:6];
@@ -3844,9 +3827,9 @@ static assert({
return true;
}());
-/**************************************************
- 7890 segfault struct with AA field
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7890
+// segfault struct with AA field
struct S7890
{
@@ -3907,9 +3890,9 @@ static assert({
return true;
}());
-/**************************************************
- 6800 bad pointer casts
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6800
+// bad pointer casts
bool badpointer(int k)
{
@@ -3974,9 +3957,9 @@ static assert(!is(typeof(compiles!(badpointer(6)))));
static assert(!is(typeof(compiles!(badpointer(7)))));
static assert(!is(typeof(compiles!(badpointer(8)))));
-/**************************************************
- 10211 Allow casts S**->D**, when S*->D* is OK
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10211
+// Allow casts S**->D**, when S*->D* is OK
int bug10211()
{
@@ -3991,9 +3974,9 @@ int bug10211()
static assert(bug10211());
-/**************************************************
- 10568 CTFE rejects function pointer safety casts
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10568
+// CTFE rejects function pointer safety casts
@safe void safetyDance() {}
@@ -4006,9 +3989,9 @@ int isItSafeToDance()
static assert(isItSafeToDance());
-/**************************************************
- 12296 CTFE rejects const compatible AA pointer cast
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12296
+// CTFE rejects const compatible AA pointer cast
int test12296()
{
@@ -4019,9 +4002,9 @@ int test12296()
}
static assert(test12296());
-/**************************************************
- 9170 Allow reinterpret casts float<->int
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=9170
+// Allow reinterpret casts float<->int
int f9170(float x)
{
@@ -4077,9 +4060,9 @@ bool bug9170()
static assert(bug9170());
-/**************************************************
- 6792 ICE with pointer cast of indexed array
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6792
+// ICE with pointer cast of indexed array
struct S6792
{
@@ -4139,9 +4122,9 @@ static assert({
return true;
}());
-/**************************************************
- 7780 array cast
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7780
+// array cast
int bug7780(int testnum)
{
@@ -4164,9 +4147,9 @@ static assert( is(typeof(compiles!(bug7780(0)))));
static assert(!is(typeof(compiles!(bug7780(1)))));
static assert(!is(typeof(compiles!(bug7780(2)))));
-/**************************************************
- 14028 - static array pointer that refers existing array elements.
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=14028
+// static array pointer that refers existing array elements.
int test14028a(size_t ofs)(bool ct)
{
@@ -4244,9 +4227,9 @@ static assert(!is(typeof(compiles!(test14028b(3)))));
static assert(test14028b(4));
static assert(!is(typeof(compiles!(test14028b(5)))));
-/**************************************************
- 10275 cast struct literals to immutable
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10275
+// cast struct literals to immutable
struct Bug10275
{
@@ -4266,9 +4249,9 @@ int test10275()
static assert(test10275());
-/**************************************************
- 6851 passing pointer by argument
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6851
+// passing pointer by argument
void set6851(int* pn)
{
@@ -4284,9 +4267,8 @@ void bug6851()
}
static assert({ bug6851(); return true; }());
-/**************************************************
- 7876
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7876
int* bug7876(int n) @system
{
@@ -4328,9 +4310,8 @@ static assert(!is(typeof(compiles!(test7876(0)))));
static assert( is(typeof(compiles!(test7876(11)))));
static assert(!is(typeof(compiles!(test7876(10)))));
-/**************************************************
- 11824
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11824
int f11824(T)()
{
@@ -4345,9 +4326,9 @@ int f11824(T)()
static assert(f11824!int()); // OK
static assert(f11824!(int[])()); // OK <- NG
-/**************************************************
- 6817 if converted to &&, only with -inline
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6817
+// if converted to &&, only with -inline
static assert({
void toggle()
@@ -4369,9 +4350,9 @@ static assert({
return true;
}());
-/**************************************************
- 6816 nested function can't access this
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6816
+// nested function can't access this
struct S6816
{
@@ -4384,9 +4365,9 @@ struct S6816
enum s6816 = S6816().foo();
-/**************************************************
- 7277 ICE nestedstruct.init.tupleof
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7277
+// ICE nestedstruct.init.tupleof
struct Foo7277
{
@@ -4406,9 +4387,9 @@ struct Foo7277
static assert(Foo7277().func() == 17);
-/**************************************************
- 10217 ICE. CTFE version of 9315
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10217
+// ICE. CTFE version of 9315
bool bug10217()
{
@@ -4424,9 +4405,9 @@ bool bug10217()
static assert(bug10217());
-/**************************************************
- 8276 ICE
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8276
+// ICE
void bug8676(int n)
{
@@ -4525,7 +4506,7 @@ auto classtest1(int n)
}
static assert(classtest1(1));
static assert(classtest1(2));
-static assert(classtest1(7)); // bug 7154
+static assert(classtest1(7)); // https://issues.dlang.org/show_bug.cgi?id=7154
// can't initialize enum with not null class
SomeClass classtest2(int n)
@@ -4555,9 +4536,9 @@ int classtest3()
static assert(classtest3());
-/**************************************************
- 12016 class cast and qualifier reinterpret
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12016
+// class cast and qualifier reinterpret
class B12016 { }
@@ -4571,9 +4552,9 @@ bool f12016(immutable B12016 b)
static assert(f12016(new immutable C12016));
-/**************************************************
- 10610 ice immutable implicit conversion
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10610
+// ice immutable implicit conversion
class Bug10610(T)
{
@@ -4590,9 +4571,9 @@ void ice10610()
static assert (T10610.min.baz());
}
-/**************************************************
- 13141 regression fix caused by 10610
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=13141
+// regression fix caused by 10610
struct MapResult13141(alias pred)
{
@@ -4613,24 +4594,24 @@ string[] array13141(R)(R r)
//immutable string[] splitterNames = [4].map!(e => "4").array();
immutable string[] splitterNames13141 = MapResult13141!(e => "4")([4]).array13141();
-/**************************************************
- 11587 AA compare
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11587
+// AA compare
static assert([1:2, 3:4] == [3:4, 1:2]);
-/**************************************************
- 14325 more AA comparisons
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=14325
+// more AA comparisons
static assert([1:1] != [1:2, 2:1]); // OK
static assert([1:1] != [1:2]); // OK
static assert([1:1] != [2:1]); // OK <- Error
static assert([1:1, 2:2] != [3:3, 4:4]); // OK <- Error
-/**************************************************
- 7147 typeid()
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7147
+// typeid()
static assert({
TypeInfo xxx = typeid(Object);
@@ -4650,9 +4631,9 @@ static assert(!is(typeof(compiles!(bug7147(0)))));
static assert( is(typeof(compiles!(bug7147(1)))));
-/**************************************************
- 14123 - identity TypeInfo objects
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=14123
+// identity TypeInfo objects
static assert({
bool eq(TypeInfo t1, TypeInfo t2)
@@ -4679,9 +4660,9 @@ static assert({
return 1;
}());
-/**************************************************
- 6885 wrong code with new array
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6885
+// wrong code with new array
struct S6885
{
@@ -4704,9 +4685,9 @@ int bug6885()
static assert(bug6885());
-/**************************************************
- 6886 ICE with new array of dynamic arrays
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6886
+// ICE with new array of dynamic arrays
int bug6886()
{
@@ -4719,13 +4700,13 @@ int bug6886()
static assert(bug6886());
-/**************************************************
- 10198 Multidimensional struct block initializer
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10198
+// Multidimensional struct block initializer
struct Block10198
{
- int val[3][4];
+ int[4][3] val;
}
int bug10198()
@@ -4737,9 +4718,9 @@ int bug10198()
}
static assert(bug10198());
-/**************************************************
- 14440 Multidimensional block initialization should create distinct arrays for each elements
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=14440
+// Multidimensional block initialization should create distinct arrays for each elements
struct Matrix14440(E, size_t row, size_t col)
{
@@ -5112,9 +5093,9 @@ int testsFromEH()
}
static assert(testsFromEH());
-/**************************************************
- With + synchronized statements + bug 6901
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6901
+// With + synchronized statements
struct With1
{
@@ -5197,9 +5178,9 @@ int testwith()
static assert(testwith());
-/**************************************************
- 9236 ICE switch with(EnumType)
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=9236
+// ICE switch with(EnumType)
enum Command9236
{
@@ -5231,9 +5212,9 @@ bool bug9236(Command9236 cmd)
static assert(bug9236(Command9236.Any));
-/**************************************************
- 6416 static struct declaration
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6416
+// static struct declaration
static assert({
static struct S { int y = 7; }
@@ -5243,18 +5224,18 @@ static assert({
return true;
}());
-/**************************************************
- 10499 static template struct declaration
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10499
+// static template struct declaration
static assert({
static struct Result() {}
return true;
}());
-/**************************************************
- 13757 extern(C) alias declaration
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=13757
+// extern(C) alias declaration
static assert({
alias FP1 = extern(C) int function();
@@ -5262,9 +5243,9 @@ static assert({
return true;
}());
-/**************************************************
- 6522 opAssign + foreach ref
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6522
+// opAssign + foreach ref
struct Foo6522
{
@@ -5285,9 +5266,9 @@ bool foo6522()
static assert(foo6522());
-/**************************************************
- 7245 pointers + foreach ref
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7245
+// pointers + foreach ref
int bug7245(int testnum)
{
@@ -5311,11 +5292,13 @@ int bug7245(int testnum)
static assert(bug7245(0) == 6);
static assert(bug7245(1) == 5);
-/**************************************************
- 8498 modifying foreach
- 7658 foreach ref
- 8539 nested funcs, ref param, -inline
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8498
+// modifying foreach
+// https://issues.dlang.org/show_bug.cgi?id=7658
+// foreach ref
+// https://issues.dlang.org/show_bug.cgi?id=8539
+// nested funcs, ref param, -inline
int bug8498()
{
@@ -5356,9 +5339,11 @@ int bug8539()
static assert(bug8539());
-/**************************************************
- 7874, 13297, 13740 - better lvalue handling
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7874
+// https://issues.dlang.org/show_bug.cgi?id=13297
+// https://issues.dlang.org/show_bug.cgi?id=13740
+// better lvalue handling
int bug7874(int x){ return ++x = 1; }
static assert(bug7874(0) == 1);
@@ -5399,9 +5384,8 @@ static assert({
return true;
}());
-/**************************************************
- 6919
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6919
void bug6919(int* val)
{
@@ -5428,9 +5412,8 @@ void test6919b()
}
static assert({ test6919b(); return true; }());
-/**************************************************
- 6995
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6995
struct Foo6995
{
@@ -5442,9 +5425,9 @@ struct Foo6995
static assert(Foo6995.index!(27)() == 27);
-/**************************************************
- 7043 ref with -inline
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7043
+// ref with -inline
int bug7043(S)(ref int x)
{
@@ -5456,9 +5439,9 @@ static assert({
return bug7043!(char)(i);
}() == 416);
-/**************************************************
- 6037 recursive ref
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6037
+// recursive ref
void bug6037(ref int x, bool b)
{
@@ -5484,9 +5467,9 @@ int bug6037outer()
static assert(bug6037outer() == 401);
-/**************************************************
- 14299 - [REG2.067a], more than one depth of recursive call with ref
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=14299
+// [REG2.067a], more than one depth of recursive call with ref
string gen14299(int max, int idx, ref string name)
{
@@ -5512,9 +5495,9 @@ static assert(test14299(3) == "01233210");
static assert(test14299(4) == "0123443210");
static assert(test14299(5) == "012345543210");
-/**************************************************
- 7940 wrong code for complicated assign
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7940
+// wrong code for complicated assign
struct Bug7940
{
@@ -5539,9 +5522,9 @@ int bug7940()
static assert(bug7940());
-/**************************************************
- 10298 wrong code for struct array literal init
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10298
+// wrong code for struct array literal init
struct Bug10298
{
@@ -5563,9 +5546,9 @@ int bug10298()
static assert(bug10298());
-/**************************************************
- 7266 dotvar ref parameters
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7266
+// dotvar ref parameters
struct S7266 { int a; }
@@ -5594,9 +5577,9 @@ void out7266(out int b)
static assert(bug7266());
-/**************************************************
- 9982 dotvar assign through pointer
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=9982
+// dotvar assign through pointer
struct Bug9982
{
@@ -5614,7 +5597,8 @@ int test9982()
static assert(test9982());
-// 9982, rejects-valid case
+// https://issues.dlang.org/show_bug.cgi?id=9982
+// rejects-valid case
struct SS9982
{
@@ -5635,9 +5619,9 @@ void emplace9982(Bug9982* chunk, Bug9982 arg)
enum s9982 = Bug9982(3);
enum p9982 = SS9982(s9982);
-/**************************************************
- 11618 dotvar assign through casted pointer
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11618
+// dotvar assign through casted pointer
struct Tuple11618(T...)
{
@@ -5652,9 +5636,9 @@ static assert({
return (result[0] == dchar.init);
}());
-/**************************************************
- 7143 'is' for classes
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7143
+// 'is' for classes
class C7143
{
@@ -5708,9 +5692,9 @@ static assert(bug7143(4) == 48);
static assert(bug7143(5) == 48);
static assert(bug7143(6) == 188);
-/**************************************************
- 7147 virtual function calls from base class
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7147
+// virtual function calls from base class
class A7147
{
@@ -5735,9 +5719,8 @@ int test7147()
static assert(test7147() == 1);
-/**************************************************
- 7158
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7158
class C7158
{
@@ -5755,9 +5738,8 @@ bool test7158()
}
static assert(test7158());
-/**************************************************
- 8484
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8484
class C8484
{
@@ -5783,9 +5765,8 @@ int test8484()
}
static assert(test8484() == 7);
-/**************************************************
- 7419
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7419
struct X7419
{
@@ -5805,9 +5786,9 @@ void bug7419()
static assert(x == 3);
}
-/**************************************************
- 9445 ice
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=9445
+// ice
template c9445(T...) { }
@@ -5817,9 +5798,9 @@ void ice9445(void delegate() expr, void function() f2)
static assert(!is(typeof(c9445!(expr()))));
}
-/**************************************************
- 10452 delegate ==
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10452
+// delegate ==
struct S10452
{
@@ -5836,7 +5817,7 @@ class C10452
bool func() { return true; }
}
-bool delegate() ref10452(ref S10452 s)
+bool delegate() ref10452(return ref S10452 s)
{
return &s.func;
}
@@ -5884,9 +5865,9 @@ bool test10452()
}
static assert(test10452());
-/**************************************************
- 7162 and 4711
-**************************************************/
+/**************************************************/
+//https://issues.dlang.org/show_bug.cgi?id=7162
+// https://issues.dlang.org/show_bug.cgi?id=4711
void f7162() { }
@@ -5894,16 +5875,16 @@ bool ice7162()
{
false && f7162();
false || f7162();
- false && f7162(); // bug 4711
+ false && f7162(); // https://issues.dlang.org/show_bug.cgi?id=4711
true && f7162();
return true;
}
static assert(ice7162());
-/**************************************************
- 8857, only with -inline (creates an &&)
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8857
+// only with -inline (creates an &&)
struct Result8857 { char[] next; }
@@ -5921,9 +5902,8 @@ static assert({
return true;
}());
-/**************************************************
- 7527
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7527
struct Bug7527
{
@@ -5940,9 +5920,8 @@ int bug7527()
static assert(!is(typeof(compiles!(bug7527()))));
-/**************************************************
- 7527
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7527
int bug7380;
@@ -5952,9 +5931,8 @@ static assert(!is(typeof( compiles!(
}()
))));
-/**************************************************
- 7165
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7165
struct S7165
{
@@ -5964,9 +5942,8 @@ struct S7165
static assert(!S7165().f());
-/**************************************************
- 7187
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7187
int[] f7187() { return [0]; }
int[] f7187b(int n) { return [0]; }
@@ -5997,9 +5974,9 @@ bool g7187c(const(int)[] r)
static assert(g7187c(f7187c()));
-/**************************************************
- 6933 struct destructors
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6933
+// struct destructors
struct Bug6933
{
@@ -6016,9 +5993,8 @@ int test6933()
static assert(test6933());
-/**************************************************
- 7197
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7197
int foo7197(int[] x...)
{
@@ -6046,9 +6022,8 @@ bool testEScmp()
static assert(testEScmp());
-/**************************************************
- 7667
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7667
bool baz7667(int[] vars...)
{
@@ -6071,9 +6046,8 @@ bool bug7667()
}
enum e7667 = bug7667();
-/**************************************************
- 7536
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7536
bool bug7536(string expr)
{
@@ -6086,9 +6060,9 @@ void vop()
static assert(bug7536(x7536));
}
-/**************************************************
- 6681 unions
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6681
+// unions
struct S6681
{
@@ -6130,9 +6104,9 @@ static assert(!is(typeof(compiles!(bug6681(1)))));
static assert(!is(typeof(compiles!(bug6681(3)))));
static assert(!is(typeof(compiles!(bug6681(4)))));
-/**************************************************
- 9113 ICE with struct in union
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=9113
+// ICE with struct in union
union U9113
{
@@ -6170,9 +6144,9 @@ int uniontest1()
static assert(uniontest1());
-/**************************************************
- 6438 void
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=6438
+// void
struct S6438
{
@@ -6209,9 +6183,9 @@ static assert( is(typeof(compiles!(bug6438(1)))));
static assert(!is(typeof(compiles!(bug6438(2)))));
static assert(!is(typeof(compiles!(bug6438(3)))));
-/**************************************************
- 10994 void static array members
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10994
+// void static array members
struct Bug10994
{
@@ -6220,9 +6194,9 @@ struct Bug10994
static bug10994 = Bug10994.init;
-/**************************************************
- 10937 struct inside union
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10937
+// struct inside union
struct S10937
{
@@ -6247,9 +6221,8 @@ struct S10937
enum test10937 = S10937(7);
enum west10937 = S10937(2);
-/**************************************************
- 13831
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=13831
struct Vector13831()
{
@@ -6276,9 +6249,8 @@ struct Chunk13831
static const Chunk13831* unknownChunk = new Chunk13831(Coord13831());
}
-/**************************************************
- 7732
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7732
struct AssociativeArray
{
@@ -6299,9 +6271,8 @@ int test7732()
static assert(test7732());
-/**************************************************
- 7784
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7784
struct Foo7784
{
void bug()
@@ -6329,15 +6300,13 @@ bool ctfe7784()
static assert(ctfe7784());
-/**************************************************
- 7781
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7781
-static assert(({ return; }(), true));
+static assert(({ return true; }()));
-/**************************************************
- 7785
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7785
bool bug7785(int n)
{
@@ -6359,9 +6328,8 @@ static assert(bug7785(1));
static assert(!is(typeof(compiles!(bug7785(2)))));
static assert(!is(typeof(compiles!(bug7785(3)))));
-/**************************************************
- 7987
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7987
class C7987
{
@@ -6400,9 +6368,9 @@ bool bug7987()
static assert(bug7987());
-/**************************************************
- 10579 typeinfo.func() must not segfault
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10579
+// typeinfo.func() must not segfault
static assert(!is(typeof(compiles!(typeid(int).toString.length))));
@@ -6414,9 +6382,9 @@ Bug10579 uninitialized10579;
static assert(!is(typeof(compiles!(uninitialized10579.foo()))));
-/**************************************************
- 10804 mixin ArrayLiteralExp typed string
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10804
+// mixin ArrayLiteralExp typed string
void test10804()
{
@@ -6476,7 +6444,7 @@ C73 test73 = func73();
struct S74
{
- int n[1];
+ int[1] n;
static S74 test(){ S74 ret = void; ret.n[0] = 0; return ret; }
}
@@ -6509,7 +6477,7 @@ label:
break label; // doesn't work.
}
}
-body
+do
{
int x = 0;
label:
@@ -6526,7 +6494,8 @@ label:
static assert(bug8865());
/******************************************************/
-// 15450 labeled foreach + continue/break
+// https://issues.dlang.org/show_bug.cgi?id=15450
+// labeled foreach + continue/break
static assert({
L1:
@@ -6590,7 +6559,8 @@ static assert( __traits(compiles, { static const Test76 t76 = new const(Test
static assert( __traits(compiles, { static immutable Test76 t76 = new immutable Test76(0); return t76; }));
static assert(!__traits(compiles, { static Test76 t76 = new Test76(0); return t76; }));
-/***** Bug 5678 *********************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5678
struct Bug5678
{
@@ -6599,9 +6569,9 @@ struct Bug5678
static assert(!__traits(compiles, { enum const(Bug5678)* b5678 = new const(Bug5678)(0); return b5678; }));
-/**************************************************
- 10782 run semantic2 for class field
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10782
+// run semantic2 for class field
enum e10782 = 0;
class C10782 { int x = e10782; }
@@ -6612,9 +6582,9 @@ string f10782()
}
mixin(f10782());
-/**************************************************
- 10929 NRVO support in CTFE
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10929
+// NRVO support in CTFE
struct S10929
{
@@ -6646,9 +6616,9 @@ bool test10929()
};
static assert(test10929());
-/**************************************************
- 9245 - support postblit call on array assignments
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=9245
+// support postblit call on array assignments
bool test9245()
{
@@ -6712,9 +6682,9 @@ bool test9245()
}
static assert(test9245());
-/**************************************************
- 12906 don't call postblit on blit initializing
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12906
+// don't call postblit on blit initializing
struct S12906 { this(this) { assert(0); } }
@@ -6723,9 +6693,9 @@ static assert({
return true;
}());
-/**************************************************
- 11510 support overlapped field access in CTFE
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11510
+// support overlapped field access in CTFE
struct S11510
{
@@ -6750,9 +6720,9 @@ bool test11510()
}
static assert(test11510());
-/**************************************************
- 11534 - subtitude inout
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11534
+// subtitude inout
struct MultiArray11534
{
@@ -6776,9 +6746,9 @@ enum test11534 = () {
return 0;
}();
-/**************************************************
- 11941 - Regression of 11534 fix
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11941
+// Regression of 11534 fix
void takeConst11941(const string[]) {}
string[] identity11941(string[] x) { return x; }
@@ -6808,9 +6778,9 @@ bool test11941b()
}
static assert(test11941b());
-/**************************************************
- 11535 - element-wise assignment from string to ubyte array literal
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11535
+// element-wise assignment from string to ubyte array literal
struct Hash11535
{
@@ -6834,33 +6804,12 @@ auto md5_digest11535(T...)(scope const T data)
static assert(md5_digest11535(`TEST`) == [84, 69, 83, 84, 0, 0]);
-/**************************************************
- 11540 - goto label + try-catch-finally / with statement
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11540
+// goto label + try-catch-finally / with statement
static assert(()
{
- // enter to TryCatchStatement.body
- {
- bool c = false;
- try
- {
- if (c) // need to bypass front-end optimization
- throw new Exception("");
- else
- {
- goto Lx;
- L1:
- c = true;
- }
- }
- catch (Exception e) {}
-
- Lx:
- if (!c)
- goto L1;
- }
-
// jump inside TryCatchStatement.body
{
bool c = false;
@@ -6952,37 +6901,6 @@ static assert(()
static assert(()
{
- // enter forward to TryFinallyStatement.body
- {
- bool c = false;
- goto L0;
- c = true;
- try
- {
- L0:
- ;
- }
- finally {}
- assert(!c);
- }
-
- // enter back to TryFinallyStatement.body
- {
- bool c = false;
- try
- {
- goto Lx;
- L1:
- c = true;
- }
- finally {
- }
-
- Lx:
- if (!c)
- goto L1;
- }
-
// jump inside TryFinallyStatement.body
{
try
@@ -7055,9 +6973,9 @@ static assert(()
return 1;
}());
-/**************************************************
- 11627 - cast dchar to char at compile time on AA assignment
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11627
+//cast dchar to char at compile time on AA assignment
bool test11627()
{
@@ -7071,9 +6989,9 @@ bool test11627()
}
static assert(test11627());
-/**************************************************
- 11664 - ignore function local static variables
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11664
+// ignore function local static variables
bool test11664()
{
@@ -7083,9 +7001,9 @@ bool test11664()
}
static assert(test11664());
-/**************************************************
- 12110 - operand of dereferencing does not need to be an lvalue
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12110
+// operand of dereferencing does not need to be an lvalue
struct SliceOverIndexed12110
{
@@ -7117,9 +7035,9 @@ struct Uint24Array12110
static m12110 = Uint24Array12110([0x80]);
-/**************************************************
- 12310 - heap allocation for built-in sclar types
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12310
+// heap allocation for built-in sclar types
bool test12310()
{
@@ -7141,9 +7059,9 @@ bool test12310()
}
static assert(test12310());
-/**************************************************
- 12499 - initialize TupleDeclaraion in CTFE
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12499
+// initialize TupleDeclaraion in CTFE
auto f12499()
{
@@ -7153,9 +7071,9 @@ auto f12499()
}
static assert(f12499() == 5);
-/**************************************************
- 12602 - slice in struct literal members
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12602
+// slice in struct literal members
struct Result12602
{
@@ -7251,9 +7169,9 @@ static assert(testWrap12602b() == [1,2,1,2]);
static assert(testWrap12602c() == [1,2,1,2]);
static assert(testWrap12602d() == [1,2,1,2]);
-/**************************************************
- 12677 - class type initializing from DotVarExp
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12677
+// class type initializing from DotVarExp
final class C12677
{
@@ -7272,9 +7190,9 @@ struct S12677
auto f = new C12677();
}
-/**************************************************
- 12851 - interpret function local const static array
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12851
+// interpret function local const static array
void test12851()
{
@@ -7282,9 +7200,9 @@ void test12851()
alias staticZip = TypeTuple!(arr[0]);
}
-/**************************************************
- 13630 - indexing and setting array element via pointer
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=13630
+// indexing and setting array element via pointer
struct S13630(T)
{
@@ -7303,15 +7221,14 @@ struct S13630(T)
enum s13630 = S13630!float(1);
-/**************************************************
- 13827
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=13827
struct Matrix13827(T, uint N)
{
private static defaultMatrix()
{
- T arr[N];
+ T[N] arr;
return arr;
}
@@ -7331,9 +7248,9 @@ struct Matrix13827(T, uint N)
}
enum m13827 = Matrix13827!(int, 3)(1, 2, 3);
-/**************************************************
- 13847 - support DotTypeExp
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=13847
+// support DotTypeExp
class B13847
{
@@ -7378,9 +7295,9 @@ static assert({
return true;
}());
-/**************************************************
- 12495 - cast from string to immutable(ubyte)[]
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12495
+// cast from string to immutable(ubyte)[]
string getStr12495()
{
@@ -7401,9 +7318,9 @@ auto indexOf12495(string s)
}
static assert(indexOf12495(getStr12495()) == 0);
-/**************************************************
- 13992 - Repainting pointer arithmetic result
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=13992
+// Repainting pointer arithmetic result
enum hash13992 = hashOf13992("abcd".ptr);
@@ -7416,9 +7333,9 @@ enum hash13992 = hashOf13992("abcd".ptr);
return hash;
}
-/**************************************************
- 13739 - Precise copy for ArrayLiteralExp elements
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=13739
+// Precise copy for ArrayLiteralExp elements
static assert(
{
@@ -7436,9 +7353,9 @@ static assert(
return 1;
}());
-/**************************************************
- 14463 - ICE on slice assignment without postblit
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=14463
+// ICE on slice assignment without postblit
struct Boo14463
{
@@ -7450,9 +7367,9 @@ struct Boo14463
}
immutable Boo14463 a14463 = Boo14463([1]);
-/**************************************************
- 13295 - Don't copy struct literal in VarExp::interpret()
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=13295
+// Don't copy struct literal in VarExp::interpret()
struct S13295
{
@@ -7483,9 +7400,9 @@ int foo14061(int[] a)
}
static assert(foo14061([1]));
-/**************************************************
- 14024 - CTFE version
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=14024
+// CTFE version
bool test14024()
{
@@ -7535,9 +7452,9 @@ bool test14024()
}
static assert(test14024());
-/**************************************************
- 14304 - cache of static immutable value
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=14304
+// cache of static immutable value
immutable struct Bug14304
{
@@ -7565,9 +7482,9 @@ void test14304()
static assert(bt == "fun");
}
-/**************************************************
- 14371 - evaluate BinAssignExp as lvalue
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=14371
+// evaluate BinAssignExp as lvalue
int test14371()
{
@@ -7577,9 +7494,9 @@ int test14371()
}
static assert(test14371() == 2);
-/**************************************************
- 7151 - [CTFE] cannot compare classes with ==
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7151
+// [CTFE] cannot compare classes with ==
bool test7151()
{
@@ -7589,9 +7506,9 @@ bool test7151()
static assert(test7151());
-/**************************************************
- 12603 - [CTFE] goto does not correctly call dtors
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12603
+// [CTFE] goto does not correctly call dtors
struct S12603
{
@@ -7702,9 +7619,9 @@ auto structInCaseScope()
static assert(!structInCaseScope());
-/**************************************************
- 15233 - ICE in TupleExp, Copy On Write bug
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15233
+// ICE in TupleExp, Copy On Write bug
alias TT15233(stuff ...) = stuff;
@@ -7713,23 +7630,23 @@ enum tup15233 = TT15233!(Tok15233(), "foo");
static assert(tup15233[0] == Tok15233());
static assert(tup15233[1] == "foo");
-/**************************************************
- 15251 - void cast in ForStatement.increment
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15251
+// void cast in ForStatement.increment
int test15251()
{
for (ubyte lwr = 19;
lwr != 20;
- cast(void)++lwr) // have to to be evaluated with ctfeNeedNothing
+ cast(void)++lwr) // have to to be evaluated with CTFEGoal.Nothing
{}
return 1;
}
static assert(test15251());
-/**************************************************
- 15998 - Sagfault caused by memory corruption
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15998
+// Sagfault caused by memory corruption
immutable string[2] foo15998 = ["",""];
immutable string[2][] bar15998a = foo15998 ~ baz15998;
@@ -7744,9 +7661,9 @@ auto baz15998()
static assert(bar15998a == [["", ""]]);
static assert(bar15998b == [["", ""]]);
-/**************************************************
- 16094 - Non-overlapped slice assignment on an aggregate
-**************************************************/
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=16094
+// Non-overlapped slice assignment on an aggregate
char[] f16094a()
{
@@ -7787,6 +7704,94 @@ struct RBNode(T)
static assert(!__traits(compiles, { alias bug18057 = RBNode!int; }));
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19140
+
+void test19140()
+{
+ real f19140();
+ static if (__traits(compiles, (){ enum real r = f19140(); })) {}
+}
+
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19074
+
+struct S19074a { }
+
+struct S19074b
+{
+ S19074a field;
+ this(S19074a) { }
+
+ static const S19074b* data = new S19074b(S19074a());
+}
+
+void test19074()
+{
+ auto var = S19074b.data;
+}
+
+/************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19447
+
+bool f19447()
+{
+ int[3] c=1;
+ assert(c[0]==1);
+ g19447(c[0..2]);
+ assert(c[0]!=1); //fails
+ assert(c[0]==2);
+ return true;
+}
+void g19447(ref int[2] a)
+{
+ int[2] b=2;
+ a=b;
+ //a[]=b; // works
+ //a[] = b[]; // works
+ assert(a[0]==2);
+}
+static assert(f19447());
+
+/***/
+
+char[] mangle19447(char[] dst)
+{
+ dst.length = 10;
+ size_t i = "_D".length;
+ dst[0 .. i] = "_D";
+ return dst;
+}
+
+static char[] x19447 = mangle19447(null);
+
+/***/
+enum KindEnum
+{
+ integer,
+ arrayOf
+}
+
+struct FullKind
+{
+ KindEnum[] contents;
+
+ this(KindEnum ) { opAssign; }
+
+ this(KindEnum , FullKind contentKind)
+ {
+ contents = contentKind.contents;
+ }
+
+ void opAssign()
+ {
+ contents = [];
+ }
+}
+
+enum fk = FullKind(KindEnum.integer);
+enum fk2 = FullKind(KindEnum.arrayOf, fk);
+
/************************************************/
// https://issues.dlang.org/show_bug.cgi?id=9937
diff --git a/gcc/testsuite/gdc.test/compilable/interpret4.d b/gcc/testsuite/gdc.test/compilable/interpret4.d
new file mode 100644
index 0000000..019ff22
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/interpret4.d
@@ -0,0 +1,31 @@
+// https://issues.dlang.org/show_bug.cgi?id=11717
+
+enum int[4] A = [1,2,3,4];
+enum int[4] B = [1,2,3,4];
+enum int[4] C = A[] + B[];
+static assert(C == [2, 4, 6, 8]);
+
+enum int[2] D1 = A[1..3] * B[2..4];
+static assert(D1 == [6, 12]);
+
+enum int[2] D2 = A[1..3] * 6;
+static assert(D2 == [12, 18]);
+
+enum int[2] D3 = 5 - A[1..3];
+static assert(D3 == [3, 2]);
+
+enum int[2][2] D4 = [D1, D2] + [D2, D3];
+static assert(D4 == [[18, 30], [15, 20]]);
+
+enum int[2][2] D5 = [[18, 30], [15, 20]] + [12, 18];
+static assert(D5 == [[30, 48], [27, 38]]);
+
+import core.simd;
+
+static if (__traits(compiles, int4))
+{
+ enum int4 D = [1,2,3,4];
+ enum int4 E = [1,2,3,4];
+ enum int4 F = D * E;
+ static assert(F.array == [1, 4, 9, 16]);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/isZeroInit.d b/gcc/testsuite/gdc.test/compilable/isZeroInit.d
index b5423cf..a64420f 100644
--- a/gcc/testsuite/gdc.test/compilable/isZeroInit.d
+++ b/gcc/testsuite/gdc.test/compilable/isZeroInit.d
@@ -72,7 +72,9 @@ struct S5
}
static assert(__traits(isZeroInit, S5));
-version(D_SIMD):
-import core.simd : int4;
-static assert(__traits(isZeroInit, Holder!(int4, 0)));
-static assert(!__traits(isZeroInit, Holder!(int4, 1)));
+template Vector(T) { alias __vector(T) Vector; }
+static if (is(Vector!(int[4])))
+{
+ static assert(__traits(isZeroInit, Holder!(Vector!(int[4]), 0)));
+ static assert(!__traits(isZeroInit, Holder!(Vector!(int[4]), 1)));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/isreturnonstack.d b/gcc/testsuite/gdc.test/compilable/isreturnonstack.d
index 8bdb97d..920f0ec 100644
--- a/gcc/testsuite/gdc.test/compilable/isreturnonstack.d
+++ b/gcc/testsuite/gdc.test/compilable/isreturnonstack.d
@@ -1,3 +1,4 @@
+
struct S { int[10] a; }
int test1();
S test2();
diff --git a/gcc/testsuite/gdc.test/compilable/issue12520.d b/gcc/testsuite/gdc.test/compilable/issue12520.d
new file mode 100644
index 0000000..9007724
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue12520.d
@@ -0,0 +1,21 @@
+module issue12520;
+
+// https://issues.dlang.org/show_bug.cgi?id=12520
+
+alias Seq(T...) = T;
+
+static assert( Seq!() == Seq!() );
+static assert( Seq!(1) == Seq!(1) );
+
+static assert((Seq!() != Seq!()) == false);
+static assert((Seq!(1) != Seq!(1)) == false);
+
+static assert( Seq!() != Seq!(1) );
+static assert( Seq!(1) != Seq!() );
+static assert( Seq!(0) != Seq!(1) );
+static assert( Seq!(0,1) != Seq!() );
+
+static assert((Seq!() == Seq!(1)) == false);
+static assert((Seq!(1) == Seq!()) == false);
+static assert((Seq!(0) == Seq!(1)) == false);
+static assert((Seq!(0,1) == Seq!()) == false);
diff --git a/gcc/testsuite/gdc.test/compilable/issue15478.d b/gcc/testsuite/gdc.test/compilable/issue15478.d
new file mode 100644
index 0000000..ad24e7f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue15478.d
@@ -0,0 +1,55 @@
+////////////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=15478
+
+void test15478_1()
+{
+ struct Foo(N)
+ {
+ this(N value) { }
+ static int bug() { return 0; }
+ }
+ enum Foo!int foo = 0;
+ Foo!int[foo.bug] bar;
+}
+
+void test15478_2()
+{
+ int getLength() { return 42; }
+ struct Get {static int length() { return 42; }}
+
+ int[getLength] i1;
+ int[Get.length] i2;
+ static assert (is(typeof(i1) == int[42]));
+ static assert (is(typeof(i2) == int[42]));
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=21870
+struct S21870
+{
+ @property size_t count() const
+ {
+ return 1;
+ }
+}
+
+int[S21870.init.count()] x; // OK
+int[S21870.init.count ] y; // error
+
+////////////////////////////////////////////////////////////////////////////////
+
+struct Foo15478(N)
+{
+ this(N value) { }
+ auto bug() { return 0; }
+}
+
+void test15478_3()
+{
+ enum Foo15478!int foo = 0;
+ Foo15478!int[foo.bug] bar; // Error: integer constant expression expected instead of Foo().bug
+
+ enum foo_bug = foo.bug;
+ Foo15478!int[foo_bug] baz; // OK
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/issue15795.d b/gcc/testsuite/gdc.test/compilable/issue15795.d
new file mode 100644
index 0000000..08ed495
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue15795.d
@@ -0,0 +1,9 @@
+module issue15795;
+
+template Foo(T : int) {}
+template Bar(T) {}
+alias Bar = Foo;
+
+alias bi = Bar!int;
+alias fi = Foo!int;
+static assert(__traits(isSame, bi, fi));
diff --git a/gcc/testsuite/gdc.test/compilable/issue15818.d b/gcc/testsuite/gdc.test/compilable/issue15818.d
new file mode 100644
index 0000000..4aed650
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue15818.d
@@ -0,0 +1,15 @@
+module issue15818;
+
+void f(int);
+void f(int);
+void f(int);
+void f(int);
+void f(int);
+
+pragma(mangle, "_D10issue158181fFiZv")
+void theVeritableF(int){}
+
+void main()
+{
+ f(1);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/issue18097.d b/gcc/testsuite/gdc.test/compilable/issue18097.d
new file mode 100644
index 0000000..0bc1613
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue18097.d
@@ -0,0 +1,12 @@
+// REQUIRED_ARGS: -unittest
+module issue18097;
+
+unittest // this first unittest is needed to trigger the bug
+{
+}
+
+unittest // second unittest
+{
+ auto a = &mixin(__traits(identifier, __traits(parent, { })));
+ auto b = &__traits(parent, { });
+}
diff --git a/gcc/testsuite/gdc.test/compilable/issue19925.d b/gcc/testsuite/gdc.test/compilable/issue19925.d
new file mode 100644
index 0000000..aed1688
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue19925.d
@@ -0,0 +1,14 @@
+// REQUIRED_ARGS: -unittest
+module issue19925;
+
+unittest {
+ with (S) {
+ a(); // Compiles!
+ b(); // Fails!
+ }
+}
+
+struct S {
+ static void a() {}
+ static void opDispatch(string name)() {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/issue20362.d b/gcc/testsuite/gdc.test/compilable/issue20362.d
new file mode 100644
index 0000000..b24bb8d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue20362.d
@@ -0,0 +1,8 @@
+void main() {
+ string str;
+ stringify((chars) {str ~= chars; });
+}
+
+void stringify(scope void delegate(scope const char[]) sink) {
+ sink("oops");
+}
diff --git a/gcc/testsuite/gdc.test/compilable/issue20599.d b/gcc/testsuite/gdc.test/compilable/issue20599.d
new file mode 100644
index 0000000..d3b614a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue20599.d
@@ -0,0 +1,10 @@
+import core.stdc.config;
+
+enum A : cpp_long;
+enum B : cpp_longlong;
+
+enum C : cpp_long { a,b,c };
+enum D : cpp_longlong { a,b,c };
+
+enum : cpp_long { a,b,c };
+enum : cpp_longlong { d,e,f };
diff --git a/gcc/testsuite/gdc.test/compilable/issue20704.d b/gcc/testsuite/gdc.test/compilable/issue20704.d
new file mode 100644
index 0000000..ec95828
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue20704.d
@@ -0,0 +1,29 @@
+/*
+https://issues.dlang.org/show_bug.cgi?id=20704
+REQUIRED_ARGS: -preview=rvaluerefparam
+ */
+
+void f1(T)(const auto ref T arg = T.init) {}
+void f2(T)(const ref T arg = T.init) {}
+void f3(T)(const auto ref T arg = 0) {}
+void f4(T)(const ref T arg = 0) {}
+
+struct S { int _; }
+class C { int _; }
+
+void main ()
+{
+ int i;
+ f1!int(i);
+ f2!int(i);
+ f3!int(i);
+ f4!int(i);
+ f1!int();
+ f2!int();
+ f3!int();
+ f4!int();
+ f1!S();
+ f2!S();
+ f1!C();
+ f2!C();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/issue20705.d b/gcc/testsuite/gdc.test/compilable/issue20705.d
new file mode 100644
index 0000000..76a364e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue20705.d
@@ -0,0 +1,16 @@
+// REQUIRED_ARGS: -preview=rvaluerefparam
+struct Foo
+{
+ int[] a;
+}
+
+void bar (T) (const ref T arg) {}
+T foo (T) (ref T arg) { return arg; }
+void goo()(ref long x) { x = 1; }
+void main ()
+{
+ bar(Foo([42]));
+ auto x = foo(Foo([42]));
+ int y;
+ static assert(!__traits(compiles, goo(y)));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/issue20995.d b/gcc/testsuite/gdc.test/compilable/issue20995.d
new file mode 100644
index 0000000..7b29587
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue20995.d
@@ -0,0 +1,12 @@
+/*
+REQUIRED_ARGS: -preview=dip1021
+
+https://issues.dlang.org/show_bug.cgi?id=20995
+*/
+
+void foo() @live
+{
+ throw new Exception("");
+}
+
+void main () {}
diff --git a/gcc/testsuite/gdc.test/compilable/issue21328.d b/gcc/testsuite/gdc.test/compilable/issue21328.d
new file mode 100644
index 0000000..91dc0ba
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue21328.d
@@ -0,0 +1,8 @@
+
+static foreach(i; 1 .. 5)
+void foo(float[i] arr)
+{
+ () {
+ float x = arr[0];
+ } ();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/issue21378.d b/gcc/testsuite/gdc.test/compilable/issue21378.d
new file mode 100644
index 0000000..007f39b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue21378.d
@@ -0,0 +1,33 @@
+// https://issues.dlang.org/show_bug.cgi?id=21378
+
+version(all)
+ enum do_inline = true;
+
+pragma(inline, do_inline)
+void stuff(){}
+
+void stuff2()
+{
+ pragma(inline, do_inline);
+}
+
+pragma(inline, canInline(1))
+void stuff3(){}
+
+void stuff4()
+{
+ pragma(inline, canInline(1));
+}
+
+void main()
+{
+ stuff();
+ stuff2();
+ stuff3();
+ stuff4();
+}
+
+int canInline(int x)
+{
+ return x*x;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/issue21662.d b/gcc/testsuite/gdc.test/compilable/issue21662.d
new file mode 100644
index 0000000..bb2e741
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue21662.d
@@ -0,0 +1,4 @@
+struct S { @disable this(); }
+extern __gshared S a;
+extern S[2] b;
+void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/issue21726.d b/gcc/testsuite/gdc.test/compilable/issue21726.d
index c8a8675..f687751 100644
--- a/gcc/testsuite/gdc.test/compilable/issue21726.d
+++ b/gcc/testsuite/gdc.test/compilable/issue21726.d
@@ -1,2 +1,3 @@
// EXTRA_SOURCES: protection/issue21726/typecons.d
+// EXTRA_FILES: protection/issue21726/format/package.d protection/issue21726/package.d
// https://issues.dlang.org/show_bug.cgi?id=21726
diff --git a/gcc/testsuite/gdc.test/compilable/issue21880.d b/gcc/testsuite/gdc.test/compilable/issue21880.d
new file mode 100644
index 0000000..183f349
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue21880.d
@@ -0,0 +1,23 @@
+// REQUIRED_ARGS: -preview=dip1000
+// https://issues.dlang.org/show_bug.cgi?id=21880
+extern(C++):
+void spawnProcess(scope const(char*)*, File = File()) @safe
+{
+}
+
+void pipeProcess(scope const(char*)* args) @safe
+{
+ pipeProcessImpl!spawnProcess(args);
+}
+
+void pipeProcessImpl(alias spawnFunc, Cmd)(Cmd command) @trusted
+{
+ spawnFunc(command);
+}
+
+struct File
+{
+ ~this() @safe
+ {
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/issue21882.d b/gcc/testsuite/gdc.test/compilable/issue21882.d
new file mode 100644
index 0000000..87a166a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue21882.d
@@ -0,0 +1,14 @@
+// REQUIRED_ARGS: -preview=dip1021
+// https://issues.dlang.org/show_bug.cgi?id=21882
+bool buildPath()
+{
+ struct ByCodeUnitImpl
+ {
+ auto opIndex(size_t) { }
+ }
+ return isRandomAccessRange!ByCodeUnitImpl;
+}
+
+enum isRandomAccessRange(R) = is(typeof(lvalueOf!R[1]));
+
+ref T lvalueOf(T)();
diff --git a/gcc/testsuite/gdc.test/compilable/issue21905.d b/gcc/testsuite/gdc.test/compilable/issue21905.d
new file mode 100644
index 0000000..76a04d8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue21905.d
@@ -0,0 +1,24 @@
+module issue21905;
+
+struct Conv
+{
+ StaticIterable b;
+ alias b this;
+}
+
+struct StaticIterable
+{
+ static Conv b;
+ alias b this;
+}
+
+void each(ref StaticIterable r)
+{
+ return ;
+}
+
+void main()
+{
+ StaticIterable s;
+ each(s);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/issue9884.d b/gcc/testsuite/gdc.test/compilable/issue9884.d
new file mode 100644
index 0000000..e799c49
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue9884.d
@@ -0,0 +1,25 @@
+// https://issues.dlang.org/show_bug.cgi?id=9884
+module issue9884;
+
+const(int)[] data;
+
+static this()
+{
+ data = new int[10];
+ foreach (ref x; data) x = 1;
+ data[] = 1;
+}
+
+struct Foo
+{
+ static const(int)[] data;
+
+ static this()
+ {
+ this.data = new int[10];
+ foreach (ref x; this.data) x = 1;
+ this.data[] = 1;
+ }
+}
+
+void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/json.d b/gcc/testsuite/gdc.test/compilable/json.d
index e2b0860..f79639d 100644
--- a/gcc/testsuite/gdc.test/compilable/json.d
+++ b/gcc/testsuite/gdc.test/compilable/json.d
@@ -1,28 +1,47 @@
// PERMUTE_ARGS:
-// REQUIRED_ARGS: -o- -X -Xf${RESULTS_DIR}/compilable/json.out
-// POST_SCRIPT: compilable/extra-files/json-postscript.sh
+// REQUIRED_ARGS: -d -preview=dip1000 -o- -X -Xf-
// EXTRA_FILES: imports/jsonimport1.d imports/jsonimport2.d imports/jsonimport3.d imports/jsonimport4.d
-
+// TRANSFORM_OUTPUT: sanitize_json
+// TEST_OUTPUT_FILE: extra-files/json.json
module json;
-
+shared static this() {}
static this() {}
-
+shared static ~this() {}
static ~this() {}
+template X(T)
+{
+ shared static this() {}
+ static this() {}
+ shared static ~this() {}
+ static ~this() {}
+}
+
+alias SSCDX = X!int;
+
+class SSCDClass
+{
+ shared static this() {}
+ static this() {}
+ shared static ~this() {}
+ static ~this() {}
+}
+
+#line 17
alias int myInt;
-myInt x; // bug 3404
+myInt x; // https://issues.dlang.org/show_bug.cgi?id=3404
struct Foo(T) { T t; }
class Bar(int T) { int t = T; }
-interface Baz(T...) { T[0] t() const; } // bug 3466
+interface Baz(T...) { T[0] t() const; } // https://issues.dlang.org/show_bug.cgi?id=3466
template P(alias T) {}
class Bar2 : Bar!1, Baz!(int, 2, null) {
this() {}
- ~this() {} // bug 4178
+ ~this() {} // https://issues.dlang.org/show_bug.cgi?id=4178
static foo() {}
protected abstract Foo!int baz();
@@ -30,48 +49,65 @@ class Bar2 : Bar!1, Baz!(int, 2, null) {
}
class Bar3 : Bar2 {
- private int val;
+ private int val;
this(int i) { val = i; }
protected override Foo!int baz() { return Foo!int(val); }
}
struct Foo2 {
- Bar2 bar2;
- union U {
- struct {
- short s;
- int i;
- }
- Object o;
- }
+ Bar2 bar2;
+ union U {
+ struct {
+ short s;
+ int i;
+ }
+ Object o;
+ }
+}
+
+struct Foo3(bool b) {
+ version(D_Ddoc) {
+ /// Doc 1
+ void method1();
+ }
+ static if (b) {
+ /// Doc 2
+ void method2();
+ } else {
+ /// Doc 3
+ void method3();
+ }
+
+ /// Doc 4
+ void method4();
}
/++
+ Documentation test
+/
-@trusted myInt bar(ref uint blah, Bar2 foo = new Bar3(7)) // bug 4477
+@trusted myInt bar(ref uint blah, Bar2 foo = new Bar3(7)) // https://issues.dlang.org/show_bug.cgi?id=4477
{
- return -1;
+ return -1;
}
@property int outer() nothrow
in {
- assert(true);
+ assert(true);
}
out(result) {
- assert(result == 18);
+ assert(result == 18);
}
-body {
- int x = 8;
- int inner(void* v) nothrow
- {
- int y = 2;
- assert(true);
- return x + y;
- }
- int z = inner(null);
- return x + z;
+do {
+ int x = 8;
+ int inner(void* v) nothrow
+ {
+ int y = 2;
+ assert(true);
+ return x + y;
+ }
+ int z = inner(null);
+ return x + z;
}
/** Issue 9484 - selective and renamed imports */
@@ -121,9 +157,60 @@ alias Seq(T...) = T;
static foreach(int i, alias a; Seq!(a0, a1, a2))
{
- mixin("alias b" ~ i.stringof ~ " = a;");
+ mixin("alias b" ~ i.stringof ~ " = a;");
+}
+
+// return ref, return scope, return ref scope
+ref int foo(return ref int a) @safe
+{
+ return a;
}
+int* foo(return scope int* a) @safe
+{
+ return a;
+}
+
+ref int* foo(scope return ref int* a) @safe
+{
+ return a;
+}
+
+struct SafeS
+{
+@safe:
+ ref SafeS foo() return
+ {
+ return this;
+ }
+
+ SafeS foo2() return scope
+ {
+ return this;
+ }
+
+ ref SafeS foo3() return scope
+ {
+ return this;
+ }
+
+ int* p;
+}
+
+extern int vlinkageDefault;
+extern(D) int vlinkageD;
+extern(C) int vlinakgeC;
+extern(C++) __gshared int vlinkageCpp;
+extern(Windows) int vlinkageWindows;
+extern(Objective-C) int vlinkageObjc;
+
+extern int flinkageDefault();
+extern(D) int flinkageD();
+extern(C) int linakgeC();
+extern(C++) int flinkageCpp();
+extern(Windows) int flinkageWindows();
+extern(Objective-C) int flinkageObjc();
+
mixin template test18211(int n)
{
static foreach (i; 0 .. n>10 ? 10 : n)
@@ -132,3 +219,5 @@ mixin template test18211(int n)
}
static if (true) {}
}
+
+alias F = size_t function (size_t a);
diff --git a/gcc/testsuite/gdc.test/compilable/json20742.d b/gcc/testsuite/gdc.test/compilable/json20742.d
new file mode 100644
index 0000000..3e91dee
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/json20742.d
@@ -0,0 +1,69 @@
+/*
+REQUIRED_ARGS: -Xf- -o- -version=Showme
+PERMUTE_ARGS:
+TEST_OUTPUT:
+----
+[
+ {
+ "kind" : "module",
+ "file" : "compilable$?:windows=\\|/$json20742.d",
+ "members" : [
+ {
+ "name" : "X1",
+ "kind" : "struct",
+ "protection" : "private",
+ "line" : 52,
+ "char" : 13,
+ "members" : []
+ },
+ {
+ "name" : "Y2",
+ "kind" : "struct",
+ "protection" : "private",
+ "line" : 59,
+ "char" : 13,
+ "members" : []
+ },
+ {
+ "name" : "A1",
+ "kind" : "struct",
+ "protection" : "private",
+ "line" : 62,
+ "char" : 13,
+ "members" : []
+ },
+ {
+ "name" : "B2",
+ "kind" : "struct",
+ "protection" : "private",
+ "line" : 69,
+ "char" : 13,
+ "members" : []
+ }
+ ]
+ }
+]
+----
+
+https://issues.dlang.org/show_bug.cgi?id=20742
+*/
+
+version(Showme)
+ private struct X1 {}
+else
+ private struct X2 {}
+
+version(Hideme)
+ private struct Y1 {}
+else
+ private struct Y2 {}
+
+static if (true)
+ private struct A1 {}
+else
+ private struct A2 {}
+
+static if (false)
+ private struct B1 {}
+else
+ private struct B2 {}
diff --git a/gcc/testsuite/gdc.test/compilable/minimal.d b/gcc/testsuite/gdc.test/compilable/minimal.d
new file mode 100644
index 0000000..6398328
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/minimal.d
@@ -0,0 +1,19 @@
+// DFLAGS:
+// PERMUTE_ARGS:
+// POST_SCRIPT: compilable/extra-files/minimal/verify_symbols.sh
+// REQUIRED_ARGS: -defaultlib=
+// EXTRA_SOURCES: extra-files/minimal/object.d
+
+// This test ensures an empty main with a struct and enum, built with a minimal
+// runtime, does not generate ModuleInfo or exception handling code, and does not
+// require TypeInfo
+
+struct S { }
+
+enum E
+{
+ e0 = 0,
+ e1 = 1
+}
+
+void main() { }
diff --git a/gcc/testsuite/gdc.test/compilable/minimal2.d b/gcc/testsuite/gdc.test/compilable/minimal2.d
new file mode 100644
index 0000000..d69eb92
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/minimal2.d
@@ -0,0 +1,31 @@
+// DFLAGS:
+// REQUIRED_ARGS: -defaultlib=
+// EXTRA_SOURCES: extra-files/minimal/object.d
+
+// This test ensures that interfaces and classes can be used in a minimal
+// runtime as long as they only contain static members.
+
+// This should compile, but will not link and run properly without
+// a thread-local storage (TLS) implementation.
+
+interface I
+{
+ static int i;
+}
+
+class A : I
+{
+ static int a;
+}
+
+class B : A
+{
+ static int b;
+}
+
+void main()
+{
+ B.i = 32;
+ B.a = 42;
+ B.b = 52;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/mixin.d b/gcc/testsuite/gdc.test/compilable/mixin.d
new file mode 100644
index 0000000..d96eae1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/mixin.d
@@ -0,0 +1,38 @@
+/*
+REQUIRED_ARGS: -mixin=${RESULTS_DIR}/runnable/mixin.mixin -o-
+OUTPUT_FILES: ${RESULTS_DIR}/runnable/mixin.mixin
+
+TEST_OUTPUT:
+----
+=== ${RESULTS_DIR}/runnable/mixin.mixin
+// expansion at compilable/mixin.d(14)
+int x =
+ 123;
+
+ int y;
+
+
+
+ int z = x + y;
+----
+
+https://issues.dlang.org/show_bug.cgi?id=1870
+https://issues.dlang.org/show_bug.cgi?id=12790
+*/
+
+#line 1
+string get()
+{
+ return "int x =\n 123;\r\n" ~
+ q{
+ int y;
+
+
+
+ int z = x + y;};
+}
+
+void main()
+{
+ mixin(get());
+}
diff --git a/gcc/testsuite/gdc.test/compilable/mixinTemplateMangling.d b/gcc/testsuite/gdc.test/compilable/mixinTemplateMangling.d
new file mode 100644
index 0000000..3596a95
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/mixinTemplateMangling.d
@@ -0,0 +1,35 @@
+// https://issues.dlang.org/show_bug.cgi?id=20012
+
+mixin template mixinFoo() {
+
+ extern(C) void cFoo() {}
+
+ extern(C) int cVar;
+ extern(D) int dVar;
+
+ void dFoo() {}
+
+ mixin(`mixin mixinBar;`); // test nesting and interaction with string mixins
+}
+
+mixin mixinFoo;
+
+mixin template mixinBar() {
+ extern(C) void cBar() {}
+ void dBar() {}
+}
+
+static assert(cFoo.mangleof == "cFoo");
+static assert(dFoo.mangleof == "_D21mixinTemplateMangling8__mixin54dFooFZv");
+static assert(cVar.mangleof == "cVar");
+static assert(dVar.mangleof == "_D21mixinTemplateMangling8__mixin54dVari");
+static assert(cBar.mangleof == "cBar");
+static assert(dBar.mangleof == "_D21mixinTemplateMangling8__mixin5Qj4dBarFZv");
+
+struct S {
+ mixin mixinFoo;
+ static assert(cFoo.mangleof == "_D21mixinTemplateMangling1S8__mixin14cFooMUZv");
+ static assert(cBar.mangleof == "_D21mixinTemplateMangling1S8__mixin18__mixin54cBarMUZv");
+ static assert(dBar.mangleof == "_D21mixinTemplateMangling1S8__mixin18__mixin54dBarMFZv");
+ static assert(dFoo.mangleof == "_D21mixinTemplateMangling1S8__mixin14dFooMFZv");
+}
diff --git a/gcc/testsuite/gdc.test/compilable/mixintempl.d b/gcc/testsuite/gdc.test/compilable/mixintempl.d
new file mode 100644
index 0000000..d897a17
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/mixintempl.d
@@ -0,0 +1,22 @@
+
+struct TypeObj
+{
+ alias This = typeof(this);
+
+ mixin template MixinTempl()
+ {
+ int value;
+ }
+}
+
+ref TypeObj Obj()
+{
+ static TypeObj a;
+ return a;
+}
+
+void func()
+{
+ mixin Obj.This.MixinTempl; // ok
+ mixin Obj.MixinTempl; // fixed: "MixinTempl!()" is not defined
+}
diff --git a/gcc/testsuite/gdc.test/compilable/nestedtempl0.d b/gcc/testsuite/gdc.test/compilable/nestedtempl0.d
new file mode 100644
index 0000000..aa6826b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/nestedtempl0.d
@@ -0,0 +1,13 @@
+class C2
+{
+ class N(alias a) {}
+}
+
+void test2()
+{
+ int a;
+ static assert(__traits(isSame, __traits(parent, C2.N!0), C2));
+ static assert(__traits(isSame, __traits(parent, C2.N!a), C2));
+ static assert(__traits(classInstanceSize, C2.N!0) == size_t.sizeof * 3);
+ static assert(__traits(classInstanceSize, C2.N!a) == size_t.sizeof * 4);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/nestedtempl1.d b/gcc/testsuite/gdc.test/compilable/nestedtempl1.d
new file mode 100644
index 0000000..ecb8e83
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/nestedtempl1.d
@@ -0,0 +1,25 @@
+class K
+{
+ class B(alias a)
+ {
+
+ }
+
+ class D(alias a) : B!a
+ {
+
+ }
+
+ class E(alias a) : B!1
+ {
+
+ }
+}
+
+void main()
+{
+ int a;
+ auto k = new K;
+ auto d = k.new K.D!a;
+ auto e = k.new K.E!a;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/nogc.d b/gcc/testsuite/gdc.test/compilable/nogc.d
index c2581da..2751801 100644
--- a/gcc/testsuite/gdc.test/compilable/nogc.d
+++ b/gcc/testsuite/gdc.test/compilable/nogc.d
@@ -52,7 +52,7 @@ void foo_compiles() {}
}
/******************************************/
-// 12630
+// https://issues.dlang.org/show_bug.cgi?id=12630
void test12630() @nogc
{
@@ -86,7 +86,7 @@ void test12630() @nogc
}
/******************************************/
-// 12642
+// https://issues.dlang.org/show_bug.cgi?id=12642
static if (is(__vector(ulong[2])))
{
@@ -99,7 +99,7 @@ static if (is(__vector(ulong[2])))
}
/******************************************/
-// 13550
+// https://issues.dlang.org/show_bug.cgi?id=13550
auto foo13550() @nogc
{
diff --git a/gcc/testsuite/gdc.test/compilable/noreturn1.d b/gcc/testsuite/gdc.test/compilable/noreturn1.d
index e21adc4..7517bb2 100644
--- a/gcc/testsuite/gdc.test/compilable/noreturn1.d
+++ b/gcc/testsuite/gdc.test/compilable/noreturn1.d
@@ -1,21 +1,66 @@
/*
+REQUIRED_ARGS: -w
TEST_OUTPUT:
---
noreturn
---
+
+Basic properties and usage mentioned in the DIP:
+https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1034.md
*/
alias noreturn = typeof(*null);
pragma(msg, noreturn);
-noreturn exits(int* p) { *p = 3; }
+static assert(!is(noreturn == void));
+
+// Fails
+// static assert(is( typeof([]) == noreturn[] ));
+// static assert(is( typeof([][0]) == noreturn ));
+
+static assert(is( typeof(assert(0)) == noreturn ));
+
+// Does not parse yet
+// static assert(is( typeof(throw new Exception()) == noreturn ));
+
+static assert(is(noreturn == noreturn));
+static assert(!is(noreturn == const noreturn));
+static assert(is(noreturn : const noreturn));
+
+static assert(!is(noreturn == int));
+static assert(is(noreturn : int));
+
+// Covariance
+static assert(is(noreturn[] : int[]));
+static assert(is(noreturn* : int*));
+static assert(is(noreturn function() : int function()));
+static assert(is(noreturn delegate() : int delegate()));
+
+// Reject inverse conversions
+static assert(!is(int[] : noreturn[]));
+static assert(!is(int* : noreturn*));
+static assert(!is(int function() : noreturn function()));
+static assert(!is(int delegate() : noreturn delegate()));
+
+static assert(noreturn.mangleof == "Nn"); // Changed from b due to conflicts with bool
+static assert(noreturn.sizeof == 0);
+static assert(noreturn.alignof == 0);
+
+static assert((noreturn*).sizeof == (int*).sizeof);
+static assert((noreturn[]).sizeof == (int[]).sizeof);
+
+version (DigitalMars)
+ noreturn exits(int* p) { *p = 3; }
noreturn exit();
+noreturn pureexits() @nogc nothrow pure @safe { assert(0); }
+
+noreturn callpureexits() { pureexits(); }
+
int test1(int i)
{
if (exit())
return i + 1;
return i - 1;
}
-
diff --git a/gcc/testsuite/gdc.test/compilable/ob1.d b/gcc/testsuite/gdc.test/compilable/ob1.d
new file mode 100644
index 0000000..720c765
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ob1.d
@@ -0,0 +1,149 @@
+// REQUIRED_ARGS: -preview=dip1021
+
+/* Should compile successfully
+ */
+
+
+struct Allocation {
+ int* ptr;
+ size_t length;
+}
+
+void canFind(scope Allocation);
+
+int* malloc();
+void free(int*);
+void pitcher();
+void borrow(scope int*);
+void borrow2c(const scope int*, const scope int*);
+void out1(out int*);
+
+
+/*****************************/
+
+@live int* foo1(int* p)
+{
+ return p; // consumes owner
+}
+
+@live int* foo2()
+{
+ int* p = null;
+ return p; // consumes owner
+}
+
+@live int* foo3(int* p)
+{
+ scope int* q = p; // borrows from p
+ return p; // use of p ends borrow in q
+}
+
+@live int* foo4(int* p)
+{
+ scope int* bq = p; // borrow
+ scope const int* cq = p; // const borrow
+ return p; // ends both borrows
+}
+
+/*******************************/
+
+@live void foo5()
+{
+ auto p = malloc();
+ scope(exit) free(p);
+ pitcher();
+}
+
+/*******************************/
+
+void deallocate(int* ptr, size_t length) @live
+{
+ canFind(Allocation(ptr, length)); // canFind() borrows ptr
+ free(ptr);
+}
+
+
+/*******************************/
+
+
+@live int* test1()
+{
+ auto p = malloc();
+ scope b = p;
+ return p;
+}
+
+@live int* test2()
+{
+ auto p = malloc();
+ auto q = p;
+ return q;
+}
+
+@live void test3()
+{
+ auto p = malloc();
+ free(p);
+}
+
+@live void test4()
+{
+ auto p = malloc();
+ borrow(p);
+ free(p);
+}
+
+@live void test5()
+{
+ auto p = malloc();
+ scope q = p;
+ borrow2c(p, p);
+ free(p);
+}
+
+@live void test6()
+{
+ int* p = void;
+ out1(p); // initialize
+ free(p); // consume
+}
+
+
+/*******************************/
+
+void zoo1(int);
+
+@live void zoo2() {
+ int* p = malloc();
+ zoo1(*p); // does not consume p
+ free(p);
+}
+
+@live void zoo3() {
+ int** p = cast(int**)malloc();
+ free(*p); // consumes p
+}
+
+@live void zoo4() {
+ int[] a = malloc()[0 .. 1];
+ zoo1(a[0]); // does not consume a
+ free(a.ptr); // consumes a
+}
+
+@live void zoo5() {
+ int*[] a = (cast(int**)malloc())[0 .. 1];
+ free(a[0]); // consumes a
+}
+
+struct S { int i; int* p; }
+
+@live void zoo6() {
+ S* s = cast(S*)malloc();
+ zoo1(s.i); // does not consume s
+ free(cast(int*)s);
+}
+
+@live void zoo7() {
+ S* s = cast(S*)malloc();
+ free(s.p); // consumes s
+}
diff --git a/gcc/testsuite/gdc.test/compilable/pr9374.d b/gcc/testsuite/gdc.test/compilable/pr9374.d
new file mode 100644
index 0000000..912639d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/pr9374.d
@@ -0,0 +1,19 @@
+// REQUIRED_ARGS: -preview=dip1000
+
+// https://github.com/dlang/dmd/pull/9374
+
+struct OnlyResult
+{
+ this(return scope ref int v2);
+
+ void* data;
+}
+
+OnlyResult foo(return scope ref int v2);
+
+OnlyResult only(int y)
+{
+ if (y)
+ return OnlyResult(y);
+ return foo(y);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/pr9383.d b/gcc/testsuite/gdc.test/compilable/pr9383.d
new file mode 100644
index 0000000..ca6d70f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/pr9383.d
@@ -0,0 +1,25 @@
+// REQUIRED_ARGS: -preview=dip1000
+// https://github.com/dlang/dmd/pull/9383
+
+void test() @safe
+{
+ int[1] a = [1];
+ cartesianProduct(a[]);
+}
+
+auto cartesianProduct(RR...)(RR ranges)
+{
+ static struct Result
+ {
+ RR current;
+
+ void popFront() scope @safe
+ {
+ foreach (ref r; current)
+ {
+ }
+ }
+ }
+
+ return Result(ranges);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/previewall.d b/gcc/testsuite/gdc.test/compilable/previewall.d
new file mode 100644
index 0000000..e5ed7a8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/previewall.d
@@ -0,0 +1,10 @@
+// ARG_SETS: -preview=all
+// ARG_SETS: -transition=all
+// ARG_SETS: -revert=all
+import core.stdc.stdio;
+
+void main (string[] args)
+{
+ if (args.length == 42)
+ printf("Hello World\n");
+}
diff --git a/gcc/testsuite/gdc.test/compilable/previewin.d b/gcc/testsuite/gdc.test/compilable/previewin.d
new file mode 100644
index 0000000..8926fbd
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/previewin.d
@@ -0,0 +1,116 @@
+/* REQUIRED_ARGS: -preview=dip1000 -preview=in -mcpu=native
+ */
+
+import core.stdc.time;
+
+void fun(in int* inParam) @safe;
+static assert([__traits(getParameterStorageClasses, fun, 0)] == ["in"]);
+static assert (is(typeof(fun) P == __parameters) && is(P[0] == const int*));
+
+struct Foo
+{
+ int a;
+ double[100] b;
+}
+void fun2(in Foo inParam) @safe;
+static assert([__traits(getParameterStorageClasses, fun2, 0)] == ["in"]);
+static assert (is(typeof(fun2) P == __parameters) && is(P[0] == const Foo));
+
+void test()
+{
+ withDefaultValue(42);
+ withDefaultValue();
+ withDefaultRef(TimeRef.init);
+ withDefaultRef();
+
+ withInitDefaultValue();
+ withInitDefaultRef();
+}
+
+struct FooBar
+{
+ string toString() const
+ {
+ string result;
+ // Type is const
+ this.toString((in char[] buf) {
+ static assert(is(typeof(buf) == const(char[])));
+ result ~= buf;
+ });
+ // Type inference works
+ this.toString((in buf) { result ~= buf; });
+ return result;
+ }
+
+ void toString(scope void delegate(in char[]) sink) const
+ {
+ sink("Hello world");
+ }
+}
+
+// Ensure that default parameter works even if non CTFEable
+void withDefaultValue(in time_t currTime = time(null)) {}
+struct TimeRef { time_t now; ulong[4] bloat; }
+void withDefaultRef(in TimeRef currTime = TimeRef(time(null))) {}
+
+// Ensure that default parameters work with `.init`
+void withInitDefaultValue(in size_t defVal = size_t.init) {}
+void withInitDefaultRef(in TimeRef defVal = TimeRef.init) {}
+
+// Ensure that temporary aren't needlessly created
+// (if they are, it'll trigger the "goto skips declaration" error)
+void checkNotIdentity(in void* p1, in void* p2) { assert(p1 !is p2); }
+void checkTemporary()
+{
+ int* p = new int;
+ if (p is null)
+ goto LError;
+ // Should not generate temporary, pass the pointers by value
+ checkNotIdentity(/*lvalue*/ p, /*rvalue*/ null);
+ checkNotIdentity(new int, null);
+LError:
+ assert(0);
+}
+
+
+// Some ABI-specific tests:
+
+version (Win64)
+{
+ void checkReal(in real p)
+ {
+ // ref for x87 real, value for double-precision real
+ static assert(__traits(isRef, p) == (real.sizeof > 8));
+ }
+
+ struct RGB { ubyte r, g, b; }
+ void checkNonPowerOf2(in RGB p)
+ {
+ static assert(__traits(isRef, p));
+ }
+}
+else version (X86_64) // Posix x86_64
+{
+ struct Empty {} // 1 dummy byte passed on the stack
+ void checkEmptyStruct(in Empty p)
+ {
+ static assert(!__traits(isRef, p));
+ }
+
+ static if (is(__vector(double[4])))
+ {
+ struct AvxVectorWrapper { __vector(double[4]) a; } // 256 bits
+ void checkAvxVector(in AvxVectorWrapper p)
+ {
+ static assert(!__traits(isRef, p));
+ }
+ }
+}
+else version (AArch64)
+{
+ alias HVA = __vector(float[4])[4]; // can be passed in 4 vector registers
+ void checkHVA(in HVA p)
+ {
+ static assert(!__traits(isRef, p));
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/protattr.d b/gcc/testsuite/gdc.test/compilable/protattr.d
index ca53a5e..5922a79 100644
--- a/gcc/testsuite/gdc.test/compilable/protattr.d
+++ b/gcc/testsuite/gdc.test/compilable/protattr.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -o-
+// EXTRA_FILES: protection/basic/mod1.d protection/basic/tests.d protection/subpkg/explicit.d protection/subpkg/tests.d protection/subpkg2/tests.d
// PERMUTE_ARGS:
import protection.basic.tests;
import protection.subpkg.tests;
diff --git a/gcc/testsuite/gdc.test/compilable/protection.d b/gcc/testsuite/gdc.test/compilable/protection.d
index 3d6198d..bf906eb 100644
--- a/gcc/testsuite/gdc.test/compilable/protection.d
+++ b/gcc/testsuite/gdc.test/compilable/protection.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/protectionimp.d
import imports.protectionimp;
alias TypeTuple(T...) = T;
@@ -76,7 +77,7 @@ void main()
}
/***************************************************/
-// 14169
+// https://issues.dlang.org/show_bug.cgi?id=14169
template staticMap14169(alias fun, T...)
{
diff --git a/gcc/testsuite/gdc.test/compilable/quadratic.d b/gcc/testsuite/gdc.test/compilable/quadratic.d
new file mode 100644
index 0000000..4619e82
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/quadratic.d
@@ -0,0 +1,42 @@
+/* PERMUTE_ARGS: -O
+ * If not careful, this can produce exponential tree traversal times
+ * when compiling the generated opEquals() function.
+ */
+
+struct Param
+{
+ bool verbose;
+ bool vcg_ast;
+ bool showColumns;
+ bool vtls;
+ bool vtemplates;
+ bool vgc;
+ bool vfield;
+ bool vcomplex;
+ int useDeprecated;
+ bool stackstomp;
+ bool useUnitTests;
+ bool useInline;
+ bool useDIP25;
+ bool noDIP25;
+ bool useDIP1021;
+ bool release;
+ bool a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;
+ uint debuglevel;
+ void* debugids;
+
+ uint versionlevel;
+ void* versionids;
+
+ const(char)[] defaultlibname;
+ const(char)[] debuglibname;
+ const(char) mscrtlib;
+
+ void* moduleDeps;
+ int messageStyle = 1;
+}
+
+struct Global
+{
+ Param params;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/readmodify_structclass.d b/gcc/testsuite/gdc.test/compilable/readmodify_structclass.d
new file mode 100644
index 0000000..ba55e54
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/readmodify_structclass.d
@@ -0,0 +1,30 @@
+// REQUIRED_ARGS:
+shared struct S
+{
+ int x = 0;
+
+ int opUnary(string s)() if (s == "++")
+ {
+ import core.atomic : atomicOp;
+ return atomicOp!"+="(x, 1);
+ }
+}
+
+shared class C
+{
+ int x = 0;
+
+ int opUnary(string s)() if (s == "++")
+ {
+ import core.atomic : atomicOp;
+ return atomicOp!"+="(x, 1);
+ }
+}
+
+void main()
+{
+ S s;
+ s++;
+ shared(C) c = new C();
+ c++;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/reinterpretctfe.d b/gcc/testsuite/gdc.test/compilable/reinterpretctfe.d
new file mode 100644
index 0000000..1d6fd4f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/reinterpretctfe.d
@@ -0,0 +1,34 @@
+// https://issues.dlang.org/show_bug.cgi?id=21997
+
+int nonPureFunc(int i)
+{
+ return 2 * i;
+}
+
+int mainCtfe()
+{
+ auto pureFunc = cast(int function(int) pure) &nonPureFunc;
+ assert(pureFunc(2) == 4);
+
+ auto baseFunc = cast(int function(int)) pureFunc;
+ assert(baseFunc(3) == 6);
+
+ /*
+ Still missing delegates: https://issues.dlang.org/show_bug.cgi?id=17487
+
+ static struct S {
+ int i;
+ int f(int j) { return i * j; }
+ }
+
+ S s = S(5);
+ auto pureDel = cast(int delegate(int) pure) &s.f;
+ assert(pureDel(3) == 15);
+
+ auto baseDel = cast(int delegate(int)) pureDel;
+ assert(baseDel(4) == 20);
+ */
+ return 0;
+}
+
+enum forceCTFE = mainCtfe();
diff --git a/gcc/testsuite/gdc.test/compilable/riia_ctor.d b/gcc/testsuite/gdc.test/compilable/riia_ctor.d
index 1c8e142..459ca53 100644
--- a/gcc/testsuite/gdc.test/compilable/riia_ctor.d
+++ b/gcc/testsuite/gdc.test/compilable/riia_ctor.d
@@ -1,4 +1,5 @@
// https://issues.dlang.org/show_bug.cgi?id=17494
+// REQUIRED_ARGS: -revert=dtorfields
struct S
{
~this() {}
diff --git a/gcc/testsuite/gdc.test/compilable/rvalueref.d b/gcc/testsuite/gdc.test/compilable/rvalueref.d
new file mode 100644
index 0000000..1c96c36
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/rvalueref.d
@@ -0,0 +1,13 @@
+/* REQUIRED_ARGS: -preview=rvaluerefparam
+ */
+
+struct AS
+{
+ string get() @safe @nogc pure nothrow { return _s; }
+ alias get this;
+ @disable this(this);
+ string _s;
+}
+
+void popFront(ref string) { }
+static assert(!is(typeof((R r) => r.popFront)));
diff --git a/gcc/testsuite/gdc.test/compilable/scope.d b/gcc/testsuite/gdc.test/compilable/scope.d
index 4f53730..7e81028 100644
--- a/gcc/testsuite/gdc.test/compilable/scope.d
+++ b/gcc/testsuite/gdc.test/compilable/scope.d
@@ -1,14 +1,255 @@
/*
- currently fails with extra safety checks
- PERMUTE_FIXME_ARGS: -dip1000
+REQUIRED_ARGS: -preview=dip1000
*/
struct Cache
{
ubyte[1] v;
- ubyte[] set(ubyte[1] v)
+ ubyte[] set(ubyte[1] v) return
{
return this.v[] = v[];
}
}
+
+/*********************************/
+
+// https://github.com/dlang/dmd/pull/9220
+
+@safe:
+
+struct OnlyResult
+{
+ private this(Values)(scope ref Values values)
+ {
+ this.s = values;
+ }
+
+ string s;
+}
+
+auto only(Values)(Values vv)
+{
+ return OnlyResult(vv);
+}
+
+
+void test() @nogc @safe pure
+{
+ only(null);
+}
+
+/************************************/
+
+// https://github.com/dlang/dmd/pull/9220
+
+auto callWrappedOops(scope string dArgs) {
+
+ string callWrappedImpl() {
+ return dArgs;
+ }
+}
+
+/************************************/
+
+struct Constant
+{
+ int* member;
+
+ this(Repeat!(int*) grid) @safe
+ {
+ foreach(ref x; grid)
+ member = x;
+
+ foreach(ref x; grid)
+ x = member;
+ }
+
+ int* foo(return scope Repeat!(int*) grid) @safe
+ {
+ foreach(ref x; grid)
+ x = member;
+
+ foreach(ref x; grid)
+ return x;
+
+ return null;
+ }
+
+ alias Repeat(T...) = T;
+}
+
+
+/************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=19387
+
+struct C
+{
+ void* u;
+ this(this) @safe
+ {
+ }
+}
+
+struct S
+{
+ C c;
+}
+
+void foo(scope S s) @safe
+{
+}
+
+void bar(scope S s) @safe
+{
+ foo(s);
+}
+
+/************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=20675
+
+struct D
+{
+ int pos;
+ char* p;
+}
+
+void test(scope ref D d) @safe
+{
+ D[] da;
+ da ~= D(d.pos, null);
+}
+
+/************************************/
+
+void withEscapes()
+{
+ static D get() @safe;
+
+ with (get())
+ {
+ }
+}
+
+/************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=20682
+
+int f1_20682(return scope ref D d) @safe
+{
+ return d.pos;
+}
+
+ref int f2_20682(return scope ref D d) @safe
+{
+ return d.pos;
+}
+
+void test_20682(scope ref D d) @safe
+{
+ int[] a;
+ a ~= f1_20682(d);
+ a ~= f2_20682(d);
+ a ~= cast(int) d.p;
+}
+
+// Phobos failure
+void formattedWrite(immutable char[2] args) @safe
+{
+ scope immutable char[] val = args;
+}
+
+void ctfeRead(const ubyte[2] array) @safe
+{
+ short result;
+
+ foreach_reverse (b; array)
+ result = cast(short) ((result << 8) | b);
+
+ foreach (b; array)
+ result = cast(short) ((result << 8) | b);
+}
+
+void demangle() @safe
+{
+ static struct DotSplitter
+ {
+ const(char)[] s;
+
+ @safe:
+ @property bool empty() const { return !s.length; }
+
+ @property const(char)[] front() const return
+ {
+ immutable i = indexOfDot();
+ return s;
+ }
+
+ void popFront() {}
+
+ private ptrdiff_t indexOfDot() const
+ {
+ return -1;
+ }
+ }
+
+ foreach (comp; DotSplitter(""))
+ {
+ const copy = comp;
+ }
+}
+
+void fileCtor() @safe
+{
+ static struct S
+ {
+ int i;
+ }
+
+ // static S get()
+ // {
+ // return S();
+ // }
+
+ with (S())
+ {
+ int* ptr = &i;
+ }
+}
+
+// Missing test coverage
+int*[4] testArray() @safe
+{
+ return typeof(return).init;
+}
+
+/************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=21209
+void testForeach(T)(const(T)[] ts)
+{
+ static int g;
+ g++; // force impure for https://issues.dlang.org/show_bug.cgi?id=20150
+ foreach (c; ts)
+ {
+
+ }
+ foreach_reverse(c0; ts)
+ {
+ foreach(c1; ts)
+ {
+
+ }
+ }
+}
+
+@safe
+void main21209()
+{
+ char[10] cs;
+ float[10] fs;
+ testForeach(cs);
+ testForeach(fs);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/scopeinfer.d b/gcc/testsuite/gdc.test/compilable/scopeinfer.d
new file mode 100644
index 0000000..1ed4c6a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/scopeinfer.d
@@ -0,0 +1,30 @@
+// PERMUTE_ARGS: -preview=dip1000
+
+// Mangling should be the same with or without inference of `return scope`
+
+@safe:
+
+auto foo(void* p) { return 0; }
+static assert(typeof(foo).mangleof == "FNaNbNiNfPvZi");
+
+auto bar(void* p) { return p; }
+static assert(typeof(bar).mangleof == "FNaNbNiNfPvZQd");
+
+// https://issues.dlang.org/show_bug.cgi?id=19857
+
+struct Stack()
+{
+@safe:
+ int** data;
+ ref int* top()
+ {
+ return *data;
+ }
+}
+
+alias S = Stack!();
+
+//pragma(msg, S.top.mangleof);
+
+version (Win32)
+static assert(S.top.mangleof == "_D10scopeinfer__T5StackZQh3topMFNaNbNcNiNfZPi");
diff --git a/gcc/testsuite/gdc.test/compilable/shared.d b/gcc/testsuite/gdc.test/compilable/shared.d
new file mode 100644
index 0000000..bfa8422
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/shared.d
@@ -0,0 +1,125 @@
+/* REQUIRED_ARGS: -preview=nosharedaccess
+TEST_OUTPUT:
+---
+pure nothrow @nogc ref @safe shared(C1)(return ref shared(C1) c)
+pure nothrow @nogc ref @safe shared(int)(return ref shared(C3) c)
+---
+*/
+ref shared(int) f(return shared ref int y)
+{
+ return y;
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20908
+void test20908()
+{
+ // shared locals (or struct members) should be able to be initialised:
+ shared int x;
+
+ ref shared(int) fun()
+ {
+ static shared(int) val;
+
+ // return by reference
+ return val;
+ }
+
+ ref shared(int) fun2()
+ {
+ static shared(int)* val;
+
+ // transfer pointer to reference
+ return *val;
+ }
+
+ ref shared(int) fun3()
+ {
+ static shared(int)*** val;
+
+ // Multiple indirections
+ return ***val;
+ }
+}
+
+// Simple tests for `DotVarExp`
+// A `DotVarExp` is `a.b`. If `a` is a `shared ref`,
+// it is of type `shared(T)*` (as opposed to `shared(T*)`).
+// We should allow arbitrarily nested `DotVarExp` as long
+// as no shared memory is read, as in the case above
+// (we're just offsetting a pointer).
+struct C1
+{
+ int value;
+}
+
+struct C2
+{
+ C1 c1;
+}
+
+struct C3
+{
+ C2 c1;
+ C2 c2;
+}
+
+ref shared(int) test_dotvarexp_1(return ref shared C1 c)
+{
+ return c.value;
+}
+
+shared(int)* test_dotvarexp_2(return ref shared C1 c)
+{
+ return &c.value;
+}
+
+shared(C2)* test_dotvarexp_3(return ref shared C3 c)
+{
+ return &c.c1;
+}
+
+shared(C2)* test_dotvarexp_4(return ref shared C3 c)
+{
+ return &c.c2;
+}
+
+ref shared(int) test_dotvarexp_5(return shared ref C3 c)
+{
+ return c.c1.c1.value;
+}
+
+ref shared(int) test_dotvarexp_5(return ref shared(C3)[] c)
+{
+ return c[0].c1.c1.value;
+}
+
+// Test `auto` inference
+auto ref test_inference_1(return ref shared C1 c)
+{
+ return c;
+}
+
+pragma(msg, typeof(test_inference_1));
+
+auto ref test_inference_2(return ref shared C3 c)
+{
+ return c.c2.c1.value;
+}
+
+pragma(msg, typeof(test_inference_2));
+
+// https://issues.dlang.org/show_bug.cgi?id=21793
+
+struct Child
+{
+ this(int) shared {}
+}
+
+struct Parent
+{
+ shared Child ch;
+ this(int i) shared
+ {
+ ch = shared Child(i);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/sharedopt.d b/gcc/testsuite/gdc.test/compilable/sharedopt.d
new file mode 100644
index 0000000..bac0ce0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/sharedopt.d
@@ -0,0 +1,19 @@
+// REQUIRED_ARGS: -O
+
+void _d_critical_term()
+{
+ for (auto p = head; p; p = p.next)
+ destroyMutex(p.i);
+}
+
+shared S* head;
+
+struct S
+{
+ S* next;
+ int i;
+}
+
+void destroyMutex(int i);
+
+struct Mutex { int i; }
diff --git a/gcc/testsuite/gdc.test/compilable/shortened_methods.d b/gcc/testsuite/gdc.test/compilable/shortened_methods.d
new file mode 100644
index 0000000..5a7ac87
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/shortened_methods.d
@@ -0,0 +1,33 @@
+// REQUIRED_ARGS: -preview=shortenedMethods
+class A {
+ int _x = 34;
+ // short syntax works in all contexts
+ @property x() => _x;
+ @property x(int v) => _x = v;
+
+ // including with contracts
+ @property y() in(true) => _x;
+
+ // or other auto returns
+ auto foo() @safe => assert(0);
+
+ // or normal method defintions
+ bool isNull() => this is null;
+}
+
+class B : A{
+ // short syntax also overrides the same as long syntax
+ override bool isNull() => this !is null;
+}
+
+static assert((new A).x == 34);
+
+string test() => "hello"; // works at any scope
+
+static assert(test() == "hello"); // works normally
+static assert(is(typeof(&test) == string function())); // same normal type
+
+void func() {
+ int a;
+ int nested() => a; // and at nested scopes too
+}
diff --git a/gcc/testsuite/gdc.test/compilable/staticforeach.d b/gcc/testsuite/gdc.test/compilable/staticforeach.d
index 8a54f32..ce9eb74 100644
--- a/gcc/testsuite/gdc.test/compilable/staticforeach.d
+++ b/gcc/testsuite/gdc.test/compilable/staticforeach.d
@@ -1,6 +1,6 @@
// REQUIRED_ARGS: -o-
-// PERMUTE_ARGS:
// EXTRA_FILES: imports/imp12242a1.d imports/imp12242a2.d
+// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
diff --git a/gcc/testsuite/gdc.test/compilable/sw_transition_complex.d b/gcc/testsuite/gdc.test/compilable/sw_transition_complex.d
index f034c69e..b6dbc8a 100644
--- a/gcc/testsuite/gdc.test/compilable/sw_transition_complex.d
+++ b/gcc/testsuite/gdc.test/compilable/sw_transition_complex.d
@@ -1,15 +1,15 @@
// PERMUTE_ARGS:
-// REQUIRED_ARGS: -c -transition=complex
+// REQUIRED_ARGS: -unittest
/*
TEST_OUTPUT:
---
-compilable/sw_transition_complex.d(15): use of complex type 'creal' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead
-compilable/sw_transition_complex.d(16): use of complex type 'cdouble' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead
-compilable/sw_transition_complex.d(17): use of complex type 'cfloat' is scheduled for deprecation, use 'std.complex.Complex!(float)' instead
-compilable/sw_transition_complex.d(19): use of imaginary type 'ireal' is scheduled for deprecation, use 'real' instead
-compilable/sw_transition_complex.d(20): use of imaginary type 'idouble' is scheduled for deprecation, use 'double' instead
-compilable/sw_transition_complex.d(21): use of imaginary type 'ifloat' is scheduled for deprecation, use 'float' instead
+compilable/sw_transition_complex.d(15): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/sw_transition_complex.d(16): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/sw_transition_complex.d(17): Deprecation: use of complex type `cfloat` is deprecated, use `std.complex.Complex!(float)` instead
+compilable/sw_transition_complex.d(19): Deprecation: use of imaginary type `ireal` is deprecated, use `real` instead
+compilable/sw_transition_complex.d(20): Deprecation: use of imaginary type `idouble` is deprecated, use `double` instead
+compilable/sw_transition_complex.d(21): Deprecation: use of imaginary type `ifloat` is deprecated, use `float` instead
---
*/
creal c80value;
@@ -23,12 +23,12 @@ ifloat i32value;
/*
TEST_OUTPUT:
---
-compilable/sw_transition_complex.d(34): use of complex type 'creal*' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead
-compilable/sw_transition_complex.d(35): use of complex type 'cdouble*' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead
-compilable/sw_transition_complex.d(36): use of complex type 'cfloat*' is scheduled for deprecation, use 'std.complex.Complex!(float)' instead
-compilable/sw_transition_complex.d(38): use of imaginary type 'ireal*' is scheduled for deprecation, use 'real' instead
-compilable/sw_transition_complex.d(39): use of imaginary type 'idouble*' is scheduled for deprecation, use 'double' instead
-compilable/sw_transition_complex.d(40): use of imaginary type 'ifloat*' is scheduled for deprecation, use 'float' instead
+compilable/sw_transition_complex.d(34): Deprecation: use of complex type `creal*` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/sw_transition_complex.d(35): Deprecation: use of complex type `cdouble*` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/sw_transition_complex.d(36): Deprecation: use of complex type `cfloat*` is deprecated, use `std.complex.Complex!(float)` instead
+compilable/sw_transition_complex.d(38): Deprecation: use of imaginary type `ireal*` is deprecated, use `real` instead
+compilable/sw_transition_complex.d(39): Deprecation: use of imaginary type `idouble*` is deprecated, use `double` instead
+compilable/sw_transition_complex.d(40): Deprecation: use of imaginary type `ifloat*` is deprecated, use `float` instead
---
*/
creal* c80pointer;
@@ -42,12 +42,12 @@ ifloat* i32pointer;
/*
TEST_OUTPUT:
---
-compilable/sw_transition_complex.d(53): use of complex type 'creal[]*' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead
-compilable/sw_transition_complex.d(54): use of complex type 'cdouble[]*' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead
-compilable/sw_transition_complex.d(55): use of complex type 'cfloat[]*' is scheduled for deprecation, use 'std.complex.Complex!(float)' instead
-compilable/sw_transition_complex.d(57): use of imaginary type 'ireal[]*' is scheduled for deprecation, use 'real' instead
-compilable/sw_transition_complex.d(58): use of imaginary type 'idouble[]*' is scheduled for deprecation, use 'double' instead
-compilable/sw_transition_complex.d(59): use of imaginary type 'ifloat[]*' is scheduled for deprecation, use 'float' instead
+compilable/sw_transition_complex.d(53): Deprecation: use of complex type `creal[]*` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/sw_transition_complex.d(54): Deprecation: use of complex type `cdouble[]*` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/sw_transition_complex.d(55): Deprecation: use of complex type `cfloat[]*` is deprecated, use `std.complex.Complex!(float)` instead
+compilable/sw_transition_complex.d(57): Deprecation: use of imaginary type `ireal[]*` is deprecated, use `real` instead
+compilable/sw_transition_complex.d(58): Deprecation: use of imaginary type `idouble[]*` is deprecated, use `double` instead
+compilable/sw_transition_complex.d(59): Deprecation: use of imaginary type `ifloat[]*` is deprecated, use `float` instead
---
*/
creal[]* c80arrayp;
@@ -61,12 +61,12 @@ ifloat[]* i32arrayp;
/*
TEST_OUTPUT:
---
-compilable/sw_transition_complex.d(72): use of complex type 'creal[4][]*' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead
-compilable/sw_transition_complex.d(73): use of complex type 'cdouble[4][]*' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead
-compilable/sw_transition_complex.d(74): use of complex type 'cfloat[4][]*' is scheduled for deprecation, use 'std.complex.Complex!(float)' instead
-compilable/sw_transition_complex.d(76): use of imaginary type 'ireal[4][]*' is scheduled for deprecation, use 'real' instead
-compilable/sw_transition_complex.d(77): use of imaginary type 'idouble[4][]*' is scheduled for deprecation, use 'double' instead
-compilable/sw_transition_complex.d(78): use of imaginary type 'ifloat[4][]*' is scheduled for deprecation, use 'float' instead
+compilable/sw_transition_complex.d(72): Deprecation: use of complex type `creal[4][]*` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/sw_transition_complex.d(73): Deprecation: use of complex type `cdouble[4][]*` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/sw_transition_complex.d(74): Deprecation: use of complex type `cfloat[4][]*` is deprecated, use `std.complex.Complex!(float)` instead
+compilable/sw_transition_complex.d(76): Deprecation: use of imaginary type `ireal[4][]*` is deprecated, use `real` instead
+compilable/sw_transition_complex.d(77): Deprecation: use of imaginary type `idouble[4][]*` is deprecated, use `double` instead
+compilable/sw_transition_complex.d(78): Deprecation: use of imaginary type `ifloat[4][]*` is deprecated, use `float` instead
---
*/
creal[4][]* c80sarrayp;
@@ -80,14 +80,14 @@ ifloat[4][]* i32sarrayp;
/*
TEST_OUTPUT:
---
-compilable/sw_transition_complex.d(96): use of complex type 'creal' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead
-compilable/sw_transition_complex.d(97): use of complex type 'creal*' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead
-compilable/sw_transition_complex.d(98): use of complex type 'creal[]' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead
-compilable/sw_transition_complex.d(99): use of complex type 'creal[4]' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead
-compilable/sw_transition_complex.d(101): use of imaginary type 'ireal' is scheduled for deprecation, use 'real' instead
-compilable/sw_transition_complex.d(102): use of imaginary type 'ireal*' is scheduled for deprecation, use 'real' instead
-compilable/sw_transition_complex.d(103): use of imaginary type 'ireal[]' is scheduled for deprecation, use 'real' instead
-compilable/sw_transition_complex.d(104): use of imaginary type 'ireal[4]' is scheduled for deprecation, use 'real' instead
+compilable/sw_transition_complex.d(96): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/sw_transition_complex.d(97): Deprecation: use of complex type `creal*` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/sw_transition_complex.d(98): Deprecation: use of complex type `creal[]` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/sw_transition_complex.d(99): Deprecation: use of complex type `creal[4]` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/sw_transition_complex.d(101): Deprecation: use of imaginary type `ireal` is deprecated, use `real` instead
+compilable/sw_transition_complex.d(102): Deprecation: use of imaginary type `ireal*` is deprecated, use `real` instead
+compilable/sw_transition_complex.d(103): Deprecation: use of imaginary type `ireal[]` is deprecated, use `real` instead
+compilable/sw_transition_complex.d(104): Deprecation: use of imaginary type `ireal[4]` is deprecated, use `real` instead
---
*/
alias C14488 = creal;
@@ -106,10 +106,10 @@ I14488[4] ialias4;
/*
TEST_OUTPUT:
---
-compilable/sw_transition_complex.d(115): use of complex type 'cdouble' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead
-compilable/sw_transition_complex.d(116): use of imaginary type 'idouble' is scheduled for deprecation, use 'double' instead
-compilable/sw_transition_complex.d(117): use of complex type 'cdouble' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead
-compilable/sw_transition_complex.d(118): use of complex type 'cdouble[]' is scheduled for deprecation, use 'std.complex.Complex!(double)' instead
+compilable/sw_transition_complex.d(115): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/sw_transition_complex.d(116): Deprecation: use of imaginary type `idouble` is deprecated, use `double` instead
+compilable/sw_transition_complex.d(117): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/sw_transition_complex.d(118): Deprecation: use of complex type `cdouble[]` is deprecated, use `std.complex.Complex!(double)` instead
---
*/
auto cauto = 1 + 0i;
@@ -120,9 +120,9 @@ TypeInfo c64ti = typeid(cdouble[]);
/*
TEST_OUTPUT:
---
-compilable/sw_transition_complex.d(128): use of complex type 'creal*' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead
-compilable/sw_transition_complex.d(128): use of imaginary type 'ireal' is scheduled for deprecation, use 'real' instead
-compilable/sw_transition_complex.d(132): use of complex type 'creal' is scheduled for deprecation, use 'std.complex.Complex!(real)' instead
+compilable/sw_transition_complex.d(128): Deprecation: use of complex type `creal*` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/sw_transition_complex.d(128): Deprecation: use of imaginary type `ireal` is deprecated, use `real` instead
+compilable/sw_transition_complex.d(132): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
---
*/
void test14488a(creal *p, real r, ireal i)
@@ -134,3 +134,41 @@ creal test14488b()
return 1 + 0i;
}
+// Forward referenced types shouldn't cause errors during test for complex or imaginary.
+enum E;
+struct S;
+
+void test14488c(E *e, S *s)
+{
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=18212
+// Usage of cfloat,cdouble,cfloat,ifloat,idouble,ireal shouldn't trigger an error in deprecated code
+deprecated void test18212(creal c){}
+deprecated unittest
+{
+ ireal a = 2i;
+ creal b = 2 + 3i;
+}
+deprecated struct Foo
+{
+ ifloat a = 2i;
+ cfloat b = 2f + 2i;
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=18218
+static assert(__traits(isDeprecated, cfloat));
+static assert(__traits(isDeprecated, cdouble));
+static assert(__traits(isDeprecated, creal));
+static assert(__traits(isDeprecated, ifloat));
+static assert(__traits(isDeprecated, idouble));
+static assert(__traits(isDeprecated, ireal));
+static assert(!__traits(isDeprecated, float));
+static assert(!__traits(isDeprecated, double));
+static assert(!__traits(isDeprecated, real));
+static assert(!__traits(isDeprecated, int));
+static assert(!__traits(isDeprecated, long));
+static assert(!__traits(isDeprecated, ubyte));
+static assert(!__traits(isDeprecated, char));
+static assert(!__traits(isDeprecated, bool));
+static assert(!__traits(isDeprecated, S));
diff --git a/gcc/testsuite/gdc.test/compilable/sw_transition_field.d b/gcc/testsuite/gdc.test/compilable/sw_transition_field.d
index 83dd261..97c8ee5 100644
--- a/gcc/testsuite/gdc.test/compilable/sw_transition_field.d
+++ b/gcc/testsuite/gdc.test/compilable/sw_transition_field.d
@@ -1,12 +1,12 @@
// PERMUTE_ARGS:
-// REQUIRED_ARGS: -c -transition=field
+// REQUIRED_ARGS: -transition=field
/*
TEST_OUTPUT:
---
-compilable/sw_transition_field.d(15): sw_transition_field.S1.ix is immutable field
-compilable/sw_transition_field.d(16): sw_transition_field.S1.cx is const field
-compilable/sw_transition_field.d(21): sw_transition_field.S2!(immutable(int)).S2.f is immutable field
-compilable/sw_transition_field.d(21): sw_transition_field.S2!(const(int)).S2.f is const field
+compilable/sw_transition_field.d(15): `sw_transition_field.S1.ix` is `immutable` field
+compilable/sw_transition_field.d(16): `sw_transition_field.S1.cx` is `const` field
+compilable/sw_transition_field.d(21): `sw_transition_field.S2!(immutable(int)).S2.f` is `immutable` field
+compilable/sw_transition_field.d(21): `sw_transition_field.S2!(const(int)).S2.f` is `const` field
---
*/
diff --git a/gcc/testsuite/gdc.test/compilable/sw_transition_tls.d b/gcc/testsuite/gdc.test/compilable/sw_transition_tls.d
index 1085e80..7954d50 100644
--- a/gcc/testsuite/gdc.test/compilable/sw_transition_tls.d
+++ b/gcc/testsuite/gdc.test/compilable/sw_transition_tls.d
@@ -1,10 +1,10 @@
// PERMUTE_ARGS:
-// REQUIRED_ARGS: -c -transition=tls
+// REQUIRED_ARGS: -transition=tls
/*
TEST_OUTPUT:
---
-compilable/sw_transition_tls.d(11): x is thread local
-compilable/sw_transition_tls.d(15): y is thread local
+compilable/sw_transition_tls.d(11): `x` is thread local
+compilable/sw_transition_tls.d(15): `y` is thread local
---
*/
diff --git a/gcc/testsuite/gdc.test/compilable/test1.d b/gcc/testsuite/gdc.test/compilable/test1.d
index 80c382b..d20d0a9 100644
--- a/gcc/testsuite/gdc.test/compilable/test1.d
+++ b/gcc/testsuite/gdc.test/compilable/test1.d
@@ -1,5 +1,5 @@
// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/test1imp.d
class File
{
import imports.test1imp;
diff --git a/gcc/testsuite/gdc.test/compilable/test10312.d b/gcc/testsuite/gdc.test/compilable/test10312.d
index db56bc2..7cb50f2 100644
--- a/gcc/testsuite/gdc.test/compilable/test10312.d
+++ b/gcc/testsuite/gdc.test/compilable/test10312.d
@@ -1,5 +1,5 @@
-version(D_SIMD)
+static if (__traits(compiles, __vector(float[4])))
{
const __vector(float[4]) si = [1f, 1f, 1f, 1f];
diff --git a/gcc/testsuite/gdc.test/compilable/test10375.d b/gcc/testsuite/gdc.test/compilable/test10375.d
index b9704f6..ba90fa5 100644
--- a/gcc/testsuite/gdc.test/compilable/test10375.d
+++ b/gcc/testsuite/gdc.test/compilable/test10375.d
@@ -1,5 +1,5 @@
// REQUIRED_ARGS: -o-
-
+// EXTRA_FILES: imports/test10375a.d
import imports.test10375a;
void packIt(Pack)(Pack p){ } //3
diff --git a/gcc/testsuite/gdc.test/compilable/test10520.d b/gcc/testsuite/gdc.test/compilable/test10520.d
index 9a24d84..d03b903 100644
--- a/gcc/testsuite/gdc.test/compilable/test10520.d
+++ b/gcc/testsuite/gdc.test/compilable/test10520.d
@@ -1,11 +1,12 @@
// REQUIRED_ARGS: -debug -profile
-// Issue 10520 [profile+nothrow] Building with profiler results in "is not nothrow" error on some contracts
+// https://issues.dlang.org/show_bug.cgi?id=10520
+// [profile+nothrow] Building with profiler results in "is not nothrow" error on some contracts
void f() { }
void g()()
in { f(); } // OK <- Error: 'main.f' is not nothrow
-body { }
+do { }
alias gi = g!();
diff --git a/gcc/testsuite/gdc.test/compilable/test10752.d b/gcc/testsuite/gdc.test/compilable/test10752.d
index 449377e..1017e0f 100644
--- a/gcc/testsuite/gdc.test/compilable/test10752.d
+++ b/gcc/testsuite/gdc.test/compilable/test10752.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/test10752.d
import imports.test10752;
void main()
{
diff --git a/gcc/testsuite/gdc.test/compilable/test10981.d b/gcc/testsuite/gdc.test/compilable/test10981.d
index f0a6820..961e07d 100644
--- a/gcc/testsuite/gdc.test/compilable/test10981.d
+++ b/gcc/testsuite/gdc.test/compilable/test10981.d
@@ -6,7 +6,7 @@ in
void in_nested() pure
in { assert(i); } // OK <- NG
out { assert(i); } // OK <- NG
- body {}
+ do {}
}
}
out
@@ -16,9 +16,9 @@ out
void out_nested() pure
in { assert(i); } // OK <- NG
out { assert(i); } // OK <- NG
- body {}
+ do {}
}
}
-body
+do
{
}
diff --git a/gcc/testsuite/gdc.test/compilable/test10993.d b/gcc/testsuite/gdc.test/compilable/test10993.d
index e5a1b84..a69d0c6 100644
--- a/gcc/testsuite/gdc.test/compilable/test10993.d
+++ b/gcc/testsuite/gdc.test/compilable/test10993.d
@@ -1,5 +1,7 @@
module test10993;
+import core.demangle : demangleType;
+
auto foo(T)(T a)
{
static immutable typeof(a) q;
@@ -29,5 +31,7 @@ void main()
auto y = cast()x;
enum mangle_y = typeof(y).mangleof;
// pragma(msg, "y : " ~ mangle_y);
- static assert (mangle_y == mangle_x[1..$]);
+ enum demangle_x = demangleType(mangle_x);
+ enum demangle_y = demangleType(mangle_y);
+ static assert ("immutable(" ~ demangle_y ~ ")" == demangle_x);
}
diff --git a/gcc/testsuite/gdc.test/compilable/test11169.d b/gcc/testsuite/gdc.test/compilable/test11169.d
index 79863e1..edf1376 100644
--- a/gcc/testsuite/gdc.test/compilable/test11169.d
+++ b/gcc/testsuite/gdc.test/compilable/test11169.d
@@ -47,7 +47,7 @@ void main()
class B : A
{
// __traits(isAbstractClass) is not usable in static if condition.
- static assert (!__traits(isAbstractClass, typeof(this)));
+ static assert (!__traits(isAbstractClass, typeof(this)));
override void foo()
{
diff --git a/gcc/testsuite/gdc.test/compilable/test11225a.d b/gcc/testsuite/gdc.test/compilable/test11225a.d
index 58df827..3333945 100644
--- a/gcc/testsuite/gdc.test/compilable/test11225a.d
+++ b/gcc/testsuite/gdc.test/compilable/test11225a.d
@@ -1,4 +1,5 @@
/*
+EXTRA_FILES: imports/test11225b.d imports/test11225c.d
TEST_OUTPUT:
---
WORKS
diff --git a/gcc/testsuite/gdc.test/compilable/test11237.d b/gcc/testsuite/gdc.test/compilable/test11237.d
deleted file mode 100644
index 1700af4..0000000
--- a/gcc/testsuite/gdc.test/compilable/test11237.d
+++ /dev/null
@@ -1,4 +0,0 @@
-// PERMUTE_ARGS:
-// POST_SCRIPT: compilable/extra-files/test11237.sh
-
-struct Buffer { ubyte[64 * 1024] buffer; }
diff --git a/gcc/testsuite/gdc.test/compilable/test11259.d b/gcc/testsuite/gdc.test/compilable/test11259.d
new file mode 100644
index 0000000..209d5e1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test11259.d
@@ -0,0 +1,25 @@
+// https://issues.dlang.org/show_bug.cgi?id=11259
+
+version (Posix)
+{
+ // smallest druntime module without imports on posix
+ import core.sys.posix.libgen;
+ static assert(__traits(isSame, __traits(parent, core.sys.posix.libgen), core.sys.posix));
+ static assert(__traits(isSame, core.sys.posix, __traits(parent, core.sys.posix.libgen)));
+
+ static assert(__traits(isSame, __traits(parent, core.sys.posix), core.sys));
+ static assert(__traits(isSame, core.sys, __traits(parent, core.sys.posix)));
+}
+else
+{
+ // smallest module without imports for windows
+ import core.sys.windows.lmuseflg;
+ static assert(__traits(isSame, __traits(parent, core.sys.windows.lmuseflg), core.sys.windows));
+ static assert(__traits(isSame, core.sys.windows, __traits(parent, core.sys.windows.lmuseflg)));
+
+ static assert(__traits(isSame, __traits(parent, core.sys.windows), core.sys));
+ static assert(__traits(isSame, core.sys, __traits(parent, core.sys.windows)));
+}
+
+static assert(__traits(isSame, __traits(parent, core.sys), core));
+static assert(__traits(isSame, core, __traits(parent, core.sys)));
diff --git a/gcc/testsuite/gdc.test/compilable/test11371.d b/gcc/testsuite/gdc.test/compilable/test11371.d
index c522929..97ca2b5 100644
--- a/gcc/testsuite/gdc.test/compilable/test11371.d
+++ b/gcc/testsuite/gdc.test/compilable/test11371.d
@@ -1,5 +1,5 @@
-version(D_SIMD)
+static if (__traits(compiles, __vector(long[2])))
{
__vector(long[2]) f()
{
diff --git a/gcc/testsuite/gdc.test/compilable/test11563.d b/gcc/testsuite/gdc.test/compilable/test11563.d
index 6fb39fe..3b4af9a 100644
--- a/gcc/testsuite/gdc.test/compilable/test11563.d
+++ b/gcc/testsuite/gdc.test/compilable/test11563.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/test11563core_bitop.d imports/test11563std_array.d imports/test11563std_range.d imports/test11563std_traits.d
import imports.test11563std_traits;
interface J : I {} // comment out to let compilation succeed
diff --git a/gcc/testsuite/gdc.test/compilable/test11656.d b/gcc/testsuite/gdc.test/compilable/test11656.d
index 4de3065..226144f 100644
--- a/gcc/testsuite/gdc.test/compilable/test11656.d
+++ b/gcc/testsuite/gdc.test/compilable/test11656.d
@@ -1,5 +1,5 @@
-version(D_SIMD)
+static if (__traits(compiles, __vector(float[4])))
{
struct Foo
{
diff --git a/gcc/testsuite/gdc.test/compilable/test1170.d b/gcc/testsuite/gdc.test/compilable/test1170.d
new file mode 100644
index 0000000..767101fa
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test1170.d
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=1170
+type x;
+mixin("alias int type;");
+
+// https://issues.dlang.org/show_bug.cgi?id=10739
+template DECLARE_HANDLE() {
+ struct HINTERNET { int h; }
+}
+const INTERNET_INVALID_STATUS_CALLBACK = cast(INTERNET_STATUS_CALLBACK) -1;
+mixin DECLARE_HANDLE;
+alias void function(HINTERNET) INTERNET_STATUS_CALLBACK;
diff --git a/gcc/testsuite/gdc.test/compilable/test11847.d b/gcc/testsuite/gdc.test/compilable/test11847.d
new file mode 100644
index 0000000..d07d995
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test11847.d
@@ -0,0 +1,14 @@
+// REQUIRED_ARGS: -Icompilable/imports
+// EXTRA_FILES: imports/pkg11847/mod11847.d imports/pkg11847/package.d
+import pkg11847;
+import pkg11847.mod11847;
+
+void main() {
+ static assert(pkg11847.func() == 1);
+ static assert(pkg11847.mod11847.func() == 2);
+
+ // This correctly won't compile.
+ // Error: pkg11847.mod11847.func at imports/pkg11847/mod11847.d(3) conflicts with pkg11847.func at imports/pkg11847/package.d(3)
+ static assert(!__traits(compiles, func()));
+
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test1238.d b/gcc/testsuite/gdc.test/compilable/test1238.d
index fa19d61..0cbd84d 100644
--- a/gcc/testsuite/gdc.test/compilable/test1238.d
+++ b/gcc/testsuite/gdc.test/compilable/test1238.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/test1238a.d imports/test1238b.d
module test1238;
import imports.test1238a;
diff --git a/gcc/testsuite/gdc.test/compilable/test12496.d b/gcc/testsuite/gdc.test/compilable/test12496.d
new file mode 100644
index 0000000..4de2b71
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test12496.d
@@ -0,0 +1,13 @@
+// https://issues.dlang.org/show_bug.cgi?id=12496
+
+final abstract class T1
+{
+ final abstract class C(uint value) { }
+
+ alias Child = C!2;
+}
+
+void main()
+{
+ static assert(__traits(isSame, __traits(parent, T1.Child), T1));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test12511.d b/gcc/testsuite/gdc.test/compilable/test12511.d
new file mode 100644
index 0000000..0a2fc75
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test12511.d
@@ -0,0 +1,15 @@
+// EXTRA_FILES: imports/a12511.d
+module test12511;
+
+import imports.a12511;
+
+public class B
+{
+ static void bar()
+ {
+ A.foo(0);
+ }
+}
+
+void main()
+{}
diff --git a/gcc/testsuite/gdc.test/compilable/test12558.d b/gcc/testsuite/gdc.test/compilable/test12558.d
deleted file mode 100644
index 580cf60..0000000
--- a/gcc/testsuite/gdc.test/compilable/test12558.d
+++ /dev/null
@@ -1,39 +0,0 @@
-// REQUIRED_ARGS:
-/*
-TEST_OUTPUT:
----
-compilable/test12558.d(16): Deprecation: catch statement without an exception specification is deprecated; use catch(Throwable) for old behavior
-compilable/test12558.d(21): Deprecation: catch statement without an exception specification is deprecated; use catch(Throwable) for old behavior
----
-*/
-
-void main()
-{
- auto handler = () { };
-
- try {
- assert(0);
- } catch
- handler();
-
- try {
- assert(0);
- } catch {
- handler();
- }
-
- // ensure diagnostics are not emitted for verioned-out blocks
- version (none)
- {
- try {
- assert(0);
- } catch // should not emit diagnostics
- handler();
-
- try {
- assert(0);
- } catch { // ditto
- handler();
- }
- }
-}
diff --git a/gcc/testsuite/gdc.test/compilable/test12567c.d b/gcc/testsuite/gdc.test/compilable/test12567c.d
index cadc375..9a686df 100644
--- a/gcc/testsuite/gdc.test/compilable/test12567c.d
+++ b/gcc/testsuite/gdc.test/compilable/test12567c.d
@@ -1,9 +1,10 @@
// REQUIRED_ARGS:
+// EXTRA_FILES: imports/a12567.d
// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-compilable/test12567c.d(9): Deprecation: module imports.a12567 is deprecated - This module will be removed in future release.
+compilable/test12567c.d(10): Deprecation: module `imports.a12567` is deprecated - This module will be removed in future release.
---
*/
import imports.a12567;
diff --git a/gcc/testsuite/gdc.test/compilable/test12567d.d b/gcc/testsuite/gdc.test/compilable/test12567d.d
index ee7bc29..5ad9b5c 100644
--- a/gcc/testsuite/gdc.test/compilable/test12567d.d
+++ b/gcc/testsuite/gdc.test/compilable/test12567d.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -d
+// EXTRA_FILES: imports/a12567.d
// PERMUTE_ARGS:
import imports.a12567;
diff --git a/gcc/testsuite/gdc.test/compilable/test12807.d b/gcc/testsuite/gdc.test/compilable/test12807.d
new file mode 100644
index 0000000..72de658
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test12807.d
@@ -0,0 +1,16 @@
+void foo(T)(ref T t)
+{
+}
+
+struct S
+{
+ int impure() {assert(0);}
+ alias impure this;
+}
+
+void main() pure
+{
+ S s;
+ foo(s);
+ s.foo(); // triggering alias this violates purity, but ufcs matches
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test13226.d b/gcc/testsuite/gdc.test/compilable/test13226.d
index 65bf335..10407bd 100644
--- a/gcc/testsuite/gdc.test/compilable/test13226.d
+++ b/gcc/testsuite/gdc.test/compilable/test13226.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -o-
+// EXTRA_FILES: imports/a13226.d
// PERMUTE_ARGS: -version=bug
import imports.a13226;
diff --git a/gcc/testsuite/gdc.test/compilable/test13242.d b/gcc/testsuite/gdc.test/compilable/test13242.d
index 0d6ef27..86f763f 100644
--- a/gcc/testsuite/gdc.test/compilable/test13242.d
+++ b/gcc/testsuite/gdc.test/compilable/test13242.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -o-
+// EXTRA_FILES: imports/test13242a.d imports/test13242b.d
/*
TEST_OUTPUT:
---
diff --git a/gcc/testsuite/gdc.test/compilable/test13512.d b/gcc/testsuite/gdc.test/compilable/test13512.d
index bc78bd4..6484188 100644
--- a/gcc/testsuite/gdc.test/compilable/test13512.d
+++ b/gcc/testsuite/gdc.test/compilable/test13512.d
@@ -1,8 +1,8 @@
#!/opt/dmd/ÐÒÏÂÙ/rdmd
-import std.stdio;
+import core.stdc.stdio;
void main () {
- writeln("we are here!");
+ printf("we are here!\n");
}
diff --git a/gcc/testsuite/gdc.test/compilable/test13582a.d b/gcc/testsuite/gdc.test/compilable/test13582a.d
new file mode 100644
index 0000000..4e3f2bb
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test13582a.d
@@ -0,0 +1,7 @@
+// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/test13582.d
+deprecated module test13582a;
+
+import imports.test13582;
+
+void main() { }
diff --git a/gcc/testsuite/gdc.test/compilable/test13582b.d b/gcc/testsuite/gdc.test/compilable/test13582b.d
new file mode 100644
index 0000000..89ec251
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test13582b.d
@@ -0,0 +1,15 @@
+// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/test13582.d
+module test13582b;
+
+deprecated void foo()
+{
+ import imports.test13582;
+}
+
+deprecated struct S
+{
+ import imports.test13582;
+}
+
+void main() { }
diff --git a/gcc/testsuite/gdc.test/compilable/test13858.d b/gcc/testsuite/gdc.test/compilable/test13858.d
index 5a0432c..98b0796 100644
--- a/gcc/testsuite/gdc.test/compilable/test13858.d
+++ b/gcc/testsuite/gdc.test/compilable/test13858.d
@@ -1,5 +1,5 @@
// REQUIRED_ARGS: -w
-// 13858
+// https://issues.dlang.org/show_bug.cgi?id=13858
void foo() { assert(0); }
diff --git a/gcc/testsuite/gdc.test/compilable/test13953.d b/gcc/testsuite/gdc.test/compilable/test13953.d
new file mode 100644
index 0000000..cde7d91
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test13953.d
@@ -0,0 +1,14 @@
+// https://issues.dlang.org/show_bug.cgi?id=13953
+
+struct S
+{
+ string[string] aa;
+ alias aa this;
+}
+
+void main()
+{
+ S s;
+ s["foo"] = "bar";
+ s.remove("foo");
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test14114.d b/gcc/testsuite/gdc.test/compilable/test14114.d
new file mode 100644
index 0000000..246277b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test14114.d
@@ -0,0 +1,10 @@
+// REQUIRED_ARGS: -O
+
+// https://issues.dlang.org/show_bug.cgi?id=14114
+
+import core.volatile;
+
+struct Ports {
+ static ubyte B() { return volatileLoad(cast(ubyte *)0x0025); }
+ static void B(ubyte value) { volatileStore(cast(ubyte *)0x0025, value); }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test14275.d b/gcc/testsuite/gdc.test/compilable/test14275.d
index 66f899c..7ce66aa 100644
--- a/gcc/testsuite/gdc.test/compilable/test14275.d
+++ b/gcc/testsuite/gdc.test/compilable/test14275.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -o-
+// EXTRA_FILES: protection/bug/bug14275.d protection/aggregate/mod14275.d
// PERMUTE_ARGS:
import protection.bug.bug14275;
diff --git a/gcc/testsuite/gdc.test/compilable/test14528.d b/gcc/testsuite/gdc.test/compilable/test14528.d
index badab92..32d99db 100644
--- a/gcc/testsuite/gdc.test/compilable/test14528.d
+++ b/gcc/testsuite/gdc.test/compilable/test14528.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -o-
+// EXTRA_FILES: imports/a14528.d
// PERMTE_ARGS:
import imports.a14528;
diff --git a/gcc/testsuite/gdc.test/compilable/test14666.d b/gcc/testsuite/gdc.test/compilable/test14666.d
index 6162dd9..198b717 100644
--- a/gcc/testsuite/gdc.test/compilable/test14666.d
+++ b/gcc/testsuite/gdc.test/compilable/test14666.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -o-
+// EXTRA_FILES: imports/test14666a.d imports/test14666b.d
// PERMUTE_ARGS:
module test14666;
diff --git a/gcc/testsuite/gdc.test/compilable/test14740.d b/gcc/testsuite/gdc.test/compilable/test14740.d
new file mode 100644
index 0000000..29c3459
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test14740.d
@@ -0,0 +1,10 @@
+// https://issues.dlang.org/show_bug.cgi?id=14740
+
+void test()
+{
+ struct S
+ {
+ void fun() {}
+ }
+ static assert([__traits(allMembers, S)] == ["fun"]);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test14831.d b/gcc/testsuite/gdc.test/compilable/test14831.d
new file mode 100644
index 0000000..c825e69
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test14831.d
@@ -0,0 +1,60 @@
+// https://issues.dlang.org/show_bug.cgi?id=14831
+
+void main()
+{
+ {
+ int x;
+ static assert(x.mangleof == "_D9test148314mainFZ1xi");
+ }
+ {
+ int x;
+ static assert(x.mangleof == "_D9test148314mainFZ4__S11xi");
+ }
+
+ {
+ static int y = 0;
+ static assert(y.mangleof == "_D9test148314mainFZ1yi");
+ }
+ {
+ static int y = 0;
+ static assert(y.mangleof == "_D9test148314mainFZ4__S11yi");
+ }
+
+ {
+ void f() {}
+ static assert(f.mangleof == "_D9test148314mainFZ1fMFNaNbNiNfZv");
+ }
+ {
+ void f() {}
+ static assert(f.mangleof == "_D9test148314mainFZ4__S11fMFNaNbNiNfZv");
+ }
+
+ {
+ struct S {}
+ static assert(S.mangleof == "S9test148314mainFZ1S");
+ }
+ {
+ struct S {}
+ static assert(S.mangleof == "S9test148314mainFZ4__S11S");
+ }
+
+ {
+ class C {}
+ static assert(C.mangleof == "C9test148314mainFZ1C");
+ }
+ {
+ class C {}
+ static assert(C.mangleof == "C9test148314mainFZ4__S11C");
+ }
+
+ {
+ enum E { a }
+ static assert(E.mangleof == "E9test148314mainFZ1E");
+ static assert(E.a.mangleof == "_D9test148314mainFZ1E1aEQwQoFZQl");
+ }
+ {
+ enum E { a }
+ static assert(E.mangleof == "E9test148314mainFZ4__S11E");
+ static assert(E.a.mangleof == "_D9test148314mainFZ4__S11E1aEQBbQuFZ4__S1Qr");
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14929.d b/gcc/testsuite/gdc.test/compilable/test14929.d
index 01edc0d..1b794a6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14929.d
+++ b/gcc/testsuite/gdc.test/compilable/test14929.d
@@ -1,14 +1,3 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/ice14929.d(45): Error: cast(Node)(*this.current).items[this.index] is not an lvalue
-fail_compilation/ice14929.d(88): Error: template instance ice14929.HashMap!(ulong, int).HashMap.opBinaryRight!"in" error instantiating
-fail_compilation/ice14929.d(92): instantiated from here: HashmapComponentStorage!int
-fail_compilation/ice14929.d(92): Error: template instance ice14929.isComponentStorage!(HashmapComponentStorage!int, int) error instantiating
-fail_compilation/ice14929.d(92): while evaluating: `static assert(isComponentStorage!(HashmapComponentStorage!int, int))`
----
-*/
-
struct HashMap(K, V)
{
V* opBinaryRight(string op)(K key) const if (op == "in")
@@ -75,7 +64,7 @@ template isComponentStorage(CS, C)
{
CS cs = CS.init;
ulong eid;
- cs.add(eid, c);
+ cs.add(eid, C.init);
}));
}
diff --git a/gcc/testsuite/gdc.test/compilable/test15019.d b/gcc/testsuite/gdc.test/compilable/test15019.d
index 963dba8..41444ce 100644
--- a/gcc/testsuite/gdc.test/compilable/test15019.d
+++ b/gcc/testsuite/gdc.test/compilable/test15019.d
@@ -1,3 +1,4 @@
+// COMPILABLE_MATH_TEST
// https://issues.dlang.org/show_bug.cgi?id=15019
// dmd -m32 -c all.d
@@ -24,7 +25,7 @@ struct Matrix(T, int R, int C)
{
try
return format("%s", v);
- catch
+ catch (Throwable)
assert(false); // should not happen since format is right
}
}
@@ -67,7 +68,7 @@ struct Vector(T, int N)
{
try
return format("%s", v);
- catch
+ catch (Throwable)
assert(false);
}
}
diff --git a/gcc/testsuite/gdc.test/compilable/test15150.d b/gcc/testsuite/gdc.test/compilable/test15150.d
index 3a00b80..5c2d421 100644
--- a/gcc/testsuite/gdc.test/compilable/test15150.d
+++ b/gcc/testsuite/gdc.test/compilable/test15150.d
@@ -1,5 +1,5 @@
// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/test15150a.d imports/test15150b.d
module test15150;
import imports.test15150a;
diff --git a/gcc/testsuite/gdc.test/compilable/test15225.d b/gcc/testsuite/gdc.test/compilable/test15225.d
new file mode 100644
index 0000000..d60fba1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test15225.d
@@ -0,0 +1,9 @@
+// https://issues.dlang.org/show_bug.cgi?id=15225
+
+alias foo = (int x) => x + 1;
+alias foo = (string x) => x ~ x;
+alias foo = (float x) => x - x;
+
+static assert( foo(1) == 2 );
+static assert( foo("a") == "aa");
+static assert(foo(2.0f) == 0.0f);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15292.d b/gcc/testsuite/gdc.test/compilable/test15292.d
index 3b3602f..38c727b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail15292.d
+++ b/gcc/testsuite/gdc.test/compilable/test15292.d
@@ -1,11 +1,3 @@
-// REQUIRED_ARGS: -o-
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail15292.d(27): Error: cannot compare S15292 because its auto generated member-wise equality has recursive definition
----
-*/
-
struct NullableRef15292(T)
{
inout(T) get() inout
diff --git a/gcc/testsuite/gdc.test/compilable/test1537.d b/gcc/testsuite/gdc.test/compilable/test1537.d
index a1717ab..0878b97 100644
--- a/gcc/testsuite/gdc.test/compilable/test1537.d
+++ b/gcc/testsuite/gdc.test/compilable/test1537.d
@@ -1,4 +1,4 @@
-// 1537
+// https://issues.dlang.org/show_bug.cgi?id=1537
void foo(char[] s)
{
@@ -56,10 +56,10 @@ int bug5245d(U)()
}
-static assert(!is(typeof(Compileable!(bug5245a!(int)()).OK)));
-static assert(!is(typeof(Compileable!(bug5245b!(int)()).OK)));
-static assert(!is(typeof(Compileable!(bug5245c!(int)()).OK)));
-static assert(!is(typeof(Compileable!(bug5245d!(int)()).OK)));
+static assert(is(typeof(Compileable!(bug5245a!(int)()).OK)));
+static assert(is(typeof(Compileable!(bug5245b!(int)()).OK)));
+static assert(is(typeof(Compileable!(bug5245c!(int)()).OK)));
+static assert(is(typeof(Compileable!(bug5245d!(int)()).OK)));
/**************************************/
diff --git a/gcc/testsuite/gdc.test/compilable/test15389_x.d b/gcc/testsuite/gdc.test/compilable/test15389_x.d
index 896f81a..4cfabac 100644
--- a/gcc/testsuite/gdc.test/compilable/test15389_x.d
+++ b/gcc/testsuite/gdc.test/compilable/test15389_x.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: test15389_y.d
import test15389_y;
//struct ns
diff --git a/gcc/testsuite/gdc.test/compilable/test15389_y.d b/gcc/testsuite/gdc.test/compilable/test15389_y.d
index 35e6a25..78f4779 100644
--- a/gcc/testsuite/gdc.test/compilable/test15389_y.d
+++ b/gcc/testsuite/gdc.test/compilable/test15389_y.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: test15389_x.d
import test15389_x;
//struct ns
diff --git a/gcc/testsuite/gdc.test/compilable/test1547.d b/gcc/testsuite/gdc.test/compilable/test1547.d
new file mode 100644
index 0000000..30c6564
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test1547.d
@@ -0,0 +1,20 @@
+// https://issues.dlang.org/show_bug.cgi?id=1547
+
+struct A
+{
+ int b;
+ static A opCall(int k)
+ {
+ A a;
+ a.b = k;
+ return a;
+ }
+}
+
+void fun(A k = 2) {}
+
+void main()
+{
+ A a = 7;
+ fun();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test15490.d b/gcc/testsuite/gdc.test/compilable/test15490.d
index eab5c61..bd8e668 100644
--- a/gcc/testsuite/gdc.test/compilable/test15490.d
+++ b/gcc/testsuite/gdc.test/compilable/test15490.d
@@ -1,5 +1,6 @@
// REQUIRED_ARGS: -o- -inline
// PERMUTE_ARGS:
+// EXTRA_FILES: imports/imp15490a.d imports/imp15490b.d
module test15490;
import imports.imp15490a;
diff --git a/gcc/testsuite/gdc.test/compilable/test15519_x.d b/gcc/testsuite/gdc.test/compilable/test15519_x.d
index 53cfe92..d647b04 100644
--- a/gcc/testsuite/gdc.test/compilable/test15519_x.d
+++ b/gcc/testsuite/gdc.test/compilable/test15519_x.d
@@ -1,4 +1,4 @@
-
+// EXTRA_FILES: test15519_y.d
import test15519_y;
extern(C++, ns)
diff --git a/gcc/testsuite/gdc.test/compilable/test15519_y.d b/gcc/testsuite/gdc.test/compilable/test15519_y.d
index 58db30b..e87a4e1 100644
--- a/gcc/testsuite/gdc.test/compilable/test15519_y.d
+++ b/gcc/testsuite/gdc.test/compilable/test15519_y.d
@@ -1,4 +1,4 @@
-
+// EXTRA_FILES: test15519_x.d
import test15519_x: NS = ns; // fails
//import test15519_x; alias test15519_x.ns NS; // works
diff --git a/gcc/testsuite/gdc.test/compilable/test15780.d b/gcc/testsuite/gdc.test/compilable/test15780.d
index 25c64cd..047d5f6 100644
--- a/gcc/testsuite/gdc.test/compilable/test15780.d
+++ b/gcc/testsuite/gdc.test/compilable/test15780.d
@@ -1,17 +1,24 @@
// PERMUTE_ARGS:
// https://issues.dlang.org/show_bug.cgi?id=15780
-import std.typecons;
-//import std.stdio;
-
void foo(alias fields)() {
foreach(i, field; fields) {
enum string a = fields[i]; // OK
enum string b = field; // not OK with 2.069.2 ???
- //writeln(field);
}
}
void main() {
foo!(tuple("H", "I"))();
}
+
+Tuple!T tuple(T...)(T values)
+{
+ return Tuple!T(values);
+}
+
+struct Tuple(T...)
+{
+ T values;
+ alias values this;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test15785.d b/gcc/testsuite/gdc.test/compilable/test15785.d
index 483c080..e7c6617 100644
--- a/gcc/testsuite/gdc.test/compilable/test15785.d
+++ b/gcc/testsuite/gdc.test/compilable/test15785.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/test15785.d
// PERMUTE_ARGS:
import imports.test15785;
@@ -13,5 +14,5 @@ class Derived : Base, IBase2
// IBase2.faz(); // doesn't work yet due to a bug in checkAccess
}
- super.T t;
+ typeof(super).T t;
}
diff --git a/gcc/testsuite/gdc.test/compilable/test15856.d b/gcc/testsuite/gdc.test/compilable/test15856.d
index 8a5c425..3fc1752 100644
--- a/gcc/testsuite/gdc.test/compilable/test15856.d
+++ b/gcc/testsuite/gdc.test/compilable/test15856.d
@@ -1,11 +1,6 @@
// REQUIRED_ARGS: -de
// PERMUTE_ARGS:
-/*
-TEST_PUTPUT:
----
----
-*/
-
+// EXTRA_FILES: imports/a15856.d
class Foo
{
import imports.a15856;
diff --git a/gcc/testsuite/gdc.test/compilable/test15907.d b/gcc/testsuite/gdc.test/compilable/test15907.d
index c362e04..aae4b4d 100644
--- a/gcc/testsuite/gdc.test/compilable/test15907.d
+++ b/gcc/testsuite/gdc.test/compilable/test15907.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/imp15907.d
// PERMUTE_ARGS:
import imports.imp15907;
diff --git a/gcc/testsuite/gdc.test/compilable/test16002.d b/gcc/testsuite/gdc.test/compilable/test16002.d
index f7b4c2e..51c7338 100644
--- a/gcc/testsuite/gdc.test/compilable/test16002.d
+++ b/gcc/testsuite/gdc.test/compilable/test16002.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/plainpackage/plainmodule.d imports/pkgmodule/package.d imports/pkgmodule/plainmodule.d
module test.compilable.test16002;
import imports.plainpackage.plainmodule;
diff --git a/gcc/testsuite/gdc.test/compilable/test16013a.d b/gcc/testsuite/gdc.test/compilable/test16013a.d
new file mode 100644
index 0000000..15eda38
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16013a.d
@@ -0,0 +1,13 @@
+// https://issues.dlang.org/show_bug.cgi?id=16013
+
+struct Impl { S _payload; } /* Only this line has changed from above. */
+
+struct RefCounted
+{
+ void opAssign(RefCounted rhs) {}
+ void opAssign(S rhs) {}
+ S refCountedPayload() { return S.init; }
+ alias refCountedPayload this;
+}
+
+struct S { RefCounted s; }
diff --git a/gcc/testsuite/gdc.test/compilable/test16013b.d b/gcc/testsuite/gdc.test/compilable/test16013b.d
new file mode 100644
index 0000000..97a58e3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16013b.d
@@ -0,0 +1,13 @@
+// https://issues.dlang.org/show_bug.cgi?id=16013
+
+S s; /* Only this line has changed from above. */
+
+struct RefCounted
+{
+ void opAssign(RefCounted rhs) {}
+ void opAssign(S rhs) {}
+ S refCountedPayload() { return S.init; }
+ alias refCountedPayload this;
+}
+
+struct S { RefCounted s; }
diff --git a/gcc/testsuite/gdc.test/compilable/test16037.d b/gcc/testsuite/gdc.test/compilable/test16037.d
new file mode 100644
index 0000000..12c672a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16037.d
@@ -0,0 +1,23 @@
+/* REQUIRED_ARGS: -preview=dip1000
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=16037
+
+@safe:
+
+void testXXX () @nogc
+{
+ Object o;
+ scope bool delegate (Object) alwaysFalse = (Object y) { return false; };
+ scope c1 = o !is null ? (Object y) { return o is y; } : alwaysFalse;
+}
+
+auto f() @nogc
+{
+ int a;
+ void g(){ a=1; }
+ scope h=&g;
+ h();
+}
+
+
diff --git a/gcc/testsuite/gdc.test/compilable/test16085.d b/gcc/testsuite/gdc.test/compilable/test16085.d
index 936a1fb..4f6d801 100644
--- a/gcc/testsuite/gdc.test/compilable/test16085.d
+++ b/gcc/testsuite/gdc.test/compilable/test16085.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/imp16085.d imports/imp16085b.d
// PERMUTE_ARGS:
import imports.imp16085;
diff --git a/gcc/testsuite/gdc.test/compilable/test16088.d b/gcc/testsuite/gdc.test/compilable/test16088.d
new file mode 100644
index 0000000..97326f1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16088.d
@@ -0,0 +1,10 @@
+// REQUIRED_ARGS: -Jcompilable/imports/
+// EXTRA_FILES: imports/imp16088.d
+
+// https://issues.dlang.org/show_bug.cgi?id=16088
+
+void bar(string x) {}
+auto foo()
+{
+ import("imp16088.d").bar;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test16107.d b/gcc/testsuite/gdc.test/compilable/test16107.d
new file mode 100644
index 0000000..2267be3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16107.d
@@ -0,0 +1,14 @@
+// https://issues.dlang.org/show_bug.cgi?id=16107
+
+bool check()
+{
+ bool result = false;
+
+ result |= false;
+ if (result) goto ret;
+
+ result |= false;
+ if (result) {}
+
+ ret: return true;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test16183.d b/gcc/testsuite/gdc.test/compilable/test16183.d
new file mode 100644
index 0000000..ba74110
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16183.d
@@ -0,0 +1,7 @@
+// https://issues.dlang.org/show_bug.cgi?id=16183
+
+void main()
+{
+ const string g(const string s) { return s; }
+ enum string y = ['f'] ~ g("g");
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test16214a.d b/gcc/testsuite/gdc.test/compilable/test16214a.d
index 2ea64d9..f29c5d2 100644
--- a/gcc/testsuite/gdc.test/compilable/test16214a.d
+++ b/gcc/testsuite/gdc.test/compilable/test16214a.d
@@ -1,5 +1,5 @@
-// EXTRA_SOURCES: imports/test16214b.d
// REQUIRED_ARGS: -Icompilable/imports
+// EXTRA_FILES: imports/test16214b.d
module test16214a;
import test16214b;
diff --git a/gcc/testsuite/gdc.test/compilable/test16273.d b/gcc/testsuite/gdc.test/compilable/test16273.d
new file mode 100644
index 0000000..c079f0a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16273.d
@@ -0,0 +1,22 @@
+// https://issues.dlang.org/show_bug.cgi?id=16273
+
+class A()
+{
+ alias MyD = D!();
+}
+
+class B
+{
+ void f() {}
+ alias MyA = A!();
+}
+
+class C : B
+{
+ override void f() {}
+}
+
+class D() : A!()
+{
+ void g() { new C; }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test16460.d b/gcc/testsuite/gdc.test/compilable/test16460.d
index 868e7ec..77193a4 100644
--- a/gcc/testsuite/gdc.test/compilable/test16460.d
+++ b/gcc/testsuite/gdc.test/compilable/test16460.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/imp16460.d
module imports.test16460;
void bug()
diff --git a/gcc/testsuite/gdc.test/compilable/test16492.d b/gcc/testsuite/gdc.test/compilable/test16492.d
new file mode 100644
index 0000000..833be1d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16492.d
@@ -0,0 +1,87 @@
+// ARG_SETS: -debug; -o-; -debug -preview=dip1000
+// https://issues.dlang.org/show_bug.cgi?id=16492
+
+void mayCallGC();
+
+void test() @nogc pure
+{
+ debug new int(1);
+ debug
+ {
+ mayCallGC();
+ auto b = [1, 2, 3];
+ b ~= 4;
+ }
+}
+
+void debugSafe() @safe
+{
+ debug unsafeSystem();
+ debug unsafeTemplated();
+}
+
+void unsafeSystem() @system {}
+void unsafeTemplated()() {
+ int[] arr;
+ auto b = arr.ptr;
+}
+
+void debugSafe2() @safe
+{
+ char[] arr1, arr2;
+ debug unsafeDIP1000Lifetime(arr1, arr2);
+
+ char* ptr;
+ char[] arr;
+ debug ptr = arr.ptr;
+}
+
+void unsafeDIP1000Lifetime()(ref char[] p, scope char[] s)
+{
+ p = s;
+}
+
+
+void test2() nothrow
+{
+ debug throw new Exception("");
+}
+
+void test3() nothrow
+{
+ debug {
+ foreach (_; 0 .. 10) {
+ if (1) {
+ throw new Exception("");
+ }
+ }
+ }
+}
+
+void test4() nothrow
+{
+ debug throwException();
+}
+
+void test5() nothrow
+{
+ debug willThrowException();
+}
+
+void willThrowException()()
+{
+ throwException();
+}
+
+void throwException()
+{
+ throw new Exception("");
+}
+
+void test6() nothrow
+{
+ debug
+ {
+ () {throw new Exception("");}();
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test16570.d b/gcc/testsuite/gdc.test/compilable/test16570.d
index 20b8485..de8b78f 100644
--- a/gcc/testsuite/gdc.test/compilable/test16570.d
+++ b/gcc/testsuite/gdc.test/compilable/test16570.d
@@ -5,4 +5,4 @@ enum Regression
a = _a,
}
-static assert(is(typeof(Regression.a) == Regression));
+static assert(is(typeof(Regression.a) == immutable(Regression)));
diff --git a/gcc/testsuite/gdc.test/compilable/test16578a.d b/gcc/testsuite/gdc.test/compilable/test16578a.d
new file mode 100644
index 0000000..f781fee
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16578a.d
@@ -0,0 +1,16 @@
+// REQUIRED_ARGS: -debug
+
+// https://issues.dlang.org/show_bug.cgi?id=16578
+
+string[string] opts;
+
+void main()
+{
+ string arg;
+ switch (arg)
+ {
+ case "-f": opts["fore"] = ""; break;
+ debug { case "-throw": opts["throw"] = ""; break; }
+ default:
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test16578b.d b/gcc/testsuite/gdc.test/compilable/test16578b.d
new file mode 100644
index 0000000..eccc949
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16578b.d
@@ -0,0 +1,16 @@
+// https://issues.dlang.org/show_bug.cgi?id=16578
+
+void main()
+{
+ string[string] opts;
+ switch (2)
+ {
+ case 0:
+ opts["a"] = "";
+ {
+ case 1:
+ break;
+ }
+ default:
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test16621.d b/gcc/testsuite/gdc.test/compilable/test16621.d
new file mode 100644
index 0000000..d5800b1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16621.d
@@ -0,0 +1,23 @@
+// https://issues.dlang.org/show_bug.cgi?id=16621
+
+template xxx()
+{
+ Vector2f xxx()
+ {
+ return this;
+ }
+}
+
+struct Vector2f
+{
+ mixin xxx!();
+ alias xxx this;
+}
+
+void foo(ref Vector2f pos);
+
+void test()
+{
+ Vector2f v;
+ foo(v);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test16635.d b/gcc/testsuite/gdc.test/compilable/test16635.d
new file mode 100644
index 0000000..5f3d0ba
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16635.d
@@ -0,0 +1,56 @@
+// https://issues.dlang.org/show_bug.cgi?id=16635
+
+struct A
+{
+ alias get this;
+
+ const(A) get() const
+ {
+ return A();
+ }
+}
+
+static assert(!__traits(compiles, A() + A()));
+
+// Original test (covers another path)
+
+struct Vector2
+{
+ float x;
+ float y;
+
+ alias byRef this;
+
+ ref const(Vector2) byRef() const
+ {
+ static Vector2 v;
+ return v;
+ }
+
+ Vector2 opBinary(string op : "+")(ref const(Vector2) a) const
+ {
+ return Vector2(x + a.x, y + a.y);
+ }
+}
+
+void test16635_1()
+{
+ Vector2 a = Vector2(1, 2);
+ Vector2 b = Vector2(3, 4);
+
+ // this line causes application to run infinitely
+ // Already fixed. It was issue 16621
+ Vector2 c = a + b;
+
+ // OK <- this line seg faults without the above line
+ Vector2 d = a + Vector2(5, 6);
+}
+
+void test16635_2()
+{
+ Vector2 a = Vector2(1, 2);
+ Vector2 b = Vector2(3, 4);
+
+ // just this line alone
+ Vector2 d = a + Vector2(5, 6);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test16657.d b/gcc/testsuite/gdc.test/compilable/test16657.d
new file mode 100644
index 0000000..3143ecd
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16657.d
@@ -0,0 +1,17 @@
+struct A
+{
+ int x;
+}
+
+struct B
+{
+ A a, b;
+}
+static assert(B(A(1), A(1)) != B(A(1), A(2))); // Works
+
+struct C
+{
+ A a, b;
+ alias a this;
+}
+static assert(C(A(1), A(1)) != C(A(1), A(2))); // Fails!
diff --git a/gcc/testsuite/gdc.test/compilable/test16685.d b/gcc/testsuite/gdc.test/compilable/test16685.d
new file mode 100644
index 0000000..0be2367
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16685.d
@@ -0,0 +1,6 @@
+// https://issues.dlang.org/show_bug.cgi?id=16685
+
+struct Id { ushort value; }
+enum Id x = Id(5);
+struct S(ushort A) {}
+alias CannotCreateFromValue = S!(x.value);
diff --git a/gcc/testsuite/gdc.test/compilable/test16709.d b/gcc/testsuite/gdc.test/compilable/test16709.d
new file mode 100644
index 0000000..695c92e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test16709.d
@@ -0,0 +1,9 @@
+// EXTRA_FILES: imports/test16709a.d imports/test16709b.d imports/test16709c.d imports/test16709d.d
+// https://issues.dlang.org/show_bug.cgi?id=16709
+
+import imports.test16709a;
+import imports.test16709b;
+
+void test(){
+ 1.to!int;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test16798.d b/gcc/testsuite/gdc.test/compilable/test16798.d
index 41e09e0..fe0f128 100644
--- a/gcc/testsuite/gdc.test/compilable/test16798.d
+++ b/gcc/testsuite/gdc.test/compilable/test16798.d
@@ -1,5 +1,6 @@
/*
REQUIRED_ARGS: -mv=its.a.dessert.topping=imports/imp16798.d -mv=its.a.floorwax=imports/
+EXTRA_FILES: imports/imp16798.d imports/wax16798.d
PERMUTE_ARGS:
TEST_OUTPUT:
---
diff --git a/gcc/testsuite/gdc.test/compilable/test17057.d b/gcc/testsuite/gdc.test/compilable/test17057.d
index c90e35f..677fe38 100644
--- a/gcc/testsuite/gdc.test/compilable/test17057.d
+++ b/gcc/testsuite/gdc.test/compilable/test17057.d
@@ -2,7 +2,7 @@
// PERMUTE_ARGS:
class LeClass {
- import std.stdio;
+ import core.stdc.stdio;
}
void main()
diff --git a/gcc/testsuite/gdc.test/compilable/test17143.d b/gcc/testsuite/gdc.test/compilable/test17143.d
index 98e31f4..4ec0295 100644
--- a/gcc/testsuite/gdc.test/compilable/test17143.d
+++ b/gcc/testsuite/gdc.test/compilable/test17143.d
@@ -1,4 +1,16 @@
-import std.typecons : tuple;
+// https://issues.dlang.org/show_bug.cgi?id=17143
+
+struct Tuple(T...)
+{
+ T values;
+ alias expand = values;
+}
+
+Tuple!T tuple(T...)(T args)
+{
+ return Tuple!T(args);
+}
+
enum foo = tuple(1, 2).expand;
static assert(typeof(foo).stringof == "(int, int)");
static assert(foo.stringof == "tuple(1, 2)");
diff --git a/gcc/testsuite/gdc.test/compilable/test17146.d b/gcc/testsuite/gdc.test/compilable/test17146.d
new file mode 100644
index 0000000..098bfe4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17146.d
@@ -0,0 +1,13 @@
+// REQUIRED_ARGS: -O -inline
+
+// https://issues.dlang.org/show_bug.cgi?id=17146
+
+struct S { int[] a; int b; }
+
+void foo()
+{
+ S[] s;
+ if (s[$-1] == S.init) {}
+}
+
+void bar() { foo(); }
diff --git a/gcc/testsuite/gdc.test/compilable/test17351.d b/gcc/testsuite/gdc.test/compilable/test17351.d
new file mode 100644
index 0000000..fffe92c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17351.d
@@ -0,0 +1,17 @@
+bool fun(S)(ref S[3] a) { assert(a == [42, 84, 169]); return true; }
+bool fun2(S)(ref S a) { return true; }
+void main()
+{
+ static const int[3] sa = [42, 84, 169];
+ static const double sa2 = 42.42;
+ static assert(fun(sa));
+ static assert(fun2(sa2));
+}
+
+int f1(ref const int p) { return p; }
+int f2(ref const int[2] p) { return p[0] + p[1]; }
+void test2()
+{
+ static immutable int[2] P = [ 0, 1 ];
+ static assert(f2(P) == 1);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test17373.d b/gcc/testsuite/gdc.test/compilable/test17373.d
index 93753ba..9a5ee64 100644
--- a/gcc/testsuite/gdc.test/runnable/test17373.d
+++ b/gcc/testsuite/gdc.test/compilable/test17373.d
@@ -1,3 +1,4 @@
+// https://issues.dlang.org/show_bug.cgi?id=17373
interface Foo { void visit (int); }
interface Bar { void visit(double); }
interface FooBar : Foo, Bar {}
@@ -17,4 +18,15 @@ interface Simple
}
static assert(__traits(getOverloads, Simple, "square").length == 2);
-void main() {}
+// https://issues.dlang.org/show_bug.cgi?id=19064
+interface InputStream {}
+interface OutputStream{}
+interface Stream : InputStream, OutputStream{}
+interface ConnectionStream : Stream
+{
+ @property bool connected() const;
+ void close();
+}
+
+static assert(__traits(getOverloads, ConnectionStream, "connected").stringof == "tuple(connected)");
+static assert(__traits(getOverloads, ConnectionStream, "close").stringof == "tuple(close)");
diff --git a/gcc/testsuite/gdc.test/compilable/test17419.d b/gcc/testsuite/gdc.test/compilable/test17419.d
index 295c563..e34e7da 100644
--- a/gcc/testsuite/gdc.test/compilable/test17419.d
+++ b/gcc/testsuite/gdc.test/compilable/test17419.d
@@ -1,6 +1,6 @@
+// REQUIRED_ARGS: -d
// https://issues.dlang.org/show_bug.cgi?id=17419
-
extern (C) int fooc();
alias aliasc = fooc;
diff --git a/gcc/testsuite/gdc.test/compilable/test17441.d b/gcc/testsuite/gdc.test/compilable/test17441.d
new file mode 100644
index 0000000..2c356fd
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17441.d
@@ -0,0 +1,9 @@
+// EXTRA_FILES: imports/test17441foo/package.d imports/test17441foo/bar.d
+import m1 = imports.test17441foo.bar;
+import m2 = imports.test17441foo;
+alias p = __traits(parent, m1);
+enum e(alias thing) = thing.stringof;
+
+static assert(e!m1 == m1.stringof);
+static assert(e!m2 == m2.stringof);
+static assert( e!p == p.stringof );
diff --git a/gcc/testsuite/gdc.test/compilable/test17512.d b/gcc/testsuite/gdc.test/compilable/test17512.d
new file mode 100644
index 0000000..4bf96b7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17512.d
@@ -0,0 +1,26 @@
+// https://issues.dlang.org/show_bug.cgi?id=17512
+
+struct A
+{
+ int _value;
+
+ bool _hasValue;
+
+ auto ref getOr(int alternativeValue)
+ {
+ return _hasValue ? _value : alternativeValue;
+ }
+}
+
+A a;
+
+// https://issues.dlang.org/show_bug.cgi?id=18661
+
+struct S0(T)
+{
+ int a;
+ auto ref immutable(int) getA() { return a; }
+}
+
+alias B = S0!int;
+
diff --git a/gcc/testsuite/gdc.test/compilable/test1754.d b/gcc/testsuite/gdc.test/compilable/test1754.d
index 3193477..c2d8ebb 100644
--- a/gcc/testsuite/gdc.test/compilable/test1754.d
+++ b/gcc/testsuite/gdc.test/compilable/test1754.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/test1754a.d imports/test1754b.d
module test1754;
import imports.test1754a;
diff --git a/gcc/testsuite/gdc.test/compilable/test17541.d b/gcc/testsuite/gdc.test/compilable/test17541.d
new file mode 100644
index 0000000..2fe4343
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17541.d
@@ -0,0 +1,28 @@
+/* EXTRA_SOURCES: imports/test17541_2.d imports/test17541_3.d
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=17541
+
+module one;
+
+import two;
+import three;
+
+struct BB
+{
+ enum MAX_NUM_FIBERS = 4096;
+
+ TWOR!1 t;
+ TT!(int) tt;
+ auto foo()
+ {
+ tt.insertabcdefg(1);
+ }
+}
+
+BB bb;
+
+@nogc bar()
+{
+ bb.foo();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test17548.d b/gcc/testsuite/gdc.test/compilable/test17548.d
index 67b32d7..8e2a390 100644
--- a/gcc/testsuite/gdc.test/compilable/test17548.d
+++ b/gcc/testsuite/gdc.test/compilable/test17548.d
@@ -1,5 +1,5 @@
// REQUIRED_ARGS: -c
-
+// EXTRA_FILES: imports/fwdref2_test17548.d
module test17548;
struct S1 {
diff --git a/gcc/testsuite/gdc.test/compilable/test17752.d b/gcc/testsuite/gdc.test/compilable/test17752.d
new file mode 100644
index 0000000..71f324c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17752.d
@@ -0,0 +1,12 @@
+// https://issues.dlang.org/show_bug.cgi?id=17752
+// REQUIRED_ARGS: -de
+void main (string[] args)
+{
+ switch (args.length)
+ {
+ // initialization not done on purpose is allowed
+ int x = void;
+ default:
+ break;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test17782.d b/gcc/testsuite/gdc.test/compilable/test17782.d
new file mode 100644
index 0000000..588bc27
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17782.d
@@ -0,0 +1,6 @@
+void main() {
+ string str = q"_DLANG
+123
+_DLANG";
+ assert( str == "123\n" );
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test17793.d b/gcc/testsuite/gdc.test/compilable/test17793.d
new file mode 100644
index 0000000..43c992b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17793.d
@@ -0,0 +1,13 @@
+// REQUIRED_ARGS: -mcpu=avx2
+import core.simd;
+
+static if (__traits(compiles, double4))
+{
+ double4 foo();
+ void test(double[4]);
+
+ void main()
+ {
+ test(foo().array);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test17807.d b/gcc/testsuite/gdc.test/compilable/test17807.d
new file mode 100644
index 0000000..b8c5518
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17807.d
@@ -0,0 +1,17 @@
+// REQUIRED_ARGS: -o- -w
+
+int bug17807(){
+ int y=0;
+ Lswitch: switch(2){
+ { case 0: break; }
+ enum x=0;
+ struct S{ enum x=0; }
+ int foo(){
+ return 0;
+ }
+ default: y=x+S.x+foo();
+ static foreach(i;1..5)
+ case i: break Lswitch;
+ }
+ return y;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test17853.d b/gcc/testsuite/gdc.test/compilable/test17853.d
new file mode 100644
index 0000000..d0e6025
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17853.d
@@ -0,0 +1,11 @@
+// Switch with no braces & empty case should compile
+
+int main() {
+ int ob = 1;
+
+ final switch (ob)
+ case 0: case 1:
+ break;
+
+ return ob;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test17906.d b/gcc/testsuite/gdc.test/compilable/test17906.d
new file mode 100644
index 0000000..9c4a547
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17906.d
@@ -0,0 +1,7 @@
+// REQUIRED_ARGS: -de
+// https://issues.dlang.org/show_bug.cgi?id=18647
+deprecated void main ()
+{
+ Object o = new Object;
+ delete o;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test17942.d b/gcc/testsuite/gdc.test/compilable/test17942.d
new file mode 100644
index 0000000..8fbc169
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17942.d
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=17942
+
+alias AliasSeq(TList...) = TList;
+
+void test()
+{
+ enum A = AliasSeq!(1);
+ static assert(A[0] == 1);
+ static assert(B[0] == 2);
+}
+
+enum B = AliasSeq!(2);
+
+enum C = AliasSeq!();
+
diff --git a/gcc/testsuite/gdc.test/compilable/test17970.d b/gcc/testsuite/gdc.test/compilable/test17970.d
new file mode 100644
index 0000000..b7880e2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test17970.d
@@ -0,0 +1,28 @@
+shared struct Shared
+{
+ static Shared make()
+ {
+ return Shared();
+ }
+
+ ~this()
+ {
+ }
+}
+
+shared struct Foo
+{
+ ~this()
+ {
+ }
+}
+
+struct Inner { ~this() {} }
+struct Outer { shared(Inner) inner; }
+
+void main()
+{
+ Foo x = Foo();
+ auto s = Shared.make();
+ Outer _;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18000.d b/gcc/testsuite/gdc.test/compilable/test18000.d
new file mode 100644
index 0000000..9de3324
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18000.d
@@ -0,0 +1,19 @@
+// REQUIRED_ARGS: -preview=dip1000
+
+// https://issues.dlang.org/show_bug.cgi?id=18000
+
+struct File
+{
+@safe @nogc:
+ ~this() scope
+ {
+ }
+
+ void* f;
+}
+
+void test() @safe @nogc
+{
+ scope File x;
+ x = File();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18020.d b/gcc/testsuite/gdc.test/compilable/test18020.d
new file mode 100644
index 0000000..d599920
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18020.d
@@ -0,0 +1,8 @@
+// https://issues.dlang.org/show_bug.cgi?id=18020
+
+void bug(T)(T t)
+{
+ t.opCmp(t);
+}
+
+alias bugi = bug!(typeof(new class{})); \ No newline at end of file
diff --git a/gcc/testsuite/gdc.test/compilable/test18030.d b/gcc/testsuite/gdc.test/compilable/test18030.d
new file mode 100644
index 0000000..f742a40
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18030.d
@@ -0,0 +1,14 @@
+// https://issues.dlang.org/show_bug.cgi?id=18030
+
+struct S(T)
+{
+ T var;
+ static assert(__traits(getProtection, __traits(getMember, T, "func")) == "public");
+}
+
+class C
+{
+ alias Al = S!C;
+
+ static void func(U)(U var) { }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18099.d b/gcc/testsuite/gdc.test/compilable/test18099.d
new file mode 100644
index 0000000..860f6a0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18099.d
@@ -0,0 +1,19 @@
+
+/* REQUIRED_ARGS: -betterC
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=18099
+
+struct D
+{
+ static struct V
+ {
+ ~this() { }
+ }
+
+ V get()
+ {
+ V v;
+ return v;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18115.d b/gcc/testsuite/gdc.test/compilable/test18115.d
new file mode 100644
index 0000000..3ad5b48
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18115.d
@@ -0,0 +1,10 @@
+// https://issues.dlang.org/show_bug.cgi?id=18115
+
+int test()
+{
+ if (test.stringof.length > 6 &&
+ test.stringof[$-7..$] == "1234567") {}
+ return 0;
+}
+
+enum a = test();
diff --git a/gcc/testsuite/gdc.test/compilable/test18199.d b/gcc/testsuite/gdc.test/compilable/test18199.d
new file mode 100644
index 0000000..a3a0885
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18199.d
@@ -0,0 +1,87 @@
+// https://issues.dlang.org/show_bug.cgi?id=18199
+
+//
+// struct initializer cases
+//
+
+// original error report
+struct Bla
+{
+ int delegate(int, int) fun;
+}
+Bla bla1 = Bla((int a, int b) { return a + b; });
+Bla bla2 = {(int a, int b) { return a + b; }}; // yielded error
+
+// additional error report with memberName:expression syntax
+struct Foo
+{
+ int function(int) bar;
+ int function(int) bar2;
+}
+Foo foo =
+{
+ bar : function(x) { return 2 * x; }, // yielded error
+ bar2 : (x) => 2 * x,
+};
+
+struct MyStruct
+{
+ int function() f;
+ int delegate() d;
+}
+
+// confirm that ambiguous cases assume struct initializer
+MyStruct ambiguous_1 = {};
+MyStruct ambiguous_2 =
+{
+ { return 1 + 1; }
+};
+
+// statement-holding function literal variants not covered above
+static MyStruct function_and_delegate_keywords =
+{
+ function () { return 1 + 1; },
+ delegate () { return 1 + 1; }
+};
+
+//
+// function literal initializer cases
+//
+
+alias IntFun = int function();
+alias VoidFun = void function();
+
+IntFun colon_at_top_level =
+{
+ return 1 + 1;
+};
+
+IntFun block_statement_only_with_nested_statement =
+{
+ if (true)
+ {
+ return 1 + 1;
+ }
+};
+
+struct SomeStruct {}
+
+// previously these cases were incorrectly parsed as struct initializer
+VoidFun[] no_semicolon_statements = [
+ { asm {} },
+ { class Foo {} },
+ { debug(foo) {} },
+ { enum Foo { A } },
+ { final switch(5) {} },
+ { if (true) {} },
+ { interface Foo {} },
+ { pragma(inline) {} },
+ { scope(exit) {} },
+ { struct Foo {} },
+ { synchronized {} },
+ { try {} finally {} },
+ { union Foo {} },
+ { version(foo) {} },
+ { while (false) {} },
+ { with (SomeStruct) {} },
+];
diff --git a/gcc/testsuite/gdc.test/compilable/test18251.d b/gcc/testsuite/gdc.test/compilable/test18251.d
new file mode 100644
index 0000000..7940850
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18251.d
@@ -0,0 +1,23 @@
+// REQUIRED_ARGS: -unittest -de
+
+auto test18251(T)(T t)
+if (!__traits(isDeprecated, T))
+{
+ return T.init;
+}
+
+unittest
+{
+ auto b = test18251(2);
+}
+
+deprecated auto test18251(T)(T t) // deprecated storage class got lost when expanding.
+if (__traits(isDeprecated, T))
+{
+ return T.init;
+}
+
+deprecated unittest
+{
+ auto b = test18251(2 + 2i);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18385b.d b/gcc/testsuite/gdc.test/compilable/test18385b.d
new file mode 100644
index 0000000..cf0fedc
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18385b.d
@@ -0,0 +1,29 @@
+/*
+Previous implementation raised errors because it was not
+aware of the special treatment for extern(C) member funtions:
+
+Member functions receive D name mangling...
+Some arguments in favour of this inconsistencies
+- static => useful for callbacks
+- non-static => doesn't exists in C anyways
+*/
+
+extern(C) struct ExternC
+{
+ void foo() {}
+ void foo(int) {}
+
+ static void bar() {}
+ static void bar(int) {}
+}
+
+#line 100
+void main()
+{
+ ExternC.bar();
+ ExternC.bar(1);
+
+ ExternC c;
+ c.foo();
+ c.foo(1);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18430.d b/gcc/testsuite/gdc.test/compilable/test18430.d
new file mode 100644
index 0000000..381ceeb
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18430.d
@@ -0,0 +1,11 @@
+template Alias(alias a)
+{
+ alias Alias = a;
+}
+
+void main()
+{
+ auto scale = 4;
+ alias edentity = a => a * scale;
+ static assert(__traits(isSame, Alias!edentity, edentity)); // fails in dmd-nightly
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18468.d b/gcc/testsuite/gdc.test/compilable/test18468.d
new file mode 100644
index 0000000..8febc9b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18468.d
@@ -0,0 +1,5 @@
+// https://issues.dlang.org/show_bug.cgi?id=18468
+@safe void main()
+{
+ synchronized {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18474.d b/gcc/testsuite/gdc.test/compilable/test18474.d
new file mode 100644
index 0000000..454e9c5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18474.d
@@ -0,0 +1,15 @@
+shared struct A
+{
+ this(this);
+}
+
+struct B
+{
+ A a;
+}
+
+void main()
+{
+ shared B b1;
+ auto b2 = b1;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18572.d b/gcc/testsuite/gdc.test/compilable/test18572.d
new file mode 100644
index 0000000..5edc1a7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18572.d
@@ -0,0 +1,16 @@
+// https://issues.dlang.org/show_bug.cgi?id=18572
+
+alias Seq(T...) = T;
+void func(Seq!(int, int, int) args = Seq!(1, 2, 3)) {}
+void func2(Seq!(int, int, int) args = Seq!(1,2,3), Seq!(int, int) args2 = Seq!(4, 5)) {}
+
+void main(){
+ Seq!(int,int,int) args = Seq!(1, 2, 3); // ok
+ func(); // error
+ func(args); // ok
+
+ Seq!(int, int) args2 = Seq!(4, 5);
+ func2();
+ func2(args);
+ func2(args, args2);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18578.d b/gcc/testsuite/gdc.test/compilable/test18578.d
new file mode 100644
index 0000000..d75a063
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18578.d
@@ -0,0 +1,5 @@
+enum Foo { foo1 }
+enum Bar : Foo { bar }
+
+void main()
+{}
diff --git a/gcc/testsuite/gdc.test/compilable/test18584.d b/gcc/testsuite/gdc.test/compilable/test18584.d
new file mode 100644
index 0000000..e447cc2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18584.d
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=18584
+
+struct S {
+ int n;
+ auto fun() { return tmp!(a => n)(); }
+}
+
+struct tmp(alias fns) {
+ alias fun = fns!int;
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/test18645.d b/gcc/testsuite/gdc.test/compilable/test18645.d
new file mode 100644
index 0000000..acb5586
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18645.d
@@ -0,0 +1,9 @@
+// https://issues.dlang.org/show_bug.cgi?id=18645
+
+immutable INIT = 42;
+
+enum A
+{
+ x = INIT,
+ y
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18651a.d b/gcc/testsuite/gdc.test/compilable/test18651a.d
new file mode 100644
index 0000000..a5ab938
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18651a.d
@@ -0,0 +1,5 @@
+// REQUIRED_ARGS: -deps=${RESULTS_DIR}/compilable/test18651a.deps
+// EXTRA_SOURCES: imports/test18651/b.d
+// EXTRA_FILES: imports/test18651/c.d imports/test18651/algorithm.d imports/test18651/datetime.d
+
+import imports.test18651.datetime;
diff --git a/gcc/testsuite/gdc.test/compilable/test18670.d b/gcc/testsuite/gdc.test/compilable/test18670.d
new file mode 100644
index 0000000..602396c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18670.d
@@ -0,0 +1,12 @@
+// REQUIRED_ARGS: -preview=dip1000
+
+// https://issues.dlang.org/show_bug.cgi?id=18670
+
+void foo() {
+ new OVERLAPPED;
+}
+
+union OVERLAPPED {
+ uint OffsetHigh;
+ uint Pointer;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18694.d b/gcc/testsuite/gdc.test/compilable/test18694.d
new file mode 100644
index 0000000..9b2018b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18694.d
@@ -0,0 +1,9 @@
+struct S { enum int x = 42; }
+static S dummy;
+pure int fun(int x)
+{
+ return dummy.x + x;
+}
+
+void main()
+{}
diff --git a/gcc/testsuite/gdc.test/compilable/test18737.d b/gcc/testsuite/gdc.test/compilable/test18737.d
new file mode 100644
index 0000000..17a27df
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18737.d
@@ -0,0 +1,32 @@
+/* REQUIRED_ARGS:
+ * PERMUTE_ARGS:
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=18737
+
+struct S
+{
+ this(char);
+
+ this(int j)
+ {
+ this('a');
+ assert(0);
+ this('b');
+ }
+
+ this(long j)
+ {
+ if (j)
+ {
+ this('c');
+ assert(0);
+ }
+ else if (j + 1)
+ {
+ this('d');
+ return;
+ }
+ this('e');
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18771.d b/gcc/testsuite/gdc.test/compilable/test18771.d
new file mode 100644
index 0000000..a71361f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18771.d
@@ -0,0 +1,7 @@
+// REQUIRED_ARGS : -c
+// EXTRA_FILES: imports/test18771a.d imports/test18771b.d imports/test18771c.d imports/test18771d.d
+// https://issues.dlang.org/show_bug.cgi?id=18771
+
+import imports.test18771c, imports.test18771d;
+
+static assert(__traits(isSame, fooC, fooD));
diff --git a/gcc/testsuite/gdc.test/compilable/test18775.d b/gcc/testsuite/gdc.test/compilable/test18775.d
new file mode 100644
index 0000000..9cf1b3e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18775.d
@@ -0,0 +1,20 @@
+// REQUIRED_ARGS: -de
+
+struct Foo { }
+
+struct Bar {
+ deprecated
+ @property Foo foo() { return Foo.init; }
+
+ alias foo this;
+}
+
+void test(Bar bar) { }
+
+void main()
+{
+ Bar bar;
+
+ // test lookup will be satisfied via ufcs, not alias, so it must not deprecation warn foo!
+ bar.test;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18821.d b/gcc/testsuite/gdc.test/compilable/test18821.d
new file mode 100644
index 0000000..28bdeca
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18821.d
@@ -0,0 +1,10 @@
+// https://issues.dlang.org/show_bug.cgi?id=18821
+
+align(1) struct epoll_event
+{
+ void* ptr;
+}
+template isAllZeroBits(epoll_event value) {}
+alias isInitAllZeroBits = isAllZeroBits!(epoll_event.init);
+
+epoll_event e = { null };
diff --git a/gcc/testsuite/gdc.test/compilable/test18905.d b/gcc/testsuite/gdc.test/compilable/test18905.d
new file mode 100644
index 0000000..c54c60c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18905.d
@@ -0,0 +1,6 @@
+/* REQUIRED_ARGS: -betterC
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=18905
+
+extern (C++) class C { } // Error: TypeInfo cannot be used with -betterC
diff --git a/gcc/testsuite/gdc.test/compilable/test18936.d b/gcc/testsuite/gdc.test/compilable/test18936.d
new file mode 100644
index 0000000..12f4b4b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18936.d
@@ -0,0 +1,31 @@
+// REQUIRED_ARGS: -fPIC -O -release -inline -m64 -betterC
+// DISABLED: win32 win64
+
+// https://issues.dlang.org/show_bug.cgi?id=18936
+// produces assert failure cgxmm.c line 684
+
+import core.stdc.math;
+
+struct S
+{
+ double re, im;
+
+
+ static S sqrtcx(S* z)
+ {
+ S c;
+ real x,y,w,r;
+
+ {
+ x = fabs(z.re);
+ y = fabs(z.im);
+ if (z.re >= 0)
+ {
+ c.im = (z.im >= 0) ? w : -w;
+ c.re = z.im / (c.im + c.im);
+ }
+ }
+ return c;
+ }
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/test18951a.d b/gcc/testsuite/gdc.test/compilable/test18951a.d
new file mode 100644
index 0000000..8aedc8d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18951a.d
@@ -0,0 +1,7 @@
+module compilable.test18951a;
+
+public class A
+{
+ package static void foo(Object) {}
+ public static void foo() {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18951b.d b/gcc/testsuite/gdc.test/compilable/test18951b.d
new file mode 100644
index 0000000..fbf6b1d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18951b.d
@@ -0,0 +1,9 @@
+// EXTRA_FILES: test18951a.d
+module compilable.test18951b;
+
+import test18951a;
+
+void test()
+{
+ A.foo(new Object);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18976.d b/gcc/testsuite/gdc.test/compilable/test18976.d
new file mode 100644
index 0000000..57a531f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18976.d
@@ -0,0 +1,32 @@
+// https://issues.dlang.org/show_bug.cgi?id=18976
+
+class Expression : Statement {}
+class Statement {}
+
+class AssertSemanticVisitor
+{
+ void visit (const Statement node) { }
+}
+
+class ExpressionVisitor : AssertSemanticVisitor
+{
+ public void visit (Expression) { }
+
+ alias visit = typeof(super).visit;
+}
+
+class ExpressionVisitor2 : AssertSemanticVisitor
+{
+ public void visit (Expression) { }
+
+ alias visit = AssertSemanticVisitor.visit;
+}
+
+void main ()
+{
+ scope x1 = new ExpressionVisitor;
+ scope x2 = new ExpressionVisitor;
+ scope y = new Statement;
+ x1.visit(y);
+ x2.visit(y);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19014.d b/gcc/testsuite/gdc.test/compilable/test19014.d
new file mode 100644
index 0000000..7bbbc94
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19014.d
@@ -0,0 +1,12 @@
+// https://issues.dlang.org/show_bug.cgi?id=19014
+
+import core.stdc.config;
+
+void main()
+{
+ if (true)
+ {
+ static import core.stdc.math;
+ }
+ static assert(!__traits(compiles, core.stdc.math.cos(0)));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19066.d b/gcc/testsuite/gdc.test/compilable/test19066.d
new file mode 100644
index 0000000..53d5005
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19066.d
@@ -0,0 +1,13 @@
+class C {}
+
+int Object;
+
+struct S
+{
+ int object;
+ C Object;
+}
+
+void main()
+{
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19081.d b/gcc/testsuite/gdc.test/compilable/test19081.d
new file mode 100644
index 0000000..ba5fd9c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19081.d
@@ -0,0 +1,14 @@
+void main() {
+ @(1) enum { A }
+ /// comment
+ @(1) enum X { A }
+ @(2) enum Y;
+ @(1) @(2) enum Z { A }
+
+ struct Test { int test; }
+ @Test(1) enum W { A }
+ @(1) enum V: int { A }
+ X a;
+ static assert(__traits(getAttributes, X).length == 1);
+ static assert(__traits(getAttributes, X)[0] == 1);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19097.d b/gcc/testsuite/gdc.test/compilable/test19097.d
new file mode 100644
index 0000000..19e189c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19097.d
@@ -0,0 +1,23 @@
+/* REQUIRED_ARGS: -preview=dip1000
+ */
+
+// Related to: https://github.com/dlang/dmd/pull/8504
+
+@safe:
+
+void betty()(ref int* r, return scope int* p)
+{
+ r = p; // infer `scope` for r
+}
+
+void boop()(ref int* r, scope int* p)
+{
+ r = p; // infer `scope` for r, `return` for p
+}
+
+void foo(scope int* pf)
+{
+ scope int* rf;
+ betty(rf, pf);
+ boop(rf, pf);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19108.d b/gcc/testsuite/gdc.test/compilable/test19108.d
new file mode 100644
index 0000000..4620750
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19108.d
@@ -0,0 +1,9 @@
+// REQUIRED_ARGS: -ignore
+
+// https://issues.dlang.org/show_bug.cgi?id=19108
+
+pragma(unknown_global);
+void main()
+{
+ pragma(unknown_local); // Error: unrecognized pragma
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19187.d b/gcc/testsuite/gdc.test/compilable/test19187.d
new file mode 100644
index 0000000..9d0630a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19187.d
@@ -0,0 +1,6 @@
+// EXTRA_FILES: imports/test19187.d
+import imports.test19187;
+void main()
+{
+ enum test = __traits(compiles, imports.test19187.foo);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19203.d b/gcc/testsuite/gdc.test/compilable/test19203.d
new file mode 100644
index 0000000..206d662
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19203.d
@@ -0,0 +1,27 @@
+//https://issues.dlang.org/show_bug.cgi?id=19203
+struct BoolWithErr {
+ bool b;
+ string error;
+ alias b this;
+}
+
+struct Foo {
+ int popBack() { return 0; }
+}
+
+struct Bar {}
+
+template hasPopBack(T) {
+ static if (!is(typeof(T.init.popBack)))
+ enum hasPopBack = BoolWithErr(false, T.stringof~" does not have popBack");
+ else
+ enum hasPopBack = BoolWithErr(true,"");
+}
+
+void test()
+{
+ static assert( hasPopBack!Foo);
+ static assert(!hasPopBack!Bar);
+ static assert( hasPopBack!Foo && !hasPopBack!Bar);
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/test19224.d b/gcc/testsuite/gdc.test/compilable/test19224.d
new file mode 100644
index 0000000..4020e0d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19224.d
@@ -0,0 +1,18 @@
+// https://issues.dlang.org/show_bug.cgi?id=19224
+static if (__traits(compiles, __vector(float[4])))
+{
+ float sum(const float[4] val)
+ {
+ float sum = 0;
+ foreach (x; val) sum += x;
+ return sum;
+ }
+
+ alias float4 = __vector(float[4]);
+
+ enum x = sum(float4.init.array);
+ static assert(x is float.nan);
+
+ enum y = sum(float4(1).array);
+ static assert(y == 4);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19227.d b/gcc/testsuite/gdc.test/compilable/test19227.d
new file mode 100644
index 0000000..27dab9e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19227.d
@@ -0,0 +1,29 @@
+// https://issues.dlang.org/show_bug.cgi?id=19227
+/* TEST_OUTPUT:
+---
+compilable/test19227.d(18): Deprecation: use of complex type `cfloat` is deprecated, use `std.complex.Complex!(float)` instead
+Deprecation: use of complex type `const(cfloat)` is deprecated, use `std.complex.Complex!(float)` instead
+Deprecation: use of complex type `const(cfloat)` is deprecated, use `std.complex.Complex!(float)` instead
+Deprecation: use of complex type `const(cfloat)` is deprecated, use `std.complex.Complex!(float)` instead
+---
+*/
+
+struct S
+{
+ float f;
+}
+
+struct T
+{
+ cfloat cf;
+}
+
+void main()
+{
+ static assert(S.init is S.init);
+ static assert(S.init != S.init);
+
+ static assert(T.init is T.init);
+ static assert(T.init != T.init);
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/test19315.d b/gcc/testsuite/gdc.test/compilable/test19315.d
new file mode 100644
index 0000000..0c31ab8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19315.d
@@ -0,0 +1,20 @@
+//https://issues.dlang.org/show_bug.cgi?id=19315
+void main()
+{
+ #line 100 "file.d"
+ enum code = q{
+ #line 10
+ };
+ static assert(__LINE__ == 103);
+ static assert(__FILE__ == "file.d");
+
+ #line 200 "file2.d"
+ enum code2 = q{
+ q{
+ #line 5
+ }
+ #line 9 "foo.d"
+ };
+ static assert(__LINE__ == 206);
+ static assert(__FILE__ == "file2.d");
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19409.d b/gcc/testsuite/gdc.test/compilable/test19409.d
new file mode 100644
index 0000000..94915e8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19409.d
@@ -0,0 +1,6 @@
+// https://issues.dlang.org/show_bug.cgi?id=19409
+
+module test.foo;
+
+static if (__traits(compiles, __traits(identifier, test.foo))) {} // fails
+else { static assert(0); }
diff --git a/gcc/testsuite/gdc.test/compilable/test19464.d b/gcc/testsuite/gdc.test/compilable/test19464.d
new file mode 100644
index 0000000..d0d3895
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19464.d
@@ -0,0 +1,5 @@
+// https://issues.dlang.org/show_bug.cgi?id=19464
+
+typeof(a0) b0 = 3;
+immutable int a0 = 4;
+static assert(is(typeof(b0) == immutable(int)));
diff --git a/gcc/testsuite/gdc.test/compilable/test19491.d b/gcc/testsuite/gdc.test/compilable/test19491.d
new file mode 100644
index 0000000..3a341b3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19491.d
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=19491
+
+class Foo
+{
+ shared this();
+}
+
+void test()
+{
+ scope foo = new shared Foo();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19499.d b/gcc/testsuite/gdc.test/compilable/test19499.d
new file mode 100644
index 0000000..c3ff73e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19499.d
@@ -0,0 +1,6 @@
+// https://issues.dlang.org/show_bug.cgi?id=19499
+
+enum __c_long_double : double;
+enum A(T : double) = true;
+enum A(T : __c_long_double) = false;
+static assert(A!double == true);
diff --git a/gcc/testsuite/gdc.test/compilable/test19519.d b/gcc/testsuite/gdc.test/compilable/test19519.d
new file mode 100644
index 0000000..3799966
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19519.d
@@ -0,0 +1,15 @@
+struct S { char[1] e = void; }
+
+void init(ref char[1] e)
+{
+ e[0 .. 1] = "A";
+}
+
+int foo()
+{
+ auto s = S();
+ init(s.e);
+ return __ctfe;
+}
+
+static assert(foo() == 1);
diff --git a/gcc/testsuite/gdc.test/compilable/test19540.d b/gcc/testsuite/gdc.test/compilable/test19540.d
new file mode 100644
index 0000000..5132897
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19540.d
@@ -0,0 +1,2 @@
+alias inst = templ!();
+template templ(T = typeof(new class {})) {}
diff --git a/gcc/testsuite/gdc.test/compilable/test19557.d b/gcc/testsuite/gdc.test/compilable/test19557.d
new file mode 100644
index 0000000..f107e22
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19557.d
@@ -0,0 +1,10 @@
+// https://issues.dlang.org/show_bug.cgi?id=19557
+// Error: redundant linkage `extern (C++)`
+
+extern(C++, "ns")
+extern(C++, class)
+struct test {}
+
+extern(C++, class)
+extern(C++, "ns")
+struct test2 {}
diff --git a/gcc/testsuite/gdc.test/compilable/test19609.d b/gcc/testsuite/gdc.test/compilable/test19609.d
index a3d6923..2646bd4 100644
--- a/gcc/testsuite/gdc.test/compilable/test19609.d
+++ b/gcc/testsuite/gdc.test/compilable/test19609.d
@@ -1,10 +1,11 @@
// https://issues.dlang.org/show_bug.cgi?id=19609
+// EXTRA_FILES: imports/test19609a.d imports/test19609b.d imports/test19609c.d
/*
TEST_OUTPUT
---
-compilable/test19609.d(10): Deprecation: module `imports.test19609a` is deprecated -
-compilable/test19609.d(11): Deprecation: module `imports.test19609b` is deprecated - hello
-compilable/test19609.d(12): Deprecation: module `imports.test19609c` is deprecated -
+compilable/test19609.d(11): Deprecation: module `imports.test19609a` is deprecated -
+compilable/test19609.d(12): Deprecation: module `imports.test19609b` is deprecated - hello
+compilable/test19609.d(13): Deprecation: module `imports.test19609c` is deprecated -
---
*/
import imports.test19609a;
diff --git a/gcc/testsuite/gdc.test/compilable/test19631.d b/gcc/testsuite/gdc.test/compilable/test19631.d
new file mode 100644
index 0000000..3a4dd8e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19631.d
@@ -0,0 +1,11 @@
+struct Field(int _w, int _h)
+{
+ bool[_h][_w] s;
+}
+
+struct Life(int w, int h)
+{
+ auto a = new Field!(w, h); // ICE
+}
+
+alias T = Life!(100, 100);
diff --git a/gcc/testsuite/gdc.test/compilable/test19652.d b/gcc/testsuite/gdc.test/compilable/test19652.d
new file mode 100644
index 0000000..193c717
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19652.d
@@ -0,0 +1,22 @@
+struct Base {
+ int i;
+}
+
+struct A {
+ Base base;
+ alias base this;
+}
+
+struct B {
+ A a;
+ alias a this;
+}
+
+auto asGeneric(inout ref Base block) @nogc {
+ return &block;
+}
+
+B* thingie;
+auto foo() {
+ return asGeneric(*thingie);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19656.d b/gcc/testsuite/gdc.test/compilable/test19656.d
new file mode 100644
index 0000000..bcfd36e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19656.d
@@ -0,0 +1,14 @@
+/*
+PERMUTE_ARGS:
+EXTRA_FILES: imports/test19656a.d imports/test19656b.d imports/test19656c.d
+*/
+
+import imports.test19656a;
+import imports.test19656c: Thud;
+
+class Foo
+{
+ Foo[Foo] _map;
+ void func (Thud ) { }
+ void thunk () { }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19657a.d b/gcc/testsuite/gdc.test/compilable/test19657a.d
new file mode 100644
index 0000000..1aefb5e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19657a.d
@@ -0,0 +1,11 @@
+/*
+REQUIRED_ARGS: -Icompilable/imports
+EXTRA_SOURCES: imports/test19657b.d imports/test19657c.d imports/test19657d.d imports/test19657e.d imports/test19657f.d imports/test19657g.d
+*/
+
+import test19657c;
+import test19657e: Bar;
+class Foo {
+ int[Foo] _map;
+ bool func (Foo rhs, Bar bee) { return true; }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19713.d b/gcc/testsuite/gdc.test/compilable/test19713.d
new file mode 100644
index 0000000..5201404
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19713.d
@@ -0,0 +1,14 @@
+extern (C++)
+{
+ double twice(double d)
+ {
+ return d * 2;
+ }
+
+ void* createFunction(R)(R function(double));
+}
+
+void main()
+{
+ const f = createFunction(&twice);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19728.d b/gcc/testsuite/gdc.test/compilable/test19728.d
new file mode 100644
index 0000000..551ac0f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19728.d
@@ -0,0 +1,52 @@
+/*
+TEST_OUTPUT:
+---
+tuple((A), (B))
+tuple((A), (B), 0)
+tuple((A), (B), (A))
+tuple((A), (B), (A), (B))
+tuple((A), (B), (A), (B))
+tuple((A), (B), (A), (B), (A), (B), (A), (B))
+tuple((Attr))
+---
+*/
+
+// Issue 19728
+enum A; enum B; enum Dummy = 0;
+
+alias Seq(T...) = T;
+
+@Seq!(A,B) struct Foo1 {}
+@Seq!(A,B, Dummy) struct Foo2 {}
+@Seq!(A,B,A) struct Foo3 {}
+@Seq!(Seq!(A,B,A,B)) struct Foo4 {}
+@Seq!(A,Seq!(B,A),B) struct Foo5 {}
+@Seq!(A,Seq!(B,A),B) @Seq!(A,B,A,B) struct Foo6 {}
+
+pragma(msg, __traits(getAttributes, Foo1));
+pragma(msg, __traits(getAttributes, Foo2));
+pragma(msg, __traits(getAttributes, Foo3));
+pragma(msg, __traits(getAttributes, Foo4));
+pragma(msg, __traits(getAttributes, Foo5));
+pragma(msg, __traits(getAttributes, Foo6));
+
+struct S(T...) {}
+static assert(is( S!(A,B) == S!(__traits(getAttributes, Foo1))));
+static assert(is( S!(A,B,Dummy) == S!(__traits(getAttributes, Foo2))));
+static assert(is( S!(A,B,A) == S!(__traits(getAttributes, Foo3))));
+static assert(is( S!(A,B,A,B) == S!(__traits(getAttributes, Foo4))));
+static assert(is( S!(A,B,A,B) == S!(__traits(getAttributes, Foo5))));
+static assert(is(S!(A,B,A,B,A,B,A,B) == S!(__traits(getAttributes, Foo6))));
+
+// Issue 20093
+mixin template MakeProperty(Attributes...) {
+ @(Attributes) void bug() {}
+}
+
+struct Attr { }
+
+struct Test {
+ mixin MakeProperty!(Attr);
+}
+
+pragma(msg, __traits(getAttributes, Test.bug));
diff --git a/gcc/testsuite/gdc.test/compilable/test19731.d b/gcc/testsuite/gdc.test/compilable/test19731.d
new file mode 100644
index 0000000..09c5102
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19731.d
@@ -0,0 +1,78 @@
+// https://issues.dlang.org/show_bug.cgi?id=19731
+
+class Out19731
+{
+ static struct State
+ {
+ int flags_;
+ }
+ Object obj_;
+
+ invariant (obj_ !is null);
+
+ auto obj7(out State state)
+ {
+ return this.obj_;
+ }
+
+ enum compiles = __traits(compiles, &Out19731.init.obj7);
+}
+
+class Arguments19731
+{
+ Object obj_;
+
+ invariant (obj_ !is null);
+
+ import core.stdc.stdarg;
+ auto obj7(...)
+ {
+ return this.obj_;
+ }
+
+ enum compiles = __traits(compiles, &Arguments19731.init.obj7);
+}
+
+class Require19731
+{
+ Object obj_;
+
+ invariant (obj_ !is null);
+
+ auto obj7(int a)
+ in(a != 0)
+ {
+ return this.obj_;
+ }
+
+ enum compiles = __traits(compiles, &Require19731.init.obj7);
+}
+
+class Ensure19731
+{
+ Object obj_;
+
+ invariant (obj_ !is null);
+
+ auto obj7(int a)
+ out(result; result is obj_)
+ {
+ return this.obj_;
+ }
+
+ enum compiles = __traits(compiles, &Ensure19731.init.obj7);
+}
+
+class Sync19731
+{
+ Object obj_;
+
+ invariant (obj_ !is null);
+
+ synchronized auto obj7()
+ {
+ return this.obj_;
+ }
+
+ enum compiles = __traits(compiles, &Sync19731.init.obj7);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19746.d b/gcc/testsuite/gdc.test/compilable/test19746.d
new file mode 100644
index 0000000..28677b0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19746.d
@@ -0,0 +1,16 @@
+// REQUIRED_ARGS: -Icompilable/imports
+// EXTRA_FILES: imports/test19746a.d imports/test19746b.d imports/test19746c.d imports/test19746d.d
+import test19746c;
+import test19746b: Frop;
+
+template Base(T)
+{
+ static if (is(T == super)) alias Base = Object;
+}
+
+class Foo
+{
+ class Nested: Base!Foo { }
+ void func(Frop) { }
+ void thunk() { }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19750.d b/gcc/testsuite/gdc.test/compilable/test19750.d
new file mode 100644
index 0000000..0d57749
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19750.d
@@ -0,0 +1,7 @@
+// REQUIRED_ARGS: -Icompilable/imports
+// EXTRA_FILES: imports/test19750a.d imports/test19750b.d imports/test19750c.d imports/test19750d.d
+import test19750b;
+class Foo {
+ import test19750a;
+ void func (Bar ) {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19754.d b/gcc/testsuite/gdc.test/compilable/test19754.d
new file mode 100644
index 0000000..a7ad4ac
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19754.d
@@ -0,0 +1,45 @@
+// https://issues.dlang.org/show_bug.cgi?id=19754
+
+void test19754()
+{
+ shared int x;
+ static assert((cast(int*) &x) == &(cast() x));
+ (cast() x) = 5;
+ (cast() x) += 3;
+
+ const int x1;
+ static assert(&x1 == &(cast() x1));
+ (cast() x1) = 5;
+ (cast() x1) *= 3;
+
+ immutable int x2;
+ static assert(&x2 == &(cast() x2));
+ (cast() x2) = 5;
+ (cast() x2) &= 3;
+
+ int[4] a;
+ (cast(long[2]) a)[0] = 5;
+ (cast(long[2]) a)[0] += 3;
+
+ static if (is(__vector(int[4])))
+ {
+ __vector(int[4]) v;
+ (cast(int[4]) v)[0] = 5;
+ (cast(int[4]) v)[0] += 3;
+ }
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20608
+
+void foo(T...)(auto ref T args) {}
+
+struct Tuple
+{
+ int expand;
+}
+
+void test20608()
+{
+ enum tup = Tuple();
+ foo(tup.expand);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19804.d b/gcc/testsuite/gdc.test/compilable/test19804.d
new file mode 100644
index 0000000..136e89f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19804.d
@@ -0,0 +1,9 @@
+// https://issues.dlang.org/show_bug.cgi?id=19804
+
+struct A { float e; }
+
+void foo(A[1] a)
+{
+ void bar(A[1] a) { a[] = null; }
+ bar(a);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19809.d b/gcc/testsuite/gdc.test/compilable/test19809.d
new file mode 100644
index 0000000..3344ef1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19809.d
@@ -0,0 +1,14 @@
+// https://issues.dlang.org/show_bug.cgi?id=19809
+mixin template Impl(M...)
+{
+ int opCmp(Object o) { return 0; }
+}
+
+class C
+{
+ override
+ {
+ int function(int) fp = ((int x) => x);
+ mixin Impl!("x", "y", ((int x) => x));
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19833.d b/gcc/testsuite/gdc.test/compilable/test19833.d
new file mode 100644
index 0000000..6ffa5c4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19833.d
@@ -0,0 +1,27 @@
+struct S
+{
+ template Temp(int x)
+ {
+ enum xxx = x;
+ }
+}
+
+alias TT = __traits(getMember, S, "Temp");
+enum x = TT!2.xxx;
+static assert(x == 2);
+
+class A
+{
+ mixin temp!("uint");
+ mixin temp!("float");
+
+ mixin template temp(string source)
+ {
+ private enum inner(string s) = s;
+ }
+}
+
+class B
+{
+ alias member = __traits(getMember, A, __traits(allMembers, A)[0]);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19840.d b/gcc/testsuite/gdc.test/compilable/test19840.d
new file mode 100644
index 0000000..e0c7b28
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19840.d
@@ -0,0 +1,21 @@
+// https://issues.dlang.org/show_bug.cgi?id=19840
+struct G
+{
+ ubyte[] I;
+ alias I this;
+}
+
+auto M(ubyte[])
+{
+ G N;
+ return N;
+}
+
+struct U { int V; }
+
+void X()
+{
+ func((cast(U[])[].M));
+}
+
+void func(U[]) {}
diff --git a/gcc/testsuite/gdc.test/compilable/test19895.d b/gcc/testsuite/gdc.test/compilable/test19895.d
new file mode 100644
index 0000000..b2d8e68
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19895.d
@@ -0,0 +1,7 @@
+// https://issues.dlang.org/show_bug.cgi?id=19895
+
+void fn()
+{
+ void[] a;
+ auto b = cast(byte[0][]) a;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19936.d b/gcc/testsuite/gdc.test/compilable/test19936.d
new file mode 100644
index 0000000..248e28a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19936.d
@@ -0,0 +1,17 @@
+// REQUIRED_ARGS: -de
+
+struct Bla
+{
+ deprecated("bla")
+ int get() { return 5; }
+
+ alias get this;
+}
+
+void main()
+{
+ Bla[] blaArray;
+ // ~= should not try to call `.get`, because there's no indication that
+ // `blaArray` has any kind of opAppendAssign related overload in the first place.
+ blaArray ~= Bla();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19954.d b/gcc/testsuite/gdc.test/compilable/test19954.d
new file mode 100644
index 0000000..6ccc8be
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19954.d
@@ -0,0 +1,14 @@
+// https://issues.dlang.org/show_bug.cgi?id=19954
+
+template AliasSeq(TList...)
+{
+ alias AliasSeq = TList;
+}
+
+void fun(string[]){}
+
+void main()
+{
+ fun(cast(string[])AliasSeq!"");
+ auto a = cast(char[][])"";
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19970.d b/gcc/testsuite/gdc.test/compilable/test19970.d
new file mode 100644
index 0000000..52f8e0c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test19970.d
@@ -0,0 +1,16 @@
+// https://issues.dlang.org/show_bug.cgi?id=19970
+
+enum void* p = cast(void*)0;
+static assert(p is null);
+static assert(ctfeLocal(p));
+static assert(ctfeGlobal());
+
+bool ctfeGlobal ()
+{
+ return p is null;
+}
+
+bool ctfeLocal (const void* ptr) pure
+{
+ return ptr is null;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20000.d b/gcc/testsuite/gdc.test/compilable/test20000.d
new file mode 100644
index 0000000..11548cb
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20000.d
@@ -0,0 +1,9 @@
+// https://issues.dlang.org/show_bug.cgi?id=20000
+
+interface A { int a(); }
+interface B { int b(); }
+class C {}
+
+bool isA(Object x) @safe { return cast(A) x !is null; }
+bool isA(B x) @safe { return cast(A) x !is null; }
+bool isA(C x) @safe { return cast(A) x !is null; }
diff --git a/gcc/testsuite/gdc.test/compilable/test20021.d b/gcc/testsuite/gdc.test/compilable/test20021.d
new file mode 100644
index 0000000..26ed1ac
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20021.d
@@ -0,0 +1,22 @@
+// https://issues.dlang.org/show_bug.cgi?id=20021
+struct S
+{
+ bool opCast(T : bool)() { return true; }
+ S prop() {return this;}
+ S prop(S newThis) {return this;}
+}
+
+struct T
+{
+ bool opCast(T : bool)() { return false; }
+}
+
+void test20021()
+{
+ static if (T.init)
+ static assert(false);
+
+ // ensure properties are resolved
+ static if (!(true && T.init || (S.init.prop = S.init).prop))
+ static assert(false);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20039.d b/gcc/testsuite/gdc.test/compilable/test20039.d
new file mode 100644
index 0000000..d912139
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20039.d
@@ -0,0 +1,13 @@
+void foo()() { }
+class bar { }
+
+alias bug = foo;
+alias bug = bar;
+
+template Identity(T...) { }
+
+void main()
+{
+ alias member1 = Identity!(__traits(getMember, mixin(__MODULE__), "bug"));
+ alias member2 = Identity!(__traits(getMember, mixin(__MODULE__), "bug"));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20051.d b/gcc/testsuite/gdc.test/compilable/test20051.d
new file mode 100644
index 0000000..20c1188
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20051.d
@@ -0,0 +1,18 @@
+// https://issues.dlang.org/show_bug.cgi?id=20051
+struct Templ2(Args...)
+{
+}
+
+struct WillAlsoWork(alias T : Templ!Args, Args...)
+{
+ alias A = Args[0];
+}
+
+void main()
+{
+ alias C2 = Templ2!int;
+ static assert(!__traits(compiles, {
+ alias B2 = WillAlsoWork!C2;
+ B2.A a2;
+ }));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20065.d b/gcc/testsuite/gdc.test/compilable/test20065.d
new file mode 100644
index 0000000..c1be44d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20065.d
@@ -0,0 +1,12 @@
+alias AliasSeq(T...) = T;
+
+void main()
+{
+ enum string[] array1 = [AliasSeq!("foo")];
+
+ static assert(array1 == ["foo"]);
+
+ enum string[] array2 = [AliasSeq!()];
+
+ static assert(array2 == []);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20100.d b/gcc/testsuite/gdc.test/compilable/test20100.d
new file mode 100644
index 0000000..bc8ad2c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20100.d
@@ -0,0 +1,50 @@
+// REQUIRED_ARGS: -checkaction=context
+struct STuple {
+ bool opEquals(STuple) { return false; }
+}
+
+class CTuple {
+}
+
+void testStruct() {
+ STuple t1;
+ assert(t1 == t1);
+}
+
+void testClass() {
+ CTuple t1 = new CTuple();
+ assert(t1 == t1);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20331
+void testAnonymousFunction()
+{
+ bool function() check = () => true;
+ assert(check());
+
+ bool result = true;
+ assert((() => result)());
+}
+
+void main() {
+ testStruct();
+ testClass();
+ testAnonymousFunction();
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20989
+ void test20989() @safe
+{
+ uint[] arr = [1, 2, 3];
+ assert(arr.ptr);
+ assert(!arr.ptr);
+ assert(arr.ptr is arr.ptr);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=21765
+ref int func21765(int);
+void test21765()
+{
+ assert((func21765(1) = 2) == 2);
+ assert((1.func21765 = 2) == 2);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20136.d b/gcc/testsuite/gdc.test/compilable/test20136.d
new file mode 100644
index 0000000..a5fb8e3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20136.d
@@ -0,0 +1,18 @@
+// https://issues.dlang.org/show_bug.cgi?id=20136
+class Context
+{
+ size_t[const(Key)] aa;
+ bool checkAll;
+}
+
+struct Key
+{
+ Context context;
+ int i;
+ bool opEquals(ref const Key other) const
+ {
+ if(context.checkAll && i != other.i)
+ return false;
+ return true;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20138.d b/gcc/testsuite/gdc.test/compilable/test20138.d
new file mode 100644
index 0000000..f4626ae
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20138.d
@@ -0,0 +1,16 @@
+alias C = const int;
+static assert(is(shared(C) U == shared U) && is(U == C));
+static assert(is(shared(C) == shared U, U) && is(U == C));
+
+alias I = inout int;
+static assert(is(shared(I) U == shared U) && is(U == I));
+static assert(is(shared(I) == shared U, U) && is(U == I));
+
+alias IC = inout const int;
+static assert(is(shared(IC) U == shared U) && is(U == IC));
+static assert(is(shared(IC) == shared U, U) && is(U == IC));
+
+alias S = shared int;
+static assert(is(const(S) U == const U) && is(U == shared int));
+static assert(is(inout(S) U == inout U) && is(U == shared int));
+static assert(is(inout(const S) U == inout(const U)) && is(U == shared int));
diff --git a/gcc/testsuite/gdc.test/compilable/test20181.d b/gcc/testsuite/gdc.test/compilable/test20181.d
new file mode 100644
index 0000000..e71b478
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20181.d
@@ -0,0 +1,11 @@
+module test20181;
+
+struct InversionList
+{
+ ubyte[] byCodepoint() { return null; }
+}
+
+void main()
+{
+ static foreach (ch; InversionList().byCodepoint) { }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20296.d b/gcc/testsuite/gdc.test/compilable/test20296.d
new file mode 100644
index 0000000..2b16fa5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20296.d
@@ -0,0 +1,8 @@
+// https://issues.dlang.org/show_bug.cgi?id=20296
+
+extern (C++)
+void foo(T...)(T args)
+{
+}
+
+alias F = foo!(char*);
diff --git a/gcc/testsuite/gdc.test/compilable/test20318.d b/gcc/testsuite/gdc.test/compilable/test20318.d
new file mode 100644
index 0000000..58d3969
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20318.d
@@ -0,0 +1,7 @@
+// https://issues.dlang.org/show_bug.cgi?id=20318
+// REQUIRED_ARGS: -dip1008 -profile=gc
+
+void main()
+{
+ throw new Exception("msg");
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20326.d b/gcc/testsuite/gdc.test/compilable/test20326.d
new file mode 100644
index 0000000..1da3eb6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20326.d
@@ -0,0 +1,11 @@
+class C;
+static assert(C.stringof == "C");
+
+interface I;
+static assert(I.stringof == "I");
+
+union U;
+static assert(U.stringof == "U");
+
+struct S;
+static assert(S.stringof == "S");
diff --git a/gcc/testsuite/gdc.test/compilable/test20367.d b/gcc/testsuite/gdc.test/compilable/test20367.d
new file mode 100644
index 0000000..ebdf9ee
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20367.d
@@ -0,0 +1,14 @@
+// https://issues.dlang.org/show_bug.cgi?id=20367
+
+struct A
+{
+ int x;
+ this(ref return scope A rhs) {}
+ @disable this(this) {}
+}
+
+void main()
+{
+ A a;
+ A b = a; // copy constructor gets called
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20388.d b/gcc/testsuite/gdc.test/compilable/test20388.d
new file mode 100644
index 0000000..e0beac9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20388.d
@@ -0,0 +1,10 @@
+// https://issues.dlang.org/show_bug.cgi?id=20388
+
+void main() {
+ foo!(mixin("(int a) { return a; }"))();
+ foo!(mixin("1+1"))();
+ foo!(mixin(0))();
+}
+
+void foo(alias t)() {
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20406.d b/gcc/testsuite/gdc.test/compilable/test20406.d
new file mode 100644
index 0000000..c3d494f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20406.d
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=20406
+struct S
+{
+ @disable this();
+ this(int) {}
+ this(ref S other) {}
+}
+
+void foo(S s) {}
+
+void main()
+{
+ S s = S(3);
+ foo(s);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20410.d b/gcc/testsuite/gdc.test/compilable/test20410.d
new file mode 100644
index 0000000..bed8017
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20410.d
@@ -0,0 +1,8 @@
+// https://issues.dlang.org/show_bug.cgi?id=20410
+
+enum E : string { foo = "foo" }
+
+static assert( is(E : string));
+static assert( is(E : T[], T));
+static assert(!is(E == string));
+static assert(!is(E == T[], T));
diff --git a/gcc/testsuite/gdc.test/compilable/test20417.d b/gcc/testsuite/gdc.test/compilable/test20417.d
new file mode 100644
index 0000000..230ad31
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20417.d
@@ -0,0 +1,12 @@
+// https://issues.dlang.org/show_bug.cgi?id=20417
+
+struct A { ~this(); }
+void f(A, int);
+A a();
+int i();
+
+static assert(__traits(compiles, { f(a, i); }));
+static assert(__traits(compiles, f(a, i)));
+
+static assert(is(typeof({ f(a, i); })));
+static assert(is(typeof(f(a, i))));
diff --git a/gcc/testsuite/gdc.test/compilable/test20420.d b/gcc/testsuite/gdc.test/compilable/test20420.d
new file mode 100644
index 0000000..5d99e9c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20420.d
@@ -0,0 +1,22 @@
+// REQUIRED_ARGS: -inline
+
+// https://issues.dlang.org/show_bug.cgi?id=20420
+
+struct S { ~this(); }
+
+class C
+{
+ this(S, int) {}
+}
+
+int i();
+
+C create()
+{
+ return new C(S(), i());
+}
+
+auto test()
+{
+ auto c = create();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20488.d b/gcc/testsuite/gdc.test/compilable/test20488.d
new file mode 100644
index 0000000..7b15ee1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20488.d
@@ -0,0 +1,11 @@
+module test20488;
+
+// https://issues.dlang.org/show_bug.cgi?id=20488
+struct Bar {
+ void opDispatch(string s, Args...) (Args args) {
+ }
+ void fun() {
+ (bool[int]).init.length;
+ this.f((int[int]).init.length);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20596.d b/gcc/testsuite/gdc.test/compilable/test20596.d
new file mode 100644
index 0000000..cd059c9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20596.d
@@ -0,0 +1,31 @@
+// PERMUTE_ARGS: -preview=dip1000
+
+// https://issues.dlang.org/show_bug.cgi?id=20596
+
+struct S(T)
+{
+ void delegate() dg;
+
+ this(scope void delegate() dg)
+ {
+ this.dg = dg;
+ }
+}
+
+@nogc void fooTemplate()
+{
+ int num;
+
+ void foo() { int dummy = num; }
+
+ scope s = S!int(&foo);
+}
+
+void test3032() @nogc
+{
+ int n = 1;
+ scope fp = (){ n = 10; }; // no closure
+ fp();
+}
+
+
diff --git a/gcc/testsuite/gdc.test/compilable/test20653.d b/gcc/testsuite/gdc.test/compilable/test20653.d
new file mode 100644
index 0000000..c7f329d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20653.d
@@ -0,0 +1,20 @@
+// LINK:
+enum x = 10;
+enum Thing { A, B }
+enum IsThing(T) = is(T == enum) || (__traits(getLinkage, T) == "C++");
+enum Is = IsThing!Thing;
+
+static assert(Is);
+
+enum Another(T) = is(T == int) && (__traits(getLinkage, T) == "C++");
+
+static assert(!Another!Thing);
+
+T myFunc(T)() { return T.init; }
+enum Foo(T) = is(T == int) || myFunc!T();
+
+void main ()
+{
+ assert(myFunc!int() == 0);
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/test20656.d b/gcc/testsuite/gdc.test/compilable/test20656.d
new file mode 100644
index 0000000..f68d654
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20656.d
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=20656
+
+import core.stdc.stdlib : free, malloc;
+
+@live
+void main()
+{
+ auto p = malloc(1);
+ free(p);
+ free(p);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20661.d b/gcc/testsuite/gdc.test/compilable/test20661.d
new file mode 100644
index 0000000..c755fa8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20661.d
@@ -0,0 +1,17 @@
+// https://issues.dlang.org/show_bug.cgi?id=20661
+
+class Context
+{
+ size_t[const(Key)] aa; /* Error: AA key type Key does not have bool opEquals(ref const Key) const */
+ bool* checkAll;
+}
+
+struct Key
+{
+ Context context;
+ bool opEquals(ref const Key other) @safe const
+ {
+ auto c = context.checkAll;
+ return true;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20695.d b/gcc/testsuite/gdc.test/compilable/test20695.d
new file mode 100644
index 0000000..fe4074b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20695.d
@@ -0,0 +1,35 @@
+// https://issues.dlang.org/show_bug.cgi?id=20695
+struct Bar
+{
+ this(const ref Bar o) {}
+
+ string a;
+ uint b;
+}
+
+struct Bar1
+{
+ @disable this(int a);
+ this(const ref Bar1 o) {}
+
+ string a;
+ uint b;
+}
+
+struct Bar2
+{
+ this(const ref Bar2 o) {}
+ @disable this(T)(T a) {}
+
+ string a;
+ uint b;
+}
+void main ()
+{
+ Bar b = { a: "Hello", b: 42 };
+ Bar c = Bar("Hello", 42);
+
+ Bar1 b1 = { a: "Hello", b: 42 };
+
+ Bar2 b2 = { a: "Hello", b: 42 };
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20710.d b/gcc/testsuite/gdc.test/compilable/test20710.d
new file mode 100644
index 0000000..277a3e5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20710.d
@@ -0,0 +1,24 @@
+// https://issues.dlang.org/show_bug.cgi?id=20710
+
+// with empty array literal
+immutable A a = A(B([]));
+immutable B b = a.b;
+
+struct A {
+ B b;
+}
+
+struct B {
+ int[] c;
+}
+
+// with empty struct literal
+immutable C c = C(D());
+immutable D d = c.d;
+
+struct C {
+ D d;
+}
+
+struct D {
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20744.d b/gcc/testsuite/gdc.test/compilable/test20744.d
new file mode 100644
index 0000000..ab9a9c8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20744.d
@@ -0,0 +1,13 @@
+// https://issues.dlang.org/show_bug.cgi?id=20744
+
+struct A {
+ struct S {}
+ void f(@S int = 3);
+ alias fun = Issue20744!f;
+}
+
+template Issue20744(func...) {
+ static if (is(typeof(func[0]) PT == __parameters)) {
+ alias Issue20744 = (PT args) {};
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20789.d b/gcc/testsuite/gdc.test/compilable/test20789.d
new file mode 100644
index 0000000..185042e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20789.d
@@ -0,0 +1,34 @@
+// REQUIRED_ARGS: -de
+module compilable.test20789;
+
+struct S(bool deprecateFunction, bool deprecateAlias)
+{
+ static if (deprecateFunction)
+ deprecated string get() { return "foo"; }
+ else
+ string get() { return "foo"; }
+
+ static if (deprecateAlias)
+ deprecated alias get this;
+ else
+ alias get this;
+}
+
+void main()
+{
+ void normalFun()
+ {
+ static assert( is(S!(false, false) : string));
+ static assert(!is(S!(false, true ) : string));
+ static assert(!is(S!(true , false) : string));
+ static assert(!is(S!(true , true ) : string));
+ }
+ deprecated void deprecatedFun()
+ {
+ // deprecations are allowed in a deprecated scope.
+ static assert(is(S!(false, false) : string));
+ static assert(is(S!(false, true ) : string));
+ static assert(is(S!(true , false) : string));
+ static assert(is(S!(true , true ) : string));
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20795.d b/gcc/testsuite/gdc.test/compilable/test20795.d
new file mode 100644
index 0000000..4b5cb17
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20795.d
@@ -0,0 +1,35 @@
+// https://issues.dlang.org/show_bug.cgi?id=20795
+
+// REQUIRED_ARGS: -preview=dip1000
+
+struct Foo
+{
+ void opEquals(T)(T rhs) if (T.init.opCast!string) {}
+}
+
+struct Bar
+{
+ void opEquals()(Bar)
+ {
+ Gun() == Foo();
+ }
+}
+
+class Baz
+{
+ void opCast(T)() {}
+}
+
+struct Gun
+{
+ void[24] buff;
+
+ auto underlying()
+ {
+ return cast(Baz) buff.ptr;
+ }
+
+ alias underlying this;
+
+ void opEquals(R)(R) if (Bar.init == R.init) {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20821.d b/gcc/testsuite/gdc.test/compilable/test20821.d
new file mode 100644
index 0000000..c018297
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20821.d
@@ -0,0 +1,17 @@
+// https://issues.dlang.org/show_bug.cgi?id=20821
+
+struct S
+{
+ int gun()(int i) { return 0; }
+ alias fun = gun;
+ int fun() { return 1; }
+
+ static int sgun()(int i) { return 0; }
+ alias sfun = sgun;
+ static int sfun() { return 1; }
+}
+
+static assert(S().fun == 1); // expressionsem.d changes
+static assert(S.sfun == 1); // ditto
+
+static assert(__traits(getOverloads, S, "fun", true).length == 2); // traits.d changes
diff --git a/gcc/testsuite/gdc.test/compilable/test20835.d b/gcc/testsuite/gdc.test/compilable/test20835.d
new file mode 100644
index 0000000..d1c0139
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20835.d
@@ -0,0 +1,59 @@
+// EXTRA_FILES: imports/test19344.d
+
+// https://issues.dlang.org/show_bug.cgi?id=20835
+
+template T(E) {
+ alias T = __traits(getAttributes, E.a);
+}
+
+void main()
+{
+ class C {}
+ enum E {
+ @C a
+ }
+
+ alias b = T!E;
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=19344
+
+import imports.test19344;
+
+struct Struct {
+ int value;
+}
+
+enum Enum {
+ @Struct(42) first,
+}
+
+static assert(getUDAs!(Enum.first, Struct)[0] == Struct(42));
+static assert(__traits(getAttributes, Enum.first)[0] == Struct(42));
+
+// https://issues.dlang.org/show_bug.cgi?id=21122
+
+void test21122()
+{
+ enum A;
+ enum E { @A a }
+
+ static assert(is(getAllUDAs!(E.a)[0] == A));
+}
+
+alias getAllUDAs(A...) = __traits(getAttributes, A);
+
+// https://issues.dlang.org/show_bug.cgi?id=21352
+
+@("aaa") enum Hoge {
+ @("bbb") foo, // tuple("aaa", "bbb") -> should be only tuple("bbb")
+ bar, // tuple()
+}
+@("aaa") struct Fuga {
+ @("bbb") int foo; // tuple("bbb")
+ int bar; // tuple()
+}
+static assert([__traits(getAttributes, Hoge.foo)] == ["bbb"]); //NG -> fixed
+static assert([__traits(getAttributes, Hoge.bar)] == []);
+static assert([__traits(getAttributes, Fuga.foo)] == ["bbb"]);
+static assert([__traits(getAttributes, Fuga.bar)] == []);
diff --git a/gcc/testsuite/gdc.test/compilable/test20842.d b/gcc/testsuite/gdc.test/compilable/test20842.d
new file mode 100644
index 0000000..86049e6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20842.d
@@ -0,0 +1,33 @@
+// https://issues.dlang.org/show_bug.cgi?id=20842
+
+struct A
+{
+ int i;
+ @disable this(ref A);
+}
+
+A a = { i: 123 };
+
+struct B
+{
+ int i;
+ @disable this();
+}
+
+B b = { i: 123 };
+
+union C
+{
+ int i;
+ @disable this(ref C);
+}
+
+C c = { i: 123 };
+
+union D
+{
+ int i;
+ @disable this();
+}
+
+D d = { i: 123 };
diff --git a/gcc/testsuite/gdc.test/compilable/test20868.d b/gcc/testsuite/gdc.test/compilable/test20868.d
new file mode 100644
index 0000000..90c3d32
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20868.d
@@ -0,0 +1,8 @@
+// https://issues.dlang.org/show_bug.cgi?id=20868
+// REQUIRED_ARGS: -preview=dip1000
+
+void scoped (scope void delegate() dg)
+{
+ static void delegate()[] dgs;
+ dgs ~= dg; // error
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20906.d b/gcc/testsuite/gdc.test/compilable/test20906.d
new file mode 100644
index 0000000..86ffeda
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20906.d
@@ -0,0 +1,15 @@
+/* REQUIRED_ARGS: -O
+ * No divide-by-zero constant folding errors
+ * https://issues.dlang.org/show_bug.cgi?id=20906
+ */
+
+int test12()
+{
+ int x = 0;
+ int a = x && 1 / x;
+ int b = !x || 1 / x;
+ int c = x ? 1 / x : 1;
+ int d = !x ? 1 : 1 / x;
+ return a | b | c;
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/test20909.d b/gcc/testsuite/gdc.test/compilable/test20909.d
new file mode 100644
index 0000000..743c979
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20909.d
@@ -0,0 +1,10 @@
+// https://issues.dlang.org/show_bug.cgi?id=20909
+
+struct S
+{
+ long a;
+ static assert(x.sizeof == 4);
+ enum offset = x.offsetof;
+ static assert(offset == 8); // OK now
+ int x;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20923.d b/gcc/testsuite/gdc.test/compilable/test20923.d
new file mode 100644
index 0000000..bae1eb3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20923.d
@@ -0,0 +1,13 @@
+version (D_LP64)
+{
+ alias size_t = uint;
+}
+else
+{
+ alias size_t = ulong;
+}
+
+struct S
+{
+ real not_reproduceable_without_this_variable;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test20958.d b/gcc/testsuite/gdc.test/compilable/test20958.d
new file mode 100644
index 0000000..d4ea92f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20958.d
@@ -0,0 +1,2 @@
+// EXTRA_FILES: imports/u20958.d
+import imports.u20958;
diff --git a/gcc/testsuite/gdc.test/compilable/test20990.d b/gcc/testsuite/gdc.test/compilable/test20990.d
new file mode 100644
index 0000000..aeae11d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test20990.d
@@ -0,0 +1,19 @@
+// REQUIRED_ARGS: -O
+// https://issues.dlang.org/show_bug.cgi?id=20990
+
+// foo() and bar() should produce the same code when
+// optimized.
+
+void foo(int* ptr)
+{
+ if (ptr is null)
+ assert(false);
+ *ptr = 42;
+}
+
+void bar(int* ptr)
+{
+ assert(ptr);
+ *ptr = 42;
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/test21050.d b/gcc/testsuite/gdc.test/compilable/test21050.d
new file mode 100644
index 0000000..5e81d23
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21050.d
@@ -0,0 +1,24 @@
+/*
+TEST_OUTPUT:
+----
+instantiated:long
+instantiated:int
+----
+*/
+struct S {
+ static int foo(T)(int i) { pragma(msg, "instantiated:", T.stringof); return 0; }
+ static int foo(T)(string s) { return 1; }
+}
+
+alias foo0 = __traits(getOverloads, S, "foo", true)[0];
+alias bar0 = foo0!long; // prints "instantiated:long"
+enum x = S.foo!long(0); // should not print "instantiated:long" again.
+static assert(bar0(3) == 0);
+alias bar0int = foo0!int; // prints "instantiated:int"
+enum y = S.foo!int(0); // should not print "instantiated:int" again.
+static assert(!__traits(compiles, bar0("hi")));
+
+alias foo1 = __traits(getOverloads, S, "foo", true)[1];
+alias bar1 = foo1!long;
+static assert(bar1("hi") == 1);
+static assert(!__traits(compiles, bar1(3)));
diff --git a/gcc/testsuite/gdc.test/compilable/test21058.d b/gcc/testsuite/gdc.test/compilable/test21058.d
new file mode 100644
index 0000000..8da9346
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21058.d
@@ -0,0 +1,25 @@
+struct A {
+ int foo(string s) { return 0; }
+}
+
+static assert(__traits(getOverloads, A.init, "foo")[0]("hi") == 0);
+static assert(__traits(getOverloads, A.init, "foo", true)[0]("hi") == 0);
+
+struct B {
+ int foo()(int i) { return 1; }
+ int foo(string s) { return 0; }
+}
+
+alias a = __traits(getOverloads, B.init, "foo", true);
+
+static assert(__traits(getOverloads, B.init, "foo")[0]("hi") == 0);
+static assert(__traits(getOverloads, B.init, "foo", true)[0]("hi") == 0);
+
+struct C {
+ static int foo()(int i) { return 1; }
+ int foo(string s) { return 0; }
+}
+
+static assert(__traits(getOverloads, C.init, "foo")[0]("hi") == 0);
+static assert(__traits(getOverloads, C.init, "foo", true)[0]("hi") == 0);
+static assert(__traits(getOverloads, C.init, "foo", true)[1](7) == 1);
diff --git a/gcc/testsuite/gdc.test/compilable/test21227.d b/gcc/testsuite/gdc.test/compilable/test21227.d
new file mode 100644
index 0000000..29dd2af
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21227.d
@@ -0,0 +1,19 @@
+// REQUIRED_ARGS: -Jcompilable/imports
+// EXTRA_FILES: imports/test21227/a..b.txt imports/test21227/a.txt imports/test21227/..foo/a.txt
+
+// https://issues.dlang.org/show_bug.cgi?id=21227
+
+void bar(string x) {}
+void test21227()
+{
+ import("./test21227/a.txt").bar;
+ import("test21227//a..b.txt").bar;
+ import("test21227/..foo/a.txt").bar;
+
+ version(Windows)
+ {
+ import(r".\test21227\a.txt").bar;
+ import(r"test21227\\a..b.txt").bar;
+ import(r"test21227\..foo\a.txt").bar;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21255.d b/gcc/testsuite/gdc.test/compilable/test21255.d
new file mode 100644
index 0000000..99a4dfb
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21255.d
@@ -0,0 +1,11 @@
+module test21255;
+
+void decodeA()(int i) { }
+void decodeB()(string s) { }
+
+alias decode = decodeA;
+alias decode = decodeB;
+
+void foo(alias A)() { A(1); A("hello"); }
+
+void main() { foo!decode; }
diff --git a/gcc/testsuite/gdc.test/compilable/test21282.d b/gcc/testsuite/gdc.test/compilable/test21282.d
new file mode 100644
index 0000000..761a6a6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21282.d
@@ -0,0 +1,15 @@
+/*
+TEST_OUTPUT:
+---
+tuple(func)
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=21282
+
+template I(T...) { alias I = T; }
+
+template Bug(T...) {
+ alias Bug = mixin("I!(T[0])");
+}
+void func() {}
+pragma(msg, Bug!func);
diff --git a/gcc/testsuite/gdc.test/compilable/test21299a.d b/gcc/testsuite/gdc.test/compilable/test21299a.d
index 049ee6a..3c6d8ec 100644
--- a/gcc/testsuite/gdc.test/compilable/test21299a.d
+++ b/gcc/testsuite/gdc.test/compilable/test21299a.d
@@ -1,4 +1,4 @@
-// EXTRA_SOURCES: imports/test21299/mtype.d imports/test21299/rootstringtable.d
+// EXTRA_SOURCES: imports/test21299/mtype.d imports/test21299/func.d imports/test21299/rootstringtable.d
// REQUIRED_ARGS: -main
// LINK
module test21299a;
diff --git a/gcc/testsuite/gdc.test/compilable/test21299b.d b/gcc/testsuite/gdc.test/compilable/test21299b.d
index b9d992a..9291c48 100644
--- a/gcc/testsuite/gdc.test/compilable/test21299b.d
+++ b/gcc/testsuite/gdc.test/compilable/test21299b.d
@@ -1,4 +1,4 @@
-// EXTRA_SOURCES: imports/test21299/func.d imports/test21299/rootstringtable.d
+// EXTRA_SOURCES: imports/test21299/mtype.d imports/test21299/func.d imports/test21299/rootstringtable.d
// REQUIRED_ARGS: -main
// LINK:
module test21299b;
diff --git a/gcc/testsuite/gdc.test/compilable/test21330.d b/gcc/testsuite/gdc.test/compilable/test21330.d
new file mode 100644
index 0000000..4abf367
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21330.d
@@ -0,0 +1,22 @@
+/*
+REQUIRED_ARGS: -unittest
+TEST_OUTPUT:
+---
+tuple(__unittest_L14_C5_1, __unittest_L14_C5_2)
+tuple(__unittest_L14_C5_2)
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=21330
+
+module test21330;
+
+mixin template Test() {
+ unittest {
+ }
+}
+
+mixin Test;
+mixin Test tm;
+
+pragma(msg, __traits(getUnitTests, test21330));
+pragma(msg, __traits(getUnitTests, tm));
diff --git a/gcc/testsuite/gdc.test/compilable/test21372.d b/gcc/testsuite/gdc.test/compilable/test21372.d
new file mode 100644
index 0000000..8d86721
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21372.d
@@ -0,0 +1,24 @@
+// REQUIRED_ARGS: -de
+struct S
+{
+ deprecated void foo(T)(int) { }
+ void foo(T)(string) { }
+}
+
+// just to be safe, check this order too
+// (there were some issues where naive checks of overloads were order dependent)
+struct T
+{
+ void foo(T)(string) { }
+ deprecated void foo(T)(int) { }
+}
+
+void main()
+{
+ // this should not hit the deprecation
+ // because the parameter type doesn't match it
+ S().foo!int("hi");
+
+ // likewise
+ T().foo!int("hi");
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21398.d b/gcc/testsuite/gdc.test/compilable/test21398.d
new file mode 100644
index 0000000..951bd91
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21398.d
@@ -0,0 +1,31 @@
+// https://issues.dlang.org/show_bug.cgi?id=21398
+
+module test21398;
+
+void free(void* ptr);
+
+class MAlloc(T)
+{
+ import test21398: free;
+
+ void free(T)(T* value)
+ {
+ free(value);
+ }
+}
+
+struct Box(T)
+{
+ private T* __ptr;
+ alias A = MAlloc!T;
+
+ ~this()
+ {
+ A.free(__ptr);
+ }
+}
+
+void main()
+{
+ auto b = Box!(char)();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21464.d b/gcc/testsuite/gdc.test/compilable/test21464.d
new file mode 100644
index 0000000..752cb57
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21464.d
@@ -0,0 +1,7 @@
+// https://issues.dlang.org/show_bug.cgi?id=21464
+// EXTRA_FILES: imports/test21464a.d
+void foo() pure
+{
+ import imports.test21464a : Mallocator;
+ auto a = Mallocator.instance; // mutable static, but empty struct
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21514.d b/gcc/testsuite/gdc.test/compilable/test21514.d
new file mode 100644
index 0000000..4eb8050
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21514.d
@@ -0,0 +1,20 @@
+// https://issues.dlang.org/show_bug.cgi?id=21514
+// DISABLED: win32 win64
+/* TEST_OUTPUT:
+---
+compilable/test21514.d(16): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/test21514.d(16): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/test21514.d(17): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/test21514.d(17): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/test21514.d(19): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/test21514.d(19): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/test21514.d(20): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/test21514.d(20): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
+---
+*/
+
+extern(C++) cdouble cpp_cadd1(cdouble c) { return c + 1; }
+extern(C++) creal cpp_cadd1l(creal c) { return c + 1; }
+
+cdouble cadd1(cdouble c) { return cpp_cadd1(c); }
+creal cadd1(creal c) { return cpp_cadd1l(c); }
diff --git a/gcc/testsuite/gdc.test/compilable/test21543.d b/gcc/testsuite/gdc.test/compilable/test21543.d
new file mode 100644
index 0000000..4914264
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21543.d
@@ -0,0 +1,116 @@
+// https://issues.dlang.org/show_bug.cgi?id=21543
+
+class B
+{
+ Nullable!B data;
+ alias data this;
+}
+
+void test1()
+{
+ B b;
+ Nullable!B n;
+}
+
+struct Nullable(T)
+{
+ T payload;
+
+ void opAssign()(T)
+ {
+ move(payload);
+ }
+
+ inout(T) get_() inout
+ {
+ return payload;
+ }
+
+ alias get_ this;
+}
+
+// another version with chain of 3 alias this
+
+struct C
+{
+ Nullable2 data;
+ alias data this;
+}
+
+void test2()
+{
+ C c;
+ Nullable2 n2 = &c;
+ Nullable3 n3 = &c;
+
+ // these are to check a sane -vcg-ast output
+ fn1(c);
+ fn1(n2);
+ fn1(n3);
+ fn2(c);
+ fn2(n2);
+ fn2(n3);
+ fn3(c);
+ fn3(n2);
+ fn3(n3);
+}
+
+void fn1(C x) {}
+
+void fn2(Nullable2 x) {}
+
+void fn3(Nullable3 x) {}
+
+struct Nullable2
+{
+ Nullable3 payload;
+
+ this(C* c)
+ {
+ payload = Nullable3(c);
+ }
+
+ void opAssign()(Nullable3)
+ {
+ move(payload);
+ }
+
+ inout(Nullable3) get_() inout
+ {
+ return payload;
+ }
+
+ alias get_ this;
+}
+
+struct Nullable3
+{
+ C* payload;
+
+ this(C* c)
+ {
+ payload = c;
+ }
+
+ void opAssign()(C)
+ {
+ move(payload);
+ }
+
+ inout(C) get_() inout
+ {
+ return *payload;
+ }
+
+ alias get_ this;
+}
+
+T move(T)(ref T source)
+{
+ return source;
+}
+
+T move(T)(T source)
+{
+ return source;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21591.d b/gcc/testsuite/gdc.test/compilable/test21591.d
new file mode 100644
index 0000000..54ffd15
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21591.d
@@ -0,0 +1,46 @@
+// https://issues.dlang.org/show_bug.cgi?id=21591
+
+alias F = void function();
+
+void fn1(void function(), void function());
+void fr1(F, F);
+static assert(fn1.mangleof == "_D9test215913fn1FPFZvQeZv");
+static assert(fr1.mangleof == "_D9test215913fr1FPFZvQeZv");
+
+void fn2(void function()*, void function()*);
+void fr2(F*, F*);
+static assert(fn2.mangleof == "_D9test215913fn2FPPFZvQfZv");
+static assert(fr2.mangleof == "_D9test215913fr2FPPFZvQfZv");
+
+void function() fn3(void function()**, void function()*);
+F fr3(F**, F*);
+static assert(fn3.mangleof == "_D9test215913fn3FPPPFZvQfZQh");
+static assert(fr3.mangleof == "_D9test215913fr3FPPPFZvQfZQh");
+
+void function()** fn4(ref void function(), ref void function()*);
+F** fr4(ref F, ref F*);
+static assert(fn4.mangleof == "_D9test215913fn4FKPFZvKPQgZPQf");
+static assert(fr4.mangleof == "_D9test215913fr4FKPFZvKPQgZPQf");
+
+
+alias D = void delegate();
+
+void dg1(void delegate(), void delegate());
+void dr1(D, D);
+static assert(dg1.mangleof == "_D9test215913dg1FDFZvQeZv");
+static assert(dr1.mangleof == "_D9test215913dr1FDFZvQeZv");
+
+void dg2(void delegate()*, void delegate()*);
+void dr2(D*, D*);
+static assert(dg2.mangleof == "_D9test215913dg2FPDFZvQfZv");
+static assert(dr2.mangleof == "_D9test215913dr2FPDFZvQfZv");
+
+void delegate() dg3(void delegate()**, void delegate()*);
+D dr3(D**, D*);
+static assert(dg3.mangleof == "_D9test215913dg3FPPDFZvQfZQh");
+static assert(dr3.mangleof == "_D9test215913dr3FPPDFZvQfZQh");
+
+void delegate()** dg4(ref void delegate(), ref void delegate()*);
+D** dr4(ref D, ref D*);
+static assert(dg4.mangleof == "_D9test215913dg4FKDFZvKPQgZPQf");
+static assert(dr4.mangleof == "_D9test215913dr4FKDFZvKPQgZPQf");
diff --git a/gcc/testsuite/gdc.test/compilable/test21659.d b/gcc/testsuite/gdc.test/compilable/test21659.d
new file mode 100644
index 0000000..28dfbca
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21659.d
@@ -0,0 +1,16 @@
+// https://issues.dlang.org/show_bug.cgi?id=21659
+
+// Compiler-recognized ident
+enum __c_ulonglong : ulong;
+
+private union EndianSwapper(T)
+{
+ T value;
+ ubyte[T.sizeof] array;
+ static assert(T.sizeof == ulong.sizeof);
+}
+
+void main ()
+{
+ EndianSwapper!(__c_ulonglong) val;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21661.d b/gcc/testsuite/gdc.test/compilable/test21661.d
new file mode 100644
index 0000000..f982d44
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21661.d
@@ -0,0 +1,24 @@
+// https://issues.dlang.org/show_bug.cgi?id=21661
+
+module pkg.pkg2.mod;
+
+immutable x = 1;
+enum e = pkg.pkg2.mod.x;
+
+// Some checks
+static assert( pkg.stringof == "package pkg" );
+static assert( pkg.pkg2.stringof == "package pkg2");
+static assert( pkg.pkg2.mod.stringof == "module mod" );
+static assert(pkg.pkg2.mod.x.stringof == "x" );
+
+alias p1 = pkg;
+alias p2 = pkg.pkg2;
+alias m = pkg.pkg2.mod;
+alias v = pkg.pkg2.mod.x;
+
+static assert( p1.stringof == "package pkg" );
+static assert( p2.stringof == "package pkg2");
+static assert( m.stringof == "module mod" );
+static assert(p1.pkg2.mod.stringof == "module mod" );
+static assert( p2.mod.stringof == "module mod" );
+static assert( v.stringof == "x" );
diff --git a/gcc/testsuite/gdc.test/compilable/test21668.d b/gcc/testsuite/gdc.test/compilable/test21668.d
new file mode 100644
index 0000000..a7c301a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21668.d
@@ -0,0 +1,7 @@
+// https://issues.dlang.org/show_bug.cgi?id=21668
+
+struct Opaque;
+
+void byPtr(Opaque*) {}
+void byRef(ref Opaque) {} // Fails
+void bySlice(Opaque[]) {}
diff --git a/gcc/testsuite/gdc.test/compilable/test21680.d b/gcc/testsuite/gdc.test/compilable/test21680.d
new file mode 100644
index 0000000..caa4df4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21680.d
@@ -0,0 +1,9 @@
+// https://issues.dlang.org/show_bug.cgi?id=21680
+
+struct Unique
+{
+ alias ValueType = typeof({ return field; }()); /* Error: need `this` for
+`field` of type `int` */
+ int field;
+ static assert(is(ValueType == int));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21743.d b/gcc/testsuite/gdc.test/compilable/test21743.d
new file mode 100644
index 0000000..dc3b709
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21743.d
@@ -0,0 +1,16 @@
+// https://issues.dlang.org/show_bug.cgi?id=21743
+
+struct A
+{
+ int foo(int a) { return a; }
+ string foo()(string b) { return b; }
+}
+
+alias ov = __traits(getOverloads, A.init, "foo", true);
+
+// member function works
+static assert(ov[0](1) == 1);
+
+// member template used to fail with the gagged error:
+// 'need this for foo of type pure nothrow @nogc @safe string(string b)'
+static assert(ov[1]("a") == "a");
diff --git a/gcc/testsuite/gdc.test/compilable/test21753.d b/gcc/testsuite/gdc.test/compilable/test21753.d
new file mode 100644
index 0000000..91ccc20
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21753.d
@@ -0,0 +1,21 @@
+// https://issues.dlang.org/show_bug.cgi?id=21753
+
+struct Sample {
+ int function() func1;
+ int function() func2;
+}
+
+void noth(Sample smpl)() {
+ static assert(smpl.func1() == 0);
+ static assert(smpl.func2() == 1);
+}
+
+void main() {
+ enum s = Sample(
+ { return 0; },
+ { return 1; }
+ );
+ static assert(s.func1() == 0);
+ static assert(s.func2() == 1);
+ noth!(s)();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21802.d b/gcc/testsuite/gdc.test/compilable/test21802.d
new file mode 100644
index 0000000..dc65a14
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21802.d
@@ -0,0 +1,38 @@
+// https://issues.dlang.org/show_bug.cgi?id=21802
+
+struct A
+{
+ auto opAssign(lazy void foo)
+ {
+ foo();
+ }
+ auto opOpAssign(string op)(lazy void foo)
+ {
+ foo();
+ }
+}
+
+class C
+{
+ auto opAssign(lazy void foo)
+ {
+ foo();
+ }
+ auto opOpAssign(string op)(lazy void foo)
+ {
+ foo();
+ }
+}
+
+void bar(int x) { }
+
+void main ()
+{
+ A a;
+ a ~= bar (1); // OK
+ a = bar (1); // Error: expression bar(1) is void and has no value
+
+ C c = new C;
+ c ~= bar(1);
+ c = bar(1);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21806.d b/gcc/testsuite/gdc.test/compilable/test21806.d
new file mode 100644
index 0000000..4b7a159
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21806.d
@@ -0,0 +1,24 @@
+// https://issues.dlang.org/show_bug.cgi?id=21806
+
+void main()
+{
+ ubyte[16] arr;
+ static assert(is(typeof( fun(arr[])) == char));
+ static assert(is(typeof(funtp(arr[])) == char));
+ static assert(is(typeof( bar(arr[])) == char));
+}
+
+// functions
+char fun(ubyte[] arr) { return 'X'; }
+
+int fun(ubyte[16] arr) { return 123; }
+
+// function templates
+char funtp()(ubyte[] arr) { return 'X'; }
+
+int funtp(size_t N)(ubyte[N] arr) { return 123; }
+
+// original case with 'in'
+char bar()(in ubyte[] arr) { return 'X'; }
+
+int bar(size_t N)(in ubyte[N] arr) { return 123; }
diff --git a/gcc/testsuite/gdc.test/compilable/test21828.d b/gcc/testsuite/gdc.test/compilable/test21828.d
new file mode 100644
index 0000000..06a67ca
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21828.d
@@ -0,0 +1,27 @@
+// https://issues.dlang.org/show_bug.cgi?id=21828
+
+struct S
+{
+ enum E
+ {
+ e1 = 0,
+ }
+ E e;
+ enum S s1 = S(E.e1);
+}
+
+SE se;
+
+enum SE
+{
+ e1 = S.s1
+}
+
+// reduced case, forward references just assume int value
+
+E e;
+
+enum E
+{
+ a = "x"
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21830.d b/gcc/testsuite/gdc.test/compilable/test21830.d
new file mode 100644
index 0000000..d1ead01
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21830.d
@@ -0,0 +1,25 @@
+// REQUIRED_ARGS: -de -unittest
+
+deprecated struct OldS21830 { }
+
+struct NewS21830 { }
+
+static if (1)
+{
+ auto test21830(T)(T t)
+ if (is(T == NewS21830))
+ {
+ return T.init;
+ }
+}
+
+deprecated auto test21830(T)(T t)
+if (is(T == OldS21830))
+{
+ return T.init;
+}
+
+unittest
+{
+ auto b = test21830(NewS21830()); // error here about using test21830!OldS21830
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21831.d b/gcc/testsuite/gdc.test/compilable/test21831.d
new file mode 100644
index 0000000..aaae135
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21831.d
@@ -0,0 +1,20 @@
+// REQUIRED_ARGS: -de -unittest
+
+deprecated struct S21831 { }
+
+auto test21831(T)(T t) // error: struct `S21831` is deprecated
+if (!__traits(isDeprecated, T))
+{
+ return T.init;
+}
+
+deprecated auto test21831(T)(T t)
+if (__traits(isDeprecated, T))
+{
+ return T.init;
+}
+
+deprecated unittest
+{
+ auto b = test21831(S21831()); // instantiated from here
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21832.d b/gcc/testsuite/gdc.test/compilable/test21832.d
new file mode 100644
index 0000000..e034f2c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21832.d
@@ -0,0 +1,13 @@
+// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/imp21832.d
+int test21832a()
+{
+ import imports.imp21832 : fun; // function 'fun' is deprecated
+ return fun(0);
+}
+
+int test21832b()
+{
+ import imports.imp21832 : tpl; // template 'tpl' is deprecated
+ return tpl(0);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21861.d b/gcc/testsuite/gdc.test/compilable/test21861.d
new file mode 100644
index 0000000..875636b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21861.d
@@ -0,0 +1,38 @@
+// https://issues.dlang.org/show_bug.cgi?id=21861
+
+int f() {
+ @("S")
+ struct S {}
+
+ @("U")
+ union U {}
+
+ @("C")
+ class C {}
+
+ // OK <- CTFE fails on this:
+ @("E")
+ enum E { X }
+
+ // OK <- CTFE fails on this:
+ @("f")
+ int f(int x) { return x + 2; }
+
+ // OK <- CTFE fails on this:
+ @(&f) int a;
+ @(1) @(2) int b = 4, c;
+ @(3) extern(C) int d = 3;
+
+ enum uda1 = __traits(getAttributes, a);
+ enum uda2 = __traits(getAttributes, b);
+ enum uda3 = __traits(getAttributes, c);
+
+ // These are to trigger a compiler assert if parser is updated in the future
+ static assert(!__traits(compiles, mixin("{ @(1) { int x; int y; } }")));
+ static assert(!__traits(compiles, mixin("{ @(1): int x; int y; }")));
+
+ // 3+2 1 2 4 1 3
+ return uda1[0](3) + uda2[0] + uda2[1] + b + uda3[0] + d;
+}
+
+static assert(f() == 16);
diff --git a/gcc/testsuite/gdc.test/compilable/test21876.d b/gcc/testsuite/gdc.test/compilable/test21876.d
new file mode 100644
index 0000000..a0cef99
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21876.d
@@ -0,0 +1,17 @@
+// https://issues.dlang.org/show_bug.cgi?id=21876
+
+auto test1()
+{
+ int[0] a;
+ return a;
+}
+
+auto test2()
+{
+ static int[0] a;
+ return a;
+}
+
+enum x = test1();
+enum y = test2();
+static assert(x == y && y == []);
diff --git a/gcc/testsuite/gdc.test/compilable/test22122.d b/gcc/testsuite/gdc.test/compilable/test22122.d
new file mode 100644
index 0000000..a06d06c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22122.d
@@ -0,0 +1,53 @@
+// EXTRA_FILES: imports/imp22122.d
+module imports.test22122;
+
+struct S22122
+{
+ import imports.imp22122;
+ Variant!(Imp22122)[] array;
+}
+
+void test22122_catch(S22122 s)
+{
+ try
+ {
+ foreach(elem; s.array)
+ {
+ import imports.imp22122;
+ with(elem.get!Imp22122)
+ {
+ }
+ }
+ }
+ catch (Exception)
+ {
+ }
+}
+
+void test22122_finally(S22122 s)
+{
+ try
+ {
+ foreach(elem; s.array)
+ {
+ import imports.imp22122;
+ with(elem.get!Imp22122)
+ {
+ }
+ }
+ }
+ finally
+ {
+ }
+}
+
+private struct Variant(T)
+{
+ union Impl
+ {
+ }
+ auto get(E)()
+ {
+ return Impl();
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22226.d b/gcc/testsuite/gdc.test/compilable/test22226.d
new file mode 100644
index 0000000..77b3797
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22226.d
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=22226
+
+struct A {}
+
+A move(A a) { return A.init; }
+
+struct SumType
+{
+ A a;
+
+ this(A value)
+ {
+ a = __ctfe ? value : move(value);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test25.d b/gcc/testsuite/gdc.test/compilable/test25.d
index 42fc814..449159c 100644
--- a/gcc/testsuite/gdc.test/compilable/test25.d
+++ b/gcc/testsuite/gdc.test/compilable/test25.d
@@ -1,10 +1,10 @@
// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/test25a.d imports/test25b.d
import imports.test25a, imports.test25b;
-import std.stdio;
+import core.stdc.stdio;
void main()
{
- std.stdio.writefln("hello");
+ printf("hello\n");
}
diff --git a/gcc/testsuite/gdc.test/compilable/test2991.d b/gcc/testsuite/gdc.test/compilable/test2991.d
index 61281b8..12cdb2f8 100644
--- a/gcc/testsuite/gdc.test/compilable/test2991.d
+++ b/gcc/testsuite/gdc.test/compilable/test2991.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/test2991.d
module test2991;
void foo()
diff --git a/gcc/testsuite/gdc.test/compilable/test3004.d b/gcc/testsuite/gdc.test/compilable/test3004.d
new file mode 100644
index 0000000..baa0cd7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test3004.d
@@ -0,0 +1,19 @@
+// https://issues.dlang.org/show_bug.cgi?id=3004
+/*
+REQUIRED_ARGS: -ignore -v
+TRANSFORM_OUTPUT: remove_lines("^(predefs|binary|version|config|DFLAG|parse|import|semantic|entry|function object|\s*$)")
+TEST_OUTPUT:
+---
+pragma GNU_attribute (__error)
+pragma GNU_attribute (__error)
+code test3004
+function test3004.test
+---
+*/
+
+extern(C) int printf(char*, ...);
+
+pragma(GNU_attribute, flatten)
+void test() { printf("Hello GNU world!\n".dup.ptr); }
+
+pragma(GNU_attribute, flatten);
diff --git a/gcc/testsuite/gdc.test/compilable/test313a.d b/gcc/testsuite/gdc.test/compilable/test313a.d
index daa6afb..5ec0211 100644
--- a/gcc/testsuite/gdc.test/compilable/test313a.d
+++ b/gcc/testsuite/gdc.test/compilable/test313a.d
@@ -1,5 +1,6 @@
/*
REQUIRED_ARGS: -de
+EXTRA_FILES: imports/a313.d imports/a313templatemixin1.d imports/a313templatemixin2.d imports/b313.d imports/pkg313/c313.d
*/
module test313;
diff --git a/gcc/testsuite/gdc.test/compilable/test313c.d b/gcc/testsuite/gdc.test/compilable/test313c.d
index 3b075bd..0110f62 100644
--- a/gcc/testsuite/gdc.test/compilable/test313c.d
+++ b/gcc/testsuite/gdc.test/compilable/test313c.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/pkgmod313/mod.d imports/pkgmod313/package.d
import imports.pkgmod313;
void test()
diff --git a/gcc/testsuite/gdc.test/compilable/test313d.d b/gcc/testsuite/gdc.test/compilable/test313d.d
index 7545d80..903cedf 100644
--- a/gcc/testsuite/gdc.test/compilable/test313d.d
+++ b/gcc/testsuite/gdc.test/compilable/test313d.d
@@ -1,5 +1,6 @@
// first imported as package
-// EXTRA_SOURCES: imports/pkgmod313/mod.d
+// COMPILED_IMPORTS: imports/pkgmod313/mod.d
+// EXTRA_FILES: imports/pkgmod313/package.d
// REQUIRED_ARGS: -de
import imports.pkgmod313; // then as package module
diff --git a/gcc/testsuite/gdc.test/compilable/test313e.d b/gcc/testsuite/gdc.test/compilable/test313e.d
index b24f24e..9ed8992 100644
--- a/gcc/testsuite/gdc.test/compilable/test313e.d
+++ b/gcc/testsuite/gdc.test/compilable/test313e.d
@@ -1,5 +1,5 @@
// first resolved as package, then created as module (with name package)
-// EXTRA_SOURCES: imports/pkgmod313/mod.d imports/pkgmod313/package.d
+// COMPILED_IMPORTS: imports/pkgmod313/mod.d imports/pkgmod313/package.d
// REQUIRED_ARGS: -de
import imports.pkgmod313; // then imported as package module
diff --git a/gcc/testsuite/gdc.test/compilable/test313f.d b/gcc/testsuite/gdc.test/compilable/test313f.d
index e758e37..c8ec63d 100644
--- a/gcc/testsuite/gdc.test/compilable/test313f.d
+++ b/gcc/testsuite/gdc.test/compilable/test313f.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/f313.d
import imports.f313;
void test()
diff --git a/gcc/testsuite/gdc.test/compilable/test313g.d b/gcc/testsuite/gdc.test/compilable/test313g.d
index f205214..91e320d 100644
--- a/gcc/testsuite/gdc.test/compilable/test313g.d
+++ b/gcc/testsuite/gdc.test/compilable/test313g.d
@@ -1,5 +1,6 @@
// REQUIRED_ARGS: -de
-// EXTRA_SOURCES: imports/g313.d
+// COMPILED_IMPORTS: imports/g313.d
+// EXTRA_FILES: imports/g313public.d imports/g313staticif.d imports/g313stringmixin.d imports/g313templatemixin.d
import imports.g313;
void test15900()
diff --git a/gcc/testsuite/gdc.test/compilable/test314.d b/gcc/testsuite/gdc.test/compilable/test314.d
index b7c15e3..0435228 100644
--- a/gcc/testsuite/gdc.test/compilable/test314.d
+++ b/gcc/testsuite/gdc.test/compilable/test314.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/a314.d imports/c314.d
module imports.test314; // package imports
import imports.a314;
diff --git a/gcc/testsuite/gdc.test/compilable/test3775.d b/gcc/testsuite/gdc.test/compilable/test3775.d
index 47b9b88..a34b329 100644
--- a/gcc/testsuite/gdc.test/compilable/test3775.d
+++ b/gcc/testsuite/gdc.test/compilable/test3775.d
@@ -1,4 +1,4 @@
-// 3775
+// https://issues.dlang.org/show_bug.cgi?id=3775
struct Bug3775 {
static int byLine()() { return 1; }
diff --git a/gcc/testsuite/gdc.test/compilable/test4003.d b/gcc/testsuite/gdc.test/compilable/test4003.d
index 8a401f2..f51310e 100644
--- a/gcc/testsuite/gdc.test/compilable/test4003.d
+++ b/gcc/testsuite/gdc.test/compilable/test4003.d
@@ -1,4 +1,5 @@
-// EXTRA_SOURCES: imports/test4003a.d
+// COMPILED_IMPORTS: imports/test4003a.d
+// EXTRA_FILES: imports/stdio4003.d imports/typecons4003.d
// PERMUTE_ARGS:
import imports.stdio4003;
diff --git a/gcc/testsuite/gdc.test/compilable/test4375.d b/gcc/testsuite/gdc.test/compilable/test4375.d
index 234895e..f5c4e4a 100644
--- a/gcc/testsuite/gdc.test/compilable/test4375.d
+++ b/gcc/testsuite/gdc.test/compilable/test4375.d
@@ -1,5 +1,6 @@
// REQUIRED_ARGS: -unittest
-// 4375: disallow dangling else
+// https://issues.dlang.org/show_bug.cgi?id=4375
+// disallow dangling else
void main() {
@@ -368,7 +369,7 @@ class C {
else
assert(63);
}
- body {
+ do {
if (true)
assert(64);
else
diff --git a/gcc/testsuite/gdc.test/compilable/test50.d b/gcc/testsuite/gdc.test/compilable/test50.d
index f05c3e4..a5dfac0 100644
--- a/gcc/testsuite/gdc.test/compilable/test50.d
+++ b/gcc/testsuite/gdc.test/compilable/test50.d
@@ -1,4 +1,4 @@
-// EXTRA_SOURCES: imports/test50a.d
+// COMPILED_IMPORTS: imports/test50a.d
// PERMUTE_ARGS:
import imports.test50a;
diff --git a/gcc/testsuite/gdc.test/compilable/test5227.d b/gcc/testsuite/gdc.test/compilable/test5227.d
index 63ca752..b713191 100644
--- a/gcc/testsuite/gdc.test/compilable/test5227.d
+++ b/gcc/testsuite/gdc.test/compilable/test5227.d
@@ -11,17 +11,19 @@ log2()
log10()
0.740363L
round()
-6.00000L
+6.0L
floor()
-5.00000F
-5.00000
-5.00000L
+5.0F
+5.0
+5.0L
ceil()
-6.00000F
-6.00000
-6.00000L
+6.0F
+6.0
+6.0L
trunc()
-5.00000L
+5.0L
+exp()
+244.692L
expm1()
243.692L
exp2()
@@ -83,6 +85,11 @@ enum truncf = trunc(5.5f); //pragma(msg, truncf);
enum truncd = trunc(5.5 ); //pragma(msg, truncd);
enum truncr = trunc(5.5L); pragma(msg, truncr);
+pragma(msg, "exp()");
+enum expf = exp(5.5f); //pragma(msg, expf);
+enum expd = exp(5.5 ); //pragma(msg, expd);
+enum expr = exp(5.5L); pragma(msg, expr);
+
pragma(msg, "expm1()");
enum expm1f = expm1(5.5f); //pragma(msg, expm1f);
enum expm1d = expm1(5.5 ); //pragma(msg, expm1d);
diff --git a/gcc/testsuite/gdc.test/compilable/test55.d b/gcc/testsuite/gdc.test/compilable/test55.d
index 0dd7b7b..6dfc665 100644
--- a/gcc/testsuite/gdc.test/compilable/test55.d
+++ b/gcc/testsuite/gdc.test/compilable/test55.d
@@ -1,5 +1,5 @@
// COMPILE_SEPARATELY
-// EXTRA_SOURCES: imports/test55a.d
+// COMPILED_IMPORTS: imports/test55a.d
// PERMUTE_ARGS: -dw
// REQUIRED_ARGS: -d
diff --git a/gcc/testsuite/gdc.test/compilable/test59.d b/gcc/testsuite/gdc.test/compilable/test59.d
index c9f4edf..de10c91 100644
--- a/gcc/testsuite/gdc.test/compilable/test59.d
+++ b/gcc/testsuite/gdc.test/compilable/test59.d
@@ -1,4 +1,4 @@
// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/test59a.d imports/test59b.d
public import imports.test59a;
public import imports.test59b;
diff --git a/gcc/testsuite/gdc.test/compilable/test5973.d b/gcc/testsuite/gdc.test/compilable/test5973.d
new file mode 100644
index 0000000..a54b0ae
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test5973.d
@@ -0,0 +1,41 @@
+// https://issues.dlang.org/show_bug.cgi?id=5973
+
+class A { int a = 1; }
+class B { int b = 2; }
+class C : A
+{
+ B obj;
+ alias obj this;
+ this(){ obj = new B(); }
+}
+class X : C {}
+
+class D
+{
+ int i;
+}
+
+class E
+{
+ D x;
+ alias x this;
+}
+
+class F : E
+{
+ void test()
+ {
+ i = 5;
+ }
+}
+
+void main()
+{
+ auto c = new C();
+ assert(c.a == 1); // lookup C -> A, OK
+ assert(c.b == 2); // lookup C => B, OK
+
+ auto x = new X();
+ assert(x.a == 1); // lookup X -> C -> A, OK
+ assert(x.b == 2); // lookup X -> C => B, NG (Line 17)
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test6013.d b/gcc/testsuite/gdc.test/compilable/test6013.d
index 5824c91..2856eeb 100644
--- a/gcc/testsuite/gdc.test/compilable/test6013.d
+++ b/gcc/testsuite/gdc.test/compilable/test6013.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/test6013.d
import imports.test6013;
static assert(__traits(compiles, public_alias_value));
diff --git a/gcc/testsuite/gdc.test/compilable/test602.d b/gcc/testsuite/gdc.test/compilable/test602.d
index 979af91..a17aa16 100644
--- a/gcc/testsuite/gdc.test/compilable/test602.d
+++ b/gcc/testsuite/gdc.test/compilable/test602.d
@@ -42,7 +42,7 @@ static assert(!__traits(compiles, (bool b)
label: {}
assert(!x);
}
- catch
+ catch(Throwable)
{
}
}));
@@ -54,7 +54,7 @@ static assert(!__traits(compiles, (bool b)
try
{
}
- catch
+ catch(Throwable)
{
int x;
label: {}
@@ -383,7 +383,7 @@ static assert(!__traits(compiles, (bool b)
}));
/***************************************************/
-// 11659
+// https://issues.dlang.org/show_bug.cgi?id=11659
int test11659()
{
@@ -394,7 +394,7 @@ int test11659()
}
/***************************************************/
-// 13321
+// https://issues.dlang.org/show_bug.cgi?id=13321
void test13321(bool b)
{
diff --git a/gcc/testsuite/gdc.test/compilable/test61.d b/gcc/testsuite/gdc.test/compilable/test61.d
index e4d3d65..e2700d6 100644
--- a/gcc/testsuite/gdc.test/compilable/test61.d
+++ b/gcc/testsuite/gdc.test/compilable/test61.d
@@ -1,5 +1,5 @@
// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/test61a.d
import imports.test61a;
alias imports.test61a.bar bar;
diff --git a/gcc/testsuite/gdc.test/compilable/test62.d b/gcc/testsuite/gdc.test/compilable/test62.d
index c723a96..fa42145 100644
--- a/gcc/testsuite/gdc.test/compilable/test62.d
+++ b/gcc/testsuite/gdc.test/compilable/test62.d
@@ -1,5 +1,5 @@
// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/test62a.d
import imports.test62a;
struct S { }
diff --git a/gcc/testsuite/gdc.test/compilable/test63.d b/gcc/testsuite/gdc.test/compilable/test63.d
index 70d4964..9cf986d 100644
--- a/gcc/testsuite/gdc.test/compilable/test63.d
+++ b/gcc/testsuite/gdc.test/compilable/test63.d
@@ -1,4 +1,4 @@
-// EXTRA_SOURCES: imports/test63a.d
+// COMPILED_IMPORTS: imports/test63a.d
// PERMUTE_ARGS:
private import imports.test63a;
diff --git a/gcc/testsuite/gdc.test/compilable/test6395.d b/gcc/testsuite/gdc.test/compilable/test6395.d
index a1bac8e..3b80203 100644
--- a/gcc/testsuite/gdc.test/compilable/test6395.d
+++ b/gcc/testsuite/gdc.test/compilable/test6395.d
@@ -2,7 +2,7 @@
// EXTRA_SOURCES: b6395.d
// EXTRA_FILES: extra-files/c6395.d
-// 6395
+// https://issues.dlang.org/show_bug.cgi?id=6395
import c6395;
diff --git a/gcc/testsuite/gdc.test/compilable/test6541.d b/gcc/testsuite/gdc.test/compilable/test6541.d
new file mode 100644
index 0000000..b492215
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test6541.d
@@ -0,0 +1,10 @@
+class C
+{
+ static synchronized func(alias a)() {}
+}
+
+void main()
+{
+ int a;
+ C.func!a();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test66.d b/gcc/testsuite/gdc.test/compilable/test66.d
index 1213884..9db082e 100644
--- a/gcc/testsuite/gdc.test/compilable/test66.d
+++ b/gcc/testsuite/gdc.test/compilable/test66.d
@@ -1,5 +1,5 @@
// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/test66a.d
import imports.test66a;
alias int TOK;
@@ -11,7 +11,7 @@ enum
struct Token
{
- static char[] tochars[TOKmax];
+ static char[][TOKmax] tochars;
}
class Lexer
diff --git a/gcc/testsuite/gdc.test/compilable/test67.d b/gcc/testsuite/gdc.test/compilable/test67.d
index bcd48b2..9f45c64 100644
--- a/gcc/testsuite/gdc.test/compilable/test67.d
+++ b/gcc/testsuite/gdc.test/compilable/test67.d
@@ -1,5 +1,5 @@
// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/test67a.d
import imports.test67a;
interface I
diff --git a/gcc/testsuite/gdc.test/compilable/test6777.d b/gcc/testsuite/gdc.test/compilable/test6777.d
new file mode 100644
index 0000000..161a94a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test6777.d
@@ -0,0 +1,11 @@
+struct S {}
+
+class C {
+ S s;
+ alias s this;
+}
+
+void main() {
+ auto c = new C;
+ auto p = cast(void*) c;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test68.d b/gcc/testsuite/gdc.test/compilable/test68.d
index bfac489..55a7995 100644
--- a/gcc/testsuite/gdc.test/compilable/test68.d
+++ b/gcc/testsuite/gdc.test/compilable/test68.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
-
-// Bugzilla 4278
+// EXTRA_FILES: imports/test68a.d
+// https://issues.dlang.org/show_bug.cgi?id=4278
import imports.test68a;
diff --git a/gcc/testsuite/gdc.test/compilable/test69.d b/gcc/testsuite/gdc.test/compilable/test69.d
index fb8e1ba..66662dc 100644
--- a/gcc/testsuite/gdc.test/compilable/test69.d
+++ b/gcc/testsuite/gdc.test/compilable/test69.d
@@ -16,7 +16,7 @@ void fromFail49()
}
}
-// Bugzilla 5735
+// https://issues.dlang.org/show_bug.cgi?id=5735
struct A {}
void b() {}
diff --git a/gcc/testsuite/gdc.test/compilable/test6999.d b/gcc/testsuite/gdc.test/compilable/test6999.d
index c4e916f..c9f414f 100644
--- a/gcc/testsuite/gdc.test/compilable/test6999.d
+++ b/gcc/testsuite/gdc.test/compilable/test6999.d
@@ -1,4 +1,4 @@
-// 6999: inout in front of return type
+// https://issues.dlang.org/show_bug.cgi?id=6999: inout in front of return type
struct A
{
diff --git a/gcc/testsuite/gdc.test/compilable/test70.d b/gcc/testsuite/gdc.test/compilable/test70.d
index 9a821b2..f4aa900 100644
--- a/gcc/testsuite/gdc.test/compilable/test70.d
+++ b/gcc/testsuite/gdc.test/compilable/test70.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/test70.d
import imports.test70 : foo;
void foo(int) // overloads with selective import
diff --git a/gcc/testsuite/gdc.test/compilable/test71.d b/gcc/testsuite/gdc.test/compilable/test71.d
index 83b24a0..bc26f76 100644
--- a/gcc/testsuite/gdc.test/compilable/test71.d
+++ b/gcc/testsuite/gdc.test/compilable/test71.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/test71.d
import imports.test71;
void bar()
diff --git a/gcc/testsuite/gdc.test/compilable/test7172.d b/gcc/testsuite/gdc.test/compilable/test7172.d
index a4cf663..859f29a 100644
--- a/gcc/testsuite/gdc.test/compilable/test7172.d
+++ b/gcc/testsuite/gdc.test/compilable/test7172.d
@@ -7,7 +7,7 @@ void main()
static assert(!__traits(compiles, { class D : FinalC{} }));
scope class ScopeC{}
- static assert(!__traits(compiles, { auto sc = new ScopeC(); }));
+// static assert(!__traits(compiles, { auto sc = new ScopeC(); }));
static assert( __traits(compiles, { scope sc = new ScopeC(); }));
synchronized class SyncC{ void f(){} }
diff --git a/gcc/testsuite/gdc.test/compilable/test72.d b/gcc/testsuite/gdc.test/compilable/test72.d
index 5de9d42..6e6890f 100644
--- a/gcc/testsuite/gdc.test/compilable/test72.d
+++ b/gcc/testsuite/gdc.test/compilable/test72.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/test72a.d imports/test72b.d imports/test72c.d
module test72;
import imports.test72a, imports.test72c;
diff --git a/gcc/testsuite/gdc.test/compilable/test7399.d b/gcc/testsuite/gdc.test/compilable/test7399.d
index 76ac920..dba0741 100644
--- a/gcc/testsuite/gdc.test/compilable/test7399.d
+++ b/gcc/testsuite/gdc.test/compilable/test7399.d
@@ -1,6 +1,6 @@
-// 7399
+// https://issues.dlang.org/show_bug.cgi?id=7399
static assert(!__traits(compiles, { import non.existing.file; }));
-// 7400
+// https://issues.dlang.org/show_bug.cgi?id=7400
static assert(!is(typeof({import non_existing_file;})));
diff --git a/gcc/testsuite/gdc.test/compilable/test7491.d b/gcc/testsuite/gdc.test/compilable/test7491.d
index eb742e2..ce0e5e4 100644
--- a/gcc/testsuite/gdc.test/compilable/test7491.d
+++ b/gcc/testsuite/gdc.test/compilable/test7491.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/test7491a.d imports/test7491b.d
struct Struct
{
import object;
diff --git a/gcc/testsuite/gdc.test/compilable/test7524.d b/gcc/testsuite/gdc.test/compilable/test7524.d
index 6ff491a..a0bb918 100644
--- a/gcc/testsuite/gdc.test/compilable/test7524.d
+++ b/gcc/testsuite/gdc.test/compilable/test7524.d
@@ -1,3 +1,3 @@
-// 7524
+// https://issues.dlang.org/show_bug.cgi?id=7524
#line __LINE__ "y.d"
diff --git a/gcc/testsuite/gdc.test/compilable/test7754.d b/gcc/testsuite/gdc.test/compilable/test7754.d
index 1ce9b44..724dce4 100644
--- a/gcc/testsuite/gdc.test/compilable/test7754.d
+++ b/gcc/testsuite/gdc.test/compilable/test7754.d
@@ -1,6 +1,23 @@
-// REQUIRED_ARGS: -H -Hd${RESULTS_DIR}/compilable
-// POST_SCRIPT: compilable/extra-files/test7754-postscript.sh
-// PERMUTE_ARGS: -d -dw
+/*
+REQUIRED_ARGS: -H -Hd${RESULTS_DIR}/compilable
+PERMUTE_ARGS: -d -dw
+
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/test7754.di
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/test7754.di
+// D import file generated from 'compilable/test7754.d'
+struct Foo(T)
+{
+ shared static this()
+ {
+ }
+ static this()
+ {
+ }
+}
+---
+*/
struct Foo(T)
{
diff --git a/gcc/testsuite/gdc.test/compilable/test8509.d b/gcc/testsuite/gdc.test/compilable/test8509.d
index a907223..5790223 100644
--- a/gcc/testsuite/gdc.test/compilable/test8509.d
+++ b/gcc/testsuite/gdc.test/compilable/test8509.d
@@ -1,6 +1,10 @@
module test8509;
enum E : string { a = "hello", b = "world" }
-struct S { E opCat(S s) { return E.a; } E opCat(string s) { return E.a; } }
+struct S
+{
+ E opBinary(string s : "~")(S s) { return E.a; }
+ E opBinary(string s : "~")(string s) { return E.a; }
+}
void main()
{
diff --git a/gcc/testsuite/gdc.test/compilable/test8543.d b/gcc/testsuite/gdc.test/compilable/test8543.d
index 4b29542..c72b0d92 100644
--- a/gcc/testsuite/gdc.test/compilable/test8543.d
+++ b/gcc/testsuite/gdc.test/compilable/test8543.d
@@ -1,5 +1,5 @@
-version (D_SIMD)
+static if (__traits(compiles, __vector(float[4])))
{
struct vfloat
{
diff --git a/gcc/testsuite/gdc.test/compilable/test8696.d b/gcc/testsuite/gdc.test/compilable/test8696.d
index 755d529..dd58c8f 100644
--- a/gcc/testsuite/gdc.test/compilable/test8696.d
+++ b/gcc/testsuite/gdc.test/compilable/test8696.d
@@ -1,6 +1,7 @@
// REQUIRED_ARGS: -w
-// 8696: incorrect dangling else with version():
+// https://issues.dlang.org/show_bug.cgi?id=8696
+// incorrect dangling else with version():
version (all):
version (linux)
diff --git a/gcc/testsuite/gdc.test/compilable/test8922a.d b/gcc/testsuite/gdc.test/compilable/test8922a.d
index e2f3d5c..8980c93 100644
--- a/gcc/testsuite/gdc.test/compilable/test8922a.d
+++ b/gcc/testsuite/gdc.test/compilable/test8922a.d
@@ -1,4 +1,5 @@
// PERMUTE_ARGS:
+// EXTRA_FILES: imports/bug8922.d
import imports.bug8922;
void test()
diff --git a/gcc/testsuite/gdc.test/compilable/test8922b.d b/gcc/testsuite/gdc.test/compilable/test8922b.d
index a91601b..007f9b6 100644
--- a/gcc/testsuite/gdc.test/compilable/test8922b.d
+++ b/gcc/testsuite/gdc.test/compilable/test8922b.d
@@ -1,4 +1,5 @@
// PERMUTE_ARGS:
+// EXTRA_FILES: imports/bug8922.d
void test()
{
import imports.bug8922;
diff --git a/gcc/testsuite/gdc.test/compilable/test8922c.d b/gcc/testsuite/gdc.test/compilable/test8922c.d
index da5ad3a..fa208a0 100644
--- a/gcc/testsuite/gdc.test/compilable/test8922c.d
+++ b/gcc/testsuite/gdc.test/compilable/test8922c.d
@@ -1,4 +1,5 @@
// PERMUTE_ARGS:
+// EXTRA_FILES: imports/bug8922.d
static import imports.bug8922;
void test()
diff --git a/gcc/testsuite/gdc.test/compilable/test8922d.d b/gcc/testsuite/gdc.test/compilable/test8922d.d
index 4a56dd7..4898cf6 100644
--- a/gcc/testsuite/gdc.test/compilable/test8922d.d
+++ b/gcc/testsuite/gdc.test/compilable/test8922d.d
@@ -1,4 +1,5 @@
// PERMUTE_ARGS:
+// EXTRA_FILES: imports/bug8922.d
void test()
{
static import imports.bug8922;
diff --git a/gcc/testsuite/gdc.test/compilable/test8922e.d b/gcc/testsuite/gdc.test/compilable/test8922e.d
index 3c52d00..b6d2d92 100644
--- a/gcc/testsuite/gdc.test/compilable/test8922e.d
+++ b/gcc/testsuite/gdc.test/compilable/test8922e.d
@@ -1,4 +1,5 @@
// PERMUTE_ARGS:
+// EXTRA_FILES: imports/bug8922.d
import renamed = imports.bug8922;
void test()
diff --git a/gcc/testsuite/gdc.test/compilable/test8922f.d b/gcc/testsuite/gdc.test/compilable/test8922f.d
index 2b2eb0f..2008e89 100644
--- a/gcc/testsuite/gdc.test/compilable/test8922f.d
+++ b/gcc/testsuite/gdc.test/compilable/test8922f.d
@@ -1,4 +1,5 @@
// PERMUTE_ARGS:
+// EXTRA_FILES: imports/bug8922.d
void test()
{
import renamed = imports.bug8922;
diff --git a/gcc/testsuite/gdc.test/compilable/test9209.d b/gcc/testsuite/gdc.test/compilable/test9209.d
index 03c2b79..8eca799 100644
--- a/gcc/testsuite/gdc.test/compilable/test9209.d
+++ b/gcc/testsuite/gdc.test/compilable/test9209.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
-// 9209
+// https://issues.dlang.org/show_bug.cgi?id=9209
auto array(T)(T t){ return t; }
diff --git a/gcc/testsuite/gdc.test/compilable/test9274.d b/gcc/testsuite/gdc.test/compilable/test9274.d
new file mode 100644
index 0000000..7ad5cda
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test9274.d
@@ -0,0 +1,26 @@
+// https://issues.dlang.org/show_bug.cgi?id=9274
+struct S
+{
+ float[] arr;
+ alias arr this;
+}
+
+static assert(!is(S == float[])); // ok
+static assert(!is(S == T[], T)); // fails
+static assert(is(S : float[]));
+static assert(is(S : T[], T));
+
+//https://issues.dlang.org/show_bug.cgi?id=9274
+struct A(T)
+{}
+
+struct B
+{
+ A!int _a;
+ alias _a this;
+}
+
+static assert(!is(B == A!int)); // OK
+static assert(!is(B == A!X, X)); // assertion fails
+static assert(is(B : A!int));
+static assert(is(B : A!X, X));
diff --git a/gcc/testsuite/gdc.test/compilable/test9276.d b/gcc/testsuite/gdc.test/compilable/test9276.d
index f6cefa5..14857a8 100644
--- a/gcc/testsuite/gdc.test/compilable/test9276.d
+++ b/gcc/testsuite/gdc.test/compilable/test9276.d
@@ -1,6 +1,6 @@
+// EXTRA_FILES: imports/test9276decl.d imports/test9276expr.d imports/test9276hash.d imports/test9276sem.d imports/test9276type.d imports/test9276util.d imports/test9276visitors.d
// EXTRA_SOURCES: imports/test9276parser.d
-
// This is a dummy module for compilable test
void main()
{}
diff --git a/gcc/testsuite/gdc.test/compilable/test9278a.d b/gcc/testsuite/gdc.test/compilable/test9278a.d
index 932411f..e0f483b 100644
--- a/gcc/testsuite/gdc.test/compilable/test9278a.d
+++ b/gcc/testsuite/gdc.test/compilable/test9278a.d
@@ -1,4 +1,4 @@
-// PREMUTE_ARGS:
+// PERMUTE_ARGS:
// Works fine here
struct datum { float num = 0.0; }
diff --git a/gcc/testsuite/gdc.test/compilable/test9278b.d b/gcc/testsuite/gdc.test/compilable/test9278b.d
index 0b4fee2..cca9000 100644
--- a/gcc/testsuite/gdc.test/compilable/test9278b.d
+++ b/gcc/testsuite/gdc.test/compilable/test9278b.d
@@ -1,4 +1,4 @@
-// PREMUTE_ARGS:
+// PERMUTE_ARGS:
// Works fine here
//struct datum { float num = 0.0; }
diff --git a/gcc/testsuite/gdc.test/compilable/test930.d b/gcc/testsuite/gdc.test/compilable/test930.d
new file mode 100644
index 0000000..fa444af
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test930.d
@@ -0,0 +1,22 @@
+// https://issues.dlang.org/show_bug.cgi?id=930
+template ATemplate(T)
+{
+ template ATemplate()
+ {
+ auto foo()
+ {
+ T x = 2; // this line causes an error
+ }
+ }
+}
+
+class TheClass(alias MixIt)
+{
+ mixin MixIt!();
+}
+
+void main()
+{
+ auto val = new TheClass!(ATemplate!(int));
+ val.foo();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test9434.d b/gcc/testsuite/gdc.test/compilable/test9434.d
index 26c7117..a03b391 100644
--- a/gcc/testsuite/gdc.test/compilable/test9434.d
+++ b/gcc/testsuite/gdc.test/compilable/test9434.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: test9435.d
import test9435;//semantic;
template Visitors()
diff --git a/gcc/testsuite/gdc.test/compilable/test9435.d b/gcc/testsuite/gdc.test/compilable/test9435.d
index 7046fdd..5ef5079 100644
--- a/gcc/testsuite/gdc.test/compilable/test9435.d
+++ b/gcc/testsuite/gdc.test/compilable/test9435.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: test9434.d
import test9434;//expression;
enum TokenType { Dot }
diff --git a/gcc/testsuite/gdc.test/compilable/test9436.d b/gcc/testsuite/gdc.test/compilable/test9436.d
index 2baee7c..5b650bd 100644
--- a/gcc/testsuite/gdc.test/compilable/test9436.d
+++ b/gcc/testsuite/gdc.test/compilable/test9436.d
@@ -1,4 +1,4 @@
// EXTRA_SOURCES: imports/test9436interp.d
-
+// EXTRA_FILES: imports/test9436aggr.d imports/test9436node.d imports/test9436type.d
// this is a dummy module for test 9436.
diff --git a/gcc/testsuite/gdc.test/compilable/test9613.d b/gcc/testsuite/gdc.test/compilable/test9613.d
index c49c293..6bf8793 100644
--- a/gcc/testsuite/gdc.test/compilable/test9613.d
+++ b/gcc/testsuite/gdc.test/compilable/test9613.d
@@ -1,4 +1,4 @@
-// PREMUTE_ARGS:
+// PERMUTE_ARGS:
struct S9613
{
int f(
diff --git a/gcc/testsuite/gdc.test/compilable/test9672.d b/gcc/testsuite/gdc.test/compilable/test9672.d
index bb10e3a..8bcd92f 100644
--- a/gcc/testsuite/gdc.test/compilable/test9672.d
+++ b/gcc/testsuite/gdc.test/compilable/test9672.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/test9672a.d
module test9672; // node
import imports.test9672a; // interpret
diff --git a/gcc/testsuite/gdc.test/compilable/test9692.d b/gcc/testsuite/gdc.test/compilable/test9692.d
index 765b657..57131b8 100644
--- a/gcc/testsuite/gdc.test/compilable/test9692.d
+++ b/gcc/testsuite/gdc.test/compilable/test9692.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: test9692a.d imports/test9692b.d
module test9692;
import test9692a;
diff --git a/gcc/testsuite/gdc.test/compilable/test9701.d b/gcc/testsuite/gdc.test/compilable/test9701.d
index 8f822ad..68055c4 100644
--- a/gcc/testsuite/gdc.test/compilable/test9701.d
+++ b/gcc/testsuite/gdc.test/compilable/test9701.d
@@ -1,4 +1,11 @@
// https://issues.dlang.org/show_bug.cgi?id=9701
+/*
+TEST_OUTPUT:
+---
+compilable/test9701.d(68): Deprecation: enum member `test9701.Enum.value7` is deprecated
+compilable/test9701.d(68): Deprecation: enum member `test9701.Enum.value8` is deprecated - message
+---
+*/
template AliasSeq(TList...)
{
@@ -56,3 +63,6 @@ static assert(__traits(getAttributes, value3) == AliasSeq!("uda0", uda4));
static assert(__traits(getAttributes, value4) == AliasSeq!("uda0", uda5, uda6));
static assert(__traits(getAttributes, value5) == AliasSeq!("uda0", "uda7", uda8));
static assert(__traits(getAttributes, value6) == AliasSeq!("uda0", uda9, "uda10"));
+
+// Test that messages are correctly displayed
+static assert(Enum.value7 != Enum.value8);
diff --git a/gcc/testsuite/gdc.test/compilable/test9818.d b/gcc/testsuite/gdc.test/compilable/test9818.d
index 779b1cf..dbf1901 100644
--- a/gcc/testsuite/gdc.test/compilable/test9818.d
+++ b/gcc/testsuite/gdc.test/compilable/test9818.d
@@ -1,5 +1,5 @@
/************************************/
-// 9818
+// https://issues.dlang.org/show_bug.cgi?id=9818
/*
TEST_OUTPUT:
diff --git a/gcc/testsuite/gdc.test/compilable/test9919.d b/gcc/testsuite/gdc.test/compilable/test9919.d
index 5cf8bc9..06f41d8 100644
--- a/gcc/testsuite/gdc.test/compilable/test9919.d
+++ b/gcc/testsuite/gdc.test/compilable/test9919.d
@@ -1,5 +1,5 @@
// REQUIRED_ARGS: -o-
-
+// EXTRA_FILES: imports/test9919a.d imports/test9919b.d imports/test9919c.d
module test9919;
public
diff --git a/gcc/testsuite/gdc.test/compilable/testAliasLookup.d b/gcc/testsuite/gdc.test/compilable/testAliasLookup.d
new file mode 100644
index 0000000..786c2f4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/testAliasLookup.d
@@ -0,0 +1,60 @@
+// REQUIRED_ARGS: -preview=fixAliasThis
+
+// https://issues.dlang.org/show_bug.cgi?id=16086
+struct A
+{
+ void tail() {}
+}
+
+struct S16086
+{
+ struct Inner2
+ {
+ Inner a;
+ alias a this;
+ }
+
+ struct Inner
+ {
+ int unique_identifier_name;
+ int tail = 2;
+ }
+
+ Inner2 inner;
+ alias inner this;
+
+ auto works()
+ {
+ return unique_identifier_name;
+ }
+
+ auto fails()
+ {
+ int a = tail;
+ return tail; // Line 22
+ // The workaround: return this.tail;
+ }
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=16082
+struct S16082
+{
+ struct Inner
+ {
+ int any_name_but_modulename;
+ int aliasthis = 5;
+ }
+
+ Inner inner;
+ alias inner this;
+
+ auto works()
+ {
+ return any_name_but_modulename;
+ }
+ auto fails()
+ {
+ return aliasthis; // Line 20
+ }
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/testCpCtor.d b/gcc/testsuite/gdc.test/compilable/testCpCtor.d
new file mode 100644
index 0000000..847c0f4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/testCpCtor.d
@@ -0,0 +1,21 @@
+// https://issues.dlang.org/show_bug.cgi?id=19870
+struct T
+{
+ int i;
+ this(ref return scope inout typeof(this) src)
+ inout @safe pure nothrow @nogc
+ {
+ i = src.i;
+ }
+}
+
+struct S
+{
+ T t;
+}
+
+void main()
+{
+ T a;
+ S b = S(a);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/testDIP37a.d b/gcc/testsuite/gdc.test/compilable/testDIP37a.d
index 8bd8b2d..5aa67f2 100644
--- a/gcc/testsuite/gdc.test/compilable/testDIP37a.d
+++ b/gcc/testsuite/gdc.test/compilable/testDIP37a.d
@@ -1,7 +1,7 @@
// PERMUTE_ARGS:
-// REQUIRED_ARGS: -c -Icompilable/extra-files
-// EXTRA_SOURCES: extra-files/pkgDIP37/datetime/package.d
-// EXTRA_SOURCES: extra-files/pkgDIP37/datetime/common.d
+// REQUIRED_ARGS: -Icompilable/extra-files
+// COMPILED_IMPORTS: extra-files/pkgDIP37/datetime/package.d
+// COMPILED_IMPORTS: extra-files/pkgDIP37/datetime/common.d
void main()
{
diff --git a/gcc/testsuite/gdc.test/compilable/testInference.d b/gcc/testsuite/gdc.test/compilable/testInference.d
index 3248f3e..9ffecc1 100644
--- a/gcc/testsuite/gdc.test/compilable/testInference.d
+++ b/gcc/testsuite/gdc.test/compilable/testInference.d
@@ -1,6 +1,6 @@
/***************************************************/
-// 6265.
+// https://issues.dlang.org/show_bug.cgi?id=6265
pure nothrow @safe int h6265() {
return 1;
@@ -63,7 +63,7 @@ void fECPb() {
}
/***************************************************/
-// 5635
+// https://issues.dlang.org/show_bug.cgi?id=5635
pure bool foo5635(R = int)(string x)
{
@@ -79,7 +79,7 @@ void test5635()
}
/***************************************************/
-// 5936
+// https://issues.dlang.org/show_bug.cgi?id=5936
auto bug5936c(R)(R i) @safe pure nothrow {
return true;
@@ -87,7 +87,7 @@ auto bug5936c(R)(R i) @safe pure nothrow {
static assert( bug5936c(0) );
/***************************************************/
-// 6351
+// https://issues.dlang.org/show_bug.cgi?id=6351
void bug6351(alias dg)()
{
@@ -101,7 +101,7 @@ void test6351()
}
/***************************************************/
-// 6359
+// https://issues.dlang.org/show_bug.cgi?id=6359
void impure6359() nothrow @safe @nogc {}
void throwable6359() pure @safe @nogc {}
@@ -164,7 +164,7 @@ void test6359() pure nothrow @safe @nogc
}
/***************************************************/
-// 7017
+// https://issues.dlang.org/show_bug.cgi?id=7017
template map7017(fun...) if (fun.length >= 1)
{
@@ -190,7 +190,7 @@ void test7017a() pure
}
/***************************************************/
-// 7017 (little simpler cases)
+// https://issues.dlang.org/show_bug.cgi?id=7017 (little simpler cases)
auto map7017a(alias fun)() { return fun(); } // depends on purity of fun
auto map7017b(alias fun)() { return; } // always pure
@@ -239,7 +239,7 @@ pure string escapeShellArguments()
}
/***************************************************/
-// 8234
+// https://issues.dlang.org/show_bug.cgi?id=8234
void test8234()
{
@@ -259,7 +259,7 @@ void test8234()
}
/***************************************************/
-// 8504
+// https://issues.dlang.org/show_bug.cgi?id=8504
import core.demangle : demangle;
@@ -267,7 +267,7 @@ void foo8504()()
{
static assert(typeof(foo8504!()).stringof == "void()");
static assert(typeof(foo8504!()).mangleof == "FZv");
- static assert(demangle(foo8504!().mangleof) == "void testInference.foo8504!().foo8504()");
+// static assert(demangle(foo8504!().mangleof) == "void testInference.foo8504!().foo8504()");
}
auto toDelegate8504a(F)(auto ref F fp) { return fp; }
@@ -291,7 +291,7 @@ void test8504()
}
/***************************************************/
-// 8751
+// https://issues.dlang.org/show_bug.cgi?id=8751
alias bool delegate(in int) pure Bar8751;
Bar8751 foo8751a(immutable int x) pure
@@ -304,7 +304,7 @@ Bar8751 foo8751b(const int x) pure
}
/***************************************************/
-// 8793
+// https://issues.dlang.org/show_bug.cgi?id=8793
alias bool delegate(in int) pure Dg8793;
alias bool function(in int) pure Fp8793;
@@ -327,7 +327,7 @@ Dg8793 foo8793ptr1(immutable int* p) pure { return x => *p == x; } // OK
Dg8793 foo8793ptr2(const int* p) pure { return x => *p == x; } // OK <- error
/***************************************************/
-// 9072
+// https://issues.dlang.org/show_bug.cgi?id=9072
struct A9072(T)
{
@@ -340,7 +340,9 @@ void test9072()
}
/***************************************************/
-// 5933 + Issue 8504 - Template attribute inferrence doesn't work
+// https://issues.dlang.org/show_bug.cgi?id=5933
+// https://issues.dlang.org/show_bug.cgi?id=8504
+// Template attribute inferrence doesn't work
int foo5933()(int a) { return a*a; }
struct S5933
@@ -359,7 +361,7 @@ void test5933()
}
/***************************************************/
-// 9148
+// https://issues.dlang.org/show_bug.cgi?id=9148
void test9148a() pure
{
@@ -517,7 +519,7 @@ void test9148e()
}
/***************************************************/
-// 12912
+// https://issues.dlang.org/show_bug.cgi?id=12912
struct S12912(alias fun)
{
@@ -539,7 +541,7 @@ class C12912
}
/***************************************************/
-// 10002
+// https://issues.dlang.org/show_bug.cgi?id=10002
void impure10002() {}
void remove10002(alias pred, bool impure = false, Range)(Range range)
@@ -568,7 +570,7 @@ class Node10002
}
/***************************************************/
-// 10148
+// https://issues.dlang.org/show_bug.cgi?id=10148
void fa10148() {} // fa is @system
@@ -604,7 +606,7 @@ void test10148()
}
/***************************************************/
-// 10289
+// https://issues.dlang.org/show_bug.cgi?id=10289
void test10289()
{
@@ -645,7 +647,7 @@ void test10289()
}
/***************************************************/
-// 10296
+// https://issues.dlang.org/show_bug.cgi?id=10296
void foo10296()()
{
@@ -661,7 +663,7 @@ pure void test10296()
}
/***************************************************/
-// 12025
+// https://issues.dlang.org/show_bug.cgi?id=12025
struct Foo12025
{
@@ -689,7 +691,7 @@ void test12025b() pure
}
/***************************************************/
-// 12542
+// https://issues.dlang.org/show_bug.cgi?id=12542
int logOf12542(T)(T n)
{
@@ -704,14 +706,14 @@ void test12542() @safe nothrow pure
}
/***************************************************/
-// 12704
+// https://issues.dlang.org/show_bug.cgi?id=12704
void foo12704() @system;
alias FP12704 = typeof(function() { foo12704(); });
static assert(is(FP12704 == void function() @system));
/***************************************************/
-// 12970
+// https://issues.dlang.org/show_bug.cgi?id=12970
@system { @safe void f12970a() {} }
@system { void f12970b() @safe {} }
@@ -769,7 +771,7 @@ static assert(AliasDecl_FP2.stringof == "void function()");
static assert(AliasDecl_FP3.stringof == "void function() @safe");
/***************************************************/
-// 13217
+// https://issues.dlang.org/show_bug.cgi?id=13217
void writeln13217(string) {}
@@ -788,7 +790,7 @@ void test13217()
}
/***************************************************/
-// 13840
+// https://issues.dlang.org/show_bug.cgi?id=13840
struct Foo13840
{
diff --git a/gcc/testsuite/gdc.test/compilable/testVRP.d b/gcc/testsuite/gdc.test/compilable/testVRP.d
index 954b501..bdd72d0 100644
--- a/gcc/testsuite/gdc.test/compilable/testVRP.d
+++ b/gcc/testsuite/gdc.test/compilable/testVRP.d
@@ -371,7 +371,7 @@ void bug1977_comment20()
}
/******************************************/
-// 9617
+// https://issues.dlang.org/show_bug.cgi?id=9617
void test9617()
{
diff --git a/gcc/testsuite/gdc.test/compilable/testcontracts.d b/gcc/testsuite/gdc.test/compilable/testcontracts.d
index 21c0e4b..6a36190 100644
--- a/gcc/testsuite/gdc.test/compilable/testcontracts.d
+++ b/gcc/testsuite/gdc.test/compilable/testcontracts.d
@@ -1,4 +1,4 @@
-// EXTRA_SOURCES: imports/testcontracts.d
+// COMPILED_IMPORTS: imports/testcontracts.d
import imports.testcontracts;
@@ -13,7 +13,7 @@ class Derived3602 : Base3602
assert(x > 0);
assert(y > 0);
}
- body
+ do
{
}
}
@@ -35,31 +35,31 @@ class Foo17502
{
auto foo()
out {}
- body {}
+ do {}
auto bar()
out { assert (__result > 5); }
- body { return 6; }
+ do { return 6; }
auto bar_2()
out (res) { assert (res > 5); }
- body { return 6; }
+ do { return 6; }
int concrete()
out { assert(__result > 5); }
- body { return 6; }
+ do { return 6; }
int concrete_2()
out(res) { assert (res > 5); }
- body { return 6; }
+ do { return 6; }
void void_foo()
out {}
- body {}
+ do {}
auto void_auto()
out {}
- body {}
+ do {}
}
/***************************************************/
@@ -76,7 +76,7 @@ class A17502
{
assert(res > 5);
}
- body
+ do
{
return p;
}
@@ -89,7 +89,7 @@ class C17502 : B17502
{
assert(p > 3);
}
- body
+ do
{
return p * 2;
}
@@ -102,7 +102,7 @@ class B17502 : A17502
{
assert(p > 2);
}
- body
+ do
{
return p * 3;
}
@@ -118,7 +118,7 @@ class X17502 : Y17502
{
assert(p > 3);
}
- body
+ do
{
return p * 2;
}
@@ -131,7 +131,7 @@ class Y17502 : Z17502
{
assert(p > 2);
}
- body
+ do
{
return p * 3;
}
@@ -148,7 +148,7 @@ class Z17502
{
assert(res > 5);
}
- body
+ do
{
return p;
}
@@ -166,9 +166,21 @@ final class Foo17893(T)
{
maythrow();
}
- body
+ do
{
}
}
Foo17893!int foo17893;
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15984
+
+alias Bar15984 = extern (C) void function(void*);
+
+final class C15984
+{
+ void foo(Bar15984 bar)
+ in { assert(bar); }
+ do {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/testcstuff3.d b/gcc/testsuite/gdc.test/compilable/testcstuff3.d
new file mode 100644
index 0000000..89228a9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/testcstuff3.d
@@ -0,0 +1,4 @@
+// EXTRA_FILES: imports/cstuff3.c
+import imports.cstuff3;
+
+static assert(squared(4) == 16);
diff --git a/gcc/testsuite/gdc.test/compilable/testdip1008.d b/gcc/testsuite/gdc.test/compilable/testdip1008.d
new file mode 100644
index 0000000..5e024fe
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/testdip1008.d
@@ -0,0 +1,21 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -preview=dip1008
+
+int bar()
+{
+ try
+ {
+ throw new Exception("message");
+ }
+ catch (Exception e)
+ {
+ return 7;
+ }
+}
+
+
+void foo()
+{
+ enum r = bar();
+ static assert(r == 7);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/testexpression.d b/gcc/testsuite/gdc.test/compilable/testexpression.d
index b581df7..df49132 100644
--- a/gcc/testsuite/gdc.test/compilable/testexpression.d
+++ b/gcc/testsuite/gdc.test/compilable/testexpression.d
@@ -54,8 +54,6 @@ void TestOpAndAssign(Tx, Ux, ops)()
struct boolean { alias TT!(bool) x; }
struct integral { alias TT!(byte, ubyte, short, ushort, int, uint, long, ulong) x; }
struct floating { alias TT!(float, double, real) x; }
-struct imaginary { alias TT!(ifloat, idouble, ireal) x; }
-struct complex { alias TT!(cfloat, cdouble, creal) x; }
struct all { alias TT!("+=", "-=", "*=", "/=", "%=", "&=", "|=", "^=", "<<=", ">>=", ">>>=") x; }
struct arith { alias TT!("+=", "-=", "*=", "/=", "%=") x; }
@@ -76,17 +74,6 @@ void OpAssignCases(alias X)()
X!(floating, boolean, arith)();
X!(floating, integral, arith)();
X!(floating, floating, arith)();
-
- X!(imaginary, boolean, muldivmod)();
- X!(imaginary, integral, muldivmod)();
- X!(imaginary, floating, muldivmod)();
- X!(imaginary, imaginary, addsub)();
-
- X!(complex, boolean, arith)();
- X!(complex, integral, arith)();
- X!(complex, floating, arith)();
- X!(complex, imaginary, arith)();
- X!(complex, complex, nomod)();
}
void OpReAssignCases(alias X)()
@@ -99,23 +86,12 @@ void OpReAssignCases(alias X)()
X!(floating, boolean, arith)();
X!(floating, integral, arith)();
X!(floating, floating, arith)();
-
- X!(imaginary, boolean, muldivmod)();
- X!(imaginary, integral, muldivmod)();
- X!(imaginary, floating, muldivmod)();
- X!(imaginary, imaginary, addsub)();
-
- X!(complex, boolean, arith)();
- X!(complex, integral, arith)();
- X!(complex, floating, arith)();
- X!(complex, imaginary, arith)();
- X!(complex, complex, nomod)();
}
void main()
{
OpAssignCases!TestOpAssign();
OpAssignCases!TestOpAssignAssign(); // was once disabled due to bug 7436
- OpAssignCases!TestOpAssignAuto(); // 5181
+ OpAssignCases!TestOpAssignAuto(); // https://issues.dlang.org/show_bug.cgi?id=5181
OpReAssignCases!TestOpAndAssign();
}
diff --git a/gcc/testsuite/gdc.test/compilable/testfwdref.d b/gcc/testsuite/gdc.test/compilable/testfwdref.d
index 12b5cc8..d5ad5fa 100644
--- a/gcc/testsuite/gdc.test/compilable/testfwdref.d
+++ b/gcc/testsuite/gdc.test/compilable/testfwdref.d
@@ -1,7 +1,8 @@
// PERMUTE_ARGS:
+// EXTRA_FILES: imports/fwdref9514.d imports/fwdref12201a.d
/***************************************************/
-// 6766
+// https://issues.dlang.org/show_bug.cgi?id=6766
class Foo6766
{
@@ -16,7 +17,7 @@ struct Bar6766
}
/***************************************************/
-// 8609
+// https://issues.dlang.org/show_bug.cgi?id=8609
struct Tuple8609(T)
{
@@ -48,7 +49,7 @@ struct Bar8609b
}
/***************************************************/
-// 8698
+// https://issues.dlang.org/show_bug.cgi?id=8698
interface IRoot8698a {}
interface IClass8698a : IRoot8698a { }
@@ -67,7 +68,7 @@ void test8698b(Class8698b.Value) { }
interface IRoot8698b {}
/***************************************************/
-// 9514
+// https://issues.dlang.org/show_bug.cgi?id=9514
template TStructHelpers9514a()
{
@@ -112,7 +113,7 @@ template FieldNames9514b()
}
/***************************************************/
-// 10015
+// https://issues.dlang.org/show_bug.cgi?id=10015
struct S10015(T) { alias X = int; }
@@ -120,7 +121,7 @@ alias Y10015 = s10015.X;
S10015!int s10015;
/***************************************************/
-// 10101
+// https://issues.dlang.org/show_bug.cgi?id=10101
int front10101(int);
@@ -147,7 +148,7 @@ void test10101()
}
/***************************************************/
-// 11019
+// https://issues.dlang.org/show_bug.cgi?id=11019
class A11019
{
@@ -162,7 +163,7 @@ class B11019 : A11019
class D11019 : B11019 {}
/***************************************************/
-// 11166
+// https://issues.dlang.org/show_bug.cgi?id=11166
template Tup11166(T...) { alias Tup11166 = T; }
@@ -193,7 +194,7 @@ struct S11166b
}
/***************************************************/
-// 12152
+// https://issues.dlang.org/show_bug.cgi?id=12152
class A12152
{
@@ -208,7 +209,7 @@ class B12152 : A12152
static assert(is(A12152.Y == int));
/***************************************************/
-// 12201
+// https://issues.dlang.org/show_bug.cgi?id=12201
template T12201()
{
@@ -258,7 +259,7 @@ struct S12201b
}
/***************************************************/
-// 12531
+// https://issues.dlang.org/show_bug.cgi?id=12531
struct Node12531(T)
{
@@ -274,7 +275,7 @@ void test12531()
}
/***************************************************/
-// 12543
+// https://issues.dlang.org/show_bug.cgi?id=12543
class C12543;
static assert(C12543.sizeof == (void*).sizeof);
@@ -282,7 +283,7 @@ static assert(C12543.alignof == (void*).sizeof);
static assert(C12543.mangleof == "C10testfwdref6C12543");
/***************************************************/
-// 14010
+// https://issues.dlang.org/show_bug.cgi?id=14010
enum E14010;
static assert(E14010.mangleof == "E10testfwdref6E14010");
@@ -291,7 +292,7 @@ struct S14010;
static assert(S14010.mangleof == "S10testfwdref6S14010");
/***************************************************/
-// 12983
+// https://issues.dlang.org/show_bug.cgi?id=12983
alias I12983 = int;
class B12983(T) { alias MyC = C12983!string; }
@@ -307,7 +308,7 @@ void f12983();
void f12983(I12983);
/***************************************************/
-// 12984
+// https://issues.dlang.org/show_bug.cgi?id=12984
class B12984a { alias MyD = D12984a!int; }
class C12984a : B12984a { }
@@ -343,7 +344,7 @@ static assert(__traits(classInstanceSize, B12984b) == (void*).sizeof * 2 + int.s
static assert(__traits(classInstanceSize, C12984b) == (void*).sizeof * 2 + int.sizeof * 2);
/***************************************************/
-// 14390
+// https://issues.dlang.org/show_bug.cgi?id=14390
class B14390a { alias MyD = D14390a!int; }
class C14390a : B14390a { void f(int) {} }
@@ -356,7 +357,7 @@ class D14390b(T) { alias MyE = E14390b!float; }
class E14390b(T) : D14390b!int { void m() { auto c = new C14390b(); } }
/***************************************************/
-// 13860
+// https://issues.dlang.org/show_bug.cgi?id=13860
/*
TEST_OUTPUT:
@@ -386,7 +387,7 @@ void test13860()
}
/***************************************************/
-// 14083
+// https://issues.dlang.org/show_bug.cgi?id=14083
class NBase14083
{
@@ -436,7 +437,7 @@ static assert(
}());
/***************************************************/
-// 14549
+// https://issues.dlang.org/show_bug.cgi?id=14549
string foo14549(T)()
{
@@ -480,7 +481,8 @@ class Bar14549
}
// ----
-// 14609 - regression case
+// https://issues.dlang.org/show_bug.cgi?id=14609
+// regression case
interface Foo14609(T)
{
@@ -651,7 +653,7 @@ void test15726y()
}
/***************************************************/
-// 15726
+// https://issues.dlang.org/show_bug.cgi?id=15726
struct RC15726(T)
{
diff --git a/gcc/testsuite/gdc.test/compilable/testheader1.d b/gcc/testsuite/gdc.test/compilable/testheader1.d
index 256a1fe..9b14f7b 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader1.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader1.d
@@ -1,12 +1,9 @@
-// EXTRA_SOURCES: extra-files/header1.d
-// REQUIRED_ARGS: -o- -unittest -H -Hf${RESULTS_DIR}/compilable/header1.di
-// PERMUTE_ARGS: -d -dw
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh
/*
-TEST_OUTPUT:
----
-Hello World
----
+EXTRA_SOURCES: extra-files/header1.d
+REQUIRED_ARGS: -o- -unittest -H -Hf${RESULTS_DIR}/compilable/testheader1.di -ignore
+PERMUTE_ARGS: -d -dw
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader1.di
+TEST_OUTPUT_FILE: extra-files/header1.di
*/
void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/testheader12567a.d b/gcc/testsuite/gdc.test/compilable/testheader12567a.d
index 27c1475..3372d87 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader12567a.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader12567a.d
@@ -1,6 +1,16 @@
-// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/header12567a.di
-// PERMUTE_ARGS:
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh header12567a
+/*
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader12567a.di
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader12567a.di
+
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/testheader12567a.di
+// D import file generated from 'compilable/testheader12567a.d'
+deprecated module header12567a;
+void main();
+---
+*/
deprecated module header12567a;
diff --git a/gcc/testsuite/gdc.test/compilable/testheader12567b.d b/gcc/testsuite/gdc.test/compilable/testheader12567b.d
index 93393c5..f17a37e 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader12567b.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader12567b.d
@@ -1,6 +1,16 @@
-// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/header12567b.di
-// PERMUTE_ARGS:
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh header12567b
+/*
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader12567b.di
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader12567b.di
+
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/testheader12567b.di
+// D import file generated from 'compilable/testheader12567b.d'
+deprecated("message") module header12567b;
+void main();
+---
+*/
deprecated("message") module header12567b;
diff --git a/gcc/testsuite/gdc.test/compilable/testheader17125.d b/gcc/testsuite/gdc.test/compilable/testheader17125.d
new file mode 100644
index 0000000..7549f61
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/testheader17125.d
@@ -0,0 +1,19 @@
+/*
+EXTRA_SOURCES: extra-files/header17125.d
+PERMUTE_ARGS:
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader17125.di
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader17125.di
+
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/testheader17125.di
+// D import file generated from 'compilable/extra-files/header17125.d'
+void func1(real value = 103500.0L);
+void func2(real value = 520199.0F);
+void func3(real value = 970000.0);
+void func4(real value = 102450.0F);
+void func5(real value = 412502.0L);
+---
+*/
+
+void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/testheader1i.d b/gcc/testsuite/gdc.test/compilable/testheader1i.d
index 0eca3c4..f79a1af 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader1i.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader1i.d
@@ -1,12 +1,9 @@
-// EXTRA_SOURCES: extra-files/header1.d
-// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/header1i.di -inline
-// PERMUTE_ARGS: -d -dw
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh
/*
-TEST_OUTPUT:
----
-Hello World
----
+EXTRA_SOURCES: extra-files/header1.d
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader1i.di -inline -ignore
+PERMUTE_ARGS: -d -dw
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader1i.di
+TEST_OUTPUT_FILE: extra-files/header1i.di
*/
void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/testheader2.d b/gcc/testsuite/gdc.test/compilable/testheader2.d
index 003d564..25cc3c9 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader2.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader2.d
@@ -1,6 +1,9 @@
-// EXTRA_SOURCES: extra-files/header2.d
-// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/header2.di
-// PERMUTE_ARGS:
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh header2
+/*
+EXTRA_SOURCES: extra-files/header2.d
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader2.di
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader2.di
+TEST_OUTPUT_FILE: extra-files/header2.di
+*/
void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/testheader2i.d b/gcc/testsuite/gdc.test/compilable/testheader2i.d
index 79662ed..517fae4 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader2i.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader2i.d
@@ -1,6 +1,9 @@
-// EXTRA_SOURCES: extra-files/header2.d
-// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/header2i.di -inline
-// PERMUTE_ARGS:
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh header2i
+/*
+EXTRA_SOURCES: extra-files/header2.d
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader2i.di -inline
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader2i.di
+TEST_OUTPUT_FILE: extra-files/header2i.di
+*/
void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/testheader3.d b/gcc/testsuite/gdc.test/compilable/testheader3.d
index f5fdbc1..be38d7c 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader3.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader3.d
@@ -1,8 +1,27 @@
-// EXTRA_SOURCES: extra-files/header3.d
-// REQUIRED_ARGS: -o- -unittest -H -Hf${RESULTS_DIR}/compilable/header3.di
-// PERMUTE_ARGS: -d -dw
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh header3
-
-void main() {}
+/*
+EXTRA_SOURCES: extra-files/header3.d
+REQUIRED_ARGS: -o- -unittest -H -Hf${RESULTS_DIR}/compilable/testheader3.di
+PERMUTE_ARGS: -d -dw
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader3.di
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/testheader3.di
+// D import file generated from 'compilable/extra-files/header3.d'
+auto elseifchain()
+{
+ bool a, b, c;
+ if (a)
+ {
+ }
+ else if (b)
+ {
+ }
+ else if (c)
+ {
+ }
+}
+---
+*/
+void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d b/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d
index 5ee9486..b6b0ed1 100644
--- a/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d
+++ b/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d
@@ -1,6 +1,22 @@
-// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheaderudamodule.di
-// PERMUTE_ARGS:
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh testheaderudamodule
+/*
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheaderudamodule.di
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheaderudamodule.di
+
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/testheaderudamodule.di
+// D import file generated from 'compilable/testheaderudamodule.d'
+@(1, UDA(2))
+module testheaderudamodule;
+struct UDA
+{
+ int a;
+}
+void main();
+void foo(@(1) int bar, @UDA(2) string bebe);
+---
+*/
@(1, UDA(2))
module testheaderudamodule;
@@ -12,4 +28,4 @@ struct UDA
void main() {}
-void foo(@(1) int bar, @UDA(2) string bebe);
+void foo(@(1) int bar, @UDA(2) string bebe) {}
diff --git a/gcc/testsuite/gdc.test/compilable/testimport12242.d b/gcc/testsuite/gdc.test/compilable/testimport12242.d
index 1d1cccd..39e0c16 100644
--- a/gcc/testsuite/gdc.test/compilable/testimport12242.d
+++ b/gcc/testsuite/gdc.test/compilable/testimport12242.d
@@ -1,5 +1,5 @@
// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/imp12242a.d imports/imp12242a1.d imports/imp12242a2.d imports/imp12242b.d imports/imp12242b1.d imports/imp12242b2.d
module testimport12242;
import imports.imp12242a; // test // stripA == OverloadSet
diff --git a/gcc/testsuite/gdc.test/compilable/testlambdacomp.d b/gcc/testsuite/gdc.test/compilable/testlambdacomp.d
new file mode 100644
index 0000000..e2efdb0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/testlambdacomp.d
@@ -0,0 +1,216 @@
+// EXTRA_FILES: imports/testlambda1.d imports/testlambda2.d
+module testlambdacomp;
+
+void test1()
+{
+ static assert(__traits(isSame, (a, b) => a + b, (c, d) => c + d));
+ static assert(__traits(isSame, a => ++a, b => ++b));
+ static assert(!__traits(isSame, (int a, int b) => a + b, (a, b) => a + b));
+ static assert(__traits(isSame, (a, b) => a + b + 10, (c, d) => c + d + 10));
+}
+
+class Y
+{
+ static int r = 5;
+ int x;
+ this(int x)
+ {
+ this.x = x;
+ }
+}
+
+class A
+{
+ Y a;
+ this(Y a)
+ {
+ this.a = a;
+ }
+}
+
+void foo3(alias pred)()
+{
+ static assert(!__traits(isSame, pred, (A x, A y) => ++x.a.x + (--y.a.x)));
+}
+
+void test2()
+{
+
+ int b;
+ static assert(!__traits(isSame, a => a + b, a => a + b));
+
+ int f() { return 3;}
+ static assert(__traits(isSame, a => a + f(), a => a + f()));
+
+ class A
+ {
+ Y a;
+ this(Y a)
+ {
+ this.a = a;
+ }
+ }
+
+ class B
+ {
+ int a;
+ this(int a)
+ {
+ this.a = a;
+ }
+ }
+
+ B q = new B(7);
+ alias pred = (A a, A b) => ++a.a.x + (--b.a.x);
+ foo3!pred();
+ static assert(!__traits(isSame, (A a) => ++a.a.x + 2, (A b) => ++b.a.x + 3));
+ static assert(__traits(isSame, pred, (A x, A y) => ++x.a.x + (--y.a.x)));
+ static assert(!__traits(isSame, (B a) => ++a.a + 2, (B b) => ++b.a + 3));
+ static assert(__traits(isSame, (B a) => ++a.a, (B a) => ++a.a));
+
+ B cl = new B(7);
+ static assert(!__traits(isSame, a => a + q.a, c => c + cl.a));
+
+ class C(G)
+ {
+ G a;
+ this(int a)
+ {
+ this.a = a;
+ }
+ }
+ static assert(!__traits(isSame, (C!int a) => ++a.a, (C!int a) => ++a.a));
+
+ struct X
+ {
+ int a;
+ }
+ static assert(__traits(isSame, (X a) => a.a + 2, (X b) => b.a + 2));
+
+ struct T(G)
+ {
+ G a;
+ }
+ static assert(!__traits(isSame, (T!int a) => ++a.a, (T!int a) => ++a.a));
+
+}
+
+void test3()
+{
+ enum q = 10;
+ static assert(__traits(isSame, (a, b) => a + b + q, (c, d) => c + d + 10));
+
+ struct Bar
+ {
+ int a;
+ }
+ enum r1 = Bar(1);
+ enum r2 = Bar(1);
+ static assert(__traits(isSame, a => a + r1.a, b => b + r2.a));
+
+ enum X { A, B, C}
+ static assert(__traits(isSame, a => a + X.A, a => a + 0));
+}
+
+void foo(alias pred)()
+{
+ static assert(__traits(isSame, pred, (c, d) => c + d));
+ static assert(__traits(isSame, (c, d) => c + d, pred));
+}
+
+void bar(alias pred)()
+{
+ static assert(__traits(isSame, pred, (c, d) => c < d + 7));
+
+ enum q = 7;
+ static assert(__traits(isSame, pred, (c, d) => c < d + q));
+
+ int r = 7;
+ static assert(!__traits(isSame, pred, (c, d) => c < d + r));
+}
+void test4()
+{
+ foo!((a, b) => a + b)();
+ bar!((a, b) => a < b + 7);
+}
+
+int bar()
+{
+ return 2;
+}
+
+void testImportedFunctions(alias pred)()
+{
+ // imports.testalambda1.bar != imports.testlambda2.bar
+ import imports.testlambda2 : bar;
+ static assert(!__traits(isSame, pred, (int a) => a + bar()));
+}
+
+void testLocalGlobalFunctionScopes(alias pred)()
+{
+ // testlambdacomp.bar != testlambdacomp.test5.bar
+ static assert(!__traits(isSame, pred, (int a) => a + bar()));
+
+ // imports.testlambda1.bar != testlambdacomp.test5.bar
+ import imports.testlambda1 : bar;
+ static assert(!__traits(isSame, pred, (int a) => a + bar()));
+
+ // functions imported from different modules are not equal
+ testImportedFunctions!((int a) => a + bar())();
+}
+
+// lambda functions which contain function calls
+void test5()
+{
+
+ int bar()
+ {
+ return 3;
+ }
+
+ // functions in the same scope
+ alias pred = a => a + bar();
+ alias pred2 = b => b + bar();
+ static assert(__traits(isSame, pred, pred2));
+
+ // functions in different scopes
+ testLocalGlobalFunctionScopes!((int a) => a + bar())();
+
+ int foo(int a, int b)
+ {
+ return 2 + a + b;
+ }
+
+ // functions with different kind of parameters
+ alias preda23 = a => a + foo(2, 3);
+ alias predb23 = b => b + foo(2, 3);
+ alias predc24 = c => c + foo(2, 4);
+ alias predd23 = (int d) => d + foo(2, 3);
+ alias prede23 = (int e) => e + foo(2, 3);
+ alias predf24 = (int f) => f + foo(2, 4);
+ static assert(__traits(isSame, preda23, predb23));
+ static assert(!__traits(isSame, predc24, predd23));
+ static assert(__traits(isSame, predd23, prede23));
+ static assert(!__traits(isSame, prede23, predf24));
+
+ // functions with function calls as parameters
+ static assert(!__traits(isSame, (int a, int b) => foo(foo(1, a), foo(1, b)), (int a, int b) => foo(foo(1, a), foo(2, b))));
+ static assert(!__traits(isSame, (a, b) => foo(foo(1, a), foo(1, b)), (int a, int b) => foo(foo(1, a), foo(2, b))));
+
+ float floatFunc(float a, float b)
+ {
+ return a + b;
+ }
+
+ static assert(__traits(isSame, a => floatFunc(a, 1.0), b => floatFunc(b, 1.0)));
+ static assert(!__traits(isSame, a => floatFunc(a, 1.0), b => floatFunc(b, 2.0)));
+}
+
+void main()
+{
+ test1();
+ test2();
+ test3();
+ test4();
+ test5();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/testparse.d b/gcc/testsuite/gdc.test/compilable/testparse.d
index f514146..99378a9 100644
--- a/gcc/testsuite/gdc.test/compilable/testparse.d
+++ b/gcc/testsuite/gdc.test/compilable/testparse.d
@@ -2,12 +2,12 @@
// REQUIRED_ARGS: -o-
/***************************************************/
-// 6719
+// https://issues.dlang.org/show_bug.cgi?id=6719
static assert(__traits(compiles, mixin("(const(A))[0..0]")) == false);
/***************************************************/
-// 9232
+// https://issues.dlang.org/show_bug.cgi?id=9232
struct Foo9232
{
@@ -25,7 +25,7 @@ void test9232()
}
/***************************************************/
-// 9401
+// https://issues.dlang.org/show_bug.cgi?id=9401
struct S9401a
{
@@ -44,7 +44,7 @@ void test9401() nothrow pure @safe
}
/***************************************************/
-// 9649
+// https://issues.dlang.org/show_bug.cgi?id=9649
class Outer9649
{
@@ -60,7 +60,7 @@ void test9649()
}
/***************************************************/
-// 9679
+// https://issues.dlang.org/show_bug.cgi?id=9679
void test9679(inout int = 0)
{
@@ -90,7 +90,7 @@ void test9679(inout int = 0)
}
/***************************************************/
-// 9901
+// https://issues.dlang.org/show_bug.cgi?id=9901
template isGood9901(T)
{
@@ -106,7 +106,7 @@ void test9901()
}
/***************************************************/
-// 10199
+// https://issues.dlang.org/show_bug.cgi?id=10199
void test10199()
{
@@ -115,7 +115,7 @@ label:
}
/***************************************************/
-// 12460
+// https://issues.dlang.org/show_bug.cgi?id=12460
void f12460(T)()
{
@@ -132,7 +132,7 @@ void test12460()
}
/***************************************************/
-// 11689
+// https://issues.dlang.org/show_bug.cgi?id=11689
void test11689()
{
@@ -140,12 +140,12 @@ void test11689()
}
/***************************************************/
-// 11751
+// https://issues.dlang.org/show_bug.cgi?id=11751
static assert(is(float == typeof(0x0.1p1F)));
/***************************************************/
-// 11957
+// https://issues.dlang.org/show_bug.cgi?id=11957
extern(C++) class C11957
{
@@ -161,8 +161,33 @@ void test11957()
}
/***************************************************/
-// 13049
+// https://issues.dlang.org/show_bug.cgi?id=13049
enum mangle13049(T) = T.mangleof;
alias FP13049 = void function(scope int); // OK
static assert(mangle13049!FP13049 == mangle13049!(void function(scope int))); // OK <- NG
+
+/***************************************************/
+// was not covered until the **12th of March 2019**
+void testIfConditionWithSTCandType()
+{
+ auto call(){return 0;}
+ if (const size_t i = call()) {}
+}
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=20791
+extern(C++, "foo", )
+struct S {}
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=22019
+void test22019()
+{
+ final switch (1)
+ {
+ case 1,:
+ case 2,3,:
+ break;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/testsctreturn.d b/gcc/testsuite/gdc.test/compilable/testsctreturn.d
new file mode 100644
index 0000000..96b82da
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/testsctreturn.d
@@ -0,0 +1,19 @@
+/* REQUIRED_ARGS: -preview=dip1000
+ * This case winds up calling buildScopeRef() with stc having only STC.return_ set.
+ */
+
+struct PackedPtrImpl(size_t bits)
+{
+pure nothrow:
+ this(inout(size_t)* ptr) inout @safe @nogc
+ {
+ origin = ptr;
+ }
+ size_t* origin;
+}
+
+void test()
+{
+ size_t* p;
+ const ppi = const(PackedPtrImpl!(3))(p);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/testtempl2.d b/gcc/testsuite/gdc.test/compilable/testtempl2.d
new file mode 100644
index 0000000..57832d9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/testtempl2.d
@@ -0,0 +1,24 @@
+class C
+{
+ int m;
+ auto fun()
+ {
+ inc!m();
+ new N!m;
+ }
+}
+
+auto inc(alias m)()
+{
+ ++m;
+}
+
+class N(alias m)
+{
+}
+
+void main()
+{
+ auto c = new C;
+ c.new N!(c.m);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/traits.d b/gcc/testsuite/gdc.test/compilable/traits.d
index 4d8a5e1..3c65dac 100644
--- a/gcc/testsuite/gdc.test/compilable/traits.d
+++ b/gcc/testsuite/gdc.test/compilable/traits.d
@@ -1,4 +1,4 @@
-// REQUIRED_ARGS:
+// REQUIRED_ARGS: -extern-std=c++98
// EXTRA_FILES: imports/plainpackage/plainmodule.d imports/pkgmodule/package.d imports/pkgmodule/plainmodule.d
// This file is intended to contain all compilable traits-related tests in an
@@ -19,9 +19,22 @@ class C19152
static assert(is(typeof(__traits(getTargetInfo, "cppRuntimeLibrary")) == string));
version (CppRuntime_Microsoft)
{
- static assert(__traits(getTargetInfo, "cppRuntimeLibrary") == "libcmt");
+ static assert(__traits(getTargetInfo, "cppRuntimeLibrary") == "libcmt" ||
+ __traits(getTargetInfo, "cppRuntimeLibrary")[0..6] == "msvcrt"); // includes mingw import libs
}
+version (D_HardFloat)
+ static assert(__traits(getTargetInfo, "floatAbi") == "hard");
+
+version (Win64)
+ static assert(__traits(getTargetInfo, "objectFormat") == "coff");
+version (OSX)
+ static assert(__traits(getTargetInfo, "objectFormat") == "macho");
+version (linux)
+ static assert(__traits(getTargetInfo, "objectFormat") == "elf");
+
+static assert(__traits(getTargetInfo, "cppStd") == 199711);
+
import imports.plainpackage.plainmodule;
import imports.pkgmodule.plainmodule;
@@ -103,6 +116,7 @@ void foo(T)()
{
this (ref S rhs) {}
}
+ static assert (__traits(hasCopyConstructor, S!int));
}
struct U(T)
@@ -123,18 +137,182 @@ struct DisabledPostblit
struct NoCpCtor { }
class C19902 { }
+static assert(__traits(hasCopyConstructor, S));
+static assert(__traits(hasCopyConstructor, OuterS.S));
+static assert(__traits(hasCopyConstructor, OuterS));
static assert(__traits(compiles, foo!int));
static assert(__traits(compiles, foo!S));
+static assert(__traits(hasCopyConstructor, U!int));
+static assert(__traits(hasCopyConstructor, U!S));
static assert(!__traits(hasPostblit, U!S));
static assert(__traits(hasPostblit, SPostblit));
+static assert(!__traits(hasCopyConstructor, SPostblit));
+static assert(!__traits(hasCopyConstructor, NoCpCtor));
+static assert(!__traits(hasCopyConstructor, C19902));
+static assert(!__traits(hasCopyConstructor, int));
static assert(!__traits(hasPostblit, NoCpCtor));
static assert(!__traits(hasPostblit, C19902));
static assert(!__traits(hasPostblit, int));
-// Check that invalid use cases don't compile
-static assert(!__traits(compiles, __traits(hasPostblit)));
-static assert(!__traits(compiles, __traits(hasPostblit, S())));
-
static assert(__traits(isCopyable, int));
static assert(!__traits(isCopyable, DisabledPostblit));
+struct S1 {} // Fine. Can be copied
+struct S2 { this(this) {} } // Fine. Can be copied
+struct S3 { @disable this(this); } // Not fine. Copying is disabled.
+struct S4 { S3 s; } // Not fine. A field has copying disabled.
+class C1 {}
+static assert( __traits(isCopyable, S1));
+static assert( __traits(isCopyable, S2));
+static assert(!__traits(isCopyable, S3));
+static assert(!__traits(isCopyable, S4));
+static assert(__traits(isCopyable, C1));
+static assert(__traits(isCopyable, int));
+static assert(__traits(isCopyable, int[]));
+
+enum E1 : S1 { a = S1(), }
+enum E2 : S2 { a = S2(), }
+enum E3 : S3 { a = S3(), }
+enum E4 : S4 { a = S4(), }
+
+static assert(__traits(isCopyable, E1));
+static assert(__traits(isCopyable, E2));
+static assert(!__traits(isCopyable, E3));
+static assert(!__traits(isCopyable, E4));
+
+struct S5
+{
+ @disable this(ref S5);
+}
+static assert(!__traits(isCopyable, S5));
+
+/******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=20884
+
+struct S20884
+{
+ int x;
+}
+
+alias T20884 = immutable(S20884);
+enum m20884 = "x";
+
+static assert(is(typeof(__traits(getMember, T20884, m20884)) == immutable(int))); // OK now
+static assert(is( typeof(mixin("T20884." ~ m20884)) == immutable(int)));
+static assert(is( typeof(T20884.x) == immutable(int)));
+
+/******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=20761
+
+alias Seq(T...) = T;
+
+static assert(__traits(isSame, Seq!(1, 2), Seq!(1, 2)));
+static assert(!__traits(isSame, Seq!(1, 1), Seq!(2, 2)));
+static assert(!__traits(isSame, Seq!(1, 1, 2), Seq!(1, 1)));
+static assert(!__traits(isSame, Seq!(1, 1), Seq!(1, 1, 2)));
+
+static assert(__traits(isSame,
+ Seq!(string, wstring),
+ Seq!(immutable(char)[], immutable(wchar)[]))
+);
+
+static assert(__traits(isSame,
+ Seq!(i => i.value, (a, b) => a + b),
+ Seq!(a => a.value, (x, y) => x + y)
+));
+
+static assert(__traits(isSame,
+ Seq!(float, Seq!(double, Seq!real)),
+ Seq!(Seq!(Seq!float, double), real)
+));
+
+static assert(!__traits(isSame,
+ Seq!(int, Seq!(a => a + a)),
+ Seq!(int, Seq!(a => a * a))
+));
+
+// Do these out of order to ensure there are no forward refencing bugs
+
+extern(C++, __traits(getCppNamespaces,GetNamespaceTest1)) struct GetNamespaceTest4 {}
+static assert (__traits(getCppNamespaces,GetNamespaceTest1) ==
+ __traits(getCppNamespaces,GetNamespaceTest4));
+
+extern(C++, "ns") struct GetNamespaceTest1 {}
+extern(C++, "multiple", "namespaces") struct GetNamespaceTest2 {}
+extern(C++, mixin("Seq!(`ns`, `nt`)")) struct GetNamespaceTest3 {}
+static assert(__traits(getCppNamespaces,GetNamespaceTest1)[0] == "ns");
+static assert(__traits(getCppNamespaces,GetNamespaceTest2) == Seq!("multiple","namespaces"));
+static assert(__traits(getCppNamespaces,GetNamespaceTest3) == Seq!("ns", "nt"));
+
+extern(C++, __traits(getCppNamespaces,GetNamespaceTest5)) struct GetNamespaceTest8 {}
+static assert (__traits(getCppNamespaces,GetNamespaceTest5) ==
+ __traits(getCppNamespaces,GetNamespaceTest8));
+
+extern(C++, ns) struct GetNamespaceTest5 {}
+extern(C++, multiple) extern(C++, namespaces) struct GetNamespaceTest6 {}
+static assert(__traits(getCppNamespaces,GetNamespaceTest5)[0] == "ns");
+static assert(__traits(getCppNamespaces,GetNamespaceTest6) == Seq!("multiple","namespaces"));
+
+extern(C++, NS)
+{
+ struct GetNamespaceTest9 {}
+ extern(C++, nested)
+ {
+ struct GetNamespaceTest10 {}
+ extern(C++,"nested2")
+ struct GetNamespaceTest11 {}
+ }
+ extern (C++, "nested3")
+ {
+ extern(C++, nested4)
+ struct GetNamespaceTest12 {}
+ }
+}
+static assert (__traits(getCppNamespaces,NS.GetNamespaceTest9)[0] == "NS");
+static assert (__traits(getCppNamespaces,NS.GetNamespaceTest10) == Seq!("NS", "nested"));
+static assert (__traits(getCppNamespaces,NS.GetNamespaceTest11) == Seq!("NS", "nested", "nested2"));
+static assert (__traits(getCppNamespaces,NS.GetNamespaceTest12) == Seq!("NS", "nested4", "nested3"));
+
+extern(C++, `ns`) struct GetNamespaceTestTemplated(T) {}
+extern(C++, `ns`)
+template GetNamespaceTestTemplated2(T)
+{
+ struct GetNamespaceTestTemplated2 {}
+}
+
+template GetNamespaceTestTemplated3(T)
+{
+ extern(C++, `ns`)
+ struct GetNamespaceTestTemplated3 {}
+}
+
+static assert (__traits(getCppNamespaces,GetNamespaceTestTemplated!int) == Seq!("ns"));
+static assert (__traits(getCppNamespaces,GetNamespaceTestTemplated2!int) == Seq!("ns"));
+static assert (__traits(getCppNamespaces,GetNamespaceTestTemplated3!int) == Seq!("ns"));
+extern(C++, `ns2`)
+template GetNamespaceTestTemplated4(T)
+{
+ extern(C++, `ns`)
+ struct GetNamespaceTestTemplated4
+ {
+ struct GetNamespaceTestTemplated5 {}
+ struct GetNamespaceTestTemplated6(T) {}
+ }
+}
+
+static assert (__traits(getCppNamespaces,GetNamespaceTestTemplated4!int) == Seq!("ns2","ns"));
+static assert (__traits(getCppNamespaces,GetNamespaceTestTemplated4!int.GetNamespaceTestTemplated5) == Seq!("ns2","ns"));
+static assert (__traits(getCppNamespaces,GetNamespaceTestTemplated4!int.GetNamespaceTestTemplated6!int) == Seq!("ns2","ns"));
+
+// Currently ignored due to https://issues.dlang.org/show_bug.cgi?id=21373
+extern(C++, `decl`)
+mixin template GetNamespaceTestTemplatedMixin()
+{
+ extern(C++, `f`)
+ void foo() {}
+}
+
+extern(C++, `inst`)
+mixin GetNamespaceTestTemplatedMixin!() GNTT;
+
+static assert (__traits(getCppNamespaces, GNTT.foo) == Seq!(`inst`,/*`decl`,*/ `f`));
diff --git a/gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d b/gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d
new file mode 100644
index 0000000..1f25b26
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d
@@ -0,0 +1,120 @@
+
+module traits_getFunctionAttributes;
+
+void test_getFunctionAttributes()
+{
+ alias tuple(T...) = T;
+
+ struct S
+ {
+ int noF() { return 0; }
+ int constF() const { return 0; }
+ int immutableF() immutable { return 0; }
+ int inoutF() inout { return 0; }
+ int sharedF() shared { return 0; }
+
+ int x;
+ ref int refF() return { return x; }
+ int propertyF() @property { return 0; }
+ int nothrowF() nothrow { return 0; }
+ int nogcF() @nogc { return 0; }
+
+ int systemF() @system { return 0; }
+ int trustedF() @trusted { return 0; }
+ int safeF() @safe { return 0; }
+
+ int pureF() pure { return 0; }
+
+ int liveF() @live { return 0; }
+ }
+
+ static assert(__traits(getFunctionAttributes, S.noF) == tuple!("@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S.noF)) == tuple!("@system"));
+
+ static assert(__traits(getFunctionAttributes, S.constF) == tuple!("const", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S.constF)) == tuple!("const", "@system"));
+
+ static assert(__traits(getFunctionAttributes, S.immutableF) == tuple!("immutable", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S.immutableF)) == tuple!("immutable", "@system"));
+
+ static assert(__traits(getFunctionAttributes, S.inoutF) == tuple!("inout", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S.inoutF)) == tuple!("inout", "@system"));
+
+ static assert(__traits(getFunctionAttributes, S.sharedF) == tuple!("shared", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S.sharedF)) == tuple!("shared", "@system"));
+
+ static assert(__traits(getFunctionAttributes, S.refF) == tuple!("ref", "return", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S.refF)) == tuple!("ref", "return", "@system"));
+
+ static assert(__traits(getFunctionAttributes, S.propertyF) == tuple!("@property", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(&S.propertyF)) == tuple!("@property", "@system"));
+
+ static assert(__traits(getFunctionAttributes, S.nothrowF) == tuple!("nothrow", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S.nothrowF)) == tuple!("nothrow", "@system"));
+
+ static assert(__traits(getFunctionAttributes, S.nogcF) == tuple!("@nogc", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S.nogcF)) == tuple!("@nogc", "@system"));
+
+ static assert(__traits(getFunctionAttributes, S.systemF) == tuple!("@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S.systemF)) == tuple!("@system"));
+
+ static assert(__traits(getFunctionAttributes, S.trustedF) == tuple!("@trusted"));
+ static assert(__traits(getFunctionAttributes, typeof(S.trustedF)) == tuple!("@trusted"));
+
+ static assert(__traits(getFunctionAttributes, S.safeF) == tuple!("@safe"));
+ static assert(__traits(getFunctionAttributes, typeof(S.safeF)) == tuple!("@safe"));
+
+ static assert(__traits(getFunctionAttributes, S.pureF) == tuple!("pure", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S.pureF)) == tuple!("pure", "@system"));
+
+ static assert(__traits(getFunctionAttributes, S.liveF) == tuple!("@live", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S.liveF)) == tuple!("@live", "@system"));
+
+ int pure_nothrow() nothrow pure { return 0; }
+ static ref int static_ref_property() @property { return *(new int); }
+ ref int ref_property() @property { return *(new int); }
+ void safe_nothrow() @safe nothrow { }
+ void live_nothrow() nothrow @live { }
+
+ static assert(__traits(getFunctionAttributes, pure_nothrow) == tuple!("pure", "nothrow", "@nogc", "@safe"));
+ static assert(__traits(getFunctionAttributes, typeof(pure_nothrow)) == tuple!("pure", "nothrow", "@nogc", "@safe"));
+
+ static assert(__traits(getFunctionAttributes, static_ref_property) == tuple!("pure", "nothrow", "@property", "ref", "@safe"));
+ static assert(__traits(getFunctionAttributes, typeof(&static_ref_property)) == tuple!("pure", "nothrow", "@property", "ref", "@safe"));
+
+ static assert(__traits(getFunctionAttributes, ref_property) == tuple!("pure", "nothrow", "@property", "ref", "@safe"));
+ static assert(__traits(getFunctionAttributes, typeof(&ref_property)) == tuple!("pure", "nothrow", "@property", "ref", "@safe"));
+
+ static assert(__traits(getFunctionAttributes, safe_nothrow) == tuple!("pure", "nothrow", "@nogc", "@safe"));
+ static assert(__traits(getFunctionAttributes, typeof(safe_nothrow)) == tuple!("pure", "nothrow", "@nogc", "@safe"));
+
+ static assert(__traits(getFunctionAttributes, live_nothrow) == tuple!("pure", "nothrow", "@nogc", "@live", "@safe"));
+ static assert(__traits(getFunctionAttributes, typeof(live_nothrow)) == tuple!("pure", "nothrow", "@nogc", "@live", "@safe"));
+
+ struct S2
+ {
+ int pure_const() const pure { return 0; }
+ int pure_sharedconst() const shared pure { return 0; }
+ }
+
+ static assert(__traits(getFunctionAttributes, S2.pure_const) == tuple!("const", "pure", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S2.pure_const)) == tuple!("const", "pure", "@system"));
+
+ static assert(__traits(getFunctionAttributes, S2.pure_sharedconst) == tuple!("const", "shared", "pure", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(S2.pure_sharedconst)) == tuple!("const", "shared", "pure", "@system"));
+
+ static assert(__traits(getFunctionAttributes, (int a) { }) == tuple!("pure", "nothrow", "@nogc", "@safe"));
+ static assert(__traits(getFunctionAttributes, typeof((int a) { })) == tuple!("pure", "nothrow", "@nogc", "@safe"));
+
+ auto safeDel = delegate() @safe { };
+ static assert(__traits(getFunctionAttributes, safeDel) == tuple!("pure", "nothrow", "@nogc", "@safe"));
+ static assert(__traits(getFunctionAttributes, typeof(safeDel)) == tuple!("pure", "nothrow", "@nogc", "@safe"));
+
+ auto trustedDel = delegate() @trusted { };
+ static assert(__traits(getFunctionAttributes, trustedDel) == tuple!("pure", "nothrow", "@nogc", "@trusted"));
+ static assert(__traits(getFunctionAttributes, typeof(trustedDel)) == tuple!("pure", "nothrow", "@nogc", "@trusted"));
+
+ auto systemDel = delegate() @system { };
+ static assert(__traits(getFunctionAttributes, systemDel) == tuple!("pure", "nothrow", "@nogc", "@system"));
+ static assert(__traits(getFunctionAttributes, typeof(systemDel)) == tuple!("pure", "nothrow", "@nogc", "@system"));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/typeid_name.d b/gcc/testsuite/gdc.test/compilable/typeid_name.d
new file mode 100644
index 0000000..e77d5c8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/typeid_name.d
@@ -0,0 +1,14 @@
+
+
+string classname(Object o)
+{
+ return typeid(o).name;
+}
+
+class Panzer {}
+class Tiger : Panzer {}
+
+static assert (() {
+ Panzer p = new Tiger(); return classname(p);
+} () == "Tiger");
+
diff --git a/gcc/testsuite/gdc.test/compilable/uda.d b/gcc/testsuite/gdc.test/compilable/uda.d
index cb9413b..ac66c2f 100644
--- a/gcc/testsuite/gdc.test/compilable/uda.d
+++ b/gcc/testsuite/gdc.test/compilable/uda.d
@@ -1,5 +1,6 @@
/************************************************/
-// 15180: [REG2.069.0-b1] Segfault with empty struct used as UDA
+// https://issues.dlang.org/show_bug.cgi?id=15180
+// [REG2.069.0-b1] Segfault with empty struct used as UDA
struct foo { }
@foo bar () { }
diff --git a/gcc/testsuite/gdc.test/compilable/udamodule1.d b/gcc/testsuite/gdc.test/compilable/udamodule1.d
index 4631642..434cf51 100644
--- a/gcc/testsuite/gdc.test/compilable/udamodule1.d
+++ b/gcc/testsuite/gdc.test/compilable/udamodule1.d
@@ -1,9 +1,10 @@
// REQUIRED_ARGS:
// PERMUTE_ARGS:
+// EXTRA_FILES: imports/udamodule1.d
/*
TEST_OUTPUT:
---
-compilable/udamodule1.d(9): Deprecation: module imports.udamodule1 is deprecated - This module will be removed.
+compilable/udamodule1.d(10): Deprecation: module `imports.udamodule1` is deprecated - This module will be removed.
---
*/
import imports.udamodule1;
diff --git a/gcc/testsuite/gdc.test/compilable/udamodule2.d b/gcc/testsuite/gdc.test/compilable/udamodule2.d
index f2c0794..5002ae0 100644
--- a/gcc/testsuite/gdc.test/compilable/udamodule2.d
+++ b/gcc/testsuite/gdc.test/compilable/udamodule2.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/udamodule2.d imports/udamodule2a.d
import imports.udamodule2;
import imports.udamodule2a;
diff --git a/gcc/testsuite/gdc.test/compilable/union_initialization.d b/gcc/testsuite/gdc.test/compilable/union_initialization.d
new file mode 100644
index 0000000..96c2bf4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/union_initialization.d
@@ -0,0 +1,43 @@
+// https://issues.dlang.org/show_bug.cgi?id=20068
+
+union B
+{
+ int i;
+ int* p;
+ @safe this(int* p)
+ {
+ // Error: cannot access pointers in @safe code that overlap other fields
+ this.p = p;
+ }
+}
+
+/**************************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=21229
+
+struct NeedsInit
+{
+ int var;
+ @disable this();
+}
+
+union Union
+{
+ NeedsInit ni;
+}
+
+union Proxy
+{
+ Union union_;
+}
+
+struct S
+{
+ Union union_;
+ Proxy proxy;
+
+ this(NeedsInit arg)
+ {
+ union_.ni = arg;
+ proxy.union_.ni = arg;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/vcg-ast.d b/gcc/testsuite/gdc.test/compilable/vcg-ast.d
index 7cc376f..61767cc 100644
--- a/gcc/testsuite/gdc.test/compilable/vcg-ast.d
+++ b/gcc/testsuite/gdc.test/compilable/vcg-ast.d
@@ -1,6 +1,11 @@
+/*
+REQUIRED_ARGS: -vcg-ast -o-
+PERMUTE_ARGS:
+OUTPUT_FILES: compilable/vcg-ast.d.cg
+TEST_OUTPUT_FILE: extra-files/vcg-ast.d.cg
+*/
+
module vcg;
-// REQUIRED_ARGS: -vcg-ast -o-
-// PERMUTE_ARGS:
template Seq(A...)
{
@@ -41,3 +46,19 @@ class C
return 2;
}
}
+
+enum __c_wchar_t : dchar;
+alias wchar_t = __c_wchar_t;
+
+T[] values(T)()
+{
+ T[] values;
+ values ~= T();
+ return values;
+}
+
+void main()
+{
+ values!wchar_t;
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/version.d b/gcc/testsuite/gdc.test/compilable/version.d
new file mode 100644
index 0000000..00c5c80
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/version.d
@@ -0,0 +1,23 @@
+/* REQUIRED_ARGS:
+*/
+
+version (D_ModuleInfo)
+{ }
+else
+{
+ static assert(0);
+}
+
+version (D_Exceptions)
+{ }
+else
+{
+ static assert(0);
+}
+
+version (D_TypeInfo)
+{ }
+else
+{
+ static assert(0);
+} \ No newline at end of file
diff --git a/gcc/testsuite/gdc.test/compilable/vgc1.d b/gcc/testsuite/gdc.test/compilable/vgc1.d
index 87b35a4..8a11657 100644
--- a/gcc/testsuite/gdc.test/compilable/vgc1.d
+++ b/gcc/testsuite/gdc.test/compilable/vgc1.d
@@ -6,19 +6,17 @@
struct S1 { }
struct S2 { this(int); }
struct S3 { this(int) @nogc; }
-struct S4 { new(size_t); }
-struct S5 { @nogc new(size_t); }
/*
TEST_OUTPUT:
---
-compilable/vgc1.d(27): vgc: 'new' causes GC allocation
-compilable/vgc1.d(29): vgc: 'new' causes GC allocation
-compilable/vgc1.d(30): vgc: 'new' causes GC allocation
-compilable/vgc1.d(32): vgc: 'new' causes GC allocation
-compilable/vgc1.d(33): vgc: 'new' causes GC allocation
-compilable/vgc1.d(34): vgc: 'new' causes GC allocation
-compilable/vgc1.d(38): vgc: 'new' causes GC allocation
+compilable/vgc1.d(25): vgc: `new` causes a GC allocation
+compilable/vgc1.d(27): vgc: `new` causes a GC allocation
+compilable/vgc1.d(28): vgc: `new` causes a GC allocation
+compilable/vgc1.d(30): vgc: `new` causes a GC allocation
+compilable/vgc1.d(31): vgc: `new` causes a GC allocation
+compilable/vgc1.d(32): vgc: `new` causes a GC allocation
+compilable/vgc1.d(34): vgc: `new` causes a GC allocation
---
*/
@@ -32,8 +30,6 @@ void testNew()
S1* ps1 = new S1();
S2* ps2 = new S2(1);
S3* ps3 = new S3(1);
- S4* ps4 = new S4; // no error
- S5* ps5 = new S5; // no error
Object o1 = new Object();
}
@@ -41,12 +37,12 @@ void testNew()
/*
TEST_OUTPUT:
---
-compilable/vgc1.d(55): vgc: 'new' causes GC allocation
-compilable/vgc1.d(57): vgc: 'new' causes GC allocation
-compilable/vgc1.d(58): vgc: 'new' causes GC allocation
-compilable/vgc1.d(60): vgc: 'new' causes GC allocation
-compilable/vgc1.d(61): vgc: 'new' causes GC allocation
-compilable/vgc1.d(62): vgc: 'new' causes GC allocation
+compilable/vgc1.d(51): vgc: `new` causes a GC allocation
+compilable/vgc1.d(53): vgc: `new` causes a GC allocation
+compilable/vgc1.d(54): vgc: `new` causes a GC allocation
+compilable/vgc1.d(56): vgc: `new` causes a GC allocation
+compilable/vgc1.d(57): vgc: `new` causes a GC allocation
+compilable/vgc1.d(58): vgc: `new` causes a GC allocation
---
*/
@@ -60,8 +56,6 @@ void testNewScope()
scope S1* ps1 = new S1();
scope S2* ps2 = new S2(1);
scope S3* ps3 = new S3(1);
- scope S4* ps4 = new S4; // no error
- scope S5* ps5 = new S5; // no error
scope Object o1 = new Object(); // no error
scope o2 = new Object(); // no error
@@ -74,9 +68,12 @@ void testNewScope()
/*
TEST_OUTPUT:
---
-compilable/vgc1.d(84): vgc: 'delete' requires GC
-compilable/vgc1.d(85): vgc: 'delete' requires GC
-compilable/vgc1.d(86): vgc: 'delete' requires GC
+compilable/vgc1.d(81): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+compilable/vgc1.d(81): vgc: `delete` requires the GC
+compilable/vgc1.d(82): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+compilable/vgc1.d(82): vgc: `delete` requires the GC
+compilable/vgc1.d(83): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+compilable/vgc1.d(83): vgc: `delete` requires the GC
---
*/
void testDelete(int* p, Object o, S1* s)
diff --git a/gcc/testsuite/gdc.test/compilable/vgc2.d b/gcc/testsuite/gdc.test/compilable/vgc2.d
index b1a7f18..c895914 100644
--- a/gcc/testsuite/gdc.test/compilable/vgc2.d
+++ b/gcc/testsuite/gdc.test/compilable/vgc2.d
@@ -6,14 +6,14 @@
/*
TEST_OUTPUT:
---
-compilable/vgc2.d(21): vgc: operator ~ may cause GC allocation
-compilable/vgc2.d(22): vgc: operator ~ may cause GC allocation
-compilable/vgc2.d(23): vgc: operator ~ may cause GC allocation
-compilable/vgc2.d(25): vgc: operator ~ may cause GC allocation
-compilable/vgc2.d(26): vgc: operator ~ may cause GC allocation
-compilable/vgc2.d(27): vgc: operator ~ may cause GC allocation
-compilable/vgc2.d(28): vgc: operator ~ may cause GC allocation
-compilable/vgc2.d(29): vgc: operator ~ may cause GC allocation
+compilable/vgc2.d(21): vgc: operator `~` may cause a GC allocation
+compilable/vgc2.d(22): vgc: operator `~` may cause a GC allocation
+compilable/vgc2.d(23): vgc: operator `~` may cause a GC allocation
+compilable/vgc2.d(25): vgc: operator `~` may cause a GC allocation
+compilable/vgc2.d(26): vgc: operator `~` may cause a GC allocation
+compilable/vgc2.d(27): vgc: operator `~` may cause a GC allocation
+compilable/vgc2.d(28): vgc: operator `~` may cause a GC allocation
+compilable/vgc2.d(29): vgc: operator `~` may cause a GC allocation
---
*/
void testCat(int[] a, string s)
@@ -38,9 +38,9 @@ void testCat(int[] a, string s)
/*
TEST_OUTPUT:
---
-compilable/vgc2.d(48): vgc: operator ~= may cause GC allocation
-compilable/vgc2.d(50): vgc: operator ~= may cause GC allocation
-compilable/vgc2.d(51): vgc: operator ~= may cause GC allocation
+compilable/vgc2.d(48): vgc: operator `~=` may cause a GC allocation
+compilable/vgc2.d(50): vgc: operator `~=` may cause a GC allocation
+compilable/vgc2.d(51): vgc: operator `~=` may cause a GC allocation
---
*/
void testCatAssign(int[] a, string s)
@@ -58,8 +58,8 @@ int* barA();
/*
TEST_OUTPUT:
---
-compilable/vgc2.d(70): vgc: array literal may cause GC allocation
-compilable/vgc2.d(71): vgc: array literal may cause GC allocation
+compilable/vgc2.d(70): vgc: array literal may cause a GC allocation
+compilable/vgc2.d(71): vgc: array literal may cause a GC allocation
---
*/
void testArray()
@@ -76,8 +76,8 @@ void testArray()
/*
TEST_OUTPUT:
---
-compilable/vgc2.d(87): vgc: associative array literal may cause GC allocation
-compilable/vgc2.d(88): vgc: associative array literal may cause GC allocation
+compilable/vgc2.d(87): vgc: associative array literal may cause a GC allocation
+compilable/vgc2.d(88): vgc: associative array literal may cause a GC allocation
---
*/
void testAssocArray()
@@ -93,8 +93,8 @@ void testAssocArray()
/*
TEST_OUTPUT:
---
-compilable/vgc2.d(102): vgc: indexing an associative array may cause GC allocation
-compilable/vgc2.d(103): vgc: indexing an associative array may cause GC allocation
+compilable/vgc2.d(102): vgc: indexing an associative array may cause a GC allocation
+compilable/vgc2.d(103): vgc: indexing an associative array may cause a GC allocation
---
*/
void testIndex(int[int] aa)
diff --git a/gcc/testsuite/gdc.test/compilable/vgc3.d b/gcc/testsuite/gdc.test/compilable/vgc3.d
index 4bf889c..efdc5cd 100644
--- a/gcc/testsuite/gdc.test/compilable/vgc3.d
+++ b/gcc/testsuite/gdc.test/compilable/vgc3.d
@@ -6,9 +6,9 @@
/*
TEST_OUTPUT:
---
-compilable/vgc3.d(16): vgc: setting 'length' may cause GC allocation
-compilable/vgc3.d(17): vgc: setting 'length' may cause GC allocation
-compilable/vgc3.d(18): vgc: setting 'length' may cause GC allocation
+compilable/vgc3.d(16): vgc: setting `length` may cause a GC allocation
+compilable/vgc3.d(17): vgc: setting `length` may cause a GC allocation
+compilable/vgc3.d(18): vgc: setting `length` may cause a GC allocation
---
*/
void testArrayLength(int[] a)
diff --git a/gcc/testsuite/gdc.test/compilable/vtemplates.d b/gcc/testsuite/gdc.test/compilable/vtemplates.d
new file mode 100644
index 0000000..578d6c0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/vtemplates.d
@@ -0,0 +1,28 @@
+/* REQUIRED_ARGS: -vtemplates
+TEST_OUTPUT:
+---
+compilable/vtemplates.d(10): vtemplate: 4 (3 distinct) instantiation(s) of template `foo(int I)()` found
+compilable/vtemplates.d(11): vtemplate: 5 (2 distinct) instantiation(s) of template `goo1(int I)()` found
+compilable/vtemplates.d(12): vtemplate: 3 (2 distinct) instantiation(s) of template `goo2(int I)()` found
+---
+*/
+
+void foo(int I)() { }
+void goo1(int I)() { }
+void goo2(int I)() { goo1!(I); }
+
+void test()
+{
+ foo!(1)();
+ foo!(1)();
+ foo!(2)();
+ foo!(3)();
+
+ goo1!(1)();
+ goo1!(1)();
+ goo1!(2)();
+
+ goo2!(1)();
+ goo2!(2)();
+ goo2!(2)();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/vtemplates_list.d b/gcc/testsuite/gdc.test/compilable/vtemplates_list.d
new file mode 100644
index 0000000..dd02e63
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/vtemplates_list.d
@@ -0,0 +1,46 @@
+/* REQUIRED_ARGS: -vtemplates=list-instances
+TEST_OUTPUT:
+---
+compilable/vtemplates_list.d(19): vtemplate: 4 (3 distinct) instantiation(s) of template `foo(int I)()` found, they are:
+compilable/vtemplates_list.d(25): vtemplate: explicit instance `foo!1`
+compilable/vtemplates_list.d(26): vtemplate: explicit instance `foo!1`
+compilable/vtemplates_list.d(27): vtemplate: explicit instance `foo!2`
+compilable/vtemplates_list.d(28): vtemplate: explicit instance `foo!3`
+compilable/vtemplates_list.d(20): vtemplate: 3 (1 distinct) instantiation(s) of template `goo1(int I)()` found, they are:
+compilable/vtemplates_list.d(30): vtemplate: explicit instance `goo1!1`
+compilable/vtemplates_list.d(31): vtemplate: explicit instance `goo1!1`
+compilable/vtemplates_list.d(21): vtemplate: implicit instance `goo1!1`
+compilable/vtemplates_list.d(21): vtemplate: 2 (1 distinct) instantiation(s) of template `goo2(int I)()` found, they are:
+compilable/vtemplates_list.d(33): vtemplate: explicit instance `goo2!1`
+compilable/vtemplates_list.d(34): vtemplate: explicit instance `goo2!1`
+compilable/vtemplates_list.d(52): vtemplate: 1 (1 distinct) instantiation(s) of template `A()` found, they are:
+compilable/vtemplates_list.d-mixin-53(53): vtemplate: explicit instance `A!()`
+---
+*/
+
+#line 19
+void foo(int I)() { }
+void goo1(int I)() { }
+void goo2(int I)() { goo1!(I); }
+
+void test()
+{
+ foo!(1)();
+ foo!(1)();
+ foo!(2)();
+ foo!(3)();
+
+ goo1!(1)();
+ goo1!(1)();
+
+ goo2!(1)();
+ goo2!(1)();
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=21489
+#line 50
+void test2()
+{
+ template A() {}
+ alias ta = mixin("A!()");
+}
diff --git a/gcc/testsuite/gdc.test/compilable/warn3882.d b/gcc/testsuite/gdc.test/compilable/warn3882.d
index d981a47..f02a87b 100644
--- a/gcc/testsuite/gdc.test/compilable/warn3882.d
+++ b/gcc/testsuite/gdc.test/compilable/warn3882.d
@@ -10,7 +10,7 @@ void test3882()
}
/******************************************/
-// 12619
+// https://issues.dlang.org/show_bug.cgi?id=12619
extern (C) @system nothrow pure void* memcpy(void* s1, in void* s2, size_t n);
// -> weakly pure
@@ -22,7 +22,7 @@ void test12619() pure
}
/******************************************/
-// 12760
+// https://issues.dlang.org/show_bug.cgi?id=12760
struct S12760(T)
{
@@ -41,11 +41,11 @@ struct K12760
}
/******************************************/
-// 12909
+// https://issues.dlang.org/show_bug.cgi?id=12909
int f12909(immutable(int[])[int] aa) pure nothrow
{
- //aa[0] = []; // fix for issue 13701
+ //aa[0] = []; // fix for https://issues.dlang.org/show_bug.cgi?id=13701
return 0;
}
@@ -60,7 +60,7 @@ void test12909()
}
/******************************************/
-// 13899
+// https://issues.dlang.org/show_bug.cgi?id=13899
const struct Foo13899
{
diff --git a/gcc/testsuite/gdc.test/compilable/zerosize.d b/gcc/testsuite/gdc.test/compilable/zerosize.d
new file mode 100644
index 0000000..3c0062e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/zerosize.d
@@ -0,0 +1,12 @@
+
+extern (C) struct S { }
+
+static assert(S.sizeof == 0);
+static assert(S.alignof == 1);
+
+extern (C++) struct T { }
+
+static assert(T.sizeof == 1);
+static assert(T.alignof == 1);
+
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/aacmp10381.d b/gcc/testsuite/gdc.test/fail_compilation/aacmp10381.d
index 397f36d..b088891 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/aacmp10381.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/aacmp10381.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/aacmp10381.d(12): Error: > is not defined for associative arrays
+fail_compilation/aacmp10381.d(12): Error: `>` is not defined for associative arrays
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/aliasassign.d b/gcc/testsuite/gdc.test/fail_compilation/aliasassign.d
new file mode 100644
index 0000000..499bef1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/aliasassign.d
@@ -0,0 +1,21 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/aliasassign.d(13): Error: `B` must have same parent `Swap!(int, string)` as alias `B`
+fail_compilation/aliasassign.d(14): Error: `A` must have same parent `Swap!(int, string)` as alias `A`
+fail_compilation/aliasassign.d(21): Error: template instance `aliasassign.Swap!(int, string)` error instantiating
+fail_compilation/aliasassign.d(21): while evaluating: `static assert(Swap!(int, string))`
+---
+*/
+
+template Swap (alias A, alias B)
+{
+ alias C = A;
+ B = A;
+ A = B;
+ enum Swap = true;
+}
+
+alias A = int;
+alias B = string;
+
+static assert(Swap!(A, B));
diff --git a/gcc/testsuite/gdc.test/fail_compilation/aliasassign1.d b/gcc/testsuite/gdc.test/fail_compilation/aliasassign1.d
new file mode 100644
index 0000000..df3f43a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/aliasassign1.d
@@ -0,0 +1,34 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/aliasassign1.d(106): Error: A was read, so cannot reassign
+fail_compilation/aliasassign1.d(110): Error: template instance `aliasassign1.staticMap!(Unqual, int, const(uint))` error instantiating
+fail_compilation/aliasassign1.d(112): Error: static assert: `is(TK == AliasSeq!(int, uint))` is false
+---
+ */
+
+template AliasSeq(T...) { alias AliasSeq = T; }
+
+template Unqual(T)
+{
+ static if (is(T U == const U))
+ alias Unqual = U;
+ else static if (is(T U == immutable U))
+ alias Unqual = U;
+ else
+ alias Unqual = T;
+}
+
+#line 100
+
+template staticMap(alias F, T...)
+{
+ alias A = AliasSeq!();
+ alias B = A;
+ static foreach (t; T)
+ A = AliasSeq!(A, F!t); // what's tested
+ alias staticMap = A;
+}
+
+alias TK = staticMap!(Unqual, int, const uint);
+//pragma(msg, TK);
+static assert(is(TK == AliasSeq!(int, uint)));
diff --git a/gcc/testsuite/gdc.test/fail_compilation/already_defined.d b/gcc/testsuite/gdc.test/fail_compilation/already_defined.d
new file mode 100644
index 0000000..7a97e09
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/already_defined.d
@@ -0,0 +1,76 @@
+/**
+TEST_OUTPUT:
+---
+fail_compilation/already_defined.d(4): Error: declaration `already_defined.func1.a` is already defined
+fail_compilation/already_defined.d(3): `variable` `a` is defined here
+fail_compilation/already_defined.d(10): Error: declaration `already_defined.func2.core` is already defined
+fail_compilation/already_defined.d(9): `import` `core` is defined here
+fail_compilation/already_defined.d(28): Error: declaration `Ident(T)` is already defined
+fail_compilation/already_defined.d(27): `template` `Ident(T)` is defined here
+fail_compilation/already_defined.d(36): Error: declaration `Tstring` is already defined
+fail_compilation/already_defined.d(35): `alias` `Tstring` is defined here
+fail_compilation/already_defined.d(42): Error: declaration `T` is already defined
+fail_compilation/already_defined.d(41): `alias` `T` is defined here
+fail_compilation/already_defined.d(48): Error: declaration `core` is already defined
+fail_compilation/already_defined.d(47): `import` `core` is defined here
+fail_compilation/already_defined.d(54): Error: declaration `core` is already defined
+fail_compilation/already_defined.d(53): `import` `core` is defined here
+---
+*/
+
+#line 1
+void func1 ()
+{
+ int a;
+ bool a;
+}
+
+void func2 ()
+{
+ import core.stdc.stdio;
+ string core;
+}
+
+void func3 ()
+{
+ {
+ import core.stdc.stdio;
+ }
+
+ {
+ // No conflict
+ string core;
+ }
+}
+
+void func4 ()
+{
+ template Ident (T) { alias Ident = T; }
+ template Ident (T) { alias Ident = T; }
+}
+
+void func5 ()
+{
+ template Ident (T) { alias Ident = T; }
+
+ alias Tstring = Ident!string;
+ alias Tstring = Ident!string;
+}
+
+void func6 ()
+{
+ static if (is(int T == int)) {}
+ static if (is(int T == int)) {}
+}
+
+void func7 ()
+{
+ import core.stdc.stdio;
+ static if (is(int core == int)) {}
+}
+
+void func8 ()
+{
+ import core.stdc.stdio;
+ static if (is(string : core[], core)) {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b15069.d b/gcc/testsuite/gdc.test/fail_compilation/b15069.d
new file mode 100644
index 0000000..4ff4266
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/b15069.d
@@ -0,0 +1,21 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/b15069.d(15): Error: template instance `T!int` `T` is not a template declaration, it is a alias
+fail_compilation/b15069.d(10): Error: template instance `b15069.Stuff!(Thing!float)` error instantiating
+---
+*/
+void main()
+{
+ Stuff!(Thing!(float)) s;
+}
+
+struct Stuff(T)
+{
+ T!(int) var;
+}
+
+struct Thing(T)
+{
+ T varling;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b15909.d b/gcc/testsuite/gdc.test/fail_compilation/b15909.d
new file mode 100644
index 0000000..22c58da
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/b15909.d
@@ -0,0 +1,15 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/b15909.d(12): Error: duplicate `case 'a'` in `switch` statement
+---
+*/
+
+void main()
+{
+ switch ('a')
+ {
+ case 'a':
+ case 'a':
+ break;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b17918.d b/gcc/testsuite/gdc.test/fail_compilation/b17918.d
new file mode 100644
index 0000000..00f2b76
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/b17918.d
@@ -0,0 +1,13 @@
+/*
+EXTRA_FILES: imports/b17918a.d
+TEST_OUTPUT:
+---
+fail_compilation/imports/b17918a.d(7): Error: undefined identifier `_listMap`
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=17918
+import imports.b17918a;
+
+class Derived : Base
+{
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b19523.d b/gcc/testsuite/gdc.test/fail_compilation/b19523.d
new file mode 100644
index 0000000..3626666
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/b19523.d
@@ -0,0 +1,18 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/b19523.d(12): Error: undefined identifier `SomeStruct`
+fail_compilation/b19523.d(13): Error: function `b19523.foo(int delegate() arg)` is not callable using argument types `(_error_)`
+fail_compilation/b19523.d(13): cannot pass argument `__lambda2` of type `_error_` to parameter `int delegate() arg`
+---
+*/
+module b19523;
+
+void bar () {
+ SomeStruct s;
+ foo({
+ return s;
+ });
+}
+
+void foo (int delegate() arg) {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b19685.d b/gcc/testsuite/gdc.test/fail_compilation/b19685.d
new file mode 100644
index 0000000..99addd8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/b19685.d
@@ -0,0 +1,19 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/b19685.d(6): Error: overlapping default initialization for field `b` and `a`
+---
+*/
+struct S
+{
+ union
+ {
+ struct { int a = 123; }
+ struct { int b = 456; }
+ }
+}
+
+void main()
+{
+ S s;
+ assert(s.b == 123);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b19691.d b/gcc/testsuite/gdc.test/fail_compilation/b19691.d
index 8663512..d01c764 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/b19691.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/b19691.d
@@ -1,8 +1,7 @@
// REQUIRED_ARGS: -de
/* TEST_OUTPUT:
---
-fail_compilation/b19691.d(13): Error: forward reference to template `this`
-fail_compilation/b19691.d(19): Deprecation: constructor `b19691.S2.this` all parameters have default arguments, but structs cannot have default constructors.
+fail_compilation/b19691.d(12): Error: forward reference to template `this`
---
*/
// https://issues.dlang.org/show_bug.cgi?id=19691
@@ -10,11 +9,11 @@ module b19691;
struct S1 {
this(T...)(T) {
- S2("");
+ S2(42, "");
}
}
struct S2 {
- this(string) {}
- this(S1 s = null) {}
+ this(int a, string) {}
+ this(int a, S1 s = null) {}
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b19691e.d b/gcc/testsuite/gdc.test/fail_compilation/b19691e.d
index 21d0e90..1b8aa1c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/b19691e.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/b19691e.d
@@ -1,10 +1,9 @@
// REQUIRED_ARGS: -de
/* TEST_OUTPUT:
---
-fail_compilation/b19691e.d(17): Error: forward reference to template `this`
-fail_compilation/b19691e.d(17): Error: constructor `b19691e.S2.this(S1 s = "")` is not callable using argument types `(string)`
-fail_compilation/b19691e.d(17): Error: forward reference to template `this`
-fail_compilation/b19691e.d(23): Deprecation: constructor `b19691e.S2.this` all parameters have default arguments, but structs cannot have default constructors.
+fail_compilation/b19691e.d(16): Error: forward reference to template `this`
+fail_compilation/b19691e.d(16): Error: constructor `b19691e.S2.this(int a, S1 s = "")` is not callable using argument types `(int, string)`
+fail_compilation/b19691e.d(16): Error: forward reference to template `this`
---
*/
// https://issues.dlang.org/show_bug.cgi?id=19691
@@ -14,11 +13,11 @@ struct S1
{
this(T)(T)
{
- S2("");
+ S2(42, "");
}
}
struct S2
{
- this(S1 s = ""){}
+ this(int a, S1 s = ""){}
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b19717a.d b/gcc/testsuite/gdc.test/fail_compilation/b19717a.d
index 79a9de0..d10b3f9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/b19717a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/b19717a.d
@@ -3,9 +3,9 @@
---
fail_compilation/b19717a.d(14): Error: forward reference to template `a`
fail_compilation/b19717a.d(14): Error: forward reference to template `a`
-fail_compilation/b19717a.d(14): Error: none of the overloads of `a` are callable using argument types `()`, candidates are:
-fail_compilation/b19717a.d(13): `b19717a.a(int b)`
-fail_compilation/b19717a.d(14): `b19717a.a(int b = a)`
+fail_compilation/b19717a.d(14): Error: none of the overloads of `a` are callable using argument types `()`
+fail_compilation/b19717a.d(13): Candidates are: `b19717a.a(int b)`
+fail_compilation/b19717a.d(14): `b19717a.a(int b = a)`
---
*/
module b19717a;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b19730.d b/gcc/testsuite/gdc.test/fail_compilation/b19730.d
new file mode 100644
index 0000000..903d629
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/b19730.d
@@ -0,0 +1,12 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/b19730.d(10): Error: found `)` while expecting `=` or identifier
+fail_compilation/b19730.d(11): Error: found `)` while expecting `=` or identifier
+---
+*/
+void func() {
+ bool x;
+ if (const x) {}
+ if (auto x) {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b20011.d b/gcc/testsuite/gdc.test/fail_compilation/b20011.d
new file mode 100644
index 0000000..669dd10
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/b20011.d
@@ -0,0 +1,40 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/b20011.d(25): Error: `S1(cast(ubyte)0u).member` is not an lvalue and cannot be modified
+fail_compilation/b20011.d(28): Error: `S2(null).member` is not an lvalue and cannot be modified
+fail_compilation/b20011.d(29): Error: `S2(null).member` is not an lvalue and cannot be modified
+fail_compilation/b20011.d(32): Error: `U1(cast(ubyte)0u, ).m2` is not an lvalue and cannot be modified
+fail_compilation/b20011.d(37): Error: function `b20011.main.assignableByRef(ref ubyte p)` is not callable using argument types `(ubyte)`
+fail_compilation/b20011.d(37): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref ubyte p`
+fail_compilation/b20011.d(38): Error: function `b20011.main.assignableByOut(out ubyte p)` is not callable using argument types `(ubyte)`
+fail_compilation/b20011.d(38): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `out ubyte p`
+fail_compilation/b20011.d(39): Error: function `b20011.main.assignableByConstRef(ref const(ubyte) p)` is not callable using argument types `(ubyte)`
+fail_compilation/b20011.d(39): cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref const(ubyte) p`
+---
+*/
+module b20011;
+
+struct S1 { ubyte member; }
+struct S2 { ubyte[] member; }
+union U1 { ubyte m1; int m2; }
+
+void main()
+{
+ enum S1 s1 = {};
+ s1.member = 42;
+
+ enum S2 s2 = {};
+ s2.member = [];
+ s2.member ~= [];
+
+ enum U1 u1 = {m1 : 0};
+ u1.m2 = 42;
+
+ void assignableByRef(ref ubyte p){ p = 42; }
+ void assignableByOut(out ubyte p){ p = 42; }
+ void assignableByConstRef(ref const ubyte p){}
+ assignableByRef(s1.member);
+ assignableByOut(s1.member);
+ assignableByConstRef(s1.member);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b20780.d b/gcc/testsuite/gdc.test/fail_compilation/b20780.d
new file mode 100644
index 0000000..ec6917b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/b20780.d
@@ -0,0 +1,11 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/b20780.d(10): Error: `@identifier` or `@(ArgumentList)` expected, not `@)`
+fail_compilation/b20780.d(11): Error: `@identifier` or `@(ArgumentList)` expected, not `@,`
+fail_compilation/b20780.d(11): Error: basic type expected, not `,`
+---
+*/
+
+void f(@){}
+void g(@,){}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b20875.d b/gcc/testsuite/gdc.test/fail_compilation/b20875.d
new file mode 100644
index 0000000..8fd8505
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/b20875.d
@@ -0,0 +1,27 @@
+module b20875;
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/b20875.d(10): Error: template instance `Foo!int` does not match template declaration `Foo(alias T : None!U, U...)`
+fail_compilation/b20875.d(10): while evaluating: `static assert(Foo!int)`
+fail_compilation/b20875.d(11): Error: template instance `Bar!int` does not match template declaration `Bar(alias T : None!U, U...)`
+fail_compilation/b20875.d(11): while evaluating: `static assert(!Bar!int)`
+fail_compilation/b20875.d(14): Error: template parameter specialization for a type must be a type and not `NotAType()`
+fail_compilation/b20875.d(15): while looking for match for `Baz!int`
+fail_compilation/b20875.d(15): while evaluating: `static assert(!Baz!int)`
+---
+*/
+
+#line 7
+
+enum Foo(alias T : None!U, U...) = true;
+enum Bar(alias T : None!U, U...) = false;
+static assert( Foo!(int));
+static assert(!Bar!(int));
+
+template NotAType(){}
+enum Baz(alias T : NotAType) = false;
+static assert(!Baz!(int));
+
+void main(){}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b3841.d b/gcc/testsuite/gdc.test/fail_compilation/b3841.d
index 4a99e9a..ceddc87 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/b3841.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/b3841.d
@@ -1,24 +1,25 @@
-// PERMUTE_ARGS:
// REQUIRED_ARGS: -w -o-
/*
TEST_OUTPUT:
---
-fail_compilation/b3841.d-mixin-31(31): Warning: char += float is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: int += float is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: long += double is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: char -= float is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: int -= float is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: long -= double is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: char *= float is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: int *= float is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: long *= double is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: char /= float is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: int /= float is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: long /= double is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: char %= float is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: int %= float is performing truncating conversion
-fail_compilation/b3841.d-mixin-31(31): Warning: long %= double is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `char += float` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `int += float` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `long += double` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `char -= float` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `int -= float` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `long -= double` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `char *= float` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `int *= float` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `long *= double` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `char /= float` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `int /= float` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `long /= double` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `char %= float` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `int %= float` is performing truncating conversion
+fail_compilation/b3841.d-mixin-32(32): Warning: `long %= double` is performing truncating conversion
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
@@ -45,7 +46,6 @@ void main()
f!(op, long, int)();
f!(op, long, short)();
f!(op, float, long)();
- f!(op, cfloat, long)();
f!(op, double, float)();
// Should that really be OK ?
@@ -58,15 +58,6 @@ void main()
f!(op, long, double)();
}
- foreach (string op; Ops!("+=", "-="))
- {
- // OK
- f!(op, idouble, ifloat)();
-
- // Should that really be OK ?
- f!(op, ifloat, idouble)();
- }
-
// OK
f!("^^=", int, int)();
f!("^^=", long, int)();
@@ -75,4 +66,4 @@ void main()
f!("^^=", double, float)();
// Should that really be OK ?
f!("^^=", float, double)();
-} \ No newline at end of file
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b6227.d b/gcc/testsuite/gdc.test/fail_compilation/b6227.d
new file mode 100644
index 0000000..a9b2a50
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/b6227.d
@@ -0,0 +1,17 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/b6227.d(16): Error: Comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType`
+fail_compilation/b6227.d(16): while evaluating: `static assert(!(X.O != Y.U))`
+fail_compilation/b6227.d(17): Error: Comparison between different enumeration types `X` and `Y`; If this behavior is intended consider using `std.conv.asOriginalType`
+fail_compilation/b6227.d(17): while evaluating: `static assert(X.O == Y.U)`
+---
+*/
+enum X {
+ O,
+ R
+}
+enum Y {
+ U
+}
+static assert(!(X.O != Y.U));
+static assert( (X.O == Y.U));
diff --git a/gcc/testsuite/gdc.test/fail_compilation/betterc.d b/gcc/testsuite/gdc.test/fail_compilation/betterc.d
new file mode 100644
index 0000000..e1cc4cf
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/betterc.d
@@ -0,0 +1,30 @@
+/* REQUIRED_ARGS: -betterC
+ * TEST_OUTPUT:
+---
+fail_compilation/betterc.d(12): Error: Cannot use `throw` statements with -betterC
+fail_compilation/betterc.d(17): Error: Cannot use try-catch statements with -betterC
+fail_compilation/betterc.d(29): Error: `TypeInfo` cannot be used with -betterC
+---
+*/
+
+void test()
+{
+ throw new Exception("msg");
+}
+
+void test2()
+{
+ try
+ {
+ test();
+ }
+ catch (Exception e)
+ {
+ }
+}
+
+void test3()
+{
+ int i;
+ auto ti = typeid(i);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug15613.d b/gcc/testsuite/gdc.test/fail_compilation/bug15613.d
index e8072fd..5b16f72 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/bug15613.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/bug15613.d
@@ -16,3 +16,18 @@ void main()
f(null);
g(8);
}
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/bug15613.d(32): Error: function `bug15613.h(int[]...)` is not callable using argument types `(int, void function(int[]...))`
+fail_compilation/bug15613.d(32): cannot pass argument `& h` of type `void function(int[]...)` to parameter `int[]...`
+---
+*/
+
+void h(int[]...);
+
+void test()
+{
+ h(7, &h);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug16165.d b/gcc/testsuite/gdc.test/fail_compilation/bug16165.d
index fdfbf73..1818e0d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/bug16165.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/bug16165.d
@@ -2,9 +2,9 @@ void f(int x, Object y);
void g()
{
- Object o;
- f(o, o, 404);
- f(5, 6, 404);
+ Object o;
+ f(o, o, 404);
+ f(5, 6, 404);
}
/*
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug18743.d b/gcc/testsuite/gdc.test/fail_compilation/bug18743.d
new file mode 100644
index 0000000..9d2f888
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/bug18743.d
@@ -0,0 +1,22 @@
+// REQUIRED_ARGS:
+/*
+TEST_OUTPUT:
+---
+fail_compilation/bug18743.d(18): Error: `a ? a = 4 : a` must be surrounded by parentheses when next to operator `=`
+fail_compilation/bug18743.d(19): Error: `a ? --a : a` must be surrounded by parentheses when next to operator `+=`
+---
+*/
+
+void main()
+{
+ int a;
+
+ // ok
+ (a ? a = 4 : a) = 5;
+ a ? a = 4 : (a = 5);
+
+ a ? a = 4 : a = 5;
+ a ? --a : a += 1;
+
+ a ? a = 4 : a++; // ok
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug19569.d b/gcc/testsuite/gdc.test/fail_compilation/bug19569.d
new file mode 100644
index 0000000..a314142
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/bug19569.d
@@ -0,0 +1,90 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/bug19569.d(70): Error: `bug19569.test0` called with argument types `()` matches both:
+fail_compilation/bug19569.d(56): `bug19569.test0()`
+and:
+fail_compilation/bug19569.d(57): `bug19569.test0()`
+fail_compilation/bug19569.d(71): Error: `bug19569.test1` called with argument types `()` matches both:
+fail_compilation/bug19569.d(59): `bug19569.test1()`
+and:
+fail_compilation/bug19569.d(60): `bug19569.test1()`
+fail_compilation/bug19569.d(72): Error: `bug19569.test2` called with argument types `()` matches both:
+fail_compilation/bug19569.d(62): `bug19569.test2!().test2()`
+and:
+fail_compilation/bug19569.d(63): `bug19569.test2!().test2()`
+fail_compilation/bug19569.d(73): Error: `bug19569.test3` called with argument types `()` matches both:
+fail_compilation/bug19569.d(65): `bug19569.test3!().test3()`
+and:
+fail_compilation/bug19569.d(66): `bug19569.test3!().test3()`
+fail_compilation/bug19569.d(78): Error: `bug19569.test0` called with argument types `()` matches both:
+fail_compilation/bug19569.d(56): `bug19569.test0()`
+and:
+fail_compilation/bug19569.d(57): `bug19569.test0()`
+fail_compilation/bug19569.d(79): Error: `bug19569.test1` called with argument types `()` matches both:
+fail_compilation/bug19569.d(59): `bug19569.test1()`
+and:
+fail_compilation/bug19569.d(60): `bug19569.test1()`
+fail_compilation/bug19569.d(80): Error: `bug19569.test2` called with argument types `()` matches both:
+fail_compilation/bug19569.d(62): `bug19569.test2!().test2()`
+and:
+fail_compilation/bug19569.d(63): `bug19569.test2!().test2()`
+fail_compilation/bug19569.d(81): Error: `bug19569.test3` called with argument types `()` matches both:
+fail_compilation/bug19569.d(65): `bug19569.test3!().test3()`
+and:
+fail_compilation/bug19569.d(66): `bug19569.test3!().test3()`
+fail_compilation/bug19569.d(86): Error: `bug19569.test0` called with argument types `()` matches both:
+fail_compilation/bug19569.d(56): `bug19569.test0()`
+and:
+fail_compilation/bug19569.d(57): `bug19569.test0()`
+fail_compilation/bug19569.d(87): Error: `bug19569.test1` called with argument types `()` matches both:
+fail_compilation/bug19569.d(59): `bug19569.test1()`
+and:
+fail_compilation/bug19569.d(60): `bug19569.test1()`
+fail_compilation/bug19569.d(88): Error: `bug19569.test2` called with argument types `()` matches both:
+fail_compilation/bug19569.d(62): `bug19569.test2!().test2()`
+and:
+fail_compilation/bug19569.d(63): `bug19569.test2!().test2()`
+fail_compilation/bug19569.d(89): Error: `bug19569.test3` called with argument types `()` matches both:
+fail_compilation/bug19569.d(65): `bug19569.test3!().test3()`
+and:
+fail_compilation/bug19569.d(66): `bug19569.test3!().test3()`
+---
+*/
+
+
+void test0();
+void test0() nothrow;
+
+void test1();
+void test1() @nogc;
+
+void test2()();
+void test2()() nothrow;
+
+void test3()();
+void test3()() @nogc;
+
+void attr0()
+{
+ test0();
+ test1();
+ test2();
+ test3();
+}
+
+void attr1() @nogc
+{
+ test0();
+ test1();
+ test2();
+ test3();
+}
+
+void attr3() nothrow @nogc
+{
+ test0();
+ test1();
+ test2();
+ test3();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug8891.d b/gcc/testsuite/gdc.test/fail_compilation/bug8891.d
index b58256e..e7316c3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/bug8891.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/bug8891.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/bug8891.d(21): Error: need 'this' for 'opCall' of type 'S(int n)'
+fail_compilation/bug8891.d(21): Error: need `this` for `opCall` of type `S(int n)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d
index 852eaae..33ea0cd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d
@@ -23,8 +23,7 @@ void main()
/*
TEST_OUTPUT:
---
-fail_compilation/bug9631.d(41): Error: incompatible types for ((x) == (y)): 'bug9631.S' and 'bug9631.tem!
-).S'
+fail_compilation/bug9631.d(41): Error: incompatible types for `(x) == (y)`: `bug9631.S` and `bug9631.tem!().S`
---
*/
@@ -45,18 +44,30 @@ void equal()
/*
TEST_OUTPUT:
---
-fail_compilation/bug9631.d(79): Error: function `bug9631.arg.f(int i, S s)` is not callable using argumen
- types `(int, S)`
-fail_compilation/bug9631.d(79): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `
-ug9631.S s`
-fail_compilation/bug9631.d(80): Error: function literal `__lambda2(S s)` is not callable using argument t
-pes `(S)`
-fail_compilation/bug9631.d(80): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631
-tem!().S s`
-fail_compilation/bug9631.d(86): Error: constructor `bug9631.arg.A.this(S _param_0)` is not callable using
-argument types `(S)`
-fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to paramete
- `bug9631.S _param_0`
+fail_compilation/bug9631.d(55): Error: cannot cast expression `x` of type `bug9631.S` to `bug9631.tem!().S` because of different sizes
+fail_compilation/bug9631.d(58): Error: cannot cast expression `ta` of type `bug9631.tem!().S[1]` to `bug9631.S[1]` because of different sizes
+fail_compilation/bug9631.d(59): Error: cannot cast expression `sa` of type `S[1]` to `S[]` since sizes don't line up
+---
+*/
+void test3()
+{
+ S x;
+ auto y = cast(tem!().S)x;
+
+ tem!().S[1] ta;
+ S[1] sa = cast(S[1])ta;
+ auto t2 = cast(tem!().S[])sa;
+}
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/bug9631.d(79): Error: function `bug9631.arg.f(int i, S s)` is not callable using argument types `(int, S)`
+fail_compilation/bug9631.d(79): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `bug9631.S s`
+fail_compilation/bug9631.d(80): Error: function literal `__lambda4(S s)` is not callable using argument types `(S)`
+fail_compilation/bug9631.d(80): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S s`
+fail_compilation/bug9631.d(86): Error: constructor `bug9631.arg.A.this(S _param_0)` is not callable using argument types `(S)`
+fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S _param_0`
---
*/
void arg()
@@ -80,10 +91,10 @@ TEST_OUTPUT:
---
fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S _param_0)` is not callable using argument types `(S)`
fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S _param_0`
-fail_compilation/bug9631.d(107): Error: template `bug9631.targ.ft` cannot deduce function from argument types `!()(S)`, candidates are:
-fail_compilation/bug9631.d(105): `bug9631.targ.ft()(tem!().S)`
-fail_compilation/bug9631.d(109): Error: template `bug9631.targ.ft2` cannot deduce function from argument types `!()(S, int)`, candidates are:
-fail_compilation/bug9631.d(108): `bug9631.targ.ft2(T)(S, T)`
+fail_compilation/bug9631.d(107): Error: template `bug9631.targ.ft` cannot deduce function from argument types `!()(S)`
+fail_compilation/bug9631.d(105): Candidate is: `ft()(tem!().S)`
+fail_compilation/bug9631.d(109): Error: template `bug9631.targ.ft2` cannot deduce function from argument types `!()(S, int)`
+fail_compilation/bug9631.d(108): Candidate is: `ft2(T)(S, T)`
---
*/
void targ()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ccast.d b/gcc/testsuite/gdc.test/fail_compilation/ccast.d
new file mode 100644
index 0000000..b4897d4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ccast.d
@@ -0,0 +1,9 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ccast.d(9): Error: C style cast illegal, use `cast(byte)i`
+---
+*/
+
+int i;
+byte b = (byte)i;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/checkimports2.d b/gcc/testsuite/gdc.test/fail_compilation/checkimports2.d
new file mode 100644
index 0000000..44c237f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/checkimports2.d
@@ -0,0 +1,30 @@
+// EXTRA_FILES: imports/imp1.d imports/imp2.d
+/*
+TEST_OUTPUT:
+---
+fail_compilation/checkimports2.d(25): Error: no property `X` for type `checkimports2.B`, did you mean `imports.imp2.X`?
+fail_compilation/checkimports2.d(25): while evaluating: `static assert((B).X == 0)`
+fail_compilation/checkimports2.d(26): Error: no property `Y` for type `checkimports2.B`, did you mean `imports.imp2.Y`?
+fail_compilation/checkimports2.d(26): while evaluating: `static assert((B).Y == 2)`
+---
+*/
+
+import imports.imp1;
+
+enum X = 0;
+
+class B
+{
+ import imports.imp2;
+ static assert(X == 0); // imp2.X --> .X
+ int[Y] aa; // imp2.Y
+}
+
+class C : B
+{
+ static assert(B.X == 0); // imp2.X --> error
+ static assert(B.Y == 2); // imp2.Y --> error
+
+ static assert(X == 0); // imp2.X --> .X
+ static assert(Y == 1); // imp2.Y --> imp1.Y
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/checkimports2a.d b/gcc/testsuite/gdc.test/fail_compilation/checkimports2a.d
deleted file mode 100644
index abec424..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/checkimports2a.d
+++ /dev/null
@@ -1,32 +0,0 @@
-// REQUIRED_ARGS:
-/*
-TEST_OUTPUT:
----
-fail_compilation/checkimports2a.d(27): Error: no property `X` for type `checkimports2a.B`, did you mean `imports.imp2.X`?
-fail_compilation/checkimports2a.d(27): while evaluating: `static assert((B).X == 0)`
-fail_compilation/checkimports2a.d(28): Error: no property `Y` for type `checkimports2a.B`, did you mean `imports.imp2.Y`?
-fail_compilation/checkimports2a.d(28): while evaluating: `static assert((B).Y == 2)`
----
-*/
-
-// new lookup + information
-
-import imports.imp1;
-
-enum X = 0;
-
-class B
-{
- import imports.imp2;
- static assert(X == 0); // imp2.X --> .X
- int[Y] aa; // imp2.Y
-}
-
-class C : B
-{
- static assert(B.X == 0); // imp2.X --> error
- static assert(B.Y == 2); // imp2.Y --> error
-
- static assert(X == 0); // imp2.X --> .X
- static assert(Y == 1); // imp2.Y --> imp1.Y
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/checkimports2b.d b/gcc/testsuite/gdc.test/fail_compilation/checkimports2b.d
deleted file mode 100644
index 8b99fdc..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/checkimports2b.d
+++ /dev/null
@@ -1,29 +0,0 @@
-// REQUIRED_ARGS:
-/*
-TEST_OUTPUT:
----
-fail_compilation/checkimports2b.d(18): Error: static assert: `0 == 2` is false
----
-*/
-
-// old lookup + information
-
-import imports.imp1;
-
-enum X = 0;
-
-class B
-{
- import imports.imp2;
- static assert(X == 2); // imp2.X --> .X (information)
- int[Y] aa; // imp2.Y
-}
-
-class C : B
-{
- static assert(B.X == 2); // imp2.X --> error (keep old lookup rule)
- static assert(B.Y == 2); // imp2.Y --> error (keep old lookup rule)
-
- static assert(X == 2); // imp2.X --> .X (information)
- static assert(Y == 2); // imp2.Y --> imp1.Y (information)
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/checkimports2c.d b/gcc/testsuite/gdc.test/fail_compilation/checkimports2c.d
deleted file mode 100644
index 4208dcdf..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/checkimports2c.d
+++ /dev/null
@@ -1,29 +0,0 @@
-// REQUIRED_ARGS:
-/*
-TEST_OUTPUT:
----
-fail_compilation/checkimports2c.d(18): Error: static assert: `0 == 2` is false
----
-*/
-
-// old lookup + information (the order of switches is reverse)
-
-import imports.imp1;
-
-enum X = 0;
-
-class B
-{
- import imports.imp2;
- static assert(X == 2); // imp2.X --> .X (information)
- int[Y] aa; // imp2.Y
-}
-
-class C : B
-{
- static assert(B.X == 2); // imp2.X --> error (keep old lookup rule)
- static assert(B.Y == 2); // imp2.Y --> error (keep old lookup rule)
-
- static assert(X == 2); // imp2.X --> .X (information)
- static assert(Y == 2); // imp2.Y --> imp1.Y (information)
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/circ10280.d b/gcc/testsuite/gdc.test/fail_compilation/circ10280.d
index b839b9f..76a7764 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/circ10280.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/circ10280.d
@@ -1,11 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/circ10280.d(11): Error: circular initialization of variable 'circ10280.q10280'
-fail_compilation/circ10280.d(10): called from here: foo10280()
+fail_compilation/circ10280.d(11): Error: circular initialization of variable `circ10280.q10280`
+fail_compilation/circ10280.d(10): called from here: `foo10280()`
---
*/
-// 10280
+// https://issues.dlang.org/show_bug.cgi?id=10280
const int q10280 = foo10280();
int foo10280() { return q10280; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/class1.d b/gcc/testsuite/gdc.test/fail_compilation/class1.d
index 261652c..a8907ef 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/class1.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/class1.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/class1.d(11): Error: class class1.C identity assignment operator overload is illegal
+fail_compilation/class1.d(11): Error: class `class1.C` identity assignment operator overload is illegal
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/class2.d b/gcc/testsuite/gdc.test/fail_compilation/class2.d
index f4894ee..a355917 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/class2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/class2.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/class2.d(11): Error: class class2.C identity assignment operator overload is illegal
+fail_compilation/class2.d(11): Error: class `class2.C` identity assignment operator overload is illegal
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/commaexp.d b/gcc/testsuite/gdc.test/fail_compilation/commaexp.d
index 3296046..7d50223 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/commaexp.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/commaexp.d
@@ -1,13 +1,16 @@
-/* REQUIRED_ARGS: -o- -de
+/* REQUIRED_ARGS: -o-
TEST_OUTPUT:
---
-fail_compilation/commaexp.d(24): Deprecation: Using the result of a comma expression is deprecated
-fail_compilation/commaexp.d(36): Deprecation: Using the result of a comma expression is deprecated
-fail_compilation/commaexp.d(37): Deprecation: Using the result of a comma expression is deprecated
-fail_compilation/commaexp.d(38): Deprecation: Using the result of a comma expression is deprecated
-fail_compilation/commaexp.d(39): Deprecation: Using the result of a comma expression is deprecated
-fail_compilation/commaexp.d(41): Deprecation: Using the result of a comma expression is deprecated
-fail_compilation/commaexp.d(42): Deprecation: Using the result of a comma expression is deprecated
+fail_compilation/commaexp.d(27): Error: Using the result of a comma expression is not allowed
+fail_compilation/commaexp.d(39): Error: Using the result of a comma expression is not allowed
+fail_compilation/commaexp.d(40): Error: Using the result of a comma expression is not allowed
+fail_compilation/commaexp.d(41): Error: Using the result of a comma expression is not allowed
+fail_compilation/commaexp.d(42): Error: Using the result of a comma expression is not allowed
+fail_compilation/commaexp.d(44): Error: Using the result of a comma expression is not allowed
+fail_compilation/commaexp.d(45): Error: Using the result of a comma expression is not allowed
+fail_compilation/commaexp.d(56): Error: Using the result of a comma expression is not allowed
+fail_compilation/commaexp.d(69): Error: Using the result of a comma expression is not allowed
+fail_compilation/commaexp.d(81): Error: Using the result of a comma expression is not allowed
---
*/
@@ -19,7 +22,7 @@ int main () {
size_t aggr;
MyContainerClass mc;
- // Bug 15997
+ // https://issues.dlang.org/show_bug.cgi?id=15997
enum WINHTTP_ERROR_BASE = 4200;
enum ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED = (WINHTTP_ERROR_BASE, + 44);
@@ -41,3 +44,39 @@ int main () {
ok = true, (ok = (true, false));
return 42, 0;
}
+
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=16022
+
+bool test16022()
+{
+ enum Type { Colon, Comma }
+ Type type;
+ return type == Type.Colon, type == Type.Comma;
+}
+
+bool test16022_structs()
+{
+ struct A
+ {
+ int i;
+ string s;
+ }
+
+ enum Type { Colon = A(0, "zero"), Comma = A(1, "one") }
+ Type type;
+ return type == Type.Colon, type == Type.Comma;
+}
+
+/********************************************/
+
+
+void bar11(int*, int*) { }
+
+void test11()
+{
+ static int* p;
+ static int i;
+ bar11((i,p), &i);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d
new file mode 100755
index 0000000..a60ea8c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_aggr.d
@@ -0,0 +1,45 @@
+/*
+EXTRA_FILES: imports/constraints.d
+TEST_OUTPUT:
+---
+fail_compilation/constraints_aggr.d(32): Error: template `imports.constraints.C.f` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(60): Candidate is: `f(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` !P!T`
+fail_compilation/constraints_aggr.d(33): Error: template `imports.constraints.C.g` cannot deduce function from argument types `!()()`
+fail_compilation/imports/constraints.d(63): Candidate is: `g(this T)()`
+ with `T = imports.constraints.C`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_aggr.d(35): Error: template instance `imports.constraints.S!int` does not match template declaration `S(T)`
+ with `T = int`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_aggr.d(44): Error: template instance `imports.constraints.BitFlags!(Enum)` does not match template declaration `BitFlags(E, bool unsafe = false)`
+ with `E = Enum`
+ must satisfy one of the following constraints:
+` unsafe
+ N!E`
+---
+*/
+
+void main()
+{
+ import imports.constraints;
+
+ C c = new C;
+ c.f(0);
+ c.g();
+
+ S!int;
+
+ enum Enum
+ {
+ A = 1,
+ B = 2,
+ C = 4,
+ BC = B|C
+ }
+ BitFlags!Enum flags;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_defs.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_defs.d
new file mode 100755
index 0000000..7515208
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_defs.d
@@ -0,0 +1,56 @@
+/*
+EXTRA_FILES: imports/constraints.d
+TEST_OUTPUT:
+---
+fail_compilation/constraints_defs.d(49): Error: template instance `constraints_defs.main.def!(int, 0, (a) => a)` does not match template declaration `def(T, int i = 5, alias R)()`
+ with `T = int,
+ i = 0,
+ R = __lambda1`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_defs.d(50): Error: template instance `imports.constraints.defa!int` does not match template declaration `defa(T, U = int)()`
+ with `T = int`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_defs.d(51): Error: template instance `imports.constraints.defv!()` does not match template declaration `defv(T = bool, int i = 5, Ts...)()`
+ with `Ts = ()`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_defs.d(52): Error: template instance `imports.constraints.defv!int` does not match template declaration `defv(T = bool, int i = 5, Ts...)()`
+ with `T = int,
+ Ts = ()`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_defs.d(53): Error: template instance `imports.constraints.defv!(int, 0)` does not match template declaration `defv(T = bool, int i = 5, Ts...)()`
+ with `T = int,
+ i = 0,
+ Ts = ()`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_defs.d(54): Error: template instance `imports.constraints.defv!(int, 0, bool)` does not match template declaration `defv(T = bool, int i = 5, Ts...)()`
+ with `T = int,
+ i = 0,
+ Ts = (bool)`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_defs.d(55): Error: template instance `imports.constraints.defv!(int, 0, bool, float)` does not match template declaration `defv(T = bool, int i = 5, Ts...)()`
+ with `T = int,
+ i = 0,
+ Ts = (bool, float)`
+ must satisfy the following constraint:
+` N!T`
+---
+*/
+
+void main()
+{
+ import imports.constraints;
+
+ def!(int, 0, a => a)();
+ defa!(int)();
+ defv!()();
+ defv!(int)();
+ defv!(int, 0)();
+ defv!(int, 0, bool)();
+ defv!(int, 0, bool, float)();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d
new file mode 100755
index 0000000..91dd405
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func1.d
@@ -0,0 +1,93 @@
+/*
+EXTRA_FILES: imports/constraints.d
+TEST_OUTPUT:
+---
+fail_compilation/constraints_func1.d(79): Error: template `imports.constraints.test1` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(9): Candidate is: `test1(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_func1.d(80): Error: template `imports.constraints.test2` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(10): Candidate is: `test2(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` !P!T`
+fail_compilation/constraints_func1.d(81): Error: template `imports.constraints.test3` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(11): Candidate is: `test3(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_func1.d(82): Error: template `imports.constraints.test4` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(12): Candidate is: `test4(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_func1.d(83): Error: template `imports.constraints.test5` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(13): Candidate is: `test5(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` N!T
+ N!T`
+fail_compilation/constraints_func1.d(84): Error: template `imports.constraints.test6` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(14): Candidate is: `test6(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` N!T
+ N!T
+ !P!T`
+fail_compilation/constraints_func1.d(85): Error: template `imports.constraints.test7` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(15): Candidate is: `test7(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` N!T
+ N!T`
+fail_compilation/constraints_func1.d(86): Error: template `imports.constraints.test8` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(16): Candidate is: `test8(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_func1.d(87): Error: template `imports.constraints.test9` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(17): Candidate is: `test9(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` !P!T`
+fail_compilation/constraints_func1.d(88): Error: template `imports.constraints.test10` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(18): Candidate is: `test10(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` !P!T`
+fail_compilation/constraints_func1.d(89): Error: template `imports.constraints.test11` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(19): Candidate is: `test11(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` N!T
+ !P!T`
+fail_compilation/constraints_func1.d(90): Error: template `imports.constraints.test12` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(20): Candidate is: `test12(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` !P!T`
+fail_compilation/constraints_func1.d(92): Error: template `imports.constraints.test1` cannot deduce function from argument types `!()(int, int)`
+fail_compilation/imports/constraints.d(9): Candidate is: `test1(T)(T v)`
+---
+*/
+
+void main()
+{
+ import imports.constraints;
+
+ test1(0);
+ test2(0);
+ test3(0);
+ test4(0);
+ test5(0);
+ test6(0);
+ test7(0);
+ test8(0);
+ test9(0);
+ test10(0);
+ test11(0);
+ test12(0);
+
+ test1(0, 0);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d
new file mode 100755
index 0000000..67aa78c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func2.d
@@ -0,0 +1,108 @@
+/*
+EXTRA_FILES: imports/constraints.d
+TEST_OUTPUT:
+---
+fail_compilation/constraints_func2.d(94): Error: template `imports.constraints.test13` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(23): Candidate is: `test13(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` N!T
+ !P!T`
+fail_compilation/constraints_func2.d(95): Error: template `imports.constraints.test14` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(24): Candidate is: `test14(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` !P!T
+ N!T`
+fail_compilation/constraints_func2.d(96): Error: template `imports.constraints.test15` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(25): Candidate is: `test15(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` !P!T
+ !P!T`
+fail_compilation/constraints_func2.d(97): Error: template `imports.constraints.test16` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(26): Candidate is: `test16(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` N!T
+ N!T`
+fail_compilation/constraints_func2.d(98): Error: template `imports.constraints.test17` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(27): Candidate is: `test17(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_func2.d(99): Error: template `imports.constraints.test18` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(28): Candidate is: `test18(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` N!T
+ N!T`
+fail_compilation/constraints_func2.d(100): Error: template `imports.constraints.test19` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(29): Candidate is: `test19(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` N!T
+ !P!T
+ N!T`
+fail_compilation/constraints_func2.d(101): Error: template `imports.constraints.test20` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(30): Candidate is: `test20(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_func2.d(102): Error: template `imports.constraints.test21` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(31): Candidate is: `test21(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` N!T
+ N!T`
+fail_compilation/constraints_func2.d(103): Error: template `imports.constraints.test22` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(32): Candidate is: `test22(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` !P!T
+ !P!T`
+fail_compilation/constraints_func2.d(104): Error: template `imports.constraints.test23` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(33): Candidate is: `test23(T)(T v)`
+ with `T = int`
+ must satisfy one of the following constraints:
+` !P!T
+ N!T
+ !P!T`
+fail_compilation/constraints_func2.d(105): Error: template `imports.constraints.test24` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(34): Candidate is: `test24(R)(R r)`
+ with `R = int`
+ must satisfy the following constraint:
+` __traits(hasMember, R, "stuff")`
+fail_compilation/constraints_func2.d(106): Error: template `imports.constraints.test25` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(35): Candidate is: `test25(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_func2.d(107): Error: template `imports.constraints.test26` cannot deduce function from argument types `!(float)(int)`
+fail_compilation/imports/constraints.d(36): Candidate is: `test26(T, U)(U u)`
+ with `T = float,
+ U = int`
+ must satisfy the following constraint:
+` N!U`
+---
+*/
+
+void main()
+{
+ import imports.constraints;
+
+ test13(0);
+ test14(0);
+ test15(0);
+ test16(0);
+ test17(0);
+ test18(0);
+ test19(0);
+ test20(0);
+ test21(0);
+ test22(0);
+ test23(0);
+ test24(0);
+ test25(0);
+ test26!float(5);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d
new file mode 100755
index 0000000..f0a5099
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func3.d
@@ -0,0 +1,60 @@
+/*
+EXTRA_FILES: imports/constraints.d
+TEST_OUTPUT:
+---
+fail_compilation/constraints_func3.d(53): Error: template `imports.constraints.overload` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(39): Candidates are: `overload(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/imports/constraints.d(40): `overload(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` !P!T`
+fail_compilation/imports/constraints.d(41): `overload(T)(T v1, T v2)`
+fail_compilation/imports/constraints.d(42): `overload(T, V)(T v1, V v2)`
+fail_compilation/constraints_func3.d(54): Error: template `imports.constraints.overload` cannot deduce function from argument types `!()(int, string)`
+fail_compilation/imports/constraints.d(39): Candidates are: `overload(T)(T v)`
+fail_compilation/imports/constraints.d(40): `overload(T)(T v)`
+fail_compilation/imports/constraints.d(41): `overload(T)(T v1, T v2)`
+fail_compilation/imports/constraints.d(42): `overload(T, V)(T v1, V v2)`
+ with `T = int,
+ V = string`
+ must satisfy one of the following constraints:
+` N!T
+ N!V`
+fail_compilation/constraints_func3.d(56): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()()`
+fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
+fail_compilation/constraints_func3.d(57): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int)`
+fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
+ with `A = int,
+ T = ()`
+ must satisfy the following constraint:
+` N!int`
+fail_compilation/constraints_func3.d(58): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int, int)`
+fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
+ with `A = int,
+ T = (int)`
+ must satisfy the following constraint:
+` N!int`
+fail_compilation/constraints_func3.d(59): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int, int, int)`
+fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
+ with `A = int,
+ T = (int, int)`
+ must satisfy the following constraint:
+` N!int`
+---
+*/
+
+void main()
+{
+ import imports.constraints;
+
+ overload(0);
+ overload(0, "");
+
+ variadic();
+ variadic(0);
+ variadic(0, 1);
+ variadic(0, 1, 2);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d
new file mode 100755
index 0000000..751e618
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_func4.d
@@ -0,0 +1,97 @@
+/*
+EXTRA_FILES: imports/constraints.d
+REQUIRED_ARGS: -verrors=context
+TEST_OUTPUT:
+---
+fail_compilation/constraints_func4.d(90): Error: template `imports.constraints.overload` cannot deduce function from argument types `!()(int)`
+ overload(0);
+ ^
+fail_compilation/imports/constraints.d(39): Candidates are: `overload(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` N!T`
+void overload(T)(T v) if (N!T);
+ ^
+fail_compilation/imports/constraints.d(40): `overload(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` !P!T`
+void overload(T)(T v) if (!P!T);
+ ^
+fail_compilation/imports/constraints.d(41): `overload(T)(T v1, T v2)`
+void overload(T)(T v1, T v2) if (N!T);
+ ^
+fail_compilation/imports/constraints.d(42): `overload(T, V)(T v1, V v2)`
+void overload(T, V)(T v1, V v2) if (N!T || N!V);
+ ^
+fail_compilation/constraints_func4.d(91): Error: template `imports.constraints.overload` cannot deduce function from argument types `!()(int, string)`
+ overload(0, "");
+ ^
+fail_compilation/imports/constraints.d(39): Candidates are: `overload(T)(T v)`
+void overload(T)(T v) if (N!T);
+ ^
+fail_compilation/imports/constraints.d(40): `overload(T)(T v)`
+void overload(T)(T v) if (!P!T);
+ ^
+fail_compilation/imports/constraints.d(41): `overload(T)(T v1, T v2)`
+void overload(T)(T v1, T v2) if (N!T);
+ ^
+fail_compilation/imports/constraints.d(42): `overload(T, V)(T v1, V v2)`
+ with `T = int,
+ V = string`
+ must satisfy one of the following constraints:
+` N!T
+ N!V`
+void overload(T, V)(T v1, V v2) if (N!T || N!V);
+ ^
+fail_compilation/constraints_func4.d(93): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()()`
+ variadic();
+ ^
+fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
+void variadic(A, T...)(A a, T v) if (N!int);
+ ^
+fail_compilation/constraints_func4.d(94): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int)`
+ variadic(0);
+ ^
+fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
+ with `A = int,
+ T = ()`
+ must satisfy the following constraint:
+` N!int`
+void variadic(A, T...)(A a, T v) if (N!int);
+ ^
+fail_compilation/constraints_func4.d(95): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int, int)`
+ variadic(0, 1);
+ ^
+fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
+ with `A = int,
+ T = (int)`
+ must satisfy the following constraint:
+` N!int`
+void variadic(A, T...)(A a, T v) if (N!int);
+ ^
+fail_compilation/constraints_func4.d(96): Error: template `imports.constraints.variadic` cannot deduce function from argument types `!()(int, int, int)`
+ variadic(0, 1, 2);
+ ^
+fail_compilation/imports/constraints.d(43): Candidate is: `variadic(A, T...)(A a, T v)`
+ with `A = int,
+ T = (int, int)`
+ must satisfy the following constraint:
+` N!int`
+void variadic(A, T...)(A a, T v) if (N!int);
+ ^
+---
+*/
+
+void main()
+{
+ import imports.constraints;
+
+ overload(0);
+ overload(0, "");
+
+ variadic();
+ variadic(0);
+ variadic(0, 1);
+ variadic(0, 1, 2);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_tmpl.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_tmpl.d
new file mode 100755
index 0000000..06caa52
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_tmpl.d
@@ -0,0 +1,44 @@
+/*
+EXTRA_FILES: imports/constraints.d
+TEST_OUTPUT:
+---
+fail_compilation/constraints_tmpl.d(35): Error: template instance `imports.constraints.dummy!()` does not match template declaration `dummy()()`
+ must satisfy the following constraint:
+` false`
+fail_compilation/constraints_tmpl.d(37): Error: template instance `imports.constraints.message_nice!(int, int)` does not match template declaration `message_nice(T, U)()`
+ with `T = int,
+ U = int`
+ must satisfy the following constraint:
+` N!U`
+fail_compilation/constraints_tmpl.d(38): Error: template instance `imports.constraints.message_ugly!int` does not match template declaration `message_ugly(T)(T v)`
+ with `T = int`
+ must satisfy the following constraint:
+` N!T`
+fail_compilation/constraints_tmpl.d(40): Error: template instance `args!int` does not match template declaration `args(T, U)()`
+fail_compilation/constraints_tmpl.d(41): Error: template instance `imports.constraints.args!(int, float)` does not match template declaration `args(T, U)()`
+ with `T = int,
+ U = float`
+ must satisfy one of the following constraints:
+` N!T
+ N!U`
+fail_compilation/constraints_tmpl.d(43): Error: template instance `constraints_tmpl.main.lambda!((a) => a)` does not match template declaration `lambda(alias pred)()`
+ with `pred = __lambda1`
+ must satisfy the following constraint:
+` N!int`
+---
+*/
+
+void main()
+{
+ import imports.constraints;
+
+ dummy!();
+
+ message_nice!(int, int);
+ message_ugly!int;
+
+ args!int;
+ args!(int, float);
+
+ lambda!(a => a)();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/cpp_abi_tag.d b/gcc/testsuite/gdc.test/fail_compilation/cpp_abi_tag.d
new file mode 100644
index 0000000..542bc43
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/cpp_abi_tag.d
@@ -0,0 +1,57 @@
+/* DISABLED: win32 win64
+REQUIRED_ARGS: -extern-std=c++11
+TEST_OUTPUT:
+---
+fail_compilation/cpp_abi_tag.d(111): Error: `@gnuAbiTag` can only apply to C++ symbols
+fail_compilation/cpp_abi_tag.d(131): Error: `@gnuAbiTag` cannot be applied to namespaces
+fail_compilation/cpp_abi_tag.d(102): Error: `@gnuAbiTag` at least one argument expected
+fail_compilation/cpp_abi_tag.d(105): Error: `@gnuAbiTag` at least one argument expected
+fail_compilation/cpp_abi_tag.d(108): Error: `@gnuAbiTag` char `0x99` not allowed in mangling
+fail_compilation/cpp_abi_tag.d(114): Error: argument `2` to `@gnuAbiTag` cannot be `null`
+fail_compilation/cpp_abi_tag.d(114): Error: argument `3` to `@gnuAbiTag` cannot be empty
+fail_compilation/cpp_abi_tag.d(117): Error: `@gnuAbiTag` at least one argument expected
+fail_compilation/cpp_abi_tag.d(137): Error: only one `@gnuAbiTag` allowed per symbol
+fail_compilation/cpp_abi_tag.d(137): instead of `@gnuAbiTag(["x"]) @gnuAbiTag(["a"])`, use `@gnuAbiTag("x", "a")`
+---
+*/
+
+#line 100
+import core.attribute;
+
+@gnuAbiTag
+extern(C++) struct A {}
+
+@gnuAbiTag()
+extern(C++) struct B {}
+
+@gnuAbiTag("a\x99")
+extern(C++) struct D {}
+
+@gnuAbiTag("a")
+struct F {}
+
+@gnuAbiTag("a", null, "")
+extern(C++) struct G {}
+
+@gnuAbiTag((string[]).init)
+extern(C++) struct H {}
+
+// Note: There is no way to distinguish between
+// `extern(C++, "ns") { ... }` and `extern(C++, "ns") ...;`
+// So ABI tags have to be on the inside
+extern(C++, "ns") @gnuAbiTag("x") void func1();
+extern(C++, ns2) @gnuAbiTag("x") void func2();
+
+@gnuAbiTag("x")
+extern(C++, "ns3")
+{
+ void func3();
+}
+@gnuAbiTag("x")
+extern(C++, ns4)
+{
+ void func4();
+}
+
+@gnuAbiTag("x") @gnuAbiTag("a")
+extern(C++) void func5();
diff --git a/gcc/testsuite/gdc.test/fail_compilation/cpp_abi_tag2.d b/gcc/testsuite/gdc.test/fail_compilation/cpp_abi_tag2.d
new file mode 100644
index 0000000..2739e2b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/cpp_abi_tag2.d
@@ -0,0 +1,19 @@
+/* DISABLED: win32 win64
+REQUIRED_ARGS: -extern-std=c++11
+TEST_OUTPUT:
+---
+fail_compilation/cpp_abi_tag2.d(102): Error: constructor `core.attribute.gnuAbiTag.this(string[] tags...)` is not callable using argument types `(string, wstring, dstring)`
+fail_compilation/cpp_abi_tag2.d(102): cannot pass argument `"b"w` of type `wstring` to parameter `string[] tags...`
+fail_compilation/cpp_abi_tag2.d(105): Error: constructor `core.attribute.gnuAbiTag.this(string[] tags...)` is not callable using argument types `(string, int, double)`
+fail_compilation/cpp_abi_tag2.d(105): cannot pass argument `2` of type `int` to parameter `string[] tags...`
+---
+*/
+
+#line 100
+import core.attribute;
+
+@gnuAbiTag("a", "b"w, "c"d)
+extern(C++) struct C {}
+
+@gnuAbiTag("a", 2, 3.3)
+extern(C++) struct E {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/cppeh1.d b/gcc/testsuite/gdc.test/fail_compilation/cppeh1.d
index e60368c..9ef0ab3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/cppeh1.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/cppeh1.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/cppeh1.d(26): Error: cannot catch C++ class objects in @safe code
+fail_compilation/cppeh1.d(26): Error: cannot catch C++ class objects in `@safe` code
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/cppmangle.d b/gcc/testsuite/gdc.test/fail_compilation/cppmangle.d
index ca9ed9a..8134afb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/cppmangle.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/cppmangle.d
@@ -1,9 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/cppmangle.d(10): Error: invalid zero length C++ namespace
-fail_compilation/cppmangle.d(14): Error: expected valid identifier for C++ namespace but got `0num`
-fail_compilation/cppmangle.d(18): Error: string expected following `,` for C++ namespace, not `)`
+fail_compilation/cppmangle.d(11): Error: expected valid identifier for C++ namespace but got ``
+fail_compilation/cppmangle.d(15): Error: expected valid identifier for C++ namespace but got `0num`
+fail_compilation/cppmangle.d(19): Error: compile time string constant (or tuple) expected, not `2`
+fail_compilation/cppmangle.d(23): Error: expected valid identifier for C++ namespace but got `invalid@namespace`
---
*/
@@ -15,6 +16,10 @@ extern(C++, "0num")
{
}
-extern(C++, "std", )
+extern(C++, 1+1)
+{
+}
+
+extern(C++, "invalid@namespace")
{
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/cppmangle2.d b/gcc/testsuite/gdc.test/fail_compilation/cppmangle2.d
new file mode 100644
index 0000000..67f0647
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/cppmangle2.d
@@ -0,0 +1,11 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/cppmangle2.d(9): Error: namespace `cppmangle2.ns` conflicts with variable `cppmangle2.ns` at fail_compilation/cppmangle2.d(8)
+---
+*/
+
+enum ns = "ns";
+extern(C++, ns)
+{
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe10989.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe10989.d
index 22b6dbb..a5da609 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ctfe10989.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe10989.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ctfe10989.d(11): Error: uncaught CTFE exception object.Exception("abc"c)
-fail_compilation/ctfe10989.d(14): called from here: throwing()
+fail_compilation/ctfe10989.d(11): Error: uncaught CTFE exception `object.Exception("abc"c)`
+fail_compilation/ctfe10989.d(14): called from here: `throwing()`
fail_compilation/ctfe10989.d(14): while evaluating: `static assert(throwing())`
---
*/
@@ -16,8 +16,8 @@ static assert(throwing());
/*
TEST_OUTPUT:
---
-fail_compilation/ctfe10989.d(33): Error: uncaught CTFE exception object.Exception("abc"c)
-fail_compilation/ctfe10989.d(36): called from here: throwing2()
+fail_compilation/ctfe10989.d(33): Error: uncaught CTFE exception `object.Exception("abc"c)`
+fail_compilation/ctfe10989.d(36): called from here: `throwing2()`
fail_compilation/ctfe10989.d(36): while evaluating: `static assert(throwing2())`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe10995.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe10995.d
index ca42495..829fb53 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ctfe10995.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe10995.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ctfe10995.d(19): Error: cannot read uninitialized variable a in CTFE
-fail_compilation/ctfe10995.d(25): Error: cannot read uninitialized variable a in CTFE
+fail_compilation/ctfe10995.d(19): Error: cannot read uninitialized variable `a` in CTFE
+fail_compilation/ctfe10995.d(25): Error: cannot read uninitialized variable `a` in CTFE
---
*/
struct T
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe11467.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe11467.d
index f7b2577..dcde98f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ctfe11467.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe11467.d
@@ -1,11 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ctfe11467.d(15): Error: overlapping slice assignment [0..4] = [1..5]
-fail_compilation/ctfe11467.d(24): called from here: test11467a()
+fail_compilation/ctfe11467.d(15): Error: overlapping slice assignment `[0..4] = [1..5]`
+fail_compilation/ctfe11467.d(24): called from here: `test11467a()`
fail_compilation/ctfe11467.d(24): while evaluating: `static assert(test11467a())`
-fail_compilation/ctfe11467.d(21): Error: overlapping slice assignment [1..5] = [0..4]
-fail_compilation/ctfe11467.d(25): called from here: test11467b()
+fail_compilation/ctfe11467.d(21): Error: overlapping slice assignment `[1..5] = [0..4]`
+fail_compilation/ctfe11467.d(25): called from here: `test11467b()`
fail_compilation/ctfe11467.d(25): while evaluating: `static assert(test11467b())`
---
*/
@@ -27,11 +27,11 @@ static assert(test11467b());
/*
TEST_OUTPUT:
---
-fail_compilation/ctfe11467.d(41): Error: overlapping slice assignment [0..4] = [1..5]
-fail_compilation/ctfe11467.d(50): called from here: test11467c()
+fail_compilation/ctfe11467.d(41): Error: overlapping slice assignment `[0..4] = [1..5]`
+fail_compilation/ctfe11467.d(50): called from here: `test11467c()`
fail_compilation/ctfe11467.d(50): while evaluating: `static assert(test11467c())`
-fail_compilation/ctfe11467.d(47): Error: overlapping slice assignment [1..5] = [0..4]
-fail_compilation/ctfe11467.d(51): called from here: test11467d()
+fail_compilation/ctfe11467.d(47): Error: overlapping slice assignment `[1..5] = [0..4]`
+fail_compilation/ctfe11467.d(51): called from here: `test11467d()`
fail_compilation/ctfe11467.d(51): while evaluating: `static assert(test11467d())`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe13612.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe13612.d
index b7ab79e..150f2ac 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ctfe13612.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe13612.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ctfe13612.d(15): Error: function ctfe13612.S.recurse CTFE recursion limit exceeded
-fail_compilation/ctfe13612.d(20): called from here: s.recurse()
-fail_compilation/ctfe13612.d(15): 1000 recursive calls to function recurse
-fail_compilation/ctfe13612.d(23): called from here: (new S).recurse()
+fail_compilation/ctfe13612.d(15): Error: function `ctfe13612.S.recurse` CTFE recursion limit exceeded
+fail_compilation/ctfe13612.d(20): called from here: `s.recurse()`
+fail_compilation/ctfe13612.d(15): 1000 recursive calls to function `recurse`
+fail_compilation/ctfe13612.d(23): called from here: `(new S).recurse()`
fail_compilation/ctfe13612.d(23): while evaluating: `static assert((new S).recurse())`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe14207.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe14207.d
index 511f755..becc068 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ctfe14207.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe14207.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ctfe14207.d(13): Error: cannot convert &immutable(ulong) to ubyte[8]* at compile time
-fail_compilation/ctfe14207.d(18): called from here: nativeToBigEndian()
-fail_compilation/ctfe14207.d(22): called from here: digest()
+fail_compilation/ctfe14207.d(13): Error: cannot convert `&immutable(ulong)` to `ubyte[8]*` at compile time
+fail_compilation/ctfe14207.d(18): called from here: `nativeToBigEndian()`
+fail_compilation/ctfe14207.d(22): called from here: `digest()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe14465.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe14465.d
index 9106d3d..52e1ad3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ctfe14465.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe14465.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ctfe14465.d(19): Error: uncaught CTFE exception ctfe14465.E("message")
-fail_compilation/ctfe14465.d(22): called from here: foo()
+fail_compilation/ctfe14465.d(19): Error: uncaught CTFE exception `ctfe14465.E("message")`
+fail_compilation/ctfe14465.d(22): called from here: `foo()`
fail_compilation/ctfe14465.d(22): while evaluating: `static assert(foo())`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dassert.d b/gcc/testsuite/gdc.test/fail_compilation/dassert.d
new file mode 100644
index 0000000..8a81317
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/dassert.d
@@ -0,0 +1,43 @@
+/*
+REQUIRED_ARGS: -checkaction=context
+TEST_OUTPUT:
+---
+fail_compilation/dassert.d(14): Error: expression `tuple(0, 0)` of type `(int, int)` does not have a boolean value
+fail_compilation/dassert.d(21): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/dassert.d(29): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/dassert.d(40): Error: expression `issue()` of type `void` does not have a boolean value
+---
+*/
+#line 10
+
+struct Baguette { int bread, floor; }
+void main ()
+{
+ assert(Baguette.init.tupleof);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=21590
+void issue21590()
+{
+ int a, b = 1;
+ assert (a = b);
+
+ static ref int get()
+ {
+ static int i;
+ return i;
+ }
+
+ assert(get() = 1);
+
+ // No errors for binary assignments (regardless of -checkaction=context)
+ int[] arr;
+ assert(arr ~= 1);
+ assert(a += b);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=21798
+void issue()
+{
+ assert(issue());
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ddoc_18083.d b/gcc/testsuite/gdc.test/fail_compilation/ddoc_18083.d
new file mode 100644
index 0000000..234c280
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ddoc_18083.d
@@ -0,0 +1,17 @@
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/fail_compilation -o- -w -c
+/* TEST_OUTPUT:
+---
+fail_compilation/ddoc_18083.d(14): Warning: Ddoc: function declaration has no parameter 'this'
+fail_compilation/ddoc_18083.d(14): Warning: Ddoc: parameter count mismatch, expected 0, got 1
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
+---
+*/
+/**
+Params:
+ this = non-existent parameter
+*/
+int foo()
+{
+ return 1;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/debugCaseDeclaration.d b/gcc/testsuite/gdc.test/fail_compilation/debugCaseDeclaration.d
new file mode 100644
index 0000000..0a06bca
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/debugCaseDeclaration.d
@@ -0,0 +1,39 @@
+/*
+https://issues.dlang.org/show_bug.cgi?id=21739
+
+REQUIRED_ARGS: -debug
+TEST_OUTPUT:
+---
+fail_compilation/debugCaseDeclaration.d(22): Error: undefined identifier `x`
+fail_compilation/debugCaseDeclaration.d(33): Error: undefined identifier `y`
+---
+*/
+
+void main()
+{
+ int i, k;
+ switch (i)
+ {
+ case 0:
+ int x;
+ break;
+
+ case 1:
+ x = 1;
+ break;
+
+ case 2:
+ int y;
+ break;
+
+ debug
+ {
+ case 3:
+ k = 1; // Valid
+ y = 1; // Invalid but accepted
+ break;
+ }
+
+ default:
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d b/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d
new file mode 100644
index 0000000..230fc4b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d
@@ -0,0 +1,191 @@
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/dep_d1_ops.d(105): Deprecation: `opAdd` is deprecated. Use `opBinary(string op)(...) if (op == "+")` instead.
+fail_compilation/dep_d1_ops.d(106): Deprecation: `opAdd_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "+")` instead.
+fail_compilation/dep_d1_ops.d(107): Deprecation: `opSub` is deprecated. Use `opBinary(string op)(...) if (op == "-")` instead.
+fail_compilation/dep_d1_ops.d(108): Deprecation: `opSub_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "-")` instead.
+fail_compilation/dep_d1_ops.d(109): Deprecation: `opMul` is deprecated. Use `opBinary(string op)(...) if (op == "*")` instead.
+fail_compilation/dep_d1_ops.d(110): Deprecation: `opMul_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "*")` instead.
+fail_compilation/dep_d1_ops.d(111): Deprecation: `opDiv` is deprecated. Use `opBinary(string op)(...) if (op == "/")` instead.
+fail_compilation/dep_d1_ops.d(112): Deprecation: `opDiv_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "/")` instead.
+fail_compilation/dep_d1_ops.d(113): Deprecation: `opMod` is deprecated. Use `opBinary(string op)(...) if (op == "%")` instead.
+fail_compilation/dep_d1_ops.d(114): Deprecation: `opMod_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "%")` instead.
+fail_compilation/dep_d1_ops.d(116): Deprecation: `opAnd` is deprecated. Use `opBinary(string op)(...) if (op == "&")` instead.
+fail_compilation/dep_d1_ops.d(117): Deprecation: `opOr` is deprecated. Use `opBinary(string op)(...) if (op == "|")` instead.
+fail_compilation/dep_d1_ops.d(118): Deprecation: `opXor` is deprecated. Use `opBinary(string op)(...) if (op == "^")` instead.
+fail_compilation/dep_d1_ops.d(120): Deprecation: `opShl` is deprecated. Use `opBinary(string op)(...) if (op == "<<")` instead.
+fail_compilation/dep_d1_ops.d(121): Deprecation: `opShl_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "<<")` instead.
+fail_compilation/dep_d1_ops.d(122): Deprecation: `opShr` is deprecated. Use `opBinary(string op)(...) if (op == ">>")` instead.
+fail_compilation/dep_d1_ops.d(123): Deprecation: `opShr_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == ">>")` instead.
+fail_compilation/dep_d1_ops.d(124): Deprecation: `opUShr` is deprecated. Use `opBinary(string op)(...) if (op == ">>>")` instead.
+fail_compilation/dep_d1_ops.d(125): Deprecation: `opUShr_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == ">>>")` instead.
+fail_compilation/dep_d1_ops.d(127): Deprecation: `opCat` is deprecated. Use `opBinary(string op)(...) if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(128): Deprecation: `opCat_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(130): Deprecation: `opNeg` is deprecated. Use `opUnary(string op)() if (op == "-")` instead.
+fail_compilation/dep_d1_ops.d(131): Deprecation: `opCom` is deprecated. Use `opUnary(string op)() if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(132): Deprecation: `opPostInc` is deprecated. Use `opUnary(string op)() if (op == "++")` instead.
+fail_compilation/dep_d1_ops.d(133): Deprecation: `opPostDec` is deprecated. Use `opUnary(string op)() if (op == "--")` instead.
+fail_compilation/dep_d1_ops.d(134): Deprecation: `opStar` is deprecated. Use `opUnary(string op)() if (op == "*")` instead.
+fail_compilation/dep_d1_ops.d(136): Deprecation: `opIn` is deprecated. Use `opBinary(string op)(...) if (op == "in")` instead.
+fail_compilation/dep_d1_ops.d(137): Deprecation: `opIn_r` is deprecated. Use `opBinaryRight(string op)(...) if (op == "in")` instead.
+fail_compilation/dep_d1_ops.d(139): Deprecation: `opAddAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "+")` instead.
+fail_compilation/dep_d1_ops.d(140): Deprecation: `opSubAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "-")` instead.
+fail_compilation/dep_d1_ops.d(141): Deprecation: `opMulAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "*")` instead.
+fail_compilation/dep_d1_ops.d(142): Deprecation: `opDivAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "/")` instead.
+fail_compilation/dep_d1_ops.d(143): Deprecation: `opModAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "%")` instead.
+fail_compilation/dep_d1_ops.d(144): Deprecation: `opAndAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "&")` instead.
+fail_compilation/dep_d1_ops.d(145): Deprecation: `opOrAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "|")` instead.
+fail_compilation/dep_d1_ops.d(146): Deprecation: `opXorAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "^")` instead.
+fail_compilation/dep_d1_ops.d(147): Deprecation: `opShlAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "<<")` instead.
+fail_compilation/dep_d1_ops.d(148): Deprecation: `opShrAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == ">>")` instead.
+fail_compilation/dep_d1_ops.d(149): Deprecation: `opUShrAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == ">>>")` instead.
+fail_compilation/dep_d1_ops.d(150): Deprecation: `opCatAssign` is deprecated. Use `opOpAssign(string op)(...) if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(158): Deprecation: `opCom` is deprecated. Use `opUnary(string op)() if (op == "~")` instead.
+---
+*/
+
+#line 50
+struct S
+{
+ int opAdd(int i) { return 0; }
+ int opAdd_r(int i) { return 0; }
+ int opSub(int i) { return 0; }
+ int opSub_r(int i) { return 0; }
+ int opMul(int i) { return 0; }
+ int opMul_r(int i) { return 0; }
+ int opDiv(int i) { return 0; }
+ int opDiv_r(int i) { return 0; }
+ int opMod(int i) { return 0; }
+ int opMod_r(int i) { return 0; }
+
+ int opAnd(int i) { return 0; }
+ int opOr(int i) { return 0; }
+ int opXor(int i) { return 0; }
+
+ int opShl(int i) { return 0; }
+ int opShl_r(int i) { return 0; }
+ int opShr(int i) { return 0; }
+ int opShr_r(int i) { return 0; }
+ int opUShr(int i) { return 0; }
+ int opUShr_r(int i) { return 0; }
+
+ int opCat(int i) { return 0; }
+ int opCat_r(int i) { return 0; }
+
+ int opNeg() { return 0; }
+ int opCom() { return 0; }
+ int opPostInc() { return 0; }
+ int opPostDec() { return 0; }
+ int opStar() { return 0; }
+
+ int opIn(int i) { return 0; }
+ int opIn_r(int i) { return 0; }
+
+ int opAddAssign(int i) { return 0; }
+ int opSubAssign(int i) { return 0; }
+ int opMulAssign(int i) { return 0; }
+ int opDivAssign(int i) { return 0; }
+ int opModAssign(int i) { return 0; }
+ int opAndAssign(int i) { return 0; }
+ int opOrAssign(int i) { return 0; }
+ int opXorAssign(int i) { return 0; }
+ int opShlAssign(int i) { return 0; }
+ int opShrAssign(int i) { return 0; }
+ int opUShrAssign(int i) { return 0; }
+ int opCatAssign(int i) { return 0; }
+}
+
+void main()
+{
+ S s;
+ int i;
+
+ i = s + 1;
+ i = 1 + s;
+ i = s - 1;
+ i = 1 - s;
+ i = s * 1;
+ i = 1 * s;
+ i = s / 1;
+ i = 1 / s;
+ i = s % 1;
+ i = 1 % s;
+
+ i = s & 1;
+ i = s | 1;
+ i = s ^ 1;
+
+ i = s << 1;
+ i = 1 << s;
+ i = s >> 1;
+ i = 1 >> s;
+ i = s >>> 1;
+ i = 1 >>> s;
+
+ i = s ~ 1;
+ i = 1 ~ s;
+
+ i = -s;
+ i = ~s;
+ s++;
+ s--;
+ i = *s;
+
+ i = s in 1;
+ i = 1 in s;
+
+ s += 1;
+ s -= 1;
+ s *= 1;
+ s /= 1;
+ s %= 1;
+ s &= 1;
+ s |= 1;
+ s ^= 1;
+ s <<= 1;
+ s >>= 1;
+ s >>>= 1;
+ s ~= 1;
+
+ scope nd = new NoDeprecation;
+ assert((42 in nd) == 0);
+ assert((nd in 42) == 0);
+ assert((nd ~ 42) == 0);
+ assert((42 ~ nd) == 0);
+
+ ~nd;
+}
+
+/// See https://github.com/dlang/dmd/pull/10716
+class NoDeprecation
+{
+ int opIn(int i) { return 0; }
+ int opIn_r(int i) { return 0; }
+ int opCat(int i) { return 0; }
+ int opCat_r(int i) { return 0; }
+
+ /// This is considered because there is no `opUnary`
+ /// However, the other overloads (`opBinary` / `opBinaryRight`)
+ /// means that other operator overloads would not be considered.
+ int opCom() { return 0; }
+
+ int opBinary(string op)(int arg)
+ if (op == "in" || op == "~")
+ {
+ static if (op == "in")
+ return this.opIn(arg);
+ else static if (op == "~")
+ return this.opCat(arg);
+ }
+
+ int opBinaryRight(string op)(int arg)
+ if (op == "in" || op == "~")
+ {
+ static if (op == "in")
+ return this.opIn_r(arg);
+ else static if (op == "~")
+ return this.opCat_r(arg);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d b/gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d
new file mode 100644
index 0000000..a97afdc
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d
@@ -0,0 +1,9 @@
+// REQUIRED_ARGS: -de
+/*
+TEST_OUTPUT:
+---
+fail_compilation/dephexstrings.d(8): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"60"` instead.
+---
+*/
+enum xstr = x"60";
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/depmsg.d b/gcc/testsuite/gdc.test/fail_compilation/depmsg.d
index 186576a..b0c2b2e6a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/depmsg.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/depmsg.d
@@ -2,19 +2,19 @@
/*
TEST_OUTPUT:
---
-fail_compilation/depmsg.d(40): Deprecation: struct depmsg.main.Inner.A is deprecated - With message!
-fail_compilation/depmsg.d(40): Deprecation: struct depmsg.main.Inner.A is deprecated - With message!
-fail_compilation/depmsg.d(41): Deprecation: class depmsg.main.Inner.B is deprecated - With message!
-fail_compilation/depmsg.d(41): Deprecation: class depmsg.main.Inner.B is deprecated - With message!
-fail_compilation/depmsg.d(42): Deprecation: interface depmsg.main.Inner.C is deprecated - With message!
-fail_compilation/depmsg.d(42): Deprecation: interface depmsg.main.Inner.C is deprecated - With message!
-fail_compilation/depmsg.d(43): Deprecation: union depmsg.main.Inner.D is deprecated - With message!
-fail_compilation/depmsg.d(43): Deprecation: union depmsg.main.Inner.D is deprecated - With message!
-fail_compilation/depmsg.d(44): Deprecation: enum depmsg.main.Inner.E is deprecated - With message!
-fail_compilation/depmsg.d(44): Deprecation: enum depmsg.main.Inner.E is deprecated - With message!
-fail_compilation/depmsg.d(46): Deprecation: alias depmsg.main.Inner.G is deprecated - With message!
-fail_compilation/depmsg.d(47): Deprecation: variable depmsg.main.Inner.H is deprecated - With message!
-fail_compilation/depmsg.d(48): Deprecation: class depmsg.main.Inner.I!().I is deprecated - With message!
+fail_compilation/depmsg.d(40): Deprecation: struct `depmsg.main.Inner.A` is deprecated - With message!
+fail_compilation/depmsg.d(40): Deprecation: struct `depmsg.main.Inner.A` is deprecated - With message!
+fail_compilation/depmsg.d(41): Deprecation: class `depmsg.main.Inner.B` is deprecated - With message!
+fail_compilation/depmsg.d(41): Deprecation: class `depmsg.main.Inner.B` is deprecated - With message!
+fail_compilation/depmsg.d(42): Deprecation: interface `depmsg.main.Inner.C` is deprecated - With message!
+fail_compilation/depmsg.d(42): Deprecation: interface `depmsg.main.Inner.C` is deprecated - With message!
+fail_compilation/depmsg.d(43): Deprecation: union `depmsg.main.Inner.D` is deprecated - With message!
+fail_compilation/depmsg.d(43): Deprecation: union `depmsg.main.Inner.D` is deprecated - With message!
+fail_compilation/depmsg.d(44): Deprecation: enum `depmsg.main.Inner.E` is deprecated - With message!
+fail_compilation/depmsg.d(44): Deprecation: enum `depmsg.main.Inner.E` is deprecated - With message!
+fail_compilation/depmsg.d(46): Deprecation: alias `depmsg.main.Inner.G` is deprecated - With message!
+fail_compilation/depmsg.d(47): Deprecation: variable `depmsg.main.Inner.H` is deprecated - With message!
+fail_compilation/depmsg.d(48): Deprecation: class `depmsg.main.Inner.I()` is deprecated - With message!
---
*/
@@ -52,13 +52,13 @@ void main()
/*
TEST_OUTPUT:
---
-fail_compilation/depmsg.d(94): Deprecation: function depmsg.test12954.Foo.bar1 is deprecated - [C] Use Foo.bar42 instead
-fail_compilation/depmsg.d(95): Deprecation: function depmsg.test12954.Foo.bar2 is deprecated - [E] Use Foo.bar42 instead
-fail_compilation/depmsg.d(96): Deprecation: function depmsg.test12954.Foo.bar3 is deprecated - [S] Use Foo.bar42 instead
-fail_compilation/depmsg.d(97): Deprecation: function depmsg.test12954.Foo.bar4 is deprecated - [F] Use Foo.bar42 instead
-fail_compilation/depmsg.d(98): Deprecation: variable depmsg.test12954.Foo.v2 is deprecated - Forward reference
-fail_compilation/depmsg.d(105): Deprecation: class depmsg.test12954.Obsolete is deprecated
-fail_compilation/depmsg.d(105): Deprecation: function depmsg.test12954.Obsolete.obs is deprecated - Function is obsolete
+fail_compilation/depmsg.d(94): Deprecation: function `depmsg.test12954.Foo.bar1` is deprecated - [C] Use Foo.bar42 instead
+fail_compilation/depmsg.d(95): Deprecation: function `depmsg.test12954.Foo.bar2` is deprecated - [E] Use Foo.bar42 instead
+fail_compilation/depmsg.d(96): Deprecation: function `depmsg.test12954.Foo.bar3` is deprecated - [S] Use Foo.bar42 instead
+fail_compilation/depmsg.d(97): Deprecation: function `depmsg.test12954.Foo.bar4` is deprecated - [F] Use Foo.bar42 instead
+fail_compilation/depmsg.d(98): Deprecation: variable `depmsg.test12954.Foo.v2` is deprecated - Forward reference
+fail_compilation/depmsg.d(105): Deprecation: class `depmsg.test12954.Obsolete` is deprecated
+fail_compilation/depmsg.d(105): Deprecation: function `depmsg.test12954.Obsolete.obs` is deprecated - Function is obsolete
---
*/
void test12954()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/depmsg15814.d b/gcc/testsuite/gdc.test/fail_compilation/depmsg15814.d
index 1a2b9f8..613576c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/depmsg15814.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/depmsg15814.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/depmsg15814.d(9): Deprecation: function depmsg15814.get15814 is deprecated - bug15814
+fail_compilation/depmsg15814.d(9): Deprecation: function `depmsg15814.get15814` is deprecated - bug15814
---
*/
deprecated("bug15814") int get15814() { return 0; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/depmsg15815.d b/gcc/testsuite/gdc.test/fail_compilation/depmsg15815.d
index 72abbd7..0b19687 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/depmsg15815.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/depmsg15815.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/depmsg15815.d(23): Deprecation: alias depmsg15815.Alias!(const(Foo)).Alias is deprecated - message
+fail_compilation/depmsg15815.d(23): Deprecation: template `depmsg15815.Alias(T)` is deprecated - message
Foo
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecate1553.d b/gcc/testsuite/gdc.test/fail_compilation/deprecate1553.d
index 4a03a6f..18a7152 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/deprecate1553.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/deprecate1553.d
@@ -1,10 +1,9 @@
// REQUIRED_ARGS: -de
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/deprecate1553.d(19): Deprecation: cannot use foreach_reverse with a delegate
+fail_compilation/deprecate1553.d(18): Deprecation: cannot use `foreach_reverse` with a delegate
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecated6760.d b/gcc/testsuite/gdc.test/fail_compilation/deprecated6760.d
index 07b9527..8faa88b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/deprecated6760.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/deprecated6760.d
@@ -3,8 +3,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/deprecated6760.d(13): Deprecation: function deprecated6760.Foo.opEquals overridden functions cannot be annotated @disable
-fail_compilation/deprecated6760.d(18): Deprecation: function deprecated6760.Bar.opEquals deprecated functions cannot be annotated @disable
+fail_compilation/deprecated6760.d(13): Deprecation: `deprecated6760.Foo.opEquals` cannot be annotated with `@disable` because it is overriding a function in the base class
+fail_compilation/deprecated6760.d(18): Deprecation: `deprecated6760.Bar.opEquals` cannot be marked as `deprecated` because it is overriding a function in the base class
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecatedImports.d b/gcc/testsuite/gdc.test/fail_compilation/deprecatedImports.d
new file mode 100644
index 0000000..bd68a9d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/deprecatedImports.d
@@ -0,0 +1,31 @@
+/*
+REQUIRED_ARGS: -de
+EXTRA_FILES: imports/deprecatedImporta.d imports/deprecatedImportb.d
+
+TEST_OUTPUT:
+----
+fail_compilation/deprecatedImports.d(19): Deprecation: alias `deprecatedImporta.foo` is deprecated - Please import deprecatedImportb directly!
+fail_compilation/deprecatedImports.d(21): Deprecation: alias `deprecatedImporta.bar` is deprecated - Please import deprecatedImportb directly!
+fail_compilation/deprecatedImports.d(23): Deprecation: alias `deprecatedImporta.AliasSeq` is deprecated - Please import deprecatedImportb directly!
+fail_compilation/deprecatedImports.d(27): Deprecation: alias `deprecatedImporta.S` is deprecated - Please import deprecatedImportb directly!
+fail_compilation/deprecatedImports.d(29): Deprecation: alias `deprecatedImporta.C` is deprecated - Please import deprecatedImportb directly!
+fail_compilation/deprecatedImports.d(31): Deprecation: alias `deprecatedImporta.I` is deprecated - Please import deprecatedImportb directly!
+fail_compilation/deprecatedImports.d(25): Deprecation: alias `deprecatedImporta.E` is deprecated - Please import deprecatedImportb directly!
+----
+*/
+
+import imports.deprecatedImporta;
+
+alias f = foo;
+
+alias b = bar!(int);
+
+alias Types = AliasSeq!(int);
+
+int x = E;
+
+S s;
+
+C c;
+
+I i;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecatedTemplates.d b/gcc/testsuite/gdc.test/fail_compilation/deprecatedTemplates.d
new file mode 100644
index 0000000..d905479
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/deprecatedTemplates.d
@@ -0,0 +1,63 @@
+/*
+REQUIRED_ARGS: -de
+
+TEST_OUTPUT:
+----
+fail_compilation/deprecatedTemplates.d(103): Deprecation: template `deprecatedTemplates.AliasSeq(V...)` is deprecated
+fail_compilation/deprecatedTemplates.d(107): Deprecation: struct `deprecatedTemplates.S1(V...)` is deprecated
+fail_compilation/deprecatedTemplates.d(115): Deprecation: template `deprecatedTemplates.C(V...)` is deprecated
+----
+*/
+#line 100
+
+deprecated alias AliasSeq(V...) = V;
+
+alias x = AliasSeq!(1, 2, 3);
+
+deprecated struct S1(V...) {}
+
+alias T1 = S1!();
+
+deprecated template C(V...)
+{
+ int i;
+ int j;
+}
+
+alias D = C!();
+
+/*
+TEST_OUTPUT:
+----
+fail_compilation/deprecatedTemplates.d(202): Deprecation: template `deprecatedTemplates.AliasSeqMsg(V...)` is deprecated - Reason
+----
+*/
+#line 200
+deprecated("Reason") alias AliasSeqMsg(V...) = V;
+
+alias xMsg = AliasSeqMsg!(1, 2, 3);
+
+deprecated struct DS()
+{
+ S1!() s;
+}
+
+deprecated struct DS2()
+{
+ static struct DS3()
+ {
+ S1!() s;
+ }
+
+ static struct DS4
+ {
+ S1!() s;
+ }
+}
+
+deprecated void foo()
+{
+ DS!() d1;
+ DS2!().DS3!() d2;
+ DS2!().DS4 d3;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d b/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d
new file mode 100644
index 0000000..5aaab6a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d
@@ -0,0 +1,30 @@
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/deprecateopdot.d(27): Deprecation: `opDot` is deprecated. Use `alias this`
+fail_compilation/deprecateopdot.d(28): Deprecation: `opDot` is deprecated. Use `alias this`
+fail_compilation/deprecateopdot.d(29): Deprecation: `opDot` is deprecated. Use `alias this`
+---
+*/
+struct S6
+{
+ int a, b;
+}
+struct T6
+{
+ S6 s;
+
+ S6* opDot() return
+ {
+ return &s;
+ }
+}
+
+void test6()
+{
+ T6 t;
+ t.a = 4;
+ assert(t.a == 4);
+ t.b = 5;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecations.d b/gcc/testsuite/gdc.test/fail_compilation/deprecations.d
new file mode 100644
index 0000000..19adab7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/deprecations.d
@@ -0,0 +1,66 @@
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/deprecations.d(43): Deprecation: struct `deprecations.S` is deprecated
+fail_compilation/deprecations.d(64): instantiated from here: `otherPar!()`
+fail_compilation/deprecations.d(55): Deprecation: struct `deprecations.S` is deprecated
+fail_compilation/deprecations.d(65): instantiated from here: `otherVar!()`
+fail_compilation/deprecations.d(55): Deprecation: struct `deprecations.S` is deprecated
+fail_compilation/deprecations.d(65): instantiated from here: `otherVar!()`
+---
+
+https://issues.dlang.org/show_bug.cgi?id=20474
+*/
+
+deprecated struct S {}
+
+deprecated void foo()(S par) if (is(S == S))
+{
+ S var;
+}
+
+deprecated template bar() if (is(S == S))
+{
+ void bar(S par)
+ {
+ S var;
+ }
+}
+
+deprecated void foobar (T) (T par) if (is(T == S))
+{
+ T inst;
+}
+
+template otherPar()
+{
+ deprecated void otherPar(S par)
+ {
+ S var;
+ }
+
+ void par(S par) {}
+}
+
+template otherVar()
+{
+ deprecated void otherVar(S par)
+ {
+ S var;
+ }
+
+ void var()
+ {
+ S var;
+ }
+}
+
+deprecated void main()
+{
+ foo(S.init);
+ bar(S.init);
+ foobar(S.init);
+ otherPar(S.init);
+ otherVar(S.init);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10089.d b/gcc/testsuite/gdc.test/fail_compilation/diag10089.d
index be0fddc..d79a49e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10089.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10089.d
@@ -1,8 +1,9 @@
/*
+EXTRA_FILES: imports/diag10089a.d imports/diag10089b.d
TEST_OUTPUT:
---
-fail_compilation/diag10089.d(15): Error: undefined identifier `chunks` in package `imports`
-fail_compilation/diag10089.d(17): Error: template Foo() does not have property 'chunks'
+fail_compilation/diag10089.d(16): Error: undefined identifier `chunks` in package `imports`
+fail_compilation/diag10089.d(18): Error: template `Foo()` does not have property `chunks`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10099.d b/gcc/testsuite/gdc.test/fail_compilation/diag10099.d
index a26ca85..cf1b645 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10099.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10099.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10099.d(15): Error: variable diag10099.main.s default construction is disabled for type S
+fail_compilation/diag10099.d(15): Error: variable `diag10099.main.s` default construction is disabled for type `S`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10141.d b/gcc/testsuite/gdc.test/fail_compilation/diag10141.d
index e9ca913..a2ea073 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10141.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10141.d
@@ -1,7 +1,8 @@
/*
+EXTRA_FILES: imports/diag10141a.d imports/diag10141b.d
TEST_OUTPUT:
---
-fail_compilation/diag10141.d(9): Error: module imports.diag10141a import 'unexisting_symbol' not found
+fail_compilation/diag10141.d(10): Error: module `imports.diag10141a` import `unexisting_symbol` not found
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10169.d b/gcc/testsuite/gdc.test/fail_compilation/diag10169.d
index 3c35b66..72becf2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10169.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10169.d
@@ -1,7 +1,8 @@
/*
+EXTRA_FILES: imports/a10169.d
TEST_OUTPUT:
---
-fail_compilation/diag10169.d(11): Error: no property `x` for type `B`, did you mean `imports.a10169.B.x`?
+fail_compilation/diag10169.d(12): Error: no property `x` for type `imports.a10169.B`
---
*/
import imports.a10169;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d
index a11e120..4a01c54 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d
@@ -1,13 +1,15 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10319.d(25): Error: pure function 'D main' cannot call impure function 'diag10319.foo'
-fail_compilation/diag10319.d(25): Error: @safe function 'D main' cannot call @system function 'diag10319.foo'
-fail_compilation/diag10319.d(26): Error: pure function 'D main' cannot call impure function 'diag10319.bar!int.bar'
-fail_compilation/diag10319.d(26): Error: @safe function 'D main' cannot call @system function 'diag10319.bar!int.bar'
-fail_compilation/diag10319.d(25): Error: function `diag10319.foo` is not nothrow
-fail_compilation/diag10319.d(26): Error: function `diag10319.bar!int.bar` is not nothrow
-fail_compilation/diag10319.d(23): Error: nothrow function `D main` may throw
+fail_compilation/diag10319.d(27): Error: `pure` function `D main` cannot call impure function `diag10319.foo`
+fail_compilation/diag10319.d(27): Error: `@safe` function `D main` cannot call `@system` function `diag10319.foo`
+fail_compilation/diag10319.d(16): `diag10319.foo` is declared here
+fail_compilation/diag10319.d(28): Error: `pure` function `D main` cannot call impure function `diag10319.bar!int.bar`
+fail_compilation/diag10319.d(28): Error: `@safe` function `D main` cannot call `@system` function `diag10319.bar!int.bar`
+fail_compilation/diag10319.d(18): `diag10319.bar!int.bar` is declared here
+fail_compilation/diag10319.d(27): Error: function `diag10319.foo` is not `nothrow`
+fail_compilation/diag10319.d(28): Error: function `diag10319.bar!int.bar` is not `nothrow`
+fail_compilation/diag10319.d(25): Error: `nothrow` function `D main` may throw
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10405.d b/gcc/testsuite/gdc.test/fail_compilation/diag10405.d
index c80c821..28da8af 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10405.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10405.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10405.d(10): Error: cannot return non-void from void function
+fail_compilation/diag10405.d(10): Error: cannot return non-void from `void` function
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10415.d b/gcc/testsuite/gdc.test/fail_compilation/diag10415.d
index a92b7a4..1fde171 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10415.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10415.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10415.d(36): Error: none of the overloads of 'x' are callable using argument types (int) const, candidates are:
-fail_compilation/diag10415.d(13): diag10415.C.x()
-fail_compilation/diag10415.d(18): diag10415.C.x(int _param_0)
+fail_compilation/diag10415.d(36): Error: none of the overloads of `x` are callable using argument types `(int) const`
+fail_compilation/diag10415.d(13): Candidates are: `diag10415.C.x()`
+fail_compilation/diag10415.d(18): `diag10415.C.x(int _param_0)`
fail_compilation/diag10415.d(39): Error: d.x is not an lvalue
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10688.d b/gcc/testsuite/gdc.test/fail_compilation/diag10688.d
index 70db7f9..f7d7479 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10688.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10688.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10688.d(12): Error: function diag10688.Bar.foo private method is not virtual and cannot override
-fail_compilation/diag10688.d(14): Error: function diag10688.Bar.bar package method is not virtual and cannot override
+fail_compilation/diag10688.d(12): Error: function `diag10688.Bar.foo` `private` method is not virtual and cannot override
+fail_compilation/diag10688.d(14): Error: function `diag10688.Bar.bar` `package` method is not virtual and cannot override
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10768.d b/gcc/testsuite/gdc.test/fail_compilation/diag10768.d
index 03b18a1..bea52ea 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10768.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10768.d
@@ -1,15 +1,14 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/diag10768.d(36): Error: cannot implicitly override base class method diag10768.Frop.frop with diag10768.Foo.frop; add 'override' attribute
+fail_compilation/diag10768.d(35): Error: cannot implicitly override base class method `diag10768.Frop.frop` with `diag10768.Foo.frop`; add `override` attribute
---
*/
struct CirBuff(T)
{
- import std.traits: isArray;
- CirBuff!T opAssign(R)(R) if (isArray!R)
+
+ CirBuff!T opAssign(R)(R)
{}
T[] toArray()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10783.d b/gcc/testsuite/gdc.test/fail_compilation/diag10783.d
index d74a66d..f18341f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10783.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10783.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10783.d(14): Error: no property 'type' for type 'Event'
+fail_compilation/diag10783.d(14): Error: no property `type` for type `diag10783.Event`
fail_compilation/diag10783.d(14): Error: undefined identifier `En`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10792.d b/gcc/testsuite/gdc.test/fail_compilation/diag10792.d
index d54e50f..3c514dd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10792.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10792.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10792.d(9): Error: semicolon expected following auto declaration, not `EOF`
+fail_compilation/diag10792.d(9): Error: semicolon expected following auto declaration, not `End of File`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10805.d b/gcc/testsuite/gdc.test/fail_compilation/diag10805.d
index 627fe82..3b5df6e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10805.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10805.d
@@ -1,10 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10805.d(11): Error: delimited string must end in FOO"
-fail_compilation/diag10805.d(13): Error: unterminated string constant starting at fail_compilation/diag10805.d(13)
-fail_compilation/diag10805.d(13): Deprecation: Implicit string concatenation is deprecated, use "" ~ "" instead
-fail_compilation/diag10805.d(14): Error: semicolon expected following auto declaration, not `EOF`
+fail_compilation/diag10805.d(12): Error: delimited string must end in FOO"
+fail_compilation/diag10805.d(14): Error: unterminated string constant starting at fail_compilation/diag10805.d(14)
+fail_compilation/diag10805.d(14): Error: Implicit string concatenation is error-prone and disallowed in D
+fail_compilation/diag10805.d(14): Use the explicit syntax instead (concatenating literals is `@nogc`): "" ~ ""
+fail_compilation/diag10805.d(15): Error: semicolon expected following auto declaration, not `End of File`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10862.d b/gcc/testsuite/gdc.test/fail_compilation/diag10862.d
index 62968f2..00949f1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10862.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10862.d
@@ -1,24 +1,36 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10862.d(28): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d(29): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d(30): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d(31): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d(32): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d(34): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d(35): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d(36): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d(37): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d(39): Error: assignment cannot be used as a condition, perhaps `==` was meant?
fail_compilation/diag10862.d(40): Error: assignment cannot be used as a condition, perhaps `==` was meant?
fail_compilation/diag10862.d(41): Error: assignment cannot be used as a condition, perhaps `==` was meant?
fail_compilation/diag10862.d(42): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d(43): Error: assignment cannot be used as a condition, perhaps `==` was meant?
fail_compilation/diag10862.d(44): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d(45): Error: assignment cannot be used as a condition, perhaps `==` was meant?
fail_compilation/diag10862.d(46): Error: assignment cannot be used as a condition, perhaps `==` was meant?
fail_compilation/diag10862.d(47): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d(49): Error: undefined identifier `semanticError`
+fail_compilation/diag10862.d(48): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d(49): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d(51): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d(52): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d(53): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d(54): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d(56): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d(57): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d(58): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d(59): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d(61): Error: undefined identifier `semanticError`
+fail_compilation/diag10862.d(71): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d(74): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d-mixin-77(77): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d-mixin-78(78): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d-mixin-79(79): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d-mixin-80(80): Error: Using the result of a comma expression is not allowed
+fail_compilation/diag10862.d-mixin-80(80): Error: assignment cannot be used as a condition, perhaps `==` was meant?
+fail_compilation/diag10862.d-mixin-83(83): Error: `a + b` is not an lvalue and cannot be modified
+fail_compilation/diag10862.d-mixin-84(84): Error: undefined identifier `c`
+fail_compilation/diag10862.d(86): Error: undefined identifier `semanticError`
+fail_compilation/diag10862.d(93): Error: lazy variable `bar` cannot be modified
+fail_compilation/diag10862.d(95): Error: template instance `diag10862.test3.foo!int` error instantiating
---
*/
void test1()
@@ -28,42 +40,27 @@ void test1()
if (a = b) {}
if ((a = b) = 0) {}
if ((a = b) = (a = b)) {}
- if (a = 0, b = 0) {} // Bugzilla 15384
+ if (a = 0, b = 0) {} // https://issues.dlang.org/show_bug.cgi?id=15384
if (auto x = a = b) {} // this is error, today
while (a = b) {}
while ((a = b) = 0) {}
while ((a = b) = (a = b)) {}
- while (a = 0, b = 0) {} // Bugzilla 15384
+ while (a = 0, b = 0) {} // https://issues.dlang.org/show_bug.cgi?id=15384
do {} while (a = b);
do {} while ((a = b) = 0);
do {} while ((a = b) = (a = b));
- do {} while (a = 0, b = 0); // Bugzilla 15384
+ do {} while (a = 0, b = 0); // https://issues.dlang.org/show_bug.cgi?id=15384
for (; a = b; ) {}
for (; (a = b) = 0; ) {}
for (; (a = b) = (a = b); ) {}
- for (; a = 0, b = 0; ) {} // Bugzilla 15384
+ for (; a = 0, b = 0; ) {} // https://issues.dlang.org/show_bug.cgi?id=15384
semanticError;
}
-/*
-TEST_OUTPUT:
----
-fail_compilation/diag10862.d(74): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d(77): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d-mixin-80(80): Error: assignment cannot be used as a condition, perhaps == was meant?
-fail_compilation/diag10862.d-mixin-81(81): Error: assignment cannot be used as a condition, perhaps == was meant?
-fail_compilation/diag10862.d-mixin-82(82): Error: assignment cannot be used as a condition, perhaps == was meant?
-fail_compilation/diag10862.d-mixin-83(83): Deprecation: Using the result of a comma expression is deprecated
-fail_compilation/diag10862.d-mixin-83(83): Error: assignment cannot be used as a condition, perhaps == was meant?
-fail_compilation/diag10862.d-mixin-86(86): Error: a + b is not an lvalue
-fail_compilation/diag10862.d-mixin-87(87): Error: undefined identifier `c`
-fail_compilation/diag10862.d(89): Error: undefined identifier `semanticError`
----
-*/
void test2()
{
int a, b;
@@ -88,3 +85,12 @@ void test2()
semanticError;
}
+
+void test3()
+{
+ void foo(T)(lazy T bar)
+ {
+ bar = 2;
+ }
+ foo(1 + 1);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10926.d b/gcc/testsuite/gdc.test/fail_compilation/diag10926.d
index bd590ba..f98a5b2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10926.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10926.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10926.d(11): Error: cast(const(int)[])c is not an lvalue
+fail_compilation/diag10926.d(11): Error: `cast(const(int)[])c` is not an lvalue and cannot be modified
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10984.d b/gcc/testsuite/gdc.test/fail_compilation/diag10984.d
index 33e0eaf..c3d835c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10984.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10984.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag10984.d(11): Error: static function diag10984.f.n cannot access frame of function diag10984.f
+fail_compilation/diag10984.d(12): Error: `static` function `diag10984.f.n` cannot access variable `x` in frame of function `diag10984.f`
+fail_compilation/diag10984.d(11): `x` declared here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11078.d b/gcc/testsuite/gdc.test/fail_compilation/diag11078.d
index 7507875..334ce16 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag11078.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag11078.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag11078.d(19): Error: none of the overloads of 'value' are callable using argument types (double), candidates are:
-fail_compilation/diag11078.d(12): diag11078.S1.value()
-fail_compilation/diag11078.d(13): diag11078.S1.value(int n)
+fail_compilation/diag11078.d(19): Error: none of the overloads of `value` are callable using argument types `(double)`
+fail_compilation/diag11078.d(12): Candidates are: `diag11078.S1.value()`
+fail_compilation/diag11078.d(13): `diag11078.S1.value(int n)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11132.d b/gcc/testsuite/gdc.test/fail_compilation/diag11132.d
index 74062c2..64db64d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag11132.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag11132.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag11132.d(22): Error: overlapping initialization for field a and b
+fail_compilation/diag11132.d(22): Error: overlapping initialization for field `a` and `b`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11425.d b/gcc/testsuite/gdc.test/fail_compilation/diag11425.d
index 16c99cc..f8edc5c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag11425.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag11425.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag11425.d(13): Error: variable x is shadowing variable diag11425.main.x
+fail_compilation/diag11425.d(13): Error: variable `x` is shadowing variable `diag11425.main.x`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11727.d b/gcc/testsuite/gdc.test/fail_compilation/diag11727.d
index 907c9bb..44cd65a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag11727.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag11727.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag11727.d(10): Error: type n is not an expression
+fail_compilation/diag11727.d(10): Error: type `n` is not an expression
---
*/
auto returnEnum()
@@ -17,7 +17,7 @@ void main()
/*
TEST_OUTPUT:
---
-fail_compilation/diag11727.d(26): Error: type void is not an expression
+fail_compilation/diag11727.d(26): Error: type `void` is not an expression
---
*/
auto returnVoid()
@@ -29,7 +29,7 @@ auto returnVoid()
/*
TEST_OUTPUT:
---
-fail_compilation/diag11727.d(38): Error: template t() has no type
+fail_compilation/diag11727.d(38): Error: template `t()` has no type
---
*/
auto returnTemplate()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11756.d b/gcc/testsuite/gdc.test/fail_compilation/diag11756.d
index 3d56b99..3a07247 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag11756.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag11756.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag11756.d(15): Error: cannot read uninitialized variable cnt in CTFE
-fail_compilation/diag11756.d(34): called from here: foo.ptr2.opAssign(Ptr(& n))
-fail_compilation/diag11756.d(39): called from here: test()
+fail_compilation/diag11756.d(15): Error: cannot read uninitialized variable `cnt` in CTFE
+fail_compilation/diag11756.d(34): called from here: `foo.ptr2.opAssign(Ptr(& n))`
+fail_compilation/diag11756.d(39): called from here: `test()`
fail_compilation/diag11756.d(39): while evaluating: `static assert(test())`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11769.d b/gcc/testsuite/gdc.test/fail_compilation/diag11769.d
index bfe4e1b..2717de4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag11769.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag11769.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag11769.d(18): Error: diag11769.foo!string.bar called with argument types (string) matches both:
-fail_compilation/diag11769.d(13): diag11769.foo!string.bar(wstring _param_0)
+fail_compilation/diag11769.d(18): Error: `diag11769.foo!string.bar` called with argument types `(string)` matches both:
+fail_compilation/diag11769.d(13): `diag11769.foo!string.bar(wstring _param_0)`
and:
-fail_compilation/diag11769.d(14): diag11769.foo!string.bar(dstring _param_0)
+fail_compilation/diag11769.d(14): `diag11769.foo!string.bar(dstring _param_0)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12063.d b/gcc/testsuite/gdc.test/fail_compilation/diag12063.d
index e029810..882a809 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag12063.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag12063.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag12063.d(11): Error: no property 'max' for type 'Foo'
-fail_compilation/diag12063.d(14): Error: incompatible types for ((Foo()) + (1)): 'Bar' and 'int'
+fail_compilation/diag12063.d(11): Error: no property `max` for type `Foo`, perhaps `import std.algorithm;` is needed?
+fail_compilation/diag12063.d(14): Error: incompatible types for `(Foo()) + (1)`: `Bar` and `int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12124.d b/gcc/testsuite/gdc.test/fail_compilation/diag12124.d
index 320cfb2..f9f165f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag12124.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag12124.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag12124.d(14): Error: struct diag12124.S1 static opCall is hidden by constructors and can never be called
-fail_compilation/diag12124.d(14): Please use a factory method instead, or replace all constructors with static opCall.
-fail_compilation/diag12124.d(20): Error: struct diag12124.S2 static opCall is hidden by constructors and can never be called
-fail_compilation/diag12124.d(20): Please use a factory method instead, or replace all constructors with static opCall.
+fail_compilation/diag12124.d(14): Error: struct `diag12124.S1` `static opCall` is hidden by constructors and can never be called
+fail_compilation/diag12124.d(14): Please use a factory method instead, or replace all constructors with `static opCall`.
+fail_compilation/diag12124.d(20): Error: struct `diag12124.S2` `static opCall` is hidden by constructors and can never be called
+fail_compilation/diag12124.d(20): Please use a factory method instead, or replace all constructors with `static opCall`.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12280.d b/gcc/testsuite/gdc.test/fail_compilation/diag12280.d
index f125ff3..8fba615 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag12280.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag12280.d
@@ -2,8 +2,8 @@
TEST_OUTPUT:
---
fail_compilation/diag12280.d(15): Error: undefined identifier `nonexistent`
-fail_compilation/diag12280.d(13): Error: template instance diag12280.f!10 error instantiating
-fail_compilation/diag12280.d(18): 11 recursive instantiations from here: f!0
+fail_compilation/diag12280.d(13): Error: template instance `diag12280.f!10` error instantiating
+fail_compilation/diag12280.d(18): 11 recursive instantiations from here: `f!0`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12312.d b/gcc/testsuite/gdc.test/fail_compilation/diag12312.d
index 7120a8f..e015cfe 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag12312.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag12312.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag12312.d(10): Error: variable diag12312.main.arr void[16] does not have a default initializer
+fail_compilation/diag12312.d(10): Error: variable `diag12312.main.arr` `void[16]` does not have a default initializer
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12380.d b/gcc/testsuite/gdc.test/fail_compilation/diag12380.d
index f6434f0..7f59f27 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag12380.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag12380.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag12380.d(12): Error: cannot implicitly convert expression `cast(E)0` of type `E` to `void*`
+fail_compilation/diag12380.d(12): Error: cannot implicitly convert expression `E.a` of type `E` to `void*`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12480.d b/gcc/testsuite/gdc.test/fail_compilation/diag12480.d
index 1989874..01c2e4e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag12480.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag12480.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag12480.d(12): Error: static assert `2u == 3u` is false
+fail_compilation/diag12480.d(12): Error: static assert: `2u == 3u` is false
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12487.d b/gcc/testsuite/gdc.test/fail_compilation/diag12487.d
index b919323..8ea103e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag12487.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag12487.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag12487.d(15): Error: recursive expansion of template instance 'diag12487.recTemplate!int'
-fail_compilation/diag12487.d(25): Error: template instance diag12487.recTemplate!int error instantiating
-fail_compilation/diag12487.d(18): Error: function diag12487.recFunction CTFE recursion limit exceeded
-fail_compilation/diag12487.d(20): called from here: recFunction(i)
-fail_compilation/diag12487.d(18): 1000 recursive calls to function recFunction
-fail_compilation/diag12487.d(27): called from here: recFunction(0)
+fail_compilation/diag12487.d(15): Error: recursive expansion of template instance `diag12487.recTemplate!int`
+fail_compilation/diag12487.d(25): Error: template instance `diag12487.recTemplate!int` error instantiating
+fail_compilation/diag12487.d(18): Error: function `diag12487.recFunction` CTFE recursion limit exceeded
+fail_compilation/diag12487.d(20): called from here: `recFunction(i)`
+fail_compilation/diag12487.d(18): 1000 recursive calls to function `recFunction`
+fail_compilation/diag12487.d(27): called from here: `recFunction(0)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12678.d b/gcc/testsuite/gdc.test/fail_compilation/diag12678.d
index afe56fb..8b17968 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag12678.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag12678.d
@@ -1,9 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag12678.d(19): Error: const field 'cf1' initialized multiple times
-fail_compilation/diag12678.d(22): Error: immutable field 'if1' initialized multiple times
-fail_compilation/diag12678.d(25): Error: const field 'cf2' initialization is not allowed in loops or after labels
+fail_compilation/diag12678.d(21): Error: const field `cf1` initialized multiple times
+fail_compilation/diag12678.d(20): Previous initialization is here.
+fail_compilation/diag12678.d(24): Error: immutable field `if1` initialized multiple times
+fail_compilation/diag12678.d(23): Previous initialization is here.
+fail_compilation/diag12678.d(27): Error: const field `cf2` initialization is not allowed in loops or after labels
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12777.d b/gcc/testsuite/gdc.test/fail_compilation/diag12777.d
index 1eefd29..dd4321b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag12777.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag12777.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag12777.d(14): Error: cannot modify this.v in const function
-fail_compilation/diag12777.d(15): Error: cannot modify this.v in immutable function
-fail_compilation/diag12777.d(21): Error: cannot modify this.v in const function
-fail_compilation/diag12777.d(22): Error: cannot modify this.v in immutable function
+fail_compilation/diag12777.d(14): Error: cannot modify `this.v` in `const` function
+fail_compilation/diag12777.d(15): Error: cannot modify `this.v` in `immutable` function
+fail_compilation/diag12777.d(21): Error: cannot modify `this.v` in `const` function
+fail_compilation/diag12777.d(22): Error: cannot modify `this.v` in `immutable` function
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12829.d b/gcc/testsuite/gdc.test/fail_compilation/diag12829.d
index dcaa9f0..f6e764b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag12829.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag12829.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag12829.d(12): Error: function diag12829.test1 is @nogc yet allocates closures with the GC
-fail_compilation/diag12829.d(15): diag12829.test1.__lambda1 closes over variable x at fail_compilation/diag12829.d(14)
+fail_compilation/diag12829.d(12): Error: function `diag12829.test1` is `@nogc` yet allocates closures with the GC
+fail_compilation/diag12829.d(15): diag12829.test1.__lambda2 closes over variable x at fail_compilation/diag12829.d(14)
fail_compilation/diag12829.d(19): diag12829.test1.bar closes over variable x at fail_compilation/diag12829.d(14)
-fail_compilation/diag12829.d(26): Error: function diag12829.test2 is @nogc yet allocates closures with the GC
+fail_compilation/diag12829.d(26): Error: function `diag12829.test2` is `@nogc` yet allocates closures with the GC
fail_compilation/diag12829.d(31): diag12829.test2.S.foo closes over variable x at fail_compilation/diag12829.d(28)
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13028.d b/gcc/testsuite/gdc.test/fail_compilation/diag13028.d
index d26cb94..6ef11aa 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag13028.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag13028.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag13028.d(15): Error: variable dg cannot be read at compile time
-fail_compilation/diag13028.d(22): Error: variable a cannot be read at compile time
-fail_compilation/diag13028.d(28): Error: CTFE failed because of previous errors in foo
-fail_compilation/diag13028.d(28): while evaluating: `static assert(foo(() => 1) == 1)`
-fail_compilation/diag13028.d(29): Error: CTFE failed because of previous errors in bar
-fail_compilation/diag13028.d(29): while evaluating: `static assert(bar(delegate int() => 1) == 1)`
+fail_compilation/diag13028.d(15): Error: variable `dg` cannot be read at compile time
+fail_compilation/diag13028.d(22): Error: variable `a` cannot be read at compile time
+fail_compilation/diag13028.d(28): Error: CTFE failed because of previous errors in `foo`
+fail_compilation/diag13028.d(28): while evaluating: `static assert(foo(() pure nothrow @nogc @safe => 1) == 1)`
+fail_compilation/diag13028.d(29): Error: CTFE failed because of previous errors in `bar`
+fail_compilation/diag13028.d(29): while evaluating: `static assert(bar(delegate int() pure nothrow @nogc @safe => 1) == 1)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13215.d b/gcc/testsuite/gdc.test/fail_compilation/diag13215.d
new file mode 100644
index 0000000..3ae50c9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag13215.d
@@ -0,0 +1,12 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag13215.d(11): Error: cannot implicitly convert expression `[1, 2, 3]` of type `int[]` to `immutable(uint[2])[]`
+---
+*/
+
+enum uint N = 10;
+immutable uint[2][3] arr2;
+shared static this() {
+ arr2 = [1, 2, 3];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13320.d b/gcc/testsuite/gdc.test/fail_compilation/diag13320.d
index 46a0032..2808606 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag13320.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag13320.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag13320.d(13): Error: 'f += 1' is not a scalar, it is a Foo
+fail_compilation/diag13320.d(13): Error: `f` is not a scalar, it is a `Foo`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13333.d b/gcc/testsuite/gdc.test/fail_compilation/diag13333.d
index f318a31..34eeaeb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag13333.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag13333.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT*
---
-fail_compilation/diag13333.d(29): Error: template instance VariantN!(maxSize!(S), T) recursive template expansion
-fail_compilation/diag13333.d(29): Error: template instance diag13333.maxSize!(S) error instantiating
-fail_compilation/diag13333.d(34): instantiated from here: Algebraic!(S)
+fail_compilation/diag13333.d(29): Error: template instance `VariantN!(maxSize!(S), T)` recursive template expansion
+fail_compilation/diag13333.d(29): Error: template instance `diag13333.maxSize!(S)` error instantiating
+fail_compilation/diag13333.d(34): instantiated from here: `Algebraic!(S)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13528.d b/gcc/testsuite/gdc.test/fail_compilation/diag13528.d
index 493cbc7..5d908f7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag13528.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag13528.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag13528.d(13): Error: value of 'this' is not known at compile time
-fail_compilation/diag13528.d(13): while evaluating pragma(msg, __traits(getMember, A, "foo"))
+fail_compilation/diag13528.d(13): Error: value of `this` is not known at compile time
+fail_compilation/diag13528.d(13): while evaluating `pragma(msg, __traits(getMember, A, "foo"))`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13609b.d b/gcc/testsuite/gdc.test/fail_compilation/diag13609b.d
index dccb9c7..86690fc 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag13609b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag13609b.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/diag13609b.d(10): Error: base classes are not allowed for `struct`, did you mean `;`?
-fail_compilation/diag13609b.d(11): Error: basic type expected, not `EOF`
+fail_compilation/diag13609b.d(11): Error: basic type expected, not `End of File`
fail_compilation/diag13609b.d(11): Error: { } expected following `struct` declaration
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13787.d b/gcc/testsuite/gdc.test/fail_compilation/diag13787.d
index 99162ed..3a3a2c9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag13787.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag13787.d
@@ -2,8 +2,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag13787.d(12): Error: cannot slice function pointer & main
-fail_compilation/diag13787.d(13): Error: cannot index function pointer & main
+fail_compilation/diag13787.d(12): Error: cannot slice function pointer `& main`
+fail_compilation/diag13787.d(13): Error: cannot index function pointer `& main`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13884.d b/gcc/testsuite/gdc.test/fail_compilation/diag13884.d
index 71909e28..fe47c83 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag13884.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag13884.d
@@ -2,8 +2,8 @@
TEST_OUTPUT:
---
fail_compilation/diag13884.d(14): Error: functions cannot return a tuple
-fail_compilation/diag13884.d(21): instantiated from here: MapResult!((t) => t.tupleof, Foo[])
-fail_compilation/diag13884.d(14): instantiated from here: map!(Foo[])
+fail_compilation/diag13884.d(21): instantiated from here: `MapResult!((t) => t.tupleof, Foo[])`
+fail_compilation/diag13884.d(14): instantiated from here: `map!(Foo[])`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13942.d b/gcc/testsuite/gdc.test/fail_compilation/diag13942.d
index 9abea3c..992d5b8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag13942.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag13942.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag13942.d(18): Error: template instance isRawStaticArray!() does not match template declaration isRawStaticArray(T, A...)
-fail_compilation/diag13942.d(26): Error: template diag13942.to!double.to cannot deduce function from argument types !()(), candidates are:
-fail_compilation/diag13942.d(17): diag13942.to!double.to(A...)(A args) if (!isRawStaticArray!A)
+fail_compilation/diag13942.d(18): Error: template instance `isRawStaticArray!()` does not match template declaration `isRawStaticArray(T, A...)`
+fail_compilation/diag13942.d(26): Error: template `diag13942.to!double.to` cannot deduce function from argument types `!()()`
+fail_compilation/diag13942.d(17): Candidate is: `to(A...)(A args)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14102.d b/gcc/testsuite/gdc.test/fail_compilation/diag14102.d
index c142b97..e93d40b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag14102.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag14102.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag14102.d(14): Error: -x is not an lvalue
-fail_compilation/diag14102.d(15): Error: -(x -= 1) is not an lvalue
-fail_compilation/diag14102.d(16): Error: -(x -= 1 -= 1) is not an lvalue
-fail_compilation/diag14102.d(17): Error: -(x -= 1 -= 1 -= 1) is not an lvalue
+fail_compilation/diag14102.d(14): Error: `-x` is not an lvalue and cannot be modified
+fail_compilation/diag14102.d(15): Error: `-(x -= 1)` is not an lvalue and cannot be modified
+fail_compilation/diag14102.d(16): Error: `-(x -= 1 -= 1)` is not an lvalue and cannot be modified
+fail_compilation/diag14102.d(17): Error: `-(x -= 1 -= 1 -= 1)` is not an lvalue and cannot be modified
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14145.d b/gcc/testsuite/gdc.test/fail_compilation/diag14145.d
new file mode 100644
index 0000000..d292f76
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag14145.d
@@ -0,0 +1,38 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag14145.d(15): Error: no property `i` for type `diag14145.main.Capture!(i)`
+fail_compilation/diag14145.d(15): potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message
+fail_compilation/diag14145.d(34): Error: expression `*this.ptr` of type `shared(int)` is not implicitly convertible to return type `ref int`
+fail_compilation/diag14145.d(16): Error: template instance `diag14145.main.Capture!(i).Capture.opDispatch!"i"` error instantiating
+---
+*/
+
+int main()
+{
+ int i;
+ auto _ = capture!i;
+ _.i;
+ _.opDispatch!"i";
+ return 0;
+}
+
+auto capture(alias c)()
+{
+ return Capture!c(c);
+}
+
+struct Capture(alias c)
+{
+ shared typeof(c)* ptr;
+ this(ref typeof(c) _c)
+ {
+ ptr = cast(shared)&c;
+ }
+ ref shared typeof(c) opDispatch(string s)()
+ {
+ return *ptr;
+ }
+}
+
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14163.d b/gcc/testsuite/gdc.test/fail_compilation/diag14163.d
index 8fe6343..eaafc07 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag14163.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag14163.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag14163.d(16): Error: constructor diag14163.Bar.this cannot call super() implicitly because it is annotated with @disable
+fail_compilation/diag14163.d(16): Error: constructor `diag14163.Bar.this` cannot call `super()` implicitly because it is annotated with `@disable`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14235.d b/gcc/testsuite/gdc.test/fail_compilation/diag14235.d
index 4880bdf..3c8a98e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag14235.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag14235.d
@@ -1,9 +1,10 @@
/*
+EXTRA_FILES: imports/a14235.d
TEST_OUTPUT:
---
-fail_compilation/diag14235.d(11): Error: template identifier 'Undefined' is not a member of module 'imports.a14235'
-fail_compilation/diag14235.d(12): Error: template identifier 'Something' is not a member of module 'imports.a14235', did you mean struct 'SomeThing(T...)'?
-fail_compilation/diag14235.d(13): Error: imports.a14235.SomeClass is not a template, it is a class
+fail_compilation/diag14235.d(12): Error: template identifier `Undefined` is not a member of module `imports.a14235`
+fail_compilation/diag14235.d(13): Error: template identifier `Something` is not a member of module `imports.a14235`, did you mean struct `SomeThing(T...)`?
+fail_compilation/diag14235.d(14): Error: `imports.a14235.SomeClass` is not a template, it is a class
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14818.d b/gcc/testsuite/gdc.test/fail_compilation/diag14818.d
index 4eef748..660066a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag14818.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag14818.d
@@ -1,11 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag14818.d(34): Error: none of the overloads of 'func' are callable using argument types (string), candidates are:
-fail_compilation/diag14818.d(12): diag14818.foo(int _param_0)
-fail_compilation/diag14818.d(13): diag14818.bar(double _param_0)
-fail_compilation/diag14818.d(35): Error: overload alias diag14818.X does not match any template declaration
-fail_compilation/diag14818.d(36): Error: overloadset diag14818.M does not match any template declaration
+fail_compilation/diag14818.d(34): Error: none of the overloads of `func` are callable using argument types `(string)`
+fail_compilation/diag14818.d(12): Candidate is: `diag14818.foo(int _param_0)`
+fail_compilation/diag14818.d(13): `diag14818.bar(double _param_0)`
+fail_compilation/diag14818.d(35): Error: overload alias `diag14818.X` does not match any template declaration
+fail_compilation/diag14818.d(36): Error: overloadset `diag14818.M` does not match any template declaration
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14875.d b/gcc/testsuite/gdc.test/fail_compilation/diag14875.d
index 52a6127..a4d4abe 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag14875.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag14875.d
@@ -6,7 +6,7 @@ deprecated immutable int depVar = 10;
/*
TEST_OUTPUT:
---
-fail_compilation/diag14875.d(16): Deprecation: class diag14875.Dep is deprecated
+fail_compilation/diag14875.d(16): Deprecation: class `diag14875.Dep` is deprecated
1: Dep
2: Dep
3: Dep
@@ -36,11 +36,16 @@ template Baz(T)
/*
TEST_OUTPUT:
---
-fail_compilation/diag14875.d(47): Deprecation: class diag14875.Dep is deprecated
-fail_compilation/diag14875.d(51): Deprecation: variable diag14875.depVar is deprecated
+fail_compilation/diag14875.d(52): Deprecation: class `diag14875.Dep` is deprecated
+fail_compilation/diag14875.d(56): Deprecation: variable `diag14875.depVar` is deprecated
+fail_compilation/diag14875.d(52): instantiated from here: `Voo!(Dep)`
4: Dep
-fail_compilation/diag14875.d(58): Deprecation: variable diag14875.depVar is deprecated
-fail_compilation/diag14875.d(59): Deprecation: variable diag14875.Vaz!(Dep).Vaz is deprecated
+fail_compilation/diag14875.d(63): Deprecation: variable `diag14875.depVar` is deprecated
+fail_compilation/diag14875.d(59): instantiated from here: `Var!(Dep)`
+fail_compilation/diag14875.d(52): instantiated from here: `Voo!(Dep)`
+fail_compilation/diag14875.d(64): Deprecation: template `diag14875.Vaz(T)` is deprecated
+fail_compilation/diag14875.d(59): instantiated from here: `Var!(Dep)`
+fail_compilation/diag14875.d(52): instantiated from here: `Voo!(Dep)`
---
*/
@@ -67,7 +72,7 @@ deprecated template Vaz(T)
/*
TEST_OUTPUT:
---
-fail_compilation/diag14875.d(75): Error: static assert `0` is false
+fail_compilation/diag14875.d(80): Error: static assert: `0` is false
---
*/
void main()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14876.d b/gcc/testsuite/gdc.test/fail_compilation/diag14876.d
index dcc440f..0ca0360 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag14876.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag14876.d
@@ -1,14 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag14876.d(17): Deprecation: class diag14876.Dep is deprecated
-fail_compilation/diag14876.d(18): Deprecation: class diag14876.Dep is deprecated
-fail_compilation/diag14876.d(19): Deprecation: class diag14876.Dep is deprecated
-fail_compilation/diag14876.d(20): Deprecation: class diag14876.Dep is deprecated
-fail_compilation/diag14876.d(21): Deprecation: class diag14876.Dep is deprecated
-fail_compilation/diag14876.d(22): Deprecation: class diag14876.Dep is deprecated
-fail_compilation/diag14876.d(23): Deprecation: class diag14876.Dep is deprecated
-fail_compilation/diag14876.d(23): Error: can only slice tuple types, not diag14876.Dep
+fail_compilation/diag14876.d(17): Deprecation: class `diag14876.Dep` is deprecated
+fail_compilation/diag14876.d(18): Deprecation: class `diag14876.Dep` is deprecated
+fail_compilation/diag14876.d(19): Deprecation: class `diag14876.Dep` is deprecated
+fail_compilation/diag14876.d(20): Deprecation: class `diag14876.Dep` is deprecated
+fail_compilation/diag14876.d(21): Deprecation: class `diag14876.Dep` is deprecated
+fail_compilation/diag14876.d(22): Deprecation: class `diag14876.Dep` is deprecated
+fail_compilation/diag14876.d(23): Deprecation: class `diag14876.Dep` is deprecated
+fail_compilation/diag14876.d(23): Error: can only slice tuple types, not `diag14876.Dep`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15209.d b/gcc/testsuite/gdc.test/fail_compilation/diag15209.d
index 341e026..9a4f396 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag15209.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag15209.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag15209.d(18): Error: need 'this' for 'x' of type 'int'
-fail_compilation/diag15209.d(21): Error: need 'this' for 'x' of type 'int'
+fail_compilation/diag15209.d(18): Error: need `this` for `x` of type `int`
+fail_compilation/diag15209.d(21): Error: need `this` for `x` of type `int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15411.d b/gcc/testsuite/gdc.test/fail_compilation/diag15411.d
index bc77d81..8b18c19 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag15411.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag15411.d
@@ -2,8 +2,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag15411.d(13): Error: function diag15411.test15411.__funcliteral1 cannot access frame of function diag15411.test15411
-fail_compilation/diag15411.d(14): Error: function diag15411.test15411.__funcliteral2 cannot access frame of function diag15411.test15411
+fail_compilation/diag15411.d(17): Error: function `diag15411.test15411.__funcliteral2` cannot access variable `i` in frame of function `diag15411.test15411`
+fail_compilation/diag15411.d(16): `i` declared here
+fail_compilation/diag15411.d(18): Error: function `diag15411.test15411.__funcliteral4` cannot access variable `i` in frame of function `diag15411.test15411`
+fail_compilation/diag15411.d(16): `i` declared here
+fail_compilation/diag15411.d(26): Error: `static` function `diag15411.testNestedFunction.myFunc2` cannot access function `myFunc1` in frame of function `diag15411.testNestedFunction`
+fail_compilation/diag15411.d(25): `myFunc1` declared here
---
*/
@@ -13,3 +17,11 @@ void test15411()
auto j = (function() { return i; })();
auto f = function() { return i; };
}
+
+void testNestedFunction ()
+{
+ int i = 42;
+
+ void myFunc1() { assert(i == 42); }
+ static void myFunc2 () { myFunc1(); }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15669.d b/gcc/testsuite/gdc.test/fail_compilation/diag15669.d
index a2ab4aa..6827685 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag15669.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag15669.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag15669.d(14): Error: variable __b_field_0 cannot be read at compile time
+fail_compilation/diag15669.d(14): Error: variable `__b_field_0` cannot be read at compile time
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15713.d b/gcc/testsuite/gdc.test/fail_compilation/diag15713.d
index a7714c9..34fc645 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag15713.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag15713.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag15713.d(18): Error: no property 'widthSign' for type 'Data'
-fail_compilation/diag15713.d(38): Error: template instance test.conwritefImpl!("parse-int", "width", "\x0a", Data()) error instantiating
-fail_compilation/diag15713.d(43): instantiated from here: conwritefImpl!("main", "\x0a", Data())
-fail_compilation/diag15713.d(48): instantiated from here: fdwritef!()
+fail_compilation/diag15713.d(19): Error: no property `widthSign` for type `diag15713.WrData.Data`
+fail_compilation/diag15713.d(39): Error: template instance `diag15713.conwritefImpl!("parse-int", "width", "\x0a", Data(null))` error instantiating
+fail_compilation/diag15713.d(44): instantiated from here: `conwritefImpl!("main", "\x0a", Data(null))`
+fail_compilation/diag15713.d(49): instantiated from here: `fdwritef!()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15974.d b/gcc/testsuite/gdc.test/fail_compilation/diag15974.d
index a6b3077..03f63f4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag15974.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag15974.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag15974.d(21): Error: variable f cannot be read at compile time
-fail_compilation/diag15974.d(21): called from here: format("%s", f)
-fail_compilation/diag15974.d(26): Error: variable f cannot be read at compile time
-fail_compilation/diag15974.d(26): called from here: format("%s", f)
+fail_compilation/diag15974.d(21): Error: variable `f` cannot be read at compile time
+fail_compilation/diag15974.d(21): called from here: `format("%s", f)`
+fail_compilation/diag15974.d(26): Error: variable `f` cannot be read at compile time
+fail_compilation/diag15974.d(26): called from here: `format("%s", f)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag16499.d b/gcc/testsuite/gdc.test/fail_compilation/diag16499.d
index 5d0c6ff..63b4b3c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag16499.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag16499.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag16499.d(22): Error: incompatible types for ((2) in (foo)): 'int' and 'A'
-fail_compilation/diag16499.d(24): Error: incompatible types for ((1.00000) in (bar)): 'double' and 'B'
+fail_compilation/diag16499.d(22): Error: incompatible types for `(2) in (foo)`: `int` and `A`
+fail_compilation/diag16499.d(24): Error: incompatible types for `(1.0) in (bar)`: `double` and `B`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d
index 0754fc6..8f991a7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d
@@ -1,12 +1,15 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag16977.d(22): Error: undefined identifier `undefined`, did you mean function `undefinedId`?
-fail_compilation/diag16977.d(23): Error: cannot implicitly convert expression `"\x01string"` of type `string` to `int`
-fail_compilation/diag16977.d(24): Error: template diag16977.templ cannot deduce function from argument types !()(int), candidates are:
-fail_compilation/diag16977.d(17): diag16977.templ(S)(S s) if (false)
-fail_compilation/diag16977.d(25): Error: cannot implicitly convert expression `5` of type `int` to `string`
-fail_compilation/diag16977.d(27): Error: template instance diag16977.test.funcTemplate!string error instantiating
+fail_compilation/diag16977.d(25): Error: undefined identifier `undefined`, did you mean function `undefinedId`?
+fail_compilation/diag16977.d(26): Error: cannot implicitly convert expression `"\x01string"` of type `string` to `int`
+fail_compilation/diag16977.d(27): Error: template `diag16977.templ` cannot deduce function from argument types `!()(int)`
+fail_compilation/diag16977.d(20): Candidate is: `templ(S)(S s)`
+ with `S = int`
+ must satisfy the following constraint:
+` false`
+fail_compilation/diag16977.d(28): Error: cannot implicitly convert expression `5` of type `int` to `string`
+fail_compilation/diag16977.d(30): Error: template instance `diag16977.test.funcTemplate!string` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag1730.d b/gcc/testsuite/gdc.test/fail_compilation/diag1730.d
index 697cd5a..a17479c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag1730.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag1730.d
@@ -1,28 +1,41 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag1730.d(38): Error: mutable method diag1730.S.func is not callable using a inout object
-fail_compilation/diag1730.d(40): Error: immutable method diag1730.S.iFunc is not callable using a inout object
-fail_compilation/diag1730.d(41): Error: shared mutable method diag1730.S.sFunc is not callable using a non-shared inout object
-fail_compilation/diag1730.d(42): Error: shared const method diag1730.S.scFunc is not callable using a non-shared inout object
-fail_compilation/diag1730.d(57): Error: immutable method diag1730.S.iFunc is not callable using a mutable object
-fail_compilation/diag1730.d(58): Error: shared method diag1730.S.sFunc is not callable using a non-shared object
-fail_compilation/diag1730.d(59): Error: shared const method diag1730.S.scFunc is not callable using a non-shared mutable object
-fail_compilation/diag1730.d(62): Error: mutable method diag1730.S.func is not callable using a const object
-fail_compilation/diag1730.d(64): Error: immutable method diag1730.S.iFunc is not callable using a const object
-fail_compilation/diag1730.d(65): Error: shared mutable method diag1730.S.sFunc is not callable using a non-shared const object
-fail_compilation/diag1730.d(66): Error: shared const method diag1730.S.scFunc is not callable using a non-shared const object
-fail_compilation/diag1730.d(69): Error: mutable method diag1730.S.func is not callable using a immutable object
-fail_compilation/diag1730.d(72): Error: shared mutable method diag1730.S.sFunc is not callable using a immutable object
-fail_compilation/diag1730.d(76): Error: non-shared method diag1730.S.func is not callable using a shared object
-fail_compilation/diag1730.d(77): Error: non-shared const method diag1730.S.cFunc is not callable using a shared mutable object
-fail_compilation/diag1730.d(78): Error: immutable method diag1730.S.iFunc is not callable using a shared mutable object
-fail_compilation/diag1730.d(81): Error: non-shared inout method diag1730.S.wFunc is not callable using a shared mutable object
-fail_compilation/diag1730.d(83): Error: non-shared mutable method diag1730.S.func is not callable using a shared const object
-fail_compilation/diag1730.d(84): Error: non-shared const method diag1730.S.cFunc is not callable using a shared const object
-fail_compilation/diag1730.d(85): Error: immutable method diag1730.S.iFunc is not callable using a shared const object
-fail_compilation/diag1730.d(86): Error: shared mutable method diag1730.S.sFunc is not callable using a shared const object
-fail_compilation/diag1730.d(88): Error: non-shared inout method diag1730.S.wFunc is not callable using a shared const object
+fail_compilation/diag1730.d(51): Error: mutable method `diag1730.S.func` is not callable using a `inout` object
+fail_compilation/diag1730.d(43): Consider adding `const` or `inout` here
+fail_compilation/diag1730.d(53): Error: `immutable` method `diag1730.S.iFunc` is not callable using a `inout` object
+fail_compilation/diag1730.d(54): Error: `shared` mutable method `diag1730.S.sFunc` is not callable using a non-shared `inout` object
+fail_compilation/diag1730.d(46): Consider adding `const` or `inout` here
+fail_compilation/diag1730.d(55): Error: `shared` `const` method `diag1730.S.scFunc` is not callable using a non-shared `inout` object
+fail_compilation/diag1730.d(70): Error: `immutable` method `diag1730.S.iFunc` is not callable using a mutable object
+fail_compilation/diag1730.d(71): Error: `shared` method `diag1730.S.sFunc` is not callable using a non-shared object
+fail_compilation/diag1730.d(72): Error: `shared` `const` method `diag1730.S.scFunc` is not callable using a non-shared mutable object
+fail_compilation/diag1730.d(75): Error: mutable method `diag1730.S.func` is not callable using a `const` object
+fail_compilation/diag1730.d(43): Consider adding `const` or `inout` here
+fail_compilation/diag1730.d(77): Error: `immutable` method `diag1730.S.iFunc` is not callable using a `const` object
+fail_compilation/diag1730.d(78): Error: `shared` mutable method `diag1730.S.sFunc` is not callable using a non-shared `const` object
+fail_compilation/diag1730.d(46): Consider adding `const` or `inout` here
+fail_compilation/diag1730.d(79): Error: `shared` `const` method `diag1730.S.scFunc` is not callable using a non-shared `const` object
+fail_compilation/diag1730.d(82): Error: mutable method `diag1730.S.func` is not callable using a `immutable` object
+fail_compilation/diag1730.d(43): Consider adding `const` or `inout` here
+fail_compilation/diag1730.d(85): Error: `shared` mutable method `diag1730.S.sFunc` is not callable using a `immutable` object
+fail_compilation/diag1730.d(46): Consider adding `const` or `inout` here
+fail_compilation/diag1730.d(89): Error: non-shared method `diag1730.S.func` is not callable using a `shared` object
+fail_compilation/diag1730.d(43): Consider adding `shared` here
+fail_compilation/diag1730.d(90): Error: non-shared `const` method `diag1730.S.cFunc` is not callable using a `shared` mutable object
+fail_compilation/diag1730.d(44): Consider adding `shared` here
+fail_compilation/diag1730.d(91): Error: `immutable` method `diag1730.S.iFunc` is not callable using a `shared` mutable object
+fail_compilation/diag1730.d(94): Error: non-shared `inout` method `diag1730.S.wFunc` is not callable using a `shared` mutable object
+fail_compilation/diag1730.d(48): Consider adding `shared` here
+fail_compilation/diag1730.d(96): Error: non-shared mutable method `diag1730.S.func` is not callable using a `shared` `const` object
+fail_compilation/diag1730.d(43): Consider adding `shared` here
+fail_compilation/diag1730.d(97): Error: non-shared `const` method `diag1730.S.cFunc` is not callable using a `shared` `const` object
+fail_compilation/diag1730.d(44): Consider adding `shared` here
+fail_compilation/diag1730.d(98): Error: `immutable` method `diag1730.S.iFunc` is not callable using a `shared` `const` object
+fail_compilation/diag1730.d(99): Error: `shared` mutable method `diag1730.S.sFunc` is not callable using a `shared` `const` object
+fail_compilation/diag1730.d(46): Consider adding `const` or `inout` here
+fail_compilation/diag1730.d(101): Error: non-shared `inout` method `diag1730.S.wFunc` is not callable using a `shared` `const` object
+fail_compilation/diag1730.d(48): Consider adding `shared` here
---
*/
struct S
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag18460.d b/gcc/testsuite/gdc.test/fail_compilation/diag18460.d
new file mode 100644
index 0000000..148b64b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag18460.d
@@ -0,0 +1,13 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag18460.d(12): Error: no property `opCall` for type `diag18460.Foo`, did you mean `new Foo`?
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=18460
+
+class Foo {}
+
+void main() {
+ auto f = Foo();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag18574.d b/gcc/testsuite/gdc.test/fail_compilation/diag18574.d
new file mode 100644
index 0000000..fef9829
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag18574.d
@@ -0,0 +1,17 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag18574.d(16): Error: `diag18574.Test`: multiple class inheritance is not supported. Use multiple interface inheritance and/or composition.
+fail_compilation/diag18574.d(16): `diag18574.Bar` has no fields, consider making it an `interface`
+fail_compilation/diag18574.d(16): `diag18574.Baz` has fields, consider making it a member of `diag18574.Test`
+fail_compilation/diag18574.d(16): Error: `diag18574.Test`: base type must be `interface`, not `int`
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=18574
+
+class Foo {}
+class Bar {}
+class Baz { int a; }
+
+class Test : Foo, Bar, Baz, int {}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag19022.d b/gcc/testsuite/gdc.test/fail_compilation/diag19022.d
new file mode 100644
index 0000000..0aa26f5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag19022.d
@@ -0,0 +1,18 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag19022.d(16): Error: immutable field `b` initialized multiple times
+fail_compilation/diag19022.d(15): Previous initialization is here.
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=19022
+
+struct Foo
+{
+ immutable int b;
+ this(int a)
+ {
+ b = 2;
+ b = 2;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag19225.d b/gcc/testsuite/gdc.test/fail_compilation/diag19225.d
new file mode 100644
index 0000000..bbb8251
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag19225.d
@@ -0,0 +1,15 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag19225.d(14): Error: basic type expected, not `else`
+fail_compilation/diag19225.d(14): There's no `static else`, use `else` instead.
+fail_compilation/diag19225.d(14): Error: found `else` without a corresponding `if`, `version` or `debug` statement
+fail_compilation/diag19225.d(15): Error: unrecognized declaration
+---
+*/
+
+void main()
+{
+ static if (true) {}
+ static else {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag20059.d b/gcc/testsuite/gdc.test/fail_compilation/diag20059.d
new file mode 100644
index 0000000..a7a5914
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag20059.d
@@ -0,0 +1,16 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag20059.d(15): Error: Expected return type of `string`, not `string[]`:
+fail_compilation/diag20059.d(13): Return type of `string` inferred here.
+---
+*/
+
+auto fail()
+{
+ string ret;
+ if (true)
+ return ret;
+ else
+ return [ret];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag20518.d b/gcc/testsuite/gdc.test/fail_compilation/diag20518.d
new file mode 100644
index 0000000..eb0a932
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag20518.d
@@ -0,0 +1,11 @@
+// EXTRA_FILES: imports/diag20518a.d imports/diag20518a/b.d
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag20518.d(11): Error: module `diag20518a` from file fail_compilation/imports/diag20518a.d conflicts with package `imports.diag20518a`
+---
+*/
+
+import imports.diag20518a.b; // from here 'imports.diag20518a' represents a package and you can optionally
+ // import its package.d with 'import imports.diag20518a;', but anyway
+import imports.diag20518a; // if 'imports/diag20518a.d' exists it will conflict with it.
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag21883.d b/gcc/testsuite/gdc.test/fail_compilation/diag21883.d
new file mode 100644
index 0000000..4823167
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag21883.d
@@ -0,0 +1,16 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag21883.d(15): Error: `diag21883.ClassB`: base class must be specified first, before any interfaces.
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=21883
+
+interface InterfaceA {
+}
+
+class ClassA {
+}
+
+class ClassB: InterfaceA, ClassA {
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag2452.d b/gcc/testsuite/gdc.test/fail_compilation/diag2452.d
index 0c12e80..e68e217 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag2452.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag2452.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag2452.d(14): Error: class diag2452.C interface function 'void f(float p)' is not implemented
+fail_compilation/diag2452.d(14): Error: class `diag2452.C` interface function `void f(float p)` is not implemented
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3013.d b/gcc/testsuite/gdc.test/fail_compilation/diag3013.d
index c57b4b9..41c98b0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag3013.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag3013.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag3013.d(11): Error: cannot pass type string as a function argument
+fail_compilation/diag3013.d(11): Error: cannot pass type `string` as a function argument
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3438.d b/gcc/testsuite/gdc.test/fail_compilation/diag3438.d
index 3c22ca8..445f6d5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag3438.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag3438.d
@@ -2,12 +2,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag3438.d(16): Deprecation: constructor diag3438.F1.this all parameters have default arguments, but structs cannot have default constructors.
-fail_compilation/diag3438.d(17): Deprecation: constructor diag3438.F2.this all parameters have default arguments, but structs cannot have default constructors.
-fail_compilation/diag3438.d(20): Deprecation: constructor diag3438.F5.this @disable'd constructor cannot have default arguments for all parameters.
-fail_compilation/diag3438.d(20): Use @disable this(); if you want to disable default initialization.
-fail_compilation/diag3438.d(21): Deprecation: constructor diag3438.F6.this @disable'd constructor cannot have default arguments for all parameters.
-fail_compilation/diag3438.d(21): Use @disable this(); if you want to disable default initialization.
+fail_compilation/diag3438.d(16): Error: constructor `diag3438.F1.this` all parameters have default arguments, but structs cannot have default constructors.
+fail_compilation/diag3438.d(17): Error: constructor `diag3438.F2.this` all parameters have default arguments, but structs cannot have default constructors.
+fail_compilation/diag3438.d(20): Error: constructor `diag3438.F5.this` is marked `@disable`, so it cannot have default arguments for all parameters.
+fail_compilation/diag3438.d(20): Use `@disable this();` if you want to disable default initialization.
+fail_compilation/diag3438.d(21): Error: constructor `diag3438.F6.this` is marked `@disable`, so it cannot have default arguments for all parameters.
+fail_compilation/diag3438.d(21): Use `@disable this();` if you want to disable default initialization.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3672.d b/gcc/testsuite/gdc.test/fail_compilation/diag3672.d
index ab3c224..41b1415 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag3672.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag3672.d
@@ -1,31 +1,53 @@
-// PERMUTE_ARGS:
// REQUIRED_ARGS: -de
/*
TEST_OUTPUT:
---
-fail_compilation/diag3672.d(36): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(x, 1) instead.
-fail_compilation/diag3672.d(37): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(x, 1) instead.
-fail_compilation/diag3672.d(38): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"-="(x, 1) instead.
-fail_compilation/diag3672.d(39): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"-="(x, 1) instead.
-fail_compilation/diag3672.d(40): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(x, 1) instead.
-fail_compilation/diag3672.d(41): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(x, 2) instead.
-fail_compilation/diag3672.d(42): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"-="(x, 3) instead.
-fail_compilation/diag3672.d(43): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"|="(x, y) instead.
-fail_compilation/diag3672.d(44): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"*="(x, y) instead.
-fail_compilation/diag3672.d(45): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"/="(x, y) instead.
-fail_compilation/diag3672.d(46): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"%="(x, y) instead.
-fail_compilation/diag3672.d(47): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"&="(x, y) instead.
-fail_compilation/diag3672.d(48): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"^="(x, y) instead.
-fail_compilation/diag3672.d(49): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"<<="(x, y) instead.
-fail_compilation/diag3672.d(50): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!">>="(x, y) instead.
-fail_compilation/diag3672.d(51): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!">>>="(x, y) instead.
-fail_compilation/diag3672.d(52): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"^^="(x, y) instead.
-fail_compilation/diag3672.d(53): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(ptr, 1) instead.
-fail_compilation/diag3672.d(54): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(ptr, 1) instead.
-fail_compilation/diag3672.d(55): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"-="(ptr, 1) instead.
-fail_compilation/diag3672.d(56): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"-="(ptr, 1) instead.
+fail_compilation/diag3672.d(8): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(8): Use `core.atomic.atomicOp!"+="(x, 1)` instead
+fail_compilation/diag3672.d(9): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(9): Use `core.atomic.atomicOp!"+="(x, 1)` instead
+fail_compilation/diag3672.d(10): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(10): Use `core.atomic.atomicOp!"-="(x, 1)` instead
+fail_compilation/diag3672.d(11): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(11): Use `core.atomic.atomicOp!"-="(x, 1)` instead
+fail_compilation/diag3672.d(12): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(12): Use `core.atomic.atomicOp!"+="(x, 1)` instead
+fail_compilation/diag3672.d(13): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(13): Use `core.atomic.atomicOp!"+="(x, 2)` instead
+fail_compilation/diag3672.d(14): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(14): Use `core.atomic.atomicOp!"-="(x, 3)` instead
+fail_compilation/diag3672.d(15): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(15): Use `core.atomic.atomicOp!"|="(x, y)` instead
+fail_compilation/diag3672.d(16): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(16): Use `core.atomic.atomicOp!"*="(x, y)` instead
+fail_compilation/diag3672.d(17): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(17): Use `core.atomic.atomicOp!"/="(x, y)` instead
+fail_compilation/diag3672.d(18): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(18): Use `core.atomic.atomicOp!"%="(x, y)` instead
+fail_compilation/diag3672.d(19): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(19): Use `core.atomic.atomicOp!"&="(x, y)` instead
+fail_compilation/diag3672.d(20): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(20): Use `core.atomic.atomicOp!"^="(x, y)` instead
+fail_compilation/diag3672.d(21): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(21): Use `core.atomic.atomicOp!"<<="(x, y)` instead
+fail_compilation/diag3672.d(22): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(22): Use `core.atomic.atomicOp!">>="(x, y)` instead
+fail_compilation/diag3672.d(23): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(23): Use `core.atomic.atomicOp!">>>="(x, y)` instead
+fail_compilation/diag3672.d(24): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(24): Use `core.atomic.atomicOp!"^^="(x, y)` instead
+fail_compilation/diag3672.d(25): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(25): Use `core.atomic.atomicOp!"+="(ptr, 1)` instead
+fail_compilation/diag3672.d(26): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(26): Use `core.atomic.atomicOp!"+="(ptr, 1)` instead
+fail_compilation/diag3672.d(27): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(27): Use `core.atomic.atomicOp!"-="(ptr, 1)` instead
+fail_compilation/diag3672.d(28): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672.d(28): Use `core.atomic.atomicOp!"-="(ptr, 1)` instead
---
*/
+
+#line 1
shared int x;
shared int y;
shared int* ptr;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3672a.d b/gcc/testsuite/gdc.test/fail_compilation/diag3672a.d
index 6c9f701..66e9c49 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag3672a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag3672a.d
@@ -1,10 +1,11 @@
-// PERMUTE_ARGS:
// REQUIRED_ARGS: -de
/*
TEST_OUTPUT:
---
-fail_compilation/diag3672a.d(16): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(ns.x, 1) instead.
-fail_compilation/diag3672a.d(18): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(s.sx, 1) instead.
+fail_compilation/diag3672a.d(17): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672a.d(17): Use `core.atomic.atomicOp!"+="(ns.x, 1)` instead
+fail_compilation/diag3672a.d(19): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672a.d(19): Use `core.atomic.atomicOp!"+="(s.sx, 1)` instead
---
*/
class NS { shared int x; }
@@ -21,8 +22,10 @@ void main()
/*
TEST_OUTPUT:
---
-fail_compilation/diag3672a.d(32): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(s.var, 1) instead.
-fail_compilation/diag3672a.d(33): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"-="(s.var, 2) instead.
+fail_compilation/diag3672a.d(35): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672a.d(35): Use `core.atomic.atomicOp!"+="(s.var, 1)` instead
+fail_compilation/diag3672a.d(36): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/diag3672a.d(36): Use `core.atomic.atomicOp!"-="(s.var, 2)` instead
---
*/
void test13003()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3869.d b/gcc/testsuite/gdc.test/fail_compilation/diag3869.d
index 62e8993..6cb92c4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag3869.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag3869.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag3869.d(10): Error: template instance diag3869.sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!int)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) recursive expansion
+fail_compilation/diag3869.d(10): Error: template instance `diag3869.sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!(sum!int))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))` recursive expansion
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3913.d b/gcc/testsuite/gdc.test/fail_compilation/diag3913.d
index e176e9d..abf70b8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag3913.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag3913.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag3913.d(12): Error: no property 'foobardoo' for type 'Foo'
-fail_compilation/diag3913.d(13): Error: no property 'secon' for type 'Foo'. Did you mean 'Foo.second' ?
+fail_compilation/diag3913.d(12): Error: no property `foobardoo` for type `Foo`
+fail_compilation/diag3913.d(13): Error: no property `secon` for type `Foo`. Did you mean `Foo.second` ?
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag4479.d b/gcc/testsuite/gdc.test/fail_compilation/diag4479.d
index 553f9ef..7ce9bd8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag4479.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag4479.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag4479.d(10): Error: module imports.fail4479mod from file fail_compilation/imports/fail4479.d must be imported with 'import imports.fail4479mod;'
+fail_compilation/diag4479.d(10): Error: module `imports.fail4479mod` from file fail_compilation/imports/fail4479.d must be imported with 'import imports.fail4479mod;'
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag4528.d b/gcc/testsuite/gdc.test/fail_compilation/diag4528.d
index accadbc..ab7b2cf 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag4528.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag4528.d
@@ -1,11 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag4528.d(14): Error: function diag4528.Foo.pva private functions cannot be abstract
-fail_compilation/diag4528.d(15): Error: function diag4528.Foo.pka package functions cannot be abstract
-fail_compilation/diag4528.d(16): Error: function diag4528.Foo.pvsa static functions cannot be abstract
-fail_compilation/diag4528.d(17): Error: function diag4528.Foo.pksa static functions cannot be abstract
-fail_compilation/diag4528.d(18): Error: function diag4528.Foo.pbsa static functions cannot be abstract
+fail_compilation/diag4528.d(14): Error: function `diag4528.Foo.pva` `private` functions cannot be `abstract`
+fail_compilation/diag4528.d(15): Error: function `diag4528.Foo.pka` `package` functions cannot be `abstract`
+fail_compilation/diag4528.d(16): Error: function `diag4528.Foo.pvsa` `static` functions cannot be `abstract`
+fail_compilation/diag4528.d(17): Error: function `diag4528.Foo.pksa` `static` functions cannot be `abstract`
+fail_compilation/diag4528.d(18): Error: function `diag4528.Foo.pbsa` `static` functions cannot be `abstract`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d
index 368f67e..f6b49d6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag4596.d(15): Error: this is not an lvalue
-fail_compilation/diag4596.d(16): Error: 1 ? this : this is not an lvalue
-fail_compilation/diag4596.d(18): Error: super is not an lvalue
-fail_compilation/diag4596.d(19): Error: 1 ? super : super is not an lvalue
+fail_compilation/diag4596.d(15): Error: `this` is not an lvalue and cannot be modified
+fail_compilation/diag4596.d(16): Error: conditional expression `1 ? this : this` is not a modifiable lvalue
+fail_compilation/diag4596.d(18): Error: `super` is not an lvalue and cannot be modified
+fail_compilation/diag4596.d(19): Error: conditional expression `1 ? super : super` is not a modifiable lvalue
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag5385.d b/gcc/testsuite/gdc.test/fail_compilation/diag5385.d
index 7c81b16..60455ec 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag5385.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag5385.d
@@ -1,14 +1,15 @@
/*
+EXTRA_FILES: imports/fail5385.d
TEST_OUTPUT:
---
-fail_compilation/diag5385.d(19): Error: no property `privX` for type `imports.fail5385.C`, did you mean `imports.fail5385.C.privX`?
-fail_compilation/diag5385.d(20): Error: no property `packX` for type `imports.fail5385.C`, did you mean `imports.fail5385.C.packX`?
-fail_compilation/diag5385.d(21): Error: no property `privX2` for type `imports.fail5385.C`, did you mean `imports.fail5385.C.privX2`?
-fail_compilation/diag5385.d(22): Error: no property `packX2` for type `imports.fail5385.C`, did you mean `imports.fail5385.C.packX2`?
-fail_compilation/diag5385.d(23): Error: no property `privX` for type `S`, did you mean `imports.fail5385.S.privX`?
-fail_compilation/diag5385.d(24): Error: no property `packX` for type `S`, did you mean `imports.fail5385.S.packX`?
-fail_compilation/diag5385.d(25): Error: no property `privX2` for type `S`, did you mean `imports.fail5385.S.privX2`?
-fail_compilation/diag5385.d(26): Error: no property `packX2` for type `S`, did you mean `imports.fail5385.S.packX2`?
+fail_compilation/diag5385.d(20): Error: no property `privX` for type `imports.fail5385.C`
+fail_compilation/diag5385.d(21): Error: no property `packX` for type `imports.fail5385.C`
+fail_compilation/diag5385.d(22): Error: no property `privX2` for type `imports.fail5385.C`
+fail_compilation/diag5385.d(23): Error: no property `packX2` for type `imports.fail5385.C`
+fail_compilation/diag5385.d(24): Error: no property `privX` for type `imports.fail5385.S`
+fail_compilation/diag5385.d(25): Error: no property `packX` for type `imports.fail5385.S`
+fail_compilation/diag5385.d(26): Error: no property `privX2` for type `imports.fail5385.S`
+fail_compilation/diag5385.d(27): Error: no property `packX2` for type `imports.fail5385.S`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag5450.d b/gcc/testsuite/gdc.test/fail_compilation/diag5450.d
index 495fea9..f544240 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag5450.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag5450.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag5450.d(18): Error: class diag5450.C cannot implicitly generate a default ctor when base class diag5450.B is missing a default ctor
+fail_compilation/diag5450.d(18): Error: class `diag5450.C` cannot implicitly generate a default constructor when base class `diag5450.B` is missing a default constructor
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag6373.d b/gcc/testsuite/gdc.test/fail_compilation/diag6373.d
index d5e396d..8711b90 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag6373.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag6373.d
@@ -2,7 +2,7 @@
REQUIRED_ARGS: -de
TEST_OUTPUT:
---
-fail_compilation/diag6373.d(15): Error: class diag6373.Bar use of `diag6373.Foo.method(double x)` is hidden by `Bar`; use `alias method = Foo.method;` to introduce base class overload set
+fail_compilation/diag6373.d(15): Error: class `diag6373.Bar` use of `diag6373.Foo.method(double x)` is hidden by `Bar`; use `alias method = Foo.method;` to introduce base class overload set
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag6539.d b/gcc/testsuite/gdc.test/fail_compilation/diag6539.d
index eddb5d2..c202548 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag6539.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag6539.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag6539.d(21): Error: overloadset diag6539.Rectangle is used as a type
+fail_compilation/diag6539.d(21): Error: overloadset `diag6539.Rectangle` is used as a type
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag6677.d b/gcc/testsuite/gdc.test/fail_compilation/diag6677.d
index 9f9c6dc..aef65d2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag6677.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag6677.d
@@ -1,17 +1,16 @@
-// REQUIRED_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/diag6677.d(18): Error: static constructor cannot be `const`
-fail_compilation/diag6677.d(19): Error: static constructor cannot be `inout`
-fail_compilation/diag6677.d(20): Error: static constructor cannot be `immutable`
+fail_compilation/diag6677.d(17): Error: static constructor cannot be `const`
+fail_compilation/diag6677.d(18): Error: static constructor cannot be `inout`
+fail_compilation/diag6677.d(19): Error: static constructor cannot be `immutable`
+fail_compilation/diag6677.d(20): Error: use `shared static this()` to declare a shared static constructor
fail_compilation/diag6677.d(21): Error: use `shared static this()` to declare a shared static constructor
-fail_compilation/diag6677.d(22): Error: use `shared static this()` to declare a shared static constructor
-fail_compilation/diag6677.d(24): Error: shared static constructor cannot be `const`
-fail_compilation/diag6677.d(25): Error: shared static constructor cannot be `inout`
-fail_compilation/diag6677.d(26): Error: shared static constructor cannot be `immutable`
+fail_compilation/diag6677.d(23): Error: shared static constructor cannot be `const`
+fail_compilation/diag6677.d(24): Error: shared static constructor cannot be `inout`
+fail_compilation/diag6677.d(25): Error: shared static constructor cannot be `immutable`
+fail_compilation/diag6677.d(26): Error: redundant attribute `shared`
fail_compilation/diag6677.d(27): Error: redundant attribute `shared`
-fail_compilation/diag6677.d(28): Error: redundant attribute `shared`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag6699.d b/gcc/testsuite/gdc.test/fail_compilation/diag6699.d
index 34b2c77..755d0fd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag6699.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag6699.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag6699.d(8): Error: no property 'x' for type 'int'
+fail_compilation/diag6699.d(8): Error: no property `x` for type `int`
---
*/
alias int b6699;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag6707.d b/gcc/testsuite/gdc.test/fail_compilation/diag6707.d
index cabdec3..70fea4f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag6707.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag6707.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag6707.d(16): Error: mutable method diag6707.Foo.value is not callable using a const object
+fail_compilation/diag6707.d(17): Error: mutable method `diag6707.Foo.value` is not callable using a `const` object
+fail_compilation/diag6707.d(13): Consider adding `const` or `inout` here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7050a.d b/gcc/testsuite/gdc.test/fail_compilation/diag7050a.d
index ddee70c..abd0d18 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag7050a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag7050a.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag7050a.d(14): Error: @safe function 'diag7050a.foo' cannot call @system constructor 'diag7050a.Foo.this'
+fail_compilation/diag7050a.d(15): Error: `@safe` function `diag7050a.foo` cannot call `@system` constructor `diag7050a.Foo.this`
+fail_compilation/diag7050a.d(11): `diag7050a.Foo.this` is declared here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7050b.d b/gcc/testsuite/gdc.test/fail_compilation/diag7050b.d
index ecbfd81..78912cd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag7050b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag7050b.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag7050b.d(12): Error: pure function 'diag7050b.f.g' cannot call impure function 'diag7050b.f'
+fail_compilation/diag7050b.d(12): Error: `pure` function `diag7050b.f.g` cannot call impure function `diag7050b.f`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7050c.d b/gcc/testsuite/gdc.test/fail_compilation/diag7050c.d
index 3fa75fc..3b366df 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag7050c.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag7050c.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag7050c.d(13): Error: @safe destructor 'diag7050c.B.~this' cannot call @system destructor 'diag7050c.A.~this'
+fail_compilation/diag7050c.d(14): Error: `@safe` destructor `diag7050c.B.~this` cannot call `@system` destructor `diag7050c.A.~this`
+fail_compilation/diag7050c.d(11): `diag7050c.A.~this` is declared here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7420.d b/gcc/testsuite/gdc.test/fail_compilation/diag7420.d
index 80077eb..3267e66 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag7420.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag7420.d
@@ -2,16 +2,17 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag7420.d(20): Error: static variable x cannot be read at compile time
-fail_compilation/diag7420.d(20): while evaluating: `static assert(x < 4)`
-fail_compilation/diag7420.d(21): Error: static variable y cannot be read at compile time
-fail_compilation/diag7420.d(21): while evaluating: `static assert(y == "abc")`
-fail_compilation/diag7420.d(22): Error: static variable y cannot be read at compile time
-fail_compilation/diag7420.d(22): while evaluating: `static assert(cast(ubyte[])y != null)`
-fail_compilation/diag7420.d(23): Error: static variable y cannot be read at compile time
-fail_compilation/diag7420.d(23): while evaluating: `static assert(cast(int)y[0] == 1)`
-fail_compilation/diag7420.d(24): Error: static variable y cannot be read at compile time
-fail_compilation/diag7420.d(24): while evaluating: `static assert(y[0..1].length == 1u)`
+fail_compilation/diag7420.d(21): Error: static variable `x` cannot be read at compile time
+fail_compilation/diag7420.d(21): while evaluating: `static assert(x < 4)`
+fail_compilation/diag7420.d(22): Error: static variable `y` cannot be read at compile time
+fail_compilation/diag7420.d(22): called from here: `__equals(y, "abc")`
+fail_compilation/diag7420.d(22): while evaluating: `static assert(y == "abc")`
+fail_compilation/diag7420.d(23): Error: static variable `y` cannot be read at compile time
+fail_compilation/diag7420.d(23): while evaluating: `static assert(cast(ubyte[])y != null)`
+fail_compilation/diag7420.d(24): Error: static variable `y` cannot be read at compile time
+fail_compilation/diag7420.d(24): while evaluating: `static assert(cast(int)y[0] == 1)`
+fail_compilation/diag7420.d(25): Error: static variable `y` cannot be read at compile time
+fail_compilation/diag7420.d(25): while evaluating: `static assert(y[0..1].length == 1u)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7477.d b/gcc/testsuite/gdc.test/fail_compilation/diag7477.d
index 1c97184..b82b33d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag7477.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag7477.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag7477.d(13): Error: cannot implicitly convert expression `0` of type `int` to `Foo`
-fail_compilation/diag7477.d(20): Error: cannot implicitly convert expression `0` of type `int` to `string`
+fail_compilation/diag7477.d(13): Error: integral constant must be scalar type, not `Foo`
+fail_compilation/diag7477.d(20): Error: integral constant must be scalar type, not `string`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7747.d b/gcc/testsuite/gdc.test/fail_compilation/diag7747.d
index 0756911..e2e5992 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag7747.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag7747.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag7747.d(8): Error: forward reference to inferred return type of function call 'fact(n - 1)'
+fail_compilation/diag7747.d(8): Error: forward reference to inferred return type of function call `fact(n - 1)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag7998.d b/gcc/testsuite/gdc.test/fail_compilation/diag7998.d
index 68f61f3..a245b40 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag7998.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag7998.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag7998.d(10): Error: static assert "abcxe"
+fail_compilation/diag7998.d(10): Error: static assert: "abcxe"
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8044.d b/gcc/testsuite/gdc.test/fail_compilation/diag8044.d
new file mode 100644
index 0000000..a8c767a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8044.d
@@ -0,0 +1,19 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag8044.d(18): Error: template instance `diag8044.test!(Enum.Bar)` does not match template declaration `test(Enum en)()`
+ with `en = Bar`
+ must satisfy the following constraint:
+` 0`
+---
+ */
+enum Enum { Foo, Bar }
+void test(Enum en)()
+ if(0)
+{
+}
+
+void main()
+{
+ test!(Enum.Bar)();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8101.d b/gcc/testsuite/gdc.test/fail_compilation/diag8101.d
index 3b2401a..a0d245b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8101.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8101.d
@@ -3,27 +3,27 @@ TEST_OUTPUT:
---
fail_compilation/diag8101.d(57): Error: function `diag8101.f_0(int)` is not callable using argument types `()`
fail_compilation/diag8101.d(57): missing argument for parameter #1: `int`
-fail_compilation/diag8101.d(58): Error: none of the overloads of `f_1` are callable using argument types `()`, candidates are:
-fail_compilation/diag8101.d(33): `diag8101.f_1(int)`
-fail_compilation/diag8101.d(34): `diag8101.f_1(int, int)`
-fail_compilation/diag8101.d(59): Error: none of the overloads of `f_2` are callable using argument types `()`, candidates are:
-fail_compilation/diag8101.d(36): `diag8101.f_2(int)`
-fail_compilation/diag8101.d(37): `diag8101.f_2(int, int)`
-fail_compilation/diag8101.d(38): `diag8101.f_2(int, int, int)`
-fail_compilation/diag8101.d(39): `diag8101.f_2(int, int, int, int)`
-fail_compilation/diag8101.d(40): `diag8101.f_2(int, int, int, int, int)`
+fail_compilation/diag8101.d(58): Error: none of the overloads of `f_1` are callable using argument types `()`
+fail_compilation/diag8101.d(33): Candidates are: `diag8101.f_1(int)`
+fail_compilation/diag8101.d(34): `diag8101.f_1(int, int)`
+fail_compilation/diag8101.d(59): Error: none of the overloads of `f_2` are callable using argument types `()`
+fail_compilation/diag8101.d(36): Candidates are: `diag8101.f_2(int)`
+fail_compilation/diag8101.d(37): `diag8101.f_2(int, int)`
+fail_compilation/diag8101.d(38): `diag8101.f_2(int, int, int)`
+fail_compilation/diag8101.d(39): `diag8101.f_2(int, int, int, int)`
+fail_compilation/diag8101.d(40): `diag8101.f_2(int, int, int, int, int)`
fail_compilation/diag8101.d(59): ... (1 more, -v to show) ...
-fail_compilation/diag8101.d(61): Error: template `diag8101.t_0` cannot deduce function from argument types `!()()`, candidates are:
-fail_compilation/diag8101.d(43): `diag8101.t_0(T1)()`
-fail_compilation/diag8101.d(62): Error: template `diag8101.t_1` cannot deduce function from argument types `!()()`, candidates are:
-fail_compilation/diag8101.d(45): `diag8101.t_1(T1)()`
-fail_compilation/diag8101.d(46): `diag8101.t_1(T1, T2)()`
-fail_compilation/diag8101.d(63): Error: template `diag8101.t_2` cannot deduce function from argument types `!()()`, candidates are:
-fail_compilation/diag8101.d(48): `diag8101.t_2(T1)()`
-fail_compilation/diag8101.d(49): `diag8101.t_2(T1, T2)()`
-fail_compilation/diag8101.d(50): `diag8101.t_2(T1, T2, T3)()`
-fail_compilation/diag8101.d(51): `diag8101.t_2(T1, T2, T3, T4)()`
-fail_compilation/diag8101.d(52): `diag8101.t_2(T1, T2, T3, T4, T5)()`
+fail_compilation/diag8101.d(61): Error: template `diag8101.t_0` cannot deduce function from argument types `!()()`
+fail_compilation/diag8101.d(43): Candidate is: `t_0(T1)()`
+fail_compilation/diag8101.d(62): Error: template `diag8101.t_1` cannot deduce function from argument types `!()()`
+fail_compilation/diag8101.d(45): Candidates are: `t_1(T1)()`
+fail_compilation/diag8101.d(46): `t_1(T1, T2)()`
+fail_compilation/diag8101.d(63): Error: template `diag8101.t_2` cannot deduce function from argument types `!()()`
+fail_compilation/diag8101.d(48): Candidates are: `t_2(T1)()`
+fail_compilation/diag8101.d(49): `t_2(T1, T2)()`
+fail_compilation/diag8101.d(50): `t_2(T1, T2, T3)()`
+fail_compilation/diag8101.d(51): `t_2(T1, T2, T3, T4)()`
+fail_compilation/diag8101.d(52): `t_2(T1, T2, T3, T4, T5)()`
fail_compilation/diag8101.d(63): ... (1 more, -v to show) ...
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d b/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d
index 228ba16..bc0ee9d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d
@@ -1,15 +1,16 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag8101b.d(27): Error: none of the overloads of `foo` are callable using argument types `(double)`, candidates are:
-fail_compilation/diag8101b.d(18): `diag8101b.S.foo(int _param_0)`
-fail_compilation/diag8101b.d(19): `diag8101b.S.foo(int _param_0, int _param_1)`
-fail_compilation/diag8101b.d(29): Error: function `diag8101b.S.bar(int _param_0)` is not callable using argument types `(double)`
-fail_compilation/diag8101b.d(29): cannot pass argument `1.00000` of type `double` to parameter `int _param_0`
-fail_compilation/diag8101b.d(32): Error: none of the overloads of `foo` are callable using a `const` object, candidates are:
-fail_compilation/diag8101b.d(18): `diag8101b.S.foo(int _param_0)`
-fail_compilation/diag8101b.d(19): `diag8101b.S.foo(int _param_0, int _param_1)`
-fail_compilation/diag8101b.d(34): Error: mutable method `diag8101b.S.bar` is not callable using a `const` object
+fail_compilation/diag8101b.d(28): Error: none of the overloads of `foo` are callable using argument types `(double)`
+fail_compilation/diag8101b.d(19): Candidates are: `diag8101b.S.foo(int _param_0)`
+fail_compilation/diag8101b.d(20): `diag8101b.S.foo(int _param_0, int _param_1)`
+fail_compilation/diag8101b.d(30): Error: function `diag8101b.S.bar(int _param_0)` is not callable using argument types `(double)`
+fail_compilation/diag8101b.d(30): cannot pass argument `1.0` of type `double` to parameter `int _param_0`
+fail_compilation/diag8101b.d(33): Error: none of the overloads of `foo` are callable using a `const` object
+fail_compilation/diag8101b.d(19): Candidates are: `diag8101b.S.foo(int _param_0)`
+fail_compilation/diag8101b.d(20): `diag8101b.S.foo(int _param_0, int _param_1)`
+fail_compilation/diag8101b.d(35): Error: mutable method `diag8101b.S.bar` is not callable using a `const` object
+fail_compilation/diag8101b.d(22): Consider adding `const` or `inout` here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8178.d b/gcc/testsuite/gdc.test/fail_compilation/diag8178.d
index 491a625..00cac98 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8178.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8178.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag8178.d(14): Error: cannot modify manifest constant 's'
+fail_compilation/diag8178.d(14): Error: cannot modify manifest constant `s`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8318.d b/gcc/testsuite/gdc.test/fail_compilation/diag8318.d
index d319532..99dc6c4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8318.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8318.d
@@ -1,7 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag8318.d(13): Error: function diag8318.Bar8318.foo return type inference is not supported if may override base class function
+fail_compilation/diag8318.d(18): Error: function `diag8318.Bar8318.foo` return type inference is not supported if may override base class function
+fail_compilation/diag8318.d(23): Error: function `diag8318.C10021.makeI` return type inference is not supported if may override base class function
+fail_compilation/diag8318.d(31): Error: function `diag8318.Bar10195.baz` return type inference is not supported if may override base class function
+fail_compilation/diag8318.d(37): Error: function `diag8318.B14173.foo` does not override any function
+fail_compilation/diag8318.d(23): Error: class `diag8318.C10021` interface function `I10021 makeI()` is not implemented
+fail_compilation/diag8318.d(29): Error: class `diag8318.Bar10195` interface function `int baz()` is not implemented
---
*/
class Foo8318
@@ -13,22 +18,10 @@ class Bar8318 : Foo8318
override auto foo() { return "Bar.foo"; }
}
-/*
-TEST_OUTPUT:
----
-fail_compilation/diag8318.d(24): Error: function diag8318.C10021.makeI return type inference is not supported if may override base class function
----
-*/
interface I10021 { I10021 makeI(); }
class D10021 : I10021 { D10021 makeI() { return this; } }
class C10021 : I10021 { auto makeI() { return this; } }
-/*
-TEST_OUTPUT:
----
-fail_compilation/diag8318.d(38): Error: function diag8318.Bar10195.baz return type inference is not supported if may override base class function
----
-*/
interface Foo10195
{
int baz();
@@ -38,12 +31,6 @@ class Bar10195 : Foo10195
override auto baz() { return 1; }
}
-/*
-TEST_OUTPUT:
----
-fail_compilation/diag8318.d(50): Error: function diag8318.B14173.foo does not override any function
----
-*/
class A14173 {}
class B14173 : A14173
{
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8425.d b/gcc/testsuite/gdc.test/fail_compilation/diag8425.d
index 14dbb1c..a30881b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8425.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8425.d
@@ -1,12 +1,11 @@
/*
REQUIRED_ARGS: -m64 -o-
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/diag8425.d(13): Error: T in __vector(T) must be a static array, not void
-fail_compilation/diag8425.d(14): Error: 1 byte vector type __vector(void[1]) is not supported on this platform
-fail_compilation/diag8425.d(15): Error: 99 byte vector type __vector(void[99]) is not supported on this platform
-fail_compilation/diag8425.d(16): Error: vector type __vector(void*[4]) is not supported on this platform
+fail_compilation/diag8425.d(12): Error: T in __vector(T) must be a static array, not `void`
+fail_compilation/diag8425.d(13): Error: 1 byte vector type `__vector(void[1])` is not supported on this platform
+fail_compilation/diag8425.d(14): Error: 99 byte vector type `__vector(void[99])` is not supported on this platform
+fail_compilation/diag8425.d(15): Error: vector type `__vector(void*[4])` is not supported on this platform
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8510.d b/gcc/testsuite/gdc.test/fail_compilation/diag8510.d
index d1a897a..77660d0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8510.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8510.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag8510.d(10): Error: alias diag8510.a conflicts with alias diag8510.a at fail_compilation/diag8510.d(9)
-fail_compilation/diag8510.d(15): Error: alias diag8510.S.a conflicts with alias diag8510.S.a at fail_compilation/diag8510.d(14)
+fail_compilation/diag8510.d(10): Error: alias `diag8510.a` conflicts with alias `diag8510.a` at fail_compilation/diag8510.d(9)
+fail_compilation/diag8510.d(15): Error: alias `diag8510.S.a` conflicts with alias `diag8510.S.a` at fail_compilation/diag8510.d(14)
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8559.d b/gcc/testsuite/gdc.test/fail_compilation/diag8559.d
index 5dc2b9d..5da50f4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8559.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8559.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag8559.d(12): Error: void does not have a default initializer
-fail_compilation/diag8559.d(13): Error: function does not have a default initializer
+fail_compilation/diag8559.d(12): Error: `void` does not have a default initializer
+fail_compilation/diag8559.d(13): Error: `function` does not have a default initializer
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8648.d b/gcc/testsuite/gdc.test/fail_compilation/diag8648.d
index fa96d5c..f202fb3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8648.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8648.d
@@ -2,14 +2,14 @@
TEST_OUTPUT:
---
fail_compilation/diag8648.d(18): Error: undefined identifier `X`
-fail_compilation/diag8648.d(29): Error: template diag8648.foo cannot deduce function from argument types !()(Foo!(int, 1)), candidates are:
-fail_compilation/diag8648.d(18): diag8648.foo(T, n)(X!(T, n))
+fail_compilation/diag8648.d(29): Error: template `diag8648.foo` cannot deduce function from argument types `!()(Foo!(int, 1))`
+fail_compilation/diag8648.d(18): Candidate is: `foo(T, n)(X!(T, n))`
fail_compilation/diag8648.d(20): Error: undefined identifier `a`
-fail_compilation/diag8648.d(31): Error: template diag8648.bar cannot deduce function from argument types !()(Foo!(int, 1)), candidates are:
-fail_compilation/diag8648.d(20): diag8648.bar(T)(Foo!(T, a))
+fail_compilation/diag8648.d(31): Error: template `diag8648.bar` cannot deduce function from argument types `!()(Foo!(int, 1))`
+fail_compilation/diag8648.d(20): Candidate is: `bar(T)(Foo!(T, a))`
fail_compilation/diag8648.d(20): Error: undefined identifier `a`
-fail_compilation/diag8648.d(32): Error: template diag8648.bar cannot deduce function from argument types !()(Foo!(int, f)), candidates are:
-fail_compilation/diag8648.d(20): diag8648.bar(T)(Foo!(T, a))
+fail_compilation/diag8648.d(32): Error: template `diag8648.bar` cannot deduce function from argument types `!()(Foo!(int, f))`
+fail_compilation/diag8648.d(20): Candidate is: `bar(T)(Foo!(T, a))`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8684.d b/gcc/testsuite/gdc.test/fail_compilation/diag8684.d
new file mode 100644
index 0000000..acfee71
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8684.d
@@ -0,0 +1,16 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag8684.d(11): Error: found `;` when expecting `)`
+fail_compilation/diag8684.d(12): Error: semicolon expected, not `for`
+---
+*/
+
+int foo(int n, int m)
+{
+ int x = foo( 5, m;
+ for (int q=0; q<10; ++q){
+ ++q;
+ }
+ return 2;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8697.d b/gcc/testsuite/gdc.test/fail_compilation/diag8697.d
index b1a1008..a2abad5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8697.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8697.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag8697.d(10): Error: no property 'Invalid' for type 'diag8697.Base'
+fail_compilation/diag8697.d(10): Error: no property `Invalid` for type `diag8697.Base`
---
*/
interface InterBase : InterRoot { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8714.d b/gcc/testsuite/gdc.test/fail_compilation/diag8714.d
index 3a7ffd8..5a9d8d9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8714.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8714.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag8714.d(9): Error: function diag8714.foo circular dependency. Functions cannot be interpreted while being compiled
-fail_compilation/diag8714.d(15): called from here: foo("somestring")
+fail_compilation/diag8714.d(9): Error: function `diag8714.foo` circular dependency. Functions cannot be interpreted while being compiled
+fail_compilation/diag8714.d(15): called from here: `foo("somestring")`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8777.d b/gcc/testsuite/gdc.test/fail_compilation/diag8777.d
index f289da9..8dfac75 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8777.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8777.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag8777.d(12): Error: constructor diag8777.Foo1.this missing initializer for immutable field x
-fail_compilation/diag8777.d(12): Error: constructor diag8777.Foo1.this missing initializer for const field y
+fail_compilation/diag8777.d(12): Error: constructor `diag8777.Foo1.this` missing initializer for immutable field `x`
+fail_compilation/diag8777.d(12): Error: constructor `diag8777.Foo1.this` missing initializer for const field `y`
---
*/
class Foo1
@@ -15,8 +15,8 @@ class Foo1
/*
TEST_OUTPUT:
---
-fail_compilation/diag8777.d(25): Error: cannot modify immutable expression x
-fail_compilation/diag8777.d(28): Error: cannot modify const expression y
+fail_compilation/diag8777.d(25): Error: cannot modify `immutable` expression `x`
+fail_compilation/diag8777.d(28): Error: cannot modify `const` expression `y`
---
*/
void test2()
@@ -31,8 +31,8 @@ void test2()
/*
TEST_OUTPUT:
---
-fail_compilation/diag8777.d(42): Error: cannot remove key from immutable associative array hashx
-fail_compilation/diag8777.d(43): Error: cannot remove key from const associative array hashy
+fail_compilation/diag8777.d(42): Error: cannot remove key from `immutable` associative array `hashx`
+fail_compilation/diag8777.d(43): Error: cannot remove key from `const` associative array `hashy`
---
*/
immutable(int[int]) hashx;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8787.d b/gcc/testsuite/gdc.test/fail_compilation/diag8787.d
index dde80ab..c4ff6d2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8787.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8787.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag8787.d(10): Error: function diag8787.I.f function body only allowed in final functions in interface I
+fail_compilation/diag8787.d(10): Error: function `diag8787.I.f` function body only allowed in `final` functions in interface `I`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8894.d b/gcc/testsuite/gdc.test/fail_compilation/diag8894.d
index 9b66bf0..9e0dadd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8894.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8894.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag8894.d(16): Error: no property 'x' for type 'Foo'
-fail_compilation/diag8894.d(17): Error: no property 'y' for type 'Foo'
-fail_compilation/diag8894.d(18): Error: no property 'x' for type 'Foo'
-fail_compilation/diag8894.d(19): Error: no property 'x' for type 'Foo'
+fail_compilation/diag8894.d(16): Error: no property `x` for type `diag8894.Foo`
+fail_compilation/diag8894.d(17): Error: no property `y` for type `diag8894.Foo`
+fail_compilation/diag8894.d(18): Error: no property `x` for type `diag8894.Foo`
+fail_compilation/diag8894.d(19): Error: no property `x` for type `diag8894.Foo`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8928.d b/gcc/testsuite/gdc.test/fail_compilation/diag8928.d
index bdd1ae8..36bfc96 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8928.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8928.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag8928.d(18): Error: class diag8928.Z cannot implicitly generate a default ctor when base class diag8928.X is missing a default ctor
+fail_compilation/diag8928.d(18): Error: class `diag8928.Z` cannot implicitly generate a default constructor when base class `diag8928.X` is missing a default constructor
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9004.d b/gcc/testsuite/gdc.test/fail_compilation/diag9004.d
index 1985275..62fce32 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9004.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9004.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9004.d(21): Error: template diag9004.bar cannot deduce function from argument types !()(Foo!int, int), candidates are:
-fail_compilation/diag9004.d(14): diag9004.bar(FooT)(FooT foo, FooT.T x)
+fail_compilation/diag9004.d(21): Error: template `diag9004.bar` cannot deduce function from argument types `!()(Foo!int, int)`
+fail_compilation/diag9004.d(14): Candidate is: `bar(FooT)(FooT foo, FooT.T x)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9148.d b/gcc/testsuite/gdc.test/fail_compilation/diag9148.d
index 0a7707e..2e5cbc6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9148.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9148.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9148.d(19): Error: pure function 'diag9148.test9148a.foo' cannot access mutable static data 'g'
-fail_compilation/diag9148.d(23): Error: pure function 'diag9148.test9148a.bar' cannot access mutable static data 'g'
-fail_compilation/diag9148.d(24): Error: immutable function 'diag9148.test9148a.bar' cannot access mutable data 'x'
-fail_compilation/diag9148.d(31): Error: pure function 'diag9148.test9148a.S.foo' cannot access mutable static data 'g'
-fail_compilation/diag9148.d(35): Error: pure function 'diag9148.test9148a.S.bar' cannot access mutable static data 'g'
-fail_compilation/diag9148.d(36): Error: immutable function 'diag9148.test9148a.S.bar' cannot access mutable data 'x'
+fail_compilation/diag9148.d(19): Error: `pure` function `diag9148.test9148a.foo` cannot access mutable static data `g`
+fail_compilation/diag9148.d(23): Error: `pure` function `diag9148.test9148a.bar` cannot access mutable static data `g`
+fail_compilation/diag9148.d(24): Error: `immutable` function `diag9148.test9148a.bar` cannot access mutable data `x`
+fail_compilation/diag9148.d(31): Error: `pure` function `diag9148.test9148a.S.foo` cannot access mutable static data `g`
+fail_compilation/diag9148.d(35): Error: `pure` function `diag9148.test9148a.S.bar` cannot access mutable static data `g`
+fail_compilation/diag9148.d(36): Error: `immutable` function `diag9148.test9148a.S.bar` cannot access mutable data `x`
---
*/
void test9148a() pure
@@ -41,7 +41,8 @@ void test9148a() pure
/*
TEST_OUTPUT:
---
-fail_compilation/diag9148.d(53): Error: static function diag9148.test9148b.foo cannot access frame of function diag9148.test9148b
+fail_compilation/diag9148.d(54): Error: `static` function `diag9148.test9148b.foo` cannot access variable `x` in frame of function `diag9148.test9148b`
+fail_compilation/diag9148.d(51): `x` declared here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9191.d b/gcc/testsuite/gdc.test/fail_compilation/diag9191.d
index 50e5445..889d1fa 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9191.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9191.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9191.d(16): Error: function diag9191.C1.aaa does not override any function, did you mean to override 'diag9191.B1.aa'?
-fail_compilation/diag9191.d(21): Error: function diag9191.C2.aaa does not override any function
-fail_compilation/diag9191.d(31): Error: function diag9191.C3.foo does not override any function, did you mean to override 'diag9191.B2._foo'?
-fail_compilation/diag9191.d(36): Error: function diag9191.C4.toStringa does not override any function, did you mean to override 'object.Object.toString'?
+fail_compilation/diag9191.d(16): Error: function `void diag9191.C1.aaa()` does not override any function, did you mean to override `void diag9191.B1.aa()`?
+fail_compilation/diag9191.d(22): Error: function `diag9191.C2.aaa` does not override any function
+fail_compilation/diag9191.d(33): Error: function `void diag9191.C3.foo()` does not override any function, did you mean to override `void diag9191.B2._foo()`?
+fail_compilation/diag9191.d(38): Error: function `void diag9191.C4.toStringa()` does not override any function, did you mean to override `string object.Object.toString()`?
---
*/
@@ -14,11 +14,13 @@ class B1 { void aa(); }
class C1 : B1, I1
{
override void aaa();
+ void a() {}
}
class C2 : I1
{
override void aaa();
+ void a() {}
}
class B2
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9210a.d b/gcc/testsuite/gdc.test/fail_compilation/diag9210a.d
index ac3609f..d70f4f7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9210a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9210a.d
@@ -1,6 +1,5 @@
// REQUIRED_ARGS: -o-
-// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/diag9210b.d imports/diag9210c.d imports/diag9210stdcomplex.d imports/diag9210stdtraits.d
/*
TEST_OUTPUT:
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9247.d b/gcc/testsuite/gdc.test/fail_compilation/diag9247.d
index e226345..1519b10 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9247.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9247.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9247.d(11): Error: functions cannot return opaque type S by value
-fail_compilation/diag9247.d(12): Error: functions cannot return opaque type S by value
+fail_compilation/diag9247.d(11): Error: functions cannot return opaque type `S` by value
+fail_compilation/diag9247.d(12): Error: functions cannot return opaque type `S` by value
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9312.d b/gcc/testsuite/gdc.test/fail_compilation/diag9312.d
index 41c1360..94e3d3f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9312.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9312.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9312.d(10): Error: with expressions must be aggregate types or pointers to them, not `int`
+fail_compilation/diag9312.d(10): Error: `with` expressions must be aggregate types or pointers to them, not `int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9357.d b/gcc/testsuite/gdc.test/fail_compilation/diag9357.d
index f26b1c4..097c8de 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9357.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9357.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9357.d(14): Error: cannot implicitly convert expression `1.00000` of type `double` to `int`
-fail_compilation/diag9357.d(15): Error: cannot implicitly convert expression `10.0000` of type `double` to `int`
-fail_compilation/diag9357.d(16): Error: cannot implicitly convert expression `11.0000` of type `double` to `int`
-fail_compilation/diag9357.d(17): Error: cannot implicitly convert expression `99.0000` of type `double` to `int`
+fail_compilation/diag9357.d(14): Error: cannot implicitly convert expression `1.0` of type `double` to `int`
+fail_compilation/diag9357.d(15): Error: cannot implicitly convert expression `10.0` of type `double` to `int`
+fail_compilation/diag9357.d(16): Error: cannot implicitly convert expression `11.0` of type `double` to `int`
+fail_compilation/diag9357.d(17): Error: cannot implicitly convert expression `99.0` of type `double` to `int`
fail_compilation/diag9357.d(18): Error: cannot implicitly convert expression `1.04858e+06L` of type `real` to `int`
fail_compilation/diag9357.d(19): Error: cannot implicitly convert expression `1.04858e+06L` of type `real` to `int`
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9358.d b/gcc/testsuite/gdc.test/fail_compilation/diag9358.d
index d368ae2..5aea6b5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9358.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9358.d
@@ -2,8 +2,8 @@
TEST_OUTPUT:
---
fail_compilation/diag9358.d(12): Error: `x` must be of integral or string type, it is a `double`
-fail_compilation/diag9358.d(14): Error: case must be a string or an integral constant, not `1.1`
-fail_compilation/diag9358.d(15): Error: case must be a string or an integral constant, not `2.1`
+fail_compilation/diag9358.d(14): Error: `case` must be a `string` or an integral constant, not `1.1`
+fail_compilation/diag9358.d(15): Error: `case` must be a `string` or an integral constant, not `2.1`
---
*/
void main()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9398.d b/gcc/testsuite/gdc.test/fail_compilation/diag9398.d
index 67900c9..fe7e400 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9398.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9398.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9398.d(11): Error: incompatible types for ((f) : (s)): 'float' and 'string'
+fail_compilation/diag9398.d(11): Error: incompatible types for `(f) : (s)`: `float` and `string`
---
*/
void main()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9451.d b/gcc/testsuite/gdc.test/fail_compilation/diag9451.d
index a9121fc..ffec627 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9451.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9451.d
@@ -1,11 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9451.d(26): Error: cannot create instance of abstract class C2
-fail_compilation/diag9451.d(26): function 'void f1()' is not implemented
-fail_compilation/diag9451.d(26): function 'void f2(int)' is not implemented
-fail_compilation/diag9451.d(26): function 'void f2(float) const' is not implemented
-fail_compilation/diag9451.d(26): function 'int f2(float) pure' is not implemented
+fail_compilation/diag9451.d(26): Error: cannot create instance of abstract class `C2`
+fail_compilation/diag9451.d(26): function `void f1()` is not implemented
+fail_compilation/diag9451.d(26): function `void f2(int)` is not implemented
+fail_compilation/diag9451.d(26): function `void f2(float) const` is not implemented
+fail_compilation/diag9451.d(26): function `int f2(float) pure` is not implemented
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9620.d b/gcc/testsuite/gdc.test/fail_compilation/diag9620.d
index 5d50cb8..d99290c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9620.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9620.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9620.d(18): Error: pure function 'diag9620.main.bar' cannot call impure function 'diag9620.foo1'
-fail_compilation/diag9620.d(19): Error: pure function 'diag9620.main.bar' cannot call impure function 'diag9620.foo2!().foo2'
+fail_compilation/diag9620.d(18): Error: `pure` function `diag9620.main.bar` cannot call impure function `diag9620.foo1`
+fail_compilation/diag9620.d(19): Error: `pure` function `diag9620.main.bar` cannot call impure function `diag9620.foo2!().foo2`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9635.d b/gcc/testsuite/gdc.test/fail_compilation/diag9635.d
index 0e15aa2..fe142ad 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9635.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9635.d
@@ -2,8 +2,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9635.d(17): Error: need 'this' for 'i' of type 'int'
-fail_compilation/diag9635.d(18): Error: need 'this' for 'foo' of type 'pure nothrow @nogc @safe void()'
+fail_compilation/diag9635.d(17): Error: need `this` for `i` of type `int`
+fail_compilation/diag9635.d(18): Error: need `this` for `foo` of type `pure nothrow @nogc @safe void()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9679.d b/gcc/testsuite/gdc.test/fail_compilation/diag9679.d
index a19d99d..4496f0c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9679.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9679.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9679.d(11): Error: variable diag9679.main.n only parameters or foreach declarations can be ref
-fail_compilation/diag9679.d(12): Error: variable diag9679.main.n storage class 'auto' has no effect if type is not inferred, did you mean 'scope'?
+fail_compilation/diag9679.d(11): Error: variable `diag9679.main.n` only parameters or `foreach` declarations can be `ref`
+fail_compilation/diag9679.d(12): Error: variable `diag9679.main.n` storage class `auto` has no effect if type is not inferred, did you mean `scope`?
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9831.d b/gcc/testsuite/gdc.test/fail_compilation/diag9831.d
index 8882f66..b990ced 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9831.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9831.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9831.d(12): Error: function diag9831.main.__lambda1 cannot access frame of function D main
+fail_compilation/diag9831.d(13): Error: function `diag9831.main.__lambda3` cannot access variable `c` in frame of function `D main`
+fail_compilation/diag9831.d(11): `c` declared here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9861.d b/gcc/testsuite/gdc.test/fail_compilation/diag9861.d
index 6c7d89f..53faea1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9861.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9861.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9861.d(8): Error: no property 'epsilon' for type 'int'
-fail_compilation/diag9861.d(9): while looking for match for Foo!int
+fail_compilation/diag9861.d(8): Error: no property `epsilon` for type `int`
+fail_compilation/diag9861.d(9): while looking for match for `Foo!int`
---
*/
struct Foo(T, real x = T.epsilon) {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9880.d b/gcc/testsuite/gdc.test/fail_compilation/diag9880.d
index 9d893b8..597b94e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9880.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9880.d
@@ -1,7 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/diag9880.d(9): Error: template instance diag9880.foo!string does not match template declaration foo(T)(int) if (is(T == int))
+fail_compilation/diag9880.d(12): Error: template instance `diag9880.foo!string` does not match template declaration `foo(T)(int)`
+ with `T = string`
+ must satisfy the following constraint:
+` is(T == int)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9961.d b/gcc/testsuite/gdc.test/fail_compilation/diag9961.d
index 6b758e5..3eba735 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9961.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9961.d
@@ -2,9 +2,9 @@
TEST_OUTPUT:
---
fail_compilation/diag9961.d(11): Error: cannot implicitly convert expression `""` of type `string` to `int`
-fail_compilation/diag9961.d(14): Error: template instance diag9961.foo!int error instantiating
+fail_compilation/diag9961.d(14): Error: template instance `diag9961.foo!int` error instantiating
fail_compilation/diag9961.d(11): Error: cannot implicitly convert expression `""` of type `string` to `int`
-fail_compilation/diag9961.d(15): Error: template instance diag9961.foo!char error instantiating
+fail_compilation/diag9961.d(15): Error: template instance `diag9961.foo!char` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag_class_alloc.d b/gcc/testsuite/gdc.test/fail_compilation/diag_class_alloc.d
new file mode 100644
index 0000000..326d82e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag_class_alloc.d
@@ -0,0 +1,19 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag_class_alloc.d(15): Error: `new` allocator must be annotated with `@disabled`
+fail_compilation/diag_class_alloc.d(16): Deprecation: `new` allocator with non-empty parameter list is deprecated
+fail_compilation/diag_class_alloc.d(16): Deprecation: `new` allocator with function definition is deprecated
+---
+*/
+
+// This test exists to ensure class allocators and deallocators emit an appropriate error message.
+// This test can be deleted when class allocators and deallocators are removed from the language.
+
+class C
+{
+ new(size_t size) // error message
+ {
+ return malloc(size);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag_cstyle.d b/gcc/testsuite/gdc.test/fail_compilation/diag_cstyle.d
index 1b1cd0c..72343e7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag_cstyle.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag_cstyle.d
@@ -1,13 +1,12 @@
-// REQUIRED_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/diag_cstyle.d(14): Error: instead of C-style syntax, use D-style `int function(int) fp1`
-fail_compilation/diag_cstyle.d(15): Error: instead of C-style syntax, use D-style `int function(int)* fp3`
-fail_compilation/diag_cstyle.d(17): Error: instead of C-style syntax, use D-style `int function(int) FP`
-fail_compilation/diag_cstyle.d(19): Error: instead of C-style syntax, use D-style `int function() fp`
-fail_compilation/diag_cstyle.d(19): Deprecation: instead of C-style syntax, use D-style syntax `int[] arr`
-fail_compilation/diag_cstyle.d(21): Deprecation: instead of C-style syntax, use D-style syntax `string[] result`
+fail_compilation/diag_cstyle.d(13): Error: instead of C-style syntax, use D-style `int function(int) fp1`
+fail_compilation/diag_cstyle.d(14): Error: instead of C-style syntax, use D-style `int function(int)* fp3`
+fail_compilation/diag_cstyle.d(16): Error: instead of C-style syntax, use D-style `int function(int) FP`
+fail_compilation/diag_cstyle.d(18): Error: instead of C-style syntax, use D-style `int function() fp`
+fail_compilation/diag_cstyle.d(18): Error: instead of C-style syntax, use D-style `int[] arr`
+fail_compilation/diag_cstyle.d(20): Error: instead of C-style syntax, use D-style `string[] result`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag_debug_conditional.d b/gcc/testsuite/gdc.test/fail_compilation/diag_debug_conditional.d
new file mode 100644
index 0000000..99884c7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag_debug_conditional.d
@@ -0,0 +1,11 @@
+/**
+TEST_OUTPUT:
+---
+fail_compilation/diag_debug_conditional.d(1): Error: identifier or integer expected inside `debug(...)`, not `alias`
+fail_compilation/diag_debug_conditional.d(2): Error: identifier or integer expected inside `version(...)`, not `alias`
+fail_compilation/diag_debug_conditional.d(3): Error: declaration expected following attribute, not end of file
+---
+ */
+#line 1
+debug(alias)
+version(alias)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag_err1.d b/gcc/testsuite/gdc.test/fail_compilation/diag_err1.d
index 50e16b4..d1659c4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag_err1.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag_err1.d
@@ -2,14 +2,14 @@
TEST_OUTPUT:
---
fail_compilation/diag_err1.d(21): Error: undefined identifier `x`
-fail_compilation/diag_err1.d(21): while evaluating pragma(msg, [1, 2, x].length)
+fail_compilation/diag_err1.d(21): while evaluating `pragma(msg, [1, 2, x].length)`
fail_compilation/diag_err1.d(22): Error: undefined identifier `x`
fail_compilation/diag_err1.d(22): Error: undefined identifier `y`
-fail_compilation/diag_err1.d(22): while evaluating pragma(msg, (x + y).sizeof)
+fail_compilation/diag_err1.d(22): while evaluating `pragma(msg, (x + y).sizeof)`
fail_compilation/diag_err1.d(23): Error: undefined identifier `x`
-fail_compilation/diag_err1.d(23): while evaluating pragma(msg, (n += x).sizeof)
-fail_compilation/diag_err1.d(24): Error: incompatible types for ((s) ~ (n)): 'string' and 'int'
-fail_compilation/diag_err1.d(24): while evaluating pragma(msg, (s ~ n).sizeof)
+fail_compilation/diag_err1.d(23): while evaluating `pragma(msg, (n += x).sizeof)`
+fail_compilation/diag_err1.d(24): Error: incompatible types for `(s) ~ (n)`: `string` and `int`
+fail_compilation/diag_err1.d(24): while evaluating `pragma(msg, (s ~ n).sizeof)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag_funclit.d b/gcc/testsuite/gdc.test/fail_compilation/diag_funclit.d
new file mode 100644
index 0000000..b46c562
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag_funclit.d
@@ -0,0 +1,40 @@
+/**
+TEST_OUTPUT:
+---
+fail_compilation/diag_funclit.d(103): Error: function literal `__lambda1(x, y, z)` is not callable using argument types `()`
+fail_compilation/diag_funclit.d(103): missing argument for parameter #1: `x`
+fail_compilation/diag_funclit.d(106): Error: function literal `__lambda2(x, y, z)` is not callable using argument types `(int, string, int, int)`
+fail_compilation/diag_funclit.d(106): too many arguments, expected `3`, got `4`
+fail_compilation/diag_funclit.d(108): Error: function literal `__lambda3(x, y, string z = "Hello")` is not callable using argument types `(int, int, string, string)`
+fail_compilation/diag_funclit.d(108): too many arguments, expected `3`, got `4`
+fail_compilation/diag_funclit.d(110): Error: function literal `__lambda4(x, y, string z = "Hello")` is not callable using argument types `(int)`
+fail_compilation/diag_funclit.d(110): too few arguments, expected `3`, got `1`
+fail_compilation/diag_funclit.d(112): Error: function literal `__lambda5(x, y, z)` is not callable using argument types `(int)`
+fail_compilation/diag_funclit.d(112): too few arguments, expected `3`, got `1`
+fail_compilation/diag_funclit.d(115): Error: function literal `__lambda6(x, y, ...)` is not callable using argument types `(int)`
+fail_compilation/diag_funclit.d(115): too few arguments, expected `2`, got `1`
+fail_compilation/diag_funclit.d(117): Error: function literal `__lambda7(x, y, string z = "Hey", ...)` is not callable using argument types `(int)`
+fail_compilation/diag_funclit.d(117): too few arguments, expected `3`, got `1`
+---
+ */
+
+#line 100
+void main()
+{
+ // No argument
+ (x, y, z) { return 42; }();
+
+ // Too many args, non-variadic
+ (x, y, z) { return 42; }(42, "Hello", 42, 42);
+ // Too many args, non-variadic, default param
+ (x, y, string z = "Hello") { return x; }(42, 42, "Nope", "Noooope");
+ // Too few args, non-variadic
+ (x, y, string z = "Hello") { return x; }(42);
+ // Too few args, non-variadic, default param
+ (x, y, z) { return x; }(42);
+
+ // Too few args, variadic
+ (x, y, ...) { return x; }(42);
+ // Too few args, variadic, default param
+ (x, y, string z = "Hey", ...) { return x; }(42);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag_template_alias.d b/gcc/testsuite/gdc.test/fail_compilation/diag_template_alias.d
new file mode 100644
index 0000000..bbfb5a0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag_template_alias.d
@@ -0,0 +1,11 @@
+/**
+TEST_OUTPUT:
+---
+fail_compilation/diag_template_alias.d(1): Error: identifier expected for template `alias` parameter
+fail_compilation/diag_template_alias.d(1): Error: found `alias` when expecting `(`
+fail_compilation/diag_template_alias.d(1): Error: semicolon expected following function declaration
+fail_compilation/diag_template_alias.d(1): Error: declaration expected, not `(`
+---
+ */
+#line 1
+void func1(alias alias)() {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag_template_this.d b/gcc/testsuite/gdc.test/fail_compilation/diag_template_this.d
new file mode 100644
index 0000000..778f68e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag_template_this.d
@@ -0,0 +1,11 @@
+/**
+TEST_OUTPUT:
+---
+fail_compilation/diag_template_this.d(1): Error: identifier expected for template `this` parameter
+fail_compilation/diag_template_this.d(1): Error: found `this` when expecting `(`
+fail_compilation/diag_template_this.d(1): Error: semicolon expected following function declaration
+fail_compilation/diag_template_this.d(1): Error: declaration expected, not `(`
+---
+ */
+#line 1
+void func1(this this)() {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diagin.d b/gcc/testsuite/gdc.test/fail_compilation/diagin.d
new file mode 100644
index 0000000..a4dabee
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diagin.d
@@ -0,0 +1,25 @@
+/*
+PERMUTE_ARGS: -preview=in
+TEST_OUTPUT:
+---
+fail_compilation/diagin.d(14): Error: function `diagin.foo(in int)` is not callable using argument types `()`
+fail_compilation/diagin.d(14): missing argument for parameter #1: `in int`
+fail_compilation/diagin.d(16): Error: template `diagin.foo1` cannot deduce function from argument types `!()(bool[])`
+fail_compilation/diagin.d(20): Candidate is: `foo1(T)(in T v, string)`
+---
+ */
+
+void main ()
+{
+ foo();
+ bool[] lvalue;
+ foo1(lvalue);
+}
+
+void foo(in int) {}
+void foo1(T)(in T v, string) {}
+
+// Ensure that `in` has a unique mangling
+static assert(foo.mangleof == `_D6diagin3fooFIiZv`);
+static assert(foo1!int.mangleof == `_D6diagin__T4foo1TiZQiFNaNbNiNfIiAyaZv`);
+static assert(foo1!char.mangleof == `_D6diagin__T4foo1TaZQiFNaNbNiNfIaAyaZv`);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diaginref.d b/gcc/testsuite/gdc.test/fail_compilation/diaginref.d
new file mode 100644
index 0000000..2e83d76
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diaginref.d
@@ -0,0 +1,13 @@
+/*
+REQUIRED_ARGS: -preview=in
+TEST_OUTPUT:
+---
+fail_compilation/diaginref.d(11): Error: attribute `ref` is redundant with previously-applied `in`
+fail_compilation/diaginref.d(13): Error: attribute `in` cannot be added after `ref`: remove `ref`
+---
+ */
+
+void foo(in string) {}
+void foo1(in ref string) {}
+void foo2(T)(in T v, string) {}
+void foo3(T)(ref in T v, string) {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip22a.d b/gcc/testsuite/gdc.test/fail_compilation/dip22a.d
index 5bd2b5b..bf04a51 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/dip22a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/dip22a.d
@@ -1,10 +1,10 @@
/*
-REQUIRED_ARGS:
+EXTRA_FILES: imports/dip22a.d
TEST_OUTPUT:
---
-fail_compilation/dip22a.d(16): Error: no property `bar` for type `imports.dip22a.Klass`, did you mean `imports.dip22a.Klass.bar`?
-fail_compilation/dip22a.d(17): Error: no property `bar` for type `Struct`, did you mean `imports.dip22a.Struct.bar`?
-fail_compilation/dip22a.d(18): Error: undefined identifier `bar` in module `imports.dip22a`, did you mean function `bar`?
+fail_compilation/dip22a.d(16): Error: no property `bar` for type `imports.dip22a.Klass`
+fail_compilation/dip22a.d(17): Error: no property `bar` for type `imports.dip22a.Struct`
+fail_compilation/dip22a.d(18): Error: undefined identifier `bar` in module `imports.dip22a`
fail_compilation/dip22a.d(19): Error: no property `bar` for type `void`
fail_compilation/dip22a.d(20): Error: no property `bar` for type `int`
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip22b.d b/gcc/testsuite/gdc.test/fail_compilation/dip22b.d
index 9520180..0cd7247 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/dip22b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/dip22b.d
@@ -1,5 +1,5 @@
/*
-REQUIRED_ARGS:
+EXTRA_FILES: imports/dip22b.d imports/dip22c.d
TEST_OUTPUT:
---
fail_compilation/dip22b.d(12): Error: undefined identifier `Foo`, did you mean variable `foo`?
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip22e.d b/gcc/testsuite/gdc.test/fail_compilation/dip22e.d
index b1411b2..f118cf1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/dip22e.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/dip22e.d
@@ -1,5 +1,5 @@
/*
-REQUIRED_ARGS:
+EXTRA_FILES: imports/dip22d.d imports/dip22e.d
TEST_OUTPUT:
---
fail_compilation/dip22e.d(14): Error: undefined identifier `foo`, did you mean struct `Foo`?
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip25.d b/gcc/testsuite/gdc.test/fail_compilation/dip25.d
new file mode 100644
index 0000000..44fec37
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/dip25.d
@@ -0,0 +1,29 @@
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/dip25.d(17): Deprecation: returning `this.buffer[]` escapes a reference to parameter `this`
+fail_compilation/dip25.d(17): perhaps annotate the parameter with `return`
+fail_compilation/dip25.d(22): Error: returning `identity(x)` escapes a reference to local variable `x`
+fail_compilation/dip25.d(23): Deprecation: returning `identity(x)` escapes a reference to parameter `x`
+fail_compilation/dip25.d(23): perhaps annotate the parameter with `return`
+---
+*/
+struct Data
+{
+ char[256] buffer;
+ @property const(char)[] filename() const pure nothrow
+ {
+ return buffer[];
+ }
+}
+
+ref int identity(return ref int x) { return x; }
+ref int fun(return int x) { return identity(x); }
+ref int fun2(ref int x) { return identity(x); }
+
+void main()
+{
+ Data d;
+ const f = d.filename;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/disable_new.d b/gcc/testsuite/gdc.test/fail_compilation/disable_new.d
new file mode 100644
index 0000000..33ae32c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/disable_new.d
@@ -0,0 +1,25 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/disable_new.d(23): Error: cannot allocate `class C` with `new` because it is annotated with `@disable new()`
+fail_compilation/disable_new.d(24): Error: cannot allocate `struct S` with `new` because it is annotated with `@disable new()`
+---
+*/
+
+class C
+{
+ // force user of a type to use an external allocation strategy
+ @disable new();
+}
+
+struct S
+{
+ // force user of a type to use an external allocation strategy
+ @disable new();
+}
+
+void main()
+{
+ auto c = new C();
+ auto s = new S();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d b/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d
new file mode 100644
index 0000000..05c5d30
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d
@@ -0,0 +1,190 @@
+/*
+Informative error messages if the compiler generated destructor overrides a user-defined one.
+
+TEST_OUTPUT:
+---
+fail_compilation/dtor_attributes.d(118): Error: `pure` function `dtor_attributes.test1` cannot call impure destructor `dtor_attributes.Strict.~this`
+fail_compilation/dtor_attributes.d(113): generated `Strict.~this` is impure because of the following field's destructors:
+fail_compilation/dtor_attributes.d(111): - HasDtor member
+fail_compilation/dtor_attributes.d(103): impure `HasDtor.~this` is declared here
+fail_compilation/dtor_attributes.d(118): Error: `@safe` function `dtor_attributes.test1` cannot call `@system` destructor `dtor_attributes.Strict.~this`
+fail_compilation/dtor_attributes.d(113): `dtor_attributes.Strict.~this` is declared here
+fail_compilation/dtor_attributes.d(113): generated `Strict.~this` is @system because of the following field's destructors:
+fail_compilation/dtor_attributes.d(111): - HasDtor member
+fail_compilation/dtor_attributes.d(103): @system `HasDtor.~this` is declared here
+fail_compilation/dtor_attributes.d(118): Error: `@nogc` function `dtor_attributes.test1` cannot call non-@nogc destructor `dtor_attributes.Strict.~this`
+fail_compilation/dtor_attributes.d(113): generated `Strict.~this` is non-@nogc because of the following field's destructors:
+fail_compilation/dtor_attributes.d(111): - HasDtor member
+fail_compilation/dtor_attributes.d(103): non-@nogc `HasDtor.~this` is declared here
+fail_compilation/dtor_attributes.d(118): Error: destructor `dtor_attributes.Strict.~this` is not `nothrow`
+fail_compilation/dtor_attributes.d(113): generated `Strict.~this` is not nothrow because of the following field's destructors:
+fail_compilation/dtor_attributes.d(111): - HasDtor member
+fail_compilation/dtor_attributes.d(103): not nothrow `HasDtor.~this` is declared here
+fail_compilation/dtor_attributes.d(116): Error: `nothrow` function `dtor_attributes.test1` may throw
+---
+*/
+#line 100
+
+struct HasDtor
+{
+ ~this() {}
+}
+
+// The user-defined dtor is overriden by a generated dtor calling both
+// - HasDtor.~this
+// - Strict.~this
+struct Strict
+{
+ HasDtor member;
+
+ ~this() pure nothrow @nogc @safe {}
+}
+
+void test1() pure nothrow @nogc @safe
+{
+ Strict s;
+}
+
+/*
+Works for clases as well.
+
+TEST_OUTPUT:
+---
+fail_compilation/dtor_attributes.d(209): Error: `pure` function `dtor_attributes.test2` cannot call impure destructor `dtor_attributes.StrictClass.~this`
+fail_compilation/dtor_attributes.d(204): generated `StrictClass.~this` is impure because of the following field's destructors:
+fail_compilation/dtor_attributes.d(203): - HasDtor member
+fail_compilation/dtor_attributes.d(103): impure `HasDtor.~this` is declared here
+---
+*/
+#line 200
+
+class StrictClass
+{
+ HasDtor member;
+ ~this() pure {}
+}
+
+void test2() pure
+{
+ scope instance = new StrictClass();
+}
+
+/*
+Ignores members whose destructors are not called.
+
+TEST_OUTPUT:
+---
+fail_compilation/dtor_attributes.d(321): Error: `pure` function `dtor_attributes.test3` cannot call impure destructor `dtor_attributes.StrictStructRef.~this`
+fail_compilation/dtor_attributes.d(316): generated `StrictStructRef.~this` is impure because of the following field's destructors:
+fail_compilation/dtor_attributes.d(310): - HasDtor structMember
+fail_compilation/dtor_attributes.d(103): impure `HasDtor.~this` is declared here
+---
+*/
+#line 300
+
+class HasDtorClass
+{
+ ~this() {}
+}
+
+struct Empty {}
+
+struct StrictStructRef
+{
+ HasDtor structMember;
+ HasDtorClass classMember;
+ int intMember;
+ int[2] arrayMember;
+ Empty e;
+
+ ~this() pure {}
+}
+
+void test3() pure
+{
+ StrictStructRef structInstance;
+}
+
+/*
+Types from nested types work as well.
+
+TEST_OUTPUT:
+---
+fail_compilation/dtor_attributes.d(411): Error: `pure` function `dtor_attributes.test4` cannot call impure destructor `dtor_attributes.StrictNested.~this`
+fail_compilation/dtor_attributes.d(406): generated `StrictNested.~this` is impure because of the following field's destructors:
+fail_compilation/dtor_attributes.d(403): - HasDtor[4] arrayMember
+fail_compilation/dtor_attributes.d(103): impure `HasDtor.~this` is declared here
+---
+*/
+#line 400
+
+struct StrictNested
+{
+ HasDtor[4] arrayMember;
+ HasDtorClass[4] classMember;
+
+ ~this() pure {}
+}
+
+void test4() pure
+{
+ StrictNested structInstance;
+}
+
+/*
+Ignores member destructors when the user-defined one is permissive enough (e.g. both impure)
+
+TEST_OUTPUT:
+---
+fail_compilation/dtor_attributes.d(509): Error: `pure` function `dtor_attributes.test5` cannot call impure destructor `dtor_attributes.Permissive.~this`
+---
+*/
+#line 500
+
+struct Permissive
+{
+ HasDtor[4] arrayMember;
+ ~this() {}
+}
+
+void test5() pure
+{
+ Permissive structInstance;
+}
+
+/*
+Works with destructors generated through multiple layers
+
+TEST_OUTPUT:
+---
+fail_compilation/dtor_attributes.d(618): Error: `pure` function `dtor_attributes.test6` cannot call impure destructor `dtor_attributes.HasNestedDtor3.~this`
+fail_compilation/dtor_attributes.d(611): generated `HasNestedDtor3.~this` is impure because of the following field's destructors:
+fail_compilation/dtor_attributes.d(613): - HasNestedDtor2 member3
+fail_compilation/dtor_attributes.d(606): generated `HasNestedDtor2.~this` is impure because of the following field's destructors:
+fail_compilation/dtor_attributes.d(608): - HasNestedDtor1 member2
+fail_compilation/dtor_attributes.d(601): generated `HasNestedDtor1.~this` is impure because of the following field's destructors:
+fail_compilation/dtor_attributes.d(603): - HasDtor member1
+fail_compilation/dtor_attributes.d(103): impure `HasDtor.~this` is declared here
+---
+*/
+#line 600
+
+struct HasNestedDtor1
+{
+ HasDtor member1;
+}
+
+struct HasNestedDtor2
+{
+ HasNestedDtor1 member2;
+}
+
+struct HasNestedDtor3
+{
+ HasNestedDtor2 member3;
+}
+
+void test6() pure
+{
+ HasNestedDtor3 instance;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d b/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d
new file mode 100644
index 0000000..f6cab89
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d
@@ -0,0 +1,43 @@
+/*
+Informative error messages if the compiler inserted an optional destructor call into the constructor.
+
+REQUIRED_ARGS: -preview=dtorfields
+TEST_OUTPUT:
+---
+fail_compilation/dtorfields_attributes.d(117): Error: `pure` constructor `dtorfields_attributes.Strict.this` cannot call impure destructor `dtorfields_attributes.Strict.~this`
+fail_compilation/dtorfields_attributes.d(119): generated `Strict.~this` is impure because of the following field's destructors:
+fail_compilation/dtorfields_attributes.d(115): - HasDtor member
+fail_compilation/dtorfields_attributes.d(103): impure `HasDtor.~this` is declared here
+fail_compilation/dtorfields_attributes.d(117): Error: `@safe` constructor `dtorfields_attributes.Strict.this` cannot call `@system` destructor `dtorfields_attributes.Strict.~this`
+fail_compilation/dtorfields_attributes.d(119): `dtorfields_attributes.Strict.~this` is declared here
+fail_compilation/dtorfields_attributes.d(119): generated `Strict.~this` is @system because of the following field's destructors:
+fail_compilation/dtorfields_attributes.d(115): - HasDtor member
+fail_compilation/dtorfields_attributes.d(103): @system `HasDtor.~this` is declared here
+fail_compilation/dtorfields_attributes.d(117): Error: `@nogc` constructor `dtorfields_attributes.Strict.this` cannot call non-@nogc destructor `dtorfields_attributes.Strict.~this`
+fail_compilation/dtorfields_attributes.d(119): generated `Strict.~this` is non-@nogc because of the following field's destructors:
+fail_compilation/dtorfields_attributes.d(115): - HasDtor member
+fail_compilation/dtorfields_attributes.d(103): non-@nogc `HasDtor.~this` is declared here
+---
+*/
+#line 100
+
+struct HasDtor
+{
+ ~this()
+ {
+ // Enforce @system, ... just to be sure
+ __gshared int i;
+ if (++i)
+ throw new Exception(new immutable(char)[](10));
+ }
+}
+
+// The user-defined dtor matches the ctor attributes
+struct Strict
+{
+ HasDtor member;
+
+ this(int) pure @nogc @safe {} // nothrow doesn't generate dtor call
+
+ ~this() pure @nogc @safe {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/e15876_1.d b/gcc/testsuite/gdc.test/fail_compilation/e15876_1.d
new file mode 100644
index 0000000..33bee25
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/e15876_1.d
@@ -0,0 +1,15 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/e15876_1.d(15): Error: valid scope identifiers are `exit`, `failure`, or `success`, not `x`
+fail_compilation/e15876_1.d(16): Error: found `End of File` when expecting `)`
+fail_compilation/e15876_1.d(16): Error: found `End of File` instead of statement
+fail_compilation/e15876_1.d(16): Error: found `End of File` when expecting `}` following compound statement
+fail_compilation/e15876_1.d(16): Error: found `End of File` when expecting `]`
+fail_compilation/e15876_1.d(16): Error: no identifier for declarator `o[()
+{
+scope(exit) }
+]`
+---
+*/
+o[{scope(x
diff --git a/gcc/testsuite/gdc.test/fail_compilation/e15876_2.d b/gcc/testsuite/gdc.test/fail_compilation/e15876_2.d
new file mode 100644
index 0000000..10ff7d5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/e15876_2.d
@@ -0,0 +1,14 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/e15876_2.d(15): Error: identifier expected following `template`
+fail_compilation/e15876_2.d(15): Error: found `End of File` when expecting `}` following compound statement
+fail_compilation/e15876_2.d(15): Error: found `End of File` when expecting `]`
+fail_compilation/e15876_2.d(15): Error: no identifier for declarator `o[()
+{
+;
+}
+]`
+---
+*/
+o[{template
diff --git a/gcc/testsuite/gdc.test/fail_compilation/e15876_3.d b/gcc/testsuite/gdc.test/fail_compilation/e15876_3.d
new file mode 100644
index 0000000..ae5f77a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/e15876_3.d
@@ -0,0 +1,25 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/e15876_3.d(25): Error: unexpected `(` in declarator
+fail_compilation/e15876_3.d(25): Error: basic type expected, not `=`
+fail_compilation/e15876_3.d(26): Error: found `End of File` when expecting `(`
+fail_compilation/e15876_3.d(26): Error: found `End of File` instead of statement
+fail_compilation/e15876_3.d(26): Error: expression expected, not `End of File`
+fail_compilation/e15876_3.d(26): Error: found `End of File` when expecting `;` following `for` condition
+fail_compilation/e15876_3.d(26): Error: expression expected, not `End of File`
+fail_compilation/e15876_3.d(26): Error: found `End of File` when expecting `)`
+fail_compilation/e15876_3.d(26): Error: found `End of File` instead of statement
+fail_compilation/e15876_3.d(26): Error: found `End of File` when expecting `}` following compound statement
+fail_compilation/e15876_3.d(26): Error: found `End of File` when expecting `)`
+fail_compilation/e15876_3.d(26): Error: no identifier for declarator `d(_error_ = ()
+{
+for (; 0; 0)
+{
+}
+}
+)`
+fail_compilation/e15876_3.d(26): Error: semicolon expected following function declaration
+---
+*/
+d(={for
diff --git a/gcc/testsuite/gdc.test/fail_compilation/e15876_4.d b/gcc/testsuite/gdc.test/fail_compilation/e15876_4.d
new file mode 100644
index 0000000..6f46633
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/e15876_4.d
@@ -0,0 +1,23 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/e15876_4.d(23): Error: found `)` when expecting `(`
+fail_compilation/e15876_4.d(24): Error: found `End of File` when expecting `(`
+fail_compilation/e15876_4.d(24): Error: found `End of File` instead of statement
+fail_compilation/e15876_4.d(24): Error: expression expected, not `End of File`
+fail_compilation/e15876_4.d(24): Error: found `End of File` when expecting `;` following `for` condition
+fail_compilation/e15876_4.d(24): Error: expression expected, not `End of File`
+fail_compilation/e15876_4.d(24): Error: found `End of File` when expecting `)`
+fail_compilation/e15876_4.d(24): Error: found `End of File` instead of statement
+fail_compilation/e15876_4.d(24): Error: found `End of File` when expecting `}` following compound statement
+fail_compilation/e15876_4.d(24): Error: found `End of File` when expecting `)`
+fail_compilation/e15876_4.d(24): Error: no identifier for declarator `typeof(()
+{
+for (; 0; 0)
+{
+}
+}
+)`
+---
+*/
+typeof){for
diff --git a/gcc/testsuite/gdc.test/fail_compilation/e15876_5.d b/gcc/testsuite/gdc.test/fail_compilation/e15876_5.d
new file mode 100644
index 0000000..5b65b1b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/e15876_5.d
@@ -0,0 +1,15 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/e15876_5.d(16): Error: basic type expected, not `End of File`
+fail_compilation/e15876_5.d(16): Error: semicolon expected to close `alias` declaration
+fail_compilation/e15876_5.d(16): Error: found `End of File` when expecting `}` following compound statement
+fail_compilation/e15876_5.d(16): Error: found `End of File` when expecting `]`
+fail_compilation/e15876_5.d(16): Error: no identifier for declarator `p[()
+{
+alias ;
+}
+]`
+---
+*/
+p[{alias
diff --git a/gcc/testsuite/gdc.test/fail_compilation/e15876_6.d b/gcc/testsuite/gdc.test/fail_compilation/e15876_6.d
new file mode 100644
index 0000000..7547b38
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/e15876_6.d
@@ -0,0 +1,7 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/e15876_6.d(7): Error: identifier expected following `(type)`.
+---
+*/
+auto unaryExParseError = immutable(int).;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/enum9921.d b/gcc/testsuite/gdc.test/fail_compilation/enum9921.d
index 54c76b9..90d8802 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/enum9921.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/enum9921.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/enum9921.d(9): Error: enum enum9921.X base type must not be void
-fail_compilation/enum9921.d(11): Error: enum enum9921.Z base type must not be void
+fail_compilation/enum9921.d(9): Error: enum `enum9921.X` base type must not be `void`
+fail_compilation/enum9921.d(11): Error: enum `enum9921.Z` base type must not be `void`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/extra-files/a14446.d b/gcc/testsuite/gdc.test/fail_compilation/extra-files/a14446.d
deleted file mode 100644
index 5e19c1e..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/extra-files/a14446.d
+++ /dev/null
@@ -1,6 +0,0 @@
-module a14446;
-
-struct CDBMaker
-{
- import ice14446;
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10.d b/gcc/testsuite/gdc.test/fail_compilation/fail10.d
index 9d73537..48901a1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10.d(18): Error: mixin Foo!y cannot resolve forward reference
+fail_compilation/fail10.d(18): Error: mixin `Foo!y` cannot resolve forward reference
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail100.d b/gcc/testsuite/gdc.test/fail_compilation/fail100.d
index 1dd8050..a8189ec 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail100.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail100.d
@@ -5,8 +5,8 @@ fail_compilation/fail100.d(24): Error: cannot implicitly convert expression `f`
---
*/
-// Issue 85 - Array of classes doesn't function as array of interfaces
-
+// https://issues.dlang.org/show_bug.cgi?id=85
+// Array of classes doesn't function as array of interfaces
interface I
{
I[] foo();
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10082.d b/gcc/testsuite/gdc.test/fail_compilation/fail10082.d
index fd30801..8a3d2fb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10082.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10082.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10082.d(24): Error: cannot infer type from overloaded function symbol &foo
+fail_compilation/fail10082.d(24): Error: cannot infer type from overloaded function symbol `&foo`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail101.d b/gcc/testsuite/gdc.test/fail_compilation/fail101.d
index 35d23e3..0f6e0b3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail101.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail101.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail101.d(8): Error: cannot implicitly convert expression `1` of type `int` to `creal`
+fail_compilation/fail101.d(9): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
+fail_compilation/fail101.d(9): Error: cannot implicitly convert expression `1` of type `int` to `creal`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10102.d b/gcc/testsuite/gdc.test/fail_compilation/fail10102.d
index 2c974ea..4847413 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10102.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10102.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10102.d(48): Error: variable fail10102.main.m default construction is disabled for type NotNull!(int*)
-fail_compilation/fail10102.d(49): Error: variable fail10102.main.a default construction is disabled for type NotNull!(int*)[3]
-fail_compilation/fail10102.d(50): Error: default construction is disabled for type NotNull!(int*)
+fail_compilation/fail10102.d(48): Error: variable `fail10102.main.m` default construction is disabled for type `NotNull!(int*)`
+fail_compilation/fail10102.d(49): Error: variable `fail10102.main.a` default construction is disabled for type `NotNull!(int*)[3]`
+fail_compilation/fail10102.d(50): Error: default construction is disabled for type `NotNull!(int*)`
fail_compilation/fail10102.d(51): Error: field `S.m` must be initialized because it has no default constructor
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10115.d b/gcc/testsuite/gdc.test/fail_compilation/fail10115.d
index e94ae87..4d766cf 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10115.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10115.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10115.d(35): Error: cannot have out parameter of type S because the default construction is disabled
-fail_compilation/fail10115.d(35): Error: cannot have out parameter of type E because the default construction is disabled
-fail_compilation/fail10115.d(35): Error: cannot have out parameter of type U because the default construction is disabled
-fail_compilation/fail10115.d(40): Error: struct fail10115.S default construction is disabled
-fail_compilation/fail10115.d(41): Error: struct fail10115.S default construction is disabled
-fail_compilation/fail10115.d(42): Error: union fail10115.U default construction is disabled
+fail_compilation/fail10115.d(35): Error: cannot have `out` parameter of type `S` because the default construction is disabled
+fail_compilation/fail10115.d(35): Error: cannot have `out` parameter of type `E` because the default construction is disabled
+fail_compilation/fail10115.d(35): Error: cannot have `out` parameter of type `U` because the default construction is disabled
+fail_compilation/fail10115.d(40): Error: struct `fail10115.S` default construction is disabled
+fail_compilation/fail10115.d(41): Error: struct `fail10115.S` default construction is disabled
+fail_compilation/fail10115.d(42): Error: union `fail10115.U` default construction is disabled
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10254.d b/gcc/testsuite/gdc.test/fail_compilation/fail10254.d
index 0d402e1..8ad8fde 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10254.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10254.d
@@ -1,10 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10254.d(18): Error: pure function 'fail10254.foo' cannot call impure constructor 'fail10254.C.this'
-fail_compilation/fail10254.d(18): Error: @safe function 'fail10254.foo' cannot call @system constructor 'fail10254.C.this'
-fail_compilation/fail10254.d(19): Error: pure function 'fail10254.foo' cannot call impure constructor 'fail10254.S.this'
-fail_compilation/fail10254.d(19): Error: @safe function 'fail10254.foo' cannot call @system constructor 'fail10254.S.this'
+fail_compilation/fail10254.d(20): Error: `pure` function `fail10254.foo` cannot call impure constructor `fail10254.C.this`
+fail_compilation/fail10254.d(20): Error: `@safe` function `fail10254.foo` cannot call `@system` constructor `fail10254.C.this`
+fail_compilation/fail10254.d(15): `fail10254.C.this` is declared here
+fail_compilation/fail10254.d(21): Error: `pure` function `fail10254.foo` cannot call impure constructor `fail10254.S.this`
+fail_compilation/fail10254.d(21): Error: `@safe` function `fail10254.foo` cannot call `@system` constructor `fail10254.S.this`
+fail_compilation/fail10254.d(16): `fail10254.S.this` is declared here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10277.d b/gcc/testsuite/gdc.test/fail_compilation/fail10277.d
index 6173d37..11ad9d5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10277.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10277.d
@@ -1,28 +1,28 @@
+// EXTRA_FILES: imports/fail10277.d
module fail10227;
-
/*
TEST_OUTPUT:
---
-fail_compilation/imports/fail10277.d(3): Error: class TypeInfo only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(4): Error: class TypeInfo_Class only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(5): Error: class TypeInfo_Interface only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(6): Error: class TypeInfo_Struct only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(8): Error: class TypeInfo_Pointer only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(9): Error: class TypeInfo_Array only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(10): Error: class TypeInfo_AssociativeArray only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(11): Error: class TypeInfo_Enum only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(12): Error: class TypeInfo_Function only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(13): Error: class TypeInfo_Delegate only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(14): Error: class TypeInfo_Tuple only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(15): Error: class TypeInfo_Const only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(16): Error: class TypeInfo_Invariant only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(17): Error: class TypeInfo_Shared only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(18): Error: class TypeInfo_Inout only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(19): Error: class TypeInfo_Vector only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(20): Error: class Object only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(21): Error: class Throwable only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(22): Error: class Exception only object.d can define this reserved class name
-fail_compilation/imports/fail10277.d(23): Error: class Error only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(3): Error: class `TypeInfo` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(4): Error: class `TypeInfo_Class` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(5): Error: class `TypeInfo_Interface` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(6): Error: class `TypeInfo_Struct` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(8): Error: class `TypeInfo_Pointer` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(9): Error: class `TypeInfo_Array` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(10): Error: class `TypeInfo_AssociativeArray` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(11): Error: class `TypeInfo_Enum` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(12): Error: class `TypeInfo_Function` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(13): Error: class `TypeInfo_Delegate` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(14): Error: class `TypeInfo_Tuple` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(15): Error: class `TypeInfo_Const` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(16): Error: class `TypeInfo_Invariant` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(17): Error: class `TypeInfo_Shared` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(18): Error: class `TypeInfo_Inout` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(19): Error: class `TypeInfo_Vector` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(20): Error: class `Object` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(21): Error: class `Throwable` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(22): Error: class `Exception` only object.d can define this reserved class name
+fail_compilation/imports/fail10277.d(23): Error: class `Error` only object.d can define this reserved class name
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10299.d b/gcc/testsuite/gdc.test/fail_compilation/fail10299.d
index 29475aa..f0eaeba 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10299.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10299.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10299.d(11): Error: foo!string is not an lvalue
+fail_compilation/fail10299.d(11): Error: `foo!string` is not an lvalue and cannot be modified
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail104.d b/gcc/testsuite/gdc.test/fail_compilation/fail104.d
index 2111844..e9190de 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail104.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail104.d
@@ -1,4 +1,5 @@
-// Issue 76 - Using a non-template struct as a template
+// https://issues.dlang.org/show_bug.cgi?id=76
+// Using a non-template struct as a template
// Compiling leads to "Assertion failure: 's->parent' on line 1694 in file
// 'template.c'"
/*
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10481.d b/gcc/testsuite/gdc.test/fail_compilation/fail10481.d
index 878cbe8..a6657c0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10481.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10481.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/fail10481.d(11): Error: undefined identifier `T1`, did you mean alias `T0`?
-fail_compilation/fail10481.d(15): Error: cannot infer type from template instance get!(A)
+fail_compilation/fail10481.d(15): Error: cannot infer type from template instance `get!(A)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail105.d b/gcc/testsuite/gdc.test/fail_compilation/fail105.d
index 8702cac..0e13e36 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail105.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail105.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail105.d(11): Error: cannot cast "bar" to int at compile time
+fail_compilation/fail105.d(11): Error: cannot cast `"bar"` to `int` at compile time
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10528.d b/gcc/testsuite/gdc.test/fail_compilation/fail10528.d
index 067e83c..38c5a23 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10528.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10528.d
@@ -1,14 +1,15 @@
/*
+EXTRA_FILES: imports/a10528.d
TEST_OUTPUT:
---
-fail_compilation/fail10528.d(19): Error: undefined identifier `a`
-fail_compilation/fail10528.d(20): Error: undefined identifier `a` in module `a10528`, did you mean variable `a`?
-fail_compilation/fail10528.d(22): Error: undefined identifier `b`
-fail_compilation/fail10528.d(23): Error: undefined identifier `b` in module `a10528`, did you mean enum member `b`?
-fail_compilation/fail10528.d(25): Error: no property `c` for type `S`, did you mean `a10528.S.c`?
-fail_compilation/fail10528.d(26): Error: no property `c` for type `S`, did you mean `a10528.S.c`?
-fail_compilation/fail10528.d(28): Error: no property `d` for type `a10528.C`, did you mean `a10528.C.d`?
-fail_compilation/fail10528.d(29): Error: no property `d` for type `a10528.C`, did you mean `a10528.C.d`?
+fail_compilation/fail10528.d(20): Error: undefined identifier `a`
+fail_compilation/fail10528.d(21): Error: undefined identifier `a` in module `a10528`
+fail_compilation/fail10528.d(23): Error: undefined identifier `b`
+fail_compilation/fail10528.d(24): Error: undefined identifier `b` in module `a10528`
+fail_compilation/fail10528.d(26): Error: no property `c` for type `a10528.S`
+fail_compilation/fail10528.d(27): Error: no property `c` for type `a10528.S`
+fail_compilation/fail10528.d(29): Error: no property `d` for type `a10528.C`
+fail_compilation/fail10528.d(30): Error: no property `d` for type `a10528.C`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10534.d b/gcc/testsuite/gdc.test/fail_compilation/fail10534.d
index 2516135..fac37f4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10534.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10534.d
@@ -1,22 +1,22 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10534.d(28): Error: 'a' is not of arithmetic type, it is a int delegate()
-fail_compilation/fail10534.d(28): Error: 'b' is not of arithmetic type, it is a int delegate()
-fail_compilation/fail10534.d(29): Error: 'a' is not of arithmetic type, it is a int delegate()
-fail_compilation/fail10534.d(29): Error: 'b' is not of arithmetic type, it is a int delegate()
-fail_compilation/fail10534.d(30): Error: 'a' is not of arithmetic type, it is a int delegate()
-fail_compilation/fail10534.d(30): Error: 'b' is not of arithmetic type, it is a int delegate()
-fail_compilation/fail10534.d(31): Error: 'a' is not of arithmetic type, it is a int delegate()
-fail_compilation/fail10534.d(31): Error: 'b' is not of arithmetic type, it is a int delegate()
-fail_compilation/fail10534.d(36): Error: 'a' is not of arithmetic type, it is a int function()
-fail_compilation/fail10534.d(36): Error: 'b' is not of arithmetic type, it is a int function()
-fail_compilation/fail10534.d(37): Error: 'a' is not of arithmetic type, it is a int function()
-fail_compilation/fail10534.d(37): Error: 'b' is not of arithmetic type, it is a int function()
-fail_compilation/fail10534.d(38): Error: 'a' is not of arithmetic type, it is a int function()
-fail_compilation/fail10534.d(38): Error: 'b' is not of arithmetic type, it is a int function()
-fail_compilation/fail10534.d(39): Error: 'a' is not of arithmetic type, it is a int function()
-fail_compilation/fail10534.d(39): Error: 'b' is not of arithmetic type, it is a int function()
+fail_compilation/fail10534.d(28): Error: `a` is not of arithmetic type, it is a `int delegate()`
+fail_compilation/fail10534.d(28): Error: `b` is not of arithmetic type, it is a `int delegate()`
+fail_compilation/fail10534.d(29): Error: `a` is not of arithmetic type, it is a `int delegate()`
+fail_compilation/fail10534.d(29): Error: `b` is not of arithmetic type, it is a `int delegate()`
+fail_compilation/fail10534.d(30): Error: `a` is not of arithmetic type, it is a `int delegate()`
+fail_compilation/fail10534.d(30): Error: `b` is not of arithmetic type, it is a `int delegate()`
+fail_compilation/fail10534.d(31): Error: `a` is not of arithmetic type, it is a `int delegate()`
+fail_compilation/fail10534.d(31): Error: `b` is not of arithmetic type, it is a `int delegate()`
+fail_compilation/fail10534.d(36): Error: `a` is not of arithmetic type, it is a `int function()`
+fail_compilation/fail10534.d(36): Error: `b` is not of arithmetic type, it is a `int function()`
+fail_compilation/fail10534.d(37): Error: `a` is not of arithmetic type, it is a `int function()`
+fail_compilation/fail10534.d(37): Error: `b` is not of arithmetic type, it is a `int function()`
+fail_compilation/fail10534.d(38): Error: `a` is not of arithmetic type, it is a `int function()`
+fail_compilation/fail10534.d(38): Error: `b` is not of arithmetic type, it is a `int function()`
+fail_compilation/fail10534.d(39): Error: `a` is not of arithmetic type, it is a `int function()`
+fail_compilation/fail10534.d(39): Error: `b` is not of arithmetic type, it is a `int function()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail106.d b/gcc/testsuite/gdc.test/fail_compilation/fail106.d
index f6dc2ea..ba9f7dd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail106.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail106.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail106.d(12): Error: cannot modify immutable expression 'C'
+fail_compilation/fail106.d(12): Error: cannot modify `immutable` expression `"ABC"[2]`
---
*/
-// Issue 239 - Internal error: changing string literal elements
-
+// https://issues.dlang.org/show_bug.cgi?id=239
+// Internal error: changing string literal elements
void main()
{
"ABC"[2] = 's';
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10630.d b/gcc/testsuite/gdc.test/fail_compilation/fail10630.d
index 738bdd1..35feaea 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10630.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10630.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10630.d(12): Error: cannot have out parameter of type S because the default construction is disabled
+fail_compilation/fail10630.d(12): Error: cannot have `out` parameter of type `S` because the default construction is disabled
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10666.d b/gcc/testsuite/gdc.test/fail_compilation/fail10666.d
index 2e1747d..9fe28d0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10666.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10666.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10666.d(16): Error: variable fail10666.foo10666.s1 has scoped destruction, cannot build closure
+fail_compilation/fail10666.d(16): Error: variable `fail10666.foo10666.s1` has scoped destruction, cannot build closure
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10806.d b/gcc/testsuite/gdc.test/fail_compilation/fail10806.d
new file mode 100644
index 0000000..48f3537
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10806.d
@@ -0,0 +1,18 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail10806.d(12): Error: function `fail10806.Class.clone` incompatible covariant types `First()` and `Second()`
+---
+*/
+
+interface First { First clone(); }
+interface Second { Second clone(); void call(); }
+
+class Class : First, Second {
+ override Class clone() { return this; }
+ override void call() { }
+}
+
+void main() {
+ (cast(Second) new Class).clone().call();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail109.d b/gcc/testsuite/gdc.test/fail_compilation/fail109.d
index 3e379c3..3419079 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail109.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail109.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail109.d(12): Error: enum member fail109.Bool.Unknown initialization with `Bool.True+1` causes overflow for type `bool`
+fail_compilation/fail109.d(12): Error: enum member `fail109.Bool.Unknown` initialization with `Bool.True+1` causes overflow for type `bool`
---
*/
@@ -12,11 +12,11 @@ enum Bool : bool
Unknown
}
-/* Bugzilla 11088
+/* https://issues.dlang.org/show_bug.cgi?id=11088
TEST_OUTPUT:
---
-fail_compilation/fail109.d(25): Error: enum member fail109.E.B initialization with `E.A+1` causes overflow for type `int`
-fail_compilation/fail109.d(31): Error: enum member fail109.E1.B initialization with `E1.A+1` causes overflow for type `short`
+fail_compilation/fail109.d(25): Error: enum member `fail109.E.B` initialization with `E.A+1` causes overflow for type `int`
+fail_compilation/fail109.d(31): Error: enum member `fail109.E1.B` initialization with `E1.A+1` causes overflow for type `short`
---
*/
enum E
@@ -31,11 +31,11 @@ enum E1 : short
B
}
-/* Bugzilla 14950
+/* https://issues.dlang.org/show_bug.cgi?id=14950
TEST_OUTPUT:
---
-fail_compilation/fail109.d(50): Deprecation: Comparison between different enumeration types `B` and `C`; If this behavior is intended consider using `std.conv.asOriginalType`
-fail_compilation/fail109.d(50): Error: enum member fail109.B.end initialization with `B.start+1` causes overflow for type `C`
+fail_compilation/fail109.d(50): Error: Comparison between different enumeration types `B` and `C`; If this behavior is intended consider using `std.conv.asOriginalType`
+fail_compilation/fail109.d(50): Error: enum member `fail109.B.end` initialization with `B.start+1` causes overflow for type `C`
---
*/
enum C
@@ -50,7 +50,7 @@ enum B
end
}
-/* Bugzilla 11849
+/* https://issues.dlang.org/show_bug.cgi?id=11849
TEST_OUTPUT:
---
fail_compilation/fail109.d(72): Error: enum member `fail109.RegValueType1a.Unknown` is forward referenced looking for `.max`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10905.d b/gcc/testsuite/gdc.test/fail_compilation/fail10905.d
index 6181d94..4f243ff 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10905.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10905.d
@@ -1,4 +1,5 @@
/*
+REQUIRED_ARGS: -m64
TEST_OUTPUT:
---
fail_compilation/fail10905.d(20): Error: incompatible types for `(this.x) == (cast(const(__vector(long[2])))cast(__vector(long[2]))1L)`: both operands are of type `const(__vector(long[2]))`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10947.d b/gcc/testsuite/gdc.test/fail_compilation/fail10947.d
index da84780..9b2de96 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10947.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10947.d
@@ -1,15 +1,15 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10947.d(21): Error: cannot have immutable out parameter of type immutable(S)
-fail_compilation/fail10947.d(22): Error: cannot have immutable out parameter of type immutable(S)
-fail_compilation/fail10947.d(23): Error: cannot have immutable out parameter of type immutable(S)
-fail_compilation/fail10947.d(25): Error: cannot have const out parameter of type const(S)
-fail_compilation/fail10947.d(26): Error: cannot have const out parameter of type const(S)
-fail_compilation/fail10947.d(27): Error: cannot have const out parameter of type const(S)
-fail_compilation/fail10947.d(29): Error: cannot have inout out parameter of type inout(S)
-fail_compilation/fail10947.d(30): Error: cannot have inout out parameter of type inout(S)
-fail_compilation/fail10947.d(31): Error: cannot have inout out parameter of type inout(S)
+fail_compilation/fail10947.d(21): Error: cannot have `immutable out` parameter of type `immutable(S)`
+fail_compilation/fail10947.d(22): Error: cannot have `immutable out` parameter of type `immutable(S)`
+fail_compilation/fail10947.d(23): Error: cannot have `immutable out` parameter of type `immutable(S)`
+fail_compilation/fail10947.d(25): Error: cannot have `const out` parameter of type `const(S)`
+fail_compilation/fail10947.d(26): Error: cannot have `const out` parameter of type `const(S)`
+fail_compilation/fail10947.d(27): Error: cannot have `const out` parameter of type `const(S)`
+fail_compilation/fail10947.d(29): Error: cannot have `inout out` parameter of type `inout(S)`
+fail_compilation/fail10947.d(30): Error: cannot have `inout out` parameter of type `inout(S)`
+fail_compilation/fail10947.d(31): Error: cannot have `inout out` parameter of type `inout(S)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10964.d b/gcc/testsuite/gdc.test/fail_compilation/fail10964.d
index 7b7c826..de3673f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10964.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10964.d
@@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10964.d(28): Error: function `fail10964.S.__postblit` is not nothrow
-fail_compilation/fail10964.d(29): Error: function `fail10964.S.__postblit` is not nothrow
-fail_compilation/fail10964.d(30): Error: function `fail10964.S.__postblit` is not nothrow
-fail_compilation/fail10964.d(33): Error: function `fail10964.S.__postblit` is not nothrow
-fail_compilation/fail10964.d(34): Error: function `fail10964.S.__postblit` is not nothrow
-fail_compilation/fail10964.d(35): Error: function `fail10964.S.__postblit` is not nothrow
-fail_compilation/fail10964.d(22): Error: nothrow function `fail10964.foo` may throw
+fail_compilation/fail10964.d(28): Error: function `fail10964.S.__postblit` is not `nothrow`
+fail_compilation/fail10964.d(29): Error: function `fail10964.S.__postblit` is not `nothrow`
+fail_compilation/fail10964.d(30): Error: function `fail10964.S.__postblit` is not `nothrow`
+fail_compilation/fail10964.d(33): Error: function `fail10964.S.__postblit` is not `nothrow`
+fail_compilation/fail10964.d(34): Error: function `fail10964.S.__postblit` is not `nothrow`
+fail_compilation/fail10964.d(35): Error: function `fail10964.S.__postblit` is not `nothrow`
+fail_compilation/fail10964.d(22): Error: `nothrow` function `fail10964.foo` may throw
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d
index 257d739..06e0687 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d
@@ -1,18 +1,24 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10968.d(33): Error: pure function 'fail10968.bar' cannot call impure function 'fail10968.SA.__postblit'
-fail_compilation/fail10968.d(33): Error: @safe function 'fail10968.bar' cannot call @system function 'fail10968.SA.__postblit'
-fail_compilation/fail10968.d(34): Error: pure function 'fail10968.bar' cannot call impure function 'fail10968.SA.__postblit'
-fail_compilation/fail10968.d(34): Error: @safe function 'fail10968.bar' cannot call @system function 'fail10968.SA.__postblit'
-fail_compilation/fail10968.d(35): Error: pure function 'fail10968.bar' cannot call impure function 'fail10968.SA.__postblit'
-fail_compilation/fail10968.d(35): Error: @safe function 'fail10968.bar' cannot call @system function 'fail10968.SA.__postblit'
-fail_compilation/fail10968.d(38): Error: pure function 'fail10968.bar' cannot call impure function 'fail10968.SA.__postblit'
-fail_compilation/fail10968.d(38): Error: @safe function 'fail10968.bar' cannot call @system function 'fail10968.SA.__postblit'
-fail_compilation/fail10968.d(39): Error: pure function 'fail10968.bar' cannot call impure function 'fail10968.SA.__postblit'
-fail_compilation/fail10968.d(39): Error: @safe function 'fail10968.bar' cannot call @system function 'fail10968.SA.__postblit'
-fail_compilation/fail10968.d(40): Error: pure function 'fail10968.bar' cannot call impure function 'fail10968.SA.__postblit'
-fail_compilation/fail10968.d(40): Error: @safe function 'fail10968.bar' cannot call @system function 'fail10968.SA.__postblit'
+fail_compilation/fail10968.d(39): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(39): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(40): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(40): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(41): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(41): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(44): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(45): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(45): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(46): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(46): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here
---
*/
@@ -43,12 +49,12 @@ void bar() pure @safe
/*
TEST_OUTPUT:
---
-fail_compilation/fail10968.d(66): Error: struct fail10968.SD is not copyable because it is annotated with `@disable`
-fail_compilation/fail10968.d(67): Error: struct fail10968.SD is not copyable because it is annotated with `@disable`
-fail_compilation/fail10968.d(68): Error: struct fail10968.SD is not copyable because it is annotated with `@disable`
-fail_compilation/fail10968.d(71): Error: struct fail10968.SD is not copyable because it is annotated with `@disable`
-fail_compilation/fail10968.d(72): Error: struct fail10968.SD is not copyable because it is annotated with `@disable`
-fail_compilation/fail10968.d(73): Error: struct fail10968.SD is not copyable because it is annotated with `@disable`
+fail_compilation/fail10968.d(72): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(73): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(74): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(77): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(78): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(79): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10980.d b/gcc/testsuite/gdc.test/fail_compilation/fail10980.d
index eb50de3..4869d27 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10980.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10980.d
@@ -1,14 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail10980.d(22): Error: variable fail10980.s1b of type struct immutable(S1) uses this(this), which is not allowed in static initialization
-fail_compilation/fail10980.d(28): Error: variable fail10980.s1d of type struct immutable(S1) uses this(this), which is not allowed in static initialization
-fail_compilation/fail10980.d(27): Error: static variable s1x cannot be read at compile time
-fail_compilation/fail10980.d(28): called from here: bar1()
-fail_compilation/fail10980.d(38): Error: variable fail10980.s2b of type struct immutable(S2) uses this(this), which is not allowed in static initialization
-fail_compilation/fail10980.d(44): Error: variable fail10980.s2d of type struct immutable(S2) uses this(this), which is not allowed in static initialization
-fail_compilation/fail10980.d(43): Error: static variable s2x cannot be read at compile time
-fail_compilation/fail10980.d(44): called from here: bar2()
+fail_compilation/fail10980.d(22): Error: variable `fail10980.s1b` of type struct `immutable(S1)` uses `this(this)`, which is not allowed in static initialization
+fail_compilation/fail10980.d(28): Error: variable `fail10980.s1d` of type struct `immutable(S1)` uses `this(this)`, which is not allowed in static initialization
+fail_compilation/fail10980.d(27): Error: static variable `s1x` cannot be read at compile time
+fail_compilation/fail10980.d(28): called from here: `bar1()`
+fail_compilation/fail10980.d(38): Error: variable `fail10980.s2b` of type struct `immutable(S2)` uses `this(this)`, which is not allowed in static initialization
+fail_compilation/fail10980.d(44): Error: variable `fail10980.s2d` of type struct `immutable(S2)` uses `this(this)`, which is not allowed in static initialization
+fail_compilation/fail10980.d(43): Error: static variable `s2x` cannot be read at compile time
+fail_compilation/fail10980.d(44): called from here: `bar2()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11.d b/gcc/testsuite/gdc.test/fail_compilation/fail11.d
index 524e615..8ba05df 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11.d(12): Error: `type` has no effect in expression `int*`
+fail_compilation/fail11.d(12): Error: `int*` has no effect
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail110.d b/gcc/testsuite/gdc.test/fail_compilation/fail110.d
index 4703401..a13922b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail110.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail110.d
@@ -1,14 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail110.d(16): Error: variable i is shadowing variable fail110.main.i
-fail_compilation/fail110.d(17): Error: variable i is shadowing variable fail110.main.i
-fail_compilation/fail110.d(18): Error: variable i is shadowing variable fail110.main.i
+fail_compilation/fail110.d(16): Error: variable `i` is shadowing variable `fail110.main.i`
+fail_compilation/fail110.d(17): Error: variable `i` is shadowing variable `fail110.main.i`
+fail_compilation/fail110.d(18): Error: variable `i` is shadowing variable `fail110.main.i`
---
*/
-// Issue 297 - Shadowing declarations allowed in foreach type lists
-
+// https://issues.dlang.org/show_bug.cgi?id=297
+// Shadowing declarations allowed in foreach type lists
void main()
{
int i;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11038.d b/gcc/testsuite/gdc.test/fail_compilation/fail11038.d
index 8f39ccc..331c3fc 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11038.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11038.d
@@ -2,16 +2,16 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11038.d(16): Error: `writeln` is not defined, perhaps `import std.stdio;` is needed?
+fail_compilation/fail11038.d(16): Error: `printf` is not defined, perhaps `import core.stdc.stdio;` is needed?
---
*/
static
{
- import std.stdio;
+ import core.stdc.stdio;
}
void main()
{
- writeln("foo"); // compiles
+ printf("foo"); // compiles
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail111.d b/gcc/testsuite/gdc.test/fail_compilation/fail111.d
index 3a5fed4..b5d1669 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail111.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail111.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail111.d(12): Error: can't have array of int(int)
+fail_compilation/fail111.d(12): Error: cannot have array of `int(int)`
---
*/
-// Issue 289 - Compiler allows (and crashes on) dynamic arrays of typedefs of "immediate"-function types
-
+// https://issues.dlang.org/show_bug.cgi?id=289
+// Compiler allows (and crashes on) dynamic arrays of typedefs of "immediate"-function types
alias int ft(int);
ft[] x; // is allowed
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11125.d b/gcc/testsuite/gdc.test/fail_compilation/fail11125.d
index b42cb88..1a682cd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11125.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11125.d
@@ -1,8 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11125.d(20): Error: template instance fail11125.filter!(function (int a) => a + 1) does not match template declaration filter(alias predfun) if (is(ReturnType!predfun == bool))
-fail_compilation/fail11125.d(21): Error: template instance fail11125.filter!(function (int a) => a + 1) does not match template declaration filter(alias predfun) if (is(ReturnType!predfun == bool))
+fail_compilation/fail11125.d(26): Error: template instance `fail11125.filter!(function (int a) pure nothrow @nogc @safe => a + 1)` does not match template declaration `filter(alias predfun)`
+ with `predfun = __lambda1`
+ must satisfy the following constraint:
+` is(ReturnType!predfun == bool)`
+fail_compilation/fail11125.d(27): Error: template instance `fail11125.filter!(function (int a) pure nothrow @nogc @safe => a + 1)` does not match template declaration `filter(alias predfun)`
+ with `predfun = __lambda2`
+ must satisfy the following constraint:
+` is(ReturnType!predfun == bool)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11151.d b/gcc/testsuite/gdc.test/fail_compilation/fail11151.d
index 6184317..e5c2622 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11151.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11151.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11151.d(30): Error: overlapping initialization for field a and y
+fail_compilation/fail11151.d(30): Error: overlapping initialization for field `a` and `y`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11163.d b/gcc/testsuite/gdc.test/fail_compilation/fail11163.d
index 3966c05..d886740 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11163.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11163.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/fail11163.d(12): Error: cannot implicitly convert expression `foo()` of type `int[]` to `immutable(int[])`
-fail_compilation/fail11163.d(13): while evaluating pragma(msg, a)
+fail_compilation/fail11163.d(13): while evaluating `pragma(msg, a)`
---
*/
int[] foo() {
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail113.d b/gcc/testsuite/gdc.test/fail_compilation/fail113.d
index 8271b02..43ee2d8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail113.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail113.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail113.d(10): Error: forward reference to 'test'
+fail_compilation/fail113.d(10): Error: forward reference to `test`
---
*/
-// Issue 370 - Compiler stack overflow on recursive typeof in function declaration.
-
+// https://issues.dlang.org/show_bug.cgi?id=370
+// Compiler stack overflow on recursive typeof in function declaration.
void test(typeof(test) p) {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11355.d b/gcc/testsuite/gdc.test/fail_compilation/fail11355.d
index c41a4c4..50897ad 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11355.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11355.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11355.d(28): Error: struct fail11355.A is not copyable because it is annotated with `@disable`
+fail_compilation/fail11355.d(28): Error: struct `fail11355.A` is not copyable because it has a disabled postblit
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11375.d b/gcc/testsuite/gdc.test/fail_compilation/fail11375.d
index ba27a08..4f221bf 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11375.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11375.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11375.d(17): Error: constructor `fail11375.D!().D.this` is not nothrow
-fail_compilation/fail11375.d(15): Error: nothrow function `D main` may throw
+fail_compilation/fail11375.d(17): Error: constructor `fail11375.D!().D.this` is not `nothrow`
+fail_compilation/fail11375.d(15): Error: `nothrow` function `D main` may throw
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail114.d b/gcc/testsuite/gdc.test/fail_compilation/fail114.d
index 5bb9cec..65eeef7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail114.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail114.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail114.d(12): Error: forward reference to 'funcA'
+fail_compilation/fail114.d(12): Error: forward reference to `funcA`
---
*/
-// Issue 371 - ICE on mutual recursive typeof in function declarations
-
+// https://issues.dlang.org/show_bug.cgi?id=371
+// ICE on mutual recursive typeof in function declarations
void funcA(typeof(&funcB) p) {}
void funcB(typeof(&funcA) p) {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11445.d b/gcc/testsuite/gdc.test/fail_compilation/fail11445.d
index ed3f226..3295b24 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11445.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11445.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11445.d(11): Error: incompatible types for ((a) + (b)): both operands are of type 'double[string]'
+fail_compilation/fail11445.d(11): Error: incompatible types for `(a) + (b)`: both operands are of type `double[string]`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11453b.d b/gcc/testsuite/gdc.test/fail_compilation/fail11453b.d
index c7bdce5..c9d7b96 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11453b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11453b.d
@@ -3,7 +3,7 @@
/*
TEST_OUTPUT
---
-fail_compilation/extra-files/foo11453.d(1): Error: module foo11453 from file fail_compilation/extra-files/foo11453.d conflicts with package name foo11453
+fail_compilation/extra-files/foo11453.d(1): Error: module `foo11453` from file fail_compilation/extra-files/foo11453.d conflicts with package name foo11453
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11503c.d b/gcc/testsuite/gdc.test/fail_compilation/fail11503c.d
index ad3963f..88565d3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11503c.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11503c.d
@@ -7,7 +7,7 @@ fail_compilation/fail11503c.d(19): Error: cannot implicitly convert expression `
struct Data
{
char[256] buffer;
- @property const(char)[] filename() const pure nothrow
+ @property const(char)[] filename() const pure nothrow return
{
return buffer[];
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11503d.d b/gcc/testsuite/gdc.test/fail_compilation/fail11503d.d
index d1605b2..30efa8d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11503d.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11503d.d
@@ -10,7 +10,7 @@ struct Data2
char buffer;
}
-@property const(char)[] filename(const ref Data2 d) pure nothrow
+@property const(char)[] filename(const return ref Data2 d) pure nothrow
{
return (&d.buffer)[0 .. 1];
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11510.d b/gcc/testsuite/gdc.test/fail_compilation/fail11510.d
index 13913a0..de08b55 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11510.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11510.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11510.d(25): Error: reinterpretation through overlapped field y is not allowed in CTFE
-fail_compilation/fail11510.d(29): called from here: test11510a()
-fail_compilation/fail11510.d(36): Error: reinterpretation through overlapped field y is not allowed in CTFE
-fail_compilation/fail11510.d(40): called from here: test11510b()
+fail_compilation/fail11510.d(25): Error: reinterpretation through overlapped field `y` is not allowed in CTFE
+fail_compilation/fail11510.d(29): called from here: `test11510a()`
+fail_compilation/fail11510.d(36): Error: reinterpretation through overlapped field `y` is not allowed in CTFE
+fail_compilation/fail11510.d(40): called from here: `test11510b()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11532.d b/gcc/testsuite/gdc.test/fail_compilation/fail11532.d
index 7f4c770..144dec7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11532.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11532.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11532.d(17): Error: cannot pass static arrays to extern(C) vararg functions
-fail_compilation/fail11532.d(18): Error: cannot pass dynamic arrays to extern(C) vararg functions
-fail_compilation/fail11532.d(19): Error: cannot pass static arrays to extern(C++) vararg functions
-fail_compilation/fail11532.d(20): Error: cannot pass dynamic arrays to extern(C++) vararg functions
+fail_compilation/fail11532.d(17): Error: cannot pass static arrays to `extern(C)` vararg functions
+fail_compilation/fail11532.d(18): Error: cannot pass dynamic arrays to `extern(C)` vararg functions
+fail_compilation/fail11532.d(19): Error: cannot pass static arrays to `extern(C++)` vararg functions
+fail_compilation/fail11532.d(20): Error: cannot pass dynamic arrays to `extern(C++)` vararg functions
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11542.d b/gcc/testsuite/gdc.test/fail_compilation/fail11542.d
index 22d29ac..0198f64 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11542.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11542.d
@@ -1,13 +1,12 @@
// REQUIRED_ARGS: -o-
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/fail11542.d(16): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail11542.d(13): Error: nothrow function `fail11542.test_success1` may throw
-fail_compilation/fail11542.d(26): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail11542.d(23): Error: nothrow function `fail11542.test_success3` may throw
+fail_compilation/fail11542.d(15): Error: `object.Exception` is thrown but not caught
+fail_compilation/fail11542.d(12): Error: `nothrow` function `fail11542.test_success1` may throw
+fail_compilation/fail11542.d(25): Error: `object.Exception` is thrown but not caught
+fail_compilation/fail11542.d(22): Error: `nothrow` function `fail11542.test_success3` may throw
---
*/
void test_success1() nothrow
@@ -29,8 +28,8 @@ void test_success3() nothrow
/*
TEST_OUTPUT:
---
-fail_compilation/fail11542.d(39): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail11542.d(36): Error: nothrow function `fail11542.test_failure1` may throw
+fail_compilation/fail11542.d(38): Error: `object.Exception` is thrown but not caught
+fail_compilation/fail11542.d(35): Error: `nothrow` function `fail11542.test_failure1` may throw
---
*/
void test_failure1() nothrow
@@ -52,8 +51,8 @@ void est_failure3() nothrow
/*
TEST_OUTPUT:
---
-fail_compilation/fail11542.d(62): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail11542.d(59): Error: nothrow function `fail11542.test_exit1` may throw
+fail_compilation/fail11542.d(61): Error: `object.Exception` is thrown but not caught
+fail_compilation/fail11542.d(58): Error: `nothrow` function `fail11542.test_exit1` may throw
---
*/
void test_exit1() nothrow
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11545.d b/gcc/testsuite/gdc.test/fail_compilation/fail11545.d
index 514cb87..a576817 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11545.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11545.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11545.d(14): Error: need 'this' for 'x' of type 'int'
-fail_compilation/fail11545.d(18): Error: need 'this' for 'x' of type 'int'
+fail_compilation/fail11545.d(14): Error: need `this` for `x` of type `int`
+fail_compilation/fail11545.d(18): Error: need `this` for `x` of type `int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11552.d b/gcc/testsuite/gdc.test/fail_compilation/fail11552.d
index 5116522..2520225 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11552.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11552.d
@@ -1,9 +1,8 @@
/*
REQUIRED_ARGS: -o-
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/fail11552.d(12): Error: label `label` is undefined
+fail_compilation/fail11552.d(11): Error: function `D main` label `label` is undefined
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11562.d b/gcc/testsuite/gdc.test/fail_compilation/fail11562.d
index 0377456..dcae1f5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11562.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11562.d
@@ -1,12 +1,11 @@
/*
REQUIRED_ARGS: -o-
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/fail11562.d(16): Error: cannot goto in or out of `finally` block
-fail_compilation/fail11562.d(37): Error: cannot goto in or out of `finally` block
-fail_compilation/fail11562.d(49): Error: cannot goto in or out of `finally` block
-fail_compilation/fail11562.d(64): Error: cannot goto in or out of `finally` block
+fail_compilation/fail11562.d(15): Error: cannot `goto` in or out of `finally` block
+fail_compilation/fail11562.d(36): Error: cannot `goto` in or out of `finally` block
+fail_compilation/fail11562.d(48): Error: cannot `goto` in or out of `finally` block
+fail_compilation/fail11562.d(63): Error: cannot `goto` in or out of `finally` block
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11591b.d b/gcc/testsuite/gdc.test/fail_compilation/fail11591b.d
index 42e89c9..ef4fe16 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11591b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11591b.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11591b.d(16): Error: AA key type S11591 does not have 'bool opEquals(ref const S11591) const'
+fail_compilation/fail11591b.d(16): Error: AA key type `S11591` does not have `bool opEquals(ref const S11591) const`
---
*/
@@ -19,8 +19,8 @@ void test11591()
/*
TEST_OUTPUT:
---
-fail_compilation/fail11591b.d(30): Error: AA key type S12307a does not have 'bool opEquals(ref const S12307a) const'
-fail_compilation/fail11591b.d(31): Error: AA key type S12307b does not have 'bool opEquals(ref const S12307b) const'
+fail_compilation/fail11591b.d(30): Error: AA key type `S12307a` does not have `bool opEquals(ref const S12307a) const`
+fail_compilation/fail11591b.d(31): Error: AA key type `S12307b` does not have `bool opEquals(ref const S12307b) const`
---
*/
struct S12307a { bool opEquals(T : typeof(this))(T) { return false; } }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail116.d b/gcc/testsuite/gdc.test/fail_compilation/fail116.d
index 87e451b..66a01c6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail116.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail116.d
@@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail116.d(11): Error: circular typeof definition
-fail_compilation/fail116.d(16): Error: template instance square!1.2 does not match template declaration square(_error_ x)
+fail_compilation/fail116.d(11): Error: circular `typeof` definition
+fail_compilation/fail116.d(16): Error: template instance `square!1.2` does not match template declaration `square(_error_ x)`
---
*/
-// Issue 405 - typeof in TemplateParameterList causes compiletime segmentfault
-
+// https://issues.dlang.org/show_bug.cgi?id=405
+// typeof in TemplateParameterList causes compiletime segmentfault
template square(typeof(x) x)
{
const square = x * x;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail117.d b/gcc/testsuite/gdc.test/fail_compilation/fail117.d
index 9279d54..b0e1b12 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail117.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail117.d
@@ -8,8 +8,8 @@ fail_compilation/fail117.d(38): Error: expression `foo.mixin MGettor!(b) getb;
---
*/
-// Issue 420 - mixin make dmd break
-
+// https://issues.dlang.org/show_bug.cgi?id=420
+// mixin make dmd break
//import std.stdio;
template MGettor(alias Fld)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11714.d b/gcc/testsuite/gdc.test/fail_compilation/fail11714.d
new file mode 100644
index 0000000..abc4708
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11714.d
@@ -0,0 +1,21 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail11714.d(14): Error: variable `fail11714.c` is a thread-local class and cannot have a static initializer. Use `static this()` to initialize instead.
+fail_compilation/fail11714.d(21): Error: variable `fail11714.s` is a thread-local pointer to struct and cannot have a static initializer. Use `static this()` to initialize instead.
+---
+*/
+
+class C11714
+{
+ int data;
+};
+
+C11714 c = new C11714; // mutable class reference.
+
+struct S11714
+{
+ int data;
+};
+
+S11714* s = new S11714; // mutable pointer to struct.
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11717.d b/gcc/testsuite/gdc.test/fail_compilation/fail11717.d
deleted file mode 100644
index c6d505c..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11717.d
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail11717.d(13): Error: cannot interpret array literal expression [1, 2, 3, 4] + [1, 2, 3, 4] at compile time
----
-*/
-
-// https://issues.dlang.org/show_bug.cgi?id=11717
-
-enum int[4] A = [1,2,3,4];
-enum int[4] B = [1,2,3,4];
-// Internal Compiler Error: non-constant value [1, 2, 3, 4]
-enum int[4] C = A[] + B[];
-
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11720.d b/gcc/testsuite/gdc.test/fail_compilation/fail11720.d
deleted file mode 100644
index 8ad1d86..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11720.d
+++ /dev/null
@@ -1,33 +0,0 @@
-// REQUIRED_ARGS: -o-
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail11720.d(23): Error: declaration fail11720.foo!().foo.temp is already defined in another scope in foo
-fail_compilation/fail11720.d(13): Error: template instance fail11720.foo!() error instantiating
-fail_compilation/fail11720.d(31): Error: declaration fail11720.bar.temp is already defined in another scope in bar
----
-*/
-
-void main()
-{
- foo();
- bar();
-}
-
-alias TypeTuple(T...) = T;
-
-void foo()()
-{
- foreach (T; TypeTuple!(int, double))
- {
- static temp = T.stringof;
- }
-}
-
-void bar()
-{
- foreach (T; TypeTuple!(int, double))
- {
- static temp = T.stringof;
- }
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11748.d b/gcc/testsuite/gdc.test/fail_compilation/fail11748.d
index 95b78fa..7b6a6c8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11748.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11748.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail11748.d(12): Error: expression my_function(0) is void and has no value
+fail_compilation/fail11748.d(12): Error: expression `my_function(0)` is `void` and has no value
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail118.d b/gcc/testsuite/gdc.test/fail_compilation/fail118.d
index e17b954..263570a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail118.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail118.d
@@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail118.d(26): Error: invalid foreach aggregate `Iter`, define opApply(), range primitives, or use .tupleof
-fail_compilation/fail118.d(27): Error: invalid foreach aggregate `Iter`, define opApply(), range primitives, or use .tupleof
+fail_compilation/fail118.d(26): Error: invalid `foreach` aggregate `Iter`, define `opApply()`, range primitives, or use `.tupleof`
+fail_compilation/fail118.d(27): Error: invalid `foreach` aggregate `Iter`, define `opApply()`, range primitives, or use `.tupleof`
---
*/
-// Issue 441 - Crash on foreach of mixed-in aggregate.
-
+// https://issues.dlang.org/show_bug.cgi?id=441
+// Crash on foreach of mixed-in aggregate.
template opHackedApply()
{
struct Iter
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail120.d b/gcc/testsuite/gdc.test/fail_compilation/fail120.d
index ae0f5b1..c9d67a4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail120.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail120.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail120.d(12): Error: need 'this' for 'nodes' of type 'int[2]'
-fail_compilation/fail120.d(13): Error: need 'this' for 'nodes' of type 'int[2]'
+fail_compilation/fail120.d(12): Error: need `this` for `nodes` of type `int[2]`
+fail_compilation/fail120.d(13): Error: need `this` for `nodes` of type `int[2]`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail122.d b/gcc/testsuite/gdc.test/fail_compilation/fail122.d
index f4ba301..da355d5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail122.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail122.d
@@ -5,8 +5,8 @@ fail_compilation/fail122.d(12): Error: undefined identifier `y`
---
*/
-// Issue 228 - Crash on inferring function literal return type after prior errors
-
+// https://issues.dlang.org/show_bug.cgi?id=228
+// Crash on inferring function literal return type after prior errors
void main()
{
y = 2;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12236.d b/gcc/testsuite/gdc.test/fail_compilation/fail12236.d
index ea95066..738864c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12236.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12236.d
@@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail12236.d(16): Error: forward reference to inferred return type of function 'f1'
-fail_compilation/fail12236.d(16): while evaluating pragma(msg, f1.mangleof)
-fail_compilation/fail12236.d(21): Error: forward reference to inferred return type of function 'f2'
-fail_compilation/fail12236.d(21): while evaluating pragma(msg, f2(T)(T).mangleof)
-fail_compilation/fail12236.d(27): Error: template instance fail12236.f2!int error instantiating
-fail_compilation/fail12236.d(31): Error: forward reference to inferred return type of function '__lambda1'
-fail_compilation/fail12236.d(31): while evaluating pragma(msg, __lambda1.mangleof)
+fail_compilation/fail12236.d(16): Error: forward reference to inferred return type of function `f1`
+fail_compilation/fail12236.d(16): while evaluating `pragma(msg, f1.mangleof)`
+fail_compilation/fail12236.d(21): Error: forward reference to inferred return type of function `f2`
+fail_compilation/fail12236.d(21): while evaluating `pragma(msg, f2(T)(T).mangleof)`
+fail_compilation/fail12236.d(27): Error: template instance `fail12236.f2!int` error instantiating
+fail_compilation/fail12236.d(31): Error: forward reference to inferred return type of function `__lambda1`
+fail_compilation/fail12236.d(31): while evaluating `pragma(msg, __lambda1.mangleof)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12255.d b/gcc/testsuite/gdc.test/fail_compilation/fail12255.d
index 4531e86..945212b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12255.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12255.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail12255.d(29): Error: AA key type SC1 does not have 'bool opEquals(ref const SC1) const'
-fail_compilation/fail12255.d(30): Error: AA key type SC2 does not support const equality
-fail_compilation/fail12255.d(35): Error: AA key type SD1 should have 'size_t toHash() const nothrow @safe' if opEquals defined
-fail_compilation/fail12255.d(36): Error: AA key type SD2 supports const equality but doesn't support const hashing
-fail_compilation/fail12255.d(40): Error: AA key type SE1 should have 'size_t toHash() const nothrow @safe' if opEquals defined
-fail_compilation/fail12255.d(41): Error: AA key type SE2 supports const equality but doesn't support const hashing
+fail_compilation/fail12255.d(29): Error: AA key type `SC1` does not have `bool opEquals(ref const SC1) const`
+fail_compilation/fail12255.d(30): Error: AA key type `SC2` does not support const equality
+fail_compilation/fail12255.d(35): Error: AA key type `SD1` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined
+fail_compilation/fail12255.d(36): Error: AA key type `SD2` supports const equality but doesn't support const hashing
+fail_compilation/fail12255.d(40): Error: AA key type `SE1` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined
+fail_compilation/fail12255.d(41): Error: AA key type `SE2` supports const equality but doesn't support const hashing
---
*/
@@ -91,12 +91,12 @@ struct SE2
/*
TEST_OUTPUT:
---
-fail_compilation/fail12255.d(108): Error: bottom of AA key type SC1 does not have 'bool opEquals(ref const SC1) const'
-fail_compilation/fail12255.d(109): Error: bottom of AA key type SC2 does not support const equality
-fail_compilation/fail12255.d(110): Error: bottom of AA key type SD1 should have 'size_t toHash() const nothrow @safe' if opEquals defined
-fail_compilation/fail12255.d(111): Error: bottom of AA key type SD2 supports const equality but doesn't support const hashing
-fail_compilation/fail12255.d(112): Error: bottom of AA key type SE1 should have 'size_t toHash() const nothrow @safe' if opEquals defined
-fail_compilation/fail12255.d(113): Error: bottom of AA key type SE2 supports const equality but doesn't support const hashing
+fail_compilation/fail12255.d(108): Error: bottom of AA key type `SC1` does not have `bool opEquals(ref const SC1) const`
+fail_compilation/fail12255.d(109): Error: bottom of AA key type `SC2` does not support const equality
+fail_compilation/fail12255.d(110): Error: bottom of AA key type `SD1` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined
+fail_compilation/fail12255.d(111): Error: bottom of AA key type `SD2` supports const equality but doesn't support const hashing
+fail_compilation/fail12255.d(112): Error: bottom of AA key type `SE1` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined
+fail_compilation/fail12255.d(113): Error: bottom of AA key type `SE2` supports const equality but doesn't support const hashing
---
*/
void testSArray()
@@ -116,12 +116,12 @@ void testSArray()
/*
TEST_OUTPUT:
---
-fail_compilation/fail12255.d(133): Error: bottom of AA key type SC1 does not have 'bool opEquals(ref const SC1) const'
-fail_compilation/fail12255.d(134): Error: bottom of AA key type SC2 does not support const equality
-fail_compilation/fail12255.d(135): Error: bottom of AA key type SD1 should have 'size_t toHash() const nothrow @safe' if opEquals defined
-fail_compilation/fail12255.d(136): Error: bottom of AA key type SD2 supports const equality but doesn't support const hashing
-fail_compilation/fail12255.d(137): Error: bottom of AA key type SE1 should have 'size_t toHash() const nothrow @safe' if opEquals defined
-fail_compilation/fail12255.d(138): Error: bottom of AA key type SE2 supports const equality but doesn't support const hashing
+fail_compilation/fail12255.d(133): Error: bottom of AA key type `SC1` does not have `bool opEquals(ref const SC1) const`
+fail_compilation/fail12255.d(134): Error: bottom of AA key type `SC2` does not support const equality
+fail_compilation/fail12255.d(135): Error: bottom of AA key type `SD1` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined
+fail_compilation/fail12255.d(136): Error: bottom of AA key type `SD2` supports const equality but doesn't support const hashing
+fail_compilation/fail12255.d(137): Error: bottom of AA key type `SE1` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined
+fail_compilation/fail12255.d(138): Error: bottom of AA key type `SE2` supports const equality but doesn't support const hashing
---
*/
void testDArray()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail123.d b/gcc/testsuite/gdc.test/fail_compilation/fail123.d
index fd1aef0..1566b91 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail123.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail123.d
@@ -2,12 +2,12 @@
TEST_OUTPUT:
---
fail_compilation/fail123.d(11): Error: undefined identifier `type`
-fail_compilation/fail123.d(17): Error: enum fail123.foo2 base type must not be void
+fail_compilation/fail123.d(17): Error: enum `fail123.foo2` base type must not be `void`
---
*/
-// Issue 355 - ICE from enum : nonexistent type
-
+// https://issues.dlang.org/show_bug.cgi?id=355
+// ICE from enum : nonexistent type
enum foo : type
{
blah1,
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12378.d b/gcc/testsuite/gdc.test/fail_compilation/fail12378.d
index 6f78730..77678eb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12378.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12378.d
@@ -3,11 +3,11 @@ TEST_OUTPUT:
---
fail_compilation/fail12378.d(18): Error: undefined identifier `ANYTHING`
fail_compilation/fail12378.d(18): Error: undefined identifier `GOES`
-fail_compilation/fail12378.d(91): instantiated from here: MapResultS!((x0) => ANYTHING - GOES, Result)
-fail_compilation/fail12378.d(17): instantiated from here: mapS!(Result)
-fail_compilation/fail12378.d(100): instantiated from here: __lambda1!int
-fail_compilation/fail12378.d(91): instantiated from here: MapResultS!((y0) => iota(2).mapS!((x0) => ANYTHING - GOES), Result)
-fail_compilation/fail12378.d(16): instantiated from here: mapS!(Result)
+fail_compilation/fail12378.d(91): instantiated from here: `MapResultS!((x0) => ANYTHING - GOES, Result)`
+fail_compilation/fail12378.d(17): instantiated from here: `mapS!(Result)`
+fail_compilation/fail12378.d(100): instantiated from here: `__lambda1!int`
+fail_compilation/fail12378.d(91): instantiated from here: `MapResultS!((y0) => iota(2).mapS!((x0) => ANYTHING - GOES), Result)`
+fail_compilation/fail12378.d(16): instantiated from here: `mapS!(Result)`
---
*/
void testS()
@@ -25,11 +25,11 @@ TEST_OUTPUT:
---
fail_compilation/fail12378.d(40): Error: undefined identifier `ANYTHING`
fail_compilation/fail12378.d(40): Error: undefined identifier `GOES`
-fail_compilation/fail12378.d(112): instantiated from here: MapResultC!((x0) => ANYTHING - GOES, Result)
-fail_compilation/fail12378.d(39): instantiated from here: mapC!(Result)
-fail_compilation/fail12378.d(123): instantiated from here: __lambda1!int
-fail_compilation/fail12378.d(112): instantiated from here: MapResultC!((y0) => iota(2).mapC!((x0) => ANYTHING - GOES), Result)
-fail_compilation/fail12378.d(38): instantiated from here: mapC!(Result)
+fail_compilation/fail12378.d(112): instantiated from here: `MapResultC!((x0) => ANYTHING - GOES, Result)`
+fail_compilation/fail12378.d(39): instantiated from here: `mapC!(Result)`
+fail_compilation/fail12378.d(123): instantiated from here: `__lambda1!int`
+fail_compilation/fail12378.d(112): instantiated from here: `MapResultC!((y0) => iota(2).mapC!((x0) => ANYTHING - GOES), Result)`
+fail_compilation/fail12378.d(38): instantiated from here: `mapC!(Result)`
---
*/
void testC()
@@ -47,11 +47,11 @@ TEST_OUTPUT:
---
fail_compilation/fail12378.d(64): Error: undefined identifier `ANYTHING`
fail_compilation/fail12378.d(64): Error: undefined identifier `GOES`
-fail_compilation/fail12378.d(135): instantiated from here: MapResultI!((x0) => ANYTHING - GOES, Result)
-fail_compilation/fail12378.d(63): instantiated from here: mapI!(Result)
-fail_compilation/fail12378.d(143): instantiated from here: __lambda1!int
-fail_compilation/fail12378.d(135): instantiated from here: MapResultI!((y0) => iota(2).mapI!((x0) => ANYTHING - GOES), Result)
-fail_compilation/fail12378.d(62): instantiated from here: mapI!(Result)
+fail_compilation/fail12378.d(135): instantiated from here: `MapResultI!((x0) => ANYTHING - GOES, Result)`
+fail_compilation/fail12378.d(63): instantiated from here: `mapI!(Result)`
+fail_compilation/fail12378.d(143): instantiated from here: `__lambda1!int`
+fail_compilation/fail12378.d(135): instantiated from here: `MapResultI!((y0) => iota(2).mapI!((x0) => ANYTHING - GOES), Result)`
+fail_compilation/fail12378.d(62): instantiated from here: `mapI!(Result)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12390.d b/gcc/testsuite/gdc.test/fail_compilation/fail12390.d
index cb1eb8a..dd28163 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12390.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12390.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail12390.d(14): Error: `==` has no effect in expression `fun().i == 4`
+fail_compilation/fail12390.d(14): Error: `fun().i == 4` has no effect
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail124.d b/gcc/testsuite/gdc.test/fail_compilation/fail124.d
index 62b5894..7eeb29f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail124.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail124.d
@@ -1,7 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail124.d(15): Error: class fail124.CC inherits from duplicate interface C
+fail_compilation/fail124.d(17): Error: class `fail124.CC` inherits from duplicate interface `C`
+fail_compilation/fail124.d(31): Error: class `fail124.D` inherits from duplicate interface `T`
+fail_compilation/fail124.d(31): Error: class `fail124.D` inherits from duplicate interface `T`
---
*/
@@ -22,3 +24,8 @@ void main()
CC cc = new CC();
cc.f();
}
+
+// https://issues.dlang.org/show_bug.cgi?id=20830
+interface T { }
+
+class D : T, T, T { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12436.d b/gcc/testsuite/gdc.test/fail_compilation/fail12436.d
index 605ab05..5bdf0d5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12436.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12436.d
@@ -21,8 +21,8 @@ TupleType test2();
/*
TEST_OUTPUT:
---
-fail_compilation/fail12436.d(28): Error: functions cannot return opaque type Opaque by value
-fail_compilation/fail12436.d(29): Error: functions cannot return opaque type Opaque[1] by value
+fail_compilation/fail12436.d(28): Error: functions cannot return opaque type `Opaque` by value
+fail_compilation/fail12436.d(29): Error: functions cannot return opaque type `Opaque[1]` by value
---
*/
Opaque ret12436a(); // error
@@ -40,7 +40,7 @@ ref Opaque[1] ret12436g(); // no error
/*
TEST_OUTPUT:
---
-fail_compilation/fail12436.d(46): Error: cannot have parameter of function type void()
+fail_compilation/fail12436.d(46): Error: cannot have parameter of function type `void()`
---
*/
void test3(FuncType) {}
@@ -48,8 +48,8 @@ void test3(FuncType) {}
/*
TEST_OUTPUT:
---
-fail_compilation/fail12436.d(55): Error: cannot have parameter of opaque type Opaque by value
-fail_compilation/fail12436.d(56): Error: cannot have parameter of opaque type Opaque[1] by value
+fail_compilation/fail12436.d(55): Error: cannot have parameter of opaque type `Opaque` by value
+fail_compilation/fail12436.d(56): Error: cannot have parameter of opaque type `Opaque[1]` by value
---
*/
void param12436a(Opaque); // error
@@ -66,9 +66,9 @@ void param12436i(out Opaque[1]); // no error
/*
TEST_OUTPUT:
---
-fail_compilation/fail12436.d(75): Error: cannot have parameter of opaque type A14906 by value
-fail_compilation/fail12436.d(76): Error: cannot have parameter of opaque type A14906[3] by value
-fail_compilation/fail12436.d(77): Error: cannot have parameter of opaque type A14906[3][3] by value
+fail_compilation/fail12436.d(75): Error: cannot have parameter of opaque type `A14906` by value
+fail_compilation/fail12436.d(76): Error: cannot have parameter of opaque type `A14906[3]` by value
+fail_compilation/fail12436.d(77): Error: cannot have parameter of opaque type `A14906[3][3]` by value
---
*/
enum A14906;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail125.d b/gcc/testsuite/gdc.test/fail_compilation/fail125.d
index 0e0f5ea..93d176d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail125.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail125.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail125.d(15): Error: array index [2] is outside array bounds [0 .. 2]
-fail_compilation/fail125.d(18): Error: template instance fail125.main.recMove!(1, a, b) error instantiating
-fail_compilation/fail125.d(25): instantiated from here: recMove!(0, a, b)
+fail_compilation/fail125.d(15): Error: array index `[2]` is outside array bounds `[0 .. 2]`
+fail_compilation/fail125.d(18): Error: template instance `fail125.main.recMove!(1, a, b)` error instantiating
+fail_compilation/fail125.d(25): instantiated from here: `recMove!(0, a, b)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail126.d b/gcc/testsuite/gdc.test/fail_compilation/fail126.d
index 280fde9..b851c50 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail126.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail126.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail126.d(8): Error: forward reference to 'test'
+fail_compilation/fail126.d(8): Error: forward reference to `test`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12622.d b/gcc/testsuite/gdc.test/fail_compilation/fail12622.d
index 04bb8d6..1a8b185 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12622.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12622.d
@@ -1,15 +1,16 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail12622.d(25): Error: pure function 'fail12622.foo' cannot call impure function pointer 'fp'
-fail_compilation/fail12622.d(25): Error: @nogc function 'fail12622.foo' cannot call non-@nogc function pointer 'fp'
-fail_compilation/fail12622.d(25): Error: @safe function 'fail12622.foo' cannot call @system function pointer 'fp'
-fail_compilation/fail12622.d(27): Error: pure function 'fail12622.foo' cannot call impure function pointer 'fp'
-fail_compilation/fail12622.d(27): Error: @nogc function 'fail12622.foo' cannot call non-@nogc function pointer 'fp'
-fail_compilation/fail12622.d(27): Error: @safe function 'fail12622.foo' cannot call @system function pointer 'fp'
-fail_compilation/fail12622.d(29): Error: pure function 'fail12622.foo' cannot call impure function 'fail12622.bar'
-fail_compilation/fail12622.d(29): Error: @safe function 'fail12622.foo' cannot call @system function 'fail12622.bar'
-fail_compilation/fail12622.d(29): Error: @nogc function 'fail12622.foo' cannot call non-@nogc function 'fail12622.bar'
+fail_compilation/fail12622.d(26): Error: `pure` function `fail12622.foo` cannot call impure function pointer `fp`
+fail_compilation/fail12622.d(26): Error: `@nogc` function `fail12622.foo` cannot call non-@nogc function pointer `fp`
+fail_compilation/fail12622.d(26): Error: `@safe` function `fail12622.foo` cannot call `@system` function pointer `fp`
+fail_compilation/fail12622.d(28): Error: `pure` function `fail12622.foo` cannot call impure function pointer `fp`
+fail_compilation/fail12622.d(28): Error: `@nogc` function `fail12622.foo` cannot call non-@nogc function pointer `fp`
+fail_compilation/fail12622.d(28): Error: `@safe` function `fail12622.foo` cannot call `@system` function pointer `fp`
+fail_compilation/fail12622.d(30): Error: `pure` function `fail12622.foo` cannot call impure function `fail12622.bar`
+fail_compilation/fail12622.d(30): Error: `@safe` function `fail12622.foo` cannot call `@system` function `fail12622.bar`
+fail_compilation/fail12622.d(20): `fail12622.bar` is declared here
+fail_compilation/fail12622.d(30): Error: `@nogc` function `fail12622.foo` cannot call non-@nogc function `fail12622.bar`
---
*/
// Note that, today nothrow violation errors are accidentally hidden.
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12636.d b/gcc/testsuite/gdc.test/fail_compilation/fail12636.d
index 9a243a5..42e7855 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12636.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12636.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail12636.d(13): Error: C++ class 'fail12636.C' cannot implement D interface 'fail12636.D'
+fail_compilation/fail12636.d(13): Error: C++ class `fail12636.C` cannot implement D interface `fail12636.D`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail127.d b/gcc/testsuite/gdc.test/fail_compilation/fail127.d
index 449dbc5..ad9ddd0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail127.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail127.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail127.d(9): Error: a struct is not a valid initializer for a char[][]
-fail_compilation/fail127.d(10): Error: a struct is not a valid initializer for a string[]
+fail_compilation/fail127.d(9): Error: a struct is not a valid initializer for a `char[][]`
+fail_compilation/fail127.d(10): Error: a struct is not a valid initializer for a `string[]`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12744.d b/gcc/testsuite/gdc.test/fail_compilation/fail12744.d
index f1216b5..46ed9f6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12744.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12744.d
@@ -1,24 +1,24 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail12744.d(38): Error: incompatible parameter storage classes 'ref' and 'out'
-fail_compilation/fail12744.d(52): Error: template instance fail12744.bar12744R!(foo12744O) error instantiating
-fail_compilation/fail12744.d(38): Error: incompatible parameter storage classes 'ref' and 'lazy'
-fail_compilation/fail12744.d(53): Error: template instance fail12744.bar12744R!(foo12744L) error instantiating
-fail_compilation/fail12744.d(39): Error: incompatible parameter storage classes 'out' and 'ref'
-fail_compilation/fail12744.d(56): Error: template instance fail12744.bar12744O!(foo12744R) error instantiating
-fail_compilation/fail12744.d(39): Error: incompatible parameter storage classes 'out' and 'lazy'
-fail_compilation/fail12744.d(58): Error: template instance fail12744.bar12744O!(foo12744L) error instantiating
-fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes 'lazy' and 'ref'
-fail_compilation/fail12744.d(61): Error: template instance fail12744.bar12744L!(foo12744R) error instantiating
-fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes 'lazy' and 'out'
-fail_compilation/fail12744.d(62): Error: template instance fail12744.bar12744L!(foo12744O) error instantiating
-fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes 'auto ref' and 'out'
-fail_compilation/fail12744.d(67): Error: template fail12744.bar12744A cannot deduce function from argument types !(foo12744O)(int), candidates are:
-fail_compilation/fail12744.d(41): fail12744.bar12744A(alias f)(auto ref PTT12744!f args)
-fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes 'auto ref' and 'lazy'
-fail_compilation/fail12744.d(68): Error: template fail12744.bar12744A cannot deduce function from argument types !(foo12744L)(int), candidates are:
-fail_compilation/fail12744.d(41): fail12744.bar12744A(alias f)(auto ref PTT12744!f args)
+fail_compilation/fail12744.d(38): Error: incompatible parameter storage classes `ref` and `out`
+fail_compilation/fail12744.d(52): Error: template instance `fail12744.bar12744R!(foo12744O)` error instantiating
+fail_compilation/fail12744.d(38): Error: incompatible parameter storage classes `ref` and `lazy`
+fail_compilation/fail12744.d(53): Error: template instance `fail12744.bar12744R!(foo12744L)` error instantiating
+fail_compilation/fail12744.d(39): Error: incompatible parameter storage classes `out` and `ref`
+fail_compilation/fail12744.d(56): Error: template instance `fail12744.bar12744O!(foo12744R)` error instantiating
+fail_compilation/fail12744.d(39): Error: incompatible parameter storage classes `out` and `lazy`
+fail_compilation/fail12744.d(58): Error: template instance `fail12744.bar12744O!(foo12744L)` error instantiating
+fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes `lazy` and `ref`
+fail_compilation/fail12744.d(61): Error: template instance `fail12744.bar12744L!(foo12744R)` error instantiating
+fail_compilation/fail12744.d(40): Error: incompatible parameter storage classes `lazy` and `out`
+fail_compilation/fail12744.d(62): Error: template instance `fail12744.bar12744L!(foo12744O)` error instantiating
+fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `out`
+fail_compilation/fail12744.d(67): Error: template `fail12744.bar12744A` cannot deduce function from argument types `!(foo12744O)(int)`
+fail_compilation/fail12744.d(41): Candidate is: `bar12744A(alias f)(auto ref PTT12744!f args)`
+fail_compilation/fail12744.d(41): Error: incompatible parameter storage classes `auto ref` and `lazy`
+fail_compilation/fail12744.d(68): Error: template `fail12744.bar12744A` cannot deduce function from argument types `!(foo12744L)(int)`
+fail_compilation/fail12744.d(41): Candidate is: `bar12744A(alias f)(auto ref PTT12744!f args)`
---
*/
template PTT12744(func...)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12749.d b/gcc/testsuite/gdc.test/fail_compilation/fail12749.d
index 149d120..231b21e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12749.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12749.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail12749.d(19): Error: immutable field 'inum' initialization is not allowed in foreach loop
-fail_compilation/fail12749.d(20): Error: const field 'cnum' initialization is not allowed in foreach loop
-fail_compilation/fail12749.d(25): Error: immutable field 'inum' initialization is not allowed in nested function 'set'
-fail_compilation/fail12749.d(26): Error: const field 'cnum' initialization is not allowed in nested function 'set'
+fail_compilation/fail12749.d(19): Error: immutable field `inum` initialization is not allowed in foreach loop
+fail_compilation/fail12749.d(20): Error: const field `cnum` initialization is not allowed in foreach loop
+fail_compilation/fail12749.d(25): Error: immutable field `inum` initialization is not allowed in nested function `set`
+fail_compilation/fail12749.d(26): Error: const field `cnum` initialization is not allowed in nested function `set`
---
*/
struct S
@@ -31,10 +31,10 @@ struct S
/*
TEST_OUTPUT:
---
-fail_compilation/fail12749.d(48): Error: immutable variable 'inum' initialization is not allowed in foreach loop
-fail_compilation/fail12749.d(49): Error: const variable 'cnum' initialization is not allowed in foreach loop
-fail_compilation/fail12749.d(54): Error: immutable variable 'inum' initialization is not allowed in nested function 'set'
-fail_compilation/fail12749.d(55): Error: const variable 'cnum' initialization is not allowed in nested function 'set'
+fail_compilation/fail12749.d(48): Error: immutable variable `inum` initialization is not allowed in foreach loop
+fail_compilation/fail12749.d(49): Error: const variable `cnum` initialization is not allowed in foreach loop
+fail_compilation/fail12749.d(54): Error: immutable variable `inum` initialization is not allowed in nested function `set`
+fail_compilation/fail12749.d(55): Error: const variable `cnum` initialization is not allowed in nested function `set`
---
*/
immutable int inum;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12764.d b/gcc/testsuite/gdc.test/fail_compilation/fail12764.d
new file mode 100644
index 0000000..f889cb7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12764.d
@@ -0,0 +1,26 @@
+// https://issues.dlang.org/show_bug.cgi?id=12764
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail12764.d(20): Error: field `s` must be initialized in constructor
+---
+*/
+
+struct S
+{
+ @disable this();
+
+ this(string) { }
+ int f;
+}
+
+class C
+{
+ this(int)
+ {
+ s.f = 1; // circumvents default ctor!
+ }
+
+ S s;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12809.d b/gcc/testsuite/gdc.test/fail_compilation/fail12809.d
index 7c08683..a5e9f72 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12809.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12809.d
@@ -1,16 +1,15 @@
// REQUIRED_ARGS: -o-
-// PERMUTE_ARGS:
bool cond;
/*
TEST_OUTPUT:
---
-fail_compilation/fail12809.d(19): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail12809.d(16): Error: nothrow function `fail12809.test_finally1` may throw
-fail_compilation/fail12809.d(35): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail12809.d(39): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail12809.d(32): Error: nothrow function `fail12809.test_finally3` may throw
+fail_compilation/fail12809.d(18): Error: `object.Exception` is thrown but not caught
+fail_compilation/fail12809.d(15): Error: `nothrow` function `fail12809.test_finally1` may throw
+fail_compilation/fail12809.d(34): Error: `object.Exception` is thrown but not caught
+fail_compilation/fail12809.d(38): Error: `object.Exception` is thrown but not caught
+fail_compilation/fail12809.d(31): Error: `nothrow` function `fail12809.test_finally3` may throw
---
*/
void test_finally1() nothrow
@@ -44,11 +43,11 @@ void test_finally3() nothrow
/*
TEST_OUTPUT:
---
-fail_compilation/fail12809.d(59): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail12809.d(54): Error: nothrow function `fail12809.test_finally4` may throw
-fail_compilation/fail12809.d(75): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail12809.d(79): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail12809.d(70): Error: nothrow function `fail12809.test_finally6` may throw
+fail_compilation/fail12809.d(58): Error: `object.Exception` is thrown but not caught
+fail_compilation/fail12809.d(53): Error: `nothrow` function `fail12809.test_finally4` may throw
+fail_compilation/fail12809.d(74): Error: `object.Exception` is thrown but not caught
+fail_compilation/fail12809.d(78): Error: `object.Exception` is thrown but not caught
+fail_compilation/fail12809.d(69): Error: `nothrow` function `fail12809.test_finally6` may throw
---
*/
void test_finally4() nothrow
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail129.d b/gcc/testsuite/gdc.test/fail_compilation/fail129.d
index 2bf4369..dc0ca07 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail129.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail129.d
@@ -3,7 +3,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail129.d: Error: module fail129 source file must start with BOM or ASCII character, not \xC3
+fail_compilation/fail129.d: Error: module `fail129` source file must start with BOM or ASCII character, not \xC3
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12901.d b/gcc/testsuite/gdc.test/fail_compilation/fail12901.d
index 8d62c3e..31c90c1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12901.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12901.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail12901.d(11): Error: constructor fail12901.S.this in and out contracts require function body
+fail_compilation/fail12901.d(11): Error: constructor `fail12901.S.this` `in` and `out` contracts can only appear without a body when they are virtual interface functions or abstract
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12908.d b/gcc/testsuite/gdc.test/fail_compilation/fail12908.d
index c238028..67ea6ce 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12908.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12908.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail12908.d(14): Error: pure delegate 'fail12908.main.__foreachbody1' cannot call impure function 'fail12908.g'
+fail_compilation/fail12908.d(14): Error: `pure` delegate `fail12908.main.__foreachbody1` cannot call impure function `fail12908.g`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12932.d b/gcc/testsuite/gdc.test/fail_compilation/fail12932.d
index 871abfe..fe68fea 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12932.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12932.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail12932.d(11): Error: array literal in @nogc function 'fail12932.foo' may cause GC allocation
-fail_compilation/fail12932.d(15): Error: array literal in @nogc function 'fail12932.foo' may cause GC allocation
+fail_compilation/fail12932.d(11): Error: array literal in `@nogc` function `fail12932.foo` may cause a GC allocation
+fail_compilation/fail12932.d(15): Error: array literal in `@nogc` function `fail12932.foo` may cause a GC allocation
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13064.d b/gcc/testsuite/gdc.test/fail_compilation/fail13064.d
index be43460..a59de72 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13064.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13064.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail13064.d(8): Error: function fail13064.f storage class 'auto' has no effect if return type is not inferred
+fail_compilation/fail13064.d(8): Error: function `fail13064.f` storage class `auto` has no effect if return type is not inferred
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail131.d b/gcc/testsuite/gdc.test/fail_compilation/fail131.d
index e0f568f..15b6dc9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail131.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail131.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail131.d(8): Error: function D main parameters must be main() or main(string[] args)
+fail_compilation/fail131.d(8): Error: function `D main` parameters must be `main()` or `main(string[] args)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d
index fe1180c..ac520d7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d
@@ -1,12 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail13116.d(13): Error: this is not an lvalue
+fail_compilation/fail13116.d(14): Error: `this` is not an lvalue and cannot be modified
+fail_compilation/fail13116.d(23): Error: `super` is not an lvalue and cannot be modified
---
*/
struct S
{
- ref S notEvil() { return this; } // this should be accepted
+ ref S notEvil() return { return this; } // this should be accepted
}
class C
{
@@ -16,12 +17,6 @@ void main()
{
}
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail13116.d(28): Error: super is not an lvalue
----
-*/
class Base { }
class Derived : Base
{
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13120.d b/gcc/testsuite/gdc.test/fail_compilation/fail13120.d
index 1acda7b2..f1cf340 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13120.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13120.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail13120.d(13): Error: pure delegate 'fail13120.g1.__foreachbody2' cannot call impure function 'fail13120.f1'
-fail_compilation/fail13120.d(13): Error: @nogc delegate 'fail13120.g1.__foreachbody2' cannot call non-@nogc function 'fail13120.f1'
+fail_compilation/fail13120.d(13): Error: `pure` delegate `fail13120.g1.__foreachbody2` cannot call impure function `fail13120.f1`
+fail_compilation/fail13120.d(13): Error: `@nogc` delegate `fail13120.g1.__foreachbody2` cannot call non-@nogc function `fail13120.f1`
---
*/
void f1() {}
@@ -16,9 +16,10 @@ void g1(char[] s) pure @nogc
/*
TEST_OUTPUT:
---
-fail_compilation/fail13120.d(34): Error: pure function 'fail13120.h2' cannot call impure function 'fail13120.g2!().g2'
-fail_compilation/fail13120.d(34): Error: @safe function 'fail13120.h2' cannot call @system function 'fail13120.g2!().g2'
-fail_compilation/fail13120.d(34): Error: @nogc function 'fail13120.h2' cannot call non-@nogc function 'fail13120.g2!().g2'
+fail_compilation/fail13120.d(35): Error: `pure` function `fail13120.h2` cannot call impure function `fail13120.g2!().g2`
+fail_compilation/fail13120.d(35): Error: `@safe` function `fail13120.h2` cannot call `@system` function `fail13120.g2!().g2`
+fail_compilation/fail13120.d(27): `fail13120.g2!().g2` is declared here
+fail_compilation/fail13120.d(35): Error: `@nogc` function `fail13120.h2` cannot call non-@nogc function `fail13120.g2!().g2`
---
*/
void f2() {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13187.d b/gcc/testsuite/gdc.test/fail_compilation/fail13187.d
index 3799d77..2972c27 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13187.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13187.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail13187.d(12): Error: pure function 'fail13187.test' cannot access mutable static data 'my_func_ptr'
+fail_compilation/fail13187.d(12): Error: `pure` function `fail13187.test` cannot access mutable static data `my_func_ptr`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail132.d b/gcc/testsuite/gdc.test/fail_compilation/fail132.d
index 3463184..2c271d9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail132.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail132.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail132.d(19): Error: outer class A 'this' needed to 'new' nested class B
+fail_compilation/fail132.d(19): Error: outer class `A` `this` needed to `new` nested class `B`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13203.d b/gcc/testsuite/gdc.test/fail_compilation/fail13203.d
index 86d30a4..e242349 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13203.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13203.d
@@ -3,10 +3,10 @@ int v1, v2;
/*
TEST_OUTPUT:
---
-fail_compilation/fail13203.d(15): Error: alias fail13203.FA1!1.T conflicts with alias fail13203.FA1!1.T at fail_compilation/fail13203.d(14)
-fail_compilation/fail13203.d(22): Error: template instance fail13203.FA1!1 error instantiating
-fail_compilation/fail13203.d(20): Error: alias fail13203.FA2!1.T conflicts with alias fail13203.FA2!1.T at fail_compilation/fail13203.d(19)
-fail_compilation/fail13203.d(23): Error: template instance fail13203.FA2!1 error instantiating
+fail_compilation/fail13203.d(15): Error: alias `fail13203.FA1!1.T` conflicts with alias `fail13203.FA1!1.T` at fail_compilation/fail13203.d(14)
+fail_compilation/fail13203.d(22): Error: template instance `fail13203.FA1!1` error instantiating
+fail_compilation/fail13203.d(20): Error: alias `fail13203.FA2!1.T` conflicts with alias `fail13203.FA2!1.T` at fail_compilation/fail13203.d(19)
+fail_compilation/fail13203.d(23): Error: template instance `fail13203.FA2!1` error instantiating
---
*/
template FA1(int b)
@@ -25,10 +25,10 @@ alias A2 = FA2!1; // variable symbol is not overloadable
/*
TEST_OUTPUT:
---
-fail_compilation/fail13203.d(36): Error: alias fail13203.FB1!1.T conflicts with alias fail13203.FB1!1.T at fail_compilation/fail13203.d(37)
-fail_compilation/fail13203.d(44): Error: template instance fail13203.FB1!1 error instantiating
-fail_compilation/fail13203.d(41): Error: alias fail13203.FB2!1.T conflicts with alias fail13203.FB2!1.T at fail_compilation/fail13203.d(42)
-fail_compilation/fail13203.d(45): Error: template instance fail13203.FB2!1 error instantiating
+fail_compilation/fail13203.d(36): Error: alias `fail13203.FB1!1.T` conflicts with alias `fail13203.FB1!1.T` at fail_compilation/fail13203.d(37)
+fail_compilation/fail13203.d(44): Error: template instance `fail13203.FB1!1` error instantiating
+fail_compilation/fail13203.d(41): Error: alias `fail13203.FB2!1.T` conflicts with alias `fail13203.FB2!1.T` at fail_compilation/fail13203.d(42)
+fail_compilation/fail13203.d(45): Error: template instance `fail13203.FB2!1` error instantiating
---
*/
template FB1(int b)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail133.d b/gcc/testsuite/gdc.test/fail_compilation/fail133.d
index e189ad5..29b7d40 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail133.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail133.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail133.d(13): Error: function D main circular dependency. Functions cannot be interpreted while being compiled
-fail_compilation/fail133.d(15): called from here: main()
+fail_compilation/fail133.d(13): Error: function `D main` circular dependency. Functions cannot be interpreted while being compiled
+fail_compilation/fail133.d(15): called from here: `main()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d b/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d
index 5ab7e6c..e3f990c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail13336a.d(28): Error: choose(true) is not an lvalue
+fail_compilation/fail13336a.d(28): Error: `choose(true)` is not an lvalue and cannot be modified
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d b/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d
index 9d30d2c..b8fb12d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d
@@ -1,5 +1,4 @@
// REQUIRED_ARGS: -o-
-// PERMUTE_ARGS:
int sx;
double sy;
@@ -7,7 +6,8 @@ double sy;
/*
TEST_OUTPUT:
---
-fail_compilation/fail13336b.d(16): Error: cast(double)sx is not an lvalue
+fail_compilation/fail13336b.d(16): Error: `cast(double)sx` is not an lvalue and cannot be modified
+fail_compilation/fail13336b.d(24): Error: `cast(double)sx` is not an lvalue and cannot be modified
---
*/
ref f1(bool f)
@@ -17,12 +17,6 @@ ref f1(bool f)
return sy;
}
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail13336b.d(30): Error: cast(double)sx is not an lvalue
----
-*/
ref f2(bool f)
{
if (f)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail134.d b/gcc/testsuite/gdc.test/fail_compilation/fail134.d
index d7b4a36..d8ae89c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail134.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail134.d
@@ -1,13 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail134.d(13): Error: template instance foo!(f) does not match template declaration foo(T)
-fail_compilation/fail134.d(14): Error: template instance fail134.bar!(f) error instantiating
+fail_compilation/fail134.d(14): Error: template instance `foo!(f)` does not match template declaration `foo(T)`
+fail_compilation/fail134.d(14): `f` is not a type
+fail_compilation/fail134.d(15): Error: template instance `fail134.bar!(f)` error instantiating
---
*/
-// Issue 651 - Assertion failure: 'global.errors' on line 2622 in file 'template.c'
-
+// https://issues.dlang.org/show_bug.cgi?id=651
+// Assertion failure: 'global.errors' on line 2622 in file 'template.c'
void f() {}
template foo(T) {}
template bar(T...) { alias foo!(T) buz; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13424.d b/gcc/testsuite/gdc.test/fail_compilation/fail13424.d
index 31bed56..dcec523 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13424.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13424.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail13424.d(12): Error: delegate fail13424.S.__lambda2 cannot be struct members
-fail_compilation/fail13424.d(17): Error: delegate fail13424.U.__lambda2 cannot be union members
-fail_compilation/fail13424.d(22): Error: delegate fail13424.C.__lambda2 cannot be class members
+fail_compilation/fail13424.d(12): Error: delegate `fail13424.S.__lambda2` cannot be struct members
+fail_compilation/fail13424.d(17): Error: delegate `fail13424.U.__lambda2` cannot be union members
+fail_compilation/fail13424.d(22): Error: delegate `fail13424.C.__lambda2` cannot be class members
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13435.d b/gcc/testsuite/gdc.test/fail_compilation/fail13435.d
new file mode 100644
index 0000000..a3ef5e4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13435.d
@@ -0,0 +1,27 @@
+// https://issues.dlang.org/show_bug.cgi?id=13435
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail13435.d(22): Error: cannot implicitly convert expression `d` of type `int[]` to `S!int`
+fail_compilation/fail13435.d(22): `this._a = d` is the first assignment of `this._a` therefore it represents its initialization
+fail_compilation/fail13435.d(22): `opAssign` methods are not used for initialization, but for subsequent assignments
+---
+*/
+
+struct S(T)
+{
+ void opAssign(T[] arg) {}
+}
+
+class B
+{
+ this(int[] d)
+ {
+ S!int c;
+ _a = d; // Error: cannot implicitly convert expression (d) of type int[] to S!int
+ c = d; // compiles OK
+ }
+
+ S!int _a;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13498.d b/gcc/testsuite/gdc.test/fail_compilation/fail13498.d
index c18d2e3..27f47b3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13498.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13498.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/fail13498.d(11): Error: cannot implicitly convert expression `"foo"` of type `string` to `int`
-fail_compilation/fail13498.d(16): Error: template instance fail13498.foo!() error instantiating
+fail_compilation/fail13498.d(16): Error: template instance `fail13498.foo!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13574.d b/gcc/testsuite/gdc.test/fail_compilation/fail13574.d
index 081f8b5..2a9336b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13574.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13574.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail13574.d(21): Error: '$' is not an lvalue
-fail_compilation/fail13574.d(27): Error: '$' is not an lvalue
+fail_compilation/fail13574.d(21): Error: cannot modify operator `$`
+fail_compilation/fail13574.d(27): Error: cannot modify operator `$`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail136.d b/gcc/testsuite/gdc.test/fail_compilation/fail136.d
index bba0c51..299b994 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail136.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail136.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail136.d(10): Error: `string` has no effect in expression `"\xef\xbb\xbf"`
+fail_compilation/fail136.d(10): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"EF BB BF"` instead.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13601.d b/gcc/testsuite/gdc.test/fail_compilation/fail13601.d
index e1aa2d5..51291f4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13601.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13601.d
@@ -4,7 +4,7 @@ TEST_OUTPUT:
fail_compilation/fail13601.d(13): Error: variable `__ctfe` cannot be read at compile time
fail_compilation/fail13601.d(14): Error: variable `__ctfe` cannot be read at compile time
fail_compilation/fail13601.d(15): Error: variable `__ctfe` cannot be read at compile time
-fail_compilation/fail13601.d(16): Error: variable __ctfe cannot be read at compile time
+fail_compilation/fail13601.d(16): Error: variable `__ctfe` cannot be read at compile time
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13701.d b/gcc/testsuite/gdc.test/fail_compilation/fail13701.d
index c0bdfcc..88ed2d9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13701.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13701.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail13701.d(16): Error: cannot modify immutable expression this.aa[10]
-fail_compilation/fail13701.d(23): Error: cannot modify immutable expression aa[10]
-fail_compilation/fail13701.d(24): Error: cannot modify immutable expression aa[10]
+fail_compilation/fail13701.d(16): Error: cannot modify `immutable` expression `this.aa[10]`
+fail_compilation/fail13701.d(23): Error: cannot modify `immutable` expression `aa[10]`
+fail_compilation/fail13701.d(24): Error: cannot modify `immutable` expression `aa[10]`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13756.d b/gcc/testsuite/gdc.test/fail_compilation/fail13756.d
index 38dfeb8..cdf0e85 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13756.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13756.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail13756.d(11): Error: foreach: index must be type `const(int)`, not `int`
+fail_compilation/fail13756.d(11): Error: `foreach`: index must be type `const(int)`, not `int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail139.d b/gcc/testsuite/gdc.test/fail_compilation/fail139.d
index 22fc616..d5cdb99 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail139.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail139.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail139.d(8): Error: forward reference to 'test'
+fail_compilation/fail139.d(8): Error: forward reference to `test`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13902.d b/gcc/testsuite/gdc.test/fail_compilation/fail13902.d
index fbe4b4a..5e3b637 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13902.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13902.d
@@ -4,9 +4,11 @@ struct S1 { int v; }
struct S2 { int* p; }
class C { int v; }
+#line 6
/*
TEST_OUTPUT:
---
+fail_compilation/fail13902.d(45): Error: Using the result of a comma expression is not allowed
fail_compilation/fail13902.d(32): Error: returning `& x` escapes a reference to local variable `x`
fail_compilation/fail13902.d(33): Error: returning `&s1.v` escapes a reference to local variable `s1`
fail_compilation/fail13902.d(38): Error: returning `& sa1` escapes a reference to local variable `sa1`
@@ -47,17 +49,19 @@ int* testEscape1()
return null; // ok
}
+#line 49
/*
TEST_OUTPUT:
---
-fail_compilation/fail13902.d(75): Error: returning `& x` escapes a reference to parameter `x`, perhaps annotate with `return`
-fail_compilation/fail13902.d(76): Error: returning `&s1.v` escapes a reference to parameter `s1`, perhaps annotate with `return`
-fail_compilation/fail13902.d(81): Error: returning `& sa1` escapes a reference to parameter `sa1`, perhaps annotate with `return`
-fail_compilation/fail13902.d(82): Error: returning `&sa2[0][0]` escapes a reference to parameter `sa2`, perhaps annotate with `return`
-fail_compilation/fail13902.d(83): Error: returning `& x` escapes a reference to parameter `x`, perhaps annotate with `return`
-fail_compilation/fail13902.d(84): Error: returning `(& x+4)` escapes a reference to parameter `x`, perhaps annotate with `return`
-fail_compilation/fail13902.d(85): Error: returning `& x + cast(long)x * 4L` escapes a reference to parameter `x`, perhaps annotate with `return`
-fail_compilation/fail13902.d(88): Error: returning `& y` escapes a reference to parameter `y`, perhaps annotate with `return`
+fail_compilation/fail13902.d(88): Error: Using the result of a comma expression is not allowed
+fail_compilation/fail13902.d(75): Error: returning `& x` escapes a reference to local variable `x`
+fail_compilation/fail13902.d(76): Error: returning `&s1.v` escapes a reference to local variable `s1`
+fail_compilation/fail13902.d(81): Error: returning `& sa1` escapes a reference to local variable `sa1`
+fail_compilation/fail13902.d(82): Error: returning `&sa2[0][0]` escapes a reference to local variable `sa2`
+fail_compilation/fail13902.d(83): Error: returning `& x` escapes a reference to local variable `x`
+fail_compilation/fail13902.d(84): Error: returning `(& x+4)` escapes a reference to local variable `x`
+fail_compilation/fail13902.d(85): Error: returning `& x + cast(long)x * 4L` escapes a reference to local variable `x`
+fail_compilation/fail13902.d(88): Error: returning `& y` escapes a reference to local variable `y`
---
*/
int* testEscape2(
@@ -90,19 +94,21 @@ int* testEscape2(
return null; // ok
}
+#line 92
/*
TEST_OUTPUT:
---
+fail_compilation/fail13902.d(123): Error: Using the result of a comma expression is not allowed
---
*/
int* testEscape3(
- ref int x, ref int y,
+ return ref int x, return ref int y,
ref int[] da1,
ref int[][] da2,
- ref int[1] sa1,
- ref int[1][1] sa2,
+ return ref int[1] sa1,
+ return ref int[1][1] sa2,
ref int* ptr,
- ref S1 s1,
+ return ref S1 s1,
ref S2 s2,
ref C c,
)
@@ -128,9 +134,9 @@ int* testEscape3(
/*
TEST_OUTPUT:
---
-fail_compilation/fail13902.d(150): Error: returning `cast(int[])sa1` escapes a reference to parameter `sa1`, perhaps annotate with `return`
-fail_compilation/fail13902.d(151): Error: returning `cast(int[])sa1` escapes a reference to parameter `sa1`, perhaps annotate with `return`
-fail_compilation/fail13902.d(152): Error: returning `sa1[]` escapes a reference to parameter `sa1`, perhaps annotate with `return`
+fail_compilation/fail13902.d(150): Error: returning `cast(int[])sa1` escapes a reference to local variable `sa1`
+fail_compilation/fail13902.d(151): Error: returning `cast(int[])sa1` escapes a reference to local variable `sa1`
+fail_compilation/fail13902.d(152): Error: returning `sa1[]` escapes a reference to local variable `sa1`
fail_compilation/fail13902.d(155): Error: returning `cast(int[])sa2` escapes a reference to local variable `sa2`
fail_compilation/fail13902.d(156): Error: returning `cast(int[])sa2` escapes a reference to local variable `sa2`
fail_compilation/fail13902.d(157): Error: returning `sa2[]` escapes a reference to local variable `sa2`
@@ -145,7 +151,7 @@ fail_compilation/fail13902.d(172): Error: escaping reference to stack allocated
fail_compilation/fail13902.d(173): Error: escaping reference to stack allocated value returned by `makeS()`
---
*/
-int[] testEscape4(int[3] sa1) // Bugzilla 9279
+int[] testEscape4(int[3] sa1) // https://issues.dlang.org/show_bug.cgi?id=9279
{
if (0) return sa1; // error <- no error
if (0) return cast(int[])sa1; // error <- no error
@@ -217,14 +223,14 @@ ref int testEscapeRef1()
/*
TEST_OUTPUT:
---
-fail_compilation/fail13902.d(240): Error: returning `x` escapes a reference to parameter `x`, perhaps annotate with `return`
-fail_compilation/fail13902.d(241): Error: returning `s1.v` escapes a reference to parameter `s1`, perhaps annotate with `return`
-fail_compilation/fail13902.d(245): Error: returning `sa1[0]` escapes a reference to parameter `sa1`, perhaps annotate with `return`
-fail_compilation/fail13902.d(246): Error: returning `sa2[0][0]` escapes a reference to parameter `sa2`, perhaps annotate with `return`
-fail_compilation/fail13902.d(247): Error: returning `x = 1` escapes a reference to parameter `x`, perhaps annotate with `return`
-fail_compilation/fail13902.d(248): Error: returning `x += 1` escapes a reference to parameter `x`, perhaps annotate with `return`
-fail_compilation/fail13902.d(249): Error: returning `s1.v = 1` escapes a reference to parameter `s1`, perhaps annotate with `return`
-fail_compilation/fail13902.d(250): Error: returning `s1.v += 1` escapes a reference to parameter `s1`, perhaps annotate with `return`
+fail_compilation/fail13902.d(240): Error: returning `x` escapes a reference to local variable `x`
+fail_compilation/fail13902.d(241): Error: returning `s1.v` escapes a reference to local variable `s1`
+fail_compilation/fail13902.d(245): Error: returning `sa1[0]` escapes a reference to local variable `sa1`
+fail_compilation/fail13902.d(246): Error: returning `sa2[0][0]` escapes a reference to local variable `sa2`
+fail_compilation/fail13902.d(247): Error: returning `x = 1` escapes a reference to local variable `x`
+fail_compilation/fail13902.d(248): Error: returning `x += 1` escapes a reference to local variable `x`
+fail_compilation/fail13902.d(249): Error: returning `s1.v = 1` escapes a reference to local variable `s1`
+fail_compilation/fail13902.d(250): Error: returning `s1.v += 1` escapes a reference to local variable `s1`
---
*/
ref int testEscapeRef2(
@@ -259,12 +265,12 @@ TEST_OUTPUT:
---
*/
ref int testEscapeRef2(
- ref int x,
+ return ref int x,
ref int[] da1,
ref int[][] da2,
- ref int[1] sa1,
- ref int[1][1] sa2,
- ref S1 s1,
+ return ref int[1] sa1,
+ return ref int[1][1] sa2,
+ return ref S1 s1,
ref C c,
)
{
@@ -317,18 +323,18 @@ int[] testSlice2() { int[3] sa; int n; return sa[n..2][1..2]; }
/*
TEST_OUTPUT:
---
-fail_compilation/fail13902.d(324): Error: returning `vda[0]` escapes a reference to parameter `vda`, perhaps annotate with `return`
-fail_compilation/fail13902.d(325): Error: returning `vda[]` escapes a reference to variadic parameter `vda`
+fail_compilation/fail13902.d(324): Error: returning `vda[0]` escapes a reference to parameter `vda`
+fail_compilation/fail13902.d(324): perhaps annotate the parameter with `return`
---
*/
ref int testDynamicArrayVariadic1(int[] vda...) { return vda[0]; }
-int[] testDynamicArrayVariadic2(int[] vda...) { return vda[]; }
+@safe int[] testDynamicArrayVariadic2(int[] vda...) { return vda[]; }
int[3] testDynamicArrayVariadic3(int[] vda...) { return vda[0..3]; } // no error
/*
TEST_OUTPUT:
---
-fail_compilation/fail13902.d(335): Error: returning `vsa[0]` escapes a reference to parameter `vsa`, perhaps annotate with `return`
+fail_compilation/fail13902.d(335): Error: returning `vsa[0]` escapes a reference to local variable `vsa`
fail_compilation/fail13902.d(336): Error: returning `vsa[]` escapes a reference to variadic parameter `vsa`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14089.d b/gcc/testsuite/gdc.test/fail_compilation/fail14089.d
index df1221a..f609104 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail14089.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14089.d
@@ -1,16 +1,16 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail14089.d(41): Error: `long` has no effect in expression `1`
-fail_compilation/fail14089.d(41): Error: `long` has no effect in expression `1`
-fail_compilation/fail14089.d(42): Error: `long` has no effect in expression `1`
-fail_compilation/fail14089.d(42): Error: `var` has no effect in expression `n`
-fail_compilation/fail14089.d(43): Error: `long` has no effect in expression `1`
-fail_compilation/fail14089.d(43): Error: `dotvar` has no effect in expression `s.val`
-fail_compilation/fail14089.d(44): Error: `var` has no effect in expression `n`
-fail_compilation/fail14089.d(44): Error: `long` has no effect in expression `1`
-fail_compilation/fail14089.d(45): Error: `dotvar` has no effect in expression `s.val`
-fail_compilation/fail14089.d(45): Error: `long` has no effect in expression `1`
+fail_compilation/fail14089.d(41): Error: `1` has no effect
+fail_compilation/fail14089.d(41): Error: `1` has no effect
+fail_compilation/fail14089.d(42): Error: `1` has no effect
+fail_compilation/fail14089.d(42): Error: `n` has no effect
+fail_compilation/fail14089.d(43): Error: `1` has no effect
+fail_compilation/fail14089.d(43): Error: `s.val` has no effect
+fail_compilation/fail14089.d(44): Error: `n` has no effect
+fail_compilation/fail14089.d(44): Error: `1` has no effect
+fail_compilation/fail14089.d(45): Error: `s.val` has no effect
+fail_compilation/fail14089.d(45): Error: `1` has no effect
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail142.d b/gcc/testsuite/gdc.test/fail_compilation/fail142.d
index e89b576..343b2e3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail142.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail142.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail142.d(20): Error: cannot create instance of abstract class B
-fail_compilation/fail142.d(20): function 'void test()' is not implemented
+fail_compilation/fail142.d(20): Error: cannot create instance of abstract class `B`
+fail_compilation/fail142.d(20): function `void test()` is not implemented
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14249.d b/gcc/testsuite/gdc.test/fail_compilation/fail14249.d
index c895c55..8d66a75 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail14249.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14249.d
@@ -2,20 +2,18 @@
REQUIRED_ARGS: -unittest
TEST_OUTPUT:
---
-fail_compilation/fail14249.d(23): Error: shared static constructor can only be member of module/aggregate/template, not function main
-fail_compilation/fail14249.d(24): Error: shared static destructor can only be member of module/aggregate/template, not function main
-fail_compilation/fail14249.d(25): Error: static constructor can only be member of module/aggregate/template, not function main
-fail_compilation/fail14249.d(26): Error: static destructor can only be member of module/aggregate/template, not function main
-fail_compilation/fail14249.d(27): Error: unittest can only be a member of module/aggregate/template, not function main
-fail_compilation/fail14249.d(28): Error: invariant can only be a member of aggregate, not function main
-fail_compilation/fail14249.d(29): Error: alias this can only be a member of aggregate, not function `main`
-fail_compilation/fail14249.d(30): Error: allocator can only be a member of aggregate, not function main
-fail_compilation/fail14249.d(31): Error: deallocator can only be a member of aggregate, not function main
-fail_compilation/fail14249.d(32): Error: constructor can only be a member of aggregate, not function main
-fail_compilation/fail14249.d(33): Error: destructor can only be a member of aggregate, not function main
-fail_compilation/fail14249.d(34): Error: postblit can only be a member of struct/union, not function main
-fail_compilation/fail14249.d(35): Error: anonymous union can only be a part of an aggregate, not function `main`
-fail_compilation/fail14249.d(39): Error: mixin fail14249.main.Mix!() error instantiating
+fail_compilation/fail14249.d(21): Error: `shared static` constructor can only be member of module/aggregate/template, not function `main`
+fail_compilation/fail14249.d(22): Error: `shared static` destructor can only be member of module/aggregate/template, not function `main`
+fail_compilation/fail14249.d(23): Error: `static` constructor can only be member of module/aggregate/template, not function `main`
+fail_compilation/fail14249.d(24): Error: `static` destructor can only be member of module/aggregate/template, not function `main`
+fail_compilation/fail14249.d(25): Error: `unittest` can only be a member of module/aggregate/template, not function `main`
+fail_compilation/fail14249.d(26): Error: `invariant` can only be a member of aggregate, not function `main`
+fail_compilation/fail14249.d(27): Error: alias this can only be a member of aggregate, not function `main`
+fail_compilation/fail14249.d(28): Error: constructor can only be a member of aggregate, not function `main`
+fail_compilation/fail14249.d(29): Error: destructor can only be a member of aggregate, not function `main`
+fail_compilation/fail14249.d(30): Error: postblit can only be a member of struct, not function `main`
+fail_compilation/fail14249.d(31): Error: anonymous union can only be a part of an aggregate, not function `main`
+fail_compilation/fail14249.d(35): Error: mixin `fail14249.main.Mix!()` error instantiating
---
*/
mixin template Mix()
@@ -27,8 +25,6 @@ mixin template Mix()
unittest {}
invariant {}
alias a this;
- new(size_t sz) { return null; }
- delete(void* p) { }
this() {} // from fail268.d
~this() {} // from fail268.d
this(this) {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail143.d b/gcc/testsuite/gdc.test/fail_compilation/fail143.d
index 0a0986a..6df232f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail143.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail143.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail143.d(23): Error: need 'this' for 'next' of type 'uint()'
-fail_compilation/fail143.d(30): Error: template instance fail143.Foo!int error instantiating
+fail_compilation/fail143.d(23): Error: need `this` for `next` of type `uint()`
+fail_compilation/fail143.d(30): Error: template instance `fail143.Foo!int` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14304.d b/gcc/testsuite/gdc.test/fail_compilation/fail14304.d
index 472b33d..8321401 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail14304.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14304.d
@@ -1,16 +1,16 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail14304.d(26): Error: cannot modify read-only constant S14304(1)
-fail_compilation/fail14304.d(58): called from here: sle14304.modify()
-fail_compilation/fail14304.d(35): Error: cannot modify read-only constant [1:1, 2:2]
-fail_compilation/fail14304.d(61): called from here: modify14304(aae14304)
-fail_compilation/fail14304.d(41): Error: cannot modify read-only constant [1, 2, 3]
-fail_compilation/fail14304.d(64): called from here: modify14304(cast(const(int)[])index14304)
-fail_compilation/fail14304.d(47): Error: cannot modify read-only constant [1.414, 1.732, 2.00000]
-fail_compilation/fail14304.d(67): called from here: modify14304(cast(const(double)[])slice14304)
-fail_compilation/fail14304.d(53): Error: cannot modify read-only string literal "abc"
-fail_compilation/fail14304.d(70): called from here: modify14304(cast(const(char)[])str14304)
+fail_compilation/fail14304.d(26): Error: reinterpreting cast from `const(S14304)*` to `S14304*` is not supported in CTFE
+fail_compilation/fail14304.d(58): called from here: `sle14304.modify()`
+fail_compilation/fail14304.d(35): Error: cannot modify read-only constant `[1:1, 2:2]`
+fail_compilation/fail14304.d(61): called from here: `modify14304(aae14304)`
+fail_compilation/fail14304.d(41): Error: cannot modify read-only constant `[1, 2, 3]`
+fail_compilation/fail14304.d(64): called from here: `modify14304(cast(const(int)[])index14304)`
+fail_compilation/fail14304.d(46): Error: array cast from `immutable(double[])` to `double[]` is not supported at compile time
+fail_compilation/fail14304.d(67): called from here: `modify14304(cast(const(double)[])slice14304)`
+fail_compilation/fail14304.d(53): Error: cannot modify read-only string literal `"abc"`
+fail_compilation/fail14304.d(70): called from here: `modify14304(cast(const(char)[])str14304)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail144.d b/gcc/testsuite/gdc.test/fail_compilation/fail144.d
index 574d167..6e73d3b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail144.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail144.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail144.d(13): Error: "message"
-fail_compilation/fail144.d(26): called from here: bar(7)
+fail_compilation/fail144.d(13): Error: `"message"`
+fail_compilation/fail144.d(26): called from here: `bar(7)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14406.d b/gcc/testsuite/gdc.test/fail_compilation/fail14406.d
index 09f4816..3725a91 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail14406.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14406.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail14406.d-mixin-20(20): Error: variable fail14406.CFrop.bar_obj cannot be further field because it will change the determined CFrop size
-fail_compilation/fail14406.d-mixin-25(25): Error: variable fail14406.IFrop.bar_obj field not allowed in interface
+fail_compilation/fail14406.d-mixin-20(20): Error: variable `fail14406.CFrop.bar_obj` cannot be further field because it will change the determined CFrop size
+fail_compilation/fail14406.d-mixin-25(25): Error: variable `fail14406.IFrop.bar_obj` field not allowed in interface
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14407.d b/gcc/testsuite/gdc.test/fail_compilation/fail14407.d
deleted file mode 100644
index 341c5ca..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail14407.d
+++ /dev/null
@@ -1,47 +0,0 @@
-import imports.a14407;
-
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail14407.d(23): Deprecation: class imports.a14407.C is deprecated
-fail_compilation/fail14407.d(23): Deprecation: allocator imports.a14407.C.new is deprecated
-fail_compilation/fail14407.d(23): Error: pure function 'fail14407.testC' cannot call impure allocator 'imports.a14407.C.new'
-fail_compilation/fail14407.d(23): Error: @safe function 'fail14407.testC' cannot call @system allocator 'imports.a14407.C.new'
-fail_compilation/fail14407.d(23): Error: @nogc function 'fail14407.testC' cannot call non-@nogc allocator 'imports.a14407.C.new'
-fail_compilation/fail14407.d(23): Error: class imports.a14407.C member `new` is not accessible
-fail_compilation/fail14407.d(23): Error: pure function 'fail14407.testC' cannot call impure constructor 'imports.a14407.C.this'
-fail_compilation/fail14407.d(23): Error: @safe function 'fail14407.testC' cannot call @system constructor 'imports.a14407.C.this'
-fail_compilation/fail14407.d(23): Error: @nogc function 'fail14407.testC' cannot call non-@nogc constructor 'imports.a14407.C.this'
-fail_compilation/fail14407.d(23): Error: class imports.a14407.C member `this` is not accessible
-fail_compilation/fail14407.d(23): Error: allocator `imports.a14407.C.new` is not nothrow
-fail_compilation/fail14407.d(23): Error: constructor `imports.a14407.C.this` is not nothrow
-fail_compilation/fail14407.d(21): Error: nothrow function `fail14407.testC` may throw
----
-*/
-void testC() pure nothrow @safe @nogc
-{
- new("arg") C(0);
-}
-
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail14407.d(46): Deprecation: struct imports.a14407.S is deprecated
-fail_compilation/fail14407.d(46): Deprecation: allocator imports.a14407.S.new is deprecated
-fail_compilation/fail14407.d(46): Error: pure function 'fail14407.testS' cannot call impure allocator 'imports.a14407.S.new'
-fail_compilation/fail14407.d(46): Error: @safe function 'fail14407.testS' cannot call @system allocator 'imports.a14407.S.new'
-fail_compilation/fail14407.d(46): Error: @nogc function 'fail14407.testS' cannot call non-@nogc allocator 'imports.a14407.S.new'
-fail_compilation/fail14407.d(46): Error: struct imports.a14407.S member `new` is not accessible
-fail_compilation/fail14407.d(46): Error: pure function 'fail14407.testS' cannot call impure constructor 'imports.a14407.S.this'
-fail_compilation/fail14407.d(46): Error: @safe function 'fail14407.testS' cannot call @system constructor 'imports.a14407.S.this'
-fail_compilation/fail14407.d(46): Error: @nogc function 'fail14407.testS' cannot call non-@nogc constructor 'imports.a14407.S.this'
-fail_compilation/fail14407.d(46): Error: struct imports.a14407.S member `this` is not accessible
-fail_compilation/fail14407.d(46): Error: allocator `imports.a14407.S.new` is not nothrow
-fail_compilation/fail14407.d(46): Error: constructor `imports.a14407.S.this` is not nothrow
-fail_compilation/fail14407.d(44): Error: nothrow function `fail14407.testS` may throw
----
-*/
-void testS() pure nothrow @safe @nogc
-{
- new("arg") S(0);
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14416.d b/gcc/testsuite/gdc.test/fail_compilation/fail14416.d
index b0518c8..9d0b3e8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail14416.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14416.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail14416.d(13): Error: template S(T) does not have property 'sizeof'
+fail_compilation/fail14416.d(13): Error: template `S(T)` does not have property `sizeof`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14486.d b/gcc/testsuite/gdc.test/fail_compilation/fail14486.d
index 84af9cf..07152f4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail14486.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14486.d
@@ -41,148 +41,48 @@ fail_compilation/fail14486.d(84): Error: `nothrow` function `fail14486.test3b` m
class C0a { }
class C1a { ~this() {} }
-class C2a { ~this() {} @nogc pure @safe delete(void* p) {} }
-class C3a { @nogc pure @safe ~this() {} delete(void* p) {} }
-class C4a { @nogc pure @safe ~this() {} @nogc pure @safe delete(void* p) {} }
class C0b { }
class C1b { ~this() {} }
-class C2b { ~this() {} nothrow delete(void* p) {} }
-class C3b { nothrow ~this() {} delete(void* p) {} }
-class C4b { nothrow ~this() {} nothrow delete(void* p) {} }
struct S0a { }
struct S1a { ~this() {} }
-struct S2a { ~this() {} @nogc pure @safe delete(void* p) {} }
-struct S3a { @nogc pure @safe ~this() {} delete(void* p) {} }
-struct S4a { @nogc pure @safe ~this() {} @nogc pure @safe delete(void* p) {} }
struct S0b { }
struct S1b { ~this() {} }
-struct S2b { ~this() {} nothrow delete(void* p) {} }
-struct S3b { nothrow ~this() {} delete(void* p) {} }
-struct S4b { nothrow ~this() {} nothrow delete(void* p) {} }
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail14486.d(44): Error: delete c0 is not @safe but is used in @safe function test1a
-fail_compilation/fail14486.d(45): Error: pure function 'fail14486.test1a' cannot call impure destructor 'fail14486.C1a.~this'
-fail_compilation/fail14486.d(45): Error: @safe function 'fail14486.test1a' cannot call @system destructor 'fail14486.C1a.~this'
-fail_compilation/fail14486.d(45): Error: @nogc function 'fail14486.test1a' cannot call non-@nogc destructor 'fail14486.C1a.~this'
-fail_compilation/fail14486.d(46): Error: pure function 'fail14486.test1a' cannot call impure destructor 'fail14486.C2a.~this'
-fail_compilation/fail14486.d(46): Error: @safe function 'fail14486.test1a' cannot call @system destructor 'fail14486.C2a.~this'
-fail_compilation/fail14486.d(46): Error: @nogc function 'fail14486.test1a' cannot call non-@nogc destructor 'fail14486.C2a.~this'
-fail_compilation/fail14486.d(47): Error: pure function 'fail14486.test1a' cannot call impure deallocator 'fail14486.C3a.delete'
-fail_compilation/fail14486.d(47): Error: @safe function 'fail14486.test1a' cannot call @system deallocator 'fail14486.C3a.delete'
-fail_compilation/fail14486.d(47): Error: @nogc function 'fail14486.test1a' cannot call non-@nogc deallocator 'fail14486.C3a.delete'
-fail_compilation/fail14486.d(48): Error: delete c4 is not @safe but is used in @safe function test1a
----*/
void test1a() @nogc pure @safe
{
C0a c0; delete c0; // error
C1a c1; delete c1; // error
- C2a c2; delete c2; // error
- C3a c3; delete c3; // error
- C4a c4; delete c4; // no error
}
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail14486.d(63): Error: destructor `fail14486.C1b.~this` is not nothrow
-fail_compilation/fail14486.d(64): Error: destructor `fail14486.C2b.~this` is not nothrow
-fail_compilation/fail14486.d(65): Error: deallocator `fail14486.C3b.delete` is not nothrow
-fail_compilation/fail14486.d(60): Error: nothrow function `fail14486.test1b` may throw
----
-*/
void test1b() nothrow
{
C0b c0; delete c0; // no error
C1b c1; delete c1; // error
- C2b c2; delete c2; // error
- C3b c3; delete c3; // error
- C4b c4; delete c4; // no error
}
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail14486.d(86): Error: delete s0 is not @safe but is used in @safe function test2a
-fail_compilation/fail14486.d(87): Error: pure function 'fail14486.test2a' cannot call impure destructor 'fail14486.S1a.~this'
-fail_compilation/fail14486.d(87): Error: @safe function 'fail14486.test2a' cannot call @system destructor 'fail14486.S1a.~this'
-fail_compilation/fail14486.d(87): Error: @nogc function 'fail14486.test2a' cannot call non-@nogc destructor 'fail14486.S1a.~this'
-fail_compilation/fail14486.d(88): Error: pure function 'fail14486.test2a' cannot call impure destructor 'fail14486.S2a.~this'
-fail_compilation/fail14486.d(88): Error: @safe function 'fail14486.test2a' cannot call @system destructor 'fail14486.S2a.~this'
-fail_compilation/fail14486.d(88): Error: @nogc function 'fail14486.test2a' cannot call non-@nogc destructor 'fail14486.S2a.~this'
-fail_compilation/fail14486.d(89): Error: pure function 'fail14486.test2a' cannot call impure deallocator 'fail14486.S3a.delete'
-fail_compilation/fail14486.d(89): Error: @safe function 'fail14486.test2a' cannot call @system deallocator 'fail14486.S3a.delete'
-fail_compilation/fail14486.d(89): Error: @nogc function 'fail14486.test2a' cannot call non-@nogc deallocator 'fail14486.S3a.delete'
----
-*/
void test2a() @nogc pure @safe
{
S0a* s0; delete s0; // error
S1a* s1; delete s1; // error
- S2a* s2; delete s2; // error
- S3a* s3; delete s3; // error
- S4a* s4; delete s4; // no error
}
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail14486.d(105): Error: destructor `fail14486.S1b.~this` is not nothrow
-fail_compilation/fail14486.d(106): Error: destructor `fail14486.S2b.~this` is not nothrow
-fail_compilation/fail14486.d(107): Error: deallocator `fail14486.S3b.delete` is not nothrow
-fail_compilation/fail14486.d(102): Error: nothrow function `fail14486.test2b` may throw
----
-*/
void test2b() nothrow
{
S0b* s0; delete s0; // no error
S1b* s1; delete s1; // error
- S2b* s2; delete s2; // error
- S3b* s3; delete s3; // error
- S4b* s4; delete s4; // no error
}
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail14486.d(127): Error: delete a0 is not @safe but is used in @safe function test3a
-fail_compilation/fail14486.d(128): Error: pure function 'fail14486.test3a' cannot call impure destructor 'fail14486.S1a.~this'
-fail_compilation/fail14486.d(128): Error: @safe function 'fail14486.test3a' cannot call @system destructor 'fail14486.S1a.~this'
-fail_compilation/fail14486.d(128): Error: @nogc function 'fail14486.test3a' cannot call non-@nogc destructor 'fail14486.S1a.~this'
-fail_compilation/fail14486.d(129): Error: pure function 'fail14486.test3a' cannot call impure destructor 'fail14486.S2a.~this'
-fail_compilation/fail14486.d(129): Error: @safe function 'fail14486.test3a' cannot call @system destructor 'fail14486.S2a.~this'
-fail_compilation/fail14486.d(129): Error: @nogc function 'fail14486.test3a' cannot call non-@nogc destructor 'fail14486.S2a.~this'
-fail_compilation/fail14486.d(130): Error: delete a3 is not @safe but is used in @safe function test3a
-fail_compilation/fail14486.d(131): Error: delete a4 is not @safe but is used in @safe function test3a
----
-*/
void test3a() @nogc pure @safe
{
S0a[] a0; delete a0; // error
S1a[] a1; delete a1; // error
- S2a[] a2; delete a2; // error
- S3a[] a3; delete a3; // error
- S4a[] a4; delete a4; // error
}
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail14486.d(145): Error: destructor `fail14486.S1b.~this` is not nothrow
-fail_compilation/fail14486.d(146): Error: destructor `fail14486.S2b.~this` is not nothrow
-fail_compilation/fail14486.d(142): Error: nothrow function `fail14486.test3b` may throw
----
-*/
void test3b() nothrow
{
S0b[] a0; delete a0; // no error
S1b[] a1; delete a1; // error
- S2b[] a2; delete a2; // error
- S3b[] a3; delete a3; // no error
- S4b[] a4; delete a4; // no error
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail145.d b/gcc/testsuite/gdc.test/fail_compilation/fail145.d
index 9d285dc..5a7a4ca 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail145.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail145.d
@@ -1,8 +1,9 @@
/*
+REQUIRED_ARGS: -checkaction=context
TEST_OUTPUT:
---
-fail_compilation/fail145.d(13): Error: assert(i < 0) failed
-fail_compilation/fail145.d(26): called from here: bar(7)
+fail_compilation/fail145.d(14): Error: `"assert(i && (i < 0)) failed"`
+fail_compilation/fail145.d(27): called from here: `bar(7)`
---
*/
@@ -10,7 +11,7 @@ fail_compilation/fail145.d(26): called from here: bar(7)
int bar(int i)
{
- assert(i < 0);
+ assert(i && i < 0);
foreach_reverse (k, v; "hello")
{
i <<= 1;
@@ -26,5 +27,5 @@ void main()
static b = bar(7);
auto c = bar(7);
//printf("b = %d, %d\n", b, c);
- assert(b == 674);
+ assert(b && b == 674);
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14554.d b/gcc/testsuite/gdc.test/fail_compilation/fail14554.d
index 5d4e96c..73b0a78 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail14554.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14554.d
@@ -3,14 +3,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail14554.d(28): Error: fail14554.issue14554_1.foo called with argument types (int) matches both:
-fail_compilation/fail14554.d(17): fail14554.issue14554_1.foo!bool.foo(int j)
+fail_compilation/fail14554.d(28): Error: `fail14554.issue14554_1.foo` called with argument types `(int)` matches both:
+fail_compilation/fail14554.d(17): `fail14554.issue14554_1.foo!bool.foo(int j)`
and:
-fail_compilation/fail14554.d(18): fail14554.issue14554_1.foo!bool.foo(int j)
-fail_compilation/fail14554.d(29): Error: fail14554.issue14554_2.foo called with argument types (int) matches both:
-fail_compilation/fail14554.d(22): fail14554.issue14554_2.foo!bool.foo(int j)
+fail_compilation/fail14554.d(18): `fail14554.issue14554_1.foo!bool.foo(int j)`
+fail_compilation/fail14554.d(29): Error: `fail14554.issue14554_2.foo` called with argument types `(int)` matches both:
+fail_compilation/fail14554.d(22): `fail14554.issue14554_2.foo!bool.foo(int j)`
and:
-fail_compilation/fail14554.d(23): fail14554.issue14554_2.foo!bool.foo(int j)
+fail_compilation/fail14554.d(23): `fail14554.issue14554_2.foo!bool.foo(int j)`
---
*/
struct issue14554_1 {
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14669.d b/gcc/testsuite/gdc.test/fail_compilation/fail14669.d
index 8984001..c5ae8e7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail14669.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14669.d
@@ -1,11 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail14669.d(11): Error: 'auto' can only be used as part of 'auto ref' for template function parameters
-fail_compilation/fail14669.d(16): Error: template instance fail14669.foo1!() error instantiating
-fail_compilation/fail14669.d(12): Error: 'auto' can only be used as part of 'auto ref' for template function parameters
-fail_compilation/fail14669.d(17): Error: template fail14669.foo2 cannot deduce function from argument types !()(int), candidates are:
-fail_compilation/fail14669.d(12): fail14669.foo2()(auto int a)
+fail_compilation/fail14669.d(11): Error: `auto` can only be used as part of `auto ref` for template function parameters
+fail_compilation/fail14669.d(16): Error: template instance `fail14669.foo1!()` error instantiating
+fail_compilation/fail14669.d(12): Error: `auto` can only be used as part of `auto ref` for template function parameters
+fail_compilation/fail14669.d(17): Error: template `fail14669.foo2` cannot deduce function from argument types `!()(int)`
+fail_compilation/fail14669.d(12): Candidate is: `foo2()(auto int a)`
---
*/
void foo1()(auto int a) {}
@@ -20,10 +20,10 @@ void test1()
/*
TEST_OUTPUT:
---
-fail_compilation/fail14669.d(29): Error: 'auto' can only be used as part of 'auto ref' for template function parameters
-fail_compilation/fail14669.d(38): Error: template instance fail14669.bar1!int error instantiating
-fail_compilation/fail14669.d(30): Error: 'auto' can only be used as part of 'auto ref' for template function parameters
-fail_compilation/fail14669.d(40): Error: template instance fail14669.bar2!int error instantiating
+fail_compilation/fail14669.d(29): Error: `auto` can only be used as part of `auto ref` for template function parameters
+fail_compilation/fail14669.d(38): Error: template instance `fail14669.bar1!int` error instantiating
+fail_compilation/fail14669.d(30): Error: `auto` can only be used as part of `auto ref` for template function parameters
+fail_compilation/fail14669.d(40): Error: template instance `fail14669.bar2!int` error instantiating
---
*/
void bar1(T)(auto ref T x) {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14965.d b/gcc/testsuite/gdc.test/fail_compilation/fail14965.d
index f1a1ec1..37fc0fa 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail14965.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14965.d
@@ -1,18 +1,18 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail14965.d(19): Error: forward reference to inferred return type of function 'foo1'
-fail_compilation/fail14965.d(20): Error: forward reference to inferred return type of function 'foo2'
-fail_compilation/fail14965.d(22): Error: forward reference to inferred return type of function 'bar1'
-fail_compilation/fail14965.d(23): Error: forward reference to inferred return type of function 'bar2'
-fail_compilation/fail14965.d(25): Error: forward reference to inferred return type of function 'baz1'
-fail_compilation/fail14965.d(26): Error: forward reference to inferred return type of function 'baz2'
-fail_compilation/fail14965.d(30): Error: forward reference to inferred return type of function 'foo1'
-fail_compilation/fail14965.d(31): Error: forward reference to inferred return type of function 'foo2'
-fail_compilation/fail14965.d(33): Error: forward reference to inferred return type of function 'bar1'
-fail_compilation/fail14965.d(34): Error: forward reference to inferred return type of function 'bar2'
-fail_compilation/fail14965.d(36): Error: forward reference to inferred return type of function 'baz1'
-fail_compilation/fail14965.d(37): Error: forward reference to inferred return type of function 'baz2'
+fail_compilation/fail14965.d(19): Error: forward reference to inferred return type of function `foo1`
+fail_compilation/fail14965.d(20): Error: forward reference to inferred return type of function `foo2`
+fail_compilation/fail14965.d(22): Error: forward reference to inferred return type of function `bar1`
+fail_compilation/fail14965.d(23): Error: forward reference to inferred return type of function `bar2`
+fail_compilation/fail14965.d(25): Error: forward reference to inferred return type of function `baz1`
+fail_compilation/fail14965.d(26): Error: forward reference to inferred return type of function `baz2`
+fail_compilation/fail14965.d(30): Error: forward reference to inferred return type of function `foo1`
+fail_compilation/fail14965.d(31): Error: forward reference to inferred return type of function `foo2`
+fail_compilation/fail14965.d(33): Error: forward reference to inferred return type of function `bar1`
+fail_compilation/fail14965.d(34): Error: forward reference to inferred return type of function `bar2`
+fail_compilation/fail14965.d(36): Error: forward reference to inferred return type of function `baz1`
+fail_compilation/fail14965.d(37): Error: forward reference to inferred return type of function `baz2`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14997.d b/gcc/testsuite/gdc.test/fail_compilation/fail14997.d
new file mode 100644
index 0000000..3654f04
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14997.d
@@ -0,0 +1,20 @@
+// https://issues.dlang.org/show_bug.cgi?id=14997
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail14997.d(19): Error: none of the overloads of `this` are callable using argument types `()`
+fail_compilation/fail14997.d(14): Candidates are: `fail14997.Foo.this(int a)`
+fail_compilation/fail14997.d(15): `fail14997.Foo.this(string a)`
+---
+*/
+
+class Foo
+{
+ this (int a) {}
+ this (string a) {}
+}
+void main()
+{
+ auto a = new Foo;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail150.d b/gcc/testsuite/gdc.test/fail_compilation/fail150.d
index 4a53053..6ba04c1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail150.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail150.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail150.d(22): Error: e.new is only for allocating nested classes
+fail_compilation/fail150.d(22): Error: `.new` is only for allocating nested classes
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15068.d b/gcc/testsuite/gdc.test/fail_compilation/fail15068.d
new file mode 100644
index 0000000..ca555b0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail15068.d
@@ -0,0 +1,18 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail15068.d(17): Error: `T!int` is not a valid template instance, because `T` is not a template declaration but a type (`T == int`)
+fail_compilation/fail15068.d(13): Error: template instance `fail15068.Stuff!int` error instantiating
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=15068
+
+void main()
+{
+ Stuff!int s;
+}
+struct Stuff(T)
+{
+ T!int var;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail153.d b/gcc/testsuite/gdc.test/fail_compilation/fail153.d
index 8e397e3..96cd383 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail153.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail153.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail153.d(10): Error: class fail153.Bar cannot inherit from final class Foo
+fail_compilation/fail153.d(10): Error: class `fail153.Bar` cannot inherit from class `Foo` because it is `final`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail154.d b/gcc/testsuite/gdc.test/fail_compilation/fail154.d
index 8b5fefc..ee9eb42 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail154.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail154.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail154.d(18): Error: template instance X!(MYP!int) does not match template declaration X(T : Policy!T, alias Policy)
+fail_compilation/fail154.d(18): Error: template instance `X!(MYP!int)` does not match template declaration `X(T : Policy!T, alias Policy)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail155.d b/gcc/testsuite/gdc.test/fail_compilation/fail155.d
index cc1e03c..6d8f184 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail155.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail155.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail155.d(19): Error: overlapping initialization for y
+fail_compilation/fail155.d(20): Error: overlapping initialization for `y`
+fail_compilation/fail155.d(20): `struct` initializers that contain anonymous unions must initialize only the first member of a `union`. All subsequent non-overlapping fields are default initialized
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15535.d b/gcc/testsuite/gdc.test/fail_compilation/fail15535.d
index d53e4d7..6f71a92 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail15535.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail15535.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail15535.d(17): Error: goto default not allowed in final switch statement
+fail_compilation/fail15535.d(17): Error: `goto default` not allowed in `final switch` statement
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15550.d b/gcc/testsuite/gdc.test/fail_compilation/fail15550.d
index e20a7f2..f7b910c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail15550.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail15550.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail15550.d(25): Error: partial template instance foo!int has no type
-fail_compilation/fail15550.d(26): Error: partial template instance opDispatch!"_isMatrix" has no type
-fail_compilation/fail15550.d(27): Error: partial template instance baz!"_isMatrix" has no type
+fail_compilation/fail15550.d(25): Error: partial template instance `foo!int` has no type
+fail_compilation/fail15550.d(26): Error: partial template instance `opDispatch!"_isMatrix"` has no type
+fail_compilation/fail15550.d(27): Error: partial template instance `baz!"_isMatrix"` has no type
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail156.d b/gcc/testsuite/gdc.test/fail_compilation/fail156.d
index cfd5b83..bfc2383b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail156.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail156.d
@@ -2,8 +2,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail156.d(33): Error: overlapping initialization for y
-fail_compilation/fail156.d(40): Error: overlapping initialization for y
+fail_compilation/fail156.d(35): Error: overlapping initialization for `y`
+fail_compilation/fail156.d(35): `struct` initializers that contain anonymous unions must initialize only the first member of a `union`. All subsequent non-overlapping fields are default initialized
+fail_compilation/fail156.d(42): Error: overlapping initialization for `y`
+fail_compilation/fail156.d(42): `struct` initializers that contain anonymous unions must initialize only the first member of a `union`. All subsequent non-overlapping fields are default initialized
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15616a.d b/gcc/testsuite/gdc.test/fail_compilation/fail15616a.d
index 9726e3df..e047365 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail15616a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail15616a.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail15616a.d(41): Error: none of the overloads of 'foo' are callable using argument types (double), candidates are:
-fail_compilation/fail15616a.d(14): fail15616a.foo(int a)
-fail_compilation/fail15616a.d(17): fail15616a.foo(int a, int b)
-fail_compilation/fail15616a.d(26): fail15616a.foo(int a, int b, int c)
-fail_compilation/fail15616a.d(29): fail15616a.foo(string a)
-fail_compilation/fail15616a.d(32): fail15616a.foo(string a, string b)
+fail_compilation/fail15616a.d(41): Error: none of the overloads of `foo` are callable using argument types `(double)`
+fail_compilation/fail15616a.d(14): Candidates are: `fail15616a.foo(int a)`
+fail_compilation/fail15616a.d(17): `fail15616a.foo(int a, int b)`
+fail_compilation/fail15616a.d(26): `fail15616a.foo(int a, int b, int c)`
+fail_compilation/fail15616a.d(29): `fail15616a.foo(string a)`
+fail_compilation/fail15616a.d(32): `fail15616a.foo(string a, string b)`
fail_compilation/fail15616a.d(41): ... (3 more, -v to show) ...
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15616b.d b/gcc/testsuite/gdc.test/fail_compilation/fail15616b.d
index 4776f40..faad0f1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail15616b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail15616b.d
@@ -1,19 +1,33 @@
/*
REQUIRED_ARGS: -v
+TRANSFORM_OUTPUT: remove_lines("^(predefs|binary|version|config|DFLAG|parse|import|semantic|entry|\s*$)")
TEST_OUTPUT:
---
-fail_compilation/fail15616b.d(43): Error: none of the overloads of 'foo' are callable using argument types (double), candidates are:
-fail_compilation/fail15616b.d(16): fail15616b.foo(int a)
-fail_compilation/fail15616b.d(19): fail15616b.foo(int a, int b)
-fail_compilation/fail15616b.d(28): fail15616b.foo(int a, int b, int c)
-fail_compilation/fail15616b.d(31): fail15616b.foo(string a)
-fail_compilation/fail15616b.d(34): fail15616b.foo(string a, string b)
-fail_compilation/fail15616b.d(37): fail15616b.foo(string a, string b, string c)
-fail_compilation/fail15616b.d(22): fail15616b.foo(T)(T a) if (is(T == float))
-fail_compilation/fail15616b.d(25): fail15616b.foo(T)(T a) if (is(T == char))
+fail_compilation/fail15616b.d(44): Error: none of the overloads of `foo` are callable using argument types `(double)`
+fail_compilation/fail15616b.d(17): Candidates are: `fail15616b.foo(int a)`
+fail_compilation/fail15616b.d(20): `fail15616b.foo(int a, int b)`
+fail_compilation/fail15616b.d(29): `fail15616b.foo(int a, int b, int c)`
+fail_compilation/fail15616b.d(32): `fail15616b.foo(string a)`
+fail_compilation/fail15616b.d(35): `fail15616b.foo(string a, string b)`
+fail_compilation/fail15616b.d(38): `fail15616b.foo(string a, string b, string c)`
+fail_compilation/fail15616b.d(23): `foo(T)(T a)`
+ with `T = double`
+ whose parameters have the following constraints:
+ `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
+` > is(T == float)
+` `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
+fail_compilation/fail15616b.d(26): `foo(T)(T a)`
+ with `T = double`
+ whose parameters have the following constraints:
+ `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
+` > is(T == char)
+` `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
+fail_compilation/fail15616b.d(44): All possible candidates are marked as `deprecated` or `@disable`
+ Tip: not satisfied constraints are marked with `>`
---
*/
+#line 17
void foo(int a)
{}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15626.d b/gcc/testsuite/gdc.test/fail_compilation/fail15626.d
index 3b70205..8ef14cd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail15626.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail15626.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail15626.d(12): Error: class fail15626.D C++ base class C needs at least one virtual function
+fail_compilation/fail15626.d(12): Error: class `fail15626.D` C++ base class `C` needs at least one virtual function
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15667.d b/gcc/testsuite/gdc.test/fail_compilation/fail15667.d
index f23963f..ce4940f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail15667.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail15667.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -o-
+// EXTRA_FILES: imports/a15667.d
/*
TEST_OUTPUT:
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15691.d b/gcc/testsuite/gdc.test/fail_compilation/fail15691.d
new file mode 100644
index 0000000..a20e1b5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail15691.d
@@ -0,0 +1,24 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail15691.d(15): Error: `c` is not a member of `Foo`
+fail_compilation/fail15691.d(20): Error: `bc` is not a member of `Foo`, did you mean variable `abc`?
+---
+*/
+
+struct Foo { int a; int abc; }
+
+void main()
+{
+ Foo z = { // line 13
+ a: 3,
+ c: 4, // line 15
+ };
+
+ Foo z2 = { // line 18
+ a: 3,
+ bc: 4, // line 20
+ };
+}
+
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15755.d b/gcc/testsuite/gdc.test/fail_compilation/fail15755.d
new file mode 100644
index 0000000..8fd2b51
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail15755.d
@@ -0,0 +1,29 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail15755.d(28): Error: `tuple(123)` has no effect
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=15755
+
+struct Foo
+{
+ @(123)
+ int a;
+}
+
+template Attributes(As...)
+{
+ alias Attributes = As;
+}
+
+template getattribute(alias member, alias attrs = Attributes!(__traits(getAttributes, member)))
+{
+ alias getattribute = attrs;
+}
+
+void main()
+{
+ getattribute!(__traits(getMember, Foo, "a"));
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail158.d b/gcc/testsuite/gdc.test/fail_compilation/fail158.d
index 353874f..6f09f65 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail158.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail158.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail158.d(17): Error: more initializers than fields (2) of S
+fail_compilation/fail158.d(17): Error: more initializers than fields (2) of `S`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail159.d b/gcc/testsuite/gdc.test/fail_compilation/fail159.d
index 13be8ee..a100606 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail159.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail159.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail159.d(24): Error: static assert `foo(S(1, 5), S(1, 4)) == 0` is false
+fail_compilation/fail159.d(24): Error: static assert: `foo(S(1, 5), S(1, 4)) == 0` is false
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail160.d b/gcc/testsuite/gdc.test/fail_compilation/fail160.d
index 1e2414c..c07c8d3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail160.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail160.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail160.d(22): Error: typeid(fail160.Foo).vtbl is not yet implemented at compile time
+fail_compilation/fail160.d(22): Error: `typeid(fail160.Foo).vtbl` is not yet implemented at compile time
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16001.d b/gcc/testsuite/gdc.test/fail_compilation/fail16001.d
new file mode 100644
index 0000000..ef5fc7b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail16001.d
@@ -0,0 +1,13 @@
+// REQUIRED_ARGS: -de
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail16001.d(10): Deprecation: Using `(args) => { ... }` to create a delegate that returns a delegate is error-prone.
+fail_compilation/fail16001.d(10): Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate.
+---
+*/
+void main() {
+ auto fail = () => {};
+ auto ok = () => () {};
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail161.d b/gcc/testsuite/gdc.test/fail_compilation/fail161.d
index d0aa940..ecbf691 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail161.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail161.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail161.d(15): Error: template instance MetaString!"2 == 1" does not match template declaration MetaString(String)
+fail_compilation/fail161.d(15): Error: template instance `MetaString!"2 == 1"` does not match template declaration `MetaString(String)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail162.d b/gcc/testsuite/gdc.test/fail_compilation/fail162.d
index f49fbac..663e0e1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail162.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail162.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail162.d(25): Error: template fail162.testHelper cannot deduce function from argument types !()(string, string), candidates are:
-fail_compilation/fail162.d(10): fail162.testHelper(A...)()
-fail_compilation/fail162.d(30): Error: template instance fail162.test!("hello", "world") error instantiating
+fail_compilation/fail162.d(25): Error: template `fail162.testHelper` cannot deduce function from argument types `!()(string, string)`
+fail_compilation/fail162.d(10): Candidate is: `testHelper(A...)()`
+fail_compilation/fail162.d(30): Error: template instance `fail162.test!("hello", "world")` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16206a.d b/gcc/testsuite/gdc.test/fail_compilation/fail16206a.d
index 3c1cc56..d28a8c3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail16206a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail16206a.d
@@ -1,12 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail16206a.d(12): Error: `bool` expected as third argument of `__traits(getOverloads)`, not `"Not a bool"` of type `string`
+fail_compilation/fail16206a.d(14): Error: `bool` expected as third argument of `__traits(getOverloads)`, not `"Not a bool"` of type `string`
---
*/
-struct S {
+struct S
+{
static int foo()() { return 0; }
}
+
alias AliasSeq(T...) = T;
-alias allFoos = AliasSeq!(__traits(getOverloads, S, "foo", "Not a bool")); \ No newline at end of file
+alias allFoos = AliasSeq!(__traits(getOverloads, S, "foo", "Not a bool"));
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16206b.d b/gcc/testsuite/gdc.test/fail_compilation/fail16206b.d
index 9b3a69c..0f20ad5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail16206b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail16206b.d
@@ -1,12 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail16206b.d(12): Error: expected 2 arguments for `hasMember` but had 3
+fail_compilation/fail16206b.d(14): Error: expected 2 arguments for `hasMember` but had 3
---
*/
-struct S {
+struct S
+{
static int foo()() { return 0; }
}
+
alias AliasSeq(T...) = T;
-alias allFoos = AliasSeq!(__traits(hasMember, S, "foo", true)); \ No newline at end of file
+alias allFoos = AliasSeq!(__traits(hasMember, S, "foo", true));
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail163.d b/gcc/testsuite/gdc.test/fail_compilation/fail163.d
index c2eb1fd..7f8f028 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail163.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail163.d
@@ -27,7 +27,7 @@ void test2()
/*
TEST_OUTPUT:
---
-fail_compilation/fail163.d(37): Error: cannot modify const expression p
+fail_compilation/fail163.d(37): Error: cannot modify `const` expression `p`
---
*/
void test3()
@@ -53,7 +53,7 @@ void test4()
/*
TEST_OUTPUT:
---
-fail_compilation/fail163.d(63): Error: cannot modify const expression *p
+fail_compilation/fail163.d(63): Error: cannot modify `const` expression `*p`
---
*/
void test5()
@@ -67,7 +67,7 @@ void test5()
TEST_OUTPUT:
---
fail_compilation/fail163.d(76): Error: cannot implicitly convert expression `& x` of type `int*` to `immutable(int)*`
-fail_compilation/fail163.d(77): Error: cannot modify immutable expression *p
+fail_compilation/fail163.d(77): Error: cannot modify `immutable` expression `*p`
---
*/
void test6()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16600.d b/gcc/testsuite/gdc.test/fail_compilation/fail16600.d
index a7f30d9..a4bc739 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail16600.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail16600.d
@@ -1,9 +1,9 @@
/* TEST_OUTPUT:
---
-fail_compilation/fail16600.d(22): Error: fail16600.S.__ctor called with argument types (string) const matches both:
-fail_compilation/fail16600.d(16): fail16600.S.this(string _param_0)
+fail_compilation/fail16600.d(22): Error: `fail16600.S.__ctor` called with argument types `(string) const` matches both:
+fail_compilation/fail16600.d(16): `fail16600.S.this(string _param_0)`
and:
-fail_compilation/fail16600.d(17): fail16600.S.this(string _param_0) immutable
+fail_compilation/fail16600.d(17): `fail16600.S.this(string _param_0) immutable`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16689.d b/gcc/testsuite/gdc.test/fail_compilation/fail16689.d
new file mode 100644
index 0000000..f8e0bae
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail16689.d
@@ -0,0 +1,14 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail16689.d(3): Error: static assert: "false"
+fail_compilation/fail16689.d(6): instantiated from here: `Issue16689!()`
+---
+*/
+#line 1
+mixin template Issue16689()
+{
+ static assert(false, "false");
+}
+
+mixin Issue16689!();
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail169.d b/gcc/testsuite/gdc.test/fail_compilation/fail169.d
index bd1da0b..a8ad102 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail169.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail169.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail169.d(8): Error: cannot have const out parameter of type const(int)
+fail_compilation/fail169.d(8): Error: cannot have `const out` parameter of type `const(int)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16997.d b/gcc/testsuite/gdc.test/fail_compilation/fail16997.d
new file mode 100644
index 0000000..a8f3ae4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail16997.d
@@ -0,0 +1,59 @@
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/fail16997.d(31): Deprecation: integral promotion not done for `~c`, use '-preview=intpromote' switch or `~cast(int)(c)`
+fail_compilation/fail16997.d(32): Deprecation: integral promotion not done for `-c`, use '-preview=intpromote' switch or `-cast(int)(c)`
+fail_compilation/fail16997.d(33): Deprecation: integral promotion not done for `+c`, use '-preview=intpromote' switch or `+cast(int)(c)`
+fail_compilation/fail16997.d(36): Deprecation: integral promotion not done for `~w`, use '-preview=intpromote' switch or `~cast(int)(w)`
+fail_compilation/fail16997.d(37): Deprecation: integral promotion not done for `-w`, use '-preview=intpromote' switch or `-cast(int)(w)`
+fail_compilation/fail16997.d(38): Deprecation: integral promotion not done for `+w`, use '-preview=intpromote' switch or `+cast(int)(w)`
+fail_compilation/fail16997.d(41): Deprecation: integral promotion not done for `~sb`, use '-preview=intpromote' switch or `~cast(int)(sb)`
+fail_compilation/fail16997.d(42): Deprecation: integral promotion not done for `-sb`, use '-preview=intpromote' switch or `-cast(int)(sb)`
+fail_compilation/fail16997.d(43): Deprecation: integral promotion not done for `+sb`, use '-preview=intpromote' switch or `+cast(int)(sb)`
+fail_compilation/fail16997.d(46): Deprecation: integral promotion not done for `~ub`, use '-preview=intpromote' switch or `~cast(int)(ub)`
+fail_compilation/fail16997.d(47): Deprecation: integral promotion not done for `-ub`, use '-preview=intpromote' switch or `-cast(int)(ub)`
+fail_compilation/fail16997.d(48): Deprecation: integral promotion not done for `+ub`, use '-preview=intpromote' switch or `+cast(int)(ub)`
+fail_compilation/fail16997.d(51): Deprecation: integral promotion not done for `~s`, use '-preview=intpromote' switch or `~cast(int)(s)`
+fail_compilation/fail16997.d(52): Deprecation: integral promotion not done for `-s`, use '-preview=intpromote' switch or `-cast(int)(s)`
+fail_compilation/fail16997.d(53): Deprecation: integral promotion not done for `+s`, use '-preview=intpromote' switch or `+cast(int)(s)`
+fail_compilation/fail16997.d(56): Deprecation: integral promotion not done for `~us`, use '-preview=intpromote' switch or `~cast(int)(us)`
+fail_compilation/fail16997.d(57): Deprecation: integral promotion not done for `-us`, use '-preview=intpromote' switch or `-cast(int)(us)`
+fail_compilation/fail16997.d(58): Deprecation: integral promotion not done for `+us`, use '-preview=intpromote' switch or `+cast(int)(us)`
+---
+*/
+
+void test()
+{
+ int x;
+
+ char c;
+ x = ~c;
+ x = -c;
+ x = +c;
+
+ wchar w;
+ x = ~w;
+ x = -w;
+ x = +w;
+
+ byte sb;
+ x = ~sb;
+ x = -sb;
+ x = +sb;
+
+ ubyte ub;
+ x = ~ub;
+ x = -ub;
+ x = +ub;
+
+ short s;
+ x = ~s;
+ x = -s;
+ x = +s;
+
+ ushort us;
+ x = ~us;
+ x = -us;
+ x = +us;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail170.d b/gcc/testsuite/gdc.test/fail_compilation/fail170.d
index a78fc03..61c7ae6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail170.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail170.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail170.d(8): Error: variable fail170.foo.x cannot be final, perhaps you meant const?
+fail_compilation/fail170.d(8): Error: variable `fail170.foo.x` cannot be `final`, perhaps you meant `const`?
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail172.d b/gcc/testsuite/gdc.test/fail_compilation/fail172.d
index c7ccdc1..9862fe8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail172.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail172.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail172.d(25): Error: cannot modify const expression c1.x
-fail_compilation/fail172.d(26): Error: cannot modify const expression c2.x
-fail_compilation/fail172.d(30): Error: cannot modify const expression s1.x
-fail_compilation/fail172.d(31): Error: cannot modify const expression s2.x
+fail_compilation/fail172.d(25): Error: cannot modify `const` expression `c1.x`
+fail_compilation/fail172.d(26): Error: cannot modify `const` expression `c2.x`
+fail_compilation/fail172.d(30): Error: cannot modify `const` expression `s1.x`
+fail_compilation/fail172.d(31): Error: cannot modify `const` expression `s2.x`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17275.d b/gcc/testsuite/gdc.test/fail_compilation/fail17275.d
index fcccdf2..fd7623f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17275.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17275.d
@@ -1,7 +1,7 @@
/* TEST_OUTPUT:
---
fail_compilation/fail17275.d(12): Error: undefined identifier `ModuleGroup`, did you mean function `moduleGroup`?
-fail_compilation/fail17275.d(12): Error: inout on return means inout must be on a parameter as well for inout(ModuleGroup)()
+fail_compilation/fail17275.d(12): Error: `inout` on `return` means `inout` must be on a parameter as well for `inout(ModuleGroup)()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17354.d b/gcc/testsuite/gdc.test/fail_compilation/fail17354.d
index e09f1e5..fd44e65 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17354.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17354.d
@@ -1,8 +1,7 @@
-/* REQUIRED_ARGS: -de
- * TEST_OUTPUT:
+/* TEST_OUTPUT:
---
-fail_compilation/fail17354.d(13): Deprecation: cannot implicitly override base class method `object.Object.opEquals` with `fail17354.Foo.opEquals`; add `override` attribute
-fail_compilation/fail17354.d(18): Deprecation: cannot implicitly override base class method `object.Object.opEquals` with `fail17354.Bar.opEquals`; add `override` attribute
+fail_compilation/fail17354.d(12): Error: cannot implicitly override base class method `object.Object.opEquals` with `fail17354.Foo.opEquals`; add `override` attribute
+fail_compilation/fail17354.d(17): Error: cannot implicitly override base class method `object.Object.opEquals` with `fail17354.Bar.opEquals`; add `override` attribute
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17491.d b/gcc/testsuite/gdc.test/fail_compilation/fail17491.d
index 4902392..0fb9708 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17491.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17491.d
@@ -1,18 +1,16 @@
/* TEST_OUTPUT:
---
-fail_compilation/fail17491.d(24): Error: (S17491).init is not an lvalue
-fail_compilation/fail17491.d(25): Error: S17491(0) is not an lvalue
-fail_compilation/fail17491.d(27): Error: constant S17491(0).field is not an lvalue
-fail_compilation/fail17491.d(28): Error: constant *&S17491(0).field is not an lvalue
-fail_compilation/fail17491.d(33): Error: S17491(0) is not an lvalue
-fail_compilation/fail17491.d(34): Error: S17491(0) is not an lvalue
-fail_compilation/fail17491.d(36): Error: constant S17491(0).field is not an lvalue
-fail_compilation/fail17491.d(37): Error: constant *&S17491(0).field is not an lvalue
+fail_compilation/fail17491.d(22): Error: `(S17491).init` is not an lvalue and cannot be modified
+fail_compilation/fail17491.d(23): Error: `S17491(0)` is not an lvalue and cannot be modified
+fail_compilation/fail17491.d(25): Error: `S17491(0).field` is not an lvalue and cannot be modified
+fail_compilation/fail17491.d(26): Error: `S17491(0).field` is not an lvalue and cannot be modified
+fail_compilation/fail17491.d(31): Error: `S17491(0)` is not an lvalue and cannot be modified
+fail_compilation/fail17491.d(32): Error: `S17491(0)` is not an lvalue and cannot be modified
+fail_compilation/fail17491.d(34): Error: `S17491(0).field` is not an lvalue and cannot be modified
+fail_compilation/fail17491.d(35): Error: `S17491(0).field` is not an lvalue and cannot be modified
---
*/
-
// https://issues.dlang.org/show_bug.cgi?id=17491
-
struct S17491
{
int field;
@@ -25,7 +23,7 @@ void test17491()
*&S17491.init = S17491(42); // NG
S17491.init.field = 42; // NG
- *&S17491.init.field = 42; // Should be NG
+ *&S17491.init.field = 42; // NG
S17491.init.var = 42; // OK
*&S17491.init.var = 42; // OK
@@ -34,7 +32,7 @@ void test17491()
*&S17491(0) = S17491(42); // NG
S17491(0).field = 42; // NG
- *&S17491(0).field = 42; // Should be NG
+ *&S17491(0).field = 42; // NG
S17491(0).var = 42; // OK
*&S17491(0).var = 42; // OK
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17492.d b/gcc/testsuite/gdc.test/fail_compilation/fail17492.d
index 80e9e2a..7236c22 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17492.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17492.d
@@ -1,7 +1,9 @@
-/* TEST_OUTPUT:
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
---
-fail_compilation/fail17492.d(20): Error: class `fail17492.C.testE.I` already exists at fail17492.d(13). Perhaps in another function with the same name?
-fail_compilation/fail17492.d(37): Error: struct `fail17492.S.testE.I` already exists at fail17492.d(30). Perhaps in another function with the same name?
+fail_compilation/fail17492.d(20): Error: function `fail17492.C.testE()` conflicts with previous declaration at fail_compilation/fail17492.d(13)
+fail_compilation/fail17492.d(37): Error: function `fail17492.S.testE()` conflicts with previous declaration at fail_compilation/fail17492.d(30)
---
https://issues.dlang.org/show_bug.cgi?id=17492
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17502.d b/gcc/testsuite/gdc.test/fail_compilation/fail17502.d
index b1366d1..49db4fc 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17502.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17502.d
@@ -11,9 +11,9 @@ class Foo
{
void foo()
out (res) { assert(res > 5); }
- body {}
+ do {}
auto bar()
out (res) { assert (res > 5); }
- body { return; }
+ do { return; }
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17518.d b/gcc/testsuite/gdc.test/fail_compilation/fail17518.d
new file mode 100644
index 0000000..385483c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17518.d
@@ -0,0 +1,22 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail17518.d(21): Error: constructor `fail17518.S.this(inout(Correct) _param_0) inout` is not callable using argument types `(Wrong)`
+fail_compilation/fail17518.d(21): cannot pass argument `Wrong()` of type `Wrong` to parameter `inout(Correct) _param_0`
+---
+*/
+
+struct S
+{
+ this(inout Correct) inout
+ {
+ }
+}
+
+struct Correct {}
+struct Wrong {}
+
+S bug()
+{
+ return S(Wrong());
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17570.d b/gcc/testsuite/gdc.test/fail_compilation/fail17570.d
new file mode 100644
index 0000000..bee61cf
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17570.d
@@ -0,0 +1,13 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail17570.d(11): Error: cannot use function constraints for non-template functions. Use `static if` instead
+fail_compilation/fail17570.d(11): Error: declaration expected, not `if`
+fail_compilation/fail17570.d(14): Error: `}` expected following members in `struct` declaration at fail_compilation/fail17570.d(10)
+---
+*/
+
+struct S(T) {
+ void func() if(isIntegral!T)
+ {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail176.d b/gcc/testsuite/gdc.test/fail_compilation/fail176.d
index 908d08c..797407e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail176.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail176.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail176.d(13): Error: cannot modify immutable expression a[1]
-fail_compilation/fail176.d(16): Error: cannot modify immutable expression b[1]
-fail_compilation/fail176.d(19): Error: cannot modify const expression c[1]
+fail_compilation/fail176.d(13): Error: cannot modify `immutable` expression `a[1]`
+fail_compilation/fail176.d(16): Error: cannot modify `immutable` expression `b[1]`
+fail_compilation/fail176.d(19): Error: cannot modify `const` expression `c[1]`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17602.d b/gcc/testsuite/gdc.test/fail_compilation/fail17602.d
new file mode 100644
index 0000000..6423d1b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17602.d
@@ -0,0 +1,18 @@
+/*
+EXTRA_FILES: imports/imp17602.d
+TEST_OUTPUT:
+---
+fail_compilation/fail17602.d(17): Error: cannot implicitly convert expression `Status.on` of type `imports.imp17602.Status` to `fail17602.Status`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=17602
+
+import imports.imp17602;
+
+enum Status { off }
+
+void main()
+{
+ Status status = imports.imp17602.Status.on;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17612.d b/gcc/testsuite/gdc.test/fail_compilation/fail17612.d
index 4ae1e0a..d39dd51 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17612.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17612.d
@@ -1,7 +1,7 @@
/* TEST_OUTPUT:
---
fail_compilation/fail17612.d(14): Error: undefined identifier `string`
-fail_compilation/fail17612.d(17): Error: class object.TypeInfo missing or corrupt object.d
+fail_compilation/fail17612.d(17): Error: class `object.TypeInfo` missing or corrupt object.d
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17625.d b/gcc/testsuite/gdc.test/fail_compilation/fail17625.d
new file mode 100644
index 0000000..bb69462
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17625.d
@@ -0,0 +1,17 @@
+/*
+EXTRA_FILES: imports/a17625.d imports/b17625.d
+TEST_OUTPUT:
+---
+fail_compilation/fail17625.d(16): Error: undefined identifier `boo`
+---
+*/
+
+module fail17625;
+
+import imports.a17625;
+import imports.b17625;
+
+void main()
+{
+ boo();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17646.d b/gcc/testsuite/gdc.test/fail_compilation/fail17646.d
index 416b0d4..3571e38 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17646.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17646.d
@@ -1,12 +1,12 @@
/*
REQUIRED_ARGS: -o-
-PERMUTE_ARGS:
+EXTRA_FILES: imports/fail17646.d
TEST_OUTPUT:
---
fail_compilation/imports/fail17646.d(10): Error: found `}` instead of statement
-fail_compilation/imports/fail17646.d(7): Error: function imports.fail17646.allTestData!"".allTestData has no return statement, but is expected to return a value of type const(TestData)[]
-fail_compilation/fail17646.d(16): Error: template instance imports.fail17646.allTestData!"" error instantiating
-fail_compilation/fail17646.d(19): instantiated from here: runTests!""
+fail_compilation/imports/fail17646.d(7): Error: function `imports.fail17646.allTestData!"".allTestData` has no `return` statement, but is expected to return a value of type `const(TestData)[]`
+fail_compilation/fail17646.d(16): Error: template instance `imports.fail17646.allTestData!""` error instantiating
+fail_compilation/fail17646.d(19): instantiated from here: `runTests!""`
---
*/
int runTests(Modules...)()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail177.d b/gcc/testsuite/gdc.test/fail_compilation/fail177.d
index 1e12077..49edf4d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail177.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail177.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail177.d(22): Error: cannot modify immutable expression j
-fail_compilation/fail177.d(24): Error: cannot modify const expression i
-fail_compilation/fail177.d(26): Error: cannot modify const expression s1.x
-fail_compilation/fail177.d(27): Error: cannot modify const expression *s1.p
-fail_compilation/fail177.d(29): Error: cannot modify const expression s2.x
-fail_compilation/fail177.d(30): Error: cannot modify const expression *s2.p
+fail_compilation/fail177.d(22): Error: cannot modify `immutable` expression `j`
+fail_compilation/fail177.d(24): Error: cannot modify `const` expression `i`
+fail_compilation/fail177.d(26): Error: cannot modify `const` expression `s1.x`
+fail_compilation/fail177.d(27): Error: cannot modify `const` expression `*s1.p`
+fail_compilation/fail177.d(29): Error: cannot modify `const` expression `s2.x`
+fail_compilation/fail177.d(30): Error: cannot modify `const` expression `*s2.p`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17722a.d b/gcc/testsuite/gdc.test/fail_compilation/fail17722a.d
index b6ede29..7e0b911 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17722a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17722a.d
@@ -1,6 +1,6 @@
/* TEST_OUTPUT:
---
-fail_compilation/fail17722a.d(12): Error: static assert `__traits(compiles, a1 && a2)` is false
+fail_compilation/fail17722a.d(12): Error: static assert: `__traits(compiles, a1 && a2)` is false
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17722b.d b/gcc/testsuite/gdc.test/fail_compilation/fail17722b.d
index 848db15..171c49f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17722b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17722b.d
@@ -1,6 +1,6 @@
/* TEST_OUTPUT:
---
-fail_compilation/fail17722b.d(12): Error: static assert `__traits(compiles, a1 || a2)` is false
+fail_compilation/fail17722b.d(12): Error: static assert: `__traits(compiles, a1 || a2)` is false
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17842.d b/gcc/testsuite/gdc.test/fail_compilation/fail17842.d
new file mode 100644
index 0000000..ef66858
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17842.d
@@ -0,0 +1,29 @@
+/* REQUIRED_ARGS: -preview=dip1000
+ * TEST_OUTPUT:
+---
+fail_compilation/fail17842.d(14): Error: scope variable `p` assigned to non-scope `*q`
+fail_compilation/fail17842.d(23): Error: scope variable `obj` may not be copied into allocated memory
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=17842
+
+void* testp(scope void* p) @safe
+{
+ scope void** q;
+ *q = p; // error
+ void** t;
+ *t = *q;
+ return *t;
+}
+
+Object testobj(scope Object obj) @safe
+{
+ scope Object[] arr;
+ arr ~= obj; // error
+ Object[] array;
+ array ~= arr;
+ return array[0];
+}
+
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail179.d b/gcc/testsuite/gdc.test/fail_compilation/fail179.d
index bd0e155..0c9c248 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail179.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail179.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail179.d(11): Error: variable fail179.main.px cannot be final, perhaps you meant const?
+fail_compilation/fail179.d(11): Error: variable `fail179.main.px` cannot be `final`, perhaps you meant `const`?
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17927.d b/gcc/testsuite/gdc.test/fail_compilation/fail17927.d
new file mode 100644
index 0000000..348d473
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17927.d
@@ -0,0 +1,24 @@
+/* REQUIRED_ARGS: -preview=dip1000
+ * TEST_OUTPUT:
+---
+fail_compilation/fail17927.d(13): Error: scope variable `this` may not be returned
+fail_compilation/fail17927.d(21): Error: scope variable `ptr` may not be returned
+fail_compilation/fail17927.d(23): Error: scope variable `ptr` may not be returned
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=17927
+
+struct String {
+ const(char)* mem1() const scope @safe { return ptr; }
+
+ inout(char)* mem2() inout scope @safe { return ptr; } // no error because `ref inout` implies `return`
+
+ char* ptr;
+}
+
+
+const(char)* foo1(scope const(char)* ptr) @safe { return ptr; }
+
+inout(char)* foo2(scope inout(char)* ptr) @safe { return ptr; }
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17955.d b/gcc/testsuite/gdc.test/fail_compilation/fail17955.d
new file mode 100644
index 0000000..f33149e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17955.d
@@ -0,0 +1,102 @@
+// https://issues.dlang.org/show_bug.cgi?id=17955
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail17955.d(81): Error: cannot create instance of abstract class `SimpleTimeZone`
+fail_compilation/fail17955.d(81): function `bool hasDST()` is not implemented
+fail_compilation/fail17955.d(93): Error: template instance `fail17955.SimpleTimeZone.fromISOExtString!dstring` error instantiating
+fail_compilation/fail17955.d(25): instantiated from here: `fromISOExtString!string`
+fail_compilation/fail17955.d(56): instantiated from here: `isISOExtStringSerializable!(SysTime)`
+fail_compilation/fail17955.d(49): instantiated from here: `toRedis!(SysTime)`
+fail_compilation/fail17955.d(40): ... (2 instantiations, -v to show) ...
+fail_compilation/fail17955.d(32): instantiated from here: `indicesOf!(isRedisType, resetCodeExpireTime)`
+fail_compilation/fail17955.d(67): instantiated from here: `RedisStripped!(User, true)`
+fail_compilation/fail17955.d(93): Error: need `this` for `fromISOExtString` of type `pure nothrow @nogc @safe immutable(SimpleTimeZone)(dstring _param_0)`
+fail_compilation/fail17955.d(95): Error: undefined identifier `DateTimeException`
+fail_compilation/fail17955.d(25): Error: variable `fail17955.isISOExtStringSerializable!(SysTime).isISOExtStringSerializable` type `void` is inferred from initializer `fromISOExtString("")`, and variables cannot be of type `void`
+fail_compilation/fail17955.d(54): Error: function `fail17955.toRedis!(SysTime).toRedis` has no `return` statement, but is expected to return a value of type `string`
+---
+*/
+
+alias Alias(alias a) = a;
+
+template isISOExtStringSerializable(T)
+{
+ enum isISOExtStringSerializable = T.fromISOExtString("");
+}
+
+template RedisObjectCollection(){}
+
+struct RedisStripped(T, bool strip_id = true)
+{
+ alias unstrippedMemberIndices = indicesOf!(Select!(strip_id,
+ isRedisTypeAndNotID, isRedisType), T.tupleof);
+}
+
+template indicesOf(alias PRED, T...)
+{
+ template impl(size_t i)
+ {
+ static if (PRED!T)
+ impl TypeTuple;
+ }
+
+ alias indicesOf = impl!0;
+}
+
+template isRedisType(alias F)
+{
+ enum isRedisType = toRedis!(typeof(F));
+}
+
+template isRedisTypeAndNotID(){}
+
+string toRedis(T)()
+{
+ static if (isISOExtStringSerializable!T)
+ return;
+}
+
+struct User
+{
+ SysTime resetCodeExpireTime;
+}
+
+class RedisUserManController
+{
+ RedisObjectCollection!(RedisStripped!User) m_users;
+}
+
+class TimeZone
+{
+ abstract bool hasDST();
+}
+
+class SimpleTimeZone : TimeZone
+{
+ unittest {}
+
+ immutable(SimpleTimeZone) fromISOExtString(S)(S)
+ {
+ new SimpleTimeZone;
+ }
+}
+
+struct SysTime
+{
+
+ static fromISOExtString(S)(S)
+ {
+ dstring zoneStr;
+
+ try
+ SimpleTimeZone.fromISOExtString(zoneStr);
+
+ catch (DateTimeException e) {}
+ }
+}
+
+template Select(bool condition, T...)
+{
+ alias Select = Alias!(T[condition]);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17969.d b/gcc/testsuite/gdc.test/fail_compilation/fail17969.d
new file mode 100644
index 0000000..57fabbb
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17969.d
@@ -0,0 +1,18 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/fail17969.d(9): Error: no property `sum` for type `fail17969.__lambda6!(int[]).__lambda6.MapResult2!((b) => b)`
+---
+ * https://issues.dlang.org/show_bug.cgi?id=17969
+ */
+
+
+alias fun = a => MapResult2!(b => b).sum;
+
+int[] e;
+static assert(!is(typeof(fun(e)) == void));
+void foo() { fun(e); }
+
+struct MapResult2(alias fun)
+{
+ int[] _input;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17976.d b/gcc/testsuite/gdc.test/fail_compilation/fail17976.d
new file mode 100644
index 0000000..4ecc092
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17976.d
@@ -0,0 +1,18 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail17976.d(11): Error: constructor `fail17976.S.this` parameter `this.a` is already defined
+fail_compilation/fail17976.d(11): Error: constructor `fail17976.S.this` parameter `this.a` is already defined
+---
+*/
+
+struct S
+{
+ this(string a, string a, string a)
+ {
+ }
+}
+
+void main()
+{
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail180.d b/gcc/testsuite/gdc.test/fail_compilation/fail180.d
index 64ba3ef..ef4ffaa 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail180.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail180.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail180.d(23): Error: cannot modify this.x in const function
-fail_compilation/fail180.d(24): Error: cannot modify this.x in const function
-fail_compilation/fail180.d(38): Error: cannot modify this.x in const function
-fail_compilation/fail180.d(39): Error: cannot modify this.x in const function
-fail_compilation/fail180.d(50): Error: variable fail180.main.t cannot be final, perhaps you meant const?
-fail_compilation/fail180.d(62): Error: variable fail180.test.d cannot be final, perhaps you meant const?
+fail_compilation/fail180.d(23): Error: cannot modify `this.x` in `const` function
+fail_compilation/fail180.d(24): Error: cannot modify `this.x` in `const` function
+fail_compilation/fail180.d(38): Error: cannot modify `this.x` in `const` function
+fail_compilation/fail180.d(39): Error: cannot modify `this.x` in `const` function
+fail_compilation/fail180.d(50): Error: variable `fail180.main.t` cannot be `final`, perhaps you meant `const`?
+fail_compilation/fail180.d(62): Error: variable `fail180.test.d` cannot be `final`, perhaps you meant `const`?
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18057.d b/gcc/testsuite/gdc.test/fail_compilation/fail18057.d
index 5e2bab7..19e8eb4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail18057.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18057.d
@@ -1,8 +1,8 @@
/**
TEST_OUTPUT:
---
-fail_compilation/fail18057.d(16): Error: template instance RBNode!int `RBNode` is not a template declaration, it is a struct
-fail_compilation/fail18057.d(13): Error: variable fail18057.RBNode.copy recursive initialization of field
+fail_compilation/fail18057.d(16): Error: template instance `RBNode!int` `RBNode` is not a template declaration, it is a struct
+fail_compilation/fail18057.d(13): Error: variable `fail18057.RBNode.copy` recursive initialization of field
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18093.d b/gcc/testsuite/gdc.test/fail_compilation/fail18093.d
new file mode 100644
index 0000000..4eb3663
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18093.d
@@ -0,0 +1,27 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/fail18093.d(19): Error: function `void fail18093.GenericTransitiveVisitor!(ASTCodegen).GenericTransitiveVisitor.ParseVisitMethods!(ASTCodegen).visit()` does not override any function, did you mean to override `extern (C++) void fail18093.ParseTimeVisitor!(ASTCodegen).ParseTimeVisitor.visit()`?
+fail_compilation/fail18093.d(24): Error: mixin `fail18093.GenericTransitiveVisitor!(ASTCodegen).GenericTransitiveVisitor.ParseVisitMethods!(ASTCodegen)` error instantiating
+fail_compilation/fail18093.d(27): Error: template instance `fail18093.GenericTransitiveVisitor!(ASTCodegen)` error instantiating
+---
+ * https://issues.dlang.org/show_bug.cgi?id=18093
+ */
+
+
+struct ASTCodegen {}
+
+extern (C++) class ParseTimeVisitor(AST)
+{
+ void visit() {}
+}
+template ParseVisitMethods(AST)
+{
+ override void visit() {}
+}
+
+class GenericTransitiveVisitor(AST) : ParseTimeVisitor!AST
+{
+ mixin ParseVisitMethods!AST;
+}
+
+alias SemanticTimeTransitiveVisitor = GenericTransitiveVisitor!ASTCodegen;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18228.d b/gcc/testsuite/gdc.test/fail_compilation/fail18228.d
new file mode 100644
index 0000000..983719a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18228.d
@@ -0,0 +1,15 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail18228.d(12): Error: Using `this` as a type is obsolete. Use `typeof(this)` instead
+fail_compilation/fail18228.d(13): Error: Using `this` as a type is obsolete. Use `typeof(this)` instead
+fail_compilation/fail18228.d(14): Error: Using `super` as a type is obsolete. Use `typeof(super)` instead
+---
+*/
+
+class C
+{
+ this(this a) {}
+ this(int a, this b) {}
+ this(super a) {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18236.d b/gcc/testsuite/gdc.test/fail_compilation/fail18236.d
new file mode 100644
index 0000000..5a696f3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18236.d
@@ -0,0 +1,21 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail18236.d(20): Error: cannot cast expression `V(12)` of type `V` to `int`
+---
+*/
+
+struct V
+{
+ int a;
+}
+
+struct S
+{
+ enum A = V(12);
+}
+
+void main()
+{
+ int b = cast(int)S.A;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18243.d b/gcc/testsuite/gdc.test/fail_compilation/fail18243.d
new file mode 100644
index 0000000..f31319b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18243.d
@@ -0,0 +1,16 @@
+/*
+EXTRA_FILES: imports/a18243.d
+TEST_OUTPUT:
+---
+fail_compilation/fail18243.d(15): Error: none of the overloads of `isNaN` are callable using argument types `!()(float)`
+---
+*/
+
+module fail18243;
+
+import imports.a18243;
+
+void main()
+{
+ bool b = isNaN(float.nan);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail183.d b/gcc/testsuite/gdc.test/fail_compilation/fail183.d
index c43d377..362213c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail183.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail183.d
@@ -1,11 +1,25 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail183.d(10): Error: redundant attribute `const`
-fail_compilation/fail183.d(10): Error: redundant attribute `scope`
-fail_compilation/fail183.d(11): Error: redundant attribute `in`
+fail_compilation/fail183.d(17): Error: attribute `const` is redundant with previously-applied `in`
+fail_compilation/fail183.d(18): Error: attribute `scope` cannot be applied with `in`, use `-preview=in` instead
+fail_compilation/fail183.d(19): Error: attribute `const` is redundant with previously-applied `in`
+fail_compilation/fail183.d(19): Error: attribute `scope` cannot be applied with `in`, use `-preview=in` instead
+fail_compilation/fail183.d(20): Error: attribute `scope` cannot be applied with `in`, use `-preview=in` instead
+fail_compilation/fail183.d(20): Error: attribute `const` is redundant with previously-applied `in`
+fail_compilation/fail183.d(22): Error: attribute `in` cannot be added after `const`: remove `const`
+fail_compilation/fail183.d(23): Error: attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`
+fail_compilation/fail183.d(24): Error: attribute `in` cannot be added after `const`: remove `const`
+fail_compilation/fail183.d(25): Error: attribute `in` cannot be added after `const`: remove `const`
---
*/
-void f(in final const scope int x) {}
-void g(final const scope in int x) {}
+void f1(in const int x) {}
+void f2(in scope int x) {}
+void f3(in const scope int x) {}
+void f4(in scope const int x) {}
+
+void f5(const in int x) {}
+void f6(scope in int x) {}
+void f7(const scope in int x) {}
+void f8(scope const in int x) {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18417.d b/gcc/testsuite/gdc.test/fail_compilation/fail18417.d
new file mode 100644
index 0000000..b32a99b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18417.d
@@ -0,0 +1,13 @@
+// REQUIRED_ARGS : -de
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail18417.d(11): Deprecation: `const` postblit is deprecated. Please use an unqualified postblit.
+fail_compilation/fail18417.d(12): Deprecation: `immutable` postblit is deprecated. Please use an unqualified postblit.
+fail_compilation/fail18417.d(13): Deprecation: `shared` postblit is deprecated. Please use an unqualified postblit.
+---
+*/
+
+struct A { this(this) const {} }
+struct B { this(this) immutable {} }
+struct C { this(this) shared {} }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail185.d b/gcc/testsuite/gdc.test/fail_compilation/fail185.d
index 7197531..8d3ffc9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail185.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail185.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail185.d(10): Error: static assert "An error message
+fail_compilation/fail185.d(10): Error: static assert: "An error message
that spans multiple lines, and also contains such characters as a tab,
\ and "."
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18620.d b/gcc/testsuite/gdc.test/fail_compilation/fail18620.d
new file mode 100644
index 0000000..ce202b8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18620.d
@@ -0,0 +1,21 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail18620.d(14): Error: `strlen` cannot be interpreted at compile time, because it has no available source code
+fail_compilation/fail18620.d(19): compile time context created here
+fail_compilation/fail18620.d(14): Error: `strlen` cannot be interpreted at compile time, because it has no available source code
+fail_compilation/fail18620.d(20): compile time context created here
+---
+*/
+class A{
+ this(const(char)* s)
+ {
+ import core.stdc.string;
+ auto a=strlen(s);
+ }
+}
+
+void main(){
+ static a = new A("a");
+ __gshared b = new A("b");
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail187.d b/gcc/testsuite/gdc.test/fail_compilation/fail187.d
index b985493..b23a95d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail187.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail187.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail187.d(16): Error: catch at fail_compilation/fail187.d(20) hides catch at fail_compilation/fail187.d(24)
+fail_compilation/fail187.d(16): Error: `catch` at fail_compilation/fail187.d(20) hides `catch` at fail_compilation/fail187.d(24)
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18719.d b/gcc/testsuite/gdc.test/fail_compilation/fail18719.d
index 7d993d1..7ed513a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail18719.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18719.d
@@ -1,10 +1,9 @@
// https://issues.dlang.org/show_bug.cgi?id=18719
-// REQUIRED_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/fail18719.d(30): Error: immutable field `x` initialized multiple times
+fail_compilation/fail18719.d(29): Error: immutable field `x` initialized multiple times
Previous initialization is here.
---
*/
@@ -15,8 +14,8 @@ struct S
this(int y) immutable
{
x = y;
- import std.stdio;
- writeln("Ctor called with ", y);
+ import core.stdc.stdio;
+ printf("Ctor called with %d\n", y);
}
void opAssign(int) immutable;
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail188.d b/gcc/testsuite/gdc.test/fail_compilation/fail188.d
index cd201d02..6809e10 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail188.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail188.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail188.d(15): Error: function fail188.Derived.foo cannot override final function fail188.Base.foo
+fail_compilation/fail188.d(15): Error: function `fail188.Derived.foo` cannot override `final` function `fail188.Base.foo`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18892.d b/gcc/testsuite/gdc.test/fail_compilation/fail18892.d
new file mode 100644
index 0000000..531d1ed
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18892.d
@@ -0,0 +1,22 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail18892.d(20): Error: no property `foo` for type `fail18892.MT`
+fail_compilation/fail18892.d(21): Error: no property `foo` for type `fail18892.MT`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=18892
+
+struct MT
+{
+ int _payload;
+ alias _payload this;
+}
+
+void main()
+{
+ MT a;
+ a.foo = 3;
+ MT.foo = 3;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18938.d b/gcc/testsuite/gdc.test/fail_compilation/fail18938.d
new file mode 100644
index 0000000..f7ece6d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18938.d
@@ -0,0 +1,11 @@
+// REQUIRED_ARGS: -c -Ifail_compilation/imports/
+// EXTRA_SOURCES: imports/test18938a/cache.d imports/test18938a/file.d
+// EXTRA_FILES: imports/test18938b/file.d
+/*
+TEST_OUTPUT:
+---
+fail_compilation/imports/test18938b/file.d(20): Error: undefined identifier `No`
+---
+*/
+
+void main() {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18970.d b/gcc/testsuite/gdc.test/fail_compilation/fail18970.d
index 0ec53c8..0973217 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail18970.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18970.d
@@ -1,8 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail18970.d(22): Error: no property `y` for type `S`
-fail_compilation/fail18970.d(29): Error: no property `yyy` for type `S2`
+fail_compilation/fail18970.d(24): Error: no property `y` for type `fail18970.S`
+fail_compilation/fail18970.d(24): potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message
+fail_compilation/fail18970.d(31): Error: no property `yyy` for type `fail18970.S2`
+fail_compilation/fail18970.d(31): potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18979.d b/gcc/testsuite/gdc.test/fail_compilation/fail18979.d
new file mode 100644
index 0000000..9756570
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18979.d
@@ -0,0 +1,14 @@
+// EXTRA_FILES: imports/imp18979.d
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail18979.d(13): Error: no property `__ctor` for type `imports.imp18979.Foo`
+----
+*/
+
+import imports.imp18979;
+
+void main()
+{
+ auto f = Foo(42);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18985.d b/gcc/testsuite/gdc.test/fail_compilation/fail18985.d
new file mode 100644
index 0000000..830a679
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18985.d
@@ -0,0 +1,18 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail18985.d(16): Error: `foo` is not a scalar, it is a `object.Object`
+fail_compilation/fail18985.d(17): Error: `bar` is not a scalar, it is a `shared(Object)`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=18985
+
+Object foo;
+shared Object bar;
+
+void main()
+{
+ foo += 1;
+ bar += 1;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18994.d b/gcc/testsuite/gdc.test/fail_compilation/fail18994.d
new file mode 100644
index 0000000..14935a72
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18994.d
@@ -0,0 +1,20 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail18994.d(19): Error: struct `fail18994.Type1` is not copyable because it has a disabled postblit
+---
+*/
+struct Type2
+{
+ int opApply(int delegate(ref Type1)) { return 0; }
+}
+
+struct Type1
+{
+ @disable this(this);
+}
+
+void test()
+{
+ foreach(b; Type2()) {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail190.d b/gcc/testsuite/gdc.test/fail_compilation/fail190.d
index 6f4046a..59e11d7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail190.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail190.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail190.d(9): Error: can't have pointer to (int, int, int)
-fail_compilation/fail190.d(16): Error: template instance fail190.f!(int, int, int) error instantiating
+fail_compilation/fail190.d(9): Error: cannot have pointer to `(int, int, int)`
+fail_compilation/fail190.d(16): Error: template instance `fail190.f!(int, int, int)` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail1900.d b/gcc/testsuite/gdc.test/fail_compilation/fail1900.d
index cabfbdf..fd0d6ac 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail1900.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail1900.d
@@ -1,10 +1,11 @@
/*
+EXTRA_FILES: imports/fail1900a.d imports/fail1900b.d
TEST_OUTPUT:
---
-fail_compilation/fail1900.d(26): Error: template fail1900.Mix1a!().Foo matches more than one template declaration:
-fail_compilation/fail1900.d(13): Foo(ubyte x)
+fail_compilation/fail1900.d(27): Error: template `fail1900.Mix1a!().Foo` matches more than one template declaration:
+fail_compilation/fail1900.d(14): `Foo(ubyte x)`
and
-fail_compilation/fail1900.d(14): Foo(byte x)
+fail_compilation/fail1900.d(15): `Foo(byte x)`
---
*/
@@ -29,7 +30,7 @@ void test1900a()
/*
TEST_OUTPUT:
---
-fail_compilation/fail1900.d(41): Error: imports.fail1900b.Bar(short n) at fail_compilation/imports/fail1900b.d(2) conflicts with imports.fail1900a.Bar(int n) at fail_compilation/imports/fail1900a.d(2)
+fail_compilation/fail1900.d(42): Error: template `imports.fail1900b.Bar(short n)` at fail_compilation/imports/fail1900b.d(2) conflicts with template `imports.fail1900a.Bar(int n)` at fail_compilation/imports/fail1900a.d(2)
---
*/
@@ -44,7 +45,7 @@ void test1900b()
/*
TEST_OUTPUT:
---
-fail_compilation/fail1900.d(65): Error: fail1900.Mix2b!().Baz(int x) at fail_compilation/fail1900.d(57) conflicts with fail1900.Mix2a!().Baz(byte x) at fail_compilation/fail1900.d(53)
+fail_compilation/fail1900.d(66): Error: template `fail1900.Mix2b!().Baz(int x)` at fail_compilation/fail1900.d(58) conflicts with template `fail1900.Mix2a!().Baz(byte x)` at fail_compilation/fail1900.d(54)
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19038.d b/gcc/testsuite/gdc.test/fail_compilation/fail19038.d
new file mode 100644
index 0000000..ef1a8b7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19038.d
@@ -0,0 +1,29 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/fail19038.d(21): Error: cannot implicitly convert expression `a` of type `string[][]` to `const(string)[][]`
+fail_compilation/fail19038.d(23): Error: cannot modify `const` expression `c[0]`
+---
+ * Credit: yshui
+ * https://github.com/dlang/dmd/pull/8413#issuecomment-401104961
+ * https://issues.dlang.org/show_bug.cgi?id=19038
+ */
+
+
+void test()
+{
+ /* string[][] is not implicitly converible to const(string)[][],
+ * and there is good reason why:
+ *
+ * https://stackoverflow.com/questions/5055655/double-pointer-const-correctness-warnings-in-c
+ */
+
+ string[][] a = [["Lord"]];
+ const(string)[][] b = a; // assume this works (and it should not)
+ const(string)[] c = ["Sauron"];
+ c[0] = "Mordor"; // invalid, because c[0] is const(string)
+
+ b[0] = c; // valid, b[0] is const(string)[]
+ // But now, a[0] has become c
+ a[0][0] = "Nazgul"; // valid, because a[0][0] is string
+ // But this also changes c[0], which shouldn't be possible
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19076.d b/gcc/testsuite/gdc.test/fail_compilation/fail19076.d
new file mode 100644
index 0000000..9bfc0a5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19076.d
@@ -0,0 +1,11 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19076.d(11): Error: no property `V` for type `fail19076.I`
+fail_compilation/fail19076.d(11): Error: `(I).V` cannot be resolved
+---
+*/
+
+interface P { }
+interface I : P { }
+auto F = __traits(getVirtualFunctions, I, "V");
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19098.d b/gcc/testsuite/gdc.test/fail_compilation/fail19098.d
new file mode 100644
index 0000000..c4f879f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19098.d
@@ -0,0 +1,19 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19098.d(18): Error: cannot modify struct instance `a` of type `A` because it contains `const` or `immutable` members
+---
+*/
+
+struct A
+{
+ const int a;
+ this(int) {}
+}
+
+void main()
+{
+ A a = A(2);
+ A b = A(3);
+ a = b;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19099.d b/gcc/testsuite/gdc.test/fail_compilation/fail19099.d
new file mode 100644
index 0000000..6fbc6147
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19099.d
@@ -0,0 +1,27 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19099.d(26): Error: cannot modify struct instance `a` of type `A` because it contains `const` or `immutable` members
+---
+*/
+
+struct B
+{
+ this(this) {}
+ ~this() {}
+ int a;
+}
+
+struct A
+{
+ B b;
+ immutable int a;
+ this(int b) { a = b;}
+}
+
+void main()
+{
+ A a = A(2);
+ A b = A(3);
+ a = b;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19103.d b/gcc/testsuite/gdc.test/fail_compilation/fail19103.d
new file mode 100644
index 0000000..6b740ac
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19103.d
@@ -0,0 +1,36 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19103.d(12): Error: no property `puts` for type `fail19103.C`
+fail_compilation/fail19103.d(14): Error: no property `puts` for type `fail19103.S1`
+fail_compilation/fail19103.d(16): Error: no property `puts` for type `S2`, did you mean `core.stdc.stdio.puts`?
+---
+*/
+
+void main()
+{
+ (new C).puts("OK."); // Error: no property puts for type test.C, did you mean core.stdc.stdio.puts(T...)(T args)?
+ S1 s1;
+ s1.puts("Hey?"); // It can be compiled and runs!
+ S2 s2;
+ s2.puts("OK."); // Error: no property puts for type S2, did you mean core.stdc.stdio.puts(T...)(T args)?
+}
+
+mixin template T()
+{
+ import core.stdc.stdio;
+}
+
+class C
+{
+ mixin T;
+}
+struct S1
+{
+ mixin T;
+}
+
+struct S2
+{
+ import core.stdc.stdio;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19107.d b/gcc/testsuite/gdc.test/fail_compilation/fail19107.d
deleted file mode 100644
index c748650..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19107.d
+++ /dev/null
@@ -1,21 +0,0 @@
-// REQUIRED_ARGS:
-/*
-TEST_OUTPUT:
----
-fail_compilation/test19107.d(20): Error: template `test19107.all` cannot deduce function from argument types `!((c) => c)(string[])`, candidates are:
-fail_compilation/test19107.d(14): `test19107.all(alias pred, T)(T t) if (is(typeof(I!pred(t))))`
----
-*/
-
-// https://issues.dlang.org/show_bug.cgi?id=19107
-
-import imports.test19107b;
-
-void all(alias pred, T)(T t)
- if (is(typeof(I!pred(t))))
-{ }
-
-void main(string[] args)
-{
- args.all!(c => c);
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19181.d b/gcc/testsuite/gdc.test/fail_compilation/fail19181.d
new file mode 100644
index 0000000..873e292
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19181.d
@@ -0,0 +1,16 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19181.d(15): Error: undefined identifier `LanguageError`
+---
+*/
+struct S
+{
+ void opDispatch(string name, T)(T arg) { }
+}
+
+void main()
+{
+ S s;
+ s.foo(LanguageError);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail192.d b/gcc/testsuite/gdc.test/fail_compilation/fail192.d
index 3c485e6..96232a5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail192.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail192.d
@@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail192.d(15): Error: outer function context of fail192.foo is needed to 'new' nested class fail192.foo.DummyClass
-fail_compilation/fail192.d(26): Error: template instance fail192.X!(DummyClass) error instantiating
+fail_compilation/fail192.d(15): Error: outer function context of `fail192.foo` is needed to `new` nested class `fail192.foo.DummyClass`
+fail_compilation/fail192.d(26): Error: template instance `fail192.X!(DummyClass)` error instantiating
---
*/
-// 1336 Internal error when trying to construct a class declared within a unittest from a templated class.
-
+// https://issues.dlang.org/show_bug.cgi?id=1336
+// Internal error when trying to construct a class declared within a unittest from a templated class.
class X(T)
{
void bar()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19202.d b/gcc/testsuite/gdc.test/fail_compilation/fail19202.d
new file mode 100644
index 0000000..f19bc18
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19202.d
@@ -0,0 +1,17 @@
+// REQUIRED_ARGS: -de
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19202.d(11): Deprecation: variable `fail19202.X!().X` is deprecated
+---
+*/
+
+void main()
+{
+ auto b = X!();
+}
+
+template X()
+{
+ deprecated enum X = true;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19209.d b/gcc/testsuite/gdc.test/fail_compilation/fail19209.d
new file mode 100644
index 0000000..ceede5e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19209.d
@@ -0,0 +1,17 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19209.d(16): Error: function `fail19209.Spammer.method()` does not override any function, did you mean to override variable `fail19209.Spam.method`?
+fail_compilation/fail19209.d(16): Functions are the only declarations that may be overriden
+---
+*/
+
+class Spam
+{
+ int method;
+}
+
+class Spammer : Spam
+{
+ override method() {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail193.d b/gcc/testsuite/gdc.test/fail_compilation/fail193.d
index c3093c7..9fcae5b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail193.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail193.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail193.d(14): Error: cannot infer type from overloaded function symbol & foo
+fail_compilation/fail193.d(14): Error: cannot infer type from overloaded function symbol `& foo`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19319a.d b/gcc/testsuite/gdc.test/fail_compilation/fail19319a.d
new file mode 100644
index 0000000..f3efe1f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19319a.d
@@ -0,0 +1,17 @@
+/*
+DFLAGS:
+REQUIRED_ARGS: -conf= -Ifail_compilation/extra-files/minimal
+TEST_OUTPUT:
+---
+fail_compilation/fail19319a.d(16): Error: `7 ^^ g19319` requires `std.math` for `^^` operators
+fail_compilation/fail19319a.d(17): Error: `g19319 ^^ 7` requires `std.math` for `^^` operators
+---
+*/
+
+__gshared int g19319 = 0;
+
+static assert(!__traits(compiles, 7 ^^ g19319));
+static assert(!__traits(compiles, g19319 ^^= 7));
+
+__gshared int e19319 = 7 ^^ g19319;
+__gshared int a19319 = g19319 ^^= 7;;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19319b.d b/gcc/testsuite/gdc.test/fail_compilation/fail19319b.d
new file mode 100644
index 0000000..933dc16
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19319b.d
@@ -0,0 +1,18 @@
+/*
+DFLAGS:
+REQUIRED_ARGS: -conf= -Ifail_compilation/extra-files/minimal
+TEST_OUTPUT:
+---
+fail_compilation/fail19319b.d(16): Error: `7 ^^ x` requires `std.math` for `^^` operators
+fail_compilation/fail19319b.d(17): Error: `x ^^ 7` requires `std.math` for `^^` operators
+---
+*/
+
+void test19319(int x)
+{
+ static assert(!__traits(compiles, 7 ^^ x));
+ static assert(!__traits(compiles, x ^^= 7));
+
+ int i = 7 ^^ x;
+ x ^^= 7;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail194.d b/gcc/testsuite/gdc.test/fail_compilation/fail194.d
index 2ce4ab8..f2270f1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail194.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail194.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail194.d(18): Error: function & foo is overloaded
+fail_compilation/fail194.d(18): Error: function `& foo` is overloaded
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19441.d b/gcc/testsuite/gdc.test/fail_compilation/fail19441.d
new file mode 100644
index 0000000..f1f1769
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19441.d
@@ -0,0 +1,49 @@
+// REQUIRED_ARGS: -de
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19441.d(44): Deprecation: Cannot use `alias this` to partially initialize variable `wrap[0]` of type `Wrap10595`. Use `wrap[0].i`
+---
+*/
+
+struct S10595
+{
+ bool b = true;
+
+ bool test()
+ {
+ if (!b) // note: must be a check, not 'return b;'
+ return false;
+
+ return true;
+ }
+}
+
+struct Wrap10595
+{
+ int i;
+ alias i this;
+ S10595 s;
+}
+
+void main()
+{
+ {
+ Wrap10595[int] wrap;
+
+ wrap[0] = Wrap10595();
+ wrap[0].i = 0;
+
+ assert(wrap[0].s.test()); // ok
+ }
+
+ {
+ Wrap10595[int] wrap;
+
+ wrap[0] = Wrap10595();
+ wrap[0] = 0; // note: using 'alias this' to assign
+
+ assert(wrap[0].s.test()); // failure
+ }
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19447.d b/gcc/testsuite/gdc.test/fail_compilation/fail19447.d
new file mode 100644
index 0000000..23f4921
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19447.d
@@ -0,0 +1,19 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/fail19447.d(110): Error: static variable `mh` cannot be read at compile time
+fail_compilation/fail19447.d(110): called from here: `g19447(mh)`
+---
+ */
+
+#line 100
+
+int [2] mh = [1, 2];
+int g19447(ref int[2] a)
+{
+ int[2] b=2;
+ a=b;
+ assert(a[0]==2);
+ return 1;
+}
+
+immutable int i = g19447(mh);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail195.d b/gcc/testsuite/gdc.test/fail_compilation/fail195.d
index 57a6bdc..5f067a9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail195.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail195.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail195.d(22): Error: struct Foo does not overload ()
+fail_compilation/fail195.d(22): Error: struct `Foo` does not overload ()
---
*/
-// 1384 Compiler segfaults when using struct variable like a function with no opCall member.
-
+// https://issues.dlang.org/show_bug.cgi?id=1384
+// Compiler segfaults when using struct variable like a function with no opCall member.
struct Foo
{
union
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19609.d b/gcc/testsuite/gdc.test/fail_compilation/fail19609.d
index 26ef576..c68f199 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19609.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19609.d
@@ -1,15 +1,16 @@
// https://issues.dlang.org/show_bug.cgi?id=19609
/*
+EXTRA_FILES: imports/fail19609a.d imports/fail19609b.d imports/fail19609c.d imports/fail19609d.d
TEST_OUTPUT
---
fail_compilation/imports/fail19609a.d(1): Error: `string` expected for deprecation message, not `([""])` of type `string[]`
-fail_compilation/fail19609.d(15): Deprecation: module `imports.fail19609a` is deprecated
+fail_compilation/fail19609.d(16): Deprecation: module `imports.fail19609a` is deprecated
fail_compilation/imports/fail19609b.d(1): Error: `string` expected for deprecation message, not `([1])` of type `int[]`
-fail_compilation/fail19609.d(16): Deprecation: module `imports.fail19609b` is deprecated
+fail_compilation/fail19609.d(17): Deprecation: module `imports.fail19609b` is deprecated
fail_compilation/imports/fail19609c.d(1): Error: `string` expected for deprecation message, not `(123.4F)` of type `float`
-fail_compilation/fail19609.d(17): Deprecation: module `imports.fail19609c` is deprecated
+fail_compilation/fail19609.d(18): Deprecation: module `imports.fail19609c` is deprecated
fail_compilation/imports/fail19609d.d(1): Error: undefined identifier `msg`
-fail_compilation/fail19609.d(19): Deprecation: module `imports.fail19609d` is deprecated
+fail_compilation/fail19609.d(20): Deprecation: module `imports.fail19609d` is deprecated
---
*/
import imports.fail19609a;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19687.d b/gcc/testsuite/gdc.test/fail_compilation/fail19687.d
new file mode 100644
index 0000000..7d1c6e5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19687.d
@@ -0,0 +1,18 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19687.d(17): Error: no property `nonexisting` for type `string`
+---
+*/
+
+struct S
+{
+ void opDispatch(string name)() {}
+ void opDispatch(string name)(string value) {}
+}
+
+void main()
+{
+ S n;
+ n.foo = "".nonexisting();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19729.d b/gcc/testsuite/gdc.test/fail_compilation/fail19729.d
new file mode 100644
index 0000000..5943d08
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19729.d
@@ -0,0 +1,37 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19729.d(35): Error: `fail19729.C.__ctor` called with argument types `(string)` matches both:
+fail_compilation/fail19729.d(18): `fail19729.C.Templ!string.this(string t)`
+and:
+fail_compilation/fail19729.d(18): `fail19729.C.Templ!string.this(string t)`
+fail_compilation/fail19729.d(36): Error: `fail19729.D.__ctor` called with argument types `(string)` matches both:
+fail_compilation/fail19729.d(18): `fail19729.D.Templ!(const(char)[]).this(const(char)[] t)`
+and:
+fail_compilation/fail19729.d(18): `fail19729.D.Templ!(const(char)*).this(const(char)* t)`
+---
+*/
+module fail19729;
+
+mixin template Templ(T)
+{
+ this(T t) { }
+}
+
+class C
+{
+ mixin Templ!string;
+ mixin Templ!string;
+}
+
+class D
+{
+ mixin Templ!(const(char)*);
+ mixin Templ!(const(char)[]);
+}
+
+void main()
+{
+ new C("conflict");
+ new D("conflict");
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19744.d b/gcc/testsuite/gdc.test/fail_compilation/fail19744.d
new file mode 100644
index 0000000..9115b4e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19744.d
@@ -0,0 +1,11 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19744.d(8): Error: Top-level function `test` has no `this` to which `return` can apply
+---
+*/
+
+int* test(return scope int* n) return
+{
+ return n;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19757_m32.d b/gcc/testsuite/gdc.test/fail_compilation/fail19757_m32.d
new file mode 100644
index 0000000..6ddb456
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19757_m32.d
@@ -0,0 +1,9 @@
+// REQUIRED_ARGS: -m32
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19757_m32.d(9): Error: cannot implicitly convert expression `"oops"` of type `string` to `uint`
+---
+*/
+
+auto s = new string("oops");
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19757_m64.d b/gcc/testsuite/gdc.test/fail_compilation/fail19757_m64.d
new file mode 100644
index 0000000..e1f9afc
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19757_m64.d
@@ -0,0 +1,9 @@
+// REQUIRED_ARGS: -m64
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19757_m64.d(9): Error: cannot implicitly convert expression `"oops"` of type `string` to `ulong`
+---
+*/
+
+auto s = new string("oops");
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail198.d b/gcc/testsuite/gdc.test/fail_compilation/fail198.d
index 4cb63b4..1a096f4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail198.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail198.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail198.d(8): Error: template instance test!42 template 'test' is not defined
+fail_compilation/fail198.d(8): Error: template instance `test!42` template `test` is not defined
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19871.d b/gcc/testsuite/gdc.test/fail_compilation/fail19871.d
new file mode 100644
index 0000000..ad458df
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19871.d
@@ -0,0 +1,20 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19871.d(10): Error: `struct Struct` may not define both a rvalue constructor and a copy constructor
+fail_compilation/fail19871.d(19): rvalue constructor defined here
+fail_compilation/fail19871.d(13): copy constructor defined here
+---
+*/
+
+struct Struct
+{
+ @disable this();
+ this(ref Struct other)
+ {
+ const Struct s = void;
+ this(s);
+ }
+
+ this(Struct) {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19881.d b/gcc/testsuite/gdc.test/fail_compilation/fail19881.d
new file mode 100644
index 0000000..f4a4d76
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19881.d
@@ -0,0 +1,15 @@
+/* REQUIRED_ARGS: -preview=dip1000
+ * TEST_OUTPUT:
+---
+fail_compilation/fail19881.d(12): Error: address of local variable `local` assigned to return scope `input`
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=19881
+
+@safe int* test(return scope int* input) {
+ int local = 42;
+ input = &local;
+
+ return input;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d b/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d
index 2120dc5..d4da116 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d
@@ -1,8 +1,8 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/fail19890a.d(8): Error: `void[/^[0-9]+(LU)?$/]` size 1 * /^[0-9]+$/ exceeds 0x7fffffff size limit for static array
+fail_compilation/fail19890a.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array
---
*/
+
void[] f = cast(void[-1]) "a";
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d b/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d
index c3ee677..f4a5dad 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d
@@ -1,8 +1,8 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/fail19890b.d(8): Error: `void[/^[0-9]+(LU)?$/]` size 1 * /^[0-9]+$/ exceeds 0x7fffffff size limit for static array
+fail_compilation/fail19890b.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array
---
*/
+
void[] f = cast(void[-2]) "a";
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19897.d b/gcc/testsuite/gdc.test/fail_compilation/fail19897.d
index 8dd4e14..d5e6f57 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19897.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19897.d
@@ -1,8 +1,7 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT
---
-fail_compilation/fail19897.d(10): Error: cannot implicitly convert expression `[]` of type `const(char[0])` to `const(char)`
+fail_compilation/fail19897.d(9): Error: cannot implicitly convert expression `[]` of type `const(char[0])` to `const(char)`
---
*/
struct S
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19898a.d b/gcc/testsuite/gdc.test/fail_compilation/fail19898a.d
index 406e468..f4aa848 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19898a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19898a.d
@@ -1,9 +1,8 @@
/*
-PERMUTE_ARGS:
REQUIRED_ARGS: -m64
TEST_OUTPUT:
---
-fail_compilation/fail19898a.d(11): Error: incompatible types for `(__key2) < (__limit3)`: both operands are of type `__vector(int[4])`
+fail_compilation/fail19898a.d(10): Error: incompatible types for `(__key2) < (__limit3)`: both operands are of type `__vector(int[4])`
---
*/
void f (__vector(int[4]) n)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19898b.d b/gcc/testsuite/gdc.test/fail_compilation/fail19898b.d
index 0b47fb78..82d92eb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19898b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19898b.d
@@ -1,11 +1,10 @@
/*
-PERMUTE_ARGS:
REQUIRED_ARGS: -m64
TEST_OUTPUT:
---
-fail_compilation/fail19898b.d(18): Error: cannot implicitly convert expression `m` of type `S` to `__vector(int[4])`
-fail_compilation/fail19898b.d(18): Error: incompatible types for `(__key2) != (__limit3)`: both operands are of type `__vector(int[4])`
-fail_compilation/fail19898b.d(18): Error: cannot cast expression `__key2` of type `__vector(int[4])` to `S`
+fail_compilation/fail19898b.d(17): Error: cannot implicitly convert expression `m` of type `S` to `__vector(int[4])`
+fail_compilation/fail19898b.d(17): Error: incompatible types for `(__key2) != (__limit3)`: both operands are of type `__vector(int[4])`
+fail_compilation/fail19898b.d(17): Error: cannot cast expression `__key2` of type `__vector(int[4])` to `S`
---
*/
struct S
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19911b.d b/gcc/testsuite/gdc.test/fail_compilation/fail19911b.d
index b4ad22b..c5d6a8a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19911b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19911b.d
@@ -1,6 +1,5 @@
/*
DFLAGS:
-REQUIRED_ARGS:
EXTRA_SOURCES: extra-files/minimal/object.d
TEST_OUTPUT:
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19911c.d b/gcc/testsuite/gdc.test/fail_compilation/fail19911c.d
index d1e954e..fbd7406 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19911c.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19911c.d
@@ -1,9 +1,8 @@
/*
DFLAGS:
-REQUIRED_ARGS:
TEST_OUTPUT:
---
-fail_compilation/fail19911c.d(15): Error: function `object.fun` `object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions
+fail_compilation/fail19911c.d(14): Error: function `object.fun` `object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19912a.d b/gcc/testsuite/gdc.test/fail_compilation/fail19912a.d
index 47d3cf2..31a508a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19912a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19912a.d
@@ -1,8 +1,7 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/fail19912a.d(8): Error: struct `fail19912a.object` conflicts with import `fail19912a.object` at fail_compilation/fail19912a.d
+fail_compilation/fail19912a.d(7): Error: struct `fail19912a.object` conflicts with import `fail19912a.object` at fail_compilation/fail19912a.d
---
*/
struct object { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19912b.d b/gcc/testsuite/gdc.test/fail_compilation/fail19912b.d
index b3bd56d..1e52814 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19912b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19912b.d
@@ -1,8 +1,7 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/fail19912b.d(8): Error: class `fail19912b.object` conflicts with import `fail19912b.object` at fail_compilation/fail19912b.d
+fail_compilation/fail19912b.d(7): Error: class `fail19912b.object` conflicts with import `fail19912b.object` at fail_compilation/fail19912b.d
---
*/
class object { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19912c.d b/gcc/testsuite/gdc.test/fail_compilation/fail19912c.d
index a4656cc..38d7a5a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19912c.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19912c.d
@@ -1,8 +1,7 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/fail19912c.d(8): Error: alias `fail19912c.object` conflicts with import `fail19912c.object` at fail_compilation/fail19912c.d
+fail_compilation/fail19912c.d(7): Error: alias `fail19912c.object` conflicts with import `fail19912c.object` at fail_compilation/fail19912c.d
---
*/
alias object = int;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19912d.d b/gcc/testsuite/gdc.test/fail_compilation/fail19912d.d
index fdc8dcb..c0fe489 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19912d.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19912d.d
@@ -1,8 +1,7 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/fail19912d.d(8): Error: enum `fail19912d.object` conflicts with import `fail19912d.object` at fail_compilation/fail19912d.d
+fail_compilation/fail19912d.d(7): Error: enum `fail19912d.object` conflicts with import `fail19912d.object` at fail_compilation/fail19912d.d
---
*/
enum object { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19912e.d b/gcc/testsuite/gdc.test/fail_compilation/fail19912e.d
index 19cc9a6..0aa3433 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19912e.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19912e.d
@@ -1,8 +1,7 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/fail19912e.d(8): Error: function `fail19912e.object` conflicts with import `fail19912e.object` at fail_compilation/fail19912e.d
+fail_compilation/fail19912e.d(7): Error: function `fail19912e.object` conflicts with import `fail19912e.object` at fail_compilation/fail19912e.d
---
*/
void object() { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19913.d b/gcc/testsuite/gdc.test/fail_compilation/fail19913.d
index b0f31b5..fe2655e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19913.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19913.d
@@ -1,10 +1,10 @@
-/* PERMUTE_ARGS:
- * TEST_OUTPUT:
+/*
+TEST_OUTPUT:
---
fail_compilation/fail19913.d(11): Error: no property `b` for type `int`
fail_compilation/fail19913.d(11): Error: mixin `fail19913.S.b!()` is not defined
---
- */
+*/
struct S
{
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19914.d b/gcc/testsuite/gdc.test/fail_compilation/fail19914.d
index a890d35..2fd3da7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19914.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19914.d
@@ -1,9 +1,8 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/fail19914.d(9): Error: undefined identifier `c` in module `fail19914`
-fail_compilation/fail19914.d(10): Error: mixin `fail19914.a!string` error instantiating
+fail_compilation/fail19914.d(8): Error: undefined identifier `c` in module `fail19914`
+fail_compilation/fail19914.d(9): Error: mixin `fail19914.a!string` error instantiating
---
*/
class a(b) { align.c d; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19915.d b/gcc/testsuite/gdc.test/fail_compilation/fail19915.d
index 17e05ee..e12fe0f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19915.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19915.d
@@ -1,9 +1,8 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/fail19915.d(9): Error: undefined identifier `c` in module `fail19915`
-fail_compilation/fail19915.d(10): Error: template instance `fail19915.a!int` error instantiating
+fail_compilation/fail19915.d(8): Error: undefined identifier `c` in module `fail19915`
+fail_compilation/fail19915.d(9): Error: template instance `fail19915.a!int` error instantiating
---
*/
class a (b) { align.c d; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19917.d b/gcc/testsuite/gdc.test/fail_compilation/fail19917.d
new file mode 100644
index 0000000..c6ad83b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19917.d
@@ -0,0 +1,49 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19917.d(22): Error: overlapping default initialization for field `c` and `a`
+fail_compilation/fail19917.d(22): Error: overlapping default initialization for field `d` and `b`
+fail_compilation/fail19917.d(39): Error: overlapping default initialization for field `b` and `a`
+---
+*/
+
+struct S
+{
+ union
+ {
+ struct
+ {
+ int a = 3;
+ int b = 4;
+ }
+ }
+}
+
+struct X
+{
+ union
+ {
+ struct
+ {
+ int a = 3;
+ int b = 4;
+ }
+ struct
+ {
+ int c = 3;
+ int d = 4;
+ }
+ }
+}
+
+struct Y
+{
+ union
+ {
+ struct
+ {
+ union { int a = 3; }
+ }
+ int b = 4;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19919.d b/gcc/testsuite/gdc.test/fail_compilation/fail19919.d
new file mode 100644
index 0000000..3c65cbf
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19919.d
@@ -0,0 +1,25 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19919.d(16): Error: union field `f` with default initialization `3.14F` must be before field `n`
+fail_compilation/fail19919.d(23): Error: union field `f` with default initialization `3.14F` must be before field `n`
+---
+*/
+
+void main()
+{
+ struct X
+ {
+ union
+ {
+ int n;
+ float f = 3.14f;
+ }
+ }
+
+ union U
+ {
+ int n;
+ float f = 3.14f;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19922.d b/gcc/testsuite/gdc.test/fail_compilation/fail19922.d
index 5c9e2bb..201b124 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19922.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19922.d
@@ -1,9 +1,8 @@
/*
DFLAGS:
-REQUIRED_ARGS:
TEST_OUTPUT:
---
-fail_compilation/fail19922.d(17): Error: `object.TypeInfo_Class` could not be found, but is implicitly used
+fail_compilation/fail19922.d(16): Error: `object.TypeInfo_Class` could not be found, but is implicitly used
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19923.d b/gcc/testsuite/gdc.test/fail_compilation/fail19923.d
index 042cf8a..1438151 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19923.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19923.d
@@ -1,9 +1,8 @@
/*
DFLAGS:
-REQUIRED_ARGS:
TEST_OUTPUT:
---
-fail_compilation/fail19923.d(17): Error: `object.TypeInfo_Class` could not be found, but is implicitly used
+fail_compilation/fail19923.d(16): Error: `object.TypeInfo_Class` could not be found, but is implicitly used
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19931.d b/gcc/testsuite/gdc.test/fail_compilation/fail19931.d
new file mode 100644
index 0000000..940a1fa
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19931.d
@@ -0,0 +1,15 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail19931.d(10): Error: `struct S` may not define both a rvalue constructor and a copy constructor
+fail_compilation/fail19931.d(12): rvalue constructor defined here
+fail_compilation/fail19931.d(13): copy constructor defined here
+---
+*/
+
+struct S
+{
+ this(S s) {}
+ this(ref S s) {}
+ this(this) {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail1995.d b/gcc/testsuite/gdc.test/fail_compilation/fail1995.d
new file mode 100644
index 0000000..7dfddec
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail1995.d
@@ -0,0 +1,12 @@
+/*
+REQUIRED_ARGS: -Jdoes_not_exists -Jfail_compilation/fail1995.d -Jfail_compilation/
+TEST_OUTPUT:
+---
+fail_compilation/fail1995.d(12): Error: file `"SomeFile.txt"` cannot be found or not in a path specified with `-J`
+fail_compilation/fail1995.d(12): Path(s) searched (as provided by `-J`):
+fail_compilation/fail1995.d(12): [0]: `does_not_exists` (path not found)
+fail_compilation/fail1995.d(12): [1]: `fail_compilation/fail1995.d` (not a directory)
+fail_compilation/fail1995.d(12): [2]: `fail_compilation/`
+---
+ */
+immutable string Var = import("SomeFile.txt");
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19955.d b/gcc/testsuite/gdc.test/fail_compilation/fail19955.d
index 7cdce2c..e2af71f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19955.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19955.d
@@ -1,8 +1,7 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/fail19955.d(8): Error: `switch` statement without a `default`; use `final switch` or add `default: assert(0);` or add `default: break;`
+fail_compilation/fail19955.d(7): Error: `switch` statement without a `default`; use `final switch` or add `default: assert(0);` or add `default: break;`
---
*/
void f() { switch(1) static assert(1); }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19965.d b/gcc/testsuite/gdc.test/fail_compilation/fail19965.d
new file mode 100644
index 0000000..b76a3a0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19965.d
@@ -0,0 +1,37 @@
+/*
+REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail19965.d(36): Error: address of variable `f` assigned to `a` with longer lifetime
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=19965
+
+struct Buffer
+{
+ int[10] data;
+
+ int[] getData() @safe return
+ {
+ return data[];
+ }
+}
+
+struct Foo()
+{
+ Buffer buffer;
+
+ int[] toArray() @safe return
+ {
+ return buffer.getData;
+ }
+}
+
+int[] a;
+
+void main() @safe
+{
+ Foo!() f;
+ a = f.toArray;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20.d b/gcc/testsuite/gdc.test/fail_compilation/fail20.d
index 821cc84..6cc4d22 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail20.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail20.d(16): Error: need member function opCmp() for struct FOO to compare
+fail_compilation/fail20.d(16): Error: need member function `opCmp()` for struct `FOO` to compare
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20000.d b/gcc/testsuite/gdc.test/fail_compilation/fail20000.d
new file mode 100644
index 0000000..fe48121
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20000.d
@@ -0,0 +1,39 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20000.d(25): Error: cast from `fail20000.DClass` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(26): Error: cast from `fail20000.DInterface` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(27): Error: cast from `fail20000.CppClass2` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(28): Error: cast from `fail20000.CppInterface2` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(30): Error: cast from `fail20000.DClass` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(31): Error: cast from `fail20000.DInterface` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(32): Error: cast from `fail20000.CppClass2` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(33): Error: cast from `fail20000.CppInterface2` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(35): Error: cast from `fail20000.CppClass` to `fail20000.DClass` not allowed in safe code
+fail_compilation/fail20000.d(36): Error: cast from `fail20000.CppInterface` to `fail20000.DClass` not allowed in safe code
+fail_compilation/fail20000.d(38): Error: cast from `fail20000.CppClass` to `fail20000.DInterface` not allowed in safe code
+fail_compilation/fail20000.d(39): Error: cast from `fail20000.CppInterface` to `fail20000.DInterface` not allowed in safe code
+---
+*/
+extern(C++) class CppClass { int a; }
+extern(C++) class CppClass2 { void* a; }
+extern(C++) interface CppInterface { int b(); }
+extern(C++) interface CppInterface2 { void* b(); }
+class DClass { int c; }
+interface DInterface { int d(); }
+
+bool isCppClass(DClass a) @safe { return cast(CppClass) a !is null; }
+bool isCppClass(DInterface a) @safe { return cast(CppClass) a !is null; }
+bool isCppClass(CppClass2 a) @safe { return cast(CppClass) a !is null; }
+bool isCppClass(CppInterface2 a) @safe { return cast(CppClass) a !is null; }
+
+bool isCppInterface(DClass a) @safe { return cast(CppInterface) a !is null; }
+bool isCppInterface(DInterface a) @safe { return cast(CppInterface) a !is null; }
+bool isCppInterface(CppClass2 a) @safe { return cast(CppInterface) a !is null; }
+bool isCppInterface(CppInterface2 a) @safe { return cast(CppInterface) a !is null; }
+
+bool isDClass(CppClass a) @safe { return cast(DClass) a !is null; }
+bool isDClass(CppInterface a) @safe { return cast(DClass) a !is null; }
+
+bool isDInterface(CppClass a) @safe { return cast(DInterface) a !is null; }
+bool isDInterface(CppInterface a) @safe { return cast(DInterface) a !is null; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20033.d b/gcc/testsuite/gdc.test/fail_compilation/fail20033.d
new file mode 100644
index 0000000..f641469
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20033.d
@@ -0,0 +1,54 @@
+// REQUIRED_ARGS: -de
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20033.d(38): Deprecation: `alias byKeyValue this` is deprecated - This was a bad idea
+fail_compilation/fail20033.d(39): Deprecation: `alias byKeyValue this` is deprecated
+fail_compilation/fail20033.d(41): Deprecation: `alias byKeyValue this` is deprecated - This was a bad idea
+fail_compilation/fail20033.d(42): Deprecation: `alias byKeyValue this` is deprecated
+---
+*/
+#line 1
+struct Tuple(T...)
+{
+ T values;
+ alias values this;
+}
+
+alias KVT = Tuple!(string, string);
+
+struct Test {
+ struct Range {
+ bool empty () { return false; }
+ KVT front() { return KVT.init; }
+ void popFront() {}
+ }
+
+ auto byKeyValue () { return Range.init; }
+
+ deprecated("This was a bad idea")
+ alias byKeyValue this;
+}
+
+struct Test2 {
+ struct Range {
+ bool empty () { return false; }
+ KVT front() { return KVT.init; }
+ void popFront() {}
+ }
+
+ auto byKeyValue () { return Range.init; }
+
+ deprecated alias byKeyValue this;
+}
+
+void main ()
+{
+ foreach (k, v; Test.init.byKeyValue) {} // Fine
+ foreach (k, v; Test2.init.byKeyValue) {} // Fine
+ foreach (k, v; Test.init) {} // Fails
+ foreach (k, v; Test2.init) {} // Fails
+
+ auto f1 = Test.init.front(); // Fails
+ auto f2 = Test2.init.front(); // Fails
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20040.d b/gcc/testsuite/gdc.test/fail_compilation/fail20040.d
new file mode 100644
index 0000000..67bdd31
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20040.d
@@ -0,0 +1,16 @@
+/*
+REQUIRED_ARGS: -o-
+TEST_OUTPUT:
+---
+fail_compilation/fail20040.d(13): Error: no property `joiner` for type `string[]`, perhaps `import std.algorithm;` is needed?
+fail_compilation/fail20040.d(14): Error: no property `split` for type `string[]`, perhaps `import std.array;` is needed?
+fail_compilation/fail20040.d(15): Error: no property `startsWith` for type `string[]`, perhaps `import std.algorithm;` is needed?
+---
+*/
+void main()
+{
+ auto x = ["a","b","c"];
+ x.joiner();
+ x.split();
+ x.startsWith;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20073.d b/gcc/testsuite/gdc.test/fail_compilation/fail20073.d
new file mode 100644
index 0000000..01a9ede
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20073.d
@@ -0,0 +1,22 @@
+// https://issues.dlang.org/show_bug.cgi?id=20073
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20073.d(20): Error: cannot implicitly convert expression `s` of type `S` to `string`
+fail_compilation/fail20073.d(21): Error: cannot implicitly convert expression `s` of type `S` to `string`
+---
+*/
+
+struct S
+{
+ char[10] x;
+ auto slice() inout { return x[0 .. 10]; }
+ alias slice this;
+}
+
+
+string test() {
+ S s;
+ string str = s; // cannot implicitly convert expression `s` of type `S` to `string`
+ return s; // and suddenly we can!
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20084.d b/gcc/testsuite/gdc.test/fail_compilation/fail20084.d
new file mode 100644
index 0000000..dcc73a9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20084.d
@@ -0,0 +1,19 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail20084.d(109): Error: returning `v.front()` escapes a reference to local variable `v`
+---
+*/
+
+#line 100
+
+// https://issues.dlang.org/show_bug.cgi?id=20084
+
+struct W() {
+ int value;
+ @safe ref int front() return { return value; }
+}
+
+@safe ref int get(W!() v) {
+ return v.front;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20108.d b/gcc/testsuite/gdc.test/fail_compilation/fail20108.d
new file mode 100644
index 0000000..f768b89
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20108.d
@@ -0,0 +1,31 @@
+// REQUIRED_ARGS: -preview=dip1000
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20108.d(15): Error: address of variable `y` assigned to `x` with longer lifetime
+fail_compilation/fail20108.d(16): Error: scope variable `x` may not be returned
+fail_compilation/fail20108.d(23): Error: address of variable `y` assigned to `x` with longer lifetime
+fail_compilation/fail20108.d(24): Error: scope variable `x` may not be returned
+---
+*/
+
+@safe auto test(scope int* x)
+{
+ int y = 69;
+ x = &y; //bad
+ return x;
+}
+
+@safe auto test2()
+{
+ scope int* x;
+ int y = 69;
+ x = &y; //bad
+ return x;
+}
+
+void main()
+{
+ auto y = test(null);
+ auto z = test2();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20163.d b/gcc/testsuite/gdc.test/fail_compilation/fail20163.d
new file mode 100644
index 0000000..67df48b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20163.d
@@ -0,0 +1,11 @@
+// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/fail20164.d
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20163.d-mixin-11(11): Deprecation: module `imports.fail20164` is deprecated
+---
+*/
+module fail20163;
+
+mixin("import imports.fail20164;");
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20164.d b/gcc/testsuite/gdc.test/fail_compilation/fail20164.d
new file mode 100644
index 0000000..c70947c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20164.d
@@ -0,0 +1,14 @@
+// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/fail20164.d
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20164.d(13): Deprecation: module `imports.fail20164` is deprecated
+---
+*/
+module fail20164;
+
+void foo()
+{
+ import imports.fail20164;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20183.d b/gcc/testsuite/gdc.test/fail_compilation/fail20183.d
new file mode 100644
index 0000000..8a08844
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20183.d
@@ -0,0 +1,47 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail20183.d(1016): Error: function `fail20183.addr(return ref int b)` is not callable using argument types `(int)`
+fail_compilation/fail20183.d(1016): cannot pass rvalue argument `S(0).i` of type `int` to parameter `return ref int b`
+fail_compilation/fail20183.d(1017): Error: address of struct temporary returned by `s()` assigned to longer lived variable `q`
+---
+ */
+
+#line 1000
+
+// https://issues.dlang.org/show_bug.cgi?id=20183
+
+@safe:
+
+int* addr(return ref int b) { return &b; }
+
+struct S
+{
+ int i;
+}
+
+S s() { return S(); }
+
+void test()
+{
+ int* p = addr(S().i); // struct literal
+ int* q = addr(s().i); // struct temporary
+}
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20183.d(1107): Error: address of struct temporary returned by `s()` assigned to longer lived variable `this.ptr`
+---
+ */
+#line 1100
+
+class Foo
+{
+ int* ptr;
+
+ this() @safe
+ {
+ ptr = addr(s().i); // struct literal
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20376.d b/gcc/testsuite/gdc.test/fail_compilation/fail20376.d
new file mode 100644
index 0000000..8410af5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20376.d
@@ -0,0 +1,20 @@
+// https://issues.dlang.org/show_bug.cgi?id=20376
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20376.d(17): Error: cannot implicitly convert expression `Foo()` of type `Foo` to `ubyte`
+---
+*/
+
+struct Foo
+{
+ this(ref scope Foo);
+}
+
+ubyte fun()
+{
+ return Foo();
+}
+
+void main(){}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20448.d b/gcc/testsuite/gdc.test/fail_compilation/fail20448.d
new file mode 100644
index 0000000..6ef3a4a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20448.d
@@ -0,0 +1,23 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20448.d(16): Error: returning `p.x` escapes a reference to local variable `p`
+fail_compilation/fail20448.d(22): Error: template instance `fail20448.member!"x"` error instantiating
+---
+*/
+
+struct S
+{
+ int x, y;
+}
+
+ref int member(string mem)(S p)
+{
+ return p.x;
+}
+
+void main()
+{
+ S p;
+ p.member!"x" = 2;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20461.d b/gcc/testsuite/gdc.test/fail_compilation/fail20461.d
new file mode 100644
index 0000000..77c7178
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20461.d
@@ -0,0 +1,16 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail20461.d(106): Error: reference to local variable `buffer` assigned to non-scope parameter calling `assert()`
+---
+*/
+
+#line 100
+
+// https://issues.dlang.org/show_bug.cgi?id=20461
+
+void test() @safe
+{
+ char[10] buffer = "0123456789";
+ assert(false, buffer[]);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20538.d b/gcc/testsuite/gdc.test/fail_compilation/fail20538.d
new file mode 100644
index 0000000..df7f142e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20538.d
@@ -0,0 +1,14 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20538.d(12): Error: assignment must be preceded by an identifier
+fail_compilation/fail20538.d(12): Error: found `1` when expecting `,`
+---
+*/
+
+enum smth
+{
+ a,
+ = 1,
+ @disable b
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20547.d b/gcc/testsuite/gdc.test/fail_compilation/fail20547.d
new file mode 100644
index 0000000..c14977d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20547.d
@@ -0,0 +1,15 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20547.d(12): Error: cannot create a `string[string]` with `new`
+fail_compilation/fail20547.d(14): Error: cannot create a `string[string]` with `new`
+---
+*/
+
+void main()
+{
+ //https://issues.dlang.org/show_bug.cgi?id=11790
+ string[string] crash = new string[string];
+ //https://issues.dlang.org/show_bug.cgi?id=20547
+ int[string] c = new typeof(crash);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20551.d b/gcc/testsuite/gdc.test/fail_compilation/fail20551.d
new file mode 100644
index 0000000..633be0a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20551.d
@@ -0,0 +1,27 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20551.d(15): Error: cannot take address of lazy parameter `e` in `@safe` function `opAssign`
+fail_compilation/fail20551.d(26): Error: template instance `fail20551.LazyStore!int.LazyStore.opAssign!int` error instantiating
+---
+*/
+
+struct LazyStore(T)
+{
+ T delegate() @safe dg;
+
+ void opAssign(E)(lazy E e) @safe
+ {
+ dg = cast(typeof(dg)) &e;
+ }
+
+ T test() @safe{ return dg(); }
+}
+
+static LazyStore!int f;
+
+void main(string[] args) @safe
+{
+ int x = 1;
+ f = x + x + 20 + x * 20;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20609.d b/gcc/testsuite/gdc.test/fail_compilation/fail20609.d
new file mode 100644
index 0000000..05b7c85
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20609.d
@@ -0,0 +1,45 @@
+/*
+ TEST_OUTPUT:
+ ---
+fail_compilation/fail20609.d(26): Error: none of the overloads of `this` are callable using argument types `(int)`
+fail_compilation/fail20609.d(23): Candidate is: `fail20609.Foo.this(string[] args)`
+fail_compilation/fail20609.d(27): Error: none of the overloads of `this` are callable using argument types `(int)`
+fail_compilation/fail20609.d(22): Candidates are: `fail20609.Foo.this(Object _param_0)`
+fail_compilation/fail20609.d(23): `fail20609.Foo.this(string[] args)`
+fail_compilation/fail20609.d(37): Error: none of the overloads of `this` are callable using argument types `(int)`
+fail_compilation/fail20609.d(37): All possible candidates are marked as `deprecated` or `@disable`
+fail_compilation/fail20609.d(43): Error: undefined identifier `deprecatedTypo_`
+fail_compilation/fail20609.d(44): Error: undefined identifier `deprecatedTypo_`, did you mean function `deprecatedTypo`?
+fail_compilation/fail20609.d(45): Error: undefined identifier `disabledTypo_`
+---
+ */
+
+// Only show `this(string[])` in non-deprecated context.
+// Show both `this(string[])` and ` this(Object)` in deprecated context.
+struct Foo
+{
+ @disable this();
+ deprecated this(Object) {}
+ this(string[] args) {}
+}
+
+void test1() { auto f = Foo(42); }
+deprecated void test2() { auto f = Foo(42); }
+
+// Make sure we do not show a message promising candidates,
+// then no candidates in the special case where nothing
+// would be usable
+struct WhoDoesThat
+{
+ @disable this();
+ deprecated this(Object) {}
+}
+void test3() { auto f = WhoDoesThat(42); }
+
+// Make sure we don't suggest disabled or deprecated functions
+deprecated void deprecatedTypo () {}
+@disable void disabledTypo () {}
+
+void test4 () { deprecatedTypo_("42"); }
+deprecated void test5 () { deprecatedTypo_("42"); }
+void test6 () { disabledTypo_("42"); }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20637.d b/gcc/testsuite/gdc.test/fail_compilation/fail20637.d
new file mode 100644
index 0000000..77c69ea
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20637.d
@@ -0,0 +1,12 @@
+/*
+EXTRA_FILES: imports/fail20637b.d
+TEST_OUTPUT:
+---
+fail_compilation/fail20637.d(12): Error: no property `foo` for type `imports.fail20637b.A`
+---
+*/
+module fail20637;
+
+import imports.fail20637b;
+
+void main() { A.foo; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20638.d b/gcc/testsuite/gdc.test/fail_compilation/fail20638.d
new file mode 100644
index 0000000..9954d37
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20638.d
@@ -0,0 +1,14 @@
+/*
+EXTRA_FILES: imports/fail20638b.d
+TEST_OUTPUT:
+---
+fail_compilation/fail20638.d(13): Error: undefined identifier `foo` in module `imports.fail20638b`
+---
+*/
+module fail20638;
+
+import imports.fail20638b;
+
+void main() {
+ imports.fail20638b.foo;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20658.d b/gcc/testsuite/gdc.test/fail_compilation/fail20658.d
new file mode 100644
index 0000000..fd422aa
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20658.d
@@ -0,0 +1,14 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20658.d(14): Error: field `U.m` cannot modify fields in `@safe` code that overlap fields with other storage classes
+---
+*/
+
+union U
+{
+ int m;
+ immutable int i;
+}
+U u;
+enum e = () @safe { u.m = 13; };
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20691.d b/gcc/testsuite/gdc.test/fail_compilation/fail20691.d
new file mode 100644
index 0000000..7a43232
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20691.d
@@ -0,0 +1,25 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail20691.d(106): Error: cannot take address of `scope` local `sa` in `@safe` function `bar`
+fail_compilation/fail20691.d(106): Error: cannot cast expression `sa` of type `char[][2]` to `char[][]`
+fail_compilation/fail20691.d(107): Error: cannot take address of `scope` local `sa` in `@safe` function `bar`
+fail_compilation/fail20691.d(107): Error: cannot cast expression `sa` of type `char[][2]` to `char[][]`
+fail_compilation/fail20691.d(108): Error: cannot take address of `scope` local `sa` in `@safe` function `bar`
+fail_compilation/fail20691.d(108): Error: cannot cast expression `sa` of type `char[][2]` to `char[][]`
+---
+*/
+
+#line 100
+
+// https://issues.dlang.org/show_bug.cgi?id=20691
+
+void bar() @safe
+{
+ scope char[][2] sa;
+ scope char[][] da = cast(char[][])sa;
+ scope char[][] ca = sa;
+ foo(sa);
+}
+
+void foo(scope char[][] a) @safe;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail207.d b/gcc/testsuite/gdc.test/fail_compilation/fail207.d
index becf49b..2a00f7f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail207.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail207.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/fail207.d(10): Error: found end of file instead of initializer
-fail_compilation/fail207.d(10): Error: semicolon expected, not `EOF`
+fail_compilation/fail207.d(10): Error: semicolon expected, not `End of File`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20714.d b/gcc/testsuite/gdc.test/fail_compilation/fail20714.d
new file mode 100644
index 0000000..6bf6b07
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20714.d
@@ -0,0 +1,32 @@
+// https://issues.dlang.org/show_bug.cgi?id=20714
+// REQUIRED_ARGS: -de
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20714.d(19): Deprecation: `struct Adder` implicitly-generated postblit hides copy constructor.
+fail_compilation/fail20714.d(19): The field postblit will have priority over the copy constructor.
+fail_compilation/fail20714.d(19): To change this, the postblit should be disabled for `struct Adder`
+---
+*/
+
+
+struct Blitter
+{
+ int payload;
+ this(this){}
+}
+
+struct Adder
+{
+ Blitter blitter;
+ this(int payload) {this.blitter.payload = payload;}
+ this(ref Adder rhs) {this.blitter.payload = rhs.blitter.payload + 1;}
+}
+
+void main()
+{
+ Adder piece1 = 1;
+ auto piece2 = piece1;
+
+ assert(piece2.blitter.payload == 2);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20730a.d b/gcc/testsuite/gdc.test/fail_compilation/fail20730a.d
new file mode 100644
index 0000000..dcf8960
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20730a.d
@@ -0,0 +1,39 @@
+/*
+REQUIRED_ARGS: -o-
+TEST_OUTPUT:
+---
+fail_compilation/fail20730a.d(11): Error: undefined identifier `undef20730`
+---
+*/
+void test20730()
+{
+ auto f = File().byLine;
+ undef20730();
+}
+
+struct File
+{
+ shared uint refs;
+
+ this(this)
+ {
+ atomicOp!"+="(refs, 1);
+ }
+
+ struct ByLineImpl(Char)
+ {
+ File file;
+ char[] line;
+ }
+
+ auto byLine()
+ {
+ return ByLineImpl!char();
+ }
+}
+
+T atomicOp(string op, T, V1)(ref shared T val, V1 mod)
+ if (__traits(compiles, mixin("*cast(T*)&val" ~ op ~ "mod")))
+{
+ return val;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d b/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d
new file mode 100644
index 0000000..9320423
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20730b.d
@@ -0,0 +1,46 @@
+/*
+REQUIRED_ARGS: -verrors=spec -o-
+TEST_OUTPUT:
+---
+(spec:1) fail_compilation/fail20730b.d-mixin-43(43): Error: C style cast illegal, use `cast(int)mod`
+fail_compilation/fail20730b.d(26): Error: template `fail20730b.atomicOp` cannot deduce function from argument types `!("+=")(shared(uint), int)`
+fail_compilation/fail20730b.d(41): Candidate is: `atomicOp(string op, T, V1)(shared ref T val, V1 mod)`
+ with `op = "+=",
+ T = uint,
+ V1 = int`
+ must satisfy the following constraint:
+` __traits(compiles, mixin("(int)mod"))`
+---
+*/
+void test20730()
+{
+ auto f = File().byLine;
+}
+
+struct File
+{
+ shared uint refs;
+
+ this(this)
+ {
+ atomicOp!"+="(refs, 1);
+ }
+
+ struct ByLineImpl(Char)
+ {
+ File file;
+ char[] line;
+ }
+
+ auto byLine()
+ {
+ return ByLineImpl!char();
+ }
+}
+
+T atomicOp(string op, T, V1)(ref shared T val, V1 mod)
+ // C-style cast causes raises a parser error whilst gagged.
+ if (__traits(compiles, mixin("(int)mod")))
+{
+ return val;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20771.d b/gcc/testsuite/gdc.test/fail_compilation/fail20771.d
new file mode 100644
index 0000000..18e1c87
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20771.d
@@ -0,0 +1,21 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20771.d(19): Error: cannot pass types with postblits or copy constructors as variadic arguments
+fail_compilation/fail20771.d(20): Error: cannot pass types with postblits or copy constructors as variadic arguments
+---
+*/
+extern void variadic(...);
+
+struct S20771
+{
+ int field;
+ this(this) { }
+}
+
+void test()
+{
+ auto v = S20771(0);
+ variadic(v,
+ S20771(1));
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20772.d b/gcc/testsuite/gdc.test/fail_compilation/fail20772.d
new file mode 100644
index 0000000..a2fdac6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20772.d
@@ -0,0 +1,22 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20772.d(20): Error: cannot pass types with postblits or copy constructors as variadic arguments
+fail_compilation/fail20772.d(21): Error: cannot pass types with postblits or copy constructors as variadic arguments
+---
+*/
+extern void variadic(...);
+
+struct S20772
+{
+ int field;
+ this(int) { }
+ this(ref S20772 o) { }
+}
+
+void test()
+{
+ auto v = S20772(0);
+ variadic(v,
+ S20772(1));
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20775.d b/gcc/testsuite/gdc.test/fail_compilation/fail20775.d
new file mode 100644
index 0000000..3e05096
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20775.d
@@ -0,0 +1,21 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20775.d(19): Error: cannot pass types that need destruction as variadic arguments
+fail_compilation/fail20775.d(20): Error: cannot pass types that need destruction as variadic arguments
+---
+*/
+extern void variadic(...);
+
+struct S20775
+{
+ int field;
+ ~this() { }
+}
+
+void test()
+{
+ auto v = S20775(0);
+ variadic(v,
+ S20775(1));
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20779.d b/gcc/testsuite/gdc.test/fail_compilation/fail20779.d
new file mode 100644
index 0000000..945803d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20779.d
@@ -0,0 +1,17 @@
+// https://issues.dlang.org/show_bug.cgi?id=20779
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20779.d(12): Error: struct `fail20779.X` cannot have field `x` with same struct type
+---
+*/
+
+module fail20779;
+
+struct X
+{
+ X x;
+
+ enum e = __traits(compiles, X.init);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail208.d b/gcc/testsuite/gdc.test/fail_compilation/fail208.d
index 8abcc3e..f81774b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail208.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail208.d
@@ -1,14 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail208.d(18): Error: return expression expected
-fail_compilation/fail208.d(21): called from here: MakeA()
+fail_compilation/fail208.d(18): Error: `return` expression expected
+fail_compilation/fail208.d(21): called from here: `MakeA()`
---
*/
-// Issue 1593 - ICE compiler crash empty return statement in function
-
+// https://issues.dlang.org/show_bug.cgi?id=1593
+// ICE compiler crash empty return statement in function
struct A
{
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20800.d b/gcc/testsuite/gdc.test/fail_compilation/fail20800.d
new file mode 100644
index 0000000..1184b8e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20800.d
@@ -0,0 +1,24 @@
+// https://issues.dlang.org/show_bug.cgi?id=20800
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20800.d(22): Error: function `fail20800.fun(int a)` is not callable using argument types `(string)`
+fail_compilation/fail20800.d(22): cannot pass argument `(m()).index()` of type `string` to parameter `int a`
+---
+*/
+
+struct RegexMatch
+{
+ string index() { return null; }
+ ~this() { }
+}
+static m() { return RegexMatch(); }
+
+void fun(int a);
+
+void initCommands()
+{
+ fun(m.index);
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail209.d b/gcc/testsuite/gdc.test/fail_compilation/fail209.d
index a0211aa..689fd7b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail209.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail209.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail209.d(20): Error: incompatible types for ((a) -= (x)): 'float' and 'fail209.X'
+fail_compilation/fail209.d(20): Error: incompatible types for `(a) -= (x)`: `float` and `fail209.X`
---
*/
-// Issue 725 - expression.c:6516: virtual Expression* MinAssignExp::semantic(Scope*): Assertion `e2->type->isfloating()' failed
-
+// https://issues.dlang.org/show_bug.cgi?id=725
+// expression.c:6516: virtual Expression* MinAssignExp::semantic(Scope*): Assertion `e2->type->isfloating()' failed
class X
{
float a;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20965.d b/gcc/testsuite/gdc.test/fail_compilation/fail20965.d
new file mode 100644
index 0000000..192b84e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20965.d
@@ -0,0 +1,27 @@
+// https://issues.dlang.org/show_bug.cgi?id=20965
+// REQUIRED_ARGS: -de
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail20965.d(17): Deprecation: `struct S` implicitly-generated postblit hides copy constructor.
+fail_compilation/fail20965.d(17): The field postblit will have priority over the copy constructor.
+fail_compilation/fail20965.d(17): To change this, the postblit should be disabled for `struct S`
+---
+*/
+
+struct C
+{
+ this(this) {}
+}
+
+struct S
+{
+ C c;
+ @disable this(ref typeof(this));
+}
+
+void main()
+{
+ S s1;
+ auto s2 = s1; // problem
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21091a.d b/gcc/testsuite/gdc.test/fail_compilation/fail21091a.d
new file mode 100644
index 0000000..74f40c2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21091a.d
@@ -0,0 +1,17 @@
+// https://issues.dlang.org/show_bug.cgi?id=21091
+
+/*
+TEST_OUTPUT:
+----
+fail_compilation/fail21091a.d(15): Error: module `Ternary` is in file 'Ternary.d' which cannot be read
+import path[0] = fail_compilation
+import path[1] = $p:druntime/import$
+import path[2] = $p:phobos$
+----
+*/
+
+struct NullAllocator
+{
+ import Ternary;
+ Ternary owns() { }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21091b.d b/gcc/testsuite/gdc.test/fail_compilation/fail21091b.d
new file mode 100644
index 0000000..d9467aa
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21091b.d
@@ -0,0 +1,17 @@
+// https://issues.dlang.org/show_bug.cgi?id=21091
+
+/*
+TEST_OUTPUT:
+----
+fail_compilation/fail21091b.d(15): Error: module `Tid` is in file 'Tid.d' which cannot be read
+import path[0] = fail_compilation
+import path[1] = $p:druntime/import$
+import path[2] = $p:phobos$
+----
+*/
+
+class Logger
+{
+ import Tid;
+ Tid threadId;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21092.d b/gcc/testsuite/gdc.test/fail_compilation/fail21092.d
new file mode 100644
index 0000000..2ca826e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21092.d
@@ -0,0 +1,27 @@
+// https://issues.dlang.org/show_bug.cgi?id=21092
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail21092.d(19): Error: Using the result of a comma expression is not allowed
+fail_compilation/fail21092.d(19): Error: using `*` on an array is no longer supported; use `*(T , U).ptr` instead
+fail_compilation/fail21092.d(19): Error: `*(T , cast(real*)U)` has no effect
+fail_compilation/fail21092.d(26): Error: Using the result of a comma expression is not allowed
+fail_compilation/fail21092.d(26): Error: using `*` on an array is no longer supported; use `*(w , SmallStirlingCoeffs).ptr` instead
+fail_compilation/fail21092.d(26): Error: `*(w , cast(real*)SmallStirlingCoeffs)` has no effect
+---
+*/
+
+real[] T;
+real[] U = [];
+real erf()
+{
+ *(T, U);
+}
+
+real gammaStirling()
+{
+ static real[] SmallStirlingCoeffs = [];
+ real w;
+ *(w, SmallStirlingCoeffs);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail212.d b/gcc/testsuite/gdc.test/fail_compilation/fail212.d
index 63c573e..5f30863 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail212.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail212.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail212.d(14): Error: function fail212.S.bar without 'this' cannot be const
+fail_compilation/fail212.d(14): Error: function `fail212.S.bar` without `this` cannot be `const`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21275.d b/gcc/testsuite/gdc.test/fail_compilation/fail21275.d
new file mode 100644
index 0000000..dbdedb3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21275.d
@@ -0,0 +1,22 @@
+// https://issues.dlang.org/show_bug.cgi?id=21275
+// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/fail21275a.d
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail21275.d(18): Deprecation: Function `imports.fail21275a.Foo.x` of type `ref int() return` is not accessible from module `fail21275`
+fail_compilation/fail21275.d(21): Deprecation: Function `imports.fail21275a.Bar.x` of type `int(int)` is not accessible from module `fail21275`
+---
+*/
+
+void main()
+{
+ import imports.fail21275a;
+
+ auto f = Foo();
+ f.x = 3;
+
+ auto b = Bar();
+ b.x = 3;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail213.d b/gcc/testsuite/gdc.test/fail_compilation/fail213.d
index d002382..fee91ec 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail213.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail213.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail213.d(18): Error: template instance Foo!int does not match template declaration Foo(T : immutable(T))
-fail_compilation/fail213.d(25): Error: template instance Foo!(const(int)) does not match template declaration Foo(T : immutable(T))
+fail_compilation/fail213.d(18): Error: template instance `Foo!int` does not match template declaration `Foo(T : immutable(T))`
+fail_compilation/fail213.d(25): Error: template instance `Foo!(const(int))` does not match template declaration `Foo(T : immutable(T))`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail215.d b/gcc/testsuite/gdc.test/fail_compilation/fail215.d
index f942723..292f071 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail215.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail215.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail215.d(10): Error: function fail215.b.k cannot be both final and abstract
+fail_compilation/fail215.d(10): Error: function `fail215.b.k` cannot be both `final` and `abstract`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21508.d b/gcc/testsuite/gdc.test/fail_compilation/fail21508.d
new file mode 100644
index 0000000..da5d8f9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21508.d
@@ -0,0 +1,18 @@
+/*
+REQUIRED_ARGS: -Ifail_compilation/imports/
+EXTRA_FILES: imports/import21508.d
+TEST_OUTPUT:
+---
+fail_compilation/fail21508.d(17): Error: import `fail21508.import21508` is used as a type
+---
+*/
+import import21508;
+
+// import21508 is a private class, code should not compile
+// The compiler used to "helpfully" look inside the import,
+// bypassing the shadowing that this introduces.
+
+void main ()
+{
+ auto c = new import21508();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21508_2.d b/gcc/testsuite/gdc.test/fail_compilation/fail21508_2.d
new file mode 100644
index 0000000..af986b7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21508_2.d
@@ -0,0 +1,11 @@
+/*
+REQUIRED_ARGS: -Ifail_compilation/imports/
+EXTRA_FILES: imports/import21508.d
+TEST_OUTPUT:
+---
+fail_compilation/fail21508_2.d(11): Error: import `fail21508_2.import21508` is used as a type
+---
+*/
+import import21508;
+
+class Other : import21508 { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21547.d b/gcc/testsuite/gdc.test/fail_compilation/fail21547.d
new file mode 100644
index 0000000..7a6a44a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21547.d
@@ -0,0 +1,34 @@
+// https://issues.dlang.org/show_bug.cgi?id=21547
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail21547.d(32): Error: struct `Bar` has constructors, cannot use `{ initializers }`, use `Bar( initializers )` instead
+fail_compilation/fail21547.d(33): Error: struct `Bar1` has constructors, cannot use `{ initializers }`, use `Bar1( initializers )` instead
+---
+*/
+
+struct Bar
+{
+ @disable this(int a) {}
+ this(int a, int b) {}
+
+ string a;
+ uint b;
+}
+
+struct Bar1
+{
+ @disable this(int a) {}
+ this(const ref Bar1 o) {}
+ this(int a, int b) {}
+
+ string a;
+ uint b;
+}
+
+void main ()
+{
+ Bar b = { a: "Hello", b: 42 };
+ Bar1 b1 = { a: "Hello", b: 42 };
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail216.d b/gcc/testsuite/gdc.test/fail_compilation/fail216.d
index 98dcbb8..eb736e6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail216.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail216.d
@@ -1,14 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail216.d(16): Error: expression foo() is void and has no value
-fail_compilation/fail216.d(14): Error: function fail216.bar has no return statement, but is expected to return a value of type int
-fail_compilation/fail216.d(19): called from here: bar()
+fail_compilation/fail216.d(16): Error: expression `foo()` is `void` and has no value
+fail_compilation/fail216.d(14): Error: function `fail216.bar` has no `return` statement, but is expected to return a value of type `int`
+fail_compilation/fail216.d(19): called from here: `bar()`
---
*/
-// Issue 1744 - CTFE: crash on assigning void-returning function to variable
-
+// https://issues.dlang.org/show_bug.cgi?id=1744
+// CTFE: crash on assigning void-returning function to variable
void foo() {}
int bar()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail218.d b/gcc/testsuite/gdc.test/fail_compilation/fail218.d
index e180e77..a468611 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail218.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail218.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail218.d(15): Error: cannot modify string literal ", "
+fail_compilation/fail218.d(15): Error: cannot modify string literal `", "`
---
*/
-// Issue 1788 - dmd segfaults without info
-
+// https://issues.dlang.org/show_bug.cgi?id=1788
+// dmd segfaults without info
void main()
{
string a = "abc";
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21830.d b/gcc/testsuite/gdc.test/fail_compilation/fail21830.d
new file mode 100644
index 0000000..9955c65
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21830.d
@@ -0,0 +1,34 @@
+/* REQUIRED_ARGS: -de -unittest
+TEST_OUTPUT
+---
+fail_compilation/fail21830.d(24): Deprecation: struct `fail21830.OldS21830` is deprecated - Deprecated type
+fail_compilation/fail21830.d(24): Deprecation: template `fail21830.test21830(T)(T t) if (is(T == OldS21830))` is deprecated - Deprecated template
+fail_compilation/fail21830.d(24): Deprecation: struct `fail21830.OldS21830` is deprecated - Deprecated type
+---
+*/
+#line 1
+deprecated("Deprecated type")
+struct OldS21830 { }
+
+struct NewS21830 { }
+
+static if (1)
+{
+ auto test21830(T)(T t)
+ if (is(T == NewS21830))
+ {
+ return T.init;
+ }
+}
+
+deprecated("Deprecated template")
+auto test21830(T)(T t)
+if (is(T == OldS21830))
+{
+ return T.init;
+}
+
+unittest
+{
+ auto b = test21830(OldS21830());
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21831.d b/gcc/testsuite/gdc.test/fail_compilation/fail21831.d
new file mode 100644
index 0000000..699ef0b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21831.d
@@ -0,0 +1,29 @@
+/* REQUIRED_ARGS: -de -unittest
+TEST_OUTPUT
+---
+fail_compilation/fail21831.d(19): Deprecation: struct `fail21831.S21831` is deprecated - Deprecated type
+fail_compilation/fail21831.d(19): Deprecation: template `fail21831.test21831(T)(T t) if (__traits(isDeprecated, T))` is deprecated - Deprecated template
+fail_compilation/fail21831.d(19): Deprecation: struct `fail21831.S21831` is deprecated - Deprecated type
+---
+*/
+#line 1
+deprecated("Deprecated type")
+struct S21831 { }
+
+auto test21831(T)(T t)
+if (!__traits(isDeprecated, T))
+{
+ return T.init;
+}
+
+deprecated("Deprecated template")
+auto test21831(T)(T t)
+if (__traits(isDeprecated, T))
+{
+ return T.init;
+}
+
+unittest
+{
+ auto b = test21831(S21831());
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21832.d b/gcc/testsuite/gdc.test/fail_compilation/fail21832.d
new file mode 100644
index 0000000..03753a4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21832.d
@@ -0,0 +1,21 @@
+// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/imp21832.d
+/*
+TEST_OUTPUT
+---
+fail_compilation/fail21832.d(4): Deprecation: function `imports.imp21832.fun` is deprecated
+fail_compilation/fail21832.d(10): Deprecation: template `imports.imp21832.tpl()(char a)` is deprecated
+---
+*/
+#line 1
+int test21832a()
+{
+ import imports.imp21832 : fun;
+ return fun('a');
+}
+
+int test21832b()
+{
+ import imports.imp21832 : tpl;
+ return tpl('a');
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21849.d b/gcc/testsuite/gdc.test/fail_compilation/fail21849.d
new file mode 100644
index 0000000..75821f6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21849.d
@@ -0,0 +1,36 @@
+// https://issues.dlang.org/show_bug.cgi?id=21849
+// REQUIRED_ARGS: -verrors=context -vcolumns
+/* TEST_OUTPUT:
+---
+fail_compilation/fail21849.d(21,17): Error: cannot implicitly convert expression `1` of type `int` to `string`
+ string ß = 1;
+ ^
+fail_compilation/fail21849.d(25,42): Error: cannot implicitly convert expression `cast(ushort)65535u` of type `ushort` to `byte`
+ string s = "ß☺-oneline"; byte S = ushort.max;
+ ^
+fail_compilation/fail21849.d(30,10): Error: undefined identifier `undefined_identifier`
+ß-utf"; undefined_identifier;
+ ^
+fail_compilation/fail21849.d(35,15): Error: `s[0..9]` has no effect
+☺-smiley"; s[0 .. 9];
+ ^
+---
+*/
+void fail21849a()
+{
+ string ß = 1;
+}
+void fail21849b()
+{
+ string s = "ß☺-oneline"; byte S = ushort.max;
+}
+void fail21849c()
+{
+ string s = "
+ß-utf"; undefined_identifier;
+}
+void fail21849d()
+{
+ string s = "
+☺-smiley"; s[0 .. 9];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21868b.d b/gcc/testsuite/gdc.test/fail_compilation/fail21868b.d
new file mode 100644
index 0000000..6f34029
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21868b.d
@@ -0,0 +1,22 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail21868b.d(19): Error: returning `&s.x` escapes a reference to parameter `s`
+fail_compilation/fail21868b.d(19): perhaps remove `scope` parameter annotation so `return` applies to `ref`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=21868
+
+struct S
+{
+ int x;
+ int* y;
+}
+
+int* test(ref return scope S s)
+{
+ return &s.x;
+}
+
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21885.d b/gcc/testsuite/gdc.test/fail_compilation/fail21885.d
new file mode 100644
index 0000000..4052efd
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21885.d
@@ -0,0 +1,25 @@
+// https://issues.dlang.org/show_bug.cgi?id=21885
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail21885.d(24): Error: struct `fail21885.Outer` is not copyable because field `i` is not copyable
+---
+*/
+
+struct Outer
+{
+ Inner i;
+}
+
+struct Inner
+{
+ @disable this(this);
+}
+
+void main()
+{
+ Outer o1;
+ Outer o2;
+ o1 = o2;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21928.d b/gcc/testsuite/gdc.test/fail_compilation/fail21928.d
new file mode 100644
index 0000000..c9fac13
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21928.d
@@ -0,0 +1,19 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail21928.d(18): Error: array literal in `@nogc` function `D main` may cause a GC allocation
+---
+*/
+
+@nogc:
+
+
+struct Shape
+{
+ immutable size_t[] dims = [];
+}
+
+void main()
+{
+ auto s = Shape(2 ~ Shape.init.dims);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21928b.d b/gcc/testsuite/gdc.test/fail_compilation/fail21928b.d
new file mode 100644
index 0000000..3ce93e0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21928b.d
@@ -0,0 +1,19 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail21928b.d(18): Error: array literal in `@nogc` function `D main` may cause a GC allocation
+---
+*/
+
+@nogc:
+
+
+struct Shape
+{
+ immutable size_t[] dims = [];
+}
+
+void main()
+{
+ auto s = Shape(Shape.init.dims ~ 2);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2195.d b/gcc/testsuite/gdc.test/fail_compilation/fail2195.d
index b6d5304..0eff066 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail2195.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail2195.d
@@ -16,3 +16,19 @@ void main()
int variable; // shadowing is disallowed but not detected
}
}
+
+void fun()
+{
+ int var1, var2, var3;
+
+ void gun()
+ {
+ int var1; // OK?
+
+ int[] arr;
+ foreach (i, var2; arr) {} // OK?
+
+ int[int] aa;
+ foreach (k, var3; aa) {} // Not OK??
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22035.d b/gcc/testsuite/gdc.test/fail_compilation/fail22035.d
new file mode 100644
index 0000000..ba03be6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22035.d
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=22035
+/* TEST_OUTPUT
+---
+fail_compilation/fail22035.d(10): Error: found `2` when expecting `:`
+fail_compilation/fail22035.d(10): Error: found `:` instead of statement
+---
+*/
+int test22035()
+{
+ case 1 2:
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22054.d b/gcc/testsuite/gdc.test/fail_compilation/fail22054.d
new file mode 100644
index 0000000..c172f08
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22054.d
@@ -0,0 +1,23 @@
+// https://issues.dlang.org/show_bug.cgi?id=22054
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22054.d(21): Error: no property `what` for type `fail22054.exception`
+fail_compilation/fail22054.d(16): `class fail22054.exception` is opaque and has no members.
+fail_compilation/fail22054.d(22): Error: no property `what` for type `fail22054.exception2`
+fail_compilation/fail22054.d(17): `struct fail22054.exception2` is opaque and has no members.
+---
+*/
+
+
+
+
+class exception;
+struct exception2;
+
+void main ()
+{
+ assert(exception.what() == "Hello");
+ assert(exception2.what() == "Hello");
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22075.d b/gcc/testsuite/gdc.test/fail_compilation/fail22075.d
new file mode 100644
index 0000000..9b857c2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22075.d
@@ -0,0 +1,30 @@
+// https://issues.dlang.org/show_bug.cgi?id=22075
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22075.d(25): Error: AA key type `S` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined
+fail_compilation/fail22075.d(26): Error: AA key type `S` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined
+---
+*/
+
+struct HasAliasThis { int a; alias a this; }
+
+struct LacksAliasThis { int a; }
+
+struct S(T)
+{
+ private T a;
+
+ bool opEquals(const S rhs) const @nogc nothrow @safe
+ {
+ return rhs is this;
+ }
+}
+
+int[S!HasAliasThis] aa1; // Compiles but should not.
+int[S!LacksAliasThis] aa2; // Correctly fails to compile with "Error: AA key
+ // type `S` should have `extern (D) size_t toHash() const nothrow @safe`
+ // if `opEquals` defined"".
+
+void main() {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22084.d b/gcc/testsuite/gdc.test/fail_compilation/fail22084.d
new file mode 100644
index 0000000..02fff2f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22084.d
@@ -0,0 +1,23 @@
+// https://issues.dlang.org/show_bug.cgi?id=22084
+/*
+TEST_OUTPUT
+---
+fail_compilation/fail22084.d(22): Error: cannot pass types that need destruction as variadic arguments
+---
+*/
+import core.stdc.stdarg;
+
+extern(C++) void testVariadic(int a, ...)
+{
+}
+
+struct Destructor
+{
+ ~this() { }
+}
+
+void test()
+{
+ auto a0 = Destructor;
+ testVariadic(1, a0);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail221.d b/gcc/testsuite/gdc.test/fail_compilation/fail221.d
index 9bada5b..14c3e7b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail221.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail221.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail221.d(11): Error: expression cast(void)0 is void and has no value
+fail_compilation/fail221.d(11): Error: expression `cast(void)0` is `void` and has no value
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22118.d b/gcc/testsuite/gdc.test/fail_compilation/fail22118.d
new file mode 100644
index 0000000..7408661
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22118.d
@@ -0,0 +1,36 @@
+// https://issues.dlang.org/show_bug.cgi?id=22118
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22118.d(33): Error: cannot modify `this.v.a` in `const` function
+---
+*/
+
+struct NeedsInit
+{
+ int n;
+ @disable this();
+}
+
+union U
+{
+ NeedsInit a;
+}
+
+struct V
+{
+ NeedsInit a;
+}
+
+struct S
+{
+ U u;
+ V v;
+ this(const NeedsInit arg) const
+ {
+ u.a = arg; // this should compile
+ v.a = arg; // this should not
+ }
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22121.d b/gcc/testsuite/gdc.test/fail_compilation/fail22121.d
new file mode 100644
index 0000000..f45cf12
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22121.d
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=22121
+// EXTRA_FILES: fail22121/imports/test22121/package.d
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22121/imports/test22121/package.d(1): Error: package name 'fail22121' conflicts with usage as a module name in file fail_compilation/fail22121.d
+---
+*/
+
+module fail22121;
+import fail22121.imports.test22121;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22121/imports/test22121/package.d b/gcc/testsuite/gdc.test/fail_compilation/fail22121/imports/test22121/package.d
new file mode 100644
index 0000000..9277fab
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22121/imports/test22121/package.d
@@ -0,0 +1 @@
+module fail22121.imports.test22121;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22138.d b/gcc/testsuite/gdc.test/fail_compilation/fail22138.d
new file mode 100644
index 0000000..4fee96f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22138.d
@@ -0,0 +1,21 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail22138.d(107): Error: scope variable `e` may not be returned
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=22138
+
+#line 100
+
+@safe
+int* test()
+{
+ int*[] a;
+ foreach (scope e; a)
+ {
+ return e;
+ }
+ return null;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22157.d b/gcc/testsuite/gdc.test/fail_compilation/fail22157.d
new file mode 100644
index 0000000..d25aaad
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22157.d
@@ -0,0 +1,34 @@
+// https://issues.dlang.org/show_bug.cgi?id=22157
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22157.d(32): Error: `fail22157.S!true.S.foo` called with argument types `()` matches both:
+fail_compilation/fail22157.d(21): `fail22157.S!true.S.foo()`
+and:
+fail_compilation/fail22157.d(22): `fail22157.S!true.S.foo()`
+fail_compilation/fail22157.d(33): Error: `fail22157.S!false.S.foo` called with argument types `()` matches both:
+fail_compilation/fail22157.d(26): `fail22157.S!false.S.foo()`
+and:
+fail_compilation/fail22157.d(27): `fail22157.S!false.S.foo()`
+---
+*/
+
+struct S(bool b)
+{
+ static if(b)
+ {
+ void foo() {}
+ static void foo() {}
+ }
+ else
+ {
+ static void foo() {}
+ void foo() {}
+ }
+}
+
+void main() {
+ S!true.foo;
+ S!false.foo;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail222.d b/gcc/testsuite/gdc.test/fail_compilation/fail222.d
index c377239..30eb014 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail222.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail222.d
@@ -1,9 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail222.d(10): Error: template fail222.getMixin(TArg..., int i = 0)() template tuple parameter must be last one
-fail_compilation/fail222.d(17): Error: template instance getMixin!() does not match template declaration getMixin(TArg..., int i = 0)()
-fail_compilation/fail222.d(20): Error: template instance fail222.Thing!() error instantiating
+fail_compilation/fail222.d(11): Error: template `fail222.getMixin(TArg..., int i = 0)()` template tuple parameter must be last one
+fail_compilation/fail222.d(18): Error: template instance `getMixin!()` does not match template declaration `getMixin(TArg..., int i = 0)()`
+fail_compilation/fail222.d(21): Error: template instance `fail222.Thing!()` error instantiating
+fail_compilation/fail222.d(23): Error: template `fail222.fooBar(A..., B...)()` template tuple parameter must be last one
---
*/
@@ -18,3 +19,5 @@ class Thing(TArg...)
}
public Thing!() stuff;
+
+void fooBar (A..., B...)() {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail223.d b/gcc/testsuite/gdc.test/fail_compilation/fail223.d
index 99e26ea..804b535 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail223.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail223.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail223.d(14): Error: cannot modify this.x in const function
+fail_compilation/fail223.d(14): Error: cannot modify `this.x` in `const` function
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail224.d b/gcc/testsuite/gdc.test/fail_compilation/fail224.d
index 4bde370..c52cb431 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail224.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail224.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail224.d(22): Error: need 'this' of type A to access member x from static function f
+fail_compilation/fail224.d(22): Error: need `this` of type `A` to access member `x` from static function `f`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail229.d b/gcc/testsuite/gdc.test/fail_compilation/fail229.d
index 6cf8676..5b42cca 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail229.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail229.d
@@ -6,6 +6,6 @@ fail_compilation/fail229.d(11): Error: array dimension overflow
---
*/
-// Issue 1936 - Error with no line number (array dimension overflow)
-
+// https://issues.dlang.org/show_bug.cgi?id=1936
+// Error with no line number (array dimension overflow)
static int[] x = [-1: 1];
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23.d b/gcc/testsuite/gdc.test/fail_compilation/fail23.d
index 29e8ed4..67d02eb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail23.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail23.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail23.d(14): Error: break is not inside a loop or switch
+fail_compilation/fail23.d(14): Error: `break` is not inside a loop or `switch`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail231.d b/gcc/testsuite/gdc.test/fail_compilation/fail231.d
index 95f25ee..fc6cfa1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail231.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail231.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail231.d(15): Error: class fail231.Derived cannot implicitly generate a default ctor when base class fail231.Base is missing a default ctor
+fail_compilation/fail231.d(15): Error: class `fail231.Derived` cannot implicitly generate a default constructor when base class `fail231.Base` is missing a default constructor
---
*/
-// Issue 951 - Missing line number: no constructor provided for a class derived from a class with no default constructor
-
+// https://issues.dlang.org/show_bug.cgi?id=951
+// Missing line number: no constructor provided for a class derived from a class with no default constructor
class Base
{
this(int x) {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail233.d b/gcc/testsuite/gdc.test/fail_compilation/fail233.d
index e2274ab..7d4d978 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail233.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail233.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail233.d(11): Error: variable fail233.bug1176.v void[1] does not have a default initializer
+fail_compilation/fail233.d(11): Error: variable `fail233.bug1176.v` `void[1]` does not have a default initializer
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail235.d b/gcc/testsuite/gdc.test/fail_compilation/fail235.d
index d0d9deb..47f302d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail235.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail235.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail235.d(12): Error: expression typeid(char) is not a valid template value argument
+fail_compilation/fail235.d(12): Error: expression `typeid(char)` is not a valid template value argument
---
*/
template Tuple(TPL...)
@@ -14,7 +14,7 @@ auto K = Tuple!(typeid(char));
/*
TEST_OUTPUT:
---
-fail_compilation/fail235.d(24): Error: expression typeid(char) is not a valid template value argument
+fail_compilation/fail235.d(24): Error: expression `typeid(char)` is not a valid template value argument
---
*/
template Alias(alias A)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail236.d b/gcc/testsuite/gdc.test/fail_compilation/fail236.d
index 255a881..f63eb21 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail236.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail236.d
@@ -2,13 +2,13 @@
TEST_OUTPUT:
---
fail_compilation/fail236.d(14): Error: undefined identifier `x`
-fail_compilation/fail236.d(22): Error: template fail236.Templ2 cannot deduce function from argument types !()(int), candidates are:
-fail_compilation/fail236.d(12): fail236.Templ2(alias a)(x)
+fail_compilation/fail236.d(22): Error: template `fail236.Templ2` cannot deduce function from argument types `!()(int)`
+fail_compilation/fail236.d(12): Candidate is: `Templ2(alias a)(x)`
---
*/
-// Issue 870 - contradictory error messages for templates
-
+// https://issues.dlang.org/show_bug.cgi?id=870
+// contradictory error messages for templates
template Templ2(alias a)
{
void Templ2(x)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2361.d b/gcc/testsuite/gdc.test/fail_compilation/fail2361.d
index 7cc402e..a969495 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail2361.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail2361.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail2361.d(13): Error: cannot modify immutable expression c
+fail_compilation/fail2361.d(14): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail2361.d(14): Error: cannot modify `immutable` expression `c`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail237.d b/gcc/testsuite/gdc.test/fail_compilation/fail237.d
index 09ca94c..c930051 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail237.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail237.d
@@ -6,6 +6,6 @@ fail_compilation/fail237.d(11): while evaluating: `static assert(module f
---
*/
-// Issue 581 - Error message w/o line number in dot-instantiated template
-
+// https://issues.dlang.org/show_bug.cgi?id=581
+// Error message w/o line number in dot-instantiated template
static assert(.a!().b);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d b/gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d
index a312dc0..b4cfbc9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail238_m32.d
@@ -10,8 +10,8 @@ fail_compilation/fail238_m32.d(35): while evaluating `pragma(msg, M!(q))`
---
*/
-// Issue 581 - Error message w/o line number in dot-instantiated template
-
+// https://issues.dlang.org/show_bug.cgi?id=581
+// Error message w/o line number in dot-instantiated template
template X(){}
template D(string str){}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d b/gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d
index dc7a50e..10e1da4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail238_m64.d
@@ -10,8 +10,8 @@ fail_compilation/fail238_m64.d(35): while evaluating `pragma(msg, M!(q))`
---
*/
-// Issue 581 - Error message w/o line number in dot-instantiated template
-
+// https://issues.dlang.org/show_bug.cgi?id=581
+// Error message w/o line number in dot-instantiated template
template X(){}
template D(string str){}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24.d b/gcc/testsuite/gdc.test/fail_compilation/fail24.d
index 84cf8e1..3b30175 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail24.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail24.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail24.d(11): Error: alias fail24.strtype conflicts with alias fail24.strtype at fail_compilation/fail24.d(10)
-fail_compilation/fail24.d(12): Error: alias fail24.strtype conflicts with alias fail24.strtype at fail_compilation/fail24.d(11)
-fail_compilation/fail24.d(13): Error: alias fail24.strtype conflicts with alias fail24.strtype at fail_compilation/fail24.d(12)
+fail_compilation/fail24.d(11): Error: alias `fail24.strtype` conflicts with alias `fail24.strtype` at fail_compilation/fail24.d(10)
+fail_compilation/fail24.d(12): Error: alias `fail24.strtype` conflicts with alias `fail24.strtype` at fail_compilation/fail24.d(11)
+fail_compilation/fail24.d(13): Error: alias `fail24.strtype` conflicts with alias `fail24.strtype` at fail_compilation/fail24.d(12)
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail240.d b/gcc/testsuite/gdc.test/fail_compilation/fail240.d
index 8a06b434..e32768a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail240.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail240.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail240.d(9): Error: type F is not an expression
+fail_compilation/fail240.d(9): Error: type `F` is not an expression
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail241.d b/gcc/testsuite/gdc.test/fail_compilation/fail241.d
index 97cad21..babd193 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail241.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail241.d
@@ -1,8 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail241.d(16): Error: mutable method fail241.Foo.f is not callable using a const object
-fail_compilation/fail241.d(17): Error: mutable method fail241.Foo.g is not callable using a const object
+fail_compilation/fail241.d(18): Error: mutable method `fail241.Foo.f` is not callable using a `const` object
+fail_compilation/fail241.d(13): Consider adding `const` or `inout` here
+fail_compilation/fail241.d(19): Error: mutable method `fail241.Foo.g` is not callable using a `const` object
+fail_compilation/fail241.d(14): Consider adding `const` or `inout` here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail243.d b/gcc/testsuite/gdc.test/fail_compilation/fail243.d
index c8970ba..d9852ff 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail243.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail243.d
@@ -2,11 +2,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail243.d(23): Deprecation: class fail243.DepClass is deprecated
-fail_compilation/fail243.d(24): Deprecation: struct fail243.DepStruct is deprecated
-fail_compilation/fail243.d(25): Deprecation: union fail243.DepUnion is deprecated
-fail_compilation/fail243.d(26): Deprecation: enum fail243.DepEnum is deprecated
-fail_compilation/fail243.d(27): Deprecation: alias fail243.DepAlias is deprecated
+fail_compilation/fail243.d(23): Deprecation: class `fail243.DepClass` is deprecated
+fail_compilation/fail243.d(24): Deprecation: struct `fail243.DepStruct` is deprecated
+fail_compilation/fail243.d(25): Deprecation: union `fail243.DepUnion` is deprecated
+fail_compilation/fail243.d(26): Deprecation: enum `fail243.DepEnum` is deprecated
+fail_compilation/fail243.d(27): Deprecation: alias `fail243.DepAlias` is deprecated
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail244.d b/gcc/testsuite/gdc.test/fail_compilation/fail244.d
index d688e9a..757eb2b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail244.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail244.d
@@ -2,16 +2,16 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail244.d(27): Deprecation: variable fail244.StructWithDeps.value is deprecated
-fail_compilation/fail244.d(28): Deprecation: variable fail244.StructWithDeps.value is deprecated
-fail_compilation/fail244.d(29): Deprecation: variable fail244.StructWithDeps.value is deprecated
-fail_compilation/fail244.d(30): Deprecation: variable fail244.StructWithDeps.value is deprecated
-fail_compilation/fail244.d(32): Deprecation: variable fail244.StructWithDeps.staticValue is deprecated
-fail_compilation/fail244.d(33): Deprecation: variable fail244.StructWithDeps.staticValue is deprecated
-fail_compilation/fail244.d(34): Deprecation: variable fail244.StructWithDeps.staticValue is deprecated
-fail_compilation/fail244.d(35): Deprecation: variable fail244.StructWithDeps.staticValue is deprecated
-fail_compilation/fail244.d(36): Deprecation: variable fail244.StructWithDeps.staticValue is deprecated
-fail_compilation/fail244.d(37): Deprecation: variable fail244.StructWithDeps.staticValue is deprecated
+fail_compilation/fail244.d(27): Deprecation: variable `fail244.StructWithDeps.value` is deprecated
+fail_compilation/fail244.d(28): Deprecation: variable `fail244.StructWithDeps.value` is deprecated
+fail_compilation/fail244.d(29): Deprecation: variable `fail244.StructWithDeps.value` is deprecated
+fail_compilation/fail244.d(30): Deprecation: variable `fail244.StructWithDeps.value` is deprecated
+fail_compilation/fail244.d(32): Deprecation: variable `fail244.StructWithDeps.staticValue` is deprecated
+fail_compilation/fail244.d(33): Deprecation: variable `fail244.StructWithDeps.staticValue` is deprecated
+fail_compilation/fail244.d(34): Deprecation: variable `fail244.StructWithDeps.staticValue` is deprecated
+fail_compilation/fail244.d(35): Deprecation: variable `fail244.StructWithDeps.staticValue` is deprecated
+fail_compilation/fail244.d(36): Deprecation: variable `fail244.StructWithDeps.staticValue` is deprecated
+fail_compilation/fail244.d(37): Deprecation: variable `fail244.StructWithDeps.staticValue` is deprecated
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail245.d b/gcc/testsuite/gdc.test/fail_compilation/fail245.d
index 79e663d..927f941 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail245.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail245.d
@@ -2,16 +2,16 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail245.d(27): Deprecation: variable fail245.ClassWithDeps.value is deprecated
-fail_compilation/fail245.d(28): Deprecation: variable fail245.ClassWithDeps.value is deprecated
-fail_compilation/fail245.d(29): Deprecation: variable fail245.ClassWithDeps.value is deprecated
-fail_compilation/fail245.d(30): Deprecation: variable fail245.ClassWithDeps.value is deprecated
-fail_compilation/fail245.d(32): Deprecation: variable fail245.ClassWithDeps.staticValue is deprecated
-fail_compilation/fail245.d(33): Deprecation: variable fail245.ClassWithDeps.staticValue is deprecated
-fail_compilation/fail245.d(34): Deprecation: variable fail245.ClassWithDeps.staticValue is deprecated
-fail_compilation/fail245.d(35): Deprecation: variable fail245.ClassWithDeps.staticValue is deprecated
-fail_compilation/fail245.d(36): Deprecation: variable fail245.ClassWithDeps.staticValue is deprecated
-fail_compilation/fail245.d(37): Deprecation: variable fail245.ClassWithDeps.staticValue is deprecated
+fail_compilation/fail245.d(27): Deprecation: variable `fail245.ClassWithDeps.value` is deprecated
+fail_compilation/fail245.d(28): Deprecation: variable `fail245.ClassWithDeps.value` is deprecated
+fail_compilation/fail245.d(29): Deprecation: variable `fail245.ClassWithDeps.value` is deprecated
+fail_compilation/fail245.d(30): Deprecation: variable `fail245.ClassWithDeps.value` is deprecated
+fail_compilation/fail245.d(32): Deprecation: variable `fail245.ClassWithDeps.staticValue` is deprecated
+fail_compilation/fail245.d(33): Deprecation: variable `fail245.ClassWithDeps.staticValue` is deprecated
+fail_compilation/fail245.d(34): Deprecation: variable `fail245.ClassWithDeps.staticValue` is deprecated
+fail_compilation/fail245.d(35): Deprecation: variable `fail245.ClassWithDeps.staticValue` is deprecated
+fail_compilation/fail245.d(36): Deprecation: variable `fail245.ClassWithDeps.staticValue` is deprecated
+fail_compilation/fail245.d(37): Deprecation: variable `fail245.ClassWithDeps.staticValue` is deprecated
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2450.d b/gcc/testsuite/gdc.test/fail_compilation/fail2450.d
new file mode 100644
index 0000000..82118d5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail2450.d
@@ -0,0 +1,27 @@
+// https://issues.dlang.org/show_bug.cgi?id=2450
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail2450.d(22): Error: function expected before `()`, not `this.mixin Event!() clicked;
+` of type `void`
+fail_compilation/fail2450.d(25): Error: function expected before `()`, not `b.mixin Event!() clicked;
+` of type `void`
+---
+*/
+
+template Event()
+{
+ void opCall() { }
+ void opAddAssign(int i) { }
+}
+class Button {
+ mixin Event clicked;
+ void func()
+ {
+ clicked.opCall(); // works
+ this.clicked(); // works
+
+ auto b = new Button();
+ b.clicked(); // works
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2456.d b/gcc/testsuite/gdc.test/fail_compilation/fail2456.d
index e8cf5ab..08e11da 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail2456.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail2456.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail2456.d(14): Error: cannot put `scope(success)` statement inside finally block
+fail_compilation/fail2456.d(14): Error: cannot put `scope(success)` statement inside `finally` block
---
*/
void test_success()
@@ -18,7 +18,7 @@ void test_success()
/*
TEST_OUTPUT:
---
-fail_compilation/fail2456.d(31): Error: cannot put `scope(failure)` statement inside finally block
+fail_compilation/fail2456.d(31): Error: cannot put `scope(failure)` statement inside `finally` block
---
*/
void test_failure()
@@ -84,8 +84,8 @@ void test2456a()
/*
TEST_OUTPUT:
---
-fail_compilation/fail2456.d(96): Error: cannot put catch statement inside `scope(success)`
-fail_compilation/fail2456.d(108): Error: cannot put catch statement inside `scope(exit)`
+fail_compilation/fail2456.d(96): Error: cannot put `catch` statement inside `scope(success)`
+fail_compilation/fail2456.d(108): Error: cannot put `catch` statement inside `scope(exit)`
---
*/
void test2456b()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail246.d b/gcc/testsuite/gdc.test/fail_compilation/fail246.d
index c6214ff..f48ddbb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail246.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail246.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail246.d-mixin-11(11): Error: identifier expected, not `EOF`
-fail_compilation/fail246.d-mixin-11(11): Error: `;` expected after mixin
+fail_compilation/fail246.d-mixin-11(11): Error: identifier expected, not `End of File`
+fail_compilation/fail246.d-mixin-11(11): Error: `;` expected after `mixin`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail247.d b/gcc/testsuite/gdc.test/fail_compilation/fail247.d
index 1acf1a4..4805d9d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail247.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail247.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail247.d-mixin-9(9): Error: identifier expected, not `EOF`
-fail_compilation/fail247.d-mixin-9(9): Error: `;` expected after mixin
+fail_compilation/fail247.d-mixin-9(9): Error: identifier expected, not `End of File`
+fail_compilation/fail247.d-mixin-9(9): Error: `;` expected after `mixin`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail248.d b/gcc/testsuite/gdc.test/fail_compilation/fail248.d
index 185de13..a15ec96 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail248.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail248.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail248.d(9): Error: type int is not an expression
+fail_compilation/fail248.d(9): Error: type `int` is not an expression
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail249.d b/gcc/testsuite/gdc.test/fail_compilation/fail249.d
index 79a4289..82b291f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail249.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail249.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail249.d(16): Error: invalid foreach aggregate `bar()`
+fail_compilation/fail249.d(16): Error: invalid `foreach` aggregate `bar()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail25.d b/gcc/testsuite/gdc.test/fail_compilation/fail25.d
index 7393a6c..11c0f0b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail25.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail25.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail25.d(14): Error: need 'this' for 'yuiop' of type 'int'
+fail_compilation/fail25.d(14): Error: need `this` for `yuiop` of type `int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail250.d b/gcc/testsuite/gdc.test/fail_compilation/fail250.d
index c3fd763..c6c08f7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail250.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail250.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail250.d(10): Error: constructor fail250.A.this default constructor for structs only allowed with @disable, no body, and no parameters
+fail_compilation/fail250.d(10): Error: constructor `fail250.A.this` default constructor for structs only allowed with `@disable`, no body, and no parameters
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail251.d b/gcc/testsuite/gdc.test/fail_compilation/fail251.d
index 083f3a4..75cf6e2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail251.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail251.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/fail251.d(12): Error: undefined identifier `xs`
-fail_compilation/fail251.d(16): called from here: foo()
+fail_compilation/fail251.d(16): called from here: `foo()`
fail_compilation/fail251.d(16): while evaluating: `static assert(foo())`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail253.d b/gcc/testsuite/gdc.test/fail_compilation/fail253.d
index 14e8858..bee7e31 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail253.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail253.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail253.d(13): Error: variable fail253.main.x inout variables can only be declared inside inout functions
-fail_compilation/fail253.d(16): Error: cannot modify inout expression x
+fail_compilation/fail253.d(13): Error: variable `fail253.main.x` `inout` variables can only be declared inside `inout` functions
+fail_compilation/fail253.d(16): Error: cannot modify `inout` expression `x`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail256.d b/gcc/testsuite/gdc.test/fail_compilation/fail256.d
index 87120e2..ce182e4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail256.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail256.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail256.d(8): Error: incompatible types for (("foo"d) ~ ("bar"c)): 'dstring' and 'string'
+fail_compilation/fail256.d(8): Error: incompatible types for `("foo"d) ~ ("bar"c)`: `dstring` and `string`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail259.d b/gcc/testsuite/gdc.test/fail_compilation/fail259.d
index 802e037..0c31b23 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail259.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail259.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail259.d(11): Error: function fail259.C.foo does not override any function
+fail_compilation/fail259.d(11): Error: function `fail259.C.foo` does not override any function
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail261.d b/gcc/testsuite/gdc.test/fail_compilation/fail261.d
index e25722c..73e062c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail261.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail261.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail261.d(18): Error: invalid foreach aggregate `range`, define opApply(), range primitives, or use .tupleof
+fail_compilation/fail261.d(18): Error: invalid `foreach` aggregate `range`, define `opApply()`, range primitives, or use `.tupleof`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail262.d b/gcc/testsuite/gdc.test/fail_compilation/fail262.d
index 6d15e1a..7c92c7c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail262.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail262.d
@@ -5,8 +5,8 @@ fail_compilation/fail262.d(23): Error: function `const void fail262.B.f()` does
---
*/
-// Issue 1645 - can override base class' const method with non-const method
-
+// https://issues.dlang.org/show_bug.cgi?id=1645
+// can override base class' const method with non-const method
import core.stdc.stdio;
class A
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail263.d b/gcc/testsuite/gdc.test/fail_compilation/fail263.d
index 8cf9b20..0fa2f86 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail263.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail263.d
@@ -6,8 +6,8 @@ fail_compilation/fail263.d(19): cannot pass argument `cast(const(byte)*)A
---
*/
-// Issue 2766 - DMD hangs with 0%cpu
-
+// https://issues.dlang.org/show_bug.cgi?id=2766
+// DMD hangs with 0%cpu
const byte[] A = [ cast(byte)0 ];
void f(byte* p)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail265.d b/gcc/testsuite/gdc.test/fail_compilation/fail265.d
index 476ff17..5585109 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail265.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail265.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail265.d-mixin-10(10): Error: found `EOF` instead of statement
+fail_compilation/fail265.d-mixin-10(10): Error: found `End of File` instead of statement
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail267.d b/gcc/testsuite/gdc.test/fail_compilation/fail267.d
index a6ebfac..fe02994 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail267.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail267.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail267.d(15): Error: template Bar() does not have property 'foo'
+fail_compilation/fail267.d(15): Error: template `Bar()` does not have property `foo`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail270.d b/gcc/testsuite/gdc.test/fail_compilation/fail270.d
index 8f31fd3..188fab8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail270.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail270.d
@@ -2,8 +2,8 @@
TEST_OUTPUT:
---
fail_compilation/fail270.d(12): Error: string slice `[1 .. 0]` is out of bounds
-fail_compilation/fail270.d(12): Error: mixin fail270.Tuple!int.Tuple.Tuple!() error instantiating
-fail_compilation/fail270.d(14): Error: mixin fail270.Tuple!int error instantiating
+fail_compilation/fail270.d(12): Error: mixin `fail270.Tuple!int.Tuple.Tuple!()` error instantiating
+fail_compilation/fail270.d(14): Error: mixin `fail270.Tuple!int` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail272.d b/gcc/testsuite/gdc.test/fail_compilation/fail272.d
index 15325ad..508599a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail272.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail272.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail272.d(9): Error: circular reference to variable 'fail272.Ins!(Ins).Ins'
-fail_compilation/fail272.d(10): Error: template instance fail272.Ins!(Ins) error instantiating
+fail_compilation/fail272.d(9): Error: circular reference to variable `fail272.Ins!(Ins).Ins`
+fail_compilation/fail272.d(10): Error: template instance `fail272.Ins!(Ins)` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail273.d b/gcc/testsuite/gdc.test/fail_compilation/fail273.d
index 9393c85..bf93276 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail273.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail273.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail273.d(10): Error: alias fail273.b recursive alias declaration
+fail_compilation/fail273.d(10): Error: alias `fail273.b` recursive alias declaration
---
*/
-// Issue 1054 - regression: circular aliases cause compiler stack overflow
-
+// https://issues.dlang.org/show_bug.cgi?id=1054
+// regression: circular aliases cause compiler stack overflow
alias a b;
alias b a;
b x; // ICE #1
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail275.d b/gcc/testsuite/gdc.test/fail_compilation/fail275.d
index df3eca1..ba4bd75 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail275.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail275.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail275.d(10): Error: circular reference to variable 'fail275.C.x'
+fail_compilation/fail275.d(10): Error: circular reference to variable `fail275.C.x`
---
*/
// REQUIRED_ARGS: -d
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail278.d b/gcc/testsuite/gdc.test/fail_compilation/fail278.d
index 8437acd..39b4e4e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail278.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail278.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail278.d(11): Error: template instance NONEXISTENT!() template 'NONEXISTENT' is not defined
-fail_compilation/fail278.d(12): Error: template instance fail278.F!() error instantiating
-fail_compilation/fail278.d(13): instantiated from here: Bar!(Foo)
+fail_compilation/fail278.d(11): Error: template instance `NONEXISTENT!()` template `NONEXISTENT` is not defined
+fail_compilation/fail278.d(12): Error: template instance `fail278.F!()` error instantiating
+fail_compilation/fail278.d(13): instantiated from here: `Bar!(Foo)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2789.d b/gcc/testsuite/gdc.test/fail_compilation/fail2789.d
new file mode 100644
index 0000000..2d6c8e2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail2789.d
@@ -0,0 +1,109 @@
+/*
+https://issues.dlang.org/show_bug.cgi?id=18385
+
+TEST_OUTPUT:
+---
+fail_compilation/fail2789.d(15): Error: function `fail2789.A2789.m()` conflicts with previous declaration at fail_compilation/fail2789.d(10)
+---
+*/
+#line 7
+
+class A2789
+{
+ int m()
+ {
+ return 1;
+ }
+
+ float m() // conflict
+ {
+ return 2.0;
+ }
+
+ float m() const // doen't conflict
+ {
+ return 3.0;
+ }
+
+ static void m() // no conflict
+ {
+ }
+}
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail2789.d(49): Error: function `fail2789.f4()` conflicts with previous declaration at fail_compilation/fail2789.d(48)
+fail_compilation/fail2789.d(55): Error: function `fail2789.f6()` conflicts with previous declaration at fail_compilation/fail2789.d(54)
+---
+*/
+
+
+void f1();
+void f1() {} // ok
+
+void f2() {}
+void f2(); // ok
+
+void f3();
+void f3(); // ok
+
+void f4() {}
+void f4() {} // conflict
+
+void f5() @safe {}
+void f5() @system {} // no conflict because of attribute based overloading in in extern(D)
+
+auto f6() { return 10; } // int()
+auto f6() { return ""; } // string(), conflict
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail2789.d(67): Error: function `fail2789.f_ExternC1()` conflicts with previous declaration at fail_compilation/fail2789.d(66)
+fail_compilation/fail2789.d(70): Deprecation: function `fail2789.f_ExternC2` cannot overload `extern(C)` function at fail_compilation/fail2789.d(69)
+fail_compilation/fail2789.d(73): Deprecation: function `fail2789.f_ExternC3` cannot overload `extern(C)` function at fail_compilation/fail2789.d(72)
+---
+*/
+
+extern(C) void f_ExternC1() {}
+extern(C) void f_ExternC1() {} // conflict
+
+extern(C) void f_ExternC2() {}
+extern(C) void f_ExternC2(int) {} // conflict
+
+extern(C) void f_ExternC3(int) {}
+extern(C) void f_ExternC3() {} // conflict
+
+extern (D) void f_MixExtern1() {}
+extern (C) void f_MixExtern1() {} // no conflict because of different mangling
+
+extern (D) void f_MixExtern2(int) {}
+extern (C) void f_MixExtern2() {} // no error
+
+extern (C) void f_ExternC4(int sig);
+extern (C) void f_ExternC4(int sig) @nogc; // no error
+
+extern (C) void f_ExternC5(int sig) {}
+extern (C) void f_ExternC5(int sig) @nogc; // no error
+
+extern (C) void f_ExternC6(int sig);
+extern (C) void f_ExternC6(int sig) @nogc {} // no error
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail2789.d(103): Error: function `fail2789.mul14147(const(int[]) left, const(int[]) right)` conflicts with previous declaration at fail_compilation/fail2789.d(99)
+---
+*/
+struct S14147(alias func)
+{
+}
+pure auto mul14147(const int[] left, const int[] right)
+{
+ S14147!(a => a) s;
+}
+pure auto mul14147(const int[] left, const int[] right)
+{
+ S14147!(a => a) s;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail282.d b/gcc/testsuite/gdc.test/fail_compilation/fail282.d
index 0b1391b..a25aa5c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail282.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail282.d
@@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail282.d(13): Error: template instance fail282.Template!500 recursive expansion
+fail_compilation/fail282.d(13): Error: template instance `fail282.Template!500` recursive expansion exceeded allowed nesting limit
---
*/
-// Issue 2920 - recursive templates blow compiler stack
+// https://issues.dlang.org/show_bug.cgi?id=2920
+// recursive templates blow compiler stack
// template_class_09.
-
template Template(int i)
{
class Class : Template!(i + 1).Class
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail284.d b/gcc/testsuite/gdc.test/fail_compilation/fail284.d
index a33f2c5..abfad67 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail284.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail284.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail284.d(19): Error: pure function 'fail284.foo' cannot call impure function pointer 'a'
+fail_compilation/fail284.d(19): Error: `pure` function `fail284.foo` cannot call impure function pointer `a`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail288.d b/gcc/testsuite/gdc.test/fail_compilation/fail288.d
index d6b68c9..4fdaddd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail288.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail288.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail288.d(14): Error: case ranges not allowed in final switch
+fail_compilation/fail288.d(14): Error: case ranges not allowed in `final switch`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail291.d b/gcc/testsuite/gdc.test/fail_compilation/fail291.d
index 79ff2b0..e8d9f37 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail291.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail291.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail291.d(9): Error: variable fail291.X cannot be declared to be a function
+fail_compilation/fail291.d(9): Error: variable `fail291.X` cannot be declared to be a function
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail296.d b/gcc/testsuite/gdc.test/fail_compilation/fail296.d
index 3f1e5d3f..920854f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail296.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail296.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail296.d(10): Error: can only * a pointer, not a 'int'
+fail_compilation/fail296.d(10): Error: can only `*` a pointer, not a `int`
---
*/
-// Issue 3117 - dmd crash by *1
-
+// https://issues.dlang.org/show_bug.cgi?id=3117
+// dmd crash by *1
void main(){ *1; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2962.d b/gcc/testsuite/gdc.test/fail_compilation/fail2962.d
index 06caadc..59e86c1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail2962.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail2962.d
@@ -4,9 +4,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail2962.d(14): Error: variable y cannot be read at compile time
-fail_compilation/fail2962.d(14): while looking for match for baz6!(int, y)
-fail_compilation/fail2962.d(22): Error: template instance fail2962.bar6!int error instantiating
+fail_compilation/fail2962.d(14): Error: variable `y` cannot be read at compile time
+fail_compilation/fail2962.d(14): while looking for match for `baz6!(int, y)`
+fail_compilation/fail2962.d(22): Error: template instance `fail2962.bar6!int` error instantiating
---
*/
T bar6(T)(T y)
@@ -26,9 +26,9 @@ void test6()
/*
TEST_OUTPUT:
---
-fail_compilation/fail2962.d(36): Error: variable x cannot be read at compile time
-fail_compilation/fail2962.d(36): while looking for match for baz4!(int, x)
-fail_compilation/imports/fail2962a.d(6): Error: template instance fail2962.bar4!int error instantiating
+fail_compilation/fail2962.d(36): Error: variable `x` cannot be read at compile time
+fail_compilation/fail2962.d(36): while looking for match for `baz4!(int, x)`
+fail_compilation/imports/fail2962a.d(6): Error: template instance `fail2962.bar4!int` error instantiating
---
*/
T bar4(T)(T x)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail297.d b/gcc/testsuite/gdc.test/fail_compilation/fail297.d
index fd2249d..5fc3bbf 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail297.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail297.d
@@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail297.d(30): Error: incompatible types for ((Bar()) + (baz())): 'Bar' and 'const(Bar)'
+fail_compilation/fail297.d(30): Error: incompatible types for `(Bar()) + (baz())`: `Bar` and `const(Bar)`
---
*/
-// Issue 1969 - ICE(cod1.c) using undefined operator with one const operand
-
-// 1969 ICE or wrong-code. D2 only. Internal error: backend\cod1.c 1673
+// https://issues.dlang.org/show_bug.cgi?id=1969
+// ICE(cod1.c) using undefined operator with one const operand
+// ICE or wrong-code. D2 only. Internal error: backend\cod1.c 1673
/* Root cause: BinExp::typeCombine() is checking for an _exact_ match, but
typeMerge() will return success.
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail299.d b/gcc/testsuite/gdc.test/fail_compilation/fail299.d
index 1bfdd82..ffe5067 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail299.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail299.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail299.d(14): Error: more initializers than fields (0) of Foo
+fail_compilation/fail299.d(14): Error: more initializers than fields (0) of `Foo`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3.d b/gcc/testsuite/gdc.test/fail_compilation/fail3.d
index 0b7516c..5c1ea91 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail3.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail3.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail3.d(41): Error: incompatible types for ((a) + (b)): both operands are of type 'vec2'
+fail_compilation/fail3.d(41): Error: incompatible types for `(a) + (b)`: both operands are of type `vec2`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail301.d b/gcc/testsuite/gdc.test/fail_compilation/fail301.d
index b012fc8..bf90f55 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail301.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail301.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail301.d(11): Error: need 'this' for 'guard' of type 'int'
-fail_compilation/fail301.d(22): Error: template instance fail301.bug3305!0 error instantiating
+fail_compilation/fail301.d(11): Error: need `this` for `guard` of type `int`
+fail_compilation/fail301.d(22): Error: template instance `fail301.bug3305!0` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail302.d b/gcc/testsuite/gdc.test/fail_compilation/fail302.d
index 02c6b24..d1133b0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail302.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail302.d
@@ -1,7 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail302.d(21): Error: cannot implicitly convert expression `1` of type `int` to `Bar`
+fail_compilation/fail302.d(23): Error: cannot implicitly convert expression `1` of type `int` to `Bar`
+fail_compilation/fail302.d(23): `bar = 1` is the first assignment of `bar` therefore it represents its initialization
+fail_compilation/fail302.d(23): `opAssign` methods are not used for initialization, but for subsequent assignments
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail303.d b/gcc/testsuite/gdc.test/fail_compilation/fail303.d
index 98223fa..2c825fe 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail303.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail303.d
@@ -1,13 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail303.d(19): Error: double /= cdouble is undefined. Did you mean double /= cdouble.re ?
-fail_compilation/fail303.d(20): Error: ireal *= ireal is an undefined operation
-fail_compilation/fail303.d(21): Error: ireal *= creal is undefined. Did you mean ireal *= creal.im ?
-fail_compilation/fail303.d(22): Error: ireal %= creal is undefined. Did you mean ireal %= creal.im ?
-fail_compilation/fail303.d(23): Error: ireal += real is undefined (result is complex)
-fail_compilation/fail303.d(24): Error: ireal -= creal is undefined (result is complex)
-fail_compilation/fail303.d(25): Error: double -= idouble is undefined (result is complex)
+fail_compilation/fail303.d(18): Deprecation: use of imaginary type `ireal` is deprecated, use `real` instead
+fail_compilation/fail303.d(20): Error: `double /= cdouble` is undefined. Did you mean `double /= cdouble.re`?
+fail_compilation/fail303.d(21): Error: `ireal *= ireal` is an undefined operation
+fail_compilation/fail303.d(22): Error: `ireal *= creal` is undefined. Did you mean `ireal *= creal.im`?
+fail_compilation/fail303.d(23): Error: `ireal %= creal` is undefined. Did you mean `ireal %= creal.im`?
+fail_compilation/fail303.d(24): Error: `ireal += real` is undefined (result is complex)
+fail_compilation/fail303.d(25): Error: `ireal -= creal` is undefined (result is complex)
+fail_compilation/fail303.d(26): Error: `double -= idouble` is undefined (result is complex)
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail305.d b/gcc/testsuite/gdc.test/fail_compilation/fail305.d
index 3c9dc76..aef1624 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail305.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail305.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail305.d(10): Error: cannot return non-void from void function
+fail_compilation/fail305.d(10): Error: cannot return non-void from `void` function
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail309.d b/gcc/testsuite/gdc.test/fail_compilation/fail309.d
index e1c9bfa..0fbfd59 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail309.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail309.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail309.d(10): Error: circular reference to variable 'fail309.S.x'
+fail_compilation/fail309.d(10): Error: circular reference to variable `fail309.S.x`
---
*/
// REQUIRED_ARGS: -d
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail310.d b/gcc/testsuite/gdc.test/fail_compilation/fail310.d
index 1dc3d5b..5b3c99a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail310.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail310.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/fail310.d(10): Error: undefined identifier `Foo`, did you mean function `foo`?
-fail_compilation/fail310.d(14): Error: template instance fail310.foo!(1, 2) error instantiating
+fail_compilation/fail310.d(14): Error: template instance `fail310.foo!(1, 2)` error instantiating
fail_compilation/fail310.d(14): while evaluating: `static assert(foo!(1, 2)())`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail311.d b/gcc/testsuite/gdc.test/fail_compilation/fail311.d
index 1713069..eaacfab 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail311.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail311.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/fail311.d(16): Error: undefined identifier `undefined`
-fail_compilation/fail311.d(25): Error: template instance fail311.foo!() error instantiating
+fail_compilation/fail311.d(25): Error: template instance `fail311.foo!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail312.d b/gcc/testsuite/gdc.test/fail_compilation/fail312.d
index 3823ee4..7260697 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail312.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail312.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail312.d(13): Error: incompatible types for ((a[]) == (b)): 'int[]' and 'short'
-fail_compilation/fail312.d(14): Error: incompatible types for ((a[]) <= (b)): 'int[]' and 'short'
+fail_compilation/fail312.d(13): Error: incompatible types for `(a[]) == (b)`: `int[]` and `short`
+fail_compilation/fail312.d(14): Error: incompatible types for `(a[]) <= (b)`: `int[]` and `short`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail313.d b/gcc/testsuite/gdc.test/fail_compilation/fail313.d
index a2c2890..3a2c7ec 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail313.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail313.d
@@ -1,10 +1,10 @@
/*
-REQUIRED_ARGS: -de
+EXTRA_FILES: imports/a313.d imports/b313.d imports/pkg313/package.d
TEST_OUTPUT:
---
-fail_compilation/fail313.d(15): Error: undefined identifier `b313` in package `imports`, perhaps add `static import imports.b313;`
-fail_compilation/fail313.d(22): Error: undefined identifier `core`
-fail_compilation/fail313.d(27): Error: undefined identifier `pkg313` in package `imports`, perhaps add `static import imports.pkg313;`
+fail_compilation/fail313.d(16): Error: undefined identifier `b313` in package `imports`, perhaps add `static import imports.b313;`
+fail_compilation/fail313.d(23): Error: undefined identifier `core`
+fail_compilation/fail313.d(28): Error: undefined identifier `pkg313` in package `imports`, perhaps add `static import imports.pkg313;`
---
*/
module test313;
@@ -23,7 +23,7 @@ void test2()
core.stdc.stdio.printf("");
}
-void test2()
+void test3()
{
imports.pkg313.bug();
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail314.d b/gcc/testsuite/gdc.test/fail_compilation/fail314.d
deleted file mode 100644
index cfbb030..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail314.d
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail314.d(11): Error: declaration T is already defined
----
-*/
-
-struct foo
-{
- static if (is(int T == int)) {}
- static if (is(int T == int)) {}
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3144.d b/gcc/testsuite/gdc.test/fail_compilation/fail3144.d
index 04e808f..ff01a03 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail3144.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail3144.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail3144.d(12): Error: break is not inside a loop or switch
-fail_compilation/fail3144.d(15): Error: break is not inside a loop or switch
+fail_compilation/fail3144.d(12): Error: `break` is not inside a loop or `switch`
+fail_compilation/fail3144.d(15): Error: `break` is not inside a loop or `switch`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail315.d b/gcc/testsuite/gdc.test/fail_compilation/fail315.d
index 7ce4a80..c7fd78f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail315.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail315.d
@@ -3,11 +3,11 @@ TEST_OUTPUT:
---
fail_compilation/fail315.d-mixin-16(16): Error: found `;` when expecting `,`
fail_compilation/fail315.d-mixin-16(16): Error: expression expected, not `}`
-fail_compilation/fail315.d-mixin-16(16): Error: found `EOF` when expecting `,`
-fail_compilation/fail315.d-mixin-16(16): Error: found `EOF` when expecting `]`
-fail_compilation/fail315.d-mixin-16(16): Error: found `EOF` when expecting `;` following return statement
-fail_compilation/fail315.d-mixin-16(16): Error: found `EOF` when expecting `}` following compound statement
-fail_compilation/fail315.d(21): Error: template instance fail315.foo!() error instantiating
+fail_compilation/fail315.d-mixin-16(16): Error: found `End of File` when expecting `,`
+fail_compilation/fail315.d-mixin-16(16): Error: found `End of File` when expecting `]`
+fail_compilation/fail315.d-mixin-16(16): Error: found `End of File` when expecting `;` following `return` statement
+fail_compilation/fail315.d-mixin-16(16): Error: found `End of File` when expecting `}` following compound statement
+fail_compilation/fail315.d(21): Error: template instance `fail315.foo!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail317.d b/gcc/testsuite/gdc.test/fail_compilation/fail317.d
index 05e7edb..d6a0f4d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail317.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail317.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail317.d(10): Error: function fail317.I.f has no function body with return type inference
+fail_compilation/fail317.d(10): Error: function `fail317.I.f` has no function body with return type inference
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail318.d b/gcc/testsuite/gdc.test/fail_compilation/fail318.d
index dd93803..d99175e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail318.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail318.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail318.d(8): Error: function D main must return int or void
+fail_compilation/fail318.d(8): Error: function `D main` must return `int` or `void`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail319.d b/gcc/testsuite/gdc.test/fail_compilation/fail319.d
index 3c4459a..cf56fee 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail319.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail319.d
@@ -1,7 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail319.d(13): Error: template instance fail319.f!(int, int) does not match template declaration f(T...)() if (T.length > 20)
+fail_compilation/fail319.d(16): Error: template instance `fail319.f!(int, int)` does not match template declaration `f(T...)()`
+ with `T = (int, int)`
+ must satisfy the following constraint:
+` T.length > 20`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail320.d b/gcc/testsuite/gdc.test/fail_compilation/fail320.d
index 3a80dd5..24020b4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail320.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail320.d
@@ -1,7 +1,8 @@
/*
+EXTRA_FILES: imports/fail320a.d imports/fail320b.d
TEST_OUTPUT:
---
-fail_compilation/fail320.d(10): Error: no overload matches for foo
+fail_compilation/fail320.d(11): Error: no overload matches for `foo`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail324.d b/gcc/testsuite/gdc.test/fail_compilation/fail324.d
deleted file mode 100644
index 931cb8d..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail324.d
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail324.d(16): Error: template instance doStuff!((i){ return i; }) cannot use local '__lambda1' as parameter to non-global template doStuff(alias fun)()
----
-*/
-
-struct Foo
-{
- void doStuff(alias fun)() {}
-}
-
-void main()
-{
- Foo foo;
- foo.doStuff!( (i) { return i; })();
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail325.d b/gcc/testsuite/gdc.test/fail_compilation/fail325.d
index e75a1c1..bf7f305 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail325.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail325.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail325.d(12): Error: template fun(T = int)(int w, int z) has no type
+fail_compilation/fail325.d(12): Error: template `fun(T = int)(int w, int z)` has no type
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail328.d b/gcc/testsuite/gdc.test/fail_compilation/fail328.d
index 7e97913..12347e5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail328.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail328.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail328.d(12): Error: @safe function 'fail328.foo' cannot call @system function 'fail328.bar'
+fail_compilation/fail328.d(13): Error: `@safe` function `fail328.foo` cannot call `@system` function `fail328.bar`
+fail_compilation/fail328.d(9): `fail328.bar` is declared here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail329.d b/gcc/testsuite/gdc.test/fail_compilation/fail329.d
index f28304e..95aaaf4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail329.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail329.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail329.d(28): Error: variable fail329.A.foo.__ensure.result cannot modify result 'result' in contract
+fail_compilation/fail329.d(28): Error: variable `fail329.A.foo.__ensure.result` cannot modify result `result` in contract
---
*/
@@ -27,7 +27,7 @@ class A
assert(x == 7);
result++;
}
- body
+ do
{
return i;
}
@@ -49,7 +49,7 @@ class B : A
assert(result < 8);
assert(x == 7);
}
- body
+ do
{
return i - 1;
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail330.d b/gcc/testsuite/gdc.test/fail_compilation/fail330.d
index a3409db..94e91bb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail330.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail330.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail330.d(9): Error: variable fail330.fun.result cannot modify result 'result' in contract
+fail_compilation/fail330.d(9): Error: variable `fail330.fun.result` cannot modify result `result` in contract
---
*/
int fun()
out(result) { result = 2; }
-body { return 1; }
+do { return 1; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail331.d b/gcc/testsuite/gdc.test/fail_compilation/fail331.d
index 8b79ea2..7f97801 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail331.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail331.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail331.d(10): Error: cannot use typeof(return) inside function foo with inferred return type
+fail_compilation/fail331.d(10): Error: cannot use `typeof(return)` inside function `foo` with inferred return type
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail332.d b/gcc/testsuite/gdc.test/fail_compilation/fail332.d
index 91f8046..12164b9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail332.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail332.d
@@ -21,7 +21,7 @@ void test()
{
foo();
foo(null);
-
+
baz("");
baz(3, null);
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail333.d b/gcc/testsuite/gdc.test/fail_compilation/fail333.d
index 717de24..89f9478 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail333.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail333.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail333.d(8): Error: forward reference to 'test'
+fail_compilation/fail333.d(8): Error: forward reference to `test`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail336.d b/gcc/testsuite/gdc.test/fail_compilation/fail336.d
index 2a6be95..9df2071 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail336.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail336.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail336.d(16): Error: struct S has constructors, cannot use { initializers }, use S( initializers ) instead
+fail_compilation/fail336.d(16): Error: struct `S` has constructors, cannot use `{ initializers }`, use `S( initializers )` instead
---
*/
-// Issue 3476 - C-style initializer for structs must be disallowed for structs with a constructor
-
+// https://issues.dlang.org/show_bug.cgi?id=3476
+// C-style initializer for structs must be disallowed for structs with a constructor
struct S
{
int a;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail337.d b/gcc/testsuite/gdc.test/fail_compilation/fail337.d
index cc86bd2..0a411e6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail337.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail337.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail337.d(13): Error: static assert `0` is false
-fail_compilation/fail337.d(26): instantiated from here: bar!()
-fail_compilation/fail337.d(33): 100 recursive instantiations from here: foo!196
-fail_compilation/fail337.d(41): 253 recursive instantiations from here: baz!300
+fail_compilation/fail337.d(13): Error: static assert: `0` is false
+fail_compilation/fail337.d(26): instantiated from here: `bar!()`
+fail_compilation/fail337.d(33): 100 recursive instantiations from here: `foo!196`
+fail_compilation/fail337.d(41): 253 recursive instantiations from here: `baz!300`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail34.d b/gcc/testsuite/gdc.test/fail_compilation/fail34.d
index f910a2d..7a3c807 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail34.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail34.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail34.d(31): Error: duplicate `case "123"` in switch statement
+fail_compilation/fail34.d(31): Error: duplicate `case "123"` in `switch` statement
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail340.d b/gcc/testsuite/gdc.test/fail_compilation/fail340.d
index 57d40a7..3d83e68 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail340.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail340.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail340.d(18): Error: variable fail340.w of type struct const(CopyTest) uses this(this), which is not allowed in static initialization
-fail_compilation/fail340.d(19): while evaluating: `static assert(w.x == 55.0000)`
+fail_compilation/fail340.d(18): Error: variable `fail340.w` of type struct `const(CopyTest)` uses `this(this)`, which is not allowed in static initialization
+fail_compilation/fail340.d(19): while evaluating: `static assert(w.x == 55.0)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail341.d b/gcc/testsuite/gdc.test/fail_compilation/fail341.d
index 8677d48..38bb6dc 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail341.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail341.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail341.d(26): Error: struct fail341.S is not copyable because it is annotated with `@disable`
+fail_compilation/fail341.d(26): Error: struct `fail341.S` is not copyable because field `t` is not copyable
fail_compilation/fail341.d(27): Error: function `fail341.foo` cannot be used because it is annotated with `@disable`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail343.d b/gcc/testsuite/gdc.test/fail_compilation/fail343.d
index 19601a7..5b7e9bf 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail343.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail343.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail343.d(22): Error: function fail343.TimedApp.run cannot override final function I.fail343.Timer.run
-fail_compilation/fail343.d(22): Error: function fail343.TimedApp.run cannot override final function Application.fail343.Application.run
+fail_compilation/fail343.d(22): Error: function `fail343.TimedApp.run` cannot override `final` function `I.fail343.Timer.run`
+fail_compilation/fail343.d(22): Error: function `fail343.TimedApp.run` cannot override `final` function `Application.fail343.Application.run`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail347.d b/gcc/testsuite/gdc.test/fail_compilation/fail347.d
index 61718df..8d061f9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail347.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail347.d
@@ -1,9 +1,10 @@
/*
+EXTRA_FILES: imports/fail347a.d
TEST_OUTPUT:
---
-fail_compilation/fail347.d(21): Error: undefined identifier `bbr`, did you mean variable `bar`?
-fail_compilation/fail347.d(22): Error: no property 'ofo' for type 'S', did you mean 'fail347.S.foo'?
-fail_compilation/fail347.d(23): Error: undefined identifier `strlenx`, did you mean function `strlen`?
+fail_compilation/fail347.d(22): Error: undefined identifier `bbr`, did you mean variable `bar`?
+fail_compilation/fail347.d(23): Error: no property `ofo` for type `S`, did you mean `fail347.S.foo`?
+fail_compilation/fail347.d(24): Error: undefined identifier `strlenx`, did you mean function `strlen`?
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail349.d b/gcc/testsuite/gdc.test/fail_compilation/fail349.d
index 8100ab7..11a392c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail349.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail349.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail349.d(15): Error: function `fail349.bug6109throwing` is not nothrow
-fail_compilation/fail349.d(13): Error: nothrow function `fail349.bug6109noThrow` may throw
+fail_compilation/fail349.d(15): Error: function `fail349.bug6109throwing` is not `nothrow`
+fail_compilation/fail349.d(13): Error: `nothrow` function `fail349.bug6109noThrow` may throw
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail35.d b/gcc/testsuite/gdc.test/fail_compilation/fail35.d
index c56f278..c35dfe1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail35.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail35.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail35.d(15): Error: variable t cannot be read at compile time
+fail_compilation/fail35.d(15): Error: variable `t` cannot be read at compile time
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail351.d b/gcc/testsuite/gdc.test/fail_compilation/fail351.d
index 04f21b2..1762ec0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail351.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail351.d
@@ -1,16 +1,16 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail351.d(14): Error: cast(uint)this.num[index] is not an lvalue
+fail_compilation/fail351.d(14): Error: expression `this.num[index]` of type `immutable(uint)` is not implicitly convertible to return type `ref uint`
---
*/
-// 2780
+// https://issues.dlang.org/show_bug.cgi?id=2780
struct Immutable {
immutable uint[2] num;
- ref uint opIndex(size_t index) immutable {
+ ref uint opIndex(size_t index) immutable return {
return num[index];
}
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail354.d b/gcc/testsuite/gdc.test/fail_compilation/fail354.d
index 55dbf52..8689f61 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail354.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail354.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail354.d(11): Error: template instance T!N template 'T' is not defined
-fail_compilation/fail354.d(13): Error: template instance fail354.S!1 error instantiating
+fail_compilation/fail354.d(11): Error: template instance `T!N` template `T` is not defined
+fail_compilation/fail354.d(13): Error: template instance `fail354.S!1` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail355.d b/gcc/testsuite/gdc.test/fail_compilation/fail355.d
index d342d12..1237801 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail355.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail355.d
@@ -1,7 +1,8 @@
/*
+EXTRA_FILES: imports/fail355.d
TEST_OUTPUT:
---
-fail_compilation/fail355.d(8): Error: module imports.fail355 import 'nonexistent' not found
+fail_compilation/fail355.d(9): Error: module `imports.fail355` import `nonexistent` not found
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail36.d b/gcc/testsuite/gdc.test/fail_compilation/fail36.d
index 47fb884..96e022e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail36.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail36.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail36.d(13): Error: template t(int L) does not have property 'a'
-fail_compilation/fail36.d(18): Error: mixin fail36.func.t!10 error instantiating
+fail_compilation/fail36.d(13): Error: template `t(int L)` does not have property `a`
+fail_compilation/fail36.d(18): Error: mixin `fail36.func.t!10` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3672.d b/gcc/testsuite/gdc.test/fail_compilation/fail3672.d
index 1622bd2..2f9bdf7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail3672.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail3672.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail3672.d(28): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(*p, 1) instead.
-fail_compilation/fail3672.d(32): Deprecation: read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!"+="(*sfp, 1) instead.
-fail_compilation/fail3672.d(32): Error: '*sfp += 1' is not a scalar, it is a shared(SF)
+fail_compilation/fail3672.d(28): Error: read-modify-write operations are not allowed for `shared` variables
+fail_compilation/fail3672.d(28): Use `core.atomic.atomicOp!"+="(*p, 1)` instead
+fail_compilation/fail3672.d(32): Error: none of the `opOpAssign` overloads of `SF` are callable for `*sfp` of type `shared(SF)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3703.d b/gcc/testsuite/gdc.test/fail_compilation/fail3703.d
index 0b4e260..6b4edd5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail3703.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail3703.d
@@ -1,5 +1,5 @@
-// Issue 3703 - static array assignment
-
+// https://issues.dlang.org/show_bug.cgi?id=3703
+// static array assignment
/*
TEST_OUTPUT:
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3753.d b/gcc/testsuite/gdc.test/fail_compilation/fail3753.d
deleted file mode 100644
index d20d8e9..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail3753.d
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-TEST_OUTPUT:
----
-Error: cannot mix core.std.stdlib.alloca() and exception handling in _Dmain()
----
-*/
-
-import core.stdc.stdlib : alloca;
-import core.stdc.stdio;
-
-struct TheStruct
-{
- ~this()
- {
- printf("dtor()\n");
- }
-}
-
-void bar()
-{
- printf("bar()\n");
-}
-
-void main()
-{
- auto s = TheStruct();
- bar();
- auto a = alloca(16);
- printf("test()\n");
- version (DigitalMars)
- {
- version (Win32) static assert(0);
- version (linux)
- {
- static assert(0);
- }
- version (FreeBSD)
- {
- static assert(0);
- }
- version (OSX)
- {
- static assert(0);
- }
- }
- else
- static assert(0);
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail37_m32.d b/gcc/testsuite/gdc.test/fail_compilation/fail37_m32.d
index 996f98f..900d80d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail37_m32.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail37_m32.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail37_m32.d(9): Error: 'cast(float)4u / cast(float)8u - cast(float)2147483647' is not of integral type, it is a float
+fail_compilation/fail37_m32.d(9): Error: `cast(float)4u / cast(float)8u - cast(float)2147483647` is not of integral type, it is a `float`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail37_m64.d b/gcc/testsuite/gdc.test/fail_compilation/fail37_m64.d
index 2e979e7..5c0d169 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail37_m64.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail37_m64.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail37_m64.d(9): Error: 'cast(float)4LU / cast(float)8LU - cast(float)2147483647' is not of integral type, it is a float
+fail_compilation/fail37_m64.d(9): Error: `cast(float)4LU / cast(float)8LU - cast(float)2147483647` is not of integral type, it is a `float`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail38.d b/gcc/testsuite/gdc.test/fail_compilation/fail38.d
index 0f2cd5f..344a075 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail38.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail38.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail38.d(12): Error: 'super' is only allowed in non-static class member functions
+fail_compilation/fail38.d(12): Error: `super` is only allowed in non-static class member functions
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3882.d b/gcc/testsuite/gdc.test/fail_compilation/fail3882.d
index b7d8a97..27ddad4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail3882.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail3882.d
@@ -2,13 +2,13 @@
// PERMUTE_ARGS: -debug
/******************************************/
-// 3882
+// https://issues.dlang.org/show_bug.cgi?id=3882
/*
TEST_OUTPUT:
---
-fail_compilation/fail3882.d(23): Warning: calling fail3882.strictlyPure!int.strictlyPure without side effects discards return value of type int, prepend a cast(void) if intentional
-fail_compilation/fail3882.d(27): Warning: calling fp without side effects discards return value of type int, prepend a cast(void) if intentional
+fail_compilation/fail3882.d(23): Warning: calling `fail3882.strictlyPure!int.strictlyPure` without side effects discards return value of type `int`; prepend a `cast(void)` if intentional
+fail_compilation/fail3882.d(27): Warning: calling `fp` without side effects discards return value of type `int`; prepend a `cast(void)` if intentional
---
*/
@@ -22,7 +22,7 @@ void main()
int x = 3;
strictlyPure(x);
- // 12649
+ // https://issues.dlang.org/show_bug.cgi?id=12649
auto fp = &strictlyPure!int;
fp(x);
}
@@ -33,8 +33,10 @@ void main()
/*
TEST_OUTPUT:
---
-fail_compilation/fail3882.d(46): Warning: calling fail3882.f1 without side effects discards return value of type int, prepend a cast(void) if intentional
-fail_compilation/fail3882.d(47): Warning: calling fail3882.f2 without side effects discards return value of type int, prepend a cast(void) if intentional
+fail_compilation/fail3882.d(48): Warning: calling `fail3882.f1` without side effects discards return value of type `int`; prepend a `cast(void)` if intentional
+fail_compilation/fail3882.d(49): Warning: calling `fail3882.f2` without side effects discards return value of type `int`; prepend a `cast(void)` if intentional
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail39.d b/gcc/testsuite/gdc.test/fail_compilation/fail39.d
index 65472cf..c0bb0e1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail39.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail39.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail39.d(11): Error: function fail39.main.__funcliteral2 cannot access frame of function D main
+fail_compilation/fail39.d(12): Error: function `fail39.main.__funcliteral2` cannot access function `foo` in frame of function `D main`
+fail_compilation/fail39.d(11): `foo` declared here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail3990.d b/gcc/testsuite/gdc.test/fail_compilation/fail3990.d
index 6d17a7d..aa0fa81 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail3990.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail3990.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail3990.d(12): Error: using * on an array is no longer supported; use *(arr1).ptr instead
-fail_compilation/fail3990.d(14): Error: using * on an array is no longer supported; use *(arr2).ptr instead
+fail_compilation/fail3990.d(12): Error: using `*` on an array is no longer supported; use `*(arr1).ptr` instead
+fail_compilation/fail3990.d(14): Error: using `*` on an array is no longer supported; use `*(arr2).ptr` instead
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail40.d b/gcc/testsuite/gdc.test/fail_compilation/fail40.d
index aa15db3..947a3af 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail40.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail40.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail40.d(11): Error: variable yuiop cannot be read at compile time
+fail_compilation/fail40.d(11): Error: variable `yuiop` cannot be read at compile time
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4082.d b/gcc/testsuite/gdc.test/fail_compilation/fail4082.d
index fc6ba78..6f9ee61 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4082.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4082.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4082.d(14): Error: destructor `fail4082.Foo.~this` is not nothrow
-fail_compilation/fail4082.d(12): Error: nothrow function `fail4082.test1` may throw
+fail_compilation/fail4082.d(14): Error: destructor `fail4082.Foo.~this` is not `nothrow`
+fail_compilation/fail4082.d(12): Error: `nothrow` function `fail4082.test1` may throw
---
*/
struct Foo
@@ -21,8 +21,8 @@ NEXT:
/*
TEST_OUTPUT:
---
-fail_compilation/fail4082.d(32): Error: destructor `fail4082.Bar.~this` is not nothrow
-fail_compilation/fail4082.d(32): Error: nothrow function `fail4082.test2` may throw
+fail_compilation/fail4082.d(32): Error: destructor `fail4082.Bar.~this` is not `nothrow`
+fail_compilation/fail4082.d(32): Error: `nothrow` function `fail4082.test2` may throw
---
*/
struct Bar
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail41.d b/gcc/testsuite/gdc.test/fail_compilation/fail41.d
index fa0e0c3..6d89395 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail41.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail41.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail41.d(17): Error: cannot return non-void from void function
+fail_compilation/fail41.d(17): Error: cannot return non-void from `void` function
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail42.d b/gcc/testsuite/gdc.test/fail_compilation/fail42.d
index 5101ca1..c153d5b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail42.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail42.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail42.d(22): Error: struct fail42.Qwert no size because of forward reference
+fail_compilation/fail42.d(22): Error: struct `fail42.Qwert` no size because of forward reference
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375a.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375a.d
index 5ee2a31..a07f78f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375a.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375a.d(14): Warning: else is dangling, add { } after condition at fail_compilation/fail4375a.d(11)
+fail_compilation/fail4375a.d(16): Warning: else is dangling, add { } after condition at fail_compilation/fail4375a.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375b.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375b.d
index 0d16446..dbc299f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375b.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375b.d(16): Warning: else is dangling, add { } after condition at fail_compilation/fail4375b.d(12)
+fail_compilation/fail4375b.d(18): Warning: else is dangling, add { } after condition at fail_compilation/fail4375b.d(14)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375c.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375c.d
index 4e578aa..230c656 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375c.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375c.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375c.d(15): Warning: else is dangling, add { } after condition at fail_compilation/fail4375c.d(11)
+fail_compilation/fail4375c.d(17): Warning: else is dangling, add { } after condition at fail_compilation/fail4375c.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d
index 8e9b4e7..7592779 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375d.d(15): Warning: else is dangling, add { } after condition at fail_compilation/fail4375d.d(11)
+fail_compilation/fail4375d.d(17): Warning: else is dangling, add { } after condition at fail_compilation/fail4375d.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375e.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375e.d
index ae809bc..3ccd4fb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375e.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375e.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375e.d(14): Warning: else is dangling, add { } after condition at fail_compilation/fail4375e.d(11)
+fail_compilation/fail4375e.d(16): Warning: else is dangling, add { } after condition at fail_compilation/fail4375e.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375f.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375f.d
index 5855b1b..867fbff 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375f.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375f.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375f.d(14): Warning: else is dangling, add { } after condition at fail_compilation/fail4375f.d(11)
+fail_compilation/fail4375f.d(16): Warning: else is dangling, add { } after condition at fail_compilation/fail4375f.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375g.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375g.d
index 4b9d12b..6f452f53 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375g.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375g.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375g.d(14): Warning: else is dangling, add { } after condition at fail_compilation/fail4375g.d(11)
+fail_compilation/fail4375g.d(16): Warning: else is dangling, add { } after condition at fail_compilation/fail4375g.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375h.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375h.d
index 72e3e14..c0f1c5b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375h.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375h.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375h.d(16): Warning: else is dangling, add { } after condition at fail_compilation/fail4375h.d(13)
+fail_compilation/fail4375h.d(18): Warning: else is dangling, add { } after condition at fail_compilation/fail4375h.d(15)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375i.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375i.d
index 5801c61..b13c9e4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375i.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375i.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375i.d(16): Warning: else is dangling, add { } after condition at fail_compilation/fail4375i.d(11)
+fail_compilation/fail4375i.d(18): Warning: else is dangling, add { } after condition at fail_compilation/fail4375i.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375j.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375j.d
index 9a87540..8f24700 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375j.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375j.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375j.d(16): Warning: else is dangling, add { } after condition at fail_compilation/fail4375j.d(11)
+fail_compilation/fail4375j.d(18): Warning: else is dangling, add { } after condition at fail_compilation/fail4375j.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375k.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375k.d
index bb8b7b2..8c21fea 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375k.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375k.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375k.d-mixin-11(15): Warning: else is dangling, add { } after condition at fail_compilation/fail4375k.d-mixin-11(12)
+fail_compilation/fail4375k.d-mixin-13(17): Warning: else is dangling, add { } after condition at fail_compilation/fail4375k.d-mixin-13(14)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375l.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375l.d
index 965b0e7..1c815ea 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375l.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375l.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375l.d(15): Warning: else is dangling, add { } after condition at fail_compilation/fail4375l.d(11)
+fail_compilation/fail4375l.d(17): Warning: else is dangling, add { } after condition at fail_compilation/fail4375l.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375m.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375m.d
index a6bdf1e..7cbf20f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375m.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375m.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375m.d(15): Warning: else is dangling, add { } after condition at fail_compilation/fail4375m.d(12)
+fail_compilation/fail4375m.d(17): Warning: else is dangling, add { } after condition at fail_compilation/fail4375m.d(14)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375o.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375o.d
index c37b219..fbfde4e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375o.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375o.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375o.d(15): Warning: else is dangling, add { } after condition at fail_compilation/fail4375o.d(11)
+fail_compilation/fail4375o.d(17): Warning: else is dangling, add { } after condition at fail_compilation/fail4375o.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375r.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375r.d
index 61923e2..dfa7731 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375r.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375r.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375r.d(17): Warning: else is dangling, add { } after condition at fail_compilation/fail4375r.d(11)
+fail_compilation/fail4375r.d(19): Warning: else is dangling, add { } after condition at fail_compilation/fail4375r.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375s.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375s.d
index cd4e5a0..f85a1db 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375s.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375s.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375s.d(17): Warning: else is dangling, add { } after condition at fail_compilation/fail4375s.d(11)
+fail_compilation/fail4375s.d(19): Warning: else is dangling, add { } after condition at fail_compilation/fail4375s.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375t.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375t.d
index 557761b..0fd1f4d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375t.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375t.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375t.d(14): Warning: else is dangling, add { } after condition at fail_compilation/fail4375t.d(11)
+fail_compilation/fail4375t.d(16): Warning: else is dangling, add { } after condition at fail_compilation/fail4375t.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375u.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375u.d
index 1028b78..8e2ea13 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375u.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375u.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375u.d(13): Warning: else is dangling, add { } after condition at fail_compilation/fail4375u.d(11)
+fail_compilation/fail4375u.d(15): Warning: else is dangling, add { } after condition at fail_compilation/fail4375u.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375v.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375v.d
index f4a6089..8b99a9c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375v.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375v.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375v.d(13): Warning: else is dangling, add { } after condition at fail_compilation/fail4375v.d(11)
+fail_compilation/fail4375v.d(15): Warning: else is dangling, add { } after condition at fail_compilation/fail4375v.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375w.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375w.d
index ae1ac21..ecfffb6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375w.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375w.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375w.d(13): Warning: else is dangling, add { } after condition at fail_compilation/fail4375w.d(11)
+fail_compilation/fail4375w.d(15): Warning: else is dangling, add { } after condition at fail_compilation/fail4375w.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375x.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375x.d
index 33c8eb2..f29a6e3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375x.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375x.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375x.d(14): Warning: else is dangling, add { } after condition at fail_compilation/fail4375x.d(11)
+fail_compilation/fail4375x.d(16): Warning: else is dangling, add { } after condition at fail_compilation/fail4375x.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375y.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375y.d
index bc79631..3111623 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375y.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375y.d
@@ -3,7 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4375y.d(16): Warning: else is dangling, add { } after condition at fail_compilation/fail4375y.d(11)
+fail_compilation/fail4375y.d(18): Warning: else is dangling, add { } after condition at fail_compilation/fail4375y.d(13)
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail44.d b/gcc/testsuite/gdc.test/fail_compilation/fail44.d
index b8916a0..e2ea40b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail44.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail44.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail44.d(18): Error: expression bar[i] is void and has no value
+fail_compilation/fail44.d(18): Error: expression `bar[i]` is `void` and has no value
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4421.d b/gcc/testsuite/gdc.test/fail_compilation/fail4421.d
index b82d701..3aedfc3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4421.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4421.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4421.d(16): Error: function fail4421.U1.__postblit destructors, postblits and invariants are not allowed in union U1
-fail_compilation/fail4421.d(17): Error: destructor fail4421.U1.~this destructors, postblits and invariants are not allowed in union U1
-fail_compilation/fail4421.d(18): Error: function fail4421.U1.__invariant1 destructors, postblits and invariants are not allowed in union U1
+fail_compilation/fail4421.d(16): Error: function `fail4421.U1.__postblit` destructors, postblits and invariants are not allowed in union `U1`
+fail_compilation/fail4421.d(17): Error: destructor `fail4421.U1.~this` destructors, postblits and invariants are not allowed in union `U1`
+fail_compilation/fail4421.d(18): Error: function `fail4421.U1.__invariant1` destructors, postblits and invariants are not allowed in union `U1`
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4448.d b/gcc/testsuite/gdc.test/fail_compilation/fail4448.d
index f8b2dbb..d5a0d4e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4448.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4448.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4448.d(19): Error: label `L1` has no break
-fail_compilation/fail4448.d(26): called from here: bug4448()
+fail_compilation/fail4448.d(19): Error: label `L1` has no `break`
+fail_compilation/fail4448.d(26): called from here: `bug4448()`
fail_compilation/fail4448.d(26): while evaluating: `static assert(bug4448() == 3)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail45.d b/gcc/testsuite/gdc.test/fail_compilation/fail45.d
index 3380fe4..503ac61 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail45.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail45.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail45.d(10): Error: variable fail45.main.O cannot be declared to be a function
+fail_compilation/fail45.d(10): Error: variable `fail45.main.O` cannot be declared to be a function
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4517.d b/gcc/testsuite/gdc.test/fail_compilation/fail4517.d
deleted file mode 100644
index f3fe031..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4517.d
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail4517.d(16): Error: `enum` member `B` not represented in `final switch`
----
-*/
-
-enum E : ushort
-{
- A, B
-}
-
-void main()
-{
- E e;
- final switch(e)
- {
- case E.A:
- break;
- }
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4544.d b/gcc/testsuite/gdc.test/fail_compilation/fail4544.d
new file mode 100644
index 0000000..cf1554d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4544.d
@@ -0,0 +1,23 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail4544.d(15): Error: character constant has multiple characters
+fail_compilation/fail4544.d(16): Error: `0x` isn't a valid integer literal, use `0x0` instead
+fail_compilation/fail4544.d(16): Error: no identifier for declarator `int`
+fail_compilation/fail4544.d(17): Error: unterminated character constant
+fail_compilation/fail4544.d(18): Error: character constant has multiple characters
+---
+*/
+
+int foo(char n, int m)
+{
+ int k = 5;
+ char c = 'asd';
+ int 0x = 'k';
+ foo('dasadasdaasdasdaslkdhasdlashdsalk, xxx);
+ goo('asdasdsa');
+ for (int i = 0; i < 10; i++)
+ {
+ k++;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail46.d b/gcc/testsuite/gdc.test/fail_compilation/fail46.d
index a62d163..9401b92 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail46.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail46.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail46.d(19): Error: need 'this' for 'bug' of type 'int()'
+fail_compilation/fail46.d(19): Error: need `this` for `bug` of type `int()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4611.d b/gcc/testsuite/gdc.test/fail_compilation/fail4611.d
index 02fcc2e..030c47c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4611.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4611.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail4611.d(15): Error: Vec[2147483647] size 4 * 2147483647 exceeds 0x7fffffff size limit for static array
+fail_compilation/fail4611.d(15): Error: `Vec[$n$]` size 4 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4923.d b/gcc/testsuite/gdc.test/fail_compilation/fail4923.d
new file mode 100644
index 0000000..3239cff
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4923.d
@@ -0,0 +1,13 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail4923.d(4): Error: immutable variable `bar` initialization is not allowed in `static this`
+fail_compilation/fail4923.d(4): Use `shared static this` instead.
+---
+*/
+#line 1
+immutable int bar;
+static this()
+{
+ bar = 42;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail50.d b/gcc/testsuite/gdc.test/fail_compilation/fail50.d
index 9cd2983..36bf382 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail50.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail50.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail50.d(12): Error: need 'this' for address of a
-fail_compilation/fail50.d(12): Error: variable a cannot be read at compile time
+fail_compilation/fail50.d(12): Error: need `this` for address of `a`
+fail_compilation/fail50.d(12): Error: variable `a` cannot be read at compile time
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail51.d b/gcc/testsuite/gdc.test/fail_compilation/fail51.d
index 41a27ca..b5a11d4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail51.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail51.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail51.d(11): Error: interface fail51.B circular inheritance of interface
+fail_compilation/fail51.d(11): Error: interface `fail51.B` circular inheritance of interface
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail5153.d b/gcc/testsuite/gdc.test/fail_compilation/fail5153.d
new file mode 100644
index 0000000..21de06e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail5153.d
@@ -0,0 +1,28 @@
+// https://issues.dlang.org/show_bug.cgi?id=5153
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail5153.d(26): Error: cannot implicitly convert expression `new Foo(0)` of type `Foo*` to `Foo`
+fail_compilation/fail5153.d(26): Perhaps remove the `new` keyword?
+---
+*/
+
+class Foo2
+{
+ this(int) {}
+}
+
+struct Foo {
+ int x;
+ this(int x_)
+ {
+ this.x = x_;
+ }
+
+ this(Foo2) {}
+}
+void main() {
+ Foo f = new Foo(0);
+ Foo f2 = new Foo2(0);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail52.d b/gcc/testsuite/gdc.test/fail_compilation/fail52.d
index 9b662de..9743be2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail52.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail52.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail52.d(10): Error: class fail52.C circular inheritance
+fail_compilation/fail52.d(10): Error: class `fail52.C` circular inheritance
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail54.d b/gcc/testsuite/gdc.test/fail_compilation/fail54.d
index aa95b1d..e52c533 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail54.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail54.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail54.d(22): Error: incompatible types for ((0) == (Exception)): cannot use '==' with types
+fail_compilation/fail54.d(22): Error: incompatible types for `(0) == (Exception)`: cannot use `==` with types
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail59.d b/gcc/testsuite/gdc.test/fail_compilation/fail59.d
index 63fab5e..8c51311 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail59.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail59.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail59.d(50): Error: outer class C1 'this' needed to 'new' nested class C2
+fail_compilation/fail59.d(50): Error: outer class `C1` `this` needed to `new` nested class `C2`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail61.d b/gcc/testsuite/gdc.test/fail_compilation/fail61.d
index e9daa61..90c3b39 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail61.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail61.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail61.d(22): Error: no property 'B' for type 'fail61.A.B'
-fail_compilation/fail61.d(23): Error: no property 'B' for type 'fail61.A.B'
-fail_compilation/fail61.d(32): Error: no property 'A2' for type 'fail61.B2'
-fail_compilation/fail61.d(41): Error: this for foo needs to be type B3 not type fail61.C3
+fail_compilation/fail61.d(22): Error: no property `B` for type `fail61.A.B`
+fail_compilation/fail61.d(23): Error: no property `B` for type `fail61.A.B`
+fail_compilation/fail61.d(32): Error: no property `A2` for type `fail61.B2`
+fail_compilation/fail61.d(41): Error: `this` for `foo` needs to be type `B3` not type `fail61.C3`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6107.d b/gcc/testsuite/gdc.test/fail_compilation/fail6107.d
index 4d79b0c..656b3cf 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail6107.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail6107.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail6107.d(10): Error: variable fail6107.Foo.__ctor is not a constructor; identifiers starting with __ are reserved for the implementation
-fail_compilation/fail6107.d(14): Error: variable fail6107.Bar.__ctor is not a constructor; identifiers starting with __ are reserved for the implementation
+fail_compilation/fail6107.d(10): Error: variable `fail6107.Foo.__ctor` is not a constructor; identifiers starting with `__` are reserved for the implementation
+fail_compilation/fail6107.d(14): Error: variable `fail6107.Bar.__ctor` is not a constructor; identifiers starting with `__` are reserved for the implementation
---
*/
struct Foo
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail62.d b/gcc/testsuite/gdc.test/fail_compilation/fail62.d
index caa7843..6e939db 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail62.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail62.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail62.d(11): Error: version Foo defined after use
+fail_compilation/fail62.d(11): Error: version `Foo` defined after use
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6242.d b/gcc/testsuite/gdc.test/fail_compilation/fail6242.d
index 08f5de3..cb2de2c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail6242.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail6242.d
@@ -6,4 +6,4 @@ fail_compilation/fail6242.d(9): Error: cannot implicitly override base class met
*/
class A { void fun(int) {} }
-class B : A { void fun(int x) in { assert(x > 0); } body {} }
+class B : A { void fun(int x) in { assert(x > 0); } do {} }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail63.d b/gcc/testsuite/gdc.test/fail_compilation/fail63.d
index 4af83ec..e4080eb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail63.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail63.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail63.d(11): Error: debug Foo defined after use
+fail_compilation/fail63.d(11): Error: debug `Foo` defined after use
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6334.d b/gcc/testsuite/gdc.test/fail_compilation/fail6334.d
index 3bb6b77..7abdb9e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail6334.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail6334.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail6334.d(12): Error: static assert `0` is false
+fail_compilation/fail6334.d(13): Error: static assert: `0` is false
+fail_compilation/fail6334.d(11): instantiated from here: `T2!()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6453.d b/gcc/testsuite/gdc.test/fail_compilation/fail6453.d
index e1db9f4..f6ce89f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail6453.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail6453.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail6453.d(13): Error: struct fail6453.S6453x mixing invariants with shared/synchronized differene is not supported
-fail_compilation/fail6453.d(18): Error: class fail6453.C6453y mixing invariants with shared/synchronized differene is not supported
-fail_compilation/fail6453.d(23): Error: class fail6453.C6453z mixing invariants with shared/synchronized differene is not supported
+fail_compilation/fail6453.d(13): Error: struct `fail6453.S6453x` mixing invariants with different `shared`/`synchronized` qualifiers is not supported
+fail_compilation/fail6453.d(18): Error: class `fail6453.C6453y` mixing invariants with different `shared`/`synchronized` qualifiers is not supported
+fail_compilation/fail6453.d(23): Error: class `fail6453.C6453z` mixing invariants with different `shared`/`synchronized` qualifiers is not supported
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail66.d b/gcc/testsuite/gdc.test/fail_compilation/fail66.d
index 5c352a5..5820ca5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail66.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail66.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail66.d(11): Error: constructor fail66.C1.this missing initializer for const field y
+fail_compilation/fail66.d(11): Error: constructor `fail66.C1.this` missing initializer for const field `y`
---
*/
@@ -14,7 +14,7 @@ class C1
/*
TEST_OUTPUT:
---
-fail_compilation/fail66.d(28): Error: cannot modify const expression c.y
+fail_compilation/fail66.d(28): Error: cannot modify `const` expression `c.y`
---
*/
class C2
@@ -31,7 +31,7 @@ void test2()
/*
TEST_OUTPUT:
---
-fail_compilation/fail66.d(43): Error: cannot modify const expression this.y
+fail_compilation/fail66.d(43): Error: cannot modify `const` expression `this.y`
---
*/
class C3
@@ -47,7 +47,7 @@ class C3
/*
TEST_OUTPUT:
---
-fail_compilation/fail66.d(59): Error: cannot modify const expression x
+fail_compilation/fail66.d(59): Error: cannot modify `const` expression `x`
---
*/
class C4
@@ -63,7 +63,7 @@ class C4
/*
TEST_OUTPUT:
---
-fail_compilation/fail66.d(73): Error: cannot modify const expression z5
+fail_compilation/fail66.d(73): Error: cannot modify `const` expression `z5`
---
*/
const int z5;
@@ -76,7 +76,7 @@ void test5()
/*
TEST_OUTPUT:
---
-fail_compilation/fail66.d(89): Error: cannot modify const expression c.y
+fail_compilation/fail66.d(89): Error: cannot modify `const` expression `c.y`
---
*/
class C6
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6652.d b/gcc/testsuite/gdc.test/fail_compilation/fail6652.d
index 45a3f5a..78cea67 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail6652.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail6652.d
@@ -1,15 +1,15 @@
// PERMUTE_ARGS: -w -dw -de -d
/******************************************/
-// 6652
+// https://issues.dlang.org/show_bug.cgi?id=6652
/*
TEST_OUTPUT:
---
-fail_compilation/fail6652.d(20): Error: cannot modify const expression i
-fail_compilation/fail6652.d(25): Error: cannot modify const expression i
-fail_compilation/fail6652.d(30): Error: cannot modify const expression i
-fail_compilation/fail6652.d(35): Error: cannot modify const expression i
+fail_compilation/fail6652.d(20): Error: cannot modify `const` expression `i`
+fail_compilation/fail6652.d(25): Error: cannot modify `const` expression `i`
+fail_compilation/fail6652.d(30): Error: cannot modify `const` expression `i`
+fail_compilation/fail6652.d(35): Error: cannot modify `const` expression `i`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6795.d b/gcc/testsuite/gdc.test/fail_compilation/fail6795.d
index d714f20..584a467 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail6795.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail6795.d
@@ -1,34 +1,27 @@
-// 6795
+// https://issues.dlang.org/show_bug.cgi?id=6795
/*
TEST_OUTPUT:
---
-fail_compilation/fail6795.d(12): Error: constant 0 is not an lvalue
-fail_compilation/fail6795.d(13): Error: constant 0 is not an lvalue
----
-*/
-
-void main() {
- enum int[] array = [0];
- array[0]++;
- array[0] += 3;
-}
-
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail6795.d(31): Error: constant 0 is not an lvalue
-fail_compilation/fail6795.d(32): Error: constant 0 is not an lvalue
-fail_compilation/fail6795.d(33): Error: constant 0 is not an lvalue
+fail_compilation/fail6795.d(19): Error: `[0][0]` is not an lvalue and cannot be modified
+fail_compilation/fail6795.d(20): Error: `[0:0][0]` is not an lvalue and cannot be modified
+fail_compilation/fail6795.d(22): Error: `[0][0]` is not an lvalue and cannot be modified
+fail_compilation/fail6795.d(23): Error: `[0:0][0]` is not an lvalue and cannot be modified
+fail_compilation/fail6795.d(25): Error: `[0][0]` is not an lvalue and cannot be modified
+fail_compilation/fail6795.d(26): Error: `[0:0][0]` is not an lvalue and cannot be modified
---
*/
void test_wrong_line_num()
{
- enum int[] da = [0];
enum int[1] sa = [0];
enum int[int] aa = [0:0];
- da[0] += 3;
- sa[0] += 3;
- aa[0] += 3;
+ sa[0]++;
+ --aa[0];
+
+ sa[0] *= 3;
+ aa[0] /= 3;
+
+ auto ps = &sa[0];
+ auto pa = &aa[0];
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6889.d b/gcc/testsuite/gdc.test/fail_compilation/fail6889.d
index 4d86256..aa18977 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail6889.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail6889.d
@@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail6889.d(16): Error: cannot goto out of `scope(success)` block
-fail_compilation/fail6889.d(17): Error: cannot goto in to `scope(success)` block
-fail_compilation/fail6889.d(19): Error: return statements cannot be in `scope(success)` bodies
-fail_compilation/fail6889.d(23): Error: continue is not inside `scope(success)` bodies
-fail_compilation/fail6889.d(24): Error: break is not inside `scope(success)` bodies
-fail_compilation/fail6889.d(29): Error: continue is not inside `scope(success)` bodies
-fail_compilation/fail6889.d(30): Error: break is not inside `scope(success)` bodies
+fail_compilation/fail6889.d(16): Error: cannot `goto` out of `scope(success)` block
+fail_compilation/fail6889.d(17): Error: cannot `goto` in to `scope(success)` block
+fail_compilation/fail6889.d(19): Error: `return` statements cannot be in `scope(success)` bodies
+fail_compilation/fail6889.d(23): Error: `continue` is not allowed inside `scope(success)` bodies
+fail_compilation/fail6889.d(24): Error: `break` is not allowed inside `scope(success)` bodies
+fail_compilation/fail6889.d(29): Error: `continue` is not allowed inside `scope(success)` bodies
+fail_compilation/fail6889.d(30): Error: `break` is not allowed inside `scope(success)` bodies
---
*/
void test_success()
@@ -46,7 +46,7 @@ L1:
/*
TEST_OUTPUT:
---
-fail_compilation/fail6889.d(56): Error: cannot goto in to `scope(failure)` block
+fail_compilation/fail6889.d(56): Error: cannot `goto` in to `scope(failure)` block
---
*/
void test_failure()
@@ -85,13 +85,13 @@ L1:
/*
TEST_OUTPUT:
---
-fail_compilation/fail6889.d(100): Error: cannot goto out of `scope(exit)` block
-fail_compilation/fail6889.d(101): Error: cannot goto in to `scope(exit)` block
-fail_compilation/fail6889.d(103): Error: return statements cannot be in `scope(exit)` bodies
-fail_compilation/fail6889.d(107): Error: continue is not inside `scope(exit)` bodies
-fail_compilation/fail6889.d(108): Error: break is not inside `scope(exit)` bodies
-fail_compilation/fail6889.d(113): Error: continue is not inside `scope(exit)` bodies
-fail_compilation/fail6889.d(114): Error: break is not inside `scope(exit)` bodies
+fail_compilation/fail6889.d(100): Error: cannot `goto` out of `scope(exit)` block
+fail_compilation/fail6889.d(101): Error: cannot `goto` in to `scope(exit)` block
+fail_compilation/fail6889.d(103): Error: `return` statements cannot be in `scope(exit)` bodies
+fail_compilation/fail6889.d(107): Error: `continue` is not allowed inside `scope(exit)` bodies
+fail_compilation/fail6889.d(108): Error: `break` is not allowed inside `scope(exit)` bodies
+fail_compilation/fail6889.d(113): Error: `continue` is not allowed inside `scope(exit)` bodies
+fail_compilation/fail6889.d(114): Error: `break` is not allowed inside `scope(exit)` bodies
---
*/
void test_exit()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7173.d b/gcc/testsuite/gdc.test/fail_compilation/fail7173.d
index 05ba7f9..2a2e46b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7173.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7173.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail7173.d(23): Error: expression `b1._a.opBinary(b2._a).fun()` is `void` and has no value
+fail_compilation/fail7173.d(23): Error: cannot implicitly convert expression `b1._a.opBinary(b2._a).fun()` of type `void` to `B`
---
*/
struct A{
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail73.d b/gcc/testsuite/gdc.test/fail_compilation/fail73.d
index dc83e5d..b9b480d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail73.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail73.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail73.d(20): Error: case not in switch statement
+fail_compilation/fail73.d(20): Error: `case` not in `switch` statement
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7352.d b/gcc/testsuite/gdc.test/fail_compilation/fail7352.d
new file mode 100644
index 0000000..f5e8f9b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7352.d
@@ -0,0 +1,52 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail7352.d(42): Error: template instance `Type!(1)` does not match template declaration `Type(T)`
+fail_compilation/fail7352.d(43): Error: template instance `Type!(b)` does not match template declaration `Type(T)`
+fail_compilation/fail7352.d(43): `b` is not a type
+fail_compilation/fail7352.d(44): Error: template instance `Type!(function () pure nothrow @nogc @safe => 1)` does not match template declaration `Type(T)`
+fail_compilation/fail7352.d(45): Error: template instance `Type!(fun)` does not match template declaration `Type(T)`
+fail_compilation/fail7352.d(45): `fun` is not a type
+fail_compilation/fail7352.d(47): Error: template instance `Immutable!int` does not match template declaration `Immutable(T : immutable(T))`
+fail_compilation/fail7352.d(49): Error: template instance `Value!int` does not match template declaration `Value(string s)`
+fail_compilation/fail7352.d(50): Error: template instance `Value!(1)` does not match template declaration `Value(string s)`
+fail_compilation/fail7352.d(51): Error: template instance `Value!(fun)` does not match template declaration `Value(string s)`
+fail_compilation/fail7352.d(51): `fun` is not of a value of type `string`
+---
+*/
+
+template Type(T)
+{
+}
+
+template Immutable(T : immutable(T))
+{
+ alias Immutable = T;
+}
+
+template Value(string s)
+{
+ auto x = s;
+}
+
+int fun(int i)
+{
+ return i;
+}
+
+void main()
+{
+ enum a = 1;
+ int b;
+
+ Type!a testTypeValue;
+ Type!b testTypeVar;
+ Type!(() => 1) testTypeFuncLiteral;
+ Type!fun testTypeFunc;
+
+ Immutable!int testImmutable;
+
+ auto testValueType = Value!int.x;
+ auto testValueWrongType = Value!a.x;
+ auto testValueFunc = Value!fun.x;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail74.d b/gcc/testsuite/gdc.test/fail_compilation/fail74.d
index c038b20a..79449eb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail74.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail74.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail74.d(13): Error: cannot append type C[1] to type C[1]
+fail_compilation/fail74.d(13): Error: cannot append type `C[1]` to type `C[1]`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7443.d b/gcc/testsuite/gdc.test/fail_compilation/fail7443.d
new file mode 100644
index 0000000..2c5c940
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7443.d
@@ -0,0 +1,14 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail7443.d(11): Error: `static` has no effect on a constructor inside a `static` block. Use `static this()`
+fail_compilation/fail7443.d(12): Error: `shared static` has no effect on a constructor inside a `shared static` block. Use `shared static this()`
+---
+*/
+
+class Foo
+{
+ public static { this() {}}
+ public shared static { this() {}}
+ public {this(int) {}}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail75.d b/gcc/testsuite/gdc.test/fail_compilation/fail75.d
index 1059e36..0b0b8e0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail75.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail75.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail75.d(13): Error: cannot append type fail75.C to type C[1]
+fail_compilation/fail75.d(13): Error: cannot append type `fail75.C` to type `C[1]`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail76.d b/gcc/testsuite/gdc.test/fail_compilation/fail76.d
index c2b7e59..673fc7a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail76.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail76.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail76.d(9): Error: alias fail76.a conflicts with alias fail76.a at fail_compilation/fail76.d(8)
+fail_compilation/fail76.d(9): Error: alias `fail76.a` conflicts with alias `fail76.a` at fail_compilation/fail76.d(8)
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7848.d b/gcc/testsuite/gdc.test/fail_compilation/fail7848.d
index 77fcdfa..4fc269e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7848.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7848.d
@@ -3,26 +3,18 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail7848.d(35): Error: pure function 'fail7848.C.__unittestL33_$n$' cannot call impure function 'fail7848.func'
-fail_compilation/fail7848.d(35): Error: @safe function 'fail7848.C.__unittestL33_$n$' cannot call @system function 'fail7848.func'
-fail_compilation/fail7848.d(35): Error: @nogc function 'fail7848.C.__unittestL33_$n$' cannot call non-@nogc function 'fail7848.func'
-fail_compilation/fail7848.d(35): Error: function `fail7848.func` is not nothrow
-fail_compilation/fail7848.d(33): Error: nothrow function `fail7848.C.__unittestL33_$n$` may throw
-fail_compilation/fail7848.d(40): Error: pure function 'fail7848.C.__invariant2' cannot call impure function 'fail7848.func'
-fail_compilation/fail7848.d(40): Error: @safe function 'fail7848.C.__invariant2' cannot call @system function 'fail7848.func'
-fail_compilation/fail7848.d(40): Error: @nogc function 'fail7848.C.__invariant2' cannot call non-@nogc function 'fail7848.func'
-fail_compilation/fail7848.d(40): Error: function `fail7848.func` is not nothrow
-fail_compilation/fail7848.d(38): Error: nothrow function `fail7848.C.__invariant2` may throw
-fail_compilation/fail7848.d(45): Error: pure allocator 'fail7848.C.new' cannot call impure function 'fail7848.func'
-fail_compilation/fail7848.d(45): Error: @safe allocator 'fail7848.C.new' cannot call @system function 'fail7848.func'
-fail_compilation/fail7848.d(45): Error: @nogc allocator 'fail7848.C.new' cannot call non-@nogc function 'fail7848.func'
-fail_compilation/fail7848.d(45): Error: function `fail7848.func` is not nothrow
-fail_compilation/fail7848.d(43): Error: nothrow allocator `fail7848.C.new` may throw
-fail_compilation/fail7848.d(51): Error: pure deallocator 'fail7848.C.delete' cannot call impure function 'fail7848.func'
-fail_compilation/fail7848.d(51): Error: @safe deallocator 'fail7848.C.delete' cannot call @system function 'fail7848.func'
-fail_compilation/fail7848.d(51): Error: @nogc deallocator 'fail7848.C.delete' cannot call non-@nogc function 'fail7848.func'
-fail_compilation/fail7848.d(51): Error: function `fail7848.func` is not nothrow
-fail_compilation/fail7848.d(49): Error: nothrow deallocator `fail7848.C.delete` may throw
+fail_compilation/fail7848.d(27): Error: `pure` function `fail7848.C.__unittest_L25_C30` cannot call impure function `fail7848.func`
+fail_compilation/fail7848.d(27): Error: `@safe` function `fail7848.C.__unittest_L25_C30` cannot call `@system` function `fail7848.func`
+fail_compilation/fail7848.d(21): `fail7848.func` is declared here
+fail_compilation/fail7848.d(27): Error: `@nogc` function `fail7848.C.__unittest_L25_C30` cannot call non-@nogc function `fail7848.func`
+fail_compilation/fail7848.d(27): Error: function `fail7848.func` is not `nothrow`
+fail_compilation/fail7848.d(25): Error: `nothrow` function `fail7848.C.__unittest_L25_C30` may throw
+fail_compilation/fail7848.d(32): Error: `pure` function `fail7848.C.__invariant1` cannot call impure function `fail7848.func`
+fail_compilation/fail7848.d(32): Error: `@safe` function `fail7848.C.__invariant1` cannot call `@system` function `fail7848.func`
+fail_compilation/fail7848.d(21): `fail7848.func` is declared here
+fail_compilation/fail7848.d(32): Error: `@nogc` function `fail7848.C.__invariant1` cannot call non-@nogc function `fail7848.func`
+fail_compilation/fail7848.d(32): Error: function `fail7848.func` is not `nothrow`
+fail_compilation/fail7848.d(30): Error: `nothrow` function `fail7848.C.__invariant1` may throw
---
*/
@@ -39,15 +31,4 @@ class C
{
func();
}
-
- @safe pure nothrow @nogc new (size_t sz)
- {
- func();
- return null;
- }
-
- @safe pure nothrow @nogc delete (void* p)
- {
- func();
- }
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7862.d b/gcc/testsuite/gdc.test/fail_compilation/fail7862.d
index a81bc65..b408b44 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7862.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7862.d
@@ -3,12 +3,12 @@ TEST_OUTPUT:
---
A: false
A: false
-fail_compilation/fail7862.d(26): Error: template instance nonExistent!() template 'nonExistent' is not defined
-fail_compilation/fail7862.d(25): Error: template instance fail7862.B!(A) error instantiating
+fail_compilation/fail7862.d(26): Error: template instance `nonExistent!()` template `nonExistent` is not defined
+fail_compilation/fail7862.d(25): Error: template instance `fail7862.B!(A)` error instantiating
---
*/
-// 7862
+// https://issues.dlang.org/show_bug.cgi?id=7862
template B(T) {
mixin(
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail79.d b/gcc/testsuite/gdc.test/fail_compilation/fail79.d
index da06984..93fb7cb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail79.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail79.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail79.d(13): Error: incompatible types for ((& a) + (& b)): both operands are of type 'int*'
+fail_compilation/fail79.d(13): Error: incompatible types for `(& a) + (& b)`: both operands are of type `int*`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7903.d b/gcc/testsuite/gdc.test/fail_compilation/fail7903.d
index 7759f1a..18168ea 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7903.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7903.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail7903.d(21): Error: variable fail7903.F1.x Field members of a synchronized class cannot be public
-fail_compilation/fail7903.d(22): Error: variable fail7903.F1.y Field members of a synchronized class cannot be export
-fail_compilation/fail7903.d(27): Error: variable fail7903.F2.x Field members of a synchronized class cannot be public
+fail_compilation/fail7903.d(21): Error: variable `fail7903.F1.x` Field members of a `synchronized` class cannot be `public`
+fail_compilation/fail7903.d(22): Error: variable `fail7903.F1.y` Field members of a `synchronized` class cannot be `export`
+fail_compilation/fail7903.d(27): Error: variable `fail7903.F2.x` Field members of a `synchronized` class cannot be `public`
---
*/
synchronized class K1
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8009.d b/gcc/testsuite/gdc.test/fail_compilation/fail8009.d
index 19a0712..a06dec5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail8009.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail8009.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail8009.d(9): Error: template `fail8009.filter` cannot deduce function from argument types `!()(void)`, candidates are:
-fail_compilation/fail8009.d(8): `filter(R)(scope bool delegate(ref BAD!R) func)`
+fail_compilation/fail8009.d(9): Error: template `fail8009.filter` cannot deduce function from argument types `!()(void)`
+fail_compilation/fail8009.d(8): Candidate is: `filter(R)(scope bool delegate(ref BAD!R) func)`
---
*/
void filter(R)(scope bool delegate(ref BAD!R) func) { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail809.d b/gcc/testsuite/gdc.test/fail_compilation/fail809.d
new file mode 100644
index 0000000..b83639b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail809.d
@@ -0,0 +1,12 @@
+// REQUIRED_ARGS: -preview=dip1000
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail809.d(11): Error: scope variable `dg_` may not be returned
+---
+*/
+int delegate() test(lazy int dg)
+{
+ int delegate() dg_ = &dg;
+ return dg_;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d b/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d
index fb2f6fa..11facfd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d
@@ -18,8 +18,8 @@ class ResourceManager
class Test
{
- import std.file;
- import std.path;
+
+
static Image[] images;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d b/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d
index 52d23d3..59c890e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d
@@ -18,8 +18,8 @@ class ResourceManager
class Test
{
- import std.file;
- import std.path;
+
+
static Image[] images;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8217.d b/gcc/testsuite/gdc.test/fail_compilation/fail8217.d
index e74b7c3..477ca63 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail8217.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail8217.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail8217.d(22): Error: this for foo needs to be type D not type fail8217.D.C
+fail_compilation/fail8217.d(22): Error: `this` for `foo` needs to be type `D` not type `fail8217.D.C`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8262.d b/gcc/testsuite/gdc.test/fail_compilation/fail8262.d
new file mode 100644
index 0000000..2df1bca
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail8262.d
@@ -0,0 +1,33 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/fail8262.d(32): Error: initializer must be an expression, not `Tuple8262!1`
+fail_compilation/fail8262.d(27): Error: template instance `fail8262.T8262!(Tuple8262!1)` error instantiating
+fail_compilation/fail8262.d(19): Error: cannot implicitly convert expression `S(0)` of type `S` to `int`
+---
+ * https://issues.dlang.org/show_bug.cgi?id=8262
+ */
+
+template Seq(T...) { alias T Seq; }
+
+struct S
+{
+ int s;
+ alias Seq!s _;
+ alias _ this;
+}
+
+int si = S.init;
+
+struct Tuple8262(T...)
+{
+ alias T expand;
+ alias expand this;
+}
+
+auto data = T8262!(Tuple8262!1);
+//pragma(msg, data);
+
+template T8262(T)
+{
+ immutable(int) T8262 = T;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8373.d b/gcc/testsuite/gdc.test/fail_compilation/fail8373.d
index d921707..2fb478d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail8373.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail8373.d
@@ -1,14 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail8373.d(21): Error: fail8373.fun1 called with argument types (int) matches both:
-fail_compilation/fail8373.d(15): fail8373.fun1!().fun1!int.fun1(int)
+fail_compilation/fail8373.d(21): Error: `fail8373.fun1` called with argument types `(int)` matches both:
+fail_compilation/fail8373.d(15): `fail8373.fun1!().fun1!int.fun1(int)`
and:
-fail_compilation/fail8373.d(16): fail8373.fun1!int.fun1(int)
-fail_compilation/fail8373.d(22): Error: fail8373.fun2 called with argument types (int) matches both:
-fail_compilation/fail8373.d(18): fail8373.fun2!int.fun2(int)
+fail_compilation/fail8373.d(16): `fail8373.fun1!int.fun1(int)`
+fail_compilation/fail8373.d(22): Error: `fail8373.fun2` called with argument types `(int)` matches both:
+fail_compilation/fail8373.d(18): `fail8373.fun2!int.fun2(int)`
and:
-fail_compilation/fail8373.d(19): fail8373.fun2!().fun2!int.fun2(int)
+fail_compilation/fail8373.d(19): `fail8373.fun2!().fun2!int.fun2(int)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail86.d b/gcc/testsuite/gdc.test/fail_compilation/fail86.d
index a0ccb7c..4f56e95 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail86.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail86.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail86.d(12): Error: alias Foo recursive alias declaration
+fail_compilation/fail86.d(12): Error: alias `Foo` recursive alias declaration
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8631.d b/gcc/testsuite/gdc.test/fail_compilation/fail8631.d
index 3aada74..4f5b076 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail8631.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail8631.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail8631.d(14): Error: function fail8631.D.foo does not override any function, did you mean to override 'fail8631.B.foo'?
+fail_compilation/fail8631.d(14): Error: function `shared const int fail8631.D.foo()` does not override any function, did you mean to override `immutable int fail8631.B.foo()`?
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8724.d b/gcc/testsuite/gdc.test/fail_compilation/fail8724.d
index 7f9cba2..c5ca98b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail8724.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail8724.d
@@ -3,7 +3,7 @@
TEST_OUTPUT:
---
fail_compilation/fail8724.d(14): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail8724.d(12): Error: nothrow constructor `fail8724.Foo.this` may throw
+fail_compilation/fail8724.d(12): Error: `nothrow` constructor `fail8724.Foo.this` may throw
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9.d b/gcc/testsuite/gdc.test/fail_compilation/fail9.d
index 6253774..0878995 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9.d(23): Error: no property 'Vector' for type 'fail9.Vector!int'
+fail_compilation/fail9.d(23): Error: no property `Vector` for type `fail9.Vector!int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9063.d b/gcc/testsuite/gdc.test/fail_compilation/fail9063.d
index 962fb04..36f04ad 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9063.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9063.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9063.d(9): Error: static assert "msg"
+fail_compilation/fail9063.d(9): Error: static assert: "msg"
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9081.d b/gcc/testsuite/gdc.test/fail_compilation/fail9081.d
index 86c8887..3d65bea 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9081.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9081.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9081.d(12): Error: package core has no type
-fail_compilation/fail9081.d(13): Error: package stdc has no type
-fail_compilation/fail9081.d(14): Error: module stdio has no type
+fail_compilation/fail9081.d(12): Error: package `core` has no type
+fail_compilation/fail9081.d(13): Error: package `stdc` has no type
+fail_compilation/fail9081.d(14): Error: module `stdio` has no type
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail91.d b/gcc/testsuite/gdc.test/fail_compilation/fail91.d
index 59f80fd..41be801 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail91.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail91.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail91.d(12): Error: struct fail91.S unknown size
+fail_compilation/fail91.d(12): Error: struct `fail91.S` unknown size
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9199.d b/gcc/testsuite/gdc.test/fail_compilation/fail9199.d
index 00a87c3..2a5cd01 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9199.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9199.d
@@ -2,12 +2,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9199.d(13): Error: function fail9199.fc without 'this' cannot be const
-fail_compilation/fail9199.d(14): Error: function fail9199.fi without 'this' cannot be immutable
-fail_compilation/fail9199.d(15): Error: function fail9199.fw without 'this' cannot be inout
-fail_compilation/fail9199.d(16): Error: function fail9199.fs without 'this' cannot be shared
-fail_compilation/fail9199.d(17): Error: function fail9199.fsc without 'this' cannot be shared const
-fail_compilation/fail9199.d(18): Error: function fail9199.fsw without 'this' cannot be shared inout
+fail_compilation/fail9199.d(13): Error: function `fail9199.fc` without `this` cannot be `const`
+fail_compilation/fail9199.d(14): Error: function `fail9199.fi` without `this` cannot be `immutable`
+fail_compilation/fail9199.d(15): Error: function `fail9199.fw` without `this` cannot be `inout`
+fail_compilation/fail9199.d(16): Error: function `fail9199.fs` without `this` cannot be `shared`
+fail_compilation/fail9199.d(17): Error: function `fail9199.fsc` without `this` cannot be `shared const`
+fail_compilation/fail9199.d(18): Error: function `fail9199.fsw` without `this` cannot be `shared inout`
---
*/
void fc() const {}
@@ -20,12 +20,12 @@ void fsw() shared inout {}
/*
TEST_OUTPUT:
---
-fail_compilation/fail9199.d(33): Error: function fail9199.C.fc without 'this' cannot be const
-fail_compilation/fail9199.d(34): Error: function fail9199.C.fi without 'this' cannot be immutable
-fail_compilation/fail9199.d(35): Error: function fail9199.C.fw without 'this' cannot be inout
-fail_compilation/fail9199.d(36): Error: function fail9199.C.fs without 'this' cannot be shared
-fail_compilation/fail9199.d(37): Error: function fail9199.C.fsc without 'this' cannot be shared const
-fail_compilation/fail9199.d(38): Error: function fail9199.C.fsw without 'this' cannot be shared inout
+fail_compilation/fail9199.d(33): Error: function `fail9199.C.fc` without `this` cannot be `const`
+fail_compilation/fail9199.d(34): Error: function `fail9199.C.fi` without `this` cannot be `immutable`
+fail_compilation/fail9199.d(35): Error: function `fail9199.C.fw` without `this` cannot be `inout`
+fail_compilation/fail9199.d(36): Error: function `fail9199.C.fs` without `this` cannot be `shared`
+fail_compilation/fail9199.d(37): Error: function `fail9199.C.fsc` without `this` cannot be `shared const`
+fail_compilation/fail9199.d(38): Error: function `fail9199.C.fsw` without `this` cannot be `shared inout`
---
*/
class C
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail92.d b/gcc/testsuite/gdc.test/fail_compilation/fail92.d
index 8fa69bb..8e34199 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail92.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail92.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail92.d(15): Error: invalid foreach aggregate `t`
-fail_compilation/fail92.d(23): Error: template instance fail92.crash!(typeof(null)) error instantiating
+fail_compilation/fail92.d(15): Error: invalid `foreach` aggregate `t`
+fail_compilation/fail92.d(23): Error: template instance `fail92.crash!(typeof(null))` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9290.d b/gcc/testsuite/gdc.test/fail_compilation/fail9290.d
new file mode 100644
index 0000000..6b51b2b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9290.d
@@ -0,0 +1,17 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail9290.d(15): Error: slice `s1[]` is not mutable, struct `S` has immutable members
+fail_compilation/fail9290.d(16): Error: array `s1` is not mutable, struct `S` has immutable members
+---
+*/
+
+struct S { immutable int i; }
+
+void main()
+{
+ S[1] s1 = S(1);
+ S[1] s2 = S(2);
+ s1 = S(3);
+ s1 = s2;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail93.d b/gcc/testsuite/gdc.test/fail_compilation/fail93.d
index 4784038..b9ad294 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail93.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail93.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail93.d(13): Error: variable i is shadowing variable fail93.main.i
+fail_compilation/fail93.d(13): Error: variable `i` is shadowing variable `fail93.main.i`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9346.d b/gcc/testsuite/gdc.test/fail_compilation/fail9346.d
index 57d420f..19d0baa 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9346.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9346.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9346.d(26): Error: struct fail9346.S is not copyable because it is annotated with `@disable`
-fail_compilation/fail9346.d(27): Error: struct fail9346.S is not copyable because it is annotated with `@disable`
+fail_compilation/fail9346.d(26): Error: struct `fail9346.S` is not copyable because it has a disabled postblit
+fail_compilation/fail9346.d(27): Error: struct `fail9346.S` is not copyable because it has a disabled postblit
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9368.d b/gcc/testsuite/gdc.test/fail_compilation/fail9368.d
deleted file mode 100644
index 25e1360..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9368.d
+++ /dev/null
@@ -1,49 +0,0 @@
-// PERMUTE_ARGS:
-// REQUIRED_ARGS: -d
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail9368.d(20): Error: enum member `b` not represented in final switch
----
-*/
-
-enum E
-{
- a,
- b
-}
-
-void main()
-{
- alias E F;
- F f;
- final switch (f)
- {
- case F.a:
- }
-}
-
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail9368.d(41): Error: enum member `B` not represented in final switch
----
-*/
-
-enum G
-{
- A,B,C
-}
-
-void test286()
-{
- G e;
- final switch (e)
- {
- case G.A:
-// case G.B:
- case G.C:
- {}
- }
-}
-
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail94.d b/gcc/testsuite/gdc.test/fail_compilation/fail94.d
index 335b695..aa722bf 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail94.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail94.d
@@ -30,7 +30,7 @@ class B : A
{
printf("B.clone()\n");
}
- body { return ia; }
+ do { return ia; }
}
void main()
@@ -59,4 +59,3 @@ void main()
void bar(IA delegate() dg)
{
}
-
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9413.d b/gcc/testsuite/gdc.test/fail_compilation/fail9413.d
index 617c995..c17e713 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9413.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9413.d
@@ -1,24 +1,24 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9413.d(45): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9413.d(32): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9413.d(33): Error: variable fail9413.foo.bar.y cannot modify parameter 'y' in contract
-fail_compilation/fail9413.d(38): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9413.d(39): Error: variable fail9413.foo.bar.y cannot modify parameter 'y' in contract
-fail_compilation/fail9413.d(40): Error: variable fail9413.foo.bar.s cannot modify result 's' in contract
-fail_compilation/fail9413.d(50): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9413.d(73): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9413.d(74): Error: variable fail9413.foo.r cannot modify result 'r' in contract
-fail_compilation/fail9413.d(58): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9413.d(59): Error: variable fail9413.foo.r cannot modify result 'r' in contract
-fail_compilation/fail9413.d(60): Error: variable fail9413.foo.baz.y cannot modify parameter 'y' in contract
-fail_compilation/fail9413.d(65): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9413.d(66): Error: variable fail9413.foo.r cannot modify result 'r' in contract
-fail_compilation/fail9413.d(67): Error: variable fail9413.foo.baz.y cannot modify parameter 'y' in contract
-fail_compilation/fail9413.d(68): Error: variable fail9413.foo.baz.s cannot modify result 's' in contract
-fail_compilation/fail9413.d(79): Error: variable fail9413.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9413.d(80): Error: variable fail9413.foo.r cannot modify result 'r' in contract
+fail_compilation/fail9413.d(45): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9413.d(32): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9413.d(33): Error: variable `fail9413.foo.bar.y` cannot modify parameter `y` in contract
+fail_compilation/fail9413.d(38): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9413.d(39): Error: variable `fail9413.foo.bar.y` cannot modify parameter `y` in contract
+fail_compilation/fail9413.d(40): Error: variable `fail9413.foo.bar.s` cannot modify result `s` in contract
+fail_compilation/fail9413.d(50): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9413.d(73): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9413.d(74): Error: variable `fail9413.foo.r` cannot modify result `r` in contract
+fail_compilation/fail9413.d(58): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9413.d(59): Error: variable `fail9413.foo.r` cannot modify result `r` in contract
+fail_compilation/fail9413.d(60): Error: variable `fail9413.foo.baz.y` cannot modify parameter `y` in contract
+fail_compilation/fail9413.d(65): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9413.d(66): Error: variable `fail9413.foo.r` cannot modify result `r` in contract
+fail_compilation/fail9413.d(67): Error: variable `fail9413.foo.baz.y` cannot modify parameter `y` in contract
+fail_compilation/fail9413.d(68): Error: variable `fail9413.foo.baz.s` cannot modify result `s` in contract
+fail_compilation/fail9413.d(79): Error: variable `fail9413.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9413.d(80): Error: variable `fail9413.foo.r` cannot modify result `r` in contract
---
*/
@@ -40,7 +40,7 @@ in
s = 10; // err
a = 1; // OK
}
- body
+ do
{
x = 10; // err
y = 1; // OK
@@ -68,7 +68,7 @@ out(r)
s = 10; // err
a = 1; // OK
}
- body
+ do
{
x = 10; // err
r = 10; // err
@@ -79,7 +79,7 @@ out(r)
x = 10; // err
r = 10; // err
}
-body
+do
{
return 1;
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9414a.d b/gcc/testsuite/gdc.test/fail_compilation/fail9414a.d
index 4fd98d3..b6e2a6f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9414a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9414a.d
@@ -1,24 +1,24 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9414a.d(47): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414a.d(34): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414a.d(35): Error: variable fail9414a.C.foo.__require.bar.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414a.d(40): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414a.d(41): Error: variable fail9414a.C.foo.__require.bar.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414a.d(42): Error: variable fail9414a.C.foo.__require.bar.s cannot modify result 's' in contract
-fail_compilation/fail9414a.d(52): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414a.d(75): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414a.d(76): Error: variable fail9414a.C.foo.__ensure.r cannot modify result 'r' in contract
-fail_compilation/fail9414a.d(60): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414a.d(61): Error: variable fail9414a.C.foo.__ensure.r cannot modify result 'r' in contract
-fail_compilation/fail9414a.d(62): Error: variable fail9414a.C.foo.__ensure.baz.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414a.d(67): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414a.d(68): Error: variable fail9414a.C.foo.__ensure.r cannot modify result 'r' in contract
-fail_compilation/fail9414a.d(69): Error: variable fail9414a.C.foo.__ensure.baz.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414a.d(70): Error: variable fail9414a.C.foo.__ensure.baz.s cannot modify result 's' in contract
-fail_compilation/fail9414a.d(81): Error: variable fail9414a.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414a.d(82): Error: variable fail9414a.C.foo.__ensure.r cannot modify result 'r' in contract
+fail_compilation/fail9414a.d(47): Error: variable `fail9414a.C.foo.__require.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414a.d(34): Error: variable `fail9414a.C.foo.__require.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414a.d(35): Error: variable `fail9414a.C.foo.__require.bar.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414a.d(40): Error: variable `fail9414a.C.foo.__require.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414a.d(41): Error: variable `fail9414a.C.foo.__require.bar.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414a.d(42): Error: variable `fail9414a.C.foo.__require.bar.s` cannot modify result `s` in contract
+fail_compilation/fail9414a.d(52): Error: variable `fail9414a.C.foo.__require.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414a.d(75): Error: variable `fail9414a.C.foo.__ensure.x` cannot modify result `x` in contract
+fail_compilation/fail9414a.d(76): Error: variable `fail9414a.C.foo.__ensure.r` cannot modify result `r` in contract
+fail_compilation/fail9414a.d(60): Error: variable `fail9414a.C.foo.__ensure.x` cannot modify result `x` in contract
+fail_compilation/fail9414a.d(61): Error: variable `fail9414a.C.foo.__ensure.r` cannot modify result `r` in contract
+fail_compilation/fail9414a.d(62): Error: variable `fail9414a.C.foo.__ensure.baz.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414a.d(67): Error: variable `fail9414a.C.foo.__ensure.x` cannot modify result `x` in contract
+fail_compilation/fail9414a.d(68): Error: variable `fail9414a.C.foo.__ensure.r` cannot modify result `r` in contract
+fail_compilation/fail9414a.d(69): Error: variable `fail9414a.C.foo.__ensure.baz.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414a.d(70): Error: variable `fail9414a.C.foo.__ensure.baz.s` cannot modify result `s` in contract
+fail_compilation/fail9414a.d(81): Error: variable `fail9414a.C.foo.__ensure.x` cannot modify result `x` in contract
+fail_compilation/fail9414a.d(82): Error: variable `fail9414a.C.foo.__ensure.r` cannot modify result `r` in contract
---
*/
@@ -42,7 +42,7 @@ class C
s = 10; // err
a = 1; // OK
}
- body
+ do
{
x = 10; // err
y = 1; // OK
@@ -70,7 +70,7 @@ class C
s = 10; // err
a = 1; // OK
}
- body
+ do
{
x = 10; // err
r = 10; // err
@@ -81,7 +81,7 @@ class C
x = 10; // err
r = 10; // err
}
- body
+ do
{
return 1;
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9414b.d b/gcc/testsuite/gdc.test/fail_compilation/fail9414b.d
index 37bd12f..dbb76da 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9414b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9414b.d
@@ -1,24 +1,24 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9414b.d(47): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414b.d(34): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414b.d(35): Error: variable fail9414b.C.foo.__require.bar.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414b.d(40): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414b.d(41): Error: variable fail9414b.C.foo.__require.bar.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414b.d(42): Error: variable fail9414b.C.foo.__require.bar.s cannot modify result 's' in contract
-fail_compilation/fail9414b.d(52): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414b.d(75): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414b.d(76): Error: variable fail9414b.C.foo.__ensure.r cannot modify result 'r' in contract
-fail_compilation/fail9414b.d(60): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414b.d(61): Error: variable fail9414b.C.foo.__ensure.r cannot modify result 'r' in contract
-fail_compilation/fail9414b.d(62): Error: variable fail9414b.C.foo.__ensure.baz.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414b.d(67): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414b.d(68): Error: variable fail9414b.C.foo.__ensure.r cannot modify result 'r' in contract
-fail_compilation/fail9414b.d(69): Error: variable fail9414b.C.foo.__ensure.baz.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414b.d(70): Error: variable fail9414b.C.foo.__ensure.baz.s cannot modify result 's' in contract
-fail_compilation/fail9414b.d(81): Error: variable fail9414b.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414b.d(82): Error: variable fail9414b.C.foo.__ensure.r cannot modify result 'r' in contract
+fail_compilation/fail9414b.d(47): Error: variable `fail9414b.C.foo.__require.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414b.d(34): Error: variable `fail9414b.C.foo.__require.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414b.d(35): Error: variable `fail9414b.C.foo.__require.bar.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414b.d(40): Error: variable `fail9414b.C.foo.__require.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414b.d(41): Error: variable `fail9414b.C.foo.__require.bar.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414b.d(42): Error: variable `fail9414b.C.foo.__require.bar.s` cannot modify result `s` in contract
+fail_compilation/fail9414b.d(52): Error: variable `fail9414b.C.foo.__require.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414b.d(75): Error: variable `fail9414b.C.foo.__ensure.x` cannot modify result `x` in contract
+fail_compilation/fail9414b.d(76): Error: variable `fail9414b.C.foo.__ensure.r` cannot modify result `r` in contract
+fail_compilation/fail9414b.d(60): Error: variable `fail9414b.C.foo.__ensure.x` cannot modify result `x` in contract
+fail_compilation/fail9414b.d(61): Error: variable `fail9414b.C.foo.__ensure.r` cannot modify result `r` in contract
+fail_compilation/fail9414b.d(62): Error: variable `fail9414b.C.foo.__ensure.baz.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414b.d(67): Error: variable `fail9414b.C.foo.__ensure.x` cannot modify result `x` in contract
+fail_compilation/fail9414b.d(68): Error: variable `fail9414b.C.foo.__ensure.r` cannot modify result `r` in contract
+fail_compilation/fail9414b.d(69): Error: variable `fail9414b.C.foo.__ensure.baz.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414b.d(70): Error: variable `fail9414b.C.foo.__ensure.baz.s` cannot modify result `s` in contract
+fail_compilation/fail9414b.d(81): Error: variable `fail9414b.C.foo.__ensure.x` cannot modify result `x` in contract
+fail_compilation/fail9414b.d(82): Error: variable `fail9414b.C.foo.__ensure.r` cannot modify result `r` in contract
---
*/
@@ -42,7 +42,7 @@ class C
s = 10; // err
a = 1; // OK
}
- body
+ do
{
x = 10; // err
y = 1; // OK
@@ -70,7 +70,7 @@ class C
s = 10; // err
a = 1; // OK
}
- body
+ do
{
x = 10; // err
r = 10; // err
@@ -81,7 +81,7 @@ class C
x = 10; // err
r = 10; // err
}
- body
+ do
{
return 1;
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9414c.d b/gcc/testsuite/gdc.test/fail_compilation/fail9414c.d
index efbff9c..3e0311a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9414c.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9414c.d
@@ -1,24 +1,24 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9414c.d(47): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414c.d(34): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414c.d(35): Error: variable fail9414c.C.foo.bar.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414c.d(40): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414c.d(41): Error: variable fail9414c.C.foo.bar.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414c.d(42): Error: variable fail9414c.C.foo.bar.s cannot modify result 's' in contract
-fail_compilation/fail9414c.d(52): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414c.d(75): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414c.d(76): Error: variable fail9414c.C.foo.r cannot modify result 'r' in contract
-fail_compilation/fail9414c.d(60): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414c.d(61): Error: variable fail9414c.C.foo.r cannot modify result 'r' in contract
-fail_compilation/fail9414c.d(62): Error: variable fail9414c.C.foo.baz.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414c.d(67): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414c.d(68): Error: variable fail9414c.C.foo.r cannot modify result 'r' in contract
-fail_compilation/fail9414c.d(69): Error: variable fail9414c.C.foo.baz.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414c.d(70): Error: variable fail9414c.C.foo.baz.s cannot modify result 's' in contract
-fail_compilation/fail9414c.d(81): Error: variable fail9414c.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414c.d(82): Error: variable fail9414c.C.foo.r cannot modify result 'r' in contract
+fail_compilation/fail9414c.d(47): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414c.d(34): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414c.d(35): Error: variable `fail9414c.C.foo.bar.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414c.d(40): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414c.d(41): Error: variable `fail9414c.C.foo.bar.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414c.d(42): Error: variable `fail9414c.C.foo.bar.s` cannot modify result `s` in contract
+fail_compilation/fail9414c.d(52): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414c.d(75): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414c.d(76): Error: variable `fail9414c.C.foo.r` cannot modify result `r` in contract
+fail_compilation/fail9414c.d(60): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414c.d(61): Error: variable `fail9414c.C.foo.r` cannot modify result `r` in contract
+fail_compilation/fail9414c.d(62): Error: variable `fail9414c.C.foo.baz.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414c.d(67): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414c.d(68): Error: variable `fail9414c.C.foo.r` cannot modify result `r` in contract
+fail_compilation/fail9414c.d(69): Error: variable `fail9414c.C.foo.baz.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414c.d(70): Error: variable `fail9414c.C.foo.baz.s` cannot modify result `s` in contract
+fail_compilation/fail9414c.d(81): Error: variable `fail9414c.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414c.d(82): Error: variable `fail9414c.C.foo.r` cannot modify result `r` in contract
---
*/
@@ -42,7 +42,7 @@ class C
s = 10; // err
a = 1; // OK
}
- body
+ do
{
x = 10; // err
y = 1; // OK
@@ -70,7 +70,7 @@ class C
s = 10; // err
a = 1; // OK
}
- body
+ do
{
x = 10; // err
r = 10; // err
@@ -81,7 +81,7 @@ class C
x = 10; // err
r = 10; // err
}
- body
+ do
{
return 1;
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9414d.d b/gcc/testsuite/gdc.test/fail_compilation/fail9414d.d
index 60b5886..06d37ce 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9414d.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9414d.d
@@ -1,24 +1,24 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9414d.d(47): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414d.d(34): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414d.d(35): Error: variable fail9414d.C.foo.bar.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414d.d(40): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414d.d(41): Error: variable fail9414d.C.foo.bar.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414d.d(42): Error: variable fail9414d.C.foo.bar.s cannot modify result 's' in contract
-fail_compilation/fail9414d.d(52): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414d.d(75): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414d.d(76): Error: variable fail9414d.C.foo.r cannot modify result 'r' in contract
-fail_compilation/fail9414d.d(60): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414d.d(61): Error: variable fail9414d.C.foo.r cannot modify result 'r' in contract
-fail_compilation/fail9414d.d(62): Error: variable fail9414d.C.foo.baz.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414d.d(67): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414d.d(68): Error: variable fail9414d.C.foo.r cannot modify result 'r' in contract
-fail_compilation/fail9414d.d(69): Error: variable fail9414d.C.foo.baz.y cannot modify parameter 'y' in contract
-fail_compilation/fail9414d.d(70): Error: variable fail9414d.C.foo.baz.s cannot modify result 's' in contract
-fail_compilation/fail9414d.d(81): Error: variable fail9414d.C.foo.x cannot modify parameter 'x' in contract
-fail_compilation/fail9414d.d(82): Error: variable fail9414d.C.foo.r cannot modify result 'r' in contract
+fail_compilation/fail9414d.d(47): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414d.d(34): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414d.d(35): Error: variable `fail9414d.C.foo.bar.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414d.d(40): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414d.d(41): Error: variable `fail9414d.C.foo.bar.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414d.d(42): Error: variable `fail9414d.C.foo.bar.s` cannot modify result `s` in contract
+fail_compilation/fail9414d.d(52): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414d.d(75): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414d.d(76): Error: variable `fail9414d.C.foo.r` cannot modify result `r` in contract
+fail_compilation/fail9414d.d(60): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414d.d(61): Error: variable `fail9414d.C.foo.r` cannot modify result `r` in contract
+fail_compilation/fail9414d.d(62): Error: variable `fail9414d.C.foo.baz.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414d.d(67): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414d.d(68): Error: variable `fail9414d.C.foo.r` cannot modify result `r` in contract
+fail_compilation/fail9414d.d(69): Error: variable `fail9414d.C.foo.baz.y` cannot modify parameter `y` in contract
+fail_compilation/fail9414d.d(70): Error: variable `fail9414d.C.foo.baz.s` cannot modify result `s` in contract
+fail_compilation/fail9414d.d(81): Error: variable `fail9414d.C.foo.x` cannot modify parameter `x` in contract
+fail_compilation/fail9414d.d(82): Error: variable `fail9414d.C.foo.r` cannot modify result `r` in contract
---
*/
@@ -42,7 +42,7 @@ class C
s = 10; // err
a = 1; // OK
}
- body
+ do
{
x = 10; // err
y = 1; // OK
@@ -70,7 +70,7 @@ class C
s = 10; // err
a = 1; // OK
}
- body
+ do
{
x = 10; // err
r = 10; // err
@@ -81,7 +81,7 @@ class C
x = 10; // err
r = 10; // err
}
- body
+ do
{
return 1;
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail95.d b/gcc/testsuite/gdc.test/fail_compilation/fail95.d
index 439e55d..b1f046a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail95.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail95.d
@@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail95.d(19): Error: template fail95.A cannot deduce function from argument types !()(int), candidates are:
-fail_compilation/fail95.d(11): fail95.A(alias T)(T)
+fail_compilation/fail95.d(19): Error: template `fail95.A` cannot deduce function from argument types `!()(int)`
+fail_compilation/fail95.d(11): Candidate is: `A(alias T)(T)`
---
*/
-// Issue 142 - Assertion failure: '0' on line 610 in file 'template.c'
-
+// https://issues.dlang.org/show_bug.cgi?id=142
+// Assertion failure: '0' on line 610 in file 'template.c'
template A(alias T)
{
void A(T) { T = 2; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9537.d b/gcc/testsuite/gdc.test/fail_compilation/fail9537.d
index bf6e4db..e08badf 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9537.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9537.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9537.d(26): Error: foo(tuple(1, 2)) is not an lvalue
+fail_compilation/fail9537.d(26): Error: `foo(tuple(1, 2))` is not an lvalue and cannot be modified
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9562.d b/gcc/testsuite/gdc.test/fail_compilation/fail9562.d
index 46aafee..7c40c41 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9562.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9562.d
@@ -1,13 +1,12 @@
/*
REQUIRED_ARGS: -o-
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/fail9562.d(17): Error: int[] is not an expression
-fail_compilation/fail9562.d(18): Error: no property 'reverse' for type 'int[]'
-fail_compilation/fail9562.d(19): Error: no property 'sort' for type 'int[]'
-fail_compilation/fail9562.d(20): Error: no property 'dup' for type 'int[]'
-fail_compilation/fail9562.d(21): Error: no property 'idup' for type 'int[]'
+fail_compilation/fail9562.d(16): Error: `int[]` is not an expression
+fail_compilation/fail9562.d(17): Error: no property `reverse` for type `int[]`
+fail_compilation/fail9562.d(18): Error: no property `sort` for type `int[]`, perhaps `import std.algorithm;` is needed?
+fail_compilation/fail9562.d(19): Error: no property `dup` for type `int[]`
+fail_compilation/fail9562.d(20): Error: no property `idup` for type `int[]`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail96.d b/gcc/testsuite/gdc.test/fail_compilation/fail96.d
index 1bdc841..639fb6c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail96.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail96.d
@@ -1,11 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail96.d(21): Error: template instance foo!long foo is not a template declaration, it is a function alias
+fail_compilation/fail96.d(21): Error: template instance `foo!long` `foo` is not a template declaration, it is a function alias
---
*/
-// 153
+// https://issues.dlang.org/show_bug.cgi?id=153
template bar(T)
{
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9613.d b/gcc/testsuite/gdc.test/fail_compilation/fail9613.d
index 7f9d007..31ca808 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9613.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9613.d
@@ -1,4 +1,4 @@
-// PREMUTE_ARGS:
+// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9665a.d b/gcc/testsuite/gdc.test/fail_compilation/fail9665a.d
index 64602f87..abfe914 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9665a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9665a.d
@@ -1,15 +1,39 @@
-// REQUIRED_ARGS:
-// PERMUTE_ARGS:
-
-/***************************************************/
-// immutable field
-
/+
TEST_OUTPUT:
---
-fail_compilation/fail9665a.d(19): Error: immutable field 'v' initialized multiple times
+fail_compilation/fail9665a.d(43): Error: immutable field `v` initialized multiple times
+fail_compilation/fail9665a.d(42): Previous initialization is here.
+fail_compilation/fail9665a.d(53): Error: immutable field `v` initialized multiple times
+fail_compilation/fail9665a.d(52): Previous initialization is here.
+fail_compilation/fail9665a.d(58): Error: immutable field `v` initialized multiple times
+fail_compilation/fail9665a.d(57): Previous initialization is here.
+fail_compilation/fail9665a.d(63): Error: immutable field `v` initialized multiple times
+fail_compilation/fail9665a.d(62): Previous initialization is here.
+fail_compilation/fail9665a.d(73): Error: immutable field `v` initialized multiple times
+fail_compilation/fail9665a.d(72): Previous initialization is here.
+fail_compilation/fail9665a.d(78): Error: immutable field `v` initialized multiple times
+fail_compilation/fail9665a.d(77): Previous initialization is here.
+fail_compilation/fail9665a.d(83): Error: immutable field `v` initialized multiple times
+fail_compilation/fail9665a.d(82): Previous initialization is here.
+fail_compilation/fail9665a.d(96): Error: immutable field `v` initialization is not allowed in loops or after labels
+fail_compilation/fail9665a.d(101): Error: immutable field `v` initialization is not allowed in loops or after labels
+fail_compilation/fail9665a.d(106): Error: immutable field `v` initialized multiple times
+fail_compilation/fail9665a.d(105): Previous initialization is here.
+fail_compilation/fail9665a.d(111): Error: immutable field `v` initialized multiple times
+fail_compilation/fail9665a.d(110): Previous initialization is here.
+fail_compilation/fail9665a.d(116): Error: immutable field `v` initialized multiple times
+fail_compilation/fail9665a.d(115): Previous initialization is here.
+fail_compilation/fail9665a.d(130): Error: immutable field `v` initialized multiple times
+fail_compilation/fail9665a.d(129): Previous initialization is here.
+fail_compilation/fail9665a.d(134): Error: immutable field `w` initialized multiple times
+fail_compilation/fail9665a.d(133): Previous initialization is here.
+fail_compilation/fail9665a.d(148): Error: static assert: `__traits(compiles, this.v = 1)` is false
---
+/
+
+/***************************************************/
+// immutable field
+
struct S1A
{
immutable int v;
@@ -20,14 +44,6 @@ struct S1A
}
}
-/+
-TEST_OUTPUT:
----
-fail_compilation/fail9665a.d(37): Error: immutable field 'v' initialized multiple times
-fail_compilation/fail9665a.d(42): Error: immutable field 'v' initialized multiple times
-fail_compilation/fail9665a.d(47): Error: immutable field 'v' initialized multiple times
----
-+/
struct S1B
{
immutable int v;
@@ -48,14 +64,6 @@ struct S1B
}
}
-/+
-TEST_OUTPUT:
----
-fail_compilation/fail9665a.d(65): Error: immutable field 'v' initialized multiple times
-fail_compilation/fail9665a.d(70): Error: immutable field 'v' initialized multiple times
-fail_compilation/fail9665a.d(75): Error: immutable field 'v' initialized multiple times
----
-+/
struct S1C
{
immutable int v;
@@ -79,16 +87,6 @@ struct S1C
/***************************************************/
// with control flow
-/+
-TEST_OUTPUT:
----
-fail_compilation/fail9665a.d(98): Error: immutable field 'v' initialization is not allowed in loops or after labels
-fail_compilation/fail9665a.d(103): Error: immutable field 'v' initialization is not allowed in loops or after labels
-fail_compilation/fail9665a.d(108): Error: immutable field 'v' initialized multiple times
-fail_compilation/fail9665a.d(113): Error: immutable field 'v' initialized multiple times
-fail_compilation/fail9665a.d(118): Error: immutable field 'v' initialized multiple times
----
-+/
struct S2
{
immutable int v;
@@ -122,13 +120,6 @@ struct S2
/***************************************************/
// with immutable constructor
-/+
-TEST_OUTPUT:
----
-fail_compilation/fail9665a.d(139): Error: immutable field 'v' initialized multiple times
-fail_compilation/fail9665a.d(143): Error: immutable field 'w' initialized multiple times
----
-+/
struct S3
{
int v;
@@ -147,12 +138,6 @@ struct S3
/***************************************************/
// in __traits(compiles)
-/+
-TEST_OUTPUT:
----
-fail_compilation/fail9665a.d(163): Error: static assert `__traits(compiles, this.v = 1)` is false
----
-+/
struct S4
{
immutable int v;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9665b.d b/gcc/testsuite/gdc.test/fail_compilation/fail9665b.d
index 8f7d79c..8980546 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9665b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9665b.d
@@ -11,12 +11,12 @@ struct X
/+
TEST_OUTPUT:
---
-fail_compilation/fail9665b.d(32): Error: one path skips field x2
-fail_compilation/fail9665b.d(33): Error: one path skips field x3
-fail_compilation/fail9665b.d(35): Error: one path skips field x5
-fail_compilation/fail9665b.d(36): Error: one path skips field x6
-fail_compilation/fail9665b.d(30): Error: field x1 must be initialized in constructor
-fail_compilation/fail9665b.d(30): Error: field x4 must be initialized in constructor
+fail_compilation/fail9665b.d(32): Error: one path skips field `x2`
+fail_compilation/fail9665b.d(33): Error: one path skips field `x3`
+fail_compilation/fail9665b.d(35): Error: one path skips field `x5`
+fail_compilation/fail9665b.d(36): Error: one path skips field `x6`
+fail_compilation/fail9665b.d(30): Error: field `x1` must be initialized in constructor
+fail_compilation/fail9665b.d(30): Error: field `x4` must be initialized in constructor
---
+/
struct S1
@@ -43,13 +43,13 @@ struct S1
/+
TEST_OUTPUT:
---
-fail_compilation/fail9665b.d(65): Error: one path skips field x2
-fail_compilation/fail9665b.d(66): Error: one path skips field x3
-fail_compilation/fail9665b.d(68): Error: one path skips field x5
-fail_compilation/fail9665b.d(69): Error: one path skips field x6
-fail_compilation/fail9665b.d(63): Error: field x1 must be initialized in constructor, because it is nested struct
-fail_compilation/fail9665b.d(63): Error: field x4 must be initialized in constructor, because it is nested struct
-fail_compilation/fail9665b.d(76): Error: template instance fail9665b.S2!(X) error instantiating
+fail_compilation/fail9665b.d(65): Error: one path skips field `x2`
+fail_compilation/fail9665b.d(66): Error: one path skips field `x3`
+fail_compilation/fail9665b.d(68): Error: one path skips field `x5`
+fail_compilation/fail9665b.d(69): Error: one path skips field `x6`
+fail_compilation/fail9665b.d(63): Error: field `x1` must be initialized in constructor, because it is nested struct
+fail_compilation/fail9665b.d(63): Error: field `x4` must be initialized in constructor, because it is nested struct
+fail_compilation/fail9665b.d(76): Error: template instance `fail9665b.S2!(X)` error instantiating
---
+/
struct S2(X)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail97.d b/gcc/testsuite/gdc.test/fail_compilation/fail97.d
index 33d0c5f..cec9819 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail97.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail97.d
@@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail97.d(11): Error: pragma lib pragma is missing closing `;`
+fail_compilation/fail97.d(11): Error: pragma `lib` is missing a terminating `;`
---
*/
-// 151
+// https://issues.dlang.org/show_bug.cgi?id=151
-import std.stdio;
+import core.stdc.stdio;
pragma(lib,"ws2_32.lib")//;
class bla{}
void main(){}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9710.d b/gcc/testsuite/gdc.test/fail_compilation/fail9710.d
index 98306b2..dc772cd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9710.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9710.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9710.d(9): Error: static variable e cannot be read at compile time
+fail_compilation/fail9710.d(9): Error: static variable `e` cannot be read at compile time
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9766.d b/gcc/testsuite/gdc.test/fail_compilation/fail9766.d
index 58cabe3..03a94cb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9766.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9766.d
@@ -2,11 +2,11 @@
TEST_OUTPUT:
---
fail_compilation/fail9766.d(14): Error: integer constant expression expected instead of `Foo!int`
-fail_compilation/fail9766.d(14): Error: alignment must be an integer positive power of 2, not Foo!int
-fail_compilation/fail9766.d(17): Error: alignment must be an integer positive power of 2, not -1
-fail_compilation/fail9766.d(20): Error: alignment must be an integer positive power of 2, not 0
-fail_compilation/fail9766.d(23): Error: alignment must be an integer positive power of 2, not 3
-fail_compilation/fail9766.d(26): Error: alignment must be an integer positive power of 2, not 2147483649u
+fail_compilation/fail9766.d(14): Error: alignment must be an integer positive power of 2, not 0x0
+fail_compilation/fail9766.d(17): Error: alignment must be an integer positive power of 2, not 0xffffffffffffffff
+fail_compilation/fail9766.d(20): Error: alignment must be an integer positive power of 2, not 0x0
+fail_compilation/fail9766.d(23): Error: alignment must be an integer positive power of 2, not 0x3
+fail_compilation/fail9766.d(26): Error: alignment must be an integer positive power of 2, not 0x80000001
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9773.d b/gcc/testsuite/gdc.test/fail_compilation/fail9773.d
index 18da406..b49ffe1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9773.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9773.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9773.d(7): Error: "" is not an lvalue
+fail_compilation/fail9773.d(7): Error: `""` is not an lvalue and cannot be modified
---
*/
void f(ref string a = "")
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9790.d b/gcc/testsuite/gdc.test/fail_compilation/fail9790.d
index 0becddd..cae33c2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9790.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9790.d
@@ -2,9 +2,9 @@
TEST_OUTPUT:
---
fail_compilation/fail9790.d(13): Error: undefined identifier `_Unused_`
-fail_compilation/fail9790.d(20): Error: template instance fail9790.foo!() error instantiating
+fail_compilation/fail9790.d(20): Error: template instance `fail9790.foo!()` error instantiating
fail_compilation/fail9790.d(18): Error: undefined identifier `_Unused_`
-fail_compilation/fail9790.d(21): Error: template instance fail9790.bar!() error instantiating
+fail_compilation/fail9790.d(21): Error: template instance `fail9790.bar!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail98.d b/gcc/testsuite/gdc.test/fail_compilation/fail98.d
index ded3624..7541d37 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail98.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail98.d
@@ -5,7 +5,7 @@ fail_compilation/fail98.d(17): Error: cannot implicitly convert expression `256`
---
*/
-// 139
+// https://issues.dlang.org/show_bug.cgi?id=139
E foo(int index)
{
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9891.d b/gcc/testsuite/gdc.test/fail_compilation/fail9891.d
index 99d5f11..791e734 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9891.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9891.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9891.d(13): Error: cast(int)i is not an lvalue
-fail_compilation/fail9891.d(18): Error: cast(int)i is not an lvalue
-fail_compilation/fail9891.d(23): Error: prop() is not an lvalue
+fail_compilation/fail9891.d(13): Error: expression `i` of type `immutable(int)` is not implicitly convertible to type `ref int` of parameter `n`
+fail_compilation/fail9891.d(18): Error: expression `i` of type `immutable(int)` is not implicitly convertible to type `out int` of parameter `n`
+fail_compilation/fail9891.d(23): Error: `prop()` is not an lvalue and cannot be modified
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9892.d b/gcc/testsuite/gdc.test/fail_compilation/fail9892.d
index 32eef12..c3fbf7a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9892.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9892.d
@@ -1,8 +1,8 @@
-// 9892
+// https://issues.dlang.org/show_bug.cgi?id=9892
/*
TEST_OUTPUT:
---
-fail_compilation/fail9892.d(11): Error: enum member fail9892.a circular reference to enum member
+fail_compilation/fail9892.d(11): Error: enum member `fail9892.a` circular reference to `enum` member
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9936.d b/gcc/testsuite/gdc.test/fail_compilation/fail9936.d
index 36178f4..0d7d44a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9936.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9936.d
@@ -1,11 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail9936.d(25): Error: S().opBinary isn't a template
-fail_compilation/fail9936.d(26): Error: S().opBinaryRight isn't a template
-fail_compilation/fail9936.d(27): Error: S().opOpAssign isn't a template
-fail_compilation/fail9936.d(29): Error: S().opIndexUnary isn't a template
-fail_compilation/fail9936.d(30): Error: S().opUnary isn't a template
+fail_compilation/fail9936.d(25): Error: `S().opBinary` isn't a template
+fail_compilation/fail9936.d(26): Error: `S().opBinaryRight` isn't a template
+fail_compilation/fail9936.d(27): Error: `S().opOpAssign` isn't a template
+fail_compilation/fail9936.d(29): Error: `S().opIndexUnary` isn't a template
+fail_compilation/fail9936.d(30): Error: `S().opUnary` isn't a template
---
*/
struct S
diff --git a/gcc/testsuite/gdc.test/fail_compilation/failCopyCtor.d b/gcc/testsuite/gdc.test/fail_compilation/failCopyCtor.d
new file mode 100644
index 0000000..f341675
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/failCopyCtor.d
@@ -0,0 +1,15 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/failCopyCtor.d(10): Error: `struct A` may not define both a rvalue constructor and a copy constructor
+fail_compilation/failCopyCtor.d(12): rvalue constructor defined here
+fail_compilation/failCopyCtor.d(13): copy constructor defined here
+---
+*/
+
+struct A
+{
+ this(immutable A a) {}
+ this(ref shared A a) immutable {}
+ this(ref A a) {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/failCopyCtor2.d b/gcc/testsuite/gdc.test/fail_compilation/failCopyCtor2.d
new file mode 100644
index 0000000..5e8f8c4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/failCopyCtor2.d
@@ -0,0 +1,19 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/failCopyCtor2.d(15): Error: `struct B` may not define a rvalue constructor and have fields with copy constructors
+fail_compilation/failCopyCtor2.d(18): rvalue constructor defined here
+fail_compilation/failCopyCtor2.d(17): field with copy constructor defined here
+---
+*/
+
+struct A
+{
+ this (ref shared A a) immutable {}
+}
+
+struct B
+{
+ A a;
+ this(immutable B b) shared {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayexp.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayexp.d
new file mode 100644
index 0000000..1a766ff
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayexp.d
@@ -0,0 +1,30 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail_arrayexp.d(24): Error: cannot use `[]` operator on expression of type `int`
+fail_compilation/fail_arrayexp.d(25): Error: cannot use `[]` operator on expression of type `void`
+fail_compilation/fail_arrayexp.d(26): Error: static array of `const(int)[]` with multiple lengths not allowed
+fail_compilation/fail_arrayexp.d(27): Error: only one index allowed to index `string`
+fail_compilation/fail_arrayexp.d(28): Error: no `[]` operator overload for type `U`
+fail_compilation/fail_arrayexp.d(29): Error: only one index allowed to index `(int, string)`
+---
+*/
+
+int i;
+string str;
+union U {}
+alias typeAlias = const(int)[];
+void getVoid();
+alias getTuple(T...) = T;
+
+void test19534() // https://issues.dlang.org/show_bug.cgi?id=19534
+{
+ U agg;
+#line 24
+ auto p = i[0];
+ auto q = getVoid()[0];
+ alias r = getTuple!(typeAlias[0, 1]);
+ auto s = str[0, 1, 2];
+ auto t = agg[];
+ auto u = getTuple!(int, string)[1, 2];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop1.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop1.d
index 3498df7..7527639 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop1.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop1.d
@@ -4,10 +4,12 @@
TEST_OUTPUT:
---
fail_compilation/fail_arrayop1.d(11): Error: invalid array operation `a + a` (possible missing [])
+fail_compilation/fail_arrayop1.d(11): did you mean to concatenate (`a ~ a`) instead ?
---
*/
-void test2199(int[] a) // Issue 2199 - Segfault using array operation in function call (from fail266.d)
+void test2199(int[] a) // https://issues.dlang.org/show_bug.cgi?id=2199 - Segfault using array operation in function call (from fail266.d)
{
+#line 11
test2199(a + a);
}
@@ -17,7 +19,7 @@ TEST_OUTPUT:
fail_compilation/fail_arrayop1.d(29): Error: invalid array operation `-a` (possible missing [])
---
*/
-void fail323() // from fail323.d, maybe was a part of issue 3471 fix?
+void fail323() // from fail323.d, maybe was a part of https://issues.dlang.org/show_bug.cgi?id=3471 fix?
{
void foo(double[]) {}
@@ -25,7 +27,7 @@ void fail323() // from fail323.d, maybe was a part of issue 3471 fix?
b = a.dup,
c = a.dup,
d = a.dup;
-
+#line 29
foo(-a);
// a[] = -(b[] * (c[] + 4)) + 5 * d[]; // / 3;
}
@@ -36,6 +38,7 @@ TEST_OUTPUT:
fail_compilation/fail_arrayop1.d(54): Error: invalid array operation `-a` (possible missing [])
fail_compilation/fail_arrayop1.d(55): Error: invalid array operation `~a` (possible missing [])
fail_compilation/fail_arrayop1.d(56): Error: invalid array operation `a + a` (possible missing [])
+fail_compilation/fail_arrayop1.d(56): did you mean to concatenate (`a ~ a`) instead ?
fail_compilation/fail_arrayop1.d(57): Error: invalid array operation `a - a` (possible missing [])
fail_compilation/fail_arrayop1.d(58): Error: invalid array operation `a * a` (possible missing [])
fail_compilation/fail_arrayop1.d(59): Error: invalid array operation `a / a` (possible missing [])
@@ -50,7 +53,7 @@ void test3903()
{
int[] a = [1, 2];
int[] r;
-
+#line 54
r = -a;
r = ~a;
r = a + a;
@@ -68,6 +71,7 @@ void test3903()
TEST_OUTPUT:
---
fail_compilation/fail_arrayop1.d(85): Error: invalid array operation `a += a[]` (possible missing [])
+fail_compilation/fail_arrayop1.d(85): did you mean to concatenate (`a ~= a[]`) instead ?
fail_compilation/fail_arrayop1.d(86): Error: invalid array operation `a -= a[]` (possible missing [])
fail_compilation/fail_arrayop1.d(87): Error: invalid array operation `a *= a[]` (possible missing [])
fail_compilation/fail_arrayop1.d(88): Error: invalid array operation `a /= a[]` (possible missing [])
@@ -81,7 +85,7 @@ fail_compilation/fail_arrayop1.d(93): Error: invalid array operation `a ^^= a[]`
void test9459()
{
int[] a = [1, 2, 3];
-
+#line 85
a += a[];
a -= a[];
a *= a[];
@@ -96,47 +100,25 @@ void test9459()
/*
TEST_OUTPUT:
---
-fail_compilation/fail_arrayop1.d(111): Error: invalid array operation `x1[] = x2[] * x3[]` because `X` doesn't support necessary arithmetic operations
-fail_compilation/fail_arrayop1.d(115): Error: invalid array operation `s2[] += s1[]` because `string` is not a scalar type
-fail_compilation/fail_arrayop1.d(119): Error: invalid array operation `pa1[] *= pa2[]` for element type `int*`
----
-*/
-void test11376()
-{
- struct X { }
-
- auto x1 = [X()];
- auto x2 = [X()];
- auto x3 = [X()];
- x1[] = x2[] * x3[];
-
- string[] s1;
- string[] s2;
- s2[] += s1[];
-
- int*[] pa1;
- int*[] pa2;
- pa1[] *= pa2[];
-}
-
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail_arrayop1.d(131): Error: invalid array operation `a[] <<= 1` (possible missing [])
+fail_compilation/fail_arrayop1.d(105): Error: invalid array operation `a[] <<= 1` (possible missing [])
---
*/
void test11566()
{
int[] a;
+#line 105
a[] <<= 1;
}
/*
TEST_OUTPUT:
---
-fail_compilation/fail_arrayop1.d(147): Error: invalid array operation `a + b` (possible missing [])
-fail_compilation/fail_arrayop1.d(148): Error: invalid array operation `x + y` (possible missing [])
-fail_compilation/fail_arrayop1.d(149): Error: invalid array operation `"hel" + "lo."` (possible missing [])
+fail_compilation/fail_arrayop1.d(121): Error: invalid array operation `a + b` (possible missing [])
+fail_compilation/fail_arrayop1.d(121): did you mean to concatenate (`a ~ b`) instead ?
+fail_compilation/fail_arrayop1.d(122): Error: invalid array operation `x + y` (possible missing [])
+fail_compilation/fail_arrayop1.d(122): did you mean to concatenate (`x ~ y`) instead ?
+fail_compilation/fail_arrayop1.d(123): Error: invalid array operation `"hel" + "lo."` (possible missing [])
+fail_compilation/fail_arrayop1.d(123): did you mean to concatenate (`"hel" ~ "lo."`) instead ?
---
*/
void test14649()
@@ -144,6 +126,7 @@ void test14649()
char[] a, b, r;
string x, y;
+#line 121
r[] = a + b;
r[] = x + y;
r[] = "hel" + "lo.";
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d
index 8f654b0..ed228a9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d
@@ -1,13 +1,14 @@
// REQUIRED_ARGS: -o-
+
/*
TEST_OUTPUT:
---
-fail_compilation/fail_arrayop2.d(12): Error: array operation `[1, 2, 3] - [1, 2, 3]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(15): Error: invalid array operation `"a" - "b"` (possible missing [])
+fail_compilation/fail_arrayop2.d(13): Error: array operation `[1, 2, 3] - [1, 2, 3]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(16): Error: invalid array operation `"a" - "b"` (possible missing [])
---
*/
-void test2603() // Issue 2603 - ICE(cgcs.c) on subtracting string literals
+void test2603() // https://issues.dlang.org/show_bug.cgi?id=2603 - ICE(cgcs.c) on subtracting string literals
{
auto c1 = [1,2,3] - [1,2,3];
@@ -18,17 +19,17 @@ void test2603() // Issue 2603 - ICE(cgcs.c) on subtracting string literals
/*
TEST_OUTPUT:
---
-fail_compilation/fail_arrayop2.d(37): Error: array operation `-a[]` without destination memory not allowed (possible missing [])
-fail_compilation/fail_arrayop2.d(38): Error: array operation `~a[]` without destination memory not allowed (possible missing [])
-fail_compilation/fail_arrayop2.d(40): Error: array operation `a[] + a[]` without destination memory not allowed (possible missing [])
-fail_compilation/fail_arrayop2.d(41): Error: array operation `a[] - a[]` without destination memory not allowed (possible missing [])
-fail_compilation/fail_arrayop2.d(42): Error: array operation `a[] * a[]` without destination memory not allowed (possible missing [])
-fail_compilation/fail_arrayop2.d(43): Error: array operation `a[] / a[]` without destination memory not allowed (possible missing [])
-fail_compilation/fail_arrayop2.d(44): Error: array operation `a[] % a[]` without destination memory not allowed (possible missing [])
-fail_compilation/fail_arrayop2.d(45): Error: array operation `a[] ^ a[]` without destination memory not allowed (possible missing [])
-fail_compilation/fail_arrayop2.d(46): Error: array operation `a[] & a[]` without destination memory not allowed (possible missing [])
-fail_compilation/fail_arrayop2.d(47): Error: array operation `a[] | a[]` without destination memory not allowed (possible missing [])
-fail_compilation/fail_arrayop2.d(48): Error: array operation `a[] ^^ a[]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(38): Error: array operation `-a[]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(39): Error: array operation `~a[]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(41): Error: array operation `a[] + a[]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(42): Error: array operation `a[] - a[]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(43): Error: array operation `a[] * a[]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(44): Error: array operation `a[] / a[]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(45): Error: array operation `a[] % a[]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(46): Error: array operation `a[] ^ a[]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(47): Error: array operation `a[] & a[]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(48): Error: array operation `a[] | a[]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(49): Error: array operation `a[] ^^ a[]` without destination memory not allowed (possible missing [])
---
*/
void test9459()
@@ -51,19 +52,19 @@ void test9459()
/*
TEST_OUTPUT:
---
-fail_compilation/fail_arrayop2.d(74): Error: array operation `a[] + a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(75): Error: array operation `a[] - a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(76): Error: array operation `a[] * a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(77): Error: array operation `a[] / a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(78): Error: array operation `a[] % a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(79): Error: array operation `a[] ^ a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(80): Error: array operation `a[] & a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(81): Error: array operation `a[] | a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(82): Error: array operation `a[] ^^ 10` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(83): Error: array operation `-a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(84): Error: array operation `~a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(89): Error: array operation `[1] + a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(75): Error: array operation `a[] + a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(76): Error: array operation `a[] - a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(77): Error: array operation `a[] * a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(78): Error: array operation `a[] / a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(79): Error: array operation `a[] % a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(80): Error: array operation `a[] ^ a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(81): Error: array operation `a[] & a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(82): Error: array operation `a[] | a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(83): Error: array operation `a[] ^^ 10` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(84): Error: array operation `-a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(85): Error: array operation `~a[]` without destination memory not allowed
fail_compilation/fail_arrayop2.d(90): Error: array operation `[1] + a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(91): Error: array operation `[1] + a[]` without destination memory not allowed
---
*/
void test12179()
@@ -83,7 +84,7 @@ void test12179()
foo(-a[]);
foo(~a[]);
- // from issue 11992
+ // from https://issues.dlang.org/show_bug.cgi?id=11992
int[] arr1;
int[][] arr2;
arr1 ~= [1] + a[]; // NG
@@ -93,7 +94,7 @@ void test12179()
/*
TEST_OUTPUT:
---
-fail_compilation/fail_arrayop2.d(104): Error: array operation `h * y[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(105): Error: array operation `h * y[]` without destination memory not allowed
---
*/
void test12381()
@@ -107,8 +108,8 @@ void test12381()
/*
TEST_OUTPUT:
---
-fail_compilation/fail_arrayop2.d(117): Error: array operation `-a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(119): Error: array operation `(-a[])[0..4]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(118): Error: array operation `-a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(120): Error: array operation `(-a[])[0..4]` without destination memory not allowed
---
*/
float[] test12769(float[] a)
@@ -122,11 +123,11 @@ float[] test12769(float[] a)
/*
TEST_OUTPUT:
---
-fail_compilation/fail_arrayop2.d(136): Error: array operation `a[] - a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(138): Error: array operation `a[] - a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(137): Error: array operation `a[] - a[]` without destination memory not allowed
fail_compilation/fail_arrayop2.d(139): Error: array operation `a[] - a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(142): Error: array operation `a[] - a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(144): Error: array operation `a[] - a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(140): Error: array operation `a[] - a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(143): Error: array operation `a[] - a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(145): Error: array operation `a[] - a[]` without destination memory not allowed
---
*/
void test13208()
@@ -147,10 +148,10 @@ void test13208()
/*
TEST_OUTPUT:
---
-fail_compilation/fail_arrayop2.d(159): Error: array operation `a[] * a[]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(160): Error: array operation `(a[] * a[])[0..1]` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(163): Error: array operation `a[] * a[]` without destination memory not allowed (possible missing [])
-fail_compilation/fail_arrayop2.d(164): Error: array operation `(a[] * a[])[0..1]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(160): Error: array operation `a[] * a[]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(161): Error: array operation `(a[] * a[])[0..1]` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(164): Error: array operation `a[] * a[]` without destination memory not allowed (possible missing [])
+fail_compilation/fail_arrayop2.d(165): Error: array operation `(a[] * a[])[0..1]` without destination memory not allowed (possible missing [])
---
*/
void test13497()
@@ -167,7 +168,7 @@ void test13497()
/*
TEST_OUTPUT:
---
-fail_compilation/fail_arrayop2.d(180): Error: array operation `data[segmentId][28..29] & cast(ubyte)(1 << 0)` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(181): Error: array operation `data[segmentId][28..29] & cast(ubyte)(1 << 0)` without destination memory not allowed
---
*/
void test13910()
@@ -184,8 +185,8 @@ void test13910()
/*
TEST_OUTPUT:
---
-fail_compilation/fail_arrayop2.d(194): Error: array operation `a[] + 1` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(194): Error: array operation `a[] * 2` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(195): Error: array operation `a[] + 1` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(195): Error: array operation `a[] * 2` without destination memory not allowed
---
*/
void test14895()
@@ -197,40 +198,41 @@ void test14895()
/*
TEST_OUTPUT:
---
-fail_compilation/fail_arrayop2.d(245): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(246): Error: array operation `[1] * 6` without destination memory not allowed
fail_compilation/fail_arrayop2.d(247): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(252): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(255): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(264): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(267): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(268): Error: array operation `"abc"[] + '\x01'` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(271): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(274): Error: ([1] * 6)[0..2] is not an lvalue
-fail_compilation/fail_arrayop2.d(277): Error: can only * a pointer, not a 'int[]'
-fail_compilation/fail_arrayop2.d(280): Error: [1] * 6 is not an lvalue
-fail_compilation/fail_arrayop2.d(283): Error: array operation `da[] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(286): Error: array operation `da[] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(289): Error: [1] * 6 is not an lvalue
-fail_compilation/fail_arrayop2.d(290): Error: invalid array operation `[1] * 6 -= 1` for element type `int`
-fail_compilation/fail_arrayop2.d(293): Error: [1] * 6 is not an lvalue
-fail_compilation/fail_arrayop2.d(294): Error: ([1] * 6)[] is not an lvalue
-fail_compilation/fail_arrayop2.d(297): Error: invalid array operation `[1] * 6 += 1` for element type `int`
-fail_compilation/fail_arrayop2.d(298): Error: invalid array operation `[1] * 6 *= 2` for element type `int`
-fail_compilation/fail_arrayop2.d(299): Error: invalid array operation `[1] * 6 ^^= 3` for element type `int`
-fail_compilation/fail_arrayop2.d(302): Error: [1] * 6 is not an lvalue
-fail_compilation/fail_arrayop2.d(303): Error: [1] * 6 is not an lvalue
-fail_compilation/fail_arrayop2.d(306): Error: '[1] * 6' is not of integral type, it is a int[]
-fail_compilation/fail_arrayop2.d(307): Error: '[1] * 6' is not of integral type, it is a int[]
-fail_compilation/fail_arrayop2.d(308): Error: '[1] * 6' is not of integral type, it is a int[]
-fail_compilation/fail_arrayop2.d(311): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(248): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(249): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(253): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(256): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(265): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(268): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(269): Error: array operation `"abc"[] + '\x01'` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(272): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(275): Error: `([1] * 6)[0..2]` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(278): Error: can only `*` a pointer, not a `int[]`
+fail_compilation/fail_arrayop2.d(281): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail_arrayop2.d(281): Error: `[1] * 6` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(284): Error: array operation `da[] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(287): Error: array operation `da[] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(290): Error: `[1] * 6` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(291): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(294): Error: `[1] * 6` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(295): Error: `([1] * 6)[]` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(298): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(299): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(300): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(303): Error: `[1] * 6` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(304): Error: `[1] * 6` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(307): Error: `[1] * 6` is not of integral type, it is a `int[]`
+fail_compilation/fail_arrayop2.d(308): Error: `[1] * 6` is not of integral type, it is a `int[]`
+fail_compilation/fail_arrayop2.d(309): Error: `[1] * 6` is not of integral type, it is a `int[]`
fail_compilation/fail_arrayop2.d(312): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(315): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(313): Error: array operation `[1] * 6` without destination memory not allowed
fail_compilation/fail_arrayop2.d(316): Error: array operation `[1] * 6` without destination memory not allowed
fail_compilation/fail_arrayop2.d(317): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(320): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(320): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(320): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(318): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without destination memory not allowed
---
*/
// Test all expressions, which can take arrays as their operands but cannot be a part of array operation.
@@ -247,7 +249,6 @@ void test15407exp()
[1] * 6]; } // AssocArrayLiteralExp
//TupleExp
-
// StructLiteralExp.elements <- preFunctionParameters in CallExp
{ auto r = S([1] * 6); }
@@ -320,18 +321,18 @@ void test15407exp()
{ auto r = [1] * 6 ? [1] * 6 : [1] * 6; }
}
-/*
-TEST_OUTPUT:
+/* TEST_OUTPUT:
---
-fail_compilation/fail_arrayop2.d(341): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(344): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(347): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(342): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(345): Error: array operation `[1] * 6` without destination memory not allowed
fail_compilation/fail_arrayop2.d(348): Error: array operation `[1] * 6` without destination memory not allowed
fail_compilation/fail_arrayop2.d(349): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(352): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(355): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(358): Error: array operation `"str"[] + cast(immutable(char))1` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(366): Error: CTFE internal error: non-constant value "uvt"[]
+fail_compilation/fail_arrayop2.d(350): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(353): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(356): Error: array operation `[1] * 6` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(359): Error: array operation `"str"[] + cast(immutable(char))1` without destination memory not allowed
+fail_compilation/fail_arrayop2.d(367): Error: CTFE internal error: non-constant value `"uvt"`
+fail_compilation/fail_arrayop2.d(367): Error: `"uvt"[] - '\x01'` cannot be interpreted at compile time
---
*/
// Test all statements, which can take arrays as their operands.
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3a.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3a.d
new file mode 100644
index 0000000..55898d1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3a.d
@@ -0,0 +1,28 @@
+/*
+REQUIRED_ARGS: -o-
+TEST_OUTPUT:
+----
+$p:druntime/import/core/internal/array/operations.d$($n$): Error: static assert: "Binary `*` not supported for types `X` and `X`."
+$p:druntime/import/core/internal/array/operations.d$($n$): instantiated from here: `typeCheck!(true, X, X, X, "*", "=")`
+$p:druntime/import/object.d$($n$): instantiated from here: `arrayOp!(X[], X[], X[], "*", "=")`
+fail_compilation/fail_arrayop3a.d(19): instantiated from here: `_arrayOp!(X[], X[], X[], "*", "=")`
+----
+*/
+
+void test11376()
+{
+ struct X { }
+
+ auto x1 = [X()];
+ auto x2 = [X()];
+ auto x3 = [X()];
+ x1[] = x2[] * x3[];
+
+ string[] s1;
+ string[] s2;
+ s2[] += s1[];
+
+ int*[] pa1;
+ int*[] pa2;
+ pa1[] *= pa2[];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3b.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3b.d
new file mode 100644
index 0000000..87f2993
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3b.d
@@ -0,0 +1,16 @@
+/*
+REQUIRED_ARGS: -o-
+TEST_OUTPUT:
+----
+$p:druntime/import/core/internal/array/operations.d$($n$): Error: static assert: "Binary op `+=` not supported for types `string` and `string`."
+$p:druntime/import/core/internal/array/operations.d$($n$): instantiated from here: `typeCheck!(true, string, string, "+=")`
+$p:druntime/import/object.d$($n$): instantiated from here: `arrayOp!(string[], string[], "+=")`
+fail_compilation/fail_arrayop3b.d(15): instantiated from here: `_arrayOp!(string[], string[], "+=")`
+---
+*/
+void test11376()
+{
+ string[] s1;
+ string[] s2;
+ s2[] += s1[];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3c.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3c.d
new file mode 100644
index 0000000..2e9d61a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop3c.d
@@ -0,0 +1,16 @@
+/*
+REQUIRED_ARGS: -o-
+TEST_OUTPUT:
+----
+$p:druntime/import/core/internal/array/operations.d$($n$): Error: static assert: "Binary op `*=` not supported for types `int*` and `int*`."
+$p:druntime/import/core/internal/array/operations.d$($n$): instantiated from here: `typeCheck!(true, int*, int*, "*=")`
+$p:druntime/import/object.d$($n$): instantiated from here: `arrayOp!(int*[], int*[], "*=")`
+fail_compilation/fail_arrayop3c.d(15): instantiated from here: `_arrayOp!(int*[], int*[], "*=")`
+----
+*/
+void test11376()
+{
+ int*[] pa1;
+ int*[] pa2;
+ pa1[] *= pa2[];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_casting.d b/gcc/testsuite/gdc.test/fail_compilation/fail_casting.d
index 74337c3..88d579b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_casting.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_casting.d
@@ -93,11 +93,11 @@ void test11485()
class C {}
interface I {}
- // 11485 TypeBasic --> Tclass
+ // https://issues.dlang.org/show_bug.cgi?id=11485 TypeBasic --> Tclass
{ int x; auto y = cast(C)x; }
{ int x; auto y = cast(I)x; }
- // 7472 TypeBasic <-- Tclass
+ // https://issues.dlang.org/show_bug.cgi?id=7472 TypeBasic <-- Tclass
{ C x; auto y = cast(int)x; }
{ I x; auto y = cast(int)x; }
}
@@ -133,7 +133,7 @@ void test13959()
/*
TEST_OUTPUT:
---
-fail_compilation/fail_casting.d(144): Error: cannot cast expression `mi.x` of type `int` to `MyUbyte14154`
+fail_compilation/fail_casting.d(144): Error: cannot cast expression `mi` of type `MyInt14154` to `MyUbyte14154` because of different sizes
---
*/
struct MyUbyte14154 { ubyte x; alias x this; }
@@ -147,10 +147,10 @@ void test14154()
/*
TEST_OUTPUT:
---
-fail_compilation/fail_casting.d(179): Error: cannot cast expression `__tup$n$.__expand_field_0` of type `int` to `object.Object`
-fail_compilation/fail_casting.d(179): Error: cannot cast expression `__tup$n$.__expand_field_1` of type `int` to `object.Object`
+fail_compilation/fail_casting.d(179): Error: cannot cast expression `point` of type `Tuple14093!(int, "x", int, "y")` to `object.Object`
---
*/
+
alias TypeTuple14093(T...) = T;
struct Tuple14093(T...)
{
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_casting2.d b/gcc/testsuite/gdc.test/fail_compilation/fail_casting2.d
index a45d6d3..16bc5bc 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_casting2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_casting2.d
@@ -3,9 +3,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail_casting2.d(15): Error: type int is not an expression
+fail_compilation/fail_casting2.d(15): Error: type `int` is not an expression
fail_compilation/fail_casting2.d(17): Error: template lambda has no type
-fail_compilation/fail_casting2.d(20): Error: template Templ() has no type
+fail_compilation/fail_casting2.d(20): Error: template `Templ()` has no type
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_circular.d b/gcc/testsuite/gdc.test/fail_compilation/fail_circular.d
index dd958af..186444e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_circular.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_circular.d
@@ -1,16 +1,16 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail_circular.d(16): Error: circular reference to variable 'fail_circular.a1'
-fail_compilation/fail_circular.d(17): Error: circular reference to variable 'fail_circular.a2'
-fail_compilation/fail_circular.d(19): Error: circular reference to variable 'fail_circular.b1'
-fail_compilation/fail_circular.d(20): Error: circular reference to variable 'fail_circular.b2'
-fail_compilation/fail_circular.d(22): Error: circular reference to variable 'fail_circular.c1'
-fail_compilation/fail_circular.d(23): Error: circular reference to variable 'fail_circular.c2'
-fail_compilation/fail_circular.d(25): Error: circular initialization of variable 'fail_circular.d1'
-fail_compilation/fail_circular.d(26): Error: circular initialization of variable 'fail_circular.d2'
-fail_compilation/fail_circular.d(28): Error: circular initialization of variable 'fail_circular.e1'
-fail_compilation/fail_circular.d(29): Error: circular initialization of variable 'fail_circular.e2'
+fail_compilation/fail_circular.d(16): Error: circular reference to variable `fail_circular.a1`
+fail_compilation/fail_circular.d(17): Error: circular reference to variable `fail_circular.a2`
+fail_compilation/fail_circular.d(19): Error: circular reference to variable `fail_circular.b1`
+fail_compilation/fail_circular.d(20): Error: circular reference to variable `fail_circular.b2`
+fail_compilation/fail_circular.d(22): Error: circular reference to variable `fail_circular.c1`
+fail_compilation/fail_circular.d(23): Error: circular reference to variable `fail_circular.c2`
+fail_compilation/fail_circular.d(25): Error: circular initialization of variable `fail_circular.d1`
+fail_compilation/fail_circular.d(26): Error: circular initialization of variable `fail_circular.d2`
+fail_compilation/fail_circular.d(28): Error: circular initialization of variable `fail_circular.e1`
+fail_compilation/fail_circular.d(29): Error: circular initialization of variable `fail_circular.e2`
---
*/
auto a1 = a1; // semantic error (cannot determine expression type)
@@ -31,16 +31,16 @@ enum int e2 = .e2; // CTFE error
/*
TEST_OUTPUT:
---
-fail_compilation/fail_circular.d(47): Error: circular reference to variable 'fail_circular.a1a'
-fail_compilation/fail_circular.d(49): Error: circular reference to variable 'fail_circular.a2a'
-fail_compilation/fail_circular.d(52): Error: circular reference to variable 'fail_circular.b1a'
-fail_compilation/fail_circular.d(54): Error: circular reference to variable 'fail_circular.b2a'
-fail_compilation/fail_circular.d(57): Error: circular reference to variable 'fail_circular.c1a'
-fail_compilation/fail_circular.d(59): Error: circular reference to variable 'fail_circular.c2a'
-fail_compilation/fail_circular.d(62): Error: circular initialization of variable 'fail_circular.d1a'
-fail_compilation/fail_circular.d(64): Error: circular initialization of variable 'fail_circular.d2a'
-fail_compilation/fail_circular.d(67): Error: circular initialization of variable 'fail_circular.e1a'
-fail_compilation/fail_circular.d(69): Error: circular initialization of variable 'fail_circular.e2a'
+fail_compilation/fail_circular.d(47): Error: circular reference to variable `fail_circular.a1a`
+fail_compilation/fail_circular.d(49): Error: circular reference to variable `fail_circular.a2a`
+fail_compilation/fail_circular.d(52): Error: circular reference to variable `fail_circular.b1a`
+fail_compilation/fail_circular.d(54): Error: circular reference to variable `fail_circular.b2a`
+fail_compilation/fail_circular.d(57): Error: circular reference to variable `fail_circular.c1a`
+fail_compilation/fail_circular.d(59): Error: circular reference to variable `fail_circular.c2a`
+fail_compilation/fail_circular.d(62): Error: circular initialization of variable `fail_circular.d1a`
+fail_compilation/fail_circular.d(64): Error: circular initialization of variable `fail_circular.d2a`
+fail_compilation/fail_circular.d(67): Error: circular initialization of variable `fail_circular.e1a`
+fail_compilation/fail_circular.d(69): Error: circular initialization of variable `fail_circular.e2a`
---
*/
auto a1a = a1b;
@@ -71,12 +71,12 @@ enum int e2b = .e2a; // CTFE error
/*
TEST_OUTPUT:
---
-fail_compilation/fail_circular.d(84): Error: circular reference to variable 'fail_circular.S1.a1'
-fail_compilation/fail_circular.d(88): Error: circular reference to variable 'fail_circular.S2.b1'
-fail_compilation/fail_circular.d(92): Error: circular reference to variable 'fail_circular.S3.c1'
-fail_compilation/fail_circular.d(97): Error: circular reference to variable 'fail_circular.S4.a1a'
-fail_compilation/fail_circular.d(102): Error: circular reference to variable 'fail_circular.S5.b1a'
-fail_compilation/fail_circular.d(107): Error: circular reference to variable 'fail_circular.S6.c1a'
+fail_compilation/fail_circular.d(84): Error: circular reference to variable `fail_circular.S1.a1`
+fail_compilation/fail_circular.d(88): Error: circular reference to variable `fail_circular.S2.b1`
+fail_compilation/fail_circular.d(92): Error: circular reference to variable `fail_circular.S3.c1`
+fail_compilation/fail_circular.d(97): Error: circular reference to variable `fail_circular.S4.a1a`
+fail_compilation/fail_circular.d(102): Error: circular reference to variable `fail_circular.S5.b1a`
+fail_compilation/fail_circular.d(107): Error: circular reference to variable `fail_circular.S6.c1a`
---
*/
struct S1
@@ -110,12 +110,12 @@ struct S6
/*
TEST_OUTPUT:
---
-fail_compilation/fail_circular.d(123): Error: circular reference to variable 'fail_circular.C.a1'
-fail_compilation/fail_circular.d(125): Error: circular reference to variable 'fail_circular.C.b1'
-fail_compilation/fail_circular.d(127): Error: circular reference to variable 'fail_circular.C.c1'
-fail_compilation/fail_circular.d(130): Error: circular reference to variable 'fail_circular.C.a1a'
-fail_compilation/fail_circular.d(133): Error: circular reference to variable 'fail_circular.C.b1a'
-fail_compilation/fail_circular.d(136): Error: circular reference to variable 'fail_circular.C.c1a'
+fail_compilation/fail_circular.d(123): Error: circular reference to variable `fail_circular.C.a1`
+fail_compilation/fail_circular.d(125): Error: circular reference to variable `fail_circular.C.b1`
+fail_compilation/fail_circular.d(127): Error: circular reference to variable `fail_circular.C.c1`
+fail_compilation/fail_circular.d(130): Error: circular reference to variable `fail_circular.C.a1a`
+fail_compilation/fail_circular.d(133): Error: circular reference to variable `fail_circular.C.b1a`
+fail_compilation/fail_circular.d(136): Error: circular reference to variable `fail_circular.C.c1a`
---
*/
class C
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_circular2.d b/gcc/testsuite/gdc.test/fail_compilation/fail_circular2.d
index f04d272..6db68c6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_circular2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_circular2.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail_circular2.d(10): Error: circular initialization of variable 'fail_circular2.S.d1'
-fail_compilation/fail_circular2.d(12): Error: circular initialization of variable 'fail_circular2.S.e1'
+fail_compilation/fail_circular2.d(10): Error: circular initialization of variable `fail_circular2.S.d1`
+fail_compilation/fail_circular2.d(12): Error: circular initialization of variable `fail_circular2.S.e1`
---
*/
struct S
@@ -15,8 +15,8 @@ struct S
/*
TEST_OUTPUT:
---
-fail_compilation/fail_circular2.d(24): Error: circular initialization of variable 'fail_circular2.C.d1'
-fail_compilation/fail_circular2.d(26): Error: circular initialization of variable 'fail_circular2.C.e1'
+fail_compilation/fail_circular2.d(24): Error: circular initialization of variable `fail_circular2.C.d1`
+fail_compilation/fail_circular2.d(26): Error: circular initialization of variable `fail_circular2.C.e1`
---
*/
class C
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_contracts3.d b/gcc/testsuite/gdc.test/fail_compilation/fail_contracts3.d
index de3e9bb..b0b366b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_contracts3.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_contracts3.d
@@ -6,9 +6,9 @@ fail_compilation/fail_contracts3.d(13): Error: function `fail_contracts3.D.foo`
*/
class C {
- void foo(){}
+ void foo(){}
}
class D : C {
- override void foo()in{}do{}
+ override void foo()in{}do{}
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_opover.d b/gcc/testsuite/gdc.test/fail_compilation/fail_opover.d
index ba930f0..2a62f53 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_opover.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_opover.d
@@ -3,8 +3,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/fail_opover.d(13): Error: no [] operator overload for type object.Object
-fail_compilation/fail_opover.d(17): Error: no [] operator overload for type TestS
+fail_compilation/fail_opover.d(13): Error: no `[]` operator overload for type `object.Object`
+fail_compilation/fail_opover.d(17): Error: no `[]` operator overload for type `TestS`
---
*/
void test1()
@@ -20,18 +20,18 @@ void test1()
/*
TEST_OUTPUT:
---
-fail_compilation/fail_opover.d(46): Error: no [] operator overload for type S
-fail_compilation/fail_opover.d(47): Error: no [] operator overload for type S
-fail_compilation/fail_opover.d(48): Error: no [] operator overload for type S
-fail_compilation/fail_opover.d(49): Error: no [] operator overload for type S
-fail_compilation/fail_opover.d(50): Error: no [] operator overload for type S
-fail_compilation/fail_opover.d(51): Error: no [] operator overload for type S
-fail_compilation/fail_opover.d(52): Error: no [] operator overload for type S
-fail_compilation/fail_opover.d(53): Error: no [] operator overload for type S
-fail_compilation/fail_opover.d(54): Error: no [] operator overload for type S
-fail_compilation/fail_opover.d(55): Error: no [] operator overload for type S
-fail_compilation/fail_opover.d(56): Error: no [] operator overload for type S
-fail_compilation/fail_opover.d(57): Error: no [] operator overload for type S
+fail_compilation/fail_opover.d(46): Error: no `[]` operator overload for type `S`
+fail_compilation/fail_opover.d(47): Error: no `[]` operator overload for type `S`
+fail_compilation/fail_opover.d(48): Error: no `[]` operator overload for type `S`
+fail_compilation/fail_opover.d(49): Error: no `[]` operator overload for type `S`
+fail_compilation/fail_opover.d(50): Error: no `[]` operator overload for type `S`
+fail_compilation/fail_opover.d(51): Error: no `[]` operator overload for type `S`
+fail_compilation/fail_opover.d(52): Error: no `[]` operator overload for type `S`
+fail_compilation/fail_opover.d(53): Error: no `[]` operator overload for type `S`
+fail_compilation/fail_opover.d(54): Error: no `[]` operator overload for type `S`
+fail_compilation/fail_opover.d(55): Error: no `[]` operator overload for type `S`
+fail_compilation/fail_opover.d(56): Error: no `[]` operator overload for type `S`
+fail_compilation/fail_opover.d(57): Error: no `[]` operator overload for type `S`
---
*/
void test2()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_pretty_errors.d b/gcc/testsuite/gdc.test/fail_compilation/fail_pretty_errors.d
new file mode 100644
index 0000000..d25e8f7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_pretty_errors.d
@@ -0,0 +1,36 @@
+/*
+REQUIRED_ARGS: -verrors=context
+TEST_OUTPUT:
+---
+fail_compilation/fail_pretty_errors.d(20): Error: undefined identifier `a`
+ a = 1;
+ ^
+fail_compilation/fail_pretty_errors.d-mixin-25(25): Error: undefined identifier `b`
+fail_compilation/fail_pretty_errors.d(30): Error: cannot implicitly convert expression `5` of type `int` to `string`
+ string x = 5;
+ ^
+fail_compilation/fail_pretty_errors.d(35): Error: mixin `fail_pretty_errors.testMixin2.mixinTemplate!()` error instantiating
+ mixin mixinTemplate;
+ ^
+---
+*/
+
+void foo()
+{
+ a = 1;
+}
+
+void testMixin1()
+{
+ mixin("b = 1;");
+}
+
+mixin template mixinTemplate()
+{
+ string x = 5;
+}
+
+void testMixin2()
+{
+ mixin mixinTemplate;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d
index c634253..41a8c2d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d
@@ -1,16 +1,19 @@
/*
-PERMUTE_ARGS:
-REQUIRED_ARGS: -dip25
+REQUIRED_ARGS:
TEST_OUTPUT:
---
-fail_compilation/fail_scope.d(45): Error: returning `cast(char[])string` escapes a reference to local variable `string`
-fail_compilation/fail_scope.d(63): Error: returning `s.bar()` escapes a reference to local variable `s`
-fail_compilation/fail_scope.d(82): Error: returning `& string` escapes a reference to local variable `string`
-fail_compilation/fail_scope.d(92): Error: returning `cast(int[])a` escapes a reference to local variable `a`
-fail_compilation/fail_scope.d(100): Error: returning `cast(int[])a` escapes a reference to local variable `a`
-fail_compilation/fail_scope.d(108): Error: escaping reference to outer local variable `x`
-fail_compilation/fail_scope.d(127): Error: returning `s.bar()` escapes a reference to local variable `s`
-fail_compilation/fail_scope.d(137): Error: returning `foo16226(i)` escapes a reference to local variable `i`
+fail_compilation/fail_scope.d(44): Error: returning `cast(char[])string` escapes a reference to local variable `string`
+fail_compilation/fail_scope.d(62): Error: returning `s.bar()` escapes a reference to local variable `s`
+fail_compilation/fail_scope.d(73): Error: `fail_scope.foo8` called with argument types `(int)` matches both:
+fail_compilation/fail_scope.d(67): `fail_scope.foo8(ref int x)`
+and:
+fail_compilation/fail_scope.d(68): `fail_scope.foo8(return ref int x)`
+fail_compilation/fail_scope.d(81): Error: returning `& string` escapes a reference to local variable `string`
+fail_compilation/fail_scope.d(91): Error: returning `cast(int[])a` escapes a reference to local variable `a`
+fail_compilation/fail_scope.d(99): Error: returning `cast(int[])a` escapes a reference to local variable `a`
+fail_compilation/fail_scope.d(107): Deprecation: escaping reference to outer local variable `x`
+fail_compilation/fail_scope.d(126): Error: returning `s.bar()` escapes a reference to local variable `s`
+fail_compilation/fail_scope.d(136): Error: returning `foo16226(i)` escapes a reference to local variable `i`
---
//fail_compilation/fail_scope.d(30): Error: scope variable `da` may not be returned
//fail_compilation/fail_scope.d(32): Error: scope variable `o` may not be returned
@@ -21,10 +24,6 @@ fail_compilation/fail_scope.d(137): Error: returning `foo16226(i)` escapes a ref
//fail_compilation/fail_scope.d(40): Error: scope variable `p` may not be returned
*/
-
-
-
-
alias int delegate() dg_t;
int[] checkEscapeScope1(scope int[] da) { return da; }
@@ -86,7 +85,7 @@ char* fail141()
int[] test1313b()
out{}
-body
+do
{
int[2] a;
return a;
@@ -94,7 +93,7 @@ body
int[] test1313a()
//out{}
-body
+do
{
int[2] a;
return a;
@@ -142,4 +141,3 @@ ref foo16226(ref int bar) @safe
{
return bar;
}
-
diff --git a/gcc/testsuite/gdc.test/fail_compilation/failattr.d b/gcc/testsuite/gdc.test/fail_compilation/failattr.d
index e0b4562..c7f0f31 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/failattr.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/failattr.d
@@ -3,12 +3,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/failattr.d(16): Error: variable failattr.C2901.v1 cannot be synchronized
-fail_compilation/failattr.d(17): Error: variable failattr.C2901.v2 cannot be override
-fail_compilation/failattr.d(18): Error: variable failattr.C2901.v3 cannot be abstract
-fail_compilation/failattr.d(19): Error: variable failattr.C2901.v4 cannot be final, perhaps you meant const?
-fail_compilation/failattr.d(31): Error: variable failattr.C2901.v13 cannot be final abstract synchronized override
-fail_compilation/failattr.d(33): Error: variable failattr.C2901.v14 cannot be final, perhaps you meant const?
+fail_compilation/failattr.d(16): Error: variable `failattr.C2901.v1` cannot be `synchronized`
+fail_compilation/failattr.d(17): Error: variable `failattr.C2901.v2` cannot be `override`
+fail_compilation/failattr.d(18): Error: variable `failattr.C2901.v3` cannot be `abstract`
+fail_compilation/failattr.d(19): Error: variable `failattr.C2901.v4` cannot be `final`, perhaps you meant `const`?
+fail_compilation/failattr.d(31): Error: variable `failattr.C2901.v13` cannot be `final abstract synchronized override`
+fail_compilation/failattr.d(33): Error: variable `failattr.C2901.v14` cannot be `final`, perhaps you meant `const`?
---
*/
class C2901
diff --git a/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d b/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d
index f190141..95663ea 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/faildeleteaa.d(11): Error: cannot delete type int
+fail_compilation/faildeleteaa.d(12): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/faildeleteaa.d(12): Error: cannot delete type `int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d b/gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d
index af238f7..d7853e6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/faildottypeinfo.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/faildottypeinfo.d(11): Error: no property 'typeinfo' for type 'int'
-fail_compilation/faildottypeinfo.d(12): Error: no property 'typeinfo' for type 'object.Object'
+fail_compilation/faildottypeinfo.d(11): Error: no property `typeinfo` for type `int`
+fail_compilation/faildottypeinfo.d(12): Error: no property `typeinfo` for type `object.Object`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/failmemalloc.d b/gcc/testsuite/gdc.test/fail_compilation/failmemalloc.d
deleted file mode 100644
index 713c180..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/failmemalloc.d
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/failmemalloc.d(13): Error: member allocators not supported by CTFE
----
-*/
-
-struct S
-{
- new(size_t sz) { return null; }
-}
-
-S* s = new S();
diff --git a/gcc/testsuite/gdc.test/fail_compilation/failob1.d b/gcc/testsuite/gdc.test/fail_compilation/failob1.d
new file mode 100644
index 0000000..7fe73d3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/failob1.d
@@ -0,0 +1,34 @@
+/*
+REQUIRED_ARGS:-preview=dip1021
+TEST_OUTPUT:
+---
+fail_compilation/failob1.d(104): Error: variable `failob1.test1.a1` is left dangling at return
+fail_compilation/failob1.d(105): Error: variable `failob1.test2.a2` is left dangling at return
+fail_compilation/failob1.d(107): Error: variable `failob1.test4.s4` is left dangling at return
+fail_compilation/failob1.d(108): Error: variable `failob1.test5.dg5` is left dangling at return
+fail_compilation/failob1.d(115): Error: variable `failob1.test12.p12` is left dangling at return
+---
+*/
+
+struct S { int i; int* f; }
+struct T { int i; const(int)* f; }
+class C { int i; int* f; }
+
+#line 100
+
+@live
+{
+ // Test what is and is not a trackable variable
+ void test1(int[] a1) { } // error
+ void test2(int*[3] a2) { } // error
+ void test3(const int*[3] a) { } // ok
+ void test4(S s4) { } // error
+ void test5(int delegate() dg5) { } // error
+ void test6(const(int*)[3] a) { } // ok
+ void test7(const(int)*[3] a) { } // ok
+ void test8(const(int)* p) { } // ok
+ void test9(T t) { } // ok
+ void test10(C c) { } // ok
+ void test11(int i) { } // ok
+ void test12(int* p12) { } // error
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/failob2.d b/gcc/testsuite/gdc.test/fail_compilation/failob2.d
new file mode 100644
index 0000000..bd52648
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/failob2.d
@@ -0,0 +1,67 @@
+// REQUIRED_ARGS: -preview=dip1021
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/failob2.d(105): Error: variable `failob2.foo1!int.foo1.p` has undefined state and cannot be read
+fail_compilation/failob2.d(105): Error: variable `failob2.foo1!int.foo1.p` is returned but is Undefined
+fail_compilation/failob2.d(124): Error: template instance `failob2.foo1!int` error instantiating
+fail_compilation/failob2.d(111): Error: variable `failob2.foo2!int.foo2.p` has undefined state and cannot be read
+fail_compilation/failob2.d(111): Error: variable `failob2.foo2!int.foo2.p` is returned but is Undefined
+fail_compilation/failob2.d(125): Error: template instance `failob2.foo2!int` error instantiating
+fail_compilation/failob2.d(119): Error: variable `failob2.foo3!int.foo3.p` has undefined state and cannot be read
+fail_compilation/failob2.d(119): Error: variable `failob2.foo3!int.foo3.p` is returned but is Undefined
+fail_compilation/failob2.d(126): Error: template instance `failob2.foo3!int` error instantiating
+---
+*/
+
+#line 100
+
+@live
+T* foo1(T)()
+{
+ T* p = void;
+ return p;
+}
+
+template foo2(T) {
+ @live T* foo2() {
+ T* p = void;
+ return p;
+ }
+}
+
+@live
+template foo3(T) {
+ T* foo3() {
+ T* p = void;
+ return p;
+ }
+}
+
+void test1() {
+ foo1!int();
+ foo2!int();
+ foo3!int();
+}
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/failob2.d(205): Error: variable `failob2.foo4!int.foo4.p` is left dangling at return
+fail_compilation/failob2.d(209): Error: template instance `failob2.foo4!int` error instantiating
+---
+*/
+
+#line 200
+
+void* alloc(size_t);
+
+@live void foo4(T)()
+{
+ auto p = alloc(4);
+}
+
+void test2() {
+ foo4!int();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/failoffset.d b/gcc/testsuite/gdc.test/fail_compilation/failoffset.d
index c991d47..bbec698 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/failoffset.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/failoffset.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/failoffset.d(12): Error: no property 'offset' for type 'int'
+fail_compilation/failoffset.d(12): Error: no property `offset` for type `int`
fail_compilation/failoffset.d(12): while evaluating: `static assert(b.offset == 4)`
---
*/
diff --git a/gcc/testsuite/gdc.test/compilable/fix17349.d b/gcc/testsuite/gdc.test/fail_compilation/fix17349.d
index 2222c35..493d30f 100644
--- a/gcc/testsuite/gdc.test/compilable/fix17349.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fix17349.d
@@ -1,8 +1,6 @@
-/* REQUIRED_ARGS: -dw
- * PERMUTE_ARGS:
- * TEST_OUTPUT:
+/* TEST_OUTPUT:
---
-compilable/fix17349.d(37): Deprecation: cannot implicitly override base class method `fix17349.E.foo` with `fix17349.F.foo`; add `override` attribute
+fail_compilation/fix17349.d(35): Error: cannot implicitly override base class method `fix17349.E.foo` with `fix17349.F.foo`; add `override` attribute
---
*/
@@ -36,5 +34,3 @@ class E {
class F : E {
void foo(const void*);
}
-
-
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix17635.d b/gcc/testsuite/gdc.test/fail_compilation/fix17635.d
new file mode 100644
index 0000000..27f55e0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fix17635.d
@@ -0,0 +1,23 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fix17635.d(22): Error: cannot implicitly convert expression `f(& p)` of type `immutable(int)**` to `immutable(int**)`
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=17635
+// https://issues.dlang.org/show_bug.cgi?id=15660
+
+alias T = immutable int;
+
+T** f(const T** input) pure
+{
+ T** output;
+ return output;
+}
+
+void main()
+{
+ T i;
+ T* p = &i;
+ immutable T** r = f(&p);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix17751.d b/gcc/testsuite/gdc.test/fail_compilation/fix17751.d
new file mode 100644
index 0000000..11b9c54
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fix17751.d
@@ -0,0 +1,22 @@
+/* REQUIRED_ARGS: -m64
+ * TEST_OUTPUT:
+---
+fail_compilation/fix17751.d(15): Error: last parameter to `__simd()` must be a constant
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=17751
+
+import core.simd;
+
+pure @safe V1 simd(XMM opcode, V1, V2)(V1 op1, V2 op2, ubyte imm8)
+ if (is(V1 == __vector) && is(V2 == __vector))
+{
+ return cast(V1)__simd(opcode, op1, op2, imm8);
+}
+
+void main()
+{
+ float4 a, b;
+ a = simd!(XMM.CMPPD)(a, b, 0x7A);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix18575.d b/gcc/testsuite/gdc.test/fail_compilation/fix18575.d
new file mode 100644
index 0000000..7b8f287
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fix18575.d
@@ -0,0 +1,41 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fix18575.d(27): Error: returning `s.foo()` escapes a reference to local variable `s`
+fail_compilation/fix18575.d(31): Error: returning `s.foo()` escapes a reference to local variable `s`
+fail_compilation/fix18575.d(35): Error: returning `s.abc()` escapes a reference to local variable `s`
+fail_compilation/fix18575.d(39): Error: returning `s.ghi(t)` escapes a reference to local variable `t`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=18575
+
+@safe:
+
+struct S {
+@safe:
+ int x;
+
+ void bar() { }
+ auto foo() { return &this.bar; }
+ auto def() { return &bar; }
+ auto abc() { return &x; }
+ auto ghi(ref S s) { return &s.bar; }
+}
+
+auto f(S s) {
+ return s.foo();
+}
+
+auto g(S s) {
+ return s.foo();
+}
+
+auto h(S s) {
+ return s.abc();
+}
+
+auto j(S s, S t) {
+ return s.ghi(t);
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix19018.d b/gcc/testsuite/gdc.test/fail_compilation/fix19018.d
new file mode 100644
index 0000000..b2a2a30
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fix19018.d
@@ -0,0 +1,21 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fix19018.d(16): Error: `0b` isn't a valid integer literal, use `0b0` instead
+fail_compilation/fix19018.d(17): Error: `0B` isn't a valid integer literal, use `0B0` instead
+fail_compilation/fix19018.d(18): Error: `0x` isn't a valid integer literal, use `0x0` instead
+fail_compilation/fix19018.d(19): Error: `0X` isn't a valid integer literal, use `0X0` instead
+fail_compilation/fix19018.d(20): Error: `0x_` isn't a valid integer literal, use `0x0` instead
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=19018
+
+void foo()
+{
+ auto a = 0b;
+ auto b = 0B;
+ auto c = 0x;
+ auto d = 0X;
+ auto e = 0x_;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix19059.d b/gcc/testsuite/gdc.test/fail_compilation/fix19059.d
new file mode 100644
index 0000000..0be003a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fix19059.d
@@ -0,0 +1,19 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fix19059.d(16): Error: octal digit expected, not `8`
+fail_compilation/fix19059.d(16): Error: octal literals larger than 7 are no longer supported
+fail_compilation/fix19059.d(17): Error: octal digit expected, not `9`
+fail_compilation/fix19059.d(17): Error: octal literals larger than 7 are no longer supported
+fail_compilation/fix19059.d(18): Error: octal literals `010` are no longer supported, use `std.conv.octal!10` instead
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=19059
+
+void foo()
+{
+ auto a = 08;
+ auto b = 09;
+ auto c = 010;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix19246.d b/gcc/testsuite/gdc.test/fail_compilation/fix19246.d
new file mode 100644
index 0000000..55b9650
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fix19246.d
@@ -0,0 +1,19 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fix19246.d(15): Error: `0b_` isn't a valid integer literal, use `0b0` instead
+fail_compilation/fix19246.d(16): Error: `0B_` isn't a valid integer literal, use `0B0` instead
+fail_compilation/fix19246.d(17): Error: `0b` isn't a valid integer literal, use `0b0` instead
+fail_compilation/fix19246.d(18): Error: `0B` isn't a valid integer literal, use `0B0` instead
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=19246
+
+void foo()
+{
+ auto a = 0b_;
+ auto b = 0B_;
+ auto c = 0b;
+ auto d = 0B;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix5212.d b/gcc/testsuite/gdc.test/fail_compilation/fix5212.d
new file mode 100644
index 0000000..faf2e29
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fix5212.d
@@ -0,0 +1,17 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fix5212.d(14): Error: scope variable `args_` assigned to non-scope `this.args`
+---
+*/
+
+
+// https://issues.dlang.org/show_bug.cgi?id=5212
+
+class Foo {
+ int[] args;
+ @safe this(int[] args_...) {
+ args = args_;
+ }
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fob1.d b/gcc/testsuite/gdc.test/fail_compilation/fob1.d
new file mode 100644
index 0000000..1f23122
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fob1.d
@@ -0,0 +1,63 @@
+// REQUIRED_ARGS: -preview=dip1021
+
+/* TEST_OUTPUT:
+---
+fail_compilation/fob1.d(104): Error: variable `fob1.foo1.p` has undefined state and cannot be read
+fail_compilation/fob1.d(104): Error: variable `fob1.foo1.p` is returned but is Undefined
+---
+*/
+
+#line 100
+
+@live int* foo1()
+{
+ int* p = void;
+ return p;
+}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/fob1.d(203): Error: variable `fob1.foo2.p` is left dangling at return
+---
+*/
+
+#line 200
+
+@live void foo2()
+{
+ int* p;
+ p = null;
+}
+
+
+/* TEST_OUTPUT:
+---
+fail_compilation/fob1.d(304): Error: variable `fob1.foo3.p` has undefined state and cannot be read
+fail_compilation/fob1.d(304): Error: variable `fob1.foo3.p` is returned but is Undefined
+fail_compilation/fob1.d(303): Error: variable `fob1.foo3.q` is left dangling at return
+---
+*/
+
+#line 300
+
+@live int* foo3(int* p)
+{
+ int* q = p;
+ return p;
+}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/fob1.d(405): Error: variable `fob1.foo4.bq` has undefined state and cannot be read
+---
+*/
+
+#line 400
+
+@live int* foo4(int* p)
+{
+ scope int* bq = p;
+ scope const int* cq = p;
+ *bq = 1;
+ return p;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fob2.d b/gcc/testsuite/gdc.test/fail_compilation/fob2.d
new file mode 100644
index 0000000..dbe8ea2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fob2.d
@@ -0,0 +1,178 @@
+/* Testing Ownership/Borrowing system
+REQUIRED_ARGS: -preview=dip1021
+ */
+
+int* malloc();
+void free(int*);
+
+/* TEST_OUTPUT:
+---
+fail_compilation/fob2.d(110): Error: variable `fob2.foo1.b1` has undefined state and cannot be read
+fail_compilation/fob2.d(103): Error: variable `fob2.foo1.p` is left dangling at return
+---
+*/
+
+#line 100
+
+@live int foo1(int i)
+{
+ int* p = malloc();
+ scope const(int)* b1, b2;
+ if (i)
+ b1 = p;
+ else
+ b2 = p;
+ *p = 3;
+ return *b1;
+}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/fob2.d(203): Error: variable `fob2.zoo2.p` is passed as Owner more than once
+fail_compilation/fob2.d(202): Error: variable `fob2.zoo2.p` is left dangling at return
+---
+*/
+
+#line 200
+
+@live void zoo2() {
+ int* p = malloc();
+ foo2(p, p + 1);
+}
+
+@live void foo2( scope int* p, scope int* q );
+
+/* TEST_OUTPUT:
+---
+fail_compilation/fob2.d(303): Error: variable `fob2.foo3.b` is left dangling at return
+---
+*/
+
+#line 300
+
+@live void foo3()
+{
+ scope int* b = malloc();
+}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/fob2.d(427): Error: variable `fob2.test43.p` is both Owner and Undefined
+fail_compilation/fob2.d(429): Error: variable `fob2.test43.p` has undefined state and cannot be read
+fail_compilation/fob2.d(429): Error: variable `fob2.test43.p` is not Owner, cannot consume its value
+fail_compilation/fob2.d(432): Error: variable `fob2.test43.p` has undefined state and cannot be read
+fail_compilation/fob2.d(432): Error: variable `fob2.test43.p` is not Owner, cannot consume its value
+---
+*/
+#line 400
+
+
+bool f();
+
+@live void test41(int* p, int i)
+{
+ for (; f(); ++i)
+ {
+ --i;
+ free(p);
+ p = null;
+ }
+ free(p);
+}
+
+@live void test42(int* p, int i)
+{
+ for (; f(); ++i)
+ {
+ --i;
+ }
+ free(p);
+}
+
+
+@live void test43(int* p, int i)
+{
+ for (; f(); ++i)
+ {
+ free(p);
+ --i;
+ }
+ free(p);
+}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/fob2.d(506): Error: variable `fob2.test51.p` has undefined state and cannot be read
+fail_compilation/fob2.d(515): Error: variable `fob2.test52.p` has undefined state and cannot be read
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=20747
+
+#line 500
+
+@live test51()
+{
+ int x;
+ scope p = &x;
+ x = 3;
+ *p = 4;
+}
+
+
+@live void test52()
+{
+ int x = 5;
+ auto p = &x;
+ auto q = &x;
+ *p = 3;
+}
+
+
+@live void test53()
+{
+ scope int x;
+ scope int y;
+ y = x;
+ x = 3;
+ y = 4;
+}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/fob2.d(603): Error: variable `fob2.test6.p` is left dangling at return
+---
+*/
+
+#line 600
+
+@live extern (C) void foo6(int, scope ...);
+
+@live void test6(int* p)
+{
+ foo6(1, p);
+}
+
+@live extern (C) void foo6b(int, scope const ...);
+
+@live int* test6b(return int* p)
+{
+ foo6b(1, p, p);
+ return p;
+}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/fob2.d(705): Error: variable `fob2.test7.p` is not Owner, cannot consume its value
+---
+*/
+
+#line 700
+
+void free7(int*);
+
+@live void test7(scope int* p)
+{
+ free7(p);
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d
index eaf8593..84d39eb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d
@@ -3,7 +3,7 @@
TEST_OUTPUT:
---
fail_compilation/gag4269f.d(11): Error: undefined identifier `Y9`, did you mean interface `X9`?
-fail_compilation/gag4269f.d(11): Error: variable gag4269f.X9.y field not allowed in interface
+fail_compilation/gag4269f.d(11): Error: variable `gag4269f.X9.y` field not allowed in interface
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/goto1.d b/gcc/testsuite/gdc.test/fail_compilation/goto1.d
new file mode 100644
index 0000000..b35a1c3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/goto1.d
@@ -0,0 +1,26 @@
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/goto1.d(1010): Error: `return` statements cannot be in `finally` bodies
+---
+ */
+
+void foo();
+void bar();
+
+#line 1000
+
+void test2()
+{
+ try
+ {
+ foo();
+ }
+ finally
+ {
+ bar();
+ return;
+ }
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/goto2.d b/gcc/testsuite/gdc.test/fail_compilation/goto2.d
new file mode 100644
index 0000000..72e8bcb6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/goto2.d
@@ -0,0 +1,143 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/goto2.d(1024): Error: case cannot be in different `try` block level from `switch`
+fail_compilation/goto2.d(1026): Error: default cannot be in different `try` block level from `switch`
+fail_compilation/goto2.d(1003): Error: cannot `goto` into `try` block
+---
+ */
+
+
+void foo();
+void bar();
+
+#line 1000
+
+void test1()
+{
+ goto L1;
+ try
+ {
+ foo();
+ L1:
+ { }
+ }
+ finally
+ {
+ bar();
+ }
+
+ /********************************/
+
+ int i;
+ switch (i)
+ {
+ case 1:
+ try
+ {
+ foo();
+ case 2:
+ { }
+ default:
+ { }
+ }
+ finally
+ {
+ bar();
+ }
+ break;
+ }
+}
+
+/**************************************************
+https://issues.dlang.org/show_bug.cgi?id=11540
+goto label + try-catch-finally / with statement
+
+TEST_OUTPUT:
+---
+fail_compilation/goto2.d(1121): Error: cannot `goto` into `try` block
+---
+*/
+#line 1100
+
+int interpret3a()
+{
+ // enter to TryCatchStatement.body
+ {
+ bool c = false;
+ try
+ {
+ if (c) // need to bypass front-end optimization
+ throw new Exception("");
+ else
+ {
+ goto Lx;
+ L1:
+ c = true;
+ }
+ }
+ catch (Exception e) {}
+
+ Lx:
+ if (!c)
+ goto L1;
+ }
+ return 1;
+}
+
+/**************************************************
+https://issues.dlang.org/show_bug.cgi?id=11540
+goto label + try-catch-finally / with statement
+
+TEST_OUTPUT:
+---
+fail_compilation/goto2.d(1217): Error: cannot `goto` into `try` block
+---
+*/
+#line 1200
+
+int interpret3b()
+{
+ // enter back to TryFinallyStatement.body
+ {
+ bool c = false;
+ try
+ {
+ goto Lx;
+ L1:
+ c = true;
+ }
+ finally {
+ }
+
+ Lx:
+ if (!c)
+ goto L1;
+ }
+
+ return 1;
+}
+
+/**************************************************
+https://issues.dlang.org/show_bug.cgi?id=13815
+
+TEST_OUTPUT:
+---
+fail_compilation/goto2.d(1234): Error: cannot `goto` into `try` block
+---
+*/
+
+bool f()
+{
+ goto L;
+ try
+ {
+L: // line 7
+ throw new Exception(""); // line 8
+ }
+ catch (Exception e)
+ {
+ return true;
+ }
+ return false;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/goto3.d b/gcc/testsuite/gdc.test/fail_compilation/goto3.d
new file mode 100644
index 0000000..4b811fa
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/goto3.d
@@ -0,0 +1,37 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/goto3.d(1010): Error: case cannot be in different `try` block level from `switch`
+fail_compilation/goto3.d(1012): Error: default cannot be in different `try` block level from `switch`
+---
+ */
+
+
+void foo();
+void bar();
+
+#line 1000
+
+void test1()
+{
+ int i;
+ switch (i)
+ {
+ case 1:
+ try
+ {
+ foo();
+ case 2:
+ { }
+ default:
+ { }
+ }
+ finally
+ {
+ bar();
+ }
+ break;
+ }
+}
+
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10016.d b/gcc/testsuite/gdc.test/fail_compilation/ice10016.d
index ff72131..2f444f1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10016.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10016.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/ice10016.d(33): Error: undefined identifier `unknownIdentifier`
-fail_compilation/ice10016.d(47): Error: template instance ice10016.RefCounted!(S) error instantiating
+fail_compilation/ice10016.d(47): Error: template instance `ice10016.RefCounted!(S)` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10076.d b/gcc/testsuite/gdc.test/fail_compilation/ice10076.d
index 8337d7f..24f92d7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10076.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10076.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10076.d(18): Error: template instance getMembersAndAttributesWhere!() template 'getMembersAndAttributesWhere' is not defined
-fail_compilation/ice10076.d(23): Error: template instance ice10076.getValidaterAttrs!string error instantiating
-fail_compilation/ice10076.d(13): instantiated from here: validate!string
+fail_compilation/ice10076.d(18): Error: template instance `getMembersAndAttributesWhere!()` template `getMembersAndAttributesWhere` is not defined
+fail_compilation/ice10076.d(23): Error: template instance `ice10076.getValidaterAttrs!string` error instantiating
+fail_compilation/ice10076.d(13): instantiated from here: `validate!string`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10212.d b/gcc/testsuite/gdc.test/fail_compilation/ice10212.d
index ce4a671..b9fe2aa 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10212.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10212.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10212.d(12): Error: mismatched function return type inference of `int function() pure nothrow @nogc @safe` and `int`
+fail_compilation/ice10212.d(13): Error: Expected return type of `int`, not `int function() pure nothrow @nogc @safe`:
+fail_compilation/ice10212.d(13): Return type of `int` inferred here.
---
*/
@@ -9,7 +10,7 @@ int delegate() foo()
{
// returns "int function() pure nothrow @safe function() pure nothrow @safe"
// and it mismatches to "int delegate()"
- return () => {
+ return () => () {
return 1;
};
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10259.d b/gcc/testsuite/gdc.test/fail_compilation/ice10259.d
index e12df7d..4a7b0df 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10259.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10259.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10259.d(11): Error: circular reference to 'ice10259.D.d'
-fail_compilation/ice10259.d(11): called from here: (*function () => x)()
+fail_compilation/ice10259.d(11): Error: circular reference to `ice10259.D.d`
+fail_compilation/ice10259.d(11): called from here: `(*function () pure nothrow @safe => x)()`
---
*/
class D
@@ -15,8 +15,8 @@ enum x = new D;
/*
TEST_OUTPUT:
---
-fail_compilation/ice10259.d(25): Error: circular reference to 'ice10259.D2.d'
-fail_compilation/ice10259.d(25): called from here: (*function () => x)()
+fail_compilation/ice10259.d(25): Error: circular reference to `ice10259.D2.d`
+fail_compilation/ice10259.d(25): called from here: `(*function () pure nothrow @safe => x)()`
---
*/
class D2
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10341.d b/gcc/testsuite/gdc.test/fail_compilation/ice10341.d
index ed6b6cb..56be4b3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10341.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10341.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10341.d(10): Error: case range not in switch statement
+fail_compilation/ice10341.d(10): Error: case range not in `switch` statement
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10419.d b/gcc/testsuite/gdc.test/fail_compilation/ice10419.d
index 47d1f73..827f045 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10419.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10419.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10419.d(12): Error: arr().length is not an lvalue
+fail_compilation/ice10419.d(12): Error: `arr().length` is not an lvalue and cannot be modified
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10600.d b/gcc/testsuite/gdc.test/fail_compilation/ice10600.d
index b1ee906..a240045 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10600.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10600.d
@@ -1,7 +1,8 @@
/*
+EXTRA_FILES: imports/ice10600a.d imports/ice10600b.d
TEST_OUTPUT:
---
-fail_compilation/ice10600.d(30): Error: template instance to!(int, double) does not match template declaration to(T)
+fail_compilation/ice10600.d(31): Error: template instance `to!(int, double)` does not match template declaration `to(T)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10616.d b/gcc/testsuite/gdc.test/fail_compilation/ice10616.d
index 6ccd1c3..654e16f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10616.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10616.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10616.d(8): Error: class ice10616.A is forward referenced when looking for 'B'
+fail_compilation/ice10616.d(8): Error: class `ice10616.A` is forward referenced when looking for `B`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10624.d b/gcc/testsuite/gdc.test/fail_compilation/ice10624.d
index 883b98e..3bc3c7d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10624.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10624.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10624.d(38): Error: need member function opCmp() for struct Tuple!(Msg) to compare
-fail_compilation/ice10624.d(48): Error: template instance ice10624.Variant.handler!(Tuple!(Msg)) error instantiating
-fail_compilation/ice10624.d(21): instantiated from here: opAssign!(Tuple!(Msg))
+fail_compilation/ice10624.d(38): Error: need member function `opCmp()` for struct `Tuple!(Msg)` to compare
+fail_compilation/ice10624.d(48): Error: template instance `ice10624.Variant.handler!(Tuple!(Msg))` error instantiating
+fail_compilation/ice10624.d(21): instantiated from here: `opAssign!(Tuple!(Msg))`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10651.d b/gcc/testsuite/gdc.test/fail_compilation/ice10651.d
index 51e0a72..1f87955 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10651.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10651.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10651.d(11): Error: can only throw class objects derived from Throwable, not type `int*`
+fail_compilation/ice10651.d(11): Error: can only throw class objects derived from `Throwable`, not type `int*`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10713.d b/gcc/testsuite/gdc.test/fail_compilation/ice10713.d
index 9ef07b3..f368032 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10713.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10713.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10713.d(10): Error: no property 'nonExistingField' for type 'S'
+fail_compilation/ice10713.d(10): Error: no property `nonExistingField` for type `ice10713.S`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d b/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d
index a7529dc..ebefe33 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -c
+// EXTRA_FILES: imports/foo10727a.d imports/stdtraits10727.d
/*
TEST_OUTPUT:
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d b/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d
index 958b506..125ac12 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d
@@ -1,4 +1,5 @@
// REQUIRED_ARGS: -c
+// EXTRA_FILES: imports/foo10727b.d imports/stdtraits10727.d
/*
TEST_OUTPUT:
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10922.d b/gcc/testsuite/gdc.test/fail_compilation/ice10922.d
index 9eeb622..c227ee5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10922.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10922.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10922.d(10): Error: function `ice10922.__lambda4(const(uint) n)` is not callable using argument types `()`
-fail_compilation/ice10922.d(10): missing argument for parameter #1: `const(uint) n`
+fail_compilation/ice10922.d(10): Error: function `ice10922.__lambda4(in uint n)` is not callable using argument types `()`
+fail_compilation/ice10922.d(10): missing argument for parameter #1: `in uint n`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10938.d b/gcc/testsuite/gdc.test/fail_compilation/ice10938.d
index 2b3eab5..2084e32 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10938.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10938.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10938.d(12): Error: no property 'opts' for type 'ice10938.C'
+fail_compilation/ice10938.d(13): Error: no property `opts` for type `ice10938.C`
+fail_compilation/ice10938.d(13): potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10949.d b/gcc/testsuite/gdc.test/fail_compilation/ice10949.d
index e81cf97..45b18e0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10949.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10949.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice10949.d(12): Deprecation: Using the result of a comma expression is deprecated
+fail_compilation/ice10949.d(12): Error: Using the result of a comma expression is not allowed
fail_compilation/ice10949.d(12): Error: array index 3 is out of bounds `[5, 5][0 .. 2]`
fail_compilation/ice10949.d(12): Error: array index 17 is out of bounds `[2, 3][0 .. 2]`
fail_compilation/ice10949.d(12): while evaluating: `static assert((((([5, 5][3] + global - global) * global / global % global >> global & global | global) ^ global) == 9 , [2, 3][17]) || [3, 3, 3][9] is 4 && [[1, 2, 3]][4].length)`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11086.d b/gcc/testsuite/gdc.test/fail_compilation/ice11086.d
index 0b2ee30..fee958d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11086.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11086.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice11086.d(10): Error: template instance foo!A template 'foo' is not defined
+fail_compilation/ice11086.d(10): Error: template instance `foo!A` template `foo` is not defined
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11404.d b/gcc/testsuite/gdc.test/fail_compilation/ice11404.d
index c3f1ce6..f445903 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11404.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11404.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice11404.d(10): Error: can't have associative array of (int, int)
+fail_compilation/ice11404.d(10): Error: cannot have associative array of `(int, int)`
---
*/
template TypeTuple(TL...) { alias TL TypeTuple; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice1144.d b/gcc/testsuite/gdc.test/fail_compilation/ice1144.d
index 68563b6..cd64864 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice1144.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice1144.d
@@ -2,12 +2,12 @@
TEST_OUTPUT:
---
fail_compilation/ice1144.d(14): Error: undefined identifier `a`
-fail_compilation/ice1144.d(23): Error: template instance ice1144.testHelper!("hello", "world") error instantiating
+fail_compilation/ice1144.d(23): Error: template instance `ice1144.testHelper!("hello", "world")` error instantiating
---
*/
-// Issue 1144 - ICE(template.c) template mixin causes DMD crash
-
+// https://issues.dlang.org/show_bug.cgi?id=1144
+// ICE(template.c) template mixin causes DMD crash
char[] testHelper(A ...)()
{
char[] result;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11472.d b/gcc/testsuite/gdc.test/fail_compilation/ice11472.d
index f5b767f..4e12490 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11472.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11472.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice11472.d(13): Error: template instance fun2!fun fun2 is not a template declaration, it is a function
-fail_compilation/ice11472.d(18): Error: template instance ice11472.fun1!(fun3) error instantiating
+fail_compilation/ice11472.d(13): Error: template instance `fun2!fun` `fun2` is not a template declaration, it is a function
+fail_compilation/ice11472.d(18): Error: template instance `ice11472.fun1!(fun3)` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11513a.d b/gcc/testsuite/gdc.test/fail_compilation/ice11513a.d
index 576c845..87ce0e1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11513a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11513a.d
@@ -1,4 +1,5 @@
/*
+EXTRA_FILES: imports/ice11513x.d
TEST_OUTPUT:
---
fail_compilation/imports/ice11513x.d(1): Error: package name 'ice11513a' conflicts with usage as a module name in file fail_compilation/ice11513a.d
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11513b.d b/gcc/testsuite/gdc.test/fail_compilation/ice11513b.d
index dab09b8..4f933f4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11513b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11513b.d
@@ -1,4 +1,5 @@
/*
+EXTRA_FILES: imports/ice11513y.d
TEST_OUTPUT:
---
fail_compilation/imports/ice11513y.d(1): Error: package name 'ice11513b' conflicts with usage as a module name in file fail_compilation/ice11513b.d
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11518.d b/gcc/testsuite/gdc.test/fail_compilation/ice11518.d
index cfceb64e..c8542f7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11518.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11518.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice11518.d(17): Error: class ice11518.B matches more than one template declaration:
-fail_compilation/ice11518.d(12): B(T : A!T)
+fail_compilation/ice11518.d(17): Error: class `ice11518.B` matches more than one template declaration:
+fail_compilation/ice11518.d(12): `B(T : A!T)`
and
-fail_compilation/ice11518.d(13): B(T : A!T)
+fail_compilation/ice11518.d(13): `B(T : A!T)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11552.d b/gcc/testsuite/gdc.test/fail_compilation/ice11552.d
index 43fba40..28d8be1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11552.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11552.d
@@ -1,11 +1,10 @@
/*
REQUIRED_ARGS: -o-
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/ice11552.d(14): Error: label `label` is undefined
-fail_compilation/ice11552.d(17): called from here: test11552()
-fail_compilation/ice11552.d(17): while evaluating: `static assert(test11552())`
+fail_compilation/ice11552.d(13): Error: function `ice11552.test11552` label `label` is undefined
+fail_compilation/ice11552.d(16): called from here: `test11552()`
+fail_compilation/ice11552.d(16): while evaluating: `static assert(test11552())`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11553.d b/gcc/testsuite/gdc.test/fail_compilation/ice11553.d
index 8fd0975..7497aad 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11553.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11553.d
@@ -1,11 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice11553.d(22): Error: recursive template expansion while looking for A!().A()
+fail_compilation/ice11553.d(22): Error: recursive template expansion while looking for `A!().A()`
+fail_compilation/ice11553.d(22): Error: expression `A()` of type `void` does not have a boolean value
---
*/
-
template A(alias T)
{
template A()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11755.d b/gcc/testsuite/gdc.test/fail_compilation/ice11755.d
deleted file mode 100644
index 86ce6f6..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11755.d
+++ /dev/null
@@ -1,30 +0,0 @@
-// REQUIRED_ARGS: -w
-/*
-TEST_OUTPUT:
----
-fail_compilation/ice11755.d(20): Error: '!<>=' is not defined for array comparisons
-fail_compilation/ice11755.d(21): Error: use '==' for non-floating comparisons rather than floating point operator '!<>'
-fail_compilation/ice11755.d(22): Error: use '!=' for non-floating comparisons rather than floating point operator '<>'
-fail_compilation/ice11755.d(23): Error: '<>=' is not defined for array comparisons
-fail_compilation/ice11755.d(24): Error: use '<=' for non-floating comparisons rather than floating point operator '!>'
-fail_compilation/ice11755.d(25): Error: use '<' for non-floating comparisons rather than floating point operator '!>='
-fail_compilation/ice11755.d(26): Error: use '>=' for non-floating comparisons rather than floating point operator '!<'
-fail_compilation/ice11755.d(27): Error: use '>' for non-floating comparisons rather than floating point operator '!<='
-fail_compilation/ice11755.d(28): Error: floating point operator '<>=' always returns true for non-floating comparisons
-fail_compilation/ice11755.d(29): Error: floating point operator '!<>=' always returns false for non-floating comparisons
----
-*/
-void main()
-{
- int[] a, b;
- auto r4 = a !<>= b; // TOKunord
- auto r2 = a !<> b; // TOKue
- auto r1 = a <> b; // TOKlg
- auto r3 = a <>= b; // TOKleg
- auto r8 = a !> b; // TOKule
- auto r7 = a !>= b; // TOKul
- auto r6 = a !< b; // TOKuge
- auto r5 = a !<= b; // TOKug
- assert((5 <>= 3) == 1);
- assert((5 !<>= 3) == 0);
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11790.d b/gcc/testsuite/gdc.test/fail_compilation/ice11790.d
deleted file mode 100644
index 34b2002..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11790.d
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/ice11790.d(8): Error: cannot pass type string as a function argument
----
-*/
-
-string[string] crash = new string[string];
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11793.d b/gcc/testsuite/gdc.test/fail_compilation/ice11793.d
index e9453a3..2d997ca 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11793.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11793.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice11793.d(11): Error: circular reference to 'ice11793.Outer.outer'
+fail_compilation/ice11793.d(11): Error: circular reference to `ice11793.Outer.outer`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11822.d b/gcc/testsuite/gdc.test/fail_compilation/ice11822.d
index 4ec46c3..830af21 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11822.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11822.d
@@ -4,9 +4,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice11822.d(32): Deprecation: function ice11822.d is deprecated
-fail_compilation/ice11822.d(21): instantiated from here: S!(__lambda1)
-fail_compilation/ice11822.d(32): instantiated from here: g!((n) => d(i))
+fail_compilation/ice11822.d(33): Deprecation: function `ice11822.d` is deprecated
+fail_compilation/ice11822.d(16): instantiated from here: `__lambda2!int`
+fail_compilation/ice11822.d(22): instantiated from here: `S!(__lambda2)`
+fail_compilation/ice11822.d(33): instantiated from here: `g!((n) => d(i))`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11849b.d b/gcc/testsuite/gdc.test/fail_compilation/ice11849b.d
index ef9380f..f879496 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11849b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11849b.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/ice11849b.d(11): Error: circular reference to enum base type `DWORD1`
-fail_compilation/ice11849b.d(11): Error: DWORD1 is used as a type
+fail_compilation/ice11849b.d(11): Error: `DWORD1` is used as a type
fail_compilation/ice11849b.d(16): Error: circular reference to enum base type `typeof(DWORD2)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11850.d b/gcc/testsuite/gdc.test/fail_compilation/ice11850.d
index 9d1f172..d33549a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11850.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11850.d
@@ -1,9 +1,10 @@
/*
+EXTRA_FILES: imports/a11850.d
TEST_OUTPUT:
---
-fail_compilation/ice11850.d(14): Error: incompatible types for ((a) < ([0])): 'uint[]' and 'int[]'
-fail_compilation/imports/a11850.d(9): instantiated from here: FilterResult!(__lambda1, uint[][])
-fail_compilation/ice11850.d(14): instantiated from here: filter!(uint[][])
+fail_compilation/ice11850.d(15): Error: incompatible types for `(a) < ([0])`: `uint[]` and `int[]`
+fail_compilation/imports/a11850.d(9): instantiated from here: `FilterResult!(__lambda1, uint[][])`
+fail_compilation/ice11850.d(15): instantiated from here: `filter!(uint[][])`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11856_0.d b/gcc/testsuite/gdc.test/fail_compilation/ice11856_0.d
new file mode 100644
index 0000000..36bc2bd
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11856_0.d
@@ -0,0 +1,19 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice11856_0.d(19): Error: template `ice11856_0.f` cannot deduce function from argument types `!()(int)`
+fail_compilation/ice11856_0.d(13): Candidates are: `f(T)(T t)`
+fail_compilation/ice11856_0.d(16): `f(T)(T t)`
+ with `T = int`
+ must satisfy the following constraint:
+` !__traits(compiles, .f!T)`
+---
+*/
+
+int f(T)(T t) if(!__traits(compiles,.f!T)) {
+ return 0;
+}
+int f(T)(T t) if(!__traits(compiles,.f!T)) {
+ return 1;
+}
+enum x=f(2);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d b/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d
new file mode 100644
index 0000000..70991ae
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11856_1.d
@@ -0,0 +1,13 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice11856_1.d(13): Error: template `ice11856_1.g` cannot deduce function from argument types `!()(A)`
+fail_compilation/ice11856_1.d(11): Candidate is: `g(T)(T x)`
+---
+*/
+struct A {}
+
+void f(T)(T x) if (is(typeof(x.g()))) {}
+void g(T)(T x) if (is(typeof(x.f()))) {}
+
+void main() { A().g(); }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11919.d b/gcc/testsuite/gdc.test/fail_compilation/ice11919.d
index 7005610..e6b4f70 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11919.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11919.d
@@ -1,10 +1,11 @@
/*
+EXTRA_FILES: imports/a11919.d
TEST_OUTPUT:
---
-fail_compilation/ice11919.d(17): Error: cannot interpret foo at compile time
-fail_compilation/imports/a11919.d(4): Error: template instance a11919.doBar!(Foo).doBar.zoo!(t) error instantiating
-fail_compilation/imports/a11919.d(11): instantiated from here: doBar!(Foo)
-fail_compilation/ice11919.d(25): instantiated from here: doBar!(Bar)
+fail_compilation/ice11919.d(18): Error: initializer must be an expression, not `foo`
+fail_compilation/imports/a11919.d(4): Error: template instance `a11919.doBar!(Foo).doBar.zoo!(t)` error instantiating
+fail_compilation/imports/a11919.d(11): instantiated from here: `doBar!(Foo)`
+fail_compilation/ice11919.d(26): instantiated from here: `doBar!(Bar)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11922.d b/gcc/testsuite/gdc.test/fail_compilation/ice11922.d
index 0999aeac..bca0bbe 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11922.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11922.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/ice11922.d(11): Error: undefined identifier `a`
-fail_compilation/ice11922.d(17): Error: template instance ice11922.S.f!int error instantiating
+fail_compilation/ice11922.d(17): Error: template instance `ice11922.S.f!int` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/compilable/ice11925.d b/gcc/testsuite/gdc.test/fail_compilation/ice11925.d
index 630af42..2627f2b 100644
--- a/gcc/testsuite/gdc.test/compilable/ice11925.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11925.d
@@ -1,3 +1,10 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/ice11925.d(23): Error: cannot `goto` into `try` block
+fail_compilation/ice11925.d(31): Error: cannot `goto` into `try` block
+---
+*/
+
void test11925a()
{
try
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11944.d b/gcc/testsuite/gdc.test/fail_compilation/ice11944.d
index c72d9f0..9b0326b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11944.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11944.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice11944.d(12): Error: template instance doCommand!(func) does not match template declaration doCommand(f, T)(f, T arg)
+fail_compilation/ice11944.d(12): Error: template instance `doCommand!(func)` does not match template declaration `doCommand(f, T)(f, T arg)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12040.d b/gcc/testsuite/gdc.test/fail_compilation/ice12040.d
index 2307e94..e43079a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12040.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12040.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12040.d(8): Error: circular reference to 'ice12040.lol'
+fail_compilation/ice12040.d(8): Error: circular reference to `ice12040.lol`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12158.d b/gcc/testsuite/gdc.test/fail_compilation/ice12158.d
index 7b8d38d..50a0b60 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12158.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12158.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12158.d(7): Error: module object import 'nonexisting' not found
+fail_compilation/ice12158.d(7): Error: module `object` import `nonexisting` not found
---
*/
import object : nonexisting;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12174.d b/gcc/testsuite/gdc.test/fail_compilation/ice12174.d
index 81fef2d..019722a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12174.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12174.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12174.d(12): Error: no property 'sum' for type 'int[]'
-fail_compilation/ice12174.d(20): Error: CTFE failed because of previous errors in this
-fail_compilation/ice12174.d(13): called from here: filter([1, 2, 3])
+fail_compilation/ice12174.d(12): Error: no property `sum` for type `int[]`
+fail_compilation/ice12174.d(20): Error: CTFE failed because of previous errors in `this`
+fail_compilation/ice12174.d(13): called from here: `filter([1, 2, 3])`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12235.d b/gcc/testsuite/gdc.test/fail_compilation/ice12235.d
index 1bf55b9..8f2fefd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12235.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12235.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12235.d(14): Error: forward reference to inferred return type of function '__lambda1'
-fail_compilation/ice12235.d(15): Error: forward reference to inferred return type of function '__lambda1'
-fail_compilation/ice12235.d(15): while evaluating pragma(msg, __lambda1.mangleof)
+fail_compilation/ice12235.d(14): Error: forward reference to inferred return type of function `__lambda1`
+fail_compilation/ice12235.d(15): Error: forward reference to inferred return type of function `__lambda1`
+fail_compilation/ice12235.d(15): while evaluating `pragma(msg, __lambda1.mangleof)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12350.d b/gcc/testsuite/gdc.test/fail_compilation/ice12350.d
index 3ac3751..73ed39d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12350.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12350.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12350.d(15): Error: type MyUDC has no value
-fail_compilation/ice12350.d(30): Error: template instance ice12350.testAttrs!(MyStruct) error instantiating
+fail_compilation/ice12350.d(15): Error: type `MyUDC` has no value
+fail_compilation/ice12350.d(30): Error: template instance `ice12350.testAttrs!(MyStruct)` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12362.d b/gcc/testsuite/gdc.test/fail_compilation/ice12362.d
index 2c662c0..d0853b9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12362.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12362.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12362.d(12): Error: cannot interpret foo at compile time
+fail_compilation/ice12362.d(12): Error: initializer must be an expression, not `foo`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12534.d b/gcc/testsuite/gdc.test/fail_compilation/ice12534.d
index 6820f39..da9c021 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12534.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12534.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12534.d(14): Error: static assert `is(exprs[0 .. 0])` is false
+fail_compilation/ice12534.d(14): Error: static assert: `is(exprs[0 .. 0])` is false
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12539.d b/gcc/testsuite/gdc.test/fail_compilation/ice12539.d
index e1ad994..8fab042 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12539.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12539.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12539.d(15): Error: array index [0] is outside array bounds [0 .. 0]
+fail_compilation/ice12539.d(15): Error: array index `[0]` is outside array bounds `[0 .. 0]`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12574.d b/gcc/testsuite/gdc.test/fail_compilation/ice12574.d
index 362c359..420b6b7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12574.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12574.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12574.d(40): Error: tuple index 2 exceeds length 2
-fail_compilation/ice12574.d(53): Error: template instance ice12574.reduce!("a", "a").reduce!(Tuple!(int, int, int)) error instantiating
+fail_compilation/ice12574.d(40): Error: tuple index `2` exceeds length 2
+fail_compilation/ice12574.d(53): Error: template instance `ice12574.reduce!("a", "a").reduce!(Tuple!(int, int, int))` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12727.d b/gcc/testsuite/gdc.test/fail_compilation/ice12727.d
index 027894c..bf6af7b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12727.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12727.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
----
-fail_compilation/ice12727.d(16): Error: alias ice12727.IndexTuple!(1, 0).IndexTuple recursive alias declaration
-fail_compilation/ice12727.d(23): Error: template instance ice12727.IndexTuple!(1, 0) error instantiating
-fail_compilation/ice12727.d(27): instantiated from here: Matrix!(float, 3)
-fail_compilation/ice12727.d(28): instantiated from here: Vector!(float, 3)
+fail_compilation/ice12727.d(16): Error: alias `ice12727.IndexTuple!(1, 0).IndexTuple` recursive alias declaration
+fail_compilation/ice12727.d(23): Error: template instance `ice12727.IndexTuple!(1, 0)` error instantiating
+fail_compilation/ice12727.d(27): instantiated from here: `Matrix!(float, 3)`
+fail_compilation/ice12727.d(28): instantiated from here: `Vector!(float, 3)`
----
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12827.d b/gcc/testsuite/gdc.test/fail_compilation/ice12827.d
index 8270c1f..20974e4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12827.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12827.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12827.d(10): Error: circular initialization of variable 'ice12827.Test.i'
+fail_compilation/ice12827.d(10): Error: circular initialization of variable `ice12827.Test.i`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12841.d b/gcc/testsuite/gdc.test/fail_compilation/ice12841.d
index 564b661..c5894d2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12841.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12841.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12841.d(23): Error: taskPool().amap(Args...)(Args args) is not an lvalue
-fail_compilation/ice12841.d(24): Error: amap(Args...)(Args args) is not an lvalue
+fail_compilation/ice12841.d(23): Error: `taskPool().amap(Args...)(Args args)` is not an lvalue and cannot be modified
+fail_compilation/ice12841.d(24): Error: `amap(Args...)(Args args)` is not an lvalue and cannot be modified
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12902.d b/gcc/testsuite/gdc.test/fail_compilation/ice12902.d
index e5ada09..ac43012 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12902.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12902.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice12902.d(20): Error: variable ice12902.main.__dollar type void is inferred from initializer s.opDollar(), and variables cannot be of type void
-fail_compilation/ice12902.d(20): Error: expression s.opDollar() is void and has no value
+fail_compilation/ice12902.d(20): Error: variable `ice12902.main.__dollar` type `void` is inferred from initializer `s.opDollar()`, and variables cannot be of type `void`
+fail_compilation/ice12902.d(20): Error: expression `s.opDollar()` is `void` and has no value
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13024.d b/gcc/testsuite/gdc.test/fail_compilation/ice13024.d
deleted file mode 100644
index bf82677..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13024.d
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/ice13024.d(15): Error: cannot implicitly convert expression `t.x` of type `A` to `B`
----
-*/
-
-enum A { a }
-enum B { b }
-struct T { A x; B y; }
-void main()
-{
- T t;
- auto r1 = [cast(int)(t.x), cast(int)(t.y)]; // OK
- auto r3 = [t.x, t.y]; // crash
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13027.d b/gcc/testsuite/gdc.test/fail_compilation/ice13027.d
index 04ccdf3..03c6820 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13027.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13027.d
@@ -1,10 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice13027.d(9): Error: template instance b!"c" template 'b' is not defined
+fail_compilation/ice13027.d(9): Error: template instance `b!"c"` template `b` is not defined
---
*/
void main()
{
scope a = b!"c";
}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13081.d b/gcc/testsuite/gdc.test/fail_compilation/ice13081.d
index 126ce9f..64474ba 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13081.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13081.d
@@ -4,7 +4,7 @@ TEST_OUTPUT:
fail_compilation/ice13081.d(17): Error: undefined identifier `node`
fail_compilation/ice13081.d(17): Error: undefined identifier `data`
fail_compilation/ice13081.d(17): Error: undefined identifier `node`
-fail_compilation/ice13081.d(28): Error: template instance ice13081.Cube!(SparseDataStore) error instantiating
+fail_compilation/ice13081.d(28): Error: template instance `ice13081.Cube!(SparseDataStore)` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13131.d b/gcc/testsuite/gdc.test/fail_compilation/ice13131.d
index 13b5aff..d4a6b91 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13131.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13131.d
@@ -1,10 +1,11 @@
// EXTRA_SOURCES: imports/a13131parameters.d imports/a13131elec.d
+// EXTRA_FILES: imports/a13131checkpoint.d
/*
TEST_OUTPUT:
---
+A
+B
-fail_compilation/imports/a13131elec.d(10): Error: template instance elecConnOf!gconn template 'elecConnOf' is not defined
+fail_compilation/imports/a13131elec.d(10): Error: template instance `elecConnOf!gconn` template `elecConnOf` is not defined
-B
-A
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13220.d b/gcc/testsuite/gdc.test/fail_compilation/ice13220.d
index 3affd54..65b661b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13220.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13220.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice13220.d(22): Error: template instance test!0 does not match template declaration test(T)()
+fail_compilation/ice13220.d(22): Error: template instance `test!0` does not match template declaration `test(T)()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13221.d b/gcc/testsuite/gdc.test/fail_compilation/ice13221.d
index b00169e..3c55054 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13221.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13221.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice13221.d(20): Error: variable r cannot be read at compile time
+fail_compilation/ice13221.d(20): Error: variable `r` cannot be read at compile time
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13225.d b/gcc/testsuite/gdc.test/fail_compilation/ice13225.d
index b042431..6988cd7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13225.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13225.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice13225.d(12): Error: mixin ice13225.S.M!(function (S _param_0) => 0) does not match template declaration M(T)
+fail_compilation/ice13225.d(12): Error: mixin `ice13225.S.M!(function (S _param_0) pure nothrow @nogc @safe => 0)` does not match template declaration `M(T)`
fail_compilation/ice13225.d(16): Error: undefined identifier `undefined`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13311.d b/gcc/testsuite/gdc.test/fail_compilation/ice13311.d
index b86681b..2aa01ad 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13311.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13311.d
@@ -1,4 +1,5 @@
/*
+EXTRA_FILES: imports/a13311.d
TEST_OUTPUT:
---
fail_compilation/imports/a13311.d(8): Error: undefined identifier `PieceTree`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13356.d b/gcc/testsuite/gdc.test/fail_compilation/ice13356.d
index 9225d55..3bac9b5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13356.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13356.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice13356.d(32): Error: template instance Algebraic!(Tuple!(List)) recursive template expansion
-fail_compilation/ice13356.d(15): Error: template instance ice13356.isPrintable!(List) error instantiating
-fail_compilation/ice13356.d(33): instantiated from here: Tuple!(List)
+fail_compilation/ice13356.d(32): Error: template instance `Algebraic!(Tuple!(List))` recursive template expansion
+fail_compilation/ice13356.d(15): Error: template instance `ice13356.isPrintable!(List)` error instantiating
+fail_compilation/ice13356.d(33): instantiated from here: `Tuple!(List)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13382.d b/gcc/testsuite/gdc.test/fail_compilation/ice13382.d
index e5f1ac0..87c70d9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13382.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13382.d
@@ -1,14 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice13382.d(18): Error: incompatible types for ((a) == (0)): 'int[]' and 'int'
-fail_compilation/ice13382.d(19): Error: incompatible types for ((a) >= (0)): 'int[]' and 'int'
-fail_compilation/ice13382.d(20): Error: incompatible types for ((0) == (a)): 'int' and 'int[]'
-fail_compilation/ice13382.d(21): Error: incompatible types for ((0) >= (a)): 'int' and 'int[]'
-fail_compilation/ice13382.d(22): Error: incompatible types for ((a) is (0)): 'int[]' and 'int'
-fail_compilation/ice13382.d(23): Error: incompatible types for ((a) !is (0)): 'int[]' and 'int'
-fail_compilation/ice13382.d(24): Error: incompatible types for ((0) is (a)): 'int' and 'int[]'
-fail_compilation/ice13382.d(25): Error: incompatible types for ((0) !is (a)): 'int' and 'int[]'
+fail_compilation/ice13382.d(18): Error: incompatible types for `(a) == (0)`: `int[]` and `int`
+fail_compilation/ice13382.d(19): Error: incompatible types for `(a) >= (0)`: `int[]` and `int`
+fail_compilation/ice13382.d(20): Error: incompatible types for `(0) == (a)`: `int` and `int[]`
+fail_compilation/ice13382.d(21): Error: incompatible types for `(0) >= (a)`: `int` and `int[]`
+fail_compilation/ice13382.d(22): Error: incompatible types for `(a) is (0)`: `int[]` and `int`
+fail_compilation/ice13382.d(23): Error: incompatible types for `(a) !is (0)`: `int[]` and `int`
+fail_compilation/ice13382.d(24): Error: incompatible types for `(0) is (a)`: `int` and `int[]`
+fail_compilation/ice13382.d(25): Error: incompatible types for `(0) !is (a)`: `int` and `int[]`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13385.d b/gcc/testsuite/gdc.test/fail_compilation/ice13385.d
index b2039b2..cf114d0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13385.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13385.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice13385.d(9): Error: protection attribute 'package(a)' does not bind to one of ancestor packages of module `ice13385`
+fail_compilation/ice13385.d(9): Error: visibility attribute `package(a)` does not bind to one of ancestor packages of module `ice13385`
---
*/
module ice13385;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13459.d b/gcc/testsuite/gdc.test/fail_compilation/ice13459.d
index 35420fd..2c42dd3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13459.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13459.d
@@ -2,13 +2,13 @@
TEST_OUTPUT:
---
fail_compilation/ice13459.d(12): Error: undefined identifier `B`
-fail_compilation/ice13459.d(18): Error: none of the overloads of 'opSlice' are callable using argument types (int, int), candidates are:
-fail_compilation/ice13459.d(11): ice13459.A.opSlice()
+fail_compilation/ice13459.d(18): Error: none of the overloads of `opSlice` are callable using argument types `(int, int)`
+fail_compilation/ice13459.d(11): Candidates are: `ice13459.A.opSlice()`
---
*/
struct A
{
- auto opSlice() {}
+ auto opSlice() const {}
auto opSlice() { return B; }
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13465a.d b/gcc/testsuite/gdc.test/fail_compilation/ice13465a.d
index 23f73b7..16c43a6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13465a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13465a.d
@@ -3,8 +3,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/imports/a13465.d(10): Error: cannot infer type from template instance isMaskField!()
-fail_compilation/ice13465a.d(17): Error: template instance imports.a13465.isMatchingMaskField!() error instantiating
+fail_compilation/imports/a13465.d(10): Error: cannot infer type from template instance `isMaskField!()`
+fail_compilation/ice13465a.d(17): Error: template instance `imports.a13465.isMatchingMaskField!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13465b.d b/gcc/testsuite/gdc.test/fail_compilation/ice13465b.d
index db0cce1..60c8505 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13465b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13465b.d
@@ -3,8 +3,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/imports/b13465.d(10): Error: cannot infer type from template instance isMaskField!()
-fail_compilation/ice13465b.d(17): Error: template instance imports.b13465.isMatchingMaskField!() error instantiating
+fail_compilation/imports/b13465.d(10): Error: cannot infer type from template instance `isMaskField!()`
+fail_compilation/ice13465b.d(17): Error: template instance `imports.b13465.isMatchingMaskField!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice1358.d b/gcc/testsuite/gdc.test/fail_compilation/ice1358.d
index ee71f8c..2c334f9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice1358.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice1358.d
@@ -5,8 +5,8 @@ fail_compilation/ice1358.d(29): Error: invalid UTF character \U80000000
---
*/
-// Issue 1358 - ICE(root.c) on Unicode codepoints greater than 0x7FFFFFFF
-
+// https://issues.dlang.org/show_bug.cgi?id=1358
+// ICE(root.c) on Unicode codepoints greater than 0x7FFFFFFF
/* 1358. Assertion failure: '0' on line 1548 in file '..\root\root.c'
This one is trivial.
PATCH(lexer.c, Lexer::escapeSequence()).
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13788.d b/gcc/testsuite/gdc.test/fail_compilation/ice13788.d
index 7d04d9d..99f3c4a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13788.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13788.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice13788.d(11): Error: pragma mangle string expected for mangled name
-fail_compilation/ice13788.d(12): Error: string expected for mangled name, not (1) of type int
-fail_compilation/ice13788.d(13): Error: pragma mangle zero-length string not allowed for mangled name
-fail_compilation/ice13788.d(14): Error: pragma mangle mangled name characters can only be of type char
+fail_compilation/ice13788.d(11): Error: pragma `mangle` string expected for mangled name
+fail_compilation/ice13788.d(12): Error: `string` expected for mangled name, not `(1)` of type `int`
+fail_compilation/ice13788.d(13): Error: pragma `mangle` zero-length string not allowed for mangled name
+fail_compilation/ice13788.d(14): Error: pragma `mangle` mangled name characters can only be of type `char`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13816.d b/gcc/testsuite/gdc.test/fail_compilation/ice13816.d
index 6745d7b..e683e33 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13816.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13816.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice13816.d(15): Error: alias ice13816.ItemProperty!().ItemProperty recursive alias declaration
-fail_compilation/ice13816.d(20): Error: template instance ice13816.ItemProperty!() error instantiating
+fail_compilation/ice13816.d(15): Error: alias `ice13816.ItemProperty!().ItemProperty` recursive alias declaration
+fail_compilation/ice13816.d(20): Error: template instance `ice13816.ItemProperty!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13835.d b/gcc/testsuite/gdc.test/fail_compilation/ice13835.d
index 6bacdb0..dcb1757 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13835.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13835.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice13835.d(15): Error: value of 'this' is not known at compile time
-fail_compilation/ice13835.d(21): Error: template instance ice13835.Foo!int error instantiating
+fail_compilation/ice13835.d(15): Error: value of `this` is not known at compile time
+fail_compilation/ice13835.d(21): Error: template instance `ice13835.Foo!int` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13921.d b/gcc/testsuite/gdc.test/fail_compilation/ice13921.d
index 8793e5c..96c11ed 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13921.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13921.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/ice13921.d(13): Error: undefined identifier `undefined_identifier`
-fail_compilation/ice13921.d(25): Error: template instance ice13921.S!string error instantiating
+fail_compilation/ice13921.d(25): Error: template instance `ice13921.S!string` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13987.d b/gcc/testsuite/gdc.test/fail_compilation/ice13987.d
index 26d3d30..28a57c0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13987.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13987.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice13987.d(9): Error: cannot use array to initialize S
+fail_compilation/ice13987.d(9): Error: cannot use array to initialize `S`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14055.d b/gcc/testsuite/gdc.test/fail_compilation/ice14055.d
index 5e60e88..13cdf34 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14055.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14055.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice14055.d(16): Error: uninitialized variable 'foo' cannot be returned from CTFE
+fail_compilation/ice14055.d(16): Error: uninitialized variable `foo` cannot be returned from CTFE
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14096.d b/gcc/testsuite/gdc.test/fail_compilation/ice14096.d
index 654cfcc..05171ad 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14096.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14096.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice14096.d(29): Error: cannot access frame pointer of ice14096.main.Baz!((i) => i).Baz
-fail_compilation/ice14096.d(23): Error: template instance ice14096.foo!(Tuple!(Baz!((i) => i))).foo.bar!(t) error instantiating
-fail_compilation/ice14096.d(40): instantiated from here: foo!(Tuple!(Baz!((i) => i)))
+fail_compilation/ice14096.d(29): Error: cannot access frame pointer of `ice14096.main.Baz!((i) => i).Baz`
+fail_compilation/ice14096.d(23): Error: template instance `ice14096.foo!(Tuple!(Baz!((i) => i))).foo.bar!(t)` error instantiating
+fail_compilation/ice14096.d(40): instantiated from here: `foo!(Tuple!(Baz!((i) => i)))`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14116.d b/gcc/testsuite/gdc.test/fail_compilation/ice14116.d
index 52cd8ce..c3339c7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14116.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14116.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/imports/a14116.d(3): Error: module ice14116.ice14116 from file fail_compilation/ice14116.d must be imported with 'import ice14116.ice14116;'
+fail_compilation/imports/a14116.d(3): Error: module `ice14116.ice14116` from file fail_compilation/ice14116.d must be imported with 'import ice14116.ice14116;'
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14130.d b/gcc/testsuite/gdc.test/fail_compilation/ice14130.d
index 916a7b9..53e35a6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14130.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14130.d
@@ -2,8 +2,8 @@
TEST_OUTPUT:
---
fail_compilation/ice14130.d(10): Error: undefined identifier `Undef`
-fail_compilation/ice14130.d(14): Error: template ice14130.foo cannot deduce function from argument types !()(int), candidates are:
-fail_compilation/ice14130.d(10): ice14130.foo(R, F = Undef)(R r, F s = 0)
+fail_compilation/ice14130.d(14): Error: template `ice14130.foo` cannot deduce function from argument types `!()(int)`
+fail_compilation/ice14130.d(10): Candidate is: `foo(R, F = Undef)(R r, F s = 0)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14146.d b/gcc/testsuite/gdc.test/fail_compilation/ice14146.d
index 1e4f9a9..f058d1c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14146.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14146.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice14146.d(15): Error: constructor ice14146.Array.this default constructor for structs only allowed with @disable, no body, and no parameters
+fail_compilation/ice14146.d(15): Error: constructor `ice14146.Array.this` default constructor for structs only allowed with `@disable`, no body, and no parameters
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14177.d b/gcc/testsuite/gdc.test/fail_compilation/ice14177.d
index b487c2b..c7968158 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14177.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14177.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
----
-fail_compilation/ice14177.d(8): Error: alias ice14177.Primitive recursive alias declaration
+fail_compilation/ice14177.d(8): Error: alias `ice14177.Primitive` recursive alias declaration
----
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14272.d b/gcc/testsuite/gdc.test/fail_compilation/ice14272.d
index d9f642d..ee102fc 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14272.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14272.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice14272.d(11): Error: circular initialization of variable 'ice14272.A14272!1.A14272.tag'
-fail_compilation/ice14272.d(14): Error: template instance ice14272.A14272!1 error instantiating
+fail_compilation/ice14272.d(11): Error: circular initialization of variable `ice14272.A14272!1.A14272.tag`
+fail_compilation/ice14272.d(14): Error: template instance `ice14272.A14272!1` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14424.d b/gcc/testsuite/gdc.test/fail_compilation/ice14424.d
index 29fe666..c99522d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14424.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14424.d
@@ -1,8 +1,9 @@
// REQUIRED_ARGS: -o- -unittest
+// EXTRA_FILES: imports/a14424.d
/*
TEST_OUTPUT:
---
-fail_compilation/ice14424.d(12): Error: `tuple` has no effect in expression `tuple(__unittestL3_$n$)`
+fail_compilation/ice14424.d(13): Error: `tuple(__unittest_L3_C1)` has no effect
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14446.d b/gcc/testsuite/gdc.test/fail_compilation/ice14446.d
deleted file mode 100644
index ee0bfc4..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14446.d
+++ /dev/null
@@ -1,14 +0,0 @@
-// REQUIRED_ARGS: -o-
-// PERMUTE_ARGS:
-// EXTRA_SOURCES: extra-files/a14446.d
-
-/*
-TEST_OUTPUT:
----
-fail_compilation/extra-files/a14446.d(5): Error: module x14446 from file fail_compilation/ice14446.d must be imported with 'import x14446;'
----
-*/
-
-module x14446;
-
-struct CDB {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14621.d b/gcc/testsuite/gdc.test/fail_compilation/ice14621.d
index 15690b7..b3d26b8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14621.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14621.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice14621.d(22): Error: static assert `false` is false
-fail_compilation/ice14621.d(28): instantiated from here: erroneousTemplateInstantiation!()
+fail_compilation/ice14621.d(22): Error: static assert: `false` is false
+fail_compilation/ice14621.d(28): instantiated from here: `erroneousTemplateInstantiation!()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14642.d b/gcc/testsuite/gdc.test/fail_compilation/ice14642.d
index 07d4963..90b9867 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14642.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14642.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/ice14642.d(47): Error: undefined identifier `errorValue`
-fail_compilation/ice14642.d(23): Error: template instance ice14642.X.NA!() error instantiating
+fail_compilation/ice14642.d(23): Error: template instance `ice14642.X.NA!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14844.d b/gcc/testsuite/gdc.test/fail_compilation/ice14844.d
index d49a1d1..9f602a5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14844.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14844.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice14844.d(20): Error: template `opDispatch(string name)` has no members
+fail_compilation/ice14844.d(21): Error: In expression `__traits(allMembers, opDispatch)` template `opDispatch(string name)` has no members
+fail_compilation/ice14844.d(21): `opDispatch(string name)` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14907.d b/gcc/testsuite/gdc.test/fail_compilation/ice14907.d
index 6d9edf0..ac4ba68 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14907.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14907.d
@@ -1,13 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice14907.d(14): Error: struct ice14907.S(int v = S) recursive template expansion
+fail_compilation/ice14907.d(14): Error: struct `ice14907.S(int v = S)` recursive template expansion
fail_compilation/ice14907.d(19): while looking for match for `S!()`
-fail_compilation/ice14907.d(15): Error: template ice14907.f(int v = f)() recursive template expansion
+fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion
fail_compilation/ice14907.d(20): while looking for match for `f!()`
-fail_compilation/ice14907.d(15): Error: template ice14907.f(int v = f)() recursive template expansion
-fail_compilation/ice14907.d(21): Error: template `ice14907.f` cannot deduce function from argument types `!()()`, candidates are:
-fail_compilation/ice14907.d(15): `ice14907.f(int v = f)()`
+fail_compilation/ice14907.d(15): Error: template `ice14907.f(int v = f)()` recursive template expansion
+fail_compilation/ice14907.d(21): Error: template `ice14907.f` cannot deduce function from argument types `!()()`
+fail_compilation/ice14907.d(15): Candidate is: `f(int v = f)()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15092.d b/gcc/testsuite/gdc.test/fail_compilation/ice15092.d
index 0064ae3..6824cc1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice15092.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice15092.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice15092.d(13): Error: struct ice15092.A.S conflicts with struct ice15092.A.S at fail_compilation/ice15092.d(12)
-fail_compilation/ice15092.d(16): Error: class ice15092.A.C conflicts with class ice15092.A.C at fail_compilation/ice15092.d(15)
-fail_compilation/ice15092.d(19): Error: interface ice15092.A.I conflicts with interface ice15092.A.I at fail_compilation/ice15092.d(18)
+fail_compilation/ice15092.d(13): Error: struct `ice15092.A.S` conflicts with struct `ice15092.A.S` at fail_compilation/ice15092.d(12)
+fail_compilation/ice15092.d(16): Error: class `ice15092.A.C` conflicts with class `ice15092.A.C` at fail_compilation/ice15092.d(15)
+fail_compilation/ice15092.d(19): Error: interface `ice15092.A.I` conflicts with interface `ice15092.A.I` at fail_compilation/ice15092.d(18)
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15172.d b/gcc/testsuite/gdc.test/fail_compilation/ice15172.d
index dc8ae94..aa070f6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice15172.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice15172.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice15172.d(14): Error: constructor ice15172.ThreadError.this no match for implicit super() call in constructor
+fail_compilation/ice15172.d(14): Error: constructor `ice15172.ThreadError.this` no match for implicit `super()` call in constructor
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15332.d b/gcc/testsuite/gdc.test/fail_compilation/ice15332.d
index 4141178..dbedc73 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice15332.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice15332.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice15332.d(16): Error: need 'this' for 'fun' of type 'int()'
-fail_compilation/ice15332.d(17): Error: need 'this' for 'var' of type 'int'
+fail_compilation/ice15332.d(16): Error: need `this` for `fun` of type `int()`
+fail_compilation/ice15332.d(17): Error: need `this` for `var` of type `int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15441.d b/gcc/testsuite/gdc.test/fail_compilation/ice15441.d
index ef4369b..97fd170 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice15441.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice15441.d
@@ -1,10 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice15441.d(24): Error: variable ice15441.main.__front$n$ type void is inferred from initializer __r$n$.front(), and variables cannot be of type void
-fail_compilation/ice15441.d(24): Error: expression __r$n$.front() is void and has no value
-fail_compilation/ice15441.d(24): Error: `s1.front` is void and has no value
-fail_compilation/ice15441.d(27): Error: cannot infer argument types, expected 1 argument, not 2
+fail_compilation/ice15441.d(22): Error: `s1.front` is `void` and has no value
+fail_compilation/ice15441.d(25): Error: cannot infer argument types, expected 1 argument, not 2
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15688.d b/gcc/testsuite/gdc.test/fail_compilation/ice15688.d
index 92810e6..e086e31 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice15688.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice15688.d
@@ -3,7 +3,7 @@
TEST_OUTPUT:
---
fail_compilation/ice15688.d(12): Error: undefined identifier `mappings`
-fail_compilation/ice15688.d(12): Error: function expected before (), not 0 of type int
+fail_compilation/ice15688.d(12): Error: function expected before `()`, not `0` of type `int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15788.d b/gcc/testsuite/gdc.test/fail_compilation/ice15788.d
index e81f25b..941b179 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice15788.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice15788.d
@@ -1,7 +1,8 @@
/*
+EXTRA_FILES: imports/range15788.d
TEST_OUTPUT:
---
-fail_compilation/ice15788.d(17): Error: none of the overloads of 'iota' are callable using argument types !()(S, S)
+fail_compilation/ice15788.d(18): Error: none of the overloads of `iota` are callable using argument types `!()(S, S)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15816.d b/gcc/testsuite/gdc.test/fail_compilation/ice15816.d
index b9e1e47..9576b56 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice15816.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice15816.d
@@ -1,4 +1,5 @@
/*
+EXTRA_FILES: imports/a15816.d
TEST_OUTPUT:
---
fail_compilation/imports/a15816.d(3): Error: anonymous classes not allowed
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15922.d b/gcc/testsuite/gdc.test/fail_compilation/ice15922.d
index c9739a1..d98404c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice15922.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice15922.d
@@ -1,11 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice15922.d(23): Error: function ice15922.ValidSparseDataStore!int.ValidSparseDataStore.correctedInsert!false.correctedInsert has no return statement, but is expected to return a value of type int
-fail_compilation/ice15922.d(21): Error: template instance ice15922.ValidSparseDataStore!int.ValidSparseDataStore.correctedInsert!false error instantiating
-fail_compilation/ice15922.d(26): instantiated from here: ValidSparseDataStore!int
-fail_compilation/ice15922.d(14): Error: need 'this' for 'insert' of type 'pure @nogc @safe int()'
-fail_compilation/ice15922.d(26): Error: template instance ice15922.StorageAttributes!(ValidSparseDataStore!int) error instantiating
+fail_compilation/ice15922.d(23): Error: function `ice15922.ValidSparseDataStore!int.ValidSparseDataStore.correctedInsert!false.correctedInsert` has no `return` statement, but is expected to return a value of type `int`
+fail_compilation/ice15922.d(21): Error: template instance `ice15922.ValidSparseDataStore!int.ValidSparseDataStore.correctedInsert!false` error instantiating
+fail_compilation/ice15922.d(26): instantiated from here: `ValidSparseDataStore!int`
+fail_compilation/ice15922.d(14): Error: need `this` for `insert` of type `pure nothrow @nogc @safe int()`
+fail_compilation/ice15922.d(26): Error: template instance `ice15922.StorageAttributes!(ValidSparseDataStore!int)` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice16035.d b/gcc/testsuite/gdc.test/fail_compilation/ice16035.d
index 9ad1a4e..8361c42 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice16035.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice16035.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice16035.d(18): Error: forward reference to inferred return type of function call 'this.a[0].toString()'
-fail_compilation/ice16035.d(13): Error: template instance ice16035.Value.get!string error instantiating
+fail_compilation/ice16035.d(18): Error: forward reference to inferred return type of function call `this.a[0].toString()`
+fail_compilation/ice16035.d(13): Error: template instance `ice16035.Value.get!string` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice16657.d b/gcc/testsuite/gdc.test/fail_compilation/ice16657.d
new file mode 100644
index 0000000..19231c2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice16657.d
@@ -0,0 +1,16 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice16657.d(9): Error: function `ice16657.RefCounted.refCountedPayload` has no `return` statement, but is expected to return a value of type `inout(RefCounted)`
+---
+*/
+struct RefCounted
+{
+ inout(RefCounted) refCountedPayload() inout { }
+ alias refCountedPayload this;
+}
+
+struct Store
+{
+ RefCounted p;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice17074.d b/gcc/testsuite/gdc.test/fail_compilation/ice17074.d
index b41b25a..53e75e4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice17074.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice17074.d
@@ -2,38 +2,18 @@
TEST_OUTPUT:
---
fail_compilation/ice17074.d(9): Error: identifier expected for C++ namespace
-fail_compilation/ice17074.d(9): Error: found `cast` when expecting `)`
+fail_compilation/ice17074.d(9): Error: found `__overloadset` when expecting `)`
fail_compilation/ice17074.d(9): Error: declaration expected, not `)`
---
*/
-extern(C++, cast) void ice_keyword();
+extern(C++, std.__overloadset) void ice_std_keyword();
/*
TEST_OUTPUT:
---
fail_compilation/ice17074.d(19): Error: identifier expected for C++ namespace
-fail_compilation/ice17074.d(19): Error: found `__overloadset` when expecting `)`
+fail_compilation/ice17074.d(19): Error: found `*` when expecting `)`
fail_compilation/ice17074.d(19): Error: declaration expected, not `)`
---
*/
-extern(C++, std.__overloadset) void ice_std_keyword();
-
-/*
-TEST_OUTPUT:
----
-fail_compilation/ice17074.d(29): Error: identifier expected for C++ namespace
-fail_compilation/ice17074.d(29): Error: found `...` when expecting `)`
-fail_compilation/ice17074.d(29): Error: declaration expected, not `)`
----
-*/
-extern(C++, ...) void ice_token();
-
-/*
-TEST_OUTPUT:
----
-fail_compilation/ice17074.d(39): Error: identifier expected for C++ namespace
-fail_compilation/ice17074.d(39): Error: found `*` when expecting `)`
-fail_compilation/ice17074.d(39): Error: declaration expected, not `)`
----
-*/
extern(C++, std.*) void ice_std_token();
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice17831.d b/gcc/testsuite/gdc.test/fail_compilation/ice17831.d
index 15b8502..41abbf7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice17831.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice17831.d
@@ -1,12 +1,16 @@
-// REQUIRED_ARGS: -d
/*
TEST_OUTPUT:
---
-fail_compilation/ice17831.d(19): Error: case variable `i` declared at fail_compilation/ice17831.d(17) cannot be declared in switch body
-fail_compilation/ice17831.d(33): Error: case variable `i` declared at fail_compilation/ice17831.d(31) cannot be declared in switch body
-fail_compilation/ice17831.d(48): Error: case variable `i` declared at fail_compilation/ice17831.d(45) cannot be declared in switch body
-fail_compilation/ice17831.d(61): Error: case variable `i` declared at fail_compilation/ice17831.d(60) cannot be declared in switch body
-fail_compilation/ice17831.d(73): Error: case variable `i` declared at fail_compilation/ice17831.d(72) cannot be declared in switch body
+fail_compilation/ice17831.d(23): Error: `case` variables have to be `const` or `immutable`
+fail_compilation/ice17831.d(23): Error: `case` variable `i` declared at fail_compilation/ice17831.d(21) cannot be declared in `switch` body
+fail_compilation/ice17831.d(37): Error: `case` variables have to be `const` or `immutable`
+fail_compilation/ice17831.d(37): Error: `case` variable `i` declared at fail_compilation/ice17831.d(35) cannot be declared in `switch` body
+fail_compilation/ice17831.d(52): Error: `case` variables have to be `const` or `immutable`
+fail_compilation/ice17831.d(52): Error: `case` variable `i` declared at fail_compilation/ice17831.d(49) cannot be declared in `switch` body
+fail_compilation/ice17831.d(65): Error: `case` variables have to be `const` or `immutable`
+fail_compilation/ice17831.d(65): Error: `case` variable `i` declared at fail_compilation/ice17831.d(64) cannot be declared in `switch` body
+fail_compilation/ice17831.d(77): Error: `case` variables have to be `const` or `immutable`
+fail_compilation/ice17831.d(77): Error: `case` variable `i` declared at fail_compilation/ice17831.d(76) cannot be declared in `switch` body
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice18469.d b/gcc/testsuite/gdc.test/fail_compilation/ice18469.d
new file mode 100644
index 0000000..8803956
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice18469.d
@@ -0,0 +1,13 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice18469.d(10): Error: no property `opCall` for type `void`
+---
+*/
+class Bar
+{
+ ~this(){}
+ this(){alias T = typeof(Bar.__dtor.opCall);}
+}
+
+void main() {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice18753.d b/gcc/testsuite/gdc.test/fail_compilation/ice18753.d
new file mode 100644
index 0000000..300eab2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice18753.d
@@ -0,0 +1,39 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice18753.d(21): Error: variable `ice18753.isInputRange!(Group).isInputRange` type `void` is inferred from initializer `ReturnType(func...)`, and variables cannot be of type `void`
+fail_compilation/ice18753.d(23): Error: template instance `ice18753.isInputRange!(Group)` error instantiating
+fail_compilation/ice18753.d(18): instantiated from here: `isForwardRange!(Group)`
+fail_compilation/ice18753.d(18): while evaluating: `static assert(isForwardRange!(Group))`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=18753
+
+struct ChunkByImpl
+{
+ struct Group
+ { }
+
+ static assert(isForwardRange!Group);
+}
+
+enum isInputRange(R) = ReturnType;
+
+enum isForwardRange(R) = isInputRange!R is ReturnType!(() => r);
+
+template ReturnType(func...)
+{
+ static if (is(FunctionTypeOf!func R == return))
+ ReturnType R;
+}
+
+template FunctionTypeOf(func...)
+{
+ static if (is(typeof(func[0]) T))
+ static if (is(T Fptr ) )
+ alias FunctionTypeOf = Fptr;
+}
+
+template Select()
+{ }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice18803a.d b/gcc/testsuite/gdc.test/fail_compilation/ice18803a.d
new file mode 100644
index 0000000..5ec5a81
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice18803a.d
@@ -0,0 +1,9 @@
+/*
+EXTRA_FILES: ice18803b.d
+TEST_OUTPUT:
+---
+fail_compilation/ice18803b.d(9): Error: (expression) expected following `static if`
+fail_compilation/ice18803b.d(9): Error: declaration expected following attribute, not end of file
+---
+*/
+void main() { import ice18803b; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice18803b.d b/gcc/testsuite/gdc.test/fail_compilation/ice18803b.d
new file mode 100644
index 0000000..cfc38c5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice18803b.d
@@ -0,0 +1,8 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice18803b.d(9): Error: (expression) expected following `static if`
+fail_compilation/ice18803b.d(9): Error: declaration expected following attribute, not end of file
+---
+*/
+static if
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice19295.d b/gcc/testsuite/gdc.test/fail_compilation/ice19295.d
new file mode 100644
index 0000000..a92f5f8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice19295.d
@@ -0,0 +1,18 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice19295.d(11): Error: `this` for `gun` needs to be type `S2` not type `S1!(gun)`
+fail_compilation/ice19295.d(11): while evaluating `pragma(msg, &gun)`
+fail_compilation/ice19295.d(17): Error: template instance `ice19295.S1!(gun)` error instantiating
+---
+*/
+struct S1(T...) {
+ auto fun() {
+ pragma(msg, &T[0]);
+ }
+}
+
+struct S2 {
+ void gun() {}
+ S1!gun overloaded;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice19755.d b/gcc/testsuite/gdc.test/fail_compilation/ice19755.d
new file mode 100644
index 0000000..f948477
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice19755.d
@@ -0,0 +1,16 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/ice19755.d(11): Error: no property `x` for type `ice19755.Thunk!int*`
+fail_compilation/ice19755.d(16): Error: template instance `ice19755.Thunk!int` error instantiating
+---
+*/
+struct Thunk(Dummy) {
+ void opAssign(int dlg) {}
+ auto get() inout {
+ Thunk* self;
+ self.x = 0;
+ }
+ alias get this;
+}
+
+alias T = Thunk!int;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice19762.d b/gcc/testsuite/gdc.test/fail_compilation/ice19762.d
new file mode 100644
index 0000000..a484327
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice19762.d
@@ -0,0 +1,17 @@
+// EXTRA_FILES: imports/b19762.d imports/c19762.d
+// PERMUTE_ARGS: -g
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice19762.d(13): Error: struct `ice19762.X` had semantic errors when compiling
+---
+*/
+
+module ice19762;
+
+struct X
+{
+ import imports.b19762 : Baz;
+ Err err;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice19887.d b/gcc/testsuite/gdc.test/fail_compilation/ice19887.d
new file mode 100644
index 0000000..a323d08
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice19887.d
@@ -0,0 +1,14 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice19887.d(9): Error: initializer must be an expression, not `(void)`
+---
+*/
+module ice19887;
+
+void func(AliasSeq!(int) params = AliasSeq!(void)) {}
+
+template AliasSeq(TList...)
+{
+ alias AliasSeq = TList;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice19950.d b/gcc/testsuite/gdc.test/fail_compilation/ice19950.d
new file mode 100644
index 0000000..dc930d5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice19950.d
@@ -0,0 +1,13 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice19950.d(8): Error: undefined identifier `NotHere`
+fail_compilation/ice19950.d(9): Error: template instance `ice19950.baz!()` does not match template declaration `baz()(Foo)`
+---
+*/
+alias Foo = NotHere;
+alias Bar = baz!();
+
+void baz()(Foo)
+ if (true)
+{}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice20042.d b/gcc/testsuite/gdc.test/fail_compilation/ice20042.d
new file mode 100644
index 0000000..6b71903
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice20042.d
@@ -0,0 +1,29 @@
+/*
+DISABLED: freebsd32 linux32 osx32 win32
+TEST_OUTPUT:
+---
+fail_compilation/ice20042.d(18): Error: slice operation `cast(__vector(float[4]))[nanF, nanF, nanF, nanF] = [1.0F, 2.0F, 3.0F, 4.0F][0..4]` cannot be evaluated at compile time
+fail_compilation/ice20042.d(25): called from here: `Vec4(cast(__vector(float[4]))[nanF, nanF, nanF, nanF]).this([1.0F, 2.0F, 3.0F, 4.0F])`
+---
+*/
+void write(T...)(T t){}
+
+struct Vec4
+{
+ __vector(float[4]) raw;
+
+ this(const(float[4]) value...) inout pure @safe nothrow @nogc
+ {
+ __vector(float[4]) raw;
+ raw[] = value[];
+ this.raw = raw;
+ }
+}
+
+void main()
+{
+ static immutable Vec4 v = Vec4( 1.0f, 2.0f, 3.0f, 4.0f );
+
+ static foreach(d; 0 .. 4)
+ write(v.raw[d], " ");
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice20056.d b/gcc/testsuite/gdc.test/fail_compilation/ice20056.d
new file mode 100644
index 0000000..1b991ca
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice20056.d
@@ -0,0 +1,25 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice20056.d(19): Error: need `this` for `iter` of type `void()`
+---
+*/
+struct Def(alias fn)
+{
+ alias func = alias_selector!(fn).VOverloads[0];
+}
+
+template alias_selector(alias fn)
+{
+ alias VOverloads = __traits(getOverloads, __traits(parent, fn), __traits(identifier, fn));
+}
+
+void init_rangewrapper()
+{
+ Def!(RangeWrapper.iter).func;
+}
+
+struct RangeWrapper
+{
+ void iter() { }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice20057.d b/gcc/testsuite/gdc.test/fail_compilation/ice20057.d
new file mode 100644
index 0000000..617e07c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice20057.d
@@ -0,0 +1,17 @@
+/*
+EXTRA_FILES: imports/i20057.d
+TEST_OUTPUT:
+---
+fail_compilation/ice20057.d(10): Error: alias `ice20057.BlackHole` conflicts with struct `ice20057.BlackHole(alias T)` at fail_compilation/ice20057.d(9)
+---
+*/
+
+struct BlackHole(alias T){T t;}
+import imports.i20057: BlackHole;
+
+extern(C++) interface Inter
+{
+ void func();
+}
+
+BlackHole!Inter var;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice20264.d b/gcc/testsuite/gdc.test/fail_compilation/ice20264.d
new file mode 100644
index 0000000..0d697e2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice20264.d
@@ -0,0 +1,13 @@
+/*
+DISABLED: freebsd32 linux32 osx32 win32
+TEST_OUTPUT:
+---
+fail_compilation/ice20264.d(12): Error: `cast(__vector(float[4]))a` is not an lvalue and cannot be modified
+---
+*/
+
+void foo(float *a)
+{
+ alias float4 = __vector(float[4]);
+ cast(float4)(a) = 1.0f;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice20545.d b/gcc/testsuite/gdc.test/fail_compilation/ice20545.d
new file mode 100644
index 0000000..26bd320
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice20545.d
@@ -0,0 +1,8 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice20545.d(8): Error: initializer expression expected following colon, not `]`
+---
+*/
+
+static initial = [{ }: ];
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice20709.d b/gcc/testsuite/gdc.test/fail_compilation/ice20709.d
new file mode 100644
index 0000000..cc36de9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice20709.d
@@ -0,0 +1,14 @@
+/*
+EXTRA_FILES: imports/imp20709.d
+TEST_OUTPUT:
+---
+fail_compilation/ice20709.d(10): Error: module `imp20709` import `Point` not found
+---
+*/
+module ice20709;
+
+import imports.imp20709 : Point;
+
+immutable Point aPoint = somePoint;
+
+Point somePoint() {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice21095.d b/gcc/testsuite/gdc.test/fail_compilation/ice21095.d
new file mode 100644
index 0000000..0d87d63
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice21095.d
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=21095
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice21095.d(14): Error: constructor `ice21095.Mutex.__ctor!().this` `in` and `out` contracts can only appear without a body when they are virtual interface functions or abstract
+fail_compilation/ice21095.d(12): Error: template instance `ice21095.Mutex.__ctor!()` error instantiating
+---
+*/
+class Mutex
+{
+ this(Object obj) {
+ this(obj, true);
+ }
+ this()(Object, bool) in { }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice2843.d b/gcc/testsuite/gdc.test/fail_compilation/ice2843.d
index c0c3797..cf53e5d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice2843.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice2843.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice2843.d(22): Error: incompatible types for ((1) is (typeid(int))): 'int' and 'object.TypeInfo'
+fail_compilation/ice2843.d(22): Error: incompatible types for `(1) is (typeid(int))`: `int` and `object.TypeInfo`
---
*/
-// Issue 2843 - ICE(constfold.c) with is-expression with invalid dot-expression in is-expression involving typeid expression
-
+// https://issues.dlang.org/show_bug.cgi?id=2843
+// ICE(constfold.c) with is-expression with invalid dot-expression in is-expression involving typeid expression
/* 2843 Assertion failure: '0' on line 863 in file 'constfold.c'
PATCH: constfold.c, line 861:
OLD:
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice4094.d b/gcc/testsuite/gdc.test/fail_compilation/ice4094.d
index cd41e65..61108c4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice4094.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice4094.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice4094.d(11): Error: circular reference to variable 'ice4094.Zug!0.Zug.bahn'
-fail_compilation/ice4094.d(19): Error: template instance ice4094.Zug!0 error instantiating
+fail_compilation/ice4094.d(11): Error: circular reference to variable `ice4094.Zug!0.Zug.bahn`
+fail_compilation/ice4094.d(19): Error: template instance `ice4094.Zug!0` error instantiating
---
*/
// REQUIRED_ARGS: -d
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice4983.d b/gcc/testsuite/gdc.test/fail_compilation/ice4983.d
index 1925c17..00fa95c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice4983.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice4983.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice4983.d(14): Error: circular reference to 'ice4983.Foo.dg'
+fail_compilation/ice4983.d(14): Error: circular reference to `ice4983.Foo.dg`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice6538.d b/gcc/testsuite/gdc.test/fail_compilation/ice6538.d
index dad6491..0715db5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice6538.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice6538.d
@@ -1,14 +1,14 @@
/**************************************/
-// 9361
+// https://issues.dlang.org/show_bug.cgi?id=9361
/*
TEST_OUTPUT:
---
-fail_compilation/ice6538.d(23): Error: expression super is not a valid template value argument
-fail_compilation/ice6538.d(28): Error: template ice6538.D.foo cannot deduce function from argument types !()(), candidates are:
-fail_compilation/ice6538.d(23): ice6538.D.foo()() if (Sym!(super))
+fail_compilation/ice6538.d(23): Error: expression `super` is not a valid template value argument
+fail_compilation/ice6538.d(28): Error: template `ice6538.D.foo` cannot deduce function from argument types `!()()`
+fail_compilation/ice6538.d(23): Candidate is: `foo()()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice7645.d b/gcc/testsuite/gdc.test/fail_compilation/ice7645.d
index 1aa3fad..379ac67 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice7645.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice7645.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice7645.d(28): Error: need 'this' for 't' of type 'char'
-fail_compilation/ice7645.d(31): Error: need 'this' for 'fn' of type 'pure nothrow @nogc @safe void()'
+fail_compilation/ice7645.d(28): Error: need `this` for `t` of type `char`
+fail_compilation/ice7645.d(31): Error: need `this` for `fn` of type `pure nothrow @nogc @safe void()`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8100.d b/gcc/testsuite/gdc.test/fail_compilation/ice8100.d
index 1e7d56b..dc68cfc 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice8100.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice8100.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice8100.d(10): Error: no property 'Q' for type 'ice8100.Bar!bool'
-fail_compilation/ice8100.d(11): Error: template instance ice8100.Foo!(Bar!bool) error instantiating
-fail_compilation/ice8100.d(12): instantiated from here: Bar!bool
+fail_compilation/ice8100.d(10): Error: no property `Q` for type `ice8100.Bar!bool`
+fail_compilation/ice8100.d(11): Error: template instance `ice8100.Foo!(Bar!bool)` error instantiating
+fail_compilation/ice8100.d(12): instantiated from here: `Bar!bool`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8255.d b/gcc/testsuite/gdc.test/fail_compilation/ice8255.d
deleted file mode 100644
index 0db3abc..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/ice8255.d
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/ice8255.d(11): Error: function `ice8255.F!(G).F.f(ref G _param_0)` is not callable using argument types `(G)`
-fail_compilation/ice8255.d(11): cannot pass rvalue argument `G()` of type `G` to parameter `ref G _param_0`
-fail_compilation/ice8255.d(11): while evaluating `pragma(msg, F().f(G()))`
----
-*/
-struct G {}
-struct F(T) { void f(ref T) {} }
-pragma(msg, F!G().f(G.init));
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8309.d b/gcc/testsuite/gdc.test/fail_compilation/ice8309.d
index 5d5bb83..2446914 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice8309.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice8309.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice8309.d(10): Error: incompatible types for ((__lambda1) : (__lambda2)): 'double function() pure nothrow @nogc @safe' and 'int function() pure nothrow @nogc @safe'
+fail_compilation/ice8309.d(10): Error: incompatible types for `(__lambda1) : (__lambda2)`: `double function() pure nothrow @nogc @safe` and `int function() pure nothrow @nogc @safe`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8711.d b/gcc/testsuite/gdc.test/fail_compilation/ice8711.d
index c143929..d6674c4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice8711.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice8711.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice8711.d(8): Error: cannot use array to initialize int function(int)
+fail_compilation/ice8711.d(8): Error: cannot use array to initialize `int function(int)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8795.d b/gcc/testsuite/gdc.test/fail_compilation/ice8795.d
index 29eabbf..5d7d6dd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice8795.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice8795.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice8795.d-mixin-14(14): Error: found `EOF` when expecting `(`
-fail_compilation/ice8795.d-mixin-14(14): Error: expression expected, not `EOF`
-fail_compilation/ice8795.d-mixin-14(14): Error: found `EOF` when expecting `)`
-fail_compilation/ice8795.d-mixin-14(14): Error: found `EOF` instead of statement
+fail_compilation/ice8795.d-mixin-14(14): Error: found `End of File` when expecting `(`
+fail_compilation/ice8795.d-mixin-14(14): Error: expression expected, not `End of File`
+fail_compilation/ice8795.d-mixin-14(14): Error: found `End of File` when expecting `)`
+fail_compilation/ice8795.d-mixin-14(14): Error: found `End of File` instead of statement
fail_compilation/ice8795.d-mixin-15(15): Error: { } expected following `interface` declaration
fail_compilation/ice8795.d-mixin-15(15): Error: anonymous interfaces not allowed
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9273a.d b/gcc/testsuite/gdc.test/fail_compilation/ice9273a.d
index 91f22d4..c2f44a3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9273a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9273a.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice9273a.d(19): Error: constructor ice9273a.C.__ctor!().this no match for implicit super() call in constructor
-fail_compilation/ice9273a.d(23): Error: template instance ice9273a.C.__ctor!() error instantiating
+fail_compilation/ice9273a.d(19): Error: constructor `ice9273a.C.__ctor!().this` no match for implicit `super()` call in constructor
+fail_compilation/ice9273a.d(23): Error: template instance `ice9273a.C.__ctor!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9273b.d b/gcc/testsuite/gdc.test/fail_compilation/ice9273b.d
index 1a779fa..2d05724 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9273b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9273b.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice9273b.d(14): Error: constructor ice9273b.B.this no match for implicit super() call in constructor
+fail_compilation/ice9273b.d(14): Error: constructor `ice9273b.B.this` no match for implicit `super()` call in constructor
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d
index 0c95bd8..a6d84ae 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice9284.d(14): Error: template ice9284.C.__ctor cannot deduce function from argument types !()(int), candidates are:
-fail_compilation/ice9284.d(12): ice9284.C.__ctor()(string)
-fail_compilation/ice9284.d(20): Error: template instance ice9284.C.__ctor!() error instantiating
+fail_compilation/ice9284.d(14): Error: template `ice9284.C.__ctor` cannot deduce function from argument types `!()(int)`
+fail_compilation/ice9284.d(12): Candidate is: `__ctor()(string)`
+fail_compilation/ice9284.d(20): Error: template instance `ice9284.C.__ctor!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9338.d b/gcc/testsuite/gdc.test/fail_compilation/ice9338.d
index 292c059..5f77817 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9338.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9338.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice9338.d(13): Error: value of 'this' is not known at compile time
-fail_compilation/ice9338.d(14): Error: value of 'this' is not known at compile time
+fail_compilation/ice9338.d(13): Error: value of `this` is not known at compile time
+fail_compilation/ice9338.d(14): Error: value of `this` is not known at compile time
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9439.d b/gcc/testsuite/gdc.test/fail_compilation/ice9439.d
index 51b84e8..a9e7008 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9439.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9439.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice9439.d(12): Error: this for foo needs to be type Derived not type ice9439.Base
+fail_compilation/ice9439.d(12): Error: `this` for `foo` needs to be type `Derived` not type `ice9439.Base`
fail_compilation/ice9439.d(12): while evaluating: `static assert((__error).foo())`
-fail_compilation/ice9439.d(19): Error: template instance ice9439.Base.boo!(foo) error instantiating
+fail_compilation/ice9439.d(19): Error: template instance `ice9439.Base.boo!(foo)` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9494.d b/gcc/testsuite/gdc.test/fail_compilation/ice9494.d
index b2743e5..732b88a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9494.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9494.d
@@ -1,9 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice9494.d(10): Error: circular reference to variable 'ice9494.test'
-fail_compilation/ice9494.d(14): Error: circular reference to variable 'ice9494.Foo.test'
-fail_compilation/ice9494.d(19): Error: circular reference to variable 'ice9494.Bar.test'
+fail_compilation/ice9494.d(10): Error: circular reference to variable `ice9494.test`
+fail_compilation/ice9494.d(14): Error: circular reference to variable `ice9494.Foo.test`
+fail_compilation/ice9494.d(19): Error: circular reference to variable `ice9494.Bar.test`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9545.d b/gcc/testsuite/gdc.test/fail_compilation/ice9545.d
index 846975a..7360bc5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9545.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9545.d
@@ -2,7 +2,7 @@
/*
TEST_OUTPUT:
----
-fail_compilation/ice9545.d(13): Error: type int has no value
+fail_compilation/ice9545.d(13): Error: type `int` has no value
----
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9759.d b/gcc/testsuite/gdc.test/fail_compilation/ice9759.d
index 300540c..6608b58 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9759.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9759.d
@@ -1,7 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice9759.d(24): Error: mutable method ice9759.Json.opAssign is not callable using a const object
+fail_compilation/ice9759.d(25): Error: mutable method `ice9759.Json.opAssign` is not callable using a `const` object
+fail_compilation/ice9759.d(17): Consider adding `const` or `inout` here
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9806.d b/gcc/testsuite/gdc.test/fail_compilation/ice9806.d
index 5f00fcc..40e6273 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9806.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9806.d
@@ -2,11 +2,11 @@
TEST_OUTPUT:
---
fail_compilation/ice9806.d(12): Error: undefined identifier `undefined_expr`
-fail_compilation/ice9806.d(17): Error: template instance ice9806.S1!() error instantiating
+fail_compilation/ice9806.d(17): Error: template instance `ice9806.S1!()` error instantiating
fail_compilation/ice9806.d(13): Error: undefined identifier `undefined_expr`
-fail_compilation/ice9806.d(19): Error: template instance ice9806.C1!() error instantiating
+fail_compilation/ice9806.d(19): Error: template instance `ice9806.C1!()` error instantiating
fail_compilation/ice9806.d(14): Error: undefined identifier `undefined_expr`
-fail_compilation/ice9806.d(21): Error: template instance ice9806.I1!() error instantiating
+fail_compilation/ice9806.d(21): Error: template instance `ice9806.I1!()` error instantiating
---
*/
struct S1() { enum x = undefined_expr; }
@@ -26,11 +26,11 @@ void test1() {
TEST_OUTPUT:
---
fail_compilation/ice9806.d(36): Error: undefined identifier `undefined_expr`
-fail_compilation/ice9806.d(44): Error: template instance ice9806.S2!() error instantiating
+fail_compilation/ice9806.d(44): Error: template instance `ice9806.S2!()` error instantiating
fail_compilation/ice9806.d(37): Error: undefined identifier `undefined_expr`
-fail_compilation/ice9806.d(46): Error: template instance ice9806.C2!() error instantiating
+fail_compilation/ice9806.d(46): Error: template instance `ice9806.C2!()` error instantiating
fail_compilation/ice9806.d(38): Error: undefined identifier `undefined_expr`
-fail_compilation/ice9806.d(48): Error: template instance ice9806.I2!() error instantiating
+fail_compilation/ice9806.d(48): Error: template instance `ice9806.I2!()` error instantiating
---
*/
int foo2()() { return undefined_expr; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9865.d b/gcc/testsuite/gdc.test/fail_compilation/ice9865.d
index 846ba2e..3d8e997 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9865.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9865.d
@@ -1,7 +1,8 @@
/*
+EXTRA_FILES: imports/ice9865b.d
TEST_OUTPUT:
---
-fail_compilation/ice9865.d(8): Error: alias ice9865.Baz recursive alias declaration
+fail_compilation/ice9865.d(9): Error: alias `ice9865.Baz` recursive alias declaration
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/impconv.d b/gcc/testsuite/gdc.test/fail_compilation/impconv.d
new file mode 100644
index 0000000..cb1cb8e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/impconv.d
@@ -0,0 +1,40 @@
+/*
+FIXME: DMD host compilers < 2.073 with faulty optimization
+lead to unfortunate test failures, see
+https://github.com/dlang/dmd/pull/6831#issuecomment-304495842.
+
+DISABLED: win32 win64 linux osx freebsd
+*/
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/impconv.d(30): Error: function `impconv.foo_float(float)` is not callable using argument types `(int)`
+fail_compilation/impconv.d(30): cannot pass argument `-2147483647` of type `int` to parameter `float`
+fail_compilation/impconv.d(31): Error: function `impconv.foo_float(float)` is not callable using argument types `(uint)`
+fail_compilation/impconv.d(31): cannot pass argument `4294967295u` of type `uint` to parameter `float`
+fail_compilation/impconv.d(34): Error: function `impconv.foo_double(double)` is not callable using argument types `(long)`
+fail_compilation/impconv.d(34): cannot pass argument `-9223372036854775807L` of type `long` to parameter `double`
+fail_compilation/impconv.d(35): Error: function `impconv.foo_double(double)` is not callable using argument types `(ulong)`
+fail_compilation/impconv.d(35): cannot pass argument `18446744073709551615LU` of type `ulong` to parameter `double`
+---
+*/
+
+void foo_float(float);
+void foo_double(double);
+void foo_real(real);
+
+void main()
+{
+ foo_float(1); // implicitly convertible to float
+ foo_float(-int.max); // -(2^31 - 1)
+ foo_float(uint.max); // 2^32 - 1
+
+ foo_double(int.max); // implicitly convertible to double
+ foo_double(-long.max); // -(2^63 - 1)
+ foo_double(ulong.max); // 2^64 - 1
+
+ foo_real(0xffff_ffff_ffffL); // 2^48 - 1, implicitly convertible to real
+ static assert(__traits(compiles, foo_real(-long.max)) == (real.mant_dig >= 63));
+ static assert(__traits(compiles, foo_real(ulong.max)) == (real.mant_dig >= 64));
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imphint.d b/gcc/testsuite/gdc.test/fail_compilation/imphint.d
index 2b3abeb..101e786 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/imphint.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/imphint.d
@@ -1,12 +1,50 @@
/*
TEST_OUTPUT:
---
-fail_compilation/imphint.d(14): Error: 'printf' is not defined, perhaps you need to import core.stdc.stdio; ?
-fail_compilation/imphint.d(15): Error: 'writeln' is not defined, perhaps you need to import std.stdio; ?
-fail_compilation/imphint.d(16): Error: 'sin' is not defined, perhaps you need to import std.math; ?
-fail_compilation/imphint.d(17): Error: 'cos' is not defined, perhaps you need to import std.math; ?
-fail_compilation/imphint.d(18): Error: 'sqrt' is not defined, perhaps you need to import std.math; ?
-fail_compilation/imphint.d(19): Error: 'fabs' is not defined, perhaps you need to import std.math; ?
+fail_compilation/imphint.d(53): Error: `printf` is not defined, perhaps `import core.stdc.stdio;` is needed?
+fail_compilation/imphint.d(54): Error: `writeln` is not defined, perhaps `import std.stdio;` is needed?
+fail_compilation/imphint.d(55): Error: `sin` is not defined, perhaps `import std.math;` is needed?
+fail_compilation/imphint.d(56): Error: `cos` is not defined, perhaps `import std.math;` is needed?
+fail_compilation/imphint.d(57): Error: `sqrt` is not defined, perhaps `import std.math;` is needed?
+fail_compilation/imphint.d(58): Error: `fabs` is not defined, perhaps `import std.math;` is needed?
+fail_compilation/imphint.d(61): Error: `AliasSeq` is not defined, perhaps `import std.meta;` is needed?
+fail_compilation/imphint.d(62): Error: `appender` is not defined, perhaps `import std.array;` is needed?
+fail_compilation/imphint.d(63): Error: `array` is not defined, perhaps `import std.array;` is needed?
+fail_compilation/imphint.d(64): Error: `calloc` is not defined, perhaps `import core.stdc.stdlib;` is needed?
+fail_compilation/imphint.d(65): Error: `chdir` is not defined, perhaps `import std.file;` is needed?
+fail_compilation/imphint.d(66): Error: `dirEntries` is not defined, perhaps `import std.file;` is needed?
+fail_compilation/imphint.d(67): Error: `drop` is not defined, perhaps `import std.range;` is needed?
+fail_compilation/imphint.d(68): Error: `each` is not defined, perhaps `import std.algorithm;` is needed?
+fail_compilation/imphint.d(69): Error: `empty` is not defined, perhaps `import std.range;` is needed?
+fail_compilation/imphint.d(70): Error: `enumerate` is not defined, perhaps `import std.range;` is needed?
+fail_compilation/imphint.d(71): Error: `endsWith` is not defined, perhaps `import std.algorithm;` is needed?
+fail_compilation/imphint.d(72): Error: `enforce` is not defined, perhaps `import std.exception;` is needed?
+fail_compilation/imphint.d(73): Error: `equal` is not defined, perhaps `import std.algorithm;` is needed?
+fail_compilation/imphint.d(74): Error: `exists` is not defined, perhaps `import std.file;` is needed?
+fail_compilation/imphint.d(75): Error: `filter` is not defined, perhaps `import std.algorithm;` is needed?
+fail_compilation/imphint.d(76): Error: `format` is not defined, perhaps `import std.format;` is needed?
+fail_compilation/imphint.d(77): Error: `free` is not defined, perhaps `import core.stdc.stdlib;` is needed?
+fail_compilation/imphint.d(78): Error: `front` is not defined, perhaps `import std.range;` is needed?
+fail_compilation/imphint.d(79): Error: `iota` is not defined, perhaps `import std.range;` is needed?
+fail_compilation/imphint.d(80): Error: `isDir` is not defined, perhaps `import std.file;` is needed?
+fail_compilation/imphint.d(81): Error: `isFile` is not defined, perhaps `import std.file;` is needed?
+fail_compilation/imphint.d(82): Error: `join` is not defined, perhaps `import std.array;` is needed?
+fail_compilation/imphint.d(83): Error: `joiner` is not defined, perhaps `import std.algorithm;` is needed?
+fail_compilation/imphint.d(84): Error: `malloc` is not defined, perhaps `import core.stdc.stdlib;` is needed?
+fail_compilation/imphint.d(85): Error: `map` is not defined, perhaps `import std.algorithm;` is needed?
+fail_compilation/imphint.d(86): Error: `max` is not defined, perhaps `import std.algorithm;` is needed?
+fail_compilation/imphint.d(87): Error: `min` is not defined, perhaps `import std.algorithm;` is needed?
+fail_compilation/imphint.d(88): Error: `mkdir` is not defined, perhaps `import std.file;` is needed?
+fail_compilation/imphint.d(89): Error: `popFront` is not defined, perhaps `import std.range;` is needed?
+fail_compilation/imphint.d(90): Error: `realloc` is not defined, perhaps `import core.stdc.stdlib;` is needed?
+fail_compilation/imphint.d(91): Error: `replace` is not defined, perhaps `import std.array;` is needed?
+fail_compilation/imphint.d(92): Error: `rmdir` is not defined, perhaps `import std.file;` is needed?
+fail_compilation/imphint.d(93): Error: `sort` is not defined, perhaps `import std.algorithm;` is needed?
+fail_compilation/imphint.d(94): Error: `split` is not defined, perhaps `import std.array;` is needed?
+fail_compilation/imphint.d(95): Error: `startsWith` is not defined, perhaps `import std.algorithm;` is needed?
+fail_compilation/imphint.d(96): Error: `take` is not defined, perhaps `import std.range;` is needed?
+fail_compilation/imphint.d(97): Error: `text` is not defined, perhaps `import std.conv;` is needed?
+fail_compilation/imphint.d(98): Error: `to` is not defined, perhaps `import std.conv;` is needed?
---
*/
@@ -18,4 +56,44 @@ void foo()
cos(1.2);
sqrt(2.0);
fabs(-3);
+
+
+ AliasSeq();
+ appender();
+ array();
+ calloc();
+ chdir();
+ dirEntries();
+ drop();
+ each();
+ empty();
+ enumerate();
+ endsWith();
+ enforce();
+ equal();
+ exists();
+ filter();
+ format();
+ free();
+ front();
+ iota();
+ isDir();
+ isFile();
+ join();
+ joiner();
+ malloc();
+ map();
+ max();
+ min();
+ mkdir();
+ popFront();
+ realloc();
+ replace();
+ rmdir();
+ sort();
+ split();
+ startsWith();
+ take();
+ text();
+ to();
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a14407.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a14407.d
deleted file mode 100644
index d906bc7..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/imports/a14407.d
+++ /dev/null
@@ -1,19 +0,0 @@
-module imports.a14407;
-
-deprecated class C
-{
- private deprecated new (size_t, string)
- {
- return null;
- }
- private this(int) {}
-}
-
-deprecated struct S
-{
- private deprecated new (size_t, string)
- {
- return null;
- }
- private this(int) {}
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a17625.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a17625.d
new file mode 100644
index 0000000..d8a457c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a17625.d
@@ -0,0 +1,3 @@
+module a17625;
+
+private int boo() { return 69; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/a18243.d b/gcc/testsuite/gdc.test/fail_compilation/imports/a18243.d
new file mode 100644
index 0000000..73df751
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/a18243.d
@@ -0,0 +1,5 @@
+module a18243;
+
+import std.math : isNaN;
+
+public bool isNaN() { return false; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/b17625.d b/gcc/testsuite/gdc.test/fail_compilation/imports/b17625.d
new file mode 100644
index 0000000..02946b0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/b17625.d
@@ -0,0 +1,3 @@
+module b17625;
+
+private int boo() { return 45; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/b17918a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/b17918a.d
new file mode 100644
index 0000000..03cf9a9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/b17918a.d
@@ -0,0 +1,9 @@
+module imports.b17918a;
+
+class Base
+{
+ auto byNode()
+ {
+ return _listMap;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/b19762.d b/gcc/testsuite/gdc.test/fail_compilation/imports/b19762.d
new file mode 100644
index 0000000..f089354
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/b19762.d
@@ -0,0 +1,7 @@
+module imports.b19762;
+
+struct Baz {}
+struct Qux
+{
+ import imports.c19762;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/c19762.d b/gcc/testsuite/gdc.test/fail_compilation/imports/c19762.d
new file mode 100644
index 0000000..ec4d389
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/c19762.d
@@ -0,0 +1,27 @@
+module imports.c19762;
+
+struct Foo
+{
+ import ice19762 : X;
+ X[] x;
+}
+
+Nullable!Foo foo()
+{
+ Nullable!Foo output;
+ return output;
+}
+
+struct Nullable(T)
+{
+ bool opEquals(U)(const(U) rhs) const
+ if (is(typeof(this.get == rhs)))
+ {
+ return true;
+ }
+
+ inout(T) get() inout
+ {
+ return T.init;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/constraints.d b/gcc/testsuite/gdc.test/fail_compilation/imports/constraints.d
new file mode 100755
index 0000000..a19e89a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/constraints.d
@@ -0,0 +1,73 @@
+module imports.constraints;
+
+// can be shared between usual and verbose output versions
+
+enum P(T) = true;
+enum N(T) = false;
+
+// constraints_func1
+void test1(T)(T v) if (N!T);
+void test2(T)(T v) if (!P!T);
+void test3(T)(T v) if (P!T && N!T);
+void test4(T)(T v) if (P!T && N!T && P!T);
+void test5(T)(T v) if (N!T || N!T);
+void test6(T)(T v) if (N!T || N!T || !P!T);
+void test7(T)(T v) if (N!T || P!T && N!T);
+void test8(T)(T v) if ((N!T || P!T) && N!T);
+void test9(T)(T v) if (!P!T && !N!T);
+void test10(T)(T v) if (!N!T && !P!T);
+void test11(T)(T v) if (!(!N!T && P!T));
+void test12(T)(T v) if (!(N!T || P!T));
+
+// constraints_func2
+void test13(T)(T v) if (P!T ? N!T : P!T); // P!T && N!T || !P!T && P!T
+void test14(T)(T v) if (!P!T ? P!T : N!T);
+void test15(T)(T v) if (!(P!T ? P!T : N!T)); // (!P!T || !P!T) && (P!T || !N!T)
+void test16(T)(T v) if (N!T && P!T || N!T);
+void test17(T)(T v) if (N!T && P!T && (P!T || P!T));
+void test18(T)(T v) if ((N!T || P!T && N!T) && P!T);
+void test19(T)(T v) if ((N!T ? P!T : !P!T) ? P!T : N!T); // (N!T && P!T || !N!T && !P!T) && P!T || (!N!T || !P!T) && (N!T || P!T) && N!T
+void test20(T)(T v) if (N!T && (P!T && N!T || N!T));
+void test21(T)(T v) if (P!T && (N!T && P!T || N!T));
+void test22(T)(T v) if ((!P!T || !P!T && P!T) && (N!T || !P!T));
+void test23(T)(T v) if (!P!T || P!T && N!T || !P!T);
+void test24(R)(R r) if (__traits(hasMember, R, "stuff"));
+int test25(T)(T v) if (N!T);
+float test26(T, U)(U u) if (N!U);
+
+// constraints_func3
+void overload(T)(T v) if (N!T);
+void overload(T)(T v) if (!P!T);
+void overload(T)(T v1, T v2) if (N!T);
+void overload(T, V)(T v1, V v2) if (N!T || N!V);
+void variadic(A, T...)(A a, T v) if (N!int);
+
+// constraints_tmpl
+void dummy()() if (false);
+void message_nice(T, U)() if (P!T && "message 1" && N!U && "message 2");
+void message_ugly(T)(T v) if (!N!T && (T.stringof ~ " must be that") && N!T);
+void args(T, U)() if (N!T || N!U);
+void lambda(alias pred)() if (N!int);
+
+// constraints_defs
+void def(T, int i = 5, alias R)() if (N!T);
+void defa(T, U = int)() if (N!T);
+void defv(T = bool, int i = 5, Ts...)() if (N!T);
+
+// constraints_aggr
+class C
+{
+ void f(T)(T v) if (P!T && !P!T)
+ {}
+
+ void g(this T)() if (N!T)
+ {}
+}
+
+template S(T) if (N!T)
+{
+ alias S = T;
+}
+
+struct BitFlags(E, bool unsafe = false) if (unsafe || N!E)
+{}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/deprecatedImporta.d b/gcc/testsuite/gdc.test/fail_compilation/imports/deprecatedImporta.d
new file mode 100644
index 0000000..ef64878
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/deprecatedImporta.d
@@ -0,0 +1,2 @@
+deprecated("Please import deprecatedImportb directly!")
+public import imports.deprecatedImportb : AliasSeq, foo, bar, E, S, C, I;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/deprecatedImportb.d b/gcc/testsuite/gdc.test/fail_compilation/imports/deprecatedImportb.d
new file mode 100644
index 0000000..4a53e7f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/deprecatedImportb.d
@@ -0,0 +1,13 @@
+alias AliasSeq(T...) = T;
+
+void foo() {}
+
+void bar(T)(T t) {}
+
+enum E = 2;
+
+struct S {}
+
+class C {}
+
+interface I {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/diag20518a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/diag20518a.d
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/diag20518a.d
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/diag20518a/b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/diag20518a/b.d
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/diag20518a/b.d
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdcomplex.d b/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdcomplex.d
index 58aa99a..76a2cee 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdcomplex.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/diag9210stdcomplex.d
@@ -8,7 +8,7 @@ struct Complex(T) if (isFloatingPoint!T)
T im;
}
-// Bugzilla 9210: Complex!real instantiation is incomplete in here,
+// https://issues.dlang.org/show_bug.cgi?id=9210: Complex!real instantiation is incomplete in here,
// because its completion is deferred by an "undefined identifier" error in imports.diag9210b.
Complex!real expi(real y)
{
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail20164.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail20164.d
new file mode 100644
index 0000000..15d6359
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail20164.d
@@ -0,0 +1 @@
+deprecated module imports.fail20164;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail20637b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail20637b.d
new file mode 100644
index 0000000..d6fbdf5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail20637b.d
@@ -0,0 +1,3 @@
+module imports.fail20637b;
+
+class A { private static void foo() { } }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail20638b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail20638b.d
new file mode 100644
index 0000000..71218d9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail20638b.d
@@ -0,0 +1,3 @@
+module imports.fail20638b;
+
+private void foo() { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/fail21275a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/fail21275a.d
new file mode 100644
index 0000000..3fee203
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/fail21275a.d
@@ -0,0 +1,34 @@
+module imports.fail21275a;
+
+struct Foo
+{
+ private int _x;
+
+ private ref int x() return
+ {
+ return _x;
+ }
+
+ int x() const
+ {
+ return _x;
+ }
+
+}
+
+struct Bar
+{
+
+ private int _x;
+
+ private int x(int)
+ {
+ return _x;
+ }
+
+ int x() const
+ {
+ return _x;
+ }
+
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/i20057.d b/gcc/testsuite/gdc.test/fail_compilation/imports/i20057.d
new file mode 100644
index 0000000..9c9c666
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/i20057.d
@@ -0,0 +1,13 @@
+template generateEmptyFunction(C, func...)
+{
+}
+
+template isAbstractFunction(T...)
+if (T.length == 1)
+{
+ enum bool isAbstractFunction = __traits(isAbstractFunction, T[0]);
+}
+
+alias BlackHole(Base) = AutoImplement!(Base, generateEmptyFunction, isAbstractFunction);
+
+class AutoImplement(Base, alias how, alias what = isAbstractFunction) : Base {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/imp17602.d b/gcc/testsuite/gdc.test/fail_compilation/imports/imp17602.d
new file mode 100644
index 0000000..c1e6790
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/imp17602.d
@@ -0,0 +1,3 @@
+module imports.imp17602;
+
+enum Status { on }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/imp18554.d b/gcc/testsuite/gdc.test/fail_compilation/imports/imp18554.d
new file mode 100644
index 0000000..9f2a855
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/imp18554.d
@@ -0,0 +1,4 @@
+struct S
+{
+ private int i;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/imp18979.d b/gcc/testsuite/gdc.test/fail_compilation/imports/imp18979.d
new file mode 100644
index 0000000..9403f69
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/imp18979.d
@@ -0,0 +1,6 @@
+module imports.imp18979;
+
+struct Foo
+{
+ private this(A)(A a) {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/imp19661.d b/gcc/testsuite/gdc.test/fail_compilation/imports/imp19661.d
new file mode 100644
index 0000000..3a96803
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/imp19661.d
@@ -0,0 +1,17 @@
+template isFunction(X...)
+if (X.length == 1)
+{
+ static if (is(typeof(&X[0]) U : U*) && is(U == function) ||
+ is(typeof(&X[0]) U == delegate))
+ {
+ // x is a (nested) function symbol.
+ enum isFunction = true;
+ }
+ else static if (is(X[0] T))
+ {
+ // x is a type. Take the type of it and examine.
+ enum isFunction = is(T == function);
+ }
+ else
+ enum isFunction = false;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/imp20709.d b/gcc/testsuite/gdc.test/fail_compilation/imports/imp20709.d
new file mode 100644
index 0000000..a232974
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/imp20709.d
@@ -0,0 +1 @@
+module imp20709;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/imp21832.d b/gcc/testsuite/gdc.test/fail_compilation/imports/imp21832.d
new file mode 100644
index 0000000..ee4a1d6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/imp21832.d
@@ -0,0 +1,24 @@
+module imports.imp21832;
+static if(1)
+{
+ int fun(int a)
+ {
+ return a;
+ }
+ int tpl()(int a)
+ {
+ return a;
+ }
+}
+
+deprecated
+{
+ int fun(char a)
+ {
+ return a;
+ }
+ int tpl()(char a)
+ {
+ return a;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/import21508.d b/gcc/testsuite/gdc.test/fail_compilation/imports/import21508.d
new file mode 100644
index 0000000..07aa66e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/import21508.d
@@ -0,0 +1,2 @@
+module import21508;
+private class import21508 {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/issue21685.d b/gcc/testsuite/gdc.test/fail_compilation/imports/issue21685.d
new file mode 100644
index 0000000..eef95bf
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/issue21685.d
@@ -0,0 +1,6 @@
+module issue21685;
+
+class E
+{
+ private this() {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test18480a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test18480a.d
new file mode 100644
index 0000000..f20cf8a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test18480a.d
@@ -0,0 +1,3 @@
+public import imports.test18480b : TestTemplate;
+alias TestTemplate = TestTemplate;
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test18480b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test18480b.d
new file mode 100644
index 0000000..aa3ebd1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test18480b.d
@@ -0,0 +1 @@
+template TestTemplate() { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test18938a/cache.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test18938a/cache.d
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test18938a/cache.d
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test18938a/file.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test18938a/file.d
new file mode 100644
index 0000000..ee3199d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test18938a/file.d
@@ -0,0 +1,13 @@
+import imports.test18938b.file;
+class IconThemeGroup : IniLikeGroup
+{
+ this()
+ {
+ super("Icon Theme");
+ }
+
+ ///setter
+ string inherits()() {
+ }
+
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test18938b/file.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test18938b/file.d
new file mode 100644
index 0000000..977fe7a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test18938b/file.d
@@ -0,0 +1,28 @@
+module imports.test18938b.file;
+import std.algorithm;
+
+class IniLikeGroup
+{
+ this(string ) {}
+ @trusted byNode()
+ {
+ map!(node => lineNode);
+ }
+}
+
+
+class IniLikeFile
+{
+ struct WriteOptions
+ {
+ static exact()
+ {
+ return WriteOptions(No.lineBetweenGroups);
+ }
+
+ this(Args)(Args ){}
+
+ }
+ void saveToFile(WriteOptions = WriteOptions.exact) {}
+ final save() {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test19107a.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test19107a.d
new file mode 100644
index 0000000..d270e3b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test19107a.d
@@ -0,0 +1,3 @@
+module imports.test19107a.d;
+
+alias I(alias A) = A;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test19107b.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test19107b.d
new file mode 100644
index 0000000..8fd8087
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test19107b.d
@@ -0,0 +1,3 @@
+module imports.test19107b;
+
+import imports.test19107a : I;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test20267.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test20267.d
new file mode 100644
index 0000000..05059f6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test20267.d
@@ -0,0 +1,3 @@
+module imports.test20267;
+
+int[1] array;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/test21246.d b/gcc/testsuite/gdc.test/fail_compilation/imports/test21246.d
new file mode 100644
index 0000000..5294c41
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/test21246.d
@@ -0,0 +1,8 @@
+module imports.test21246;
+
+class Clock {}
+
+class B
+{
+ void set (Clock clock) { }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue15103.d b/gcc/testsuite/gdc.test/fail_compilation/issue15103.d
new file mode 100644
index 0000000..c4a67eb
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue15103.d
@@ -0,0 +1,25 @@
+/*
+TEST_OUTPUT:
+----
+fail_compilation/issue15103.d(22): Error: found `(` when expecting `;` or `=`, did you mean `Foo foo = 42`?
+fail_compilation/issue15103.d(23): Error: found `(` when expecting `;` or `=`, did you mean `Boo boo = 43`?
+fail_compilation/issue15103.d(24): Error: found `(` when expecting `;` or `=`, did you mean `string y = "a string"`?
+---
+*/
+
+struct Foo
+{
+ this(int x) {}
+}
+
+class Boo
+{
+ this(int x) {}
+}
+
+void main ()
+{
+ Foo foo(42);
+ Boo boo(43);
+ string y("a string");
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue20422.d b/gcc/testsuite/gdc.test/fail_compilation/issue20422.d
new file mode 100644
index 0000000..1964f8a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue20422.d
@@ -0,0 +1,12 @@
+// https://issues.dlang.org/show_bug.cgi?id=20422
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/issue20422.d(11): Error: missing length argument for array
+---
+*/
+
+void main() {
+ new int[];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue20627.d b/gcc/testsuite/gdc.test/fail_compilation/issue20627.d
new file mode 100644
index 0000000..ff08c6a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue20627.d
@@ -0,0 +1,67 @@
+/**
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/issue20627.d(38): Deprecation: `shared static` constructor can only be of D linkage
+fail_compilation/issue20627.d(39): Deprecation: `shared static` destructor can only be of D linkage
+fail_compilation/issue20627.d(40): Deprecation: `static` constructor can only be of D linkage
+fail_compilation/issue20627.d(41): Deprecation: `static` destructor can only be of D linkage
+fail_compilation/issue20627.d(55): Deprecation: `shared static` constructor can only be of D linkage
+fail_compilation/issue20627.d(56): Deprecation: `shared static` destructor can only be of D linkage
+fail_compilation/issue20627.d(57): Deprecation: `static` constructor can only be of D linkage
+fail_compilation/issue20627.d(58): Deprecation: `static` destructor can only be of D linkage
+fail_compilation/issue20627.d(63): Deprecation: `shared static` constructor can only be of D linkage
+fail_compilation/issue20627.d(64): Deprecation: `shared static` destructor can only be of D linkage
+fail_compilation/issue20627.d(65): Deprecation: `static` constructor can only be of D linkage
+fail_compilation/issue20627.d(66): Deprecation: `static` destructor can only be of D linkage
+---
+*/
+
+// OK, default linkage
+shared static this () {}
+shared static ~this () {}
+static this () {}
+static ~this () {}
+
+// Still okay
+extern(D)
+{
+ shared static this () {}
+ shared static ~this () {}
+ static this () {}
+ static ~this () {}
+}
+
+// No!
+extern(C)
+{
+ shared static this () {}
+ shared static ~this () {}
+ static this () {}
+ static ~this () {}
+}
+
+// Disabled because platform specific
+version (none) extern(Objective-C)
+{
+ shared static this () {}
+ shared static ~this () {}
+ static this () {}
+ static ~this () {}
+}
+
+extern(C++)
+{
+ shared static this () {}
+ shared static ~this () {}
+ static this () {}
+ static ~this () {}
+}
+
+extern(System)
+{
+ shared static this () {}
+ shared static ~this () {}
+ static this () {}
+ static ~this () {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue20704.d b/gcc/testsuite/gdc.test/fail_compilation/issue20704.d
new file mode 100644
index 0000000..1e1f2e6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue20704.d
@@ -0,0 +1,39 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/issue20704.d(17): Error: cannot modify constant `0`
+fail_compilation/issue20704.d(28): Error: template instance `issue20704.f2!int` error instantiating
+fail_compilation/issue20704.d(19): Error: cannot modify constant `0`
+fail_compilation/issue20704.d(30): Error: template instance `issue20704.f4!int` error instantiating
+fail_compilation/issue20704.d(17): Error: `S(0)` is not an lvalue and cannot be modified
+fail_compilation/issue20704.d(36): Error: template instance `issue20704.f2!(S)` error instantiating
+fail_compilation/issue20704.d(17): Error: `null` is not an lvalue and cannot be modified
+fail_compilation/issue20704.d(38): Error: template instance `issue20704.f2!(C)` error instantiating
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=20704
+
+void f1(T)(const auto ref T arg = T.init) {}
+void f2(T)(const ref T arg = T.init) {}
+void f3(T)(const auto ref T arg = 0) {}
+void f4(T)(const ref T arg = 0) {}
+
+struct S { int _; }
+class C { int _; }
+
+void main ()
+{
+ int i;
+ f1!int(i);
+ f2!int(i);
+ f3!int(i);
+ f4!int(i);
+ f1!int();
+ f2!int();
+ f3!int();
+ f4!int();
+ f1!S();
+ f2!S();
+ f1!C();
+ f2!C();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue21203.d b/gcc/testsuite/gdc.test/fail_compilation/issue21203.d
new file mode 100644
index 0000000..7679d67
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue21203.d
@@ -0,0 +1,17 @@
+// Ideally this should work, at least give a nice error messae
+/**
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/issue21203.d(12): Error: pragma `mangle` cannot apply to a template declaration
+fail_compilation/issue21203.d(12): use `template Class(Args...){ pragma(mangle, "other_name") class Class {} }`
+---
+*/
+
+extern(C++)
+pragma(mangle,"gdkfjgh")
+class F(T)
+{
+
+}
+void use(F!int a) {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue21295.d b/gcc/testsuite/gdc.test/fail_compilation/issue21295.d
index 9916e9b..24d282c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/issue21295.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue21295.d
@@ -1,8 +1,7 @@
/*
-REQUIRED_ARGS: -de
TEST_OUTPUT:
---
-fail_compilation/issue21295.d(9): Deprecation: imports.issue21295ast_node.Visitor is not visible from module issue21295
+fail_compilation/issue21295.d(8): Error: undefined identifier `Visitor`
---
*/
import imports.issue21295ast_node;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue21378.d b/gcc/testsuite/gdc.test/fail_compilation/issue21378.d
new file mode 100644
index 0000000..22c60a3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue21378.d
@@ -0,0 +1,16 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/issue21378.d(13): Error: function `issue21378.fn` circular dependency. Functions cannot be interpreted while being compiled
+fail_compilation/issue21378.d(12): called from here: `fn()`
+fail_compilation/issue21378.d(12): Error: pragma `inline` pragma(`inline`, `true` or `false`) expected, not `fn()`
+---
+*/
+
+// Cannot call the same function linked to the pragma
+// Really hard to fix this limitation in the implementation
+pragma(inline, fn())
+int fn()
+{
+ return 1;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue21685_main.d b/gcc/testsuite/gdc.test/fail_compilation/issue21685_main.d
new file mode 100644
index 0000000..c6e29c3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue21685_main.d
@@ -0,0 +1,12 @@
+/* REQUIRED_ARGS: -preview=dip1000 -Ifail_compilation/imports
+TEST_OUTPUT:
+---
+fail_compilation/issue21685_main.d(11): Error: class `issue21685.E` constructor `this` is not accessible
+---
+*/
+import issue21685;
+
+void main()
+{
+ new E;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue21936.d b/gcc/testsuite/gdc.test/fail_compilation/issue21936.d
new file mode 100644
index 0000000..a37aa04
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue21936.d
@@ -0,0 +1,32 @@
+/* REQUIRED_ARGS: -preview=dip1000 -Ifail_compilation/imports
+TEST_OUTPUT:
+---
+fail_compilation/issue21936.d(15): Error: struct `issue21936s.S` variable `field` is not accessible from `@safe` code
+fail_compilation/issue21936.d(15): Error: struct `issue21936s.S` variable `field` is not accessible from `@safe` code
+fail_compilation/issue21936.d(11): Error: template instance `issue21936.constructImplicit!(S)` error instantiating
+fail_compilation/issue21936.d(7): instantiated from here: `registerConstructors!(S)`
+fail_compilation/issue21936.d(21): instantiated from here: `registerType!(S)`
+---
+*/
+#line 2
+module issue21936;
+import issue21936s;
+struct Handlers {
+ void registerType(T)()
+ {
+ registerConstructors!T;
+ }
+ void registerConstructors(T)()
+ {
+ constructImplicit!T;
+ }
+}
+
+auto constructImplicit(T)(typeof(T.init.tupleof) x = T.init.tupleof)
+{
+}
+
+void registerHandlersDateTime(Handlers handlers)
+{
+ handlers.registerType!(S);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue3827.d b/gcc/testsuite/gdc.test/fail_compilation/issue3827.d
index 76d90ed..d17cee8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/issue3827.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue3827.d
@@ -2,8 +2,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/issue3827.d(12): Deprecation: Implicit string concatenation is deprecated, use "Hello" ~ "World" instead
-fail_compilation/issue3827.d(13): Deprecation: Implicit string concatenation is deprecated, use "A" ~ "B" instead
+fail_compilation/issue3827.d(14): Error: Implicit string concatenation is error-prone and disallowed in D
+fail_compilation/issue3827.d(14): Use the explicit syntax instead (concatenating literals is `@nogc`): "Hello" ~ "World"
+fail_compilation/issue3827.d(15): Error: Implicit string concatenation is error-prone and disallowed in D
+fail_compilation/issue3827.d(15): Use the explicit syntax instead (concatenating literals is `@nogc`): "A" ~ "B"
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer1.d b/gcc/testsuite/gdc.test/fail_compilation/lexer1.d
index 31246ce..088e897 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/lexer1.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/lexer1.d
@@ -1,6 +1,7 @@
/*
TEST_OUTPUT:
---
+fail_compilation/lexer1.d(30): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"01 02 03"w` instead.
fail_compilation/lexer1.d(30): Error: declaration expected, not `x"01 02 03"w`
fail_compilation/lexer1.d(31): Error: declaration expected, not `2147483649U`
fail_compilation/lexer1.d(32): Error: declaration expected, not `0.1`
@@ -15,7 +16,7 @@ fail_compilation/lexer1.d(40): Error: declaration expected, not `65536U`
fail_compilation/lexer1.d(41): Error: declaration expected, not `"ab\\c\"\u1234a\U00011100a"d`
fail_compilation/lexer1.d(43): Error: declaration expected, not `module`
fail_compilation/lexer1.d(45): Error: escape hex sequence has 1 hex digits instead of 2
-fail_compilation/lexer1.d(46): Error: undefined escape hex sequence \G
+fail_compilation/lexer1.d(46): Error: undefined escape hex sequence \xG
fail_compilation/lexer1.d(47): Error: unnamed character entity &unnamedentity;
fail_compilation/lexer1.d(48): Error: unterminated named entity &1;
fail_compilation/lexer1.d(49): Error: unterminated named entity &*;
@@ -26,7 +27,6 @@ fail_compilation/lexer1.d(52): Error: escape octal sequence \400 is larger than
*/
// https://dlang.dawg.eu/coverage/src/lexer.c.gcov.html
-
x"01 02 03"w;
0x80000001;
0.1;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer2.d b/gcc/testsuite/gdc.test/fail_compilation/lexer2.d
index d574b07..2386da5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/lexer2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/lexer2.d
@@ -1,11 +1,13 @@
/*
TEST_OUTPUT:
---
-fail_compilation/lexer2.d(14): Error: odd number (3) of hex characters in hex string
-fail_compilation/lexer2.d(15): Error: non-hex character 'G' in hex string
-fail_compilation/lexer2.d(16): Error: heredoc rest of line should be blank
-fail_compilation/lexer2.d(18): Error: unterminated delimited string constant starting at fail_compilation/lexer2.d(18)
-fail_compilation/lexer2.d(20): Error: semicolon expected following auto declaration, not `EOF`
+fail_compilation/lexer2.d(16): Error: odd number (3) of hex characters in hex string
+fail_compilation/lexer2.d(16): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"123"` instead.
+fail_compilation/lexer2.d(17): Error: non-hex character 'G' in hex string
+fail_compilation/lexer2.d(17): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"123G"` instead.
+fail_compilation/lexer2.d(18): Error: heredoc rest of line should be blank
+fail_compilation/lexer2.d(20): Error: unterminated delimited string constant starting at fail_compilation/lexer2.d(20)
+fail_compilation/lexer2.d(22): Error: semicolon expected following auto declaration, not `End of File`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer3.d b/gcc/testsuite/gdc.test/fail_compilation/lexer3.d
index f2bcda4..dc6ad64 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/lexer3.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/lexer3.d
@@ -2,7 +2,7 @@
TEST_OUTPUT:
---
fail_compilation/lexer3.d(9): Error: unterminated token string constant starting at fail_compilation/lexer3.d(9)
-fail_compilation/lexer3.d(10): Error: semicolon expected following auto declaration, not `EOF`
+fail_compilation/lexer3.d(10): Error: semicolon expected following auto declaration, not `End of File`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer4.d b/gcc/testsuite/gdc.test/fail_compilation/lexer4.d
index 374f69d..ecc7208 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/lexer4.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/lexer4.d
@@ -4,10 +4,10 @@ TEST_OUTPUT:
fail_compilation/lexer4.d(22): Error: unterminated character constant
fail_compilation/lexer4.d(24): Error: unterminated character constant
fail_compilation/lexer4.d(25): Error: unterminated character constant
-fail_compilation/lexer4.d(26): Error: binary digit expected
-fail_compilation/lexer4.d(27): Error: radix 8 digit expected, not `8`
-fail_compilation/lexer4.d(27): Error: octal literals `0130` are no longer supported, use `std.conv.octal!130` instead
-fail_compilation/lexer4.d(28): Error: radix 10 digit expected, not `a`
+fail_compilation/lexer4.d(26): Error: binary digit expected, not `2`
+fail_compilation/lexer4.d(27): Error: octal digit expected, not `8`
+fail_compilation/lexer4.d(27): Error: octal literals larger than 7 are no longer supported
+fail_compilation/lexer4.d(28): Error: decimal digit expected, not `a`
fail_compilation/lexer4.d(29): Error: unrecognized token
fail_compilation/lexer4.d(30): Error: exponent required for hex float
fail_compilation/lexer4.d(31): Error: lower case integer suffix 'l' is not allowed. Please use 'L' instead
diff --git a/gcc/testsuite/gdc.test/fail_compilation/lookup.d b/gcc/testsuite/gdc.test/fail_compilation/lookup.d
index aedb44e..fe752f2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/lookup.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/lookup.d
@@ -1,10 +1,11 @@
/*
+EXTRA_FILES: imports/imp1.d imports/imp2.d
TEST_OUTPUT:
---
-fail_compilation/lookup.d(23): Error: no property `X` for type `lookup.B`, did you mean `imports.imp2.X`?
-fail_compilation/lookup.d(23): while evaluating: `static assert((B).X == 0)`
-+fail_compilation/lookup.d(24): Error: no property `Y` for type `lookup.B`, did you mean `imports.imp2.Y`?
-fail_compilation/lookup.d(24): while evaluating: `static assert((B).Y == 2)`
+fail_compilation/lookup.d(24): Error: no property `X` for type `lookup.B`, did you mean `imports.imp2.X`?
+fail_compilation/lookup.d(24): while evaluating: `static assert((B).X == 0)`
+fail_compilation/lookup.d(25): Error: no property `Y` for type `lookup.B`, did you mean `imports.imp2.Y`?
+fail_compilation/lookup.d(25): while evaluating: `static assert((B).Y == 2)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/mangle1.d b/gcc/testsuite/gdc.test/fail_compilation/mangle1.d
index bc2bc3d..a97a55b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/mangle1.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/mangle1.d
@@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/mangle1.d(8): Error: pragma mangle can only apply to a single declaration
+fail_compilation/mangle1.d(8): Error: pragma `mangle` can only apply to a single declaration
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/mangle2.d b/gcc/testsuite/gdc.test/fail_compilation/mangle2.d
index e68c92a..415e719 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/mangle2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/mangle2.d
@@ -1,18 +1,18 @@
/*
TEST_OUTPUT:
---
-fail_compilation/mangle2.d(20): Error: pragma mangle char 0x20 not allowed in mangled name
-fail_compilation/mangle2.d(21): Error: pragma mangle char 0x20 not allowed in mangled name
-fail_compilation/mangle2.d(24): Error: pragma mangle char 0x0a not allowed in mangled name
-fail_compilation/mangle2.d(25): Error: pragma mangle char 0x0a not allowed in mangled name
-fail_compilation/mangle2.d(28): Error: pragma mangle char 0x07 not allowed in mangled name
-fail_compilation/mangle2.d(29): Error: pragma mangle char 0x07 not allowed in mangled name
-fail_compilation/mangle2.d(32): Error: pragma mangle char 0x01 not allowed in mangled name
-fail_compilation/mangle2.d(33): Error: pragma mangle char 0x01 not allowed in mangled name
-fail_compilation/mangle2.d(36): Error: pragma mangle char 0x00 not allowed in mangled name
-fail_compilation/mangle2.d(37): Error: pragma mangle char 0x00 not allowed in mangled name
-fail_compilation/mangle2.d(40): Error: pragma mangle Outside Unicode code space
-fail_compilation/mangle2.d(41): Error: pragma mangle Outside Unicode code space
+fail_compilation/mangle2.d(20): Error: pragma `mangle` char 0x20 not allowed in mangled name
+fail_compilation/mangle2.d(21): Error: pragma `mangle` char 0x20 not allowed in mangled name
+fail_compilation/mangle2.d(24): Error: pragma `mangle` char 0x0a not allowed in mangled name
+fail_compilation/mangle2.d(25): Error: pragma `mangle` char 0x0a not allowed in mangled name
+fail_compilation/mangle2.d(28): Error: pragma `mangle` char 0x07 not allowed in mangled name
+fail_compilation/mangle2.d(29): Error: pragma `mangle` char 0x07 not allowed in mangled name
+fail_compilation/mangle2.d(32): Error: pragma `mangle` char 0x01 not allowed in mangled name
+fail_compilation/mangle2.d(33): Error: pragma `mangle` char 0x01 not allowed in mangled name
+fail_compilation/mangle2.d(36): Error: pragma `mangle` char 0x00 not allowed in mangled name
+fail_compilation/mangle2.d(37): Error: pragma `mangle` char 0x00 not allowed in mangled name
+fail_compilation/mangle2.d(40): Error: pragma `mangle` Outside Unicode code space
+fail_compilation/mangle2.d(41): Error: pragma `mangle` Outside Unicode code space
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/misc1.d b/gcc/testsuite/gdc.test/fail_compilation/misc1.d
new file mode 100644
index 0000000..9a319eb
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/misc1.d
@@ -0,0 +1,20 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/misc1.d(108): Error: `5` has no effect
+fail_compilation/misc1.d(109): Error: `1 + 2` has no effect
+---
+*/
+
+#line 100
+
+/***************************************************/
+//https://issues.dlang.org/show_bug.cgi?id=12490
+
+void hasSideEffect12490(){}
+
+void issue12490()
+{
+ 5, hasSideEffect12490();
+ 1 + 2, hasSideEffect12490();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d
new file mode 100644
index 0000000..df169e19
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d
@@ -0,0 +1,51 @@
+/*
+REQUIRED_ARGS: -verrors=0
+TEST_OUTPUT:
+---
+fail_compilation/misc_parser_err_cov1.d(29): Error: basic type expected, not `)`
+fail_compilation/misc_parser_err_cov1.d(30): Error: basic type expected, not `)`
+fail_compilation/misc_parser_err_cov1.d(31): Error: `__traits(identifier, args...)` expected
+fail_compilation/misc_parser_err_cov1.d(31): Error: semicolon expected following auto declaration, not `o`
+fail_compilation/misc_parser_err_cov1.d(31): Error: expression expected, not `)`
+fail_compilation/misc_parser_err_cov1.d(32): Error: `type identifier : specialization` expected following `is`
+fail_compilation/misc_parser_err_cov1.d(33): Error: semicolon expected following auto declaration, not `auto`
+fail_compilation/misc_parser_err_cov1.d(33): Error: found `+` when expecting `(` following `mixin`
+fail_compilation/misc_parser_err_cov1.d(34): Error: cannot create a `char[float]` with `new`
+fail_compilation/misc_parser_err_cov1.d(35): Error: `key:value` expected for associative array literal
+fail_compilation/misc_parser_err_cov1.d(36): Error: basic type expected, not `;`
+fail_compilation/misc_parser_err_cov1.d(36): Error: `{ members }` expected for anonymous class
+fail_compilation/misc_parser_err_cov1.d(38): Error: template argument expected following `!`
+fail_compilation/misc_parser_err_cov1.d(38): Error: found `if` when expecting `)`
+fail_compilation/misc_parser_err_cov1.d(38): Error: found `)` instead of statement
+fail_compilation/misc_parser_err_cov1.d(39): Error: identifier expected following `(type)`.
+fail_compilation/misc_parser_err_cov1.d(39): Error: expression expected, not `;`
+fail_compilation/misc_parser_err_cov1.d(40): Error: semicolon expected following auto declaration, not `auto`
+fail_compilation/misc_parser_err_cov1.d(40): Error: identifier or `new` expected following `.`, not `+`
+fail_compilation/misc_parser_err_cov1.d(41): Error: declaration expected, not `(`
+fail_compilation/misc_parser_err_cov1.d(42): Error: unrecognized declaration
+---
+*/
+module misc_parser_err_cov1;
+
+
+//https://issues.dlang.org/show_bug.cgi?id=19995
+#line 29
+void foo(in);
+void bar(int, const @tation);
+
+void main()
+{
+ // cover errors from line 7930 to EOF
+ #line 31
+ auto tt = __traits(<o<);
+ auto b = is ;
+ auto mx1 = mixin +);
+ auto aa1 = new char[float];
+ aa += [key:value, key];
+ auto anon1 = new class;
+ auto anon2 = new class {};
+ if (parseShift !if){}
+ auto unaryExParseError = immutable(int).+;
+ auto postFixParseError = int.max.+;
+ (int).+;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/mixin.d b/gcc/testsuite/gdc.test/fail_compilation/mixin.d
new file mode 100644
index 0000000..1db1206
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/mixin.d
@@ -0,0 +1,25 @@
+// REQUIRED_ARGS: -mixin=${RESULTS_DIR}/fail_compilation/mixin_test.mixin
+/*
+TEST_OUTPUT:
+---
+{{RESULTS_DIR}}/fail_compilation/mixin_test.mixin(7): Error: undefined identifier `b`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=1870
+// https://issues.dlang.org/show_bug.cgi?id=12790
+string get()
+{
+ return
+ q{int x;
+ int y;
+
+
+
+ int z = x + b;};
+}
+
+void main()
+{
+ mixin(get());
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/mixin_gc.d b/gcc/testsuite/gdc.test/fail_compilation/mixin_gc.d
new file mode 100644
index 0000000..6c2d8de
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/mixin_gc.d
@@ -0,0 +1,25 @@
+// REQUIRED_ARGS: -mixin=${RESULTS_DIR}/fail_compilation/mixin_test.mixin -lowmem
+/*
+TEST_OUTPUT:
+---
+{{RESULTS_DIR}}/fail_compilation/mixin_test.mixin(7): Error: undefined identifier `b`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=1870
+// https://issues.dlang.org/show_bug.cgi?id=12790
+string get()
+{
+ return
+ q{int x;
+ int y;
+
+
+
+ int z = x + b;};
+}
+
+void main()
+{
+ mixin(get());
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/nestedtempl0.d b/gcc/testsuite/gdc.test/fail_compilation/nestedtempl0.d
new file mode 100644
index 0000000..d323c34
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/nestedtempl0.d
@@ -0,0 +1,35 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/nestedtempl0.d(18): Error: class `nestedtempl0.K.D!(1, B!(a)).D` doesn't need a frame pointer, but super class `B` needs the frame pointer of `main`
+fail_compilation/nestedtempl0.d(28): Error: template instance `nestedtempl0.K.D!(1, B!(a))` error instantiating
+fail_compilation/nestedtempl0.d(18): Error: class `nestedtempl0.main.fun.D!(b, B!(a)).D` needs the frame pointer of `fun`, but super class `B` needs the frame pointer of `main`
+fail_compilation/nestedtempl0.d(33): Error: template instance `nestedtempl0.main.fun.D!(b, B!(a))` error instantiating
+---
+*/
+
+class K
+{
+ class B(alias a)
+ {
+
+ }
+
+ class D(alias a, T) : T
+ {
+
+ }
+}
+
+void main()
+{
+ int a;
+ auto k = new K;
+ auto d = k.new K.D!(1, K.B!a);
+
+ auto fun()
+ {
+ int b;
+ auto o = k.new K.D!(b, K.B!a);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/nestedtempl1.d b/gcc/testsuite/gdc.test/fail_compilation/nestedtempl1.d
new file mode 100644
index 0000000..c34d70b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/nestedtempl1.d
@@ -0,0 +1,27 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/nestedtempl1.d(14): Deprecation: function `nestedtempl1.main.bar!(a).bar` function requires a dual-context, which is deprecated
+fail_compilation/nestedtempl1.d(26): instantiated from here: `bar!(a)`
+fail_compilation/nestedtempl1.d(26): Error: modify `inout` to `mutable` is not allowed inside `inout` function
+---
+*/
+
+auto foo(ref inout(int) x)
+{
+ struct S
+ {
+ ref inout(int) bar(alias a)() inout
+ {
+ return x;
+ }
+ }
+ return S();
+}
+
+void main()
+{
+ int a;
+ auto o = foo(a);
+ o.bar!a() = 1; // bad!
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/nestedtempl2.d b/gcc/testsuite/gdc.test/fail_compilation/nestedtempl2.d
new file mode 100644
index 0000000..afc8a29
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/nestedtempl2.d
@@ -0,0 +1,38 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/nestedtempl2.d(22): Deprecation: function `nestedtempl2.B.func!(n).func` function requires a dual-context, which is deprecated
+fail_compilation/nestedtempl2.d(34): instantiated from here: `func!(n)`
+fail_compilation/nestedtempl2.d(34): Error: `this` is only defined in non-static member functions, not `test`
+fail_compilation/nestedtempl2.d(34): Error: need `this` of type `B` to call function `func`
+fail_compilation/nestedtempl2.d(35): Error: `this` is only defined in non-static member functions, not `test`
+fail_compilation/nestedtempl2.d(35): Error: need `this` of type `B` to make delegate from function `func`
+fail_compilation/nestedtempl2.d(37): Error: `this` is only defined in non-static member functions, not `test`
+fail_compilation/nestedtempl2.d(37): Error: need `this` of type `B` needed to `new` nested class `N`
+---
+*/
+
+class B
+{
+ int n;
+}
+
+void test()
+{
+ auto func(alias a)()
+ {
+ return a;
+ }
+
+ class N(alias a)
+ {
+ }
+
+ auto b = new B();
+ b.n = 1;
+
+ func!(b.n)();
+ auto dg = &func!(b.n);
+
+ new N!(b.n)();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/nestedtempl3.d b/gcc/testsuite/gdc.test/fail_compilation/nestedtempl3.d
new file mode 100644
index 0000000..a95bda0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/nestedtempl3.d
@@ -0,0 +1,24 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/nestedtempl3.d(23): Error: cannot access frame pointer of `nestedtempl3.test.S!(i).S`
+---
+*/
+
+void test()
+{
+ int i;
+
+ auto f0()
+ {
+ int j = 10;
+ struct S(alias a)
+ {
+ auto get() { return j; }
+ }
+ return S!i();
+ }
+
+ alias S = typeof(f0());
+ auto s = S();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d b/gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d
new file mode 100644
index 0000000..29481e3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/no_Throwable.d
@@ -0,0 +1,26 @@
+/*
+DFLAGS:
+REQUIRED_ARGS: -c
+EXTRA_SOURCES: extra-files/minimal/object.d
+TEST_OUTPUT:
+---
+fail_compilation/no_Throwable.d(14): Error: Cannot use `throw` statements because `object.Throwable` was not declared
+fail_compilation/no_Throwable.d(19): Error: Cannot use try-catch statements because `object.Throwable` was not declared
+---
+*/
+
+void test()
+{
+ throw new Exception("msg");
+}
+
+void test2()
+{
+ try
+ {
+ test();
+ }
+ catch (Exception e)
+ {
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/no_TypeInfo.d b/gcc/testsuite/gdc.test/fail_compilation/no_TypeInfo.d
new file mode 100644
index 0000000..328f9b9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/no_TypeInfo.d
@@ -0,0 +1,16 @@
+/*
+DFLAGS:
+REQUIRED_ARGS: -c
+EXTRA_SOURCES: extra-files/minimal/object.d
+TEST_OUTPUT:
+---
+fail_compilation/no_TypeInfo.d(14): Error: `object.TypeInfo` could not be found, but is implicitly used
+---
+*/
+
+void test()
+{
+ int i;
+ auto ti = typeid(i);
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/nogc1.d b/gcc/testsuite/gdc.test/fail_compilation/nogc1.d
index 8a66ac3..a862e52 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/nogc1.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/nogc1.d
@@ -1,25 +1,21 @@
// REQUIRED_ARGS: -o-
-// PERMUTE_ARGS:
/***************** NewExp *******************/
struct S1 { }
struct S2 { this(int); }
struct S3 { this(int) @nogc; }
-struct S4 { new(size_t); }
-struct S5 { @nogc new(size_t); }
/*
TEST_OUTPUT:
---
-fail_compilation/nogc1.d(27): Error: cannot use 'new' in @nogc function 'nogc1.testNew'
-fail_compilation/nogc1.d(29): Error: cannot use 'new' in @nogc function 'nogc1.testNew'
-fail_compilation/nogc1.d(30): Error: cannot use 'new' in @nogc function 'nogc1.testNew'
-fail_compilation/nogc1.d(32): Error: cannot use 'new' in @nogc function 'nogc1.testNew'
-fail_compilation/nogc1.d(33): Error: @nogc function 'nogc1.testNew' cannot call non-@nogc constructor 'nogc1.S2.this'
-fail_compilation/nogc1.d(34): Error: cannot use 'new' in @nogc function 'nogc1.testNew'
-fail_compilation/nogc1.d(35): Error: @nogc function 'nogc1.testNew' cannot call non-@nogc allocator 'nogc1.S4.new'
-fail_compilation/nogc1.d(38): Error: cannot use 'new' in @nogc function 'nogc1.testNew'
+fail_compilation/nogc1.d(23): Error: cannot use `new` in `@nogc` function `nogc1.testNew`
+fail_compilation/nogc1.d(25): Error: cannot use `new` in `@nogc` function `nogc1.testNew`
+fail_compilation/nogc1.d(26): Error: cannot use `new` in `@nogc` function `nogc1.testNew`
+fail_compilation/nogc1.d(28): Error: cannot use `new` in `@nogc` function `nogc1.testNew`
+fail_compilation/nogc1.d(29): Error: `@nogc` function `nogc1.testNew` cannot call non-@nogc constructor `nogc1.S2.this`
+fail_compilation/nogc1.d(30): Error: cannot use `new` in `@nogc` function `nogc1.testNew`
+fail_compilation/nogc1.d(32): Error: cannot use `new` in `@nogc` function `nogc1.testNew`
---
*/
@nogc void testNew()
@@ -32,8 +28,6 @@ fail_compilation/nogc1.d(38): Error: cannot use 'new' in @nogc function 'nogc1.t
S1* ps1 = new S1();
S2* ps2 = new S2(1);
S3* ps3 = new S3(1);
- S4* ps4 = new S4;
- S5* ps5 = new S5; // no error
Object o1 = new Object();
}
@@ -41,13 +35,12 @@ fail_compilation/nogc1.d(38): Error: cannot use 'new' in @nogc function 'nogc1.t
/*
TEST_OUTPUT:
---
-fail_compilation/nogc1.d(55): Error: cannot use 'new' in @nogc function 'nogc1.testNewScope'
-fail_compilation/nogc1.d(57): Error: cannot use 'new' in @nogc function 'nogc1.testNewScope'
-fail_compilation/nogc1.d(58): Error: cannot use 'new' in @nogc function 'nogc1.testNewScope'
-fail_compilation/nogc1.d(60): Error: cannot use 'new' in @nogc function 'nogc1.testNewScope'
-fail_compilation/nogc1.d(61): Error: @nogc function 'nogc1.testNewScope' cannot call non-@nogc constructor 'nogc1.S2.this'
-fail_compilation/nogc1.d(62): Error: cannot use 'new' in @nogc function 'nogc1.testNewScope'
-fail_compilation/nogc1.d(63): Error: @nogc function 'nogc1.testNewScope' cannot call non-@nogc allocator 'nogc1.S4.new'
+fail_compilation/nogc1.d(48): Error: cannot use `new` in `@nogc` function `nogc1.testNewScope`
+fail_compilation/nogc1.d(50): Error: cannot use `new` in `@nogc` function `nogc1.testNewScope`
+fail_compilation/nogc1.d(51): Error: cannot use `new` in `@nogc` function `nogc1.testNewScope`
+fail_compilation/nogc1.d(53): Error: cannot use `new` in `@nogc` function `nogc1.testNewScope`
+fail_compilation/nogc1.d(54): Error: `@nogc` function `nogc1.testNewScope` cannot call non-@nogc constructor `nogc1.S2.this`
+fail_compilation/nogc1.d(55): Error: cannot use `new` in `@nogc` function `nogc1.testNewScope`
---
*/
@nogc void testNewScope()
@@ -60,8 +53,6 @@ fail_compilation/nogc1.d(63): Error: @nogc function 'nogc1.testNewScope' cannot
scope S1* ps1 = new S1();
scope S2* ps2 = new S2(1);
scope S3* ps3 = new S3(1);
- scope S4* ps4 = new S4;
- scope S5* ps5 = new S5; // no error
scope Object o1 = new Object(); // no error
scope o2 = new Object(); // no error
@@ -72,9 +63,12 @@ fail_compilation/nogc1.d(63): Error: @nogc function 'nogc1.testNewScope' cannot
/*
TEST_OUTPUT:
---
-fail_compilation/nogc1.d(82): Error: cannot use 'delete' in @nogc function 'nogc1.testDelete'
-fail_compilation/nogc1.d(83): Error: cannot use 'delete' in @nogc function 'nogc1.testDelete'
-fail_compilation/nogc1.d(84): Error: cannot use 'delete' in @nogc function 'nogc1.testDelete'
+fail_compilation/nogc1.d(76): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/nogc1.d(76): Error: cannot use `delete` in `@nogc` function `nogc1.testDelete`
+fail_compilation/nogc1.d(77): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/nogc1.d(77): Error: cannot use `delete` in `@nogc` function `nogc1.testDelete`
+fail_compilation/nogc1.d(78): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/nogc1.d(78): Error: cannot use `delete` in `@nogc` function `nogc1.testDelete`
---
*/
@nogc void testDelete(int* p, Object o, S1* s)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/nogc2.d b/gcc/testsuite/gdc.test/fail_compilation/nogc2.d
index 1af413a..2a3ea8a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/nogc2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/nogc2.d
@@ -1,19 +1,18 @@
// REQUIRED_ARGS: -o-
-// PERMUTE_ARGS:
/***************** CatExp *******************/
/*
TEST_OUTPUT:
---
-fail_compilation/nogc2.d(21): Error: cannot use operator ~ in @nogc function 'nogc2.testCat'
-fail_compilation/nogc2.d(22): Error: cannot use operator ~ in @nogc function 'nogc2.testCat'
-fail_compilation/nogc2.d(23): Error: cannot use operator ~ in @nogc function 'nogc2.testCat'
-fail_compilation/nogc2.d(25): Error: cannot use operator ~ in @nogc function 'nogc2.testCat'
-fail_compilation/nogc2.d(26): Error: cannot use operator ~ in @nogc function 'nogc2.testCat'
-fail_compilation/nogc2.d(27): Error: cannot use operator ~ in @nogc function 'nogc2.testCat'
-fail_compilation/nogc2.d(28): Error: cannot use operator ~ in @nogc function 'nogc2.testCat'
-fail_compilation/nogc2.d(29): Error: cannot use operator ~ in @nogc function 'nogc2.testCat'
+fail_compilation/nogc2.d(20): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat`
+fail_compilation/nogc2.d(21): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat`
+fail_compilation/nogc2.d(22): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat`
+fail_compilation/nogc2.d(24): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat`
+fail_compilation/nogc2.d(25): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat`
+fail_compilation/nogc2.d(26): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat`
+fail_compilation/nogc2.d(27): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat`
+fail_compilation/nogc2.d(28): Error: cannot use operator `~` in `@nogc` function `nogc2.testCat`
---
*/
@nogc void testCat(int[] a, string s)
@@ -38,9 +37,9 @@ fail_compilation/nogc2.d(29): Error: cannot use operator ~ in @nogc function 'no
/*
TEST_OUTPUT:
---
-fail_compilation/nogc2.d(48): Error: cannot use operator ~= in @nogc function 'nogc2.testCatAssign'
-fail_compilation/nogc2.d(50): Error: cannot use operator ~= in @nogc function 'nogc2.testCatAssign'
-fail_compilation/nogc2.d(51): Error: cannot use operator ~= in @nogc function 'nogc2.testCatAssign'
+fail_compilation/nogc2.d(47): Error: cannot use operator `~=` in `@nogc` function `nogc2.testCatAssign`
+fail_compilation/nogc2.d(49): Error: cannot use operator `~=` in `@nogc` function `nogc2.testCatAssign`
+fail_compilation/nogc2.d(50): Error: cannot use operator `~=` in `@nogc` function `nogc2.testCatAssign`
---
*/
@nogc void testCatAssign(int[] a, string s)
@@ -58,8 +57,8 @@ fail_compilation/nogc2.d(51): Error: cannot use operator ~= in @nogc function 'n
/*
TEST_OUTPUT:
---
-fail_compilation/nogc2.d(70): Error: array literal in @nogc function 'nogc2.testArray' may cause GC allocation
-fail_compilation/nogc2.d(71): Error: array literal in @nogc function 'nogc2.testArray' may cause GC allocation
+fail_compilation/nogc2.d(69): Error: array literal in `@nogc` function `nogc2.testArray` may cause a GC allocation
+fail_compilation/nogc2.d(70): Error: array literal in `@nogc` function `nogc2.testArray` may cause a GC allocation
---
*/
@nogc void testArray()
@@ -76,8 +75,8 @@ fail_compilation/nogc2.d(71): Error: array literal in @nogc function 'nogc2.test
/*
TEST_OUTPUT:
---
-fail_compilation/nogc2.d(87): Error: associative array literal in @nogc function 'nogc2.testAssocArray' may cause GC allocation
-fail_compilation/nogc2.d(88): Error: associative array literal in @nogc function 'nogc2.testAssocArray' may cause GC allocation
+fail_compilation/nogc2.d(86): Error: associative array literal in `@nogc` function `nogc2.testAssocArray` may cause a GC allocation
+fail_compilation/nogc2.d(87): Error: associative array literal in `@nogc` function `nogc2.testAssocArray` may cause a GC allocation
---
*/
@nogc void testAssocArray()
@@ -93,8 +92,8 @@ fail_compilation/nogc2.d(88): Error: associative array literal in @nogc function
/*
TEST_OUTPUT:
---
-fail_compilation/nogc2.d(102): Error: indexing an associative array in @nogc function 'nogc2.testIndex' may cause GC allocation
-fail_compilation/nogc2.d(103): Error: indexing an associative array in @nogc function 'nogc2.testIndex' may cause GC allocation
+fail_compilation/nogc2.d(101): Error: indexing an associative array in `@nogc` function `nogc2.testIndex` may cause a GC allocation
+fail_compilation/nogc2.d(102): Error: indexing an associative array in `@nogc` function `nogc2.testIndex` may cause a GC allocation
---
*/
@nogc void testIndex(int[int] aa)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/nogc3.d b/gcc/testsuite/gdc.test/fail_compilation/nogc3.d
index 7c9e6d2..fdc3cde 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/nogc3.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/nogc3.d
@@ -1,14 +1,13 @@
// REQUIRED_ARGS: -o-
-// PERMUTE_ARGS:
/***************** AssignExp *******************/
/*
TEST_OUTPUT:
---
-fail_compilation/nogc3.d(16): Error: setting 'length' in @nogc function 'nogc3.testArrayLength' may cause GC allocation
-fail_compilation/nogc3.d(17): Error: setting 'length' in @nogc function 'nogc3.testArrayLength' may cause GC allocation
-fail_compilation/nogc3.d(18): Error: setting 'length' in @nogc function 'nogc3.testArrayLength' may cause GC allocation
+fail_compilation/nogc3.d(15): Error: setting `length` in `@nogc` function `nogc3.testArrayLength` may cause a GC allocation
+fail_compilation/nogc3.d(16): Error: setting `length` in `@nogc` function `nogc3.testArrayLength` may cause a GC allocation
+fail_compilation/nogc3.d(17): Error: setting `length` in `@nogc` function `nogc3.testArrayLength` may cause a GC allocation
---
*/
@nogc void testArrayLength(int[] a)
@@ -25,8 +24,8 @@ void barCall();
/*
TEST_OUTPUT:
---
-fail_compilation/nogc3.d(35): Error: @nogc function 'nogc3.testCall' cannot call non-@nogc function pointer 'fp'
-fail_compilation/nogc3.d(36): Error: @nogc function 'nogc3.testCall' cannot call non-@nogc function 'nogc3.barCall'
+fail_compilation/nogc3.d(34): Error: `@nogc` function `nogc3.testCall` cannot call non-@nogc function pointer `fp`
+fail_compilation/nogc3.d(35): Error: `@nogc` function `nogc3.testCall` cannot call non-@nogc function `nogc3.barCall`
---
*/
@nogc void testCall()
@@ -44,10 +43,10 @@ fail_compilation/nogc3.d(36): Error: @nogc function 'nogc3.testCall' cannot call
/*
TEST_OUTPUT:
---
-fail_compilation/nogc3.d(53): Error: function nogc3.testClosure1 is @nogc yet allocates closures with the GC
-fail_compilation/nogc3.d(56): nogc3.testClosure1.bar closes over variable x at fail_compilation/nogc3.d(55)
-fail_compilation/nogc3.d(65): Error: function nogc3.testClosure3 is @nogc yet allocates closures with the GC
-fail_compilation/nogc3.d(68): nogc3.testClosure3.bar closes over variable x at fail_compilation/nogc3.d(67)
+fail_compilation/nogc3.d(52): Error: function `nogc3.testClosure1` is `@nogc` yet allocates closures with the GC
+fail_compilation/nogc3.d(55): nogc3.testClosure1.bar closes over variable x at fail_compilation/nogc3.d(54)
+fail_compilation/nogc3.d(64): Error: function `nogc3.testClosure3` is `@nogc` yet allocates closures with the GC
+fail_compilation/nogc3.d(67): nogc3.testClosure3.bar closes over variable x at fail_compilation/nogc3.d(66)
---
*/
@nogc auto testClosure1()
@@ -74,10 +73,10 @@ fail_compilation/nogc3.d(68): nogc3.testClosure3.bar closes over variable
/*
TEST_OUTPUT:
---
-fail_compilation/nogc3.d(86): Error: array literal in @nogc function 'nogc3.foo13702' may cause GC allocation
-fail_compilation/nogc3.d(87): Error: array literal in @nogc function 'nogc3.foo13702' may cause GC allocation
-fail_compilation/nogc3.d(93): Error: array literal in @nogc function 'nogc3.bar13702' may cause GC allocation
-fail_compilation/nogc3.d(92): Error: array literal in @nogc function 'nogc3.bar13702' may cause GC allocation
+fail_compilation/nogc3.d(85): Error: array literal in `@nogc` function `nogc3.foo13702` may cause a GC allocation
+fail_compilation/nogc3.d(86): Error: array literal in `@nogc` function `nogc3.foo13702` may cause a GC allocation
+fail_compilation/nogc3.d(92): Error: array literal in `@nogc` function `nogc3.bar13702` may cause a GC allocation
+fail_compilation/nogc3.d(91): Error: array literal in `@nogc` function `nogc3.bar13702` may cause a GC allocation
---
*/
int[] foo13702(bool b) @nogc
diff --git a/gcc/testsuite/gdc.test/fail_compilation/noreturn.d b/gcc/testsuite/gdc.test/fail_compilation/noreturn.d
new file mode 100644
index 0000000..3b340e8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/noreturn.d
@@ -0,0 +1,118 @@
+/*
+REQUIRED_ARGS: -w -o-
+
+TEST_OUTPUT:
+---
+fail_compilation\noreturn.d(38): Error: `"Accessed expression of type `noreturn`"`
+fail_compilation\noreturn.d(42): called from here: `assign()`
+fail_compilation\noreturn.d(49): Error: `"Accessed expression of type `noreturn`"`
+fail_compilation\noreturn.d(49): called from here: `foo(n)`
+fail_compilation\noreturn.d(53): called from here: `calling()`
+fail_compilation\noreturn.d(59): Error: `"Accessed expression of type `noreturn`"`
+fail_compilation\noreturn.d(62): called from here: `nested()`
+fail_compilation\noreturn.d(68): Error: `"Accessed expression of type `noreturn`"`
+fail_compilation\noreturn.d(78): called from here: `casting(0)`
+fail_compilation\noreturn.d(69): Error: `"Accessed expression of type `noreturn`"`
+fail_compilation\noreturn.d(79): called from here: `casting(1)`
+fail_compilation\noreturn.d(72): Error: `"Accessed expression of type `noreturn`"`
+fail_compilation\noreturn.d(80): called from here: `casting(2)`
+---
+
+https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1034.md
+*/
+
+alias noreturn = typeof(*null);
+
+int pass()
+{
+ noreturn n;
+ noreturn m;
+ return 0;
+}
+
+enum forcePass = pass();
+
+int assign()
+{
+ noreturn n;
+ noreturn m = n;
+ return 0;
+}
+
+enum forceAss = assign();
+
+void foo(const noreturn) {}
+
+int calling()
+{
+ noreturn n;
+ foo(n);
+ return 0;
+}
+
+enum forceCall = calling();
+
+int nested()
+{
+ int[4] arr;
+ noreturn n;
+ return arr[n ? n : n];
+}
+
+enum forceNested = nested();
+
+noreturn casting(int i)
+{
+ final switch (i)
+ {
+ case 0: return cast(noreturn) i;
+ case 1: return cast(typeof(assert(0))) cast(double) i;
+ case 2, 3: {
+ noreturn n;
+ return cast() n;
+ }
+ }
+
+}
+
+enum forceCasting0 = casting(0);
+enum forceCasting1 = casting(1);
+enum forceCasting2 = casting(2);
+
+/*
+struct HasNoreturnStruct
+{
+ noreturn n;
+}
+
+int inStruct()
+{
+ HasNoreturnStruct hn;
+ return hn.n;
+}
+
+enum forceInStruct = inStruct();
+
+class HasNoreturnClass
+{
+ noreturn n;
+}
+
+int inClass()
+{
+ HasNoreturnClass hn = new HasNoreturnClass();
+ return hn.n;
+}
+
+enum forceInClass = inClass();
+
+int inClassRef()
+{
+ static void byRef(ref noreturn n) {}
+ HasNoreturnClass hn = new HasNoreturnClass();
+ byRef(hn.n);
+ return 0;
+}
+
+enum forceInClassRef = inClassRef();
+*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/notype.d b/gcc/testsuite/gdc.test/fail_compilation/notype.d
new file mode 100644
index 0000000..1825968
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/notype.d
@@ -0,0 +1,31 @@
+struct S(int var = 3) {
+ int a;
+}
+S s;
+
+alias A() = int;
+A a;
+
+enum e() = 5;
+e val;
+
+interface I()
+{
+}
+I i;
+
+template t()
+{
+}
+t tv;
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/notype.d(4): Error: template struct `notype.S(int var = 3)` is used as a type without instantiation; to instantiate it use `S!(arguments)`
+fail_compilation/notype.d(7): Error: template `notype.A()` is used as a type
+fail_compilation/notype.d(10): Error: template `notype.e()` is used as a type
+fail_compilation/notype.d(15): Error: template interface `notype.I()` is used as a type without instantiation; to instantiate it use `I!(arguments)`
+fail_compilation/notype.d(20): Error: template `notype.t()` is used as a type
+---
+*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/objc_class2.d b/gcc/testsuite/gdc.test/fail_compilation/objc_class2.d
new file mode 100644
index 0000000..9d6658c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/objc_class2.d
@@ -0,0 +1,15 @@
+// EXTRA_OBJC_SOURCES
+/*
+TEST_OUTPUT:
+---
+fail_compilation/objc_class2.d(14): Error: function `objc_class2.A.test` number of colons in Objective-C selector must match number of parameters
+---
+*/
+
+import core.attribute : selector;
+
+extern (Objective-C)
+extern class A
+{
+ void test(int a, int b, int c) @selector("test:"); // non-matching number of colon
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/objc_class3.d b/gcc/testsuite/gdc.test/fail_compilation/objc_class3.d
new file mode 100644
index 0000000..f76443d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/objc_class3.d
@@ -0,0 +1,22 @@
+// EXTRA_OBJC_SOURCES
+/*
+TEST_OUTPUT:
+---
+fail_compilation/objc_class3.d(15): Error: function `objc_class3.A.test!int.test` template cannot have an Objective-C selector attached
+fail_compilation/objc_class3.d(21): Error: template instance `objc_class3.A.test!int` error instantiating
+---
+*/
+
+import core.attribute : selector;
+
+extern (Objective-C)
+extern class A
+{
+ void test(T)(T a) @selector("test:"); // selector defined for template
+}
+
+void test()
+{
+ A a;
+ a.test(3);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/objc_non_objc_base.d b/gcc/testsuite/gdc.test/fail_compilation/objc_non_objc_base.d
new file mode 100644
index 0000000..6e2b078
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/objc_non_objc_base.d
@@ -0,0 +1,12 @@
+// EXTRA_OBJC_SOURCES
+/*
+TEST_OUTPUT:
+---
+fail_compilation/objc_non_objc_base.d(12): Error: class `objc_non_objc_base.A` base class for an Objective-C class must be `extern (Objective-C)`
+---
+*/
+
+interface Base {}
+
+extern (Objective-C)
+class A : Base {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/parse12967a.d b/gcc/testsuite/gdc.test/fail_compilation/parse12967a.d
index 90bccb7..5282232 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/parse12967a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/parse12967a.d
@@ -1,14 +1,14 @@
/*
TEST_OUTPUT:
---
-fail_compilation/parse12967a.d(14): Error: function parse12967a.pre_i1 without 'this' cannot be immutable
-fail_compilation/parse12967a.d(15): Error: function parse12967a.pre_i2 without 'this' cannot be immutable
-fail_compilation/parse12967a.d(16): Error: function parse12967a.pre_c1 without 'this' cannot be const
-fail_compilation/parse12967a.d(17): Error: function parse12967a.pre_c2 without 'this' cannot be const
-fail_compilation/parse12967a.d(18): Error: function parse12967a.pre_w1 without 'this' cannot be inout
-fail_compilation/parse12967a.d(19): Error: function parse12967a.pre_w2 without 'this' cannot be inout
-fail_compilation/parse12967a.d(20): Error: function parse12967a.pre_s1 without 'this' cannot be shared
-fail_compilation/parse12967a.d(21): Error: function parse12967a.pre_s2 without 'this' cannot be shared
+fail_compilation/parse12967a.d(14): Error: function `parse12967a.pre_i1` without `this` cannot be `immutable`
+fail_compilation/parse12967a.d(15): Error: function `parse12967a.pre_i2` without `this` cannot be `immutable`
+fail_compilation/parse12967a.d(16): Error: function `parse12967a.pre_c1` without `this` cannot be `const`
+fail_compilation/parse12967a.d(17): Error: function `parse12967a.pre_c2` without `this` cannot be `const`
+fail_compilation/parse12967a.d(18): Error: function `parse12967a.pre_w1` without `this` cannot be `inout`
+fail_compilation/parse12967a.d(19): Error: function `parse12967a.pre_w2` without `this` cannot be `inout`
+fail_compilation/parse12967a.d(20): Error: function `parse12967a.pre_s1` without `this` cannot be `shared`
+fail_compilation/parse12967a.d(21): Error: function `parse12967a.pre_s2` without `this` cannot be `shared`
---
*/
immutable pre_i1() {}
@@ -23,14 +23,14 @@ shared void pre_s2() {}
/*
TEST_OUTPUT:
---
-fail_compilation/parse12967a.d(36): Error: function parse12967a.post_i1 without 'this' cannot be immutable
-fail_compilation/parse12967a.d(37): Error: function parse12967a.post_i2 without 'this' cannot be immutable
-fail_compilation/parse12967a.d(38): Error: function parse12967a.post_c1 without 'this' cannot be const
-fail_compilation/parse12967a.d(39): Error: function parse12967a.post_c2 without 'this' cannot be const
-fail_compilation/parse12967a.d(40): Error: function parse12967a.post_w1 without 'this' cannot be inout
-fail_compilation/parse12967a.d(41): Error: function parse12967a.post_w2 without 'this' cannot be inout
-fail_compilation/parse12967a.d(42): Error: function parse12967a.post_s1 without 'this' cannot be shared
-fail_compilation/parse12967a.d(43): Error: function parse12967a.post_s2 without 'this' cannot be shared
+fail_compilation/parse12967a.d(36): Error: function `parse12967a.post_i1` without `this` cannot be `immutable`
+fail_compilation/parse12967a.d(37): Error: function `parse12967a.post_i2` without `this` cannot be `immutable`
+fail_compilation/parse12967a.d(38): Error: function `parse12967a.post_c1` without `this` cannot be `const`
+fail_compilation/parse12967a.d(39): Error: function `parse12967a.post_c2` without `this` cannot be `const`
+fail_compilation/parse12967a.d(40): Error: function `parse12967a.post_w1` without `this` cannot be `inout`
+fail_compilation/parse12967a.d(41): Error: function `parse12967a.post_w2` without `this` cannot be `inout`
+fail_compilation/parse12967a.d(42): Error: function `parse12967a.post_s1` without `this` cannot be `shared`
+fail_compilation/parse12967a.d(43): Error: function `parse12967a.post_s2` without `this` cannot be `shared`
---
*/
auto post_i1() immutable {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/parse12967b.d b/gcc/testsuite/gdc.test/fail_compilation/parse12967b.d
index 60d9d09..064f297 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/parse12967b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/parse12967b.d
@@ -1,41 +1,45 @@
/*
TEST_OUTPUT:
---
-fail_compilation/parse12967b.d(24): Error: function parse12967b.C.pre_c without 'this' cannot be const
-fail_compilation/parse12967b.d(25): Error: function parse12967b.C.pre_c without 'this' cannot be const
-fail_compilation/parse12967b.d(26): Error: function parse12967b.C.pre_i without 'this' cannot be immutable
-fail_compilation/parse12967b.d(27): Error: function parse12967b.C.pre_i without 'this' cannot be immutable
-fail_compilation/parse12967b.d(28): Error: function parse12967b.C.pre_w without 'this' cannot be inout
-fail_compilation/parse12967b.d(29): Error: function parse12967b.C.pre_w without 'this' cannot be inout
-fail_compilation/parse12967b.d(30): Error: function parse12967b.C.pre_s without 'this' cannot be shared
-fail_compilation/parse12967b.d(31): Error: function parse12967b.C.pre_s without 'this' cannot be shared
-fail_compilation/parse12967b.d(33): Error: function parse12967b.C.post_c without 'this' cannot be const
-fail_compilation/parse12967b.d(34): Error: function parse12967b.C.post_c without 'this' cannot be const
-fail_compilation/parse12967b.d(35): Error: function parse12967b.C.post_i without 'this' cannot be immutable
-fail_compilation/parse12967b.d(36): Error: function parse12967b.C.post_i without 'this' cannot be immutable
-fail_compilation/parse12967b.d(37): Error: function parse12967b.C.post_w without 'this' cannot be inout
-fail_compilation/parse12967b.d(38): Error: function parse12967b.C.post_w without 'this' cannot be inout
-fail_compilation/parse12967b.d(39): Error: function parse12967b.C.post_s without 'this' cannot be shared
-fail_compilation/parse12967b.d(40): Error: function parse12967b.C.post_s without 'this' cannot be shared
+fail_compilation/parse12967b.d(24): Error: function `parse12967b.C.pre_c` without `this` cannot be `const`
+fail_compilation/parse12967b.d(25): Error: function `parse12967b.C.pre_i` without `this` cannot be `immutable`
+fail_compilation/parse12967b.d(26): Error: function `parse12967b.C.pre_w` without `this` cannot be `inout`
+fail_compilation/parse12967b.d(27): Error: function `parse12967b.C.pre_s` without `this` cannot be `shared`
+fail_compilation/parse12967b.d(29): Error: function `parse12967b.C.post_c` without `this` cannot be `const`
+fail_compilation/parse12967b.d(30): Error: function `parse12967b.C.post_i` without `this` cannot be `immutable`
+fail_compilation/parse12967b.d(31): Error: function `parse12967b.C.post_w` without `this` cannot be `inout`
+fail_compilation/parse12967b.d(32): Error: function `parse12967b.C.post_s` without `this` cannot be `shared`
+fail_compilation/parse12967b.d(37): Error: function `parse12967b.D.pre_c` without `this` cannot be `const`
+fail_compilation/parse12967b.d(38): Error: function `parse12967b.D.pre_i` without `this` cannot be `immutable`
+fail_compilation/parse12967b.d(39): Error: function `parse12967b.D.pre_w` without `this` cannot be `inout`
+fail_compilation/parse12967b.d(40): Error: function `parse12967b.D.pre_s` without `this` cannot be `shared`
+fail_compilation/parse12967b.d(41): Error: function `parse12967b.D.post_c` without `this` cannot be `const`
+fail_compilation/parse12967b.d(42): Error: function `parse12967b.D.post_i` without `this` cannot be `immutable`
+fail_compilation/parse12967b.d(43): Error: function `parse12967b.D.post_w` without `this` cannot be `inout`
+fail_compilation/parse12967b.d(44): Error: function `parse12967b.D.post_s` without `this` cannot be `shared`
---
*/
class C
{
const static pre_c() {}
- const static void pre_c() {}
immutable static pre_i() {}
- immutable static void pre_i() {}
inout static pre_w() {}
- inout static void pre_w() {}
shared static pre_s() {}
- shared static void pre_s() {}
static post_c() const {}
- static void post_c() const {}
static post_i() immutable {}
- static void post_i() immutable {}
static post_w() inout {}
- static void post_w() inout {}
static post_s() shared {}
+}
+
+class D
+{
+ const static void pre_c() {}
+ immutable static void pre_i() {}
+ inout static void pre_w() {}
+ shared static void pre_s() {}
+ static void post_c() const {}
+ static void post_i() immutable {}
+ static void post_w() inout {}
static void post_s() shared {}
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/parse19277.d b/gcc/testsuite/gdc.test/fail_compilation/parse19277.d
new file mode 100644
index 0000000..19dd747
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/parse19277.d
@@ -0,0 +1,20 @@
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/parse19277.d(13): Deprecation: storage class `ref` has no effect in type aliases
+fail_compilation/parse19277.d(14): Deprecation: storage class `__gshared` has no effect in type aliases
+fail_compilation/parse19277.d(15): Deprecation: storage class `static` has no effect in type aliases
+fail_compilation/parse19277.d(16): Deprecation: storage class `extern` has no effect in type aliases
+fail_compilation/parse19277.d(17): Deprecation: storage class `scope` has no effect in type aliases
+---
+*/
+
+alias T = ref int;
+alias U = __gshared int;
+alias V = static int;
+alias W = extern int;
+alias Dg = scope void delegate();
+
+alias F = ref pure nothrow @nogc @safe @live int function();
+alias G = ref pure nothrow @nogc @system @live int delegate();
diff --git a/gcc/testsuite/gdc.test/fail_compilation/parseStc2.d b/gcc/testsuite/gdc.test/fail_compilation/parseStc2.d
index 5e9c446..936769a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/parseStc2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/parseStc2.d
@@ -43,8 +43,8 @@ extern(C++, foo) extern(C++, bar) void f8() {} // OK
/*
TEST_OUTPUT:
---
-fail_compilation/parseStc2.d(50): Error: redundant protection attribute `public`
-fail_compilation/parseStc2.d(51): Error: conflicting protection attribute `public` and `private`
+fail_compilation/parseStc2.d(50): Error: redundant visibility attribute `public`
+fail_compilation/parseStc2.d(51): Error: conflicting visibility attribute `public` and `private`
---
*/
public public void f9() {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/parseStc3.d b/gcc/testsuite/gdc.test/fail_compilation/parseStc3.d
index 1417f94..d4c0aa0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/parseStc3.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/parseStc3.d
@@ -1,10 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/parseStc3.d(10): Deprecation: redundant attribute `pure`
-fail_compilation/parseStc3.d(11): Deprecation: redundant attribute `nothrow`
-fail_compilation/parseStc3.d(12): Deprecation: redundant attribute `@nogc`
-fail_compilation/parseStc3.d(13): Deprecation: redundant attribute `@property`
+fail_compilation/parseStc3.d(10): Error: redundant attribute `pure`
+fail_compilation/parseStc3.d(11): Error: redundant attribute `nothrow`
+fail_compilation/parseStc3.d(12): Error: redundant attribute `@nogc`
+fail_compilation/parseStc3.d(13): Error: redundant attribute `@property`
---
*/
pure void f1() pure {}
@@ -16,9 +16,9 @@ nothrow void f2() nothrow {}
/*
TEST_OUTPUT:
---
-fail_compilation/parseStc3.d(24): Deprecation: redundant attribute `@safe`
-fail_compilation/parseStc3.d(25): Deprecation: redundant attribute `@system`
-fail_compilation/parseStc3.d(26): Deprecation: redundant attribute `@trusted`
+fail_compilation/parseStc3.d(24): Error: redundant attribute `@safe`
+fail_compilation/parseStc3.d(25): Error: redundant attribute `@system`
+fail_compilation/parseStc3.d(26): Error: redundant attribute `@trusted`
---
*/
@safe void f6() @safe {}
@@ -49,11 +49,11 @@ TEST_OUTPUT:
fail_compilation/parseStc3.d(59): Error: conflicting attribute `@system`
fail_compilation/parseStc3.d(59): Error: conflicting attribute `@trusted`
fail_compilation/parseStc3.d(60): Error: conflicting attribute `@system`
-fail_compilation/parseStc3.d(60): Deprecation: redundant attribute `@system`
+fail_compilation/parseStc3.d(60): Error: redundant attribute `@system`
fail_compilation/parseStc3.d(61): Error: conflicting attribute `@safe`
-fail_compilation/parseStc3.d(61): Deprecation: redundant attribute `@system`
+fail_compilation/parseStc3.d(61): Error: redundant attribute `@system`
fail_compilation/parseStc3.d(62): Error: conflicting attribute `@safe`
-fail_compilation/parseStc3.d(62): Deprecation: redundant attribute `@trusted`
+fail_compilation/parseStc3.d(62): Error: redundant attribute `@trusted`
---
*/
@safe @system void f15() @trusted {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/parseStc4.d b/gcc/testsuite/gdc.test/fail_compilation/parseStc4.d
index fee3e08..4bd3a04 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/parseStc4.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/parseStc4.d
@@ -2,11 +2,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/parseStc4.d(14): Deprecation: redundant attribute `pure`
-fail_compilation/parseStc4.d(14): Deprecation: redundant attribute `nothrow`
+fail_compilation/parseStc4.d(14): Error: redundant attribute `pure`
+fail_compilation/parseStc4.d(14): Error: redundant attribute `nothrow`
fail_compilation/parseStc4.d(14): Error: conflicting attribute `@system`
-fail_compilation/parseStc4.d(14): Deprecation: redundant attribute `@nogc`
-fail_compilation/parseStc4.d(14): Deprecation: redundant attribute `@property`
+fail_compilation/parseStc4.d(14): Error: redundant attribute `@nogc`
+fail_compilation/parseStc4.d(14): Error: redundant attribute `@property`
---
*/
pure nothrow @safe @nogc @property
@@ -19,13 +19,14 @@ pure nothrow @system @nogc @property
/*
TEST_OUTPUT:
---
-fail_compilation/parseStc4.d(34): Deprecation: redundant attribute `const`
-fail_compilation/parseStc4.d(35): Deprecation: redundant attribute `const`
-fail_compilation/parseStc4.d(36): Deprecation: redundant attribute `const`
-fail_compilation/parseStc4.d(38): Deprecation: redundant attribute `pure`
-fail_compilation/parseStc4.d(39): Deprecation: redundant attribute `@safe`
-fail_compilation/parseStc4.d(40): Deprecation: redundant attribute `nothrow`
-fail_compilation/parseStc4.d(41): Error: conflicting attribute `@trusted`
+fail_compilation/parseStc4.d(35): Error: redundant attribute `const`
+fail_compilation/parseStc4.d(36): Error: redundant attribute `const`
+fail_compilation/parseStc4.d(36): Deprecation: `const` postblit is deprecated. Please use an unqualified postblit.
+fail_compilation/parseStc4.d(37): Error: redundant attribute `const`
+fail_compilation/parseStc4.d(39): Error: redundant attribute `pure`
+fail_compilation/parseStc4.d(40): Error: redundant attribute `@safe`
+fail_compilation/parseStc4.d(41): Error: redundant attribute `nothrow`
+fail_compilation/parseStc4.d(42): Error: conflicting attribute `@trusted`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/parseStc5.d b/gcc/testsuite/gdc.test/fail_compilation/parseStc5.d
index a274c6e..8c3718b6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/parseStc5.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/parseStc5.d
@@ -1,9 +1,8 @@
-// REQUIRED_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/parseStc5.d(11): Error: constructor cannot be static
-fail_compilation/parseStc5.d(12): Error: postblit cannot be static
+fail_compilation/parseStc5.d(10): Error: constructor cannot be static
+fail_compilation/parseStc5.d(11): Error: postblit cannot be `static`
---
*/
class C1
@@ -15,12 +14,12 @@ class C1
/*
TEST_OUTPUT:
---
+fail_compilation/parseStc5.d(27): Error: use `shared static this()` to declare a shared static constructor
fail_compilation/parseStc5.d(28): Error: use `shared static this()` to declare a shared static constructor
-fail_compilation/parseStc5.d(29): Error: use `shared static this()` to declare a shared static constructor
-fail_compilation/parseStc5.d(31): Error: use `shared static this()` to declare a shared static constructor
+fail_compilation/parseStc5.d(30): Error: use `shared static this()` to declare a shared static constructor
+fail_compilation/parseStc5.d(32): Error: use `shared static ~this()` to declare a shared static destructor
fail_compilation/parseStc5.d(33): Error: use `shared static ~this()` to declare a shared static destructor
-fail_compilation/parseStc5.d(34): Error: use `shared static ~this()` to declare a shared static destructor
-fail_compilation/parseStc5.d(36): Error: use `shared static ~this()` to declare a shared static destructor
+fail_compilation/parseStc5.d(35): Error: use `shared static ~this()` to declare a shared static destructor
---
*/
class C2 // wrong combinations of `shared`, `static`, and `~?this()`
@@ -39,8 +38,8 @@ class C2 // wrong combinations of `shared`, `static`, and `~?this()`
/*
TEST_OUTPUT:
---
-fail_compilation/parseStc5.d(48): Error: use `static this()` to declare a static constructor
-fail_compilation/parseStc5.d(49): Error: use `static ~this()` to declare a static destructor
+fail_compilation/parseStc5.d(47): Error: use `static this()` to declare a static constructor
+fail_compilation/parseStc5.d(48): Error: use `static ~this()` to declare a static destructor
---
*/
class C3 // wrong combinations of `static` and `~?this()`
@@ -52,11 +51,11 @@ class C3 // wrong combinations of `static` and `~?this()`
/*
TEST_OUTPUT:
---
+fail_compilation/parseStc5.d(63): Error: redundant attribute `shared`
fail_compilation/parseStc5.d(64): Error: redundant attribute `shared`
-fail_compilation/parseStc5.d(65): Error: redundant attribute `shared`
-fail_compilation/parseStc5.d(67): Error: redundant attribute `static`
+fail_compilation/parseStc5.d(66): Error: redundant attribute `static`
+fail_compilation/parseStc5.d(68): Error: redundant attribute `static shared`
fail_compilation/parseStc5.d(69): Error: redundant attribute `static shared`
-fail_compilation/parseStc5.d(70): Error: redundant attribute `static shared`
---
*/
class C4 // redundancy of `shared` and/or `static`
@@ -73,10 +72,10 @@ class C4 // redundancy of `shared` and/or `static`
/*
TEST_OUTPUT:
---
-fail_compilation/parseStc5.d(84): Error: static constructor cannot be `const`
-fail_compilation/parseStc5.d(85): Error: static destructor cannot be `const`
-fail_compilation/parseStc5.d(86): Error: shared static constructor cannot be `const`
-fail_compilation/parseStc5.d(87): Error: shared static destructor cannot be `const`
+fail_compilation/parseStc5.d(83): Error: static constructor cannot be `const`
+fail_compilation/parseStc5.d(84): Error: static destructor cannot be `const`
+fail_compilation/parseStc5.d(85): Error: shared static constructor cannot be `const`
+fail_compilation/parseStc5.d(86): Error: shared static destructor cannot be `const`
---
*/
class C5 // wrong MemberFunctionAttributes on `shared? static (con|de)structor`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/pragmainline.d b/gcc/testsuite/gdc.test/fail_compilation/pragmainline.d
index 030f19a..6d935a0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/pragmainline.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/pragmainline.d
@@ -1,11 +1,10 @@
/*
TEST_OUTPUT:
---
-fail_compilation/pragmainline.d(9): Error: pragma inline one boolean expression expected for `pragma(inline)`, not 3
-fail_compilation/pragmainline.d(10): Error: pragma inline pragma(`inline`, `true` or `false`) expected, not `"string"`
+fail_compilation/pragmainline.d(8): Error: pragma `inline` one boolean expression expected for `pragma(inline)`, not 3
---
*/
pragma(inline, 1,2,3) void bar();
-pragma(inline, "string") void baz();
+pragma(inline, "string") void baz(); // works now
diff --git a/gcc/testsuite/gdc.test/fail_compilation/pragmas.d b/gcc/testsuite/gdc.test/fail_compilation/pragmas.d
index 33a8921..25ab151 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/pragmas.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/pragmas.d
@@ -1,16 +1,10 @@
-/*
-REQUIRED_ARGS:
-PERMUTE_ARGS:
-*/
-
/************************************************************/
/*
TEST_OUTPUT:
---
-fail_compilation/pragmas.d(103): Error: boolean expression expected for pragma(inline)
-fail_compilation/pragmas.d(108): Error: boolean expression expected for pragma(inline)
-fail_compilation/pragmas.d(113): Error: pragma(inline, true or false) expected, not `"string"`
+fail_compilation/pragmas.d(103): Error: boolean expression expected for `pragma(inline)`
+fail_compilation/pragmas.d(108): Error: boolean expression expected for `pragma(inline)`
fail_compilation/pragmas.d(118): Error: unrecognized `pragma(unrecognized)`
---
*/
@@ -29,7 +23,7 @@ void test2()
void test3()
{
- pragma(inline, "string");
+ pragma(inline, "string"); // works now
}
void test4()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/previewin.d b/gcc/testsuite/gdc.test/fail_compilation/previewin.d
new file mode 100644
index 0000000..b3beaf4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/previewin.d
@@ -0,0 +1,42 @@
+/*
+REQUIRED_ARGS: -preview=in -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/previewin.d(4): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(real x) pure nothrow @nogc @safe)`
+fail_compilation/previewin.d(4): cannot pass argument `__lambda1` of type `void function(real x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
+fail_compilation/previewin.d(5): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(const(real) x) pure nothrow @nogc @safe)`
+fail_compilation/previewin.d(5): cannot pass argument `__lambda2` of type `void function(const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
+fail_compilation/previewin.d(6): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(ref const(real) x) pure nothrow @nogc @safe)`
+fail_compilation/previewin.d(6): cannot pass argument `__lambda3` of type `void function(ref const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
+fail_compilation/previewin.d(15): Error: scope variable `arg` assigned to non-scope `myGlobal`
+fail_compilation/previewin.d(16): Error: scope variable `arg` assigned to non-scope `myGlobal`
+fail_compilation/previewin.d(17): Error: scope variable `arg` may not be returned
+fail_compilation/previewin.d(18): Error: scope variable `arg` assigned to `escape` with longer lifetime
+fail_compilation/previewin.d(22): Error: returning `arg` escapes a reference to parameter `arg`
+fail_compilation/previewin.d(22): perhaps annotate the parameter with `return`
+---
+ */
+
+#line 1
+void main ()
+{
+ // No covariance without explicit `in`
+ takeFunction((real x) {});
+ takeFunction((const scope real x) {});
+ takeFunction((const scope ref real x) {});
+
+ tryEscape("Hello World"); // Yes by `tryEscape` is NG
+}
+
+void takeFunction(void function(in real) f);
+
+// Make sure things cannot be escaped (`scope` is applied)
+const(char)[] myGlobal;
+void tryEscape(in char[] arg) @safe { myGlobal = arg; }
+void tryEscape2(scope const char[] arg) @safe { myGlobal = arg; }
+const(char)[] tryEscape3(in char[] arg) @safe { return arg; }
+void tryEscape4(in char[] arg, ref const(char)[] escape) @safe { escape = arg; }
+// Okay: value type
+ulong[8] tryEscape5(in ulong[8] arg) @safe { return arg; }
+// NG: Ref
+ref const(ulong[8]) tryEscape6(in ulong[8] arg) @safe { return arg; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/protattr1.d b/gcc/testsuite/gdc.test/fail_compilation/protattr1.d
index dbd2efa..f5976ff 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/protattr1.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/protattr1.d
@@ -1,7 +1,8 @@
/*
+EXTRA_FILES: protection/subpkg/test1.d
TEST_OUTPUT:
---
-fail_compilation/protection/subpkg/test1.d(3): Error: protection attribute 'package(undefined)' does not bind to one of ancestor packages of module `protection.subpkg.test1`
+fail_compilation/protection/subpkg/test1.d(3): Error: visibility attribute `package(undefined)` does not bind to one of ancestor packages of module `protection.subpkg.test1`
---
*/
import protection.subpkg.test1;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/protattr2.d b/gcc/testsuite/gdc.test/fail_compilation/protattr2.d
index cc36cc0..7b6704f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/protattr2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/protattr2.d
@@ -1,7 +1,8 @@
/*
+EXTRA_FILES: protection/subpkg/test2.d
TEST_OUTPUT:
---
-fail_compilation/protection/subpkg/test2.d(3): Error: protection attribute 'package(protection.subpkg2)' does not bind to one of ancestor packages of module `protection.subpkg.test2`
+fail_compilation/protection/subpkg/test2.d(3): Error: visibility attribute `package(protection.subpkg2)` does not bind to one of ancestor packages of module `protection.subpkg.test2`
---
*/
import protection.subpkg.test2;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/protattr3.d b/gcc/testsuite/gdc.test/fail_compilation/protattr3.d
index 8f40b2e..acfc9f9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/protattr3.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/protattr3.d
@@ -1,4 +1,5 @@
/*
+EXTRA_FILES: protection/subpkg/test3.d
TEST_OUTPUT:
---
fail_compilation/protection/subpkg/test3.d(3): Error: `protection package` expected as dot-separated identifiers, got `123`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/pull12941.d b/gcc/testsuite/gdc.test/fail_compilation/pull12941.d
new file mode 100644
index 0000000..b020868
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/pull12941.d
@@ -0,0 +1,31 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/pull12941.d(110): Error: `pull12941.foo` called with argument types `(int*)` matches both:
+fail_compilation/pull12941.d(101): `pull12941.foo(ref return scope int* p)`
+and:
+fail_compilation/pull12941.d(102): `pull12941.foo(out return scope int* p)`
+fail_compilation/pull12941.d(111): Error: function `pull12941.bar(return scope int* p)` is not callable using argument types `(int)`
+fail_compilation/pull12941.d(111): cannot pass argument `1` of type `int` to parameter `return scope int* p`
+fail_compilation/pull12941.d(112): Error: function `pull12941.abc(return ref int* p)` is not callable using argument types `(int)`
+fail_compilation/pull12941.d(112): cannot pass rvalue argument `1` of type `int` to parameter `return ref int* p`
+---
+ */
+
+/*********************************/
+// Tests for https://github.com/dlang/dmd/pull/12941
+
+#line 100
+
+int* foo(ref scope return int* p);
+int* foo(out scope return int* p);
+
+int* bar(scope return int* p);
+int* abc(ref return int* p);
+
+void test()
+{
+ int* p;
+ foo(p);
+ bar(1);
+ abc(1);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d b/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d
index 1fe4728..034fa54 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d
@@ -13,95 +13,106 @@ fail_compilation/reserved_version.d(112): Error: version identifier `Win32` is r
fail_compilation/reserved_version.d(113): Error: version identifier `Win64` is reserved and cannot be set
fail_compilation/reserved_version.d(114): Error: version identifier `linux` is reserved and cannot be set
fail_compilation/reserved_version.d(115): Error: version identifier `OSX` is reserved and cannot be set
-fail_compilation/reserved_version.d(116): Error: version identifier `FreeBSD` is reserved and cannot be set
-fail_compilation/reserved_version.d(117): Error: version identifier `OpenBSD` is reserved and cannot be set
-fail_compilation/reserved_version.d(118): Error: version identifier `NetBSD` is reserved and cannot be set
-fail_compilation/reserved_version.d(119): Error: version identifier `DragonFlyBSD` is reserved and cannot be set
-fail_compilation/reserved_version.d(120): Error: version identifier `BSD` is reserved and cannot be set
-fail_compilation/reserved_version.d(121): Error: version identifier `Solaris` is reserved and cannot be set
-fail_compilation/reserved_version.d(122): Error: version identifier `Posix` is reserved and cannot be set
-fail_compilation/reserved_version.d(123): Error: version identifier `AIX` is reserved and cannot be set
-fail_compilation/reserved_version.d(124): Error: version identifier `Haiku` is reserved and cannot be set
-fail_compilation/reserved_version.d(125): Error: version identifier `SkyOS` is reserved and cannot be set
-fail_compilation/reserved_version.d(126): Error: version identifier `SysV3` is reserved and cannot be set
-fail_compilation/reserved_version.d(127): Error: version identifier `SysV4` is reserved and cannot be set
-fail_compilation/reserved_version.d(128): Error: version identifier `Hurd` is reserved and cannot be set
-fail_compilation/reserved_version.d(129): Error: version identifier `Android` is reserved and cannot be set
-fail_compilation/reserved_version.d(130): Error: version identifier `PlayStation` is reserved and cannot be set
-fail_compilation/reserved_version.d(131): Error: version identifier `PlayStation4` is reserved and cannot be set
-fail_compilation/reserved_version.d(132): Error: version identifier `Cygwin` is reserved and cannot be set
-fail_compilation/reserved_version.d(133): Error: version identifier `MinGW` is reserved and cannot be set
-fail_compilation/reserved_version.d(134): Error: version identifier `FreeStanding` is reserved and cannot be set
-fail_compilation/reserved_version.d(135): Error: version identifier `X86` is reserved and cannot be set
-fail_compilation/reserved_version.d(136): Error: version identifier `X86_64` is reserved and cannot be set
-fail_compilation/reserved_version.d(137): Error: version identifier `ARM` is reserved and cannot be set
-fail_compilation/reserved_version.d(138): Error: version identifier `ARM_Thumb` is reserved and cannot be set
-fail_compilation/reserved_version.d(139): Error: version identifier `ARM_SoftFloat` is reserved and cannot be set
-fail_compilation/reserved_version.d(140): Error: version identifier `ARM_SoftFP` is reserved and cannot be set
-fail_compilation/reserved_version.d(141): Error: version identifier `ARM_HardFloat` is reserved and cannot be set
-fail_compilation/reserved_version.d(142): Error: version identifier `AArch64` is reserved and cannot be set
-fail_compilation/reserved_version.d(143): Error: version identifier `Epiphany` is reserved and cannot be set
-fail_compilation/reserved_version.d(144): Error: version identifier `PPC` is reserved and cannot be set
-fail_compilation/reserved_version.d(145): Error: version identifier `PPC_SoftFloat` is reserved and cannot be set
-fail_compilation/reserved_version.d(146): Error: version identifier `PPC_HardFloat` is reserved and cannot be set
-fail_compilation/reserved_version.d(147): Error: version identifier `PPC64` is reserved and cannot be set
-fail_compilation/reserved_version.d(148): Error: version identifier `IA64` is reserved and cannot be set
-fail_compilation/reserved_version.d(149): Error: version identifier `MIPS32` is reserved and cannot be set
-fail_compilation/reserved_version.d(150): Error: version identifier `MIPS64` is reserved and cannot be set
-fail_compilation/reserved_version.d(151): Error: version identifier `MIPS_O32` is reserved and cannot be set
-fail_compilation/reserved_version.d(152): Error: version identifier `MIPS_N32` is reserved and cannot be set
-fail_compilation/reserved_version.d(153): Error: version identifier `MIPS_O64` is reserved and cannot be set
-fail_compilation/reserved_version.d(154): Error: version identifier `MIPS_N64` is reserved and cannot be set
-fail_compilation/reserved_version.d(155): Error: version identifier `MIPS_EABI` is reserved and cannot be set
-fail_compilation/reserved_version.d(156): Error: version identifier `MIPS_SoftFloat` is reserved and cannot be set
-fail_compilation/reserved_version.d(157): Error: version identifier `MIPS_HardFloat` is reserved and cannot be set
-fail_compilation/reserved_version.d(158): Error: version identifier `NVPTX` is reserved and cannot be set
-fail_compilation/reserved_version.d(159): Error: version identifier `NVPTX64` is reserved and cannot be set
-fail_compilation/reserved_version.d(160): Error: version identifier `RISCV32` is reserved and cannot be set
-fail_compilation/reserved_version.d(161): Error: version identifier `RISCV64` is reserved and cannot be set
-fail_compilation/reserved_version.d(162): Error: version identifier `SPARC` is reserved and cannot be set
-fail_compilation/reserved_version.d(163): Error: version identifier `SPARC_V8Plus` is reserved and cannot be set
-fail_compilation/reserved_version.d(164): Error: version identifier `SPARC_SoftFloat` is reserved and cannot be set
-fail_compilation/reserved_version.d(165): Error: version identifier `SPARC_HardFloat` is reserved and cannot be set
-fail_compilation/reserved_version.d(166): Error: version identifier `SPARC64` is reserved and cannot be set
-fail_compilation/reserved_version.d(167): Error: version identifier `S390` is reserved and cannot be set
-fail_compilation/reserved_version.d(168): Error: version identifier `S390X` is reserved and cannot be set
-fail_compilation/reserved_version.d(169): Error: version identifier `SystemZ` is reserved and cannot be set
-fail_compilation/reserved_version.d(170): Error: version identifier `HPPA` is reserved and cannot be set
-fail_compilation/reserved_version.d(171): Error: version identifier `HPPA64` is reserved and cannot be set
-fail_compilation/reserved_version.d(172): Error: version identifier `SH` is reserved and cannot be set
-fail_compilation/reserved_version.d(173): Error: version identifier `Alpha` is reserved and cannot be set
-fail_compilation/reserved_version.d(174): Error: version identifier `Alpha_SoftFloat` is reserved and cannot be set
-fail_compilation/reserved_version.d(175): Error: version identifier `Alpha_HardFloat` is reserved and cannot be set
-fail_compilation/reserved_version.d(176): Error: version identifier `LittleEndian` is reserved and cannot be set
-fail_compilation/reserved_version.d(177): Error: version identifier `BigEndian` is reserved and cannot be set
-fail_compilation/reserved_version.d(178): Error: version identifier `ELFv1` is reserved and cannot be set
-fail_compilation/reserved_version.d(179): Error: version identifier `ELFv2` is reserved and cannot be set
-fail_compilation/reserved_version.d(180): Error: version identifier `CRuntime_Bionic` is reserved and cannot be set
-fail_compilation/reserved_version.d(181): Error: version identifier `CRuntime_DigitalMars` is reserved and cannot be set
-fail_compilation/reserved_version.d(182): Error: version identifier `CRuntime_Glibc` is reserved and cannot be set
-fail_compilation/reserved_version.d(183): Error: version identifier `CRuntime_Microsoft` is reserved and cannot be set
-fail_compilation/reserved_version.d(184): Error: version identifier `CRuntime_Musl` is reserved and cannot be set
-fail_compilation/reserved_version.d(185): Error: version identifier `CRuntime_UClibc` is reserved and cannot be set
-fail_compilation/reserved_version.d(186): Error: version identifier `D_Coverage` is reserved and cannot be set
-fail_compilation/reserved_version.d(187): Error: version identifier `D_Ddoc` is reserved and cannot be set
-fail_compilation/reserved_version.d(188): Error: version identifier `D_InlineAsm_X86` is reserved and cannot be set
-fail_compilation/reserved_version.d(189): Error: version identifier `D_InlineAsm_X86_64` is reserved and cannot be set
-fail_compilation/reserved_version.d(190): Error: version identifier `D_LP64` is reserved and cannot be set
-fail_compilation/reserved_version.d(191): Error: version identifier `D_X32` is reserved and cannot be set
-fail_compilation/reserved_version.d(192): Error: version identifier `D_HardFloat` is reserved and cannot be set
-fail_compilation/reserved_version.d(193): Error: version identifier `D_SoftFloat` is reserved and cannot be set
-fail_compilation/reserved_version.d(194): Error: version identifier `D_PIC` is reserved and cannot be set
-fail_compilation/reserved_version.d(195): Error: version identifier `D_SIMD` is reserved and cannot be set
-fail_compilation/reserved_version.d(196): Error: version identifier `D_Version2` is reserved and cannot be set
-fail_compilation/reserved_version.d(197): Error: version identifier `D_NoBoundsChecks` is reserved and cannot be set
-fail_compilation/reserved_version.d(200): Error: version identifier `all` is reserved and cannot be set
-fail_compilation/reserved_version.d(201): Error: version identifier `none` is reserved and cannot be set
-fail_compilation/reserved_version.d(202): Error: version identifier `CppRuntime_Clang` is reserved and cannot be set
-fail_compilation/reserved_version.d(203): Error: version identifier `CppRuntime_DigitalMars` is reserved and cannot be set
-fail_compilation/reserved_version.d(204): Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set
-fail_compilation/reserved_version.d(205): Error: version identifier `CppRuntime_Microsoft` is reserved and cannot be set
-fail_compilation/reserved_version.d(206): Error: version identifier `CppRuntime_Sun` is reserved and cannot be set
+fail_compilation/reserved_version.d(116): Error: version identifier `iOS` is reserved and cannot be set
+fail_compilation/reserved_version.d(117): Error: version identifier `TVOS` is reserved and cannot be set
+fail_compilation/reserved_version.d(118): Error: version identifier `WatchOS` is reserved and cannot be set
+fail_compilation/reserved_version.d(119): Error: version identifier `FreeBSD` is reserved and cannot be set
+fail_compilation/reserved_version.d(120): Error: version identifier `OpenBSD` is reserved and cannot be set
+fail_compilation/reserved_version.d(121): Error: version identifier `NetBSD` is reserved and cannot be set
+fail_compilation/reserved_version.d(122): Error: version identifier `DragonFlyBSD` is reserved and cannot be set
+fail_compilation/reserved_version.d(123): Error: version identifier `BSD` is reserved and cannot be set
+fail_compilation/reserved_version.d(124): Error: version identifier `Solaris` is reserved and cannot be set
+fail_compilation/reserved_version.d(125): Error: version identifier `Posix` is reserved and cannot be set
+fail_compilation/reserved_version.d(126): Error: version identifier `AIX` is reserved and cannot be set
+fail_compilation/reserved_version.d(127): Error: version identifier `Haiku` is reserved and cannot be set
+fail_compilation/reserved_version.d(128): Error: version identifier `SkyOS` is reserved and cannot be set
+fail_compilation/reserved_version.d(129): Error: version identifier `SysV3` is reserved and cannot be set
+fail_compilation/reserved_version.d(130): Error: version identifier `SysV4` is reserved and cannot be set
+fail_compilation/reserved_version.d(131): Error: version identifier `Hurd` is reserved and cannot be set
+fail_compilation/reserved_version.d(132): Error: version identifier `Android` is reserved and cannot be set
+fail_compilation/reserved_version.d(133): Error: version identifier `PlayStation` is reserved and cannot be set
+fail_compilation/reserved_version.d(134): Error: version identifier `PlayStation4` is reserved and cannot be set
+fail_compilation/reserved_version.d(135): Error: version identifier `Cygwin` is reserved and cannot be set
+fail_compilation/reserved_version.d(136): Error: version identifier `MinGW` is reserved and cannot be set
+fail_compilation/reserved_version.d(137): Error: version identifier `FreeStanding` is reserved and cannot be set
+fail_compilation/reserved_version.d(138): Error: version identifier `X86` is reserved and cannot be set
+fail_compilation/reserved_version.d(139): Error: version identifier `X86_64` is reserved and cannot be set
+fail_compilation/reserved_version.d(140): Error: version identifier `ARM` is reserved and cannot be set
+fail_compilation/reserved_version.d(141): Error: version identifier `ARM_Thumb` is reserved and cannot be set
+fail_compilation/reserved_version.d(142): Error: version identifier `ARM_SoftFloat` is reserved and cannot be set
+fail_compilation/reserved_version.d(143): Error: version identifier `ARM_SoftFP` is reserved and cannot be set
+fail_compilation/reserved_version.d(144): Error: version identifier `ARM_HardFloat` is reserved and cannot be set
+fail_compilation/reserved_version.d(145): Error: version identifier `AArch64` is reserved and cannot be set
+fail_compilation/reserved_version.d(146): Error: version identifier `Epiphany` is reserved and cannot be set
+fail_compilation/reserved_version.d(147): Error: version identifier `PPC` is reserved and cannot be set
+fail_compilation/reserved_version.d(148): Error: version identifier `PPC_SoftFloat` is reserved and cannot be set
+fail_compilation/reserved_version.d(149): Error: version identifier `PPC_HardFloat` is reserved and cannot be set
+fail_compilation/reserved_version.d(150): Error: version identifier `PPC64` is reserved and cannot be set
+fail_compilation/reserved_version.d(151): Error: version identifier `IA64` is reserved and cannot be set
+fail_compilation/reserved_version.d(152): Error: version identifier `MIPS32` is reserved and cannot be set
+fail_compilation/reserved_version.d(153): Error: version identifier `MIPS64` is reserved and cannot be set
+fail_compilation/reserved_version.d(154): Error: version identifier `MIPS_O32` is reserved and cannot be set
+fail_compilation/reserved_version.d(155): Error: version identifier `MIPS_N32` is reserved and cannot be set
+fail_compilation/reserved_version.d(156): Error: version identifier `MIPS_O64` is reserved and cannot be set
+fail_compilation/reserved_version.d(157): Error: version identifier `MIPS_N64` is reserved and cannot be set
+fail_compilation/reserved_version.d(158): Error: version identifier `MIPS_EABI` is reserved and cannot be set
+fail_compilation/reserved_version.d(159): Error: version identifier `MIPS_SoftFloat` is reserved and cannot be set
+fail_compilation/reserved_version.d(160): Error: version identifier `MIPS_HardFloat` is reserved and cannot be set
+fail_compilation/reserved_version.d(161): Error: version identifier `NVPTX` is reserved and cannot be set
+fail_compilation/reserved_version.d(162): Error: version identifier `NVPTX64` is reserved and cannot be set
+fail_compilation/reserved_version.d(163): Error: version identifier `RISCV32` is reserved and cannot be set
+fail_compilation/reserved_version.d(164): Error: version identifier `RISCV64` is reserved and cannot be set
+fail_compilation/reserved_version.d(165): Error: version identifier `SPARC` is reserved and cannot be set
+fail_compilation/reserved_version.d(166): Error: version identifier `SPARC_V8Plus` is reserved and cannot be set
+fail_compilation/reserved_version.d(167): Error: version identifier `SPARC_SoftFloat` is reserved and cannot be set
+fail_compilation/reserved_version.d(168): Error: version identifier `SPARC_HardFloat` is reserved and cannot be set
+fail_compilation/reserved_version.d(169): Error: version identifier `SPARC64` is reserved and cannot be set
+fail_compilation/reserved_version.d(170): Error: version identifier `S390` is reserved and cannot be set
+fail_compilation/reserved_version.d(171): Error: version identifier `S390X` is reserved and cannot be set
+fail_compilation/reserved_version.d(172): Error: version identifier `SystemZ` is reserved and cannot be set
+fail_compilation/reserved_version.d(173): Error: version identifier `HPPA` is reserved and cannot be set
+fail_compilation/reserved_version.d(174): Error: version identifier `HPPA64` is reserved and cannot be set
+fail_compilation/reserved_version.d(175): Error: version identifier `SH` is reserved and cannot be set
+fail_compilation/reserved_version.d(176): Error: version identifier `Alpha` is reserved and cannot be set
+fail_compilation/reserved_version.d(177): Error: version identifier `Alpha_SoftFloat` is reserved and cannot be set
+fail_compilation/reserved_version.d(178): Error: version identifier `Alpha_HardFloat` is reserved and cannot be set
+fail_compilation/reserved_version.d(179): Error: version identifier `LittleEndian` is reserved and cannot be set
+fail_compilation/reserved_version.d(180): Error: version identifier `BigEndian` is reserved and cannot be set
+fail_compilation/reserved_version.d(181): Error: version identifier `ELFv1` is reserved and cannot be set
+fail_compilation/reserved_version.d(182): Error: version identifier `ELFv2` is reserved and cannot be set
+fail_compilation/reserved_version.d(183): Error: version identifier `CRuntime_Bionic` is reserved and cannot be set
+fail_compilation/reserved_version.d(184): Error: version identifier `CRuntime_DigitalMars` is reserved and cannot be set
+fail_compilation/reserved_version.d(185): Error: version identifier `CRuntime_Glibc` is reserved and cannot be set
+fail_compilation/reserved_version.d(186): Error: version identifier `CRuntime_Microsoft` is reserved and cannot be set
+fail_compilation/reserved_version.d(187): Error: version identifier `CRuntime_Musl` is reserved and cannot be set
+fail_compilation/reserved_version.d(188): Error: version identifier `CRuntime_Newlib` is reserved and cannot be set
+fail_compilation/reserved_version.d(189): Error: version identifier `CRuntime_UClibc` is reserved and cannot be set
+fail_compilation/reserved_version.d(190): Error: version identifier `CRuntime_WASI` is reserved and cannot be set
+fail_compilation/reserved_version.d(191): Error: version identifier `D_Coverage` is reserved and cannot be set
+fail_compilation/reserved_version.d(192): Error: version identifier `D_Ddoc` is reserved and cannot be set
+fail_compilation/reserved_version.d(193): Error: version identifier `D_InlineAsm_X86` is reserved and cannot be set
+fail_compilation/reserved_version.d(194): Error: version identifier `D_InlineAsm_X86_64` is reserved and cannot be set
+fail_compilation/reserved_version.d(195): Error: version identifier `D_LP64` is reserved and cannot be set
+fail_compilation/reserved_version.d(196): Error: version identifier `D_X32` is reserved and cannot be set
+fail_compilation/reserved_version.d(197): Error: version identifier `D_HardFloat` is reserved and cannot be set
+fail_compilation/reserved_version.d(198): Error: version identifier `D_SoftFloat` is reserved and cannot be set
+fail_compilation/reserved_version.d(199): Error: version identifier `D_PIC` is reserved and cannot be set
+fail_compilation/reserved_version.d(200): Error: version identifier `D_SIMD` is reserved and cannot be set
+fail_compilation/reserved_version.d(201): Error: version identifier `D_Version2` is reserved and cannot be set
+fail_compilation/reserved_version.d(202): Error: version identifier `D_NoBoundsChecks` is reserved and cannot be set
+fail_compilation/reserved_version.d(205): Error: version identifier `all` is reserved and cannot be set
+fail_compilation/reserved_version.d(206): Error: version identifier `none` is reserved and cannot be set
+fail_compilation/reserved_version.d(207): Error: version identifier `AsmJS` is reserved and cannot be set
+fail_compilation/reserved_version.d(208): Error: version identifier `Emscripten` is reserved and cannot be set
+fail_compilation/reserved_version.d(209): Error: version identifier `WebAssembly` is reserved and cannot be set
+fail_compilation/reserved_version.d(210): Error: version identifier `WASI` is reserved and cannot be set
+fail_compilation/reserved_version.d(211): Error: version identifier `CppRuntime_Clang` is reserved and cannot be set
+fail_compilation/reserved_version.d(212): Error: version identifier `CppRuntime_DigitalMars` is reserved and cannot be set
+fail_compilation/reserved_version.d(213): Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set
+fail_compilation/reserved_version.d(214): Error: version identifier `CppRuntime_Microsoft` is reserved and cannot be set
+fail_compilation/reserved_version.d(215): Error: version identifier `CppRuntime_Sun` is reserved and cannot be set
+fail_compilation/reserved_version.d(216): Error: version identifier `D_PIE` is reserved and cannot be set
+fail_compilation/reserved_version.d(217): Error: version identifier `AVR` is reserved and cannot be set
---
*/
@@ -119,6 +130,9 @@ version = Win32;
version = Win64;
version = linux;
version = OSX;
+version = iOS;
+version = TVOS;
+version = WatchOS;
version = FreeBSD;
version = OpenBSD;
version = NetBSD;
@@ -188,7 +202,9 @@ version = CRuntime_DigitalMars;
version = CRuntime_Glibc;
version = CRuntime_Microsoft;
version = CRuntime_Musl;
+version = CRuntime_Newlib;
version = CRuntime_UClibc;
+version = CRuntime_WASI;
version = D_Coverage;
version = D_Ddoc;
version = D_InlineAsm_X86;
@@ -205,11 +221,17 @@ version = D_NoBoundsChecks;
//version = assert;
version = all;
version = none;
+version = AsmJS;
+version = Emscripten;
+version = WebAssembly;
+version = WASI;
version = CppRuntime_Clang;
version = CppRuntime_DigitalMars;
version = CppRuntime_Gcc;
version = CppRuntime_Microsoft;
version = CppRuntime_Sun;
+version = D_PIE;
+version = AVR;
// This should work though
debug = DigitalMars;
@@ -276,6 +298,8 @@ debug = SystemZ;
debug = HPPA;
debug = HPPA64;
debug = SH;
+debug = WebAssembly;
+debug = WASI;
debug = Alpha;
debug = Alpha_SoftFloat;
debug = Alpha_HardFloat;
@@ -288,7 +312,9 @@ debug = CRuntime_DigitalMars;
debug = CRuntime_Glibc;
debug = CRuntime_Microsoft;
debug = CRuntime_Musl;
+debug = CRuntime_Newlib;
debug = CRuntime_UClibc;
+debug = CRuntime_WASI;
debug = CppRuntime_Clang;
debug = CppRuntime_DigitalMars;
debug = CppRuntime_Gcc;
@@ -303,6 +329,7 @@ debug = D_X32;
debug = D_HardFloat;
debug = D_SoftFloat;
debug = D_PIC;
+debug = D_PIE;
debug = D_SIMD;
debug = D_Version2;
debug = D_NoBoundsChecks;
@@ -312,3 +339,4 @@ debug = all;
debug = none;
debug = D_P16;
debug = MSP430;
+debug = AVR;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d b/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d
index 0259273..b8b6fa4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d
@@ -34,6 +34,7 @@
// REQUIRED_ARGS: -version=ARM_SoftFP
// REQUIRED_ARGS: -version=ARM_HardFloat
// REQUIRED_ARGS: -version=AArch64
+// REQUIRED_ARGS: -version=AVR
// REQUIRED_ARGS: -version=Epiphany
// REQUIRED_ARGS: -version=PPC
// REQUIRED_ARGS: -version=PPC_SoftFloat
@@ -64,6 +65,8 @@
// REQUIRED_ARGS: -version=HPPA
// REQUIRED_ARGS: -version=HPPA64
// REQUIRED_ARGS: -version=SH
+// REQUIRED_ARGS: -version=WebAssembly
+// REQUIRED_ARGS: -version=WASI
// REQUIRED_ARGS: -version=Alpha
// REQUIRED_ARGS: -version=Alpha_SoftFloat
// REQUIRED_ARGS: -version=Alpha_HardFloat
@@ -76,7 +79,9 @@
// REQUIRED_ARGS: -version=CRuntime_Glibc
// REQUIRED_ARGS: -version=CRuntime_Microsoft
// REQUIRED_ARGS: -version=CRuntime_Musl
+// REQUIRED_ARGS: -version=CRuntime_Newlib
// REQUIRED_ARGS: -version=CRuntime_UClibc
+// REQUIRED_ARGS: -version=CRuntime_WASI
// REQUIRED_ARGS: -version=CppRuntime_Clang
// REQUIRED_ARGS: -version=CppRuntime_DigitalMars
// REQUIRED_ARGS: -version=CppRuntime_Gcc
@@ -160,6 +165,8 @@
// REQUIRED_ARGS: -debug=HPPA
// REQUIRED_ARGS: -debug=HPPA64
// REQUIRED_ARGS: -debug=SH
+// REQUIRED_ARGS: -debug=WebAssembly
+// REQUIRED_ARGS: -debug=WASI
// REQUIRED_ARGS: -debug=Alpha
// REQUIRED_ARGS: -debug=Alpha_SoftFloat
// REQUIRED_ARGS: -debug=Alpha_HardFloat
@@ -172,7 +179,9 @@
// REQUIRED_ARGS: -debug=CRuntime_Glibc
// REQUIRED_ARGS: -debug=CRuntime_Microsoft
// REQUIRED_ARGS: -debug=CRuntime_Musl
+// REQUIRED_ARGS: -debug=CRuntime_Newlib
// REQUIRED_ARGS: -debug=CRuntime_UClibc
+// REQUIRED_ARGS: -debug=CRuntime_WASI
// REQUIRED_ARGS: -debug=CppRuntime_Clang
// REQUIRED_ARGS: -debug=CppRuntime_DigitalMars
// REQUIRED_ARGS: -debug=CppRuntime_Gcc
@@ -231,6 +240,7 @@ Error: version identifier `ARM_SoftFloat` is reserved and cannot be set
Error: version identifier `ARM_SoftFP` is reserved and cannot be set
Error: version identifier `ARM_HardFloat` is reserved and cannot be set
Error: version identifier `AArch64` is reserved and cannot be set
+Error: version identifier `AVR` is reserved and cannot be set
Error: version identifier `Epiphany` is reserved and cannot be set
Error: version identifier `PPC` is reserved and cannot be set
Error: version identifier `PPC_SoftFloat` is reserved and cannot be set
@@ -261,6 +271,8 @@ Error: version identifier `SystemZ` is reserved and cannot be set
Error: version identifier `HPPA` is reserved and cannot be set
Error: version identifier `HPPA64` is reserved and cannot be set
Error: version identifier `SH` is reserved and cannot be set
+Error: version identifier `WebAssembly` is reserved and cannot be set
+Error: version identifier `WASI` is reserved and cannot be set
Error: version identifier `Alpha` is reserved and cannot be set
Error: version identifier `Alpha_SoftFloat` is reserved and cannot be set
Error: version identifier `Alpha_HardFloat` is reserved and cannot be set
@@ -273,7 +285,9 @@ Error: version identifier `CRuntime_DigitalMars` is reserved and cannot be set
Error: version identifier `CRuntime_Glibc` is reserved and cannot be set
Error: version identifier `CRuntime_Microsoft` is reserved and cannot be set
Error: version identifier `CRuntime_Musl` is reserved and cannot be set
+Error: version identifier `CRuntime_Newlib` is reserved and cannot be set
Error: version identifier `CRuntime_UClibc` is reserved and cannot be set
+Error: version identifier `CRuntime_WASI` is reserved and cannot be set
Error: version identifier `CppRuntime_Clang` is reserved and cannot be set
Error: version identifier `CppRuntime_DigitalMars` is reserved and cannot be set
Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retref2.d b/gcc/testsuite/gdc.test/fail_compilation/retref2.d
index 037c258..aaa5b41 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/retref2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/retref2.d
@@ -1,11 +1,8 @@
-
-// REQUIRED_ARGS: -dip25
-
/*
TEST_OUTPUT:
---
-fail_compilation/retref2.d(21): Error: function retref2.D.foo does not override any function, did you mean to override 'retref2.C.foo'?
-fail_compilation/retref2.d(22): Error: function retref2.D.bar does not override any function, did you mean to override 'retref2.C.bar'?
+fail_compilation/retref2.d(18): Error: function `ref int retref2.D.foo(return ref int)` does not override any function, did you mean to override `ref int retref2.C.foo(ref int)`?
+fail_compilation/retref2.d(19): Error: function `ref scope int retref2.D.bar() return` does not override any function, did you mean to override `ref int retref2.C.bar()`?
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope.d b/gcc/testsuite/gdc.test/fail_compilation/retscope.d
index 35efda3..58f0430 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/retscope.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope.d
@@ -1,14 +1,13 @@
/*
-REQUIRED_ARGS: -dip1000
-PERMUTE_ARGS:
+REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/retscope.d(23): Error: scope variable `p` may not be returned
-fail_compilation/retscope.d(33): Error: returning `b ? nested1(& i) : nested2(& j)` escapes a reference to local variable `j`
-fail_compilation/retscope.d(46): Error: scope variable `p` assigned to non-scope `q`
-fail_compilation/retscope.d(48): Error: address of variable `i` assigned to `q` with longer lifetime
-fail_compilation/retscope.d(49): Error: variadic variable `a` assigned to non-scope `b`
-fail_compilation/retscope.d(50): Error: reference to stack allocated value returned by `(*fp2)()` assigned to non-scope `q`
+fail_compilation/retscope.d(22): Error: scope variable `p` may not be returned
+fail_compilation/retscope.d(32): Error: returning `b ? nested1(& i) : nested2(& j)` escapes a reference to local variable `j`
+fail_compilation/retscope.d(45): Error: scope variable `p` assigned to non-scope `q`
+fail_compilation/retscope.d(47): Error: address of variable `i` assigned to `q` with longer lifetime
+fail_compilation/retscope.d(48): Error: scope variable `a` assigned to non-scope `b`
+fail_compilation/retscope.d(49): Error: address of struct temporary returned by `(*fp2)()` assigned to longer lived variable `q`
---
*/
@@ -55,8 +54,8 @@ void test2(scope int* p, int[] a ...) @safe
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(76): Error: function retscope.HTTP.Impl.onReceive is @nogc yet allocates closures with the GC
-fail_compilation/retscope.d(78): retscope.HTTP.Impl.onReceive.__lambda1 closes over variable this at fail_compilation/retscope.d(76)
+fail_compilation/retscope.d(75): Error: function `retscope.HTTP.Impl.onReceive` is `@nogc` yet allocates closures with the GC
+fail_compilation/retscope.d(77): retscope.HTTP.Impl.onReceive.__lambda1 closes over variable this at fail_compilation/retscope.d(75)
---
*/
@@ -86,7 +85,7 @@ struct HTTP
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(97): Error: reference to local variable `sa` assigned to non-scope parameter `a` calling retscope.bar8
+fail_compilation/retscope.d(96): Error: reference to local variable `sa` assigned to non-scope parameter `a` calling retscope.bar8
---
*/
// https://issues.dlang.org/show_bug.cgi?id=8838
@@ -108,7 +107,7 @@ int[] bar8(int[] a) @safe
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(124): Error: returning `foo9(cast(char[])tmp)` escapes a reference to local variable `tmp`
+fail_compilation/retscope.d(123): Error: returning `foo9(cast(char[])tmp)` escapes a reference to local variable `tmp`
---
*/
@@ -129,7 +128,7 @@ char[] bar9() @safe
/*
//
//
-//fail_compilation/retscope.d(143): To enforce @safe compiler allocates a closure unless the opApply() uses 'scope'
+//fail_compilation/retscope.d(143): To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`
//
*/
@@ -150,7 +149,7 @@ S10* test10()
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(159): Error: scope variable `this` may not be returned
+fail_compilation/retscope.d(158): Error: scope variable `this` may not be returned
---
*/
@@ -165,7 +164,7 @@ class C11
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(178): Error: address of variable `i` assigned to `p` with longer lifetime
+fail_compilation/retscope.d(177): Error: address of variable `i` assigned to `p` with longer lifetime
---
*/
@@ -182,7 +181,7 @@ void foo11() @safe
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(198): Error: scope variable `e` may not be returned
+fail_compilation/retscope.d(197): Error: scope variable `e` may not be returned
---
*/
@@ -202,7 +201,7 @@ void* escapeDg1(scope void* d) @safe
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(213): Error: scope variable `p` assigned to non-scope `e`
+fail_compilation/retscope.d(212): Error: scope variable `p` assigned to non-scope `e.e`
---
*/
struct Escaper3 { void* e; }
@@ -219,7 +218,7 @@ void* escape3 (scope void* p) @safe {
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(230): Error: scope variable `ptr` may not be returned
+fail_compilation/retscope.d(229): Error: scope variable `ptr` may not be returned
---
*/
@@ -235,10 +234,10 @@ void* funretscope(scope dg_t ptr) @safe
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda1` of type `void* delegate() pure nothrow @nogc return @safe` to `void* delegate() @safe`
-fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda1` of type `void* delegate() pure nothrow @nogc return @safe` to `void* delegate() @safe`
-fail_compilation/retscope.d(250): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc return @safe` to `void* delegate() @safe`
-fail_compilation/retscope.d(250): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc return @safe` to `void* delegate() @safe`
+fail_compilation/retscope.d(248): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() @safe`
+fail_compilation/retscope.d(248): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() @safe`
+fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda4` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() @safe`
+fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda4` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() @safe`
---
*/
@@ -255,7 +254,7 @@ void escape4() @safe
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(267): Error: cannot take address of scope local p in @safe function escape5
+fail_compilation/retscope.d(266): Error: cannot take address of `scope` local `p` in `@safe` function `escape5`
---
*/
@@ -272,7 +271,7 @@ void escape5() @safe
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(287): Error: returning `foo6(& b)` escapes a reference to local variable `b`
+fail_compilation/retscope.d(286): Error: returning `foo6(& b)` escapes a reference to local variable `b`
---
*/
@@ -308,7 +307,7 @@ char*[3] escape9(scope char*[] p) @safe { return p[0 .. 3]; }
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(320): Error: reference to local variable `i` assigned to non-scope `f`
+fail_compilation/retscope.d(319): Error: reference to local variable `i` assigned to non-scope `f`
---
*/
@@ -332,7 +331,7 @@ int* bar10( scope int** ptr ) @safe
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(343): Error: cannot take address of scope local aa in @safe function escape11
+fail_compilation/retscope.d(342): Error: cannot take address of `scope` local `aa` in `@safe` function `escape11`
---
*/
@@ -455,7 +454,7 @@ fail_compilation/retscope.d(1311): Error: scope variable `u2` assigned to `ek` w
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(1405): Error: reference to local variable `buf` assigned to non-scope parameter `unnamed` calling retscope.myprintf
+fail_compilation/retscope.d(1405): Error: reference to local variable `buf` assigned to non-scope parameter `__anonymous_param` calling retscope.myprintf
---
*/
@@ -473,7 +472,7 @@ fail_compilation/retscope.d(1405): Error: reference to local variable `buf` assi
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(1509): Error: reference to stack allocated value returned by `(*fp15)()` assigned to non-scope parameter `unnamed`
+fail_compilation/retscope.d(1509): Error: reference to stack allocated value returned by `(*fp15)()` assigned to non-scope parameter `__anonymous_param`
---
*/
@@ -506,9 +505,9 @@ void foo16() @nogc nothrow
TEST_OUTPUT:
---
fail_compilation/retscope.d(1701): Error: cannot implicitly convert expression `& func` of type `int* function(int* p)` to `int* function(scope int* p)`
-fail_compilation/retscope.d(1702): Error: cannot implicitly convert expression `& func` of type `int* function(int* p)` to `int* function(return scope int* p)`
+fail_compilation/retscope.d(1702): Error: cannot implicitly convert expression `& func` of type `int* function(int* p)` to `int* function(return int* p)`
fail_compilation/retscope.d(1703): Error: cannot implicitly convert expression `& func` of type `int* function(int* p)` to `int* function(return scope int* p)`
-fail_compilation/retscope.d(1711): Error: cannot implicitly convert expression `& funcr` of type `int* function(return scope int* p)` to `int* function(scope int* p)`
+fail_compilation/retscope.d(1711): Error: cannot implicitly convert expression `& funcr` of type `int* function(return int* p)` to `int* function(scope int* p)`
fail_compilation/retscope.d(1716): Error: cannot implicitly convert expression `& funcrs` of type `int* function(return scope int* p)` to `int* function(scope int* p)`
---
*/
@@ -660,3 +659,31 @@ int test21()
foo22(s);
}
+/*********************************************
+TEST_OUTPUT:
+---
+fail_compilation/retscope.d(1907): Error: scope variable `x` assigned to `this` with longer lifetime
+fail_compilation/retscope.d(1913): Error: scope variable `x` may not be returned
+---
+*/
+#line 1900
+struct Constant
+{
+ int* member;
+
+ int* foo(scope Repeat!(int*) grid) @safe
+ {
+ foreach(ref x; grid)
+ member = x;
+
+ foreach(ref x; grid)
+ x = member;
+
+ foreach(ref x; grid)
+ return x;
+
+ return null;
+ }
+
+ alias Repeat(T...) = T;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope2.d b/gcc/testsuite/gdc.test/fail_compilation/retscope2.d
index a565008..8e6e0a4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/retscope2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope2.d
@@ -1,6 +1,5 @@
/*
-REQUIRED_ARGS: -dip1000
-PERMUTE_ARGS:
+REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
fail_compilation/retscope2.d(102): Error: scope variable `s` assigned to `p` with longer lifetime
@@ -87,9 +86,9 @@ fail_compilation/retscope2.d(504): Error: scope variable `c` may not be returned
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(604): Error: scope variable `_param_0` assigned to non-scope parameter `unnamed` calling retscope2.foo600
-fail_compilation/retscope2.d(604): Error: scope variable `_param_1` assigned to non-scope parameter `unnamed` calling retscope2.foo600
-fail_compilation/retscope2.d(614): Error: template instance retscope2.test600!(int*, int*) error instantiating
+fail_compilation/retscope2.d(604): Error: scope variable `_param_0` assigned to non-scope parameter `__anonymous_param` calling retscope2.foo600
+fail_compilation/retscope2.d(604): Error: scope variable `_param_1` assigned to non-scope parameter `__anonymous_param` calling retscope2.foo600
+fail_compilation/retscope2.d(614): Error: template instance `retscope2.test600!(int*, int*)` error instantiating
---
*/
@@ -124,7 +123,7 @@ fail_compilation/retscope2.d(721): Error: returning `s.get1()` escapes a referen
#line 700
// https://issues.dlang.org/show_bug.cgi?id=17049
-@safe S700* get2(return ref scope S700 _this)
+@safe S700* get2(return ref S700 _this)
{
return &_this;
}
@@ -164,12 +163,12 @@ void foo800()
}
/*************************************************/
-/+
-/*
-XEST_OUTPUT:
+/*
+TEST_OUTPUT:
+---
fail_compilation/retscope2.d(907): Error: address of variable `this` assigned to `p17568` with longer lifetime
-
+---
*/
#line 900
@@ -183,14 +182,15 @@ struct T17568
p17568 = &a;
}
}
-+/
+
/*************************************************/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(1005): Error: scope variable `p` assigned to `this` with longer lifetime
-fail_compilation/retscope2.d(1024): Error: scope variable `p` assigned to `d` with longer lifetime
+fail_compilation/retscope2.d(1005): Error: scope variable `p` assigned to non-scope `this._p`
+fail_compilation/retscope2.d(1021): Error: scope variable `p` assigned to non-scope `c._p`
+fail_compilation/retscope2.d(1024): Error: scope variable `p` assigned to non-scope `d._p`
---
*/
@@ -216,7 +216,7 @@ void test17428() @safe
int x;
int* p = &x;
scope C17428b c;
- c._p = p; // ok
+ c._p = p; // bad
C17428b d;
d._p = p; // bad
@@ -291,5 +291,28 @@ struct T17388
return t.foo();
}
+/****************************************************/
+/*
+TEST_OUTPUT:
+---
+fail_compilation/retscope2.d(1306): Error: copying `& i` into allocated memory escapes a reference to local variable `i`
+---
+*/
+
+#line 1300
+
+// https://issues.dlang.org/show_bug.cgi?id=17370
+
+void test1300() @safe
+{
+ int i;
+ auto p = new S1300(&i).oops;
+}
+
+struct S1300
+{
+ int* oops;
+// this(int* p) @safe { oops = p; }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope3.d b/gcc/testsuite/gdc.test/fail_compilation/retscope3.d
new file mode 100644
index 0000000..130d49b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope3.d
@@ -0,0 +1,130 @@
+/*
+REQUIRED_ARGS: -preview=dip1000
+*/
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/retscope3.d(2008): Error: copying `& i` into allocated memory escapes a reference to local variable `i`
+fail_compilation/retscope3.d(2017): Error: copying `S2000(& i)` into allocated memory escapes a reference to local variable `i`
+---
+*/
+
+#line 2000
+
+// https://issues.dlang.org/show_bug.cgi?id=17790
+
+@safe:
+
+int* bar1()
+{
+ int i;
+ int*[] arr = [ &i ];
+ return arr[0];
+}
+
+struct S2000 { int* p; }
+
+S2000 bar2()
+{
+ int i;
+ S2000[] arr = [ S2000(&i) ];
+ return arr[0];
+}
+
+void bar3(string[] u...) @safe pure nothrow @nogc
+{
+ foreach (str; u)
+ {
+ }
+}
+
+void bar4()
+{
+ static struct S { int* p; }
+ S[2][10] pairs;
+ foreach (ref pair; pairs)
+ {
+ }
+}
+
+/**********************************************/
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/retscope3.d(3027): Error: scope variable `l` assigned to `elem` with longer lifetime
+---
+*/
+
+#line 3000
+
+struct List
+{
+ Elem front() @safe return scope;
+
+ ~this() @trusted scope;
+
+ @disable this(this);
+
+ void* data;
+}
+
+struct Elem
+{
+ void* data;
+}
+
+List list() @trusted
+{
+ return List();
+}
+
+void test3000() @safe
+{
+ Elem elem;
+ {
+ auto l = list(); // inferred as scope
+ elem = l.front; // escapes, b/c l isn't scoped
+ }
+}
+
+/**********************************************/
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/retscope3.d(4003): Error: copying `u[]` into allocated memory escapes a reference to variadic parameter `u`
+fail_compilation/retscope3.d(4016): Error: storing reference to outer local variable `i` into allocated memory causes it to escape
+fail_compilation/retscope3.d(4025): Error: storing reference to stack allocated value returned by `makeSA()` into allocated memory causes it to escape
+---
+*/
+
+#line 4000
+
+void bar4000(int[1] u...) @safe
+{
+ int[][] n = [u[]];
+}
+
+void bar4001() @safe
+{
+ static int i;
+ int*[] n = [&i];
+}
+
+ref int bar4002(return ref int i) @safe
+{
+ void nested()
+ {
+ int*[] n = [&i];
+ }
+ return i;
+}
+
+int[3] makeSA() @safe;
+
+void bar4003() @safe
+{
+ int[][] a = [makeSA()[]];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope4.d b/gcc/testsuite/gdc.test/fail_compilation/retscope4.d
new file mode 100644
index 0000000..e5fc278
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope4.d
@@ -0,0 +1,21 @@
+/*
+REQUIRED_ARGS: -de
+*/
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/retscope4.d(3007): Deprecation: slice of static array temporary returned by `func()` assigned to longer lived variable `a`
+---
+*/
+
+#line 3000
+
+// https://issues.dlang.org/show_bug.cgi?id=12625
+
+int[16] func();
+
+void foo()
+{
+ int[] a = func();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope5.d b/gcc/testsuite/gdc.test/fail_compilation/retscope5.d
new file mode 100644
index 0000000..1f9906e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope5.d
@@ -0,0 +1,26 @@
+/*
+REQUIRED_ARGS: -preview=dip1000
+*/
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/retscope5.d(5010): Error: reference `t` assigned to `p` with longer lifetime
+---
+*/
+
+#line 5000
+
+// https://issues.dlang.org/show_bug.cgi?id=17725
+
+void test() @safe
+{
+ int* p;
+ struct T {
+ int a;
+ }
+ void escape(ref T t) @safe {
+ p = &t.a; // should not compile
+ }
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d
new file mode 100644
index 0000000..47f216f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d
@@ -0,0 +1,233 @@
+/*
+REQUIRED_ARGS: -preview=dip1000
+*/
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/retscope6.d(6007): Error: copying `& i` into allocated memory escapes a reference to local variable `i`
+---
+*/
+
+#line 6000
+
+// https://issues.dlang.org/show_bug.cgi?id=17795
+
+int* test() @safe
+{
+ int i;
+ int*[][] arr = new int*[][](1);
+ arr[0] ~= &i;
+ return arr[0][0];
+}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/retscope6.d(7034): Error: address of variable `i` assigned to `s` with longer lifetime
+fail_compilation/retscope6.d(7035): Error: address of variable `i` assigned to `s` with longer lifetime
+fail_compilation/retscope6.d(7025): Error: scope variable `_param_2` assigned to `t` with longer lifetime
+fail_compilation/retscope6.d(7037): Error: template instance `retscope6.S.emplace4!(int*)` error instantiating
+fail_compilation/retscope6.d(7037): Error: address of variable `i` assigned to `s` with longer lifetime
+---
+*/
+
+#line 7000
+
+alias T = int*;
+
+struct S
+{
+ T payload;
+
+ static void emplace(Args...)(ref S s, Args args) @safe
+ {
+ s.payload = args[0];
+ }
+
+ void emplace2(Args...)(Args args) @safe
+ {
+ payload = args[0];
+ }
+
+ static void emplace3(Args...)(S s, Args args) @safe
+ {
+ s.payload = args[0];
+ }
+
+ static void emplace4(Args...)(scope ref S s, scope out S t, scope Args args) @safe
+ {
+ s.payload = args[0];
+ t.payload = args[0];
+ }
+
+}
+
+void foo() @safe
+{
+ S s;
+ int i;
+ s.emplace(s, &i);
+ s.emplace2(&i);
+ s.emplace3(s, &i);
+ s.emplace4(s, s, &i);
+}
+
+
+/* TEST_OUTPUT:
+---
+fail_compilation/retscope6.d(8016): Error: address of variable `i` assigned to `p` with longer lifetime
+fail_compilation/retscope6.d(8031): Error: reference to local variable `i` assigned to non-scope parameter `p` calling retscope6.betty!().betty
+fail_compilation/retscope6.d(8031): Error: reference to local variable `j` assigned to non-scope parameter `q` calling retscope6.betty!().betty
+fail_compilation/retscope6.d(8048): Error: reference to local variable `j` assigned to non-scope parameter `q` calling retscope6.archie!().archie
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=19035
+
+#line 8000
+@safe
+{
+
+void escape(int*);
+
+/**********************/
+
+void frank()(ref scope int* p, int* s)
+{
+ p = s; // should error here
+}
+
+void testfrankly()
+{
+ int* p;
+ int i;
+ frank(p, &i);
+}
+
+/**********************/
+
+void betty()(int* p, int* q)
+{
+ p = q;
+ escape(p);
+}
+
+void testbetty()
+{
+ int i;
+ int j;
+ betty(&i, &j); // should error on i and j
+}
+
+/**********************/
+
+void archie()(int* p, int* q, int* r)
+{
+ p = q;
+ r = p;
+ escape(q);
+}
+
+void testarchie()
+{
+ int i;
+ int j;
+ int k;
+ archie(&i, &j, &k); // should error on j
+}
+
+}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/retscope6.d(9022): Error: returning `fred(& i)` escapes a reference to local variable `i`
+---
+*/
+
+#line 9000
+
+@safe:
+
+alias T9 = S9!(); struct S9()
+{
+ this(int* q)
+ {
+ this.p = q;
+ }
+
+ int* p;
+}
+
+auto fred(int* r)
+{
+ return T9(r);
+}
+
+T9 testfred()
+{
+ int i;
+ auto j = fred(&i); // ok
+ return fred(&i); // error
+}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/retscope6.d(10003): Error: scope variable `values` assigned to non-scope parameter `values` calling retscope6.escape
+---
+*/
+
+#line 10000
+
+void variadicCaller(int[] values...)
+{
+ escape(values);
+}
+
+void escape(int[] values) {}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/retscope6.d(11004): Error: address of variable `buffer` assigned to `secret` with longer lifetime
+---
+*/
+
+#line 11000
+
+void hmac(scope ubyte[] secret)
+{
+ ubyte[10] buffer;
+ secret = buffer[];
+}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/retscope6.d(12011): Error: reference to local variable `x` assigned to non-scope parameter `r` calling retscope6.escape_m_20150
+fail_compilation/retscope6.d(12022): Error: reference to local variable `x` assigned to non-scope parameter `r` calling retscope6.escape_c_20150
+---
+*/
+
+#line 12000
+
+// https://issues.dlang.org/show_bug.cgi?id=20150
+
+int* escape_m_20150(int* r) @safe pure
+{
+ return r;
+}
+
+int* f_m_20150() @safe
+{
+ int x = 42;
+ return escape_m_20150(&x);
+}
+
+const(int)* escape_c_20150(const int* r) @safe pure
+{
+ return r;
+}
+
+const(int)* f_c_20150() @safe
+{
+ int x = 42;
+ return escape_c_20150(&x);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/scope_class.d b/gcc/testsuite/gdc.test/fail_compilation/scope_class.d
new file mode 100644
index 0000000..b70e3eb
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/scope_class.d
@@ -0,0 +1,21 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/scope_class.d(11): Error: functions cannot return `scope scope_class.C`
+---
+*/
+
+
+scope class C { int i; } // Notice the use of `scope` here
+
+C increment(C c)
+{
+ c.i++;
+ return c;
+}
+
+void main()
+{
+ scope C c = new C();
+ c.increment();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/scope_type.d b/gcc/testsuite/gdc.test/fail_compilation/scope_type.d
new file mode 100644
index 0000000..b087411
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/scope_type.d
@@ -0,0 +1,12 @@
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/scope_type.d(11): Deprecation: `scope` as a type constraint is deprecated. Use `scope` at the usage site.
+---
+*/
+
+
+scope class C { }
+scope interface I { }
+//scope struct S { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/shared.d b/gcc/testsuite/gdc.test/fail_compilation/shared.d
new file mode 100644
index 0000000..6011d17
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/shared.d
@@ -0,0 +1,227 @@
+/* REQUIRED_ARGS: -preview=nosharedaccess
+ * TEST_OUTPUT:
+---
+fail_compilation/shared.d(1010): Error: direct access to shared `j` is not allowed, see `core.atomic`
+fail_compilation/shared.d(1011): Error: direct access to shared `j` is not allowed, see `core.atomic`
+fail_compilation/shared.d(1012): Error: direct access to shared `*p` is not allowed, see `core.atomic`
+fail_compilation/shared.d(1013): Error: direct access to shared `a[0]` is not allowed, see `core.atomic`
+fail_compilation/shared.d(1014): Error: direct access to shared `s.si` is not allowed, see `core.atomic`
+fail_compilation/shared.d(1015): Error: direct access to shared `t.i` is not allowed, see `core.atomic`
+---
+*/
+
+#line 1000
+
+struct S
+{
+ shared(int) si;
+ int i;
+}
+
+int test1(shared int j, shared(int)* p, shared(int)[] a, ref S s, ref shared S t)
+{
+ int i;
+ j = i;
+ i = j;
+ i = *p;
+ i = a[0];
+ i = s.si;
+ return t.i;
+}
+
+/**************************************/
+
+void byref(ref shared int);
+void byptr(shared(int)*);
+
+shared int x;
+
+void test2()
+{
+ byref(x); // ok
+ byptr(&x); // ok
+}
+
+/**************************************/
+
+/*
+ * TEST_OUTPUT:
+---
+fail_compilation/shared.d(2008): Error: direct access to shared `i` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2009): Error: direct access to shared `j` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2010): Error: direct access to shared `k` is not allowed, see `core.atomic`
+---
+ */
+
+#line 2000
+
+void func(int);
+
+shared int i;
+
+void test3(shared int k)
+{
+ shared int j = void;
+ func(i);
+ func(j);
+ func(k);
+}
+
+/**************************************/
+
+void test4() // no errors for initialization
+{
+ shared int x;
+ shared int y = 3;
+}
+
+/*
+ * TEST_OUTPUT:
+---
+fail_compilation/shared.d(2105): Error: direct access to shared `*pi` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2112): Error: direct access to shared `**pi` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2136): Error: direct access to shared `*c` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2142): Error: direct access to shared `*c` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2148): Error: direct access to shared `*c` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2154): Error: direct access to shared `*c.c1` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2160): Error: direct access to shared `*c.c1.c1` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2181): Error: direct access to shared `k` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2187): Error: direct access to shared `k.k2.k1` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2194): Error: direct access to shared `(new shared(K2)).k1` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2202): Error: direct access to shared `c` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2206): Error: function `shared.test_inference_2` function returns `shared` but cannot be inferred `ref`
+fail_compilation/shared.d(2208): Error: returning `c` escapes a reference to parameter `c`
+fail_compilation/shared.d(2208): perhaps annotate the parameter with `return`
+fail_compilation/shared.d(2214): Error: function `shared.test_inference_3` function returns `shared` but cannot be inferred `ref`
+fail_compilation/shared.d(2216): return value `getSharedObject()` is not an lvalue
+fail_compilation/shared.d(2222): Error: direct access to shared `a` is not allowed, see `core.atomic`
+fail_compilation/shared.d(2220): Error: function `shared.test_inference_4` function returns `shared` but cannot be inferred `ref`
+fail_compilation/shared.d(2222): cannot implicitly convert `a` of type `shared(const(Object))` to `object.Object`
+fail_compilation/shared.d(2222): Error: cannot implicitly convert expression `a` of type `shared(const(Object))` to `object.Object`
+---
+ */
+#line 2100
+// Derived from https://issues.dlang.org/show_bug.cgi?id=20908
+ref shared(int) test20908()
+{
+ shared int* pi;
+ // Single indirection, but the pointer is `shared`
+ return *pi;
+}
+
+ref shared(int) test20908_2()
+{
+ shared(int*)* pi;
+ // Double indirection, external pointer is not `shared`
+ return **pi;
+}
+
+// DotVarExp tests: See matching tests in `compilable/shared.d`
+
+struct C1
+{
+ int value;
+}
+
+struct C2
+{
+ C1* c1;
+}
+
+struct C3
+{
+ C2 c1;
+ C2* c2;
+}
+
+// Reading a shared pointer: not okay
+ref shared(int) test_dotvarexp_1(return shared C1* c)
+{
+ return c.value;
+}
+
+// Ditto, but explicitly dereferenced
+ref shared(int) test_dotvarexp_2(return shared C1* c)
+{
+ return (*c).value;
+}
+
+// Even taking the address (which offset the pointers) requires a load
+shared(int)* test_dotvarexp_3(return shared C1* c)
+{
+ return &c.value;
+}
+
+// First level DotVarExp dereferencing
+ref shared(int) test_dotvarexp_4(return shared ref C2 c)
+{
+ return c.c1.value;
+}
+
+// Second level DotVarExp dereferencing
+ref shared(int) test_dotvarexp_5(return shared ref C3 c)
+{
+ return c.c1.c1.value;
+}
+
+class K1
+{
+ int value;
+}
+
+class K2
+{
+ shared K1 k1;
+}
+
+class K3
+{
+ K2 k2;
+}
+
+// A class is a pointer under the hood, and `shared` applies to the pointer
+ref shared(int) test_dotvarexp_6(return shared K1 k)
+{
+ return k.value;
+}
+
+// Using `k.ke.k1` would be okay, but not `value`
+ref shared(int) test_dotvarexp_7(return ref K3 k)
+{
+ return k.k2.k1.value;
+}
+
+// The returned value is `shared` so we shouldn't be able to access it
+// The pointer could already be shared, e.g. by the ctor
+ref shared(K1) test_newexp_1()
+{
+ return new shared(K2)().k1;
+}
+
+// Inference tests
+
+// Fails because no `ref`
+auto test_inference_1(return shared ref C3 c)
+{
+ return c;
+}
+
+// Fails because no `return` => Escapes
+auto ref test_inference_2(shared C3 c)
+{
+ return c;
+}
+
+shared(Object) getSharedObject() { assert(0); }
+
+// Fails because rvalue
+auto ref test_inference_3()
+{
+ return getSharedObject();
+}
+
+// Fails because `const` conversion
+auto ref Object test_inference_4(const return shared ref Object a)
+{
+ return a;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/skip.d b/gcc/testsuite/gdc.test/fail_compilation/skip.d
index c870e7e..0f3a9ec 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/skip.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/skip.d
@@ -2,8 +2,8 @@
* REQUIRED_ARGS: -de
* TEST_OUTPUT:
---
-fail_compilation/skip.d(21): Deprecation: 'switch' skips declaration of 'with' temporary at fail_compilation/skip.d(26)
-fail_compilation/skip.d(43): Deprecation: 'switch' skips declaration of variable skip.test14532.n at fail_compilation/skip.d(45)
+fail_compilation/skip.d(21): Error: `switch` skips declaration of `with` temporary at fail_compilation/skip.d(26)
+fail_compilation/skip.d(43): Error: `switch` skips declaration of variable `skip.test14532.n` at fail_compilation/skip.d(45)
---
*/
// https://issues.dlang.org/show_bug.cgi?id=10524
diff --git a/gcc/testsuite/gdc.test/fail_compilation/spell9644.d b/gcc/testsuite/gdc.test/fail_compilation/spell9644.d
index 383ec67..0c6d67b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/spell9644.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/spell9644.d
@@ -1,17 +1,16 @@
// REQUIRED_ARGS: -o-
-// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/spell9644a.d imports/spell9644b.d
/*
TEST_OUTPUT:
---
-fail_compilation/spell9644.d(27): Error: undefined identifier `b`
-fail_compilation/spell9644.d(28): Error: undefined identifier `xx`
-fail_compilation/spell9644.d(29): Error: undefined identifier `cb`, did you mean variable `ab`?
-fail_compilation/spell9644.d(30): Error: undefined identifier `bc`, did you mean variable `abc`?
-fail_compilation/spell9644.d(31): Error: undefined identifier `ccc`
-fail_compilation/spell9644.d(33): Error: undefined identifier `cor2`, did you mean variable `cor1`?
-fail_compilation/spell9644.d(34): Error: undefined identifier `pua`, did you mean variable `pub`?
-fail_compilation/spell9644.d(35): Error: undefined identifier `priw`
+fail_compilation/spell9644.d(26): Error: undefined identifier `b`
+fail_compilation/spell9644.d(27): Error: undefined identifier `xx`
+fail_compilation/spell9644.d(28): Error: undefined identifier `cb`, did you mean variable `ab`?
+fail_compilation/spell9644.d(29): Error: undefined identifier `bc`, did you mean variable `abc`?
+fail_compilation/spell9644.d(30): Error: undefined identifier `ccc`
+fail_compilation/spell9644.d(32): Error: undefined identifier `cor2`, did you mean variable `cor1`?
+fail_compilation/spell9644.d(33): Error: undefined identifier `pua`, did you mean variable `pub`?
+fail_compilation/spell9644.d(34): Error: undefined identifier `priw`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d b/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d
index 6a5a16d..1305bc5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/staticarrayoverflow.d
@@ -2,14 +2,14 @@
REQUIRED_ARGS: -m64
TEST_OUTPUT:
---
-fail_compilation/staticarrayoverflow.d(24): Error: static array `S[1879048192]` size overflowed to 7516192768000
-fail_compilation/staticarrayoverflow.d(24): Error: variable `staticarrayoverflow.y` size overflow
-fail_compilation/staticarrayoverflow.d(26): Error: static array `S[8070450532247928832]` size overflowed to 8070450532247928832
-fail_compilation/staticarrayoverflow.d(26): Error: variable `staticarrayoverflow.a` size overflow
-fail_compilation/staticarrayoverflow.d(27): Error: static array `S[0][18446744073709551615LU]` size overflowed to 18446744073709551615
-fail_compilation/staticarrayoverflow.d(27): Error: variable `staticarrayoverflow.b` size overflow
-fail_compilation/staticarrayoverflow.d(28): Error: static array `S[0][4294967295]` size overflowed to 4294967295
-fail_compilation/staticarrayoverflow.d(28): Error: variable `staticarrayoverflow.c` size overflow
+fail_compilation/staticarrayoverflow.d(23): Error: static array `S[1879048192]` size overflowed to 7516192768000
+fail_compilation/staticarrayoverflow.d(23): Error: variable `staticarrayoverflow.y` size overflow
+fail_compilation/staticarrayoverflow.d(25): Error: static array `S[8070450532247928832]` size overflowed to 8070450532247928832
+fail_compilation/staticarrayoverflow.d(25): Error: variable `staticarrayoverflow.a` size overflow
+fail_compilation/staticarrayoverflow.d(26): Error: static array `S[0][18446744073709551615LU]` size overflowed to 18446744073709551615
+fail_compilation/staticarrayoverflow.d(26): Error: variable `staticarrayoverflow.b` size overflow
+fail_compilation/staticarrayoverflow.d(27): Error: static array `S[0][4294967295]` size overflowed to 4294967295
+fail_compilation/staticarrayoverflow.d(27): Error: variable `staticarrayoverflow.c` size overflow
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/staticforeach4.d b/gcc/testsuite/gdc.test/fail_compilation/staticforeach4.d
new file mode 100644
index 0000000..93ba6e4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/staticforeach4.d
@@ -0,0 +1,17 @@
+/*
+REQUIRED_ARGS: -verrors=context
+TEST_OUTPUT:
+---
+fail_compilation/staticforeach4.d(16): Error: index type `byte` cannot cover index range 0..257
+static foreach (byte a, int b; data) { }
+ ^
+fail_compilation/staticforeach4.d(17): Error: index type `byte` cannot cover index range 0..257
+static foreach (byte a, int b; fn()) { }
+ ^
+---
+*/
+immutable int[257] data = 1;
+int[257] fn() { return data; }
+
+static foreach (byte a, int b; data) { }
+static foreach (byte a, int b; fn()) { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/switches.d b/gcc/testsuite/gdc.test/fail_compilation/switches.d
index c96ddb2..da66d0e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/switches.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/switches.d
@@ -1,8 +1,3 @@
-/*
-REQUIRED_ARGS:
-PERMUTE_ARGS:
-*/
-
/************************************************************/
/*
@@ -29,7 +24,7 @@ void test1(int i)
/*
TEST_OUTPUT:
---
-fail_compilation/switches.d(205): Error: no case statement following goto case;
+fail_compilation/switches.d(205): Error: no `case` statement following `goto case;`
---
*/
@@ -50,7 +45,7 @@ void test2(int i)
/*
TEST_OUTPUT:
---
-fail_compilation/switches.d(302): Deprecation: 'switch' skips declaration of variable switches.test3.j at fail_compilation/switches.d(306)
+fail_compilation/switches.d(302): Error: `switch` skips declaration of variable `switches.test3.j` at fail_compilation/switches.d(306)
---
*/
@@ -72,3 +67,29 @@ void test3(int i)
}
+/************************************************************/
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/switches.d(404): Error: `switch` skips declaration of variable `switches.test.z` at fail_compilation/switches.d(406)
+---
+*/
+
+#line 400
+// https://issues.dlang.org/show_bug.cgi?id=18858
+
+int test(int n)
+{
+ final switch(n)
+ {
+ int z = 5;
+ enum e = 6;
+
+ case 1:
+ int y = 2;
+ return y;
+ }
+}
+
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test10.d b/gcc/testsuite/gdc.test/fail_compilation/test10.d
new file mode 100644
index 0000000..4c14257
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test10.d
@@ -0,0 +1,12 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test10.d(10): Error: found `else` without a corresponding `if`, `version` or `debug` statement
+---
+*/
+
+void test(int i)
+{
+ ++i;
+ else
+ ++i;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test1021.d b/gcc/testsuite/gdc.test/fail_compilation/test1021.d
new file mode 100644
index 0000000..0792545
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test1021.d
@@ -0,0 +1,171 @@
+/* REQUIRED_ARGS: -preview=dip1021
+ */
+
+@safe:
+
+/* TEST_OUTPUT:
+---
+fail_compilation/test1021.d(1009): Error: more than one mutable reference of `p` in arguments to `test1021.fooa()`
+fail_compilation/test1021.d(1010): Error: mutable and const references of `p` in arguments to `test1021.foob()`
+fail_compilation/test1021.d(1011): Error: mutable and const references of `p` in arguments to `test1021.fooc()`
+fail_compilation/test1021.d(1013): Error: more than one mutable reference of `p` in arguments to `test1021.fooe()`
+---
+*/
+
+#line 1000
+
+void fooa(int*, int*);
+void foob(const(int)*, int*);
+void fooc(int*, const(int)*);
+void food(const(int)*, const(int)*);
+void fooe(int*, ...);
+
+void test1(int* p)
+{
+ fooa(p, p); // error
+ foob(p, p); // error
+ fooc(p, p); // error
+ food(p, p); // ok
+ fooe(p, p); // error
+}
+
+/***********************************/
+
+/* TEST_OUTPUT:
+---
+fail_compilation/test1021.d(2010): Error: more than one mutable reference to `i` in arguments to `test1021.fopa()`
+fail_compilation/test1021.d(2011): Error: mutable and const references to `i` in arguments to `test1021.fopb()`
+fail_compilation/test1021.d(2012): Error: mutable and const references to `i` in arguments to `test1021.fopc()`
+fail_compilation/test1021.d(2014): Error: more than one mutable reference to `i` in arguments to `test1021.fope()`
+---
+*/
+
+#line 2000
+
+void fopa(ref int, scope int*);
+void fopb(ref int, scope const int*);
+void fopc(ref const int, scope int*);
+void fopd(ref const int, scope const int*);
+inout(int) fope(ref inout int, scope int*);
+void test2()
+{
+ int i;
+ @trusted int* toPtr(ref int i) { return &i; }
+ fopa(i, toPtr(i)); // error
+ fopb(i, toPtr(i)); // error
+ fopc(i, toPtr(i)); // error
+ fopd(i, toPtr(i)); // ok
+ fope(i, toPtr(i)); // error
+}
+
+/***********************************/
+
+/* TEST_OUTPUT:
+---
+fail_compilation/test1021.d(3015): Error: more than one mutable reference to `s` in arguments to `test1021.S.method()`
+fail_compilation/test1021.d(3019): Error: more than one mutable reference of `c` in arguments to `test1021.C.method()`
+---
+*/
+
+#line 3000
+
+struct S
+{
+ void method(ref S s);
+}
+
+class C
+{
+ void method(C c);
+}
+
+void test3()
+{
+ S s;
+ S* ps;
+ s.method(s); // error
+ ps.method(s); // ok
+
+ C c;
+ c.method(c); // error
+}
+
+/***********************************/
+
+/* TEST_OUTPUT:
+---
+fail_compilation/test1021.d(4008): Error: more than one mutable reference to `i` in arguments to `test1021.test4.nested()`
+---
+*/
+
+#line 4000
+
+void test4()
+{
+ int i, k;
+ int nested(ref int j)
+ {
+ return i + j;
+ }
+ nested(i); // error
+ nested(k); // ok
+}
+
+/***********************************/
+
+/* TEST_OUTPUT:
+---
+fail_compilation/test1021.d(5012): Error: more than one mutable reference of `s` in arguments to `test1021.foo5()`
+---
+*/
+
+#line 5000
+
+struct S5
+{
+ int i;
+ int* p;
+}
+
+void foo5(S5, S5);
+
+void test5()
+{
+ S5 s;
+ foo5(s, s);
+}
+
+alias A5 = void delegate() const;
+
+void foo5(A5, A5);
+
+void test5a()
+{
+ A5 a;
+ foo5(a, a);
+}
+
+alias B5 = void function();
+
+void foo5(B5, B5);
+
+void test5b()
+{
+ B5 b;
+ foo5(b, b);
+}
+
+struct S5c
+{
+ void function() fp;
+}
+
+void foo5(S5c, S5c);
+
+void test5c()
+{
+ S5c s;
+ foo5(s, s);
+}
+
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test11006.d b/gcc/testsuite/gdc.test/fail_compilation/test11006.d
new file mode 100644
index 0000000..e7257b7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test11006.d
@@ -0,0 +1,11 @@
+/* REQUIRED_ARGS: -main -de
+ * TEST_OUTPUT:
+---
+fail_compilation/test11006.d(10): Deprecation: cannot subtract pointers to different types: `void*` and `int*`.
+fail_compilation/test11006.d(10): while evaluating: `static assert(2L == 2L)`
+fail_compilation/test11006.d(11): Deprecation: cannot subtract pointers to different types: `int*` and `void*`.
+fail_compilation/test11006.d(11): while evaluating: `static assert(8L == 8L)`
+---
+ */
+static assert(cast(void*)8 - cast(int*) 0 == 2L);
+static assert(cast(int*) 8 - cast(void*)0 == 8L);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test11047.d b/gcc/testsuite/gdc.test/fail_compilation/test11047.d
index ef8007d..2cbc9c6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test11047.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test11047.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/test11047.d(11): Error: value of x is not known at compile time
-fail_compilation/test11047.d(11): Error: value of x is not known at compile time
+fail_compilation/test11047.d(11): Error: value of `x` is not known at compile time
+fail_compilation/test11047.d(11): Error: value of `x` is not known at compile time
---
*/
// https://issues.dlang.org/show_bug.cgi?id=11047
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test11176.d b/gcc/testsuite/gdc.test/fail_compilation/test11176.d
index 020d807..6c94b40 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test11176.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test11176.d
@@ -1,9 +1,8 @@
/*
-REQUIRED_ARGS: -de
TEST_OUTPUT:
---
-fail_compilation/test11176.d(12): Deprecation: b.ptr cannot be used in @safe code, use &b[0] instead
-fail_compilation/test11176.d(16): Deprecation: b.ptr cannot be used in @safe code, use &b[0] instead
+fail_compilation/test11176.d(12): Error: `b.ptr` cannot be used in `@safe` code, use `&b[0]` instead
+fail_compilation/test11176.d(16): Error: `b.ptr` cannot be used in `@safe` code, use `&b[0]` instead
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test12228.d b/gcc/testsuite/gdc.test/fail_compilation/test12228.d
new file mode 100644
index 0000000..522bceb
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test12228.d
@@ -0,0 +1,21 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test12228.d(13): Error: Using `this` as a type is obsolete. Use `typeof(this)` instead
+fail_compilation/test12228.d(18): Error: no property `x` for type `object.Object`
+fail_compilation/test12228.d(19): Error: Using `super` as a type is obsolete. Use `typeof(super)` instead
+fail_compilation/test12228.d(20): Error: Using `super` as a type is obsolete. Use `typeof(super)` instead
+---
+*/
+
+class C
+{
+ shared(this) x;
+}
+
+class D : C
+{
+ alias x = typeof(super).x;
+ shared(super) a;
+ super b;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test12385.d b/gcc/testsuite/gdc.test/fail_compilation/test12385.d
new file mode 100644
index 0000000..cbba723
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test12385.d
@@ -0,0 +1,30 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test12385.d(29): Error: cannot modify `immutable` expression `unbundled.x`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=12385
+
+class BundledState
+{
+ string m_State;
+
+ int x = 3;
+
+ this(string state) immutable
+ {
+ m_State = state;
+ }
+}
+
+enum States : immutable(BundledState)
+{
+ unbundled = new immutable BundledState("bla"),
+}
+
+void main()
+{
+ States.unbundled.x = 6; // Modifies x.
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test12558.d b/gcc/testsuite/gdc.test/fail_compilation/test12558.d
new file mode 100644
index 0000000..5ff7c97
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test12558.d
@@ -0,0 +1,57 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test12558.d(32): Deprecation: `catch` statement without an exception specification is deprecated
+fail_compilation/test12558.d(32): use `catch(Throwable)` for old behavior
+fail_compilation/test12558.d(36): Deprecation: `catch` statement without an exception specification is deprecated
+fail_compilation/test12558.d(36): use `catch(Throwable)` for old behavior
+fail_compilation/test12558.d(43): Deprecation: `catch` statement without an exception specification is deprecated
+fail_compilation/test12558.d(43): use `catch(Throwable)` for old behavior
+fail_compilation/test12558.d(47): Deprecation: `catch` statement without an exception specification is deprecated
+fail_compilation/test12558.d(47): use `catch(Throwable)` for old behavior
+fail_compilation/test12558.d(56): Deprecation: `catch` statement without an exception specification is deprecated
+fail_compilation/test12558.d(56): use `catch(Throwable)` for old behavior
+fail_compilation/test12558.d(31): Error: `catch` statement without an exception specification is deprecated
+fail_compilation/test12558.d(31): use `catch(Throwable)` for old behavior
+fail_compilation/test12558.d(36): Error: `catch` statement without an exception specification is deprecated
+fail_compilation/test12558.d(36): use `catch(Throwable)` for old behavior
+fail_compilation/test12558.d(42): Error: `catch` statement without an exception specification is deprecated
+fail_compilation/test12558.d(42): use `catch(Throwable)` for old behavior
+fail_compilation/test12558.d(47): Error: `catch` statement without an exception specification is deprecated
+fail_compilation/test12558.d(47): use `catch(Throwable)` for old behavior
+---
+*/
+
+void main()
+{
+ auto handler = () { };
+
+ try {
+ assert(0);
+ } catch
+ handler();
+
+ try {
+ assert(0);
+ } catch {
+ handler();
+ }
+
+ try {
+ assert(0);
+ } catch
+ handler();
+
+ try {
+ assert(0);
+ } catch {
+ handler();
+ }
+}
+
+void foo()()
+{
+ try {}
+ catch
+ assert(false);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test12822.d b/gcc/testsuite/gdc.test/fail_compilation/test12822.d
index fe71098..510d9e2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test12822.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test12822.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/test12822.d(13): Error: cannot modify delegate pointer in @safe code dg.ptr
-fail_compilation/test12822.d(14): Error: dg.funcptr cannot be used in @safe code
+fail_compilation/test12822.d(13): Error: cannot modify delegate pointer in `@safe` code `dg.ptr`
+fail_compilation/test12822.d(14): Error: `dg.funcptr` cannot be used in `@safe` code
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13152.d b/gcc/testsuite/gdc.test/fail_compilation/test13152.d
index 814dcb7..8033e28 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test13152.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test13152.d
@@ -1,7 +1,8 @@
/*
+EXTRA_FILES: imports/test13152a.d imports/test13152b.d imports/test13152c.d imports/test13152d.d imports/test13152e.d imports/test13152f.d imports/test13152g.d imports/test13152h.d imports/test13152i.d imports/test13152j.d imports/test13152k.d imports/test13152l.d imports/test13152m.d imports/test13152n.d imports/test13152o.d imports/test13152p.d imports/test13152q.d imports/test13152r.d imports/test13152s.d imports/test13152t.d imports/test13152u.d imports/test13152v.d imports/test13152w.d imports/test13152x.d imports/test13152y.d imports/test13152z.d
TEST_OUTPUT:
---
-fail_compilation/test13152.d(11): Error: undefined identifier `x`
+fail_compilation/test13152.d(12): Error: undefined identifier `x`
---
*/
import imports.test13152a;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13536.d b/gcc/testsuite/gdc.test/fail_compilation/test13536.d
index 800757d..e29861f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test13536.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test13536.d
@@ -1,10 +1,9 @@
/*
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/test13536.d(24): Error: field U.sysDg cannot access pointers in @safe code that overlap other fields
-fail_compilation/test13536.d(24): Error: address of variable `s` assigned to `u` with longer lifetime
-fail_compilation/test13536.d(25): Error: field U.safeDg cannot access pointers in @safe code that overlap other fields
+fail_compilation/test13536.d(23): Error: field `U.sysDg` cannot access pointers in `@safe` code that overlap other fields
+fail_compilation/test13536.d(23): Error: address of variable `s` assigned to `u` with longer lifetime
+fail_compilation/test13536.d(24): Error: field `U.safeDg` cannot access pointers in `@safe` code that overlap other fields
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13537.d b/gcc/testsuite/gdc.test/fail_compilation/test13537.d
index 0e087dd..a92a7c1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test13537.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test13537.d
@@ -1,11 +1,10 @@
/*
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/test13537.d(32): Error: field U.y cannot modify fields in @safe code that overlap fields with other storage classes
-fail_compilation/test13537.d(33): Error: field U.y cannot modify fields in @safe code that overlap fields with other storage classes
-fail_compilation/test13537.d(34): Error: field U.z cannot access pointers in @safe code that overlap other fields
-fail_compilation/test13537.d(35): Error: field U.y cannot modify fields in @safe code that overlap fields with other storage classes
+fail_compilation/test13537.d(31): Error: field `U.y` cannot modify fields in `@safe` code that overlap fields with other storage classes
+fail_compilation/test13537.d(32): Error: field `U.y` cannot modify fields in `@safe` code that overlap fields with other storage classes
+fail_compilation/test13537.d(33): Error: field `U.z` cannot access pointers in `@safe` code that overlap other fields
+fail_compilation/test13537.d(34): Error: field `U.y` cannot modify fields in `@safe` code that overlap fields with other storage classes
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13667.d b/gcc/testsuite/gdc.test/fail_compilation/test13667.d
new file mode 100644
index 0000000..e63e21e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test13667.d
@@ -0,0 +1,101 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test13667.d(112): Error: cannot cast expression `this` of type `const(Array1!int)` to `Array1!int*`
+fail_compilation/test13667.d(116): Error: template instance `test13667.Array1!int` error instantiating
+fail_compilation/test13667.d(121): Error: cannot cast expression `this` of type `const(Array2!int)` to `B*`
+fail_compilation/test13667.d(125): Error: template instance `test13667.Array2!int` error instantiating
+fail_compilation/test13667.d(136): Error: cannot cast expression `this` of type `const(Array3!int)` to `C*`
+fail_compilation/test13667.d(140): Error: template instance `test13667.Array3!int` error instantiating
+fail_compilation/test13667.d(151): Error: cannot cast expression `this` of type `const(Array4!int)` to `D*`
+fail_compilation/test13667.d(155): Error: template instance `test13667.Array4!int` error instantiating
+fail_compilation/test13667.d(172): Error: cannot cast expression `this` of type `const(Array5!int)` to `F*`
+fail_compilation/test13667.d(176): Error: template instance `test13667.Array5!int` error instantiating
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=13667
+
+#line 100
+// 0, no error but also crashed before
+struct Array0(T)
+{
+ Array0!(T) impConv() const { return cast(typeof(return))this; }
+ alias impConv this;
+}
+
+alias AI0 = Array0!int;
+
+// 1
+struct Array1(T)
+{
+ Array1!(T) impConv() const { return *cast(typeof(return)*)this; }
+ alias impConv this;
+}
+
+alias AI1 = Array1!int;
+
+// 2
+struct Array2(T)
+{
+ B impConv() const { return cast(B*)this; }
+ alias impConv this;
+}
+
+alias AI2 = Array2!int;
+
+struct B
+{
+ AI2 get() { return AI2(); }
+ alias get this;
+}
+
+// 3
+struct Array3(T)
+{
+ C impConv() const { return cast(C*)this; }
+ alias impConv this;
+}
+
+alias AI3 = Array3!int;
+
+struct C
+{
+ C get() { return C(); }
+ alias get this;
+}
+
+// 4
+struct Array4(T)
+{
+ D impConv() const { return cast(D*)this; }
+ alias impConv this;
+}
+
+alias AI4 = Array4!int;
+
+struct D
+{
+ E get() { return E(); }
+ alias get this;
+}
+
+struct E
+{
+ AI4 ai;
+ alias ai this;
+}
+
+// 5: test enum based on struct, needed to use base type (toBasetype())
+struct Array5(T)
+{
+ F impConv() const { return cast(F*)this; }
+ alias impConv this;
+}
+
+alias AI5 = Array5!int;
+
+enum F : AI5
+{
+ f = AI5()
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13786.d b/gcc/testsuite/gdc.test/fail_compilation/test13786.d
index 3b05dcc..3524875 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test13786.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test13786.d
@@ -1,11 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/test13786.d(14): Error: debug 123 level declaration must be at module level
-fail_compilation/test13786.d(15): Error: debug abc declaration must be at module level
-fail_compilation/test13786.d(16): Error: version 123 level declaration must be at module level
-fail_compilation/test13786.d(17): Error: version abc declaration must be at module level
-fail_compilation/test13786.d(20): Error: template instance test13786.T!() error instantiating
+fail_compilation/test13786.d(14): Error: debug `123` level declaration must be at module level
+fail_compilation/test13786.d(15): Error: debug `abc` declaration must be at module level
+fail_compilation/test13786.d(16): Error: version `123` level declaration must be at module level
+fail_compilation/test13786.d(17): Error: version `abc` declaration must be at module level
+fail_compilation/test13786.d(20): Error: template instance `test13786.T!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test13867.d b/gcc/testsuite/gdc.test/fail_compilation/test13867.d
index aebab2b..36543f9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test13867.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test13867.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/test13867.d(12): Error: function test13867.X.blah does not override any function, did you mean to override 'extern (C++) test13867.Base.blah'?
-fail_compilation/test13867.d(19): Error: function test13867.Z.blah does not override any function, did you mean to override 'extern (C++) test13867.Base.blah'?
+fail_compilation/test13867.d(12): Error: function `void test13867.X.blah()` does not override any function, did you mean to override `extern (C++) void test13867.Base.blah()`?
+fail_compilation/test13867.d(19): Error: function `void test13867.Z.blah()` does not override any function, did you mean to override `extern (C++) void test13867.Base.blah()`?
---
*/
extern (C++) class Base {
@@ -15,14 +15,14 @@ extern (C++) class Y : Base {
override void blah(){}
}
class Z : Base {
- alias blah = super.blah;
+ alias blah = typeof(super).blah;
override void blah(){}//Error
}
class O : Base {
extern (C++) override void blah(){}
}
extern (C++) class OK : Base {
- alias blah = super.blah;
+ alias blah = typeof(super).blah;
override void blah(){}
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test14064.d b/gcc/testsuite/gdc.test/fail_compilation/test14064.d
new file mode 100644
index 0000000..9513e47
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test14064.d
@@ -0,0 +1,15 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test14064.d(11): Error: `private` is a keyword, not an `@` attribute
+fail_compilation/test14064.d(12): Error: `deprecated` is a keyword, not an `@` attribute
+fail_compilation/test14064.d(13): Error: `pure` is a keyword, not an `@` attribute
+fail_compilation/test14064.d(14): Error: `nothrow` is a keyword, not an `@` attribute
+fail_compilation/test14064.d(15): Error: `in` is a keyword, not an `@` attribute
+---
+*/
+@private int v;
+@deprecated void foo();
+int goo() @pure;
+@nothrow unittest {};
+void zoom(@in int x);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test14238.d b/gcc/testsuite/gdc.test/fail_compilation/test14238.d
index 2d5f586..e0d0b35 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test14238.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test14238.d
@@ -1,9 +1,8 @@
-/* REQUIRED_ARGS: -dip1000
- PERMUTE_ARGS:
+/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test14238.d(21): Error: scope variable `fn` may not be returned
-fail_compilation/test14238.d(29): Error: escaping reference to stack allocated value returned by `&baz`
+fail_compilation/test14238.d(20): Error: scope variable `fn` may not be returned
+fail_compilation/test14238.d(28): Error: escaping reference to stack allocated value returned by `&baz`
---
*/
// https://issues.dlang.org/show_bug.cgi?id=14238
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test143.d b/gcc/testsuite/gdc.test/fail_compilation/test143.d
index c95ecc1..1a1ed70 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test143.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test143.d
@@ -4,7 +4,7 @@
/*
TEST_OUTPUT:
---
-fail_compilation/test143.d(19): Error: undefined identifier `x`
+fail_compilation/test143.d(20): Error: undefined identifier `x`
---
*/
module test143;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test14496.d b/gcc/testsuite/gdc.test/fail_compilation/test14496.d
index 8575e72..2835907 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test14496.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test14496.d
@@ -1,11 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/test14496.d(21): Error: variable test14496.foo.f void initializers for pointers not allowed in safe functions
-fail_compilation/test14496.d(24): Error: variable test14496.foo.Bar.foo void initializers for pointers not allowed in safe functions
-fail_compilation/test14496.d(28): Error: variable test14496.foo.Baz.x void initializers for pointers not allowed in safe functions
-fail_compilation/test14496.d(48): Error: variable test14496.sinister.bar void initializers for pointers not allowed in safe functions
-fail_compilation/test14496.d(49): Error: variable test14496.sinister.baz void initializers for pointers not allowed in safe functions
+fail_compilation/test14496.d(21): Error: variable `test14496.foo.f` `void` initializers for pointers not allowed in safe functions
+fail_compilation/test14496.d(24): Error: variable `test14496.foo.Bar.foo` `void` initializers for pointers not allowed in safe functions
+fail_compilation/test14496.d(28): Error: variable `test14496.foo.Baz.x` `void` initializers for pointers not allowed in safe functions
+fail_compilation/test14496.d(48): Error: variable `test14496.sinister.bar` `void` initializers for pointers not allowed in safe functions
+fail_compilation/test14496.d(49): Error: variable `test14496.sinister.baz` `void` initializers for pointers not allowed in safe functions
---
*/
// https://issues.dlang.org/show_bug.cgi?id=14496
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test14538.d b/gcc/testsuite/gdc.test/fail_compilation/test14538.d
index b0b76a7..1ad2126 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test14538.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test14538.d
@@ -1,9 +1,8 @@
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/test14538.d(19): Error: cannot implicitly convert expression `x ? cast(uint)this.fCells[x].code : 32u` of type `uint` to `Cell`
+fail_compilation/test14538.d(18): Error: cannot implicitly convert expression `x ? cast(uint)this.fCells[x].code : 32u` of type `uint` to `Cell`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15117.d b/gcc/testsuite/gdc.test/fail_compilation/test15177.d
index e6ce3b5..b0ae7ae 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15117.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15177.d
@@ -1,11 +1,10 @@
// REQUIRED_ARGS: -o-
-// PERMUTE_ARGS:
// COMPILED_IMPORTS: imports/test15117a.d
/*
TEST_OUTPUT:
---
-fail_compilation/test15177.d-mixin-20(20): Error: `imports.test15117a.object` is not visible from module `test15177`
-fail_compilation/test15177.d(29): Error: template instance `test15177.RunApiTest!()` error instantiating
+fail_compilation/test15177.d-mixin-19(19): Error: `imports.test15117a.object` is not visible from module `test15177`
+fail_compilation/test15177.d(28): Error: template instance `test15177.RunApiTest!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15191.d b/gcc/testsuite/gdc.test/fail_compilation/test15191.d
index 55b09b7..173473a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15191.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15191.d
@@ -1,6 +1,6 @@
/* TEST_OUTPUT:
---
-fail_compilation/test15191.d(17): Error: cannot take address of ref return of foo() in @safe function bar
+fail_compilation/test15191.d(17): Error: cannot take address of `ref return` of `foo()` in `@safe` function `bar`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15306.d b/gcc/testsuite/gdc.test/fail_compilation/test15306.d
index ad51371..ff532ae 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15306.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15306.d
@@ -1,10 +1,8 @@
/*
-REQUIRED_ARGS:
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/test15306.d(17): Error: immutable delegate 'test15306.main.__dgliteral1' cannot access mutable data 'i'
-fail_compilation/test15306.d(21): Error: shared delegate 'test15306.main.__dgliteral2' cannot access non-shared data 'p'
+fail_compilation/test15306.d(15): Error: `immutable` delegate `test15306.main.__dgliteral2` cannot access mutable data `i`
+fail_compilation/test15306.d(19): Error: `shared` delegate `test15306.main.__dgliteral5` cannot access non-shared data `p`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15373.d b/gcc/testsuite/gdc.test/fail_compilation/test15373.d
new file mode 100644
index 0000000..1b3cecd
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15373.d
@@ -0,0 +1,22 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test15373.d(21): Error: Runtime type information is not supported for `extern(C++)` classes
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=15373
+
+// Using `typeid` on an `extern(C++) class` type is ok as it is evaluated at compile-time
+// See test/runnable/test15373.d
+
+// Using `typeid` on an `extern(C++) class` instance is not ok because `extern(C++) class`
+// instances are not rooted in `Object`
+
+extern(C++) class C { }
+
+void foo()
+{
+ C c = new C();
+ auto ti = typeid(c);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15399.d b/gcc/testsuite/gdc.test/fail_compilation/test15399.d
index bad3ed2..00ec33a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15399.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15399.d
@@ -1,14 +1,14 @@
/* https://issues.dlang.org/show_bug.cgi?id=15399
TEST_OUTPUT:
---
-fail_compilation/test15399.d(31): Error: writing to misaligned pointer in field S1.ptr is not @safe
-fail_compilation/test15399.d(32): Error: writing to misaligned pointer in field S2.ptr is not @safe
-fail_compilation/test15399.d(33): Error: taking address of misaligned pointer in field S1.ptr is not @safe
-fail_compilation/test15399.d(34): Error: taking address of misaligned pointer in field S2.ptr is not @safe
-fail_compilation/test15399.d(35): Error: 'ref' of misaligned pointer in field S1.ptr is not @safe
-fail_compilation/test15399.d(36): Error: 'ref' of misaligned pointer in field S2.ptr is not @safe
-fail_compilation/test15399.d(37): Error: 'out' of misaligned pointer in field S1.ptr is not @safe
-fail_compilation/test15399.d(38): Error: 'out' of misaligned pointer in field S2.ptr is not @safe
+fail_compilation/test15399.d(32): Error: field `S1.ptr` cannot modify misaligned pointers in `@safe` code
+fail_compilation/test15399.d(33): Error: field `S2.ptr` cannot modify misaligned pointers in `@safe` code
+fail_compilation/test15399.d(34): Error: field `S1.ptr` cannot modify misaligned pointers in `@safe` code
+fail_compilation/test15399.d(35): Error: field `S2.ptr` cannot modify misaligned pointers in `@safe` code
+fail_compilation/test15399.d(36): Error: field `S1.ptr` cannot modify misaligned pointers in `@safe` code
+fail_compilation/test15399.d(37): Error: field `S2.ptr` cannot modify misaligned pointers in `@safe` code
+fail_compilation/test15399.d(38): Error: field `S1.ptr` cannot modify misaligned pointers in `@safe` code
+fail_compilation/test15399.d(39): Error: field `S2.ptr` cannot modify misaligned pointers in `@safe` code
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15544.d b/gcc/testsuite/gdc.test/fail_compilation/test15544.d
index 9757dbf..eeb4492 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15544.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15544.d
@@ -1,10 +1,9 @@
/*
-REQUIRED_ARGS: -dip1000
-PERMUTE_ARGS:
+REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test15544.d(21): Error: reference to local `this` assigned to non-scope `_del` in @safe code
-fail_compilation/test15544.d(23): Error: reference to local `this` assigned to non-scope `_del` in @safe code
+fail_compilation/test15544.d(20): Error: reference to local `this` assigned to non-scope `_del` in @safe code
+fail_compilation/test15544.d(22): Error: reference to local `this` assigned to non-scope `_del` in @safe code
---
*/
@@ -27,7 +26,7 @@ struct S {
/*
TEST_OUTPUT:
---
-fail_compilation/test15544.d(47): Error: reference to local `y` assigned to non-scope `dg` in @safe code
+fail_compilation/test15544.d(46): Error: reference to local `y` assigned to non-scope `dg` in @safe code
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15660.d b/gcc/testsuite/gdc.test/fail_compilation/test15660.d
new file mode 100644
index 0000000..c979bb5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15660.d
@@ -0,0 +1,22 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/test15660.d(20): Error: cannot implicitly convert expression `f(v)` of type `int[]` to `immutable(int[])`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=15660
+
+int[] f(ref void[] m) pure
+{
+ auto result = new int[5];
+ m = result;
+ return result;
+}
+
+void main()
+{
+ void[] v;
+ immutable x = f(v);
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15672.d b/gcc/testsuite/gdc.test/fail_compilation/test15672.d
index 19b5bf1..859521d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15672.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15672.d
@@ -1,8 +1,8 @@
/*
* TEST_OUTPUT:
---
-fail_compilation/test15672.d(15): Error: cast from void[] to byte[] not allowed in safe code
-fail_compilation/test15672.d(25): Error: cast from void* to byte* not allowed in safe code
+fail_compilation/test15672.d(15): Error: cast from `void[]` to `byte[]` not allowed in safe code
+fail_compilation/test15672.d(25): Error: cast from `void*` to `byte*` not allowed in safe code
---
*/
// https://issues.dlang.org/show_bug.cgi?id=15672
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15703.d b/gcc/testsuite/gdc.test/fail_compilation/test15703.d
index cf24c3b..1665e85 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15703.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15703.d
@@ -1,11 +1,10 @@
/*
REQUIRED_ARGS: -m32
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/test15703.d(17): Error: cast from Object[] to uint[] not allowed in safe code
-fail_compilation/test15703.d(19): Error: cast from object.Object to const(uint)* not allowed in safe code
-fail_compilation/test15703.d(22): Error: cast from uint[] to Object[] not allowed in safe code
+fail_compilation/test15703.d(16): Error: cast from `Object[]` to `uint[]` not allowed in safe code
+fail_compilation/test15703.d(18): Error: cast from `object.Object` to `const(uint)*` not allowed in safe code
+fail_compilation/test15703.d(21): Error: cast from `uint[]` to `Object[]` not allowed in safe code
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15704.d b/gcc/testsuite/gdc.test/fail_compilation/test15704.d
index 6b41906..d818033 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15704.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15704.d
@@ -1,7 +1,7 @@
/*
* TEST_OUTPUT:
---
-fail_compilation/test15704.d(15): Error: cannot copy void[] to void[] in @safe code
+fail_compilation/test15704.d(15): Error: cannot copy `void[]` to `void[]` in `@safe` code
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15785.d b/gcc/testsuite/gdc.test/fail_compilation/test15785.d
index 474076f..23a3660 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15785.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15785.d
@@ -1,8 +1,8 @@
-// PERMUTE_ARGS:
+// EXTRA_FILES: imports/test15785.d
/*
TEST_OUTPUT:
---
-fail_compilation/test15785.d(16): Error: no property `foo` for type `imports.test15785.Base`, did you mean `imports.test15785.Base.foo`?
+fail_compilation/test15785.d(16): Error: no property `foo` for type `imports.test15785.Base`
fail_compilation/test15785.d(17): Error: undefined identifier `bar`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15785b.d b/gcc/testsuite/gdc.test/fail_compilation/test15785b.d
index e09b4bf..910db18 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15785b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15785b.d
@@ -1,18 +1,17 @@
-// REQUIRED_ARGS:
-// PERMUTE_ARGS:
+// EXTRA_FILES: imports/test15785.d
/*
TEST_OUTPUT:
---
+fail_compilation/test15785b.d(14): Error: `imports.test15785.Base.T` is not visible from module `test15785b`
fail_compilation/test15785b.d(15): Error: `imports.test15785.Base.T` is not visible from module `test15785b`
-fail_compilation/test15785b.d(16): Error: `imports.test15785.Base.T` is not visible from module `test15785b`
-fail_compilation/test15785b.d(17): Error: `imports.test15785.IBase2.T` is not visible from module `test15785b`
+fail_compilation/test15785b.d(16): Error: `imports.test15785.IBase2.T` is not visible from module `test15785b`
---
*/
import imports.test15785;
class Derived : Base, IBase2
{
- super.T t;
+ typeof(super).T t;
Base.T t2;
IBase2.T t3;
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15897.d b/gcc/testsuite/gdc.test/fail_compilation/test15897.d
index aa22c10..e4ade7d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15897.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15897.d
@@ -1,8 +1,9 @@
// REQUIRED_ARGS: -de
+// EXTRA_FILES: imports/test15897.d
/*
TEST_OUTPUT:
---
-fail_compilation/test15897.d(18): Error: no property `create` for type `imports.test15897.Cat`
+fail_compilation/test15897.d(19): Error: no property `create` for type `imports.test15897.Cat`
---
*/
module test15897;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15925.d b/gcc/testsuite/gdc.test/fail_compilation/test15925.d
index 9359859..88102ac 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15925.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15925.d
@@ -1,5 +1,5 @@
-/* REQUIRED_ARGS:
-PERMUTE_ARGS:
+/*
+EXTRA_FILES: imports/imp15925.d
TEST_OUTPUT:
---
fail_compilation/test15925.d(18): Error: undefined identifier `X`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15989.d b/gcc/testsuite/gdc.test/fail_compilation/test15989.d
index 29eab9c..a78dec4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15989.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15989.d
@@ -1,10 +1,9 @@
/*
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/test15989.d(40): Error: variable test15989.main.ctRegex : Unable to initialize enum with class or pointer to struct. Use static const variable instead.
-fail_compilation/test15989.d(49): Error: variable test15989.test.c : Unable to initialize enum with class or pointer to struct. Use static const variable instead.
-fail_compilation/test15989.d(50): Error: cannot use non-constant CTFE pointer in an initializer '&[3][0]'
+fail_compilation/test15989.d(39): Error: variable `test15989.main.ctRegex` : Unable to initialize enum with class or pointer to struct. Use static const variable instead.
+fail_compilation/test15989.d(48): Error: variable `test15989.test.c` : Unable to initialize enum with class or pointer to struct. Use static const variable instead.
+fail_compilation/test15989.d(49): Error: cannot use non-constant CTFE pointer in an initializer `new int(3)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16095.d b/gcc/testsuite/gdc.test/fail_compilation/test16095.d
index cb164f5..38a3a7d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test16095.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16095.d
@@ -1,11 +1,9 @@
/*
-REQUIRED_ARGS:
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/test16095.d(20): Error: shared method test16095.C.ping is not callable using a non-shared a
-fail_compilation/test16095.d(30): Error: shared method test16095.S.ping is not callable using a non-shared *a
-fail_compilation/test16095.d(43): Error: mutable method test16095.Foo.flip is not callable using a immutable foo
+fail_compilation/test16095.d(18): Error: `shared` method `test16095.C.ping` is not callable using a non-shared `a`
+fail_compilation/test16095.d(28): Error: `shared` method `test16095.S.ping` is not callable using a non-shared `*a`
+fail_compilation/test16095.d(41): Error: mutable method `test16095.Foo.flip` is not callable using a `immutable` `foo`
---
*/
// https://issues.dlang.org/show_bug.cgi?id=16095
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16116.d b/gcc/testsuite/gdc.test/fail_compilation/test16116.d
index be6e786..d407aa3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test16116.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16116.d
@@ -1,9 +1,8 @@
/*
REQUIRED_ARGS: -m64
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/test16116.d(15): Error: incompatible types for ((v) * (i)): '__vector(short[8])' and 'int'
+fail_compilation/test16116.d(14): Error: incompatible types for `(v) * (i)`: `__vector(short[8])` and `int`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16193.d b/gcc/testsuite/gdc.test/fail_compilation/test16193.d
index de65e8a..4124c43 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test16193.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16193.d
@@ -1,15 +1,14 @@
/*
-REQUIRED_ARGS: -dip1000
-PERMUTE_ARGS:
+REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test16193.d(39): Error: function test16193.abc is @nogc yet allocates closures with the GC
-fail_compilation/test16193.d(41): test16193.abc.__foreachbody1 closes over variable x at fail_compilation/test16193.d(40)
+fail_compilation/test16193.d(38): Error: function `test16193.abc` is `@nogc` yet allocates closures with the GC
+fail_compilation/test16193.d(40): test16193.abc.__foreachbody2 closes over variable x at fail_compilation/test16193.d(39)
---
*/
-//fail_compilation/test16193.d(22): To enforce @safe compiler allocates a closure unless the opApply() uses 'scope'
-//fail_compilation/test16193.d(34): To enforce @safe compiler allocates a closure unless the opApply() uses 'scope'
-//fail_compilation/test16193.d(41): To enforce @safe compiler allocates a closure unless the opApply() uses 'scope'
+//fail_compilation/test16193.d(22): To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`
+//fail_compilation/test16193.d(34): To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`
+//fail_compilation/test16193.d(41): To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`
// https://issues.dlang.org/show_bug.cgi?id=16193
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16195.d b/gcc/testsuite/gdc.test/fail_compilation/test16195.d
index 704974c..a315f33 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test16195.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16195.d
@@ -1,7 +1,8 @@
/*
* TEST_OUTPUT:
---
-fail_compilation/test16195.d(13): Error: delete p is not @safe but is used in @safe function test
+fail_compilation/test16195.d(14): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/test16195.d(14): Error: `delete p` is not `@safe` but is used in `@safe` function `test`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16228.d b/gcc/testsuite/gdc.test/fail_compilation/test16228.d
index 63951e6..b862284 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test16228.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16228.d
@@ -1,4 +1,4 @@
-/* REQUIRED_ARGS: -dip25
+/* REQUIRED_ARGS:
TEST_OUTPUT:
---
fail_compilation/test16228.d(23): Error: function `test16228.S.bar` `static` member has no `this` to which `return` can apply
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16284.d b/gcc/testsuite/gdc.test/fail_compilation/test16284.d
new file mode 100644
index 0000000..77b73b0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16284.d
@@ -0,0 +1,27 @@
+/* REQUIRED_ARGS: -preview=fieldwise
+TEST_OUTPUT:
+---
+fail_compilation/test16284.d(24): Error: reinterpretation through overlapped field `s` is not allowed in CTFE
+fail_compilation/test16284.d(27): called from here: `test()`
+fail_compilation/test16284.d(27): while evaluating: `static assert(test())`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=16284
+
+struct S {}
+
+struct T
+{
+ union {int i; S s;}
+ this(uint dummy) { s = S.init; }
+}
+
+bool test()
+{
+ auto t1 = T(0);
+ auto t2 = T(0);
+ return t1 == t2;
+}
+
+static assert(test());
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16365.d b/gcc/testsuite/gdc.test/fail_compilation/test16365.d
index 067361b..a11807f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test16365.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16365.d
@@ -1,11 +1,10 @@
-/* REQUIRED_ARGS:
- PERMUTE_ARGS:
- TEST_OUTPUT:
+/*
+TEST_OUTPUT:
---
-fail_compilation/test16365.d(22): Error: 'this' reference necessary to take address of member f1 in @safe function main
-fail_compilation/test16365.d(24): Error: cannot implicitly convert expression `&f2` of type `void delegate() pure nothrow @nogc @safe` to `void function() @safe`
-fail_compilation/test16365.d(28): Error: address of variable `s` assigned to `dg` with longer lifetime
-fail_compilation/test16365.d(29): Error: dg.funcptr cannot be used in @safe code
+fail_compilation/test16365.d(21): Error: `this` reference necessary to take address of member `f1` in `@safe` function `main`
+fail_compilation/test16365.d(23): Error: cannot implicitly convert expression `&f2` of type `void delegate() pure nothrow @nogc @safe` to `void function() @safe`
+fail_compilation/test16365.d(27): Error: address of variable `s` assigned to `dg` with longer lifetime
+fail_compilation/test16365.d(28): Error: `dg.funcptr` cannot be used in `@safe` code
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16381.d b/gcc/testsuite/gdc.test/fail_compilation/test16381.d
index ed591bd..b854c27 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test16381.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16381.d
@@ -1,9 +1,8 @@
/*
REQUIRED_ARGS: -m64
-PERMUTE_ARGS:
TEST_OUTPUT:
---
-fail_compilation/test16381.d(16): Error: foo() is not an lvalue
+fail_compilation/test16381.d(15): Error: `foo()` is not an lvalue and cannot be modified
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16523.d b/gcc/testsuite/gdc.test/fail_compilation/test16523.d
index e5de7c1..78563c9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test16523.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16523.d
@@ -1,8 +1,7 @@
-// REQUIRED_ARGS: -de
/*
TEST_OUTPUT:
---
-fail_compilation/test16523.d(13): Deprecation: case variables have to be const or immutable
+fail_compilation/test16523.d(12): Error: `case` variables have to be `const` or `immutable`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16589.d b/gcc/testsuite/gdc.test/fail_compilation/test16589.d
index 205347b..7b1f14f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test16589.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16589.d
@@ -1,20 +1,20 @@
-/* PERMUTE_ARGS:
-REQUIRED_ARGS: -dip1000
+/*
+REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test16589.d(26): Error: returning `&this.data` escapes a reference to parameter `this`, perhaps annotate with `return`
-fail_compilation/test16589.d(31): Error: returning `&this` escapes a reference to parameter `this`, perhaps annotate with `return`
-fail_compilation/test16589.d(37): Error: returning `&s.data` escapes a reference to parameter `s`, perhaps annotate with `return`
-fail_compilation/test16589.d(42): Error: returning `&s` escapes a reference to parameter `s`, perhaps annotate with `return`
-fail_compilation/test16589.d(47): Error: returning `&s.data` escapes a reference to parameter `s`, perhaps annotate with `return`
-fail_compilation/test16589.d(52): Error: returning `& s` escapes a reference to parameter `s`, perhaps annotate with `return`
+fail_compilation/test16589.d(26): Error: returning `&this.data` escapes a reference to parameter `this`
+fail_compilation/test16589.d(26): perhaps annotate the parameter with `return`
+fail_compilation/test16589.d(31): Error: returning `&this` escapes a reference to parameter `this`
+fail_compilation/test16589.d(31): perhaps annotate the parameter with `return`
+fail_compilation/test16589.d(37): Error: returning `&s.data` escapes a reference to parameter `s`
+fail_compilation/test16589.d(37): perhaps annotate the parameter with `return`
+fail_compilation/test16589.d(42): Error: returning `&s` escapes a reference to parameter `s`
+fail_compilation/test16589.d(42): perhaps annotate the parameter with `return`
+fail_compilation/test16589.d(47): Error: returning `&s.data` escapes a reference to local variable `s`
+fail_compilation/test16589.d(52): Error: returning `& s` escapes a reference to local variable `s`
---
*/
-
-
-
-
// https://issues.dlang.org/show_bug.cgi?id=16589
struct S
@@ -61,5 +61,3 @@ class C
return &data;
}
}
-
-
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16694.d b/gcc/testsuite/gdc.test/fail_compilation/test16694.d
new file mode 100644
index 0000000..1b15aa4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16694.d
@@ -0,0 +1,8 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test16694.d(8): Error: cannot take address of imported symbol `bar` at compile time
+---
+*/
+export void bar();
+auto barptr = &bar;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17284.d b/gcc/testsuite/gdc.test/fail_compilation/test17284.d
new file mode 100644
index 0000000..a0ea05b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17284.d
@@ -0,0 +1,20 @@
+TEST_OUTPUT:
+---
+fail_compilation/test17284.d(1): Error: no identifier for declarator `TEST_OUTPUT`
+fail_compilation/test17284.d(1): Error: declaration expected, not `:`
+fail_compilation/test17284.d(12): Error: unrecognized declaration
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=17284
+
+class C { }
+union U { C c; int i; }
+
+@safe void func(T)(T t)
+{
+ t.c = new C;
+}
+
+pragma(msg, typeof(func!U));
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17380spec.d b/gcc/testsuite/gdc.test/fail_compilation/test17380spec.d
new file mode 100644
index 0000000..2456a59
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17380spec.d
@@ -0,0 +1,23 @@
+/* REQUIRED_ARGS: -verrors=spec
+TEST_OUTPUT:
+---
+(spec:1) fail_compilation/test17380spec.d(14): Error: cannot resolve identifier `ThisTypeDoesNotExistAndCrashesTheCompiler`
+(spec:1) fail_compilation/test17380spec.d(14): Error: no property `ThisTypeDoesNotExistAndCrashesTheCompiler` for type `test17380spec.Uint128`
+fail_compilation/test17380spec.d(14): Error: undefined identifier `ThisTypeDoesNotExistAndCrashesTheCompiler`
+---
+ */
+
+struct Int128
+{
+ Uint128 opCast()
+ {
+ return ThisTypeDoesNotExistAndCrashesTheCompiler;
+ }
+ alias opCast this;
+}
+
+struct Uint128
+{
+ Int128 opCast() { return Int128.init; }
+ alias opCast this;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17422.d b/gcc/testsuite/gdc.test/fail_compilation/test17422.d
index 4d203cb..7bb1315 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test17422.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17422.d
@@ -1,5 +1,5 @@
/*
-REQUIRED_ARGS: -dip1000
+REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
fail_compilation/test17422.d(23): Error: scope variable `p` may not be returned
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17423.d b/gcc/testsuite/gdc.test/fail_compilation/test17423.d
new file mode 100644
index 0000000..66a81c3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17423.d
@@ -0,0 +1,29 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/test17423.d(26): Error: reference to local `this` assigned to non-scope parameter `dlg` calling test17423.Bar.opApply
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=17423
+
+struct Bar
+{
+ int delegate(int) @safe myDlg;
+
+ auto opApply(int delegate(int) @safe dlg) @safe {
+ myDlg = dlg;
+ return 0;
+ }
+}
+
+struct Foo
+{
+ Bar o;
+ int i = 3;
+
+ this(int x) @safe {
+ foreach(_; o) { i = 0; }
+ i = x;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17450.d b/gcc/testsuite/gdc.test/fail_compilation/test17450.d
index 58a5c7d..6d0e25a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test17450.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17450.d
@@ -1,9 +1,11 @@
/*
-REQUIRED_ARGS: -dip1000 -dip25
+REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test17450.d(15): Error: returning `&s.bar` escapes a reference to parameter `s`, perhaps annotate with `return`
-fail_compilation/test17450.d(18): Error: returning `&this.bar` escapes a reference to parameter `this`, perhaps annotate with `return`
+fail_compilation/test17450.d(17): Error: returning `&s.bar` escapes a reference to parameter `s`
+fail_compilation/test17450.d(17): perhaps annotate the parameter with `return`
+fail_compilation/test17450.d(20): Error: returning `&this.bar` escapes a reference to parameter `this`
+fail_compilation/test17450.d(20): perhaps annotate the parameter with `return`
---
*/
// https://issues.dlang.org/show_bug.cgi?id=17450
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17451.d b/gcc/testsuite/gdc.test/fail_compilation/test17451.d
index fc2f2d2..a7ef88a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test17451.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17451.d
@@ -1,9 +1,9 @@
/* TEST_OUTPUT:
---
fail_compilation/test17451.d(22): Error: undefined identifier `allocator`
-fail_compilation/test17451.d(23): Error: `long` has no effect in expression `false`
-fail_compilation/test17451.d(30): Error: variable test17451.HashMap!(ThreadSlot).HashMap.__lambda2.v size of type ThreadSlot is invalid
-fail_compilation/test17451.d(44): Error: template instance test17451.HashMap!(ThreadSlot) error instantiating
+fail_compilation/test17451.d(23): Error: `false` has no effect
+fail_compilation/test17451.d(30): Error: variable `test17451.HashMap!(ThreadSlot).HashMap.__lambda2.v` size of type `ThreadSlot` is invalid
+fail_compilation/test17451.d(44): Error: template instance `test17451.HashMap!(ThreadSlot)` error instantiating
---
*/
@@ -20,7 +20,7 @@ struct ArraySet(Key)
~this()
{
try allocator;
- catch false; // should never happen
+ catch (Exception e) false; // should never happen
}
}
@@ -40,6 +40,6 @@ struct ThreadSlot {
ArraySet!Task tasks;
}
-class Libevent2ManualEvent {
+class Libevent2ManualEvent : ManualEvent {
HashMap!ThreadSlot m_waiters;
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17586.d b/gcc/testsuite/gdc.test/fail_compilation/test17586.d
new file mode 100644
index 0000000..fcfb7b7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17586.d
@@ -0,0 +1,14 @@
+/* REQUIRED_ARGS: -o- -de
+TEST_OUTPUT:
+---
+fail_compilation/test17586.d(13): Deprecation: `test17586.D.foo` is overriding the deprecated method `test17586.C.foo`
+---
+*/
+
+class C{
+ deprecated void foo(){}
+}
+
+class D : C{
+ override void foo(){}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17868.d b/gcc/testsuite/gdc.test/fail_compilation/test17868.d
new file mode 100644
index 0000000..4e55c2a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17868.d
@@ -0,0 +1,24 @@
+/*
+TEST_OUTPUT:
+----
+fail_compilation/test17868.d(10): Error: pragma `crt_constructor` takes no argument
+fail_compilation/test17868.d(11): Error: pragma `crt_constructor` takes no argument
+fail_compilation/test17868.d(12): Error: pragma `crt_constructor` takes no argument
+fail_compilation/test17868.d(13): Error: pragma `crt_constructor` takes no argument
+----
+ */
+pragma(crt_constructor, ctfe())
+pragma(crt_constructor, 1.5f)
+pragma(crt_constructor, "foobar")
+pragma(crt_constructor, S())
+void foo()
+{
+}
+
+int ctfe()
+{
+ __gshared int val;
+ return val;
+}
+
+struct S {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17868b.d b/gcc/testsuite/gdc.test/fail_compilation/test17868b.d
new file mode 100644
index 0000000..5bfff5c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17868b.d
@@ -0,0 +1,16 @@
+/*
+TEST_OUTPUT:
+----
+fail_compilation/test17868b.d(10): Error: function `test17868b.foo` must be `extern(C)` for `pragma(crt_constructor)`
+fail_compilation/test17868b.d(14): Error: function `test17868b.bar` must be `extern(C)` for `pragma(crt_constructor)`
+fail_compilation/test17868b.d(9): Error: pragma `crt_constructor` can only apply to a single declaration
+----
+ */
+pragma(crt_constructor):
+void foo()
+{
+}
+
+void bar()
+{
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17892.d b/gcc/testsuite/gdc.test/fail_compilation/test17892.d
new file mode 100644
index 0000000..aaa7ad3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17892.d
@@ -0,0 +1,32 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/test17892.d(27): Error: returning `s.pointer1()` escapes a reference to local variable `s`
+fail_compilation/test17892.d(29): Error: returning `s.pointer2()` escapes a reference to local variable `s`
+fail_compilation/test17892.d(31): Error: returning `s.pointer3()` escapes a reference to local variable `s`
+---
+*/
+
+
+// https://issues.dlang.org/show_bug.cgi?id=17892
+
+struct S
+{
+ @safe:
+ int x;
+ int[1] y;
+ auto pointer1() return { return &x; }
+ auto pointer2() return { return &y[0]; }
+ auto pointer3() return { return &y[0..1][0]; }
+}
+
+@safe int* testPointer(int b)
+{
+ S s;
+ if (b == 1)
+ return s.pointer1();
+ else if (b == 2)
+ return s.pointer2();
+ else
+ return s.pointer3();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17959.d b/gcc/testsuite/gdc.test/fail_compilation/test17959.d
new file mode 100644
index 0000000..cd2216f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17959.d
@@ -0,0 +1,21 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/test17959.d(18): Error: scope variable `this` assigned to non-scope `this.escape`
+fail_compilation/test17959.d(19): Error: scope variable `this` assigned to non-scope `this.f`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=17959
+
+class Foo
+{
+ void delegate () @safe escape;
+ Foo f;
+
+ void escfoo() @safe scope
+ {
+ this.escape = &this.escfoo;
+ f = this;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18130.d b/gcc/testsuite/gdc.test/fail_compilation/test18130.d
new file mode 100644
index 0000000..4309a6b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18130.d
@@ -0,0 +1,10 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test18130.d(8): Error: variable `test18130.foo.v` Zero-length `out` parameters are not allowed.
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=18130
+void foo(out byte[0] v)
+{
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18282.d b/gcc/testsuite/gdc.test/fail_compilation/test18282.d
new file mode 100644
index 0000000..b853801
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18282.d
@@ -0,0 +1,89 @@
+/* REQUIRED_ARGS: -preview=dip1000
+ TEST_OUTPUT:
+---
+fail_compilation/test18282.d(25): Error: scope variable `aa` may not be returned
+fail_compilation/test18282.d(34): Error: copying `& i` into allocated memory escapes a reference to local variable `i`
+fail_compilation/test18282.d(35): Error: copying `& i` into allocated memory escapes a reference to local variable `i`
+fail_compilation/test18282.d(36): Error: scope variable `staa` may not be returned
+fail_compilation/test18282.d(44): Error: copying `S2000(& i)` into allocated memory escapes a reference to local variable `i`
+fail_compilation/test18282.d(53): Error: copying `& i` into allocated memory escapes a reference to local variable `i`
+fail_compilation/test18282.d(53): Error: copying `& c` into allocated memory escapes a reference to local variable `c`
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=18282
+
+string* f() @safe
+{
+ scope string*[] ls;
+ return ls[0];
+}
+
+int* g() @safe
+{
+ scope int*[3] aa;
+ return aa[0];
+}
+
+@safe:
+
+auto bar1()
+{
+ int i = void;
+ int*[1] staa = [ &i ];
+ auto dyna = [ &i ];
+ int*[ ] dynb = [ &i ];
+ return staa[0];
+}
+
+struct S2000 { int* p; }
+
+S2000 bar2()
+{
+ int i;
+ S2000[] arr = [ S2000(&i) ];
+ return arr[0];
+}
+
+
+void bar3()
+{
+ int i;
+ char c;
+ char*[int*] aa = [ &i : &c ];
+}
+
+
+/******************************
+TEST_OUTPUT:
+---
+fail_compilation/test18282.d(1007): Error: copying `& foo` into allocated memory escapes a reference to local variable `foo`
+fail_compilation/test18282.d(1008): Error: copying `& foo` into allocated memory escapes a reference to local variable `foo`
+fail_compilation/test18282.d(1009): Error: copying `& foo` into allocated memory escapes a reference to local variable `foo`
+fail_compilation/test18282.d(1016): Error: copying `&this` into allocated memory escapes a reference to parameter variable `this`
+---
+*/
+
+#line 1000
+
+// https://issues.dlang.org/show_bug.cgi?id=18282
+
+void test18282() @safe
+{
+ string foo = "foo";
+ scope string*[] ls;
+ ls = ls ~ &foo;
+ ls = &foo ~ ls;
+ ls ~= &foo;
+}
+
+struct S
+{
+ auto fun()
+ {
+ arr ~= &this;
+ }
+
+ S*[] arr;
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18385.d b/gcc/testsuite/gdc.test/fail_compilation/test18385.d
new file mode 100644
index 0000000..3f87885
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18385.d
@@ -0,0 +1,31 @@
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/test18385.d(13): Deprecation: function `test18385.foo` cannot overload `extern(C)` function at fail_compilation/test18385.d(12)
+---
+*/
+
+
+extern (C):
+
+void foo(int) { }
+void foo(double) { }
+
+struct S
+{
+ static void foo(int) {}
+ static void foo(double) {}
+}
+
+void foo2(int) { }
+extern(D) void foo2(double) { } // OK as it has a different mangling
+
+void foo3(int) { }
+void foo3(double); // duplicate declarations are allowed
+
+void foo4();
+void foo4() { }
+
+extern(D) void foo5();
+extern(D) void foo5() { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18385b.d b/gcc/testsuite/gdc.test/fail_compilation/test18385b.d
new file mode 100644
index 0000000..f0b9d01
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18385b.d
@@ -0,0 +1,47 @@
+/*
+Previous implementation raised errors for overloads using alias declarations
+because they ignored the actual function name
+
+TEST_OUTPUT:
+---
+fail_compilation/test18385b.d(13): Error: `test18385b.S.foo` called with argument types `(int)` matches both:
+fail_compilation/test18385b.d(8): `test18385b.S.foo(int s)`
+and:
+fail_compilation/test18385b.d(3): `test18385b.foo(int s)`
+fail_compilation/test18385b.d(102): Error: `test18385b.bar` called with argument types `(int)` matches both:
+fail_compilation/test18385b.d(2): `test18385b.bar(int s)`
+and:
+fail_compilation/test18385b.d(3): `test18385b.foo(int s)`
+---
+*/
+#line 1
+
+void bar(int s) {}
+void foo(int s) {}
+alias bar = foo;
+
+struct S
+{
+ void foo(int s) {}
+ alias foo = bar;
+
+ void useEm()
+ {
+ foo(1);
+ }
+}
+
+// False positive in mutex.d when building druntime
+class Mutex
+{
+ this() {}
+ this() shared {}
+ this(Object obj) {}
+}
+
+#line 100
+void main()
+{
+ bar(0);
+ new Mutex();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18480.d b/gcc/testsuite/gdc.test/fail_compilation/test18480.d
new file mode 100644
index 0000000..49f306b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18480.d
@@ -0,0 +1,10 @@
+// REQUIRED_ARGS: -i
+/*
+TEST_OUTPUT:
+---
+fail_compilation/imports/test18480a.d(2): Error: `alias TestTemplate = TestTemplate;` cannot alias itself, use a qualified name to create an overload set
+---
+https://issues.dlang.org/show_bug.cgi?id=18480
+*/
+
+import imports.test18480a : TestTemplate;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18484.d b/gcc/testsuite/gdc.test/fail_compilation/test18484.d
new file mode 100644
index 0000000..678609b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18484.d
@@ -0,0 +1,26 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/test18484.d(19): Error: returning `x.bar()` escapes a reference to local variable `x`
+fail_compilation/test18484.d(24): Error: escaping reference to stack allocated value returned by `S(0)`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=18484
+
+struct S
+{
+ int* bar() return;
+ int i;
+}
+
+int* test1()
+{
+ auto x = S(); return x.bar(); // error
+}
+
+int* test2()
+{
+ return S().bar(); // error
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18554.d b/gcc/testsuite/gdc.test/fail_compilation/test18554.d
new file mode 100644
index 0000000..acbda50
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18554.d
@@ -0,0 +1,24 @@
+/* REQUIRED_ARGS: -preview=dip1000
+EXTRA_FILES: imports/imp18554.d
+TEST_OUTPUT:
+---
+fail_compilation/test18554.d(16): Error: struct `imp18554.S` variable `i` is not accessible from `@safe` code
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=18554
+
+import imports.imp18554;
+
+void test1() @safe
+{
+ S s;
+ s.tupleof[0] = 1;
+}
+
+void test2()
+{
+ S s;
+ s.tupleof[0] = 1;
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18597.d b/gcc/testsuite/gdc.test/fail_compilation/test18597.d
new file mode 100644
index 0000000..66cde58
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18597.d
@@ -0,0 +1,27 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test18597.d(24): Error: field `Unaligned.p` cannot modify misaligned pointers in `@safe` code
+fail_compilation/test18597.d(25): Error: field `Unaligned.p` cannot assign to misaligned pointers in `@safe` code
+fail_compilation/test18597.d(26): Error: field `Unaligned.p` cannot assign to misaligned pointers in `@safe` code
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=18597
+
+@safe:
+
+align(1)
+struct Unaligned
+{
+align(1):
+ ubyte filler;
+ int* p;
+}
+
+void test()
+{
+ Unaligned u;
+ u.p = new int;
+ Unaligned v = Unaligned(0, new int);
+ Unaligned w = { p : new int };
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18607.d b/gcc/testsuite/gdc.test/fail_compilation/test18607.d
new file mode 100644
index 0000000..b3af393
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18607.d
@@ -0,0 +1,18 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test18607.d(10): Error: function `test18607.test!int.test` no `return exp;` or `assert(0);` at end of function
+& test
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=18607
+
+int* test(T...)() pure @safe {
+ L:foreach(_; T) {
+ continue L;
+ return null;
+ }
+}
+
+
+pragma(msg, &test!(int));
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18644.d b/gcc/testsuite/gdc.test/fail_compilation/test18644.d
new file mode 100644
index 0000000..20743ea
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18644.d
@@ -0,0 +1,25 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/test18644.d(15): Error: storing reference to stack allocated value returned by `foo()` into allocated memory causes it to escape
+fail_compilation/test18644.d(16): Error: escaping reference to stack allocated value returned by `foo()`
+fail_compilation/test18644.d(22): Error: escaping reference to stack allocated value returned by `foo()`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=18644
+
+@safe int* test1() {
+ int i;
+ int* foo() { return &i; }
+ int*[] b = [foo()];
+ return foo();
+}
+
+@safe ref int test2() {
+ int i;
+ ref int foo() { return i; }
+ return foo();
+}
+
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18708.d b/gcc/testsuite/gdc.test/fail_compilation/test18708.d
new file mode 100644
index 0000000..5c6f162
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18708.d
@@ -0,0 +1,64 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test18708.d(24): Error: one path skips field `s`
+fail_compilation/test18708.d(29): Error: one path skips field `s`
+fail_compilation/test18708.d(34): Error: one path skips field `s`
+fail_compilation/test18708.d(39): Error: one path skips field `s`
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=18708
+
+struct S { int y; @disable this(); }
+
+class C
+{
+ S s;
+
+ this(S t)
+ {
+ if (bar(s = t)) foo(); // OK
+ }
+
+ this(S t, int i)
+ {
+ i || bar(s = t);
+ }
+
+ this(S t, int i, int j)
+ {
+ i && bar(s = t);
+ }
+
+ this(S t, int i, long j)
+ {
+ i ? bar(s = t) : i;
+ }
+
+ this(S t, int i, byte j)
+ {
+ i ? i : bar(s = t);
+ }
+}
+
+int bar(S s);
+int foo();
+
+/***********************************/
+
+class E : Exception
+{
+ this(string msg, int line = 0, int pos = 0) pure nothrow @safe
+ {
+ if (line)
+ super("hello");
+ else
+ super(msg);
+ }
+
+ this(string msg, string file, size_t line) pure nothrow @safe
+ {
+ super(msg, file, line);
+ }
+}
+
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18736.d b/gcc/testsuite/gdc.test/fail_compilation/test18736.d
new file mode 100644
index 0000000..36c5fd8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18736.d
@@ -0,0 +1,23 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test18736.d(21): Error: constructor calls not allowed in loops or after labels
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=18736
+
+class A
+{
+ this(char c) { }
+
+ this(int i)
+ {
+ switch (i)
+ {
+ case 1: break;
+ case 2: .. case 4: break;
+ default: break;
+ }
+ this('c');
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19097.d b/gcc/testsuite/gdc.test/fail_compilation/test19097.d
new file mode 100644
index 0000000..b5560f0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19097.d
@@ -0,0 +1,56 @@
+/* REQUIRED_ARGS: -preview=dip1000
+ * TEST_OUTPUT:
+---
+fail_compilation/test19097.d(35): Error: scope variable `s` may not be returned
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=19097
+
+@safe:
+
+void betty(ref scope int* r, return scope int* p)
+{
+ r = p;
+}
+
+void freddy(out scope int* r, return scope int* p)
+{
+ r = p;
+}
+
+struct S
+{
+ int* a;
+ this(return scope int* b) scope { a = b; }
+
+ int* c;
+ void mem(return scope int* d) scope { c = d; }
+}
+
+S thorin()
+{
+ int i;
+ S s = S(&i); // should infer scope for s
+ return s; // so this should error
+}
+
+/************************/
+
+struct S2(T)
+{
+ int* p;
+
+ void silent(lazy void dg);
+
+ void foo()
+ {
+ char[] name;
+ silent(name = parseType());
+ }
+
+ char[] parseType(char[] name = null);
+}
+
+S2!int s2;
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19107.d b/gcc/testsuite/gdc.test/fail_compilation/test19107.d
new file mode 100644
index 0000000..98858b4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19107.d
@@ -0,0 +1,25 @@
+/*
+EXTRA_FILES: imports/imp19661.d imports/test19107a.d imports/test19107b.d
+TEST_OUTPUT:
+---
+fail_compilation/test19107.d(24): Error: template `test19107.all` cannot deduce function from argument types `!((c) => c)(string[])`
+fail_compilation/test19107.d(18): Candidate is: `all(alias pred, T)(T t)`
+ with `pred = __lambda2,
+ T = string[]`
+ must satisfy the following constraint:
+` is(typeof(I!pred(t)))`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=19107
+
+import imports.test19107b;
+
+void all(alias pred, T)(T t)
+ if (is(typeof(I!pred(t))))
+{ }
+
+void main(string[] args)
+{
+ args.all!(c => c);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19112.d b/gcc/testsuite/gdc.test/fail_compilation/test19112.d
new file mode 100644
index 0000000..f5bd403
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19112.d
@@ -0,0 +1,16 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test19112.d(13): Error: cannot implicitly convert expression `[123, 456]` of type `int[]` to `int[1]`
+fail_compilation/test19112.d(15): Error: cannot implicitly convert expression `a` of type `int[]` to `int[1]`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=19112
+
+void main()
+{
+ int[int[1]] aa;
+ int* p = [123, 456] in aa;
+ int[] a;
+ p = a in aa;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19176.d b/gcc/testsuite/gdc.test/fail_compilation/test19176.d
new file mode 100644
index 0000000..ceceb74
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19176.d
@@ -0,0 +1,26 @@
+/*
+REQUIRED_ARGS: -unittest
+TEST_OUTPUT:
+---
+fail_compilation/test19176.d(13): Error: argument `foo()` to __traits(getUnitTests) must be a module or aggregate, not a template
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=19176
+
+void main()
+{
+ __traits(getUnitTests, foo);
+}
+
+template foo()
+{
+ static if(true)
+ {
+ enum bar;
+ }
+ else
+ {
+ enum bar;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19193.d b/gcc/testsuite/gdc.test/fail_compilation/test19193.d
new file mode 100644
index 0000000..9022776
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19193.d
@@ -0,0 +1,22 @@
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT
+---
+fail_compilation/test19193.d(13): Deprecation: enum member `test19193.T19193!int.A.b` is deprecated
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=19193
+
+void main ()
+{
+ cast(void)T19193!int.A.b;
+}
+
+template T19193(T)
+{
+ enum A
+ {
+ deprecated b
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19473.d b/gcc/testsuite/gdc.test/fail_compilation/test19473.d
new file mode 100644
index 0000000..ba6024b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19473.d
@@ -0,0 +1,31 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test19473.d(14): Error: union `test19473.P` no size because of forward reference
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=19473
+
+struct A {
+ P p;
+
+ struct UTpl() {
+ union {
+ P p;
+ }
+ }
+
+ alias U = UTpl!();
+}
+
+alias B = A.U;
+
+struct C {
+ union D {
+ B b;
+ }
+}
+
+union P {
+ C.D p;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19646.d b/gcc/testsuite/gdc.test/fail_compilation/test19646.d
new file mode 100644
index 0000000..ee0b042
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19646.d
@@ -0,0 +1,11 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test19646.d(11): Error: cast from `const(int)*` to `int*` not allowed in safe code
+---
+https://issues.dlang.org/show_bug.cgi?id=19646
+ */
+
+@safe:
+
+const x = 42;
+int* y = cast(int*)&x;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19661.d b/gcc/testsuite/gdc.test/fail_compilation/test19661.d
new file mode 100644
index 0000000..369c0a8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19661.d
@@ -0,0 +1,18 @@
+/*
+EXTRA_FILES: imports/imp19661.d
+TEST_OUTPUT:
+---
+fail_compilation/test19661.d(11): Error: variables cannot be initialized with an expression of type `void`. Use `void` initialization instead.
+---
+*/
+
+module ice19661;
+
+immutable bool testModule = testFunctionMembers!();
+
+void testFunctionMembers()() {
+ import imports.imp19661 : isFunction;
+ foreach(member; __traits(allMembers, ice19661)) {
+ bool b = isFunction!(__traits(getMember, ice19661, member));
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19971.d b/gcc/testsuite/gdc.test/fail_compilation/test19971.d
new file mode 100644
index 0000000..f854362
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19971.d
@@ -0,0 +1,17 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test19971.d(15): Error: function `test19971.f(int x)` is not callable using argument types `(string)`
+fail_compilation/test19971.d(15): cannot pass argument `"%s"` of type `string` to parameter `int x`
+fail_compilation/test19971.d(16): Error: function literal `__lambda1(int x)` is not callable using argument types `(string)`
+fail_compilation/test19971.d(16): cannot pass argument `"%s"` of type `string` to parameter `int x`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=19971
+
+void f(int x) {}
+void main()
+{
+ f("%s");
+ (int x) {} ("%s");
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20096.d b/gcc/testsuite/gdc.test/fail_compilation/test20096.d
new file mode 100644
index 0000000..159efc0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20096.d
@@ -0,0 +1,28 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test20096.d(15): Error: cannot `goto` into `try` block
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=20096
+
+void test()
+{
+ int x;
+
+ try {
+ L2:
+ goto L1;
+
+ try
+ {
+ L1:
+ ++x;
+ goto L2;
+ }
+ finally
+ {
+ ++x;
+ }
+ } finally {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20149.d b/gcc/testsuite/gdc.test/fail_compilation/test20149.d
new file mode 100644
index 0000000..af99a59
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20149.d
@@ -0,0 +1,34 @@
+/* REQUIRED_ARGS: -preview=dip1000
+ * TEST_OUTPUT:
+---
+fail_compilation/test20149.d(28): Error: escaping reference to stack allocated value returned by `S('\xff').this(1)`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=20149#c10
+
+@safe:
+
+struct S
+{
+ this(int){ }
+
+ char[] opSlice() return
+ {
+ return buf[];
+ }
+
+ char[4] buf;
+}
+
+S bar();
+
+char[] fun()
+{
+ return S(1)[];
+}
+
+void main()
+{
+ auto x = fun();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20245.d b/gcc/testsuite/gdc.test/fail_compilation/test20245.d
new file mode 100644
index 0000000..24a6f99
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20245.d
@@ -0,0 +1,43 @@
+/*
+REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/test20245.d(14): Error: scope variable `a` may not be returned
+fail_compilation/test20245.d(18): Error: cannot take address of `scope` parameter `x` in `@safe` function `foo`
+fail_compilation/test20245.d(33): Error: reference to local variable `price` assigned to non-scope `this.minPrice`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=20245
+@safe int* foo(ref int x) {
+ int* a = &x;
+ return a;
+}
+
+@safe int** foo(ref scope int* x) {
+ int** a = &x;
+ return a;
+}
+
+@safe int* foo(return ref int x) {
+ int* a = &x;
+ return a;
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=21212
+class MinPointerRecorder
+{
+ int* minPrice;
+ void update(ref int price) @safe
+ {
+ minPrice = &price; // Should not compile.
+ }
+}
+
+void main() @safe
+{
+ auto r = new MinPointerRecorder;
+ () { int mp = 42; r.update(mp); } ();
+ () { ulong[1000] stomp = 13; } ();
+ auto x = *r.minPrice; // "13"
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20267.d b/gcc/testsuite/gdc.test/fail_compilation/test20267.d
new file mode 100644
index 0000000..996980a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20267.d
@@ -0,0 +1,31 @@
+/*
+EXTRA_FILES: imports/test20267.d
+TEST_OUTPUT:
+---
+fail_compilation/test20267.d(20): Error: variable `string` is used as a type
+fail_compilation/test20267.d(19): variable `string` is declared here
+fail_compilation/test20267.d(23): Error: variable `boolean` is used as a type
+fail_compilation/test20267.d(22): variable `boolean` is declared here
+fail_compilation/test20267.d(30): Error: variable `array` is used as a type
+fail_compilation/test20267.d(28): variable `array` is imported here from: `imports.test20267`
+fail_compilation/imports/test20267.d(3): variable `array` is declared here
+---
+*/
+
+alias boolean = bool;
+
+void foo(string[] args)
+{
+ immutable string = "bar";
+ string[] args2 = args;
+
+ bool boolean = true;
+ boolean b = false;
+}
+
+void bar()
+{
+ import imports.test20267 : array;
+
+ array foo;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20324.d b/gcc/testsuite/gdc.test/fail_compilation/test20324.d
new file mode 100644
index 0000000..c38e348
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20324.d
@@ -0,0 +1,16 @@
+/*
+REQUIRED_ARGS: -unittest
+TEST_OUTPUT:
+---
+fail_compilation/test20324.d(16): Error: argument `Test()` to __traits(getUnitTests) must be a module or aggregate, not a template
+fail_compilation/test20324.d(16): while evaluating `pragma(msg, __traits(getUnitTests, Test))`
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=20324
+
+template Test() {
+ unittest {
+ }
+}
+
+pragma(msg, __traits(getUnitTests, Test));
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20383.d b/gcc/testsuite/gdc.test/fail_compilation/test20383.d
new file mode 100644
index 0000000..88c56ee
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20383.d
@@ -0,0 +1,13 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test20383.d(11): Error: invalid array operation `cast(int[])data[] & [42]` (possible missing [])
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=20383
+
+ubyte[1] ice(ubyte[1] data)
+{
+ ubyte[1] result = data[] & [42];
+ return result;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20515.d b/gcc/testsuite/gdc.test/fail_compilation/test20515.d
new file mode 100644
index 0000000..cf4bbde
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20515.d
@@ -0,0 +1,18 @@
+// REQUIRED_ARGS: -verror-style=gnu
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test20515.d:16: Deprecation: function `test20515.foo` is deprecated
+fail_compilation/test20515.d:17: Error: undefined identifier `bar`
+---
+*/
+
+module test20515;
+
+deprecated void foo() { }
+
+void test()
+{
+ foo;
+ bar;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20549.d b/gcc/testsuite/gdc.test/fail_compilation/test20549.d
new file mode 100644
index 0000000..2cafc1b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20549.d
@@ -0,0 +1,12 @@
+/*
+TEST_OUTPUT:
+----
+fail_compilation/test20549.d(12): Error: variable `test.__a_field_0` variables cannot be of type `void`
+----
+*/
+
+module test;
+
+alias AliasSeq(T...) = T;
+
+enum a = AliasSeq!test;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20565.d b/gcc/testsuite/gdc.test/fail_compilation/test20565.d
new file mode 100644
index 0000000..5f21675
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20565.d
@@ -0,0 +1,19 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test20565.d(107): Error: function `test20565.test.box` the same declaration cannot be in multiple scopes with non-D linkage
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=20565
+
+#line 100
+
+void test()
+{
+ {
+ extern (C++) int box() { return 3; }
+ }
+ {
+ extern (C++) int box() { return 4; }
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20569.d b/gcc/testsuite/gdc.test/fail_compilation/test20569.d
new file mode 100644
index 0000000..a5ac98b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20569.d
@@ -0,0 +1,24 @@
+/* REQUIRED_ARGS: -preview=dip1000
+ TEST_OUTPUT:
+---
+fail_compilation/test20569.d(19): Error: cannot take address of `scope` local `s1` in `@safe` function `main`
+fail_compilation/test20569.d(23): Error: cannot take address of `scope` local `s2` in `@safe` function `main`
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=20569
+
+struct S
+{
+ int* pointer;
+}
+
+void main() @safe
+{
+ scope S s1;
+ scope int** p1 = &s1.pointer;
+
+ int x;
+ S s2 = S(&x);
+ auto p2 = &s2.pointer;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20610.d b/gcc/testsuite/gdc.test/fail_compilation/test20610.d
new file mode 100644
index 0000000..9bdeb20
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20610.d
@@ -0,0 +1,22 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test20610.d(20): Error: cannot modify `const` expression `field`
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=20610
+
+struct S
+{
+ int what;
+}
+
+void main()
+{
+ S record;
+
+ foreach (const ref field; record.tupleof)
+ {
+ field = 10;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20626.d b/gcc/testsuite/gdc.test/fail_compilation/test20626.d
new file mode 100644
index 0000000..bd0bed8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20626.d
@@ -0,0 +1,22 @@
+/*
+REQUIRED_ARGS: -check=invariant=off
+TEST_OUTPUT:
+----
+fail_compilation/test20626.d(2): Error: expression `__unittest_L1_C1` has no type
+_error_
+const void()
+----
+
+https://issues.dlang.org/show_bug.cgi?id=20626
+*/
+
+#line 1
+unittest {}
+pragma(msg, typeof(__unittest_L1_C1));
+
+struct S
+{
+ invariant {}
+}
+
+pragma(msg, typeof(S.init.__invariant1));
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20696.d b/gcc/testsuite/gdc.test/fail_compilation/test20696.d
new file mode 100644
index 0000000..7cb96e5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20696.d
@@ -0,0 +1,21 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test20696.d(106): Error: function `test20696.S!().S.test` cannot retrieve its `.mangleof` while inferring attributes
+fail_compilation/test20696.d(106): while evaluating `pragma(msg, test.mangleof)`
+fail_compilation/test20696.d(111): Error: template instance `test20696.S!()` error instantiating
+---
+*/
+
+#line 100
+
+// https://issues.dlang.org/show_bug.cgi?id=20696
+
+struct S()
+{
+ int test() {
+ pragma(msg, test.mangleof);
+ return 3;
+ }
+}
+
+S!() s;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20719.d b/gcc/testsuite/gdc.test/fail_compilation/test20719.d
new file mode 100644
index 0000000..44d3d5a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20719.d
@@ -0,0 +1,32 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test20719.d(13): Error: struct `test20719.SumType` no size because of forward reference
+fail_compilation/test20719.d(32): Error: variable `test20719.isCopyable!(SumType).__lambda2.foo` size of type `SumType` is invalid
+fail_compilation/test20719.d(18): Error: template instance `test20719.isCopyable!(SumType)` error instantiating
+---
+*/
+struct SumType
+{
+ alias Types = AliasSeq!(typeof(this));
+ union Storage
+ {
+ Types[0] t;
+ }
+
+ Storage storage;
+
+ static if (isCopyable!(Types[0])) {}
+ static if (isAssignable!(Types[0])) {}
+}
+
+alias AliasSeq(TList...) = TList;
+
+enum isAssignable(Rhs) = __traits(compiles, lvalueOf = rvalueOf!Rhs);
+
+struct __InoutWorkaroundStruct {}
+
+T rvalueOf(T)();
+
+T lvalueOf()(__InoutWorkaroundStruct);
+
+enum isCopyable(S) = { S foo; };
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21096.d b/gcc/testsuite/gdc.test/fail_compilation/test21096.d
new file mode 100644
index 0000000..e32ad9c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21096.d
@@ -0,0 +1,13 @@
+// https://issues.dlang.org/show_bug.cgi?id=21096
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21096.d(13): Error: identifier or new keyword expected following `(...)`.
+fail_compilation/test21096.d(13): Error: found `.` when expecting `]`
+fail_compilation/test21096.d(13): Error: no identifier for declarator `char`
+fail_compilation/test21096.d(13): Error: declaration expected, not `]`
+---
+*/
+
+char[(void*).];
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21198.d b/gcc/testsuite/gdc.test/fail_compilation/test21198.d
new file mode 100644
index 0000000..cab6fc8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21198.d
@@ -0,0 +1,24 @@
+// https://issues.dlang.org/show_bug.cgi?id=21198
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21198.d(23): Error: Generating an `inout` copy constructor for `struct test21198.U` failed, therefore instances of it are uncopyable
+---
+*/
+
+struct S
+{
+ this(ref inout(S) other) inout {}
+}
+
+union U
+{
+ S s;
+}
+
+void fun()
+{
+ U original;
+ U copy = original;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21204.d b/gcc/testsuite/gdc.test/fail_compilation/test21204.d
new file mode 100644
index 0000000..8732cc0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21204.d
@@ -0,0 +1,23 @@
+// https://issues.dlang.org/show_bug.cgi?id=21204
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21204.d(22): Error: Generating an `inout` copy constructor for `struct test21204.B` failed, therefore instances of it are uncopyable
+---
+*/
+
+struct A
+{
+ this(ref A other) {}
+}
+
+struct B
+{
+ A a;
+}
+
+void example()
+{
+ B b1;
+ B b2 = b1;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21246.d b/gcc/testsuite/gdc.test/fail_compilation/test21246.d
new file mode 100644
index 0000000..02c0b35
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21246.d
@@ -0,0 +1,19 @@
+// https://issues.dlang.org/show_bug.cgi?id=21246
+// EXTRA_FILES: imports/test21246.d
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21246.d(16): Error: function `void test21246.C.set(Clock clock)` does not override any function, did you mean to override `void imports.test21246.B.set(imports.test21246.Clock clock)`?
+---
+*/
+module test21246;
+
+import imports.test21246;
+
+class Clock { }
+class C : B
+{
+ override void set (Clock clock) { }
+}
+
+void main () { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21259.d b/gcc/testsuite/gdc.test/fail_compilation/test21259.d
new file mode 100644
index 0000000..31dba3d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21259.d
@@ -0,0 +1,52 @@
+// https://issues.dlang.org/show_bug.cgi?id=21259
+// REQUIRED_ARGS: -de
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21259.d(39): Deprecation: alias `test21259.Foo.width` is deprecated
+fail_compilation/test21259.d(40): Deprecation: alias `test21259.Foo2.width` is deprecated
+fail_compilation/test21259.d(41): Deprecation: variable `test21259.Foo3.bar` is deprecated
+fail_compilation/test21259.d(42): Deprecation: alias `test21259.Foo4.width` is deprecated
+---
+*/
+
+struct Foo
+{
+ int bar;
+ deprecated alias width = bar;
+}
+
+struct Foo2
+{
+ deprecated int bar;
+ deprecated alias width = bar;
+}
+
+struct Foo3
+{
+ deprecated int bar;
+}
+
+struct Foo4
+{
+ int bar;
+deprecated:
+ alias width = bar;
+}
+
+void main()
+{
+ Foo a = { width : 100};
+ Foo2 b = { width : 100};
+ Foo3 c = { bar : 100};
+ Foo4 d = { width : 100};
+}
+
+// deprecations inside a deprecated scope shouldn't be triggered
+deprecated void test()
+{
+ Foo a = { width : 100};
+ Foo2 b = { width : 100};
+ Foo3 c = { bar : 100};
+ Foo4 d = { width : 100};
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21319.d b/gcc/testsuite/gdc.test/fail_compilation/test21319.d
new file mode 100644
index 0000000..7298de2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21319.d
@@ -0,0 +1,12 @@
+// https://issues.dlang.org/show_bug.cgi?id=21319
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21319.d(11): Error: circular reference to `test21319.C.c`
+---
+*/
+
+class C
+{
+ immutable C c = new C();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21518.d b/gcc/testsuite/gdc.test/fail_compilation/test21518.d
new file mode 100644
index 0000000..59a9c3c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21518.d
@@ -0,0 +1,38 @@
+/*
+https://issues.dlang.org/show_bug.cgi?id=21518
+TEST_OUTPUT:
+---
+fail_compilation/test21518.d(19): Error: cannot implicitly convert expression `[dg]` of type `const(void delegate() pure nothrow @nogc @system)[]` to `void delegate() @safe[]`
+fail_compilation/test21518.d(23): Error: cannot implicitly convert expression `[dg]` of type `const(void delegate() pure nothrow @nogc @system)[]` to `const(void delegate() @safe)[]`
+fail_compilation/test21518.d(28): Error: cannot implicitly convert expression `sysA` of type `const(void delegate() @system)[]` to `const(void delegate() @safe)[]`
+fail_compilation/test21518.d(31): Error: cannot implicitly convert expression `sysA` of type `const(void delegate() @system)[]` to `const(void delegate() @safe)`
+fail_compilation/test21518.d(32): Error: cannot implicitly convert expression `dg` of type `const(void delegate() pure nothrow @nogc @system)` to `const(void delegate() @safe)`
+---
+*/
+
+void delegates()
+{
+ const dg = delegate() @system { int* p; int x; p = &x; };
+ // pragma(msg, typeof(dg)); // const(void delegate() pure nothrow @nogc @system)
+
+ // Correctly fails
+ void delegate() @safe[] arg2 = [ dg ];
+ void delegate() @system[] arg3 = [ dg ]; // But doesnt break this
+
+ // Previously ignored
+ const(void delegate() @safe)[] arg = [ dg ];
+ // pragma(msg, typeof(arg)); // const(void delegate() @safe)[]
+
+ // Also for variables, not only array literals
+ const(void delegate() @system)[] sysA = [ dg ];
+ const(void delegate() @safe)[] safeA = sysA;
+
+ // Original bug report:
+ func(sysA);
+ func(dg);
+}
+
+void func(const void delegate() @safe [] paramDGs...) @safe
+{
+ if (paramDGs.length > 0) paramDGs[0]();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21665.d b/gcc/testsuite/gdc.test/fail_compilation/test21665.d
new file mode 100644
index 0000000..a3a348d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21665.d
@@ -0,0 +1,31 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test21665.d(18): Error: variable `test21665.test1.s` `void` initializers for structs with invariants are not allowed in safe functions
+fail_compilation/test21665.d(30): Error: field `U.s` cannot access structs with invariants in `@safe` code that overlap other fields
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=21665
+
+struct ShortString {
+ private ubyte length;
+ private char[15] data;
+
+ invariant { assert(length <= data.length); }
+}
+
+@safe void test1() {
+ ShortString s = void;
+}
+
+union U
+{
+ int n;
+ ShortString s;
+}
+
+@safe void test2()
+{
+ U u;
+ u.s.length = 3;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21807.d b/gcc/testsuite/gdc.test/fail_compilation/test21807.d
new file mode 100644
index 0000000..9f56bf7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21807.d
@@ -0,0 +1,54 @@
+/*
+https://issues.dlang.org/show_bug.cgi?id=21807
+
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/test21807.d(11): Deprecation: slice of static array temporary returned by `getSArray()` assigned to longer lived variable `this.str`
+fail_compilation/test21807.d(12): Deprecation: slice of static array temporary returned by `getSArray()` assigned to longer lived variable `this.ca`
+---
+*/
+#line 1
+
+char[12] getSArray() pure;
+
+class Foo
+{
+ string str;
+ char[] ca;
+
+ this()
+ {
+ str = getSArray(); // Should probably be a type error
+ ca = getSArray();
+ }
+}
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21807.d(117): Error: function `test21807.addr(return ref int b)` is not callable using argument types `(int)`
+fail_compilation/test21807.d(117): cannot pass rvalue argument `S(0).i` of type `int` to parameter `return ref int b`
+---
+*/
+#line 100
+
+struct S
+{
+ int i;
+}
+
+int* addr(return ref int b)
+{
+ return &b;
+}
+
+class Foo2
+{
+ int* ptr;
+
+ this()
+ {
+ ptr = addr(S().i); // struct temporary
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21912.d b/gcc/testsuite/gdc.test/fail_compilation/test21912.d
new file mode 100644
index 0000000..8dde98a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21912.d
@@ -0,0 +1,54 @@
+/*
+PERMUTE_ARGS: -preview=dip1000
+TEST_OUTPUT
+---
+fail_compilation/test21912.d(24): Error: function `test21912.escapeParam` is `@nogc` yet allocates closures with the GC
+fail_compilation/test21912.d(26): test21912.escapeParam.__lambda2 closes over variable i at fail_compilation/test21912.d(24)
+fail_compilation/test21912.d(29): Error: function `test21912.escapeAssign` is `@nogc` yet allocates closures with the GC
+fail_compilation/test21912.d(31): test21912.escapeAssign.__lambda3 closes over variable i at fail_compilation/test21912.d(29)
+fail_compilation/test21912.d(40): Error: function `test21912.escapeAssignRef` is `@nogc` yet allocates closures with the GC
+fail_compilation/test21912.d(42): test21912.escapeAssignRef.__lambda3 closes over variable i at fail_compilation/test21912.d(40)
+fail_compilation/test21912.d(51): Error: function `test21912.escapeParamInferred` is `@nogc` yet allocates closures with the GC
+fail_compilation/test21912.d(53): test21912.escapeParamInferred.__lambda2 closes over variable i at fail_compilation/test21912.d(51)
+---
+*/
+@nogc:
+
+alias Dg = @nogc int delegate();
+
+Dg identity(return scope Dg dg)
+{
+ return dg;
+}
+
+Dg escapeParam(int i)
+{
+ return identity(() => i);
+}
+
+Dg escapeAssign(int i, return scope Dg dg)
+{
+ dg = () => i;
+ return dg;
+}
+
+ref Dg identityR(ref return scope Dg dg)
+{
+ return dg;
+}
+
+ref Dg escapeAssignRef(int i, ref return scope Dg dg)
+{
+ dg = () => i;
+ return dg;
+}
+
+auto identityInferred(Dg dg)
+{
+ return dg;
+}
+
+Dg escapeParamInferred(int i)
+{
+ return identityInferred(() => i);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22048.d b/gcc/testsuite/gdc.test/fail_compilation/test22048.d
new file mode 100644
index 0000000..e056068
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test22048.d
@@ -0,0 +1,10 @@
+// https://issues.dlang.org/show_bug.cgi?id=22048
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test22048.d(10): Error: unexpected identifier `p` in declarator
+---
+*/
+
+alias a = int p;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22227.d b/gcc/testsuite/gdc.test/fail_compilation/test22227.d
new file mode 100644
index 0000000..ecffb69
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test22227.d
@@ -0,0 +1,16 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/test22227.d(12): Error: scope variable `foo` may not be returned
+fail_compilation/test22227.d(14): Error: scope variable `foo` may not be returned
+---
+*/
+
+int[] foo() @safe
+{
+ if (scope foo = [1])
+ return foo;
+ while (scope foo = [1])
+ return foo;
+ return [];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test314.d b/gcc/testsuite/gdc.test/fail_compilation/test314.d
index eb3f07d..26de737 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test314.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test314.d
@@ -1,5 +1,5 @@
/*
-REQUIRED_ARGS:
+EXTRA_FILES: imports/a314.d imports/b314.d imports/c314.d
TEST_OUTPUT:
---
fail_compilation/test314.d(19): Error: undefined identifier `renamed`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test4838.d b/gcc/testsuite/gdc.test/fail_compilation/test4838.d
index 0bf0757..a135c79 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test4838.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test4838.d
@@ -1,12 +1,12 @@
/*
TEST_OUTPUT:
---
-fail_compilation/test4838.d(13): Error: const/immutable/shared/inout/return attributes are only valid for non-static member functions
-fail_compilation/test4838.d(14): Error: const/immutable/shared/inout/return attributes are only valid for non-static member functions
-fail_compilation/test4838.d(15): Error: const/immutable/shared/inout/return attributes are only valid for non-static member functions
-fail_compilation/test4838.d(16): Error: const/immutable/shared/inout/return attributes are only valid for non-static member functions
-fail_compilation/test4838.d(17): Error: const/immutable/shared/inout/return attributes are only valid for non-static member functions
-fail_compilation/test4838.d(18): Error: const/immutable/shared/inout/return attributes are only valid for non-static member functions
+fail_compilation/test4838.d(13): Error: `const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions
+fail_compilation/test4838.d(14): Error: `const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions
+fail_compilation/test4838.d(15): Error: `const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions
+fail_compilation/test4838.d(16): Error: `const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions
+fail_compilation/test4838.d(17): Error: `const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions
+fail_compilation/test4838.d(18): Error: `const`/`immutable`/`shared`/`inout`/`return` attributes are only valid for non-static member functions
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test4946.d b/gcc/testsuite/gdc.test/fail_compilation/test4946.d
new file mode 100644
index 0000000..e19932b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test4946.d
@@ -0,0 +1,19 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test4946.d(13): Error: 'pure' cannot be placed after a template constraint
+fail_compilation/test4946.d(14): Error: 'const' cannot be placed after a template constraint
+fail_compilation/test4946.d(15): Error: 'immutable' cannot be placed after a template constraint
+fail_compilation/test4946.d(16): Error: 'inout' cannot be placed after a template constraint
+fail_compilation/test4946.d(17): Error: 'shared' cannot be placed after a template constraint
+fail_compilation/test4946.d(18): Error: 'nothrow' cannot be placed after a template constraint
+fail_compilation/test4946.d(19): Error: attributes cannot be placed after a template constraint
+---
+*/
+
+void bar1(int x)() if (x > 0) pure { int a;}
+void bar2(int x)() if (x > 0) const { int a;}
+void bar3(int x)() if (x > 0) immutable { int a;}
+void bar4(int x)() if (x > 0) inout { int a;}
+void bar5(int x)() if (x > 0) shared { int a;}
+void bar6(int x)() if (x > 0) nothrow { int a;}
+void bar7(int x)() if (x > 0) @safe { int a;}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test64.d b/gcc/testsuite/gdc.test/fail_compilation/test64.d
index bfc63f2..d10f669 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test64.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test64.d
@@ -1,11 +1,11 @@
/*
+EXTRA_FILES: imports/test64a.d
TEST_OUTPUT:
---
-fail_compilation/imports/test64a.d(1): Error: module imports from file fail_compilation/imports/test64a.d conflicts with package name imports
+fail_compilation/imports/test64a.d(1): Error: module `imports` from file fail_compilation/imports/test64a.d conflicts with package name imports
---
*/
-// PERMUTE_ARGS:
//import std.stdio;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test8556.d b/gcc/testsuite/gdc.test/fail_compilation/test8556.d
index 3490041..75c5c59 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test8556.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test8556.d
@@ -1,8 +1,11 @@
/*
TEST_OUTPUT:
---
-fail_compilation/test8556.d(21): Error: template instance test8556.Grab!(Circle!(uint[])) does not match template declaration Grab(Range) if (!isSliceable!Range)
-fail_compilation/test8556.d(52): Error: template instance test8556.grab!(Circle!(uint[])) error instantiating
+fail_compilation/test8556.d(24): Error: template instance `test8556.Grab!(Circle!(uint[]))` does not match template declaration `Grab(Range)`
+ with `Range = Circle!(uint[])`
+ must satisfy the following constraint:
+` !isSliceable!Range`
+fail_compilation/test8556.d(55): Error: template instance `test8556.grab!(Circle!(uint[]))` error instantiating
---
*/
@@ -34,7 +37,7 @@ struct Circle(Range)
{
//pragma(msg, typeof(opSlice)); // prints "fwdref err" with B, but doesn't with A
- printf("%d %d\n", i, j);
+ printf("%d %d\n", cast(int)i, cast(int)j);
assert(j >= i);
// 1. grabExactly curcular refers this opSlice.
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test9150.d b/gcc/testsuite/gdc.test/fail_compilation/test9150.d
index 650bcd4..e65afec 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test9150.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test9150.d
@@ -1,5 +1,5 @@
-// Issue 9150 - Mismatching static array length should be detected in foreach
-
+// https://issues.dlang.org/show_bug.cgi?id=9150
+// Mismatching static array length should be detected in foreach
/*
TEST_OUTPUT:
---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test9176.d b/gcc/testsuite/gdc.test/fail_compilation/test9176.d
index 357d54f..62ae5c0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test9176.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test9176.d
@@ -1,8 +1,8 @@
/*
TEST_OUTPUT:
---
-fail_compilation/test9176.d(14): Error: forward reference to inferred return type of function call 'get()'
-fail_compilation/test9176.d(10): while evaluating: `static assert(!false)`
+fail_compilation/test9176.d(14): Error: forward reference to inferred return type of function call `get()`
+fail_compilation/test9176.d(10): while evaluating: `static assert(!is(typeof(foo(S()))))`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/testCols.d b/gcc/testsuite/gdc.test/fail_compilation/testCols.d
index d072b3c..e5bff18 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/testCols.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/testCols.d
@@ -1,10 +1,9 @@
// REQUIRED_ARGS: -vcolumns
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/testCols.d(13,5): Error: undefined identifier `nonexistent`
+fail_compilation/testCols.d(12,5): Error: undefined identifier `nonexistent`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/testInference.d b/gcc/testsuite/gdc.test/fail_compilation/testInference.d
index 3a49c58..c0d5a05 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/testInference.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/testInference.d
@@ -137,7 +137,7 @@ immutable(void)* g10063(inout int* p) pure
/*
TEST_OUTPUT:
---
-fail_compilation/testInference.d(154): Error: pure function 'testInference.bar14049' cannot call impure function 'testInference.foo14049!int.foo14049'
+fail_compilation/testInference.d(154): Error: `pure` function `testInference.bar14049` cannot call impure function `testInference.foo14049!int.foo14049`
---
*/
auto impure14049() { static int i = 1; return i; }
@@ -157,7 +157,7 @@ void bar14049() pure
/*
TEST_OUTPUT:
---
-fail_compilation/testInference.d(166): Error: pure function 'testInference.f14160' cannot access mutable static data 'g14160'
+fail_compilation/testInference.d(166): Error: `pure` function `testInference.f14160` cannot access mutable static data `g14160`
---
*/
int g14160;
@@ -169,7 +169,7 @@ int* f14160() pure
/*
TEST_OUTPUT:
---
-fail_compilation/testInference.d(180): Error: pure function 'testInference.test12422' cannot call impure function 'testInference.test12422.bar12422!().bar12422'
+fail_compilation/testInference.d(180): Error: `pure` function `testInference.test12422` cannot call impure function `testInference.test12422.bar12422!().bar12422`
---
*/
int g12422;
@@ -183,8 +183,8 @@ void test12422() pure
/*
TEST_OUTPUT:
---
-fail_compilation/testInference.d(196): Error: pure function 'testInference.test13729a' cannot access mutable static data 'g13729'
-fail_compilation/testInference.d(206): Error: pure function 'testInference.test13729b' cannot call impure function 'testInference.test13729b.foo!().foo'
+fail_compilation/testInference.d(198): Error: `pure` function `testInference.test13729a` cannot call impure function `testInference.test13729a.foo`
+fail_compilation/testInference.d(206): Error: `pure` function `testInference.test13729b` cannot call impure function `testInference.test13729b.foo!().foo`
---
*/
int g13729;
@@ -193,9 +193,9 @@ void test13729a() pure
{
static void foo() // typed as impure
{
- g13729++; // disallowed
+ g13729++;
}
- foo();
+ foo(); // cannot call impure function
}
void test13729b() pure
{
@@ -209,10 +209,10 @@ void test13729b() pure
/*
TEST_OUTPUT:
---
-fail_compilation/testInference.d(225): Error: testInference.test17086 called with argument types (bool) matches both:
-fail_compilation/testInference.d(219): testInference.test17086!(bool, false).test17086(bool x)
+fail_compilation/testInference.d(225): Error: `testInference.test17086` called with argument types `(bool)` matches both:
+fail_compilation/testInference.d(219): `testInference.test17086!(bool, false).test17086(bool x)`
and:
-fail_compilation/testInference.d(220): testInference.test17086!(bool, false).test17086(bool y)
+fail_compilation/testInference.d(220): `testInference.test17086!(bool, false).test17086(bool y)`
---
*/
@@ -224,3 +224,16 @@ void test17086_call ()
bool f;
test17086(f);
}
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/testInference.d(238): Error: `pure` function `testInference.test20047_pure_function` cannot call impure function `testInference.test20047_pure_function.bug`
+---
+*/
+void test20047_impure_function() {}
+void test20047_pure_function() pure
+{
+ static void bug() { return test20047_impure_function(); }
+ bug();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/testpull1810.d b/gcc/testsuite/gdc.test/fail_compilation/testpull1810.d
index 141c9d2..73ac830 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/testpull1810.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/testpull1810.d
@@ -2,7 +2,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/testpull1810.d(19): Warning: statement is not reachable
+fail_compilation/testpull1810.d(21): Warning: statement is not reachable
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d b/gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d
index 310e9fe..45e73c0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d
@@ -1,10 +1,10 @@
/* TEST_OUTPUT:
---
-fail_compilation/testscopestatic.d(15): Error: variable testscopestatic.foo.p cannot be 'scope' and 'static'
-fail_compilation/testscopestatic.d(16): Error: variable testscopestatic.foo.b cannot be 'scope' and 'extern'
-fail_compilation/testscopestatic.d(17): Error: variable testscopestatic.foo.c cannot be 'scope' and '__gshared'
-fail_compilation/testscopestatic.d(21): Error: variable testscopestatic.foo.S.x field cannot be 'scope'
+fail_compilation/testscopestatic.d(15): Error: variable `testscopestatic.foo.p` cannot be `scope` and `static`
+fail_compilation/testscopestatic.d(16): Error: variable `testscopestatic.foo.b` cannot be `scope` and `extern`
+fail_compilation/testscopestatic.d(17): Error: variable `testscopestatic.foo.c` cannot be `scope` and `__gshared`
+fail_compilation/testscopestatic.d(21): Error: variable `testscopestatic.foo.S.x` field cannot be `scope`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d b/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d
index 8d5d480..c5d0579 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d
@@ -2,14 +2,14 @@
TEST_OUTPUT:
---
fail_compilation/trait_loc_err.d(13): Error: can only get the location of a symbol, not `trait_loc_err`
-fail_compilation/trait_loc_err.d(14): Error: can only get the location of a symbol, not `std`
+fail_compilation/trait_loc_err.d(14): Error: can only get the location of a symbol, not `stdc`
---
*/
module trait_loc_err;
-import std.stdio;
+import core.stdc.stdio;
void main()
{
__traits(getLocation, __traits(parent, main));
- __traits(getLocation, __traits(parent, std.stdio));
+ __traits(getLocation, __traits(parent, core.stdc.stdio));
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/traits.d b/gcc/testsuite/gdc.test/fail_compilation/traits.d
index bee29ed..5b9daaa 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/traits.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/traits.d
@@ -11,6 +11,16 @@ fail_compilation/traits.d(200): Error: undefined identifier `imports.nonexistent
fail_compilation/traits.d(201): Error: undefined identifier `imports.nonexistent`
fail_compilation/traits.d(202): Error: expected 1 arguments for `isPackage` but had 0
fail_compilation/traits.d(203): Error: expected 1 arguments for `isModule` but had 0
+fail_compilation/traits.d(300): Error: In expression `__traits(allMembers, float)` `float` can't have members
+fail_compilation/traits.d(300): `float` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation
+fail_compilation/traits.d(306): Error: In expression `__traits(allMembers, TemplatedStruct)` struct `TemplatedStruct(T)` has no members
+fail_compilation/traits.d(306): `TemplatedStruct(T)` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation
+fail_compilation/traits.d(309): Error: In expression `__traits(derivedMembers, float)` `float` can't have members
+fail_compilation/traits.d(309): `float` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation
+fail_compilation/traits.d(316): Error: In expression `__traits(derivedMembers, TemplatedStruct)` struct `TemplatedStruct(T)` has no members
+fail_compilation/traits.d(316): `TemplatedStruct(T)` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation
+fail_compilation/traits.d(404): Error: function `traits.func1` circular reference in `__traits(GetCppNamespaces,...)`
+fail_compilation/traits.d(413): Error: function `traits.foo1.func1` circular reference in `__traits(GetCppNamespaces,...)`
---
*/
@@ -25,3 +35,84 @@ enum A2 = __traits(isPackage, imports.nonexistent);
enum B2 = __traits(isModule, imports.nonexistent);
enum C2 = __traits(isPackage);
enum D2 = __traits(isModule);
+
+interface Interface {}
+struct TemplatedStruct(T) {}
+struct Struct {}
+union Union {}
+class Class {}
+
+#line 300
+enum AM0 = __traits(allMembers, float); // compile error
+enum AM1 = __traits(allMembers, Struct); // no error
+enum AM2 = __traits(allMembers, Union); // no error
+enum AM3 = __traits(allMembers, Class); // no error
+enum AM4 = __traits(allMembers, Interface); // no error
+enum AM5 = __traits(allMembers, TemplatedStruct!float); // no error
+enum AM6 = __traits(allMembers, TemplatedStruct); // compile error
+enum AM7 = __traits(allMembers, mixin(__MODULE__)); // no error
+
+enum DM0 = __traits(derivedMembers, float); // compile error
+enum DM1 = __traits(derivedMembers, Struct); // no error
+enum DM2 = __traits(derivedMembers, Struct); // no error
+enum DM3 = __traits(derivedMembers, Union); // no error
+enum DM4 = __traits(derivedMembers, Class); // no error
+enum DM5 = __traits(derivedMembers, Interface); // no error
+enum DM6 = __traits(derivedMembers, TemplatedStruct!float); // no error
+enum DM7 = __traits(derivedMembers, TemplatedStruct); // compile error
+enum DM8 = __traits(derivedMembers, mixin(__MODULE__)); // no error
+
+#line 400
+extern(C++, "bar")
+extern(C++, __traits(getCppNamespaces, func1)) void func () {}
+
+extern(C++, "foo")
+extern(C++, __traits(getCppNamespaces, func2)) void func1 () {}
+
+extern(C++, "foobar")
+extern(C++, __traits(getCppNamespaces, func)) void func2 () {}
+
+extern(C++, bar1)
+extern(C++, __traits(getCppNamespaces, foo1.func1)) void func () {}
+
+extern(C++, foo1)
+extern(C++, __traits(getCppNamespaces, foobar1.func2)) void func1 () {}
+
+extern(C++, foobar1)
+extern(C++, __traits(getCppNamespaces, bar1.func)) void func2 () {}
+
+/********************************************
+https://issues.dlang.org/show_bug.cgi?id=21918
+
+TEST_OUTPUT:
+---
+fail_compilation/traits.d(501): Error: undefined identifier `T`
+fail_compilation/traits.d(502): while evaluating `pragma(msg, __traits(getParameterStorageClasses, yip, 0))`
+---
+*/
+#line 500
+
+auto yip(int f) {return T[];}
+pragma(msg, __traits(getParameterStorageClasses, yip, 0));
+
+
+/********************************************
+TEST_OUTPUT:
+---
+fail_compilation/traits.d(602): Error: expected 1 arguments for `hasCopyConstructor` but had 0
+fail_compilation/traits.d(602): while evaluating `pragma(msg, __traits(hasCopyConstructor))`
+fail_compilation/traits.d(603): Error: type expected as second argument of __traits `hasCopyConstructor` instead of `S()`
+fail_compilation/traits.d(603): while evaluating `pragma(msg, __traits(hasCopyConstructor, S()))`
+fail_compilation/traits.d(604): Error: expected 1 arguments for `hasPostblit` but had 0
+fail_compilation/traits.d(604): while evaluating `pragma(msg, __traits(hasPostblit))`
+fail_compilation/traits.d(605): Error: type expected as second argument of __traits `hasPostblit` instead of `S()`
+fail_compilation/traits.d(605): while evaluating `pragma(msg, __traits(hasPostblit, S()))`
+---
+*/
+#line 600
+
+struct S { this (ref S rhs) {} }
+pragma(msg, __traits(hasCopyConstructor));
+pragma(msg, __traits(hasCopyConstructor, S()));
+pragma(msg, __traits(hasPostblit));
+pragma(msg, __traits(hasPostblit, S()));
diff --git a/gcc/testsuite/gdc.test/fail_compilation/traits_child.d b/gcc/testsuite/gdc.test/fail_compilation/traits_child.d
index 7a0b75e..aeaf213 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/traits_child.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/traits_child.d
@@ -4,10 +4,8 @@
TEST_OUTPUT:
---
fail_compilation/traits_child.d(100): Error: expected 2 arguments for `child` but had 1
-fail_compilation/traits_child.d(101): Error: symbol or expression expected as first argument of __traits
-child` instead of `long`
-fail_compilation/traits_child.d(102): Error: symbol expected as second argument of __traits `child` inste
-d of `3`
+fail_compilation/traits_child.d(101): Error: symbol or expression expected as first argument of __traits `child` instead of `long`
+fail_compilation/traits_child.d(102): Error: symbol expected as second argument of __traits `child` instead of `3`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d b/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d
index ba80fdc..a93a49f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d
@@ -1,22 +1,22 @@
/*
-PERMUTE_ARGS:
TEST_OUTPUT:
---
fail_compilation/typeerrors.d(36): Error: tuple index 4 exceeds 4
-fail_compilation/typeerrors.d(38): Error: variable x cannot be read at compile time
-fail_compilation/typeerrors.d(39): Error: can't have array of void()
-fail_compilation/typeerrors.d(40): Error: cannot have array of scope typeerrors.C
-fail_compilation/typeerrors.d(41): Error: cannot have array of scope typeerrors.C
-fail_compilation/typeerrors.d(44): Error: int[5] is not an expression
-fail_compilation/typeerrors.d(46): Error: x is used as a type
-fail_compilation/typeerrors.d(47): Error: can't have associative array key of void()
-fail_compilation/typeerrors.d(48): Error: can't have associative array key of void
-fail_compilation/typeerrors.d(49): Error: cannot have array of scope typeerrors.C
-fail_compilation/typeerrors.d(50): Error: can't have associative array of void
-fail_compilation/typeerrors.d(51): Error: can't have associative array of void()
-fail_compilation/typeerrors.d(53): Error: cannot have parameter of type void
-fail_compilation/typeerrors.d(55): Error: slice [1..5] is out of range of [0..4]
-fail_compilation/typeerrors.d(56): Error: slice [2..1] is out of range of [0..4]
+fail_compilation/typeerrors.d(38): Error: variable `x` cannot be read at compile time
+fail_compilation/typeerrors.d(39): Error: cannot have array of `void()`
+fail_compilation/typeerrors.d(40): Error: cannot have array of scope `typeerrors.C`
+fail_compilation/typeerrors.d(41): Error: cannot have array of scope `typeerrors.C`
+fail_compilation/typeerrors.d(44): Error: `int[5]` is not an expression
+fail_compilation/typeerrors.d(46): Error: variable `x` is used as a type
+fail_compilation/typeerrors.d(37): variable `x` is declared here
+fail_compilation/typeerrors.d(47): Error: cannot have associative array key of `void()`
+fail_compilation/typeerrors.d(48): Error: cannot have associative array key of `void`
+fail_compilation/typeerrors.d(49): Error: cannot have array of scope `typeerrors.C`
+fail_compilation/typeerrors.d(50): Error: cannot have associative array of `void`
+fail_compilation/typeerrors.d(51): Error: cannot have associative array of `void()`
+fail_compilation/typeerrors.d(53): Error: cannot have parameter of type `void`
+fail_compilation/typeerrors.d(55): Error: slice `[1..5]` is out of range of [0..4]
+fail_compilation/typeerrors.d(56): Error: slice `[2..1]` is out of range of [0..4]
---
*/
@@ -55,4 +55,3 @@ void foo()
alias T2 = T[1 .. 5];
alias T3 = T[2 .. 1];
}
-
diff --git a/gcc/testsuite/gdc.test/fail_compilation/union_initialization.d b/gcc/testsuite/gdc.test/fail_compilation/union_initialization.d
new file mode 100644
index 0000000..36fc63a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/union_initialization.d
@@ -0,0 +1,88 @@
+/*
+https://issues.dlang.org/show_bug.cgi?id=20068
+
+TEST_OUTPUT:
+---
+fail_compilation/union_initialization.d(19): Error: field `B.p` cannot access pointers in `@safe` code that overlap other fields
+fail_compilation/union_initialization.d(25): Error: field `B.p` cannot access pointers in `@safe` code that overlap other fields
+---
+*/
+
+union B
+{
+ int i;
+ int* p;
+
+ @safe this(int* p)
+ {
+ this.p = p;
+ int* x = this.p;
+ }
+
+ @safe this(int** i)
+ {
+ this.p = null;
+ this.p = *i;
+ }
+}
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/union_initialization.d(109): Error: immutable field `p` initialized multiple times
+fail_compilation/union_initialization.d(108): Previous initialization is here.
+---
+*/
+#line 100
+
+union C
+{
+ int i;
+ immutable int* p;
+
+ @safe this(immutable int* p)
+ {
+ this.p = p;
+ this.p = null;
+ }
+}
+
+/*
+https://issues.dlang.org/show_bug.cgi?id=21229
+
+TEST_OUTPUT:
+---
+fail_compilation/union_initialization.d(223): Error: field `union_` must be initialized in constructor
+fail_compilation/union_initialization.d(223): Error: field `proxy` must be initialized in constructor
+---
+*/
+#line 200
+
+struct NeedsInit
+{
+ int var;
+ long lo;
+ @disable this();
+}
+
+union Union
+{
+ NeedsInit ni;
+}
+
+union Proxy
+{
+ Union union_;
+}
+
+struct S
+{
+ Union union_;
+ Proxy proxy;
+
+ this(int arg)
+ {
+ union_.ni.var = arg;
+ proxy.union_.ni.var = arg;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/vararg2.d b/gcc/testsuite/gdc.test/fail_compilation/vararg2.d
new file mode 100644
index 0000000..eb23558
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/vararg2.d
@@ -0,0 +1,23 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/vararg2.d(106): Error: function `vararg2.foo(int x, const return ...)` is not callable using argument types `(double)`
+fail_compilation/vararg2.d(106): cannot pass argument `1.0` of type `double` to parameter `int x`
+fail_compilation/vararg2.d(111): Error: function `vararg2.bar(int x, scope shared ...)` is not callable using argument types `(double)`
+fail_compilation/vararg2.d(111): cannot pass argument `1.0` of type `double` to parameter `int x`
+---
+*/
+
+#line 100
+
+int* foo(int x, return const ...);
+int* bar(int x, scope shared ...);
+
+void test1()
+{
+ foo(1.0);
+}
+
+void test2()
+{
+ bar(1.0);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/varargsstc.d b/gcc/testsuite/gdc.test/fail_compilation/varargsstc.d
new file mode 100644
index 0000000..674455b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/varargsstc.d
@@ -0,0 +1,11 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/varargsstc.d(102): Error: variadic parameter cannot have attributes `out ref`
+---
+ */
+
+#line 100
+
+int printf(const(char)*, const scope shared return ...);
+int printf(const(char)*, ref out scope immutable shared return ...);
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/verifyhookexist.d b/gcc/testsuite/gdc.test/fail_compilation/verifyhookexist.d
new file mode 100644
index 0000000..d7b8f66
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/verifyhookexist.d
@@ -0,0 +1,45 @@
+/*
+REQUIRED_ARGS: -checkaction=context
+EXTRA_SOURCES: extra-files/minimal/object.d
+*/
+
+/************************************************************/
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/verifyhookexist.d(22): Error: `object.__ArrayCast` not found. The current runtime does not support casting array of structs, or the runtime is corrupt.
+fail_compilation/verifyhookexist.d(28): Error: `object.__equals` not found. The current runtime does not support equal checks on arrays, or the runtime is corrupt.
+fail_compilation/verifyhookexist.d(29): Error: `object.__cmp` not found. The current runtime does not support comparing arrays, or the runtime is corrupt.
+fail_compilation/verifyhookexist.d(33): Error: `object._d_assert_fail` not found. The current runtime does not support generating assert messages, or the runtime is corrupt.
+fail_compilation/verifyhookexist.d(36): Error: `object.__switch` not found. The current runtime does not support switch cases on strings, or the runtime is corrupt.
+fail_compilation/verifyhookexist.d(41): Error: `object.__switch_error` not found. The current runtime does not support generating assert messages, or the runtime is corrupt.
+---
+*/
+
+struct MyStruct { int a, b; }
+MyStruct[] castToMyStruct(int[] arr) {
+ return cast(MyStruct[])arr;
+}
+
+void test() {
+ int[] arrA, arrB;
+
+ bool a = arrA[] == arrB[];
+ bool b = arrA < arrB;
+
+ {
+ int x = 1; int y = 1;
+ assert(x == y);
+ }
+
+ switch ("") {
+ default:
+ break;
+ }
+
+ final switch (0) {
+ case 1:
+ break;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/warn13679.d b/gcc/testsuite/gdc.test/fail_compilation/warn13679.d
index 0a92b76..74d4564 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/warn13679.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/warn13679.d
@@ -1,10 +1,11 @@
// REQUIRED_ARGS: -w
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/warn13679.d(14): Warning: cannot use foreach_reverse with an associative array
+fail_compilation/warn13679.d(15): Warning: cannot use `foreach_reverse` with an associative array
+Error: warnings are treated as errors
+ Use -wi if you wish to treat warnings only as informational.
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/warn7444.d b/gcc/testsuite/gdc.test/fail_compilation/warn7444.d
index ec7d49c..025039a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/warn7444.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/warn7444.d
@@ -1,10 +1,9 @@
// REQUIRED_ARGS: -w
-// PERMUTE_ARGS:
/*
TEST_OUTPUT:
---
-fail_compilation/warn7444.d(23): Error: cannot implicitly convert expression `e` of type `int` to `int[]`
+fail_compilation/warn7444.d(22): Error: cannot implicitly convert expression `e` of type `int` to `int[]`
---
*/
diff --git a/gcc/testsuite/gdc.test/runnable/A16.d b/gcc/testsuite/gdc.test/runnable/A16.d
index f653353..e89e714 100644
--- a/gcc/testsuite/gdc.test/runnable/A16.d
+++ b/gcc/testsuite/gdc.test/runnable/A16.d
@@ -1,6 +1,13 @@
-// EXTRA_SOURCES: imports/A16a.d
+/*
+EXTRA_SOURCES: imports/A16a.d
+RUN_OUTPUT:
+---
+class AA16
+class B16
+---
+*/
-import std.stdio;
+import core.stdc.stdio;
class AA16
{
diff --git a/gcc/testsuite/gdc.test/runnable/Same.d b/gcc/testsuite/gdc.test/runnable/Same.d
index 85025e7..a4c6f0f 100644
--- a/gcc/testsuite/gdc.test/runnable/Same.d
+++ b/gcc/testsuite/gdc.test/runnable/Same.d
@@ -1,5 +1,12 @@
-// EXTRA_SOURCES: imports/Other.d
-// PERMUTE_ARGS:
+/*
+EXTRA_SOURCES: imports/Other.d
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+Same
+other
+---
+*/
module Same; // makes no difference if removed
import core.stdc.stdio;
diff --git a/gcc/testsuite/gdc.test/runnable/a17.d b/gcc/testsuite/gdc.test/runnable/a17.d
index 79eeecf..21f4f38 100644
--- a/gcc/testsuite/gdc.test/runnable/a17.d
+++ b/gcc/testsuite/gdc.test/runnable/a17.d
@@ -1,8 +1,14 @@
-// EXTRA_SOURCES: imports/a17a.d
+/*
+EXTRA_SOURCES: imports/a17a.d
+RUN_OUTPUT:
+---
+barx
+---
+*/
module a17;
-import std.stdio;
+import core.stdc.stdio;
private import imports.a17a;
diff --git a/gcc/testsuite/gdc.test/runnable/a18.d b/gcc/testsuite/gdc.test/runnable/a18.d
index 4d8b000..f568982 100644
--- a/gcc/testsuite/gdc.test/runnable/a18.d
+++ b/gcc/testsuite/gdc.test/runnable/a18.d
@@ -1,6 +1,12 @@
-// COMPILE_SEPARATELY
-// EXTRA_SOURCES: imports/a18a.d
-// PERMUTE_ARGS:
+/*
+COMPILE_SEPARATELY
+EXTRA_SOURCES: imports/a18a.d
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+Test enumerator
+---
+*/
import imports.a18a;
diff --git a/gcc/testsuite/gdc.test/runnable/a21.d b/gcc/testsuite/gdc.test/runnable/a21.d
index 6b3be9d..65806c4 100644
--- a/gcc/testsuite/gdc.test/runnable/a21.d
+++ b/gcc/testsuite/gdc.test/runnable/a21.d
@@ -1,7 +1,14 @@
-// EXTRA_SOURCES: imports/a21a.d
-// PERMUTE_ARGS:
+/*
+EXTRA_SOURCES: imports/a21a.d
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+goodFunc
+badFunc
+---
+*/
-import std.stdio;
+import core.stdc.stdio;
import imports.a21a;
@@ -26,4 +33,3 @@ int main()
return 0;
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/aliasassign.d b/gcc/testsuite/gdc.test/runnable/aliasassign.d
new file mode 100644
index 0000000..986cccc
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/aliasassign.d
@@ -0,0 +1,31 @@
+
+
+template AliasSeq(T...) { alias AliasSeq = T; }
+
+template staticMap(alias F, T...)
+{
+ alias A = AliasSeq!();
+ static foreach (t; T)
+ A = AliasSeq!(A, F!t);
+ alias staticMap = A;
+}
+
+template Qual(alias T)
+{
+ alias Qual = T;
+}
+
+void test()
+{
+ int x = 3;
+ int y = 4;
+
+ alias XY = staticMap!(Qual, x, y);
+ assert(XY[0] == 3);
+ assert(XY[1] == 4);
+}
+
+void main()
+{
+ test();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/aliasthis.d b/gcc/testsuite/gdc.test/runnable/aliasthis.d
index ee8e6a1..cc12f55 100644
--- a/gcc/testsuite/gdc.test/runnable/aliasthis.d
+++ b/gcc/testsuite/gdc.test/runnable/aliasthis.d
@@ -132,7 +132,7 @@ struct Iter
bool empty() { return true; }
void popFront() { }
ref Tup!(int, int) front() { return *new Tup!(int, int); }
- ref Iter opSlice() { return this; }
+ ref Iter opSlice() return { return this; }
}
void test4()
@@ -153,7 +153,7 @@ void test5()
}
/**********************************************/
-// 4617
+// https://issues.dlang.org/show_bug.cgi?id=4617
struct S4617
{
@@ -215,7 +215,7 @@ void test4617b()
}
/**********************************************/
-// 4773
+// https://issues.dlang.org/show_bug.cgi?id=4773
void test4773()
{
@@ -233,7 +233,7 @@ void test4773()
}
/**********************************************/
-// 5188
+// https://issues.dlang.org/show_bug.cgi?id=5188
void test5188()
{
@@ -434,7 +434,7 @@ void test7()
static assert(!__traits(compiles, { switch (c1) { default: } }));
static assert(!__traits(compiles, { switch (c3) { default: } }));
- // Bugzilla 12537: function arguments with IFTI
+ // https://issues.dlang.org/show_bug.cgi?id=12537: function arguments with IFTI
void eq12537()(Object lhs) {}
const C0 cc0;
const C1 cc1;
@@ -445,7 +445,8 @@ void test7()
}
/***************************************************/
-// 11875 - endless recursion in Type::deduceType
+// https://issues.dlang.org/show_bug.cgi?id=11875
+// endless recursion in Type::deduceType
struct T11875x(C)
{
@@ -467,7 +468,7 @@ class D11875c { T11875y!D11875b c; alias c this; }
static assert(is(D11875c : T11875y!D, D) && is(D == D11875b));
/***************************************************/
-// 11930
+// https://issues.dlang.org/show_bug.cgi?id=11930
class BarObj11930 {}
@@ -492,7 +493,7 @@ void test11930()
}
/***************************************************/
-// 2781
+// https://issues.dlang.org/show_bug.cgi?id=2781
struct Tuple2781a(T...) {
T data;
@@ -594,7 +595,7 @@ void test2781()
}
/**********************************************/
-// 6546
+// https://issues.dlang.org/show_bug.cgi?id=6546
void test6546()
{
@@ -643,7 +644,7 @@ void test6546()
}
/**********************************************/
-// 6736
+// https://issues.dlang.org/show_bug.cgi?id=6736
void test6736()
{
@@ -661,7 +662,7 @@ void test6736()
}
/**********************************************/
-// 2777
+// https://issues.dlang.org/show_bug.cgi?id=2777
struct ArrayWrapper(T) {
T[] array;
@@ -698,7 +699,7 @@ void test2777b()
}
/****************************************/
-// 2787
+// https://issues.dlang.org/show_bug.cgi?id=2787
struct Base2787
{
@@ -715,7 +716,7 @@ struct Derived2787
}
/***********************************/
-// 5679
+// https://issues.dlang.org/show_bug.cgi?id=5679
void test5679()
{
@@ -736,7 +737,7 @@ void test5679()
}
/***********************************/
-// 6508
+// https://issues.dlang.org/show_bug.cgi?id=6508
void test6508()
{
@@ -791,7 +792,7 @@ void test6508x()
}
/***********************************/
-// 6369
+// https://issues.dlang.org/show_bug.cgi?id=6369
void test6369a()
{
@@ -869,7 +870,7 @@ void test6369d()
}
/**********************************************/
-// 6434
+// https://issues.dlang.org/show_bug.cgi?id=6434
struct Variant6434{}
@@ -890,7 +891,7 @@ void test6434()
}
/**************************************/
-// 6366
+// https://issues.dlang.org/show_bug.cgi?id=6366
void test6366()
{
@@ -965,7 +966,7 @@ void test6366()
}
/***************************************************/
-// 6711
+// https://issues.dlang.org/show_bug.cgi?id=6711
void test6711()
{
@@ -989,7 +990,7 @@ void test6711()
}
/**********************************************/
-// 12161
+// https://issues.dlang.org/show_bug.cgi?id=12161
class A12161
{
@@ -1011,7 +1012,7 @@ void test12161()
}
/**********************************************/
-// 6759
+// https://issues.dlang.org/show_bug.cgi?id=6759
struct Range
{
@@ -1037,7 +1038,7 @@ void test6759()
}
/**********************************************/
-// 6479
+// https://issues.dlang.org/show_bug.cgi?id=6479
struct Memory6479
{
@@ -1053,7 +1054,7 @@ mixin template Wrapper6479()
}
/**********************************************/
-// 6832
+// https://issues.dlang.org/show_bug.cgi?id=6832
void test6832()
{
@@ -1071,7 +1072,7 @@ void test6832()
}
/**********************************************/
-// 6928
+// https://issues.dlang.org/show_bug.cgi?id=6928
void test6928()
{
@@ -1094,7 +1095,7 @@ void test6928()
}
/**********************************************/
-// 6929
+// https://issues.dlang.org/show_bug.cgi?id=6929
struct S6929
{
@@ -1114,7 +1115,7 @@ void test6929()
}
/***************************************************/
-// 7136
+// https://issues.dlang.org/show_bug.cgi?id=7136
void test7136()
{
@@ -1140,7 +1141,7 @@ void test7136()
}
/***************************************************/
-// 7731
+// https://issues.dlang.org/show_bug.cgi?id=7731
struct A7731
{
@@ -1183,7 +1184,7 @@ void test7731()
}
/***************************************************/
-// 7808
+// https://issues.dlang.org/show_bug.cgi?id=7808
struct Nullable7808(T)
{
@@ -1213,7 +1214,7 @@ void test7808()
}
/***************************************************/
-// 7945
+// https://issues.dlang.org/show_bug.cgi?id=7945
struct S7945
{
@@ -1232,7 +1233,8 @@ void test7945()
}
/***************************************************/
-// 15674 - alias this on out parameter, consistent with 7945 case
+// https://issues.dlang.org/show_bug.cgi?id=15674
+// alias this on out parameter, consistent with 7945 case
struct S15674
{
@@ -1251,7 +1253,7 @@ void test15674()
}
/***************************************************/
-// 7979
+// https://issues.dlang.org/show_bug.cgi?id=7979
void test7979()
{
@@ -1291,7 +1293,7 @@ void test7979()
}
/***************************************************/
-// 7992
+// https://issues.dlang.org/show_bug.cgi?id=7992
struct S7992
{
@@ -1314,7 +1316,7 @@ void test7992()
}
/***************************************************/
-// 8169
+// https://issues.dlang.org/show_bug.cgi?id=8169
void test8169()
{
@@ -1339,7 +1341,7 @@ void test8169()
}
/***************************************************/
-// 8735
+// https://issues.dlang.org/show_bug.cgi?id=8735
struct S8735(alias Arg)
{
@@ -1360,11 +1362,11 @@ void test8735()
int n = s;
assert(n == 1);
- // 11502 case
+ // https://issues.dlang.org/show_bug.cgi?id=11502
static void f(int i);
S8735!f sf;
- // 9709 case
+ // https://issues.dlang.org/show_bug.cgi?id=9709
alias A = Tuple9709!(1,int,"foo");
A a;
//static assert(A[0] == 1);
@@ -1376,7 +1378,7 @@ void test8735()
}
/***************************************************/
-// 9174
+// https://issues.dlang.org/show_bug.cgi?id=9174
void test9174()
{
@@ -1390,7 +1392,7 @@ void test9174()
}
/***************************************************/
-// 9177
+// https://issues.dlang.org/show_bug.cgi?id=9177
struct S9177
{
@@ -1400,7 +1402,7 @@ struct S9177
pragma(msg, is(S9177 : int));
/***************************************************/
-// 9858
+// https://issues.dlang.org/show_bug.cgi?id=9858
struct S9858()
{
@@ -1418,7 +1420,7 @@ void test9858()
}
/***************************************************/
-// 9873
+// https://issues.dlang.org/show_bug.cgi?id=9873
void test9873()
{
@@ -1453,7 +1455,7 @@ void test9873()
}
/***************************************************/
-// 10178
+// https://issues.dlang.org/show_bug.cgi?id=10178
void test10178()
{
@@ -1473,7 +1475,7 @@ void test10178()
}
/***************************************************/
-// 10179
+// https://issues.dlang.org/show_bug.cgi?id=10179
void test10179()
{
@@ -1493,7 +1495,7 @@ void test10179()
}
/***************************************************/
-// 9890
+// https://issues.dlang.org/show_bug.cgi?id=9890
void test9890()
{
@@ -1519,7 +1521,7 @@ void test9890()
}
/***************************************************/
-// 10004
+// https://issues.dlang.org/show_bug.cgi?id=10004
void test10004()
{
@@ -1541,7 +1543,7 @@ void test10004()
}
/***************************************************/
-// 10180
+// https://issues.dlang.org/show_bug.cgi?id=10180
template TypeTuple10180(TL...) { alias TypeTuple10180 = TL; }
@@ -1580,7 +1582,7 @@ void test10180()
}
/***************************************************/
-// 10456
+// https://issues.dlang.org/show_bug.cgi?id=10456
void test10456()
{
@@ -1596,7 +1598,7 @@ struct S10456
}
/***************************************************/
-// 11261
+// https://issues.dlang.org/show_bug.cgi?id=11261
template Tuple11261(Specs...)
{
@@ -1686,7 +1688,7 @@ void test11261()
}
/***************************************************/
-// 11333
+// https://issues.dlang.org/show_bug.cgi?id=11333
alias id11333(a...) = a;
@@ -1712,7 +1714,22 @@ void test11333()
}
/***************************************************/
-// 11800
+// https://issues.dlang.org/show_bug.cgi?id=11538
+
+struct NullableRef11538(T)
+{
+ T* _value;
+ inout(T) get() inout { return *_value; }
+ alias get this;
+}
+
+struct S11538
+{
+ NullableRef11538!S11538 parent;
+}
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11800
struct A11800
{
@@ -1739,7 +1756,7 @@ void test11800()
}
/***************************************************/
-// 12008
+// https://issues.dlang.org/show_bug.cgi?id=12008
struct RefCounted12008(T)
{
@@ -1792,7 +1809,7 @@ struct Group12008
}
/***************************************************/
-// 12038
+// https://issues.dlang.org/show_bug.cgi?id=12038
bool f12038(void* p) { return true; }
@@ -1803,7 +1820,7 @@ struct S12038
}
/***************************************************/
-// 13490
+// https://issues.dlang.org/show_bug.cgi?id=13490
struct S13490
{
@@ -1830,7 +1847,7 @@ void test13490()
}
/***************************************************/
-// 11355
+// https://issues.dlang.org/show_bug.cgi?id=11355
struct A11355
{
@@ -1855,7 +1872,7 @@ void test11355()
}
/***************************************************/
-// 13009
+// https://issues.dlang.org/show_bug.cgi?id=13009
struct T13009
{
@@ -1909,7 +1926,7 @@ void test13009()
}
/***************************************************/
-// 14806
+// https://issues.dlang.org/show_bug.cgi?id=14806
struct Nullable14806
{
@@ -1926,18 +1943,18 @@ struct Foo14806(T)
void test14806()
{
Foo14806!int a, b;
- assert(a != b);
+ assert(a == b);
// ==> a.tupleof != b.tupleof
// ==> a.bar != b.bar || a.baz.get() != b.baz.get()
Foo14806!string c, d;
- assert(c != d);
+ assert(c == d);
// ==> c.tupleof != d.tupleof
// ==> c.bar != d.bar || c.baz.get() != d.baz.get()
}
/***************************************************/
-// 14948
+// https://issues.dlang.org/show_bug.cgi?id=14948
struct RefCounted14948(T)
{
@@ -1967,7 +1984,7 @@ void test14948()
}
/***************************************************/
-// 15292
+// https://issues.dlang.org/show_bug.cgi?id=15292
struct NullableRef15292(T)
{
@@ -1998,6 +2015,93 @@ struct S15292
/***************************************************/
+struct S19284a { int x; }
+struct S19284b
+{
+ S19284a s;
+ alias s this;
+ int t;
+ void f()
+ {
+ void wrapped()
+ {
+ x = 1;
+ t = 1;
+ }
+ wrapped(); // <-- 'x' not found, whereas 's.x' works fine
+ }
+
+ void f1()
+ {
+ x = 2;
+ }
+
+ void f2()
+ {
+ int x;
+ void wrapped()
+ {
+ x = 7;
+ }
+ wrapped();
+ assert(x == 7);
+ }
+
+ void f3()
+ {
+ void wrapped()
+ {
+ void wrapped2()
+ {
+ x = 5;
+ }
+ wrapped2();
+ }
+ wrapped();
+ }
+}
+
+void test19284()
+{
+ S19284b t;
+
+ // nested function modifies alias this
+ t.f();
+ assert(t.x == 1);
+ assert(t.t == 1);
+
+ // member function modifies alias this
+ t.f1();
+ assert(t.x == 2);
+
+ // nested function does not modify alias this when it is shadowd by a local variable
+ t.f2();
+ assert(t.x == 2);
+
+ // multiple levels of nesting
+ t.f3();
+ assert(t.x == 5);
+}
+
+// 16633
+
+class Item
+{
+ alias children this;
+ Item[] children;
+ void populate()
+ {
+ children ~= new Item(); // Item is seen as []
+ assert(children.length == 1);
+ }
+}
+
+void test16633()
+{
+ Item root = new Item();
+ root.populate;
+}
+
int main()
{
test1();
@@ -2054,6 +2158,8 @@ int main()
test13490();
test11355();
test14806();
+ test19284();
+ test16633();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/arrayop.d b/gcc/testsuite/gdc.test/runnable/arrayop.d
index 8c6b083..4c0836a 100644
--- a/gcc/testsuite/gdc.test/runnable/arrayop.d
+++ b/gcc/testsuite/gdc.test/runnable/arrayop.d
@@ -48,28 +48,28 @@ template Floating(T)
abc = null;
A()[] = B()[] + C()[];
- assert(abc == "BCA");
+ assert(abc == "ABC");
assert(a[0] == 5);
assert(a[1] == 7);
assert(a[2] == 9);
abc = null;
A()[] = B()[] + 4;
- assert(abc == "BA");
+ assert(abc == "AB");
assert(a[0] == 5);
assert(a[1] == 6);
assert(a[2] == 7);
abc = null;
A()[] = 4 + B()[];
- assert(abc == "BA");
+ assert(abc == "AB");
assert(a[0] == 5);
assert(a[1] == 6);
assert(a[2] == 7);
abc = null;
A()[] = D() + B()[];
- assert(abc == "DBA");
+ assert(abc == "ADB");
assert(a[0] == 5);
assert(a[1] == 6);
assert(a[2] == 7);
@@ -77,7 +77,7 @@ template Floating(T)
a = [11, 22, 33];
abc = null;
A()[] += B()[];
- assert(abc == "BA");
+ assert(abc == "AB");
assert(a[0] == 12);
assert(a[1] == 24);
assert(a[2] == 36);
@@ -115,14 +115,14 @@ template Floating(T)
a = [11, 22, 33];
abc = null;
A()[] += 4 + B()[];
- assert(abc == "BA");
+ assert(abc == "AB");
assert(a[0] == 16);
assert(a[1] == 28);
assert(a[2] == 40);
abc = null;
A()[] = B()[] - C()[];
- assert(abc == "BCA");
+ assert(abc == "ABC");
printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]);
assert(a[0] == -3);
assert(a[1] == -3);
@@ -130,7 +130,7 @@ template Floating(T)
abc = null;
A()[] = -B()[] - C()[];
- assert(abc == "BCA");
+ assert(abc == "ABC");
printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]);
assert(a[0] == -5);
assert(a[1] == -7);
@@ -138,7 +138,7 @@ template Floating(T)
abc = null;
A()[] = B()[] + C()[] * 4;
- assert(abc == "BCA");
+ assert(abc == "ABC");
printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]);
assert(a[0] == 17);
assert(a[1] == 22);
@@ -146,7 +146,7 @@ template Floating(T)
abc = null;
A()[] = B()[] + C()[] * B()[];
- assert(abc == "BCBA");
+ assert(abc == "ABCB");
printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]);
assert(a[0] == 5);
assert(a[1] == 12);
@@ -154,7 +154,7 @@ template Floating(T)
abc = null;
A()[] = B()[] + C()[] / 2;
- assert(abc == "BCA");
+ assert(abc == "ABC");
printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]);
assert(a[0] == 3);
assert(a[1] == 4.5);
@@ -162,7 +162,7 @@ template Floating(T)
abc = null;
A()[] = B()[] + C()[] % 2;
- assert(abc == "BCA");
+ assert(abc == "ABC");
printf("%Lg, %Lg, %Lg\n", cast(real)a[0], cast(real)a[1], cast(real)a[2]);
assert(a[0] == 1);
assert(a[1] == 3);
@@ -226,28 +226,28 @@ template Integral(T)
abc = null;
A()[] = B()[] + C()[];
- assert(abc == "BCA");
+ assert(abc == "ABC");
assert(a[0] == 5);
assert(a[1] == 7);
assert(a[2] == 9);
abc = null;
A()[] = B()[] + 4;
- assert(abc == "BA");
+ assert(abc == "AB");
assert(a[0] == 5);
assert(a[1] == 6);
assert(a[2] == 7);
abc = null;
A()[] = 4 + B()[];
- assert(abc == "BA");
+ assert(abc == "AB");
assert(a[0] == 5);
assert(a[1] == 6);
assert(a[2] == 7);
abc = null;
A()[] = D() + B()[];
- assert(abc == "DBA");
+ assert(abc == "ADB");
assert(a[0] == 5);
assert(a[1] == 6);
assert(a[2] == 7);
@@ -255,7 +255,7 @@ template Integral(T)
a = [11, 22, 33];
abc = null;
A()[] += B()[];
- assert(abc == "BA");
+ assert(abc == "AB");
assert(a[0] == 12);
assert(a[1] == 24);
assert(a[2] == 36);
@@ -311,14 +311,14 @@ template Integral(T)
a = [11, 22, 33];
abc = null;
A()[] += 4 + B()[];
- assert(abc == "BA");
+ assert(abc == "AB");
assert(a[0] == 16);
assert(a[1] == 28);
assert(a[2] == 40);
abc = null;
A()[] = B()[] - C()[];
- assert(abc == "BCA");
+ assert(abc == "ABC");
printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]);
assert(a[0] == -3);
assert(a[1] == -3);
@@ -326,7 +326,7 @@ template Integral(T)
abc = null;
A()[] = -B()[] - C()[];
- assert(abc == "BCA");
+ assert(abc == "ABC");
printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]);
assert(a[0] == -5);
assert(a[1] == -7);
@@ -334,7 +334,7 @@ template Integral(T)
abc = null;
A()[] = B()[] + C()[] * 4;
- assert(abc == "BCA");
+ assert(abc == "ABC");
printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]);
assert(a[0] == 17);
assert(a[1] == 22);
@@ -342,7 +342,7 @@ template Integral(T)
abc = null;
A()[] = B()[] + C()[] * B()[];
- assert(abc == "BCBA");
+ assert(abc == "ABCB");
printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]);
assert(a[0] == 5);
assert(a[1] == 12);
@@ -350,7 +350,7 @@ template Integral(T)
abc = null;
A()[] = B()[] + C()[] / 2;
- assert(abc == "BCA");
+ assert(abc == "ABC");
printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]);
assert(a[0] == 3);
assert(a[1] == 4);
@@ -358,7 +358,7 @@ template Integral(T)
abc = null;
A()[] = B()[] + C()[] % 2;
- assert(abc == "BCA");
+ assert(abc == "ABC");
printf("%lld, %lld, %lld\n", cast(long)a[0], cast(long)a[1], cast(long)a[2]);
assert(a[0] == 1);
assert(a[1] == 3);
@@ -366,28 +366,28 @@ template Integral(T)
abc = null;
A()[] = ~B()[];
- assert(abc == "BA");
- assert(a[0] == ~cast(T)1);
- assert(a[1] == ~cast(T)2);
- assert(a[2] == ~cast(T)3);
+ assert(abc == "AB");
+ assert(a[0] == cast(T) ~1);
+ assert(a[1] == cast(T) ~2);
+ assert(a[2] == cast(T) ~3);
abc = null;
A()[] = B()[] & 2;
- assert(abc == "BA");
+ assert(abc == "AB");
assert(a[0] == 0);
assert(a[1] == 2);
assert(a[2] == 2);
abc = null;
A()[] = B()[] | 2;
- assert(abc == "BA");
+ assert(abc == "AB");
assert(a[0] == 3);
assert(a[1] == 2);
assert(a[2] == 3);
abc = null;
A()[] = B()[] ^ 2;
- assert(abc == "BA");
+ assert(abc == "AB");
assert(a[0] == 3);
assert(a[1] == 0);
assert(a[2] == 1);
@@ -439,7 +439,7 @@ void test4662()
}
/***************************************************/
-// 5284
+// https://issues.dlang.org/show_bug.cgi?id=5284
void bug5284_1()
{
@@ -550,7 +550,7 @@ void test8390() {
}
/************************************************************************/
-// 8651
+// https://issues.dlang.org/show_bug.cgi?id=8651
void test8651()
{
@@ -605,7 +605,7 @@ void test8651()
}
/************************************************************************/
-// 9656
+// https://issues.dlang.org/show_bug.cgi?id=9656
void test9656()
{
@@ -628,14 +628,14 @@ void test9656()
{
int[] ma = [1,2,3];
- immutable ia = ma.dup;
+ immutable ia = ma.idup;
}
{
static struct V { int val; }
V[] ma = [V(1), V(2)];
- immutable ia = ma.dup;
+ immutable ia = ma.idup;
}
{
@@ -651,7 +651,7 @@ void test9656()
}
/************************************************************************/
-// 10282
+// https://issues.dlang.org/show_bug.cgi?id=10282
void test10282()
{
@@ -669,7 +669,7 @@ void test10282()
}
/************************************************************************/
-// 10433
+// https://issues.dlang.org/show_bug.cgi?id=10433
void test10433()
{
@@ -684,7 +684,7 @@ void test10433()
}
/************************************************************************/
-// 10684
+// https://issues.dlang.org/show_bug.cgi?id=10684
void test10684a()
{
@@ -716,7 +716,7 @@ void test10684b()
}
/************************************************************************/
-// 11376
+// https://issues.dlang.org/show_bug.cgi?id=11376
template TL11376(T...)
{
@@ -732,7 +732,7 @@ auto sumArrs11376(T0, T1)(T0[] a, T1[] b)
static assert(!__traits(compiles, sumArrs11376(TL11376!(string[], string).init)));
/************************************************************************/
-// 11525
+// https://issues.dlang.org/show_bug.cgi?id=11525
void test11525()
{
@@ -756,7 +756,7 @@ void test11525()
}
/************************************************************************/
-// 12250
+// https://issues.dlang.org/show_bug.cgi?id=12250
void f12250(inout int[] p, inout int[] q, int[] r)
{
@@ -774,7 +774,7 @@ void test12250()
}
/************************************************************************/
-// 12179
+// https://issues.dlang.org/show_bug.cgi?id=12179
void test12179()
{
@@ -792,7 +792,7 @@ void test12179()
foo(a[] |= a[]);
foo(a[] ^^= a[]);
- // from issue 11992
+ // from https://issues.dlang.org/show_bug.cgi?id=11992
int[] arr1;
int[][] arr2;
arr1 ~= (a[] = [1] + a[]); // OK
@@ -800,7 +800,7 @@ void test12179()
}
/************************************************************************/
-// 12780
+// https://issues.dlang.org/show_bug.cgi?id=12780
void test12780()
{
@@ -854,7 +854,7 @@ void test12780()
}
/************************************************************************/
-// 13497
+// https://issues.dlang.org/show_bug.cgi?id=13497
void test13497()
{
@@ -866,7 +866,7 @@ void test13497()
}
/************************************************************************/
-// 14649
+// https://issues.dlang.org/show_bug.cgi?id=14649
void test14649()
{
@@ -891,7 +891,7 @@ void test14649()
}
/************************************************************************/
-// 14851
+// https://issues.dlang.org/show_bug.cgi?id=14851
void test14851()
{
diff --git a/gcc/testsuite/gdc.test/runnable/auto1.d b/gcc/testsuite/gdc.test/runnable/auto1.d
index e68b063..ea02383 100644
--- a/gcc/testsuite/gdc.test/runnable/auto1.d
+++ b/gcc/testsuite/gdc.test/runnable/auto1.d
@@ -1,3 +1,16 @@
+/*
+RUN_OUTPUT:
+---
+Foo.~this()
+Foo.~this()
+Foo.~this()
+Foo.~this()
+A2.this()
+Hello world.
+A2.~this()
+Success
+---
+*/
import core.stdc.stdio;
diff --git a/gcc/testsuite/gdc.test/runnable/b10562.d b/gcc/testsuite/gdc.test/runnable/b10562.d
new file mode 100644
index 0000000..cf79d16
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/b10562.d
@@ -0,0 +1,93 @@
+void main()
+{
+ {
+ int[3] ok = 3;
+ assert(ok == [ 3, 3, 3]);
+
+ ok = 1;
+ assert(ok == [ 1, 1, 1]);
+
+ int[][] da2;
+ assert(da2 == []);
+ }
+ {
+ int[3][2] a;
+ assert(a == [ [ 0, 0, 0 ], [ 0, 0, 0 ] ]);
+
+ int[3][2] b = 4;
+ assert(b == [ [ 4, 4, 4 ], [ 4, 4, 4 ] ]);
+
+ // b = 9;
+ // assert(b == [ [ 9, 9, 9 ], [ 9, 9, 9 ] ]);
+
+ int[3][2] c = [ 1, 2, 3 ];
+ assert(c == [ [ 1, 2, 3 ], [ 1, 2, 3 ] ]);
+
+ c = [ 5, 6, 7 ];
+ assert(c == [ [ 5, 6, 7 ], [ 5, 6, 7 ] ]);
+
+ int[3][2] d = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ];
+ assert(d == [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]);
+ }
+ {
+ int[3][2][4] a;
+ assert(a == [ [ [ 0, 0, 0 ], [ 0, 0, 0 ] ],
+ [ [ 0, 0, 0 ], [ 0, 0, 0 ] ],
+ [ [ 0, 0, 0 ], [ 0, 0, 0 ] ],
+ [ [ 0, 0, 0 ], [ 0, 0, 0 ] ] ]);
+
+ // a = 1;
+ // assert(a == [ [ [ 1, 1, 1 ], [ 1, 1, 1 ] ],
+ // [ [ 1, 1, 1 ], [ 1, 1, 1 ] ],
+ // [ [ 1, 1, 1 ], [ 1, 1, 1 ] ],
+ // [ [ 1, 1, 1 ], [ 1, 1, 1 ] ] ]);
+
+ int[3][2][4] b = [ 1, 2, 3 ];
+ assert(b == [ [ [ 1, 2, 3 ], [ 1, 2, 3 ] ],
+ [ [ 1, 2, 3 ], [ 1, 2, 3 ] ],
+ [ [ 1, 2, 3 ], [ 1, 2, 3 ] ],
+ [ [ 1, 2, 3 ], [ 1, 2, 3 ] ] ]);
+
+ // b = [ 4, 5, 6];
+ // assert(b == [ [ [ 4, 5, 6 ], [ 4, 5, 6 ] ],
+ // [ [ 4, 5, 6 ], [ 4, 5, 6 ] ],
+ // [ [ 4, 5, 6 ], [ 4, 5, 6 ] ],
+ // [ [ 4, 5, 6 ], [ 4, 5, 6 ] ] ]);
+
+ int[3][2][4] c = [ [ 1, 2, 3 ], [ 4, 5, 6 ] ];
+ assert(c == [ [ [ 1, 2, 3 ], [ 4, 5, 6 ] ],
+ [ [ 1, 2, 3 ], [ 4, 5, 6 ] ],
+ [ [ 1, 2, 3 ], [ 4, 5, 6 ] ],
+ [ [ 1, 2, 3 ], [ 4, 5, 6 ] ] ]);
+
+ c = [ [ 4, 5, 6 ], [ 7, 8, 9 ] ];
+ assert(c == [ [ [ 4, 5, 6 ], [ 7, 8, 9 ] ],
+ [ [ 4, 5, 6 ], [ 7, 8, 9 ] ],
+ [ [ 4, 5, 6 ], [ 7, 8, 9 ] ],
+ [ [ 4, 5, 6 ], [ 7, 8, 9 ] ] ]);
+ }
+ {
+ int[3] val = [4, 5, 6];
+ int[3][2][4] a = val[];
+
+ assert(a == [ [ [ 4, 5, 6 ], [ 4, 5, 6 ] ],
+ [ [ 4, 5, 6 ], [ 4, 5, 6 ] ],
+ [ [ 4, 5, 6 ], [ 4, 5, 6 ] ],
+ [ [ 4, 5, 6 ], [ 4, 5, 6 ] ] ]);
+ }
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=10562
+ int[3] value = [ 1, 2, 3 ];
+ int[3][2] a = value; // <-- COMPILATION ERROR
+ assert(a == [ [ 1, 2, 3 ], [ 1, 2, 3 ] ]);
+ }
+ {
+ // https://issues.dlang.org/show_bug.cgi?id=20465
+ int[][3][2] arr;
+ assert(arr == [[ null, null, null ], [ null, null, null ]]);
+
+ // int[] slice = [ 1 ];
+ // arr = slice;
+ // assert(arr == [[ slice, slice, slice ], [ slice, slice, slice ]]);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/b16360.d b/gcc/testsuite/gdc.test/runnable/b16360.d
new file mode 100644
index 0000000..50c28e6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/b16360.d
@@ -0,0 +1,50 @@
+// REQUIRED_ARGS: -inline
+
+pragma(inline, true)
+auto foo()
+{
+ static struct U
+ {
+ int a = 42;
+ float b;
+ }
+ U u;
+ return u.a;
+}
+
+pragma(inline, true)
+T bitCast(T, S)(auto ref S s)
+{
+ union BitCaster
+ {
+ S ss;
+ T tt;
+ }
+ BitCaster bt;
+ bt.ss = s;
+ return bt.tt;
+}
+
+pragma(inline, true)
+int withFuncCalls()
+{
+ static struct WithFuncCalls
+ {
+ int v;
+ pragma(inline, true)
+ int call(){return v;}
+ pragma(inline, true)
+ void otherCall(){v++;}
+ }
+ auto bt = WithFuncCalls(50);
+ bt.v += -9;
+ bt.otherCall();
+ return bt.call();
+}
+
+void main()
+{
+ assert(foo == 42);
+ assert(bitCast!int(1.0f) == 0x3f800000);
+ assert(withFuncCalls() == 42);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/b18034.d b/gcc/testsuite/gdc.test/runnable/b18034.d
new file mode 100644
index 0000000..3981aaf
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/b18034.d
@@ -0,0 +1,28 @@
+// REQUIRED_ARGS: -O
+import core.simd;
+
+static if (__traits(compiles, { void16 a; ushort8 b; }))
+{
+ void check(void16 a)
+ {
+ foreach (x; (cast(ushort8)a).array)
+ {
+ assert(x == 1);
+ }
+ }
+
+ void make(ushort x)
+ {
+ ushort8 v = ushort8(x);
+ check(v);
+ }
+
+ void main()
+ {
+ make(1);
+ }
+}
+else
+{
+ void main() { }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/b19584.d b/gcc/testsuite/gdc.test/runnable/b19584.d
new file mode 100644
index 0000000..8eb790e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/b19584.d
@@ -0,0 +1,13 @@
+/*
+REQUIRED_ARGS: -O
+*/
+void main()
+{
+ int a = 711;
+ assert(182215 == (a | (a << 8)));
+ assert(182727 == (a * (1 + (1 << 8))));
+
+ int b = 31;
+ assert(511 == (b | (b << 4)));
+ assert(527 == (b * (1 + (1 << 4))));
+}
diff --git a/gcc/testsuite/gdc.test/runnable/b20470.d b/gcc/testsuite/gdc.test/runnable/b20470.d
new file mode 100644
index 0000000..73d8d10
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/b20470.d
@@ -0,0 +1,97 @@
+// https://issues.dlang.org/show_bug.cgi?id=20470
+
+alias AliasSeq(Args...) = Args;
+
+int g, h;
+
+void test0()
+{
+ static struct S
+ {
+ int a, b;
+ float c = 0, d = 0;
+ alias fields = AliasSeq!(a, b, c, d);
+ alias ints = AliasSeq!(a, b);
+ alias floats = AliasSeq!(c, d);
+ alias reversed = AliasSeq!(d, c, b, a);
+ alias globals = AliasSeq!(g, h);
+
+ alias properties = AliasSeq!(e, f);
+ @property int e() { return a; }
+ @property void e(int i) { a = i; }
+ @property float f() { return c; }
+ @property void f(float j) { c = j; }
+ }
+
+ S s;
+ assert(s.fields == AliasSeq!(0, 0, 0, 0));
+ s.ints = AliasSeq!(1, 2);
+ assert(s.fields == AliasSeq!(1, 2, 0, 0));
+ s.floats = AliasSeq!(3, 4);
+ assert(s.fields == AliasSeq!(1, 2, 3, 4));
+
+ int a, b;
+ float c, d;
+ AliasSeq!(d, c, b, a) = s.reversed;
+ assert(AliasSeq!(a, b, c, d) == AliasSeq!(1, 2, 3, 4));
+
+ s.globals = AliasSeq!(30, 40);
+ assert(g == 30 && h == 40);
+
+ // Propagating `this` to functions and properties within tuples will be a breaking change.
+ // See `test2()` below for an example of existing code that would need to be fixed.
+
+ //s.properties = AliasSeq!(11, 12);
+ //assert(s.e == 11 && s.f == 12);
+}
+
+class Nested(Vars...)
+{
+ int a, b;
+ alias outervars = Vars;
+ alias fields = AliasSeq!(a, b);
+ alias all = AliasSeq!(a, b, Vars);
+}
+
+auto makeNested()
+{
+ static class C
+ {
+ bool b;
+ double d;
+ auto nested() { return new Nested!(b, d)(); }
+ }
+ return new C().nested();
+}
+
+void test1()
+{
+ auto n = makeNested();
+ n.fields = AliasSeq!(1, 2);
+ n.outervars = AliasSeq!(true, 1.3);
+ assert(n.all == AliasSeq!(1, 2, true, 1.3));
+}
+
+void test2()
+{
+ // backwards compatibility test for functions within tuples
+
+ static struct S
+ {
+ void f();
+ void g();
+ alias funcs = AliasSeq!(f, g);
+ }
+
+ S s;
+ alias voidTf = void();
+ foreach (f; s.funcs)
+ static assert(is(typeof(f) == voidTf));
+}
+
+void main()
+{
+ test0();
+ test1();
+ test2();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/b20890.d b/gcc/testsuite/gdc.test/runnable/b20890.d
new file mode 100644
index 0000000..9b208da
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/b20890.d
@@ -0,0 +1,48 @@
+module b20890;
+// https://issues.dlang.org/show_bug.cgi?id=20890
+
+struct S0 { }
+void format0(string spec, S0[1] s)
+{
+ assert (spec == "lengthy");
+}
+struct S1 { ubyte m = 42; }
+void format1(string spec, S1[1] s)
+{
+ assert (spec == "lengthy");
+ assert (s[0].m == 42);
+}
+struct S2 { ushort m = 42; }
+void format2(string spec, S2[1] s)
+{
+ assert (spec == "lengthy");
+ assert (s[0].m == 42);
+}
+struct S4 { uint m = 42; }
+void format4(string spec, S4[1] s)
+{
+ assert (spec == "lengthy");
+ assert (s[0].m == 42);
+}
+struct S8 { ulong m = 42; }
+void format8(string spec, S8[1] s)
+{
+ assert (spec == "lengthy");
+ assert (s[0].m == 42);
+}
+struct S42 { ubyte[42] m = [42]; }
+void format42(string spec, S42[1] s)
+{
+ assert (spec == "lengthy");
+ assert (s[0].m[0] == 42);
+}
+
+void main()
+{
+ { S0[1] s; format0("lengthy", s); }
+ { S1[1] s; format1("lengthy", s); }
+ { S2[1] s; format2("lengthy", s); }
+ { S4[1] s; format4("lengthy", s); }
+ { S8[1] s; format8("lengthy", s); }
+ {S42[1] s;format42("lengthy", s); }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/b26.d b/gcc/testsuite/gdc.test/runnable/b26.d
index e32533b..54e28da 100644
--- a/gcc/testsuite/gdc.test/runnable/b26.d
+++ b/gcc/testsuite/gdc.test/runnable/b26.d
@@ -2,7 +2,7 @@
// EXTRA_SOURCES: imports/b26a.d
// PERMUTE_ARGS:
-// 382
+// https://issues.dlang.org/show_bug.cgi?id=382
struct List(T) {
interface A {}
diff --git a/gcc/testsuite/gdc.test/runnable/b6400.d b/gcc/testsuite/gdc.test/runnable/b6400.d
new file mode 100644
index 0000000..8b10184
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/b6400.d
@@ -0,0 +1,69 @@
+/* TEST_OUTPUT:
+---
+Foo
+Bar
+Foo
+Bar
+Bar
+Foo
+Bar
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=6400
+
+enum int base(string name) = 10 * (name[$-1] - '0');
+struct Foo { int opDispatch(string name)() { pragma(msg, "Foo"); return base!name + 1; } }
+struct Bar { int opDispatch(string name)() { pragma(msg, "Bar"); return base!name + 2; } }
+struct Baz { }
+
+void main()
+{
+ assert(test());
+ static assert(test());
+}
+
+bool test()
+{
+ auto foo = new Foo;
+ auto bar = new Bar;
+ auto baz = new Baz;
+
+ with (foo)
+ {
+ assert(f1() == 11);
+ with (baz) assert(f1() == 11);
+ with (bar)
+ {
+ assert(f2() == 22);
+ with (baz) assert(f2() == 22);
+ with (foo)
+ {
+ assert(f3() == 31);
+ with (baz) assert(f3() == 31);
+ with (bar)
+ {
+ assert(f4() == 42);
+ with (baz) assert(f4() == 42);
+ with (baz)
+ {
+ assert(f5() == 52);
+ with (baz) assert(f5() == 52);
+ }
+ with (foo)
+ {
+ assert(f6() == 61);
+ with (baz) assert(f6() == 61);
+ }
+ with (bar)
+ {
+ assert(f7() == 72);
+ with (baz) assert(f7() == 72);
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/bench1.d b/gcc/testsuite/gdc.test/runnable/bench1.d
index 74b24a4..d19ba9a 100644
--- a/gcc/testsuite/gdc.test/runnable/bench1.d
+++ b/gcc/testsuite/gdc.test/runnable/bench1.d
@@ -1,5 +1,12 @@
-// REQUIRED_ARGS:
-// EXECUTE_ARGS: 10000
+/*
+REQUIRED_ARGS:
+EXECUTE_ARGS: 10000
+RUN_OUTPUT:
+---
+count = 10000
+70000
+---
+*/
extern(C) int printf(const char *, ...);
extern(C) int atoi(const char *);
@@ -18,7 +25,7 @@ extern(C) int atoi(const char *);
s ~= "hello\n";
for (loop = 0; loop < count; loop ++)
s ~= "h";
- printf ("%d\n", s.length);
+ printf ("%llu\n", cast(ulong) s.length);
//printf("%.*s\n", s[0..100]);
assert(s.length == count * (6 + 1));
s.length = 3;
@@ -27,4 +34,3 @@ extern(C) int atoi(const char *);
s.length = 1000;
return 0;
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/betterc.d b/gcc/testsuite/gdc.test/runnable/betterc.d
new file mode 100644
index 0000000..0da798b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/betterc.d
@@ -0,0 +1,202 @@
+/* REQUIRED_ARGS: -betterC
+ PERMUTE_ARGS:
+ */
+
+
+void test(int ij)
+{
+ assert(ij);
+#line 100 "anotherfile"
+ assert(ij,"it is not zero");
+}
+
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18010
+
+void test1()
+{
+ int[10] a1 = void;
+ int[10] a2 = void;
+ a1[] = a2[];
+}
+
+void test2(int[] a1, int[] a2)
+{
+ a1[] = a2[];
+}
+
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=17843
+
+struct S
+{
+ double d = 0.0;
+ int[] x;
+}
+
+/*******************************************/
+
+extern (C) void main()
+{
+ test(1);
+ test18472();
+ testRuntimeLowerings();
+ test18457();
+}
+
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=17605
+
+extern (C) void test17605()
+{
+ int a;
+ enum bool works = __traits(compiles, { a = 1; });
+ a = 1;
+}
+
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18472
+
+void test18472()
+{
+ version(D_LP64)
+ {
+ enum b = typeid(size_t) is typeid(ulong);
+ }
+ else
+ {
+ enum b = typeid(size_t) is typeid(uint);
+ }
+
+ assert(b);
+}
+
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18493
+
+struct S18493
+{
+ this(this) nothrow { } // Since this is attributed with `nothrow` there should be no error about using
+ // try-catch with -betterC
+ ~this() { }
+}
+
+struct S18493_2
+{
+ S18493 s1;
+ S18493 s2;
+}
+
+/******************************************************
+ * tests to ensure there is sufficient runtime support
+ * in imported object.d
+ */
+mixin template initArray()
+{
+ static if (is(T == bool))
+ {
+ T[6] a1 = [true, false, true, true, false, true];
+ }
+ else static if (is(T == Sint))
+ {
+ T[6] a1 = [Sint(1), Sint(2), Sint(3), Sint(1), Sint(2), Sint(3)];
+ }
+ else
+ {
+ T[6] a1 = [1,2,3,1,2,3];
+ }
+}
+
+struct Sint
+{
+ int x;
+ this(int v) { x = v;}
+}
+
+void testRuntimeLowerings()
+{
+ // test call to `object.__equals`
+ void test__equals(T)()
+ {
+ mixin initArray;
+
+ assert(a1[0..3] == a1[3..$]);
+ }
+
+ test__equals!int;
+ test__equals!uint;
+ test__equals!long;
+ test__equals!ulong;
+ test__equals!short;
+ test__equals!ushort;
+ test__equals!byte;
+ test__equals!dchar;
+ test__equals!wchar;
+ test__equals!ubyte;
+ test__equals!char;
+ test__equals!(const char);
+ test__equals!bool;
+ test__equals!Sint;
+
+ // test call to `object.__cmp`
+ void test__cmp(T)()
+ {
+ mixin initArray;
+
+ assert(a1[0..3] >= a1[3..$]);
+ assert(a1[0..3] <= a1[3..$]);
+ }
+
+ test__cmp!int;
+ test__cmp!uint;
+ test__cmp!long;
+ test__cmp!ulong;
+ test__cmp!short;
+ test__cmp!ushort;
+ test__cmp!byte;
+ test__cmp!dchar;
+ test__cmp!wchar;
+ test__cmp!ubyte;
+ test__cmp!char;
+ test__cmp!(const char);
+ test__cmp!bool;
+ test__cmp!Sint;
+
+ // test call to `object.__switch``
+ auto s = "abc";
+ switch(s)
+ {
+ case "abc":
+ break;
+ default:
+ break;
+ }
+}
+
+/**********************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18457
+
+__gshared int dtor;
+
+struct S18457
+{
+ int a = 3;
+ ~this() { a = 0; ++dtor; }
+}
+
+S18457 myFunction()
+{
+ S18457 s = S18457();
+ return s;
+}
+
+void test18457()
+{
+ {
+ S18457 s = myFunction();
+ assert(s.a == 3);
+ assert(dtor == 0);
+ }
+ assert(dtor == 1);
+}
+
diff --git a/gcc/testsuite/gdc.test/runnable/bettercUnittest.d b/gcc/testsuite/gdc.test/runnable/bettercUnittest.d
new file mode 100644
index 0000000..ace2c14
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/bettercUnittest.d
@@ -0,0 +1,38 @@
+/*
+REQUIRED_ARGS: -betterC -unittest
+PERMUTE_ARGS:
+EXTRA_SOURCES: extra-files/moreBettercUnittests.d
+*/
+
+import moreBettercUnittests;
+
+unittest
+{
+ sum |= 0x1;
+}
+
+unittest
+{
+ sum |= 0x10;
+}
+
+extern (C) int main()
+{
+ uint count;
+
+ static foreach (alias unit; __traits(getUnitTests, bettercUnittest))
+ {
+ unit();
+ count++;
+ }
+
+ static foreach (alias unit; __traits(getUnitTests, moreBettercUnittests))
+ {
+ unit();
+ count++;
+ }
+
+ assert(count == 4);
+ assert(sum == 0x1111);
+ return sum == 0x1111 ? 0 : 1;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/bitops.d b/gcc/testsuite/gdc.test/runnable/bitops.d
index eb51f0f..28a18c4 100644
--- a/gcc/testsuite/gdc.test/runnable/bitops.d
+++ b/gcc/testsuite/gdc.test/runnable/bitops.d
@@ -7,7 +7,7 @@ import core.bitop;
void test1()
{
- size_t array[2];
+ size_t[2] array;
uint x;
version (D_LP64)
size_t bitToUse = 67;
@@ -16,35 +16,35 @@ else
array[0] = 2;
array[1] = 0x100;
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+ printf("array = [0]:x%zx, [1]:x%zx\n", array[0], array[1]);
x = btc(array.ptr, bitToUse);
- printf("btc(array, %d) = %d\n", bitToUse, x);
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+ printf("btc(array, %zd) = %d\n", bitToUse, x);
+ printf("array = [0]:x%zx, [1]:x%zx\n", array[0], array[1]);
assert(x == 0);
assert(array[0] == 0x2 && array[1] == 0x108);
x = btc(array.ptr, bitToUse);
- printf("btc(array, %d) = %d\n", bitToUse, x);
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+ printf("btc(array, %zd) = %d\n", bitToUse, x);
+ printf("array = [0]:x%zx, [1]:x%zx\n", array[0], array[1]);
assert(x != 0);
assert(array[0] == 2 && array[1] == 0x100);
x = bts(array.ptr, bitToUse);
- printf("bts(array, %d) = %d\n", bitToUse, x);
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+ printf("bts(array, %zd) = %d\n", bitToUse, x);
+ printf("array = [0]:x%zx, [1]:x%zx\n", array[0], array[1]);
assert(x == 0);
assert(array[0] == 2 && array[1] == 0x108);
x = btr(array.ptr, bitToUse);
- printf("btr(array, %d) = %d\n", bitToUse, x);
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+ printf("btr(array, %zd) = %d\n", bitToUse, x);
+ printf("array = [0]:x%zx, [1]:x%zx\n", array[0], array[1]);
assert(x != 0);
assert(array[0] == 2 && array[1] == 0x100);
x = bt(array.ptr, 1);
printf("bt(array, 1) = %d\n", x);
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+ printf("array = [0]:x%zx, [1]:x%zx\n", array[0], array[1]);
assert(x != 0);
assert(array[0] == 2 && array[1] == 0x100);
}
@@ -69,17 +69,19 @@ void test2()
/*****************************************************/
version (DigitalMars)
-void test3()
-{ uint v;
- int b;
-
- b = inp(b);
- b = inpw(b);
- b = inpl(b);
-
- b = outp(v, cast(ubyte)b);
- b = outpw(v, cast(ushort)b);
- b = outpl(v, b);
+{
+ void test3()
+ { uint v;
+ int b;
+
+ b = inp(b);
+ b = inpw(b);
+ b = inpl(b);
+
+ b = outp(v, cast(ubyte)b);
+ b = outpw(v, cast(ushort)b);
+ b = outpl(v, b);
+ }
}
/*****************************************************/
@@ -95,25 +97,25 @@ void test4()
void test5()
{
- size_t array[2];
+ size_t[2] array;
array[0] = 2;
array[1] = 0x100;
printf("btc(array, 35) = %d\n", btc(array.ptr, 35));
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+ printf("array = [0]:x%zx, [1]:x%zx\n", array[0], array[1]);
printf("btc(array, 35) = %d\n", btc(array.ptr, 35));
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+ printf("array = [0]:x%zx, [1]:x%zx\n", array[0], array[1]);
printf("bts(array, 35) = %d\n", bts(array.ptr, 35));
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+ printf("array = [0]:x%zx, [1]:x%zx\n", array[0], array[1]);
printf("btr(array, 35) = %d\n", btr(array.ptr, 35));
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+ printf("array = [0]:x%zx, [1]:x%zx\n", array[0], array[1]);
printf("bt(array, 1) = %d\n", bt(array.ptr, 1));
- printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
+ printf("array = [0]:x%zx, [1]:x%zx\n", array[0], array[1]);
}
diff --git a/gcc/testsuite/gdc.test/runnable/bug11155.d b/gcc/testsuite/gdc.test/runnable/bug11155.d
index afe4208..b346ce2 100644
--- a/gcc/testsuite/gdc.test/runnable/bug11155.d
+++ b/gcc/testsuite/gdc.test/runnable/bug11155.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
-version(D_SIMD)
+static if (__traits(compiles, __vector(float[4])))
{
alias float4 = __vector(float[4]);
diff --git a/gcc/testsuite/gdc.test/runnable/bug19652.d b/gcc/testsuite/gdc.test/runnable/bug19652.d
new file mode 100644
index 0000000..e922b59
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/bug19652.d
@@ -0,0 +1,22 @@
+
+struct Base {
+ int i;
+}
+
+struct A {
+ Base base;
+ alias base this;
+}
+
+struct B {
+ A a;
+ alias a this;
+}
+
+auto otherTest(inout ref Base block) @nogc { assert(0); }
+auto otherTest(inout ref A block) @nogc {}
+
+void main() {
+ B* thingie;
+ otherTest(*thingie);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/bug7068.d b/gcc/testsuite/gdc.test/runnable/bug7068.d
index 70e351e..75ea5bf 100644
--- a/gcc/testsuite/gdc.test/runnable/bug7068.d
+++ b/gcc/testsuite/gdc.test/runnable/bug7068.d
@@ -1,4 +1,5 @@
-// PERMUTE_ARGS: -inline -g -O -d
+// REQUIRED_ARGS: -d
+// PERMUTE_ARGS: -inline -g -O
void main()
{
auto darray1 = new int*[](10);
diff --git a/gcc/testsuite/gdc.test/runnable/builtin.d b/gcc/testsuite/gdc.test/runnable/builtin.d
index 44817b1..a7f09a3 100644
--- a/gcc/testsuite/gdc.test/runnable/builtin.d
+++ b/gcc/testsuite/gdc.test/runnable/builtin.d
@@ -1,7 +1,5 @@
// RUNNABLE_PHOBOS_TEST
-
-import std.stdio;
-import std.math;
+import core.math;
import core.bitop;
version (DigitalMars)
@@ -12,30 +10,31 @@ version (DigitalMars)
version = AnyX86;
}
+bool isClose(real lhs, real rhs, real maxRelDiff = 1e-09L, real maxAbsDiff = 0.0)
+{
+ if (lhs == rhs)
+ return true;
+ if (lhs == lhs.infinity || rhs == rhs.infinity ||
+ lhs == -lhs.infinity || rhs == -rhs.infinity)
+ return false;
+
+ auto diff = fabs(lhs - rhs);
+ return diff <= maxRelDiff*fabs(lhs)
+ || diff <= maxRelDiff*fabs(rhs)
+ || diff <= maxAbsDiff;
+}
+
/*******************************************/
void test1()
{
- writefln("%a", sin(6.8L));
auto f = 6.8L;
- writefln("%a", sin(f));
assert(sin(f) == sin(6.8L));
- static assert(approxEqual(sin(6.8L), 0x1.f9f8d9aea10fdf1cp-2));
+ static assert(isClose(sin(6.8L), 0x1.f9f8d9aea10fdf1cp-2));
- writefln("%a", cos(6.8L));
f = 6.8L;
- writefln("%a", cos(f));
assert(cos(f) == cos(6.8L));
- static assert(approxEqual(cos(6.8L), 0x1.bd21aaf88dcfa13ap-1));
-
- writefln("%a", tan(6.8L));
- f = 6.8L;
- writefln("%a", tan(f));
- version (Win64)
- { }
- else
- assert(tan(f) == tan(6.8L));
- static assert(approxEqual(tan(6.8L), 0x1.22fd752af75cd08cp-1));
+ static assert(isClose(cos(6.8L), 0x1.bd21aaf88dcfa13ap-1));
}
/*******************************************/
@@ -55,7 +54,7 @@ void test2()
assert(i == 2);
}
-/**** Bug 5703 *****************************/
+/**** https://issues.dlang.org/show_bug.cgi?id=5703 ****/
static assert({
int a = 0x80;
@@ -113,7 +112,5 @@ int main()
test1();
test2();
test3();
-
- printf("Success\n");
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/cassert.d b/gcc/testsuite/gdc.test/runnable/cassert.d
deleted file mode 100644
index 8c76750..0000000
--- a/gcc/testsuite/gdc.test/runnable/cassert.d
+++ /dev/null
@@ -1,17 +0,0 @@
-/* REQUIRED_ARGS: -betterC
- PERMUTE_ARGS:
- */
-
-
-void test(int ij)
-{
- assert(ij);
-#line 100 "anotherfile"
- assert(ij,"it is not zero");
-}
-
-extern (C) int main()
-{
- test(1);
- return 0;
-}
diff --git a/gcc/testsuite/gdc.test/runnable/casting.d b/gcc/testsuite/gdc.test/runnable/casting.d
index 233cc94..1eb262c 100644
--- a/gcc/testsuite/gdc.test/runnable/casting.d
+++ b/gcc/testsuite/gdc.test/runnable/casting.d
@@ -1,9 +1,15 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
extern(C) int printf(const char*, ...);
template Seq(T...) { alias T Seq; }
/***************************************************/
-// 3133
+// https://issues.dlang.org/show_bug.cgi?id=3133
void test3133()
{
@@ -12,7 +18,7 @@ void test3133()
}
/***************************************************/
-// 7504
+// https://issues.dlang.org/show_bug.cgi?id=7504
void test7504() pure nothrow @safe
{
@@ -56,7 +62,7 @@ C7504 create7504(T...)(T input)
}
/***************************************************/
-// 8119
+// https://issues.dlang.org/show_bug.cgi?id=8119
struct S8119;
@@ -73,7 +79,7 @@ void test8119()
}
/***************************************************/
-// 8645
+// https://issues.dlang.org/show_bug.cgi?id=8645
template TypeTuple8645(TL...)
{
@@ -88,7 +94,7 @@ void test8645()
}
/***************************************************/
-// 10497
+// https://issues.dlang.org/show_bug.cgi?id=10497
struct S10497;
@@ -99,7 +105,7 @@ void test10497(S10497** s)
}
/***************************************************/
-// 10793
+// https://issues.dlang.org/show_bug.cgi?id=10793
struct RealFoo10793
{
@@ -116,7 +122,7 @@ void test10793()
}
/***************************************************/
-// 10834
+// https://issues.dlang.org/show_bug.cgi?id=10834
void test10834()
{
@@ -137,7 +143,7 @@ void test10834()
}
/***************************************************/
-// 10842
+// https://issues.dlang.org/show_bug.cgi?id=10842
template Test10842(F, T)
{
@@ -162,30 +168,12 @@ template Test10842(F, T)
void test10842()
{
- foreach (From; Seq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real))
- {
- foreach (To; Seq!(ifloat, idouble, ireal))
- {
- if (!Test10842!(From, To).test())
- assert(0);
- }
- }
-
- foreach (From; Seq!(ifloat, idouble, ireal))
- {
- foreach (To; Seq!(/*bool*, */byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real))
- {
- if (!Test10842!(From, To).test())
- assert(0);
- }
- }
-
if (!Test10842!(typeof(null), string).test()) // 10842
assert(0);
}
/***************************************************/
-// 11722
+// https://issues.dlang.org/show_bug.cgi?id=11722
class C11722
{
@@ -199,7 +187,7 @@ void test11722()
}
/***************************************************/
-// 14218
+// https://issues.dlang.org/show_bug.cgi?id=14218
void test14218()
{
@@ -214,18 +202,11 @@ void test14218()
version (DigitalMars)
{
// Questionable but currently accepted by DMD (but not GDC).
- foreach (To; Seq!( float, double, real,
- ifloat, idouble, ireal))
+ foreach (To; Seq!( float, double, real))
{
auto x = cast(To)null;
assert(x == 0); // 0i
}
-
- // Internal error: backend/el.c in el_long()
- //foreach (To; Seq!(cfloat, cdouble, creal))
- //{
- // static assert(!__traits(compiles, { auto x = cast(To)null; }));
- //}
}
}
diff --git a/gcc/testsuite/gdc.test/runnable/circular.d b/gcc/testsuite/gdc.test/runnable/circular.d
deleted file mode 100644
index 8fdc8aa..0000000
--- a/gcc/testsuite/gdc.test/runnable/circular.d
+++ /dev/null
@@ -1,25 +0,0 @@
-// REQUIRED_ARGS: -d
-// PERMUTE_ARGS: -dw
-// EXTRA_SOURCES: imports/circularA.d
-// This bug is typedef-specific.
-
-// Bugzilla 4543
-
-import core.stdc.stdio;
-import imports.circularA;
-
-class bclass {};
-alias bclass Tclass;
-
-struct bstruct {}
-alias bstruct Tstruct;
-
-
-/************************************/
-
-int main()
-{
- printf("Success\n");
- return 0;
-}
-
diff --git a/gcc/testsuite/gdc.test/runnable/closure.d b/gcc/testsuite/gdc.test/runnable/closure.d
index 1ed10e2..af304c1 100644
--- a/gcc/testsuite/gdc.test/runnable/closure.d
+++ b/gcc/testsuite/gdc.test/runnable/closure.d
@@ -689,7 +689,7 @@ void test22()
}
/************************************/
-// 1759
+// https://issues.dlang.org/show_bug.cgi?id=1759
void test1759()
{
@@ -724,7 +724,7 @@ void test1759()
}
/************************************/
-// 1841
+// https://issues.dlang.org/show_bug.cgi?id=1841
int delegate() foo1841()
{
@@ -768,7 +768,7 @@ void test1841()
}
/************************************/
-// 5911
+// https://issues.dlang.org/show_bug.cgi?id=5911
void writeln5911(const(char)[] str) {}
@@ -791,7 +791,7 @@ void test5911()
}
/************************************/
-// 9685
+// https://issues.dlang.org/show_bug.cgi?id=9685
auto get9685a(alias fun)()
{
@@ -844,7 +844,7 @@ void test9685b()
}
/************************************/
-// 12406
+// https://issues.dlang.org/show_bug.cgi?id=12406
auto createDg12406()
{
@@ -898,7 +898,7 @@ void test12406()
}
/************************************/
-// 14730
+// https://issues.dlang.org/show_bug.cgi?id=14730
void test14730()
{
diff --git a/gcc/testsuite/gdc.test/runnable/complex.d b/gcc/testsuite/gdc.test/runnable/complex.d
index 78fe574..50e793e 100644
--- a/gcc/testsuite/gdc.test/runnable/complex.d
+++ b/gcc/testsuite/gdc.test/runnable/complex.d
@@ -1,27 +1,43 @@
-// RUNNABLE_PHOBOS_TEST
-// PERMUTE_ARGS:
-
-import std.stdio;
-import std.math;
+/*
+REQUIRED_ARGS: -d
+TEST_OUTPUT:
+---
+---
+*/
+
+import core.stdc.math : isnan, signbit;
import core.stdc.stdio;
-/***************************************/
+template AliasSeq(T...) { alias T AliasSeq; }
-void test1()
-{
- creal c = 3.0 + 4.0i;
- c = sqrt(c);
- printf("re = %Lg, im = %Lg\n", c.re, c.im);
- assert(c.re == 2.0);
- assert(c.im == 1.0);
+/************************************/
- float f = sqrt(25.0f);
- assert(f == 5.0);
- double d = sqrt(4.0);
- assert(d == 2.0);
- real r = sqrt(9.0L);
- assert(r == 3.0);
-}
+static assert(-(6i) == -6i);
+static assert(-(1 + 6i) == -1 - 6i);
+
+static assert(!3.7i == 0);
+static assert(!0.0i == 1);
+static assert(!(2+3.7i) == 0);
+static assert(!(0+3.7i) == 0);
+static assert(!(2+0.0i) == 0);
+static assert(!(0+0.0i) == 1);
+
+static assert(-6i + 2i == -4i);
+static assert(6i - 1i == 5i);
+
+static assert((3.6 + 7.2i) / (1 + 0i) == 3.6 + 7.2i);
+static assert((3.6 + 7.2i) / (0.0 + 1i) == 7.2 - 3.6i);
+
+static assert((7.2i < 6.2i) == 0);
+
+static assert((7.2i == 6.2i) == 0);
+static assert((7.2i != 6.2i) == 1);
+
+static assert((7.2i == 7.2i) == 1);
+static assert((7.2i != 7.2i) == 0);
+
+static assert((5.1 is 5.1i) == 0);
+static assert((5.1 !is 5.1i) == 1);
/***************************************/
@@ -227,11 +243,11 @@ void test12()
{
real x = 3;
creal a = (2 + 4i) % 3;
- writeln(a);
+ printf("%Lg %Lgi\n", a.re, a.im);
assert(a == 2 + 1i);
creal b = (2 + 4i) % x;
- writeln(b);
+ printf("%Lg %Lgi\n", b.re, b.im);
assert(b == a);
}
@@ -241,7 +257,7 @@ void test13()
{
ireal a = 5i;
ireal b = a % 2;
- writeln(b);
+ printf("%Lg %Lgi\n", b.re, b.im);
assert(b == 1i);
}
@@ -405,6 +421,974 @@ void test15()
assert(bar15r(1.0L, 2.0Li) == 1.0L + 2.0Li);
}
+/************************************/
+
+void test16()
+{
+ real n = -0.0;
+ const real m = -0.0;
+
+ creal c = -0.0 + 3i;
+ creal d = n + 3i;
+ creal e = m + 3i;
+
+ assert(signbit(c.re) != 0);
+ assert(signbit(d.re) != 0);
+ assert(signbit(e.re) != 0);
+}
+
+/************************************/
+
+void test17()
+{
+ void test(cdouble v)
+ {
+ auto x2 = cdouble(v);
+ assert(x2 == v);
+ }
+ test(1.2+3.4i);
+}
+
+/************************************/
+
+template factorial18(float n, cdouble c, string sss, string ttt)
+{
+ static if (n == 1)
+ const float factorial18 = 1;
+ else
+ const float factorial18 = n * 2;
+}
+
+template bar18(wstring abc, dstring def)
+{
+ const int x = 3;
+}
+
+void test18()
+{
+ float f = factorial18!(4.25, 6.8+3i, "hello", null);
+ printf("%g\n", f);
+ assert(f == 8.5);
+ int i = bar18!("abc"w, "def"d).x;
+ printf("%d\n", i);
+ assert(i == 3);
+}
+
+/*****************************************/
+
+void test19()
+{
+ float f;
+ double d;
+ real r;
+
+ if (f > ifloat.max)
+ goto Loverflow;
+ if (d > ifloat.max)
+ goto Loverflow;
+ if (r > ifloat.max)
+ goto Loverflow;
+
+ if (ifloat.max < f)
+ goto Loverflow;
+ if (ifloat.max < d)
+ goto Loverflow;
+ if (ifloat.max < r)
+ goto Loverflow;
+
+ return;
+
+ Loverflow:
+ return;
+}
+
+/*****************************************/
+
+void test20()
+{
+ double d = 1;
+ cdouble cd = 1+0i;
+ assert(cd == 1.0 + 0i);
+}
+
+/*****************************************/
+
+void test21()
+{
+ cdouble[] a;
+ cdouble[] b;
+ foreach(ref cdouble d; b)
+ {
+ d = -a[0];
+ for(;;){}
+ }
+}
+
+/*************************************/
+
+void test22()
+{
+ static creal[] params = [1+0i, 3+0i, 5+0i];
+
+ printf("params[0] = %Lf + %Lfi\n", params[0].re, params[0].im);
+ printf("params[1] = %Lf + %Lfi\n", params[1].re, params[1].im);
+ printf("params[2] = %Lf + %Lfi\n", params[2].re, params[2].im);
+
+ creal[] sums = new creal[3];
+ sums[] = 0+0i;
+
+ foreach(creal d; params)
+ {
+ creal prod = d;
+
+ printf("prod = %Lf + %Lfi\n", prod.re, prod.im);
+ for(int i; i<2; i++)
+ {
+ sums[i] += prod;
+ prod *= d;
+ }
+ sums[2] += prod;
+ }
+
+ printf("sums[0] = %Lf + %Lfi", sums[0].re, sums[0].im);
+ assert(sums[0].re==9);
+ assert(sums[0].im==0);
+ assert(sums[1].re==35);
+ assert(sums[1].im==0);
+ assert(sums[2].re==153);
+ assert(sums[2].im==0);
+}
+
+/*******************************************/
+
+cdouble y23;
+
+cdouble f23(cdouble x)
+{
+ return (y23 = x);
+}
+
+void test23()
+{
+ f23(1.0+2.0i);
+ assert(y23 == 1.0+2.0i);
+}
+
+/*************************************/
+
+ifloat func_24_1(ifloat f, double d)
+{
+// f /= cast(cdouble)d;
+ return f;
+}
+
+ifloat func_24_2(ifloat f, double d)
+{
+ f = cast(ifloat)(f / cast(cdouble)d);
+ return f;
+}
+
+float func_24_3(float f, double d)
+{
+// f /= cast(cdouble)d;
+ return f;
+}
+
+float func_24_4(float f, double d)
+{
+ f = cast(float)(f / cast(cdouble)d);
+ return f;
+}
+
+void test24()
+{
+ ifloat f = func_24_1(10i, 8);
+ printf("%fi\n", f);
+// assert(f == 1.25i);
+
+ f = func_24_2(10i, 8);
+ printf("%fi\n", f);
+ assert(f == 1.25i);
+
+ float g = func_24_3(10, 8);
+ printf("%f\n", g);
+// assert(g == 1.25);
+
+ g = func_24_4(10, 8);
+ printf("%f\n", g);
+ assert(g == 1.25);
+}
+
+/*******************************************/
+
+void test25()
+{
+ ireal x = 4.0Li;
+ ireal y = 4.0Li;
+ ireal z = 4Li;
+ creal c = 4L + 0Li;
+}
+
+/*************************************/
+
+string toString26(cdouble z)
+{
+ char[ulong.sizeof*8] buf;
+
+ auto len = snprintf(buf.ptr, buf.sizeof, "%f+%fi", z.re, z.im);
+ return buf[0 .. len].idup;
+}
+
+void test26()
+{
+ static cdouble[] A = [1+0i, 0+1i, 1+1i];
+ string s;
+
+ foreach( cdouble z; A )
+ {
+ s = toString26(z);
+ printf("%.*s ", cast(int)s.length, s.ptr);
+ }
+ printf("\n");
+
+ for(int ii=0; ii<A.length; ii++ )
+ A[ii] += -1i*A[ii];
+
+ assert(A[0] == 1 - 1i);
+ assert(A[1] == 1 + 1i);
+ assert(A[2] == 2);
+
+ foreach( cdouble z; A )
+ {
+ s = toString26(z);
+ printf("%.*s ", cast(int)s.length, s.ptr);
+ }
+ printf("\n");
+}
+
+/*************************************/
+
+void test27()
+{
+ creal z = 1. + 2.0i;
+
+ real r = z.re;
+ assert(r == 1.0);
+
+ real i = z.im;
+ assert(i == 2.0);
+
+ assert(r.im == 0.0);
+ assert(r.re == 1.0);
+
+ assert(i.re == 2.0);
+ assert(i.im == 0.0i);
+}
+
+/*************************************/
+
+void test28()
+{
+ alias cdouble X;
+ X four = cast(X) (4.0i + 0.4);
+}
+
+/*************************************/
+
+void test29()
+{
+ ireal a = 6.5i % 3i;
+ printf("%Lfi %Lfi\n", a, a - .5i);
+ assert(a == .5i);
+
+ a = 6.5i % 3;
+ printf("%Lfi %Lfi\n", a, a - .5i);
+ assert(a == .5i);
+
+ real b = 6.5 % 3i;
+ printf("%Lf %Lf\n", b, b - .5);
+ assert(b == .5);
+
+ b = 6.5 % 3;
+ printf("%Lf %Lf\n", b, b - .5);
+ assert(b == .5);
+}
+
+/*************************************/
+
+void test30()
+{
+ cfloat f = 1+0i;
+ f %= 2fi;
+ printf("%f + %fi\n", f.re, f.im);
+ assert(f == 1 + 0i);
+
+ cdouble d = 1+0i;
+ d %= 2i;
+ printf("%f + %fi\n", d.re, d.im);
+ assert(d == 1 + 0i);
+
+ creal r = 1+0i;
+ r %= 2i;
+ printf("%Lf + %Lfi\n", r.re, r.im);
+ assert(r == 1 + 0i);
+}
+
+/*************************************/
+
+void test31()
+{
+ cfloat f = 1+0i;
+ f %= 2i;
+ printf("%f + %fi\n", f.re, f.im);
+ assert(f == 1);
+
+ cdouble d = 1+0i;
+ d = d % 2i;
+ printf("%f + %fi\n", d.re, d.im);
+ assert(d == 1);
+
+ creal r = 1+0i;
+ r = r % 2i;
+ printf("%Lf + %Lfi\n", r.re, r.im);
+ assert(r == 1);
+}
+
+/*************************************/
+
+void assertEqual(real* a, real* b, string file = __FILE__, size_t line = __LINE__)
+{
+ auto x = cast(ubyte*)a;
+ auto y = cast(ubyte*)b;
+
+ // Only compare the 10 value bytes, the padding bytes are of undefined
+ // value.
+ version (X86) enum count = 10;
+ else version (X86_64) enum count = 10;
+ else enum count = real.sizeof;
+ for (size_t i = 0; i < count; i++)
+ {
+ if (x[i] != y[i])
+ {
+ printf("%02zd: %02x %02x\n", i, x[i], y[i]);
+ import core.exception;
+ throw new AssertError(file, line);
+ }
+ }
+}
+
+void assertEqual(creal* a, creal* b, string file = __FILE__, size_t line = __LINE__)
+{
+ assertEqual(cast(real*)a, cast(real*)b, file, line);
+ assertEqual(cast(real*)a + 1, cast(real*)b + 1, file, line);
+}
+
+void test32()
+{
+ creal a = creal.nan;
+ creal b = real.nan + ireal.nan;
+ assertEqual(&a, &b);
+
+ real c= real.nan;
+ real d=a.re;
+ assertEqual(&c, &d);
+
+ d=a.im;
+ assertEqual(&c, &d);
+}
+
+/*************************************/
+
+void test33()
+{
+ creal a = creal.infinity;
+ creal b = real.infinity + ireal.infinity;
+ assertEqual(&a, &b);
+
+ real c = real.infinity;
+ real d=a.re;
+ assertEqual(&c, &d);
+
+ d=a.im;
+ assertEqual(&c, &d);
+}
+
+/*************************************/
+
+void test34()
+{
+ creal a = creal.nan;
+ creal b = creal.nan;
+ b = real.nan + ireal.nan;
+ assertEqual(&a, &b);
+
+ real c = real.nan;
+ real d=a.re;
+ assertEqual(&c, &d);
+
+ d=a.im;
+ assertEqual(&c, &d);
+}
+
+/*************************************/
+
+ireal x35;
+
+void foo35()
+{
+ x35 = -x35;
+}
+
+void bar35()
+{
+ return foo35();
+}
+
+void test35()
+{
+ x35=2i;
+ bar35();
+ assert(x35==-2i);
+}
+
+/*************************************/
+
+void test36()
+{
+ ireal imag = 2.5i;
+ printf ("test of imag*imag = %Lf\n",imag*imag);
+ assert(imag * imag == -6.25);
+}
+
+/*************************************/
+
+void test37()
+{
+ creal z1 = 1. - 2.0i;
+ ireal imag_part = z1.im/1i;
+}
+
+/***********************************/
+
+void test38()
+{
+ ireal imag = 2.5i;
+ //printf ("test of imag*imag = %Lf\n",imag*imag);
+ real f = imag * imag;
+ assert(f == -6.25);
+}
+
+/***********************************/
+
+void test39()
+{
+ creal z = 1 + 2.5i;
+ real e = z.im;
+
+ printf ("e = %Lf\n", e);
+ assert(e == 2.5);
+}
+
+/***********************************/
+
+void test40()
+{
+ ifloat b = cast(ifloat)1i;
+ assert(b == 1.0i);
+
+ ifloat c = 2fi;
+ assert(c == 2.0i);
+
+ c = 0fi;
+ assert(c == 0i);
+}
+
+/***************************************************/
+
+void test41()
+{
+ creal a=1.3L+9.7Li;
+ assert(a.re == 1.3L);
+ assert(a.im == 9.7L);
+}
+
+/***************************************************/
+
+void test42()
+{
+ creal c = 2.7L + 0i;
+ assert(c.re==2.7L);
+ assert(c.im==0.0L);
+}
+
+/***********************************/
+
+void test43()
+{
+ creal C,Cj;
+ real y1,x1;
+
+ C = x1 + y1*1i + Cj;
+ C = 1i*y1 + x1 + Cj;
+ C = Cj + 1i*y1 + x1;
+ C = y1*1i + Cj + x1;
+ C = 1i*y1 + Cj;
+ C = Cj + 1i*y1;
+}
+
+/***************************************************/
+
+void test44()
+{
+ ifloat f = 1.0fi;
+// f *= 2.0fi; // illegal but compiles
+ printf("%g\n", f);
+// assert(f == 0i);
+}
+
+/******************************************************/
+
+void test45()
+{
+ TypeInfo ti;
+
+ ti = typeid(ifloat[]);
+ assert(!(ti is null));
+ ti = typeid(idouble[]);
+ assert(!(ti is null));
+ ti = typeid(ireal[]);
+ assert(!(ti is null));
+
+ ti = typeid(cfloat[]);
+ assert(!(ti is null));
+ ti = typeid(cdouble[]);
+ assert(!(ti is null));
+ ti = typeid(creal[]);
+ assert(!(ti is null));
+}
+
+/******************************************************/
+
+void test46()
+{
+ TypeInfo ti = typeid(ifloat*);
+ assert(!(ti is null));
+ assert(ti.tsize==(ifloat*).sizeof);
+ assert(ti.toString()=="ifloat*");
+}
+
+/******************************************************/
+
+void test47()
+{
+ TypeInfo ti = typeid(cfloat*);
+ assert(!(ti is null));
+ assert(ti.tsize==(cfloat*).sizeof);
+ assert(ti.toString()=="cfloat*");
+}
+
+/******************************************************/
+
+void test48()
+{
+ TypeInfo ti = typeid(idouble*);
+ assert(!(ti is null));
+ assert(ti.tsize==(idouble*).sizeof);
+ assert(ti.toString()=="idouble*");
+}
+
+/******************************************************/
+
+void test49()
+{
+ TypeInfo ti = typeid(cdouble*);
+ assert(!(ti is null));
+ assert(ti.tsize==(cdouble*).sizeof);
+ assert(ti.toString()=="cdouble*");
+}
+
+/***********************************/
+
+void foo51(creal a)
+{
+ assert(a == -8i);
+}
+
+void test51()
+{
+ assert((2-2i)*(2-2i) == -8i);
+
+ cdouble a = (2-2i)*(2-2i);
+ assert(a == -8i);
+
+ foo51((2-2i)*(2-2i));
+}
+
+/******************************************************/
+
+void test52()
+{
+ TypeInfo ti = typeid(ireal*);
+ assert(!(ti is null));
+ assert(ti.tsize==(ireal*).sizeof);
+ assert(ti.toString()=="ireal*");
+}
+
+/******************************************************/
+
+void test53()
+{
+ TypeInfo ti = typeid(creal*);
+ assert(!(ti is null));
+ assert(ti.tsize==(creal*).sizeof);
+ assert(ti.toString()=="creal*");
+}
+
+/*******************************************/
+
+auto init(T)(T val) { return 1; }
+
+void test54()
+{
+ // See built-in 'init' property
+ assert(10i .init is idouble.nan);
+
+ // x.init() has parens, so it runs UFCS call
+ assert(10i .init() == 1);
+
+ // x.init!YYY matches templatized UFCS call.
+ assert(10i .init!idouble() == 1);
+}
+
+/*******************************************/
+
+creal x55;
+
+void foo55()
+{
+ x55 = -x55;
+}
+
+void bar55()
+{
+ return foo55();
+}
+
+void test55()
+{
+ x55 = 2.0L + 0.0Li;
+ bar55();
+ assert(x55 == -2.0L + 0.0Li);
+}
+
+/***************************************************/
+
+template Q(s...) { alias s q; }
+
+void test56()
+{
+ enum complex80 = Q!( 1+1.0i ).q.stringof;
+}
+
+/********************************************************/
+
+void test57()
+{
+ assert(__traits(isArithmetic, ifloat) == true);
+ assert(__traits(isArithmetic, idouble) == true);
+ assert(__traits(isArithmetic, ireal) == true);
+ assert(__traits(isArithmetic, cfloat) == true);
+ assert(__traits(isArithmetic, cdouble) == true);
+ assert(__traits(isArithmetic, creal) == true);
+
+ assert(__traits(isScalar, ifloat) == true);
+ assert(__traits(isScalar, idouble) == true);
+ assert(__traits(isScalar, ireal) == true);
+ assert(__traits(isScalar, cfloat) == true);
+ assert(__traits(isScalar, cdouble) == true);
+ assert(__traits(isScalar, creal) == true);
+
+ assert(__traits(isFloating, ifloat) == true);
+ assert(__traits(isFloating, idouble) == true);
+ assert(__traits(isFloating, ireal) == true);
+ assert(__traits(isFloating, cfloat) == true);
+ assert(__traits(isFloating, cdouble) == true);
+ assert(__traits(isFloating, creal) == true);
+
+ assert(__traits(isIntegral, ifloat) == false);
+ assert(__traits(isIntegral, idouble) == false);
+ assert(__traits(isIntegral, ireal) == false);
+ assert(__traits(isIntegral, cfloat) == false);
+ assert(__traits(isIntegral, cdouble) == false);
+ assert(__traits(isIntegral, creal) == false);
+
+ assert(__traits(isUnsigned, ifloat) == false);
+ assert(__traits(isUnsigned, idouble) == false);
+ assert(__traits(isUnsigned, ireal) == false);
+ assert(__traits(isUnsigned, cfloat) == false);
+ assert(__traits(isUnsigned, cdouble) == false);
+ assert(__traits(isUnsigned, creal) == false);
+
+ assert(__traits(isAssociativeArray, ifloat) == false);
+ assert(__traits(isAssociativeArray, idouble) == false);
+ assert(__traits(isAssociativeArray, ireal) == false);
+ assert(__traits(isAssociativeArray, cfloat) == false);
+ assert(__traits(isAssociativeArray, cdouble) == false);
+ assert(__traits(isAssociativeArray, creal) == false);
+
+ assert(__traits(isStaticArray, ifloat) == false);
+ assert(__traits(isStaticArray, idouble) == false);
+ assert(__traits(isStaticArray, ireal) == false);
+ assert(__traits(isStaticArray, cfloat) == false);
+ assert(__traits(isStaticArray, cdouble) == false);
+ assert(__traits(isStaticArray, creal) == false);
+
+ assert(__traits(isAbstractClass, ifloat) == false);
+ assert(__traits(isAbstractClass, idouble) == false);
+ assert(__traits(isAbstractClass, ireal) == false);
+ assert(__traits(isAbstractClass, cfloat) == false);
+ assert(__traits(isAbstractClass, cdouble) == false);
+ assert(__traits(isAbstractClass, creal) == false);
+}
+
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=3382
+
+real toreal(ireal x){ return x.im; }
+
+void test3382()
+{
+ assert(1.4i.toreal() == 1.4);
+}
+
+/***************************************************/
+
+alias ireal BUG3919;
+alias typeof(BUG3919.init*BUG3919.init) ICE3919;
+alias typeof(BUG3919.init/BUG3919.init) ICE3920;
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=8454
+
+double sqrt8454(double d) { return d/2; }
+void foo8454(cdouble m) {}
+
+void test8454()
+{
+ foo8454(0 - sqrt8454(1.0) * 1i);
+}
+
+/************************************/
+// https://issues.dlang.org/show_bug.cgi?id=9046
+
+void test9046()
+{
+ foreach (T; AliasSeq!(ifloat, idouble, ireal, cfloat, cdouble, creal))
+ foreach (U; AliasSeq!(T, const T, immutable T, shared T, shared const T, inout T, shared inout T))
+ {
+ static assert(is(typeof(U.init) == U));
+ }
+}
+
+/********************************************/
+// https://issues.dlang.org/show_bug.cgi?id=9112
+
+void test9112a() // T() and T(v)
+{
+ void test(T)(T v)
+ {
+ foreach (string qual; AliasSeq!("", "const ", "immutable "))
+ {
+ mixin("alias U = "~qual~T.stringof~";");
+ //pragma(msg, U);
+
+ mixin("auto x1 = "~qual~T.stringof~"();"); // U() default construction syntax
+ mixin("auto x2 = "~qual~T.stringof~"(v);"); // U(v)
+ static assert(!__traits(compiles, mixin(qual~T.stringof~"(v, v)"))); // U(v, v)
+ static assert(is(typeof(x1) == U));
+ static assert(is(typeof(x2) == U));
+ static if ( is(typeof(U.nan) : real)) assert( isnan(x1.re) && !isnan(x1.im), U.stringof);
+ static if ( is(typeof(U.nan) : ireal)) assert(!isnan(x1.re) && isnan(x1.im), U.stringof);
+ static if ( is(typeof(U.nan) : creal)) assert( isnan(x1.re) && isnan(x1.im), U.stringof);
+ static if (!is(typeof(U.nan))) assert( x1 == U.init, U.stringof);
+ assert(x2 == v, U.stringof);
+ }
+ }
+ test!(ifloat )(1.4142i);
+ test!(idouble)(1.4142i);
+ test!(ireal )(1.4142i);
+ test!(cfloat )(1.2+3.4i);
+ test!(cdouble)(1.2+3.4i);
+ test!(creal )(1.2+3.4i);
+
+ static assert(!__traits(compiles, double(3.14i)));
+}
+
+void test9112b() // new T(v)
+{
+ void test(T)(T v)
+ {
+ foreach (string qual; AliasSeq!("", "const ", "immutable "))
+ {
+ mixin("alias U = "~qual~T.stringof~";");
+ //pragma(msg, U);
+
+ mixin("auto p1 = new "~qual~T.stringof~"();"); // U() default construction syntax
+ mixin("auto p2 = new "~qual~T.stringof~"(v);"); // U(v)
+ static assert(!__traits(compiles, mixin("new "~qual~T.stringof~"(v, v)"))); // U(v, v)
+ static assert(is(typeof(p1) == U*));
+ static assert(is(typeof(p2) == U*));
+ assert( p1 !is null);
+ assert( p2 !is null);
+ auto x1 = *p1;
+ auto x2 = *p2;
+ static if ( is(typeof(U.nan) : real)) assert( isnan(x1.re) && !isnan(x1.im), U.stringof);
+ static if ( is(typeof(U.nan) : ireal)) assert(!isnan(x1.re) && isnan(x1.im), U.stringof);
+ static if ( is(typeof(U.nan) : creal)) assert( isnan(x1.re) && isnan(x1.im), U.stringof);
+ static if (!is(typeof(U.nan))) assert( x1 == U.init, U.stringof);
+ assert(x2 == v, U.stringof);
+ }
+ }
+
+ test!(ifloat )(1.4142i);
+ test!(idouble)(1.4142i);
+ test!(ireal )(1.4142i);
+ test!(cfloat )(1.2+3.4i);
+ test!(cdouble)(1.2+3.4i);
+ test!(creal )(1.2+3.4i);
+
+ static assert(!__traits(compiles, new double(3.14i)));
+}
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10639
+
+struct S1
+{
+ cdouble val;
+}
+
+void formatTest(S1 s, double re, double im)
+{
+ assert(s.val.re == re);
+ assert(s.val.im == im);
+}
+
+void test10639()
+{
+ S1 s = S1(3+2.25i);
+ formatTest(s, 3, 2.25);
+}
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=10842
+
+template Test10842(F, T)
+{
+ bool res;
+ F from()
+ {
+ res = true;
+ return F.init;
+ }
+ T to()
+ {
+ // The cast operand had incorrectly been eliminated
+ return cast(T)from();
+ }
+ bool test()
+ {
+ res = false;
+ to();
+ return res;
+ }
+}
+
+void test10842()
+{
+ foreach (From; AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real))
+ {
+ foreach (To; AliasSeq!(ifloat, idouble, ireal))
+ {
+ if (!Test10842!(From, To).test())
+ assert(0);
+ }
+ }
+
+ foreach (From; AliasSeq!(ifloat, idouble, ireal))
+ {
+ foreach (To; AliasSeq!(/*bool*, */byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real))
+ {
+ if (!Test10842!(From, To).test())
+ assert(0);
+ }
+ }
+}
+
+/***************************************************/
+
+void test10927()
+{
+ static assert( (1+2i) ^^ 3 == -11 - 2i );
+ auto a = (1+2i) ^^ 3;
+}
+
+/******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=13252
+
+alias TypeTuple13252(T...) = T;
+
+static assert(is(typeof(TypeTuple13252!(cast(cfloat )(1 + 2i))[0]) == cfloat ));
+static assert(is(typeof(TypeTuple13252!(cast(cdouble)(1 + 2i))[0]) == cdouble));
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=14218
+
+void test14218()
+{
+ version (DigitalMars)
+ {
+ // Questionable but currently accepted by DMD (but not GDC).
+ foreach (To; AliasSeq!(ifloat, idouble, ireal))
+ {
+ auto x = cast(To)null;
+ assert(x == 0); // 0i
+ }
+
+ // Internal error: backend/el.c in el_long()
+ //foreach (To; AliasSeq!(cfloat, cdouble, creal))
+ //{
+ // static assert(!__traits(compiles, { auto x = cast(To)null; }));
+ //}
+ }
+}
+
+/******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15653
+
+alias TypeTuple15653(T...) = T;
+
+void test15653()
+{
+ void foo(U, T)(const T x) { static assert(is(T == U)); }
+ void bar(U, T)(immutable T x) { static assert(is(T == U)); }
+
+ struct X { int a; long[2] b; }
+ struct Y { int* a; long[] b; }
+
+ foreach (U; TypeTuple15653!(
+ ifloat, idouble, ireal,
+ cfloat, cdouble, creal))
+ {
+ foo!U(U.init); // OK
+ bar!U(U.init); // Was error, now OK
+
+ U u;
+ foo!U(u); // OK
+ bar!U(u); // Was error, now OK
+ }
+}
+
/***************************************/
// https://issues.dlang.org/show_bug.cgi?id=17087
@@ -427,11 +1411,108 @@ void test17677()
}
/***************************************/
+// https://issues.dlang.org/show_bug.cgi?id=17677
+
+float getreal_rcx(cfloat z)
+{
+ return z.re;
+}
+float getimag_rcx(cfloat z)
+{
+ return z.im;
+}
+
+float getreal_rdx(cfloat z, int)
+{
+ return z.re;
+}
+float getimag_rdx(cfloat z, int)
+{
+ return z.im;
+}
+
+float getreal_r8(cfloat z, int, int)
+{
+ return z.re;
+}
+float getimag_r8(cfloat z, int, int)
+{
+ return z.im;
+}
+
+float getreal_r9(cfloat z, int, int, int)
+{
+ return z.re;
+}
+float getimag_r9(cfloat z, int, int, int)
+{
+ return z.im;
+}
+
+float getreal_stack(cfloat z, int, int, int, int)
+{
+ return z.re;
+}
+float getimag_stack(cfloat z, int, int, int, int)
+{
+ return z.im;
+}
+
+void test18772a()
+{
+ cfloat[1] A;
+ float[1] B;
+ int i = 0;
+ A[0] = 2.0f + 4i;
+ B[0] = 3.0f;
+ assert(6.0 == getreal_rcx(A[i] * B[i]));
+ assert(12.0 == getimag_rcx(A[i] * B[i]));
+
+ assert(6.0 == getreal_rdx(A[i] * B[i], 1));
+ assert(12.0 == getimag_rdx(A[i] * B[i], 1));
+
+ assert(6.0 == getreal_r8(A[i] * B[i], 1, 2));
+ assert(12.0 == getimag_r8(A[i] * B[i], 1, 2));
+
+ assert(6.0 == getreal_r9(A[i] * B[i], 1, 2, 3));
+ assert(12.0 == getimag_r9(A[i] * B[i], 1, 2, 3));
+
+ assert(6.0 == getreal_stack(A[i] * B[i], 1, 2, 3, 4));
+ assert(12.0 == getimag_stack(A[i] * B[i], 1, 2, 3, 4));
+}
+
+void test18772b(T)()
+{
+ static auto getre0(T z)
+ {
+ return z.re;
+ }
+ static auto getim0(T z)
+ {
+ return z.im;
+ }
+
+ T z = 3 + 4i;
+ auto d = z.re;
+
+ assert(getre0(d * z) == d * 3);
+ assert(getim0(d * z) == d * 4);
+}
+
+void test18772()
+{
+ test18772a();
+
+ test18772b!cfloat();
+ test18772b!cdouble();
+ test18772b!creal();
+}
+
+/***************************************/
int main(char[][] args)
{
- test1();
test2();
test3();
test4();
@@ -454,10 +1535,59 @@ int main(char[][] args)
test7806();
test7976();
test15();
+ test16();
+ test17();
+ test18();
+ test19();
+ test20();
+ test21();
+ test22();
+ test23();
+ test24();
+ test25();
+ test26();
+ test27();
+ test28();
+ test29();
+ test30();
+ test31();
+ test32();
+ test33();
+ test34();
+ test35();
+ test36();
+ test37();
+ test38();
+ test39();
+ test40();
+ test41();
+ test42();
+ test43();
+ test44();
+ test45();
+ test46();
+ test47();
+ test48();
+ test49();
+ test51();
+ test52();
+ test53();
+ test54();
+ test55();
+ test56();
+ test57();
+ test8454();
+ test9046();
+ test9112a();
+ test9112b();
+ test10639();
+ test10842();
+ test14218();
+ test15653();
test17087();
test17677();
+ test18772();
printf("Success!\n");
return 0;
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/constfold.d b/gcc/testsuite/gdc.test/runnable/constfold.d
index 1d259f6..7857eaf 100644
--- a/gcc/testsuite/gdc.test/runnable/constfold.d
+++ b/gcc/testsuite/gdc.test/runnable/constfold.d
@@ -2,32 +2,17 @@
// RUNNABLE_PHOBOS_TEST
static assert(__LINE__ == 3); // fails as __LINE__ is 2
-import std.stdio;
-import std.math : signbit, sqrt;
+import core.stdc.math : signbit;
/************************************/
static assert(-(1) == -1);
-static assert(-(6i) == -6i);
-static assert(-(1 + 6i) == -1 - 6i);
static assert(!27 == 0);
static assert(!0 == 1);
static assert(!6.2 == 0);
static assert(!0.0 == 1);
-static assert(!3.7i == 0);
-static assert(!0.0i == 1);
-static assert(!(2+3.7i) == 0);
-static assert(!(0+3.7i) == 0);
-static assert(!(2+0.0i) == 0);
-static assert(!(0+0.0i) == 1);
-
-static assert(-6i + 2i == -4i);
-static assert(6i - 1i == 5i);
-
-static assert((3.6 + 7.2i) / (1 + 0i) == 3.6 + 7.2i);
-static assert((3.6 + 7.2i) / (0.0 + 1i) == 7.2 - 3.6i);
static assert((6 % 4) == 2);
static assert((6u % 4u) == 2u);
@@ -157,16 +142,9 @@ static assert((7.2 <= 6.2) == 0);
static assert((7.2 > 6.2) == 1);
static assert((7.2 >= 6.2) == 1);
-static assert((7.2i < 6.2i) == 0);
-
-
-static assert((7.2i == 6.2i) == 0);
-static assert((7.2i != 6.2i) == 1);
static assert((7.2 == 6.2) == 0);
static assert((7.2 != 6.2) == 1);
-static assert((7.2i == 7.2i) == 1);
-static assert((7.2i != 7.2i) == 0);
static assert((7.2 == 7.2) == 1);
static assert((7.2 != 7.2) == 0);
@@ -187,9 +165,6 @@ static assert((5.1 is 4.1) == 0);
static assert((5.1 !is 5.1) == 0);
static assert((5.1 !is 4.1) == 1);
-static assert((5.1 is 5.1i) == 0);
-static assert((5.1 !is 5.1i) == 1);
-
static assert((5 ? 2 : 3) == 2);
static assert((0 ? 2 : 3) == 3);
static assert((5.0 ? 2 : 3) == 2);
@@ -208,25 +183,6 @@ static assert(['a','b','c','d'] == "abcd");
static assert("efgh" == ['e','f','g','h']);
static assert("efgi" != ['e','f','g','h']);
-static assert((2 ^^ 8) == 256);
-static assert((3 ^^ 8.0) == 6561);
-static assert((4.0 ^^ 8) == 65536);
-static assert((5.0 ^^ 8.0) == 390625);
-
-static assert((0.5 ^^ 3) == 0.125);
-static assert((1.5 ^^ 3.0) == 3.375);
-static assert((2.5 ^^ 3) == 15.625);
-static assert((3.5 ^^ 3.0) == 42.875);
-
-static assert(((-2) ^^ -5.0) == -0.031250);
-static assert(((-2.0) ^^ -6) == 0.015625);
-static assert(((-2.0) ^^ -7.0) == -0.0078125);
-
-static assert((144 ^^ 0.5) == 12);
-static assert((1089 ^^ 0.5) == 33);
-static assert((1764 ^^ 0.5) == 42);
-static assert((650.25 ^^ 0.5) == 25.5);
-
void test1()
{
@@ -256,8 +212,6 @@ void test2()
{
float f = float.infinity;
int i = cast(int) f;
- writeln(i);
- writeln(cast(int)float.max);
assert(i == cast(int)float.max);
assert(i == 0x80000000);
}
@@ -270,19 +224,8 @@ void test3()
real n = -0.0;
const real m = -0.0;
- creal c = -0.0 + 3i;
- creal d = n + 3i;
- creal e = m + 3i;
-
- // should print "11111"
- writeln(signbit(n), signbit(m),
- signbit(c.re), signbit(d.re), signbit(e.re));
-
- assert(signbit(n) == 1);
- assert(signbit(m) == 1);
- assert(signbit(c.re) == 1);
- assert(signbit(d.re) == 1);
- assert(signbit(e.re) == 1);
+ assert(signbit(n) != 0);
+ assert(signbit(m) != 0);
}
/************************************/
@@ -354,7 +297,7 @@ int foo9() {
static assert(foo9()==2);
/************************************/
-// Bugzilla 6077
+// https://issues.dlang.org/show_bug.cgi?id=6077
void test6077() {
static string scat(string s1, string s2)
@@ -424,7 +367,7 @@ int test4()
static assert(test4() == 24666);
/************************************/
-// 8400
+// https://issues.dlang.org/show_bug.cgi?id=8400
void test8400()
{
@@ -434,7 +377,7 @@ void test8400()
}
/************************************/
-// 8939
+// https://issues.dlang.org/show_bug.cgi?id=8939
void foo8939(T)(ref T) { } // same for `auto ref`
void bar8939(ref const int) { }
@@ -486,7 +429,7 @@ class C8939regression
}
/************************************/
-// 9058
+// https://issues.dlang.org/show_bug.cgi?id=9058
template TypeTuple9058(TL...) { alias TypeTuple9058 = TL; }
template EnumMembers9058(T)
@@ -504,22 +447,7 @@ void test9058()
}
/************************************/
-// 11159
-
-void test11159()
-{
- import std.math : pow;
- enum ulong
- e_2_pow_64 = 2uL^^64,
- e_10_pow_19 = 10uL^^19,
- e_10_pow_20 = 10uL^^20;
- assert(e_2_pow_64 == pow(2uL, 64));
- assert(e_10_pow_19 == pow(10uL, 19));
- assert(e_10_pow_20 == pow(10uL, 20));
-}
-
-/************************************/
-// 12306
+// https://issues.dlang.org/show_bug.cgi?id=12306
void test12306()
{
@@ -540,7 +468,7 @@ void test12306()
}
/************************************/
-// 13977
+// https://issues.dlang.org/show_bug.cgi?id=13977
void test13977()
{
@@ -570,7 +498,7 @@ void test13977()
}
/************************************/
-// 13978
+// https://issues.dlang.org/show_bug.cgi?id=13978
void test13978()
{
@@ -616,7 +544,7 @@ void test3697or()
}
/************************************/
-// 14459
+// https://issues.dlang.org/show_bug.cgi?id=14459
void test14459()
{
@@ -665,11 +593,9 @@ int main()
test8400();
test8939();
test9058();
- test11159();
test13977();
test13978();
test14459();
- printf("Success\n");
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/cppdtor.d b/gcc/testsuite/gdc.test/runnable/cppdtor.d
new file mode 100644
index 0000000..0592d44
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/cppdtor.d
@@ -0,0 +1,143 @@
+/*
+https://issues.dlang.org/show_bug.cgi?id=21693
+
+RUN_OUTPUT:
+---
+CppA:
+1: CppA.~this
+CppB:
+2: CppB.~this
+2: CppA.~this
+CppC:
+3: CppC.~this
+3: CppB.~this
+3: CppA.~this
+CppC:
+4: CppC.~this
+4: CppB.~this
+4: CppA.~this
+CppNoDestruct:
+DA:
+1: DA.~this
+DB:
+2: DB.~this
+2: DA.~this
+DC:
+3: DC.~this
+3: DB.~this
+3: DA.~this
+DC:
+4: DC.~this
+4: DB.~this
+4: DA.~this
+---
+*/
+
+extern (C) int printf(scope const char*, ...);
+
+extern (C++) class CppA
+{
+ int num;
+ this(int num)
+ {
+ this.num = num;
+ }
+
+ ~this()
+ {
+ printf("%d: CppA.~this\n", num);
+ }
+}
+
+extern (C++) class CppB : CppA
+{
+ this(int num)
+ {
+ super(num);
+ }
+
+ ~this()
+ {
+ printf("%d: CppB.~this\n", num);
+ }
+}
+
+extern (C++) class CppC : CppB
+{
+ this(int num)
+ {
+ super(num);
+ }
+
+ ~this()
+ {
+ printf("%d: CppC.~this\n", num);
+ }
+}
+
+extern (D) class DA
+{
+ int num;
+ this(int num)
+ {
+ this.num = num;
+ }
+
+ ~this()
+ {
+ printf("%d: DA.~this\n", num);
+ }
+}
+
+extern (D) class DB : DA
+{
+ this(int num)
+ {
+ super(num);
+ }
+
+ ~this()
+ {
+ printf("%d: DB.~this\n", num);
+ }
+}
+
+extern (D) class DC : DB
+{
+ this(int num)
+ {
+ super(num);
+ }
+
+ ~this()
+ {
+ printf("%d: DC.~this\n", num);
+ }
+}
+
+extern (C++) class CppNoDestruct
+{
+ int num;
+ this(int num)
+ {
+ this.num = num;
+ }
+}
+
+void main()
+{
+ printf("CppA:\n"); { scope a = new CppA(1); }
+ printf("CppB:\n"); { scope CppA b = new CppB(2); }
+ printf("CppC:\n"); { scope CppA c = new CppC(3); }
+ printf("CppC:\n"); { scope CppB c2 = new CppC(4); }
+
+ printf("CppNoDestruct:\n");
+ {
+ scope const nd = new CppNoDestruct(1);
+ }
+
+ printf("DA:\n"); { scope a = new DA(1); }
+ printf("DB:\n"); { scope DA b = new DB(2); }
+ printf("DC:\n"); { scope DA c = new DC(3); }
+ printf("DC:\n"); { scope DB c2 = new DC(4); }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/ctorpowtests.d b/gcc/testsuite/gdc.test/runnable/ctorpowtests.d
index 89f846a..f2cf5d8 100644
--- a/gcc/testsuite/gdc.test/runnable/ctorpowtests.d
+++ b/gcc/testsuite/gdc.test/runnable/ctorpowtests.d
@@ -3,23 +3,32 @@
int magicVariable()
{
- if (__ctfe)
- return 3;
+ if (__ctfe)
+ return 3;
- shared int var = 2;
- return var;
+ shared int var = 2;
+ return var;
}
static assert(magicVariable()==3);
-void main()
+/************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11159
+
+void test11159()
{
- assert(!__ctfe);
- assert(magicVariable()==2);
+ import std.math : pow;
+ enum ulong
+ e_2_pow_64 = 2uL^^64,
+ e_10_pow_19 = 10uL^^19,
+ e_10_pow_20 = 10uL^^20;
+ assert(e_2_pow_64 == pow(2uL, 64));
+ assert(e_10_pow_19 == pow(10uL, 19));
+ assert(e_10_pow_20 == pow(10uL, 20));
}
-// bug 991 -- invalid.
-// bug 3500 -- is this related to 2127?
+// https://issues.dlang.org/show_bug.cgi?id=991 -- invalid.
+// https://issues.dlang.org/show_bug.cgi?id=3500 -- is this related to 2127?
// Tests for ^^
// TODO: These tests should not require import std.math.
@@ -32,6 +41,25 @@ static assert( 2.0 ^^ 3 == 8.0);
static assert( 2.0 ^^ 4 == 16.0);
static assert( 2 ^^ 4 == 16);
+static assert((2 ^^ 8) == 256);
+static assert((3 ^^ 8.0) == 6561);
+static assert((4.0 ^^ 8) == 65536);
+static assert((5.0 ^^ 8.0) == 390625);
+
+static assert((0.5 ^^ 3) == 0.125);
+static assert((1.5 ^^ 3.0) == 3.375);
+static assert((2.5 ^^ 3) == 15.625);
+static assert((3.5 ^^ 3.0) == 42.875);
+
+static assert(((-2) ^^ -5.0) == -0.031250);
+static assert(((-2.0) ^^ -6) == 0.015625);
+static assert(((-2.0) ^^ -7.0) == -0.0078125);
+
+static assert((144 ^^ 0.5) == 12);
+static assert((1089 ^^ 0.5) == 33);
+static assert((1764 ^^ 0.5) == 42);
+static assert((650.25 ^^ 0.5) == 25.5);
+
// Check the typing rules.
static assert( is (typeof(2.0^^7) == double));
static assert( is (typeof(7^^3) == int));
@@ -78,13 +106,16 @@ static assert( 2 ^^ 3 ^^ 2 == 2 ^^ 9);
static assert( 2.0 ^^ -3 ^^ 2 == 2.0 ^^ -9);
// 1 ^^ n is always 1, even if n is negative
-static assert( 1 ^^ -5 == 1);
+static assert( 1 ^^ -5.0 == 1);
-// -1 ^^ n gets transformed into n & 1 ? -1 : 1
-// even if n is negative
-static assert( (-1) ^^ -5 == -1);
-static assert( (-1) ^^ -4 == 1);
-static assert( (-1) ^^ 0 == 1);
+// -1.0 ^^ n is either 1 or -1 if n is integral.
+static assert( (-1.0) ^^ -5 == -1);
+static assert( (-1.0) ^^ -4 == 1);
+static assert( (-1.0) ^^ 0 == 1);
+// -1.0 ^^ n is otherwise always NaN.
+static assert( (-1.0) ^^ -5.5 is double.nan);
+static assert( (-1.0) ^^ -4.4 is double.nan);
+static assert( (-1.0) ^^ -0.1 is double.nan);
// n ^^ 0 is always 1
static assert( (-5) ^^ 0 == 1);
@@ -100,7 +131,7 @@ static assert( 9 ^^ -1.0 == 1.0 / 9);
static assert( !is(typeof(2 ^^ -5)));
static assert( !is(typeof((-2) ^^ -4)));
-// Bug 3535
+// https://issues.dlang.org/show_bug.cgi?id=3535
struct StructWithCtor
{
this(int _n) {
@@ -232,3 +263,12 @@ int anotherPowTest()
double x = 5.0;
return x^^4 > 2.0 ? 3: 2;
}
+
+/************************************/
+
+void main()
+{
+ assert(!__ctfe);
+ assert(magicVariable()==2);
+ test11159();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/declaration.d b/gcc/testsuite/gdc.test/runnable/declaration.d
index 0dbd287..5be76fa 100644
--- a/gcc/testsuite/gdc.test/runnable/declaration.d
+++ b/gcc/testsuite/gdc.test/runnable/declaration.d
@@ -15,7 +15,7 @@ Success
extern(C) int printf(const char*, ...);
/***************************************************/
-// 6475
+// https://issues.dlang.org/show_bug.cgi?id=6475
class Foo6475(Value)
{
@@ -34,7 +34,7 @@ void test6475()
}
/***************************************************/
-// 6905
+// https://issues.dlang.org/show_bug.cgi?id=6905
void test6905()
{
@@ -62,7 +62,7 @@ void test6905()
}
/***************************************************/
-// 7019
+// https://issues.dlang.org/show_bug.cgi?id=7019
struct S7019
{
@@ -106,7 +106,7 @@ void test7019()
}
/***************************************************/
-// 7239
+// https://issues.dlang.org/show_bug.cgi?id=7239
struct vec7239
{
@@ -145,7 +145,7 @@ void test10635()
}
/***************************************************/
-// 8123
+// https://issues.dlang.org/show_bug.cgi?id=8123
void test8123()
{
@@ -169,7 +169,7 @@ void test8123()
}
/***************************************************/
-// 8147
+// https://issues.dlang.org/show_bug.cgi?id=8147
enum A8147 { a, b, c }
@@ -195,7 +195,7 @@ void test8147()
}
/***************************************************/
-// 8410
+// https://issues.dlang.org/show_bug.cgi?id=8410
void test8410()
{
@@ -207,7 +207,7 @@ void test8410()
}
/***************************************************/
-// 8942
+// https://issues.dlang.org/show_bug.cgi?id=8942
alias const int A8942_0;
static assert(is(A8942_0 == const int)); // passes
@@ -230,7 +230,7 @@ void test8942()
}
/***************************************************/
-// 10144
+// https://issues.dlang.org/show_bug.cgi?id=10144
final class TNFA10144(char_t)
{
@@ -258,7 +258,7 @@ class C10144
/***************************************************/
-// 10142
+// https://issues.dlang.org/show_bug.cgi?id=10142
class File10142
{
@@ -291,7 +291,7 @@ void test10142()
}
/***************************************************/
-// 11421
+// https://issues.dlang.org/show_bug.cgi?id=11421
void test11421()
{
@@ -308,7 +308,7 @@ void test11421()
}
/***************************************************/
-// 13776
+// https://issues.dlang.org/show_bug.cgi?id=13776
enum a13776(T) = __traits(compiles, { T; });
@@ -364,7 +364,7 @@ void test13776()
}
/***************************************************/
-// 14090
+// https://issues.dlang.org/show_bug.cgi?id=14090
template Packed14090(Args...)
{
@@ -389,7 +389,7 @@ template RoundRobin14090()
alias roundRobin14090 = RoundRobin14090!();
/***************************************************/
-// 13950
+// https://issues.dlang.org/show_bug.cgi?id=13950
template Tuple13950(T...) { alias T Tuple13950; }
diff --git a/gcc/testsuite/gdc.test/runnable/delegate.d b/gcc/testsuite/gdc.test/runnable/delegate.d
index a371e1c..1eed53a 100644
--- a/gcc/testsuite/gdc.test/runnable/delegate.d
+++ b/gcc/testsuite/gdc.test/runnable/delegate.d
@@ -1,4 +1,19 @@
-// REQUIRED_ARGS:
+/*
+REQUIRED_ARGS:
+RUN_OUTPUT:
+---
+47 47
+47 47
+48 48
+48 48
+i = 1
+6
+here 3
+here 3
+here 3
+Success
+---
+*/
import core.stdc.stdio;
@@ -187,7 +202,7 @@ void test9()
}
/********************************************************/
-// 8257
+// https://issues.dlang.org/show_bug.cgi?id=8257
struct S8257 {
static int g() {
@@ -227,8 +242,8 @@ void test10()
class A12
{
public:
- int delegate(int, int) dgs[4];
- int function(int, int) fps[4];
+ int delegate(int, int)[4] dgs;
+ int function(int, int)[4] fps;
int delegate(int, int) dg;
int function(int, int) fp;
int f(int x, int y) {
@@ -263,7 +278,7 @@ void test12()
}
/********************************************************/
-// 1570
+// https://issues.dlang.org/show_bug.cgi?id=1570
class A13
{
@@ -291,7 +306,24 @@ void test13()
}
/********************************************************/
-// 2472
+
+enum dg14 = delegate { ++a14; b14 += 2; };
+
+int a14, b14;
+
+void test14()
+{
+ a14 = b14 = 10;
+
+ auto var = dg14;
+ var();
+
+ assert(a14 == 11);
+ assert(b14 == 12);
+}
+
+/********************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=2472
class A2472
{
@@ -348,6 +380,7 @@ int main()
test10();
test12();
test13();
+ test14();
test2472();
test8257();
testAssign();
diff --git a/gcc/testsuite/gdc.test/runnable/dhry.d b/gcc/testsuite/gdc.test/runnable/dhry.d
new file mode 100644
index 0000000..f772d61
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/dhry.d
@@ -0,0 +1,931 @@
+/*
+PERMUTE_ARGS:
+REQUIRED_ARGS: -release -O -g -inline
+DISABLED: freebsd dragonflybsd
+
+Deprecation caused by https://issues.dlang.org/show_bug.cgi?id=20645
+*/
+
+/*
+ *************************************************************************
+ *
+ * "DHRYSTONE" Benchmark Program
+ * -----------------------------
+ *
+ * Version: C, Version 2.1
+ *
+ * File: dhry.h (part 1 of 3)
+ *
+ * Date: May 25, 1988
+ *
+ * Author: Reinhold P. Weicker
+ * Siemens Nixdorf Inf. Syst.
+ * STM OS 32
+ * Otto-Hahn-Ring 6
+ * W-8000 Muenchen 83
+ * Germany
+ * Phone: [+49]-89-636-42436
+ * (8-17 Central European Time)
+ * UUCP: weicker@ztivax.uucp@unido.uucp
+ * Internet: weicker@ztivax.siemens.com
+ *
+ * Original Version (in Ada) published in
+ * "Communications of the ACM" vol. 27., no. 10 (Oct. 1984),
+ * pp. 1013 - 1030, together with the statistics
+ * on which the distribution of statements etc. is based.
+ *
+ * In this C version, the following C library functions are
+ * used:
+ * - strcpy, strcmp (inside the measurement loop)
+ * - printf, scanf (outside the measurement loop)
+ *
+ * Collection of Results:
+ * Reinhold Weicker (address see above) and
+ *
+ * Rick Richardson
+ * PC Research. Inc.
+ * 94 Apple Orchard Drive
+ * Tinton Falls, NJ 07724
+ * Phone: (201) 834-1378 (9-17 EST)
+ * UUCP: ...!uunet!pcrat!rick
+ *
+ * Please send results to Rick Richardson and/or Reinhold Weicker.
+ * Complete information should be given on hardware and software
+ * used. Hardware information includes: Machine type, CPU, type and
+ * size of caches; for microprocessors: clock frequency, memory speed
+ * (number of wait states). Software information includes: Compiler
+ * (and runtime library) manufacturer and version, compilation
+ * switches, OS version. The Operating System version may give an
+ * indication about the compiler; Dhrystone itself performs no OS
+ * calls in the measurement loop.
+ *
+ * The complete output generated by the program should be mailed
+ * such that at least some checks for correctness can be made.
+ *
+ *************************************************************************
+ *
+ * History: This version C/2.1 has been made for two reasons:
+ *
+ * 1) There is an obvious need for a common C version of
+ * Dhrystone, since C is at present the most popular system
+ * programming language for the class of processors
+ * (microcomputers, minicomputers) where Dhrystone is used
+ * most. There should be, as far as possible, only one C
+ * version of Dhrystone such that results can be compared
+ * without restrictions. In the past, the C versions
+ * distributed by Rick Richardson (Version 1.1) and by
+ * Reinhold Weicker had small (though not significant)
+ * differences.
+ *
+ * 2) As far as it is possible without changes to the
+ * Dhrystone statistics, optimizing compilers should be
+ * prevented from removing significant statements.
+ *
+ * This C version has been developed in cooperation with
+ * Rick Richardson (Tinton Falls, NJ), it incorporates many
+ * ideas from the "Version 1.1" distributed previously by
+ * him over the UNIX network Usenet.
+ * I also thank Chaim Benedelac (National Semiconductor),
+ * David Ditzel (SUN), Earl Killian and John Mashey (MIPS),
+ * Alan Smith and Rafael Saavedra-Barrera (UC at Berkeley)
+ * for their help with comments on earlier versions of the
+ * benchmark.
+ *
+ * Changes: In the initialization part, this version follows mostly
+ * Rick Richardson's version distributed via Usenet, not the
+ * version distributed earlier via floppy disk by Reinhold
+ * Weicker. As a concession to older compilers, names have
+ * been made unique within the first 8 characters. Inside the
+ * measurement loop, this version follows the version
+ * previously distributed by Reinhold Weicker.
+ *
+ * At several places in the benchmark, code has been added,
+ * but within the measurement loop only in branches that
+ * are not executed. The intention is that optimizing
+ * compilers should be prevented from moving code out of the
+ * measurement loop, or from removing code altogether. Since
+ * the statements that are executed within the measurement
+ * loop have NOT been changed, the numbers defining the
+ * "Dhrystone distribution" (distribution of statements,
+ * operand types and locality) still hold. Except for
+ * sophisticated optimizing compilers, execution times for
+ * this version should be the same as for previous versions.
+ *
+ * Since it has proven difficult to subtract the time for the
+ * measurement loop overhead in a correct way, the loop check
+ * has been made a part of the benchmark. This does have
+ * an impact - though a very minor one - on the distribution
+ * statistics which have been updated for this version.
+ *
+ * All changes within the measurement loop are described
+ * and discussed in the companion paper "Rationale for
+ * Dhrystone version 2".
+ *
+ * Because of the self-imposed limitation that the order and
+ * distribution of the executed statements should not be
+ * changed, there are still cases where optimizing compilers
+ * may not generate code for some statements. To a certain
+ * degree, this is unavoidable for small synthetic
+ * benchmarks. Users of the benchmark are advised to check
+ * code listings whether code is generated for all statements
+ * of Dhrystone.
+ *
+ * Version 2.1 is identical to version 2.0 distributed via
+ * the UNIX network Usenet in March 1988 except that it
+ * corrects some minor deficiencies that were found by users
+ * of version 2.0. The only change within the measurement
+ * loop is that a non-executed "else" part was added to the
+ * "if" statement in Func_3, and a non-executed "else" part
+ * removed from Proc_3.
+ *
+ *************************************************************************
+ *
+ * Defines: The following "Defines" are possible:
+ * -DROPT (default: Not defined)
+ * As an approximation to what an average C
+ * programmer might do, the "register" storage class
+ * is applied (if enabled by -DROPT)
+ * - for local variables, if they are used
+ * (dynamically) five or more times
+ * - for parameters if they are used (dynamically)
+ * six or more times
+ * Note that an optimal "register" strategy is
+ * compiler-dependent, and that "register"
+ * declarations do not necessarily lead to faster
+ * execution.
+ * -DNOSTRUCTASSIGN (default: Not defined)
+ * Define if the C compiler does not support
+ * assignment of structures.
+ * -DNOENUMS (default: Not defined)
+ * Define if the C compiler does not support
+ * enumeration types.
+ *
+ *************************************************************************
+ *
+ * Compilation model and measurement (IMPORTANT):
+ *
+ * This C version of Dhrystone consists of three files:
+ * - dhry.h (this file, containing global definitions and comments)
+ * - dhry_1.c (containing the code corresponding to Ada package Pack_1)
+ * - dhry_2.c (containing the code corresponding to Ada package Pack_2)
+ *
+ * The following "ground rules" apply for measurements:
+ * - Separate compilation
+ * - No procedure merging
+ * - Otherwise, compiler optimizations are allowed but should be
+ * indicated
+ * - Default results are those without register declarations
+ * See the companion paper "Rationale for Dhrystone Version 2" for a more
+ * detailed discussion of these ground rules.
+ *
+ * For 16-Bit processors (e.g. 80186, 80286), times for all compilation
+ * models ("small", "medium", "large" etc.) should be given if possible,
+ * together with a definition of these models for the compiler system
+ * used.
+ *
+ *************************************************************************
+ *
+ * Dhrystone (C version) statistics:
+ *
+ * [Comment from the first distribution, updated for version 2.
+ * Note that because of language differences, the numbers are slightly
+ * different from the Ada version.]
+ *
+ * The following program contains statements of a high level programming
+ * language (here: C) in a distribution considered representative:
+ *
+ * assignments 52 (51.0 %)
+ * control statements 33 (32.4 %)
+ * procedure, function calls 17 (16.7 %)
+ *
+ * 103 statements are dynamically executed. The program is balanced with
+ * respect to the three aspects:
+ *
+ * - statement type
+ * - operand type
+ * - operand locality
+ * operand global, local, parameter, or constant.
+ *
+ * The combination of these three aspects is balanced only approximately.
+ *
+ * 1. Statement Type:
+ * ----------------- number
+ *
+ * V1 = V2 9
+ * (incl. V1 = F(..)
+ * V = Constant 12
+ * Assignment, 7
+ * with array element
+ * Assignment, 6
+ * with record component
+ * --
+ * 34 34
+ *
+ * X = Y +|-|"&&"|"|" Z 5
+ * X = Y +|-|"==" Constant 6
+ * X = X +|- 1 3
+ * X = Y *|/ Z 2
+ * X = Expression, 1
+ * two operators
+ * X = Expression, 1
+ * three operators
+ * --
+ * 18 18
+ *
+ * if .... 14
+ * with "else" 7
+ * without "else" 7
+ * executed 3
+ * not executed 4
+ * for ... 7 | counted every time
+ * while ... 4 | the loop condition
+ * do ... while 1 | is evaluated
+ * switch ... 1
+ * break 1
+ * declaration with 1
+ * initialization
+ * --
+ * 34 34
+ *
+ * P (...) procedure call 11
+ * user procedure 10
+ * library procedure 1
+ * X = F (...)
+ * function call 6
+ * user function 5
+ * library function 1
+ * --
+ * 17 17
+ * ---
+ * 103
+ *
+ * The average number of parameters in procedure or function calls
+ * is 1.82 (not counting the function values as implicit parameters).
+ *
+ *
+ * 2. Operators
+ * ------------
+ * number approximate
+ * percentage
+ *
+ * Arithmetic 32 50.8
+ *
+ * + 21 33.3
+ * - 7 11.1
+ * * 3 4.8
+ * / (int div) 1 1.6
+ *
+ * Comparison 27 42.8
+ *
+ * == 9 14.3
+ * /= 4 6.3
+ * > 1 1.6
+ * < 3 4.8
+ * >= 1 1.6
+ * <= 9 14.3
+ *
+ * Logic 4 6.3
+ *
+ * && (AND-THEN) 1 1.6
+ * | (OR) 1 1.6
+ * ! (NOT) 2 3.2
+ *
+ * -- -----
+ * 63 100.1
+ *
+ *
+ * 3. Operand Type (counted once per operand reference):
+ * ---------------
+ * number approximate
+ * percentage
+ *
+ * Integer 175 72.3 %
+ * Character 45 18.6 %
+ * Pointer 12 5.0 %
+ * String30 6 2.5 %
+ * Array 2 0.8 %
+ * Record 2 0.8 %
+ * --- -------
+ * 242 100.0 %
+ *
+ * When there is an access path leading to the final operand (e.g. a
+ * record component), only the final data type on the access path is
+ * counted.
+ *
+ *
+ * 4. Operand Locality:
+ * -------------------
+ * number approximate
+ * percentage
+ *
+ * local variable 114 47.1 %
+ * global variable 22 9.1 %
+ * parameter 45 18.6 %
+ * value 23 9.5 %
+ * reference 22 9.1 %
+ * function result 6 2.5 %
+ * constant 55 22.7 %
+ * --- -------
+ * 242 100.0 %
+ *
+ *
+ * The program does not compute anything meaningful, but it is
+ * syntactically and semantically correct. All variables have a value
+ * assigned to them before they are used as a source operand.
+ *
+ * There has been no explicit effort to account for the effects of a
+ * cache, or to balance the use of long or short displacements for code
+ * or data.
+ *
+ *************************************************************************
+ */
+
+import core.stdc.stdio;
+import core.stdc.string;
+import core.stdc.stdlib;
+import std.string;
+
+
+/* Compiler and system dependent definitions: */
+
+const double Mic_secs_Per_Second = 1000000.0;
+ /* Berkeley UNIX C returns process times in seconds/HZ */
+
+enum {Ident_1, Ident_2, Ident_3, Ident_4, Ident_5}
+alias int Enumeration;
+ /* for boolean and enumeration types in Ada, Pascal */
+
+/* General definitions: */
+
+const int StrLen = 30;
+
+alias int One_Thirty;
+alias int One_Fifty;
+alias char Capital_Letter;
+alias bool Boolean;
+alias char[StrLen] Str_30;
+alias int[50] Arr_1_Dim;
+alias int[50][50] Arr_2_Dim;
+
+struct record
+{
+ record *Ptr_Comp;
+ Enumeration Discr;
+ union V {
+ struct V1 {
+ Enumeration Enum_Comp;
+ int Int_Comp;
+ char[StrLen] Str_Comp;
+ }
+ V1 var_1;
+ struct V2 {
+ Enumeration E_Comp_2;
+ char [StrLen] Str_2_Comp;
+ }
+ V2 var_2;
+ struct V3 {
+ char Ch_1_Comp;
+ char Ch_2_Comp;
+ }
+ V3 var_3;
+ }
+ V variant;
+}
+
+alias record Rec_Type;
+alias record *Rec_Pointer;
+
+
+/* Global Variables: */
+
+Rec_Pointer Ptr_Glob,
+ Next_Ptr_Glob;
+int Int_Glob;
+Boolean Bool_Glob;
+char Ch_1_Glob,
+ Ch_2_Glob;
+int[50] Arr_1_Glob;
+int[50][50] Arr_2_Glob;
+
+char[StrLen] Reg_Define = "Register option selected.";
+
+/* variables for time measurement: */
+
+const int Too_Small_Time = 2;
+ /* Measurements should last at least 2 seconds */
+
+double Begin_Time,
+ End_Time,
+ User_Time;
+
+double Microseconds,
+ Dhrystones_Per_Second,
+ Vax_Mips;
+
+/* end of variables for time measurement */
+
+
+void main ()
+/*****/
+
+ /* main program, corresponds to procedures */
+ /* Main and Proc_0 in the Ada version */
+{
+ One_Fifty Int_1_Loc;
+ One_Fifty Int_2_Loc;
+ One_Fifty Int_3_Loc;
+ char Ch_Index;
+ Enumeration Enum_Loc;
+ Str_30 Str_1_Loc;
+ Str_30 Str_2_Loc;
+ int Run_Index;
+ int Number_Of_Runs;
+
+/+
+ FILE *Ap;
+
+ /* Initializations */
+
+ if ((Ap = fopen("dhry.res","a+")) == null)
+ {
+ printf("Can not open dhry.res\n\n");
+ exit(1);
+ }
++/
+
+ Next_Ptr_Glob = cast(Rec_Pointer) malloc (Rec_Type.sizeof);
+ Ptr_Glob = cast(Rec_Pointer) malloc (Rec_Type.sizeof);
+
+ Ptr_Glob.Ptr_Comp = Next_Ptr_Glob;
+ Ptr_Glob.Discr = Ident_1;
+ Ptr_Glob.variant.var_1.Enum_Comp = Ident_3;
+ Ptr_Glob.variant.var_1.Int_Comp = 40;
+// strcpy (Ptr_Glob.variant.var_1.Str_Comp,
+// "DHRYSTONE PROGRAM, SOME STRING");
+// strcpy (Str_1_Loc, "DHRYSTONE PROGRAM, 1'ST STRING");
+ Ptr_Glob.variant.var_1.Str_Comp[] = "DHRYSTONE PROGRAM, SOME STRING";
+ Str_1_Loc[] = "DHRYSTONE PROGRAM, 1'ST STRING";
+
+ Arr_2_Glob [8][7] = 10;
+ /* Was missing in published program. Without this statement, */
+ /* Arr_2_Glob [8][7] would have an undefined value. */
+ /* Warning: With 16-Bit processors and Number_Of_Runs > 32000, */
+ /* overflow may occur for this array element. */
+
+ printf ("\n");
+ printf ("Dhrystone Benchmark, Version 2.1 (Language: D)\n");
+ printf ("\n");
+ printf ("Please give the number of runs through the benchmark: ");
+ {
+ int n;
+ //scanf ("%d", &n);
+ n = 10000000;
+ Number_Of_Runs = n;
+ }
+ printf ("\n");
+
+ printf ("Execution starts, %d runs through Dhrystone\n",Number_Of_Runs);
+
+ /***************/
+ /* Start timer */
+ /***************/
+
+ Begin_Time = dtime();
+
+ for (Run_Index = 1; Run_Index <= Number_Of_Runs; ++Run_Index)
+ {
+
+ Proc_5();
+ Proc_4();
+ /* Ch_1_Glob == 'A', Ch_2_Glob == 'B', Bool_Glob == true */
+ Int_1_Loc = 2;
+ Int_2_Loc = 3;
+ //strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 2'ND STRING");
+ Str_2_Loc[] = "DHRYSTONE PROGRAM, 2'ND STRING";
+ Enum_Loc = Ident_2;
+ Bool_Glob = ! Func_2 (Str_1_Loc, Str_2_Loc);
+ /* Bool_Glob == 1 */
+ while (Int_1_Loc < Int_2_Loc) /* loop body executed once */
+ {
+ Int_3_Loc = 5 * Int_1_Loc - Int_2_Loc;
+ /* Int_3_Loc == 7 */
+ Proc_7 (Int_1_Loc, Int_2_Loc, &Int_3_Loc);
+ /* Int_3_Loc == 7 */
+ Int_1_Loc += 1;
+ } /* while */
+ /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+ Proc_8 (Arr_1_Glob, Arr_2_Glob, Int_1_Loc, Int_3_Loc);
+ /* Int_Glob == 5 */
+ Proc_1 (Ptr_Glob);
+ for (Ch_Index = 'A'; Ch_Index <= Ch_2_Glob; ++Ch_Index)
+ /* loop body executed twice */
+ {
+ if (Enum_Loc == Func_1 (Ch_Index, 'C'))
+ /* then, not executed */
+ {
+ Proc_6 (Ident_1, &Enum_Loc);
+ //strcpy (Str_2_Loc, "DHRYSTONE PROGRAM, 3'RD STRING");
+ Str_2_Loc[] = "DHRYSTONE PROGRAM, 3'RD STRING";
+ Int_2_Loc = Run_Index;
+ Int_Glob = Run_Index;
+ }
+ }
+ /* Int_1_Loc == 3, Int_2_Loc == 3, Int_3_Loc == 7 */
+ Int_2_Loc = Int_2_Loc * Int_1_Loc;
+ Int_1_Loc = Int_2_Loc / Int_3_Loc;
+ Int_2_Loc = 7 * (Int_2_Loc - Int_3_Loc) - Int_1_Loc;
+ /* Int_1_Loc == 1, Int_2_Loc == 13, Int_3_Loc == 7 */
+ Proc_2 (&Int_1_Loc);
+ /* Int_1_Loc == 5 */
+
+ } /* loop "for Run_Index" */
+
+ /**************/
+ /* Stop timer */
+ /**************/
+
+ End_Time = dtime();
+
+ printf ("Execution ends\n");
+ printf ("\n");
+ printf ("Final values of the variables used in the benchmark:\n");
+ printf ("\n");
+ printf ("Int_Glob: %d\n", Int_Glob);
+ printf (" should be: %d\n", 5);
+ printf ("Bool_Glob: %d\n", Bool_Glob);
+ printf (" should be: %d\n", 1);
+ printf ("Ch_1_Glob: %c\n", Ch_1_Glob);
+ printf (" should be: %c\n", 'A');
+ printf ("Ch_2_Glob: %c\n", Ch_2_Glob);
+ printf (" should be: %c\n", 'B');
+ printf ("Arr_1_Glob[8]: %d\n", Arr_1_Glob[8]);
+ printf (" should be: %d\n", 7);
+ printf ("Arr_2_Glob[8][7]: %d\n", Arr_2_Glob[8][7]);
+ printf (" should be: Number_Of_Runs + 10\n");
+ printf ("Ptr_Glob.\n");
+ printf (" Ptr_Comp: %d\n", cast(int) Ptr_Glob.Ptr_Comp);
+ printf (" should be: (implementation-dependent)\n");
+ printf (" Discr: %d\n", Ptr_Glob.Discr);
+ printf (" should be: %d\n", 0);
+ printf (" Enum_Comp: %d\n", Ptr_Glob.variant.var_1.Enum_Comp);
+ printf (" should be: %d\n", 2);
+ printf (" Int_Comp: %d\n", Ptr_Glob.variant.var_1.Int_Comp);
+ printf (" should be: %d\n", 17);
+ printf (" Str_Comp: %.*s\n", cast(int)Ptr_Glob.variant.var_1.Str_Comp.length, Ptr_Glob.variant.var_1.Str_Comp.ptr);
+ printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
+ printf ("Next_Ptr_Glob.\n");
+ printf (" Ptr_Comp: %d\n", cast(int) Next_Ptr_Glob.Ptr_Comp);
+ printf (" should be: (implementation-dependent), same as above\n");
+ printf (" Discr: %d\n", Next_Ptr_Glob.Discr);
+ printf (" should be: %d\n", 0);
+ printf (" Enum_Comp: %d\n", Next_Ptr_Glob.variant.var_1.Enum_Comp);
+ printf (" should be: %d\n", 1);
+ printf (" Int_Comp: %d\n", Next_Ptr_Glob.variant.var_1.Int_Comp);
+ printf (" should be: %d\n", 18);
+ printf (" Str_Comp: %.*s\n", cast(int)Next_Ptr_Glob.variant.var_1.Str_Comp.length, Next_Ptr_Glob.variant.var_1.Str_Comp.ptr);
+ printf (" should be: DHRYSTONE PROGRAM, SOME STRING\n");
+ printf ("Int_1_Loc: %d\n", Int_1_Loc);
+ printf (" should be: %d\n", 5);
+ printf ("Int_2_Loc: %d\n", Int_2_Loc);
+ printf (" should be: %d\n", 13);
+ printf ("Int_3_Loc: %d\n", Int_3_Loc);
+ printf (" should be: %d\n", 7);
+ printf ("Enum_Loc: %d\n", Enum_Loc);
+ printf (" should be: %d\n", 1);
+ printf ("Str_1_Loc: %.*s\n", cast(int)Str_1_Loc.length, Str_1_Loc.ptr);
+ printf (" should be: DHRYSTONE PROGRAM, 1'ST STRING\n");
+ printf ("Str_2_Loc: %.*s\n", cast(int)Str_2_Loc.length, Str_2_Loc.ptr);
+ printf (" should be: DHRYSTONE PROGRAM, 2'ND STRING\n");
+ printf ("\n");
+
+ User_Time = End_Time - Begin_Time;
+
+ if (User_Time < Too_Small_Time)
+ {
+ printf ("Measured time too small to obtain meaningful results\n");
+ printf ("Please increase number of runs\n");
+ printf ("\n");
+ }
+ else
+ {
+ Microseconds = User_Time * Mic_secs_Per_Second
+ / cast(double) Number_Of_Runs;
+ Dhrystones_Per_Second = cast(double) Number_Of_Runs / User_Time;
+ Vax_Mips = Dhrystones_Per_Second / 1757.0;
+
+ printf ("Register option selected? NO\n");
+ strcpy(Reg_Define.ptr, "Register option not selected.");
+ printf ("Microseconds for one run through Dhrystone: ");
+ printf ("%7.1f \n", Microseconds);
+ printf ("Dhrystones per Second: ");
+ printf ("%10.1f \n", Dhrystones_Per_Second);
+ printf ("VAX MIPS rating = %10.3f \n",Vax_Mips);
+ printf ("\n");
+
+ /+
+ fprintf(Ap,"\n");
+ fprintf(Ap,"Dhrystone Benchmark, Version 2.1 (Language: D)\n");
+ fprintf(Ap,"%.*s\n",Reg_Define.length, Reg_Define.ptr);
+ fprintf(Ap,"Microseconds for one loop: %7.1f\n",Microseconds);
+ fprintf(Ap,"Dhrystones per second: %10.1f\n",Dhrystones_Per_Second);
+ fprintf(Ap,"VAX MIPS rating: %10.3f\n",Vax_Mips);
+ fclose(Ap);
+ +/
+
+ }
+
+}
+
+void Proc_1 (Rec_Pointer Ptr_Val_Par)
+/******************/
+
+ /* executed once */
+{
+ Rec_Pointer Next_Record = Ptr_Val_Par.Ptr_Comp;
+ /* == Ptr_Glob_Next */
+ /* Local variable, initialized with Ptr_Val_Par.Ptr_Comp, */
+ /* corresponds to "rename" in Ada, "with" in Pascal */
+
+ *Ptr_Val_Par.Ptr_Comp = *Ptr_Glob;
+ Ptr_Val_Par.variant.var_1.Int_Comp = 5;
+ Next_Record.variant.var_1.Int_Comp
+ = Ptr_Val_Par.variant.var_1.Int_Comp;
+ Next_Record.Ptr_Comp = Ptr_Val_Par.Ptr_Comp;
+ Proc_3 (&Next_Record.Ptr_Comp);
+ /* Ptr_Val_Par.Ptr_Comp.Ptr_Comp
+ == Ptr_Glob.Ptr_Comp */
+ if (Next_Record.Discr == Ident_1)
+ /* then, executed */
+ {
+ Next_Record.variant.var_1.Int_Comp = 6;
+ Proc_6 (Ptr_Val_Par.variant.var_1.Enum_Comp,
+ &Next_Record.variant.var_1.Enum_Comp);
+ Next_Record.Ptr_Comp = Ptr_Glob.Ptr_Comp;
+ Proc_7 (Next_Record.variant.var_1.Int_Comp, 10,
+ &Next_Record.variant.var_1.Int_Comp);
+ }
+ else /* not executed */
+ *Ptr_Val_Par = *Ptr_Val_Par.Ptr_Comp;
+} /* Proc_1 */
+
+void Proc_2 (One_Fifty *Int_Par_Ref)
+/******************/
+ /* executed once */
+ /* *Int_Par_Ref == 1, becomes 4 */
+{
+ One_Fifty Int_Loc;
+ Enumeration Enum_Loc;
+
+ Int_Loc = *Int_Par_Ref + 10;
+ do /* executed once */
+ if (Ch_1_Glob == 'A')
+ /* then, executed */
+ {
+ Int_Loc -= 1;
+ *Int_Par_Ref = Int_Loc - Int_Glob;
+ Enum_Loc = Ident_1;
+ } /* if */
+ while (Enum_Loc != Ident_1); /* true */
+} /* Proc_2 */
+
+
+void Proc_3 (Rec_Pointer *Ptr_Ref_Par)
+/******************/
+ /* executed once */
+ /* Ptr_Ref_Par becomes Ptr_Glob */
+
+{
+ if (Ptr_Glob != null)
+ /* then, executed */
+ *Ptr_Ref_Par = Ptr_Glob.Ptr_Comp;
+ Proc_7 (10, Int_Glob, &Ptr_Glob.variant.var_1.Int_Comp);
+} /* Proc_3 */
+
+void Proc_4 () /* without parameters */
+/*******/
+ /* executed once */
+{
+ Boolean Bool_Loc;
+
+ Bool_Loc = Ch_1_Glob == 'A';
+ Bool_Glob = Bool_Loc | Bool_Glob;
+ Ch_2_Glob = 'B';
+} /* Proc_4 */
+
+
+void Proc_5 () /* without parameters */
+/*******/
+ /* executed once */
+{
+ Ch_1_Glob = 'A';
+ Bool_Glob = false;
+} /* Proc_5 */
+
+
+void Proc_6 (Enumeration Enum_Val_Par, Enumeration *Enum_Ref_Par)
+/*********************************/
+ /* executed once */
+ /* Enum_Val_Par == Ident_3, Enum_Ref_Par becomes Ident_2 */
+{
+ *Enum_Ref_Par = Enum_Val_Par;
+ if (! Func_3 (Enum_Val_Par))
+ /* then, not executed */
+ *Enum_Ref_Par = Ident_4;
+ final switch (Enum_Val_Par)
+ {
+ case Ident_1:
+ *Enum_Ref_Par = Ident_1;
+ break;
+ case Ident_2:
+ if (Int_Glob > 100)
+ /* then */
+ *Enum_Ref_Par = Ident_1;
+ else *Enum_Ref_Par = Ident_4;
+ break;
+ case Ident_3: /* executed */
+ *Enum_Ref_Par = Ident_2;
+ break;
+ case Ident_4: break;
+ case Ident_5:
+ *Enum_Ref_Par = Ident_3;
+ break;
+ } /* switch */
+} /* Proc_6 */
+
+
+void Proc_7 (One_Fifty Int_1_Par_Val, One_Fifty Int_2_Par_Val, One_Fifty *Int_Par_Ref)
+/**********************************************/
+ /* executed three times */
+ /* first call: Int_1_Par_Val == 2, Int_2_Par_Val == 3, */
+ /* Int_Par_Ref becomes 7 */
+ /* second call: Int_1_Par_Val == 10, Int_2_Par_Val == 5, */
+ /* Int_Par_Ref becomes 17 */
+ /* third call: Int_1_Par_Val == 6, Int_2_Par_Val == 10, */
+ /* Int_Par_Ref becomes 18 */
+{
+ One_Fifty Int_Loc;
+
+ Int_Loc = Int_1_Par_Val + 2;
+ *Int_Par_Ref = Int_2_Par_Val + Int_Loc;
+} /* Proc_7 */
+
+
+void Proc_8 (ref Arr_1_Dim Arr_1_Par_Ref, ref Arr_2_Dim Arr_2_Par_Ref, int Int_1_Par_Val, int Int_2_Par_Val)
+/*********************************************************************/
+ /* executed once */
+ /* Int_Par_Val_1 == 3 */
+ /* Int_Par_Val_2 == 7 */
+{
+ One_Fifty Int_Index;
+ One_Fifty Int_Loc;
+
+ Int_Loc = Int_1_Par_Val + 5;
+ Arr_1_Par_Ref [Int_Loc] = Int_2_Par_Val;
+ Arr_1_Par_Ref [Int_Loc+1] = Arr_1_Par_Ref [Int_Loc];
+ Arr_1_Par_Ref [Int_Loc+30] = Int_Loc;
+ for (Int_Index = Int_Loc; Int_Index <= Int_Loc+1; ++Int_Index)
+ Arr_2_Par_Ref [Int_Loc] [Int_Index] = Int_Loc;
+ Arr_2_Par_Ref [Int_Loc] [Int_Loc-1] += 1;
+ Arr_2_Par_Ref [Int_Loc+20] [Int_Loc] = Arr_1_Par_Ref [Int_Loc];
+ Int_Glob = 5;
+} /* Proc_8 */
+
+
+Enumeration Func_1 (Capital_Letter Ch_1_Par_Val, Capital_Letter Ch_2_Par_Val)
+/*************************************************/
+ /* executed three times */
+ /* first call: Ch_1_Par_Val == 'H', Ch_2_Par_Val == 'R' */
+ /* second call: Ch_1_Par_Val == 'A', Ch_2_Par_Val == 'C' */
+ /* third call: Ch_1_Par_Val == 'B', Ch_2_Par_Val == 'C' */
+{
+ Capital_Letter Ch_1_Loc;
+ Capital_Letter Ch_2_Loc;
+
+ Ch_1_Loc = Ch_1_Par_Val;
+ Ch_2_Loc = Ch_1_Loc;
+ if (Ch_2_Loc != Ch_2_Par_Val)
+ /* then, executed */
+ return (Ident_1);
+ else /* not executed */
+ {
+ Ch_1_Glob = Ch_1_Loc;
+ return (Ident_2);
+ }
+} /* Func_1 */
+
+
+Boolean Func_2 (Str_30 Str_1_Par_Ref, Str_30 Str_2_Par_Ref)
+/*************************************************/
+ /* executed once */
+ /* Str_1_Par_Ref == "DHRYSTONE PROGRAM, 1'ST STRING" */
+ /* Str_2_Par_Ref == "DHRYSTONE PROGRAM, 2'ND STRING" */
+{
+ One_Thirty Int_Loc;
+ Capital_Letter Ch_Loc;
+
+ Int_Loc = 2;
+ while (Int_Loc <= 2) /* loop body executed once */
+ if (Func_1 (Str_1_Par_Ref[Int_Loc],
+ Str_2_Par_Ref[Int_Loc+1]) == Ident_1)
+ /* then, executed */
+ {
+ Ch_Loc = 'A';
+ Int_Loc += 1;
+ } /* if, while */
+ if (Ch_Loc >= 'W' && Ch_Loc < 'Z')
+ /* then, not executed */
+ Int_Loc = 7;
+ if (Ch_Loc == 'R')
+ /* then, not executed */
+ return (true);
+ else /* executed */
+ {
+ //if (strcmp (Str_1_Par_Ref, Str_2_Par_Ref) > 0)
+ //if (memcmp (Str_1_Par_Ref, Str_2_Par_Ref, 30) > 0)
+ if (Str_1_Par_Ref > Str_2_Par_Ref)
+ /* then, not executed */
+ {
+ Int_Loc += 7;
+ Int_Glob = Int_Loc;
+ return (true);
+ }
+ else /* executed */
+ return (false);
+ } /* if Ch_Loc */
+} /* Func_2 */
+
+
+Boolean Func_3 (Enumeration Enum_Par_Val)
+/***************************/
+ /* executed once */
+ /* Enum_Par_Val == Ident_3 */
+{
+ Enumeration Enum_Loc;
+
+ Enum_Loc = Enum_Par_Val;
+ if (Enum_Loc == Ident_3)
+ /* then, executed */
+ return (true);
+ else /* not executed */
+ return (false);
+} /* Func_3 */
+
+version (Windows)
+{
+ import core.sys.windows.winbase;
+
+ double dtime()
+ {
+ double q;
+
+ q = cast(double)GetTickCount() * 1.0e-03;
+
+ return q;
+ }
+}
+
+version (linux)
+{
+ import core.stdc.time;
+
+ double dtime()
+ {
+ double q;
+
+ q = cast(double)time(null);
+
+ return q;
+ }
+}
+
+version (OSX) // supplied by Anders F Bjorklund
+{
+ import core.sys.posix.sys.time;
+
+ double dtime()
+ {
+ double q;
+ timeval tv;
+
+ gettimeofday(&tv,null);
+ q = cast(double)tv.tv_sec + cast(double)tv.tv_usec * 1.0e-6;
+
+ return q;
+ }
+}
+
+version (NetBSD)
+{
+ import core.sys.posix.sys.time;
+
+ double dtime()
+ {
+ double q;
+ timeval tv;
+
+ gettimeofday(&tv,null);
+ q = cast(double)tv.tv_sec + cast(double)tv.tv_usec * 1.0e-6;
+
+ return q;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/eh.d b/gcc/testsuite/gdc.test/runnable/eh.d
index b3077a2..7e7ec19 100644
--- a/gcc/testsuite/gdc.test/runnable/eh.d
+++ b/gcc/testsuite/gdc.test/runnable/eh.d
@@ -104,7 +104,7 @@ printf("catch, i = %d\n", i);
}
}
- printf("iterations %d totals: %ld, %ld\n", cIterations, total_x, total_nox);
+ printf("iterations %d totals: %lld, %lld\n", cIterations, total_x, total_nox);
}
int fn2_nox()
@@ -170,7 +170,7 @@ void test4()
catch(Exception e)
{
auto es = e.toString();
- printf("%.*s\n", es.length, es.ptr);
+ printf("%.*s\n", cast(int)es.length, es.ptr);
b++;
}
finally
@@ -213,7 +213,7 @@ void test4()
{
d++;
string es = e.toString;
- printf("%.*s\n", es.length, es.ptr);
+ printf("%.*s\n", cast(int)es.length, es.ptr);
}
assert(a == 2);
@@ -255,7 +255,7 @@ void test4()
{
q3++;
string es = e.toString;
- printf("%.*s\n", es.length, es.ptr);
+ printf("%.*s\n", cast(int)es.length, es.ptr);
}
assert(q0 == 1);
@@ -287,7 +287,7 @@ void test5()
result ~= cast(char)('a' + i);
}
}
- printf("--- %.*s", result.length, result.ptr);
+ printf("--- %.*s", cast(int)result.length, result.ptr);
if (result != "tctbta")
assert(0);
}
@@ -352,6 +352,38 @@ void test7()
/****************************************************
* Exception chaining tests. See also test4.d
+ * Don writes about the complexity:
+
+I can explain this, since I did the original implementation.
+When I originally implemented this, I discovered that the idea of
+"chained exceptions" was hopeless naive. The idea was that while
+processing one exception, if you encounter a second one, and you
+chain them together. Then you get a third, fourth, etc.
+
+The problem is that it's much more complicated than that. Each of
+the exceptions can be a chain of exceptions themselves. This means
+that you don't end up with a chain of exceptions, but rather a tree
+of exceptions. That's why there are those really nasty test cases
+in the test suite.
+
+The examples in the test suite are very difficult to understand if
+you expect it to be a simple chain!
+
+On the one hand, I was very proud that I was able to work out the
+barely-documented behaviour of Windows SEH, and it was really
+thorough. In the initial implementation, all the complexity
+was covered. It wasn't the bugfix-driven-development which dmd
+usually operates under <g>.
+
+But on the other hand, once you can see all of the complexity,
+exception chaining becomes much less convincing as a concept. Sure,
+the full exception tree is available in the final exception which
+you catch. But, is it of any use? I doubt it very much.
+It's pretty clearly a nett loss to the language, it increases
+complexity with negligible benefit. Fortunately in this case, the
+cost isn't really high.
+
+https://digitalmars.com/d/archives/digitalmars/D/Dicebot_on_leaving_D_It_is_anarchy_driven_development_in_all_its_317950.html#N318305
****************************************************/
int result1513;
@@ -379,6 +411,15 @@ void bug1513b()
assert(e.msg == "d");
assert(e.next.msg == "f");
assert(!e.next.next);
+ int i;
+ foreach (u; e)
+ {
+ if (i)
+ assert(u.msg == "f");
+ else
+ assert(u.msg == "d");
+ ++i;
+ }
}
}
@@ -658,7 +699,7 @@ void test9()
}
/****************************************************/
-// 10964
+// https://issues.dlang.org/show_bug.cgi?id=10964
void test10964()
{
@@ -836,6 +877,137 @@ void test17481()
/****************************************************/
+// a nothrow function, even though it is not marked as nothrow
+void test12()
+{
+ int i = 3;
+ try
+ {
+ try
+ {
+ ++i;
+ goto L10;
+ }
+ finally
+ {
+ i *= 2;
+ printf("f1\n");
+ }
+ }
+ finally
+ {
+ i += 5;
+ printf("f2\n");
+ }
+
+L10:
+ printf("3\n");
+ assert(i == (3 + 1) * 2 + 5);
+}
+
+/****************************************************/
+
+void foo13() { }
+
+void test13()
+{
+ int i = 3;
+ try
+ {
+ try
+ {
+ foo13(); // compiler assumes it throws
+ ++i;
+ goto L10;
+ }
+ finally
+ {
+ i *= 2;
+ printf("f1\n");
+ }
+ }
+ finally
+ {
+ i += 5;
+ printf("f2\n");
+ }
+
+L10:
+ printf("3\n");
+ assert(i == (3 + 1) * 2 + 5);
+}
+
+/****************************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=10966
+
+void bug10966a(void* p)
+{
+ void* pstart = p;
+
+ try
+ {
+ p = null;
+ throw new Exception("dummy");
+ }
+ catch (Throwable o)
+ {
+ assert(p != pstart);
+ }
+}
+
+void bug10966b()
+{
+ int x = 0;
+ int i = 0;
+ try
+ {
+ i = 1;
+ throw new Exception("dummy");
+ }
+ catch (Throwable o)
+ {
+ x = i;
+ }
+ assert(x == 1);
+}
+
+void test10966()
+{
+ int s;
+ bug10966a(&s);
+ bug10966b();
+}
+
+/****************************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=11049
+
+void test11049()
+{
+ int[] arr = [1,2,3];
+
+#line 4100 "foo"
+ try { auto n = arr[3]; }
+ catch (Error e)
+ {
+ //printf("e.file = %s\n", e.file.ptr);
+ assert(e.file == "foo"); // fails
+ assert(e.line == 4100);
+ }
+
+#line 4200 "bar"
+ try { auto a = arr[3..9]; }
+ catch (Error e)
+ {
+ //printf("e.file = %s\n", e.file.ptr);
+ assert(e.file == "bar"); // fails
+ assert(e.line == 4200);
+ }
+}
+
+/****************************************************/
+
int main()
{
printf("start\n");
@@ -860,6 +1032,10 @@ int main()
test10();
test11();
test17481();
+ test12();
+ test13();
+ test10966();
+ test11049();
printf("finish\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/entity1.d b/gcc/testsuite/gdc.test/runnable/entity1.d
index 3921193..feeb1ee 100644
--- a/gcc/testsuite/gdc.test/runnable/entity1.d
+++ b/gcc/testsuite/gdc.test/runnable/entity1.d
@@ -136,7 +136,7 @@ int main(){
return 0;
}
-// Bug 5221
+// https://issues.dlang.org/show_bug.cgi?id=5221
static assert('\&check;'==10003);
static assert('\&lsim;'==8818);
static assert('\&numero;'==8470);
diff --git a/gcc/testsuite/gdc.test/runnable/evalorder.d b/gcc/testsuite/gdc.test/runnable/evalorder.d
index 8b56cc7..6805ee2 100644
--- a/gcc/testsuite/gdc.test/runnable/evalorder.d
+++ b/gcc/testsuite/gdc.test/runnable/evalorder.d
@@ -1,3 +1,9 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
extern(C) int printf(const char*, ...);
void test14040()
diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/lib13742a.d b/gcc/testsuite/gdc.test/runnable/extra-files/lib13742a.d
new file mode 100644
index 0000000..762559b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/extra-files/lib13742a.d
@@ -0,0 +1,6 @@
+module lib13742a;
+
+void performLocked(alias PROC)()
+{
+ PROC();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/lib13742b.d b/gcc/testsuite/gdc.test/runnable/extra-files/lib13742b.d
new file mode 100644
index 0000000..03163b5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/extra-files/lib13742b.d
@@ -0,0 +1,8 @@
+module lib13742b;
+import lib13742a;
+
+void clear()
+{
+ void foo() {} // nested function
+ performLocked!foo; // template from other module (preceding on command line)
+}
diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/minimal/object.d b/gcc/testsuite/gdc.test/runnable/extra-files/minimal/object.d
new file mode 100644
index 0000000..bc8b372
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/extra-files/minimal/object.d
@@ -0,0 +1,8 @@
+module object;
+
+extern(C) void _Dmain();
+
+extern(C) void main()
+{
+ _Dmain();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/moreBettercUnittests.d b/gcc/testsuite/gdc.test/runnable/extra-files/moreBettercUnittests.d
new file mode 100644
index 0000000..1597a16
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/extra-files/moreBettercUnittests.d
@@ -0,0 +1,11 @@
+__gshared uint sum;
+
+unittest
+{
+ sum |= 0x100;
+}
+
+unittest
+{
+ sum |= 0x1000;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/test13742.d b/gcc/testsuite/gdc.test/runnable/extra-files/test13742.d
new file mode 100644
index 0000000..3666bb2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/extra-files/test13742.d
@@ -0,0 +1,6 @@
+import lib13742b;
+
+void main()
+{
+ clear();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/teststdio.txt b/gcc/testsuite/gdc.test/runnable/extra-files/teststdio.txt
deleted file mode 100644
index 9a5f6b1..0000000
--- a/gcc/testsuite/gdc.test/runnable/extra-files/teststdio.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-asdfasdf
-a
-sdf
-asdf
-
-
diff --git a/gcc/testsuite/gdc.test/runnable/fix20466.d b/gcc/testsuite/gdc.test/runnable/fix20466.d
new file mode 100644
index 0000000..afc8349
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/fix20466.d
@@ -0,0 +1,40 @@
+/* REQUIRED_ARGS: -O -fPIC
+ * DISABLED: win32 win64
+ */
+// https://issues.dlang.org/show_bug.cgi?id=20466
+
+extern (C++) final class Parameter
+{
+ ulong storageClass;
+ void* type;
+}
+
+extern (C++) final class IfStatement
+{
+ Parameter prm;
+}
+
+extern (C++) final class Visitor
+{
+ void visit(IfStatement s)
+ {
+ if (Parameter p = s.prm)
+ {
+ ulong stc = p.storageClass;
+ if (!p.type && !stc)
+ stc = 1L << 8;
+ assert(!(stc & (1L << 34)));
+ }
+ }
+}
+
+int main()
+{
+ auto p = new Parameter;
+ p.storageClass = 1L << 2;
+ auto s = new IfStatement;
+ s.prm = p;
+ auto v = new Visitor;
+ v.visit(s);
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/fix22115.d b/gcc/testsuite/gdc.test/runnable/fix22115.d
new file mode 100644
index 0000000..2344bcc
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/fix22115.d
@@ -0,0 +1,70 @@
+/* PERMUTE_ARGS: -O -inline
+ */
+// https://issues.dlang.org/show_bug.cgi?id=22115
+
+
+int sx;
+void sss() { ++sx; }
+
+static if (1)
+{
+ struct S { int a; }
+
+ void test1(S* s)
+ {
+ if (s.a == 3 ? s : null)
+ sss();
+ }
+}
+
+static if (1)
+{
+ extern (C++) class Exp
+ {
+ int a;
+
+ void func() { }
+ final inout(AddExp) isAddExp() inout { return a == 3 ? cast(typeof(return))this : null; }
+ }
+
+ extern (C++) class AddExp : Exp
+ {
+ }
+
+ void test2(Exp e)
+ {
+ if (e.isAddExp())
+ sss();
+ }
+}
+
+
+int main()
+{
+ static if (1)
+ {
+ S s;
+ s.a = 3;
+ test1(&s);
+ assert(sx == 1);
+ s.a = 2;
+ test1(&s);
+ assert(sx == 1);
+ }
+ sx = 1;
+
+ static if (1)
+ {
+ auto c = new AddExp();
+ c.a = 3;
+ test2(c);
+ assert(sx == 2);
+ auto ae = c.isAddExp();
+ assert(ae && ae.a == 3);
+ c.a = 2;
+ test2(c);
+ assert(sx == 2);
+ }
+
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/foreach.d b/gcc/testsuite/gdc.test/runnable/foreach.d
index 331c927..f0d1ea9 100644
--- a/gcc/testsuite/gdc.test/runnable/foreach.d
+++ b/gcc/testsuite/gdc.test/runnable/foreach.d
@@ -1,3 +1,22 @@
+/*
+RUN_OUTPUT:
+---
+u = 17
+u = 1
+u = 1
+u = 1
+u = 1
+a[0] = 21
+a[1] = 22
+a[2] = 23
+a[] = 21
+a[] = 22
+a[] = 23
+a = 63, b = 47, c = 83
+a = 63, b = 48, c = 83
+Success
+---
+*/
import core.stdc.stdio;
@@ -209,16 +228,26 @@ void test7()
a["foo"] = 3;
a["bar"] = 4;
+ bool sawBar, sawFoo;
foreach (string s, uint v; a)
{
- printf("a[%.*s] = %d\n", s.length, s.ptr, v);
if (s == "bar")
+ {
assert(v == 4);
+ assert(!sawBar);
+ sawBar = true;
+ }
else if (s == "foo")
+ {
assert(v == 3);
+ assert(!sawFoo);
+ sawFoo = true;
+ }
else
assert(0);
}
+ assert(sawBar);
+ assert(sawFoo);
}
diff --git a/gcc/testsuite/gdc.test/runnable/foreach2.d b/gcc/testsuite/gdc.test/runnable/foreach2.d
index 34edb41..b30d151 100644
--- a/gcc/testsuite/gdc.test/runnable/foreach2.d
+++ b/gcc/testsuite/gdc.test/runnable/foreach2.d
@@ -1,3 +1,9 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
import core.stdc.stdio;
diff --git a/gcc/testsuite/gdc.test/runnable/foreach3.d b/gcc/testsuite/gdc.test/runnable/foreach3.d
index e167217..3c9c288 100644
--- a/gcc/testsuite/gdc.test/runnable/foreach3.d
+++ b/gcc/testsuite/gdc.test/runnable/foreach3.d
@@ -1,9 +1,15 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
import core.stdc.stdio;
struct Foo
{
- uint array[2];
+ uint[2] array;
int opApply(int delegate(ref uint) dg)
{
diff --git a/gcc/testsuite/gdc.test/runnable/foreach4.d b/gcc/testsuite/gdc.test/runnable/foreach4.d
index 8c9d421..f2e1943 100644
--- a/gcc/testsuite/gdc.test/runnable/foreach4.d
+++ b/gcc/testsuite/gdc.test/runnable/foreach4.d
@@ -1,6 +1,4 @@
-// RUNNABLE_PHOBOS_TEST
import core.stdc.stdio;
-import std.stdio;
alias bool bit;
@@ -8,7 +6,7 @@ alias bool bit;
class Foo
{
- uint array[2];
+ uint[2] array;
int opApply(int delegate(ref uint) dg)
{
@@ -363,7 +361,7 @@ void test12()
j = 0;
foreach (size_t i, dchar d; "hello")
{
- printf("i = %d, d = x%x\n", i, d);
+ printf("i = %d, d = x%x\n", cast(int)i, d);
if (j == 0) assert(d == 'h');
if (j == 1) assert(d == 'e');
if (j == 2) assert(d == 'l');
@@ -397,7 +395,7 @@ void test13()
j = 0;
foreach (size_t i, wchar d; "hello")
{
- printf("i = %d, d = x%x\n", i, d);
+ printf("i = %d, d = x%x\n", cast(int)i, d);
if (j == 0) assert(d == 'h');
if (j == 1) assert(d == 'e');
if (j == 2) assert(d == 'l');
@@ -431,7 +429,7 @@ void test14()
j = 0;
foreach (size_t i, char d; cast(wstring)"hello")
{
- printf("i = %d, d = x%x\n", i, d);
+ printf("i = %d, d = x%x\n", cast(int)i, d);
if (j == 0) assert(d == 'h');
if (j == 1) assert(d == 'e');
if (j == 2) assert(d == 'l');
@@ -465,7 +463,7 @@ void test15()
j = 0;
foreach (size_t i, dchar d; cast(wstring)"hello")
{
- printf("i = %d, d = x%x\n", i, d);
+ printf("i = %d, d = x%x\n", cast(int)i, d);
if (j == 0) assert(d == 'h');
if (j == 1) assert(d == 'e');
if (j == 2) assert(d == 'l');
@@ -499,7 +497,7 @@ void test16()
j = 0;
foreach (size_t i, char d; cast(dstring)"hello")
{
- printf("i = %d, d = x%x\n", i, d);
+ printf("i = %d, d = x%x\n", cast(int)i, d);
if (j == 0) assert(d == 'h');
if (j == 1) assert(d == 'e');
if (j == 2) assert(d == 'l');
@@ -533,7 +531,7 @@ void test17()
j = 0;
foreach (size_t i, wchar d; cast(dstring)"hello")
{
- printf("i = %d, d = x%x\n", i, d);
+ printf("i = %d, d = x%x\n", cast(int)i, d);
if (j == 0) assert(d == 'h');
if (j == 1) assert(d == 'e');
if (j == 2) assert(d == 'l');
@@ -577,7 +575,7 @@ void test18()
void test19()
{
- string string = x"F0 9D 83 93";
+ string string = "\xF0\x9D\x83\x93";
int count=0;
dchar tmp;
@@ -615,18 +613,18 @@ void test20()
void foo21(string[] args)
{
- printf("args.length = %d\n", args.length);
+ printf("args.length = %d\n", cast(int)args.length);
assert(args.length == 3);
foreach (i, arg; args)
{
assert(typeid(typeof(i)) == typeid(size_t));
assert(typeid(typeof(arg)) == typeid(string));
- writefln("args[%d] = '%s'", i, arg);
+ printf("args[%d] = '%.*s'\n", cast(int)i, cast(int)arg.length, arg.ptr);
}
foreach (arg; args)
{
assert(typeid(typeof(arg)) == typeid(string));
- writefln("args[] = '%s'", arg);
+ printf("args[] = '%.*s'\n", cast(int)arg.length, arg.ptr);
}
}
@@ -654,24 +652,24 @@ void test22()
{
assert(typeid(typeof(key)) == typeid(string));
assert(typeid(typeof(value)) == typeid(int));
- writefln("map[%s] = %s", key, value);
+ printf("map[%.*s] = %d\n", cast(int)key.length, key.ptr, value);
}
foreach (key, int value; map)
{
assert(typeid(typeof(key)) == typeid(string));
assert(typeid(typeof(value)) == typeid(int));
- writefln("map[%s] = %s", key, value);
+ printf("map[%.*s] = %d\n", cast(int)key.length, key.ptr, value);
}
foreach (string key, value; map)
{
assert(typeid(typeof(key)) == typeid(string));
assert(typeid(typeof(value)) == typeid(int));
- writefln("map[%s] = %s", key, value);
+ printf("map[%.*s] = %d\n", cast(int)key.length, key.ptr, value);
}
foreach (value; map)
{
assert(typeid(typeof(value)) == typeid(int));
- writefln("map[] = %s", value);
+ printf("map[] = %d\n", value);
}
}
@@ -679,7 +677,7 @@ void test22()
class Foo23
{
- int array[2];
+ int[2] array;
int opApply(int delegate(ref int) dg)
{
@@ -719,7 +717,7 @@ void test23()
assert(typeid(typeof(u)) == typeid(int));
i++;
u++;
- //writefln("u = %d", u);
+ //printf("u = %d\n", u);
assert((i == 1) ? u == 74 : u == 83);
}
assert(i == 2);
@@ -732,7 +730,7 @@ void test23()
assert(typeid(typeof(u)) == typeid(int));
i++;
u++;
- writefln("u = %d", u);
+ //printf("u = %d\n", u);
assert((i == 3) ? u == 74 : u == 83);
assert(j == i - 3);
}
@@ -777,7 +775,6 @@ void test25()
{
foreach (string s; aarray)
{
- writeln(s);
assert(s == "b");
}
};
@@ -790,7 +787,7 @@ void test25()
struct Foo26
{
- uint array[2];
+ uint[2] array;
int forward(int delegate(ref uint) dg)
{
@@ -833,7 +830,7 @@ void test26()
foreach (u; &a.forward)
{
- writeln(u);
+ printf("%d\n", u);
i++;
u++;
}
@@ -843,7 +840,7 @@ void test26()
foreach (uint u; &a.reverse)
{
- writeln(u);
+ printf("%d\n", u);
}
}
diff --git a/gcc/testsuite/gdc.test/runnable/foreach5.d b/gcc/testsuite/gdc.test/runnable/foreach5.d
index 003a34a..59b88ec 100644
--- a/gcc/testsuite/gdc.test/runnable/foreach5.d
+++ b/gcc/testsuite/gdc.test/runnable/foreach5.d
@@ -1,4 +1,5 @@
/*
+EXTRA_FILES: imports/test15777a.d imports/test15777b.d
TEST_OUTPUT:
---
int
@@ -14,6 +15,8 @@ test7406()
extern(C) int printf(const char* fmt, ...);
+alias AliasSeq(X...) = X;
+
/***************************************/
void test1()
@@ -43,7 +46,7 @@ void test1()
}
/***************************************/
-// 2411
+// https://issues.dlang.org/show_bug.cgi?id=2411
struct S2411
{
@@ -68,7 +71,7 @@ void test2411()
}
/***************************************/
-// 2442
+// https://issues.dlang.org/show_bug.cgi?id=2442
template canForeach(T, E)
{
@@ -148,7 +151,7 @@ void test2442()
}
/***************************************/
-// 2443
+// https://issues.dlang.org/show_bug.cgi?id=2443
struct S2443
{
@@ -175,7 +178,7 @@ void test2443()
}
/***************************************/
-// 3187
+// https://issues.dlang.org/show_bug.cgi?id=3187
class Collection
{
@@ -200,7 +203,7 @@ void test3187()
}
/***************************************/
-// 4090
+// https://issues.dlang.org/show_bug.cgi?id=4090
void test4090a()
{
@@ -244,7 +247,7 @@ void test4090b()
}
/***************************************/
-// 5605
+// https://issues.dlang.org/show_bug.cgi?id=5605
struct MyRange
{
@@ -255,7 +258,7 @@ struct MyRange
return true;
}
- @property ref int front()
+ @property ref int front() return
{
return theOnlyOne;
}
@@ -282,7 +285,7 @@ void test5605()
}
/***************************************/
-// 7004
+// https://issues.dlang.org/show_bug.cgi?id=7004
void func7004(A...)(A args)
{
@@ -296,7 +299,7 @@ void test7004()
}
/***************************************/
-// 7406
+// https://issues.dlang.org/show_bug.cgi?id=7406
template TypeTuple7406(T...)
{
@@ -327,7 +330,7 @@ void test7406()
}
/***************************************/
-// 6659
+// https://issues.dlang.org/show_bug.cgi?id=6659
void test6659()
{
@@ -417,7 +420,7 @@ void test6659c()
/***************************************/
-// 10221
+// https://issues.dlang.org/show_bug.cgi?id=10221
void test10221()
{
@@ -446,7 +449,7 @@ void test10221()
}
/***************************************/
-// 7814
+// https://issues.dlang.org/show_bug.cgi?id=7814
struct File7814
{
@@ -475,7 +478,7 @@ void test7814()
}
/***************************************/
-// 10049
+// https://issues.dlang.org/show_bug.cgi?id=10049
struct ByLine10049
{
@@ -515,7 +518,7 @@ void test11955()
}
/******************************************/
-// 6652
+// https://issues.dlang.org/show_bug.cgi?id=6652
void test6652()
{
@@ -616,7 +619,7 @@ void test6652()
}
/***************************************/
-// 8595
+// https://issues.dlang.org/show_bug.cgi?id=8595
struct OpApply8595
{
@@ -636,7 +639,7 @@ string test8595()
}
/***************************************/
-// 9068
+// https://issues.dlang.org/show_bug.cgi?id=9068
struct Foo9068
{
@@ -723,7 +726,7 @@ loop_with_dtors:
}
/***************************************/
-// 11885
+// https://issues.dlang.org/show_bug.cgi?id=11885
struct Foo11885
{
@@ -810,7 +813,7 @@ loop_with_dtors:
}
/***************************************/
-// 10475
+// https://issues.dlang.org/show_bug.cgi?id=10475
void test10475a()
{
@@ -888,7 +891,7 @@ void test10475b()
}
/***************************************/
-// 11291
+// https://issues.dlang.org/show_bug.cgi?id=11291
void test11291()
{
@@ -917,7 +920,7 @@ void test11291()
}
/***************************************/
-// 12103
+// https://issues.dlang.org/show_bug.cgi?id=12103
alias TypeTuple12103(TL...) = TL;
@@ -945,7 +948,7 @@ void test12103()
}
/***************************************/
-// 12739
+// https://issues.dlang.org/show_bug.cgi?id=12739
struct S12739
{
@@ -963,7 +966,7 @@ void test12739() nothrow
}
/***************************************/
-// 12932
+// https://issues.dlang.org/show_bug.cgi?id=12932
void test12932() @nogc
{
@@ -976,7 +979,7 @@ void test12932() @nogc
}
/***************************************/
-// 13756
+// https://issues.dlang.org/show_bug.cgi?id=13756
void test13756()
{
@@ -1046,7 +1049,7 @@ void test13756()
}
/***************************************/
-// 14653
+// https://issues.dlang.org/show_bug.cgi?id=14653
static string result14653;
@@ -1098,6 +1101,81 @@ void test14653()
}
/***************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15777
+
+template funA15777()
+{
+ import imports.test15777a;
+ alias funA15777 = fun;
+}
+
+template funB15777()
+{
+ import imports.test15777b;
+ alias funB15777 = fun;
+}
+
+template funAB15777()
+{
+ import imports.test15777a;
+ import imports.test15777b;
+ alias funAB15777 = fun;
+}
+
+void foo15777(alias tpl)()
+{
+ alias seq = AliasSeq!(tpl!());
+ // Make alias of 'overload set' in tuple elements
+ static assert(seq.length == 1);
+ foreach (i, n; seq)
+ {
+ static assert(__traits(identifier, seq[i]) == "fun");
+ }
+}
+
+void test15777()
+{
+ foo15777!funA15777;
+ foo15777!funB15777;
+ foo15777!funAB15777;
+}
+
+/***************************************/
+// https://issues.dlang.org/show_bug.cgi?id=17041
+
+auto ref int[2] foo17041(A...)(auto ref A args)
+{
+ foreach(a; args)
+ {
+ a = [12, 22];
+ }
+ foreach(ref a; args)
+ {
+ a = [31, 41];
+ return args[0];
+ }
+}
+
+void test17041()
+{
+ int[2] x = [10, 20];
+ foreach(a; AliasSeq!(x))
+ {
+ a = [11, 21];
+ }
+ assert(x == [10, 20]); // test by value
+ foreach(ref a; AliasSeq!(x))
+ {
+ a = [30, 40];
+ }
+ assert(x == [30, 40]); // test by ref value
+
+ assert(foo17041(x) == [31, 41]); // test lvalue
+ assert(x == [31, 41]);
+ assert(foo17041(cast(int[2]) [10, 20]) == [31, 41]); // test rvalue
+}
+
+/***************************************/
int main()
{
@@ -1125,10 +1203,10 @@ int main()
test11291();
test12103();
test12739();
- printf("test12932()\n");
test12932();
test13756();
test14653();
+ test17041();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/funclit.d b/gcc/testsuite/gdc.test/runnable/funclit.d
index c299bad..25b4e6e 100644
--- a/gcc/testsuite/gdc.test/runnable/funclit.d
+++ b/gcc/testsuite/gdc.test/runnable/funclit.d
@@ -176,7 +176,7 @@ void test4()
// function/delegate inference + overload resolution
assert(nbaz4({ }) == 1);
assert(nbaz4({ v = 1; }) == 2);
- assert(nbaz4({ sfoo(); }) == 1); // Bugzilla 8836
+ assert(nbaz4({ sfoo(); }) == 1); // https://issues.dlang.org/show_bug.cgi?id=8836
assert(nbaz4({ nfoo(); }) == 2);
assert(tbaz4({ }) == 1);
@@ -354,7 +354,7 @@ void test11()
}
/***************************************************/
-// 3235
+// https://issues.dlang.org/show_bug.cgi?id=3235
void test3235()
{
@@ -365,7 +365,7 @@ void test3235()
}
/***************************************************/
-// 6714
+// https://issues.dlang.org/show_bug.cgi?id=6714
void foo6714x(int function (int, int) a){}
void bar6714x(int delegate (int, int) a){}
@@ -384,7 +384,7 @@ void test6714()
}
/***************************************************/
-// 7193
+// https://issues.dlang.org/show_bug.cgi?id=7193
void test7193()
{
@@ -394,7 +394,8 @@ void test7193()
}
/***************************************************/
-// 7207 : on CastExp
+// https://issues.dlang.org/show_bug.cgi?id=7207
+// on CastExp
void test7202()
{
@@ -403,7 +404,7 @@ void test7202()
}
/***************************************************/
-// 7288
+// https://issues.dlang.org/show_bug.cgi?id=7288
void test7288()
{
@@ -411,7 +412,7 @@ void test7288()
auto foo()
{
int x;
- return () => { return x; };
+ return () { return () => x; };
}
pragma(msg, typeof(&foo));
alias int delegate() pure nothrow @nogc @safe delegate() pure nothrow @nogc @safe delegate() pure nothrow @safe Dg;
@@ -420,7 +421,7 @@ void test7288()
}
/***************************************************/
-// 7499
+// https://issues.dlang.org/show_bug.cgi?id=7499
void test7499()
{
@@ -431,7 +432,7 @@ void test7499()
}
/***************************************************/
-// 7500
+// https://issues.dlang.org/show_bug.cgi?id=7500
void test7500()
{
@@ -440,7 +441,7 @@ void test7500()
}
/***************************************************/
-// 7525
+// https://issues.dlang.org/show_bug.cgi?id=7525
void test7525()
{
@@ -462,7 +463,7 @@ void test7525()
}
/***************************************************/
-// 7582
+// https://issues.dlang.org/show_bug.cgi?id=7582
void test7582()
{
@@ -474,7 +475,7 @@ void test7582()
}
/***************************************************/
-// 7649
+// https://issues.dlang.org/show_bug.cgi?id=7649
void test7649()
{
@@ -486,7 +487,7 @@ void test7649()
}
/***************************************************/
-// 7650
+// https://issues.dlang.org/show_bug.cgi?id=7650
void test7650()
{
@@ -513,7 +514,7 @@ void test7650()
}
/***************************************************/
-// 7705
+// https://issues.dlang.org/show_bug.cgi?id=7705
void test7705()
{
@@ -529,7 +530,7 @@ void test7705()
}
/***************************************************/
-// 7713
+// https://issues.dlang.org/show_bug.cgi?id=7713
void foo7713(T)(T delegate(in Object) dlg)
{}
@@ -539,7 +540,7 @@ void test7713()
}
/***************************************************/
-// 7743
+// https://issues.dlang.org/show_bug.cgi?id=7743
auto foo7743a()
{
@@ -564,7 +565,7 @@ void test7743()
}
/***************************************************/
-// 7761
+// https://issues.dlang.org/show_bug.cgi?id=7761
enum dg7761 = (int a) pure => 2 * a;
@@ -575,7 +576,7 @@ void test7761()
}
/***************************************************/
-// 7941
+// https://issues.dlang.org/show_bug.cgi?id=7941
void test7941()
{
@@ -583,7 +584,7 @@ void test7941()
}
/***************************************************/
-// 8005
+// https://issues.dlang.org/show_bug.cgi?id=8005
void test8005()
{
@@ -615,7 +616,7 @@ void test8198()
}
/***************************************************/
-// 8226
+// https://issues.dlang.org/show_bug.cgi?id=8226
immutable f8226 = (int x) => x * 2;
@@ -625,7 +626,7 @@ void test8226()
}
/***************************************************/
-// 8241
+// https://issues.dlang.org/show_bug.cgi?id=8241
auto exec8241a(alias a = function(x) => x, T...)(T as)
{
@@ -644,7 +645,7 @@ void test8241()
}
/***************************************************/
-// 8242
+// https://issues.dlang.org/show_bug.cgi?id=8242
template exec8242(alias a, T...)
{
@@ -664,7 +665,7 @@ void test8242()
}
/***************************************************/
-// 8315
+// https://issues.dlang.org/show_bug.cgi?id=8315
void test8315()
{
@@ -677,7 +678,7 @@ if (is(typeof(pred(1)) == bool))
{}
/***************************************************/
-// 8397
+// https://issues.dlang.org/show_bug.cgi?id=8397
void test8397()
{
@@ -688,7 +689,7 @@ void test8397()
}
/***************************************************/
-// 8496
+// https://issues.dlang.org/show_bug.cgi?id=8496
void test8496()
{
@@ -700,7 +701,7 @@ void test8496()
}
/***************************************************/
-// 8575
+// https://issues.dlang.org/show_bug.cgi?id=8575
template tfunc8575(func...)
{
@@ -720,7 +721,7 @@ void test8575()
}
/***************************************************/
-// 9153
+// https://issues.dlang.org/show_bug.cgi?id=9153
void writeln9153(string s){}
@@ -737,7 +738,7 @@ void test9153()
}
/***************************************************/
-// 9393
+// https://issues.dlang.org/show_bug.cgi?id=9393
template ifThrown9393a(E)
{
@@ -761,7 +762,7 @@ void test9393()
}
/***************************************************/
-// 9415
+// https://issues.dlang.org/show_bug.cgi?id=9415
void test9415()
{
@@ -771,7 +772,7 @@ void test9415()
}
/***************************************************/
-// 9628
+// https://issues.dlang.org/show_bug.cgi?id=9628
template TypeTuple9628(TL...) { alias TypeTuple9628 = TL; }
void map9628(alias func)() { func(0); }
@@ -805,7 +806,7 @@ void test9628()
}
/***************************************************/
-// 9928
+// https://issues.dlang.org/show_bug.cgi?id=9928
void test9928()
{
@@ -813,7 +814,7 @@ void test9928()
}
/***************************************************/
-// 10133
+// https://issues.dlang.org/show_bug.cgi?id=10133
ptrdiff_t countUntil10133(alias pred, R)(R haystack)
{
@@ -855,7 +856,7 @@ void test10133()
}
/***************************************************/
-// 10219
+// https://issues.dlang.org/show_bug.cgi?id=10219
void test10219()
{
@@ -904,7 +905,7 @@ void test10219()
}
/***************************************************/
-// 10288
+// https://issues.dlang.org/show_bug.cgi?id=10288
T foo10288(T)(T x)
{
@@ -934,7 +935,7 @@ void test10288() @safe pure nothrow
}
/***************************************************/
-// 10666
+// https://issues.dlang.org/show_bug.cgi?id=10666
struct S10666
{
@@ -954,7 +955,7 @@ void foo10666(S10666 s1)
}
/***************************************************/
-// 11081
+// https://issues.dlang.org/show_bug.cgi?id=11081
T ifThrown11081(E : Throwable, T)(T delegate(E) errorHandler)
{
@@ -972,7 +973,7 @@ void test11081()
}
/***************************************************/
-// 11220
+// https://issues.dlang.org/show_bug.cgi?id=11220
int parsePrimaryExp11220(int x)
{
@@ -986,7 +987,7 @@ typeof(handler(1)) parseAmbig11220(alias handler)()
}
/***************************************************/
-// 11230
+// https://issues.dlang.org/show_bug.cgi?id=11230
template map11230(fun...)
{
@@ -1022,7 +1023,7 @@ C11230 visit11230()
}
/***************************************************/
-// 10336
+// https://issues.dlang.org/show_bug.cgi?id=10336
struct S10336
{
@@ -1041,7 +1042,7 @@ void test10336()
}
/***************************************************/
-// 10928
+// https://issues.dlang.org/show_bug.cgi?id=10928
struct D10928
{
@@ -1065,7 +1066,7 @@ void test10928()
}
/***************************************************/
-// 11661
+// https://issues.dlang.org/show_bug.cgi?id=11661
void test11661()
{
@@ -1074,7 +1075,7 @@ void test11661()
}
/***************************************************/
-// 11774
+// https://issues.dlang.org/show_bug.cgi?id=11774
void f11774(T, R)(R delegate(T[]) dg)
{
@@ -1091,7 +1092,7 @@ void test11774()
}
/***************************************************/
-// 12421
+// https://issues.dlang.org/show_bug.cgi?id=12421
void test12421()
{
@@ -1145,7 +1146,7 @@ void test12421()
}
/***************************************************/
-// 12508
+// https://issues.dlang.org/show_bug.cgi?id=12508
interface A12508(T)
{
@@ -1182,7 +1183,7 @@ void test12508()
}
/***************************************************/
-// 13879
+// https://issues.dlang.org/show_bug.cgi?id=13879
void test13879()
{
@@ -1194,7 +1195,7 @@ void test13879()
}
/***************************************************/
-// 14745
+// https://issues.dlang.org/show_bug.cgi?id=14745
void test14745()
{
@@ -1216,7 +1217,7 @@ void test14745()
}
/***************************************************/
-// 15794
+// https://issues.dlang.org/show_bug.cgi?id=15794
struct Foo15794
{
diff --git a/gcc/testsuite/gdc.test/runnable/functype.d b/gcc/testsuite/gdc.test/runnable/functype.d
index 7aa7efd..28e2709 100644
--- a/gcc/testsuite/gdc.test/runnable/functype.d
+++ b/gcc/testsuite/gdc.test/runnable/functype.d
@@ -183,7 +183,7 @@ void testxx()
}
/***************************************************/
-// 3646
+// https://issues.dlang.org/show_bug.cgi?id=3646
int bar3646(int x = 10) { printf("bar %d\n", x); return x; }
int bam3646(int y) { printf("bam %d\n", y); return y; }
@@ -215,7 +215,7 @@ void test3646()
}
/***************************************************/
-// 3866
+// https://issues.dlang.org/show_bug.cgi?id=3866
void test3866()
{
@@ -230,7 +230,7 @@ void test3866()
}
/***************************************************/
-// 8579
+// https://issues.dlang.org/show_bug.cgi?id=8579
void test8579()
{
@@ -254,7 +254,7 @@ void test8579()
}
/***************************************************/
-// 14210
+// https://issues.dlang.org/show_bug.cgi?id=14210
string foo14210a(DT)(string name, DT dg)
{
@@ -274,7 +274,7 @@ void test14210()
}
/***************************************************/
-// 10734
+// https://issues.dlang.org/show_bug.cgi?id=10734
// There's no platform independent export symbol, so
// test just only in Win32.
@@ -297,7 +297,7 @@ void test10734()
}
/***************************************************/
-// 14656
+// https://issues.dlang.org/show_bug.cgi?id=14656
void test14656()
{
diff --git a/gcc/testsuite/gdc.test/runnable/hello.d b/gcc/testsuite/gdc.test/runnable/hello.d
index 88adaa4..b46f59d 100644
--- a/gcc/testsuite/gdc.test/runnable/hello.d
+++ b/gcc/testsuite/gdc.test/runnable/hello.d
@@ -5,8 +5,8 @@ extern(C) int printf(const char*, ...);
int main(char[][] args)
{
printf("hello world\n");
- printf("args.length = %d\n", args.length);
+ printf("args.length = %zd\n", args.length);
for (int i = 0; i < args.length; i++)
- printf("args[%d] = '%.*s'\n", i, args[i].length, args[i].ptr);
+ printf("args[%d] = '%.*s'\n", i, cast(int)args[i].length, args[i].ptr);
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/helloUTF8.d b/gcc/testsuite/gdc.test/runnable/helloUTF8.d
index 78f3bcd..aed6613 100644
--- a/gcc/testsuite/gdc.test/runnable/helloUTF8.d
+++ b/gcc/testsuite/gdc.test/runnable/helloUTF8.d
@@ -1,4 +1,10 @@
-// PERMUTE_ARGS:
+/*
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+hello world
+---
+*/
extern(C) int printf(const char *, ...);
diff --git a/gcc/testsuite/gdc.test/runnable/ice15030.d b/gcc/testsuite/gdc.test/runnable/ice15030.d
index 5925e74..5c9587c 100644
--- a/gcc/testsuite/gdc.test/runnable/ice15030.d
+++ b/gcc/testsuite/gdc.test/runnable/ice15030.d
@@ -1,6 +1,7 @@
// REQUIRED_ARGS: -unittest -boundscheck=off
// PERMUTE_ARGS:
// EXTRA_SOURCES: imports/a15030.d imports/b15030.d
+// EXTRA_FILES: imports/std15030algo.d
void main() {}
diff --git a/gcc/testsuite/gdc.test/runnable/ice21696.d b/gcc/testsuite/gdc.test/runnable/ice21696.d
new file mode 100644
index 0000000..8b7a81e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/ice21696.d
@@ -0,0 +1,23 @@
+module ice21696;
+
+// https://issues.dlang.org/show_bug.cgi?id=21696
+
+double[1][1] func(double[1][1] stuff = [[1.0]])
+{
+ bool myFunc()
+ {
+ if (stuff[])
+ return true;
+ return false;
+ }
+
+ if (!myFunc())
+ assert(false);
+
+ return stuff;
+}
+
+int main()
+{
+ return func() != [[1.0]];
+}
diff --git a/gcc/testsuite/gdc.test/runnable/ice21727.d b/gcc/testsuite/gdc.test/runnable/ice21727.d
new file mode 100644
index 0000000..5b5745f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/ice21727.d
@@ -0,0 +1,46 @@
+// REQUIRED_ARGS: -m64 -O -inline
+// DISABLED: win32 linux32 freebsd32 osx32 netbsd32 dragonflybsd32
+// https://issues.dlang.org/show_bug.cgi?id=21727
+
+import core.simd;
+
+@nogc nothrow pure @safe:
+
+struct Float4
+{
+ float4 mVector;
+
+ pragma(inline, false) ref typeof(this) doubleInPlace() return
+ @nogc nothrow pure @safe
+ {
+ mVector = mVector + mVector;
+ return this;
+ }
+}
+
+pragma(inline, false) Float4 identity(Float4 a)
+{
+ return a;
+}
+
+pragma(inline, true) Float4 twoTimes(const ref Float4 a)
+{
+ version (D_SIMD)
+ return Float4(cast(float4) __simd(XMM.ADDPS, a.mVector, a.mVector));
+ else // Allow non-DMD compilers to compile this test.
+ return Float4(a.mVector + a.mVector);
+}
+
+pragma(inline, false) Float4 fourTimes(const Float4 a)
+{
+ auto x = identity(a);
+ auto y = x.doubleInPlace(); // This crashed in dmd.backend.cgxmm.xmmload.
+ auto z = twoTimes(y);
+ return z;
+}
+
+void main()
+{
+ const c = fourTimes(Float4([5,7,11,13]));
+ assert(c.mVector.array == [20, 28, 44, 52]);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/ifti.d b/gcc/testsuite/gdc.test/runnable/ifti.d
index 6d66975..0c94946c 100644
--- a/gcc/testsuite/gdc.test/runnable/ifti.d
+++ b/gcc/testsuite/gdc.test/runnable/ifti.d
@@ -1,27 +1,26 @@
-// RUNNABLE_PHOBOS_TEST
-import std.stdio;
+extern (C) int printf(const scope char*, ...);
struct S {
int x = 3;
- void fun(T)(T x) { writefln("S.fun(%s)(%s)",typeid(T),x); this.x += x; }
+ void fun(T)(T x) { printf("S.fun(%s)(%d)\n", T.stringof.ptr, x); this.x += x; }
}
class Tst(TST, int v = 2) {
int x = 3;
int z = 4;
- final private void proc(int x) { writefln("proc(%s) -> %s",x,this.x); }
- void fun(T)(T x) { writefln("fun(%s)(%s) -> %s",typeid(T),x,this.x);}
- void fun()() { writefln("fun()() -> %s",this.x); }
- void fun2()() { writefln("fun2"); }
+ final private void proc(int x) { printf("proc(%d) -> %d\n", x, this.x); }
+ void fun(T)(T x) { printf("fun(%s)(%d) -> %d\n", T.stringof.ptr, x, this.x);}
+ void fun()() { printf("fun()() -> %d\n", this.x); }
+ void fun2()() { printf("fun2\n"); }
class Inner {
int y = 99;
Tst outer;
void f3() { z = 55; }
// Make sure the correct this-ptr is used
- void f1() { writefln("Inner.f1"); proc(-11); outer.proc(-11); }
- void f2() { writefln("Inner.f2"); fun(-17); outer.fun(-17); }
+ void f1() { printf("Inner.f1\n"); proc(-11); outer.proc(-11); }
+ void f2() { printf("Inner.f2\n"); fun(-17); outer.fun(-17); }
}
Inner inner;
@@ -30,38 +29,36 @@ class Tst(TST, int v = 2) {
inner.outer = this;
}
- void callInnerf1() { writefln("callInnerf1"); inner.f1(); }
- void callInnerf2() { writefln("callInnerf2"); inner.f2(); }
+ void callInnerf1() { printf("callInnerf1\n"); inner.f1(); }
+ void callInnerf2() { printf("callInnerf2\n"); inner.f2(); }
//
- void opAdd(T)(T x) { this.x += x; writefln("opAdd(%s)",x); }
- void opPos()() { writefln("opPos()"); }
- //void opPos() { writefln("xxx"); }
- void opIndex(T)(T x) { writefln("opIndex[%s]",x); }
+ void opBinary(string op : "+", T)(T x) { this.x += x; printf("opAdd(%d)\n", x); }
+ void opUnary(string op : "+")() { printf("opPos()\n"); }
+ //void opPos() { printf("xxx"); }
+ void opIndex(T)(T x) { printf("opIndex[%d]\n",x); }
void opIndex(A,B,C)(A a, B b, C c) {
- writefln("opIndex[(%s)%s,(%s)%s,(%s)%s]",typeid(A),a,
- typeid(B),b,typeid(C),c);
+ printf("opIndex[(%s) %d, (%s) %d, (%s) %d]\n", A.stringof.ptr, a,
+ B.stringof.ptr,b,C.stringof.ptr,c);
}
-
static if (v > 1) {
- void opCall(A = int, B = float)(A a = 1, B b = 8.2) { writefln("opCall(%s,%s)",a,b); this.x++; }
-
+ void opCall(A = int, B = float)(A a = 1, B b = 8.2) { printf("opCall(%d, %d)\n",a,b); this.x++; }
}
- void opSlice(A,B)(A a, B b) { writefln("opSlice(%s,%s)",a,b); }
- void opSlice()() { writefln("opSlice()"); }
+ void opSlice(A,B)(A a, B b) { printf("opSlice(%d, %d)\n",a,b); }
+ void opSlice()() { printf("opSlice()\n"); }
void opIndexAssign(A,B)(A a, B b) {
- writefln("opIndexAssign((%s)%s,(%s)%s)",typeid(A),a,typeid(B),b);
+ printf("opIndexAssign((%s) %d, (%s) %d)\n", A.stringof.ptr, a, B.stringof.ptr, b);
}
void opSliceAssign(A,B,C)(A a, B b, C c) {
- writefln("opSliceAssign(%s,%s,%s)",a,b,c);
+ printf("opSliceAssign(%.s, %d, %d)\n", a.length, a.ptr, b, c);
}
- bool opEquals(A)(A x) { writefln("opEquals((%s))",typeid(A));return true; }
+ bool opEquals(A)(A x) { printf("opEquals((%s))\n", A.stringof.ptr); return true; }
int opApply(T)(int delegate(ref T)dg) {
for (int i = 0; i < 5; i++) {
@@ -103,8 +100,6 @@ void main() {
t[];
t[1..2];
u[1..2.5];
- t[1i] = 5;
- t[-4.5..7i] = "hello";
t == t;
auto b = t != t; // without assignment -> "! has no effect in expression"
t == u;
@@ -112,10 +107,10 @@ void main() {
u == u;
b = u != u;
foreach(int i;t) {
- writefln("%s",i);
+ printf("%d\n", i);
}
foreach(double i;t) {
- writefln("%s",i);
+ printf("%g\n", i);
}
}
diff --git a/gcc/testsuite/gdc.test/runnable/implicit.d b/gcc/testsuite/gdc.test/runnable/implicit.d
index 9170b04..75b992c 100644
--- a/gcc/testsuite/gdc.test/runnable/implicit.d
+++ b/gcc/testsuite/gdc.test/runnable/implicit.d
@@ -1,5 +1,17 @@
-// RUNNABLE_PHOBOS_TEST
-import std.stdio;
+/*
+TEST_OUTPUT:
+---
+runnable/implicit.d(162): Deprecation: slice of static array temporary returned by `pureMaker3c()` assigned to longer lived variable `z1`
+runnable/implicit.d(163): Deprecation: slice of static array temporary returned by `pureMaker3c()` assigned to longer lived variable `z2`
+---
+
+RUN_OUTPUT:
+---
+Success
+---
+*/
+
+import core.stdc.stdio;
/***********************************/
@@ -150,7 +162,8 @@ void testDIP29_3()
immutable z1 = pureMaker3c()[];
immutable z2 = pureMaker3c()[0..2];
- // Issue 12467 - conversion from lvalue of mutable static array to immutable slice
+ // https://issues.dlang.org/show_bug.cgi?id=12467
+ // conversion from lvalue of mutable static array to immutable slice
char[3] arr = "foo";
static assert(!__traits(compiles, { string str = arr[]; }));
}
@@ -182,11 +195,11 @@ void testDIP29_4()
}
/***********************************/
-// 14155
+// https://issues.dlang.org/show_bug.cgi?id=14155
immutable int g14155;
-static this() { g14155 = 1; }
+shared static this() { g14155 = 1; }
int* make14155m ( int* p) pure { return null; }
const(int*) make14155c ( const(int*) p) pure { return &g14155; }
@@ -232,7 +245,7 @@ void test14155_for_testDIP29_4()
}
/***********************************/
-// 14141
+// https://issues.dlang.org/show_bug.cgi?id=14141
struct S14141
{
@@ -265,7 +278,7 @@ int*[] pureFoo() pure { return null; }
void testDIP29_5() pure
{
- { char[] s; immutable x = s.dup; }
+ { char[] s; immutable x = s.idup; }
{ immutable x = (cast(int*[])null).dup; }
{ immutable x = pureFoo(); }
{ immutable x = pureFoo().dup; }
@@ -396,7 +409,7 @@ void testDIP29_6()
}));
}
-// 14155
+// https://issues.dlang.org/show_bug.cgi?id=14155
void test14155_for_testDIP29_6()
{
@@ -417,7 +430,7 @@ void test14155_for_testDIP29_6()
}
/***********************************/
-// 13640
+// https://issues.dlang.org/show_bug.cgi?id=13640
struct S13640
{
@@ -437,7 +450,7 @@ struct S13640
}
/***********************************/
-// 15778
+// https://issues.dlang.org/show_bug.cgi?id=15778
void test15778()
{
@@ -477,5 +490,5 @@ void main()
testDIP29_6();
test15778();
- writefln("Success");
+ printf("Success\n");
}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/A16a.d b/gcc/testsuite/gdc.test/runnable/imports/A16a.d
index 9f385cc..e60acdc 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/A16a.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/A16a.d
@@ -1,6 +1,6 @@
import A16;
-import std.stdio;
+import core.stdc.stdio;
class B16 : AA16
{
diff --git a/gcc/testsuite/gdc.test/runnable/imports/Other.d b/gcc/testsuite/gdc.test/runnable/imports/Other.d
index cd523c0..81d846f 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/Other.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/Other.d
@@ -2,13 +2,12 @@ module imports.Other; // makes no difference if removed
import Same;
import core.stdc.stdio;
-class Other : Same // segfault
-// class Other : Same.Same //***UGLY ALERT*** but doesn't segfault
+class Other : Same.Same
{
-this()
-{
-printf("other\n");
-}
+ this()
+ {
+ printf("other\n");
+ }
}
int main()
diff --git a/gcc/testsuite/gdc.test/runnable/imports/a12037.d b/gcc/testsuite/gdc.test/runnable/imports/a12037.d
index 7c25d87..3d6e456 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/a12037.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/a12037.d
@@ -19,29 +19,28 @@ private template CustomFloatParams(uint precision, uint exponentWidth)
) CustomFloatParams;
}
-struct CustomFloat(uint precision, uint exponentWidth)
-if ((1 + precision + exponentWidth) % 8 == 0 && precision + exponentWidth > 0)
+private union ToBinary(F)
+if (is(typeof(CustomFloatParams!(F.sizeof*8))) || is(F == real))
{
-private:
- union ToBinary(F)
- if (is(typeof(CustomFloatParams!(F.sizeof*8))) || is(F == real))
- {
- F set;
+ F set;
- // If on Linux or Mac, where 80-bit reals are padded, ignore the
- // padding.
- CustomFloat!(CustomFloatParams!(min(F.sizeof*8, 80))) get;
+ // If on Linux or Mac, where 80-bit reals are padded, ignore the
+ // padding.
+ CustomFloat!(CustomFloatParams!(min(F.sizeof*8, 80))) get;
- // Convert F to the correct binary type.
- static typeof(get) opCall(F value)
- {
- ToBinary r;
- r.set = value;
- return r.get;
- }
- alias get this;
+ // Convert F to the correct binary type.
+ static typeof(get) opCall(F value)
+ {
+ ToBinary r;
+ r.set = value;
+ return r.get;
}
+ alias get this;
+}
+struct CustomFloat(uint precision, uint exponentWidth)
+if ((1 + precision + exponentWidth) % 8 == 0 && precision + exponentWidth > 0)
+{
public:
@property bool sign() { return 1; }
@property void sign(bool) {}
@@ -65,7 +64,7 @@ public:
@property F get(F)()
if (is(F == float) || is(F == double) || is(F == real))
{
- ToBinary!F result;
+ ToBinary result;
return F.init;
}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/a21a.d b/gcc/testsuite/gdc.test/runnable/imports/a21a.d
index 8ba1462..ded47da 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/a21a.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/a21a.d
@@ -1,6 +1,6 @@
module imports.a21a;
-import std.stdio;
+import core.stdc.stdio;
import a21;
template GoodMixin()
diff --git a/gcc/testsuite/gdc.test/runnable/imports/another_module_with_tests.d b/gcc/testsuite/gdc.test/runnable/imports/another_module_with_tests.d
new file mode 100644
index 0000000..5329004
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/another_module_with_tests.d
@@ -0,0 +1,4 @@
+module imports.another_module_with_tests;
+unittest {}
+unittest {}
+unittest { assert(false); }
diff --git a/gcc/testsuite/gdc.test/runnable/imports/depsprot_default.d b/gcc/testsuite/gdc.test/runnable/imports/depsprot_default.d
deleted file mode 100644
index 2d5de35..0000000
--- a/gcc/testsuite/gdc.test/runnable/imports/depsprot_default.d
+++ /dev/null
@@ -1 +0,0 @@
-void pack() {}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/depsprot_private.d b/gcc/testsuite/gdc.test/runnable/imports/depsprot_private.d
deleted file mode 100644
index be063dd..0000000
--- a/gcc/testsuite/gdc.test/runnable/imports/depsprot_private.d
+++ /dev/null
@@ -1 +0,0 @@
-void priv() {}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/depsprot_public.d b/gcc/testsuite/gdc.test/runnable/imports/depsprot_public.d
deleted file mode 100644
index ad18eaf..0000000
--- a/gcc/testsuite/gdc.test/runnable/imports/depsprot_public.d
+++ /dev/null
@@ -1 +0,0 @@
-void pub() {}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/module_with_tests.d b/gcc/testsuite/gdc.test/runnable/imports/module_with_tests.d
new file mode 100644
index 0000000..c0372ab
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/module_with_tests.d
@@ -0,0 +1,2 @@
+module imports.module_with_tests;
+unittest {} unittest { assert(false); }
diff --git a/gcc/testsuite/gdc.test/runnable/imports/pubprivtmpla.d b/gcc/testsuite/gdc.test/runnable/imports/pubprivtmpla.d
new file mode 100644
index 0000000..f68bdd7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/pubprivtmpla.d
@@ -0,0 +1,8 @@
+module pubprivtmpla;
+
+struct S
+{
+ private int m = 42;
+ private int _get()() { return m; }
+ public alias get = _get!();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/std11file.d b/gcc/testsuite/gdc.test/runnable/imports/std11file.d
new file mode 100644
index 0000000..76d43be
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/std11file.d
@@ -0,0 +1,6 @@
+module imports.std11file;
+
+string getcwd() @trusted
+{
+ return "/dlang/test/runnable";
+}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/std15017variant.d b/gcc/testsuite/gdc.test/runnable/imports/std15017variant.d
index f6f7f5e..cf5dbf1 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/std15017variant.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/std15017variant.d
@@ -1,6 +1,6 @@
module imports.std15017variant;
-struct VariantN(size_t maxDataSize)
+struct VariantN(uint maxDataSize)
{
VariantN opAssign() { return this; }
diff --git a/gcc/testsuite/gdc.test/runnable/imports/template_ovs1.d b/gcc/testsuite/gdc.test/runnable/imports/template_ovs1.d
index a4b2ecf..465e74c 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/template_ovs1.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/template_ovs1.d
@@ -1,7 +1,8 @@
module imports.template_ovs1;
/***************************************************/
-// 1900 - template overload set
+// https://issues.dlang.org/show_bug.cgi?id=1900
+// template overload set
auto foo1900a(int num) { return 1; }
auto foo1900b(T)(T arg) if (is(T : const(char)[])) { return 2; }
@@ -34,7 +35,7 @@ auto merge1900(T)(int)
}
/***************************************************/
-// 1900
+// https://issues.dlang.org/show_bug.cgi?id=1900
class AClass1900 {}
template Traits1900(T : AClass1900) { enum name = "AClass"; }
@@ -47,12 +48,12 @@ template Value1900b(T) if (is(T == double)) { enum Value1900b = 1; }
void Value1900b() {}
/***************************************************/
-// 8352
+// https://issues.dlang.org/show_bug.cgi?id=8352
Range remove8352a(alias pred, Range)(Range range) { return range; }
void remove8352b(in char[] name) {}
/***************************************************/
-// 10658
+// https://issues.dlang.org/show_bug.cgi?id=10658
template Val10658(int n) { enum Val10658 = 1; }
diff --git a/gcc/testsuite/gdc.test/runnable/imports/template_ovs2.d b/gcc/testsuite/gdc.test/runnable/imports/template_ovs2.d
index 5b92568..1c9500c 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/template_ovs2.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/template_ovs2.d
@@ -1,7 +1,8 @@
module imports.template_ovs2;
/***************************************************/
-// 1900 - template overload set
+// https://issues.dlang.org/show_bug.cgi?id=1900
+// template overload set
auto foo1900a(T)(T arg) if (is(T : const(char)[])) { return 2; }
auto foo1900b(int num) { return 1; }
@@ -34,7 +35,7 @@ auto merge1900(T)(string)
}
/***************************************************/
-// 1900
+// https://issues.dlang.org/show_bug.cgi?id=1900
class BClass1900 {}
template Traits1900(T : BClass1900) { enum name = "BClass"; }
@@ -47,12 +48,12 @@ template Value1900b(T) if (is(T == string)) { enum Value1900b = 2; }
void Value1900b() {}
/***************************************************/
-// 8352
+// https://issues.dlang.org/show_bug.cgi?id=8352
void remove8352a(in char[] name) {}
Range remove8352b(alias pred, Range)(Range range) { return range; }
/***************************************************/
-// 10658
+// https://issues.dlang.org/show_bug.cgi?id=10658
template Val10658(long n) { enum Val10658 = 2; }
diff --git a/gcc/testsuite/gdc.test/runnable/imports/template_ovs3.d b/gcc/testsuite/gdc.test/runnable/imports/template_ovs3.d
index ca76914..75beeb9 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/template_ovs3.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/template_ovs3.d
@@ -1,7 +1,8 @@
module imports.template_ovs3;
/***************************************************/
-// 1900 - template overload set
+// https://issues.dlang.org/show_bug.cgi?id=1900
+// template overload set
import imports.template_ovs1;
import imports.template_ovs2;
@@ -31,6 +32,6 @@ struct S1900
}
/***************************************************/
-// 1900
+// https://issues.dlang.org/show_bug.cgi?id=1900
struct Traits1900(T) if (!is(T == class)) { enum name = "any"; }
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test11931a.d b/gcc/testsuite/gdc.test/runnable/imports/test11931a.d
index 152b38a..f43ac4f 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/test11931a.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/test11931a.d
@@ -1,7 +1,5 @@
module imports.test11931a;
-import std.stdio;
-
import imports.test11931d;
import imports.test11931b;
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test11931d.d b/gcc/testsuite/gdc.test/runnable/imports/test11931d.d
index 7a3ed39..dc9bbb1 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/test11931d.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/test11931d.d
@@ -1,7 +1,20 @@
module imports.test11931d;
-import std.array;
-import std.algorithm;
+template filter(alias pred)
+{
+ auto filter(Range)(Range r)
+ {
+ struct FilterResult
+ {
+ Range array()
+ {
+ return data;
+ }
+ Range data;
+ }
+ return FilterResult(r);
+ }
+}
struct ConnectionPoint
{
@@ -26,5 +39,5 @@ struct Signal(T, A...)
private:
alias D = T delegate(A);
- D _arr[];
+ D[] _arr;
}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test13a.d b/gcc/testsuite/gdc.test/runnable/imports/test13a.d
index 4b00277..4512e41 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/test13a.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/test13a.d
@@ -17,7 +17,7 @@ template Ordinal(T) {
public T clamp(T item, T lower, T upper)
in {
assert(lower <= upper);
- } body {
+ } do {
return max(min(item, upper), lower);
}
}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test15777a.d b/gcc/testsuite/gdc.test/runnable/imports/test15777a.d
new file mode 100644
index 0000000..55ae716
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test15777a.d
@@ -0,0 +1 @@
+void fun() {}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test15777b.d b/gcc/testsuite/gdc.test/runnable/imports/test15777b.d
new file mode 100644
index 0000000..55ae716
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test15777b.d
@@ -0,0 +1 @@
+void fun() {}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test17181a.d b/gcc/testsuite/gdc.test/runnable/imports/test17181a.d
new file mode 100644
index 0000000..c080e96
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test17181a.d
@@ -0,0 +1,10 @@
+module imports.test17181a;
+
+int a = 0;
+static this() { a = 1; }
+
+T abc(T)(T i)
+{
+ import imports.test17181b;
+ return i;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test17181b.d b/gcc/testsuite/gdc.test/runnable/imports/test17181b.d
new file mode 100644
index 0000000..25e6088
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test17181b.d
@@ -0,0 +1,3 @@
+module imports.test17181b;
+import imports.test17181a;
+static this() { a = 2; }
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test17181c.d b/gcc/testsuite/gdc.test/runnable/imports/test17181c.d
new file mode 100644
index 0000000..1722711
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test17181c.d
@@ -0,0 +1,7 @@
+module imports.test17181c;
+
+int getA()()
+{
+ import imports.test17181a;
+ return a;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test18868_a.d b/gcc/testsuite/gdc.test/runnable/imports/test18868_a.d
new file mode 100644
index 0000000..275cf22
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test18868_a.d
@@ -0,0 +1,3 @@
+shared static this() { }
+import imports.test18868_fls;
+alias floop = FLS!(int);
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test18868_fls.d b/gcc/testsuite/gdc.test/runnable/imports/test18868_fls.d
new file mode 100644
index 0000000..4714205
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test18868_fls.d
@@ -0,0 +1,33 @@
+module imports.test18868_fls;
+
+template FLS(T)
+{
+ int ctorcount = 0;
+ int dtorcount = 0;
+ int sharedctorcount = 0;
+ int shareddtorcount = 0;
+
+ static this()
+ {
+ assert(ctorcount == 0);
+ ctorcount += 1;
+ }
+
+ static ~this()
+ {
+ assert(dtorcount == 0);
+ dtorcount += 1;
+ }
+
+ shared static this()
+ {
+ assert(sharedctorcount == 0);
+ sharedctorcount += 1;
+ }
+
+ shared static ~this()
+ {
+ assert(shareddtorcount == 0);
+ shareddtorcount += 1;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test19655b.d b/gcc/testsuite/gdc.test/runnable/imports/test19655b.d
new file mode 100644
index 0000000..83d3c9d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test19655b.d
@@ -0,0 +1,8 @@
+import test19655c;
+import test19655d;
+class Garply: Grault
+{ }
+void main()
+{
+ (new Garply).func;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test19655c.d b/gcc/testsuite/gdc.test/runnable/imports/test19655c.d
new file mode 100644
index 0000000..f69b7d9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test19655c.d
@@ -0,0 +1,8 @@
+import test19655f;
+import test19655e;
+import test19655a: Corge;
+class Foo
+{
+ int[Foo] map;
+ void fun0(Corge) { }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test19655d.d b/gcc/testsuite/gdc.test/runnable/imports/test19655d.d
new file mode 100644
index 0000000..9928644
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test19655d.d
@@ -0,0 +1,14 @@
+import test19655f;
+import test19655g;
+class Grault: Bar
+{
+ void func()
+ {
+ func2;
+ }
+ void func1()
+ {
+ assert(false, "func1 was never called");
+ }
+ void func2() { }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test19655e.d b/gcc/testsuite/gdc.test/runnable/imports/test19655e.d
new file mode 100644
index 0000000..d497fff
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test19655e.d
@@ -0,0 +1,2 @@
+import test19655c;
+int[Foo] map;
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test19655f.d b/gcc/testsuite/gdc.test/runnable/imports/test19655f.d
new file mode 100644
index 0000000..32a58f8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test19655f.d
@@ -0,0 +1,2 @@
+import test19655c;
+import test19655g;
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test19655g.d b/gcc/testsuite/gdc.test/runnable/imports/test19655g.d
new file mode 100644
index 0000000..d1cacfe
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test19655g.d
@@ -0,0 +1,3 @@
+import test19655c;
+class Bar: Foo
+{ }
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test24a.d b/gcc/testsuite/gdc.test/runnable/imports/test24a.d
index e606f1c..d7ca719 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/test24a.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/test24a.d
@@ -1,3 +1,3 @@
module imports.test24a;
-public import std.string;
+public import imports.test24c;
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test24b.d b/gcc/testsuite/gdc.test/runnable/imports/test24b.d
index dcb380f..507a848 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/test24b.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/test24b.d
@@ -1,3 +1,3 @@
module imports.test24b;
-public import std.string;
+public import imports.test24c;
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test24c.d b/gcc/testsuite/gdc.test/runnable/imports/test24c.d
new file mode 100644
index 0000000..a6ffee0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test24c.d
@@ -0,0 +1,6 @@
+module imports.test24c;
+
+immutable(Char)[] format(Char, Args...)(in Char[] fmt, Args args)
+{
+ return "3";
+}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test27a.d b/gcc/testsuite/gdc.test/runnable/imports/test27a.d
index 75c945d..8a68a16 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/test27a.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/test27a.d
@@ -1,10 +1,17 @@
module imports.test27a;
-import std.variant;
+struct Variant
+{
+ this(T)(T)
+ {
+ }
+}
-class myClass(T) {
+class myClass(T)
+{
public:
- void func(T v) {
+ void func(T v)
+ {
Variant b = Variant(v);
}
}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test39a.d b/gcc/testsuite/gdc.test/runnable/imports/test39a.d
index 84a1530..4150eaf 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/test39a.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/test39a.d
@@ -6,7 +6,7 @@ class Test (T)
{
final void show (in T[] msg)
{
- printf ("%.*s\n", msg.length, msg.ptr);
+ printf ("%.*s\n", cast(int)msg.length, msg.ptr);
}
}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test40a.d b/gcc/testsuite/gdc.test/runnable/imports/test40a.d
index b688b9f..d894f45 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/test40a.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/test40a.d
@@ -1,6 +1,6 @@
module imports.test40a;
-import std.stdio;
+import core.stdc.stdio;
template Mix()
{
@@ -8,7 +8,7 @@ template Mix()
{
auto context = new Context;
auto ts = context.toString;
- printf("context: %.*s %p\n", ts.length, ts.ptr, context);
+ printf("context: %.*s %p\n", cast(int)ts.length, ts.ptr, context);
context.func!(typeof(this))();
printf("returning from opCall\n");
}
@@ -23,8 +23,8 @@ class Bar
void someFunc(string z)
{
- printf("str length: %d\n", z.length);
- printf("str: '%.*s'\n", z.length, z.ptr);
+ printf("str length: %zd\n", z.length);
+ printf("str: '%.*s'\n", cast(int)z.length, z.ptr);
}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test45a.d b/gcc/testsuite/gdc.test/runnable/imports/test45a.d
index df3b852..d466cbe 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/test45a.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/test45a.d
@@ -1,6 +1,6 @@
module imports.test45a;
-import std.stdio;
+import core.stdc.stdio;
int foo()
{
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test45b.d b/gcc/testsuite/gdc.test/runnable/imports/test45b.d
index 371a162..d1b0c34 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/test45b.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/test45b.d
@@ -1,6 +1,6 @@
module imports.test45b;
-import std.stdio;
+import core.stdc.stdio;
int foo(int i)
{
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test49a.d b/gcc/testsuite/gdc.test/runnable/imports/test49a.d
index 57baf4b..cb9c952 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/test49a.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/test49a.d
@@ -1,6 +1,6 @@
module imports.test49a;
-import std.stdio;
+import core.stdc.stdio;
int x;
diff --git a/gcc/testsuite/gdc.test/runnable/imports/testmod2a.d b/gcc/testsuite/gdc.test/runnable/imports/testmod2a.d
index a59d12c..a715811 100644
--- a/gcc/testsuite/gdc.test/runnable/imports/testmod2a.d
+++ b/gcc/testsuite/gdc.test/runnable/imports/testmod2a.d
@@ -1,7 +1,7 @@
module imports.testmod2a;
/**********************************/
-// bug 1904
+// https://issues.dlang.org/show_bug.cgi?id=1904
// testmod.d
private void bar(alias a)() {}
diff --git a/gcc/testsuite/gdc.test/runnable/inclusive_incontracts.d b/gcc/testsuite/gdc.test/runnable/inclusive_incontracts.d
new file mode 100644
index 0000000..7670b24
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/inclusive_incontracts.d
@@ -0,0 +1,80 @@
+// REQUIRED_ARGS: -preview=inclusiveincontracts
+// PERMUTE_ARGS: -O -inline
+
+import core.exception : AssertError;
+
+void main()
+{
+ basic_test;
+ multiple_incontracts_test;
+}
+
+void basic_test()
+{
+ class A
+ {
+ void foo() @nogc
+ in (true, "foo")
+ {
+ }
+ }
+
+ class B : A
+ {
+ override void foo() @nogc
+ in (false, "nope not foo")
+ {
+ }
+ }
+
+ auto b = new B;
+
+ try
+ {
+ b.foo;
+ throw new Exception("Assert expected.");
+ }
+ catch (AssertError assertError)
+ {
+ assert(assertError.line == 25); // line of invalid in-contract
+ assert(assertError.msg == "Logic error: in-contract was tighter than parent in-contract");
+ }
+}
+
+void multiple_incontracts_test()
+{
+ class A
+ {
+ void foo(int a, int b)
+ in (a > 0, "A::a")
+ in (b > 0, "B::b")
+ {
+ }
+ }
+
+ class B : A
+ {
+ override void foo(int a, int b)
+ in (a >= 0, "B::a")
+ in (b > 0, "B::b")
+ {
+ }
+ }
+
+ auto b = new B;
+
+ b.foo(0, 2);
+ try
+ {
+ b.foo(0, 0);
+ throw new Exception("Assert expected.");
+ }
+ catch (AssertError assertError) {
+ /**
+ * Having found that the looser contract in B is not fulfilled, we try
+ * the stricter contract in A. As that one is also violated, we error.
+ */
+ assert(assertError.line == 49);
+ assert(assertError.msg == "A::a");
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/inline.d b/gcc/testsuite/gdc.test/runnable/inline.d
index d3bb0a9..19be479 100644
--- a/gcc/testsuite/gdc.test/runnable/inline.d
+++ b/gcc/testsuite/gdc.test/runnable/inline.d
@@ -1,3 +1,14 @@
+/*
+RUN_OUTPUT:
+---
+7
+83
+4
+4
+1.000000 2.000000 3.000000
+Success
+---
+*/
import core.stdc.stdio;
@@ -145,7 +156,7 @@ void test7()
/************************************/
-// 10833
+// https://issues.dlang.org/show_bug.cgi?id=10833
string fun10833(T...)()
{
foreach (v ; T)
@@ -159,7 +170,7 @@ void test10833()
}
/************************************/
-// Bugzilla 4825
+// https://issues.dlang.org/show_bug.cgi?id=4825
int a8() {
int r;
@@ -178,7 +189,7 @@ void test8() {
}
/************************************/
-// 4841
+// https://issues.dlang.org/show_bug.cgi?id=4841
auto fun4841a()
{
@@ -264,7 +275,7 @@ void test4841()
}
/************************************/
-// 7261
+// https://issues.dlang.org/show_bug.cgi?id=7261
struct AbstractTask
{
@@ -287,7 +298,7 @@ struct Task
}
/************************************/
-// 9356
+// https://issues.dlang.org/show_bug.cgi?id=9356
void test9356()
{
@@ -302,7 +313,7 @@ void test9356()
}
/************************************/
-// 12079
+// https://issues.dlang.org/show_bug.cgi?id=12079
void test12079()
{
@@ -312,7 +323,7 @@ void test12079()
}
/************************************/
-// 12243
+// https://issues.dlang.org/show_bug.cgi?id=12243
char f12243() { return 'a'; }
@@ -323,7 +334,7 @@ void test12243()
}
/************************************/
-// 11201
+// https://issues.dlang.org/show_bug.cgi?id=11201
struct Foo11201
{
@@ -343,7 +354,7 @@ void test11201()
}
/************************************/
-// 11223
+// https://issues.dlang.org/show_bug.cgi?id=11223
struct Tuple11223(T...)
{
@@ -382,7 +393,7 @@ void test3918()
}
/************************************/
-// 11314
+// https://issues.dlang.org/show_bug.cgi?id=11314
struct Tuple11314(T...)
{
@@ -406,7 +417,7 @@ void test11314()
}
/************************************/
-// 11224
+// https://issues.dlang.org/show_bug.cgi?id=11224
S11224* ptr11224;
@@ -438,7 +449,7 @@ void test11224()
}
/************************************/
-// 11322
+// https://issues.dlang.org/show_bug.cgi?id=11322
bool b11322;
uint n11322;
@@ -460,7 +471,7 @@ void test11322()
}
/************************************/
-// 11394
+// https://issues.dlang.org/show_bug.cgi?id=11394
debug(NRVO) static void* p11394a, p11394b, p11394c;
@@ -497,7 +508,7 @@ void test11394()
}
/**********************************/
-// 12080
+// https://issues.dlang.org/show_bug.cgi?id=12080
class TZ12080 {}
@@ -521,7 +532,7 @@ class Foo12080
public ST12080 sysTime()
out {}
- body
+ do
{
if (quux)
return ST12080();
@@ -533,7 +544,7 @@ class Foo12080
}
/**********************************/
-// 13503
+// https://issues.dlang.org/show_bug.cgi?id=13503
void f13503a(string[] s...)
{
@@ -559,7 +570,7 @@ void test13503()
}
/**********************************/
-// 14267
+// https://issues.dlang.org/show_bug.cgi?id=14267
// EXTRA_SOURCES: imports/a14267.d
import imports.a14267;
@@ -584,7 +595,7 @@ void test14267()
}
/**********************************/
-// 13244
+// https://issues.dlang.org/show_bug.cgi?id=13244
struct MapResult13244(alias fun)
{
@@ -610,7 +621,7 @@ void test13244()
}
/**********************************/
-// 14306
+// https://issues.dlang.org/show_bug.cgi?id=14306
struct MapResult(alias fun)
{
@@ -656,7 +667,7 @@ void test14306()
}
/**********************************/
-// 14754
+// https://issues.dlang.org/show_bug.cgi?id=14754
auto aafunc14754(string k)
{
@@ -694,7 +705,7 @@ void test14754()
}
/**********************************/
-// 14606
+// https://issues.dlang.org/show_bug.cgi?id=14606
struct S14606
{
@@ -729,7 +740,7 @@ void test14606()
}
/**********************************/
-// 14753
+// https://issues.dlang.org/show_bug.cgi?id=14753
pragma(inline)
void test14753(string) { }
@@ -754,7 +765,7 @@ void test14975()
}
/**********************************/
-// 15210
+// https://issues.dlang.org/show_bug.cgi?id=15210
struct BigInt15210 {}
@@ -809,7 +820,7 @@ void test7625()
}
/**********************************/
-// 9785 partial fix
+// https://issues.dlang.org/show_bug.cgi?id=9785 partial fix
void test9785()
{
@@ -829,7 +840,7 @@ void test9785()
/**********************************/
-// 9785 partial fix
+// https://issues.dlang.org/show_bug.cgi?id=9785 partial fix
void test9785_2() {
int j = 3;
@@ -849,7 +860,7 @@ void test9785_2() {
}
/**********************************/
-// 9785 partial fix
+// https://issues.dlang.org/show_bug.cgi?id=9785 partial fix
void test9785_3() @nogc
{
@@ -879,7 +890,7 @@ void test9785_3() @nogc
}
/**********************************/
-// 15207
+// https://issues.dlang.org/show_bug.cgi?id=15207
struct Vec15207
{
@@ -923,7 +934,7 @@ void test15207()
}
/**********************************/
-// 15253
+// https://issues.dlang.org/show_bug.cgi?id=15253
struct MessageType15253
{
@@ -946,7 +957,7 @@ struct ProtoPackage15253
}
/**********************************/
-// 15296
+// https://issues.dlang.org/show_bug.cgi?id=15296
static int x15296;
@@ -1132,7 +1143,7 @@ int main()
test15296b();
test15296c();
test17676();
-
+
printf("Success\n");
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/inner.d b/gcc/testsuite/gdc.test/runnable/inner.d
index e1be7b9..7bf59d2 100644
--- a/gcc/testsuite/gdc.test/runnable/inner.d
+++ b/gcc/testsuite/gdc.test/runnable/inner.d
@@ -1,5 +1,5 @@
-// RUNNABLE_PHOBOS_TEST
-import std.stdio;
+
+import core.stdc.stdio;
/*******************************************************/
@@ -591,7 +591,7 @@ class Foo18
{
void doSayHello()
{
- writefln("Betty");
+ printf("Betty\n");
sayHello();
}
}
@@ -599,7 +599,7 @@ class Foo18
void sayHello()
{
- writefln("Hello");
+ printf("Hello\n");
}
}
@@ -614,7 +614,7 @@ class Foo182 : Foo18
void test18()
{
Foo182 foo = new Foo182();
- writefln("This should print Hello:");
+ printf("This should print Hello:\n");
foo.bar.doSayHello();
}
@@ -627,7 +627,7 @@ class Foo19
{
void doSayHello()
{
- writefln("Betty");
+ printf("Betty\n");
sayHello();
}
}
@@ -635,7 +635,7 @@ class Foo19
void sayHello()
{
- writefln("Hello");
+ printf("Hello\n");
}
this()
@@ -651,7 +651,7 @@ class Foo192 : Foo19
void test19()
{
Foo192 foo = new Foo192();
- writefln("This should print Hello:");
+ printf("This should print Hello:\n");
foo.bar.doSayHello();
}
@@ -796,7 +796,7 @@ struct S7426
}
/*******************************************************/
-// 14046
+// https://issues.dlang.org/show_bug.cgi?id=14046
class A14046
{
@@ -828,7 +828,7 @@ void test14046()
}
/*******************************************************/
-// 15839
+// https://issues.dlang.org/show_bug.cgi?id=15839
class AnimatedProgress15839(bool makeClosure)
{
diff --git a/gcc/testsuite/gdc.test/runnable/interface.d b/gcc/testsuite/gdc.test/runnable/interface.d
index dab7beb..78a712e 100644
--- a/gcc/testsuite/gdc.test/runnable/interface.d
+++ b/gcc/testsuite/gdc.test/runnable/interface.d
@@ -1,3 +1,10 @@
+/*
+TEST_OUTPUT:
+---
+runnable/interface.d(41): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+runnable/interface.d(55): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+---
+*/
import core.stdc.stdio;
@@ -79,7 +86,7 @@ void test3()
j.f();
K3 k = a;
k.f();
- assert(&j.f == &k.f); // Bugzilla 3706
+ assert(&j.f == &k.f); // https://issues.dlang.org/show_bug.cgi?id=3706
}
/*******************************************/
diff --git a/gcc/testsuite/gdc.test/runnable/interface2.d b/gcc/testsuite/gdc.test/runnable/interface2.d
index 85adf65..328f839 100644
--- a/gcc/testsuite/gdc.test/runnable/interface2.d
+++ b/gcc/testsuite/gdc.test/runnable/interface2.d
@@ -1,4 +1,11 @@
// PERMUTE_ARGS:
+/*
+TEST_OUTPUT:
+---
+runnable/interface2.d(47): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+runnable/interface2.d(98): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+---
+*/
extern(C) int printf(const char*, ...);
@@ -27,7 +34,7 @@ void test1()
printf("f = %p\n", f);
assert(cast(void*)b !is cast(void*)f);
- printf("f.class = '%.*s'\n", f.classinfo.name.length, f.classinfo.name.ptr);
+ printf("f.class = '%.*s'\n", cast(int)f.classinfo.name.length, f.classinfo.name.ptr);
assert(f.classinfo.name == "interface2.Foo");
f.bar();
@@ -341,7 +348,7 @@ class B12 : A12
{
printf("B12.clone()\n");
}
- body
+ do
{
return ia;
}
@@ -395,7 +402,7 @@ class B13 : A13
{
printf("B13.clone()\n");
}
- body { return ia; }
+ do { return ia; }
}
void test13()
@@ -662,11 +669,11 @@ void test19()
assert(cast(void*)c + (3*(void*).sizeof) == cast(void*)ifoo);
string s = ifoo.classinfo.name;
- printf("%.*s\n", s.length, s.ptr);
+ printf("%.*s\n", cast(int)s.length, s.ptr);
assert(s == "interface2.IFoo19");
s = (cast(Object)ifoo).toString;
- printf("%.*s\n", s.length, s.ptr);
+ printf("%.*s\n", cast(int)s.length, s.ptr);
assert(s == "interface2.Child19");
}
@@ -923,7 +930,8 @@ void test27()
}
/*******************************************************/
-// 1747 & 2013
+// https://issues.dlang.org/show_bug.cgi?id=1747
+// https://issues.dlang.org/show_bug.cgi?id=2013
void test1747()
{
@@ -1009,14 +1017,14 @@ bool foo4088(Test4088 x, Test4088 y)
}
/*******************************************************/
-// 7950
+// https://issues.dlang.org/show_bug.cgi?id=7950
template TypeTuple7950(T...){alias T TypeTuple7950;}
interface I7950a {} // ok
interface I7950b : I7950a, TypeTuple7950!() {} // fail
/*******************************************************/
-// 10007
+// https://issues.dlang.org/show_bug.cgi?id=10007
struct A10007 {}
@@ -1032,7 +1040,7 @@ class Foo10007 : IFoo10007
}
/*******************************************************/
-// 10744
+// https://issues.dlang.org/show_bug.cgi?id=10744
interface A10744
{
@@ -1065,7 +1073,7 @@ interface Baz10744 { }
interface Qux10744 : Baz10744 { }
/*******************************************************/
-// 11034
+// https://issues.dlang.org/show_bug.cgi?id=11034
class A11034(T)
{
diff --git a/gcc/testsuite/gdc.test/runnable/interface3.d b/gcc/testsuite/gdc.test/runnable/interface3.d
index f748f72..f0de22c 100644
--- a/gcc/testsuite/gdc.test/runnable/interface3.d
+++ b/gcc/testsuite/gdc.test/runnable/interface3.d
@@ -1,4 +1,10 @@
-// PERMUTE_ARGS:
+/*
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+OK
+---
+*/
extern(C) int printf(const char*, ...);
@@ -71,5 +77,3 @@ int main()
assert(Newline.OKset == 1);
return 0;
}
-
-
diff --git a/gcc/testsuite/gdc.test/runnable/interpret.d b/gcc/testsuite/gdc.test/runnable/interpret.d
index fe44744..a626749 100644
--- a/gcc/testsuite/gdc.test/runnable/interpret.d
+++ b/gcc/testsuite/gdc.test/runnable/interpret.d
@@ -1,4 +1,4 @@
-/* RUNNABLE_PHOBOS_TEST
+/*
TEST_OUTPUT:
---
true
@@ -17,7 +17,8 @@ tfoo
Crash!
---
*/
-import std.stdio;
+
+import core.stdc.stdio;
template Tuple(A...)
{
@@ -813,7 +814,7 @@ void test36()
string someCompileTimeFunction()
{
- return "writefln(\"Wowza!\");";
+ return "printf(\"Wowza!\n\");";
}
void test37()
@@ -871,7 +872,6 @@ string UpToSpace(string x)
void test40()
{
const y = UpToSpace("first space was after first");
- writeln(y);
assert(y == "first");
}
@@ -893,7 +893,6 @@ int foo41(int i)
void test41()
{
const y = foo41(3);
- writeln(y);
assert(y == 6);
}
@@ -915,7 +914,6 @@ int foo42(int i)
void test42()
{
const y = foo42(3);
- writeln(y);
assert(y == 6);
}
@@ -937,7 +935,6 @@ int bar(string a)
void test43()
{
const int foo = bar("a b c d");
- writeln(foo);
assert(foo == 28);
}
@@ -963,11 +960,11 @@ void test45()
/************************************************/
-const int foo46[5] = [0,1,2,3,4];
+const int[5] foo46 = [0,1,2,3,4];
void test46()
{
- writeln(eval!(foo46[3]));
+ printf("%d\n", eval!(foo46[3]));
}
/************************************************/
@@ -1017,7 +1014,6 @@ dstring testd49(dstring input)
void test49()
{
static x = testd49("hello");
- writeln(x);
assert(x == "el");
}
@@ -1126,26 +1122,29 @@ bool equals54(string a, string b)
/************************************************/
-const string foo55[2] = ["a", "b"];
+const string[2] foo55 = ["a", "b"];
string retsth55(int i) { return foo55[i]; }
void test55()
{
- writeln(eval!(foo55[0]));
- writeln(eval!(retsth55(0)));
+ enum res1 = eval!(foo55[0]);
+ printf("%.*s\n", cast(int)res1.length, res1.ptr);
+ enum res2 = eval!(retsth55(0));
+ printf("%.*s\n", cast(int)res2.length, res2.ptr);
}
/************************************************/
string retsth56(int i)
{
- static const string foo[2] = ["a", "b"];
+ static const string[2] foo = ["a", "b"];
return foo[i];
}
void test56()
{
- writeln(eval!(retsth56(0)));
+ enum result = eval!(retsth56(0));
+ printf("%.*s\n", cast(int)result.length, result.ptr);
}
/************************************************/
@@ -1178,7 +1177,6 @@ void test58()
assert(b.length == 2);
assert(b[0] == 2);
assert(b[1] == 3);
- writeln(b);
}
/************************************************/
@@ -1622,7 +1620,6 @@ const string s83 = mixItemList83();
void test83()
{
- writeln(s83);
assert(s83 == "item");
}
@@ -1813,7 +1810,7 @@ string foo90(string a, string b)
void test90()
{
static const string xxx = foo90("A", "xxx");
- printf("%.*s\n", xxx.length, xxx.ptr);
+ printf("%.*s\n", cast(int)xxx.length, xxx.ptr);
assert(xxx == "A");
}
@@ -2199,12 +2196,12 @@ struct Q
{
int x;
char y;
- int opAddAssign(int w)
+ int opOpAssign(string op)(int w) if (op == "+")
{
x += w;
return x + w;
}
- Q opSubAssign(int w)
+ Q opOpAssign(string op)(int w) if (op == "-")
{
x -= w;
version(D_Version2) { mixin("return this;"); } else { mixin("return *this;"); }
@@ -2300,7 +2297,7 @@ static assert(memtest8() == 6 + 17);
// --------- CTFE REF PASSING TESTS --------
-// Bugzilla 1950 - CTFE doesn't work correctly for structs passed by ref
+// https://issues.dlang.org/show_bug.cgi?id=1950 - CTFE doesn't work correctly for structs passed by ref
struct S1950
{
int x;
@@ -2412,7 +2409,8 @@ int nested2(int x)
static assert(nested2(7) == 17 + 8 + 10);
-// 1605 D1 & D2. break in switch with goto breaks in ctfe
+// https://issues.dlang.org/show_bug.cgi?id=1605
+// D1 & D2. break in switch with goto breaks in ctfe
int bug1605()
{
int i = 0;
@@ -2430,7 +2428,8 @@ int bug1605()
static assert(bug1605() == 27);
-// 2564. D2 only. CTFE: the index in a tuple foreach is uninitialized (bogus error)
+// https://issues.dlang.org/show_bug.cgi?id=2564
+// D2 only. CTFE: the index in a tuple foreach is uninitialized (bogus error)
// NOTE: Beware of optimizer bug 3264.
int bug2564()
@@ -2444,7 +2443,8 @@ int bug2564()
static int bug2564b = bug2564();
-// 1461 D1 + D2. Local variable as template alias parameter breaks CTFE
+// https://issues.dlang.org/show_bug.cgi?id=1461
+// D1 + D2. Local variable as template alias parameter breaks CTFE
void bug1461()
{
int x;
@@ -2620,7 +2620,7 @@ int delegtest6()
{
DelegStruct s;
s.a = 5;
- FoolishStruct k[3];
+ FoolishStruct[3] k;
DelegType u = &s.bar;
k[1].z = u;
return k[1].z(3);
@@ -2655,8 +2655,9 @@ static assert(lazyTest2(17) == 18);
version(D_Version2)
{
-// Bug 4020 and 4027 are D2 only
-
+// https://issues.dlang.org/show_bug.cgi?id=4020
+// https://issues.dlang.org/show_bug.cgi?id=4027
+// D2 only
struct PostblitCrash
{
int x;
@@ -2814,7 +2815,7 @@ void bug4257b()
}
/************************************************/
-// 5117
+// https://issues.dlang.org/show_bug.cgi?id=5117
static int dummy5117 = test5117();
@@ -2853,7 +2854,7 @@ int test5117b()
assert(s.value == 1); // fails, value == 0
return 0;
}
-ref S5117b getRef5117b(ref S5117b s) { return s; }
+ref S5117b getRef5117b(return ref S5117b s) { return s; }
struct S5117b
{
@@ -2862,7 +2863,7 @@ struct S5117b
}
/************************************************/
-// 6439
+// https://issues.dlang.org/show_bug.cgi?id=6439
struct A6439
{
@@ -2902,7 +2903,7 @@ static assert(!is(typeof(Compileable!(
}(3)
))));
-// 6504 regression
+// https://issues.dlang.org/show_bug.cgi?id=6504 regression
void test6504()
{
for (int i = 0; i < 3; ++i)
@@ -2913,7 +2914,7 @@ void test6504()
}
}
-// 8818 regression
+// https://issues.dlang.org/show_bug.cgi?id=8818 regression
void test8818()
{
static bool test()
@@ -3148,7 +3149,7 @@ void test108()
}
*/
-/***** Bug 5678 *********************************/
+/***** https://issues.dlang.org/show_bug.cgi?id=5678 *****/
/*
struct Bug5678
@@ -3185,7 +3186,7 @@ struct Test110s { this(int, int, int){} }
auto test110 = [Test110f(1, Test110s(1, 2, 3))];
/************************************************/
-// 6907
+// https://issues.dlang.org/show_bug.cgi?id=6907
int test6907()
{
@@ -3219,7 +3220,7 @@ int test6907()
static assert(test6907());
/************************************************/
-// 9023
+// https://issues.dlang.org/show_bug.cgi?id=9023
bool test9023()
{
@@ -3244,7 +3245,7 @@ bool test9023()
static assert(test9023());
/************************************************/
-// 15817
+// https://issues.dlang.org/show_bug.cgi?id=15817
S[] split15817(S)(S s)
{
@@ -3292,11 +3293,11 @@ void test9954()
}
/************************************************/
-// 10483
+// https://issues.dlang.org/show_bug.cgi?id=10483
struct Bug10483
{
- int val[3][4];
+ int[3][4] val;
}
struct Outer10483
@@ -3340,7 +3341,7 @@ void test112()
}
/************************************************/
-// 10687
+// https://issues.dlang.org/show_bug.cgi?id=10687
enum Foo10687 : uint { A, B, C, D, E }
immutable uint[5][] m10687 = [[0, 1, 2, 3, 4]];
@@ -3363,7 +3364,6 @@ void test113()
static void compare(real a, real b)
{
- writefln("compare(%30.30f, %30.30f);", a, b);
assert(fabs(a - b) < 128 * real.epsilon);
}
@@ -3399,7 +3399,7 @@ void test113()
}
/************************************************/
-// 14140
+// https://issues.dlang.org/show_bug.cgi?id=14140
struct S14140
{
@@ -3442,7 +3442,7 @@ void test14140()
}
/************************************************/
-// 14862
+// https://issues.dlang.org/show_bug.cgi?id=14862
struct S14862
{
@@ -3470,7 +3470,7 @@ void test14862()
}
/************************************************/
-// 15681
+// https://issues.dlang.org/show_bug.cgi?id=15681
void test15681()
{
@@ -3544,6 +3544,68 @@ void testToPrec()
/************************************************/
+auto test20366()
+{
+ const(char)[] s = ['h', 'e', 'l', '\xef', '\xbd', '\x8c', 'o'];
+
+ foreach_reverse (dchar c; s)
+ {
+ }
+
+ return true;
+}
+static assert(test20366());
+
+/************************************************/
+
+bool test20400()
+{
+ char[] s = cast(char[])"1234";
+ char[] ret = s[2 .. $];
+ ret.length += 1;
+ ret[$-1] = '5';
+ assert(ret == "345");
+
+ return true;
+}
+static assert(test20400());
+
+/************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=21878
+
+struct A21878
+{
+ int i;
+ ref inout(int) opIndex(size_t idx) inout return { return i; }
+}
+
+struct B21878
+{
+ A21878[1] a;
+ ref inout(int) opIndex(size_t idx) inout return { return a[0][idx]; }
+}
+
+bool ctfeFunc21878()
+{
+ A21878 a;
+ a[0] = 42;
+ assert(a[0] == 42); // OK
+
+ B21878 b;
+ b[0] = 42;
+ assert(b[0] == 42); // OK <- fails
+
+ return true;
+}
+
+void test21878()
+{
+ enum eval = ctfeFunc21878();
+ ctfeFunc21878(); // succeeds at runtime
+}
+
+/************************************************/
+
int main()
{
test1();
@@ -3667,6 +3729,9 @@ int main()
test14140();
test14862();
test15681();
+ test20366();
+ test20400();
+ test21878();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/interpret2.d b/gcc/testsuite/gdc.test/runnable/interpret2.d
index 38242a7..77bc25c 100644
--- a/gcc/testsuite/gdc.test/runnable/interpret2.d
+++ b/gcc/testsuite/gdc.test/runnable/interpret2.d
@@ -1,5 +1,11 @@
-
-//import std.stdio;
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
+
+//import core.stdc.stdio;
extern(C) int printf(const char*, ...);
template Tuple(A...)
@@ -52,7 +58,7 @@ void test1()
assert(z1 == 8194);
}
-/***** Bug 2850 *********************************/
+/***** https://issues.dlang.org/show_bug.cgi?id=2850 *****/
/* These tests are not passing, and shouldn't pass. A non-first field in a union
being initialized cannot be converted to an expression, at least not until there are
@@ -122,11 +128,11 @@ void test2()
}
}
-/***** Bug 3779 *********************************/
+/***** https://issues.dlang.org/show_bug.cgi?id=3779 *****/
static const bug3779 = ["123"][0][$-1];
-/***** Bug 1880 *********************************/
+/***** https://issues.dlang.org/show_bug.cgi?id=1880 *****/
enum Property1880 {First=1,Second=2}
diff --git a/gcc/testsuite/gdc.test/runnable/issue16995.d b/gcc/testsuite/gdc.test/runnable/issue16995.d
new file mode 100644
index 0000000..3b028d4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/issue16995.d
@@ -0,0 +1,42 @@
+// REQUIRED_ARGS: -unittest
+// COMPILE_SEPARATELY
+// EXTRA_SOURCES: imports/module_with_tests.d imports/another_module_with_tests.d
+
+import imports.module_with_tests;
+import imports.another_module_with_tests;
+import core.exception: AssertError;
+
+shared static this()
+{
+ import core.runtime: Runtime, UnitTestResult;
+ Runtime.extendedModuleUnitTester = () => UnitTestResult.pass;
+}
+
+void main()
+{
+ foreach(i, ut; __traits(getUnitTests, imports.module_with_tests))
+ {
+ try
+ {
+ ut();
+ assert(i == 0, "2nd unittest should fail");
+ }
+ catch(AssertError e)
+ {
+ assert(i == 1, "Only 2nd unittest should fail");
+ }
+ }
+
+ foreach(i, ut; __traits(getUnitTests, imports.another_module_with_tests))
+ {
+ try
+ {
+ ut();
+ assert(i == 0 || i == 1, "3rd unittest should fail");
+ }
+ catch(AssertError e)
+ {
+ assert(i == 2, "Only 3rd unittest should fail");
+ }
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/issue8671.d b/gcc/testsuite/gdc.test/runnable/issue8671.d
deleted file mode 100644
index c28e63b..0000000
--- a/gcc/testsuite/gdc.test/runnable/issue8671.d
+++ /dev/null
@@ -1,6 +0,0 @@
-// RUNNABLE_PHOBOS_TEST
-import std.random;
-void main()
-{
- double t = 1.0 - uniform(0.0, 1.0);
-}
diff --git a/gcc/testsuite/gdc.test/runnable/lazy.d b/gcc/testsuite/gdc.test/runnable/lazy.d
index c184619..0bd8f96 100644
--- a/gcc/testsuite/gdc.test/runnable/lazy.d
+++ b/gcc/testsuite/gdc.test/runnable/lazy.d
@@ -1,6 +1,5 @@
-// RUNNABLE_PHOBOS_TEST
import core.vararg;
-import std.stdio;
+import core.stdc.stdio;
/*********************************************************/
@@ -105,9 +104,14 @@ void bar3(...)
assert(va_arg!int(_argptr) == 14);
}
+void arr3(...)
+{
+ assert(_arguments.length == 1);
+ assert(va_arg!(int[])(_argptr) == [1,0,0,0,0,0,0,0,0,9]);
+}
+
void abc3(int* p)
{
- writeln(*p);
assert(*p == 3);
}
@@ -115,15 +119,13 @@ void test3()
{
int x = 3;
dotimes3(10, abc3(&x));
- dotimes3(10, write(++x));
- writeln();
+ dotimes3(10, ++x);
dotimes3(1, bar3(++x));
int[10] a = new int[10];
a[0] = 1;
a[$ - 1] = 9;
- dotimes3(3, write(a[0..$]));
- writeln();
+ dotimes3(3, arr3(a[0..$]));
}
/*********************************************************/
@@ -133,7 +135,6 @@ int p4;
void foo4(void* delegate()[] dgs...)
{
assert(dgs.length == 4);
- writefln("%s %s", dgs[0](), cast(void*)&p4);
assert(dgs[0]() == cast(void*)&p4);
assert(dgs[1]() == cast(void*)&p4);
assert(dgs[2]() == null);
@@ -144,7 +145,6 @@ void test4()
{
void *abc()
{
- writeln(cast(void*)&p4);
return cast(void*)&p4;
}
@@ -254,7 +254,7 @@ void test6682()
}
/*********************************************************/
-// 9109
+// https://issues.dlang.org/show_bug.cgi?id=9109
void test9109()
{
@@ -269,7 +269,7 @@ void test9109()
}
/*********************************************************/
-// 15835
+// https://issues.dlang.org/show_bug.cgi?id=15835
class C15835 {}
diff --git a/gcc/testsuite/gdc.test/runnable/lexer.d b/gcc/testsuite/gdc.test/runnable/lexer.d
index c16d7b3..ee2fef8 100644
--- a/gcc/testsuite/gdc.test/runnable/lexer.d
+++ b/gcc/testsuite/gdc.test/runnable/lexer.d
@@ -53,7 +53,7 @@ void test7()
}
/*********************************************************/
-// 4633
+// https://issues.dlang.org/show_bug.cgi?id=4633
template Types(alias v)
{
@@ -71,7 +71,7 @@ void test8()
/*********************************************************/
-// bug 6584
+// https://issues.dlang.org/show_bug.cgi?id=6584
version(9223372036854775807){}
debug(9223372036854775807){}
diff --git a/gcc/testsuite/gdc.test/runnable/link11069a.d b/gcc/testsuite/gdc.test/runnable/link11069a.d
index 01b923e..e31cfa0 100644
--- a/gcc/testsuite/gdc.test/runnable/link11069a.d
+++ b/gcc/testsuite/gdc.test/runnable/link11069a.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/std11069array.d imports/std11069container.d imports/std11069range.d imports/std11069typecons.d
// REQUIRED_ARGS: -noboundscheck
// <-- To remove necessity of _D7imports13std11069array7__arrayZ
diff --git a/gcc/testsuite/gdc.test/runnable/link11127.d b/gcc/testsuite/gdc.test/runnable/link11127.d
index 0ce963d..0e5118f 100644
--- a/gcc/testsuite/gdc.test/runnable/link11127.d
+++ b/gcc/testsuite/gdc.test/runnable/link11127.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/link11127a.d
import imports.link11127a;
void main()
diff --git a/gcc/testsuite/gdc.test/runnable/link12037.d b/gcc/testsuite/gdc.test/runnable/link12037.d
index ce5b17f..ca3e3c7 100644
--- a/gcc/testsuite/gdc.test/runnable/link12037.d
+++ b/gcc/testsuite/gdc.test/runnable/link12037.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/a12037.d
import imports.a12037;
alias CustomFloat!(10, 5) Float16;
diff --git a/gcc/testsuite/gdc.test/runnable/link12144.d b/gcc/testsuite/gdc.test/runnable/link12144.d
index 9092556..e7bcf86 100644
--- a/gcc/testsuite/gdc.test/runnable/link12144.d
+++ b/gcc/testsuite/gdc.test/runnable/link12144.d
@@ -1,5 +1,11 @@
// COMPILE_SEPARATELY: -g
// EXTRA_SOURCES: imports/link12144a.d
+/*
+TEST_OUTPUT:
+---
+runnable/imports/link12144a.d(31): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+---
+*/
import imports.link12144a;
diff --git a/gcc/testsuite/gdc.test/runnable/link13043.d b/gcc/testsuite/gdc.test/runnable/link13043.d
index 2969074..561651f 100644
--- a/gcc/testsuite/gdc.test/runnable/link13043.d
+++ b/gcc/testsuite/gdc.test/runnable/link13043.d
@@ -1,5 +1,5 @@
// PERMUTE_ARGS: -g -inline -version=bug -release -O
-
+// EXTRA_FILES: imports/link13043a.d
import imports.link13043a;
void main() {}
diff --git a/gcc/testsuite/gdc.test/runnable/link13350.d b/gcc/testsuite/gdc.test/runnable/link13350.d
index bceb4b8..2a2b40b 100644
--- a/gcc/testsuite/gdc.test/runnable/link13350.d
+++ b/gcc/testsuite/gdc.test/runnable/link13350.d
@@ -1,3 +1,9 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
extern (C) int printf(const(char*) fmt, ...);
static int foo();
diff --git a/gcc/testsuite/gdc.test/runnable/link13415.d b/gcc/testsuite/gdc.test/runnable/link13415.d
index 00b39d1..782bb6b 100644
--- a/gcc/testsuite/gdc.test/runnable/link13415.d
+++ b/gcc/testsuite/gdc.test/runnable/link13415.d
@@ -1,7 +1,13 @@
-// EXTRA_SOURCES: imports/link13415a.d
-// REQUIRED_ARGS: -inline
-// PERMUTE_ARGS: -allinst -unittest -debug
-// COMPILE_SEPARATELY
+/*
+EXTRA_SOURCES: imports/link13415a.d
+REQUIRED_ARGS: -inline
+PERMUTE_ARGS: -allinst -unittest -debug
+COMPILE_SEPARATELY
+RUN_OUTPUT:
+---
+i = 77;
+---
+*/
import imports.link13415a;
diff --git a/gcc/testsuite/gdc.test/runnable/link14074a.d b/gcc/testsuite/gdc.test/runnable/link14074a.d
index eaf1c89..200e810 100644
--- a/gcc/testsuite/gdc.test/runnable/link14074a.d
+++ b/gcc/testsuite/gdc.test/runnable/link14074a.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/link14074x.d
// EXTRA_SOURCES: imports/link14074y.d
import imports.link14074x;
import imports.link14074y;
diff --git a/gcc/testsuite/gdc.test/runnable/link14074b.d b/gcc/testsuite/gdc.test/runnable/link14074b.d
index fea2369..a05ecdc 100644
--- a/gcc/testsuite/gdc.test/runnable/link14074b.d
+++ b/gcc/testsuite/gdc.test/runnable/link14074b.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/link14074z.d
import imports.link14074z;
void main()
diff --git a/gcc/testsuite/gdc.test/runnable/link14541.d b/gcc/testsuite/gdc.test/runnable/link14541.d
index 433b9d7..7877a34 100644
--- a/gcc/testsuite/gdc.test/runnable/link14541.d
+++ b/gcc/testsuite/gdc.test/runnable/link14541.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/link14541traits.d
import imports.link14541traits;
void main()
diff --git a/gcc/testsuite/gdc.test/runnable/link14992.d b/gcc/testsuite/gdc.test/runnable/link14992.d
index 2da97b9..d024b5f 100644
--- a/gcc/testsuite/gdc.test/runnable/link14992.d
+++ b/gcc/testsuite/gdc.test/runnable/link14992.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/a14992.d
import imports.a14992; // do not link
int test()
diff --git a/gcc/testsuite/gdc.test/runnable/link15017.d b/gcc/testsuite/gdc.test/runnable/link15017.d
index ec3304e..16187a8 100644
--- a/gcc/testsuite/gdc.test/runnable/link15017.d
+++ b/gcc/testsuite/gdc.test/runnable/link15017.d
@@ -1,5 +1,11 @@
// COMPILE_SEPARATELY
// EXTRA_SOURCES: imports/std15017variant.d
+/*
+TEST_OUTPUT:
+---
+runnable/link15017.d(48): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+---
+*/
import imports.std15017variant;
@@ -40,6 +46,7 @@ void test()
// OK <- in DeleteExp::semantic
Variant10* p10;
delete p10;
+ static assert(Variant10.__dtor.mangleof == "_D7imports15std15017variant__T8VariantNVki10ZQp6__dtorMFNaNbNiNfZv");
}
void main() {}
diff --git a/gcc/testsuite/gdc.test/runnable/link6574.d b/gcc/testsuite/gdc.test/runnable/link6574.d
index 53e95f2..0f633f3 100644
--- a/gcc/testsuite/gdc.test/runnable/link6574.d
+++ b/gcc/testsuite/gdc.test/runnable/link6574.d
@@ -15,14 +15,18 @@ import imports.testmangle;
enum Method { A, B, }
+@safe @nogc pure nothrow:
+
+enum FZi = "FNaNbNiNfZi"; // pure nothrow @nogc @safe
+
int foo(Method method = Method.A)()
{
- static assert(foo.mangleof == "_D8link6574"~tl!"28"~"__T3fooVE"~id!("8link6574","Qs")~"6Methodi0Z"~id!("3foo","Qs")~"FZi");
+ static assert(foo.mangleof == "_D8link6574"~tl!"28"~"__T3fooVE"~id!("8link6574","Qs")~"6Methodi0Z"~id!("3foo","Qs")~FZi);
return 10 * foo!method();
}
int foo(Method method : Method.A)()
{
- static assert(foo.mangleof == "_D8link6574"~tl!"29"~"__T3fooHVE"~id!("8link6574","Qt")~"6Methodi0Z"~id!("3foo","Qt")~"FZi");
+ static assert(foo.mangleof == "_D8link6574"~tl!"29"~"__T3fooHVE"~id!("8link6574","Qt")~"6Methodi0Z"~id!("3foo","Qt")~FZi);
return 2;
}
int foo(Method method : Method.B)()
@@ -33,7 +37,7 @@ int foo(Method method : Method.B)()
int bar(Method method = Method.B)()
{
- static assert(bar.mangleof == "_D8link6574"~tl!"28"~"__T3barVE"~id!("8link6574","Qs")~"6Methodi1Z"~id!("3bar","Qs")~"FZi");
+ static assert(bar.mangleof == "_D8link6574"~tl!"28"~"__T3barVE"~id!("8link6574","Qs")~"6Methodi1Z"~id!("3bar","Qs")~FZi);
return 10 * bar!method();
}
int bar(Method method : Method.A)()
@@ -43,7 +47,7 @@ int bar(Method method : Method.A)()
}
int bar(Method method : Method.B)()
{
- static assert(bar.mangleof == "_D8link6574"~tl!"29"~"__T3barHVE"~id!("8link6574","Qt")~"6Methodi1Z"~id!("3bar","Qt")~"FZi");
+ static assert(bar.mangleof == "_D8link6574"~tl!"29"~"__T3barHVE"~id!("8link6574","Qt")~"6Methodi1Z"~id!("3bar","Qt")~FZi);
return 3;
}
diff --git a/gcc/testsuite/gdc.test/runnable/link7745.d b/gcc/testsuite/gdc.test/runnable/link7745.d
index fb36a9a..9a0eccf 100644
--- a/gcc/testsuite/gdc.test/runnable/link7745.d
+++ b/gcc/testsuite/gdc.test/runnable/link7745.d
@@ -15,6 +15,6 @@ static assert(forceSemantic7745());
void f(C c) { auto x = &c.asdfg; }
void main() {
- // extra test for bug 4820
+ // https://issues.dlang.org/show_bug.cgi?id=4820
nextis!(int)();
}
diff --git a/gcc/testsuite/gdc.test/runnable/literal.d b/gcc/testsuite/gdc.test/runnable/literal.d
index 60bac91..99b1777 100644
--- a/gcc/testsuite/gdc.test/runnable/literal.d
+++ b/gcc/testsuite/gdc.test/runnable/literal.d
@@ -1,3 +1,9 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
extern(C) int printf(const char*, ...);
@@ -165,7 +171,7 @@ void test2()
}
/***************************************************/
-// 13907
+// https://issues.dlang.org/show_bug.cgi?id=13907
void f13907_1(wchar[1] a) {}
void f13907_2(wchar[2] a) {}
@@ -185,8 +191,8 @@ void test13907()
static assert(!__traits(compiles, { f13907_1("\U00010000" ); }));
f13907_2("\U00010000"w);
f13907_2("\U00010000");
- f13907_3("\U00010000"w); // Re-enable implicit length extension, from issue 13999
- f13907_3("\U00010000" ); // Re-enable implicit length extension, from issue 13999
+ f13907_3("\U00010000"w); // Re-enable implicit length extension, from https://issues.dlang.org/show_bug.cgi?id=13999
+ f13907_3("\U00010000" ); // Re-enable implicit length extension, from https://issues.dlang.org/show_bug.cgi?id=13999
assert(f13907_12("a") == 1);
assert(f13907_12("ab") == 2);
@@ -210,13 +216,13 @@ void test13907()
static wchar[20] wsa = "hello world"; // ok
static dchar[20] dsa = "hello world"; // ok
- // Bugzilla 13966
+ // https://issues.dlang.org/show_bug.cgi?id=13966
string[1][] arr;
arr ~= ["class"];
enum immutable(char[5]) sarrstr = "class";
arr ~= [sarrstr];
- // Bugzilla 13999
+ // https://issues.dlang.org/show_bug.cgi?id=13999
string[dchar[2]] aa13999 = ["ã‚": "bar"];
assert(aa13999["ã‚"] == "bar");
dchar[2] key13999 = "ã‚";
@@ -225,6 +231,16 @@ void test13907()
assert(aa13999[key13999] == "bar");
}
+ulong op12950(ulong v){return v + 12950;}
+
+void test12950()
+{
+ assert(0x00_00_00_01.op12950() == 12951);
+ assert(0x00_00_00_01UL.op12950() == 12951);
+ assert(0b00_00_00_01.op12950() == 12951);
+ assert(0b00_00_00_01UL.op12950() == 12951);
+}
+
/***************************************************/
int main()
@@ -232,6 +248,7 @@ int main()
test1();
test2();
test13907();
+ test12950();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/loopunroll.d b/gcc/testsuite/gdc.test/runnable/loopunroll.d
index 19e2db2..b614d1b 100644
--- a/gcc/testsuite/gdc.test/runnable/loopunroll.d
+++ b/gcc/testsuite/gdc.test/runnable/loopunroll.d
@@ -1,5 +1,22 @@
-
-/* PERMUTE_ARGS: -O
+/*
+PERMUTE_ARGS: -O
+RUN_OUTPUT:
+---
+0
+45
+45
+45
+45
+45
+45
+45
+10
+45
+0
+5
+45
+45
+---
*/
import core.stdc.stdio;
diff --git a/gcc/testsuite/gdc.test/runnable/m1.d b/gcc/testsuite/gdc.test/runnable/m1.d
index 49a3d15..5689ffd 100644
--- a/gcc/testsuite/gdc.test/runnable/m1.d
+++ b/gcc/testsuite/gdc.test/runnable/m1.d
@@ -1,9 +1,15 @@
-// EXTRA_SOURCES: imports/m1a.d
-// PERMUTE_ARGS:
+/*
+EXTRA_SOURCES: imports/m1a.d
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+Success
+---
+*/
module m1;
-import std.stdio;
+import core.stdc.stdio;
import imports.m1a;
diff --git a/gcc/testsuite/gdc.test/runnable/manboy.d b/gcc/testsuite/gdc.test/runnable/manboy.d
index 0386226..8e53307 100644
--- a/gcc/testsuite/gdc.test/runnable/manboy.d
+++ b/gcc/testsuite/gdc.test/runnable/manboy.d
@@ -1,6 +1,6 @@
// PERMUTE_ARGS:
-import std.stdio;
+import core.stdc.stdio;
int a(int k, lazy int x1, lazy int x2, lazy int x3, lazy int x4, lazy int x5)
{
diff --git a/gcc/testsuite/gdc.test/runnable/mangle.d b/gcc/testsuite/gdc.test/runnable/mangle.d
index 9a8420a..7599e0e 100644
--- a/gcc/testsuite/gdc.test/runnable/mangle.d
+++ b/gcc/testsuite/gdc.test/runnable/mangle.d
@@ -14,7 +14,8 @@ false
import imports.testmangle;
/***************************************************/
-// 10077 - pragma(mangle)
+// https://issues.dlang.org/show_bug.cgi?id=10077
+// pragma(mangle)
pragma(mangle, "_test10077a_") int test10077a;
static assert(test10077a.mangleof == "_test10077a_");
@@ -54,7 +55,7 @@ void test10077i()
}
/***************************************************/
-// 13050
+// https://issues.dlang.org/show_bug.cgi?id=13050
void func13050(int);
template decl13050(Arg)
@@ -79,7 +80,7 @@ static assert(is(typeof(&problem13050!int) == void function(int)));
static assert(is(typeof(&workaround13050!int) == void function(int)));
/***************************************************/
-// 2774
+// https://issues.dlang.org/show_bug.cgi?id=2774
int foo2774(int n) { return 0; }
static assert(foo2774.mangleof == "_D6mangle7foo2774FiZi");
@@ -100,7 +101,7 @@ void test2774()
}
/*******************************************/
-// 8847
+// https://issues.dlang.org/show_bug.cgi?id=8847
auto S8847()
{
@@ -294,7 +295,7 @@ static assert(typeof(f8847a()).mangleof == "S6mangle6f8847aFNaZ1S");
static assert(typeof(f8847b()).mangleof == "S6mangle6f8847bFNaZ1S");
/*******************************************/
-// 12352
+// https://issues.dlang.org/show_bug.cgi?id=12352
auto bar12352()
{
@@ -325,7 +326,7 @@ static assert(typeof(baz12352()) .mangleof == "C6mangle8baz12352FZ1C");
static assert(typeof(baz12352()).func.mangleof == "_D6mangle8baz12352FZ1C4funcMFZv");
/*******************************************/
-// 9525
+// https://issues.dlang.org/show_bug.cgi?id=9525
void f9525(T)(in T*) { }
@@ -334,27 +335,29 @@ void test9525()
enum result1 = "S6mangle8test9525FZ"~tl!"26"~"__T5test1S"~tl!"13"~id!("6mangle","QBc")~"5f9525Z"~id!("5test1","Qr")~"MFZ1S";
enum result2 = "S6mangle8test9525FZ"~tl!"26"~"__T5test2S"~tl!"13"~id!("6mangle","QBc")~"5f9525Z"~id!("5test2","Qr")~"MFNaNbZ1S";
- void test1(alias a)()
+ bool test1(alias a)()
{
static struct S {}
static assert(S.mangleof == result1);
S s;
a(&s); // Error: Cannot convert &S to const(S*) at compile time
+ return true;
}
- static assert((test1!f9525(), true));
+ enum evalTest1 = test1!f9525();
- void test2(alias a)() pure nothrow
+ bool test2(alias a)() pure nothrow
{
static struct S {}
static assert(S.mangleof == result2);
S s;
a(&s); // Error: Cannot convert &S to const(S*) at compile time
+ return true;
}
- static assert((test2!f9525(), true));
+ enum evalTest2 = test2!f9525();
}
/******************************************/
-// 10249
+// https://issues.dlang.org/show_bug.cgi?id=10249
template Seq10249(T...) { alias Seq10249 = T; }
@@ -390,7 +393,7 @@ static: // necessary to make overloaded symbols accessible via __traits(getOverl
}
/*******************************************/
-// 11718
+// https://issues.dlang.org/show_bug.cgi?id=11718
struct Ty11718(alias sym) {}
@@ -431,7 +434,7 @@ void test11718()
}
/*******************************************/
-// 11776
+// https://issues.dlang.org/show_bug.cgi?id=11776
struct S11776(alias fun) { }
@@ -454,7 +457,7 @@ void test11776()
}
/***************************************************/
-// 12044
+// https://issues.dlang.org/show_bug.cgi?id=12044
struct S12044(T)
{
@@ -481,7 +484,7 @@ void test12044()
}
/*******************************************/
-// 12217
+// https://issues.dlang.org/show_bug.cgi?id=12217
void test12217(int)
{
@@ -499,7 +502,7 @@ void test12217(int)
void test12217() {}
/***************************************************/
-// 12231
+// https://issues.dlang.org/show_bug.cgi?id=12231
void func12231a()()
if (is(typeof({
@@ -599,6 +602,13 @@ void fooB(void delegate (void delegate()) scope dg)
//pragma(msg, fooB.mangleof);
static assert(typeof(fooA).mangleof != typeof(fooB).mangleof);
+
+/***************************************************/
+
+@live int testLive() { return 42; }
+
+static assert(testLive.mangleof == "_D6mangle8testLiveFNmZi");
+
/***************************************************/
alias noreturn = typeof(*null);
@@ -608,6 +618,12 @@ static assert(funcd.mangleof == "_D6mangle5funcdFPFZNnZi");
/***************************************************/
+struct S21753 { void function() f1; }
+void fun21753(S21753 v)() {}
+alias fl21753 = (){};
+static assert((fun21753!(S21753(fl21753))).mangleof == "_D6mangle__T8fun21753VSQv6S21753S1f_DQBj10" ~ fl21753.stringof ~ "MFNaNbNiNfZvZQCbQp");
+
+/***************************************************/
void main()
{
test10077h();
diff --git a/gcc/testsuite/gdc.test/runnable/mars1.d b/gcc/testsuite/gdc.test/runnable/mars1.d
index 4d17d33..4f38f4d 100644
--- a/gcc/testsuite/gdc.test/runnable/mars1.d
+++ b/gcc/testsuite/gdc.test/runnable/mars1.d
@@ -1,259 +1,36 @@
/*
-RUNNABLE_PHOBOS_TEST
-REQUIRED_ARGS: -mcpu=native
-PERMUTE_ARGS: -O -inline
+REQUIRED_ARGS: -mcpu=native -preview=intpromote
+PERMUTE_ARGS: -O -inline -release
*/
import core.stdc.stdio;
-void testgoto()
-{
- int i;
-
- i = 3;
- goto L4;
-L3: i++;
- goto L5;
-L4: goto L3;
-L5: assert(i == 4);
-}
-
-int testswitch()
-{
- int i;
-
- i = 3;
- switch (i)
- {
- case 0:
- case 1:
- default:
- assert(0);
- case 3:
- break;
- }
- return 0;
-}
-
-void testdo()
-{
- int x = 0;
-
- do
- {
- x++;
- } while (x < 10);
- printf("x == %d\n", x);
- assert(x == 10);
-}
-
-
-void testbreak()
-{ int i, j;
-
- Louter:
- for (i = 0; i < 10; i++)
- {
- for (j = 0; j < 10; j++)
- {
- if (j == 3)
- break Louter;
- }
- }
-
- printf("i = %d, j = %d\n", i, j);
- assert(i == 0);
- assert(j == 3);
-}
+template tuple(A...) { alias tuple = A; }
///////////////////////
-int foo(string s)
-{
- int i;
-
- i = 0;
- switch (s)
- {
- case "hello":
- i = 1;
- break;
- case "goodbye":
- i = 2;
- break;
- case "goodb":
- i = 3;
- break;
- default:
- i = 10;
- break;
- }
- return i;
-}
-
-
-void teststringswitch()
-{ int i;
-
- i = foo("hello");
- printf("i = %d\n", i);
- assert(i == 1);
-
- i = foo("goodbye");
- printf("i = %d\n", i);
- assert(i == 2);
-
- i = foo("goodb");
- printf("i = %d\n", i);
- assert(i == 3);
-
- i = foo("huzzah");
- printf("i = %d\n", i);
- assert(i == 10);
-}
-
-
-///////////////////////
+// https://github.com/dlang/dmd/pull/11441
-struct Foo
+long sdiv1(long l)
{
- int a;
- char b;
- long c;
+ return l / 2;
}
-Foo test(Foo f)
+int sdiv2(int i)
{
- f.a += 1;
- f.b += 3;
- f.c += 4;
- return f;
+ return i / 2;
}
-
-void teststrarg()
+void testsdiv2()
{
- Foo g;
- g.a = 1;
- g.b = 2;
- g.c = 3;
-
- Foo q;
- q = test(g);
- assert(q.a == 2);
- assert(q.b == 5);
- assert(q.c == 7);
+ assert(sdiv1(10) == 5);
+ assert(sdiv1(-10) == -5);
+ assert(sdiv2(10) == 5);
+ assert(sdiv2(-10) == -5);
}
///////////////////////
-align (1) struct Foo1
-{
- align (1):
- int a;
- char b;
- long c;
-}
-
-struct Foo2
-{
- int a;
- char b;
- long c;
-}
-
-struct Foo3
-{
- int a;
- align (1) char b;
- long c;
-}
-
-struct Foo4
-{
- int a;
- struct { char b; }
- long c;
-}
-
-void testsizes()
-{
- printf("%d\n", Foo1.sizeof);
- assert(Foo1.a.offsetof == 0);
- assert(Foo1.b.offsetof == 4);
- assert(Foo1.c.offsetof == 5);
- assert(Foo1.sizeof == 13);
-
- assert(Foo2.a.offsetof == 0);
- assert(Foo2.b.offsetof == 4);
- assert(Foo2.c.offsetof == 8);
- assert(Foo2.sizeof == 16);
-
- assert(Foo3.a.offsetof == 0);
- assert(Foo3.b.offsetof == 4);
- assert(Foo3.c.offsetof == 8);
- assert(Foo3.b.sizeof == 1);
- assert(Foo3.sizeof == 16);
-
- assert(Foo4.sizeof == 16);
-}
-
-///////////////////////
-
-size_t cond11565(size_t val)
-{
- return val ? size_t.max : 0;
-}
-
-void test11565()
-{
- assert(cond11565(true) == size_t.max);
-}
-
-///////////////////////
-
-int[3] array1 = [1:1,2,0:3];
-
-void testarrayinit()
-{
- assert(array1[0] == 3);
- assert(array1[1] == 1);
- assert(array1[2] == 2);
-}
-
-///////////////////////
-
-void test13023(ulong n)
-{
- static void func(bool b) {}
-
- ulong k = 0;
-
- func(k >= n / 2);
-
- if (k >= n / 2)
- assert(0);
-}
-
-///////////////////////
-
-struct U { int a; union { char c; int d; } long b; }
-
-U f = { b:3, d:0x22222222, a:1 };
-
-void testU()
-{
- assert(f.b == 3);
- assert(f.d == 0x22222222);
- assert(f.c == 0x22);
- assert(f.a == 1);
- assert(f.sizeof == 16);
- assert(U.sizeof == 16);
-}
-
-
-///////////////////////
-
void testulldiv()
{
__gshared ulong[4][] vectors =
@@ -280,19 +57,18 @@ void testulldiv()
{
ulong q = vectors[i][0] / vectors[i][1];
if (q != vectors[i][2])
- printf("[%d] %lld / %lld = %lld, should be %lld\n",
- vectors[i][0], vectors[i][1], q, vectors[i][2]);
+ printf("[%zd] %lld / %lld = %lld, should be %lld\n",
+ i, vectors[i][0], vectors[i][1], q, vectors[i][2]);
ulong r = vectors[i][0] % vectors[i][1];
if (r != vectors[i][3])
- printf("[%d] %lld %% %lld = %lld, should be %lld\n",
+ printf("[%zd] %lld %% %lld = %lld, should be %lld\n",
i, vectors[i][0], vectors[i][1], r, vectors[i][3]);
}
}
////////////////////////////////////////////////////////////////////////
-
uint udiv10(uint x)
{
return x / 10;
@@ -427,307 +203,498 @@ void testfastudiv()
////////////////////////////////////////////////////////////////////////
-void vfunc() {}
-
-void test12095(int k)
-{
- int e = 0;
- e ? k || assert(0) : !e || vfunc();
- e ? k || assert(0) : e && vfunc();
- !e ? !e || vfunc() : k || assert(0);
+// https://issues.dlang.org/show_bug.cgi?id=14936
+
+long sldiv1 (long x) { return x / (1L << 1); }
+long sldiv2 (long x) { return x / (1L << 2); }
+long sldiv3 (long x) { return x / (1L << 3); }
+long sldiv7 (long x) { return x / (1L << 7); }
+long sldiv8 (long x) { return x / (1L << 8); }
+long sldiv9 (long x) { return x / (1L << 9); }
+long sldiv30(long x) { return x / (1L << 30); }
+long sldiv31(long x) { return x / (1L << 31); }
+long sldiv32(long x) { return x / (1L << 32); }
+long sldiv33(long x) { return x / (1L << 33); }
+long sldiv34(long x) { return x / (1L << 34); }
+long sldiv62(long x) { return x / (1L << 62); }
+long sldiv63(long x) { return x / (1L << 63); }
+
+void testsldiv()
+{
+ /* Test special div code for signed long divide
+ * by power of 2 for 32 bit targets.
+ */
+
+ // printf("63 = %llx\n", sldiv63(-0x7FFF_F8FF_FF3F_2FFFL));
+
+ static foreach (C; tuple!(
+ 1,2,3,10,300,1000,
+ 4_1001_2030_0030,
+ 0x7FFF_F8FF_FF3F_2FFFL))
+ {
+ /* Check if runtime computation matches compile time
+ */
+ assert(sldiv1 ( C) == C / (1L << 1));
+ assert(sldiv1 (-C) == -C / (1L << 1));
+ assert(sldiv2 ( C) == C / (1L << 2));
+ assert(sldiv2 (-C) == -C / (1L << 2));
+ assert(sldiv3 ( C) == C / (1L << 3));
+ assert(sldiv3 (-C) == -C / (1L << 3));
+ assert(sldiv7 ( C) == C / (1L << 7));
+ assert(sldiv7 (-C) == -C / (1L << 7));
+ assert(sldiv8 ( C) == C / (1L << 8));
+ assert(sldiv8 (-C) == -C / (1L << 8));
+ assert(sldiv9 ( C) == C / (1L << 9));
+ assert(sldiv9 (-C) == -C / (1L << 9));
+
+ assert(sldiv30( C) == C / (1L << 30));
+ assert(sldiv30(-C) == -C / (1L << 30));
+ assert(sldiv31( C) == C / (1L << 31));
+ assert(sldiv31(-C) == -C / (1L << 31));
+ assert(sldiv32( C) == C / (1L << 32));
+ assert(sldiv32(-C) == -C / (1L << 32));
+ assert(sldiv33( C) == C / (1L << 33));
+ assert(sldiv33(-C) == -C / (1L << 33));
+ assert(sldiv34( C) == C / (1L << 34));
+ assert(sldiv34(-C) == -C / (1L << 34));
+ assert(sldiv62( C) == C / (1L << 62));
+ assert(sldiv62(-C) == -C / (1L << 62));
+ assert(sldiv63( C) == C / (1L << 63));
+ assert(sldiv63(-C) == -C / (1L << 63));
+ }
}
+////////////////////////////////////////////////////////////////////////
+
+// https://issues.dlang.org/show_bug.cgi?id=14936
+
+long slmod1 (long x) { return x % (1L << 1); }
+long slmod2 (long x) { return x % (1L << 2); }
+long slmod3 (long x) { return x % (1L << 3); }
+long slmod7 (long x) { return x % (1L << 7); }
+long slmod8 (long x) { return x % (1L << 8); }
+long slmod9 (long x) { return x % (1L << 9); }
+long slmod30(long x) { return x % (1L << 30); }
+long slmod31(long x) { return x % (1L << 31); }
+long slmod32(long x) { return x % (1L << 32); }
+long slmod33(long x) { return x % (1L << 33); }
+long slmod34(long x) { return x % (1L << 34); }
+long slmod62(long x) { return x % (1L << 62); }
+long slmod63(long x) { return x % (1L << 63); }
+
+void testslmod()
+{
+ static foreach (C; tuple!(
+ 1,2,3,10,300,1000,
+ 4_1001_2030_0030,
+ 0x7FFF_F8FF_FF3F_2FFFL))
+ {
+ /* Check if runtime computation matches compile time
+ */
+ assert(slmod1 ( C) == C % (1L << 1));
+ assert(slmod1 (-C) == -C % (1L << 1));
+ assert(slmod2 ( C) == C % (1L << 2));
+ assert(slmod2 (-C) == -C % (1L << 2));
+ assert(slmod3 ( C) == C % (1L << 3));
+ assert(slmod3 (-C) == -C % (1L << 3));
+ assert(slmod7 ( C) == C % (1L << 7));
+ assert(slmod7 (-C) == -C % (1L << 7));
+ assert(slmod8 ( C) == C % (1L << 8));
+ assert(slmod8 (-C) == -C % (1L << 8));
+ assert(slmod9 ( C) == C % (1L << 9));
+ assert(slmod9 (-C) == -C % (1L << 9));
+
+ assert(slmod30( C) == C % (1L << 30));
+ assert(slmod30(-C) == -C % (1L << 30));
+ assert(slmod31( C) == C % (1L << 31));
+ assert(slmod31(-C) == -C % (1L << 31));
+ assert(slmod32( C) == C % (1L << 32));
+ assert(slmod32(-C) == -C % (1L << 32));
+ assert(slmod33( C) == C % (1L << 33));
+ assert(slmod33(-C) == -C % (1L << 33));
+ assert(slmod34( C) == C % (1L << 34));
+ assert(slmod34(-C) == -C % (1L << 34));
+ assert(slmod62( C) == C % (1L << 62));
+ assert(slmod62(-C) == -C % (1L << 62));
+ assert(slmod63( C) == C % (1L << 63));
+ assert(slmod63(-C) == -C % (1L << 63));
+ }
+}
////////////////////////////////////////////////////////////////////////
+T divC(int C, T)(T x)
+{
+ T y = x;
+ y /= C;
+ assert(y == x / C);
+ y = x;
+ y /= -C;
+ assert(y == x / -C);
+ return x / C;
+}
-bool test3918a( float t, real u )
+T modC(int C, T)(T x)
{
- printf("%f\n", u );
- return t && u;
+ T y = x;
+ y %= C;
+ assert(y == x % C);
+ y = x;
+ y %= -C;
+ assert(y == x % -C);
+ return x % C;
}
-bool test3918b( real t, float u )
+T remquoC(int C, T)(T x)
{
- printf("%f\n", t );
- return t && u;
+ return (x / C) | (x % C);
}
-void test3918()
+void testfastdiv()
{
- assert(test3918a(float.nan, real.nan));
- assert(test3918b(real.nan, float.nan));
+ static int z = 0; // prevent constant folding by optimizer
+
+ static foreach (T; tuple!(int, long, uint, ulong))
+ {{
+ T u = 10000;
+ T r;
+ static foreach (C; tuple!(10, 14, 14007, -10, -14, -14007))
+ {
+ r = divC!C(u); assert(r == u / (z + C));
+ r = modC!C(u); assert(r == u % (z + C));
+ r = remquoC!C(u); assert(r == ((u / (z + C) | (u % (z + C)))));
+ }
+ }}
}
////////////////////////////////////////////////////////////////////////
-int div10(int x)
-{
- return x / 10;
-}
+/* Test the pattern:
+ * replace ((i / C1) / C2) with (i / (C1 * C2))
+ * when e1 is 0 or 1 and (i2-i1) is a power of 2.
+ */
-int div14(int x)
+void divdiv(T, T C1, T C2)(T i)
{
- return x / 14;
+ auto a = (i / C1) / C2;
+ auto b = i / (C1 * C2);
+ if (a != b) assert(0);
}
-int div14007(int x)
+void testdivdiv()
{
- return x / 14007;
+ divdiv!(int,10,20)(30);
+ divdiv!(uint,10,20)(30);
+ divdiv!(long,10,20)(30);
+ divdiv!(ulong,10,20)(30);
+
+ divdiv!(int,-10,20)(30);
+ divdiv!(long,-10,20)(30);
+
+ divdiv!(int,-10,-20)(-30);
+ divdiv!(long,-10,-20)(-30);
}
-int mod10(int x)
+////////////////////////////////////////////////////////////////////////
+
+void testdivcmp()
{
- return x % 10;
+ // https://github.com/dlang/dmd/pull/7128
+ static bool foo(uint a, uint b)
+ {
+ return cast(bool)(a / b); // convert / to >=
+ }
+
+ assert(!foo(3, 4));
+ assert(foo(4, 4));
+ assert(foo(5, 4));
}
-int mod14(int x)
+/////////////////////////////////////////////////////
+
+void testgoto()
{
- return x % 14;
+ int i;
+
+ i = 3;
+ goto L4;
+L3: i++;
+ goto L5;
+L4: goto L3;
+L5: assert(i == 4);
}
-int mod14007(int x)
+int testswitch()
{
- return x % 14007;
+ int i;
+
+ i = 3;
+ switch (i)
+ {
+ case 0:
+ case 1:
+ default:
+ assert(0);
+ case 3:
+ break;
+ }
+ return 0;
}
-int remquo10(int x)
+void testdo()
{
- return (x / 10) | (x % 10);
+ int x = 0;
+
+ do
+ {
+ x++;
+ } while (x < 10);
+ printf("x == %d\n", x);
+ assert(x == 10);
}
-int remquo14(int x)
-{
- return (x / 14) | (x % 14);
+
+void testbreak()
+{ int i, j;
+
+ Louter:
+ for (i = 0; i < 10; i++)
+ {
+ for (j = 0; j < 10; j++)
+ {
+ if (j == 3)
+ break Louter;
+ }
+ }
+
+ printf("i = %d, j = %d\n", i, j);
+ assert(i == 0);
+ assert(j == 3);
}
-int remquo14007(int x)
+///////////////////////
+
+int foo(string s)
{
- return (x / 14007) | (x % 14007);
+ int i;
+
+ i = 0;
+ switch (s)
+ {
+ case "hello":
+ i = 1;
+ break;
+ case "goodbye":
+ i = 2;
+ break;
+ case "goodb":
+ i = 3;
+ break;
+ default:
+ i = 10;
+ break;
+ }
+ return i;
}
-////////////////////
-int mdiv10(int x)
-{
- return x / -10;
+void teststringswitch()
+{ int i;
+
+ i = foo("hello");
+ printf("i = %d\n", i);
+ assert(i == 1);
+
+ i = foo("goodbye");
+ printf("i = %d\n", i);
+ assert(i == 2);
+
+ i = foo("goodb");
+ printf("i = %d\n", i);
+ assert(i == 3);
+
+ i = foo("huzzah");
+ printf("i = %d\n", i);
+ assert(i == 10);
}
-int mdiv14(int x)
+
+///////////////////////
+
+struct Foo
{
- return x / -14;
+ int a;
+ char b;
+ long c;
}
-int mdiv14007(int x)
+Foo test(Foo f)
{
- return x / -14007;
+ f.a += 1;
+ f.b += 3;
+ f.c += 4;
+ return f;
}
-int mmod10(int x)
+
+void teststrarg()
{
- return x % -10;
+ Foo g;
+ g.a = 1;
+ g.b = 2;
+ g.c = 3;
+
+ Foo q;
+ q = test(g);
+ assert(q.a == 2);
+ assert(q.b == 5);
+ assert(q.c == 7);
}
-int mmod14(int x)
+///////////////////////
+
+align (1) struct Foo1
{
- return x % -14;
+ align (1):
+ int a;
+ char b;
+ long c;
}
-int mmod14007(int x)
+struct Foo2
{
- return x % -14007;
+ int a;
+ char b;
+ long c;
}
-int mremquo10(int x)
+struct Foo3
{
- return (x / -10) | (x % -10);
+ int a;
+ align (1) char b;
+ long c;
}
-int mremquo14(int x)
+struct Foo4
{
- return (x / -14) | (x % -14);
+ int a;
+ struct { char b; }
+ long c;
}
-int mremquo14007(int x)
+void testsizes()
{
- return (x / -14007) | (x % -14007);
-}
+ printf("%zd\n", Foo1.sizeof);
+ assert(Foo1.a.offsetof == 0);
+ assert(Foo1.b.offsetof == 4);
+ assert(Foo1.c.offsetof == 5);
+ assert(Foo1.sizeof == 13);
-////////////////////
+ assert(Foo2.a.offsetof == 0);
+ assert(Foo2.b.offsetof == 4);
+ assert(Foo2.c.offsetof == 8);
+ assert(Foo2.sizeof == 16);
+ assert(Foo3.a.offsetof == 0);
+ assert(Foo3.b.offsetof == 4);
+ assert(Foo3.c.offsetof == 8);
+ assert(Foo3.b.sizeof == 1);
+ assert(Foo3.sizeof == 16);
-long ldiv10(long x)
-{
- return x / 10;
+ assert(Foo4.sizeof == 16);
}
-long ldiv14(long x)
-{
- return x / 14;
-}
+///////////////////////
-long ldiv14007(long x)
+size_t cond11565(size_t val)
{
- return x / 14007;
+ return val ? size_t.max : 0;
}
-long lmod10(long x)
+void test11565()
{
- return x % 10;
+ assert(cond11565(true) == size_t.max);
}
-long lmod14(long x)
-{
- return x % 14;
-}
+///////////////////////
-long lmod14007(long x)
-{
- return x % 14007;
-}
+int[3] array1 = [1:1,2,0:3];
-long lremquo10(long x)
+void testarrayinit()
{
- return (x / 10) | (x % 10);
+ assert(array1[0] == 3);
+ assert(array1[1] == 1);
+ assert(array1[2] == 2);
}
-long lremquo14(long x)
-{
- return (x / 14) | (x % 14);
-}
+///////////////////////
-long lremquo14007(long x)
+void test13023(ulong n)
{
- return (x / 14007) | (x % 14007);
+ static void func(bool b) {}
+
+ ulong k = 0;
+
+ func(k >= n / 2);
+
+ if (k >= n / 2)
+ assert(0);
}
+///////////////////////
-////////////////////
+struct U { int a; union { char c; int d; } long b; }
+U f = { b:3, d:0x22222222, a:1 };
-long mldiv10(long x)
+void testU()
{
- return x / -10;
+ assert(f.b == 3);
+ assert(f.d == 0x22222222);
+ assert(f.c == 0x22);
+ assert(f.a == 1);
+ assert(f.sizeof == 16);
+ assert(U.sizeof == 16);
}
-long mldiv14(long x)
-{
- return x / -14;
-}
-long mldiv14007(long x)
-{
- return x / -14007;
-}
+////////////////////////////////////////////////////////////////////////
-long mlmod10(long x)
-{
- return x % -10;
-}
+void vfunc() {}
-long mlmod14(long x)
+void test12095(int k)
{
- return x % -14;
+ int e = 0;
+ e ? k || assert(0) : !e || vfunc();
+ e ? k || assert(0) : e && vfunc();
+ !e ? !e || vfunc() : k || assert(0);
}
-long mlmod14007(long x)
-{
- return x % -14007;
-}
-long mlremquo10(long x)
-{
- return (x / -10) | (x % -10);
-}
+////////////////////////////////////////////////////////////////////////
+
-long mlremquo14(long x)
+bool test3918a( float t, real u )
{
- return (x / -14) | (x % -14);
+ printf("%Lf\n", u );
+ return t && u;
}
-long mlremquo14007(long x)
+bool test3918b( real t, float u )
{
- return (x / -14007) | (x % -14007);
+ printf("%Lf\n", t );
+ return t && u;
}
-
-
-void testfastdiv()
+void test3918()
{
- {
- static int x10 = 10;
- static int x14 = 14;
- static int x14007 = 14007;
-
- int u = 10000;
- int r;
- r = div10(u); assert(r == u/x10);
- r = div14(u); assert(r == u/x14);
- r = div14007(u); assert(r == u/x14007);
- r = mod10(u); assert(r == u%x10);
- r = mod14(u); assert(r == u%x14);
- r = mod14007(u); assert(r == u%x14007);
- r = remquo10(u); assert(r == ((u/x10)|(u%x10)));
- r = remquo14(u); assert(r == ((u/x14)|(u%x14)));
- r = remquo14007(u); assert(r == ((u/x14007)|(u%x14007)));
- }
- {
- static int t10 = -10;
- static int t14 = -14;
- static int t14007 = -14007;
-
- int u = 10000;
- int r;
- r = mdiv10(u); assert(r == u/t10);
- r = mdiv14(u); assert(r == u/t14);
- r = mdiv14007(u); assert(r == u/t14007);
- r = mmod10(u); assert(r == u%t10);
- r = mmod14(u); assert(r == u%t14);
- r = mmod14007(u); assert(r == u%t14007);
- r = mremquo10(u); assert(r == ((u/t10)|(u%t10)));
- r = mremquo14(u); assert(r == ((u/t14)|(u%t14)));
- r = mremquo14007(u); assert(r == ((u/t14007)|(u%t14007)));
- }
- {
- static long y10 = 10;
- static long y14 = 14;
- static long y14007 = 14007;
-
- long u = 10000;
- long r;
- r = ldiv10(u); assert(r == u/y10);
- r = ldiv14(u); assert(r == u/y14);
- r = ldiv14007(u); assert(r == u/y14007);
- r = lmod10(u); assert(r == u%y10);
- r = lmod14(u); assert(r == u%y14);
- r = lmod14007(u); assert(r == u%y14007);
- r = lremquo10(u); assert(r == ((u/y10)|(u%y10)));
- r = lremquo14(u); assert(r == ((u/y14)|(u%y14)));
- r = lremquo14007(u); assert(r == ((u/y14007)|(u%y14007)));
- }
- {
- static long z10 = -10;
- static long z14 = -14;
- static long z14007 = -14007;
-
- long u = 10000;
- long r;
- r = mldiv10(u); assert(r == u/z10);
- r = mldiv14(u); assert(r == u/z14);
- r = mldiv14007(u); assert(r == u/z14007);
- r = mlmod10(u); assert(r == u%z10);
- r = mlmod14(u); assert(r == u%z14);
- r = mlmod14007(u); assert(r == u%z14007);
- r = mlremquo10(u); assert(r == ((u/z10)|(u%z10)));
- r = mlremquo14(u); assert(r == ((u/z14)|(u%z14)));
- r = mlremquo14007(u); assert(r == ((u/z14007)|(u%z14007)));
- }
+ assert(test3918a(float.nan, real.nan));
+ assert(test3918b(real.nan, float.nan));
}
////////////////////////////////////////////////////////////////////////
-
T docond1(T)(T l, ubyte thresh, ubyte val) {
l += (thresh < val);
return l;
@@ -1041,25 +1008,6 @@ void testshrshl()
////////////////////////////////////////////////////////////////////////
-struct S1
-{
- cdouble val;
-}
-
-void formatTest(S1 s, double re, double im)
-{
- assert(s.val.re == re);
- assert(s.val.im == im);
-}
-
-void test10639()
-{
- S1 s = S1(3+2.25i);
- formatTest(s, 3, 2.25);
-}
-
-////////////////////////////////////////////////////////////////////////
-
bool bt10715(in uint[] ary, size_t bitnum)
{
return !!(ary[bitnum >> 5] & 1 << (bitnum & 31)); // uses bt
@@ -1245,6 +1193,19 @@ void test9449()
if (arr[0].g != 4.0) assert(0);
}
+struct Point9449x
+{
+ float f = 0.0;
+ double g = 0.0;
+}
+
+void test9449x()
+{
+ Point9449x[1] arr;
+ if (arr[0].f != 0.0) assert(0);
+ if (arr[0].g != 0.0) assert(0);
+}
+
////////////////////////////////////////////////////////////////////////
// https://issues.dlang.org/show_bug.cgi?id=12057
@@ -1351,18 +1312,6 @@ void test14829()
////////////////////////////////////////////////////////////////////////
-void test2()
-{
- void test(cdouble v)
- {
- auto x2 = cdouble(v);
- assert(x2 == v);
- }
- test(1.2+3.4i);
-}
-
-////////////////////////////////////////////////////////////////////////
-
void test3()
{
int[6] a;
@@ -1374,7 +1323,7 @@ void test3()
}
////////////////////////////////////////////////////////////////////////
-// 14782
+// https://issues.dlang.org/show_bug.cgi?id=14782
void test14782()
@@ -1477,7 +1426,7 @@ void test4()
double sumKBN(double s = 0.0)
{
- import std.math : fabs;
+ import core.math : fabs;
double c = 0.0;
foreach(double x; [1, 1e100, 1, -1e100])
{
@@ -1547,35 +1496,6 @@ void test16102()
////////////////////////////////////////////////////////////////////////
-
-/* Test the pattern:
- * replace ((i / C1) / C2) with (i / (C1 * C2))
- * when e1 is 0 or 1 and (i2-i1) is a power of 2.
- */
-
-void divdiv(T, T C1, T C2)(T i)
-{
- auto a = (i / C1) / C2;
- auto b = i / (C1 * C2);
- if (a != b) assert(0);
-}
-
-void testdivdiv()
-{
- divdiv!(int,10,20)(30);
- divdiv!(uint,10,20)(30);
- divdiv!(long,10,20)(30);
- divdiv!(ulong,10,20)(30);
-
- divdiv!(int,-10,20)(30);
- divdiv!(long,-10,20)(30);
-
- divdiv!(int,-10,-20)(-30);
- divdiv!(long,-10,-20)(-30);
-}
-
-////////////////////////////////////////////////////////////////////////
-
void test5a(ulong x, ulong y)
{
int a;
@@ -1663,8 +1583,904 @@ void testeqeqranges()
////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=16189
+
+void test16189()
+{
+ ubyte[9][1] data;
+ uint a = 0;
+ loop:
+ data[0] = data[a];
+ a--;
+ bool b = false;
+ if (b) goto loop;
+ assert(a == -1); // was failing with -O
+}
+
+
+////////////////////////////////////////////////////////////////////////
+
+// https://issues.dlang.org/show_bug.cgi?id=16997
+
+void test16997()
+{
+ /* Exhaustively test all signed and unsigned byte promotions for
+ * - + and ~
+ */
+ for (int i = 0; i < 256; ++i)
+ {
+ ubyte c = cast(ubyte)i;
+
+ int i1 = cast(int)(~c);
+ int i2 = cast(int)(~cast(int)c);
+
+ //printf("%d, %d\n", i1, i2);
+ assert(i1 == i2);
+
+ i1 = cast(int)(+c);
+ i2 = cast(int)(+cast(int)c);
+ assert(i1 == i2);
+
+ i1 = cast(int)(-c);
+ i2 = cast(int)(-cast(int)c);
+ assert(i1 == i2);
+ }
+
+ for (int i = 0; i < 256; ++i)
+ {
+ byte c = cast(byte)i;
+
+ int i1 = cast(int)(~c);
+ int i2 = cast(int)(~cast(int)c);
+
+ //printf("%d, %d\n", i1, i2);
+ assert(i1 == i2);
+
+ i1 = cast(int)(+c);
+ i2 = cast(int)(+cast(int)c);
+ assert(i1 == i2);
+
+ i1 = cast(int)(-c);
+ i2 = cast(int)(-cast(int)c);
+ assert(i1 == i2);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+
+void test18315() // https://issues.dlang.org/show_bug.cgi?id=18315
+{
+ int i = int.min;
+ bool b = i > 0;
+ assert(!b);
+ b = 0 < i;
+ assert(!b);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// https://issues.dlang.org/show_bug.cgi?id=18461
+
+void test18461()
+{
+ import core.bitop;
+
+ size_t test_val = 0b0001_0000;
+
+ if (bt(&test_val, 4) == 0)
+ assert(false);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+void test18730() // https://issues.dlang.org/show_bug.cgi?id=18730
+{
+ static if (size_t.sizeof == 8)
+ {
+ static int bt18730_64_64(in ulong* p, ulong bitnum) pure @system
+ {
+ return ((p[bitnum >> 6] & (1L << (bitnum & 63)))) != 0;
+ }
+ static int bt18730_64_32(in ulong* p, uint bitnum) pure @system
+ {
+ return ((p[bitnum >> 6] & (1L << (bitnum & 63)))) != 0;
+ }
+ static int bt18730_32_64(in uint* p, ulong bitnum) pure @system
+ {
+ return ((p[bitnum >> 5] & (1 << (bitnum & 31)))) != 0;
+ }
+
+ // Check that bt_64_64 uses a 64-bit register for the offset.
+ {
+ enum bitIndex = int.max + 1L;
+ auto a = new ulong[](bitIndex / 64 + 1);
+ a[bitIndex / 64] = 1;
+ assert(bt18730_64_64(a.ptr, bitIndex));
+ assert(!bt18730_64_64(a.ptr, bitIndex + 1));
+ assert(!bt18730_64_64(a.ptr, bitIndex - 1));
+ }
+ // Check that bt_64_32 uses a 32-bit register for the offset.
+ {
+ static int f(ulong* p, ulong bitnum)
+ {
+ return bt18730_64_32(p, cast(uint) bitnum);
+ }
+ enum bitIndex = uint.max + 1L;
+ assert(cast(uint) bitIndex == 0);
+ ulong s = 1;
+ assert(f(&s, bitIndex));
+ }
+ /* Check that bt_32_64 does not become a 64-bit bt instruction. Would lead
+ to a segfault when trying to load 8 bytes while only 4 are accessible. */
+ version (Posix)
+ {{
+ import core.sys.posix.sys.mman;
+ import core.sys.posix.unistd;
+ // Allocate two pages.
+ immutable sz = 2 * sysconf(_SC_PAGESIZE);
+ auto m = mmap(null, sz, PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0);
+ // Discard the higher page. It becomes unreadable.
+ munmap(m + sz / 2, sz / 2);
+ // Try looking at the last 4 bytes of the readable page.
+ uint* p = cast(uint*) (m + sz / 2 - uint.sizeof);
+ bt18730_32_64(p, 0);
+ munmap(m, sz / 2); // Free the readable page.
+ }}
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+
+void test19497() // https://issues.dlang.org/show_bug.cgi?id=19497
+{
+ {
+ ubyte[1024] data;
+ ushort* ushortPtr = cast(ushort*) data.ptr;
+ *ushortPtr++ = 0xfe00;
+ printf("ushortPtr(%p)\n", ushortPtr);
+ fflush(stdout);
+ }
+
+ alias Seq(stuff ...) = stuff;
+ static foreach (T; Seq!(ubyte, ushort, uint, ulong, byte, short, int, long))
+ {{
+ T[2] data = 0x2A;
+ T* q = &data[0];
+ *q++ = cast(T) 0x1122334455667788;
+ if (*q != 0x2A) assert(false);
+ }}
+
+ {
+ static int toStringz(string s) { return s.length > 0 ? s[0] : 0; }
+ static void toAStringz(in string[] a, int* az)
+ {
+ foreach (string s; a)
+ {
+ *az++ = toStringz(s);
+ }
+ }
+ string[1] sa = ["abc"];
+ int[2] tgt = 0x2a;
+ toAStringz(sa[], tgt.ptr);
+ if (tgt[0] != 'a') assert(false);
+ if (tgt[1] != 0x2a) assert(false);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// https://issues.dlang.org/show_bug.cgi?id=18794
+
+bool method18794(size_t* p)
+{
+ int bitIdx = 0;
+ func18794();
+ return (*p & (1UL << bitIdx)) != 0;
+}
+
+void func18794() {}
+
+void prep18794()
+{
+ asm {}
+ ulong[2] x = -1;
+}
+
+void test18794()
+{
+ prep18794();
+ size_t s;
+ method18794(&s);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+/* Test the optimization
+ * (e1+c)-e2 => (e1-e2)+c
+ */
+
+void testelmin()
+{
+ static void foo(int i)
+ {
+ static ubyte[4] bar()
+ {
+ ubyte[4] array;
+ foreach (i, ref a; array)
+ a = cast(ubyte)(i + 1);
+ return array;
+ }
+
+ static void test(int i, ubyte* p)
+ {
+ foreach (j; 0 .. 4)
+ assert(p[i * 4 + j] == j + 1);
+ }
+
+ ubyte[32] data;
+ data[i*4..(i+1)*4] = bar(); // optimize to single MOV
+
+ test(i, data.ptr);
+ }
+
+ foo(4);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+const(char)* fastpar(string s)
+{
+ return s.ptr + s.length;
+}
+
+void testfastpar()
+{
+ string s = "abcde";
+ auto p = fastpar(s);
+ assert(*p == 0);
+}
+
+////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=20363
+
+ulong foo20363(double d)
+{
+ ulong u = * cast(ulong*) &d;
+ return (u >> 1) & 1;
+}
+
+void test20363()
+{
+ ulong u = 0b10;
+ if (foo20363(*cast(double*) &u) == 0)
+ assert(false);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+
+T testfooa(T)(T value)
+{
+ return 10 - (value * 57); // gets rewritten into (value*-57)+10
+}
+
+T testfoob(T)(T value)
+{
+ return (value * -57) + 10;
+}
+
+void testNegConst()
+{
+ assert(testfooa(1) == -47);
+ assert(testfoob(1) == -47);
+ assert(testfooa(1.0) == -47);
+ assert(testfoob(1.0) == -47);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// https://issues.dlang.org/show_bug.cgi?id=16317
+
+int add8ret3(ref int s)
+{
+ s += 8;
+ return 3;
+}
+
+int binAdd(int val)
+{
+ val = val + add8ret3(val);
+ return val;
+}
+
+void test16317()
+{
+ assert(binAdd(1) == (1 + 3));
+ static assert(binAdd(1) == (1 + 3));
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// https://issues.dlang.org/show_bug.cgi?id=20050
+
+int test20050_g = 0;
+void test20050_impure_function_1() { ++test20050_g; }
+void function() test20050_get_impure_function() pure
+{
+ static void impure_function_2()
+ {
+ ++test20050_g;
+ test20050_impure_function_1();
+ }
+ return &impure_function_2;
+}
+void test20050()
+{
+ auto f = test20050_get_impure_function();
+ f();
+ assert(test20050_g == 2);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// http://github.com/dlang/dmd/pull/11238
+
+int testCpStatic1(int y)
+{
+ __gshared int yyy = 7;
+ auto x = yyy; // no copy-propagation
+ if (y)
+ return x;
+ return x + 3;
+}
+
+void testCpStatic()
+{
+ assert(testCpStatic1(1) == 7);
+ assert(testCpStatic1(0) == 10);
+}
+
+////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=20991
+
+int x7;
+
+void bar7(int i)
+{
+ assert(i == x7);
+ ++x7;
+}
+
+void test7()
+{
+ for (int i = 0; i <= 1; ++i)
+ bar7(i);
+ assert(x7 == 2);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// http://github.com/dlang/dmd/pull/11388
+
+ushort byteswap(ushort x) pure
+{
+ // Should be detected and XCHG instruction generated
+ return cast(ushort) (((x >> 8) & 0xFF) | ((x << 8) & 0xFF00u));
+}
+
+void testbyteswap()
+{
+ assert(byteswap(0xF234) == 0x34F2);
+ static ushort xx = 0xF234;
+ assert(byteswap(xx) == 0x34F2);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// These should all be recognized by the compiler and generate ROL or ROR
+// instructions.
+
+uint rol32(uint x, uint n)
+{
+ return (x << n) | (x >> (32 - n));
+}
+
+uint ror32(uint x, uint n)
+{
+ return (x >> n) | (x << (32 - n));
+}
+
+ulong rol64(ulong x, uint n)
+{
+ return (x << n) | (x >> (64 - n));
+}
+
+ulong ror64(ulong x, uint n)
+{
+ return (x >> n) | (x << (64 - n));
+}
+
+void testrolror()
+{
+ assert(ror32(0x0123_4567u, 4) == 0x7012_3456);
+ assert(rol32(0x7012_3456u, 4) == 0x0123_4567);
+
+ assert(ror64(0x0123_4567_89AB_CDEFuL, 4) == 0xF012_3456_789A_BCDE);
+ assert(rol64(0xF012_3456_789A_BCDEuL, 4) == 0x0123_4567_89AB_CDEF);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// https://issues.dlang.org/show_bug.cgi?id=20162
+
+void test20162()
+{
+ static long f(long a)
+ {
+ assert(a == -1L);
+ return a;
+ }
+
+ foreach (i; 1 .. 2)
+ {
+ foreach (j; 0 .. 2)
+ {
+ printf("%d %d %llx\n", i,
+ ((i != 0) ? -1 : +1),
+ f((i != 0) ? -1 : +1));
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=3713
+
+int star1(int i)
+{
+ return i ? star1(i - 1) : 0;
+}
+
+int star2(int i)
+{
+ return i == 0 ? 0 : star2(i - 1);
+}
+
+int star3(int i)
+{
+ if (i == 0)
+ return 0;
+ return i == 2 ? star3(i - 2) : star3(i - 1);
+}
+
+int star4(int i)
+{
+ return (i == 0) ? 0
+ : i != 2 ? star4(i - 1)
+ : star4(i - 2);
+}
+
+void test3713()
+{
+ assert(star1(10) == 0);
+ assert(star2(10) == 0);
+ assert(star3(10) == 0);
+ assert(star4(10) == 0);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+void testsbbrex()
+{
+ // special code is generated for these two cases
+ static long foolt(dchar c)
+ {
+ return c < 0x10000 ? 1 : 2;
+ }
+
+ static long fooge(uint c)
+ {
+ return c >= 0x10000 ? 1L : 2L;
+ }
+
+ assert(foolt(0) == 1);
+ assert(foolt(0x10000) == 2);
+ assert(fooge(0) == 2);
+ assert(fooge(0x10000) == 1);
+}
+
+
+////////////////////////////////////////////////////////////////////////
+
+// https://issues.dlang.org/show_bug.cgi?id=19846
+
+alias Void = byte[0];
+static immutable Void VOID; // = [];
+
+__gshared int x19846;
+
+Void print19846()
+{
+ //printf("This should print\n");
+ x19846 = 3;
+ return VOID;
+}
+
+Void identity19846(Void value, out int i)
+{
+ i = 7;
+ return value;
+}
+
+void test19846()
+{
+ int i;
+ identity19846(print19846(), i);
+ //printf("i = %d\n", i);
+ assert(x19846 == 3);
+ assert(i == 7);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// Some tests for OPmemcpy
+
+enum N = 128;
+
+ubyte[N] def()
+{
+ ubyte[N] array;
+ foreach (i, ref a; array)
+ a = cast(ubyte)(i + 1);
+ return array;
+}
+
+
+void ghi(ubyte* p)
+{
+ foreach (i; 0 .. N)
+ assert(p[i] == i + 1);
+}
+
+void testmemcpy()
+{
+ ubyte[N] bits;
+ ubyte[N] bits2;
+ bits2[0..N] = bits[0..N] = def();
+ ghi(bits.ptr);
+ ghi(bits2.ptr);
+
+ __gshared size_t n = N;
+ ubyte[N] bits3;
+ ubyte[N] bits4;
+ bits4[0..n] = bits3[0..n] = def();
+ ghi(bits3.ptr);
+ ghi(bits4.ptr);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+
+/* Test all the cases of uses of LEA for multiplication by a constant
+ */
+
+T testlea(uint C, T)(T x, T y)
+{
+ y = y * C; // cdmul()
+ x *= C; // cdmulass()
+ return x + y;
+}
+
+void testleax(uint C)(uint X, uint Y)
+{
+ assert(testlea!C(X,Y) == C * (X + Y));
+ assert(testlea!C(cast(long)X,cast(long)Y) == cast(long)C*X + cast(long)C*Y);
+}
+
+void testMulLea()
+{
+ testleax!3(10,11);
+ testleax!5(10,11);
+ testleax!6(10,11);
+ testleax!9(10,11);
+
+ testleax!10(10,11);
+ testleax!12(10,11);
+ testleax!18(10,11);
+ testleax!20(10,11);
+ testleax!24(10,11);
+ testleax!36(10,11);
+ testleax!40(10,11);
+ testleax!72(10,11);
+
+ testleax!37(10,11);
+ testleax!74(10,11);
+ testleax!13(10,11);
+ testleax!26(10,11);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+/* Test *= of register pair
+ */
+
+void testMulAssPair()
+{
+ static ulong pow(ulong x, int m)
+ {
+ ulong v = x;
+ ulong p = 1;
+ while (1)
+ {
+ if (m & 1)
+ p *= v;
+ m >>= 1;
+ if (!m)
+ break;
+ v *= v;
+ }
+ return p;
+ }
+
+ enum ulong e_10_pow_19 = 10uL^^19;
+ assert(e_10_pow_19 == pow(10uL, 19));
+}
+
+////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=21038
+
+const(wchar)* x21038 = "xz";
+const(dchar)* name21038 = "abcd";
+
+void test21038()
+{
+ assert((cast(size_t) x21038) % wchar.sizeof == 0);
+ assert((cast(size_t) name21038) % dchar.sizeof == 0);
+}
+
+////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=21325
+
+real f21325(const real x) pure @safe nothrow @nogc
+{
+ return (x != 0.0L) ? x : real.nan;
+}
+
+void test21325() @safe
+{
+ ulong x = 0uL;
+ while(true)
+ {
+ const y = f21325(x); // should set y to real.nan
+
+ assert(y != y);
+
+ if (++x)
+ return; // good
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=16274
+
+extern(C) int pair(short a, ushort b, byte c, ubyte d);
+
+struct S
+{
+ // provide alternate implementation of .pair()
+ pragma(mangle, "pair")
+ extern(C) static void pair(int a, int b, int c, int d)
+ {
+ //printf("%d %d %d %d\n", a, b, c, d);
+ assert(a == -1);
+ assert(b == 2);
+ assert(c == -3);
+ assert(d == 4);
+ }
+}
+
+void test16274()
+{
+ version (X86_64)
+ pair(-1, 2, -3, 4);
+ version (X86)
+ pair(-1, 2, -3, 4);
+}
+
+////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=16268
+
+void test16268()
+{
+ static void f(byte x)
+ {
+ for (byte i = 0; i <= x && i >= 0; ++i)
+ {
+ assert(i >= 0);
+ assert(i != -1);
+ //printf("%d\n", i);
+ }
+ }
+
+ f(byte.max);
+}
+
+////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=11435
+
+void test11435a()
+{
+ alias T = byte;
+
+ static void fun(T c, T b, int v)
+ {
+ }
+
+ static void abc(T[] b)
+ {
+ fun(b[0], b[1], 0);
+ }
+
+ version(Windows)
+ {
+ import core.sys.windows.windows;
+ auto p = VirtualAlloc(null, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ }
+ else
+ {
+ import core.sys.posix.sys.mman;
+ auto p = mmap(null, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0L);
+ }
+ assert(p);
+ auto px = (cast(T*)(p + 4096 - 2 * T.sizeof));
+ abc(px[0..2]);
+}
+
+void test11435b()
+{
+ import core.sys.windows.windows;
+ alias T = short;
+
+ static void fun(T c, T b, int v)
+ {
+ }
+
+ static void abc(T[] b)
+ {
+ fun(b[0], b[1], 0);
+ }
+
+ version(Windows)
+ {
+ import core.sys.windows.windows;
+ auto p = VirtualAlloc(null, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
+ }
+ else
+ {
+ import core.sys.posix.sys.mman;
+ auto p = mmap(null, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0L);
+ }
+ assert(p);
+ auto px = (cast(T*)(p + 4096 - 2 * T.sizeof));
+ abc(px[0..2]);
+}
+
+////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=21513
+
+struct Stuff
+{
+ size_t c; // declare after items and not crash !
+ ubyte[1] items;
+}
+
+void grow(ref Stuff stuff)
+{
+ with (stuff)
+ {
+ const oldCapacity = c;
+ items.ptr[0..oldCapacity] = items.ptr[0..0]; // use literal 0 instead of
+ items.ptr[0] = 0; // oldcapacity and no crash !
+ }
+}
+
+void test21513()
+{
+ Stuff stuff;
+ grow(stuff);
+}
+
+////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=21526
+
+double f21256(double a, double b) {
+ double c = a + b;
+ return c;
+}
+
+void test21256()
+{
+ union DX
+ {
+ double d;
+ ulong l;
+ }
+
+ DX a, b;
+ a.l = 0x4341c37937e08000;
+ b.l = 0x4007ffcb923a29c7;
+
+ DX r;
+ r.d = f21256(a.d, b.d);
+ //if (r.d != 0x1.1c37937e08001p+53)
+ //printf("r = %A should be 0x1.1c37937e08001p+53 %A\n", r.d, 0x1.1c37937e08001p+53);
+ //assert(r == 0x1.1c37937e08001p+53);
+
+ // cannot seem to get the two to produce the same value
+ assert(r.l == 0x4341c37937e08001 || // value using XMM
+ r.l == 0x4341c37937e08002); // value using x87
+}
+
+////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=21816
+
+bool test21816a(float t)
+{
+ return cast(bool)t;
+}
+
+void test21816()
+{
+ assert(test21816a(float.nan));
+}
+
+////////////////////////////////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=21835
+
+struct Point21835
+{
+ float f = 3.0;
+ double d = 4.0;
+ real r = 5.0;
+}
+
+void test21835y()
+{
+ Point21835[1] arr;
+ if (arr[0].f != 3.0) assert(0);
+ if (arr[0].d != 4.0) assert(0);
+ if (arr[0].r != 5.0) assert(0);
+}
+
+struct Point21835x
+{
+ float f = 0.0;
+ double d = 0.0;
+ real r = 0.0;
+}
+
+void test21835()
+{
+ test21835y();
+ Point21835x[1] arr;
+ if (arr[0].f != 0.0) assert(0);
+ if (arr[0].d != 0.0) assert(0);
+ if (arr[0].r != 0.0) assert(0);
+}
+
+////////////////////////////////////////////////////////////////////////
+
int main()
{
+ // All the various integer divide tests
+ testsdiv2();
+ testulldiv();
+ testfastudiv();
+ testsldiv();
+ testslmod();
+ testfastdiv();
+ testdivdiv();
+ testdivcmp();
+
testgoto();
testswitch();
testdo();
@@ -1675,11 +2491,8 @@ int main()
testsizes();
testarrayinit();
testU();
- testulldiv();
testbittest();
test8658();
- testfastudiv();
- testfastdiv();
test3918();
test12051();
testdocond();
@@ -1695,18 +2508,17 @@ int main()
test13190();
test13485();
test14436();
- test10639();
test10715();
test10678();
test7565();
test13023(0x10_0000_0000);
test12833();
test9449();
+ test9449x();
test12057();
test13784();
test14220();
test14829();
- test2();
test3();
test14782();
test14987();
@@ -1717,10 +2529,44 @@ int main()
test13474();
test16699();
test16102();
- testdivdiv();
test5();
test6();
testeqeqranges();
+ test16189();
+ test16997();
+ test18315();
+ test18461();
+ test18730();
+ test19497();
+ test18794();
+ testelmin();
+ testfastpar();
+ test20363();
+ testNegConst();
+ test16317();
+ test20050();
+ testCpStatic();
+ test7();
+ testbyteswap();
+ testrolror();
+ test20162();
+ test3713();
+ testsbbrex();
+ test19846();
+ testmemcpy();
+ testMulLea();
+ testMulAssPair();
+ test21038();
+ test21325();
+ test16274();
+ test16268();
+ test11435a();
+ test11435b();
+ test21513();
+ test21256();
+ test21816();
+ test21835();
+
printf("Success\n");
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/minimal.d b/gcc/testsuite/gdc.test/runnable/minimal.d
new file mode 100644
index 0000000..2f2df71
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/minimal.d
@@ -0,0 +1,8 @@
+// DFLAGS:
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -defaultlib=
+// EXTRA_SOURCES: extra-files/minimal/object.d
+
+// This test ensures an empty main can be built and executed with a minimal runtime
+
+void main() { }
diff --git a/gcc/testsuite/gdc.test/runnable/minimal2.d b/gcc/testsuite/gdc.test/runnable/minimal2.d
new file mode 100644
index 0000000..7319463
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/minimal2.d
@@ -0,0 +1,46 @@
+// DFLAGS:
+// REQUIRED_ARGS: -defaultlib=
+// EXTRA_SOURCES: extra-files/minimal/object.d
+
+// This test ensures that interfaces and classes can be used in a minimal
+// runtime as long as they only contain shared static members. Non-shared
+// static members would require a thread-local storage (TLS) implementation.
+
+interface I
+{
+ shared static int i;
+}
+
+class A : I
+{
+ shared static int a;
+}
+
+class B : A
+{
+ shared static int b;
+
+ static int sumAll()
+ {
+ return b + a + i;
+ }
+}
+
+void poorMansAssert(bool condition)
+{
+ if (!condition)
+ {
+ static char* hlt;
+ *hlt = 0;
+ }
+}
+
+void main()
+{
+ B.i = 32;
+ B.a = 42;
+ B.b = 52;
+
+ poorMansAssert(B.i == 32 || B.a == 42 || B.b == 52);
+ poorMansAssert(B.sumAll() == (32 + 42 + 52));
+}
diff --git a/gcc/testsuite/gdc.test/runnable/mixin1.d b/gcc/testsuite/gdc.test/runnable/mixin1.d
index 9d88fbd..d8b5516 100644
--- a/gcc/testsuite/gdc.test/runnable/mixin1.d
+++ b/gcc/testsuite/gdc.test/runnable/mixin1.d
@@ -1,7 +1,61 @@
-// RUNNABLE_PHOBOS_TEST
+/*
+TEST_OUTPUT:
+---
+runnable/mixin1.d(948): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+---
+
+RUN_OUTPUT:
+---
+Foo3.func()
+Code3.func()
+Foo4.func()
+Foo5.func()
+b.x = 5
+x = 5
+duff_for(1, 11)
+fid = 1, 2
+foo12
+foo12
+foo13 j = 1
+foo13 j = 1
+x14 = 6
+x15 = 6
+bar15() = 5
+x16 = 6
+bar() = 5
+x17 = 5
+b.x17 = 5
+x17 = 3
+x17 = 5
+x17 = 4
+x17 = 3
+x17 = 5
+in C20.f()
+B22.foo()
+5
+5
+a = 0
+int
+int
+int
+int
+foo 1
+foo 2
+0 0
+two
+one
+one
+Class39 dtor
+Mixed-in dtor
+Mixed-in dtor
+Base39 dtor
+Success
+---
+*/
+
module mixin1;
-import std.stdio;
+import core.stdc.stdio;
alias TypeTuple(T...) = T;
@@ -680,7 +734,11 @@ class A30
{
this(Type[] arr)
{
- foreach(Type v; arr) writeln(typeid(typeof(v)));
+ foreach(Type v; arr)
+ {
+ const str = typeid(typeof(v)).toString();
+ printf("%.*s\n", cast(int)str.length, str.ptr);
+ }
}
}
@@ -744,11 +802,6 @@ template T33( int i )
printf("foo %d\n", i );
return i;
}
- int opCall()
- {
- printf("opCall %d\n", i );
- return i;
- }
}
@@ -766,10 +819,6 @@ void test33()
assert(i == 1);
i = c1.t2.foo();
assert(i == 2);
- i = c1.t1();
- assert(i == 1);
- i = c1.t2();
- assert(i == 2);
}
@@ -825,7 +874,6 @@ struct Foo36
void test36()
{
Foo36 f;
- printf("f.sizeof = %d\n", f.sizeof);
assert(f.sizeof == 12);
f.a = 1;
@@ -932,7 +980,7 @@ class Class39 : Base39
void test39()
{
- auto test = new Class39;
+ scope test = new Class39;
}
@@ -974,7 +1022,7 @@ void test41()
}
/*******************************************/
-// 2245
+// https://issues.dlang.org/show_bug.cgi?id=2245
template TCALL2245a(ARGS...)
{
@@ -1044,7 +1092,7 @@ void test2245()
}
/*******************************************/
-// 2481
+// https://issues.dlang.org/show_bug.cgi?id=2481
template M2481() { int i; }
class Z2481a { struct { mixin M2481!(); } }
@@ -1058,7 +1106,7 @@ void test2481()
}
/*******************************************/
-// 2740
+// https://issues.dlang.org/show_bug.cgi?id=2740
interface IFooable2740
{
@@ -1144,7 +1192,7 @@ void test42()
}
/*******************************************/
-// 7744
+// https://issues.dlang.org/show_bug.cgi?id=7744
class ZeroOrMore7744(Expr)
{
@@ -1165,7 +1213,7 @@ mixin(q{
});
/*******************************************/
-// 8032
+// https://issues.dlang.org/show_bug.cgi?id=8032
mixin template T8032()
{
@@ -1193,7 +1241,7 @@ class B8032b : A8032b
}
/*********************************************/
-// 9417
+// https://issues.dlang.org/show_bug.cgi?id=9417
mixin template Foo9417()
{
@@ -1209,7 +1257,7 @@ void test9417()
}
/*******************************************/
-// 11487
+// https://issues.dlang.org/show_bug.cgi?id=11487
template X11487()
{
@@ -1236,7 +1284,7 @@ class C11487
}
/*******************************************/
-// 11767
+// https://issues.dlang.org/show_bug.cgi?id=11767
mixin template M11767()
{
@@ -1262,7 +1310,7 @@ void test11767()
}
/*******************************************/
-// 12023
+// https://issues.dlang.org/show_bug.cgi?id=12023
void Delete12023(Object obj) {}
@@ -1303,7 +1351,7 @@ void test12023()
}
/*******************************************/
-// 14243
+// https://issues.dlang.org/show_bug.cgi?id=14243
mixin template Mix14243a(int n)
{
@@ -1397,7 +1445,7 @@ int test14243()
static assert(test14243()); // changed to be workable
/*******************************************/
-// 10492
+// https://issues.dlang.org/show_bug.cgi?id=10492
class TestClass10492 {}
diff --git a/gcc/testsuite/gdc.test/runnable/mixin2.d b/gcc/testsuite/gdc.test/runnable/mixin2.d
index 26a2352..7679bbe 100644
--- a/gcc/testsuite/gdc.test/runnable/mixin2.d
+++ b/gcc/testsuite/gdc.test/runnable/mixin2.d
@@ -1,4 +1,4 @@
-/* RUNNABLE_PHOBOS_TEST
+/*
TEST_OUTPUT:
---
hello
@@ -31,7 +31,7 @@ hey
Success
---
*/
-import std.stdio;
+import core.stdc.stdio;
/*********************************************/
@@ -53,7 +53,7 @@ void test2()
mixin("
int x = 3;
for (int i = 0; i < 10; i++)
- writeln(x + i, ++j);
+ printf(\"%d%d\n\", x + i, ++j);
");
assert(j == 10);
}
@@ -64,7 +64,7 @@ mixin("int abc3 = 5;");
void test3()
{
- writeln(abc3);
+ printf("%d\n", abc3);
assert(abc3 == 5);
}
@@ -73,24 +73,24 @@ void test3()
mixin("
void test4()
{
- writeln(\"test4\");
+ printf(\"test4\n\");
" ~ "}");
/*********************************************/
int x5;
-scope class Foo5
+class Foo5
{
this ()
{
- writeln ("Constructor");
+ printf ("Constructor\n");
assert(x5 == 0);
x5++;
}
~this ()
{
- writeln ("Destructor");
+ printf ("Destructor\n");
assert(x5 == 2);
x5++;
}
@@ -100,7 +100,7 @@ void test5()
{
{
mixin ("scope Foo5 f = new Foo5;\n");
- writeln (" Inside Scope");
+ printf (" Inside Scope\n");
assert(x5 == 1);
x5++;
}
@@ -194,7 +194,7 @@ void test10()
}
/*********************************************/
-// 7560
+// https://issues.dlang.org/show_bug.cgi?id=7560
class Base7560
{
@@ -213,7 +213,7 @@ class Derived7560 : Base7560
}
/*********************************************/
-// 10577
+// https://issues.dlang.org/show_bug.cgi?id=10577
enum sync10577;
@@ -267,7 +267,7 @@ class derived10577 : base10577
}
/*********************************************/
-// 10583
+// https://issues.dlang.org/show_bug.cgi?id=10583
enum sync10583;
@@ -329,7 +329,7 @@ void test7156()
}
/*********************************************/
-// 7553
+// https://issues.dlang.org/show_bug.cgi?id=7553
template Foo7553()
{
@@ -358,7 +358,7 @@ void test7553()
}
/*********************************************/
-// 13479
+// https://issues.dlang.org/show_bug.cgi?id=13479
mixin template F13479()
{
@@ -392,5 +392,5 @@ void main()
test7156();
test13479();
- writeln("Success");
+ printf("Success\n");
}
diff --git a/gcc/testsuite/gdc.test/runnable/mod1.d b/gcc/testsuite/gdc.test/runnable/mod1.d
index 3efb0cf..46b14ed 100644
--- a/gcc/testsuite/gdc.test/runnable/mod1.d
+++ b/gcc/testsuite/gdc.test/runnable/mod1.d
@@ -1,5 +1,11 @@
-// PERMUTE_ARGS:
-// EXTRA_SOURCES: imports/mod2.d
+/*
+PERMUTE_ARGS:
+EXTRA_SOURCES: imports/mod2.d
+RUN_OUTPUT:
+---
+EvilOne
+---
+*/
// mod1.d
diff --git a/gcc/testsuite/gdc.test/runnable/nan.d b/gcc/testsuite/gdc.test/runnable/nan.d
index b229fd5..d4e4ae4 100644
--- a/gcc/testsuite/gdc.test/runnable/nan.d
+++ b/gcc/testsuite/gdc.test/runnable/nan.d
@@ -20,6 +20,43 @@ static assert(!(ed1 <= ed2));
bool b;
+
+T byCTFE(T)()
+{
+ T x;
+ return x;
+}
+
+bool bittst(const ubyte[] ba, uint pos)
+{
+ uint mask = 1 << (pos % 8);
+ version(LittleEndian)
+ return (ba[pos / 8] & mask) != 0;
+ else
+ return (ba[$ - 1 - pos / 8] & mask) != 0;
+}
+
+void test2(T)()
+{
+ T a = T.init, b = T.nan;
+ assert(a is b);
+
+ enum c = byCTFE!T();
+ assert(a is c);
+
+ static if (T.mant_dig == 64 && T.max_exp == 16384)
+ enum size = 10; // x87, exclude padding
+ else
+ enum size = T.sizeof;
+ const pa = (cast(ubyte*) &a)[0 .. size];
+
+ // the highest 2 bits of the mantissa should be set, everything else zero
+ assert(bittst(pa, T.mant_dig - 1));
+ assert(bittst(pa, T.mant_dig - 2));
+ foreach(p; 0..T.mant_dig - 2)
+ assert(!bittst(pa, p));
+}
+
bool test()
{
real r1 = real.nan;
@@ -53,5 +90,8 @@ bool test()
void main()
{
- assert(test());
+ assert(test());
+ test2!float();
+ test2!double();
+ test2!real();
}
diff --git a/gcc/testsuite/gdc.test/runnable/nested.d b/gcc/testsuite/gdc.test/runnable/nested.d
index 6b2fcb0..4c99c59 100644
--- a/gcc/testsuite/gdc.test/runnable/nested.d
+++ b/gcc/testsuite/gdc.test/runnable/nested.d
@@ -863,8 +863,8 @@ class Foo35
//writefln("y = %s", y);
assert(x == 42);
assert(y == 43);
- //static assert(is(typeof(this.outer) == void*)); // Bugzilla 14442
- static assert(is(typeof(this.outer) == Foo35)); // Bugzilla 15839
+ //static assert(is(typeof(this.outer) == void*)); // https://issues.dlang.org/show_bug.cgi?id=14442
+ static assert(is(typeof(this.outer) == Foo35)); // https://issues.dlang.org/show_bug.cgi?id=15839
}
};
}
@@ -1485,7 +1485,20 @@ void test55()
}
/*******************************************/
-// 4401
+
+enum dg56 = delegate { return 5; };
+
+void test56()
+{
+ auto inner() {
+ return dg56();
+ }
+
+ assert(inner() == 5);
+}
+
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=4401
void test4401()
{
@@ -1542,7 +1555,7 @@ void test7428(){
}
/*******************************************/
-// 4612
+// https://issues.dlang.org/show_bug.cgi?id=4612
struct S4612a(alias x)
{
@@ -1604,7 +1617,7 @@ void test7199()
}
/*******************************************/
-// 7965
+// https://issues.dlang.org/show_bug.cgi?id=7965
void test7965()
{
@@ -1662,7 +1675,7 @@ void test7965a()
}
/*******************************************/
-// 8188
+// https://issues.dlang.org/show_bug.cgi?id=8188
mixin template Print8188(b...)
{
@@ -1687,7 +1700,7 @@ void test8188()
}
/*******************************************/
-// 5082
+// https://issues.dlang.org/show_bug.cgi?id=5082
struct S5082 { float x; }
@@ -1714,7 +1727,7 @@ void test5082()
/*******************************************/
-// 8194
+// https://issues.dlang.org/show_bug.cgi?id=8194
void test8194()
{
@@ -1727,7 +1740,7 @@ void test8194()
}
/*******************************************/
-// 8339
+// https://issues.dlang.org/show_bug.cgi?id=8339
template map8339a(fun...)
{
@@ -1822,7 +1835,7 @@ void test8339c()
}
/*******************************************/
-// 8704
+// https://issues.dlang.org/show_bug.cgi?id=8704
void check8704(T, int num)()
{
@@ -1849,7 +1862,7 @@ void test8704()
}
/*******************************************/
-// 8923
+// https://issues.dlang.org/show_bug.cgi?id=8923
void test8923a()
{
@@ -2029,7 +2042,7 @@ void test8923c()
}
/*******************************************/
-// 9003
+// https://issues.dlang.org/show_bug.cgi?id=9003
void test9003()
{
@@ -2072,7 +2085,7 @@ void test9003()
}
/*******************************************/
-// 9006
+// https://issues.dlang.org/show_bug.cgi?id=9006
void test9006()
{
@@ -2101,7 +2114,7 @@ void test9006()
}
/*******************************************/
-// 9035
+// https://issues.dlang.org/show_bug.cgi?id=9035
void test9035()
{
@@ -2144,7 +2157,7 @@ void test9035a()
}
/*******************************************/
-// 9036
+// https://issues.dlang.org/show_bug.cgi?id=9036
void test9036()
{
@@ -2201,7 +2214,7 @@ void test8863()
+/
/*******************************************/
-// 8774
+// https://issues.dlang.org/show_bug.cgi?id=8774
void popFront8774()
{
@@ -2274,7 +2287,7 @@ void test8832()
}
/*******************************************/
-// 9315
+// https://issues.dlang.org/show_bug.cgi?id=9315
auto test9315()
{
@@ -2287,7 +2300,7 @@ auto test9315()
}
/*******************************************/
-// 9244
+// https://issues.dlang.org/show_bug.cgi?id=9244
void test9244()
{
@@ -2298,7 +2311,7 @@ void test9244()
}
/*******************************************/
-// 10495
+// https://issues.dlang.org/show_bug.cgi?id=10495
struct X10495
{
@@ -2321,7 +2334,7 @@ class C10495
}
/*******************************************/
-// 11385
+// https://issues.dlang.org/show_bug.cgi?id=11385
auto map11385(alias fun, R)(R range)
{
@@ -2354,6 +2367,12 @@ enum foo11297 = function (int x)
xmap!(y => x)(7);
};
+enum goo11297 = delegate (int x)
+ {
+ //int bar(int y) { return x; } xmap!bar(7);
+ xmap!(y => x)(7);
+ };
+
void xreduce(alias f)()
{
f(4);
@@ -2362,10 +2381,11 @@ void xreduce(alias f)()
void test11297()
{
xreduce!foo11297();
+ xreduce!goo11297();
}
/*******************************************/
-// 11886
+// https://issues.dlang.org/show_bug.cgi?id=11886
struct Lambda11886(alias fun)
{
@@ -2388,7 +2408,7 @@ void test11886()
}
/*******************************************/
-// 12234
+// https://issues.dlang.org/show_bug.cgi?id=12234
void test12234()
{
@@ -2407,7 +2427,7 @@ void test12234()
}
/*******************************************/
-// 12981
+// https://issues.dlang.org/show_bug.cgi?id=12981
template Mix12981(T)
{
@@ -2425,7 +2445,7 @@ class B12981
}
/*******************************************/
-// 13861
+// https://issues.dlang.org/show_bug.cgi?id=13861
struct Foo13861(alias f)
{
@@ -2444,7 +2464,7 @@ void test13861()
}
/*******************************************/
-// 14398
+// https://issues.dlang.org/show_bug.cgi?id=14398
void test14398()
{
@@ -2479,7 +2499,7 @@ void test14398()
}
/*******************************************/
-// 14846
+// https://issues.dlang.org/show_bug.cgi?id=14846
void foo14846(Dg)(scope Dg code)
{
@@ -2509,14 +2529,14 @@ void test14846()
}
/*******************************************/
-// 15422
+// https://issues.dlang.org/show_bug.cgi?id=15422
class App15422(T)
{
this() {}
auto test1(T val)
- in {} body // necessary to reproduce the crash
+ in {} do // necessary to reproduce the crash
{
struct Foo
{
@@ -2544,7 +2564,7 @@ class App15422(T)
}
auto test2(T val)
- //in {} body
+ //in {} do
{
int closVar;
struct Foo
@@ -2662,7 +2682,7 @@ void test15422b()
}
/***************************************************/
-// 15757
+// https://issues.dlang.org/show_bug.cgi?id=15757
template map15757(fun...)
{
@@ -2703,6 +2723,45 @@ void test15757() @safe
/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19384
+
+struct Vec
+{
+ uint item;
+
+ ref uint august() return
+ {
+ return item;
+ // commenting next line removes bug
+ foreach(ref val; range()) return val;
+ assert(false);
+ }
+
+ uint* august2() return
+ {
+ return &item;
+ foreach(ref val; range()) return &val;
+ assert(false);
+ }
+}
+
+struct range
+{
+ int opApply(scope int delegate(ref uint) dg) { return 0; }
+}
+
+void test19384()
+{
+ Vec preds = Vec(0xDEAD);
+ void* ptr2 = &preds.august();
+ void* ptr3 = preds.august2();
+ assert(&preds == ptr2);
+ assert(&preds == ptr3);
+}
+
+
+/***************************************************/
+
int main()
{
test1();
@@ -2760,6 +2819,7 @@ int main()
test53();
test54();
test55();
+ test56();
test4401();
test7428();
test4612();
@@ -2797,6 +2857,7 @@ int main()
test15422a();
test15422b();
test15757();
+ test19384();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/newdel.d b/gcc/testsuite/gdc.test/runnable/newdel.d
index 21f7809..3729b2e 100644
--- a/gcc/testsuite/gdc.test/runnable/newdel.d
+++ b/gcc/testsuite/gdc.test/runnable/newdel.d
@@ -1,4 +1,10 @@
// PERMUTE_ARGS:
+/*
+TEST_OUTPUT:
+---
+runnable/newdel.d(46): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+---
+*/
import core.stdc.stdio;
import core.stdc.stdlib;
@@ -9,18 +15,6 @@ class Foo
{
static uint flags;
- new(size_t sz, int x)
- { void* p;
-
- printf("Foo.new(sz = %d, x = %d)\n", sz, x);
- assert(sz == Foo.classinfo.initializer.length);
- assert(x == 5);
-
- p = core.stdc.stdlib.malloc(sz);
- flags |= 4;
- return p;
- }
-
this()
{
printf("this() %p\n", this);
@@ -34,13 +28,6 @@ class Foo
flags |= 1;
}
- delete(void* p)
- {
- printf("delete %p\n", p);
- free(p);
- flags |= 2;
- }
-
int a = 3;
int b = 4;
int d = 56;
@@ -50,61 +37,22 @@ void test1()
{
Foo f;
- f = new(5) Foo;
+ f = new Foo();
assert(f.a == 36);
assert(f.b == 4);
assert(f.d == 56);
- assert(Foo.flags == 4);
-
- delete f;
- assert(Foo.flags == 7);
-}
-
-
-/*********************************************/
-
-struct Foo2
-{
- static uint flags;
-
- new(size_t sz, int x)
- { void* p;
-
- printf("Foo2.new(sz = %d, x = %d)\n", sz, x);
- assert(sz == Foo2.sizeof);
- assert(x == 5);
-
- p = core.stdc.stdlib.malloc(sz);
- flags |= 4;
- return p;
- }
-
- delete(void *p)
- {
- printf("p = %p\n", p);
- flags |= 2;
- core.stdc.stdlib.free(p);
- }
-}
+ assert(Foo.flags == 0);
-void test2()
-{
- Foo2 *f = new(5) Foo2();
-
- printf("f = %p\n", f);
delete f;
- assert(Foo2.flags == 6);
+ assert(Foo.flags == 1);
}
-
/*********************************************/
int main()
{
test1();
- test2();
printf("Success\n");
return 0;
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/nogc.d b/gcc/testsuite/gdc.test/runnable/nogc.d
index 8214e96..c9a58b7 100644
--- a/gcc/testsuite/gdc.test/runnable/nogc.d
+++ b/gcc/testsuite/gdc.test/runnable/nogc.d
@@ -1,3 +1,9 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
extern(C) int printf(const char*, ...);
@@ -9,7 +15,7 @@ extern(C) int printf(const char*, ...);
}
/***********************/
-// 3032
+// https://issues.dlang.org/show_bug.cgi?id=3032
void test3032() @nogc
{
@@ -23,7 +29,7 @@ void test3032() @nogc
}
/***********************/
-// 12642
+// https://issues.dlang.org/show_bug.cgi?id=12642
__gshared int[1] data12642;
@@ -44,7 +50,7 @@ void test12642() @nogc
}
/***********************/
-// 12936
+// https://issues.dlang.org/show_bug.cgi?id=12936
void test12936() @nogc
{
diff --git a/gcc/testsuite/gdc.test/runnable/nulltype.d b/gcc/testsuite/gdc.test/runnable/nulltype.d
index 7a1f1c3..87d7940 100644
--- a/gcc/testsuite/gdc.test/runnable/nulltype.d
+++ b/gcc/testsuite/gdc.test/runnable/nulltype.d
@@ -58,7 +58,7 @@ void test2()
}
/**********************************************/
-// 5899
+// https://issues.dlang.org/show_bug.cgi?id=5899
auto f5899(bool b)
{
@@ -91,7 +91,7 @@ static assert(is(typeof(h5899) R == return) && is(R == int[]));
pragma(msg, typeof(h5899));
/**********************************************/
-// 7278
+// https://issues.dlang.org/show_bug.cgi?id=7278
struct Foo7278(string s)
{
@@ -109,7 +109,7 @@ void test7278()
}
/**********************************************/
-// 8221
+// https://issues.dlang.org/show_bug.cgi?id=8221
class A8221
{
@@ -130,7 +130,7 @@ void test8221()
}
/***************************************************/
-// 8589
+// https://issues.dlang.org/show_bug.cgi?id=8589
void test8589()
{
@@ -157,7 +157,7 @@ void test8589()
}
/**********************************************/
-// 9385
+// https://issues.dlang.org/show_bug.cgi?id=9385
void test9385()
{
@@ -167,7 +167,7 @@ void test9385()
}
/**********************************************/
-// 12203
+// https://issues.dlang.org/show_bug.cgi?id=12203
void test12203()
{
diff --git a/gcc/testsuite/gdc.test/runnable/opdisp.d b/gcc/testsuite/gdc.test/runnable/opdisp.d
index f84a0ec..6aca559 100644
--- a/gcc/testsuite/gdc.test/runnable/opdisp.d
+++ b/gcc/testsuite/gdc.test/runnable/opdisp.d
@@ -1,3 +1,9 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
extern (C) int printf(const char* fmt, ...);
int pass(int n){ return n; }
@@ -265,7 +271,7 @@ void test6()
}
/**********************************************/
-// 7578
+// https://issues.dlang.org/show_bug.cgi?id=7578
struct Foo7578
{
diff --git a/gcc/testsuite/gdc.test/runnable/opover.d b/gcc/testsuite/gdc.test/runnable/opover.d
index 66270f4..633981e 100644
--- a/gcc/testsuite/gdc.test/runnable/opover.d
+++ b/gcc/testsuite/gdc.test/runnable/opover.d
@@ -1,5 +1,29 @@
+/*
+RUN_OUTPUT:
+---
+i = 1
+Writer.opShl(char[])
+BinaryWriter.opShl(int)
+a + 1 = 2
+1 + a = 2
+a + b = 3
+b + a = 3
+i = 64
+12
+534
+A::opShl(int 4)
+4A::opShl(char[])
+ A::opShl(int 12)
+12A::opShl(char[])
+
+B::opShl_r(A)
+Success
+---
+*/
// Test operator overloading
+// Ignore deprecation warnings for D1 style operator overloading
+// TRANSFORM_OUTPUT: remove_lines("Deprecation: `op")
import core.stdc.stdio;
@@ -776,7 +800,7 @@ class A13
A13 opShl(string x)
{
printf("A::opShl(char[])\n");
- printf("%.*s", x.length, x.ptr);
+ printf("%.*s", cast(int)x.length, x.ptr);
return this;
}
}
@@ -821,7 +845,7 @@ void test14()
/**************************************/
-// 3983
+// https://issues.dlang.org/show_bug.cgi?id=3983
struct Fug
{
@@ -849,7 +873,7 @@ void test15()
}
/**************************************/
-// 4953
+// https://issues.dlang.org/show_bug.cgi?id=4953
struct S4953a
{
@@ -907,7 +931,7 @@ void test4953d()
}
/**************************************/
-// 4993
+// https://issues.dlang.org/show_bug.cgi?id=4993
// reduced from the bug report
struct Bar4993
@@ -924,7 +948,7 @@ void test4993()
}
/**************************************/
-// 8133
+// https://issues.dlang.org/show_bug.cgi?id=8133
void test8133()
{
@@ -942,7 +966,7 @@ void test8133()
}
/**************************************/
-// 8522
+// https://issues.dlang.org/show_bug.cgi?id=8522
struct Point8522
{
@@ -961,7 +985,7 @@ void test8522()
}
/**************************************/
-// 12778
+// https://issues.dlang.org/show_bug.cgi?id=12778
struct Vec12778X
{
@@ -1009,7 +1033,7 @@ void test12778()
}
/**************************************/
-// 14343
+// https://issues.dlang.org/show_bug.cgi?id=14343
struct S14343a
{
@@ -1049,7 +1073,7 @@ void test14343()
}
/**************************************/
-// 14344
+// https://issues.dlang.org/show_bug.cgi?id=14344
struct S14344
{
@@ -1080,7 +1104,41 @@ class C14344
}
/**************************************/
+// https://issues.dlang.org/show_bug.cgi?id=1547
+struct A
+{
+ int b;
+ static A opCall(int k)
+ {
+ assert(0);
+ }
+ this(int) {}
+}
+
+void fun(A k = 2) {}
+
+void test1547()
+{
+ fun();
+}
+/**************************************/
+// https://issues.dlang.org/show_bug.cgi?id=20475
+struct S20475
+{
+ string[2] x;
+}
+
+void test20475()
+{
+ auto s = S20475(["abc", "bcd"]);
+ auto t = S20475(["abc", ""]);
+ string u = "abcd";
+ t.x[1] = u[1..$];
+ assert(s == t);
+}
+
+/**************************************/
int main()
{
test1();
@@ -1098,6 +1156,7 @@ int main()
test13();
test14();
test15();
+ test1547();
test4953a();
test4953b();
test4953c();
@@ -1105,6 +1164,7 @@ int main()
test4993();
test8133();
test8522();
+ test20475();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/opover2.d b/gcc/testsuite/gdc.test/runnable/opover2.d
index 78fa04c..dfc0352 100644
--- a/gcc/testsuite/gdc.test/runnable/opover2.d
+++ b/gcc/testsuite/gdc.test/runnable/opover2.d
@@ -1,5 +1,5 @@
-// PERMUTE_ARGS: -inline -O -property
-// REQUIRED_ARGS: -dip25
+// PERMUTE_ARGS: -inline -O
+// REQUIRED_ARGS: -preview=fieldwise
// Test operator overloading
@@ -21,7 +21,7 @@ class A
{
string opUnary(string s)()
{
- printf("A.opUnary!(%.*s)\n", s.length, s.ptr);
+ printf("A.opUnary!(%.*s)\n", cast(int)s.length, s.ptr);
return s;
}
}
@@ -50,7 +50,7 @@ class A2
T opCast(T)()
{
auto s = T.stringof;
- printf("A.opCast!(%.*s)\n", s.length, s.ptr);
+ printf("A.opCast!(%.*s)\n", cast(int)s.length, s.ptr);
return T.init;
}
}
@@ -73,20 +73,20 @@ struct A3
{
int opBinary(string s)(int i)
{
- printf("A.opBinary!(%.*s)\n", s.length, s.ptr);
+ printf("A.opBinary!(%.*s)\n", cast(int)s.length, s.ptr);
return 0;
}
int opBinaryRight(string s)(int i) if (s == "/" || s == "*")
{
- printf("A.opBinaryRight!(%.*s)\n", s.length, s.ptr);
+ printf("A.opBinaryRight!(%.*s)\n", cast(int)s.length, s.ptr);
return 0;
}
T opCast(T)()
{
auto s = T.stringof;
- printf("A.opCast!(%.*s)\n", s.length, s.ptr);
+ printf("A.opCast!(%.*s)\n", cast(int)s.length, s.ptr);
return T.init;
}
}
@@ -108,14 +108,14 @@ struct A4
{
int opUnary(string s)()
{
- printf("A.opUnary!(%.*s)\n", s.length, s.ptr);
+ printf("A.opUnary!(%.*s)\n", cast(int)s.length, s.ptr);
return 0;
}
T opCast(T)()
{
auto s = T.stringof;
- printf("A.opCast!(%.*s)\n", s.length, s.ptr);
+ printf("A.opCast!(%.*s)\n", cast(int)s.length, s.ptr);
return T.init;
}
}
@@ -145,14 +145,14 @@ class A5
int opUnary(string s)()
{
- printf("A.opUnary!(%.*s)\n", s.length, s.ptr);
+ printf("A.opUnary!(%.*s)\n", cast(int)s.length, s.ptr);
return 0;
}
T opCast(T)()
{
auto s = T.stringof;
- printf("A.opCast!(%.*s)\n", s.length, s.ptr);
+ printf("A.opCast!(%.*s)\n", cast(int)s.length, s.ptr);
return T.init;
}
}
@@ -296,31 +296,31 @@ struct A8
{
int opUnary(string s)()
{
- printf("A.opUnary!(%.*s)\n", s.length, s.ptr);
+ printf("A.opUnary!(%.*s)\n", cast(int)s.length, s.ptr);
return 0;
}
int opIndexUnary(string s, T)(T i)
{
- printf("A.opIndexUnary!(%.*s)(%d)\n", s.length, s.ptr, i);
+ printf("A.opIndexUnary!(%.*s)(%d)\n", cast(int)s.length, s.ptr, i);
return 0;
}
int opIndexUnary(string s, T)(T i, T j)
{
- printf("A.opIndexUnary!(%.*s)(%d, %d)\n", s.length, s.ptr, i, j);
+ printf("A.opIndexUnary!(%.*s)(%d, %d)\n", cast(int)s.length, s.ptr, i, j);
return 0;
}
int opSliceUnary(string s)()
{
- printf("A.opSliceUnary!(%.*s)()\n", s.length, s.ptr);
+ printf("A.opSliceUnary!(%.*s)()\n", cast(int)s.length, s.ptr);
return 0;
}
int opSliceUnary(string s, T)(T i, T j)
{
- printf("A.opSliceUnary!(%.*s)(%d, %d)\n", s.length, s.ptr, i, j);
+ printf("A.opSliceUnary!(%.*s)(%d, %d)\n", cast(int)s.length, s.ptr, i, j);
return 0;
}
}
@@ -344,31 +344,31 @@ struct A9
{
int opOpAssign(string s)(int i)
{
- printf("A.opOpAssign!(%.*s)\n", s.length, s.ptr);
+ printf("A.opOpAssign!(%.*s)\n", cast(int)s.length, s.ptr);
return 0;
}
int opIndexOpAssign(string s, T)(int v, T i)
{
- printf("A.opIndexOpAssign!(%.*s)(%d, %d)\n", s.length, s.ptr, v, i);
+ printf("A.opIndexOpAssign!(%.*s)(%d, %d)\n", cast(int)s.length, s.ptr, v, i);
return 0;
}
int opIndexOpAssign(string s, T)(int v, T i, T j)
{
- printf("A.opIndexOpAssign!(%.*s)(%d, %d, %d)\n", s.length, s.ptr, v, i, j);
+ printf("A.opIndexOpAssign!(%.*s)(%d, %d, %d)\n", cast(int)s.length, s.ptr, v, i, j);
return 0;
}
int opSliceOpAssign(string s)(int v)
{
- printf("A.opSliceOpAssign!(%.*s)(%d)\n", s.length, s.ptr, v);
+ printf("A.opSliceOpAssign!(%.*s)(%d)\n", cast(int)s.length, s.ptr, v);
return 0;
}
int opSliceOpAssign(string s, T)(int v, T i, T j)
{
- printf("A.opSliceOpAssign!(%.*s)(%d, %d, %d)\n", s.length, s.ptr, v, i, j);
+ printf("A.opSliceOpAssign!(%.*s)(%d, %d, %d)\n", cast(int)s.length, s.ptr, v, i, j);
return 0;
}
}
@@ -468,7 +468,7 @@ int bug4913()
static assert(bug4913() == 83);
/**************************************/
-// 5551
+// https://issues.dlang.org/show_bug.cgi?id=5551
struct Foo11 {
Foo11 opUnary(string op:"++")() {
@@ -486,7 +486,7 @@ void test11()
}
/**************************************/
-// 4099
+// https://issues.dlang.org/show_bug.cgi?id=4099
struct X4099
{
@@ -672,7 +672,7 @@ void test17()
}
/**************************************/
-// 3789
+// https://issues.dlang.org/show_bug.cgi?id=3789
bool test3789()
{
@@ -728,7 +728,7 @@ bool test3789()
auto ua2 = UnionA([1,2,3]);
assert(ua1.u.x is ua2.u.x);
assert(ua1.u.x != ua2.u.x);
- assert(ua1 == ua2);
+ assert(ua1 != ua2);
ua1.u.x = 1.0;
ua2.u.x = 1.0;
assert(ua1.u.x is ua2.u.x);
@@ -755,7 +755,7 @@ bool test3789()
ub2.u.a = [1,2,3].dup;
assert(ub1.u.a !is ub2.u.a);
assert(ub1.u.a == ub2.u.a);
- assert(ub1 != ub2);
+ assert(ub1 == ub2);
ub2.u.a = ub1.u.a;
assert(ub1.u.a is ub2.u.a);
assert(ub1.u.a == ub2.u.a);
@@ -789,44 +789,27 @@ bool test3789()
}
static assert(test3789());
-/**************************************/
-// 10037
-
-struct S10037
-{
- bool opEquals(ref const S10037) { assert(0); }
-}
-
-struct T10037
+struct S
{
- S10037 s;
- // Compiler should not generate 'opEquals' here implicitly:
+ bool opEquals(ref const S) { return false; }
}
-struct Sub10037(TL...)
+struct T
{
- TL data;
+ S s;
int value;
alias value this;
}
-void test10037()
+void test11161()
{
- S10037 s;
- T10037 t;
- static assert( __traits(hasMember, S10037, "opEquals"));
- static assert(!__traits(hasMember, T10037, "opEquals"));
- assert(thrown!Error(s == s));
- assert(thrown!Error(t == t));
-
- Sub10037!(S10037) lhs;
- Sub10037!(S10037) rhs;
- static assert(!__traits(hasMember, Sub10037!(S10037), "opEquals"));
- assert(lhs == rhs); // lowered to: lhs.value == rhs.value
+ T t1, t2;
+ assert(t1.tupleof != t2.tupleof);
+ assert(t1 != t2); // fails
}
/**************************************/
-// 5810
+// https://issues.dlang.org/show_bug.cgi?id=5810
struct Bug5810
{
@@ -840,7 +823,7 @@ struct Foo5810
}
/**************************************/
-// 6798
+// https://issues.dlang.org/show_bug.cgi?id=6798
struct Tuple6798(T...)
{
@@ -1013,7 +996,7 @@ void test6798()
}
/**************************************/
-// 12382
+// https://issues.dlang.org/show_bug.cgi?id=12382
struct S12382
{
@@ -1041,7 +1024,7 @@ void test12382()
}
/**************************************/
-// 12904
+// https://issues.dlang.org/show_bug.cgi?id=12904
struct S12904
{
@@ -1080,7 +1063,7 @@ void test12904()
}
/**************************************/
-// 7641
+// https://issues.dlang.org/show_bug.cgi?id=7641
mixin template Proxy7641(alias a)
{
@@ -1110,7 +1093,7 @@ void test7641()
}
/**************************************/
-// 8434
+// https://issues.dlang.org/show_bug.cgi?id=8434
void test8434()
{
@@ -1338,7 +1321,7 @@ void test19()
}
/**************************************/
-// 9453
+// https://issues.dlang.org/show_bug.cgi?id=9453
struct Foo9453
{
@@ -1360,7 +1343,7 @@ void test9453()
}
/**************************************/
-// 9496
+// https://issues.dlang.org/show_bug.cgi?id=9496
struct S9496
{
@@ -1392,7 +1375,7 @@ void test9496()
}
/**************************************/
-// 9689
+// https://issues.dlang.org/show_bug.cgi?id=9689
struct B9689(T)
{
@@ -1418,7 +1401,7 @@ void test9689()
}
/**************************************/
-// 9694
+// https://issues.dlang.org/show_bug.cgi?id=9694
struct S9694
{
@@ -1438,7 +1421,7 @@ void test9694()
}
/**************************************/
-// 10064
+// https://issues.dlang.org/show_bug.cgi?id=10064
void test10064()
{
@@ -1465,7 +1448,7 @@ void test10064()
}
/**************************************/
-// 12585
+// https://issues.dlang.org/show_bug.cgi?id=12585
void test12585()
{
@@ -1504,7 +1487,7 @@ void test12585()
}
/**************************************/
-// 10394
+// https://issues.dlang.org/show_bug.cgi?id=10394
void test10394()
{
@@ -1533,7 +1516,7 @@ void test10394()
}
/**************************************/
-// 10597
+// https://issues.dlang.org/show_bug.cgi?id=10597
struct R10597
{
@@ -1577,7 +1560,7 @@ void test10597()
}
/**************************************/
-// 10567
+// https://issues.dlang.org/show_bug.cgi?id=10567
// doesn't require thunk
struct S10567x1n { int value; int opCmp(ref const S10567x1n rhs) const { return 0; } }
@@ -1662,13 +1645,6 @@ void test10567()
S sy = S(2);
assert(!(sx < sy) && !(sx > sy));
assert(sx.opCmp(sy) == 0);
-
- try
- {
- auto x = typeid(S).compare(&sx, &sy);
- assert(0);
- }
- catch (Error e) { assert(e.msg[$-15 .. $] == "not implemented"); }
}
/+
foreach (S; Seq!(S10567d1, S10567d2))
@@ -1690,7 +1666,7 @@ void test10567()
}
/**************************************/
-// 11062
+// https://issues.dlang.org/show_bug.cgi?id=11062
struct S11062ia
{
@@ -1734,7 +1710,7 @@ void test11062()
}
/**************************************/
-// 11311
+// https://issues.dlang.org/show_bug.cgi?id=11311
void test11311()
{
@@ -1791,7 +1767,7 @@ void test11311()
}
/**************************************/
-// 12193
+// https://issues.dlang.org/show_bug.cgi?id=12193
void test12193()
{
@@ -1810,7 +1786,7 @@ void test12193()
}
/**************************************/
-// 14057
+// https://issues.dlang.org/show_bug.cgi?id=14057
struct W14057
{
@@ -1936,7 +1912,7 @@ void test20d()
}
/**************************************/
-// 14624
+// https://issues.dlang.org/show_bug.cgi?id=14624
void test14624()
{
@@ -1981,7 +1957,7 @@ void test14624()
}
/**************************************/
-// 14625
+// https://issues.dlang.org/show_bug.cgi?id=14625
void test14625()
{
@@ -2033,7 +2009,7 @@ int main()
test16();
test17();
test3789();
- test10037();
+ test11161();
test6798();
test12904();
test7641();
@@ -2061,4 +2037,3 @@ int main()
printf("Success\n");
return 0;
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/opover3.d b/gcc/testsuite/gdc.test/runnable/opover3.d
index c6de5d7..7146826 100644
--- a/gcc/testsuite/gdc.test/runnable/opover3.d
+++ b/gcc/testsuite/gdc.test/runnable/opover3.d
@@ -125,7 +125,7 @@ void test4()
}
/**************************************/
-// 12070
+// https://issues.dlang.org/show_bug.cgi?id=12070
void test12070()
{
@@ -160,7 +160,7 @@ void test12070()
}
/**************************************/
-// 12124
+// https://issues.dlang.org/show_bug.cgi?id=12124
struct S12124
{
diff --git a/gcc/testsuite/gdc.test/runnable/overload.d b/gcc/testsuite/gdc.test/runnable/overload.d
index f8fa7d5..c413ade 100644
--- a/gcc/testsuite/gdc.test/runnable/overload.d
+++ b/gcc/testsuite/gdc.test/runnable/overload.d
@@ -1,5 +1,13 @@
-// EXTRA_SOURCES: imports/ovs1528a.d imports/ovs1528b.d
-// EXTRA_SOURCES: imports/template_ovs1.d imports/template_ovs2.d imports/template_ovs3.d
+/*
+REQUIRED_ARGS: -preview=rvaluerefparam
+EXTRA_SOURCES: imports/ovs1528a.d imports/ovs1528b.d
+EXTRA_SOURCES: imports/template_ovs1.d imports/template_ovs2.d imports/template_ovs3.d
+EXTRA_FILES: imports/m8668a.d imports/m8668b.d imports/m8668c.d
+RUN_OUTPUT:
+---
+Success
+---
+*/
import imports.template_ovs1;
import imports.template_ovs2;
@@ -12,7 +20,7 @@ template Id( T){ alias T Id; }
template Id(alias A){ alias A Id; }
/***************************************************/
-// 1528
+// https://issues.dlang.org/show_bug.cgi?id=1528
int foo1528(long){ return 1; }
int foo1528(int[]){ return 2; }
@@ -313,7 +321,7 @@ void test1528d()
}
/***************************************************/
-// 1680
+// https://issues.dlang.org/show_bug.cgi?id=1680
struct S1680
{
@@ -360,7 +368,7 @@ void test1680()
}
/***************************************************/
-// 7418
+// https://issues.dlang.org/show_bug.cgi?id=7418
int foo7418(uint a) { return 1; }
int foo7418(char[] a) { return 2; }
@@ -378,7 +386,7 @@ void test7418()
}
/***************************************************/
-// 7552
+// https://issues.dlang.org/show_bug.cgi?id=7552
struct S7552
{
@@ -434,7 +442,7 @@ void test7552()
}
/***************************************************/
-// 8668
+// https://issues.dlang.org/show_bug.cgi?id=8668
import imports.m8668a;
import imports.m8668c; //replace with m8668b to make it work
@@ -446,7 +454,7 @@ void test8668()
}
/***************************************************/
-// 8943
+// https://issues.dlang.org/show_bug.cgi?id=8943
void test8943()
{
@@ -461,7 +469,7 @@ void test8943()
}
/***************************************************/
-// 9410
+// https://issues.dlang.org/show_bug.cgi?id=9410
struct S {}
int foo(float f, ref S s) { return 1; }
@@ -470,11 +478,17 @@ void test9410()
{
S s;
assert(foo(1, s ) == 1); // works fine. Print: ref
- assert(foo(1, S()) == 2); // Fails with: Error: S() is not an lvalue
+
+ /* With the rvalue to ref param change, this calls the 'ref' version
+ * because both are the same match level, but the 'ref' version is
+ * considered "more specialized", as the non-ref version undergoes
+ * a "conversion" to call the ref version.
+ */
+ assert(foo(1, S()) == 1);
}
/***************************************************/
-// 10171
+// https://issues.dlang.org/show_bug.cgi?id=10171
struct B10171(T) { static int x; }
@@ -484,7 +498,8 @@ void test10171()
}
/***************************************************/
-// 1900 - template overload set
+// https://issues.dlang.org/show_bug.cgi?id=1900
+// template overload set
void test1900a()
{
@@ -623,7 +638,7 @@ void test1900e()
}
/***************************************************/
-// 1900
+// https://issues.dlang.org/show_bug.cgi?id=1900
void test1900()
{
@@ -669,7 +684,7 @@ mixin Foo1900!(char) B1900;
alias Bar1900!(int) bar1900; // error
/***************************************************/
-// 7780
+// https://issues.dlang.org/show_bug.cgi?id=7780
mixin template A7780()
{
@@ -710,7 +725,7 @@ void test7849()
}
/***************************************************/
-// 8352
+// https://issues.dlang.org/show_bug.cgi?id=8352
void test8352()
{
@@ -721,7 +736,7 @@ void test8352()
}
/***************************************************/
-// 8441
+// https://issues.dlang.org/show_bug.cgi?id=8441
mixin template T8441a(string i)
{
@@ -819,7 +834,7 @@ void test8441c()
}
/***************************************************/
-// 9235
+// https://issues.dlang.org/show_bug.cgi?id=9235
template FlowEvaluator9235()
{
@@ -893,7 +908,7 @@ void test9235b()
}
/***************************************************/
-// 10658
+// https://issues.dlang.org/show_bug.cgi?id=10658
alias Val10658 = imports.template_ovs1.Val10658;
alias Val10658 = imports.template_ovs2.Val10658;
@@ -1009,7 +1024,7 @@ void test11785()
}
/***************************************************/
-// 11915
+// https://issues.dlang.org/show_bug.cgi?id=11915
int f11915( int) { return 1; }
int f11915(ref int) { return 2; }
@@ -1025,7 +1040,7 @@ void test11915()
}
/***************************************************/
-// 11916
+// https://issues.dlang.org/show_bug.cgi?id=11916
auto f11916(T)( T) { return 1; }
auto f11916(T)(out T) if (false) { return 2; }
@@ -1054,12 +1069,12 @@ void test11916()
}
/***************************************************/
-// 13783
+// https://issues.dlang.org/show_bug.cgi?id=13783
enum E13783 { a = 5 }
inout(int) f( inout(int) t) { return t * 2; }
-ref inout(int) f(ref inout(int) t) { return t; }
+ref inout(int) f(return ref inout(int) t) { return t; }
void test13783()
{
@@ -1068,7 +1083,7 @@ void test13783()
}
/***************************************************/
-// 14858
+// https://issues.dlang.org/show_bug.cgi?id=14858
int foo14858()() { return 1; }
int bar14858(int) { return 2; }
@@ -1083,7 +1098,7 @@ void test14858()
}
/***************************************************/
-// 14989
+// https://issues.dlang.org/show_bug.cgi?id=14989
template Foo14989(T) if (is(T == int)) { enum Foo14989 = 1; }
template Bar14989(T) if (is(T == double)) { enum Bar14989 = 2; }
@@ -1136,7 +1151,7 @@ void test14989()
}
/***************************************************/
-// 14965
+// https://issues.dlang.org/show_bug.cgi?id=14965
auto f14965a1() { return f14965a1(123); }
int f14965a1(int x) { return x; }
@@ -1212,6 +1227,40 @@ void test14965()
}
/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=21481
+
+struct S21481
+{
+ void funB2(char a) {}
+ alias funB = funB2;
+ // template as first symbol in overload set and overloading an alias
+ void funB()(float t) {}
+ void funB(int b) {} // function was lost -> OK now
+}
+
+void test21481()
+{
+ static assert(__traits(getOverloads, S21481, "funB", true).length == 3);
+}
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=21522
+
+struct S21522
+{
+ // alias to template as first symbol in overload set
+ void funA2()(int a) {}
+ void funA2(char a) {} // function was lost -> OK now
+ alias funA = funA2;
+ void funA(float b) {}
+}
+
+void test21522()
+{
+ static assert(__traits(getOverloads, S21522, "funA", true).length == 3);
+}
+
+/***************************************************/
int main()
{
@@ -1247,6 +1296,8 @@ int main()
test13783();
test14858();
test14965();
+ test21481();
+ test21522();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/previewin.d b/gcc/testsuite/gdc.test/runnable/previewin.d
new file mode 100644
index 0000000..12a0551
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/previewin.d
@@ -0,0 +1,189 @@
+// REQUIRED_ARGS: -preview=dip1000 -preview=in
+
+void main ()
+{
+ testWithAllAttributes();
+ testForeach();
+}
+
+void testWithAllAttributes() @safe pure nothrow @nogc
+{
+ // Used to test dtors
+ bool isTestOver = false;
+
+ // rvalues
+ testin1(42);
+ testin2((ulong[64]).init);
+ testin3(ValueT(42));
+ testin3(RefT(42));
+ testin4((ValueT[64]).init);
+ testin4([RefT(42), RefT(84), RefT(126), RefT(4)]);
+ testin5(NonCopyable(true));
+ testin6(WithPostblit(true));
+ testin7(WithCopyCtor(true));
+ isTestOver = false;
+ testin8(WithDtor(&isTestOver), &isTestOver);
+ isTestOver = false;
+
+ // lvalues
+ uint a1;
+ ulong[64] a2;
+ ValueT a3;
+ ValueT[64] a4;
+ RefT a5;
+ RefT[4] a6;
+ NonCopyable a7 = NonCopyable(true);
+ WithPostblit a8;
+ WithCopyCtor a9;
+ WithDtor a10 = WithDtor(&isTestOver);
+
+ testin1(a1);
+ testin2(a2);
+ testin3(a3);
+ testin3(a5);
+ testin4(a4);
+ testin4(a6);
+ testin5(a7);
+ testin6(a8);
+ testin7(a9);
+ isTestOver = false;
+ testin8(a10, null);
+
+ // Arguments are all values, no `ref` needed
+ testin9(int.init);
+ testin9(char.init, ubyte.init, short.init, int.init, size_t.init);
+ // Arguments are all refs
+ testin9(a2, a4, a5, a6, a7, a8, a9, a10);
+ testin9(NonCopyable(true), WithPostblit(true), WithCopyCtor(true));
+ // Mixed values and ref
+ testin9(char.init, ubyte.init, a2, a4, a5, a6, a7, a8, a9, a10, size_t.init);
+
+ // With dtor
+ isTestOver = false;
+ testin10(&isTestOver, NonCopyable(true), WithPostblit(true),
+ WithCopyCtor(true), WithDtor(&isTestOver));
+ isTestOver = true;
+}
+
+void testForeach() @safe pure
+{
+ int testCallNC (in NonCopyable k, in NonCopyable v)
+ {
+ assert(k == v);
+ return k.value - v.value;
+ }
+
+ NonCopyable[NonCopyable] nc;
+ nc[NonCopyable(0)] = NonCopyable(0);
+ nc[NonCopyable(42)] = NonCopyable(42);
+ nc[NonCopyable(int.min)] = NonCopyable(int.min);
+ nc[NonCopyable(int.max)] = NonCopyable(int.max);
+ foreach (ref k, const ref v; nc)
+ {
+ assert(k.value == v.value);
+ assert(testCallNC(k, v) == 0);
+ }
+ assert(nc == nc);
+ assert(nc.length == 4);
+
+ RefT[RefT] rt;
+ rt[RefT(42)] = RefT(42);
+ rt[RefT(4)] = RefT(4);
+ rt[RefT(242)] = RefT(242);
+ rt[RefT(24)] = RefT(24);
+ foreach (k, v; rt)
+ assert(k.value == v.value);
+ assert(rt == rt);
+
+ static struct Msg
+ {
+ ubyte[3] value;
+ const(char)[] msg;
+ }
+
+ static void testMsg (in Msg k_func, in Msg v_func)
+ {
+ assert(k_func.value == v_func.value);
+ assert(k_func.msg == v_func.msg);
+ assert(k_func == v_func);
+ }
+
+ Msg[Msg] msg;
+ msg[Msg([1, 2, 3], "123")] = Msg([1, 2, 3], "123");
+ msg[Msg([42, 4, 2], "4242")] = Msg([42, 4, 2], "4242");
+ msg[Msg([242, 4, 0], "2424")] = Msg([242, 4, 0], "2424");
+ foreach (ref k_loop, ref v_loop; msg)
+ testMsg(k_loop, v_loop);
+}
+
+struct ValueT { int value; }
+struct RefT { ulong[64] value; }
+
+struct NonCopyable
+{
+ @safe pure nothrow @nogc:
+
+ int value;
+ this(int b) { this.value = b; }
+
+ @disable this(this);
+ @disable this(ref NonCopyable);
+}
+
+struct WithPostblit
+{
+ int value;
+ this(this) @safe pure nothrow @nogc { assert(0); }
+}
+
+struct WithCopyCtor
+{
+ @safe pure nothrow @nogc:
+
+ int value;
+ this(int b) { this.value = b; }
+ this(ref WithCopyCtor) { assert(0); }
+}
+
+struct WithDtor
+{
+ bool* value;
+ ~this() scope @safe pure nothrow @nogc { assert(*value); }
+}
+
+@safe pure nothrow @nogc:
+
+// By value
+void testin1(in uint p) { static assert(!__traits(isRef, p)); }
+// By ref because of size
+void testin2(in ulong[64] p) { static assert(__traits(isRef, p)); }
+// By value or ref depending on size
+void testin3(in ValueT p) { static assert(!__traits(isRef, p)); }
+void testin3(in RefT p) { static assert(__traits(isRef, p)); }
+// By ref because of size
+void testin4(in ValueT[64] p) { static assert(__traits(isRef, p)); }
+void testin4(in RefT[4] p) { static assert(__traits(isRef, p)); }
+
+// By ref because of non-copyability
+void testin5(in NonCopyable noncopy) { static assert(__traits(isRef, noncopy)); }
+static assert(testin5.mangleof == "_D9previewin7testin5FNaNbNiNfIKSQBe11NonCopyableZv"); // incl. `ref`
+// By ref because of postblit
+void testin6(in WithPostblit withpostblit) { static assert(__traits(isRef, withpostblit)); }
+// By ref because of copy ctor
+void testin7(in WithCopyCtor withcopy) { static assert(__traits(isRef, withcopy)); }
+// By ref because of dtor
+void testin8(in WithDtor withdtor, scope bool* isTestOver)
+{
+ static assert(__traits(isRef, withdtor));
+ if (isTestOver)
+ *isTestOver = true;
+}
+
+// Allow to test various tuples (e.g. `(int, int)` and `(int, WithDtor)`)
+// `ref` is only applied to the members which need it
+void testin9(T...)(in T args) {}
+void testin10(T...)(scope bool* isTestOver, in T args)
+{
+ if (isTestOver)
+ *isTestOver = true;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/printargs.d b/gcc/testsuite/gdc.test/runnable/printargs.d
index f4fc703..7d4d916 100644
--- a/gcc/testsuite/gdc.test/runnable/printargs.d
+++ b/gcc/testsuite/gdc.test/runnable/printargs.d
@@ -3,12 +3,12 @@
extern(C) int printf(const char*, ...);
-int main(char args[][])
+int main(char[][] args)
{
int i;
for (i = 0; i < args.length; i++)
- printf("args[%d] = '%.*s'\n", i, args[i].length, args[i].ptr);
+ printf("args[%d] = '%.*s'\n", i, cast(int)args[i].length, args[i].ptr);
assert(args[1] == "A");
assert(args[2] == "B");
diff --git a/gcc/testsuite/gdc.test/runnable/property.d b/gcc/testsuite/gdc.test/runnable/property.d
index 4fd3af4..661bd68 100644
--- a/gcc/testsuite/gdc.test/runnable/property.d
+++ b/gcc/testsuite/gdc.test/runnable/property.d
@@ -26,12 +26,12 @@ int test1()
}
/******************************************/
-// 6259
+// https://issues.dlang.org/show_bug.cgi?id=6259
struct S6259
{
private int m_prop;
- ref const(int) prop() { return m_prop; }
+ ref const(int) prop() return { return m_prop; }
void prop(int v) { m_prop = v; }
}
diff --git a/gcc/testsuite/gdc.test/runnable/property2.d b/gcc/testsuite/gdc.test/runnable/property2.d
index 1c5cf30..275729f 100644
--- a/gcc/testsuite/gdc.test/runnable/property2.d
+++ b/gcc/testsuite/gdc.test/runnable/property2.d
@@ -1,4 +1,3 @@
-// PERMUTE_ARGS: -property
/*
TEST_OUTPUT:
---
@@ -19,23 +18,13 @@ RUN_OUTPUT:
Success
---
*/
-
extern (C) int printf(const char* fmt, ...);
-// Is -property option specified?
-enum enforceProperty = !__traits(compiles, {
- int prop(){ return 1; }
- int n = prop;
-});
-
/*******************************************/
template select(alias v1, alias v2)
{
- static if (enforceProperty)
- enum select = v1;
- else
- enum select = v2;
+ enum select = v2;
}
struct Test(int N)
@@ -48,32 +37,28 @@ struct Test(int N)
ref foo(){ getset = 1; return value; }
enum result = select!(0, 1);
- // -property test.d(xx): Error: not a property foo
- // (no option) prints "getter"
+ // prints "getter"
}
static if (N == 1)
{
ref foo(int x){ getset = 2; value = x; return value; }
enum result = select!(0, 2);
- // -property test.d(xx): Error: not a property foo
- // (no option) prints "setter"
+ // prints "setter"
}
static if (N == 2)
{
@property ref foo(){ getset = 1; return value; }
enum result = select!(1, 1);
- // -property prints "getter"
- // (no option) prints "getter"
+ // prints "getter"
}
static if (N == 3)
{
@property ref foo(int x){ getset = 2; value = x; return value; }
enum result = select!(2, 2);
- // -property prints "setter"
- // (no option) prints "setter"
+ // prints "setter"
}
@@ -83,8 +68,7 @@ struct Test(int N)
ref foo(int x){ getset = 2; value = x; return value; }
enum result = select!(0, 2);
- // -property test.d(xx): Error: not a property foo
- // (no option) prints "setter"
+ // prints "setter"
}
static if (N == 5)
{
@@ -92,8 +76,7 @@ struct Test(int N)
ref foo(int x){ getset = 2; value = x; return value; }
enum result = select!(0, 0);
- // -property test.d(xx): Error: cannot overload both property and non-property functions
- // (no option) test.d(xx): Error: cannot overload both property and non-property functions
+ // test.d(xx): Error: cannot overload both property and non-property functions
}
static if (N == 6)
{
@@ -101,8 +84,7 @@ struct Test(int N)
@property ref foo(int x){ getset = 2; value = x; return value; }
enum result = select!(0, 0);
- // -property test.d(xx): Error: cannot overload both property and non-property functions
- // (no option) test.d(xx): Error: cannot overload both property and non-property functions
+ // test.d(xx): Error: cannot overload both property and non-property functions
}
static if (N == 7)
{
@@ -110,8 +92,7 @@ struct Test(int N)
@property ref foo(int x){ getset = 2; value = x; return value; }
enum result = select!(2, 2);
- // -property prints "setter"
- // (no option) prints "setter"
+ // prints "setter"
}
}
@@ -153,7 +134,7 @@ void test1()
}
/*******************************************/
-// 7722
+// https://issues.dlang.org/show_bug.cgi?id=7722
class Foo7722 {}
void spam7722(Foo7722 f) {}
@@ -161,10 +142,7 @@ void spam7722(Foo7722 f) {}
void test7722()
{
auto f = new Foo7722;
- static if (enforceProperty)
- static assert(!__traits(compiles, f.spam7722));
- else
- f.spam7722;
+ f.spam7722;
}
/*******************************************/
@@ -179,10 +157,7 @@ void test7722()
assert(dg(0) == v);
}
- static if (enforceProperty)
- checkImpl!(v1)();
- else
- checkImpl!(v2)();
+ checkImpl!(v2)();
}
struct S {}
@@ -292,7 +267,7 @@ void test7722b()
}
/*******************************************/
-// 7174
+// https://issues.dlang.org/show_bug.cgi?id=7174
void test7174()
{
@@ -301,7 +276,7 @@ void test7174()
}
/***************************************************/
-// 7274
+// https://issues.dlang.org/show_bug.cgi?id=7274
@property foo7274(){ return "test"; }
@property bar7274(){ return "kernel32.lib"; }
@@ -316,7 +291,7 @@ void test7274()
}
/***************************************************/
-// 7275
+// https://issues.dlang.org/show_bug.cgi?id=7275
void test7275()
{
@@ -333,7 +308,7 @@ void test7275()
}
/*****************************************/
-// 7538
+// https://issues.dlang.org/show_bug.cgi?id=7538
void test7538()
{
@@ -478,7 +453,7 @@ void test7538()
}
/*****************************************/
-// 8251
+// https://issues.dlang.org/show_bug.cgi?id=8251
struct S8251
{
@@ -515,13 +490,13 @@ void test8251()
}
/*****************************************/
-// 9063
+// https://issues.dlang.org/show_bug.cgi?id=9063
@property bool foo9063(){ return true; }
static assert(foo9063);
/*****************************************/
-// 9234
+// https://issues.dlang.org/show_bug.cgi?id=9234
class Fizz9234
{
@@ -533,7 +508,7 @@ struct Foo9234(alias F) {}
struct Foo9234(string thunk) {}
/*****************************************/
-// 10103
+// https://issues.dlang.org/show_bug.cgi?id=10103
mixin template Getter10103()
{
@@ -577,7 +552,7 @@ void test10103()
}
/*****************************************/
-// 10197
+// https://issues.dlang.org/show_bug.cgi?id=10197
template OriginalType10197(T)
{
diff --git a/gcc/testsuite/gdc.test/runnable/pubprivtmpl.d b/gcc/testsuite/gdc.test/runnable/pubprivtmpl.d
new file mode 100644
index 0000000..992f04f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/pubprivtmpl.d
@@ -0,0 +1,20 @@
+// EXTRA_SOURCES: imports/pubprivtmpla.d
+
+module pubprivtmpl;
+
+// Idiom: public alias to private template
+// This idiom was discovered while refactoring access.d. The idiom was not being used in any DLang repository
+// but was being used by a few projects in the D ecosystem. It is unkown at this time if this idiom is permitted
+// by design or by accident. This test was added to DMD to prevent regressions in those projects that utilize this
+// idiom. See also:
+// https://issues.dlang.org/show_bug.cgi?id=4533
+// https://issues.dlang.org/show_bug.cgi?id=11173
+
+import pubprivtmpla;
+
+void main()
+{
+ auto s = S();
+ auto v = s.get();
+ assert(v == 42);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/s2ir.d b/gcc/testsuite/gdc.test/runnable/s2ir.d
index 29cfc96..840e6de 100644
--- a/gcc/testsuite/gdc.test/runnable/s2ir.d
+++ b/gcc/testsuite/gdc.test/runnable/s2ir.d
@@ -1,5 +1,14 @@
-// RUNNABLE_PHOBOS_TEST
-import std.stdio;
+/*
+RUN_OUTPUT:
+---
+hello
+world
+foo
+Success
+---
+*/
+
+import core.stdc.stdio;
/***********************************/
@@ -17,6 +26,8 @@ void test1()
}
version(D_PIC)
{}
+ else version (D_PIE)
+ {}
else
{
asm
@@ -43,7 +54,7 @@ int main()
a[2] = "foo";
foreach (string s; a)
- writefln(s);
+ printf("%.*s\n", cast(int)s.length, s.ptr);
switch (1)
{
@@ -92,6 +103,6 @@ int main()
default: assert(0);
}
- writefln("Success\n");
+ printf("Success\n");
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/sctor.d b/gcc/testsuite/gdc.test/runnable/sctor.d
index 7d640c0..b587e6e 100644
--- a/gcc/testsuite/gdc.test/runnable/sctor.d
+++ b/gcc/testsuite/gdc.test/runnable/sctor.d
@@ -1,5 +1,11 @@
-// REQUIRED_ARGS:
-// PERMUTE_ARGS: -w -d -de -dw
+/*
+REQUIRED_ARGS: -w -de
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+Success
+---
+*/
extern(C) int printf(const char*, ...);
@@ -117,7 +123,7 @@ struct S4
}
/***************************************************/
-// 8117
+// https://issues.dlang.org/show_bug.cgi?id=8117
struct S8117
{
@@ -136,7 +142,7 @@ void test8117()
}
/***************************************************/
-// 9665
+// https://issues.dlang.org/show_bug.cgi?id=9665
struct X9665
{
@@ -182,7 +188,7 @@ void test9665()
}
/***************************************************/
-// 11246
+// https://issues.dlang.org/show_bug.cgi?id=11246
struct Foo11246
{
@@ -223,7 +229,7 @@ void test11246()
}
/***************************************************/
-// 13515
+// https://issues.dlang.org/show_bug.cgi?id=13515
Object[string][100] aa13515;
@@ -253,7 +259,7 @@ void test13515()
}
/***************************************************/
-// 14409
+// https://issues.dlang.org/show_bug.cgi?id=14409
class B14409 { this(int) {} }
class C14409 : B14409
@@ -268,7 +274,7 @@ class C14409 : B14409
}
/***************************************************/
-// 14376
+// https://issues.dlang.org/show_bug.cgi?id=14376
auto map14376()
{
@@ -294,7 +300,7 @@ struct S14376
}
/***************************************************/
-// 14351
+// https://issues.dlang.org/show_bug.cgi?id=14351
class B14351
{
@@ -317,7 +323,7 @@ class D14351c : B14351
}
/***************************************************/
-// 14450
+// https://issues.dlang.org/show_bug.cgi?id=14450
struct S14450a // non-template struct + non template ctors - OK
{
@@ -366,7 +372,7 @@ void test14450()
}
/***************************************************/
-// 14944
+// https://issues.dlang.org/show_bug.cgi?id=14944
static int[2] tbl14944;
@@ -386,7 +392,8 @@ void test14944()
}
/***************************************************/
-// 15258 - a field initialization affects other overlapped fields
+// https://issues.dlang.org/show_bug.cgi?id=15258
+// a field initialization affects other overlapped fields
class C15258
{
@@ -403,18 +410,62 @@ class C15258
}
/***************************************************/
-// 15665
+// https://issues.dlang.org/show_bug.cgi?id=15869
-scope class C15665 (V)
+struct Set {
+ @disable this(this);
+ int value = 0;
+}
+
+Set clobber(ref Set a) {
+ Set ret; // <- This overwrites *a, i.e. &ret is the same as a
+ ret.value = a.value; // <- Now a.value is 0
+ return ret;
+}
+
+struct XX {
+ Set a = Set(1);
+ this(int n) {
+ a = clobber(a); // fix is to make this an assignment, not a construction
+ }
+}
+void test15869()
{
- this () {}
+ Set a = Set(1);
+ a = clobber(a);
+ assert(a.value == 1);
+
+ XX xx = XX(0);
+ assert(xx.a.value == 1);
}
-void test15665()
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19389
+
+struct Foo19389 {
+ int x;
+
+ this(int dummy) { x = dummy; }
+}
+
+struct Bar19389 {
+ Foo19389 a;
+ Foo19389 b;
+
+ this(int dummy) {
+ a = (b = Foo19389(dummy));
+ }
+}
+
+
+void test19389()
{
- scope foo = new C15665!int;
+ Bar19389 bar = Bar19389(7);
+ assert(bar.a.x == 7);
+ assert(bar.b.x == 7); // fails
}
+
/***************************************************/
int main()
@@ -425,7 +476,8 @@ int main()
test13515();
test14450();
test14944();
- test15665();
+ test15869();
+ test19389();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/sctor2.d b/gcc/testsuite/gdc.test/runnable/sctor2.d
new file mode 100644
index 0000000..a2367cf
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/sctor2.d
@@ -0,0 +1,20 @@
+// REQUIRED_ARGS: -w -de
+// PERMUTE_ARGS:
+
+/***************************************************/
+// 15665
+
+scope class C15665 (V)
+{
+ this () {}
+}
+
+void test15665()
+{
+ scope foo = new C15665!int;
+}
+
+void main()
+{
+ test15665();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/sdtor.d b/gcc/testsuite/gdc.test/runnable/sdtor.d
index 3edf8cf..56c5125 100644
--- a/gcc/testsuite/gdc.test/runnable/sdtor.d
+++ b/gcc/testsuite/gdc.test/runnable/sdtor.d
@@ -1,4 +1,5 @@
// PERMUTE_ARGS: -unittest -O -release -inline -fPIC -g
+// REQUIRED_ARGS: -preview=dtorfields
/*
TEST_OUTPUT:
---
@@ -16,7 +17,7 @@ S7353
import core.vararg;
-extern (C) int printf(const(char*) fmt, ...);
+extern (C) int printf(const(char*) fmt, ...) nothrow;
template TypeTuple(T...) { alias TypeTuple = T; }
@@ -38,23 +39,6 @@ void test1()
/**********************************/
-int sdtor2;
-
-struct S2
-{
- ~this() { printf("~S2()\n"); sdtor2++; }
- delete(void* p) { assert(sdtor2 == 1); printf("S2.delete()\n"); sdtor2++; }
-}
-
-void test2()
-{
- S2* s = new S2();
- delete s;
- assert(sdtor2 == 2);
-}
-
-/**********************************/
-
int sdtor3;
struct S3
@@ -1185,7 +1169,7 @@ void test45()
}
/**********************************/
-// 3986
+// https://issues.dlang.org/show_bug.cgi?id=3986
struct SiberianHamster
{
@@ -1200,7 +1184,7 @@ void test46()
}
/**********************************/
-// 8741
+// https://issues.dlang.org/show_bug.cgi?id=8741
struct Vec8741
{
@@ -1351,12 +1335,12 @@ void test52()
A52 b = a.copy();
printf("a: %p, b: %p\n", &a, &b);
}
- printf("s = '%.*s'\n", s52.length, s52.ptr);
+ printf("s = '%.*s'\n", cast(int)s52.length, s52.ptr);
assert(s52 == "cabb");
}
/**********************************/
-// 4339
+// https://issues.dlang.org/show_bug.cgi?id=4339
struct A53 {
invariant() { }
@@ -1520,7 +1504,7 @@ void test56()
}
/**********************************/
-// 5859
+// https://issues.dlang.org/show_bug.cgi?id=5859
int dtor_cnt = 0;
struct S57
@@ -1669,7 +1653,7 @@ void test57()
}
/**********************************/
-// 5574
+// https://issues.dlang.org/show_bug.cgi?id=5574
struct foo5574a
{
@@ -1690,7 +1674,7 @@ struct bar5574b
}
/**********************************/
-// 5777
+// https://issues.dlang.org/show_bug.cgi?id=5777
int sdtor58 = 0;
S58* ps58;
@@ -1716,7 +1700,7 @@ void test58()
}
/**********************************/
-// 6308
+// https://issues.dlang.org/show_bug.cgi?id=6308
struct C59
{
@@ -1749,7 +1733,7 @@ void test59()
}
/**********************************/
-// 5737
+// https://issues.dlang.org/show_bug.cgi?id=5737
void test5737()
{
@@ -1785,7 +1769,7 @@ void test5737()
}
/**********************************/
-// 6119
+// https://issues.dlang.org/show_bug.cgi?id=6119
void test6119()
{
@@ -1817,7 +1801,7 @@ void test6119()
}
/**********************************/
-// 6364
+// https://issues.dlang.org/show_bug.cgi?id=6364
struct Foo6364
{
@@ -1843,7 +1827,7 @@ void test6364()
}
/**********************************/
-// 6499
+// https://issues.dlang.org/show_bug.cgi?id=6499
struct S6499
{
@@ -1852,18 +1836,18 @@ struct S6499
this(string s)
{
m = s;
- printf("Constructor - %.*s\n", m.length, m.ptr);
+ printf("Constructor - %.*s\n", cast(int)m.length, m.ptr);
if (m == "foo") { ++sdtor; assert(sdtor == 1); }
if (m == "bar") { ++sdtor; assert(sdtor == 2); }
}
this(this)
{
- printf("Postblit - %.*s\n", m.length, m.ptr);
+ printf("Postblit - %.*s\n", cast(int)m.length, m.ptr);
assert(0);
}
~this()
{
- printf("Destructor - %.*s\n", m.length, m.ptr);
+ printf("Destructor - %.*s\n", cast(int)m.length, m.ptr);
if (m == "bar") { assert(sdtor == 2); --sdtor; }
if (m == "foo") { assert(sdtor == 1); --sdtor; }
}
@@ -1957,7 +1941,7 @@ void test60()
}
/**********************************/
-// 4316
+// https://issues.dlang.org/show_bug.cgi?id=4316
struct A4316
{
@@ -1990,7 +1974,7 @@ void test6177()
/**********************************/
-// 6470
+// https://issues.dlang.org/show_bug.cgi?id=6470
struct S6470
{
@@ -2021,7 +2005,7 @@ void test6470()
}
/**********************************/
-// 6636
+// https://issues.dlang.org/show_bug.cgi?id=6636
struct S6636
{
@@ -2043,7 +2027,7 @@ void test6636()
}
/**********************************/
-// 6637
+// https://issues.dlang.org/show_bug.cgi?id=6637
struct S6637
{
@@ -2062,7 +2046,7 @@ void test6637()
}
/**********************************/
-// 7353
+// https://issues.dlang.org/show_bug.cgi?id=7353
struct S7353
{
@@ -2101,7 +2085,7 @@ void test7353()
}
/**********************************/
-// 8036
+// https://issues.dlang.org/show_bug.cgi?id=8036
struct S8036a
{
@@ -2142,7 +2126,7 @@ void test61()
}
/**********************************/
-// 7506
+// https://issues.dlang.org/show_bug.cgi?id=7506
void test7506()
{
@@ -2172,7 +2156,7 @@ void test7506()
}
/**********************************/
-// 7516
+// https://issues.dlang.org/show_bug.cgi?id=7516
struct S7516
{
@@ -2295,7 +2279,7 @@ void test7516e()
}
/**********************************/
-// 7530
+// https://issues.dlang.org/show_bug.cgi?id=7530
void test7530()
{
@@ -2352,7 +2336,7 @@ void test62()
}
/**********************************/
-// 7579
+// https://issues.dlang.org/show_bug.cgi?id=7579
void test7579a()
{
@@ -2425,7 +2409,7 @@ void test7579b()
}
/**********************************/
-// 8335
+// https://issues.dlang.org/show_bug.cgi?id=8335
struct S8335
{
@@ -2471,7 +2455,7 @@ void test8335()
}
/**********************************/
-// 8356
+// https://issues.dlang.org/show_bug.cgi?id=8356
void test8356()
{
@@ -2493,7 +2477,7 @@ void test8356()
}
/**********************************/
-// 8475
+// https://issues.dlang.org/show_bug.cgi?id=8475
T func8475(T)(T x) @safe pure
{
@@ -2535,7 +2519,7 @@ Foo9320 test9320(Foo9320 a, Foo9320 b, Foo9320 c) {
}
/**********************************/
-// 9386
+// https://issues.dlang.org/show_bug.cgi?id=9386
struct Test9386
{
@@ -2548,21 +2532,21 @@ struct Test9386
this(string name)
{
this.name = name;
- printf("Created %.*s...\n", name.length, name.ptr);
+ printf("Created %.*s...\n", cast(int)name.length, name.ptr);
assert(i + 1 < op.length);
op[i++] = 'a';
}
this(this)
{
- printf("Copied %.*s...\n", name.length, name.ptr);
+ printf("Copied %.*s...\n", cast(int)name.length, name.ptr);
assert(i + 1 < op.length);
op[i++] = 'b';
}
~this()
{
- printf("Deleted %.*s\n", name.length, name.ptr);
+ printf("Deleted %.*s\n", cast(int)name.length, name.ptr);
assert(i + 1 < op.length);
op[i++] = 'c';
}
@@ -2592,7 +2576,7 @@ void test9386()
printf("----\n");
foreach (Test9386 test; tests)
{
- printf("\tForeach %.*s\n", test.name.length, test.name.ptr);
+ printf("\tForeach %.*s\n", cast(int)test.name.length, test.name.ptr);
Test9386.op[Test9386.i++] = 'x';
}
@@ -2603,7 +2587,7 @@ void test9386()
printf("----\n");
foreach (ref Test9386 test; tests)
{
- printf("\tForeach %.*s\n", test.name.length, test.name.ptr);
+ printf("\tForeach %.*s\n", cast(int)test.name.length, test.name.ptr);
Test9386.op[Test9386.i++] = 'x';
}
assert(Test9386.sop == "xxxx");
@@ -2625,8 +2609,8 @@ void test9386()
printf("----\n");
foreach (Test9386 k, Test9386 v; tests)
{
- printf("\tForeach %.*s : %.*s\n", k.name.length, k.name.ptr,
- v.name.length, v.name.ptr);
+ printf("\tForeach %.*s : %.*s\n", cast(int)k.name.length, k.name.ptr,
+ cast(int)v.name.length, v.name.ptr);
Test9386.op[Test9386.i++] = 'x';
}
@@ -2637,8 +2621,8 @@ void test9386()
printf("----\n");
foreach (Test9386 k, ref Test9386 v; tests)
{
- printf("\tForeach %.*s : %.*s\n", k.name.length, k.name.ptr,
- v.name.length, v.name.ptr);
+ printf("\tForeach %.*s : %.*s\n", cast(int)k.name.length, k.name.ptr,
+ cast(int)v.name.length, v.name.ptr);
Test9386.op[Test9386.i++] = 'x';
}
assert(Test9386.sop == "bxcbxcbxcbxc");
@@ -2648,7 +2632,7 @@ void test9386()
}
/**********************************/
-// 9441
+// https://issues.dlang.org/show_bug.cgi?id=9441
auto x9441 = X9441(0.123);
@@ -2697,7 +2681,7 @@ struct Data
~this()
{
- printf("%d\n", _store._count);
+ printf("%zd\n", _store._count);
--_store._count;
}
}
@@ -2711,7 +2695,7 @@ void test9720()
}
/**********************************/
-// 9899
+// https://issues.dlang.org/show_bug.cgi?id=9899
struct S9899
{
@@ -2729,7 +2713,7 @@ void test9899() @safe pure nothrow
}
/**********************************/
-// 9907
+// https://issues.dlang.org/show_bug.cgi?id=9907
void test9907()
{
@@ -2746,13 +2730,13 @@ void test9907()
void opAssign(SX rhs)
{
- printf("%08X(%d) from Rvalue %08X(%d)\n", &this.i, this.i, &rhs.i, rhs.i);
+ printf("%08zX(%d) from Rvalue %08zX(%d)\n", cast(size_t)&this.i, this.i, cast(size_t)&rhs.i, rhs.i);
++assign;
}
void opAssign(ref SX rhs)
{
- printf("%08X(%d) from Lvalue %08X(%d)\n", &this.i, this.i, &rhs.i, rhs.i);
+ printf("%08zX(%d) from Lvalue %08zX(%d)\n", cast(size_t)&this.i, this.i, cast(size_t)&rhs.i, rhs.i);
assert(0);
}
@@ -2760,7 +2744,7 @@ void test9907()
{
~this()
{
- printf("destroying %08X(%d)\n", &this.i, this.i);
+ printf("destroying %08zX(%d)\n", cast(size_t)&this.i, this.i);
++dtor;
}
}
@@ -2793,12 +2777,12 @@ void test9907()
}
/**********************************/
-// 9985
+// https://issues.dlang.org/show_bug.cgi?id=9985
struct S9985
{
ubyte* b;
- ubyte buf[128];
+ ubyte[128] buf;
this(this) { assert(0); }
static void* ptr;
@@ -2864,7 +2848,7 @@ void test17457()
}
/**********************************/
-// 9994
+// https://issues.dlang.org/show_bug.cgi?id=9994
void test9994()
{
@@ -2884,7 +2868,7 @@ void test9994()
}
/**********************************/
-// 10053
+// https://issues.dlang.org/show_bug.cgi?id=10053
struct S10053A
{
@@ -2898,7 +2882,7 @@ struct S10053B
}
/**********************************/
-// 10055
+// https://issues.dlang.org/show_bug.cgi?id=10055
void test10055a()
{
@@ -2999,7 +2983,7 @@ void test10055b()
}
/**********************************/
-// 10160
+// https://issues.dlang.org/show_bug.cgi?id=10160
struct S10160 { this(this) {} }
@@ -3013,7 +2997,7 @@ void test10160()
}
/**********************************/
-// 10094
+// https://issues.dlang.org/show_bug.cgi?id=10094
void test10094()
{
@@ -3035,7 +3019,7 @@ void test10094()
}
/**********************************/
-// 10079
+// https://issues.dlang.org/show_bug.cgi?id=10079
// dtor || postblit
struct S10079a
@@ -3082,7 +3066,7 @@ static assert(__traits(compiles, &check10079!S10079e));
static assert(__traits(compiles, &check10079!S10079f));
/**********************************/
-// 10244
+// https://issues.dlang.org/show_bug.cgi?id=10244
void test10244()
{
@@ -3110,7 +3094,7 @@ void test10244()
}
/**********************************/
-// 10694
+// https://issues.dlang.org/show_bug.cgi?id=10694
struct Foo10694 { ~this() { } }
@@ -3126,7 +3110,7 @@ void test10694() pure
}
/**********************************/
-// 10787
+// https://issues.dlang.org/show_bug.cgi?id=10787
int global10787;
@@ -3145,7 +3129,7 @@ shared static ~this() nothrow pure @safe
}
/**********************************/
-// 10789
+// https://issues.dlang.org/show_bug.cgi?id=10789
struct S10789
{
@@ -3212,7 +3196,7 @@ void test10789()
}
/**********************************/
-// 10972
+// https://issues.dlang.org/show_bug.cgi?id=10972
int test10972()
{
@@ -3276,7 +3260,7 @@ int test10972()
static assert(test10972()); // CTFE
/**********************************/
-// 11134
+// https://issues.dlang.org/show_bug.cgi?id=11134
void test11134()
{
@@ -3312,7 +3296,7 @@ void test11134()
}
/**********************************/
-// 11197
+// https://issues.dlang.org/show_bug.cgi?id=11197
struct S11197a
{
@@ -3346,7 +3330,7 @@ void fun7474(T...)() { T x; }
void test7474() { fun7474!S7474(); }
/**********************************/
-// 11286
+// https://issues.dlang.org/show_bug.cgi?id=11286
struct A11286
{
@@ -3364,7 +3348,7 @@ void test11286()
}
/**********************************/
-// 11505
+// https://issues.dlang.org/show_bug.cgi?id=11505
struct Foo11505
{
@@ -3384,7 +3368,7 @@ void test11505()
}
/**********************************/
-// 12045
+// https://issues.dlang.org/show_bug.cgi?id=12045
bool test12045()
{
@@ -3435,7 +3419,7 @@ bool test12045()
static assert(test12045());
/**********************************/
-// 12591
+// https://issues.dlang.org/show_bug.cgi?id=12591
struct S12591(T)
{
@@ -3458,7 +3442,7 @@ void test12591()
}
/**********************************/
-// 12660
+// https://issues.dlang.org/show_bug.cgi?id=12660
struct X12660
{
@@ -3499,7 +3483,7 @@ void test12660() @nogc
}
/**********************************/
-// 12686
+// https://issues.dlang.org/show_bug.cgi?id=12686
struct Foo12686
{
@@ -3527,7 +3511,7 @@ void test12686()
}
/**********************************/
-// 13089
+// https://issues.dlang.org/show_bug.cgi?id=13089
struct S13089
{
@@ -3687,7 +3671,7 @@ void test13586()
}
/**********************************/
-// 14443
+// https://issues.dlang.org/show_bug.cgi?id=14443
T enforce14443(E : Throwable = Exception, T)(T value)
{
@@ -3831,7 +3815,10 @@ void test14443()
}
/**********************************/
-// 13661, 14022, 14023 - postblit/dtor call on static array assignment
+// postblit/dtor call on static array assignment
+// https://issues.dlang.org/show_bug.cgi?id=13661
+// https://issues.dlang.org/show_bug.cgi?id=14022
+// https://issues.dlang.org/show_bug.cgi?id=14023
bool test13661()
{
@@ -4039,7 +4026,7 @@ bool test14023()
static assert(test14023());
/************************************************/
-// 13669 - dtor call on static array variable
+// https://issues.dlang.org/show_bug.cgi?id=13669 - dtor call on static array variable
bool test13669()
{
@@ -4084,7 +4071,7 @@ void test13095()
}
/**********************************/
-// 14264
+// https://issues.dlang.org/show_bug.cgi?id=14264
void test14264()
{
@@ -4116,7 +4103,7 @@ void test14264()
}
/**********************************/
-// 14686
+// https://issues.dlang.org/show_bug.cgi?id=14686
int test14686()
{
@@ -4160,7 +4147,7 @@ int test14686()
static assert(test14686());
/**********************************/
-// 14815
+// https://issues.dlang.org/show_bug.cgi?id=14815
int test14815()
{
@@ -4222,7 +4209,7 @@ void test16197() {
}
/**********************************/
-// 14860
+// https://issues.dlang.org/show_bug.cgi?id=14860
int test14860()
{
@@ -4245,7 +4232,39 @@ int test14860()
static assert(test14860());
/**********************************/
-// 14696
+// https://issues.dlang.org/show_bug.cgi?id=14246
+
+struct A14246 {
+ int a = 3;
+ static string s;
+ this( int var ) { printf("A()\n"); a += var; s ~= "a"; }
+
+ ~this() { printf("~A()\n"); s ~= "b"; }
+}
+
+struct B14246 {
+ int i;
+ A14246 a;
+
+ this( int var ) {
+ A14246.s ~= "c";
+ a = A14246(var+1);
+ throw new Exception("An exception");
+ }
+}
+
+void test14246() {
+ try {
+ auto b = B14246(2);
+ } catch( Exception ex ) {
+ printf("Caught ex\n");
+ A14246.s ~= "d";
+ }
+ assert(A14246.s == "cabd");
+}
+
+/**********************************/
+// https://issues.dlang.org/show_bug.cgi?id=14696
void test14696(int len = 2)
{
@@ -4351,10 +4370,12 @@ void test14696(int len = 2)
check({ foo(len == 2 ? makeS(1).get(len != 2 ? makeS(2).get() : null) : null); }, "makeS(1).get(1).foo.dtor(1).");
check({ foo(len != 2 ? makeS(1).get(len == 2 ? makeS(2).get() : null) : null); }, "foo.");
check({ foo(len != 2 ? makeS(1).get(len != 2 ? makeS(2).get() : null) : null); }, "foo.");
+ check({ foo(len == 2 ? makeS(makeS(2).n - 1).get() : null); }, "makeS(2).makeS(1).get(1).foo.dtor(1).dtor(2).");
+ check({ foo(len != 2 ? makeS(makeS(2).n - 1).get() : null); }, "foo.");
}
/**********************************/
-// 14838
+// https://issues.dlang.org/show_bug.cgi?id=14838
int test14838() pure nothrow @safe
{
@@ -4408,6 +4429,21 @@ static assert(test14838());
/**********************************/
+// https://issues.dlang.org/show_bug.cgi?id=14639
+
+struct Biggy {
+ ulong[50000] a;
+ @disable this(this);
+}
+
+__gshared Biggy biggy;
+
+void test14639() {
+ biggy = Biggy.init;
+}
+
+/**********************************/
+
struct S63
{
private long p = 87;
@@ -4501,7 +4537,7 @@ void test65()
}
/**********************************/
-// 15661
+// https://issues.dlang.org/show_bug.cgi?id=15661
struct X15661
{
@@ -4542,10 +4578,253 @@ void test15661()
/**********************************/
-int main()
+// https://issues.dlang.org/show_bug.cgi?id=18045
+
+struct A18045
+{
+ nothrow:
+ __gshared int r;
+ int state;
+ this(this) { printf("postblit: A(%d)\n", state); r += 1; }
+ ~this() { printf("dtor: A(%d)\n", state); r *= 3; }
+}
+
+A18045 fun18045() nothrow
+{
+ __gshared a = A18045(42);
+ return a;
+}
+
+void test18045() nothrow
+{
+ alias A = A18045;
+
+ __gshared a = A(-42);
+ if (fun18045() == a)
+ assert(0);
+ else
+ assert(A.r == 3);
+
+ A.r = 0;
+ if (a == fun18045())
+ assert(0);
+ else
+ assert(A.r == 3);
+}
+
+/**********************************/
+
+struct S66
+{
+ ~this() { }
+}
+
+nothrow void notthrow() { }
+
+class C66
{
+ S66 s;
+
+ this() nothrow { notthrow(); }
+}
+
+/**********************************/
+// https://issues.dlang.org/show_bug.cgi?id=16652
+
+struct Vector
+{
+ this(ubyte a)
+ {
+ pragma(inline, false);
+ buf = a;
+ }
+
+ ~this()
+ {
+ pragma(inline, false);
+ buf = 0;
+ }
+
+ ubyte buf;
+}
+
+int bar16652(ubyte* v)
+{
+ pragma(inline, true);
+ assert(*v == 1);
+ return 0;
+}
+
+void test16652()
+{
+ bar16652(&Vector(1).buf);
+}
+
+
+/**********************************/
+// https://issues.dlang.org/show_bug.cgi?id=19676
+
+void test19676()
+{
+ static struct S
+ {
+ __gshared int count;
+ ~this() { ++count; }
+ }
+
+ static S foo() { return S(); }
+
+ static void test1()
+ {
+ cast(void)foo();
+ }
+
+ static void test2()
+ {
+ foo();
+ }
+
test1();
+ assert(S.count == 1);
test2();
+ assert(S.count == 2);
+}
+
+/**********************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=14708
+
+__gshared bool dtor14078 = false;
+
+struct S14078
+{
+ int n;
+
+ void* get(void* p = null)
+ {
+ return null;
+ }
+
+ ~this()
+ {
+ //printf("dtor\n");
+ dtor14078 = true;
+ }
+}
+
+S14078 makeS14078(int n)
+{
+ return S14078(n);
+}
+
+void foo14078(void* x)
+{
+ throw new Exception("fail!");
+}
+
+void test(int len = 2)
+{
+ foo14078(makeS14078(1).get());
+ // A temporary is allocated on stack for the
+ // return value from makeS14078(1).
+ // When foo14078 throws exception, it's dtor should be called
+ // during unwinding stack, but it does not happen in Win64.
+}
+
+void test14078()
+{
+ try
+ {
+ test();
+ } catch (Exception e) {}
+ assert(dtor14078); // fails!
+}
+
+/**********************************/
+
+void test67()
+{
+ char[] deleted;
+
+ struct S
+ {
+ char* p;
+
+ ~this() { deleted ~= *p; }
+
+ void opAssign(S rhs)
+ {
+ // swap
+ char* tmp = p;
+ this.p = rhs.p;
+ rhs.p = tmp;
+ }
+ }
+
+ char a = 'a', b = 'b';
+ {
+ S s = S(&a);
+ s = S(&b);
+ }
+ assert(deleted == "ab", deleted);
+}
+
+/**********************************/
+
+void test68()
+{
+ static struct S
+ {
+ int i;
+ bool opEquals(S) { return false; }
+ ~this() {}
+ }
+
+ assert(S(0) != S(1));
+}
+
+/**********************************/
+
+// https://github.com/dlang/dmd/pull/12012
+
+extern (C++)
+{
+struct S12012
+{
+ int* ctr;
+ ~this() { }
+}
+
+void bar12012(int value, S12012 s)
+{
+}
+
+S12012 abc12012(ref S12012 s)
+{
+ s.ctr = null;
+ return s;
+}
+
+int def12012(ref S12012 s)
+{
+ return *s.ctr; // seg fault is here
+}
+
+void testPR12012()
+{
+ int i;
+ S12012 s = S12012(&i);
+ // def must be executed before abc else seg fault
+ bar12012(def12012(s), abc12012(s));
+}
+}
+
+/**********************************/
+
+int main()
+{
+ test1();
+
test3();
test4();
test5();
@@ -4666,12 +4945,21 @@ int main()
test14815();
test16197();
test14860();
+ test14246();
test14696();
test14838();
+ test14639();
test63();
test64();
test65();
test15661();
+ test18045();
+ test16652();
+ test19676();
+ test14078();
+ test67();
+ test68();
+ testPR12012();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/statictor.d b/gcc/testsuite/gdc.test/runnable/statictor.d
index 7e34bd1..b00277b 100644
--- a/gcc/testsuite/gdc.test/runnable/statictor.d
+++ b/gcc/testsuite/gdc.test/runnable/statictor.d
@@ -1,7 +1,19 @@
-// PERMUTE_ARGS:
-// POST_SCRIPT: runnable/extra-files/statictor-postscript.sh
+/*
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+shared static this()
+Foo static ctor
+static ctor
+Bar static ctor
+Bar static dtor
+static dtor
+Foo static dtor
+shared static this()
+---
+*/
-private import std.stdio;
+private import core.stdc.stdio;
class Foo
{
@@ -29,7 +41,7 @@ class Bar
}
/***********************************************/
-// 6677
+// https://issues.dlang.org/show_bug.cgi?id=6677
int global6677;
@@ -50,7 +62,7 @@ shared static this() nothrow pure @safe
}
/***********************************************/
-// 7533
+// https://issues.dlang.org/show_bug.cgi?id=7533
struct Foo7533(int n)
{
pure static this() { }
@@ -64,4 +76,3 @@ int main()
{
return 0;
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/stress.d b/gcc/testsuite/gdc.test/runnable/stress.d
index a8c6c91..66373c4 100644
--- a/gcc/testsuite/gdc.test/runnable/stress.d
+++ b/gcc/testsuite/gdc.test/runnable/stress.d
@@ -83,10 +83,10 @@ void MDCHAR()
str[idx] = str[idx] ~ "TEST LINE\n";
}
- if(str.length != ITERS) printf("Length Error: %d\n",str.length);
- if(str[0].length != 10) printf("Length Error: %d\n",str[0].length);
- if(str[ITERS-1].sizeof != (typ[]).sizeof) printf("Size Error: %d\n",str[ITERS-1].sizeof);
- if(str[ITERS-1][0].sizeof != (typ).sizeof) printf("Size Error: %d\n",str[ITERS-1][0].sizeof);
+ if(str.length != ITERS) printf("Length Error: %zd\n",str.length);
+ if(str[0].length != 10) printf("Length Error: %zd\n",str[0].length);
+ if(str[ITERS-1].sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",str[ITERS-1].sizeof);
+ if(str[ITERS-1][0].sizeof != (typ).sizeof) printf("Size Error: %zd\n",str[ITERS-1][0].sizeof);
foreach(s; str) {
size_t lstart;
@@ -131,8 +131,8 @@ void CHAR()
str = str ~ "TEST LINE\n";
}
- if(str.length != (ITERS * 10)) printf("Length Error: %d\n",str.length);
- if(str.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",str.sizeof);
+ if(str.length != (ITERS * 10)) printf("Length Error: %zd\n",str.length);
+ if(str.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",str.sizeof);
size_t lstart;
foreach(size_t idx, char c; str) {
@@ -156,8 +156,8 @@ void WCHAR()
str = str ~ toUTF16(cast(char[])"TEST LINE\n");
}
- if(str.length != (ITERS * 10)) printf("Length Error: %d\n",str.length);
- if(str.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",str.sizeof);
+ if(str.length != (ITERS * 10)) printf("Length Error: %zd\n",str.length);
+ if(str.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",str.sizeof);
size_t lstart;
foreach(size_t idx, char c; str) {
@@ -181,8 +181,8 @@ void DCHAR()
str = str ~ toUTF32(cast(char[])"TEST LINE\n");
}
- if(str.length != (ITERS * 10)) printf("Length Error: %d\n",str.length);
- if(str.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",str.sizeof);
+ if(str.length != (ITERS * 10)) printf("Length Error: %zd\n",str.length);
+ if(str.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",str.sizeof);
size_t lstart;
foreach(size_t idx, char c; str) {
@@ -206,8 +206,8 @@ void BYTE()
a ~= idx;
}
- if(a.length != ITERS) printf("Length Error: %d\n",a.length);
- if(a.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",a.sizeof);
+ if(a.length != ITERS) printf("Length Error: %zd\n",a.length);
+ if(a.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",a.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(a[idx] != idx) {
printf("a Data Error: %d\n",a[idx]);
@@ -218,8 +218,8 @@ void BYTE()
typ[] b = a[];
- if(b.length != ITERS) printf("Length Error: %d\n",b.length);
- if(b.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",b.sizeof);
+ if(b.length != ITERS) printf("Length Error: %zd\n",b.length);
+ if(b.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",b.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(b[idx] != idx) {
printf("b Data Error: %d\n",b[idx]);
@@ -230,8 +230,8 @@ void BYTE()
c = a[0..ITERS/2] ~ b[ITERS/2..$];
- if(c.length != ITERS) printf("Length Error: %d\n",c.length);
- if(c.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",c.sizeof);
+ if(c.length != ITERS) printf("Length Error: %zd\n",c.length);
+ if(c.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",c.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(c[idx] != idx) {
printf("c Data Error: %d\n",c[idx]);
@@ -250,8 +250,8 @@ void UBYTE()
a ~= idx;
}
- if(a.length != ITERS) printf("Length Error: %d\n",a.length);
- if(a.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",a.sizeof);
+ if(a.length != ITERS) printf("Length Error: %zd\n",a.length);
+ if(a.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",a.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(a[idx] != idx) {
printf("a Data Error: %d\n",a[idx]);
@@ -262,8 +262,8 @@ void UBYTE()
typ[] b = a[];
- if(b.length != ITERS) printf("Length Error: %d\n",b.length);
- if(b.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",b.sizeof);
+ if(b.length != ITERS) printf("Length Error: %zd\n",b.length);
+ if(b.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",b.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(b[idx] != idx) {
printf("b Data Error: %d\n",b[idx]);
@@ -275,8 +275,8 @@ void UBYTE()
c = a[0..ITERS/2] ~ b[ITERS/2..$];
- if(c.length != ITERS) printf("Length Error: %d\n",c.length);
- if(c.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",c.sizeof);
+ if(c.length != ITERS) printf("Length Error: %zd\n",c.length);
+ if(c.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",c.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(c[idx] != idx) {
printf("c Data Error: %d\n",c[idx]);
@@ -295,8 +295,8 @@ void SHORT()
a ~= idx;
}
- if(a.length != ITERS) printf("Length Error: %d\n",a.length);
- if(a.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",a.sizeof);
+ if(a.length != ITERS) printf("Length Error: %zd\n",a.length);
+ if(a.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",a.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(a[idx] != idx) {
printf("a Data Error: %d\n",a[idx]);
@@ -306,8 +306,8 @@ void SHORT()
typ[] b = a[];
- if(b.length != ITERS) printf("Length Error: %d\n",b.length);
- if(b.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",b.sizeof);
+ if(b.length != ITERS) printf("Length Error: %zd\n",b.length);
+ if(b.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",b.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(b[idx] != idx) {
printf("b Data Error: %d\n",b[idx]);
@@ -319,8 +319,8 @@ void SHORT()
c = a[0..ITERS/2] ~ b[ITERS/2..$];
- if(c.length != ITERS) printf("Length Error: %d\n",c.length);
- if(c.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",c.sizeof);
+ if(c.length != ITERS) printf("Length Error: %zd\n",c.length);
+ if(c.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",c.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(c[idx] != idx) {
printf("c Data Error: %d\n",c[idx]);
@@ -339,8 +339,8 @@ void USHORT()
a ~= idx;
}
- if(a.length != ITERS) printf("Length Error: %d\n",a.length);
- if(a.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",a.sizeof);
+ if(a.length != ITERS) printf("Length Error: %zd\n",a.length);
+ if(a.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",a.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(a[idx] != idx) {
printf("a Data Error: %d\n",a[idx]);
@@ -350,8 +350,8 @@ void USHORT()
typ[] b = a[];
- if(b.length != ITERS) printf("Length Error: %d\n",b.length);
- if(b.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",b.sizeof);
+ if(b.length != ITERS) printf("Length Error: %zd\n",b.length);
+ if(b.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",b.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(b[idx] != idx) {
printf("b Data Error: %d\n",b[idx]);
@@ -363,8 +363,8 @@ void USHORT()
c = a[0..ITERS/2] ~ b[ITERS/2..$];
- if(c.length != ITERS) printf("Length Error: %d\n",c.length);
- if(c.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",c.sizeof);
+ if(c.length != ITERS) printf("Length Error: %zd\n",c.length);
+ if(c.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",c.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(c[idx] != idx) {
printf("c Data Error: %d\n",c[idx]);
@@ -383,8 +383,8 @@ void INT()
a ~= idx;
}
- if(a.length != ITERS) printf("Length Error: %d\n",a.length);
- if(a.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",a.sizeof);
+ if(a.length != ITERS) printf("Length Error: %zd\n",a.length);
+ if(a.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",a.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(a[idx] != idx) {
printf("a Data Error: %d\n",a[idx]);
@@ -395,8 +395,8 @@ void INT()
typ[] b = a[];
- if(b.length != ITERS) printf("Length Error: %d\n",b.length);
- if(b.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",b.sizeof);
+ if(b.length != ITERS) printf("Length Error: %zd\n",b.length);
+ if(b.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",b.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(b[idx] != idx) {
printf("b Data Error: %d\n",b[idx]);
@@ -408,8 +408,8 @@ void INT()
c = a[0..ITERS/2] ~ b[ITERS/2..$];
- if(c.length != ITERS) printf("Length Error: %d\n",c.length);
- if(c.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",c.sizeof);
+ if(c.length != ITERS) printf("Length Error: %zd\n",c.length);
+ if(c.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",c.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(c[idx] != idx) {
printf("c Data Error: %d\n",c[idx]);
@@ -428,8 +428,8 @@ void UINT()
a ~= idx;
}
- if(a.length != ITERS) printf("Length Error: %d\n",a.length);
- if(a.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",a.sizeof);
+ if(a.length != ITERS) printf("Length Error: %zd\n",a.length);
+ if(a.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",a.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(a[idx] != idx) {
printf("a Data Error: %d\n",a[idx]);
@@ -440,8 +440,8 @@ void UINT()
typ[] b = a[];
- if(b.length != ITERS) printf("Length Error: %d\n",b.length);
- if(b.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",b.sizeof);
+ if(b.length != ITERS) printf("Length Error: %zd\n",b.length);
+ if(b.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",b.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(b[idx] != idx) {
printf("b Data Error: %d\n",b[idx]);
@@ -453,8 +453,8 @@ void UINT()
c = a[0..ITERS/2] ~ b[ITERS/2..$];
- if(c.length != ITERS) printf("Length Error: %d\n",c.length);
- if(c.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",c.sizeof);
+ if(c.length != ITERS) printf("Length Error: %zd\n",c.length);
+ if(c.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",c.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(c[idx] != idx) {
printf("c Data Error: %d\n",c[idx]);
@@ -473,22 +473,22 @@ void LONG()
a ~= idx;
}
- if(a.length != ITERS) printf("Length Error: %d\n",a.length);
- if(a.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",a.sizeof);
+ if(a.length != ITERS) printf("Length Error: %zd\n",a.length);
+ if(a.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",a.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(a[idx] != idx) {
- printf("a Data Error: %d\n",a[idx]);
+ printf("a Data Error: %lld\n",a[idx]);
break;
}
}
typ[] b = a[];
- if(b.length != ITERS) printf("Length Error: %d\n",b.length);
- if(b.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",b.sizeof);
+ if(b.length != ITERS) printf("Length Error: %zd\n",b.length);
+ if(b.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",b.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(b[idx] != idx) {
- printf("b Data Error: %d\n",b[idx]);
+ printf("b Data Error: %lld\n",b[idx]);
break;
}
}
@@ -497,11 +497,11 @@ void LONG()
c = a[0..ITERS/2] ~ b[ITERS/2..$];
- if(c.length != ITERS) printf("Length Error: %d\n",c.length);
- if(c.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",c.sizeof);
+ if(c.length != ITERS) printf("Length Error: %zd\n",c.length);
+ if(c.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",c.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(c[idx] != idx) {
- printf("c Data Error: %d\n",c[idx]);
+ printf("c Data Error: %lld\n",c[idx]);
break;
}
}
@@ -517,22 +517,22 @@ void ULONG()
a ~= idx;
}
- if(a.length != ITERS) printf("Length Error: %d\n",a.length);
- if(a.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",a.sizeof);
+ if(a.length != ITERS) printf("Length Error: %zd\n",a.length);
+ if(a.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",a.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(a[idx] != idx) {
- printf("a Data Error: %d\n",a[idx]);
+ printf("a Data Error: %lld\n",a[idx]);
break;
}
}
typ[] b = a[];
- if(b.length != ITERS) printf("Length Error: %d\n",b.length);
- if(b.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",b.sizeof);
+ if(b.length != ITERS) printf("Length Error: %zd\n",b.length);
+ if(b.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",b.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(b[idx] != idx) {
- printf("b Data Error: %d\n",b[idx]);
+ printf("b Data Error: %lld\n",b[idx]);
break;
}
}
@@ -541,11 +541,11 @@ void ULONG()
c = a[0..ITERS/2] ~ b[ITERS/2..$];
- if(c.length != ITERS) printf("Length Error: %d\n",c.length);
- if(c.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",c.sizeof);
+ if(c.length != ITERS) printf("Length Error: %zd\n",c.length);
+ if(c.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",c.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(c[idx] != idx) {
- printf("c Data Error: %d\n",c[idx]);
+ printf("c Data Error: %lld\n",c[idx]);
break;
}
}
@@ -561,22 +561,22 @@ void FLOAT()
a ~= idx;
}
- if(a.length != ITERS) printf("Length Error: %d\n",a.length);
- if(a.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",a.sizeof);
+ if(a.length != ITERS) printf("Length Error: %zd\n",a.length);
+ if(a.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",a.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(a[idx] != idx) {
- printf("a Data Error: %d\n",a[idx]);
+ printf("a Data Error: %g\n",a[idx]);
break;
}
}
typ[] b = a[];
- if(b.length != ITERS) printf("Length Error: %d\n",b.length);
- if(b.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",b.sizeof);
+ if(b.length != ITERS) printf("Length Error: %zd\n",b.length);
+ if(b.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",b.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(b[idx] != idx) {
- printf("b Data Error: %d\n",b[idx]);
+ printf("b Data Error: %g\n",b[idx]);
break;
}
}
@@ -585,11 +585,11 @@ void FLOAT()
c = a[0..ITERS/2] ~ b[ITERS/2..$];
- if(c.length != ITERS) printf("Length Error: %d\n",c.length);
- if(c.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",c.sizeof);
+ if(c.length != ITERS) printf("Length Error: %zd\n",c.length);
+ if(c.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",c.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(c[idx] != idx) {
- printf("c Data Error: %d\n",c[idx]);
+ printf("c Data Error: %g\n",c[idx]);
break;
}
}
@@ -605,22 +605,22 @@ void DOUBLE()
a ~= idx;
}
- if(a.length != ITERS) printf("Length Error: %d\n",a.length);
- if(a.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",a.sizeof);
+ if(a.length != ITERS) printf("Length Error: %zd\n",a.length);
+ if(a.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",a.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(a[idx] != idx) {
- printf("a Data Error: %d\n",a[idx]);
+ printf("a Data Error: %g\n",a[idx]);
break;
}
}
typ[] b = a[];
- if(b.length != ITERS) printf("Length Error: %d\n",b.length);
- if(b.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",b.sizeof);
+ if(b.length != ITERS) printf("Length Error: %zd\n",b.length);
+ if(b.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",b.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(b[idx] != idx) {
- printf("b Data Error: %d\n",b[idx]);
+ printf("b Data Error: %g\n",b[idx]);
break;
}
}
@@ -629,11 +629,11 @@ void DOUBLE()
c = a[0..ITERS/2] ~ b[ITERS/2..$];
- if(c.length != ITERS) printf("Length Error: %d\n",c.length);
- if(c.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",c.sizeof);
+ if(c.length != ITERS) printf("Length Error: %zd\n",c.length);
+ if(c.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",c.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(c[idx] != idx) {
- printf("c Data Error: %d\n",c[idx]);
+ printf("c Data Error: %g\n",c[idx]);
break;
}
}
@@ -649,22 +649,22 @@ void REAL()
a ~= idx;
}
- if(a.length != ITERS) printf("Length Error: %d\n",a.length);
- if(a.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",a.sizeof);
+ if(a.length != ITERS) printf("Length Error: %zd\n",a.length);
+ if(a.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",a.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(a[idx] != idx) {
- printf("a Data Error: %d\n",a[idx]);
+ printf("a Data Error: %Lg\n",a[idx]);
break;
}
}
typ[] b = a[];
- if(b.length != ITERS) printf("Length Error: %d\n",b.length);
- if(b.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",b.sizeof);
+ if(b.length != ITERS) printf("Length Error: %zd\n",b.length);
+ if(b.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",b.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(b[idx] != idx) {
- printf("b Data Error: %d\n",b[idx]);
+ printf("b Data Error: %Lg\n",b[idx]);
break;
}
}
@@ -673,11 +673,11 @@ void REAL()
c = a[0..ITERS/2] ~ b[ITERS/2..$];
- if(c.length != ITERS) printf("Length Error: %d\n",c.length);
- if(c.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",c.sizeof);
+ if(c.length != ITERS) printf("Length Error: %zd\n",c.length);
+ if(c.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",c.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(c[idx] != idx) {
- printf("c Data Error: %d\n",c[idx]);
+ printf("c Data Error: %Lg\n",c[idx]);
break;
}
}
@@ -694,8 +694,8 @@ void CLASS()
a ~= tc;
}
- if(a.length != ITERS) printf("Length Error: %d\n",a.length);
- if(a.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",a.sizeof);
+ if(a.length != ITERS) printf("Length Error: %zd\n",a.length);
+ if(a.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",a.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(a[idx].i != idx) {
printf("a Data Error: %d\n",a[idx].i);
@@ -705,8 +705,8 @@ void CLASS()
typ[] b = a[];
- if(b.length != ITERS) printf("Length Error: %d\n",b.length);
- if(b.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",b.sizeof);
+ if(b.length != ITERS) printf("Length Error: %zd\n",b.length);
+ if(b.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",b.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(b[idx].i != idx) {
printf("b Data Error: %d\n",b[idx].i);
@@ -717,8 +717,8 @@ void CLASS()
typ[] c;
c = a[0..ITERS/2] ~ b[ITERS/2..$];
- if(c.length != ITERS) printf("Length Error: %d\n",c.length);
- if(c.sizeof != (typ[]).sizeof) printf("Size Error: %d\n",c.sizeof);
+ if(c.length != ITERS) printf("Length Error: %zd\n",c.length);
+ if(c.sizeof != (typ[]).sizeof) printf("Size Error: %zd\n",c.sizeof);
for(int idx = 0; idx < ITERS; idx++) {
if(c[idx].i != idx) {
printf("c Data Error: %d\n",c[idx].i);
diff --git a/gcc/testsuite/gdc.test/runnable/structlit.d b/gcc/testsuite/gdc.test/runnable/structlit.d
index 38af612..d4a6bd6 100644
--- a/gcc/testsuite/gdc.test/runnable/structlit.d
+++ b/gcc/testsuite/gdc.test/runnable/structlit.d
@@ -1,4 +1,12 @@
-import std.stdio;
+/*
+REQUIRED_ARGS: -preview=rvaluerefparam
+RUN_OUTPUT:
+---
+Success
+---
+*/
+
+import core.stdc.stdio;
struct S
{
@@ -318,13 +326,13 @@ int waz14(S)(ref S s) { return 2; }
void test14()
{
- // can not bind rvalue-sl with ref
- static assert(!__traits(compiles, foo14(S14a(0))));
- static assert(!__traits(compiles, foo14(S14b(0))));
- static assert(!__traits(compiles, hoo14(S14a(0))));
- static assert(!__traits(compiles, hoo14(S14b(0))));
- static assert(!__traits(compiles, poo14(S14a(0))));
- static assert(!__traits(compiles, poo14(S14b(0))));
+ // can bind rvalue-sl with ref
+ foo14(S14a(0));
+ foo14(S14b(0));
+ hoo14(S14a(0));
+ hoo14(S14b(0));
+ poo14(S14a(0));
+ poo14(S14b(0));
// still can bind rvalue-sl with non-ref
bar14(S14a(0));
@@ -491,7 +499,7 @@ void test15c()
auto c2 = new immutable C(1);
}
-void test15d() // Bugzilla 9974
+void test15d() // https://issues.dlang.org/show_bug.cgi?id=9974
{
class CM { this() {} }
auto cm = new CM();
@@ -525,7 +533,7 @@ void test15d() // Bugzilla 9974
shared const ssc = new shared const SSC(1);
}
-void test15e() // Bugzilla 10005
+void test15e() // https://issues.dlang.org/show_bug.cgi?id=10005
{
// struct literal
static struct S
@@ -642,7 +650,7 @@ void test9993b()
}
/********************************************/
-// 1914
+// https://issues.dlang.org/show_bug.cgi?id=1914
struct Bug1914a
{
@@ -703,7 +711,7 @@ void test3198and1914()
}
/********************************************/
-// 14996
+// https://issues.dlang.org/show_bug.cgi?id=14996
enum E14996a : string { confirm = "confirm" }
enum E14996b : long[] { confirm = [1,2,3,4] }
@@ -715,7 +723,7 @@ struct S14996
}
/********************************************/
-// 2427
+// https://issues.dlang.org/show_bug.cgi?id=2427
void test2427()
{
@@ -755,7 +763,7 @@ void test5885()
}
/********************************************/
-// 5889
+// https://issues.dlang.org/show_bug.cgi?id=5889
struct S5889a { int n; }
struct S5889b { this(int n){} }
@@ -812,7 +820,7 @@ void test5889()
}
/********************************************/
-// 4147
+// https://issues.dlang.org/show_bug.cgi?id=4147
struct S4247
{
@@ -829,7 +837,7 @@ void test4247()
}
/********************************************/
-// 6937
+// https://issues.dlang.org/show_bug.cgi?id=6937
void test6937()
{
@@ -885,7 +893,7 @@ void test6937()
}
/********************************************/
-// 12681
+// https://issues.dlang.org/show_bug.cgi?id=12681
struct HasUnion12774
{
@@ -930,7 +938,7 @@ bool test12681()
static assert(test12681());
/********************************************/
-// 3991
+// https://issues.dlang.org/show_bug.cgi?id=3991
union X3991
{
@@ -940,8 +948,8 @@ union X3991
union Y3991
{
- int a = void;
dchar b = 'a';
+ int a = void;
}
union Z3991
@@ -962,7 +970,7 @@ void test3991()
}
/********************************************/
-// 7727
+// https://issues.dlang.org/show_bug.cgi?id=7727
union U7727A1 { int i; double d; }
union U7727A2 { int i = 123; double d; }
@@ -990,7 +998,7 @@ void test7727()
{ U7727A2 u = { i: 1024, d: 1.225 }; }
));
-// Blocked by issue 1432
+// Blocked by https://issues.dlang.org/show_bug.cgi?id=1432
// { U7727A3 u; assert(u.d == 2.5); }
// { U7727A3 u = { i: 1024 }; assert(u.i == 1024); }
// { U7727A3 u = { d: 1.225 }; assert(u.d == 1.225); }
@@ -1012,7 +1020,7 @@ void test7727()
{ U7727B2 u = { i: 1024, d: 1.225 }; }
));
-// Blocked by issue 1432
+// Blocked by https://issues.dlang.org/show_bug.cgi?id=1432
// { U7727B3 u; assert(u.i == 123); }
// { U7727B3 u = { i: 1024 }; assert(u.i == 1024); }
// { U7727B3 u = { d: 1.225 }; assert(u.d == 1.225); }
@@ -1058,7 +1066,7 @@ void test7727b()
}
/********************************************/
-// 7929
+// https://issues.dlang.org/show_bug.cgi?id=7929
void test7929()
{
@@ -1076,7 +1084,7 @@ void test7929()
}
/********************************************/
-// 7021
+// https://issues.dlang.org/show_bug.cgi?id=7021
struct S7021
{
@@ -1091,7 +1099,7 @@ void test7021()
}
/********************************************/
-// 8738
+// https://issues.dlang.org/show_bug.cgi?id=8738
void test8738()
{
@@ -1108,7 +1116,7 @@ void test8738()
}
/********************************************/
-// 8763
+// https://issues.dlang.org/show_bug.cgi?id=8763
void test8763()
{
@@ -1128,7 +1136,7 @@ void test8763()
}
/********************************************/
-// 8902
+// https://issues.dlang.org/show_bug.cgi?id=8902
union U8902 { int a, b; }
@@ -1146,7 +1154,7 @@ void test8902()
}
/********************************************/
-// 9116
+// https://issues.dlang.org/show_bug.cgi?id=9116
void test9116()
{
@@ -1167,7 +1175,7 @@ void test9116()
}
/********************************************/
-// 9293
+// https://issues.dlang.org/show_bug.cgi?id=9293
void test9293()
{
@@ -1192,7 +1200,7 @@ void test9293()
}
/********************************************/
-// 9566
+// https://issues.dlang.org/show_bug.cgi?id=9566
void test9566()
{
@@ -1205,7 +1213,7 @@ void test9566()
}
/********************************************/
-// 9775
+// https://issues.dlang.org/show_bug.cgi?id=9775
enum Month9775 : ubyte { jan = 1, }
struct Date9775
@@ -1227,7 +1235,7 @@ enum Date9775 date9775e1 = Date9775(2012, 12, 21);
enum date9775e2 = Date9775(2012, 12, 21);
/********************************************/
-// 11105
+// https://issues.dlang.org/show_bug.cgi?id=11105
struct S11105
{
@@ -1240,7 +1248,7 @@ void test11105()
}
/********************************************/
-// 11147
+// https://issues.dlang.org/show_bug.cgi?id=11147
struct V11147
{
@@ -1273,7 +1281,7 @@ void test11147()
}
/********************************************/
-// 11256
+// https://issues.dlang.org/show_bug.cgi?id=11256
struct S11256 { @disable this(); }
@@ -1311,7 +1319,7 @@ void test11256()
}
/********************************************/
-// 11269
+// https://issues.dlang.org/show_bug.cgi?id=11269
struct Atom
{
@@ -1336,7 +1344,7 @@ void test11269()
}
/********************************************/
-// 11427
+// https://issues.dlang.org/show_bug.cgi?id=11427
struct S11427
{
@@ -1356,7 +1364,7 @@ int foo11427() @safe
}
/********************************************/
-// 12011
+// https://issues.dlang.org/show_bug.cgi?id=12011
struct S12011a
{
@@ -1379,7 +1387,7 @@ void test12011()
}
/********************************************/
-// 13021
+// https://issues.dlang.org/show_bug.cgi?id=13021
void test13021()
{
@@ -1417,7 +1425,7 @@ void test13021()
}
/********************************************/
-// 14556
+// https://issues.dlang.org/show_bug.cgi?id=14556
enum E14556 { a = 1 }
diff --git a/gcc/testsuite/gdc.test/runnable/template1.d b/gcc/testsuite/gdc.test/runnable/template1.d
index 51f96bf..dde9213 100644
--- a/gcc/testsuite/gdc.test/runnable/template1.d
+++ b/gcc/testsuite/gdc.test/runnable/template1.d
@@ -715,7 +715,7 @@ public template TRange29(T) {
recursing = false;
}
}
- } body {
+ } do {
return contains(other.lower()) || contains(other.upper()) || other.includes(this);
}
public bool includes(Range other)
@@ -723,7 +723,7 @@ public template TRange29(T) {
assert(other !is null);
} out (result) {
assert(result == (contains(other.lower()) && contains(other.upper())));
- } body {
+ } do {
return contains(other.lower()) && contains(other.upper());
}
}
@@ -771,22 +771,22 @@ void test30()
assert(i == 3);
copystr.copy(s, "Here it comes");
- printf("%.*s\n", s.length, s.ptr);
+ printf("%.*s\n", cast(int)s.length, s.ptr);
assert(s == "Here it comes");
}
/******************************************/
-import std.string;
+import core.demangle;
template Foo31(alias X)
{
- alias X.toStringz y;
+ alias X.demangle y;
}
void test31()
{
- alias Foo31!(std.string) bar;
+ alias Foo31!(core.demangle) bar;
}
@@ -1367,7 +1367,7 @@ void test56()
{
alias CT56!(int) Ct;
Ct.C c= new Ct.C();
- printf("%.*s\n", c.arrArr[0].length, c.arrArr[0].ptr);
+ printf("%.*s\n", cast(int)c.arrArr[0].length, c.arrArr[0].ptr);
assert(c.arrArr[0] == "foo");
}
@@ -1449,15 +1449,15 @@ void test60()
B60!(int, long).Thing thing1;
B60!(int).Thing thing2;
- printf("thing1.sizeof: %u\n", thing1.sizeof);
- printf("thing2.sizeof: %u\n", thing2.sizeof);
+ printf("thing1.sizeof: %zu\n", thing1.sizeof);
+ printf("thing2.sizeof: %zu\n", thing2.sizeof);
assert(thing1.sizeof == long.alignof + long.sizeof);
assert(thing2.sizeof == 8);
C60!(int /*,A60*/ ) container1;
- printf("container1.sizeof: %u\n", container1.sizeof);
+ printf("container1.sizeof: %zu\n", container1.sizeof);
assert(container1.sizeof == (void*).sizeof);
}
@@ -1604,7 +1604,7 @@ template Foo67(alias T)
{
void Foo67()
{
- printf("T = '%.*s'\n", T.length, T.ptr);
+ printf("T = '%.*s'\n", cast(int)T.length, T.ptr);
assert(T == "hello");
}
}
@@ -1620,7 +1620,7 @@ void test67()
/******************************************/
template T68(int a) {
- int vec[a];
+ int[a] vec;
}
void test68()
@@ -1637,7 +1637,7 @@ void test68()
size_t printx(string s)
{
- printf("s = '%.*s'\n", s.length, s.ptr);
+ printf("s = '%.*s'\n", cast(int)s.length, s.ptr);
return s.length;
}
@@ -1735,8 +1735,8 @@ void test72()
static ulong[5] a = [0,1,2,3,4];
static uint[5] b = [0,1,2,3,4];
char[] r;
- r = foo72!(ulong[5])(a); printf("%.*s\n", r.length, r.ptr);
- r = foo72!(uint[5])(b); printf("%.*s\n", r.length, r.ptr);
+ r = foo72!(ulong[5])(a); printf("%.*s\n", cast(int)r.length, r.ptr);
+ r = foo72!(uint[5])(b); printf("%.*s\n", cast(int)r.length, r.ptr);
}
diff --git a/gcc/testsuite/gdc.test/runnable/template13478.d b/gcc/testsuite/gdc.test/runnable/template13478.d
index 7fa7a18..b7b9709 100644
--- a/gcc/testsuite/gdc.test/runnable/template13478.d
+++ b/gcc/testsuite/gdc.test/runnable/template13478.d
@@ -1,3 +1,5 @@
+// EXTRA_FILES: imports/template13478a.d imports/template13478b.d
+
/// Tests emission of templates also referenced in speculative contexts.
/// Failure triggered with -inline.
module template13478;
diff --git a/gcc/testsuite/gdc.test/runnable/template2.d b/gcc/testsuite/gdc.test/runnable/template2.d
index 3adaeae..fe08a6c0 100644
--- a/gcc/testsuite/gdc.test/runnable/template2.d
+++ b/gcc/testsuite/gdc.test/runnable/template2.d
@@ -1,17 +1,16 @@
-// RUNNABLE_PHOBOS_TEST
// original post to the D newsgroup:
// http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=D&artnum=10554&header
// Test to manipulate 3D vectors, in D!
// by Sean L Palmer (seanpalmer@directvinternet.com)
// This code is released without any warranty. Use at your own risk.
import core.stdc.stdio;
-import std.math : sqrt;
+import core.math : sqrt;
template VecTemplate(tfloat, int dim:3)
{
struct Vector
{
- tfloat d[dim];
+ tfloat[dim] d;
version(none)
{
@@ -21,24 +20,24 @@ template VecTemplate(tfloat, int dim:3)
bool opEquals(Vector b) { for (int i=0; i<dim; ++i) if (d[i] != b.d[i]) return
false; return true; }
// negate (-a)
- Vector opNeg() { Vector r; for (int i=0; i<dim; ++i) r.d[i] = -d[i]; return
+ Vector opUnary(string op : "-")() { Vector r; for (int i=0; i<dim; ++i) r.d[i] = -d[i]; return
r; }
// complement (~a)
- Vector opCom() { Vector r; for (int i=0; i<dim; ++i) r.d[i] = d[(i+1)%dim];
+ Vector opUnary(string op : "~")() { Vector r; for (int i=0; i<dim; ++i) r.d[i] = d[(i+1)%dim];
d[0] = -d[0]; return r; }
// add (a + b)
- Vector opAdd(Vector b) { Vector r; r.d[] = d[] + b.d[]; return r; }
+ Vector opBinary(string op : "+")(Vector b) { Vector r; r.d[] = d[] + b.d[]; return r; }
// addto (a += b)
- Vector opAddAssign(Vector b) { d[] += b.d[]; return r; }
+ Vector opOpAssign(string op : "+")(Vector b) { d[] += b.d[]; return r; }
// subtract (a - b)
- Vector opSub(Vector b) { Vector r; r.d[] = d[] - b.d[]; return r; }
+ Vector opBinary(string op : "-")(Vector b) { Vector r; r.d[] = d[] - b.d[]; return r; }
// multiply by scalar (a * 2.0)
- Vector opMul(tfloat b) { Vector r; for (int i=0; i<dim; ++i) r.d[i] = d[i]
+ Vector opBinary(string op : "*")(tfloat b) { Vector r; for (int i=0; i<dim; ++i) r.d[i] = d[i]
* b; return r; }
// divide by scalar (a / b)
- Vector opDiv(tfloat b) { return *this * (1/b); }
+ Vector opBinary(string op : "/")(tfloat b) { return *this * (1/b); }
// dot product (a * b)
- tfloat opMul(Vector b) { tfloat r=0; for (int i=0; i<dim; ++i) r += d[i];
+ tfloat opBinary(string op : "*")(Vector b) { tfloat r=0; for (int i=0; i<dim; ++i) r += d[i];
return r; }
// outer product (a ^ b)
//Vector opXor(Vector b) { Vector r; for (int i=0; i<dim; ++i) r += d[i]; return r; }
@@ -49,27 +48,27 @@ return r; }
const bool opEquals(ref const Vector b) { for (int i=0; i<dim; ++i) if (d[i] != b.d[i]) return
false; return true; }
// negate (-a)
- Vector opNeg() { Vector r; for (int i=0; i<dim; ++i) r.d[i] = -d[i]; return
+ Vector opUnary(string op : "-")() { Vector r; for (int i=0; i<dim; ++i) r.d[i] = -d[i]; return
r; }
// complement (~a)
- Vector opCom() { Vector r; for (int i=0; i<dim; ++i) r.d[i] = d[(i+1)%dim];
+ Vector opUnary(string op : "~")() { Vector r; for (int i=0; i<dim; ++i) r.d[i] = d[(i+1)%dim];
d[0] = -d[0]; return r; }
// add (a + b)
- Vector opAdd(Vector b) { Vector r; for (int i=0; i<dim; ++i) r.d[i] = d[i] +
+ Vector opBinary(string op : "+")(Vector b) { Vector r; for (int i=0; i<dim; ++i) r.d[i] = d[i] +
b.d[i]; return r; }
// addto (a += b)
- Vector opAddAssign(Vector b) { for (int i=0; i<dim; ++i) d[i] += b.d[i]; return
+ Vector opOpAssign(string op : "+")(Vector b) { for (int i=0; i<dim; ++i) d[i] += b.d[i]; return
this; }
// subtract (a - b)
- Vector opSub(Vector b) { Vector r; for (int i=0; i<dim; ++i) r.d[i] = d[i] -
+ Vector opBinary(string op : "-")(Vector b) { Vector r; for (int i=0; i<dim; ++i) r.d[i] = d[i] -
b.d[i]; return r; }
// multiply by scalar (a * 2.0)
- Vector opMul(tfloat b) { Vector r; for (int i=0; i<dim; ++i) r.d[i] = d[i] *
+ Vector opBinary(string op : "*")(tfloat b) { Vector r; for (int i=0; i<dim; ++i) r.d[i] = d[i] *
b; return r; }
// divide by scalar (a / b)
- Vector opDiv(tfloat b) { return this * (1/b); }
+ Vector opBinary(string op : "/")(tfloat b) { return this * (1/b); }
// dot product (a * b)
- tfloat opMul(Vector b) { tfloat r=0; for (int i=0; i<dim; ++i) r += d[i];
+ tfloat opBinary(string op : "*")(Vector b) { tfloat r=0; for (int i=0; i<dim; ++i) r += d[i];
return r; }
// outer product (a ^ b)
//Vector opXor(Vector b) { Vector r; for (int i=0; i<dim; ++i) r += d[i]; return r; }
@@ -110,6 +109,3 @@ int main(char[][] args)
printf("closing\n");
return 0;
}
-
-
-
diff --git a/gcc/testsuite/gdc.test/runnable/template4.d b/gcc/testsuite/gdc.test/runnable/template4.d
index 0381d89..ae02c18 100644
--- a/gcc/testsuite/gdc.test/runnable/template4.d
+++ b/gcc/testsuite/gdc.test/runnable/template4.d
@@ -1,4 +1,4 @@
-/* RUNNABLE_PHOBOS_TEST
+/*
TEST_OUTPUT:
---
This actually gets evaluated!
@@ -10,7 +10,6 @@ Alias Test instantiated
Alias Test instantiated
---
*/
-import std.stdio;
import core.stdc.stdio;
/*********************************************************/
@@ -246,31 +245,6 @@ void test6()
/*********************************************************/
-template factorial7(float n, cdouble c, string sss, string ttt)
-{
- static if (n == 1)
- const float factorial7 = 1;
- else
- const float factorial7 = n * 2;
-}
-
-template bar7(wstring abc, dstring def)
-{
- const int x = 3;
-}
-
-void test7()
-{
- float f = factorial7!(4.25, 6.8+3i, "hello", null);
- printf("%g\n", f);
- assert(f == 8.5);
- int i = bar7!("abc"w, "def"d).x;
- printf("%d\n", i);
- assert(i == 3);
-}
-
-/*********************************************************/
-
template whale(string walrus)
{
const char [] whale = walrus;
@@ -449,20 +423,15 @@ template horse(string w)
void test14()
{
bool lion = zebra!("a");
- writeln(lion);
assert(!lion);
lion = zebra!("aqb");
- writeln(lion);
assert(lion);
lion = horse!("a");
- writeln(lion);
assert(lion);
lion = horse!("aqb");
- writeln(lion);
assert(lion);
lion = horse!("ab");
- writeln(lion);
assert(!lion);
}
@@ -529,7 +498,7 @@ void test16()
{
for (int i=0; i<smallfactorials.length; ++i)
{
- writefln("%d %d", i, smallfactorials[i]);
+ printf("%d %d\n", i, smallfactorials[i]);
assert(smallfactorials[i] == testtable[i]);
}
}
@@ -621,7 +590,7 @@ template sqrt(real x, real root = x/2, int ntries = 0)
void test20()
{
real x = sqrt!(2);
- writefln("%.20g", x); // 1.4142135623730950487
+ printf("%.20Lg\n", x); // 1.4142135623730950487
}
/*********************************************************/
@@ -642,7 +611,7 @@ uint foo21()
void test21()
{
auto i = foo21();
- writeln(i);
+ printf("%d\n", i);
assert(i == 1871483972);
}
@@ -826,10 +795,14 @@ void test31()
i2s[1] = "Hello";
i2s[5] = "There";
- writeln( i2s.get31(1, "yeh") );
- writeln( i2s.get31(2, "default") );
- writeln( i2s.get31(1) );
- writeln( i2s.get31(2) );
+ auto result = i2s.get31(1, "yeh");
+ printf("%.*s\n", cast(int)result.length, result.ptr);
+ result = i2s.get31(2, "default");
+ printf("%.*s\n", cast(int)result.length, result.ptr);
+ result = i2s.get31(1);
+ printf("%.*s\n", cast(int)result.length, result.ptr);
+ result = i2s.get31(2);
+ printf("%.*s\n", cast(int)result.length, result.ptr);
}
/*********************************************************/
@@ -860,7 +833,7 @@ struct Composer(T) {
}
return result;
}
- public void opAddAssign(Fun f) {
+ public void opOpAssign(string op)(Fun f) if (op == "+") {
funs ~= f;
}
}
@@ -904,14 +877,14 @@ void test33() {
comp += delegate double (double x) { return x/3.0;};
comp += delegate double (double x) { return x*x;};
comp += (double x) => x + 1.0;
- writefln("%f", comp(2.0));
+ printf("%f\n", comp(2.0));
// Try function objects
Composer!(double) comp2;
comp2 += tofp!(div3!(double))();
comp2 += tofp!(square!(double))();
comp2 += tofp!(plus1!(double))();
- writefln("%f", comp2( 2.0));
+ printf("%f\n", comp2( 2.0));
}
/*********************************************************/
@@ -1035,7 +1008,7 @@ void instantiate4652()
}
/*********************************************************/
-// 7589
+// https://issues.dlang.org/show_bug.cgi?id=7589
struct T7589(T)
{
@@ -1062,7 +1035,7 @@ void test39()
}
/*********************************************************/
-// 6701
+// https://issues.dlang.org/show_bug.cgi?id=6701
uint foo_6701(uint v:0)() { return 1; }
uint foo_6701(uint v)() { return 0; }
@@ -1076,7 +1049,7 @@ void test6701()
}
/******************************************/
-// 7469
+// https://issues.dlang.org/show_bug.cgi?id=7469
struct Foo7469a(int x) { }
struct Foo7469b(int x) { }
@@ -1142,7 +1115,6 @@ int main()
test4();
test5();
test6();
- test7();
test8();
test9();
test10();
diff --git a/gcc/testsuite/gdc.test/runnable/template9.d b/gcc/testsuite/gdc.test/runnable/template9.d
index 486eb67..63620dd 100644
--- a/gcc/testsuite/gdc.test/runnable/template9.d
+++ b/gcc/testsuite/gdc.test/runnable/template9.d
@@ -1,4 +1,5 @@
-/* RUNNABLE_PHOBOS_TEST
+/*
+REQUIRED_ARGS: -preview=rvaluerefparam
PERMUTE_ARGS:
EXTRA_FILES: imports/testmangle.d
TEST_OUTPUT:
@@ -123,19 +124,23 @@ void test4()
/**********************************/
-import std.stdio:writefln;
-
template foo5(T,S)
{
void foo5(T t, S s) {
- writefln("typeof(T)=",typeid(T)," typeof(S)=",typeid(S));
+ const tstr = typeid(T).toString();
+ const sstr = typeid(S).toString();
+ printf("typeof(T)=%.*s typeof(S)=%.*s\n",
+ cast(int)tstr.length, tstr.ptr, cast(int)sstr.length, sstr.ptr);
}
}
template bar5(T,S)
{
void bar5(S s) {
- writefln("typeof(T)=",typeid(T),"typeof(S)=",typeid(S));
+ const tstr = typeid(T).toString();
+ const sstr = typeid(S).toString();
+ printf("typeof(T)=%.*s typeof(S)=%.*s\n",
+ cast(int)tstr.length, tstr.ptr, cast(int)sstr.length, sstr.ptr);
}
}
@@ -200,7 +205,7 @@ void test7()
}
/**********************************/
-// 5946
+// https://issues.dlang.org/show_bug.cgi?id=5946
template TTest8()
{
@@ -217,7 +222,7 @@ void test8()
}
/**********************************/
-// 693
+// https://issues.dlang.org/show_bug.cgi?id=693
template TTest9(alias sym)
{
@@ -236,7 +241,7 @@ void test9()
}
/**********************************/
-// 1780
+// https://issues.dlang.org/show_bug.cgi?id=1780
template Tuple1780(Ts ...) { alias Ts Tuple1780; }
@@ -253,7 +258,7 @@ void test1780()
}
/**********************************/
-// 1659
+// https://issues.dlang.org/show_bug.cgi?id=1659
class Foo1659 { }
class Bar1659 : Foo1659 { }
@@ -267,7 +272,7 @@ void test1659()
}
/**********************************/
-// 2025
+// https://issues.dlang.org/show_bug.cgi?id=2025
struct S2025 {}
void f2025() {}
@@ -294,7 +299,7 @@ static assert(Baz2025!S2025 == 1); // 2 -> 1
static assert(Baz2025!f2025 == 2);
/**********************************/
-// 3608
+// https://issues.dlang.org/show_bug.cgi?id=3608
template foo3608(T, U){}
@@ -318,7 +323,7 @@ void test3608()
}
/**********************************/
-// 5015
+// https://issues.dlang.org/show_bug.cgi?id=5015
import breaker;
@@ -333,7 +338,7 @@ template _ElemType(T) {
}
/**********************************/
-// 5185
+// https://issues.dlang.org/show_bug.cgi?id=5185
class C5185(V)
{
@@ -349,7 +354,7 @@ void test5185()
}
/**********************************/
-// 5893
+// https://issues.dlang.org/show_bug.cgi?id=5893
class C5893
{
@@ -372,7 +377,7 @@ void test5893()
}
/**********************************/
-// 5988
+// https://issues.dlang.org/show_bug.cgi?id=5988
template Templ5988(alias T)
{
@@ -388,7 +393,7 @@ Templ5988!C5988b foo5988b; // Uncomment version
void test5988b() { C5988b!int a; } // Works
/**********************************/
-// 6404
+// https://issues.dlang.org/show_bug.cgi?id=6404
// receive only rvalue
void rvalue(T)(auto ref T x) if (!__traits(isRef, x)) {}
@@ -416,7 +421,7 @@ void test6404()
}
/**********************************/
-// 2246
+// https://issues.dlang.org/show_bug.cgi?id=2246
class A2246(T,d){
T p;
@@ -452,7 +457,7 @@ void test2246(){
}
/**********************************/
-// 2296
+// https://issues.dlang.org/show_bug.cgi?id=2296
void foo2296(size_t D)(int[D] i...){}
void test2296()
@@ -461,7 +466,7 @@ void test2296()
}
/**********************************/
-// 1684
+// https://issues.dlang.org/show_bug.cgi?id=1684
template Test1684( uint memberOffset ){}
@@ -494,7 +499,7 @@ void bug4984() {
}
/***************************************/
-// 2579
+// https://issues.dlang.org/show_bug.cgi?id=2579
void foo2579(T)(T delegate(in Object) dlg)
{
@@ -506,7 +511,7 @@ void test2579()
}
/**********************************/
-// 2803
+// https://issues.dlang.org/show_bug.cgi?id=2803
auto foo2803(T)(T t = 0) { return t; }
@@ -576,7 +581,7 @@ void test2803()
}
/**********************************/
-// 6613
+// https://issues.dlang.org/show_bug.cgi?id=6613
alias Tuple6613(T...) = T;
@@ -592,13 +597,14 @@ void test6613()
}
/**********************************/
-// 4953
+// https://issues.dlang.org/show_bug.cgi?id=4953
void bug4953(T = void)(short x) {}
static assert(is(typeof(bug4953(3))));
/**********************************/
-// 5886 & 5393
+// https://issues.dlang.org/show_bug.cgi?id=5886
+// https://issues.dlang.org/show_bug.cgi?id=5393
mixin template Foo5886(T)
{
@@ -666,7 +672,7 @@ void test5393()
}
/**********************************/
-// 5896
+// https://issues.dlang.org/show_bug.cgi?id=5896
struct X5896
{
@@ -691,7 +697,7 @@ void test5896()
}
/**********************************/
-// 6312
+// https://issues.dlang.org/show_bug.cgi?id=6312
void h6312() {}
@@ -715,7 +721,7 @@ void test6312()
}
/**********************************/
-// 6825
+// https://issues.dlang.org/show_bug.cgi?id=6825
void test6825()
{
@@ -731,7 +737,7 @@ void test6825()
}
/**********************************/
-// 6789
+// https://issues.dlang.org/show_bug.cgi?id=6789
template isStaticArray6789(T)
{
@@ -751,7 +757,7 @@ void test6789()
}
/**********************************/
-// 2778
+// https://issues.dlang.org/show_bug.cgi?id=2778
struct ArrayWrapper2778(T)
{
@@ -806,7 +812,7 @@ void test2778get()
static struct S
{
ubyte[] val = [1,2,3];
- @property ref ubyte[] get(){ return val; }
+ @property ref ubyte[] get() return { return val; }
alias get this;
}
S s;
@@ -814,7 +820,7 @@ void test2778get()
}
/**********************************/
-// 6208
+// https://issues.dlang.org/show_bug.cgi?id=6208
int getRefNonref(T)(ref T s){ return 1; }
int getRefNonref(T)( T s){ return 2; }
@@ -929,7 +935,7 @@ void test6208c()
}
/**********************************/
-// 6805
+// https://issues.dlang.org/show_bug.cgi?id=6805
struct T6805
{
@@ -941,7 +947,7 @@ struct T6805
static assert(is(T6805.xxx.Type == int));
/**********************************/
-// 6738
+// https://issues.dlang.org/show_bug.cgi?id=6738
struct Foo6738
{
@@ -960,7 +966,7 @@ void test6738()
}
/**********************************/
-// 7498
+// https://issues.dlang.org/show_bug.cgi?id=7498
template IndexMixin(){
void insert(T)(T value){ }
@@ -976,7 +982,7 @@ class MultiIndexContainer{
}
/**********************************/
-// 6780
+// https://issues.dlang.org/show_bug.cgi?id=6780
@property int foo6780()(){ return 10; }
@@ -993,7 +999,7 @@ void test6780()
}
/**********************************/
-// 6810
+// https://issues.dlang.org/show_bug.cgi?id=6810
int f6810(int n)(int) { return 1;}
int f6810(U...)(U) { assert(0); }
@@ -1007,7 +1013,7 @@ void test6810()
}
/**********************************/
-// 6891
+// https://issues.dlang.org/show_bug.cgi?id=6891
struct S6891(int N, T)
{
@@ -1021,7 +1027,7 @@ void test6891()
}
/**********************************/
-// 6994
+// https://issues.dlang.org/show_bug.cgi?id=6994
struct Foo6994
{
@@ -1044,7 +1050,7 @@ void test6994()
}
/**********************************/
-// 6764
+// https://issues.dlang.org/show_bug.cgi?id=6764
enum N6764 = 1; //use const for D1
@@ -1064,7 +1070,8 @@ void test6764()
}
/**********************************/
-// 3467 & 6806
+// https://issues.dlang.org/show_bug.cgi?id=3467
+// https://issues.dlang.org/show_bug.cgi?id=6806
struct Foo3467( uint n )
{
@@ -1087,11 +1094,11 @@ void test3467()
a1 ~ a2; // line 7, Error
}
-struct TS6806(size_t n) { pragma(msg, typeof(n)); }
+struct TS6806(uint n) { pragma(msg, typeof(n)); }
static assert(is(TS6806!(1u) == TS6806!(1)));
/**********************************/
-// 4413
+// https://issues.dlang.org/show_bug.cgi?id=4413
struct Foo4413
{
@@ -1112,7 +1119,7 @@ void test4413()
}
/**********************************/
-// 4675
+// https://issues.dlang.org/show_bug.cgi?id=4675
template isNumeric(T)
{
@@ -1130,7 +1137,7 @@ void test4675()
}
/**********************************/
-// 5525
+// https://issues.dlang.org/show_bug.cgi?id=5525
template foo5525(T)
{
@@ -1146,7 +1153,7 @@ void test5525()
}
/**********************************/
-// 5801
+// https://issues.dlang.org/show_bug.cgi?id=5801
int a5801;
void bar5801(T = double)(typeof(a5801) i) {}
@@ -1158,7 +1165,7 @@ void test5801()
}
/**********************************/
-// 5832
+// https://issues.dlang.org/show_bug.cgi?id=5832
struct Bar5832(alias v) {}
@@ -1188,7 +1195,7 @@ static assert( isBar5832b!(Bar5832!1234));
static assert(!isBar5832c!(Bar5832!1234));
/**********************************/
-// 2550
+// https://issues.dlang.org/show_bug.cgi?id=2550
template pow10_2550(long n)
{
@@ -1246,7 +1253,7 @@ void test10()
}
/**********************************/
-// 3092
+// https://issues.dlang.org/show_bug.cgi?id=3092
template Foo3092(A...)
{
@@ -1255,7 +1262,7 @@ template Foo3092(A...)
static assert(is(Foo3092!(int, "foo") == int));
/**********************************/
-// 7037
+// https://issues.dlang.org/show_bug.cgi?id=7037
struct Foo7037 {}
struct Bar7037 { Foo7037 f; alias f this; }
@@ -1270,7 +1277,7 @@ void test7037()
}
/**********************************/
-// 7110
+// https://issues.dlang.org/show_bug.cgi?id=7110
struct S7110
{
@@ -1304,7 +1311,7 @@ alias T7110!( (e7110[0]) ) D1; // passes
alias T7110!( e7110[0] ) D2; // fails: e7110 must be an array or pointer type, not S7110
/**********************************/
-// 7124
+// https://issues.dlang.org/show_bug.cgi?id=7124
template StaticArrayOf(T : E[dim], E, size_t dim)
{
@@ -1336,7 +1343,7 @@ void test7124()
}
/**********************************/
-// 7359
+// https://issues.dlang.org/show_bug.cgi?id=7359
bool foo7359(T)(T[] a ...)
{
@@ -1350,7 +1357,7 @@ void test7359()
}
/**********************************/
-// 7363
+// https://issues.dlang.org/show_bug.cgi?id=7363
template t7363()
{
@@ -1382,7 +1389,7 @@ alias S4371!("hi!") t;
static if (is(t U == S4371!(U))) { }
/**********************************/
-// 7416
+// https://issues.dlang.org/show_bug.cgi?id=7416
void t7416(alias a)() if(is(typeof(a())))
{}
@@ -1393,7 +1400,7 @@ void test7416() {
}
/**********************************/
-// 7563
+// https://issues.dlang.org/show_bug.cgi?id=7563
class Test7563
{
@@ -1411,7 +1418,7 @@ void test7563()
}
/**********************************/
-// 7572
+// https://issues.dlang.org/show_bug.cgi?id=7572
class F7572
{
@@ -1430,7 +1437,7 @@ void test7572()
}
/**********************************/
-// 7580
+// https://issues.dlang.org/show_bug.cgi?id=7580
struct S7580(T)
{
@@ -1462,7 +1469,7 @@ void test7580()
}
/**********************************/
-// 7585
+// https://issues.dlang.org/show_bug.cgi?id=7585
extern(C) alias void function() Callback;
@@ -1499,7 +1506,7 @@ void test7585()
}
/**********************************/
-// 7643
+// https://issues.dlang.org/show_bug.cgi?id=7643
template T7643(A...){ alias A T7643; }
@@ -1508,7 +1515,7 @@ alias T7643!(long, "x", string, "y") Specs7643;
alias T7643!( Specs7643[] ) U7643; // Error: tuple A is used as a type
/**********************************/
-// 7671
+// https://issues.dlang.org/show_bug.cgi?id=7671
inout(int)[3] id7671n1 ( inout(int)[3] );
inout( U )[n] id7671x1(U, size_t n)( inout( U )[n] );
@@ -1526,7 +1533,7 @@ void test7671()
}
/************************************/
-// 7672
+// https://issues.dlang.org/show_bug.cgi?id=7672
T foo7672(T)(T a){ return a; }
@@ -1540,7 +1547,7 @@ void test7672(inout(int[]) a = null, inout(int*) p = null)
}
/**********************************/
-// 7684
+// https://issues.dlang.org/show_bug.cgi?id=7684
U[] id7684(U)( U[] );
shared(U[]) id7684(U)( shared(U[]) );
@@ -1552,7 +1559,7 @@ void test7684()
}
/**********************************/
-// 7694
+// https://issues.dlang.org/show_bug.cgi?id=7694
void match7694(alias m)()
{
@@ -1573,7 +1580,7 @@ struct T7694
}
/**********************************/
-// 7755
+// https://issues.dlang.org/show_bug.cgi?id=7755
template to7755(T)
{
@@ -1628,7 +1635,7 @@ void test11b()
}
/**********************************/
-// 7769
+// https://issues.dlang.org/show_bug.cgi?id=7769
void f7769(K)(inout(K) value){}
void test7769()
@@ -1637,7 +1644,7 @@ void test7769()
}
/**********************************/
-// 7812
+// https://issues.dlang.org/show_bug.cgi?id=7812
template A7812(T...) {}
@@ -1651,7 +1658,7 @@ template D7812()
static assert(!__traits(compiles, D7812!()));
/**********************************/
-// 7873
+// https://issues.dlang.org/show_bug.cgi?id=7873
inout(T)* foo(T)(inout(T)* t)
{
@@ -1671,7 +1678,7 @@ void test7873()
}
/**********************************/
-// 7933
+// https://issues.dlang.org/show_bug.cgi?id=7933
struct Boo7933(size_t dim){int a;}
struct Baa7933(size_t dim)
@@ -1690,7 +1697,7 @@ void test7933()
}
/**********************************/
-// 8094
+// https://issues.dlang.org/show_bug.cgi?id=8094
struct Tuple8094(T...) {}
@@ -1728,14 +1735,14 @@ void test12()
}
/**********************************/
-// 14290
+// https://issues.dlang.org/show_bug.cgi?id=14290
struct Foo14290(int i) {}
alias Foo14290a = Foo14290!1;
static assert(!is(Foo14290!2 == Foo14290a!T, T...));
/**********************************/
-// 8125
+// https://issues.dlang.org/show_bug.cgi?id=8125
void foo8125(){}
@@ -1823,7 +1830,7 @@ void test15()
}
/**********************************/
-// 8129
+// https://issues.dlang.org/show_bug.cgi?id=8129
class X8129 {}
class A8129 {}
@@ -1857,7 +1864,7 @@ void test8129()
}
/**********************************/
-// 8238
+// https://issues.dlang.org/show_bug.cgi?id=8238
void test8238()
{
@@ -1873,7 +1880,7 @@ void test8238()
}
/**********************************/
-// 8669
+// https://issues.dlang.org/show_bug.cgi?id=8669
struct X8669
{
@@ -1939,7 +1946,7 @@ void test8669()
}
/**********************************/
-// 8833
+// https://issues.dlang.org/show_bug.cgi?id=8833
template TypeTuple8833(T...) { alias TypeTuple = T; }
@@ -1956,7 +1963,7 @@ void test8833()
}
/**********************************/
-// 8976
+// https://issues.dlang.org/show_bug.cgi?id=8976
void f8976(ref int) { }
@@ -1971,17 +1978,17 @@ void h8976()()
g8976!()();
}
-static assert(! __traits(compiles, h8976!()() ) ); // causes error
-static assert(!is(typeof( h8976!()() )));
+static assert( __traits(compiles, h8976!()() ) ); // causes error
+static assert(is(typeof( h8976!()() )));
void test8976()
{
- static assert(! __traits(compiles, h8976!()() ) );
- static assert(!is(typeof( h8976!()() )));
+ static assert( __traits(compiles, h8976!()() ) );
+ static assert(is(typeof( h8976!()() )));
}
/****************************************/
-// 8940
+// https://issues.dlang.org/show_bug.cgi?id=8940
const int n8940; // or `immutable`
static this() { n8940 = 3; }
@@ -2002,7 +2009,8 @@ void test8940()
}
/**********************************/
-// 6969 + 8990
+// https://issues.dlang.org/show_bug.cgi?id=6969
+// https://issues.dlang.org/show_bug.cgi?id=8990
class A6969() { alias C6969!() C1; }
class B6969 { alias A6969!() A1; }
@@ -2013,7 +2021,7 @@ struct B8990(T) { A8990!T* a; }
struct C8990 { B8990!C8990* b; }
/**********************************/
-// 9018
+// https://issues.dlang.org/show_bug.cgi?id=9018
template Inst9018(alias Template, T)
{
@@ -2029,7 +2037,7 @@ static assert(!__traits(compiles, Inst9018!(Template9018, int))); // Assert pass
static assert(!__traits(compiles, Inst9018!(Template9018, int))); // Assert fails
/**********************************/
-// 9022
+// https://issues.dlang.org/show_bug.cgi?id=9022
class C9022
{
@@ -2074,7 +2082,7 @@ void test9022()
}
/**********************************/
-// 9026
+// https://issues.dlang.org/show_bug.cgi?id=9026
mixin template node9026()
{
@@ -2107,7 +2115,7 @@ void test9026()
}
/**********************************/
-// 9038
+// https://issues.dlang.org/show_bug.cgi?id=9038
mixin template Foo9038()
{
@@ -2142,7 +2150,7 @@ void test9038()
}
/**********************************/
-// 9050
+// https://issues.dlang.org/show_bug.cgi?id=9050
struct A9050(T) {}
@@ -2159,7 +2167,7 @@ auto foo9050()(A9050!int base) pure
auto s9050 = foo9050(A9050!int());
/**********************************/
-// 10936 (dup of 9050)
+// https://issues.dlang.org/show_bug.cgi?id=10936 (dup of 9050)
struct Vec10936(string s)
{
@@ -2178,7 +2186,7 @@ struct Vec10936(string s)
Vec10936!"" v;
/**********************************/
-// 9076
+// https://issues.dlang.org/show_bug.cgi?id=9076
template forward9076(args...)
{
@@ -2193,7 +2201,7 @@ void test9076()
}
/**********************************/
-// 9083
+// https://issues.dlang.org/show_bug.cgi?id=9083
template isFunction9083(X...) if (X.length == 1)
{
@@ -2231,7 +2239,7 @@ class C9083
}
/**********************************/
-// 9100
+// https://issues.dlang.org/show_bug.cgi?id=9100
template Id(alias A) { alias Id = A; }
template ErrId(alias A) { static assert(0); }
@@ -2287,7 +2295,7 @@ void test9100()
}
/**********************************/
-// 9101
+// https://issues.dlang.org/show_bug.cgi?id=9101
class Node9101
{
@@ -2300,7 +2308,7 @@ class Node9101
enum x9101 = __traits(compiles, Node9101.ForwardCtorNoId!());
/**********************************/
-// 9124
+// https://issues.dlang.org/show_bug.cgi?id=9124
struct Foo9124a(N...)
{
@@ -2353,7 +2361,7 @@ void test9124b()
}
/**********************************/
-// 9143
+// https://issues.dlang.org/show_bug.cgi?id=9143
struct Foo9143a(bool S, bool L)
{
@@ -2392,7 +2400,7 @@ void test9143()
}
/**********************************/
-// 9266
+// https://issues.dlang.org/show_bug.cgi?id=9266
template Foo9266(T...)
{
@@ -2408,7 +2416,7 @@ void test9266()
}
/**********************************/
-// 9361
+// https://issues.dlang.org/show_bug.cgi?id=9361
struct Unit9361(A)
{
@@ -2429,7 +2437,7 @@ void test9361()
}
/**********************************/
-// 9536
+// https://issues.dlang.org/show_bug.cgi?id=9536
struct S9536
{
@@ -2450,7 +2458,7 @@ void test9536()
}
/**********************************/
-// 9578
+// https://issues.dlang.org/show_bug.cgi?id=9578
template t9578(alias f) { void tf()() { f(); } }
@@ -2467,7 +2475,7 @@ void test9578()
}
/**********************************/
-// 9596
+// https://issues.dlang.org/show_bug.cgi?id=9596
int foo9596a(K, V)(inout( V [K])) { return 1; }
int foo9596a(K, V)(inout(shared(V) [K])) { return 2; }
@@ -2499,7 +2507,7 @@ void test9596()
}
/******************************************/
-// 9806
+// https://issues.dlang.org/show_bug.cgi?id=9806
struct S9806a(alias x)
{
@@ -2535,7 +2543,7 @@ alias S9806c!1 One9806c;
alias S9806c!0.Next!() OneAgain9806c;
/******************************************/
-// 9837
+// https://issues.dlang.org/show_bug.cgi?id=9837
void test9837()
{
@@ -2576,7 +2584,7 @@ void test9837()
}
/******************************************/
-// 9874
+// https://issues.dlang.org/show_bug.cgi?id=9874
bool foo9874() { return true; }
void bar9874(T)(T) if (foo9874()) {} // OK
@@ -2667,7 +2675,7 @@ void test9885()
}
/******************************************/
-// 9971
+// https://issues.dlang.org/show_bug.cgi?id=9971
void goo9971()()
{
@@ -2691,7 +2699,7 @@ void test9971()
}
/******************************************/
-// 9977
+// https://issues.dlang.org/show_bug.cgi?id=9977
void test9977()
{
@@ -2730,7 +2738,7 @@ static assert(T8848b!([1:2,3:4]) == [1:2,3:4]);
static assert(T8848c!(null) == null);
/******************************************/
-// 9990
+// https://issues.dlang.org/show_bug.cgi?id=9990
auto initS9990() { return "hi"; }
@@ -2739,7 +2747,7 @@ class C9990(alias init) {}
alias SC9990 = C9990!(initS9990);
/******************************************/
-// 10067
+// https://issues.dlang.org/show_bug.cgi?id=10067
struct assumeSize10067(alias F) {}
@@ -2753,7 +2761,7 @@ template useItemAt10067(size_t idx, T)
useItemAt10067!(0, char) mapS10067;
/******************************************/
-// 4072
+// https://issues.dlang.org/show_bug.cgi?id=4072
void bug4072(T)(T x)
if (is(typeof(bug4072(x))))
@@ -2762,7 +2770,7 @@ void bug4072(T)(T x)
static assert(!is(typeof(bug4072(7))));
/******************************************/
-// 10074
+// https://issues.dlang.org/show_bug.cgi?id=10074
template foo10074(F)
{
@@ -2777,7 +2785,7 @@ bool foo10074(F)(F f)
static assert(!is(typeof(foo10074(1))));
/******************************************/
-// 10083
+// https://issues.dlang.org/show_bug.cgi?id=10083
// [a-c] IFTI can find syntactic eponymous member
template foo10083a(T)
@@ -2867,7 +2875,7 @@ void test10083()
}
/******************************************/
-// 10134
+// https://issues.dlang.org/show_bug.cgi?id=10134
template ReturnType10134(alias func)
{
@@ -2914,7 +2922,7 @@ template b10134()
pragma(msg, getResultType10134!(a10134!()));
/******************************************/
-// 10313
+// https://issues.dlang.org/show_bug.cgi?id=10313
void test10313()
{
@@ -2933,7 +2941,7 @@ void test10313()
}
/******************************************/
-// 10498
+// https://issues.dlang.org/show_bug.cgi?id=10498
template triggerIssue10498a()
{
@@ -2985,7 +2993,7 @@ void test10498b()
}
/******************************************/
-// 10537
+// https://issues.dlang.org/show_bug.cgi?id=10537
struct Iota10537
{
@@ -3010,7 +3018,7 @@ dstring rewriteCode10537(dstring code)
}
/******************************************/
-// 10558
+// https://issues.dlang.org/show_bug.cgi?id=10558
template Template10558() {}
@@ -3029,7 +3037,7 @@ template foo10558(alias T)
}
/******************************************/
-// 10592
+// https://issues.dlang.org/show_bug.cgi?id=10592
void test10592()
{
@@ -3058,7 +3066,7 @@ void test10592()
}
/******************************************/
-// 11242
+// https://issues.dlang.org/show_bug.cgi?id=11242
inout(T[]) fromString11242(T)(inout(char[]) s, T[] dst)
{
@@ -3072,7 +3080,7 @@ void test11242()
}
/******************************************/
-// 10811
+// https://issues.dlang.org/show_bug.cgi?id=10811
void foo10811a(R1, R2)(R1, R2) {}
template foo10811a(alias pred) { void foo10811a(R1, R2)(R1, R2) {} }
@@ -3090,7 +3098,7 @@ void test10811()
}
/******************************************/
-// 10969
+// https://issues.dlang.org/show_bug.cgi?id=10969
template A10969(T, U...) { alias A10969 = T; }
void foo10969(T, U...)(A10969!(T, U) a) {}
@@ -3105,7 +3113,7 @@ void test10969()
}
/******************************************/
-// 11271
+// https://issues.dlang.org/show_bug.cgi?id=11271
struct SmartPtr11271(T)
{
@@ -3120,7 +3128,7 @@ void test11271()
}
/******************************************/
-// 11533
+// https://issues.dlang.org/show_bug.cgi?id=11533
version (none)
{
@@ -3171,7 +3179,7 @@ void test11533()
}
/******************************************/
-// 11553
+// https://issues.dlang.org/show_bug.cgi?id=11553
struct Pack11553(T ...)
{
@@ -3226,7 +3234,7 @@ static if ( hl11553!(Pack11553!(5))) { pragma(msg, "All good 2"); }
static if (!hl11553!(Pack11553!( ))) { pragma(msg, "All good 3"); }
/******************************************/
-// 11818
+// https://issues.dlang.org/show_bug.cgi?id=11818
enum E11818 { e0, e1 }
@@ -3244,13 +3252,13 @@ void test11818()
}
/******************************************/
-// 11843
+// https://issues.dlang.org/show_bug.cgi?id=11843
void test11843()
{
struct Foo
{
- int x[string];
+ int[string] x;
}
struct Bar(alias foo) {}
@@ -3268,7 +3276,7 @@ void test11843()
}
/******************************************/
-// 11872
+// https://issues.dlang.org/show_bug.cgi?id=11872
class Foo11872
{
@@ -3299,7 +3307,7 @@ void test11872()
}
/******************************************/
-// 12042
+// https://issues.dlang.org/show_bug.cgi?id=12042
struct S12042
{
@@ -3324,7 +3332,7 @@ int test12042()
static assert(test12042());
/******************************************/
-// 12077
+// https://issues.dlang.org/show_bug.cgi?id=12077
struct S12077(A) {}
@@ -3336,7 +3344,7 @@ alias U12077( T : Base!Args, alias Base, Args...) = Base;
static assert(__traits(isSame, U12077!(S12077!int), S12077));
/******************************************/
-// 12262
+// https://issues.dlang.org/show_bug.cgi?id=12262
template Inst12262(T) { int x; }
@@ -3347,7 +3355,7 @@ static assert(fqnSym12262!(Inst12262!(Object)) == 2);
static assert(fqnSym12262!(Inst12262!(Object).x) == 1);
/******************************************/
-// 12264
+// https://issues.dlang.org/show_bug.cgi?id=12264
struct S12264(A) {}
@@ -3372,7 +3380,7 @@ static assert(TY12264!(S12264!int) == 2);
static assert(TZ12264!(S12264!int) == 2);
/******************************************/
-// 12122
+// https://issues.dlang.org/show_bug.cgi?id=12122
enum N12122 = 1;
@@ -3385,7 +3393,7 @@ void test12122()
}
/******************************************/
-// 12186
+// https://issues.dlang.org/show_bug.cgi?id=12186
template map_front12186(fun...)
{
@@ -3406,7 +3414,7 @@ void test12186()
}
/******************************************/
-// 12207
+// https://issues.dlang.org/show_bug.cgi?id=12207
void test12207()
{
@@ -3421,7 +3429,7 @@ void test12207()
}
/******************************************/
-// 12263
+// https://issues.dlang.org/show_bug.cgi?id=12263
template A12263(alias a) { int x; }
template B12263(alias a) { int x; }
@@ -3435,7 +3443,7 @@ static assert(fqnSym12263!(A12263!(Object)));
static assert(fqnSym12263!(B12263!(Object)));
/******************************************/
-// 12290
+// https://issues.dlang.org/show_bug.cgi?id=12290
void test12290()
{
@@ -3520,7 +3528,7 @@ void test12290()
}
/******************************************/
-// 12292
+// https://issues.dlang.org/show_bug.cgi?id=12292
void test12292()
{
@@ -3532,7 +3540,7 @@ void test12292()
}
/******************************************/
-// 12376
+// https://issues.dlang.org/show_bug.cgi?id=12376
static auto encode12376(size_t sz)(dchar ch) if (sz > 1)
{
@@ -3545,7 +3553,7 @@ void test12376()
}
/******************************************/
-// 12447
+// https://issues.dlang.org/show_bug.cgi?id=12447
enum test12447(string str) = str; // [1]
string test12447(T...)(T args) if (T.length) { return args[0]; } // [2]
@@ -3560,7 +3568,7 @@ static assert(test12447("foo") == "foo");
static assert(test12447!("bar") == "bar");
/******************************************/
-// 12651
+// https://issues.dlang.org/show_bug.cgi?id=12651
alias TemplateArgsOf12651(alias T : Base!Args, alias Base, Args...) = Args;
@@ -3569,7 +3577,7 @@ struct S12651(T) { }
static assert(!__traits(compiles, TemplateArgsOf12651!(S12651!int, S, float)));
/******************************************/
-// 12719
+// https://issues.dlang.org/show_bug.cgi?id=12719
struct A12719
{
@@ -3598,7 +3606,7 @@ struct W12719(R)
W12719!int a12719;
/******************************************/
-// 12746
+// https://issues.dlang.org/show_bug.cgi?id=12746
template foo12746()
{
@@ -3620,7 +3628,7 @@ void test12746()
}
/******************************************/
-// 12748
+// https://issues.dlang.org/show_bug.cgi?id=12748
void foo12748(S, C : typeof(S.init[0]))(S s, C c)
{
@@ -3632,7 +3640,7 @@ void test12748()
}
/******************************************/
-// 9708
+// https://issues.dlang.org/show_bug.cgi?id=9708
struct S9708
{
@@ -3646,13 +3654,13 @@ void test9708()
}
/******************************************/
-// 12880
+// https://issues.dlang.org/show_bug.cgi?id=12880
void f12880(T)(in T value) { static assert(is(T == string)); }
void test12880() { f12880(string.init); }
/******************************************/
-// 13087
+// https://issues.dlang.org/show_bug.cgi?id=13087
struct Vec13087
{
@@ -3674,7 +3682,7 @@ template component13087(alias vec, char c)
}
/******************************************/
-// 13127
+// https://issues.dlang.org/show_bug.cgi?id=13127
/+void test13127(inout int = 0)
{
@@ -3895,7 +3903,7 @@ void test13127a()
}
/******************************************/
-// 13159
+// https://issues.dlang.org/show_bug.cgi?id=13159
template maxSize13159(T...)
{
@@ -3924,7 +3932,7 @@ struct Node13159
}
/******************************************/
-// 13180
+// https://issues.dlang.org/show_bug.cgi?id=13180
void test13180()
{
@@ -3962,7 +3970,7 @@ void test13180()
}
/******************************************/
-// 13204
+// https://issues.dlang.org/show_bug.cgi?id=13204
struct A13204(uint v)
{
@@ -3994,7 +4002,7 @@ void test13204()
}
/******************************************/
-// 8462 (dup of 13204)
+// https://issues.dlang.org/show_bug.cgi?id=8462 (dup of 13204)
alias FP8462 = void function(C8462.Type arg);
@@ -4005,7 +4013,7 @@ class C8462
}
/******************************************/
-// 13218
+// https://issues.dlang.org/show_bug.cgi?id=13218
template isCallable13218(T...)
if (T.length == 1)
@@ -4039,7 +4047,7 @@ struct R13218
}
/******************************************/
-// 13219
+// https://issues.dlang.org/show_bug.cgi?id=13219
struct Map13219(V) {}
@@ -4059,7 +4067,7 @@ void test13219()
}
/******************************************/
-// 13223
+// https://issues.dlang.org/show_bug.cgi?id=13223
void test13223()
{
@@ -4125,7 +4133,7 @@ void test13223a()
}
/******************************************/
-// 13235
+// https://issues.dlang.org/show_bug.cgi?id=13235
struct Tuple13235(T...)
{
@@ -4171,7 +4179,7 @@ void test13235()
}
/******************************************/
-// 13252
+// https://issues.dlang.org/show_bug.cgi?id=13252
alias TypeTuple13252(T...) = T;
@@ -4181,9 +4189,6 @@ static assert(is(typeof(TypeTuple13252!(cast(long)1)[0]) == long));
static assert(is(typeof(TypeTuple13252!(cast(float )3.14)[0]) == float ));
static assert(is(typeof(TypeTuple13252!(cast(double)3.14)[0]) == double));
-static assert(is(typeof(TypeTuple13252!(cast(cfloat )(1 + 2i))[0]) == cfloat ));
-static assert(is(typeof(TypeTuple13252!(cast(cdouble)(1 + 2i))[0]) == cdouble));
-
static assert(is(typeof(TypeTuple13252!(cast(string )null)[0]) == string ));
static assert(is(typeof(TypeTuple13252!(cast(string[])null)[0]) == string[])); // OK <- NG
@@ -4198,7 +4203,7 @@ static assert(is(typeof(TypeTuple13252!(const S13252())[0]) == const(S13
static assert(is(typeof(TypeTuple13252!(immutable S13252())[0]) == immutable(S13252))); // OK <- NG
/******************************************/
-// 13294
+// https://issues.dlang.org/show_bug.cgi?id=13294
void test13294()
{
@@ -4218,7 +4223,7 @@ void test13294()
f(src, dst);
}
- // 13351
+ // https://issues.dlang.org/show_bug.cgi?id=13351
T add(T)(in T x, in T y)
{
T z;
@@ -4232,7 +4237,7 @@ void test13294()
}
/******************************************/
-// 13299
+// https://issues.dlang.org/show_bug.cgi?id=13299
struct Foo13299
{
@@ -4263,7 +4268,7 @@ void test13299()
}
/******************************************/
-// 13333
+// https://issues.dlang.org/show_bug.cgi?id=13333
template AliasThisTypeOf13333(T)
{
@@ -4315,7 +4320,7 @@ void test13333()
}
/******************************************/
-// 13374
+// https://issues.dlang.org/show_bug.cgi?id=13374
int f13374(alias a)() { return 1; }
int f13374(string s)() { return 2; }
@@ -4328,7 +4333,7 @@ void test13374()
}
/******************************************/
-// 14109
+// https://issues.dlang.org/show_bug.cgi?id=14109
string f14109() { return "a"; }
string g14109()() { return "a"; }
@@ -4340,7 +4345,7 @@ alias Y14109 = S14109!(g14109!());
static assert(is(X14109 == Y14109));
/******************************************/
-// 13378
+// https://issues.dlang.org/show_bug.cgi?id=13378
struct Vec13378(size_t n, T, string as)
{
@@ -4356,7 +4361,7 @@ void test13378()
}
/******************************************/
-// 13379
+// https://issues.dlang.org/show_bug.cgi?id=13379
void test13379()
{
@@ -4395,7 +4400,7 @@ MinType13379!T min13379(T...)(T args) // #4 MinType!uint (speculative && thist
}
/******************************************/
-// 13417
+// https://issues.dlang.org/show_bug.cgi?id=13417
struct V13417(size_t N, E, alias string AS)
{
@@ -4412,7 +4417,7 @@ void test13417()
}
/******************************************/
-// 13484
+// https://issues.dlang.org/show_bug.cgi?id=13484
int foo13484()(void delegate() hi) { return 1; }
int foo13484(T)(void delegate(T) hi) { return 2; }
@@ -4424,7 +4429,7 @@ void test13484()
}
/******************************************/
-// 13675
+// https://issues.dlang.org/show_bug.cgi?id=13675
enum E13675;
@@ -4440,7 +4445,7 @@ void test13675()
}
/******************************************/
-// 13694
+// https://issues.dlang.org/show_bug.cgi?id=13694
auto foo13694(T)(string A, T[] G ...) { return 1; }
auto foo13694(T)(string A, long E, T[] G ...) { return 2; }
@@ -4456,7 +4461,7 @@ void test13694()
}
/******************************************/
-// 13760
+// https://issues.dlang.org/show_bug.cgi?id=13760
void test13760()
{
@@ -4468,7 +4473,7 @@ void test13760()
}
/******************************************/
-// 13714
+// https://issues.dlang.org/show_bug.cgi?id=13714
struct JSONValue13714
{
@@ -4497,7 +4502,7 @@ void test13714()
}
/******************************************/
-// 13807
+// https://issues.dlang.org/show_bug.cgi?id=13807
T f13807(T)(inout(T)[] arr)
{
@@ -4512,7 +4517,7 @@ void test13807()
}
/******************************************/
-// 14174
+// https://issues.dlang.org/show_bug.cgi?id=14174
import imports.testmangle;
struct Config14174(a, b) {}
@@ -4521,6 +4526,7 @@ struct N14174 {}
alias defConfig14174 = Config14174!(N14174, N14174);
+@safe @nogc pure nothrow
void accepter14174a(Config : Config14174!(T) = defConfig14174, T...)()
{
static assert(equalDemangle(accepter14174a.mangleof,
@@ -4528,9 +4534,10 @@ void accepter14174a(Config : Config14174!(T) = defConfig14174, T...)()
"accepter14174a"~
"HTS7breaker51__T11Config14174TS7breaker6N14174TS7breaker6N14174Z11Config14174TS7breaker6N14174TS7breaker6N14174Z14"~
"accepter14174a"~
- "FZv"));
+ "FNaNbNiNfZv"));
}
+@safe @nogc pure nothrow
void accepter14174b(Config : Config14174!(T) = defConfig14174, T...)()
{
static assert(equalDemangle(accepter14174b.mangleof,
@@ -4538,17 +4545,18 @@ void accepter14174b(Config : Config14174!(T) = defConfig14174, T...)()
"accepter14174b"~
"HTS7breaker51__T11Config14174TS7breaker6N14174TS7breaker6N14174Z11Config14174TS7breaker6N14174TS7breaker6N14174Z14"~
"accepter14174b"~
- "FZv"));
+ "FNaNbNiNfZv"));
}
void test14174()
{
- accepter14174a!()(); // ok
- accepter14174b(); // error
+ accepter14174a!()();
+
+ accepter14174b!()();
}
/******************************************/
-// 14836
+// https://issues.dlang.org/show_bug.cgi?id=14836
template a14836x(alias B, C...)
{
@@ -4571,7 +4579,7 @@ void test14836()
}
/******************************************/
-// 14357
+// https://issues.dlang.org/show_bug.cgi?id=14357
template Qux14357(T : U*, U : V*, V)
{
@@ -4583,7 +4591,7 @@ template Qux14357(T : U*, U : V*, V)
static assert(!__traits(compiles, Qux14357!(float**, int*)));
/******************************************/
-// 14481
+// https://issues.dlang.org/show_bug.cgi?id=14481
template someT14481(alias e)
{
@@ -4602,7 +4610,7 @@ struct Hoge14481
}
/******************************************/
-// 14520
+// https://issues.dlang.org/show_bug.cgi?id=14520
template M14520(alias a) { enum M14520 = 1; }
template M14520(string s) { enum M14520 = 2; }
@@ -4616,7 +4624,7 @@ static assert(M14520!f14520b == 1);
static assert(M14520!f14520c == 1);
/******************************************/
-// 14568
+// https://issues.dlang.org/show_bug.cgi?id=14568
struct Interval14568()
{
@@ -4659,7 +4667,8 @@ template SubOps14568(Args...)
struct Nat14568 { mixin SubOps14568!(null); }
/******************************************/
-// 14603, 14604
+// https://issues.dlang.org/show_bug.cgi?id=14603
+// https://issues.dlang.org/show_bug.cgi?id=14604
struct S14603
{
@@ -4683,7 +4692,7 @@ alias c14604 = Id14604!(S14604.opDispatch!"go"); // ok
alias d14604 = Id14604!(S14604.go); // issue 14604, 'Error: template instance opDispatch!"go" cannot resolve forward reference'
/******************************************/
-// 14735
+// https://issues.dlang.org/show_bug.cgi?id=14735
enum CS14735 { yes, no }
@@ -4707,7 +4716,7 @@ void test14735()
}
/******************************************/
-// 14743
+// https://issues.dlang.org/show_bug.cgi?id=14743
class A14743
{
@@ -4716,7 +4725,7 @@ class A14743
}
/******************************************/
-// 14802
+// https://issues.dlang.org/show_bug.cgi?id=14802
void test14802()
{
@@ -4756,7 +4765,7 @@ void test14802()
}
/******************************************/
-// 14886
+// https://issues.dlang.org/show_bug.cgi?id=14886
void test14886()
{
@@ -4778,9 +4787,9 @@ void test14886()
}
/******************************************/
-// 15156
+// https://issues.dlang.org/show_bug.cgi?id=15156
-// 15156
+// https://issues.dlang.org/show_bug.cgi?id=15156
auto f15116a(T)(string s, string arg2) { return 1; }
auto f15116b(T)(int i, string arg2) { return 2; }
@@ -4798,7 +4807,7 @@ void test15116()
}
/******************************************/
-// 15152
+// https://issues.dlang.org/show_bug.cgi?id=15152
void test15152()
{
@@ -4814,7 +4823,7 @@ void test15152()
}
/******************************************/
-// 15352
+// https://issues.dlang.org/show_bug.cgi?id=15352
struct S15352(T, T delegate(uint idx) supplier)
{
@@ -4844,7 +4853,7 @@ void test15352()
}
/******************************************/
-// 15623
+// https://issues.dlang.org/show_bug.cgi?id=15623
struct WithFoo15623a { void foo() {} }
struct WithFoo15623b { void foo() {} }
@@ -4875,7 +4884,7 @@ static assert( __traits(compiles, { alias Baz = CallsFoo15623!WithFoo15623d; ret
static assert(!__traits(compiles, { alias Baz = CallsFoo15623!WithoutFoo15623d; return Baz.init; }()));
/******************************************/
-// 15781
+// https://issues.dlang.org/show_bug.cgi?id=15781
void test15781()
{
@@ -4898,6 +4907,133 @@ void test15781()
}
/******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=16042
+
+struct Foo16042 {}
+
+auto map16042(alias func, T)(T t)
+{
+ return func(t);
+}
+
+auto toChars16042(R)(R r) if (is(R == int[]))
+{
+ Foo16042 f;
+ assert(toChars16042(f) == 1); // OK
+ assert(map16042!(toChars16042)(f) == 1); // OK <- NG
+ assert(map16042!((toChars16042))(f) == 1); // OK
+}
+
+auto toChars16042(Foo16042 f)
+{
+ return 1;
+}
+
+void test16042()
+{
+ [1].toChars16042();
+}
+
+// ---
+
+auto fn16042(R)(R r) if (is(R == int[])) {}
+auto fn16042(Foo16042 f) { return 1; }
+
+struct Namespace16042
+{
+ alias fn = fn16042!(int[]);
+}
+
+void test16042b()
+{
+ Foo16042 f;
+
+ with (Namespace16042)
+ {
+ static assert(!__traits(compiles, fn(f))); // NG
+ static assert(!__traits(compiles, map16042!(fn)(f))); // should be NG -> actually NG
+ static assert(!__traits(compiles, map16042!((fn))(f))); // NG
+ }
+}
+
+/******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15243
+
+struct S15243(Types...)
+{
+ void apply1(U)(U delegate(Types[0]) f0) {}
+
+ void apply2(U)(U delegate(Types) f0) {}
+
+ void apply3(U)(U delegate(Types[1..$]) f0) {}
+}
+
+void test15243()
+{
+ int f1(int) { return 0; }
+ int f2(int, long) { return 0; }
+ int f3(long, string) { return 0; }
+
+ S15243!(int) s1;
+ s1.apply1(&f1);
+ s1.apply2(&f1);
+
+ S15243!(int, long) s2;
+ s2.apply2(&f2);
+
+ S15243!(int, long, string) s3;
+ s3.apply3(&f3);
+}
+
+/******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15653
+
+alias TypeTuple15653(T...) = T;
+
+void test15653()
+{
+ void foo(U, T)(const T x) { static assert(is(T == U)); }
+ void bar(U, T)(immutable T x) { static assert(is(T == U)); }
+
+ struct X { int a; long[2] b; }
+ struct Y { int* a; long[] b; }
+
+ foreach (U; TypeTuple15653!( byte, short, int, long,
+ ubyte, ushort, uint, ulong,
+ float, double, real,
+ void delegate(),
+ int[2], X, X[2]))
+ {
+ foo!U(U.init); // OK
+ bar!U(U.init); // Was error, now OK
+
+ U u;
+ foo!U(u); // OK
+ bar!U(u); // Was error, now OK
+ }
+
+ foreach (U; TypeTuple15653!(void*, int**, long[], double*[2]))
+ {
+ foo!U(U.init); // OK
+ bar!U(U.init); // Was error, now OK
+
+ U u;
+ foo!U(u);
+ static assert(!__traits(compiles, bar!U(u)), U.stringof);
+ }
+
+ foreach (U; TypeTuple15653!(Object, Y, Y[2], int[int]))
+ {
+ foo!U(U.init); // OK
+ static assert(!__traits(compiles, bar!U(U.init)), U.stringof);
+
+ U u;
+ foo!U(u); // OK
+ static assert(!__traits(compiles, bar!U(u)), U.stringof);
+ }
+}
+
+/******************************************/
int main()
{
@@ -5011,6 +5147,10 @@ int main()
test14735();
test14802();
test15116();
+ test16042();
+ test16042b();
+ test15243();
+ test15653();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/test10.d b/gcc/testsuite/gdc.test/runnable/test10.d
index 671a61a..b9f8885 100644
--- a/gcc/testsuite/gdc.test/runnable/test10.d
+++ b/gcc/testsuite/gdc.test/runnable/test10.d
@@ -1,4 +1,10 @@
-// EXTRA_SOURCES: imports/test10a.d
+/*
+EXTRA_SOURCES: imports/test10a.d
+RUN_OUTPUT:
+---
+it is 32
+---
+*/
import imports.test10a;
diff --git a/gcc/testsuite/gdc.test/runnable/test10378.d b/gcc/testsuite/gdc.test/runnable/test10378.d
index f83ece1..8ad457a 100644
--- a/gcc/testsuite/gdc.test/runnable/test10378.d
+++ b/gcc/testsuite/gdc.test/runnable/test10378.d
@@ -1,4 +1,4 @@
-
+// EXTRA_FILES: imports/bar10378.d
int writeln() { return 3; }
struct S {
diff --git a/gcc/testsuite/gdc.test/runnable/test10619.d b/gcc/testsuite/gdc.test/runnable/test10619.d
new file mode 100644
index 0000000..4156289
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test10619.d
@@ -0,0 +1,38 @@
+/*
+https://issues.dlang.org/show_bug.cgi?id=10619
+
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+1
+2
+3
+4
+---
+*/
+
+void main()
+{
+ {
+ int x = 1;
+ print!x();
+ }
+ {
+ int x = 2;
+ print!x();
+ }
+ {
+ static int y = 3;
+ print!y();
+ }
+ {
+ static int y = 4;
+ print!y();
+ }
+}
+
+void print(alias symbol)()
+{
+ import core.stdc.stdio : printf;
+ printf("%d\n", symbol);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test10736.d b/gcc/testsuite/gdc.test/runnable/test10736.d
index 55b6f53..0b70606 100644
--- a/gcc/testsuite/gdc.test/runnable/test10736.d
+++ b/gcc/testsuite/gdc.test/runnable/test10736.d
@@ -1,5 +1,12 @@
-// EXTRA_SOURCES: imports/test10736a.d
-// EXTRA_SOURCES: imports/test10736b.d
+/*
+EXTRA_SOURCES: imports/test10736a.d
+EXTRA_SOURCES: imports/test10736b.d
+EXTRA_FILES: imports/test10736c.d
+RUN_OUTPUT:
+---
+success
+---
+*/
import imports.test10736a;
import imports.test10736b;
diff --git a/gcc/testsuite/gdc.test/runnable/test10942.d b/gcc/testsuite/gdc.test/runnable/test10942.d
index 0d48946..8c45c20 100644
--- a/gcc/testsuite/gdc.test/runnable/test10942.d
+++ b/gcc/testsuite/gdc.test/runnable/test10942.d
@@ -1,16 +1,22 @@
-// RUNNABLE_PHOBOS_TEST
// REQUIRED_ARGS: -g
-import std.string;
-
string getEnum(size_t count)
{
string en;
en ~= "enum KeyCode\n { \n";
- foreach (i; 0 .. count)
+ foreach (i; 1 .. count + 1)
{
- en ~= format(" memb_%s = %s,\n", i+1, i+1);
+ char[4] buffer;
+ int start = buffer.length;
+
+ while (i > 0)
+ {
+ buffer[--start] = cast(char) ('0' + (i % 10));
+ i /= 10;
+ }
+ char[] id = buffer[start .. $];
+ en ~= "memb_" ~ id ~ " = " ~ id ~ ",\n";
}
en ~= "} ";
diff --git a/gcc/testsuite/gdc.test/runnable/test11.d b/gcc/testsuite/gdc.test/runnable/test11.d
index 0d916c1..abaae37 100644
--- a/gcc/testsuite/gdc.test/runnable/test11.d
+++ b/gcc/testsuite/gdc.test/runnable/test11.d
@@ -1,5 +1,5 @@
-// RUNNABLE_PHOBOS_TEST
// REQUIRED_ARGS:
+// EXTRA_SOURCES: imports/std11file.d
extern(C) int printf(const char*, ...);
extern(C) size_t strlen(const char*);
@@ -531,14 +531,14 @@ struct NODE27 {
shared(NODE27) *next;
}
-static shared NODE27 nodetbl[3] =
+static shared NODE27[3] nodetbl =
[
{ 0,cast(shared(NODE27)*)nodetbl + 1},
{ 0,cast(shared(NODE27)*)nodetbl + 2},
{ 0,null}
];
-static shared NODE27 nodetbl2[3] = [
+static shared NODE27[3] nodetbl2 = [
{ 0,&nodetbl2[1]},
{ 0,&nodetbl2[2]},
{ 0,null}
@@ -682,7 +682,7 @@ void test35()
try {
alias Foo35!( Bar35 ) filter;
} catch (Exception e) {
- printf( "Exception %.*s", e.msg.length, e.msg.ptr );
+ printf( "Exception %.*s", cast(int)e.msg.length, e.msg.ptr );
} finally {
printf( "Done0." );
}
@@ -886,7 +886,7 @@ void test45()
char[5] foo;
foo[] = "hello";
- printf("'%.*s'\n", foo.length, foo.ptr);
+ printf("'%.*s'\n", cast(int)foo.length, foo.ptr);
func45(cast(string)foo);
}
@@ -1182,15 +1182,15 @@ void test62()
class A63
{
- private import std.file;
- alias std.file.getcwd getcwd;
+ private import imports.std11file;
+ alias imports.std11file.getcwd getcwd;
}
void test63()
{
A63 f = new A63();
auto s = f.getcwd();
- printf("%.*s\n", s.length, s.ptr);
+ printf("%.*s\n", cast(int)s.length, s.ptr);
}
@@ -1229,7 +1229,7 @@ void test65()
}
/**************************************/
-// 8809
+// https://issues.dlang.org/show_bug.cgi?id=8809
void test8809()
{
@@ -1298,7 +1298,7 @@ void test8809()
}
/**************************************/
-// 9734
+// https://issues.dlang.org/show_bug.cgi?id=9734
void test9734()
{
diff --git a/gcc/testsuite/gdc.test/runnable/test11447c.d b/gcc/testsuite/gdc.test/runnable/test11447c.d
index d09e3d2..ecec3e5 100644
--- a/gcc/testsuite/gdc.test/runnable/test11447c.d
+++ b/gcc/testsuite/gdc.test/runnable/test11447c.d
@@ -1,6 +1,7 @@
// COMPILE_SEPARATELY
// EXTRA_SOURCES: imports/c11447.d
-// PERMUTE_ARGS: -allinst -w -debug -g
+// REQUIRED_ARGS: -w
+// PERMUTE_ARGS: -allinst -debug -g
import imports.c11447;
diff --git a/gcc/testsuite/gdc.test/runnable/test11863.d b/gcc/testsuite/gdc.test/runnable/test11863.d
index c1285b3..f6446aa 100644
--- a/gcc/testsuite/gdc.test/runnable/test11863.d
+++ b/gcc/testsuite/gdc.test/runnable/test11863.d
@@ -1,6 +1,6 @@
// COMPILE_SEPARATELY
// EXTRA_SOURCES: imports/std11863conv.d
-// EXTRA_FILES: imports/std11863format.d
+// EXTRA_FILES: imports/std11863bitmanip.d imports/std11863format.d
import imports.std11863conv;
diff --git a/gcc/testsuite/gdc.test/runnable/test11934.d b/gcc/testsuite/gdc.test/runnable/test11934.d
new file mode 100644
index 0000000..4ab65d2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test11934.d
@@ -0,0 +1,22 @@
+void main()
+{
+ struct Struct11934
+ {
+ this(int i) { instances++; }
+ this(this) { instances++; }
+ ~this() { instances--; }
+ static size_t instances = 0;
+ }
+
+ struct Range11934
+ {
+ void popFront() { cnt++; }
+ @property front() { return Struct11934(0); }
+ @property empty() { return cnt >= 10; }
+ size_t cnt;
+ }
+
+ foreach(ref i; Range11934()) { }
+
+ assert(Struct11934.instances == 0);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test12.d b/gcc/testsuite/gdc.test/runnable/test12.d
index eb7e422..dac4ed6 100644
--- a/gcc/testsuite/gdc.test/runnable/test12.d
+++ b/gcc/testsuite/gdc.test/runnable/test12.d
@@ -1,4 +1,3 @@
-// RUNNABLE_PHOBOS_TEST
// PERMUTE_ARGS: -unittest -O -release -inline -fPIC -g
extern(C) int printf(const char*, ...);
@@ -156,7 +155,7 @@ int[] fun(int i)
{
assert(result[0] == 2);
}
- body
+ do
{
char result;
int[] res = new int[10];
@@ -312,15 +311,15 @@ void test12()
class A13
{
- int opShl(char* v) { return 1; }
- int opShl(string v) { return 2; }
+ int opBinary(string op : "<<")(char* v) { return 1; }
+ int opBinary(string op : "<<")(string v) { return 2; }
}
void test13()
{
A13 a = new A13();
int i;
- i = a.opShl(cast(string)"");
+ i = a << cast(string) "";
assert(i == 2);
i = a << cast(string)"";
assert(i == 2);
@@ -366,32 +365,32 @@ union U6
void test14()
{
- printf("%d %d %d\n", U1.a.offsetof, U1.b.offsetof, U1.sizeof);
+ printf("%zd %zd %zd\n", U1.a.offsetof, U1.b.offsetof, U1.sizeof);
assert(U1.a.offsetof == 0);
assert(U1.b.offsetof == 0);
assert(U1.sizeof == 4);
- printf("%d %d %d\n", U2.a.offsetof, U2.b.offsetof, U2.sizeof);
+ printf("%zd %zd %zd\n", U2.a.offsetof, U2.b.offsetof, U2.sizeof);
assert(U2.a.offsetof == 0);
assert(U2.b.offsetof == 0);
assert(U2.sizeof == 8);
- printf("%d %d %d\n", U3.a.offsetof, U3.b.offsetof, U3.sizeof);
+ printf("%zd %zd %zd\n", U3.a.offsetof, U3.b.offsetof, U3.sizeof);
assert(U3.a.offsetof == 0);
assert(U3.b.offsetof == 0);
assert(U3.sizeof == 8);
- printf("%d %d %d\n", U4.a.offsetof, U4.b.offsetof, U4.sizeof);
+ printf("%zd %zd %zd\n", U4.a.offsetof, U4.b.offsetof, U4.sizeof);
assert(U4.a.offsetof == 0);
assert(U4.b.offsetof == 0);
assert(U4.sizeof == 4);
- printf("%d %d %d\n", U5.a.offsetof, U5.b.offsetof, U5.sizeof);
+ printf("%zd %zd %zd\n", U5.a.offsetof, U5.b.offsetof, U5.sizeof);
assert(U5.a.offsetof == 0);
assert(U5.b.offsetof == 0);
assert(U5.sizeof == 8);
- printf("%d %d %d\n", U6.a.offsetof, U6.b.offsetof, U6.sizeof);
+ printf("%zd %zd %zd\n", U6.a.offsetof, U6.b.offsetof, U6.sizeof);
assert(U6.a.offsetof == 0);
assert(U6.b.offsetof == 0);
assert(U6.sizeof == 8);
@@ -434,7 +433,7 @@ class Cout17
printf("%d",x);
return this;
}
- alias set opShl;
+ alias opBinary(string op : "<<") = set;
}
void test17()
@@ -671,9 +670,9 @@ void test31()
printf("%s\n", foo.ptr);
auto s = typeid(typeof(foo.ptr)).toString();
- printf("%.*s\n", s.length, s.ptr);
+ printf("%.*s\n", cast(int)s.length, s.ptr);
s = typeid(char*).toString();
- printf("%.*s\n", s.length, s.ptr);
+ printf("%.*s\n", cast(int)s.length, s.ptr);
assert(typeid(typeof(foo.ptr)) == typeid(immutable(char)*));
}
@@ -689,7 +688,7 @@ class Qwert32
void foo()
{
- printf("yuiop = %d, asdfg = %d\n", Qwert32.yuiop.offsetof, Qwert32.asdfg.offsetof);
+ printf("yuiop = %zd, asdfg = %zd\n", Qwert32.yuiop.offsetof, Qwert32.asdfg.offsetof);
version(D_LP64)
{
assert(Qwert32.yuiop.offsetof == 16);
@@ -778,7 +777,7 @@ void test36()
{
A36 a = new A36;
- printf("A36.sizeof = %d\n", a.classinfo.initializer.length);
+ printf("A36.sizeof = %zd\n", a.classinfo.initializer.length);
printf("%d\n", a.s);
printf("%d\n", a.a);
printf("%d\n", a.b);
@@ -819,7 +818,7 @@ class Foo38
{
static void display_name()
{
- printf("%.*s\n", Object.classinfo.name.length, Object.classinfo.name.ptr);
+ printf("%.*s\n", cast(int)Object.classinfo.name.length, Object.classinfo.name.ptr);
assert(Object.classinfo.name == "object.Object");
assert(super.classinfo.name == "object.Object");
assert(this.classinfo.name == "test12.Foo38");
@@ -951,31 +950,28 @@ struct Shell
const int opCmp(ref const Shell s)
{
- import std.algorithm;
- return std.algorithm.cmp(this.str, s.str);
+ // Obviously not Unicode-aware...
+ foreach (const i, const a; this.str)
+ {
+ const b = s.str[i];
+ if (a < b) return -1;
+ if (a > b) return 1;
+ }
+
+ if (this.str.length < s.str.length) return -1;
+ if (this.str.length > s.str.length) return 1;
+ return 0;
}
}
void test45()
{
- import std.algorithm;
-
- Shell[3] a;
-
- a[0].str = "hello";
- a[1].str = "betty";
- a[2].str = "fred";
-
- a[].sort;
-
- foreach (Shell s; a)
- {
- printf("%.*s\n", s.str.length, s.str.ptr);
- }
+ Shell a = Shell("hello");
+ Shell b = Shell("betty");
+ Shell c = Shell("fred");
- assert(a[0].str == "betty");
- assert(a[1].str == "fred");
- assert(a[2].str == "hello");
+ assert(a > b);
+ assert(b < c);
}
/**************************************/
@@ -1153,7 +1149,7 @@ void test55()
void writefln(string s)
{
- printf("%.*s\n", s.length, s.ptr);
+ printf("%.*s\n", cast(int)s.length, s.ptr);
}
void test58()
diff --git a/gcc/testsuite/gdc.test/runnable/test12486.d b/gcc/testsuite/gdc.test/runnable/test12486.d
new file mode 100644
index 0000000..a0a6e2c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test12486.d
@@ -0,0 +1,18 @@
+module test12486;
+
+struct S { enum a = 1; } // or `const` but not for all types
+
+S f(ref int i)
+{
+ ++i;
+ return S();
+}
+
+void main()
+{
+ int i = 2;
+ assert(f(i).a == 1);
+ // ensure that f(i) was actually called, even though
+ // a is a statically known property of the returned type
+ assert(i == 3);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test14874.d b/gcc/testsuite/gdc.test/runnable/test14874.d
index 470a93c..fa69211 100644
--- a/gcc/testsuite/gdc.test/runnable/test14874.d
+++ b/gcc/testsuite/gdc.test/runnable/test14874.d
@@ -1,38 +1,38 @@
-// REQUIRED_ARGS: -dip25
-
-template indexOfReturn(T...)
-{
- static if (T.length == 0)
- {
- enum indexOfReturn = -1;
- }
- else static if (T[$ - 1] == "return")
- {
- enum indexOfReturn = T.length - 1;
- }
- else
- {
- enum indexOfReturn = indexOfReturn!(T[0..$-1]);
- }
-}
-
-struct Test
-{
- int n;
-
- ref int getN() return
- {
- return n;
- }
-
- int getNNonReturn()
- {
- return n;
- }
-}
-
-void main()
-{
- assert(indexOfReturn!(__traits(getFunctionAttributes, Test.getN)) != -1);
- assert(indexOfReturn!(__traits(getFunctionAttributes, Test.getNNonReturn)) == -1);
-}
+// REQUIRED_ARGS:
+
+template indexOfReturn(T...)
+{
+ static if (T.length == 0)
+ {
+ enum indexOfReturn = -1;
+ }
+ else static if (T[$ - 1] == "return")
+ {
+ enum indexOfReturn = T.length - 1;
+ }
+ else
+ {
+ enum indexOfReturn = indexOfReturn!(T[0..$-1]);
+ }
+}
+
+struct Test
+{
+ int n;
+
+ ref int getN() return
+ {
+ return n;
+ }
+
+ int getNNonReturn()
+ {
+ return n;
+ }
+}
+
+void main()
+{
+ assert(indexOfReturn!(__traits(getFunctionAttributes, Test.getN)) != -1);
+ assert(indexOfReturn!(__traits(getFunctionAttributes, Test.getNNonReturn)) == -1);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test15.d b/gcc/testsuite/gdc.test/runnable/test15.d
index 405171e..222742c 100644
--- a/gcc/testsuite/gdc.test/runnable/test15.d
+++ b/gcc/testsuite/gdc.test/runnable/test15.d
@@ -1,13 +1,10 @@
-// RUNNABLE_PHOBOS_TEST
-// REQUIRED_ARGS:
-// EXTRA_FILES: extra-files/test15.txt
+/*
+REQUIRED_ARGS: -Jrunnable/extra-files
+EXTRA_FILES: extra-files/test15.txt
+*/
-import std.array;
-import core.stdc.math : cos, fabs, sin, sqrt;
+import core.math;
import core.vararg;
-import std.math: rndtol, rint;
-import std.string;
-import std.stdio : File;
extern (C)
{
@@ -46,9 +43,9 @@ void test6()
void test7()
{
string s = `hello"there'you`;
- printf("s = '%.*s'\n", s.length, s.ptr);
+ printf("s = '%.*s'\n", cast(int)s.length, s.ptr);
assert(s == "hello\"there'you");
- ubyte[] b = cast(ubyte[])x"8B 7D f4 0d";
+ ubyte[] b = cast(ubyte[])"\x8B\x7D\xf4\x0d";
for (int i = 0; i < b.length; i++)
printf("b[%d] = x%02x\n", i, b[i]);
assert(b.length == 4);
@@ -95,7 +92,7 @@ struct Pair
return this;
}
- Pair opDiv(Pair other)
+ Pair opBinary(string op)(Pair other) if (op == "/")
{
Pair result;
@@ -206,8 +203,8 @@ class A15
List2.rehash;
}
private:
- int delegate(in int arg1) List1[char[]];
- int List2[char []];
+ int delegate(in int arg1)[char[]] List1;
+ int[char []] List2;
}
void test15()
@@ -223,7 +220,7 @@ void test16()
uint c = 200000;
while (c--)
a ~= 'x';
- //printf("a = '%.*s'\n", a.length, a.ptr);
+ //printf("a = '%.*s'\n", cast(int)a.length, a.ptr);
}
@@ -266,7 +263,7 @@ void test19()
int foo20(string s,char d) { return 1; }
int foo20(string s,double d) { return 2; }
-int foo20(string s,cdouble d) { return 3; }
+int foo20(string s,long d) { return 3; }
void test20()
{
@@ -280,10 +277,47 @@ void test20()
void test21()
{
+ // Minimalistic byLine implementation
+ static struct Lines
+ {
+ private string text, line;
+ this(string text)
+ {
+ this.text = text;
+ popFront();
+ }
+
+ bool empty() const { return text == ""; }
+
+ string front() const
+ {
+ assert(!empty);
+ return line;
+ }
+
+ void popFront()
+ {
+ assert(!empty);
+ foreach (const idx; 0 .. text.length)
+ {
+ if (text[idx] == '\n')
+ {
+ line = text[0..idx];
+ text = text[idx + 1..$];
+ return;
+ }
+ }
+
+ line = text;
+ text = null;
+ }
+ }
+
+ static immutable string file = import(`test15.txt`);
+
int[string] esdom;
- auto f = File("runnable/extra-files/test15.txt", "r");
- foreach(it; f.byLine())
+ foreach(it; Lines(file))
esdom[it.idup] = 0;
esdom.rehash;
@@ -362,16 +396,16 @@ void test25()
void test26()
{
- string[] instructions = std.array.split("a;b;c", ";");
+ string[] instructions =[ "a", "b", "c" ];
foreach(ref string instr; instructions)
{
- std.string.strip(instr);
+ instr = instr[];
}
foreach(string instr; instructions)
{
- printf("%.*s\n", instr.length, instr.ptr);
+ printf("%.*s\n", cast(int)instr.length, instr.ptr);
}
}
@@ -402,7 +436,7 @@ void test27()
void foo28(ClassInfo ci)
{
- printf("%.*s\n", ci.name.length, ci.name.ptr);
+ printf("%.*s\n", cast(int)ci.name.length, ci.name.ptr);
static int i;
switch (i++)
@@ -786,7 +820,7 @@ class C44
void test44()
{
C44 c= new C44();
- printf("%.*s\n", c.arrArr[0].length, c.arrArr[0].ptr);
+ printf("%.*s\n", cast(int)c.arrArr[0].length, c.arrArr[0].ptr);
assert(c.arrArr[0] == "foo");
}
@@ -815,11 +849,11 @@ union A46
void test46()
{
A46 a;
- printf("%d\n", cast(byte*)&a.c - cast(byte*)&a);
- printf("%d\n", cast(byte*)&a.s - cast(byte*)&a);
- printf("%d\n", cast(byte*)&a.l - cast(byte*)&a);
- printf("%d\n", cast(byte*)&a.a - cast(byte*)&a);
- printf("%d\n", cast(byte*)&a.f - cast(byte*)&a);
+ printf("%td\n", cast(byte*)&a.c - cast(byte*)&a);
+ printf("%td\n", cast(byte*)&a.s - cast(byte*)&a);
+ printf("%td\n", cast(byte*)&a.l - cast(byte*)&a);
+ printf("%td\n", cast(byte*)&a.a - cast(byte*)&a);
+ printf("%td\n", cast(byte*)&a.f - cast(byte*)&a);
assert(cast(byte*)&a.c == cast(byte*)&a);
assert(cast(byte*)&a.s == cast(byte*)&a);
@@ -1044,9 +1078,9 @@ void test56()
/************************************/
-void det(float mat[][])
+void det(float[][] mat)
{
- float newmat[][];
+ float[][] newmat;
size_t i = newmat[0 .. (mat.length - 1)].length;
}
@@ -1099,7 +1133,6 @@ void test59()
class Foo60
{
int x;
-static:
this() { x = 3; }
~this() { }
}
@@ -1117,16 +1150,13 @@ void test60()
class StdString
{
- alias std.string.format toString;
+ alias nearest = core.math.rint;
}
void test61()
{
- int i = 123;
StdString g = new StdString();
- string s = g.toString("%s", i);
- printf("%.*s\n", s.length, s.ptr);
- assert(s == "123");
+ assert(g.nearest(123.1) == 123);
}
@@ -1366,6 +1396,38 @@ void test72()
assert(foos.length == 1);
}
+/************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19758
+
+void test19758()
+{
+ byte[1] a = [1];
+ int b = 0;
+
+ // If delete this 4 lines, the result is correct.
+ if (a[b] == 0)
+ {
+ a[b] = 0;
+ if (1 << b) { }
+ }
+
+ if ((a[b] & 0xFF) == 0)
+ {
+ assert((a[b] & 0xFF) == 0);
+ }
+}
+
+/************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19968
+
+@safe void test19968()
+{
+ int[2] array = [16, 678];
+ union U { int i; bool b; }
+ U u;
+ u.i = 0xDEADBEEF;
+ assert(array[u.b] == 678);
+}
/************************************/
@@ -1436,6 +1498,8 @@ int main()
test70();
test71();
test72();
+ test19758();
+ test19968();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/test15079.d b/gcc/testsuite/gdc.test/runnable/test15079.d
index 5316d73..e0fea97 100644
--- a/gcc/testsuite/gdc.test/runnable/test15079.d
+++ b/gcc/testsuite/gdc.test/runnable/test15079.d
@@ -1,3 +1,4 @@
+// EXTRA_FILES: imports/a15079.d
module test15079;
import imports.a15079;
diff --git a/gcc/testsuite/gdc.test/runnable/test15373.d b/gcc/testsuite/gdc.test/runnable/test15373.d
new file mode 100644
index 0000000..13144b7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test15373.d
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=15373
+
+// Using `typeid` on an `extern(C++) class` type is fine as it is evaluated at compile-time
+
+// Using `typeid` on an `extern(C++) class` instance is not ok because `extern(C++) class`
+// instances are not rooted in `Object`. See test/fail_compilation/test15373.d
+
+extern(C++) class C
+{ }
+
+void main()
+{
+ auto Cti = typeid(C);
+ assert(Cti.name == "test15373.C");
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test15568.d b/gcc/testsuite/gdc.test/runnable/test15568.d
new file mode 100644
index 0000000..d21ede2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test15568.d
@@ -0,0 +1,58 @@
+// REQUIRED_ARGS: -unittest -main -O
+// https://issues.dlang.org/show_bug.cgi?id=15568
+
+auto filter(alias pred)(D[])
+{
+ struct FilterResult
+ {
+ void popFront()
+ {
+ pred(null);
+ }
+
+ D[] array()
+ {
+ return null;
+ }
+ }
+ return FilterResult();
+}
+
+class A
+{
+ B foo(C c, D[] ds, bool f)
+ in
+ {
+ assert(c !is null);
+ }
+ do
+ {
+ D[] ds2 = ds.filter!(a => c).array;
+
+ return new B(ds2, f);
+ }
+}
+
+class B
+{
+ this(D[], bool)
+ {
+ }
+}
+
+class C
+{
+}
+
+struct D
+{
+}
+
+unittest
+{
+ auto a = new A;
+ C c = new C;
+
+ a.foo(c, null, false);
+}
+
diff --git a/gcc/testsuite/gdc.test/runnable/test15624.d b/gcc/testsuite/gdc.test/runnable/test15624.d
new file mode 100644
index 0000000..7927579
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test15624.d
@@ -0,0 +1,51 @@
+/* PERMUTE_ARGS:
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=15624
+
+struct Foo {
+ int x;
+ int opApply(int delegate(int, string, string) @safe dg) @safe {
+ x = 1;
+ return 0;
+ }
+ int opApply(int delegate(int, string, string) @system dg) @system {
+ x = 2;
+ return 0;
+ }
+}
+
+void testSafe() @safe {
+ Foo foo;
+ foreach (i, k, v; foo) {
+ }
+ assert(foo.x == 1);
+}
+
+void testSystem() @system {
+ Foo foo;
+ foreach (i, k, v; foo) {
+ }
+ assert(foo.x == 2);
+}
+
+void test() @system
+{
+ Foo f;
+
+ int dgsafe (int x, string s, string t) @safe { return 1; }
+ int dgsystem(int x, string s, string t) @system { return 1; }
+
+ f.opApply(&dgsafe);
+ assert(f.x == 1);
+ f.opApply(&dgsystem);
+ assert(f.x == 2);
+}
+
+int main()
+{
+ testSafe();
+ testSystem();
+ test();
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test16047.d b/gcc/testsuite/gdc.test/runnable/test16047.d
new file mode 100644
index 0000000..eff2db3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test16047.d
@@ -0,0 +1,17 @@
+// https://issues.dlang.org/show_bug.cgi?id=16047
+module test16047;
+
+void main()
+{
+ Reassignable[int][int] aa;
+
+ aa[0][0] = Reassignable.init;
+ aa[s()][0] = Reassignable.init; // range violation
+}
+
+struct Reassignable
+{
+ void opAssign(Reassignable) {}
+}
+
+int s() { return 1; }
diff --git a/gcc/testsuite/gdc.test/runnable/test16115.d b/gcc/testsuite/gdc.test/runnable/test16115.d
index c8ad464..8cd9c6a 100644
--- a/gcc/testsuite/gdc.test/runnable/test16115.d
+++ b/gcc/testsuite/gdc.test/runnable/test16115.d
@@ -25,7 +25,7 @@ auto call()
else // assert error
{
//return n = tagx, null;
- return n = Test.tag, null;
+ return n = Test.tag;
//return n = Test.tag;
}
}
diff --git a/gcc/testsuite/gdc.test/runnable/test16140.d b/gcc/testsuite/gdc.test/runnable/test16140.d
new file mode 100644
index 0000000..3004945
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test16140.d
@@ -0,0 +1,32 @@
+// https://issues.dlang.org/show_bug.cgi?id=16140
+
+int fun()
+{
+ static int count = 0;
+ if (count == 3)
+ {
+ count = 0;
+ return 0;
+ }
+ ++count;
+ return count;
+}
+
+void main()
+{
+ uint[] res;
+ while(auto value = fun())
+ res ~= value;
+ assert(res == [1, 2, 3]);
+
+ res.length = 0;
+ while(uint value = fun())
+ res ~= value;
+ assert(res == [1, 2, 3]);
+
+ res.length = 0;
+ while(const value = fun())
+ res ~= value;
+ assert(res == [1, 2, 3]);
+}
+
diff --git a/gcc/testsuite/gdc.test/runnable/test16555.d b/gcc/testsuite/gdc.test/runnable/test16555.d
new file mode 100644
index 0000000..78db1f7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test16555.d
@@ -0,0 +1,20 @@
+// https://issues.dlang.org/show_bug.cgi?id=16555
+
+void outer(
+ double x,
+ double a, double b, double c, double d,
+ double e, double f, double g, double h)
+{
+ assert(x == 999.0 && a == 1 && b == 2 && c == 3 && d == 4
+ && e == 5 && f == 6 && g == 7 && h == 8);
+}
+
+void main()
+{
+ void inner(double x)
+ {
+ outer(x, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0);
+ }
+
+ inner(999.0);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test17.d b/gcc/testsuite/gdc.test/runnable/test17.d
index 58873a0..4b17ede 100644
--- a/gcc/testsuite/gdc.test/runnable/test17.d
+++ b/gcc/testsuite/gdc.test/runnable/test17.d
@@ -5,15 +5,15 @@ extern(C) int printf(const char*, ...);
void ulog(string s)
{
- printf("%.*s\n",s.length, s.ptr);
+ printf("%.*s\n",cast(int)s.length, s.ptr);
fflush(stdout);
}
int open()
{
char *s;
- char abs[2000];
- char qu[100];
+ char[2000] abs;
+ char[100] qu;
int a;
ulog("reaches this only 9 times of 10!\n");
return 0;
@@ -22,7 +22,7 @@ int open()
int yhenda()
{
- char MEM[2200];
+ char[2200] MEM;
int a;
ulog("point(2.1) \n");
open();
diff --git a/gcc/testsuite/gdc.test/runnable/test17072.d b/gcc/testsuite/gdc.test/runnable/test17072.d
index 0ad0410..2c5977f 100644
--- a/gcc/testsuite/gdc.test/runnable/test17072.d
+++ b/gcc/testsuite/gdc.test/runnable/test17072.d
@@ -1,6 +1,6 @@
/*
REQUIRED_ARGS: -inline
-PERMUTE_ARGS: -release -O -dip25
+PERMUTE_ARGS: -release -O
*/
// https://issues.dlang.org/show_bug.cgi?id=17072
diff --git a/gcc/testsuite/gdc.test/runnable/test17073.d b/gcc/testsuite/gdc.test/runnable/test17073.d
deleted file mode 100644
index 82df219..0000000
--- a/gcc/testsuite/gdc.test/runnable/test17073.d
+++ /dev/null
@@ -1,13 +0,0 @@
-struct S0
-{
- int x = void;
-}
-struct S1
-{
- S0 x = S0(42);
-}
-void main()
-{
- S1 x;
- assert(x.x.x == 42);
-}
diff --git a/gcc/testsuite/gdc.test/runnable/test17181.d b/gcc/testsuite/gdc.test/runnable/test17181.d
new file mode 100644
index 0000000..59ee895
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test17181.d
@@ -0,0 +1,12 @@
+// EXTRA_SOURCES: imports/test17181a.d imports/test17181b.d
+
+module test17181;
+import imports.test17181a;
+
+int foo()
+{
+ return imports.test17181a.abc(1);
+}
+
+static this() { assert(a == 2); }
+void main() {}
diff --git a/gcc/testsuite/gdc.test/runnable/test17181b.d b/gcc/testsuite/gdc.test/runnable/test17181b.d
new file mode 100644
index 0000000..5e4a4be
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test17181b.d
@@ -0,0 +1,16 @@
+// EXTRA_SOURCES: imports/test17181a.d
+// EXTRA_FILES: imports/test17181c.d
+module test17181b;
+
+import imports.test17181c; // only imported, not compiled
+ // => must not be in ModuleInfo.importedModules
+
+static this()
+{
+ // By instantiating the getA template, its local imports.test17181a
+ // import is added to this module (not to imports.test17181c), and its
+ // module ctor must have run already.
+ assert(imports.test17181c.getA!() == 1);
+}
+
+void main() {}
diff --git a/gcc/testsuite/gdc.test/runnable/test17246.d b/gcc/testsuite/gdc.test/runnable/test17246.d
new file mode 100644
index 0000000..2d51720
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test17246.d
@@ -0,0 +1,50 @@
+/* REQUIRED_ARGS:
+ * OPTIONAL_ARGS:
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=17246
+
+struct Foo
+{
+ int* rc;
+ this(int val)
+ {
+ rc = new int;
+ (*rc) = 1;
+ }
+ this(this)
+ {
+ (*rc)++;
+ }
+ ~this()
+ {
+ if (rc)
+ {
+ assert(*rc > 0);
+ (*rc)--;
+ }
+ }
+}
+
+struct Bar
+{
+ Foo foo;
+ this(Foo foo, bool)
+ {
+ this.foo = foo;
+ }
+}
+
+bool fun(bool val) { return !val; }
+
+auto genBar(bool flag)
+{
+ return flag ? Bar() : Bar(Foo(10), fun(!flag));
+}
+
+int main(string[] args)
+{
+ auto bar = genBar(args.length == 0);
+ return 0;
+}
+
diff --git a/gcc/testsuite/gdc.test/runnable/test17258.d b/gcc/testsuite/gdc.test/runnable/test17258.d
new file mode 100644
index 0000000..1e86c95
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test17258.d
@@ -0,0 +1,33 @@
+class ByNameC(alias Var)
+{
+ alias var = Var;
+}
+
+struct ByNameS(alias Var)
+{
+ alias var = Var;
+ ubyte value = 1;
+}
+
+void main()
+{
+ ulong x;
+ ByNameS!x v;
+ ubyte w = 2;
+
+ v.var = 0xAA_BB; /* stomps over v.value and w */
+
+ assert(w == 2);
+ assert(v.value == 1);
+ //printf("%x\n", w); /* prints "aa", should be 2 */
+ //printf("%x\n", v.value); /* prints "bb", should be 1 */
+
+ auto c = new ByNameC!x;
+ c.var = 0xAA_BB; /* stomps over c.__vptr */
+
+ assert(*cast(ulong*)c != 0xAA_BB);
+ //printf("%x\n", *cast(ulong*)c); /* prints "aabb", should be pointer value */
+
+ assert(x == 0xAA_BB);
+ //printf("%lx\n", x); /* prints 0, should be "aabb" */
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test17337.d b/gcc/testsuite/gdc.test/runnable/test17337.d
new file mode 100644
index 0000000..f817eb7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test17337.d
@@ -0,0 +1,23 @@
+// REQUIRED_ARGS: -mcpu=native
+
+static if (__traits(compiles, __vector(ubyte[16])))
+{
+ alias ubyte16 = __vector(ubyte[16]);
+
+ ubyte16 bug(ubyte val)
+ {
+ immutable ubyte16 a = 0, b = val;
+ return b;
+ }
+
+ void main()
+ {
+ bug(0);
+ }
+}
+else
+{
+ void main()
+ {
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test17338.d b/gcc/testsuite/gdc.test/runnable/test17338.d
index 5c5012f..1c937be 100644
--- a/gcc/testsuite/gdc.test/runnable/test17338.d
+++ b/gcc/testsuite/gdc.test/runnable/test17338.d
@@ -1,25 +1,23 @@
// PERMUTE_ARGS:
+
+// COMDAT folding increases runtime by > 80x
+// REQUIRED_ARGS(windows): -L/OPT:NOICF
+
+// Apparently omf or optlink does not support more than 32767 symbols.
+// DISABLED: win32
+
// Generate \sum_{i=0}^{14} 2^i = 32767 template instantiations
// (each with 3 sections) to use more than 64Ki sections in total.
-version (Win32)
+
+size_t foo(size_t i, size_t mask)()
{
- // Apparently omf or optlink does not support more than 32767 symbols.
- void main()
- {
- }
+ static if (i == 14)
+ return mask;
+ else
+ return foo!(i + 1, mask) + foo!(i + 1, mask | (1UL << i));
}
-else
-{
- size_t foo(size_t i, size_t mask)()
- {
- static if (i == 14)
- return mask;
- else
- return foo!(i + 1, mask) + foo!(i + 1, mask | (1UL << i));
- }
- void main()
- {
- assert(foo!(0, 0) != 0);
- }
+void main()
+{
+ assert(foo!(0, 0) != 0);
}
diff --git a/gcc/testsuite/gdc.test/runnable/test17559.d b/gcc/testsuite/gdc.test/runnable/test17559.d
new file mode 100644
index 0000000..a759f15
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test17559.d
@@ -0,0 +1,84 @@
+// REQUIRED_ARGS: -g
+// REQUIRED_ARGS(linux freebsd dragonflybsd): -L-export-dynamic
+// PERMUTE_ARGS:
+// DISABLED: osx
+
+import core.stdc.stdio;
+
+void main()
+{
+ fun(1);
+ fun(2);
+ fun(3);
+#line 30
+ fun(4);
+
+ foo(1, 10);
+ foo(2, 10);
+ foo(3, 10);
+#line 40
+ foo(4, 10);
+}
+
+void fun(int n, int defParam = 10)
+{
+ try
+ {
+ if (n == 4)
+ throw new Exception("fun");
+ }
+ catch(Exception e)
+ {
+ string s = e.toString();
+ printf("%.*s\n", cast(int)s.length, s.ptr);
+ int line = lineInMain(e.toString());
+ assert(line >= 30 && line <= 32); // return address might be next statement
+ }
+}
+
+void foo(int n, int m)
+{
+ try
+ {
+ if (n == 4)
+ throw new Exception("foo");
+ }
+ catch(Exception e)
+ {
+ string s = e.toString();
+ printf("%.*s\n", cast(int)s.length, s.ptr);
+ int line = lineInMain(e.toString());
+ assert(line >= 40 && line <= 41); // return address might be next statement
+ }
+}
+
+int lineInMain(string msg)
+{
+ // find line number of _Dmain in stack trace
+ // on linux: file.d:line _Dmain [addr]
+ // on windows: addr in _Dmain at file.d(line)
+ int line = 0;
+ bool mainFound = false;
+ for (size_t pos = 0; pos + 6 < msg.length; pos++)
+ {
+ if (msg[pos] == '\n')
+ {
+ line = 0;
+ mainFound = false;
+ }
+ else if ((msg[pos] == ':' || msg[pos] == '(') && line == 0)
+ {
+ for (pos++; pos < msg.length && msg[pos] >= '0' && msg[pos] <= '9'; pos++)
+ line = line * 10 + msg[pos] - '0';
+ if (line > 0 && mainFound)
+ return line;
+ }
+ else if (msg[pos .. pos + 6] == "_Dmain" || msg[pos .. pos + 6] == "D main")
+ {
+ mainFound = true;
+ if (line > 0 && mainFound)
+ return line;
+ }
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test17684.d b/gcc/testsuite/gdc.test/runnable/test17684.d
index 4734d96..d42baac 100644
--- a/gcc/testsuite/gdc.test/runnable/test17684.d
+++ b/gcc/testsuite/gdc.test/runnable/test17684.d
@@ -74,6 +74,20 @@ bool boolTest(T)()
assert(t == boolValue);
assert(boolValue == t);
+ t = true; // tests inferType
+ auto inferredValue = t;
+ assert(inferredValue == true);
+
+ t = true; // tests function argument
+ bool functionCall(bool test)
+ {
+ return test;
+ }
+ assert(t == functionCall(t));
+
+ t = true; // tests CastExp
+ assert(t == cast(bool)t);
+
t = true;
return t; // tests ReturnStatement
}
@@ -97,6 +111,9 @@ int intTest(T)()
assert(t <= 42);
assert(42 >= t);
+ t = 42; // tests CastExp
+ assert(42 == cast(int)t);
+
// These currently don't work for properties due to https://issues.dlang.org/show_bug.cgi?id=8006
static if (!(typeid(T) is typeid(StructProperty!int)) && !(typeid(T) is typeid(ClassProperty!int)))
{
diff --git a/gcc/testsuite/gdc.test/runnable/test17868.d b/gcc/testsuite/gdc.test/runnable/test17868.d
new file mode 100644
index 0000000..4609440
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test17868.d
@@ -0,0 +1,45 @@
+/*
+REQUIRED_ARGS: -betterC
+RUN_OUTPUT:
+---
+init
+init
+main
+fini
+fini
+---
+*/
+
+import core.stdc.stdio;
+
+extern(C):
+
+pragma(crt_constructor)
+void init()
+{
+ puts("init");
+}
+
+pragma(crt_destructor)
+void fini2()
+{
+ puts("fini");
+}
+
+pragma(crt_constructor)
+void foo()
+{
+ puts("init");
+}
+
+pragma(crt_destructor)
+void bar()
+{
+ puts("fini");
+}
+
+int main()
+{
+ puts("main");
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test17868b.d b/gcc/testsuite/gdc.test/runnable/test17868b.d
new file mode 100644
index 0000000..d28cae2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test17868b.d
@@ -0,0 +1,52 @@
+/*
+REQUIRED_ARGS: -betterC
+RUN_OUTPUT:
+---
+init
+init
+main
+fini
+fini
+---
+*/
+
+import core.stdc.stdio;
+
+extern(C):
+
+pragma(crt_constructor)
+pragma(crt_destructor)
+void ctor_dtor_1()
+{
+ __gshared bool initialized;
+ puts(initialized ? "fini" : "init");
+ initialized = true;
+}
+
+pragma(crt_constructor)
+__gshared int var; // ignored for anything but functions
+
+pragma(crt_constructor)
+{
+ version (all) void init()
+ {
+ puts("init");
+ }
+}
+
+template fini()
+{
+ pragma(crt_destructor)
+ void fini()
+ {
+ puts("fini");
+ }
+}
+
+alias instantiate = fini!();
+
+int main()
+{
+ puts("main");
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test17885.d b/gcc/testsuite/gdc.test/runnable/test17885.d
new file mode 100644
index 0000000..a6e521b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test17885.d
@@ -0,0 +1,11 @@
+module test17885;
+
+struct T { ulong a, b; }
+T f() { return T(); }
+
+void main()
+{
+ int[T] set = [f(): 0];
+ set.remove(f());
+ assert(f() !in set);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test17940.d b/gcc/testsuite/gdc.test/runnable/test17940.d
new file mode 100644
index 0000000..1ea43db
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test17940.d
@@ -0,0 +1,46 @@
+// PERMUTE_ARGS: -O
+
+// https://issues.dlang.org/show_bug.cgi?id=17940
+
+struct Array
+{
+ long length;
+ long ptr;
+}
+
+struct Struct
+{
+ bool b = true;
+}
+
+void fun1(int)
+{
+}
+
+void fun2(Array arr, int, int)
+{
+ assert(!arr.length);
+}
+
+void fn(Struct* str)
+{
+ Array arr;
+ if (!str)
+ {
+ return;
+ }
+ if (str)
+ {
+ fun1(str.b);
+ }
+ if (str.b)
+ {
+ fun2(arr, str.b, 0);
+ }
+}
+
+void main()
+{
+ Struct s;
+ fn(&s);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test17943.d b/gcc/testsuite/gdc.test/runnable/test17943.d
new file mode 100644
index 0000000..7ec2665
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test17943.d
@@ -0,0 +1,9 @@
+// REQUIRED_ARGS: -O
+
+void main()
+{
+ int[32] data;
+ auto p1 = data.ptr + 0;
+ auto p2 = data.ptr + 3;
+ assert(p2 - p1 == 3);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test17965.d b/gcc/testsuite/gdc.test/runnable/test17965.d
new file mode 100644
index 0000000..2937d6d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test17965.d
@@ -0,0 +1,29 @@
+/***************************************/
+// https://issues.dlang.org/show_bug.cgi?id=17965
+
+import core.stdc.math;
+
+struct Point{double x,y;}
+
+Point foo10()
+{
+ Point result = Point(1.0, 2.0);
+ return result;
+}
+
+Point foo20()
+{
+ Point result;
+ return result;
+}
+
+void main()
+{
+ auto p = foo10();
+ assert(p.x == 1.0);
+ assert(p.y == 2.0);
+
+ auto q = foo20();
+ assert(isnan(q.x));
+ assert(isnan(q.y));
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test18296.d b/gcc/testsuite/gdc.test/runnable/test18296.d
new file mode 100644
index 0000000..0f7ac7e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test18296.d
@@ -0,0 +1,24 @@
+// REQUIRED_ARGS: -cov
+// PERMUTE_ARGS: -fPIC
+alias AliasSeq(Args...) = Args;
+
+struct Duration
+{
+ this(long hnsecs)
+ {
+ _hnsecs = hnsecs;
+ }
+
+
+ long _hnsecs;
+}
+
+void main()
+{
+ foreach(U; AliasSeq!(Duration, const Duration))
+ {
+ const Duration t = 42;
+ U u = t;
+ assert(t._hnsecs == u._hnsecs);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test18534.d b/gcc/testsuite/gdc.test/runnable/test18534.d
new file mode 100644
index 0000000..8d4653d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test18534.d
@@ -0,0 +1,18 @@
+/* REQUIRED_ARGS: -O
+ * PERMUTE_ARGS:
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=18534
+
+auto blah(char ch) { return ch; }
+
+auto foo(int i)
+{
+ return blah(i ? 'A' : 'A');
+}
+
+void main()
+{
+ auto c = foo(0);
+ assert(c == 'A');
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test18545.d b/gcc/testsuite/gdc.test/runnable/test18545.d
new file mode 100644
index 0000000..fc3d24a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test18545.d
@@ -0,0 +1,63 @@
+module test18545;
+
+enum Constness
+{
+ Mutable,
+ Const,
+ Immutable,
+}
+
+enum Cases = [Constness.Mutable, Constness.Const, Constness.Immutable];
+
+void main()
+{
+ static foreach (from; Cases)
+ {
+ static foreach (to; Cases)
+ {
+ test!(from, to)();
+ }
+ }
+}
+
+void test(Constness from, Constness to)()
+{
+ struct S {
+ int i;
+
+ @property int get() const { return 0; }
+
+ alias get this;
+ }
+
+ static if (from == Constness.Mutable)
+ {
+ alias ConstS = S;
+ }
+ else static if (from == Constness.Const)
+ {
+ alias ConstS = const(S);
+ }
+ else
+ {
+ alias ConstS = immutable(S);
+ }
+
+ ConstS s1 = S(42);
+
+ // this should reinterpret-cast, NOT call the implicit constructor with .get!
+ static if (to == Constness.Mutable)
+ {
+ auto s2 = cast() s1;
+ }
+ else static if (to == Constness.Const)
+ {
+ const s2 = cast(const) s1;
+ }
+ else static if (to == Constness.Immutable)
+ {
+ immutable s2 = cast(immutable) s1;
+ }
+
+ assert(s2.i == s1.i, "Bug 18545 occurred casting from "~from.stringof~" to "~to.stringof);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test18746.d b/gcc/testsuite/gdc.test/runnable/test18746.d
new file mode 100644
index 0000000..a2cf38b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test18746.d
@@ -0,0 +1,16 @@
+// https://issues.dlang.org/show_bug.cgi?id=18746
+
+struct S {}
+
+S f(ref int i)
+{
+ ++i;
+ return S();
+}
+
+void main()
+{
+ int i = 2;
+ assert(f(i) == S());
+ assert(i == 3); /* failed before patch, i = 2; should pass */
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test18868.d b/gcc/testsuite/gdc.test/runnable/test18868.d
new file mode 100644
index 0000000..b0085c0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test18868.d
@@ -0,0 +1,9 @@
+/*
+COMPILE_SEPARATELY
+EXTRA_SOURCES: imports/test18868_a.d imports/test18868_fls.d
+PERMUTE_ARGS:
+*/
+
+import imports.test18868_fls;
+alias floop = FLS!(int);
+void main() {}
diff --git a/gcc/testsuite/gdc.test/runnable/test18868_2.d b/gcc/testsuite/gdc.test/runnable/test18868_2.d
new file mode 100644
index 0000000..a90ec1f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test18868_2.d
@@ -0,0 +1,13 @@
+mixin(genCtor("666")); mixin(genCtor("777"));
+
+int i;
+
+string genCtor(string a)
+{
+ return "static this() { i += " ~ a ~ "; }";
+}
+
+void main()
+{
+ assert(i == 0 + 666 + 777);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test18868_3.d b/gcc/testsuite/gdc.test/runnable/test18868_3.d
new file mode 100644
index 0000000..ed6f172
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test18868_3.d
@@ -0,0 +1,16 @@
+static foreach(s; ["666", "777", "888"])
+{
+ mixin(genCtor(s));
+}
+
+int i;
+
+string genCtor(string a)
+{
+ return "static this() { i += " ~ a ~ "; }";
+}
+
+void main()
+{
+ assert(i == 0 + 666 + 777 + 888);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test18880.d b/gcc/testsuite/gdc.test/runnable/test18880.d
new file mode 100644
index 0000000..c275ef2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test18880.d
@@ -0,0 +1,20 @@
+/* REQUIRED_ARGS: -unittest
+ PERMUTE_ARGS:
+ */
+
+static foreach(s; ["666", "777", "888"])
+{
+ mixin(genTest(s));
+}
+
+int i;
+
+string genTest(string a)
+{
+ return "unittest { i += " ~ a ~ "; }";
+}
+
+void main()
+{
+ assert(i == 0 + 666 + 777 + 888);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test18916.d b/gcc/testsuite/gdc.test/runnable/test18916.d
new file mode 100644
index 0000000..0e844ad
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test18916.d
@@ -0,0 +1,22 @@
+struct Line
+{
+ int line;
+ alias line this;
+
+ this(int line)
+ {
+ this.line = line;
+ }
+}
+
+void foo(Line line1 = __LINE__, int line2 = __LINE__, int line3 = int(__LINE__))
+{
+ assert(line1 == 12);
+ assert(line2 == 21);
+ assert(line3 == 12);
+}
+
+void main()
+{
+ foo();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19.d b/gcc/testsuite/gdc.test/runnable/test19.d
index b9360ee..372d32f 100644
--- a/gcc/testsuite/gdc.test/runnable/test19.d
+++ b/gcc/testsuite/gdc.test/runnable/test19.d
@@ -128,8 +128,8 @@ int[] test6_1(int[] a)
void test6()
{
printf("test6()\n");
- int b[3];
- int a[];
+ int[3] b;
+ int[] a;
b[0] = 0;
b[1] = 1;
@@ -144,7 +144,7 @@ void test6()
class OutBuffer7
{
- char data[];
+ char[] data;
uint offset;
void write(const(char) *p, uint nbytes)
@@ -161,7 +161,7 @@ void test7()
OutBuffer7 ob = new OutBuffer7;
ob.data = new char[10];
- printf("ob.data.length = %d\n", ob.data.length);
+ printf("ob.data.length = %zd\n", ob.data.length);
assert(ob.data.length == 10);
for (i = 0; i < 10; i++)
assert(ob.data[i] == char.init);
@@ -169,14 +169,14 @@ void test7()
printf("test7.1()\n");
ob.data[] = '-';
printf("test7.2()\n");
- printf("ob.data[] = '%.*s'\n", ob.data.length, ob.data.ptr);
+ printf("ob.data[] = '%.*s'\n", cast(int)ob.data.length, ob.data.ptr);
for (i = 0; i < 10; i++)
assert(ob.data[i] == '-');
ob.offset = 3;
ob.write("foo", 3);
- printf("ob.data.length = %d\n", ob.data.length);
- printf("ob.data[] = '%.*s'\n", ob.data.length, ob.data.ptr);
+ printf("ob.data.length = %zd\n", ob.data.length);
+ printf("ob.data[] = '%.*s'\n", cast(int)ob.data.length, ob.data.ptr);
for (i = 0; i < 10; i++)
{
if (i < 3 || i >= 6)
@@ -404,7 +404,7 @@ void test20()
}
/* ================================ */
-// 7848
+// https://issues.dlang.org/show_bug.cgi?id=7848
@safe pure nothrow void func7848() {}
@@ -414,7 +414,7 @@ void test20()
}
/* ================================ */
-// 8128
+// https://issues.dlang.org/show_bug.cgi?id=8128
int flag8128 = 0;
diff --git a/gcc/testsuite/gdc.test/runnable/test19086.d b/gcc/testsuite/gdc.test/runnable/test19086.d
new file mode 100644
index 0000000..026aee4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19086.d
@@ -0,0 +1,64 @@
+// REQUIRED_ARGS: -g
+// REQUIRED_ARGS(linux freebsd dragonflybsd): -L-export-dynamic
+// PERMUTE_ARGS:
+// DISABLED: osx
+
+void run19086()
+{
+ long x = 1;
+ int y = 0;
+#line 20
+ throw newException();
+}
+
+// moved here to keep run19086 short
+Exception newException() { return new Exception("hi"); }
+
+void test19086()
+{
+ try
+ {
+ run19086();
+ }
+ catch(Exception e)
+ {
+ int line = findLineStackTrace(e.toString(), "run19086");
+ assert(line >= 20 && line <= 21);
+ }
+}
+
+int findLineStackTrace(string msg, string func)
+{
+ // find line number of _Dmain in stack trace
+ // on linux: file.d:line _Dmain [addr]
+ // on windows: addr in _Dmain at file.d(line)
+ int line = 0;
+ bool found = false;
+ for (size_t pos = 0; pos + func.length < msg.length; pos++)
+ {
+ if (msg[pos] == '\n')
+ {
+ line = 0;
+ found = false;
+ }
+ else if ((msg[pos] == ':' || msg[pos] == '(') && line == 0)
+ {
+ for (pos++; pos < msg.length && msg[pos] >= '0' && msg[pos] <= '9'; pos++)
+ line = line * 10 + msg[pos] - '0';
+ if (line > 0 && found)
+ return line;
+ }
+ else if (msg[pos .. pos + func.length] == func)
+ {
+ found = true;
+ if (line > 0 && found)
+ return line;
+ }
+ }
+ return 0;
+}
+
+void main()
+{
+ test19086();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19122.d b/gcc/testsuite/gdc.test/runnable/test19122.d
new file mode 100644
index 0000000..369f5dd
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19122.d
@@ -0,0 +1,46 @@
+// https://issues.dlang.org/show_bug.cgi?id=19122
+struct HasDestructor
+{
+ ~this()
+ {
+ assert(0);
+ }
+ this(this)
+ {
+ assert(0);
+ }
+}
+
+struct S
+{
+ union
+ {
+ int i;
+ HasDestructor h;
+ }
+}
+
+struct S2
+{
+ union
+ {
+ align(1)
+ {
+ int i;
+ HasDestructor h;
+ }
+ }
+}
+
+void main()
+{
+ {
+ S s;
+ s = s;
+ }
+
+ {
+ S2 s2;
+ s2 = s2;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19185.d b/gcc/testsuite/gdc.test/runnable/test19185.d
new file mode 100644
index 0000000..d5a1e5e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19185.d
@@ -0,0 +1,22 @@
+// https://issues.dlang.org/show_bug.cgi?id=19185
+
+int fun()
+{
+ int x = 2;
+ struct A
+ {
+ int a;
+ this(int a)
+ {
+ this.a = a + x; // segault here
+ }
+ }
+
+ A a = 5;
+ return a.a;
+}
+
+void main()
+{
+ assert(fun() == 7);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19192.d b/gcc/testsuite/gdc.test/runnable/test19192.d
new file mode 100644
index 0000000..24f2450
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19192.d
@@ -0,0 +1,18 @@
+// https://issues.dlang.org/show_bug.cgi?id=19192
+interface Foo
+{
+ Foo covariant();
+}
+
+abstract class Frop : Foo {}
+
+class Bar : Frop
+{
+ Bar covariant() { return this; }
+}
+
+void main()
+{
+ Foo foo = new Bar;
+ assert(foo is foo.covariant());
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19223.d b/gcc/testsuite/gdc.test/runnable/test19223.d
new file mode 100644
index 0000000..6faa59b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19223.d
@@ -0,0 +1,38 @@
+
+static if (__traits(compiles, __vector(int[4])))
+{
+ alias int4 = __vector(int[4]);
+
+ int fn(const int[4] x)
+ {
+ int sum = 0;
+ foreach (i; x) sum += i;
+ return sum;
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=19223
+ void test19223()
+ {
+ int4 v1 = int4.init;
+ assert(fn(v1.array) == 0);
+ assert(fn(int4.init.array) == 0);
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=19607
+ void test19607()
+ {
+ int4 v1 = 1;
+ assert(fn(v1.array) == 4);
+ assert(fn(int4(2).array) == 8);
+ }
+
+ void main ()
+ {
+ test19223();
+ test19607();
+ }
+}
+else
+{
+ void main() { }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19251.d b/gcc/testsuite/gdc.test/runnable/test19251.d
new file mode 100644
index 0000000..9e0b9d4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19251.d
@@ -0,0 +1,20 @@
+string result;
+
+struct A
+{
+ int[] a;
+ immutable(A) fun()
+ {
+ result ~= "Yo";
+ return immutable A([7]);
+ }
+
+ alias fun this;
+}
+
+void main()
+{
+ A a;
+ immutable A b = a; // error: cannot implicitly convert expression a of type A to immutable(A)
+ assert(result == "Yo");
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19317.d b/gcc/testsuite/gdc.test/runnable/test19317.d
new file mode 100644
index 0000000..a5633b8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19317.d
@@ -0,0 +1,32 @@
+// REQUIRED_ARGS: -preview=dip1008
+// https://issues.dlang.org/show_bug.cgi?id=19317
+
+class MyException: Exception {
+ static int numInstances;
+ this(string msg) {
+ super(msg);
+ ++numInstances;
+ }
+
+ ~this() {
+ --numInstances;
+ }
+}
+
+void main() {
+ assert(MyException.numInstances == 0);
+
+ try
+ throw new MyException("oops");
+ catch(MyException _)
+ assert(MyException.numInstances == 1);
+
+ assert(MyException.numInstances == 0);
+
+ try
+ throw new MyException("oops I did it again");
+ catch(MyException)
+ assert(MyException.numInstances == 1);
+
+ assert(MyException.numInstances == 0);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19386.d b/gcc/testsuite/gdc.test/runnable/test19386.d
new file mode 100644
index 0000000..3e3157a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19386.d
@@ -0,0 +1,36 @@
+struct Thing
+{
+ this(int* i)
+ {
+ ptr = i;
+ (*ptr)++;
+ }
+
+ ~this()
+ {
+ (*ptr)--;
+ }
+
+ T opCast(T : bool)()
+ {
+ return false;
+ }
+
+ int* ptr;
+}
+
+Thing makeThing(int* p)
+{
+ return Thing(p);
+}
+
+void main()
+{
+ int i;
+ {
+ if (auto t = makeThing(&i)) // destructor not called
+ {
+ }
+ }
+ assert(i == 0);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19393.d b/gcc/testsuite/gdc.test/runnable/test19393.d
new file mode 100644
index 0000000..4226bbd
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19393.d
@@ -0,0 +1,37 @@
+string result;
+
+struct S
+{
+ this(this)
+ {
+ result ~= "A";
+ }
+
+ ~this()
+ {
+ result ~= "B";
+ }
+}
+
+void foo(const(S)[] ar...)
+{
+ /* postblit gets called on this initialization,
+ * then when the function returns, the destructor
+ * gets called => result = "AB";
+ */
+ auto d = ar[0];
+}
+
+void bar()
+{
+ /* S(null) needs to be destroyed after the function call,
+ * that means that another `B` is appended => result = "ABB"
+ */
+ foo(S());
+}
+
+void main()
+{
+ bar();
+ assert(result == "ABB");
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19441.d b/gcc/testsuite/gdc.test/runnable/test19441.d
new file mode 100644
index 0000000..5dcb573
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19441.d
@@ -0,0 +1,24 @@
+// https://issues.dlang.org/show_bug.cgi?id=19441
+struct S1
+{
+ int a;
+ long b;
+ alias a this;
+}
+
+struct S2
+{
+ S1 v;
+ alias v this;
+}
+
+void main()
+{
+ auto x = S2(S1(1, 12345678));
+ assert(x.a == 1 && x.b == 12345678); // prints: 1 12345678
+ S1 y;
+ y = x;
+ assert(y.a == 1 && y.b == 12345678);
+ y = x.v;
+ assert(y.a == 1 && y.b == 12345678);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19476.d b/gcc/testsuite/gdc.test/runnable/test19476.d
new file mode 100644
index 0000000..3143c20
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19476.d
@@ -0,0 +1,18 @@
+// https://issues.dlang.org/show_bug.cgi?id=19476
+
+mixin template operators() {
+ int foo(int op = 1, T)(T rhs) {
+ return 1;
+ }
+}
+
+struct S {
+ mixin operators ops;
+ int foo(int op = 1, T)(T a) {
+ return ops.foo!1(a);
+ }
+}
+
+void main() {
+ S.init.foo(S.init);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19639.d b/gcc/testsuite/gdc.test/runnable/test19639.d
new file mode 100644
index 0000000..36b7630
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19639.d
@@ -0,0 +1,22 @@
+enum EMPTY_STRING = ""[0..0];
+enum SMALL_STRING = "a"[0..1];
+
+void main()
+{
+ {
+ char[64] buf = EMPTY_STRING;
+ foreach (c; buf) assert(c == 0);
+ buf[$-1] = 'e';
+ buf = EMPTY_STRING;
+ assert(buf[$-1] == 0);
+ }
+
+ {
+ char[64] buf = SMALL_STRING;
+ assert(buf[0] == 'a');
+ foreach (c; buf[1..$]) assert(c == 0);
+ buf[$-1] = 'e';
+ buf = SMALL_STRING;
+ assert(buf[$-1] == 0);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19655a.d b/gcc/testsuite/gdc.test/runnable/test19655a.d
new file mode 100644
index 0000000..fc63639
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19655a.d
@@ -0,0 +1,10 @@
+/*
+REQUIRED_ARGS: -Irunnable/imports
+PERMUTE_ARGS:
+COMPILE_SEPARATELY:
+EXTRA_SOURCES: imports/test19655b.d imports/test19655c.d imports/test19655d.d imports/test19655e.d imports/test19655f.d imports/test19655g.d
+*/
+
+import test19655g;
+class Corge
+{ }
diff --git a/gcc/testsuite/gdc.test/runnable/test19672.d b/gcc/testsuite/gdc.test/runnable/test19672.d
new file mode 100644
index 0000000..8f5f50b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19672.d
@@ -0,0 +1,21 @@
+// https://issues.dlang.org/show_bug.cgi?id=19672
+
+struct S
+{
+ ulong c;
+ bool b; // removing this prevents bug
+}
+
+// increase the struct size at least to 17 bytes also prevents the bug.
+
+void main()
+{
+ S[1] a = [S(42)];
+ assert(a[0].c == 42); /* Passes. */
+ f(a);
+}
+
+void f(S[1] a)
+{
+ assert(a[0].c == 42); /* Fails. */
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19679.d b/gcc/testsuite/gdc.test/runnable/test19679.d
new file mode 100644
index 0000000..18b050c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19679.d
@@ -0,0 +1,21 @@
+void delegate() foo()
+{
+ size_t value = 0;
+
+ void check()
+ {
+ assert(value == 0);
+ }
+
+ void nest1()
+ {
+ void nest2() { check(); }
+ nest2();
+ }
+ return &nest1;
+}
+
+void main()
+{
+ foo()();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19688.d b/gcc/testsuite/gdc.test/runnable/test19688.d
new file mode 100644
index 0000000..9cc4dd7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19688.d
@@ -0,0 +1,13 @@
+/* TEST_OUTUT:
+---
+---
+*/
+void test(string s = __FUNCTION__ ~ __MODULE__ ~ __FUNCTION__)
+{
+ assert(s == "test19688.maintest19688test19688.main");
+}
+
+void main()
+{
+ test();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19729.d b/gcc/testsuite/gdc.test/runnable/test19729.d
new file mode 100644
index 0000000..b959c71
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19729.d
@@ -0,0 +1,61 @@
+//https://issues.dlang.org/show_bug.cgi?id=19729
+// PERMUTE_ARGS:
+module test19729;
+
+mixin template Templ(T)
+{
+ this(T t)
+ {
+ }
+}
+
+class C // original TC
+{
+ mixin Templ!int;
+ mixin Templ!string;
+}
+
+class D // named
+{
+ mixin Templ!int ti;
+ mixin Templ!string ts;
+}
+
+class E // top level ctor wins
+{
+ bool topLevelWins;
+ mixin Templ!int;
+ this(int){topLevelWins = true;}
+}
+
+class F // top level ctor wins even if not exact match
+{
+ bool topLevelWins;
+ mixin Templ!ubyte;
+ this(int){topLevelWins = true;}
+}
+
+class G // same as F but change lexicographical order
+{
+ bool topLevelWins;
+ this(int){topLevelWins = true;}
+ mixin Templ!ubyte;
+}
+
+void main()
+{
+ auto c0 = new C("should work");
+ auto c1 = new C(42);
+
+ auto d0 = new D("should work");
+ auto d1 = new D(42);
+
+ auto e = new E(0);
+ assert(e.topLevelWins);
+
+ auto f = new F(ubyte(0));
+ assert(f.topLevelWins);
+
+ auto g = new G(ubyte(0));
+ assert(g.topLevelWins);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19734.d b/gcc/testsuite/gdc.test/runnable/test19734.d
index efa7da3..7342920 100644
--- a/gcc/testsuite/gdc.test/runnable/test19734.d
+++ b/gcc/testsuite/gdc.test/runnable/test19734.d
@@ -9,15 +9,13 @@ class C19734
{
// Invalid 'this' parameter because of applied 'extern' storage class.
void testin(typeof(this) p)
- in { assert(this is p); }
- body
+ in(this is p)
{
}
// Undefined reference to __result.
int testout()
- out { assert(__result == 2); }
- body
+ out(; __result == 2)
{
return 2;
}
diff --git a/gcc/testsuite/gdc.test/runnable/test19774.d b/gcc/testsuite/gdc.test/runnable/test19774.d
new file mode 100644
index 0000000..940a07c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19774.d
@@ -0,0 +1,43 @@
+// https://issues.dlang.org/show_bug.cgi?id=19774
+C bar()
+{
+ return C(42);
+}
+
+C foo()
+{
+ return bar()[1];
+}
+
+C gun()
+{
+ return bar()[$];
+}
+
+struct C
+{
+ int x;
+
+ ~this()
+ {
+ x = 0;
+ }
+
+ int opDollar()
+ {
+ return 1;
+ }
+
+ C opIndex(int a)
+ {
+ return this;
+ }
+}
+
+void main()
+{
+ auto c = foo();
+ assert(c.x == 42); /* fails; should pass */
+ auto d = gun();
+ assert(d.x == 42);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19782.d b/gcc/testsuite/gdc.test/runnable/test19782.d
new file mode 100644
index 0000000..a24d841
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19782.d
@@ -0,0 +1,23 @@
+// https://issues.dlang.org/show_bug.cgi?id=19782
+class Inner
+{
+ int a;
+}
+
+class Outer
+{
+ Inner inner; alias inner this;
+ this(Inner i) { inner = i; }
+}
+
+void main()
+{
+ Inner[] inners = [];
+ inners ~= new Inner;
+ inners ~= new Outer(new Inner); // Appends null
+
+ foreach(inner; inners)
+ {
+ assert(inner.a == 0);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19822.d b/gcc/testsuite/gdc.test/runnable/test19822.d
new file mode 100644
index 0000000..8f0e3f1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19822.d
@@ -0,0 +1,29 @@
+// https://issues.dlang.org/show_bug.cgi?id=19822
+struct Quat
+{
+ static struct Vec { int x; }
+
+ union
+ {
+ Vec v;
+ struct { float x; }
+ }
+
+ static Quat identity()
+ {
+ Quat q;
+ q.x = 1.0f;
+ return q;
+ }
+}
+
+struct QuatContainerWithIncompatibleInit
+{
+ Quat q = Quat.identity;
+}
+
+void main()
+{
+ QuatContainerWithIncompatibleInit c;
+ assert(c.q.x == 1.0f); // fails
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19825.d b/gcc/testsuite/gdc.test/runnable/test19825.d
new file mode 100644
index 0000000..a4f85ca
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19825.d
@@ -0,0 +1,42 @@
+struct JSONValue
+{
+ TaggedUnion payload;
+}
+
+struct TaggedUnion
+{
+ size_t[2] m_data;
+ int m_kind;
+
+ JSONValue opIndex(size_t i)
+ {
+ return JSONValue();
+ }
+}
+
+void yap(lazy JSONValue arg)
+{
+ arg();
+}
+
+struct Foo
+{
+ int a;
+ string name;
+}
+
+Foo makeFoo()
+{
+ JSONValue root;
+ yap(root.payload[0]
+ .payload[0]
+ .payload[0]);
+
+ Foo foo;
+ return foo;
+}
+
+void main()
+{
+ auto foo = makeFoo();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test19891.d b/gcc/testsuite/gdc.test/runnable/test19891.d
new file mode 100644
index 0000000..08e51bc
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test19891.d
@@ -0,0 +1,13 @@
+int g;
+
+void fun(R)(auto ref int a, auto ref R r = g, auto ref int b = 1)
+{
+ ++r;
+}
+
+void main()
+{
+ fun(10, 2);
+ fun(10);
+ assert(g == 1);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test20.d b/gcc/testsuite/gdc.test/runnable/test20.d
index 0e21e30..5a1985a 100644
--- a/gcc/testsuite/gdc.test/runnable/test20.d
+++ b/gcc/testsuite/gdc.test/runnable/test20.d
@@ -1,3 +1,9 @@
+/*
+TEST_OUTPUT:
+---
+runnable/test20.d(448): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+---
+*/
import core.vararg;
extern(C) int printf(const char*, ...);
@@ -72,7 +78,7 @@ struct A4
void test4()
{
- printf("A4.sizeof = %d\n", A4.sizeof);
+ printf("A4.sizeof = %zd\n", A4.sizeof);
assert(A4.sizeof == 1 * int.sizeof);
A4 q;
@@ -213,7 +219,7 @@ void test10()
/*****************************************/
-scope class T11
+class T11
{
this(){}
~this(){}
@@ -270,7 +276,7 @@ void test13()
void write14(bool[] c)
{
- printf("[%2d]: ", c.length);
+ printf("[%2zd]: ", c.length);
foreach (bool x; c)
printf("%d,", x);
printf("\n");
@@ -334,12 +340,6 @@ int y16;
class C16
{
- new(size_t size, byte blah){
- void* v = (new byte[C16.classinfo.initializer.length]).ptr;
- y16 = 1;
- assert(blah == 3);
- return v;
- }
int x;
this()
{
@@ -349,8 +349,7 @@ class C16
void test16()
{
- C16 c = new(3) C16;
- assert(y16 == 1);
+ C16 c = new C16();
assert(c.x == 4);
}
@@ -491,34 +490,6 @@ void test22()
/*****************************************/
-void test23()
-{
- float f;
- double d;
- real r;
-
- if (f > ifloat.max)
- goto Loverflow;
- if (d > ifloat.max)
- goto Loverflow;
- if (r > ifloat.max)
- goto Loverflow;
-
- if (ifloat.max < f)
- goto Loverflow;
- if (ifloat.max < d)
- goto Loverflow;
- if (ifloat.max < r)
- goto Loverflow;
-
- return;
-
- Loverflow:
- return;
-}
-
-/*****************************************/
-
interface I24 { }
void test24()
@@ -583,15 +554,6 @@ void test29()
/*****************************************/
-void test30()
-{
- double d = 1;
- cdouble cd = 1+0i;
- assert(cd == 1.0 + 0i);
-}
-
-/*****************************************/
-
void foo31(...)
{
byte b = va_arg!byte(_argptr);
@@ -743,7 +705,7 @@ void test42()
string string1 = "ワロスw";
string string2 = r"ワロスw";
string string3 = `ワロスw`;
- string string4 = x"E3 83 AF E3 83 AD E3 82 B9 EF BD 97";
+ string string4 = "\xE3\x83\xAF\xE3\x83\xAD\xE3\x82\xB9\xEF\xBD\x97";
assert(string1.length==master.length);
@@ -806,7 +768,7 @@ struct S45
{
double x = 0, y = 0;
static S45 opCall(int i) { S45 r; r.x = i; return r; }
- S45 opMul(S45 s)
+ S45 opBinary(string op)(S45 s) if (op == "*")
{
S45 r;
r.x = x * s.x;
@@ -842,11 +804,11 @@ void test45()
{
S45 s = S45(10);
S45 val = pow!(S45)(s,2);
- printf("x = %2.2lf, y = %2.2lf\n", val.x, val.y);
+ printf("x = %2.2f, y = %2.2f\n", val.x, val.y);
assert(val.x == 100);
assert(val.y == 0);
double d = pow!(double)(10,3);
- printf("%2.2lf\n", d);
+ printf("%2.2f\n", d);
assert(d == 1000);
}
@@ -873,19 +835,6 @@ void test46()
/*****************************************/
-void test47()
-{
- cdouble[] a;
- cdouble[] b;
- foreach(ref cdouble d; b)
- {
- d = -a[0];
- for(;;){}
- }
-}
-
-/*****************************************/
-
string foo48(string s)
{
return s;
@@ -915,7 +864,7 @@ void test49()
{
int i = void;
//printf("i = %d\n", i);
- int[10] a = void;
+ int[10] a;
foreach (int x; a)
{
printf("\tx = %d\n", x);
@@ -938,7 +887,7 @@ void test51()
{
bool[9][3] qwert;
- printf("qwert.sizeof = %d\n", qwert.sizeof);
+ printf("qwert.sizeof = %zd\n", qwert.sizeof);
for (int i = 0; i < 3; i++)
for (int j = 0; j < 9; j++)
@@ -987,13 +936,13 @@ const char[3][13] month = [
void test53()
{
- printf("%.*s\n", month[1].length, month[1].ptr);
- printf("%.*s\n", month[2].length, month[2].ptr);
- printf("%.*s\n", month[3].length, month[3].ptr);
- printf("%.*s\n", month[4].length, month[4].ptr);
- printf("%.*s\n", month[5].length, month[5].ptr);
- printf("%.*s\n", month[6].length, month[6].ptr);
- printf("%.*s\n", month[8].length, month[8].ptr);
+ printf("%.*s\n", cast(int)month[1].length, month[1].ptr);
+ printf("%.*s\n", cast(int)month[2].length, month[2].ptr);
+ printf("%.*s\n", cast(int)month[3].length, month[3].ptr);
+ printf("%.*s\n", cast(int)month[4].length, month[4].ptr);
+ printf("%.*s\n", cast(int)month[5].length, month[5].ptr);
+ printf("%.*s\n", cast(int)month[6].length, month[6].ptr);
+ printf("%.*s\n", cast(int)month[8].length, month[8].ptr);
assert(month[1] == "Jan");
assert(month[2] == "Feb");
@@ -1032,7 +981,7 @@ struct S54
return S54.foo() * S54.foo();
}
- S54 opMul(S54 s)
+ S54 opBinary(string op)(S54 s) if (op == "*")
{
return s;
}
@@ -1052,12 +1001,12 @@ void test55()
str = str ~ c;
uvw = c ~ uvw;
- printf("%.*s\n", str.length, str.ptr);
+ printf("%.*s\n", cast(int)str.length, str.ptr);
assert(str == "a");
assert(uvw == "a");
c = 'b';
- printf("%.*s\n", str.length, str.ptr);
+ printf("%.*s\n", cast(int)str.length, str.ptr);
assert(str == "a");
assert(uvw == "a");
}
@@ -1199,7 +1148,7 @@ void foo61(real[] arr)
for (size_t j = i; j >= i; j -= i)
{
// interesting results follow from this:
- printf("%d ", i);
+ printf("%zd ", i);
// it prints a _lot_ of ones
arr[j] = arr[j - i];
@@ -1253,14 +1202,12 @@ int main()
test20();
test21();
test22();
- test23();
test24();
test25();
test26();
test27();
test28();
test29();
- test30();
test31();
test33();
test34();
@@ -1274,7 +1221,6 @@ int main()
test44();
test45();
test46();
- test47();
test48();
test49();
test50();
@@ -1294,4 +1240,3 @@ int main()
printf("Success\n");
return 0;
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/test20025.d b/gcc/testsuite/gdc.test/runnable/test20025.d
new file mode 100644
index 0000000..9abee45
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test20025.d
@@ -0,0 +1,21 @@
+// https://issues.dlang.org/show_bug.cgi?id=20025
+struct B
+{
+ static int value = 77;
+ alias value this;
+
+ this(ref return scope inout B rhs) inout { }
+}
+
+void test(int x)
+{
+ assert(x == 77);
+}
+
+int main()
+{
+ B b;
+ test(b);
+
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test20036.d b/gcc/testsuite/gdc.test/runnable/test20036.d
new file mode 100644
index 0000000..640de19
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test20036.d
@@ -0,0 +1,10 @@
+
+__gshared int x = 7;
+__gshared int*[70000] px = &x;
+
+void main()
+{
+ foreach(p; px)
+ assert(p && *p == 7);
+}
+
diff --git a/gcc/testsuite/gdc.test/runnable/test20130.d b/gcc/testsuite/gdc.test/runnable/test20130.d
new file mode 100644
index 0000000..09eaee3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test20130.d
@@ -0,0 +1,44 @@
+// https://issues.dlang.org/show_bug.cgi?id=20130
+
+void main() {
+ auto a1 = cast(char[]) "12345678";
+ auto a2 = cast(wchar[]) "12345678"; // Or cast(string|wstring|dstring).
+ auto a3 = cast(dchar[]) "12345678"; // Encoding conversion.
+ assert(a1.length == 8);
+ assert(a2.length == 8);
+ assert(a3.length == 8);
+
+ auto b1 = cast(char[]) "12345678"c;
+ auto b2 = cast(wchar[]) "12345678"c;
+ auto b3 = cast(dchar[]) "12345678"c;
+ assert(b1.length == 8);
+ assert(b2.length == 4);
+ assert(b3.length == 2);
+
+ auto c1 = cast(char[]) "12345678"w;
+ auto c2 = cast(wchar[]) "12345678"w;
+ auto c3 = cast(dchar[]) "12345678"w;
+ assert(c1.length == 16);
+ assert(c2.length == 8);
+ assert(c3.length == 4);
+
+ auto d1 = cast(char[]) "12345678"d;
+ auto d2 = cast(wchar[]) "12345678"d;
+ auto d3 = cast(dchar[]) "12345678"d;
+ assert(d1.length == 32);
+ assert(d2.length == 16);
+ assert(d3.length == 8);
+
+ auto a = cast(uint[]) "12345678";
+ auto b = cast(uint[]) "12345678"d;
+ auto c = cast(uint[]) "12345678"w;
+ auto d = cast(const char[5][]) "12345";
+ auto e = cast(const wchar[2][]) "12345678";
+ immutable f = cast(immutable(uint)[]) "123456789012";
+ assert(a.length == 2);
+ assert(b.length == 8);
+ assert(c.length == 4);
+ assert(d.length == 1);
+ assert(e.length == 2);
+ assert(f.length == 3);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test20401.d b/gcc/testsuite/gdc.test/runnable/test20401.d
new file mode 100644
index 0000000..c3b6072
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test20401.d
@@ -0,0 +1,20 @@
+// https://issues.dlang.org/show_bug.cgi?id=20401
+
+void main()
+{
+ int i;
+ assert(&passthrough(i) == &i);
+}
+
+ref int passthrough(return ref int i)
+{
+ return get().flag ? i : i;
+}
+
+S get() { return S(); }
+
+struct S
+{
+ bool flag;
+ ~this(){}
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test20565.d b/gcc/testsuite/gdc.test/runnable/test20565.d
new file mode 100644
index 0000000..47a8db3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test20565.d
@@ -0,0 +1,18 @@
+// https://issues.dlang.org/show_bug.cgi?id=20565
+
+void main()
+{
+ {
+ int temp(T)() { return 3; }
+ assert(temp!int() == 3);
+ }
+ {
+ int temp(T)() { return 4; }
+ assert(temp!int() == 4);
+ }
+ {
+ int temp(T)() { return 5; }
+ assert(temp!int() == 5);
+ }
+}
+
diff --git a/gcc/testsuite/gdc.test/runnable/test20649.d b/gcc/testsuite/gdc.test/runnable/test20649.d
new file mode 100644
index 0000000..6c645e6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test20649.d
@@ -0,0 +1,15 @@
+struct S { int i; }
+
+auto f()
+{
+ S[] ss;
+ ss.length = 1;
+ return 0;
+}
+
+enum a = f();
+
+void main()
+{
+ f();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test20855.d b/gcc/testsuite/gdc.test/runnable/test20855.d
new file mode 100644
index 0000000..7e43ec8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test20855.d
@@ -0,0 +1,26 @@
+// https://issues.dlang.org/show_bug.cgi?id=20855
+
+string exp()
+{
+ string s = "a = b + c * d + a;";
+ foreach (i; 0 .. 9)
+ s = s ~ s;
+ return s;
+}
+
+int test()
+{
+ auto a=1, b=2, c=3, d=4;
+ mixin(exp());
+ return a;
+}
+
+import core.stdc.stdio;
+
+int main()
+{
+ int a = test();
+ printf("a = %d\n", a);
+ assert(test() == 7169);
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test20893.d b/gcc/testsuite/gdc.test/runnable/test20893.d
new file mode 100644
index 0000000..18a83aa
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test20893.d
@@ -0,0 +1,21 @@
+// REQUIRED_ARGS: -O -inline
+//
+// https://issues.dlang.org/show_bug.cgi?id=20893
+// caused by https://github.com/dlang/dmd/pull/9722
+
+int f(int n)
+{
+ foreach (i; 0..n) {}
+ return 10;
+}
+
+int c(int a, int b)
+{
+ return (f(a) * 1L * f(b)) % 1000;
+}
+
+void main()
+{
+ int[] a = [1];
+ assert(c(2 - 1, 2) == 100);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test21040.d b/gcc/testsuite/gdc.test/runnable/test21040.d
new file mode 100644
index 0000000..8e5ee56
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test21040.d
@@ -0,0 +1,61 @@
+// REQUIRED_ARGS:
+// PERMUTE_ARGS: -mcpu=native
+// https://issues.dlang.org/show_bug.cgi?id=21040
+
+import core.simd;
+
+alias AliasSeq(A ...) = A;
+
+void main()
+{
+ static foreach (T; AliasSeq!(
+ float[8], float[4], double[4], double[2],
+ byte[32], ubyte[32], byte[16], ubyte[16],
+ short[16], ushort[16], short[8], ushort[8],
+ int[8], uint[8], int[4], uint[4],
+ long[4], ulong[4], long[2], ulong[2],
+ void[32], void[16]))
+ {
+ static if (__traits(compiles, __vector(T)))
+ {{
+ __vector(T) v;
+
+ static if (__traits(compiles, { __vector(T) x = 2; }))
+ v = 2;
+ static if (__traits(compiles, { __vector(T) x; x = +x; }))
+ v = +v;
+ static if (__traits(compiles, { __vector(T) x; x = -x; }))
+ v = -v;
+ static if (__traits(compiles, { __vector(T) x; x = x + x; }))
+ v = v + v;
+ static if (__traits(compiles, { __vector(T) x; x += 2; }))
+ v += 2;
+ static if (__traits(compiles, { __vector(T) x; x = x - x; }))
+ v = v - v;
+ static if (__traits(compiles, { __vector(T) x; x -= 2; }))
+ v -= 2;
+ static if (__traits(compiles, { __vector(T) x; x = x * x; }))
+ v = v * v;
+ static if (__traits(compiles, { __vector(T) x; x *= 2; }))
+ v *= 2;
+ static if (__traits(compiles, { __vector(T) x; x = x / x; }))
+ v = v / v;
+ static if (__traits(compiles, { __vector(T) x; x /= 2; }))
+ v /= 2;
+ static if (__traits(compiles, { __vector(T) x; x = x & x; }))
+ v = v & v;
+ static if (__traits(compiles, { __vector(T) x; x &= 2; }))
+ v &= 2;
+ static if (__traits(compiles, { __vector(T) x; x = x | x; }))
+ v = v | v;
+ static if (__traits(compiles, { __vector(T) x; x |= 2; }))
+ v |= 2;
+ static if (__traits(compiles, { __vector(T) x; x = x ^ x; }))
+ v = v ^ v;
+ static if (__traits(compiles, { __vector(T) x; x ^= 2; }))
+ v ^= 2;
+ static if (__traits(compiles, { __vector(T) x; x = ~x; }))
+ v = ~v;
+ }}
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test21120.d b/gcc/testsuite/gdc.test/runnable/test21120.d
new file mode 100644
index 0000000..2714bfc
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test21120.d
@@ -0,0 +1,27 @@
+// https://issues.dlang.org/show_bug.cgi?id=21120
+
+module one.two.three;
+
+struct S {}
+
+struct StructTemplate(T)
+{
+ int a = 123; // non-zero initialized
+
+ ref const(StructTemplate) getInitSymbol()
+ {
+ return initSymbol!StructTemplate;
+ }
+}
+
+template initSymbol(T)
+{
+ pragma(mangle, "_D" ~ T.mangleof[1..$] ~ "6__initZ")
+ extern immutable T initSymbol;
+}
+
+void main()
+{
+ StructTemplate!S inst;
+ assert(inst.getInitSymbol() == inst);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test21357.d b/gcc/testsuite/gdc.test/runnable/test21357.d
new file mode 100644
index 0000000..de219e9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test21357.d
@@ -0,0 +1,35 @@
+// https://issues.dlang.org/show_bug.cgi?id=21357
+// PERMUTE_ARGS:
+struct BatchState
+{
+ int[10] arr;
+
+ BatchState copy()
+ {
+ auto ret = BatchState(arr);
+ arr[0] += 1;
+ return ret;
+ }
+}
+
+struct GrayArea
+{
+ BatchState low;
+
+ this(this)
+ {
+ low = low.copy;
+ }
+}
+
+void main()
+{
+ GrayArea a;
+ a.low.arr[0] = 1;
+ GrayArea b;
+ b.low.arr[0] = 4;
+ b = a; // calls the postblit
+
+ assert(a.low.arr[0] == 1);
+ assert(b.low.arr[0] == 1);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test21403.d b/gcc/testsuite/gdc.test/runnable/test21403.d
new file mode 100644
index 0000000..15314b0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test21403.d
@@ -0,0 +1,72 @@
+// https://issues.dlang.org/show_bug.cgi?id=21403
+
+/***********************************************/
+
+int[] cat11ret3(ref int[] s)
+{
+ s ~= 11;
+ return [3];
+}
+
+int[] doit1(int[] val)
+{
+ (val ~= cat11ret3(val)) ~= 7;
+ return val;
+}
+
+void test1()
+{
+ static assert(doit1([2]) == [2, 11, 3, 7]);
+ assert(doit1([2]) == [2, 11, 3, 7]);
+}
+
+/***********************************************/
+
+char catbretc(ref char[] s)
+{
+ s ~= 'b';
+ return 'c';
+}
+
+char[] doit2(char[] val)
+{
+ (val ~= catbretc(val)) ~= 'd';
+ return val;
+}
+
+void test2()
+{
+ static assert(doit2(['a']) == ['a', 'b', 'c', 'd']);
+ assert(doit2(['a']) == ['a', 'b', 'c', 'd']);
+}
+
+/***********************************************/
+
+int cat2ret3(ref int[] s)
+{
+ s ~= 2;
+ return 3;
+}
+
+int[] doit2(int[] val)
+{
+ (val ~= cat2ret3(val)) ~= 4;
+ return val;
+}
+
+void test3()
+{
+ static assert(doit2([1]) == [1, 2, 3, 4]);
+ assert(doit2([1]) == [1, 2, 3, 4]);
+}
+
+/***********************************************/
+
+int main()
+{
+ test1();
+ test2();
+ test3();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test21424.d b/gcc/testsuite/gdc.test/runnable/test21424.d
new file mode 100644
index 0000000..72abd3f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test21424.d
@@ -0,0 +1,12 @@
+// https://issues.dlang.org/show_bug.cgi?id=21424
+
+void main()
+{
+ ubyte[10] buf;
+ size_t pos = 0;
+ size_t num = 5;
+ buf[pos++] += num;
+ assert(pos == 1);
+ assert(buf[0] == 5);
+ assert(buf[1] == 0);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test21479.d b/gcc/testsuite/gdc.test/runnable/test21479.d
new file mode 100644
index 0000000..84612ab
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test21479.d
@@ -0,0 +1,28 @@
+// https://issues.dlang.org/show_bug.cgi?id=21479
+enum Side
+{
+ left,
+ right
+}
+
+struct Both(T)
+{
+ T left;
+ T right;
+
+ ref T get(Side side)
+ {
+ return side == Side.left ? left : right;
+ }
+}
+
+void main()
+{
+ Both!(int[]) t;
+ t.get(Side.left) ~= 1;
+ assert (t.left.length == 1);
+
+ t.get(Side.right) ~= 1;
+ t.get(Side.right) ~= 2;
+ assert (t.right.length == 2);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test21515.d b/gcc/testsuite/gdc.test/runnable/test21515.d
new file mode 100644
index 0000000..09aea83
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test21515.d
@@ -0,0 +1,81 @@
+// https://issues.dlang.org/show_bug.cgi?id=21515
+// DISABLED: win32 win64
+
+// ABI layout of native complex
+struct _Complex(T) { T re; T im; }
+
+// Special enum definitions.
+version (Posix)
+{
+ align(float.alignof) enum __c_complex_float : _Complex!float;
+ align(double.alignof) enum __c_complex_double : _Complex!double;
+ align(real.alignof) enum __c_complex_real : _Complex!real;
+}
+else
+{
+ align(float.sizeof * 2) enum __c_complex_float : _Complex!float;
+ align(double.sizeof * 2) enum __c_complex_double : _Complex!double;
+ align(real.alignof) enum __c_complex_real : _Complex!real;
+}
+alias complex_float = __c_complex_float;
+alias complex_double = __c_complex_double;
+alias complex_real = __c_complex_real;
+
+extern(D) complex_float dcomplexf() { return typeof(return)(2, 1); }
+extern(D) complex_double dcomplex() { return typeof(return)(2, 1); }
+extern(D) complex_real dcomplexl() { return typeof(return)(2, 1); }
+
+extern(D) void dcomplexf(complex_float c) { assert(c.re == 2 && c.im == 1); }
+extern(D) void dcomplex(complex_double c) { assert(c.re == 2 && c.im == 1); }
+extern(D) void dcomplexl(complex_real c) { assert(c.re == 2 && c.im == 1); }
+
+extern(C) complex_float ccomplexf() { return typeof(return)(2, 1); }
+extern(C) complex_double ccomplex() { return typeof(return)(2, 1); }
+extern(C) complex_real ccomplexl() { return typeof(return)(2, 1); }
+
+extern(C) void ccomplexf2(complex_float c) { assert(c.re == 2 && c.im == 1); }
+extern(C) void ccomplex2(complex_double c) { assert(c.re == 2 && c.im == 1); }
+extern(C) void ccomplexl2(complex_real c) { assert(c.re == 2 && c.im == 1); }
+
+extern(C++) complex_float cpcomplexf() { return typeof(return)(2, 1); }
+extern(C++) complex_double cpcomplex() { return typeof(return)(2, 1); }
+extern(C++) complex_real cpcomplexl() { return typeof(return)(2, 1); }
+
+extern(C++) void cpcomplexf(complex_float c) { assert(c.re == 2 && c.im == 1); }
+extern(C++) void cpcomplex(complex_double c) { assert(c.re == 2 && c.im == 1); }
+extern(C++) void cpcomplexl(complex_real c) { assert(c.re == 2 && c.im == 1); }
+
+int main()
+{
+ auto a1 = dcomplexf();
+ auto b1 = dcomplex();
+ auto c1 = dcomplexl();
+ assert(a1.re == 2 && a1.im == 1);
+ assert(b1.re == 2 && b1.im == 1);
+ assert(c1.re == 2 && c1.im == 1);
+ dcomplexf(a1);
+ dcomplex(b1);
+ dcomplexl(c1);
+
+ auto a2 = ccomplexf();
+ auto b2 = ccomplex();
+ auto c2 = ccomplexl();
+ assert(a2.re == 2 && a2.im == 1);
+ assert(b2.re == 2 && b2.im == 1);
+ assert(c2.re == 2 && c2.im == 1);
+ ccomplexf2(a2);
+ ccomplex2(b2);
+ ccomplexl2(c2);
+
+ auto a3 = cpcomplexf();
+ auto b3 = cpcomplex();
+ auto c3 = cpcomplexl();
+ assert(a3.re == 2 && a3.im == 1);
+ assert(b3.re == 2 && b3.im == 1);
+ assert(c3.re == 2 && c3.im == 1);
+ cpcomplexf(a3);
+ cpcomplex(b3);
+ cpcomplexl(c3);
+
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test21586.d b/gcc/testsuite/gdc.test/runnable/test21586.d
new file mode 100644
index 0000000..6af695c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test21586.d
@@ -0,0 +1,31 @@
+/*
+RUN_OUTPUT:
+---
+this
+~this 1
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=21586
+
+import core.stdc.stdio : printf;
+
+struct S
+{
+ this(int arg)
+ {
+ a = arg;
+ printf("this\n");
+ }
+
+ ~this()
+ {
+ printf("~this %d\n", a);
+ }
+
+ int a;
+}
+
+void main()
+{
+ auto s = true ? S(1) : S(0);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test21822.d b/gcc/testsuite/gdc.test/runnable/test21822.d
new file mode 100644
index 0000000..f0a020a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test21822.d
@@ -0,0 +1,18 @@
+// https://issues.dlang.org/show_bug.cgi?id=21822
+
+bool testAliasedString()
+{
+ auto a = soundexer();
+ auto b = soundexer();
+ return a == b;
+}
+
+char[4] soundexer()
+{
+ return "M365";
+}
+
+void main()
+{
+ assert(testAliasedString());
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test21833.d b/gcc/testsuite/gdc.test/runnable/test21833.d
new file mode 100644
index 0000000..dd59a8e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test21833.d
@@ -0,0 +1,30 @@
+// REQUIRED_ARGS: -O -inline
+// https://issues.dlang.org/show_bug.cgi?id=20855
+
+void testit()
+{
+ pragma(inline, false);
+ short[4] arr = [-1, 6, 0, 4];
+ long1 A = *cast(long1*)(arr.ptr);
+ assert(_mm_extract_pi16(A, 0) == 65535);
+}
+
+struct short4
+{
+ short[4] array;
+}
+
+struct long1
+{
+ long[1] array;
+}
+
+int _mm_extract_pi16 (long1 a, int imm8)
+{
+ return cast(ushort)((cast(short4)a).array[imm8]);
+}
+
+void main()
+{
+ testit();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test22.d b/gcc/testsuite/gdc.test/runnable/test22.d
index 2aabb4d..1d806d6 100644
--- a/gcc/testsuite/gdc.test/runnable/test22.d
+++ b/gcc/testsuite/gdc.test/runnable/test22.d
@@ -1,7 +1,5 @@
-// RUNNABLE_PHOBOS_TEST
// REQUIRED_ARGS:
-import std.math: poly;
import core.stdc.stdarg;
extern(C)
@@ -119,67 +117,6 @@ void test5()
/*************************************/
-void test6()
-{
- ireal a = 6.5i % 3i;
- printf("%Lfi %Lfi\n", a, a - .5i);
- assert(a == .5i);
-
- a = 6.5i % 3;
- printf("%Lfi %Lfi\n", a, a - .5i);
- assert(a == .5i);
-
- real b = 6.5 % 3i;
- printf("%Lf %Lf\n", b, b - .5);
- assert(b == .5);
-
- b = 6.5 % 3;
- printf("%Lf %Lf\n", b, b - .5);
- assert(b == .5);
-}
-
-/*************************************/
-
-void test7()
-{
- cfloat f = 1+0i;
- f %= 2fi;
- printf("%f + %fi\n", f.re, f.im);
- assert(f == 1 + 0i);
-
- cdouble d = 1+0i;
- d %= 2i;
- printf("%f + %fi\n", d.re, d.im);
- assert(d == 1 + 0i);
-
- creal r = 1+0i;
- r %= 2i;
- printf("%Lf + %Lfi\n", r.re, r.im);
- assert(r == 1 + 0i);
-}
-
-/*************************************/
-
-void test8()
-{
- cfloat f = 1+0i;
- f %= 2i;
- printf("%f + %fi\n", f.re, f.im);
- assert(f == 1);
-
- cdouble d = 1+0i;
- d = d % 2i;
- printf("%f + %fi\n", d.re, d.im);
- assert(d == 1);
-
- creal r = 1+0i;
- r = r % 2i;
- printf("%Lf + %Lfi\n", r.re, r.im);
- assert(r == 1);
-}
-
-/*************************************/
-
class A9
{
this(int[] params ...)
@@ -219,7 +156,7 @@ void test10()
{
auto i = 5u;
auto s = typeid(typeof(i)).toString;
- printf("%.*s\n", s.length, s.ptr);
+ printf("%.*s\n", cast(int)s.length, s.ptr);
assert(typeid(typeof(i)) == typeid(uint));
}
@@ -233,103 +170,6 @@ void test11()
/*************************************/
-void assertEqual(real* a, real* b, string file = __FILE__, size_t line = __LINE__)
-{
- auto x = cast(ubyte*)a;
- auto y = cast(ubyte*)b;
-
- // Only compare the 10 value bytes, the padding bytes are of undefined
- // value.
- version (X86) enum count = 10;
- else version (X86_64) enum count = 10;
- else enum count = real.sizeof;
- for (size_t i = 0; i < count; i++)
- {
- if (x[i] != y[i])
- {
- printf("%02d: %02x %02x\n", i, x[i], y[i]);
- import core.exception;
- throw new AssertError(file, line);
- }
- }
-}
-
-void assertEqual(creal* a, creal* b, string file = __FILE__, size_t line = __LINE__)
-{
- assertEqual(cast(real*)a, cast(real*)b, file, line);
- assertEqual(cast(real*)a + 1, cast(real*)b + 1, file, line);
-}
-
-void test12()
-{
- creal a = creal.nan;
- creal b = real.nan + ireal.nan;
- assertEqual(&a, &b);
-
- real c= real.nan;
- real d=a.re;
- assertEqual(&c, &d);
-
- d=a.im;
- assertEqual(&c, &d);
-}
-
-/*************************************/
-
-void test13()
-{
- creal a = creal.infinity;
- creal b = real.infinity + ireal.infinity;
- assertEqual(&a, &b);
-
- real c = real.infinity;
- real d=a.re;
- assertEqual(&c, &d);
-
- d=a.im;
- assertEqual(&c, &d);
-}
-
-/*************************************/
-
-void test14()
-{
- creal a = creal.nan;
- creal b = creal.nan;
- b = real.nan + ireal.nan;
- assertEqual(&a, &b);
-
- real c = real.nan;
- real d=a.re;
- assertEqual(&c, &d);
-
- d=a.im;
- assertEqual(&c, &d);
-}
-
-/*************************************/
-
-ireal x15;
-
-void foo15()
-{
- x15 = -x15;
-}
-
-void bar15()
-{
- return foo15();
-}
-
-void test15()
-{
- x15=2i;
- bar15();
- assert(x15==-2i);
-}
-
-/*************************************/
-
real x16;
void foo16()
@@ -358,7 +198,7 @@ class Bar17
class Foo17
{
- void opAdd (Bar17 b) {}
+ void opBinary(string op : "+") (Bar17 b) {}
}
void test17()
@@ -427,41 +267,6 @@ void test21()
/*************************************/
-void test22()
-{
- static creal[] params = [1+0i, 3+0i, 5+0i];
-
- printf("params[0] = %Lf + %Lfi\n", params[0].re, params[0].im);
- printf("params[1] = %Lf + %Lfi\n", params[1].re, params[1].im);
- printf("params[2] = %Lf + %Lfi\n", params[2].re, params[2].im);
-
- creal[] sums = new creal[3];
- sums[] = 0+0i;
-
- foreach(creal d; params)
- {
- creal prod = d;
-
- printf("prod = %Lf + %Lfi\n", prod.re, prod.im);
- for(int i; i<2; i++)
- {
- sums[i] += prod;
- prod *= d;
- }
- sums[2] += prod;
- }
-
- printf("sums[0] = %Lf + %Lfi", sums[0].re, sums[0].im);
- assert(sums[0].re==9);
- assert(sums[0].im==0);
- assert(sums[1].re==35);
- assert(sums[1].im==0);
- assert(sums[2].re==153);
- assert(sums[2].im==0);
-}
-
-/*************************************/
-
const int c23 = b23 * b23;
const int a23 = 1;
const int b23 = a23 * 3;
@@ -480,51 +285,6 @@ void test23()
/*************************************/
-ifloat func_24_1(ifloat f, double d)
-{
-// f /= cast(cdouble)d;
- return f;
-}
-
-ifloat func_24_2(ifloat f, double d)
-{
- f = cast(ifloat)(f / cast(cdouble)d);
- return f;
-}
-
-float func_24_3(float f, double d)
-{
-// f /= cast(cdouble)d;
- return f;
-}
-
-float func_24_4(float f, double d)
-{
- f = cast(float)(f / cast(cdouble)d);
- return f;
-}
-
-void test24()
-{
- ifloat f = func_24_1(10i, 8);
- printf("%fi\n", f);
-// assert(f == 1.25i);
-
- f = func_24_2(10i, 8);
- printf("%fi\n", f);
- assert(f == 1.25i);
-
- float g = func_24_3(10, 8);
- printf("%f\n", g);
-// assert(g == 1.25);
-
- g = func_24_4(10, 8);
- printf("%f\n", g);
- assert(g == 1.25);
-}
-
-/*************************************/
-
template cat(int n)
{
const int dog = n;
@@ -541,48 +301,11 @@ void test25()
/*************************************/
-string toString26(cdouble z)
-{
- char[ulong.sizeof*8] buf;
-
- auto len = snprintf(buf.ptr, buf.sizeof, "%f+%fi", z.re, z.im);
- return buf[0 .. len].idup;
-}
-
-void test26()
-{
- static cdouble[] A = [1+0i, 0+1i, 1+1i];
- string s;
-
- foreach( cdouble z; A )
- {
- s = toString26(z);
- printf("%.*s ", s.length, s.ptr);
- }
- printf("\n");
-
- for(int ii=0; ii<A.length; ii++ )
- A[ii] += -1i*A[ii];
-
- assert(A[0] == 1 - 1i);
- assert(A[1] == 1 + 1i);
- assert(A[2] == 2);
-
- foreach( cdouble z; A )
- {
- s = toString26(z);
- printf("%.*s ", s.length, s.ptr);
- }
- printf("\n");
-}
-
-/*************************************/
-
void test27()
{ int x;
string s = (int*function(int ...)[]).mangleof;
- printf("%.*s\n", s.length, s.ptr);
+ printf("%.*s\n", cast(int)s.length, s.ptr);
assert((int*function(int ...)[]).mangleof == "APFiXPi");
assert(typeof(x).mangleof == "i");
assert(x.mangleof == "_D6test226test27FZ1xi");
@@ -590,20 +313,12 @@ void test27()
/*************************************/
-void test28()
-{
- alias cdouble X;
- X four = cast(X) (4.0i + 0.4);
-}
-
-/*************************************/
-
void test29()
{
ulong a = 10_000_000_000_000_000,
b = 1_000_000_000_000_000;
- printf("test29\n%lx\n%lx\n%lx\n", a, b, a / b);
+ printf("test29\n%llx\n%llx\n%llx\n", a, b, a / b);
assert((a / b) == 10);
}
@@ -666,7 +381,7 @@ struct particle
float yg; /* Y Gravity */
}
-particle particles[10000];
+particle[10000] particles;
void test32()
{
@@ -923,7 +638,7 @@ in
{
assert(A.length > 0);
}
-body
+do
{
version (D_InlineAsm_X86)
{
@@ -1086,7 +801,7 @@ in
{
assert(A.length > 0);
}
-body
+do
{
ptrdiff_t i = A.length - 1;
real r = A[i];
@@ -1101,19 +816,17 @@ body
void test47()
{
real x = 3.1;
- static real pp[] = [56.1, 32.7, 6];
+ static real[] pp = [56.1, 32.7, 6];
real r;
printf("The result should be %Lf\n",(56.1L + (32.7L + 6L * x) * x));
printf("The C version outputs %Lf\n", poly_c(x, pp));
printf("The asm version outputs %Lf\n", poly_asm(x, pp));
- printf("The std.math version outputs %Lf\n", poly(x, pp));
r = (56.1L + (32.7L + 6L * x) * x);
assert(r == poly_c(x, pp));
version (D_InlineAsm_X86)
assert(r == poly_asm(x, pp));
- assert(r == poly(x, pp));
}
/*************************************/
@@ -1211,28 +924,36 @@ void test52()
}
/*************************************/
-import std.stdio;
-import core.stdc.stdarg;
void myfunc(int a1, ...) {
va_list argument_list;
TypeInfo argument_type;
string sa; int ia; double da;
- writefln("%d variable arguments", _arguments.length);
- writefln("argument types %s", _arguments);
+ assert(_arguments.length == 9);
+
va_start(argument_list, a1);
for (int i = 0; i < _arguments.length; ) {
if ((argument_type=_arguments[i++]) == typeid(string)) {
va_arg(argument_list, sa);
- writefln("%d) string arg = '%s', length %d", i+1, sa.length<=20? sa : "?", sa.length);
+ switch (i)
+ {
+ case 1: assert(sa == "2"); break;
+ case 7: assert(sa == "8"); break;
+ case 8: assert(sa == "9"); break;
+ case 9: assert(sa == "10"); break;
+ default:
+ printf("i = %d\n", i);
+ assert(false);
+ }
} else if (argument_type == typeid(int)) {
va_arg(argument_list, ia);
- writefln("%d) int arg = %d", i+1, ia);
+ assert(ia == i+1);
} else if (argument_type == typeid(double)) {
va_arg(argument_list, da);
- writefln("%d) double arg = %f", i+1, da);
+ const e = i+1;
+ assert((e - 0.0001) < da && da < (e + 0.0001));
} else {
- throw new Exception("invalid argument type");
+ assert(false, argument_type.toString());
}
}
va_end(argument_list);
@@ -1248,6 +969,24 @@ void test6758() {
/*************************************/
+real f18573() { return 1; }
+
+void test18573()
+{
+ cast(void) f18573();
+ cast(void) f18573();
+ cast(void) f18573();
+ cast(void) f18573();
+ cast(void) f18573();
+ cast(void) f18573();
+ cast(void) f18573();
+
+ real b = 2;
+ assert(b == 2); /* fails; should pass */
+}
+
+/*************************************/
+
int main()
{
test1();
@@ -1255,29 +994,18 @@ int main()
test3();
test4();
test5();
- test6();
- test7();
- test8();
test9();
test10();
test11();
- test12();
- test13();
- test14();
- test15();
test16();
test17();
test18();
test19();
test20();
test21();
- test22();
test23();
- test24();
test25();
- test26();
test27();
- test28();
test29();
test30();
test31();
@@ -1305,6 +1033,7 @@ int main()
test51();
test52();
test6758();
+ test18573();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/test22209.d b/gcc/testsuite/gdc.test/runnable/test22209.d
new file mode 100644
index 0000000..f2a4bd5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test22209.d
@@ -0,0 +1,21 @@
+// https://issues.dlang.org/show_bug.cgi?id=22209
+
+struct U { size_t[4] a; }
+
+struct S
+{
+ int x;
+ U u;
+ alias u this;
+}
+
+U foo()
+{
+ S s = S(42, U([1, 2, 3, 4]));
+ return s;
+}
+
+void main()
+{
+ assert(foo().a[0] == 1);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test23.d b/gcc/testsuite/gdc.test/runnable/test23.d
index abf8e37..f1fd4a6 100644
--- a/gcc/testsuite/gdc.test/runnable/test23.d
+++ b/gcc/testsuite/gdc.test/runnable/test23.d
@@ -1,14 +1,8 @@
-// RUNNABLE_PHOBOS_TEST
-// REQUIRED_ARGS:
-
module test;
import core.vararg;
import core.stdc.stdlib;
-import std.stdio;
-import std.string;
-import core.stdc.stdlib;
-
+import core.stdc.stdio;
/*******************************************/
@@ -69,13 +63,6 @@ void test3()
/*******************************************/
-void test4()
-{
- writeln("",true);
-}
-
-/*******************************************/
-
void test5()
{
int[] qwert = new int[6];
@@ -228,9 +215,9 @@ void test11()
{
Foo11 fooIt = new Foo11();
if (fooIt !is null)
- writefln("fooIt should be valid");
+ printf("fooIt should be valid\n");
fooIt.f.foo();
- writefln("it worked");
+ printf("it worked\n");
}
/*******************************************/
@@ -251,7 +238,7 @@ struct B12 {
void test12()
{
A12 a;
- printf("%d\n", A12.sizeof);
+ printf("%zd\n", A12.sizeof);
assert(A12.sizeof == 12);
}
@@ -272,7 +259,7 @@ interface Father {}
class Mother {
Father test() {
- writefln("Called Mother.test!");
+ printf("Called Mother.test!\n");
return new Child(42);
}
}
@@ -283,7 +270,7 @@ class Child : Mother, Father {
this(int d) { data = d; }
override Child test() {
- writefln("Called Child.test!");
+ printf("Called Child.test!\n");
return new Child(69);
}
}
@@ -294,7 +281,7 @@ void test14()
Mother childsMum = aChild;
Child childsChild = aChild.test();
Child mumsChild = cast(Child) childsMum.test();
- writefln("Success2");
+ printf("Success2\n");
}
@@ -335,27 +322,6 @@ void test15()
/*******************************************/
-creal x16;
-
-void foo16()
-{
- x16 = -x16;
-}
-
-void bar16()
-{
- return foo16();
-}
-
-void test16()
-{
- x16 = 2.0L + 0.0Li;
- bar16();
- assert(x16 == -2.0L + 0.0Li);
-}
-
-/*******************************************/
-
void test17()
{
version(D_InlineAsm_X86_64)
@@ -557,15 +523,12 @@ void test25()
char[6] cstr = "123456"c;
auto str1 = cast(wchar[3])(cstr);
- writefln("str1: ", (cast(char[])str1).length , " : ", (cast(char[])str1));
assert(cast(char[])str1 == "123456"c);
auto str2 = cast(wchar[3])("789abc"c);
- writefln("str2: ", (cast(char[])str2).length , " : ", (cast(char[])str2));
assert(cast(char[])str2 == "789abc"c);
auto str3 = cast(wchar[3])("defghi");
- writefln("str3: ", (cast(char[])str3).length , " : ", (cast(char[])str3));
version (LittleEndian)
assert(cast(char[])str3 == "d\000e\000f\000"c);
version (BigEndian)
@@ -631,26 +594,20 @@ uint intRes()
void test28()
{
- auto s = std.string.format("%s", "abc123"[intRes() % $] );
- writefln( "%s", s );
- assert(s == "2");
+ auto s = "abc123"[intRes() % $];
+ assert(s == '2');
static const char[] foo = "abc123";
- s = std.string.format("%s", foo[intRes() % $] );
- assert(s == "2");
-
+ assert(foo[intRes() % $] == '2');
static string bar = "abc123";
- s = std.string.format("%s", bar[intRes() % $] );
- assert(s == "2");
+ assert(bar[intRes() % $] == '2');
const char[] abc = "abc123";
- s = std.string.format("%s", abc[intRes() % $] );
- assert(s == "2");
+ assert(abc[intRes() % $] == '2');
string def = "abc123";
- s = std.string.format("%s", def[intRes() % $] );
- assert(s == "2");
+ assert(def[intRes() % $] == '2');
}
/*******************************************/
@@ -703,72 +660,6 @@ void test31()
/*******************************************/
-class Foo32
-{
- static void* ps;
-
- new (size_t sz)
- {
- void* p = core.stdc.stdlib.malloc(sz);
- printf("new(sz = %d) = %p\n", sz, p);
- ps = p;
- return p;
- }
-
- delete(void* p)
- {
- printf("delete(p = %p)\n", p);
- assert(p == ps);
- if (p) core.stdc.stdlib.free(p);
- }
-}
-
-void test32()
-{
- Foo32 f = new Foo32;
- delete f;
-}
-
-/*******************************************/
-
-class Foo33
-{
-// this() { printf("this()\n"); }
-// ~this() { printf("~this()\n"); }
-
- static void* ps;
- static int del;
-
- new (size_t sz, int i)
- {
- void* p = core.stdc.stdlib.malloc(sz);
- printf("new(sz = %d) = %p\n", sz, p);
- ps = p;
- return p;
- }
-
- delete(void* p)
- {
- printf("delete(p = %p)\n", p);
- assert(p == ps);
- if (p) core.stdc.stdlib.free(p);
- del += 1;
- }
-}
-
-void foo33()
-{
- scope Foo33 f = new(3) Foo33;
-}
-
-void test33()
-{
- foo33();
- assert(Foo33.del == 1);
-}
-
-/*******************************************/
-
struct o_O { int a; }
union O_O { int a; }
class O_o { int a; }
@@ -806,12 +697,6 @@ void test37()
{
Foo37 f = new Foo37();
- writefln("Foo.array[0] = %s", f.array[0] );
- writefln("Foo.array[1] = %s", f.array[1] );
- writefln("Foo.array[2] = %s", f.array[2] );
- writefln("Foo.array[3] = %s", f.array[3] );
- writefln("Foo.count = %s", f.count );
-
assert(f.array[0] == 1.0);
assert(f.array[1] == 1.0);
assert(f.array[2] == 1.0);
@@ -831,7 +716,7 @@ in
checkParameters();
}
-body
+do
{
}
@@ -848,7 +733,7 @@ void delegate() foo39()
void dg()
{
- writefln("delegate!");
+ printf("delegate!\n");
assert(a == 3);
}
}).dg;
@@ -1019,7 +904,8 @@ void test45()
buffer[i] -= cast(char)'a' - 'A'; // segfault here
}
}
- writeln(buffer);
+
+ assert(buffer == "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
}
/*******************************************/
@@ -1189,10 +1075,10 @@ bool[void[]] reg57;
void addToReg57(const(void)[] a, int b, bool v)
{
if (!v)
- writefln("X");
+ printf("X\n");
auto key = a~(cast(void*)&b)[0..4];
reg57[cast(immutable(void)[])key] = v;
- writefln("OK");
+ printf("OK\n");
}
void test57()
@@ -1232,10 +1118,9 @@ struct S59
void test59()
{ S59 s;
- writefln("s = %s", s);
string p;
- p = std.string.format("s = %s", s);
+ p = "s = " ~ s.toString();
assert(p == "s = foo");
}
@@ -1263,11 +1148,13 @@ void test60()
void test61()
{
int[][] f = [[1,2],[3,4]];
+ assert(f.length == 2);
+ assert(f[0].length == 2);
+ assert(f[1].length == 2);
assert(f[0][0] == 1);
assert(f[0][1] == 2);
assert(f[1][0] == 3);
assert(f[1][1] == 4);
- writeln(f);
}
/*******************************************/
@@ -1304,7 +1191,7 @@ void test63()
arr = [1] ~ 2;
// runtime crash, the length == 1
- printf("%d\n", arr.length);
+ printf("%zd\n", arr.length);
assert (arr.length == 2);
assert(arr[0] == 1);
assert(arr[1] == 2);
@@ -1333,7 +1220,6 @@ void test64()
foreach_reverse(v; x)
{
- writeln(v);
assert(j == v);
j--;
}
@@ -1342,7 +1228,6 @@ void test64()
j = 4;
foreach_reverse(i, v; x)
{
- writefln("[%s] = %s", i, v);
assert(i + 1 == j);
assert(j == v);
j--;
@@ -1411,11 +1296,11 @@ void test69()
auto n = new NoBug;
auto n2 = new NoBug2;
- writefln("bug %d", b.t);
+ printf("bug %d\n", b.t);
assert(b.t == 1);
- writefln("nobug %d", n.t);
+ printf("nobug %d\n", n.t);
assert(n.t == 2);
- writefln("nobug2 %d", n2.t);
+ printf("nobug2 %d\n", n2.t);
assert(n2.t == 3);
}
@@ -1428,8 +1313,6 @@ void test70()
}
static const char[0] altsep;
- string s = std.string.format("test%spath", altsep);
- assert(s == "testpath");
foo(altsep);
}
@@ -1502,7 +1385,6 @@ void main()
test1();
test2();
test3();
- test4();
test5();
test6();
test7();
@@ -1514,7 +1396,6 @@ void main()
test13();
test14();
test15();
- test16();
test17();
test18();
test19();
@@ -1530,8 +1411,8 @@ void main()
test29();
test30();
test31();
- test32();
- test33();
+
+
test34();
test37();
test38();
diff --git a/gcc/testsuite/gdc.test/runnable/test24.d b/gcc/testsuite/gdc.test/runnable/test24.d
index 2f31d75..d41d060 100644
--- a/gcc/testsuite/gdc.test/runnable/test24.d
+++ b/gcc/testsuite/gdc.test/runnable/test24.d
@@ -1,5 +1,5 @@
-// RUNNABLE_PHOBOS_TEST
// EXTRA_SOURCES: imports/test24a.d imports/test24b.d
+// EXTRA_FILES: imports/test24c.d
// PERMUTE_ARGS:
// REQUIRED_ARGS:
@@ -7,5 +7,5 @@ import imports.test24a, imports.test24b;
void main()
{
- string hi = std.string.format("%s", 3);
+ string hi = imports.test24c.format("%s", 3);
}
diff --git a/gcc/testsuite/gdc.test/runnable/test27.d b/gcc/testsuite/gdc.test/runnable/test27.d
index a3e76ea..b45c132 100644
--- a/gcc/testsuite/gdc.test/runnable/test27.d
+++ b/gcc/testsuite/gdc.test/runnable/test27.d
@@ -1,4 +1,3 @@
-// RUNNABLE_PHOBOS_TEST
// COMPILE_SEPARATELY
// EXTRA_SOURCES: imports/test27a.d
// PERMUTE_ARGS:
diff --git a/gcc/testsuite/gdc.test/runnable/test28.d b/gcc/testsuite/gdc.test/runnable/test28.d
index 5355c2c..8fb60b9 100644
--- a/gcc/testsuite/gdc.test/runnable/test28.d
+++ b/gcc/testsuite/gdc.test/runnable/test28.d
@@ -1,11 +1,7 @@
-// RUNNABLE_PHOBOS_TEST
module test;
+import core.stdc.stdio;
import core.vararg;
-import std.stdio;
-import std.string;
-
-extern(C) int printf(const char*, ...);
/*******************************************/
@@ -117,41 +113,24 @@ void test8()
{
int[] test;
test.length = 10;
- // Show address of array start and its length (10)
- writefln("%s %s", cast(uint)test.ptr, test.length);
+ assert(test.length == 10);
+ assert(test.ptr != null);
test.length = 1;
- // Show address of array start and its length (1)
- writefln("%s %s", cast(uint)test.ptr, test.length);
+ assert(test.length == 1);
+ assert(test.ptr != null);
test.length = 8;
- // Show address of array start and its length (8)
- writefln("%s %s", cast(uint)test.ptr, test.length);
+ assert(test.length == 8);
+ assert(test.ptr != null);
test.length = 0;
- // Shows 0 and 0!
- writefln("%s %s", cast(uint)test.ptr, test.length);
assert(test.length == 0);
assert(test.ptr != null);
}
/*******************************************/
-cdouble y9;
-
-cdouble f9(cdouble x)
-{
- return (y9 = x);
-}
-
-void test9()
-{
- f9(1.0+2.0i);
- assert(y9 == 1.0+2.0i);
-}
-
-/*******************************************/
-
class CBase10
{
this() { }
@@ -227,10 +206,10 @@ void test14()
void func15(...)
in {
- writefln("Arguments len = %d\n", _arguments.length);
+ printf("Arguments len = %d\n", cast(int)_arguments.length);
assert(_arguments.length == 2);
}
-body {
+do {
}
@@ -402,11 +381,9 @@ void test22()
void test23()
{
auto t=['a','b','c','d'];
- writeln(typeid(typeof(t)));
assert(is(typeof(t) == char[]));
const t2=['a','b','c','d','e'];
- writeln(typeid(typeof(t2)));
assert(is(typeof(t2) == const(const(char)[])));
}
@@ -424,16 +401,6 @@ void test24()
/*******************************************/
-void test25()
-{
- ireal x = 4.0Li;
- ireal y = 4.0Li;
- ireal z = 4Li;
- creal c = 4L + 0Li;
-}
-
-/*******************************************/
-
struct Foo26
{
int a;
@@ -688,7 +655,6 @@ template a34(string name, T...)
string localchar;
foreach (a34; T)
{
- writefln(`hello`);
localchar ~= a34.mangleof;
}
return localchar;
@@ -697,7 +663,7 @@ template a34(string name, T...)
void test34()
{
- writeln(a34!("Adf"[], typeof("adf"),uint)("Adf"[],"adf",1234));
+ assert(a34!("Adf"[], typeof("adf"),uint)("Adf"[],"adf",1234) == "Ayak");
}
/*******************************************/
@@ -722,7 +688,6 @@ template a36(AnotherT,string name,T...){
AnotherT localchar;
foreach(a;T)
{
- writefln(`hello`);
localchar~=a.mangleof;
}
return cast(AnotherT)localchar;
@@ -734,7 +699,7 @@ void test36()
string b="adf";
uint i=123;
char[3] c="Adf";
- writeln(a36!(typeof(b),"Adf")());
+ assert(a36!(typeof(b),"Adf")() == "");
}
/*******************************************/
@@ -780,8 +745,7 @@ void test39()
{
void print(string[] strs)
{
- writeln(strs);
- assert(format("%s", strs) == `["Matt", "Andrew"]`);
+ assert(strs == ["Matt", "Andrew"]);
}
print(["Matt", "Andrew"]);
@@ -803,7 +767,7 @@ void test40()
with (c.propName)
{
- writeln(toString());
+ assert(toString() == "test.test40.C");
}
auto foo = c.propName;
@@ -829,7 +793,7 @@ void test41()
assert(x3 == 1);
//test [0 .. 2] = 'b'; // this line should assert
- writef ("%s\n", test.ptr [0 .. 2]);
+ assert(test.ptr[0 .. 2] == "ba");
}
/*******************************************/
@@ -846,6 +810,12 @@ void test42()
/*******************************************/
+void vararg43(string fmt, ...)
+{
+ assert(_arguments[0] is typeid(const string));
+ assert(va_arg!(const string)(_argptr) == "hello");
+}
+
struct A43
{
static const MY_CONST_STRING = "hello";
@@ -854,7 +824,7 @@ struct A43
{
// This will either print garbage or throw a UTF exception.
// But if never_called() is commented out, then it will work.
- writefln("%s", MY_CONST_STRING);
+ vararg43("%s", MY_CONST_STRING);
}
}
@@ -862,7 +832,7 @@ void never_called43()
{
// This can be anything; there just needs to be a reference to
// A43.MY_CONST_STRING somewhere.
- writefln("%s", A43.MY_CONST_STRING);
+ vararg43("%s", A43.MY_CONST_STRING);
}
void test43()
@@ -873,6 +843,12 @@ void test43()
/*******************************************/
+void vararg44(string fmt, ...)
+{
+ assert(_arguments[0] is typeid(const string));
+ assert(va_arg!(const string)(_argptr) == "hello");
+}
+
class A44
{
static const MY_CONST_STRING = "hello";
@@ -881,7 +857,7 @@ class A44
{
// This will either print garbage or throw a UTF exception.
// But if never_called() is commented out, then it will work.
- writefln("%s", MY_CONST_STRING);
+ vararg44("%s", MY_CONST_STRING);
}
}
@@ -889,7 +865,7 @@ void never_called44()
{
// This can be anything; there just needs to be a reference to
// A44.MY_CONST_STRING somewhere.
- writefln("%s", A44.MY_CONST_STRING);
+ vararg44("%s", A44.MY_CONST_STRING);
}
void test44()
@@ -941,9 +917,9 @@ void test47()
void test48()
{
Object o = new Object();
- printf("%.*s\n", typeof(o).classinfo.name.length, typeof(o).classinfo.name.ptr);
- printf("%.*s\n", (typeof(o)).classinfo.name.length, (typeof(o)).classinfo.name.ptr);
- printf("%.*s\n", (Object).classinfo.name.length, (Object).classinfo.name.ptr);
+ printf("%.*s\n", cast(int)typeof(o).classinfo.name.length, typeof(o).classinfo.name.ptr);
+ printf("%.*s\n", cast(int)(typeof(o)).classinfo.name.length, (typeof(o)).classinfo.name.ptr);
+ printf("%.*s\n", cast(int)(Object).classinfo.name.length, (Object).classinfo.name.ptr);
}
/*******************************************/
@@ -1076,13 +1052,11 @@ void test58()
static S a = {i: 1};
static S b;
- writefln("a.bar: %s, %s", a.bar, a.abc);
assert(a.i == 1);
assert(a.bar[0] == 4);
assert(a.bar[1] == 4);
assert(a.bar[2] == 4);
assert(a.bar[3] == 4);
- writefln("b.bar: %s, %s", b.bar, b.abc);
assert(b.i == 0);
assert(b.bar[0] == 4);
assert(b.bar[1] == 4);
@@ -1093,10 +1067,18 @@ void test58()
/*******************************************/
+void vararg59(...)
+{
+ if (_arguments[0] is typeid(size_t))
+ assert(va_arg!size_t(_argptr) == 454);
+ else
+ assert(va_arg!string(_argptr) == "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234");
+}
+
void bug59(string s)()
{
- writeln(s);
- writeln(s.length);
+ vararg59(s);
+ vararg59(s.length);
}
void test59()
@@ -1139,7 +1121,6 @@ void test62()
Vector62 a;
a.set(1,2,24);
a = a * 2;
- writeln(a.x, a.y, a.z);
assert(a.x == 2);
assert(a.y == 4);
assert(a.z == 48);
@@ -1158,7 +1139,7 @@ struct Vector62
z = _z;
}
- Vector62 opMul(float s)
+ Vector62 opBinary(string op : "*")(float s)
{
Vector62 ret;
ret.x = x*s;
@@ -1191,8 +1172,6 @@ void test63()
{
Data63 d; d.x = 1; d.y = 2;
d = frob(d);
- writeln(d.x);
- writeln(d.y);
assert(d.x == 3 && d.y == -1);
}
@@ -1200,8 +1179,8 @@ void test63()
class Foo64
{
- this() { writefln("Foo64 created"); }
- ~this() { writefln("Foo64 destroyed"); }
+ this() { }
+ ~this() { }
}
template Mix64()
@@ -1249,6 +1228,49 @@ void test65()
/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18576
+
+void delegate() callback;
+
+struct S66 {
+ int x;
+ @disable this(this);
+
+ this(int x) {
+ this.x = x;
+ callback = &inc;
+ }
+ void inc() {
+ x++;
+ }
+}
+
+auto f66()
+{
+ return g66(); // RVO should be done
+}
+
+auto g66()
+{
+ return h66(); // RVO should be done
+}
+
+auto h66()
+{
+ return S66(100);
+}
+
+void test18576()
+{
+ auto s = f66();
+ printf("%p vs %p\n", &s, callback.ptr);
+ callback();
+ printf("s.x = %d\n", s.x);
+ assert(s.x == 101);
+ assert(&s == callback.ptr);
+}
+
+/*******************************************/
void main()
{
@@ -1261,7 +1283,6 @@ void main()
test6();
test7();
test8();
- test9();
test10();
test11();
test12();
@@ -1276,7 +1297,6 @@ void main()
test22();
test23();
test24();
- test25();
test26();
test27();
test28();
@@ -1315,6 +1335,7 @@ void main()
test63();
test64();
test65();
+ test18576();
printf("Success\n");
}
diff --git a/gcc/testsuite/gdc.test/runnable/test29.d b/gcc/testsuite/gdc.test/runnable/test29.d
index 9156c91..03c81c6 100644
--- a/gcc/testsuite/gdc.test/runnable/test29.d
+++ b/gcc/testsuite/gdc.test/runnable/test29.d
@@ -1,6 +1,12 @@
-// COMPILE_SEPARATELY
-// EXTRA_SOURCES: imports/test29a.d imports/test29b.d
-// PERMUTE_ARGS:
+/*
+COMPILE_SEPARATELY
+EXTRA_SOURCES: imports/test29a.d imports/test29b.d
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+42
+---
+*/
import imports.test29a;
import imports.test29b;
@@ -10,4 +16,3 @@ extern(C) int printf(const char*, ...);
void main() {
printf("%d\n", qwert);
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/test3.d b/gcc/testsuite/gdc.test/runnable/test3.d
index 11f66c6..4c6b9de 100644
--- a/gcc/testsuite/gdc.test/runnable/test3.d
+++ b/gcc/testsuite/gdc.test/runnable/test3.d
@@ -34,7 +34,7 @@ int main(string[] args)
a.bar = "hello";
a.bar = baz ~ "betty";
- printf("a.bar = '%.*s'\n", a.bar.length, a.bar.ptr);
+ printf("a.bar = '%.*s'\n", cast(int)a.bar.length, a.bar.ptr);
assert(a.bar == "lolobetty");
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/test30.d b/gcc/testsuite/gdc.test/runnable/test30.d
index 085311a..384ff4c 100644
--- a/gcc/testsuite/gdc.test/runnable/test30.d
+++ b/gcc/testsuite/gdc.test/runnable/test30.d
@@ -1,4 +1,4 @@
-// 444
+// https://issues.dlang.org/show_bug.cgi?id=444
int main()
{
diff --git a/gcc/testsuite/gdc.test/runnable/test34.d b/gcc/testsuite/gdc.test/runnable/test34.d
index e38ab1c..dee6609 100644
--- a/gcc/testsuite/gdc.test/runnable/test34.d
+++ b/gcc/testsuite/gdc.test/runnable/test34.d
@@ -1,18 +1,8 @@
-// RUNNABLE_PHOBOS_TEST
-/*
-TEST_OUTPUT:
----
-Object
----
-*/
-
module test34;
-import std.stdio;
-import std.string;
-import std.format;
import core.exception;
-
+import core.stdc.stdio;
+import core.vararg;
/************************************************/
@@ -26,16 +16,12 @@ void test1()
auto hfoo = ti_foo.toHash();
auto hbar = ti_bar.toHash();
- writefln("typeid(Foo).toHash: ", hfoo);
- writefln("typeid(Bar).toHash: ", hbar);
assert(hfoo != hbar);
auto e = (ti_foo == ti_bar);
- writefln("opEquals: ", e ? "equal" : "not equal");
assert(!e);
auto c = (ti_foo.opCmp(ti_bar) == 0);
- writefln("opCmp: ", c ? "equal" : "not equal");
assert(!c);
}
@@ -63,7 +49,6 @@ Struct[1] table;
Struct getfirst()
{
foreach(v; table) {
- writeln(v.langID);
assert(v.langID == 1);
return v;
}
@@ -73,7 +58,6 @@ Struct getfirst()
Struct getsecond()
{
foreach(ref v; table) {
- writeln(v.langID);
assert(v.langID == 1);
return v;
}
@@ -85,11 +69,9 @@ void test3()
table[0].langID = 1;
auto v = getfirst();
- writeln(v.langID);
assert(v.langID == 1);
v = getsecond();
- writeln(v.langID);
assert(v.langID == 1);
}
@@ -198,11 +180,6 @@ template parseInteger(string s)
void test7()
{
- writeln(parseUinteger!("1234abc").value);
- writeln(parseUinteger!("1234abc").rest);
- writeln(parseInteger!("-1234abc").value);
- writeln(parseInteger!("-1234abc").rest);
-
assert(parseUinteger!("1234abc").value == "1234");
assert(parseUinteger!("1234abc").rest == "abc");
assert(parseInteger!("-1234abc").value == "-1234");
@@ -284,10 +261,8 @@ class B34 : A34 { }
void test11()
{
A34 test=new B34;
- writefln("Test is ", test.toString);
assert(test.toString == "test34.B34");
A34 test_2=cast(A34)(new B34);
- writefln("Test 2 is ", test_2.toString);
assert(test_2.toString == "test34.B34");
}
@@ -357,7 +332,6 @@ struct Iterator16(T : Basic16!(T, U), U)
{
static void Foo()
{
- writeln(typeid(T), typeid(U));
assert(is(T == int));
assert(is(U == float));
}
@@ -529,11 +503,8 @@ template Mang(alias F)
template moo(alias A)
{
- pragma(msg," ");
const string a = Mang!(A).mangledname;
- pragma(msg," ");
static assert(Mang!(A).mangledname == a); // FAILS !!!
- pragma(msg," ");
}
void test27()
@@ -658,10 +629,39 @@ struct Vector34
public string toString()
{
- return std.string.format("<%f, %f, %f>", x, y, z);
+ return formatImpl("<%f, %f, %f>", x, y, z);
+ }
+
+ private static string formatImpl(string fmt, ...)
+ {
+ string ret = "<";
+ bool comma;
+ foreach (arg; _arguments)
+ {
+ assert(arg is typeid(float));
+ if (comma)
+ ret ~= ", ";
+ auto f = va_arg!float(_argptr);
+ if (f == 1)
+ ret ~= "1.000000";
+ else if (f == 0)
+ ret ~= "0.000000";
+ else
+ assert(0);
+ comma = true;
+ }
+ ret ~= ">";
+ return ret;
}
}
+string format34(string fmt, ...)
+{
+ assert(_arguments[0] is typeid(Vector34));
+ auto arg = va_arg!Vector34(_argptr);
+ return arg.toString();
+}
+
class Foo34
{
private Vector34 v;
@@ -679,17 +679,12 @@ class Foo34
private void bar()
{
auto s = foobar();
- writef("Returned: %s\n", s);
- assert(std.string.format("%s", s) == "<1.000000, 0.000000, 0.000000>");
+ assert(format34("%s", s) == "<1.000000, 0.000000, 0.000000>");
}
public Vector34 foobar()
{
- writef("Returning %s\n", v);
-
return v;
- Vector34 b = Vector34();
- return b;
}
}
@@ -704,18 +699,18 @@ void test34()
void foo35()
{
- uint a;
- uint b;
- uint c;
- extern (Windows) int function(int i, int j, int k) xxx;
+ uint a;
+ uint b;
+ uint c;
+ extern (Windows) int function(int i, int j, int k) xxx;
- a = 1;
- b = 2;
- c = 3;
+ a = 1;
+ b = 2;
+ c = 3;
- xxx = cast(typeof(xxx))(a + b);
- throw new Exception("xxx");
- xxx( 4, 5, 6 );
+ xxx = cast(typeof(xxx))(a + b);
+ throw new Exception("xxx");
+ xxx( 4, 5, 6 );
}
void test35()
@@ -737,7 +732,7 @@ void test37()
{
synchronized
{
- writefln("Hello world!");
+ printf("Hello world!\n");
}
}
}
@@ -768,7 +763,7 @@ static Rect sizeTest(bool empty) {
}
void print38(Rect r) {
- writefln("(%d, %d)-(%d, %d)", r.left, r.top, r.right, r.bottom);
+ printf("(%d, %d)-(%d, %d)\n", r.left, r.top, r.right, r.bottom);
assert(r.left == 0);
assert(r.right == 0);
assert(r.top == 0);
@@ -781,37 +776,66 @@ Rect defaultRect() {
/************************************************/
+void varargs39(...)
+{
+ if (_arguments[0] is typeid(double[]))
+ {
+ auto arg = va_arg!(double[])(_argptr);
+ assert(arg.length == 1 && arg[0] == 1 || arg[0] == 2);
+ }
+ else if (_arguments[0] is typeid(double[][]))
+ {
+ auto arg = va_arg!(double[][])(_argptr);
+ assert(arg == [[1],[2]]);
+ }
+ else if (_arguments[0] is typeid(double[1][]))
+ {
+ auto arg = va_arg!(double[1][])(_argptr);
+ assert(arg == [[1], [2]]);
+ }
+ else
+ assert(0);
+}
+
void test39()
{
double[][] foo = [[1.0],[2.0]];
- writeln(foo[0]); // --> [1] , ok
- writeln(foo[1]); // --> [2] , ok
-
- writeln(foo); // --> [[1],4.63919e-306] ack!
- writefln("%s", foo); // --> ditto
- auto f = std.string.format("%s", foo);
- assert(f == "[[1], [2]]");
+ varargs39(foo[0]); // --> [1] , ok
+ varargs39(foo[1]); // --> [2] , ok
+ varargs39(foo); // --> [[1],4.63919e-306] ack!
double[1][2] bar;
bar[0][0] = 1.0;
bar[1][0] = 2.0;
- writeln(bar); // Error: Access violation
- auto r = std.string.format("%s", bar);
- assert(r == "[[1], [2]]");
+ varargs39(bar); // Error: Access violation
}
/************************************************/
+void varargs40(...)
+{
+ if (_arguments[0] is typeid(int[char]))
+ {
+ auto x = va_arg!(int[char])(_argptr);
+ assert(x == ['b':123]);
+ }
+ else if (_arguments[0] is typeid(int))
+ {
+ auto x = va_arg!int(_argptr);
+ assert(x == 123);
+ }
+ else
+ assert(0);
+}
+
void test40()
{
int[char] x;
x['b'] = 123;
- writeln(x);
- auto r = std.string.format("%s", x);
- assert(r == "['b':123]");
- writeln(x['b']);
+ varargs40(x);
+ varargs40(x['b']);
}
/************************************************/
@@ -855,12 +879,28 @@ void test44()
/************************************************/
+void varargs45(...)
+{
+ if (_arguments[0] is typeid(const(char[3])[]))
+ {
+ auto a = va_arg!(const(char[3])[])(_argptr);
+ assert(a == ["abc", "def"]);
+ }
+ else if (_arguments[0] is typeid(const(char)[][]))
+ {
+ auto b = va_arg!(const(char)[][])(_argptr);
+ assert(b == ["abc", "def"]);
+ }
+ else
+ assert(0);
+}
+
void test45()
{
- //char[3][] a = ["abc", "def"];
- //writefln(a);
- //char[][2] b = ["abc", "def"];
- //writefln(b);
+ const(char)[3][] a = ["abc", "def"];
+ varargs45(a);
+ const(char)[][2] b = ["abc", "def"];
+ varargs45(b);
}
/************************************************/
@@ -981,26 +1021,22 @@ void test49()
version (all)
{
- writefln("Before test 1: ", a.v);
- if (a == a.init) { writeln(a.v,"(a==a.init)"); assert(0); }
- else { writeln(a.v,"(a!=a.init)"); assert(a.v == 10); }
+ if (a == a.init) { assert(0); }
+ else { assert(a.v == 10); }
}
else
{
- writefln("Before test 1: ", a.v);
- if (a == a.init) { writeln(a.v,"(a==a.init)"); assert(a.v == 10); }
- else { writeln(a.v,"(a!=a.init)"); assert(0); }
+ if (a == a.init) { assert(a.v == 10); }
+ else { assert(0); }
}
a.v = 100;
- writefln("Before test 2: ", a.v);
- if (a == a.init) { writeln(a.v,"(a==a.init)"); assert(0); }
- else { writeln(a.v,"(a!=a.init)"); assert(a.v == 100); }
+ if (a == a.init) { assert(0); }
+ else { assert(a.v == 100); }
a = A(1000);
- writefln("Before test 3: ", a.v);
- if (a == a.init) { writeln(a.v,"(a==a.init)"); assert(0); }
- else { writeln(a.v,"(a!=a.init)"); assert(a.v == 1000); }
+ if (a == a.init) { assert(0); }
+ else { assert(a.v == 1000); }
version (all)
assert(a.init.v == 0);
@@ -1044,14 +1080,6 @@ struct TestStruct
void func53(TestStruct[2] testarg)
{
- writeln(testarg[0].dummy0);
- writeln(testarg[0].dummy1);
- writeln(testarg[0].dummy2);
-
- writeln(testarg[1].dummy0);
- writeln(testarg[1].dummy1);
- writeln(testarg[1].dummy2);
-
assert(testarg[0].dummy0 == 0);
assert(testarg[0].dummy1 == 1);
assert(testarg[0].dummy2 == 2);
@@ -1061,11 +1089,10 @@ void func53(TestStruct[2] testarg)
assert(testarg[1].dummy2 == 2);
}
-TestStruct m53[2];
+TestStruct[2] m53;
void test53()
{
- writeln(&m53);
func53(m53);
}
@@ -1076,13 +1103,11 @@ void test54()
double a = 0;
double b = 1;
// Internal error: ..\ztc\cg87.c 3233
-// a += (1? b: 1+1i)*1i;
- writeln(a);
-// assert(a == 0);
+ a += ((1? b: 1+1i)*1i).re;
+ assert(a == 0);
// Internal error: ..\ztc\cod2.c 1680
-// a += (b?1:b-1i)*1i;
- writeln(a);
-// assert(a == 0);
+ a += ((b?1:b-1i)*1i).re;
+ assert(a == 0);
}
/************************************************/
@@ -1101,7 +1126,7 @@ void test55()
/************************************************/
template t56() { alias Object t56; }
-pragma(msg, t56!().stringof);
+static assert(t56!().stringof == "Object");
void test56()
{
@@ -1115,9 +1140,6 @@ void test57()
static if (is(AA T : T[U], U : const char[]))
{
- writeln(typeid(T));
- writeln(typeid(U));
-
assert(is(T == long));
assert(is(U == const(char)[]));
}
@@ -1129,9 +1151,7 @@ void test57()
static if (is(int[10] W : W[V], int V))
{
- writeln(typeid(W));
assert(is(W == int));
- writeln(V);
assert(V == 10);
}
@@ -1295,7 +1315,7 @@ void main()
test61();
test62();
- writefln("Success");
+ printf("Success\n");
}
diff --git a/gcc/testsuite/gdc.test/runnable/test3449.d b/gcc/testsuite/gdc.test/runnable/test3449.d
index d330cb9..8d38918 100644
--- a/gcc/testsuite/gdc.test/runnable/test3449.d
+++ b/gcc/testsuite/gdc.test/runnable/test3449.d
@@ -1,6 +1,6 @@
/******************************************/
-// 3449
+// https://issues.dlang.org/show_bug.cgi?id=3449
template TypeTuple(T...) { alias TypeTuple = T; }
@@ -13,6 +13,10 @@ static this()
{
mg1 = 10;
cg1 = 10;
+}
+
+shared static this()
+{
ig1 = 10;
}
static assert(!__traits(compiles, { static assert(mg1 == 0); }));
@@ -89,7 +93,7 @@ void test3449()
}
/******************************************/
-// 10643
+// https://issues.dlang.org/show_bug.cgi?id=10643
struct S10643
{
diff --git a/gcc/testsuite/gdc.test/runnable/test3574a.d b/gcc/testsuite/gdc.test/runnable/test3574a.d
index c2283f7..c6122e7 100644
--- a/gcc/testsuite/gdc.test/runnable/test3574a.d
+++ b/gcc/testsuite/gdc.test/runnable/test3574a.d
@@ -6,7 +6,7 @@ out
{
g = 100;
}
-body
+do
{
return;
// expected return code == 0
diff --git a/gcc/testsuite/gdc.test/runnable/test3574b.d b/gcc/testsuite/gdc.test/runnable/test3574b.d
index d239ab6..b256c64 100644
--- a/gcc/testsuite/gdc.test/runnable/test3574b.d
+++ b/gcc/testsuite/gdc.test/runnable/test3574b.d
@@ -6,7 +6,7 @@ out
{
g = 100;
}
-body
+do
{
//return;
// expected return code == 0
diff --git a/gcc/testsuite/gdc.test/runnable/test3574c.d b/gcc/testsuite/gdc.test/runnable/test3574c.d
index 2974da5..f93e22a 100644
--- a/gcc/testsuite/gdc.test/runnable/test3574c.d
+++ b/gcc/testsuite/gdc.test/runnable/test3574c.d
@@ -6,7 +6,7 @@ void main()
//{
// g = 100;
//}
-//body
+//do
{
return;
// expected return code == 0
diff --git a/gcc/testsuite/gdc.test/runnable/test3574d.d b/gcc/testsuite/gdc.test/runnable/test3574d.d
index 0eaf2dd..7976b34 100644
--- a/gcc/testsuite/gdc.test/runnable/test3574d.d
+++ b/gcc/testsuite/gdc.test/runnable/test3574d.d
@@ -6,7 +6,7 @@ void main()
//{
// g = 100;
//}
-//body
+//do
{
//return;
// expected return code == 0
diff --git a/gcc/testsuite/gdc.test/runnable/test37.d b/gcc/testsuite/gdc.test/runnable/test37.d
index f4a4547..08305cb 100644
--- a/gcc/testsuite/gdc.test/runnable/test37.d
+++ b/gcc/testsuite/gdc.test/runnable/test37.d
@@ -1,14 +1,15 @@
-// RUNNABLE_PHOBOS_TEST
// PERMUTE_ARGS:
// REQUIRED_ARGS: -Jrunnable/extra-files
// EXTRA_FILES: extra-files/foo37.txt extra-files/std14198/uni.d
-import std.stdio;
+import core.stdc.stdio;
void main()
{
- writefln(import("foo37.txt"));
+ auto s = import("foo37.txt");
+ printf("%.*s\n", cast(int)s.length, s.ptr);
// also want to ensure that we can access
// imports in a subdirectory of the -J path
- writefln(import("std14198/uni.d"));
+ s = import("std14198/uni.d");
+ printf("%.*s\n", cast(int)s.length, s.ptr);
}
diff --git a/gcc/testsuite/gdc.test/runnable/test38.d b/gcc/testsuite/gdc.test/runnable/test38.d
index 4fc728d..4c76e9f 100644
--- a/gcc/testsuite/gdc.test/runnable/test38.d
+++ b/gcc/testsuite/gdc.test/runnable/test38.d
@@ -1,8 +1,14 @@
-// COMPILE_SEPARATELY
-// EXTRA_SOURCES: imports/test38a.d
-// PERMUTE_ARGS:
+/*
+COMPILE_SEPARATELY
+EXTRA_SOURCES: imports/test38a.d
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+b = 49, 49
+---
+*/
-import std.stdio;
+import core.stdc.stdio;
import imports.test38a;
void main()
diff --git a/gcc/testsuite/gdc.test/runnable/test4.d b/gcc/testsuite/gdc.test/runnable/test4.d
index 1d03572..9811254 100644
--- a/gcc/testsuite/gdc.test/runnable/test4.d
+++ b/gcc/testsuite/gdc.test/runnable/test4.d
@@ -1,5 +1,11 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS:
+/*
+TEST_OUTPUT:
+---
+runnable/test4.d(717): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+---
+*/
import core.exception;
import core.stdc.math;
@@ -48,17 +54,17 @@ void test1()
void test2()
{
- byte foo1[5];
- ubyte foo2[6];
- short foo3[7];
- ushort foo4[8];
- int foo5[9];
- uint foo6[10];
- long foo7[11];
- ulong foo8[12];
- float foo9[13];
- double foo10[14];
- real foo11[15];
+ byte[5] foo1;
+ ubyte[6] foo2;
+ short[7] foo3;
+ ushort[8] foo4;
+ int[9] foo5;
+ uint[10] foo6;
+ long[11] foo7;
+ ulong[12] foo8;
+ float[13] foo9;
+ double[14] foo10;
+ real[15] foo11;
int i;
@@ -96,17 +102,17 @@ void test2()
void test3()
{
- byte foo1[5] = 20;
- ubyte foo2[6] = 21;
- short foo3[7] = 22;
- ushort foo4[8] = 23;
- int foo5[9] = 24;
- uint foo6[10] = 25;
- long foo7[11] = 26;
- ulong foo8[12] = 27;
- float foo9[13] = 28;
- double foo10[14] = 29;
- real foo11[15] = 30;
+ byte[5] foo1 = 20;
+ ubyte[6] foo2 = 21;
+ short[7] foo3 = 22;
+ ushort[8] foo4 = 23;
+ int[9] foo5 = 24;
+ uint[10] foo6 = 25;
+ long[11] foo7 = 26;
+ ulong[12] foo8 = 27;
+ float[13] foo9 = 28;
+ double[14] foo10 = 29;
+ real[15] foo11 = 30;
int i;
@@ -257,13 +263,13 @@ struct TestVectors
string replace;
};
-TestVectors tva[] =
+TestVectors[] tva =
[
{ pattern:"(a)\\1", input:"abaab", result:"y", format:"&", replace:"aa" },
{ pattern:"abc", input:"abc", result:"y", format:"&", replace:"abc" },
];
-TestVectors tvs[2] =
+TestVectors[2] tvs =
[
{ pattern:"(a)\\1", input:"abaab", result:"y", format:"&", replace:"aa" },
{ pattern:"abc", input:"abc", result:"y", format:"&", replace:"abc" },
@@ -360,8 +366,8 @@ const uint MAX_PATH1 = 260;
enum { MAX_PATH2 = 261 }
struct WIN32_FIND_DATA {
- char cFileName1[MAX_PATH1];
- char cFileName2[MAX_PATH2];
+ char[MAX_PATH1] cFileName1;
+ char[MAX_PATH2] cFileName2;
}
void test11()
@@ -502,10 +508,10 @@ void test15()
struct GUID { // size is 16
align(1):
- uint Data1;
- ushort Data2;
- ushort Data3;
- ubyte Data4[8];
+ uint Data1;
+ ushort Data2;
+ ushort Data3;
+ ubyte[8] Data4;
}
@@ -543,26 +549,7 @@ void test16()
/* ================================ */
-void test17()
-{
- creal z = 1. + 2.0i;
-
- real r = z.re;
- assert(r == 1.0);
-
- real i = z.im;
- assert(i == 2.0);
-
- assert(r.im == 0.0);
- assert(r.re == 1.0);
-
- assert(i.re == 2.0);
- assert(i.im == 0.0i);
-}
-
-/* ================================ */
-
-private const uint crc_table[256] = [
+private const uint[256] crc_table = [
0x00000000u, 0x77073096u, 0xee0e612cu, 0x990951bau, 0x076dc419u,
0x2d02ef8du
];
@@ -640,24 +627,6 @@ void test20()
/* ================================ */
-void test21()
-{
- ireal imag = 2.5i;
- printf ("test of imag*imag = %Lf\n",imag*imag);
- assert(imag * imag == -6.25);
-}
-
-/* ================================ */
-
-void test22()
-{
- creal z1 = 1. - 2.0i;
- ireal imag_part = z1.im/1i;
-}
-
-
-/* ================================ */
-
int def23(int x, int y)
{
return x * y;
@@ -978,11 +947,11 @@ void test43()
{
string s;
- s = __FILE__; printf("file = '%.*s'\n", s.length, s.ptr);
+ s = __FILE__; printf("file = '%.*s'\n", cast(int)s.length, s.ptr);
printf("line = %d\n", __LINE__);
- s = __DATE__; printf("date = '%.*s'\n", s.length, s.ptr);
- s = __TIME__; printf("time = '%.*s'\n", s.length, s.ptr);
- s = __TIMESTAMP__; printf("timestamp = '%.*s'\n", s.length, s.ptr);
+ s = __DATE__; printf("date = '%.*s'\n", cast(int)s.length, s.ptr);
+ s = __TIME__; printf("time = '%.*s'\n", cast(int)s.length, s.ptr);
+ s = __TIMESTAMP__; printf("timestamp = '%.*s'\n", cast(int)s.length, s.ptr);
}
/* ================================ */
@@ -1143,7 +1112,10 @@ class Cout{
Cout set(int x){
return this;
}
- alias set opShl;
+ Cout opBinary(string op)(int x) if (op == "<<")
+ {
+ return set(x);
+ }
}
void test49()
@@ -1250,7 +1222,7 @@ void test54()
}
catch(Exception e)
{
- printf("catch %.*s\n", e.msg.length, e.msg.ptr);
+ printf("catch %.*s\n", cast(int)e.msg.length, e.msg.ptr);
assert(e.msg == "first");
assert(e.next.msg == "second");
}
@@ -1270,7 +1242,7 @@ void foo55()
catch (Exception e)
{
printf("inner catch %p\n", e);
- printf("e.msg == %.*s\n", e.msg.length, e.msg.ptr);
+ printf("e.msg == %.*s\n", cast(int)e.msg.length, e.msg.ptr);
assert(e.msg == "second");
//assert(e.msg == "first");
//assert(e.next.msg == "second");
@@ -1404,6 +1376,46 @@ void test59()
/* ================================ */
+// https://issues.dlang.org/show_bug.cgi?id=10664
+
+Exception collectExceptionE(int delegate () expression, ref int result)
+{
+ try
+ {
+ result = expression();
+ }
+ catch (Exception e)
+ {
+ return e;
+ }
+ return null;
+}
+
+RangeError collectExceptionR(int delegate () expression, ref int result)
+{
+ try
+ {
+ result = expression();
+ }
+ catch (RangeError e)
+ {
+ return e;
+ }
+ return null;
+}
+
+void test10664()
+{
+ int b;
+ int foo() { throw new Exception("blah"); }
+ assert(collectExceptionE(&foo, b));
+
+ int[] a = new int[3];
+ int goo() { return a[4]; }
+ collectExceptionR(&goo, b);
+}
+
+/* ================================ */
int main()
@@ -1424,12 +1436,9 @@ int main()
test14();
//test15();
test16();
- test17();
test18();
test19();
test20();
- test21();
- test22();
test23();
test24();
// test26();
@@ -1465,6 +1474,7 @@ int main()
test57();
test58();
test59();
+ test10664();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/test40.d b/gcc/testsuite/gdc.test/runnable/test40.d
index 528162b..2c1069d 100644
--- a/gcc/testsuite/gdc.test/runnable/test40.d
+++ b/gcc/testsuite/gdc.test/runnable/test40.d
@@ -2,7 +2,7 @@
// PERMUTE_ARGS:
// REQUIRED_ARGS:
-import std.stdio;
+import core.stdc.stdio;
import imports.test40a;
class Foo {
diff --git a/gcc/testsuite/gdc.test/runnable/test42.d b/gcc/testsuite/gdc.test/runnable/test42.d
index e887fae..57045ba 100644
--- a/gcc/testsuite/gdc.test/runnable/test42.d
+++ b/gcc/testsuite/gdc.test/runnable/test42.d
@@ -1,4 +1,4 @@
-/* RUNNABLE_PHOBOS_TEST
+/*
REQUIRED_ARGS:
TEST_OUTPUT:
---
@@ -13,10 +13,10 @@ C6test427test219FZ8__mixin11C
*/
module test42;
-import std.stdio;
+
import core.stdc.stdio;
-import std.string;
import core.memory;
+import core.vararg;
/***************************************************/
@@ -61,7 +61,7 @@ void test2()
void test3()
{
auto i = mixin("__LINE__");
- writefln("%d", i);
+ printf("%d\n", i);
assert(i == 63);
}
@@ -94,7 +94,8 @@ void test5()
}
/***************************************************/
-// Bug 1200. One case moved to deprecate1.d
+// https://issues.dlang.org/show_bug.cgi?id=1200
+// One case moved to deprecate1.d
void foo6a() {
do
@@ -162,8 +163,8 @@ void test8()
void test9()
{
- writeln(long.max.stringof);
- writeln(ulong.max.stringof);
+ //writeln(long.max.stringof);
+ //writeln(ulong.max.stringof);
assert(long.max.stringof == "9223372036854775807L");
assert(ulong.max.stringof == "18446744073709551615LU");
}
@@ -205,7 +206,7 @@ void test12()
assert((foo ~ cast(char[])"foo").length == foo.length + 1);
assert((cast(char[])"foo" ~ foo).length == foo.length + 1);
- printf("%d\n", (foo ~ cast(char[])"foo")[0].length);
+ printf("%zd\n", (foo ~ cast(char[])"foo")[0].length);
assert((foo ~ [cast(char[])"foo"]).length == foo.length + 1);
@@ -421,7 +422,7 @@ void test25()
int[10] arrayA = [0,1,2,3,4,5,6,7,8,9];
foreach(int i; arrayA)
{
- writeln(i);
+ printf("%d\n", i);
}
}
@@ -532,11 +533,11 @@ struct S35
void test35()
{ S35 s;
auto t = typeid(S35);
- writefln("s = %s", s);
- writefln("s = %s", t);
+ //writefln("s = %s", s);
+ //writefln("s = %s", t);
auto tis = cast(TypeInfo_Struct)t;
- writefln("s = %s", tis);
- writefln("s = %s", tis.xtoString);
+ //writefln("s = %s", tis);
+ //writefln("s = %s", tis.xtoString);
assert(tis.xtoString != null);
}
@@ -660,16 +661,6 @@ void test43()
/***************************************************/
-void test44()
-{
- ifloat f = 1.0fi;
-// f *= 2.0fi; // illegal but compiles
- writefln("%s", f);
-// assert(f == 0i);
-}
-
-/***************************************************/
-
int foo45(int i)
{
if(i==0){
@@ -685,7 +676,7 @@ void test45()
assert(foo45(0)==2);
try{
foo45(1);
- }catch{
+ }catch(Throwable){
return cast(void)0;
}
assert(0);
@@ -819,7 +810,7 @@ void test54()
string[] k=["adf","AsdfadSF","dfdsfassdf"];
foreach(d;k)
{
- printf("%.*s\n", d.length, d.ptr);
+ printf("%.*s\n", cast(int)d.length, d.ptr);
string foo() {assert(d!="");return d;}
func54(&foo);
func54(delegate string() {assert(d!="");return d;});
@@ -827,7 +818,7 @@ void test54()
}
/***************************************************/
-// bug 1767
+// https://issues.dlang.org/show_bug.cgi?id=1767
class DebugInfo
{
@@ -862,7 +853,7 @@ void test56()
void writecrossing(bool goal)
{
- writeln(goal?"escape":"return");
+ goal ? printf("escape\n") : printf("return\n");
}
void test57()
@@ -1313,15 +1304,15 @@ class C79
void test79()
{
C79 c = new C79();
- writeln(c.__vptr);
- writeln(c.__vptr[0]);
- writeln(cast(void*)c.classinfo);
+// writeln(c.__vptr);
+// writeln(c.__vptr[0]);
+// writeln(cast(void*)c.classinfo);
assert(c.__vptr[0] == cast(void*)c.classinfo);
- writeln(c.__monitor);
+// writeln(c.__monitor);
assert(c.__monitor == null);
synchronized (c)
{
- writeln(c.__monitor);
+// writeln(c.__monitor);
assert(c.__monitor !is null);
}
}
@@ -1396,7 +1387,7 @@ void test83()
void test84()
{
int[0][10] arr;
- printf("%u\n", &arr[9] - &arr[0]);
+ printf("%tu\n", &arr[9] - &arr[0]);
auto i = &arr[9] - &arr[0];
assert(i == 0);
}
@@ -1615,11 +1606,11 @@ void test96()
void test97()
{
const short[] ct = cast(short[]) [cast(byte)1, 1];
- writeln(ct);
+// writeln(ct);
assert(ct.length == 2 && ct[0] == 1 && ct[1] == 1);
short[] rt = cast(short[]) [cast(byte)1, cast(byte)1].dup;
- writeln(rt);
+// writeln(rt);
assert(rt.length == 1 && rt[0] == 257);
}
@@ -1751,7 +1742,7 @@ void test105()
{
Templ!(int).Type x;
auto s = Templ!(int).XXX;
- writeln(s);
+ printf("%.*s\n", cast(int)s.length, s.ptr);
assert(s == "i");
}
@@ -1793,7 +1784,7 @@ void test108()
void test109()
{
- double x[] = new double[1];
+ double[] x = new double[1];
assert(x[0] != 0);
}
@@ -1860,7 +1851,7 @@ struct VariantN
void bar(int value, int i)
{
- int args[2] = [ VariantN(value), VariantN(i) ];
+ int[2] args = [ VariantN(value), VariantN(i) ];
}
}
@@ -2100,7 +2091,7 @@ void test129()
}
/***************************************************/
-// 12725
+// https://issues.dlang.org/show_bug.cgi?id=12725
struct R12725(R : E[], E)
{
@@ -2118,7 +2109,7 @@ void test12725()
}
/***************************************************/
-// 12728
+// https://issues.dlang.org/show_bug.cgi?id=12728
struct Matrix12728(T, uint m, uint n = m, ubyte f = 0)
{
@@ -2226,7 +2217,7 @@ void test135()
void test136()
{
- struct S { int i[3]; }
+ struct S { int[3] i; }
enum S s = S(8);
const int i = s.i[2];
assert(i == 8);
@@ -2286,7 +2277,7 @@ void test140()
class Foo141 {
Foo141 next;
void start()
- in { assert (!next); } body
+ in { assert (!next); } do
{
void* p = cast(void*)this;
}
@@ -2426,7 +2417,7 @@ bool foo150()
}
/***************************************************/
-// 3521
+// https://issues.dlang.org/show_bug.cgi?id=3521
void crash(int x)
{
@@ -2724,7 +2715,7 @@ enum FwdEnum : int
}
/***************************************************/
-// 3740
+// https://issues.dlang.org/show_bug.cgi?id=3740
abstract class Address {
abstract int nameLen();
@@ -2848,12 +2839,6 @@ double[100_000] arr = 0.0;
/***************************************************/
-alias ireal BUG3919;
-alias typeof(BUG3919.init*BUG3919.init) ICE3919;
-alias typeof(BUG3919.init/BUG3919.init) ICE3920;
-
-/***************************************************/
-
struct S179 {
char a, b, c, d;
}
@@ -2935,7 +2920,7 @@ void test181()
}
/***************************************************/
-// 4042
+// https://issues.dlang.org/show_bug.cgi?id=4042
template isQObjectType(T)
{
@@ -3193,7 +3178,7 @@ void test197()
/***************************************************/
-void test198() // Bugzilla 4506
+void test198() // https://issues.dlang.org/show_bug.cgi?id=4506
{
int c = 1;
for (int k = 0; k < 2; k++) {
@@ -3204,7 +3189,7 @@ void test198() // Bugzilla 4506
/***************************************************/
-// Bugzilla 4514
+// https://issues.dlang.org/show_bug.cgi?id=4514
void g199(void delegate(void*, void*) d) { }
struct X199 {
@@ -3216,7 +3201,7 @@ struct X199 {
}
/***************************************************/
-// Bugzilla 4443
+// https://issues.dlang.org/show_bug.cgi?id=4443
struct Struct4443
{
@@ -3241,10 +3226,10 @@ void test200()
/***************************************************/
-// Bugzilla 2931
+// https://issues.dlang.org/show_bug.cgi?id=2931
struct Bug2931 {
- int val[3][4];
+ int[4][3] val;
}
struct Outer2931 {
@@ -3290,10 +3275,9 @@ void test201() {
/***************************************************/
// This was the original varargs example in std.vararg
-import core.vararg;
void foo202(int x, ...) {
- printf("%d arguments\n", _arguments.length);
+ printf("%zd arguments\n", _arguments.length);
for (int i = 0; i < _arguments.length; i++) {
int j = va_arg!(int)(_argptr);
printf("\t%d\n", j);
@@ -3302,7 +3286,7 @@ void foo202(int x, ...) {
}
void fooRef202(ref int x, ...) {
- printf("%d arguments\n", _arguments.length);
+ printf("%zd arguments\n", _arguments.length);
for (int i = 0; i < _arguments.length; i++) {
int j = va_arg!(int)(_argptr);
printf("\t%d\n", j);
@@ -3321,7 +3305,7 @@ void test202()
}
/***************************************************/
-// Bugzilla 1418
+// https://issues.dlang.org/show_bug.cgi?id=1418
class A203
{
@@ -3343,22 +3327,22 @@ void test203()
auto b = a.new B203;
auto c = new C203;
- writeln(a.tupleof); // prints: A
- writeln(b.tupleof); // prints: B main.A
- writeln(c.tupleof); // prints: C 0000
+// writeln(a.tupleof); // prints: A
+// writeln(b.tupleof); // prints: B main.A
+// writeln(c.tupleof); // prints: C 0000
assert(a.tupleof.length == 1 && a.tupleof[0] == 'A');
assert(b.tupleof.length == 1 && b.tupleof[0] == 'B');
assert(c.tupleof.length == 1 && c.tupleof[0] == 'C');
}
/***************************************************/
-// Bugzilla 4516
+// https://issues.dlang.org/show_bug.cgi?id=4516
struct A204 { B204 b; }
enum B204 { Z }
/***************************************************/
-// Bugzilla 4503
+// https://issues.dlang.org/show_bug.cgi?id=4503
class Collection205(T) { }
ICollection c;
@@ -3451,13 +3435,13 @@ template Bug6602B(U) {
enum bug6602Compiles = __traits(compiles, Bug6602A!short);
/***************************************************/
-// Bugzilla 3493
+// https://issues.dlang.org/show_bug.cgi?id=3493
const bar209 = foo209;
const int * foo209 = null;
/***************************************************/
-// 3418
+// https://issues.dlang.org/show_bug.cgi?id=3418
void test210()
{
@@ -3482,7 +3466,7 @@ void test212()
}
/***************************************************/
-// 4768
+// https://issues.dlang.org/show_bug.cgi?id=4768
struct A213 { B213 b; }
enum B213 { Z213 = 2 }
@@ -3515,7 +3499,6 @@ void test215()
{
class C {}
enum assocarrayliteral = Q!( [1:2] ).q.stringof;
- enum complex80 = Q!( 1+1.0i ).q.stringof;
//enum dottype = Q!( C.Object.toString ).q.stringof;
enum halt = 0.stringof; // ICE w/ -release
//enum remove = Q!( [1:2].remove(1) ).q.stringof;
@@ -3523,7 +3506,7 @@ void test215()
}
/***************************************************/
-// 4941
+// https://issues.dlang.org/show_bug.cgi?id=4941
template T216(_...) { alias _ T216; }
size_t mid216(size_t n) { return n/2; }
@@ -3558,7 +3541,7 @@ void test217()
}
/***************************************************/
-// 2954
+// https://issues.dlang.org/show_bug.cgi?id=2954
void test218()
{
@@ -3574,7 +3557,7 @@ void test218()
}
/***************************************************/
-// 2206
+// https://issues.dlang.org/show_bug.cgi?id=2206
template T219(U) {
class C {}
@@ -3593,7 +3576,7 @@ void test219()
/***************************************************/
-// 2206
+// https://issues.dlang.org/show_bug.cgi?id=2206
class D220 {}
@@ -3606,9 +3589,9 @@ void test220()
mixin T220!(int);
// all print 8
- writeln(T220!(int).C.classinfo.initializer.length);
- writeln(C.classinfo.initializer.length);
- writeln(D220.classinfo.initializer.length);
+// writeln(T220!(int).C.classinfo.initializer.length);
+// writeln(C.classinfo.initializer.length);
+// writeln(D220.classinfo.initializer.length);
auto c = new C; // segfault in _d_newclass
}
@@ -3677,7 +3660,7 @@ synchronized shared class C5105
}
/***************************************************/
-// 5145
+// https://issues.dlang.org/show_bug.cgi?id=5145
interface I221{
void bla();
@@ -3692,7 +3675,7 @@ class A221 : B221
{
final override I221 sync()
in { assert( valid ); }
- body
+ do
{
return null;
}
@@ -3702,7 +3685,7 @@ class B221 : J221
{
override I221 sync()
in { assert( valid ); }
- body
+ do
{
return null;
}
@@ -3729,7 +3712,7 @@ template Bug3276_b(alias W) {
alias Bug3276_b!(Bug3276) Bug3276_c;
/***************************************************/
-// 5294
+// https://issues.dlang.org/show_bug.cgi?id=5294
void foo222(int) {}
@@ -3757,7 +3740,7 @@ void test223()
}
/***************************************************/
-// 4379
+// https://issues.dlang.org/show_bug.cgi?id=4379
template BigTuple(U...) {
alias U BigTuple;
@@ -3777,7 +3760,7 @@ void test224()
}
/***************************************************/
-// 3681
+// https://issues.dlang.org/show_bug.cgi?id=3681
public final class A3681 {
private this() {
@@ -3876,7 +3859,7 @@ static assert(mixin(ice4390()) == ``);
static assert(mixin(ice4390()) == ``);
/***************************************************/
-// 190
+// https://issues.dlang.org/show_bug.cgi?id=190
alias int avocado;
void eat(avocado x225 = .x225);
@@ -3887,7 +3870,7 @@ void test225()
}
/***************************************************/
-// 5534
+// https://issues.dlang.org/show_bug.cgi?id=5534
void doStuff(byte start, byte end, uint increment = 1U) {
auto output = new byte[3];
@@ -3903,7 +3886,7 @@ void test226() {
}
/***************************************************/
-// 5536
+// https://issues.dlang.org/show_bug.cgi?id=5536
void test227()
{
@@ -3914,7 +3897,7 @@ void test227()
}
/***************************************************/
-// 4017
+// https://issues.dlang.org/show_bug.cgi?id=4017
struct _A
{
@@ -3926,7 +3909,7 @@ const A_SIZE = (A4017.sizeof);
alias _A A4017;
/***************************************************/
-// 5455
+// https://issues.dlang.org/show_bug.cgi?id=5455
void thrw(Data *s) {
throw new Exception("xxx");
@@ -3959,7 +3942,7 @@ struct Resp {
}
/**************************************/
-// 5571
+// https://issues.dlang.org/show_bug.cgi?id=5571
void test228() {
auto b = new bool;
@@ -3968,7 +3951,7 @@ void test228() {
}
/***************************************************/
-// 5572
+// https://issues.dlang.org/show_bug.cgi?id=5572
void doSynchronized() {
printf("In doSynchronized() 1: %p\n", cast(void*) global229);
@@ -3994,10 +3977,10 @@ void test229() {
/***************************************************/
-static immutable real negtab[14] =
+static immutable real[14] negtab =
[ 1e-4096L,1e-2048L,1e-1024L,1e-512L,1e-256L,1e-128L,1e-64L,1e-32L,
1e-16L,1e-8L,1e-4L,1e-2L,1e-1L,1.0L ];
-static immutable real postab[13] =
+static immutable real[13] postab =
[ 1e+4096L,1e+2048L,1e+1024L,1e+512L,1e+256L,1e+128L,1e+64L,1e+32L,
1e+16L,1e+8L,1e+4L,1e+2L,1e+1L ];
@@ -4095,7 +4078,7 @@ void bug5717()
}
/***************************************************/
-// 3086
+// https://issues.dlang.org/show_bug.cgi?id=3086
class X231 {
void a() {}
@@ -4115,7 +4098,7 @@ void test231() {
}
/***************************************************/
-// 4140
+// https://issues.dlang.org/show_bug.cgi?id=4140
const A232 = [1,2,3];
const B232 = A232[1..A232.length];
@@ -4133,7 +4116,7 @@ void test232()
}
/***************************************************/
-// 1389
+// https://issues.dlang.org/show_bug.cgi?id=1389
void test233()
{
@@ -4142,7 +4125,7 @@ void test233()
}
/***************************************************/
-// 5735
+// https://issues.dlang.org/show_bug.cgi?id=5735
struct A234 {}
@@ -4204,7 +4187,7 @@ void bug6184()
{
bool cmp(ref int[3] a, ref int[3] b)
{
- return a is b;
+ return a[] is b[];
}
static struct Ary
@@ -4224,7 +4207,7 @@ void bug6184()
}
/***************************************************/
-// 6229
+// https://issues.dlang.org/show_bug.cgi?id=6229
int test6229()
{
@@ -4288,13 +4271,13 @@ void test236()
/***************************************************/
-// 4460
+// https://issues.dlang.org/show_bug.cgi?id=4460
void test237()
{
foreach (s, i; [ "a":1, "b":2 ])
{
- writeln(s, i);
+ //writeln(s, i);
}
}
@@ -4327,7 +4310,7 @@ void test238()
}
/***************************************************/
-// 5239
+// https://issues.dlang.org/show_bug.cgi?id=5239
struct S239 { int x; }
@@ -4353,22 +4336,25 @@ void test6506() {
}
/***************************************************/
-// 6505
+// https://issues.dlang.org/show_bug.cgi?id=6505
double foo240() {
return 1.0;
}
void test240() {
- double a = foo240();
- double b = foo240();
- double x = a*a + a*a + a*a + a*a + a*a + a*a + a*a +
+ double a = void;
+ double b = void;
+ double x = void;
+ a = foo240();
+ b = foo240();
+ x = a*a + a*a + a*a + a*a + a*a + a*a + a*a +
a*b + a*b;
assert(x > 0);
}
/***************************************************/
-// 6563
+// https://issues.dlang.org/show_bug.cgi?id=6563
int foo6563(float a, float b, float c, float d, float e, float f, float g, float h)
{
@@ -4480,7 +4466,7 @@ void test6189() {
}
/***************************************************/
-// 6997
+// https://issues.dlang.org/show_bug.cgi?id=6997
long fun6997(long a,long b,long c)
{
@@ -4517,6 +4503,7 @@ void test6997()
auto x = S6997().foo();
}
+
/***************************************************/
ubyte foo7026(uint n) {
@@ -4584,7 +4571,7 @@ struct Point6881
}
/***************************************************/
-// 7212
+// https://issues.dlang.org/show_bug.cgi?id=7212
void foo7212(scope int delegate(int a) dg)
{
}
@@ -4612,7 +4599,7 @@ void test242()
}
/***************************************************/
-// 7290
+// https://issues.dlang.org/show_bug.cgi?id=7290
void foo7290a(alias dg)()
{
@@ -4634,11 +4621,13 @@ void test7290()
int add = 2;
scope dg = (int a) => a + add;
+ // This will break with -preview=dip1000 because a closure will no longer be allocated
assert(GC.addrOf(dg.ptr) == null);
foo7290a!dg();
foo7290b(dg);
- foo7290c(dg);
+ foo7290c(dg); // this will fail with -preview=dip1000 and @safe because a scope delegate gets
+ // assigned to @system delegate, but no closure was allocated
}
/***************************************************/
@@ -4651,7 +4640,7 @@ void test7367()
}
/***************************************************/
-// 7375
+// https://issues.dlang.org/show_bug.cgi?id=7375
class A7375 {}
class B7375(int i) : A7375 {}
@@ -4833,7 +4822,7 @@ void test243() {
}
/***************************************************/
-// 7742
+// https://issues.dlang.org/show_bug.cgi?id=7742
struct Foo7742 {
static immutable f = Foo7742(1, 2);
@@ -4855,7 +4844,7 @@ void test7742()
}
/***************************************************/
-// 7807
+// https://issues.dlang.org/show_bug.cgi?id=7807
interface Interface7807
{
@@ -4890,7 +4879,7 @@ void test7807()
}
/***************************************************/
-// 7815
+// https://issues.dlang.org/show_bug.cgi?id=7815
enum Closure {
Matrix
@@ -4985,7 +4974,7 @@ struct Foo7974
}
/***************************************************/
-// 4155
+// https://issues.dlang.org/show_bug.cgi?id=4155
float getnanf() { return float.nan; }
@@ -5000,7 +4989,7 @@ void test4155()
}
/***************************************************/
-// 7911
+// https://issues.dlang.org/show_bug.cgi?id=7911
struct Klass7911
{
@@ -5020,7 +5009,7 @@ void test7911()
}
/***************************************************/
-// 8429
+// https://issues.dlang.org/show_bug.cgi?id=8429
static if(true)
version = Foo8429;
@@ -5028,7 +5017,7 @@ static if(true)
version(Foo8429) {}
/***************************************************/
-// 8069
+// https://issues.dlang.org/show_bug.cgi?id=8069
interface I8069
{
@@ -5044,7 +5033,7 @@ struct A8069
}
/***************************************************/
-// 8095
+// https://issues.dlang.org/show_bug.cgi?id=8095
void bug8095(int p0, int *p1, int z, int edx, int *p4, int p5)
{
@@ -5068,7 +5057,7 @@ void test8095() {
}
/***************************************************/
-// 8091
+// https://issues.dlang.org/show_bug.cgi?id=8091
int solve1(int n) {
int a;
@@ -5114,7 +5103,7 @@ void test6189_2()
}
/***************************************************/
-// 8199
+// https://issues.dlang.org/show_bug.cgi?id=8199
version (D_InlineAsm_X86_64)
{
@@ -5126,6 +5115,8 @@ else version (D_InlineAsm_X86)
version = Check;
version (OSX)
enum Align = 0xC;
+// version (linux)
+// enum Align = 0xC;
}
void onFailure()
@@ -5167,6 +5158,21 @@ void test8199()
}
/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=13285
+void test13285()
+{
+ static struct S
+ {
+ ~this()
+ {
+ checkAlign();
+ }
+ }
+ S s; // correct alignment of RSP when calling ~this()
+ S(); // incorrect alignment
+}
+
+/***************************************************/
void test246()
{
@@ -5178,15 +5184,7 @@ void test246()
}
/***************************************************/
-
-double sqrt8454(double d) { return d/2; }
-void foo8454(cdouble m) {}
-void test8454() {
- foo8454(0 - sqrt8454(1.0) * 1i);
-}
-
-/***************************************************/
-// 8423
+// https://issues.dlang.org/show_bug.cgi?id=8423
struct S8423
{
@@ -5217,8 +5215,7 @@ public:
ubyte size = value < (0x7fU << 0 ) ? 1 :
value < (0x7fU << 14) ? 2 :
3;
- import std.stdio;
- writeln(size);
+ printf("%u\n", size);
assert(size == 2);
}
}
@@ -5336,7 +5333,7 @@ void test247()
}
/***************************************************/
-// 8340
+// https://issues.dlang.org/show_bug.cgi?id=8340
void test8340(){
byte[] ba = [1,2,3,4,5];
@@ -5356,7 +5353,7 @@ void test8340(){
}
/***************************************************/
-// 8376
+// https://issues.dlang.org/show_bug.cgi?id=8376
void test8376() {
int i = 0;
@@ -5392,7 +5389,7 @@ void test8987(){
}
/***************************************************/
-// 8796
+// https://issues.dlang.org/show_bug.cgi?id=8796
int* wrong8796(int* p)
{
@@ -5409,7 +5406,7 @@ void test8796()
}
/***************************************************/
-// 9171
+// https://issues.dlang.org/show_bug.cgi?id=9171
ulong bitcomb9171(ulong v)
{
@@ -5447,7 +5444,7 @@ void test9171()
}
/***************************************************/
-// 9248
+// https://issues.dlang.org/show_bug.cgi?id=9248
void test9248()
{
@@ -5458,7 +5455,7 @@ void test9248()
}
/***************************************************/
-// 14682
+// https://issues.dlang.org/show_bug.cgi?id=14682
void test14682a()
{
@@ -5562,8 +5559,9 @@ void test14682b()
{ auto x = [[[[]]]] ~ a3; static assert(is(typeof(x) == typeof(a3)[])); assert(x == r4b); } // fix
}
+
/***************************************************/
-// 9739
+// https://issues.dlang.org/show_bug.cgi?id=9739
class Foo9739
{
@@ -5580,7 +5578,7 @@ void test9739()
}
/***************************************************/
-// 6057
+// https://issues.dlang.org/show_bug.cgi?id=6057
void test6057()
{
enum Foo { A=1, B=2 }
@@ -5665,7 +5663,7 @@ void testreal_to_ulong()
static assert(false, "Test not implemented for this architecture");
auto v = r2ulong(adjust * 1.1);
- writefln("%s %s %s", adjust, v, u + u/10);
+ //writefln("%s %s %s", adjust, v, u + u/10);
//assert(v == 10145709240540253389UL);
}
@@ -5808,7 +5806,7 @@ void test251()
}
/***************************************************/
-// 9387
+// https://issues.dlang.org/show_bug.cgi?id=9387
void bug9387a(double x) { }
@@ -5866,10 +5864,15 @@ void test4414() {
assert(x == 7);
}
{
- auto x = bytes4414()[0..4];
+ auto u = bytes4414();
+ auto x = u[0..4];
if (x[0] != 7 || x[1] != 8 || x[2] != 9 || x[3] != 10)
assert(0);
}
+ assert(bytes4414()[0] == 7);
+ assert(bytes4414()[1] == 8);
+ assert(bytes4414()[2] == 9);
+ assert(bytes4414()[3] == 10);
}
/***************************************************/
@@ -5882,7 +5885,7 @@ void test9844() {
}
/***************************************************/
-// 10628
+// https://issues.dlang.org/show_bug.cgi?id=10628
abstract class B10628
{
@@ -5905,7 +5908,7 @@ void test10628()
}
/***************************************************/
-// 11265
+// https://issues.dlang.org/show_bug.cgi?id=11265
struct S11265
{
@@ -5956,8 +5959,6 @@ void test10633()
/***************************************************/
-import std.stdio;
-
void _assertEq (ubyte lhs, short rhs, string msg, string file, size_t line)
{
immutable result = lhs == rhs;
@@ -5966,9 +5967,9 @@ void _assertEq (ubyte lhs, short rhs, string msg, string file, size_t line)
{
string op = "==";
if(msg.length > 0)
- writefln(`_assertEq failed: [%s] is not [%s].`, lhs, rhs);
+ printf("_assertEq failed: [%u] is not [%d].\n", lhs, rhs);
else
- writefln(`_assertEq failed: [%s] is not [%s]: %s`, lhs, rhs, msg);
+ printf("_assertEq failed: [%u] is not [%d]: %.*s\n", lhs, rhs, cast(int)msg.length, msg.ptr);
}
assert(result);
@@ -5998,7 +5999,7 @@ void test10642()
}
/***************************************************/
-// 11581
+// https://issues.dlang.org/show_bug.cgi?id=11581
alias TT11581(T...) = T;
@@ -6036,7 +6037,7 @@ void test11581()
}
/***************************************************/
-// 7436
+// https://issues.dlang.org/show_bug.cgi?id=7436
void test7436()
{
@@ -6047,7 +6048,7 @@ void test7436()
}
/***************************************************/
-// 12138
+// https://issues.dlang.org/show_bug.cgi?id=12138
struct S12138
{
@@ -6064,7 +6065,7 @@ label:
}
/***************************************************/
-// 14430
+// https://issues.dlang.org/show_bug.cgi?id=14430
void setCookie(long x = 1L << 32L, string y = null){
assert(y.ptr is null);
@@ -6075,7 +6076,7 @@ void test14430(){
}
/***************************************************/
-// 14510
+// https://issues.dlang.org/show_bug.cgi?id=14510
alias Vector14510 = ulong[3];
@@ -6118,7 +6119,7 @@ double entropy2(double[] probs)
__gshared int x;
++x;
if (!p) continue;
- import std.math : log2;
+ import core.stdc.math : log2;
result -= p * log2(p);
}
return result;
@@ -6126,7 +6127,6 @@ double entropy2(double[] probs)
void test16530()
{
- import std.stdio;
if (entropy2([1.0, 0, 0]) != 0.0)
assert(0);
}
@@ -6144,9 +6144,42 @@ void test252()
}
/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7997
+
+void test7997()
+{
+ __gshared int[0] foos;
+ foreach (f; foos) {}
+}
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=5332
+
+int[0] arr5332;
+
+void test5332()
+{
+ auto a = arr5332;
+}
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=11742
+
+const int x11472 = void;
+
+static this() { x11472 = 10; }
+
+void test11472()
+{
+ assert(x11472 == 10);
+}
+
+
+/***************************************************/
int main()
{
+ checkAlign();
test1();
test2();
test3();
@@ -6188,7 +6221,6 @@ int main()
test41();
test42();
test43();
- test44();
test45();
test46();
test47();
@@ -6404,7 +6436,6 @@ int main()
test6189_2();
test8199();
test246();
- test8454();
test8423();
test8496();
test8840();
@@ -6443,8 +6474,11 @@ int main()
test16027();
test16530();
test252();
+ test7997();
+ test5332();
+ test11472();
+ test13285();
- writefln("Success");
+ printf("Success\n");
return 0;
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/test42a.d b/gcc/testsuite/gdc.test/runnable/test42a.d
index 0bb98ef..10c09b3 100644
--- a/gcc/testsuite/gdc.test/runnable/test42a.d
+++ b/gcc/testsuite/gdc.test/runnable/test42a.d
@@ -1,4 +1,10 @@
-// PERMUTE_ARGS:
+/*
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+Success
+---
+*/
module test42;
@@ -312,4 +318,3 @@ int main()
printf("Success\n");
return 0;
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/test435.d b/gcc/testsuite/gdc.test/runnable/test435.d
index 4dcabd1..700e9fd 100644
--- a/gcc/testsuite/gdc.test/runnable/test435.d
+++ b/gcc/testsuite/gdc.test/runnable/test435.d
@@ -1,3 +1,9 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
import core.stdc.stdio;
class A
@@ -65,7 +71,7 @@ void test1()
//------------------------------------------------------------------------------
-// bug 435.
+// https://issues.dlang.org/show_bug.cgi?id=435.
class B
{
int i;
@@ -90,7 +96,7 @@ void test2()
//------------------------------------------------------------------------------
-// bug 4905
+// https://issues.dlang.org/show_bug.cgi?id=4905
class C2
{
string x;
@@ -114,7 +120,7 @@ void test3()
//------------------------------------------------------------------------------
-// bug 4531 test case 2
+// https://issues.dlang.org/show_bug.cgi?id=4531 test case 2
class MyError : Exception
{
this(T...)(T msg)
@@ -139,5 +145,3 @@ void main()
test4();
printf("Success\n");
}
-
-
diff --git a/gcc/testsuite/gdc.test/runnable/test45.d b/gcc/testsuite/gdc.test/runnable/test45.d
index 49fa548..d36b378 100644
--- a/gcc/testsuite/gdc.test/runnable/test45.d
+++ b/gcc/testsuite/gdc.test/runnable/test45.d
@@ -1,5 +1,17 @@
-// EXTRA_SOURCES: imports/test45a.d imports/test45b.d
-// PERMUTE_ARGS:
+/*
+EXTRA_SOURCES: imports/test45a.d imports/test45b.d
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+foo()
+foo(int)
+foo()
+foo()
+foo(int)
+bar(t)
+bar(t,i)
+---
+*/
import imports.test45a;
import imports.test45b;
diff --git a/gcc/testsuite/gdc.test/runnable/test48.d b/gcc/testsuite/gdc.test/runnable/test48.d
index 827d681..36160e5 100644
--- a/gcc/testsuite/gdc.test/runnable/test48.d
+++ b/gcc/testsuite/gdc.test/runnable/test48.d
@@ -1,7 +1,7 @@
// EXTRA_SOURCES: imports/test48a.d
// PERMUTE_ARGS:
-import std.stdio;
+import core.stdc.stdio;
import imports.test48a;
void main()
@@ -16,28 +16,28 @@ void main()
printf("i = %d\n", i);
assert(i == 6);
- printf("a = %d %d %d\n", S.tupleof.offsetof);
+ printf("a = %zd %zd %zd\n", S.tupleof.offsetof);
auto o = S.tupleof.offsetof;
assert(o[0] == 0);
assert(o[1] == 4);
assert(o[2] == 8);
- printf("a = %d %d %d\n", S.tupleof[0].offsetof, S.tupleof[1].offsetof, S.tupleof[2].offsetof);
+ printf("a = %zd %zd %zd\n", S.tupleof[0].offsetof, S.tupleof[1].offsetof, S.tupleof[2].offsetof);
assert(S.tupleof[0].offsetof == 0);
assert(S.tupleof[1].offsetof == 4);
assert(S.tupleof[2].offsetof == 8);
auto offset0 = cast(void*)&s.tupleof[0] - cast(void*)&s;
- printf("offset0 = %d\n", offset0);
+ printf("offset0 = %td\n", offset0);
assert(offset0 == 0);
auto offset1 = cast(void*)&s.tupleof[1] - cast(void*)&s;
- printf("offset1 = %d\n", offset1);
+ printf("offset1 = %td\n", offset1);
assert(offset1 == 4);
auto offset2 = cast(void*)&s.tupleof[2] - cast(void*)&s;
- printf("offset2 = %d\n", offset2);
+ printf("offset2 = %td\n", offset2);
assert(offset2 == 8);
- int t1[S.tupleof.offsetof[1]];
+ int[S.tupleof.offsetof[1]] t1;
assert(t1.length == 4);
}
diff --git a/gcc/testsuite/gdc.test/runnable/test49.d b/gcc/testsuite/gdc.test/runnable/test49.d
index fc80d61..641d196 100644
--- a/gcc/testsuite/gdc.test/runnable/test49.d
+++ b/gcc/testsuite/gdc.test/runnable/test49.d
@@ -1,6 +1,13 @@
-// COMPILE_SEPARATELY
-// EXTRA_SOURCES: imports/test49a.d
-// PERMUTE_ARGS:
+/*
+COMPILE_SEPARATELY
+EXTRA_SOURCES: imports/test49a.d
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+static this()
+static ~this()
+---
+*/
import imports.test49a;
@@ -9,4 +16,3 @@ alias Foo!(int) foo;
void main()
{
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/test5.d b/gcc/testsuite/gdc.test/runnable/test5.d
index 7d9769d..a14b4b1 100644
--- a/gcc/testsuite/gdc.test/runnable/test5.d
+++ b/gcc/testsuite/gdc.test/runnable/test5.d
@@ -40,7 +40,7 @@ class bar : foo
int def(foo f)
{
- printf("def(%p), %p\n", f, (cast(int*)f)[0]);
+ printf("def(%p), %d\n", f, (cast(int*)f)[0]);
assert(f.testc(3) == 50);
assert(f.testd(7) == 54);
assert(f.testd(10) == 57);
@@ -49,7 +49,7 @@ int def(foo f)
void abc(bar b)
{
- printf("abc(%p), %p\n", b, (cast(int*)b)[3]);
+ printf("abc(%p), %d\n", b, (cast(int*)b)[3]);
def(b);
}
@@ -57,8 +57,8 @@ int main()
{
bar b = new bar();
- printf("b.size = x%x\n", b.classinfo.initializer.length);
- printf("bar.size = x%x\n", bar.classinfo.initializer.length);
+ printf("b.size = x%zx\n", b.classinfo.initializer.length);
+ printf("bar.size = x%zx\n", bar.classinfo.initializer.length);
assert(b.classinfo.initializer.length == bar.classinfo.initializer.length);
abc(b);
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/test52.d b/gcc/testsuite/gdc.test/runnable/test52.d
index 2a906d0..85b8d67 100644
--- a/gcc/testsuite/gdc.test/runnable/test52.d
+++ b/gcc/testsuite/gdc.test/runnable/test52.d
@@ -1,29 +1,36 @@
-// PERMUTE_ARGS:
+/*
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+count = 3
+---
+*/
-// 2311
+// https://issues.dlang.org/show_bug.cgi?id=2311
-extern(C)
+extern(C) int printf(const char*, ...);
+
+__gshared ulong count;
+
+shared static ~this()
{
- void exit(int);
- int printf(const char*, ...);
+ printf("count = %llu\n", count);
+ assert(count == 3);
}
-struct X()
+template X(uint idx)
{
- static this()
- {
- printf("this()\n");
- }
- static ~this()
- {
- printf("~this()\n");
- exit(0);
- }
+ static ~this()
+ {
+ assert(count == idx);
+ ++count;
+ }
}
-static ~this()
+void main()
{
- printf("g: ~this()\n");
+ // Instantiate module destructors in reverse order
+ alias x = X!(2);
+ alias y = X!(1);
+ alias z = X!(0);
}
-
-int main() { alias X!() x; return 1; }
diff --git a/gcc/testsuite/gdc.test/runnable/test5305.d b/gcc/testsuite/gdc.test/runnable/test5305.d
deleted file mode 100644
index ff52936..0000000
--- a/gcc/testsuite/gdc.test/runnable/test5305.d
+++ /dev/null
@@ -1,8 +0,0 @@
-// RUNNABLE_PHOBOS_TEST
-// https://issues.dlang.org/show_bug.cgi?id=5305
-
-import std.math;
-void map(real function(real) f) { }
-int main() { map(&sqrt); return 0; }
-
-
diff --git a/gcc/testsuite/gdc.test/runnable/test60.d b/gcc/testsuite/gdc.test/runnable/test60.d
deleted file mode 100644
index cfd92b2..0000000
--- a/gcc/testsuite/gdc.test/runnable/test60.d
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUNNABLE_PHOBOS_TEST
-import std.stdio;
-import std.algorithm;
-
-void test1()
-{
- int[] a = [1,2,3,4,5];
- writeln( remove!("a < 3")(a) );
-}
-
-void test2()
-{
- auto arr = [1,2,3,4,5];
- auto m = map!"a + 1"(filter!"a < 4"(arr));
-}
-
-void main()
-{
- test1();
- test2();
-
- writeln("Success");
-}
diff --git a/gcc/testsuite/gdc.test/runnable/test61.d b/gcc/testsuite/gdc.test/runnable/test61.d
index 6e09769..016e9a0 100644
--- a/gcc/testsuite/gdc.test/runnable/test61.d
+++ b/gcc/testsuite/gdc.test/runnable/test61.d
@@ -1,7 +1,7 @@
// PERMUTE_ARGS:
// EXTRA_SOURCES: imports/test61a.d
-// Bugzilla 6556
+// https://issues.dlang.org/show_bug.cgi?id=6556
debug=BUG;
diff --git a/gcc/testsuite/gdc.test/runnable/test6795.d b/gcc/testsuite/gdc.test/runnable/test6795.d
new file mode 100644
index 0000000..7e44fd4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test6795.d
@@ -0,0 +1,26 @@
+// https://issues.dlang.org/show_bug.cgi?id=6795
+void check6795()
+{
+ enum int[] array = [0];
+ // PostExp
+ assert(array[0]++ == 0);
+ assert(array[0]-- == 0);
+ // PreExp
+ assert(++array[0] == 1);
+ assert(--array[0] == -1);
+ // BinAssignExp
+ assert((array[0] += 3) == 3);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=21312
+void check21312()
+{
+ auto p = &[123][0];
+ assert(*p == 123);
+}
+
+void main()
+{
+ check6795();
+ check21312();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test711.d b/gcc/testsuite/gdc.test/runnable/test711.d
new file mode 100644
index 0000000..b9fae4e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test711.d
@@ -0,0 +1,51 @@
+// https://issues.dlang.org/show_bug.cgi?id=711
+string result;
+
+template Mixer()
+{
+ override void test()
+ {
+ result ~= "A";
+ }
+}
+
+class Foo
+{
+ void test()
+ {
+ result ~= "B";
+ }
+}
+
+class Bar : Foo
+{
+ mixin Mixer!() mixer;
+ override void test()
+ {
+ result ~= "C";
+ mixer.test();
+ }
+}
+
+class Bar2 : Foo
+{
+ override void test()
+ {
+ result ~= "C";
+ mixer.test();
+ }
+ mixin Mixer!() mixer;
+}
+
+void main()
+{
+ Bar f = new Bar();
+ f.test();
+ assert(result == "CA");
+
+ result = "";
+
+ Bar2 f2 = new Bar2();
+ f2.test();
+ assert(result == "CA");
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test7452.d b/gcc/testsuite/gdc.test/runnable/test7452.d
index cc04529..de591f3 100644
--- a/gcc/testsuite/gdc.test/runnable/test7452.d
+++ b/gcc/testsuite/gdc.test/runnable/test7452.d
@@ -1,3 +1,9 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
import core.stdc.stdio : printf;
//------------------------------------------------------------------------------
@@ -71,5 +77,3 @@ int main()
printf("Success\n");
return 0;
}
-
-
diff --git a/gcc/testsuite/gdc.test/runnable/test7511.d b/gcc/testsuite/gdc.test/runnable/test7511.d
index 0d19f54..bb87995 100644
--- a/gcc/testsuite/gdc.test/runnable/test7511.d
+++ b/gcc/testsuite/gdc.test/runnable/test7511.d
@@ -1,7 +1,13 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
extern(C) int printf(const char*, ...);
/**********************************/
-// 7511
+// https://issues.dlang.org/show_bug.cgi?id=7511
struct S7511(T)
{
@@ -186,7 +192,7 @@ void test7511d()
}
/**********************************/
-// 9952
+// https://issues.dlang.org/show_bug.cgi?id=9952
@system void writeln9952(int) {} // impure throwable
@@ -214,7 +220,7 @@ void test9952()
}
/**********************************/
-// 10373
+// https://issues.dlang.org/show_bug.cgi?id=10373
template isMutable10373(T)
{
@@ -294,7 +300,7 @@ void test10373()
}
/**********************************/
-// 10329
+// https://issues.dlang.org/show_bug.cgi?id=10329
auto foo10329(T)(T arg)
{
@@ -326,7 +332,7 @@ void test10329() pure nothrow @safe
}
/**********************************/
-// 11896
+// https://issues.dlang.org/show_bug.cgi?id=11896
class Foo11896a(T = int)
{
@@ -393,7 +399,7 @@ void test11896c()
}
/**********************************/
-// 12392
+// https://issues.dlang.org/show_bug.cgi?id=12392
void f12392(T)() {}
alias fa12392 = f12392;
diff --git a/gcc/testsuite/gdc.test/runnable/test7932.d b/gcc/testsuite/gdc.test/runnable/test7932.d
index 245cf17..22aa279 100644
--- a/gcc/testsuite/gdc.test/runnable/test7932.d
+++ b/gcc/testsuite/gdc.test/runnable/test7932.d
@@ -1,6 +1,6 @@
-// 7932
+// https://issues.dlang.org/show_bug.cgi?id=7932
-import std.stdio;
+import core.stdc.stdio;
size_t N;
@@ -13,7 +13,7 @@ class C
cast(void*) this, &n, n);
assert (N == n);
}
- body
+ do
{
int dummy;
//printf("\n");
diff --git a/gcc/testsuite/gdc.test/runnable/test8.d b/gcc/testsuite/gdc.test/runnable/test8.d
index 4927bbc..7d66eb6 100644
--- a/gcc/testsuite/gdc.test/runnable/test8.d
+++ b/gcc/testsuite/gdc.test/runnable/test8.d
@@ -1,3 +1,9 @@
+/*
+TEST_OUTPUT:
+---
+runnable/test8.d(261): Deprecation: identity comparison of static arrays implicitly coerces them to slices, which are compared by reference
+---
+*/
module testxxx8;
@@ -167,28 +173,6 @@ void test8()
/***********************************/
-void test9()
-{
- ireal imag = 2.5i;
- //printf ("test of imag*imag = %Lf\n",imag*imag);
- real f = imag * imag;
- assert(f == -6.25);
-}
-
-/***********************************/
-
-void test10()
-{
- creal z = 1 + 2.5i;
- real e = z.im;
-
- printf ("e = %Lf\n", e);
- assert(e == 2.5);
-}
-
-
-/***********************************/
-
class Foo11
{
public:
@@ -316,11 +300,11 @@ void test17()
string s;
s = passString();
- printf("passString() = %.*s\n", s.length, s.ptr);
+ printf("passString() = %.*s\n", cast(int)s.length, s.ptr);
assert(s == "First stringConcatenated with second");
s = butThisWorks();
- printf("butThisWorks() = %.*s\n", s.length, s.ptr);
+ printf("butThisWorks() = %.*s\n", cast(int)s.length, s.ptr);
assert(s == "Third stringConcatenated with fourth");
}
@@ -453,7 +437,7 @@ in
out (result)
{
}
-body
+do
{ int i = 5;
while (i)
@@ -607,21 +591,6 @@ void test34()
assert(b[i][j] == 16);
}
-
-/***********************************/
-
-void test35()
-{
- ifloat b = cast(ifloat)1i;
- assert(b == 1.0i);
-
- ifloat c = 2fi;
- assert(c == 2.0i);
-
- c = 0fi;
- assert(c == 0i);
-}
-
/***********************************/
string itoa(int i)
@@ -646,7 +615,7 @@ void test36()
{
string s = testa36(26, 47, "a", "b", "c");
- printf("s = '%.*s'\n", s.length, s.ptr);
+ printf("s = '%.*s'\n", cast(int)s.length, s.ptr);
assert(s == "string 0;26string 1;47string 2;26string 3;");
}
@@ -668,7 +637,7 @@ void test37()
void test38()
{
int n = atoi("1");
- static char flags[8192 + 1];
+ static char[8192 + 1] flags;
long i, k;
int count = 0;
@@ -698,7 +667,7 @@ void test38()
}
catch(Throwable)
{
- printf("Exception: %d\n", k);
+ printf("Exception: %lld\n", k);
assert(0);
}
}
@@ -776,21 +745,6 @@ void test42()
/***********************************/
-void test43()
-{
- creal C,Cj;
- real y1,x1;
-
- C = x1 + y1*1i + Cj;
- C = 1i*y1 + x1 + Cj;
- C = Cj + 1i*y1 + x1;
- C = y1*1i + Cj + x1;
- C = 1i*y1 + Cj;
- C = Cj + 1i*y1;
-}
-
-/***********************************/
-
int x44;
class A44 {
@@ -883,46 +837,6 @@ void test50()
/***********************************/
-/+
-void foo51(creal a)
-{
- writeln(a);
- assert(a == -8i);
-}
-
-void test51()
-{
- cdouble a = (2-2i)*(2-2i);
-
- // This fails
- writeln(a);
- assert(a == -8i);
-
- // This works
- writeln((2-2i)*(2-2i));
-
- // This fails
- foo51((2-2i)*(2-2i));
-}
-+/
-
-void foo51(creal a)
-{
- assert(a == -8i);
-}
-
-void test51()
-{
- assert((2-2i)*(2-2i) == -8i);
-
- cdouble a = (2-2i)*(2-2i);
- assert(a == -8i);
-
- foo51((2-2i)*(2-2i));
-}
-
-/***********************************/
-
int main()
{
test1();
@@ -933,8 +847,6 @@ int main()
test6();
test7();
test8();
- test9();
- test10();
test11();
test12();
test13();
@@ -956,21 +868,18 @@ int main()
test32();
test33();
test34();
- test35();
test36();
test37();
test38();
test39();
test40();
test42();
- test43();
test44();
test45();
test46();
test48();
test49();
test50();
- test51();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/test809.d b/gcc/testsuite/gdc.test/runnable/test809.d
new file mode 100644
index 0000000..efe4a37
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test809.d
@@ -0,0 +1,13 @@
+// https://issues.dlang.org/show_bug.cgi?id=809
+void test(lazy int dg)
+{
+ int delegate() dg_ = &dg;
+ assert(dg_() == 7);
+ assert(dg == dg_());
+}
+
+void main()
+{
+ int a = 7;
+ test(a);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test8544.d b/gcc/testsuite/gdc.test/runnable/test8544.d
index 7c47e86..0b8b86b 100644
--- a/gcc/testsuite/gdc.test/runnable/test8544.d
+++ b/gcc/testsuite/gdc.test/runnable/test8544.d
@@ -1,6 +1,6 @@
// EXECUTE_ARGS: foo bar doo
// PERMUTE_ARGS:
-import std.stdio;
+import core.stdc.stdio;
import std.conv;
import core.runtime;
diff --git a/gcc/testsuite/gdc.test/runnable/test9259.d b/gcc/testsuite/gdc.test/runnable/test9259.d
index f870f63..abad02b 100644
--- a/gcc/testsuite/gdc.test/runnable/test9259.d
+++ b/gcc/testsuite/gdc.test/runnable/test9259.d
@@ -1,4 +1,5 @@
-// PERMUTE_ARGS: -inline -release -g -O -d -dw -de
+// REQUIRED_ARGS: -de
+// PERMUTE_ARGS: -inline -release -g -O
void test(int*[] arr...)
{
diff --git a/gcc/testsuite/gdc.test/runnable/test9271.d b/gcc/testsuite/gdc.test/runnable/test9271.d
index 3ce7fc8..b10b575 100644
--- a/gcc/testsuite/gdc.test/runnable/test9271.d
+++ b/gcc/testsuite/gdc.test/runnable/test9271.d
@@ -1,5 +1,5 @@
// PERMUTE_ARGS:
-
+// EXTRA_FILES: imports/test9271a.d
import algorithm = imports.test9271a;
bool any(alias predicate, Range)(Range range)
diff --git a/gcc/testsuite/gdc.test/runnable/testCopyCtor.d b/gcc/testsuite/gdc.test/runnable/testCopyCtor.d
new file mode 100644
index 0000000..9d86bdc
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/testCopyCtor.d
@@ -0,0 +1,159 @@
+string result;
+
+struct A
+{
+ this(ref A rhs)
+ {
+ result ~= "A";
+ }
+ this(ref immutable A rhs)
+ {
+ result ~= "B";
+ }
+ this(ref const A rhs)
+ {
+ result ~= "C";
+ }
+ this(ref A rhs) immutable
+ {
+ result ~= "D";
+ }
+ this(ref const A rhs) shared
+ {
+ result ~= "E";
+ }
+ this(ref A rhs) shared
+ {
+ result ~= "F";
+ }
+ this(ref shared A rhs) immutable
+ {
+ result ~= "G";
+ }
+ this(ref shared A rhs) shared
+ {
+ result ~= "H";
+ }
+}
+
+// copy constructor correctly uses function declaration overload resolution
+void test1()
+{
+ result = "";
+ A a;
+ A a1 = a;
+ immutable A a2 = a;
+ const A a3 = a2;
+ shared A a4 = a3;
+ A a5 = a3;
+ assert(result == "ADBEC");
+}
+
+// copy constructor has priority over alias this
+struct B
+{
+ B fun(immutable B)
+ {
+ return B();
+ }
+
+ this(ref immutable B rhs)
+ {
+ result ~= "A";
+ }
+ alias fun this;
+}
+
+void test2()
+{
+ result = "";
+ immutable B a;
+ B a1 = a;
+ assert(result == "A");
+}
+
+// arguments and return values correctly call the copy constructor
+shared(A) fun(A x)
+{
+ return x;
+}
+
+immutable(A) fun2(shared A x)
+{
+ return x;
+}
+
+void test3()
+{
+ result = "";
+ A a1;
+ shared A a2 = fun(a1);
+ immutable A a3 = fun2(a2);
+ assert(result == "AFHG");
+}
+
+// nested structs
+int fun()
+{
+ int x = 1;
+ struct A
+ {
+ struct B
+ {
+ int x2 = 2;
+ }
+
+ B b;
+ int x1;
+
+ this(int x)
+ {
+ this.x1 = x;
+ b = B(3);
+ }
+ this(ref A rhs)
+ {
+ this.x1 = rhs.x1 + rhs.b.x2 + x;
+ }
+ }
+
+ A a = A(2);
+ A b = a;
+ return b.x1;
+}
+
+void test4()
+{
+ assert(fun() == 6);
+}
+
+// generated copy constructor
+struct X
+{
+ this(ref inout(X) rhs) inout
+ {
+ result ~= "A";
+ }
+}
+
+struct Y
+{
+ X a;
+}
+
+void test5()
+{
+ result = "";
+ Y b1;
+ Y b2 = b1;
+ assert(result == "A");
+}
+
+void main()
+{
+ test1();
+ test2();
+ test3();
+ test4();
+ test5();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test_dip1006.d b/gcc/testsuite/gdc.test/runnable/test_dip1006.d
new file mode 100644
index 0000000..c785e21
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test_dip1006.d
@@ -0,0 +1,38 @@
+// REQUIRED_ARGS: -check=in=off -check=out=off -check=invariant=off
+// PERMUTE_ARGS:
+class C
+{
+ int foo(int a)
+ in { assert(a != 0); } // skipped
+ out(res) { assert(res != 0); } // skipped
+ do
+ {
+ return a;
+ }
+
+ invariant // skipped
+ {
+ assert(false);
+ }
+
+ void bar(int a)
+ {
+ assert(a != 0); // triggered
+ }
+}
+
+void main()
+{
+ import core.exception : AssertError;
+
+ auto c = new C;
+ c.foo(0);
+
+ bool catched;
+ try
+ c.bar(0);
+ catch (AssertError e)
+ catched = true;
+ if (!catched)
+ assert(0);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test_dip1006b.d b/gcc/testsuite/gdc.test/runnable/test_dip1006b.d
new file mode 100644
index 0000000..e167768
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test_dip1006b.d
@@ -0,0 +1,35 @@
+// REQUIRED_ARGS: -check=in=off -check=invariant=off
+// PERMUTE_ARGS:
+class C
+{
+ int foo(int a)
+ in { assert(a != 0); } // skipped
+ out(res) { assert(res != 0, "out"); } // triggered
+ do
+ {
+ return a;
+ }
+
+ invariant // skipped
+ {
+ assert(false);
+ }
+}
+
+void main()
+{
+ import core.exception : AssertError;
+
+ auto c = new C;
+ bool catched;
+ try
+ c.foo(0);
+ catch (AssertError e)
+ {
+ assert(e.msg == "out");
+ catched = e.msg == "out";
+ }
+
+ if (!catched)
+ assert(0);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/testaa.d b/gcc/testsuite/gdc.test/runnable/testaa.d
index 34cc705..75d5414 100644
--- a/gcc/testsuite/gdc.test/runnable/testaa.d
+++ b/gcc/testsuite/gdc.test/runnable/testaa.d
@@ -1,4 +1,3 @@
-// RUNNABLE_PHOBOS_TEST
// PERMUTE_ARGS: -fPIC
/* Test associative arrays */
@@ -7,11 +6,10 @@ extern(C) int printf(const char*, ...);
extern(C) int memcmp(const void *s1, const void *s2, size_t n);
import core.memory; // for GC.collect
-import std.random; // for uniform random numbers
/************************************************/
-int nametable[char[]];
+int[char[]] nametable;
void insert(string name, int value)
{
@@ -272,9 +270,9 @@ struct S12
void test12()
{
S12[] x;
- printf("size %d\n",S12.sizeof);
- printf("align %d\n",S12.alignof);
- printf("offset %d\n",S12.description.offsetof);
+ printf("size %zd\n",S12.sizeof);
+ printf("align %zd\n",S12.alignof);
+ printf("offset %zd\n",S12.description.offsetof);
for (int i=0;i<3;i++) {
S12 s;
@@ -294,8 +292,8 @@ void test12()
x ~= s;
*/
GC.collect();
- printf("%.*s\n",x[0].font_face.length,x[0].font_face.ptr);
- printf("%.*s\n",x[1].font_face.length,x[1].font_face.ptr);
+ printf("%.*s\n", cast(int)x[0].font_face.length, x[0].font_face.ptr);
+ printf("%.*s\n", cast(int)x[1].font_face.length, x[1].font_face.ptr);
}
@@ -316,7 +314,7 @@ void test13()
string[] key = array.keys;
assert(key.length==3);
- bool have[3];
+ bool[3] have;
assert(!have[0]);
assert(!have[1]);
@@ -424,13 +422,9 @@ void test16()
{
int[int] aa;
- Random gen;
for (int i = 0; i < 50000; i++)
{
- int key = uniform(0, int.max, gen);
- int value = uniform(0, int.max, gen);
-
- aa[key] = value;
+ aa[i] = i;
}
int[] keys = aa.keys;
@@ -442,7 +436,7 @@ void test16()
assert(k in aa);
j += aa[k];
}
- printf("test16 = %d\n", j);
+ assert(j == 1249975000);
int m;
foreach (k, v; aa)
@@ -471,10 +465,7 @@ void test16()
for (int i = 0; i < 1000; i++)
{
- int key2 = uniform(0, int.max, gen);
- int value2 = uniform(0, int.max, gen);
-
- aa[key2] = value2;
+ aa[i] = i;
}
foreach(k; aa)
{
@@ -494,7 +485,7 @@ void dummy17()
{
}
-int bb17[string];
+int[string] bb17;
int foo17()
{
@@ -558,14 +549,14 @@ void test19()
printf("%d\n", keys[1]);
auto vs = aa.values;
- printf("%.*s\n", vs[0].length, vs[0].ptr);
- printf("%.*s\n", vs[1].length, vs[1].ptr);
+ printf("%.*s\n", cast(int)vs[0].length, vs[0].ptr);
+ printf("%.*s\n", cast(int)vs[1].length, vs[1].ptr);
string aavalue_typeid = typeid(typeof(aa.values)).toString();
- printf("%.*s\n", aavalue_typeid.length, aavalue_typeid.ptr);
+ printf("%.*s\n", cast(int)aavalue_typeid.length, aavalue_typeid.ptr);
- printf("%.*s\n", aa[3].length, aa[3].ptr);
- printf("%.*s\n", aa[4].length, aa[4].ptr);
+ printf("%.*s\n", cast(int)aa[3].length, aa[3].ptr);
+ printf("%.*s\n", cast(int)aa[4].length, aa[4].ptr);
}
/************************************************/
@@ -582,14 +573,14 @@ void test20()
printf("%d\n", keys[1]);
auto values = aa.values;
- printf("%.*s\n", values[0].length, values[0].ptr);
- printf("%.*s\n", values[1].length, values[1].ptr);
+ printf("%.*s\n", cast(int)values[0].length, values[0].ptr);
+ printf("%.*s\n", cast(int)values[1].length, values[1].ptr);
string aavalue_typeid = typeid(typeof(aa.values)).toString();
- printf("%.*s\n", aavalue_typeid.length, aavalue_typeid.ptr);
+ printf("%.*s\n", cast(int)aavalue_typeid.length, aavalue_typeid.ptr);
- printf("%.*s\n", aa[3].length, aa[3].ptr);
- printf("%.*s\n", aa[4].length, aa[4].ptr);
+ printf("%.*s\n", cast(int)aa[3].length, aa[3].ptr);
+ printf("%.*s\n", cast(int)aa[4].length, aa[4].ptr);
}
/************************************************/
@@ -783,7 +774,7 @@ void test4826c()
}
/************************************************/
-// 5131
+// https://issues.dlang.org/show_bug.cgi?id=5131
struct ICE5131
{
@@ -799,7 +790,7 @@ void test5131()
}
/************************************************/
-// 6178
+// https://issues.dlang.org/show_bug.cgi?id=6178
bool test6178a()
{
@@ -1036,7 +1027,7 @@ void test6178x()
}
/************************************************/
-// 10595
+// https://issues.dlang.org/show_bug.cgi?id=10595
struct S10595
{
@@ -1073,14 +1064,13 @@ void test10595()
Wrap10595[int] wrap;
wrap[0] = Wrap10595();
- wrap[0] = 0; // note: using 'alias this' to assign
assert(wrap[0].s.test()); // failure
}
}
/************************************************/
-// 10970
+// https://issues.dlang.org/show_bug.cgi?id=10970
struct RefCounted10970(T) //if (!is(T == class))
{
@@ -1119,7 +1109,7 @@ void test10970()
}
/************************************************/
-// 6433
+// https://issues.dlang.org/show_bug.cgi?id=6433
void test6433()
{
@@ -1138,7 +1128,7 @@ void test6433()
}
/************************************************/
-// 6612
+// https://issues.dlang.org/show_bug.cgi?id=6612
void test6612()
{
@@ -1150,7 +1140,7 @@ void test6612()
}
/************************************************/
-// 7365
+// https://issues.dlang.org/show_bug.cgi?id=7365
struct TickDuration
{
@@ -1197,7 +1187,7 @@ void test6799()
}
/************************************************/
-// 11359
+// https://issues.dlang.org/show_bug.cgi?id=11359
void test11359()
{
@@ -1213,7 +1203,7 @@ void test11359()
}
/************************************************/
-// 11730
+// https://issues.dlang.org/show_bug.cgi?id=11730
struct SysTime11730
{
@@ -1246,7 +1236,7 @@ void test11730()
}
/************************************************/
-// 14089
+// https://issues.dlang.org/show_bug.cgi?id=14089
struct S14089
{
@@ -1263,7 +1253,7 @@ void test14089()
}
/************************************************/
-// 14144
+// https://issues.dlang.org/show_bug.cgi?id=14144
struct JSON14144
{
@@ -1291,7 +1281,7 @@ void test14144()
}
/************************************************/
-// 14321
+// https://issues.dlang.org/show_bug.cgi?id=14321
void test14321()
{
@@ -1330,6 +1320,20 @@ void test14321()
}
/************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19112
+
+void test19112()
+{
+ int[int[1]] aa;
+ aa[[2]] = 1;
+ assert([2] in aa);
+
+ int[int[]] aa2 = [[1, 2, 3]: 4];
+ int[3] k = [1, 2, 3];
+ assert(*(k in aa2) == 4);
+}
+
+/************************************************/
int main()
{
@@ -1380,6 +1384,7 @@ int main()
test11730();
test14089();
test14321();
+ test19112();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/testaa2.d b/gcc/testsuite/gdc.test/runnable/testaa2.d
index 17de167..ba8ceec 100644
--- a/gcc/testsuite/gdc.test/runnable/testaa2.d
+++ b/gcc/testsuite/gdc.test/runnable/testaa2.d
@@ -1,16 +1,26 @@
-// RUNNABLE_PHOBOS_TEST
-// PERMUTE_ARGS:
+/*
+RUNNABLE_PHOBOS_TEST
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+foo()
+foo() 2
+foo() 3
+foo() 4
+Success
+---
+*/
extern(C) int printf(const char*, ...);
/************************************************/
-int a[string];
+int[string] a;
size_t foo(immutable char [3] s)
{
printf("foo()\n");
- int b[string];
+ int[string] b;
string[] key;
int[] value;
printf("foo() 2\n");
@@ -23,7 +33,7 @@ size_t foo(immutable char [3] s)
void foo2()
{
- int c[string];
+ int[string] c;
string[] key;
int[] value;
int i;
@@ -51,10 +61,9 @@ void foo2()
value = c.values;
assert(value.length == 2);
- for (i = 0; i < key.length; i++)
- {
- printf("c[\"%.*s\"] = %d\n", key[i].length, key[i].ptr, value[i]);
- }
+ const fooIndex = key[1] == "foo";
+ assert(key[fooIndex] == "foo" && value[fooIndex] == 3);
+ assert(key[1 - fooIndex] == "bar" && value[1 - fooIndex] == 4);
assert("foo" in c);
c.remove("foo");
@@ -70,7 +79,6 @@ void foo2()
void testaa()
{
size_t i = foo("abc");
- printf("i = %d\n", i);
assert(i == 0);
foo2();
@@ -107,7 +115,7 @@ void test4523()
}
/************************************************/
-// 3825
+// https://issues.dlang.org/show_bug.cgi?id=3825
import std.math; // necessary for ^^=
void test3825()
@@ -257,7 +265,7 @@ void test3825x()
}
/************************************************/
-// 10106
+// https://issues.dlang.org/show_bug.cgi?id=10106
struct GcPolicy10106 {}
diff --git a/gcc/testsuite/gdc.test/runnable/testaa3.d b/gcc/testsuite/gdc.test/runnable/testaa3.d
index 3e3ae96..4aac1fb 100644
--- a/gcc/testsuite/gdc.test/runnable/testaa3.d
+++ b/gcc/testsuite/gdc.test/runnable/testaa3.d
@@ -315,7 +315,7 @@ int[int] testRetx()
void aafunc(int[int] aa) {}
/***************************************************/
-// 12214
+// https://issues.dlang.org/show_bug.cgi?id=12214
void test12214() pure nothrow
{
@@ -324,7 +324,8 @@ void test12214() pure nothrow
}
/***************************************************/
-// 12220 & 12221
+// https://issues.dlang.org/show_bug.cgi?id=12220
+// https://issues.dlang.org/show_bug.cgi?id=12221
void test12220()
{
@@ -338,7 +339,7 @@ void test12220()
}
/***************************************************/
-// 12403
+// https://issues.dlang.org/show_bug.cgi?id=12403
void test12403()
{
diff --git a/gcc/testsuite/gdc.test/runnable/testabi.d b/gcc/testsuite/gdc.test/runnable/testabi.d
deleted file mode 100644
index c50dfbd..0000000
--- a/gcc/testsuite/gdc.test/runnable/testabi.d
+++ /dev/null
@@ -1,926 +0,0 @@
-// PERMUTE_ARGS: -release -g
-
-version(Windows) {}
-else version(X86_64)
-{
- /* uncomment to enable tests! */
- //version = Run_X86_64_Tests;
-}
-
-extern (C) int printf(const char*, ...);
-
-template tuple(A...) { alias A tuple; }
-
-alias byte B;
-alias short S;
-alias int I;
-alias long L;
-alias float F;
-alias double D;
-alias real R;
-
-// Single Type
-
-struct b { B a; }
-struct bb { B a,b; }
-struct bbb { B a,b,c; }
-struct bbbb { B a,b,c,d; }
-struct bbbbb { B a,b,c,d, e; }
-struct b6 { B a,b,c,d, e,f; }
-struct b7 { B a,b,c,d, e,f,g; }
-struct b8 { B a,b,c,d, e,f,g,h; }
-struct b9 { B a,b,c,d, e,f,g,h, i; }
-struct b10 { B a,b,c,d, e,f,g,h, i,j; }
-struct b11 { B a,b,c,d, e,f,g,h, i,j,k; }
-struct b12 { B a,b,c,d, e,f,g,h, i,j,k,l; }
-struct b13 { B a,b,c,d, e,f,g,h, i,j,k,l, m; }
-struct b14 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n; }
-struct b15 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o; }
-struct b16 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p; }
-struct b17 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p, q; }
-struct b18 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p, q,r; }
-struct b19 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p, q,r,s; }
-struct b20 { B a,b,c,d, e,f,g,h, i,j,k,l, m,n,o,p, q,r,s,t;}
-
-struct s { S a; }
-struct ss { S a,b; }
-struct sss { S a,b,c; }
-struct ssss { S a,b,c,d; }
-struct sssss { S a,b,c,d, e; }
-struct s6 { S a,b,c,d, e,f; }
-struct s7 { S a,b,c,d, e,f,g; }
-struct s8 { S a,b,c,d, e,f,g,h; }
-struct s9 { S a,b,c,d, e,f,g,h, i; }
-struct s10 { S a,b,c,d, e,f,g,h, i,j;}
-
-struct i { I a; } struct l { L a; }
-struct ii { I a,b; } struct ll { L a,b; }
-struct iii { I a,b,c; } struct lll { L a,b,c; }
-struct iiii { I a,b,c,d; } struct llll { L a,b,c,d; }
-struct iiiii { I a,b,c,d,e; } struct lllll { L a,b,c,d,e; }
-
-struct f { F a; } struct d { D a; }
-struct ff { F a,b; } struct dd { D a,b; }
-struct fff { F a,b,c; } struct ddd { D a,b,c; }
-struct ffff { F a,b,c,d; } struct dddd { D a,b,c,d; }
-struct fffff { F a,b,c,d,e; } struct ddddd { D a,b,c,d,e; }
-
-// Mixed Size
-
-struct js { I a; S b; }
-struct iss { I a; S b,c; }
-struct si { S a; I b; }
-struct ssi { S a,b; I c; }
-struct sis { S a; I b; S c; }
-
-struct ls { L a; S b; }
-struct lss { L a; S b,c; }
-struct sl { S a; L b; }
-struct ssl { S a,b; L c; }
-struct sls { S a; L b; S c; }
-
-struct li { L a; I b; }
-struct lii { L a; I b,c; }
-struct il { I a; L b; }
-struct iil { I a,b; L c; }
-struct ili { I a; L b; I c; }
-
-struct df { D a; F b; }
-struct dff { D a; F b,c; }
-struct fd { F a; D b; }
-struct ffd { F a,b; D c; }
-struct fdf { F a; D b; F c; }
-
-// Mixed Types
-
-struct fi { F a; I b; }
-struct fii { F a; I b,c; }
-struct jf { I a; F b; }
-struct iif { I a,b; F c; }
-struct ifi { I a; F b; I c; }
-
-struct ffi { F a,b; I c; }
-struct ffii { F a,b; I c,d; }
-struct iff { I a; F b,c; }
-struct iiff { I a,b; F c,d; }
-struct ifif { I a; F b; I c; F d;}
-
-struct di { D a; I b; }
-struct dii { D a; I b,c; }
-struct id { I a; D b; }
-struct iid { I a,b; D c; }
-struct idi { I a; D b; I c; }
-
-// Real ( long double )
-
-struct r { R a; }
-struct rr { R a,b; }
-struct rb { R a; B b; }
-struct rf { R a; F b; }
-struct fr { F a; R b; }
-
- // Int Registers only
-alias tuple!( b,bb,bbb,bbbb,bbbbb,
- b6, b7, b8, b9, b10,
- b11,b12,b13,b14,b15,
- b16,b17,b18,b19,b20,
- s,ss,sss,ssss,sssss,
- s6, s7, s8, s9, s10,
- i,ii,iii,iiii,iiiii,
- l,ll,lll,llll,lllll,
- //
- js,iss,si,ssi, sis,
- ls,lss,sl,ssl, sls,
- li,lii,il,iil, ili,
- fi,fii,jf,iif, ifi,
- ffi,ffii,iff,iiff,ifif, // INT_END
-
- // SSE registers only
- f,ff,fff,ffff,fffff,
- d,dd,ddd,dddd,ddddd,
- //
- df,dff,fd,ffd, fdf, // SSE_END
-
- // Int and SSE
- di, dii,id, iid, idi, // MIX_END
- // ---
- ) ALL_T;
-
-enum INT_END = 65;
-enum SSE_END = 80;
-enum MIX_END = ALL_T.length;
-
- // x87
-alias tuple!( r,rr,rb,rf,fr,
- // ---
- ) R_T;
-//"r","rr","rb","rf","fr",
-
-
-string[] ALL_S=[
- "b","bb","bbb","bbbb","bbbbb",
- "b6", "b7", "b8", "b9", "b10",
- "b11","b12","b13","b14","b15",
- "b16","b17","b18","b19","b20",
- "s","ss","sss","ssss","sssss",
- "s6","s7","s8","s9" , "s10",
- "i","ii","iii","iiii","iiiii",
- "l","ll","lll","llll","lllll",
- // ---
- "js","iss","si","ssi", "sis",
- "ls","lss","sl","ssl", "sls",
- "li","lii","il","iil", "ili",
- "fi","fii","jf","iif", "ifi",
- "ffi","ffii","iff","iiff","ifif",
- // ---
- "f","ff","fff","ffff","fffff",
- "d","dd","ddd","dddd","ddddd",
- "df","dff","fd","ffd", "dfd",
- // ---
- "di","dii","id","iid","idi",
- ];
-
-/* ***********************************************************************
- All
- ************************************************************************/
-// test1 Struct passing and return
-
-int[MIX_END] results_1;
-
-T test1_out(T)( )
-{
- T t;
- foreach( i, ref e; t.tupleof ) e = i+1;
- return t;
-}
-T test1_inout(T)( T t)
-{
- foreach( i, ref e; t.tupleof ) e += 10;
- return t;
-}
-
-void test1_call_out(T)( int n )
-{
- T t1;
- foreach( i, ref e; t1.tupleof ) e = i+1;
- T t2 = test1_out!(T)();
-
- if( t1 == t2 ) results_1[n] |= 1;
-}
-void test1_call_inout(T)( int n )
-{
- T t1;
- foreach( i, ref e; t1.tupleof ) e = i+1;
- T t2 = test1_inout!(T)( t1 );
- foreach( i, ref e; t1.tupleof ) e += 10;
-
- if( t1 == t2 ) results_1[n] |= 2;
-}
-
-void D_test1( )
-{
- // Run Tests
- foreach( n, T; ALL_T )
- {
- test1_call_out!(T)(n);
- test1_call_inout!(T)(n);
- }
-
- bool pass = true;
- foreach( i, r; results_1 )
- {
- if( ~r & 1 )
- {
- pass = false;
- printf( "Test1 out %s \tFail\n", ALL_S[i].ptr );
- }
- if( ~r & 2 )
- {
- pass = false;
- printf( "Test1 inout %s \tFail\n", ALL_S[i].ptr );
- }
- }
- assert( pass );
-
- results_1[0..5] = 0;
- foreach( n, T; R_T )
- {
- test1_call_out!(T)(n);
- test1_call_inout!(T)(n);
- }
-}
-
-/************************************************************************/
-// based on runnable/test23.d : test44()
-// Return Struct into an Array
-
-struct S1
-{ int i,j;
-
- static S1 foo(int x)
- { S1 s;
- s.i = x;
- return s;
-} }
-struct S2
-{ int i,j,k;
-
- static S2 foo(int x)
- { S2 s;
- s.i = x;
- return s;
-} }
-struct S3
-{ float i,j;
-
- static S3 foo(int x)
- { S3 s;
- s.i = x;
- return s;
-} }
-struct S4
-{ float i,j,k;
-
- static S4 foo(int x)
- { S4 s;
- s.i = x;
- return s;
-} }
-struct S5
-{ float i,j;
- int k;
-
- static S5 foo(float x)
- { S5 s;
- s.i = x;
- return s;
-} }
-
-void D_test2()
-{
- S1[] s1;
- S2[] s2;
- S3[] s3;
- S4[] s4;
- S5[] s5;
-
- s1 = s1 ~ S1.foo(6); s1 = s1 ~ S1.foo(1);
- s2 = s2 ~ S2.foo(6); s2 = s2 ~ S2.foo(1);
- s3 = s3 ~ S3.foo(6); s3 = s3 ~ S3.foo(1);
- s4 = s4 ~ S4.foo(6); s4 = s4 ~ S4.foo(1);
- s5 = s5 ~ S5.foo(6); s5 = s5 ~ S5.foo(1);
-
- assert( s1.length == 2 );
- assert( s1[0].i == 6 );
- assert( s1[1].i == 1 );
-
- assert( s2.length == 2 );
- assert( s2[0].i == 6 );
- assert( s2[1].i == 1 );
-
-/+ // These Fail on Mainline DMD64 ( Should pass! )
- assert( s3.length == 2 );
- assert( s3[0].i == 6 );
- assert( s3[1].i == 1 );
-
- assert( s4.length == 2 );
- assert( s4[0].i == 6 );
- assert( s4[1].i == 1 );
-+/
- assert( s5.length == 2 );
- assert( s5[0].i == 6 );
- assert( s5[1].i == 1 );
-
-}
-
-/* ***********************************************************************
- X86_64
- ************************************************************************/
-
-version(Run_X86_64_Tests)
-{
-
-
-struct TEST
-{
- immutable int num;
- immutable string desc;
- bool[MIX_END] result;
-}
-
-/**
- * 0 = Should Fail
- * 1 = Should Pass
- */
-immutable int[MIX_END] expected =
- [
- 1,1,1,1,1, // b
- 1,1,1,1,1, // b6
- 1,1,1,1,1, // b11
- 1,0,0,0,0, // b16
-
- 1,1,1,1,1, // s
- 1,1,1,0,0, // s6
- 1,1,1,1,0, // i
- 1,1,0,0,0, // l
- 1,1,1,1,1, // si mix
- 1,1,1,1,0, // sl
- 1,1,1,1,0, // il
- 1,1,1,1,1, // int and float
- 1,1,1,1,1, // int and float
-
- // SSE regs only
- 1,1,1,1,0, // f
- 1,1,0,0,0, // d
- 1,1,1,1,0, // float and double
-
- // SSE + INT regs
- 1,1,1,1,0, // int and double
- ];
-
-
-/**
- * Describes value expected in registers
- *
- * null means do not test
- * ( because value is passed on the stack ).
- */
-
-immutable long[][] RegValue =
- [
-/* 0 b */ [ 0x0000000000000001, ],
-/* 1 bb */ [ 0x0000000000000201, ],
-/* 2 bbb */ [ 0x0000000000030201, ],
-/* 3 bbbb */ [ 0x0000000004030201, ],
-/* 4 bbbbb */ [ 0x0000000504030201, ],
-/* 5 b6 */ [ 0x0000060504030201, ],
-/* 6 b7 */ [ 0x0007060504030201, ],
-/* 7 b8 */ [ 0x0807060504030201, ],
-/* 8 b9 */ [ 0x0807060504030201, 0x0000000000000009 ],
-/* 9 b10 */ [ 0x0807060504030201, 0x0000000000000a09 ],
-/* 10 b11 */ [ 0x0807060504030201, 0x00000000000b0a09 ],
-/* 11 b12 */ [ 0x0807060504030201, 0x000000000c0b0a09 ],
-/* 12 b13 */ [ 0x0807060504030201, 0x0000000d0c0b0a09 ],
-/* 13 b14 */ [ 0x0807060504030201, 0x00000e0d0c0b0a09 ],
-/* 14 b15 */ [ 0x0807060504030201, 0x000f0e0d0c0b0a09 ],
-/* 15 b16 */ [ 0x0807060504030201, 0x100f0e0d0c0b0a09 ],
-/* 16 b17 */ null,
-/* 17 b18 */ null,
-/* 18 b19 */ null,
-/* 19 b20 */ null,
-/* 20 s */ [ 0x0000000000000001, ],
-/* 21 ss */ [ 0x0000000000020001, ],
-/* 22 sss */ [ 0x0000000300020001, ],
-/* 23 ssss */ [ 0x0004000300020001, ],
-/* 24 sssss */ [ 0x0004000300020001, 0x0000000000000005 ],
-/* 25 s6 */ [ 0x0004000300020001, 0x0000000000060005 ],
-/* 26 s7 */ [ 0x0004000300020001, 0x0000000700060005 ],
-/* 27 s8 */ [ 0x0004000300020001, 0x0008000700060005 ],
-/* 28 s9 */ null,
-/* 29 s10 */ null,
-/* 30 i */ [ 0x0000000000000001, ],
-/* 31 ii */ [ 0x0000000200000001, ],
-/* 32 iii */ [ 0x0000000200000001, 0x0000000000000003 ],
-/* 33 iiii */ [ 0x0000000200000001, 0x0000000400000003 ],
-/* 34 iiiii */ null,
-/* 35 l */ [ 0x0000000000000001, ],
-/* 36 ll */ [ 0x0000000000000001, 0x0000000000000002 ],
-/* 37 lll */ null,
-/* 38 llll */ null,
-/* 39 lllll */ null,
-
-/* 40 js */ [ 0x0000000200000001, ],
-/* 41 iss */ [ 0x0003000200000001, ],
-/* 42 si */ [ 0x0000000200000001, ],
-/* 43 ssi */ [ 0x0000000300020001, ],
-/* 44 sis */ [ 0x0000000200000001, 0x0000000000000003 ],
-/* 45 ls */ [ 0x0000000000000001, 0x0000000000000002 ],
-/* 46 lss */ [ 0x0000000000000001, 0x0000000000030002 ],
-/* 47 sl */ [ 0x0000000000000001, 0x0000000000000002 ],
-/* 48 ssl */ [ 0x0000000000020001, 0x0000000000000003 ],
-/* 49 sls */ null,
-/* 50 li */ [ 0x0000000000000001, 0x0000000000000002 ],
-/* 51 lii */ [ 0x0000000000000001, 0x0000000300000002 ],
-/* 52 il */ [ 0x0000000000000001, 0x0000000000000002 ],
-/* 53 iil */ [ 0x0000000200000001, 0x0000000000000003 ],
-/* 54 ili */ null,
-
-/* 55 fi */ [ 0x000000023f800000, ],
-/* 56 fii */ [ 0x000000023f800000, 0x0000000000000003 ],
-/* 57 jf */ [ 0x4000000000000001, ],
-/* 58 iif */ [ 0x0000000200000001, 0x0000000040400000 ],
-/* 59 ifi */ [ 0x4000000000000001, 0x0000000000000003 ],
-
-/* 60 ffi */ [ 0x0000000000000003, 0x400000003f800000 ],
-/* 61 ffii */ [ 0x0000000400000003, 0x400000003f800000 ],
-/* 62 iff */ [ 0x4000000000000001, 0x0000000040400000 ],
-/* 63 iiff */ [ 0x0000000200000001, 0x4080000040400000 ],
-/* 64 ifif */ [ 0x4000000000000001, 0x4080000000000003 ],
-
-/* 65 f */ [ 0x000000003f800000, ],
-/* 66 ff */ [ 0x400000003f800000, ],
-/* 67 fff */ [ 0x400000003f800000, 0x0000000040400000 ],
-/* 68 ffff */ [ 0x400000003f800000, 0x4080000040400000 ],
-/* 69 fffff */ null,
-/* 70 d */ [ 0x3ff0000000000000, ],
-/* 71 dd */ [ 0x3ff0000000000000, 0x4000000000000000 ],
-/* 72 ddd */ null,
-/* 73 dddd */ null,
-/* 74 ddddd */ null,
-
-/* 75 df */ [ 0x3ff0000000000000, 0x0000000040000000 ],
-/* 76 dff */ [ 0x3ff0000000000000, 0x4040000040000000 ],
-/* 77 fd */ [ 0x000000003f800000, 0x4000000000000000 ],
-/* 78 ffd */ [ 0x400000003f800000, 0x4008000000000000 ],
-/* 79 fdf */ null,
-
-/* 80 di */ [ 0x3ff0000000000000, 0x0000000000000002 ],
-/* 81 dii */ [ 0x3ff0000000000000, 0x0000000300000002 ],
-/* 82 id */ [ 0x4000000000000000, 0x0000000000000001 ],
-/* 83 iid */ [ 0x4008000000000000, 0x0000000200000001 ],
-/* 84 idi */ null,
- ];
-
-/* Have to do it this way for OSX: Issue 7354 */
-__gshared long[2] dump;
-
-/**
- * Generate Register capture
- */
-string gen_reg_capture( int n, string registers )( )
-{
- if( RegValue[n] == null ) return "return;";
-
- string[] REG = mixin(registers); // ["RDI","RSI"];
-
- // Which type of compare
- static if(n < INT_END)
- enum MODE = 1; // Int
- else static if(n < SSE_END)
- enum MODE = 2; // Float
- else enum MODE = 3; // Mix
-
- /* Begin */
-
- string code = "asm {\n";
-
- final switch( MODE )
- {
- case 1: code ~= "mov [dump], "~REG[0]~";\n";
- REG = REG[1..$];
- break;
- case 2:
- case 3: code ~= "movq [dump], XMM0;\n";
- }
-
- if( RegValue[n].length == 2 )
- final switch( MODE )
- {
- case 1:
- case 3: code ~= "mov [dump+8], "~REG[0]~";\n";
- break;
- case 2: code ~= "movq [dump+8], XMM1;\n";
- } else {
- code ~= "xor R8, R8;\n";
- code ~= "mov [dump+8], R8;\n";
- }
-
- return code ~ "}\n";
-}
-
-/**
- * Check the results
- */
-bool check( TEST data )
-{
- bool pass = true;
- foreach( i, e; expected )
- {
- if( data.result[i] != (e & 1) )
- {
- printf( "Test%d %s \tFail\n", data.num, ALL_S[i].ptr);
- pass = false;
- }
- }
- return pass;
-}
-
-/************************************************************************/
-
-// test1 Return Struct in Registers
-// ( if RDI == 12 we have no hidden pointer )
-
-TEST data1 = { 1, "RDI hidden pointer" };
-
-T test1_asm( T, int n )( int i )
-{
- asm {
-
- cmp EDI, 12;
- je L1;
-
- leave; ret;
- }
-L1:
- data1.result[n] = true;
-}
-
-void test1()
-{
- printf("\nRunning iasm Test 1 ( %s )\n", data1.desc.ptr);
-
- foreach( int n, T; ALL_T )
- test1_asm!(T,n)(12);
-
- check( data1 );
-}
-
-/************************************************************************/
-// test2 Pass Struct in Registers
-// ( if RDI == 0 we have no stack pointer )
-
-TEST data2 = { 2, "RDI struct pointer" };
-
-T test2_asm( T, int n )( T t )
-{
- asm {
-
- mov [dump], RDI;
- mov [dump+8], RSP;
- cmp EDI, 0; // TODO test RDI is a ptr to stack ? ?
- je L1;
-
- leave; ret;
- }
-L1:
- data2.result[n] = true;
-}
-T test2f_asm( T, int n )( T t, int x )
-{
- asm {
-
- cmp EDI, 12;
- je L1;
-
- leave; ret;
- }
-L1:
- data2.result[n] = true;
-}
-
-void test2()
-{
- printf("\nRunning iasm Test 2 ( %s )\n", data2.desc.ptr);
-
- // Integer
- foreach( int n, T; ALL_T ) {
- T t = { 0 };
- test2_asm!(T,n)( t );
- }
-
- // float alternative test
- foreach( int n, T; ALL_T[INT_END..SSE_END] )
- {
- enum n2 = n + INT_END;
- data2.result[n2] = false;
- test2f_asm!(T,n2)( T.init, 12 );
- }
-
- check( data2 );
-}
-
-/************************************************************************/
-// test3
-
-TEST data3 = { 3, "Check Return Register value" };
-
-void test3_run( T, int n )( )
-{
- test3_ret!T();
- mixin( gen_reg_capture!(n,`["RAX","RDX"]`)() );
-
- //dbg!(T,n)( );
-
- enum len = RegValue[n].length;
- if( dump[0..len] == RegValue[n] )
- data3.result[n] = true;
-}
-
-T test3_ret( T )( )
-{
- T t;
- foreach( i, ref e; t.tupleof ) e = i+1;
- return t;
-}
-
-void test3()
-{
- printf("\nRunning iasm Test 3 ( %s )\n", data3.desc.ptr);
-
- foreach( int n, T; ALL_T )
- test3_run!(T,n)( );
-
- check( data3 );
-}
-
-/************************************************************************/
-// test4
-
-TEST data4 = { 4, "Check Input Register value" };
-
-void test4_run( T, int n )( T t )
-{
- mixin( gen_reg_capture!(n,`["RDI","RSI"]`)() );
-
- //dbg!(T,n)( );
-
- enum len = RegValue[n].length;
- if( dump[0..len] == RegValue[n] )
- data4.result[n] = true;
-}
-
-void dbg( T, int n )( )
-{
- import std.stdio;
- writefln( "D %s\t[ %16x, %16x ]", T.stringof, dump[0], dump[1], );
- writef( "C %s\t[ %16x", T.stringof, RegValue[n][0] );
- if( RegValue[n].length == 2 )
- writef( ", %16x", RegValue[n][1] );
- writefln( " ]" );
-}
-void test4()
-{
- printf("\nRunning iasm Test 4 ( %s )\n", data4.desc.ptr);
-
- foreach( int n, T; ALL_T )
- {
- T t;
- foreach( i, ref e; t.tupleof ) e = i+1;
- test4_run!(T,n)( t );
- }
- check( data4 );
-}
-
-
-} // end version(Run_X86_64_Tests)
-
-/************************************************************************/
-
-
-void main()
-{
- D_test1();
- D_test2();
-
- version(Run_X86_64_Tests)
- {
- test1();
- test2();
- test3();
- test4();
- }
-}
-
-/+
-/**
- * C code to generate the table RegValue
- */
-string c_generate_returns()
-{
- string value = " 1, 2, 3, 4, 5, 6, 7, 8, 9,10,"
- "11,12,13,14,15,16,17,18,19,20,";
-
- string code = "#include \"cgen.h\"\n";
-
- // Generate return functions
- foreach( int n, T; ALL_T )
- {
- auto Ts = T.stringof;
- auto len = T.tupleof.length;
-
- code ~= "struct "~Ts~" func_ret_"~Ts~"(void) { \n";
- code ~= "struct "~Ts~" x = { ";
- code ~= value[0..len*3] ~ " };\n";
- code ~= "return x;\n}\n";
- }
- return code;
-}
-string c_generate_pass()
-{
- string value = " 1, 2, 3, 4, 5, 6, 7, 8, 9,10,"
- "11,12,13,14,15,16,17,18,19,20,";
-
- string code;
-
- // Generate return functions
- foreach( int n, T; ALL_T )
- {
- auto Ts = T.stringof;
- auto len = T.tupleof.length;
-
- code ~= "void func_pass_"~Ts~"( struct "~Ts~" x ) {\n";
- ////////////////
- // Which type of compare
- static if(n < INT_END)
- enum MODE = 1; // Int
- else static if(n < SSE_END)
- enum MODE = 2; // Float
- else enum MODE = 3; // Mix
-
- auto nn = n.stringof;
-
- /* Begin */
-
- code ~= "asm(\n";
- final switch( MODE )
- {
- case 1:
- code ~= `"movq %rdi, reg\n" "movq %rsi, reg+8\n"`;
- break;
- case 2:
- code ~= `"movq %xmm0, reg\n" "movq %xmm1, reg+8\n"`;
- break;
- case 3:
- code ~= `"movq %xmm0, reg\n" "movq %rdi, reg+8\n"`;
- }
- code ~= "\n);\n";
- code ~= "}\n";
-
- ////////////////
- code ~= "void func_call_"~Ts~"( void ) {\n";
- code ~= "struct "~Ts~" x = { ";
- code ~= value[0..len*3] ~ " };\n";
- code ~= "func_pass_"~Ts~"( x );\n}\n";
- }
- return code;
-}
-string c_generate_main()
-{
- string code = "void main() {\n";
-
- foreach( int n, T; ALL_T )
- {
- // Which type of compare
- static if(n < INT_END)
- enum MODE = 1; // Int
- else static if(n < SSE_END)
- enum MODE = 2; // Float
- else enum MODE = 3; // Mix
-
- auto nn = n.stringof;
- auto Ts = T.stringof;
-
- /* Begin */
-
- code ~= `printf("/* %3d `~Ts~`\t*/ ", `~nn~`);`"\n";
- if( !(expected[n] & 1) )
- {
- code ~= `printf("null,\n");`"\n";
- continue;
- }
- code ~= "asm(\n";
- code ~= `"call func_ret_`~Ts~`\n"`"\n";
- final switch( MODE )
- {
- case 1:
- code ~= `"movq %rax, reg\n" "movq %rdx, reg+8\n"`;
- break;
- case 2:
- code ~= `"movq %xmm0, reg\n" "movq %xmm1, reg+8\n"`;
- break;
- case 3:
- code ~= `"movq %xmm0, reg\n" "movq %rax, reg+8\n"`;
- }
- code ~= "\n);\n";
-
- code ~= `printf("[ 0x%016lx", reg.r1 );`"\n";
-
- if( T.sizeof > 8 || MODE == 3 )
- code ~= `printf(", 0x%016lx ],\n", reg.r2 );`"\n";
- else code ~= `printf(", %015c ],\n", ' ' );`"\n";
- }
-
- foreach( int n, T; ALL_T )
- {
- // Which type of compare
- static if(n < INT_END)
- enum MODE = 1; // Int
- else static if(n < SSE_END)
- enum MODE = 2; // Float
- else enum MODE = 3; // Mix
-
- auto nn = n.stringof;
- auto Ts = T.stringof;
-
- /* Begin */
-
- code ~= `printf("/* %3d `~Ts~`\t*/ ", `~nn~`);`"\n";
- if( !(expected[n] & 1) )
- {
- code ~= `printf("null,\n");`"\n";
- continue;
- }
- code ~= "func_call_"~Ts~"();\n";
-
- code ~= `printf("[ 0x%016lx", reg.r1 );`"\n";
-
- if( T.sizeof > 8 || MODE == 3 )
- code ~= `printf(", 0x%016lx ],\n", reg.r2 );`"\n";
- else code ~= `printf(", %015c ],\n", ' ' );`"\n";
- }
-
-
- return code ~ "}";
-}
-pragma(msg, c_generate_returns() );
-pragma(msg, c_generate_pass() );
-pragma(msg, c_generate_main() );
-// +/
-
-/+
-/**
- * Generate Functions that pass/return each Struct type
- *
- * ( Easier to look at objdump this way )
- */
-string d_generate_functions( )
-{
- string code = "extern(C) {";
-
- // pass
- foreach( s; ALL_T )
- {
- string ss = s.stringof;
-
- code ~= "void func_in_"~ss~"( "~ss~" t ) { t.a = 12; }\n";
- }
- // return
- foreach( s; ALL_T[0..10] )
- {
- string ss = s.stringof;
-
- code ~= `
- auto func_out_`~ss~`()
- {
- `~ss~` t;
- foreach( i, ref e; t.tupleof ) e = i+1;
- return t;
- }`;
- }
- // pass & return
- foreach( s; ALL_T[0..10] )
- {
- string ss = s.stringof;
-
- code ~= `
- auto func_inout_`~ss~`( `~ss~` t )
- {
- foreach( i, ref e; t.tupleof ) e += 10;
- return t;
- }`;
- }
- return code ~ "\n} // extern(C)\n";
-}
-//pragma( msg, d_generate_functions() );
-mixin( d_generate_functions() );
-// +/
diff --git a/gcc/testsuite/gdc.test/runnable/testaliascast.d b/gcc/testsuite/gdc.test/runnable/testaliascast.d
new file mode 100644
index 0000000..c55f820
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/testaliascast.d
@@ -0,0 +1,63 @@
+// https://issues.dlang.org/show_bug.cgi?id=11294
+
+string result;
+
+extern(C) void rt_finalize(void *ptr, bool det=true);
+void clear(T)(T obj) if (is(T == class))
+{
+ rt_finalize(cast(void*)obj);
+}
+
+class A
+{
+ ~this() { result ~= "A"; }
+ string dummy = "0";
+}
+
+class B
+{
+ A a;
+ string dummy = "0";
+ alias a this;
+ ~this() { result ~= "B"; }
+}
+
+void test11294()
+{
+ auto a = new A;
+ auto b = new B;
+ b.a = a;
+ result ~= b.dummy;
+ clear(b);
+ result ~= a.dummy;
+ result ~= "END";
+ clear(a);
+
+ assert(result == "0B0ENDA");
+}
+
+
+// https://issues.dlang.org/show_bug.cgi?id=13392
+void foo(T)(T t)
+{
+ void* p = cast(void*) t; //Callas alias this
+}
+
+class X {}
+
+class Y
+{
+ alias a this;
+ @property X a(){assert(0);} //Here
+}
+
+void test13392()
+{
+ foo(B.init);
+}
+
+void main()
+{
+ test11294();
+ test13392();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/testappend.d b/gcc/testsuite/gdc.test/runnable/testappend.d
index cbdae36..f8bff3e 100644
--- a/gcc/testsuite/gdc.test/runnable/testappend.d
+++ b/gcc/testsuite/gdc.test/runnable/testappend.d
@@ -1,4 +1,18 @@
-// PERMUTE_ARGS:
+/*
+PERMUTE_ARGS:
+TEST_OUTPUT:
+---
+runnable/testappend.d(54): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+runnable/testappend.d(55): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+runnable/testappend.d(76): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+runnable/testappend.d(77): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+---
+
+RUN_OUTPUT:
+---
+Success
+---
+*/
import core.stdc.stdio;
import core.stdc.math : isnan;
diff --git a/gcc/testsuite/gdc.test/runnable/testassert.d b/gcc/testsuite/gdc.test/runnable/testassert.d
new file mode 100644
index 0000000..30fe8d9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/testassert.d
@@ -0,0 +1,380 @@
+/*
+REQUIRED_ARGS: -checkaction=context -preview=dip1000
+PERMUTE_ARGS: -O -g -inline
+*/
+
+void test8765()
+{
+ string msg;
+ try
+ {
+ int a = 0;
+ assert(a);
+ }
+ catch (Throwable e)
+ {
+ // no-message -> assert expression
+ msg = e.msg;
+ }
+ assert(msg == "0 != true");
+}
+
+ void test9255()
+{
+ string file;
+ try
+ {
+ int x = 0;
+ assert(x);
+ }
+ catch (Throwable e)
+ {
+ file = e.file;
+ }
+
+ version(Windows)
+ assert(file && file == r"runnable\testassert.d");
+ else
+ assert(file && file == "runnable/testassert.d");
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20114
+void test20114()
+{
+ // Function call returning simple type
+ static int fun() {
+ static int i = 0;
+ assert(i++ == 0);
+ return 3;
+ }
+
+ const a = getMessage(assert(fun() == 4));
+ assert(a == "3 != 4");
+
+ // Function call returning complex type with opEquals
+ static struct S
+ {
+ bool opEquals(const int x) const
+ {
+ return false;
+ }
+ }
+
+ static S bar()
+ {
+ static int i = 0;
+ assert(i++ == 0);
+ return S.init;
+ }
+
+ const b = getMessage(assert(bar() == 4));
+ assert(b == "S() != 4");
+
+ // Non-call expression with side effects
+ int i = 0;
+ const c = getMessage(assert(++i == 0));
+ assert(c == "1 != 0");
+}
+
+version (DigitalMars) version (Win64) version = DMD_Win64;
+
+void test20375() @safe
+{
+ static struct RefCounted
+ {
+ // Force temporary through "impure" generator function
+ static RefCounted create() @trusted
+ {
+ __gshared int counter = 0;
+ return RefCounted(++counter > 0);
+ }
+
+ static int instances;
+ static int postblits;
+
+ this(bool) @safe
+ {
+ instances++;
+ }
+
+ this(this) @safe
+ {
+ instances++;
+ postblits++;
+ }
+
+ ~this() @safe
+ {
+ // make the dtor non-nothrow (we are tracking clean-ups during AssertError unwinding)
+ if (postblits > 100)
+ throw new Exception("");
+ assert(instances > 0);
+ instances--;
+ }
+
+ bool opEquals(RefCounted) @safe
+ {
+ return true;
+ }
+ }
+
+ {
+ auto a = RefCounted.create();
+ RefCounted.instances++; // we're about to construct an instance below, increment manually
+ assert(a == RefCounted()); // both operands are pure expressions => no temporaries
+ }
+
+ assert(RefCounted.instances == 0);
+ assert(RefCounted.postblits == 0);
+
+ {
+ auto a = RefCounted.create();
+ assert(a == RefCounted.create()); // impure rhs is promoted to a temporary lvalue => copy for a.opEquals(rhs)
+ }
+
+ assert(RefCounted.instances == 0);
+ assert(RefCounted.postblits == 1);
+ RefCounted.postblits = 0;
+
+ {
+ const msg = getMessage(assert(RefCounted.create() != RefCounted.create())); // both operands promoted to temporary lvalues
+ assert(msg == "RefCounted() == RefCounted()");
+ }
+
+ version (DMD_Win64) // FIXME: temporaries apparently not destructed when unwinding via AssertError
+ {
+ assert(RefCounted.instances >= 0 && RefCounted.instances <= 2);
+ RefCounted.instances = 0;
+ }
+ else
+ assert(RefCounted.instances == 0);
+ assert(RefCounted.postblits == 1);
+ RefCounted.postblits = 0;
+
+ static int numGetLvalImpureCalls = 0;
+ ref RefCounted getLvalImpure() @trusted
+ {
+ numGetLvalImpureCalls++;
+ __gshared lval = RefCounted(); // not incrementing RefCounted.instances
+ return lval;
+ }
+
+ {
+ const msg = getMessage(assert(getLvalImpure() != getLvalImpure())); // both operands promoted to ref temporaries
+ assert(msg == "RefCounted() == RefCounted()");
+ }
+
+ assert(numGetLvalImpureCalls == 2);
+ assert(RefCounted.instances == 0);
+ assert(RefCounted.postblits == 1);
+ RefCounted.postblits = 0;
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=21471
+void test21471()
+{
+ {
+ static struct S
+ {
+ S get()() const { return this; }
+ }
+
+ static auto f(S s) { return s; }
+
+ auto s = S();
+ assert(f(s.get) == s);
+ }
+ {
+ pragma(inline, true)
+ real exp(real x) pure nothrow
+ {
+ return x;
+ }
+
+ bool isClose(int lhs, real rhs) pure nothrow
+ {
+ return false;
+ }
+ auto c = 0;
+ assert(!isClose(c, exp(1)));
+ }
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20581
+void test20581() @safe
+{
+ static auto retro(return scope int[] s) @safe
+ {
+ static struct R
+ {
+ int[] source;
+ }
+ return R(s);
+ }
+
+ int[5] a = [ 1, 2, 3, 4, 5 ];
+ // Creates ref temporary __assertTmpXXXX for source
+ // Error: address of variable a assigned to __assertOp27 with longer lifetime
+ assert(retro(a[]).source is a[]);
+}
+
+string getMessage(T)(lazy T expr) @trusted
+{
+ try
+ {
+ expr();
+ return null;
+ }
+ catch (Throwable t)
+ {
+ return t.msg;
+ }
+}
+
+void testMixinExpression() @safe
+{
+ static struct S
+ {
+ bool opEquals(S) @safe { return true; }
+ }
+
+ const msg = getMessage(assert(mixin("S() != S()")));
+ assert(msg == "S() == S()");
+}
+
+void testUnaryFormat()
+{
+ int zero = 0, one = 1;
+ assert(getMessage(assert(zero)) == "0 != true");
+ assert(getMessage(assert(!one)) == "1 == true");
+
+ assert(getMessage(assert(!cast(int) 1.5)) == "1 == true");
+
+ assert(getMessage(assert(!!__ctfe)) == "assert(__ctfe) failed!");
+
+ static struct S
+ {
+ int i;
+ bool opCast() const
+ {
+ return i < 2;
+ }
+ }
+
+ assert(getMessage(assert(S(4))) == "S(4) != true");
+
+ S s = S(4);
+ assert(getMessage(assert(*&s)) == "S(4) != true");
+
+ assert(getMessage(assert(--(++zero))) == "0 != true");
+}
+
+void testAssignments()
+{
+ int a = 1;
+ int b = 2;
+ assert(getMessage(assert(a -= --b)) == "0 != true");
+
+ static ref int c()
+ {
+ static int counter;
+ counter++;
+ return counter;
+ }
+
+ assert(getMessage(assert(--c())) == "0 != true");
+}
+
+/// https://issues.dlang.org/show_bug.cgi?id=21472
+void testTupleFormat()
+{
+ alias AliasSeq(T...) = T;
+
+ // Default usage
+ {
+ alias a = AliasSeq!(1, "ab");
+ alias b = AliasSeq!(false, "xyz");
+ assert(getMessage(assert(a == b)) == `(1, "ab") != (false, "xyz")`);
+ }
+
+ // Single elements work but are not formatted as tuples
+ // Is this acceptable? (a workaround would probably require a
+ // different name for the tuple formatting hook)
+ {
+ alias a = AliasSeq!(1, "ab", []);
+ alias b = AliasSeq!(false, "xyz", [1]);
+ assert(getMessage(assert(a == b)) == `(1, "ab", []) != (false, "xyz", [1])`);
+ }
+
+ // Also works with tupleof (as taken from the bug report)
+ {
+ static struct Var { int a, b; }
+ const a = Var(1, 2);
+ const b = Var(3, 4);
+ const msg = getMessage(assert(a.tupleof == b.tupleof));
+ assert(msg == `(1, 2) != (3, 4)`);
+ }
+
+ // Also works when creating temporaries for the TupleExp
+ {
+ static struct S
+ {
+ int a, b;
+ }
+
+ static S get()
+ {
+ static int i;
+ return S(i++, i++);
+ }
+
+ auto a = get().tupleof;
+ auto b = get().tupleof;
+
+ string msg = getMessage(assert(a == b));
+ assert(msg == `(0, 1) != (2, 3)`);
+
+ msg = getMessage(assert(get().tupleof == AliasSeq!(2, 3)));
+ assert(msg == `(4, 5) != (2, 3)`);
+
+ msg = getMessage(assert(get().tupleof == get().tupleof));
+ assert(msg == `(6, 7) != (8, 9)`);
+ }
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=21682
+void testStaticOperators()
+{
+ static class environment {
+ static bool opCmp(scope const(char)[] name)
+ {
+ return false;
+ }
+
+ static bool opBinaryRight(string op : "in")(scope const(char)[] name)
+ {
+ return false;
+ }
+ }
+
+ string msg = getMessage(assert(environment < "Hello"));
+ assert(msg == `"environment" >= "Hello"`);
+
+ msg = getMessage(assert("Hello" in environment));
+ assert(msg == `"Hello" !in "environment"`);
+}
+
+void main()
+{
+ test8765();
+ test9255();
+ test20114();
+ test20375();
+ test21471();
+ test20581();
+ testMixinExpression();
+ testUnaryFormat();
+ testAssignments();
+ testTupleFormat();
+ testStaticOperators();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/testassert_debug.d b/gcc/testsuite/gdc.test/runnable/testassert_debug.d
new file mode 100644
index 0000000..8817a96
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/testassert_debug.d
@@ -0,0 +1,26 @@
+/*
+https://issues.dlang.org/show_bug.cgi?id=21598
+
+REQUIRED_ARGS: -checkaction=context -debug
+PERMUTE_ARGS:
+*/
+
+void main()
+{
+ bool caught;
+ try
+ assert(foo(1));
+ catch (Throwable)
+ caught = true;
+
+ assert(caught);
+ assert(counter == 1);
+}
+
+__gshared int counter;
+
+int foo(int i) pure nothrow
+{
+ debug counter++;
+ return i - 1;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/testassign.d b/gcc/testsuite/gdc.test/runnable/testassign.d
index b000967..f47d2b2 100644
--- a/gcc/testsuite/gdc.test/runnable/testassign.d
+++ b/gcc/testsuite/gdc.test/runnable/testassign.d
@@ -1,4 +1,5 @@
/*
+REQUIRED_ARGS: -preview=rvaluerefparam
TEST_OUTPUT:
---
\ S1 S2a S2b S3a S3b S4a S4b
@@ -23,7 +24,7 @@ import core.stdc.stdio;
template TypeTuple(T...){ alias T TypeTuple; }
/***************************************************/
-// 2625
+// https://issues.dlang.org/show_bug.cgi?id=2625
struct Pair {
immutable uint g1;
@@ -36,7 +37,7 @@ void test1() {
}
/***************************************************/
-// 5327
+// https://issues.dlang.org/show_bug.cgi?id=5327
struct ID
{
@@ -154,12 +155,12 @@ void test3()
}
/***************************************************/
-// 3511
+// https://issues.dlang.org/show_bug.cgi?id=3511
struct S4
{
private int _prop = 42;
- ref int property() { return _prop; }
+ ref int property() return { return _prop; }
}
void test4()
@@ -177,11 +178,11 @@ struct S5
int mX;
string mY;
- ref int x()
+ ref int x() return
{
return mX;
}
- ref string y()
+ ref string y() return
{
return mY;
}
@@ -230,7 +231,7 @@ void test5()
}
/***************************************************/
-// 4424
+// https://issues.dlang.org/show_bug.cgi?id=4424
void test4424()
{
@@ -242,7 +243,7 @@ void test4424()
}
/***************************************************/
-// 6174
+// https://issues.dlang.org/show_bug.cgi?id=6174
struct CtorTest6174(Data)
{
@@ -464,12 +465,12 @@ void test6174c()
static assert(!is(typeof({
int func1a(int n)
in{ n = 10; }
- body { return n; }
+ do { return n; }
})));
static assert(!is(typeof({
int func1b(int n)
out(r){ r = 20; }
- body{ return n; }
+ do{ return n; }
})));
struct DataX
@@ -479,18 +480,18 @@ void test6174c()
static assert(!is(typeof({
DataX func2a(DataX n)
in{ n.x = 10; }
- body { return n; }
+ do { return n; }
})));
static assert(!is(typeof({
DataX func2b(DataX n)
in{}
out(r){ r.x = 20; }
- body{ return n; }
+ do{ return n; }
})));
}
/***************************************************/
-// 6216
+// https://issues.dlang.org/show_bug.cgi?id=6216
void test6216a()
{
@@ -658,7 +659,7 @@ void test6216e()
}
/***************************************************/
-// 6286
+// https://issues.dlang.org/show_bug.cgi?id=6286
void test6286()
{
@@ -672,7 +673,7 @@ void test6286()
}
/***************************************************/
-// 6336
+// https://issues.dlang.org/show_bug.cgi?id=6336
void test6336()
{
@@ -701,7 +702,7 @@ void test6336()
}
/***************************************************/
-// 8783
+// https://issues.dlang.org/show_bug.cgi?id=8783
struct Foo8783
{
@@ -719,7 +720,7 @@ static this()
}
/***************************************************/
-// 9077
+// https://issues.dlang.org/show_bug.cgi?id=9077
struct S9077a
{
@@ -735,17 +736,17 @@ struct S9077b
}
/***************************************************/
-// 9140
+// https://issues.dlang.org/show_bug.cgi?id=9140
immutable(int)[] bar9140()
out(result) {
foreach (ref r; result) {}
-} body {
+} do {
return null;
}
/***************************************************/
-// 9154
+// https://issues.dlang.org/show_bug.cgi?id=9154
struct S9154a
{
@@ -770,7 +771,7 @@ void test9154()
}
/***************************************************/
-// 9258
+// https://issues.dlang.org/show_bug.cgi?id=9258
class A9258 {}
class B9258 : A9258 // Error: class test.B9258 identity assignment operator overload is illegal
@@ -797,7 +798,7 @@ class E9258 : A9258
}
/***************************************************/
-// 9416
+// https://issues.dlang.org/show_bug.cgi?id=9416
struct S9416
{
@@ -818,7 +819,7 @@ void test9416()
}
/***************************************************/
-// 9658
+// https://issues.dlang.org/show_bug.cgi?id=9658
struct S9658
{
@@ -830,7 +831,7 @@ struct S9658
}
/***************************************************/
-// 11187
+// https://issues.dlang.org/show_bug.cgi?id=11187
void test11187()
{
@@ -850,7 +851,7 @@ void test11187()
}
/***************************************************/
-// 12131
+// https://issues.dlang.org/show_bug.cgi?id=12131
struct X12131
{
@@ -872,7 +873,7 @@ void test12131() pure
}
/***************************************************/
-// 12211
+// https://issues.dlang.org/show_bug.cgi?id=12211
void test12211()
{
@@ -891,12 +892,12 @@ void test12211()
// array ops should make rvalue
int[3] sa, sb;
void bar(ref int[]) {}
- static assert(!__traits(compiles, bar(sa[] = sb[])));
- static assert(!__traits(compiles, bar(sa[] += sb[])));
+ static assert(__traits(compiles, bar(sa[] = sb[])));
+ static assert(__traits(compiles, bar(sa[] += sb[])));
}
/***************************************************/
-// 4791 (dup of 12212)
+// https://issues.dlang.org/show_bug.cgi?id=4791 (dup of 12212)
void test4791()
{
@@ -925,7 +926,7 @@ void test4791()
}
/***************************************************/
-// 12212
+// https://issues.dlang.org/show_bug.cgi?id=12212
void test12212()
{
@@ -1013,7 +1014,7 @@ void test12212()
}
/***************************************************/
-// 12650
+// https://issues.dlang.org/show_bug.cgi?id=12650
void test12650()
{
@@ -1083,7 +1084,7 @@ void test12650()
}
/***************************************************/
-// 13044
+// https://issues.dlang.org/show_bug.cgi?id=13044
void test13044()
{
@@ -1106,7 +1107,7 @@ void test13044()
}
/***************************************************/
-// 12500
+// https://issues.dlang.org/show_bug.cgi?id=12500
void test12500()
{
@@ -1115,7 +1116,7 @@ void test12500()
}
/***************************************************/
-// 14672
+// https://issues.dlang.org/show_bug.cgi?id=14672
void test14672()
{
@@ -1150,7 +1151,7 @@ void test14672()
}
/***************************************************/
-// 15044
+// https://issues.dlang.org/show_bug.cgi?id=15044
void destroy15044(T)(ref T obj)
{
@@ -1166,7 +1167,7 @@ struct V15044
{
}
- RC15044!V15044 dup()
+ RC15044!V15044 dup() return
{
return RC15044!V15044(&this);
}
diff --git a/gcc/testsuite/gdc.test/runnable/testbitarray.d b/gcc/testsuite/gdc.test/runnable/testbitarray.d
deleted file mode 100644
index 8a34f88..0000000
--- a/gcc/testsuite/gdc.test/runnable/testbitarray.d
+++ /dev/null
@@ -1,17 +0,0 @@
-// RUNNABLE_PHOBOS_TEST
-// PERMUTE_ARGS:
-
-import std.bitmanip;
-
-void main() {
- BitArray a;
- a.length = 5;
- foreach (ref bool b; a) {
- assert (b == 0);
- b = 1;
- }
- foreach (bool b; a)
- assert (b == 1); // FAILS, they're all 0
-}
-
-
diff --git a/gcc/testsuite/gdc.test/runnable/testbounds.d b/gcc/testsuite/gdc.test/runnable/testbounds.d
index b23c88f..bb9e54d 100644
--- a/gcc/testsuite/gdc.test/runnable/testbounds.d
+++ b/gcc/testsuite/gdc.test/runnable/testbounds.d
@@ -1,3 +1,9 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
// REQUIRED_ARGS:
// Test array bounds checking
@@ -179,44 +185,63 @@ void test1()
}
/******************************************/
-// 13976
+// https://issues.dlang.org/show_bug.cgi?id=13976
void test13976()
{
int[] da = new int[](10);
int[10] sa;
- size_t l = 0; // upperInRange
- size_t u = 9; // | lowerLessThan
- // | | check code
- { auto s = da[l .. u]; } // 0 0 (u <= 10 && l <= u )
- { auto s = da[1 .. u]; } // 0 0 (u <= 10 && l <= u )
- { auto s = da[l .. 10]; } // 0 0 (u <= 10 && l <= u )
- { auto s = da[1 .. u%5]; } // 0 0 (u <= 10 && l <= u%5)
-
- { auto s = da[l .. u]; } // 0 0 (u <= 10 && l <= u)
- { auto s = da[0 .. u]; } // 0 1 (u <= 10 )
- { auto s = da[l .. 10]; } // 0 0 (u <= 10 && l <= u)
- { auto s = da[0 .. u%5]; } // 0 1 (u%5 <= 10 )
-
- { auto s = sa[l .. u]; } // 0 0 (u <= 10 && l <= u )
- { auto s = sa[1 .. u]; } // 0 0 (u <= 10 && l <= u )
- { auto s = sa[l .. 10]; } // 1 0 ( l <= u )
- { auto s = sa[1 .. u%5]; } // 1 0 ( l <= u%5)
-
- { auto s = sa[l .. u]; } // 0 0 (u <= 10 && l <= u )
- { auto s = sa[0 .. u]; } // 0 1 (u <= 10 )
- { auto s = sa[l .. 10]; } // 1 0 ( l <= 10)
- { auto s = sa[0 .. u%5]; } // 1 1 NULL
+ enum size_t two = 2;
+ enum size_t five = 5;
+ size_t lb = 0; // upperInRange
+ size_t ub = 9; // | lowerLessThan
+ // | | check code
+ { auto s = da[lb .. ub]; } // 0 0 (ub <= $ && lb <= ub )
+ { auto s = da[1 .. ub]; } // 0 0 (ub <= $ && 1 <= ub )
+ { auto s = da[lb .. 10]; } // 0 0 (10 <= $ && lb <= 10 )
+ { auto s = da[1 .. ub%5]; } // 0 0 (ub%5 <= $ && 1 <= ub%5)
+
+ { auto s = da[lb .. ub]; } // 0 0 (ub <= $ && lb <= ub )
+ { auto s = da[0 .. ub]; } // 0 1 (ub <= $ )
+ { auto s = da[lb .. 10]; } // 0 0 (10 <= $ && lb <= 10 )
+ { auto s = da[0 .. ub%5]; } // 0 1 (ub%5 <= $ )
+
+ { auto s = da[0 .. 0]; } // 1 1 NULL
+ { auto s = da[0 .. $]; } // 1 1 NULL
+ { auto s = da[1 .. $]; } // 1 0 ( 1 <= $ )
+ { auto s = da[$ .. $]; } // 1 0 ( $ <= $ )
+ { auto s = da[0 .. $/two]; } // 0 1 ($/2 <= $ )
+ { auto s = da[$/two .. $]; } // 1 0 ( $/2 <= $ )
+ { auto s = da[$/five .. $/two]; } // 0 0 ($/2 <= $ && $/5 <= $/2)
+
+ { auto s = sa[lb .. ub]; } // 0 0 (ub <= 10 && lb <= ub )
+ { auto s = sa[1 .. ub]; } // 0 0 (ub <= 10 && 1 <= ub )
+ { auto s = sa[lb .. 10]; } // 1 0 ( lb <= 10 )
+ { auto s = sa[1 .. ub%5]; } // 1 0 ( 1 <= ub%5)
+
+ { auto s = sa[lb .. ub]; } // 0 0 (ub <= 10 && lb <= ub )
+ { auto s = sa[0 .. ub]; } // 0 1 (ub <= 10 )
+ { auto s = sa[lb .. 10]; } // 1 0 ( lb <= 10 )
+ { auto s = sa[0 .. ub%5]; } // 1 1 NULL
+
+ { auto s = sa[0 .. 0]; } // 1 1 NULL
+ { auto s = sa[0 .. $]; } // 1 1 NULL
+ { auto s = sa[1 .. $]; } // 1 1 NULL
+ { auto s = sa[$ .. $]; } // 1 1 NULL
+ { auto s = sa[0 .. $/two]; } // 1 1 NULL
+ { auto s = sa[$/two .. $]; } // 1 1 NULL
+ { auto s = sa[$/five .. $/two]; } // 1 1 NULL
int* p = new int[](10).ptr;
- { auto s = p[0 .. u]; } // 1 1 NULL
- { auto s = p[l .. u]; } // 1 0 (l <= u)
- { auto s = p[0 .. u%5]; } // 1 1 NULL
- { auto s = p[1 .. u%5]; } // 1 0 (l <= u%5)
+ { auto s = p[0 .. ub]; } // 1 1 NULL
+ { auto s = p[lb .. ub]; } // 1 0 (lb <= ub )
+ { auto s = p[0 .. ub%5]; } // 1 1 NULL
+ { auto s = p[1 .. ub%5]; } // 1 0 (1 <= ub%5)
+ { auto s = p[0 .. 0]; } // 1 1 NULL
}
/******************************************/
-// 3652
+// https://issues.dlang.org/show_bug.cgi?id=3652
void test3652()
{
@@ -340,7 +365,7 @@ void test3652b() @safe
}
/**********************************/
-// 9654
+// https://issues.dlang.org/show_bug.cgi?id=9654
auto foo9654a(ref char[8] str) { return str; }
auto foo9654b(ref const char[8] str) { return str; }
@@ -364,7 +389,7 @@ static assert( is(typeof(baz9654b("testinfo")) == const char[8]));
static assert( is(typeof(baz9654c("testinfo")) == immutable char[8]));
/******************************************/
-// 9712
+// https://issues.dlang.org/show_bug.cgi?id=9712
auto func9712(T)(T[2] arg) { return arg; }
static assert(is(typeof(func9712([1,2])) == int[2]));
@@ -373,7 +398,7 @@ auto deduceLength9712(T,size_t n)(T[n] a) { return a; }
static assert(is(typeof(deduceLength9712([1,2,3])) == int[3]));
/******************************************/
-// 9743
+// https://issues.dlang.org/show_bug.cgi?id=9743
void test9743()
{
@@ -436,7 +461,7 @@ void test9743()
}
/******************************************/
-// 9747
+// https://issues.dlang.org/show_bug.cgi?id=9747
void foo9747A(T)(T[4]) {}
void foo9747C(size_t dim)(char[dim]) {}
@@ -454,7 +479,7 @@ void test9747()
}
/******************************************/
-// 12876
+// https://issues.dlang.org/show_bug.cgi?id=12876
void test12876()
{
@@ -467,24 +492,24 @@ void test12876()
}
/******************************************/
-// 13775
+// https://issues.dlang.org/show_bug.cgi?id=13775
void test13775()
{
ubyte[4] ubytes = [1,2,3,4];
- // CT-known slicing (issue 3652)
+ // CT-known slicing (https://issues.dlang.org/show_bug.cgi?id=3652)
auto ok1 = cast(ubyte[2]) ubytes[0 .. 2];
assert(ok1 == [1, 2]);
- // CT-known slicing with implicit conversion of SliceExp::e1 (issue 13154)
+ // CT-known slicing with implicit conversion of SliceExp::e1 (https://issues.dlang.org/show_bug.cgi?id=13154)
enum double[] arr = [1.0, 2.0, 3.0];
auto ok2 = cast(float[2]) [1.0, 2.0, 3.0][0..2];
auto ok3 = cast(float[2]) arr[1..3]; // currently this is accepted
assert(ok2 == [1f, 2f]);
assert(ok3 == [2f, 3f]);
- // CT-known slicing with type coercing (issue 13775)
+ // CT-known slicing with type coercing (https://issues.dlang.org/show_bug.cgi?id=13775)
auto ok4 = cast( byte[2]) ubytes[0 .. 2]; // CT-known slicing + type coercing
auto ok5 = cast(short[1]) ubytes[0 .. 2]; // CT-known slicing + type coercing
assert(ok4 == [1, 2]);
@@ -493,6 +518,29 @@ void test13775()
}
/******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15889
+// Array bounds check should report index and length
+void test15889()
+{
+ int[] a = new int[2];
+
+ try {
+ a[3] = 40;
+ } catch (ArrayIndexError e) {
+ assert(e.index == 3);
+ assert(e.length == 2);
+ }
+
+ try {
+ a[1 .. 4] = 50;
+ } catch (ArraySliceError e) {
+ assert(e.lower == 1);
+ assert(e.upper == 4);
+ assert(e.length == 2);
+ }
+}
+
+/******************************************/
int main()
{
@@ -504,6 +552,7 @@ int main()
test9743();
test9747();
test13775();
+ test15889();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/testbtst.d b/gcc/testsuite/gdc.test/runnable/testbtst.d
new file mode 100644
index 0000000..a6967f6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/testbtst.d
@@ -0,0 +1,156 @@
+/* PERMUTE_ARGS: -O
+ * https://issues.dlang.org/show_bug.cgi?id=19813
+ */
+
+struct BitArray
+{
+ import core.bitop : btc, bts, btr, bsf, bt;
+
+ size_t _len;
+ size_t* _ptr;
+ enum bitsPerSizeT = size_t.sizeof * 8;
+
+ static size_t lenToDim(size_t len) @nogc pure nothrow @safe
+ {
+ return (len + (bitsPerSizeT-1)) / bitsPerSizeT;
+ }
+
+ this(in bool[] ba) nothrow pure
+ {
+ length = ba.length;
+ foreach (i, b; ba)
+ {
+ if (b)
+ bts(_ptr, i);
+ else
+ btr(_ptr, i);
+ }
+ }
+
+ @property size_t length(size_t newlen) pure nothrow @system
+ {
+ if (newlen != _len)
+ {
+ size_t olddim = lenToDim(_len);
+ immutable newdim = lenToDim(newlen);
+
+ if (newdim != olddim)
+ {
+ // Create a fake array so we can use D's realloc machinery
+ auto b = _ptr[0 .. olddim];
+ b.length = newdim; // realloc
+ _ptr = b.ptr;
+ }
+
+ _len = newlen;
+ }
+ return _len;
+ }
+
+ int opCmp(ref BitArray a2) const @nogc pure nothrow
+ {
+ const lesser = this._len < a2._len ? &this : &a2;
+ immutable fullWords = lesser._len / lesser.bitsPerSizeT;
+ immutable endBits = lesser._len % lesser.bitsPerSizeT;
+ auto p1 = this._ptr;
+ auto p2 = a2._ptr;
+
+ foreach (i; 0 .. fullWords)
+ {
+ if (p1[i] != p2[i])
+ {
+ return p1[i] & (size_t(1) << bsf(p1[i] ^ p2[i])) ? 1 : -1;
+ }
+ }
+
+ if (endBits)
+ {
+ immutable i = fullWords;
+ immutable diff = p1[i] ^ p2[i];
+ if (diff)
+ {
+ immutable index = bsf(diff);
+ if (index < endBits)
+ {
+ // This gets optimized into OPbtst, and was doing it incorrectly
+ return p1[i] & (size_t(1) << index) ? 1 : -1;
+ }
+ }
+ }
+
+ return -1;
+ }
+}
+
+void test1()
+{
+ bool[] ba = [1,0,1,0,1];
+ bool[] bd = [1,0,1,1,1];
+
+ auto a = BitArray(ba);
+ auto d = BitArray(bd);
+
+ assert(a < d);
+}
+
+/***************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=18748
+
+int bt_32_imm(in uint* p)
+{
+ enum bitnum = 1;
+ return ((p[bitnum >> 5] & (1 << (bitnum & 31)))) != 0;
+}
+
+void test18748()
+{
+ version (linux)
+ {
+ import core.sys.posix.sys.mman;
+ import core.sys.posix.unistd;
+ // Allocate two pages.
+ immutable sz = 2 * sysconf(_SC_PAGESIZE);
+ auto m = mmap(null, sz, PROT_READ, MAP_PRIVATE | MAP_ANON, -1, 0);
+ // Discard the higher page. It becomes unreadable.
+ munmap(m + sz / 2, sz / 2);
+ // Try looking at the last 4 bytes of the readable page.
+ uint* p = cast(uint*) (m + sz / 2 - uint.sizeof);
+ bt_32_imm(p);
+ munmap(m, sz / 2); // Free the readable page.
+ }
+}
+
+/***************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=18749
+
+ulong f(ulong* p, uint shift)
+{
+ return (*p >> shift) & 1;
+}
+
+ulong g(ulong* p, ulong shift)
+{
+ return f(p, cast(uint) shift);
+}
+
+void test18749()
+{
+ enum shift = uint.max + 1L;
+ assert(cast(uint) shift == 0);
+ ulong s = 1;
+ assert(g(&s, shift));
+}
+
+
+/***************************************/
+
+int main()
+{
+ test1();
+ test18748();
+ test18749();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/testcgelem.d b/gcc/testsuite/gdc.test/runnable/testcgelem.d
new file mode 100644
index 0000000..b5c7f7d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/testcgelem.d
@@ -0,0 +1,47 @@
+/*
+REQUIRED_ARGS: -mcpu=native -preview=intpromote
+PERMUTE_ARGS: -O -inline -release
+*/
+
+/***
+ * Do coverage testing of cgelem.d
+ * Check coverage here:
+ * https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/cgelem.d
+ */
+
+import core.stdc.stdio;
+
+template tuple(A...) { alias tuple = A; }
+
+/*************************************************/
+
+void test_eladdr()
+{
+ // & (*p1 = e) => ((*(t = p1) = e), t)
+ int i = 4;
+ int* p1 = &i;
+ int e = 5;
+ auto x = &(*p1 = e);
+ assert(i == 5);
+ assert(x == p1);
+}
+
+/*************************************************/
+
+void test_elneg()
+{
+ static int i = 3;
+ int j = - -i;
+ assert(i == j);
+}
+
+/*************************************************/
+
+int main()
+{
+ test_eladdr();
+ test_elneg();
+
+ printf("Success\n");
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/testclass.d b/gcc/testsuite/gdc.test/runnable/testclass.d
index c5480da..cd8dd84 100644
--- a/gcc/testsuite/gdc.test/runnable/testclass.d
+++ b/gcc/testsuite/gdc.test/runnable/testclass.d
@@ -1,7 +1,13 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
extern(C) int printf(const char*, ...);
/******************************************/
-// 12078
+// https://issues.dlang.org/show_bug.cgi?id=12078
class B12078(T)
{
@@ -26,7 +32,7 @@ void test12078()
}
/******************************************/
-// 12143
+// https://issues.dlang.org/show_bug.cgi?id=12143
class Node12143
{
@@ -39,7 +45,7 @@ class Type12143 : Node12143 {}
class Class12143 : Type12143 {}
/***************************************************/
-// 13353
+// https://issues.dlang.org/show_bug.cgi?id=13353
interface Base13353(T)
{
@@ -57,7 +63,7 @@ class Concrete13353 : Derived13353
}
/***************************************************/
-// 15733
+// https://issues.dlang.org/show_bug.cgi?id=15733
class CStmt15733 : CNode15733 {}
class CDecl15733 : CStmt15733 {}
@@ -71,8 +77,48 @@ template IMix(T){ mixin("static " ~ T.stringof ~ " x;"); }
/***************************************************/
+// https://issues.dlang.org/show_bug.zip?id=20716
+
+extern(C++):
+
+struct S20716
+{
+ void* s;
+ ~this() {}
+ // or this(this) {}
+}
+
+interface I20716
+{
+ S20716 x();
+}
+
+final class C20716 : I20716
+{
+ int l = 3;
+
+ S20716 x()
+ {
+ //printf("this = %p, %p\n", this, &this.l);
+ assert(l == 3); //fails
+ return S20716.init;
+ }
+}
+
+extern(D):
+
+void test20716()
+{
+ auto s = new C20716().x;
+ auto t = new C20716().I20716.x;
+}
+
+/***************************************************/
+
int main()
{
+ test20716();
+
printf("Success\n");
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/testconst.d b/gcc/testsuite/gdc.test/runnable/testconst.d
index 7ec4245..5c0e75d 100644
--- a/gcc/testsuite/gdc.test/runnable/testconst.d
+++ b/gcc/testsuite/gdc.test/runnable/testconst.d
@@ -53,7 +53,7 @@ template TypeTuple(T...) { alias T TypeTuple; }
void showf(string f)
{
- printf("%.*s\n", f.length, f.ptr);
+ printf("%.*s\n", cast(int)f.length, f.ptr);
}
/************************************/
@@ -626,7 +626,7 @@ class C42
void test42()
{
- printf("%d\n", C42.classinfo.initializer.length);
+ printf("%zd\n", C42.classinfo.initializer.length);
assert(C42.classinfo.initializer.length == 12 + (void*).sizeof +
(void*).sizeof);
C42 c = new C42;
@@ -963,7 +963,7 @@ void test56()
{
S56 s;
S56 t;
- printf("S56.sizeof = %d\n", S56.sizeof);
+ printf("S56.sizeof = %zd\n", S56.sizeof);
//t = s;
}
@@ -1574,7 +1574,7 @@ void test87()
}
/************************************/
-// 2751
+// https://issues.dlang.org/show_bug.cgi?id=2751
void test88(immutable(int[3]) a)
@@ -1603,7 +1603,7 @@ void test88(immutable(int[3]) a)
}
/************************************/
-// 3748
+// https://issues.dlang.org/show_bug.cgi?id=3748
// version = error8;
// version = error11;
@@ -1878,7 +1878,7 @@ void test3748c(inout int = 1)
}
/************************************/
-// 4968
+// https://issues.dlang.org/show_bug.cgi?id=4968
void test4968()
{
@@ -1924,7 +1924,7 @@ void test4968()
}
/************************************/
-// 1961
+// https://issues.dlang.org/show_bug.cgi?id=1961
inout(char)[] strstr(inout(char)[] source, const(char)[] pattern)
{
@@ -2042,7 +2042,7 @@ void test88()
}
/************************************/
-// 4251
+// https://issues.dlang.org/show_bug.cgi?id=4251
void test4251a()
{
@@ -2185,7 +2185,7 @@ void test4251b()
}
/************************************/
-// 5473
+// https://issues.dlang.org/show_bug.cgi?id=5473
void test5473()
{
@@ -2227,7 +2227,7 @@ void test5473()
}
/************************************/
-// 5493
+// https://issues.dlang.org/show_bug.cgi?id=5493
void test5493()
{
@@ -2282,7 +2282,7 @@ void test5493()
}
/************************************/
-// 5493 + inout
+// https://issues.dlang.org/show_bug.cgi?id=5493 + inout
void test5493inout()
{
@@ -2330,7 +2330,7 @@ void test5493inout()
}
/************************************/
-// 6782
+// https://issues.dlang.org/show_bug.cgi?id=6782
struct Tuple6782(T...)
{
@@ -2368,7 +2368,7 @@ void test6782()
}
/************************************/
-// 6864
+// https://issues.dlang.org/show_bug.cgi?id=6864
int fn6864( const int n) { return 1; }
int fn6864(shared int n) { return 2; }
@@ -2387,7 +2387,7 @@ void test6864()
}
/************************************/
-// 6865
+// https://issues.dlang.org/show_bug.cgi?id=6865
shared(inout(int)) foo6865(shared(inout(int)) n){ return n; }
void test6865()
@@ -2397,7 +2397,7 @@ void test6865()
}
/************************************/
-// 6866
+// https://issues.dlang.org/show_bug.cgi?id=6866
struct S6866
{
@@ -2414,7 +2414,7 @@ void test6866()
}
/************************************/
-// 6867
+// https://issues.dlang.org/show_bug.cgi?id=6867
inout(char)[] test6867(inout(char)[] a)
{
@@ -2428,7 +2428,7 @@ inout(char)[] test6867(inout(char)[] a)
}
/************************************/
-// 6870
+// https://issues.dlang.org/show_bug.cgi?id=6870
void test6870()
{
@@ -2440,7 +2440,8 @@ void test6870()
}
/************************************/
-// 6338, 6922
+// https://issues.dlang.org/show_bug.cgi?id=6338
+// https://issues.dlang.org/show_bug.cgi?id=6922
alias int T;
@@ -2468,7 +2469,7 @@ static assert(is( inout(shared(immutable(T))) == immutable(T) ));
static assert(is( inout(immutable(shared(T))) == immutable(T) ));
/************************************/
-// 6912
+// https://issues.dlang.org/show_bug.cgi?id=6912
void test6912()
{
@@ -2585,7 +2586,7 @@ void test6912()
}
/************************************/
-// 6930
+// https://issues.dlang.org/show_bug.cgi?id=6930
void test6930a()
{
@@ -2657,7 +2658,7 @@ void test6930b(inout int = 0)
}
/************************************/
-// 11868
+// https://issues.dlang.org/show_bug.cgi?id=11868
void f11868(A...)(A) { }
@@ -2673,7 +2674,7 @@ void test11868()
}
/************************************/
-// 11924
+// https://issues.dlang.org/show_bug.cgi?id=11924
inout(StringType) localize11924(StringType)(inout StringType str, string locale)
{
@@ -2695,7 +2696,7 @@ struct S11924
}
/************************************/
-// 11966
+// https://issues.dlang.org/show_bug.cgi?id=11966
inout(char)[] stripped11966 (inout(char)[] path)
{
@@ -2721,7 +2722,7 @@ void test11966()
}
/************************************/
-// 14788
+// https://issues.dlang.org/show_bug.cgi?id=14788
auto make14788(K, V)(inout V[K] aa)
{
@@ -2740,7 +2741,7 @@ void test14788()
}
/************************************/
-// 12089
+// https://issues.dlang.org/show_bug.cgi?id=12089
void foo12089(inout(char[]) a)
{
@@ -2754,7 +2755,7 @@ void decodeImpl12089(S)(auto ref S str)
{}
/************************************/
-// 12524
+// https://issues.dlang.org/show_bug.cgi?id=12524
inout(int) dup12524(inout(const(int)) val)
{
@@ -2771,7 +2772,7 @@ void test12524(inout(int))
}
/************************************/
-// 6941
+// https://issues.dlang.org/show_bug.cgi?id=6941
static assert((const(shared(int[])[])).stringof == "const(shared(int[])[])"); // fail
static assert((const(shared(int[])[])).stringof != "const(shared(const(int[]))[])"); // fail
@@ -2780,7 +2781,7 @@ static assert((inout(shared(int[])[])).stringof == "inout(shared(int[])[])");
static assert((inout(shared(int[])[])).stringof != "inout(shared(inout(int[]))[])"); // fail
/************************************/
-// 6872
+// https://issues.dlang.org/show_bug.cgi?id=6872
static assert((shared(inout(int)[])).stringof == "shared(inout(int)[])");
static assert((shared(inout(const(int)[]))).stringof == "shared(inout(const(int)[]))");
@@ -2788,7 +2789,7 @@ static assert((shared(inout(const(int)[])[])).stringof == "shared(inout(const(in
static assert((shared(inout(const(immutable(int)[])[])[])).stringof == "shared(inout(const(immutable(int)[])[])[])");
/************************************/
-// 6939
+// https://issues.dlang.org/show_bug.cgi?id=6939
void test6939()
{
@@ -2808,7 +2809,7 @@ void test6939()
}
/************************************/
-// 6940
+// https://issues.dlang.org/show_bug.cgi?id=6940
void test6940()
{
@@ -2830,7 +2831,7 @@ void test6940()
}
/************************************/
-// 6982
+// https://issues.dlang.org/show_bug.cgi?id=6982
void test6982()
{
@@ -2847,7 +2848,7 @@ void test6982()
}
/************************************/
-// 7038
+// https://issues.dlang.org/show_bug.cgi?id=7038
static assert(is(S7038 == const));
const struct S7038{ int x; }
@@ -2875,7 +2876,7 @@ void test7038()
}
/************************************/
-// 7105
+// https://issues.dlang.org/show_bug.cgi?id=7105
void copy(inout(int)** tgt, inout(int)* src){ *tgt = src; }
@@ -2909,11 +2910,11 @@ void test7105()
}
/************************************/
-// 7202
+// https://issues.dlang.org/show_bug.cgi?id=7202
void test7202()
{
- void writeln(string s) @system { printf("%.*s\n", s.length, s.ptr); }
+ void writeln(string s) @system { printf("%.*s\n", cast(int)s.length, s.ptr); }
void delegate() @system x = { writeln("I am @system"); };
void delegate() @safe y = { };
auto px = &x;
@@ -2924,7 +2925,7 @@ void test7202()
}
/************************************/
-// 7554
+// https://issues.dlang.org/show_bug.cgi?id=7554
T outer7554(T)(immutable T function(T) pure foo) pure {
pure int inner() {
@@ -2957,7 +2958,7 @@ void test7518() {
}
/************************************/
-// 7669
+// https://issues.dlang.org/show_bug.cgi?id=7669
shared(inout U)[n] id7669(U, size_t n)( shared(inout U)[n] );
void test7669()
@@ -2966,7 +2967,7 @@ void test7669()
}
/************************************/
-// 7757
+// https://issues.dlang.org/show_bug.cgi?id=7757
inout(int) foo7757a(int x, lazy inout(int) def) { return def; }
inout(int)[] foo7757b(int x, lazy inout(int)[] def) { return def; }
@@ -2999,7 +3000,7 @@ void test7757()
}
/************************************/
-// 8098
+// https://issues.dlang.org/show_bug.cgi?id=8098
class Outer8098
{
@@ -3033,7 +3034,7 @@ void test8098()
}
/************************************/
-// 8099
+// https://issues.dlang.org/show_bug.cgi?id=8099
void test8099()
{
@@ -3068,7 +3069,7 @@ void test8099()
}
/************************************/
-// 8201
+// https://issues.dlang.org/show_bug.cgi?id=8201
void test8201()
{
@@ -3080,7 +3081,7 @@ void test8201()
}
/************************************/
-// 8212
+// https://issues.dlang.org/show_bug.cgi?id=8212
struct S8212 { int x; }
@@ -3095,7 +3096,7 @@ void test8212()
}
/************************************/
-// 8366
+// https://issues.dlang.org/show_bug.cgi?id=8366
class B8366
{
@@ -3115,7 +3116,7 @@ class C8366a : B8366
class C8366b : B8366
{
bool foo(in Object o) { return false; }
- alias super.foo foo;
+ alias typeof(super).foo foo;
bool foo(in Object o) immutable { return false; }
bool foo(in Object o) shared { return false; }
bool foo(in Object o) shared const { return false; }
@@ -3146,7 +3147,7 @@ void test8366()
}
/************************************/
-// 8408
+// https://issues.dlang.org/show_bug.cgi?id=8408
template hasMutableIndirection8408(T)
{
@@ -3211,18 +3212,20 @@ void test8408()
struct T2 { S2 s; }
struct T3 { S1 s1; S2 s2; }
- test!(int , true )();
- test!(int[3], true )();
+/*
+ test!(int , false)();
+ test!(int[3], false)();
test!(C , false)();
- test!(S1 , true )();
+ test!(S1 , false)();
test!(S2 , false)();
- test!(T1 , true )();
+ test!(T1 , false)();
test!(T2 , false)();
test!(T3 , false)();
+*/
}
/************************************/
-// 8688
+// https://issues.dlang.org/show_bug.cgi?id=8688
void test8688()
{
@@ -3236,7 +3239,7 @@ void test8688()
}
/************************************/
-// 10946 (regression by fixing bug 8688, from 2.061)
+// https://issues.dlang.org/show_bug.cgi?id=10946 (regression by fixing bug 8688, from 2.061)
enum xlen10946 = 4;
alias immutable(char)[xlen10946] e3;
@@ -3246,12 +3249,12 @@ alias immutable(char)[vlen10946] i3;
alias immutable(char[vlen10946]) i4; // NG -> OK
/************************************/
-// 9046
+// https://issues.dlang.org/show_bug.cgi?id=9046
void test9046()
{
foreach (T; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, char, wchar, dchar,
- float, double, real, ifloat, idouble, ireal, cfloat, cdouble, creal))
+ float, double, real))
foreach (U; TypeTuple!(T, const T, immutable T, shared T, shared const T, inout T, shared inout T))
{
static assert(is(typeof(U.init) == U));
@@ -3285,7 +3288,7 @@ void test9046()
}
/************************************/
-// 9090
+// https://issues.dlang.org/show_bug.cgi?id=9090
void test9090()
{
@@ -3296,7 +3299,7 @@ void test9090()
}
/************************************/
-// 9461
+// https://issues.dlang.org/show_bug.cgi?id=9461
void test9461()
{
@@ -3328,15 +3331,15 @@ void test9209() {
}
/************************************/
-// 10758
+// https://issues.dlang.org/show_bug.cgi?id=10758
struct X10758
{
static:
inout(int) screwUpVal(ref inout(int) wx) { return wx; }
- ref inout(int) screwUpRef(ref inout(int) wx) { return wx; }
- inout(int)* screwUpPtr(ref inout(int) wx) { return &wx; }
- inout(int)[] screwUpArr(ref inout(int) wx) { return (&wx)[0 .. 1]; }
+ ref inout(int) screwUpRef(return ref inout(int) wx) { return wx; }
+ inout(int)* screwUpPtr(return ref inout(int) wx) { return &wx; }
+ inout(int)[] screwUpArr(return ref inout(int) wx) { return (&wx)[0 .. 1]; }
}
struct S10758
@@ -3471,7 +3474,7 @@ void test10758(ref inout(int) wx, inout(int)* wp, inout(int)[] wa, inout(S10758)
}
/************************************/
-// 10761
+// https://issues.dlang.org/show_bug.cgi?id=10761
inout(int)* function(inout(int)*) fptr10761(inout(int)*)
{
@@ -3545,7 +3548,7 @@ void test10761()
}
/************************************/
-// 11226
+// https://issues.dlang.org/show_bug.cgi?id=11226
void test11226()
{
@@ -3573,7 +3576,7 @@ void test11226()
}
/************************************/
-// 11257
+// https://issues.dlang.org/show_bug.cgi?id=11257
struct R11257
{
@@ -3590,7 +3593,7 @@ void test11257()
}
/************************************/
-// 11215
+// https://issues.dlang.org/show_bug.cgi?id=11215
shared(inout(void)**) f11215(inout int);
@@ -3598,7 +3601,7 @@ static assert(is(typeof(f11215(0)) == shared(void**)));
static assert(is(typeof(f11215((const int).init)) == shared(const(void)**)));
/************************************/
-// 11489
+// https://issues.dlang.org/show_bug.cgi?id=11489
void test11489(inout int = 0)
{
@@ -3671,7 +3674,7 @@ void test11489(inout int = 0)
}
/************************************/
-// 11768
+// https://issues.dlang.org/show_bug.cgi?id=11768
void test11768(inout int = 0)
{
@@ -3683,7 +3686,7 @@ void test11768(inout int = 0)
}
/************************************/
-// 12403
+// https://issues.dlang.org/show_bug.cgi?id=12403
void test12403()
{
@@ -3698,7 +3701,7 @@ void test12403()
}
/************************************/
-// 13011
+// https://issues.dlang.org/show_bug.cgi?id=13011
void test13011()
{
@@ -3712,7 +3715,7 @@ void test13011()
}
/************************************/
-// 13030
+// https://issues.dlang.org/show_bug.cgi?id=13030
void va13030(Args...)(const Args args) {}
@@ -3722,7 +3725,8 @@ void func13030(int delegate(int n) a)
}
/************************************/
-// 13802 & 13803
+// https://issues.dlang.org/show_bug.cgi?id=13802
+// https://issues.dlang.org/show_bug.cgi?id=13803
static assert(( string ).stringof == "string" );
static assert(( string[] ).stringof == "string[]" );
diff --git a/gcc/testsuite/gdc.test/runnable/testcontracts.d b/gcc/testsuite/gdc.test/runnable/testcontracts.d
index f99a10a..7869691 100644
--- a/gcc/testsuite/gdc.test/runnable/testcontracts.d
+++ b/gcc/testsuite/gdc.test/runnable/testcontracts.d
@@ -1,5 +1,21 @@
-// PERMUTE_ARGS: -inline -g -O
-
+/* PERMUTE_ARGS: -inline -g -O
+TEST_OUTPUT:
+---
+runnable/testcontracts.d(323): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+runnable/testcontracts.d(324): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+runnable/testcontracts.d(325): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+runnable/testcontracts.d(326): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+runnable/testcontracts.d(328): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+runnable/testcontracts.d(329): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+runnable/testcontracts.d(330): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+runnable/testcontracts.d(331): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+runnable/testcontracts.d(502): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+runnable/testcontracts.d(503): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+runnable/testcontracts.d(504): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+runnable/testcontracts.d(505): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+runnable/testcontracts.d(505): Deprecation: Usage of the `body` keyword is deprecated. Use `do` instead.
+---
+*/
extern(C) int printf(const char*, ...);
/*******************************************/
@@ -192,7 +208,7 @@ void test5()
}
/*******************************************/
-// 3273
+// https://issues.dlang.org/show_bug.cgi?id=3273
// original case
struct Bug3273
@@ -205,7 +221,7 @@ struct Bug3273
ref int func3273()
out(r)
{
- // Regression check of issue 3390
+ // Regression check of https://issues.dlang.org/show_bug.cgi?id=3390
static assert(!__traits(compiles, r = 1));
}
do
@@ -318,13 +334,13 @@ void test9()
/*******************************************/
-auto test10() body { return 3; }
-auto test11()() body { return 3; }
+auto test10() do { return 3; }
+auto test11()() do { return 3; }
auto test12()
{
- auto test10() body { return 3; }
- auto test11()() body { return 3; }
+ auto test10() do { return 3; }
+ auto test11()() do { return 3; }
return 3;
}
@@ -335,7 +351,7 @@ void test13()
}
/*******************************************/
-// 4785
+// https://issues.dlang.org/show_bug.cgi?id=4785
int cnt;
@@ -360,7 +376,7 @@ void test4785()
}
/*******************************************/
-// 5039
+// https://issues.dlang.org/show_bug.cgi?id=5039
class C5039 {
int x;
@@ -375,7 +391,7 @@ class C5039 {
}
/*******************************************/
-// 5204
+// https://issues.dlang.org/show_bug.cgi?id=5204
interface IFoo5204
{
@@ -388,7 +404,7 @@ class Foo5204 : IFoo5204
}
/*******************************************/
-// 6417
+// https://issues.dlang.org/show_bug.cgi?id=6417
class Bug6417
{
@@ -422,7 +438,7 @@ void test6417()
}
/*******************************************/
-// 6549
+// https://issues.dlang.org/show_bug.cgi?id=6549
class C6549
{
@@ -472,7 +488,7 @@ void test6549()
}
/*******************************************/
-// 7218
+// https://issues.dlang.org/show_bug.cgi?id=7218
void test7218()
{
@@ -491,7 +507,55 @@ void test7218()
}
/*******************************************/
-// 7517
+// https://issues.dlang.org/show_bug.cgi?id=7335
+
+class A7335
+{
+ int mValue = 10;
+
+ void setValue(int newValue)
+ in { }
+ out { assert(mValue == 3); }
+ do
+ {
+ mValue = newValue;
+ }
+}
+
+class B7335 : A7335
+{
+ override void setValue(int newValue)
+ in { assert(false); }
+ out { assert(mValue == 3); }
+ do
+ {
+ mValue = newValue;
+ }
+}
+
+class C7335 : A7335
+{
+ override void setValue(int newValue)
+ in { int a = newValue; }
+ out { assert(mValue == 3); }
+ do
+ {
+ mValue = newValue;
+ }
+}
+
+void test7335()
+{
+ A7335 aObject = new B7335();
+ aObject.setValue(3);
+
+ A7335 bObject = new C7335();
+ bObject.setValue(3); // <<<<< will crash because undefined mValue in the
+ // A7335.setValue().out-block.
+}
+
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7517
void test7517()
{
@@ -575,7 +639,7 @@ void test7517()
}
/*******************************************/
-// 7699
+// https://issues.dlang.org/show_bug.cgi?id=7699
class P7699
{
@@ -589,7 +653,7 @@ class D7699 : P7699
}
/*******************************************/
-// 7883
+// https://issues.dlang.org/show_bug.cgi?id=7883
// Segmentation fault
class AA7883
@@ -665,7 +729,7 @@ class DC7883 : CC7883
}
/*******************************************/
-// 7892
+// https://issues.dlang.org/show_bug.cgi?id=7892
struct S7892
{
@@ -695,7 +759,7 @@ class C7892
}
/*******************************************/
-// 8066
+// https://issues.dlang.org/show_bug.cgi?id=8066
struct CLCommandQueue
{
@@ -709,7 +773,7 @@ struct CLCommandQueue
}
/*******************************************/
-// 8073
+// https://issues.dlang.org/show_bug.cgi?id=8073
struct Container8073
{
@@ -748,7 +812,7 @@ void test8073()
}
/*******************************************/
-// 8093
+// https://issues.dlang.org/show_bug.cgi?id=8093
void test8093()
{
@@ -785,7 +849,7 @@ void test8093()
}
/*******************************************/
-// 9383
+// https://issues.dlang.org/show_bug.cgi?id=9383
class A9383
{
@@ -871,7 +935,8 @@ void test9383()
}
/*******************************************/
-// 15524 - Different from issue 9383 cases, closed variable size is bigger than REGSIZE.
+// https://issues.dlang.org/show_bug.cgi?id=15524
+// Different from issue 9383 cases, closed variable size is bigger than REGSIZE.
class A15524
{
@@ -1004,7 +1069,7 @@ class Test15524b
}
/*******************************************/
-// 10479
+// https://issues.dlang.org/show_bug.cgi?id=10479
class B10479
{
@@ -1018,7 +1083,7 @@ class D10479 : B10479
}
/*******************************************/
-// 10596
+// https://issues.dlang.org/show_bug.cgi?id=10596
class Foo10596
{
@@ -1028,7 +1093,7 @@ class Foo10596
}
/*******************************************/
-// 10721
+// https://issues.dlang.org/show_bug.cgi?id=10721
class Foo10721
{
@@ -1049,7 +1114,7 @@ struct Bar10721
}
/*******************************************/
-// 10981
+// https://issues.dlang.org/show_bug.cgi?id=10981
class C10981
{
@@ -1060,7 +1125,7 @@ class C10981
}
/*******************************************/
-// 14779
+// https://issues.dlang.org/show_bug.cgi?id=14779
class C14779
{
@@ -1079,6 +1144,79 @@ void test14779()
}
/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15984
+
+I15984 i15984;
+C15984 c15984;
+
+void check15984(T)(const char* s, T this_, int i)
+{
+ printf("%s this = %p, i = %d\n", s, this_, i);
+ static if (is(T == I15984)) assert(this_ is i15984);
+ else static if (is(T == C15984)) assert(this_ is c15984);
+ else static assert(0);
+ assert(i == 5);
+}
+
+interface I15984
+{
+ void f1(int i)
+ in { check15984("I.f1.i", this, i); assert(0); }
+ out { check15984("I.f1.o", this, i); }
+
+ int[3] f2(int i)
+ in { check15984("I.f2.i", this, i); assert(0); }
+ out { check15984("I.f2.o", this, i); }
+
+ void f3(int i)
+ in { void nested() { check15984("I.f3.i", this, i); } nested(); assert(0); }
+ out { void nested() { check15984("I.f3.o", this, i); } nested(); }
+
+ void f4(out int i, lazy int j)
+ in { }
+ out { }
+}
+
+class C15984 : I15984
+{
+ void f1(int i)
+ in { check15984("C.f1.i", this, i); }
+ out { check15984("C.f1.o", this, i); }
+ do { check15984("C.f1 ", this, i); }
+
+ int[3] f2(int i)
+ in { check15984("C.f2.i", this, i); }
+ out { check15984("C.f2.o", this, i); }
+ do { check15984("C.f2 ", this, i); return [0,0,0]; }
+
+ void f3(int i)
+ in { void nested() { check15984("C.f3.i", this, i); } nested(); }
+ out { void nested() { check15984("C.f3.o", this, i); } nested(); }
+ do { check15984("C.f3 ", this, i); }
+
+ void f4(out int i, lazy int j)
+ in { assert(0); }
+ do { i = 10; }
+}
+
+void test15984()
+{
+ c15984 = new C15984;
+ i15984 = c15984;
+ printf("i = %p\n", i15984);
+ printf("c = %p\n", c15984);
+ printf("====\n");
+ i15984.f1(5);
+ printf("====\n");
+ i15984.f2(5);
+ printf("====\n");
+ i15984.f3(5);
+ int i;
+ i15984.f4(i, 1);
+ assert(i == 10);
+}
+
+/*******************************************/
//******************************************/
// DIP 1009
@@ -1170,6 +1308,7 @@ int main()
test6417();
test6549();
test7218();
+ test7335();
test7517();
test8073();
test8093();
@@ -1177,6 +1316,7 @@ int main()
test15524();
test15524a();
test14779();
+ test15984();
dip1009_1(1);
dip1009_2(1);
dip1009_3(1);
diff --git a/gcc/testsuite/gdc.test/runnable/testdefault_after_variadic.d b/gcc/testsuite/gdc.test/runnable/testdefault_after_variadic.d
new file mode 100644
index 0000000..f0bade2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/testdefault_after_variadic.d
@@ -0,0 +1,98 @@
+/*
+PERMUTE_ARGS:
+*/
+
+version (with_phobos) import std.conv : text;
+
+struct Tuple(T...)
+{
+ T expand;
+ alias expand this;
+}
+
+auto tuple(T...)(T t)
+{
+ return Tuple!T(t);
+}
+
+void fun0(U, T...)(U gold, int b_gold, T a, int b)
+{
+ assert(tuple(a) == gold);
+ assert(b == b_gold);
+}
+
+void fun(U, T...)(U gold, T a, int b = 1)
+{
+ assert(tuple(a) == gold);
+ assert(b == 1);
+}
+
+void fun2(U, V, T...)(U gold, V gold2, T a, string file = __FILE__, int line = __LINE__)
+{
+ assert(tuple(a) == gold);
+ assert(tuple(file, line) == gold2);
+}
+
+void fun3(int[] gold, int[] a...)
+{
+ assert(gold == a);
+}
+
+void fun4(T...)(size_t length_gold, int b_gold, T a, int b = 1)
+{
+ assert(T.length == length_gold);
+ assert(b == b_gold);
+}
+
+// Example in changelog
+string log(T...)(T a, string file = __FILE__, int line = __LINE__)
+{
+ return text(file, ":", line, " ", a);
+}
+
+void fun_constraint(T...)(T a, string b = "bar") if (T.length == 1)
+{
+}
+
+/+
+NOTE: this is disallowed by the parser:
+void fun5(int[] gold, int[] a ..., int b = 1)
+{
+ assert(gold==a);
+ assert(b==1);
+}
++/
+
+void main()
+{
+ fun0(tuple(10), 7, 10, 7);
+
+ fun(tuple());
+ fun(tuple(10), 10);
+ fun(tuple(10, 11), 10, 11);
+
+ fun2(tuple(10), tuple(__FILE__, __LINE__), 10);
+
+ fun3([1, 2, 3], 1, 2, 3);
+
+ fun_constraint(1);
+ assert(!__traits(compiles, fun_constraint(1, "baz")));
+
+ version (with_phobos)
+ assert(log(10, "abc") == text(__FILE__, ":", __LINE__, " 10abc"));
+
+ // IFTI: `b` is always default-set
+ fun4(0, 1);
+ fun4(1, 1, 10);
+ fun4(2, 1, 10, 11);
+
+ // with explicit instantiation, and default-set `b`
+ fun4!int(1, 1, 10);
+ fun4!(int, int)(2, 1, 10, 11);
+
+ // with explicit instantiation, and over-ridden `b`
+ fun4!int(1, 100, 10, 100);
+ fun4!(int, int)(2, 100, 10, 11, 100);
+
+ // fun5([1,2,3], 1,2,3);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/testdstress.d b/gcc/testsuite/gdc.test/runnable/testdstress.d
index a416b8a..6ca5500 100644
--- a/gcc/testsuite/gdc.test/runnable/testdstress.d
+++ b/gcc/testsuite/gdc.test/runnable/testdstress.d
@@ -1,5 +1,10 @@
-// RUNNABLE_PHOBOS_TEST
// PERMUTE_ARGS:
+/*
+TEST_OUTPUT:
+---
+runnable/testdstress.d(666): Deprecation: The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+---
+*/
module run.module_01;
@@ -8,6 +13,7 @@ import core.exception;
import core.vararg;
extern(C) void* malloc(size_t size);
+extern(C) int printf(const char*, ...);
/* ================================ */
@@ -23,7 +29,7 @@ void test1()
assert(1);
}out (result){
assert(result.i==1);
- }body{
+ }do{
MyStruct s;
s.i = 1;
return s;
@@ -37,7 +43,7 @@ void foo2()
in{
assert(0);
}
-body{
+do{
}
void test2()
@@ -452,7 +458,7 @@ void test21()
/* ================================ */
-scope class AutoClass{
+class AutoClass{
}
void test22()
@@ -467,7 +473,7 @@ void test22()
int status23;
-scope class C23{
+class C23{
~this(){
assert(status23==0);
status23--;
@@ -493,7 +499,7 @@ void test23()
int status24;
-scope class C24{
+class C24{
this(){
assert(status24==0);
status24+=2;
@@ -525,7 +531,7 @@ void test24()
/* ================================ */
struct S25{
- S25 opSub(int i) { S25 s; return s; }
+ S25 opBinary(string op)(int i) if (op == "-") { S25 s; return s; }
}
struct GeomObject{
@@ -539,7 +545,7 @@ void extractTriangles(GeomObject g)
void foobar()
{
g.mesh - g.xlate;
- //g.mesh.opSub(g.xlate);
+ //g.mesh.opBinary!("-")(g.xlate);
}
foobar();
@@ -672,7 +678,7 @@ void test30()
void test31()
{
- string str = x"F0 9D 83 93"; // utf-8 for U+1D0D3
+ string str = "\xF0\x9D\x83\x93"; // utf-8 for U+1D0D3
int count=0;
dchar tmp;
@@ -686,8 +692,6 @@ void test31()
/* ================================ */
-import std.stdio;
-
union MyUnion32
{
int i;
@@ -698,31 +702,12 @@ void test32()
{
TypeInfo ti = typeid(MyUnion32*);
assert(!(ti is null));
- writefln("%s %d %d", ti.toString(), ti.tsize, (MyUnion32*).sizeof);
assert(ti.tsize==(MyUnion32*).sizeof);
assert(ti.toString()=="run.module_01.MyUnion32*");
}
/* ================================ */
-void test33()
-{
- creal a=1.3L+9.7Li;
- assert(a.re == 1.3L);
- assert(a.im == 9.7L);
-}
-
-/* ================================ */
-
-void test34()
-{
- creal c = 2.7L + 0i;
- assert(c.re==2.7L);
- assert(c.im==0.0L);
-}
-
-/* ================================ */
-
void test35()
{
try{
@@ -845,15 +830,8 @@ int counter41;
class C41{
this(){
printf("this: counter41 = %d\n", counter41);
- assert(counter41==1);
- counter41+=2;
- }
-
- new(size_t size){
- printf("new: size = %d\n", size);
assert(counter41==0);
- counter41++;
- return malloc(size);
+ counter41+=2;
}
}
@@ -862,7 +840,7 @@ void test41()
C41 c;
assert(counter41==0);
c = new C41();
- assert(counter41==3);
+ assert(counter41==2);
}
/* ================================ */
@@ -917,8 +895,6 @@ int main()
test30();
test31();
test32();
- test33();
- test34();
test35();
test36();
test37();
diff --git a/gcc/testsuite/gdc.test/runnable/testdt.d b/gcc/testsuite/gdc.test/runnable/testdt.d
index 8224abc..4b5338f 100644
--- a/gcc/testsuite/gdc.test/runnable/testdt.d
+++ b/gcc/testsuite/gdc.test/runnable/testdt.d
@@ -2,7 +2,7 @@
/******************************************/
-static int bigarray[100][100];
+static int[100][100] bigarray;
void test1()
{
@@ -17,7 +17,7 @@ void test1()
}
/******************************************/
-// 10629
+// https://issues.dlang.org/show_bug.cgi?id=10629
class Foo10629 {}
@@ -27,7 +27,7 @@ struct Bar10629
}
/******************************************/
-// 11233
+// https://issues.dlang.org/show_bug.cgi?id=11233
struct S11233
{
@@ -35,7 +35,7 @@ struct S11233
}
/******************************************/
-// 11672
+// https://issues.dlang.org/show_bug.cgi?id=11672
void test11672()
{
@@ -50,7 +50,7 @@ void test11672()
}
/******************************************/
-// 12509
+// https://issues.dlang.org/show_bug.cgi?id=12509
struct A12509
{
@@ -62,7 +62,7 @@ struct B12509
}
/******************************************/
-// 13505
+// https://issues.dlang.org/show_bug.cgi?id=13505
class C13505 { void[10] x; }
struct S13505 { void[10] x; }
@@ -74,7 +74,7 @@ void test13505()
}
/******************************************/
-// 14699
+// https://issues.dlang.org/show_bug.cgi?id=14699
struct S14699a { ubyte[0][10] values; }
struct S14699b { S14699a tbl; }
@@ -88,7 +88,7 @@ void test14699()
}
/******************************************/
-// 14805
+// https://issues.dlang.org/show_bug.cgi?id=14805
struct S14805
{
@@ -97,7 +97,7 @@ struct S14805
auto a14805 = new S14805[513*513];
/******************************************/
-// 15664
+// https://issues.dlang.org/show_bug.cgi?id=15664
struct Data15664A
{
diff --git a/gcc/testsuite/gdc.test/runnable/testenum.d b/gcc/testsuite/gdc.test/runnable/testenum.d
index 0532744..a752951 100644
--- a/gcc/testsuite/gdc.test/runnable/testenum.d
+++ b/gcc/testsuite/gdc.test/runnable/testenum.d
@@ -109,7 +109,7 @@ void test6()
}
/**********************************************/
-// 2407
+// https://issues.dlang.org/show_bug.cgi?id=2407
int i2407;
@@ -223,7 +223,7 @@ void test2407()
}
/**********************************************/
-// 3096
+// https://issues.dlang.org/show_bug.cgi?id=3096
void test3096()
{
@@ -252,30 +252,30 @@ void test3096()
}
/**********************************************/
-// 7719
+// https://issues.dlang.org/show_bug.cgi?id=7719
enum foo7719 = bar7719;
enum { bar7719 = 1 }
/**********************************************/
-// 9845
+// https://issues.dlang.org/show_bug.cgi?id=9845
enum { A9845 = B9845 }
enum { B9845 = 1 }
/**********************************************/
-// 9846
+// https://issues.dlang.org/show_bug.cgi?id=9846
const int A9846 = B9846;
enum { B9846 = 1 }
/**********************************************/
-// 10105
+// https://issues.dlang.org/show_bug.cgi?id=10105
enum E10105 : char[1] { a = "a" }
/**********************************************/
-// 10113
+// https://issues.dlang.org/show_bug.cgi?id=10113
enum E10113 : string
{
@@ -299,7 +299,7 @@ void test10113()
}
/**********************************************/
-// 10503
+// https://issues.dlang.org/show_bug.cgi?id=10503
@property int octal10503(string num)()
{
@@ -313,7 +313,7 @@ enum
}
/**********************************************/
-// 10505
+// https://issues.dlang.org/show_bug.cgi?id=10505
enum
{
@@ -331,7 +331,7 @@ static assert(is(typeof(d10505) == int));
static assert(is(typeof(e10505) == typeof(null)));
/**********************************************/
-// 10561
+// https://issues.dlang.org/show_bug.cgi?id=10561
void test10561()
{
@@ -367,7 +367,7 @@ void test10561()
}
/**********************************************/
-// 10612
+// https://issues.dlang.org/show_bug.cgi?id=10612
int[E10612] ie10612;
E10612[int] ei10612;
@@ -376,7 +376,7 @@ E10612[E10612] ee10612;
enum E10612 { a }
/**********************************************/
-// 10788
+// https://issues.dlang.org/show_bug.cgi?id=10788
enum v10788 = e10788;
enum : int { e10788 }
@@ -417,7 +417,7 @@ void test8()
}
/**********************************************/
-// 13220
+// https://issues.dlang.org/show_bug.cgi?id=13220
enum E13220a;
@(1) enum E13220b;
diff --git a/gcc/testsuite/gdc.test/runnable/testfile.d b/gcc/testsuite/gdc.test/runnable/testfile.d
deleted file mode 100644
index 6f56804..0000000
--- a/gcc/testsuite/gdc.test/runnable/testfile.d
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUNNABLE_PHOBOS_TEST
-// PERMUTE_ARGS:
-
-import std.file;
-import std.stdio;
-
-/***********************************************/
-
-void test1()
-{
- auto p = std.file.getcwd();
-
- writefln("%s '%s'\n", p.length, p);
- assert(p[$ - 1] != 0);
-}
-
-/***********************************************/
-
-int main()
-{
- test1();
-
- printf("Success\n");
- return 0;
-}
diff --git a/gcc/testsuite/gdc.test/runnable/testfloat.d b/gcc/testsuite/gdc.test/runnable/testfloat.d
new file mode 100644
index 0000000..e9fe397
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/testfloat.d
@@ -0,0 +1,239 @@
+/* PERMUTE_ARGS: -O
+ * Test floating point code generation
+ */
+
+import core.stdc.stdio;
+import core.stdc.stdlib;
+
+double value_1() {
+ return 1;
+}
+
+double value_2() {
+ return 2;
+}
+
+/***************************************/
+
+void testcse1(T)() // common subexpressions
+{
+ T a = value_1();
+ T b = value_2();
+ T x = a*a + a*a + a*a + a*a + a*a + a*a + a*a +
+ a*b + a*b;
+ printf("%g\n", cast(double)x); // destroy scratch reg contents
+ T y = a*a + a*a + a*a + a*a + a*a + a*a + a*a +
+ a*b + a*b;
+ assert(x == 11);
+ assert(x == y);
+}
+
+void test240()
+{
+ testcse1!float();
+ testcse1!double();
+ testcse1!real();
+}
+
+/***************************************/
+
+void testcse2(T)() // common subexpressions
+{
+ T a = value_1();
+ T b = value_2();
+ T x = a*a + a*a + a*a + a*a + a*a + a*a + a*a +
+ a*b + a*b + 1;
+ printf("%g\n", cast(double)x); // destroy scratch reg contents
+ int i = (a*a + a*a + a*a + a*a + a*a + a*a + a*a + a*b + a*b) != 0;
+ assert(i);
+ assert(x == 12);
+}
+
+void test241()
+{
+ testcse2!float();
+ testcse2!double();
+ testcse2!real();
+}
+
+/***************************************/
+
+void test1(float f)
+{
+ real r = f;
+ double d = f;
+}
+
+void test2(long l)
+{
+ real r = l;
+ double d = l;
+}
+
+void test3(float f)
+{
+ real r = f * f;
+ double d = f * f;
+}
+
+void test3(long l)
+{
+ real r = l * l;
+ double d = l * l;
+}
+
+/***************************************/
+
+double foo4(int i, double d)
+{
+ return ((i << 1) - d) + ((i << 1) - d);
+}
+
+void test4()
+{
+ double d = foo4(3, 4);
+ assert(d == 4);
+}
+
+/***************************************/
+
+import core.math; // trigger use of sqrt intrinsic
+
+void test5x(double p)
+{
+ bool b = p >= 0;
+ double mean = (1 - p) / p;
+ double skew = sqrt(1 - p);
+}
+
+void test5()
+{
+ test5x(2);
+}
+
+/***************************************/
+
+import core.math; // trigger use of sqrt intrinsic
+
+void dstatsEnforce(bool, string) { }
+
+ulong invNegBinomCDF(double pVal, ulong n, double p)
+{
+ dstatsEnforce(p >= 0 && p <= 1,
+ "p must be between 0, 1 for negative binomial distribution.");
+ dstatsEnforce(pVal >= 0 && pVal <= 1,
+ "P-values must be between 0, 1.");
+
+ // Normal or gamma approx, then adjust.
+ double mean = n * (1 - p) / p;
+ double var = n * (1 - p) / (p * p);
+ double skew = (2 - p) / sqrt(n * (1 - p));
+ double kk = 4.0L / (skew * skew);
+ double theta = sqrt(var / kk);
+ double offset = (kk * theta) - mean + 0.5L;
+ ulong guess;
+ return 0;
+}
+
+void test6()
+{
+ invNegBinomCDF(2.0, 3, 4.0);
+}
+
+/***************************************/
+
+float expDigamma(F)(in F x)
+{
+ return x;
+}
+
+float nextDown(float f) { return f; }
+
+void test7()
+{
+ foreach (i; 1 .. 2)
+ {
+ assert(expDigamma(float(i)) >= expDigamma(float(i).nextDown));
+ }
+}
+
+/***************************************/
+
+void foo8_1(double x)
+{
+ printf("x = %g\n", x);
+ assert(x == 0);
+}
+
+void foo8_2(double x)
+{
+ printf("x = %g\n", x);
+ assert(x != 0);
+}
+
+void test8()
+{
+ foo8_1(0.0);
+ foo8_2(1.0);
+}
+
+/***************************************/
+
+void test9()
+{
+ double a = 9;
+ double b = 3;
+ double c = a * b + 1;
+ double d = a + b + 1;
+ printf("%g %g\n", c, d); // clobber XMM registers
+ assert(c == 28 && d == 13);
+ double e = a * b - 1;
+ double f = a + b - 1; // reload 2 CSEs
+ printf("%g %g\n", e, f);
+ assert(e == 26 && f == 11);
+}
+
+/***************************************/
+// https://issues.dlang.org/show_bug.cgi?id=20349
+
+double f20349(double a, int b)
+{
+ import core.math;
+ return core.math.sqrt(-a / b) / b;
+}
+
+void test20349()
+{
+ assert(f20349(-9, 1) == 3);
+}
+
+/****************************************/
+// https://issues.dlang.org/show_bug.cgi?id=20963
+
+void test20963()
+{
+ ulong v = 0xE3251BACB112CB8B;
+ double d = cast(double)v;
+ printf("%a\n", d); //0x1.c64a37596225ap+63
+ assert(d == 0x1.c64a375962259p+63);
+}
+
+/***************************************/
+
+
+int main()
+{
+ test240();
+ test241();
+ test4();
+ test5();
+ test6();
+ test7();
+ test8();
+ test9();
+ test20349();
+ test20963();
+
+ printf("Success\n");
+ return EXIT_SUCCESS;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/testformat.d b/gcc/testsuite/gdc.test/runnable/testformat.d
deleted file mode 100644
index 74f4095..0000000
--- a/gcc/testsuite/gdc.test/runnable/testformat.d
+++ /dev/null
@@ -1,126 +0,0 @@
-// RUNNABLE_PHOBOS_TEST
-// PERMUTE_ARGS:
-
-import std.stdio;
-import std.string;
-
-/*************************************************************/
-
-void test1()
-{
- double x = 1e6;
- float f;
- double d;
- real r;
-
- while (x > 1e-5)
- { double y = x / 101.0;
-
- std.stdio.writef("x = %g\t%f\t%e\n",x/101.0,x/101.0,x/101.0);
- x /= 10.0;
- }
-
- double a = 123456789.0;
- for (int i = 20; i--; a /= 10)
- std.stdio.writef("%20.6g|%20.6e|%20.6f\n",a,a,a);
-
- std.stdio.writef("%e %e %e %e\n",float.nan,double.nan,real.nan,double.infinity);
- std.stdio.writef("%e %e %e\n",-float.nan,-double.nan,-double.infinity);
- std.stdio.writef("%-5E %5E %E\n",float.nan,double.nan,double.infinity);
-
- std.stdio.writef("%f %f %f\n",float.nan,double.nan,double.infinity);
- std.stdio.writef("%f %f %f\n",-float.nan,-double.nan,-double.infinity);
- std.stdio.writef("%+F %+ F %F\n",float.nan,double.nan,double.infinity);
-
- std.stdio.writef("%g %g %g\n",float.nan,double.nan,double.infinity);
- std.stdio.writef("%g %g %g\n",-float.nan,-double.nan,-double.infinity);
- std.stdio.writef("% G %G %G\n",float.nan,double.nan,double.infinity);
-
- r = 0x1.AAp+3L;
- std.stdio.writef(" r = %g\n", r);
- std.stdio.writef(" r = %a\n", r);
- std.stdio.writef(" r = %A\n", r);
-
- d = 0x1.AAp+3;
- std.stdio.writef(" d = %.5a\n", d);
- std.stdio.writef(" d = %A\n", d);
-
- f = 0x1.AAp+3f;
- std.stdio.writef(" f = %a\n", f);
- std.stdio.writef(" f = %A\n", f);
-
- f = 0x1.FFp+3f;
- std.stdio.writef(" f = %.1a\n", f);
- std.stdio.writef(" f = %A\n", f);
-
- r = 0;
- std.stdio.writef(" r = %a\n", r);
- std.stdio.writef(" r = %A\n", r);
-
- std.stdio.writef("%e\n", 1e+300);
- std.stdio.writef("%.0f\n%.307f\n", 1e+300, 1e-300);
- std.stdio.writef("%.0A\n%.307A\n", 1e+300, 1e-300);
-}
-
-/*************************************************************/
-
-void test2()
-{
- writefln("%o", 9);
- assert(std.string.format("%o", 9) == "11");
- assert(std.string.format("%o", 10) == "12");
- assert(std.string.format("%b", 9) == "1001");
- assert(std.string.format("%b", 10) == "1010");
-}
-
-
-/*************************************************************/
-
-void test3()
-{
- Object e = new Exception("hello");
- writeln(e.toString());
- //assert(e.toString() == "object.Exception: hello");
- //assert(format(e) == "object.Exception: hello");
-
- alias char[] xstring;
- assert(format(cast(xstring)"world") == "world");
-}
-
-/*************************************************************/
-
-void test4()
-{
- const char[][] x = ["%s","123"];
- writeln(x);
- assert(std.string.format("%s", x) == `["%s", "123"]`);
-}
-
-/*************************************************************/
-
-void test5()
-{
- int[int] foo;
-
- foo[1] = 2;
- foo[7] = 28;
-
- writefln("%s", foo);
-
- void[0] v;
- assert(format("%s", v) == "[]");
-}
-
-/*************************************************************/
-
-int main()
-{
- test1();
- test2();
- test3();
- test4();
- test5();
-
- std.stdio.writefln("Success");
- return 0;
-}
diff --git a/gcc/testsuite/gdc.test/runnable/testgc2.d b/gcc/testsuite/gdc.test/runnable/testgc2.d
index 0d7ab8c..f107f1c 100644
--- a/gcc/testsuite/gdc.test/runnable/testgc2.d
+++ b/gcc/testsuite/gdc.test/runnable/testgc2.d
@@ -1,4 +1,10 @@
-// PERMUTE_ARGS:
+/*
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+Success
+---
+*/
module testgc2;
@@ -7,30 +13,34 @@ import core.exception : OutOfMemoryError;
/*******************************************/
+__gshared ulong counter;
+
void test1()
{
- printf("This should not take a while\n");
try
{
long[] l = new long[ptrdiff_t.max];
- printf("%lu\n", cast(ulong)l.capacity); // Make sure l is not optimized out.
+ counter += l.capacity; // Make sure l is not optimized out.
assert(0);
}
catch (OutOfMemoryError o)
{
}
- printf("This may take a while\n");
+ assert(counter == 0);
+
try
{
byte[] b = new byte[size_t.max / 3];
- printf("%lu\n", cast(ulong)b.capacity); // Make sure b is not optimized out.
+ counter += b.capacity; // Make sure b is not optimized out.
version (Windows)
assert(0);
}
catch (OutOfMemoryError o)
{
}
+
+ assert(counter >= 0);
}
/*******************************************/
@@ -41,5 +51,3 @@ void main()
printf("Success\n");
}
-
-
diff --git a/gcc/testsuite/gdc.test/runnable/testgc3.d b/gcc/testsuite/gdc.test/runnable/testgc3.d
index 88232fe..300888f 100644
--- a/gcc/testsuite/gdc.test/runnable/testgc3.d
+++ b/gcc/testsuite/gdc.test/runnable/testgc3.d
@@ -1,5 +1,11 @@
-// PERMUTE_ARGS:
-// REQUIRED_ARGS:
+/*
+PERMUTE_ARGS:
+REQUIRED_ARGS:
+RUN_OUTPUT:
+---
+finished
+---
+*/
import core.stdc.stdio;
@@ -21,4 +27,3 @@ void main()
printf("finished\n");
aa[] = null;
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/testinvariant.d b/gcc/testsuite/gdc.test/runnable/testinvariant.d
index 93d66ef..d3b3b6f 100644
--- a/gcc/testsuite/gdc.test/runnable/testinvariant.d
+++ b/gcc/testsuite/gdc.test/runnable/testinvariant.d
@@ -17,7 +17,7 @@ int testinvariant()
printf("hello\n");
Foo f = new Foo();
printf("f = %p\n", f);
- printf("f.sizeof = x%x\n", Foo.sizeof);
+ printf("f.sizeof = x%zx\n", Foo.sizeof);
printf("f.classinfo = %p\n", f.classinfo);
printf("f.classinfo._invariant = %p\n", f.classinfo.base);
f.test();
@@ -26,7 +26,7 @@ int testinvariant()
}
/***************************************************/
-// 6453
+// https://issues.dlang.org/show_bug.cgi?id=6453
void test6453()
{
@@ -107,7 +107,7 @@ void test6453()
}
/***************************************************/
-// 13113
+// https://issues.dlang.org/show_bug.cgi?id=13113
struct S13113
{
@@ -140,7 +140,7 @@ void test13113()
}
/***************************************************/
-// 13147
+// https://issues.dlang.org/show_bug.cgi?id=13147
version (D_InlineAsm_X86)
enum x86iasm = true;
diff --git a/gcc/testsuite/gdc.test/runnable/testkeyword.d b/gcc/testsuite/gdc.test/runnable/testkeyword.d
index 79f2c29..5fb4d44 100644
--- a/gcc/testsuite/gdc.test/runnable/testkeyword.d
+++ b/gcc/testsuite/gdc.test/runnable/testkeyword.d
@@ -97,8 +97,8 @@ void main(string[] args) nothrow
auto funcLiteral = (int x, int y)
{
- enum thisFunc = "testkeyword.main.__lambda3";
- enum thisFunc2 = "testkeyword.main.__lambda3(int x, int y)";
+ enum thisFunc = "testkeyword.main.__lambda5";
+ enum thisFunc2 = "testkeyword.main.__lambda5(int x, int y)";
static assert(getFuncArgFile() == thisFile);
static assert(getFuncArgLine() == 104);
diff --git a/gcc/testsuite/gdc.test/runnable/testline.d b/gcc/testsuite/gdc.test/runnable/testline.d
index 5b84204..cbf536c 100644
--- a/gcc/testsuite/gdc.test/runnable/testline.d
+++ b/gcc/testsuite/gdc.test/runnable/testline.d
@@ -1,4 +1,3 @@
-// RUNNABLE_PHOBOS_TEST
// PERMUTE_ARGS:
// $HeadURL$
@@ -7,7 +6,6 @@
module dstress.run.line_token_03;
-import std.stdio;
import core.exception;
int main(){
@@ -22,8 +20,6 @@ int main(){
assert(0);
}
-import std.stdio;
-
/*
* @WARNING@: this code depends on the phobos implementation.
* char[]s returned by wrong assertions have to look like:
@@ -39,6 +35,5 @@ void checkFileSpec(Object o){
}
}
-writeln(str);
assert(str[start .. start+3]=="(1)");
}
diff --git a/gcc/testsuite/gdc.test/runnable/testmain.d b/gcc/testsuite/gdc.test/runnable/testmain.d
index 4619bde..d615e10 100644
--- a/gcc/testsuite/gdc.test/runnable/testmain.d
+++ b/gcc/testsuite/gdc.test/runnable/testmain.d
@@ -1,5 +1,6 @@
// REQUIRED_ARGS: -main
+// PERMUTE_ARGS: -betterC
void foo() { }
diff --git a/gcc/testsuite/gdc.test/runnable/testminit.d b/gcc/testsuite/gdc.test/runnable/testminit.d
index 52c99bb..92c2d3a 100644
--- a/gcc/testsuite/gdc.test/runnable/testminit.d
+++ b/gcc/testsuite/gdc.test/runnable/testminit.d
@@ -1,5 +1,14 @@
-// EXTRA_SOURCES: imports/testminitAA.d imports/testminitBB.d
-// PERMUTE_ARGS:
+/*
+EXTRA_SOURCES: imports/testminitAA.d imports/testminitBB.d
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+AA
+BB
+hello
+Success
+---
+*/
import core.stdc.stdio;
diff --git a/gcc/testsuite/gdc.test/runnable/testmmfile.d b/gcc/testsuite/gdc.test/runnable/testmmfile.d
deleted file mode 100644
index 6a9d6e9..0000000
--- a/gcc/testsuite/gdc.test/runnable/testmmfile.d
+++ /dev/null
@@ -1,120 +0,0 @@
-// RUNNABLE_PHOBOS_TEST
-// PERMUTE_ARGS:
-// REQUIRED_ARGS:
-
-import std.file;
-import std.mmfile;
-
-int main()
-{
- static string name = "test.tmp";
- static string s = "abcd";
-
- write(name, s);
-
- { scope MmFile mmf = new MmFile(name);
- string p;
-
- assert(mmf[0] == 'a');
- p = cast(string)mmf[];
- //printf("p.length = %d\n", p.length);
- assert(p[1] == 'b');
- p = cast(string)mmf[0 .. 4];
- assert(p[2] == 'c');
- }
-
- { scope MmFile mmf = new MmFile(name, MmFile.Mode.read, 0, null);
- string p;
-
- assert(mmf[0] == 'a');
- p = cast(string)mmf[];
- //printf("p.length = %d\n", p.length);
- assert(mmf.length == 4);
- assert(p[1] == 'b');
- p = cast(string)mmf[0 .. 4];
- assert(p[2] == 'c');
- }
-
- remove(name);
-
- { scope MmFile mmf = new MmFile(name, MmFile.Mode.readWriteNew, 4, null);
- char[] p;
-
- p = cast(char[])mmf[];
- p[] = "1234";
- mmf[3] = '5';
- assert(mmf[2] == '3');
- assert(mmf[3] == '5');
- }
-
- { string p = cast(string)read(name);
-
- assert(p[] == "1235");
- }
-
- { scope MmFile mmf = new MmFile(name, MmFile.Mode.readWriteNew, 4, null);
- char[] p;
-
- p = cast(char[])mmf[];
- p[] = "5678";
- mmf[3] = '5';
- assert(mmf[2] == '7');
- assert(mmf[3] == '5');
- assert(cast(string)mmf[] == "5675");
- }
-
- { string p = cast(string)read(name);
-
- assert(p[] == "5675");
- }
-
- { scope MmFile mmf = new MmFile(name, MmFile.Mode.readWrite, 4, null);
- char[] p;
-
- p = cast(char[])mmf[];
- assert(cast(char[])mmf[] == "5675");
- p[] = "9102";
- mmf[2] = '5';
- assert(cast(string)mmf[] == "9152");
- }
-
- { string p = cast(string)read(name);
-
- assert(p[] == "9152");
- }
-
- remove(name);
-
- { scope MmFile mmf = new MmFile(name, MmFile.Mode.readWrite, 4, null);
- char[] p;
-
- p = cast(char[])mmf[];
- p[] = "abcd";
- mmf[2] = '5';
- assert(cast(string)mmf[] == "ab5d");
- }
-
- { string p = cast(string)read(name);
-
- assert(p[] == "ab5d");
- }
-
- { scope MmFile mmf = new MmFile(name, MmFile.Mode.readCopyOnWrite, 4, null);
- char[] p;
-
- p = cast(char[])mmf[];
- assert(cast(string)mmf[] == "ab5d");
- p[] = "9102";
- mmf[2] = '5';
- assert(cast(string)mmf[] == "9152");
- }
-
- { string p = cast(string)read(name);
-
- assert(p[] == "ab5d");
- }
-
- remove(name);
-
- return 0;
-}
diff --git a/gcc/testsuite/gdc.test/runnable/testmod2.d b/gcc/testsuite/gdc.test/runnable/testmod2.d
index c03a8c7..111696a 100644
--- a/gcc/testsuite/gdc.test/runnable/testmod2.d
+++ b/gcc/testsuite/gdc.test/runnable/testmod2.d
@@ -1,7 +1,7 @@
// EXTRA_SOURCES: imports/testmod2a.d
/**********************************/
-// bug 1904
+// https://issues.dlang.org/show_bug.cgi?id=1904
import imports.testmod2a;
void main()
diff --git a/gcc/testsuite/gdc.test/runnable/testpic.d b/gcc/testsuite/gdc.test/runnable/testpic.d
index 60f6775..ef3ab86 100644
--- a/gcc/testsuite/gdc.test/runnable/testpic.d
+++ b/gcc/testsuite/gdc.test/runnable/testpic.d
@@ -1,4 +1,5 @@
-// PERMUTE_ARGS: -fPIC -O
+// PERMUTE_ARGS: -fPIC -O -fPIE
+// DISABLED: win32 win64
extern (C) int printf(const char*, ...);
@@ -44,10 +45,26 @@ void test17034()
/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=20441
+
+const(char)* moo(const (char) *s)
+{
+ return s;
+}
+
+void test20441()
+{
+ const(char) *x = "abc".ptr;
+ assert( moo(x) - x == 0 );
+}
+
+/***************************************************/
+
int main()
{
test11310();
test17034();
+ test20441();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/testptrref.d b/gcc/testsuite/gdc.test/runnable/testptrref.d
index 5bcf444..c616d57 100644
--- a/gcc/testsuite/gdc.test/runnable/testptrref.d
+++ b/gcc/testsuite/gdc.test/runnable/testptrref.d
@@ -7,15 +7,11 @@ version(CRuntime_Microsoft)
extern __gshared uint _DP_end;
extern __gshared uint _TP_beg;
extern __gshared uint _TP_end;
- extern int _tls_start;
- extern int _tls_end;
}
alias _DPbegin = _DP_beg;
alias _DPend = _DP_end;
alias _TPbegin = _TP_beg;
alias _TPend = _TP_end;
- alias _tlsstart = _tls_start;
- alias _tlsend = _tls_end;
__gshared void[] dataSection;
shared static this()
@@ -26,6 +22,15 @@ version(CRuntime_Microsoft)
dataSection = findImageSection(".data");
}
+ void[] tlsRange;
+ static this()
+ {
+ import core.internal.traits : externDFunc;
+ alias initTLSRanges = externDFunc!("rt.sections_win64.initTLSRanges",
+ void[] function() nothrow @nogc);
+ tlsRange = initTLSRanges();
+ }
+
version = ptrref_supported;
}
else version(Win32)
@@ -39,6 +44,13 @@ else version(Win32)
extern int _tlsstart;
extern int _tlsend;
}
+
+ void[] tlsRange;
+ static this()
+ {
+ tlsRange = (cast(void*)&_tlsstart)[0.. cast(void*)&_tlsend - cast(void*)&_tlsstart];
+ }
+
version = ptrref_supported;
}
@@ -91,13 +103,13 @@ void main()
version(ptrref_supported):
bool findTlsPtr(const(void)* ptr)
-{
+{
debug(PRINT) printf("findTlsPtr %p\n", ptr);
for (uint* p = &_TPbegin; p < &_TPend; p++)
{
- void* addr = cast(void*) &_tlsstart + *p;
+ void* addr = tlsRange.ptr + *p;
debug(PRINT) printf(" try %p\n", addr);
- assert(addr < &_tlsend);
+ assert(*p < tlsRange.length);
if (addr == ptr)
return true;
}
@@ -126,6 +138,9 @@ void testRefPtr()
debug(PRINT) printf("&_DPbegin %p\n", &_DPbegin);
debug(PRINT) printf("&_DPend %p\n", &_DPend);
+ debug(PRINT) printf("&_TPbegin %p\n", &_TPbegin);
+ debug(PRINT) printf("&_TPend %p\n", &_TPend);
+
assert(!findDataPtr(cast(void*)&sharedInt));
assert(!findTlsPtr(&tlsInt));
diff --git a/gcc/testsuite/gdc.test/runnable/testptrref_gc.d b/gcc/testsuite/gdc.test/runnable/testptrref_gc.d
new file mode 100644
index 0000000..3bd6bf5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/testptrref_gc.d
@@ -0,0 +1,3 @@
+// REQUIRED_ARGS: -lowmem -Jrunnable
+// EXTRA_FILES: testptrref.d
+mixin(import("testptrref.d"));
diff --git a/gcc/testsuite/gdc.test/runnable/testreturn.d b/gcc/testsuite/gdc.test/runnable/testreturn.d
index fcebf79..42b93ba 100644
--- a/gcc/testsuite/gdc.test/runnable/testreturn.d
+++ b/gcc/testsuite/gdc.test/runnable/testreturn.d
@@ -1,9 +1,15 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
extern(C) int printf(const char*, ...);
alias TypeTuple(T...) = T;
/***************************************************/
-// 13336
+// https://issues.dlang.org/show_bug.cgi?id=13336
struct S13336
{
@@ -96,7 +102,7 @@ out(r)
assert(r == (f ? sx : sy));
result13336 = r;
}
-body
+do
{
mixin(fbody13336);
}
@@ -109,7 +115,7 @@ out(r)
assert(r == (f ? sx : sy));
result13336 = r;
}
-body
+do
{
mixin(fbody13336);
}
@@ -150,7 +156,7 @@ void test13336()
}
/***************************************************/
-// 15018
+// https://issues.dlang.org/show_bug.cgi?id=15018
struct S15018(int n)
{
diff --git a/gcc/testsuite/gdc.test/runnable/testrightthis.d b/gcc/testsuite/gdc.test/runnable/testrightthis.d
index 32879ce..e5d7ba3 100644
--- a/gcc/testsuite/gdc.test/runnable/testrightthis.d
+++ b/gcc/testsuite/gdc.test/runnable/testrightthis.d
@@ -474,7 +474,7 @@ void test7()
}
/********************************************************/
-// 4350
+// https://issues.dlang.org/show_bug.cgi?id=4350
template Mix4350() { int b; }
@@ -509,7 +509,7 @@ void test4350()
}
/********************************************************/
-// 6430
+// https://issues.dlang.org/show_bug.cgi?id=6430
auto bug6430(int a)
{
@@ -528,7 +528,7 @@ auto bug6430(int a, int b)
}
/********************************************************/
-// 9619
+// https://issues.dlang.org/show_bug.cgi?id=9619
struct Foo9619 { int x; }
void test9619()
@@ -540,7 +540,7 @@ void test9619()
}
/********************************************************/
-// 9633
+// https://issues.dlang.org/show_bug.cgi?id=9633
class Foo9633
{
@@ -573,7 +573,7 @@ void test9633()
}
/********************************************************/
-// 11245
+// https://issues.dlang.org/show_bug.cgi?id=11245
struct Vec11245
{
@@ -589,7 +589,7 @@ class Bar11245
}
/********************************************************/
-// 11614
+// https://issues.dlang.org/show_bug.cgi?id=11614
struct Tuple11614(T...)
{
@@ -613,7 +613,7 @@ struct Foo11614
}
/********************************************************/
-// 11993
+// https://issues.dlang.org/show_bug.cgi?id=11993
struct S11993
{
@@ -634,7 +634,7 @@ void test11993()
}
/********************************************************/
-// 15934
+// https://issues.dlang.org/show_bug.cgi?id=15934
class B15934
{
diff --git a/gcc/testsuite/gdc.test/runnable/testsafe.d b/gcc/testsuite/gdc.test/runnable/testsafe.d
index cec4c0f..40496f5 100644
--- a/gcc/testsuite/gdc.test/runnable/testsafe.d
+++ b/gcc/testsuite/gdc.test/runnable/testsafe.d
@@ -137,7 +137,7 @@ struct uD
}
@safe
-void safeunions() // improved for issue 11510
+void safeunions() // improved for https://issues.dlang.org/show_bug.cgi?id=11510
{
SafeUnion1 su1;
SafeUnion2 su2;
@@ -197,11 +197,6 @@ void safeexception()
try {}
catch(Throwable e) {}
}));
-
- static assert(!__traits(compiles, () @safe {
- try {}
- catch {}
- }));
}
@safe
@@ -415,7 +410,7 @@ void classcast()
}
/***************************************************/
-// 6278
+// https://issues.dlang.org/show_bug.cgi?id=6278
@safe
{
@@ -423,18 +418,18 @@ void classcast()
class A6278 {
int test()
in { assert(0); }
- body { return 1; }
+ do { return 1; }
}
class B6278 : A6278 {
override int test()
in { assert(0); }
- body { return 1; }
+ do { return 1; }
}
}
/***************************************************/
-// 7803
+// https://issues.dlang.org/show_bug.cgi?id=7803
@safe int f7803() {
scope(success) {/* ... */}
@@ -447,13 +442,13 @@ nothrow int g7803() {
}
/***************************************************/
-// 6405
+// https://issues.dlang.org/show_bug.cgi?id=6405
void foo6405(int[][] args...) @trusted { }
void test6405() @safe { foo6405([1,2,3], [1,2,3]); }
/***************************************************/
-// 12502
+// https://issues.dlang.org/show_bug.cgi?id=12502
void test12502() @safe
{
@@ -495,4 +490,3 @@ void main()
{
test14162();
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/testscope.d b/gcc/testsuite/gdc.test/runnable/testscope.d
index ca5c4c9..32d66b5 100644
--- a/gcc/testsuite/gdc.test/runnable/testscope.d
+++ b/gcc/testsuite/gdc.test/runnable/testscope.d
@@ -1,5 +1,5 @@
// PERMUTE_ARGS:
-// REQUIRED_ARGS: -d -dip1000
+// REQUIRED_ARGS: -d -preview=dip1000
extern(C) int printf(const char*, ...);
@@ -293,8 +293,6 @@ void test11()
static int* p;
static int i;
bar11(p, &i);
-
- bar11((i,p), &i); // comma expressions are deprecated, but need to test them
}
/********************************************/
@@ -302,7 +300,7 @@ void test11()
int test17432(scope int delegate() dg)
{
- return dg();
+ return dg();
}
// stripped down version of std.traits.Parameters
@@ -342,6 +340,53 @@ template test14(T)
test14!(char[] function(return char[])) x14;
/********************************************/
+// https://issues.dlang.org/show_bug.cgi?id=17935
+
+struct ByChunk(IO)
+{
+@safe:
+ ~this() scope
+ {}
+
+ ubyte[] buf;
+ IO io;
+}
+
+struct IO
+{
+ ~this() @safe @nogc scope
+ {}
+}
+
+@safe @nogc void test17395()
+{
+ ubyte[256] buf;
+ auto chunks = ByChunk!IO(buf[], IO());
+ chunks.__xdtor(); // auto-generated inclusive (fields and struct) dtor
+}
+
+/********************************************/
+// https://issues.dlang.org/show_bug.cgi?id=20569
+
+void test20569() @safe
+{
+ static struct S
+ {
+ int value;
+ int* pointer;
+ }
+
+ /* explicit `scope`: */
+ scope S s1;
+ scope int* p1 = &s1.value;
+
+ /* inferred `scope`: */
+ int x;
+ S s2 = S(0, &x);
+ int* p2 = &s2.value;
+}
+
+/********************************************/
void main()
{
@@ -359,6 +404,8 @@ void main()
test7049();
test16747();
test11();
+ test17395();
+ test20569();
printf("Success\n");
}
diff --git a/gcc/testsuite/gdc.test/runnable/testscope2.d b/gcc/testsuite/gdc.test/runnable/testscope2.d
index 85282c2..1b8cf29 100644
--- a/gcc/testsuite/gdc.test/runnable/testscope2.d
+++ b/gcc/testsuite/gdc.test/runnable/testscope2.d
@@ -1,5 +1,4 @@
-// RUNNABLE_PHOBOS_TEST
-// REQUIRED_ARGS: -dip25
+// REQUIRED_ARGS:
/*
TEST_OUTPUT:
---
@@ -30,7 +29,7 @@ pragma(msg, "foo4 ", typeof(&SS.foo4));
void test3()
{
- version (all)
+ version (none)
{
import std.stdio;
writeln(SS.foo1.mangleof);
@@ -52,7 +51,7 @@ void test3()
assert(SS.foo4.mangleof == "_D10testscope22SS4foo4MFNcNkKNgPiZi");
// Test scope pretty-printing
- assert(typeof(SS.foo1).stringof == "ref return ulong(return ref int* delegate() return p)");
+ assert(typeof(SS.foo1).stringof == "ref ulong(return ref int* delegate() return p) return");
assert(typeof(SS.foo2).stringof == "ref int(return ref int delegate() p)");
assert(typeof(SS.foo3).stringof == "ref int(return ref inout(int*) p)");
assert(typeof(SS.foo4).stringof == "ref int(return ref inout(int*) p)");
@@ -255,4 +254,3 @@ void main()
test11();
printf("Success\n");
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/testsignals.d b/gcc/testsuite/gdc.test/runnable/testsignals.d
deleted file mode 100644
index c2fbcee..0000000
--- a/gcc/testsuite/gdc.test/runnable/testsignals.d
+++ /dev/null
@@ -1,114 +0,0 @@
-// RUNNABLE_PHOBOS_TEST
-import std.stdio;
-import std.signals;
-
-class Observer
-{ // our slot
- void watch(string msg, int i)
- {
- writefln("Observed msg '%s' and value %s", msg, i);
- }
-
- void watch2(int i, int j)
- {
- writefln("Observed msg %s,%s", i, j);
- }
-}
-
-class Foo
-{
- int value() { return _value; }
-
- int value(int v)
- {
- if (v != _value)
- { _value = v;
- // call all the connected slots with the two parameters
- emit("setting new value", v);
- }
- return v;
- }
-
- // Mix in all the code we need to make Foo into a signal
- mixin Signal!(string, int);
-
- private :
- int _value;
-}
-
-void test1()
-{
- Foo a = new Foo;
- Observer o = new Observer;
-
- a.value = 3; // should not call o.watch()
- a.connect(&o.watch); // o.watch is the slot
- a.value = 4; // should call o.watch()
- a.disconnect(&o.watch); // o.watch is no longer a slot
- a.value = 5; // so should not call o.watch()
- a.connect(&o.watch); // connect again
- a.value = 6; // should call o.watch()
- delete o; // destroying o should automatically disconnect it
- a.value = 7; // should not call o.watch()
-}
-
-/******************************************/
-
-class Input
-{
- mixin Signal!(int, int) click;
- mixin Signal!(char) keyDown;
-}
-
-void test2()
-{
- Observer o = new Observer();
- Input a = new Input();
- a.click.connect(&o.watch2);
- a.click.emit(5,6);
-}
-
-/******************************************/
-
-class Args3
-{
- int foo;
-}
-
-class Base3
-{
- ~this()
- {
- writefln("Base3 dtor!");
- }
-}
-
-class Test3 : Base3
-{
- mixin Signal!(Args3) A;
- mixin Signal!(Args3) B;
-
- ~this()
- {
- writefln("Test3 dtor");
- }
-}
-
-
-void test3()
-{
- auto test = new Test3;
-}
-
-
-/******************************************/
-
-int main()
-{
- test1();
- test2();
- test3();
-
- printf("Success\n");
- return 0;
-}
diff --git a/gcc/testsuite/gdc.test/runnable/testsocket.d b/gcc/testsuite/gdc.test/runnable/testsocket.d
deleted file mode 100644
index d061929..0000000
--- a/gcc/testsuite/gdc.test/runnable/testsocket.d
+++ /dev/null
@@ -1,51 +0,0 @@
-// RUNNABLE_PHOBOS_TEST
-// PERMUTE_ARGS:
-
-import std.stdio;
-import std.socket;
-
-class Connection
-{
- private
- {
- Socket sock;
- }
-
- void connect (string host, ushort port)
- {
- sock.connect (new InternetAddress (host, port));
- }
-
- void poll ()
- {
- SocketSet rset = new SocketSet (1); /** XXX: here is the bug */
-
- rset.reset ();
- rset.add (sock);
- }
-
- this ()
- {
-
- sock = new TcpSocket;
- sock.blocking = false;
- }
-}
-
-int main ()
-{
- try
- {
- Connection ns;
- ns = new Connection ();
- ns.connect ("localhost", 80);
- ns.poll ();
- delete ns;
- }
- catch(SocketException e)
- {
- }
- return 0;
-}
-
-
diff --git a/gcc/testsuite/gdc.test/runnable/teststdio.d b/gcc/testsuite/gdc.test/runnable/teststdio.d
deleted file mode 100644
index d340f21..0000000
--- a/gcc/testsuite/gdc.test/runnable/teststdio.d
+++ /dev/null
@@ -1,34 +0,0 @@
-// RUNNABLE_PHOBOS_TEST
-// PERMUTE_ARGS:
-// EXTRA_FILES: extra-files/teststdio.txt
-
-import std.stdio;
-import core.stdc.stdio;
-
-void main()
-{
- auto f = std.stdio.File("runnable/extra-files/teststdio.txt", "r");
- FILE* fp = f.getFP();
- string buf;
- int i;
- do
- {
- buf = f.readln('\n');
- foreach (c; buf)
- printf("%x\n", c);
- printf("\n");
- switch (i)
- {
- case 0: assert(buf == "asdfasdf\n"); break;
- case 1: assert(buf == "a\n"); break;
- case 2: assert(buf == "sdf\n"); break;
- case 3: assert(buf == "asdf\n"); break;
- case 4: assert(buf == "\n"); break;
- case 5: assert(buf == "\n"); break;
- case 6: assert(buf == null); break;
- default: assert(0);
- }
- i++;
- } while (!feof(fp));
- //fclose(fp);
-}
diff --git a/gcc/testsuite/gdc.test/runnable/testswitch.d b/gcc/testsuite/gdc.test/runnable/testswitch.d
index 02633a8..c7b9378 100644
--- a/gcc/testsuite/gdc.test/runnable/testswitch.d
+++ b/gcc/testsuite/gdc.test/runnable/testswitch.d
@@ -308,7 +308,7 @@ void bar14(A...)(int i)
{
goto case;
case A[j]:
- printf("a = %d, A[%d] = %d\n", a, j, A[j]);
+ printf("a = %d, A[%zd] = %d\n", a, j, A[j]);
}
break;
default:
@@ -356,10 +356,14 @@ int foo15(int i)
static this()
{
X15 = 4;
- Y15 = 4;
Z15 = 5;
}
+shared static this()
+{
+ Y15 = 4;
+}
+
void test15()
{
auto i = foo15(3);
@@ -465,7 +469,7 @@ int wrongcode3139(int x)
static assert(wrongcode3139(-5)==3);
-// bug 3139
+// https://issues.dlang.org/show_bug.cgi?id=3139
static assert(!is(typeof(
(long x) { switch(x) { case long.max: .. case -long.max:
default:} return 4; }(3)
@@ -499,7 +503,7 @@ void test7358()
}
/*****************************************/
-// 9263
+// https://issues.dlang.org/show_bug.cgi?id=9263
void test9263()
{
@@ -622,7 +626,7 @@ void test23()
}
/*****************************************/
-// 14352
+// https://issues.dlang.org/show_bug.cgi?id=14352
int transmogrify14352(int input)
{
@@ -659,7 +663,8 @@ void test14352()
}
/*****************************************/
-// Issue 14587 - DMD 2.067.1 generating crashing binary on OSX
+// https://issues.dlang.org/show_bug.cgi?id=14587
+// DMD 2.067.1 generating crashing binary on OSX
struct Card {
int value;
@@ -680,7 +685,8 @@ void test14587() {
}
/*****************************************/
-// Issue 15396 - static immutable not recognized as constant within switch statement
+// https://issues.dlang.org/show_bug.cgi?id=15396
+// static immutable not recognized as constant within switch statement
void test15396()
{
@@ -702,6 +708,33 @@ void test15396()
}
/*****************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15538
+
+struct S15538
+{
+ int a = 0;
+ int b = 1;
+}
+
+int f15538(S15538 s)
+{
+ switch (s.a)
+ {
+ case 0: return 10;
+ case 1: return 20;
+ case 2: return 30;
+ case 3: return 40;
+ default: return 99;
+ }
+}
+
+void test15538()
+{
+ S15538 s;
+ assert(f15538(s) == 10); /* fails */
+}
+
+/*****************************************/
int main()
{
@@ -732,6 +765,7 @@ int main()
test14352();
test14587();
test15396();
+ test15538();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/testthread.d b/gcc/testsuite/gdc.test/runnable/testthread.d
index 4ae4395..139a891 100644
--- a/gcc/testsuite/gdc.test/runnable/testthread.d
+++ b/gcc/testsuite/gdc.test/runnable/testthread.d
@@ -49,7 +49,7 @@ int main()
assert(f.x == 3);
int i;
- Thread tx[5];
+ Thread[5] tx;
for (i = 0; i < tx.length; i++)
tx[i] = new Thread(&f.bar);
for (i = 0; i < tx.length; i++)
diff --git a/gcc/testsuite/gdc.test/runnable/testthread2.d b/gcc/testsuite/gdc.test/runnable/testthread2.d
index 93aace6..53f8a3b 100644
--- a/gcc/testsuite/gdc.test/runnable/testthread2.d
+++ b/gcc/testsuite/gdc.test/runnable/testthread2.d
@@ -1,11 +1,5 @@
-// RUNNABLE_PHOBOS_TEST
// PERMUTE_ARGS:
-import std.algorithm : map;
-import std.random : Random, uniform, unpredictableSeed;
-import std.range : repeat;
-import std.stdio : writeln;
-
// Quick, dirty and inefficient AA using linear search, useful for testing.
struct LinearAA(K, V) {
K[] keys;
@@ -33,7 +27,7 @@ struct LinearAA(K, V) {
return val;
}
- V* opIn_r(K key) {
+ V* opBinaryRight(string op : "in")(K key) {
foreach(i, k; keys) {
if(key == k) {
return values.ptr + i;
@@ -67,24 +61,35 @@ struct LinearAA(K, V) {
}
}
-void main() {
- Random gen;
- uint[] seed;
- gen.seed(map!((a) {
- seed ~= unpredictableSeed;
- return seed[$-1]; })(repeat(0)));
- writeln(seed);
+extern (C) int rand();
+
+uint random(const uint max = uint.max)
+{
+ version (Windows)
+ {
+ // RAND_MAX is quite low for windows, extend the range by
+ // abusing multiple random values and rounding errors.
+ const a = rand(), b = rand();
+ const c = a < b ? double(a) / b : double(b) / a;
+ return (cast(int) (c * max)) % max;
+ }
+ else
+ return rand() % max;
+}
+
+void main()
+{
foreach(iter; 0..10) { // Bug only happens after a few iterations.
- writeln(iter);
+
uint[size_t] builtin;
LinearAA!(size_t, uint) linAA;
uint[] nums = new uint[100_000];
foreach(ref num; nums) {
- num = uniform(0U, uint.max, gen);
+ num = random();
}
foreach(i; 0..10_000) {
- auto index = uniform(0, nums.length, gen);
+ auto index = random(cast(uint) nums.length);
if(index in builtin) {
assert(index in linAA);
assert(builtin[index] == nums[index]);
diff --git a/gcc/testsuite/gdc.test/runnable/testtypeid.d b/gcc/testsuite/gdc.test/runnable/testtypeid.d
index ebdda30..d3f4503 100644
--- a/gcc/testsuite/gdc.test/runnable/testtypeid.d
+++ b/gcc/testsuite/gdc.test/runnable/testtypeid.d
@@ -1,6 +1,6 @@
-// RUNNABLE_PHOBOS_TEST
+
import core.vararg;
-import std.stdio;
+import core.stdc.stdio;
/******************************************************/
@@ -18,10 +18,10 @@ FOO3 foox3;
void foo3(int x, ...)
{
- printf("%d arguments\n", _arguments.length);
+ printf("%zd arguments\n", _arguments.length);
for (int i = 0; i < _arguments.length; i++)
{
- writeln(_arguments[i].toString());
+ //writeln(_arguments[i].toString());
if (_arguments[i] is typeid(int))
{
@@ -76,20 +76,6 @@ void test4()
ti = typeid(real[]);
assert(!(ti is null));
- ti = typeid(ifloat[]);
- assert(!(ti is null));
- ti = typeid(idouble[]);
- assert(!(ti is null));
- ti = typeid(ireal[]);
- assert(!(ti is null));
-
- ti = typeid(cfloat[]);
- assert(!(ti is null));
- ti = typeid(cdouble[]);
- assert(!(ti is null));
- ti = typeid(creal[]);
- assert(!(ti is null));
-
ti = typeid(void);
assert(!(ti is null));
ti = typeid(void[]);
@@ -210,26 +196,6 @@ void test16()
/******************************************************/
-void test17()
-{
- TypeInfo ti = typeid(ifloat*);
- assert(!(ti is null));
- assert(ti.tsize==(ifloat*).sizeof);
- assert(ti.toString()=="ifloat*");
-}
-
-/******************************************************/
-
-void test18()
-{
- TypeInfo ti = typeid(cfloat*);
- assert(!(ti is null));
- assert(ti.tsize==(cfloat*).sizeof);
- assert(ti.toString()=="cfloat*");
-}
-
-/******************************************************/
-
void test19()
{
TypeInfo ti = typeid(double*);
@@ -240,26 +206,6 @@ void test19()
/******************************************************/
-void test20()
-{
- TypeInfo ti = typeid(idouble*);
- assert(!(ti is null));
- assert(ti.tsize==(idouble*).sizeof);
- assert(ti.toString()=="idouble*");
-}
-
-/******************************************************/
-
-void test21()
-{
- TypeInfo ti = typeid(cdouble*);
- assert(!(ti is null));
- assert(ti.tsize==(cdouble*).sizeof);
- assert(ti.toString()=="cdouble*");
-}
-
-/******************************************************/
-
void test22()
{
TypeInfo ti = typeid(real*);
@@ -270,26 +216,6 @@ void test22()
/******************************************************/
-void test23()
-{
- TypeInfo ti = typeid(ireal*);
- assert(!(ti is null));
- assert(ti.tsize==(ireal*).sizeof);
- assert(ti.toString()=="ireal*");
-}
-
-/******************************************************/
-
-void test24()
-{
- TypeInfo ti = typeid(creal*);
- assert(!(ti is null));
- assert(ti.tsize==(creal*).sizeof);
- assert(ti.toString()=="creal*");
-}
-
-/******************************************************/
-
void test25()
{
TypeInfo ti = typeid(char*);
@@ -367,10 +293,10 @@ class Bar32 { long y = 4; }
void printargs(int x, ...)
{
- printf("%d arguments\n", _arguments.length);
+ printf("%zd arguments\n", _arguments.length);
for (int i = 0; i < _arguments.length; i++)
{
- writeln(_arguments[i].toString());
+ //writeln(_arguments[i].toString());
if (_arguments[i] == typeid(int))
{
@@ -506,7 +432,7 @@ void test40()
}
/******************************************************/
-// 9442
+// https://issues.dlang.org/show_bug.cgi?id=9442
class C
{
@@ -526,7 +452,7 @@ void test9442()
}
/******************************************************/
-// 10451
+// https://issues.dlang.org/show_bug.cgi?id=10451
struct Foo10451;
@@ -543,7 +469,7 @@ void test10451()
}
/******************************************************/
-// 11010
+// https://issues.dlang.org/show_bug.cgi?id=11010
struct S11010 { S11010* p; }
@@ -567,7 +493,7 @@ void test11010()
}
/******************************************************/
-// 13045
+// https://issues.dlang.org/show_bug.cgi?id=13045
void test13045a()
{
@@ -623,7 +549,7 @@ void test13045b()
}
/******************************************************/
-// 15680
+// https://issues.dlang.org/show_bug.cgi?id=15680
void test15680()
{
@@ -651,14 +577,8 @@ int main()
test14();
test15();
test16();
- test17();
- test18();
test19();
- test20();
- test21();
test22();
- test23();
- test24();
test25();
test26();
test27();
diff --git a/gcc/testsuite/gdc.test/runnable/traits.d b/gcc/testsuite/gdc.test/runnable/traits.d
index 9d14ecd..ddd5059 100644
--- a/gcc/testsuite/gdc.test/runnable/traits.d
+++ b/gcc/testsuite/gdc.test/runnable/traits.d
@@ -1,4 +1,3 @@
-// RUNNABLE_PHOBOS_TEST
/*
PERMUTE_ARGS:
EXTRA_FILES: imports/a9546.d
@@ -17,7 +16,7 @@ __lambda1
module traits;
-import std.stdio;
+import core.stdc.stdio;
alias int myint;
struct S { void bar() { } int x = 4; static int z = 5; }
@@ -34,7 +33,6 @@ struct D1 { @disable void true_(); void false_(){} }
void test1()
{
auto t = __traits(isArithmetic, int);
- writeln(t);
assert(t == true);
assert(__traits(isArithmetic) == false);
@@ -61,12 +59,6 @@ void test1()
assert(__traits(isArithmetic, float) == true);
assert(__traits(isArithmetic, double) == true);
assert(__traits(isArithmetic, real) == true);
- assert(__traits(isArithmetic, ifloat) == true);
- assert(__traits(isArithmetic, idouble) == true);
- assert(__traits(isArithmetic, ireal) == true);
- assert(__traits(isArithmetic, cfloat) == true);
- assert(__traits(isArithmetic, cdouble) == true);
- assert(__traits(isArithmetic, creal) == true);
assert(__traits(isArithmetic, char) == true);
assert(__traits(isArithmetic, wchar) == true);
assert(__traits(isArithmetic, dchar) == true);
@@ -81,7 +73,6 @@ void test1()
void test2()
{
auto t = __traits(isScalar, int);
- writeln(t);
assert(t == true);
assert(__traits(isScalar) == false);
@@ -108,12 +99,6 @@ void test2()
assert(__traits(isScalar, float) == true);
assert(__traits(isScalar, double) == true);
assert(__traits(isScalar, real) == true);
- assert(__traits(isScalar, ifloat) == true);
- assert(__traits(isScalar, idouble) == true);
- assert(__traits(isScalar, ireal) == true);
- assert(__traits(isScalar, cfloat) == true);
- assert(__traits(isScalar, cdouble) == true);
- assert(__traits(isScalar, creal) == true);
assert(__traits(isScalar, char) == true);
assert(__traits(isScalar, wchar) == true);
assert(__traits(isScalar, dchar) == true);
@@ -147,12 +132,6 @@ void test3()
assert(__traits(isIntegral, float) == false);
assert(__traits(isIntegral, double) == false);
assert(__traits(isIntegral, real) == false);
- assert(__traits(isIntegral, ifloat) == false);
- assert(__traits(isIntegral, idouble) == false);
- assert(__traits(isIntegral, ireal) == false);
- assert(__traits(isIntegral, cfloat) == false);
- assert(__traits(isIntegral, cdouble) == false);
- assert(__traits(isIntegral, creal) == false);
assert(__traits(isIntegral, char) == true);
assert(__traits(isIntegral, wchar) == true);
assert(__traits(isIntegral, dchar) == true);
@@ -185,12 +164,6 @@ void test4()
assert(__traits(isFloating, float) == true);
assert(__traits(isFloating, double) == true);
assert(__traits(isFloating, real) == true);
- assert(__traits(isFloating, ifloat) == true);
- assert(__traits(isFloating, idouble) == true);
- assert(__traits(isFloating, ireal) == true);
- assert(__traits(isFloating, cfloat) == true);
- assert(__traits(isFloating, cdouble) == true);
- assert(__traits(isFloating, creal) == true);
assert(__traits(isFloating, char) == false);
assert(__traits(isFloating, wchar) == false);
assert(__traits(isFloating, dchar) == false);
@@ -223,12 +196,6 @@ void test5()
assert(__traits(isUnsigned, float) == false);
assert(__traits(isUnsigned, double) == false);
assert(__traits(isUnsigned, real) == false);
- assert(__traits(isUnsigned, ifloat) == false);
- assert(__traits(isUnsigned, idouble) == false);
- assert(__traits(isUnsigned, ireal) == false);
- assert(__traits(isUnsigned, cfloat) == false);
- assert(__traits(isUnsigned, cdouble) == false);
- assert(__traits(isUnsigned, creal) == false);
assert(__traits(isUnsigned, char) == true);
assert(__traits(isUnsigned, wchar) == true);
assert(__traits(isUnsigned, dchar) == true);
@@ -261,12 +228,6 @@ void test6()
assert(__traits(isAssociativeArray, float) == false);
assert(__traits(isAssociativeArray, double) == false);
assert(__traits(isAssociativeArray, real) == false);
- assert(__traits(isAssociativeArray, ifloat) == false);
- assert(__traits(isAssociativeArray, idouble) == false);
- assert(__traits(isAssociativeArray, ireal) == false);
- assert(__traits(isAssociativeArray, cfloat) == false);
- assert(__traits(isAssociativeArray, cdouble) == false);
- assert(__traits(isAssociativeArray, creal) == false);
assert(__traits(isAssociativeArray, char) == false);
assert(__traits(isAssociativeArray, wchar) == false);
assert(__traits(isAssociativeArray, dchar) == false);
@@ -299,12 +260,6 @@ void test7()
assert(__traits(isStaticArray, float) == false);
assert(__traits(isStaticArray, double) == false);
assert(__traits(isStaticArray, real) == false);
- assert(__traits(isStaticArray, ifloat) == false);
- assert(__traits(isStaticArray, idouble) == false);
- assert(__traits(isStaticArray, ireal) == false);
- assert(__traits(isStaticArray, cfloat) == false);
- assert(__traits(isStaticArray, cdouble) == false);
- assert(__traits(isStaticArray, creal) == false);
assert(__traits(isStaticArray, char) == false);
assert(__traits(isStaticArray, wchar) == false);
assert(__traits(isStaticArray, dchar) == false);
@@ -338,12 +293,6 @@ void test8()
assert(__traits(isAbstractClass, float) == false);
assert(__traits(isAbstractClass, double) == false);
assert(__traits(isAbstractClass, real) == false);
- assert(__traits(isAbstractClass, ifloat) == false);
- assert(__traits(isAbstractClass, idouble) == false);
- assert(__traits(isAbstractClass, ireal) == false);
- assert(__traits(isAbstractClass, cfloat) == false);
- assert(__traits(isAbstractClass, cdouble) == false);
- assert(__traits(isAbstractClass, creal) == false);
assert(__traits(isAbstractClass, char) == false);
assert(__traits(isAbstractClass, wchar) == false);
assert(__traits(isAbstractClass, dchar) == false);
@@ -400,18 +349,16 @@ void test13()
auto j = __traits(getMember, S, "z");
assert(j == 5);
- writeln(__traits(hasMember, s, "x"));
assert(__traits(hasMember, s, "x") == true);
assert(__traits(hasMember, S, "z") == true);
assert(__traits(hasMember, S, "aaa") == false);
auto k = __traits(classInstanceSize, C);
- writeln(k);
assert(k == C.classinfo.initializer.length);
}
/********************************************************/
-// 7123
+// https://issues.dlang.org/show_bug.cgi?id=7123
private struct DelegateFaker7123(F)
{
@@ -443,7 +390,6 @@ class D14
void test14()
{
auto a = [__traits(derivedMembers, D14)];
- writeln(a);
assert(a == ["__ctor","__dtor","foo", "__xdtor"]);
}
@@ -461,12 +407,15 @@ void test15()
{
D15 d = new D15();
- foreach (t; __traits(getVirtualFunctions, D15, "foo"))
- writeln(typeid(typeof(t)));
+ assert(__traits(getVirtualFunctions, D15, "foo").length == 2);
+ assert(typeid(typeof(__traits(getVirtualFunctions, D15, "foo")[0])).toString()
+ == "void function()");
+ assert(typeid(typeof(__traits(getVirtualFunctions, D15, "foo")[1])).toString()
+ == "int function(int)");
alias typeof(__traits(getVirtualFunctions, D15, "foo")) b;
- foreach (t; b)
- writeln(typeid(t));
+ assert(typeid(b[0]).toString() == "void function()");
+ assert(typeid(b[1]).toString() == "int function(int)");
auto i = __traits(getVirtualFunctions, d, "foo")[1](1);
assert(i == 2);
@@ -485,8 +434,8 @@ void test16()
assert(__traits(isSame, foo16, bar16) == false);
assert(__traits(isSame, foo16, S16) == false);
assert(__traits(isSame, S16, S16) == true);
- assert(__traits(isSame, std, S16) == false);
- assert(__traits(isSame, std, std) == true);
+ assert(__traits(isSame, core, S16) == false);
+ assert(__traits(isSame, core, core) == true);
}
/********************************************************/
@@ -508,7 +457,7 @@ void test17()
assert(__traits(compiles, typeof(1)) == true);
assert(__traits(compiles, S17.s1) == true);
assert(__traits(compiles, S17.s3) == false);
- assert(__traits(compiles, 1,2,3,int,long,std) == true);
+ assert(__traits(compiles, 1,2,3,int,long,core) == true);
assert(__traits(compiles, 3[1]) == false);
assert(__traits(compiles, 1,2,3,int,long,3[1]) == false);
}
@@ -525,7 +474,6 @@ interface D18
void test18()
{
auto a = __traits(allMembers, D18);
- writeln(a);
assert(a.length == 1);
}
@@ -546,11 +494,10 @@ class C19
void test19()
{
auto a = __traits(allMembers, C19);
- writeln(a);
assert(a.length == 9);
foreach( m; __traits(allMembers, C19) )
- writeln(m);
+ printf("%.*s\n", cast(int)m.length, m.ptr);
}
@@ -603,12 +550,14 @@ void test22()
{
D22 d = new D22();
- foreach (t; __traits(getOverloads, D22, "foo"))
- writeln(typeid(typeof(t)));
+ assert(typeid(typeof(__traits(getOverloads, D22, "foo")[0])).toString()
+ == "void function()");
+ assert(typeid(typeof(__traits(getOverloads, D22, "foo")[1])).toString()
+ == "int function(int)");
alias typeof(__traits(getOverloads, D22, "foo")) b;
- foreach (t; b)
- writeln(typeid(t));
+ assert(typeid(b[0]).toString() == "void function()");
+ assert(typeid(b[1]).toString() == "int function(int)");
auto i = __traits(getOverloads, d, "foo")[1](1);
assert(i == 2);
@@ -642,7 +591,7 @@ struct Test24
static assert(__traits(getVisibility, __traits(getOverloads, Test24, "test24")[1]) == "private");
/********************************************************/
-// 1369
+// https://issues.dlang.org/show_bug.cgi?id=1369
void test1369()
{
@@ -698,7 +647,7 @@ static assert([__traits(allMembers, S2234b)] == ["x"]);
static assert([__traits(allMembers, S2234c)] == ["foo"]);
/********************************************************/
-// 5878
+// https://issues.dlang.org/show_bug.cgi?id=5878
template J5878(A)
{
@@ -735,7 +684,7 @@ static assert([__traits(allMembers,Test6674)] == [
"toString","toHash","opCmp","opEquals","Monitor","factory"]);
/********************************************************/
-// 6073
+// https://issues.dlang.org/show_bug.cgi?id=6073
struct S6073 {}
@@ -747,13 +696,13 @@ alias T6073!(__traits(parent, S6073)) U6073; // error
static assert(__traits(isSame, V6073, U6073)); // same instantiation == same arguemnts
/********************************************************/
-// 7027
+// https://issues.dlang.org/show_bug.cgi?id=7027
struct Foo7027 { int a; }
static assert(!__traits(compiles, { return Foo7027.a; }));
/********************************************************/
-// 9213
+// https://issues.dlang.org/show_bug.cgi?id=9213
class Foo9213 { int a; }
static assert(!__traits(compiles, { return Foo9213.a; }));
@@ -795,7 +744,7 @@ static assert(__traits(isVirtualMethod, FF.YYY));
static assert(__traits(getVirtualMethods, FF, "YYY").length == 1);
/********************************************************/
-// 7608
+// https://issues.dlang.org/show_bug.cgi?id=7608
struct S7608a(bool T)
{
@@ -820,7 +769,7 @@ void test7608()
}
/********************************************************/
-// 7858
+// https://issues.dlang.org/show_bug.cgi?id=7858
void test7858()
{
@@ -857,7 +806,7 @@ void test7858()
}
/********************************************************/
-// 8971
+// https://issues.dlang.org/show_bug.cgi?id=8971
template Tuple8971(TL...){ alias TL Tuple8971; }
@@ -873,7 +822,7 @@ class A8971
}
/********************************************************/
-// 8972
+// https://issues.dlang.org/show_bug.cgi?id=8972
struct A8972
{
@@ -956,7 +905,7 @@ void getVisibility()
}
/********************************************************/
-// 9546
+// https://issues.dlang.org/show_bug.cgi?id=9546
void test9546()
{
@@ -1007,7 +956,7 @@ void test9546()
}
/********************************************************/
-// 9091
+// https://issues.dlang.org/show_bug.cgi?id=9091
template isVariable9091(X...) if (X.length == 1)
{
@@ -1153,7 +1102,7 @@ void test9237()
}
/*************************************************************/
-// 5978
+// https://issues.dlang.org/show_bug.cgi?id=5978
void test5978()
{
@@ -1178,7 +1127,7 @@ void test7408()
}
/*************************************************************/
-// 9552
+// https://issues.dlang.org/show_bug.cgi?id=9552
class C9552
{
@@ -1225,7 +1174,7 @@ void test9136()
}
/********************************************************/
-// 9939
+// https://issues.dlang.org/show_bug.cgi?id=9939
struct Test9939
{
@@ -1245,7 +1194,7 @@ struct Test9939
static assert([__traits(allMembers, Test9939)] == ["f", "A", "B", "NamedEnum"]);
/********************************************************/
-// 10043
+// https://issues.dlang.org/show_bug.cgi?id=10043
void test10043()
{
@@ -1255,7 +1204,7 @@ void test10043()
}
/********************************************************/
-// 10096
+// https://issues.dlang.org/show_bug.cgi?id=10096
struct S10096X
{
@@ -1270,7 +1219,7 @@ struct S10096X
this(this) {}
~this() {}
- string getStr() in { assert(str); } out(r) { assert(r == str); } body { return str; }
+ string getStr() in(str) out(r; r == str) { return str; }
}
static assert(
[__traits(allMembers, S10096X)] ==
@@ -1288,7 +1237,7 @@ class C10096X
this(int) {}
~this() {}
- string getStr() in { assert(str); } out(r) { assert(r == str); } body { return str; }
+ string getStr() in(str) out(r; r == str) { return str; }
}
static assert(
[__traits(allMembers, C10096X)] ==
@@ -1341,117 +1290,6 @@ void test_getUnitTests ()
/********************************************************/
-void test_getFunctionAttributes()
-{
- alias tuple(T...) = T;
-
- struct S
- {
- int noF() { return 0; }
- int constF() const { return 0; }
- int immutableF() immutable { return 0; }
- int inoutF() inout { return 0; }
- int sharedF() shared { return 0; }
-
- int x;
- ref int refF() { return x; }
- int propertyF() @property { return 0; }
- int nothrowF() nothrow { return 0; }
- int nogcF() @nogc { return 0; }
-
- int systemF() @system { return 0; }
- int trustedF() @trusted { return 0; }
- int safeF() @safe { return 0; }
-
- int pureF() pure { return 0; }
- }
-
- static assert(__traits(getFunctionAttributes, S.noF) == tuple!("@system"));
- static assert(__traits(getFunctionAttributes, typeof(S.noF)) == tuple!("@system"));
-
- static assert(__traits(getFunctionAttributes, S.constF) == tuple!("const", "@system"));
- static assert(__traits(getFunctionAttributes, typeof(S.constF)) == tuple!("const", "@system"));
-
- static assert(__traits(getFunctionAttributes, S.immutableF) == tuple!("immutable", "@system"));
- static assert(__traits(getFunctionAttributes, typeof(S.immutableF)) == tuple!("immutable", "@system"));
-
- static assert(__traits(getFunctionAttributes, S.inoutF) == tuple!("inout", "@system"));
- static assert(__traits(getFunctionAttributes, typeof(S.inoutF)) == tuple!("inout", "@system"));
-
- static assert(__traits(getFunctionAttributes, S.sharedF) == tuple!("shared", "@system"));
- static assert(__traits(getFunctionAttributes, typeof(S.sharedF)) == tuple!("shared", "@system"));
-
- static assert(__traits(getFunctionAttributes, S.refF) == tuple!("ref", "@system"));
- static assert(__traits(getFunctionAttributes, typeof(S.refF)) == tuple!("ref", "@system"));
-
- static assert(__traits(getFunctionAttributes, S.propertyF) == tuple!("@property", "@system"));
- static assert(__traits(getFunctionAttributes, typeof(&S.propertyF)) == tuple!("@property", "@system"));
-
- static assert(__traits(getFunctionAttributes, S.nothrowF) == tuple!("nothrow", "@system"));
- static assert(__traits(getFunctionAttributes, typeof(S.nothrowF)) == tuple!("nothrow", "@system"));
-
- static assert(__traits(getFunctionAttributes, S.nogcF) == tuple!("@nogc", "@system"));
- static assert(__traits(getFunctionAttributes, typeof(S.nogcF)) == tuple!("@nogc", "@system"));
-
- static assert(__traits(getFunctionAttributes, S.systemF) == tuple!("@system"));
- static assert(__traits(getFunctionAttributes, typeof(S.systemF)) == tuple!("@system"));
-
- static assert(__traits(getFunctionAttributes, S.trustedF) == tuple!("@trusted"));
- static assert(__traits(getFunctionAttributes, typeof(S.trustedF)) == tuple!("@trusted"));
-
- static assert(__traits(getFunctionAttributes, S.safeF) == tuple!("@safe"));
- static assert(__traits(getFunctionAttributes, typeof(S.safeF)) == tuple!("@safe"));
-
- static assert(__traits(getFunctionAttributes, S.pureF) == tuple!("pure", "@system"));
- static assert(__traits(getFunctionAttributes, typeof(S.pureF)) == tuple!("pure", "@system"));
-
- int pure_nothrow() nothrow pure { return 0; }
- static ref int static_ref_property() @property { return *(new int); }
- ref int ref_property() @property { return *(new int); }
- void safe_nothrow() @safe nothrow { }
-
- static assert(__traits(getFunctionAttributes, pure_nothrow) == tuple!("pure", "nothrow", "@nogc", "@safe"));
- static assert(__traits(getFunctionAttributes, typeof(pure_nothrow)) == tuple!("pure", "nothrow", "@nogc", "@safe"));
-
- static assert(__traits(getFunctionAttributes, static_ref_property) == tuple!("pure", "nothrow", "@property", "ref", "@safe"));
- static assert(__traits(getFunctionAttributes, typeof(&static_ref_property)) == tuple!("pure", "nothrow", "@property", "ref", "@safe"));
-
- static assert(__traits(getFunctionAttributes, ref_property) == tuple!("pure", "nothrow", "@property", "ref", "@safe"));
- static assert(__traits(getFunctionAttributes, typeof(&ref_property)) == tuple!("pure", "nothrow", "@property", "ref", "@safe"));
-
- static assert(__traits(getFunctionAttributes, safe_nothrow) == tuple!("pure", "nothrow", "@nogc", "@safe"));
- static assert(__traits(getFunctionAttributes, typeof(safe_nothrow)) == tuple!("pure", "nothrow", "@nogc", "@safe"));
-
- struct S2
- {
- int pure_const() const pure { return 0; }
- int pure_sharedconst() const shared pure { return 0; }
- }
-
- static assert(__traits(getFunctionAttributes, S2.pure_const) == tuple!("const", "pure", "@system"));
- static assert(__traits(getFunctionAttributes, typeof(S2.pure_const)) == tuple!("const", "pure", "@system"));
-
- static assert(__traits(getFunctionAttributes, S2.pure_sharedconst) == tuple!("const", "shared", "pure", "@system"));
- static assert(__traits(getFunctionAttributes, typeof(S2.pure_sharedconst)) == tuple!("const", "shared", "pure", "@system"));
-
- static assert(__traits(getFunctionAttributes, (int a) { }) == tuple!("pure", "nothrow", "@nogc", "@safe"));
- static assert(__traits(getFunctionAttributes, typeof((int a) { })) == tuple!("pure", "nothrow", "@nogc", "@safe"));
-
- auto safeDel = delegate() @safe { };
- static assert(__traits(getFunctionAttributes, safeDel) == tuple!("pure", "nothrow", "@nogc", "@safe"));
- static assert(__traits(getFunctionAttributes, typeof(safeDel)) == tuple!("pure", "nothrow", "@nogc", "@safe"));
-
- auto trustedDel = delegate() @trusted { };
- static assert(__traits(getFunctionAttributes, trustedDel) == tuple!("pure", "nothrow", "@nogc", "@trusted"));
- static assert(__traits(getFunctionAttributes, typeof(trustedDel)) == tuple!("pure", "nothrow", "@nogc", "@trusted"));
-
- auto systemDel = delegate() @system { };
- static assert(__traits(getFunctionAttributes, systemDel) == tuple!("pure", "nothrow", "@nogc", "@system"));
- static assert(__traits(getFunctionAttributes, typeof(systemDel)) == tuple!("pure", "nothrow", "@nogc", "@system"));
-}
-
-/********************************************************/
-
class TestIsOverrideFunctionBase
{
void bar () {}
@@ -1469,7 +1307,8 @@ void test_isOverrideFunction ()
}
/********************************************************/
-// 11711 - Add __traits(getAliasThis)
+// https://issues.dlang.org/show_bug.cgi?id=11711
+// Add __traits(getAliasThis)
alias TypeTuple(T...) = T;
@@ -1492,11 +1331,15 @@ void test11711()
static assert(__traits(getAliasThis, S2) == TypeTuple!("var"));
static assert(is(typeof(__traits(getMember, S2.init, __traits(getAliasThis, S2)[0]))
== TypeTuple!(int, string)));
+
+ // https://issues.dlang.org/show_bug.cgi?id=19439
+ // Return empty tuple for non-aggregate types.
+ static assert(__traits(getAliasThis, int).length == 0);
}
/********************************************************/
-// Issue 12278
+// https://issues.dlang.org/show_bug.cgi?id=12278
class Foo12278
{
@@ -1511,7 +1354,7 @@ struct InPlace12278(T)
}
/********************************************************/
-// 12571
+// https://issues.dlang.org/show_bug.cgi?id=12571
mixin template getScopeName12571()
{
@@ -1525,7 +1368,7 @@ void test12571()
}
/********************************************************/
-// 12237
+// https://issues.dlang.org/show_bug.cgi?id=12237
auto f12237(T)(T a)
{
@@ -1564,7 +1407,7 @@ void async(ARGS...)(ARGS)
alias test17495 = async!(int, int);
/********************************************************/
-// 15094
+// https://issues.dlang.org/show_bug.cgi?id=15094
void test15094()
{
@@ -1638,11 +1481,10 @@ int main()
test9136();
test10096();
test_getUnitTests();
- test_getFunctionAttributes();
test_isOverrideFunction();
test12237();
test15094();
- writeln("Success");
+ printf("Success\n");
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/traits_getPointerBitmap.d b/gcc/testsuite/gdc.test/runnable/traits_getPointerBitmap.d
index 512bcea..3c5a4bd 100644
--- a/gcc/testsuite/gdc.test/runnable/traits_getPointerBitmap.d
+++ b/gcc/testsuite/gdc.test/runnable/traits_getPointerBitmap.d
@@ -1,8 +1,7 @@
module traits_getPointerBitmap;
-import std.stdio;
-static import std.traits;
+import core.stdc.stdio;
// version = RTInfo;
// debug = LOG;
@@ -190,7 +189,7 @@ class N
union U
{
- size_t data[4];
+ size_t[4] data;
Large*[] arr; // { length, ptr }
struct
@@ -210,8 +209,6 @@ void testRTInfo()
testType!(int) ([ 0b0 ]);
testType!(long) ([ 0b00 ]);
testType!(double) ([ 0b00 ]);
- testType!(ifloat) ([ 0b0 ]);
- testType!(cdouble) ([ 0b0000 ]);
testType!(dg) ([ 0b01 ]);
testType!(fn) ([ 0b0 ]);
testType!(S!fn) ([ 0b100 ]);
diff --git a/gcc/testsuite/gdc.test/runnable/traits_getUnitTests.d b/gcc/testsuite/gdc.test/runnable/traits_getUnitTests.d
index 38295ae..2786917 100644
--- a/gcc/testsuite/gdc.test/runnable/traits_getUnitTests.d
+++ b/gcc/testsuite/gdc.test/runnable/traits_getUnitTests.d
@@ -62,7 +62,7 @@ void test_getUnitTestsFromImport ()
static assert(__traits(getUnitTests, mixin("imports.traits_getUnitTests_import")).length == 1);
}
-// 11358
+// https://issues.dlang.org/show_bug.cgi?id=11358
debug { }
enum len11358 = __traits(getUnitTests, mixin(__MODULE__)).length;
diff --git a/gcc/testsuite/gdc.test/runnable/tuple_default_parameters.d b/gcc/testsuite/gdc.test/runnable/tuple_default_parameters.d
new file mode 100644
index 0000000..a725d31
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/tuple_default_parameters.d
@@ -0,0 +1,64 @@
+void main()
+{
+ assert(func(1,0) == 1);
+ assert(func(1) == 1);
+ assert(func2() == 0);
+
+ assert(func3() == 15);
+ assert(func3(2) == 10);
+ assert(func3(2, 1) == 2);
+
+ assert(func4() == 15);
+
+ assert(func5() == 86);
+ assert(func5(1) == 84);
+ assert(func5(1, 2) == 81);
+ assert(func5(1, 2, 3) == 80);
+ assert(func5(1, 2, 3, 4) == 74);
+ assert(func5(1, 2, 3, 4, 0) == 69);
+ assert(func5(1, 2, 3, 4, 0, 5) == 68);
+ assert(func5(1, 2, 3, 4, 0, 5, 6) == 32);
+ assert(func5(1, 2, 3, 4, 0, 5, 6, 7) == 37);
+ assert(func5(1, 2, 3, 4, 0, 5, 6, 7, 8) == 42);
+ assert(func5(1, 2, 3, 4, 0, 5, 6, 7, 8, 9) == 46);
+}
+
+template AliasSeq(TList...)
+{
+ alias AliasSeq = TList;
+}
+
+T func(T)(T value, AliasSeq!(int) params = AliasSeq!(0))
+{
+ return value;
+}
+
+int func2(AliasSeq!(int) params = AliasSeq!(0))
+{
+ return 0;
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=21258
+int func3(AliasSeq!(int, int) args = AliasSeq!(3, 5))
+{
+ return args[0] * args[1];
+}
+
+size_t func4(AliasSeq!(int, string) args = AliasSeq!(3, "hello"))
+{
+ return args[0] * args[1].length;
+}
+
+int func5(AliasSeq!(int, int, int) a1 = AliasSeq!(3, 5, 4),
+ AliasSeq!(int, int, int) a2 = AliasSeq!(10, 5, 6),
+ int a3 = 42,
+ AliasSeq!(int, int, int) a4 = AliasSeq!(2, 3, 5),
+ int a5 = 1,
+ )
+{
+ return a1[0] + a1[1] + a1[2] +
+ a2[0] + a2[1] + a2[2] +
+ a3 +
+ a4[0] + a4[1] + a4[2] +
+ a5;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/uda.d b/gcc/testsuite/gdc.test/runnable/uda.d
index a01a5ca..cdb9aa6 100644
--- a/gcc/testsuite/gdc.test/runnable/uda.d
+++ b/gcc/testsuite/gdc.test/runnable/uda.d
@@ -286,7 +286,7 @@ void test12()
}
/************************************************/
-// 9178
+// https://issues.dlang.org/show_bug.cgi?id=9178
void test9178()
{
@@ -297,7 +297,7 @@ void test9178()
}
/************************************************/
-// 9652
+// https://issues.dlang.org/show_bug.cgi?id=9652
struct Bug9652
{
@@ -353,7 +353,7 @@ struct Bug9652
}
/************************************************/
-// 9741
+// https://issues.dlang.org/show_bug.cgi?id=9741
import imports.a9741;
@@ -364,7 +364,7 @@ alias X9741 = ShowAttributes!(B9741);
@A9741 struct B9741 {}
/************************************************/
-// 12160
+// https://issues.dlang.org/show_bug.cgi?id=12160
auto before12160(alias Hook)(string) { return 0; }
@@ -384,7 +384,7 @@ void test12160()
}
/************************************************/
-// 10208
+// https://issues.dlang.org/show_bug.cgi?id=10208
@( 10) enum int x10208_01 = 100;
@( 20) int x10208_02;
@@ -416,7 +416,8 @@ static assert(__traits(getAttributes, x10208_13)[0] == 130); // Error -> OK
static assert(__traits(getAttributes, x10208_14)[0] == 140); // Error -> OK
/************************************************/
-// 11677, 11678
+// https://issues.dlang.org/show_bug.cgi?id=11677
+// https://issues.dlang.org/show_bug.cgi?id=11678
bool test_uda(alias func)() @safe
{
@@ -445,7 +446,7 @@ static assert(test_uda!func11678b());
static assert(test_uda!func11678c());
/************************************************/
-// 11678
+// https://issues.dlang.org/show_bug.cgi?id=11678
class C11678
{
@@ -460,7 +461,7 @@ static ~this() @(10) @(20) {}
shared static ~this() @(10) @(20) {}
/************************************************/
-// 11679
+// https://issues.dlang.org/show_bug.cgi?id=11679
void test11679()
{
@@ -469,7 +470,7 @@ void test11679()
}
/************************************************/
-// 11680
+// https://issues.dlang.org/show_bug.cgi?id=11680
@(10) gvar11680 = 1; // OK <- NG
@(10) gfun11680() {} // OK <- NG
@@ -481,7 +482,7 @@ void test11680()
}
/************************************************/
-// 11844
+// https://issues.dlang.org/show_bug.cgi?id=11844
auto make_encode11844(T, string name)()
{
@@ -687,7 +688,14 @@ void test20()
}
/************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=20831
+void foo20831(int f, float, @("test") string s = "test") {}
+
+static if(is(typeof(foo20831) Params20831 == __parameters))
+ static assert([__traits(getAttributes, Params20831[1..2])] == []);
+
+/************************************************/
int main()
{
diff --git a/gcc/testsuite/gdc.test/runnable/ufcs.d b/gcc/testsuite/gdc.test/runnable/ufcs.d
index e09c531..2d9bf15 100644
--- a/gcc/testsuite/gdc.test/runnable/ufcs.d
+++ b/gcc/testsuite/gdc.test/runnable/ufcs.d
@@ -129,7 +129,6 @@ void test3()
assert([1] .init == null);
assert([1:1].init == null);
assert(1.0 .init is double.nan);
- assert(10i .init is idouble.nan);
assert('c' .init == 0xFF);
assert("s" .init == null);
@@ -138,7 +137,6 @@ void test3()
assert([1] .init() == 1);
assert([1:1].init() == 1);
assert(1.0 .init() == 1);
- assert(10i .init() == 1);
assert('c' .init() == 1);
assert("s" .init() == 1);
@@ -147,7 +145,6 @@ void test3()
assert([1] .init!(int[])() == 1);
assert([1:1].init!(int[int])() == 1);
assert(1.0 .init!double() == 1);
- assert(10i .init!idouble() == 1);
assert('c' .init!char() == 1);
assert("s" .init!string() == 1);
@@ -422,9 +419,7 @@ class C5 : B5
}
/*******************************************/
-// 662
-
-import std.stdio,std.string, std.conv;
+// https://issues.dlang.org/show_bug.cgi?id=662
enum Etest
{
@@ -450,6 +445,10 @@ int test(Etest test)
//{
// return cast(int)i;
//}
+string to(T)(int i) {
+ assert(i == 22);
+ return "22";
+}
void test682()
{
@@ -465,16 +464,56 @@ void test682()
}
/*******************************************/
-// 3382
-
-import std.range, std.algorithm;
+// https://issues.dlang.org/show_bug.cgi?id=3382
@property T twice(T)(T x){ return x * x; }
-real toreal(ireal x){ return x.im; }
char toupper(char c){ return ('a'<=c && c<='z') ? cast(char)(c - 'a' + 'A') : c; }
@property ref T setter(T)(ref T x, T v){ x = v; return x; }
+auto iota(T)(T min, T max)
+{
+ static struct Result
+ {
+ T cur, end;
+
+ T front() { return cur; }
+ bool empty() { return front == end; }
+ void popFront() { cur++; }
+ }
+ return Result(min, max);
+}
+
+auto map(string s, R)(R range)
+{
+ static struct Result
+ {
+ R source;
+ auto front() { auto a = source.front; return mixin(s); }
+ alias source this;
+ }
+ return Result(range);
+}
+
+auto filter(string s, R)(R range)
+{
+ static struct Result
+ {
+ R source;
+ alias source this;
+ void popFront()
+ {
+ while (true)
+ {
+ auto a = source.front;
+ if (mixin(s)) break;
+ source.popFront();
+ }
+ }
+ }
+ return Result(range);
+}
+
void test3382()
{
auto r = iota(0, 10).map!"a*3"().filter!"a%2 != 0"();
@@ -483,17 +522,29 @@ void test3382()
assert(10.twice == 100);
assert(0.5.twice == 0.25);
- assert(1.4i.toreal() == 1.4);
assert('c'.toupper() == 'C');
}
/*******************************************/
-// 6185
+// https://issues.dlang.org/show_bug.cgi?id=6185
-void test6185()
+ref T front(T)(T[] array) { return array[0]; }
+bool empty(T)(T[] array) { return array.length == 0; }
+void popFront(T)(ref T[] array) { array = array[1..$]; }
+
+bool equal(T, U)(T t, U u)
{
- import std.algorithm;
+ while (true)
+ {
+ if (t.empty) return u.empty;
+ if (u.empty || t.front != u.front) return false;
+ t.popFront();
+ u.popFront();
+ }
+}
+void test6185()
+{
auto r1 = [1,2,3].map!"a*2";
assert(equal(r1, [2,4,6]));
@@ -502,7 +553,7 @@ void test6185()
}
/*******************************************/
-// 6070
+// https://issues.dlang.org/show_bug.cgi?id=6070
enum test6070a = ["test"].foo6070();
enum test6070b = foo6070(["test"]);
@@ -510,13 +561,13 @@ enum test6070b = foo6070(["test"]);
string foo6070(string[] s) { return ""; }
/*******************************************/
-// 7670
+// https://issues.dlang.org/show_bug.cgi?id=7670
struct A7670
{
double x;
}
-@property ref double y7670(ref A7670 a)
+@property ref double y7670(return ref A7670 a)
{
return a.x;
}
@@ -528,7 +579,7 @@ void test7670()
}
/*******************************************/
-// 7703
+// https://issues.dlang.org/show_bug.cgi?id=7703
void f7703(T)(T a) { }
void test7703()
@@ -541,9 +592,9 @@ void test7703()
}
/*******************************************/
-// 7773
+// https://issues.dlang.org/show_bug.cgi?id=7773
-//import std.stdio;
+//import core.stdc.stdio;
void writeln7773(int n){}
void test7773()
{
@@ -552,7 +603,7 @@ void test7773()
}
/*******************************************/
-// 7943
+// https://issues.dlang.org/show_bug.cgi?id=7943
struct Foo7943
{
@@ -570,7 +621,7 @@ void test7943()
}
/*******************************************/
-// 8180
+// https://issues.dlang.org/show_bug.cgi?id=8180
int writeln8180(T...)(T args) { return 1; }
@@ -587,7 +638,7 @@ void test8180()
}
/*******************************************/
-// 8245
+// https://issues.dlang.org/show_bug.cgi?id=8245
string toStr8245(immutable(char)* p) { return null; }
@property string asStr8245(immutable(char)* p) { return null; }
@@ -600,7 +651,7 @@ void test8245()
}
/*******************************************/
-// 8252
+// https://issues.dlang.org/show_bug.cgi?id=8252
bool f(int x) { return !x; }
@@ -611,7 +662,7 @@ void test8252()
}
/*******************************************/
-// 8453
+// https://issues.dlang.org/show_bug.cgi?id=8453
T[] sort8453(T)(T[] a) { return a; }
@@ -623,7 +674,7 @@ void test8453()
}
/*******************************************/
-// 8503
+// https://issues.dlang.org/show_bug.cgi?id=8503
void α8503(int i) {}
@@ -634,7 +685,7 @@ void test8503()
}
/*******************************************/
-// 9014
+// https://issues.dlang.org/show_bug.cgi?id=9014
@property ref int foo9014(int[] a)
{
@@ -649,7 +700,7 @@ void test9014()
}
/*******************************************/
-// 9590
+// https://issues.dlang.org/show_bug.cgi?id=9590
auto func9590(E)(lazy E expr) { }
@@ -666,7 +717,7 @@ void test9590()
}
/*******************************************/
-// 9946
+// https://issues.dlang.org/show_bug.cgi?id=9946
size_t count9946(alias x)(int[] haystack)
{
@@ -682,7 +733,7 @@ void test9946()
}
/*******************************************/
-// 10618
+// https://issues.dlang.org/show_bug.cgi?id=10618
template Temp10618(T)
{
@@ -695,7 +746,7 @@ void test10618()
}
/*******************************************/
-// 10003
+// https://issues.dlang.org/show_bug.cgi?id=10003
void foo10003(void *p) {}
void test10003()
@@ -705,7 +756,7 @@ void test10003()
}
/*******************************************/
-// 10041
+// https://issues.dlang.org/show_bug.cgi?id=10041
auto writeln10041(T...)(T args) { return typeof(args[0]).stringof; }
@@ -717,7 +768,7 @@ void test10041()
}
/*******************************************/
-// 10047
+// https://issues.dlang.org/show_bug.cgi?id=10047
struct Typedef10047(T)
{
@@ -737,7 +788,7 @@ void test10047()
}
/*******************************************/
-// 10166
+// https://issues.dlang.org/show_bug.cgi?id=10166
auto foo10166()
{
@@ -752,7 +803,7 @@ void bar10166(alias handler, T)(T t, int i)
void buzz10166() {}
/*******************************************/
-// 10526
+// https://issues.dlang.org/show_bug.cgi?id=10526
struct S10526
{
@@ -781,7 +832,7 @@ void test10526()
}
/********************************************************/
-// 10609
+// https://issues.dlang.org/show_bug.cgi?id=10609
int foo10609(int x) { return x; }
@@ -794,7 +845,7 @@ void test10609()
}
/*******************************************/
-// 11312
+// https://issues.dlang.org/show_bug.cgi?id=11312
struct S11312;
@@ -809,7 +860,7 @@ void test11312()
}
/*******************************************/
-// 15123
+// https://issues.dlang.org/show_bug.cgi?id=15123
auto keys15123(K, V)(V[K] aa) { return [1]; }
auto values15123(K, V)(V[K] aa) { return [2]; }
diff --git a/gcc/testsuite/gdc.test/runnable/uniformctor.d b/gcc/testsuite/gdc.test/runnable/uniformctor.d
index d56c782..6cd4582 100644
--- a/gcc/testsuite/gdc.test/runnable/uniformctor.d
+++ b/gcc/testsuite/gdc.test/runnable/uniformctor.d
@@ -1,10 +1,16 @@
+/*
+RUN_OUTPUT:
+---
+Success
+---
+*/
extern(C) int printf(const char*, ...);
template TypeTuple(TL...) { alias TypeTuple = TL; }
import core.stdc.math : isnan;
/********************************************/
-// 9112
+// https://issues.dlang.org/show_bug.cgi?id=9112
void test9112a() // T() and T(v)
{
@@ -40,19 +46,12 @@ void test9112a() // T() and T(v)
test!( float )(3.14);
test!( double)(3.14);
test!( real )(3.14);
- test!(ifloat )(1.4142i);
- test!(idouble)(1.4142i);
- test!(ireal )(1.4142i);
- test!(cfloat )(1.2+3.4i);
- test!(cdouble)(1.2+3.4i);
- test!(creal )(1.2+3.4i);
test!( char )('A');
test!(wchar )('A');
test!(dchar )('A');
test!(bool )(true);
static assert(!__traits(compiles, int(1.42))); // in curre,t this is disallowed
- static assert(!__traits(compiles, double(3.14i)));
{
int x;
@@ -107,12 +106,6 @@ void test9112b() // new T(v)
test!( float )(3.14);
test!( double)(3.14);
test!( real )(3.14);
- test!(ifloat )(1.4142i);
- test!(idouble)(1.4142i);
- test!(ireal )(1.4142i);
- test!(cfloat )(1.2+3.4i);
- test!(cdouble)(1.2+3.4i);
- test!(creal )(1.2+3.4i);
test!( char )('A');
test!(wchar )('A');
test!(dchar )('A');
@@ -138,7 +131,6 @@ void test9112b() // new T(v)
static assert(!__traits(compiles, new const int(1, 2)));
static assert(!__traits(compiles, new int(1.42))); // in curre,t this is disallowed
- static assert(!__traits(compiles, new double(3.14i)));
// int(1) in directly on statement scope should be parsed as an expression, but
// would fail to compile because of "has no effect" error.
diff --git a/gcc/testsuite/gdc.test/runnable/unique_typeinfo_names.d b/gcc/testsuite/gdc.test/runnable/unique_typeinfo_names.d
new file mode 100644
index 0000000..120f8ff
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/unique_typeinfo_names.d
@@ -0,0 +1,93 @@
+module unique_typeinfo_names;
+
+// https://issues.dlang.org/show_bug.cgi?id=22149
+void structs()
+{
+ static struct Foo(T) {}
+
+ auto foo()
+ {
+ struct S {}
+ return Foo!S();
+ }
+
+ auto bar()
+ {
+ struct S {}
+ return Foo!S();
+ }
+
+ auto f = foo();
+ auto b = bar();
+
+ assert(typeid(f) != typeid(b));
+ assert(typeid(f).name != typeid(b).name);
+
+ assert(typeid(f).mangledName == typeof(f).mangleof);
+ assert(typeid(b).mangledName == typeof(b).mangleof);
+ assert(typeid(f).name == "unique_typeinfo_names.structs().Foo!(unique_typeinfo_names.structs().foo().S).Foo");
+ assert(typeid(b).name == "unique_typeinfo_names.structs().Foo!(unique_typeinfo_names.structs().bar().S).Foo");
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=22150
+void classes()
+{
+ static class Foo(T) {}
+
+ static auto foo()
+ {
+ struct S {}
+ return new Foo!S();
+ }
+
+ static auto bar()
+ {
+ struct S {}
+ return new Foo!S();
+ }
+
+ auto f = foo();
+ auto b = bar();
+
+ assert(typeid(f) != typeid(b));
+ assert(typeid(f).name != typeid(b).name);
+
+ assert(typeid(f).name == "unique_typeinfo_names.classes.Foo!(unique_typeinfo_names.classes.foo.S).Foo");
+ assert(typeid(b).name == "unique_typeinfo_names.classes.Foo!(unique_typeinfo_names.classes.bar.S).Foo");
+}
+
+void interfaces()
+{
+ static interface IFoo(T) {}
+ static class Foo(T) : IFoo!T {}
+
+ static auto foo()
+ {
+ struct S {}
+ IFoo!S r = new Foo!S();
+ return r;
+ }
+
+ static auto bar()
+ {
+ struct S {}
+ IFoo!S r = new Foo!S();
+ return r;
+ }
+
+ auto f = foo();
+ auto b = bar();
+
+ assert(typeid(f) != typeid(b));
+ assert(typeid(f).name != typeid(b).name);
+
+ assert(typeid(f).name == "unique_typeinfo_names.interfaces.IFoo!(unique_typeinfo_names.interfaces.foo.S).IFoo");
+ assert(typeid(b).name == "unique_typeinfo_names.interfaces.IFoo!(unique_typeinfo_names.interfaces.bar.S).IFoo");
+}
+
+void main()
+{
+ structs();
+ classes();
+ interfaces();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/variadic.d b/gcc/testsuite/gdc.test/runnable/variadic.d
index 984d896..2d0736d 100644
--- a/gcc/testsuite/gdc.test/runnable/variadic.d
+++ b/gcc/testsuite/gdc.test/runnable/variadic.d
@@ -672,7 +672,7 @@ void test61()
template Tuple63(T...){
alias T Tuple63;
}
-// Bugzilla 3336
+// https://issues.dlang.org/show_bug.cgi?id=3336
static assert(!is(int[ Tuple63!(int, int) ]));
void test63()
@@ -691,7 +691,7 @@ void test1411()
}
/***************************************/
-// Bugzilla 4444
+// https://issues.dlang.org/show_bug.cgi?id=4444
void test4444()
{
@@ -701,7 +701,7 @@ void test4444()
}
/***************************************/
-// 13864
+// https://issues.dlang.org/show_bug.cgi?id=13864
struct Tuple13864(T...)
{
@@ -721,7 +721,7 @@ void test13864()
}
/***************************************/
-// 4884
+// https://issues.dlang.org/show_bug.cgi?id=4884
struct A4884(T...)
{
@@ -736,7 +736,7 @@ void test4884()
}
/***************************************/
-// 4920
+// https://issues.dlang.org/show_bug.cgi?id=4920
struct Test4920(parameters_...)
{
@@ -751,7 +751,7 @@ void test4920()
}
/***************************************/
-// 4940
+// https://issues.dlang.org/show_bug.cgi?id=4940
template Tuple4940(T...)
{
@@ -777,7 +777,7 @@ struct S4940add
long x;
}
-ref S4940add get4940add(ref S4940add s){ return s; }
+ref S4940add get4940add(return ref S4940add s){ return s; }
void test4940add()
{
@@ -787,7 +787,7 @@ void test4940add()
}
/***************************************/
-// 6530
+// https://issues.dlang.org/show_bug.cgi?id=6530
struct S6530
{
@@ -876,7 +876,7 @@ void testCopy()
}
/***************************************/
-// 6700
+// https://issues.dlang.org/show_bug.cgi?id=6700
template bug6700(TList ...) {
const int bug6700 = 2;
@@ -886,7 +886,7 @@ TypeTuple!(int, long) TT6700;
static assert(bug6700!( (TT6700[1..$]) )==2);
/***************************************/
-// 6966
+// https://issues.dlang.org/show_bug.cgi?id=6966
template X6966(T...)
{
@@ -896,7 +896,7 @@ static assert(is(X6966!(int) == const(int)));
static assert(is(X6966!(int, 0) == const(int)));
/***************************************/
-// 7233
+// https://issues.dlang.org/show_bug.cgi?id=7233
struct Foo7233 { int x, y; }
Foo7233[] front7233(Foo7233[][] a)
@@ -920,7 +920,7 @@ void test7233()
}
/***************************************/
-// 7263
+// https://issues.dlang.org/show_bug.cgi?id=7263
template TypeTuple7263(T...){ alias T TypeTuple7263; }
@@ -940,13 +940,13 @@ void test7263()
}
/***************************************/
-// 8244
+// https://issues.dlang.org/show_bug.cgi?id=8244
TypeTuple!(int,int)[] x8244;
static assert(is(typeof(x8244) == TypeTuple!(int, int)));
/***************************************/
-// 9017
+// https://issues.dlang.org/show_bug.cgi?id=9017
template X9017(Args...)
{
@@ -974,13 +974,13 @@ void test9017()
}
/***************************************/
-// 10279
+// https://issues.dlang.org/show_bug.cgi?id=10279
void foo10279(int[][] strs...) @trusted { }
void bar10279() @safe { foo10279(); }
/***************************************/
-// 13508
+// https://issues.dlang.org/show_bug.cgi?id=13508
struct S13508
{
@@ -1001,7 +1001,7 @@ void test13508() @safe @nogc
}
/***************************************/
-// 14395
+// https://issues.dlang.org/show_bug.cgi?id=14395
int v2u14395(uint[1] ar...)
{
@@ -1019,7 +1019,7 @@ void test14395()
}
/***************************************/
-// 10414
+// https://issues.dlang.org/show_bug.cgi?id=10414
void foo10414(void delegate()[] ...) { }
@@ -1057,7 +1057,7 @@ void test14179()
}
/***************************************/
-// 10722
+// https://issues.dlang.org/show_bug.cgi?id=10722
struct S10722
{
diff --git a/gcc/testsuite/gdc.test/runnable/version.d b/gcc/testsuite/gdc.test/runnable/version.d
index 67da188..1186e4c 100644
--- a/gcc/testsuite/gdc.test/runnable/version.d
+++ b/gcc/testsuite/gdc.test/runnable/version.d
@@ -1,5 +1,12 @@
-// PERMUTE_ARGS:
-// REQUIRED_ARGS: -version=3 -version=foo
+/*
+PERMUTE_ARGS:
+REQUIRED_ARGS: -version=3 -version=foo
+RUN_OUTPUT:
+---
+i = 2
+i = 2
+---
+*/
extern(C) int printf(const char*, ...);
@@ -64,4 +71,3 @@ int main()
test2();
return 0;
}
-
diff --git a/gcc/testsuite/gdc.test/runnable/warning1.d b/gcc/testsuite/gdc.test/runnable/warning1.d
index 9dcbea9..537088e 100644
--- a/gcc/testsuite/gdc.test/runnable/warning1.d
+++ b/gcc/testsuite/gdc.test/runnable/warning1.d
@@ -120,7 +120,7 @@ nothrow int foo6()
}
/******************************************/
-// 6518
+// https://issues.dlang.org/show_bug.cgi?id=6518
template TypeTuple(T...) { alias T TypeTuple; }
void test6518()
@@ -134,7 +134,7 @@ void test6518()
}
/******************************************/
-// 7232
+// https://issues.dlang.org/show_bug.cgi?id=7232
bool test7232()
{
@@ -154,7 +154,7 @@ struct S9332
}
/******************************************/
-// 13201
+// https://issues.dlang.org/show_bug.cgi?id=13201
class C13201
{
diff --git a/gcc/testsuite/gdc.test/runnable/wc.d b/gcc/testsuite/gdc.test/runnable/wc.d
index 8f847c5..69d3cf8 100644
--- a/gcc/testsuite/gdc.test/runnable/wc.d
+++ b/gcc/testsuite/gdc.test/runnable/wc.d
@@ -37,14 +37,14 @@ int main (string[] args)
inword = 0;
++c_cnt;
}
- printf ("%8lu%8lu%8lu %.*s\n", l_cnt, w_cnt, c_cnt, arg.length, arg.ptr);
+ printf ("%8u%8u%8u %.*s\n", l_cnt, w_cnt, c_cnt, cast(int)arg.length, arg.ptr);
l_total += l_cnt;
w_total += w_cnt;
c_total += c_cnt;
}
if (args.length > 2)
{
- printf ("--------------------------------------\n%8lu%8lu%8lu total",
+ printf ("--------------------------------------\n%8u%8u%8u total",
l_total, w_total, c_total);
}
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/wc2.d b/gcc/testsuite/gdc.test/runnable/wc2.d
index a97c6fa..97fcdee 100644
--- a/gcc/testsuite/gdc.test/runnable/wc2.d
+++ b/gcc/testsuite/gdc.test/runnable/wc2.d
@@ -54,7 +54,7 @@ int main (string[] args)
{ string w = input[wstart .. input.length];
dictionary[w]++;
}
- printf("%8lu%8lu%8lu %.*s\n", l_cnt, w_cnt, c_cnt, arg.length, arg.ptr);
+ printf("%8u%8u%8u %.*s\n", l_cnt, w_cnt, c_cnt, cast(int)arg.length, arg.ptr);
l_total += l_cnt;
w_total += w_cnt;
c_total += c_cnt;
@@ -62,14 +62,14 @@ int main (string[] args)
if (args.length > 2)
{
- printf("--------------------------------------\n%8lu%8lu%8lu total",
+ printf("--------------------------------------\n%8u%8u%8u total",
l_total, w_total, c_total);
}
printf("--------------------------------------\n");
foreach (string word1; dictionary.keys)
{
- printf("%3d %.*s\n", dictionary[word1], word1.length, word1.ptr);
+ printf("%3d %.*s\n", dictionary[word1], cast(int)word1.length, word1.ptr);
}
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/whetstone.d b/gcc/testsuite/gdc.test/runnable/whetstone.d
new file mode 100644
index 0000000..9145c74
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/whetstone.d
@@ -0,0 +1,231 @@
+/*
+PERMUTE_ARGS: -O
+*/
+
+/*
+ WHETSTONE BENCHMARK PROGRAM
+
+ This program uses a carefully chosen mix of instructions typical of
+ scientific (floating point) calculations.
+
+ See H.J. Curnow and B.A. Wichmann,
+ "A Synthetic Benchmark", Computer J., V19 #1, Feb. 1976, pp. 43-49.
+
+ Table of times for various computers in <info-ibmpc>whetst.answers
+ compiled by Richard Gillmann (GILLMANN@ISIB)
+
+Whetstone Fortran Benchmark
+(I=10, optimization off, CPU seconds)
+
+DEC 1.1 sec DECsystem 2060 (TOPS-20 v4, F66)
+PR1ME 1.4 sec PR1ME 750 (PRIMOS v18.1, F66)
+PR1ME 1.5 sec PR1ME 750 (PRIMOS v18.1, F77)
+DEC 2.1 sec VAX 11/780 (Unix, F77)
+Apollo 6.2 sec 10 MHz MC68000 w/hardware float. point (AEGIS v4.0, F77)
+Apollo 13.1 sec 10 MHz MC68000 w/software float. point (AEGIS v4.0, F77)
+Intel 16.0 sec 8086/8087 (286WD Micro Development System,Intel FORTRAN)
+IBM 16.0 sec 4.77 MHz 8088 PC w/8087 (DOS 2, Microsoft F77/3.10)
+Z80 124.0 sec 4 MHz Z80 with Microsoft Fortran, CP/M
+IBM 268.9 sec 4.77 MHz 8088 PC ($NODEBUG) (DOS 1, Microsoft F77/1.0)
+Intel 390.0 sec 8086 alone (286WD Micro Development System,Intel FORTRAN)
+
+Table compiled by Richard Gillmann (Gillmann@ISIB).
+*/
+
+import core.stdc.stdio;
+import core.stdc.time;
+import core.stdc.math;
+
+double t, t1, t2;
+double[5] e1;
+int j, k, l;
+
+int main()
+{
+ clock_t start, stop;
+ double x1, x2, x3, x4, x, y, z;
+ int i, isave, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12;
+
+ start = clock();
+
+/* I=10 CORRESPONDS TO ONE MILLION WHETSTONE INSTRUCTIONS */
+
+ i = 10;
+ t1 = 0.50025000;
+ t = 0.499975000;
+ t2 = 2.0000;
+ isave = i;
+ n1 = 0;
+ n2 = 12 * i;
+ n3 = 14 * i;
+ n4 = 348 * i;
+ n5 = 0;
+ n6 = 210 * i;
+ n7 = 32 * i;
+ n8 = 899 * i;
+ n9 = 516 * i;
+ n10 = 0;
+ n11 = 93 * i;
+ n12 = 0;
+ x1 = 1.0;
+ x2 = -1.0;
+ x3 = -1.0;
+ x4 = -1.0;
+ for (i = 1; i <= n1; i++)
+ {
+ x1 = (x1+x2+x3-x4)*t;
+ x2 = (x1+x2-x3+x4)*t;
+ x3 = (x1-x2+x3+x4)*t;
+ x4 = (-x1+x2+x3+x4)*t;
+ }
+ auto s = pout(n1,n1,n1,x1,x2,x3,x4);
+ assert(s[] == " 0 0 0 1.0000e+00 -1.0000e+00 -1.0000e+00 -1.0000e+00");
+
+ e1[1] = 1.0;
+ e1[2] = -1.0;
+ e1[3] = -1.0;
+ e1[4] = -1.0;
+
+ for (i = 1; i <= n2; i++)
+ {
+ e1[1] = (e1[1]+e1[2]+e1[3]-e1[4])*t;
+ e1[2] = (e1[1]+e1[2]-e1[3]+e1[4])*t;
+ e1[3] = (e1[1]-e1[2]+e1[3]+e1[4])*t;
+ e1[4] = (-e1[1]+e1[2]+e1[3]+e1[4])*t;
+ }
+ pout(n2,n3,n2,e1[1],e1[2],e1[3],e1[4]);
+ assert(s == " 120 140 120 -6.8342e-02 -4.6264e-01 -7.2972e-01 -1.1240e+00");
+
+ for (i = 1; i <= n3; i++)
+ {
+ pa(e1);
+ }
+ pout(n3,n2,n2,e1[1],e1[2],e1[3],e1[4]);
+ assert(s == " 140 120 120 -5.5336e-02 -4.4744e-01 -7.1097e-01 -1.1031e+00");
+
+ j = 1;
+ for (i = 1; i <= n4; i++)
+ {
+ j = (j-1) ? 3 : 2;
+ j = (j-2 < 0) ? 0 : 1;
+ j = (j-1 < 0) ? 1 : 0;
+ }
+ pout(n4, j, j, x1, x2, x3, x4);
+ assert(s == " 3480 0 0 1.0000e+00 -1.0000e+00 -1.0000e+00 -1.0000e+00");
+
+ j = 1;
+ k = 2;
+ l = 3;
+ for (i = 1; i <= n6; i++)
+ {
+ j = j*(k-j)*(l-k);
+ k = l*k-(l-j)*k;
+ l = (l-k)*(k+j);
+ e1[l-1] = j+k+l;
+ e1[k-1] = j*k*l;
+ }
+ pout(n6,j,k,e1[1],e1[2],e1[3],e1[4]);
+ assert(s == " 2100 1 2 6.0000e+00 6.0000e+00 -7.1097e-01 -1.1031e+00");
+
+ x = 0.5;
+ y = 0.5;
+ for (i = 1; i <= n7; i++)
+ {
+ x = t * atan(t2* sin(x)* cos(x) /
+ ( cos(x+y)+ cos(x-y)-1.0 ));
+ y = t * atan(t2* sin(y)* cos(y) /
+ ( cos(x+y)+ cos(x-y)-1.0 ));
+ }
+ pout(n7, j, k, x, x, y, y);
+ assert(s == " 320 1 2 4.9041e-01 4.9041e-01 4.9039e-01 4.9039e-01");
+
+ x = 1.0;
+ y = 1.0;
+ z = 1.0;
+
+ for (i = 1; i <= n8; i++)
+ {
+ z = p3(x, y);
+ }
+ pout(n8, j, k, x, y, z, z);
+ assert(s == " 8990 1 2 1.0000e+00 1.0000e+00 9.9994e-01 9.9994e-01");
+
+ j = 1;
+ k = 2;
+ l = 3;
+ e1[1] = 1.0;
+ e1[2] = 2.0;
+ e1[3] = 3.0;
+
+ for (i = 1; i <= n9; i++)
+ {
+ p0();
+ }
+ pout(n9, j, k, e1[1], e1[2], e1[3], e1[4]);
+ assert(s == " 5160 1 2 3.0000e+00 2.0000e+00 3.0000e+00 -1.1031e+00");
+
+ j = 2;
+ k = 3;
+
+ for (i = 1; i <= n10; i++)
+ {
+ j = j + k;
+ k = j + k;
+ j = j - k;
+ k = k - j - j;
+ }
+ pout(n10, j, k, x1, x2, x3, x4);
+ assert(s == " 0 2 3 1.0000e+00 -1.0000e+00 -1.0000e+00 -1.0000e+00");
+
+ x = 0.75;
+
+ for (i = 1; i <= n11; i++)
+ {
+ x = sqrt( exp( log(x) / t1));
+ }
+
+ pout(n11,j,k,x,x,x,x);
+ assert(s == " 930 2 3 8.3467e-01 8.3467e-01 8.3467e-01 8.3467e-01");
+
+ stop = clock();
+
+ version (none)
+ printf("Elapsed time = %d.%02d seconds\n",
+ cast(int)(stop - start)/CLOCKS_PER_SEC,
+ cast(int)(stop - start)%CLOCKS_PER_SEC);
+ return 0;
+}
+
+void pa(double[] e)
+{
+ for (j = 0; j < 6; j++)
+ {
+ e[1] = (e[1] + e[2] + e[3] - e[4]) * t;
+ e[2] = (e[1] + e[2] - e[3] + e[4]) * t;
+ e[3] = (e[1] - e[2] + e[3] + e[4]) * t;
+ e[4] = (-e[1] + e[2] + e[3] + e[4]) / t2;
+ }
+}
+
+void p0()
+{
+ e1[j] = e1[k];
+ e1[k] = e1[l];
+ e1[l] = e1[j];
+}
+
+double p3(double x, double y)
+{
+ x = t * (x + y);
+ y = t * (x + y);
+ return (x + y) / t2;
+}
+
+char[] pout(int n, int j, int k, double x1, double x2, double x3, double x4)
+{
+ __gshared char[80] result;
+ const len = sprintf(result.ptr, " %7d %7d %7d %12.4e %12.4e %12.4e %12.4e",
+ n, j, k, x1, x2, x3, x4);
+ printf("%s\n", result.ptr);
+ return result[0 .. len];
+}
diff --git a/gcc/testsuite/gdc.test/runnable/xdtor.d b/gcc/testsuite/gdc.test/runnable/xdtor.d
index df3a4d1..d4b6e2b 100644
--- a/gcc/testsuite/gdc.test/runnable/xdtor.d
+++ b/gcc/testsuite/gdc.test/runnable/xdtor.d
@@ -79,8 +79,34 @@ void test2() @safe @nogc nothrow
assert(Counter.cnt == 1);
}
+struct Bar17257(E)
+{
+ ~this() @safe @nogc nothrow
+ {
+ assert(__traits(hasMember, E, "__xdtor"));
+ }
+}
+
+struct Foo17257A
+{
+ Bar17257!Foo17257A foo;
+ ~this() @safe @nogc nothrow {}
+}
+
+struct Foo17257B
+{
+ Bar17257!Foo17257B foo;
+}
+
+void test3() @safe @nogc nothrow
+{
+ Foo17257A foo17257A;
+ Foo17257B foo17257B;
+}
+
void main()
{
test1();
test2();
+ test3();
}
diff --git a/gcc/testsuite/gdc.test/runnable/xpostblit.d b/gcc/testsuite/gdc.test/runnable/xpostblit.d
index b364c4c..8f8a59d 100644
--- a/gcc/testsuite/gdc.test/runnable/xpostblit.d
+++ b/gcc/testsuite/gdc.test/runnable/xpostblit.d
@@ -70,8 +70,67 @@ void test2() @safe @nogc nothrow
assert(Counter.cnt == 1);
}
+/****************************************************************
+ This test is intended to verify the exception safety of field
+ postblits
+*/
+string trace = "";
+
+struct FieldThrow
+{
+ string name;
+ this(string n)
+ {
+ name = n;
+ }
+
+ bool throwExcept;
+ this(this)
+ {
+ if (throwExcept)
+ {
+ throw new Exception("");
+ }
+ }
+
+ ~this() { trace ~= name ~ ".dtor"; }
+}
+
+struct S
+{
+ auto f1 = FieldThrow("f1");
+ FieldThrow[2] f2f3= [FieldThrow("f2"), FieldThrow("f3")];
+ auto f4 = FieldThrow("f4");
+}
+
+void test3()
+{
+ trace = "";
+
+ S s1;
+
+ // Cause `s1.f4`'s postblit to throw
+ s1.f4.throwExcept = true;
+
+ try
+ {
+ // `s`'s postblit will be a combination of `f1`, `f2f3`, and `f4`'s
+ // postblit in that order. However, `f4`'s postblit will throw,
+ // causing `s1.f2f3` and `s1.f1`'s destructors to execute in that
+ // order
+ S s2 = s1;
+ }
+ catch(Exception ex){ }
+
+ // Confirm the field destructors were called and were called in the
+ // corrrect order
+ assert(trace == "f3.dtor" ~ "f2.dtor" ~ "f1.dtor");
+}
+/****************************************************************************/
+
void main()
{
test1();
test2();
+ test3();
}
diff --git a/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d
index bf19f57..20cc225 100644
--- a/gcc/testsuite/gdc.test/runnable/xtest46.d
+++ b/gcc/testsuite/gdc.test/runnable/xtest46.d
@@ -1,5 +1,5 @@
-// RUNNABLE_PHOBOS_TEST
-// PERMUTE_ARGS: -unittest -O -release -inline -fPIC -g
+// REQUIRED_ARGS: -preview=rvaluerefparam
+//
/* TEST_OUTPUT:
---
Boo!double
@@ -33,14 +33,14 @@ TFunction1: extern (C) void function()
---
*/
-import std.stdio;
+//import std.stdio;
import core.stdc.stdio;
/******************************************/
struct S
{
- int opStar() { return 7; }
+ int opUnary(string op)() if (op == "*") { return 7; }
}
void test1()
@@ -76,29 +76,6 @@ void bar2(D)(const(void)* arg)
D obj = *cast(D*) arg;
}
-/***************************************************/
-
-void test3()
-{
- version (unittest)
- {
- printf("unittest!\n");
- }
- else
- {
- printf("no unittest!\n");
- }
-
- version (assert)
- {
- printf("assert!\n");
- }
- else
- {
- printf("no assert!\n");
- }
-}
-
/***************************************************/
@@ -160,7 +137,7 @@ struct T6
S6 s;
int b = 7;
- S6* opDot()
+ S6* opDot() return
{
return &s;
}
@@ -217,7 +194,7 @@ void test7()
void foo8(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__)
{
assert(n1 < n2);
- printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, s.length, s.ptr);
+ printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr);
}
void test8()
@@ -230,7 +207,7 @@ void test8()
void foo9(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__)()
{
assert(n1 < n2);
- printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, s.length, s.ptr);
+ printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr);
}
void test9()
@@ -564,7 +541,7 @@ void test27()
/***************************************************/
-ref int foo28(ref int x) { return x; }
+ref int foo28(return ref int x) { return x; }
void test28()
{
@@ -687,13 +664,13 @@ void test34()
/***************************************************/
-ref int foo35(bool condition, ref int lhs, ref int rhs)
+ref int foo35(bool condition, return ref int lhs, return ref int rhs)
{
if ( condition ) return lhs;
return rhs;
}
-ref int bar35()(bool condition, ref int lhs, ref int rhs)
+ref int bar35()(bool condition, return ref int lhs, return ref int rhs)
{
if ( condition ) return lhs;
return rhs;
@@ -874,7 +851,7 @@ void test44()
}
/***************************************************/
-// 2006
+// https://issues.dlang.org/show_bug.cgi?id=2006
void test2006()
{
@@ -887,7 +864,7 @@ void test2006()
}
/***************************************************/
-// 8442
+// https://issues.dlang.org/show_bug.cgi?id=8442
void test8442()
{
@@ -988,7 +965,7 @@ void test48()
}
/***************************************************/
-// 6408
+// https://issues.dlang.org/show_bug.cgi?id=6408
static assert(!is(typeof(string[0..1].init)));
static assert(is(typeof(string[].init) == string[]));
@@ -1009,7 +986,7 @@ static assert(is(typeof(TT6408!(int, int)[0..$].init) == TT6408!(int, int)));
static assert(is(typeof(TT6408!(int, int)[$-1].init) == int));
/***************************************************/
-// 9409
+// https://issues.dlang.org/show_bug.cgi?id=9409
template TT9409(T...) { alias T TT9409; }
@@ -1028,7 +1005,7 @@ struct S49
this( string name )
{
- printf( "(ctor) &%.*s.x = %p\n", name.length, name.ptr, &x );
+ printf( "(ctor) &%.*s.x = %p\n", cast(int)name.length, name.ptr, &x );
p = cast(void*)&x;
}
@@ -1198,7 +1175,8 @@ pure immutable(T)[] fooPT(T)(immutable(T)[] x, immutable(T)[] y){
void test61()
{
- writeln(fooPT("p", "c"));
+ auto s = fooPT("p", "c");
+ printf("%.*s\n", cast(int)s.length, s.ptr);
}
/***************************************************/
@@ -1347,7 +1325,7 @@ void test67()
void test68()
{
- digestToString(cast(ubyte[16])x"c3fcd3d76192e4007dfb496cca67e13b");
+ digestToString(cast(ubyte[16])"\xc3\xfc\xd3\xd7\x61\x92\xe4\x00\x7d\xfb\x49\x6c\xca\x67\xe1\x3b");
}
void digestToString(const ubyte[16] digest)
@@ -1360,7 +1338,7 @@ void digestToString(const ubyte[16] digest)
void test69()
{
- digestToString69(cast(ubyte[16])x"c3fcd3d76192e4007dfb496cca67e13b");
+ digestToString69(cast(ubyte[16])"\xc3\xfc\xd3\xd7\x61\x92\xe4\x00\x7d\xfb\x49\x6c\xca\x67\xe1\x3b");
}
void digestToString69(ref const ubyte[16] digest)
@@ -1776,7 +1754,7 @@ void test86()
/***************************************************/
-// Bugzilla 3379
+// https://issues.dlang.org/show_bug.cgi?id=3379
T1[] find(T1, T2)(T1[] longer, T2[] shorter)
if (is(typeof(longer[0 .. 1] == shorter) : bool))
@@ -1832,7 +1810,7 @@ struct S88
{
void opDispatch(string s, T)(T i)
{
- printf("S.opDispatch('%.*s', %d)\n", s.length, s.ptr, i);
+ printf("S.opDispatch('%.*s', %d)\n", cast(int)s.length, s.ptr, i);
}
}
@@ -1840,7 +1818,7 @@ class C88
{
void opDispatch(string s)(int i)
{
- printf("C.opDispatch('%.*s', %d)\n", s.length, s.ptr, i);
+ printf("C.opDispatch('%.*s', %d)\n", cast(int)s.length, s.ptr, i);
}
}
@@ -1874,7 +1852,7 @@ void test89() {
int bar() { return x; }
}
X s;
- printf("%d\n", s.sizeof);
+ printf("%zd\n", s.sizeof);
assert(s.sizeof == 4);
}
@@ -2053,8 +2031,8 @@ void test96()
{
S96!([12, 3]) s1;
S96!([1, 23]) s2;
- writeln(s1.content);
- writeln(s2.content);
+ //writeln(s1.content);
+ //writeln(s2.content);
assert(!is(typeof(s1) == typeof(s2)));
}
@@ -2105,7 +2083,7 @@ void test99()
}
/***************************************************/
-// 5081
+// https://issues.dlang.org/show_bug.cgi?id=5081
void test5081()
{
@@ -2222,7 +2200,7 @@ void test104()
/***************************************************/
-ref int bump105(ref int x) { return ++x; }
+ref int bump105(return ref int x) { return ++x; }
void test105()
{
@@ -2246,8 +2224,8 @@ pure int genFactorials(int n) {
void test107()
{
int[6] a;
- writeln(a);
- writeln(a.init);
+ //writeln(a);
+ //writeln(a.init);
assert(a.init == [0,0,0,0,0,0]);
}
@@ -2289,7 +2267,7 @@ int test11247()
/***************************************************/
-// 3716
+// https://issues.dlang.org/show_bug.cgi?id=3716
void test111()
{
auto k1 = true ? [1,2] : []; // OK
@@ -2302,7 +2280,7 @@ void test111()
}
/***************************************************/
-// 658
+// https://issues.dlang.org/show_bug.cgi?id=658
void test658()
{
@@ -2333,7 +2311,7 @@ void test3069()
}
/***************************************************/
-// 4303
+// https://issues.dlang.org/show_bug.cgi?id=4303
template foo112() if (__traits(compiles,undefined))
{
@@ -2405,7 +2383,7 @@ template foo114(fun...)
pragma(msg, typeof(foo114!"a + b"([1,2,3])));
/***************************************************/
-// Bugzilla 3935
+// https://issues.dlang.org/show_bug.cgi?id=3935
struct Foo115 {
void opBinary(string op)(Foo other) {
@@ -2421,7 +2399,7 @@ void test115()
}
/***************************************************/
-// Bugzilla 2477
+// https://issues.dlang.org/show_bug.cgi?id=2477
void foo116(T,)(T t) { T x; }
@@ -2458,7 +2436,7 @@ void test1891()
}
/***************************************************/
-// Bugzilla 4291
+// https://issues.dlang.org/show_bug.cgi?id=4291
void test117() pure
{
@@ -2474,7 +2452,7 @@ template declareFunction()
}
/***************************************************/
-// Bugzilla 4177
+// https://issues.dlang.org/show_bug.cgi?id=4177
pure real log118(real x) {
if (__ctfe)
@@ -2510,7 +2488,7 @@ pure void test120()
}
/***************************************************/
-// 4866
+// https://issues.dlang.org/show_bug.cgi?id=4866
immutable int[3] statik = [ 1, 2, 3 ];
enum immutable(int)[] dynamic = statik;
@@ -2523,7 +2501,7 @@ static if (! is(typeof(dynamic) == immutable(int)[]))
pragma(msg, "!! ", typeof(dynamic));
/***************************************************/
-// 2943
+// https://issues.dlang.org/show_bug.cgi?id=2943
struct Foo2943
{
@@ -2545,7 +2523,7 @@ void test122()
}
/***************************************************/
-// 4641
+// https://issues.dlang.org/show_bug.cgi?id=4641
struct S123 {
int i;
@@ -2558,7 +2536,7 @@ void test123() {
}
/***************************************************/
-// 2451
+// https://issues.dlang.org/show_bug.cgi?id=2451
struct Foo124 {
int z = 3;
@@ -2585,21 +2563,6 @@ void test124() {
/***************************************************/
-void test3022()
-{
- static class Foo3022
- {
- new(size_t)
- {
- assert(0);
- }
- }
-
- scope x = new Foo3022;
-}
-
-/***************************************************/
-
void doNothing() {}
void bug5071(short d, ref short c) {
@@ -2681,7 +2644,7 @@ alias const MyInt4434[3] IceConstInt4434;
alias immutable string[] Bug4830;
/***************************************************/
-// 4254
+// https://issues.dlang.org/show_bug.cgi?id=4254
void bub(const inout int other) {}
@@ -2703,12 +2666,12 @@ void bug4915c()
}
/***************************************************/
-// 5164
+// https://issues.dlang.org/show_bug.cgi?id=5164
static if (is(int Q == int, Z...)) { }
/***************************************************/
-// 5195
+// https://issues.dlang.org/show_bug.cgi?id=5195
alias typeof(foo5195) food5195;
const int * foo5195 = null;
@@ -2727,7 +2690,7 @@ void test5332() { auto x = var5332; }
}
/***************************************************/
-// 5191
+// https://issues.dlang.org/show_bug.cgi?id=5191
struct Foo129
{
@@ -2750,15 +2713,15 @@ void test129()
assert(foo.value == 5);
foo.add(2);
- writeln(foo.value);
+ printf("%d\n", foo.value);
assert(foo.value == 7);
foo.add(3);
- writeln(foo.value);
+ printf("%d\n", foo.value);
assert(foo.value == 10);
foo.add(3);
- writeln(foo.value);
+ printf("%d\n", foo.value);
assert(foo.value == 13);
void delegate (int) nothrow dg = &foo.add!(int);
@@ -2767,7 +2730,7 @@ void test129()
}
/***************************************************/
-// 6169
+// https://issues.dlang.org/show_bug.cgi?id=6169
auto ctfefunc6169() { return "{}"; }
enum ctfefptr6169 = &ctfefunc6169;
@@ -2813,7 +2776,7 @@ void test6169() pure @safe
}
/***************************************************/
-// 10506
+// https://issues.dlang.org/show_bug.cgi?id=10506
void impureFunc10506() {}
string join10506(RoR)(RoR ror)
@@ -2847,7 +2810,7 @@ immutable struct S3598
}
/***************************************************/
-// 4211
+// https://issues.dlang.org/show_bug.cgi?id=4211
@safe struct X130
{
@@ -2885,7 +2848,7 @@ alias Return!( __traits(getOverloads, I4217, "square")[1] ) S4217;
static assert(! is(R4217 == S4217));
/***************************************************/
-// 5094
+// https://issues.dlang.org/show_bug.cgi?id=5094
void test131()
{
@@ -2913,7 +2876,7 @@ void test7545()
}
/***************************************************/
-// 5020
+// https://issues.dlang.org/show_bug.cgi?id=5020
void test132()
{
@@ -2928,7 +2891,7 @@ struct S132
}
/***************************************************/
-// 5343
+// https://issues.dlang.org/show_bug.cgi?id=5343
struct Tuple5343(Specs...)
{
@@ -2944,7 +2907,7 @@ alias Tuple5343!(A5343) TA5343;
alias S5343!(A5343) SA5343;
/***************************************************/
-// 5365
+// https://issues.dlang.org/show_bug.cgi?id=5365
interface IFactory
{
@@ -2987,7 +2950,7 @@ void test133()
}
/***************************************************/
-// 5365
+// https://issues.dlang.org/show_bug.cgi?id=5365
class B134
{
@@ -3020,7 +2983,7 @@ void test134()
}
/***************************************************/
-// 5025
+// https://issues.dlang.org/show_bug.cgi?id=5025
struct S135 {
void delegate() d;
@@ -3034,7 +2997,7 @@ void test135()
}
/***************************************************/
-// 5545
+// https://issues.dlang.org/show_bug.cgi?id=5545
bool enforce136(bool value, lazy const(char)[] msg = null) {
if(!value) {
@@ -3052,7 +3015,7 @@ struct Perm {
foreach(elem; input) {
enforce136(i < 3);
perm[i++] = elem;
- std.stdio.stderr.writeln(i); // Never gets incremented. Stays at 0.
+ printf("%d\n", i); // Never gets incremented. Stays at 0.
}
}
}
@@ -3060,12 +3023,12 @@ struct Perm {
void test136() {
byte[] stuff = [0, 1, 2];
auto perm2 = Perm(stuff);
- writeln(perm2.perm); // Prints [2, 0, 0]
+ //writeln(perm2.perm); // Prints [2, 0, 0]
assert(perm2.perm[] == [0, 1, 2]);
}
/***************************************************/
-// 4097
+// https://issues.dlang.org/show_bug.cgi?id=4097
void foo4097() { }
alias typeof(&foo4097) T4097;
@@ -3074,7 +3037,7 @@ static assert(is(T4097 X : X*) && is(X == function));
static assert(!is(X));
/***************************************************/
-// 5798
+// https://issues.dlang.org/show_bug.cgi?id=5798
void assign9(ref int lhs) pure {
lhs = 9;
@@ -3099,7 +3062,7 @@ int test137(){
/***************************************************/
-// 9366
+// https://issues.dlang.org/show_bug.cgi?id=9366
static assert(!is(typeof((void[]).init ~ cast(void)0)));
static assert(!is(typeof(cast(void)0 ~ (void[]).init)));
@@ -3146,7 +3109,8 @@ void test3822()
/***************************************************/
-// 5939, 5940
+// https://issues.dlang.org/show_bug.cgi?id=5939
+// https://issues.dlang.org/show_bug.cgi?id=5940
template map(fun...)
{
@@ -3176,7 +3140,7 @@ void test139()
/***************************************************/
-// 5966
+// https://issues.dlang.org/show_bug.cgi?id=5966
string[] foo5966(string[] a)
{
@@ -3187,7 +3151,7 @@ string[] foo5966(string[] a)
enum var5966 = foo5966([""]);
/***************************************************/
-// 5975
+// https://issues.dlang.org/show_bug.cgi?id=5975
int foo5975(wstring replace)
{
@@ -3199,7 +3163,7 @@ int foo5975(wstring replace)
enum X5975 = foo5975("X"w);
/***************************************************/
-// 5965
+// https://issues.dlang.org/show_bug.cgi?id=5965
template mapx(fun...) if (fun.length >= 1)
{
@@ -3232,7 +3196,7 @@ void bug5976()
}
/***************************************************/
-// 5771
+// https://issues.dlang.org/show_bug.cgi?id=5771
struct S141
{
@@ -3253,7 +3217,7 @@ class test5498_C : test5498_A {}
static assert(is(typeof([test5498_B.init, test5498_C.init]) == test5498_A[]));
/***************************************************/
-// 3688
+// https://issues.dlang.org/show_bug.cgi?id=3688
struct S142
{
@@ -3290,7 +3254,7 @@ void test142()
}
/***************************************************/
-// 6072
+// https://issues.dlang.org/show_bug.cgi?id=6072
static assert({
if (int x = 5) {}
@@ -3298,7 +3262,7 @@ static assert({
}());
/***************************************************/
-// 5959
+// https://issues.dlang.org/show_bug.cgi?id=5959
int n;
@@ -3318,7 +3282,7 @@ void test143()
}
/***************************************************/
-// 6119
+// https://issues.dlang.org/show_bug.cgi?id=6119
void startsWith(alias pred) () if (is(typeof(pred('c', 'd')) : bool))
{
@@ -3349,18 +3313,18 @@ void test146()
}
/***************************************************/
-// 5856
+// https://issues.dlang.org/show_bug.cgi?id=5856
struct X147
{
- void f() { writeln("X.f mutable"); }
- void f() const { writeln("X.f const"); }
+ void f() { printf("X.f mutable\n"); }
+ void f() const { printf("X.f const\n"); }
- void g()() { writeln("X.g mutable"); }
- void g()() const { writeln("X.g const"); }
+ void g()() { printf("X.g mutable\n"); }
+ void g()() const { printf("X.g const\n"); }
- void opOpAssign(string op)(int n) { writeln("X+= mutable"); }
- void opOpAssign(string op)(int n) const { writeln("X+= const"); }
+ void opOpAssign(string op)(int n) { printf("X+= mutable\n"); }
+ void opOpAssign(string op)(int n) const { printf("X+= const\n"); }
}
void test147()
@@ -3465,7 +3429,7 @@ void test13182()
}
/***************************************************/
-// 5897
+// https://issues.dlang.org/show_bug.cgi?id=5897
struct A148{ int n; }
struct B148{
@@ -3493,7 +3457,7 @@ void test148()
}
/***************************************************/
-// 4969
+// https://issues.dlang.org/show_bug.cgi?id=4969
class MyException : Exception
{
@@ -3519,7 +3483,7 @@ void cantthrow() nothrow
}
/***************************************************/
-// 2356
+// https://issues.dlang.org/show_bug.cgi?id=2356
void test2356()
{
@@ -3565,7 +3529,7 @@ void test2356()
}
/***************************************************/
-// 13652
+// https://issues.dlang.org/show_bug.cgi?id=13652
void test13652()
{
@@ -3633,7 +3597,7 @@ void test13652()
}
/***************************************************/
-// 11238
+// https://issues.dlang.org/show_bug.cgi?id=11238
void test11238()
{
@@ -3676,18 +3640,18 @@ class A2540
class B2540 : A2540
{
int b;
- override super.X foo() { return 1; }
+ override typeof(super).X foo() { return 1; }
- alias this athis;
- alias this.b thisb;
- alias super.a supera;
- alias super.foo superfoo;
- alias this.foo thisfoo;
+ alias typeof(this) athis;
+ alias typeof(this).b thisb;
+ alias typeof(super).a supera;
+ alias typeof(super).foo superfoo;
+ alias typeof(this).foo thisfoo;
}
struct X2540
{
- alias this athis;
+ alias typeof(this) athis;
}
void test2540()
@@ -3726,12 +3690,12 @@ B14348 test14348()
}
/***************************************************/
-// 7295
+// https://issues.dlang.org/show_bug.cgi?id=7295
struct S7295
{
int member;
- @property ref int refCountedPayload() { return member; }
+ @property ref int refCountedPayload() return { return member; }
alias refCountedPayload this;
}
@@ -3745,24 +3709,20 @@ void bar7295() pure
}
/***************************************************/
-// 5659
+// https://issues.dlang.org/show_bug.cgi?id=5659
void test149()
{
- import std.traits;
-
char a;
immutable(char) b;
static assert(is(typeof(true ? a : b) == const(char)));
static assert(is(typeof([a, b][0]) == const(char)));
-
- static assert(is(CommonType!(typeof(a), typeof(b)) == const(char)));
}
/***************************************************/
-// 1373
+// https://issues.dlang.org/show_bug.cgi?id=1373
void func1373a(){}
@@ -3815,7 +3775,7 @@ nothrow void test151()
@property int eoo() { return 1; }
@property auto ref hoo(int i) { return i; }
-// 3359
+// https://issues.dlang.org/show_bug.cgi?id=3359
int goo(int i) pure { return i; }
auto ioo(int i) pure { return i; }
@@ -3829,7 +3789,7 @@ class A152 {
auto eoo(int i) shared { return i; }
}
-// 4706
+// https://issues.dlang.org/show_bug.cgi?id=4706
struct Foo152(T) {
@property auto ref front() {
@@ -3846,7 +3806,7 @@ void test152() {
}
/***************************************************/
-// 6733
+// https://issues.dlang.org/show_bug.cgi?id=6733
void bug6733(int a, int b) pure nothrow { }
void test6733() {
@@ -3856,7 +3816,7 @@ void test6733() {
}
/***************************************************/
-// 3799
+// https://issues.dlang.org/show_bug.cgi?id=3799
void test153()
{
@@ -3868,7 +3828,7 @@ void test153()
}
/***************************************************/
-// 3632
+// https://issues.dlang.org/show_bug.cgi?id=3632
void test154() {
@@ -3905,7 +3865,7 @@ void test6545()
}
/***************************************************/
-// 3147
+// https://issues.dlang.org/show_bug.cgi?id=3147
void test155()
@@ -3924,7 +3884,7 @@ void test155()
}
/***************************************************/
-// 2486
+// https://issues.dlang.org/show_bug.cgi?id=2486
void test2486()
{
@@ -3932,7 +3892,7 @@ void test2486()
int[] arr = [1,2,3];
foo(arr); //OK
- static assert(!__traits(compiles, foo(arr[1..2]))); // should be NG
+ static assert(__traits(compiles, foo(arr[1..2])));
struct S
{
@@ -3943,7 +3903,7 @@ void test2486()
s[];
// opSlice should return rvalue
static assert(is(typeof(&S.opSlice) == int[] function() pure nothrow @nogc @safe));
- static assert(!__traits(compiles, foo(s[]))); // should be NG
+ static assert(__traits(compiles, foo(s[])));
}
/***************************************************/
@@ -3963,7 +3923,7 @@ void test15080()
}
/***************************************************/
-// 2521
+// https://issues.dlang.org/show_bug.cgi?id=2521
immutable int val = 23;
const int val2 = 23;
@@ -4011,7 +3971,7 @@ void test5554()
}
/***************************************************/
-// 5962
+// https://issues.dlang.org/show_bug.cgi?id=5962
struct S156
{
@@ -4044,7 +4004,7 @@ void test6708(const ref int y)
}
/***************************************************/
-// 4258
+// https://issues.dlang.org/show_bug.cgi?id=4258
struct Vec4258 {
Vec4258 opOpAssign(string Op)(auto ref Vec4258 other) if (Op == "+") {
@@ -4097,7 +4057,7 @@ static assert(!is(typeof(Bar4258.init += 1)));
static assert(!is(typeof(1 + Baz4258.init)));
/***************************************************/
-// 4539
+// https://issues.dlang.org/show_bug.cgi?id=4539
void test4539()
{
@@ -4118,20 +4078,20 @@ void test4539()
assert(s[4] == 0x61);
}
- static assert(!__traits(compiles, foo1("hello")));
+ static assert(__traits(compiles, foo1("hello")));
static assert(!__traits(compiles, foo2("hello")));
static assert(!__traits(compiles, foo3("hello")));
// same as test68, 69, 70
foo4("hello");
- foo5(cast(ubyte[5])x"c3fcd3d761");
+ foo5(cast(ubyte[5])"\xc3\xfc\xd3\xd7\x61");
//import std.conv;
//static assert(!__traits(compiles, parse!int("10") == 10));
}
/***************************************************/
-// 1471
+// https://issues.dlang.org/show_bug.cgi?id=1471
void test1471()
{
@@ -4147,14 +4107,6 @@ static assert(!is(typeof(bug6389 = bug6389)));
/***************************************************/
-void test10927()
-{
- static assert( (1+2i) ^^ 3 == -11 - 2i );
- auto a = (1+2i) ^^ 3;
-}
-
-/***************************************************/
-
void test4963()
{
struct Value {
@@ -4178,7 +4130,7 @@ pure int test4031()
}
/***************************************************/
-// 5437
+// https://issues.dlang.org/show_bug.cgi?id=5437
template EnumMembers5437(E)
{
@@ -4203,7 +4155,7 @@ void test5437()
}
/***************************************************/
-// 1962
+// https://issues.dlang.org/show_bug.cgi?id=1962
void test1962()
@@ -4213,12 +4165,12 @@ void test1962()
}
/***************************************************/
-// 6228
-
+// https://issues.dlang.org/show_bug.cgi?id=6228
void test6228()
{
- const(int)* ptr;
+ int val;
+ const(int)* ptr = &val;
const(int) temp;
auto x = (*ptr) ^^ temp;
}
@@ -4308,7 +4260,7 @@ void test6264()
}
/***************************************************/
-// 5046
+// https://issues.dlang.org/show_bug.cgi?id=5046
void test5046()
{
@@ -4328,7 +4280,7 @@ S5046!(p, T) makeS5046(alias p, T)()
}
/***************************************************/
-// 6335
+// https://issues.dlang.org/show_bug.cgi?id=6335
struct S6335
{
@@ -4428,7 +4380,7 @@ void test6293() {
}
/***************************************************/
-// 3733
+// https://issues.dlang.org/show_bug.cgi?id=3733
class C3733
{
@@ -4444,7 +4396,7 @@ void test3733()
}
/***************************************************/
-// 4392
+// https://issues.dlang.org/show_bug.cgi?id=4392
class C4392
{
@@ -4460,7 +4412,7 @@ void test4392()
}
/***************************************************/
-// 6220
+// https://issues.dlang.org/show_bug.cgi?id=6220
void test6220() {
struct Foobar { real x; real y; real z;}
@@ -4473,7 +4425,7 @@ void test6220() {
}
/***************************************************/
-// 5799
+// https://issues.dlang.org/show_bug.cgi?id=5799
void test5799()
{
@@ -4483,7 +4435,7 @@ void test5799()
}
/***************************************************/
-// 6529
+// https://issues.dlang.org/show_bug.cgi?id=6529
enum Foo6529 : char { A='a' }
ref const(Foo6529) func6529(const(Foo6529)[] arr){ return arr[0]; }
@@ -4536,7 +4488,7 @@ void test157()
}
/***************************************************/
-// 6473
+// https://issues.dlang.org/show_bug.cgi?id=6473
struct Eins6473
{
@@ -4634,7 +4586,7 @@ void test6578()
}
/***************************************************/
-// 6630
+// https://issues.dlang.org/show_bug.cgi?id=6630
void test6630()
{
@@ -4674,7 +4626,7 @@ void test199()
}
/***************************************************/
-// 6690
+// https://issues.dlang.org/show_bug.cgi?id=6690
T useLazy6690(T)(lazy T val)
{
@@ -4694,7 +4646,7 @@ template Hoge6691()
immutable static int[int] dict;
immutable static int value;
- static this()
+ shared static this()
{
dict = [1:1, 2:2];
value = 10;
@@ -4716,13 +4668,14 @@ void test10626()
double[2] a = v[] * ++z;
double[2] b = v[] * --z;
double[2] c = v[] * y.u;
- double[2] d = v[] * (x[] = 3, x[0]);
+ x[] = 3;
+ double[2] d = v[] * x[0];
double[2] e = v[] * (v[] ~ z)[0];
}
/***************************************************/
-// 2953
+// https://issues.dlang.org/show_bug.cgi?id=2953
template Tuple2953(T...)
{
@@ -4743,7 +4696,7 @@ void test2953()
}
/***************************************************/
-// 2997
+// https://issues.dlang.org/show_bug.cgi?id=2997
abstract class B2997 { void foo(); }
interface I2997 { void bar(); }
@@ -4758,7 +4711,7 @@ void test2997()
}
/***************************************************/
-// 6596
+// https://issues.dlang.org/show_bug.cgi?id=6596
extern (C) int function() pfunc6596;
extern (C) int cfunc6596(){ return 0; }
@@ -4767,7 +4720,7 @@ static assert(typeof(cfunc6596).stringof == "extern (C) int()");
/***************************************************/
-// 4423
+// https://issues.dlang.org/show_bug.cgi?id=4423
struct S4423
{
@@ -4813,7 +4766,7 @@ void test4423()
}
/***************************************************/
-// 4647
+// https://issues.dlang.org/show_bug.cgi?id=4647
interface Timer
{
@@ -4903,7 +4856,7 @@ void test1064()
}
/***************************************************/
-// 5696
+// https://issues.dlang.org/show_bug.cgi?id=5696
template Seq5696(T...){ alias T Seq5696; }
template Pred5696(T) { alias T Pred5696; } // TOKtemplate
@@ -4931,7 +4884,7 @@ void test5696()
}
/***************************************************/
-// 5933
+// https://issues.dlang.org/show_bug.cgi?id=5933
int dummyfunc5933();
alias typeof(dummyfunc5933) FuncType5933;
@@ -4962,7 +4915,7 @@ class C5933d { auto x() { return 0; } }
static assert(is(typeof(C5933d.x) == FuncType5933));
/***************************************************/
-// 6084
+// https://issues.dlang.org/show_bug.cgi?id=6084
template TypeTuple6084(T...){ alias T TypeTuple6084; }
void test6084()
@@ -4973,7 +4926,7 @@ void test6084()
}
/***************************************************/
-// 6763
+// https://issues.dlang.org/show_bug.cgi?id=6763
template TypeTuple6763(TList...)
{
@@ -4994,20 +4947,20 @@ void test6763()
f6763(0); //With D2: Error: function main.f ((ref const const(int) _param_0)) is not callable using argument types (int)
c6763(0);
- r6763(n); static assert(!__traits(compiles, r6763(0)));
+ r6763(n); static assert(__traits(compiles, r6763(0)));
i6763(0);
o6763(n); static assert(!__traits(compiles, o6763(0)));
- // 6755
+ // https://issues.dlang.org/show_bug.cgi?id=6755
static assert(typeof(f6763).stringof == "void(int _param_0)");
static assert(typeof(c6763).stringof == "void(const(int) _param_0)");
static assert(typeof(r6763).stringof == "void(ref int _param_0)");
- static assert(typeof(i6763).stringof == "void(const(int) _param_0)");
+ static assert(typeof(i6763).stringof == "void(in int _param_0)");
static assert(typeof(o6763).stringof == "void(out int _param_0)");
}
/***************************************************/
-// 6695
+// https://issues.dlang.org/show_bug.cgi?id=6695
struct X6695
{
@@ -5044,7 +4997,7 @@ struct X6695
}
/***************************************************/
-// 6087
+// https://issues.dlang.org/show_bug.cgi?id=6087
template True6087(T)
{
@@ -5061,7 +5014,7 @@ struct Bar6087
}
/***************************************************/
-// 6848
+// https://issues.dlang.org/show_bug.cgi?id=6848
class Foo6848 {}
@@ -5094,7 +5047,7 @@ else
static assert(!__traits(compiles, { cent x; }));
/***************************************************/
-// 6847
+// https://issues.dlang.org/show_bug.cgi?id=6847
template True6847(T)
{
@@ -5144,7 +5097,7 @@ void test6488()
}
/***************************************************/
-// 6565
+// https://issues.dlang.org/show_bug.cgi?id=6565
void foo6565(out int[2][2] m) {}
@@ -5156,7 +5109,7 @@ void test6565()
}
/***************************************************/
-// 6836
+// https://issues.dlang.org/show_bug.cgi?id=6836
template map6836(fun...) if (fun.length >= 1)
{
@@ -5194,7 +5147,7 @@ void test5448()
}
/***************************************************/
-// 6837
+// https://issues.dlang.org/show_bug.cgi?id=6837
struct Ref6837a(T)
{
@@ -5232,7 +5185,7 @@ void test6837()
}
/***************************************************/
-// 6927
+// https://issues.dlang.org/show_bug.cgi?id=6927
@property int[] foo6927()
{
@@ -5286,7 +5239,7 @@ struct Interval6753{ int a,b; }
}
/***************************************************/
-// 6859
+// https://issues.dlang.org/show_bug.cgi?id=6859
class Parent6859
{
@@ -5299,7 +5252,7 @@ public:
{
assert(isHage);
}
- body { }
+ do { }
}
class Child6859 : Parent6859
@@ -5322,7 +5275,7 @@ void test6859()
}
/***************************************************/
-// 6910
+// https://issues.dlang.org/show_bug.cgi?id=6910
template Test6910(alias i, B)
{
@@ -5371,7 +5324,7 @@ void fun12503()
b = null;
return;
}
- catch
+ catch(Throwable)
{
}
}
@@ -5387,7 +5340,7 @@ void test12503()
}
/***************************************************/
-// 6902
+// https://issues.dlang.org/show_bug.cgi?id=6902
void test6902()
{
@@ -5407,7 +5360,7 @@ void test6902()
}
/***************************************************/
-// 6330
+// https://issues.dlang.org/show_bug.cgi?id=6330
struct S6330
{
@@ -5444,7 +5397,7 @@ void test8269()
}
/***************************************************/
-// 5311
+// https://issues.dlang.org/show_bug.cgi?id=5311
class C5311
{
@@ -5487,7 +5440,7 @@ static void breaksPure5311b(S5311 x) pure
}
/***************************************************/
-// 6868
+// https://issues.dlang.org/show_bug.cgi?id=6868
@property bool empty6868(T)(in T[] a) @safe pure nothrow
{
@@ -5504,7 +5457,7 @@ void test6868()
}
/***************************************************/
-// 2856
+// https://issues.dlang.org/show_bug.cgi?id=2856
struct foo2856 { static void opIndex(int i) { printf("foo\n"); } }
struct bar2856(T) { static void opIndex(int i) { printf("bar\n"); } }
@@ -5539,7 +5492,7 @@ void test13947()
}
/***************************************************/
-// 3091
+// https://issues.dlang.org/show_bug.cgi?id=3091
void test3091(inout int = 0)
{
@@ -5563,7 +5516,7 @@ void test3091(inout int = 0)
}
/***************************************************/
-// 6837
+// https://issues.dlang.org/show_bug.cgi?id=6837
template Id6837(T)
{
@@ -5573,7 +5526,7 @@ static assert(is(Id6837!(shared const int) == shared const int));
static assert(is(Id6837!(shared inout int) == shared inout int));
/***************************************************/
-// 6056 fixup
+// https://issues.dlang.org/show_bug.cgi?id=6056 fixup
template ParameterTypeTuple6056(func)
{
@@ -5599,7 +5552,7 @@ void test6056()
}
/***************************************************/
-// 6356
+// https://issues.dlang.org/show_bug.cgi?id=6356
int f6356()(int a)
{
@@ -5619,13 +5572,13 @@ void test6356()
}
/***************************************************/
-// 7108
+// https://issues.dlang.org/show_bug.cgi?id=7108
static assert(!__traits(hasMember, int, "x"));
static assert( __traits(hasMember, int, "init"));
/***************************************************/
-// 7073
+// https://issues.dlang.org/show_bug.cgi?id=7073
void test7073()
{
@@ -5636,7 +5589,7 @@ void test7073()
}
/***************************************************/
-// 7104
+// https://issues.dlang.org/show_bug.cgi?id=7104
void test7104()
{
@@ -5645,7 +5598,7 @@ void test7104()
}
/***************************************************/
-// 7150
+// https://issues.dlang.org/show_bug.cgi?id=7150
struct A7150
{
@@ -5669,7 +5622,7 @@ void test7150()
}
/***************************************************/
-// 7159
+// https://issues.dlang.org/show_bug.cgi?id=7159
alias void delegate() Void7159;
@@ -5683,7 +5636,7 @@ class HomeController7159 {
}
/***************************************************/
-// 7160
+// https://issues.dlang.org/show_bug.cgi?id=7160
class HomeController {
static if (false) {
@@ -5699,7 +5652,7 @@ void test7160()
{}
/***************************************************/
-// 7168
+// https://issues.dlang.org/show_bug.cgi?id=7168
void test7168()
{
@@ -5720,7 +5673,7 @@ void test7168()
}
/***************************************************/
-// 7170
+// https://issues.dlang.org/show_bug.cgi?id=7170
T to7170(T)(string x) { return 1; }
void test7170()
@@ -5730,7 +5683,7 @@ void test7170()
}
/***************************************************/
-// 7196
+// https://issues.dlang.org/show_bug.cgi?id=7196
auto foo7196(int x){return x;}
auto foo7196(double x){return x;}
@@ -5742,7 +5695,7 @@ void test7196()
}
/***************************************************/
-// 7285
+// https://issues.dlang.org/show_bug.cgi?id=7285
int[2] spam7285()
{
@@ -5759,7 +5712,7 @@ void test7285()
}
/***************************************************/
-// 14737
+// https://issues.dlang.org/show_bug.cgi?id=14737
void test14737()
{
@@ -5783,7 +5736,7 @@ void test14737()
}
/***************************************************/
-// 7321
+// https://issues.dlang.org/show_bug.cgi?id=7321
void test7321()
{
@@ -5810,13 +5763,13 @@ class B158 : A158
}
/***************************************************/
-// 9231
+// https://issues.dlang.org/show_bug.cgi?id=9231
class B9231 { void foo() inout pure {} }
class D9231 : B9231 { override void foo() inout {} }
/***************************************************/
-// 3282
+// https://issues.dlang.org/show_bug.cgi?id=3282
class Base3282
{
@@ -5848,7 +5801,7 @@ void test3282()
}
/***************************************************/
-// 7534
+// https://issues.dlang.org/show_bug.cgi?id=7534
class C7534
{
@@ -5877,7 +5830,8 @@ void test7534()
}
/***************************************************/
-// 7534 + return type covariance
+// https://issues.dlang.org/show_bug.cgi?id=7534
+// return type covariance
class X7534 {}
class Y7534 : X7534
@@ -5913,7 +5867,7 @@ void test7534cov()
}
/***************************************************/
-// 7562
+// https://issues.dlang.org/show_bug.cgi?id=7562
static struct MyInt
{
@@ -5946,7 +5900,7 @@ void test13427(void* buffer = alloca(100))
}
/***************************************************/
-// 7583
+// https://issues.dlang.org/show_bug.cgi?id=7583
template Tup7583(E...) { alias E Tup7583; }
@@ -5966,7 +5920,7 @@ int bug7583() {
static assert (bug7583());
/***************************************************/
-// 7618
+// https://issues.dlang.org/show_bug.cgi?id=7618
void test7618(const int x = 1)
{
@@ -5984,7 +5938,7 @@ void test7618(const int x = 1)
}
/***************************************************/
-// 7621
+// https://issues.dlang.org/show_bug.cgi?id=7621
void test7621()
{
@@ -5996,7 +5950,7 @@ void test7621()
}
/***************************************************/
-// 7682
+// https://issues.dlang.org/show_bug.cgi?id=7682
template ConstOf7682(T)
{
@@ -6017,7 +5971,7 @@ void test7682()
}
/***************************************************/
-// 7735
+// https://issues.dlang.org/show_bug.cgi?id=7735
void a7735(void[][] data...)
{
@@ -6055,7 +6009,7 @@ struct A7823 {
void test7823(A7823 a = A7823.b) { }
/***************************************************/
-// 7871
+// https://issues.dlang.org/show_bug.cgi?id=7871
struct Tuple7871
{
@@ -6076,7 +6030,7 @@ void test7871()
}
/***************************************************/
-// 7906
+// https://issues.dlang.org/show_bug.cgi?id=7906
void test7906()
{
@@ -6084,7 +6038,7 @@ void test7906()
}
/***************************************************/
-// 7907
+// https://issues.dlang.org/show_bug.cgi?id=7907
template Id7907(E)
{
@@ -6101,7 +6055,7 @@ void test7907()
}
/***************************************************/
-// 1175
+// https://issues.dlang.org/show_bug.cgi?id=1175
class A1175
{
@@ -6116,28 +6070,7 @@ class B1175 : A1175
}
/***************************************************/
-// 7983
-
-class A7983 {
- void f() {
- g7983(this);
- }
- unittest {
- }
-}
-
-void g7983(T)(T a)
-{
- foreach (name; __traits(allMembers, T)) {
- pragma(msg, name);
- static if (__traits(compiles, &__traits(getMember, a, name)))
- {
- }
- }
-}
-
-/***************************************************/
-// 8004
+// https://issues.dlang.org/show_bug.cgi?id=8004
void test8004()
{
@@ -6146,7 +6079,7 @@ void test8004()
}
/***************************************************/
-// 8064
+// https://issues.dlang.org/show_bug.cgi?id=8064
void test8064()
{
@@ -6159,7 +6092,7 @@ void test8064()
}
/***************************************************/
-// 8220
+// https://issues.dlang.org/show_bug.cgi?id=8220
void foo8220(int){}
static assert(!__traits(compiles, foo8220(typeof(0)))); // fail
@@ -6200,7 +6133,7 @@ void test159()
}
/***************************************************/
-// 8283
+// https://issues.dlang.org/show_bug.cgi?id=8283
struct Foo8283 {
this(long) { }
@@ -6222,7 +6155,7 @@ void test8283() {
/***************************************************/
-// 8395
+// https://issues.dlang.org/show_bug.cgi?id=8395
struct S8395
{
@@ -6238,7 +6171,7 @@ void test8395()
}
/***************************************************/
-// 5749
+// https://issues.dlang.org/show_bug.cgi?id=5749
void test5749()
{
@@ -6286,7 +6219,7 @@ void test5749()
}
/***************************************************/
-// 8396
+// https://issues.dlang.org/show_bug.cgi?id=8396
void test8396()
{
@@ -6380,7 +6313,7 @@ void test160()
}
/***************************************************/
-// 8437
+// https://issues.dlang.org/show_bug.cgi?id=8437
class Cgi8437
{
@@ -6394,7 +6327,7 @@ class Cgi8437
}
/***************************************************/
-// 8665
+// https://issues.dlang.org/show_bug.cgi?id=8665
auto foo8665a(bool val)
{
@@ -6441,7 +6374,7 @@ void test8108()
}
/***************************************************/
-// 8360
+// https://issues.dlang.org/show_bug.cgi?id=8360
struct Foo8360
{
@@ -6482,7 +6415,7 @@ void test8360()
}
/***************************************************/
-// 8361
+// https://issues.dlang.org/show_bug.cgi?id=8361
struct Foo8361
{
@@ -6496,7 +6429,8 @@ void test8361()
}
/***************************************************/
-// 6141 + 8526
+// https://issues.dlang.org/show_bug.cgi?id=6141
+// https://issues.dlang.org/show_bug.cgi?id=8526
void test6141()
{
@@ -6569,7 +6503,7 @@ void test161()
}
/***************************************************/
-// 7175
+// https://issues.dlang.org/show_bug.cgi?id=7175
void test7175()
{
@@ -6580,7 +6514,7 @@ void test7175()
}
/***************************************************/
-// 8819
+// https://issues.dlang.org/show_bug.cgi?id=8819
void test8819()
{
@@ -6603,7 +6537,7 @@ void test8819()
}
/***************************************************/
-// 8897
+// https://issues.dlang.org/show_bug.cgi?id=8897
class C8897
{
@@ -6614,7 +6548,7 @@ class C8897
template M8897 ( E ) { }
/***************************************************/
-// 8917
+// https://issues.dlang.org/show_bug.cgi?id=8917
void test8917()
{
@@ -6624,7 +6558,7 @@ void test8917()
}
/***************************************************/
-// 8945
+// https://issues.dlang.org/show_bug.cgi?id=8945
struct S8945 // or `class`, or `union`
{
@@ -6746,7 +6680,7 @@ struct X164()
/***************************************************/
-// 9428
+// https://issues.dlang.org/show_bug.cgi?id=9428
void test9428()
{
@@ -6783,7 +6717,7 @@ void test9428()
}
/***************************************************/
-// 9477
+// https://issues.dlang.org/show_bug.cgi?id=9477
template Tuple9477(T...) { alias T Tuple9477; }
template Select9477(bool b, T, U) { static if (b) alias T Select9477; else alias U Select9477; }
@@ -6808,7 +6742,7 @@ void test9477()
foreach (b1; Tuple9477!(false, true))
foreach (b2; Tuple9477!(false, true))
{
- version (D_PIC) {} else // Work around http://d.puremagic.com/issues/show_bug.cgi?id=9754
+ version (D_PIC) {} else version (D_PIE) {} else // Work around http://d.puremagic.com/issues/show_bug.cgi?id=9754
{
assert( isEq (cast(Select9477!(b1, string, char[0]))"" , cast(Select9477!(b2, string, char[0]))"" ));
assert(!isNeq(cast(Select9477!(b1, string, char[0]))"" , cast(Select9477!(b2, string, char[0]))"" ));
@@ -6853,7 +6787,7 @@ void test9477()
}
/***************************************************/
-// 9504
+// https://issues.dlang.org/show_bug.cgi?id=9504
struct Bar9504
{
@@ -6884,7 +6818,7 @@ Bar9504 test9504()
}
/***************************************************/
-// 9538
+// https://issues.dlang.org/show_bug.cgi?id=9538
void test9538()
{
@@ -6893,7 +6827,7 @@ void test9538()
}
/***************************************************/
-// 9539
+// https://issues.dlang.org/show_bug.cgi?id=9539
void test9539()
{
@@ -6911,7 +6845,7 @@ void test9539()
}
/***************************************************/
-// 9700
+// https://issues.dlang.org/show_bug.cgi?id=9700
mixin template Proxy9700(alias a)
{
@@ -6931,7 +6865,7 @@ void test9700()
}
/***************************************************/
-// 9834
+// https://issues.dlang.org/show_bug.cgi?id=9834
struct Event9834
{
@@ -6955,7 +6889,7 @@ void test9834()
}
/***************************************************/
-// 9859
+// https://issues.dlang.org/show_bug.cgi?id=9859
void test9859(inout int[] arr)
{
@@ -6999,7 +6933,7 @@ void test9859(inout int[] arr)
}
/***************************************************/
-// 9912
+// https://issues.dlang.org/show_bug.cgi?id=9912
template TypeTuple9912(Stuff...)
{
@@ -7021,7 +6955,7 @@ struct S9912
}
/***************************************************/
-// 9883
+// https://issues.dlang.org/show_bug.cgi?id=9883
struct S9883
{
@@ -7041,7 +6975,7 @@ void test9883()
/***************************************************/
-// 10091
+// https://issues.dlang.org/show_bug.cgi?id=10091
struct S10091
{
@@ -7064,7 +6998,7 @@ label:
}
/***************************************************/
-// 9130
+// https://issues.dlang.org/show_bug.cgi?id=9130
class S9130 { void bar() { } }
@@ -7078,7 +7012,7 @@ struct Function
@property void meta(alias m)()
{
static Function md;
- printf("length = %d\n", md.ai.length);
+ printf("length = %zd\n", md.ai.length);
printf("ptr = %p\n", md.ai.ptr);
md.ai[0] = 0;
}
@@ -7090,14 +7024,14 @@ void test9130()
}
/***************************************************/
-// 10390
+// https://issues.dlang.org/show_bug.cgi?id=10390
class C10390 { this() { this.c = this; } C10390 c; }
const c10390 = new C10390();
pragma(msg, c10390);
/***************************************************/
-// 10542
+// https://issues.dlang.org/show_bug.cgi?id=10542
class B10542
{
@@ -7114,7 +7048,7 @@ void test10542() nothrow pure @safe
}
/***************************************************/
-// 10539
+// https://issues.dlang.org/show_bug.cgi?id=10539
void test10539()
{
@@ -7193,7 +7127,7 @@ void test11075()
}
/***************************************************/
-// 11181
+// https://issues.dlang.org/show_bug.cgi?id=11181
void test11181()
{
@@ -7207,7 +7141,7 @@ void test11181()
}
/***************************************************/
-// 11317
+// https://issues.dlang.org/show_bug.cgi?id=11317
void test11317()
{
@@ -7217,13 +7151,13 @@ void test11317()
}
void test(ref uint x) {}
- static assert(!__traits(compiles, test(fun())));
+ static assert(__traits(compiles, test(fun())));
assert(fun() == 0);
}
/***************************************************/
-// 11888
+// https://issues.dlang.org/show_bug.cgi?id=11888
void test11888()
{
@@ -7248,7 +7182,7 @@ void test11888()
}
/***************************************************/
-// 12036
+// https://issues.dlang.org/show_bug.cgi?id=12036
template T12036(alias a)
{
@@ -7268,7 +7202,7 @@ void test12036()
}
/***************************************************/
-// 12153
+// https://issues.dlang.org/show_bug.cgi?id=12153
void test12153()
{
@@ -7284,7 +7218,7 @@ void test12153()
}
/***************************************************/
-// 12498
+// https://issues.dlang.org/show_bug.cgi?id=12498
string a12498()
{
@@ -7301,7 +7235,7 @@ void test12498()
}
/***************************************************/
-// 12900
+// https://issues.dlang.org/show_bug.cgi?id=12900
struct A12900
{
@@ -7316,7 +7250,22 @@ void test12900()
}
/***************************************************/
-// 12937
+// https://issues.dlang.org/show_bug.cgi?id=12929
+
+struct Foo12929
+{
+ union { }
+ int var;
+}
+
+struct Bar12929
+{
+ struct { }
+ int var;
+}
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=12937
void test12937()
{
@@ -7325,7 +7274,7 @@ void test12937()
}
/***************************************************/
-// 13154
+// https://issues.dlang.org/show_bug.cgi?id=13154
void test13154()
{
@@ -7341,7 +7290,7 @@ void test13154()
}
/***************************************************/
-// 13437
+// https://issues.dlang.org/show_bug.cgi?id=13437
ubyte[4] foo13437() { return [1,2,3,4]; }
@@ -7353,7 +7302,7 @@ void test13437()
}
/***************************************************/
-// 13472
+// https://issues.dlang.org/show_bug.cgi?id=13472
class A13472
{
@@ -7369,7 +7318,7 @@ void test13472()
}
/***************************************************/
-// 13476
+// https://issues.dlang.org/show_bug.cgi?id=13476
template ParameterTypeTuple13476(func...)
{
@@ -7416,16 +7365,16 @@ void test13476()
}
/***************************************************/
-// 14038
+// https://issues.dlang.org/show_bug.cgi?id=14038
static immutable ubyte[string] wordsAA14038;
-static this()
+shared static this()
{
wordsAA14038["zero"] = 0;
}
/***************************************************/
-// 14192
+// https://issues.dlang.org/show_bug.cgi?id=14192
void test14192()
{
@@ -7434,7 +7383,7 @@ void test14192()
}
/***************************************************/
-// 13720
+// https://issues.dlang.org/show_bug.cgi?id=13720
struct FracSec13720
{
@@ -7461,7 +7410,7 @@ void test13720()
}
/***************************************************/
-// 13952
+// https://issues.dlang.org/show_bug.cgi?id=13952
struct Reg13952
{
@@ -7507,7 +7456,7 @@ void test13952()
}
/***************************************************/
-// 14165
+// https://issues.dlang.org/show_bug.cgi?id=14165
class Foo14165
{
@@ -7516,7 +7465,7 @@ class Foo14165
}
/***************************************************/
-// 13985
+// https://issues.dlang.org/show_bug.cgi?id=13985
interface I13985
{
@@ -7552,7 +7501,7 @@ void test13985()
}
/***************************************************/
-// 14211
+// https://issues.dlang.org/show_bug.cgi?id=14211
extern(C++) // all derived classes won't have invariants
class B14211
@@ -7574,7 +7523,7 @@ void test14211()
}
/***************************************************/
-// 14552
+// https://issues.dlang.org/show_bug.cgi?id=14552
template map14552(fun...)
{
@@ -7608,7 +7557,7 @@ class Outer14552
}
/***************************************************/
-// 14853
+// https://issues.dlang.org/show_bug.cgi?id=14853
struct Queue14853(T)
{
@@ -7641,7 +7590,7 @@ void test14853()
}
/********************************************************/
-// 15045
+// https://issues.dlang.org/show_bug.cgi?id=15045
void test15045()
{
@@ -7700,7 +7649,7 @@ void test15045()
}
/***************************************************/
-// 15116
+// https://issues.dlang.org/show_bug.cgi?id=15116
alias TypeTuple15116(T...) = T;
@@ -7722,7 +7671,7 @@ void test15116()
}
/***************************************************/
-// 15117
+// https://issues.dlang.org/show_bug.cgi?id=15117
template Mix15117()
{
@@ -7737,7 +7686,7 @@ struct S15117
}
/***************************************************/
-// 15126
+// https://issues.dlang.org/show_bug.cgi?id=15126
struct Json15126
{
@@ -7754,7 +7703,7 @@ template isCustomSerializable15126(T)
alias bug15126 = isCustomSerializable15126!Json15126;
/***************************************************/
-// 15141
+// https://issues.dlang.org/show_bug.cgi?id=15141
class A15141
{
@@ -7772,7 +7721,7 @@ void test15141()
}
/***************************************************/
-// 15366
+// https://issues.dlang.org/show_bug.cgi?id=15366
enum E15366 : bool { A, B };
@@ -7791,7 +7740,7 @@ struct S15366
}
/***************************************************/
-// 15369
+// https://issues.dlang.org/show_bug.cgi?id=15369
struct MsgTable15369
{
@@ -7856,7 +7805,7 @@ void test15638()
}
/***************************************************/
-// 15961
+// https://issues.dlang.org/show_bug.cgi?id=15961
struct SliceOverIndexed15961(T)
{
@@ -7877,13 +7826,26 @@ struct Grapheme15961
}
/***************************************************/
-// 16022
+// https://issues.dlang.org/show_bug.cgi?id=16022
bool test16022()
{
enum Type { Colon, Comma }
Type type;
- return type == Type.Colon, type == Type.Comma;
+ return type == Type.Comma;
+}
+
+bool test16022_structs()
+{
+ struct A
+ {
+ int i;
+ string s;
+ }
+
+ enum Type { Colon = A(0, "zero"), Comma = A(1, "one") }
+ Type type;
+ return type == Type.Comma;
}
/***************************************************/
@@ -7918,7 +7880,7 @@ void test16466()
real r;
}
real r;
- printf("S.alignof: %x, r.alignof: %x\n", S.alignof, r.alignof);
+ printf("S.alignof: %zx, r.alignof: %zx\n", S.alignof, r.alignof);
assert(S.alignof == r.alignof);
}
@@ -7991,13 +7953,30 @@ struct S17915(T)
T owner;
}
+void test18232()
+{
+ static struct Canary
+ {
+ int x = 0x900D_900D;
+ }
+ union U
+ {
+ Canary method()
+ {
+ Canary c;
+ return c;
+ }
+ }
+ U u;
+ assert(u.method() == Canary.init);
+}
+
/***************************************************/
int main()
{
test1();
test2();
- test3();
test4();
test5();
test6();
@@ -8214,7 +8193,7 @@ int main()
test6733();
test6813();
test6859();
- test3022();
+
test6910();
test6902();
test6330();
@@ -8312,6 +8291,7 @@ int main()
test16408();
test17349();
test17915();
+ test18232();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/xtest46_gc.d b/gcc/testsuite/gdc.test/runnable/xtest46_gc.d
new file mode 100644
index 0000000..14b82a0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/xtest46_gc.d
@@ -0,0 +1,37 @@
+/*
+REQUIRED_ARGS: -lowmem -Jrunnable -preview=rvaluerefparam
+EXTRA_FILES: xtest46.d
+TEST_OUTPUT:
+---
+Boo!double
+Boo!int
+true
+int
+!! immutable(int)[]
+int(int i, long j = 7L)
+long
+C10390(C10390(<recursion>))
+tuple(height)
+tuple(get, get)
+tuple(clear)
+tuple(draw, draw)
+runnable/xtest46_gc.d-mixin-$n$(185): Deprecation: `opDot` is deprecated. Use `alias this`
+runnable/xtest46_gc.d-mixin-$n$(187): Deprecation: `opDot` is deprecated. Use `alias this`
+runnable/xtest46_gc.d-mixin-$n$(188): Deprecation: `opDot` is deprecated. Use `alias this`
+runnable/xtest46_gc.d-mixin-$n$(190): Deprecation: `opDot` is deprecated. Use `alias this`
+runnable/xtest46_gc.d-mixin-$n$(217): Deprecation: `opDot` is deprecated. Use `alias this`
+runnable/xtest46_gc.d-mixin-$n$(219): Deprecation: `opDot` is deprecated. Use `alias this`
+runnable/xtest46_gc.d-mixin-$n$(220): Deprecation: `opDot` is deprecated. Use `alias this`
+runnable/xtest46_gc.d-mixin-$n$(222): Deprecation: `opDot` is deprecated. Use `alias this`
+const(int)
+string[]
+double[]
+double[]
+{}
+tuple("m")
+true
+TFunction1: extern (C) void function()
+---
+*/
+
+mixin(import("xtest46.d"));
diff --git a/gcc/testsuite/gdc.test/runnable/xtest47.d b/gcc/testsuite/gdc.test/runnable/xtest47.d
new file mode 100644
index 0000000..42cabaf9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/xtest47.d
@@ -0,0 +1,67 @@
+// PERMUTE_ARGS: -unittest
+/* TEST_OUTPUT:
+---
+f
+toString
+toHash
+opCmp
+opEquals
+Monitor
+factory
+---
+*/
+
+import core.stdc.stdio;
+
+/***************************************************/
+
+void test3()
+{
+ version (unittest)
+ {
+ printf("unittest!\n");
+ }
+ else
+ {
+ printf("no unittest!\n");
+ }
+
+ version (assert)
+ {
+ printf("assert!\n");
+ }
+ else
+ {
+ printf("no assert!\n");
+ }
+}
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=7983
+
+class A7983 {
+ void f() {
+ g7983(this);
+ }
+ unittest {
+ }
+}
+
+void g7983(T)(T a)
+{
+ foreach (name; __traits(allMembers, T)) {
+ pragma(msg, name);
+ static if (__traits(compiles, &__traits(getMember, a, name)))
+ {
+ }
+ }
+}
+
+/***************************************************/
+
+int main()
+{
+ test3();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/xtest55.d b/gcc/testsuite/gdc.test/runnable/xtest55.d
index 4b295d8..f976520 100644
--- a/gcc/testsuite/gdc.test/runnable/xtest55.d
+++ b/gcc/testsuite/gdc.test/runnable/xtest55.d
@@ -1,7 +1,6 @@
-// RUNNABLE_PHOBOS_TEST
// PERMUTE_ARGS:
-import core.memory, std.stdio;
+import core.memory, core.stdc.stdio;
Stuff* stuff1;
@@ -16,9 +15,9 @@ int main()
auto bar = new byte[1024 * 1024];
auto stuff2 = new Stuff;
stuff2.num = 2;
- writeln(stuff1, "\t", stuff2); // Same address.
+ printf("%p\t%p\n", stuff1, stuff2); // Same address.
assert(stuff1 != stuff2);
- writeln(stuff1.num, "\t", stuff2.num); // Both 2.
+ printf("%d\t%d\n", stuff1.num, stuff2.num); // Both 2.
assert(stuff1.num == 1);
return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/xtestenum.d b/gcc/testsuite/gdc.test/runnable/xtestenum.d
index fa812a1..ce77782 100644
--- a/gcc/testsuite/gdc.test/runnable/xtestenum.d
+++ b/gcc/testsuite/gdc.test/runnable/xtestenum.d
@@ -1,4 +1,11 @@
-// PERMUTE_ARGS:
+/*
+PERMUTE_ARGS:
+RUN_OUTPUT:
+---
+foo
+Success
+---
+*/
extern(C) int printf(const char*, ...);
@@ -45,7 +52,7 @@ enum E3 : string
void test3()
{
- printf("%.*s\n", E3.E3a.length, E3.E3a.ptr);
+ printf("%.*s\n", cast(int)E3.E3a.length, E3.E3a.ptr);
assert(E3.E3a == "foo");
assert(E3.E3b == "bar");
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/abi_tags.d b/gcc/testsuite/gdc.test/runnable_cxx/abi_tags.d
new file mode 100644
index 0000000..80eead2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/abi_tags.d
@@ -0,0 +1,139 @@
+/*
+ * Test C++ abi-tag name mangling.
+ * They are a C++11 feature required to bind `std::string`,
+ * introduced in G++ 5.1 / clang++ 3.9
+ * https://issues.dlang.org/show_bug.cgi?id=19949
+ *
+ * DISABLED: win32 win64
+ * REQUIRED_ARGS: -extern-std=c++11
+ * EXTRA_CPP_SOURCES: abi_tags.cpp
+ * CXXFLAGS: -std=c++11
+ */
+
+#line 100
+import core.attribute;
+
+alias Tuple(A...) = A;
+enum foo_bar = gnuAbiTag("foo", "bar");
+
+extern(C++)
+{
+ @gnuAbiTag("tag1") struct Tagged1 {}
+ @gnuAbiTag("tag2") struct Tagged2 {}
+ @gnuAbiTag("tag1") struct Tagged1Too {}
+
+ // Note: Outer tags do not propagate, unlike in C++
+ @gnuAbiTag("tag1", "tag2") struct Tagged1_2
+ {
+ @gnuAbiTag("tag1", "tag2", "tag3") struct Tagged3
+ {
+ // _ZN9Tagged1_2B4tag1B4tag27Tagged3B4tag37Tagged4B4tag4Ev
+ @gnuAbiTag("tag1", "tag2", "tag3", "tag4") int Tagged4 ();
+
+ int value;
+ }
+ }
+
+ extern __gshared Tagged1_2 inst1;
+ extern __gshared Tagged1_2.Tagged3 inst2;
+
+ Tagged1_2 func0(int a);
+ Tagged1_2 func1(Tagged1_2 a);
+ Tagged1_2 func2(Tagged1 a);
+ Tagged1_2 func3(Tagged2 a);
+ Tagged1_2 func4(Tagged2 a, Tagged1 b);
+ Tagged1_2.Tagged3 func5(Tagged2 a, Tagged1 b);
+ void func6(Tagged2 a, Tagged2 b, Tagged1 c, Tagged1_2 d);
+ T func7(T)(T a, int);
+ void func8 (Tagged1, Tagged1Too);
+
+ @foo_bar struct S
+ {
+ int i;
+ }
+
+ @foo_bar extern __gshared int a;
+
+ extern __gshared S b;
+
+ @foo_bar int f();
+
+ S gs(int);
+ S gss(S, int);
+
+ @foo_bar S fss(S, int);
+
+ T gt(T)(int);
+ T gtt(T)(T, int);
+
+ @foo_bar T ft(T)(int);
+
+ @foo_bar T ftt(T)(T, int);
+
+ @("abc") extern(C++, "N")
+ {
+ @gnuAbiTag("AAA", "foo")
+ template K(int i)
+ {
+ @gnuAbiTag("bar", "AAA", "foo")
+ struct K
+ {
+ int i;
+ this(int);
+ }
+ }
+ }
+
+ //K!i fk(int i)(int);
+ K!1 fk1(int);
+
+ extern __gshared K!10 k10;
+
+ @gnuAbiTag("ENN") enum E0 { a = 0xa, }
+ E0 fe();
+ E0 fei(int i)();
+
+ void initVars();
+}
+
+void main()
+{
+ inst1 = func0(42);
+ assert(inst2.value == 42);
+ inst2 = func5(Tagged2.init, Tagged1.init);
+ assert(inst2.value == 420);
+ func1(inst1);
+ func2(Tagged1.init);
+ func3(Tagged2.init);
+ func4(Tagged2.init, Tagged1.init);
+
+ func6(Tagged2.init, Tagged2.init, Tagged1.init, Tagged1_2.init);
+ func7(Tagged1_2.init, 42);
+ func8(Tagged1.init, Tagged1Too.init);
+
+ initVars();
+ assert(a == 10);
+ assert(b.i == 20);
+ assert(k10.i == 30);
+
+ assert(f() == 0xf);
+ assert(gs(1).i == 1+0xe0);
+ assert(gss(S(1), 1).i == 2+0xe0);
+ assert(fss(S(1), 1).i == 2+0xf);
+ assert(gt!S(1).i == 1+0xe0);
+ assert(gtt!S(S(1), 1).i == 2+0xe0);
+
+ // Bug: Template parameter tags get double mangled
+ version(none)
+ {
+ assert(ft!S(1).i == 1+0xf); // GCC inconsistent
+ assert(ftt!S(S(1), 1).i == 2+0xf); // GCC inconsistent
+ }
+ //assert(fk!0(1).i == 1+0xf);
+ assert(fk1(1).i == 2+0xf);
+ version(gcc6)
+ {
+ assert(fei!0() == E0.a); // GCC only
+ assert(fe() == E0.a); // GCC only
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/cpp11.d b/gcc/testsuite/gdc.test/runnable_cxx/cpp11.d
new file mode 100644
index 0000000..6951dec
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/cpp11.d
@@ -0,0 +1,70 @@
+// DISABLED: win32
+// REQUIRED_ARGS: -extern-std=c++11
+// EXTRA_CPP_SOURCES: cpp11.cpp
+// CXXFLAGS(osx linux freebsd openbsd netbsd dragonflybsd solaris): -std=c++11
+
+// Disabled on win32 because the compiler is too old
+
+/****************************************/
+alias nullptr_t = typeof(null);
+
+// Only run on OSX/Win64 because the compilers are too old
+// and nullptr_t gets substituted
+version (FreeBSD)
+ version = IgnoreNullptrTest;
+version (linux)
+ version = IgnoreNullptrTest;
+
+version (IgnoreNullptrTest) { void test17() {} }
+else
+{
+ extern (C++) void testnull(nullptr_t);
+ extern (C++) void testnullnull(nullptr_t, nullptr_t);
+
+ void test17()
+ {
+ testnull(null);
+ testnullnull(null, null);
+ }
+}
+
+/****************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19658
+
+enum i8_19658 : byte { a }
+enum u8_19658 : ubyte { a }
+enum i16_19658 : short { a }
+enum u16_19658 : ushort { a }
+enum i32_19658 : int { a }
+enum u32_19658 : uint { a }
+enum i64_19658 : long { a }
+enum u64_19658 : ulong { a }
+
+extern(C++) void test19658_i8(i8_19658);
+extern(C++) void test19658_u8(u8_19658);
+extern(C++) void test19658_i16(i16_19658);
+extern(C++) void test19658_u16(u16_19658);
+extern(C++) void test19658_i32(i32_19658);
+extern(C++) void test19658_u32(u32_19658);
+extern(C++) void test19658_i64(i64_19658);
+extern(C++) void test19658_u64(u64_19658);
+
+void test19658()
+{
+ test19658_i8(i8_19658.a);
+ test19658_u8(u8_19658.a);
+ test19658_i16(i16_19658.a);
+ test19658_u16(u16_19658.a);
+ test19658_i32(i32_19658.a);
+ test19658_u32(u32_19658.a);
+ test19658_i64(i64_19658.a);
+ test19658_u64(u64_19658.a);
+}
+
+/****************************************/
+
+void main()
+{
+ test17();
+ test19658();
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d b/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d
index 83e1cff..c677d6e 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d
+++ b/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d
@@ -1,4 +1,14 @@
// EXTRA_CPP_SOURCES: cpp_abi_tests.cpp
+// CXXFLAGS(linux freebsd osx netbsd dragonflybsd): -std=c++11
+
+// N.B MSVC doesn't have a C++11 switch, but it defaults to the latest fully-supported standard
+// N.B MSVC 2013 doesn't support char16_t/char32_t
+
+version(Posix)
+ enum __c_wchar_t : dchar;
+else version(Windows)
+ enum __c_wchar_t : wchar;
+alias wchar_t = __c_wchar_t;
extern(C++) {
@@ -7,11 +17,43 @@ struct S
float a = 1;
}
+struct S18784
+{
+ int i;
+ this(int);
+}
+
+extern(C++, std)
+{
+ struct test19248_ {int a = 42;}
+}
+extern(C++, `std`)
+{
+ struct test19248 {int a = 34;}
+}
+
+struct Sdtor
+{
+ extern __gshared int counter;
+ ~this();
+}
+void consume(Sdtor);
+void consume2(Sdtor value){}
+void doConsume2(ref Sdtor);
+
+struct SPack(Args...)
+{
+ int i;
+}
+alias SInt = SPack!int;
+
bool passthrough(bool value);
byte passthrough(byte value);
ubyte passthrough(ubyte value);
char passthrough(char value);
+wchar passthrough(wchar value);
dchar passthrough(dchar value);
+wchar_t passthrough(wchar_t value);
short passthrough(short value);
ushort passthrough(ushort value);
int passthrough(int value);
@@ -21,12 +63,17 @@ ulong passthrough(ulong value);
float passthrough(float value);
double passthrough(double value);
S passthrough(S value);
+test19248 passthrough(const(test19248) value);
+std.test19248_ passthrough(const(std.test19248_) value);
+SInt passthrough(SInt value);
bool passthrough_ptr(bool *value);
byte passthrough_ptr(byte *value);
ubyte passthrough_ptr(ubyte *value);
char passthrough_ptr(char *value);
+wchar passthrough_ptr(wchar *value);
dchar passthrough_ptr(dchar *value);
+wchar_t passthrough_ptr(wchar_t *value);
short passthrough_ptr(short *value);
ushort passthrough_ptr(ushort *value);
int passthrough_ptr(int *value);
@@ -36,12 +83,17 @@ ulong passthrough_ptr(ulong *value);
float passthrough_ptr(float *value);
double passthrough_ptr(double *value);
S passthrough_ptr(S *value);
+test19248 passthrough_ptr(const(test19248)* value);
+std.test19248_ passthrough_ptr(const(std.test19248_)* value);
+SInt passthrough_ptr(SInt *value);
bool passthrough_ref(ref bool value);
byte passthrough_ref(ref byte value);
ubyte passthrough_ref(ref ubyte value);
char passthrough_ref(ref char value);
+wchar passthrough_ref(ref wchar value);
dchar passthrough_ref(ref dchar value);
+wchar_t passthrough_ref(ref wchar_t value);
short passthrough_ref(ref short value);
ushort passthrough_ref(ref ushort value);
int passthrough_ref(ref int value);
@@ -51,6 +103,9 @@ ulong passthrough_ref(ref ulong value);
float passthrough_ref(ref float value);
double passthrough_ref(ref double value);
S passthrough_ref(ref S value);
+test19248 passthrough_ref(ref const(test19248) value);
+std.test19248_ passthrough_ref(ref const(std.test19248_) value);
+SInt passthrough_ref(ref SInt value);
}
template IsSigned(T)
@@ -86,7 +141,7 @@ template IsBoolean(T)
template IsSomeChar(T)
{
- enum IsSomeChar = is(T==char) || is(T==dchar);
+ enum IsSomeChar = is(T==char) || is(T==wchar) || is(T==dchar) || is(T==wchar_t);
}
void check(T)(T actual, T expected)
@@ -138,13 +193,50 @@ T[] values(T)()
return values;
}
+extern(C++, `ns1`)
+ {
+ // C++: `const char*, const char**`
+ int constFunction1(const(char)*, const(char)**);
+ // C++: `const char*, const char* const*`
+ int constFunction2(const(char)*, const(char*)*);
+ // C++: `const char* const, const char* const* const*`
+ int constFunction3(const(char*), const(char**)*);
+ // C++: `const char* const, const char* const* const* const`
+ int constFunction4(const(char*), const(char***));
+}
+
+extern(C++)
+{
+ struct SmallStruct
+ {
+ int i;
+ this(int i) { this.i = i; }
+ this(ref const SmallStruct); // implemented in C++
+ }
+ void smallStructTest(SmallStruct p);
+ void smallStructCallBack(SmallStruct p)
+ {
+ assert(p.i == 62);
+ }
+}
+
void main()
{
foreach(bool val; values!bool()) check(val);
foreach(byte val; values!byte()) check(val);
foreach(ubyte val; values!ubyte()) check(val);
foreach(char val; values!char()) check(val);
+version(CppRuntime_DigitalMars){} else
+version(CppRuntime_Microsoft)
+{
+// TODO: figure out how to detect VS2013 which doesn't support char16_t/char32_t
+}
+else
+{
+ foreach(wchar val; values!wchar()) check(val);
foreach(dchar val; values!dchar()) check(val);
+}
+ foreach(wchar_t val; values!wchar_t()) check(val);
foreach(short val; values!short()) check(val);
foreach(ushort val; values!ushort()) check(val);
foreach(int val; values!int()) check(val);
@@ -154,4 +246,26 @@ void main()
foreach(float val; values!float()) check(val);
foreach(double val; values!double()) check(val);
check(S());
+ check(test19248());
+ check(std.test19248_());
+ check(SInt());
+
+ assert(constFunction1(null, null) == 1);
+ assert(constFunction2(null, null) == 2);
+ assert(constFunction3(null, null) == 3);
+ assert(constFunction4(null, null) == 42);
+
+ auto ss = SmallStruct(42);
+ smallStructTest(ss);
+ assert(ss.i == 42);
+ assert(S18784(1).i == 1);
+
+ {
+ Sdtor sd;
+ assert(Sdtor.counter == 0);
+ consume(sd);
+ assert(Sdtor.counter == 1);
+ doConsume2(sd);
+ assert(Sdtor.counter == 2);
+ }
}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/cpp_stdlib.d b/gcc/testsuite/gdc.test/runnable_cxx/cpp_stdlib.d
new file mode 100644
index 0000000..dd7bb11
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/cpp_stdlib.d
@@ -0,0 +1,58 @@
+// DISABLED: win32 win64
+// EXTRA_CPP_SOURCES: cpp_stdlib.cpp
+// CXXFLAGS(osx linux freebsd openbsd netbsd dragonflybsd solaris): -std=c++11
+import core.stdc.stdio;
+
+// Disabled on windows because it needs bindings
+
+version (CppRuntime_Clang)
+{
+ extern(C++, `std`, `__1`)
+ {
+ struct allocator(T);
+ struct vector (T, A = allocator!T);
+ struct array (T, size_t N);
+ }
+}
+else
+{
+ extern(C++, `std`)
+ {
+ struct allocator(T);
+ struct vector (T, A = allocator!T);
+ struct array (T, size_t N);
+ }
+}
+
+extern(C++):
+
+ref T identity (T) (ref T v);
+T** identityPP (T) (T** v);
+vector!T* getVector (T) (size_t length, const T* ptr);
+array!(T, N)* getArray(T, size_t N) (const T* ptr);
+
+void main ()
+{
+ int i = 42;
+ float f = 21.0f;
+
+ int* pi = &i;
+ float* pf = &f;
+
+ assert(42 == identity(i));
+ assert(21.0f == identity(f));
+ assert(&pi == identityPP(&pi));
+ assert(&pf == identityPP(&pf));
+
+ auto vi = getVector(1, &i);
+ auto vf = getVector(3, [f, f, f].ptr);
+ assert(vi !is null);
+ assert(vf !is null);
+
+ auto ai = getArray!(int, 4)([2012, 10, 11, 42].ptr);
+ auto af = getArray!(float, 4)([42.0f, 21.0f, 14.0f, 1957.0f].ptr);
+ assert(ai !is null);
+ assert(af !is null);
+
+ printf("Success\n");
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/cppa.d b/gcc/testsuite/gdc.test/runnable_cxx/cppa.d
index cb576ba..e6db3c4 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/cppa.d
+++ b/gcc/testsuite/gdc.test/runnable_cxx/cppa.d
@@ -1,9 +1,18 @@
// PERMUTE_ARGS: -g
// EXTRA_CPP_SOURCES: cppb.cpp
+// EXTRA_FILES: extra-files/cppb.h
+// CXXFLAGS(linux freebsd osx netbsd dragonflybsd): -std=c++11
+// druntime isn't linked, this prevents missing symbols '_d_arraybounds_slicep':
+// REQUIRED_ARGS: -checkaction=C
+// Filter a spurious warning on Semaphore:
+// TRANSFORM_OUTPUT: remove_lines("warning: relocation refers to discarded section")
+
+// N.B MSVC doesn't have a C++11 switch, but it defaults to the latest fully-supported standard
import core.stdc.stdio;
import core.stdc.stdarg;
import core.stdc.config;
+import core.stdc.stdint;
extern (C++)
int foob(int i, int j, int k);
@@ -152,7 +161,7 @@ extern (C) int foosize6();
void test6()
{
S6 f = foo6();
- printf("%d %d\n", foosize6(), S6.sizeof);
+ printf("%d %zd\n", foosize6(), S6.sizeof);
assert(foosize6() == S6.sizeof);
version (X86)
{
@@ -176,7 +185,7 @@ struct S
void test7()
{
- printf("%d %d\n", foo7(), S.sizeof);
+ printf("%d %zd\n", foo7(), S.sizeof);
assert(foo7() == S.sizeof);
}
@@ -191,7 +200,7 @@ void test8()
}
/****************************************/
-// 4059
+// https://issues.dlang.org/show_bug.cgi?id=4059
struct elem9 { }
@@ -249,14 +258,7 @@ extern(C++) void check13956(S13956 arg0, int arg1, int arg2, int arg3, int arg4,
assert(arg3 == 3);
assert(arg4 == 4);
assert(arg5 == 5);
- version (OSX)
- {
- version (D_LP64)
- assert(arg6 == 6);
- // fails on OSX 32-bit
- }
- else
- assert(arg6 == 6);
+ assert(arg6 == 6);
}
void test13956()
@@ -265,7 +267,7 @@ void test13956()
}
/****************************************/
-// 5148
+// https://issues.dlang.org/show_bug.cgi?id=5148
extern (C++)
{
@@ -342,7 +344,7 @@ void testvalist()
}
/****************************************/
-// 12825
+// https://issues.dlang.org/show_bug.cgi?id=12825
extern(C++) class C12825
{
@@ -455,7 +457,7 @@ version (linux)
extern (C++, std)
{
- struct allocator(T)
+ extern (C++, class) struct allocator(T)
{
version (linux)
{
@@ -465,50 +467,47 @@ extern (C++, std)
}
}
- version (linux)
+ class vector(T, A = allocator!T)
{
- class vector(T, A = allocator!T)
- {
- final void push_back(ref const T);
- }
+ final void push_back(ref const T);
+ }
- struct char_traits(T)
- {
- }
+ struct char_traits(T)
+ {
+ }
- // https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
- version (none)
- {
- extern (C++, __cxx11)
- {
- struct basic_string(T, C = char_traits!T, A = allocator!T)
- {
- }
- }
- }
- else
+ // https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
+ version (none)
+ {
+ extern (C++, __cxx11)
{
struct basic_string(T, C = char_traits!T, A = allocator!T)
{
}
}
-
- struct basic_istream(T, C = char_traits!T)
+ }
+ else
+ {
+ extern (C++, class) struct basic_string(T, C = char_traits!T, A = allocator!T)
{
}
+ }
- struct basic_ostream(T, C = char_traits!T)
- {
- }
+ struct basic_istream(T, C = char_traits!T)
+ {
+ }
- struct basic_iostream(T, C = char_traits!T)
- {
- }
+ struct basic_ostream(T, C = char_traits!T)
+ {
+ }
+
+ struct basic_iostream(T, C = char_traits!T)
+ {
}
class exception { }
- // 14956
+ // https://issues.dlang.org/show_bug.cgi?id=14956
extern(C++, N14956)
{
struct S14956 { }
@@ -584,8 +583,10 @@ extern(C++)
{
bool f13289_cpp_test();
+
wchar_t f13289_cpp_wchar_t(wchar_t);
+
wchar f13289_d_wchar(wchar ch)
{
if (ch <= 'z' && ch >= 'a')
@@ -681,6 +682,7 @@ void test16()
{
mylong ld = 5;
ld = testl(ld);
+ printf("ld = %lld, mylong.sizeof = %lld\n", cast(long)ld, cast(long)mylong.sizeof);
assert(ld == 5 + mylong.sizeof);
}
{
@@ -694,13 +696,16 @@ void test16()
static assert(__c_long.max == long.max);
static assert(__c_long.min == long.min);
static assert(__c_long.init == long.init);
+
static assert(__c_ulong.max == ulong.max);
static assert(__c_ulong.min == ulong.min);
static assert(__c_ulong.init == ulong.init);
+
__c_long cl = 0;
cl = cl + 1;
long l = cl;
cl = l;
+
__c_ulong cul = 0;
cul = cul + 1;
ulong ul = cul;
@@ -711,13 +716,16 @@ void test16()
static assert(__c_long.max == int.max);
static assert(__c_long.min == int.min);
static assert(__c_long.init == int.init);
+
static assert(__c_ulong.max == uint.max);
static assert(__c_ulong.min == uint.min);
static assert(__c_ulong.init == uint.init);
+
__c_long cl = 0;
cl = cl + 1;
int i = cl;
cl = i;
+
__c_ulong cul = 0;
cul = cul + 1;
uint u = cul;
@@ -767,7 +775,7 @@ extern(C++, N13337.M13337)
}
/****************************************/
-// 14195
+// https://issues.dlang.org/show_bug.cgi?id=14195
struct Delegate1(T) {}
struct Delegate2(T1, T2) {}
@@ -793,7 +801,7 @@ void test14195()
/****************************************/
-// 14200
+// https://issues.dlang.org/show_bug.cgi?id=14200
template Tuple14200(T...)
{
@@ -810,7 +818,7 @@ void test14200()
}
/****************************************/
-// 14956
+// https://issues.dlang.org/show_bug.cgi?id=14956
extern(C++) void test14956(S14956 s);
@@ -869,13 +877,13 @@ void testVtable()
/****************************************/
/* problems detected by fuzzer */
-extern(C++) void fuzz1_cppvararg(long arg10, long arg11, bool arg12);
-extern(C++) void fuzz1_dvararg(long arg10, long arg11, bool arg12)
+extern(C++) void fuzz1_cppvararg(int64_t arg10, int64_t arg11, bool arg12);
+extern(C++) void fuzz1_dvararg(int64_t arg10, int64_t arg11, bool arg12)
{
fuzz1_checkValues(arg10, arg11, arg12);
}
-extern(C++) void fuzz1_checkValues(long arg10, long arg11, bool arg12)
+extern(C++) void fuzz1_checkValues(int64_t arg10, int64_t arg11, bool arg12)
{
assert(arg10 == 103);
assert(arg11 == 104);
@@ -892,13 +900,13 @@ void fuzz1()
}
////////
-extern(C++) void fuzz2_cppvararg(ulong arg10, ulong arg11, bool arg12);
-extern(C++) void fuzz2_dvararg(ulong arg10, ulong arg11, bool arg12)
+extern(C++) void fuzz2_cppvararg(uint64_t arg10, uint64_t arg11, bool arg12);
+extern(C++) void fuzz2_dvararg(uint64_t arg10, uint64_t arg11, bool arg12)
{
fuzz2_checkValues(arg10, arg11, arg12);
}
-extern(C++) void fuzz2_checkValues(ulong arg10, ulong arg11, bool arg12)
+extern(C++) void fuzz2_checkValues(uint64_t arg10, uint64_t arg11, bool arg12)
{
assert(arg10 == 103);
assert(arg11 == 104);
@@ -915,13 +923,22 @@ void fuzz2()
}
////////
-extern(C++) void fuzz3_cppvararg(wchar arg10, wchar arg11, bool arg12);
-extern(C++) void fuzz3_dvararg(wchar arg10, wchar arg11, bool arg12)
+version(CppRuntime_DigitalMars)
+ enum UNICODE = false;
+else version(CppRuntime_Microsoft)
+ enum UNICODE = false; //VS2013 doesn't support them
+else
+ enum UNICODE = true;
+
+static if (UNICODE)
+{
+extern(C++) void fuzz3_cppvararg(wchar arg10, dchar arg11, bool arg12);
+extern(C++) void fuzz3_dvararg(wchar arg10, dchar arg11, bool arg12)
{
fuzz2_checkValues(arg10, arg11, arg12);
}
-extern(C++) void fuzz3_checkValues(wchar arg10, wchar arg11, bool arg12)
+extern(C++) void fuzz3_checkValues(wchar arg10, dchar arg11, bool arg12)
{
assert(arg10 == 103);
assert(arg11 == 104);
@@ -931,17 +948,18 @@ extern(C++) void fuzz3_checkValues(wchar arg10, wchar arg11, bool arg12)
void fuzz3()
{
wchar arg10 = 103;
- wchar arg11 = 104;
+ dchar arg11 = 104;
bool arg12 = false;
fuzz3_dvararg(arg10, arg11, arg12);
fuzz3_cppvararg(arg10, arg11, arg12);
}
+}
void fuzz()
{
fuzz1();
fuzz2();
- fuzz3();
+ static if (UNICODE) fuzz3();
}
/****************************************/
@@ -1038,7 +1056,7 @@ void testeh3()
}
/****************************************/
-// 15576
+// https://issues.dlang.org/show_bug.cgi?id=15576
extern (C++, ns15576)
{
@@ -1056,7 +1074,7 @@ void test15576()
}
/****************************************/
-// 15579
+// https://issues.dlang.org/show_bug.cgi?id=15579
extern (C++)
{
@@ -1138,7 +1156,7 @@ void test15579()
}
/****************************************/
-// 15610
+// https://issues.dlang.org/show_bug.cgi?id=15610
extern(C++) class Base2
{
@@ -1164,7 +1182,7 @@ void test15610()
}
/******************************************/
-// 15455
+// https://issues.dlang.org/show_bug.cgi?id=15455
struct X6
{
@@ -1209,9 +1227,9 @@ void test15455()
}
/****************************************/
-// 15372
+// https://issues.dlang.org/show_bug.cgi?id=15372
-extern(C++) int foo15372(T)(T v);
+extern(C++) int foo15372(T)(int v);
void test15372()
{
@@ -1221,7 +1239,7 @@ void test15372()
}
/****************************************/
-// 15802
+// https://issues.dlang.org/show_bug.cgi?id=15802
extern(C++) {
template Foo15802(T) {
@@ -1237,9 +1255,10 @@ void test15802()
}
/****************************************/
-// 16536 - mangling mismatch on OSX
+// https://issues.dlang.org/show_bug.cgi?id=16536
+// mangling mismatch on OSX
-version(OSX) extern(C++) ulong pass16536(ulong);
+version(OSX) extern(C++) uint64_t pass16536(uint64_t);
void test16536()
{
@@ -1247,6 +1266,347 @@ void test16536()
}
/****************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15589
+// extern(C++) virtual destructors are not put in vtbl[]
+
+extern(C++)
+{
+ class A15589
+ {
+ extern(D) static int[] dtorSeq;
+ struct S
+ {
+ this(int x) { this.x = x; }
+ ~this() { dtorSeq ~= x; }
+ int x;
+ }
+ int foo() { return 100; } // shift dtor to slot 1
+ ~this() { dtorSeq ~= 10; }
+ S s1 = S(1);
+ S s2 = S(2);
+ }
+ class B15589 : A15589
+ {
+ int bar() { return 200;} // add an additional function AFTER the dtor at slot 2
+ ~this() { dtorSeq ~= 20; }
+ S s3 = S(3);
+ }
+
+ void test15589b(A15589 p);
+}
+
+void test15589()
+{
+ A15589 c = new B15589;
+ assert(A15589.dtorSeq == null);
+ assert(c.foo() == 100);
+ assert((cast(B15589)c).bar() == 200);
+ c.__xdtor(); // virtual dtor call
+ assert(A15589.dtorSeq[] == [ 20, 3, 10, 2, 1 ]); // destroyed full hierarchy!
+
+ A15589.dtorSeq = null;
+ test15589b(c);
+ assert(A15589.dtorSeq[] == [ 20, 3, 10, 2, 1 ]); // destroyed full hierarchy!
+}
+
+extern(C++)
+{
+ class Cpp15589Base
+ {
+ public:
+ final ~this();
+
+ void nonVirtual();
+ int a;
+ }
+
+ class Cpp15589Derived : Cpp15589Base
+ {
+ public:
+ this();
+ final ~this();
+ int b;
+ }
+
+ class Cpp15589BaseVirtual
+ {
+ public:
+ void beforeDtor();
+
+ this();
+ ~this();
+
+ void afterDtor();
+ int c = 1;
+ }
+
+ class Cpp15589DerivedVirtual : Cpp15589BaseVirtual
+ {
+ public:
+ this();
+ ~this();
+
+ override void afterDtor();
+
+ int d;
+ }
+
+ class Cpp15589IntroducingVirtual : Cpp15589Base
+ {
+ public:
+ this();
+ void beforeIntroducedVirtual();
+ ~this();
+ void afterIntroducedVirtual(int);
+
+ int e;
+ }
+
+ struct Cpp15589Struct
+ {
+ ~this();
+ int s;
+ }
+
+ void trace15589(int ch)
+ {
+ traceBuf[traceBufPos++] = cast(char) ch;
+ }
+}
+
+__gshared char[32] traceBuf;
+__gshared size_t traceBufPos;
+
+// workaround for https://issues.dlang.org/show_bug.cgi?id=18986
+version(OSX)
+ enum cppCtorReturnsThis = false;
+else version(FreeBSD)
+ enum cppCtorReturnsThis = false;
+else
+ enum cppCtorReturnsThis = true;
+
+mixin template scopeAllocCpp(C)
+{
+ static if (cppCtorReturnsThis)
+ scope C ptr = new C;
+ else
+ {
+ ubyte[__traits(classInstanceSize, C)] data;
+ C ptr = (){ auto p = cast(C) data.ptr; p.__ctor(); return p; }();
+ }
+}
+
+void test15589b()
+{
+ traceBufPos = 0;
+ {
+ Cpp15589Struct struc = Cpp15589Struct();
+ mixin scopeAllocCpp!Cpp15589Derived derived;
+ mixin scopeAllocCpp!Cpp15589DerivedVirtual derivedVirtual;
+ mixin scopeAllocCpp!Cpp15589IntroducingVirtual introducingVirtual;
+
+ // `scope` instances are destroyed automatically
+ static if (!cppCtorReturnsThis)
+ {
+ introducingVirtual.ptr.destroy();
+ derivedVirtual.ptr.destroy();
+ derived.ptr.destroy();
+ }
+ }
+ printf("traceBuf15589 %.*s\n", cast(int)traceBufPos, traceBuf.ptr);
+ assert(traceBuf[0..traceBufPos] == "IbVvBbs");
+}
+
+/****************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=18928
+// Win64: extern(C++) bad codegen, wrong calling convention
+
+extern(C++) struct Small18928
+{
+ int x;
+}
+
+extern(C++) class CC18928
+{
+ Small18928 getVirtual(); // { return S(3); }
+ final Small18928 getFinal(); // { return S(4); }
+ static Small18928 getStatic(); // { return S(5); }
+}
+
+extern(C++) CC18928 newCC18928();
+
+void test18928()
+{
+ auto cc = newCC18928();
+ Small18928 v = cc.getVirtual();
+ assert(v.x == 3);
+ Small18928 f = cc.getFinal();
+ assert(f.x == 4);
+ Small18928 s = cc.getStatic();
+ assert(s.x == 5);
+}
+
+/****************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18953
+// Win32: extern(C++) struct destructor not called correctly through runtime
+
+extern(C++)
+struct S18953
+{
+ char x;
+ ~this() nothrow @nogc { traceBuf[traceBufPos++] = x; }
+}
+
+void test18953()
+{
+ traceBufPos = 0;
+ S18953[] arr = new S18953[3];
+ arr[1].x = '1';
+ arr[2].x = '2';
+ arr.length = 1;
+ assumeSafeAppend(arr); // destroys arr[1] and arr[2]
+ printf("traceBuf18953 %.*s\n", cast(int)traceBufPos, traceBuf.ptr);
+ assert(traceBuf[0..traceBufPos] == "21");
+}
+
+/****************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=18966
+
+extern(C++):
+class Base18966
+{
+ this() @safe nothrow;
+ ~this() @safe;
+ void vf();
+ int x;
+}
+
+class Derived18966 : Base18966
+{
+ override void vf() { x = 200; }
+}
+
+class Explicit18966 : Base18966
+{
+ this() @safe { super(); }
+ override void vf() { x = 250; }
+}
+
+class Implicit18966 : Base18966
+{
+ this() nothrow {}
+ override void vf() { x = 300; }
+}
+
+// test vptr in full ctor chain of mixed D/C++ class hierarchies
+
+// TODO: Make this a D class and let C++ derive from it. This works on Windows,
+// but results in linker errors on Posix due to extra base ctor (`C2`
+// mangling) being called by the B ctor.
+class A18966 // in C++
+{
+ char[8] calledOverloads = 0;
+ int i;
+ this();
+ void foo();
+}
+
+class B18966 : A18966 // in C++
+{
+ this();
+ override void foo();
+}
+
+class C18966 : B18966
+{
+ this() { foo(); }
+ override void foo() { calledOverloads[i++] = 'C'; }
+}
+
+class D18966 : C18966
+{
+ this() { foo(); }
+ override void foo() { calledOverloads[i++] = 'D'; }
+}
+
+void test18966()
+{
+ Derived18966 d = new Derived18966;
+ assert(d.x == 10);
+ d.vf();
+ assert(d.x == 200);
+
+ Explicit18966 e = new Explicit18966;
+ assert(e.x == 10);
+ e.vf();
+ assert(e.x == 250);
+
+ Implicit18966 i = new Implicit18966;
+ assert(i.x == 10);
+ i.vf();
+ assert(i.x == 300);
+
+ // TODO: Allocating + constructing a C++ class with the D GC is not
+ // supported on Posix. The returned pointer (probably from C++ ctor)
+ // seems to be an offset and not the actual object address.
+ version (Windows)
+ {
+ auto a = new A18966;
+ assert(a.calledOverloads[0..2] == "A\0");
+
+ auto b = new B18966;
+ assert(b.calledOverloads[0..3] == "AB\0");
+ }
+
+ auto c = new C18966;
+ assert(c.calledOverloads[0..4] == "ABC\0");
+
+ auto d2 = new D18966;
+ // note: the vptr semantics in ctors of extern(C++) classes may be revised (to "ABCD")
+ assert(d2.calledOverloads[0..5] == "ABDD\0");
+}
+
+/****************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=19134
+
+class Base19134
+{
+ int a = 123;
+ this() { a += 42; }
+ int foo() const { return a; }
+}
+
+class Derived19134 : Base19134
+{
+ int b = 666;
+ this()
+ {
+ a *= 2;
+ b -= 6;
+ }
+ override int foo() const { return b; }
+}
+
+void test19134()
+{
+ static const d = new Derived19134;
+ assert(d.a == (123 + 42) * 2);
+ assert(d.b == 666 - 6);
+ assert(d.foo() == 660);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=18955
+alias std_string = std.basic_string!(char);
+
+extern(C++) void callback18955(ref const(std_string) str)
+{
+}
+extern(C++) void test18955();
+
+/****************************************/
void main()
{
@@ -1290,6 +1650,13 @@ void main()
test15372();
test15802();
test16536();
+ test15589();
+ test15589b();
+ test18928();
+ test18953();
+ test18966();
+ test19134();
+ test18955();
printf("Success\n");
}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/externmangle.d b/gcc/testsuite/gdc.test/runnable_cxx/externmangle.d
index 9099f94..ef132dc 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/externmangle.d
+++ b/gcc/testsuite/gdc.test/runnable_cxx/externmangle.d
@@ -1,4 +1,8 @@
// EXTRA_CPP_SOURCES: externmangle.cpp
+// REQUIRED_ARGS: -extern-std=c++11
+
+import core.stdc.config;
+import core.stdc.stdint;
extern(C++):
@@ -122,7 +126,16 @@ interface Module
public static int dim(Array!Module*);
};
-ulong testlongmangle(int a, uint b, long c, ulong d);
+uint64_t testlongmangle(int a, uint b, int64_t c, uint64_t d);
+cpp_ulong testCppLongMangle(cpp_long a, cpp_ulong b);
+cpp_ulonglong testCppLongLongMangle(cpp_longlong a, cpp_ulonglong b);
+
+// direct size_t/ptrdiff_t interop is fine except on 32-bit OS X
+version (OSX) { version (D_LP64) {} else version = OSX_32; }
+version (OSX_32)
+ cpp_size_t testCppSizeTMangle(cpp_ptrdiff_t a, cpp_size_t b);
+else
+ size_t testCppSizeTMangle(ptrdiff_t a, size_t b);
__gshared extern int[2][2][2] test31;
__gshared extern int* test32;
@@ -224,6 +237,40 @@ void test39()
assert(result == 0);
}
+extern(C++, "foo", "bar", "baz") int doStuff(int);
+
+version(CppRuntime_DigitalMars) // DMC doesn't support c++11
+{
+ void test40() {}
+ void test41() {}
+}
+else
+{
+ void test40();
+
+ void foovargs(T...)(T args)
+ {
+ static if (is(T[0] == char*))
+ {
+ assert(*args[0] == 'a');
+ }
+ else
+ {
+ float ret = args[0] + args[1];
+ assert(ret == 3.0f);
+ }
+ }
+
+ alias FooVargs = foovargs!(int, float);
+ alias FooVargs2 = foovargs!(char*);
+
+ void test41();
+ void make_shared_poc(T, Args...)(ref Args args)
+ {
+ assert(args[0] + args[1] == 3);
+ }
+ alias Make_Shared_Poc = make_shared_poc!(int, int, int);
+}
void main()
{
@@ -280,6 +327,9 @@ void main()
assert(Module.dim(&arr2) == 20);
assert(testlongmangle(1, 2, 3, 4) == 10);
+ assert(testCppLongMangle(1, 2) == 3);
+ assert(testCppLongLongMangle(3, 4) == 7);
+ assert(testCppSizeTMangle(3, 4) == 7);
assert(test31 == [[[1, 1], [1, 1]], [[1, 1], [1, 1]]]);
assert(test32 == null);
@@ -311,4 +361,9 @@ void main()
assert(t38.test(1, 2, 3) == 1);
Test38.dispose(t38);
test39();
+
+ assert(doStuff(2) == 4);
+
+ test40();
+ test41();
}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/externmangle2.d b/gcc/testsuite/gdc.test/runnable_cxx/externmangle2.d
index 74beb25..e003c95 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/externmangle2.d
+++ b/gcc/testsuite/gdc.test/runnable_cxx/externmangle2.d
@@ -1,164 +1,156 @@
// EXTRA_CPP_SOURCES: externmangle2.cpp
+// DISABLED: win
-version(Windows)
+extern(C++):
+
+struct Test32NS1
{
- void main()
+ struct Foo(X)
{
+ X *v;
}
-}
-else
-{
- extern(C++):
-
- struct Test32NS1
- {
- struct Foo(X)
- {
- X *v;
- }
- struct Bar(X)
- {
- X *v;
- }
+ struct Bar(X)
+ {
+ X *v;
+ }
- };
+};
- struct Test32NS2
+struct Test32NS2
+{
+ struct Foo(X)
{
- struct Foo(X)
- {
- X *v;
- }
- };
+ X *v;
+ }
+};
- struct Test32(alias Y, alias Z)
- {
- Y!(int)* field;
- };
+struct Test32(alias Y, alias Z)
+{
+ Y!(int)* field;
+};
- void test32a(Test32!(Test32NS1.Foo, Test32NS1.Foo) arg);
- void test32b(Test32!(Test32NS1.Foo, Test32NS1.Bar) arg);
- void test32c(Test32!(Test32NS1.Foo, Test32NS2.Foo) arg);
- void test32d(Test32!(Test32NS1.Foo, Test32NS2.Foo) arg1, Test32!(Test32NS2.Foo, Test32NS1.Foo) arg2);
+void test32a(Test32!(Test32NS1.Foo, Test32NS1.Foo) arg);
+void test32b(Test32!(Test32NS1.Foo, Test32NS1.Bar) arg);
+void test32c(Test32!(Test32NS1.Foo, Test32NS2.Foo) arg);
+void test32d(Test32!(Test32NS1.Foo, Test32NS2.Foo) arg1, Test32!(Test32NS2.Foo, Test32NS1.Foo) arg2);
- interface XXX
- {
- }
+interface XXX
+{
+}
- void test33a(XXX, XXX*);
+void test33a(XXX, XXX*);
- struct Test33(alias A, alias B)
- {
- }
+struct Test33(alias A, alias B)
+{
+}
- /*
- void test33(XXX, Test33!(test33a, test33a) arg, XXX);
+/*
+void test33(XXX, Test33!(test33a, test33a) arg, XXX);
- struct Test34(alias A)
- {
- };
+struct Test34(alias A)
+{
+};
- struct Test34A
- {
- static void foo(int);
- };
+struct Test34A
+{
+ static void foo(int);
+};
- void test34(Test34!(Test34A.foo) arg);
- */
+void test34(Test34!(Test34A.foo) arg);
+*/
- __gshared extern int test36;
+__gshared extern int test36;
- /*
- struct Test37(alias A)
- {
- };
+/*
+struct Test37(alias A)
+{
+};
- struct Test37A
- {
- __gshared extern int t38;
- };
+struct Test37A
+{
+ __gshared extern int t38;
+};
- void test37(Test37!(test36) arg);
- void test38(Test37!(Test37A.t38) arg);
- */
+void test37(Test37!(test36) arg);
+void test38(Test37!(Test37A.t38) arg);
+*/
- struct Test39
+struct Test39
+{
+ struct T39A(X)
{
- struct T39A(X)
- {
- }
}
+}
- struct T39A
- {
- }
+struct T39A
+{
+}
- void test39(Test39.T39A!(.T39A));
+void test39(Test39.T39A!(.T39A));
- version(none)
+version(none)
+{
+ version(Posix) //Only for g++ with -std=c++0x and Visual Studio 2013+
{
- version(Posix) //Only for g++ with -std=c++0x and Visual Studio 2013+
- {
-
- struct Test40(T, V...)
- {
- }
+ struct Test40(T, V...)
+ {
- void test40(Test40!(int, double, void))
- {
- }
}
- else version(Win64) //Only for g++ with -std=c++0x and Visual Studio 2013+
+
+ void test40(Test40!(int, double, void))
{
+ }
+ }
+ else version(Win64) //Only for g++ with -std=c++0x and Visual Studio 2013+
+ {
- struct Test40(T, V...)
- {
+ struct Test40(T, V...)
+ {
- }
+ }
- void test40(Test40!(int, double, void))
- {
- }
+ void test40(Test40!(int, double, void))
+ {
}
}
+}
- __gshared extern const XXX test41;
- struct Test42
- {
- __gshared extern const XXX test42;
- }
- __gshared extern int[4] test43;
- const(XXX) test44();
+__gshared extern const XXX test41;
+struct Test42
+{
+ __gshared extern const XXX test42;
+}
+__gshared extern int[4] test43;
+const(XXX) test44();
- void main()
- {
- test32a(Test32!(Test32NS1.Foo, Test32NS1.Foo)());
- test32b(Test32!(Test32NS1.Foo, Test32NS1.Bar)());
- test32c(Test32!(Test32NS1.Foo, Test32NS2.Foo)());
- test32d(Test32!(Test32NS1.Foo, Test32NS2.Foo)(), Test32!(Test32NS2.Foo, Test32NS1.Foo)());
+void main()
+{
+ test32a(Test32!(Test32NS1.Foo, Test32NS1.Foo)());
+ test32b(Test32!(Test32NS1.Foo, Test32NS1.Bar)());
+ test32c(Test32!(Test32NS1.Foo, Test32NS2.Foo)());
+ test32d(Test32!(Test32NS1.Foo, Test32NS2.Foo)(), Test32!(Test32NS2.Foo, Test32NS1.Foo)());
- //test33a(null, null);
- //test33(null, Test33!(test33a, test33a)(), null);
+ //test33a(null, null);
+ //test33(null, Test33!(test33a, test33a)(), null);
- //test34(Test34!(Test34A.foo)());
+ //test34(Test34!(Test34A.foo)());
- assert(test36 == 36);
+ assert(test36 == 36);
- //test37(Test37!(test36)());
- //test38(Test37!(Test37A.t38)());
- test39(Test39.T39A!(.T39A)());
+ //test37(Test37!(test36)());
+ //test38(Test37!(Test37A.t38)());
+ test39(Test39.T39A!(.T39A)());
- assert(test41 is null);
- assert(Test42.test42 is null);
- assert(test43 == [1, 2, 3, 4]);
- auto ptr = &test44;
- }
+ assert(test41 is null);
+ assert(Test42.test42 is null);
+ assert(test43 == [1, 2, 3, 4]);
+ auto ptr = &test44;
}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/abi_tags.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/abi_tags.cpp
new file mode 100644
index 0000000..a161f05
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/abi_tags.cpp
@@ -0,0 +1,146 @@
+/*
+ * Test C++ abi-tag name mangling.
+ * https://issues.dlang.org/show_bug.cgi?id=19949
+ *
+ * ABI tags are only supported on Linux & OSX,
+ * however OSX doesn't use it in its standard library.
+ *
+ * Requires at minimum Clang 3.9.0 or GCC 5.1
+ */
+
+struct [[gnu::abi_tag("tag1")]] Tagged1 {};
+struct [[gnu::abi_tag("tag2")]] Tagged2 {};
+
+struct [[gnu::abi_tag("tag1", "tag2")]] Tagged1_2
+{
+ struct [[gnu::abi_tag("tag3")]] Tagged3
+ {
+ Tagged3(int value_) : value(value_) {}
+
+ // _ZN9Tagged1_2B4tag1B4tag27Tagged3B4tag37Tagged4B4tag4Ev
+ [[gnu::abi_tag("tag4")]]
+ int Tagged4 () { return this->value; }
+
+ int value;
+ };
+};
+struct [[gnu::abi_tag("tag1")]] Tagged1Too {};
+
+// _Z5inst1B4tag1B4tag2
+Tagged1_2 inst1;
+// _Z5inst2B4tag1B4tag2B4tag3
+Tagged1_2::Tagged3 inst2(42);
+
+// _Z5func0B4tag1B4tag2i
+Tagged1_2 func0(int a) { return Tagged1_2(); }
+// _Z5func19Tagged1_2B4tag1B4tag2
+Tagged1_2 func1(Tagged1_2 a) { return a; }
+// _Z5func2B4tag27Tagged1B4tag1
+Tagged1_2 func2(Tagged1 a) { return Tagged1_2(); }
+// _Z5func3B4tag17Tagged2B4tag2
+Tagged1_2 func3(Tagged2 a) { return Tagged1_2(); }
+// _Z5func47Tagged2B4tag27Tagged1B4tag1
+Tagged1_2 func4(Tagged2 a, Tagged1 b) { return Tagged1_2(); }
+// _Z5func5B4tag37Tagged2B4tag27Tagged1B4tag1
+Tagged1_2::Tagged3 func5(Tagged2 a, Tagged1 b) { return Tagged1_2::Tagged3(420); }
+// _Z5func67Tagged2B4tag2S_7Tagged1B4tag19Tagged1_2B4tag1B4tag2
+void func6(Tagged2 a, Tagged2 b, Tagged1 c, Tagged1_2 d) {}
+// With T=Tagged1_2: _Z5func7I9Tagged1_2B4tag1B4tag2ET_S1_i
+template<typename T>
+T func7(T a, int) { return a; }
+// _Z5func87Tagged1B4tag110Tagged1TooB4tag1
+void func8 (Tagged1, Tagged1Too) {}
+
+// Explicitly instantiate the above templates.
+template Tagged1_2 func7<Tagged1_2>(Tagged1_2, int);
+
+struct [[gnu::abi_tag("foo", "bar")]] S
+{
+public:
+ int i;
+ S(int);
+};
+
+S::S(int i) : i(i) {}
+
+[[gnu::abi_tag("foo", "bar")]]
+int a;
+
+S b(0);
+
+[[gnu::abi_tag("foo", "bar")]]
+int f() { return 0xf; }
+
+S gs(int i) { return S(i + 0xe0); }
+S gss(S s, int i) { return S(i + s.i + 0xe0); }
+
+[[gnu::abi_tag("foo", "bar")]]
+S fss(S s, int i) { return S(i + s.i + 0xf); }
+
+template <class T>
+T gt(int i) { return T(i + 0xe0); }
+
+template <class T>
+T gtt(T t, int i) { return T(i + t.i + 0xe0); }
+
+
+template <class T>
+[[gnu::abi_tag("foo", "bar")]] /* GCC is inconsistent here, <= 6 matches clang but >= 7 is different */
+T ft(int i) { return T(i + 0xf); }
+
+template <class T>
+[[gnu::abi_tag("foo", "bar")]] /* GCC is inconsistent here, <= 6 matches clang but >= 7 is different */
+T ftt(T t, int i) { return T(i + t.i + 0xf); }
+
+#ifdef __clang__
+inline namespace [[gnu::abi_tag("AAA")]] N
+#else
+inline namespace N [[gnu::abi_tag("AAA")]]
+#endif
+{
+ template <int>
+ struct [[gnu::abi_tag("foo", "bar")]] K
+ {
+ public:
+ int i;
+ K(int i);
+ };
+}
+
+template <int j>
+K<j>::K(int i) : i(i) {}
+
+// Note: This does not include the 'AAA' in the mangling
+// template <int j>
+// K<j> fk(int i) { return K<j>(i + j + 0xf); }
+
+K<1> fk1(int i) { return K<1>(i + 1 + 0xf); }
+
+K<10> k10(0);
+
+void initVars()
+{
+ a = 10;
+ b = S(20);
+ k10 = K<10>(30);
+}
+
+// doesn't compile on GCC < 6, and not at all on Clang (tested with 9.0.1)
+#if __GNUC__ >= 6
+enum [[gnu::abi_tag("ENN")]] E0
+{ E0a = 0xa };
+
+E0 fe() { return E0a; }
+
+template<int>
+E0 fei() { return E0a; }
+#endif
+
+// Explicitly instantiate the above templates.
+template S gt<S>(int);
+template S gtt<S>(S, int);
+template S ft<S>(int);
+template S ftt<S>(S, int);
+#if __GNUC__ >= 6
+template E0 fei<0>();
+#endif
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/c14203.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/c14203.cpp
new file mode 100644
index 0000000..059d0ee
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/c14203.cpp
@@ -0,0 +1,2 @@
+
+float func1() { return 73; }
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp11.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp11.cpp
new file mode 100644
index 0000000..88aa719
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp11.cpp
@@ -0,0 +1,35 @@
+#include <assert.h>
+#include <cstddef>
+#include <cstdint>
+
+void testnull(std::nullptr_t n)
+{
+ assert(n == nullptr);
+}
+
+void testnullnull(std::nullptr_t n1, std::nullptr_t n2)
+{
+ assert(n1 == nullptr);
+ assert(n2 == nullptr);
+}
+
+/****************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19658
+
+enum class i8_19658 : std::int8_t;
+enum class u8_19658 : std::uint8_t;
+enum class i16_19658 : std::int16_t;
+enum class u16_19658 : std::uint16_t;
+enum class i32_19658 : std::int32_t;
+enum class u32_19658 : std::uint32_t;
+enum class i64_19658 : std::int64_t;
+enum class u64_19658 : std::uint64_t;
+
+void test19658_i8(i8_19658) {}
+void test19658_u8(u8_19658) {}
+void test19658_i16(i16_19658) {}
+void test19658_u16(u16_19658) {}
+void test19658_i32(i32_19658) {}
+void test19658_u32(u32_19658) {}
+void test19658_i64(i64_19658) {}
+void test19658_u64(u64_19658) {}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp19179.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp19179.cpp
new file mode 100644
index 0000000..3ca23c1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp19179.cpp
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=19179
+
+struct SmallStruct { int x, y; };
+
+SmallStruct test_small(SmallStruct);
+void test_small_noret(SmallStruct);
+
+void cppmain()
+{
+ SmallStruct s;
+ s.x = 10;
+ s.y = 20;
+ test_small(s);
+ test_small_noret(s);
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_abi_tests.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_abi_tests.cpp
index 63f74a2..8ba6139 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_abi_tests.cpp
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_abi_tests.cpp
@@ -1,11 +1,51 @@
+#include <assert.h>
+
struct S{
float a;
};
+namespace std
+{
+ struct test19248_ {int a;}; // Remove when `extern(C++, ns)` is gone
+ struct test19248 {int a;};
+};
+
+#ifdef __DMC__
+// DMC doesn't support c++11
+#elif defined (_MSC_VER) && _MSC_VER <= 1800
+// MSVC2013 doesn't support char16_t/char32_t
+#else
+#define TEST_UNICODE
+#endif
+
+struct S18784
+{
+ int i;
+ S18784(int n);
+};
+
+S18784::S18784(int n) : i(n) {}
+
+#ifdef __DMC__ // DMC doesn't support c++11
+template <class>
+#else
+template <class...>
+#endif
+struct SPack
+{
+ int i;
+};
+
+typedef SPack<int> SInt;
+
bool passthrough(bool value) { return value; }
signed char passthrough(signed char value) { return value; }
unsigned char passthrough(unsigned char value) { return value; }
char passthrough(char value) { return value; }
+#ifdef TEST_UNICODE
+char16_t passthrough(char16_t value) { return value; }
+char32_t passthrough(char32_t value) { return value; }
+#endif
wchar_t passthrough(wchar_t value) { return value; }
short passthrough(short value) { return value; }
unsigned short passthrough(unsigned short value) { return value; }
@@ -18,11 +58,18 @@ unsigned long long passthrough(unsigned long long value) { return value; }
float passthrough(float value) { return value; }
double passthrough(double value) { return value; }
S passthrough(S value) { return value; }
+std::test19248 passthrough(const std::test19248 value) { return value; }
+std::test19248_ passthrough(const std::test19248_ value) { return value; }
+SInt passthrough(SInt value) { return value; }
bool passthrough_ptr(bool *value) { return *value; }
signed char passthrough_ptr(signed char *value) { return *value; }
unsigned char passthrough_ptr(unsigned char *value) { return *value; }
char passthrough_ptr(char *value) { return *value; }
+#ifdef TEST_UNICODE
+char16_t passthrough_ptr(char16_t *value) { return *value; }
+char32_t passthrough_ptr(char32_t *value) { return *value; }
+#endif
wchar_t passthrough_ptr(wchar_t *value) { return *value; }
short passthrough_ptr(short *value) { return *value; }
unsigned short passthrough_ptr(unsigned short *value) { return *value; }
@@ -35,11 +82,18 @@ unsigned long long passthrough_ptr(unsigned long long *value) { return *value; }
float passthrough_ptr(float *value) { return *value; }
double passthrough_ptr(double *value) { return *value; }
S passthrough_ptr(S *value) { return *value; }
+std::test19248 passthrough_ptr(const std::test19248 *value) { return *value; }
+std::test19248_ passthrough_ptr(const std::test19248_ *value) { return *value; }
+SInt passthrough_ptr(SInt *value) { return *value; }
bool passthrough_ref(bool &value) { return value; }
signed char passthrough_ref(signed char &value) { return value; }
unsigned char passthrough_ref(unsigned char &value) { return value; }
char passthrough_ref(char &value) { return value; }
+#ifdef TEST_UNICODE
+char16_t passthrough_ref(char16_t &value) { return value; }
+char32_t passthrough_ref(char32_t &value) { return value; }
+#endif
wchar_t passthrough_ref(wchar_t &value) { return value; }
short passthrough_ref(short &value) { return value; }
unsigned short passthrough_ref(unsigned short &value) { return value; }
@@ -52,6 +106,55 @@ unsigned long long passthrough_ref(unsigned long long &value) { return value; }
float passthrough_ref(float &value) { return value; }
double passthrough_ref(double &value) { return value; }
S passthrough_ref(S &value) { return value; }
+std::test19248 passthrough_ref(const std::test19248 &value) { return value; }
+std::test19248_ passthrough_ref(const std::test19248_ &value) { return value; }
+SInt passthrough_ref(SInt &value) { return value; }
+
+namespace ns1
+{
+ // D: `char*, const(char)**`
+ int constFunction1(const char*, const char**) { return 1; }
+ // D: `const(char)*, const(char*)*`
+ int constFunction2(const char*, const char* const*) { return 2; }
+ // D: `const(char*), const(char**)*`
+ int constFunction3(const char* const, const char* const* const*) { return 3; }
+ // D: `const(char*), const(char***)`
+ int constFunction4(const char* const, const char* const* const* const) { return 42; }
+};
+
+struct SmallStruct
+{
+ int i;
+ SmallStruct(int); // implemented in D
+ SmallStruct(const SmallStruct &);
+};
+SmallStruct::SmallStruct(const SmallStruct &rhs)
+ : i(rhs.i + 10) {}
+void smallStructCallBack(SmallStruct p);
+void smallStructTest(SmallStruct p)
+{
+ assert(p.i == 52);
+
+ smallStructCallBack(p);
+ assert(p.i == 52);
+}
+
+struct Sdtor
+{
+ static int counter;
+ ~Sdtor();
+};
+
+Sdtor::~Sdtor() { ++counter; }
+int Sdtor::counter = 0;
+
+void consume(Sdtor value) {}
+
+void consume2(Sdtor value);
+void doConsume2(Sdtor& value)
+{
+ consume2(value);
+}
// Uncomment when mangling is fixed
// typedef void(*fn0)();
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_stdlib.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_stdlib.cpp
new file mode 100644
index 0000000..deb027a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_stdlib.cpp
@@ -0,0 +1,47 @@
+#include <array>
+#include <string>
+#include <vector>
+
+template<typename T>
+T& identity (T& v) { return v; }
+template<typename T>
+T** identityPP (T** v) { return v; }
+
+template<typename T>
+std::vector<T>* getVector(size_t len, const T* ptr)
+{
+ std::vector<T>* ret = new std::vector<T>(len);
+ for (size_t i = 0; i < len; ++i)
+ (*ret)[i] = ptr[i];
+ return ret;
+}
+
+std::string* getString(int len, const char* ptr)
+{
+ return new std::string(ptr, len);
+}
+
+template<typename T, size_t N>
+std::array<T, N>* getArray(const T* ptr)
+{
+ std::array<T, N>* ret = new std::array<T, N>();
+ for (size_t x = 0; x < N; ++x)
+ (*ret)[x] = ptr[x];
+ return ret;
+}
+
+// Explicit instantiations, so they are callable outside this compilation unit.
+template int** identityPP<int>(int**);
+template float** identityPP<float>(float**);
+template int& identity<int>(int&);
+template float& identity<float>(float&);
+
+template std::vector<int>* getVector<int>(size_t, const int*);
+template std::vector<float>* getVector<float>(size_t, const float*);
+//typedef std::vector<float> svf_t;
+//template std::vector<svf_t>* getVector<svf_t>(size_t, const svf_t*);
+
+template std::array<int, 4>* getArray<int, 4>(const int*);
+template std::array<float, 4>* getArray<float, 4>(const float*);
+//typedef Foo<int, 42> fi42_t;
+//template std::array<fi42_t, 4> getArray<fi42_t, 4>(const fi42_t*);
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.cpp
index 823c660..ab1ea0a5 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.cpp
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.cpp
@@ -32,10 +32,13 @@ headers.
#define _GLIBCXX_USE_CXX11_ABI 0
#include <stdio.h>
+#include <stdint.h>
#include <assert.h>
#include <exception>
#include <cstdarg>
+#include "cppb.h"
+
/**************************************/
int foo(int i, int j, int k);
@@ -268,13 +271,13 @@ void foo8(const char *p)
}
/**************************************/
-// 4059
+// https://issues.dlang.org/show_bug.cgi?id=4059
struct elem9 { };
void foobar9(elem9*, elem9*) { }
/**************************************/
-// 5148
+// https://issues.dlang.org/show_bug.cgi?id=5148
void foo10(const char*, const char*) { }
void foo10(const int, const int) { }
@@ -347,7 +350,7 @@ size_t getoffset13161a()
/****************************************************/
-#if __linux__ || __APPLE__ || __FreeBSD__
+#if __linux__ || __APPLE__ || __FreeBSD__ || __DragonFly__
#include <memory>
#include <vector>
#include <string>
@@ -403,36 +406,30 @@ wchar_t f13289_cpp_wchar_t(wchar_t ch)
return ch;
}
}
-
-#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun || __NetBSD__
-unsigned short f13289_d_wchar(unsigned short ch);
-wchar_t f13289_d_dchar(wchar_t ch);
-#elif _WIN32
-wchar_t f13289_d_wchar(wchar_t ch);
-unsigned int f13289_d_dchar(unsigned int ch);
+#ifdef __DMC__
+// DMC doesn't support c++11
+#elif defined (_MSC_VER) //&& _MSC_VER <= 1800
+// MSVC2013 doesn't support char16_t/char32_t
+#else
+#define TEST_UNICODE
+#endif
+#ifdef TEST_UNICODE
+char16_t f13289_d_wchar(char16_t ch);
+char32_t f13289_d_dchar(char32_t ch);
#endif
-
wchar_t f13289_d_wchar_t(wchar_t ch);
bool f13289_cpp_test()
{
if (!(f13289_d_wchar_t(L'e') == L'E')) return false;
if (!(f13289_d_wchar_t(L'F') == L'F')) return false;
-#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun || __NetBSD__
- if (!(f13289_d_wchar((unsigned short)'c') == (unsigned short)'C')) return false;
- if (!(f13289_d_wchar((unsigned short)'D') == (unsigned short)'D')) return false;
- if (!(f13289_d_dchar(L'e') == L'E')) return false;
- if (!(f13289_d_dchar(L'F') == L'F')) return false;
- return true;
-#elif _WIN32
- if (!(f13289_d_wchar(L'c') == L'C')) return false;
- if (!(f13289_d_wchar(L'D') == L'D')) return false;
- if (!(f13289_d_dchar((unsigned int)'e') == (unsigned int)'E')) return false;
- if (!(f13289_d_dchar((unsigned int)'F') == (unsigned int)'F')) return false;
- return true;
-#else
- return false;
+#ifdef TEST_UNICODE
+ if (!(f13289_d_wchar(u'c') == u'C')) return false;
+ if (!(f13289_d_wchar(u'D') == u'D')) return false;
+ if (!(f13289_d_dchar(U'e') == U'E')) return false;
+ if (!(f13289_d_dchar(U'F') == U'F')) return false;
#endif
+ return true;
}
/******************************************/
@@ -499,7 +496,7 @@ namespace N13337 {
}
/****************************************/
-// 14195
+// https://issues.dlang.org/show_bug.cgi?id=14195
template <typename T>
struct Delegate1 {};
@@ -518,17 +515,17 @@ void test14195a(Delegate1<void()> func) {}
void test14195b(Delegate2<int(float, double), int(float, double)> func) {}
/******************************************/
-// 14200
+// https://issues.dlang.org/show_bug.cgi?id=14200
void test14200a(int a) {};
void test14200b(float a, int b, double c) {};
/******************************************/
-// 14956
+// https://issues.dlang.org/show_bug.cgi?id=14956
namespace std {
namespace N14956 {
- struct S14956 { };
+ struct S14956 { };
}
}
@@ -577,35 +574,26 @@ Visitor2* getVisitor2()
/******************************************/
// issues detected by fuzzer
-#if _LP64
-#define longlong long
-#else
-#define longlong long long
-#endif
-void fuzz1_checkValues(longlong arg10, longlong arg11, bool arg12);
-void fuzz1_cppvararg(longlong arg10, longlong arg11, bool arg12)
+void fuzz1_checkValues(int64_t arg10, int64_t arg11, bool arg12);
+void fuzz1_cppvararg(int64_t arg10, int64_t arg11, bool arg12)
{
fuzz1_checkValues(arg10, arg11, arg12);
}
-void fuzz2_checkValues(unsigned longlong arg10, unsigned longlong arg11, bool arg12);
-void fuzz2_cppvararg(unsigned longlong arg10, unsigned longlong arg11, bool arg12)
+void fuzz2_checkValues(uint64_t arg10, uint64_t arg11, bool arg12);
+void fuzz2_cppvararg(uint64_t arg10, uint64_t arg11, bool arg12)
{
fuzz2_checkValues(arg10, arg11, arg12);
}
-#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun || __NetBSD__
-#define wchar unsigned short
-#elif _WIN32
-#define wchar wchar_t
-#endif
-
-void fuzz3_checkValues(wchar arg10, wchar arg11, bool arg12);
-void fuzz3_cppvararg(wchar arg10, wchar arg11, bool arg12)
+#ifdef TEST_UNICODE
+void fuzz3_checkValues(char16_t arg10, char32_t arg11, bool arg12);
+void fuzz3_cppvararg(char16_t arg10, char32_t arg11, bool arg12)
{
fuzz3_checkValues(arg10, arg11, arg12);
}
+#endif
/******************************************/
@@ -620,7 +608,7 @@ void throwit()
/******************************************/
-#if linux
+#if __linux__
#include <stdexcept>
void throwle()
@@ -632,10 +620,10 @@ void throwle()
#endif
/******************************************/
-// 15579
+// https://issues.dlang.org/show_bug.cgi?id=15579
/******************************************/
-// 15579
+// https://issues.dlang.org/show_bug.cgi?id=15579
class Base
{
@@ -710,7 +698,7 @@ Interface *cppfooi(Interface *i)
}
/******************************************/
-// 15610
+// https://issues.dlang.org/show_bug.cgi?id=15610
class Base2
{
@@ -738,7 +726,7 @@ void Derived2::f()
}
/******************************************/
-// 15455
+// https://issues.dlang.org/show_bug.cgi?id=15455
struct X6
{
@@ -766,7 +754,7 @@ void test15455b(X8 s)
}
/******************************************/
-// 15372
+// https://issues.dlang.org/show_bug.cgi?id=15372
template <typename T>
int foo15372(int value)
@@ -776,11 +764,11 @@ int foo15372(int value)
void test15372b()
{
- int t = foo15372<int>(1);
+ int t = foo15372<int>(1);
}
/****************************************/
-// 15576
+// https://issues.dlang.org/show_bug.cgi?id=15576
namespace ns15576
{
@@ -793,7 +781,7 @@ namespace ns15576
}
/****************************************/
-// 15802
+// https://issues.dlang.org/show_bug.cgi?id=15802
template <typename T>
class Foo15802
@@ -807,16 +795,174 @@ public:
void test15802b()
{
- int t = Foo15802<int>::boo(1);
+ int t = Foo15802<int>::boo(1);
}
/****************************************/
-// 16536 - mangling mismatch on OSX
+// https://issues.dlang.org/show_bug.cgi?id=16536
+// mangling mismatch on OSX
#if defined(__APPLE__)
-__UINTMAX_TYPE__ pass16536(__UINTMAX_TYPE__ a)
+uint64_t pass16536(uint64_t a)
{
return a;
}
#endif
+
+/****************************************/
+// https://issues.dlang.org/show_bug.cgi?id=15589
+// extern(C++) virtual destructors are not put in vtbl[]
+
+class A15589
+{
+public:
+ struct S
+ {
+ public:
+ int x;
+ };
+ virtual int foo();
+ virtual ~A15589();
+ S s1;
+ S s2;
+};
+class B15589 : public A15589
+{
+public:
+ virtual int bar();
+ virtual ~B15589();
+ S s3;
+};
+
+void test15589b(A15589 *p)
+{
+ assert(p->foo() == 100);
+ assert(((B15589*)p)->bar() == 200);
+ p->~A15589();
+}
+
+
+/////////////////
+void trace15589(int ch);
+
+Cpp15589Base::~Cpp15589Base()
+{
+ trace15589('b');
+}
+
+Cpp15589Derived::Cpp15589Derived()
+{
+ b = 1;
+}
+
+Cpp15589Derived::~Cpp15589Derived()
+{
+ trace15589('B');
+}
+
+Cpp15589BaseVirtual::Cpp15589BaseVirtual()
+{
+ c = 2;
+}
+
+Cpp15589BaseVirtual::~Cpp15589BaseVirtual()
+{
+ trace15589('v');
+}
+
+Cpp15589DerivedVirtual::Cpp15589DerivedVirtual()
+{
+ d = 3;
+}
+
+Cpp15589DerivedVirtual::~Cpp15589DerivedVirtual()
+{
+ trace15589('V');
+}
+
+Cpp15589IntroducingVirtual::Cpp15589IntroducingVirtual()
+{
+ e = 4;
+}
+
+Cpp15589IntroducingVirtual::~Cpp15589IntroducingVirtual()
+{
+ trace15589('I');
+}
+
+Cpp15589Struct::~Cpp15589Struct()
+{
+ trace15589('s');
+}
+
+/****************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18928
+
+struct Small18928
+{
+ int x;
+};
+
+class CC18928
+{
+public:
+ virtual Small18928 getVirtual();
+ Small18928 getFinal();
+ static Small18928 getStatic();
+};
+
+Small18928 CC18928::getVirtual() { Small18928 s = {3}; return s; }
+Small18928 CC18928::getFinal() { Small18928 s = {4}; return s; }
+Small18928 CC18928::getStatic() { Small18928 s = {5}; return s; }
+
+CC18928* newCC18928()
+{
+ return new CC18928();
+}
+
+/****************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18966
+Base18966::Base18966() { x = 10; }
+Base18966::~Base18966() {}
+void Base18966::vf()
+{
+ x = 100;
+}
+
+A18966::A18966() : calledOverloads(/*zero-init*/), i(0) { foo(); }
+void A18966::foo() { calledOverloads[i++] = 'A'; }
+
+B18966::B18966() { foo(); }
+void B18966::foo() { calledOverloads[i++] = 'B'; }
+
+#if _WIN32 // otherwise defined in C header files!
+// https://issues.dlang.org/show_bug.cgi?id=18955
+namespace std
+{
+ template<typename Char>
+ struct char_traits
+ {
+ };
+ template<typename Char>
+ class allocator
+ {
+ };
+ template<typename Char, typename Traits, typename Alloc>
+ class basic_string
+ {
+ };
+ typedef basic_string<char, char_traits<char>, allocator<char> > string;
+}
+#endif // _WIN32
+
+void callback18955(const std::string& s);
+
+void test18955()
+{
+ std::string s;
+// TODO: on OSX and FreeBSD, std is mangled as std::__1
+#if !__APPLE__ && !__FreeBSD__
+ callback18955(s);
+#endif
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.h b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.h
new file mode 100644
index 0000000..2ace632
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.h
@@ -0,0 +1,83 @@
+// avoid declaration in cpp file so the C/C++ compiler does no assume
+// these are inaccessible from elsewhere
+class Cpp15589Base
+{
+public:
+ ~Cpp15589Base();
+
+ virtual void nonVirtual() {}
+ int a;
+};
+
+class Cpp15589Derived : public Cpp15589Base
+{
+public:
+ Cpp15589Derived();
+ ~Cpp15589Derived();
+ int b;
+};
+
+class Cpp15589BaseVirtual
+{
+public:
+ virtual void beforeDtor() {}
+
+ Cpp15589BaseVirtual();
+ virtual ~Cpp15589BaseVirtual();
+
+ virtual void afterDtor() {}
+ int c;
+};
+
+class Cpp15589DerivedVirtual : public Cpp15589BaseVirtual
+{
+public:
+ Cpp15589DerivedVirtual(); // explicit C++ ctor needed, see https://issues.dlang.org/show_bug.cgi?id=18966
+ virtual ~Cpp15589DerivedVirtual();
+
+ virtual void afterDtor() {}
+
+ int d;
+};
+
+class Cpp15589IntroducingVirtual : public Cpp15589Base
+{
+public:
+ Cpp15589IntroducingVirtual();
+ virtual void beforeIntroducedVirtual() {}
+ virtual ~Cpp15589IntroducingVirtual();
+ virtual void afterIntroducedVirtual(int) {}
+
+ int e;
+};
+
+struct Cpp15589Struct
+{
+ ~Cpp15589Struct();
+ int s;
+};
+
+class Base18966
+{
+public:
+ Base18966();
+ virtual ~Base18966();
+ virtual void vf();
+ int x;
+};
+
+class A18966
+{
+public:
+ char calledOverloads[8];
+ int i;
+ A18966();
+ virtual void foo();
+};
+
+class B18966 : public A18966
+{
+public:
+ B18966();
+ void foo() /*override*/;
+};
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/externmangle.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/externmangle.cpp
index da3e844..37c98ea 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/externmangle.cpp
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/externmangle.cpp
@@ -1,3 +1,4 @@
+#include <stddef.h>
#include <stdint.h>
template<class X>
@@ -194,17 +195,25 @@ int Module::dim(Array<Module*>* arr)
return arr->dim;
}
-#if _LP64
-unsigned long testlongmangle(int32_t a, uint32_t b, long c, unsigned long d)
+uint64_t testlongmangle(int a, unsigned int b, int64_t c, uint64_t d)
{
return a + b + c + d;
}
-#else
-unsigned long long testlongmangle(int a, unsigned int b, long long c, unsigned long long d)
+
+unsigned long testCppLongMangle(long a, unsigned long b)
{
- return a + b + c + d;
+ return a + b;
+}
+
+unsigned long long testCppLongLongMangle(long long a, unsigned long long b)
+{
+ return a + b;
+}
+
+size_t testCppSizeTMangle(ptrdiff_t a, size_t b)
+{
+ return a + b;
}
-#endif
int test31[2][2][2] = {1, 1, 1, 1, 1, 1, 1, 1};
int *test32 = 0;
@@ -401,4 +410,40 @@ int test39cpp(C2<char>* c2, S2<int>* s2)
if (s2->value() != otherS2->value())
return 2;
return 0;
-} \ No newline at end of file
+}
+
+namespace foo
+{
+ namespace bar
+ {
+ namespace baz
+ {
+ int doStuff(int i)
+ {
+ return i * 2;
+ }
+ }
+ }
+}
+
+#ifndef __DMC__ // DMC doesn't support c++11
+template<typename ...T> void foovargs(T... args);
+
+void test40()
+{
+ foovargs<int, float>(1, 2.0f);
+ char c = 'a';
+ foovargs<char*>(&c);
+}
+
+template<typename T, typename ...Args>
+void make_shared_poc(Args&... args);
+
+void test41()
+{
+ int a = 1;
+ int b = 2;
+ make_shared_poc<int, int, int>(a, b);
+
+}
+#endif
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/stdint.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/stdint.cpp
new file mode 100644
index 0000000..1f5d605
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/stdint.cpp
@@ -0,0 +1,8 @@
+#include <stdint.h>
+
+int testCppI8Mangle (int8_t, uint8_t, int_least8_t, uint_least8_t, int_fast8_t, uint_fast8_t) { return 1; }
+int testCppI16Mangle(int16_t, uint16_t, int_least16_t, uint_least16_t, int_fast16_t, uint_fast16_t) { return 2; }
+int testCppI32Mangle(int32_t, uint32_t, int_least32_t, uint_least32_t, int_fast32_t, uint_fast32_t) { return 3; }
+int testCppI64Mangle(int64_t, uint64_t, int_least64_t, uint_least64_t, int_fast64_t, uint_fast64_t) { return 4; }
+int testCppIntPtrMangle(intptr_t, uintptr_t) { return 5; }
+int testCppIntMaxMangle(intmax_t, uintmax_t) { return 6; }
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test20652.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test20652.cpp
new file mode 100644
index 0000000..91ab66a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test20652.cpp
@@ -0,0 +1,34 @@
+#if defined(__DMC__) // DMC doesn't support immintrin.h
+#else
+
+#include <assert.h>
+
+// Inline the typedef of __m128 instead of including immintrin.h.
+#if defined(__GNUC__) || defined(__clang__)
+typedef float __m128 __attribute__((__vector_size__(16), __may_alias__));
+
+#elif defined(_MSC_VER)
+typedef union __declspec(intrin_type) __declspec(align(16)) __m128 {
+ float m128_f32[4];
+} __m128;
+
+#else
+#error "Unknown vendor"
+#endif
+
+void test20652(const __m128& a)
+{
+ union
+ {
+ __m128 value;
+ float array[4];
+ } b;
+ b.value = a;
+
+ assert(b.array[0] == 1);
+ assert(b.array[1] == 1);
+ assert(b.array[2] == 1);
+ assert(b.array[3] == 1);
+}
+
+#endif
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test21515.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test21515.cpp
index 076777a..71c624e 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test21515.cpp
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test21515.cpp
@@ -7,17 +7,17 @@ union cdouble_t { _Complex double z; struct { double re; double im; }; };
union creal_t { _Complex long double z; struct { long double re; long double im; }; };
// extern(C) tests
-extern "C" _Complex float ccomplexf() { return 2.0f+I; }
-extern "C" _Complex double ccomplex() { return 2.0+I; }
-extern "C" _Complex long double ccomplexl() { return 2.0L+I; }
+extern "C" _Complex float ccomplexf() { return {2.0f, 1.0f}; }
+extern "C" _Complex double ccomplex() { return {2.0, 1.0}; }
+extern "C" _Complex long double ccomplexl() { return {2.0L, 1.0L}; }
extern "C" void ccomplexf2(_Complex float c) { cfloat_t z = {c}; assert(z.re == 2 && z.im == 1); }
extern "C" void ccomplex2(_Complex double c) { cdouble_t z = {c}; assert(z.re == 2 && z.im == 1); }
extern "C" void ccomplexl2(_Complex long double c) { creal_t z = {c}; assert(z.re == 2 && z.im == 1); }
// extern(C++) tests
-_Complex float cpcomplexf() { return 2.0f+I; }
-_Complex double cpcomplex() { return 2.0+I; }
-_Complex long double cpcomplexl() { return 2.0L+I; }
+_Complex float cpcomplexf() { return {2.0f, 1.0f}; }
+_Complex double cpcomplex() { return {2.0, 1.0}; }
+_Complex long double cpcomplexl() { return {2.0L, 1.0L}; }
void cpcomplexf(_Complex float c) { cfloat_t z = {c}; assert(z.re == 2 && z.im == 1); }
void cpcomplex(_Complex double c) { cdouble_t z = {c}; assert(z.re == 2 && z.im == 1); }
void cpcomplexl(_Complex long double c) { creal_t z = {c}; assert(z.re == 2 && z.im == 1); }
@@ -30,21 +30,21 @@ struct wrap_complexl { _Complex long double c; };
wrap_complexf wcomplexf()
{
wrap_complexf s;
- s.c = 2.0f+I;
+ s.c = {2.0f, 1.0f};
return s;
}
wrap_complex wcomplex()
{
wrap_complex s;
- s.c = 2.0+I;
+ s.c = {2.0, 1.0};
return s;
}
wrap_complexl wcomplexl()
{
wrap_complexl s;
- s.c = 2.0L+I;
+ s.c = {2.0L, 1.0L};
return s;
}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test6716.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test6716.cpp
new file mode 100644
index 0000000..2528b18
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test6716.cpp
@@ -0,0 +1,13 @@
+
+int test6716(int magic);
+
+extern "C" int rt_init();
+extern "C" int rt_term();
+
+int main(int argc, char*argv[])
+{
+ rt_init();
+ int rc = test6716(12345);
+ rt_term();
+ return rc;
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/stdint.d b/gcc/testsuite/gdc.test/runnable_cxx/stdint.d
new file mode 100644
index 0000000..e599425
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/stdint.d
@@ -0,0 +1,24 @@
+// EXTRA_CPP_SOURCES: stdint.cpp
+
+module stdint_test;
+
+import core.stdc.stdint;
+
+extern(C++):
+
+int testCppI8Mangle (int8_t, uint8_t, int_least8_t, uint_least8_t, int_fast8_t, uint_fast8_t);
+int testCppI16Mangle(int16_t, uint16_t, int_least16_t, uint_least16_t, int_fast16_t, uint_fast16_t);
+int testCppI32Mangle(int32_t, uint32_t, int_least32_t, uint_least32_t, int_fast32_t, uint_fast32_t);
+int testCppI64Mangle(int64_t, uint64_t, int_least64_t, uint_least64_t, int_fast64_t, uint_fast64_t);
+int testCppIntPtrMangle(intptr_t, uintptr_t);
+int testCppIntMaxMangle(intmax_t, uintmax_t);
+
+void main()
+{
+ assert(testCppI8Mangle (1, 2, 3, 4, 5, 6) == 1);
+ assert(testCppI16Mangle(1, 2, 3, 4, 5, 6) == 2);
+ assert(testCppI32Mangle(1, 2, 3, 4, 5, 6) == 3);
+ assert(testCppI64Mangle(1, 2, 3, 4, 5, 6) == 4);
+ assert(testCppIntPtrMangle(1, 2) == 5);
+ assert(testCppIntMaxMangle(1, 2) == 6);
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test14203.d b/gcc/testsuite/gdc.test/runnable_cxx/test14203.d
new file mode 100644
index 0000000..3b29c66
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/test14203.d
@@ -0,0 +1,22 @@
+// EXTRA_CPP_SOURCES: c14203.cpp
+
+
+/************************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=14203
+
+extern (C++) float func1();
+
+void test14203()
+{
+ assert(func1() == 73);
+}
+
+/************************************************/
+
+int main()
+{
+ test14203();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test19179.d b/gcc/testsuite/gdc.test/runnable_cxx/test19179.d
new file mode 100644
index 0000000..6bdccfd
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/test19179.d
@@ -0,0 +1,32 @@
+// EXTRA_CPP_SOURCES: cpp19179.cpp
+
+// https://issues.dlang.org/show_bug.cgi?id=19179
+
+import core.stdc.stdio;
+
+extern(C++) struct SmallStruct { int x = 10, y = 20; }
+
+extern (C++)
+SmallStruct test_small(SmallStruct s)
+{
+ printf("%d %d\n", s.x, s.y); // prints: invalid memory
+ assert(s.x == 10);
+ assert(s.y == 20);
+ return s;
+}
+
+extern (C++)
+void test_small_noret(SmallStruct s)
+{
+ printf("%d %d\n", s.x, s.y); // prints: 10 20
+ assert(s.x == 10);
+ assert(s.y == 20);
+}
+
+extern (C++) void cppmain();
+
+int main()
+{
+ cppmain();
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test20652.d b/gcc/testsuite/gdc.test/runnable_cxx/test20652.d
new file mode 100644
index 0000000..68bb0a7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/test20652.d
@@ -0,0 +1,23 @@
+// https://issues.dlang.org/show_bug.cgi?id=20652
+// EXTRA_CPP_SOURCES: test20652.cpp
+
+import core.simd;
+
+version (CRuntime_DigitalMars) // DMC doesn't support immintrin.h
+{
+ void main() {}
+}
+else static if (!__traits(compiles, float4)) // No __vector support
+{
+ void main() {}
+}
+else
+{
+ extern(C++) void test20652(ref const float4);
+
+ void main()
+ {
+ float4 f4 = 1;
+ test20652(f4);
+ }
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test21515.d b/gcc/testsuite/gdc.test/runnable_cxx/test21515.d
index cc44207..e548456 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/test21515.d
+++ b/gcc/testsuite/gdc.test/runnable_cxx/test21515.d
@@ -1,5 +1,6 @@
// https://issues.dlang.org/show_bug.cgi?id=21515
// EXTRA_CPP_SOURCES: test21515.cpp
+// CXXFLAGS: -std=c++11
// DISABLED: win32 win64
// ABI layout of native complex
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test6716.d b/gcc/testsuite/gdc.test/runnable_cxx/test6716.d
new file mode 100644
index 0000000..edda423
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/test6716.d
@@ -0,0 +1,20 @@
+// EXTRA_CPP_SOURCES: test6716.cpp
+
+version(Windows)
+{
+ // without main, there is no implicit reference to the runtime library
+ // other platforms pass the runtime library on the linker command line
+ version(CRuntime_Microsoft)
+ version(Win64)
+ pragma(lib, "phobos64");
+ else
+ pragma(lib, "phobos32mscoff");
+ else
+ pragma(lib, "phobos");
+}
+
+extern(C++) int test6716(int magic)
+{
+ assert(magic == 12345);
+ return 0;
+} \ No newline at end of file
diff --git a/gcc/testsuite/lib/gdc-utils.exp b/gcc/testsuite/lib/gdc-utils.exp
index 33c0145..b3da788 100644
--- a/gcc/testsuite/lib/gdc-utils.exp
+++ b/gcc/testsuite/lib/gdc-utils.exp
@@ -35,6 +35,15 @@ proc gdc-convert-args { args } {
set compilable_output_file_ext "di"
lappend out "-H"
+ } elseif [string match "-HC" $arg] {
+ upvar 1 compilable_output_file_ext compilable_output_file_ext
+ upvar 1 name name
+ set compilable_output_file_ext "h"
+ lappend out "-fdump-c++-spec=[file rootname $name].h"
+
+ } elseif [string match "-HC=verbose" $arg] {
+ lappend out "-fdump-c++-spec-verbose"
+
} elseif { [regexp -- {^-I([\w+/-]+)} $arg pattern path] } {
lappend out "-I$path"
@@ -54,11 +63,11 @@ proc gdc-convert-args { args } {
} elseif { [string match "-boundscheck" $arg]
|| [string match "-boundscheck=on" $arg] } {
- lappend out "-fbounds-check"
+ lappend out "-fbounds-check=on"
} elseif { [string match "-boundscheck=off" $arg]
|| [string match "-noboundscheck" $arg] } {
- lappend out "-fno-bounds-check"
+ lappend out "-fbounds-check=off"
} elseif [string match "-boundscheck=safeonly" $arg] {
lappend out "-fbounds-check=safeonly"
@@ -66,6 +75,12 @@ proc gdc-convert-args { args } {
} elseif [string match "-c" $arg] {
lappend out "-c"
+ } elseif [regexp -- {^-check=(\w+)=off} $arg pattern value] {
+ lappend out "-fno-check=$value"
+
+ } elseif [string match "-checkaction=context" $arg] {
+ lappend out "-fcheckaction=context"
+
} elseif [string match "-d" $arg] {
lappend out "-Wno-deprecated"
@@ -79,23 +94,35 @@ proc gdc-convert-args { args } {
} elseif [regexp -- {^-debug=(\w+)} $arg pattern value] {
lappend out "-fdebug=$value"
+ } elseif [string match "-dip25" $arg] {
+ lappend out "-fpreview=dip25"
+
} elseif [string match "-dip1000" $arg] {
- lappend out "-ftransition=dip1000"
+ lappend out "-fpreview=dip1000"
- } elseif [string match "-dip25" $arg] {
- lappend out "-ftransition=dip25"
+ } elseif [string match "-dip1008" $arg] {
+ lappend out "-fpreview=dip1008"
} elseif [string match "-dw" $arg] {
lappend out "-Wdeprecated"
lappend out "-Wno-error"
+ } elseif [regexp -- {^-extern-std=([\w+]+)} $arg pattern value] {
+ lappend out "-fextern-std=$value"
+
} elseif [string match "-fPIC" $arg] {
lappend out "-fPIC"
+ } elseif [string match "-fPIE" $arg] {
+ lappend out "-fPIE"
+
} elseif { [string match "-g" $arg]
|| [string match "-gc" $arg] } {
lappend out "-g"
+ } elseif [string match "-ignore" $arg] {
+ lappend out "-fignore-unknown-pragmas"
+
} elseif [string match "-inline" $arg] {
lappend out "-finline-functions"
@@ -108,11 +135,17 @@ proc gdc-convert-args { args } {
} elseif [string match "-O" $arg] {
lappend out "-O2"
+ } elseif [regexp -- {^-preview=(\w+)} $arg pattern value] {
+ lappend out "-fpreview=[string tolower $value]"
+
} elseif [string match "-release" $arg] {
lappend out "-frelease"
+ } elseif [regexp -- {^-revert=(\w+)} $arg pattern value] {
+ lappend out "-frevert=[string tolower $value]"
+
} elseif [regexp -- {^-transition=(\w+)} $arg pattern value] {
- lappend out "-ftransition=$value"
+ lappend out "-ftransition=[string tolower $value]"
} elseif [string match "-unittest" $arg] {
lappend out "-funittest"
@@ -126,6 +159,16 @@ proc gdc-convert-args { args } {
} elseif [regexp -- {^-version=(\w+)} $arg pattern value] {
lappend out "-fversion=$value"
+ } elseif [string match "-o-" $arg] {
+ upvar 2 compilable_do_what compilable_do_what
+ set compilable_do_what "compile"
+
+ } elseif [string match "-vgc" $arg] {
+ lappend out "-ftransition=nogc"
+
+ } elseif [string match "-vtemplates" $arg] {
+ lappend out "-ftransition=templates"
+
} elseif [string match "-vtls" $arg] {
lappend out "-ftransition=tls"
@@ -184,10 +227,15 @@ proc gdc-copy-file { srcdir filename } {
# the test.
# EXTRA_CPP_SOURCES: List of extra C++ files to build and link along with
# the test.
+# CXXFLAGS: list of extra arguments passed when compiling C++
+# sources defined in EXTRA_CPP_SOURCES.
+# EXTRA_OBJC_SOURCES: List of extra Objective-C file to build and link along
+# with the test. Currently not handled.
# EXTRA_FILES: List of extra files to copy for the test runs.
# PERMUTE_ARGS: The set of arguments to permute in multiple compiler
# invocations. An empty set means only one permutation
# with no arguments.
+# ARG_SETS: Not handled.
# LINK: Enables linking.
# TEST_OUTPUT: The output expected from the compilation.
# POST_SCRIPT: Not handled.
@@ -241,6 +289,10 @@ proc gdc-convert-test { base test } {
# LINK sets dg-do-what-default "link"
set compilable_do_what "link"
+ } elseif [regexp -- {ARG_SETS} $copy_line] {
+ # ARG_SETS is not handled.
+ regsub -- {ARG_SETS.*$} $copy_line "" out_line
+
} elseif [regexp -- {POST_SCRIPT} $copy_line] {
# POST_SCRIPT is not handled
@@ -279,6 +331,16 @@ proc gdc-convert-test { base test } {
lappend extra_sources "extra-files/$srcfile"
}
+ } elseif [regexp -- {CXXFLAGS\s*:\s*(.*)} $copy_line match args] {
+ # Both C++ and D sources are compiled together, so include each
+ # other's command line flags too.
+ set new_option "{ dg-additional-options \"$args\" }"
+ regsub -- {CXXFLAGS.*$} $copy_line $new_option out_line
+
+ } elseif [regexp -- {EXTRA_OBJC_SOURCES\s*:\s*(.*)} $copy_line match sources] {
+ # EXTRA_OBJC_SOURCES is not handled.
+ regsub -- {EXTRA_OBJC_SOURCES.*$} $copy_line "" out_line
+
} elseif [regexp -- {EXTRA_FILES\s*:\s*(.*)} $copy_line match files] {
# EXTRA_FILES are appended to extra_files list
foreach file $files {
@@ -365,6 +427,11 @@ proc gdc-convert-test { base test } {
}
fail_compilation {
+ # Fail compilation tests only check for language errors from the
+ # front-end. No need to run all permutations of the default DFLAGS.
+ if { $PERMUTE_ARGS == $DEFAULT_DFLAGS } {
+ set PERMUTE_ARGS ""
+ }
puts $fdout "// { dg-final { output-exists-not } }"
}
}
@@ -434,7 +501,7 @@ proc gdc-do-test { testcases } {
regexp -- "(.*)/(.+)/(.+)\.(.+)$" $test match base type name ext
# Convert to DG test.
- set imports [format "-I%s/%s" $base $type]
+ set imports [format "-I%s" $type]
set cleanup_extra_files ""
set compilable_do_what "compile"
set filename "[gdc-convert-test $base $type/$name.$ext]"